mirror of
https://github.com/TES3MP/openmw-tes3mp.git
synced 2025-01-29 22:15:32 +00:00
Merge branch 'master' of github.com:scrawl/openmw
This commit is contained in:
commit
0da4757ee6
11 changed files with 131 additions and 34 deletions
|
@ -536,6 +536,9 @@ namespace MWBase
|
|||
|
||||
/// @see MWWorld::WeatherManager::getStormDirection
|
||||
virtual Ogre::Vector3 getStormDirection() const = 0;
|
||||
|
||||
/// Resets all actors in the current active cells to their original location within that cell.
|
||||
virtual void resetActors() = 0;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -280,7 +280,7 @@ namespace MWMechanics
|
|||
|| actor1.getClass().getCreatureStats(actor1).isDead())
|
||||
return;
|
||||
|
||||
const ESM::Position& actor1Pos = actor2.getRefData().getPosition();
|
||||
const ESM::Position& actor1Pos = actor1.getRefData().getPosition();
|
||||
const ESM::Position& actor2Pos = actor2.getRefData().getPosition();
|
||||
float sqrDist = Ogre::Vector3(actor1Pos.pos).squaredDistance(Ogre::Vector3(actor2Pos.pos));
|
||||
if (sqrDist > 7168*7168)
|
||||
|
@ -756,7 +756,7 @@ namespace MWMechanics
|
|||
MWMechanics::CreatureStats& summonedCreatureStats = ref.getPtr().getClass().getCreatureStats(ref.getPtr());
|
||||
|
||||
// Make the summoned creature follow its master and help in fights
|
||||
AiFollow package(ptr.getRefData().getHandle());
|
||||
AiFollow package(ptr.getCellRef().getRefId());
|
||||
summonedCreatureStats.getAiSequence().stack(package, ref.getPtr());
|
||||
int creatureActorId = summonedCreatureStats.getActorId();
|
||||
|
||||
|
|
|
@ -59,6 +59,29 @@ void suggestCombatRange(int rangeTypes, float& rangeAttack, float& rangeFollow)
|
|||
}
|
||||
}
|
||||
|
||||
int numEffectsToCure (const MWWorld::Ptr& actor, int effectFilter=-1)
|
||||
{
|
||||
int toCure=0;
|
||||
const MWMechanics::ActiveSpells& activeSpells = actor.getClass().getCreatureStats(actor).getActiveSpells();
|
||||
for (MWMechanics::ActiveSpells::TIterator it = activeSpells.begin(); it != activeSpells.end(); ++it)
|
||||
{
|
||||
const MWMechanics::ActiveSpells::ActiveSpellParams& params = it->second;
|
||||
for (std::vector<MWMechanics::ActiveSpells::ActiveEffect>::const_iterator effectIt = params.mEffects.begin();
|
||||
effectIt != params.mEffects.end(); ++effectIt)
|
||||
{
|
||||
int effectId = effectIt->mEffectId;
|
||||
if (effectFilter != -1 && effectId != effectFilter)
|
||||
continue;
|
||||
const ESM::MagicEffect* magicEffect = MWBase::Environment::get().getWorld()->getStore().get<ESM::MagicEffect>().find(effectId);
|
||||
if (magicEffect->mData.mFlags & ESM::MagicEffect::Harmful
|
||||
&& effectIt->mDuration > 3 // Don't attempt to cure if effect runs out shortly anyway
|
||||
)
|
||||
++toCure;
|
||||
}
|
||||
}
|
||||
return toCure;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace MWMechanics
|
||||
|
@ -178,20 +201,24 @@ namespace MWMechanics
|
|||
{
|
||||
// NOTE: target may be empty
|
||||
|
||||
float baseRating = 1;
|
||||
float rating = 1;
|
||||
switch (effect.mEffectID)
|
||||
{
|
||||
case ESM::MagicEffect::Soultrap:
|
||||
case ESM::MagicEffect::AlmsiviIntervention:
|
||||
case ESM::MagicEffect::DivineIntervention:
|
||||
case ESM::MagicEffect::CalmCreature:
|
||||
case ESM::MagicEffect::CalmHumanoid:
|
||||
case ESM::MagicEffect::CalmCreature:
|
||||
case ESM::MagicEffect::FrenzyHumanoid:
|
||||
case ESM::MagicEffect::FrenzyCreature:
|
||||
case ESM::MagicEffect::DemoralizeHumanoid:
|
||||
case ESM::MagicEffect::DemoralizeCreature:
|
||||
case ESM::MagicEffect::RallyHumanoid:
|
||||
case ESM::MagicEffect::RallyCreature:
|
||||
case ESM::MagicEffect::Charm:
|
||||
case ESM::MagicEffect::DetectAnimal:
|
||||
case ESM::MagicEffect::DetectEnchantment:
|
||||
case ESM::MagicEffect::DetectKey:
|
||||
case ESM::MagicEffect::FrenzyCreature:
|
||||
case ESM::MagicEffect::FrenzyHumanoid:
|
||||
case ESM::MagicEffect::Telekinesis:
|
||||
case ESM::MagicEffect::Mark:
|
||||
case ESM::MagicEffect::Recall:
|
||||
|
@ -204,16 +231,39 @@ namespace MWMechanics
|
|||
case ESM::MagicEffect::Lock:
|
||||
case ESM::MagicEffect::Open:
|
||||
case ESM::MagicEffect::TurnUndead:
|
||||
case ESM::MagicEffect::WeaknessToCommonDisease:
|
||||
case ESM::MagicEffect::WeaknessToBlightDisease:
|
||||
case ESM::MagicEffect::WeaknessToCorprusDisease:
|
||||
case ESM::MagicEffect::CureCommonDisease:
|
||||
case ESM::MagicEffect::CureBlightDisease:
|
||||
case ESM::MagicEffect::CureCorprusDisease:
|
||||
case ESM::MagicEffect::Invisibility:
|
||||
return 0.f;
|
||||
case ESM::MagicEffect::Feather:
|
||||
return 0.f; // TODO: check if target is overencumbered
|
||||
if (actor.getClass().getEncumbrance(actor) - actor.getClass().getCapacity(actor) >= 0)
|
||||
return 100.f;
|
||||
else
|
||||
return 0.f;
|
||||
case ESM::MagicEffect::Levitate:
|
||||
return 0.f; // AI isn't designed to take advantage of this, and could be perceived as unfair anyway
|
||||
// TODO: check if Beast race (can't wear boots or helm)
|
||||
/*
|
||||
case ESM::MagicEffect::BoundBoots:
|
||||
case ESM::MagicEffect::BoundHelm:
|
||||
*/
|
||||
if (actor.getClass().isNpc())
|
||||
{
|
||||
// Beast races can't wear helmets or boots
|
||||
std::string raceid = actor.get<ESM::NPC>()->mBase->mRace;
|
||||
const ESM::Race* race = MWBase::Environment::get().getWorld()->getStore().get<ESM::Race>().find(raceid);
|
||||
if (race->mData.mFlags & ESM::Race::Beast)
|
||||
return 0.f;
|
||||
}
|
||||
// Intended fall-through
|
||||
// Creatures can not wear armor
|
||||
case ESM::MagicEffect::BoundCuirass:
|
||||
case ESM::MagicEffect::BoundGloves:
|
||||
if (!actor.getClass().isNpc())
|
||||
return 0.f;
|
||||
break;
|
||||
|
||||
case ESM::MagicEffect::RestoreHealth:
|
||||
case ESM::MagicEffect::RestoreMagicka:
|
||||
case ESM::MagicEffect::RestoreFatigue:
|
||||
|
@ -231,25 +281,13 @@ namespace MWMechanics
|
|||
}
|
||||
break;
|
||||
|
||||
// Give a small boost to all direct damage effects. This is combat, after all!
|
||||
case ESM::MagicEffect::FireDamage:
|
||||
case ESM::MagicEffect::ShockDamage:
|
||||
case ESM::MagicEffect::FrostDamage:
|
||||
case ESM::MagicEffect::Poison:
|
||||
case ESM::MagicEffect::AbsorbHealth:
|
||||
case ESM::MagicEffect::DamageHealth:
|
||||
baseRating *= 4;
|
||||
break;
|
||||
|
||||
case ESM::MagicEffect::Paralyze: // *Evil laughter*
|
||||
baseRating *= 5;
|
||||
break;
|
||||
|
||||
// TODO: rate these effects very high if we are currently suffering from negative effects that could be cured
|
||||
// Prefer Cure effects over Dispel, because Dispel also removes positive effects
|
||||
case ESM::MagicEffect::Dispel:
|
||||
return 1000.f * numEffectsToCure(actor);
|
||||
case ESM::MagicEffect::CureParalyzation:
|
||||
return 1001.f * numEffectsToCure(actor, ESM::MagicEffect::Paralyze);
|
||||
case ESM::MagicEffect::CurePoison:
|
||||
break;
|
||||
return 1001.f * numEffectsToCure(actor, ESM::MagicEffect::Poison);
|
||||
|
||||
default:
|
||||
break;
|
||||
|
@ -261,12 +299,10 @@ namespace MWMechanics
|
|||
|
||||
const ESM::MagicEffect* magicEffect = MWBase::Environment::get().getWorld()->getStore().get<ESM::MagicEffect>().find(effect.mEffectID);
|
||||
|
||||
baseRating *= magicEffect->mData.mBaseCost;
|
||||
rating *= magicEffect->mData.mBaseCost;
|
||||
|
||||
if (magicEffect->mData.mFlags & ESM::MagicEffect::NoMagnitude)
|
||||
return 0.f; // No clue how useful this would be; will need special cases for each effect
|
||||
|
||||
float rating = baseRating * (effect.mMagnMin + effect.mMagnMax)/2.f;
|
||||
if (!(magicEffect->mData.mFlags & ESM::MagicEffect::NoMagnitude))
|
||||
rating *= (effect.mMagnMin + effect.mMagnMax)/2.f;
|
||||
if (!(magicEffect->mData.mFlags & ESM::MagicEffect::NoDuration))
|
||||
rating *= effect.mDuration;
|
||||
|
||||
|
|
|
@ -684,9 +684,23 @@ namespace MWMechanics
|
|||
|
||||
if (item.getCellRef().getEnchantmentCharge() < castCost)
|
||||
{
|
||||
// TODO: Should there be a sound here?
|
||||
if (mCaster.getRefData().getHandle() == "player")
|
||||
MWBase::Environment::get().getWindowManager()->messageBox("#{sMagicInsufficientCharge}");
|
||||
|
||||
// Failure sound
|
||||
int school = 0;
|
||||
for (std::vector<ESM::ENAMstruct>::const_iterator effectIt (enchantment->mEffects.mList.begin());
|
||||
effectIt!=enchantment->mEffects.mList.end(); ++effectIt)
|
||||
{
|
||||
const ESM::MagicEffect* magicEffect = MWBase::Environment::get().getWorld()->getStore().get<ESM::MagicEffect>().find(effectIt->mEffectID);
|
||||
school = magicEffect->mData.mSchool;
|
||||
break;
|
||||
}
|
||||
static const std::string schools[] = {
|
||||
"alteration", "conjuration", "destruction", "illusion", "mysticism", "restoration"
|
||||
};
|
||||
MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager();
|
||||
sndMgr->playSound3D(mCaster, "Spell Failure " + schools[school], 1.0f, 1.0f);
|
||||
return false;
|
||||
}
|
||||
// Reduce charge
|
||||
|
|
|
@ -431,5 +431,6 @@ op 0x2000294-0x20002ab: SetMagicEffect
|
|||
op 0x20002ac-0x20002c3: SetMagicEffect, explicit
|
||||
op 0x20002c4-0x20002db: ModMagicEffect
|
||||
op 0x20002dc-0x20002f3: ModMagicEffect, explicit
|
||||
op 0x20002f4: ResetActors
|
||||
|
||||
opcodes 0x20002f4-0x3ffffff unused
|
||||
opcodes 0x20002f5-0x3ffffff unused
|
||||
|
|
|
@ -719,6 +719,15 @@ namespace MWScript
|
|||
}
|
||||
};
|
||||
|
||||
class OpResetActors : public Interpreter::Opcode0
|
||||
{
|
||||
public:
|
||||
|
||||
virtual void execute (Interpreter::Runtime& runtime)
|
||||
{
|
||||
MWBase::Environment::get().getWorld()->resetActors();
|
||||
}
|
||||
};
|
||||
|
||||
void installOpcodes (Interpreter::Interpreter& interpreter)
|
||||
{
|
||||
|
@ -759,6 +768,7 @@ namespace MWScript
|
|||
interpreter.installSegment5(Compiler::Transformation::opcodeMoveWorldExplicit,new OpMoveWorld<ExplicitRef>);
|
||||
interpreter.installSegment5(Compiler::Transformation::opcodeGetStartingAngle, new OpGetStartingAngle<ImplicitRef>);
|
||||
interpreter.installSegment5(Compiler::Transformation::opcodeGetStartingAngleExplicit, new OpGetStartingAngle<ExplicitRef>);
|
||||
interpreter.installSegment5(Compiler::Transformation::opcodeResetActors, new OpResetActors);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -358,7 +358,7 @@ namespace MWWorld
|
|||
Class::copyToCell(const Ptr &ptr, CellStore &cell) const
|
||||
{
|
||||
Ptr newPtr = copyToCellImpl(ptr, cell);
|
||||
|
||||
newPtr.getCellRef().unsetRefNum(); // This RefNum is only valid within the original cell of the reference
|
||||
return newPtr;
|
||||
}
|
||||
|
||||
|
|
|
@ -2989,4 +2989,31 @@ namespace MWWorld
|
|||
if (!interpreterContext.hasActivationBeenHandled())
|
||||
interpreterContext.executeActivation(object, actor);
|
||||
}
|
||||
|
||||
struct ResetActorsFunctor
|
||||
{
|
||||
bool operator() (Ptr ptr)
|
||||
{
|
||||
// Can't reset actors that were moved to a different cell, because we don't know what cell they came from.
|
||||
// This could be fixed once we properly track actor cell changes, but may not be desirable behaviour anyhow.
|
||||
if (ptr.getClass().isActor() && ptr.getCellRef().getRefNum().mContentFile != -1)
|
||||
{
|
||||
const ESM::Position& origPos = ptr.getCellRef().getPosition();
|
||||
MWBase::Environment::get().getWorld()->moveObject(ptr, origPos.pos[0], origPos.pos[1], origPos.pos[2]);
|
||||
MWBase::Environment::get().getWorld()->rotateObject(ptr, origPos.rot[0], origPos.rot[1], origPos.rot[2]);
|
||||
ptr.getClass().adjustPosition(ptr, false);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
void World::resetActors()
|
||||
{
|
||||
for (Scene::CellStoreCollection::const_iterator iter (mWorldScene->getActiveCells().begin());
|
||||
iter!=mWorldScene->getActiveCells().end(); ++iter)
|
||||
{
|
||||
CellStore* cellstore = *iter;
|
||||
ResetActorsFunctor functor;
|
||||
cellstore->forEach(functor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -611,6 +611,9 @@ namespace MWWorld
|
|||
|
||||
/// @see MWWorld::WeatherManager::getStormDirection
|
||||
virtual Ogre::Vector3 getStormDirection() const;
|
||||
|
||||
/// Resets all actors in the current active cells to their original location within that cell.
|
||||
virtual void resetActors();
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -527,6 +527,8 @@ namespace Compiler
|
|||
extensions.registerInstruction("move","cf",opcodeMove,opcodeMoveExplicit);
|
||||
extensions.registerInstruction("moveworld","cf",opcodeMoveWorld,opcodeMoveWorldExplicit);
|
||||
extensions.registerFunction("getstartingangle",'f',"c",opcodeGetStartingAngle,opcodeGetStartingAngleExplicit);
|
||||
extensions.registerInstruction("resetactors","",opcodeResetActors);
|
||||
extensions.registerInstruction("ra","",opcodeResetActors);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -484,6 +484,7 @@ namespace Compiler
|
|||
const int opcodeMoveExplicit = 0x2000207;
|
||||
const int opcodeMoveWorld = 0x2000208;
|
||||
const int opcodeMoveWorldExplicit = 0x2000209;
|
||||
const int opcodeResetActors = 0x20002f4;
|
||||
}
|
||||
|
||||
namespace User
|
||||
|
|
Loading…
Reference in a new issue