diff --git a/Source/Contents/MovementRoute.cpp b/Source/Contents/MovementRoute.cpp new file mode 100644 index 0000000..a8c878b --- /dev/null +++ b/Source/Contents/MovementRoute.cpp @@ -0,0 +1,101 @@ +#include "Contents/MovementRouteInterpolation.h" +#include "Utility/Math/AffineMatrix.h" + +// OFFSET: 0x00AD7F70 +// FUNCTION: fn_17861 +MovementRouteInterpolation::MovementRouteInterpolation() : segment(0), startX(0), startY(0) { +} + +// OFFSET: 0x00AD87A0 +// FUNCTION: fn_17867 +void BuildMovementRoute(std::uint32_t tick, const MovementPathNode* last, int stepDuration, MovementRouteInterpolation& route) { + std::uint32_t count = 0; + for (const MovementPathNode* node = last; node; node = node->parent) { + ++count; + } + + route.points.resize(count); + if (static_cast(count) > 1) { + const MovementPathNode* node = last; + for (std::uint32_t index = count; index != 0;) { + --index; + route.points[index].x = node->x; + route.points[index].y = node->y; + route.points[index].metadata = node->metadata; + node = node->parent; + } + + const int diagonalDuration = static_cast(static_cast(stepDuration) * 1.414f); + route.points[0].tick = tick; + const float deltaY = static_cast(route.points[1].y) - route.startY; + const float deltaX = static_cast(route.points[1].x) - route.startX; + const float initialDuration = SquareRoot(deltaY * deltaY + deltaX * deltaX) * static_cast(stepDuration); + route.points[1].tick = tick + static_cast(initialDuration); + for (std::uint32_t index = 2; index < count; ++index) { + const int duration = route.points[index].metadata & 1 ? diagonalDuration : stepDuration; + route.points[index].tick = route.points[index - 1].tick + duration; + } + } +} + +// OFFSET: 0x00AD8D20 +// FUNCTION: fn_17869 +bool MovementRouteInterpolation::Point(int index, std::int32_t* x, std::int32_t* y) const { + if (this->points.empty() || index < 0 || static_cast(index) >= this->points.size()) { + return false; + } + + *x = this->points[index].x; + *y = this->points[index].y; + return true; +} + +// OFFSET: 0x00AD8D70 +// FUNCTION: fn_17870 +std::uint32_t* MovementRouteInterpolation::EndTick(std::uint32_t* tick) const { + *tick = this->points.back().tick; + return tick; +} + +// OFFSET: 0x00AD8D90 +// FUNCTION: fn_17871 +int MovementRouteInterpolation::EndMetadata() const { + if (this->points.empty()) { + return -1; + } + + return this->points.back().metadata; +} + +// OFFSET: 0x00AD8F20 +// FUNCTION: fn_17874 +int MovementRouteInterpolation::NextPoint(std::uint32_t tick, std::uint32_t* nextTick, float* x, float* y) const { + if (this->points.empty() || this->points.front().tick == 0) { + return -1; + } + + if (this->points.front().tick > tick) { + *nextTick = this->points[1].tick; + *x = static_cast(this->points[1].x); + *y = static_cast(this->points[1].y); + return 0; + } + + int index = 0; + const int last = static_cast(this->points.size()) - 1; + while (index < last) { + if (this->points[index].tick <= tick && tick < this->points[index + 1].tick) { + *nextTick = this->points[index + 1].tick; + *x = static_cast(this->points[index + 1].x); + *y = static_cast(this->points[index + 1].y); + return index; + } + + ++index; + } + + *nextTick = this->points[index].tick; + *x = static_cast(this->points[index].x); + *y = static_cast(this->points[index].y); + return -1; +} diff --git a/Source/Contents/MovementRouteInterpolation.h b/Source/Contents/MovementRouteInterpolation.h index 1b31063..4242eb3 100644 --- a/Source/Contents/MovementRouteInterpolation.h +++ b/Source/Contents/MovementRouteInterpolation.h @@ -1,9 +1,20 @@ #ifndef RAGNAROK_SOURCE_CONTENTS_MOVEMENTROUTEINTERPOLATION_H #define RAGNAROK_SOURCE_CONTENTS_MOVEMENTROUTEINTERPOLATION_H +#include #include #include +struct MovementPathNode { + /* 0000 */ std::int32_t x; + /* 0004 */ std::int32_t y; + /* 0008 */ MovementPathNode* parent; + /* 000C */ int cost; + /* 0010 */ int estimatedCost; + /* 0014 */ int state; + /* 0018 */ int metadata; +}; + struct MovementRoutePoint { /* 0000 */ std::int32_t x; /* 0004 */ std::int32_t y; @@ -12,18 +23,31 @@ struct MovementRoutePoint { }; struct MovementRouteInterpolation { + MovementRouteInterpolation(); + /* 0000 */ std::vector points; /* 000C */ std::uint32_t segment; /* 0010 */ float startX; /* 0014 */ float startY; + bool Point(int index, std::int32_t* x, std::int32_t* y) const; + std::uint32_t* EndTick(std::uint32_t* tick) const; + int EndMetadata() const; + int NextPoint(std::uint32_t tick, std::uint32_t* nextTick, float* x, float* y) const; int Sample(std::uint32_t tick, float* x, float* y, int* metadata); std::uint32_t Segment() const; }; +void BuildMovementRoute(std::uint32_t tick, const MovementPathNode* last, int stepDuration, MovementRouteInterpolation& route); + static_assert(sizeof(MovementRoutePoint) == 16); #if defined(_WIN32) && !defined(_WIN64) +static_assert(sizeof(MovementPathNode) == 28); +static_assert(offsetof(MovementPathNode, metadata) == 0x18); static_assert(sizeof(MovementRouteInterpolation) == 24); +static_assert(offsetof(MovementRouteInterpolation, segment) == 0xC); +static_assert(offsetof(MovementRouteInterpolation, startX) == 0x10); +static_assert(offsetof(MovementRouteInterpolation, startY) == 0x14); #endif #endif diff --git a/compile.json b/compile.json index 777aa63..22625a4 100644 --- a/compile.json +++ b/compile.json @@ -352,6 +352,7 @@ "Source/Contents/Models/ModelRendering.cpp": 3, "Source/Contents/Models/ModelSpatial.cpp": 3, "Source/Contents/Models/ModelTextureAnimation.cpp": 3, + "Source/Contents/MovementRoute.cpp": 4, "Source/Contents/MovementRouteInterpolation.cpp": 4, "Source/Contents/Movies/BinkMovie.cpp": 3, "Source/Contents/Movies/BinkMovies.cpp": 3,