A bit tired to set up a full conversion for you right now - here's an RMP loader - with some comments pointing out the key stuff you'd need to write the bits you want back out again - if you can't work it out I could set it up for you another day, maybe saturday.
Basic idea to write it will be the following - note this is a starting point a working write function will be about 40 lines.
//make the output file
let outputFile = new DataStream(fileName.replace(".rmp",".js"), FileOp.Write);
//write out the strings
//you'd need to add the names and brakcets etc to them first
//the loaded versions will be function bodies only
outputFile.writeStringRaw(string1, string1.length);
Note this requires the latest beta of miniSphere 5 to run as it uses some new tricks.
Here's the RMP reading function - this takes an RMP fileName as an input loads the file and then returns an object containing all the data from the file - note you can't skip the read functions you don't need as the data is stored sequentially and each read moves you along in the file - if you just need the map scripts it will be easier - the entity scripts are further down but the below does load them all.
import {DataStream} from "sphere-runtime";
function loadRMP(fileName)
{
let inputFile = new DataStream(fileName, FileOp.Read);
if(inputFile.readStringRaw(4) !== ".rmp")
{
throw new Error("rmpLoader provided with file that is not an rmp file filename is " + fileName);
}
inputFile.position = inputFile.position + 3;//skip version number (always 1) and type which is meaningless
let numLayers = inputFile.readUint8();
inputFile.position = inputFile.position + 1;//skip reserved byte
let numEntities = inputFile.readUint16(true);
//skip startX, startY, (Uint16s) startLayer, startDirection (Uint8s) <- not used with MEngine
inputFile.position = inputFile.position + 6;
let numStrings = inputFile.readUint16(true);
let numZones = inputFile.readUint16(true);
let repeating = inputFile.readUint8();
inputFile.position = inputFile.position + 234;
/* -strings are all currently ignored, they are:
0 - tileset file (obsolete)
1 - music file
2 - script file (obsolete)
3 - entry script
4 - exit script
5 - north script
6 - east script
7 - south script
8 - west script*/
let mapStrings = new Array(9);
for(let i = 0; i < numStrings; ++i)
{
mapStrings[i] = inputFile.readString16(true);
}
let width = 0;
let height = 0;
//load main Layer data - 1st key output
let layers = new Array(numLayers);
for(let i = 0; i < numLayers; ++i)
{
layers[i] =
{
width : inputFile.readUint16(true),
height : inputFile.readUint16(true),
flags : inputFile.readUint16(true),
parallaxX : inputFile.readFloat32(true),
parallaxY : inputFile.readFloat32(true),
scrollX : inputFile.readFloat32(true),
scrollY : inputFile.readFloat32(true),
numSegments : inputFile.readUint32(true),
reflective : inputFile.readUint8(),
zones : [],
triggers : []
};
width = Math.max(width, layers[i].width);
height = Math.max(height, layers[i].height);
inputFile.position = inputFile.position + 3;//skip 3 reserved bytes
layers[i].name = inputFile.readString16(true);
layers[i].tiles = inputFile.read(2 * layers[i].width * layers[i].height);
layers[i].segments = new Array(layers[i].numSegments);
for(let j = 0; j < layers[i].numSegments; ++j)
{
let x = inputFile.readUint32(true);
let y = inputFile.readUint32(true);
layers[i].segments[j] = new Polygon(1, x, y, inputFile.readUint32(true) - x, inputFile.readUint32(true) - y);
}
}
//load entity data 2nd key output
//and load trigger data - attached into layer objects from above
let entities = [];
for(let i = 0; i < numEntities; ++i)
{
let x = inputFile.readUint16(true);
let y = inputFile.readUint16(true);
let layer = inputFile.readUint16(true);
let type = inputFile.readUint16(true);
inputFile.position = inputFile.position + 8;//skip 8 reserved bytes
if(layer > numLayers)
{
throw new Error("layer number " + layer + "for entity" + i + " but total layers in rmp are " + numLayers);
}
if(type == 1)
{
entities.push(
{
x : x,
y : y,
layer : layer,
name : inputFile.readString16(true),
sprite : inputFile.readString16(true),//.replace(".rss",".ses"),
sripts : new Array(5)
});
inputFile.position = inputFile.position + 2;//skip reading number of scripts as always 5
entities.scripts[0] = inputFile.readString16(true);
entities.scripts[1] = inputFile.readString16(true);
entities.scripts[2] = inputFile.readString16(true);
entities.scripts[3] = inputFile.readString16(true);
entities.scripts[4] = inputFile.readString16(true);
/* inputFile.position = inputFile.readUint16(true) + inputFile.position;//burn the scripts I don't want them
inputFile.position = inputFile.readUint16(true) + inputFile.position;
inputFile.position = inputFile.readUint16(true) + inputFile.position;
inputFile.position = inputFile.readUint16(true) + inputFile.position;
inputFile.position = inputFile.readUint16(true) + inputFile.position;*/
inputFile.position = inputFile.position + 16;//skip the reserved bytes
}
else if (type == 2)
{
layers[layer].triggers.push(
{
x : x,
y : y,
name : inputFile.readString16(true)//note per spec this is script - but no name and need an ID
});
}
}
//load zone data - attached into layer objects from above
for(let i = 0; i < numZones; ++i)
{
let x1 = inputFile.readUint16(true);
let y1 = inputFile.readUint16(true);
let x2 = inputFile.readUint16(true);
let y2 = inputFile.readUint16(true);
let layer = inputFile.readUint16(true);
let steps = inputFile.readUint16(true);
inputFile.position = inputFile.position + 4;
let name = inputFile.readString16(true);//script field re-purposed as a ref
layers[layer] = {
poly : new Polygon(1, x1, x2, x2 - x1, y2 - y1),
steps : steps,
name : name
};
}
if(inputFile.readStringRaw(4) !== ".rts")
{
throw new Error("Tile signiture not found either .rmp file is corrupt/out of date or there's an error in the reader script");
}
inputFile.position = inputFile.position + 2;//skip version number - always 1
let numTiles = inputFile.readUint16(true);
let tileWidth = inputFile.readUint16(true);
let tileHeight = inputFile.readUint16(true);
let tileSize = tileWidth * tileHeight;
inputFile.position = inputFile.position + 244;//skip 3 reserved bytes then 1 byte "has_obstructions" then 240 reserved bytes
//has_obstructions is aassumed to always be true
//load rawTile data 3rd key Output
let tileData = inputFile.read(numTiles * tileWidth * tileHeight * 4);
//load and process tile properties 4th key output
let tiles = new Array(numTiles);
for(let i = 0; i < numTiles; ++i)
{
inputFile.position = inputFile.position + 1;//skip 1 reserved byte
let animated = inputFile.readUint8();
let nextTile = inputFile.readUint16(true);
let delay = inputFile.readUint16(true);
inputFile.position = inputFile.position + 1;//skip 1 reserved byte
let obsType = inputFile.readUint8();
let numSegments = inputFile.readUint16(true);
let nameLength = inputFile.readUint16(true);
inputFile.position = inputFile.position + 20;//skip 20 reserved bytes
let tileName = inputFile.readStringRaw(nameLength);
let tileObs = [];
if(obsType == 1)
{
for(let j = 0; j < tileSize; ++j)
{
if(inputFile.readUint8() === 1)
{
tileObs.push(new Polygon(1, j % tileWidth, Math.floor(j / tileHeight), 1, 1));
}
}
}
else
{
for(let j = 0; j < numSegments; ++j)
{
let x1 = inputFile.readUint16(true);
let y1 = inputFile.readUint16(true);
let x2 = inputFile.readUint16(true);
let y2 = inputFile.readUint16(true);
let x_ = Math.min(x1, x2);
let y_ = Math.min(y1, y2);
tileObs.push(new Polygon(1, x_, y_,
Math.abs(x1 - x2),
Math.abs(y1 - y2)));
}
}
tiles[i] =
{
name : tileName,
animated : animated,
nextTile : nextTile,
delay : delay,
obs : tileObs
};
}
return {
width : width,
height : height,
repeating : repeating,
layers : layers,
mapStrings : mapStrings,
entities : entities,
numTiles : numTiles,
tileWidth : tileWidth,
tileHeight : tileHeight,
tileData : tileData,
tiles : tiles
};
}
class Polygon
{
constructor(type, x, y, w, h)
{
this.type = type;
this.x = x;
this.y = y;
this.w = w;
this.h = h;
}
}