From 0e13207afe5f28a017873dec241150e0a4137214 Mon Sep 17 00:00:00 2001 From: David Cernat Date: Tue, 10 Jul 2018 05:07:58 +0300 Subject: [PATCH] [General] Implement ActorAI packet, part 3 The server can now cancel actor AI, make actors travel to a location, make actors wander, and make actors get escorted by a player or another actor. --- apps/openmw-mp/Script/Functions/Actors.cpp | 17 ++++++ apps/openmw-mp/Script/Functions/Actors.hpp | 29 ++++++++++ apps/openmw-mp/Script/Functions/Items.cpp | 4 -- apps/openmw/mwmp/Cell.cpp | 3 + apps/openmw/mwmp/DedicatedActor.cpp | 57 ++++++++++++++++--- components/openmw-mp/Base/BaseActor.hpp | 11 +++- .../openmw-mp/Packets/Actor/PacketActorAI.cpp | 39 +++++++++---- 7 files changed, 136 insertions(+), 24 deletions(-) diff --git a/apps/openmw-mp/Script/Functions/Actors.cpp b/apps/openmw-mp/Script/Functions/Actors.cpp index 071909d2d..2947f0166 100644 --- a/apps/openmw-mp/Script/Functions/Actors.cpp +++ b/apps/openmw-mp/Script/Functions/Actors.cpp @@ -327,6 +327,23 @@ void ActorFunctions::SetActorAITargetToActor(int refNumIndex, int mpNum) noexcep tempActor.aiTarget.mpNum = mpNum; } +void ActorFunctions::SetActorAICoordinates(double x, double y, double z) noexcept +{ + tempActor.aiCoordinates.pos[0] = x; + tempActor.aiCoordinates.pos[1] = y; + tempActor.aiCoordinates.pos[2] = z; +} + +void ActorFunctions::SetActorAIDistance(unsigned int distance) noexcept +{ + tempActor.aiDistance = distance; +} + +void ActorFunctions::SetActorAIDuration(unsigned int duration) noexcept +{ + tempActor.aiDuration = duration; +} + void ActorFunctions::EquipActorItem(unsigned short slot, const char *refId, unsigned int count, int charge, double enchantmentCharge) noexcept { tempActor.equipmentItems[slot].refId = refId; diff --git a/apps/openmw-mp/Script/Functions/Actors.hpp b/apps/openmw-mp/Script/Functions/Actors.hpp index e80f2f3d8..f9a2c07e6 100644 --- a/apps/openmw-mp/Script/Functions/Actors.hpp +++ b/apps/openmw-mp/Script/Functions/Actors.hpp @@ -70,6 +70,9 @@ {"SetActorAIAction", ActorFunctions::SetActorAIAction},\ {"SetActorAITargetToPlayer", ActorFunctions::SetActorAITargetToPlayer},\ {"SetActorAITargetToActor", ActorFunctions::SetActorAITargetToActor},\ + {"SetActorAICoordinates", ActorFunctions::SetActorAICoordinates},\ + {"SetActorAIDistance", ActorFunctions::SetActorAIDistance},\ + {"SetActorAIDuration", ActorFunctions::SetActorAIDuration},\ \ {"EquipActorItem", ActorFunctions::EquipActorItem},\ {"UnequipActorItem", ActorFunctions::UnequipActorItem},\ @@ -566,6 +569,32 @@ public: */ static void SetActorAITargetToActor(int refNumIndex, int mpNum) noexcept; + /** + * \brief Set the coordinates for the AI package associated with the current AI action. + * + * \param x The X coordinate. + * \param y The Y coordinate. + * \param z The Z coordinate. + * \return void + */ + static void SetActorAICoordinates(double x, double y, double z) noexcept; + + /** + * \brief Set the distance of the AI package associated with the current AI action. + * + * \param duration The distance of the package. + * \return void + */ + static void SetActorAIDistance(unsigned int distance) noexcept; + + /** + * \brief Set the duration of the AI package associated with the current AI action. + * + * \param duration The duration of the package. + * \return void + */ + static void SetActorAIDuration(unsigned int duration) noexcept; + /** * \brief Equip an item in a certain slot of the equipment of the temporary actor stored * on the server. diff --git a/apps/openmw-mp/Script/Functions/Items.cpp b/apps/openmw-mp/Script/Functions/Items.cpp index 7182dcd32..f007e7b9f 100644 --- a/apps/openmw-mp/Script/Functions/Items.cpp +++ b/apps/openmw-mp/Script/Functions/Items.cpp @@ -1,7 +1,3 @@ -// -// Created by koncord on 02.03.16. -// - #include "Items.hpp" #include diff --git a/apps/openmw/mwmp/Cell.cpp b/apps/openmw/mwmp/Cell.cpp index 694867d9e..d020e9107 100644 --- a/apps/openmw/mwmp/Cell.cpp +++ b/apps/openmw/mwmp/Cell.cpp @@ -257,6 +257,9 @@ void Cell::readAI(ActorList& actorList) { DedicatedActor *actor = dedicatedActors[mapIndex]; actor->aiAction = baseActor.aiAction; + actor->aiDistance = baseActor.aiDistance; + actor->aiDuration = baseActor.aiDuration; + actor->aiCoordinates = baseActor.aiCoordinates; actor->hasAiTarget = baseActor.hasAiTarget; actor->aiTarget = baseActor.aiTarget; actor->setAI(); diff --git a/apps/openmw/mwmp/DedicatedActor.cpp b/apps/openmw/mwmp/DedicatedActor.cpp index 263ebadf1..b0a0868cd 100644 --- a/apps/openmw/mwmp/DedicatedActor.cpp +++ b/apps/openmw/mwmp/DedicatedActor.cpp @@ -7,7 +7,11 @@ #include "../mwdialogue/dialoguemanagerimp.hpp" #include "../mwmechanics/aicombat.hpp" +#include "../mwmechanics/aiescort.hpp" #include "../mwmechanics/aifollow.hpp" +#include "../mwmechanics/aitravel.hpp" +#include "../mwmechanics/aiwander.hpp" + #include "../mwmechanics/creaturestats.hpp" #include "../mwmechanics/mechanicsmanagerimp.hpp" #include "../mwmechanics/movement.hpp" @@ -207,7 +211,31 @@ void DedicatedActor::setEquipment() void DedicatedActor::setAI() { - if (hasAiTarget) + if (aiAction == mwmp::BaseActorList::CANCEL) + { + LOG_APPEND(Log::LOG_VERBOSE, "--- Cancelling AI sequence"); + + ptr.getClass().getCreatureStats(ptr).getAiSequence().clear(); + } + else if (aiAction == mwmp::BaseActorList::TRAVEL) + { + LOG_APPEND(Log::LOG_VERBOSE, "--- Travelling to %f, %f, %f", + aiCoordinates.pos[0], aiCoordinates.pos[1], aiCoordinates.pos[2]); + + MWMechanics::AiTravel package(aiCoordinates.pos[0], aiCoordinates.pos[1], aiCoordinates.pos[2]); + ptr.getClass().getCreatureStats(ptr).getAiSequence().stack(package, ptr, true); + } + else if (aiAction == mwmp::BaseActorList::WANDER) + { + LOG_APPEND(Log::LOG_VERBOSE, "--- Wandering for distance %i and duration %i", + aiDistance, aiDuration); + + std::vector idleList; + + MWMechanics::AiWander package(aiDistance, aiDuration, -1, idleList, true); + ptr.getClass().getCreatureStats(ptr).getAiSequence().stack(package, ptr, true); + } + else if (hasAiTarget) { MWWorld::Ptr targetPtr; @@ -215,7 +243,9 @@ void DedicatedActor::setAI() { targetPtr = MechanicsHelper::getPlayerPtr(aiTarget); - LOG_APPEND(Log::LOG_VERBOSE, "-- DedicatedActor %s %i-%i has player target %s", targetPtr.getClass().getName(targetPtr).c_str()); + LOG_APPEND(Log::LOG_VERBOSE, "-- DedicatedActor %s %i-%i has player target %s", + ptr.getCellRef().getRefId().c_str(), ptr.getCellRef().getRefNum().mIndex, ptr.getCellRef().getMpNum(), + targetPtr.getClass().getName(targetPtr).c_str()); } else { @@ -241,15 +271,28 @@ void DedicatedActor::setAI() if (targetPtr) { - if (aiAction == mwmp::BaseActorList::FOLLOW) + if (aiAction == mwmp::BaseActorList::COMBAT) { - MWMechanics::AiFollow package(targetPtr); - package.allowAnyDistance(true); + LOG_APPEND(Log::LOG_VERBOSE, "--- Starting combat with target"); + + MWMechanics::AiCombat package(targetPtr); ptr.getClass().getCreatureStats(ptr).getAiSequence().stack(package, ptr, true); } - else if (aiAction == mwmp::BaseActorList::COMBAT) + else if (aiAction == mwmp::BaseActorList::ESCORT) { - MWMechanics::AiCombat package(targetPtr); + LOG_APPEND(Log::LOG_VERBOSE, "--- Being escorted by target, for duration %i, to coordinates %f, %f, %f", + aiDuration, aiCoordinates.pos[0], aiCoordinates.pos[1], aiCoordinates.pos[2]); + + MWMechanics::AiEscort package(targetPtr.getCellRef().getRefId(), aiDuration, + aiCoordinates.pos[0], aiCoordinates.pos[1], aiCoordinates.pos[2]); + ptr.getClass().getCreatureStats(ptr).getAiSequence().stack(package, ptr, true); + } + else if (aiAction == mwmp::BaseActorList::FOLLOW) + { + LOG_APPEND(Log::LOG_VERBOSE, "--- Following target"); + + MWMechanics::AiFollow package(targetPtr); + package.allowAnyDistance(true); ptr.getClass().getCreatureStats(ptr).getAiSequence().stack(package, ptr, true); } } diff --git a/components/openmw-mp/Base/BaseActor.hpp b/components/openmw-mp/Base/BaseActor.hpp index 429ee6fed..93e3acef4 100644 --- a/components/openmw-mp/Base/BaseActor.hpp +++ b/components/openmw-mp/Base/BaseActor.hpp @@ -44,6 +44,9 @@ namespace mwmp bool hasAiTarget; Target aiTarget; unsigned int aiAction; + unsigned int aiDistance; + unsigned int aiDuration; + ESM::Position aiCoordinates; bool hasPositionData; bool hasStatsDynamicData; @@ -70,8 +73,12 @@ namespace mwmp enum AI_ACTION { - FOLLOW = 0, - COMBAT = 1 + CANCEL = 0, + COMBAT = 1, + ESCORT = 2, + FOLLOW = 3, + TRAVEL = 4, + WANDER = 5 }; RakNet::RakNetGUID guid; diff --git a/components/openmw-mp/Packets/Actor/PacketActorAI.cpp b/components/openmw-mp/Packets/Actor/PacketActorAI.cpp index 2b9390cae..7e02d764b 100644 --- a/components/openmw-mp/Packets/Actor/PacketActorAI.cpp +++ b/components/openmw-mp/Packets/Actor/PacketActorAI.cpp @@ -12,21 +12,38 @@ PacketActorAI::PacketActorAI(RakNet::RakPeerInterface *peer) : ActorPacket(peer) void PacketActorAI::Actor(BaseActor &actor, bool send) { RW(actor.aiAction, send); - RW(actor.hasAiTarget, send); - if (actor.hasAiTarget) + if (actor.aiAction != mwmp::BaseActorList::CANCEL) { - RW(actor.aiTarget.isPlayer, send); + if (actor.aiAction == mwmp::BaseActorList::WANDER) + RW(actor.aiDistance, send); - if (actor.aiTarget.isPlayer) - { - RW(actor.aiTarget.guid, send); - } - else + if (actor.aiAction == mwmp::BaseActorList::ESCORT || actor.aiAction == mwmp::BaseActorList::TRAVEL) + RW(actor.aiCoordinates, send); + + if (actor.aiAction == mwmp::BaseActorList::ESCORT || actor.aiAction == mwmp::BaseActorList::WANDER) + RW(actor.aiDuration, send); + + if (actor.aiAction == mwmp::BaseActorList::COMBAT || actor.aiAction == mwmp::BaseActorList::ESCORT || + actor.aiAction == mwmp::BaseActorList::FOLLOW) { - RW(actor.aiTarget.refId, send, true); - RW(actor.aiTarget.refNumIndex, send); - RW(actor.aiTarget.mpNum, send); + RW(actor.hasAiTarget, send); + + if (actor.hasAiTarget) + { + RW(actor.aiTarget.isPlayer, send); + + if (actor.aiTarget.isPlayer) + { + RW(actor.aiTarget.guid, send); + } + else + { + RW(actor.aiTarget.refId, send, true); + RW(actor.aiTarget.refNumIndex, send); + RW(actor.aiTarget.mpNum, send); + } + } } } }