#include "aiextensions.hpp" #include #include /* Start of tes3mp addition Include additional headers for multiplayer purposes */ #include #include "../mwmp/Main.hpp" #include "../mwmp/Networking.hpp" #include "../mwmp/ActorList.hpp" #include "../mwmp/MechanicsHelper.hpp" /* End of tes3mp addition */ #include #include #include #include #include #include "../mwworld/class.hpp" #include "../mwworld/esmstore.hpp" #include "../mwmechanics/creaturestats.hpp" #include "../mwmechanics/aiactivate.hpp" #include "../mwmechanics/aiescort.hpp" #include "../mwmechanics/aifollow.hpp" #include "../mwmechanics/aitravel.hpp" #include "../mwmechanics/aiwander.hpp" #include "../mwmechanics/aiface.hpp" #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" #include "../mwbase/mechanicsmanager.hpp" #include "interpretercontext.hpp" #include "ref.hpp" namespace MWScript { namespace Ai { template class OpAiActivate : public Interpreter::Opcode1 { public: virtual void execute (Interpreter::Runtime& runtime, unsigned int arg0) { MWWorld::Ptr ptr = R()(runtime); std::string objectID = runtime.getStringLiteral (runtime[0].mInteger); runtime.pop(); // discard additional arguments (reset), because we have no idea what they mean. for (unsigned int i=0; i class OpAiTravel : public Interpreter::Opcode1 { public: virtual void execute (Interpreter::Runtime& runtime, unsigned int arg0) { MWWorld::Ptr ptr = R()(runtime); Interpreter::Type_Float x = runtime[0].mFloat; runtime.pop(); Interpreter::Type_Float y = runtime[0].mFloat; runtime.pop(); Interpreter::Type_Float z = runtime[0].mFloat; runtime.pop(); // discard additional arguments (reset), because we have no idea what they mean. for (unsigned int i=0; i class OpAiEscort : public Interpreter::Opcode1 { public: virtual void execute (Interpreter::Runtime& runtime, unsigned int arg0) { MWWorld::Ptr ptr = R()(runtime); std::string actorID = runtime.getStringLiteral (runtime[0].mInteger); runtime.pop(); Interpreter::Type_Float duration = runtime[0].mFloat; runtime.pop(); Interpreter::Type_Float x = runtime[0].mFloat; runtime.pop(); Interpreter::Type_Float y = runtime[0].mFloat; runtime.pop(); Interpreter::Type_Float z = runtime[0].mFloat; runtime.pop(); // discard additional arguments (reset), because we have no idea what they mean. for (unsigned int i=0; i(duration), x, y, z); ptr.getClass().getCreatureStats (ptr).getAiSequence().stack(escortPackage, ptr); std::cout << "AiEscort: " << x << ", " << y << ", " << z << ", " << duration << std::endl; } }; template class OpAiEscortCell : public Interpreter::Opcode1 { public: virtual void execute (Interpreter::Runtime& runtime, unsigned int arg0) { MWWorld::Ptr ptr = R()(runtime); std::string actorID = runtime.getStringLiteral (runtime[0].mInteger); runtime.pop(); std::string cellID = runtime.getStringLiteral (runtime[0].mInteger); runtime.pop(); Interpreter::Type_Float duration = runtime[0].mFloat; runtime.pop(); Interpreter::Type_Float x = runtime[0].mFloat; runtime.pop(); Interpreter::Type_Float y = runtime[0].mFloat; runtime.pop(); Interpreter::Type_Float z = runtime[0].mFloat; runtime.pop(); // discard additional arguments (reset), because we have no idea what they mean. for (unsigned int i=0; igetStore().get().find(cellID); MWMechanics::AiEscort escortPackage(actorID, cellID, static_cast(duration), x, y, z); ptr.getClass().getCreatureStats (ptr).getAiSequence().stack(escortPackage, ptr); std::cout << "AiEscort: " << x << ", " << y << ", " << z << ", " << duration << std::endl; } }; template class OpGetAiPackageDone : public Interpreter::Opcode0 { public: virtual void execute (Interpreter::Runtime& runtime) { MWWorld::Ptr ptr = R()(runtime); Interpreter::Type_Integer value = ptr.getClass().getCreatureStats (ptr).getAiSequence().isPackageDone(); runtime.push (value); } }; template class OpAiWander : public Interpreter::Opcode1 { public: virtual void execute (Interpreter::Runtime& runtime, unsigned int arg0) { MWWorld::Ptr ptr = R()(runtime); Interpreter::Type_Integer range = static_cast(runtime[0].mFloat); runtime.pop(); Interpreter::Type_Integer duration = static_cast(runtime[0].mFloat); runtime.pop(); Interpreter::Type_Integer time = static_cast(runtime[0].mFloat); runtime.pop(); // Chance for Idle is unused if (arg0) { --arg0; runtime.pop(); } std::vector idleList; bool repeat = false; // Chances for Idle2-Idle9 for(int i=2; i<=9 && arg0; ++i) { if(!repeat) repeat = true; Interpreter::Type_Integer idleValue = runtime[0].mInteger; idleValue = std::min(255, std::max(0, idleValue)); idleList.push_back(idleValue); runtime.pop(); --arg0; } if(arg0) { repeat = runtime[0].mInteger != 0; runtime.pop(); --arg0; } // discard additional arguments (reset), because we have no idea what they mean. for (unsigned int i=0; i class OpGetAiSetting : public Interpreter::Opcode0 { int mIndex; public: OpGetAiSetting(int index) : mIndex(index) {} virtual void execute (Interpreter::Runtime& runtime) { MWWorld::Ptr ptr = R()(runtime); runtime.push(ptr.getClass().getCreatureStats (ptr).getAiSetting ( (MWMechanics::CreatureStats::AiSetting)mIndex).getModified()); } }; template class OpModAiSetting : public Interpreter::Opcode0 { int mIndex; public: OpModAiSetting(int index) : mIndex(index) {} virtual void execute (Interpreter::Runtime& runtime) { MWWorld::Ptr ptr = R()(runtime); Interpreter::Type_Integer value = runtime[0].mInteger; runtime.pop(); MWMechanics::CreatureStats::AiSetting setting = MWMechanics::CreatureStats::AiSetting(mIndex); ptr.getClass().getCreatureStats (ptr).setAiSetting (setting, ptr.getClass().getCreatureStats (ptr).getAiSetting (setting).getBase() + value); } }; template class OpSetAiSetting : public Interpreter::Opcode0 { int mIndex; public: OpSetAiSetting(int index) : mIndex(index) {} virtual void execute (Interpreter::Runtime& runtime) { MWWorld::Ptr ptr = R()(runtime); Interpreter::Type_Integer value = runtime[0].mInteger; runtime.pop(); MWMechanics::CreatureStats::AiSetting setting = (MWMechanics::CreatureStats::AiSetting)mIndex; MWMechanics::Stat stat = ptr.getClass().getCreatureStats(ptr).getAiSetting(setting); stat.setModified(value, 0); ptr.getClass().getCreatureStats(ptr).setAiSetting(setting, stat); /* Start of tes3mp addition Setting an actor's AI_Fight to 100 is equivalent to starting combat with the local player, so send a combat packet regardless of whether we're the cell authority or not; the server can decide if it wants to comply with them by forwarding them to the cell authority */ if (setting == MWMechanics::CreatureStats::AI_Fight && value == 100) { mwmp::ActorList *actorList = mwmp::Main::get().getNetworking()->getActorList(); actorList->reset(); actorList->cell = *ptr.getCell()->getCell(); actorList->addAiActor(ptr, MWBase::Environment::get().getWorld()->getPlayerPtr(), mwmp::BaseActorList::COMBAT); actorList->sendAiActors(); } /* End of tes3mp addition */ } }; template class OpAiFollow : public Interpreter::Opcode1 { public: virtual void execute (Interpreter::Runtime& runtime, unsigned int arg0) { MWWorld::Ptr ptr = R()(runtime); std::string actorID = runtime.getStringLiteral (runtime[0].mInteger); runtime.pop(); Interpreter::Type_Float duration = runtime[0].mFloat; runtime.pop(); Interpreter::Type_Float x = runtime[0].mFloat; runtime.pop(); Interpreter::Type_Float y = runtime[0].mFloat; runtime.pop(); Interpreter::Type_Float z = runtime[0].mFloat; runtime.pop(); // discard additional arguments (reset), because we have no idea what they mean. for (unsigned int i=0; isearchPtr(actorID, true); if (targetPtr) { mwmp::ActorList *actorList = mwmp::Main::get().getNetworking()->getActorList(); actorList->reset(); actorList->cell = *ptr.getCell()->getCell(); actorList->addAiActor(ptr, targetPtr, mwmp::BaseActorList::FOLLOW); actorList->sendAiActors(); } /* End of tes3mp addition */ } }; template class OpAiFollowCell : public Interpreter::Opcode1 { public: virtual void execute (Interpreter::Runtime& runtime, unsigned int arg0) { MWWorld::Ptr ptr = R()(runtime); std::string actorID = runtime.getStringLiteral (runtime[0].mInteger); runtime.pop(); std::string cellID = runtime.getStringLiteral (runtime[0].mInteger); runtime.pop(); Interpreter::Type_Float duration = runtime[0].mFloat; runtime.pop(); Interpreter::Type_Float x = runtime[0].mFloat; runtime.pop(); Interpreter::Type_Float y = runtime[0].mFloat; runtime.pop(); Interpreter::Type_Float z = runtime[0].mFloat; runtime.pop(); // discard additional arguments (reset), because we have no idea what they mean. for (unsigned int i=0; i class OpGetCurrentAIPackage : public Interpreter::Opcode0 { public: virtual void execute (Interpreter::Runtime& runtime) { MWWorld::Ptr ptr = R()(runtime); Interpreter::Type_Integer value = ptr.getClass().getCreatureStats (ptr).getAiSequence().getLastRunTypeId(); runtime.push (value); } }; template class OpGetDetected : public Interpreter::Opcode0 { public: virtual void execute (Interpreter::Runtime& runtime) { MWWorld::Ptr observer = R()(runtime, false); // required=false std::string actorID = runtime.getStringLiteral (runtime[0].mInteger); runtime.pop(); MWWorld::Ptr actor = MWBase::Environment::get().getWorld()->getPtr(actorID, true); Interpreter::Type_Integer value = MWBase::Environment::get().getMechanicsManager()->isActorDetected(actor, observer); runtime.push (value); } }; template class OpGetLineOfSight : public Interpreter::Opcode0 { public: virtual void execute (Interpreter::Runtime& runtime) { MWWorld::Ptr source = R()(runtime); std::string actorID = runtime.getStringLiteral (runtime[0].mInteger); runtime.pop(); MWWorld::Ptr dest = MWBase::Environment::get().getWorld()->getPtr(actorID,true); bool value = false; if(dest != MWWorld::Ptr() && source.getClass().isActor() && dest.getClass().isActor()) { value = MWBase::Environment::get().getWorld()->getLOS(source,dest); } runtime.push (value); } }; template class OpGetTarget : public Interpreter::Opcode0 { public: virtual void execute (Interpreter::Runtime &runtime) { MWWorld::Ptr actor = R()(runtime); std::string testedTargetId = runtime.getStringLiteral (runtime[0].mInteger); runtime.pop(); const MWMechanics::CreatureStats& creatureStats = actor.getClass().getCreatureStats(actor); bool targetsAreEqual = false; MWWorld::Ptr targetPtr; if (creatureStats.getAiSequence().getCombatTarget (targetPtr)) { if (!targetPtr.isEmpty() && targetPtr.getCellRef().getRefId() == testedTargetId) targetsAreEqual = true; } runtime.push(int(targetsAreEqual)); } }; template class OpStartCombat : public Interpreter::Opcode0 { public: virtual void execute (Interpreter::Runtime &runtime) { MWWorld::Ptr actor = R()(runtime); std::string targetID = runtime.getStringLiteral (runtime[0].mInteger); runtime.pop(); MWWorld::Ptr target = MWBase::Environment::get().getWorld()->getPtr(targetID, true); MWBase::Environment::get().getMechanicsManager()->startCombat(actor, target); /* Start of tes3mp addition Send ActorAI packets when an actor starts combat, regardless of whether we're the cell authority or not; the server can decide if it wants to comply with them by forwarding them to the cell authority */ if (target) { mwmp::ActorList *actorList = mwmp::Main::get().getNetworking()->getActorList(); actorList->reset(); actorList->cell = *actor.getCell()->getCell(); actorList->addAiActor(actor, target, mwmp::BaseActorList::COMBAT); actorList->sendAiActors(); } /* End of tes3mp addition */ } }; template class OpStopCombat : public Interpreter::Opcode0 { public: virtual void execute (Interpreter::Runtime& runtime) { MWWorld::Ptr actor = R()(runtime); MWMechanics::CreatureStats& creatureStats = actor.getClass().getCreatureStats(actor); creatureStats.getAiSequence().stopCombat(); } }; class OpToggleAI : public Interpreter::Opcode0 { public: virtual void execute (Interpreter::Runtime& runtime) { bool enabled = MWBase::Environment::get().getMechanicsManager()->toggleAI(); runtime.getContext().report (enabled ? "AI -> On" : "AI -> Off"); } }; template class OpFace : public Interpreter::Opcode0 { public: virtual void execute(Interpreter::Runtime& runtime) { MWWorld::Ptr actor = R()(runtime); Interpreter::Type_Float x = runtime[0].mFloat; runtime.pop(); Interpreter::Type_Float y = runtime[0].mFloat; runtime.pop(); MWMechanics::AiFace facePackage(x, y); actor.getClass().getCreatureStats(actor).getAiSequence().stack(facePackage, actor); } }; void installOpcodes (Interpreter::Interpreter& interpreter) { interpreter.installSegment3 (Compiler::Ai::opcodeAIActivate, new OpAiActivate); interpreter.installSegment3 (Compiler::Ai::opcodeAIActivateExplicit, new OpAiActivate); interpreter.installSegment3 (Compiler::Ai::opcodeAiTravel, new OpAiTravel); interpreter.installSegment3 (Compiler::Ai::opcodeAiTravelExplicit, new OpAiTravel); interpreter.installSegment3 (Compiler::Ai::opcodeAiEscort, new OpAiEscort); interpreter.installSegment3 (Compiler::Ai::opcodeAiEscortExplicit, new OpAiEscort); interpreter.installSegment3 (Compiler::Ai::opcodeAiEscortCell, new OpAiEscortCell); interpreter.installSegment3 (Compiler::Ai::opcodeAiEscortCellExplicit, new OpAiEscortCell); interpreter.installSegment3 (Compiler::Ai::opcodeAiWander, new OpAiWander); interpreter.installSegment3 (Compiler::Ai::opcodeAiWanderExplicit, new OpAiWander); interpreter.installSegment3 (Compiler::Ai::opcodeAiFollow, new OpAiFollow); interpreter.installSegment3 (Compiler::Ai::opcodeAiFollowExplicit, new OpAiFollow); interpreter.installSegment3 (Compiler::Ai::opcodeAiFollowCell, new OpAiFollowCell); interpreter.installSegment3 (Compiler::Ai::opcodeAiFollowCellExplicit, new OpAiFollowCell); interpreter.installSegment5 (Compiler::Ai::opcodeGetAiPackageDone, new OpGetAiPackageDone); interpreter.installSegment5 (Compiler::Ai::opcodeGetAiPackageDoneExplicit, new OpGetAiPackageDone); interpreter.installSegment5 (Compiler::Ai::opcodeGetCurrentAiPackage, new OpGetCurrentAIPackage); interpreter.installSegment5 (Compiler::Ai::opcodeGetCurrentAiPackageExplicit, new OpGetCurrentAIPackage); interpreter.installSegment5 (Compiler::Ai::opcodeGetDetected, new OpGetDetected); interpreter.installSegment5 (Compiler::Ai::opcodeGetDetectedExplicit, new OpGetDetected); interpreter.installSegment5 (Compiler::Ai::opcodeGetLineOfSight, new OpGetLineOfSight); interpreter.installSegment5 (Compiler::Ai::opcodeGetLineOfSightExplicit, new OpGetLineOfSight); interpreter.installSegment5 (Compiler::Ai::opcodeGetTarget, new OpGetTarget); interpreter.installSegment5 (Compiler::Ai::opcodeGetTargetExplicit, new OpGetTarget); interpreter.installSegment5 (Compiler::Ai::opcodeStartCombat, new OpStartCombat); interpreter.installSegment5 (Compiler::Ai::opcodeStartCombatExplicit, new OpStartCombat); interpreter.installSegment5 (Compiler::Ai::opcodeStopCombat, new OpStopCombat); interpreter.installSegment5 (Compiler::Ai::opcodeStopCombatExplicit, new OpStopCombat); interpreter.installSegment5 (Compiler::Ai::opcodeToggleAI, new OpToggleAI); interpreter.installSegment5 (Compiler::Ai::opcodeSetHello, new OpSetAiSetting(0)); interpreter.installSegment5 (Compiler::Ai::opcodeSetHelloExplicit, new OpSetAiSetting(0)); interpreter.installSegment5 (Compiler::Ai::opcodeSetFight, new OpSetAiSetting(1)); interpreter.installSegment5 (Compiler::Ai::opcodeSetFightExplicit, new OpSetAiSetting(1)); interpreter.installSegment5 (Compiler::Ai::opcodeSetFlee, new OpSetAiSetting(2)); interpreter.installSegment5 (Compiler::Ai::opcodeSetFleeExplicit, new OpSetAiSetting(2)); interpreter.installSegment5 (Compiler::Ai::opcodeSetAlarm, new OpSetAiSetting(3)); interpreter.installSegment5 (Compiler::Ai::opcodeSetAlarmExplicit, new OpSetAiSetting(3)); interpreter.installSegment5 (Compiler::Ai::opcodeModHello, new OpModAiSetting(0)); interpreter.installSegment5 (Compiler::Ai::opcodeModHelloExplicit, new OpModAiSetting(0)); interpreter.installSegment5 (Compiler::Ai::opcodeModFight, new OpModAiSetting(1)); interpreter.installSegment5 (Compiler::Ai::opcodeModFightExplicit, new OpModAiSetting(1)); interpreter.installSegment5 (Compiler::Ai::opcodeModFlee, new OpModAiSetting(2)); interpreter.installSegment5 (Compiler::Ai::opcodeModFleeExplicit, new OpModAiSetting(2)); interpreter.installSegment5 (Compiler::Ai::opcodeModAlarm, new OpModAiSetting(3)); interpreter.installSegment5 (Compiler::Ai::opcodeModAlarmExplicit, new OpModAiSetting(3)); interpreter.installSegment5 (Compiler::Ai::opcodeGetHello, new OpGetAiSetting(0)); interpreter.installSegment5 (Compiler::Ai::opcodeGetHelloExplicit, new OpGetAiSetting(0)); interpreter.installSegment5 (Compiler::Ai::opcodeGetFight, new OpGetAiSetting(1)); interpreter.installSegment5 (Compiler::Ai::opcodeGetFightExplicit, new OpGetAiSetting(1)); interpreter.installSegment5 (Compiler::Ai::opcodeGetFlee, new OpGetAiSetting(2)); interpreter.installSegment5 (Compiler::Ai::opcodeGetFleeExplicit, new OpGetAiSetting(2)); interpreter.installSegment5 (Compiler::Ai::opcodeGetAlarm, new OpGetAiSetting(3)); interpreter.installSegment5 (Compiler::Ai::opcodeGetAlarmExplicit, new OpGetAiSetting(3)); interpreter.installSegment5 (Compiler::Ai::opcodeFace, new OpFace); interpreter.installSegment5 (Compiler::Ai::opcodeFaceExplicit, new OpFace); } } }