diff options
| author | KonAki <konaki@anokonaki.org> | 2026-10-15 05:40:42 +0800 |
|---|---|---|
| committer | KonAki <konaki@anokonaki.org> | 2026-10-15 05:40:42 +0800 |
| commit | 79957363275663e82900160b5a08aa56fc21086c (patch) | |
| tree | 1cf23e5497a8c82ff69c45c6bcefd69be0066434 | |
| parent | 60698e3006c88bc6b9eb4a851e21197c39e7a12d (diff) | |
find the data folder from the game folder in the converters
| -rw-r--r-- | tools/mzmap.c | 515 | ||||
| -rw-r--r-- | tools/mzscript.c | 25 | ||||
| -rw-r--r-- | tools/mzsurvey.c | 28 |
3 files changed, 564 insertions, 4 deletions
diff --git a/tools/mzmap.c b/tools/mzmap.c new file mode 100644 index 0000000..fae8221 --- /dev/null +++ b/tools/mzmap.c @@ -0,0 +1,515 @@ +/* SPDX-License-Identifier: MIT */ +/* + * mzmap.c + * + * Copyright (c) 2026 KonAki + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* + * usage: mzmap [-n name] <data folder> <output folder> + * turns the maps, tilesets and start settings of an exported RPG Maker MV or MZ game into C, as const data for konrmmap.h. + * + * name_maps.h, name_maps.c the tables to use: name_maps[id] and name_tilesets[id] (NULL for an id that is not there), + * and name_system. each map is in its own name_mapNNN.inc that name_maps.c includes + * + * only const data is written: numbers, strings and pointers to other const data, nothing that runs. a map that is not + * the size it says it is, or has a tile that does not fit, is made safe (missing tiles are empty) instead of refused + */ + +#define KONJSON_IMPLEMENTATION +#include "konjson.h" + +#include <ctype.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#define MAX_MAP_ID 1999 +#define MAX_SIDE 256 +#define STRING_PIECE 100 +#define LAYERS 6 + +static int mapCount, eventCount, pageCount, tileTotal; + +/*** output ***/ + +static void cstring(FILE *f, const char *s) +{ + size_t i, piece = 0; + + if (!s || !*s) { + fputs("\"\"", f); + return; + } + fputc('"', f); + for (i = 0; s[i]; i++) { + unsigned char ch = (unsigned char)s[i]; + + if (piece >= STRING_PIECE) { + fputs("\"\n\t\"", f); + piece = 0; + } + if (ch == '"' || ch == '\\') fprintf(f, "\\%c", ch); + else if (ch == '\n') fputs("\\n", f); + else if (ch == '\t') fputs("\\t", f); + else if (ch >= 32 && ch < 127 && ch != '?') fputc(ch, f); + else fprintf(f, "\\%03o", ch); + piece++; + } + fputc('"', f); +} + +static const char *text(const kon_json_t *j) +{ + const char *s = kon_jsonString(j, ""); + + return s ? s : ""; +} + +static int number(const kon_json_t *j, int low, int high, int fallback) +{ + int v = kon_jsonInt(j, fallback); + + return v < low ? low : v > high ? high : v; +} + +/* a value that does not fit in 16 bits is not a tile or a flag, so it becomes 0 */ +static int unsigned16(const kon_json_t *j) +{ + int v = kon_jsonInt(j, 0); + + return v < 0 || v > 65535 ? 0 : v; +} + +static int flag(const kon_json_t *j) +{ + return kon_jsonBool(j, 0) ? 1 : 0; +} + +/* a game folder works too, the data is in data, or in www/data for MV */ +static int findData(char *out, size_t size, const char *folder) +{ + static const char *const where[] = {"", "/data", "/www/data"}; + char path[1100]; + FILE *f; + int i; + + for (i = 0; i < 3; i++) { + snprintf(path, sizeof path, "%s%s/System.json", folder, where[i]); + f = fopen(path, "rb"); + if (f) { + fclose(f); + snprintf(out, size, "%s%s", folder, where[i]); + return 1; + } + } + fprintf(stderr, "no System.json in %s, %s/data or %s/www/data\n", folder, folder, folder); + return 0; +} + +static kon_json_t *load(const char *folder, const char *name) +{ + char path[1024], error[120]; + kon_json_t *j; + + snprintf(path, sizeof path, "%s/%s", folder, name); + j = kon_jsonParseFile(path, error, sizeof error); + if (!j && strncmp(error, "cannot open", 11)) fprintf(stderr, "%s: %s\n", path, error); + return j; +} + +static void audio(FILE *f, const kon_json_t *a) +{ + fputs("{", f); + cstring(f, text(kon_jsonGet(a, "name"))); + fprintf(f, ", %d, %d, %d}", number(kon_jsonGet(a, "volume"), 0, 100, 90), number(kon_jsonGet(a, "pitch"), 50, 150, 100), number(kon_jsonGet(a, "pan"), -100, 100, 0)); +} + +/*** one map ***/ + +static void pageRoute(FILE *f, const char *name, const kon_json_t *route) +{ + const kon_json_t *list = kon_jsonGet(route, "list"); + int i, k, written = 0; + + for (i = 0; i < kon_jsonCount(list); i++) { + const kon_json_t *command = kon_jsonAt(list, i); + const kon_json_t *params = kon_jsonGet(command, "parameters"); + int code = number(kon_jsonGet(command, "code"), 0, 1000, 0); + int count = 0, allNumbers = 1; + + if (code == 0) continue; + for (k = 0; k < kon_jsonCount(params) && k < 8; k++) { + const kon_json_t *p = kon_jsonAt(params, k); + + if (!p || (p->type != KON_JSON_NUMBER && p->type != KON_JSON_BOOL)) allNumbers = 0; + } + if (allNumbers) count = kon_jsonCount(params) < 8 ? kon_jsonCount(params) : 8; + + if (!written) fprintf(f, "static const int32_t %s[] = {\n", name); + fprintf(f, "\t%d, %d", code, count); + for (k = 0; k < count; k++) fprintf(f, ", %d", number(kon_jsonAt(params, k), -2147483647, 2147483647, 0)); + fputs(",\n", f); + written++; + } + if (written) fputs("};\n\n", f); +} + +static int routeSize(const kon_json_t *route) +{ + const kon_json_t *list = kon_jsonGet(route, "list"); + int i, k, size = 0; + + for (i = 0; i < kon_jsonCount(list); i++) { + const kon_json_t *command = kon_jsonAt(list, i); + const kon_json_t *params = kon_jsonGet(command, "parameters"); + int allNumbers = 1, count; + + if (number(kon_jsonGet(command, "code"), 0, 1000, 0) == 0) continue; + for (k = 0; k < kon_jsonCount(params) && k < 8; k++) { + const kon_json_t *p = kon_jsonAt(params, k); + + if (!p || (p->type != KON_JSON_NUMBER && p->type != KON_JSON_BOOL)) allNumbers = 0; + } + count = allNumbers ? (kon_jsonCount(params) < 8 ? kon_jsonCount(params) : 8) : 0; + size += 2 + count; + } + return size; +} + +static void writeEvent(FILE *f, const char *name, int mapId, const kon_json_t *event, int index) +{ + const kon_json_t *pages = kon_jsonGet(event, "pages"); + int eventId = number(kon_jsonGet(event, "id"), 0, 1000000, index); + int p, np = kon_jsonCount(pages); + + for (p = 0; p < np; p++) { + char routeName[128]; + + snprintf(routeName, sizeof routeName, "%s_m%d_e%d_p%d_route", name, mapId, eventId, p + 1); + pageRoute(f, routeName, kon_jsonGet(kon_jsonAt(pages, p), "moveRoute")); + } + if (np == 0) return; + + fprintf(f, "static const kon_rmPage_t %s_m%d_e%d_pages[] = {\n", name, mapId, eventId); + for (p = 0; p < np; p++) { + const kon_json_t *page = kon_jsonAt(pages, p); + const kon_json_t *c = kon_jsonGet(page, "conditions"); + const kon_json_t *image = kon_jsonGet(page, "image"); + const kon_json_t *route = kon_jsonGet(page, "moveRoute"); + const char *letter = text(kon_jsonGet(c, "selfSwitchCh")); + int size = routeSize(route); + + fprintf(f, "\t{%d, %d, %d, %d, %d, %d, '%c', %d, %d, %d, %d, %d, %d,\n\t\t", flag(kon_jsonGet(c, "switch1Valid")), flag(kon_jsonGet(c, "switch2Valid")), flag(kon_jsonGet(c, "variableValid")), flag(kon_jsonGet(c, "selfSwitchValid")), flag(kon_jsonGet(c, "itemValid")), flag(kon_jsonGet(c, "actorValid")), letter[0] >= 'A' && letter[0] <= 'D' ? letter[0] : 'A', number(kon_jsonGet(c, "switch1Id"), 0, 100000, 0), number(kon_jsonGet(c, "switch2Id"), 0, 100000, 0), number(kon_jsonGet(c, "variableId"), 0, 100000, 0), number(kon_jsonGet(c, "variableValue"), -2147483647, 2147483647, 0), number(kon_jsonGet(c, "itemId"), 0, 100000, 0), number(kon_jsonGet(c, "actorId"), 0, 100000, 0)); + cstring(f, text(kon_jsonGet(image, "characterName"))); + fprintf(f, ", %d, %d, %d, %d,\n\t\t%d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d,\n\t\t", number(kon_jsonGet(image, "characterIndex"), 0, 7, 0), number(kon_jsonGet(image, "direction"), 0, 10, 2), number(kon_jsonGet(image, "pattern"), 0, 2, 0), number(kon_jsonGet(image, "tileId"), 0, 65535, 0), number(kon_jsonGet(page, "moveType"), 0, 3, 0), number(kon_jsonGet(page, "moveSpeed"), 1, 6, 3), number(kon_jsonGet(page, "moveFrequency"), 1, 5, 3), number(kon_jsonGet(page, "priorityType"), 0, 2, 0), number(kon_jsonGet(page, "trigger"), 0, 4, 0), flag(kon_jsonGet(page, "walkAnime")), flag(kon_jsonGet(page, "stepAnime")), flag(kon_jsonGet(page, "directionFix")), flag(kon_jsonGet(page, "through")), flag(kon_jsonGet(route, "repeat")), flag(kon_jsonGet(route, "skippable")), flag(kon_jsonGet(route, "wait"))); + fprintf(f, "\"m%de%dp%d\", ", mapId, eventId, p + 1); + if (size > 0) fprintf(f, "%s_m%d_e%d_p%d_route, %d},\n", name, mapId, eventId, p + 1, size); + else fputs("NULL, 0},\n", f); + pageCount++; + } + fputs("};\n\n", f); +} + +static int writeMap(const char *folder, const char *outFolder, const char *name, int id) +{ + char file[32], path[1100]; + kon_json_t *json; + const kon_json_t *data, *events, *encounters; + FILE *f; + int width, height, layerSize, i, k, written = 0, hasEvents = 0, hasEncounters = 0; + size_t total, count; + + snprintf(file, sizeof file, "Map%03d.json", id); + json = load(folder, file); + if (!json) return 0; + + width = kon_jsonInt(kon_jsonGet(json, "width"), 0); + height = kon_jsonInt(kon_jsonGet(json, "height"), 0); + if (width < 1 || height < 1 || width > MAX_SIDE || height > MAX_SIDE) { + fprintf(stderr, "%s has no usable size, skipped\n", file); + kon_jsonFree(json); + return 0; + } + layerSize = width * height; + total = (size_t)layerSize * LAYERS; + data = kon_jsonGet(json, "data"); + count = (size_t)kon_jsonCount(data); + + snprintf(path, sizeof path, "%s/%s_map%03d.inc", outFolder, name, id); + f = fopen(path, "wb"); + if (!f) { + fprintf(stderr, "cannot write %s\n", path); + kon_jsonFree(json); + return -1; + } + + fprintf(f, "/* map %d from %s, written by mzmap */\n\n", id, file); + fprintf(f, "static const uint16_t %s_m%d_tiles[] = {\n", name, id); + for (i = 0; (size_t)i < total; i++) { + int v = (size_t)i < count ? unsigned16(kon_jsonAt(data, i)) : 0; + + fprintf(f, "%s%d,", written % 24 == 0 ? "\t" : " ", v); + if (++written % 24 == 0) fputc('\n', f); + } + if (written % 24) fputc('\n', f); + fputs("};\n\n", f); + tileTotal += (int)total; + + events = kon_jsonGet(json, "events"); + for (i = 0; i < kon_jsonCount(events); i++) { + const kon_json_t *event = kon_jsonAt(events, i); + + if (!event || event->type != KON_JSON_OBJECT) continue; + writeEvent(f, name, id, event, i); + hasEvents++; + } + if (hasEvents) { + fprintf(f, "static const kon_rmEvent_t %s_m%d_events[] = {\n", name, id); + for (i = 0; i < kon_jsonCount(events); i++) { + const kon_json_t *event = kon_jsonAt(events, i); + int eventId; + + if (!event || event->type != KON_JSON_OBJECT) continue; + eventId = number(kon_jsonGet(event, "id"), 0, 1000000, i); + fprintf(f, "\t{%d, ", eventId); + cstring(f, text(kon_jsonGet(event, "name"))); + fprintf(f, ", %d, %d, ", number(kon_jsonGet(event, "x"), 0, MAX_SIDE, 0), number(kon_jsonGet(event, "y"), 0, MAX_SIDE, 0)); + if (kon_jsonCount(kon_jsonGet(event, "pages")) > 0) fprintf(f, "%s_m%d_e%d_pages, %d},\n", name, id, eventId, kon_jsonCount(kon_jsonGet(event, "pages"))); + else fputs("NULL, 0},\n", f); + eventCount++; + } + fputs("};\n\n", f); + } + + encounters = kon_jsonGet(json, "encounterList"); + for (i = 0; i < kon_jsonCount(encounters); i++) { + const kon_json_t *regions = kon_jsonGet(kon_jsonAt(encounters, i), "regionSet"); + + if (kon_jsonCount(regions) == 0) continue; + fprintf(f, "static const int %s_m%d_enc%d_regions[] = {", name, id, i); + for (k = 0; k < kon_jsonCount(regions); k++) fprintf(f, "%s%d", k ? ", " : "", number(kon_jsonAt(regions, k), 0, 255, 0)); + fputs("};\n", f); + } + if (kon_jsonCount(encounters) > 0) { + fprintf(f, "\nstatic const kon_rmEncounter_t %s_m%d_encounters[] = {\n", name, id); + for (i = 0; i < kon_jsonCount(encounters); i++) { + const kon_json_t *e = kon_jsonAt(encounters, i); + int rc = kon_jsonCount(kon_jsonGet(e, "regionSet")); + + fprintf(f, "\t{%d, %d, ", number(kon_jsonGet(e, "troopId"), 0, 100000, 0), number(kon_jsonGet(e, "weight"), 0, 1000, 1)); + if (rc > 0) fprintf(f, "%s_m%d_enc%d_regions, %d},\n", name, id, i, rc); + else fputs("NULL, 0},\n", f); + } + fputs("};\n", f); + hasEncounters = 1; + } + fputs("\n", f); + + fprintf(f, "static const kon_rmMap_t %s_m%d = {\n\t%d, %d, %d, %d, %s_m%d_tiles,\n\t", name, id, id, width, height, number(kon_jsonGet(json, "tilesetId"), 0, 100000, 0), name, id); + cstring(f, text(kon_jsonGet(json, "displayName"))); + fputs(",\n\t", f); + cstring(f, text(kon_jsonGet(json, "note"))); + fprintf(f, ",\n\t%d, %d, %d, %d,\n\t", number(kon_jsonGet(json, "scrollType"), 0, 3, 0), flag(kon_jsonGet(json, "disableDashing")), flag(kon_jsonGet(json, "autoplayBgm")), flag(kon_jsonGet(json, "autoplayBgs"))); + audio(f, kon_jsonGet(json, "bgm")); + fputs(", ", f); + audio(f, kon_jsonGet(json, "bgs")); + fputs(",\n\t", f); + cstring(f, text(kon_jsonGet(json, "parallaxName"))); + fprintf(f, ", %d, %d, %d, %d, %d,\n\t%d,\n\t", flag(kon_jsonGet(json, "parallaxLoopX")), flag(kon_jsonGet(json, "parallaxLoopY")), number(kon_jsonGet(json, "parallaxSx"), -100, 100, 0), number(kon_jsonGet(json, "parallaxSy"), -100, 100, 0), flag(kon_jsonGet(json, "parallaxShow")), number(kon_jsonGet(json, "encounterStep"), 0, 10000, 30)); + if (hasEncounters) fprintf(f, "%s_m%d_encounters, %d,\n\t", name, id, kon_jsonCount(encounters)); + else fputs("NULL, 0,\n\t", f); + if (hasEvents) fprintf(f, "%s_m%d_events, %d\n};\n", name, id, hasEvents); + else fputs("NULL, 0\n};\n", f); + + if (ferror(f) || fclose(f) != 0) { + fprintf(stderr, "cannot write %s\n", path); + kon_jsonFree(json); + return -1; + } + kon_jsonFree(json); + mapCount++; + return id; +} + +/*** tilesets and system ***/ + +static int writeTilesets(FILE *f, const char *name, const kon_json_t *json) +{ + int i, k, highest = 0; + + for (i = 1; i < kon_jsonCount(json); i++) { + const kon_json_t *t = kon_jsonAt(json, i); + const kon_json_t *flags = kon_jsonGet(t, "flags"); + int id = number(kon_jsonGet(t, "id"), 0, 100000, i), n = kon_jsonCount(flags); + + if (!t || t->type != KON_JSON_OBJECT || id < 1) continue; + if (id > highest) highest = id; + if (n > 0) { + fprintf(f, "static const uint16_t %s_tileset%d_flags[] = {\n", name, id); + for (k = 0; k < n; k++) { + fprintf(f, "%s%d,", k % 24 == 0 ? "\t" : " ", unsigned16(kon_jsonAt(flags, k))); + if (k % 24 == 23 || k == n - 1) fputc('\n', f); + } + fputs("};\n", f); + } + fprintf(f, "static const kon_rmTileset_t %s_tileset%d = {\n\t%d, %d, {", name, id, id, number(kon_jsonGet(t, "mode"), 0, 1, 1)); + for (k = 0; k < 9; k++) { + if (k) fputs(", ", f); + cstring(f, text(kon_jsonAt(kon_jsonGet(t, "tilesetNames"), k))); + } + fputs("},\n\t", f); + if (n > 0) fprintf(f, "%s_tileset%d_flags, %d\n};\n\n", name, id, n); + else fputs("NULL, 0\n};\n\n", f); + } + return highest; +} + +static int validName(const char *s) +{ + if (!isalpha((unsigned char)s[0]) && s[0] != '_') return 0; + for (; *s; s++) { + if (!isalnum((unsigned char)*s) && *s != '_') return 0; + } + return 1; +} + +int main(int argc, char **argv) +{ + char name[64] = "game", path[1100], upper[64], dataPath[1100]; + const char *folder = NULL, *outFolder = NULL; + kon_json_t *system, *tilesets; + int ids[MAX_MAP_ID + 1], found = 0, highestMap = 0, highestSet = 0, a, id, k, n; + FILE *f; + + for (a = 1; a < argc; a++) { + if (!strcmp(argv[a], "-n") && a + 1 < argc) snprintf(name, sizeof name, "%s", argv[++a]); + else if (!folder) folder = argv[a]; + else if (!outFolder) outFolder = argv[a]; + } + if (!folder || !outFolder) { + fprintf(stderr, "usage: mzmap [-n name] <data folder> <output folder>\n"); + return 2; + } + if (!validName(name)) { + fprintf(stderr, "the name has to be usable in C: letters, digits and _\n"); + return 2; + } + if (!findData(dataPath, sizeof dataPath, folder)) return 1; + folder = dataPath; + memset(ids, 0, sizeof ids); + + for (id = 1; id <= MAX_MAP_ID; id++) { + int r = writeMap(folder, outFolder, name, id); + + if (r < 0) return 1; + if (r > 0) { + ids[id] = 1; + found++; + highestMap = id; + } + } + if (!found) { + fprintf(stderr, "no maps found in %s\n", folder); + return 1; + } + + snprintf(path, sizeof path, "%s/%s_maps.c", outFolder, name); + f = fopen(path, "wb"); + if (!f) { + fprintf(stderr, "cannot write %s\n", path); + return 1; + } + fprintf(f, "/* written by mzmap, the maps, tilesets and start settings of the game */\n\n#include \"%s_maps.h\"\n\n#include <stddef.h>\n\n", name); + for (id = 1; id <= highestMap; id++) { + if (ids[id]) fprintf(f, "#include \"%s_map%03d.inc\"\n", name, id); + } + fputs("\n", f); + + tilesets = load(folder, "Tilesets.json"); + if (tilesets) highestSet = writeTilesets(f, name, tilesets); + + fprintf(f, "const kon_rmMap_t *const %s_maps[%d] = {\n\tNULL,\n", name, highestMap + 1); + for (id = 1; id <= highestMap; id++) { + if (ids[id]) fprintf(f, "\t&%s_m%d,\n", name, id); + else fputs("\tNULL,\n", f); + } + fputs("};\n\n", f); + + fprintf(f, "const kon_rmTileset_t *const %s_tilesets[%d] = {\n\tNULL,\n", name, highestSet + 1); + for (id = 1; id <= highestSet; id++) { + int there = 0; + + for (k = 1; tilesets && k < kon_jsonCount(tilesets); k++) { + if (number(kon_jsonGet(kon_jsonAt(tilesets, k), "id"), 0, 100000, k) == id && kon_jsonAt(tilesets, k)->type == KON_JSON_OBJECT) there = 1; + } + if (there) fprintf(f, "\t&%s_tileset%d,\n", name, id); + else fputs("\tNULL,\n", f); + } + fputs("};\n\n", f); + kon_jsonFree(tilesets); + + system = load(folder, "System.json"); + if (system) { + const kon_json_t *party = kon_jsonGet(system, "partyMembers"), *tone = kon_jsonGet(system, "windowTone"); + + n = kon_jsonCount(party); + if (n > 0) { + fprintf(f, "static const int %s_party[] = {", name); + for (k = 0; k < n; k++) fprintf(f, "%s%d", k ? ", " : "", number(kon_jsonAt(party, k), 0, 100000, 0)); + fputs("};\n", f); + } + fprintf(f, "const kon_rmSystem_t %s_system = {\n\t", name); + cstring(f, text(kon_jsonGet(system, "gameTitle"))); + fprintf(f, ",\n\t%d, %d, %d,\n\t", number(kon_jsonGet(system, "startMapId"), 0, MAX_MAP_ID, 0), number(kon_jsonGet(system, "startX"), 0, MAX_SIDE, 0), number(kon_jsonGet(system, "startY"), 0, MAX_SIDE, 0)); + if (n > 0) fprintf(f, "%s_party, %d,\n\t", name, n); + else fputs("NULL, 0,\n\t", f); + fprintf(f, "%d, %d, %d, %d, {%d, %d, %d}\n};\n", kon_jsonCount(kon_jsonGet(system, "switches")) - 1 > 0 ? kon_jsonCount(kon_jsonGet(system, "switches")) - 1 : 0, kon_jsonCount(kon_jsonGet(system, "variables")) - 1 > 0 ? kon_jsonCount(kon_jsonGet(system, "variables")) - 1 : 0, flag(kon_jsonGet(system, "optFollowers")), flag(kon_jsonGet(system, "optTransparent")), number(kon_jsonAt(tone, 0), -255, 255, 0), number(kon_jsonAt(tone, 1), -255, 255, 0), number(kon_jsonAt(tone, 2), -255, 255, 0)); + kon_jsonFree(system); + } else { + fprintf(f, "const kon_rmSystem_t %s_system = {\"\", 0, 0, 0, NULL, 0, 0, 0, 0, 0, {0, 0, 0}};\n", name); + } + if (ferror(f) || fclose(f) != 0) { + fprintf(stderr, "cannot write %s\n", path); + return 1; + } + + for (k = 0; name[k]; k++) upper[k] = (char)toupper((unsigned char)name[k]); + upper[k] = '\0'; + snprintf(path, sizeof path, "%s/%s_maps.h", outFolder, name); + f = fopen(path, "wb"); + if (!f) { + fprintf(stderr, "cannot write %s\n", path); + return 1; + } + fprintf(f, "/* written by mzmap */\n\n#ifndef %s_MAPS_H\n#define %s_MAPS_H\n\n#include \"konrmmap.h\"\n\n", upper, upper); + fprintf(f, "#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n"); + fprintf(f, "#define %s_MAP_IDS %d\n#define %s_TILESET_IDS %d\n\n", upper, highestMap + 1, upper, highestSet + 1); + fprintf(f, "/* index by the id the game uses, NULL when there is none */\nextern const kon_rmMap_t *const %s_maps[%d];\nextern const kon_rmTileset_t *const %s_tilesets[%d];\nextern const kon_rmSystem_t %s_system;\n\n", name, highestMap + 1, name, highestSet + 1, name); + fprintf(f, "#ifdef __cplusplus\n}\n#endif\n#endif\n"); + if (ferror(f) || fclose(f) != 0) { + fprintf(stderr, "cannot write %s\n", path); + return 1; + } + + printf("%d maps, %d events, %d pages, %d tiles\n", mapCount, eventCount, pageCount, tileTotal); + return 0; +} diff --git a/tools/mzscript.c b/tools/mzscript.c index 077efb2..38b2f6d 100644 --- a/tools/mzscript.c +++ b/tools/mzscript.c @@ -725,6 +725,27 @@ static void convert(context_t *c, const kon_json_t *list) /*** files ***/ +/* a game folder works too, the data is in data, or in www/data for MV */ +static int findData(char *out, size_t size, const char *folder) +{ + static const char *const where[] = {"", "/data", "/www/data"}; + char path[1100]; + FILE *f; + int i; + + for (i = 0; i < 3; i++) { + snprintf(path, sizeof path, "%s%s/System.json", folder, where[i]); + f = fopen(path, "rb"); + if (f) { + fclose(f); + snprintf(out, size, "%s%s", folder, where[i]); + return 1; + } + } + fprintf(stderr, "no System.json in %s, %s/data or %s/www/data\n", folder, folder, folder); + return 0; +} + static kon_json_t *load(const char *folder, const char *name) { char path[1024], error[120]; @@ -788,7 +809,7 @@ int main(int argc, char **argv) buf_t out; context_t c; kon_json_t *system, *json; - char scope[40], name[64] = "game", prefix[1024], error[200]; + char scope[40], name[64] = "game", prefix[1024], error[200], dataPath[1100]; const char *folder = NULL, *outFolder = NULL; int id, k, p, a, maxCommon = 0, entries = 0, split = 0, text = 0; konsc_result_t result; @@ -804,6 +825,8 @@ int main(int argc, char **argv) fprintf(stderr, "usage: mzscript [-n name] [-split rows] [-text] <data folder> <output folder>\n"); return 2; } + if (!findData(dataPath, sizeof dataPath, folder)) return 1; + folder = dataPath; snprintf(prefix, sizeof prefix, "%s/%s", outFolder, name); memset(&out, 0, sizeof out); diff --git a/tools/mzsurvey.c b/tools/mzsurvey.c index 61253a6..92995f4 100644 --- a/tools/mzsurvey.c +++ b/tools/mzsurvey.c @@ -380,21 +380,43 @@ static void plugins(const char *path) free(text); } +/* a game folder works too, the data is in data, or in www/data for MV */ +static int findData(char *out, size_t size, const char *folder) +{ + static const char *const where[] = {"", "/data", "/www/data"}; + char path[1100]; + FILE *f; + int i; + + for (i = 0; i < 3; i++) { + snprintf(path, sizeof path, "%s%s/System.json", folder, where[i]); + f = fopen(path, "rb"); + if (f) { + fclose(f); + snprintf(out, size, "%s%s", folder, where[i]); + return 1; + } + } + fprintf(stderr, "no System.json in %s, %s/data or %s/www/data\n", folder, folder, folder); + return 0; +} + int main(int argc, char **argv) { - char path[1024]; + char path[1024], dataPath[1000]; if (argc < 2) { fprintf(stderr, "usage: mzsurvey <data folder> [plugins.js]\n"); return 2; } - if (survey(argv[1])) return 1; + if (!findData(dataPath, sizeof dataPath, argv[1])) return 1; + if (survey(dataPath)) return 1; commandReport(); show(&pluginCommands, "plugin commands", 40); show(&scriptCalls, "script calls", 25); show(¬eTags, "note tags", 40); show(&tilesets, "tilesets used by maps", 20); - snprintf(path, sizeof path, "%s/../js/plugins.js", argv[1]); + snprintf(path, sizeof path, "%s/../js/plugins.js", dataPath); plugins(argc > 2 ? argv[2] : path); return 0; } |
