added ovo 1 & 2 w/ mods
This commit is contained in:
@@ -0,0 +1,169 @@
|
||||
// we should probably re-write this...
|
||||
|
||||
(async () => {
|
||||
// Get mods
|
||||
|
||||
const mods = await fetch("/ModLoader/V1/mods.json").then(r => r.json());
|
||||
|
||||
// Get runtime
|
||||
let runtime;
|
||||
let notify;
|
||||
|
||||
// Util stuff
|
||||
let onFinishLoad = () => {
|
||||
if ((cr_getC2Runtime() || { isloading: true }).isloading) {
|
||||
setTimeout(onFinishLoad, 100);
|
||||
} else {
|
||||
runtime = cr_getC2Runtime();
|
||||
|
||||
notify = (title, text, image = "./speedrunner.png") => {
|
||||
cr.plugins_.sirg_notifications.prototype.acts.AddSimpleNotification.call(
|
||||
runtime.types_by_index.find(
|
||||
(type) => type.plugin instanceof cr.plugins_.sirg_notifications
|
||||
).instances[0],
|
||||
title,
|
||||
text,
|
||||
image
|
||||
);
|
||||
};
|
||||
|
||||
modloader.init();
|
||||
}
|
||||
}
|
||||
|
||||
const validURL = (str) => {
|
||||
const pattern = new RegExp('^(https?:\\/\\/)?' +
|
||||
'((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.)+[a-z]{2,}|' +
|
||||
'((\\d{1,3}\\.){3}\\d{1,3}))' +
|
||||
'(\\:\\d+)?(\\/[-a-z\\d%_.~+]*)*' +
|
||||
'(\\?[;&a-z\\d%_.~+=-]*)?' +
|
||||
'(\\#[-a-z\\d_]*)?$', 'i');
|
||||
return !!pattern.test(str);
|
||||
}
|
||||
|
||||
const loadModUrl = (modURL) => {
|
||||
const name = modloader.getURLName(modURL);
|
||||
|
||||
if (modloader.getIsScriptLoaded(name)) {
|
||||
notify("Mod already loaded", name);
|
||||
return;
|
||||
}
|
||||
|
||||
const js = document.createElement("script");
|
||||
js.type = "application/javascript";
|
||||
js.src = modURL;
|
||||
js.id = name;
|
||||
document.head.appendChild(js);
|
||||
}
|
||||
|
||||
const loadModJS = (modJS) => {
|
||||
setTimeout(modJS, 0);
|
||||
}
|
||||
|
||||
const promptMod = () => {
|
||||
let mod = prompt("Please enter a mod name/url");
|
||||
if (!mod) return;
|
||||
|
||||
if (!validURL(mod)) {
|
||||
mod = mods[mod.toLowerCase()].url || mod;
|
||||
}
|
||||
|
||||
if (validURL(mod) || mod.startsWith("/")) {
|
||||
loadModUrl(mod);
|
||||
} else {
|
||||
loadModJS(mod);
|
||||
}
|
||||
|
||||
notify("Code Ran/Added", "Please wait");
|
||||
}
|
||||
|
||||
const modloader = {
|
||||
init() {
|
||||
document.addEventListener("keydown", (event) => {
|
||||
if (event.code === "KeyL") {
|
||||
if (event.shiftKey) {
|
||||
promptMod();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
this.initDomUI();
|
||||
globalThis.ovoModLoader = this;
|
||||
notify("Mod loaded", "Modloader mod loaded");
|
||||
},
|
||||
|
||||
initDomUI() {
|
||||
const style = document.createElement("style");
|
||||
style.type = "text/css";
|
||||
style.innerHTML = `
|
||||
.ovo-modloader-button {
|
||||
background-color: white;
|
||||
border: solid;
|
||||
border-color: black;
|
||||
border-width: 6px;
|
||||
font-family: "Retron2000";
|
||||
position: absolute;
|
||||
z-index: 3;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.ovo-modloader-button:hover {
|
||||
background-color: rgba(200, 200, 200, 1);
|
||||
}
|
||||
`
|
||||
document.head.appendChild(style);
|
||||
|
||||
const toggleButton = document.createElement("button");
|
||||
toggleButton.id = "ovo-modloader-toggle-button";
|
||||
toggleButton.innerText = "";
|
||||
|
||||
const loadIcon = document.createElement("img");
|
||||
loadIcon.src = "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4NCjwhLS0gU3ZnIFZlY3RvciBJY29ucyA6IGh0dHA6Ly93d3cub25saW5ld2ViZm9udHMuY29tL2ljb24gLS0+DQo8IURPQ1RZUEUgc3ZnIFBVQkxJQyAiLS8vVzNDLy9EVEQgU1ZHIDEuMS8vRU4iICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiPg0KPHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4IiB2aWV3Qm94PSIwIDAgMTAwMCAxMDAwIiBlbmFibGUtYmFja2dyb3VuZD0ibmV3IDAgMCAxMDAwIDEwMDAiIHhtbDpzcGFjZT0icHJlc2VydmUiPg0KPG1ldGFkYXRhPiBTdmcgVmVjdG9yIEljb25zIDogaHR0cDovL3d3dy5vbmxpbmV3ZWJmb250cy5jb20vaWNvbiA8L21ldGFkYXRhPg0KPGc+PGcgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMC4wMDAwMDAsNTExLjAwMDAwMCkgc2NhbGUoMC4xMDAwMDAsLTAuMTAwMDAwKSI+PHBhdGggZD0iTTQ4ODIuOSw0NzQ5LjRjLTEwNy4zLTMyLjYtMjE2LjQtMTQzLjYtMjQ1LjItMjUwLjljLTE1LjMtNDkuOC0yMS4xLTExMDctMjEuMS0zMzc2LjZWLTIxODJMMzUwMi0xMDY3LjNDMjg4Ny4yLTQ1Ni4zLDIzNTYuNyw2MC44LDIzMjAuMyw3OGMtMTAxLjUsNTEuNy0yODMuNSwzMi42LTM3NS40LTM2LjRjLTEzNC4xLTEwMy40LTE4NS44LTI0OS0xNDMuNi00MDkuOWMyMy04NC4zLDEzMi4yLTE5Ny4zLDE0OTItMTU2MC45Yzk4Ni40LTk4OC4zLDE0OTItMTQ4Mi40LDE1NDUuNi0xNTA3LjNjOTEuOS00NiwyMTIuNi00OS44LDMxMC4zLTkuNmM5MiwzOC4zLDI5NTUuMywyODk0LDMwMTYuNiwzMDA3YzEyMC43LDIyNy45LTI0LjksNTE3LjEtMjcyLDU0MmMtMjE2LjQsMjEuMS0xMzIuMSw5MS45LTEzNzUuMi0xMTUxLjFMNTM4Mi44LTIxODJ2MzMwMy44YzAsMjI2OS42LTUuNywzMzI2LjgtMjEuMSwzMzc2LjZjLTMwLjcsMTExLjEtMTM3LjksMjE4LjMtMjUyLjgsMjUyLjhTNDk5Niw0Nzg1LjgsNDg4Mi45LDQ3NDkuNHoiLz48cGF0aCBkPSJNNDMxLjgtMTgzNy4yYy05LjYtMy44LTQyLjEtMTEuNS03Mi44LTE3LjJjLTc4LjUtMTcuMi0xOTkuMi0xMzYtMjM1LjYtMjMzLjdjLTU5LjQtMTU3LTEuOS01OTcuNiwxMjQuNS05NDQuMmMyNzkuNi03NjQuMiw5NjUuMy0xMzM0LjksMTc5Mi43LTE0OTJjMTU3LjEtMzAuNiw0MDkuOS0zMi42LDI5NTkuMS0zMi42YzI1NTYuOSwwLDI4MDAuMSwxLjksMjk2MSwzMi42YzEwNzQuNSwyMDQuOSwxODU3LjgsMTA4MC4yLDE5MzQuNCwyMTY2LjJjMTUuMywyMDYuOC0zLjgsMjg5LjItOTMuOCwzODguOGMtMTM3LjksMTU5LTM1Ni4zLDE3OC4xLTUxNS4yLDQ0Yy05Ny43LTc4LjUtMTMwLjItMTYyLjgtMTQ5LjQtMzk4LjRjLTExLjUtMTEzLTM2LjQtMjY2LjItNTkuNC0zMzljLTEzNi00NDQuMy00NDguMi04MDIuNS04NjUuNy05OTRjLTMxNC4xLTE0NS41LTU3LjUtMTM0LjEtMzIxMS45LTEzNC4xYy0yNjg1LjIsMC0yODMwLjgsMS45LTI5NDkuNSwzNC41Yy00OTYuMSwxNDEuNy04OTQuNCw0OTQuMS0xMDc4LjMsOTU1LjdjLTY3LDE2NC43LTEwOS4yLDM0Ni43LTEwOS4yLDQ2OS4zYzAsMTgzLjgtMzQuNSwyOTEuMS0xMjIuNiwzNzkuMkM2NTIuMS0xODY0LjEsNTA4LjUtMTgxMC40LDQzMS44LTE4MzcuMnoiLz48L2c+PC9nPg0KPC9zdmc+"
|
||||
loadIcon.style.width = "38px";
|
||||
loadIcon.style.height = "38px";
|
||||
|
||||
toggleButton.appendChild(loadIcon);
|
||||
toggleButton.classList.add("ovo-modloader-button");
|
||||
toggleButton.style.top = "50%";
|
||||
toggleButton.style.right = "0%";
|
||||
toggleButton.style.transform = "translateY(-50%)";
|
||||
toggleButton.style.width = "50px";
|
||||
toggleButton.style.height = "50px";
|
||||
toggleButton.style.zIndex = "3";
|
||||
toggleButton.onclick = promptMod;
|
||||
document.body.appendChild(toggleButton);
|
||||
},
|
||||
|
||||
getIsScriptLoaded(script) {
|
||||
if (validURL(script)) {
|
||||
const scripts = document.getElementsByTagName('script');
|
||||
for (let i = scripts.length; i--;) {
|
||||
if (scripts[i].src == script) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
const element = document.getElementById(script);
|
||||
return (!!element && (element.tagName == "SCRIPT"));
|
||||
},
|
||||
|
||||
getURLName(url) {
|
||||
return url.substring(url.lastIndexOf("/") + 1).replace(/\.[^/.]+$/, "");
|
||||
},
|
||||
|
||||
getModURL(name) {
|
||||
return mods[name.toLowerCase()];
|
||||
},
|
||||
|
||||
loadScriptURL(url) {
|
||||
return loadModUrl(url);
|
||||
},
|
||||
|
||||
loadScript(js) {
|
||||
return loadModJS(js);
|
||||
}
|
||||
}
|
||||
|
||||
// Uneeded?
|
||||
alert("This is a MODDED client. Press Shift+L to load mods. (url, script, or default mods on homepage)");
|
||||
setTimeout(onFinishLoad, 100);
|
||||
})();
|
||||
@@ -0,0 +1,180 @@
|
||||
(async () => {
|
||||
// Get mods
|
||||
const mods = await fetch("../modloader/mods/v2.json").then(r => r.json());
|
||||
|
||||
// Get runtime
|
||||
var c3interface;
|
||||
var runtime;
|
||||
var notify;
|
||||
|
||||
// Util stuff
|
||||
const onFinishLoad = () => {
|
||||
c3interface = c3_runtimeInterface;
|
||||
runtime = c3interface._GetLocalRuntime();
|
||||
|
||||
if ((runtime && runtime.IsLoading) && runtime.IsLoading()) {
|
||||
setTimeout(onFinishLoad, 100);
|
||||
} else {
|
||||
notify = () => {};
|
||||
modloader.init();
|
||||
|
||||
setTimeout(() => {
|
||||
notify("Mod loaded", "Modloader mod loaded");
|
||||
}, 1000);
|
||||
}
|
||||
}
|
||||
|
||||
const validURL = (str) => {
|
||||
const pattern = new RegExp('^(https?:\\/\\/)?' +
|
||||
'((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.)+[a-z]{2,}|' +
|
||||
'((\\d{1,3}\\.){3}\\d{1,3}))' +
|
||||
'(\\:\\d+)?(\\/[-a-z\\d%_.~+]*)*' +
|
||||
'(\\?[;&a-z\\d%_.~+=-]*)?' +
|
||||
'(\\#[-a-z\\d_]*)?$', 'i');
|
||||
return !!pattern.test(str);
|
||||
}
|
||||
|
||||
const loadModUrl = (modURL) => {
|
||||
const name = modloader.getURLName(modURL);
|
||||
|
||||
if (modloader.getIsScriptLoaded(name)) {
|
||||
notify("Mod already loaded", name);
|
||||
return;
|
||||
}
|
||||
|
||||
const js = document.createElement("script");
|
||||
js.type = "application/javascript";
|
||||
js.src = modURL;
|
||||
js.id = name;
|
||||
document.head.appendChild(js);
|
||||
}
|
||||
|
||||
const loadModJS = (modJS) => {
|
||||
setTimeout(modJS, 0);
|
||||
}
|
||||
|
||||
const promptMod = () => {
|
||||
let mod = prompt("Please enter a mod name/url");
|
||||
|
||||
if (!mod) return;
|
||||
|
||||
if (!validURL(mod)) {
|
||||
mod = mods[mod.toLowerCase()].url ? "../modloader/mods/v2/" + mods[mod.toLowerCase()].url : mod;
|
||||
}
|
||||
|
||||
if (validURL(mod) || mod.startsWith("/")) {
|
||||
loadModUrl(mod);
|
||||
} else {
|
||||
loadModJS(mod);
|
||||
}
|
||||
|
||||
notify("Code Ran/Added", "Please wait");
|
||||
}
|
||||
|
||||
const modloader = {
|
||||
init() {
|
||||
document.addEventListener("keydown", (event) => {
|
||||
if (event.code === "KeyL" && !this.removed) {
|
||||
if (event.shiftKey) {
|
||||
promptMod();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
this.initDomUI();
|
||||
this.updateDomContainers();
|
||||
this.initialised = true;
|
||||
this.removed = false;
|
||||
this.mainElements = [];
|
||||
|
||||
globalThis.ovoModLoader = this;
|
||||
},
|
||||
|
||||
initDomUI() {
|
||||
const style = document.createElement("style");
|
||||
style.type = "text/css";
|
||||
style.innerHTML = `
|
||||
.ovo-modloader-button {
|
||||
background-color: white;
|
||||
border: solid;
|
||||
border-color: black;
|
||||
border-width: 6px;
|
||||
font-family: "Retron2000";
|
||||
position: absolute;
|
||||
z-index: 3;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.ovo-modloader-button img {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
}
|
||||
|
||||
.ovo-modloader-button:hover {
|
||||
background-color: rgba(200, 200, 200, 1);
|
||||
}
|
||||
`
|
||||
document.head.appendChild(style);
|
||||
|
||||
const toggleButton = document.createElement("button");
|
||||
toggleButton.id = "ovo-modloader-toggle-button";
|
||||
toggleButton.innerText = "";
|
||||
|
||||
const loadIcon = document.createElement("img");
|
||||
loadIcon.src = "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4NCjwhLS0gU3ZnIFZlY3RvciBJY29ucyA6IGh0dHA6Ly93d3cub25saW5ld2ViZm9udHMuY29tL2ljb24gLS0+DQo8IURPQ1RZUEUgc3ZnIFBVQkxJQyAiLS8vVzNDLy9EVEQgU1ZHIDEuMS8vRU4iICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiPg0KPHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4IiB2aWV3Qm94PSIwIDAgMTAwMCAxMDAwIiBlbmFibGUtYmFja2dyb3VuZD0ibmV3IDAgMCAxMDAwIDEwMDAiIHhtbDpzcGFjZT0icHJlc2VydmUiPg0KPG1ldGFkYXRhPiBTdmcgVmVjdG9yIEljb25zIDogaHR0cDovL3d3dy5vbmxpbmV3ZWJmb250cy5jb20vaWNvbiA8L21ldGFkYXRhPg0KPGc+PGcgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMC4wMDAwMDAsNTExLjAwMDAwMCkgc2NhbGUoMC4xMDAwMDAsLTAuMTAwMDAwKSI+PHBhdGggZD0iTTQ4ODIuOSw0NzQ5LjRjLTEwNy4zLTMyLjYtMjE2LjQtMTQzLjYtMjQ1LjItMjUwLjljLTE1LjMtNDkuOC0yMS4xLTExMDctMjEuMS0zMzc2LjZWLTIxODJMMzUwMi0xMDY3LjNDMjg4Ny4yLTQ1Ni4zLDIzNTYuNyw2MC44LDIzMjAuMyw3OGMtMTAxLjUsNTEuNy0yODMuNSwzMi42LTM3NS40LTM2LjRjLTEzNC4xLTEwMy40LTE4NS44LTI0OS0xNDMuNi00MDkuOWMyMy04NC4zLDEzMi4yLTE5Ny4zLDE0OTItMTU2MC45Yzk4Ni40LTk4OC4zLDE0OTItMTQ4Mi40LDE1NDUuNi0xNTA3LjNjOTEuOS00NiwyMTIuNi00OS44LDMxMC4zLTkuNmM5MiwzOC4zLDI5NTUuMywyODk0LDMwMTYuNiwzMDA3YzEyMC43LDIyNy45LTI0LjksNTE3LjEtMjcyLDU0MmMtMjE2LjQsMjEuMS0xMzIuMSw5MS45LTEzNzUuMi0xMTUxLjFMNTM4Mi44LTIxODJ2MzMwMy44YzAsMjI2OS42LTUuNywzMzI2LjgtMjEuMSwzMzc2LjZjLTMwLjcsMTExLjEtMTM3LjksMjE4LjMtMjUyLjgsMjUyLjhTNDk5Niw0Nzg1LjgsNDg4Mi45LDQ3NDkuNHoiLz48cGF0aCBkPSJNNDMxLjgtMTgzNy4yYy05LjYtMy44LTQyLjEtMTEuNS03Mi44LTE3LjJjLTc4LjUtMTcuMi0xOTkuMi0xMzYtMjM1LjYtMjMzLjdjLTU5LjQtMTU3LTEuOS01OTcuNiwxMjQuNS05NDQuMmMyNzkuNi03NjQuMiw5NjUuMy0xMzM0LjksMTc5Mi43LTE0OTJjMTU3LjEtMzAuNiw0MDkuOS0zMi42LDI5NTkuMS0zMi42YzI1NTYuOSwwLDI4MDAuMSwxLjksMjk2MSwzMi42YzEwNzQuNSwyMDQuOSwxODU3LjgsMTA4MC4yLDE5MzQuNCwyMTY2LjJjMTUuMywyMDYuOC0zLjgsMjg5LjItOTMuOCwzODguOGMtMTM3LjksMTU5LTM1Ni4zLDE3OC4xLTUxNS4yLDQ0Yy05Ny43LTc4LjUtMTMwLjItMTYyLjgtMTQ5LjQtMzk4LjRjLTExLjUtMTEzLTM2LjQtMjY2LjItNTkuNC0zMzljLTEzNi00NDQuMy00NDguMi04MDIuNS04NjUuNy05OTRjLTMxNC4xLTE0NS41LTU3LjUtMTM0LjEtMzIxMS45LTEzNC4xYy0yNjg1LjIsMC0yODMwLjgsMS45LTI5NDkuNSwzNC41Yy00OTYuMSwxNDEuNy04OTQuNCw0OTQuMS0xMDc4LjMsOTU1LjdjLTY3LDE2NC43LTEwOS4yLDM0Ni43LTEwOS4yLDQ2OS4zYzAsMTgzLjgtMzQuNSwyOTEuMS0xMjIuNiwzNzkuMkM2NTIuMS0xODY0LjEsNTA4LjUtMTgxMC40LDQzMS44LTE4MzcuMnoiLz48L2c+PC9nPg0KPC9zdmc+"
|
||||
loadIcon.style.width = "38px";
|
||||
loadIcon.style.height = "38px";
|
||||
|
||||
toggleButton.appendChild(loadIcon);
|
||||
toggleButton.classList.add("ovo-modloader-button");
|
||||
toggleButton.style.top = "50%";
|
||||
toggleButton.style.right = "0%";
|
||||
toggleButton.style.transform = "translateY(-50%)";
|
||||
toggleButton.style.width = "50px";
|
||||
toggleButton.style.height = "50px";
|
||||
toggleButton.style.zIndex = "3";
|
||||
|
||||
toggleButton.onclick = promptMod;
|
||||
document.body.appendChild(toggleButton);
|
||||
|
||||
this.mainElements += [style, toggleButton];
|
||||
},
|
||||
|
||||
updateDomContainers() {
|
||||
|
||||
},
|
||||
|
||||
getIsScriptLoaded(script) {
|
||||
if (validURL(script)) {
|
||||
const scripts = document.getElementsByTagName("script");
|
||||
for (let i = scripts.length; i--;) {
|
||||
if (scripts[i].src == script) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
const element = document.getElementById(script);
|
||||
return (!!element && (element.tagName == "SCRIPT"));
|
||||
},
|
||||
|
||||
getURLName(url) {
|
||||
return url.substring(url.lastIndexOf("/")+1).replace(/\.[^/.]+$/, "");
|
||||
},
|
||||
|
||||
getModURL(name) {
|
||||
return mods[name.toLowerCase()];
|
||||
},
|
||||
|
||||
loadScriptURL(url) {
|
||||
return loadModUrl(url);
|
||||
},
|
||||
|
||||
loadScript(js) {
|
||||
return loadModJS(js);
|
||||
}
|
||||
}
|
||||
|
||||
alert("This is a MODDED client. Press Shift+L to load mods. (url, script, or default mods on homepage)");
|
||||
setTimeout(onFinishLoad, 100);
|
||||
})();
|
||||
@@ -0,0 +1,107 @@
|
||||
{
|
||||
"ai": {
|
||||
"name": "AI",
|
||||
"author": "drakeerv",
|
||||
"description": "Basic AI that plays ovo.",
|
||||
"advanced": true,
|
||||
"url": "ai.js"
|
||||
},
|
||||
"chaos": {
|
||||
"name": "Chaos",
|
||||
"author": "drakeerv",
|
||||
"description": "CHAOS!",
|
||||
"advanced": false,
|
||||
"url": "chaos.js"
|
||||
},
|
||||
"explorer": {
|
||||
"name": "Explorer",
|
||||
"author": "Toadi",
|
||||
"description": "Explore OvO levels.",
|
||||
"advanced": true,
|
||||
"url": "explorer.js"
|
||||
},
|
||||
"hurricane": {
|
||||
"name": "Hurricane",
|
||||
"author": "Toadi",
|
||||
"description": "Creates a hurricane!",
|
||||
"advanced": false,
|
||||
"url": "hurricane.js"
|
||||
},
|
||||
"flymod": {
|
||||
"name": "Fly",
|
||||
"author": "Toadi",
|
||||
"description": "Fly around the level.",
|
||||
"advanced": false,
|
||||
"url": "flymod.js"
|
||||
},
|
||||
"levelselector": {
|
||||
"name": "Level Selector",
|
||||
"author": "drakeerv",
|
||||
"description": "Load any level in the game.",
|
||||
"advanced": false,
|
||||
"url": "levelselector.js"
|
||||
},
|
||||
"modapi": {
|
||||
"name": "Mod API",
|
||||
"author": "drakeerv",
|
||||
"description": "A basic mod API for other mods to use.",
|
||||
"advanced": true,
|
||||
"url": "modapi.js"
|
||||
},
|
||||
"multiplayer": {
|
||||
"name": "Multiplayer",
|
||||
"author": "Skymen",
|
||||
"description": "Play multiplayer with your friends!",
|
||||
"advanced": false,
|
||||
"url": "multiplayer.js"
|
||||
},
|
||||
"randomlevel": {
|
||||
"name": "Random Level",
|
||||
"author": "drakeerv",
|
||||
"description": "Hop into a random level.",
|
||||
"advanced": false,
|
||||
"url": "randomlevel.js"
|
||||
},
|
||||
"savestate": {
|
||||
"name": "Save State",
|
||||
"author": "Skymen",
|
||||
"description": "Pause the game in place.",
|
||||
"advanced": true,
|
||||
"url": "savestate.js"
|
||||
},
|
||||
"tas": {
|
||||
"name": "TAS",
|
||||
"author": "Skymen",
|
||||
"description": "TAS tools for OvO.",
|
||||
"advanced": true,
|
||||
"url": "tas.js"
|
||||
},
|
||||
"dark": {
|
||||
"name": "Dark",
|
||||
"author": "drakeerv",
|
||||
"description": "Dark Mode for OvO!",
|
||||
"advanced": false,
|
||||
"url": "dark.js"
|
||||
},
|
||||
"keystrokes": {
|
||||
"name": "Keystrokes",
|
||||
"author": "R3XFadeaway",
|
||||
"description": "See you keystrokes.",
|
||||
"advanced": false,
|
||||
"url": "keystrokes.js"
|
||||
},
|
||||
"collision": {
|
||||
"name": "Collision",
|
||||
"author": "OvOPlant",
|
||||
"description": "Enable or disable collisions",
|
||||
"advanced": false,
|
||||
"url": "collision.js"
|
||||
},
|
||||
"picture": {
|
||||
"name": "Picture",
|
||||
"author": "drakeerv",
|
||||
"description": "Loads a image from your computer and loads it into the game",
|
||||
"advanced": false,
|
||||
"url": "picture.js"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,141 @@
|
||||
(function () {
|
||||
// Get runtime
|
||||
let old = globalThis.sdk_runtime;
|
||||
c2_callFunction("execCode", ["globalThis.sdk_runtime = this.runtime"]);
|
||||
let runtime = globalThis.sdk_runtime;
|
||||
globalThis.sdk_runtime = old;
|
||||
|
||||
// Util stuff
|
||||
let clamp = (num, min, max) => Math.min(Math.max(num, min), max);
|
||||
|
||||
let notify = (title, text, image = "./speedrunner.png") => {
|
||||
cr.plugins_.sirg_notifications.prototype.acts.AddSimpleNotification.call(
|
||||
runtime.types_by_index.find(
|
||||
(type) => type.plugin instanceof cr.plugins_.sirg_notifications
|
||||
).instances[0],
|
||||
title,
|
||||
text,
|
||||
image
|
||||
);
|
||||
};
|
||||
|
||||
let addScript = (src, id, onload) => {
|
||||
if (document.getElementById(id)) return;
|
||||
let fjs = document.getElementsByTagName("script")[0];
|
||||
let js = document.createElement("script");
|
||||
js.id = id;
|
||||
fjs.parentNode.insertBefore(js, fjs);
|
||||
js.onload = onload;
|
||||
js.src = src;
|
||||
};
|
||||
|
||||
let getPlayer = () => {
|
||||
return runtime.types_by_index
|
||||
.filter(
|
||||
(x) =>
|
||||
!!x.animations &&
|
||||
x.animations[0].frames[0].texture_file.includes("collider")
|
||||
)[0]
|
||||
.instances.filter(
|
||||
(x) => x.instance_vars[17] === "" && x.behavior_insts[0].enabled
|
||||
)[0];
|
||||
};
|
||||
|
||||
let getFlag = () => {
|
||||
return runtime.types_by_index.find(
|
||||
(x) =>
|
||||
x.name === "EndFlag" ||
|
||||
(x.plugin instanceof cr.plugins_.Sprite &&
|
||||
x.all_frames &&
|
||||
x.all_frames[0].texture_file.includes("endflag"))
|
||||
).instances[0];
|
||||
};
|
||||
|
||||
let ai = {
|
||||
init() {
|
||||
this.network_config = { hiddenLayers: [3, 4, 5] };
|
||||
this.train_config = { log: false };
|
||||
this.enabled = false;
|
||||
this.threshold = 0.5;
|
||||
this.prevInputs = { up: Math.random(), down: Math.random(), left: Math.random(), right: Math.random() };
|
||||
this.prevDistance = Infinity;
|
||||
this.failRandomness = 0.2;
|
||||
this.correctRandomness = 0.1;
|
||||
this.frameLimit = 500;
|
||||
this.frame = 0;
|
||||
|
||||
runtime.tickMe(this);
|
||||
globalThis.ovoAi = this;
|
||||
},
|
||||
resetLevel() {
|
||||
c2_callFunction("Menu > Replay");
|
||||
},
|
||||
playInputs(inputs) {
|
||||
if (inputs.up > this.threshold) c2_callFunction("Controls > Buffer", ["Jump"]);
|
||||
if (inputs.down > this.threshold) c2_callFunction("Controls > Down");
|
||||
if (inputs.left > this.threshold) c2_callFunction("Controls > Left In");
|
||||
else if (inputs.left <= this.threshold) c2_callFunction("Controls > Left Out");
|
||||
if (inputs.right > this.threshold) c2_callFunction("Controls > Right In");
|
||||
else if (inputs.right <= this.threshold) c2_callFunction("Controls > Right Out");
|
||||
},
|
||||
|
||||
start() {
|
||||
this.network = new brain.NeuralNetwork(this.network_config);
|
||||
this.network.train([{ input: {}, output: { up: Math.random(), down: Math.random(), left: Math.random(), right: Math.random() } }], this.train_config); // figure out what data to send, possible position, solid, flag, spike
|
||||
this.enabled = true;
|
||||
},
|
||||
|
||||
stop() {
|
||||
this.prevInputs = { up: Math.random(), down: Math.random(), left: Math.random(), right: Math.random() };
|
||||
this.prevDistance = Infinity;
|
||||
this.frame = 0;
|
||||
delete this.beginDistance;
|
||||
delete this.endDistance;
|
||||
delete this.network;
|
||||
this.enabled = false;
|
||||
},
|
||||
|
||||
addRandom(json) {
|
||||
newJson = {}
|
||||
|
||||
Object.entries(json).forEach((item) => {
|
||||
newJson[item[0]] = clamp(item[1] + ((Math.random() - 0.5) * this.failRandomness * 2), 0, 1);
|
||||
});
|
||||
|
||||
return newJson;
|
||||
},
|
||||
|
||||
tick() {
|
||||
let player = getPlayer();
|
||||
let flag = getFlag();
|
||||
let layout = runtime.running_layout;
|
||||
|
||||
if (this.enabled && player && flag && this.frame < 1) {
|
||||
this.beginDistance = Math.sqrt((flag.x - player.x) ** 2, (flag.y - player.y) ** 2);
|
||||
}
|
||||
|
||||
if (this.enabled && player && flag && this.frame <= this.frameLimit) {
|
||||
let pos = { playerx: player.x / layout.width, playery: player.y / layout.height, flagx: flag.x / layout.width, flagy: flag.y / layout.height };
|
||||
let inputs = this.network.run({ ...this.prevInputs, ...pos });
|
||||
this.playInputs(inputs);
|
||||
this.prevInputs = inputs;
|
||||
this.frame++;
|
||||
} else if (this.enabled && player && flag && this.frame > this.frameLimit) {
|
||||
let pos = { playerx: player.x / layout.width, playery: player.y / layout.height, flagx: flag.x / layout.width, flagy: flag.y / layout.height };
|
||||
let endDistance = Math.sqrt((flag.x - player.x) ** 2, (flag.y - player.y) ** 2);
|
||||
|
||||
if (endDistance < this.beginDistance && endDistance <= this.prevDistance) {
|
||||
let inputs = this.network.run({ ...this.prevInputs, ...pos });
|
||||
this.network.train([{ input: { ...this.prevInputs, ...pos }, output: { ...this.addRandom(inputs) } }]);
|
||||
} else if (endDistance <= this.prevDistance) {
|
||||
this.prevDistance = endDistance;
|
||||
}
|
||||
|
||||
this.resetLevel();
|
||||
this.frame = 0;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
addScript("https://unpkg.com/brain.js@latest/dist/brain-browser.min.js", "brainJs", ai.init.bind(ai));
|
||||
})();
|
||||
@@ -0,0 +1,117 @@
|
||||
let chaosPresets = {
|
||||
"original": {
|
||||
"sin": "random",
|
||||
"cos": "random",
|
||||
"tan": "random"
|
||||
},
|
||||
"funky": {
|
||||
"sin": "sinh",
|
||||
"cos": "cosh",
|
||||
"tan": "tanh"
|
||||
},
|
||||
"size": {
|
||||
"sin": "fib"
|
||||
}
|
||||
};
|
||||
|
||||
(function () {
|
||||
let chaos = {
|
||||
init() {
|
||||
this.random = Math.random;
|
||||
|
||||
this.abs = Math.abs;
|
||||
this.acos = Math.acos;
|
||||
this.acosh = Math.acosh;
|
||||
this.asin = Math.asin;
|
||||
this.asinh = Math.asinh;
|
||||
this.atan = Math.atan;
|
||||
this.atanh = Math.atanh;
|
||||
this.cbrt = Math.cbrt;
|
||||
this.ceil = Math.ceil;
|
||||
this.clz32 = Math.clz32;
|
||||
this.cos = Math.cos;
|
||||
this.cosh = Math.cosh;
|
||||
this.exp = Math.exp;
|
||||
this.expm1 = Math.expm1;
|
||||
this.floor = Math.floor;
|
||||
this.fround = Math.fround;
|
||||
this.log = Math.log;
|
||||
this.log1p = Math.log1p;
|
||||
this.log10 = Math.log10;
|
||||
this.log2 = Math.log2;
|
||||
this.sign = Math.sign;
|
||||
this.sin = Math.sin;
|
||||
this.sinh = Math.sinh;
|
||||
this.sqrt = Math.sqrt;
|
||||
this.tan = Math.tan;
|
||||
this.tanh = Math.tanh;
|
||||
this.trunc = Math.trunc;
|
||||
|
||||
this.atan2 = Math.atan2;
|
||||
this.hypot = Math.hypot;
|
||||
this.imul = Math.imul;
|
||||
this.max = Math.max;
|
||||
this.min = Math.min;
|
||||
this.pow = Math.pow;
|
||||
|
||||
this.fib = (n) => { for (var r, c = 1, f = 0; n >= 0;)r = c, c += f, f = r, n--; return f };
|
||||
this.carea = (a) => { return a * a * Math.PI };
|
||||
this.fix = (n) => { return n < 0 ? Math.ceil(n) : n > 0 ? Math.floor(n) : n };
|
||||
this.cat = (n) => { if (n <= 1) return 1; let t = 0; for (let a = 0; a < n; n++)t += this.cat(a) * this.cat(n - a - 1); return t }
|
||||
|
||||
this.start("original");
|
||||
globalThis.ovoChaos = this;
|
||||
},
|
||||
|
||||
start(presetName = "original") {
|
||||
let preset = chaosPresets[presetName];
|
||||
|
||||
if (preset) {
|
||||
for (const [key, value] of Object.entries(preset)) {
|
||||
eval(`Math.${key} = this.${value}`)
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
stop() {
|
||||
Math.random = this.random;
|
||||
|
||||
Math.abs = this.abs;
|
||||
Math.acos = this.acos;
|
||||
Math.acosh = this.acosh;
|
||||
Math.asin = this.asin;
|
||||
Math.asinh = this.asinh;
|
||||
Math.atan = this.atan;
|
||||
Math.atanh = this.atanh;
|
||||
Math.cbrt = this.cbrt;
|
||||
Math.ceil = this.ceil;
|
||||
Math.clz32 = this.clz32;
|
||||
Math.cos = this.cos;
|
||||
Math.cosh = this.cosh;
|
||||
Math.exp = this.exp;
|
||||
Math.expm1 = this.expm1;
|
||||
Math.floor = this.floor;
|
||||
Math.fround = this.fround;
|
||||
Math.log = this.log;
|
||||
Math.log1p = this.log1p;
|
||||
Math.log10 = this.log10;
|
||||
Math.log2 = this.log2;
|
||||
Math.sign = this.sign;
|
||||
Math.sin = this.sin;
|
||||
Math.sinh = this.sinh;
|
||||
Math.sqrt = this.sqrt;
|
||||
Math.tan = this.tan;
|
||||
Math.tanh = this.tanh;
|
||||
Math.trunc = this.trunc;
|
||||
|
||||
Math.atan2 = this.atan2;
|
||||
Math.hypot = this.hypot;
|
||||
Math.imul = this.imul;
|
||||
Math.max = this.max;
|
||||
Math.min = this.min;
|
||||
Math.pow = this.pow;
|
||||
}
|
||||
}
|
||||
|
||||
chaos.init();
|
||||
})();
|
||||
@@ -0,0 +1,249 @@
|
||||
(function () {
|
||||
let modapi = {
|
||||
init() {
|
||||
this.game.init();
|
||||
this.ui.init();
|
||||
this.keybind.init();
|
||||
|
||||
globalThis.ovoModAPI = this;
|
||||
this.game.notify("Mod Loaded", "ModAPI mod loaded");
|
||||
},
|
||||
|
||||
math: {
|
||||
degreeToRadian(radians) {
|
||||
return (radians / 180) * Math.PI;
|
||||
},
|
||||
|
||||
radianToDegree(degrees) {
|
||||
return (180 / Math.PI) * degrees;
|
||||
},
|
||||
},
|
||||
|
||||
game: {
|
||||
init() {
|
||||
this.runtime = cr_getC2Runtime();
|
||||
},
|
||||
|
||||
notify(title, text, image = "./speedrunner.png") {
|
||||
cr.plugins_.sirg_notifications.prototype.acts.AddSimpleNotification.call(
|
||||
this.runtime.types_by_index.find(
|
||||
(type) => type.plugin instanceof cr.plugins_.sirg_notifications
|
||||
).instances[0],
|
||||
title,
|
||||
text,
|
||||
image
|
||||
);
|
||||
},
|
||||
|
||||
getPlayer() {
|
||||
return this.runtime.types_by_index
|
||||
.filter(
|
||||
(x) =>
|
||||
!!x.animations &&
|
||||
x.animations[0].frames[0].texture_file.includes("collider")
|
||||
)[0]
|
||||
.instances.filter(
|
||||
(x) => x.instance_vars[17] === "" && x.behavior_insts[0].enabled
|
||||
)[0];
|
||||
},
|
||||
|
||||
getFlag() {
|
||||
return this.runtime.types_by_index.find(
|
||||
(x) =>
|
||||
x.name === "EndFlag" ||
|
||||
(x.plugin instanceof cr.plugins_.Sprite &&
|
||||
x.all_frames &&
|
||||
x.all_frames[0].texture_file.includes("endflag"))
|
||||
).instances[0];
|
||||
},
|
||||
|
||||
getCoin() {
|
||||
return this.runtime.types_by_index.find(
|
||||
(x) =>
|
||||
x.name === "Coin" ||
|
||||
(x.plugin instanceof cr.plugins_.Sprite &&
|
||||
x.all_frames &&
|
||||
x.all_frames[0].texture_file.includes("coin"))
|
||||
).instances[0];
|
||||
},
|
||||
|
||||
getLayout(layoutName) {
|
||||
return this.runtime.layouts[layoutName] || this.runtime.running_layout;
|
||||
},
|
||||
|
||||
setLayout(layout) {
|
||||
this.runtime.changelayout = layout;
|
||||
},
|
||||
|
||||
getLayer(layerName = "Layer 0") {
|
||||
return this.runtime.running_layout.layers.find(x => x.name === layerName)
|
||||
},
|
||||
|
||||
layerScale(layer, scale) {
|
||||
layer.scale = scale;
|
||||
return layer;
|
||||
},
|
||||
|
||||
//platformScale(platform, scale) {
|
||||
// platform.behavior.my_types[0].all_frames.forEach((frame) => {
|
||||
// frame.height /= scale;
|
||||
// frame.width /= scale;
|
||||
// });
|
||||
//
|
||||
// platform.inst.height *= scale;
|
||||
// platform.inst.width *= scale;
|
||||
//
|
||||
// return platform;
|
||||
//},
|
||||
|
||||
moveInstance(instance, x, y) {
|
||||
instance.x = x;
|
||||
instance.y = y;
|
||||
instance.set_bbox_changed();
|
||||
return instance;
|
||||
},
|
||||
|
||||
rotateInstance(instance, angle) {
|
||||
instance.angle = (angle / 180) * Math.PI;
|
||||
instance.set_bbox_changed();
|
||||
return instance;
|
||||
},
|
||||
|
||||
resizeInstance(instance, width, height) {
|
||||
instance.width = width;
|
||||
instance.height = height;
|
||||
instance.set_bbox_changed();
|
||||
return instance;
|
||||
},
|
||||
|
||||
instanceOpacity(instance, opacity) {
|
||||
instance.opacity = opacity;
|
||||
return instance;
|
||||
},
|
||||
|
||||
destroyInstance(instance) {
|
||||
this.runtime.DestroyInstance(instance);
|
||||
},
|
||||
|
||||
createSolid(x, y, width, height, angle, layerName = "Layer 0") {
|
||||
let solidType = this.runtime.types_by_index.find(x => x.plugin instanceof cr.plugins_.TiledBg && x.texture_file && x.texture_file.includes("/solid.png") && x.behs_count === 2)
|
||||
let layer = this.runtime.running_layout.layers.find(x => x.name === layerName)
|
||||
|
||||
let solid = this.runtime.createInstance(solidType, layer, x, y)
|
||||
solid.width = width || solid.width;
|
||||
solid.height = height || solid.height;;
|
||||
solid.angle = angle || solid.angle;
|
||||
solid.set_bbox_changed();
|
||||
return solid;
|
||||
},
|
||||
|
||||
createSprite(x, y, width, height, angle, spriteName = "", layerName = "Layer 0") {
|
||||
let spriteType = this.runtime.types_by_index.find(x => x.plugin instanceof cr.plugins_.Sprite && x.all_frames && x.all_frames[0].texture_file.includes(spriteName))
|
||||
let layer = this.runtime.running_layout.layers.find(x => x.name === layerName)
|
||||
|
||||
let sprite = this.runtime.createInstance(spriteType, layer, x, y)
|
||||
sprite.width = width || sprite.width;
|
||||
sprite.height = height || sprite.height;;
|
||||
sprite.angle = angle || sprite.angle;
|
||||
sprite.set_bbox_changed();
|
||||
return sprite;
|
||||
},
|
||||
|
||||
isInLevel() {
|
||||
return this.runtime.running_layout.name.startsWith("Level")
|
||||
},
|
||||
|
||||
isPaused() {
|
||||
if (this.isInLevel()) return this.runtime.running_layout.layers.find(function (a) {
|
||||
return "Pause" === a.name
|
||||
}).visible
|
||||
},
|
||||
},
|
||||
|
||||
ui: {
|
||||
init() {
|
||||
|
||||
}
|
||||
},
|
||||
|
||||
keybind: {
|
||||
init() {
|
||||
//this.events = [[name, callback, code, {"alt": event.altKey, "ctrl": event.ctrlKey, "meta": event.metaKey, "shift": event.shiftKey}]]
|
||||
this.events = [];
|
||||
//this.events.push({name: "Test", callback: () => {console.log("YEY");}, key: "G", modifiers: {shift: true}})
|
||||
|
||||
document.addEventListener("keydown", (event) => {
|
||||
this.events.forEach((keybind) => {
|
||||
if (event.key.toLowerCase() == keybind.key.toLowerCase() && !event.isComposing && (!!keybind.modifiers.alt == event.altKey && !!keybind.modifiers.ctrl == event.ctrlKey && !!keybind.modifiers.meta == event.metaKey && !!keybind.modifiers.shift == event.shiftKey)) {
|
||||
console.log("here1")
|
||||
keybind.callback(event);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
modapi.init();
|
||||
})();
|
||||
|
||||
|
||||
(function () {
|
||||
let old = globalThis.sdk_runtime;
|
||||
c2_callFunction("execCode", ["globalThis.sdk_runtime = this.runtime"]);
|
||||
let runtime = globalThis.sdk_runtime;
|
||||
globalThis.sdk_runtime = old;
|
||||
|
||||
let notify = (title, text, image = "./speedrunner.png") => {
|
||||
cr.plugins_.sirg_notifications.prototype.acts.AddSimpleNotification.call(
|
||||
runtime.types_by_index.find(
|
||||
(type) => type.plugin instanceof cr.plugins_.sirg_notifications
|
||||
).instances[0],
|
||||
title,
|
||||
text,
|
||||
image
|
||||
);
|
||||
};
|
||||
|
||||
let collision = {
|
||||
init() {
|
||||
document.addEventListener("keydown", (event) => {
|
||||
if (event.code === "KeyQ") {
|
||||
if (event.shiftKey) {
|
||||
this.loadCollisionOn();
|
||||
}
|
||||
}
|
||||
if (event.code === "KeyW") {
|
||||
if (event.shiftKey) {
|
||||
this.loadCollisionOff();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
this.interval = null;
|
||||
globalThis.ovoCollision = this;
|
||||
notify("Mod loaded", "Collision mod loaded");
|
||||
},
|
||||
|
||||
loadCollisionOn() {
|
||||
ovoModAPI.game.getPlayer().angle = 0 * (Math.PI / 180);
|
||||
},
|
||||
loadCollisionOff() {
|
||||
ovoModAPI.game.getPlayer().angle = undefined;
|
||||
},
|
||||
startCycle(time) {
|
||||
if (!this.interval) {
|
||||
this.interval = setInterval(this.loadCollisionOn, time); (this.loadCollisionOff, time + time);
|
||||
}
|
||||
},
|
||||
|
||||
stopCycle() {
|
||||
if (this.interval) {
|
||||
clearInterval(this.interval);
|
||||
this.interval = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
collision.init();
|
||||
})()
|
||||
@@ -0,0 +1,18 @@
|
||||
(function () {
|
||||
// create a div element
|
||||
const div = document.createElement("div");
|
||||
|
||||
// set styles for the div element
|
||||
div.style.width = "100%";
|
||||
div.style.height = "100%";
|
||||
div.style.position = "fixed";
|
||||
div.style.top = "0";
|
||||
div.style.left = "0";
|
||||
div.style.mixBlendMode = "difference";
|
||||
div.style.backgroundColor = "white";
|
||||
div.style.zIndex = "99999"; // set an extremely high z-index value
|
||||
div.style.pointerEvents = "none"; // make the div pass events to the items below it
|
||||
|
||||
// add the div element to the body of the webpage
|
||||
document.body.appendChild(div);
|
||||
})();
|
||||
@@ -0,0 +1,229 @@
|
||||
(function () {
|
||||
let old = globalThis.sdk_runtime;
|
||||
c2_callFunction("execCode", ["globalThis.sdk_runtime = this.runtime"]);
|
||||
let runtime = globalThis.sdk_runtime;
|
||||
globalThis.sdk_runtime = old;
|
||||
targetY = null;
|
||||
let prevY = 0;
|
||||
let prevSm = 0;
|
||||
let prevS = 0;
|
||||
let xprevY = 0;
|
||||
let xprevSm = 0;
|
||||
let xprevS = 0;
|
||||
let sex = new Date();
|
||||
let sexs = sex.getMilliseconds();
|
||||
let timescale = 1;
|
||||
let rounder = 5;
|
||||
let showPosition = {
|
||||
tick() {
|
||||
if (
|
||||
!cr_getC2Runtime().running_layout.layers.find(function (a) {
|
||||
return "Pause" === a.name;
|
||||
}).visible
|
||||
) {
|
||||
cr_getC2Runtime().timescale = timescale;
|
||||
try {
|
||||
if (timescale > 0) {
|
||||
deeznuts();
|
||||
}
|
||||
} catch (err) { }
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
function deeznuts() {
|
||||
let baka = timescale == 0 ? 1 : timescale
|
||||
let playerInstances = runtime.types_by_index
|
||||
.filter(
|
||||
(x) =>
|
||||
!!x.animations &&
|
||||
x.animations[0].frames[0].texture_file.includes("collider")
|
||||
)[0]
|
||||
.instances.filter(
|
||||
(x) => x.instance_vars[17] === "" && x.behavior_insts[0].enabled
|
||||
);
|
||||
let player = playerInstances[0];
|
||||
let sex = new Date();
|
||||
let sexsincelast = sex.getMilliseconds() - sexs;
|
||||
|
||||
document.getElementById("69").innerText =
|
||||
"Timescale: " +
|
||||
timescale +
|
||||
"\n" +
|
||||
"\n" +
|
||||
"x: " +
|
||||
balls(player.x, rounder).toString() +
|
||||
"\n" +
|
||||
"y: " +
|
||||
balls(player.y, rounder).toString() +
|
||||
"\n" +
|
||||
"\n" +
|
||||
"Vertical Speed: " +
|
||||
"\n" +
|
||||
"p/ms: " +
|
||||
balls((player.y - prevY) / sexsincelast / baka, rounder).toString() +
|
||||
"\n" +
|
||||
"A/ms: " +
|
||||
balls(
|
||||
prevS - (player.y - prevY) / sexsincelast / baka,
|
||||
rounder
|
||||
).toString() +
|
||||
"\n" +
|
||||
"p/f: " +
|
||||
balls((player.y - prevY) / baka, rounder).toString() +
|
||||
"\n" +
|
||||
"A/f: " +
|
||||
balls(prevSm - (player.y - prevY) / baka, rounder).toString() +
|
||||
"\n" +
|
||||
"\n" +
|
||||
//Owa oaw------------------------------------------
|
||||
"Horizontal Speed: " +
|
||||
"\n" +
|
||||
"p/ms: " +
|
||||
balls(
|
||||
(player.x - xprevY) / sexsincelast / baka,
|
||||
rounder
|
||||
).toString() +
|
||||
"\n" +
|
||||
"A/ms: " +
|
||||
balls(
|
||||
xprevS - (player.x - xprevY) / sexsincelast / baka,
|
||||
rounder
|
||||
).toString() +
|
||||
"\n" +
|
||||
"p/f: " +
|
||||
balls((player.x - xprevY) / baka, rounder).toString() +
|
||||
"\n" +
|
||||
"A/f: " +
|
||||
balls(xprevSm - (player.x - xprevY) / baka, rounder).toString() +
|
||||
"\n" +
|
||||
"\n" +
|
||||
"PPms: " +
|
||||
balls(player.x + xprevS, rounder).toString() +
|
||||
", " +
|
||||
balls(player.y + prevS, rounder).toString() +
|
||||
"\n" +
|
||||
"PPf: " +
|
||||
balls(player.x + xprevSm, rounder).toString() +
|
||||
", " +
|
||||
balls(player.y + prevSm, rounder).toString() +
|
||||
"\n" +
|
||||
"\n" +
|
||||
"ms/f:" +
|
||||
sexsincelast.toString() +
|
||||
"\n" +
|
||||
"A ms/f:" +
|
||||
sexsincelast.toString() * baka;
|
||||
|
||||
prevSm = (player.y - prevY) / baka;
|
||||
prevS = (player.y - prevY) / sexsincelast / baka;
|
||||
prevY = player.y;
|
||||
|
||||
xprevS = (player.x - xprevY) / sexsincelast / baka;
|
||||
xprevSm = (player.x - xprevY) / baka;
|
||||
xprevY = player.x;
|
||||
|
||||
sexs = sex.getMilliseconds();
|
||||
}
|
||||
|
||||
function balls(b, af) {
|
||||
return Math.round(b * 10 ** af) / 10 ** af;
|
||||
}
|
||||
let fly = {
|
||||
tick() {
|
||||
let playerInstances = runtime.types_by_index
|
||||
.filter(
|
||||
(x) =>
|
||||
!!x.animations &&
|
||||
x.animations[0].frames[0].texture_file.includes("collider")
|
||||
)[0]
|
||||
.instances.filter(
|
||||
(x) => x.instance_vars[17] === "" && x.behavior_insts[0].enabled
|
||||
);
|
||||
let player = playerInstances[0];
|
||||
try {
|
||||
player.y = targetY;
|
||||
} catch (err) { }
|
||||
},
|
||||
};
|
||||
|
||||
var b = document.createElement("div"),
|
||||
c = {
|
||||
backgroundColor: "rgba(150,10,1,0.7)",
|
||||
width: "500px",
|
||||
height: "600px",
|
||||
position: "absolute",
|
||||
top: "100px",
|
||||
left: "100px",
|
||||
fontSize: "x-large",
|
||||
};
|
||||
Object.keys(c).forEach(function (a) {
|
||||
b.style[a] = c[a];
|
||||
});
|
||||
b.id = 69;
|
||||
const newContent = document.createTextNode("poggers");
|
||||
|
||||
// add the text node to the newly created div
|
||||
b.appendChild(newContent);
|
||||
|
||||
document.body.appendChild(b);
|
||||
|
||||
g = globalThis.ovoExplorer = {
|
||||
init: function () {
|
||||
runtime.tickMe(showPosition);
|
||||
},
|
||||
|
||||
trackOvO: function (a) {
|
||||
a ? runtime.tickMe(showPosition) : runtime.untickMe(showPosition);
|
||||
},
|
||||
step: function () {
|
||||
var a = cr_getC2Runtime().timescale;
|
||||
cr_getC2Runtime().timescale = 1;
|
||||
cr_getC2Runtime().tick(!0, null, null);
|
||||
cr_getC2Runtime().timescale = a;
|
||||
deeznuts();
|
||||
},
|
||||
suspend: function () {
|
||||
cr_getC2Runtime().timescale = 0;
|
||||
timescale = 0;
|
||||
},
|
||||
updateTimescale: function (a) {
|
||||
timescale = a;
|
||||
cr_getC2Runtime().timescale = a;
|
||||
},
|
||||
setRoundDigits: function (a) {
|
||||
rounder = a;
|
||||
},
|
||||
warp: function (x, y) {
|
||||
targetY = y;
|
||||
let playerInstances = runtime.types_by_index
|
||||
.filter(
|
||||
(x) =>
|
||||
!!x.animations &&
|
||||
x.animations[0].frames[0].texture_file.includes("collider")
|
||||
)[0]
|
||||
.instances.filter(
|
||||
(x) => x.instance_vars[17] === "" && x.behavior_insts[0].enabled
|
||||
);
|
||||
let player = playerInstances[0];
|
||||
player.x = x;
|
||||
player.y = y;
|
||||
},
|
||||
|
||||
levitate: function (a) {
|
||||
let playerInstances = runtime.types_by_index
|
||||
.filter(
|
||||
(x) =>
|
||||
!!x.animations &&
|
||||
x.animations[0].frames[0].texture_file.includes("collider")
|
||||
)[0]
|
||||
.instances.filter(
|
||||
(x) => x.instance_vars[17] === "" && x.behavior_insts[0].enabled
|
||||
);
|
||||
let player = playerInstances[0];
|
||||
targetY = player.y;
|
||||
a ? runtime.tickMe(fly) : runtime.untickMe(fly);
|
||||
},
|
||||
};
|
||||
g.init();
|
||||
})();
|
||||
@@ -0,0 +1,138 @@
|
||||
(function () {
|
||||
let old = globalThis.sdk_runtime;
|
||||
c2_callFunction("execCode", ["globalThis.sdk_runtime = this.runtime"]);
|
||||
let runtime = globalThis.sdk_runtime;
|
||||
globalThis.sdk_runtime = old;
|
||||
|
||||
let getPlayer = () => {
|
||||
return runtime.types_by_index
|
||||
.filter(
|
||||
(x) =>
|
||||
!!x.animations &&
|
||||
x.animations[0].frames[0].texture_file.includes("collider")
|
||||
)[0]
|
||||
.instances.filter(
|
||||
(x) => x.instance_vars[17] === "" && x.behavior_insts[0].enabled
|
||||
)[0];
|
||||
}
|
||||
|
||||
let notify = (title, text, image = "./speedrunner.png") => {
|
||||
cr.plugins_.sirg_notifications.prototype.acts.AddSimpleNotification.call(
|
||||
runtime.types_by_index.find(
|
||||
(type) => type.plugin instanceof cr.plugins_.sirg_notifications
|
||||
).instances[0],
|
||||
title,
|
||||
text,
|
||||
image
|
||||
);
|
||||
};
|
||||
|
||||
let flyMod = {
|
||||
init() {
|
||||
this.movementKeys = [false, false, false, false];
|
||||
this.activatorKeyHeld = false;
|
||||
this.activated = false;
|
||||
this.speed = { x: 10, y: 10 };
|
||||
this.stored = [1500, true];
|
||||
this.override = false;
|
||||
|
||||
document.addEventListener("keydown", (event) => { this.keyDown(event) });
|
||||
document.addEventListener("keyup", (event) => { this.keyUp(event) });
|
||||
|
||||
runtime.tickMe(this);
|
||||
|
||||
globalThis.ovoFlyMod = this;
|
||||
},
|
||||
|
||||
keyDown(event) {
|
||||
let key = event.key.toLowerCase();
|
||||
|
||||
if (key == "control" && !this.override) {
|
||||
this.activatorKeyHeld = true;
|
||||
} else if (event.keyCode >= 37 && event.keyCode <= 40 && this.activatorKeyHeld) {
|
||||
if (!this.activated) {
|
||||
this.startActivation();
|
||||
this.activated = true;
|
||||
}
|
||||
|
||||
this.movementKeys[event.keyCode - 37] = true;
|
||||
}
|
||||
},
|
||||
|
||||
keyUp(event) {
|
||||
let key = event.key.toLowerCase();
|
||||
|
||||
if (key == "control" && this.activatorKeyHeld) {
|
||||
this.activatorKeyHeld = false;
|
||||
|
||||
if (this.activated) {
|
||||
this.movementKeys = [false, false, false, false];
|
||||
this.activated = false;
|
||||
this.endActivation();
|
||||
}
|
||||
} else if (event.keyCode >= 37 && event.keyCode <= 40 && this.activatorKeyHeld) {
|
||||
this.movementKeys[event.keyCode - 37] = false;
|
||||
}
|
||||
},
|
||||
|
||||
startActivation() {
|
||||
let player = getPlayer();
|
||||
|
||||
if (player) {
|
||||
this.stored = [player.behavior_insts[0].g, player.collisionsEnabled];
|
||||
} else {
|
||||
this.stored = [1500, true];
|
||||
}
|
||||
|
||||
notify("Fly Mod", "Fly Enabled");
|
||||
},
|
||||
|
||||
endActivation() {
|
||||
let player = getPlayer();
|
||||
|
||||
if (player) {
|
||||
player.behavior_insts[0].g = this.stored[0];
|
||||
player.collisionsEnabled = this.stored[1];
|
||||
}
|
||||
|
||||
notify("Fly Mod", "Fly Disabled");
|
||||
},
|
||||
|
||||
speedX(speed) {
|
||||
this.speed.x = speed;
|
||||
},
|
||||
|
||||
speedY(speed) {
|
||||
this.speed.y = speed;
|
||||
},
|
||||
|
||||
setSpeed(speed) {
|
||||
this.speed.x = speed;
|
||||
this.speed.y = speed;
|
||||
},
|
||||
|
||||
setOverride(value) {
|
||||
this.override = !!value;
|
||||
},
|
||||
|
||||
tick() {
|
||||
if (this.activated) {
|
||||
let player = getPlayer();
|
||||
|
||||
if (player) {
|
||||
if (!!player.behavior_insts[0].g || player.collisionsEnabled) {
|
||||
player.behavior_insts[0].g = 0;
|
||||
player.collisionsEnabled = false
|
||||
}
|
||||
|
||||
let moveX = this.movementKeys[2] - this.movementKeys[0];
|
||||
let moveY = this.movementKeys[3] - this.movementKeys[1];
|
||||
player.x += moveX * this.speed.x;
|
||||
player.y += moveY * this.speed.y;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
flyMod.init();
|
||||
})();
|
||||
@@ -0,0 +1,38 @@
|
||||
(function () {
|
||||
let old = globalThis.sdk_runtime;
|
||||
c2_callFunction("execCode", ["globalThis.sdk_runtime = this.runtime"]);
|
||||
let runtime = globalThis.sdk_runtime;
|
||||
globalThis.sdk_runtime = old;
|
||||
|
||||
let notify = (title, text, image = "./speedrunner.png") => {
|
||||
cr.plugins_.sirg_notifications.prototype.acts.AddSimpleNotification.call(
|
||||
runtime.types_by_index.find(
|
||||
(type) => type.plugin instanceof cr.plugins_.sirg_notifications
|
||||
).instances[0],
|
||||
title,
|
||||
text,
|
||||
image
|
||||
);
|
||||
};
|
||||
|
||||
let gyro = {
|
||||
init() {
|
||||
globalThis.ovoGyro = this;
|
||||
|
||||
if (window.DeviceOrientationEvent) {
|
||||
window.addEventListener("deviceorientation", (event) => { this.updateGyro });
|
||||
} else {
|
||||
notify("Gyro", "This device does not support gyroscope");
|
||||
}
|
||||
},
|
||||
|
||||
updateGyro(event) {
|
||||
let absolute = event.absolute;
|
||||
let alpha = event.alpha;
|
||||
let beta = event.beta;
|
||||
let gamma = event.gamma;
|
||||
}
|
||||
};
|
||||
|
||||
gyro.init();
|
||||
})();
|
||||
@@ -0,0 +1,46 @@
|
||||
(function () {
|
||||
let old = globalThis.sdk_runtime;
|
||||
c2_callFunction("execCode", ["globalThis.sdk_runtime = this.runtime"]);
|
||||
let runtime = globalThis.sdk_runtime;
|
||||
globalThis.sdk_runtime = old;
|
||||
let counter = 0;
|
||||
|
||||
let wind = {
|
||||
tick() {
|
||||
let playerInstances = runtime.types_by_index
|
||||
.filter(
|
||||
(x) =>
|
||||
!!x.animations &&
|
||||
x.animations[0].frames[0].texture_file.includes("collider")
|
||||
)[0]
|
||||
.instances.filter(
|
||||
(x) => x.instance_vars[17] === "" && x.behavior_insts[0].enabled
|
||||
);
|
||||
let player = playerInstances[0];
|
||||
try {
|
||||
counter++;
|
||||
switch (Math.floor((counter % 2000) / 500)) {
|
||||
case 0:
|
||||
player.x = player.x - 1;
|
||||
break;
|
||||
case 1:
|
||||
player.x = player.x + 1;
|
||||
break;
|
||||
case 2:
|
||||
player.y = player.y - 3;
|
||||
break;
|
||||
case 3:
|
||||
player.y = player.y + 3;
|
||||
break;
|
||||
}
|
||||
} catch (err) { }
|
||||
},
|
||||
};
|
||||
|
||||
g = globalThis.ovoExplorer = {
|
||||
init: function () {
|
||||
runtime.tickMe(wind);
|
||||
},
|
||||
};
|
||||
g.init();
|
||||
})();
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
@@ -0,0 +1,198 @@
|
||||
// new features: onLevelLoad
|
||||
// onbboxchanged
|
||||
// speed
|
||||
// Math.round(Math.sqrt(Math.pow(player.behavior_insts[0].dx, 2) + Math.pow(player.behavior_insts[0].dy, 2)));
|
||||
|
||||
(function () {
|
||||
const modapi = {
|
||||
init() {
|
||||
this.game.init();
|
||||
this.ui.init();
|
||||
this.keybind.init();
|
||||
|
||||
globalThis.ovoModAPI = this;
|
||||
},
|
||||
|
||||
game: {
|
||||
init() {
|
||||
this.runtime = cr_getC2Runtime();
|
||||
},
|
||||
|
||||
tick(functionToTick) {
|
||||
const tick = {
|
||||
tick() {
|
||||
functionToTick();
|
||||
}
|
||||
}
|
||||
|
||||
this.runtime.tickMe(tick);
|
||||
},
|
||||
|
||||
getGameValues() {
|
||||
return {
|
||||
tickCount: this.runtime.tickcount,
|
||||
fps: this.runtime.fps,
|
||||
frameCount: this.runtime.framecount,
|
||||
deltaTime: this.runtime.dt,
|
||||
width: this.runtime.width,
|
||||
height: this.runtime.height,
|
||||
};
|
||||
},
|
||||
|
||||
notify(title, text, image = "./speedrunner.png") {
|
||||
cr.plugins_.sirg_notifications.prototype.acts.AddSimpleNotification.call(
|
||||
this.runtime.types_by_index.find(
|
||||
(type) => type.plugin instanceof cr.plugins_.sirg_notifications
|
||||
).instances[0],
|
||||
title,
|
||||
text,
|
||||
image
|
||||
);
|
||||
},
|
||||
|
||||
getPlayer() {
|
||||
return this.runtime.types_by_index
|
||||
.filter(
|
||||
(x) =>
|
||||
!!x.animations &&
|
||||
x.animations[0].frames[0].texture_file.includes("collider")
|
||||
)[0]
|
||||
.instances.filter(
|
||||
(x) => x.instance_vars[17] === "" && x.behavior_insts[0].enabled
|
||||
)[0];
|
||||
},
|
||||
|
||||
getFlag() {
|
||||
return this.runtime.types_by_index.find(
|
||||
(x) =>
|
||||
x.name === "EndFlag" ||
|
||||
(x.plugin instanceof cr.plugins_.Sprite &&
|
||||
x.all_frames &&
|
||||
x.all_frames[0].texture_file.includes("endflag"))
|
||||
).instances[0];
|
||||
},
|
||||
|
||||
getCoin() {
|
||||
return this.runtime.types_by_index.find(
|
||||
(x) =>
|
||||
x.name === "Coin" ||
|
||||
(x.plugin instanceof cr.plugins_.Sprite &&
|
||||
x.all_frames &&
|
||||
x.all_frames[0].texture_file.includes("coin"))
|
||||
).instances[0];
|
||||
},
|
||||
|
||||
getLayout(layoutName) {
|
||||
return this.runtime.layouts[layoutName] || this.runtime.running_layout;
|
||||
},
|
||||
|
||||
setLayout(layout) {
|
||||
this.runtime.changelayout = layout;
|
||||
},
|
||||
|
||||
getLayer(layerName = "Layer 0") {
|
||||
return this.runtime.running_layout.layers.find(x => x.name === layerName)
|
||||
},
|
||||
|
||||
layerScale(layer, scale) {
|
||||
layer.scale = scale;
|
||||
return layer;
|
||||
},
|
||||
|
||||
//platformScale(platform, scale) {
|
||||
// platform.behavior.my_types[0].all_frames.forEach((frame) => {
|
||||
// frame.height /= scale;
|
||||
// frame.width /= scale;
|
||||
// });
|
||||
//
|
||||
// platform.inst.height *= scale;
|
||||
// platform.inst.width *= scale;
|
||||
//
|
||||
// return platform;
|
||||
//},
|
||||
|
||||
moveInstance(instance, x, y) {
|
||||
instance.x = x;
|
||||
instance.y = y;
|
||||
instance.set_bbox_changed();
|
||||
return instance;
|
||||
},
|
||||
|
||||
rotateInstance(instance, angle) {
|
||||
instance.angle = modapi.math.degreeToRadian(angle);
|
||||
instance.set_bbox_changed();
|
||||
return instance;
|
||||
},
|
||||
|
||||
resizeInstance(instance, width, height) {
|
||||
instance.width = width;
|
||||
instance.height = height;
|
||||
instance.set_bbox_changed();
|
||||
return instance;
|
||||
},
|
||||
|
||||
instanceOpacity(instance, opacity) {
|
||||
instance.opacity = opacity;
|
||||
return instance;
|
||||
},
|
||||
|
||||
destroyInstance(instance) {
|
||||
this.runtime.DestroyInstance(instance);
|
||||
},
|
||||
|
||||
createSolid(x, y, width, height, angle, layer) {
|
||||
const solidType = this.runtime.types_by_index.find(x => x.plugin instanceof cr.plugins_.TiledBg && x.texture_file && x.texture_file.includes("/solid.png") && x.behs_count === 2);
|
||||
|
||||
const solid = this.runtime.createInstance(solidType, layer, x, y);
|
||||
solid.width = width || solid.width;
|
||||
solid.height = height || solid.height;;
|
||||
solid.angle = angle || solid.angle;
|
||||
solid.set_bbox_changed();
|
||||
return solid;
|
||||
},
|
||||
|
||||
createSprite(x, y, width, height, angle, spriteName, layer) {
|
||||
const spriteType = this.runtime.types_by_index.find(x => x.plugin instanceof cr.plugins_.Sprite && x.all_frames && x.all_frames[0].texture_file.includes(spriteName));
|
||||
|
||||
const sprite = this.runtime.createInstance(spriteType, layer, x, y);
|
||||
sprite.width = width || sprite.width;
|
||||
sprite.height = height || sprite.height;;
|
||||
sprite.angle = angle || sprite.angle;
|
||||
sprite.set_bbox_changed();
|
||||
return sprite;
|
||||
},
|
||||
|
||||
isInLevel() {
|
||||
return this.runtime.running_layout.name.startsWith("Level")
|
||||
},
|
||||
|
||||
isPaused() {
|
||||
if (this.isInLevel()) return this.runtime.running_layout.layers.find(function (a) {
|
||||
return "Pause" === a.name
|
||||
}).visible
|
||||
},
|
||||
},
|
||||
|
||||
ui: {
|
||||
init() {
|
||||
|
||||
}
|
||||
},
|
||||
|
||||
keybind: {
|
||||
init() {
|
||||
this.events = [];
|
||||
|
||||
document.addEventListener("keydown", (event) => {
|
||||
this.events.forEach((keybind) => {
|
||||
if (event.key.toLowerCase() == keybind.key.toLowerCase() && !event.isComposing && (!!keybind.modifiers.alt == event.altKey && !!keybind.modifiers.ctrl == event.ctrlKey && !!keybind.modifiers.meta == event.metaKey && !!keybind.modifiers.shift == event.shiftKey)) {
|
||||
keybind.callback(event);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
modapi.init();
|
||||
})();
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,80 @@
|
||||
(function () {
|
||||
let old = globalThis.sdk_runtime;
|
||||
c2_callFunction("execCode", ["globalThis.sdk_runtime = this.runtime"]);
|
||||
let runtime = globalThis.sdk_runtime;
|
||||
globalThis.sdk_runtime = old;
|
||||
|
||||
let stored = [1500, true];
|
||||
let go = false;
|
||||
let held = [false, false, false, false];
|
||||
let xSpeed = 10;
|
||||
let ySpeed = 10;
|
||||
let getPlayer = () => {
|
||||
return runtime.types_by_index
|
||||
.filter(
|
||||
(x) =>
|
||||
!!x.animations &&
|
||||
x.animations[0].frames[0].texture_file.includes("collider")
|
||||
)[0]
|
||||
.instances.filter(
|
||||
(x) => x.instance_vars[17] === "" && x.behavior_insts[0].enabled
|
||||
)[0];
|
||||
}
|
||||
let ba = {
|
||||
tick() {
|
||||
try {
|
||||
let player = getPlayer();
|
||||
if (go) {
|
||||
moveX = held[2] - held[0];
|
||||
moveY = held[3] - held[1];
|
||||
player.behavior_insts[0].dx = 0;
|
||||
player.behavior_insts[0].dy = 0;
|
||||
player.behavior_insts[0].g = 0;
|
||||
player.collisionsEnabled = false
|
||||
player.x += moveX * xSpeed;
|
||||
player.y += moveY * ySpeed;
|
||||
} else { }
|
||||
} catch (err) { }
|
||||
},
|
||||
};
|
||||
|
||||
g = globalThis.FlyMod = {
|
||||
xSpeed: function (a) {
|
||||
xSpeed = a;
|
||||
},
|
||||
|
||||
ySpeed: function (a) {
|
||||
ySpeed = a;
|
||||
},
|
||||
}
|
||||
|
||||
runtime.tickMe(ba);
|
||||
|
||||
|
||||
document.addEventListener("keydown", function (event) {
|
||||
if (event.keyCode >= 37 && event.keyCode <= 40) {
|
||||
held[event.keyCode - 37] = true;
|
||||
}
|
||||
if (event.keyCode == 16) {
|
||||
let player = getPlayer();
|
||||
if (player) {
|
||||
stored = [player.behavior_insts[0].g, player.collisionsEnabled];
|
||||
}
|
||||
go = true;
|
||||
}
|
||||
});
|
||||
|
||||
document.addEventListener("keyup", function (event) {
|
||||
if (event.keyCode >= 37 && event.keyCode <= 40) {
|
||||
held[event.keyCode - 37] = false;
|
||||
}
|
||||
if (event.keyCode == 16) {
|
||||
go = false;
|
||||
let player = getPlayer();
|
||||
if (player) {
|
||||
player.behavior_insts[0].g = stored[0];
|
||||
player.collisionsEnabled = stored[1];
|
||||
}
|
||||
}
|
||||
});
|
||||
})();
|
||||
@@ -0,0 +1,77 @@
|
||||
(function () {
|
||||
const imagePosition = {
|
||||
x: 0,
|
||||
y: 0
|
||||
};
|
||||
const pixelSize = 5;
|
||||
const collisionsEnabled = false;
|
||||
const advancedCollisions = true;
|
||||
const enableAlpha = true;
|
||||
const layerName = "Layer 0";
|
||||
|
||||
const inputElement = document.createElement("input");
|
||||
inputElement.type = "file";
|
||||
inputElement.accept = "image/webp, image/png, image/jpeg";
|
||||
inputElement.addEventListener("change", handleFiles, false);
|
||||
|
||||
function handleFiles() {
|
||||
const fileList = this.files;
|
||||
if (fileList.length > 0) {
|
||||
const file = fileList[0];
|
||||
const reader = new FileReader();
|
||||
reader.onload = function (e) {
|
||||
const img = new Image();
|
||||
img.onload = function () {
|
||||
const canvas = document.createElement("canvas");
|
||||
canvas.width = img.width;
|
||||
canvas.height = img.height;
|
||||
const ctx = canvas.getContext("2d");
|
||||
|
||||
const newWidth = 120;
|
||||
const newHeight = Math.round(img.height * 120 / img.width);
|
||||
ctx.drawImage(img, 0, 0, newWidth, newHeight);
|
||||
const data = ctx.getImageData(0, 0, newWidth, newHeight).data;
|
||||
|
||||
const layer = ovoModAPI.game.getLayer(layerName);
|
||||
|
||||
if (!enableAlpha) {
|
||||
const solidType = cr_getC2Runtime().types_by_index.find(x => x.texture_file && x.texture_file.includes("solid2"));
|
||||
const whiteSolid = cr_getC2Runtime().createInstance(solidType, layer, 0, 0);
|
||||
ovoModAPI.game.resizeInstance(whiteSolid, newWidth * pixelSize + imagePosition.x, newHeight * pixelSize + imagePosition.y);
|
||||
whiteSolid.collisionsEnabled = collisionsEnabled;
|
||||
}
|
||||
|
||||
for (let x = 0; x < newWidth; x++) {
|
||||
for (let y = 0; y < newHeight; y++) {
|
||||
const position = (y * newWidth + x) * 4;
|
||||
const average = (data[position] + data[position + 1] + data[position + 2]) / 3;
|
||||
|
||||
if (average === 255) continue;
|
||||
|
||||
const inst = ovoModAPI.game.createSolid(x * pixelSize + imagePosition.x, y * pixelSize + imagePosition.y, pixelSize, pixelSize, 0, layer);
|
||||
|
||||
if (advancedCollisions && average < 127) {
|
||||
inst.collisionsEnabled = true;
|
||||
} else {
|
||||
inst.collisionsEnabled = false;
|
||||
}
|
||||
|
||||
inst.opacity = 1 - average / 255;
|
||||
}
|
||||
}
|
||||
};
|
||||
img.src = e.target.result;
|
||||
};
|
||||
reader.readAsDataURL(file);
|
||||
}
|
||||
}
|
||||
|
||||
const button = document.createElement("button");
|
||||
button.innerText = "Open file picker";
|
||||
button.style.position = "absolute";
|
||||
button.style.top = "0";
|
||||
button.style.left = "0";
|
||||
button.style.zIndex = "99999";
|
||||
button.addEventListener("click", () => inputElement.click());
|
||||
document.body.appendChild(button);
|
||||
})();
|
||||
@@ -0,0 +1,25 @@
|
||||
(function () {
|
||||
let old = globalThis.sdk_runtime;
|
||||
c2_callFunction("execCode", ["globalThis.sdk_runtime = this.runtime"]);
|
||||
let runtime = globalThis.sdk_runtime;
|
||||
globalThis.sdk_runtime = old;
|
||||
|
||||
let notify = (title, text, image = "./speedrunner.png") => {
|
||||
cr.plugins_.sirg_notifications.prototype.acts.AddSimpleNotification.call(
|
||||
runtime.types_by_index.find(
|
||||
(type) => type.plugin instanceof cr.plugins_.sirg_notifications
|
||||
).instances[0],
|
||||
title,
|
||||
text,
|
||||
image
|
||||
);
|
||||
};
|
||||
|
||||
let randomKeys = {
|
||||
init() {
|
||||
this.availibleKeys = []
|
||||
|
||||
globalThis.ovoRandomKeys = this;
|
||||
}
|
||||
}
|
||||
})();
|
||||
@@ -0,0 +1,51 @@
|
||||
(function () {
|
||||
let old = globalThis.sdk_runtime;
|
||||
c2_callFunction("execCode", ["globalThis.sdk_runtime = this.runtime"]);
|
||||
let runtime = globalThis.sdk_runtime;
|
||||
globalThis.sdk_runtime = old;
|
||||
|
||||
let notify = (title, text, image = "./speedrunner.png") => {
|
||||
cr.plugins_.sirg_notifications.prototype.acts.AddSimpleNotification.call(
|
||||
runtime.types_by_index.find(
|
||||
(type) => type.plugin instanceof cr.plugins_.sirg_notifications
|
||||
).instances[0],
|
||||
title,
|
||||
text,
|
||||
image
|
||||
);
|
||||
};
|
||||
|
||||
let randomlevel = {
|
||||
init() {
|
||||
document.addEventListener("keydown", (event) => {
|
||||
if (event.code === "KeyY") {
|
||||
if (event.shiftKey) {
|
||||
this.loadRandomLevel();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
this.interval = null;
|
||||
globalThis.ovoRandomLevel = this;
|
||||
},
|
||||
|
||||
loadRandomLevel() {
|
||||
runtime.changelayout = runtime.layouts[Object.keys(runtime.layouts)[Math.floor(Math.random() * Object.keys(runtime.layouts).length)]]
|
||||
},
|
||||
|
||||
startCycle(time) {
|
||||
if (!this.interval) {
|
||||
this.interval = setInterval(this.loadRandomLevel, time);
|
||||
}
|
||||
},
|
||||
|
||||
stopCycle() {
|
||||
if (this.interval) {
|
||||
clearInterval(this.interval);
|
||||
this.interval = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
randomlevel.init();
|
||||
})()
|
||||
@@ -0,0 +1,252 @@
|
||||
(function () {
|
||||
let old = globalThis.sdk_runtime;
|
||||
c2_callFunction("execCode", ["globalThis.sdk_runtime = this.runtime"]);
|
||||
let runtime = globalThis.sdk_runtime;
|
||||
globalThis.sdk_runtime = old;
|
||||
targetY = null;
|
||||
let showPosition = {
|
||||
tick() {
|
||||
let playerInstances = runtime.types_by_index
|
||||
.filter(
|
||||
(x) =>
|
||||
!!x.animations &&
|
||||
x.animations[0].frames[0].texture_file.includes("collider")
|
||||
)[0]
|
||||
.instances.filter(
|
||||
(x) => x.instance_vars[17] === "" && x.behavior_insts[0].enabled
|
||||
);
|
||||
let player = playerInstances[0];
|
||||
try {
|
||||
document.getElementById("pos").innerHTML =
|
||||
Math.round(player.x.toString()) +
|
||||
", " +
|
||||
Math.round(player.y.toString());
|
||||
} catch (err) { }
|
||||
},
|
||||
};
|
||||
|
||||
let fly = {
|
||||
tick() {
|
||||
let playerInstances = runtime.types_by_index
|
||||
.filter(
|
||||
(x) =>
|
||||
!!x.animations &&
|
||||
x.animations[0].frames[0].texture_file.includes("collider")
|
||||
)[0]
|
||||
.instances.filter(
|
||||
(x) => x.instance_vars[17] === "" && x.behavior_insts[0].enabled
|
||||
);
|
||||
let player = playerInstances[0];
|
||||
try {
|
||||
player.y = targetY;
|
||||
} catch (err) { }
|
||||
},
|
||||
};
|
||||
|
||||
var b = document.createElement("div"),
|
||||
c = {
|
||||
backgroundColor: "white",
|
||||
border: "solid",
|
||||
borderColor: "black",
|
||||
borderWidth: "6px",
|
||||
fontFamily: "Retron2000",
|
||||
position: "absolute",
|
||||
top: "115px",
|
||||
left: "86px",
|
||||
padding: "10px",
|
||||
color: "black",
|
||||
fontSize: "20pt",
|
||||
};
|
||||
Object.keys(c).forEach(function (a) {
|
||||
b.style[a] = c[a];
|
||||
});
|
||||
b.id = "pos";
|
||||
const newContent = document.createTextNode("N/A");
|
||||
|
||||
// add the text node to the newly created div
|
||||
b.appendChild(newContent);
|
||||
|
||||
document.body.appendChild(b);
|
||||
|
||||
g = globalThis.ovoExplorer = {
|
||||
init: function () {
|
||||
runtime.tickMe(showPosition);
|
||||
},
|
||||
|
||||
trackOvO: function (a) {
|
||||
a ? runtime.tickMe(showPosition) : runtime.untickMe(showPosition);
|
||||
},
|
||||
|
||||
warp: function (x, y) {
|
||||
targetY = y;
|
||||
let playerInstances = runtime.types_by_index
|
||||
.filter(
|
||||
(x) =>
|
||||
!!x.animations &&
|
||||
x.animations[0].frames[0].texture_file.includes("collider")
|
||||
)[0]
|
||||
.instances.filter(
|
||||
(x) => x.instance_vars[17] === "" && x.behavior_insts[0].enabled
|
||||
);
|
||||
let player = playerInstances[0];
|
||||
player.x = x;
|
||||
player.y = y;
|
||||
},
|
||||
|
||||
levitate: function (a) {
|
||||
let playerInstances = runtime.types_by_index
|
||||
.filter(
|
||||
(x) =>
|
||||
!!x.animations &&
|
||||
x.animations[0].frames[0].texture_file.includes("collider")
|
||||
)[0]
|
||||
.instances.filter(
|
||||
(x) => x.instance_vars[17] === "" && x.behavior_insts[0].enabled
|
||||
);
|
||||
let player = playerInstances[0];
|
||||
targetY = player.y;
|
||||
a ? runtime.tickMe(fly) : runtime.untickMe(fly);
|
||||
},
|
||||
};
|
||||
g.init();
|
||||
})();
|
||||
|
||||
(function () {
|
||||
let old = globalThis.sdk_runtime;
|
||||
c2_callFunction("execCode", ["globalThis.sdk_runtime = this.runtime"]);
|
||||
let runtime = globalThis.sdk_runtime;
|
||||
globalThis.sdk_runtime = old;
|
||||
|
||||
//Get all valid players on the layout
|
||||
// Ghosts don't count as valid players, and replays don't count either
|
||||
|
||||
let notify = (text, title = "Save state", image = "./speedrunner.png") => {
|
||||
cr.plugins_.sirg_notifications.prototype.acts.AddSimpleNotification.call(
|
||||
runtime.types_by_index.find(
|
||||
(type) => type.plugin instanceof cr.plugins_.sirg_notifications
|
||||
).instances[0],
|
||||
title,
|
||||
text,
|
||||
image
|
||||
);
|
||||
};
|
||||
|
||||
notify(
|
||||
"Save state with Shift+S, load with S, reset with R, reset sate with Shift+R, skip level with Shift+N, go back in level with Shift+B",
|
||||
"Mod loaded"
|
||||
);
|
||||
|
||||
let getPlayer = () =>
|
||||
runtime.types_by_index
|
||||
.filter(
|
||||
(x) =>
|
||||
!!x.animations &&
|
||||
x.animations[0].frames[0].texture_file.includes("collider")
|
||||
)[0]
|
||||
.instances.filter(
|
||||
(x) => x.instance_vars[17] === "" && x.behavior_insts[0].enabled
|
||||
)[0];
|
||||
let getFlag = () =>
|
||||
runtime.types_by_index.find(
|
||||
(x) =>
|
||||
x.name === "EndFlag" ||
|
||||
(x.plugin instanceof cr.plugins_.Sprite &&
|
||||
x.all_frames &&
|
||||
x.all_frames[0].texture_file.includes("endflag"))
|
||||
).instances[0];
|
||||
let getCoin = () =>
|
||||
runtime.types_by_index.find(
|
||||
(x) =>
|
||||
x.name === "Coin" ||
|
||||
(x.plugin instanceof cr.plugins_.Sprite &&
|
||||
x.all_frames &&
|
||||
x.all_frames[0].texture_file.includes("coin"))
|
||||
).instances[0];
|
||||
let curState = null;
|
||||
let curLayout = null;
|
||||
let saveState = () => {
|
||||
notify("Saved player state", "State Saved");
|
||||
let state = runtime.saveInstanceToJSON(getPlayer(), true);
|
||||
return state;
|
||||
};
|
||||
let loadState = (state) => {
|
||||
let player = getPlayer();
|
||||
player.y -= 10;
|
||||
player.set_bbox_changed();
|
||||
player.behavior_insts[0].lastFloorObject = null;
|
||||
notify("Loaded player state", "State Loaded");
|
||||
runtime.loadInstanceFromJSON(player, state, true);
|
||||
};
|
||||
document.addEventListener("keydown", (event) => {
|
||||
if (!getFlag()) {
|
||||
return;
|
||||
}
|
||||
if (event.code === "KeyS") {
|
||||
if (event.shiftKey) {
|
||||
curState = saveState();
|
||||
} else if (curState != null) {
|
||||
loadState(curState);
|
||||
}
|
||||
}
|
||||
if (event.code === "KeyR" && event.shiftKey) {
|
||||
curState = null;
|
||||
runtime.changeLayout = runtime.runningLayout;
|
||||
notify("State reset by soft level reset (Shift + R)", "State Reset");
|
||||
}
|
||||
if (event.code === "KeyN") {
|
||||
if (event.shiftKey) {
|
||||
runtime.changelayout = runtime.layouts["Level " + String(parseInt(runtime.running_layout.name.split(' ')[1]) + 1)]
|
||||
setTimeout(() => {
|
||||
notify("Going to next level bypass (Shift + N)", "Next Level");
|
||||
}, 300);
|
||||
}
|
||||
}
|
||||
if (event.code === "KeyM") {
|
||||
if (event.shiftKey) {
|
||||
let player = getPlayer();
|
||||
let flag = getFlag();
|
||||
player.x = flag.x;
|
||||
player.y = flag.y;
|
||||
player.set_bbox_changed();
|
||||
setTimeout(() => {
|
||||
notify("Going to next level (Shift + M)", "Next Level");
|
||||
}, 300);
|
||||
}
|
||||
}
|
||||
if (event.code === "KeyB") {
|
||||
if (event.shiftKey) {
|
||||
runtime.changelayout = runtime.layouts["Level " + String(parseInt(runtime.running_layout.name.split(' ')[1]) - 1)]
|
||||
setTimeout(() => {
|
||||
notify("Going to next level (Shift + N)", "Next Level");
|
||||
}, 300);
|
||||
}
|
||||
}
|
||||
if (event.code === "KeyC") {
|
||||
if (event.shiftKey) {
|
||||
let player = getPlayer();
|
||||
let flag = getCoin();
|
||||
player.x = flag.x;
|
||||
player.y = flag.y;
|
||||
player.set_bbox_changed();
|
||||
setTimeout(() => {
|
||||
notify("Going to coin (Shift + C)", "Coin");
|
||||
}, 300);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
Object.values(runtime.layouts).forEach((layout) => {
|
||||
let oldFn = layout.startRunning.bind(layout);
|
||||
layout.startRunning = () => {
|
||||
oldFn();
|
||||
if (!getFlag()) {
|
||||
curLayout = layout.name;
|
||||
curState = null;
|
||||
} else {
|
||||
if (curState && curLayout === layout.name) loadState(curState);
|
||||
else curState = null;
|
||||
curLayout = layout.name;
|
||||
}
|
||||
};
|
||||
});
|
||||
})();
|
||||
@@ -0,0 +1,106 @@
|
||||
var $jscomp = $jscomp || {};
|
||||
$jscomp.scope = {};
|
||||
$jscomp.arrayIteratorImpl = function (a) {
|
||||
var b = 0;
|
||||
return function () {
|
||||
return b < a.length ? {
|
||||
done: !1,
|
||||
value: a[b++]
|
||||
} : {
|
||||
done: !0
|
||||
}
|
||||
}
|
||||
};
|
||||
$jscomp.arrayIterator = function (a) {
|
||||
return {
|
||||
next: $jscomp.arrayIteratorImpl(a)
|
||||
}
|
||||
};
|
||||
$jscomp.makeIterator = function (a) {
|
||||
var b = "undefined" != typeof Symbol && Symbol.iterator && a[Symbol.iterator];
|
||||
return b ? b.call(a) : $jscomp.arrayIterator(a)
|
||||
};
|
||||
$jscomp.arrayFromIterator = function (a) {
|
||||
for (var b, c = []; !(b = a.next()).done;) c.push(b.value);
|
||||
return c
|
||||
};
|
||||
$jscomp.arrayFromIterable = function (a) {
|
||||
return a instanceof Array ? a : $jscomp.arrayFromIterator($jscomp.makeIterator(a))
|
||||
};
|
||||
$jscomp.ASSUME_ES5 = !1;
|
||||
$jscomp.ASSUME_NO_NATIVE_MAP = !1;
|
||||
$jscomp.ASSUME_NO_NATIVE_SET = !1;
|
||||
$jscomp.defineProperty = $jscomp.ASSUME_ES5 || "function" == typeof Object.defineProperties ? Object.defineProperty : function (a, b, c) {
|
||||
a != Array.prototype && a != Object.prototype && (a[b] = c.value)
|
||||
};
|
||||
$jscomp.getGlobal = function (a) {
|
||||
return "undefined" != typeof window && window === a ? a : "undefined" != typeof global && null != global ? global : a
|
||||
};
|
||||
$jscomp.global = $jscomp.getGlobal(this);
|
||||
$jscomp.SYMBOL_PREFIX = "jscomp_symbol_";
|
||||
$jscomp.initSymbol = function () {
|
||||
$jscomp.initSymbol = function () { };
|
||||
$jscomp.global.Symbol || ($jscomp.global.Symbol = $jscomp.Symbol)
|
||||
};
|
||||
$jscomp.Symbol = function () {
|
||||
var a = 0;
|
||||
return function (b) {
|
||||
return $jscomp.SYMBOL_PREFIX + (b || "") + a++
|
||||
}
|
||||
}();
|
||||
$jscomp.initSymbolIterator = function () {
|
||||
$jscomp.initSymbol();
|
||||
var a = $jscomp.global.Symbol.iterator;
|
||||
a || (a = $jscomp.global.Symbol.iterator = $jscomp.global.Symbol("iterator"));
|
||||
"function" != typeof Array.prototype[a] && $jscomp.defineProperty(Array.prototype, a, {
|
||||
configurable: !0,
|
||||
writable: !0,
|
||||
value: function () {
|
||||
return $jscomp.iteratorPrototype($jscomp.arrayIteratorImpl(this))
|
||||
}
|
||||
});
|
||||
$jscomp.initSymbolIterator = function () { }
|
||||
};
|
||||
$jscomp.initSymbolAsyncIterator = function () {
|
||||
$jscomp.initSymbol();
|
||||
var a = $jscomp.global.Symbol.asyncIterator;
|
||||
a || (a = $jscomp.global.Symbol.asyncIterator = $jscomp.global.Symbol("asyncIterator"));
|
||||
$jscomp.initSymbolAsyncIterator = function () { }
|
||||
};
|
||||
$jscomp.iteratorPrototype = function (a) {
|
||||
$jscomp.initSymbolIterator();
|
||||
a = {
|
||||
next: a
|
||||
};
|
||||
a[$jscomp.global.Symbol.iterator] = function () {
|
||||
return this
|
||||
};
|
||||
return a
|
||||
};
|
||||
$jscomp.iteratorFromArray = function (a, b) {
|
||||
$jscomp.initSymbolIterator();
|
||||
a instanceof String && (a += "");
|
||||
var c = 0,
|
||||
e = {
|
||||
next: function () {
|
||||
if (c < a.length) {
|
||||
var d = c++;
|
||||
return {
|
||||
value: b(d, a[d]),
|
||||
done: !1
|
||||
}
|
||||
}
|
||||
e.next = function () {
|
||||
return {
|
||||
done: !0,
|
||||
value: void 0
|
||||
}
|
||||
};
|
||||
return e.next()
|
||||
}
|
||||
};
|
||||
e[Symbol.iterator] = function () {
|
||||
return e
|
||||
};
|
||||
return e
|
||||
};
|
||||
@@ -0,0 +1,30 @@
|
||||
{
|
||||
"chaos": {
|
||||
"name": "Chaos",
|
||||
"author": "drakeerv",
|
||||
"description": "CHAOS!",
|
||||
"advanced": false,
|
||||
"url": "chaos.js"
|
||||
},
|
||||
"levelselector": {
|
||||
"name": "Level Selector",
|
||||
"author": "drakeerv",
|
||||
"description": "Load any level in the game.",
|
||||
"advanced": false,
|
||||
"url": "levelselector.js"
|
||||
},
|
||||
"dark": {
|
||||
"name": "Dark",
|
||||
"author": "drakeerv",
|
||||
"description": "Dark Mode for OvO!",
|
||||
"advanced": false,
|
||||
"url": "dark.js"
|
||||
},
|
||||
"resetbutton": {
|
||||
"name": "Reset Button",
|
||||
"author": "drakeerv",
|
||||
"description": "Allows you to reset using R.",
|
||||
"advanced": false,
|
||||
"url": "resetbutton.js"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,118 @@
|
||||
let chaosPresets = {
|
||||
"original": {
|
||||
"sin": "random",
|
||||
"cos": "random",
|
||||
"tan": "random"
|
||||
},
|
||||
"funky": {
|
||||
"sin": "sinh",
|
||||
"cos": "cosh",
|
||||
"tan": "tanh"
|
||||
},
|
||||
"size": {
|
||||
"sin": "fib"
|
||||
}
|
||||
};
|
||||
|
||||
(function() {
|
||||
let chaos = {
|
||||
init() {
|
||||
this.random = Math.random;
|
||||
|
||||
this.abs = Math.abs;
|
||||
this.acos = Math.acos;
|
||||
this.acosh = Math.acosh;
|
||||
this.asin = Math.asin;
|
||||
this.asinh = Math.asinh;
|
||||
this.atan = Math.atan;
|
||||
this.atanh = Math.atanh;
|
||||
this.cbrt = Math.cbrt;
|
||||
this.ceil = Math.ceil;
|
||||
this.clz32 = Math.clz32;
|
||||
this.cos = Math.cos;
|
||||
this.cosh = Math.cosh;
|
||||
this.exp = Math.exp;
|
||||
this.expm1 = Math.expm1;
|
||||
this.floor = Math.floor;
|
||||
this.fround = Math.fround;
|
||||
this.log = Math.log;
|
||||
this.log1p = Math.log1p;
|
||||
this.log10 = Math.log10;
|
||||
this.log2 = Math.log2;
|
||||
this.sign = Math.sign;
|
||||
this.sin = Math.sin;
|
||||
this.sinh = Math.sinh;
|
||||
this.sqrt = Math.sqrt;
|
||||
this.tan = Math.tan;
|
||||
this.tanh = Math.tanh;
|
||||
this.trunc = Math.trunc;
|
||||
|
||||
this.atan2 = Math.atan2;
|
||||
this.hypot = Math.hypot;
|
||||
this.imul = Math.imul;
|
||||
this.max = Math.max;
|
||||
this.min = Math.min;
|
||||
this.pow = Math.pow;
|
||||
|
||||
this.fib = (n) => {for(var r,c=1,f=0;n>=0;)r=c,c+=f,f=r,n--;return f};
|
||||
this.carea = (a) => {return a*a*Math.PI};
|
||||
this.fix = (n) => {return n<0?Math.ceil(n):n>0?Math.floor(n):n};
|
||||
this.cat = (n) => {if(n<=1)return 1;let t=0;for(let a=0;a<n;n++)t+=this.cat(a)*this.cat(n-a-1);return t}
|
||||
this.erandom = (n) => {(Math.random()-0.5)*2}
|
||||
|
||||
this.start("original");
|
||||
globalThis.ovoChaos = this;
|
||||
},
|
||||
|
||||
start(presetName="original") {
|
||||
let preset = chaosPresets[presetName];
|
||||
|
||||
if (preset) {
|
||||
for (const [key, value] of Object.entries(preset)) {
|
||||
eval(`Math.${key} = this.${value}`)
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
stop() {
|
||||
Math.random = this.random;
|
||||
|
||||
Math.abs = this.abs;
|
||||
Math.acos = this.acos;
|
||||
Math.acosh = this.acosh;
|
||||
Math.asin = this.asin;
|
||||
Math.asinh = this.asinh;
|
||||
Math.atan = this.atan;
|
||||
Math.atanh = this.atanh;
|
||||
Math.cbrt = this.cbrt;
|
||||
Math.ceil = this.ceil;
|
||||
Math.clz32 = this.clz32;
|
||||
Math.cos = this.cos;
|
||||
Math.cosh = this.cosh;
|
||||
Math.exp = this.exp;
|
||||
Math.expm1 = this.expm1;
|
||||
Math.floor = this.floor;
|
||||
Math.fround = this.fround;
|
||||
Math.log = this.log;
|
||||
Math.log1p = this.log1p;
|
||||
Math.log10 = this.log10;
|
||||
Math.log2 = this.log2;
|
||||
Math.sign = this.sign;
|
||||
Math.sin = this.sin;
|
||||
Math.sinh = this.sinh;
|
||||
Math.sqrt = this.sqrt;
|
||||
Math.tan = this.tan;
|
||||
Math.tanh = this.tanh;
|
||||
Math.trunc = this.trunc;
|
||||
|
||||
Math.atan2 = this.atan2;
|
||||
Math.hypot = this.hypot;
|
||||
Math.imul = this.imul;
|
||||
Math.max = this.max;
|
||||
Math.min = this.min;
|
||||
Math.pow = this.pow;
|
||||
}
|
||||
}
|
||||
|
||||
chaos.init();
|
||||
})();
|
||||
@@ -0,0 +1,18 @@
|
||||
(function() {
|
||||
// create a div element
|
||||
const div = document.createElement("div");
|
||||
|
||||
// set styles for the div element
|
||||
div.style.width = "100%";
|
||||
div.style.height = "100%";
|
||||
div.style.position = "fixed";
|
||||
div.style.top = "0";
|
||||
div.style.left = "0";
|
||||
div.style.mixBlendMode = "difference";
|
||||
div.style.backgroundColor = "white";
|
||||
div.style.zIndex = "99999"; // set an extremely high z-index value
|
||||
div.style.pointerEvents = "none"; // make the div pass events to the items below it
|
||||
|
||||
// add the div element to the body of the webpage
|
||||
document.body.appendChild(div);
|
||||
})();
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,20 @@
|
||||
(function() {
|
||||
let runtime = c3_runtimeInterface._GetLocalRuntime();
|
||||
let notify = () => {};
|
||||
|
||||
let resetButton = {
|
||||
init() {
|
||||
document.addEventListener("keydown", (event) => {this.keydown(event)})
|
||||
|
||||
globalThis.ovoResetButton = this;
|
||||
notify("Mod Loaded", "Reset Button Mod Loaded");
|
||||
},
|
||||
|
||||
keydown(event) {
|
||||
if (event.key.toLowerCase() == "r") {
|
||||
runtime._layoutManager._pendingChangeLayout = runtime._layoutManager._mainRunningLayout;
|
||||
}
|
||||
}
|
||||
};
|
||||
resetButton.init();
|
||||
})();
|
||||
@@ -0,0 +1,203 @@
|
||||
(function () {
|
||||
const modDirectory = "/mods/";
|
||||
const versionFolder = "v1";
|
||||
|
||||
class ModLoader {
|
||||
constructor(runtime) {
|
||||
window.ovoModLoader = this;
|
||||
|
||||
this.runtime = runtime;
|
||||
this.initialised = false;
|
||||
this.mods = {};
|
||||
this.loadedMods = [];
|
||||
|
||||
this.#init();
|
||||
}
|
||||
|
||||
async #init() {
|
||||
this.mods = await fetch(this.getModDirectory() + "v1.json").then(res => res.json());
|
||||
this.loadModURL("modapi.js", true, false);
|
||||
|
||||
window.addEventListener("keydown", (event) => {
|
||||
if (event.code === "KeyL") {
|
||||
if (event.shiftKey) {
|
||||
this.promptMod();
|
||||
}
|
||||
}
|
||||
});
|
||||
this.#initDomUI();
|
||||
|
||||
this.initialised = true;
|
||||
}
|
||||
|
||||
async #initDomUI() {
|
||||
const style = document.createElement("style");
|
||||
style.innerHTML = `
|
||||
.ovo-modloader-button {
|
||||
background-color: white;
|
||||
border: solid;
|
||||
border-color: black;
|
||||
border-width: 6px;
|
||||
font-family: "Retron2000";
|
||||
position: absolute;
|
||||
z-index: 999999;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.ovo-modloader-button:hover {
|
||||
background-color: rgba(200, 200, 200, 1);
|
||||
}
|
||||
`
|
||||
document.head.appendChild(style);
|
||||
|
||||
const toggleButton = document.createElement("button");
|
||||
toggleButton.id = "ovo-modloader-toggle-button";
|
||||
toggleButton.innerText = "";
|
||||
|
||||
const loadIcon = document.createElement("img");
|
||||
loadIcon.src = "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4NCjwhLS0gU3ZnIFZlY3RvciBJY29ucyA6IGh0dHA6Ly93d3cub25saW5ld2ViZm9udHMuY29tL2ljb24gLS0+DQo8IURPQ1RZUEUgc3ZnIFBVQkxJQyAiLS8vVzNDLy9EVEQgU1ZHIDEuMS8vRU4iICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiPg0KPHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4IiB2aWV3Qm94PSIwIDAgMTAwMCAxMDAwIiBlbmFibGUtYmFja2dyb3VuZD0ibmV3IDAgMCAxMDAwIDEwMDAiIHhtbDpzcGFjZT0icHJlc2VydmUiPg0KPG1ldGFkYXRhPiBTdmcgVmVjdG9yIEljb25zIDogaHR0cDovL3d3dy5vbmxpbmV3ZWJmb250cy5jb20vaWNvbiA8L21ldGFkYXRhPg0KPGc+PGcgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMC4wMDAwMDAsNTExLjAwMDAwMCkgc2NhbGUoMC4xMDAwMDAsLTAuMTAwMDAwKSI+PHBhdGggZD0iTTQ4ODIuOSw0NzQ5LjRjLTEwNy4zLTMyLjYtMjE2LjQtMTQzLjYtMjQ1LjItMjUwLjljLTE1LjMtNDkuOC0yMS4xLTExMDctMjEuMS0zMzc2LjZWLTIxODJMMzUwMi0xMDY3LjNDMjg4Ny4yLTQ1Ni4zLDIzNTYuNyw2MC44LDIzMjAuMyw3OGMtMTAxLjUsNTEuNy0yODMuNSwzMi42LTM3NS40LTM2LjRjLTEzNC4xLTEwMy40LTE4NS44LTI0OS0xNDMuNi00MDkuOWMyMy04NC4zLDEzMi4yLTE5Ny4zLDE0OTItMTU2MC45Yzk4Ni40LTk4OC4zLDE0OTItMTQ4Mi40LDE1NDUuNi0xNTA3LjNjOTEuOS00NiwyMTIuNi00OS44LDMxMC4zLTkuNmM5MiwzOC4zLDI5NTUuMywyODk0LDMwMTYuNiwzMDA3YzEyMC43LDIyNy45LTI0LjksNTE3LjEtMjcyLDU0MmMtMjE2LjQsMjEuMS0xMzIuMSw5MS45LTEzNzUuMi0xMTUxLjFMNTM4Mi44LTIxODJ2MzMwMy44YzAsMjI2OS42LTUuNywzMzI2LjgtMjEuMSwzMzc2LjZjLTMwLjcsMTExLjEtMTM3LjksMjE4LjMtMjUyLjgsMjUyLjhTNDk5Niw0Nzg1LjgsNDg4Mi45LDQ3NDkuNHoiLz48cGF0aCBkPSJNNDMxLjgtMTgzNy4yYy05LjYtMy44LTQyLjEtMTEuNS03Mi44LTE3LjJjLTc4LjUtMTcuMi0xOTkuMi0xMzYtMjM1LjYtMjMzLjdjLTU5LjQtMTU3LTEuOS01OTcuNiwxMjQuNS05NDQuMmMyNzkuNi03NjQuMiw5NjUuMy0xMzM0LjksMTc5Mi43LTE0OTJjMTU3LjEtMzAuNiw0MDkuOS0zMi42LDI5NTkuMS0zMi42YzI1NTYuOSwwLDI4MDAuMSwxLjksMjk2MSwzMi42YzEwNzQuNSwyMDQuOSwxODU3LjgsMTA4MC4yLDE5MzQuNCwyMTY2LjJjMTUuMywyMDYuOC0zLjgsMjg5LjItOTMuOCwzODguOGMtMTM3LjksMTU5LTM1Ni4zLDE3OC4xLTUxNS4yLDQ0Yy05Ny43LTc4LjUtMTMwLjItMTYyLjgtMTQ5LjQtMzk4LjRjLTExLjUtMTEzLTM2LjQtMjY2LjItNTkuNC0zMzljLTEzNi00NDQuMy00NDguMi04MDIuNS04NjUuNy05OTRjLTMxNC4xLTE0NS41LTU3LjUtMTM0LjEtMzIxMS45LTEzNC4xYy0yNjg1LjIsMC0yODMwLjgsMS45LTI5NDkuNSwzNC41Yy00OTYuMSwxNDEuNy04OTQuNCw0OTQuMS0xMDc4LjMsOTU1LjdjLTY3LDE2NC43LTEwOS4yLDM0Ni43LTEwOS4yLDQ2OS4zYzAsMTgzLjgtMzQuNSwyOTEuMS0xMjIuNiwzNzkuMkM2NTIuMS0xODY0LjEsNTA4LjUtMTgxMC40LDQzMS44LTE4MzcuMnoiLz48L2c+PC9nPg0KPC9zdmc+"
|
||||
loadIcon.style.width = "38px";
|
||||
loadIcon.style.height = "38px";
|
||||
|
||||
toggleButton.appendChild(loadIcon);
|
||||
toggleButton.classList.add("ovo-modloader-button");
|
||||
toggleButton.style.top = "50%";
|
||||
toggleButton.style.right = "0%";
|
||||
toggleButton.style.transform = "translateY(-50%)";
|
||||
toggleButton.style.width = "50px";
|
||||
toggleButton.style.height = "50px";
|
||||
toggleButton.onclick = this.promptMod.bind(this);
|
||||
document.body.appendChild(toggleButton);
|
||||
}
|
||||
|
||||
notify(title, text, image = "./speedrunner.png") {
|
||||
cr.plugins_.sirg_notifications.prototype.acts.AddSimpleNotification.call(
|
||||
this.runtime.types_by_index.find(
|
||||
(type) => type.plugin instanceof cr.plugins_.sirg_notifications
|
||||
).instances[0],
|
||||
title,
|
||||
text,
|
||||
image
|
||||
);
|
||||
}
|
||||
|
||||
getModDirectory() {
|
||||
return this.getScriptDir() + modDirectory;
|
||||
}
|
||||
|
||||
getScriptPath() {
|
||||
return decodeURI(new Error().stack.match(/([^ \n\(@])*([a-z]*:\/\/\/?)*?[a-z0-9\/\\]*\.js/ig)[0]);
|
||||
}
|
||||
|
||||
getScriptDir() {
|
||||
return this.getScriptPath().split("/").slice(0, -1).join("/") + "/";
|
||||
}
|
||||
|
||||
getURLName(url) {
|
||||
return url.split("/").pop().split(".").slice(0, -1).join(".");
|
||||
}
|
||||
|
||||
getIsScriptLoaded(name) {
|
||||
return this.loadedMods.includes(name);
|
||||
}
|
||||
|
||||
getIsValidURL(str) {
|
||||
const pattern = new RegExp('^(https?:\\/\\/)?' +
|
||||
'((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.)+[a-z]{2,}|' +
|
||||
'((\\d{1,3}\\.){3}\\d{1,3}))' +
|
||||
'(\\:\\d+)?(\\/[-a-z\\d%_.~+]*)*' +
|
||||
'(\\?[;&a-z\\d%_.~+=-]*)?' +
|
||||
'(\\#[-a-z\\d_]*)?$', 'i');
|
||||
return pattern.test(str);
|
||||
}
|
||||
|
||||
#createScript(src, key, name, notify = true) {
|
||||
const js = document.createElement("script");
|
||||
js.type = "application/javascript";
|
||||
js.src = src;
|
||||
|
||||
js.onload = () => {
|
||||
this.loadedMods.push(key);
|
||||
if (notify) {
|
||||
this.notify("Mod loaded", name);
|
||||
}
|
||||
}
|
||||
|
||||
js.onerror = () => {
|
||||
if (notify) {
|
||||
this.notify("Error loading mod", name);
|
||||
}
|
||||
}
|
||||
|
||||
document.head.appendChild(js);
|
||||
}
|
||||
|
||||
loadModURL(url, local = false, notify = true) {
|
||||
if (local) {
|
||||
url = this.getModDirectory() + "v1/" + url;
|
||||
}
|
||||
|
||||
const name = this.getURLName(url);
|
||||
|
||||
if (this.getIsScriptLoaded(name)) {
|
||||
if (notify) {
|
||||
this.notify("Mod already loaded", name);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
this.#createScript(url, name, name, notify);
|
||||
}
|
||||
|
||||
loadModJSON(key, json, notify = true) {
|
||||
const url = this.getModDirectory() + "v1/" + json.url;
|
||||
const name = json.name;
|
||||
|
||||
if (this.getIsScriptLoaded(key)) {
|
||||
if (notify) {
|
||||
this.notify("Mod already loaded", name);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
this.#createScript(url, key, name, notify);
|
||||
}
|
||||
|
||||
loadModJS(modJS, notify = true) {
|
||||
setTimeout(modJS, 0);
|
||||
|
||||
if (notify) {
|
||||
this.notify("Mod loaded", "Loaded JS code");
|
||||
}
|
||||
}
|
||||
|
||||
promptMod() {
|
||||
const input = prompt("Enter mod URL, ID, or JS code");
|
||||
const key = input.toLocaleLowerCase();
|
||||
|
||||
if (!input) return;
|
||||
|
||||
if (this.mods[key]) {
|
||||
this.loadModJSON(key, this.mods[key], true);
|
||||
} else {
|
||||
if (this.getIsValidURL(input)) {
|
||||
this.loadModURL(input, false, true);
|
||||
} else {
|
||||
this.loadModJS(input, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof window.ovoModLoader === "undefined") {
|
||||
if (typeof window.cr_getC2Runtime !== "undefined" && typeof window.cr_getC2Runtime() !== "undefined" && window.cr_getC2Runtime().isloading === false) {
|
||||
new ModLoader(cr_getC2Runtime());
|
||||
} else {
|
||||
const createCommand = window.cr_createRuntime;
|
||||
const hookCommand = (canvasId) => {
|
||||
new ModLoader(createCommand(canvasId));
|
||||
}
|
||||
window.cr_createRuntime = hookCommand;
|
||||
}
|
||||
}
|
||||
})();
|
||||
Reference in New Issue
Block a user