1
0
mirror of https://gitlab.com/OpenMW/openmw.git synced 2025-04-07 13:20:25 +00:00
OpenMW/apps/openmw/mwscript/statsextensions.cpp
florent.teppe 65cdd489fb create a specific esm reader function for RefID to avoid allocation for string and then again for RefId
Fixed some types

removed useless header

applied clang format

fixed compile tests

fixed clang tidy, and closer to logic before this MR

Removed hardcoded refids

unless there is a returned value we don't use static RefIds
can use == between RefId and hardcoded string

Fix clang format

Fixed a few instances where std::string was used, when only const std::string& was needed

removed unused variable
2022-12-27 19:15:57 +01:00

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
{
const ESM::RefId& getDialogueActorFaction(const MWWorld::ConstPtr& actor)
{
const 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().getWorld()->getStore();
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().getWorld()->getStore().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().getWorld()->getStore().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().getWorld()->getStore().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().getWorld()->getStore().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().getWorld()->getStore().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);
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);
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);
}
}
}