/* savegame-editor.js v20190411 A library that lets you create easily a savegame editor. Made with vanilla JS. by Marc Robledo 2016-2019 http://www.marcrobledo.com/license */ /* LIBRARIES */ /* MODDED VERSION OF MarcFile.js v20181020 - Marc Robledo 2014-2018 - http://www.marcrobledo.com/license */ function MarcFile(a,b){"object"==typeof a&&a.files&&(a=a.files[0]);var c=!1;if("object"==typeof a&&a.name&&a.size){if("function"!=typeof window.FileReader)throw new Error("Incompatible Browser");c=!0,this.fileName=a.name,this.fileType=a.type,this.fileSize=a.size}else if("number"==typeof a)this.fileName="file.bin",this.fileType="application/octet-stream",this.fileSize=a;else throw new Error("Invalid source");if(this.littleEndian=!1,c)this._fileReader=new FileReader,this._fileReader.marcFile=this,this._fileReader.addEventListener("load",function(){this.marcFile._u8array=new Uint8Array(this.result),this.marcFile._dataView=new DataView(this.result),b&&b.call()},!1),this._fileReader.readAsArrayBuffer(a);else if(0>>0:(this._u8array[a]<<8)+this._u8array[a+1]>>>0},MarcFile.prototype.readU24=function(a){return this.littleEndian?this._u8array[a]+(this._u8array[a+1]<<8)+(this._u8array[a+2]<<16)>>>0:(this._u8array[a]<<16)+(this._u8array[a+1]<<8)+this._u8array[a+2]>>>0},MarcFile.prototype.readU32=function(a){return this.littleEndian?this._u8array[a]+(this._u8array[a+1]<<8)+(this._u8array[a+2]<<16)+(this._u8array[a+3]<<24)>>>0:(this._u8array[a]<<24)+(this._u8array[a+1]<<16)+(this._u8array[a+2]<<8)+this._u8array[a+3]>>>0},MarcFile.prototype.readS8=function(a){return this._dataView.getInt8(a,this.littleEndian)},MarcFile.prototype.readS16=function(a){return this._dataView.getInt16(a,this.littleEndian)},MarcFile.prototype.readS32=function(a){return this._dataView.getInt32(a,this.littleEndian)},MarcFile.prototype.readF32=function(a){return this._dataView.getFloat32(a,this.littleEndian)},MarcFile.prototype.readF64=function(a){return this._dataView.getFloat64(a,this.littleEndian)},MarcFile.prototype.readBytes=function(a,b){for(var c=Array(b),d=0;d>8):(this._u8array[a]=b>>8,this._u8array[a+1]=255&b)},MarcFile.prototype.writeU24=function(a,b){this.littleEndian?(this._u8array[a]=255&b,this._u8array[a+1]=(65280&b)>>8,this._u8array[a+2]=(16711680&b)>>16):(this._u8array[a]=(16711680&b)>>16,this._u8array[a+1]=(65280&b)>>8,this._u8array[a+2]=255&b)},MarcFile.prototype.writeU32=function(a,b){this.littleEndian?(this._u8array[a]=255&b,this._u8array[a+1]=(65280&b)>>8,this._u8array[a+2]=(16711680&b)>>16,this._u8array[a+3]=(4278190080&b)>>24):(this._u8array[a]=(4278190080&b)>>24,this._u8array[a+1]=(16711680&b)>>16,this._u8array[a+2]=(65280&b)>>8,this._u8array[a+3]=255&b)},MarcFile.prototype.writeS8=function(a,b){this._dataView.setInt8(a,b,this.littleEndian)},MarcFile.prototype.writeS16=function(a,b){this._dataView.setInt16(a,b,this.littleEndian)},MarcFile.prototype.writeS32=function(a,b){this._dataView.setInt32(a,b,this.littleEndian)},MarcFile.prototype.writeF32=function(a,b){this._dataView.setFloat32(a,b,this.littleEndian)},MarcFile.prototype.writeF64=function(a,b){this._dataView.setFloat64(a,b,this.littleEndian)},MarcFile.prototype.writeBytes=function(b,c){for(var a=0;a=0){ SavegameEditor.save(); tempFile.save(); }else{ MarcDialogs.open('warning'); } } function closeFileConfirm(){ MarcDialogs.confirm('All changes will be lost.', function(){ closeFile(); MarcDialogs.close() }); } function closeFile(){ show('dragzone'); hide('the-editor'); hide('toolbar'); } function getSavegameDefaultName(){ if(typeof SavegameEditor.Filename==='string') return SavegameEditor.Filename; return SavegameEditor.Filename[0] } function getSavegameAllNames(){ if(typeof SavegameEditor.Filename==='string') return SavegameEditor.Filename; else{ var s=''; for(var i=0; i Browse '+getSavegameAllNames()+' or drop it here'; var inputFile=document.createElement('input'); inputFile.type='file'; inputFile.className='hidden'; inputFile.id='file-load'; inputFile.addEventListener('change', function(){ loadSavegameFromInput(this); }, false); var demoMessage=document.createElement('button'); demoMessage.id='demo'; demoMessage.innerHTML='Do you want to try it out? Try an example savegame'; demoMessage.addEventListener('click', function(){ if(typeof window.fetch==='function'){ fetch(SavegameEditor.Filename) .then(res => res.arrayBuffer()) // Gets the response and returns it as a blob .then(ab => { tempFile=new MarcFile(ab.byteLength); tempFile.fileName=SavegameEditor.Filename; tempFile._u8array=new Uint8Array(ab); tempFile._dataView=new DataView(ab); _tempFileLoadFunction(); }) .catch(function(){ alert('Unexpected error: can\'t download example savegame'); }); }else{ var oReq=new XMLHttpRequest(); oReq.open('GET', SavegameEditor.Filename, true); oReq.responseType='arraybuffer'; oReq.onload=function(oEvent){ if(this.status===200) { var ab=oReq.response; //Note: not oReq.responseText tempFile=new MarcFile(ab.byteLength); tempFile.fileName=SavegameEditor.Filename; tempFile._u8array=new Uint8Array(ab); tempFile._dataView=new DataView(ab); _tempFileLoadFunction(); }else{ alert('Unexpected error: can\'t download example savegame'); } }; oReq.onerror=function(oEvent){ alert('Unexpected error: can\'t download example savegame'); }; oReq.send(null); } }, false); dragZone.appendChild(dragMessage); dragZone.appendChild(inputFile); dragZone.appendChild(demoMessage); document.body.appendChild(dragZone); MarcDragAndDrop.add('dragzone', function(droppedFiles){ tempFile=new MarcFile(droppedFiles[0], _tempFileLoadFunction); }); var warningDialog=document.createElement('div'); warningDialog.className='dialog'; warningDialog.id='dialog-warning'; warningDialog.innerHTML='Use this tool at your own risk. By using it, you are responsible of any data lost.'; var divButtons=document.createElement('div'); divButtons.className='buttons'; var understandButton=document.createElement('button'); understandButton.innerHTML='I understand'; understandButton.addEventListener('click',function(){ var EXPIRE_DAYS=3; var d=new Date(); d.setTime(d.getTime()+(EXPIRE_DAYS*24*60*60*1000)); document.cookie="hideWarningMessage=1;expires="+d.toUTCString();//+";path=./"; MarcDialogs.close(); saveChanges(); }, false); divButtons.appendChild(understandButton); warningDialog.appendChild(divButtons); document.body.appendChild(warningDialog); }, false); /* binary and other helpers */ function compareBytes(offset,a2){ var a1=tempFile.readBytes(offset, a2.length); for(var i=0;i field.maxValue){ val=field.maxValue; } field.value=val; } function fixNumericFieldValueFromEvent(){fixNumericFieldValue(this)} function inputNumber(id,min,max,def){ var input=document.createElement('input'); input.id='number-'+id; input.className='full-width text-right'; input.type='text'; /* type='number' validation breaks getting input value when it's not valid */ input.minValue=min; input.maxValue=max; input.value=def; input.addEventListener('change', fixNumericFieldValueFromEvent, false); return input; } function inputFloat(id,min,max,def){ var input=document.createElement('input'); input.id='float-'+id; input.className='full-width text-right'; input.type='text'; input.minValue=min; input.maxValue=max; input.value=def; input.addEventListener('change', fixNumericFieldValueFromEvent, false); return input } function input(id,def){ var input=document.createElement('input'); input.id='input-'+id; input.className='full-width'; input.type='text'; input.value=def; return input } function checkbox(id,val){ var input=document.createElement('input'); input.id='checkbox-'+id; input.type='checkbox'; if(val) input.value=val; return input } function select(id,options,func){ var select; if(document.getElementById('select-'+id)){ select=document.getElementById('select-'+id); }else{ select=document.createElement('select'); select.id='select-'+id; select.className='full-width'; } if(options){ for(var i=0; i