Batch #12114 by Yommy: 0 byte-identical, 1 confirmed by peer review. - fn_07750 CActRes::Load: logic confirmed by peer review Peer-reviewed-by: KWDev, SapitoSucio, Tanke Accepted without human review: peers confirmed the logic ("same" ahead by at least 3, with 70% of the votes).
271 lines
7.6 KiB
C++
271 lines
7.6 KiB
C++
#include "Client/Application/ErrorDialog.h"
|
|
#include "File/File.h"
|
|
#include "Render/DeviceContext/DCSurface.h"
|
|
#include "Resource/Sprites/ActionResource.h"
|
|
#include "Resource/Bitmap/BitmapResource.h"
|
|
#include "Resource/ResourceByteReader.h"
|
|
#include "Resource/ResourceMgr.h"
|
|
#include "Resource/Sprites/SpriteResource.h"
|
|
|
|
#include "Utility/Math/ScalarConversion.h"
|
|
#include <algorithm>
|
|
#include <cstring>
|
|
|
|
namespace {
|
|
// INLINED
|
|
int RelativeCoordinate(int position, int extent, float scale) {
|
|
const int center = extent / 2 + extent % 2;
|
|
const float offset = static_cast<float>(center) * scale;
|
|
const float coordinate = static_cast<float>(position) - offset;
|
|
|
|
return TruncateToInt(coordinate / scale);
|
|
}
|
|
}
|
|
|
|
// INLINED
|
|
CActRes::CActRes() : maximumCells(0) {
|
|
}
|
|
|
|
// OFFSET: 0x00745FB0
|
|
// FUNCTION: fn_07767
|
|
CActRes::~CActRes() = default;
|
|
|
|
// OFFSET: 0x007436B0
|
|
// FUNCTION: fn_07749
|
|
CActRes* CActRes::Create() {
|
|
return new CActRes;
|
|
}
|
|
|
|
// OFFSET: 0x007437B0
|
|
// FUNCTION: fn_07750
|
|
bool CActRes::Load(const char* name) {
|
|
CFile file;
|
|
if (!file.Open(name, 0, true, false)) {
|
|
ShowErrorDialog(GetRenderSystemHolder()->system, (std::string("Cannot find File : ") + std::string(name)).c_str(), 0);
|
|
return false;
|
|
}
|
|
|
|
struct Header {
|
|
std::uint16_t magic;
|
|
std::uint16_t version;
|
|
std::uint16_t count;
|
|
unsigned char reserved[10];
|
|
} header;
|
|
file.Read(&header, sizeof(header));
|
|
|
|
if (header.magic != 0x4341) {
|
|
ShowErrorDialog(GetRenderSystemHolder()->system, "Illegal file format", 0);
|
|
ShowErrorDialog(GetRenderSystemHolder()->system, name, 0);
|
|
file.Close();
|
|
|
|
return false;
|
|
}
|
|
|
|
std::string spriteName(name);
|
|
spriteName.resize(spriteName.size() - 4);
|
|
spriteName.append(".spr", 4);
|
|
|
|
if (header.version > 0x0205) {
|
|
ShowErrorDialog(GetRenderSystemHolder()->system, "Unsupported Version. Content may be corrupted", 0);
|
|
file.Close();
|
|
return false;
|
|
}
|
|
|
|
this->Unload();
|
|
this->animations.resize(header.count);
|
|
this->speeds.resize(header.count, 4.0f);
|
|
|
|
for (unsigned animationIndex = 0; animationIndex < this->animations.size(); ++animationIndex) {
|
|
std::vector<ActionFrame>& animation = this->animations[animationIndex];
|
|
int frameCount;
|
|
file.Read(&frameCount, sizeof(frameCount));
|
|
animation.resize(frameCount);
|
|
|
|
for (int frameIndex = 0; frameIndex < frameCount; ++frameIndex) {
|
|
std::int32_t range1[4];
|
|
std::int32_t range2[4];
|
|
file.Read(range1, sizeof(range1));
|
|
file.Read(range2, sizeof(range2));
|
|
int cellCount;
|
|
file.Read(&cellCount, sizeof(cellCount));
|
|
ActionFrame& frame = animation[frameIndex];
|
|
frame.sound = -1;
|
|
frame.cellCount = cellCount;
|
|
frame.cells.resize(std::min(static_cast<unsigned>(cellCount), 1000u));
|
|
frame.anchors.clear();
|
|
frame.anchorCount = 0;
|
|
std::memcpy(frame.unknown_0000, range1, sizeof(range1));
|
|
std::memcpy(frame.unknown_0000 + 4, range2, sizeof(range2));
|
|
if (this->maximumCells < cellCount) {
|
|
this->maximumCells = cellCount;
|
|
}
|
|
|
|
for (int index = 0; index < cellCount; ++index) {
|
|
SpriteFrameCell& cell = frame.cells[index];
|
|
|
|
if (header.version < 0x0200) {
|
|
file.Read(&cell, 16);
|
|
cell.color = 0xFFFFFFFFu;
|
|
cell.scaleX = 1.0f;
|
|
cell.scaleY = 1.0f;
|
|
cell.unknown_001C = 0;
|
|
cell.imageType = 0;
|
|
continue;
|
|
}
|
|
|
|
if (header.version < 0x0204) {
|
|
struct LegacyCell {
|
|
std::int32_t x;
|
|
std::int32_t y;
|
|
std::int32_t image;
|
|
std::int32_t mirrored;
|
|
std::uint32_t color;
|
|
float scale;
|
|
std::int32_t rotation;
|
|
std::int32_t imageType;
|
|
} legacy;
|
|
file.Read(&legacy, sizeof(legacy));
|
|
cell = {legacy.x, legacy.y, legacy.image, legacy.mirrored, legacy.color, legacy.scale, legacy.scale, legacy.rotation, legacy.imageType};
|
|
} else {
|
|
file.Read(&cell, sizeof(cell));
|
|
}
|
|
|
|
if (header.version >= 0x0205) {
|
|
int width;
|
|
int height;
|
|
file.Read(&width, sizeof(width));
|
|
file.Read(&height, sizeof(height));
|
|
|
|
if (cell.image != -1) {
|
|
cell.x = RelativeCoordinate(cell.x, width, cell.scaleX);
|
|
cell.y = RelativeCoordinate(cell.y, height, cell.scaleY);
|
|
}
|
|
} else if (cell.image != -1) {
|
|
auto* sprite = static_cast<CSprRes*>(ResourceMgr::Instance().Load(spriteName.c_str()));
|
|
|
|
if (sprite) {
|
|
const SpriteRleImage* image = sprite->images[cell.imageType][cell.image];
|
|
|
|
if (image) {
|
|
const int width = image->width * (image->unknown_0004 != 0 ? 2 : 1);
|
|
const int height = image->height * (image->unknown_0006 != 0 ? 2 : 1);
|
|
cell.x = RelativeCoordinate(cell.x, width, cell.scaleX);
|
|
cell.y = RelativeCoordinate(cell.y, height, cell.scaleY);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (header.version >= 0x0200) {
|
|
file.Read(&frame.sound, sizeof(frame.sound));
|
|
|
|
if (header.version == 0x0200) {
|
|
frame.sound = -1;
|
|
}
|
|
}
|
|
|
|
if (header.version >= 0x0203) {
|
|
int count;
|
|
file.Read(&count, sizeof(count));
|
|
frame.anchorCount = count;
|
|
frame.anchors.resize(static_cast<unsigned>(count));
|
|
|
|
for (int index = 0; index < count; ++index) {
|
|
struct AnchorRecord {
|
|
int unused;
|
|
ActionAnchor anchor;
|
|
} anchor;
|
|
file.Read(&anchor, sizeof(anchor));
|
|
frame.anchors[index] = anchor.anchor;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (header.version >= 0x0201) {
|
|
int count;
|
|
file.Read(&count, sizeof(count));
|
|
this->sounds.resize(static_cast<unsigned>(count));
|
|
|
|
for (int index = 0; index < count; ++index) {
|
|
char sound[40];
|
|
file.Read(sound, sizeof(sound));
|
|
this->sounds[index] = sound;
|
|
}
|
|
}
|
|
|
|
if (header.version >= 0x0202) {
|
|
for (int index = 0; index < header.count; ++index) {
|
|
file.Read(&this->speeds[index], sizeof(float));
|
|
}
|
|
}
|
|
|
|
file.Close();
|
|
return true;
|
|
}
|
|
|
|
// OFFSET: 0x007445A0
|
|
// FUNCTION: fn_07751
|
|
void CActRes::Unload() {
|
|
this->animations.clear();
|
|
this->sounds.clear();
|
|
}
|
|
|
|
// OFFSET: 0x00746F80
|
|
// FUNCTION: fn_07783
|
|
const std::vector<ActionFrame>& CActRes::Animation(unsigned index) const {
|
|
if (index < this->animations.size()) {
|
|
return this->animations[index];
|
|
}
|
|
|
|
// STATIC: 0x0138D700
|
|
static const std::vector<ActionFrame> missing;
|
|
return missing;
|
|
}
|
|
|
|
// OFFSET: 0x00747050
|
|
// FUNCTION: fn_07784
|
|
const SpriteFrameCell& ActionFrame::Cell(unsigned index) const {
|
|
if (index < this->cells.size()) {
|
|
return this->cells[index];
|
|
}
|
|
|
|
// STATIC: 0x0132A1A8
|
|
static const SpriteFrameCell missing{0, 0, -1, 0, 0xFFFFFFFFu, 1.0f, 1.0f, 0, 0};
|
|
return missing;
|
|
}
|
|
|
|
// OFFSET: 0x00747090
|
|
// FUNCTION: fn_07785
|
|
float CActRes::Speed(unsigned index) const {
|
|
return index < this->speeds.size() ? this->speeds[index] : 4.0f;
|
|
}
|
|
|
|
// OFFSET: 0x007470E0
|
|
// FUNCTION: fn_07786
|
|
const char* CActRes::Sound(unsigned index) const {
|
|
return index < this->sounds.size() ? this->sounds[index].c_str() : "";
|
|
}
|
|
|
|
// OFFSET: 0x00747170
|
|
// FUNCTION: fn_07787
|
|
const ActionFrame& CActRes::Frame(unsigned animation, unsigned frame) const {
|
|
const auto& frames = this->Animation(animation);
|
|
if (frame < frames.size()) {
|
|
return frames[frame];
|
|
}
|
|
if (!frames.empty()) {
|
|
return frames.front();
|
|
}
|
|
|
|
// GLOBAL: gl_24507
|
|
static const ActionFrame missing;
|
|
return missing;
|
|
}
|
|
|
|
// OFFSET: 0x00747370
|
|
// FUNCTION: fn_07788
|
|
unsigned CActRes::FrameCount(unsigned animation) const {
|
|
const auto& frames = this->Animation(animation);
|
|
return frames.empty() ? 1u : static_cast<unsigned>(frames.size());
|
|
}
|