You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
openmw/apps/openmw/mwscript/statsextensions.cpp

1523 lines
59 KiB
C++

#include "statsextensions.hpp"
#include <cmath>
#include <components/esm3/loadcrea.hpp>
#include <components/esm3/loadnpc.hpp>
#include "../mwworld/esmstore.hpp"
#include <components/compiler/opcodes.hpp>
#include <components/debug/debuglog.hpp>
#include <components/esm3/loadfact.hpp>
#include <components/interpreter/interpreter.hpp>
#include <components/interpreter/opcodes.hpp>
#include <components/interpreter/runtime.hpp>
#include <components/esm3/loadmgef.hpp>
#include "../mwbase/environment.hpp"
#include "../mwbase/mechanicsmanager.hpp"
#include "../mwbase/statemanager.hpp"
#include "../mwbase/windowmanager.hpp"
#include "../mwbase/world.hpp"
#include "../mwworld/class.hpp"
#include "../mwworld/player.hpp"
#include "../mwmechanics/actorutil.hpp"
#include "../mwmechanics/creaturestats.hpp"
#include "../mwmechanics/npcstats.hpp"
#include "ref.hpp"
namespace
{
ESM::RefId getDialogueActorFaction(const MWWorld::ConstPtr& actor)
{
ESM::RefId factionId = actor.getClass().getPrimaryFaction(actor);
if (factionId.empty())
throw std::runtime_error("failed to determine dialogue actors faction (because actor is factionless)");
return factionId;
}
void modStat(MWMechanics::AttributeValue& stat, float amount)
{
const float base = stat.getBase();
const float modifier = stat.getModifier() - stat.getDamage();
const float modified = base + modifier;
// Clamp to 100 unless base < 100 and we have a fortification going
if ((modifier <= 0.f || base >= 100.f) && amount > 0.f)
amount = std::clamp(100.f - modified, 0.f, amount);
// Clamp the modified value in a way that doesn't properly account for negative numbers
float newModified = modified + amount;
if (newModified < 0.f)
{
if (modified >= 0.f)
newModified = 0.f;
else if (newModified < modified)
newModified = modified;
}
// Calculate damage/fortification based on the clamped base value
stat.setBase(std::clamp(base + amount, 0.f, 100.f), true);
stat.setModifier(newModified - stat.getBase());
}
template <class T>
void updateBaseRecord(MWWorld::Ptr& ptr)
{
const auto& store = *MWBase::Environment::get().getESMStore();
const T* base = store.get<T>().find(ptr.getCellRef().getRefId());
ptr.get<T>()->mBase = base;
}
}
namespace MWScript
{
namespace Stats
{
template <class R>
class OpGetLevel : public Interpreter::Opcode0
{
public:
void execute(Interpreter::Runtime& runtime) override
{
MWWorld::Ptr ptr = R()(runtime);
Interpreter::Type_Integer value = ptr.getClass().getCreatureStats(ptr).getLevel();
runtime.push(value);
}
};
template <class R>
class OpSetLevel : public Interpreter::Opcode0
{
public:
void execute(Interpreter::Runtime& runtime) override
{
MWWorld::Ptr ptr = R()(runtime);
Interpreter::Type_Integer value = runtime[0].mInteger;
runtime.pop();
ptr.getClass().getCreatureStats(ptr).setLevel(value);
}
};
template <class R>
class OpGetAttribute : public Interpreter::Opcode0
{
int mIndex;
public:
OpGetAttribute(int index)
: mIndex(index)
{
}
void execute(Interpreter::Runtime& runtime) override
{
MWWorld::Ptr ptr = R()(runtime);
Interpreter::Type_Float value = ptr.getClass().getCreatureStats(ptr).getAttribute(mIndex).getModified();
runtime.push(value);
}
};
template <class R>
class OpSetAttribute : public Interpreter::Opcode0
{
int mIndex;
public:
OpSetAttribute(int index)
: mIndex(index)
{
}
void execute(Interpreter::Runtime& runtime) override
{
MWWorld::Ptr ptr = R()(runtime);
Interpreter::Type_Float value = runtime[0].mFloat;
runtime.pop();
MWMechanics::AttributeValue attribute = ptr.getClass().getCreatureStats(ptr).getAttribute(mIndex);
attribute.setBase(value, true);
ptr.getClass().getCreatureStats(ptr).setAttribute(mIndex, attribute);
}
};
template <class R>
class OpModAttribute : public Interpreter::Opcode0
{
int mIndex;
public:
OpModAttribute(int index)
: mIndex(index)
{
}
void execute(Interpreter::Runtime& runtime) override
{
MWWorld::Ptr ptr = R()(runtime);
Interpreter::Type_Float value = runtime[0].mFloat;
runtime.pop();
MWMechanics::AttributeValue attribute = ptr.getClass().getCreatureStats(ptr).getAttribute(mIndex);
modStat(attribute, value);
ptr.getClass().getCreatureStats(ptr).setAttribute(mIndex, attribute);
}
};
template <class R>
class OpGetDynamic : public Interpreter::Opcode0
{
int mIndex;
public:
OpGetDynamic(int index)
: mIndex(index)
{
}
void execute(Interpreter::Runtime& runtime) override
{
MWWorld::Ptr ptr = R()(runtime);
Interpreter::Type_Float value;
if (mIndex == 0 && ptr.getClass().hasItemHealth(ptr))
{
// health is a special case
value = static_cast<Interpreter::Type_Float>(ptr.getClass().getItemMaxHealth(ptr));
}
else
{
value = ptr.getClass().getCreatureStats(ptr).getDynamic(mIndex).getCurrent();
// GetMagicka shouldn't return negative values
if (mIndex == 1 && value < 0)
value = 0;
}
runtime.push(value);
}
};
template <class R>
class OpSetDynamic : public Interpreter::Opcode0
{
int mIndex;
public:
OpSetDynamic(int index)
: mIndex(index)
{
}
void execute(Interpreter::Runtime& runtime) override
{
MWWorld::Ptr ptr = R()(runtime);
Interpreter::Type_Float value = runtime[0].mFloat;
runtime.pop();
MWMechanics::DynamicStat<float> stat(ptr.getClass().getCreatureStats(ptr).getDynamic(mIndex));
stat.setBase(value);
stat.setCurrent(stat.getModified(false), true, true);
ptr.getClass().getCreatureStats(ptr).setDynamic(mIndex, stat);
}
};
template <class R>
class OpModDynamic : public Interpreter::Opcode0
{
int mIndex;
public:
OpModDynamic(int index)
: mIndex(index)
{
}
void execute(Interpreter::Runtime& runtime) override
{
int peek = R::implicit ? 0 : runtime[0].mInteger;
MWWorld::Ptr ptr = R()(runtime);
Interpreter::Type_Float diff = runtime[0].mFloat;
runtime.pop();
// workaround broken endgame scripts that kill dagoth ur
if (!R::implicit && ptr.getCellRef().getRefId() == "dagoth_ur_1")
{
runtime.push(peek);
if (R()(runtime, false, true).isEmpty())
{
Log(Debug::Warning) << "Warning: Compensating for broken script in Morrowind.esm by "
<< "ignoring remote access to dagoth_ur_1";
return;
}
}
MWMechanics::CreatureStats& stats = ptr.getClass().getCreatureStats(ptr);
MWMechanics::DynamicStat<float> stat = stats.getDynamic(mIndex);
float current = stat.getCurrent();
float base = diff + stat.getBase();
if (mIndex != 2)
base = std::max(base, 0.f);
stat.setBase(base);
stat.setCurrent(diff + current, true, true);
stats.setDynamic(mIndex, stat);
}
};
template <class R>
class OpModCurrentDynamic : public Interpreter::Opcode0
{
int mIndex;
public:
OpModCurrentDynamic(int index)
: mIndex(index)
{
}
void execute(Interpreter::Runtime& runtime) override
{
MWWorld::Ptr ptr = R()(runtime);
Interpreter::Type_Float diff = runtime[0].mFloat;
runtime.pop();
MWMechanics::CreatureStats& stats = ptr.getClass().getCreatureStats(ptr);
Interpreter::Type_Float current = stats.getDynamic(mIndex).getCurrent();
MWMechanics::DynamicStat<float> stat(ptr.getClass().getCreatureStats(ptr).getDynamic(mIndex));
bool allowDecreaseBelowZero = false;
if (mIndex == 2) // Fatigue-specific logic
{
// For fatigue, a negative current value is allowed and means the actor will be knocked down
allowDecreaseBelowZero = true;
// Knock down the actor immediately if a non-positive new value is the case
if (diff + current <= 0.f)
ptr.getClass().getCreatureStats(ptr).setKnockedDown(true);
}
stat.setCurrent(diff + current, allowDecreaseBelowZero);
ptr.getClass().getCreatureStats(ptr).setDynamic(mIndex, stat);
}
};
template <class R>
class OpGetDynamicGetRatio : public Interpreter::Opcode0
{
int mIndex;
public:
OpGetDynamicGetRatio(int index)
: mIndex(index)
{
}
void execute(Interpreter::Runtime& runtime) override
{
MWWorld::Ptr ptr = R()(runtime);
const MWMechanics::CreatureStats& stats = ptr.getClass().getCreatureStats(ptr);
runtime.push(stats.getDynamic(mIndex).getRatio());
}
};
template <class R>
class OpGetSkill : public Interpreter::Opcode0
{
int mIndex;
public:
OpGetSkill(int index)
: mIndex(index)
{
}
void execute(Interpreter::Runtime& runtime) override
{
MWWorld::Ptr ptr = R()(runtime);
Interpreter::Type_Float value = ptr.getClass().getSkill(ptr, mIndex);
runtime.push(value);
}
};
template <class R>
class OpSetSkill : public Interpreter::Opcode0
{
int mIndex;
public:
OpSetSkill(int index)
: mIndex(index)
{
}
void execute(Interpreter::Runtime& runtime) override
{
MWWorld::Ptr ptr = R()(runtime);
Interpreter::Type_Float value = runtime[0].mFloat;
runtime.pop();
MWMechanics::NpcStats& stats = ptr.getClass().getNpcStats(ptr);
stats.getSkill(mIndex).setBase(value, true);
}
};
template <class R>
class OpModSkill : public Interpreter::Opcode0
{
int mIndex;
public:
OpModSkill(int index)
: mIndex(index)
{
}
void execute(Interpreter::Runtime& runtime) override
{
MWWorld::Ptr ptr = R()(runtime);
Interpreter::Type_Float value = runtime[0].mFloat;
runtime.pop();
MWMechanics::SkillValue& skill = ptr.getClass().getNpcStats(ptr).getSkill(mIndex);
modStat(skill, value);
}
};
class OpGetPCCrimeLevel : public Interpreter::Opcode0
{
public:
void execute(Interpreter::Runtime& runtime) override
{
MWBase::World* world = MWBase::Environment::get().getWorld();
MWWorld::Ptr player = world->getPlayerPtr();
runtime.push(static_cast<Interpreter::Type_Float>(player.getClass().getNpcStats(player).getBounty()));
}
};
class OpSetPCCrimeLevel : public Interpreter::Opcode0
{
public:
void execute(Interpreter::Runtime& runtime) override
{
MWBase::World* world = MWBase::Environment::get().getWorld();
MWWorld::Ptr player = world->getPlayerPtr();
int bounty = static_cast<int>(runtime[0].mFloat);
runtime.pop();
player.getClass().getNpcStats(player).setBounty(bounty);
if (bounty == 0)
MWBase::Environment::get().getWorld()->getPlayer().recordCrimeId();
}
};
class OpModPCCrimeLevel : public Interpreter::Opcode0
{
public:
void execute(Interpreter::Runtime& runtime) override
{
MWBase::World* world = MWBase::Environment::get().getWorld();
MWWorld::Ptr player = world->getPlayerPtr();
player.getClass().getNpcStats(player).setBounty(
static_cast<int>(runtime[0].mFloat) + player.getClass().getNpcStats(player).getBounty());
runtime.pop();
}
};
template <class R>
class OpAddSpell : public Interpreter::Opcode0
{
public:
void execute(Interpreter::Runtime& runtime) override
{
MWWorld::Ptr ptr = R()(runtime);
ESM::RefId id = ESM::RefId::stringRefId(runtime.getStringLiteral(runtime[0].mInteger));
runtime.pop();
const ESM::Spell* spell = MWBase::Environment::get().getESMStore()->get<ESM::Spell>().find(id);
MWMechanics::CreatureStats& creatureStats = ptr.getClass().getCreatureStats(ptr);
creatureStats.getSpells().add(spell);
ESM::Spell::SpellType type = static_cast<ESM::Spell::SpellType>(spell->mData.mType);
if (type != ESM::Spell::ST_Spell && type != ESM::Spell::ST_Power)
{
// Add spell effect to *this actor's* queue immediately
creatureStats.getActiveSpells().addSpell(spell, ptr);
// Apply looping particles immediately for constant effects
MWBase::Environment::get().getWorld()->applyLoopingParticles(ptr);
}
}
};
template <class R>
class OpRemoveSpell : public Interpreter::Opcode0
{
public:
void execute(Interpreter::Runtime& runtime) override
{
MWWorld::Ptr ptr = R()(runtime);
ESM::RefId id = ESM::RefId::stringRefId(runtime.getStringLiteral(runtime[0].mInteger));
runtime.pop();
MWMechanics::CreatureStats& creatureStats = ptr.getClass().getCreatureStats(ptr);
creatureStats.getSpells().remove(id);
MWBase::WindowManager* wm = MWBase::Environment::get().getWindowManager();
if (ptr == MWMechanics::getPlayer() && id == wm->getSelectedSpell())
{
wm->unsetSelectedSpell();
}
}
};
template <class R>
class OpRemoveSpellEffects : public Interpreter::Opcode0
{
public:
void execute(Interpreter::Runtime& runtime) override
{
MWWorld::Ptr ptr = R()(runtime);
ESM::RefId spellid = ESM::RefId::stringRefId(runtime.getStringLiteral(runtime[0].mInteger));
runtime.pop();
ptr.getClass().getCreatureStats(ptr).getActiveSpells().removeEffects(ptr, spellid);
}
};
template <class R>
class OpRemoveEffects : public Interpreter::Opcode0
{
public:
void execute(Interpreter::Runtime& runtime) override
{
MWWorld::Ptr ptr = R()(runtime);
Interpreter::Type_Integer effectId = runtime[0].mInteger;
runtime.pop();
ptr.getClass().getCreatureStats(ptr).getActiveSpells().purgeEffect(ptr, effectId);
}
};
template <class R>
class OpGetSpell : public Interpreter::Opcode0
{
public:
void execute(Interpreter::Runtime& runtime) override
{
MWWorld::Ptr ptr = R()(runtime);
ESM::RefId id = ESM::RefId::stringRefId(runtime.getStringLiteral(runtime[0].mInteger));
runtime.pop();
Interpreter::Type_Integer value = 0;
if (ptr.getClass().isActor() && ptr.getClass().getCreatureStats(ptr).getSpells().hasSpell(id))
value = 1;
runtime.push(value);
}
};
template <class R>
class OpPCJoinFaction : public Interpreter::Opcode1
{
public:
void execute(Interpreter::Runtime& runtime, unsigned int arg0) override
{
MWWorld::ConstPtr actor = R()(runtime, false);
ESM::RefId factionID;
if (arg0 == 0)
{
factionID = getDialogueActorFaction(actor);
}
else
{
factionID = ESM::RefId::stringRefId(runtime.getStringLiteral(runtime[0].mInteger));
runtime.pop();
}
// Make sure this faction exists
MWBase::Environment::get().getESMStore()->get<ESM::Faction>().find(factionID);
if (!factionID.empty())
{
MWWorld::Ptr player = MWMechanics::getPlayer();
player.getClass().getNpcStats(player).joinFaction(factionID);
}
}
};
template <class R>
class OpPCRaiseRank : public Interpreter::Opcode1
{
public:
void execute(Interpreter::Runtime& runtime, unsigned int arg0) override
{
MWWorld::ConstPtr actor = R()(runtime, false);
ESM::RefId factionID;
if (arg0 == 0)
{
factionID = getDialogueActorFaction(actor);
}
else
{
factionID = ESM::RefId::stringRefId(runtime.getStringLiteral(runtime[0].mInteger));
runtime.pop();
}
// Make sure this faction exists
MWBase::Environment::get().getESMStore()->get<ESM::Faction>().find(factionID);
if (!factionID.empty())
{
MWWorld::Ptr player = MWMechanics::getPlayer();
if (!player.getClass().getNpcStats(player).isInFaction(factionID))
{
player.getClass().getNpcStats(player).joinFaction(factionID);
}
else
{
player.getClass().getNpcStats(player).raiseRank(factionID);
}
}
}
};
template <class R>
class OpPCLowerRank : public Interpreter::Opcode1
{
public:
void execute(Interpreter::Runtime& runtime, unsigned int arg0) override
{
MWWorld::ConstPtr actor = R()(runtime, false);
ESM::RefId factionID;
if (arg0 == 0)
{
factionID = getDialogueActorFaction(actor);
}
else
{
factionID = ESM::RefId::stringRefId(runtime.getStringLiteral(runtime[0].mInteger));
runtime.pop();
}
// Make sure this faction exists
MWBase::Environment::get().getESMStore()->get<ESM::Faction>().find(factionID);
if (!factionID.empty())
{
MWWorld::Ptr player = MWMechanics::getPlayer();
player.getClass().getNpcStats(player).lowerRank(factionID);
}
}
};
template <class R>
class OpGetPCRank : public Interpreter::Opcode1
{
public:
void execute(Interpreter::Runtime& runtime, unsigned int arg0) override
{
MWWorld::ConstPtr ptr = R()(runtime, false);
ESM::RefId factionID;
if (arg0 > 0)
{
factionID = ESM::RefId::stringRefId(runtime.getStringLiteral(runtime[0].mInteger));
runtime.pop();
}
else
{
factionID = ptr.getClass().getPrimaryFaction(ptr);
}
// Make sure this faction exists
MWBase::Environment::get().getESMStore()->get<ESM::Faction>().find(factionID);
if (!factionID.empty())
{
MWWorld::Ptr player = MWMechanics::getPlayer();
runtime.push(player.getClass().getNpcStats(player).getFactionRank(factionID));
}
else
{
runtime.push(-1);
}
}
};
template <class R>
class OpModDisposition : public Interpreter::Opcode0
{
public:
void execute(Interpreter::Runtime& runtime) override
{
MWWorld::Ptr ptr = R()(runtime);
Interpreter::Type_Integer value = runtime[0].mInteger;
runtime.pop();
if (ptr.getClass().isNpc())
ptr.getClass().getNpcStats(ptr).setBaseDisposition(
ptr.getClass().getNpcStats(ptr).getBaseDisposition() + value);
// else: must not throw exception (used by an Almalexia dialogue script)
}
};
template <class R>
class OpSetDisposition : public Interpreter::Opcode0
{
public:
void execute(Interpreter::Runtime& runtime) override
{
MWWorld::Ptr ptr = R()(runtime);
Interpreter::Type_Integer value = runtime[0].mInteger;
runtime.pop();
if (ptr.getClass().isNpc())
ptr.getClass().getNpcStats(ptr).setBaseDisposition(value);
}
};
template <class R>
class OpGetDisposition : public Interpreter::Opcode0
{
public:
void execute(Interpreter::Runtime& runtime) override
{
MWWorld::Ptr ptr = R()(runtime);
if (!ptr.getClass().isNpc())
runtime.push(0);
else
runtime.push(MWBase::Environment::get().getMechanicsManager()->getDerivedDisposition(ptr));
}
};
class OpGetDeadCount : public Interpreter::Opcode0
{
public:
void execute(Interpreter::Runtime& runtime) override
{
ESM::RefId id = ESM::RefId::stringRefId(runtime.getStringLiteral(runtime[0].mInteger));
runtime[0].mInteger = MWBase::Environment::get().getMechanicsManager()->countDeaths(id);
}
};
template <class R>
class OpGetPCFacRep : public Interpreter::Opcode1
{
public:
void execute(Interpreter::Runtime& runtime, unsigned int arg0) override
{
MWWorld::ConstPtr ptr = R()(runtime, false);
ESM::RefId factionId;
if (arg0 == 1)
{
factionId = ESM::RefId::stringRefId(runtime.getStringLiteral(runtime[0].mInteger));
runtime.pop();
}
else
{
factionId = getDialogueActorFaction(ptr);
}
if (factionId.empty())
throw std::runtime_error("failed to determine faction");
MWWorld::Ptr player = MWMechanics::getPlayer();
runtime.push(player.getClass().getNpcStats(player).getFactionReputation(factionId));
}
};
template <class R>
class OpSetPCFacRep : public Interpreter::Opcode1
{
public:
void execute(Interpreter::Runtime& runtime, unsigned int arg0) override
{
MWWorld::ConstPtr ptr = R()(runtime, false);
Interpreter::Type_Integer value = runtime[0].mInteger;
runtime.pop();
ESM::RefId factionId;
if (arg0 == 1)
{
factionId = ESM::RefId::stringRefId(runtime.getStringLiteral(runtime[0].mInteger));
runtime.pop();
}
else
{
factionId = getDialogueActorFaction(ptr);
}
if (factionId.empty())
throw std::runtime_error("failed to determine faction");
MWWorld::Ptr player = MWMechanics::getPlayer();
player.getClass().getNpcStats(player).setFactionReputation(factionId, value);
}
};
template <class R>
class OpModPCFacRep : public Interpreter::Opcode1
{
public:
void execute(Interpreter::Runtime& runtime, unsigned int arg0) override
{
MWWorld::ConstPtr ptr = R()(runtime, false);
Interpreter::Type_Integer value = runtime[0].mInteger;
runtime.pop();
ESM::RefId factionId;
if (arg0 == 1)
{
factionId = ESM::RefId::stringRefId(runtime.getStringLiteral(runtime[0].mInteger));
runtime.pop();
}
else
{
factionId = getDialogueActorFaction(ptr);
}
if (factionId.empty())
throw std::runtime_error("failed to determine faction");
MWWorld::Ptr player = MWMechanics::getPlayer();
player.getClass().getNpcStats(player).setFactionReputation(
factionId, player.getClass().getNpcStats(player).getFactionReputation(factionId) + value);
}
};
template <class R>
class OpGetCommonDisease : public Interpreter::Opcode0
{
public:
void execute(Interpreter::Runtime& runtime) override
{
MWWorld::Ptr ptr = R()(runtime);
runtime.push(ptr.getClass().getCreatureStats(ptr).hasCommonDisease());
}
};
template <class R>
class OpGetBlightDisease : public Interpreter::Opcode0
{
public:
void execute(Interpreter::Runtime& runtime) override
{
MWWorld::Ptr ptr = R()(runtime);
runtime.push(ptr.getClass().getCreatureStats(ptr).hasBlightDisease());
}
};
template <class R>
class OpGetRace : public Interpreter::Opcode0
{
public:
void execute(Interpreter::Runtime& runtime) override
{
MWWorld::ConstPtr ptr = R()(runtime);
ESM::RefId race = ESM::RefId::stringRefId(runtime.getStringLiteral(runtime[0].mInteger));
runtime.pop();
const ESM::RefId& npcRace = ptr.get<ESM::NPC>()->mBase->mRace;
runtime.push(race == npcRace);
}
};
class OpGetWerewolfKills : public Interpreter::Opcode0
{
public:
void execute(Interpreter::Runtime& runtime) override
{
MWWorld::Ptr ptr = MWBase::Environment::get().getWorld()->getPlayerPtr();
runtime.push(ptr.getClass().getNpcStats(ptr).getWerewolfKills());
}
};
template <class R>
class OpPcExpelled : public Interpreter::Opcode1
{
public:
void execute(Interpreter::Runtime& runtime, unsigned int arg0) override
{
MWWorld::ConstPtr ptr = R()(runtime, false);
ESM::RefId factionID;
if (arg0 > 0)
{
factionID = ESM::RefId::stringRefId(runtime.getStringLiteral(runtime[0].mInteger));
runtime.pop();
}
else
{
factionID = ptr.getClass().getPrimaryFaction(ptr);
}
MWWorld::Ptr player = MWMechanics::getPlayer();
if (!factionID.empty())
{
runtime.push(player.getClass().getNpcStats(player).getExpelled(factionID));
}
else
{
runtime.push(0);
}
}
};
template <class R>
class OpPcExpell : public Interpreter::Opcode1
{
public:
void execute(Interpreter::Runtime& runtime, unsigned int arg0) override
{
MWWorld::ConstPtr ptr = R()(runtime, false);
ESM::RefId factionID;
if (arg0 > 0)
{
factionID = ESM::RefId::stringRefId(runtime.getStringLiteral(runtime[0].mInteger));
runtime.pop();
}
else
{
factionID = ptr.getClass().getPrimaryFaction(ptr);
}
MWWorld::Ptr player = MWMechanics::getPlayer();
if (!factionID.empty())
{
player.getClass().getNpcStats(player).expell(factionID);
}
}
};
template <class R>
class OpPcClearExpelled : public Interpreter::Opcode1
{
public:
void execute(Interpreter::Runtime& runtime, unsigned int arg0) override
{
MWWorld::ConstPtr ptr = R()(runtime, false);
ESM::RefId factionID;
if (arg0 > 0)
{
factionID = ESM::RefId::stringRefId(runtime.getStringLiteral(runtime[0].mInteger));
runtime.pop();
}
else
{
factionID = ptr.getClass().getPrimaryFaction(ptr);
}
MWWorld::Ptr player = MWMechanics::getPlayer();
if (!factionID.empty())
player.getClass().getNpcStats(player).clearExpelled(factionID);
}
};
template <class R>
class OpRaiseRank : public Interpreter::Opcode0
{
public:
void execute(Interpreter::Runtime& runtime) override
{
MWWorld::Ptr ptr = R()(runtime);
const ESM::RefId& factionID = ptr.getClass().getPrimaryFaction(ptr);
if (factionID.empty())
return;
MWWorld::Ptr player = MWMechanics::getPlayer();
// no-op when executed on the player
if (ptr == player)
return;
// If we already changed rank for this NPC, modify current rank in the NPC stats.
// Otherwise take rank from base NPC record, increase it and put it to NPC data.
int currentRank = ptr.getClass().getNpcStats(ptr).getFactionRank(factionID);
if (currentRank >= 0)
ptr.getClass().getNpcStats(ptr).raiseRank(factionID);
else
{
int rank = ptr.getClass().getPrimaryFactionRank(ptr);
rank++;
ptr.getClass().getNpcStats(ptr).joinFaction(factionID);
for (int i = 0; i < rank; i++)
ptr.getClass().getNpcStats(ptr).raiseRank(factionID);
}
}
};
template <class R>
class OpLowerRank : public Interpreter::Opcode0
{
public:
void execute(Interpreter::Runtime& runtime) override
{
MWWorld::Ptr ptr = R()(runtime);
const ESM::RefId& factionID = ptr.getClass().getPrimaryFaction(ptr);
if (factionID.empty())
return;
MWWorld::Ptr player = MWMechanics::getPlayer();
// no-op when executed on the player
if (ptr == player)
return;
// If we already changed rank for this NPC, modify current rank in the NPC stats.
// Otherwise take rank from base NPC record, decrease it and put it to NPC data.
int currentRank = ptr.getClass().getNpcStats(ptr).getFactionRank(factionID);
if (currentRank == 0)
return;
else if (currentRank > 0)
ptr.getClass().getNpcStats(ptr).lowerRank(factionID);
else
{
int rank = ptr.getClass().getPrimaryFactionRank(ptr);
rank--;
ptr.getClass().getNpcStats(ptr).joinFaction(factionID);
for (int i = 0; i < rank; i++)
ptr.getClass().getNpcStats(ptr).raiseRank(factionID);
}
}
};
template <class R>
class OpOnDeath : public Interpreter::Opcode0
{
public:
void execute(Interpreter::Runtime& runtime) override
{
MWWorld::Ptr ptr = R()(runtime);
Interpreter::Type_Integer value = ptr.getClass().getCreatureStats(ptr).hasDied();
if (value)
ptr.getClass().getCreatureStats(ptr).clearHasDied();
runtime.push(value);
}
};
template <class R>
class OpOnMurder : public Interpreter::Opcode0
{
public:
void execute(Interpreter::Runtime& runtime) override
{
MWWorld::Ptr ptr = R()(runtime);
Interpreter::Type_Integer value = ptr.getClass().getCreatureStats(ptr).hasBeenMurdered();
if (value)
ptr.getClass().getCreatureStats(ptr).clearHasBeenMurdered();
runtime.push(value);
}
};
template <class R>
class OpOnKnockout : public Interpreter::Opcode0
{
public:
void execute(Interpreter::Runtime& runtime) override
{
MWWorld::Ptr ptr = R()(runtime);
Interpreter::Type_Integer value = ptr.getClass().getCreatureStats(ptr).getKnockedDownOneFrame();
runtime.push(value);
}
};
template <class R>
class OpIsWerewolf : public Interpreter::Opcode0
{
public:
void execute(Interpreter::Runtime& runtime) override
{
MWWorld::Ptr ptr = R()(runtime);
runtime.push(ptr.getClass().getNpcStats(ptr).isWerewolf());
}
};
template <class R, bool set>
class OpSetWerewolf : public Interpreter::Opcode0
{
public:
void execute(Interpreter::Runtime& runtime) override
{
MWWorld::Ptr ptr = R()(runtime);
MWBase::Environment::get().getMechanicsManager()->setWerewolf(ptr, set);
}
};
template <class R>
class OpSetWerewolfAcrobatics : public Interpreter::Opcode0
{
public:
void execute(Interpreter::Runtime& runtime) override
{
MWWorld::Ptr ptr = R()(runtime);
MWBase::Environment::get().getMechanicsManager()->applyWerewolfAcrobatics(ptr);
}
};
template <class R>
class OpResurrect : public Interpreter::Opcode0
{
public:
void execute(Interpreter::Runtime& runtime) override
{
MWWorld::Ptr ptr = R()(runtime);
if (ptr == MWMechanics::getPlayer())
{
MWBase::Environment::get().getMechanicsManager()->resurrect(ptr);
if (MWBase::Environment::get().getStateManager()->getState() == MWBase::StateManager::State_Ended)
MWBase::Environment::get().getStateManager()->resumeGame();
}
else if (ptr.getClass().getCreatureStats(ptr).isDead())
{
bool wasEnabled = ptr.getRefData().isEnabled();
MWBase::Environment::get().getWorld()->undeleteObject(ptr);
auto windowManager = MWBase::Environment::get().getWindowManager();
bool wasOpen = windowManager->containsMode(MWGui::GM_Container);
windowManager->onDeleteCustomData(ptr);
// HACK: disable/enable object to re-add it to the scene properly (need a new Animation).
MWBase::Environment::get().getWorld()->disable(ptr);
// The actor's base record may have changed after this specific reference was created.
// So we need to update to the current version
if (ptr.getClass().isNpc())
updateBaseRecord<ESM::NPC>(ptr);
else
updateBaseRecord<ESM::Creature>(ptr);
if (wasOpen && !windowManager->containsMode(MWGui::GM_Container))
{
// Reopen the loot GUI if it was closed because we resurrected the actor we were looting
MWBase::Environment::get().getMechanicsManager()->resurrect(ptr);
windowManager->forceLootMode(ptr);
}
else
{
MWBase::Environment::get().getWorld()->removeContainerScripts(ptr);
// resets runtime state such as inventory, stats and AI. does not reset position in the world
ptr.getRefData().setCustomData(nullptr);
}
if (wasEnabled)
MWBase::Environment::get().getWorld()->enable(ptr);
}
}
};
template <class R>
class OpGetStat : public Interpreter::Opcode0
{
public:
void execute(Interpreter::Runtime& runtime) override
{
// dummy
runtime.pop();
runtime.push(0);
}
};
template <class R>
class OpGetMagicEffect : public Interpreter::Opcode0
{
int mPositiveEffect;
int mNegativeEffect;
public:
OpGetMagicEffect(int positiveEffect, int negativeEffect)
: mPositiveEffect(positiveEffect)
, mNegativeEffect(negativeEffect)
{
}
void execute(Interpreter::Runtime& runtime) override
{
MWWorld::Ptr ptr = R()(runtime);
const MWMechanics::MagicEffects& effects = ptr.getClass().getCreatureStats(ptr).getMagicEffects();
float currentValue = effects.get(mPositiveEffect).getMagnitude();
if (mNegativeEffect != -1)
currentValue -= effects.get(mNegativeEffect).getMagnitude();
// GetResist* should take in account elemental shields
if (mPositiveEffect == ESM::MagicEffect::ResistFire)
currentValue += effects.get(ESM::MagicEffect::FireShield).getMagnitude();
if (mPositiveEffect == ESM::MagicEffect::ResistShock)
currentValue += effects.get(ESM::MagicEffect::LightningShield).getMagnitude();
if (mPositiveEffect == ESM::MagicEffect::ResistFrost)
currentValue += effects.get(ESM::MagicEffect::FrostShield).getMagnitude();
int ret = static_cast<int>(currentValue);
runtime.push(ret);
}
};
template <class R>
class OpSetMagicEffect : public Interpreter::Opcode0
{
int mPositiveEffect;
int mNegativeEffect;
public:
OpSetMagicEffect(int positiveEffect, int negativeEffect)
: mPositiveEffect(positiveEffect)
, mNegativeEffect(negativeEffect)
{
}
void execute(Interpreter::Runtime& runtime) override
{
MWWorld::Ptr ptr = R()(runtime);
MWMechanics::MagicEffects& effects = ptr.getClass().getCreatureStats(ptr).getMagicEffects();
float currentValue = effects.get(mPositiveEffect).getMagnitude();
if (mNegativeEffect != -1)
currentValue -= effects.get(mNegativeEffect).getMagnitude();
// SetResist* should take in account elemental shields
if (mPositiveEffect == ESM::MagicEffect::ResistFire)
currentValue += effects.get(ESM::MagicEffect::FireShield).getMagnitude();
if (mPositiveEffect == ESM::MagicEffect::ResistShock)
currentValue += effects.get(ESM::MagicEffect::LightningShield).getMagnitude();
if (mPositiveEffect == ESM::MagicEffect::ResistFrost)
currentValue += effects.get(ESM::MagicEffect::FrostShield).getMagnitude();
int arg = runtime[0].mInteger;
runtime.pop();
effects.modifyBase(mPositiveEffect, (arg - static_cast<int>(currentValue)));
}
};
template <class R>
class OpModMagicEffect : public Interpreter::Opcode0
{
int mPositiveEffect;
int mNegativeEffect;
public:
OpModMagicEffect(int positiveEffect, int negativeEffect)
: mPositiveEffect(positiveEffect)
, mNegativeEffect(negativeEffect)
{
}
void execute(Interpreter::Runtime& runtime) override
{
MWWorld::Ptr ptr = R()(runtime);
MWMechanics::CreatureStats& stats = ptr.getClass().getCreatureStats(ptr);
int arg = runtime[0].mInteger;
runtime.pop();
stats.getMagicEffects().modifyBase(mPositiveEffect, arg);
}
};
class OpGetPCVisionBonus : public Interpreter::Opcode0
{
public:
void execute(Interpreter::Runtime& runtime) override
{
MWWorld::Ptr player = MWMechanics::getPlayer();
MWMechanics::EffectParam nightEye
= player.getClass().getCreatureStats(player).getMagicEffects().get(ESM::MagicEffect::NightEye);
runtime.push(std::clamp(nightEye.getMagnitude() / 100.f, 0.f, 1.f));
}
};
class OpSetPCVisionBonus : public Interpreter::Opcode0
{
public:
void execute(Interpreter::Runtime& runtime) override
{
float arg = runtime[0].mFloat;
runtime.pop();
MWWorld::Ptr player = MWMechanics::getPlayer();
auto& effects = player.getClass().getCreatureStats(player).getMagicEffects();
float delta
= std::clamp(arg * 100.f, 0.f, 100.f) - effects.get(ESM::MagicEffect::NightEye).getMagnitude();
effects.modifyBase(ESM::MagicEffect::NightEye, static_cast<int>(delta));
}
};
class OpModPCVisionBonus : public Interpreter::Opcode0
{
public:
void execute(Interpreter::Runtime& runtime) override
{
float arg = runtime[0].mFloat;
runtime.pop();
MWWorld::Ptr player = MWMechanics::getPlayer();
auto& effects = player.getClass().getCreatureStats(player).getMagicEffects();
const MWMechanics::EffectParam nightEye = effects.get(ESM::MagicEffect::NightEye);
float newBase = std::clamp(nightEye.getMagnitude() + arg * 100.f, 0.f, 100.f);
newBase -= nightEye.getModifier();
float delta = std::clamp(newBase, 0.f, 100.f) - nightEye.getMagnitude();
effects.modifyBase(ESM::MagicEffect::NightEye, static_cast<int>(delta));
}
};
struct MagicEffect
{
int mPositiveEffect;
int mNegativeEffect;
};
void installOpcodes(Interpreter::Interpreter& interpreter)
{
for (int i = 0; i < Compiler::Stats::numberOfAttributes; ++i)
{
interpreter.installSegment5<OpGetAttribute<ImplicitRef>>(Compiler::Stats::opcodeGetAttribute + i, i);
interpreter.installSegment5<OpGetAttribute<ExplicitRef>>(
Compiler::Stats::opcodeGetAttributeExplicit + i, i);
interpreter.installSegment5<OpSetAttribute<ImplicitRef>>(Compiler::Stats::opcodeSetAttribute + i, i);
interpreter.installSegment5<OpSetAttribute<ExplicitRef>>(
Compiler::Stats::opcodeSetAttributeExplicit + i, i);
interpreter.installSegment5<OpModAttribute<ImplicitRef>>(Compiler::Stats::opcodeModAttribute + i, i);
interpreter.installSegment5<OpModAttribute<ExplicitRef>>(
Compiler::Stats::opcodeModAttributeExplicit + i, i);
}
for (int i = 0; i < Compiler::Stats::numberOfDynamics; ++i)
{
interpreter.installSegment5<OpGetDynamic<ImplicitRef>>(Compiler::Stats::opcodeGetDynamic + i, i);
interpreter.installSegment5<OpGetDynamic<ExplicitRef>>(
Compiler::Stats::opcodeGetDynamicExplicit + i, i);
interpreter.installSegment5<OpSetDynamic<ImplicitRef>>(Compiler::Stats::opcodeSetDynamic + i, i);
interpreter.installSegment5<OpSetDynamic<ExplicitRef>>(
Compiler::Stats::opcodeSetDynamicExplicit + i, i);
interpreter.installSegment5<OpModDynamic<ImplicitRef>>(Compiler::Stats::opcodeModDynamic + i, i);
interpreter.installSegment5<OpModDynamic<ExplicitRef>>(
Compiler::Stats::opcodeModDynamicExplicit + i, i);
interpreter.installSegment5<OpModCurrentDynamic<ImplicitRef>>(
Compiler::Stats::opcodeModCurrentDynamic + i, i);
interpreter.installSegment5<OpModCurrentDynamic<ExplicitRef>>(
Compiler::Stats::opcodeModCurrentDynamicExplicit + i, i);
interpreter.installSegment5<OpGetDynamicGetRatio<ImplicitRef>>(
Compiler::Stats::opcodeGetDynamicGetRatio + i, i);
interpreter.installSegment5<OpGetDynamicGetRatio<ExplicitRef>>(
Compiler::Stats::opcodeGetDynamicGetRatioExplicit + i, i);
}
for (int i = 0; i < Compiler::Stats::numberOfSkills; ++i)
{
interpreter.installSegment5<OpGetSkill<ImplicitRef>>(Compiler::Stats::opcodeGetSkill + i, i);
interpreter.installSegment5<OpGetSkill<ExplicitRef>>(Compiler::Stats::opcodeGetSkillExplicit + i, i);
interpreter.installSegment5<OpSetSkill<ImplicitRef>>(Compiler::Stats::opcodeSetSkill + i, i);
interpreter.installSegment5<OpSetSkill<ExplicitRef>>(Compiler::Stats::opcodeSetSkillExplicit + i, i);
interpreter.installSegment5<OpModSkill<ImplicitRef>>(Compiler::Stats::opcodeModSkill + i, i);
interpreter.installSegment5<OpModSkill<ExplicitRef>>(Compiler::Stats::opcodeModSkillExplicit + i, i);
}
interpreter.installSegment5<OpGetPCCrimeLevel>(Compiler::Stats::opcodeGetPCCrimeLevel);
interpreter.installSegment5<OpSetPCCrimeLevel>(Compiler::Stats::opcodeSetPCCrimeLevel);
interpreter.installSegment5<OpModPCCrimeLevel>(Compiler::Stats::opcodeModPCCrimeLevel);
interpreter.installSegment5<OpAddSpell<ImplicitRef>>(Compiler::Stats::opcodeAddSpell);
interpreter.installSegment5<OpAddSpell<ExplicitRef>>(Compiler::Stats::opcodeAddSpellExplicit);
interpreter.installSegment5<OpRemoveSpell<ImplicitRef>>(Compiler::Stats::opcodeRemoveSpell);
interpreter.installSegment5<OpRemoveSpell<ExplicitRef>>(Compiler::Stats::opcodeRemoveSpellExplicit);
interpreter.installSegment5<OpRemoveSpellEffects<ImplicitRef>>(Compiler::Stats::opcodeRemoveSpellEffects);
interpreter.installSegment5<OpRemoveSpellEffects<ExplicitRef>>(
Compiler::Stats::opcodeRemoveSpellEffectsExplicit);
interpreter.installSegment5<OpResurrect<ImplicitRef>>(Compiler::Stats::opcodeResurrect);
interpreter.installSegment5<OpResurrect<ExplicitRef>>(Compiler::Stats::opcodeResurrectExplicit);
interpreter.installSegment5<OpRemoveEffects<ImplicitRef>>(Compiler::Stats::opcodeRemoveEffects);
interpreter.installSegment5<OpRemoveEffects<ExplicitRef>>(Compiler::Stats::opcodeRemoveEffectsExplicit);
interpreter.installSegment5<OpGetSpell<ImplicitRef>>(Compiler::Stats::opcodeGetSpell);
interpreter.installSegment5<OpGetSpell<ExplicitRef>>(Compiler::Stats::opcodeGetSpellExplicit);
interpreter.installSegment3<OpPCRaiseRank<ImplicitRef>>(Compiler::Stats::opcodePCRaiseRank);
interpreter.installSegment3<OpPCLowerRank<ImplicitRef>>(Compiler::Stats::opcodePCLowerRank);
interpreter.installSegment3<OpPCJoinFaction<ImplicitRef>>(Compiler::Stats::opcodePCJoinFaction);
interpreter.installSegment3<OpPCRaiseRank<ExplicitRef>>(Compiler::Stats::opcodePCRaiseRankExplicit);
interpreter.installSegment3<OpPCLowerRank<ExplicitRef>>(Compiler::Stats::opcodePCLowerRankExplicit);
interpreter.installSegment3<OpPCJoinFaction<ExplicitRef>>(Compiler::Stats::opcodePCJoinFactionExplicit);
interpreter.installSegment3<OpGetPCRank<ImplicitRef>>(Compiler::Stats::opcodeGetPCRank);
interpreter.installSegment3<OpGetPCRank<ExplicitRef>>(Compiler::Stats::opcodeGetPCRankExplicit);
interpreter.installSegment5<OpModDisposition<ImplicitRef>>(Compiler::Stats::opcodeModDisposition);
interpreter.installSegment5<OpModDisposition<ExplicitRef>>(Compiler::Stats::opcodeModDispositionExplicit);
interpreter.installSegment5<OpSetDisposition<ImplicitRef>>(Compiler::Stats::opcodeSetDisposition);
interpreter.installSegment5<OpSetDisposition<ExplicitRef>>(Compiler::Stats::opcodeSetDispositionExplicit);
interpreter.installSegment5<OpGetDisposition<ImplicitRef>>(Compiler::Stats::opcodeGetDisposition);
interpreter.installSegment5<OpGetDisposition<ExplicitRef>>(Compiler::Stats::opcodeGetDispositionExplicit);
interpreter.installSegment5<OpGetLevel<ImplicitRef>>(Compiler::Stats::opcodeGetLevel);
interpreter.installSegment5<OpGetLevel<ExplicitRef>>(Compiler::Stats::opcodeGetLevelExplicit);
interpreter.installSegment5<OpSetLevel<ImplicitRef>>(Compiler::Stats::opcodeSetLevel);
interpreter.installSegment5<OpSetLevel<ExplicitRef>>(Compiler::Stats::opcodeSetLevelExplicit);
interpreter.installSegment5<OpGetDeadCount>(Compiler::Stats::opcodeGetDeadCount);
interpreter.installSegment3<OpGetPCFacRep<ImplicitRef>>(Compiler::Stats::opcodeGetPCFacRep);
interpreter.installSegment3<OpGetPCFacRep<ExplicitRef>>(Compiler::Stats::opcodeGetPCFacRepExplicit);
interpreter.installSegment3<OpSetPCFacRep<ImplicitRef>>(Compiler::Stats::opcodeSetPCFacRep);
interpreter.installSegment3<OpSetPCFacRep<ExplicitRef>>(Compiler::Stats::opcodeSetPCFacRepExplicit);
interpreter.installSegment3<OpModPCFacRep<ImplicitRef>>(Compiler::Stats::opcodeModPCFacRep);
interpreter.installSegment3<OpModPCFacRep<ExplicitRef>>(Compiler::Stats::opcodeModPCFacRepExplicit);
interpreter.installSegment5<OpGetCommonDisease<ImplicitRef>>(Compiler::Stats::opcodeGetCommonDisease);
interpreter.installSegment5<OpGetCommonDisease<ExplicitRef>>(
Compiler::Stats::opcodeGetCommonDiseaseExplicit);
interpreter.installSegment5<OpGetBlightDisease<ImplicitRef>>(Compiler::Stats::opcodeGetBlightDisease);
interpreter.installSegment5<OpGetBlightDisease<ExplicitRef>>(
Compiler::Stats::opcodeGetBlightDiseaseExplicit);
interpreter.installSegment5<OpGetRace<ImplicitRef>>(Compiler::Stats::opcodeGetRace);
interpreter.installSegment5<OpGetRace<ExplicitRef>>(Compiler::Stats::opcodeGetRaceExplicit);
interpreter.installSegment5<OpGetWerewolfKills>(Compiler::Stats::opcodeGetWerewolfKills);
interpreter.installSegment3<OpPcExpelled<ImplicitRef>>(Compiler::Stats::opcodePcExpelled);
interpreter.installSegment3<OpPcExpelled<ExplicitRef>>(Compiler::Stats::opcodePcExpelledExplicit);
interpreter.installSegment3<OpPcExpell<ImplicitRef>>(Compiler::Stats::opcodePcExpell);
interpreter.installSegment3<OpPcExpell<ExplicitRef>>(Compiler::Stats::opcodePcExpellExplicit);
interpreter.installSegment3<OpPcClearExpelled<ImplicitRef>>(Compiler::Stats::opcodePcClearExpelled);
interpreter.installSegment3<OpPcClearExpelled<ExplicitRef>>(Compiler::Stats::opcodePcClearExpelledExplicit);
interpreter.installSegment5<OpRaiseRank<ImplicitRef>>(Compiler::Stats::opcodeRaiseRank);
interpreter.installSegment5<OpRaiseRank<ExplicitRef>>(Compiler::Stats::opcodeRaiseRankExplicit);
interpreter.installSegment5<OpLowerRank<ImplicitRef>>(Compiler::Stats::opcodeLowerRank);
interpreter.installSegment5<OpLowerRank<ExplicitRef>>(Compiler::Stats::opcodeLowerRankExplicit);
interpreter.installSegment5<OpOnDeath<ImplicitRef>>(Compiler::Stats::opcodeOnDeath);
interpreter.installSegment5<OpOnDeath<ExplicitRef>>(Compiler::Stats::opcodeOnDeathExplicit);
interpreter.installSegment5<OpOnMurder<ImplicitRef>>(Compiler::Stats::opcodeOnMurder);
interpreter.installSegment5<OpOnMurder<ExplicitRef>>(Compiler::Stats::opcodeOnMurderExplicit);
interpreter.installSegment5<OpOnKnockout<ImplicitRef>>(Compiler::Stats::opcodeOnKnockout);
interpreter.installSegment5<OpOnKnockout<ExplicitRef>>(Compiler::Stats::opcodeOnKnockoutExplicit);
interpreter.installSegment5<OpIsWerewolf<ImplicitRef>>(Compiler::Stats::opcodeIsWerewolf);
interpreter.installSegment5<OpIsWerewolf<ExplicitRef>>(Compiler::Stats::opcodeIsWerewolfExplicit);
interpreter.installSegment5<OpSetWerewolf<ImplicitRef, true>>(Compiler::Stats::opcodeBecomeWerewolf);
interpreter.installSegment5<OpSetWerewolf<ExplicitRef, true>>(
Compiler::Stats::opcodeBecomeWerewolfExplicit);
interpreter.installSegment5<OpSetWerewolf<ImplicitRef, false>>(Compiler::Stats::opcodeUndoWerewolf);
interpreter.installSegment5<OpSetWerewolf<ExplicitRef, false>>(Compiler::Stats::opcodeUndoWerewolfExplicit);
interpreter.installSegment5<OpSetWerewolfAcrobatics<ImplicitRef>>(
Compiler::Stats::opcodeSetWerewolfAcrobatics);
interpreter.installSegment5<OpSetWerewolfAcrobatics<ExplicitRef>>(
Compiler::Stats::opcodeSetWerewolfAcrobaticsExplicit);
interpreter.installSegment5<OpGetStat<ImplicitRef>>(Compiler::Stats::opcodeGetStat);
interpreter.installSegment5<OpGetStat<ExplicitRef>>(Compiler::Stats::opcodeGetStatExplicit);
static const MagicEffect sMagicEffects[] = {
{ ESM::MagicEffect::ResistMagicka, ESM::MagicEffect::WeaknessToMagicka },
{ ESM::MagicEffect::ResistFire, ESM::MagicEffect::WeaknessToFire },
{ ESM::MagicEffect::ResistFrost, ESM::MagicEffect::WeaknessToFrost },
{ ESM::MagicEffect::ResistShock, ESM::MagicEffect::WeaknessToShock },
{ ESM::MagicEffect::ResistCommonDisease, ESM::MagicEffect::WeaknessToCommonDisease },
{ ESM::MagicEffect::ResistBlightDisease, ESM::MagicEffect::WeaknessToBlightDisease },
{ ESM::MagicEffect::ResistCorprusDisease, ESM::MagicEffect::WeaknessToCorprusDisease },
{ ESM::MagicEffect::ResistPoison, ESM::MagicEffect::WeaknessToPoison },
{ ESM::MagicEffect::ResistParalysis, -1 },
{ ESM::MagicEffect::ResistNormalWeapons, ESM::MagicEffect::WeaknessToNormalWeapons },
{ ESM::MagicEffect::WaterBreathing, -1 },
{ ESM::MagicEffect::Chameleon, -1 },
{ ESM::MagicEffect::WaterWalking, -1 },
{ ESM::MagicEffect::SwiftSwim, -1 },
{ ESM::MagicEffect::Jump, -1 },
{ ESM::MagicEffect::Levitate, -1 },
{ ESM::MagicEffect::Shield, -1 },
{ ESM::MagicEffect::Sound, -1 },
{ ESM::MagicEffect::Silence, -1 },
{ ESM::MagicEffect::Blind, -1 },
{ ESM::MagicEffect::Paralyze, -1 },
{ ESM::MagicEffect::Invisibility, -1 },
{ ESM::MagicEffect::FortifyAttack, -1 },
{ ESM::MagicEffect::Sanctuary, -1 },
};
for (int i = 0; i < 24; ++i)
{
int positive = sMagicEffects[i].mPositiveEffect;
int negative = sMagicEffects[i].mNegativeEffect;
interpreter.installSegment5<OpGetMagicEffect<ImplicitRef>>(
Compiler::Stats::opcodeGetMagicEffect + i, positive, negative);
interpreter.installSegment5<OpGetMagicEffect<ExplicitRef>>(
Compiler::Stats::opcodeGetMagicEffectExplicit + i, positive, negative);
interpreter.installSegment5<OpSetMagicEffect<ImplicitRef>>(
Compiler::Stats::opcodeSetMagicEffect + i, positive, negative);
interpreter.installSegment5<OpSetMagicEffect<ExplicitRef>>(
Compiler::Stats::opcodeSetMagicEffectExplicit + i, positive, negative);
interpreter.installSegment5<OpModMagicEffect<ImplicitRef>>(
Compiler::Stats::opcodeModMagicEffect + i, positive, negative);
interpreter.installSegment5<OpModMagicEffect<ExplicitRef>>(
Compiler::Stats::opcodeModMagicEffectExplicit + i, positive, negative);
}
interpreter.installSegment5<OpGetPCVisionBonus>(Compiler::Stats::opcodeGetPCVisionBonus);
interpreter.installSegment5<OpSetPCVisionBonus>(Compiler::Stats::opcodeSetPCVisionBonus);
interpreter.installSegment5<OpModPCVisionBonus>(Compiler::Stats::opcodeModPCVisionBonus);
}
}
}