0
0
mirror of https://github.com/marcrobledo/savegame-editors.git synced 2025-04-24 16:35:10 +00:00
2024-12-15 10:57:41 +01:00

406 lines
14 KiB
JavaScript

/*
Nintendogs + Cats for HTML5 Save Editor v20160704
by Marc Robledo 2016
*/
var reg = /\d+/;
var diffs = [1056964607, 12582913, 6291456, 4194304];
for (var i = 0; i < 30; i++) {
diffs.push(diffs[diffs.length-2]*0.5);
}
var value = 0;
var level_borders = [];
for (var j = 0; j < 34; j++) {
var amount = 1;
if (j > 3 && j%2==1) {
amount = Math.pow(2, (j-1)*0.5)-1;
}
for (var k = 0; k < amount; k++) {
level_borders.push([value, value + diffs[j] - 1]);
value += diffs[j];
}
if (level_borders.length > 99999) {
level_borders.length = 100000;
break;
}
}
level_borders[99999][1] = 1203982336;
SavegameEditor={
Name:'Nintendogs + Cats',
Filename:'sysdata.dat',
/* Constants */
Constants:{
MONEY_OFFSET:0xA0,
LASTSAVED_OFFSET:0x10,
GENDERS:[
{value:0, name:'Male'},
{value:1, name:'Female'}
],
STREETPASS_MET_OFFSET: 0x98,
OWNER_POINTS_OFFSET: 0x9C,
PEDOMETER_OFFSET: 0x218,
PET_OFFSET:[
0x026A, // 618
0x1E6A, // 7,786
0x3A6A, // 14,954
0x566A, // 22,122
0x726A, // 29,290
0x8E6A // 36,458
],
PET_NAME_OFFSET: 0x42, // 66
PET_GENDER_OFFSET: 0x56, // 86
PET_POINTS_OFFSET_CAT: 0x5A, // 90
PET_POINTS_OFFSET_DOG: 0x62, // 98
PET_BREED_OFFSET: 0x32, // 50
PET_BREED_VARIANT_OFFSET: 0x33, // 51 = Variant (e.g. Spaniel = 0:Blentheim, 1:Tricolour, 2:Ruby)
PET_BREED_STYLE_OFFSET: 0x34, // 52 = Hairstyle
PET_BREED_EYE_COLOR_OFFSET: 0x35, // 53 = Eye Color (Cats: 0=gray, 1=yellow, 2=blue; Dogs: 255)
PET_BREED_COLOR_OFFSET: 0x36, // 54 = Fur Color
PET1_COMP_DISC_PLAYED: 0x24E,
PET1_COMP_OBED_PLAYED: 0x24F,
PET1_COMP_LURE_PLAYED: 0x250,
PET2_COMP_DISC_PLAYED: 0x251,
PET2_COMP_OBED_PLAYED: 0x252,
PET2_COMP_LURE_PLAYED: 0x253,
PET3_COMP_DISC_PLAYED: 0x254,
PET3_COMP_OBED_PLAYED: 0x255,
PET3_COMP_LURE_PLAYED: 0x256,
PET4_COMP_DISC_PLAYED: 0x257,
PET4_COMP_OBED_PLAYED: 0x258,
PET4_COMP_LURE_PLAYED: 0x259,
PET5_COMP_DISC_PLAYED: 0x25A,
PET5_COMP_OBED_PLAYED: 0x25B,
PET5_COMP_LURE_PLAYED: 0x25C,
PET6_COMP_DISC_PLAYED: 0x25D,
PET6_COMP_OBED_PLAYED: 0x25E,
PET6_COMP_LURE_PLAYED: 0x25F,
PET_PERSONALITIES_OFFSET_DOG1: 0x1F6,
PET_PERSONALITIES_OFFSET_DOG2: 0x1FA,
PET_PERSONALITIES_OFFSET_CAT1: 0x1EE,
PET_PERSONALITIES_OFFSET_CAT2: 0x1F2,
WALKING_COUNTER_OFFSET: 0x215
},
_write_money:function(){
tempFile.writeU32(
SavegameEditor.Constants.MONEY_OFFSET,
getValue('money')
);
},
_write_streetpass_met:function(){
tempFile.writeU32(
SavegameEditor.Constants.STREETPASS_MET_OFFSET,
getValue('streetpass-met')
);
},
_write_pedometer:function(){
tempFile.writeU32(
SavegameEditor.Constants.PEDOMETER_OFFSET,
getValue('pedometer')
);
},
_write_walking_counter:function(){
tempFile.writeU8(
SavegameEditor.Constants.WALKING_COUNTER_OFFSET,
getValue('walking-counter')
);
},
_write_supply_amount:function(e){
tempFile.writeU8(
Number(e.target.dataset.offset),
getValue(e.target.id)
);
},
_write_pet_name:function(e){
var index = Number((e.target.id).match(reg)[0]);
var offset = SavegameEditor.Constants.PET_OFFSET[index-1]+SavegameEditor.Constants.PET_NAME_OFFSET;
tempFile.writeU16String(
offset,
10,
getValue(e.target.id)
);
document.getElementsByClassName('pet' + index + '_name')[0].innerText = getValue(e.target.id);
},
_write_u_number:function(e, n, o, g){
var index = Number((e.target.id).match(reg)[0]);
var pet_offset = SavegameEditor.Constants.PET_OFFSET[index-1];
if (g) {
pet_offset = 0;
}
var offset = pet_offset+SavegameEditor.Constants[o];
tempFile['writeU' + n](
offset,
Number(getValue(e.target.id))
);
},
_write_pet_value:function(e){
SavegameEditor._write_u_number(e, Number(e.target.parentElement.dataset.size), e.target.parentElement.dataset.var, e.target.parentElement.dataset.global);
},
_getPetData(petOffset, value, size) {
return tempFile['readU' + (size || 8)](SavegameEditor.Constants.PET_OFFSET[petOffset]+SavegameEditor.Constants[value]);
},
_mark_as_changed(e) {
e.target.dataset.data_changed=true;
},
/* check if savegame is valid */
checkValidSavegame:function(){
return (tempFile.fileSize==60936);
},
preload:function() {
var btn_last_saved = document.getElementById('update-lastsaved');
btn_last_saved.addEventListener('click', function(e) {
tempFile.writeU32(
SavegameEditor.Constants.LASTSAVED_OFFSET,
Math.floor(Date.now() * 0.001)
);
var a = new Date (Number(tempFile.readU32(SavegameEditor.Constants.LASTSAVED_OFFSET)) * 1000);
a.setHours(a.getHours() - a.getTimezoneOffset()/60);
setValue('lastsaved', a.toLocaleString("en-GB", {
day: "numeric",
month: "short",
year: "numeric",
hour: "2-digit",
minute: "2-digit",
second: "2-digit"
}));
}, false);
get('number-money').addEventListener('change', SavegameEditor._write_money);
get('number-streetpass-met').addEventListener('change', SavegameEditor._write_streetpass_met);
get('number-pedometer').addEventListener('change', SavegameEditor._write_pedometer);
get('number-walking-counter').addEventListener('change', SavegameEditor._write_walking_counter);
fetch('/savegame-editors/nintendogs+cats/supplies.json')
.then(function(response) {
return response.json();
}).then(function(data) {
var counter = 0;
for (var rowtype of [
['fooddrink', 'food & drink'],
['toys', 'toys'],
['accessories', 'accessories'],
['furniture', 'furnitures'],
['leashes', 'leashes'],
['skins', 'skins']
]){
var rt = get('row-'+rowtype[0]);
counter = 0;
for (var entry of data[rowtype[1]]) {
rt.append(
col(3, span(entry[1])),
col(1, inputNumber('supplies_' + rowtype[0] + '_'+counter+'_amount', 0, 99, tempFile.readU8(Number(entry[0]))))
);
get('number-supplies_' + rowtype[0] + '_'+counter+'_amount').dataset.offset = entry[0];
get('number-supplies_' + rowtype[0] + '_'+counter+'_amount').addEventListener('change', SavegameEditor._write_supply_amount);
counter++;
}
var lastRow = counter%3;
if (lastRow !== 0) {
rt.append(col((3-lastRow) * 4, span('')));
}
}
}).catch(function(error) {
console.log('[Picross Save Editor]', error);
});
},
/* load function */
load:function(){
tempFile.fileName='sysdata.dat';
tempFile.littleEndian=true;
setValue('money', tempFile.readU32(SavegameEditor.Constants.MONEY_OFFSET));
setNumericRange('money', 0, 9999999);
setValue('streetpass-met', tempFile.readU32(SavegameEditor.Constants.STREETPASS_MET_OFFSET));
setNumericRange('streetpass-met', 0, 9999999);
setValue('pedometer', tempFile.readU32(SavegameEditor.Constants.PEDOMETER_OFFSET));
setNumericRange('pedometer', 0, 9999999);
setValue('walking-counter', tempFile.readU8(SavegameEditor.Constants.WALKING_COUNTER_OFFSET));
setNumericRange('walking-counter', 0, 255);
setNumericRange('owner-points', 0, 99999);
var owner_points = tempFile.readU32(SavegameEditor.Constants.OWNER_POINTS_OFFSET);
for (var k = 0; k < level_borders.length; k++) {
if (owner_points >= level_borders[k][0] && owner_points <= level_borders[k][1]) {
setValue('owner-points', k);
break;
}
}
var level_ele_ = get('number-owner-points');
level_ele_.addEventListener('change', SavegameEditor._mark_as_changed);
var a = new Date (Number(tempFile.readU32(SavegameEditor.Constants.LASTSAVED_OFFSET)) * 1000);
setValue('lastsaved', a.toLocaleString("en-GB", {
day: "numeric",
month: "short",
year: "numeric",
hour: "2-digit",
minute: "2-digit",
second: "2-digit",
timezone: "Europe/London"
}));
var template = document.getElementById("template-row-pet");
var pet_tabs = document.getElementById('pet_tabs');
pet_tabs.innerText = '';
var pet_tabs_content_seperator = document.createElement('div');
pet_tabs.appendChild(pet_tabs_content_seperator);
var first_pet = true;
for (var i=1; i<7; i++){
var pet_present = tempFile.readU8(SavegameEditor.Constants.PET_OFFSET[i-1]) > 0;
if (!pet_present) {continue;}
var pet_tab_input = document.createElement('input');
pet_tab_input.name = 'pet_tabgroup';
pet_tab_input.type = 'radio';
pet_tab_input.id = 'pet_tab' + i;
if (first_pet) {
pet_tab_input.checked = true;
first_pet = false;
}
pet_tab_input.className = 'pet_tab';
pet_tabs.insertBefore(pet_tab_input, pet_tabs_content_seperator);
var pet_tab_label = document.createElement('label');
pet_tab_label.className = 'pet_label';
pet_tab_label.setAttribute('for', 'pet_tab' + i);
pet_tabs.insertBefore(pet_tab_label, pet_tabs_content_seperator);
var templateClone = template.content.cloneNode(true);
templateClone.querySelector('.row').id="row-pet"+i;
for (var ele of templateClone.querySelectorAll('.update-name')) {
if ((ele.id || '').includes('petX')) {
ele.id = ele.id.replaceAll('petX', 'pet' + i);
}
if (ele.getAttribute('for')) {
ele.setAttribute('for', ele.getAttribute('for').replaceAll('petX', 'pet' + i));
}
if ((ele.dataset && ele.dataset.var || '').includes('PETX')) {
ele.dataset.var = ele.dataset.var.replaceAll('PETX', 'PET' + i);
}
}
var breed = SavegameEditor._getPetData(i-1, 'PET_BREED_OFFSET');
var isDog = true;
if (breed > 28 && breed < 32)
isDog = false;
pet_tabs.appendChild(templateClone);
var dialogClassName = 'page-' +
breed +
'-' +
SavegameEditor._getPetData(i-1, 'PET_BREED_VARIANT_OFFSET');
const dialogEle = document.getElementsByClassName(
dialogClassName
)[0];
if (!isDog) {
document.getElementById('eyecolor').querySelector('[data-offset="' + SavegameEditor._getPetData(i-1, 'PET_BREED_EYE_COLOR_OFFSET') + '"]').checked=true;
}
window._sidebar_event({
target: dialogEle
});
var breedImg = document.createElement('img');
var breedImgTmp = document
.getElementById('menu-content')
.getElementsByClassName(dialogClassName)[0]
.querySelector('div[data-color="' + SavegameEditor._getPetData(i-1, 'PET_BREED_COLOR_OFFSET') + '"][data-style="' + SavegameEditor._getPetData(i-1, 'PET_BREED_STYLE_OFFSET') + '"]'
);
if (breedImgTmp) {
breedImg = breedImgTmp.cloneNode();
breedImg.id='petimage'+i;
}
get('container-pet' + i + '-breed').appendChild(breedImg);
var breedImg2 = breedImg.cloneNode();
breedImg2.id = '';
pet_tab_label.appendChild(breedImg2);
var dialogbtn = document.createElement('button');
dialogbtn.dataset.pet = i - 1;
dialogbtn.onclick = function(e) {
e.preventDefault();
get('menu').dataset.pet = e.target.dataset.pet;
get('menu').showModal();
var breed = SavegameEditor._getPetData(e.target.dataset.pet, 'PET_BREED_OFFSET');
var dialogClassName_ = 'page-' +
breed +
'-' +
SavegameEditor._getPetData(e.target.dataset.pet, 'PET_BREED_VARIANT_OFFSET');
var dialogEle_ = document.getElementsByClassName(
dialogClassName_
)[0];
if (breed > 28 && breed < 32) {
document.getElementById('eyecolor').querySelector('[data-offset="' + SavegameEditor._getPetData(e.target.dataset.pet, 'PET_BREED_EYE_COLOR_OFFSET') + '"]').checked=true;
}
window._sidebar_event({
target: dialogEle_
});
};
dialogbtn.innerText = 'Change';
get('container-pet' + i + '-breed').appendChild(dialogbtn);
get('container-pet' + i + '-gender').appendChild(select('pet' + i + '-gender', SavegameEditor.Constants.GENDERS, SavegameEditor._write_pet_value));
setValue('pet' + i + '-name', tempFile.readU16String(SavegameEditor.Constants.PET_OFFSET[i-1]+SavegameEditor.Constants.PET_NAME_OFFSET, 10));
var pet_tab_label_name = document.createElement('span');
pet_tab_label_name.innerText = getValue('pet' + i + '-name');
pet_tab_label_name.className = 'pet' + i + '_name';
pet_tab_label.appendChild(pet_tab_label_name);
setValue('pet' + i + '-gender', SavegameEditor._getPetData(i-1, 'PET_GENDER_OFFSET'));
get('input-pet' + i + '-name').addEventListener('change', SavegameEditor._write_pet_name);
setNumericRange('pet' + i + '-disc-played', 0, 2);
setValue('pet' + i + '-disc-played', tempFile.readU8(SavegameEditor.Constants['PET' + i + '_COMP_DISC_PLAYED']));
get('number-pet' + i + '-disc-played').addEventListener('change', SavegameEditor._write_pet_value);
setNumericRange('pet' + i + '-lure-played', 0, 2);
setValue('pet' + i + '-lure-played', tempFile.readU8(SavegameEditor.Constants['PET' + i + '_COMP_LURE_PLAYED']));
get('number-pet' + i + '-lure-played').addEventListener('change', SavegameEditor._write_pet_value);
setNumericRange('pet' + i + '-obed-played', 0, 2);
setValue('pet' + i + '-obed-played', tempFile.readU8(SavegameEditor.Constants['PET' + i + '_COMP_OBED_PLAYED']));
get('number-pet' + i + '-obed-played').addEventListener('change', SavegameEditor._write_pet_value);
var personality = window.personalities[SavegameEditor._getPetData(i-1, 'PET_PERSONALITIES_OFFSET_' + (isDog ? 'DOG' : 'CAT') + '1', 8)][SavegameEditor._getPetData(i-1, 'PET_PERSONALITIES_OFFSET_' + (isDog ? 'DOG' : 'CAT') + '2', 8)];
setValue('pet' + i + '-personality', personality[Number(SavegameEditor._getPetData(i-1, 'PET_GENDER_OFFSET'))]);
setNumericRange('pet' + i + '-level', 0, 99999);
var points = SavegameEditor._getPetData(i-1, (isDog ? 'PET_POINTS_OFFSET_DOG' : 'PET_POINTS_OFFSET_CAT'), 32);
for (var j = 0; j < level_borders.length; j++) {
if (points >= level_borders[j][0] && points <= level_borders[j][1]) {
setValue('pet' + i + '-level', j);
break;
}
}
var level_ele = get('number-pet' + i + '-level');
level_ele.dataset.is_dog = isDog;
level_ele.addEventListener('change', SavegameEditor._mark_as_changed);
}
pet_tabs.removeChild(pet_tabs_content_seperator);
},
/* save function */
save:function(){
var changed_levels = document.querySelectorAll('[data-data_changed]');
for (var i = 0; i < changed_levels.length; i++) {
var value_old = changed_levels[i].value;
setNumericRange(changed_levels[i].id.substring(7));
changed_levels[i].value = level_borders[changed_levels[i].value][0];
if (changed_levels[i].id === 'number-owner-points') {
tempFile.writeU32(
SavegameEditor.Constants.OWNER_POINTS_OFFSET,
getValue('owner-points')
);
} else {
SavegameEditor._write_u_number(
{target: {id: changed_levels[i].id}},
32,
changed_levels[i].dataset.is_dog ? 'PET_POINTS_OFFSET_DOG' : 'PET_POINTS_OFFSET_CAT'
);
}
changed_levels[i].value = value_old;
delete changed_levels[i].dataset.data_changed;
setNumericRange(changed_levels[i].id.substring(0, 99999));
}
}
};