forked from mirror/openmw-tes3mp
[General] Implement ActorAI packet, part 1
The server can now make actors become followers of players or other actors.
This commit is contained in:
parent
c00b3bbe97
commit
77389538e8
11 changed files with 167 additions and 3 deletions
|
@ -267,6 +267,31 @@ void ActorFunctions::SetActorFatigueModified(double value) noexcept
|
||||||
tempActor.creatureStats.mDynamic[2].mMod = value;
|
tempActor.creatureStats.mDynamic[2].mMod = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ActorFunctions::SetActorAIAction(unsigned int action) noexcept
|
||||||
|
{
|
||||||
|
tempActor.aiAction = action;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ActorFunctions::SetActorAITargetToPlayer(unsigned short pid) noexcept
|
||||||
|
{
|
||||||
|
Player *player;
|
||||||
|
GET_PLAYER(pid, player, );
|
||||||
|
|
||||||
|
tempActor.hasAiTarget = true;
|
||||||
|
tempActor.aiTarget.isPlayer = true;
|
||||||
|
|
||||||
|
tempActor.aiTarget.guid = player->guid;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ActorFunctions::SetActorAITargetToActor(int refNumIndex, int mpNum) noexcept
|
||||||
|
{
|
||||||
|
tempActor.hasAiTarget = true;
|
||||||
|
tempActor.aiTarget.isPlayer = false;
|
||||||
|
|
||||||
|
tempActor.aiTarget.refNumIndex = refNumIndex;
|
||||||
|
tempActor.aiTarget.mpNum = mpNum;
|
||||||
|
}
|
||||||
|
|
||||||
void ActorFunctions::EquipActorItem(unsigned short slot, const char *refId, unsigned int count, int charge, double enchantmentCharge) noexcept
|
void ActorFunctions::EquipActorItem(unsigned short slot, const char *refId, unsigned int count, int charge, double enchantmentCharge) noexcept
|
||||||
{
|
{
|
||||||
tempActor.equipmentItems[slot].refId = refId;
|
tempActor.equipmentItems[slot].refId = refId;
|
||||||
|
@ -328,6 +353,12 @@ void ActorFunctions::SendActorEquipment() noexcept
|
||||||
mwmp::Networking::get().getActorPacketController()->GetPacket(ID_ACTOR_EQUIPMENT)->Send(writeActorList.guid);
|
mwmp::Networking::get().getActorPacketController()->GetPacket(ID_ACTOR_EQUIPMENT)->Send(writeActorList.guid);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ActorFunctions::SendActorAI() noexcept
|
||||||
|
{
|
||||||
|
mwmp::Networking::get().getActorPacketController()->GetPacket(ID_ACTOR_AI)->setActorList(&writeActorList);
|
||||||
|
mwmp::Networking::get().getActorPacketController()->GetPacket(ID_ACTOR_AI)->Send(writeActorList.guid);
|
||||||
|
}
|
||||||
|
|
||||||
void ActorFunctions::SendActorCellChange() noexcept
|
void ActorFunctions::SendActorCellChange() noexcept
|
||||||
{
|
{
|
||||||
mwmp::Networking::get().getActorPacketController()->GetPacket(ID_ACTOR_CELL_CHANGE)->setActorList(&writeActorList);
|
mwmp::Networking::get().getActorPacketController()->GetPacket(ID_ACTOR_CELL_CHANGE)->setActorList(&writeActorList);
|
||||||
|
|
|
@ -60,6 +60,10 @@
|
||||||
{"SetActorFatigueCurrent", ActorFunctions::SetActorFatigueCurrent},\
|
{"SetActorFatigueCurrent", ActorFunctions::SetActorFatigueCurrent},\
|
||||||
{"SetActorFatigueModified", ActorFunctions::SetActorFatigueModified},\
|
{"SetActorFatigueModified", ActorFunctions::SetActorFatigueModified},\
|
||||||
\
|
\
|
||||||
|
{"SetActorAIAction", ActorFunctions::SetActorAIAction},\
|
||||||
|
{"SetActorAITargetToPlayer", ActorFunctions::SetActorAITargetToPlayer},\
|
||||||
|
{"SetActorAITargetToActor", ActorFunctions::SetActorAITargetToActor},\
|
||||||
|
\
|
||||||
{"EquipActorItem", ActorFunctions::EquipActorItem},\
|
{"EquipActorItem", ActorFunctions::EquipActorItem},\
|
||||||
{"UnequipActorItem", ActorFunctions::UnequipActorItem},\
|
{"UnequipActorItem", ActorFunctions::UnequipActorItem},\
|
||||||
\
|
\
|
||||||
|
@ -70,9 +74,10 @@
|
||||||
{"SendActorPosition", ActorFunctions::SendActorPosition},\
|
{"SendActorPosition", ActorFunctions::SendActorPosition},\
|
||||||
{"SendActorStatsDynamic", ActorFunctions::SendActorStatsDynamic},\
|
{"SendActorStatsDynamic", ActorFunctions::SendActorStatsDynamic},\
|
||||||
{"SendActorEquipment", ActorFunctions::SendActorEquipment},\
|
{"SendActorEquipment", ActorFunctions::SendActorEquipment},\
|
||||||
|
{"SendActorAI", ActorFunctions::SendActorAI},\
|
||||||
{"SendActorCellChange", ActorFunctions::SendActorCellChange}
|
{"SendActorCellChange", ActorFunctions::SendActorCellChange}
|
||||||
|
|
||||||
class ActorFunctions
|
class ActorFunctions
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
@ -481,6 +486,31 @@ public:
|
||||||
*/
|
*/
|
||||||
static void SetActorFatigueModified(double value) noexcept;
|
static void SetActorFatigueModified(double value) noexcept;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Set the AI action of the temporary actor stored on the server.
|
||||||
|
*
|
||||||
|
* \param action The new action.
|
||||||
|
* \return void
|
||||||
|
*/
|
||||||
|
static void SetActorAIAction(unsigned int action) noexcept;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Set a player as the AI target of the temporary actor stored on the server.
|
||||||
|
*
|
||||||
|
* \param pid The player ID.
|
||||||
|
* \return void
|
||||||
|
*/
|
||||||
|
static void SetActorAITargetToPlayer(unsigned short pid) noexcept;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Set another actor as the AI target of the temporary actor stored on the server.
|
||||||
|
*
|
||||||
|
* \param refNumIndex The refNumIndex of the target actor.
|
||||||
|
* \param mpNum The mpNum of the target actor.
|
||||||
|
* \return void
|
||||||
|
*/
|
||||||
|
static void SetActorAITargetToActor(int refNumIndex, int mpNum) noexcept;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Equip an item in a certain slot of the equipment of the temporary actor stored
|
* \brief Equip an item in a certain slot of the equipment of the temporary actor stored
|
||||||
* on the server.
|
* on the server.
|
||||||
|
@ -561,6 +591,15 @@ public:
|
||||||
*/
|
*/
|
||||||
static void SendActorEquipment() noexcept;
|
static void SendActorEquipment() noexcept;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Send an ActorAI packet.
|
||||||
|
*
|
||||||
|
* It is sent only to the player for whom the current actor list was initialized.
|
||||||
|
*
|
||||||
|
* \return void
|
||||||
|
*/
|
||||||
|
static void SendActorAI() noexcept;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Send an ActorCellChange packet.
|
* \brief Send an ActorCellChange packet.
|
||||||
*
|
*
|
||||||
|
|
|
@ -244,6 +244,24 @@ void Cell::readSpeech(ActorList& actorList)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Cell::readAI(ActorList& actorList)
|
||||||
|
{
|
||||||
|
initializeDedicatedActors(actorList);
|
||||||
|
|
||||||
|
for (const auto &baseActor : actorList.baseActors)
|
||||||
|
{
|
||||||
|
std::string mapIndex = Main::get().getCellController()->generateMapIndex(baseActor);
|
||||||
|
|
||||||
|
if (dedicatedActors.count(mapIndex) > 0)
|
||||||
|
{
|
||||||
|
DedicatedActor *actor = dedicatedActors[mapIndex];
|
||||||
|
actor->aiAction = baseActor.aiAction;
|
||||||
|
actor->aiTarget = baseActor.aiTarget;
|
||||||
|
actor->setAI();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Cell::readAttack(ActorList& actorList)
|
void Cell::readAttack(ActorList& actorList)
|
||||||
{
|
{
|
||||||
for (const auto &baseActor : actorList.baseActors)
|
for (const auto &baseActor : actorList.baseActors)
|
||||||
|
|
|
@ -24,6 +24,7 @@ namespace mwmp
|
||||||
void readStatsDynamic(ActorList& actorList);
|
void readStatsDynamic(ActorList& actorList);
|
||||||
void readEquipment(ActorList& actorList);
|
void readEquipment(ActorList& actorList);
|
||||||
void readSpeech(ActorList& actorList);
|
void readSpeech(ActorList& actorList);
|
||||||
|
void readAI(ActorList& actorList);
|
||||||
void readAttack(ActorList& actorList);
|
void readAttack(ActorList& actorList);
|
||||||
void readCellChange(ActorList& actorList);
|
void readCellChange(ActorList& actorList);
|
||||||
|
|
||||||
|
|
|
@ -154,6 +154,17 @@ void CellController::readSpeech(ActorList& actorList)
|
||||||
cellsInitialized[mapIndex]->readSpeech(actorList);
|
cellsInitialized[mapIndex]->readSpeech(actorList);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CellController::readAI(ActorList& actorList)
|
||||||
|
{
|
||||||
|
std::string mapIndex = actorList.cell.getDescription();
|
||||||
|
|
||||||
|
initializeCell(actorList.cell);
|
||||||
|
|
||||||
|
// If this now exists, send it the data
|
||||||
|
if (cellsInitialized.count(mapIndex) > 0)
|
||||||
|
cellsInitialized[mapIndex]->readAI(actorList);
|
||||||
|
}
|
||||||
|
|
||||||
void CellController::readAttack(ActorList& actorList)
|
void CellController::readAttack(ActorList& actorList)
|
||||||
{
|
{
|
||||||
std::string mapIndex = actorList.cell.getDescription();
|
std::string mapIndex = actorList.cell.getDescription();
|
||||||
|
|
|
@ -27,6 +27,7 @@ namespace mwmp
|
||||||
void readStatsDynamic(mwmp::ActorList& actorList);
|
void readStatsDynamic(mwmp::ActorList& actorList);
|
||||||
void readEquipment(mwmp::ActorList& actorList);
|
void readEquipment(mwmp::ActorList& actorList);
|
||||||
void readSpeech(mwmp::ActorList& actorList);
|
void readSpeech(mwmp::ActorList& actorList);
|
||||||
|
void readAI(mwmp::ActorList& actorList);
|
||||||
void readAttack(mwmp::ActorList& actorList);
|
void readAttack(mwmp::ActorList& actorList);
|
||||||
void readCellChange(mwmp::ActorList& actorList);
|
void readCellChange(mwmp::ActorList& actorList);
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
|
|
||||||
#include "../mwdialogue/dialoguemanagerimp.hpp"
|
#include "../mwdialogue/dialoguemanagerimp.hpp"
|
||||||
|
|
||||||
|
#include "../mwmechanics/aifollow.hpp"
|
||||||
#include "../mwmechanics/creaturestats.hpp"
|
#include "../mwmechanics/creaturestats.hpp"
|
||||||
#include "../mwmechanics/mechanicsmanagerimp.hpp"
|
#include "../mwmechanics/mechanicsmanagerimp.hpp"
|
||||||
#include "../mwmechanics/movement.hpp"
|
#include "../mwmechanics/movement.hpp"
|
||||||
|
@ -203,6 +204,41 @@ void DedicatedActor::setEquipment()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DedicatedActor::setAI()
|
||||||
|
{
|
||||||
|
if (hasAiTarget)
|
||||||
|
{
|
||||||
|
MWWorld::Ptr targetPtr;
|
||||||
|
|
||||||
|
if (aiTarget.isPlayer)
|
||||||
|
targetPtr = MechanicsHelper::getPlayerPtr(aiTarget);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (mwmp::Main::get().getCellController()->isLocalActor(aiTarget.refNumIndex, aiTarget.mpNum))
|
||||||
|
targetPtr = mwmp::Main::get().getCellController()->getLocalActor(aiTarget.refNumIndex, aiTarget.mpNum)->getPtr();
|
||||||
|
else if (mwmp::Main::get().getCellController()->isDedicatedActor(aiTarget.refNumIndex, aiTarget.mpNum))
|
||||||
|
targetPtr = mwmp::Main::get().getCellController()->getDedicatedActor(aiTarget.refNumIndex, aiTarget.mpNum)->getPtr();
|
||||||
|
else
|
||||||
|
LOG_APPEND(Log::LOG_VERBOSE, "-- DedicatedActor %s %i-%i has invalid target AI target %i-%i",
|
||||||
|
ptr.getCellRef().getRefId().c_str(), ptr.getCellRef().getRefNum().mIndex, ptr.getCellRef().getMpNum(),
|
||||||
|
aiTarget.refNumIndex, aiTarget.mpNum);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (targetPtr)
|
||||||
|
{
|
||||||
|
LOG_APPEND(Log::LOG_VERBOSE, "-- DedicatedActor %s %i-%i has AI target %s %i-%i",
|
||||||
|
ptr.getCellRef().getRefId().c_str(), ptr.getCellRef().getRefNum().mIndex, ptr.getCellRef().getMpNum(),
|
||||||
|
targetPtr.getCellRef().getRefId().c_str(), aiTarget.refNumIndex, aiTarget.mpNum);
|
||||||
|
|
||||||
|
if (aiAction == mwmp::BaseActorList::FOLLOW)
|
||||||
|
{
|
||||||
|
MWMechanics::AiFollow package(targetPtr.getCellRef().getRefId());
|
||||||
|
ptr.getClass().getCreatureStats(ptr).getAiSequence().stack(package, ptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void DedicatedActor::playAnimation()
|
void DedicatedActor::playAnimation()
|
||||||
{
|
{
|
||||||
if (!animation.groupname.empty())
|
if (!animation.groupname.empty())
|
||||||
|
|
|
@ -22,6 +22,7 @@ namespace mwmp
|
||||||
void setAnimFlags();
|
void setAnimFlags();
|
||||||
void setStatsDynamic();
|
void setStatsDynamic();
|
||||||
void setEquipment();
|
void setEquipment();
|
||||||
|
void setAI();
|
||||||
void playAnimation();
|
void playAnimation();
|
||||||
void playSound();
|
void playSound();
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,7 @@ namespace mwmp
|
||||||
|
|
||||||
virtual void Do(ActorPacket &packet, ActorList &actorList)
|
virtual void Do(ActorPacket &packet, ActorList &actorList)
|
||||||
{
|
{
|
||||||
//Main::get().getCellController()->readAI(actorList);
|
Main::get().getCellController()->readAI(actorList);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,6 +39,10 @@ namespace mwmp
|
||||||
Animation animation;
|
Animation animation;
|
||||||
Attack attack;
|
Attack attack;
|
||||||
|
|
||||||
|
bool hasAiTarget;
|
||||||
|
Target aiTarget;
|
||||||
|
unsigned int aiAction;
|
||||||
|
|
||||||
bool hasPositionData;
|
bool hasPositionData;
|
||||||
bool hasStatsDynamicData;
|
bool hasStatsDynamicData;
|
||||||
|
|
||||||
|
@ -62,6 +66,11 @@ namespace mwmp
|
||||||
REQUEST = 3
|
REQUEST = 3
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum AI_ACTION
|
||||||
|
{
|
||||||
|
FOLLOW = 0
|
||||||
|
};
|
||||||
|
|
||||||
RakNet::RakNetGUID guid;
|
RakNet::RakNetGUID guid;
|
||||||
|
|
||||||
std::vector<BaseActor> baseActors;
|
std::vector<BaseActor> baseActors;
|
||||||
|
|
|
@ -11,5 +11,22 @@ PacketActorAI::PacketActorAI(RakNet::RakPeerInterface *peer) : ActorPacket(peer)
|
||||||
|
|
||||||
void PacketActorAI::Actor(BaseActor &actor, bool send)
|
void PacketActorAI::Actor(BaseActor &actor, bool send)
|
||||||
{
|
{
|
||||||
// Placeholder to be filled in later
|
RW(actor.aiAction, 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, 1);
|
||||||
|
RW(actor.aiTarget.refNumIndex, send);
|
||||||
|
RW(actor.aiTarget.mpNum, send);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue