/* PUT this in the same directory as the asset files of MegaMan Unlimited PRAISE be to lodepng http://lodev.org/lodepng/ */ #include #include #include "lodepng.h" using namespace std; int cutscenesCount = 0, gameobjectsCount = 0, levelartCount = 0, menusCount = 0, miscCount = 0, gunsCount; void encodeOneStep(const char* filename, vector& image, unsigned width, unsigned height){ unsigned error = lodepng::encode(filename, image, width, height); if (error) cout << "encoder error " << error << ": "<< lodepng_error_text(error) << endl;} unsigned int get2(fstream* bin){ int ret = 0; for (int shift = 0;;shift += 7){ int byte = bin->get(); ret += byte<= 0x80) ret -= 128<seekg(2, ios_base::cur); for(int j = 0; j < 3; j++){ bin->seekg(1, ios_base::cur); pal[3*i + j] = get2(bin);}} bin->seekg(0x1D, ios_base::cur); unsigned width = get2(bin); bin->seekg(0x1, ios_base::cur); unsigned height = get2(bin); bin->seekg(0x7, ios_base::cur); vector image; image.resize(width*height*4); for(unsigned y = 0; y < height; y++) for(unsigned x = 0; x < width; x++){ unsigned char pixel = bin->get(); image[4*width*y + 4*x + 0] = pal[pixel*3 + 0]; image[4*width*y + 4*x + 1] = pal[pixel*3 + 1]; image[4*width*y + 4*x + 2] = pal[pixel*3 + 2]; image[4*width*y + 4*x + 3] = 255;} bin->seekg(0x6, ios_base::cur); int namelen = bin->get(); char* filename = new char[namelen+1]; filename[namelen] = 0x00; bin->read(filename,namelen); cout << dec << noshowbase << width << "x" << height << " " << hex << showbase << uppercase << bin->tellg() << " " << filename << endl; for (int i = 0; i < namelen; i++) if (filename[i] == '\\' || filename[i] == '/') filename[i] = '-'; encodeOneStep(filename, image, width, height); delete[] filename;} void extractImages8(const char* filename, int* inc){ fstream asset(filename, ios::in|ios::binary); asset.seekg(0, ios_base::beg); unsigned char* palette = new unsigned char[768]; for (;;){ if (!asset) break; if (asset.get() != static_cast(0x10)) continue; if (asset.get() != static_cast(0x08)) continue; if (asset.get() != static_cast(0x80)) continue; if (asset.get() != static_cast(0x02)) continue; dumpImage8(&asset, palette); *inc += 1;} asset.close(); delete[] palette;} void dumpImage32(fstream* bin, int* inc, bool hasName = true){ bin->seekg(1, ios_base::cur); unsigned width = get2(bin); bin->seekg(1, ios_base::cur); unsigned height = get2(bin); bin->seekg(1, ios_base::cur); get2(bin); bin->seekg(1, ios_base::cur); get2(bin); vector image; image.resize(width*height*4); for(unsigned y = 0; y < height; y++) for(unsigned x = 0; x < width; x++) for(int channel = 0; channel < 4; channel++) image[4*width*y + 4*x + channel] = bin->get(); if (hasName == true){ bin->seekg(1, ios_base::cur); get2(bin); bin->seekg(1, ios_base::cur); get2(bin); bin->seekg(1, ios_base::cur); int namelen = bin->get(); char* filename = new char[namelen+1]; filename[namelen] = 0x00; bin->read(filename,namelen); cout << dec << noshowbase << width << "x" << height << " " << hex << showbase << uppercase << bin->tellg() << " " << filename << endl; for (int i = 0; i < namelen; i++) if (filename[i] == '\\' || filename[i] == '/') filename[i] = '-'; encodeOneStep(filename, image, width, height); delete[] filename;} else{ char filename[6] = {49 + *inc, '.', 'p', 'n', 'g', '\0'}; encodeOneStep(filename, image, width, height);}} void extractImages32(const char* filename, int* inc, bool hasName = true){ fstream asset(filename, ios::in|ios::binary); asset.seekg(0, ios_base::beg); for (;;){ if (!asset) break; if (asset.get() != static_cast(0x80)) continue; if (asset.get() != static_cast(0xF8)) continue; if (asset.get() != static_cast(0x0F)) continue; dumpImage32(&asset, inc, hasName); *inc += 1;} asset.close();} void extractSound(const char* filename, int* inc, unsigned init = 0, unsigned atrimoden = 0xFFFFFFFF){ fstream asset(filename, ios::in|ios::binary); asset.seekg(init, ios_base::beg); for (;;){ if (!asset) break; if (asset.tellg() >= atrimoden) return; cout << hex << asset.tellg() << " "; asset.seekg(1, ios_base::cur); get2(&asset); asset.seekg(1, ios_base::cur); get2(&asset); asset.seekg(1, ios_base::cur); int namelen = get2(&asset); char* outname = new char[namelen+1]; outname[namelen] = 0x00; asset.read(outname,namelen); for (int i = 0; i < namelen; i++) if (outname[i] == '\\' || outname[i] == '/') outname[i] = '-'; fstream out(outname, ios::out|ios::binary); cout << outname << endl; int isWav = outname[namelen-1] == 'v'; if (isWav){ asset.seekg(1, ios_base::cur); get2(&asset);} asset.seekg(1, ios_base::cur); int songSize = get2(&asset); if (isWav){ long temp = 0x46464952; out.write(reinterpret_cast(&temp), 4); temp = songSize + 36; out.write(reinterpret_cast(&temp), 4); temp = 0x45564157; out.write(reinterpret_cast(&temp), 4); temp = 0x20746D66; out.write(reinterpret_cast(&temp), 4); temp = 0x00000010; out.write(reinterpret_cast(&temp), 4); temp = 0x00020001; out.write(reinterpret_cast(&temp), 4); temp = 44100; out.write(reinterpret_cast(&temp), 4); temp *= 4; out.write(reinterpret_cast(&temp), 4); temp = 0x00100004; out.write(reinterpret_cast(&temp), 4); temp = 0x61746164; out.write(reinterpret_cast(&temp), 4); temp = songSize; out.write(reinterpret_cast(&temp), 4);} for (; out.tellp() < songSize + isWav*44;) out.put(asset.get()); out.close(); asset.seekg(1, ios_base::cur); get2(&asset); if (isWav){ asset.seekg(1, ios_base::cur); get2(&asset);} *inc += 1;} asset.close();} int main(int argc, char** argv){ extractImages32("cutscenes.mmu", &cutscenesCount); extractImages32("gameobjects.mmu", &gameobjectsCount); extractImages32("menus.mmu", &menusCount); extractImages32("misc.mmu", &miscCount, false); extractImages8("levelart.mmu", &levelartCount); extractSound("guns.mmu", &gunsCount, 0xB, 0x4000000); cout << dec; cout << cutscenesCount << " cutscene images exported." << endl; cout << gameobjectsCount << " object images exported." << endl; cout << levelartCount << " level images exported." << endl; cout << menusCount << " menu images exported." << endl; cout << miscCount << " miscellaneous images exported." << endl; cout << gunsCount << " sounds exported." << endl; return EXIT_SUCCESS;}