mirror of
https://github.com/lscharen/iigs-game-engine.git
synced 2024-09-27 05:54:24 +00:00
Improve export of Tiled projects. Does level data and tileset export in one command now
This commit is contained in:
parent
191094e7e6
commit
44ee61a3f3
44
tools/mksprite.js
Normal file
44
tools/mksprite.js
Normal file
@ -0,0 +1,44 @@
|
||||
/**
|
||||
* Basic sprite compiler
|
||||
*
|
||||
* GTE has some specific needs that makes existing tools (like MrSprite) inappropriate. GTE
|
||||
* sprites need to reference some internal data structures and have slightly difference code
|
||||
* in order to handle clipping to the playfield bounds.
|
||||
*
|
||||
* The core sprite drawing approach is the same (set up Bank 1 direct page and stack), but
|
||||
* the setup and dispatch are a bit different.
|
||||
*
|
||||
* A Note on Clipping
|
||||
*
|
||||
* GTE supports two clipping buffers for sprites to use. The first one is a static buffer
|
||||
* that is aligned with the playfield and is used to clip the sprite when crossing the
|
||||
* left and right boundaries, but since it's a static image, mask data can be put anywhere
|
||||
* that the sprites should not show through, so irregular borders and sprite punch-outs
|
||||
* on the playfield are possible.
|
||||
*
|
||||
* The second buffer matches the current tiles in the playfield and can be used as a
|
||||
* dynamic mask of the playfield. Since the sprite code itself must use this data,
|
||||
* different variations of the same sprite can be created to stand in "front" and "behind"
|
||||
* different screen elements.
|
||||
*
|
||||
* The sprite requires the X and Y registers for this. The most general code that
|
||||
* should be used for each sprite word is this:
|
||||
*
|
||||
* Example: DATA = $5670, MASK = $000F, screen_mask = $FF00, field_mask = $F0FF
|
||||
* lda DP ; A = $1234
|
||||
* eor #DATA ; A = $4444
|
||||
* and #~MASK ; A = $4440
|
||||
* and screen_mask,y ; A = $4400
|
||||
* and >field_mask,x ; A = $4000
|
||||
* eor DP ; A = $5234 <-- Only the high nibble is set to the sprite data
|
||||
* sta DP
|
||||
*
|
||||
* It is not *required* that sprites use this approach, any compiled sprites code can be used,
|
||||
* so if a sprite does not need to be masked, than any of the fast sprite approaches can be
|
||||
* used.
|
||||
*
|
||||
* For clipping vertically, we pass in the starting and finishing lines in a register and
|
||||
* a sprite record is set up to allow the sprite to be entered in the middle and exited
|
||||
* before the last line of the sprite.
|
||||
*/
|
||||
|
@ -2,6 +2,7 @@ const fs = require('fs').promises;
|
||||
const PNG = require("pngjs").PNG;
|
||||
const process = require('process');
|
||||
const { Buffer } = require('buffer');
|
||||
const StringBuilder = require('string-builder');
|
||||
|
||||
// Starting color index
|
||||
let startIndex = 0;
|
||||
@ -17,7 +18,7 @@ main(process.argv.slice(2)).then(
|
||||
|
||||
function findColorIndex(png, pixel) {
|
||||
for (let i = 0; i < png.palette.length; i += 1) {
|
||||
const color = png.palette[i];
|
||||
const color = png.palette[i].slice(0, pixel.length); // Handle RGB or RGBA
|
||||
if (color.every((c, idx) => c === pixel[idx])) {
|
||||
return i + startIndex;
|
||||
}
|
||||
@ -104,15 +105,31 @@ function getArg(argv, arg, fn, defaultValue) {
|
||||
if (fn) {
|
||||
return fn(argv[i+1]);
|
||||
}
|
||||
return true; // REturn true if the argument was found
|
||||
return true; // Return true if the argument was found
|
||||
}
|
||||
}
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
async function main(argv) {
|
||||
const data = await fs.readFile(argv[0]);
|
||||
async function readPNG(filename) {
|
||||
const data = await fs.readFile(filename);
|
||||
const png = PNG.sync.read(data);
|
||||
|
||||
if (png.colorType !== 3) {
|
||||
throw new Error('PNG must be in palette color type');
|
||||
}
|
||||
|
||||
if (png.palette.length > 16) {
|
||||
throw new Error(`Too many colors. Must be 16 or less. Found ${png.palette.length}`);
|
||||
}
|
||||
|
||||
return png;
|
||||
}
|
||||
|
||||
async function main(argv) {
|
||||
try {
|
||||
const png = await readPNG(argv[0]);
|
||||
|
||||
startIndex = getArg(argv, '--start-index', x => parseInt(x, 10), 0);
|
||||
asTileData = getArg(argv, '--as-tile-data', null, 0);
|
||||
|
||||
@ -135,7 +152,7 @@ async function main(argv) {
|
||||
const hexCodes = png.palette.map(c => '$' + paletteToIIgs(c));
|
||||
console.log(';', hexCodes.join(','));
|
||||
|
||||
// Just convert a paletted PNG to IIgs memory format. We make sute that only a few widths
|
||||
// Just convert a paletted PNG to IIgs memory format. We make sure that only a few widths
|
||||
// are supported
|
||||
let buff = null;
|
||||
|
||||
@ -163,12 +180,171 @@ async function main(argv) {
|
||||
await writeBinayOutput(argv[1], buff);
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
console.log(`; ${e}`);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
function reverse(str) {
|
||||
return [...str].reverse().join(''); // use [...str] instead of split as it is unicode-aware.
|
||||
}
|
||||
|
||||
function toHex(h) {
|
||||
return h.toString(16).padStart(2, '0');
|
||||
}
|
||||
|
||||
function swap(hex) {
|
||||
const high = hex & 0xF0;
|
||||
const low = hex & 0x0F;
|
||||
|
||||
return (high >> 4) | (low << 4);
|
||||
}
|
||||
|
||||
function toMask(hex, transparentIndex) {
|
||||
if (transparentIndex === -1) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const indexHigh = (transparentIndex & 0xF) << 4;
|
||||
const indexLow = (transparentIndex & 0xF);
|
||||
let mask = 0;
|
||||
if ((hex & 0xF0) === indexHigh) {
|
||||
mask = mask | 0xF0;
|
||||
}
|
||||
if ((hex & 0x0F) === indexLow) {
|
||||
mask = mask | 0x0F;
|
||||
}
|
||||
return mask;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return all four 32 byte chunks of data for a single 8x8 tile
|
||||
*/
|
||||
function buildTile(buff, width, x, y, transparentIndex = -1) {
|
||||
const tile = {
|
||||
normal: {
|
||||
data: [],
|
||||
mask: []
|
||||
},
|
||||
flipped: {
|
||||
data: [],
|
||||
mask: []
|
||||
}
|
||||
};
|
||||
|
||||
const offset = y * width + x;
|
||||
for (dy = 0; dy < 8; dy += 1) {
|
||||
const hex0 = buff[offset + dy * width + 0];
|
||||
const hex1 = buff[offset + dy * width + 1];
|
||||
const hex2 = buff[offset + dy * width + 2];
|
||||
const hex3 = buff[offset + dy * width + 3];
|
||||
|
||||
const data = [hex0, hex1, hex2, hex3];
|
||||
const mask = data.map(h => toMask(h, transparentIndex));
|
||||
|
||||
tile.normal.data.push(data);
|
||||
tile.normal.mask.push(mask);
|
||||
}
|
||||
|
||||
for (dy = 0; dy < 8; dy += 1) {
|
||||
const hex0 = swap(buff[offset + dy * width + 0]);
|
||||
const hex1 = swap(buff[offset + dy * width + 1]);
|
||||
const hex2 = swap(buff[offset + dy * width + 2]);
|
||||
const hex3 = swap(buff[offset + dy * width + 3]);
|
||||
|
||||
const data = [hex3, hex2, hex1, hex0];
|
||||
const mask = data.map(h => toMask(h, transparentIndex));
|
||||
|
||||
tile.flipped.data.push(data);
|
||||
tile.flipped.mask.push(mask);
|
||||
}
|
||||
|
||||
return tile;
|
||||
}
|
||||
|
||||
function buildTiles(buff, width, transparentIndex = -1) {
|
||||
const tiles = [];
|
||||
|
||||
const MAX_TILES = 64;
|
||||
|
||||
let count = 0;
|
||||
for (let y = 0; ; y += 8) {
|
||||
for (let x = 0; x < width; x += 4, count += 1) {
|
||||
if (count >= MAX_TILES) {
|
||||
return tiles;
|
||||
}
|
||||
const tile = buildTile(buff, width, x, y, transparentIndex);
|
||||
tiles.push(tile);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function writeTileToStream(stream, data) {
|
||||
// Output the tile data
|
||||
for (const row of data) {
|
||||
const hex = row.map(d => toHex(d)).join('');
|
||||
stream.write(' hex ' + hex + '\n');
|
||||
}
|
||||
}
|
||||
|
||||
function writeTilesToStream(stream, tiles, label='tiledata') {
|
||||
stream.write(`${label} ENT\n`);
|
||||
stream.write('');
|
||||
stream.write('; Reserved space (tile 0 is special...)\n');
|
||||
stream.write(' ds 128\n');
|
||||
|
||||
const MAX_TILES = 511;
|
||||
let count = 0;
|
||||
for (const tile of tiles.slice(0, MAX_TILES)) {
|
||||
console.log(`Writing tile ${count + 1}`);
|
||||
stream.write(`; Tile ID ${count + 1}\n`);
|
||||
writeTileToStream(stream, tile.normal.data);
|
||||
writeTileToStream(stream, tile.normal.mask);
|
||||
writeTileToStream(stream, tile.flipped.data);
|
||||
writeTileToStream(stream, tile.flipped.mask);
|
||||
stream.write('');
|
||||
|
||||
count += 1;
|
||||
}
|
||||
}
|
||||
|
||||
function buildMerlinCodeForTile(data) {
|
||||
const sb = new StringBuilder();
|
||||
|
||||
// Output the tile data
|
||||
for (const row of data) {
|
||||
const hex = row.map(d => toHex(d)).join('');
|
||||
sb.appendLine(' hex ' + hex);
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
function buildMerlinCodeForTiles(tiles, label='tiledata') {
|
||||
const sb = new StringBuilder();
|
||||
sb.appendLine(`${label} ENT`);
|
||||
sb.appendLine();
|
||||
sb.appendLine('; Reserved space (tile 0 is special...)');
|
||||
sb.appendLine(' ds 128');
|
||||
|
||||
const MAX_TILES = 511;
|
||||
let count = 0;
|
||||
for (const tile of tiles.slice(0, MAX_TILES)) {
|
||||
console.log(`Writing tile ${count + 1}`);
|
||||
sb.appendLine(`; Tile ID ${count + 1}`);
|
||||
sb.append(buildMerlinCodeForTile(tile.normal.data));
|
||||
sb.append(buildMerlinCodeForTile(tile.normal.mask));
|
||||
sb.append(buildMerlinCodeForTile(tile.flipped.data));
|
||||
sb.append(buildMerlinCodeForTile(tile.flipped.mask));
|
||||
sb.appendLine();
|
||||
|
||||
count += 1;
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
function writeToTileDataSource(buff, width) {
|
||||
console.log('tiledata ENT');
|
||||
console.log();
|
||||
@ -186,47 +362,35 @@ function writeToTileDataSource(buff, width) {
|
||||
console.log('; Tile ID ' + (count + 1));
|
||||
console.log('; From image coordinates ' + (x * 2) + ', ' + y);
|
||||
|
||||
const tile = buildTile(buff, width, x, y, transparentIndex);
|
||||
|
||||
// Output the tile data
|
||||
const offset = y * width + x;
|
||||
for (dy = 0; dy < 8; dy += 1) {
|
||||
const hex0 = buff[offset + dy * width + 0].toString(16).padStart(2, '0');
|
||||
const hex1 = buff[offset + dy * width + 1].toString(16).padStart(2, '0');
|
||||
const hex2 = buff[offset + dy * width + 2].toString(16).padStart(2, '0');
|
||||
const hex3 = buff[offset + dy * width + 3].toString(16).padStart(2, '0');
|
||||
console.log(' hex ' + hex0 + hex1 + hex2 + hex3);
|
||||
for (const row of tile.normal.data) {
|
||||
const hex = row.map(d => toHex(d)).join('');
|
||||
console.log(' hex ' + hex);
|
||||
}
|
||||
console.log();
|
||||
|
||||
// Output the tile mask
|
||||
for (dy = 0; dy < 8; dy += 1) {
|
||||
//const hex0 = buff[offset + dy * width + 0].toString(16).padStart(2, '0');
|
||||
//const hex1 = buff[offset + dy * width + 1].toString(16).padStart(2, '0');
|
||||
//const hex2 = buff[offset + dy * width + 2].toString(16).padStart(2, '0');
|
||||
//const hex3 = buff[offset + dy * width + 3].toString(16).padStart(2, '0');
|
||||
console.log(' hex 00000000');
|
||||
for (const row of tile.normal.mask) {
|
||||
const hex = row.map(d => toHex(d)).join('');
|
||||
console.log(' hex ' + hex);
|
||||
}
|
||||
console.log();
|
||||
|
||||
// Output the flipped tile data
|
||||
for (dy = 0; dy < 8; dy += 1) {
|
||||
const hex0 = reverse(buff[offset + dy * width + 0].toString(16).padStart(2, '0'));
|
||||
const hex1 = reverse(buff[offset + dy * width + 1].toString(16).padStart(2, '0'));
|
||||
const hex2 = reverse(buff[offset + dy * width + 2].toString(16).padStart(2, '0'));
|
||||
const hex3 = reverse(buff[offset + dy * width + 3].toString(16).padStart(2, '0'));
|
||||
console.log(' hex ' + hex3 + hex2 + hex1 + hex0);
|
||||
for (const row of tile.flipped.data) {
|
||||
const hex = row.map(d => toHex(d)).join('');
|
||||
console.log(' hex ' + hex);
|
||||
}
|
||||
console.log();
|
||||
|
||||
// Output the flipped tile mask
|
||||
for (dy = 0; dy < 8; dy += 1) {
|
||||
//const hex0 = buff[offset + dy * width + 0].toString(16).padStart(2, '0');
|
||||
//const hex1 = buff[offset + dy * width + 1].toString(16).padStart(2, '0');
|
||||
//const hex2 = buff[offset + dy * width + 2].toString(16).padStart(2, '0');
|
||||
//const hex3 = buff[offset + dy * width + 3].toString(16).padStart(2, '0');
|
||||
console.log(' hex 00000000');
|
||||
// Output the flipped tile data
|
||||
for (const row of tile.flipped.mask) {
|
||||
const hex = row.map(d => toHex(d)).join('');
|
||||
console.log(' hex ' + hex);
|
||||
}
|
||||
console.log();
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -249,3 +413,17 @@ async function writeBinayOutput(filename, buff) {
|
||||
await fs.writeFile(filename, Buffer.concat([header, buff]));
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
buildTile,
|
||||
buildTiles,
|
||||
buildMerlinCodeForTiles,
|
||||
buildMerlinCodeForTile,
|
||||
findColorIndex,
|
||||
paletteToIIgs,
|
||||
pngToIIgsBuff,
|
||||
readPNG,
|
||||
toHex,
|
||||
writeBinayOutput,
|
||||
writeToTileDataSource,
|
||||
writeTilesToStream
|
||||
}
|
@ -2,9 +2,13 @@
|
||||
* Read an exported Tiled project in JSON format and produce Merlin32 output files with
|
||||
* GTE-compatible setup code wrapped around it.
|
||||
*/
|
||||
const fs = require('fs').promises;
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const { abort } = require('process');
|
||||
const process = require('process');
|
||||
const { Buffer } = require('buffer');
|
||||
const StringBuilder = require('string-builder');
|
||||
const parser = require('xml2json');
|
||||
const png2iigs = require('./png2iigs');
|
||||
|
||||
main(process.argv.slice(2)).then(
|
||||
() => process.exit(0),
|
||||
@ -14,15 +18,92 @@
|
||||
}
|
||||
);
|
||||
|
||||
function emitHeader() {
|
||||
console.log('; Tiled Map Export');
|
||||
console.log(';');
|
||||
console.log('; This is a generated file. Do not modify.');
|
||||
function hexToRbg(hex) {
|
||||
const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
|
||||
return result ? [parseInt(result[1], 16), parseInt(result[2], 16), parseInt(result[3], 16)] : null;
|
||||
}
|
||||
|
||||
async function readTileSet(workdir, tileset) {
|
||||
// Load up the PNG image
|
||||
const pngfile = path.resolve(path.join(workdir, tileset.image.source));
|
||||
console.log(`Reading PNG file from ${pngfile}`);
|
||||
const png = await png2iigs.readPNG(pngfile);
|
||||
|
||||
// Find the index of the transparent color (if defined)
|
||||
console.log(`Looking for transparency...`);
|
||||
let transparentIndex = -1;
|
||||
if (tileset.image.trans) {
|
||||
const color = hexToRbg(tileset.image.trans);
|
||||
console.log(`Found color ${color} as transparent marker`);
|
||||
transparentIndex = png2iigs.findColorIndex(png, color);
|
||||
if (typeof transparentIndex !== 'number') {
|
||||
console.log('Could not find color in palette');
|
||||
console.log(png.palette);
|
||||
transparentIndex = -1;
|
||||
} else {
|
||||
console.log(`Transparent color palette index is ${transparentIndex}`);
|
||||
}
|
||||
}
|
||||
|
||||
console.log(`Converting PNG to IIgs bitmap format...`);
|
||||
const buff = png2iigs.pngToIIgsBuff(png);
|
||||
|
||||
console.log(`Building tiles...`);
|
||||
const tiles = png2iigs.buildTiles(buff, png.width / 2, transparentIndex);
|
||||
|
||||
// Return the tiles
|
||||
return tiles;
|
||||
}
|
||||
|
||||
function emitHeader() {
|
||||
const sb = new StringBuilder();
|
||||
sb.appendLine('; Tiled Map Export');
|
||||
sb.appendLine(';');
|
||||
sb.appendLine('; This is a generated file. Do not modify.');
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
async function loadTileset(workdir, tileset) {
|
||||
const source = tileset.source;
|
||||
const filename = path.isAbsolute(source) ? source : path.join(workdir, source);
|
||||
|
||||
const contents = fs.readFileSync(filename);
|
||||
return JSON.parse(parser.toJson(contents));
|
||||
}
|
||||
|
||||
function getArg(argv, arg, fn, defaultValue) {
|
||||
for (let i = 0; i < argv.length; i += 1) {
|
||||
if (argv[i] === arg) {
|
||||
if (fn) {
|
||||
return fn(argv[i+1]);
|
||||
}
|
||||
return true; // Return true if the argument was found
|
||||
}
|
||||
}
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
function writeTiles(filename, tiles) {
|
||||
const tileSource = png2iigs.buildMerlinCodeForTiles(tiles);
|
||||
fs.writeFileSync(filename, tileSource);
|
||||
}
|
||||
|
||||
/**
|
||||
* Command line arguments
|
||||
*
|
||||
* --output-dir : sets the output folder to write all assets into
|
||||
*/
|
||||
async function main(argv) {
|
||||
// Read in the JSON data
|
||||
const doc = JSON.parse(await fs.readFile(argv[0]));
|
||||
const fullpath = path.resolve(argv[0]);
|
||||
const workdir = path.dirname(fullpath);
|
||||
|
||||
const outdir = getArg(argv, '--output-dir', x => x, workdir);
|
||||
|
||||
console.log(`Reading Tiled JSON file from ${fullpath}`);
|
||||
const raw = fs.readFileSync(fullpath);
|
||||
console.log(`Parsing JSON file...`);
|
||||
const doc = JSON.parse(raw);
|
||||
|
||||
// Make sure it's a map format we can handle
|
||||
if (doc.infinite) {
|
||||
@ -53,16 +134,43 @@ async function main(argv) {
|
||||
// Sort the tile layers by ID. The lower ID is considered to be the "front" layer
|
||||
tileLayers.sort((first, second) => first.id <= second.id);
|
||||
|
||||
// Ok, looks good. Write out the source code
|
||||
emitHeader();
|
||||
emitBG0Layer(tileLayers[0]);
|
||||
// Load up any/all tilesets
|
||||
const tileSets = await Promise.all(doc.tilesets.map(tileset => loadTileset(workdir, tileset)));
|
||||
|
||||
for (const record of tileSets) {
|
||||
console.log(`Importing tileset "${record.tileset.name}"`);
|
||||
const tiles = await readTileSet(workdir, record.tileset);
|
||||
|
||||
const outputFilename = path.resolve(path.join(outdir, record.tileset.name + '.s'));
|
||||
console.log(`Writing tiles to ${outputFilename}`);
|
||||
writeTiles(outputFilename, tiles);
|
||||
console.log(`Writing complete`);
|
||||
}
|
||||
|
||||
// Ok, looks good. Write out the source code for the layers
|
||||
console.log('Generating data for front layer (BG0): ' + tileLayers[0].name);
|
||||
const header = emitHeader();
|
||||
const bg0 = emitBG0Layer(tileLayers[0]);
|
||||
|
||||
const bg0OutputFilename = path.resolve(path.join(outdir, tileLayers[0].name + '.s'));
|
||||
console.log(`Writing BG0 data to ${bg0OutputFilename}`);
|
||||
fs.writeFileSync(bg0OutputFilename, header + '\n' + bg0);
|
||||
console.log(`Writing complete`);
|
||||
|
||||
if (tileLayers.length > 1) {
|
||||
emitBG1Layer(tileLayers[1]);
|
||||
console.log('Generating data for front layer (BG0): ' + tileLayers[1].name);
|
||||
const bg1 = emitBG1Layer(tileLayers[1]);
|
||||
const bg1OutputFilename = path.resolve(path.join(outdir, tileLayers[1].name + '.s'));
|
||||
console.log(`Writing BG1 data to ${bg1OutputFilename}`);
|
||||
fs.writeFileSync(bg1OutputFilename, header + '\n' + bg1);
|
||||
console.log(`Writing complete`);
|
||||
}
|
||||
}
|
||||
|
||||
function emitBG1Layer(layer) {
|
||||
const label = layer.name.split(' ').join('_');
|
||||
const sb = new StringBuilder();
|
||||
|
||||
const label = layer.name.split(' ').join('_').split('.').join('_');
|
||||
const initCode = `
|
||||
BG1SetUp
|
||||
lda #${layer.width}
|
||||
@ -75,12 +183,17 @@ BG1SetUp
|
||||
sta BG1TileMapPtr+2
|
||||
rts
|
||||
`;
|
||||
console.log(initCode);
|
||||
console.log(`${label}`);
|
||||
sb.appendLine(initCode);
|
||||
sb.appendLine(`${label}`);
|
||||
emitLayerData(sb, layer);
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
function emitBG0Layer(layer) {
|
||||
const label = layer.name.split(' ').join('_');
|
||||
const sb = new StringBuilder();
|
||||
|
||||
const label = layer.name.split(' ').join('_').split('.').join('_');
|
||||
const initCode = `
|
||||
BG0SetUp
|
||||
lda #${layer.width}
|
||||
@ -93,9 +206,14 @@ BG0SetUp
|
||||
sta TileMapPtr+2
|
||||
rts
|
||||
`;
|
||||
console.log(initCode);
|
||||
console.log(`${label}`);
|
||||
sb.appendLine(initCode);
|
||||
sb.appendLine(`${label}`);
|
||||
emitLayerData(sb, layer);
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
function emitLayerData(sb, layer) {
|
||||
// Print out the data in groups of N
|
||||
const N = 16;
|
||||
const chunks = [];
|
||||
@ -106,6 +224,8 @@ BG0SetUp
|
||||
// Tiled starts numbering its tiles at 1. This is OK since Tile 0 is reserved in
|
||||
// GTE, also
|
||||
for (const chunk of chunks) {
|
||||
console.log(' dw ' + chunk.join(','));
|
||||
sb.appendLine(' dw ' + chunk.join(','));
|
||||
}
|
||||
|
||||
return sb;
|
||||
}
|
Loading…
Reference in New Issue
Block a user