mirror of
https://github.com/mod-playerbots/azerothcore-wotlk.git
synced 2026-01-22 13:16:23 +00:00
fix(Core): Activate creatures and objects during opening cinematics (#4045)
Co-authored-by: Si1ker <55638679+Sombranator@users.noreply.github.com> Co-authored-by: Stefano Borzì <stefanoborzi32@gmail.com>
This commit is contained in:
@@ -15,6 +15,9 @@
|
||||
#include "BattlegroundMgr.h"
|
||||
#include "World.h"
|
||||
#include <map>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
|
||||
typedef std::map<uint16, uint32> AreaFlagByAreaID;
|
||||
typedef std::map<uint32, uint32> AreaFlagByMapID;
|
||||
@@ -41,6 +44,7 @@ DBCStorage <CharTitlesEntry> sCharTitlesStore(CharTitlesEntryfmt);
|
||||
DBCStorage <ChatChannelsEntry> sChatChannelsStore(ChatChannelsEntryfmt);
|
||||
DBCStorage <ChrClassesEntry> sChrClassesStore(ChrClassesEntryfmt);
|
||||
DBCStorage <ChrRacesEntry> sChrRacesStore(ChrRacesEntryfmt);
|
||||
DBCStorage <CinematicCameraEntry> sCinematicCameraStore(CinematicCameraEntryfmt);
|
||||
DBCStorage <CinematicSequencesEntry> sCinematicSequencesStore(CinematicSequencesEntryfmt);
|
||||
DBCStorage <CreatureDisplayInfoEntry> sCreatureDisplayInfoStore(CreatureDisplayInfofmt);
|
||||
DBCStorage <CreatureFamilyEntry> sCreatureFamilyStore(CreatureFamilyfmt);
|
||||
@@ -171,6 +175,8 @@ DBCStorage <WMOAreaTableEntry> sWMOAreaTableStore(WMOAreaTableEntryfmt);
|
||||
DBCStorage <WorldMapAreaEntry> sWorldMapAreaStore(WorldMapAreaEntryfmt);
|
||||
DBCStorage <WorldMapOverlayEntry> sWorldMapOverlayStore(WorldMapOverlayEntryfmt);
|
||||
|
||||
std::unordered_map<uint32, FlyByCameraCollection> sFlyByCameraStore;
|
||||
|
||||
typedef std::list<std::string> StoreProblemList;
|
||||
|
||||
uint32 DBCFileCount = 0;
|
||||
@@ -258,6 +264,7 @@ void LoadDBCStores(const std::string& dataPath)
|
||||
LOAD_DBC(sChatChannelsStore, "ChatChannels.dbc", "chatchannels_dbc");
|
||||
LOAD_DBC(sChrClassesStore, "ChrClasses.dbc", "chrclasses_dbc");
|
||||
LOAD_DBC(sChrRacesStore, "ChrRaces.dbc", "chrraces_dbc");
|
||||
LOAD_DBC(sCinematicCameraStore, "CinematicCamera.dbc", "cinematiccamera_dbc");
|
||||
LOAD_DBC(sCinematicSequencesStore, "CinematicSequences.dbc", "cinematicsequences_dbc");
|
||||
LOAD_DBC(sCreatureDisplayInfoStore, "CreatureDisplayInfo.dbc", "creaturedisplayinfo_dbc");
|
||||
LOAD_DBC(sCreatureFamilyStore, "CreatureFamily.dbc", "creaturefamily_dbc");
|
||||
@@ -583,10 +590,278 @@ void LoadDBCStores(const std::string& dataPath)
|
||||
exit(1);
|
||||
}
|
||||
|
||||
LoadM2Cameras(dataPath);
|
||||
|
||||
sLog->outString(">> Initialized %d data stores in %u ms", DBCFileCount, GetMSTimeDiffToNow(oldMSTime));
|
||||
sLog->outString();
|
||||
}
|
||||
|
||||
// Convert the geomoetry from a spline value, to an actual WoW XYZ
|
||||
G3D::Vector3 TranslateLocation(G3D::Vector4 const* DBCPosition, G3D::Vector3 const* basePosition, G3D::Vector3 const* splineVector)
|
||||
{
|
||||
G3D::Vector3 work;
|
||||
float x = basePosition->x + splineVector->x;
|
||||
float y = basePosition->y + splineVector->y;
|
||||
float z = basePosition->z + splineVector->z;
|
||||
float const distance = sqrt((x * x) + (y * y));
|
||||
float angle = std::atan2(x, y) - DBCPosition->w;
|
||||
|
||||
if (angle < 0)
|
||||
{
|
||||
angle += 2 * float(M_PI);
|
||||
}
|
||||
|
||||
work.x = DBCPosition->x + (distance * sin(angle));
|
||||
work.y = DBCPosition->y + (distance * cos(angle));
|
||||
work.z = DBCPosition->z + z;
|
||||
return work;
|
||||
}
|
||||
|
||||
// Number of cameras not used. Multiple cameras never used in 3.3.5
|
||||
bool readCamera(M2Camera const* cam, uint32 buffSize, M2Header const* header, CinematicCameraEntry const* dbcentry)
|
||||
{
|
||||
char const* buffer = reinterpret_cast<char const*>(header);
|
||||
|
||||
FlyByCameraCollection cameras;
|
||||
FlyByCameraCollection targetcam;
|
||||
|
||||
G3D::Vector4 DBCData;
|
||||
DBCData.x = dbcentry->base_x;
|
||||
DBCData.y = dbcentry->base_y;
|
||||
DBCData.z = dbcentry->base_z;
|
||||
DBCData.w = dbcentry->base_o;
|
||||
|
||||
// Read target locations, only so that we can calculate orientation
|
||||
for (uint32 k = 0; k < cam->target_positions.timestamps.number; ++k)
|
||||
{
|
||||
// Extract Target positions
|
||||
if (cam->target_positions.timestamps.offset_elements + sizeof(M2Array) > buffSize)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
M2Array const* targTsArray = reinterpret_cast<M2Array const*>(buffer + cam->target_positions.timestamps.offset_elements);
|
||||
if (targTsArray->offset_elements + sizeof(uint32) > buffSize || cam->target_positions.values.offset_elements + sizeof(M2Array) > buffSize)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
uint32 const* targTimestamps = reinterpret_cast<uint32 const*>(buffer + targTsArray->offset_elements);
|
||||
M2Array const* targArray = reinterpret_cast<M2Array const*>(buffer + cam->target_positions.values.offset_elements);
|
||||
|
||||
if (targArray->offset_elements + sizeof(M2SplineKey<G3D::Vector3>) > buffSize)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
M2SplineKey<G3D::Vector3> const* targPositions = reinterpret_cast<M2SplineKey<G3D::Vector3> const*>(buffer + targArray->offset_elements);
|
||||
|
||||
// Read the data for this set
|
||||
uint32 currPos = targArray->offset_elements;
|
||||
for (uint32 i = 0; i < targTsArray->number; ++i)
|
||||
{
|
||||
if (currPos + sizeof(M2SplineKey<G3D::Vector3>) > buffSize)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
// Translate co-ordinates
|
||||
G3D::Vector3 newPos = TranslateLocation(&DBCData, &cam->target_position_base, &targPositions->p0);
|
||||
|
||||
// Add to vector
|
||||
FlyByCamera thisCam;
|
||||
thisCam.timeStamp = targTimestamps[i];
|
||||
thisCam.locations.x = newPos.x;
|
||||
thisCam.locations.y = newPos.y;
|
||||
thisCam.locations.z = newPos.z;
|
||||
thisCam.locations.w = 0.0f;
|
||||
targetcam.push_back(thisCam);
|
||||
targPositions++;
|
||||
currPos += sizeof(M2SplineKey<G3D::Vector3>);
|
||||
}
|
||||
}
|
||||
|
||||
// Read camera positions and timestamps (translating first position of 3 only, we don't need to translate the whole spline)
|
||||
for (uint32 k = 0; k < cam->positions.timestamps.number; ++k)
|
||||
{
|
||||
// Extract Camera positions for this set
|
||||
if (cam->positions.timestamps.offset_elements + sizeof(M2Array) > buffSize)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
M2Array const* posTsArray = reinterpret_cast<M2Array const*>(buffer + cam->positions.timestamps.offset_elements);
|
||||
if (posTsArray->offset_elements + sizeof(uint32) > buffSize || cam->positions.values.offset_elements + sizeof(M2Array) > buffSize)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
uint32 const* posTimestamps = reinterpret_cast<uint32 const*>(buffer + posTsArray->offset_elements);
|
||||
M2Array const* posArray = reinterpret_cast<M2Array const*>(buffer + cam->positions.values.offset_elements);
|
||||
if (posArray->offset_elements + sizeof(M2SplineKey<G3D::Vector3>) > buffSize)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
M2SplineKey<G3D::Vector3> const* positions = reinterpret_cast<M2SplineKey<G3D::Vector3> const*>(buffer + posArray->offset_elements);
|
||||
|
||||
// Read the data for this set
|
||||
uint32 currPos = posArray->offset_elements;
|
||||
for (uint32 i = 0; i < posTsArray->number; ++i)
|
||||
{
|
||||
if (currPos + sizeof(M2SplineKey<G3D::Vector3>) > buffSize)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
// Translate co-ordinates
|
||||
G3D::Vector3 newPos = TranslateLocation(&DBCData, &cam->position_base, &positions->p0);
|
||||
|
||||
// Add to vector
|
||||
FlyByCamera thisCam;
|
||||
thisCam.timeStamp = posTimestamps[i];
|
||||
thisCam.locations.x = newPos.x;
|
||||
thisCam.locations.y = newPos.y;
|
||||
thisCam.locations.z = newPos.z;
|
||||
|
||||
if (targetcam.size() > 0)
|
||||
{
|
||||
// Find the target camera before and after this camera
|
||||
FlyByCamera lastTarget;
|
||||
FlyByCamera nextTarget;
|
||||
|
||||
// Pre-load first item
|
||||
lastTarget = targetcam[0];
|
||||
nextTarget = targetcam[0];
|
||||
for (uint32 j = 0; j < targetcam.size(); ++j)
|
||||
{
|
||||
nextTarget = targetcam[j];
|
||||
if (targetcam[j].timeStamp > posTimestamps[i])
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
lastTarget = targetcam[j];
|
||||
}
|
||||
|
||||
float x = lastTarget.locations.x;
|
||||
float y = lastTarget.locations.y;
|
||||
// float z = lastTarget.locations.z;
|
||||
|
||||
// Now, the timestamps for target cam and position can be different. So, if they differ we interpolate
|
||||
if (lastTarget.timeStamp != posTimestamps[i])
|
||||
{
|
||||
uint32 timeDiffTarget = nextTarget.timeStamp - lastTarget.timeStamp;
|
||||
uint32 timeDiffThis = posTimestamps[i] - lastTarget.timeStamp;
|
||||
float xDiff = nextTarget.locations.x - lastTarget.locations.x;
|
||||
float yDiff = nextTarget.locations.y - lastTarget.locations.y;
|
||||
// float zDiff = nextTarget.locations.z - lastTarget.locations.z;
|
||||
x = lastTarget.locations.x + (xDiff * (float(timeDiffThis) / float(timeDiffTarget)));
|
||||
y = lastTarget.locations.y + (yDiff * (float(timeDiffThis) / float(timeDiffTarget)));
|
||||
// z = lastTarget.locations.z + (zDiff * (float(timeDiffThis) / float(timeDiffTarget)));
|
||||
}
|
||||
float xDiff = x - thisCam.locations.x;
|
||||
float yDiff = y - thisCam.locations.y;
|
||||
thisCam.locations.w = std::atan2(yDiff, xDiff);
|
||||
|
||||
if (thisCam.locations.w < 0)
|
||||
{
|
||||
thisCam.locations.w += 2 * float(M_PI);
|
||||
}
|
||||
}
|
||||
|
||||
cameras.push_back(thisCam);
|
||||
positions++;
|
||||
currPos += sizeof(M2SplineKey<G3D::Vector3>);
|
||||
}
|
||||
}
|
||||
|
||||
sFlyByCameraStore[dbcentry->id] = cameras;
|
||||
return true;
|
||||
}
|
||||
|
||||
void LoadM2Cameras(const std::string& dataPath)
|
||||
{
|
||||
sFlyByCameraStore.clear();
|
||||
sLog->outString(">> Loading Cinematic Camera files");
|
||||
|
||||
uint32 oldMSTime = getMSTime();
|
||||
for (uint32 i = 0; i < sCinematicCameraStore.GetNumRows(); ++i)
|
||||
{
|
||||
if (CinematicCameraEntry const* dbcentry = sCinematicCameraStore.LookupEntry(i))
|
||||
{
|
||||
std::string filename = dataPath.c_str();
|
||||
filename.append(dbcentry->filename);
|
||||
|
||||
// Replace slashes
|
||||
size_t loc = filename.find("\\");
|
||||
while (loc != std::string::npos)
|
||||
{
|
||||
filename.replace(loc, 1, "/");
|
||||
loc = filename.find("\\");
|
||||
}
|
||||
|
||||
// Replace mdx to .m2
|
||||
loc = filename.find(".mdx");
|
||||
if (loc != std::string::npos)
|
||||
{
|
||||
filename.replace(loc, 4, ".m2");
|
||||
}
|
||||
|
||||
std::ifstream m2file(filename.c_str(), std::ios::in | std::ios::binary);
|
||||
if (!m2file.is_open())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Get file size
|
||||
m2file.seekg(0, std::ios::end);
|
||||
std::streamoff const fileSize = m2file.tellg();
|
||||
|
||||
// Reject if not at least the size of the header
|
||||
if (static_cast<uint32 const>(fileSize) < sizeof(M2Header))
|
||||
{
|
||||
sLog->outError("Camera file %s is damaged. File is smaller than header size", filename.c_str());
|
||||
m2file.close();
|
||||
continue;
|
||||
}
|
||||
|
||||
// Read 4 bytes (signature)
|
||||
m2file.seekg(0, std::ios::beg);
|
||||
char fileCheck[5];
|
||||
m2file.read(fileCheck, 4);
|
||||
fileCheck[4] = 0;
|
||||
|
||||
// Check file has correct magic (MD20)
|
||||
if (strcmp(fileCheck, "MD20"))
|
||||
{
|
||||
sLog->outError("Camera file %s is damaged. File identifier not found", filename.c_str());
|
||||
m2file.close();
|
||||
continue;
|
||||
}
|
||||
|
||||
// Now we have a good file, read it all into a vector of char's, then close the file.
|
||||
std::vector<char> buffer(fileSize);
|
||||
m2file.seekg(0, std::ios::beg);
|
||||
if (!m2file.read(buffer.data(), fileSize))
|
||||
{
|
||||
m2file.close();
|
||||
continue;
|
||||
}
|
||||
m2file.close();
|
||||
|
||||
// Read header
|
||||
M2Header const* header = reinterpret_cast<M2Header const*>(buffer.data());
|
||||
|
||||
if (header->ofsCameras + sizeof(M2Camera) > static_cast<uint32 const>(fileSize))
|
||||
{
|
||||
sLog->outError("Camera file %s is damaged. Camera references position beyond file end", filename.c_str());
|
||||
continue;
|
||||
}
|
||||
|
||||
// Get camera(s) - Main header, then dump them.
|
||||
M2Camera const* cam = reinterpret_cast<M2Camera const*>(buffer.data() + header->ofsCameras);
|
||||
if (!readCamera(cam, fileSize, header, dbcentry))
|
||||
{
|
||||
sLog->outError("Camera file %s is damaged. Camera references position beyond file end", filename.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
sLog->outString(">> Loaded %u cinematic waypoint sets in %u ms", (uint32)sFlyByCameraStore.size(), GetMSTimeDiffToNow(oldMSTime));
|
||||
}
|
||||
|
||||
SimpleFactionsList const* GetFactionTeamList(uint32 faction)
|
||||
{
|
||||
FactionTeamMap::const_iterator itr = sFactionTeamMap.find(faction);
|
||||
|
||||
@@ -13,6 +13,8 @@
|
||||
#include <list>
|
||||
|
||||
typedef std::list<uint32> SimpleFactionsList;
|
||||
typedef std::vector<FlyByCamera> FlyByCameraCollection;
|
||||
|
||||
SimpleFactionsList const* GetFactionTeamList(uint32 faction);
|
||||
|
||||
char* GetPetName(uint32 petfamily, uint32 dbclang);
|
||||
@@ -67,6 +69,7 @@ extern DBCStorage <CharStartOutfitEntry> sCharStartOutfitStore;
|
||||
extern DBCStorage <CharTitlesEntry> sCharTitlesStore;
|
||||
extern DBCStorage <ChrClassesEntry> sChrClassesStore;
|
||||
extern DBCStorage <ChrRacesEntry> sChrRacesStore;
|
||||
extern DBCStorage <CinematicCameraEntry> sCinematicCameraStore;
|
||||
extern DBCStorage <CinematicSequencesEntry> sCinematicSequencesStore;
|
||||
extern DBCStorage <CreatureDisplayInfoEntry> sCreatureDisplayInfoStore;
|
||||
extern DBCStorage <CreatureFamilyEntry> sCreatureFamilyStore;
|
||||
@@ -160,7 +163,9 @@ extern DBCStorage <VehicleSeatEntry> sVehicleSeatStore;
|
||||
extern DBCStorage <WMOAreaTableEntry> sWMOAreaTableStore;
|
||||
//extern DBCStorage <WorldMapAreaEntry> sWorldMapAreaStore; -- use Zone2MapCoordinates and Map2ZoneCoordinates
|
||||
extern DBCStorage <WorldMapOverlayEntry> sWorldMapOverlayStore;
|
||||
extern std::unordered_map<uint32, FlyByCameraCollection> sFlyByCameraStore;
|
||||
|
||||
void LoadDBCStores(const std::string& dataPath);
|
||||
void LoadM2Cameras(const std::string& dataPath);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1529,13 +1529,23 @@ bool Position::IsPositionValid() const
|
||||
float WorldObject::GetGridActivationRange() const
|
||||
{
|
||||
if (ToPlayer())
|
||||
{
|
||||
if (ToPlayer()->IsOnCinematic())
|
||||
{
|
||||
return DEFAULT_VISIBILITY_INSTANCE;
|
||||
}
|
||||
return IsInWintergrasp() ? VISIBILITY_DIST_WINTERGRASP : GetMap()->GetVisibilityRange();
|
||||
}
|
||||
else if (ToCreature())
|
||||
{
|
||||
return ToCreature()->m_SightDistance;
|
||||
else if (GetTypeId() == TYPEID_GAMEOBJECT && ToGameObject()->IsTransport())
|
||||
}
|
||||
else if (GetTypeId() == TYPEID_GAMEOBJECT && ToGameObject()->IsTransport() && isActiveObject())
|
||||
{
|
||||
return GetMap()->GetVisibilityRange();
|
||||
else
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
float WorldObject::GetVisibilityRange() const
|
||||
@@ -1564,15 +1574,27 @@ float WorldObject::GetSightRange(const WorldObject* target) const
|
||||
if (target)
|
||||
{
|
||||
if (target->IsVisibilityOverridden() && target->GetTypeId() == TYPEID_UNIT)
|
||||
{
|
||||
return MAX_VISIBILITY_DISTANCE;
|
||||
}
|
||||
else if (target->GetTypeId() == TYPEID_GAMEOBJECT)
|
||||
{
|
||||
if (IsInWintergrasp() && target->IsInWintergrasp())
|
||||
{
|
||||
return VISIBILITY_DIST_WINTERGRASP + VISIBILITY_INC_FOR_GOBJECTS;
|
||||
}
|
||||
else if (target->IsVisibilityOverridden())
|
||||
{
|
||||
return MAX_VISIBILITY_DISTANCE;
|
||||
}
|
||||
else if (ToPlayer()->IsOnCinematic())
|
||||
{
|
||||
return DEFAULT_VISIBILITY_INSTANCE;
|
||||
}
|
||||
else
|
||||
{
|
||||
return GetMap()->GetVisibilityRange() + VISIBILITY_INC_FOR_GOBJECTS;
|
||||
}
|
||||
}
|
||||
|
||||
return IsInWintergrasp() && target->IsInWintergrasp() ? VISIBILITY_DIST_WINTERGRASP : GetMap()->GetVisibilityRange();
|
||||
@@ -1580,9 +1602,18 @@ float WorldObject::GetSightRange(const WorldObject* target) const
|
||||
return IsInWintergrasp() ? VISIBILITY_DIST_WINTERGRASP : GetMap()->GetVisibilityRange();
|
||||
}
|
||||
else if (ToCreature())
|
||||
{
|
||||
return ToCreature()->m_SightDistance;
|
||||
}
|
||||
else
|
||||
{
|
||||
return SIGHT_RANGE_UNIT;
|
||||
}
|
||||
}
|
||||
|
||||
if (ToDynObject() && isActiveObject())
|
||||
{
|
||||
return GetMap()->GetVisibilityRange();
|
||||
}
|
||||
|
||||
return 0.0f;
|
||||
|
||||
@@ -97,6 +97,9 @@
|
||||
#define SKILL_PERM_BONUS(x) int16(PAIR32_HIPART(x))
|
||||
#define MAKE_SKILL_BONUS(t, p) MAKE_PAIR32(t, p)
|
||||
|
||||
#define CINEMATIC_LOOKAHEAD (2 * IN_MILLISECONDS)
|
||||
#define CINEMATIC_UPDATEDIFF 500
|
||||
|
||||
enum CharacterFlags
|
||||
{
|
||||
CHARACTER_FLAG_NONE = 0x00000000,
|
||||
@@ -944,6 +947,13 @@ Player::Player(WorldSession* session): Unit(true), m_mover(this)
|
||||
|
||||
_activeCheats = CHEAT_NONE;
|
||||
|
||||
m_cinematicDiff = 0;
|
||||
m_lastCinematicCheck = 0;
|
||||
m_activeCinematicCameraId = 0;
|
||||
m_cinematicCamera = nullptr;
|
||||
m_remoteSightPosition = Position(0.0f, 0.0f, 0.0f);
|
||||
m_CinematicObject = nullptr;
|
||||
|
||||
m_achievementMgr = new AchievementMgr(this);
|
||||
m_reputationMgr = new ReputationMgr(this);
|
||||
|
||||
@@ -1589,6 +1599,14 @@ void Player::Update(uint32 p_time)
|
||||
m_nextMailDelivereTime = 0;
|
||||
}
|
||||
|
||||
// Update cinematic location, if 500ms have passed and we're doing a cinematic now.
|
||||
m_cinematicDiff += p_time;
|
||||
if (m_cinematicCamera && m_activeCinematicCameraId && GetMSTimeDiffToNow(m_lastCinematicCheck) > CINEMATIC_UPDATEDIFF)
|
||||
{
|
||||
m_lastCinematicCheck = getMSTime();
|
||||
UpdateCinematicLocation(p_time);
|
||||
}
|
||||
|
||||
//used to implement delayed far teleports
|
||||
SetMustDelayTeleport(true);
|
||||
Unit::Update(p_time);
|
||||
@@ -6980,6 +6998,10 @@ void Player::SendCinematicStart(uint32 CinematicSequenceId)
|
||||
WorldPacket data(SMSG_TRIGGER_CINEMATIC, 4);
|
||||
data << uint32(CinematicSequenceId);
|
||||
SendDirectMessage(&data);
|
||||
if (const CinematicSequencesEntry* sequence = sCinematicSequencesStore.LookupEntry(CinematicSequenceId))
|
||||
{
|
||||
SetActiveCinematicCamera(sequence->cinematicCamera);
|
||||
}
|
||||
}
|
||||
|
||||
void Player::SendMovieStart(uint32 MovieId)
|
||||
@@ -27695,6 +27717,142 @@ bool Player::SetFeatherFall(bool apply, bool packetOnly /*= false*/)
|
||||
return true;
|
||||
}
|
||||
|
||||
void Player::BeginCinematic()
|
||||
{
|
||||
// Sanity check for active camera set
|
||||
if (m_activeCinematicCameraId == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
auto itr = sFlyByCameraStore.find(m_activeCinematicCameraId);
|
||||
if (itr != sFlyByCameraStore.end())
|
||||
{
|
||||
// Initialize diff, and set camera
|
||||
m_cinematicDiff = 0;
|
||||
m_cinematicCamera = &itr->second;
|
||||
|
||||
auto camitr = m_cinematicCamera->begin();
|
||||
if (camitr != m_cinematicCamera->end())
|
||||
{
|
||||
Position pos(camitr->locations.x, camitr->locations.y, camitr->locations.z, camitr->locations.w);
|
||||
if (!pos.IsPositionValid())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
m_mapRef->LoadGrid(camitr->locations.x, camitr->locations.y);
|
||||
m_CinematicObject = SummonCreature(VISUAL_WAYPOINT, pos.m_positionX, pos.m_positionY, pos.m_positionZ, 0.0f, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 120000);
|
||||
if (m_CinematicObject)
|
||||
{
|
||||
m_CinematicObject->setActive(true);
|
||||
SetViewpoint(m_CinematicObject, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Player::EndCinematic()
|
||||
{
|
||||
m_cinematicDiff = 0;
|
||||
m_cinematicCamera = nullptr;
|
||||
m_activeCinematicCameraId = 0;
|
||||
if (m_CinematicObject)
|
||||
{
|
||||
if (m_seer && m_seer == m_CinematicObject)
|
||||
{
|
||||
SetViewpoint(m_CinematicObject, false);
|
||||
}
|
||||
m_CinematicObject->AddObjectToRemoveList();
|
||||
}
|
||||
}
|
||||
|
||||
void Player::UpdateCinematicLocation(uint32 /*diff*/)
|
||||
{
|
||||
Position lastPosition;
|
||||
uint32 lastTimestamp = 0;
|
||||
Position nextPosition;
|
||||
uint32 nextTimestamp = 0;
|
||||
|
||||
if (m_cinematicCamera->size() == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Obtain direction of travel
|
||||
for (FlyByCamera cam : *m_cinematicCamera)
|
||||
{
|
||||
if (cam.timeStamp > m_cinematicDiff)
|
||||
{
|
||||
nextPosition = Position(cam.locations.x, cam.locations.y, cam.locations.z, cam.locations.w);
|
||||
nextTimestamp = cam.timeStamp;
|
||||
break;
|
||||
}
|
||||
lastPosition = Position(cam.locations.x, cam.locations.y, cam.locations.z, cam.locations.w);
|
||||
lastTimestamp = cam.timeStamp;
|
||||
}
|
||||
float angle = lastPosition.GetAngle(&nextPosition);
|
||||
angle -= lastPosition.GetOrientation();
|
||||
if (angle < 0)
|
||||
{
|
||||
angle += 2 * float(M_PI);
|
||||
}
|
||||
|
||||
// Look for position around 2 second ahead of us.
|
||||
int32 workDiff = m_cinematicDiff;
|
||||
|
||||
// Modify result based on camera direction (Humans for example, have the camera point behind)
|
||||
workDiff += static_cast<int32>(float(CINEMATIC_LOOKAHEAD) * cos(angle));
|
||||
|
||||
// Get an iterator to the last entry in the cameras, to make sure we don't go beyond the end
|
||||
FlyByCameraCollection::const_reverse_iterator endItr = m_cinematicCamera->rbegin();
|
||||
if (endItr != m_cinematicCamera->rend() && workDiff > static_cast<int32>(endItr->timeStamp))
|
||||
{
|
||||
workDiff = endItr->timeStamp;
|
||||
}
|
||||
|
||||
// Never try to go back in time before the start of cinematic!
|
||||
if (workDiff < 0)
|
||||
{
|
||||
workDiff = m_cinematicDiff;
|
||||
}
|
||||
|
||||
// Obtain the previous and next waypoint based on timestamp
|
||||
for (FlyByCamera cam : *m_cinematicCamera)
|
||||
{
|
||||
if (static_cast<int32>(cam.timeStamp) >= workDiff)
|
||||
{
|
||||
nextPosition = Position(cam.locations.x, cam.locations.y, cam.locations.z, cam.locations.w);
|
||||
nextTimestamp = cam.timeStamp;
|
||||
break;
|
||||
}
|
||||
lastPosition = Position(cam.locations.x, cam.locations.y, cam.locations.z, cam.locations.w);
|
||||
lastTimestamp = cam.timeStamp;
|
||||
}
|
||||
|
||||
// Never try to go beyond the end of the cinematic
|
||||
if (workDiff > static_cast<int32>(nextTimestamp))
|
||||
{
|
||||
workDiff = static_cast<int32>(nextTimestamp);
|
||||
}
|
||||
|
||||
// Interpolate the position for this moment in time (or the adjusted moment in time)
|
||||
uint32 timeDiff = nextTimestamp - lastTimestamp;
|
||||
uint32 interDiff = workDiff - lastTimestamp;
|
||||
float xDiff = nextPosition.m_positionX - lastPosition.m_positionX;
|
||||
float yDiff = nextPosition.m_positionY - lastPosition.m_positionY;
|
||||
float zDiff = nextPosition.m_positionZ - lastPosition.m_positionZ;
|
||||
Position interPosition(lastPosition.m_positionX + (xDiff * (float(interDiff) / float (timeDiff))), lastPosition.m_positionY +
|
||||
(yDiff * (float(interDiff) / float (timeDiff))), lastPosition.m_positionZ + (zDiff * (float(interDiff) / float (timeDiff))));
|
||||
|
||||
// Advance (at speed) to this position. The remote sight object is used
|
||||
// to send update information to player in cinematic
|
||||
if (m_CinematicObject && interPosition.IsPositionValid())
|
||||
{
|
||||
m_CinematicObject->MonsterMoveWithSpeed(interPosition.m_positionX, interPosition.m_positionY, interPosition.m_positionZ, 200.0f);
|
||||
}
|
||||
}
|
||||
|
||||
Guild* Player::GetGuild() const
|
||||
{
|
||||
uint32 guildId = GetGuildId();
|
||||
|
||||
@@ -2641,6 +2641,17 @@ public:
|
||||
|
||||
static std::unordered_map<int, bgZoneRef> bgZoneIdToFillWorldStates; // zoneId -> FillInitialWorldStates
|
||||
|
||||
// Cinematic camera data and remote sight functions
|
||||
[[nodiscard]] uint32 GetActiveCinematicCamera() const { return m_activeCinematicCameraId; }
|
||||
void SetActiveCinematicCamera(uint32 cinematicCameraId = 0) { m_activeCinematicCameraId = cinematicCameraId; }
|
||||
[[nodiscard]] bool IsOnCinematic() const { return (m_cinematicCamera != nullptr); }
|
||||
void BeginCinematic();
|
||||
void EndCinematic();
|
||||
void UpdateCinematicLocation(uint32 diff);
|
||||
|
||||
std::string GetMapAreaAndZoneString();
|
||||
std::string GetCoordsMapAreaAndZoneString();
|
||||
|
||||
protected:
|
||||
// Gamemaster whisper whitelist
|
||||
WhisperListContainer WhisperList;
|
||||
@@ -2990,6 +3001,14 @@ private:
|
||||
uint32 manaBeforeDuel;
|
||||
|
||||
bool m_isInstantFlightOn;
|
||||
|
||||
// Remote location information
|
||||
uint32 m_cinematicDiff;
|
||||
uint32 m_lastCinematicCheck;
|
||||
uint32 m_activeCinematicCameraId;
|
||||
FlyByCameraCollection* m_cinematicCamera;
|
||||
Position m_remoteSightPosition;
|
||||
Creature* m_CinematicObject;
|
||||
};
|
||||
|
||||
void AddItemsSetItem(Player* player, Item* item);
|
||||
|
||||
@@ -963,15 +963,23 @@ void WorldSession::HandleSetActionButtonOpcode(WorldPacket& recv_data)
|
||||
void WorldSession::HandleCompleteCinematic(WorldPacket& /*recv_data*/)
|
||||
{
|
||||
#if defined(ENABLE_EXTRAS) && defined(ENABLE_EXTRA_LOGS)
|
||||
{
|
||||
sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_COMPLETE_CINEMATIC");
|
||||
}
|
||||
#endif
|
||||
// If player has sight bound to visual waypoint NPC we should remove it
|
||||
GetPlayer()->EndCinematic();
|
||||
}
|
||||
|
||||
void WorldSession::HandleNextCinematicCamera(WorldPacket& /*recv_data*/)
|
||||
{
|
||||
#if defined(ENABLE_EXTRAS) && defined(ENABLE_EXTRA_LOGS)
|
||||
{
|
||||
sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_NEXT_CINEMATIC_CAMERA");
|
||||
}
|
||||
#endif
|
||||
// Sent by client when cinematic actually begun. So we begin the server side process
|
||||
GetPlayer()->BeginCinematic();
|
||||
}
|
||||
|
||||
void WorldSession::HandleFeatherFallAck(WorldPacket& recv_data)
|
||||
|
||||
@@ -785,6 +785,19 @@ void Map::Update(const uint32 t_diff, const uint32 s_diff, bool /*thread*/)
|
||||
|
||||
VisitNearbyCellsOfPlayer(player, grid_object_update, world_object_update, grid_large_object_update, world_large_object_update);
|
||||
|
||||
// If player is using far sight, visit that object too
|
||||
if (WorldObject* viewPoint = player->GetViewpoint())
|
||||
{
|
||||
if (Creature* viewCreature = viewPoint->ToCreature())
|
||||
{
|
||||
VisitNearbyCellsOf(viewCreature, grid_object_update, world_object_update, grid_large_object_update, world_large_object_update);
|
||||
}
|
||||
else if (DynamicObject* viewObject = viewPoint->ToDynObject())
|
||||
{
|
||||
VisitNearbyCellsOf(viewObject, grid_object_update, world_object_update, grid_large_object_update, world_large_object_update);
|
||||
}
|
||||
}
|
||||
|
||||
// handle updates for creatures in combat with player and are more than X yards away
|
||||
if (player->IsInCombat())
|
||||
{
|
||||
@@ -2269,6 +2282,28 @@ char const* Map::GetMapName() const
|
||||
return i_mapEntry ? i_mapEntry->name[sWorld->GetDefaultDbcLocale()] : "UNNAMEDMAP\x0";
|
||||
}
|
||||
|
||||
void Map::UpdateObjectVisibility(WorldObject* obj, Cell cell, CellCoord cellpair)
|
||||
{
|
||||
cell.SetNoCreate();
|
||||
acore::VisibleChangesNotifier notifier(*obj);
|
||||
TypeContainerVisitor<acore::VisibleChangesNotifier, WorldTypeMapContainer > player_notifier(notifier);
|
||||
cell.Visit(cellpair, player_notifier, *this, *obj, obj->GetVisibilityRange());
|
||||
}
|
||||
|
||||
void Map::UpdateObjectsVisibilityFor(Player* player, Cell cell, CellCoord cellpair)
|
||||
{
|
||||
acore::VisibleNotifier notifier(*player, false, false);
|
||||
|
||||
cell.SetNoCreate();
|
||||
TypeContainerVisitor<acore::VisibleNotifier, WorldTypeMapContainer > world_notifier(notifier);
|
||||
TypeContainerVisitor<acore::VisibleNotifier, GridTypeMapContainer > grid_notifier(notifier);
|
||||
cell.Visit(cellpair, world_notifier, *this, *player->m_seer, player->GetSightRange());
|
||||
cell.Visit(cellpair, grid_notifier, *this, *player->m_seer, player->GetSightRange());
|
||||
|
||||
// send data
|
||||
notifier.SendToSelf();
|
||||
}
|
||||
|
||||
void Map::SendInitSelf(Player* player)
|
||||
{
|
||||
#if defined(ENABLE_EXTRAS) && defined(ENABLE_EXTRA_LOGS)
|
||||
|
||||
@@ -407,8 +407,8 @@ public:
|
||||
void AddObjectToSwitchList(WorldObject* obj, bool on);
|
||||
virtual void DelayedUpdate(const uint32 diff);
|
||||
|
||||
//void UpdateObjectVisibility(WorldObject* obj, Cell cell, CellCoord cellpair);
|
||||
//void UpdateObjectsVisibilityFor(Player* player, Cell cell, CellCoord cellpair);
|
||||
void UpdateObjectVisibility(WorldObject* obj, Cell cell, CellCoord cellpair);
|
||||
void UpdateObjectsVisibilityFor(Player* player, Cell cell, CellCoord cellpair);
|
||||
|
||||
void resetMarkedCells() { marked_cells.reset(); }
|
||||
bool isCellMarked(uint32 pCellId) { return marked_cells.test(pCellId); }
|
||||
|
||||
Reference in New Issue
Block a user