0% found this document useful (0 votes)
7 views13 pages

A 2214

fake sugarcube script aswell
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as TXT, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
7 views13 pages

A 2214

fake sugarcube script aswell
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as TXT, PDF, TXT or read online on Scribd

(function () {

// Because sugarcube freezes Engine, I can't really hook into stuff like `show`
calls, sadly.
// And replacing SugarCube.Engine would not yield the result, since it's also
scoped locally.
// Two methods are used: Per-frame fixup and passage events. Seem to work
reasonably well.

class VarWatch {

/**
* (".");
* Param temp {Boolean}
* Param path {String[]}
* Param getContainer {Boolean}
*/
static getValue(temp, path, getContainer = true) {
let root = temp ? SugarCube.State.temporary : getvars();
let i = 0, l = getContainer ? path.length - 1 :

limitVal(val) {
if (this.allowIncrease) {
return val < this.lastValue ? this.lastValue : val;
} else if (this.allowDecrease) {
return val > this.lastValue ? this.lastValue : val;
} else {
return this.lastValue;
}
}

update() {
if (this.freeze) {
let val = this.value;
if (val instanceof Date) {
val.setTime(this.lastValue = this.limitVal(val.getTime()));
} else if (val != this.lastValue) {
if (typeof(val) == "number" || typeof(val) == "bigint") {
this.value = this.lastValue = this.limitVal(val);
} else {
this.value = this.lastValue;
}
}
} else {
var val = this.value;
if (val instanceof Date) {
this.lastValue = val.getTime();
} else {
this.lastValue = val;
}
}
if (this.view) this.view.update();
}

}
/** Type {Map<String, VarWatch>} */
VarWatch.watch = new Map();
VarWatch.NULL_PATH = { error:"Path does not exists" };
VarWatch.frequency = 10; // Every 10th frame.
// Variable type, in order to display proper data.
const VTString = 0;
const VTNumber = 1;
const VTBool = 2;
const VTOther = 3;
const VTNull = 4;
const VTUndefined = 5;
const VTFunction = 6;
const VTDate = 7;

const storage_key = SugarCube.Config.saves.id + ".varwatch";

class VarView {

/**
* Param watch {VarWatch}
*/
constructor(watch) {
this.watch = watch;
this.lastType = VTNull;
}

add() {
if (!this.view) this.update();
else {
this.view.appendTo(watcherRoot.find("#debug-bar-watch"));
}
}

destroy() {
if (this.view) {
this.view.remove();
this.view = null;
}
}

build(type, val) {
this.destroy();
let content = "";
this.viewType = type;
switch (type) {
case VTUndefined:
content = "<span style='color: red;'>Undefined</span>";
break;
case VTNull:
content = "<span style='color: red;'>Null</span>";
break;
case VTBool:
content = "<input type='checkbox'>";
break;
case VTNumber:
content = "<input type='number'>";
break;
case VTOther:
content = "<span style='color: #fdffb2' class='watch-value'></span>";
break;
case VTFunction:
content = "<span style='color: red;'>Function</span>";
break;
case VTString:
content = "<input>";
case VTDate:
content = "<input>";
break;
default:
content = "<span style='color:red'>Unknown type</span>";
}
this.view = $(`
<tr>
<td class="watch-controls">
<label><input type="checkbox" class="watch-freeze connect-right"><i class='fa'
title="${this.watch.name}"></i></label>
<label><input type="checkbox" class="watch-freeze-dir connect-left"><i class='fa'
title="Toggle allowed change direction increase/decrease"></i></label>
</td>
<td>
<span title=${this.watch.fullPath}>${this.watch.name}</span>
</td>
<td class='watch-edit'>
${content}
<button class="watch-delete"></button>
</td>
</tr>`);
let self = this;
const DIR_BOTH = "";
const DIR_DOWN = "";
const DIR_UP = "";
this.view.find(".watch-freeze").change( (e) => self.watch.freeze =
e.currentTarget.checked );
this.view.find(".watch-freeze-dir").change( function(e) {
if (self.watch.allowDecrease) {
self.watch.allowDecrease = false;
e.currentTarget.checked = false;
e.currentTarget.nextElementSibling.textContent = DIR_BOTH;
} else if (self.watch.allowIncrease) {
self.watch.allowIncrease = false;
self.watch.allowDecrease = true;
e.currentTarget.checked = true;
e.currentTarget.nextElementSibling.textContent = DIR_DOWN;
} else {
self.watch.allowIncrease = true;
e.currentTarget.checked = true;
e.currentTarget.nextElementSibling.textContent = DIR_UP;
}
} );
this.view.find(".watch-delete").click( () => self.watch.destroy() );
this.view.find(".watch-edit input")
.change( function(e) {
if (self.viewType == VTBool) self.watch.change(e.currentTarget.checked);
else if (self.viewType == VTNumber) self.watch.change(parseFloat($
(e.currentTarget).val()));
else self.watch.change($(e.currentTarget).val());
})
.on('wheel', function(e) {
if (self.viewType == VTNumber) {
var delta = e.originalEvent.deltaY > 0 ? -1 : 1;
self.watch.change(self.watch.value + delta);
e.originalEvent.preventDefault();
}
});
this.view
.on("mouseover", function(e) {
if (watcherRoot[0].classList.contains("cheat-hide")) {
self.showShadow();
}
})
.on('mouseout', function(e) {
var shadow = watcherRoot.find("#cheat-bar-value-shadow")[0];
if (shadow._view === self) {
shadow.style.left = "100%";
}
});
this.add();
this.assign(val);
}

showShadow() {
var shadow = watcherRoot.find("#cheat-bar-value-shadow").empty()[0];
shadow._view = this;
var vals = this.view.find("td");
shadow.appendChild(vals[1].cloneNode(true));
shadow.appendChild(vals[2].cloneNode(true));
var watch = watcherRoot.find("#debug-bar-watch")[0];
var settings = watcherRoot.find("#cheat-bar-settings")[0];
shadow.style.bottom = "calc(100% + " + (-watch.offsetTop) + "px)";
shadow.style.left = (-shadow.offsetWidth) + "px";
}

stringifyOther(val) {
if (val instanceof Date) {
return "Date { " + val.toLocaleString() + "}";
} else if (val instanceof RegExp) {
return "RegExp " + val.toString();
}
var v = JSON.stringify(val);
if (v.length > 100) {
return v.substr(0, 100) + " [..." + (v.length - 100) + " more omitted]";
}
return v;
// if (e instanceof Array || e instanceof Set) {
// let v = e instanceof Array ? e : Array.from(e);
// for (let i = 0, l = a.length; i < l; i++) {
// arr.push(v.hasOwnProperty(i) ? this.stringifyOther(v) : "<empty>");
// }
// return Object.keys(v).forEach()
// }
}

assign(val) {
let disp = val;
if (this.viewType == VTOther) {
disp = this.stringifyOther(disp);
}
if (disp == this.lastDisp) return;
this.lastDisp = disp;
switch (this.viewType) {
case VTBool:
this.view.find(".watch-edit input").prop("checked", disp);
break;
case VTDate:
/** Type {Date} */
var date = val;
this.view.find(".watch-edit input").val(
date.getUTCHours() + ":" + date.getUTCMinutes() + ":" + date.getUTCSeconds() + " "
+
date.getUTCDate() + "/" + (date.getUTCMonth()+1) + "/" + date.getUTCFullYear());
break;
default:
this.view.find(".watch-edit input").val(disp);
this.view.find(".watch-value").text(disp);
}
}

getType(val) {
if (val === undefined) return VTUndefined;
if (val === null) return this.lastType;
switch (typeof(val)) {
case "bigint": case "number":
return this.lastType = VTNumber;
case "boolean":
return this.lastType = VTBool;
case "function":
return this.lastType = VTFunction;
case "string":
return this.lastType = VTString;
case "undefined":
return this.lastType;
case "object":
if (val instanceof Date) {
return this.lastType = VTDate;
}
return this.lastType = VTOther;
case "symbol":
return VTUndefined;
//throw new Error("Symbol type not supported");
}
}

static detectType(val, tnull = 4) {


if (val === undefined) return VTUndefined;
if (val === null) return tnull;
switch (typeof(val)) {
case "bigint": case "number":
return VTNumber;
case "boolean":
return VTBool;
case "function":
return VTFunction;
case "string":
return VTString;
case "undefined":
return tnull;
case "object":
if (val instanceof Date) {
return VTDate;
}
return VTOther;
case "symbol":
return VTUndefined;
//throw new Error("Symbol type not supported");
}
}

update() {
let val = this.watch.value;
let type = this.getType(val);
if (type !== this.viewType) {
this.build(type, val);
} else {
// TODO: Only when input not focused
this.assign(val);
}
}

// Primary view html


$(".cheat-bar,#debug-bar-hint").remove();
// TODO: Custom CSS as to not be reliant on specific game css shenanigans.
let watcherRoot = $(`
<div class="cheat-bar" style="right: 0px">
<div id="cheat-bar-value-shadow"></div>
<div id="debug-bar-watch" class="flex-table"></div>
<div>
<button id="debug-bar-watch-toggle" tabindex="0" title="Show watch
bar">Watch</button>
<button id="debug-bar-watch-save" tabindex="0" title="Save table to local
storage">Save</button>
<label>
<span>Add</span>
<span id="cheat-bar-watch-input-container">
<input id="debug-bar-watch-input" type="text" tabindex="0" autocomplete="off">
<div id="cheat-bar-completion" class="flex-table selectable"></div>
</span>
</label>
<button id="debug-bar-watch-add" tabindex="0" title="Add"></button>
<button id="cheat-bar-settings-toggle" tabindex="0" title="Settings"><i
class='fa'></i></button>
</div>
<div id="cheat-bar-settings" hidden>
<button id="cheat-bar-copy-share" title="Copy current table into clipboard">Copy <i
class='fa'></i></button>
<button id="cheat-bar-paste-share" title="Load the table from clipboard">Paste <i
class='fa'></i></button>
<button id="cheat-bar-clear-table" title="Remove all variables from the
table">Clear <i class='fa'></i></button>
<button id="cheat-bar-load-table" title="Load table stored in local storage">Load
<i class='fa'></i></button>
</div>
<button id="debug-bar-toggle" tabindex="0" title="Toggle bar"></button>
</div>
<div id="debug-bar-hint"></div>
`).appendTo("body");
// Some games bind hotkeys to navigation - we don't want to trigger those when our
bar is focused.
function cancelTraversal(e) {
e.stopPropagation();
}
watcherRoot[0].addEventListener("click", cancelTraversal);
watcherRoot[0].addEventListener("keyup", cancelTraversal);
watcherRoot[0].addEventListener("keydown", cancelTraversal);
watcherRoot[0].addEventListener("textinput", cancelTraversal);
watcherRoot[0].addEventListener("input", cancelTraversal);
// Toggle the bar
watcherRoot.find("#debug-bar-toggle").click( function() {
var b = watcherRoot[0];
if (b.classList.toggle("cheat-hide")) {
b.style.right = (-b.offsetWidth) + "px";
} else {
b.style.right = "0px";
}
});
// Save current state
function getTableString() {
return JSON.stringify(VarWatch.save());
}
watcherRoot.find("#debug-bar-watch-save").click( function() {
localStorage.setItem(storage_key, getTableString());
});
// Watch bar toggle
watcherRoot.find("#debug-bar-watch-toggle").click(function() {
var prop = watcherRoot.find("#debug-bar-watch");
prop.attr("hidden") ? prop.removeAttr("hidden") : prop.attr("hidden", "hidden");
});
watcherRoot.find("#cheat-bar-settings-toggle").click(function() {
var prop = watcherRoot.find("#cheat-bar-settings");
prop.attr("hidden") ? prop.removeAttr("hidden") : prop.attr("hidden", "hidden");
});
// Settings
watcherRoot.find("#cheat-bar-copy-share").click(function() {
navigator.clipboard.writeText(getTableString());
});
watcherRoot.find("#cheat-bar-paste-share").click(async function() {
if ( (await navigator.permissions.query({ name: "clipboard-read" })).state ==
"granted") {
VarWatch.restore(JSON.parse(await navigator.clipboard.readText()));
} else {
var p = prompt("Please paste the JSON data here:");
if (p) VarWatch.restore(JSON.parse(p));
}
});
watcherRoot.find("#cheat-bar-clear-table").click(function() {
for (w of Array.from(VarWatch.watch.values())) w.destroy();
});
watcherRoot.find("#cheat-bar-load-table").click(function() {
if (localStorage.getItem(storage_key))
VarWatch.restore(JSON.parse(localStorage.getItem(storage_key)));
});

// The watch bar input


let completionIndex = 0;
watcherRoot.find("#debug-bar-watch-input")
.on('input', () => buildCompletion() )
.on('keyup', function(e) {
if (e.originalEvent.code == "Enter") {
watcherRoot.find("#debug-bar-watch-add").click();
} else if (e.originalEvent.code == "Tab") {
e.originalEvent.preventDefault();
}
})
.on('keydown', function(e) {
if (e.originalEvent.code == "Tab") {
var first = watcherRoot.find("#cheat-bar-completion>tr");
first = first[(completionIndex++) % first.length];
if (first) {
watcherRoot.find("#cheat-bar-completion>tr.highlight").removeClass("highlight");
watcherRoot.find("#debug-bar-watch-input").val(first._value);
first.classList.add("highlight");
e.originalEvent.preventDefault();
}
}
})
.on('focus', () => buildCompletion())
.on('blur', (e) => $(e.originalEvent.relatedTarget).parent("#cheat-bar-
completion").length == 0 && watcherRoot.find("#cheat-bar-
completion").removeClass("show") );
watcherRoot.find("#cheat-bar-completion")
.on('click', function(e) {
var target = e.originalEvent.target;
if (target.tagName == "TR") {
watcherRoot.find("#debug-bar-watch-input").val(target._value).focus();
}
});
// Add button
watcherRoot.find("#debug-bar-watch-add").click(function() {
var inp = watcherRoot.find("#debug-bar-watch-input").val();
if (VarWatch.getValueSmart(inp, false, false) !== undefined) new VarWatch(inp);
watcherRoot.find("#debug-bar-watch-input").val("");
buildCompletion();
});

let lastRoot = null;


function buildCompletion() {
let dl = watcherRoot.find("#cheat-bar-completion").empty()[0];

let inp = watcherRoot.find("#debug-bar-watch-input").val();


let temp = inp.startsWith("_");
completionIndex = 0;
if (inp.length < (temp ? 3 : 2)) return;
inp = VarWatch.splitPath(inp, false);

let val = VarWatch.getValue(temp, inp, true);


lastRoot = val;

if (val) {
let top = inp.pop();
let prefix = watcherRoot.find("#debug-bar-watch-input").val();
if (!prefix.startsWith("$") && !temp) prefix = ("$") + prefix;
prefix = prefix.substr(0, prefix.length - top.length);

for (let k of Object.keys(val)) {


if (top.length == 0 || k.toLowerCase().startsWith(top.toLowerCase())) {
let sval = prefix + k;
let div = document.createElement("tr");
div._value = sval;
div.tabIndex = -1;
switch (VarView.detectType(val[k])) {
case VTString:
div.textContent = sval + ' = "' + val[k].substr(0, 30) + (val[k].length > 30 ?
'"...' : '"');
break;
case VTOther:
if (Array.isArray(val[k])) div.textContent = sval + "[" + val[k].length + "]";
else div.textContent = sval + "{}";
break;
case VTNumber:
case VTBool:
case VTNull:
case VTUndefined:
div.textContent = sval + " = " + val[k];
break;
case VTFunction:
div.textContent = sval + "()";
break;
case VTDate:
var date = val[k];
div.textContent = sval + " = "
date.getUTCHours() + ":" + date.getUTCMinutes() + ":" + date.getUTCSeconds() + " "
+
date.getUTCDate() + "/" + (date.getUTCMonth()+1) + "/" + date.getUTCFullYear();
break;
}
dl.appendChild(div);
}
}
}

if (dl.children.length > 0) {
if (!dl.classList.contains("show")) dl.classList.add("show");
} else dl.classList.remove("show");
}

// Add refresh hooks


function updateWatch() {
for (let w of VarWatch.watch.values()) w.update();
}
var counter = 0;
function refresh() {
window.__refreshFrame = requestAnimationFrame(refresh);
counter++;
if (counter >= VarWatch.frequency) {
counter = 0;
updateWatch();
}
}

if (window.__destroy) window.__destroy();
window.__destroy = function() {
jQuery(document).off(":passagestart", updateWatch).off(":passageend", updateWatch);
cancelAnimationFrame(window.__refreshFrame);
};
jQuery(document).on(":passagestart", updateWatch).on(":passageend", updateWatch);
requestAnimationFrame(refresh);

// Insert CSS
{
// Font-awesome icons
let fa = document.querySelector("#cheat-icons") || document.createElement("link");
fa.id = "cheat-icons";
fa.href = "https://stackpath.bootstrapcdn.com/font-awesome/4.7.0/css/font-
awesome.min.css";
fa.rel = "stylesheet";
document.head.appendChild(fa);

let css = document.querySelector("#cheat-css") || document.createElement("style");


css.id = "cheat-css";
document.head.appendChild(css);
css.textContent = `
.cheat-bar {
font-family: "Arial", Times, font-family;
font-size: 1em;
background: #222;
border-left: 1px solid #444;
border-top: 1px solid #444;
bottom: 0;
margin: 0;
max-height: 75%;
padding: .3em;
position: fixed;
right: 0;
z-index: 99990;
}

.cheat-hide #debug-bar-watch {
left: calc(-2.2em - 2px);
}

#debug-bar-watch {
overflow-x: auto;
}

.cheat-bar button {
cursor: pointer;
color: #eee;
background-color: #35a;
border: 1px solid #57c;
line-height: normal;
padding: .2em;
transition-duration: .2s;
user-select: none;
}

#debug-bar-views-toggle, #debug-bar-watch-toggle {
padding: .2em;
margin-right: .1em;
}

#cheat-bar-watch-input-container {
position: relative;
}
#cheat-bar-completion, #cheat-bar-value-shadow {
position: absolute;
z-index: 99991;
color: #eee;
background-color: #222;
border: 1px solid #444;
}
#cheat-bar-completion {
display: none;
left: 0px;
bottom: calc(100% + .4em);
padding-right: .8em;
max-height: 50vh;
overflow-y: auto;
}
#cheat-bar-completion tr {
padding: .4em;
}
#cheat-bar-completion.show {
display: initial;
}
#cheat-bar-value-shadow {
left: 100%;
transition: left 0.2s ease, width 0.2s ease ;
pointer-events: none;
padding: .2em;
display: flex;
align-items: baseline;
min-width: 300px;
}
#cheat-bar-value-shadow td:first-child {
padding-right: 4px;
text-align: right;
flex-grow: 1;
}
#cheat-bar-value-shadow button {
display: none;
}

.cheat-bar-toggle {
color: #eee;
background-color: #222;
border: 1px solid #444;
height: calc(100% + 1px);
left: -2em;
position: absolute;
top: -1px;
width: 2em;
}

.cheat-bar-toggle::before {
content: "\e838";
}

i.ico, .icon-before::before {
font-family: tme-fa-icons;
font-style: normal;
font-weight: 400;
font-variant: normal;
text-transform: none;
line-height: 1;
speak: none
}
.flex-table {
display: flex;
flex-direction: column;
}
.flex-table tr {
display: flex;
width: 100%;
align-items: center;
}
.flex-table td {
flex-basis: 0;
flex-grow: 1;
}
.flex-table td.watch-edit {
flex-grow: 5;
display: flex;
}
.flex-table .watch-edit input {
width: 100%;
}
.flex-table td.watch-controls {
padding-left: 4px !important;
min-width: 46px;
user-select: none;
}
.flex-table tr:nth-child(2n) {
background-color: rgba(127,127,127,.15);
}
.flex-table.selectable tr:hover {
background-color: rgba(108, 108, 108, .47);
}
.watch-controls label input[type=checkbox] {
display: none;
}
.watch-controls label input+i {
background: #3355aa;
padding: 4px;
border: 1px solid #5577cc;
border-radius: 4px;
color: white;
user-select: none;
cursor: pointer;
}
.watch-controls label input.connect-right+i {
border-right: none;
borlabel input:checked+i {
background: #228822;
border-color: #4a4;
}
`;
}

// Load saved watch list


if (localStorage.getItem(storage_key))
})();

You might also like