summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKonAki <konaki@anokonaki.org>2026-10-15 05:40:42 +0800
committerKonAki <konaki@anokonaki.org>2026-10-15 05:40:42 +0800
commit79957363275663e82900160b5a08aa56fc21086c (patch)
tree1cf23e5497a8c82ff69c45c6bcefd69be0066434
parent60698e3006c88bc6b9eb4a851e21197c39e7a12d (diff)
find the data folder from the game folder in the converters
-rw-r--r--tools/mzmap.c515
-rw-r--r--tools/mzscript.c25
-rw-r--r--tools/mzsurvey.c28
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(&noteTags, "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;
}