Created
April 18, 2026 11:28
-
-
Save RealDeuce/26dde7fb6253138a18546715bdc072d9 to your computer and use it in GitHub Desktop.
Simple thing to extract the map for LORE 2.5
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #include <stdio.h> | |
| #include <stdlib.h> | |
| #include <string.h> | |
| #include <stdint.h> | |
| #define REC_SIZE 1484 | |
| #define GRID 38 | |
| #define CELL_COUNT (GRID * GRID) /* 1444 */ | |
| #define KEY_OFF CELL_COUNT /* 1444 */ | |
| #define KEY_LEN GRID /* 38 */ | |
| #define HDR_OFF (KEY_OFF + KEY_LEN)/* 1482 */ | |
| static const unsigned char chars[256] = { | |
| 0x00, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x18, 0x19, 0x20, 0x56, 0x6F, | |
| 0x87, 0x8B, 0x8C, 0x8C, 0x8C, 0x8D, 0x8D, 0x8E, 0x95, 0x9D, 0x9D, 0xA1, 0xA1, 0xA2, 0xA6, 0xB0, | |
| 0xB0, 0xB0, 0xB0, 0xB0, 0xB0, 0xB0, 0xB0, 0xB0, 0xB1, 0xB1, 0xB1, 0xB1, 0xB1, 0xB1, 0xB1, 0xB1, | |
| 0xB1, 0xB1, 0xB1, 0xB1, 0xB2, 0xB2, 0xB2, 0xB2, 0xB2, 0xB2, 0xB2, 0xB2, 0xB2, 0xB2, 0xB2, 0xB3, | |
| 0xB3, 0xB4, 0xB6, 0xB9, 0xBA, 0xBB, 0xBC, 0xBF, 0xBF, 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC4, 0xC4, | |
| 0xC5, 0xC5, 0xC5, 0xC5, 0xC5, 0xC5, 0xC5, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCD, 0xCF, | |
| 0xD1, 0xD7, 0xD8, 0xD8, 0xD9, 0xDA, 0xDB, 0xDB, 0xDB, 0xDB, 0xDB, 0xE0, 0xE0, 0xE2, 0xE2, 0xE2, | |
| 0xE2, 0xE2, 0xE2, 0xE3, 0xE4, 0xE4, 0xE4, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE6, 0xE7, 0xE7, | |
| 0xE7, 0xE7, 0xE7, 0xE7, 0xE7, 0xE7, 0xE8, 0xE8, 0xE8, 0xE8, 0xE8, 0xE8, 0xE9, 0xE9, 0xE9, 0xE9, | |
| 0xE9, 0xE9, 0xEC, 0xEC, 0xEC, 0xEC, 0xED, 0xEE, 0xEE, 0xEE, 0xEF, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, | |
| 0xF0, 0xF0, 0xF1, 0xF2, 0xF2, 0xF2, 0xF3, 0xF3, 0xF3, 0xF4, 0xF4, 0xF4, 0xF4, 0xF4, 0xF4, 0xF7, | |
| 0xF8, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0x00, 0x02, 0x0A, 0x06, 0x0C, 0x0F, 0x0B, 0x0D, 0x09, 0x0E, | |
| 0x08, 0x07, 0x07, 0x00, 0x0E, 0x0F, 0x01, 0x0A, 0x09, 0x06, 0x08, 0x0E, 0x08, 0x02, 0x0C, 0x0E, | |
| 0x02, 0x0E, 0x08, 0x07, 0x0E, 0x01, 0x02, 0x06, 0x04, 0xCC, 0x0E, 0x03, 0x07, 0x0F, 0x01, 0x12, | |
| 0x02, 0x07, 0x0F, 0x0A, 0x19, 0x09, 0x6E, 0x06, 0xCC, 0x70, 0x01, 0x02, 0x07, 0x0F, 0x19, 0x09, | |
| 0x04, 0x4C, 0xCC, 0x06, 0x08, 0x06, 0x07, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x07, 0x06, | |
| }; | |
| static const unsigned char attrs[256] = { | |
| 0x00, 0x02, 0x0A, 0x06, 0x0C, 0x0F, 0x0B, 0x0D, 0x09, 0x0E, 0x08, 0x07, 0x07, 0x00, 0x0E, 0x0F, | |
| 0x01, 0x0A, 0x09, 0x06, 0x08, 0x0E, 0x08, 0x02, 0x0C, 0x0E, 0x02, 0x0E, 0x08, 0x07, 0x0E, 0x01, | |
| 0x02, 0x06, 0x04, 0xCC, 0x0E, 0x03, 0x07, 0x0F, 0x01, 0x12, 0x02, 0x07, 0x0F, 0x0A, 0x19, 0x09, | |
| 0x6E, 0x06, 0xCC, 0x70, 0x01, 0x02, 0x07, 0x0F, 0x19, 0x09, 0x04, 0x4C, 0xCC, 0x06, 0x08, 0x06, | |
| 0x07, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x07, 0x06, 0x06, 0x06, 0x06, 0x06, 0x03, 0x07, | |
| 0x0E, 0x0F, 0x08, 0x07, 0x0C, 0x05, 0x04, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x07, 0x06, | |
| 0x06, 0x06, 0x07, 0x06, 0x06, 0x06, 0x00, 0x06, 0x05, 0x0F, 0x01, 0x05, 0x0E, 0x02, 0x0E, 0x07, | |
| 0x03, 0x08, 0x09, 0x06, 0x08, 0x04, 0x05, 0x07, 0x08, 0x0D, 0x04, 0x0E, 0x06, 0x09, 0x02, 0x0A, | |
| 0x06, 0x04, 0x0C, 0x07, 0x08, 0x0E, 0x09, 0x07, 0x0F, 0x05, 0x0D, 0x08, 0x06, 0x4F, 0x03, 0x0D, | |
| 0x0B, 0x02, 0x08, 0x09, 0x0E, 0x05, 0x08, 0x07, 0x04, 0x03, 0x0F, 0x07, 0x06, 0x02, 0x04, 0x05, | |
| 0x03, 0x09, 0x05, 0x0E, 0x06, 0x09, 0x06, 0x0E, 0x09, 0x0D, 0x0E, 0x06, 0x02, 0x0A, 0x07, 0x01, | |
| 0x0F, 0x0F, 0x70, 0x0E, 0x07, 0x08, 0x00, 0x01, 0x00, 0xC0, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1C, | |
| 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC1, 0x18, 0x18, 0x18, 0x18, 0x18, | |
| 0x18, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC2, 0x00, 0x00, 0x00, 0x00, | |
| 0x00, 0x00, 0xFF, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xC3, 0x18, 0x18, 0x18, | |
| 0x18, 0x18, 0x18, 0x1F, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xC4, 0x00, 0x00, | |
| }; | |
| static void decode_area(const unsigned char *rec, unsigned char ch[GRID][GRID], unsigned char at[GRID][GRID]) | |
| { | |
| const unsigned char *key = rec + KEY_OFF; | |
| for (int y = 1; y <= GRID; y++) { | |
| for (int x = 1; x <= GRID; x++) { | |
| unsigned char raw = rec[(y - 1) * GRID + (x - 1)]; | |
| unsigned char idx = (unsigned char)(raw - key[x - 1] - key[y - 1]); | |
| ch[y - 1][x - 1] = chars[idx]; | |
| at[y - 1][x - 1] = attrs[idx]; | |
| } | |
| } | |
| } | |
| static int is_empty(const unsigned char ch[GRID][GRID]) | |
| { | |
| unsigned char first = ch[0][0]; | |
| for (int y = 0; y < GRID; y++) | |
| for (int x = 0; x < GRID; x++) | |
| if (ch[y][x] != first) return 0; | |
| return 1; | |
| } | |
| static void preview(int rn, int wx, int wy, const unsigned char ch[GRID][GRID]) | |
| { | |
| printf("=== record %d world (%d,%d) ===\n", rn, wx, wy); | |
| for (int y = 0; y < GRID; y++) { | |
| for (int x = 0; x < GRID; x++) { | |
| unsigned char c = ch[y][x]; | |
| fputc((c >= 0x20 && c < 0x7F) ? c : c < 0x20 ? c + 0x20 : c < 0xA0 ? c - 0x60 : c - 0x7f , stdout); | |
| } | |
| fputc('\n', stdout); | |
| } | |
| } | |
| static char | |
| xlat(unsigned char c) | |
| { | |
| if (c == 0xb0) | |
| return '~'; // Ocean? | |
| if (c == 0xb1) | |
| return '.'; // Plains? | |
| if (c == 0xb2) | |
| return '^'; // Trees? | |
| if (c == 0x0f) | |
| return '*'; // Entry? | |
| if (c == 0xba) | |
| return 'I'; // Road | |
| if (c == 0xcd) | |
| return '='; // Road | |
| if (c >= 0x20 && c < 0x7f) | |
| return c; | |
| if (c < 0x20) | |
| return c + 0x20; | |
| c -= 0x80; | |
| return xlat(c); | |
| } | |
| /* | |
| * World layout (MAP1, verified by edge-match): rec = Y*stride + X with | |
| * X the fast index (stride = world width). For MAP1 stride = 16 → 16 cols x 22 rows. | |
| */ | |
| static void stitch(FILE *f, long nrec, int stride) | |
| { | |
| long ndata = nrec - 1; | |
| int cols = stride; | |
| int rows = (int)((ndata + stride - 1) / stride); | |
| int W = cols * GRID, H = rows * GRID; | |
| unsigned char *world = malloc((size_t)W * H); | |
| if (!world) { perror("malloc"); return; } | |
| memset(world, ' ', (size_t)W * H); | |
| unsigned char rec[REC_SIZE]; | |
| unsigned char ch[GRID][GRID], at[GRID][GRID]; | |
| for (long rn = 1; rn <= ndata; rn++) { | |
| if (fread(rec, 1, REC_SIZE, f) != REC_SIZE) break; | |
| decode_area(rec, ch, at); | |
| int X = (int)((rn - 1) % stride); /* 0-based column (fast) */ | |
| int Y = (int)((rn - 1) / stride); /* 0-based row (slow) */ | |
| for (int y = 0; y < GRID; y++) { | |
| unsigned char *dst = world + (size_t)(Y * GRID + y) * W + X * GRID; | |
| for (int x = 0; x < GRID; x++) { | |
| unsigned char c = ch[y][x]; | |
| dst[x] = xlat(c); | |
| } | |
| } | |
| } | |
| for (int y = 0; y < H; y++) { | |
| fwrite(world + (size_t)y * W, 1, W, stdout); | |
| fputc('\n', stdout); | |
| } | |
| free(world); | |
| } | |
| int main(int argc, char **argv) | |
| { | |
| if (argc < 2) { | |
| fprintf(stderr, | |
| "usage: %s MAPFILE [-s [STRIDE] | -p | -a]\n" | |
| " -s [N] stitched ASCII world (default; STRIDE defaults to 16)\n" | |
| " -p per-area ASCII preview\n" | |
| " -a per-area binary dumps area_XX_YY.bin\n", | |
| argv[0]); | |
| return 2; | |
| } | |
| const char *path = argv[1]; | |
| enum { M_STITCH, M_PREVIEW, M_BIN } mode = M_STITCH; | |
| int stride = 16; | |
| if (argc >= 3) { | |
| if (!strcmp(argv[2], "-p")) mode = M_PREVIEW; | |
| else if (!strcmp(argv[2], "-a")) mode = M_BIN; | |
| else if (!strcmp(argv[2], "-s")) { | |
| mode = M_STITCH; | |
| if (argc >= 4) stride = atoi(argv[3]); | |
| } | |
| } | |
| FILE *f = fopen(path, "rb"); | |
| if (!f) { perror(path); return 1; } | |
| fseek(f, 0, SEEK_END); | |
| long sz = ftell(f); | |
| fseek(f, 0, SEEK_SET); | |
| if (sz % REC_SIZE) { | |
| fprintf(stderr, "%s: size %ld not a multiple of %d\n", path, sz, REC_SIZE); | |
| fclose(f); | |
| return 1; | |
| } | |
| long nrec = sz / REC_SIZE; | |
| unsigned char rec[REC_SIZE]; | |
| unsigned char ch[GRID][GRID], at[GRID][GRID]; | |
| /* Record 0 is the signature header. */ | |
| if (fread(rec, 1, REC_SIZE, f) != REC_SIZE) { perror(path); fclose(f); return 1; } | |
| fprintf(stderr, "signature: %.21s\n", (char *)rec); | |
| fprintf(stderr, "data records: %ld\n", nrec - 1); | |
| if (mode == M_STITCH) { | |
| stitch(f, nrec, stride); | |
| fclose(f); | |
| return 0; | |
| } | |
| for (long rn = 1; rn < nrec; rn++) { | |
| if (fread(rec, 1, REC_SIZE, f) != REC_SIZE) break; | |
| decode_area(rec, ch, at); | |
| int wx = rec[HDR_OFF]; | |
| int wy = rec[HDR_OFF + 1]; | |
| if (is_empty(ch)) continue; | |
| if (mode == M_PREVIEW) preview((int)rn, wx, wy, ch); | |
| if (mode == M_BIN) { | |
| char name[64]; | |
| snprintf(name, sizeof name, "area_%02d_%02d.bin", wx, wy); | |
| FILE *o = fopen(name, "wb"); | |
| if (!o) { perror(name); continue; } | |
| fwrite(ch, 1, GRID * GRID, o); | |
| fwrite(at, 1, GRID * GRID, o); | |
| fclose(o); | |
| } | |
| } | |
| fclose(f); | |
| return 0; | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment