// https://docs.google.com/spreadsheets/d/1-3E_t-KsFIw2rpM0hZIKOdNdGm5-GnQjvJb3cysOawE/edit#gid=1532331536 const fs = require("fs"); const _ = require("underscore"); const { allTypes, shuffledModels } = require("./models"); if (!fs.existsSync("config.js")) { fs.writeFileSync("config.js", fs.readFileSync("config.default.js")); } if (!fs.existsSync("output")) { fs.mkdirSync("output"); } const { mode, sameType, singleModel, randomModels, excludedModels, blacklist, } = require("./config"); // Check if a model is excluded from modification function isModelExcluded(fb, sb) { for (let i = 0; i < excludedModels.length; i++) { const model = excludedModels[i]; if ( (model[0] === fb && model[1] === -1) || (model[0] === -1 && model[1] === sb) ) { return true; } else if (model[0] === fb && model[1] === sb) { return true; } } return false; } // Check if a model is blacklisted function isModelBlacklisted(fb, sb) { for (let i = 0; i < blacklist.models.length; i++) { const model = blacklist.models[i]; if ( (model[0] === fb && model[1] === -1) || (model[0] === -1 && model[1] === sb) ) { return !blacklist.isWhitelist; } else if (model[0] === fb && model[1] === sb) { return !blacklist.isWhitelist; } } return blacklist.isWhitelist; } function replaceModels(doReplace = true) { const data = fs.readFileSync("original/character_character_data.bin.orig"); if (doReplace) { // Magic if (mode === 0) { for (let i = 0x16194; i < 0x18ea8; i += 4) { if (isModelExcluded(data[i], data[i + 1])) continue; data[i] = singleModel[0]; data[i + 1] = singleModel[1]; } } else if (mode === 1) { for (let i = 0x16194; i < 0x18ea8; i += 4) { if (isModelExcluded(data[i], data[i + 1])) continue; const model = randomModels[_.random(randomModels.length - 1)]; data[i] = model[0]; data[i + 1] = model[1]; } } else if (mode === 2) { for (let i = 0x16194; i < 0x18ea8; i += 4) { const id = data[i]; const type = data[i + 1]; if (isModelExcluded(id, type)) continue; const modelType = sameType ? type : allTypes[_.random(allTypes.length - 1)]; const models = shuffledModels[modelType]; let modelId = models[_.random(models.length - 1)]; while (isModelBlacklisted(modelId, type)) { modelId = models[_.random(models.length - 1)]; } data[i] = modelId; data[i + 1] = type; } } // ----- } fs.writeFileSync("output/character_character_data.bin", data); } // TODO: Create a reverse-lookup map of some sort to fit the proper model height with other models? // Only does scaling, so not that needed apparently... function replaceHeights(doReplace = true) { const data = fs.readFileSync("original/character_model_model_data.bin.orig"); if (doReplace) { // Magic for (let i = 0x23220; i < 0x24910; i += 2) { data[i] = 0xb9; data[i + 1] = 0x00; } // ----- } fs.writeFileSync("output/character_model_model_data.bin", data); } replaceModels(); replaceHeights(false);