// genmaps.js — 生成《崩坏童话:蜜糖村》全部 10 张 Tiled 地图 (.tmx) // 用法: /Applications/Tiled.app/Contents/MacOS/Tiled -e tools/tiled/genmaps.js // 说明: -e 模式无编辑器,tiled.open/TileMap 绘制 API 不可用,故用 TextFile 直接写 .tmx XML。 // 导出: Tiled --export-map --embed-tilesets in.tmx out.json (必须 --embed-tilesets,JSON 才有 image 字段) // // 约定(与 CONTRACT.md §3 一致): // - 固定三层:ground(瓦片层)/ obstacles(瓦片层,图层属性 collides=true)/ objects(点对象层) // - 瓦片 gid = CONTRACT §2 瓦片 id + 1;obstacles 中空格 = gid 0 // - 点对象坐标 = 所在瓦片中心像素 (tx*16+8, ty*16+8) // - door 属性 target=目标地图 key, spawn=目标地图中的 spawn id(= "from_"+本图 key),双向成对 var OUT = '/Users/leidianyayi/Documents/GitHub/ModelTest20260714/Kimi-K3/public/assets/maps/'; // ---- 瓦片 gid 表(id+1)---- var G = { grass:1, flowerA:2, flowerB:3, deepGrass:4, dirt:5, stone:6, stoneAlt:7, brick:8, waterA:9, waterB:10, shoreN:11, shoreS:12, shoreW:13, shoreE:14, bedPink:15, bedYellow:16, berry:17, berryEmpty:18, treeTL:19, treeTR:20, treeBL:21, treeBR:22, bush:23, stump:24, rock:25, sign:26, fenceH:27, fenceV:28, lamp:29, ribbonR:30, ribbonY:31, ribbonB:32, creamWall:33, creamWallWin:34, woodWall:35, roofOL:36, roofOM:37, roofOR:38, doorT:39, doorTop:40, window:41, chimney:42, wellTL:43, wellTR:44, wellBL:45, wellBR:46, mailbox:47, board:48, floorA:49, floorB:50, wallIn:51, wallInWin:52, bedTL:53, bedTR:54, bedBL:55, bedBR:56, counterL:57, counterR:58, oven:59, shelfE:60, shelfF:61, table:62, chair:63, rug:64, calendar:65, recipe:66, fileP:67, picTL:68, picTR:69, picBL:70, picBR:71, benchL:72, benchR:73, stool:74, cabinet:75, fridge:76, sink:77, plant:78, barrel:79, crate:80, fogA:81, fogB:82, fogC:83, wFloor:84, wWall:85, wPanel:86, wDoor:87, wBedTL:88, wBedTR:89, wBedBL:90, wBedBR:91, wCab:92, wMon:93, wCur:94, wFloor2:95, wLamp:96, ladder:97, bridgeH:98, bridgeV:99, mushroom:100, flR:101, flY:102, flB:103, honey:104, bread:105, letter:106, book:107, candle:108, basket:109, bucket:110, broom:111, cake:112, roofRL:113, roofRM:114, roofRR:115, roofBL:116, roofBM:117, roofBR:118, pinkWall:119, pinkWallWin:120, stoneWall:121, stoneWallWin:122, awning:123, clock:124, flag:125, garC:126, garM:127, empty:128 }; // ---- 基础工具(ES5)---- function grid(w, h, v) { var a = []; for (var y = 0; y < h; y++) { var r = []; for (var x = 0; x < w; x++) r.push(v); a.push(r); } return a; } function newMap(w, h) { return { w: w, h: h, ground: grid(w, h, 0), obs: grid(w, h, 0), objs: [] }; } function fill(l, x, y, w, h, g) { for (var j = y; j < y + h; j++) for (var i = x; i < x + w; i++) l[j][i] = g; } function put(l, x, y, g) { l[y][x] = g; } // 确定性散点随机数(固定种子,结果可复现) function rnd(x, y, s) { var n = Math.sin(x * 127.1 + y * 311.7 + s * 74.7) * 43758.5453; return n - Math.floor(n); } function obj(m, name, tx, ty, props) { m.objs.push({ name: name, x: tx * 16 + 8, y: ty * 16 + 8, props: props }); } function spawn(m, tx, ty, id) { obj(m, 'spawn', tx, ty, [['id', id]]); } function door(m, tx, ty, target, sp) { obj(m, 'door', tx, ty, [['target', target], ['spawn', sp]]); } function npc(m, tx, ty, id) { obj(m, 'npc', tx, ty, [['id', id]]); } function inter(m, tx, ty, id) { obj(m, 'interact', tx, ty, [['id', id]]); } function tree2x2(m, x, y) { put(m.obs, x, y, G.treeTL); put(m.obs, x + 1, y, G.treeTR); put(m.obs, x, y + 1, G.treeBL); put(m.obs, x + 1, y + 1, G.treeBR); } // 草地散点装饰(ground 层,无碰撞) function scatter(m, seed, d) { for (var y = 0; y < m.h; y++) { for (var x = 0; x < m.w; x++) { var r = rnd(x, y, seed); var g = 0; if (r < d[0]) g = G.flowerA; else if (r < d[1]) g = G.flowerB; else if (r < d[2]) g = G.deepGrass; else if (r < d[3]) g = [G.flR, G.flY, G.flB][(x + y) % 3]; if (g) m.ground[y][x] = g; } } } // 室外房屋:5 宽 × 4 高,朝南单门,整体进 obstacles function houseS(m, x, y, roofL, roofM, roofR, chimney) { for (var i = 0; i < 5; i++) { var t = (i === 0) ? roofL : (i === 4 ? roofR : roofM); put(m.obs, x + i, y, t); put(m.obs, x + i, y + 1, t); } if (chimney) put(m.obs, x + 1, y, G.chimney); put(m.obs, x, y + 2, G.creamWall); put(m.obs, x + 1, y + 2, G.creamWallWin); put(m.obs, x + 2, y + 2, G.doorTop); put(m.obs, x + 3, y + 2, G.creamWallWin); put(m.obs, x + 4, y + 2, G.creamWall); put(m.obs, x, y + 3, G.creamWall); put(m.obs, x + 1, y + 3, G.creamWall); put(m.obs, x + 2, y + 3, G.doorT); put(m.obs, x + 3, y + 3, G.creamWall); put(m.obs, x + 4, y + 3, G.creamWall); } // 室内外壳:木地板满铺(ground),墙围边(obstacles),底边留门(门瓦片在 ground) function indoorShell(m, wins, doorX) { for (var y = 0; y < m.h; y++) for (var x = 0; x < m.w; x++) m.ground[y][x] = ((x + y) % 2 === 0) ? G.floorA : G.floorB; m.ground[m.h - 1][doorX] = G.doorT; for (var x2 = 0; x2 < m.w; x2++) { m.obs[0][x2] = G.wallIn; if (x2 !== doorX) m.obs[m.h - 1][x2] = G.wallIn; } for (var i = 0; i < wins.length; i++) m.obs[0][wins[i]] = G.wallInWin; for (var y2 = 1; y2 < m.h - 1; y2++) { m.obs[y2][0] = G.wallIn; m.obs[y2][m.w - 1] = G.wallIn; } } // ================= 1. house 12×8 小满小屋 ================= function buildHouse() { var m = newMap(12, 8); indoorShell(m, [3, 8], 5); // 床(睡觉过日)+ 床头日历(C1) put(m.obs, 1, 1, G.bedTL); put(m.obs, 2, 1, G.bedTR); put(m.obs, 1, 2, G.bedBL); put(m.obs, 2, 2, G.bedBR); put(m.obs, 3, 1, G.calendar); // 桌椅 + 盆栽 + 地毯 put(m.obs, 8, 4, G.table); put(m.obs, 7, 4, G.chair); put(m.obs, 9, 4, G.chair); put(m.obs, 10, 1, G.plant); put(m.ground, 5, 3, G.rug); put(m.ground, 6, 3, G.rug); put(m.ground, 5, 4, G.rug); put(m.ground, 6, 4, G.rug); spawn(m, 3, 3, 'default'); spawn(m, 5, 5, 'from_plaza'); door(m, 5, 6, 'plaza', 'from_house'); inter(m, 1, 3, 'bed'); inter(m, 3, 2, 'calendar'); return m; } // ================= 2. plaza 30×20 村广场(枢纽) ================= function buildPlaza() { var m = newMap(30, 20); fill(m.ground, 0, 0, 30, 20, G.grass); scatter(m, 7, [0.05, 0.10, 0.15, 0.18]); // 石路:南北 x=14/15,东西 y=9/10,通往四座房屋的小路 var y, x; for (y = 0; y < 20; y++) { put(m.ground, 14, y, (y % 3 === 0) ? G.stoneAlt : G.stone); put(m.ground, 15, y, (y % 3 === 0) ? G.stoneAlt : G.stone); } for (x = 0; x < 30; x++) { put(m.ground, x, 9, (x % 3 === 0) ? G.stoneAlt : G.stone); put(m.ground, x, 10, (x % 3 === 0) ? G.stoneAlt : G.stone); } var stubs = [4, 11, 18, 25]; for (var s = 0; s < stubs.length; s++) for (y = 5; y <= 9; y++) put(m.ground, stubs[s], y, G.stone); // 中央广场砖(庆典场地核心) fill(m.ground, 11, 8, 8, 5, G.brick); // 庆典彩带(广场四角,装饰无碰撞;透明瓦片须放 obstacles 层,ground 层会露黑底) put(m.obs, 11, 7, G.ribbonR); put(m.obs, 18, 7, G.ribbonY); put(m.obs, 11, 13, G.ribbonB); put(m.obs, 18, 13, G.ribbonR); // 四周房屋:小屋/杂货店=橙屋顶,面包房/诊所=红屋顶 houseS(m, 2, 1, G.roofOL, G.roofOM, G.roofOR, true); // house 门 x=4 houseS(m, 9, 1, G.roofRL, G.roofRM, G.roofRR, true); // bakery 门 x=11 houseS(m, 16, 1, G.roofOL, G.roofOM, G.roofOR, true); // shop 门 x=18 houseS(m, 23, 1, G.roofRL, G.roofRM, G.roofRR, false); // clinic 门 x=25 // 公告板 + 三个花坛 + 双子鸟大树 put(m.obs, 14, 8, G.board); put(m.obs, 10, 8, G.bedPink); put(m.obs, 19, 8, G.bedYellow); put(m.obs, 14, 13, G.bedPink); tree2x2(m, 12, 14); // 村口邮筒(大宝)+ 路灯 + 装饰树/灌木 put(m.obs, 2, 8, G.mailbox); put(m.obs, 10, 6, G.lamp); put(m.obs, 19, 6, G.lamp); tree2x2(m, 1, 6); tree2x2(m, 27, 14); tree2x2(m, 1, 16); put(m.obs, 8, 16, G.bush); put(m.obs, 21, 17, G.bush); put(m.obs, 16, 15, G.bush); // 地图边缘装饰(留出 4 个路口) function skip(x2, y2) { return (y2 === 0 && (x2 === 14 || x2 === 15)) || (y2 === 19 && (x2 === 14 || x2 === 15)) || (x2 === 0 && (y2 === 9 || y2 === 10)) || (x2 === 29 && (y2 === 9 || y2 === 10)); } function edge(x2, y2) { var r = rnd(x2, y2, 9); put(m.obs, x2, y2, r < 0.5 ? G.bush : (r < 0.75 ? G.rock : G.stump)); } for (x = 0; x < 30; x++) { if (!skip(x, 0)) edge(x, 0); if (!skip(x, 19)) edge(x, 19); } for (y = 1; y < 19; y++) { if (!skip(0, y)) edge(0, y); if (!skip(29, y)) edge(29, y); } // 对象 spawn(m, 14, 11, 'default'); spawn(m, 4, 7, 'from_house'); // 落点距门 24px,防回弹 spawn(m, 11, 7, 'from_bakery'); spawn(m, 18, 7, 'from_shop'); spawn(m, 25, 7, 'from_clinic'); spawn(m, 1, 10, 'from_lake'); spawn(m, 28, 10, 'from_field'); spawn(m, 14, 2, 'from_well'); // 落点距门 24px,防回弹 spawn(m, 15, 18, 'from_fog'); door(m, 4, 5, 'house', 'from_plaza'); door(m, 11, 5, 'bakery', 'from_plaza'); door(m, 18, 5, 'shop', 'from_plaza'); door(m, 25, 5, 'clinic', 'from_plaza'); door(m, 0, 9, 'lake', 'from_plaza'); door(m, 29, 10, 'field', 'from_plaza'); door(m, 14, 0, 'well', 'from_plaza'); door(m, 15, 19, 'fog', 'from_plaza'); npc(m, 15, 8, 'afu'); // 公告板旁 npc(m, 12, 14, 'bird'); // 双子鸟,树上 npc(m, 7, 12, 'squirrel'); npc(m, 22, 14, 'fox'); npc(m, 3, 8, 'dabao'); // 村口邮筒旁(PRD §4) inter(m, 14, 9, 'noticeboard'); inter(m, 10, 9, 'flowerbed_1'); inter(m, 19, 9, 'flowerbed_2'); inter(m, 14, 14, 'flowerbed_3'); return m; } // ================= 3. bakery 15×10 面包房 ================= function buildBakery() { var m = newMap(15, 10); indoorShell(m, [3, 7, 11], 7); fill(m.ground, 5, 5, 3, 2, G.rug); // 两段柜台 + 烤炉(C2 配方纸在桌上) put(m.obs, 4, 3, G.counterL); put(m.obs, 5, 3, G.counterR); put(m.obs, 8, 3, G.counterL); put(m.obs, 9, 3, G.counterR); put(m.obs, 12, 1, G.oven); put(m.obs, 10, 6, G.table); put(m.obs, 11, 6, G.recipe); put(m.obs, 13, 8, G.barrel); put(m.obs, 1, 8, G.plant); spawn(m, 7, 6, 'default'); spawn(m, 7, 7, 'from_plaza'); door(m, 7, 8, 'plaza', 'from_bakery'); npc(m, 5, 2, 'yuanyuan'); // 柜台后 inter(m, 4, 4, 'counter_bread'); inter(m, 11, 7, 'recipe_paper'); return m; } // ================= 4. shop 15×10 杂货店 ================= function buildShop() { var m = newMap(15, 10); indoorShell(m, [3, 7, 11], 7); fill(m.ground, 6, 6, 3, 2, G.rug); // 上排 9 格满货架(C5:同一商品重复 9 格)+ 下排空满混排 var x; for (x = 3; x <= 11; x++) put(m.obs, x, 1, G.shelfF); for (x = 3; x <= 11; x++) put(m.obs, x, 4, (x % 3 === 0) ? G.shelfE : G.shelfF); put(m.obs, 1, 7, G.crate); put(m.obs, 1, 8, G.barrel); put(m.obs, 13, 1, G.plant); spawn(m, 7, 6, 'default'); spawn(m, 7, 7, 'from_plaza'); door(m, 7, 8, 'plaza', 'from_shop'); npc(m, 2, 5, 'mimi'); npc(m, 11, 7, 'hedgehog'); inter(m, 7, 2, 'shelf_count'); return m; } // ================= 5. clinic 12×8 诊所 ================= function buildClinic() { var m = newMap(12, 8); indoorShell(m, [3, 8], 5); // 芙医生的桌 + 桌上文件(C8) put(m.obs, 8, 2, G.table); put(m.obs, 9, 2, G.fileP); put(m.obs, 9, 3, G.chair); put(m.obs, 1, 1, G.cabinet); put(m.obs, 10, 6, G.plant); spawn(m, 6, 5, 'default'); spawn(m, 5, 5, 'from_plaza'); door(m, 5, 6, 'plaza', 'from_clinic'); npc(m, 8, 1, 'fuyisheng'); // 桌后 inter(m, 8, 3, 'doctor_desk'); return m; } // ================= 6. lake 24×16 湖畔 ================= function buildLake() { var m = newMap(24, 16); fill(m.ground, 0, 0, 24, 16, G.grass); scatter(m, 21, [0.06, 0.11, 0.15, 0.18]); var x, y; // 石路:东门(23,10)通向长椅与野餐区 for (x = 3; x <= 23; x++) put(m.ground, x, 10, (x % 3 === 0) ? G.stoneAlt : G.stone); // 野餐布(T7,走上去触发,放 ground 可行走) put(m.ground, 15, 10, G.picTL); put(m.ground, 16, 10, G.picTR); put(m.ground, 15, 11, G.picBL); put(m.ground, 16, 11, G.picBR); put(m.ground, 3, 12, G.mushroom); // 湖水:北半边大片湖,水岸瓦片围边(全部进 obstacles) for (y = 0; y <= 5; y++) for (x = 2; x <= 21; x++) put(m.obs, x, y, ((x + y) % 2 === 0) ? G.waterA : G.waterB); for (x = 1; x <= 22; x++) put(m.obs, x, 6, G.shoreS); for (y = 0; y <= 5; y++) { put(m.obs, 1, y, G.shoreW); put(m.obs, 22, y, G.shoreE); } // 长椅(龟爷爷)+ 树木花草装饰 put(m.obs, 10, 8, G.benchL); put(m.obs, 11, 8, G.benchR); tree2x2(m, 1, 13); tree2x2(m, 20, 12); put(m.obs, 8, 14, G.bush); put(m.obs, 12, 13, G.bush); put(m.obs, 5, 9, G.rock); put(m.obs, 14, 14, G.stump); spawn(m, 21, 11, 'default'); spawn(m, 22, 10, 'from_plaza'); door(m, 23, 10, 'plaza', 'from_lake'); npc(m, 12, 8, 'guiyeye'); // 长椅旁 npc(m, 6, 12, 'pig'); inter(m, 16, 11, 'picnic_mat'); return m; } // ================= 7. field 20×14 花田 ================= function buildField() { var m = newMap(20, 14); fill(m.ground, 0, 0, 20, 14, G.grass); scatter(m, 33, [0.10, 0.18, 0.24, 0.32]); var x, y; // 土路横穿(西门进出) for (x = 0; x <= 19; x++) put(m.ground, x, 7, G.dirt); // 浇花点花丛(T2/T12 用,ground 装饰) put(m.ground, 15, 9, G.flR); put(m.ground, 16, 9, G.flY); put(m.ground, 17, 9, G.flB); put(m.ground, 15, 10, G.flY); put(m.ground, 16, 10, G.flR); put(m.ground, 17, 10, G.flB); // 栅栏围边,西门留口 for (x = 0; x <= 19; x++) { put(m.obs, x, 0, G.fenceH); put(m.obs, x, 13, G.fenceH); } for (y = 1; y <= 12; y++) { if (y !== 7) put(m.obs, 0, y, G.fenceV); put(m.obs, 19, y, G.fenceV); } // 5 丛莓果(T6) var berries = [[4, 4], [9, 4], [14, 4], [6, 9], [12, 9]]; for (var b = 0; b < berries.length; b++) put(m.obs, berries[b][0], berries[b][1], G.berry); // 树木装饰 tree2x2(m, 16, 1); put(m.obs, 2, 11, G.bush); put(m.obs, 10, 11, G.bush); put(m.obs, 2, 2, G.rock); spawn(m, 2, 7, 'default'); spawn(m, 1, 7, 'from_plaza'); door(m, 0, 7, 'plaza', 'from_field'); npc(m, 10, 7, 'chick'); inter(m, 4, 5, 'berry_1'); inter(m, 9, 5, 'berry_2'); inter(m, 14, 5, 'berry_3'); inter(m, 6, 10, 'berry_4'); inter(m, 12, 10, 'berry_5'); inter(m, 16, 10, 'water_point'); return m; } // ================= 8. well 14×10 古井空地 ================= function buildWell() { var m = newMap(14, 10); fill(m.ground, 0, 0, 14, 10, G.grass); scatter(m, 45, [0.07, 0.13, 0.17, 0.19]); var y; // 土场 + 南门土路 fill(m.ground, 5, 3, 4, 4, G.dirt); for (y = 7; y <= 9; y++) { put(m.ground, 6, y, G.dirt); put(m.ground, 7, y, G.dirt); } put(m.ground, 3, 4, G.mushroom); put(m.ground, 10, 6, G.mushroom); // 中央古井(C7) put(m.obs, 6, 4, G.wellTL); put(m.obs, 7, 4, G.wellTR); put(m.obs, 6, 5, G.wellBL); put(m.obs, 7, 5, G.wellBR); // 四周树木 tree2x2(m, 1, 1); tree2x2(m, 11, 1); tree2x2(m, 1, 7); tree2x2(m, 11, 7); put(m.obs, 4, 2, G.bush); put(m.obs, 9, 2, G.bush); put(m.obs, 4, 8, G.bush); put(m.obs, 9, 8, G.bush); put(m.obs, 4, 5, G.rock); put(m.obs, 9, 5, G.rock); spawn(m, 6, 8, 'default'); spawn(m, 7, 8, 'from_plaza'); door(m, 7, 9, 'plaza', 'from_well'); inter(m, 6, 6, 'ancient_well'); return m; } // ================= 9. fog 20×8 雾墙边界 ================= function buildFog() { var m = newMap(20, 8); fill(m.ground, 0, 0, 20, 8, G.grass); scatter(m, 57, [0.05, 0.09, 0.20, 0.20]); var x, y; // 雾前深草带 + 北门土路 for (x = 0; x <= 19; x++) put(m.ground, x, 4, G.deepGrass); for (y = 0; y <= 4; y++) { put(m.ground, 9, y, G.dirt); put(m.ground, 10, y, G.dirt); } // 远端(南侧)雾墙铺满,进 obstacles(E3 入口) for (y = 5; y <= 7; y++) for (x = 0; x <= 19; x++) put(m.obs, x, y, [G.fogA, G.fogB, G.fogC][(x + y) % 3]); // 两侧树木 tree2x2(m, 1, 1); tree2x2(m, 17, 1); put(m.obs, 4, 3, G.bush); put(m.obs, 15, 3, G.bush); put(m.obs, 0, 3, G.bush); put(m.obs, 19, 3, G.bush); put(m.obs, 6, 2, G.rock); spawn(m, 10, 2, 'default'); spawn(m, 9, 2, 'from_plaza'); // 落点距门 >24px,防回弹 door(m, 10, 0, 'plaza', 'from_fog'); inter(m, 10, 4, 'fog_wall'); // 雾前可达格 return m; } // ================= 10. white 20×14 白色层(走廊 + 病房) ================= function buildWhite() { var m = newMap(20, 14); var x, y; // 默认白墙铺底;上半 20×6 走廊 + 左下 10×8 病房刷白地板 fill(m.ground, 0, 0, 20, 14, G.wWall); for (y = 1; y <= 5; y++) for (x = 1; x <= 18; x++) m.ground[y][x] = (x % 4 === 0 && y % 2 === 0) ? G.wFloor2 : G.wFloor; for (y = 7; y <= 12; y++) for (x = 1; x <= 8; x++) m.ground[y][x] = ((x + y) % 3 === 0) ? G.wFloor2 : G.wFloor; put(m.ground, 4, 6, G.wFloor); put(m.ground, 5, 6, G.wFloor); // 走廊↔病房通道格 // 墙体(obstacles):北墙(含墙板/天花板灯)、东西墙、南墙、右下实心墙块、病房北/东墙 for (x = 0; x <= 19; x++) put(m.obs, x, 0, G.wWall); put(m.obs, 5, 0, G.wPanel); put(m.obs, 10, 0, G.wPanel); put(m.obs, 15, 0, G.wPanel); put(m.obs, 3, 0, G.wLamp); put(m.obs, 8, 0, G.wLamp); put(m.obs, 13, 0, G.wLamp); put(m.obs, 18, 0, G.wLamp); for (y = 1; y <= 13; y++) { put(m.obs, 0, y, G.wWall); put(m.obs, 19, y, G.wWall); } for (x = 1; x <= 9; x++) put(m.obs, x, 13, G.wWall); fill(m.obs, 10, 6, 10, 8, G.wWall); // 右下 10×8 实心(房间之外) for (x = 1; x <= 9; x++) if (x !== 4 && x !== 5) put(m.obs, x, 6, G.wWall); for (y = 6; y <= 13; y++) put(m.obs, 9, y, G.wWall); put(m.obs, 9, 8, G.wCur); put(m.obs, 9, 9, G.wCur); // 白窗帘挂在东墙上 // 病房家具:白床 + 白监护仪 + 白柜 put(m.obs, 2, 8, G.wBedTL); put(m.obs, 3, 8, G.wBedTR); put(m.obs, 2, 9, G.wBedBL); put(m.obs, 3, 9, G.wBedBR); put(m.obs, 4, 8, G.wMon); put(m.obs, 7, 12, G.wCab); spawn(m, 17, 3, 'default'); // 走廊一端 return m; } // ================= 序列化 ================= function csv(l, w, h) { var s = ''; for (var y = 0; y < h; y++) { var row = ''; for (var x = 0; x < w; x++) { row += l[y][x]; if (x < w - 1) row += ','; } s += row; if (y < h - 1) s += ',\n'; } return s; } function tmx(m) { var s = '\n'; s += '\n'; s += ' \n'; s += ' \n'; s += ' \n' + csv(m.ground, m.w, m.h) + '\n \n \n'; s += ' \n'; s += ' \n \n \n'; s += ' \n' + csv(m.obs, m.w, m.h) + '\n \n \n'; s += ' \n'; for (var i = 0; i < m.objs.length; i++) { var o = m.objs[i]; s += ' \n'; s += ' \n'; for (var p = 0; p < o.props.length; p++) s += ' \n'; s += ' \n \n \n'; } s += ' \n\n'; return s; } function writeMap(name, m) { var f = new TextFile(OUT + name + '.tmx', TextFile.WriteOnly); f.write(tmx(m)); f.commit(); tiled.log('wrote ' + name + '.tmx (' + m.w + 'x' + m.h + ', ' + m.objs.length + ' objects)'); } writeMap('house', buildHouse()); writeMap('plaza', buildPlaza()); writeMap('bakery', buildBakery()); writeMap('shop', buildShop()); writeMap('clinic', buildClinic()); writeMap('lake', buildLake()); writeMap('field', buildField()); writeMap('well', buildWell()); writeMap('fog', buildFog()); writeMap('white', buildWhite()); tiled.log('all 10 maps done');