mkjs/code/engine/ingameRes.js

290 lines
10 KiB
JavaScript

//
// ingameRes.js
//--------------------
// Provides access to general ingame resources.
// by RHY3756547
//
window.GraphicTester = function(rom) {
findGraphicsRecursive(rom);
function listRecursive(resource, path) {
path = path || "";
var files = resource.list();
for (var i=0; i<files.length; i++) {
var file = files[i];
console.log(path + file);
if (file.toLowerCase().endsWith(".carc")) {
listRecursive(new narc(lz77.decompress(resource.getFile(file))), path + file);
}
if (file.toLowerCase().endsWith(".nftr")) {
testFont(new nftr(resource.getFile(file)), 0, path + file);
}
}
}
function findGraphicsRecursive(resource, path) {
path = path || "";
var files = resource.list();
var pals = files.filter(x => x.toLowerCase().endsWith(".nclr"));
var graphics = files.filter(x => x.toLowerCase().endsWith(".ncgr"));
for (var i=0; i<files.length; i++) {
var file = files[i];
console.log(path + file);
if (file.toLowerCase().endsWith(".carc")) {
if (/\_..\./.exec(file) != null) continue; //a localization carc (format _us.carc). only scan the main ones. (+us)
var mainCarc = new narc(lz77.decompress(resource.getFile(file)));
var locCarc = resource.getFile(file.replace(".carc", "_us.carc"));
if (locCarc != null) {
//create a combo
mainCarc = new narcGroup([mainCarc, new narc(lz77.decompress(locCarc))]);
}
findGraphicsRecursive(mainCarc, path + file);
}
if (file.toLowerCase().endsWith(".nscr")) {
//screen
//try to find a pal
//...not a friend, like a color palette
var palFile = mostSimilarString(file, pals, "b");
var grFile = mostSimilarString(file, graphics.filter(x => !x.endsWith(".nce.ncgr")), "b");
if (palFile != null && grFile != null) {
var scr = new nscr(resource.getFile(file));
var pal = new nclr(resource.getFile(palFile));
var graphic = new ncgr(resource.getFile(grFile));
var flattener = new TileFlattener(pal, graphic, scr);
var render = flattener.toCanvas(true, 0, 0);
var split = document.createElement("h3");
split.innerText = path + file;
document.body.appendChild(split);
split = document.createElement("h4");
split.innerText = path + palFile + " " + path + grFile;
document.body.appendChild(split);
document.body.appendChild(render);
}
}
if (file.toLowerCase().endsWith(".ncer")) {
//cell resource
//try to find a pal
//...not a friend, like a color palette
var palFile = mostSimilarString(file, pals, "o");
var grFile = mostSimilarString(file, graphics, "o");
if (palFile != null && grFile != null) {
var cer = new ncer(resource.getFile(file));
var pal = new nclr(resource.getFile(palFile));
var graphic = new ncgr(resource.getFile(grFile));
var flattener = new TileFlattener(pal, graphic, cer);
var split = document.createElement("h3");
split.innerText = path + file;
document.body.appendChild(split);
split = document.createElement("h4");
split.innerText = path + palFile + " " + path + grFile;
document.body.appendChild(split);
//render all images
var imageCount = cer.cebk.imageCount;
for (var j=0; j<imageCount; j++) {
var render = flattener.toCanvas(true, j, 0);
document.body.appendChild(render);
}
}
}
}
}
function mostSimilarString(text, list, pref) {
var bestString = null;
var bestScore = 0;
for (var i=0; i<list.length; i++) {
var score = startSimilarity(text, list[i], pref);
if (score > bestScore) {
bestScore = score;
bestString = list[i];
}
}
return bestString;
}
function countStr(text, char) {
var count = 0;
for (var i=0; i<text.length; i++) {
if (text[i] == char) count++;
}
return count;
}
function startSimilarity(text1, text2, pref) {
var min = Math.min(text1.length, text2.length);
var score = 0;
for (var i=0; i<min; i++) {
if (text1[i] != text2[i]) {
if (pref != null) {
score += countStr(text2.substr(i), pref) / 10;
}
return score;
}
score++;
}
return score; //as similar as possible
}
}
window.IngameRes = function(rom) {
var r = this;
this.kartPhys = new kartphysicalparam(rom.getFile("/data/KartModelMenu/kartphysicalparam.bin"));
this.kartOff = new kartoffsetdata(rom.getFile("/data/KartModelMenu/kartoffsetdata.bin"));
this.MapObj = new narc(lz77.decompress(rom.getFile("/data/Main/MapObj.carc"))); //contains generic map obj, look in here when mapobj res is missing from course. (itembox etc)
this.MainRace = new narc(lz77.decompress(rom.getFile("/data/MainRace.carc"))); //contains item models.
this.MainEffect = new narc(lz77.decompress(rom.getFile("/data/MainEffect.carc"))); //contains particles.
this.Main2D = new narc(lz77.decompress(rom.getFile("/data/Main2D.carc")));
this.KartModelSub = new narc(lz77.decompress(rom.getFile("/data/KartModelSub.carc"))); //contains characters + animations
this.Race = new narc(lz77.decompress(rom.getFile("/data/Scene/Race.carc"))); //contains lakitu, count, various graphics
this.RaceLoc = new narc(lz77.decompress(rom.getFile("/data/Scene/Race_us.carc"))); //contains lakitu lap signs, START, YOU WIN etc. some of these will be replaced by hi res graphics by default.
this.RaceEffect = new spa(r.MainEffect.getFile("RaceEffect.spa"));
this.MainFont = new nftr(r.Main2D.getFile("marioFont.NFTR"));
this.MFont = new nftr(r.Main2D.getFile("LC_Font_m.NFTR"));
this.SFont = new nftr(r.Main2D.getFile("LC_Font_s.NFTR"));
//testFont(this.MainFont, 0);
//testFont(this.MFont, 16*4);
//testFont(this.SFont, 32*4);
/*
var test = new GraphicTester(rom);
listRecursive(rom);
*/
function testFont(font, off, name) {
var all = Object.keys(font.charMap).join("");
var split = document.createElement("h3");
split.innerText = name;
document.body.appendChild(split);
for (var i=0; i<4; i++) {
var sliceF = Math.floor((all.length * i) / 4);
var sliceT = Math.floor((all.length * (i+1)) / 4);
var canvas = font.drawToCanvas(all.substring(sliceF, sliceT), [[0, 0, 0, 0], [255, 0, 0, 255], [255, 255, 255, 255],
[32, 0, 0, 255], [64, 0, 0, 255], [96, 0, 0, 255], [128, 0, 0, 255]]);
document.body.appendChild(canvas);
//canvas.style.position = "absolute";
//canvas.style.left = 0;
//canvas.style.top = off + "px";
//off += 16;
}
}
function listRecursive(resource, path) {
path = path || "";
var files = resource.list();
for (var i=0; i<files.length; i++) {
var file = files[i];
console.log(path + file);
if (file.toLowerCase().endsWith(".carc")) {
listRecursive(new narc(lz77.decompress(resource.getFile(file))), path + file);
}
if (file.toLowerCase().endsWith(".nftr")) {
if (file == "/selectFont.NFTR") debugger;
testFont(new nftr(resource.getFile(file)), 0, path + file);
}
}
}
//debugger;
this.getChar = getChar;
this.getKart = getKart;
var itemNames = [
"banana", "bomb", "gesso" /*squid*/, "kinoko" /*mushroom*/, "kinoko_p" /*queen shroom*/, "koura_g" /*green shell*/, "koura_r" /*red shell*/, "star", "teresa" /*boo*/, "thunder",
"koura_w" /*blue shell item rep*/, "f_box", "killer" /*bullet bill*/
]
//order
//donkey, toad, bowser?, luigi, mario, peach, wario, yoshi, daisy, waluigi, dry bones (karon), robo, heyho
var toSoundOff = [
4, 0, 1, 2, 5, 6, 7, 3, 10, 8, 9, 11, 12
];
var charNames = [
"mario", "donkey", "kinopio", "koopa", "peach", "wario", "yoshi", "luigi", "karon", "daisy", "waluigi", "robo", "heyho"
];
var charAbbrv = [
"MR", "DK", "KO", "KP", "PC", "WR", "YS", "LG", "KA", "DS", "WL", "RB", "HH"
];
var tireName = ["kart_tire_L", "kart_tire_M", "kart_tire_S"];
var characters = [];
var karts = [];
loadItems();
loadTires();
function loadItems() { //loads physical representations of items
var t = {}
for (var i=0; i<itemNames.length; i++) {
var n = itemNames[i];
t[n] = new nitroModel(new nsbmd(r.MainRace.getFile("/Item/it_"+n+".nsbmd")));
}
t.blueShell = new nitroModel(new nsbmd(r.MainRace.getFile("/Item/koura_w.nsbmd")));
t.splat = new nitroModel(new nsbmd(r.MainRace.getFile("/Item/geso_sumi.nsbmd")));
t.fakeBox = new nitroModel(new nsbmd(r.MainRace.getFile("/MapObj/box.nsbmd")));
r.items = t;
}
function loadTires() {
var path = "/data/KartModelMenu/kart/tire/";
var tires = {};
for (var i=0; i<tireName.length; i++) tires[tireName[i]] = new nitroModel(new nsbmd(rom.getFile(path+tireName[i]+".nsbmd")), new nsbtx(rom.getFile(path+tireName[i]+".nsbtx")));
r.tireRes = tires;
}
function getChar(ind) {
if (characters[ind] != null) return characters[ind];
var base = "/character/"+charNames[ind]+"/P_"+charAbbrv[ind];
var obj = {
model: new nitroModel(new nsbmd(r.KartModelSub.getFile(base+".nsbmd")), new nsbtx(r.KartModelSub.getFile(base+".nsbtx")), {tex:{1:2}, pal:{1:2}}),
driveA: new nsbca(r.KartModelSub.getFile(base+"_drive.nsbca")),
loseA: new nsbca(r.KartModelSub.getFile(base+"_lose.nsbca")),
spinA: new nsbca(r.KartModelSub.getFile(base+"_spin.nsbca")),
winA: new nsbca(r.KartModelSub.getFile(base+"_win.nsbca")),
sndOff: toSoundOff[ind]*14,
}
characters[ind] = obj;
return characters[ind];
}
var letters = ["a", "b", "c"]
function getKart(ind) { //returns a nitroModel, but also includes a property "shadVol" containing the kart's shadow volume.
if (karts[ind] != null) return karts[ind];
var c = Math.floor(ind/3);
var t = ind%3;
if (t == 0) c = 0; //only mario has standard kart
var name = charAbbrv[c]+"_"+letters[t];
var path = "/data/KartModelMenu/kart/"+charNames[c]+"/kart_"+name;
var model = new nitroModel(new nsbmd(rom.getFile(path+".nsbmd")), new nsbtx(rom.getFile(path+".nsbtx")));
model.shadVol = new nitroModel(new nsbmd(rom.getFile("/data/KartModelMenu/kart/shadow/sh_"+name+".nsbmd")));
//todo, assign special pallete for A karts
karts[ind] = model;
return karts[ind];
}
}