2022-05-19 01:51:26 -07:00
|
|
|
#include "art.h"
|
|
|
|
|
|
|
|
#include "animation.h"
|
|
|
|
#include "debug.h"
|
|
|
|
#include "draw.h"
|
|
|
|
#include "game_config.h"
|
|
|
|
#include "memory.h"
|
|
|
|
#include "object.h"
|
|
|
|
#include "proto.h"
|
2022-06-08 12:01:25 -07:00
|
|
|
#include "sfall_config.h"
|
2022-05-19 01:51:26 -07:00
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
|
2022-06-08 12:01:25 -07:00
|
|
|
// 0x5002D8
|
|
|
|
char gDefaultJumpsuitMaleFileName[] = "hmjmps";
|
|
|
|
|
|
|
|
// 0x05002E0
|
|
|
|
char gDefaultJumpsuitFemaleFileName[] = "hfjmps";
|
|
|
|
|
|
|
|
// 0x5002E8
|
|
|
|
char gDefaultTribalMaleFileName[] = "hmwarr";
|
|
|
|
|
|
|
|
// 0x5002F0
|
|
|
|
char gDefaultTribalFemaleFileName[] = "hfprim";
|
|
|
|
|
2022-05-19 01:51:26 -07:00
|
|
|
// 0x510738
|
|
|
|
ArtListDescription gArtListDescriptions[OBJ_TYPE_COUNT] = {
|
|
|
|
{ 0, "items", 0, 0, 0 },
|
|
|
|
{ 0, "critters", 0, 0, 0 },
|
|
|
|
{ 0, "scenery", 0, 0, 0 },
|
|
|
|
{ 0, "walls", 0, 0, 0 },
|
|
|
|
{ 0, "tiles", 0, 0, 0 },
|
|
|
|
{ 0, "misc", 0, 0, 0 },
|
|
|
|
{ 0, "intrface", 0, 0, 0 },
|
|
|
|
{ 0, "inven", 0, 0, 0 },
|
|
|
|
{ 0, "heads", 0, 0, 0 },
|
|
|
|
{ 0, "backgrnd", 0, 0, 0 },
|
|
|
|
{ 0, "skilldex", 0, 0, 0 },
|
|
|
|
};
|
|
|
|
|
|
|
|
// This flag denotes that localized arts should be looked up first. Used
|
|
|
|
// together with [gArtLanguage].
|
|
|
|
//
|
|
|
|
// 0x510898
|
|
|
|
bool gArtLanguageInitialized = false;
|
|
|
|
|
|
|
|
// 0x51089C
|
|
|
|
const char* _head1 = "gggnnnbbbgnb";
|
|
|
|
|
|
|
|
// 0x5108A0
|
|
|
|
const char* _head2 = "vfngfbnfvppp";
|
|
|
|
|
|
|
|
// Current native look base fid.
|
|
|
|
//
|
|
|
|
// 0x5108A4
|
|
|
|
int _art_vault_guy_num = 0;
|
|
|
|
|
|
|
|
// Base fids for unarmored dude.
|
|
|
|
//
|
|
|
|
// Outfit file names:
|
|
|
|
// - tribal: "hmwarr", "hfprim"
|
|
|
|
// - jumpsuit: "hmjmps", "hfjmps"
|
|
|
|
//
|
|
|
|
// NOTE: This value could have been done with two separate arrays - one for
|
|
|
|
// tribal look, and one for jumpsuit look. However in this case it would have
|
|
|
|
// been accessed differently in 0x49F984, which clearly uses look type as an
|
|
|
|
// index, not gender.
|
|
|
|
//
|
|
|
|
// 0x5108A8
|
|
|
|
int _art_vault_person_nums[DUDE_NATIVE_LOOK_COUNT][GENDER_COUNT];
|
|
|
|
|
|
|
|
// Index of "grid001.frm" in tiles.lst.
|
|
|
|
//
|
|
|
|
// 0x5108B8
|
|
|
|
int _art_mapper_blank_tile = 1;
|
|
|
|
|
|
|
|
// Non-english language name.
|
|
|
|
//
|
|
|
|
// This value is used as a directory name to display localized arts.
|
|
|
|
//
|
|
|
|
// 0x56C970
|
|
|
|
char gArtLanguage[32];
|
|
|
|
|
|
|
|
// 0x56C990
|
|
|
|
Cache gArtCache;
|
|
|
|
|
|
|
|
// 0x56C9E4
|
2022-05-28 02:34:49 -07:00
|
|
|
char _art_name[COMPAT_MAX_PATH];
|
2022-05-19 01:51:26 -07:00
|
|
|
|
|
|
|
// head_info
|
|
|
|
// 0x56CAE8
|
|
|
|
HeadDescription* gHeadDescriptions;
|
|
|
|
|
|
|
|
// anon_alias
|
|
|
|
// 0x56CAEC
|
|
|
|
int* _anon_alias;
|
|
|
|
|
|
|
|
// artCritterFidShouldRunData
|
|
|
|
// 0x56CAF0
|
|
|
|
int* gArtCritterFidShoudRunData;
|
|
|
|
|
|
|
|
// 0x418840
|
|
|
|
int artInit()
|
|
|
|
{
|
2022-05-28 02:34:49 -07:00
|
|
|
char path[COMPAT_MAX_PATH];
|
2022-05-19 01:51:26 -07:00
|
|
|
int i;
|
|
|
|
File* stream;
|
|
|
|
char str[200];
|
|
|
|
char *ptr, *curr;
|
|
|
|
|
|
|
|
int cacheSize;
|
|
|
|
if (!configGetInt(&gGameConfig, GAME_CONFIG_SYSTEM_KEY, GAME_CONFIG_ART_CACHE_SIZE_KEY, &cacheSize)) {
|
|
|
|
cacheSize = 8;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!cacheInit(&gArtCache, artCacheGetFileSizeImpl, artCacheReadDataImpl, artCacheFreeImpl, cacheSize << 20)) {
|
|
|
|
debugPrint("cache_init failed in art_init\n");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
char* language;
|
2022-05-28 01:57:32 -07:00
|
|
|
if (configGetString(&gGameConfig, GAME_CONFIG_SYSTEM_KEY, GAME_CONFIG_LANGUAGE_KEY, &language) && compat_stricmp(language, ENGLISH) != 0) {
|
2022-05-19 01:51:26 -07:00
|
|
|
strcpy(gArtLanguage, language);
|
|
|
|
gArtLanguageInitialized = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < 11; i++) {
|
|
|
|
gArtListDescriptions[i].flags = 0;
|
|
|
|
sprintf(path, "%s%s%s\\%s.lst", _cd_path_base, "art\\", gArtListDescriptions[i].name, gArtListDescriptions[i].name);
|
|
|
|
|
|
|
|
if (artReadList(path, &(gArtListDescriptions[i].fileNames), &(gArtListDescriptions[i].fileNamesLength)) != 0) {
|
|
|
|
debugPrint("art_read_lst failed in art_init\n");
|
|
|
|
cacheFree(&gArtCache);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-05-21 08:22:03 -07:00
|
|
|
_anon_alias = (int*)internal_malloc(sizeof(*_anon_alias) * gArtListDescriptions[1].fileNamesLength);
|
2022-05-19 01:51:26 -07:00
|
|
|
if (_anon_alias == NULL) {
|
|
|
|
gArtListDescriptions[1].fileNamesLength = 0;
|
|
|
|
debugPrint("Out of memory for anon_alias in art_init\n");
|
|
|
|
cacheFree(&gArtCache);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2022-05-21 08:22:03 -07:00
|
|
|
gArtCritterFidShoudRunData = (int*)internal_malloc(sizeof(*gArtCritterFidShoudRunData) * gArtListDescriptions[1].fileNamesLength);
|
2022-05-19 01:51:26 -07:00
|
|
|
if (gArtCritterFidShoudRunData == NULL) {
|
|
|
|
gArtListDescriptions[1].fileNamesLength = 0;
|
|
|
|
debugPrint("Out of memory for artCritterFidShouldRunData in art_init\n");
|
|
|
|
cacheFree(&gArtCache);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < gArtListDescriptions[1].fileNamesLength; i++) {
|
|
|
|
gArtCritterFidShoudRunData[i] = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
sprintf(path, "%s%s%s\\%s.lst", _cd_path_base, "art\\", gArtListDescriptions[1].name, gArtListDescriptions[1].name);
|
|
|
|
|
|
|
|
stream = fileOpen(path, "rt");
|
|
|
|
if (stream == NULL) {
|
|
|
|
debugPrint("Unable to open %s in art_init\n", path);
|
|
|
|
cacheFree(&gArtCache);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2022-06-08 12:01:25 -07:00
|
|
|
char* jumpsuitMaleFileName = NULL;
|
|
|
|
configGetString(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_DUDE_NATIVE_LOOK_JUMPSUIT_MALE_KEY, &jumpsuitMaleFileName);
|
|
|
|
if (jumpsuitMaleFileName == NULL || jumpsuitMaleFileName[0] != '\0') {
|
|
|
|
jumpsuitMaleFileName = gDefaultJumpsuitMaleFileName;
|
|
|
|
}
|
|
|
|
|
|
|
|
char* jumpsuitFemaleFileName = NULL;
|
|
|
|
configGetString(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_DUDE_NATIVE_LOOK_JUMPSUIT_FEMALE_KEY, &jumpsuitFemaleFileName);
|
|
|
|
if (jumpsuitFemaleFileName == NULL || jumpsuitFemaleFileName[0] == '\0') {
|
|
|
|
jumpsuitFemaleFileName = gDefaultJumpsuitFemaleFileName;
|
|
|
|
}
|
|
|
|
|
|
|
|
char* tribalMaleFileName = NULL;
|
|
|
|
configGetString(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_DUDE_NATIVE_LOOK_TRIBAL_MALE_KEY, &tribalMaleFileName);
|
|
|
|
if (tribalMaleFileName == NULL || tribalMaleFileName[0] == '\0') {
|
|
|
|
tribalMaleFileName = gDefaultTribalMaleFileName;
|
|
|
|
}
|
|
|
|
|
|
|
|
char *tribalFemaleFileName = NULL;
|
|
|
|
configGetString(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_DUDE_NATIVE_LOOK_TRIBAL_FEMALE_KEY, &tribalFemaleFileName);
|
|
|
|
if (tribalFemaleFileName == NULL || tribalFemaleFileName[0] == '\0') {
|
|
|
|
tribalFemaleFileName = gDefaultTribalFemaleFileName;
|
|
|
|
}
|
|
|
|
|
2022-05-19 01:51:26 -07:00
|
|
|
ptr = gArtListDescriptions[1].fileNames;
|
|
|
|
for (i = 0; i < gArtListDescriptions[1].fileNamesLength; i++) {
|
2022-06-08 12:01:25 -07:00
|
|
|
if (compat_stricmp(ptr, jumpsuitMaleFileName) == 0) {
|
2022-05-19 01:51:26 -07:00
|
|
|
_art_vault_person_nums[DUDE_NATIVE_LOOK_JUMPSUIT][GENDER_MALE] = i;
|
2022-06-08 12:01:25 -07:00
|
|
|
} else if (compat_stricmp(ptr, jumpsuitFemaleFileName) == 0) {
|
2022-05-19 01:51:26 -07:00
|
|
|
_art_vault_person_nums[DUDE_NATIVE_LOOK_JUMPSUIT][GENDER_FEMALE] = i;
|
|
|
|
}
|
|
|
|
|
2022-06-08 12:01:25 -07:00
|
|
|
if (compat_stricmp(ptr, tribalMaleFileName) == 0) {
|
2022-05-19 01:51:26 -07:00
|
|
|
_art_vault_person_nums[DUDE_NATIVE_LOOK_TRIBAL][GENDER_MALE] = i;
|
|
|
|
_art_vault_guy_num = i;
|
2022-06-08 12:01:25 -07:00
|
|
|
} else if (compat_stricmp(ptr, tribalFemaleFileName) == 0) {
|
2022-05-19 01:51:26 -07:00
|
|
|
_art_vault_person_nums[DUDE_NATIVE_LOOK_TRIBAL][GENDER_FEMALE] = i;
|
|
|
|
}
|
|
|
|
|
|
|
|
ptr += 13;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < gArtListDescriptions[1].fileNamesLength; i++) {
|
|
|
|
if (!fileReadString(str, sizeof(str), stream)) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
ptr = str;
|
|
|
|
curr = ptr;
|
|
|
|
while (*curr != '\0' && *curr != ',') {
|
|
|
|
curr++;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (*curr != '\0') {
|
|
|
|
_anon_alias[i] = atoi(curr + 1);
|
|
|
|
|
|
|
|
ptr = curr + 1;
|
|
|
|
curr = ptr;
|
|
|
|
while (*curr != '\0' && *curr != ',') {
|
|
|
|
curr++;
|
|
|
|
}
|
|
|
|
|
|
|
|
gArtCritterFidShoudRunData[i] = *curr != '\0' ? atoi(ptr) : 0;
|
|
|
|
} else {
|
|
|
|
_anon_alias[i] = _art_vault_guy_num;
|
|
|
|
gArtCritterFidShoudRunData[i] = 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fileClose(stream);
|
|
|
|
|
|
|
|
ptr = gArtListDescriptions[4].fileNames;
|
|
|
|
for (i = 0; i < gArtListDescriptions[4].fileNamesLength; i++) {
|
2022-05-28 01:57:32 -07:00
|
|
|
if (compat_stricmp(ptr, "grid001.frm") == 0) {
|
2022-05-19 01:51:26 -07:00
|
|
|
_art_mapper_blank_tile = i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-05-21 08:22:03 -07:00
|
|
|
gHeadDescriptions = (HeadDescription*)internal_malloc(sizeof(HeadDescription) * gArtListDescriptions[8].fileNamesLength);
|
2022-05-19 01:51:26 -07:00
|
|
|
if (gHeadDescriptions == NULL) {
|
|
|
|
gArtListDescriptions[8].fileNamesLength = 0;
|
|
|
|
debugPrint("Out of memory for head_info in art_init\n");
|
|
|
|
cacheFree(&gArtCache);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
sprintf(path, "%s%s%s\\%s.lst", _cd_path_base, "art\\", gArtListDescriptions[8].name, gArtListDescriptions[8].name);
|
|
|
|
|
|
|
|
stream = fileOpen(path, "rt");
|
|
|
|
if (stream == NULL) {
|
|
|
|
debugPrint("Unable to open %s in art_init\n", path);
|
|
|
|
cacheFree(&gArtCache);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < gArtListDescriptions[8].fileNamesLength; i++) {
|
|
|
|
if (!fileReadString(str, sizeof(str), stream)) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
ptr = str;
|
|
|
|
curr = ptr;
|
|
|
|
while (*curr != '\0' && *curr != ',') {
|
|
|
|
curr++;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (*curr != '\0') {
|
|
|
|
ptr = curr + 1;
|
|
|
|
curr = ptr;
|
|
|
|
while (*curr != '\0' && *curr != ',') {
|
|
|
|
curr++;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (*curr != '\0') {
|
|
|
|
gHeadDescriptions[i].goodFidgetCount = atoi(ptr);
|
|
|
|
|
|
|
|
ptr = curr + 1;
|
|
|
|
curr = ptr;
|
|
|
|
while (*curr != '\0' && *curr != ',') {
|
|
|
|
curr++;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (*curr != '\0') {
|
|
|
|
gHeadDescriptions[i].neutralFidgetCount = atoi(ptr);
|
|
|
|
|
|
|
|
ptr = curr + 1;
|
|
|
|
curr = strpbrk(ptr, " ,;\t\n");
|
|
|
|
if (curr != NULL) {
|
|
|
|
*curr = '\0';
|
|
|
|
}
|
|
|
|
|
|
|
|
gHeadDescriptions[i].badFidgetCount = atoi(ptr);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fileClose(stream);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// 0x418EB8
|
|
|
|
void artReset()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
// 0x418EBC
|
|
|
|
void artExit()
|
|
|
|
{
|
|
|
|
cacheFree(&gArtCache);
|
|
|
|
|
|
|
|
internal_free(_anon_alias);
|
|
|
|
internal_free(gArtCritterFidShoudRunData);
|
|
|
|
|
|
|
|
for (int index = 0; index < OBJ_TYPE_COUNT; index++) {
|
|
|
|
internal_free(gArtListDescriptions[index].fileNames);
|
|
|
|
gArtListDescriptions[index].fileNames = NULL;
|
|
|
|
|
|
|
|
internal_free(gArtListDescriptions[index].field_18);
|
|
|
|
gArtListDescriptions[index].field_18 = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
internal_free(gHeadDescriptions);
|
|
|
|
}
|
|
|
|
|
|
|
|
// 0x418F1C
|
|
|
|
char* artGetObjectTypeName(int objectType)
|
|
|
|
{
|
|
|
|
return objectType >= 0 && objectType < OBJ_TYPE_COUNT ? gArtListDescriptions[objectType].name : NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
// 0x418F34
|
|
|
|
int artIsObjectTypeHidden(int objectType)
|
|
|
|
{
|
|
|
|
return objectType >= 0 && objectType < OBJ_TYPE_COUNT ? gArtListDescriptions[objectType].flags & 1 : 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// 0x418F7C
|
|
|
|
int artGetFidgetCount(int headFid)
|
|
|
|
{
|
|
|
|
if ((headFid & 0xF000000) >> 24 != OBJ_TYPE_HEAD) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int head = headFid & 0xFFF;
|
|
|
|
|
|
|
|
if (head > gArtListDescriptions[OBJ_TYPE_HEAD].fileNamesLength) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
HeadDescription* headDescription = &(gHeadDescriptions[head]);
|
|
|
|
|
|
|
|
int fidget = (headFid & 0xFF0000) >> 16;
|
|
|
|
switch (fidget) {
|
|
|
|
case FIDGET_GOOD:
|
|
|
|
return headDescription->goodFidgetCount;
|
|
|
|
case FIDGET_NEUTRAL:
|
|
|
|
return headDescription->neutralFidgetCount;
|
|
|
|
case FIDGET_BAD:
|
|
|
|
return headDescription->badFidgetCount;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// 0x418FFC
|
|
|
|
void artRender(int fid, unsigned char* dest, int width, int height, int pitch)
|
|
|
|
{
|
|
|
|
// NOTE: Original code is different. For unknown reason it directly calls
|
|
|
|
// many art functions, for example instead of [artLock] it calls lower level
|
|
|
|
// [cacheLock], instead of [artGetWidth] is calls [artGetFrame], then get
|
|
|
|
// width from frame's struct field. I don't know if this was intentional or
|
|
|
|
// not. I've replaced these calls with higher level functions where
|
|
|
|
// appropriate.
|
|
|
|
|
|
|
|
CacheEntry* handle;
|
|
|
|
Art* frm = artLock(fid, &handle);
|
|
|
|
if (frm == NULL) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned char* frameData = artGetFrameData(frm, 0, 0);
|
|
|
|
int frameWidth = artGetWidth(frm, 0, 0);
|
|
|
|
int frameHeight = artGetHeight(frm, 0, 0);
|
|
|
|
|
|
|
|
int remainingWidth = width - frameWidth;
|
|
|
|
int remainingHeight = height - frameHeight;
|
|
|
|
if (remainingWidth < 0 || remainingHeight < 0) {
|
|
|
|
if (height * frameWidth >= width * frameHeight) {
|
|
|
|
blitBufferToBufferStretchTrans(frameData,
|
|
|
|
frameWidth,
|
|
|
|
frameHeight,
|
|
|
|
frameWidth,
|
|
|
|
dest + pitch * ((height - width * frameHeight / frameWidth) / 2),
|
|
|
|
width,
|
|
|
|
width * frameHeight / frameWidth,
|
|
|
|
pitch);
|
|
|
|
} else {
|
|
|
|
blitBufferToBufferStretchTrans(frameData,
|
|
|
|
frameWidth,
|
|
|
|
frameHeight,
|
|
|
|
frameWidth,
|
|
|
|
dest + (width - height * frameWidth / frameHeight) / 2,
|
|
|
|
height * frameWidth / frameHeight,
|
|
|
|
height,
|
|
|
|
pitch);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
blitBufferToBufferTrans(frameData,
|
|
|
|
frameWidth,
|
|
|
|
frameHeight,
|
|
|
|
frameWidth,
|
|
|
|
dest + pitch * (remainingHeight / 2) + remainingWidth / 2,
|
|
|
|
pitch);
|
|
|
|
}
|
|
|
|
|
|
|
|
artUnlock(handle);
|
|
|
|
}
|
|
|
|
|
|
|
|
// 0x419160
|
|
|
|
Art* artLock(int fid, CacheEntry** handlePtr)
|
|
|
|
{
|
|
|
|
if (handlePtr == NULL) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
Art* art = NULL;
|
|
|
|
cacheLock(&gArtCache, fid, (void**)&art, handlePtr);
|
|
|
|
return art;
|
|
|
|
}
|
|
|
|
|
|
|
|
// 0x419188
|
|
|
|
unsigned char* artLockFrameData(int fid, int frame, int direction, CacheEntry** handlePtr)
|
|
|
|
{
|
|
|
|
Art* art;
|
|
|
|
ArtFrame* frm;
|
|
|
|
|
|
|
|
art = NULL;
|
|
|
|
if (handlePtr) {
|
|
|
|
cacheLock(&gArtCache, fid, (void**)&art, handlePtr);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (art != NULL) {
|
|
|
|
frm = artGetFrame(art, frame, direction);
|
|
|
|
if (frm != NULL) {
|
|
|
|
|
2022-05-21 10:05:34 -07:00
|
|
|
return (unsigned char*)frm + sizeof(*frm);
|
2022-05-19 01:51:26 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
// 0x4191CC
|
|
|
|
unsigned char* artLockFrameDataReturningSize(int fid, CacheEntry** handlePtr, int* widthPtr, int* heightPtr)
|
|
|
|
{
|
|
|
|
*handlePtr = NULL;
|
|
|
|
|
|
|
|
Art* art;
|
|
|
|
cacheLock(&gArtCache, fid, (void**)&art, handlePtr);
|
|
|
|
|
|
|
|
if (art == NULL) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
// NOTE: Uninline.
|
|
|
|
*widthPtr = artGetWidth(art, 0, 0);
|
|
|
|
if (*widthPtr == -1) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
// NOTE: Uninline.
|
|
|
|
*heightPtr = artGetHeight(art, 0, 0);
|
|
|
|
if (*heightPtr == -1) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
// NOTE: Uninline.
|
|
|
|
return artGetFrameData(art, 0, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
// 0x419260
|
|
|
|
int artUnlock(CacheEntry* handle)
|
|
|
|
{
|
|
|
|
return cacheUnlock(&gArtCache, handle);
|
|
|
|
}
|
|
|
|
|
|
|
|
// 0x41927C
|
|
|
|
int artCacheFlush()
|
|
|
|
{
|
|
|
|
return cacheFlush(&gArtCache);
|
|
|
|
}
|
|
|
|
|
|
|
|
// 0x4192B0
|
|
|
|
int artCopyFileName(int type, int id, char* dest)
|
|
|
|
{
|
|
|
|
ArtListDescription* ptr;
|
|
|
|
|
|
|
|
if (type < 0 && type >= 11) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
ptr = &(gArtListDescriptions[type]);
|
|
|
|
|
|
|
|
if (id >= ptr->fileNamesLength) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
strcpy(dest, ptr->fileNames + id * 13);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// 0x419314
|
|
|
|
int _art_get_code(int animation, int weaponType, char* a3, char* a4)
|
|
|
|
{
|
|
|
|
if (weaponType < 0 || weaponType >= WEAPON_ANIMATION_COUNT) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (animation >= ANIM_TAKE_OUT && animation <= ANIM_FIRE_CONTINUOUS) {
|
|
|
|
*a4 = 'c' + (animation - ANIM_TAKE_OUT);
|
|
|
|
if (weaponType == WEAPON_ANIMATION_NONE) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
*a3 = 'd' + (weaponType - 1);
|
|
|
|
return 0;
|
|
|
|
} else if (animation == ANIM_PRONE_TO_STANDING) {
|
|
|
|
*a4 = 'h';
|
|
|
|
*a3 = 'c';
|
|
|
|
return 0;
|
|
|
|
} else if (animation == ANIM_BACK_TO_STANDING) {
|
|
|
|
*a4 = 'j';
|
|
|
|
*a3 = 'c';
|
|
|
|
return 0;
|
|
|
|
} else if (animation == ANIM_CALLED_SHOT_PIC) {
|
|
|
|
*a4 = 'a';
|
|
|
|
*a3 = 'n';
|
|
|
|
return 0;
|
|
|
|
} else if (animation >= FIRST_SF_DEATH_ANIM) {
|
|
|
|
*a4 = 'a' + (animation - FIRST_SF_DEATH_ANIM);
|
|
|
|
*a3 = 'r';
|
|
|
|
return 0;
|
|
|
|
} else if (animation >= FIRST_KNOCKDOWN_AND_DEATH_ANIM) {
|
|
|
|
*a4 = 'a' + (animation - FIRST_KNOCKDOWN_AND_DEATH_ANIM);
|
|
|
|
*a3 = 'b';
|
|
|
|
return 0;
|
|
|
|
} else if (animation == ANIM_THROW_ANIM) {
|
|
|
|
if (weaponType == WEAPON_ANIMATION_KNIFE) {
|
|
|
|
// knife
|
|
|
|
*a3 = 'd';
|
|
|
|
*a4 = 'm';
|
|
|
|
} else if (weaponType == WEAPON_ANIMATION_SPEAR) {
|
|
|
|
// spear
|
|
|
|
*a3 = 'g';
|
|
|
|
*a4 = 'm';
|
|
|
|
} else {
|
|
|
|
// other -> probably rock or grenade
|
|
|
|
*a3 = 'a';
|
|
|
|
*a4 = 's';
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
} else if (animation == ANIM_DODGE_ANIM) {
|
|
|
|
if (weaponType <= 0) {
|
|
|
|
*a3 = 'a';
|
|
|
|
*a4 = 'n';
|
|
|
|
} else {
|
|
|
|
*a3 = 'd' + (weaponType - 1);
|
|
|
|
*a4 = 'e';
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
*a4 = 'a' + animation;
|
|
|
|
if (animation <= ANIM_WALK && weaponType > 0) {
|
|
|
|
*a3 = 'd' + (weaponType - 1);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
*a3 = 'a';
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// 0x419428
|
|
|
|
char* artBuildFilePath(int fid)
|
|
|
|
{
|
|
|
|
int v1, v2, v3, v4, v5, type, v8, v10;
|
|
|
|
char v9, v11, v12;
|
|
|
|
|
|
|
|
v2 = fid;
|
|
|
|
|
|
|
|
v10 = (fid & 0x70000000) >> 28;
|
|
|
|
|
|
|
|
v1 = _art_alias_fid(fid);
|
|
|
|
if (v1 != -1) {
|
|
|
|
v2 = v1;
|
|
|
|
}
|
|
|
|
|
|
|
|
*_art_name = '\0';
|
|
|
|
|
|
|
|
v3 = v2 & 0xFFF;
|
|
|
|
v4 = (v2 & 0xFF0000) >> 16;
|
|
|
|
v5 = (v2 & 0xF000) >> 12;
|
|
|
|
type = (v2 & 0xF000000) >> 24;
|
|
|
|
|
|
|
|
if (v3 >= gArtListDescriptions[type].fileNamesLength) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (type < 0 || type >= 11) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
v8 = v3 * 13;
|
|
|
|
|
|
|
|
if (type == 1) {
|
|
|
|
if (_art_get_code(v4, v5, &v11, &v12) == -1) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
if (v10) {
|
|
|
|
sprintf(_art_name, "%s%s%s\\%s%c%c.fr%c", _cd_path_base, "art\\", gArtListDescriptions[1].name, gArtListDescriptions[1].fileNames + v8, v11, v12, v10 + 47);
|
|
|
|
} else {
|
|
|
|
sprintf(_art_name, "%s%s%s\\%s%c%c.frm", _cd_path_base, "art\\", gArtListDescriptions[1].name, gArtListDescriptions[1].fileNames + v8, v11, v12);
|
|
|
|
}
|
|
|
|
} else if (type == 8) {
|
|
|
|
v9 = _head2[v4];
|
|
|
|
if (v9 == 'f') {
|
|
|
|
sprintf(_art_name, "%s%s%s\\%s%c%c%d.frm", _cd_path_base, "art\\", gArtListDescriptions[8].name, gArtListDescriptions[8].fileNames + v8, _head1[v4], 102, v5);
|
|
|
|
} else {
|
|
|
|
sprintf(_art_name, "%s%s%s\\%s%c%c.frm", _cd_path_base, "art\\", gArtListDescriptions[8].name, gArtListDescriptions[8].fileNames + v8, _head1[v4], v9);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
sprintf(_art_name, "%s%s%s\\%s", _cd_path_base, "art\\", gArtListDescriptions[type].name, gArtListDescriptions[type].fileNames + v8);
|
|
|
|
}
|
|
|
|
|
|
|
|
return _art_name;
|
|
|
|
}
|
|
|
|
|
|
|
|
// art_read_lst
|
|
|
|
// 0x419664
|
|
|
|
int artReadList(const char* path, char** out_arr, int* out_count)
|
|
|
|
{
|
|
|
|
File* stream;
|
|
|
|
char str[200];
|
|
|
|
char* arr;
|
|
|
|
int count;
|
|
|
|
char* brk;
|
|
|
|
|
|
|
|
stream = fileOpen(path, "rt");
|
|
|
|
if (stream == NULL) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
count = 0;
|
|
|
|
while (fileReadString(str, sizeof(str), stream)) {
|
|
|
|
count++;
|
|
|
|
}
|
|
|
|
|
|
|
|
fileSeek(stream, 0, SEEK_SET);
|
|
|
|
|
|
|
|
*out_count = count;
|
|
|
|
|
2022-05-21 08:22:03 -07:00
|
|
|
arr = (char*)internal_malloc(13 * count);
|
2022-05-19 01:51:26 -07:00
|
|
|
*out_arr = arr;
|
|
|
|
if (arr == NULL) {
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
|
|
|
while (fileReadString(str, sizeof(str), stream)) {
|
|
|
|
brk = strpbrk(str, " ,;\r\t\n");
|
|
|
|
if (brk != NULL) {
|
|
|
|
*brk = '\0';
|
|
|
|
}
|
|
|
|
|
|
|
|
strncpy(arr, str, 12);
|
|
|
|
arr[12] = '\0';
|
|
|
|
|
|
|
|
arr += 13;
|
|
|
|
}
|
|
|
|
|
|
|
|
fileClose(stream);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
err:
|
|
|
|
|
|
|
|
fileClose(stream);
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
// 0x419760
|
|
|
|
int artGetFramesPerSecond(Art* art)
|
|
|
|
{
|
|
|
|
if (art == NULL) {
|
|
|
|
return 10;
|
|
|
|
}
|
|
|
|
|
|
|
|
return art->framesPerSecond == 0 ? 10 : art->framesPerSecond;
|
|
|
|
}
|
|
|
|
|
|
|
|
// 0x419778
|
|
|
|
int artGetActionFrame(Art* art)
|
|
|
|
{
|
|
|
|
return art == NULL ? -1 : art->actionFrame;
|
|
|
|
}
|
|
|
|
|
|
|
|
// 0x41978C
|
|
|
|
int artGetFrameCount(Art* art)
|
|
|
|
{
|
|
|
|
return art == NULL ? -1 : art->frameCount;
|
|
|
|
}
|
|
|
|
|
|
|
|
// 0x4197A0
|
|
|
|
int artGetWidth(Art* art, int frame, int direction)
|
|
|
|
{
|
|
|
|
ArtFrame* frm;
|
|
|
|
|
|
|
|
frm = artGetFrame(art, frame, direction);
|
|
|
|
if (frm == NULL) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return frm->width;
|
|
|
|
}
|
|
|
|
|
|
|
|
// 0x4197B8
|
|
|
|
int artGetHeight(Art* art, int frame, int direction)
|
|
|
|
{
|
|
|
|
ArtFrame* frm;
|
|
|
|
|
|
|
|
frm = artGetFrame(art, frame, direction);
|
|
|
|
if (frm == NULL) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return frm->height;
|
|
|
|
}
|
|
|
|
|
|
|
|
// 0x4197D4
|
|
|
|
int artGetSize(Art* art, int frame, int direction, int* widthPtr, int* heightPtr)
|
|
|
|
{
|
|
|
|
ArtFrame* frm;
|
|
|
|
|
|
|
|
frm = artGetFrame(art, frame, direction);
|
|
|
|
if (frm == NULL) {
|
|
|
|
if (widthPtr != NULL) {
|
|
|
|
*widthPtr = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (heightPtr != NULL) {
|
|
|
|
*heightPtr = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (widthPtr != NULL) {
|
|
|
|
*widthPtr = frm->width;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (heightPtr != NULL) {
|
|
|
|
*heightPtr = frm->height;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// 0x419820
|
|
|
|
int artGetFrameOffsets(Art* art, int frame, int direction, int* xPtr, int* yPtr)
|
|
|
|
{
|
|
|
|
ArtFrame* frm;
|
|
|
|
|
|
|
|
frm = artGetFrame(art, frame, direction);
|
|
|
|
if (frm == NULL) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
*xPtr = frm->x;
|
|
|
|
*yPtr = frm->y;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// 0x41984C
|
|
|
|
int artGetRotationOffsets(Art* art, int rotation, int* xPtr, int* yPtr)
|
|
|
|
{
|
|
|
|
if (art == NULL) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
*xPtr = art->xOffsets[rotation];
|
|
|
|
*yPtr = art->yOffsets[rotation];
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// 0x419870
|
|
|
|
unsigned char* artGetFrameData(Art* art, int frame, int direction)
|
|
|
|
{
|
|
|
|
ArtFrame* frm;
|
|
|
|
|
|
|
|
frm = artGetFrame(art, frame, direction);
|
|
|
|
if (frm == NULL) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2022-05-21 10:05:34 -07:00
|
|
|
return (unsigned char*)frm + sizeof(*frm);
|
2022-05-19 01:51:26 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// 0x419880
|
|
|
|
ArtFrame* artGetFrame(Art* art, int frame, int rotation)
|
|
|
|
{
|
|
|
|
if (rotation < 0 || rotation >= 6) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (art == NULL) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (frame < 0 || frame >= art->frameCount) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2022-05-21 10:05:34 -07:00
|
|
|
ArtFrame* frm = (ArtFrame*)((unsigned char*)art + sizeof(*art) + art->dataOffsets[rotation]);
|
2022-05-19 01:51:26 -07:00
|
|
|
for (int index = 0; index < frame; index++) {
|
2022-05-21 10:05:34 -07:00
|
|
|
frm = (ArtFrame*)((unsigned char*)frm + sizeof(*frm) + frm->size);
|
2022-05-19 01:51:26 -07:00
|
|
|
}
|
|
|
|
return frm;
|
|
|
|
}
|
|
|
|
|
|
|
|
// 0x4198C8
|
|
|
|
bool artExists(int fid)
|
|
|
|
{
|
|
|
|
int v3;
|
|
|
|
bool result;
|
|
|
|
|
|
|
|
v3 = -1;
|
|
|
|
result = false;
|
|
|
|
|
|
|
|
if ((fid & 0xF000000) >> 24 == 1) {
|
|
|
|
v3 = _db_current(1);
|
|
|
|
// _db_current(_critter_db_handle);
|
|
|
|
_db_current(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
char* filePath = artBuildFilePath(fid);
|
|
|
|
if (filePath == NULL) {
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
int fileSize;
|
|
|
|
if (dbGetFileSize(filePath, &fileSize) == -1) {
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
result = true;
|
|
|
|
|
|
|
|
out:
|
|
|
|
|
|
|
|
if (v3 != -1) {
|
|
|
|
_db_current(v3);
|
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
// 0x419930
|
|
|
|
bool _art_fid_valid(int fid)
|
|
|
|
{
|
|
|
|
// NOTE: Original Code involves calling some unknown function. Check in debugger in mapper.
|
|
|
|
char* filePath = artBuildFilePath(fid);
|
|
|
|
if (filePath == NULL) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
int fileSize;
|
|
|
|
if (dbGetFileSize(filePath, &fileSize) == -1) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// 0x419998
|
|
|
|
int _art_alias_num(int index)
|
|
|
|
{
|
|
|
|
return _anon_alias[index];
|
|
|
|
}
|
|
|
|
|
|
|
|
// 0x4199AC
|
|
|
|
int artCritterFidShouldRun(int fid)
|
|
|
|
{
|
|
|
|
if ((fid & 0xF000000) >> 24 == 1) {
|
|
|
|
return gArtCritterFidShoudRunData[fid & 0xFFF];
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// 0x4199D4
|
|
|
|
int _art_alias_fid(int fid)
|
|
|
|
{
|
|
|
|
int v2;
|
|
|
|
int v3;
|
|
|
|
int result;
|
|
|
|
|
|
|
|
v2 = (fid & 0xF000000) >> 24;
|
|
|
|
v3 = (fid & 0xFF0000) >> 16;
|
|
|
|
|
|
|
|
if (v2 != 1 || v3 != 27 && v3 != 29 && v3 != 30 && v3 != 55 && v3 != 57 && v3 != 58 && v3 != 33 && v3 != 64)
|
|
|
|
result = -1;
|
|
|
|
else
|
|
|
|
result = ((fid & 0x70000000) >> 28 << 28) & 0x70000000 | (v3 << 16) & 0xFF0000 | 0x1000000 | (((fid & 0xF000) >> 12) << 12) & 0xF000 | _anon_alias[fid & 0xFFF] & 0xFFF;
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
// 0x419A78
|
|
|
|
int artCacheGetFileSizeImpl(int fid, int* sizePtr)
|
|
|
|
{
|
|
|
|
int v4;
|
|
|
|
char* str;
|
|
|
|
char* ptr;
|
|
|
|
int result;
|
2022-05-28 02:34:49 -07:00
|
|
|
char path[COMPAT_MAX_PATH];
|
2022-05-19 01:51:26 -07:00
|
|
|
bool loaded;
|
|
|
|
int fileSize;
|
|
|
|
|
|
|
|
v4 = -1;
|
|
|
|
result = -1;
|
|
|
|
|
|
|
|
if ((fid & 0xF000000) >> 24 == 1) {
|
|
|
|
v4 = _db_current(1);
|
|
|
|
// _db_current(_critter_db_handle);
|
|
|
|
_db_current(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
str = artBuildFilePath(fid);
|
|
|
|
if (str != NULL) {
|
|
|
|
loaded = false;
|
|
|
|
if (gArtLanguageInitialized) {
|
|
|
|
ptr = str;
|
|
|
|
while (*ptr != '\0' && *ptr != '\\') {
|
|
|
|
ptr++;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (*ptr == '\0') {
|
|
|
|
ptr = str;
|
|
|
|
}
|
|
|
|
|
|
|
|
sprintf(path, "art\\%s\\%s", gArtLanguage, ptr);
|
|
|
|
if (dbGetFileSize(path, &fileSize) == 0) {
|
|
|
|
loaded = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!loaded) {
|
|
|
|
if (dbGetFileSize(str, &fileSize) == 0) {
|
|
|
|
loaded = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (loaded) {
|
|
|
|
*sizePtr = fileSize;
|
|
|
|
result = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (v4 != -1) {
|
|
|
|
_db_current(v4);
|
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
// 0x419B78
|
|
|
|
int artCacheReadDataImpl(int fid, int* sizePtr, unsigned char* data)
|
|
|
|
{
|
|
|
|
int v4;
|
|
|
|
char* str;
|
|
|
|
char* ptr;
|
|
|
|
int result;
|
2022-05-28 02:34:49 -07:00
|
|
|
char path[COMPAT_MAX_PATH];
|
2022-05-19 01:51:26 -07:00
|
|
|
bool loaded;
|
|
|
|
|
|
|
|
v4 = -1;
|
|
|
|
result = -1;
|
|
|
|
|
|
|
|
if ((fid & 0xF000000) >> 24 == 1) {
|
|
|
|
v4 = _db_current(1);
|
|
|
|
// _db_current(_critter_db_handle);
|
|
|
|
_db_current(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
str = artBuildFilePath(fid);
|
|
|
|
if (str != NULL) {
|
|
|
|
loaded = false;
|
|
|
|
if (gArtLanguageInitialized) {
|
|
|
|
ptr = str;
|
|
|
|
while (*ptr != '\0' && *ptr != '\\') {
|
|
|
|
ptr++;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (*ptr == '\0') {
|
|
|
|
ptr = str;
|
|
|
|
}
|
|
|
|
|
|
|
|
sprintf(path, "art\\%s\\%s", gArtLanguage, ptr);
|
|
|
|
if (artRead(str, data) == 0) {
|
|
|
|
loaded = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!loaded) {
|
|
|
|
if (artRead(str, data) == 0) {
|
|
|
|
loaded = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (loaded) {
|
|
|
|
// TODO: Why it adds 74?
|
|
|
|
*sizePtr = ((Art*)data)->field_3A + 74;
|
|
|
|
result = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (v4 != -1) {
|
|
|
|
_db_current(v4);
|
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
// 0x419C80
|
|
|
|
void artCacheFreeImpl(void* ptr)
|
|
|
|
{
|
|
|
|
internal_free(ptr);
|
|
|
|
}
|
|
|
|
|
|
|
|
// 0x419C88
|
|
|
|
int buildFid(int objectType, int a2, int anim, int a3, int rotation)
|
|
|
|
{
|
|
|
|
int v7, v8, v9, v10;
|
|
|
|
|
|
|
|
v10 = rotation;
|
|
|
|
|
|
|
|
if (objectType != OBJ_TYPE_CRITTER) {
|
|
|
|
goto zero;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (anim == 33 || anim < 20 || anim > 35) {
|
|
|
|
goto zero;
|
|
|
|
}
|
|
|
|
|
|
|
|
v7 = ((a3 << 12) & 0xF000) | (anim << 16) & 0xFF0000 | 0x1000000;
|
|
|
|
v8 = (rotation << 28) & 0x70000000 | v7;
|
|
|
|
v9 = a2 & 0xFFF;
|
|
|
|
|
|
|
|
if (artExists(v9 | v8) != 0) {
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (objectType == rotation) {
|
|
|
|
goto zero;
|
|
|
|
}
|
|
|
|
|
|
|
|
v10 = objectType;
|
|
|
|
if (artExists(v9 | v7 | 0x10000000) != 0) {
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
zero:
|
|
|
|
|
|
|
|
v10 = 0;
|
|
|
|
|
|
|
|
out:
|
|
|
|
|
|
|
|
return (v10 << 28) & 0x70000000 | (objectType << 24) | (anim << 16) & 0xFF0000 | (a3 << 12) & 0xF000 | a2 & 0xFFF;
|
|
|
|
}
|
|
|
|
|
|
|
|
// 0x419D60
|
|
|
|
int artReadFrameData(unsigned char* data, File* stream, int count)
|
|
|
|
{
|
|
|
|
unsigned char* ptr = data;
|
|
|
|
for (int index = 0; index < count; index++) {
|
|
|
|
ArtFrame* frame = (ArtFrame*)ptr;
|
|
|
|
|
|
|
|
if (fileReadInt16(stream, &(frame->width)) == -1) return -1;
|
|
|
|
if (fileReadInt16(stream, &(frame->height)) == -1) return -1;
|
|
|
|
if (fileReadInt32(stream, &(frame->size)) == -1) return -1;
|
|
|
|
if (fileReadInt16(stream, &(frame->x)) == -1) return -1;
|
|
|
|
if (fileReadInt16(stream, &(frame->y)) == -1) return -1;
|
|
|
|
if (fileRead(ptr + sizeof(ArtFrame), frame->size, 1, stream) != 1) return -1;
|
|
|
|
|
|
|
|
ptr += sizeof(ArtFrame) + frame->size;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// 0x419E1C
|
|
|
|
int artReadHeader(Art* art, File* stream)
|
|
|
|
{
|
|
|
|
if (fileReadInt32(stream, &(art->field_0)) == -1) return -1;
|
|
|
|
if (fileReadInt16(stream, &(art->framesPerSecond)) == -1) return -1;
|
|
|
|
if (fileReadInt16(stream, &(art->actionFrame)) == -1) return -1;
|
|
|
|
if (fileReadInt16(stream, &(art->frameCount)) == -1) return -1;
|
|
|
|
if (fileReadInt16List(stream, art->xOffsets, ROTATION_COUNT) == -1) return -1;
|
|
|
|
if (fileReadInt16List(stream, art->yOffsets, ROTATION_COUNT) == -1) return -1;
|
|
|
|
if (fileReadInt32List(stream, art->dataOffsets, ROTATION_COUNT) == -1) return -1;
|
|
|
|
if (fileReadInt32(stream, &(art->field_3A)) == -1) return -1;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// 0x419FC0
|
|
|
|
int artRead(const char* path, unsigned char* data)
|
|
|
|
{
|
|
|
|
File* stream = fileOpen(path, "rb");
|
|
|
|
if (stream == NULL) {
|
|
|
|
return -2;
|
|
|
|
}
|
|
|
|
|
|
|
|
Art* art = (Art*)data;
|
|
|
|
if (artReadHeader(art, stream) != 0) {
|
|
|
|
fileClose(stream);
|
|
|
|
return -3;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (int index = 0; index < ROTATION_COUNT; index++) {
|
|
|
|
if (index == 0 || art->dataOffsets[index - 1] != art->dataOffsets[index]) {
|
|
|
|
if (artReadFrameData(data + sizeof(Art) + art->dataOffsets[index], stream, art->frameCount) != 0) {
|
|
|
|
fileClose(stream);
|
|
|
|
return -5;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fileClose(stream);
|
|
|
|
return 0;
|
|
|
|
}
|