// Build a port-compatible RAM dump that has the FS2.1 polygon // region (file offset $D000+) placed at the dispatcher-expected dest // address ($BD28 in chicago city RAM). // // Usage: extractCityPolygons // // The chunk5 standard scenery loader (FetchSectorFromDisk → // ReadBlocks) can't reach FS2.1 blocks past index ~$5F, so the // polygon region at file offset $D000+ never makes it into RAM via // fs2trace's normal boot. We manually copy that region into the dump // at $BD28 (overlaying the database-only section that chunk5 loaded). #include #include #include #include int main(int argc, char **argv) { if (argc != 4) { fprintf(stderr, "usage: %s \n", argv[0]); return 1; } FILE *fr = fopen(argv[1], "rb"); if (fr == NULL) { perror(argv[1]); return 1; } uint8_t ram[65536]; if (fread(ram, 1, 65536, fr) != 65536) { fprintf(stderr, "%s: not 64K\n", argv[1]); fclose(fr); return 1; } fclose(fr); FILE *fp = fopen(argv[2], "rb"); if (fp == NULL) { perror(argv[2]); return 1; } fseek(fp, 0, SEEK_END); long pSize = ftell(fp); fseek(fp, 0, SEEK_SET); uint8_t *poly = malloc(pSize); fread(poly, 1, pSize, fp); fclose(fp); // Polygon region in FS2.1: file offset $D000 onwards (~block // 104+). Copy it on top of the city dump's $BD28 so the // dispatcher's HEADER target now points to actual polygons // instead of the COM/NAV database. uint16_t dest = 0xBD28; long polyOff = 0xD000; long maxLen = 0xC000 - dest; // don't cross into $C000 I/O region long avail = pSize - polyOff; long copyLen = (avail < maxLen) ? avail : maxLen; if (copyLen <= 0) { fprintf(stderr, "polygon region empty\n"); free(poly); return 1; } memcpy(&ram[dest], &poly[polyOff], copyLen); FILE *fo = fopen(argv[3], "wb"); if (fo == NULL) { perror(argv[3]); free(poly); return 1; } fwrite(ram, 1, 65536, fo); fclose(fo); free(poly); fprintf(stderr, "Copied %ld bytes from %s @ $%lX to %s @ $%04X\n", copyLen, argv[2], polyOff, argv[3], dest); return 0; }