From 6d34f0e18dee61e4607c1f252b396ef0f419d40d Mon Sep 17 00:00:00 2001 From: kichikuou Date: Sun, 20 Mar 2022 14:31:00 +0900 Subject: [PATCH] Implement ChrLoader HLL For Widenyo. --- src/ffi.c | 2 + src/hll/ChrLoader.c | 214 ++++++++++++++++++++++++++++++++++++++++++++ src/meson.build | 1 + 3 files changed, 217 insertions(+) create mode 100644 src/hll/ChrLoader.c diff --git a/src/ffi.c b/src/ffi.c index 5469d3d..4492774 100644 --- a/src/ffi.c +++ b/src/ffi.c @@ -295,6 +295,7 @@ extern struct static_library lib_AnteaterADVEngine; extern struct static_library lib_BanMisc; extern struct static_library lib_Bitarray; extern struct static_library lib_ChipmunkSpriteEngine; +extern struct static_library lib_ChrLoader; extern struct static_library lib_Confirm; extern struct static_library lib_Confirm2; extern struct static_library lib_CrayfishLogViewer; @@ -347,6 +348,7 @@ static struct static_library *static_libraries[] = { &lib_BanMisc, &lib_Bitarray, &lib_ChipmunkSpriteEngine, + &lib_ChrLoader, &lib_Confirm, &lib_Confirm2, &lib_CrayfishLogViewer, diff --git a/src/hll/ChrLoader.c b/src/hll/ChrLoader.c new file mode 100644 index 0000000..6f3e707 --- /dev/null +++ b/src/hll/ChrLoader.c @@ -0,0 +1,214 @@ +/* Copyright (C) 2022 kichikuou + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ + +#include +#include +#include + +#include "system4/cg.h" +#include "system4/file.h" +#include "system4/hashtable.h" +#include "system4/mt19937int.h" +#include "system4/string.h" +#include "little_endian.h" + +#include "sact.h" +#include "xsystem4.h" + +#include "hll.h" + +/* + * struct ChrHeader { + * char magic[4]; // "CHR\0" + * // the below are encrypted + * char type[4]; // "Mine" or "Enmy" + * }; // Followed by a MineIndex or an EnmyIndex + * + * struct MineIndex { + * uint32_t info_offset; + * uint32_t cg_offset[4]; + * uint32_t cg_size[4]; + * uint32_t sound_offset; + * uint32_t sound_size; + * uint32_t string_offset[48]; + * }; + * + * struct MineInfo { + * uint32_t unknown[6]; + * uint32_t status[24]; + * char name[32]; + * }; + * + * struct EnmyIndex { + * uint32_t info_offset; + * uint32_t cg_offset[3]; + * uint32_t cg_size[3]; + * uint32_t sound_offset; + * uint32_t sound_size; + * }; + * + * struct EnmyInfo { + * uint32_t unknown[5]; + * uint32_t status[17]; + * char name[32]; + * }; + */ + +static struct hash_table *chr_table; // Caches decrypted .chr file data + +static bool is_enemy(uint8_t *data) +{ + return !memcmp(data + 4, "Enmy", 4); +} + +static uint8_t *chr_get(int id) +{ + struct ht_slot *slot = ht_put_int(chr_table, id, NULL); + if (slot->value) + return slot->value; + + char buf[32]; + sprintf(buf, "CHR/%d.chr", id); + char *path = gamedir_path(buf); + size_t size; + uint8_t *data = file_read(path, &size); + if (!data) { + // WARNING("Cannot load %s", path); + } else if (memcmp(data, "CHR", 4)) { + WARNING("%s: Wrong magic bytes", path); + free(data); + data = NULL; + } else { + struct mt19937 mt; + mt19937_init(&mt, 12753); + for (size_t i = 4; i < size; i++) + data[i] ^= mt19937_genrand(&mt); + slot->value = data; + } + free(path); + return data; +} + +static bool ChrLoader_Init(void) +{ + chr_table = ht_create(512); + return true; +} + +static bool ChrLoader_LoadCG(int sprite, int x, int y, int id, int type) +{ + uint8_t *data = chr_get(id); + if (!data) + return false; + + struct sact_sprite *sp = sact_get_sprite(sprite); + if (!sp) + return false; + + int index = -1; + switch (type) { + case 0: // Unit + index = is_enemy(data) ? 0 : 1; + break; + case 1: // Attack + index = is_enemy(data) ? 1 : 2; + break; + case 2: // Damage + index = is_enemy(data) ? 2 : 3; + break; + case 3: // Face + index = is_enemy(data) ? -1 : 0; + break; + } + if (index < 0) + return false; + + size_t offset = LittleEndian_getDW(data, 12 + index * 4); + size_t size = LittleEndian_getDW(data, (is_enemy(data) ? 24 : 28) + index * 4); + struct cg *cg = cg_load_buffer(data + offset, size); + if (!cg) + return false; + sprite_set_cg(sp, cg); + cg_free(cg); + return true; +} + +HLL_WARN_UNIMPLEMENTED(false, bool, ChrLoader, LoadWavFile, int nSoundChannel, int nID); + +static bool ChrLoader_LoadSentence(int id, int type, struct string **msg) +{ + uint8_t *data = chr_get(id); + if (!data || is_enemy(data) || (unsigned)type >= 48) + return false; + + uint32_t offset = LittleEndian_getDW(data, 52 + type * 4); + if (!offset) + return false; + *msg = cstr_to_string((char *)data + offset); + return true; +} + +static bool ChrLoader_GetName(int id, struct string **name) +{ + uint8_t *data = chr_get(id); + if (!data) + return false; + + uint32_t offset = LittleEndian_getDW(data, 8); + offset += is_enemy(data) ? 88 : 120; + *name = cstr_to_string((char *)data + offset); + return true; +} + +static int ChrLoader_GetStatus(int id, int type) +{ + uint8_t *data = chr_get(id); + if (!data) + return false; + + const int mine_indices[26] = { + 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, + 19, 20, 23, 24, 21, 22, -1, -1, 25, 26, 27, 28, 29 + }; + const int enmy_indices[26] = { + 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 17, 18, 19, 20, 21 + }; + int index = (unsigned)type >= 26 ? -1 + : is_enemy(data) ? enmy_indices[type] : mine_indices[type]; + if (index < 0) { + WARNING("nType Error nType==%d", type); + return false; + } + + uint32_t offset = LittleEndian_getDW(data, 8) + index * 4; + return LittleEndian_getDW(data, offset); +} + +static bool ChrLoader_IsExist(int id) +{ + return chr_get(id) != NULL; +} + +HLL_LIBRARY(ChrLoader, + HLL_EXPORT(Init, ChrLoader_Init), + HLL_EXPORT(LoadCG, ChrLoader_LoadCG), + HLL_EXPORT(LoadWavFile, ChrLoader_LoadWavFile), + HLL_EXPORT(LoadSentence, ChrLoader_LoadSentence), + HLL_EXPORT(GetName, ChrLoader_GetName), + HLL_EXPORT(GetStatus, ChrLoader_GetStatus), + HLL_EXPORT(IsExist, ChrLoader_IsExist) + ); diff --git a/src/meson.build b/src/meson.build index 0aa3234..427f44d 100644 --- a/src/meson.build +++ b/src/meson.build @@ -43,6 +43,7 @@ xsystem4 = ['audio.c', 'hll/Bitarray.c', 'hll/CharSpriteManager.c', 'hll/ChipmunkSpriteEngine.c', + 'hll/ChrLoader.c', 'hll/Confirm.c', 'hll/Confirm2.c', 'hll/CrayfishLogViewer.c',