mirror of
https://github.com/DarkflameUniverse/DarkflameServer.git
synced 2026-10-02 10:53:44 +00:00
CollectibleComponent (79 rows: id, requirement_mission) is only in the CDClient for the server: the 1.10.64 client has no string for it. DLU never read it. What the column holds (1.10.64 CDClient, joined with ComponentsRegistry, Missions and MissionTasks): for 63 rows it is the mission the collectible belongs to. Mostly that is the achievement whose collection task (taskType 3) targets the collectible's LOT (the flags, imagination bricks, Johnny Thunder collectibles). For a few it is a mission to accept from an NPC that does not collect the item itself: the four Ninjago dragon relics (16483-16485) are collected by the hidden achievements 2064-2067 but their requirement is 2040 (accepted from LOT 13789, "complete 2064-2067"). Other values: -1 and 66666666 (no such mission) on test rows. So a collectible whose requirement_mission is a mission to accept (Missions.isMission) now only counts (HasBeenCollected progresses nothing) while the player has that mission accepted and not handed in (ACTIVE, READY_TO_COMPLETE or their repeat states). Achievements, missing missions and rows without one are unchanged. Without this, a player who had not accepted 2040 could collect the relics early and have 2040 complete as soon as it was accepted. The gate itself is inferred from the data: the captures show collections but not the live server's check. The collectible's object report shows the requirement mission. Check in game: in Ninjago Monastery, before accepting the dragon relic mission (2040), touch a dragon relic: it does not count; accept 2040 and collect them: each counts and 2040 completes after the fourth. Flags, imagination bricks and Johnny Thunder collectibles still count as before. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
287 lines
9.8 KiB
C++
287 lines
9.8 KiB
C++
#include "MissionMessages.h"
|
|
|
|
#include "BitStreamUtils.h"
|
|
#include "Character.h"
|
|
#include "CppScripts.h"
|
|
#include "dConfig.h"
|
|
#include "eMissionLockState.h"
|
|
#include "eMissionState.h"
|
|
#include "eMissionTaskType.h"
|
|
#include "ePlayerFlag.h"
|
|
#include "eReplicaComponentType.h"
|
|
#include "Entity.h"
|
|
#include "EntityManager.h"
|
|
#include "Game.h"
|
|
#include "Logger.h"
|
|
#include "Mission.h"
|
|
#include "CollectibleComponent.h"
|
|
#include "MissionComponent.h"
|
|
#include "MissionOfferComponent.h"
|
|
#include "EffectsMessages.h"
|
|
|
|
namespace GameMessages {
|
|
void OfferMission::Serialize(RakNet::BitStream& bitStream) const {
|
|
bitStream.Write(missionID);
|
|
bitStream.Write(offerer);
|
|
}
|
|
|
|
bool OfferMission::Deserialize(RakNet::BitStream& bitStream) {
|
|
VALIDATE_READ(bitStream.Read(missionID));
|
|
VALIDATE_READ(bitStream.Read(offerer));
|
|
return true;
|
|
}
|
|
|
|
void RespondToMission::Serialize(RakNet::BitStream& bitStream) const {
|
|
bitStream.Write(missionID);
|
|
bitStream.Write(playerID);
|
|
bitStream.Write(receiver);
|
|
BitStreamUtils::WriteOptional(bitStream, rewardItem, LOT_NULL);
|
|
}
|
|
|
|
bool RespondToMission::Deserialize(RakNet::BitStream& bitStream) {
|
|
VALIDATE_READ(bitStream.Read(missionID));
|
|
VALIDATE_READ(bitStream.Read(playerID));
|
|
VALIDATE_READ(bitStream.Read(receiver));
|
|
VALIDATE_READ(BitStreamUtils::ReadOptional(bitStream, rewardItem, LOT_NULL));
|
|
return true;
|
|
}
|
|
|
|
void RespondToMission::Handle(Entity& entity, const SystemAddress& sysAddr) {
|
|
const auto reward = rewardItem;
|
|
MissionComponent* missionComponent = static_cast<MissionComponent*>(entity.GetComponent(eReplicaComponentType::MISSION));
|
|
if (!missionComponent) {
|
|
LOG("Unable to get mission component for entity %llu to handle RespondToMission", playerID);
|
|
return;
|
|
}
|
|
|
|
Mission* mission = missionComponent->GetMission(missionID);
|
|
if (mission) {
|
|
mission->SetReward(reward);
|
|
} else {
|
|
LOG("Unable to get mission %i for entity %llu to update reward in RespondToMission", missionID, playerID);
|
|
}
|
|
|
|
Entity* offerer = Game::entityManager->GetEntity(receiver);
|
|
|
|
if (offerer == nullptr) {
|
|
LOG("Unable to get receiver entity %llu for RespondToMission", receiver);
|
|
return;
|
|
}
|
|
|
|
offerer->GetScript()->OnRespondToMission(offerer, missionID, Game::entityManager->GetEntity(playerID), reward);
|
|
}
|
|
|
|
void NotifyMission::Serialize(RakNet::BitStream& bitStream) const {
|
|
bitStream.Write(missionID);
|
|
bitStream.Write(missionState);
|
|
bitStream.Write(sendingRewards);
|
|
}
|
|
|
|
bool NotifyMission::Deserialize(RakNet::BitStream& bitStream) {
|
|
VALIDATE_READ(bitStream.Read(missionID));
|
|
VALIDATE_READ(bitStream.Read(missionState));
|
|
VALIDATE_READ(bitStream.Read(sendingRewards));
|
|
return true;
|
|
}
|
|
|
|
void NotifyMissionTask::Serialize(RakNet::BitStream& bitStream) const {
|
|
bitStream.Write(missionID);
|
|
bitStream.Write(taskMask);
|
|
bitStream.Write<uint8_t>(updates.size());
|
|
for (const auto update : updates) bitStream.Write(update);
|
|
}
|
|
|
|
bool NotifyMissionTask::Deserialize(RakNet::BitStream& bitStream) {
|
|
VALIDATE_READ(bitStream.Read(missionID));
|
|
VALIDATE_READ(bitStream.Read(taskMask));
|
|
uint8_t count{};
|
|
VALIDATE_READ(bitStream.Read(count));
|
|
updates.resize(count);
|
|
for (auto& update : updates) VALIDATE_READ(bitStream.Read(update));
|
|
return true;
|
|
}
|
|
|
|
void ResetMissions::Serialize(RakNet::BitStream& bitStream) const {
|
|
BitStreamUtils::WriteOptional(bitStream, missionID, -1);
|
|
}
|
|
|
|
bool ResetMissions::Deserialize(RakNet::BitStream& bitStream) {
|
|
VALIDATE_READ(BitStreamUtils::ReadOptional(bitStream, missionID, -1));
|
|
return true;
|
|
}
|
|
|
|
void MissionDialogueOK::Serialize(RakNet::BitStream& bitStream) const {
|
|
bitStream.Write(bIsComplete);
|
|
bitStream.Write(iMissionState);
|
|
bitStream.Write(missionID);
|
|
bitStream.Write(responder);
|
|
}
|
|
|
|
bool MissionDialogueOK::Deserialize(RakNet::BitStream& bitStream) {
|
|
VALIDATE_READ(bitStream.Read(bIsComplete));
|
|
VALIDATE_READ(bitStream.Read(iMissionState));
|
|
VALIDATE_READ(bitStream.Read(missionID));
|
|
VALIDATE_READ(bitStream.Read(responder));
|
|
return true;
|
|
}
|
|
|
|
void MissionDialogueCancelled::Serialize(RakNet::BitStream& bitStream) const {
|
|
bitStream.Write(bIsComplete);
|
|
bitStream.Write(iMissionState);
|
|
bitStream.Write(missionID);
|
|
bitStream.Write(responder);
|
|
}
|
|
|
|
bool MissionDialogueCancelled::Deserialize(RakNet::BitStream& bitStream) {
|
|
VALIDATE_READ(bitStream.Read(bIsComplete));
|
|
VALIDATE_READ(bitStream.Read(iMissionState));
|
|
VALIDATE_READ(bitStream.Read(missionID));
|
|
VALIDATE_READ(bitStream.Read(responder));
|
|
return true;
|
|
}
|
|
|
|
void MissionDialogueOK::Handle(Entity& entityRef, const SystemAddress& sysAddr) {
|
|
Entity* entity = &entityRef;
|
|
Entity* player = Game::entityManager->GetEntity(responder);
|
|
if (!player) {
|
|
LOG("MissionDialogueOK for mission %i from unknown responder %llu", missionID, responder);
|
|
return;
|
|
}
|
|
|
|
entity->GetScript()->OnMissionDialogueOK(entity, player, missionID, iMissionState);
|
|
|
|
// Get the player's mission component
|
|
MissionComponent* missionComponent = static_cast<MissionComponent*>(player->GetComponent(eReplicaComponentType::MISSION));
|
|
if (!missionComponent) {
|
|
LOG("Unable to get mission component for entity %llu to handle MissionDialogueOK", player->GetObjectID());
|
|
return;
|
|
}
|
|
|
|
if (iMissionState == eMissionState::AVAILABLE || iMissionState == eMissionState::COMPLETE_AVAILABLE) {
|
|
missionComponent->AcceptMission(missionID);
|
|
} else if (iMissionState == eMissionState::READY_TO_COMPLETE || iMissionState == eMissionState::COMPLETE_READY_TO_COMPLETE) {
|
|
missionComponent->CompleteMission(missionID);
|
|
}
|
|
|
|
if (Game::config->GetValue("allow_players_to_skip_cinematics") != "1"
|
|
|| !player->GetCharacter()
|
|
|| !player->GetCharacter()->GetPlayerFlag(ePlayerFlag::DLU_SKIP_CINEMATICS)) return;
|
|
player->AddCallbackTimer(0.5f, [player]() {
|
|
if (!player) return;
|
|
GameMessages::EndCinematic endCinematic;
|
|
endCinematic.target = player->GetObjectID();
|
|
endCinematic.Send(player->GetSystemAddress());
|
|
});
|
|
}
|
|
|
|
void RequestLinkedMission::Serialize(RakNet::BitStream& bitStream) const {
|
|
bitStream.Write(playerID);
|
|
bitStream.Write(missionID);
|
|
bitStream.Write(bMissionOffered);
|
|
}
|
|
|
|
bool RequestLinkedMission::Deserialize(RakNet::BitStream& bitStream) {
|
|
VALIDATE_READ(bitStream.Read(playerID));
|
|
VALIDATE_READ(bitStream.Read(missionID));
|
|
VALIDATE_READ(bitStream.Read(bMissionOffered));
|
|
return true;
|
|
}
|
|
|
|
void RequestLinkedMission::Handle(Entity& entity, const SystemAddress& sysAddr) {
|
|
auto* player = Game::entityManager->GetEntity(playerID);
|
|
|
|
auto* missionOfferComponent = static_cast<MissionOfferComponent*>(entity.GetComponent(eReplicaComponentType::MISSION_OFFER));
|
|
|
|
if (missionOfferComponent != nullptr) {
|
|
missionOfferComponent->OfferMissions(player, 0);
|
|
}
|
|
}
|
|
|
|
void SetFlag::Serialize(RakNet::BitStream& bitStream) const {
|
|
bitStream.Write(bFlag);
|
|
bitStream.Write(iFlagID);
|
|
}
|
|
|
|
bool SetFlag::Deserialize(RakNet::BitStream& bitStream) {
|
|
VALIDATE_READ(bitStream.Read(bFlag));
|
|
VALIDATE_READ(bitStream.Read(iFlagID));
|
|
return true;
|
|
}
|
|
|
|
void SetFlag::Handle(Entity& entity, const SystemAddress& sysAddr) {
|
|
auto character = entity.GetCharacter();
|
|
if (character) character->SetPlayerFlag(iFlagID, bFlag);
|
|
|
|
// This is always set the first time a player loads into a world from character select
|
|
// and is used to know when to refresh the players inventory items so they show up.
|
|
if (iFlagID == ePlayerFlag::IS_NEWS_SCREEN_VISIBLE && bFlag) {
|
|
entity.SetVar<bool>(u"dlu_first_time_load", true);
|
|
}
|
|
}
|
|
|
|
void NotifyClientFlagChange::Serialize(RakNet::BitStream& bitStream) const {
|
|
bitStream.Write(bFlag);
|
|
bitStream.Write(iFlagID);
|
|
}
|
|
|
|
bool NotifyClientFlagChange::Deserialize(RakNet::BitStream& bitStream) {
|
|
VALIDATE_READ(bitStream.Read(bFlag));
|
|
VALIDATE_READ(bitStream.Read(iFlagID));
|
|
return true;
|
|
}
|
|
|
|
void HasBeenCollected::Serialize(RakNet::BitStream& bitStream) const {
|
|
bitStream.Write(playerID);
|
|
}
|
|
|
|
bool HasBeenCollected::Deserialize(RakNet::BitStream& bitStream) {
|
|
VALIDATE_READ(bitStream.Read(playerID));
|
|
return true;
|
|
}
|
|
|
|
void HasBeenCollected::Handle(Entity& entity, const SystemAddress& sysAddr) {
|
|
Entity* player = Game::entityManager->GetEntity(playerID);
|
|
if (!player || entity.GetCollectibleID() == 0) return;
|
|
|
|
// Collectibles of a mission to accept only count while the player has it
|
|
const auto* const collectible = entity.GetComponent<CollectibleComponent>();
|
|
if (collectible && !collectible->CountsFor(*player)) return;
|
|
|
|
MissionComponent* missionComponent = static_cast<MissionComponent*>(player->GetComponent(eReplicaComponentType::MISSION));
|
|
if (missionComponent) {
|
|
missionComponent->Progress(eMissionTaskType::COLLECTION, entity.GetLOT(), entity.GetObjectID());
|
|
}
|
|
}
|
|
|
|
SetMissionTypeState::SetMissionTypeState() : NetGameMsg(MessageType::Game::SET_MISSION_TYPE_STATE), state{ eMissionLockState::NEW } {}
|
|
|
|
void SetMissionTypeState::Serialize(RakNet::BitStream& bitStream) const {
|
|
BitStreamUtils::WriteOptional(bitStream, state, eMissionLockState::NEW);
|
|
BitStreamUtils::WriteLengthPrefixed(bitStream, subtype);
|
|
BitStreamUtils::WriteLengthPrefixed(bitStream, type);
|
|
}
|
|
|
|
bool SetMissionTypeState::Deserialize(RakNet::BitStream& bitStream) {
|
|
VALIDATE_READ(BitStreamUtils::ReadOptional(bitStream, state, eMissionLockState::NEW));
|
|
VALIDATE_READ(BitStreamUtils::ReadLengthPrefixed(bitStream, subtype));
|
|
VALIDATE_READ(BitStreamUtils::ReadLengthPrefixed(bitStream, type));
|
|
return true;
|
|
}
|
|
|
|
void SetMissionTypeState::Handle(Entity& entity, const SystemAddress& sysAddr) {
|
|
auto* const missionComponent = entity.GetComponent<MissionComponent>();
|
|
if (missionComponent) missionComponent->SetMissionTypeState(type, subtype, state);
|
|
}
|
|
|
|
void NotifyLevelRewards::Serialize(RakNet::BitStream& bitStream) const {
|
|
bitStream.Write(level);
|
|
bitStream.Write(sendingRewards);
|
|
}
|
|
|
|
bool NotifyLevelRewards::Deserialize(RakNet::BitStream& bitStream) {
|
|
VALIDATE_READ(bitStream.Read(level));
|
|
VALIDATE_READ(bitStream.Read(sendingRewards));
|
|
return true;
|
|
}
|
|
}
|