diff --git a/apps/openmw-mp/CMakeLists.txt b/apps/openmw-mp/CMakeLists.txt index 65eb032b9..75389e2b8 100644 --- a/apps/openmw-mp/CMakeLists.txt +++ b/apps/openmw-mp/CMakeLists.txt @@ -113,10 +113,10 @@ source_group(tes3mp-server FILES ${SERVER} ${SERVER_HEADER}) set(PROCESSORS_ACTOR processors/actor/ProcessorActorAnimFlags.hpp processors/actor/ProcessorActorAnimPlay.hpp processors/actor/ProcessorActorAttack.hpp processors/actor/ProcessorActorCellChange.hpp - processors/actor/ProcessorActorEquipment.hpp processors/actor/ProcessorActorInteraction.hpp - processors/actor/ProcessorActorList.hpp processors/actor/ProcessorActorPosition.hpp - processors/actor/ProcessorActorSpeech.hpp processors/actor/ProcessorActorStatsDynamic.hpp - processors/actor/ProcessorActorTest.hpp + processors/actor/ProcessorActorDeath.hpp processors/actor/ProcessorActorEquipment.hpp + processors/actor/ProcessorActorInteraction.hpp processors/actor/ProcessorActorList.hpp + processors/actor/ProcessorActorPosition.hpp processors/actor/ProcessorActorSpeech.hpp + processors/actor/ProcessorActorStatsDynamic.hpp processors/actor/ProcessorActorTest.hpp ) source_group(tes3mp-server\\processors\\actor FILES ${PROCESSORS_ACTOR}) diff --git a/apps/openmw-mp/Script/Functions/Actors.cpp b/apps/openmw-mp/Script/Functions/Actors.cpp index 65b69772f..2d721744a 100644 --- a/apps/openmw-mp/Script/Functions/Actors.cpp +++ b/apps/openmw-mp/Script/Functions/Actors.cpp @@ -168,6 +168,11 @@ double ActorFunctions::GetActorEquipmentItemEnchantmentCharge(unsigned int i, un return readActorList->baseActors.at(i).equipmentItems[slot].enchantmentCharge; } +const char *ActorFunctions::GetActorDeathReason(unsigned int i) noexcept +{ + return readActorList->baseActors.at(i).deathReason.c_str(); +} + bool ActorFunctions::DoesActorHavePosition(unsigned int i) noexcept { return readActorList->baseActors.at(i).hasPositionData; diff --git a/apps/openmw-mp/Script/Functions/Actors.hpp b/apps/openmw-mp/Script/Functions/Actors.hpp index cc2792fd6..44d104cd3 100644 --- a/apps/openmw-mp/Script/Functions/Actors.hpp +++ b/apps/openmw-mp/Script/Functions/Actors.hpp @@ -36,6 +36,8 @@ {"GetActorEquipmentItemCharge", ActorFunctions::GetActorEquipmentItemCharge},\ {"GetActorEquipmentItemEnchantmentCharge", ActorFunctions::GetActorEquipmentItemEnchantmentCharge},\ \ + {"GetActorDeathReason", ActorFunctions::GetActorDeathReason},\ + \ {"DoesActorHavePosition", ActorFunctions::DoesActorHavePosition},\ {"DoesActorHaveStatsDynamic", ActorFunctions::DoesActorHaveStatsDynamic},\ \ @@ -315,6 +317,14 @@ public: */ static double GetActorEquipmentItemEnchantmentCharge(unsigned int i, unsigned short slot) noexcept; + /** + * \brief Get the death reason of the actor at a certain index in the read actor list. + * + * \param i The index of the actor. + * \return The death reason. + */ + static const char *GetActorDeathReason(unsigned int i) noexcept; + /** * \brief Check whether there is any positional data for the actor at a certain index in * the read actor list. diff --git a/apps/openmw-mp/Script/ScriptFunctions.hpp b/apps/openmw-mp/Script/ScriptFunctions.hpp index 21a6323e4..495dfa2e4 100644 --- a/apps/openmw-mp/Script/ScriptFunctions.hpp +++ b/apps/openmw-mp/Script/ScriptFunctions.hpp @@ -340,6 +340,7 @@ public: {"OnObjectTrap", Function()}, {"OnActorList", Function()}, {"OnActorEquipment", Function()}, + {"OnActorDeath", Function()}, {"OnActorCellChange", Function()}, {"OnActorTest", Function()}, {"OnPlayerSendMessage", Function()}, diff --git a/apps/openmw-mp/processors/actor/ProcessorActorDeath.hpp b/apps/openmw-mp/processors/actor/ProcessorActorDeath.hpp index ef6953318..9d1981c55 100644 --- a/apps/openmw-mp/processors/actor/ProcessorActorDeath.hpp +++ b/apps/openmw-mp/processors/actor/ProcessorActorDeath.hpp @@ -19,7 +19,11 @@ namespace mwmp Cell *serverCell = CellController::get()->getCell(&actorList.cell); if (serverCell != nullptr && *serverCell->getAuthority() == actorList.guid) + { + Script::Call(player.getId(), actorList.cell.getDescription().c_str()); + serverCell->sendToLoaded(&packet, &actorList); + } } }; } diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index 8e59a7aa1..5a5ed80cc 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -540,6 +540,8 @@ namespace MWClass Start of tes3mp addition If the attacker was the LocalPlayer or LocalActor, record their target and send a packet with it + + If the victim was a LocalActor who died, record their attacker as the deathReason */ mwmp::Attack *localAttack = MechanicsHelper::getLocalAttack(attacker); @@ -553,6 +555,14 @@ namespace MWClass localAttack->shouldSend = true; } + + if (mwmp::Main::get().getCellController()->isLocalActor(ptr)) + { + if (getCreatureStats(ptr).isDead()) + { + mwmp::Main::get().getCellController()->getLocalActor(ptr)->deathReason = attacker.getClass().getName(attacker); + } + } /* End of tes3mp addition */ diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index c91bab33f..8bfc84fa3 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -953,6 +953,8 @@ namespace MWClass If the victim was the LocalPlayer, check whether packets should be sent about their new dynamic stats and position + + If the victim was a LocalActor who died, record their attacker as the deathReason */ mwmp::Attack *localAttack = MechanicsHelper::getLocalAttack(attacker); @@ -978,6 +980,13 @@ namespace MWClass mwmp::Main::get().getLocalPlayer()->deathReason = attacker.getClass().getName(attacker); } } + else if (mwmp::Main::get().getCellController()->isLocalActor(ptr)) + { + if (getCreatureStats(ptr).isDead()) + { + mwmp::Main::get().getCellController()->getLocalActor(ptr)->deathReason = attacker.getClass().getName(attacker); + } + } /* End of tes3mp addition */ diff --git a/apps/openmw/mwmp/ActorList.cpp b/apps/openmw/mwmp/ActorList.cpp index c32495da6..11d3d3d15 100644 --- a/apps/openmw/mwmp/ActorList.cpp +++ b/apps/openmw/mwmp/ActorList.cpp @@ -32,6 +32,7 @@ void ActorList::reset() animPlayActors.clear(); speechActors.clear(); statsDynamicActors.clear(); + deathActors.clear(); equipmentActors.clear(); attackActors.clear(); cellChangeActors.clear(); @@ -73,6 +74,11 @@ void ActorList::addStatsDynamicActor(LocalActor localActor) statsDynamicActors.push_back(localActor); } +void ActorList::addDeathActor(LocalActor localActor) +{ + deathActors.push_back(localActor); +} + void ActorList::addEquipmentActor(LocalActor localActor) { equipmentActors.push_back(localActor); @@ -138,6 +144,16 @@ void ActorList::sendStatsDynamicActors() } } +void ActorList::sendDeathActors() +{ + if (deathActors.size() > 0) + { + baseActors = deathActors; + Main::get().getNetworking()->getActorPacket(ID_ACTOR_DEATH)->setActorList(this); + Main::get().getNetworking()->getActorPacket(ID_ACTOR_DEATH)->Send(); + } +} + void ActorList::sendEquipmentActors() { if (equipmentActors.size() > 0) diff --git a/apps/openmw/mwmp/ActorList.hpp b/apps/openmw/mwmp/ActorList.hpp index 4f8d4b831..369d6be24 100644 --- a/apps/openmw/mwmp/ActorList.hpp +++ b/apps/openmw/mwmp/ActorList.hpp @@ -26,6 +26,7 @@ namespace mwmp void addAnimPlayActor(LocalActor localActor); void addSpeechActor(LocalActor localActor); void addStatsDynamicActor(LocalActor localActor); + void addDeathActor(LocalActor localActor); void addEquipmentActor(LocalActor localActor); void addAttackActor(LocalActor localActor); void addCellChangeActor(LocalActor localActor); @@ -35,6 +36,7 @@ namespace mwmp void sendAnimPlayActors(); void sendSpeechActors(); void sendStatsDynamicActors(); + void sendDeathActors(); void sendEquipmentActors(); void sendAttackActors(); void sendCellChangeActors(); @@ -49,6 +51,7 @@ namespace mwmp std::vector animPlayActors; std::vector speechActors; std::vector statsDynamicActors; + std::vector deathActors; std::vector equipmentActors; std::vector attackActors; std::vector cellChangeActors; diff --git a/apps/openmw/mwmp/Cell.cpp b/apps/openmw/mwmp/Cell.cpp index b20cf4796..3a3bfdc8f 100644 --- a/apps/openmw/mwmp/Cell.cpp +++ b/apps/openmw/mwmp/Cell.cpp @@ -93,6 +93,7 @@ void Cell::updateLocal(bool forceUpdate) actorList->sendAnimFlagsActors(); actorList->sendAnimPlayActors(); actorList->sendSpeechActors(); + actorList->sendDeathActors(); actorList->sendStatsDynamicActors(); actorList->sendEquipmentActors(); actorList->sendAttackActors(); @@ -370,6 +371,11 @@ void Cell::initializeLocalActor(const MWWorld::Ptr& ptr) actor->cell = *store->getCell(); actor->setPtr(ptr); + // Note that this actor was already dead when we were given control over it, + // to avoid sending an ActorDeath packet + if (ptr.getClass().getCreatureStats(ptr).isDead()) + actor->wasDead = true; + std::string mapIndex = Main::get().getCellController()->generateMapIndex(ptr); localActors[mapIndex] = actor; diff --git a/apps/openmw/mwmp/LocalActor.cpp b/apps/openmw/mwmp/LocalActor.cpp index 79be0e6e1..922720bf8 100644 --- a/apps/openmw/mwmp/LocalActor.cpp +++ b/apps/openmw/mwmp/LocalActor.cpp @@ -30,6 +30,7 @@ LocalActor::LocalActor() wasForceJumping = false; wasForceMoveJumping = false; wasFlying = false; + wasDead = false; attack.type = Attack::MELEE; attack.shouldSend = false; @@ -179,6 +180,22 @@ void LocalActor::updateStatsDynamic(bool forceUpdate) creatureStats.mDead = ptrCreatureStats->isDead(); mwmp::Main::get().getNetworking()->getActorList()->addStatsDynamicActor(*this); + + if (creatureStats.mDead && !wasDead) + { + if (deathReason.empty()) + deathReason = "suicide"; + + LOG_MESSAGE_SIMPLE(Log::LOG_INFO, "Sending ID_ACTOR_DEATH about %s-%i-%i to server", + refId.c_str(), refNumIndex, mpNum); + LOG_APPEND(Log::LOG_INFO, "- deathReason was %s", deathReason.c_str()); + + mwmp::Main::get().getNetworking()->getActorList()->addDeathActor(*this); + + deathReason = ""; + } + + wasDead = creatureStats.mDead; } } diff --git a/apps/openmw/mwmp/LocalActor.hpp b/apps/openmw/mwmp/LocalActor.hpp index c78358f98..35ba5f407 100644 --- a/apps/openmw/mwmp/LocalActor.hpp +++ b/apps/openmw/mwmp/LocalActor.hpp @@ -28,6 +28,8 @@ namespace mwmp MWWorld::Ptr getPtr(); void setPtr(const MWWorld::Ptr& newPtr); + bool wasDead; + private: MWWorld::Ptr ptr; diff --git a/components/openmw-mp/Base/BaseActor.hpp b/components/openmw-mp/Base/BaseActor.hpp index 8cbd32dcc..0441c8b7d 100644 --- a/components/openmw-mp/Base/BaseActor.hpp +++ b/components/openmw-mp/Base/BaseActor.hpp @@ -39,6 +39,8 @@ namespace mwmp Animation animation; Attack attack; + std::string deathReason; + bool hasAiTarget; Target aiTarget; unsigned int aiAction; diff --git a/components/openmw-mp/Packets/Actor/PacketActorDeath.cpp b/components/openmw-mp/Packets/Actor/PacketActorDeath.cpp index b2b3d95a6..0e8982fb1 100644 --- a/components/openmw-mp/Packets/Actor/PacketActorDeath.cpp +++ b/components/openmw-mp/Packets/Actor/PacketActorDeath.cpp @@ -11,5 +11,5 @@ PacketActorDeath::PacketActorDeath(RakNet::RakPeerInterface *peer) : ActorPacket void PacketActorDeath::Actor(BaseActor &actor, bool send) { - // Placeholder to be filled in later + RW(actor.deathReason, send); }