mirror of
https://gitlab.com/OpenMW/openmw.git
synced 2025-02-06 09:39:49 +00:00
Implement SoulTrap magic effect
This commit is contained in:
parent
596e0c8a49
commit
299690631f
@ -22,7 +22,8 @@ namespace MWGui
|
||||
{
|
||||
|
||||
void EffectSourceVisitor::visit (MWMechanics::EffectKey key,
|
||||
const std::string& sourceName, float magnitude, float remainingTime)
|
||||
const std::string& sourceName, const std::string& casterHandle,
|
||||
float magnitude, float remainingTime)
|
||||
{
|
||||
MagicEffectInfo newEffectSource;
|
||||
newEffectSource.mKey = key;
|
||||
|
@ -43,7 +43,8 @@ namespace MWGui
|
||||
std::map <int, std::vector<MagicEffectInfo> > mEffectSources;
|
||||
|
||||
virtual void visit (MWMechanics::EffectKey key,
|
||||
const std::string& sourceName, float magnitude, float remainingTime = -1);
|
||||
const std::string& sourceName, const std::string& casterHandle,
|
||||
float magnitude, float remainingTime = -1);
|
||||
};
|
||||
|
||||
class SpellIcons
|
||||
|
@ -126,7 +126,8 @@ namespace MWMechanics
|
||||
return mSpells;
|
||||
}
|
||||
|
||||
void ActiveSpells::addSpell(const std::string &id, bool stack, std::vector<Effect> effects, const std::string &displayName)
|
||||
void ActiveSpells::addSpell(const std::string &id, bool stack, std::vector<Effect> effects,
|
||||
const std::string &displayName, const std::string& casterHandle)
|
||||
{
|
||||
bool exists = false;
|
||||
for (TContainer::const_iterator it = begin(); it != end(); ++it)
|
||||
@ -139,6 +140,7 @@ namespace MWMechanics
|
||||
params.mTimeStamp = MWBase::Environment::get().getWorld()->getTimeStamp();
|
||||
params.mEffects = effects;
|
||||
params.mDisplayName = displayName;
|
||||
params.mCasterHandle = casterHandle;
|
||||
|
||||
if (!exists || stack)
|
||||
mSpells.insert (std::make_pair(id, params));
|
||||
@ -164,7 +166,7 @@ namespace MWMechanics
|
||||
float magnitude = effectIt->mMagnitude;
|
||||
|
||||
if (magnitude)
|
||||
visitor.visit(effectIt->mKey, name, magnitude, remainingTime);
|
||||
visitor.visit(effectIt->mKey, name, it->second.mCasterHandle, magnitude, remainingTime);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -37,8 +37,8 @@ namespace MWMechanics
|
||||
MWWorld::TimeStamp mTimeStamp;
|
||||
std::string mDisplayName;
|
||||
|
||||
// TODO: To handle CASTER_LINKED flag (spell is purged when caster dies),
|
||||
// we should probably store a handle to the caster here.
|
||||
// Handle to the caster that that inflicted this spell on us
|
||||
std::string mCasterHandle;
|
||||
};
|
||||
|
||||
typedef std::multimap<std::string, ActiveSpellParams > TContainer;
|
||||
@ -76,8 +76,10 @@ namespace MWMechanics
|
||||
/// \param stack If false, the spell is not added if one with the same ID exists already.
|
||||
/// \param effects
|
||||
/// \param displayName Name for display in magic menu.
|
||||
/// \param casterHandle
|
||||
///
|
||||
void addSpell (const std::string& id, bool stack, std::vector<Effect> effects, const std::string& displayName);
|
||||
void addSpell (const std::string& id, bool stack, std::vector<Effect> effects,
|
||||
const std::string& displayName, const std::string& casterHandle);
|
||||
|
||||
/// Remove all active effects with this id
|
||||
void purgeEffect (short effectId);
|
||||
|
@ -88,6 +88,68 @@ bool disintegrateSlot (MWWorld::Ptr ptr, int slot, float disintegrate)
|
||||
|
||||
namespace MWMechanics
|
||||
{
|
||||
|
||||
class SoulTrap : public MWMechanics::EffectSourceVisitor
|
||||
{
|
||||
MWWorld::Ptr mCreature;
|
||||
MWWorld::Ptr mActor;
|
||||
public:
|
||||
SoulTrap(MWWorld::Ptr trappedCreature)
|
||||
: mCreature(trappedCreature) {}
|
||||
|
||||
virtual void visit (MWMechanics::EffectKey key,
|
||||
const std::string& sourceName, const std::string& casterHandle,
|
||||
float magnitude, float remainingTime = -1)
|
||||
{
|
||||
if (key.mId != ESM::MagicEffect::Soultrap)
|
||||
return;
|
||||
if (magnitude <= 0)
|
||||
return;
|
||||
|
||||
MWBase::World* world = MWBase::Environment::get().getWorld();
|
||||
|
||||
MWWorld::Ptr caster = world->searchPtrViaHandle(casterHandle);
|
||||
if (caster.isEmpty() || !caster.getClass().isActor())
|
||||
return;
|
||||
|
||||
static const float fSoulgemMult = world->getStore().get<ESM::GameSetting>().find("fSoulgemMult")->getFloat();
|
||||
|
||||
float creatureSoulValue = mCreature.get<ESM::Creature>()->mBase->mData.mSoul;
|
||||
|
||||
// Use the smallest soulgem that is large enough to hold the soul
|
||||
MWWorld::ContainerStore& container = caster.getClass().getContainerStore(caster);
|
||||
MWWorld::ContainerStoreIterator gem = container.end();
|
||||
float gemCapacity = std::numeric_limits<float>().max();
|
||||
std::string soulgemFilter = "misc_soulgem"; // no other way to check for soulgems? :/
|
||||
for (MWWorld::ContainerStoreIterator it = container.begin(MWWorld::ContainerStore::Type_Miscellaneous);
|
||||
it != container.end(); ++it)
|
||||
{
|
||||
const std::string& id = it->getCellRef().mRefID;
|
||||
if (id.size() >= soulgemFilter.size()
|
||||
&& id.substr(0,soulgemFilter.size()) == soulgemFilter)
|
||||
{
|
||||
float thisGemCapacity = it->get<ESM::Miscellaneous>()->mBase->mData.mValue * fSoulgemMult;
|
||||
if (thisGemCapacity >= creatureSoulValue && thisGemCapacity < gemCapacity
|
||||
&& it->getCellRef().mSoul.empty())
|
||||
{
|
||||
gem = it;
|
||||
gemCapacity = thisGemCapacity;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (gem == container.end())
|
||||
return;
|
||||
|
||||
// Set the soul on just one of the gems, not the whole stack
|
||||
gem->getContainerStore()->unstack(*gem, caster);
|
||||
gem->getCellRef().mSoul = mCreature.getCellRef().mRefID;
|
||||
|
||||
if (caster.getRefData().getHandle() == "player")
|
||||
MWBase::Environment::get().getWindowManager()->messageBox("#{sSoultrapSuccess}");
|
||||
}
|
||||
};
|
||||
|
||||
void Actors::updateActor (const MWWorld::Ptr& ptr, float duration)
|
||||
{
|
||||
// magic effects
|
||||
@ -705,6 +767,13 @@ namespace MWMechanics
|
||||
|
||||
iter->second->kill();
|
||||
|
||||
// Apply soultrap
|
||||
if (iter->first.getTypeName() == typeid(ESM::Creature).name())
|
||||
{
|
||||
SoulTrap soulTrap (iter->first);
|
||||
stats.getActiveSpells().visitEffectSources(soulTrap);
|
||||
}
|
||||
|
||||
// Reset magic effects and recalculate derived effects
|
||||
// One case where we need this is to make sure bound items are removed upon death
|
||||
stats.setMagicEffects(MWMechanics::MagicEffects());
|
||||
@ -714,6 +783,7 @@ namespace MWMechanics
|
||||
|
||||
if(cls.isEssential(iter->first))
|
||||
MWBase::Environment::get().getWindowManager()->messageBox("#{sKilledEssential}");
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -56,7 +56,8 @@ namespace MWMechanics
|
||||
struct EffectSourceVisitor
|
||||
{
|
||||
virtual void visit (MWMechanics::EffectKey key,
|
||||
const std::string& sourceName, float magnitude, float remainingTime = -1) = 0;
|
||||
const std::string& sourceName, const std::string& casterHandle,
|
||||
float magnitude, float remainingTime = -1) = 0;
|
||||
};
|
||||
|
||||
/// \brief Effects currently affecting a NPC or creature
|
||||
|
@ -24,21 +24,13 @@ void Repair::repair(const MWWorld::Ptr &itemToRepair)
|
||||
MWWorld::LiveCellRef<ESM::Repair> *ref =
|
||||
mTool.get<ESM::Repair>();
|
||||
|
||||
// unstack tool if required
|
||||
player.getClass().getContainerStore(player).unstack(mTool, player);
|
||||
|
||||
// reduce number of uses left
|
||||
int uses = (mTool.getCellRef().mCharge != -1) ? mTool.getCellRef().mCharge : ref->mBase->mData.mUses;
|
||||
mTool.getCellRef().mCharge = uses-1;
|
||||
|
||||
// unstack tool if required
|
||||
if (mTool.getRefData().getCount() > 1 && uses == ref->mBase->mData.mUses)
|
||||
{
|
||||
MWWorld::ContainerStore& store = MWWorld::Class::get(player).getContainerStore(player);
|
||||
MWWorld::ContainerStoreIterator it = store.add(mTool, player);
|
||||
it->getRefData().setCount(mTool.getRefData().getCount()-1);
|
||||
it->getCellRef().mCharge = -1;
|
||||
|
||||
mTool.getRefData().setCount(1);
|
||||
}
|
||||
|
||||
MWMechanics::CreatureStats& stats = MWWorld::Class::get(player).getCreatureStats(player);
|
||||
MWMechanics::NpcStats& npcStats = MWWorld::Class::get(player).getNpcStats(player);
|
||||
|
||||
|
@ -154,7 +154,8 @@ namespace MWMechanics
|
||||
ActiveSpells::Effect effect_ = effect;
|
||||
effect_.mMagnitude *= -1;
|
||||
effects.push_back(effect_);
|
||||
caster.getClass().getCreatureStats(caster).getActiveSpells().addSpell("", true, effects, mSourceName);
|
||||
caster.getClass().getCreatureStats(caster).getActiveSpells().addSpell("", true,
|
||||
effects, mSourceName, caster.getRefData().getHandle());
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -198,7 +199,8 @@ namespace MWMechanics
|
||||
inflict(caster, target, reflectedEffects, range, true);
|
||||
|
||||
if (appliedLastingEffects.size())
|
||||
target.getClass().getCreatureStats(target).getActiveSpells().addSpell(mId, mStack, appliedLastingEffects, mSourceName);
|
||||
target.getClass().getCreatureStats(target).getActiveSpells().addSpell(mId, mStack, appliedLastingEffects,
|
||||
mSourceName, caster.getRefData().getHandle());
|
||||
}
|
||||
|
||||
void CastSpell::applyInstantEffect(const MWWorld::Ptr &target, short effectId, float magnitude)
|
||||
|
@ -192,7 +192,7 @@ namespace MWMechanics
|
||||
effectIt != list.mList.end(); ++effectIt, ++i)
|
||||
{
|
||||
float magnitude = effectIt->mMagnMin + (effectIt->mMagnMax - effectIt->mMagnMin) * it->second[i];
|
||||
visitor.visit(MWMechanics::EffectKey(*effectIt), spell->mName, magnitude);
|
||||
visitor.visit(MWMechanics::EffectKey(*effectIt), spell->mName, "", magnitude);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -607,7 +607,7 @@ void MWWorld::InventoryStore::visitEffectSources(MWMechanics::EffectSourceVisito
|
||||
const EffectParams& params = mPermanentMagicEffectMagnitudes[(**iter).getCellRef().mRefID][i];
|
||||
float magnitude = effectIt->mMagnMin + (effectIt->mMagnMax - effectIt->mMagnMin) * params.mRandom;
|
||||
magnitude *= params.mMultiplier;
|
||||
visitor.visit(MWMechanics::EffectKey(*effectIt), (**iter).getClass().getName(**iter), magnitude);
|
||||
visitor.visit(MWMechanics::EffectKey(*effectIt), (**iter).getClass().getName(**iter), "", magnitude);
|
||||
|
||||
++i;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user