(function(window, document) { "use strict"; // form labels often need unique IDs - this can be used to generate some window.Patcher_uniqueid = 0; var createID = function() { window.Patcher_uniqueid++; return "dllpatch_" + window.Patcher_uniqueid; }; var bytesMatch = function(buffer, offset, bytes) { for(var i = 0; i < bytes.length; i++) { if(buffer[offset+i] != bytes[i]) return false; } return true; }; var replace = function(buffer, offset, bytes) { for(var i = 0; i < bytes.length; i++) { buffer[offset+i] = bytes[i]; } } var whichBytesMatch = function(buffer, offset, bytesArray) { for(var i = 0; i < bytesArray.length; i++) { if(bytesMatch(buffer, offset, bytesArray[i])) return i; } return -1; } // Each unique kind of patch should have createUI, validatePatch, applyPatch, // updateUI class StandardPatch { constructor(options) { this.name = options.name; this.patches = options.patches; this.tooltip = options.tooltip; } createUI(parent) { var id = createID(); var label = this.name; var patch = $('
', {'class' : 'patch'}); this.checkbox = $('')[0]; patch.append(this.checkbox); patch.append(''); if(this.tooltip) { patch.append('
' + this.tooltip + '
'); } parent.append(patch); } updateUI(file) { this.checkbox.checked = this.checkPatchBytes(file) === "on"; } validatePatch(file) { var status = this.checkPatchBytes(file); if(status === "on") { console.log('"' + this.name + '"', "is enabled!"); } else if(status === "off") { console.log('"' + this.name + '"', "is disabled!"); } else { return '"' + this.name + '" is neither on nor off! Have you got the right file?'; } } applyPatch(file) { this.replaceAll(file, this.checkbox.checked); } replaceAll(file, featureOn) { for(var i = 0; i < this.patches.length; i++) { replace(file, this.patches[i].offset, featureOn? this.patches[i].on : this.patches[i].off); } } checkPatchBytes(file) { var patchStatus = ""; for(var i = 0; i < this.patches.length; i++) { var patch = this.patches[i]; if(bytesMatch(file, patch.offset, patch.off)) { if(patchStatus === "") { patchStatus = "off"; } else if(patchStatus != "off"){ return "on/off mismatch within patch"; } } else if(bytesMatch(file, patch.offset, patch.on)) { if(patchStatus === "") { patchStatus = "on"; } else if(patchStatus != "on"){ return "on/off mismatch within patch"; } } else { return "patch neither on nor off"; } } return patchStatus; } } // Each unique kind of patch should have createUI, validatePatch, applyPatch, // updateUI // The DEFAULT state is always the 1st element in the patches array class UnionPatch { constructor(options) { this.name = options.name; this.offset = options.offset; this.patches = options.patches; } createUI(parent) { this.radios = []; var radio_id = createID(); var container = $("
", {"class": "patch-union"}); container.append('' + this.name + ':'); for(var i = 0; i < this.patches.length; i++) { var patch = this.patches[i]; var id = createID(); var label = patch.name; var patchDiv = $('
', {'class' : 'patch'}); var radio = $('')[0]; this.radios.push(radio); patchDiv.append(radio); patchDiv.append(''); if(patch.tooltip) { patchDiv.append('
' + patch.tooltip + '
'); } container.append(patchDiv); } parent.append(container); } updateUI(file) { for(var i = 0; i < this.patches.length; i++) { if(bytesMatch(file, this.offset, this.patches[i].patch)) { this.radios[i].checked = true; return; } } // Default fallback this.radios[0].checked = true; } validatePatch(file) { for(var i = 0; i < this.patches.length; i++) { if(bytesMatch(file, this.offset, this.patches[i].patch)) { console.log(this.name, "has", this.patches[i].name, "enabled"); return; } } return '"' + this.name + '" doesn\'t have a valid patch! Have you got the right file?'; } applyPatch(file) { var patch = this.getSelected(); replace(file, this.offset, patch.patch); } getSelected() { for(var i = 0; i < this.patches.length; i++) { if(this.radios[i].checked) { return this.patches[i]; } } return null; } } var loadPatch = function(_this, self, patcher) { patcher.loadPatchUI(); patcher.updatePatchUI(); patcher.container.show(); var successStr = patcher.filename; if ($.type(_this.description) === "string") { successStr += "(" + patcher.description + ")"; } self.successDiv.html(successStr + " loaded successfully!"); }; class PatchContainer { constructor(patchers) { this.patchers = patchers; this.createUI(); } getSupportedDLLs() { var dlls = []; for (var i = 0; i < this.patchers.length; i++) { var name = this.patchers[i].filename; if (dlls.indexOf(name) === -1) { dlls.push(name); } } return dlls; } createUI() { var self = this; var container = $("
", {"class": "patchContainer"}); var header = this.getSupportedDLLs().join(", "); container.html("

" + header + "

"); var supportedDlls = $("
    "); this.forceLoadTexts = []; this.forceLoadButtons = []; this.matchSuccessText = []; for (var i = 0; i < this.patchers.length; i++) { var checkboxId = createID(); var listItem = $("
  • "); $('