Skip to content

Instantly share code, notes, and snippets.

@MegaLoler
Last active June 14, 2022 21:29
Show Gist options
  • Save MegaLoler/a141dda8871f7912c984f80d96c0427d to your computer and use it in GitHub Desktop.
Save MegaLoler/a141dda8871f7912c984f80d96c0427d to your computer and use it in GitHub Desktop.
my random chocobo mystery dungeon psx romhacking scripts
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#define STB_IMAGE_WRITE_IMPLEMENTATION
#include "stb_image_write.h"
#define COLOR 5
#define OFFSET (256*128)
#define WIDTH 256
#define HEIGHT 64//(512 - 8)
#define PAGES 1
#define MAX_ENTRIES 4096
typedef struct clut_entry_t {
int stp; /* transparency control bit */
float r; /* red */
float g; /* green */
float b; /* blue */
} clut_entry_t;
clut_entry_t *read_clt_file (char *path) {
FILE *fp;
clut_entry_t *entries;
fp = fopen (path, "rb");
/* read all the clut entries */
entries = (clut_entry_t *) malloc (MAX_ENTRIES * sizeof (clut_entry_t));
uint16_t clut;
int i = 0;
while (fread (&clut, 2, 1, fp) > 0) {
int r, g, b;
/* read a clut entry */
clut_entry_t *entry = &entries[i++];
r = (clut >> 0) & 0x1f;
g = (clut >> 5) & 0x1f;
b = (clut >> 10) & 0x1f;
entry->stp = (clut >> 15) & 1;
entry->r = r / 31.;
entry->g = g / 31.;
entry->b = b / 31.;
}
fclose (fp);
return entries;
}
uint32_t lookup (int index, clut_entry_t *palette) {
clut_entry_t entry = palette[index + 64 * COLOR];
uint8_t r = entry.r * 255;
uint8_t g = entry.g * 255;
uint8_t b = entry.b * 255;
uint8_t a = (entry.r == 0 && entry.g == 0 && entry.b == 0 && entry.stp == 0)
? 0 : 255;
uint32_t color = (r << 0)
+ (g << 8)
+ (b << 16)
+ (a << 24);
return color;
}
void decode (FILE *fp, uint32_t *buffer, clut_entry_t *pal) {
/* 2bpp, interleaved */
fseek (fp, OFFSET, SEEK_SET);
int size = WIDTH * HEIGHT / PAGES;
for (int i = 0; i < size;) {
uint8_t byte;
int a, b, c, d;
fread (&byte, 1, 1, fp);
a = (byte >> 0) & 0x03; /* buffer a */
b = (byte >> 2) & 0x03; /* buffer b */
c = (byte >> 4) & 0x03; /* buffer a */
d = (byte >> 6) & 0x03; /* buffer b */
buffer[i] = lookup (a, pal);
//buffer[i + size] = lookup (b, pal);
i++;
buffer[i] = lookup (c, pal);
//buffer[i + size] = lookup (d, pal);
i++;
}
}
int main (int argc, char **argv) {
/* 32-bit image buffers */
uint32_t *buffer;
/* palette */
clut_entry_t *palette;
/* file paths */
char *pxl_path;
char *clt_path;
char *png_path;
/* file handles */
FILE *fp;
/* parse arguments */
if (argc != 4) {
fprintf (stderr, "usage: %s [input.pxl] [input.clt] [output.png]\n",
argv[0]);
return EXIT_FAILURE;
}
pxl_path = argv[1];
clt_path = argv[2];
png_path = argv[3];
/* decode the palette */
palette = read_clt_file (clt_path);
/* allocate buffer */
printf ("allocating 32-bit image buffers for %dx%d pixels...\n",
WIDTH, HEIGHT);
if ((buffer = (uint32_t *) malloc (WIDTH * HEIGHT * sizeof(uint32_t)))
== NULL) {
fprintf (stderr, "failure to allocate first image buffer.\n");
return EXIT_FAILURE;
}
/* decode input */
printf ("opening pxl file \"%s\"...\n", pxl_path);
if ((fp = fopen (pxl_path, "rb")) == NULL) {
fprintf (stderr, "failure to open pxl file \"%s\".\n", pxl_path);
return EXIT_FAILURE;
}
printf ("decoding...\n");
decode (fp, buffer, palette);
fclose (fp);
/* write out image buffers */
printf ("writing 32-bit %dx%d data to \"%s\"...\n",
WIDTH, HEIGHT, png_path);
stbi_write_png (png_path, WIDTH, HEIGHT, 4,
buffer, sizeof (uint32_t) * WIDTH);
/* cleanup */
printf ("done.\n");
free (palette);
free (buffer);
return EXIT_SUCCESS;
}
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <math.h>
#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"
#define STB_IMAGE_WRITE_IMPLEMENTATION
#include "stb_image_write.h"
/* font dimensions */
#define CHAR_WIDTH 8 // 12
#define CHAR_HEIGHT 8 // 12
/* image dimensions */
#define WIDTH 256
#define HEIGHT 64 // 256
#define Y_OFFSET 256 // 0
int main (int argc, char **argv) {
/* read the font file */
int w,h,n;
uint8_t *font = stbi_load ("font.png", &w, &h, &n, 4);
if (font == NULL) {
fprintf (stderr, "couldnt open font.png\n");
return EXIT_FAILURE;
}
puts ("ok.");
/* render image */
int x_chars = WIDTH / CHAR_WIDTH;
int y_chars = HEIGHT / CHAR_HEIGHT;
int i = 0;
printf ("got to chop %d x %d = %d...\n", x_chars, y_chars, x_chars*y_chars);
for (int y = 0; y < y_chars; y++) {
for (int x = 0; x < x_chars; x++) {
int sxo = x * CHAR_WIDTH;
int syo = y * CHAR_HEIGHT + Y_OFFSET;
printf ("doin #%03d... (%d, %d) (x=%d, y=%d)\n", i, x, y, sxo, syo);
uint8_t *buffer = (uint8_t *) malloc (CHAR_WIDTH * CHAR_HEIGHT * 4);
for (int dy = 0; dy < CHAR_HEIGHT; dy++) {
for (int dx = 0; dx < CHAR_WIDTH; dx++) {
int sx = sxo + dx;
int sy = syo + dy;
int si = (sx + sy * WIDTH) * 4;
int di = (dx + dy * CHAR_WIDTH) * 4;
buffer[di + 0] = font[si + 0];
buffer[di + 1] = font[si + 1];
buffer[di + 2] = font[si + 2];
buffer[di + 3] = font[si + 3];
}
}
/* write the png file out */
char path[256];
sprintf (path, "out/%03d.png", i);
if (stbi_write_png (path,
CHAR_WIDTH, CHAR_HEIGHT,
/* rgba */ 4,
buffer,
/* stride */ CHAR_WIDTH * 4) == 0) {
fprintf (stderr, "error writing %s\n", path);
return EXIT_FAILURE;
}
free (buffer);
i++;
}
}
puts ("BYE.");
stbi_image_free (font);
return EXIT_SUCCESS;
}
#!/usr/bin/env python3
font1dir = 'font1'
font2dir = 'font2'
chars1 = 441
chars2 = 256
def row (i, path, y):
return f'<td><img src="{path}/{i:03}.png"></img></td>' if y else '<td></td>'
def template():
N = 16
nrows = max (chars1, chars2)
d,m = divmod(nrows, N)
ntables = d + 1 if m > 0 else 0
table_sizes = [N] * d + [m]
tables = []
for x in range(ntables):
tr = table_sizes[x]
rows1 = [row(i+x*N, font1dir, i+x*N<chars1) for i in range(tr)]
rows2 = [row(i+x*N, font2dir, i+x*N<chars2) for i in range(tr)]
rows = [f'<tr><td>{n+x*N}</td>{a+b}</tr>' for a,b,n in zip(rows1, rows2,
range(N))]
t = ''.join(rows)
tables.append(f'''<table>
<tr><th>#</th><th>big</th><th>lil</th></tr>
{t}
</table>''')
return f'''
<html>
<head>
<title>chocobo no fushigi na dungeon font table</title>
<style type="text/css">
body {{
background-color: black;
color: white;
font-size: 12px;
font-family: mono;
}}
table {{
margin-left:auto;
margin-right:auto;
float:left;
padding-right: 48px;
padding-bottom: 16px;
font-size: 12px;
font-family: mono;
}}
td {{
text-align: center;
font-size: 12px;
font-family: mono;
}}
</style>
</head>
<body>
<h1>chocobo no fushigi na dungeon font tables !!!!</h1>
{''.join(tables)}
</body>
</html>
'''
with open('index.html', 'w') as f:
f.write(template())
#!/usr/bin/env python3
import sys
width = 1
chars = {}
with open(sys.argv[1], 'rb') as f:
data = f.read()
l = len(data)
print ('length: ', l, l/2, l/3, l/4)
for c in data:
if c in chars:
chars[c] += 1
else:
chars[c] = 1
char_keys = chars.keys()
sorted_chars = sorted(char_keys, key=lambda x: -chars[x])
for x in sorted_chars:
p = chars[x]/l
print (f'{x}\t= {chars[x]}\t({p:.4f}%)')
print ('there r this many chars total: ', len(char_keys))
#!/usr/bin/env python3
def gen_row(page: int, offset: int, num: int) -> bytes:
assert 1 <= page <= 3
a = ord(str(page)[0])
b, c = divmod(offset, 0x10)
b = ord(hex(b)[-1])
c = ord(hex(c)[-1])
chars = []
for i in range(num):
chars.append(page)
chars.append(offset+i)
return bytes([0x4, 0x1, a, b, c, 0xf, 0x4, 0x0] + chars + [0xd, 0xa])
rows = []
for page in range(1,4):
rows += [gen_row(page, b*8, 8) for b in range(256//8)]
data = b''.join(rows) + b'\x00'
#print (data)
with open('out.bin', 'wb') as f:
f.write(data)
def mk(p, n):
a, b = divmod(n*8, 0x10)
a = hex(a)[-1]
b = hex(b)[-1]
return f'{p}{a}{b}'
page1 = [mk(1, x) for x in range(256//8)]
page2 = [mk(2, x) for x in range(256//8)]
page3 = [mk(3, x) for x in range(256//8)]
tablerows = [f'<tr><td><img src="screenshots/{a}.PNG" /></td><td><img src="screenshots/{b}.PNG" /></td><td><img src="screenshots/{c}.PNG" /></td></tr>' for a,b,c in zip(page1, page2,page3)]
trows = ''.join(tablerows)
html = f'''
<html>
<head><title>chocobo no fushigi na dungeon kanji screenshots</title>
<style>
body{{background-color:black;}}</style>
<body>
<table>
{trows}
</table>
</body>
</html>
'''
with open('index.html', 'w') as f:
f.write(html)
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#define STB_IMAGE_WRITE_IMPLEMENTATION
#include "stb_image_write.h"
typedef struct clut_entry_t {
int stp; /* transparency control bit */
float r; /* red */
float g; /* green */
float b; /* blue */
} clut_entry_t;
clut_entry_t *read_clt_file (char *path, int *n_entries) {
FILE *fp;
// uint32_t id;
// uint32_t flag;
// uint32_t bnum;
// uint16_t dx, dy;
// uint16_t w, h;
clut_entry_t *entries;
fp = fopen (path, "r");
/* read the clt header */
// fread (&id, 4, 1, fp);
// fread (&flag, 4, 1, fp);
// fread (&bnum, 4, 1, fp);
// fread (&dx, 2, 1, fp);
// fread (&dy, 2, 1, fp);
// fread (&w, 2, 1, fp);
// fread (&h, 2, 1, fp);
/* read all the clut entries */
//n_entries = (bnum - 12) / 2;
*n_entries = 2048;
entries = (clut_entry_t *) malloc (*n_entries * sizeof (clut_entry_t));
for (int i = 0; i < *n_entries; i++) {
uint16_t clut;
int r, g, b;
/* read a clut entry */
clut_entry_t *entry = &entries[i];
fread (&clut, 2, 1, fp);
r = (clut >> 0) & 0x1f;
g = (clut >> 5) & 0x1f;
b = (clut >> 10) & 0x1f;
entry->stp = clut & (1 << 15);
entry->r = r / 31.;
entry->g = g / 31.;
entry->b = b / 31.;
}
fclose (fp);
return entries;
}
int *read_pxl_file (char *path, int *width, int *height) {
FILE *fp;
// uint32_t id;
// uint32_t flag;
// uint32_t bnum;
// uint16_t dx, dy;
// uint16_t w, h;
int *buffer;
fp = fopen (path, "r");
/* read the clt header */
// fread (&id, 4, 1, fp);
// fread (&flag, 4, 1, fp);
// fread (&bnum, 4, 1, fp);
// fread (&dx, 2, 1, fp);
// fread (&dy, 2, 1, fp);
// fread (&w, 2, 1, fp);
// fread (&h, 2, 1, fp);
/* read all the clut entries */
*width = 256;//*2;
*height = 512*8*8;
buffer = (int *) malloc (*width * *height * sizeof (int));
for (int i = 0; i < *width * *height; i += 4) {
uint16_t word;
int pix0, pix1, pix2, pix3;
/* read a word */
fread (&word, 2, 1, fp);
pix0 = (word >> 0) & 0xf;
pix1 = (word >> 4) & 0xf;
pix2 = (word >> 8) & 0xf;
pix3 = (word >> 12) & 0xf;
buffer[i + 0] = pix0;
buffer[i + 1] = pix1;
buffer[i + 2] = pix2;
buffer[i + 3] = pix3;
}
fclose (fp);
return buffer;
}
int main (int argc, char **argv) {
/* image data */
int width, height;
int *image; /* indexed format */
uint8_t *buffer; /* rgba format */
int n_pal;
clut_entry_t *palette;
/* input files */
char *pxl_path;
char *clt_path;
/* output file */
char *png_path;
/* make sure all the args are specified */
if (argc != 4) {
fprintf (stderr, "usage: %s [input.pxl] [input.clt] [output.png]\n",
argv[0]);
return EXIT_FAILURE;
}
/* read the args */
pxl_path = argv[1];
clt_path = argv[2];
png_path = argv[3];
/* read the palette data */
palette = read_clt_file (clt_path, &n_pal);
/* read the image data */
image = read_pxl_file (pxl_path, &width, &height);
/* convert to png */
buffer = (uint8_t *) malloc (width * height * 4);
for (int i = 0; i < width * height * 4; i += 4) {
int transparent;
int index = image[i/4];
clut_entry_t entry = palette[index];
transparent = entry.r == entry.g == entry.b == entry.stp == 0;
buffer[i + 0] = (uint8_t) (entry.r * 255);
buffer[i + 1] = (uint8_t) (entry.g * 255);
buffer[i + 2] = (uint8_t) (entry.b * 255);
buffer[i + 3] = 255;//transparent ? 0 : 255;
}
/* write the png file */
if (stbi_write_png (png_path,
width, height,
/* rgba */ 4,
buffer,
/* stride */ width * 4) == 0) {
fprintf (stderr, "error writing png file\n");
return EXIT_FAILURE;
}
/* also write out the index file */
FILE *fp = fopen ("out.index", "w");
fwrite (image, sizeof (int), width * height, fp);
fclose (fp);
/* cleanup */
free (palette);
free (image);
free (buffer);
return EXIT_SUCCESS;
}
#!/usr/bin/env python3
import sys
import struct
fmt = 'B'
#fmt = 'H'
print (f'using fmt="{fmt}"')
print (f'reading from {sys.argv[1]}')
print (f'writing to {sys.argv[2]}')
with open(sys.argv[1], "r") as f:
s = f.read().split()
s = list(filter(lambda c: c!='?', s))
i = list(map(int, s))
with open(sys.argv[2], "wb") as f2:
f2.write(struct.pack('<'+fmt*len(i), *i))
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#define STB_IMAGE_WRITE_IMPLEMENTATION
#include "stb_image_write.h"
#define WIDTH 256
#define BLOCK_SIZE 16
#define MAX_ENTRIES 4096
typedef struct clut_entry_t {
int stp; /* transparency control bit */
float r; /* red */
float g; /* green */
float b; /* blue */
} clut_entry_t;
clut_entry_t *read_clt_file (char *path, int *n_entries) {
FILE *fp;
clut_entry_t *entries;
fp = fopen (path, "rb");
/* read all the clut entries */
entries = (clut_entry_t *) malloc (MAX_ENTRIES * sizeof (clut_entry_t));
uint16_t clut;
*n_entries = 0;
while (fread (&clut, 2, 1, fp) > 0) {
int r, g, b;
/* read a clut entry */
clut_entry_t *entry = &entries[(*n_entries)++];
r = (clut >> 0) & 0x1f;
g = (clut >> 5) & 0x1f;
b = (clut >> 10) & 0x1f;
entry->stp = (clut >> 15) & 1;
entry->r = r / 31.;
entry->g = g / 31.;
entry->b = b / 31.;
}
fclose (fp);
return entries;
}
uint32_t lookup (int index, clut_entry_t *palette) {
clut_entry_t entry = palette[index];
uint8_t r = entry.r * 255;
uint8_t g = entry.g * 255;
uint8_t b = entry.b * 255;
uint8_t a = (entry.r == 0 && entry.g == 0 && entry.b == 0 && entry.stp == 0)
? 0 : 255;
uint32_t color = (r << 0)
+ (g << 8)
+ (b << 16)
+ (a << 24);
return color;
}
int main (int argc, char **argv) {
/* 32-bit image buffer */
int blocks_per_line = WIDTH / BLOCK_SIZE;
int width = WIDTH;
int height;
uint32_t *buffer;
/* palette */
int n_entries;
clut_entry_t *palette;
/* file paths */
char *clt_path;
char *png_path;
/* parse arguments */
if (argc != 3) {
fprintf (stderr, "usage: %s [input.clt] [output.png]\n",
argv[0]);
return EXIT_FAILURE;
}
clt_path = argv[1];
png_path = argv[2];
/* decode the palette */
printf ("reading palette file...\n");
palette = read_clt_file (clt_path, &n_entries);
printf ("read %d entries.\n", n_entries);
/* allocate buffer */
height = BLOCK_SIZE * n_entries / blocks_per_line;
printf ("allocating 32-bit image buffer for %dx%d pixels...\n",
width, height);
if ((buffer = (uint32_t *) malloc (width * height * sizeof(uint32_t)))
== NULL) {
fprintf (stderr, "failure to allocate image buffer.\n");
return EXIT_FAILURE;
}
/* creating palette image */
for (int i = 0; i < n_entries; i++) {
int bx = i % blocks_per_line;
int by = i / blocks_per_line;
int ox = bx * BLOCK_SIZE;
int oy = by * BLOCK_SIZE;
for (int y = oy; y < oy + BLOCK_SIZE; y++)
for (int x = ox; x < ox + BLOCK_SIZE; x++)
buffer[x + y * width] = lookup (i, palette);
}
/* write out image buffers */
printf ("writing 32-bit %dx%d data to \"%s\"...\n",
width, height, png_path);
stbi_write_png (png_path, width, height, 4,
buffer, sizeof (uint32_t) * width);
/* cleanup */
printf ("done.\n");
free (palette);
free (buffer);
return EXIT_SUCCESS;
}
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"
#define STB_IMAGE_WRITE_IMPLEMENTATION
#include "stb_image_write.h"
#define BIG_FONT_PATH "big.png"
#define SMALL_FONT_PATH "small.png"
#define IN_PATH "in.bin"
#define OUT_PATH "out.png"
#define WIDTH 256
#define HEIGHT (12*4)
typedef struct point_t {
int x;
int y;
} point_t;
typedef struct font_t {
uint32_t *atlas;
point_t atlas_size;
point_t page_size;
point_t char_size;
} font_t;
point_t get_char_pos (font_t *font, int i_character, int i_page) {
int pages_per_line = font->atlas_size.x / font->page_size.x;
int chars_per_line = font->page_size.x / font->char_size.x;
point_t page_pos;
page_pos.x = i_page % pages_per_line * font->page_size.x;
page_pos.y = i_page / pages_per_line * font->page_size.y;
point_t char_pos;
char_pos.x = i_character % chars_per_line * font->char_size.x + page_pos.x;
char_pos.y = i_character / chars_per_line * font->char_size.y + page_pos.y;
return char_pos;
}
font_t *load_font (char *atlas_path,
int page_width, int page_height,
int char_width, int char_height) {
font_t *font = (font_t *) malloc (sizeof (font_t));
int comp;
font->atlas = (uint32_t *) stbi_load (atlas_path,
&font->atlas_size.x,
&font->atlas_size.y,
&comp, 4);
if (font->atlas == NULL) {
free (font);
return NULL;
}
font->page_size.x = page_width;
font->page_size.y = page_height;
font->char_size.x = char_width;
font->char_size.y = char_height;
return font;
}
void destroy_font (font_t *font) {
free (font->atlas);
free (font);
}
void blit (uint32_t *source, point_t source_pos, int source_width,
uint32_t *dest, point_t dest_pos, int dest_width,
int width, int height) {
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
int sx = source_pos.x + x;
int sy = source_pos.y + y;
int dx = dest_pos.x + x;
int dy = dest_pos.y + y;
int si = sx + sy * source_width;
int di = dx + dy * dest_width;
dest[di] = source[si];
}
}
}
int main (int argc, char **argv) {
/* load the fonts */
font_t *big_font = load_font (BIG_FONT_PATH, 256, 252, 12, 12);
if (big_font == NULL) {
fprintf (stderr, "failed to load font \"%s\".\n", BIG_FONT_PATH);
return EXIT_FAILURE;
}
font_t *small_font = load_font (BIG_FONT_PATH, 256, 64, 8, 8);
if (small_font == NULL) {
fprintf (stderr, "failed to load font \"%s\".\n", SMALL_FONT_PATH);
return EXIT_FAILURE;
}
font_t *font = big_font;
/* allocate image */
uint32_t *buffer = (uint32_t *) malloc (sizeof (uint32_t) * WIDTH * HEIGHT);
memset (buffer, 0, sizeof (uint32_t) * WIDTH * HEIGHT);
/* process input file */
FILE *fp = fopen (IN_PATH, "rb");
if (fp == NULL) {
fprintf (stderr, "failed to open input file \"%s\".\n", IN_PATH);
return EXIT_FAILURE;
}
int chars_per_line = WIDTH / font->char_size.x;
uint8_t byte;
unsigned int c;
int color = 0;
point_t cursor;
cursor.x = cursor.y = 0;
point_t source_pos;
while (fread (&byte, 1, 1, fp)) {
point_t dest_pos;
dest_pos.x = cursor.x * font->char_size.x;
dest_pos.y = cursor.y * font->char_size.y;
switch (byte) {
case 0x0:
goto end;
case 0x1:
fread (&byte, 1, 1, fp);
c = byte + 0x100 - 16;
goto print;
case 0x2:
fread (&byte, 1, 1, fp);
c = byte + 0x200 - 16;
goto print;
case 0x3:
fread (&byte, 1, 1, fp);
c = byte + 0x300 - 16;
goto print;
case 0x4:
fread (&color, 1, 1, fp);
break;
case 0x5:
case 0x6:
case 0x7:
case 0x8:
case 0x9:
break;
case 0xa:
cursor.x = 0;
cursor.y++;
break;
case 0xb:
case 0xc:
case 0xd:
case 0xe:
break;
case 0xf:
goto move;
default: {
c = byte - 16;
print:
source_pos = get_char_pos (font, c, color);
blit (font->atlas, source_pos, font->atlas_size.x,
buffer, dest_pos, WIDTH,
font->char_size.x, font->char_size.y);
move:
cursor.x++;
if (cursor.x >= chars_per_line) {
cursor.x = 0;
cursor.y++;
}
}
}
}
end:
fclose (fp);
/* write out image */
if (stbi_write_png (OUT_PATH, WIDTH, HEIGHT, 4, buffer, 4 * WIDTH) == 0) {
fprintf (stderr, "error writing to \"%s\".\n", OUT_PATH);
return EXIT_FAILURE;
}
/* cleanup */
free (buffer);
destroy_font (big_font);
destroy_font (small_font);
return EXIT_SUCCESS;
}
#!/usr/bin/env python3
import sys
with open(sys.argv[1], 'rb') as f:
source = f.read()
with open(sys.argv[2], 'wb') as f2:
f2.write(bytes((b - a)%256 for a,b in zip(source[:-1], source[1:])))
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <math.h>
#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"
#define STB_IMAGE_WRITE_IMPLEMENTATION
#include "stb_image_write.h"
/* font dimensions */
#define CHAR_WIDTH 8
#define CHAR_HEIGHT 8
/* output image dimensions */
#define OUT_WIDTH 512
void blit (uint8_t *source, int sx, int sy, int sw,
uint8_t *dest, int dx, int dy, int dw,
int width, int height) {
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
int _sx = sx + x;
int _sy = sy + y;
int _dx = dx + x;
int _dy = dy + y;
int si = _sx + _sy * sw;
int di = _dx + _dy * dw;
dest[di * 4 + 0] = source[si * 4 + 0];
dest[di * 4 + 1] = source[si * 4 + 1];
dest[di * 4 + 2] = source[si * 4 + 2];
dest[di * 4 + 3] = source[si * 4 + 3];
}
}
}
int font_w, font_h;
int main (int argc, char **argv) {
if (argc != 3) {
fprintf (stderr, "usage: render [font.png] [input.bin]\n");
exit(1);
}
char *font_path = argv[1];
char *in_path = argv[2];
/* read in all the text to render...... */
uint8_t s[256 * 256 * 64];
puts ("reading input...");
FILE *fp = fopen (in_path, "rb");
uint8_t c;
int len = 0;
int MAX = 256*256;
while (fread (&c, 1, 1, fp) > 0 && len < MAX)
s[len++] = c;
fclose (fp);
puts ("ok.");
printf ("read %d chars.\n", len);
printf ("reading font from %s...\n", font_path);
/* read the font file */
int n;
uint8_t *font = stbi_load (font_path, &font_w, &font_h, &n, 4);
if (font == NULL) {
fprintf (stderr, "couldnt open font.png\n");
return EXIT_FAILURE;
}
puts ("ok.");
/* render image */
int width = OUT_WIDTH;
int height = (int) ceil ((float) len / width * CHAR_WIDTH) * CHAR_HEIGHT;
int size = width * height * 4;
printf ("allocating image of size %d x %d...\n", width, height);
uint8_t *buffer = (uint8_t *) malloc (size + 10);
if(buffer==NULL){
fprintf (stderr, "dude FAILED to allocate buffer\n");
exit(1);
}
puts ("ok.");
int chars_line = (int) (width / CHAR_WIDTH);
int chars_line_font = (int) (font_w / CHAR_WIDTH);
printf ("characters per line = %d\n", chars_line);
puts ("rendering...\n");
int SIZE = 1;
for (int i = 0; i < len; i += SIZE) {
int c = 0;
for (int j = 0; j < SIZE; j++) {
uint8_t byte = s[i+j];
c+=byte*pow(256, j);
}
int dx = (i/SIZE) % chars_line * CHAR_WIDTH;
int dy = (i/SIZE) / chars_line * CHAR_HEIGHT;
int sx = c % chars_line_font * CHAR_WIDTH;
int sy = c / chars_line_font * CHAR_HEIGHT + 256;
if (sy > font_h - CHAR_HEIGHT)
{
printf ("WARNING sy=%d; skiipng\n", sy);
} else{
blit (font, sx, sy, font_w, buffer, dx, dy, width, CHAR_WIDTH, CHAR_HEIGHT);
}
}
puts ("ok.");
puts ("writing to out.png...");
/* write the png file out */
if (stbi_write_png ("out.png",
width, height,
/* rgba */ 4,
buffer,
/* stride */ width * 4) == 0) {
fprintf (stderr, "error writing out.png\n");
return EXIT_FAILURE;
}
puts ("ok.");
puts ("BYE.");
stbi_image_free (font);
return EXIT_SUCCESS;
}
#!/usr/bin/env python3
import sys
with open(sys.argv[1], 'rb') as f:
source = f.read()
with open(sys.argv[2], 'rb') as f:
search_str = f.read()
#test strings lol
#source = b'abcdefg12346def187324defp.l,c'
#search_str = b'def'
print (f'==== {sys.argv[1]} ==== {sys.argv[2]} ====')
print(f'searchin for', search_str,f'in {len(source)} bytes')
occurences = []
buf = b''
i = 0 # buf num
j = 0# char num
t = 0# timer for progress
totes = len(source)
for c in source:
if t == 1024*1024*32:
t = 0
p = j / totes
print (f'...{p:.4f}% ({j} / {totes})')
if c == search_str[i]:
buf += c
i+=1
if i == len(search_str):
buf = 0
occurences.append(j-i+1)
print (f'found @ pos={j-i+1}')
i = 0
else:
buf = 0
i = 0
t += 1
j += 1
print (f'found {len(occurences)} occurences')
if (len(occurences)>0):
print (' DING DING DING DING DING DING DING DING DING DING DING!!!!!!!!!')
print ('found here:', occurences)
#!/usr/bin/env python3
#encoding: utf-8
# script to extract the script from chocobo no fushigi na dungeon .bin file
# and to inject the script back after changes hav been made !!!
import struct
import os
import sys
MSG_BIN_OFFSET = 0x1714c800
MSG_BIN_SIZE = 0x40000
BIN_SIZE = 709332624
CHUNK_DELIMITER = '\n\n\\\n\n'
ITEM_DELIMITER = '\n\n'
# decode translation table
decode_table = 'あいうえおかきくけこさしすせそたヴ!ァィゥ'\
'ェォッ()。+,-./0123456789'\
':ー〜・⋯?「ABCDEFGHIJKLMN'\
'OPQRSTUVWXYZャュョベボ」abc'\
'defghijklmnopqrstuvwx'\
'yzパピプペポちつてとなにぬねのはひふへほ'\
'まみむめもやゆよらりるれろわをんがぎぐげご'\
'ざじずぜぞだぢづでどばびぶべぼぱぴぶぺぽぁ'\
'ぃぅぇぉっゃゅょアイウエオカキクケコサシス'\
'セソタチツテトナニヌネノハヒフヘホマミムメ'\
'モヤユヨラリルレロワヲンガギグゲゴザジズゼ'\
'ゾダヂヅデドバビブ'
# encode translation table
encode_table_a = '()*+,-./0123456789:—~•…?“ABCDEFGHIJKLMNOPQRSTUVWXYZ'
encode_table_b = '”abcdefghijklmnopqrstuvwxyz'
encode_table = {'!': 33}
for i, c in enumerate(encode_table_a):
encode_table[c] = i + 40
for i, c in enumerate(encode_table_b):
encode_table[c] = i + 96
# special sequences
END_TK = 'end'
COLOR_TK = 'color'
SPEED_TK = 'speed'
DELAY_TK = 'delay'
NAME_TK = 'name'
EVENT_TK = 'event'
WAIT_TK = 'wait'
CLOSE_TK = 'close'
tk_val = {
END_TK: 0x0,
COLOR_TK: 0x4,
SPEED_TK: 0x5,
DELAY_TK: 0x6,
NAME_TK: 0xb,
EVENT_TK: 0xc,
WAIT_TK: 0xd,
CLOSE_TK: 0xe,
}
# colors
colors = ['white', 'red', 'green', 'blue', 'yellow', 'gray']
for i, color in enumerate(colors):
tk_val[color] = i
def token(*args):
s =' '.join([f'{x}' for x in args])
return f'<{s}>'
def encode_text(text: str) -> bytes:
i = 0
out = b''
while i < len(text):
c = text[i]
if c in decode_table:
value = decode_table.index(c) + 16
page = value // 0x100
byte = value % 0x100
if page > 0:
out += bytes([page])
out += bytes([byte])
elif c == '\n':
out += bytes([0xa])
elif c == ' ':
out += bytes([0xf])
elif c == '<':
buf = ''
i += 1
while text[i] != '>':
buf += text[i]
i += 1
args = buf.split()
args = [tk_val[arg] if arg in tk_val else int(arg) for arg in args]
out += bytes(args)
elif c in encode_table:
out += bytes([encode_table[c]])
else:
raise Exception(f'cannot encode char "{c}"')
i += 1
return out
def decode_text(text: bytes) -> str:
i = 0
out = ''
def dec_char (c):
i = c - 16
if i < len(decode_table):
return decode_table[i]
else:
page = c // 0x100
byte = c % 0x100
if page == 0:
return token(byte)
else:
return token(page, byte)
while i < len(text):
c = int(text[i])
if c == 0x0:
out += token(END_TK)
elif c == 0x1:
out += dec_char(text[i + 1] + 0x100)
i += 1
elif c == 0x2:
out += dec_char(text[i + 1] + 0x200)
i += 1
elif c == 0x3:
out += dec_char(text[i + 1] + 0x300)
i += 1
elif c == 0x4:
out += token(COLOR_TK, colors[int(text[i + 1])])
i += 1
elif c == 0x5:
out += token(SPEED_TK, int(text[i + 1]))
i += 1
elif c == 0x6:
out += token(DELAY_TK, int(text[i + 1]))
i += 1
elif c == 0x7:
out += token(c, int(text[i + 1]))
i += 1
elif c == 0xa:
out += '\n'
elif c == 0xb:
out += token(NAME_TK)
elif c == 0xc:
out += token(EVENT_TK)
elif c == 0xd:
out += token(WAIT_TK)
elif c == 0xe:
out += token(CLOSE_TK)
elif c == 0xf:
out += ' '
else:
if c < 16:
out += token(c)
else:
out += dec_char(c)
i += 1
return out
def do_encode(bin_path: str, script_path: str):
assert os.path.getsize(bin_path) == BIN_SIZE
# first read in the script file
with open(script_path, 'rb') as f:
script = f.read().decode('utf8').strip()
# split out the chunks
chunks_str = script.split(CHUNK_DELIMITER)
# split out the text items
for i, chunk_str in enumerate(chunks_str):
chunks_str[i] = chunk_str.split(ITEM_DELIMITER)
# encode each chunk
chunks = [[encode_text(item) for item in chunk] for chunk in chunks_str]
# format each chunk with offsets and stuff
chunk_datas = []
for chunk in chunks:
num_items = len(chunk)
offset = num_items * 2
offsets = [offset]
for item in chunk[:-1]:
offset += len(item)
offsets.append(offset)
assert len(offsets) == num_items
offsets_bytes = struct.pack(f'<{"H"*num_items}', *offsets)
chunk_data = offsets_bytes + b''.join(chunk)
padding = 0x8000 - len(chunk_data)
chunk_data += b'\0' * padding
chunk_datas.append(chunk_data)
data = b''.join(chunk_datas)
# write out to msg.bin file in the bin
assert len(data) == MSG_BIN_SIZE
with open(bin_path, 'r+b') as f:
# we gotta deal with the sector offsets so....
# lets break the data into sectors!
num_sectors = MSG_BIN_SIZE // 0x800
starts = [i * 0x800 for i in range(num_sectors)]
sectors = [data[o:o+0x800] for o in starts]
# now figure out the actual in file offsets for each sector
sector = MSG_BIN_OFFSET // 0x800
offset = sector * 0x930 + 0x18
# write all the sectors
for s in sectors:
f.seek(offset)
f.write(s)
offset += 0x930
def do_decode(bin_path: str, script_path: str):
assert os.path.getsize(bin_path) == BIN_SIZE
# first read in the msg file from the bin file
# that means we gotta extract the msg file from the bin file
# stripping the extra meta data in the bin file
# (sector data or something?)
with open(bin_path, 'rb') as f:
# so uh, first read in the sectors relevant here
sector = MSG_BIN_OFFSET // 0x800
sector_offset = sector * 0x930
num_sectors = MSG_BIN_SIZE // 0x800
sectors_size = num_sectors * 0x930
f.seek(sector_offset)
sector_data = f.read(sectors_size)
# now strip the meta data from the sectors
starts = [i * 0x930 for i in range(num_sectors)]
sectors = [sector_data[o+0x18:o+0x818] for o in starts]
data = b''.join(sectors)
assert len(data) == MSG_BIN_SIZE
with open('msg.bin', 'wb') as g:
g.write(data)
# split it into 0x8000 chunks
chunks = [data[i:i+0x8000] for i in range(0, len(data), 0x8000)]
# decode each chunk
chunks_str = []
for chunk in chunks:
# strip off the trailing null bytes
while chunk[-1] == 0:
chunk = chunk[:-1]
# figure out how many text items there are in this chunk
# this is implied by the offset to the first item
# which immediately follows the 16bit offset array
first_offset = struct.unpack('<H', chunk[:2])[0]
num_items = first_offset // 2
# read all of the offsets
offsets = list(struct.unpack(f'<{"H"*num_items}', chunk[:first_offset]))
# get the ending offsets
end_offsets = offsets[1:] + [len(chunk)]
# collect all the text items
items = [decode_text(chunk[start:end]) for start, end in zip(offsets, end_offsets)]
# accumulate
chunks_str.append(items)
# write to output file
out = CHUNK_DELIMITER.join([ITEM_DELIMITER.join(items) for items in chunks_str])
with open(script_path, 'wb') as f:
f.write(out.encode('utf8'))
if __name__ == '__main__':
if len(sys.argv) != 4:
print(f'usage: {sys.argv[0]} [encode|decode] [game.bin] [script.txt]')
exit(1)
if sys.argv[1] == 'encode':
do_encode(sys.argv[2], sys.argv[3])
elif sys.argv[1] == 'decode':
do_decode(sys.argv[2], sys.argv[3])
else:
print('first argument must be "encode" or "decode"')
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment