#include "miscextensions.hpp" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "../mwbase/environment.hpp" #include "../mwbase/luamanager.hpp" #include "../mwbase/mechanicsmanager.hpp" #include "../mwbase/scriptmanager.hpp" #include "../mwbase/soundmanager.hpp" #include "../mwbase/windowmanager.hpp" #include "../mwbase/world.hpp" #include "../mwworld/cellstore.hpp" #include "../mwworld/class.hpp" #include "../mwworld/containerstore.hpp" #include "../mwworld/esmstore.hpp" #include "../mwworld/inventorystore.hpp" #include "../mwworld/manualref.hpp" #include "../mwworld/player.hpp" #include "../mwmechanics/actorutil.hpp" #include "../mwmechanics/aicast.hpp" #include "../mwmechanics/creaturestats.hpp" #include "../mwmechanics/npcstats.hpp" #include "../mwmechanics/spellcasting.hpp" #include "../mwrender/animation.hpp" #include "interpretercontext.hpp" #include "ref.hpp" namespace { struct TextureFetchVisitor : osg::NodeVisitor { std::vector> mTextures; TextureFetchVisitor(osg::NodeVisitor::TraversalMode mode = TRAVERSE_ALL_CHILDREN) : osg::NodeVisitor(mode) { } void apply(osg::Node& node) override { const osg::StateSet* stateset = node.getStateSet(); if (stateset) { const osg::StateSet::TextureAttributeList& texAttributes = stateset->getTextureAttributeList(); for (size_t i = 0; i < texAttributes.size(); i++) { const osg::StateAttribute* attr = stateset->getTextureAttribute(i, osg::StateAttribute::TEXTURE); if (!attr) continue; const osg::Texture* texture = attr->asTexture(); if (!texture) continue; const osg::Image* image = texture->getImage(0); std::string fileName; if (image) fileName = image->getFileName(); mTextures.emplace_back(SceneUtil::getTextureType(*stateset, *texture, i), fileName); } } traverse(node); } }; void addToLevList(ESM::LevelledListBase* list, const ESM::RefId& itemId, int level) { for (auto& levelItem : list->mList) { if (levelItem.mLevel == level && itemId == levelItem.mId) return; } ESM::LevelledListBase::LevelItem item; item.mId = itemId; item.mLevel = level; list->mList.push_back(item); } void removeFromLevList(ESM::LevelledListBase* list, const ESM::RefId& itemId, int level) { // level of -1 removes all items with that itemId for (std::vector::iterator it = list->mList.begin(); it != list->mList.end();) { if (level != -1 && it->mLevel != level) { ++it; continue; } if (itemId == it->mId) it = list->mList.erase(it); else ++it; } } } namespace MWScript { namespace Misc { class OpMenuMode : public Interpreter::Opcode0 { public: void execute(Interpreter::Runtime& runtime) override { runtime.push(MWBase::Environment::get().getWindowManager()->isGuiMode()); } }; class OpRandom : public Interpreter::Opcode0 { public: void execute(Interpreter::Runtime& runtime) override { Interpreter::Type_Integer limit = runtime[0].mInteger; runtime.pop(); if (limit < 0) throw std::runtime_error("random: argument out of range (Don't be so negative!)"); auto& prng = MWBase::Environment::get().getWorld()->getPrng(); runtime.push(static_cast(::Misc::Rng::rollDice(limit, prng))); // [o, limit) } }; template class OpStartScript : public Interpreter::Opcode0 { public: void execute(Interpreter::Runtime& runtime) override { MWWorld::Ptr target = R()(runtime, false); ESM::RefId name = ESM::RefId::stringRefId(runtime.getStringLiteral(runtime[0].mInteger)); runtime.pop(); if (!MWBase::Environment::get().getESMStore()->get().search(name)) { runtime.getContext().report( "Failed to start global script '" + name.getRefIdString() + "': script record not found"); return; } MWBase::Environment::get().getScriptManager()->getGlobalScripts().addScript(name, target); } }; class OpScriptRunning : public Interpreter::Opcode0 { public: void execute(Interpreter::Runtime& runtime) override { const ESM::RefId& name = ESM::RefId::stringRefId(runtime.getStringLiteral(runtime[0].mInteger)); runtime.pop(); runtime.push(MWBase::Environment::get().getScriptManager()->getGlobalScripts().isRunning(name)); } }; class OpStopScript : public Interpreter::Opcode0 { public: void execute(Interpreter::Runtime& runtime) override { const ESM::RefId& name = ESM::RefId::stringRefId(runtime.getStringLiteral(runtime[0].mInteger)); runtime.pop(); if (!MWBase::Environment::get().getESMStore()->get().search(name)) { runtime.getContext().report( "Failed to stop global script '" + name.getRefIdString() + "': script record not found"); return; } MWBase::Environment::get().getScriptManager()->getGlobalScripts().removeScript(name); } }; class OpGetSecondsPassed : public Interpreter::Opcode0 { public: void execute(Interpreter::Runtime& runtime) override { runtime.push(MWBase::Environment::get().getFrameDuration()); } }; template class OpEnable : public Interpreter::Opcode0 { public: void execute(Interpreter::Runtime& runtime) override { MWWorld::Ptr ptr = R()(runtime); MWBase::Environment::get().getWorld()->enable(ptr); } }; template class OpDisable : public Interpreter::Opcode0 { public: void execute(Interpreter::Runtime& runtime) override { MWWorld::Ptr ptr = R()(runtime); MWBase::Environment::get().getWorld()->disable(ptr); } }; template class OpGetDisabled : public Interpreter::Opcode0 { public: void execute(Interpreter::Runtime& runtime) override { MWWorld::Ptr ptr = R()(runtime); runtime.push(!ptr.getRefData().isEnabled()); } }; class OpPlayBink : public Interpreter::Opcode0 { public: void execute(Interpreter::Runtime& runtime) override { std::string_view name = runtime.getStringLiteral(runtime[0].mInteger); runtime.pop(); bool allowSkipping = runtime[0].mInteger != 0; runtime.pop(); MWBase::Environment::get().getWindowManager()->playVideo(name, allowSkipping); } }; class OpGetPcSleep : public Interpreter::Opcode0 { public: void execute(Interpreter::Runtime& runtime) override { runtime.push(MWBase::Environment::get().getWindowManager()->getPlayerSleeping()); } }; class OpGetPcJumping : public Interpreter::Opcode0 { public: void execute(Interpreter::Runtime& runtime) override { MWBase::World* world = MWBase::Environment::get().getWorld(); runtime.push(world->getPlayer().getJumping()); } }; class OpWakeUpPc : public Interpreter::Opcode0 { public: void execute(Interpreter::Runtime& runtime) override { MWBase::Environment::get().getWindowManager()->wakeUpPlayer(); } }; class OpXBox : public Interpreter::Opcode0 { public: void execute(Interpreter::Runtime& runtime) override { runtime.push(0); } }; template class OpOnActivate : public Interpreter::Opcode0 { public: void execute(Interpreter::Runtime& runtime) override { MWWorld::Ptr ptr = R()(runtime); runtime.push(ptr.getRefData().onActivate()); } }; template class OpActivate : public Interpreter::Opcode0 { public: void execute(Interpreter::Runtime& runtime) override { InterpreterContext& context = static_cast(runtime.getContext()); MWWorld::Ptr ptr = R()(runtime); if (ptr.getRefData().activateByScript() || ptr.getContainerStore()) context.executeActivation(ptr, MWMechanics::getPlayer()); } }; template class OpLock : public Interpreter::Opcode1 { public: void execute(Interpreter::Runtime& runtime, unsigned int arg0) override { MWWorld::Ptr ptr = R()(runtime); Interpreter::Type_Integer lockLevel = ptr.getCellRef().getLockLevel(); if (lockLevel == 0) { // no lock level was ever set, set to 100 as default lockLevel = 100; } if (arg0 == 1) { lockLevel = runtime[0].mInteger; runtime.pop(); } ptr.getCellRef().lock(lockLevel); // Instantly reset door to closed state // This is done when using Lock in scripts, but not when using Lock spells. if (ptr.getType() == ESM::Door::sRecordId && !ptr.getCellRef().getTeleport()) { MWBase::Environment::get().getWorld()->activateDoor(ptr, MWWorld::DoorState::Idle); } } }; template class OpUnlock : public Interpreter::Opcode0 { public: void execute(Interpreter::Runtime& runtime) override { MWWorld::Ptr ptr = R()(runtime); if (ptr.getCellRef().isLocked()) ptr.getCellRef().unlock(); } }; class OpToggleCollisionDebug : public Interpreter::Opcode0 { public: void execute(Interpreter::Runtime& runtime) override { bool enabled = MWBase::Environment::get().getWorld()->toggleRenderMode(MWRender::Render_CollisionDebug); runtime.getContext().report( enabled ? "Collision Mesh Rendering -> On" : "Collision Mesh Rendering -> Off"); } }; class OpToggleCollisionBoxes : public Interpreter::Opcode0 { public: void execute(Interpreter::Runtime& runtime) override { bool enabled = MWBase::Environment::get().getWorld()->toggleRenderMode(MWRender::Render_CollisionDebug); runtime.getContext().report( enabled ? "Collision Mesh Rendering -> On" : "Collision Mesh Rendering -> Off"); } }; class OpToggleWireframe : public Interpreter::Opcode0 { public: void execute(Interpreter::Runtime& runtime) override { bool enabled = MWBase::Environment::get().getWorld()->toggleRenderMode(MWRender::Render_Wireframe); runtime.getContext().report(enabled ? "Wireframe Rendering -> On" : "Wireframe Rendering -> Off"); } }; class OpToggleBorders : public Interpreter::Opcode0 { public: void execute(Interpreter::Runtime& runtime) override { bool enabled = MWBase::Environment::get().getWorld()->toggleBorders(); runtime.getContext().report(enabled ? "Border Rendering -> On" : "Border Rendering -> Off"); } }; class OpTogglePathgrid : public Interpreter::Opcode0 { public: void execute(Interpreter::Runtime& runtime) override { bool enabled = MWBase::Environment::get().getWorld()->toggleRenderMode(MWRender::Render_Pathgrid); runtime.getContext().report(enabled ? "Path Grid rendering -> On" : "Path Grid Rendering -> Off"); } }; class OpFadeIn : public Interpreter::Opcode0 { public: void execute(Interpreter::Runtime& runtime) override { Interpreter::Type_Float time = runtime[0].mFloat; runtime.pop(); MWBase::Environment::get().getWindowManager()->fadeScreenIn(time, false); } }; class OpFadeOut : public Interpreter::Opcode0 { public: void execute(Interpreter::Runtime& runtime) override { Interpreter::Type_Float time = runtime[0].mFloat; runtime.pop(); MWBase::Environment::get().getWindowManager()->fadeScreenOut(time, false); } }; class OpFadeTo : public Interpreter::Opcode0 { public: void execute(Interpreter::Runtime& runtime) override { Interpreter::Type_Float alpha = runtime[0].mFloat; runtime.pop(); Interpreter::Type_Float time = runtime[0].mFloat; runtime.pop(); MWBase::Environment::get().getWindowManager()->fadeScreenTo(static_cast(alpha), time, false); } }; class OpToggleWater : public Interpreter::Opcode0 { public: void execute(Interpreter::Runtime& runtime) override { runtime.getContext().report( MWBase::Environment::get().getWorld()->toggleWater() ? "Water -> On" : "Water -> Off"); } }; class OpToggleWorld : public Interpreter::Opcode0 { public: void execute(Interpreter::Runtime& runtime) override { runtime.getContext().report( MWBase::Environment::get().getWorld()->toggleWorld() ? "World -> On" : "World -> Off"); } }; class OpDontSaveObject : public Interpreter::Opcode0 { public: void execute(Interpreter::Runtime& runtime) override { // We are ignoring the DontSaveObject statement for now. Probably not worth // bothering with. The incompatibility we are creating should be marginal at most. } }; class OpPcForce1stPerson : public Interpreter::Opcode0 { public: void execute(Interpreter::Runtime& runtime) override { if (!MWBase::Environment::get().getWorld()->isFirstPerson()) MWBase::Environment::get().getWorld()->togglePOV(true); } }; class OpPcForce3rdPerson : public Interpreter::Opcode0 { void execute(Interpreter::Runtime& runtime) override { if (MWBase::Environment::get().getWorld()->isFirstPerson()) MWBase::Environment::get().getWorld()->togglePOV(true); } }; class OpPcGet3rdPerson : public Interpreter::Opcode0 { public: void execute(Interpreter::Runtime& runtime) override { runtime.push(!MWBase::Environment::get().getWorld()->isFirstPerson()); } }; class OpToggleVanityMode : public Interpreter::Opcode0 { static bool sActivate; public: void execute(Interpreter::Runtime& runtime) override { MWBase::World* world = MWBase::Environment::get().getWorld(); if (world->toggleVanityMode(sActivate)) { runtime.getContext().report(sActivate ? "Vanity Mode -> On" : "Vanity Mode -> Off"); sActivate = !sActivate; } else { runtime.getContext().report("Vanity Mode -> No"); } } }; bool OpToggleVanityMode::sActivate = true; template class OpGetLocked : public Interpreter::Opcode0 { public: void execute(Interpreter::Runtime& runtime) override { MWWorld::Ptr ptr = R()(runtime); runtime.push(ptr.getCellRef().isLocked()); } }; template class OpGetEffect : public Interpreter::Opcode0 { public: void execute(Interpreter::Runtime& runtime) override { MWWorld::Ptr ptr = R()(runtime); std::string_view effect = runtime.getStringLiteral(runtime[0].mInteger); runtime.pop(); if (!ptr.getClass().isActor()) { runtime.push(0); return; } long key; if (const auto k = ::Misc::StringUtils::toNumeric(effect.data()); k.has_value() && *k >= 0 && *k <= 32767) key = *k; else key = ESM::MagicEffect::effectGmstIdToIndex(effect); const MWMechanics::CreatureStats& stats = ptr.getClass().getCreatureStats(ptr); const MWMechanics::MagicEffects& effects = stats.getMagicEffects(); for (const auto& activeEffect : effects) { if (activeEffect.first.mId == key && activeEffect.second.getModifier() > 0) { runtime.push(1); return; } } runtime.push(0); } }; template class OpAddSoulGem : public Interpreter::Opcode0 { public: void execute(Interpreter::Runtime& runtime) override { MWWorld::Ptr ptr = R()(runtime); ESM::RefId creature = ESM::RefId::stringRefId(runtime.getStringLiteral(runtime[0].mInteger)); runtime.pop(); ESM::RefId gem = ESM::RefId::stringRefId(runtime.getStringLiteral(runtime[0].mInteger)); runtime.pop(); if (!ptr.getClass().isActor()) return; const MWWorld::ESMStore& store = *MWBase::Environment::get().getESMStore(); store.get().find( creature); // This line throws an exception if it can't find the creature MWWorld::Ptr item = *ptr.getClass().getContainerStore(ptr).add(gem, 1); // Set the soul on just one of the gems, not the whole stack item.getContainerStore()->unstack(item); item.getCellRef().setSoul(creature); // Restack the gem with other gems with the same soul item.getContainerStore()->restack(item); } }; template class OpRemoveSoulGem : public Interpreter::Opcode1 { public: void execute(Interpreter::Runtime& runtime, unsigned int arg0) override { MWWorld::Ptr ptr = R()(runtime); ESM::RefId soul = ESM::RefId::stringRefId(runtime.getStringLiteral(runtime[0].mInteger)); runtime.pop(); // throw away additional arguments for (unsigned int i = 0; i < arg0; ++i) runtime.pop(); if (!ptr.getClass().isActor()) return; MWWorld::ContainerStore& store = ptr.getClass().getContainerStore(ptr); for (MWWorld::ContainerStoreIterator it = store.begin(); it != store.end(); ++it) { if (it->getCellRef().getSoul() == soul) { store.remove(*it, 1); return; } } } }; template class OpDrop : public Interpreter::Opcode0 { public: void execute(Interpreter::Runtime& runtime) override { MWWorld::Ptr ptr = R()(runtime); ESM::RefId item = ESM::RefId::stringRefId(runtime.getStringLiteral(runtime[0].mInteger)); runtime.pop(); Interpreter::Type_Integer amount = runtime[0].mInteger; runtime.pop(); if (amount < 0) throw std::runtime_error("amount must be non-negative"); // no-op if (amount == 0) return; if (!ptr.getClass().isActor()) return; MWWorld::InventoryStore* invStorePtr = nullptr; if (ptr.getClass().hasInventoryStore(ptr)) { invStorePtr = &ptr.getClass().getInventoryStore(ptr); // Prefer dropping unequipped items first; re-stack if possible by unequipping items before dropping // them. int numNotEquipped = invStorePtr->count(item); for (int slot = 0; slot < MWWorld::InventoryStore::Slots; ++slot) { MWWorld::ConstContainerStoreIterator it = invStorePtr->getSlot(slot); if (it != invStorePtr->end() && it->getCellRef().getRefId() == item) { numNotEquipped -= it->getCellRef().getCount(); } } for (int slot = 0; slot < MWWorld::InventoryStore::Slots && amount > numNotEquipped; ++slot) { MWWorld::ContainerStoreIterator it = invStorePtr->getSlot(slot); if (it != invStorePtr->end() && it->getCellRef().getRefId() == item) { int numToRemove = std::min(amount - numNotEquipped, it->getCellRef().getCount()); invStorePtr->unequipItemQuantity(*it, numToRemove); numNotEquipped += numToRemove; } } } MWWorld::ContainerStore& store = ptr.getClass().getContainerStore(ptr); for (MWWorld::ContainerStoreIterator iter(store.begin()); iter != store.end(); ++iter) { if (iter->getCellRef().getRefId() == item && (!invStorePtr || !invStorePtr->isEquipped(*iter))) { int removed = store.remove(*iter, amount); MWWorld::Ptr dropped = MWBase::Environment::get().getWorld()->dropObjectOnGround(ptr, *iter, removed); dropped.getCellRef().setOwner(ESM::RefId()); amount -= removed; if (amount <= 0) break; } } MWWorld::ManualRef ref(*MWBase::Environment::get().getESMStore(), item, 1); MWWorld::Ptr itemPtr(ref.getPtr()); if (amount > 0) { if (itemPtr.getClass().getScript(itemPtr).empty()) { MWBase::Environment::get().getWorld()->dropObjectOnGround(ptr, itemPtr, amount); } else { // Dropping one item per time to prevent making stacks of scripted items for (int i = 0; i < amount; i++) MWBase::Environment::get().getWorld()->dropObjectOnGround(ptr, itemPtr, 1); } } MWBase::Environment::get().getSoundManager()->playSound3D( ptr, itemPtr.getClass().getDownSoundId(itemPtr), 1.f, 1.f); } }; template class OpDropSoulGem : public Interpreter::Opcode0 { public: void execute(Interpreter::Runtime& runtime) override { MWWorld::Ptr ptr = R()(runtime); ESM::RefId soul = ESM::RefId::stringRefId(runtime.getStringLiteral(runtime[0].mInteger)); runtime.pop(); if (!ptr.getClass().isActor()) return; MWWorld::ContainerStore& store = ptr.getClass().getContainerStore(ptr); for (MWWorld::ContainerStoreIterator iter(store.begin()); iter != store.end(); ++iter) { if (iter->getCellRef().getSoul() == soul) { MWBase::Environment::get().getWorld()->dropObjectOnGround(ptr, *iter, 1); store.remove(*iter, 1); break; } } } }; template class OpGetAttacked : public Interpreter::Opcode0 { public: void execute(Interpreter::Runtime& runtime) override { MWWorld::Ptr ptr = R()(runtime); runtime.push(ptr.getClass().getCreatureStats(ptr).getAttacked()); } }; template class OpGetWeaponDrawn : public Interpreter::Opcode0 { public: void execute(Interpreter::Runtime& runtime) override { MWWorld::Ptr ptr = R()(runtime); auto& cls = ptr.getClass(); if (!cls.hasInventoryStore(ptr) && !cls.isBipedal(ptr)) { runtime.push(0); return; } if (cls.getCreatureStats(ptr).getDrawState() != MWMechanics::DrawState::Weapon) { runtime.push(0); return; } MWRender::Animation* anim = MWBase::Environment::get().getWorld()->getAnimation(ptr); runtime.push(anim && anim->getWeaponsShown()); } }; template class OpGetSpellReadied : public Interpreter::Opcode0 { public: void execute(Interpreter::Runtime& runtime) override { MWWorld::Ptr ptr = R()(runtime); runtime.push(ptr.getClass().getCreatureStats(ptr).getDrawState() == MWMechanics::DrawState::Spell); } }; template class OpGetSpellEffects : 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(); if (!ptr.getClass().isActor()) { runtime.push(0); return; } const MWMechanics::CreatureStats& stats = ptr.getClass().getCreatureStats(ptr); runtime.push(stats.getActiveSpells().isSpellActive(id)); } }; class OpGetCurrentTime : public Interpreter::Opcode0 { public: void execute(Interpreter::Runtime& runtime) override { runtime.push(MWBase::Environment::get().getWorld()->getTimeStamp().getHour()); } }; template class OpSetDelete : public Interpreter::Opcode0 { public: void execute(Interpreter::Runtime& runtime) override { MWWorld::Ptr ptr = R()(runtime); int parameter = runtime[0].mInteger; runtime.pop(); if (parameter == 1) MWBase::Environment::get().getWorld()->deleteObject(ptr); else if (parameter == 0) MWBase::Environment::get().getWorld()->undeleteObject(ptr); else throw std::runtime_error("SetDelete: unexpected parameter"); } }; class OpGetSquareRoot : public Interpreter::Opcode0 { public: void execute(Interpreter::Runtime& runtime) override { float param = runtime[0].mFloat; runtime.pop(); if (param < 0) throw std::runtime_error("square root of negative number (we aren't that imaginary)"); runtime.push(std::sqrt(param)); } }; template class OpFall : public Interpreter::Opcode0 { public: void execute(Interpreter::Runtime& runtime) override {} }; template class OpGetStandingPc : public Interpreter::Opcode0 { public: void execute(Interpreter::Runtime& runtime) override { MWWorld::Ptr ptr = R()(runtime); runtime.push(MWBase::Environment::get().getWorld()->getPlayerStandingOn(ptr)); } }; template class OpGetStandingActor : public Interpreter::Opcode0 { public: void execute(Interpreter::Runtime& runtime) override { MWWorld::Ptr ptr = R()(runtime); runtime.push(MWBase::Environment::get().getWorld()->getActorStandingOn(ptr)); } }; template class OpGetCollidingPc : public Interpreter::Opcode0 { public: void execute(Interpreter::Runtime& runtime) override { MWWorld::Ptr ptr = R()(runtime); runtime.push(MWBase::Environment::get().getWorld()->getPlayerCollidingWith(ptr)); } }; template class OpGetCollidingActor : public Interpreter::Opcode0 { public: void execute(Interpreter::Runtime& runtime) override { MWWorld::Ptr ptr = R()(runtime); runtime.push(MWBase::Environment::get().getWorld()->getActorCollidingWith(ptr)); } }; template class OpHurtStandingActor : public Interpreter::Opcode0 { public: void execute(Interpreter::Runtime& runtime) override { MWWorld::Ptr ptr = R()(runtime); float healthDiffPerSecond = runtime[0].mFloat; runtime.pop(); MWBase::Environment::get().getWorld()->hurtStandingActors(ptr, healthDiffPerSecond); } }; template class OpHurtCollidingActor : public Interpreter::Opcode0 { public: void execute(Interpreter::Runtime& runtime) override { MWWorld::Ptr ptr = R()(runtime); float healthDiffPerSecond = runtime[0].mFloat; runtime.pop(); MWBase::Environment::get().getWorld()->hurtCollidingActors(ptr, healthDiffPerSecond); } }; class OpGetWindSpeed : public Interpreter::Opcode0 { public: void execute(Interpreter::Runtime& runtime) override { runtime.push(MWBase::Environment::get().getWorld()->getWindSpeed()); } }; template class OpHitOnMe : public Interpreter::Opcode0 { public: void execute(Interpreter::Runtime& runtime) override { MWWorld::Ptr ptr = R()(runtime); ESM::RefId objectID = ESM::RefId::stringRefId(runtime.getStringLiteral(runtime[0].mInteger)); runtime.pop(); MWMechanics::CreatureStats& stats = ptr.getClass().getCreatureStats(ptr); bool hit = objectID == stats.getLastHitObject(); runtime.push(hit); if (hit) stats.clearLastHitObject(); } }; template class OpHitAttemptOnMe : public Interpreter::Opcode0 { public: void execute(Interpreter::Runtime& runtime) override { MWWorld::Ptr ptr = R()(runtime); ESM::RefId objectID = ESM::RefId::stringRefId(runtime.getStringLiteral(runtime[0].mInteger)); runtime.pop(); MWMechanics::CreatureStats& stats = ptr.getClass().getCreatureStats(ptr); bool hit = objectID == stats.getLastHitAttemptObject(); runtime.push(hit); if (hit) stats.clearLastHitAttemptObject(); } }; template class OpEnableTeleporting : public Interpreter::Opcode0 { public: void execute(Interpreter::Runtime& runtime) override { MWBase::World* world = MWBase::Environment::get().getWorld(); world->enableTeleporting(Enable); } }; template class OpEnableLevitation : public Interpreter::Opcode0 { public: void execute(Interpreter::Runtime& runtime) override { MWBase::World* world = MWBase::Environment::get().getWorld(); world->enableLevitation(Enable); } }; template class OpShow : public Interpreter::Opcode0 { public: void execute(Interpreter::Runtime& runtime) override { MWWorld::Ptr ptr = R()(runtime, false); std::string_view var = runtime.getStringLiteral(runtime[0].mInteger); runtime.pop(); std::stringstream output; if (!ptr.isEmpty()) { ESM::RefId script = ESM::RefId::stringRefId(runtime.getStringLiteral(runtime[0].mInteger)); if (!script.empty()) { const Compiler::Locals& locals = MWBase::Environment::get().getScriptManager()->getLocals(script); char type = locals.getType(var); std::string refId = ptr.getCellRef().getRefId().getRefIdString(); if (refId.find(' ') != std::string::npos) refId = '"' + refId + '"'; switch (type) { case 'l': case 's': output << refId << "." << var << " = " << ptr.getRefData().getLocals().getIntVar(script, var); break; case 'f': output << refId << "." << var << " = " << ptr.getRefData().getLocals().getFloatVar(script, var); break; } } } if (output.rdbuf()->in_avail() == 0) { MWBase::World* world = MWBase::Environment::get().getWorld(); char type = world->getGlobalVariableType(var); switch (type) { case 's': output << var << " = " << runtime.getContext().getGlobalShort(var); break; case 'l': output << var << " = " << runtime.getContext().getGlobalLong(var); break; case 'f': output << var << " = " << runtime.getContext().getGlobalFloat(var); break; default: output << "unknown variable"; } } runtime.getContext().report(output.str()); } }; template class OpShowVars : public Interpreter::Opcode0 { void printLocalVars(Interpreter::Runtime& runtime, const MWWorld::Ptr& ptr) { std::stringstream str; const ESM::RefId& script = ptr.getClass().getScript(ptr); if (script.empty()) str << ptr.getCellRef().getRefId() << " does not have a script."; else { str << "Local variables for " << ptr.getCellRef().getRefId(); const Locals& locals = ptr.getRefData().getLocals(); const Compiler::Locals& complocals = MWBase::Environment::get().getScriptManager()->getLocals(script); const std::vector* names = &complocals.get('s'); for (size_t i = 0; i < names->size(); ++i) { if (i >= locals.mShorts.size()) break; str << std::endl << " " << (*names)[i] << " = " << locals.mShorts[i] << " (short)"; } names = &complocals.get('l'); for (size_t i = 0; i < names->size(); ++i) { if (i >= locals.mLongs.size()) break; str << std::endl << " " << (*names)[i] << " = " << locals.mLongs[i] << " (long)"; } names = &complocals.get('f'); for (size_t i = 0; i < names->size(); ++i) { if (i >= locals.mFloats.size()) break; str << std::endl << " " << (*names)[i] << " = " << locals.mFloats[i] << " (float)"; } } runtime.getContext().report(str.str()); } void printGlobalVars(Interpreter::Runtime& runtime) { std::stringstream str; str << "Global variables:"; MWBase::World* world = MWBase::Environment::get().getWorld(); std::vector names = runtime.getContext().getGlobals(); for (size_t i = 0; i < names.size(); ++i) { char type = world->getGlobalVariableType(names[i]); str << std::endl << " " << names[i] << " = "; switch (type) { case 's': str << runtime.getContext().getGlobalShort(names[i]) << " (short)"; break; case 'l': str << runtime.getContext().getGlobalLong(names[i]) << " (long)"; break; case 'f': str << runtime.getContext().getGlobalFloat(names[i]) << " (float)"; break; default: str << ""; } } runtime.getContext().report(str.str()); } public: void execute(Interpreter::Runtime& runtime) override { MWWorld::Ptr ptr = R()(runtime, false); if (!ptr.isEmpty()) printLocalVars(runtime, ptr); else { // No reference, no problem. printGlobalVars(runtime); } } }; class OpToggleScripts : public Interpreter::Opcode0 { public: void execute(Interpreter::Runtime& runtime) override { bool enabled = MWBase::Environment::get().getWorld()->toggleScripts(); runtime.getContext().report(enabled ? "Scripts -> On" : "Scripts -> Off"); } }; class OpToggleGodMode : public Interpreter::Opcode0 { public: void execute(Interpreter::Runtime& runtime) override { bool enabled = MWBase::Environment::get().getWorld()->toggleGodMode(); runtime.getContext().report(enabled ? "God Mode -> On" : "God Mode -> Off"); } }; template class OpCast : 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(); ESM::RefId targetId = ESM::RefId::stringRefId(runtime.getStringLiteral(runtime[0].mInteger)); runtime.pop(); const ESM::Spell* spell = MWBase::Environment::get().getESMStore()->get().search(spellId); if (!spell) { runtime.getContext().report( "spellcasting failed: cannot find spell \"" + spellId.getRefIdString() + "\""); return; } if (ptr == MWMechanics::getPlayer()) { MWBase::Environment::get().getWorld()->getPlayer().setSelectedSpell(spell->mId); return; } if (ptr.getClass().isActor()) { if (!MWBase::Environment::get().getMechanicsManager()->isCastingSpell(ptr)) { MWMechanics::AiCast castPackage(targetId, spell->mId, true); ptr.getClass().getCreatureStats(ptr).getAiSequence().stack(castPackage, ptr); } return; } MWWorld::Ptr target = MWBase::Environment::get().getWorld()->searchPtr(targetId, false, false); if (target.isEmpty()) return; MWMechanics::CastSpell cast(ptr, target, false, true); cast.playSpellCastingEffects(spell); cast.mHitPosition = target.getRefData().getPosition().asVec3(); cast.mAlwaysSucceed = true; cast.cast(spell); } }; template class OpExplodeSpell : 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(); const ESM::Spell* spell = MWBase::Environment::get().getESMStore()->get().search(spellId); if (!spell) { runtime.getContext().report( "spellcasting failed: cannot find spell \"" + spellId.getRefIdString() + "\""); return; } if (ptr == MWMechanics::getPlayer()) { MWBase::Environment::get().getWorld()->getPlayer().setSelectedSpell(spell->mId); return; } if (ptr.getClass().isActor()) { if (!MWBase::Environment::get().getMechanicsManager()->isCastingSpell(ptr)) { MWMechanics::AiCast castPackage(ptr.getCellRef().getRefId(), spell->mId, true); ptr.getClass().getCreatureStats(ptr).getAiSequence().stack(castPackage, ptr); } return; } MWMechanics::CastSpell cast(ptr, ptr, false, true); cast.mHitPosition = ptr.getRefData().getPosition().asVec3(); cast.mAlwaysSucceed = true; cast.cast(spell); } }; class OpGoToJail : public Interpreter::Opcode0 { public: void execute(Interpreter::Runtime& runtime) override { MWBase::World* world = MWBase::Environment::get().getWorld(); world->goToJail(); } }; class OpPayFine : public Interpreter::Opcode0 { public: void execute(Interpreter::Runtime& runtime) override { MWWorld::Ptr player = MWMechanics::getPlayer(); player.getClass().getNpcStats(player).setBounty(0); MWBase::World* world = MWBase::Environment::get().getWorld(); world->confiscateStolenItems(player); world->getPlayer().recordCrimeId(); world->getPlayer().setDrawState(MWMechanics::DrawState::Nothing); } }; class OpPayFineThief : public Interpreter::Opcode0 { public: void execute(Interpreter::Runtime& runtime) override { MWWorld::Ptr player = MWMechanics::getPlayer(); player.getClass().getNpcStats(player).setBounty(0); MWBase::Environment::get().getWorld()->getPlayer().recordCrimeId(); } }; class OpGetPcInJail : public Interpreter::Opcode0 { public: void execute(Interpreter::Runtime& runtime) override { runtime.push(MWBase::Environment::get().getWorld()->isPlayerInJail()); } }; class OpGetPcTraveling : public Interpreter::Opcode0 { public: void execute(Interpreter::Runtime& runtime) override { runtime.push(MWBase::Environment::get().getWorld()->isPlayerTraveling()); } }; template class OpBetaComment : public Interpreter::Opcode1 { public: void execute(Interpreter::Runtime& runtime, unsigned int arg0) override { MWWorld::Ptr ptr = R()(runtime); std::stringstream msg; msg << "Report time: "; std::time_t currentTime = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now()); tm timeinfo{}; #ifdef _WIN32 gmtime_s(&timeinfo, ¤tTime); #else gmtime_r(¤tTime, &timeinfo); #endif msg << std::put_time(&timeinfo, "%Y.%m.%d %T UTC") << std::endl; msg << "Content file: " << ptr.getCellRef().getRefNum().mContentFile; if (!ptr.getCellRef().hasContentFile()) msg << " [None]" << std::endl; else { std::vector contentFiles = MWBase::Environment::get().getWorld()->getContentFiles(); msg << " [" << contentFiles.at(ptr.getCellRef().getRefNum().mContentFile) << "]" << std::endl; } msg << "RefNum: " << ptr.getCellRef().getRefNum().mIndex << std::endl; if (ptr.getRefData().isDeletedByContentFile()) msg << "[Deleted by content file]" << std::endl; if (!ptr.getCellRef().getCount()) msg << "[Deleted]" << std::endl; msg << "RefID: " << ptr.getCellRef().getRefId() << std::endl; msg << "Memory address: " << ptr.getBase() << std::endl; if (ptr.isInCell()) { MWWorld::CellStore* cell = ptr.getCell(); msg << "Cell: " << MWBase::Environment::get().getWorld()->getCellName(cell) << std::endl; if (cell->getCell()->isExterior()) msg << "Grid: " << cell->getCell()->getGridX() << " " << cell->getCell()->getGridY() << std::endl; osg::Vec3f pos(ptr.getRefData().getPosition().asVec3()); msg << "Coordinates: " << pos.x() << " " << pos.y() << " " << pos.z() << std::endl; auto vfs = MWBase::Environment::get().getResourceSystem()->getVFS(); std::string model = ::Misc::ResourceHelpers::correctActorModelPath(ptr.getClass().getCorrectedModel(ptr), vfs); msg << "Model: " << model << std::endl; if (!model.empty()) { const std::string archive = vfs->getArchive(model); if (!archive.empty()) msg << "(" << archive << ")" << std::endl; TextureFetchVisitor visitor; SceneUtil::PositionAttitudeTransform* baseNode = ptr.getRefData().getBaseNode(); if (baseNode) baseNode->accept(visitor); // The instance might not have a physical model due to paging or scripting. // If this is the case, fall back to the template if (visitor.mTextures.empty()) { Resource::SceneManager* sceneManager = MWBase::Environment::get().getResourceSystem()->getSceneManager(); const_cast(sceneManager->getTemplate(model).get())->accept(visitor); msg << "Bound textures: [None]" << std::endl; if (!visitor.mTextures.empty()) msg << "Model textures: "; } else { msg << "Bound textures: "; } if (!visitor.mTextures.empty()) { msg << std::endl; std::string lastTextureSrc; for (auto& [textureName, fileName] : visitor.mTextures) { std::string textureSrc; if (!fileName.empty()) textureSrc = vfs->getArchive(fileName); if (lastTextureSrc.empty() || textureSrc != lastTextureSrc) { lastTextureSrc = std::move(textureSrc); if (lastTextureSrc.empty()) lastTextureSrc = "[No Source]"; msg << " " << lastTextureSrc << std::endl; } msg << " "; msg << (textureName.empty() ? "[Anonymous]: " : textureName) << ": "; msg << (fileName.empty() ? "[No File]" : fileName) << std::endl; } } else { msg << "[None]" << std::endl; } } if (!ptr.getClass().getScript(ptr).empty()) msg << "Script: " << ptr.getClass().getScript(ptr) << std::endl; } while (arg0 > 0) { std::string_view notes = runtime.getStringLiteral(runtime[0].mInteger); runtime.pop(); if (!notes.empty()) msg << "Notes: " << notes << std::endl; --arg0; } Log(Debug::Warning) << "\n" << msg.str(); runtime.getContext().report(msg.str()); } }; class OpAddToLevCreature : public Interpreter::Opcode0 { public: void execute(Interpreter::Runtime& runtime) override { const ESM::RefId& levId = ESM::RefId::stringRefId(runtime.getStringLiteral(runtime[0].mInteger)); runtime.pop(); const ESM::RefId& creatureId = ESM::RefId::stringRefId(runtime.getStringLiteral(runtime[0].mInteger)); runtime.pop(); int level = runtime[0].mInteger; runtime.pop(); ESM::CreatureLevList listCopy = *MWBase::Environment::get().getESMStore()->get().find(levId); addToLevList(&listCopy, creatureId, level); MWBase::Environment::get().getESMStore()->overrideRecord(listCopy); } }; class OpRemoveFromLevCreature : public Interpreter::Opcode0 { public: void execute(Interpreter::Runtime& runtime) override { const ESM::RefId& levId = ESM::RefId::stringRefId(runtime.getStringLiteral(runtime[0].mInteger)); runtime.pop(); const ESM::RefId& creatureId = ESM::RefId::stringRefId(runtime.getStringLiteral(runtime[0].mInteger)); runtime.pop(); int level = runtime[0].mInteger; runtime.pop(); ESM::CreatureLevList listCopy = *MWBase::Environment::get().getESMStore()->get().find(levId); removeFromLevList(&listCopy, creatureId, level); MWBase::Environment::get().getESMStore()->overrideRecord(listCopy); } }; class OpAddToLevItem : public Interpreter::Opcode0 { public: void execute(Interpreter::Runtime& runtime) override { const ESM::RefId& levId = ESM::RefId::stringRefId(runtime.getStringLiteral(runtime[0].mInteger)); runtime.pop(); const ESM::RefId& itemId = ESM::RefId::stringRefId(runtime.getStringLiteral(runtime[0].mInteger)); runtime.pop(); int level = runtime[0].mInteger; runtime.pop(); ESM::ItemLevList listCopy = *MWBase::Environment::get().getESMStore()->get().find(levId); addToLevList(&listCopy, itemId, level); MWBase::Environment::get().getESMStore()->overrideRecord(listCopy); } }; class OpRemoveFromLevItem : public Interpreter::Opcode0 { public: void execute(Interpreter::Runtime& runtime) override { const ESM::RefId& levId = ESM::RefId::stringRefId(runtime.getStringLiteral(runtime[0].mInteger)); runtime.pop(); const ESM::RefId& itemId = ESM::RefId::stringRefId(runtime.getStringLiteral(runtime[0].mInteger)); runtime.pop(); int level = runtime[0].mInteger; runtime.pop(); ESM::ItemLevList listCopy = *MWBase::Environment::get().getESMStore()->get().find(levId); removeFromLevList(&listCopy, itemId, level); MWBase::Environment::get().getESMStore()->overrideRecord(listCopy); } }; template class OpShowSceneGraph : public Interpreter::Opcode1 { public: void execute(Interpreter::Runtime& runtime, unsigned int arg0) override { MWWorld::Ptr ptr = R()(runtime, false); int confirmed = 0; if (arg0 == 1) { confirmed = runtime[0].mInteger; runtime.pop(); } if (ptr.isEmpty() && !confirmed) runtime.getContext().report( "Exporting the entire scene graph will result in a large file. Confirm this action using " "'showscenegraph 1' or select an object instead."); else { const auto filename = MWBase::Environment::get().getWorld()->exportSceneGraph(ptr); runtime.getContext().report("Wrote '" + Files::pathToUnicodeString(filename) + "'"); } } }; class OpToggleNavMesh : public Interpreter::Opcode0 { public: void execute(Interpreter::Runtime& runtime) override { bool enabled = MWBase::Environment::get().getWorld()->toggleRenderMode(MWRender::Render_NavMesh); runtime.getContext().report( enabled ? "Navigation Mesh Rendering -> On" : "Navigation Mesh Rendering -> Off"); } }; class OpToggleActorsPaths : public Interpreter::Opcode0 { public: void execute(Interpreter::Runtime& runtime) override { bool enabled = MWBase::Environment::get().getWorld()->toggleRenderMode(MWRender::Render_ActorsPaths); runtime.getContext().report(enabled ? "Agents Paths Rendering -> On" : "Agents Paths Rendering -> Off"); } }; class OpSetNavMeshNumberToRender : public Interpreter::Opcode0 { public: void execute(Interpreter::Runtime& runtime) override { const auto navMeshNumber = runtime[0].mInteger; runtime.pop(); if (navMeshNumber < 0) { runtime.getContext().report("Invalid navmesh number: use not less than zero values"); return; } MWBase::Environment::get().getWorld()->setNavMeshNumberToRender( static_cast(navMeshNumber)); } }; template class OpRepairedOnMe : public Interpreter::Opcode0 { public: void execute(Interpreter::Runtime& runtime) override { // Broken in vanilla and deliberately no-op. runtime.push(0); } }; class OpToggleRecastMesh : public Interpreter::Opcode0 { public: void execute(Interpreter::Runtime& runtime) override { bool enabled = MWBase::Environment::get().getWorld()->toggleRenderMode(MWRender::Render_RecastMesh); runtime.getContext().report(enabled ? "Recast Mesh Rendering -> On" : "Recast Mesh Rendering -> Off"); } }; class OpHelp : public Interpreter::Opcode0 { public: void execute(Interpreter::Runtime& runtime) override { std::stringstream message; message << MWBase::Environment::get().getWindowManager()->getVersionDescription() << "\n\n"; std::vector commands; MWBase::Environment::get().getScriptManager()->getExtensions().listKeywords(commands); for (const auto& command : commands) message << command << "\n"; runtime.getContext().report(message.str()); } }; class OpReloadLua : public Interpreter::Opcode0 { public: void execute(Interpreter::Runtime& runtime) override { MWBase::Environment::get().getLuaManager()->reloadAllScripts(); runtime.getContext().report("All Lua scripts are reloaded"); } }; class OpTestModels : public Interpreter::Opcode0 { template void test(int& count) const { Resource::SceneManager* sceneManager = MWBase::Environment::get().getResourceSystem()->getSceneManager(); const MWWorld::ESMStore& store = *MWBase::Environment::get().getESMStore(); for (const T& record : store.get()) { MWWorld::ManualRef ref(store, record.mId); std::string model = ref.getPtr().getClass().getCorrectedModel(ref.getPtr()); if (!model.empty()) { sceneManager->getTemplate(model); ++count; } } } public: void execute(Interpreter::Runtime& runtime) override { Resource::SceneManager* sceneManager = MWBase::Environment::get().getResourceSystem()->getSceneManager(); double delay = sceneManager->getExpiryDelay(); sceneManager->setExpiryDelay(0.0); int count = 0; test(count); test(count); test(count); test(count); test(count); test(count); test(count); test(count); test(count); test(count); test(count); test(count); test(count); test(count); test(count); test(count); test(count); test(count); sceneManager->setExpiryDelay(delay); std::stringstream message; message << "Attempted to load models for " << count << " objects. Check the log for details."; runtime.getContext().report(message.str()); } }; void installOpcodes(Interpreter::Interpreter& interpreter) { interpreter.installSegment5(Compiler::Misc::opcodeMenuMode); interpreter.installSegment5(Compiler::Misc::opcodeRandom); interpreter.installSegment5(Compiler::Misc::opcodeScriptRunning); interpreter.installSegment5>(Compiler::Misc::opcodeStartScript); interpreter.installSegment5>(Compiler::Misc::opcodeStartScriptExplicit); interpreter.installSegment5(Compiler::Misc::opcodeStopScript); interpreter.installSegment5(Compiler::Misc::opcodeGetSecondsPassed); interpreter.installSegment5>(Compiler::Misc::opcodeEnable); interpreter.installSegment5>(Compiler::Misc::opcodeEnableExplicit); interpreter.installSegment5>(Compiler::Misc::opcodeDisable); interpreter.installSegment5>(Compiler::Misc::opcodeDisableExplicit); interpreter.installSegment5>(Compiler::Misc::opcodeGetDisabled); interpreter.installSegment5>(Compiler::Misc::opcodeGetDisabledExplicit); interpreter.installSegment5(Compiler::Misc::opcodeXBox); interpreter.installSegment5>(Compiler::Misc::opcodeOnActivate); interpreter.installSegment5>(Compiler::Misc::opcodeOnActivateExplicit); interpreter.installSegment5>(Compiler::Misc::opcodeActivate); interpreter.installSegment5>(Compiler::Misc::opcodeActivateExplicit); interpreter.installSegment3>(Compiler::Misc::opcodeLock); interpreter.installSegment3>(Compiler::Misc::opcodeLockExplicit); interpreter.installSegment5>(Compiler::Misc::opcodeUnlock); interpreter.installSegment5>(Compiler::Misc::opcodeUnlockExplicit); interpreter.installSegment5(Compiler::Misc::opcodeToggleCollisionDebug); interpreter.installSegment5(Compiler::Misc::opcodeToggleCollisionBoxes); interpreter.installSegment5(Compiler::Misc::opcodeToggleWireframe); interpreter.installSegment5(Compiler::Misc::opcodeFadeIn); interpreter.installSegment5(Compiler::Misc::opcodeFadeOut); interpreter.installSegment5(Compiler::Misc::opcodeFadeTo); interpreter.installSegment5(Compiler::Misc::opcodeTogglePathgrid); interpreter.installSegment5(Compiler::Misc::opcodeToggleWater); interpreter.installSegment5(Compiler::Misc::opcodeToggleWorld); interpreter.installSegment5(Compiler::Misc::opcodeDontSaveObject); interpreter.installSegment5(Compiler::Misc::opcodePcForce1stPerson); interpreter.installSegment5(Compiler::Misc::opcodePcForce3rdPerson); interpreter.installSegment5(Compiler::Misc::opcodePcGet3rdPerson); interpreter.installSegment5(Compiler::Misc::opcodeToggleVanityMode); interpreter.installSegment5(Compiler::Misc::opcodeGetPcSleep); interpreter.installSegment5(Compiler::Misc::opcodeGetPcJumping); interpreter.installSegment5(Compiler::Misc::opcodeWakeUpPc); interpreter.installSegment5(Compiler::Misc::opcodePlayBink); interpreter.installSegment5(Compiler::Misc::opcodePayFine); interpreter.installSegment5(Compiler::Misc::opcodePayFineThief); interpreter.installSegment5(Compiler::Misc::opcodeGoToJail); interpreter.installSegment5>(Compiler::Misc::opcodeGetLocked); interpreter.installSegment5>(Compiler::Misc::opcodeGetLockedExplicit); interpreter.installSegment5>(Compiler::Misc::opcodeGetEffect); interpreter.installSegment5>(Compiler::Misc::opcodeGetEffectExplicit); interpreter.installSegment5>(Compiler::Misc::opcodeAddSoulGem); interpreter.installSegment5>(Compiler::Misc::opcodeAddSoulGemExplicit); interpreter.installSegment3>(Compiler::Misc::opcodeRemoveSoulGem); interpreter.installSegment3>(Compiler::Misc::opcodeRemoveSoulGemExplicit); interpreter.installSegment5>(Compiler::Misc::opcodeDrop); interpreter.installSegment5>(Compiler::Misc::opcodeDropExplicit); interpreter.installSegment5>(Compiler::Misc::opcodeDropSoulGem); interpreter.installSegment5>(Compiler::Misc::opcodeDropSoulGemExplicit); interpreter.installSegment5>(Compiler::Misc::opcodeGetAttacked); interpreter.installSegment5>(Compiler::Misc::opcodeGetAttackedExplicit); interpreter.installSegment5>(Compiler::Misc::opcodeGetWeaponDrawn); interpreter.installSegment5>(Compiler::Misc::opcodeGetWeaponDrawnExplicit); interpreter.installSegment5>(Compiler::Misc::opcodeGetSpellReadied); interpreter.installSegment5>(Compiler::Misc::opcodeGetSpellReadiedExplicit); interpreter.installSegment5>(Compiler::Misc::opcodeGetSpellEffects); interpreter.installSegment5>(Compiler::Misc::opcodeGetSpellEffectsExplicit); interpreter.installSegment5(Compiler::Misc::opcodeGetCurrentTime); interpreter.installSegment5>(Compiler::Misc::opcodeSetDelete); interpreter.installSegment5>(Compiler::Misc::opcodeSetDeleteExplicit); interpreter.installSegment5(Compiler::Misc::opcodeGetSquareRoot); interpreter.installSegment5>(Compiler::Misc::opcodeFall); interpreter.installSegment5>(Compiler::Misc::opcodeFallExplicit); interpreter.installSegment5>(Compiler::Misc::opcodeGetStandingPc); interpreter.installSegment5>(Compiler::Misc::opcodeGetStandingPcExplicit); interpreter.installSegment5>(Compiler::Misc::opcodeGetStandingActor); interpreter.installSegment5>( Compiler::Misc::opcodeGetStandingActorExplicit); interpreter.installSegment5>(Compiler::Misc::opcodeGetCollidingPc); interpreter.installSegment5>(Compiler::Misc::opcodeGetCollidingPcExplicit); interpreter.installSegment5>(Compiler::Misc::opcodeGetCollidingActor); interpreter.installSegment5>( Compiler::Misc::opcodeGetCollidingActorExplicit); interpreter.installSegment5>(Compiler::Misc::opcodeHurtStandingActor); interpreter.installSegment5>( Compiler::Misc::opcodeHurtStandingActorExplicit); interpreter.installSegment5>(Compiler::Misc::opcodeHurtCollidingActor); interpreter.installSegment5>( Compiler::Misc::opcodeHurtCollidingActorExplicit); interpreter.installSegment5(Compiler::Misc::opcodeGetWindSpeed); interpreter.installSegment5>(Compiler::Misc::opcodeHitOnMe); interpreter.installSegment5>(Compiler::Misc::opcodeHitOnMeExplicit); interpreter.installSegment5>(Compiler::Misc::opcodeHitAttemptOnMe); interpreter.installSegment5>(Compiler::Misc::opcodeHitAttemptOnMeExplicit); interpreter.installSegment5>(Compiler::Misc::opcodeDisableTeleporting); interpreter.installSegment5>(Compiler::Misc::opcodeEnableTeleporting); interpreter.installSegment5>(Compiler::Misc::opcodeShowVars); interpreter.installSegment5>(Compiler::Misc::opcodeShowVarsExplicit); interpreter.installSegment5>(Compiler::Misc::opcodeShow); interpreter.installSegment5>(Compiler::Misc::opcodeShowExplicit); interpreter.installSegment5(Compiler::Misc::opcodeToggleGodMode); interpreter.installSegment5(Compiler::Misc::opcodeToggleScripts); interpreter.installSegment5>(Compiler::Misc::opcodeDisableLevitation); interpreter.installSegment5>(Compiler::Misc::opcodeEnableLevitation); interpreter.installSegment5>(Compiler::Misc::opcodeCast); interpreter.installSegment5>(Compiler::Misc::opcodeCastExplicit); interpreter.installSegment5>(Compiler::Misc::opcodeExplodeSpell); interpreter.installSegment5>(Compiler::Misc::opcodeExplodeSpellExplicit); interpreter.installSegment5(Compiler::Misc::opcodeGetPcInJail); interpreter.installSegment5(Compiler::Misc::opcodeGetPcTraveling); interpreter.installSegment3>(Compiler::Misc::opcodeBetaComment); interpreter.installSegment3>(Compiler::Misc::opcodeBetaCommentExplicit); interpreter.installSegment5(Compiler::Misc::opcodeAddToLevCreature); interpreter.installSegment5(Compiler::Misc::opcodeRemoveFromLevCreature); interpreter.installSegment5(Compiler::Misc::opcodeAddToLevItem); interpreter.installSegment5(Compiler::Misc::opcodeRemoveFromLevItem); interpreter.installSegment3>(Compiler::Misc::opcodeShowSceneGraph); interpreter.installSegment3>(Compiler::Misc::opcodeShowSceneGraphExplicit); interpreter.installSegment5(Compiler::Misc::opcodeToggleBorders); interpreter.installSegment5(Compiler::Misc::opcodeToggleNavMesh); interpreter.installSegment5(Compiler::Misc::opcodeToggleActorsPaths); interpreter.installSegment5(Compiler::Misc::opcodeSetNavMeshNumberToRender); interpreter.installSegment5>(Compiler::Misc::opcodeRepairedOnMe); interpreter.installSegment5>(Compiler::Misc::opcodeRepairedOnMeExplicit); interpreter.installSegment5(Compiler::Misc::opcodeToggleRecastMesh); interpreter.installSegment5(Compiler::Misc::opcodeHelp); interpreter.installSegment5(Compiler::Misc::opcodeReloadLua); interpreter.installSegment5(Compiler::Misc::opcodeTestModels); } } }