diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 00000000..c7441266 --- /dev/null +++ b/.prettierignore @@ -0,0 +1,4 @@ +**/*.html +**/*.json +**/*.css +**/*.md \ No newline at end of file diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 00000000..9df5fb0a --- /dev/null +++ b/.prettierrc @@ -0,0 +1,21 @@ +{ + "arrowParens": "avoid", + "bracketSameLine": false, + "bracketSpacing": true, + "semi": true, + "experimentalTernaries": false, + "singleQuote": false, + "jsxSingleQuote": false, + "quoteProps": "as-needed", + "trailingComma": "all", + "singleAttributePerLine": false, + "htmlWhitespaceSensitivity": "css", + "vueIndentScriptAndStyle": false, + "proseWrap": "preserve", + "insertPragma": false, + "printWidth": 1000, + "requirePragma": false, + "tabWidth": 2, + "useTabs": false, + "embeddedLanguageFormatting": "auto" +} diff --git a/Makefile b/Makefile index 6925dfff..4f1d8522 100755 --- a/Makefile +++ b/Makefile @@ -27,19 +27,19 @@ ifeq ($(CROSS)$(CC), emcc) endif ifdef NEDITOR - CPPFLAGS += -DNO_EDITOR + CPPFLAGS += -DNO_EDITOR endif ifdef NFLAC - CPPFLAGS += -DNFLAC + CPPFLAGS += -DNFLAC endif ifdef NMP3 - CPPFLAGS += -DNMP3 + CPPFLAGS += -DNMP3 endif ifdef NSVG - CPPFLAGS += -DNSVG + CPPFLAGS += -DNSVG endif ifdef NQOA @@ -297,4 +297,4 @@ tags: $(TAGINC) MYFILES != (ls scripts/*.js* source/engine/*.[ch] source/engine/sound/*.[ch]) pretty: - clang-format -i $(MYFILES) \ No newline at end of file + clang-format -i $(MYFILES) diff --git a/scripts/achievements.js b/scripts/achievements.js index bfb4215c..afd14722 100644 --- a/scripts/achievements.js +++ b/scripts/achievements.js @@ -16,5 +16,5 @@ achievement.doc = { hidden: "True if the player shouldn't see this achievement.", icon: "Path to an unlocked icon.", licon: "Path to icon for not achieved.", - max: "Value needed to reach to unlock the achievement." + max: "Value needed to reach to unlock the achievement.", }; diff --git a/scripts/actor.js b/scripts/actor.js index 07a92521..2c827b1c 100644 --- a/scripts/actor.js +++ b/scripts/actor.js @@ -5,8 +5,7 @@ var script_times = {}; var actor_spawns = {}; -globalThis.class_use = function(script, config, base, callback) -{ +globalThis.class_use = function (script, config, base, callback) { var file = Resources.find_script(script); if (!file) { @@ -31,24 +30,21 @@ globalThis.class_use = function(script, config, base, callback) var script = Resources.replstrs(file); script = `(function() { var self = this; var $ = this.__proto__; ${script}; })`; - - var fn = os.eval(file,script); + + var fn = os.eval(file, script); fn.call(padawan); - if (typeof config === 'object') - Object.merge(padawan,config); + if (typeof config === "object") Object.merge(padawan, config); return padawan; -} +}; -globalThis.rmactor = function(e) -{ +globalThis.rmactor = function (e) { if (!actor_spawns[e._file]) return; actor_spawns[e._file].remove(e); -} +}; -actor.__stats = function() -{ +actor.__stats = function () { var total = 0; var stats = {}; for (var i in actor_spawns) { @@ -57,10 +53,9 @@ actor.__stats = function() } stats.total = total; return stats; -} +}; -actor.hotreload = function() -{ +actor.hotreload = function () { profile.cache("hotreload", "check"); for (var i in script_times) { if (io.mod(i) > script_times[i]) { @@ -72,54 +67,54 @@ actor.hotreload = function() var $ = this.__proto__; ${script}; })`; - var fn = os.eval(i,script); - + var fn = os.eval(i, script); + for (var obj of actor_spawns[i]) { var a = obj; - for (var t of a.timers) - t(); - a.timers = []; - var save = json.decode(json.encode(a)); + for (var t of a.timers) t(); + a.timers = []; + var save = json.decode(json.encode(a)); fn.call(a); - Object.merge(a,save); - check_registers(a); + Object.merge(a, save); + check_registers(a); } } } profile.endcache(); -} +}; -actor.spawn = function(script, config){ - if (typeof script !== 'string') return undefined; +actor.spawn = function (script, config) { + if (typeof script !== "string") return undefined; var padawan = class_use(script, config, actor); - + padawan.padawans = []; padawan.timers = []; padawan.master = this; - Object.hide(padawan, "master","padawans"); - padawan.toString = function() { return script; } + Object.hide(padawan, "master", "padawans"); + padawan.toString = function () { + return script; + }; check_registers(padawan); this.padawans.push(padawan); if (padawan.awake) padawan.awake(); return padawan; }; -actor.tween = function(from,to,time,fn) { - var stop = tween(from,to,time,fn); +actor.tween = function (from, to, time, fn) { + var stop = tween(from, to, time, fn); this.timers.push(stop); return stop; -} +}; actor.spawn.doc = `Create a new actor, using this actor as the master, initializing it with 'script' and with data (as a JSON or Nota file) from 'config'.`; -actor.rm_pawn = function(pawn) -{ +actor.rm_pawn = function (pawn) { this.padawans.remove(pawn); -} +}; actor.timers = []; -actor.kill = function(){ +actor.kill = function () { if (this.__dead__) return; this.timers.forEach(t => t()); input.do_uncontrol(this); @@ -129,62 +124,65 @@ actor.kill = function(){ this.padawans = []; this.__dead__ = true; actor_spawns[this._file].remove(this); - if (typeof this.die === 'function') this.die(); - if (typeof this.stop === 'function') this.stop(); - if (typeof this.garbage === 'function') this.garbage(); - if (typeof this.then === 'function') this.then(); + if (typeof this.die === "function") this.die(); + if (typeof this.stop === "function") this.stop(); + if (typeof this.garbage === "function") this.garbage(); + if (typeof this.then === "function") this.then(); }; actor.kill.doc = `Remove this actor and all its padawans from existence.`; -actor.delay = function(fn, seconds) { +actor.delay = function (fn, seconds) { var timers = this.timers; - var stop = function() { + var stop = function () { timers.remove(stop); stop = undefined; rm(); - } + }; function execute() { if (fn) fn(); if (stop && stop.then) stop.then(); stop(); } - + stop.remain = seconds; stop.seconds = seconds; - stop.pct = function() { return 1-(stop.remain / stop.seconds); }; - + stop.pct = function () { + return 1 - stop.remain / stop.seconds; + }; + function update(dt) { profile.frame("timer"); stop.remain -= dt; if (stop.remain <= 0) execute(); profile.endframe(); } - + var rm = Register.appupdate.register(update); - + timers.push(stop); return stop; }; actor.delay.doc = `Call 'fn' after 'seconds' with 'this' set to the actor.`; -actor.interval = function(fn, seconds) -{ +actor.interval = function (fn, seconds) { var self = this; var stop; - var usefn = function() { + var usefn = function () { fn(); stop = self.delay(usefn, seconds); - } + }; stop = self.delay(usefn, seconds); return stop; -} +}; actor.padawans = []; global.app = Object.create(actor); -app.die = function() { os.quit(); } +app.die = function () { + os.quit(); +}; -return {actor, app}; +return { actor, app }; diff --git a/scripts/ai.js b/scripts/ai.js index 25eca196..90932551 100644 --- a/scripts/ai.js +++ b/scripts/ai.js @@ -1,58 +1,55 @@ var ai = { race(list) { - return function(dt) { + return function (dt) { var good = false; - for (var i = 0; i < list.length; i++) - if (list[i].call(this,dt)) good=true; - + for (var i = 0; i < list.length; i++) if (list[i].call(this, dt)) good = true; return good; }; }, sequence(list) { var i = 0; - var fn = function(dt) { + var fn = function (dt) { while (i !== list.length) { - if (list[i].call(this,dt)) - i++; - else - return false; + if (list[i].call(this, dt)) i++; + else return false; } if (fn.done) fn.done(); return true; }; - - fn.restart = function() { i = 0; }; + + fn.restart = function () { + i = 0; + }; return fn; }, parallel(list) { - return function(dt) { + return function (dt) { var good = true; - list.forEach(function(x){ if (!x.call(this,dt)) good = false; },this); + list.forEach(function (x) { + if (!x.call(this, dt)) good = false; + }, this); return good; }; }, - + dofor(secs, fn) { - return ai.race([ - ai.wait(secs), - fn - ]); + return ai.race([ai.wait(secs), fn]); }, wait(secs = 1) { var accum = 0; - return function(dt) { + return function (dt) { accum += dt; if (accum >= secs) { accum = 0; return true; } - + return false; }; }, }; -return {ai}; +return { ai }; diff --git a/scripts/base.js b/scripts/base.js index fe9e158e..17a2711a 100644 --- a/scripts/base.js +++ b/scripts/base.js @@ -30,44 +30,65 @@ Number.roman = { L: 50, X: 10, V: 5, - I: 1 + I: 1, }; var convert = {}; -convert.romanize = function(num) { +convert.romanize = function (num) { if (!+num) return false; - var digits = String(+num).split(''); - var key = ['','C','CC','CCC','CD','D','DC','DCC','DCCC','CM', - '','X','XX','XXX','XL','L','LX','LXX','LXXX','XC', - '','I','II','III','IV','V','VI','VII','VIII','IX']; - var roman = '', i = 3; - while (i--) roman = (key[+digits.pop() + (i * 10)] || '') + roman; - return Array(+digits.join('') + 1).join('M') + roman; -} + var digits = String(+num).split(""); + var key = ["", "C", "CC", "CCC", "CD", "D", "DC", "DCC", "DCCC", "CM", "", "X", "XX", "XXX", "XL", "L", "LX", "LXX", "LXXX", "XC", "", "I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX"]; + var roman = "", + i = 3; + while (i--) roman = (key[+digits.pop() + i * 10] || "") + roman; + return Array(+digits.join("") + 1).join("M") + roman; +}; -convert.deromanize = function(str) { +convert.deromanize = function (str) { var str = str.toUpperCase(); var validator = /^M*(?:D?C{0,3}|C[MD])(?:L?X{0,3}|X[CL])(?:V?I{0,3}|I[XV])$/; var token = /[MDLV]|C[MD]?|X[CL]?|I[XV]?/g; - var key = {M:1000,CM:900,D:500,CD:400,C:100,XC:90,L:50,XL:40,X:10,IX:9,V:5,IV:4,I:1}; - var num = 0, m; + var key = { + M: 1000, + CM: 900, + D: 500, + CD: 400, + C: 100, + XC: 90, + L: 50, + XL: 40, + X: 10, + IX: 9, + V: 5, + IV: 4, + I: 1, + }; + var num = 0, + m; if (!(str && validator.test(str))) return false; - while (m = token.exec(str)) num += key[m[0]]; + while ((m = token.exec(str))) num += key[m[0]]; return num; -} +}; -convert.buf2hex = function(buffer) { // buffer is an ArrayBuffer - return [...new Uint8Array(buffer)] - .map(x => x.toString(16).padStart(2, '0')) - .join(' '); -} +convert.buf2hex = function (buffer) { + // buffer is an ArrayBuffer + return [...new Uint8Array(buffer)].map(x => x.toString(16).padStart(2, "0")).join(" "); +}; /* Time values are always expressed in terms of real earth-seconds */ Object.assign(time, { - hour2minute() { return this.hour/this.minute; }, - day2hour() { return this.day/this.hour; }, - minute2second() { return this.minute/this.second; }, - week2day() { return this.week/this.day; }, + hour2minute() { + return this.hour / this.minute; + }, + day2hour() { + return this.day / this.hour; + }, + minute2second() { + return this.minute / this.second; + }, + week2day() { + return this.week / this.day; + }, }); time.strparse = { @@ -104,7 +125,7 @@ time.doc = { fmt: "Default format for time.", record: "Given a time, return an object with time fields.", number: "Return the number representation of a given time.", - text: "Return a text formatted time." + text: "Return a text formatted time.", }; time.second = 1; @@ -113,32 +134,31 @@ time.hour = 3_600; time.day = 86_400; time.week = 604_800; time.weekdays = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"]; -time.monthstr = ["January", "February", "March", 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December']; +time.monthstr = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"]; time.epoch = 1970; -time.isleap = function(year) { return this.yearsize(year) === 366; } +time.isleap = function (year) { + return this.yearsize(year) === 366; +}; time.isleap.doc = "Return true if the given year is a leapyear."; -time.yearsize = function(y) { - if (y%4 === 0 && (y%100 != 0 || y%400 === 0)) - return 366; +time.yearsize = function (y) { + if (y % 4 === 0 && (y % 100 != 0 || y % 400 === 0)) return 366; return 365; -} +}; -time.timecode = function(t, fps = 24) -{ +time.timecode = function (t, fps = 24) { var s = Math.trunc(t); t -= s; - return `${s}:${Math.trunc(fps*s)}`; -} + return `${s}:${Math.trunc(fps * s)}`; +}; -time.monthdays = [31,28,31,30,31,30,31,31,30,31,30,31]; +time.monthdays = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]; time.zones = {}; -time.zones['-12'] = 'IDLW'; -time.record = function(num, zone = this.computer_zone()) -{ - if (typeof num === 'object') return num; - else if (typeof num === 'number') { +time.zones["-12"] = "IDLW"; +time.record = function (num, zone = this.computer_zone()) { + if (typeof num === "object") return num; + else if (typeof num === "number") { var monthdays = this.monthdays.slice(); var rec = { second: 0, @@ -146,62 +166,52 @@ time.record = function(num, zone = this.computer_zone()) hour: 0, yday: 0, year: 0, - zone: 0 + zone: 0, }; rec.zone = zone; - num += zone*this.hour; - + num += zone * this.hour; + var hms = num % this.day; - var day = parseInt(num/this.day); + var day = parseInt(num / this.day); if (hms < 0) { hms += this.day; day--; } - rec.second = hms%this.minute; - var d1 = Math.floor(hms/this.minute); + rec.second = hms % this.minute; + var d1 = Math.floor(hms / this.minute); rec.minute = d1 % this.minute; - rec.hour = Math.floor(d1/this.minute); + rec.hour = Math.floor(d1 / this.minute); /* addend%7 is 4 */ - rec.weekday = (day + 4503599627370496+2)%7; + rec.weekday = (day + 4503599627370496 + 2) % 7; var d1 = this.epoch; - if (day >= 0) - for (d1= this.epoch; day >= this.yearsize(d1); d1++) - day -= this.yearsize(d1); - else - for (d1 = this.epoch; day < 0; d1--) - day += this.yearsize(d1-1); + if (day >= 0) for (d1 = this.epoch; day >= this.yearsize(d1); d1++) day -= this.yearsize(d1); + else for (d1 = this.epoch; day < 0; d1--) day += this.yearsize(d1 - 1); rec.year = d1; - if (rec.year <= 0) - rec.ce = 'BC'; - else - rec.ce = 'AD'; - + if (rec.year <= 0) rec.ce = "BC"; + else rec.ce = "AD"; + rec.yday = day; - if (this.yearsize(d1) === 366) - monthdays[1] = 29; + if (this.yearsize(d1) === 366) monthdays[1] = 29; - var d0 = day; - for (d1 = 0; d0 >= monthdays[d1]; d1++) - d0 -= monthdays[d1]; + var d0 = day; + for (d1 = 0; d0 >= monthdays[d1]; d1++) d0 -= monthdays[d1]; monthdays[1] = 28; rec.day = d0 + 1; rec.month = d1; - return rec; - } -} - -time.number = function(rec) -{ - if (typeof rec === 'number') return rec; - else if (typeof rec === 'object') { + } +}; + +time.number = function (rec) { + if (typeof rec === "number") return rec; + else if (typeof rec === "object") { var c = 0; var year = rec.year ? rec.year : 0; var hour = rec.hour ? rec.hour : 0; @@ -209,18 +219,15 @@ time.number = function(rec) var second = rec.second ? rec.second : 0; var zone = rec.zone ? rec.zone : 0; - if (year > this.epoch) - for (var i = this.epoch; i < year; i++) - c += this.day*this.yearsize(i); + if (year > this.epoch) for (var i = this.epoch; i < year; i++) c += this.day * this.yearsize(i); else if (year < this.epoch) { - for (var i = this.epoch-1; i > year; i--) - c += this.day*this.yearsize(i); + for (var i = this.epoch - 1; i > year; i--) c += this.day * this.yearsize(i); - c += (this.yearsize(year)-yday-1)*this.day; - c += (this.day2hour()-hour-1)*this.hour; - c += (this.hour2minute()-minute-1)*this.minute; - c += (this.minute2second()-second); - c += zone*this.hour; + c += (this.yearsize(year) - yday - 1) * this.day; + c += (this.day2hour() - hour - 1) * this.hour; + c += (this.hour2minute() - minute - 1) * this.minute; + c += this.minute2second() - second; + c += zone * this.hour; c *= -1; return c; } @@ -233,7 +240,7 @@ time.number = function(rec) return c; } -} +}; /* Time formatting yyyy - year in a 4 digit field @@ -260,92 +267,82 @@ time.number = function(rec) time.fmt = "vB mB d h:nn:ss TZz a y c"; /* If num is a number, converts to a rec first. */ -time.text = function(num, fmt = this.fmt, zone) -{ +time.text = function (num, fmt = this.fmt, zone) { var rec = num; - - if (typeof rec === 'number') - rec = time.record(num, zone); + + if (typeof rec === "number") rec = time.record(num, zone); zone = rec.zone; - if (fmt.match('a')) { + if (fmt.match("a")) { if (rec.hour >= 13) { rec.hour -= 12; - fmt = fmt.replaceAll('a', 'PM'); - } else if (rec.hour === 12) - fmt = fmt.replaceAll('a', 'PM'); + fmt = fmt.replaceAll("a", "PM"); + } else if (rec.hour === 12) fmt = fmt.replaceAll("a", "PM"); else if (rec.hour === 0) { rec.hour = 12; - fmt = fmt.replaceAll('a', 'AM'); - } else - fmt = fmt.replaceAll('a', 'AM'); + fmt = fmt.replaceAll("a", "AM"); + } else fmt = fmt.replaceAll("a", "AM"); } var year = rec.year > 0 ? rec.year : rec.year - 1; - if (fmt.match('c')) { + if (fmt.match("c")) { if (year < 0) { year = Math.abs(year); - fmt = fmt.replaceAll('c', 'BC'); - } else - fmt = fmt.replaceAll('c', 'AD'); + fmt = fmt.replaceAll("c", "BC"); + } else fmt = fmt.replaceAll("c", "AD"); } - - fmt = fmt.replaceAll('yyyy', year.toString().padStart(4,'0')); - fmt = fmt.replaceAll('y', year); - fmt = fmt.replaceAll('eee', rec.yday+1); - fmt = fmt.replaceAll('dd', rec.day.toString().padStart(2,'0')); - fmt = fmt.replaceAll('d', rec.day); - fmt = fmt.replaceAll('hh', rec.hour.toString().padStart(2,'0')); - fmt = fmt.replaceAll('h', rec.hour); - fmt = fmt.replaceAll('nn', rec.minute.toString().padStart(2,'0')); - fmt = fmt.replaceAll('n', rec.minute); - fmt = fmt.replaceAll('ss', rec.second.toString().padStart(2, '0')); - fmt = fmt.replaceAll('s', rec.second); - fmt = fmt.replaceAll('z', zone >= 0 ? "+" + zone : zone); - fmt = fmt.replaceAll(/mm[^bB]/g, rec.month+1); - fmt = fmt.replaceAll(/m[^bB]/g, rec.month+1); - fmt = fmt.replaceAll(/v[^bB]/g, rec.weekday); - fmt = fmt.replaceAll('mb', this.monthstr[rec.month].slice(0,3)); - fmt = fmt.replaceAll('mB', this.monthstr[rec.month]); - fmt = fmt.replaceAll('vB', this.weekdays[rec.weekday]); - fmt = fmt.replaceAll('vb', this.weekdays[rec.weekday].slice(0,3)); + + fmt = fmt.replaceAll("yyyy", year.toString().padStart(4, "0")); + fmt = fmt.replaceAll("y", year); + fmt = fmt.replaceAll("eee", rec.yday + 1); + fmt = fmt.replaceAll("dd", rec.day.toString().padStart(2, "0")); + fmt = fmt.replaceAll("d", rec.day); + fmt = fmt.replaceAll("hh", rec.hour.toString().padStart(2, "0")); + fmt = fmt.replaceAll("h", rec.hour); + fmt = fmt.replaceAll("nn", rec.minute.toString().padStart(2, "0")); + fmt = fmt.replaceAll("n", rec.minute); + fmt = fmt.replaceAll("ss", rec.second.toString().padStart(2, "0")); + fmt = fmt.replaceAll("s", rec.second); + fmt = fmt.replaceAll("z", zone >= 0 ? "+" + zone : zone); + fmt = fmt.replaceAll(/mm[^bB]/g, rec.month + 1); + fmt = fmt.replaceAll(/m[^bB]/g, rec.month + 1); + fmt = fmt.replaceAll(/v[^bB]/g, rec.weekday); + fmt = fmt.replaceAll("mb", this.monthstr[rec.month].slice(0, 3)); + fmt = fmt.replaceAll("mB", this.monthstr[rec.month]); + fmt = fmt.replaceAll("vB", this.weekdays[rec.weekday]); + fmt = fmt.replaceAll("vb", this.weekdays[rec.weekday].slice(0, 3)); return fmt; -} +}; -Object.methods = function(o) -{ +Object.methods = function (o) { var m = []; - Object.keys(o).forEach(function(k) { - if (typeof o[k] === 'function') m.push(k); + Object.keys(o).forEach(function (k) { + if (typeof o[k] === "function") m.push(k); }); return m; -} +}; Object.methods.doc = "Retun an array of all functions an object has access to."; -Object.dig = function(obj, path, def = {}) -{ - var pp = path.split('.'); - for (var i = 0; i < pp.length-1; i++) { +Object.dig = function (obj, path, def = {}) { + var pp = path.split("."); + for (var i = 0; i < pp.length - 1; i++) { obj = obj[pp[i]] = obj[pp[i]] || {}; } - obj[pp[pp.length-1]] = def; + obj[pp[pp.length - 1]] = def; return def; -} +}; -Object.rkeys = function(o) -{ +Object.rkeys = function (o) { var keys = []; - Object.keys(o).forEach(function(key) { + Object.keys(o).forEach(function (key) { keys.push(key); - if (Object.isObject(o[key])) - keys.push(Object.rkeys(o[key])); + if (Object.isObject(o[key])) keys.push(Object.rkeys(o[key])); }); return keys; -} +}; -Object.readonly = function(o, name, msg) -{ +Object.readonly = function (o, name, msg) { var tmp = {}; var prop = Object.getOwnPropertyDescriptor(o, name); if (!prop) { @@ -353,500 +350,478 @@ Object.readonly = function(o, name, msg) return; } Object.defineProperty(tmp, name, prop); - prop.get = function() { return tmp[name]; } - prop.set = function() { console.warn(`Attempted to set readonly property ${name}`); } + prop.get = function () { + return tmp[name]; + }; + prop.set = function () { + console.warn(`Attempted to set readonly property ${name}`); + }; Object.defineProperty(o, name, prop); -} +}; -Object.mixin = function(target, source) -{ - if (typeof source !== 'object') return target; +Object.mixin = function (target, source) { + if (typeof source !== "object") return target; Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); return target; }; -Object.mix = function(...objs) -{ +Object.mix = function (...objs) { var n = {}; - for (var o of objs) - Object.mixin(n,o); + for (var o of objs) Object.mixin(n, o); return n; -} +}; -Object.deepmixin = function(target, source) -{ +Object.deepmixin = function (target, source) { var o = source; while (o !== Object.prototype) { Object.mixin(target, o); o = o.__proto__; - }; -} + } +}; -Object.deepfreeze = function(obj) -{ +Object.deepfreeze = function (obj) { for (var key in obj) { - if (typeof obj[key] === 'object') - Object.deepfreeze(obj[key]); + if (typeof obj[key] === "object") Object.deepfreeze(obj[key]); } Object.freeze(obj); -} +}; /* Goes through each key and overwrites if it's present */ -Object.dainty_assign = function(target, source) -{ - Object.keys(source).forEach(function(k) { - if (typeof source[k] === 'function') return; +Object.dainty_assign = function (target, source) { + Object.keys(source).forEach(function (k) { + if (typeof source[k] === "function") return; if (!(k in target)) return; - if (Array.isArray(source[k])) - target[k] = deep_copy(source[k]); - else if (Object.isObject(source[k])) - Object.dainty_assign(target[k], source[k]); - else - target[k] = source[k]; + if (Array.isArray(source[k])) target[k] = deep_copy(source[k]); + else if (Object.isObject(source[k])) Object.dainty_assign(target[k], source[k]); + else target[k] = source[k]; }); -} +}; -Object.isObject = function(o) -{ - return (o instanceof Object && !(o instanceof Array)); -} +Object.isObject = function (o) { + return o instanceof Object && !(o instanceof Array); +}; -Object.setter_assign = function(target, source) -{ - for (var key in target) - if (Object.isAccessor(target,key) && typeof source[key] !== 'undefined') - target[key] = source[key]; -} +Object.setter_assign = function (target, source) { + for (var key in target) if (Object.isAccessor(target, key) && typeof source[key] !== "undefined") target[key] = source[key]; +}; -Object.containingKey = function(obj, prop) -{ - if (typeof obj !== 'object') return undefined; +Object.containingKey = function (obj, prop) { + if (typeof obj !== "object") return undefined; if (!(prop in obj)) return undefined; - + var o = obj; - while (o.__proto__ && !Object.hasOwn(o, prop)) - o = o.__proto__; + while (o.__proto__ && !Object.hasOwn(o, prop)) o = o.__proto__; return o; -} +}; -Object.access = function(obj, name) -{ - var dig = name.split('.'); +Object.access = function (obj, name) { + var dig = name.split("."); for (var i of dig) { obj = obj[i]; if (!obj) return undefined; } - - return obj; -} -Object.isAccessor = function(obj, prop) -{ - var o = Object.containingKey(obj,prop); + return obj; +}; + +Object.isAccessor = function (obj, prop) { + var o = Object.containingKey(obj, prop); if (!o) return false; - - var desc = Object.getOwnPropertyDescriptor(o,prop); + + var desc = Object.getOwnPropertyDescriptor(o, prop); if (!desc) return false; if (desc.get || desc.set) return true; return false; -} +}; -Object.mergekey = function(o1,o2,k) -{ +Object.mergekey = function (o1, o2, k) { if (!o2) return; - if (typeof o2[k] === 'object') { - if (Array.isArray(o2[k])) - o1[k] = deep_copy(o2[k]); + if (typeof o2[k] === "object") { + if (Array.isArray(o2[k])) o1[k] = deep_copy(o2[k]); else { if (!o1[k]) o1[k] = {}; - if (typeof o1[k] === 'object') - Object.merge(o1[k], o2[k]); - else - o1[k] = o2[k]; + if (typeof o1[k] === "object") Object.merge(o1[k], o2[k]); + else o1[k] = o2[k]; } - } else - o1[k] = o2[k]; -} + } else o1[k] = o2[k]; +}; /* Same as merge from Ruby */ /* Adds objs key by key to target */ -Object.merge = function(target, ...objs) -{ - for (var obj of objs) - for (var key of Object.keys(obj)) - Object.mergekey(target,obj,key); +Object.merge = function (target, ...objs) { + for (var obj of objs) for (var key of Object.keys(obj)) Object.mergekey(target, obj, key); return target; -} +}; -Object.totalmerge = function(target, ...objs) -{ - for (var obj of objs) - for (var key in obj) - Object.mergekey(target,obj,key); +Object.totalmerge = function (target, ...objs) { + for (var obj of objs) for (var key in obj) Object.mergekey(target, obj, key); return target; -} +}; /* Returns a new object with undefined, null, and empty values removed. */ -Object.compact = function(obj) -{ +Object.compact = function (obj) {}; -} - -Object.totalassign = function(to, from) -{ - for (var key in from) - to[key] = from[key]; -} +Object.totalassign = function (to, from) { + for (var key in from) to[key] = from[key]; +}; /* Prototypes out an object and assigns values */ -Object.copy = function(proto, ...objs) -{ +Object.copy = function (proto, ...objs) { var c = Object.create(proto); - for (var obj of objs) - Object.mixin(c, obj); + for (var obj of objs) Object.mixin(c, obj); return c; -} +}; /* OBJECT DEFININTIONS */ -Object.defHidden = function(obj, prop) -{ - Object.defineProperty(obj, prop, {enumerable:false, writable:true}); -} +Object.defHidden = function (obj, prop) { + Object.defineProperty(obj, prop, { enumerable: false, writable: true }); +}; -Object.hide = function(obj,...props) -{ +Object.hide = function (obj, ...props) { for (var prop of props) { - var p = Object.getOwnPropertyDescriptor(obj,prop); + var p = Object.getOwnPropertyDescriptor(obj, prop); if (!p) continue; p.enumerable = false; Object.defineProperty(obj, prop, p); } -} +}; -Object.enumerable = function(obj, val, ...props) -{ +Object.enumerable = function (obj, val, ...props) { for (var prop of props) { - p = Object.getOwnPropertyDescriptor(obj,prop); + p = Object.getOwnPropertyDescriptor(obj, prop); if (!p) continue; p.enumerable = val; Object.defineProperty(obj, prop, p); - } -} + } +}; -Object.unhide = function(obj, ...props) -{ +Object.unhide = function (obj, ...props) { for (var prop of props) { - var p = Object.getOwnPropertyDescriptor(obj,prop); + var p = Object.getOwnPropertyDescriptor(obj, prop); if (!p) continue; p.enumerable = true; Object.defineProperty(obj, prop, p); } -} +}; -Object.defineProperty(Object.prototype, 'obscure', { - value: function(name) { +Object.defineProperty(Object.prototype, "obscure", { + value: function (name) { Object.defineProperty(this, name, { enumerable: false }); - } -}); - -Object.defineProperty(Object.prototype, 'mixin', { - value: function(obj) { - if (typeof obj === 'string') - obj = use(obj); - - if (obj) - Object.mixin(this, obj); }, }); -Object.defineProperty(Object.prototype, 'hasOwn', { - value: function(x) { return this.hasOwnProperty(x); } +Object.defineProperty(Object.prototype, "mixin", { + value: function (obj) { + if (typeof obj === "string") obj = use(obj); + + if (obj) Object.mixin(this, obj); + }, }); -Object.defineProperty(Object.prototype, 'defn', { - value: function(name, val) { - Object.defineProperty(this, name, { value:val, writable:true, configurable:true }); - } +Object.defineProperty(Object.prototype, "hasOwn", { + value: function (x) { + return this.hasOwnProperty(x); + }, }); -Object.defineProperty(Object.prototype, 'nulldef', { - value: function(name, val) { +Object.defineProperty(Object.prototype, "defn", { + value: function (name, val) { + Object.defineProperty(this, name, { + value: val, + writable: true, + configurable: true, + }); + }, +}); + +Object.defineProperty(Object.prototype, "nulldef", { + value: function (name, val) { if (!this.hasOwnProperty(name)) this[name] = val; - } + }, }); -Object.defineProperty(Object.prototype, 'prop_obj', { - value: function() { return JSON.parse(JSON.stringify(this)); } +Object.defineProperty(Object.prototype, "prop_obj", { + value: function () { + return JSON.parse(JSON.stringify(this)); + }, }); /* defc 'define constant'. Defines a value that is not writable. */ -Object.defineProperty(Object.prototype, 'defc', { - value: function(name, val) { - Object.defineProperty(this,name, { +Object.defineProperty(Object.prototype, "defc", { + value: function (name, val) { + Object.defineProperty(this, name, { value: val, - writable:false, - enumerable:true, - configurable:false, + writable: false, + enumerable: true, + configurable: false, }); - } + }, }); -Object.defineProperty(Object.prototype, 'stick', { - value: function(prop) { - Object.defineProperty(this, prop, {writable:false}); - } +Object.defineProperty(Object.prototype, "stick", { + value: function (prop) { + Object.defineProperty(this, prop, { writable: false }); + }, }); -Object.defineProperty(Object.prototype, 'harden', { - value: function(prop) { - Object.defineProperty(this, prop, {writable:false, configurable:false, enumerable: false}); - } +Object.defineProperty(Object.prototype, "harden", { + value: function (prop) { + Object.defineProperty(this, prop, { + writable: false, + configurable: false, + enumerable: false, + }); + }, }); -Object.defineProperty(Object.prototype, 'deflock', { - value: function(prop) { - Object.defineProperty(this,prop, {configurable:false}); - } +Object.defineProperty(Object.prototype, "deflock", { + value: function (prop) { + Object.defineProperty(this, prop, { configurable: false }); + }, }); -Object.defineProperty(Object.prototype, 'forEach', { - value: function(fn) { +Object.defineProperty(Object.prototype, "forEach", { + value: function (fn) { Object.values(this).forEach(fn); - } + }, }); -Object.empty = function(obj) { +Object.empty = function (obj) { return Object.keys(obj).length === 0; -} +}; -Object.defineProperty(Object.prototype, 'nth', { - value: function(x) { +Object.defineProperty(Object.prototype, "nth", { + value: function (x) { if (this.empty || x >= Object.keys(this).length) return null; return this[Object.keys(this)[x]]; }, }); -Object.defineProperty(Object.prototype, 'filter', { - value: function(fn) { +Object.defineProperty(Object.prototype, "filter", { + value: function (fn) { return Object.values(this).filter(fn); - } + }, }); - -Object.defineProperty(Object.prototype, 'push', { - value: function(val) { + +Object.defineProperty(Object.prototype, "push", { + value: function (val) { var str = val.toString(); - str = str.replaceAll('.', '_'); + str = str.replaceAll(".", "_"); var n = 1; var t = str; - while (Object.hasOwn(this,t)) { + while (Object.hasOwn(this, t)) { t = str + n; - n++; + n++; } this[t] = val; return t; - } + }, }); /* STRING DEFS */ -Object.defineProperty(String.prototype, 'next', { - value: function(char, from) { - if (!Array.isArray(char)) - char = [char]; - if (from > this.length-1) - return -1; - else if (!from) - from = 0; +Object.defineProperty(String.prototype, "next", { + value: function (char, from) { + if (!Array.isArray(char)) char = [char]; + if (from > this.length - 1) return -1; + else if (!from) from = 0; var find = this.slice(from).search(char[0]); - if (find === -1) - return -1; - else - return from + find; - + if (find === -1) return -1; + else return from + find; + var i = 0; - var c = this.charAt(from+i); + var c = this.charAt(from + i); while (!char.includes(c)) { i++; - if (from+i >this.length-1) return -1; - c = this.charAt(from+i); + if (from + i > this.length - 1) return -1; + c = this.charAt(from + i); } - return from+i; - } + return from + i; + }, }); -Object.defineProperty(String.prototype, 'prev', { - value: function(char, from, count) { - if (from > this.length-1) - return -1; - else if (!from) - from = this.length-1; +Object.defineProperty(String.prototype, "prev", { + value: function (char, from, count) { + if (from > this.length - 1) return -1; + else if (!from) from = this.length - 1; if (!count) count = 0; - var find = this.slice(0,from).lastIndexOf(char); + var find = this.slice(0, from).lastIndexOf(char); while (count > 1) { - find = this.slice(0,find).lastIndexOf(char); + find = this.slice(0, find).lastIndexOf(char); count--; } - if (find === -1) - return 0; - else - return find; - } + if (find === -1) return 0; + else return find; + }, }); -Object.defineProperty(String.prototype, 'shift', { - value: function(n) { +Object.defineProperty(String.prototype, "shift", { + value: function (n) { if (n === 0) return this.slice(); - if (n > 0) - return this.slice(n); + if (n > 0) return this.slice(n); - if (n < 0) - return this.slice(0, this.length+n); - } + if (n < 0) return this.slice(0, this.length + n); + }, }); -Object.defineProperty(String.prototype, 'strip_ext', { - value: function() { return this.tolast('.'); } +Object.defineProperty(String.prototype, "strip_ext", { + value: function () { + return this.tolast("."); + }, }); -Object.defineProperty(String.prototype, 'ext', { - value: function() { return this.fromlast('.'); } +Object.defineProperty(String.prototype, "ext", { + value: function () { + return this.fromlast("."); + }, }); -Object.defineProperty(String.prototype, 'set_ext', { - value: function(val) { return this.strip_ext() + val; } +Object.defineProperty(String.prototype, "set_ext", { + value: function (val) { + return this.strip_ext() + val; + }, }); -Object.defineProperty(String.prototype, 'folder_same_name', { - value: function() { - var dirs = this.dir().split('/'); +Object.defineProperty(String.prototype, "folder_same_name", { + value: function () { + var dirs = this.dir().split("/"); return dirs.last() === this.name(); - } + }, }); -Object.defineProperty(String.prototype, 'up_path', { - value: function() { +Object.defineProperty(String.prototype, "up_path", { + value: function () { var base = this.base(); - var dirs = this.dir().split('/'); + var dirs = this.dir().split("/"); dirs.pop(); - return dirs.join('/') + base; - } + return dirs.join("/") + base; + }, }); -Object.defineProperty(String.prototype, 'fromlast', { - value: function(val) { +Object.defineProperty(String.prototype, "fromlast", { + value: function (val) { var idx = this.lastIndexOf(val); if (idx === -1) return ""; - return this.slice(idx+1); - } + return this.slice(idx + 1); + }, }); -Object.defineProperty(String.prototype, 'tofirst', { - value: function(val) { +Object.defineProperty(String.prototype, "tofirst", { + value: function (val) { var idx = this.indexOf(val); if (idx === -1) return this.slice(); - return this.slice(0,idx); - } + return this.slice(0, idx); + }, }); -Object.defineProperty(String.prototype, 'fromfirst', { - value: function(val) { +Object.defineProperty(String.prototype, "fromfirst", { + value: function (val) { var idx = this.indexOf(val); if (idx === -1) return this; - return this.slice(idx+val.length); - } + return this.slice(idx + val.length); + }, }); -Object.defineProperty(String.prototype, 'name', { - value: function() { - var idx = this.indexOf('/'); - if (idx === -1) - return this.tolast('.'); - return this.fromlast('/').tolast('.'); } +Object.defineProperty(String.prototype, "name", { + value: function () { + var idx = this.indexOf("/"); + if (idx === -1) return this.tolast("."); + return this.fromlast("/").tolast("."); + }, }); -Object.defineProperty(String.prototype, 'set_name', { - value: function(name) { +Object.defineProperty(String.prototype, "set_name", { + value: function (name) { var dir = this.dir(); return this.dir() + "/" + name + "." + this.ext(); - } + }, }); -Object.defineProperty(String.prototype, 'base', { - value: function() { return this.fromlast('/'); } +Object.defineProperty(String.prototype, "base", { + value: function () { + return this.fromlast("/"); + }, }); -Object.defineProperty(String.prototype, 'splice', { - value: function(index, str) { - return this.slice(0,index) + str + this.slice(index); - } +Object.defineProperty(String.prototype, "splice", { + value: function (index, str) { + return this.slice(0, index) + str + this.slice(index); + }, }); -Object.defineProperty(String.prototype, 'sub', { - value: function(index, str) { - return this.slice(0,index) + str + this.slice(index+str.length); - } +Object.defineProperty(String.prototype, "sub", { + value: function (index, str) { + return this.slice(0, index) + str + this.slice(index + str.length); + }, }); -Object.defineProperty(String.prototype, 'updir', { - value: function() { - if (this.lastIndexOf('/') === this.length-1) - return this.slice(0,this.length-1); - +Object.defineProperty(String.prototype, "updir", { + value: function () { + if (this.lastIndexOf("/") === this.length - 1) return this.slice(0, this.length - 1); + var dir = (this + "/").dir(); return dir.dir(); - } + }, }); -Object.defineProperty(String.prototype, 'trimchr', { - value: function(chars) { +Object.defineProperty(String.prototype, "trimchr", { + value: function (chars) { return vector.trimchr(this, chars); - } + }, }); -Object.defineProperty(String.prototype, 'uc', { value: function() { return this.toUpperCase(); } }); -Object.defineProperty(String.prototype, 'lc', {value:function() { return this.toLowerCase(); }}); +Object.defineProperty(String.prototype, "uc", { + value: function () { + return this.toUpperCase(); + }, +}); +Object.defineProperty(String.prototype, "lc", { + value: function () { + return this.toLowerCase(); + }, +}); /* ARRAY DEFS */ -Object.defineProperty(Array.prototype, 'copy', { - value: function() { +Object.defineProperty(Array.prototype, "copy", { + value: function () { var c = []; - this.forEach(function(x, i) { + this.forEach(function (x, i) { c[i] = deep_copy(x); }); - + return c; - } + }, }); -Object.defineProperty(Array.prototype, 'forFrom', { - value: function(n, fn) { +Object.defineProperty(Array.prototype, "forFrom", { + value: function (n, fn) { for (var i = n; i < this.length; i++) fn(this[i]); - } + }, }); -Object.defineProperty(Array.prototype, 'forTo', { - value: function(n, fn) { +Object.defineProperty(Array.prototype, "forTo", { + value: function (n, fn) { for (var i = 0; i < n; i++) fn(this[i]); - } + }, }); -Object.defineProperty(Array.prototype, 'dofilter', { - value: function(fn) { +Object.defineProperty(Array.prototype, "dofilter", { + value: function (fn) { for (let i = 0; i < this.length; i++) { if (!fn.call(this, this[i], i, this)) { this.splice(i, 1); @@ -854,129 +829,161 @@ Object.defineProperty(Array.prototype, 'dofilter', { } } return this; - } + }, }); -Object.defineProperty(Array.prototype, 'reversed', { - value: function() { +Object.defineProperty(Array.prototype, "reversed", { + value: function () { var c = this.slice(); return c.reverse(); - } + }, }); -Object.defineProperty(Array.prototype, 'rotate', { - value: function(a) { +Object.defineProperty(Array.prototype, "rotate", { + value: function (a) { return Vector.rotate(this, a); - } + }, }); function make_swizz() { -function setelem(n) { - return { - get: function() { return this[n]; }, - set: function(x) { this[n] = x; } + function setelem(n) { + return { + get: function () { + return this[n]; + }, + set: function (x) { + this[n] = x; + }, + }; } -}; -function arrsetelem(str, n) -{ - Object.defineProperty(Array.prototype, str, setelem(n)); -} + function arrsetelem(str, n) { + Object.defineProperty(Array.prototype, str, setelem(n)); + } -var arr_elems = ['x', 'y', 'z', 'w']; -var quat_elems = ['i', 'j', 'k']; -var color_elems = ['r', 'g', 'b', 'a']; + var arr_elems = ["x", "y", "z", "w"]; + var quat_elems = ["i", "j", "k"]; + var color_elems = ["r", "g", "b", "a"]; -arr_elems.forEach(function(x, i) { arrsetelem(x,i); }); -quat_elems.forEach(function(x, i) { arrsetelem(x,i); }); -color_elems.forEach(function(x, i) { arrsetelem(x,i); }); - -var nums = [0,1,2,3]; - -var swizz = []; - -for (var i of nums) - for (var j of nums) - swizz.push([i,j]); - -swizz.forEach(function(x) { - var str = ""; - for (var i of x) - str += arr_elems[i]; - - Object.defineProperty(Array.prototype, str, { - get() { return [this[x[0]], this[x[1]]]; }, - set(j) { this[x[0]] = j[0]; this[x[1]] = j[1]; }, + arr_elems.forEach(function (x, i) { + arrsetelem(x, i); + }); + quat_elems.forEach(function (x, i) { + arrsetelem(x, i); + }); + color_elems.forEach(function (x, i) { + arrsetelem(x, i); }); - str = ""; - for (var i of x) str += color_elems[i]; - Object.defineProperty(Array.prototype, str, { - get() { return [this[x[0]], this[x[1]]]; }, - set(j) { this[x[0]] = j[0]; this[x[1]] = j[1]; }, - }); + var nums = [0, 1, 2, 3]; -}); + var swizz = []; + for (var i of nums) for (var j of nums) swizz.push([i, j]); -swizz = []; -for (var i of nums) - for (var j of nums) - for (var k of nums) - swizz.push([i,j,k]); + swizz.forEach(function (x) { + var str = ""; + for (var i of x) str += arr_elems[i]; -swizz.forEach(function(x) { - var str = ""; - for (var i of x) - str += arr_elems[i]; - - Object.defineProperty(Array.prototype, str, { - get() { return [this[x[0]], this[x[1]], this[x[2]]]; }, - set(j) { this[x[0]] = j[0]; this[x[1]] = j[1]; this[x[2]] = j[2];}, - }); - - str = ""; - for (var i of x) str += color_elems[i]; - Object.defineProperty(Array.prototype, str, { - get() { return [this[x[0]], this[x[1]], this[x[2]]]; }, - set(j) { this[x[0]] = j[0]; this[x[1]] = j[1]; this[x[2]] = j[2];}, - }); -}); - -swizz = []; -for (var i of nums) - for (var j of nums) - for (var k of nums) - for (var w of nums) - swizz.push([i,j,k,w]); - -swizz.forEach(function(x) { - var str = ""; - for (var i of x) - str += arr_elems[i]; - - Object.defineProperty(Array.prototype, str, { - get() { return [this[x[0]], this[x[1]], this[x[2]], this[x[3]]];}, - set(j) { this[x[0]] = j[0]; this[x[1]] = j[1]; this[x[2]] = j[2]; this[x[3]] = j[3];}, - }); - - str = ""; - for (var i of x) str += color_elems[i]; Object.defineProperty(Array.prototype, str, { - get() { return [this[x[0]], this[x[1]], this[x[2]], this[x[3]]];}, - set(j) { this[x[0]] = j[0]; this[x[1]] = j[1]; this[x[2]] = j[2]; this[x[3]] = j[3];}, + get() { + return [this[x[0]], this[x[1]]]; + }, + set(j) { + this[x[0]] = j[0]; + this[x[1]] = j[1]; + }, + }); + + str = ""; + for (var i of x) str += color_elems[i]; + Object.defineProperty(Array.prototype, str, { + get() { + return [this[x[0]], this[x[1]]]; + }, + set(j) { + this[x[0]] = j[0]; + this[x[1]] = j[1]; + }, + }); }); -}); -}; + swizz = []; + for (var i of nums) for (var j of nums) for (var k of nums) swizz.push([i, j, k]); + + swizz.forEach(function (x) { + var str = ""; + for (var i of x) str += arr_elems[i]; + + Object.defineProperty(Array.prototype, str, { + get() { + return [this[x[0]], this[x[1]], this[x[2]]]; + }, + set(j) { + this[x[0]] = j[0]; + this[x[1]] = j[1]; + this[x[2]] = j[2]; + }, + }); + + str = ""; + for (var i of x) str += color_elems[i]; + Object.defineProperty(Array.prototype, str, { + get() { + return [this[x[0]], this[x[1]], this[x[2]]]; + }, + set(j) { + this[x[0]] = j[0]; + this[x[1]] = j[1]; + this[x[2]] = j[2]; + }, + }); + }); + + swizz = []; + for (var i of nums) for (var j of nums) for (var k of nums) for (var w of nums) swizz.push([i, j, k, w]); + + swizz.forEach(function (x) { + var str = ""; + for (var i of x) str += arr_elems[i]; + + Object.defineProperty(Array.prototype, str, { + get() { + return [this[x[0]], this[x[1]], this[x[2]], this[x[3]]]; + }, + set(j) { + this[x[0]] = j[0]; + this[x[1]] = j[1]; + this[x[2]] = j[2]; + this[x[3]] = j[3]; + }, + }); + + str = ""; + for (var i of x) str += color_elems[i]; + Object.defineProperty(Array.prototype, str, { + get() { + return [this[x[0]], this[x[1]], this[x[2]], this[x[3]]]; + }, + set(j) { + this[x[0]] = j[0]; + this[x[1]] = j[1]; + this[x[2]] = j[2]; + this[x[3]] = j[3]; + }, + }); + }); +} make_swizz(); -Object.defineProperty(Array.prototype, 'normalized', { - value: function() { return vector.norm(this); } +Object.defineProperty(Array.prototype, "normalized", { + value: function () { + return vector.norm(this); + }, }); -Object.defineProperty(Array.prototype, 'newfirst', { - value: function(i) { +Object.defineProperty(Array.prototype, "newfirst", { + value: function (i) { var c = this.slice(); if (i >= c.length) return c; @@ -986,195 +993,212 @@ Object.defineProperty(Array.prototype, 'newfirst', { } while (i > 0); return c; - } + }, }); -Object.defineProperty(Array.prototype, 'doubleup', { - value: function(n) { +Object.defineProperty(Array.prototype, "doubleup", { + value: function (n) { var c = []; - this.forEach(function(x) { - for (var i = 0; i < n; i++) - c.push(x); + this.forEach(function (x) { + for (var i = 0; i < n; i++) c.push(x); }); - + return c; - } + }, }); -Object.defineProperty(Array.prototype, 'mult', { - value: function(arr) { +Object.defineProperty(Array.prototype, "mult", { + value: function (arr) { var c = []; - for (var i = 0; i < this.length; i++) { c[i] = this[i] * arr[i]; } + for (var i = 0; i < this.length; i++) { + c[i] = this[i] * arr[i]; + } return c; -}}); - -Object.defineProperty(Array.prototype, 'apply', { - value: function(fn) { - this.forEach(function(x) { x[fn].apply(x); }); - } + }, }); -Object.defineProperty(Array.prototype, 'sorted', { - value: function() { +Object.defineProperty(Array.prototype, "apply", { + value: function (fn) { + this.forEach(function (x) { + x[fn].apply(x); + }); + }, +}); + +Object.defineProperty(Array.prototype, "sorted", { + value: function () { return this.toSorted(); - } + }, }); -Object.defineProperty(Array.prototype, 'equal', { -value: function(b) { - if (this.length !== b.length) return false; - if (b == null) return false; - if (this === b) return true; +Object.defineProperty(Array.prototype, "equal", { + value: function (b) { + if (this.length !== b.length) return false; + if (b == null) return false; + if (this === b) return true; - return JSON.stringify(this.sorted()) === JSON.stringify(b.sorted()); - - for (var i = 0; i < this.length; i++) { - if (!this[i] === b[i]) - return false; - } + return JSON.stringify(this.sorted()) === JSON.stringify(b.sorted()); - return true; -}}); + for (var i = 0; i < this.length; i++) { + if (!this[i] === b[i]) return false; + } -Object.defineProperty(Array.prototype, 'mapc', { - value: function(fn) { + return true; + }, +}); + +Object.defineProperty(Array.prototype, "mapc", { + value: function (fn) { return this.map(x => fn(x)); - } + }, }); -Object.defineProperty(Array.prototype, 'mapvec', { - value: function(fn, b) { - return this.map((x,i) => fn(x,b[i])); - } +Object.defineProperty(Array.prototype, "mapvec", { + value: function (fn, b) { + return this.map((x, i) => fn(x, b[i])); + }, }); -Object.defineProperty(Array.prototype, 'remove', { - value: function(b) { - var idx = this.indexOf(b); - - if (idx === -1) return false; - - this.splice(idx, 1); +Object.defineProperty(Array.prototype, "remove", { + value: function (b) { + var idx = this.indexOf(b); - return true; -}}); + if (idx === -1) return false; -Object.defineProperty(Array.prototype, 'set', { - value: function(b) { + this.splice(idx, 1); + + return true; + }, +}); + +Object.defineProperty(Array.prototype, "set", { + value: function (b) { if (this.length !== b.length) return; - b.forEach(function(val, i) { this[i] = val; }, this); - } + b.forEach(function (val, i) { + this[i] = val; + }, this); + }, }); -Object.defineProperty(Array.prototype, 'flat', { - value: function() { - return [].concat.apply([],this); - } +Object.defineProperty(Array.prototype, "flat", { + value: function () { + return [].concat.apply([], this); + }, }); /* Return true if array contains x */ -Object.defineProperty(Array.prototype, 'empty', { - get: function() { return this.length === 0; }, +Object.defineProperty(Array.prototype, "empty", { + get: function () { + return this.length === 0; + }, }); -Object.defineProperty(Array.prototype, 'push_unique', { - value: function(x) { - var inc = !this.includes(x); - if (inc) this.push(x); - return inc; -}}); +Object.defineProperty(Array.prototype, "push_unique", { + value: function (x) { + var inc = !this.includes(x); + if (inc) this.push(x); + return inc; + }, +}); -Object.defineProperty(Array.prototype, 'unique', { - value: function() { +Object.defineProperty(Array.prototype, "unique", { + value: function () { var c = []; - this.forEach(function(x) { c.push_unique(x); }); + this.forEach(function (x) { + c.push_unique(x); + }); return c; - } + }, }); -Object.defineProperty(Array.prototype, 'unduped', { - value: function() { return [... new Set(this)]; } +Object.defineProperty(Array.prototype, "unduped", { + value: function () { + return [...new Set(this)]; + }, }); -Object.defineProperty(Array.prototype, 'findIndex', { - value: function(fn) { - var idx = -1; - this.every(function(x, i) { - if (fn(x)) { - idx = i; - return false; - } +Object.defineProperty(Array.prototype, "findIndex", { + value: function (fn) { + var idx = -1; + this.every(function (x, i) { + if (fn(x)) { + idx = i; + return false; + } - return true; - }); + return true; + }); - return idx; -}}); + return idx; + }, +}); -Object.defineProperty(Array.prototype, 'find', { - value: function(fn) { - var ret; +Object.defineProperty(Array.prototype, "find", { + value: function (fn) { + var ret; - this.every(function(x) { - if (fn(x)) { - ret = x; - return false; - } + this.every(function (x) { + if (fn(x)) { + ret = x; + return false; + } - return true; - }); + return true; + }); - return ret; -}}); + return ret; + }, +}); -Object.defineProperty(Array.prototype, 'search', { - value: function(val) { - for (var i = 0; i < this.length; i++) - if (this[i] === val) return i; +Object.defineProperty(Array.prototype, "search", { + value: function (val) { + for (var i = 0; i < this.length; i++) if (this[i] === val) return i; return undefined; - } + }, }); -Object.defineProperty(Array.prototype, 'last', { - value: function() { return this[this.length-1]; }, +Object.defineProperty(Array.prototype, "last", { + value: function () { + return this[this.length - 1]; + }, }); -Object.defineProperty(Array.prototype, 'at', { -value: function(x) { - return x < 0 ? this[this.length+x] : this[x]; -}}); +Object.defineProperty(Array.prototype, "at", { + value: function (x) { + return x < 0 ? this[this.length + x] : this[x]; + }, +}); -Object.defineProperty(Array.prototype, 'wrapped', { - value: function(x) { +Object.defineProperty(Array.prototype, "wrapped", { + value: function (x) { var c = this.slice(0, this.length); - for (var i = 0; i < x; i++) - c.push(this[i]); - - return c; -}}); + for (var i = 0; i < x; i++) c.push(this[i]); -Object.defineProperty(Array.prototype, 'wrap_idx', { - value: function(x) { + return c; + }, +}); + +Object.defineProperty(Array.prototype, "wrap_idx", { + value: function (x) { while (x >= this.length) { x -= this.length; } return x; - } + }, }); -Object.defineProperty(Array.prototype, 'mirrored', { - value: function(x) { +Object.defineProperty(Array.prototype, "mirrored", { + value: function (x) { var c = this.slice(0); if (c.length <= 1) return c; - for (var i = c.length-2; i >= 0; i--) - c.push(c[i]); + for (var i = c.length - 2; i >= 0; i--) c.push(c[i]); return c; - } + }, }); Math.lerp = vector.lerp; @@ -1185,20 +1209,21 @@ Math.mean = vector.mean; Math.sigma = vector.sigma; Math.median = vector.median; -Math.variance = function(series) { +Math.variance = function (series) { var mean = Math.mean(series); var vnce = 0; - for (var i = 0; i < series.length; i++) - vnce += Math.pow(series[i]-mean, 2); - return vnce/(series.length); -} + for (var i = 0; i < series.length; i++) vnce += Math.pow(series[i] - mean, 2); + return vnce / series.length; +}; -Math.ci = function(series) { return 3*Math.sigma(series)/Math.sqrt(series.length); } +Math.ci = function (series) { + return (3 * Math.sigma(series)) / Math.sqrt(series.length); +}; -Math.grab_from_points = function(pos, points, slop) { +Math.grab_from_points = function (pos, points, slop) { var shortest = slop; var idx = -1; - points.forEach(function(x,i) { + points.forEach(function (x, i) { if (Vector.length(pos.sub(x)) < shortest) { shortest = Vector.length(pos.sub(x)); idx = i; @@ -1207,155 +1232,160 @@ Math.grab_from_points = function(pos, points, slop) { return idx; }; -Math.nearest = function(n, incr) -{ - return Math.round(n/incr)*incr; -} +Math.nearest = function (n, incr) { + return Math.round(n / incr) * incr; +}; -Math.places = function(n,digits) -{ - var div = Math.pow(10,digits); - return Math.round(n*div)/div; -} +Math.places = function (n, digits) { + var div = Math.pow(10, digits); + return Math.round(n * div) / div; +}; -Number.hex = function(n) -{ +Number.hex = function (n) { var s = Math.floor(n).toString(16); - if (s.length === 1) s = '0' + s; + if (s.length === 1) s = "0" + s; return s.uc(); -} +}; -Object.defineProperty(Object.prototype, 'lerp',{ - value: function(to, t) { +Object.defineProperty(Object.prototype, "lerp", { + value: function (to, t) { var self = this; var obj = {}; - Object.keys(self).forEach(function(key) { - obj[key] = self[key].lerp(to[key],t); + Object.keys(self).forEach(function (key) { + obj[key] = self[key].lerp(to[key], t); }); return obj; -}}); - -/* MATH EXTENSIONS */ -Object.defineProperty(Number.prototype, 'lerp', { - value: function(to, t) { return Math.lerp(this, to, t); } + }, }); -Object.defineProperty(Number.prototype, 'clamp', { - value: function(from,to) { return Math.clamp(this,from,to); } +/* MATH EXTENSIONS */ +Object.defineProperty(Number.prototype, "lerp", { + value: function (to, t) { + return Math.lerp(this, to, t); + }, +}); + +Object.defineProperty(Number.prototype, "clamp", { + value: function (from, to) { + return Math.clamp(this, from, to); + }, }); Math.clamp = vector.clamp; Math.random_range = vector.random_range; -Math.rand_int = function(max = 9007199254740991) { return Math.floor(Math.random()*max); }; +Math.rand_int = function (max = 9007199254740991) { + return Math.floor(Math.random() * max); +}; -Math.snap = function(val, grid) { +Math.snap = function (val, grid) { if (!grid || grid === 1) return Math.round(val); - var rem = val%grid; + var rem = val % grid; var d = val - rem; - var i = Math.round(rem/grid)*grid; - return d+i; -} + var i = Math.round(rem / grid) * grid; + return d + i; +}; Math.angledist = vector.angledist; Math.angledist.doc = "Find the shortest angle between two angles."; -Math.TAU = Math.PI*2; -Math.deg2rad = function(deg) { return deg * 0.0174533; }; -Math.rad2deg = function(rad) { return rad / 0.0174533; }; -Math.turn2rad = function(x) { return x*Math.TAU; }; -Math.rad2turn = function(x) { return x/Math.TAU; }; -Math.turn2deg = function(x) { return x*360; }; -Math.deg2turn = function(x) { return x/360; }; -Math.randomint = function(max) { return Math.clamp(Math.floor(Math.random() * max), 0, max-1); }; +Math.TAU = Math.PI * 2; +Math.deg2rad = function (deg) { + return deg * 0.0174533; +}; +Math.rad2deg = function (rad) { + return rad / 0.0174533; +}; +Math.turn2rad = function (x) { + return x * Math.TAU; +}; +Math.rad2turn = function (x) { + return x / Math.TAU; +}; +Math.turn2deg = function (x) { + return x * 360; +}; +Math.deg2turn = function (x) { + return x / 360; +}; +Math.randomint = function (max) { + return Math.clamp(Math.floor(Math.random() * max), 0, max - 1); +}; Math.variate = vector.variate; /* BOUNDINGBOXES */ var bbox = {}; -bbox.overlap = function(box1, box2) { - return ( - box1.l > box2.l && - box1.r < box2.r && - box1.t < box2.t && - box1.b > box2.b - ); - return ( - box1.l > box2.r || - box1.r < box2.l || - box1.t > box2.b || - box1.b < box2.t - ); -} +bbox.overlap = function (box1, box2) { + return box1.l > box2.l && box1.r < box2.r && box1.t < box2.t && box1.b > box2.b; + return box1.l > box2.r || box1.r < box2.l || box1.t > box2.b || box1.b < box2.t; +}; -bbox.fromcwh = function(c, wh) { +bbox.fromcwh = function (c, wh) { return { - t: c.y+(wh.y/2), - b: c.y-(wh.y/2), - l: c.x-(wh.x/2), - r: c.x+(wh.x/2) + t: c.y + wh.y / 2, + b: c.y - wh.y / 2, + l: c.x - wh.x / 2, + r: c.x + wh.x / 2, }; }; -bbox.frompoints = function(points) { - var b= {t:0,b:0,l:0,r:0}; - - points.forEach(function(x) { - if (x.y > b.t) b.t = x.y; - if (x.y < b.b) b.b = x.y; - if (x.x > b.r) b.r = x.x; - if (x.x < b.l) b.l = x.x; - }); - - return b; +bbox.frompoints = function (points) { + var b = { t: 0, b: 0, l: 0, r: 0 }; + + points.forEach(function (x) { + if (x.y > b.t) b.t = x.y; + if (x.y < b.b) b.b = x.y; + if (x.x > b.r) b.r = x.x; + if (x.x < b.l) b.l = x.x; + }); + + return b; }; -bbox.topoints = function(bb) -{ +bbox.topoints = function (bb) { return [ - [bb.l,bb.t], - [bb.r,bb.t], - [bb.r,bb.b], - [bb.l,bb.b] + [bb.l, bb.t], + [bb.r, bb.t], + [bb.r, bb.b], + [bb.l, bb.b], ]; -} +}; -bbox.tocwh = function(bb) { +bbox.tocwh = function (bb) { if (!bb) return undefined; var cwh = {}; var w = bb.r - bb.l; var h = bb.t - bb.b; cwh.wh = [w, h]; - cwh.c = [bb.l + w/2, bb.b + h/2]; - + cwh.c = [bb.l + w / 2, bb.b + h / 2]; + return cwh; }; -bbox.towh = function(bb) { - return [bb.r-bb.l, bb.t-bb.b]; +bbox.towh = function (bb) { + return [bb.r - bb.l, bb.t - bb.b]; }; -bbox.pointin = function(bb, p) -{ - if (bb.t < p.y || bb.b > p.y || bb.l > p.x || bb.r < p.x) - return false; +bbox.pointin = function (bb, p) { + if (bb.t < p.y || bb.b > p.y || bb.l > p.x || bb.r < p.x) return false; return true; -} +}; -bbox.zero = function(bb) { - var newbb = Object.assign({},bb); +bbox.zero = function (bb) { + var newbb = Object.assign({}, bb); newbb.r -= newbb.l; newbb.t -= newbb.b; newbb.b = 0; newbb.l = 0; return newbb; -} +}; -bbox.move = function(bb, pos) { +bbox.move = function (bb, pos) { var newbb = Object.assign({}, bb); newbb.t += pos.y; newbb.b += pos.y; @@ -1364,16 +1394,16 @@ bbox.move = function(bb, pos) { return newbb; }; -bbox.moveto = function(bb, pos) { +bbox.moveto = function (bb, pos) { bb = bbox.zero(bb); return bbox.move(bb, pos); -} +}; -bbox.expand = function(oldbb, x) { +bbox.expand = function (oldbb, x) { if (!oldbb || !x) return; var bb = {}; Object.assign(bb, oldbb); - + if (bb.t < x.t) bb.t = x.t; if (bb.r < x.r) bb.r = x.r; if (bb.b > x.b) bb.b = x.b; @@ -1382,22 +1412,22 @@ bbox.expand = function(oldbb, x) { return bb; }; -bbox.blwh = function(bl,wh) -{ +bbox.blwh = function (bl, wh) { return { b: bl.y, l: bl.x, r: bl.x + wh.x, - t: bl.y + wh.y + t: bl.y + wh.y, }; -} +}; bbox.blwh.doc = "Bounding box from (bottom left, width height)"; -bbox.fromobjs = function(objs) -{ +bbox.fromobjs = function (objs) { var bb = objs[0].boundingbox; - objs.forEach(function(obj) { bb = bbox.expand(bb, obj.boundingbox); }); + objs.forEach(function (obj) { + bb = bbox.expand(bb, obj.boundingbox); + }); return bb; }; @@ -1407,129 +1437,127 @@ Vector.length = vector.length; Vector.norm = vector.norm; Vector.project = vector.project; Vector.dot = vector.dot; -Vector.random = function() { - var vec = [Math.random()-0.5, Math.random()-0.5]; +Vector.random = function () { + var vec = [Math.random() - 0.5, Math.random() - 0.5]; return Vector.norm(vec); -} +}; Vector.angle_between = vector.angle_between; Vector.rotate = vector.rotate; -vector.direction = function(from,to) -{ +vector.direction = function (from, to) { return vector.norm(to.sub(from)); -} - -Vector.equal = function(v1, v2, tol) { - if (!tol) - return v1.equal(v2); +}; + +Vector.equal = function (v1, v2, tol) { + if (!tol) return v1.equal(v2); var eql = true; var c = v1.sub(v2); - c.forEach(function(x) { + c.forEach(function (x) { if (!eql) return; - if (Math.abs(x) > tol) - eql = false; + if (Math.abs(x) > tol) eql = false; }); return eql; -} +}; -Vector.reflect = function(vec, plane) { +Vector.reflect = function (vec, plane) { var p = Vector.norm(plane); - return vec.sub(p.scale(2*Vector.dot(vec, p))); -} + return vec.sub(p.scale(2 * Vector.dot(vec, p))); +}; -Vector.reflect_point = function(vec, point) { return point.add(vec.sub(point).scale(-1)); } +Vector.reflect_point = function (vec, point) { + return point.add(vec.sub(point).scale(-1)); +}; /* POINT ASSISTANCE */ -function points2cm(points) -{ +function points2cm(points) { var x = 0; var y = 0; var n = points.length; - points.forEach(function(p) { + points.forEach(function (p) { x = x + p[0]; y = y + p[1]; }); - - return [x/n,y/n]; -}; -Math.sortpointsccw = function(points) -{ + return [x / n, y / n]; +} + +Math.sortpointsccw = function (points) { var cm = points2cm(points); - var cmpoints = points.map(function(x) { return x.sub(cm); }); - var ccw = cmpoints.sort(function(a,b) { + var cmpoints = points.map(function (x) { + return x.sub(cm); + }); + var ccw = cmpoints.sort(function (a, b) { var aatan = Math.atan2(a.y, a.x); var batan = Math.atan2(b.y, b.x); return aatan - batan; }); - - return ccw.map(function(x) { return x.add(cm); }); -} + + return ccw.map(function (x) { + return x.add(cm); + }); +}; var yaml = {}; -yaml.tojson = function(yaml) -{ +yaml.tojson = function (yaml) { // Replace key value pairs that are strings with quotation marks around them yaml = yaml.replace(/(\w+):/g, '"$1":'); yaml = yaml.replace(/: ([\w\.\/]+)/g, ': "$1"'); // TODO: make this more general - + yaml = yaml.split("\n"); var cont = {}; var cur = 0; for (var i = 0; i < yaml.length; i++) { var line = yaml[i]; var indent = line.search(/\S/); - + if (indent > cur) { if (line[indent] == "-") { cont[indent] = "array"; - yaml[i] = line.sub(indent, '['); + yaml[i] = line.sub(indent, "["); } else { cont[indent] = "obj"; - yaml[i] = line.sub(indent-1, '{'); + yaml[i] = line.sub(indent - 1, "{"); } } - + if (indent < cur) { while (cur > indent) { - if (cont[cur] === "obj") - yaml[i-1] = yaml[i-1] + "}"; - else if (cont[cur] === "array") - yaml[i-1] = yaml[i-1] + "]"; - - delete cont[cur]; - cur--; + if (cont[cur] === "obj") yaml[i - 1] = yaml[i - 1] + "}"; + else if (cont[cur] === "array") yaml[i - 1] = yaml[i - 1] + "]"; + + delete cont[cur]; + cur--; } } if (indent === cur) { - if (yaml[i][indent] === '-') - yaml[i] = yaml[i].sub(indent,','); - else - yaml[i-1] = yaml[i-1] + ','; + if (yaml[i][indent] === "-") yaml[i] = yaml[i].sub(indent, ","); + else yaml[i - 1] = yaml[i - 1] + ","; } - + cur = indent; } yaml = "{" + yaml.join("\n") + "}"; - yaml = yaml.replace(/\s/g, ''); - yaml = yaml.replace(/,}/g, '}'); - yaml = yaml.replace(/,]/g, ']'); - yaml = yaml.replace(/,"[^"]+"\:,/g, ','); - return yaml; -} + yaml = yaml.replace(/\s/g, ""); + yaml = yaml.replace(/,}/g, "}"); + yaml = yaml.replace(/,]/g, "]"); + yaml = yaml.replace(/,"[^"]+"\:,/g, ","); + return yaml; +}; -Math.sign = function(n) { return n >= 0 ? 1 : -1; } +Math.sign = function (n) { + return n >= 0 ? 1 : -1; +}; return { convert, time, Vector, bbox, - yaml + yaml, }; diff --git a/scripts/camera2d.js b/scripts/camera2d.js index 93bbc1aa..19037ab6 100644 --- a/scripts/camera2d.js +++ b/scripts/camera2d.js @@ -1,43 +1,48 @@ this.phys = physics.kinematic; -this.dir_view2world = function(dir) { return dir.scale(this.zoom); }; -this.view2world = function(pos) { +this.dir_view2world = function (dir) { + return dir.scale(this.zoom); +}; +this.view2world = function (pos) { var useren = window.rendersize.scale(this.zoom); if (window.mode === window.modetypes.stretch) { - pos = pos.scale([window.rendersize.x/window.size.x, window.rendersize.y/window.size.y]); + pos = pos.scale([window.rendersize.x / window.size.x, window.rendersize.y / window.size.y]); pos = pos.sub(window.rendersize.scale(0.5)); pos = pos.scale(this.zoom); pos = pos.add(this.pos); } if (window.mode === window.modetypes.full) { pos = pos.sub(window.size.scale(0.5)); - pos = pos.scale(this.zoom); + pos = pos.scale(this.zoom); pos = pos.add(this.pos); } if (window.mode === window.modetypes.expand) { - pos = pos.sub(window.size.scale(0.5)); - pos = pos.scale([window.rendersize.x/window.size.x, window.rendersize.y/window.size.y]); + pos = pos.sub(window.size.scale(0.5)); + pos = pos.scale([window.rendersize.x / window.size.x, window.rendersize.y / window.size.y]); } return pos; }; -this.world2view = function(pos) { +this.world2view = function (pos) { if (window.mode === window.modetypes.stretch) { pos = pos.sub(this.pos); - pos = pos.scale(1.0/this.zoom); + pos = pos.scale(1.0 / this.zoom); pos = pos.add(window.rendersize.scale(0.5)); } if (window.mode === window.modetypes.full) { pos = pos.sub(this.pos); - pos = pos.scale(1/this.zoom); + pos = pos.scale(1 / this.zoom); pos = pos.add(window.size.scale(0.5)); } if (window.mode === window.modetypes.expand) { - } return pos; }; -this.screenright = function() { return this.view2world(window.size).x; } -this.screenleft = function() { return this.view2world([0,0]).x; } +this.screenright = function () { + return this.view2world(window.size).x; +}; +this.screenleft = function () { + return this.view2world([0, 0]).x; +}; var zoom = 1; @@ -46,6 +51,7 @@ Object.mixin(self, { zoom = x; if (zoom <= 0.1) zoom = 0.1; }, - get zoom() { return zoom; } -} -); + get zoom() { + return zoom; + }, +}); diff --git a/scripts/color.js b/scripts/color.js index 40afbbbc..79214584 100644 --- a/scripts/color.js +++ b/scripts/color.js @@ -1,113 +1,118 @@ var Color = { - white: [255,255,255], - black: [0,0,0], - blue: [0,0,255], - green: [0,255,0], - yellow: [255,255,0], - red: [255,0,0], - gray: [181,181,181], - cyan: [0,255,255], - purple: [162,93,227], - orange: [255,144,64], - magenta: [255,0,255], + white: [255, 255, 255], + black: [0, 0, 0], + blue: [0, 0, 255], + green: [0, 255, 0], + yellow: [255, 255, 0], + red: [255, 0, 0], + gray: [181, 181, 181], + cyan: [0, 255, 255], + purple: [162, 93, 227], + orange: [255, 144, 64], + magenta: [255, 0, 255], }; Color.editor = {}; Color.editor.ur = Color.green; -Color.tohtml = function(v) -{ - var html = v.map(function(n) { return Number.hex(n*255); }); - return "#" + html.join(''); -} +Color.tohtml = function (v) { + var html = v.map(function (n) { + return Number.hex(n * 255); + }); + return "#" + html.join(""); +}; var esc = {}; esc.reset = "\x1b[0"; -esc.color = function(v) { - var c = v.map(function(n) { return Math.floor(n*255); }); - var truecolor = "\x1b[38;2;" + c.join(';') + ';'; +esc.color = function (v) { + var c = v.map(function (n) { + return Math.floor(n * 255); + }); + var truecolor = "\x1b[38;2;" + c.join(";") + ";"; return truecolor; -} +}; esc.doc = "Functions and constants for ANSI escape sequences."; Color.Arkanoid = { - orange: [255,143,0], - teal: [0,255,255], - green: [0,255,0], - red: [255,0,0], - blue: [0,112,255], - purple: [255,0,255], - yellow: [255,255,0], - silver: [157,157,157], - gold: [188,174,0], + orange: [255, 143, 0], + teal: [0, 255, 255], + green: [0, 255, 0], + red: [255, 0, 0], + blue: [0, 112, 255], + purple: [255, 0, 255], + yellow: [255, 255, 0], + silver: [157, 157, 157], + gold: [188, 174, 0], }; Color.Arkanoid.Powerups = { - red: [174,0,0], /* laser */ - blue: [0,0,174], /* enlarge */ - green: [0,174,0], /* catch */ - orange: [224,143,0], /* slow */ - purple: [210,0,210], /* break */ - cyan: [0,174,255], /* disruption */ - gray: [143,143,143] /* 1up */ + red: [174, 0, 0] /* laser */, + blue: [0, 0, 174] /* enlarge */, + green: [0, 174, 0] /* catch */, + orange: [224, 143, 0] /* slow */, + purple: [210, 0, 210] /* break */, + cyan: [0, 174, 255] /* disruption */, + gray: [143, 143, 143] /* 1up */, }; Color.Gameboy = { - darkest: [229,107,26], - dark: [229,189,26], - light: [189,229,26], - lightest: [107,229,26], + darkest: [229, 107, 26], + dark: [229, 189, 26], + light: [189, 229, 26], + lightest: [107, 229, 26], }; Color.Apple = { - green: [94,189,62], - yellow: [255,185,0], - orange: [247,130,0], - red: [226,56,56], - purple: [151,57,153], - blue: [0,156,223] + green: [94, 189, 62], + yellow: [255, 185, 0], + orange: [247, 130, 0], + red: [226, 56, 56], + purple: [151, 57, 153], + blue: [0, 156, 223], }; Color.Debug = { boundingbox: Color.white, - names: [84,110,255], + names: [84, 110, 255], }; Color.Editor = { - grid: [99,255,128], - select: [255,255,55], - newgroup: [120,255,10], + grid: [99, 255, 128], + select: [255, 255, 55], + newgroup: [120, 255, 10], }; /* Detects the format of all colors and munges them into a floating point format */ -Color.normalize = function(c) { - var add_a = function(a) { +Color.normalize = function (c) { + var add_a = function (a) { var n = this.slice(); n.a = a; return n; }; - + for (var p of Object.keys(c)) { var fmt = "nrm"; - if (typeof c[p] !== 'object') continue; + if (typeof c[p] !== "object") continue; if (!Array.isArray(c[p])) { Color.normalize(c[p]); continue; } - + c[p][3] = 255; - + for (var color of c[p]) { if (color > 1) { fmt = "8b"; - break; + break; } } - switch(fmt) { + switch (fmt) { case "8b": - c[p] = c[p].map(function(x) { return x/255; }); + c[p] = c[p].map(function (x) { + return x / 255; + }); } c[p].alpha = add_a; } @@ -118,66 +123,64 @@ Color.normalize(Color); Object.deepfreeze(Color); var ColorMap = {}; -ColorMap.makemap = function(map) -{ +ColorMap.makemap = function (map) { var newmap = Object.create(ColorMap); Object.assign(newmap, map); return newmap; -} +}; ColorMap.Jet = ColorMap.makemap({ - 0: [0,0,131], - 0.125: [0,60,170], - 0.375: [5,255,255], - 0.625: [255,255,0], - 0.875: [250,0,0], - 1: [128,0,0] + 0: [0, 0, 131], + 0.125: [0, 60, 170], + 0.375: [5, 255, 255], + 0.625: [255, 255, 0], + 0.875: [250, 0, 0], + 1: [128, 0, 0], }); ColorMap.BlueRed = ColorMap.makemap({ - 0: [0,0,255], - 1: [255,0,0] + 0: [0, 0, 255], + 1: [255, 0, 0], }); ColorMap.Inferno = ColorMap.makemap({ - 0:[0,0,4], - 0.13: [31,12,72], - 0.25: [85,15,109], - 0.38: [136,34,106], - 0.5: [186,54,85], - 0.63: [227,89,51], - 0.75: [249,140,10], - 0.88: [249,201,50], - 1: [252,255,164] + 0: [0, 0, 4], + 0.13: [31, 12, 72], + 0.25: [85, 15, 109], + 0.38: [136, 34, 106], + 0.5: [186, 54, 85], + 0.63: [227, 89, 51], + 0.75: [249, 140, 10], + 0.88: [249, 201, 50], + 1: [252, 255, 164], }); ColorMap.Bathymetry = ColorMap.makemap({ - 0: [40,26,44], - 0.13: [59.49,90], - 0.25: [64,76,139], - 0.38: [63,110,151], - 0.5: [72,142,158], - 0.63: [85,174,163], - 0.75: [120,206,163], - 0.88: [187,230,172], - 1: [253,254,204] + 0: [40, 26, 44], + 0.13: [59.49, 90], + 0.25: [64, 76, 139], + 0.38: [63, 110, 151], + 0.5: [72, 142, 158], + 0.63: [85, 174, 163], + 0.75: [120, 206, 163], + 0.88: [187, 230, 172], + 1: [253, 254, 204], }); ColorMap.Viridis = ColorMap.makemap({ - 0: [68,1,84], - 0.13: [71,44,122], - 0.25: [59,81,139], - 0.38: [44,113,142], - 0.5: [33,144,141], - 0.63: [39,173,129], - 0.75: [92,200,99], - 0.88: [170,220,50], - 1: [253,231,37] + 0: [68, 1, 84], + 0.13: [71, 44, 122], + 0.25: [59, 81, 139], + 0.38: [44, 113, 142], + 0.5: [33, 144, 141], + 0.63: [39, 173, 129], + 0.75: [92, 200, 99], + 0.88: [170, 220, 50], + 1: [253, 231, 37], }); Color.normalize(ColorMap); -ColorMap.sample = function(t, map = this) -{ +ColorMap.sample = function (t, map = this) { if (t < 0) return map[0]; if (t > 1) return map[1]; @@ -192,7 +195,7 @@ ColorMap.sample = function(t, map = this) lastkey = key; } return map[1]; -} +}; ColorMap.doc = { sample: "Sample a given colormap at the given percentage (0 to 1).", @@ -203,5 +206,5 @@ Object.freeze(ColorMap); return { Color, esc, - ColorMap -} + ColorMap, +}; diff --git a/scripts/components.js b/scripts/components.js index 63328063..0b971c9e 100644 --- a/scripts/components.js +++ b/scripts/components.js @@ -1,7 +1,6 @@ var component = {}; -var make_point_obj = function(o, p) -{ +var make_point_obj = function (o, p) { return { pos: p, move(d) { @@ -9,51 +8,46 @@ var make_point_obj = function(o, p) p.x += d.x; p.y += d.y; }, - sync: o.sync.bind(o) - } -} + sync: o.sync.bind(o), + }; +}; -var fullrect = [0,0,1,1]; +var fullrect = [0, 0, 1, 1]; -var sprite_addbucket = function(sprite) -{ +var sprite_addbucket = function (sprite) { var layer = sprite.gameobject.drawlayer; sprite_buckets[layer] ??= {}; sprite_buckets[layer][sprite.path] ??= {}; sprite_buckets[layer][sprite.path][sprite.guid] = sprite; -} +}; -var sprite_rmbucket = function(sprite) -{ - for (var layer of Object.values(sprite_buckets)) - for (var path of Object.values(layer)) - delete path[sprite.guid]; -} +var sprite_rmbucket = function (sprite) { + for (var layer of Object.values(sprite_buckets)) for (var path of Object.values(layer)) delete path[sprite.guid]; +}; var sprite = { loop: true, rect: fullrect, - anim:{}, + anim: {}, playing: 0, anim_speed: 1, play(str = 0, fn, loop = true, reverse = false) { this.del_anim?.(); var self = this; var stop; - self.del_anim = function() { + self.del_anim = function () { self.del_anim = undefined; self = undefined; advance = undefined; stop?.(); - } + }; var playing = self.anim[str]; if (!playing) return; var f = 0; - if (reverse) - f = playing.frames.length-1; - + if (reverse) f = playing.frames.length - 1; + self.path = playing.path; - + function advance() { if (!self) return; if (!self.gameobject) return; @@ -62,29 +56,30 @@ var sprite = { self.update_dimensions(); var done = false; if (reverse) { - f = (((f-1)%playing.frames.length)+playing.frames.length)%playing.frames.length; - if (f === playing.frames.length-1) done = true; + f = (((f - 1) % playing.frames.length) + playing.frames.length) % playing.frames.length; + if (f === playing.frames.length - 1) done = true; + } else { + f = (f + 1) % playing.frames.length; + if (f === 0) done = true; } - else { - f = (f+1)%playing.frames.length; - if (f === 0) done = true; - } - + if (done) { fn?.(); - if (!loop) { self?.stop(); return; } -// self?.anim_done?.(); -// if (!self.loop) { self.stop(); return; } + if (!loop) { + self?.stop(); + return; + } + // self?.anim_done?.(); + // if (!self.loop) { self.stop(); return; } } - if (self) - stop = self.gameobject.delay(advance, playing.frames[f].time/self.anim_speed); + if (self) stop = self.gameobject.delay(advance, playing.frames[f].time / self.anim_speed); } advance(); }, tex_sync() { if (this.anim) this.stop(); - this.rect = fullrect; + this.rect = fullrect; var anim = SpriteAnim.make(this.path); this.update_dimensions(); this.sync(); @@ -92,7 +87,7 @@ var sprite = { if (!anim) return; this.anim = anim; this.play(); - + this.pos = this.dimensions().scale(this.anchor); }, stop() { @@ -107,10 +102,10 @@ var sprite = { if (p === this.path) return; this._p = p; - + this.del_anim?.(); this.texture = game.texture(p); - + this.diffuse = this.texture; this.tex_sync(); @@ -126,75 +121,120 @@ var sprite = { this.anim_done = undefined; delete allsprites[this.guid]; }, - move(d) { this.pos = this.pos.add(d); }, + move(d) { + this.pos = this.pos.add(d); + }, grow(x) { this.scale = this.scale.scale(x); this.pos = this.pos.scale(x); }, - anchor:[0,0], + anchor: [0, 0], sync() { sprite_rmbucket(this); sprite_addbucket(this); }, - pick() { return this; }, + pick() { + return this; + }, boundingbox() { var dim = this.dimensions(); dim = dim.scale(this.gameobject.scale); var realpos = dim.scale(0.5).add(this.pos); - return bbox.fromcwh(realpos,dim); + return bbox.fromcwh(realpos, dim); }, - + update_dimensions() { - this._dimensions = [this.texture.width*this.rect[2], this.texture.height*this.rect[3]]; + this._dimensions = [this.texture.width * this.rect[2], this.texture.height * this.rect[3]]; component.sprite_dim_hook?.(this); }, - + dimensions() { return this._dimensions; }, - width() { return this.dimensions().x; }, - height() { return this.dimensions().y; }, + width() { + return this.dimensions().x; + }, + height() { + return this.dimensions().y; + }, }; globalThis.allsprites = {}; var sprite_buckets = {}; -component.sprite_buckets = function() { return sprite_buckets; } +component.sprite_buckets = function () { + return sprite_buckets; +}; sprite.doc = { path: "Path to the texture.", color: "Color to mix with the sprite.", - pos: "The offset position of the sprite, relative to its entity." + pos: "The offset position of the sprite, relative to its entity.", }; -sprite.setanchor = function(anch) { - var off = [0,0]; - switch(anch) { - case "ll": break; - case "lm": off = [-0.5,0]; break; - case "lr": off = [-1,0]; break; - case "ml": off = [0,-0.5]; break; - case "mm": off = [-0.5,-0.5]; break; - case "mr": off = [-1,-0.5]; break; - case "ul": off = [0,-1]; break; - case "um": off = [-0.5,-1]; break; - case "ur": off = [-1,-1]; break; - } +sprite.setanchor = function (anch) { + var off = [0, 0]; + switch (anch) { + case "ll": + break; + case "lm": + off = [-0.5, 0]; + break; + case "lr": + off = [-1, 0]; + break; + case "ml": + off = [0, -0.5]; + break; + case "mm": + off = [-0.5, -0.5]; + break; + case "mr": + off = [-1, -0.5]; + break; + case "ul": + off = [0, -1]; + break; + case "um": + off = [-0.5, -1]; + break; + case "ur": + off = [-1, -1]; + break; + } this.anchor = off; this.pos = this.dimensions().scale(off); -} +}; sprite.inputs = {}; -sprite.inputs.kp9 = function() { this.setanchor("ll"); } -sprite.inputs.kp8 = function() { this.setanchor("lm"); } -sprite.inputs.kp7 = function() { this.setanchor("lr"); } -sprite.inputs.kp6 = function() { this.setanchor("ml"); } -sprite.inputs.kp5 = function() { this.setanchor("mm"); } -sprite.inputs.kp4 = function() { this.setanchor("mr"); } -sprite.inputs.kp3 = function() { this.setanchor("ur"); } -sprite.inputs.kp2 = function() { this.setanchor("um"); } -sprite.inputs.kp1 = function() { this.setanchor("ul"); } +sprite.inputs.kp9 = function () { + this.setanchor("ll"); +}; +sprite.inputs.kp8 = function () { + this.setanchor("lm"); +}; +sprite.inputs.kp7 = function () { + this.setanchor("lr"); +}; +sprite.inputs.kp6 = function () { + this.setanchor("ml"); +}; +sprite.inputs.kp5 = function () { + this.setanchor("mm"); +}; +sprite.inputs.kp4 = function () { + this.setanchor("mr"); +}; +sprite.inputs.kp3 = function () { + this.setanchor("ur"); +}; +sprite.inputs.kp2 = function () { + this.setanchor("um"); +}; +sprite.inputs.kp1 = function () { + this.setanchor("ul"); +}; -component.sprite = function(obj) { +component.sprite = function (obj) { var sp = Object.create(sprite); sp.gameobject = obj; sp.transform = obj.transform; @@ -203,12 +243,14 @@ component.sprite = function(obj) { if (component.sprite.make_hook) component.sprite.make_hook(sp); sprite_addbucket(sp); return sp; -} +}; -sprite.shade = [1,1,1,1]; +sprite.shade = [1, 1, 1, 1]; Object.mixin(os.make_seg2d(), { - sync() { this.set_endpoints(this.points[0], this.points[1]); } + sync() { + this.set_endpoints(this.points[0], this.points[1]); + }, }); /* sprite anim returns a data structure for the given file path @@ -219,59 +261,53 @@ Object.mixin(os.make_seg2d(), { */ var animcache = {}; var SpriteAnim = {}; -SpriteAnim.make = function(path) { +SpriteAnim.make = function (path) { var anim; - if (io.exists(path.set_ext(".ase"))) - anim = SpriteAnim.aseprite(path.set_ext(".ase")); - else if (io.exists(path.set_ext(".json"))) - anim = SpriteAnim.aseprite(path.set_ext(".json")); - else if (path.ext() === 'ase') - anim = SpriteAnim.aseprite(path); - else if (path.ext() === 'gif') - anim = SpriteAnim.gif(path); - else - anim = undefined; - - animcache[path] = anim; + if (io.exists(path.set_ext(".ase"))) anim = SpriteAnim.aseprite(path.set_ext(".ase")); + else if (io.exists(path.set_ext(".json"))) anim = SpriteAnim.aseprite(path.set_ext(".json")); + else if (path.ext() === "ase") anim = SpriteAnim.aseprite(path); + else if (path.ext() === "gif") anim = SpriteAnim.gif(path); + else anim = undefined; + + animcache[path] = anim; return animcache[path]; }; -SpriteAnim.gif = function(path) { +SpriteAnim.gif = function (path) { var anim = {}; anim.frames = []; anim.path = path; var tex = game.texture(path); var frames = tex.frames; if (frames === 1) return undefined; - var yslice = 1/frames; + var yslice = 1 / frames; for (var f = 0; f < frames; f++) { var frame = {}; frame.rect = { x: 0, w: 1, - y: yslice*f, - h: yslice + y: yslice * f, + h: yslice, }; frame.time = 0.05; anim.frames.push(frame); } var times = tex.delays; - for (var i = 0; i < frames; i++) - anim.frames[i].time = times[i]/1000; + for (var i = 0; i < frames; i++) anim.frames[i].time = times[i] / 1000; anim.loop = true; - var dim = [tex.width,tex.height]; + var dim = [tex.width, tex.height]; dim.y /= frames; anim.dim = dim; - return {0:anim}; + return { 0: anim }; }; -SpriteAnim.strip = function(path, frames, time=0.05) { +SpriteAnim.strip = function (path, frames, time = 0.05) { var anim = {}; anim.frames = []; anim.path = path; - var xslice = 1/frames; + var xslice = 1 / frames; for (var f = 0; f < frames; f++) { var frame = {}; - frame.rect = {s0:xslice*f, s1: xslice*(f+1), t0:0, t1:1}; + frame.rect = { s0: xslice * f, s1: xslice * (f + 1), t0: 0, t1: 1 }; frame.time = time; anim.frames.push(frame); } @@ -280,21 +316,21 @@ SpriteAnim.strip = function(path, frames, time=0.05) { return anim; }; -SpriteAnim.aseprite = function(path) { +SpriteAnim.aseprite = function (path) { function aseframeset2anim(frameset, meta) { var anim = {}; anim.frames = []; anim.path = path.folder() + meta.image; var dim = meta.size; - var ase_make_frame = function(ase_frame) { + var ase_make_frame = function (ase_frame) { var f = ase_frame.frame; var frame = {}; frame.rect = { - x: f.x/dim.w, - w: f.w/dim.w, - y: f.y/dim.h, - h: f.h/dim.h + x: f.x / dim.w, + w: f.w / dim.w, + y: f.y / dim.h, + h: f.h / dim.h, }; frame.time = ase_frame.duration / 1000; anim.frames.push(frame); @@ -304,7 +340,7 @@ SpriteAnim.aseprite = function(path) { anim.dim = frameset[0].sourceSize; anim.loop = true; return anim; - }; + } var data = json.decode(io.slurp(path)); if (!data?.meta?.app.includes("aseprite")) return; @@ -316,7 +352,7 @@ SpriteAnim.aseprite = function(path) { return anims; } for (var tag of data.meta.frameTags) { - anims[tag.name] = aseframeset2anim(frames.slice(tag.from, tag.to+1), data.meta); + anims[tag.name] = aseframeset2anim(frames.slice(tag.from, tag.to + 1), data.meta); anims[f] = anims[tag.name]; f++; } @@ -324,84 +360,86 @@ SpriteAnim.aseprite = function(path) { return anims; }; -SpriteAnim.validate = function(anim) { +SpriteAnim.validate = function (anim) { if (!Object.isObject(anim)) return false; - if (typeof anim.path !== 'string') return false; - if (typeof anim.dim !== 'object') return false; + if (typeof anim.path !== "string") return false; + if (typeof anim.dim !== "object") return false; return true; }; -SpriteAnim.find = function(path) { +SpriteAnim.find = function (path) { if (!io.exists(path + ".asset")) return; var asset = JSON.parse(io.slurp(path + ".asset")); }; -SpriteAnim.doc = 'Functions to create Primum animations from varying sources.'; -SpriteAnim.gif.doc = 'Convert a gif.'; -SpriteAnim.strip.doc = 'Given a path and number of frames, converts a horizontal strip animation, where each cell is the same width.' -SpriteAnim.aseprite.doc = 'Given an aseprite json metadata, returns an object of animations defined in the aseprite file.'; -SpriteAnim.find.doc = 'Given a path, find the relevant animation for the file.'; +SpriteAnim.doc = "Functions to create Primum animations from varying sources."; +SpriteAnim.gif.doc = "Convert a gif."; +SpriteAnim.strip.doc = "Given a path and number of frames, converts a horizontal strip animation, where each cell is the same width."; +SpriteAnim.aseprite.doc = "Given an aseprite json metadata, returns an object of animations defined in the aseprite file."; +SpriteAnim.find.doc = "Given a path, find the relevant animation for the file."; var collider2d = {}; collider2d.inputs = {}; -collider2d.inputs['M-s'] = function() { this.sensor = !this.sensor; } -collider2d.inputs['M-s'].doc = "Toggle if this collider is a sensor."; +collider2d.inputs["M-s"] = function () { + this.sensor = !this.sensor; +}; +collider2d.inputs["M-s"].doc = "Toggle if this collider is a sensor."; -collider2d.inputs['M-t'] = function() { this.enabled = !this.enabled; } -collider2d.inputs['M-t'].doc = "Toggle if this collider is enabled."; +collider2d.inputs["M-t"] = function () { + this.enabled = !this.enabled; +}; +collider2d.inputs["M-t"].doc = "Toggle if this collider is enabled."; Object.mix(os.make_poly2d(), { boundingbox() { return bbox.frompoints(this.spoints()); }, - - /* EDITOR */ + + /* EDITOR */ spoints() { var spoints = this.points.slice(); - + if (this.flipx) { - spoints.forEach(function(x) { + spoints.forEach(function (x) { var newpoint = x.slice(); - newpoint.x = -newpoint.x; + newpoint.x = -newpoint.x; spoints.push(newpoint); }); } - + if (this.flipy) { - spoints.forEach(function(x) { + spoints.forEach(function (x) { var newpoint = x.slice(); - newpoint.y = -newpoint.y; - spoints.push(newpoint); + newpoint.y = -newpoint.y; + spoints.push(newpoint); }); } return spoints; }, - + gizmo() { this.spoints().forEach(x => render.point(this.gameobject.this2screen(x), 3, Color.green)); - this.points.forEach((x,i)=>render.coordinate(this.gameobject.this2screen(x))); + this.points.forEach((x, i) => render.coordinate(this.gameobject.this2screen(x))); }, pick(pos) { - if (!Object.hasOwn(this,'points')) - this.points = deep_copy(this.__proto__.points); - + if (!Object.hasOwn(this, "points")) this.points = deep_copy(this.__proto__.points); + var i = Gizmos.pick_gameobject_points(pos, this.gameobject, this.points); var p = this.points[i]; - if (p) - return make_point_obj(this, p); - + if (p) return make_point_obj(this, p); + return undefined; }, }); function pointscaler(x) { - if (typeof x === 'number') return; + if (typeof x === "number") return; this.points = this.points.map(p => p.mult(x)); } Object.mixin(os.make_poly2d(), { - sync() { + sync() { this.setverts(this.points); }, grow: pointscaler, @@ -411,84 +449,86 @@ var polyinputs = Object.create(collider2d.inputs); os.make_poly2d().inputs = polyinputs; polyinputs = {}; -polyinputs.f10 = function() { +polyinputs.f10 = function () { this.points = Math.sortpointsccw(this.points); }; polyinputs.f10.doc = "Sort all points to be CCW order."; -polyinputs['C-lm'] = function() { +polyinputs["C-lm"] = function () { this.points.push(this.gameobject.world2this(input.mouse.worldpos())); }; -polyinputs['C-lm'].doc = "Add a point to location of mouse."; -polyinputs.lm = function(){}; -polyinputs.lm.released = function(){}; +polyinputs["C-lm"].doc = "Add a point to location of mouse."; +polyinputs.lm = function () {}; +polyinputs.lm.released = function () {}; -polyinputs['C-M-lm'] = function() { - var idx = Math.grab_from_points(input.mouse.worldpos(), this.points.map(p => this.gameobject.this2world(p)), 25); +polyinputs["C-M-lm"] = function () { + var idx = Math.grab_from_points( + input.mouse.worldpos(), + this.points.map(p => this.gameobject.this2world(p)), + 25, + ); if (idx === -1) return; this.points.splice(idx, 1); }; -polyinputs['C-M-lm'].doc = "Remove point under mouse."; +polyinputs["C-M-lm"].doc = "Remove point under mouse."; -polyinputs['C-b'] = function() { +polyinputs["C-b"] = function () { this.points = this.spoints; this.flipx = false; this.flipy = false; }; -polyinputs['C-b'].doc = "Freeze mirroring in place."; +polyinputs["C-b"].doc = "Freeze mirroring in place."; var edge2d = { - dimensions:2, - thickness:1, + dimensions: 2, + thickness: 1, /* if type === -1, point to point */ type: Spline.type.catmull, - C: 1, /* when in bezier, continuity required. 0, 1 or 2. */ + C: 1 /* when in bezier, continuity required. 0, 1 or 2. */, looped: false, - angle: 0.5, /* smaller for smoother bezier */ + angle: 0.5 /* smaller for smoother bezier */, elasticity: 0, friction: 0, sync() { var ppp = this.sample(); this.segs ??= []; - var count = ppp.length-1; + var count = ppp.length - 1; this.segs.length = count; for (var i = 0; i < count; i++) { this.segs[i] ??= os.make_seg2d(this.body); - this.segs[i].set_endpoints(ppp[i],ppp[i+1]); - this.segs[i].set_neighbors(ppp[i],ppp[i+1]); + this.segs[i].set_endpoints(ppp[i], ppp[i + 1]); + this.segs[i].set_neighbors(ppp[i], ppp[i + 1]); this.segs[i].radius = this.thickness; this.segs[i].elasticity = this.elasticity; this.segs[i].friction = this.friction; this.segs[i].collide = this.collide; } }, - + flipx: false, flipy: false, - + hollow: false, hollowt: 0, spoints() { if (!this.points) return []; var spoints = this.points.slice(); - - if (this.flipx) { - if (Spline.is_bezier(this.type)) - spoints.push(Vector.reflect_point(spoints.at(-2), spoints.at(-1))); - for (var i = spoints.length-1; i >= 0; i--) { + if (this.flipx) { + if (Spline.is_bezier(this.type)) spoints.push(Vector.reflect_point(spoints.at(-2), spoints.at(-1))); + + for (var i = spoints.length - 1; i >= 0; i--) { var newpoint = spoints[i].slice(); - newpoint.x = -newpoint.x; + newpoint.x = -newpoint.x; spoints.push(newpoint); } } - + if (this.flipy) { - if (Spline.is_bezier(this.type)) - spoints.push(Vector.reflect(point(spoints.at(-2),spoints.at(-1)))); - - for (var i = spoints.length-1; i >= 0; i--) { + if (Spline.is_bezier(this.type)) spoints.push(Vector.reflect(point(spoints.at(-2), spoints.at(-1)))); + + for (var i = spoints.length - 1; i >= 0; i--) { var newpoint = spoints[i].slice(); newpoint.y = -newpoint.y; spoints.push(newpoint); @@ -498,14 +538,17 @@ var edge2d = { if (this.hollow) { var hpoints = vector.inflate(spoints, this.hollowt); if (hpoints.length === spoints.length) return spoints; - var arr1 = hpoints.filter(function(x,i) { return i % 2 === 0; }); - var arr2 = hpoints.filter(function(x,i) { return i % 2 !== 0; }); + var arr1 = hpoints.filter(function (x, i) { + return i % 2 === 0; + }); + var arr2 = hpoints.filter(function (x, i) { + return i % 2 !== 0; + }); return arr1.concat(arr2.reverse()); } - - if (this.looped) - spoints = spoints.wrapped(1); - + + if (this.looped) spoints = spoints.wrapped(1); + return spoints; }, @@ -516,96 +559,93 @@ var edge2d = { sample() { var spoints = this.spoints(); if (spoints.length === 0) return []; - + if (this.type === -1) { if (this.looped) spoints.push(spoints[0]); return spoints; } if (this.type === Spline.type.catmull) { - if (this.looped) - spoints = Spline.catmull_loop(spoints); - else - spoints = Spline.catmull_caps(spoints); + if (this.looped) spoints = Spline.catmull_loop(spoints); + else spoints = Spline.catmull_caps(spoints); - return Spline.sample_angle(this.type, spoints,this.angle); + return Spline.sample_angle(this.type, spoints, this.angle); } - if (this.looped && Spline.is_bezier(this.type)) - spoints = Spline.bezier_loop(spoints); + if (this.looped && Spline.is_bezier(this.type)) spoints = Spline.bezier_loop(spoints); return Spline.sample_angle(this.type, spoints, this.angle); }, - boundingbox() { return bbox.frompoints(this.points.map(x => x.scale(this.gameobject.scale))); }, + boundingbox() { + return bbox.frompoints(this.points.map(x => x.scale(this.gameobject.scale))); + }, /* EDITOR */ gizmo() { if (this.type === Spline.type.catmull || this.type === -1) { this.spoints().forEach(x => render.point(this.gameobject.this2screen(x), 3, Color.teal)); - this.points.forEach((x,i) => render.coordinate(this.gameobject.this2screen(x))); + this.points.forEach((x, i) => render.coordinate(this.gameobject.this2screen(x))); } else { - for (var i = 0; i < this.points.length; i += 3) - render.coordinate(this.gameobject.this2screen(this.points[i]), 1, Color.teal); - - for (var i = 1; i < this.points.length; i+=3) { + for (var i = 0; i < this.points.length; i += 3) render.coordinate(this.gameobject.this2screen(this.points[i]), 1, Color.teal); + + for (var i = 1; i < this.points.length; i += 3) { render.coordinate(this.gameobject.this2screen(this.points[i]), 1, Color.green); - render.coordinate(this.gameobject.this2screen(this.points[i+1]), 1, Color.green); - render.line([this.gameobject.this2screen(this.points[i-1]), this.gameobject.this2screen(this.points[i])], Color.yellow); - render.line([this.gameobject.this2screen(this.points[i+1]), this.gameobject.this2screen(this.points[i+2])], Color.yellow); + render.coordinate(this.gameobject.this2screen(this.points[i + 1]), 1, Color.green); + render.line([this.gameobject.this2screen(this.points[i - 1]), this.gameobject.this2screen(this.points[i])], Color.yellow); + render.line([this.gameobject.this2screen(this.points[i + 1]), this.gameobject.this2screen(this.points[i + 2])], Color.yellow); } } }, - - finish_center(change) { this.points = this.points.map(function(x) { return x.sub(change); }); }, + + finish_center(change) { + this.points = this.points.map(function (x) { + return x.sub(change); + }); + }, pick(pos) { var i = Gizmos.pick_gameobject_points(pos, this.gameobject, this.points); var p = this.points[i]; if (!p) return undefined; - if (Spline.is_catmull(this.type) || this.type === -1) - return make_point_obj(this,p); - + if (Spline.is_catmull(this.type) || this.type === -1) return make_point_obj(this, p); + var that = this.gameobject; var me = this; if (p) { var o = { pos: p, - sync: me.sync.bind(me) + sync: me.sync.bind(me), }; - if (Spline.bezier_is_handle(this.points,i)) - o.move = function(d) { - d = that.dir_world2this(d); - p.x += d.x; - p.y += d.y; - Spline.bezier_cp_mirror(me.points,i); - }; - else - o.move = function(d) { + if (Spline.bezier_is_handle(this.points, i)) + o.move = function (d) { d = that.dir_world2this(d); p.x += d.x; p.y += d.y; - var pp = Spline.bezier_point_handles(me.points,i); - pp.forEach(ph => me.points[ph] = me.points[ph].add(d)); - } + Spline.bezier_cp_mirror(me.points, i); + }; + else + o.move = function (d) { + d = that.dir_world2this(d); + p.x += d.x; + p.y += d.y; + var pp = Spline.bezier_point_handles(me.points, i); + pp.forEach(ph => (me.points[ph] = me.points[ph].add(d))); + }; return o; } }, rm_node(idx) { if (idx < 0 || idx >= this.points.length) return; - if (Spline.is_catmull(this.type)) - this.points.splice(idx,1); + if (Spline.is_catmull(this.type)) this.points.splice(idx, 1); if (Spline.is_bezier(this.type)) { - assert(Spline.bezier_is_node(this.points, idx), 'Attempted to delete a bezier handle.'); - if (idx === 0) - this.points.splice(idx,2); - else if (idx === this.points.length-1) - this.points.splice(this.points.length-2,2); - else - this.points.splice(idx-1,3); + assert(Spline.bezier_is_node(this.points, idx), "Attempted to delete a bezier handle."); + if (idx === 0) this.points.splice(idx, 2); + else if (idx === this.points.length - 1) this.points.splice(this.points.length - 2, 2); + else this.points.splice(idx - 1, 3); } }, @@ -613,77 +653,84 @@ var edge2d = { pos = this.gameobject.world2this(pos); var idx = 0; if (Spline.is_catmull(this.type) || this.type === -1) { - if (this.points.length >= 2) - idx = physics.closest_point(pos, this.points, 400); + if (this.points.length >= 2) idx = physics.closest_point(pos, this.points, 400); - if (idx === this.points.length) - this.points.push(pos); - else - this.points.splice(idx, 0, pos); + if (idx === this.points.length) this.points.push(pos); + else this.points.splice(idx, 0, pos); } if (Spline.is_bezier(this.type)) { - idx = physics.closest_point(pos, Spline.bezier_nodes(this.points),400); + idx = physics.closest_point(pos, Spline.bezier_nodes(this.points), 400); if (idx < 0) return; - + if (idx === 0) { - this.points.unshift(pos.slice(), pos.add([-100,0]), Vector.reflect_point(this.points[1], this.points[0])); - return; + this.points.unshift(pos.slice(), pos.add([-100, 0]), Vector.reflect_point(this.points[1], this.points[0])); + return; } if (idx === Spline.bezier_node_count(this.points)) { - this.points.push(Vector.reflect_point(this.points.at(-2), this.points.at(-1)), pos.add([-100,0]), pos.slice()); - return; + this.points.push(Vector.reflect_point(this.points.at(-2), this.points.at(-1)), pos.add([-100, 0]), pos.slice()); + return; } - idx = 2 + (idx-1)*3; - var adds = [pos.add([100,0]), pos.slice(), pos.add([-100,0])]; + idx = 2 + (idx - 1) * 3; + var adds = [pos.add([100, 0]), pos.slice(), pos.add([-100, 0])]; this.points.splice(idx, 0, ...adds); } }, pick_all() { var picks = []; - this.points.forEach(x =>picks.push(make_point_obj(this,x))); + this.points.forEach(x => picks.push(make_point_obj(this, x))); return picks; }, }; -component.edge2d = function(obj) { +component.edge2d = function (obj) { if (!obj.body) obj.rigidify(); var edge = Object.create(edge2d); edge.body = obj.body; return edge; -} +}; edge2d.spoints.doc = "Returns the controls points after modifiers are applied, such as it being hollow or mirrored on its axises."; edge2d.inputs = {}; -edge2d.inputs.h = function() { this.hollow = !this.hollow; }; +edge2d.inputs.h = function () { + this.hollow = !this.hollow; +}; edge2d.inputs.h.doc = "Toggle hollow."; -edge2d.inputs['C-g'] = function() { if (this.hollowt > 0) this.hollowt--; }; -edge2d.inputs['C-g'].doc = "Thin the hollow thickness."; -edge2d.inputs['C-g'].rep = true; +edge2d.inputs["C-g"] = function () { + if (this.hollowt > 0) this.hollowt--; +}; +edge2d.inputs["C-g"].doc = "Thin the hollow thickness."; +edge2d.inputs["C-g"].rep = true; -edge2d.inputs['C-f'] = function() { this.hollowt++; }; -edge2d.inputs['C-f'].doc = "Increase the hollow thickness."; -edge2d.inputs['C-f'].rep = true; +edge2d.inputs["C-f"] = function () { + this.hollowt++; +}; +edge2d.inputs["C-f"].doc = "Increase the hollow thickness."; +edge2d.inputs["C-f"].rep = true; -edge2d.inputs['M-v'] = function() { if (this.thickness > 0) this.thickness--; }; -edge2d.inputs['M-v'].doc = "Decrease spline thickness."; -edge2d.inputs['M-v'].rep = true; +edge2d.inputs["M-v"] = function () { + if (this.thickness > 0) this.thickness--; +}; +edge2d.inputs["M-v"].doc = "Decrease spline thickness."; +edge2d.inputs["M-v"].rep = true; -edge2d.inputs['C-y'] = function() { +edge2d.inputs["C-y"] = function () { this.points = this.spoints(); this.flipx = false; this.flipy = false; this.hollow = false; }; -edge2d.inputs['C-y'].doc = "Freeze mirroring,"; -edge2d.inputs['M-b'] = function() { this.thickness++; }; -edge2d.inputs['M-b'].doc = "Increase spline thickness."; -edge2d.inputs['M-b'].rep = true; +edge2d.inputs["C-y"].doc = "Freeze mirroring,"; +edge2d.inputs["M-b"] = function () { + this.thickness++; +}; +edge2d.inputs["M-b"].doc = "Increase spline thickness."; +edge2d.inputs["M-b"].rep = true; -edge2d.inputs.plus = function() { +edge2d.inputs.plus = function () { if (this.angle <= 1) { this.angle = 1; return; @@ -693,18 +740,24 @@ edge2d.inputs.plus = function() { edge2d.inputs.plus.doc = "Increase the number of samples of this spline."; edge2d.inputs.plus.rep = true; -edge2d.inputs.minus = function() { this.angle *= 1.1; }; +edge2d.inputs.minus = function () { + this.angle *= 1.1; +}; edge2d.inputs.minus.doc = "Decrease the number of samples on this spline."; edge2d.inputs.minus.rep = true; -edge2d.inputs['C-r'] = function() { this.points = this.points.reverse(); }; -edge2d.inputs['C-r'].doc = "Reverse the order of the spline's points."; +edge2d.inputs["C-r"] = function () { + this.points = this.points.reverse(); +}; +edge2d.inputs["C-r"].doc = "Reverse the order of the spline's points."; -edge2d.inputs['C-l'] = function() { this.looped = !this.looped}; -edge2d.inputs['C-l'].doc = "Toggle spline being looped."; +edge2d.inputs["C-l"] = function () { + this.looped = !this.looped; +}; +edge2d.inputs["C-l"].doc = "Toggle spline being looped."; -edge2d.inputs['C-c'] = function() { - switch(this.type) { +edge2d.inputs["C-c"] = function () { + switch (this.type) { case Spline.type.bezier: this.points = Spline.bezier2catmull(this.points); break; @@ -712,10 +765,10 @@ edge2d.inputs['C-c'] = function() { this.type = Spline.type.catmull; }; -edge2d.inputs['C-c'].doc = "Set type of spline to catmull-rom."; +edge2d.inputs["C-c"].doc = "Set type of spline to catmull-rom."; -edge2d.inputs['C-b'] = function() { - switch(this.type) { +edge2d.inputs["C-b"] = function () { + switch (this.type) { case Spline.type.catmull: this.points = Spline.catmull2bezier(Spline.catmull_caps(this.points)); break; @@ -723,45 +776,60 @@ edge2d.inputs['C-b'] = function() { this.type = Spline.type.bezier; }; -edge2d.inputs['C-o'] = function() { this.type = -1; }; -edge2d.inputs['C-o'].doc = "Set spline to linear."; +edge2d.inputs["C-o"] = function () { + this.type = -1; +}; +edge2d.inputs["C-o"].doc = "Set spline to linear."; -edge2d.inputs['C-M-lm'] = function() { +edge2d.inputs["C-M-lm"] = function () { if (Spline.is_catmull(this.type)) { - var idx = Math.grab_from_points(input.mouse.worldpos(), this.points.map(p => this.gameobject.this2world(p)), 25); + var idx = Math.grab_from_points( + input.mouse.worldpos(), + this.points.map(p => this.gameobject.this2world(p)), + 25, + ); if (idx === -1) return; } else { - } this.points = this.points.newfirst(idx); }; -edge2d.inputs['C-M-lm'].doc = "Select the given point as the '0' of this spline."; +edge2d.inputs["C-M-lm"].doc = "Select the given point as the '0' of this spline."; -edge2d.inputs['C-lm'] = function() { this.add_node(input.mouse.worldpos()); } -edge2d.inputs['C-lm'].doc = "Add a point to the spline at the mouse position."; +edge2d.inputs["C-lm"] = function () { + this.add_node(input.mouse.worldpos()); +}; +edge2d.inputs["C-lm"].doc = "Add a point to the spline at the mouse position."; -edge2d.inputs['C-M-lm'] = function() { +edge2d.inputs["C-M-lm"] = function () { var idx = -1; if (Spline.is_catmull(this.type)) - idx = Math.grab_from_points(input.mouse.worldpos(), this.points.map(p => this.gameobject.this2world(p)), 25); + idx = Math.grab_from_points( + input.mouse.worldpos(), + this.points.map(p => this.gameobject.this2world(p)), + 25, + ); else { var nodes = Spline.bezier_nodes(this.points); - idx = Math.grab_from_points(input.mouse.worldpos(), nodes.map(p => this.gameobject.this2world(p)), 25); + idx = Math.grab_from_points( + input.mouse.worldpos(), + nodes.map(p => this.gameobject.this2world(p)), + 25, + ); idx *= 3; } this.rm_node(idx); }; -edge2d.inputs['C-M-lm'].doc = "Remove point from the spline."; +edge2d.inputs["C-M-lm"].doc = "Remove point from the spline."; -edge2d.inputs.lm = function(){}; -edge2d.inputs.lm.released = function(){}; +edge2d.inputs.lm = function () {}; +edge2d.inputs.lm.released = function () {}; -edge2d.inputs.lb = function() { +edge2d.inputs.lb = function () { var np = []; - this.points.forEach(function(c) { + this.points.forEach(function (c) { np.push(Vector.rotate(c, Math.deg2rad(-1))); }); @@ -770,10 +838,10 @@ edge2d.inputs.lb = function() { edge2d.inputs.lb.doc = "Rotate the points CCW."; edge2d.inputs.lb.rep = true; -edge2d.inputs.rb = function() { +edge2d.inputs.rb = function () { var np = []; - this.points.forEach(function(c) { + this.points.forEach(function (c) { np.push(Vector.rotate(c, Math.deg2rad(1))); }); @@ -785,28 +853,38 @@ edge2d.inputs.rb.rep = true; /* CIRCLE */ function shape_maker(maker) { - return function(obj) { - if (!obj.body) obj.rigidify(); - return maker(obj.body); - } + return function (obj) { + if (!obj.body) obj.rigidify(); + return maker(obj.body); + }; } component.circle2d = shape_maker(os.make_circle2d); component.poly2d = shape_maker(os.make_poly2d); component.seg2d = shape_maker(os.make_seg2d); Object.mix(os.make_circle2d(), { - boundingbox() { return bbox.fromcwh(this.offset, [this.radius,this.radius]); }, - - set scale(x) { this.radius = x; }, - get scale() { return this.radius; }, + boundingbox() { + return bbox.fromcwh(this.offset, [this.radius, this.radius]); + }, - get pos() { return this.offset; }, - set pos(x) { this.offset = x; }, + set scale(x) { + this.radius = x; + }, + get scale() { + return this.radius; + }, + + get pos() { + return this.offset; + }, + set pos(x) { + this.offset = x; + }, grow(x) { - if (typeof x === 'number') this.scale *= x; - else if (typeof x === 'object') this.scale *= x[0]; + if (typeof x === "number") this.scale *= x; + else if (typeof x === "object") this.scale *= x[0]; }, }); -return {component, SpriteAnim}; +return { component, SpriteAnim }; diff --git a/scripts/debug.js b/scripts/debug.js index 8a561b27..22fd22d2 100644 --- a/scripts/debug.js +++ b/scripts/debug.js @@ -1,4 +1,7 @@ -debug.build = function(fn) { if (!debug.show) return; fn(); } +debug.build = function (fn) { + if (!debug.show) return; + fn(); +}; debug.show = true; debug.urnames = false; debug.termout = true; @@ -7,64 +10,62 @@ debug.cheat = false; debug.meta = false; debug.showprofiler = false; -debug.fn_break = function(fn,obj = globalThis) { - if (typeof fn !== 'function') return; - - var newfn = function() { +debug.fn_break = function (fn, obj = globalThis) { + if (typeof fn !== "function") return; + + var newfn = function () { console.log("broke"); fn(); }; - obj[fn.name] = newfn; -} + obj[fn.name] = newfn; +}; debug.draw_phys = false; debug.draw_bb = false; debug.draw_gizmos = false; debug.draw_names = false; debug.sprite_nums = false; -debug.draw = function() { - if (this.draw_phys) game.all_objects(function(x) { debug.draw_gameobject(x); }); - +debug.draw = function () { + if (this.draw_phys) + game.all_objects(function (x) { + debug.draw_gameobject(x); + }); + if (this.draw_bb) - game.all_objects(function(x) { debug.boundingbox(x.boundingbox(), Color.debug.boundingbox.alpha(0.05)); }); + game.all_objects(function (x) { + debug.boundingbox(x.boundingbox(), Color.debug.boundingbox.alpha(0.05)); + }); if (this.draw_gizmos) - game.all_objects(function(x) { + game.all_objects(function (x) { if (!x.icon) return; gui.image(x.icon, game.camera.world2view(x.pos)); }); if (this.draw_names) - game.all_objects(function(x) { - render.text(x, game.camera.view2screen(x.pos).add([0,32]), 1, Color.debug.names); + game.all_objects(function (x) { + render.text(x, game.camera.view2screen(x.pos).add([0, 32]), 1, Color.debug.names); }); if (debug.gif.rec) { - render.text("REC", [0,40], 1); - render.text(time.timecode(time.timenow() - debug.gif.start_time, debug.gif.fps), [0,30], 1); + render.text("REC", [0, 40], 1); + render.text(time.timecode(time.timenow() - debug.gif.start_time, debug.gif.fps), [0, 30], 1); } - + return; - - if (sim.paused()) render.text("PAUSED", [0,0],1); - render.text(sim.playing() ? "PLAYING" - : sim.stepping() ? - "STEP" : - sim.paused() ? - "PAUSED; EDITING" : - "EDIT", [0, 0], 1); -} + if (sim.paused()) render.text("PAUSED", [0, 0], 1); -var assert = function(op, str = `assertion failed [value '${op}']`) -{ - if (!op) - console.panic(str); -} + render.text(sim.playing() ? "PLAYING" : sim.stepping() ? "STEP" : sim.paused() ? "PAUSED; EDITING" : "EDIT", [0, 0], 1); +}; + +var assert = function (op, str = `assertion failed [value '${op}']`) { + if (!op) console.panic(str); +}; var Gizmos = { pick_gameobject_points(worldpos, gameobject, points) { - var idx = Math.grab_from_points(worldpos, points.map(gameobject.this2world,gameobject), 25); + var idx = Math.grab_from_points(worldpos, points.map(gameobject.this2world, gameobject), 25); if (idx === -1) return undefined; return idx; }, @@ -72,20 +73,24 @@ var Gizmos = { /* These controls are available during editing, and during play of debug builds */ debug.inputs = {}; -debug.inputs.f1 = function () { debug.draw_phys = !debug.draw_phys; }; +debug.inputs.f1 = function () { + debug.draw_phys = !debug.draw_phys; +}; debug.inputs.f1.doc = "Draw physics debugging aids."; -debug.inputs.f3 = function() { debug.draw_bb = !debug.draw_bb; }; +debug.inputs.f3 = function () { + debug.draw_bb = !debug.draw_bb; +}; debug.inputs.f3.doc = "Toggle drawing bounding boxes."; -debug.inputs.f4 = function() { +debug.inputs.f4 = function () { debug.draw_names = !debug.draw_names; debug.draw_gizmos = !debug.draw_gizmos; }; debug.inputs.f4.doc = "Toggle drawing gizmos and names of objects."; var gif = { - w: 640, /* Max width */ - h: 480, /* Max height */ - stretch: false, /* True if you want to stretch */ + w: 640 /* Max width */, + h: 480 /* Max height */, + stretch: false /* True if you want to stretch */, cpf: 4, depth: 16, file: "out.gif", @@ -97,17 +102,15 @@ var gif = { var w = this.w; var h = this.h; if (!this.stretch) { - var win = window.height / window.width; - var gif = h/w; - if (gif > win) - h = w * win; - else - w = h / win; + var win = window.height / window.width; + var gif = h / w; + if (gif > win) h = w * win; + else w = h / win; } -// cmd(131, w, h, this.cpf, this.depth); + // cmd(131, w, h, this.cpf, this.depth); this.rec = true; - this.fps = (1/this.cpf)*100; + this.fps = (1 / this.cpf) * 100; this.start_time = time.now(); timer.oneshot(this.stop.bind(this), this.secs, this, true); @@ -115,54 +118,59 @@ var gif = { stop() { if (!this.rec) return; -// cmd(132, this.file); + // cmd(132, this.file); this.rec = false; }, }; -debug.inputs.f8 = function() { +debug.inputs.f8 = function () { var now = new Date(); debug.gif.file = now.toISOString() + ".gif"; debug.gif.start(); }; -debug.inputs.f9 = function() { +debug.inputs.f9 = function () { debug.gif.stop(); -} +}; -debug.inputs.f10 = function() { time.timescale = 0.1; }; +debug.inputs.f10 = function () { + time.timescale = 0.1; +}; debug.inputs.f10.doc = "Toggle timescale to 1/10."; -debug.inputs.f10.released = function () { time.timescale = 1.0; }; -debug.inputs.f12 = function() { gui.defaults.debug = !gui.defaults.debug; console.warn("gui toggle debug");}; +debug.inputs.f10.released = function () { + time.timescale = 1.0; +}; +debug.inputs.f12 = function () { + gui.defaults.debug = !gui.defaults.debug; + console.warn("gui toggle debug"); +}; debug.inputs.f12.doc = "Toggle drawing gui debugging aids."; -debug.inputs['M-1'] = render.normal; -debug.inputs['M-2'] = render.wireframe; -debug.inputs['C-M-f'] = function() {}; -debug.inputs['C-M-f'].doc = "Enter camera fly mode."; +debug.inputs["M-1"] = render.normal; +debug.inputs["M-2"] = render.wireframe; +debug.inputs["C-M-f"] = function () {}; +debug.inputs["C-M-f"].doc = "Enter camera fly mode."; debug.api = {}; -debug.api.doc_entry = function(obj, key) -{ - if (typeof key !== 'string') { +debug.api.doc_entry = function (obj, key) { + if (typeof key !== "string") { console.warn("Cannot print a key that isn't a string."); return undefined; } - + var title = key; - + var o = obj[key]; - if (typeof o === 'undefined' && obj.impl && typeof obj.impl[key] !== 'undefined') - o = obj.impl[key]; + if (typeof o === "undefined" && obj.impl && typeof obj.impl[key] !== "undefined") o = obj.impl[key]; var t = typeof o; if (Array.isArray(o)) t = "array"; - else if (t === 'function') { - title = o.toString().tofirst(')') + ")"; - title = title.fromfirst('('); + else if (t === "function") { + title = o.toString().tofirst(")") + ")"; + title = title.fromfirst("("); title = key + "(" + title; if (o.doc) doc = o.doc; t = ""; - } else if (t === 'undefined') t = ""; + } else if (t === "undefined") t = ""; if (t) t = "**" + t + "**\n"; @@ -175,12 +183,11 @@ debug.api.doc_entry = function(obj, key) ${t} ${doc} `; -} +}; -debug.api.print_doc = function(name) -{ +debug.api.print_doc = function (name) { var obj = name; - if (typeof name === 'string') { + if (typeof name === "string") { obj = eval(name); if (!obj) { console.warn(`Cannot print the API of '${name}', as it was not found.`); @@ -189,8 +196,8 @@ debug.api.print_doc = function(name) obj = globalThis[name]; } - - obj = eval(name); + + obj = eval(name); if (!Object.isObject(obj)) { console.warn("Cannot print the API of something that isn't an object."); @@ -201,24 +208,24 @@ debug.api.print_doc = function(name) console.warn(`Object '${name}' does not exist.`); return; } - + var mdoc = "# " + name + "\n"; if (obj.doc?.doc) mdoc += obj.doc.doc + "\n"; - else if (typeof obj.doc === 'string') mdoc += obj.doc + "\n"; + else if (typeof obj.doc === "string") mdoc += obj.doc + "\n"; var keys = Object.keys(obj); for (var key of keys) { - if (key === 'doc') continue; - if (key === 'toString') continue; + if (key === "doc") continue; + if (key === "toString") continue; mdoc += debug.api.doc_entry(obj, key) + "\n"; } return mdoc; -} +}; return { debug, Gizmos, - assert -} + assert, +}; diff --git a/scripts/diff.js b/scripts/diff.js index 26db2ecd..2ad751e8 100644 --- a/scripts/diff.js +++ b/scripts/diff.js @@ -1,98 +1,90 @@ -function deep_copy(from) { return json.decode(json.encode(from)); } +function deep_copy(from) { + return json.decode(json.encode(from)); +} -function valdiff(from,to) -{ +function valdiff(from, to) { if (typeof from !== typeof to) return from; - if (typeof from === 'function') return undefined; - if (typeof from === 'undefined') return undefined; + if (typeof from === "function") return undefined; + if (typeof from === "undefined") return undefined; + + if (typeof from === "number") { + return to; - if (typeof from === 'number') { - return to; - return undefined; } - if (typeof from === 'object') - return ediff(from,to); + if (typeof from === "object") return ediff(from, to); if (from !== to) return to; return undefined; } -function ediff(from,to) -{ +function ediff(from, to) { var ret = {}; - - if (!to) -// return ediff(from, {}); - return deep_copy(from); - - Object.entries(from).forEach(function([key,v]) { - if (typeof v === 'function') return; - if (typeof v === 'undefined') return; + if (!to) + // return ediff(from, {}); + return deep_copy(from); + + Object.entries(from).forEach(function ([key, v]) { + if (typeof v === "function") return; + if (typeof v === "undefined") return; if (Array.isArray(v)) { if (!Array.isArray(to[key]) || v.length !== to[key].length) { - var r = ediff(v,[]); + var r = ediff(v, []); if (r) ret[key] = Object.values(r); return; } var diff = ediff(from[key], to[key]); - if (diff && !Object.empty(diff)) - ret[key] = Object.values(ediff(v,[])); + if (diff && !Object.empty(diff)) ret[key] = Object.values(ediff(v, [])); return; } - if (typeof v === 'object' && v !== null) { + if (typeof v === "object" && v !== null) { var diff = ediff(v, to[key]); - if (diff && !Object.empty(diff)) - ret[key] = diff; + if (diff && !Object.empty(diff)) ret[key] = diff; return; } - if (typeof v === 'number' || v === null) { + if (typeof v === "number" || v === null) { if (!isFinite(v)) v = null; // Squash infinity to null - if (v !== to[key]) - ret[key] = v; + if (v !== to[key]) ret[key] = v; return; } - if (!to || v !== to[key]) - ret[key] = v; + if (!to || v !== to[key]) ret[key] = v; }); if (Object.empty(ret)) return undefined; - + return ret; } ediff.doc = "Given a from and to object, returns an object that, if applied to from, will make it the same as to. Does not include deletion; it is only additive. If one element in an array is different, the entire array is copied. Squashes infinite numbers to null for use in JSON."; -function samediff(from, to) -{ +function samediff(from, to) { var same = []; if (!to) return same; - if (typeof to !== 'object') { + if (typeof to !== "object") { console.warn("'To' must be an object. Got " + to); return same; } - Object.keys(from).forEach(function(k) { + Object.keys(from).forEach(function (k) { if (Object.isObject(from[k])) { samediff(from[k], to[k]); return; } -// if (Array.isArray(from[k])) { -// var d = valdiff(from[k], to[k]); -// if (!d) -// } + // if (Array.isArray(from[k])) { + // var d = valdiff(from[k], to[k]); + // if (!d) + // } var d = valdiff(from[k], to[k]); - if (!d) - delete from[k]; + if (!d) delete from[k]; }); return same; @@ -104,4 +96,4 @@ return { deep_copy, ediff, samediff, -} +}; diff --git a/scripts/editor.js b/scripts/editor.js index c9e857c8..4f849c83 100644 --- a/scripts/editor.js +++ b/scripts/editor.js @@ -10,7 +10,9 @@ player[0].control(debug); var show_frame = true; var editor = { - toString() { return "editor"; }, + toString() { + return "editor"; + }, grid_size: 100, ruler_mark_px: 100, grid_color: Color.green.alpha(0.3), @@ -20,40 +22,43 @@ var editor = { scalelist: [], rotlist: [], camera: undefined, - edit_level: undefined, /* The current level that is being edited */ - desktop: undefined, /* The editor desktop, where all editing objects live */ + edit_level: undefined /* The current level that is being edited */, + desktop: undefined /* The editor desktop, where all editing objects live */, working_layer: 0, get cursor() { - if (this.selectlist.length === 0 ) return input.mouse.worldpos(); + if (this.selectlist.length === 0) return input.mouse.worldpos(); return physics.com(this.selectlist.map(x => x.pos)); }, edit_mode: "basic", - get_this() { return this.edit_level; }, + get_this() { + return this.edit_level; + }, - try_select() { /* nullify true if it should set selected to null if it doesn't find an object */ + try_select() { + /* nullify true if it should set selected to null if it doesn't find an object */ var go = physics.pos_query(input.mouse.worldpos()); return this.do_select(go); }, - - do_select(obj) { /* select an object, if it is selectable given the current editor state */ + + do_select(obj) { + /* select an object, if it is selectable given the current editor state */ if (!obj) return; if (!obj._ed.selectable) return undefined; - + if (obj.master !== this.edit_level) { var testlevel = obj.master; - while (testlevel && testlevel.master !== world && testlevel.master !== this.edit_level && testlevel !== testlevel.master) - testlevel = testlevel.master; + while (testlevel && testlevel.master !== world && testlevel.master !== this.edit_level && testlevel !== testlevel.master) testlevel = testlevel.master; return testlevel; } - + return obj; if (this.working_layer > -1 && obj.draw_layer !== this.working_layer) return undefined; return obj; }, - + curpanel: undefined, check_level_nested() { @@ -78,28 +83,34 @@ var editor = { sel_start: [], mover(amt, snap) { - return function(go) { go.pos = go.pos.add(amt)}; + return function (go) { + go.pos = go.pos.add(amt); + }; }, - step_amt() { return input.keyboard.down("shift") ? 10 : 1; }, + step_amt() { + return input.keyboard.down("shift") ? 10 : 1; + }, on_grid(pos) { - return pos.every(function(x) { return x % editor.grid_size === 0; }); + return pos.every(function (x) { + return x % editor.grid_size === 0; + }); }, snapper(dir, grid) { - return function(go) { - go.pos = go.pos.add(dir.scale(grid/2)); - go.pos = go.pos.map(function(x) { return Math.snap(x, grid) }, this); - } + return function (go) { + go.pos = go.pos.add(dir.scale(grid / 2)); + go.pos = go.pos.map(function (x) { + return Math.snap(x, grid); + }, this); + }; }, key_move(dir) { if (!editor.grabselect) return; - if (input.keyboard.down('ctrl')) - this.selectlist.forEach(this.snapper(dir.scale(1.01), editor.grid_size)); - else - this.selectlist.forEach(this.mover(dir.scale(this.step_amt()))); + if (input.keyboard.down("ctrl")) this.selectlist.forEach(this.snapper(dir.scale(1.01), editor.grid_size)); + else this.selectlist.forEach(this.mover(dir.scale(this.step_amt()))); }, /* Snapmode @@ -115,13 +126,15 @@ var editor = { return pos; case 1: - return pos.map(function(x) { return Math.round(x); }); + return pos.map(function (x) { + return Math.round(x); + }); case 2: - return pos.map + return pos.map; } }, - + unselect() { editor.selectlist = []; this.grabselect = []; @@ -133,14 +146,14 @@ var editor = { sel_comp: undefined, comp_info: false, brush_obj: undefined, - + camera_recalls: {}, camera_recall_stack: [], camera_recall_store() { this.camera_recall_stack.push({ - pos:this.camera.pos, - zoom:this.camera.zoom + pos: this.camera.pos, + zoom: this.camera.zoom, }); }, @@ -151,37 +164,36 @@ var editor = { camera_recall_clear() { this.camera_recall_stack = []; }, - + input_num_pressed(num) { - if (input.keyboard.down('ctrl')) { + if (input.keyboard.down("ctrl")) { this.camera_recalls[num] = { - pos:this.camera.pos, - zoom:this.camera.zoom + pos: this.camera.pos, + zoom: this.camera.zoom, }; return; } - if (num in this.camera_recalls) - Object.assign(this.camera, this.camera_recalls[num]); + if (num in this.camera_recalls) Object.assign(this.camera, this.camera_recalls[num]); }, zoom_to_bb(bb) { var cwh = bbox.tocwh(bb); - + var xscale = cwh.wh.x / window.width; var yscale = cwh.wh.y / window.height; - + var zoom = yscale > xscale ? yscale : xscale; - + this.camera.pos = cwh.c; - this.camera.zoom = zoom*1.3; + this.camera.zoom = zoom * 1.3; }, z_start: undefined, grabselect: undefined, mousejoy: undefined, joystart: undefined, - + stash: undefined, start_play_ed() { @@ -196,7 +208,7 @@ var editor = { global.mixin("predbg.js"); console.warn(`starting game with ${this.dbg_ur}`); editor.dbg_play = world.spawn(this.dbg_ur); - editor.dbg_play.pos = [0,0]; + editor.dbg_play.pos = [0, 0]; global.mixin("debug.js"); }, @@ -206,7 +218,7 @@ var editor = { sim.play(); player[0].uncontrol(this); player[0].control(limited_editor); - editor.cbs.forEach(cb=>cb()); + editor.cbs.forEach(cb => cb()); editor.cbs = []; actor.spawn("game.js"); }, @@ -217,12 +229,12 @@ var editor = { sim.pause(); player[0].control(this); player[0].uncontrol(limited_editor); - + editor.cbs.push(Register.gui.register(editor.gui.bind(editor))); editor.cbs.push(Register.draw.register(editor.draw.bind(editor))); editor.cbs.push(Register.debug.register(editor.ed_debug.bind(editor))); editor.cbs.push(Register.update.register(gui.controls.update, gui.controls)); - + this.desktop = world.spawn(); world.rename_obj(this.desktop.toString(), "desktop"); this.edit_level = this.desktop; @@ -236,13 +248,13 @@ var editor = { editor.camera._ed.selectable = false; game.camera = editor.camera; }, - + openpanel(panel) { if (this.curpanel) { this.curpanel.close(); player[0].uncontrol(this.curpanel); } - + this.curpanel = panel; player[0].control(this.curpanel); this.curpanel.open(); @@ -255,11 +267,13 @@ var editor = { }, cleanpanels(panel) { - this.curpanels = this.curpanels.filter(function(x) { return x.on; }); + this.curpanels = this.curpanels.filter(function (x) { + return x.on; + }); }, - + snapshots: [], - curlvl: {}, /* What the level currently looks like on file */ + curlvl: {} /* What the level currently looks like on file */, reset_undos() { this.snapshots = []; @@ -270,7 +284,7 @@ var editor = { return; // TODO: Implement var dif = this.edit_level.json_obj(); if (!dif) return; - + if (this.snapshots.length !== 0) { var ddif = ediff(dif, this.snapshots.last()); if (!ddif) return; @@ -280,7 +294,7 @@ var editor = { this.snapshots.push(dif); this.backshots = []; return; - + this.snapshots.push(dif); this.backshots = []; @@ -289,7 +303,7 @@ var editor = { this.edit_level.check_dirty(); }, - backshots: [], /* Redo snapshots */ + backshots: [] /* Redo snapshots */, restore_lvl(lvl) { this.unselect(); @@ -318,12 +332,12 @@ var editor = { return; } this.unselect(); -// this.backshots.push(this.edit_level.save()); + // this.backshots.push(this.edit_level.save()); var dd = this.snapshots.pop(); Object.dainty_assign(this.edit_level, dd); this.edit_level.check_dirty(); }, - + restore_buffer() { this.restore_level(this.filesnap); }, @@ -334,28 +348,28 @@ var editor = { return; } }, - - draw_objects_names(obj,root,depth = 0){ - if (!obj) return; - if (!obj.objects) return; - root = root ? root + "." : root; - Object.entries(obj.objects).forEach(function(x) { - var p = root + x[0]; - render.text(p, x[1].this2screen(), 1, editor.color_depths[depth]); - editor.draw_objects_names(x[1], p, depth+1); - }); + + draw_objects_names(obj, root, depth = 0) { + if (!obj) return; + if (!obj.objects) return; + root = root ? root + "." : root; + Object.entries(obj.objects).forEach(function (x) { + var p = root + x[0]; + render.text(p, x[1].this2screen(), 1, editor.color_depths[depth]); + editor.draw_objects_names(x[1], p, depth + 1); + }); }, _sel_comp: undefined, - get sel_comp() { return this._sel_comp; }, + get sel_comp() { + return this._sel_comp; + }, set sel_comp(x) { - if (this._sel_comp) - player[0].uncontrol(this._sel_comp); - + if (this._sel_comp) player[0].uncontrol(this._sel_comp); + this._sel_comp = x; - if (this._sel_comp) - player[0].control(this._sel_comp); + if (this._sel_comp) player[0].control(this._sel_comp); }, time: 0, @@ -363,11 +377,10 @@ var editor = { color_depths: [], draw() { this.selectlist.forEach(x => { - if ('gizmo' in x && typeof x['gizmo'] === 'function' ) - x.gizmo(); + if ("gizmo" in x && typeof x["gizmo"] === "function") x.gizmo(); }); - render.line(bbox.topoints(bbox.fromcwh([0,0],[game.width,game.height])).wrapped(1), Color.green); + render.line(bbox.topoints(bbox.fromcwh([0, 0], [game.width, game.height])).wrapped(1), Color.green); /* Draw selection box */ if (this.sel_start) { @@ -380,49 +393,46 @@ var editor = { var wh = []; wh[0] = Math.abs(endpos[0] - this.sel_start[0]); wh[1] = Math.abs(endpos[1] - this.sel_start[1]); - var bb = bbox.fromcwh(c,wh); + var bb = bbox.fromcwh(c, wh); render.boundingbox(bb, Color.Editor.select.alpha(0.1)); render.line(bbox.topoints(bb).wrapped(1), Color.white); } }, - gui() { + gui() { /* Clean out killed objects */ -// if (show_frame) -/// render.line(shape.box(window.rendersize.x, window.rendersize.y).wrapped(1).map(p => game.camera.world2view(p)), Color.yellow); + // if (show_frame) + /// render.line(shape.box(window.rendersize.x, window.rendersize.y).wrapped(1).map(p => game.camera.world2view(p)), Color.yellow); - render.text([0,0], game.camera.world2view([0,0])); + render.text([0, 0], game.camera.world2view([0, 0])); - render.text("WORKING LAYER: " + this.working_layer, [0,520]); - render.text("MODE: " + this.edit_mode, [0,520-render.font.linegap]); + render.text("WORKING LAYER: " + this.working_layer, [0, 520]); + render.text("MODE: " + this.edit_mode, [0, 520 - render.font.linegap]); - if (this.comp_info && this.sel_comp) - render.text(input.print_pawn_kbm(this.sel_comp,false), [100,700],1); + if (this.comp_info && this.sel_comp) render.text(input.print_pawn_kbm(this.sel_comp, false), [100, 700], 1); - render.cross(editor.edit_level.this2screen(),3,Color.blue); + render.cross(editor.edit_level.this2screen(), 3, Color.blue); var thiso = editor.get_this(); var clvl = thiso; - + var lvlchain = []; while (clvl !== world) { lvlchain.push(clvl); clvl = clvl.master; } lvlchain.push(clvl); - + var colormap = ColorMap.Inferno; editor.color_depths = []; - for (var i = 1; i > 0 ; i -= 0.1) - editor.color_depths.push(colormap.sample(i)); - + for (var i = 1; i > 0; i -= 0.1) editor.color_depths.push(colormap.sample(i)); + var ypos = 200; var depth = 0; var alldirty = false; for (var lvl of lvlchain) { if (!lvl._ed?.selectable) continue; - if (alldirty) - lvl._ed.dirty = true; + if (alldirty) lvl._ed.dirty = true; else { if (!lvl._ed) continue; lvl.check_dirty(); @@ -430,93 +440,99 @@ var editor = { } } lvlchain.reverse(); - lvlchain.forEach(function(x,i) { + lvlchain.forEach(function (x, i) { depth = i; var lvlstr = x.namestr(); - if (i === lvlchain.length-1) lvlstr += "[this]"; + if (i === lvlchain.length - 1) lvlstr += "[this]"; render.text(lvlstr, [0, ypos], 1, editor.color_depths[depth]); ypos += render.font.linegap; - render.text("^^^^^^", [0,ypos],1); + render.text("^^^^^^", [0, ypos], 1); ypos += render.font.linegap; }); depth++; - render.text("$$$$$$", [0,ypos],1,editor.color_depths[depth]); - - this.selectlist.forEach(function(x) { - render.text(x.urstr(), x.this2screen().add([0, render.font.linegap*2]), 1, Color.editor.ur); - render.text(x.pos.map(function(x) { return Math.round(x); }), x.this2screen()); + render.text("$$$$$$", [0, ypos], 1, editor.color_depths[depth]); + + this.selectlist.forEach(function (x) { + render.text(x.urstr(), x.this2screen().add([0, render.font.linegap * 2]), 1, Color.editor.ur); + render.text( + x.pos.map(function (x) { + return Math.round(x); + }), + x.this2screen(), + ); render.cross(x.this2screen(), 10, Color.blue); }); - Object.entries(thiso.objects).forEach(function(x) { + Object.entries(thiso.objects).forEach(function (x) { var p = x[1].namestr(); - render.text(p, x[1].this2screen().add([0,render.font.linegap]),1,editor.color_depths[depth]); - render.point(x[1].this2screen(),5,Color.blue.alpha(0.3)); + render.text(p, x[1].this2screen().add([0, render.font.linegap]), 1, editor.color_depths[depth]); + render.point(x[1].this2screen(), 5, Color.blue.alpha(0.3)); render.point(x[1].this2screen(), 1, Color.red); }); var mg = physics.pos_query(input.mouse.worldpos()); - + if (mg && mg._ed?.selectable) { var p = mg.path_from(thiso); - render.text(p, input.mouse.screenpos(),1,Color.teal); + render.text(p, input.mouse.screenpos(), 1, Color.teal); } - if (this.rotlist.length === 1) - render.text(Math.places(this.rotlist[0].angle, 3), input.mouse.screenpos(), 1, Color.teal); + if (this.rotlist.length === 1) render.text(Math.places(this.rotlist[0].angle, 3), input.mouse.screenpos(), 1, Color.teal); if (this.selectlist.length === 1) { var i = 1; for (var key in this.selectlist[0].components) { var selected = this.sel_comp === this.selectlist[0].components[key]; var str = (selected ? ">" : " ") + key + " [" + this.selectlist[0].components[key].toString() + "]"; - render.text(str, this.selectlist[0].this2screen().add([0,-render.font.linegap*(i++)])); + render.text(str, this.selectlist[0].this2screen().add([0, -render.font.linegap * i++])); } if (this.sel_comp) { - if ('gizmo' in this.sel_comp) this.sel_comp.gizmo(); + if ("gizmo" in this.sel_comp) this.sel_comp.gizmo(); } } - editor.edit_level.objects.forEach(function(obj) { - if (!obj._ed.selectable) - render.text("lock", obj,screenpos()); + editor.edit_level.objects.forEach(function (obj) { + if (!obj._ed.selectable) render.text("lock", obj, screenpos()); }); render.grid(1, editor.grid_size, editor.grid_color); - var startgrid = game.camera.view2world([-20,0]).map(function(x) { return Math.snap(x, editor.grid_size); }); + var startgrid = game.camera.view2world([-20, 0]).map(function (x) { + return Math.snap(x, editor.grid_size); + }); var endgrid = game.camera.view2world([window.width, window.height]); - - var w_step = Math.round(editor.ruler_mark_px/window.width * (endgrid.x-startgrid.x)/editor.grid_size)*editor.grid_size; + + var w_step = Math.round(((editor.ruler_mark_px / window.width) * (endgrid.x - startgrid.x)) / editor.grid_size) * editor.grid_size; if (w_step === 0) w_step = editor.grid_size; - - var h_step = Math.round(editor.ruler_mark_px/window.height * (endgrid.y-startgrid.y)/editor.grid_size)*editor.grid_size; + + var h_step = Math.round(((editor.ruler_mark_px / window.height) * (endgrid.y - startgrid.y)) / editor.grid_size) * editor.grid_size; if (h_step === 0) h_step = editor.grid_size; - - while(startgrid[0] <= endgrid[0]) { - render.text(startgrid[0], [game.camera.world2view([startgrid[0], 0])[0],0]); + + while (startgrid[0] <= endgrid[0]) { + render.text(startgrid[0], [game.camera.world2view([startgrid[0], 0])[0], 0]); startgrid[0] += w_step; } - while(startgrid[1] <= endgrid[1]) { + while (startgrid[1] <= endgrid[1]) { render.text(startgrid[1], [0, game.camera.world2view([0, startgrid[1]])[1]]); startgrid[1] += h_step; } - - if (this.curpanel && this.curpanel.on) - this.curpanel.gui(); - this.curpanels.forEach(function(x) { + if (this.curpanel && this.curpanel.on) this.curpanel.gui(); + + this.curpanels.forEach(function (x) { if (x.on) x.gui(); - }); + }); }, - + ed_debug() { if (!debug.phys_drawing) - this.selectlist.forEach(function(x) { debug.draw_obj_phys(x); }); + this.selectlist.forEach(function (x) { + debug.draw_obj_phys(x); + }); }, - + killring: [], killcom: [], @@ -537,7 +553,7 @@ var editor = { this.edit_level = Level.loadfile(file); this.unselect(); }, - + /* Checking to save an entity as a subtype. */ /* sub is the name of the (sub)type; obj is the object to save it as */ /* if saving subtype of 'empty', it appears on the top level */ @@ -552,46 +568,46 @@ var editor = { return; } - if (obj.ur === 'empty') { + if (obj.ur === "empty") { /* make a new type path */ - if (Object.access(ur,sub)) { + if (Object.access(ur, sub)) { console.warn(`Ur named ${sub} already exists.`); - return; + return; } var file = `${sub}.json`; - io.slurpwrite(file, json.encode(obj.json_obj(),null,1)); + io.slurpwrite(file, json.encode(obj.json_obj(), null, 1)); ur[sub] = { name: sub, data: file, - fresh: json.decode(json.encode(obj)) - } + fresh: json.decode(json.encode(obj)), + }; obj.ur = sub; - + return; } else if (!sub.startsWith(obj.ur)) { console.warn(`Cannot make an ur of type ${sub} from an object with the ur ${obj.ur}`); return; } - var curur = Object.access(ur,sub); - + var curur = Object.access(ur, sub); + if (curur) { notifypanel.action = editor.saveas; this.openpanel(gen_notify("Entity already exists with that name. Delete first.")); } else { - var path = sub.replaceAll('.', '/') + ".json"; + var path = sub.replaceAll(".", "/") + ".json"; var saveobj = obj.json_obj(); - io.slurpwrite(path, JSON.stringify(saveobj,null,1)); + io.slurpwrite(path, JSON.stringify(saveobj, null, 1)); if (obj === editor.edit_level) { if (obj === editor.desktop) { - obj.clear(); - var nobj = editor.edit_level.spawn(sub); + obj.clear(); + var nobj = editor.edit_level.spawn(sub); editor.selectlist = [nobj]; return; - } - editor.edit_level = editor.edit_level.master; + } + editor.edit_level = editor.edit_level.master; } var t = obj.transform(); @@ -602,26 +618,24 @@ var editor = { obj.angle = t.angle; } }, -} +}; -editor.new_object = function() -{ +editor.new_object = function () { var obj = editor.edit_level.spawn(); obj.set_pos(input.mouse.worldpos()); this.selectlist = [obj]; return obj; -} +}; editor.new_object.doc = "Create an empty object."; -editor.new_from_img = function(path) -{ +editor.new_from_img = function (path) { var o = editor.new_object(); o.add_component(component.sprite).path = path; return o; -} +}; editor.inputs = {}; -editor.inputs['C-b'] = function() { +editor.inputs["C-b"] = function () { if (this.selectlist.length !== 1) { console.warn(`Can only bake a single object at a time.`); return; @@ -629,58 +643,64 @@ editor.inputs['C-b'] = function() { var obj = this.selectlist[0]; - obj.components.forEach(function(c) { - if (typeof c.grow !== 'function') return; + obj.components.forEach(function (c) { + if (typeof c.grow !== "function") return; c.grow(obj.scale); c.sync?.(); }); - obj.set_scale([1,1,1]); -} + obj.set_scale([1, 1, 1]); +}; -editor.inputs.drop = function(str) { - str = str.slice(os.cwd().length+1); +editor.inputs.drop = function (str) { + str = str.slice(os.cwd().length + 1); if (!Resources.is_image(str)) { console.warn("NOT AN IMAGE"); return; } - if (this.selectlist.length === 0) - return editor.new_from_img(str); - - if (this.sel_comp?.comp === 'sprite') { + if (this.selectlist.length === 0) return editor.new_from_img(str); + + if (this.sel_comp?.comp === "sprite") { this.sel_comp.path = str; return; } - + var mg = physics.pos_query(input.mouse.worldpos()); if (!mg) return; - var img = mg.get_comp_by_name('sprite'); + var img = mg.get_comp_by_name("sprite"); if (!img) return; img[0].path = str; -} +}; -editor.inputs.f9 = function() { os.capture( "capture.bmp", 0, 0, 500, 500); } +editor.inputs.f9 = function () { + os.capture("capture.bmp", 0, 0, 500, 500); +}; -editor.inputs.release_post = function() { +editor.inputs.release_post = function () { editor.snapshot(); editor.selectlist?.forEach(x => x.check_dirty()); /* snap all objects to be pixel perfect */ - game.all_objects(o => o.pos = o.pos.map(x => Math.round(x)), editor.edit_level); + game.all_objects(o => (o.pos = o.pos.map(x => Math.round(x))), editor.edit_level); }; -editor.inputs['C-a'] = function() { - if (!Object.empty(editor.selectlist)) { editor.unselect(); return; } +editor.inputs["C-a"] = function () { + if (!Object.empty(editor.selectlist)) { + editor.unselect(); + return; + } editor.unselect(); editor.selectlist = editor.edit_level.objects.slice(); }; -editor.inputs['C-a'].doc = "Select all objects."; +editor.inputs["C-a"].doc = "Select all objects."; -editor.inputs['C-`'] = function() { editor.openpanel(replpanel); } -editor.inputs['C-`'].doc = "Open or close the repl."; +editor.inputs["C-`"] = function () { + editor.openpanel(replpanel); +}; +editor.inputs["C-`"].doc = "Open or close the repl."; -editor.inputs.n = function() { +editor.inputs.n = function () { if (editor.selectlist.length !== 1) return; var o = editor.try_select(); if (!o) return; @@ -691,9 +711,8 @@ editor.inputs.n = function() { tpos.x *= -1; o.set_pos(tpos, o.master); }; -editor.inputs.n.doc = "Set the hovered object's position to mirror the selected object's position on the X axis." -editor.inputs['M-n'] = function() -{ +editor.inputs.n.doc = "Set the hovered object's position to mirror the selected object's position on the X axis."; +editor.inputs["M-n"] = function () { if (editor.selectlist.length !== 1) return; var o = editor.try_select(); if (!o) return; @@ -704,98 +723,118 @@ editor.inputs['M-n'] = function() tpos.y *= -1; o.pos = tpos; }; -editor.inputs.n.doc = "Set the hovered object's position to mirror the selected object's position on the Y axis." +editor.inputs.n.doc = "Set the hovered object's position to mirror the selected object's position on the Y axis."; /* Return if selected component. */ -editor.inputs['h'] = function() { +editor.inputs["h"] = function () { var visible = true; - editor.selectlist.forEach(function(x) { if (x.visible) visible = false; }); - editor.selectlist.forEach(function(x) { x.visible = visible; }); + editor.selectlist.forEach(function (x) { + if (x.visible) visible = false; + }); + editor.selectlist.forEach(function (x) { + x.visible = visible; + }); }; -editor.inputs['h'].doc = "Toggle object hidden."; +editor.inputs["h"].doc = "Toggle object hidden."; -editor.inputs['C-h'] = function() { world.objects.forEach(function(x) { x.visible = true; }); }; -editor.inputs['C-h'].doc = "Unhide all objects."; +editor.inputs["C-h"] = function () { + world.objects.forEach(function (x) { + x.visible = true; + }); +}; +editor.inputs["C-h"].doc = "Unhide all objects."; -editor.inputs['C-e'] = function() { editor.openpanel(assetexplorer); }; -editor.inputs['C-e'].doc = "Open asset explorer."; +editor.inputs["C-e"] = function () { + editor.openpanel(assetexplorer); +}; +editor.inputs["C-e"].doc = "Open asset explorer."; -editor.inputs['C-l'] = function() { editor.openpanel(entitylistpanel); }; -editor.inputs['C-l'].doc = "Open list of spawned entities."; +editor.inputs["C-l"] = function () { + editor.openpanel(entitylistpanel); +}; +editor.inputs["C-l"].doc = "Open list of spawned entities."; -editor.inputs['C-i'] = function() { +editor.inputs["C-i"] = function () { if (editor.selectlist.length !== 1) return; objectexplorer.obj = editor.selectlist[0]; editor.openpanel(objectexplorer); }; -editor.inputs['C-i'].doc = "Open the object explorer for a selected object."; +editor.inputs["C-i"].doc = "Open the object explorer for a selected object."; -editor.inputs['C-d'] = function() { +editor.inputs["C-d"] = function () { if (editor.selectlist.length === 0) return; var duped = editor.dup_objects(editor.selectlist); editor.unselect(); editor.selectlist = duped; }; -editor.inputs['C-d'].doc = "Duplicate all selected objects."; +editor.inputs["C-d"].doc = "Duplicate all selected objects."; -editor.inputs['C-m'] = function() { +editor.inputs["C-m"] = function () { if (editor.sel_comp) { - if ('flipy' in editor.sel_comp) - editor.sel_comp.flipy = !editor.sel_comp.flipy; + if ("flipy" in editor.sel_comp) editor.sel_comp.flipy = !editor.sel_comp.flipy; return; } - - editor.selectlist.forEach(function(x) { x.mirror([0,1]);}); + + editor.selectlist.forEach(function (x) { + x.mirror([0, 1]); + }); }; -editor.inputs['C-m'].doc = "Mirror selected objects on the Y axis."; +editor.inputs["C-m"].doc = "Mirror selected objects on the Y axis."; -editor.inputs.m = function() { +editor.inputs.m = function () { if (editor.sel_comp) { - if ('flipx' in editor.sel_comp) - editor.sel_comp.flipx = !editor.sel_comp.flipx; + if ("flipx" in editor.sel_comp) editor.sel_comp.flipx = !editor.sel_comp.flipx; return; } - editor.selectlist.forEach(obj => obj.grow([-1,1,1])); + editor.selectlist.forEach(obj => obj.grow([-1, 1, 1])); }; editor.inputs.m.doc = "Mirror selected objects on the X axis."; -editor.inputs.q = function() { editor.comp_info = !editor.comp_info; }; +editor.inputs.q = function () { + editor.comp_info = !editor.comp_info; +}; editor.inputs.q.doc = "Toggle help for the selected component."; -editor.inputs.f = function() { +editor.inputs.f = function () { return; if (editor.selectlist.length === 0) return; var bb = editor.selectlist[0].boundingbox(); - editor.selectlist.forEach(function(obj) { bb = bbox.expand(bb, obj.boundingbox()); }); + editor.selectlist.forEach(function (obj) { + bb = bbox.expand(bb, obj.boundingbox()); + }); editor.zoom_to_bb(bb); }; editor.inputs.f.doc = "Find the selected objects."; -editor.inputs['C-f'] = function() { +editor.inputs["C-f"] = function () { if (editor.selectlist.length !== 1) return; editor.edit_level = editor.selectlist[0]; editor.unselect(); - editor.reset_undos(); + editor.reset_undos(); }; -editor.inputs['C-f'].doc = "Tunnel into the selected level object to edit it."; +editor.inputs["C-f"].doc = "Tunnel into the selected level object to edit it."; -editor.inputs['M-f'] = function() { - if (editor.edit_level.master === world) return; +editor.inputs["M-f"] = function () { + if (editor.edit_level.master === world) return; editor.edit_level = editor.edit_level.master; editor.unselect(); editor.reset_undos(); }; -editor.inputs['M-f'].doc = "Tunnel out of the level you are editing, saving it in the process."; -editor.inputs['C-r'] = function() { editor.selectlist.forEach(function(x) { x.rotate(-x.angle*2); }); } -editor.inputs['C-r'].doc = "Negate the selected's angle."; +editor.inputs["M-f"].doc = "Tunnel out of the level you are editing, saving it in the process."; +editor.inputs["C-r"] = function () { + editor.selectlist.forEach(function (x) { + x.rotate(-x.angle * 2); + }); +}; +editor.inputs["C-r"].doc = "Negate the selected's angle."; -editor.inputs.r = function() { - if (editor.sel_comp && 'angle' in editor.sel_comp) { +editor.inputs.r = function () { + if (editor.sel_comp && "angle" in editor.sel_comp) { var relpos = input.mouse.worldpos().sub(editor.sel_comp.gameobject.pos); return; } @@ -803,60 +842,61 @@ editor.inputs.r = function() { editor.rotlist = editor.selectlist; }; editor.inputs.r.doc = "Rotate selected using the mouse while held down."; -editor.inputs.r.released = function() { editor.rotlist = []; } +editor.inputs.r.released = function () { + editor.rotlist = []; +}; -editor.inputs.f5 = function() { editor.start_play_ed(); } +editor.inputs.f5 = function () { + editor.start_play_ed(); +}; editor.inputs.f5.doc = "Start game from 'debug' if it exists; otherwise, from 'game'."; -editor.inputs.f6 = function() { editor.start_play(); } +editor.inputs.f6 = function () { + editor.start_play(); +}; editor.inputs.f6.doc = "Start game as if the player started it."; -editor.inputs['M-p'] = function() { - if (sim.playing()) - sim.pause(); +editor.inputs["M-p"] = function () { + if (sim.playing()) sim.pause(); sim.step(); -} -editor.inputs['M-p'].doc = "Do one time step, pausing if necessary."; +}; +editor.inputs["M-p"].doc = "Do one time step, pausing if necessary."; -editor.inputs['C-M-p'] = function() { +editor.inputs["C-M-p"] = function () { if (!sim.playing()) { editor.start_play_ed(); } console.warn(`Starting edited level ...`); }; -editor.inputs['C-M-p'].doc = "Start game from currently edited level."; +editor.inputs["C-M-p"].doc = "Start game from currently edited level."; -editor.inputs['C-q'] = function() { - -}; -editor.inputs['C-q'].doc = "Quit simulation and return to editor."; +editor.inputs["C-q"] = function () {}; +editor.inputs["C-q"].doc = "Quit simulation and return to editor."; var rebinder = {}; rebinder.inputs = {}; -rebinder.inputs.any = function(cmd) { - -}; +rebinder.inputs.any = function (cmd) {}; -editor.inputs['C-space'] = function() { - -}; -editor.inputs['C-space'].doc = "Search to execute a specific command."; +editor.inputs["C-space"] = function () {}; +editor.inputs["C-space"].doc = "Search to execute a specific command."; -editor.inputs['M-m'] = function() { -// player[0].control(rebinder); +editor.inputs["M-m"] = function () { + // player[0].control(rebinder); }; -editor.inputs['M-m'].doc = "Rebind a shortcut. Usage: M-m SHORTCUT TARGET"; +editor.inputs["M-m"].doc = "Rebind a shortcut. Usage: M-m SHORTCUT TARGET"; -editor.inputs['M-S-8'] = function() { +editor.inputs["M-S-8"] = function () { editor.camera_recall_pop(); }; -editor.inputs['M-S-8'].doc = "Jump to last location."; +editor.inputs["M-S-8"].doc = "Jump to last location."; -editor.inputs.escape = function() { editor.openpanel(quitpanel); } +editor.inputs.escape = function () { + editor.openpanel(quitpanel); +}; editor.inputs.escape.doc = "Quit editor."; -editor.inputs['C-s'] = function() { +editor.inputs["C-s"] = function () { var saveobj = undefined; if (editor.selectlist.length === 0) { if (editor.edit_level === editor.desktop) { @@ -864,10 +904,8 @@ editor.inputs['C-s'] = function() { saveaspanel.obj = editor.edit_level; editor.openpanel(saveaspanel); return; - } else - saveobj = editor.edit_level; - } else if (editor.selectlist.length === 1) - saveobj = editor.selectlist[0]; + } else saveobj = editor.edit_level; + } else if (editor.selectlist.length === 1) saveobj = editor.selectlist[0]; saveobj.check_dirty(); if (!saveobj._ed.dirty) { @@ -882,246 +920,260 @@ editor.inputs['C-s'] = function() { return; } if (!tur.data) { - io.slurpwrite(tur.text.set_ext(".json"), json.encode(savejs,null,1)); + io.slurpwrite(tur.text.set_ext(".json"), json.encode(savejs, null, 1)); tur.data = tur.text.set_ext(".json"); } else { var oldjs = json.decode(io.slurp(tur.data)); Object.merge(oldjs, savejs); - io.slurpwrite(tur.data, json.encode(oldjs,null,1)); + io.slurpwrite(tur.data, json.encode(oldjs, null, 1)); } Object.merge(tur.fresh, savejs); saveobj.check_dirty(); -// Object.values(saveobj.objects).forEach(function(x) { x.check_dirty(); }); + // Object.values(saveobj.objects).forEach(function(x) { x.check_dirty(); }); return; - - game.all_objects(function(x) { - if (typeof x !== 'object') return; - if (!('_ed' in x)) return; + + game.all_objects(function (x) { + if (typeof x !== "object") return; + if (!("_ed" in x)) return; if (x._ed.dirty) return; x.revert(); x.check_dirty(); }); }; -editor.inputs['C-s'].doc = "Save selected."; +editor.inputs["C-s"].doc = "Save selected."; -editor.inputs['C-S'] = function() { +editor.inputs["C-S"] = function () { if (editor.selectlist.length !== 1) return; - if (this.selectlist[0].ur !== 'empty') - saveaspanel.stem = this.selectlist[0].ur + "."; - else - saveaspanel.stem = ""; - + if (this.selectlist[0].ur !== "empty") saveaspanel.stem = this.selectlist[0].ur + "."; + else saveaspanel.stem = ""; + saveaspanel.obj = this.selectlist[0]; editor.openpanel(saveaspanel); }; -editor.inputs['C-S'].doc = "Save selected as."; +editor.inputs["C-S"].doc = "Save selected as."; -editor.inputs['C-z'] = function() { editor.undo(); }; -editor.inputs['C-z'].doc = "Undo the last change made."; +editor.inputs["C-z"] = function () { + editor.undo(); +}; +editor.inputs["C-z"].doc = "Undo the last change made."; -editor.inputs['C-S-z'] = function() { editor.redo(); }; -editor.inputs['C-S-z'].doc = "Redo the last undo."; +editor.inputs["C-S-z"] = function () { + editor.redo(); +}; +editor.inputs["C-S-z"].doc = "Redo the last undo."; -editor.inputs.t = function() { editor.selectlist.forEach(function(x) { x._ed.selectable = false; }); }; +editor.inputs.t = function () { + editor.selectlist.forEach(function (x) { + x._ed.selectable = false; + }); +}; editor.inputs.t.doc = "Lock selected objects to make them non selectable."; -editor.inputs['M-t'] = function() { editor.edit_level.objects.forEach(function(x) { x._ed.selectable = true; }); }; -editor.inputs['M-t'].doc = "Unlock all objects in current level."; +editor.inputs["M-t"] = function () { + editor.edit_level.objects.forEach(function (x) { + x._ed.selectable = true; + }); +}; +editor.inputs["M-t"].doc = "Unlock all objects in current level."; -editor.inputs['C-n'] = editor.new_object; +editor.inputs["C-n"] = editor.new_object; -editor.inputs['C-o'] = function() { +editor.inputs["C-o"] = function () { editor.openpanel(openlevelpanel); }; -editor.inputs['C-o'].doc = "Open a level."; +editor.inputs["C-o"].doc = "Open a level."; -editor.inputs['C-M-o'] = function() { +editor.inputs["C-M-o"] = function () { if (editor.selectlist.length === 1 && editor.selectlist[0].file) { if (editor.edit_level._ed.dirty) return; editor.load(editor.selectlist[0].file); } }; -editor.inputs['C-M-o'].doc = "Revert opened level back to its disk form."; +editor.inputs["C-M-o"].doc = "Revert opened level back to its disk form."; -editor.inputs['C-S-o'] = function() { - if (!editor.edit_level._ed.dirty) - editor.load_prev(); +editor.inputs["C-S-o"] = function () { + if (!editor.edit_level._ed.dirty) editor.load_prev(); }; -editor.inputs['C-S-o'].doc = "Open previous level."; +editor.inputs["C-S-o"].doc = "Open previous level."; -editor.inputs['C-y'] = function() { - texteditor.on_close = function() { editor.edit_level.script = texteditor.value;}; +editor.inputs["C-y"] = function () { + texteditor.on_close = function () { + editor.edit_level.script = texteditor.value; + }; editor.openpanel(texteditor); texteditor.value = ""; texteditor.start(); }; -editor.inputs['C-y'].doc = "Open script editor for the level."; +editor.inputs["C-y"].doc = "Open script editor for the level."; -editor.inputs['C-p'] = function() { +editor.inputs["C-p"] = function () { os.system("prosperon"); -} +}; -editor.inputs['M-y'] = function() { editor.programmode = !editor.programmode; }; -editor.inputs['M-y'].doc = "Toggle program mode."; +editor.inputs["M-y"] = function () { + editor.programmode = !editor.programmode; +}; +editor.inputs["M-y"].doc = "Toggle program mode."; -editor.inputs.minus = function() { +editor.inputs.minus = function () { if (!Object.empty(editor.selectlist)) { - editor.selectlist.forEach(function(x) { x.draw_layer--; }); + editor.selectlist.forEach(function (x) { + x.draw_layer--; + }); return; } - if (editor.working_layer > -1) - editor.working_layer--; + if (editor.working_layer > -1) editor.working_layer--; }; editor.inputs.minus.doc = "Go down one working layer, or, move selected objects down one layer."; -editor.inputs.plus = function() { +editor.inputs.plus = function () { if (!Object.empty(editor.selectlist)) { editor.selectlist.forEach(x => x.draw_layer++); return; } - if (editor.working_layer < 4) - editor.working_layer++; + if (editor.working_layer < 4) editor.working_layer++; }; editor.inputs.plus.doc = "Go up one working layer, or, move selected objects down one layer."; -editor.inputs['C-f1'] = function() { editor.edit_mode = "basic"; }; -editor.inputs['C-f1'].doc = "Enter basic edit mode."; -editor.inputs['C-f2'] = function() { editor.edit_mode = "brush"; }; -editor.inputs['C-f2'].doc = "Enter brush mode."; +editor.inputs["C-f1"] = function () { + editor.edit_mode = "basic"; +}; +editor.inputs["C-f1"].doc = "Enter basic edit mode."; +editor.inputs["C-f2"] = function () { + editor.edit_mode = "brush"; +}; +editor.inputs["C-f2"].doc = "Enter brush mode."; -editor.inputs.f2 = function() { +editor.inputs.f2 = function () { if (this.selectlist.length !== 1) return; objectexplorer.obj = this.selectlist[0]; this.openpanel(objectexplorer); }; editor.inputs.f2.doc = "Open configurations object."; -editor.inputs.f3 = function() { +editor.inputs.f3 = function () { if (this.selectlist.length !== 1) return; this.openpanel(componentexplorer); }; -editor.inputs.lm = function() { editor.sel_start = input.mouse.worldpos(); }; +editor.inputs.lm = function () { + editor.sel_start = input.mouse.worldpos(); +}; editor.inputs.lm.doc = "Selection box."; -editor.inputs.lm.released = function() { - input.mouse.normal(); - editor.unselect(); +editor.inputs.lm.released = function () { + input.mouse.normal(); + editor.unselect(); - if (!editor.sel_start) return; - - if (editor.sel_comp) { - editor.sel_start = undefined; - return; - } + if (!editor.sel_start) return; - var selects = []; - - /* TODO: selects somehow gets undefined objects in here */ - if (Vector.equal(input.mouse.worldpos(), editor.sel_start, 5)) { - var sel = editor.try_select(); - if (sel) selects.push(sel); - } else { - var box = bbox.frompoints([editor.sel_start, input.mouse.worldpos()]); - - physics.box_query(bbox.tocwh(box), function(entity) { - var obj = editor.do_select(entity); - if (obj) selects.push(obj); - }); - } + if (editor.sel_comp) { + editor.sel_start = undefined; + return; + } - this.sel_start = undefined; - selects = selects.flat(); - selects = selects.unique(); - - if (Object.empty(selects)) return; + var selects = []; - if (input.keyboard.down('shift')) { - selects.forEach(function(x) { - this.selectlist.push_unique(x); - }, this); + /* TODO: selects somehow gets undefined objects in here */ + if (Vector.equal(input.mouse.worldpos(), editor.sel_start, 5)) { + var sel = editor.try_select(); + if (sel) selects.push(sel); + } else { + var box = bbox.frompoints([editor.sel_start, input.mouse.worldpos()]); - return; - } - - if (input.keyboard.down('ctrl')) { - selects.forEach(function(x) { - delete this.selectlist[x.toString()]; - }, this); + physics.box_query(bbox.tocwh(box), function (entity) { + var obj = editor.do_select(entity); + if (obj) selects.push(obj); + }); + } - return; - } - - editor.selectlist = []; - selects.forEach(function(x) { - if (x !== undefined) - this.selectlist.push(x); + this.sel_start = undefined; + selects = selects.flat(); + selects = selects.unique(); + + if (Object.empty(selects)) return; + + if (input.keyboard.down("shift")) { + selects.forEach(function (x) { + this.selectlist.push_unique(x); }, this); + + return; + } + + if (input.keyboard.down("ctrl")) { + selects.forEach(function (x) { + delete this.selectlist[x.toString()]; + }, this); + + return; + } + + editor.selectlist = []; + selects.forEach(function (x) { + if (x !== undefined) this.selectlist.push(x); + }, this); }; -editor.inputs.rm = function() { - if (editor.brush_obj) - editor.brush_obj = undefined; - - if (editor.sel_comp) { - editor.sel_comp = undefined; - return; - } - - editor.unselect(); +editor.inputs.rm = function () { + if (editor.brush_obj) editor.brush_obj = undefined; + + if (editor.sel_comp) { + editor.sel_comp = undefined; + return; + } + + editor.unselect(); }; -editor.try_pick = function() -{ +editor.try_pick = function () { editor.grabselect = []; - if (editor.sel_comp && 'pick' in editor.sel_comp) - return editor.sel_comp.pick(input.mouse.worldpos()); + if (editor.sel_comp && "pick" in editor.sel_comp) return editor.sel_comp.pick(input.mouse.worldpos()); return editor.try_select(); -} +}; -editor.inputs.mm = function() { - if (editor.brush_obj) { - editor.selectlist = editor.dup_objects([editor.brush_obj]); - editor.selectlist[0].pos = input.mouse.worldpos(); - editor.grabselect = editor.selectlist[0]; - return; - } +editor.inputs.mm = function () { + if (editor.brush_obj) { + editor.selectlist = editor.dup_objects([editor.brush_obj]); + editor.selectlist[0].pos = input.mouse.worldpos(); + editor.grabselect = editor.selectlist[0]; + return; + } var o = editor.try_pick(); if (!o) return; -// editor.selectlist = [o]; + // editor.selectlist = [o]; editor.grabselect = [o]; }; -editor.inputs['C-mm'] = editor.inputs.mm; +editor.inputs["C-mm"] = editor.inputs.mm; -editor.inputs['C-M-lm'] = function() -{ +editor.inputs["C-M-lm"] = function () { var go = physics.pos_query(input.mouse.worldpos()); if (!go) return; editor.edit_level = go.master; -} +}; -editor.inputs['C-M-mm'] = function() { +editor.inputs["C-M-mm"] = function () { editor.mousejoy = input.mouse.screenpos(); editor.joystart = editor.camera.pos; }; -editor.inputs['C-M-rm'] = function() { +editor.inputs["C-M-rm"] = function () { editor.mousejoy = input.mouse.screenpos(); editor.z_start = editor.camera.zoom; input.mouse.disabled(); }; -editor.inputs.rm.released = function() { +editor.inputs.rm.released = function () { editor.mousejoy = undefined; editor.z_start = undefined; input.mouse.normal(); @@ -1134,208 +1186,225 @@ editor.inputs.mm.released = function () { editor.joystart = undefined; }; editor.inputs.mouse = {}; -editor.inputs.mouse.move = function(pos, dpos) -{ +editor.inputs.mouse.move = function (pos, dpos) { if (editor.mousejoy) { - if (editor.z_start) - editor.camera.zoom -= dpos.y/500; - else if (editor.joystart) - editor.camera.pos = editor.camera.pos.sub(game.camera.dir_view2world(dpos)); + if (editor.z_start) editor.camera.zoom -= dpos.y / 500; + else if (editor.joystart) editor.camera.pos = editor.camera.pos.sub(game.camera.dir_view2world(dpos)); } - editor.grabselect?.forEach(function(x) { + editor.grabselect?.forEach(function (x) { x.move(game.camera.dir_view2world(dpos)); x.sync(); }); - + var relpos = input.mouse.worldpos().sub(editor.cursor); var lastpos = relpos.sub(dpos); - + var dist = Vector.length(relpos.add(dpos)) - Vector.length(relpos); - var scalediff = 1+(dist/editor.scaleoffset); - - editor.scalelist?.forEach(function(x) { x.grow(scalediff); }); + var scalediff = 1 + dist / editor.scaleoffset; + + editor.scalelist?.forEach(function (x) { + x.grow(scalediff); + }); var anglediff = Math.atan2(relpos.y, relpos.x) - Math.atan2(lastpos.y, lastpos.x); - editor.rotlist?.forEach(function(x) { - x.rotate(anglediff/(2*Math.PI)); - if (input.keyboard.down('shift')) { - var rotate = Math.nearest(x.angle, 1/24) - x.angle; - x.rotate(rotate) + editor.rotlist?.forEach(function (x) { + x.rotate(anglediff / (2 * Math.PI)); + if (input.keyboard.down("shift")) { + var rotate = Math.nearest(x.angle, 1 / 24) - x.angle; + x.rotate(rotate); } }); -} +}; -editor.inputs.mouse.scroll = function(scroll) -{ +editor.inputs.mouse.scroll = function (scroll) { scroll.y *= -1; editor.camera.move(game.camera.dir_view2world(scroll.scale(-3))); -} +}; -editor.inputs.mouse['C-scroll'] = function(scroll) -{ - editor.camera.zoom += scroll.y/100; -} +editor.inputs.mouse["C-scroll"] = function (scroll) { + editor.camera.zoom += scroll.y / 100; +}; -editor.inputs['C-M-S-lm'] = function() { editor.selectlist[0].set_center(input.mouse.worldpos()); }; -editor.inputs['C-M-S-lm'].doc = "Set world center to mouse position."; +editor.inputs["C-M-S-lm"] = function () { + editor.selectlist[0].set_center(input.mouse.worldpos()); +}; +editor.inputs["C-M-S-lm"].doc = "Set world center to mouse position."; -editor.inputs.delete = function() { +editor.inputs.delete = function () { this.selectlist.forEach(x => x.kill()); this.unselect(); }; editor.inputs.delete.doc = "Delete selected objects."; -editor.inputs['S-d'] = editor.inputs.delete; -editor.inputs['C-k'] = editor.inputs.delete; +editor.inputs["S-d"] = editor.inputs.delete; +editor.inputs["C-k"] = editor.inputs.delete; -editor.inputs['C-u'] = function() { this.selectlist.forEach(x => x.revert()); }; -editor.inputs['C-u'].doc = "Revert selected objects back to their prefab form."; +editor.inputs["C-u"] = function () { + this.selectlist.forEach(x => x.revert()); +}; +editor.inputs["C-u"].doc = "Revert selected objects back to their prefab form."; -editor.inputs['M-u'] = function() { - this.selectlist.forEach(function(x) { +editor.inputs["M-u"] = function () { + this.selectlist.forEach(function (x) { x.unique = true; }); }; -editor.inputs['M-u'].doc = "Make selected objects unique."; +editor.inputs["M-u"].doc = "Make selected objects unique."; -editor.inputs['C-S-g'] = function() { editor.openpanel(groupsaveaspanel); }; -editor.inputs['C-S-g'].doc = "Save selected objects as a new level."; +editor.inputs["C-S-g"] = function () { + editor.openpanel(groupsaveaspanel); +}; +editor.inputs["C-S-g"].doc = "Save selected objects as a new level."; -editor.inputs.g = function() { +editor.inputs.g = function () { if (editor.selectlist.length === 0) { var o = editor.try_pick(); if (!o) return; editor.selectlist = [o]; } - + if (editor.sel_comp) { - if ('pick' in editor.sel_comp) { + if ("pick" in editor.sel_comp) { editor.grabselect = [editor.sel_comp.pick(input.mouse.worldpos())]; return; } - if ('pos' in editor.sel_comp) { + if ("pos" in editor.sel_comp) { var comp = editor.sel_comp; var o = { pos: editor.sel_comp.pos, - move(d) { comp.pos = comp.pos.add(comp.gameobject.dir_world2this(d)); }, - sync: comp.sync.bind(comp), + move(d) { + comp.pos = comp.pos.add(comp.gameobject.dir_world2this(d)); + }, + sync: comp.sync.bind(comp), }; editor.grabselect = [o]; return; } } - if (editor.sel_comp && 'pick' in editor.sel_comp) { + if (editor.sel_comp && "pick" in editor.sel_comp) { var o = editor.sel_comp.pick(input.mouse.worldpos()); if (o) editor.grabselect = [o]; return; } - + editor.grabselect = editor.selectlist.slice(); }; editor.inputs.g.doc = "Move selected objects."; -editor.inputs.g.released = function() { editor.grabselect = []; input.mouse.normal(); }; +editor.inputs.g.released = function () { + editor.grabselect = []; + input.mouse.normal(); +}; -editor.inputs.up = function() { this.key_move([0,1]); }; +editor.inputs.up = function () { + this.key_move([0, 1]); +}; editor.inputs.up.rep = true; -editor.inputs.left = function() { this.key_move([-1,0]); }; +editor.inputs.left = function () { + this.key_move([-1, 0]); +}; editor.inputs.left.rep = true; -editor.inputs.right = function() { this.key_move([1,0]); }; +editor.inputs.right = function () { + this.key_move([1, 0]); +}; editor.inputs.right.rep = true; -editor.inputs.down = function() { this.key_move([0,-1]); }; +editor.inputs.down = function () { + this.key_move([0, -1]); +}; editor.inputs.down.rep = true; -editor.inputs.tab = function() { +editor.inputs.tab = function () { if (!(this.selectlist.length === 1)) return; if (!this.selectlist[0].components) return; var sel = this.selectlist[0].components; - if (!this.sel_comp) - this.sel_comp = sel.nth(0); + if (!this.sel_comp) this.sel_comp = sel.nth(0); else { var idx = sel.findIndex(this.sel_comp) + 1; - if (idx >= Object.keys(sel).length) - this.sel_comp = undefined; - else - this.sel_comp = sel.nth(idx); + if (idx >= Object.keys(sel).length) this.sel_comp = undefined; + else this.sel_comp = sel.nth(idx); } }; editor.inputs.tab.doc = "Cycle through selected object's components."; -editor.inputs['C-g'] = function() { +editor.inputs["C-g"] = function () { if (!this.selectlist) return; this.selectlist = this.dup_objects(this.selectlist); editor.inputs.g(); }; -editor.inputs['C-g'].doc = "Duplicate selected objects, then move them."; +editor.inputs["C-g"].doc = "Duplicate selected objects, then move them."; -editor.inputs['M-g'] = function() -{ - if (this.sel_comp && 'pick_all' in this.sel_comp) - this.grabselect = this.sel_comp.pick_all(); -} -editor.inputs['M-g'].doc = "Move all."; +editor.inputs["M-g"] = function () { + if (this.sel_comp && "pick_all" in this.sel_comp) this.grabselect = this.sel_comp.pick_all(); +}; +editor.inputs["M-g"].doc = "Move all."; -editor.inputs['C-lb'] = function() { - editor.grid_size -= input.keyboard.down('shift') ? 10 : 1; +editor.inputs["C-lb"] = function () { + editor.grid_size -= input.keyboard.down("shift") ? 10 : 1; if (editor.grid_size <= 0) editor.grid_size = 1; }; -editor.inputs['C-lb'].doc = "Decrease grid size. Hold shift to decrease it more."; -editor.inputs['C-lb'].rep = true; +editor.inputs["C-lb"].doc = "Decrease grid size. Hold shift to decrease it more."; +editor.inputs["C-lb"].rep = true; -editor.inputs['C-rb'] = function() { editor.grid_size += input.keyboard.down('shift') ? 10 : 1; }; -editor.inputs['C-rb'].doc = "Increase grid size. Hold shift to increase it more."; -editor.inputs['C-rb'].rep = true; +editor.inputs["C-rb"] = function () { + editor.grid_size += input.keyboard.down("shift") ? 10 : 1; +}; +editor.inputs["C-rb"].doc = "Increase grid size. Hold shift to increase it more."; +editor.inputs["C-rb"].rep = true; -editor.inputs['C-c'] = function() { +editor.inputs["C-c"] = function () { this.killring = []; this.killcom = []; - this.killcom = physics.com(this.selectlist.map(x=>x.pos)); + this.killcom = physics.com(this.selectlist.map(x => x.pos)); - this.selectlist.forEach(function(x) { + this.selectlist.forEach(function (x) { this.killring.push(x.instance_obj()); - },this); + }, this); }; -editor.inputs['C-c'].doc = "Copy selected objects to killring."; +editor.inputs["C-c"].doc = "Copy selected objects to killring."; -editor.inputs['C-x'] = function() { - editor.inputs['C-c'].call(editor); - this.selectlist.forEach(function(x) { x.kill(); }); +editor.inputs["C-x"] = function () { + editor.inputs["C-c"].call(editor); + this.selectlist.forEach(function (x) { + x.kill(); + }); editor.unselect(); }; -editor.inputs['C-x'].doc = "Cut objects to killring."; +editor.inputs["C-x"].doc = "Cut objects to killring."; -editor.inputs['C-v'] = function() { - this.unselect(); - this.killring.forEach(function(x) { - editor.selectlist.push(editor.edit_level.spawn(x)); - }); +editor.inputs["C-v"] = function () { + this.unselect(); + this.killring.forEach(function (x) { + editor.selectlist.push(editor.edit_level.spawn(x)); + }); - this.selectlist.forEach(function(x) { - x.pos = x.pos.sub(this.killcom).add(this.cursor); - },this); + this.selectlist.forEach(function (x) { + x.pos = x.pos.sub(this.killcom).add(this.cursor); + }, this); }; -editor.inputs['C-v'].doc = "Pull objects from killring to world."; +editor.inputs["C-v"].doc = "Pull objects from killring to world."; -editor.inputs.char = function(c) { - if (c === '0') { - this.camera.pos = [0,0]; +editor.inputs.char = function (c) { + if (c === "0") { + this.camera.pos = [0, 0]; this.camera.zoom = 1; } }; var brushmode = {}; brushmode.inputs = {}; -brushmode.inputs.lm = function() { editor.inputs['C-v'].call(editor); }; +brushmode.inputs.lm = function () { + editor.inputs["C-v"].call(editor); +}; brushmode.inputs.lm.doc = "Paste selected brush."; -brushmode.inputs.b = function() { +brushmode.inputs.b = function () { if (editor.brush_obj) { editor.brush_obj = undefined; return; @@ -1349,16 +1418,16 @@ brushmode.inputs.b.doc = "Clear brush, or set a new one."; var compmode = {}; compmode.inputs = {}; -compmode.inputs['C-c'] = function() {}; /* Simply a blocker */ -compmode.inputs['C-x'] = function() {}; +compmode.inputs["C-c"] = function () {}; /* Simply a blocker */ +compmode.inputs["C-x"] = function () {}; editor.scalelist = []; -editor.inputs.s = function() { +editor.inputs.s = function () { editor.scaleoffset = Vector.length(input.mouse.worldpos().sub(editor.cursor)); editor.scalelist = []; - + if (editor.sel_comp) { - if (!('scale' in editor.sel_comp)) return; + if (!("scale" in editor.sel_comp)) return; editor.scalelist.push(editor.sel_comp); return; } @@ -1367,27 +1436,39 @@ editor.inputs.s = function() { }; editor.inputs.s.doc = "Scale selected."; -editor.inputs.s.released = function() { this.scalelist = []; }; +editor.inputs.s.released = function () { + this.scalelist = []; +}; var replpanel = Object.copy(inputpanel, { title: "", - closeonsubmit:false, - wh: [700,300], - pos: [50,50], - anchor: [0,1], - padding: [0,0], - scrolloffset: [0,0], + closeonsubmit: false, + wh: [700, 300], + pos: [50, 50], + anchor: [0, 1], + padding: [0, 0], + scrolloffset: [0, 0], guibody() { this.win.selectable = true; var log = console.transcript; return [ - Mum.text({str:log, anchor:[0,0], offset:[0,-300].sub(this.scrolloffset), selectable: true}), - Mum.text({str:this.value,color:Color.green, offset:[0,-290], caret: this.caret}) + Mum.text({ + str: log, + anchor: [0, 0], + offset: [0, -300].sub(this.scrolloffset), + selectable: true, + }), + Mum.text({ + str: this.value, + color: Color.green, + offset: [0, -290], + caret: this.caret, + }), ]; }, - prevmark:-1, - prevthis:[], + prevmark: -1, + prevthis: [], action() { if (!this.value) return; @@ -1396,155 +1477,135 @@ var replpanel = Object.copy(inputpanel, { var ecode = ""; var repl_obj = editor.get_this(); ecode += `var $ = repl_obj.objects;`; - for (var key in repl_obj.objects) - ecode += `var ${key} = editor.edit_level.objects['${key}'];`; - + for (var key in repl_obj.objects) ecode += `var ${key} = editor.edit_level.objects['${key}'];`; + ecode += this.value; say(this.value); this.value = ""; this.caret = 0; - var ret = function() {return eval(ecode);}.call(repl_obj); - if (typeof ret === 'object') ret = json.encode(ret,null,1); - if (typeof ret !== 'undefined') say(ret); + var ret = function () { + return eval(ecode); + }.call(repl_obj); + if (typeof ret === "object") ret = json.encode(ret, null, 1); + if (typeof ret !== "undefined") say(ret); }, resetscroll() { - this.scrolloffset.y = 0; + this.scrolloffset.y = 0; }, }); replpanel.inputs = Object.create(inputpanel.inputs); replpanel.inputs.block = true; -replpanel.inputs.lm = function() -{ +replpanel.inputs.lm = function () { var mg = physics.pos_query(input.mouse.worldpos()); if (!mg) return; var p = mg.path_from(editor.get_this()); this.value = p; this.caret = this.value.length; -} -replpanel.inputs.tab = function() { +}; +replpanel.inputs.tab = function () { this.resetscroll(); if (!this.value) return; var obj = globalThis; var keys = []; - var keyobj = this.value.tolast('.'); - var o = this.value.tolast('.'); - var stub = this.value.fromlast('.'); - var replobj = (editor.selectlist.length === 1) ? "editor.selectlist[0]" : "editor.edit_level"; - - if (this.value.startsWith("this.")) - keyobj = keyobj.replace("this", replobj); + var keyobj = this.value.tolast("."); + var o = this.value.tolast("."); + var stub = this.value.fromlast("."); + var replobj = editor.selectlist.length === 1 ? "editor.selectlist[0]" : "editor.edit_level"; - if (!this.value.includes('.')) keys.push("this"); + if (this.value.startsWith("this.")) keyobj = keyobj.replace("this", replobj); - if (eval(`typeof ${keyobj.tofirst('.')}`) === 'object' && eval(`typeof ${keyobj.replace('.', '?.')}`) === 'object') - obj = eval(keyobj); - else if (this.value.includes('.')){ + if (!this.value.includes(".")) keys.push("this"); + + if (eval(`typeof ${keyobj.tofirst(".")}`) === "object" && eval(`typeof ${keyobj.replace(".", "?.")}`) === "object") obj = eval(keyobj); + else if (this.value.includes(".")) { say(`${this.value} is not an object.`); return; - } - - for (var k in obj) - keys.push(k) + } - for (var k in editor.get_this()) - keys.push(k); + for (var k in obj) keys.push(k); + + for (var k in editor.get_this()) keys.push(k); var comp = ""; - if (stub) - comp = input.tabcomplete(stub, keys); - else if (!this.value.includes('.')) - comp = input.tabcomplete(o, keys); - else - comp = input.tabcomplete("",keys); - - if (stub) - this.value = o + '.' + comp; - else if (this.value.endsWith('.')) - this.value = o + '.' + comp; - else - this.value = comp; + if (stub) comp = input.tabcomplete(stub, keys); + else if (!this.value.includes(".")) comp = input.tabcomplete(o, keys); + else comp = input.tabcomplete("", keys); + + if (stub) this.value = o + "." + comp; + else if (this.value.endsWith(".")) this.value = o + "." + comp; + else this.value = comp; this.caret = this.value.length; keys = keys.sort(); - keys = keys.map(function(x) { - if (typeof obj[x] === 'function') - return esc.color(Color.Apple.orange) + x + esc.reset; - if (Object.isObject(obj[x])) - return esc.color(Color.Apple.purple) + x + esc.reset; - if (Array.isArray(obj[x])) - return esc.color(Color.Apple.green) + x + esc.reset; + keys = keys.map(function (x) { + if (typeof obj[x] === "function") return esc.color(Color.Apple.orange) + x + esc.reset; + if (Object.isObject(obj[x])) return esc.color(Color.Apple.purple) + x + esc.reset; + if (Array.isArray(obj[x])) return esc.color(Color.Apple.green) + x + esc.reset; return x; }); - if (keys.length > 1) - say(keys.join(', ')); + if (keys.length > 1) say(keys.join(", ")); }; -replpanel.inputs['C-p'] = function() -{ +replpanel.inputs["C-p"] = function () { if (this.prevmark >= this.prevthis.length) return; this.prevmark++; this.value = this.prevthis[this.prevmark]; - this.inputs['C-e'].call(this); -} + this.inputs["C-e"].call(this); +}; -replpanel.inputs['C-n'] = function() -{ +replpanel.inputs["C-n"] = function () { this.prevmark--; if (this.prevmark < 0) { this.prevmark = -1; this.value = ""; - } else - this.value = this.prevthis[this.prevmark]; + } else this.value = this.prevthis[this.prevmark]; - this.inputs['C-e'].call(this); -} + this.inputs["C-e"].call(this); +}; replpanel.inputs.mouse = {}; -replpanel.inputs.mouse.scroll = function(scroll) -{ +replpanel.inputs.mouse.scroll = function (scroll) { if (!this.win.selected) return; this.scrolloffset.y += scroll.y; if (this.scrolloffset.y < 0) this.scrolloffset.y = 0; -} +}; -replpanel.inputs.mm = function() { this.mm = true; }; -replpanel.inputs.mm.released = function() { this.mm = false; }; +replpanel.inputs.mm = function () { + this.mm = true; +}; +replpanel.inputs.mm.released = function () { + this.mm = false; +}; -replpanel.inputs.mouse.move = function(pos,dpos) -{ - if (this.mm) - this.scrolloffset.y -= dpos.y; -} +replpanel.inputs.mouse.move = function (pos, dpos) { + if (this.mm) this.scrolloffset.y -= dpos.y; +}; -replpanel.inputs.up = function() -{ +replpanel.inputs.up = function () { this.scrolloffset.y += 40; -} +}; replpanel.inputs.up.rep = true; -replpanel.inputs.down = function() -{ +replpanel.inputs.down = function () { this.scrolloffset.y -= 40; - if (this.scrolloffset.y < 0) this.scrolloffset.y = 0; -} + if (this.scrolloffset.y < 0) this.scrolloffset.y = 0; +}; replpanel.inputs.down.rep = true; -replpanel.inputs.pgup = function() -{ +replpanel.inputs.pgup = function () { this.scrolloffset.y += 300; -} +}; replpanel.inputs.pgup.rep = true; -replpanel.inputs.pgdown = function() -{ +replpanel.inputs.pgdown = function () { this.scrolloffset.y -= 300; - if (this.scrolloffset.y < 0) this.scrolloffset.y = 0; -} + if (this.scrolloffset.y < 0) this.scrolloffset.y = 0; +}; replpanel.inputs.pgdown.rep = true; var objectexplorer = Object.copy(inputpanel, { @@ -1567,10 +1628,10 @@ var objectexplorer = Object.copy(inputpanel, { guibody() { var items = []; - items.push(Mum.text({str:"Examining " + this.obj.toString() + " entity"})); - items.push(Mum.text({str: JSON.stringify(this.obj,undefined,1)})); + items.push(Mum.text({ str: "Examining " + this.obj.toString() + " entity" })); + items.push(Mum.text({ str: JSON.stringify(this.obj, undefined, 1) })); return items; - + var n = 0; var curobj = this.obj; while (curobj) { @@ -1581,12 +1642,17 @@ var objectexplorer = Object.copy(inputpanel, { n--; curobj = this.obj.__proto__; while (curobj) { - items.push(Mum.text({str:curobj.toString(), action:this.goto_obj(curobj)})); + items.push(Mum.text({ str: curobj.toString(), action: this.goto_obj(curobj) })); curobj = curobj.__proto__; } if (!Object.empty(this.previous)) - items.push(Mum.text({str:"prev: " + this.previous.last(), action: this.prev_obj})); + items.push( + Mum.text({ + str: "prev: " + this.previous.last(), + action: this.prev_obj, + }), + ); Object.getOwnPropertyNames(this.obj).forEach(key => { var descriptor = Object.getOwnPropertyDescriptor(this.obj, key); @@ -1597,55 +1663,60 @@ var objectexplorer = Object.copy(inputpanel, { if (!descriptor.configurable) return; if (hidden) return; - + var name = (hidden ? "[hidden] " : "") + key; var val = this.obj[key]; switch (typeof val) { - case 'object': + case "object": if (val) { - items.push(Mum.text({str:name})); - items.push(Mum.text({str:val.toString(), action: this.goto_obj.bind(val)})); - } - break; + items.push(Mum.text({ str: name })); + items.push( + Mum.text({ + str: val.toString(), + action: this.goto_obj.bind(val), + }), + ); + } + break; - case 'function': - items.push(Mum.text({str:name})); - items.push(Mum.text({str:"function"})); - break; + case "function": + items.push(Mum.text({ str: name })); + items.push(Mum.text({ str: "function" })); + break; - default: - items.push(Mum.text({str:name})); - items.push(Mum.text({str:val.toString()})); - break; + default: + items.push(Mum.text({ str: name })); + items.push(Mum.text({ str: val.toString() })); + break; } }); - items.push(Mum.text({str:"Properties that can be pulled in ..."})); + items.push(Mum.text({ str: "Properties that can be pulled in ..." })); var pullprops = []; for (var key in this.obj.__proto__) { if (!this.obj.hasOwn(key)) { - if (typeof this.obj[key] === 'object' || typeof this.obj[key] === 'function') continue; - pullprops.push(key); + if (typeof this.obj[key] === "object" || typeof this.obj[key] === "function") continue; + pullprops.push(key); } } pullprops = pullprops.sort(); - pullprops.forEach(function(key) { - items.push(Mum.text({str:key})); + pullprops.forEach(function (key) { + items.push(Mum.text({ str: key })); }); return items; }, }); -var openlevelpanel = Object.copy(inputpanel, { +var openlevelpanel = Object.copy(inputpanel, { title: "open entity", action() { editor.load(this.value); }, - + assets: [], allassets: [], @@ -1662,7 +1733,7 @@ var openlevelpanel = Object.copy(inputpanel, { this.allassets = ur._list.sort(); this.assets = this.allassets.slice(); this.caret = 0; - var click_ur = function(btn) { + var click_ur = function (btn) { this.value = btn.str; this.keycb(); this.submit(); @@ -1670,27 +1741,30 @@ var openlevelpanel = Object.copy(inputpanel, { click_ur = click_ur.bind(this); this.mumlist = []; - this.assets.forEach(function(x) { - this.mumlist[x] = Mum.text({str:x, action:click_ur, color: Color.blue, hovered: {color:Color.red}, selectable:true}); + this.assets.forEach(function (x) { + this.mumlist[x] = Mum.text({ + str: x, + action: click_ur, + color: Color.blue, + hovered: { color: Color.red }, + selectable: true, + }); }, this); }, keycb() { - if(this.value) - this.assets = this.allassets.filter(x => x.startsWith(this.value)); - else - this.assets = this.allassets.slice(); - for (var m in this.mumlist) - this.mumlist[m].hide = true; - this.assets.forEach(function(x) { - this.mumlist[x].hide = false; + if (this.value) this.assets = this.allassets.filter(x => x.startsWith(this.value)); + else this.assets = this.allassets.slice(); + for (var m in this.mumlist) this.mumlist[m].hide = true; + this.assets.forEach(function (x) { + this.mumlist[x].hide = false; }, this); }, - + guibody() { - var a = [Mum.text({str:this.value,color:Color.green, caret:this.caret})]; + var a = [Mum.text({ str: this.value, color: Color.green, caret: this.caret })]; var b = a.concat(Object.values(this.mumlist)); - return Mum.column({items:b, offset:[0,-10]}); + return Mum.column({ items: b, offset: [0, -10] }); }, }); @@ -1710,15 +1784,19 @@ var saveaspanel = Object.copy(inputpanel, { var groupsaveaspanel = Object.copy(inputpanel, { title: "group save as", - action() { editor.groupsaveas(editor.selectlist, this.value); } + action() { + editor.groupsaveas(editor.selectlist, this.value); + }, }); var quitpanel = Object.copy(inputpanel, { title: "really quit?", - action() { os.quit(); }, - - guibody () { - return Mum.text({str: "Really quit?"}); + action() { + os.quit(); + }, + + guibody() { + return Mum.text({ str: "Really quit?" }); }, }); @@ -1730,24 +1808,30 @@ var assetexplorer = Object.copy(openlevelpanel, { title: "asset explorer", extensions: allfiles, closeonsubmit: false, - allassets:[], + allassets: [], action() { - if (editor.sel_comp && 'asset' in editor.sel_comp) - editor.sel_comp.asset = this.value; - else - editor.viewasset(this.value); + if (editor.sel_comp && "asset" in editor.sel_comp) editor.sel_comp.asset = this.value; + else editor.viewasset(this.value); }, }); var componentexplorer = Object.copy(inputpanel, { title: "component menu", - assets: ['sprite', 'model', 'edge2d', 'polygon2d', 'circle2d'], + assets: ["sprite", "model", "edge2d", "polygon2d", "circle2d"], click(name) { if (editor.selectlist.length !== 1) return; editor.selectlist[0].add_component(component[name]); }, guibody() { - return componentexplorer.assets.map(x => Mum.text({str:x, action:this.click, color: Color.blue, hovered:{Color:Color.red}, selectable:true})); + return componentexplorer.assets.map(x => + Mum.text({ + str: x, + action: this.click, + color: Color.blue, + hovered: { Color: Color.red }, + selectable: true, + }), + ); }, }); @@ -1763,28 +1847,23 @@ var limited_editor = {}; limited_editor.inputs = {}; -limited_editor.inputs['C-p'] = function() -{ - if (sim.playing()) - sim.pause(); - else - sim.play(); -} +limited_editor.inputs["C-p"] = function () { + if (sim.playing()) sim.pause(); + else sim.play(); +}; -limited_editor.inputs['M-p'] = function() -{ +limited_editor.inputs["M-p"] = function () { sim.pause(); sim.step(); -} +}; -limited_editor.inputs['C-q'] = function() -{ +limited_editor.inputs["C-q"] = function () { world.clear(); global.mixin("editorconfig.js"); global.mixin("dbgret.js"); - + editor.enter_editor(); -} +}; /* This is used for editing during a paused game */ var limited_editing = {}; @@ -1796,5 +1875,5 @@ window.editor = true; debug.draw_phys = true; return { - editor -} + editor, +}; diff --git a/scripts/engine.js b/scripts/engine.js index 11a8c20b..c1bd80dd 100644 --- a/scripts/engine.js +++ b/scripts/engine.js @@ -4,8 +4,10 @@ os.mem_limit.doc = "Set the memory limit of the runtime in bytes."; os.gc_threshold.doc = "Set the threshold before a GC pass is triggered in bytes. This is set to malloc_size + malloc_size>>1 after a GC pass."; os.max_stacksize.doc = "Set the max stack size in bytes."; -Object.defineProperty(String.prototype, 'rm', { - value: function(index, endidx = index+1) { return this.slice(0,index) + this.slice(endidx); } +Object.defineProperty(String.prototype, "rm", { + value: function (index, endidx = index + 1) { + return this.slice(0, index) + this.slice(endidx); + }, }); Object.defineProperty(String.prototype, "tolast", { @@ -33,23 +35,22 @@ Object.defineProperty(String.prototype, "folder", { globalThis.Resources = {}; -Resources.rm_fn = function rm_fn(fn, text) -{ +Resources.rm_fn = function rm_fn(fn, text) { var reg = new RegExp(fn.source + "\\s*\\("); var match; - while (match = text.match(reg)) { - var last = match.index+match[0].length; + while ((match = text.match(reg))) { + var last = match.index + match[0].length; var par = 1; while (par !== 0) { - if (text[last] === '(') par++; - if (text[last] === ')') par--; + if (text[last] === "(") par++; + if (text[last] === ")") par--; last++; } text = text.rm(match.index, last); } return text; -} +}; Resources.rm_fn.doc = "Remove calls to a given function from a given text script."; Resources.replpath = function replpath(str, path) { @@ -76,17 +77,15 @@ Resources.replstrs = function replstrs(path) { var stem = path.dir(); - if (!console.enabled) - script = Resources.rm_fn(/console\.(spam|info|warn|error)/, script); - - if (!profile.enabled) - script = Resources.rm_fn(/profile\.(cache|frame|endcache|endframe)/, script); - + if (!console.enabled) script = Resources.rm_fn(/console\.(spam|info|warn|error)/, script); + + if (!profile.enabled) script = Resources.rm_fn(/profile\.(cache|frame|endcache|endframe)/, script); + if (!debug.enabled) { script = Resources.rm_fn(/assert/, script); script = Resources.rm_fn(/debug\.(build|fn_break)/, script); } - + script = script.replace(regexp, function (str) { var newstr = Resources.replpath(str.trimchr('"'), path); return `"${newstr}"`; @@ -95,23 +94,21 @@ Resources.replstrs = function replstrs(path) { return script; }; -Resources.is_sound = function(path) { +Resources.is_sound = function (path) { var ext = path.ext(); return Resources.sounds.any(x => x === ext); -} +}; + +Resources.is_animation = function (path) { + if (path.ext() === "gif" && Resources.gif.frames(path) > 1) return true; + if (path.ext() === "ase") return true; -Resources.is_animation = function(path) -{ - if (path.ext() === 'gif' && Resources.gif.frames(path) > 1) return true; - if (path.ext() === 'ase') return true; - return false; -} +}; -Resources.is_path = function(str) -{ +Resources.is_path = function (str) { return !/[\\\/:*?"<>|]/.test(str); -} +}; globalThis.json = {}; json.encode = function (value, replacer, space = 1) { @@ -154,16 +151,14 @@ function find_ext(file, ext, root = "") { if (ext.some(x => x === file_ext)) return file; for (var e of ext) { var nf = `${file}.${e}`; - if (io.exists(nf)) - return nf; + if (io.exists(nf)) return nf; } var all_files = io.glob(`**/${file}.*`); var find = undefined; for (var e of ext) { var finds = all_files.filter(x => x.ext() === e); - if (finds.length > 1) - console.warn(`Found conflicting files when searching for '${file}': ${json.encode(finds)}. Returning the first one.`); + if (finds.length > 1) console.warn(`Found conflicting files when searching for '${file}': ${json.encode(finds)}. Returning the first one.`); if (finds.length > 0) { find = finds[0]; break; @@ -176,18 +171,17 @@ function find_ext(file, ext, root = "") { var hashhit = 0; var hashmiss = 0; -Object.defineProperty(Function.prototype, 'hashify', { - value: function() { +Object.defineProperty(Function.prototype, "hashify", { + value: function () { var hash = new Map(); var fn = this; function ret() { - if (!hash.has(arguments[0])) - hash.set(arguments[0], fn(...arguments)); + if (!hash.has(arguments[0])) hash.set(arguments[0], fn(...arguments)); return hash.get(arguments[0]); } return ret; - } + }, }); Resources.find_image = function (file, root = "") { @@ -258,7 +252,7 @@ console.stackstr = function (skip = 0) { }; console.stack = function (skip = 0) { - var stack = console.stackstr(skip+1); + var stack = console.stackstr(skip + 1); console.log(stack); return stack; }; @@ -301,9 +295,9 @@ globalThis.use = function use(file) { profile.endcache(); return ret; -} +}; -function stripped_use (file, script) { +function stripped_use(file, script) { file = Resources.find_script(file); if (use_cache[file]) { @@ -316,12 +310,11 @@ function stripped_use (file, script) { var fn = os.eval(file, script); var ret = fn(); profile.endcache(); - + return ret; } -function bare_use(file) -{ +function bare_use(file) { var script = io.slurp(file); if (!script) return; script = `(function() { var self = this; ${script}; })`; @@ -337,17 +330,15 @@ debug.enabled = true; bare_use("scripts/base.js"); bare_use("scripts/profile.js"); -prosperon.release = function() -{ +prosperon.release = function () { profile.enabled = false; console.enabled = false; debug.enabled = false; -} +}; bare_use("preconfig.js"); -if (!profile.enabled) - use = stripped_use; +if (!profile.enabled) use = stripped_use; Object.assign(globalThis, use("scripts/prosperon.js")); @@ -359,4 +350,3 @@ app.interval(_ => { repl.hotreload(); profile.endframe(); }, 1); - diff --git a/scripts/entity.js b/scripts/entity.js index c51df9d6..5d79965d 100644 --- a/scripts/entity.js +++ b/scripts/entity.js @@ -1,12 +1,11 @@ globalThis.entityreport = {}; -var timer_update = function(dt) -{ +var timer_update = function (dt) { this.fn(); -} +}; function obj_unique_name(name, obj) { - name = name.replaceAll('.', '_'); + name = name.replaceAll(".", "_"); if (!(name in obj)) return name; var t = 1; var n = name + t; @@ -18,7 +17,7 @@ function obj_unique_name(name, obj) { } function unique_name(list, name = "new_object") { - var str = name.replaceAll('.', '_'); + var str = name.replaceAll(".", "_"); var n = 1; var t = str; while (list.indexOf(t) !== -1) { @@ -26,23 +25,22 @@ function unique_name(list, name = "new_object") { n++; } return t; -}; +} var entity = { drawlayer: -1, get_comp_by_name(name) { var comps = []; - for (var c of Object.values(this.components)) - if (c.comp === name) comps.push(c); - + for (var c of Object.values(this.components)) if (c.comp === name) comps.push(c); + if (comps.length) return comps; return undefined; }, - + rigidify() { this.body = os.make_body(this.transform); }, - + path_from(o) { var p = this.toString(); var c = this.master; @@ -53,15 +51,17 @@ var entity = { if (c === world) p = "world." + p; return p; }, - + drawlayer: 0, - - full_path() { return this.path_from(world); }, - + + full_path() { + return this.path_from(world); + }, + clear() { for (var k in this.objects) { this.objects[k].kill(); - }; + } this.objects = {}; }, @@ -72,54 +72,75 @@ var entity = { delay(fn, seconds) { var timers = this.timers; - var stop = function() { + var stop = function () { timers.remove(stop); execute = undefined; stop = undefined; rm?.(); rm = undefined; update = undefined; - } - + }; + function execute() { fn(); stop?.(); } - + stop.remain = seconds; stop.seconds = seconds; - stop.pct = function() { return 1 - (stop.remain/stop.seconds); }; - + stop.pct = function () { + return 1 - stop.remain / stop.seconds; + }; + function update(dt) { profile.frame("timer"); - if (stop) { // TODO: This seems broken - stop.remain -= dt; - if (stop.remain <= 0) execute(); + if (stop) { + // TODO: This seems broken + stop.remain -= dt; + if (stop.remain <= 0) execute(); } profile.endframe(); } - + var rm = Register.update.register(update); timers.push(stop); return stop; }, - - cry(file) { return audio.cry(file); }, - - get pos() { return this.transform.pos; }, - set pos(x) { this.transform.pos = x; }, - get angle() { return this.transform.angle; }, - set angle(x) { this.transform.angle = x; }, - get scale() { return this.transform.scale; }, - set scale(x) { this.transform.scale = x; }, - - move(vec) { this.pos = this.pos.add(vec); }, - rotate(x) { this.transform.rotate(x, [0,0,-1]); }, - grow(vec) { - if (typeof vec === 'number') vec = [vec,vec]; - this.scale = this.scale.map((x,i) => x*vec[i]); + + cry(file) { + return audio.cry(file); }, - + + get pos() { + return this.transform.pos; + }, + set pos(x) { + this.transform.pos = x; + }, + get angle() { + return this.transform.angle; + }, + set angle(x) { + this.transform.angle = x; + }, + get scale() { + return this.transform.scale; + }, + set scale(x) { + this.transform.scale = x; + }, + + move(vec) { + this.pos = this.pos.add(vec); + }, + rotate(x) { + this.transform.rotate(x, [0, 0, -1]); + }, + grow(vec) { + if (typeof vec === "number") vec = [vec, vec]; + this.scale = this.scale.map((x, i) => x * vec[i]); + }, + /* Reparent 'this' to be 'parent's child */ reparent(parent) { assert(parent, `Tried to reparent ${this.toString()} to nothing.`); @@ -127,28 +148,26 @@ var entity = { console.warn(`not reparenting ... ${this.master} is the same as ${parent}`); return; } - + var name = unique_name(Object.keys(parent), this.name); this.name = name; - + this.master?.remove_obj(this); this.master = parent; parent.objects[this.guid] = this; parent[name] = this; Object.hide(parent, name); }, - + remove_obj(obj) { - if (this.objects) - delete this.objects[obj.guid]; - else - console.warn(`Object ${this.guid} has no objects file.`); + if (this.objects) delete this.objects[obj.guid]; + else console.warn(`Object ${this.guid} has no objects file.`); delete this[obj.name]; Object.unhide(this, obj.name); }, - + spawn(text, config, callback) { - var ent = class_use(text, config, entity, function(ent) { + var ent = class_use(text, config, entity, function (ent) { ent.transform = os.make_transform(); ent.guid = prosperon.guid(); ent.components = {}; @@ -157,7 +176,7 @@ var entity = { ent.ur = {}; ent.urname = text; }); -/* + /* if (!text) ent.ur = emptyur; else if (text instanceof Object) {// assume it's an ur @@ -192,15 +211,15 @@ var entity = { profile.cache("ENTITY TIME", ent.ur.name); */ ent.reparent(this); - + for (var [prop, p] of Object.entries(ent)) { if (!p) continue; - if (typeof p !== 'object') continue; + if (typeof p !== "object") continue; if (!p.comp) continue; ent[prop] = component[p.comp](ent); Object.merge(ent[prop], p); ent.components[prop] = ent[prop]; - }; + } check_registers(ent); @@ -209,20 +228,20 @@ var entity = { ent._started = true; if (ent.start instanceof Function) ent.start(); } - - Object.hide(ent, 'ur', 'components', 'objects', 'timers', 'guid', 'master', 'guid'); - + + Object.hide(ent, "ur", "components", "objects", "timers", "guid", "master", "guid"); + ent._ed = { selectable: true, dirty: false, inst: false, - urdiff: {} + urdiff: {}, }; - - Object.hide(ent, '_ed'); - + + Object.hide(ent, "_ed"); + ent.sync(); - + if (!Object.empty(ent.objects)) { var o = ent.objects; delete ent.objects; @@ -235,46 +254,63 @@ var entity = { ent.rename_obj(n.toString(), i); } } - + if (ent.tag) game.tag_add(ent.tag, ent); - + if (callback) callback(ent); - + ent.ur.fresh ??= json.decode(json.encode(ent)); ent.ur.fresh.objects = {}; - for (var i in ent.objects) - ent.ur.fresh.objects[i] = ent.objects[i].instance_obj(); + for (var i in ent.objects) ent.ur.fresh.objects[i] = ent.objects[i].instance_obj(); profile.endcache(); - + return ent; }, - - disable() { for (var x of this.components) x.disable(); }, - enable() { for (var x of this.components) x.enable(); }, - - this2screen(pos) { return game.camera.world2view(this.this2world(pos)); }, - screen2this(pos) { return this.world2this(game.camera.view2world(pos)); }, - + + disable() { + for (var x of this.components) x.disable(); + }, + enable() { + for (var x of this.components) x.enable(); + }, + + this2screen(pos) { + return game.camera.world2view(this.this2world(pos)); + }, + screen2this(pos) { + return this.world2this(game.camera.view2world(pos)); + }, + /* Make a unique object the same as its prototype */ - revert() { Object.merge(this, this.ur.fresh); }, - + revert() { + Object.merge(this, this.ur.fresh); + }, + name: "new_object", - toString() { return this.name; }, + toString() { + return this.name; + }, width() { var bb = this.boundingbox(); return bb.r - bb.l; }, - + height() { var bb = this.boundingbox(); return bb.t - bb.b; }, - - flipx() { return this.scale.x < 0; }, - flipy() { return this.scale.y < 0; }, - - mirror(plane) { this.scale = Vector.reflect(this.scale, plane); }, + + flipx() { + return this.scale.x < 0; + }, + flipy() { + return this.scale.y < 0; + }, + + mirror(plane) { + this.scale = Vector.reflect(this.scale, plane); + }, /* Bounding box of the object in world dimensions */ boundingbox() { @@ -283,46 +319,42 @@ var entity = { t: 0, r: 0, b: 0, - l: 0 + l: 0, }); - + for (var key in this.components) { - if ('boundingbox' in this.components[key]) - boxes.push(this.components[key].boundingbox()); + if ("boundingbox" in this.components[key]) boxes.push(this.components[key].boundingbox()); } - for (var key in this.objects) - boxes.push(this.objects[key].boundingbox()); - + for (var key in this.objects) boxes.push(this.objects[key].boundingbox()); + var bb = boxes.shift(); - + for (var x of boxes) bb = bbox.expand(bb, x); - + bb = bbox.move(bb, this.pos); - + return bb ? bb : bbox.fromcwh([0, 0], [0, 0]); }, toJSON() { - return {guid:this.guid}; + return { guid: this.guid }; }, - + /* The unique components of this object. Its diff. */ - json_obj(depth=0) { + json_obj(depth = 0) { var fresh = this.ur.fresh; var thiso = json.decode(json.encode(this)); // TODO: SLOW. Used to ignore properties in toJSON of components. var d = ediff(thiso, fresh); - + d ??= {}; - + fresh.objects ??= {}; var curobjs = {}; - for (var o in this.objects) - curobjs[o] = this.objects[o].instance_obj(); - + for (var o in this.objects) curobjs[o] = this.objects[o].instance_obj(); + var odiff = ediff(curobjs, fresh.objects); - if (odiff) - d.objects = curobjs; - + if (odiff) d.objects = curobjs; + delete d.pos; delete d.angle; delete d.scale; @@ -330,7 +362,7 @@ var entity = { delete d.angularvelocity; return d; }, - + /* The object needed to store an object as an instance of a master */ instance_obj() { var t = os.make_transform(); @@ -338,65 +370,65 @@ var entity = { t.ur = this.ur.name; return t; }, - + transform() { var t = {}; t.pos = this.get_pos(this.master).map(x => Math.places(x, 0)); t.angle = Math.places(this.get_angle(this.master), 4); - t.scale = this.get_scale(this.master).map(x => Math.places(x, 2));; + t.scale = this.get_scale(this.master).map(x => Math.places(x, 2)); return t; }, -dup(diff) { + dup(diff) { var n = this.master.spawn(this.ur); Object.totalmerge(n, this.transform()); return n; }, - + kill() { if (this.__kill) return; this.__kill = true; - + this.timers.forEach(x => x()); delete this.timers; Event.rm_obj(this); input.do_uncontrol(this); - + if (this.master) { this.master.remove_obj(this); this.master = undefined; } - + for (var key in this.components) { this.components[key].kill?.(); this.components[key].gameobject = undefined; this.components[key].enabled = false; delete this.components[key]; } - + delete this.components; - + this.clear(); if (this.stop instanceof Function) this.stop(); - if (typeof this.garbage === 'function') this.garbage(); - if (typeof this.then === 'function') this.then(); - + if (typeof this.garbage === "function") this.garbage(); + if (typeof this.then === "function") this.then(); + game.tag_clear_guid(this.guid); rmactor(this); - + for (var i in this) { if (this[i] instanceof Object || this[i] instanceof Function) delete this[i]; } }, - + make_objs(objs) { for (var prop in objs) { say(`spawning ${json.encode(objs[prop])}`); var newobj = this.spawn(objs[prop]); } }, - + rename_obj(name, newname) { if (!this.objects[name]) { console.warn(`No object with name ${name}. Could not rename to ${newname}.`); @@ -406,18 +438,19 @@ dup(diff) { Object.hide(this, name); return; } - if (this.objects[newname]) - return; - + if (this.objects[newname]) return; + this.objects[newname] = this.objects[name]; this[newname] = this[name]; - this[newname].toString = function() { return newname; }; + this[newname].toString = function () { + return newname; + }; Object.hide(this, newname); delete this.objects[name]; delete this[name]; return this.objects[newname]; }, - + add_component(comp, data) { var name = prosperon.guid(); this.components[name] = comp(this); @@ -438,10 +471,8 @@ var gameobject = { if (!lur) return; var lur = lur.objects[this.toString()]; var d = ediff(this._ed.urdiff, lur); - if (!d || Object.empty(d)) - this._ed.inst = true; - else - this._ed.inst = false; + if (!d || Object.empty(d)) this._ed.inst = true; + else this._ed.inst = false; }, namestr() { @@ -460,9 +491,9 @@ var gameobject = { /* pin this object to the to object */ pin(to) { - var p = joint.pin(this,to); + var p = joint.pin(this, to); }, - slide(to, a = [0,0], b = [0,0], min = 0, max = 50) { + slide(to, a = [0, 0], b = [0, 0], min = 0, max = 50) { var p = joint.slide(this, to, a, b, min, max); p.max_force = 500; p.break(); @@ -471,10 +502,10 @@ var gameobject = { var p = joint.pivot(this, to, piv); }, /* groove is on to, from local points a and b, anchored to this at local anchor */ - groove(to, a, b, anchor = [0,0]) { + groove(to, a, b, anchor = [0, 0]) { var p = joint.groove(to, this, a, b, anchor); }, - damped_spring(to, length = Vector.length(this.pos,to.pos), stiffness = 1, damping = 1) { + damped_spring(to, length = Vector.length(this.pos, to.pos), stiffness = 1, damping = 1) { var dc = 2 * Math.sqrt(stiffness * this.mass); var p = joint.damped_spring(this, to, [0, 0], [0, 0], stiffness, damping * dc); }, @@ -506,7 +537,7 @@ var gameobject = { this.rpos = newpos; for (var o of this.objects) o.move(move); }, - + set_angle(x, relative = world) { var newangle = relative.angle + x; var diff = newangle - this.angle; @@ -516,37 +547,42 @@ var gameobject = { obj.set_pos(Vector.rotate(obj.get_pos(obj.master), diff), obj.master); } }, - + set_scale(x, relative = world) { - if (typeof x === 'number') x = [x,x,x]; - var newscale = relative.scale.map((s,i) => x[i]*s); - var pct = this.scale.map((s,i) => newscale[i]/s); + if (typeof x === "number") x = [x, x, x]; + var newscale = relative.scale.map((s, i) => x[i] * s); + var pct = this.scale.map((s, i) => newscale[i] / s); this.rscale = newscale; for (var obj of this.objects) { obj.grow(pct); - obj.set_pos(obj.get_pos(obj.master).map((x,i) => x*pct[i]), obj.master); - }; + obj.set_pos( + obj.get_pos(obj.master).map((x, i) => x * pct[i]), + obj.master, + ); + } }, - + get_pos(relative = world) { if (relative === world) return this.pos; return relative.world2this(this.pos); //return this.pos.sub(relative.pos); }, - + get_angle(relative = world) { if (relative === world) return this.angle; return this.angle - relative.angle; }, - + get_scale(relative = world) { if (relative === world) return this.scale; var masterscale = relative.scale; - return this.scale.map((x,i) => x/masterscale[i]); + return this.scale.map((x, i) => x / masterscale[i]); }, - - in_air() { return this.in_air(); }, - + + in_air() { + return this.in_air(); + }, + /* Velocity and angular velocity of the object */ phys_obj() { var phys = {}; @@ -554,13 +590,13 @@ var gameobject = { phys.angularvelocity = this.angularvelocity; return phys; }, - + set category(n) { if (n === 0) { this.categories = n; return; } - var cat = (1 << (n-1)); + var cat = 1 << (n - 1); this.categories = cat; }, get category() { @@ -568,16 +604,16 @@ var gameobject = { var pos = 0; var num = this.categories; while (num > 0) { - if (num & 1) { - break; - } - pos++; - num >>>= 1; + if (num & 1) { + break; + } + pos++; + num >>>= 1; } - - return pos+1; - } -} + + return pos + 1; + }, +}; entity.spawn.doc = `Spawn an entity of type 'ur' on this entity. Returns the spawned entity.`; @@ -598,12 +634,12 @@ gameobject.doc = { set_pos: `Function to set the position of the object in world coordinates.`, worldangle: `Function to get the angle of the entity in the world.`, rotate: `Function to rotate this object by x degrees.`, - move: 'Move an object by x,y,z. If the first parameter is an array, uses up to the first three array values.', + move: "Move an object by x,y,z. If the first parameter is an array, uses up to the first three array values.", pulse: `Apply an impulse to this body in world coordinates. Impulse is a short force.`, shove: `Apply a force to this body in world coordinates. Should be used over many frames.`, - shove_at: 'Apply a force to this body, at a position relative to itself.', - max_velocity: 'The max linear velocity this object can travel.', - max_angularvelocity: 'The max angular velocity this object can rotate.', + shove_at: "Apply a force to this body, at a position relative to itself.", + max_velocity: "The max linear velocity this object can travel.", + max_angularvelocity: "The max angular velocity this object can rotate.", on_ground: `Return true if the object is on the ground.`, spawn: `Create an instance of a supplied ur-type on this object. Optionally provide a data object to modify the created entity.`, hide: `Make this object invisible.`, @@ -616,28 +652,27 @@ gameobject.doc = { transform: `Return an object representing the transform state of this object.`, kill: `Remove this object from the world.`, master: "The entity this entity belongs to.", - delay: 'Run the given function after the given number of seconds has elapsed.', - cry: 'Make a sound. Can only make one at a time.', - add_component: 'Add a component to the object by name.', - pin: 'Pin joint to another object. Acts as if a rigid rod is between the two objects.', - slide: 'Slide joint, similar to a pin but with min and max allowed distances.', - pivot: 'Pivot joint to an object, with the pivot given in world coordinates.', - groove: 'Groove joint. The groove is on to, from to local coordinates a and b, with this object anchored at anchor.', - damped_spring: 'Damped spring to another object. Length is the distance it wants to be, stiffness is the spring constant, and damping is the damping ratio. 1 is critical, < 1 is underdamped, > 1 is overdamped.', - damped_rotary_spring: 'Similar to damped spring but for rotation. Rest angle is the attempted angle.', - rotary_limit: 'Limit the angle relative to the to body between min and max.', - ratchet: 'Like a socket wrench, relative to to. ratch is the distance between clicks.', - gear: 'Keeps the angular velocity ratio of this body and to constant. Ratio is the gear ratio.', - motor: 'Keeps the relative angular velocity of this body to to at a constant rate. The most simple idea is for one of the bodies to be static, to the other is kept at rate.', - layer: 'Bitmask for collision layers.', - drawlayer: 'Layer for drawing. Higher numbers draw above lower ones.', - warp_filter: 'Bitmask for selecting what warps should affect this entity.', + delay: "Run the given function after the given number of seconds has elapsed.", + cry: "Make a sound. Can only make one at a time.", + add_component: "Add a component to the object by name.", + pin: "Pin joint to another object. Acts as if a rigid rod is between the two objects.", + slide: "Slide joint, similar to a pin but with min and max allowed distances.", + pivot: "Pivot joint to an object, with the pivot given in world coordinates.", + groove: "Groove joint. The groove is on to, from to local coordinates a and b, with this object anchored at anchor.", + damped_spring: "Damped spring to another object. Length is the distance it wants to be, stiffness is the spring constant, and damping is the damping ratio. 1 is critical, < 1 is underdamped, > 1 is overdamped.", + damped_rotary_spring: "Similar to damped spring but for rotation. Rest angle is the attempted angle.", + rotary_limit: "Limit the angle relative to the to body between min and max.", + ratchet: "Like a socket wrench, relative to to. ratch is the distance between clicks.", + gear: "Keeps the angular velocity ratio of this body and to constant. Ratio is the gear ratio.", + motor: "Keeps the relative angular velocity of this body to to at a constant rate. The most simple idea is for one of the bodies to be static, to the other is kept at rate.", + layer: "Bitmask for collision layers.", + drawlayer: "Layer for drawing. Higher numbers draw above lower ones.", + warp_filter: "Bitmask for selecting what warps should affect this entity.", }; global.ur = {}; -if (io.exists(`${io.dumpfolder}/ur.json`)) - ur = json.decode(io.slurp(`${io.dumpfolder}/ur.json`)); +if (io.exists(`${io.dumpfolder}/ur.json`)) ur = json.decode(io.slurp(`${io.dumpfolder}/ur.json`)); else { ur = {}; ur._list = []; @@ -655,79 +690,72 @@ ur { /* Apply an ur u to an entity e */ /* u is given as */ function apply_ur(u, ent) { - if (typeof u !== 'string') { + if (typeof u !== "string") { console.warn("Must give u as a string."); return; } - var urs = u.split('.'); + var urs = u.split("."); if (!urs.every(u => ur[u])) { console.error(`Attempted to make ur combo ${u} but not every ur in the chain exists.`); return; } - + for (var u of urs) { var text = u.text; var data = u.data; - if (typeof text === 'string') - use(text, ent); - else if (Array.isArray(text)) - for (var path of text) use(path,ent); - - if (typeof data === 'string') - Object.merge(ent, json.decode(Resources.replstrs(data))); + if (typeof text === "string") use(text, ent); + else if (Array.isArray(text)) for (var path of text) use(path, ent); + + if (typeof data === "string") Object.merge(ent, json.decode(Resources.replstrs(data))); else if (Array.isArray(data)) { for (var path of data) { - if (typeof path === 'string') - Object.merge(ent, json.decode(Resources.replstrs(data))); - else if (path instanceof Object) - Object.merge(ent,path); - }; + if (typeof path === "string") Object.merge(ent, json.decode(Resources.replstrs(data))); + else if (path instanceof Object) Object.merge(ent, path); + } } } } var emptyur = { - name: "empty" -} + name: "empty", +}; -var getur = function(text, data) -{ +var getur = function (text, data) { if (!text && !data) { - console.info('empty ur'); + console.info("empty ur"); return { - name: "empty" + name: "empty", }; } var urstr = text; - if (data) - urstr += "+" + data; + if (data) urstr += "+" + data; if (!ur[urstr]) { ur[urstr] = { name: urstr, text: text, - data: data - } + data: data, + }; } return ur[urstr]; -} +}; -var ur_from_file = function(file) { +var ur_from_file = function (file) { var urname = file.name(); if (ur[urname]) { console.warn(`Tried to make another ur with the name ${urname} from ${file}, but it already exists.`); return undefined; } var newur = { - name: urname + name: urname, }; ur[urname] = newur; ur._list.push(urname); return newur; -} +}; -game.loadurs = function() { +game.loadurs = function () { return; ur = {}; ur._list = []; @@ -739,12 +767,12 @@ game.loadurs = function() { var urjson = json.decode(uur); Object.assign(newur, urjson); } - + for (var file of io.glob("**.jso").filter(f => !ur[f.name()])) { - if (file[0] === '.' || file[0] === '_') continue; + if (file[0] === "." || file[0] === "_") continue; var newur = ur_from_file(file); if (!newur) continue; - newur.text = file; + newur.text = file; var data = file.set_ext(".json"); if (io.exists(data)) { @@ -755,9 +783,8 @@ game.loadurs = function() { }; game.ur = {}; -game.ur.load = function(str) {} -game.ur.add_data = function(str, data) -{ +game.ur.load = function (str) {}; +game.ur.add_data = function (str, data) { var nur = ur[str]; if (!nur) { console.warn(`Cannot add data to the ur ${str}.`); @@ -768,17 +795,16 @@ game.ur.add_data = function(str, data) if (ur.data) arr.push(ur.data); ur.data = arr; } - - ur.data.push(data); -} -game.ur.save = function(str) -{ + ur.data.push(data); +}; + +game.ur.save = function (str) { var nur = ur[str]; if (!nur) { console.warn(`Cannot save ur ${str}.`); return; } -} +}; -return { entity } +return { entity }; diff --git a/scripts/geometry.js b/scripts/geometry.js index 2c53c214..9db609e6 100644 --- a/scripts/geometry.js +++ b/scripts/geometry.js @@ -1,81 +1,70 @@ var shape = {}; shape.box = {}; -shape.box.points = function(ll, ur) -{ - return [ll, ll.add([ur.x-ll.x,0]), ur, ll.add([0,ur.y-ll.y])]; -} +shape.box.points = function (ll, ur) { + return [ll, ll.add([ur.x - ll.x, 0]), ur, ll.add([0, ur.y - ll.y])]; +}; shape.sphere = {}; shape.circle = {}; -shape.sphere.volume = function(r) { return Math.pi*r*r*r*4/3; }; -shape.sphere.random = function(r,theta = [0,1], phi = [-0.5,0.5]) -{ - if (typeof r === 'number') r = [r,r]; - if (typeof theta === 'number') theta = [theta,theta]; - if (typeof phi === 'number') phi = [phi,phi]; - - var ra = Math.random_range(r[0],r[1]); - var ta = Math.turn2rad(Math.random_range(theta[0],theta[1])); - var pa = Math.turn2rad(Math.random_range(phi[0],phi[1])); - return [ - ra*Math.sin(ta)*Math.cos(pa), - ra*Math.sin(ta)*Math.sin(pa), - ra*Math.cos(ta) - ]; -} +shape.sphere.volume = function (r) { + return (Math.pi * r * r * r * 4) / 3; +}; +shape.sphere.random = function (r, theta = [0, 1], phi = [-0.5, 0.5]) { + if (typeof r === "number") r = [r, r]; + if (typeof theta === "number") theta = [theta, theta]; + if (typeof phi === "number") phi = [phi, phi]; -shape.circle.area = function(r) { return Math.pi*r*r; }; -shape.circle.random = function(r,theta) -{ - return shape.sphere.random(r,theta).xz; -} + var ra = Math.random_range(r[0], r[1]); + var ta = Math.turn2rad(Math.random_range(theta[0], theta[1])); + var pa = Math.turn2rad(Math.random_range(phi[0], phi[1])); + return [ra * Math.sin(ta) * Math.cos(pa), ra * Math.sin(ta) * Math.sin(pa), ra * Math.cos(ta)]; +}; -shape.box = function(w,h) { +shape.circle.area = function (r) { + return Math.pi * r * r; +}; +shape.circle.random = function (r, theta) { + return shape.sphere.random(r, theta).xz; +}; + +shape.box = function (w, h) { w /= 2; h /= 2; var points = [ - [w,h], - [-w,h], - [-w,-h], - [w,-h] + [w, h], + [-w, h], + [-w, -h], + [w, -h], ]; return points; }; -shape.ngon = function(radius, n) { - return shape.arc(radius,360,n); +shape.ngon = function (radius, n) { + return shape.arc(radius, 360, n); }; -shape.arc = function(radius, angle, n, start = 0) { +shape.arc = function (radius, angle, n, start = 0) { start = Math.deg2rad(start); - if (angle >= 360) - angle = 360; + if (angle >= 360) angle = 360; if (n <= 1) return []; var points = []; angle = Math.deg2rad(angle); - var arclen = angle/n; - for (var i = 0; i < n; i++) - points.push(Vector.rotate([radius,0], start + (arclen*i))); + var arclen = angle / n; + for (var i = 0; i < n; i++) points.push(Vector.rotate([radius, 0], start + arclen * i)); return points; }; -shape.circle.points = function(radius, n) { +shape.circle.points = function (radius, n) { if (n <= 1) return []; return shape.arc(radius, 360, n); }; -shape.corners2points = function(ll, ur) -{ - return [ - ll, - ll.add([ur.x,0]), - ur, - ll.add([0,ur.y]), - ]; -} +shape.corners2points = function (ll, ur) { + return [ll, ll.add([ur.x, 0]), ur, ll.add([0, ur.y])]; +}; -return {shape}; +return { shape }; diff --git a/scripts/input.js b/scripts/input.js index 47a7620e..a9cd7994 100644 --- a/scripts/input.js +++ b/scripts/input.js @@ -1,31 +1,30 @@ input.keycodes = { - 32: "space", - 45: "minus", - 256: "escape", + 32: "space", + 45: "minus", + 256: "escape", 257: "enter", 258: "tab", 259: "backspace", 260: "insert", 261: "delete", - 262: "right", + 262: "right", 263: "left", - 264: "down", + 264: "down", 265: "up", - 266: "pgup", + 266: "pgup", 267: "pgdown", 268: "home", 269: "end", }; input.codekeys = {}; -for (var code in input.keycodes) - input.codekeys[input.keycodes[code]] = code; +for (var code in input.keycodes) input.codekeys[input.keycodes[code]] = code; var mod = { shift: 0, ctrl: 0, alt: 0, - super: 0 + super: 0, }; /* @@ -35,32 +34,32 @@ pressed down */ -function keycode(name) { return charCodeAt(name); } +function keycode(name) { + return charCodeAt(name); +} + +function keyname_extd(key) { + if (!parseInt(key)) return key; -function keyname_extd(key) -{ - if (!parseInt(key)) return key; - if (key > 289 && key < 302) { - var num = key-289; + var num = key - 289; return `f${num}`; } - + if (key >= 320 && key <= 329) { - var num = key-320; + var num = key - 320; return `kp${num}`; } - + if (input.keycodes[key]) return input.keycodes[key]; if (key >= 32 && key <= 126) return String.fromCharCode(key).lc(); - + return undefined; } var downkeys = {}; -function modstr() -{ +function modstr() { var s = ""; if (mod.ctrl) s += "C-"; if (mod.alt) s += "M-"; @@ -68,98 +67,89 @@ function modstr() return s; } -prosperon.keydown = function(key, repeat) -{ +prosperon.keydown = function (key, repeat) { downkeys[key] = true; - - if (key == 341 || key == 345) - mod.ctrl = 1; - else if (key == 342 || key == 346) - mod.alt = 1; - else if (key == 343 || key == 347) - mod.super = 1; - else if (key == 340 || key == 344) - mod.shift = 1; + + if (key == 341 || key == 345) mod.ctrl = 1; + else if (key == 342 || key == 346) mod.alt = 1; + else if (key == 343 || key == 347) mod.super = 1; + else if (key == 340 || key == 344) mod.shift = 1; else { var emacs = modstr() + keyname_extd(key); - if (repeat) - player[0].raw_input(emacs, "rep"); - else - player[0].raw_input(emacs, "pressed"); + if (repeat) player[0].raw_input(emacs, "rep"); + else player[0].raw_input(emacs, "pressed"); } -} +}; -prosperon.keyup = function(key) -{ +prosperon.keyup = function (key) { delete downkeys[key]; - - if (key == 341 || key == 345) - mod.ctrl = 0; - else if (key == 342 || key == 346) - mod.alt = 0; - else if (key == 343 || key == 347) - mod.super = 0; - else if (key == 340 || key == 344) - mod.shift = 0; + if (key == 341 || key == 345) mod.ctrl = 0; + else if (key == 342 || key == 346) mod.alt = 0; + else if (key == 343 || key == 347) mod.super = 0; + else if (key == 340 || key == 344) mod.shift = 0; else { var emacs = modstr() + keyname_extd(key); player[0].raw_input(emacs, "released"); } -} +}; -prosperon.droppedfile = function(path) -{ +prosperon.droppedfile = function (path) { player[0].raw_input("drop", "pressed", path); -} +}; -var mousepos = [0,0]; +var mousepos = [0, 0]; -prosperon.textinput = function(c){ +prosperon.textinput = function (c) { player[0].raw_input("char", "pressed", c); }; -prosperon.mousemove = function(pos, dx){ +prosperon.mousemove = function (pos, dx) { mousepos = pos; mousepos.y = window.size.y - mousepos.y; player[0].mouse_input("move", pos, dx); }; -prosperon.mousescroll = function(dx){ +prosperon.mousescroll = function (dx) { player[0].mouse_input(modstr() + "scroll", dx); }; -prosperon.mousedown = function(b){ +prosperon.mousedown = function (b) { player[0].raw_input(modstr() + input.mouse.button[b], "pressed"); downkeys[input.mouse.button[b]] = true; }; -prosperon.mouseup = function(b){ +prosperon.mouseup = function (b) { player[0].raw_input(input.mouse.button[b], "released"); delete downkeys[input.mouse.button[b]]; }; input.mouse = {}; -input.mouse.screenpos = function() { return mousepos.slice(); }; -input.mouse.worldpos = function() { return game.camera.view2world(mousepos); }; -input.mouse.disabled = function() { input.mouse_mode(1); }; -input.mouse.normal = function() { input.mouse_mode(0); }; -input.mouse.mode = function(m) { - if (input.mouse.custom[m]) - input.cursor_img(input.mouse.custom[m]); - else - input.mouse_cursor(m); +input.mouse.screenpos = function () { + return mousepos.slice(); }; - -input.mouse.set_custom_cursor = function(img, mode = input.mouse.cursor.default) { - if (!img) - delete input.mouse.custom[mode]; +input.mouse.worldpos = function () { + return game.camera.view2world(mousepos); +}; +input.mouse.disabled = function () { + input.mouse_mode(1); +}; +input.mouse.normal = function () { + input.mouse_mode(0); +}; +input.mouse.mode = function (m) { + if (input.mouse.custom[m]) input.cursor_img(input.mouse.custom[m]); + else input.mouse_cursor(m); +}; + +input.mouse.set_custom_cursor = function (img, mode = input.mouse.cursor.default) { + if (!img) delete input.mouse.custom[mode]; else { input.cursor_img(img); input.mouse.custom[mode] = img; } }; - -input.mouse.button = { /* left, right, middle mouse */ - 0: "lm", + +input.mouse.button = { + /* left, right, middle mouse */ 0: "lm", 1: "rm", - 2: "mm" + 2: "mm", }; input.mouse.custom = []; input.mouse.cursor = { @@ -173,7 +163,7 @@ input.mouse.cursor = { nwse: 7, nesw: 8, resize: 9, - no: 10 + no: 10, }; input.mouse.doc = {}; @@ -183,14 +173,14 @@ input.mouse.disabled.doc = "Set the mouse to hidden. This locks it to the game a input.mouse.normal.doc = "Set the mouse to show again after hiding."; input.keyboard = {}; -input.keyboard.down = function(code) { - if (typeof code === 'number') return downkeys[code]; - if (typeof code === 'string') return (downkeys[code.uc().charCodeAt()] || downkeys[code.lc().charCodeAt()]); +input.keyboard.down = function (code) { + if (typeof code === "number") return downkeys[code]; + if (typeof code === "string") return downkeys[code.uc().charCodeAt()] || downkeys[code.lc().charCodeAt()]; return undefined; -} +}; -input.state2str = function(state) { - if (typeof state === 'string') return state; +input.state2str = function (state) { + if (typeof state === "string") return state; switch (state) { case 0: return "down"; @@ -199,10 +189,10 @@ input.state2str = function(state) { case 2: return "released"; } -} +}; -input.print_pawn_kbm = function(pawn) { - if (!('inputs' in pawn)) return; +input.print_pawn_kbm = function (pawn) { + if (!("inputs" in pawn)) return; var str = ""; for (var key in pawn.inputs) { if (!pawn.inputs[key].doc) continue; @@ -217,13 +207,11 @@ joysticks["wasd"] = { uy: "w", dy: "s", ux: "d", - dx: "a" + dx: "a", }; -input.procdown = function() -{ - for (var k in downkeys) - player[0].raw_input(keyname_extd(k), "down"); +input.procdown = function () { + for (var k in downkeys) player[0].raw_input(keyname_extd(k), "down"); for (var i in joysticks) { var joy = joysticks[i]; @@ -231,10 +219,10 @@ input.procdown = function() var y = joy.uy - joy.dy; player[0].joy_input(i, joysticks[i]); } -} +}; -input.print_md_kbm = function(pawn) { - if (!('inputs' in pawn)) return; +input.print_md_kbm = function (pawn) { + if (!("inputs" in pawn)) return; var str = ""; str += "|control|description|\n|---|---|\n"; @@ -247,8 +235,8 @@ input.print_md_kbm = function(pawn) { return str; }; -input.has_bind = function(pawn, bind) { - return (typeof pawn.inputs?.[bind] === 'function'); +input.has_bind = function (pawn, bind) { + return typeof pawn.inputs?.[bind] === "function"; }; input.action = { @@ -263,28 +251,36 @@ input.action = { actions: [], }; -input.tabcomplete = function(val, list) { - if (!val) return val; - list.dofilter(function(x) { return x.startsWith(val); }); +input.tabcomplete = function (val, list) { + if (!val) return val; + list.dofilter(function (x) { + return x.startsWith(val); + }); - if (list.length === 1) { - return list[0]; - } - - var ret = undefined; - var i = val.length; - while (!ret && !Object.empty(list)) { - var char = list[0][i]; - if (!list.every(function(x) { return x[i] === char; })) - ret = list[0].slice(0, i); - else { - i++; - list.dofilter(function(x) { return x.length-1 > i; }); - } - } + if (list.length === 1) { + return list[0]; + } - return ret ? ret : val; -} + var ret = undefined; + var i = val.length; + while (!ret && !Object.empty(list)) { + var char = list[0][i]; + if ( + !list.every(function (x) { + return x[i] === char; + }) + ) + ret = list[0].slice(0, i); + else { + i++; + list.dofilter(function (x) { + return x.length - 1 > i; + }); + } + } + + return ret ? ret : val; +}; /* May be a human player; may be an AI player */ @@ -300,24 +296,22 @@ var Player = { mouse_input(type, ...args) { for (var pawn of this.pawns.reversed()) { - if (typeof pawn.inputs?.mouse?.[type] === 'function') { - pawn.inputs.mouse[type].call(pawn,...args); - pawn.inputs.post?.call(pawn); - if (!pawn.inputs.fallthru) - return; + if (typeof pawn.inputs?.mouse?.[type] === "function") { + pawn.inputs.mouse[type].call(pawn, ...args); + pawn.inputs.post?.call(pawn); + if (!pawn.inputs.fallthru) return; } } }, char_input(c) { for (var pawn of this.pawns.reversed()) { - if (typeof pawn.inputs?.char === 'function') { + if (typeof pawn.inputs?.char === "function") { pawn.inputs.char.call(pawn, c); - pawn.inputs.post?.call(pawn); - if (!pawn.inputs.fallthru) - return; + pawn.inputs.post?.call(pawn); + if (!pawn.inputs.fallthru) return; } - }; + } }, joy_input(name, joystick) { @@ -329,11 +323,11 @@ var Player = { var x = 0; if (input.keyboard.down(joystick.ux)) x++; if (input.keyboard.down(joystick.dx)) x--; - var y = 0; + var y = 0; if (input.keyboard.down(joystick.uy)) y++; if (input.keyboard.down(joystick.dy)) y--; - pawn.inputs.joystick[name](x,y); + pawn.inputs.joystick[name](x, y); } }, @@ -341,62 +335,56 @@ var Player = { for (var pawn of this.pawns.reversed()) { if (!pawn.inputs) { console.error(`pawn no longer has inputs object.`); - continue; + continue; } var block = pawn.inputs.block; - + if (!pawn.inputs[cmd]) { if (pawn.inputs.block) return; - continue; + continue; } var fn = null; switch (state) { - case 'pressed': - fn = pawn.inputs[cmd]; - break; - case 'rep': - fn = pawn.inputs[cmd].rep ? pawn.inputs[cmd] : null; - break; - case 'released': - fn = pawn.inputs[cmd].released; - break; - case 'down': - if (typeof pawn.inputs[cmd].down === 'function') - fn = pawn.inputs[cmd].down; - else if (pawn.inputs[cmd].down) - fn = pawn.inputs[cmd]; + case "pressed": + fn = pawn.inputs[cmd]; + break; + case "rep": + fn = pawn.inputs[cmd].rep ? pawn.inputs[cmd] : null; + break; + case "released": + fn = pawn.inputs[cmd].released; + break; + case "down": + if (typeof pawn.inputs[cmd].down === "function") fn = pawn.inputs[cmd].down; + else if (pawn.inputs[cmd].down) fn = pawn.inputs[cmd]; } - if (typeof fn === 'function') - fn.call(pawn, ... args); + if (typeof fn === "function") fn.call(pawn, ...args); if (!pawn.inputs) if (block) return; - else continue; + else continue; - if (state === 'released') - pawn.inputs.release_post?.call(pawn); + if (state === "released") pawn.inputs.release_post?.call(pawn); if (!pawn.inputs.fallthru) return; - if (pawn.inputs.block) return; + if (pawn.inputs.block) return; } }, obj_controlled(obj) { for (var p in Player.players) { - if (p.pawns.contains(obj)) - return true; + if (p.pawns.contains(obj)) return true; } return false; }, print_pawns() { - for (var pawn of this.pawns.reversed()) - say(pawn.toString()); + for (var pawn of this.pawns.reversed()) say(pawn.toString()); }, create() { @@ -404,7 +392,7 @@ var Player = { n.pawns = []; n.gamepads = []; this.players.push(n); - this[this.players.length-1] = n; + this[this.players.length - 1] = n; return n; }, @@ -423,12 +411,11 @@ var Player = { }, }; -input.do_uncontrol = function(pawn) -{ - Player.players.forEach(function(p) { +input.do_uncontrol = function (pawn) { + Player.players.forEach(function (p) { p.pawns = p.pawns.filter(x => x !== pawn); }); -} +}; for (var i = 0; i < 4; i++) { Player.create(); @@ -443,5 +430,5 @@ Player.doc.players = "A list of current players."; var player = Player; return { - player + player, }; diff --git a/scripts/mum.js b/scripts/mum.js index 98702227..29d9f248 100644 --- a/scripts/mum.js +++ b/scripts/mum.js @@ -5,17 +5,16 @@ var panel; var selected = undefined; mum.inputs = {}; -mum.inputs.lm = function() -{ +mum.inputs.lm = function () { if (!selected) return; if (!selected.action) return; selected.action(); -} +}; mum.base = { pos: null, // If set, puts the cursor to this position before drawing the element - offset:[0,0], // Move x,y to the right and down before drawing - padding:[0,0], // Pad inwards after drawing, to prepare for the next element + offset: [0, 0], // Move x,y to the right and down before drawing + padding: [0, 0], // Pad inwards after drawing, to prepare for the next element font: "fonts/c64.ttf", selectable: false, selected: false, @@ -23,33 +22,33 @@ mum.base = { scale: 1, angle: 0, inset: null, - anchor: [0,1], // where to draw the item from, relative to the cursor. [0,1] is from the top left corner. [1,0] is from the bottom right + anchor: [0, 1], // where to draw the item from, relative to the cursor. [0,1] is from the top left corner. [1,0] is from the bottom right background_image: null, slice: null, // pass to slice an image as a 9 slice. see render.slice9 for its format hover: { color: Color.red, }, text_shadow: { - pos: [0,0], + pos: [0, 0], color: Color.white, }, border: 0, // Draw a border around the element. For text, an outline. overflow: "wrap", // how to deal with overflow from parent element wrap: -1, - text_align: "left", /* left, center, right */ + text_align: "left" /* left, center, right */, shader: null, // Use this shader, instead of the engine provided one color: Color.white, - opacity:1, - width:0, - height:0, + opacity: 1, + width: 0, + height: 0, max_width: Infinity, max_height: Infinity, image_repeat: false, - image_repeat_offset: [0,0], - debug: false, /* set to true to draw debug boxes */ + image_repeat_offset: [0, 0], + debug: false /* set to true to draw debug boxes */, hide: false, tooltip: null, -} +}; // data is passed into each function, and various stats are generated // drawpos: the point to start the drawing from @@ -57,22 +56,23 @@ mum.base = { // bound: a boundingbox around the drawn UI element // extent: a boundingbox around the total extents of the element (ie before padding) -function show_debug() { return prosperon.debug && mum.debug; } +function show_debug() { + return prosperon.debug && mum.debug; +} mum.debug = false; -var post = function() {}; +var post = function () {}; var posts = []; mum.style = mum.base; -var cursor = [0,0]; +var cursor = [0, 0]; -var pre = function(data) -{ +var pre = function (data) { if (data.hide) return true; data.__proto__ = mum.style; - + if (data.pos) cursor = data.pos.slice(); data.drawpos = cursor.slice().add(data.offset); @@ -81,87 +81,77 @@ var pre = function(data) data.color[3] = data.opacity; } - data.wh = [data.width,data.height]; -} + data.wh = [data.width, data.height]; +}; -var anchor_calc = function(data) -{ - var aa = [0,1].sub(data.anchor); - data.drawpos = data.drawpos.add([data.width,data.height]).scale(aa); -} +var anchor_calc = function (data) { + var aa = [0, 1].sub(data.anchor); + data.drawpos = data.drawpos.add([data.width, data.height]).scale(aa); +}; -var end = function(data) -{ +var end = function (data) { cursor = cursor.add(data.padding); post(data); -} +}; -mum.list = function(fn, data = {}) -{ +mum.list = function (fn, data = {}) { if (pre(data)) return; - var aa = [0,1].sub(data.anchor); - cursor = cursor.add([data.width,data.height].scale(aa)).add(data.offset).add(data.padding); + var aa = [0, 1].sub(data.anchor); + cursor = cursor.add([data.width, data.height].scale(aa)).add(data.offset).add(data.padding); posts.push(post); post = mum.list.post.bind(data); - + if (show_debug()) render.boundingbox({ - t:cursor.y, - b:cursor.y-data.height, - l:cursor.x, - r:cursor.x+data.width + t: cursor.y, + b: cursor.y - data.height, + l: cursor.x, + r: cursor.x + data.width, }); - - //if (data.background_image) mum.image(null, Object.create(data)) + + //if (data.background_image) mum.image(null, Object.create(data)) if (data.background_image) { var imgpos = data.pos.slice(); - imgpos.y -= data.height/2; - imgpos.x -= data.width/2; - var imgscale = [data.width,data.height]; - if (data.slice) - render.slice9(game.texture(data.background_image), imgpos, data.slice, imgscale); - else - render.image(game.texture(data.background_image), imgpos, [data.width,data.height]); + imgpos.y -= data.height / 2; + imgpos.x -= data.width / 2; + var imgscale = [data.width, data.height]; + if (data.slice) render.slice9(game.texture(data.background_image), imgpos, data.slice, imgscale); + else render.image(game.texture(data.background_image), imgpos, [data.width, data.height]); } - + fn(); - + data.bb.l -= data.padding.x; data.bb.r += data.padding.x; data.bb.t += data.padding.y; data.bb.b -= data.padding.y; - if (show_debug()) - render.boundingbox(data.bb); + if (show_debug()) render.boundingbox(data.bb); post = posts.pop(); end(data); -} +}; -mum.list.post = function(e) -{ - cursor.y -= (e.bb.t - e.bb.b); +mum.list.post = function (e) { + cursor.y -= e.bb.t - e.bb.b; cursor.y -= e.padding.y; - - if (this.bb) - this.bb = bbox.expand(this.bb,e.bb) - else - this.bb = e.bb; -} -mum.label = function(str, data = {}) -{ + if (this.bb) this.bb = bbox.expand(this.bb, e.bb); + else this.bb = e.bb; +}; + +mum.label = function (str, data = {}) { if (pre(data)) return; render.set_font(data.font, data.font_size); - + data.bb = render.text_bb(str, data.scale, -1, cursor); data.wh = bbox.towh(data.bb); - - var aa = [0,1].sub(data.anchor); - - data.drawpos.y -= (data.bb.t-cursor.y); + + var aa = [0, 1].sub(data.anchor); + + data.drawpos.y -= data.bb.t - cursor.y; data.drawpos = data.drawpos.add(data.wh.scale(aa)).add(data.offset); data.bb = render.text_bb(str, data.scale, data.wrap, data.drawpos); @@ -175,87 +165,72 @@ mum.label = function(str, data = {}) } data.bb = render.text(str, data.drawpos, data.scale, data.color, data.wrap); - - if (show_debug()) - render.boundingbox(data.bb); - - end(data); -} -mum.image = function(path, data = {}) -{ + if (show_debug()) render.boundingbox(data.bb); + + end(data); +}; + +mum.image = function (path, data = {}) { if (pre(data)) return; path ??= data.background_image; var tex = path; - if (typeof path === 'string') - tex = game.texture(path); + if (typeof path === "string") tex = game.texture(path); if (!data.height) - if (data.width) - data.height = tex.height * (data.width/tex.width); - else - data.height = tex.height; + if (data.width) data.height = tex.height * (data.width / tex.width); + else data.height = tex.height; if (!data.width) - if (data.height) - data.width = tex.width * (data.height/tex.height); - else - data.height = tex.height; + if (data.height) data.width = tex.width * (data.height / tex.height); + else data.height = tex.height; if (!data.width) data.width = tex.width; if (!data.height) data.height = tex.height; - var aa = [0,1].sub(data.anchor); - data.drawpos = data.drawpos.add(aa.scale([data.width,data.height])); - - if (data.slice) - render.slice9(tex, data.drawpos, data.slice, [data.width,data.height]); - else - data.bb = render.image(tex, data.drawpos, [data.width, data.height]); - - end(data); -} + var aa = [0, 1].sub(data.anchor); + data.drawpos = data.drawpos.add(aa.scale([data.width, data.height])); -mum.rectangle = function(data = {}) -{ + if (data.slice) render.slice9(tex, data.drawpos, data.slice, [data.width, data.height]); + else data.bb = render.image(tex, data.drawpos, [data.width, data.height]); + + end(data); +}; + +mum.rectangle = function (data = {}) { if (pre(data)) return; - var aa = [0,0].sub(data.anchor); - data.drawpos = data.drawpos.add(aa.scale([data.width,data.height])); - - render.rectangle(data.drawpos, data.drawpos.add([data.width,data.height]), data.color); + var aa = [0, 0].sub(data.anchor); + data.drawpos = data.drawpos.add(aa.scale([data.width, data.height])); + + render.rectangle(data.drawpos, data.drawpos.add([data.width, data.height]), data.color); end(data); -} +}; var btnbb; -var btnpost = function() -{ +var btnpost = function () { btnbb = data.bb; -} +}; -mum.button = function(str, data = {padding:[4,4], color:Color.black}) -{ +mum.button = function (str, data = { padding: [4, 4], color: Color.black }) { if (pre(data)) return; posts.push(post); post = btnpost; - if (typeof str === 'string') - render.text(str, cursor.add(data.padding), data.scale, data.color); - else - str(); + if (typeof str === "string") render.text(str, cursor.add(data.padding), data.scale, data.color); + else str(); if (data.action && data.hover && bbox.pointin(btnbb, input.mouse.screenpos())) { data.hover.__proto__ = data; data = data.hover; } - render.rectangle([btnbb.l-data.padding.x, btnbb.b-data.padding.y], [btnbb.r+data.padding.y, btnbb.t+data.padding.y], data.color); + render.rectangle([btnbb.l - data.padding.x, btnbb.b - data.padding.y], [btnbb.r + data.padding.y, btnbb.t + data.padding.y], data.color); data.bb = btnbb; post = posts.pop(); end(data); -} +}; -mum.window = function(fn, data = {}) -{ +mum.window = function (fn, data = {}) { if (pre(data)) return; render.rectangle(cursor, cursor.add(data.size), data.color); @@ -263,28 +238,34 @@ mum.window = function(fn, data = {}) cursor = cursor.add(data.padding); fn(); end(data); -} +}; -mum.ex_hud = function() -{ - mum.label("TOP LEFT", {pos:[0,game.size.y], anchor:[0,1]}); - mum.label("BOTTOM LEFT", {pos:[0,0], anchor:[0,0]}); - mum.label("TOP RIGHT", {pos:game.size, anchor:[1,1]}); - mum.label("BOTTOM RIGHT", {pos:[game.size.x, 0], anchor:[1,0]}); -} +mum.ex_hud = function () { + mum.label("TOP LEFT", { pos: [0, game.size.y], anchor: [0, 1] }); + mum.label("BOTTOM LEFT", { pos: [0, 0], anchor: [0, 0] }); + mum.label("TOP RIGHT", { pos: game.size, anchor: [1, 1] }); + mum.label("BOTTOM RIGHT", { pos: [game.size.x, 0], anchor: [1, 0] }); +}; mum.drawinput = undefined; var ptext = ""; var panpan = { draw() { - mum.rectangle({pos:[0,0], anchor:[0,0], height:20, width: window.size.x, padding:[10,16], color:Color.black}); + mum.rectangle({ + pos: [0, 0], + anchor: [0, 0], + height: 20, + width: window.size.x, + padding: [10, 16], + color: Color.black, + }); mum.label("input level: "); - mum.label(ptext, {offset:[50,0], color:Color.red}); + mum.label(ptext, { offset: [50, 0], color: Color.red }); }, inputs: { block: true, char(c) { - ptext += c + ptext += c; }, enter() { delete mum.drawinput; @@ -295,18 +276,18 @@ var panpan = { player[0].uncontrol(panpan); }, backspace() { - ptext = ptext.slice(0,ptext.length-1); - } + ptext = ptext.slice(0, ptext.length - 1); + }, }, -} +}; mum.textinput = function (fn, str = "") { mum.drawinput = panpan.draw; ptext = str; player[0].control(panpan); - panpan.inputs.enter = function() { + panpan.inputs.enter = function () { fn(ptext); delete mum.drawinput; player[0].uncontrol(panpan); - } -} + }; +}; diff --git a/scripts/nogame.js b/scripts/nogame.js index 5cae666b..0961ebee 100644 --- a/scripts/nogame.js +++ b/scripts/nogame.js @@ -1,4 +1,6 @@ -this.hud = function() -{ - mum.label("No game yet! Make game.js to get started!", {pos:game.size.scale(0.5), anchor:[0.5,0.5]}); -} +this.hud = function () { + mum.label("No game yet! Make game.js to get started!", { + pos: game.size.scale(0.5), + anchor: [0.5, 0.5], + }); +}; diff --git a/scripts/particle.js b/scripts/particle.js index 15fbd7b3..6919129e 100644 --- a/scripts/particle.js +++ b/scripts/particle.js @@ -7,44 +7,38 @@ emitter.spawn_timer = 0; emitter.pps = 0; emitter.color = Color.white; -emitter.draw = function() -{ +emitter.draw = function () { var pars = Object.values(this.particles); if (pars.length === 0) return; render.use_shader(this.shader); render.use_mat(this); render.make_particle_ssbo(pars, this.ssbo); render.draw(this.shape, this.ssbo, pars.length); -} +}; -emitter.kill = function() -{ +emitter.kill = function () { emitters.remove(this); -} +}; -var std_step = function(p) -{ +var std_step = function (p) { if (p.time < this.grow_for) { - var s = Math.lerp(0, this.scale, p.time/this.grow_for); - p.transform.scale = [s,s,s]; - } - else if (p.time > (p.life - this.shrink_for)) { - var s = Math.lerp(0,this.scale,(p.life-p.time)/this.shrink_for); - p.transform.scale=[s,s,s]; - } else - p.transform.scale = [this.scale,this.scale,this.scale]; -} + var s = Math.lerp(0, this.scale, p.time / this.grow_for); + p.transform.scale = [s, s, s]; + } else if (p.time > p.life - this.shrink_for) { + var s = Math.lerp(0, this.scale, (p.life - p.time) / this.shrink_for); + p.transform.scale = [s, s, s]; + } else p.transform.scale = [this.scale, this.scale, this.scale]; +}; emitter.step_hook = std_step; -emitter.spawn = function(t) -{ +emitter.spawn = function (t) { t ??= this.transform; - + var par = this.dead.shift(); if (par) { par.body.pos = t.pos; - par.transform.scale = [this.scale,this.scale,this.scale]; + par.transform.scale = [this.scale, this.scale, this.scale]; this.particles[par.id] = par; par.time = 0; this.spawn_hook?.(par); @@ -56,25 +50,24 @@ emitter.spawn = function(t) transform: os.make_transform(), life: this.life, time: 0, - color: this.color + color: this.color, }; par.body = os.make_body(par.transform); par.body.pos = t.pos; - par.transform.scale = [this.scale,this.scale,this.scale]; + par.transform.scale = [this.scale, this.scale, this.scale]; par.id = prosperon.guid(); this.particles[par.id] = par; this.spawn_hook(par); -} +}; -emitter.step = function(dt) -{ +emitter.step = function (dt) { // update spawning particles if (this.on && this.pps > 0) { this.spawn_timer += dt; - var pp = 1/this.pps; + var pp = 1 / this.pps; while (this.spawn_timer > pp) { this.spawn_timer -= pp; this.spawn(); @@ -92,16 +85,15 @@ emitter.step = function(dt) delete this.particles[p.id]; } } -} +}; -emitter.burst = function(count, t) { +emitter.burst = function (count, t) { for (var i = 0; i < count; i++) this.spawn(t); -} +}; var emitters = []; -var make_emitter = function() -{ +var make_emitter = function () { var e = Object.create(emitter); e.ssbo = render.make_textssbo(); e.shape = shape.centered_quad; @@ -109,17 +101,14 @@ var make_emitter = function() e.dead = []; emitters.push(e); return e; +}; + +function update_emitters(dt) { + for (var e of emitters) e.step(dt); } -function update_emitters(dt) -{ - for (var e of emitters) - e.step(dt); -} - -function draw_emitters() -{ +function draw_emitters() { for (var e of emitters) e.draw(); } -return {make_emitter, update_emitters, draw_emitters}; +return { make_emitter, update_emitters, draw_emitters }; diff --git a/scripts/physics.js b/scripts/physics.js index 6406c5f8..c46335ef 100644 --- a/scripts/physics.js +++ b/scripts/physics.js @@ -9,27 +9,25 @@ var HIT = { }; */ -physics.pos_query = function(pos, start = world, give = 10) { +physics.pos_query = function (pos, start = world, give = 10) { var ret; ret = physics.point_query_nearest(pos, 0); - if (ret) - return ret.entity; + if (ret) return ret.entity; - return game.all_objects(function(o) { + return game.all_objects(function (o) { var dist = Vector.length(o.pos.sub(pos)); if (dist <= give) return o; }); -} +}; -physics.box_point_query = function(box,points) { +physics.box_point_query = function (box, points) { if (!box || !points) return []; - var bbox = bbox.fromcwh(box.pos,box.wh); + var bbox = bbox.fromcwh(box.pos, box.wh); var inside = []; - for (var i in points) - if (bbox.pointin(bbox,points[i])) inside.push[i]; + for (var i in points) if (bbox.pointin(bbox, points[i])) inside.push[i]; return inside; -} +}; Object.assign(physics, { dynamic: 0, @@ -37,8 +35,8 @@ Object.assign(physics, { static: 2, com(pos) { - if (!Array.isArray(pos)) return [0,0]; - return pos.reduce((a,i) => a.add(i)).map(g => g/pos.length); + if (!Array.isArray(pos)) return [0, 0]; + return pos.reduce((a, i) => a.add(i)).map(g => g / pos.length); }, }); @@ -53,8 +51,8 @@ physics.gravity.strength = 500; physics.damp = physics.make_damp(); physics.damp.mask = ~1; -physics.delta = 1/240; +physics.delta = 1 / 240; return { - physics -} + physics, +}; diff --git a/scripts/profile.js b/scripts/profile.js index cee27ecb..aeb1707f 100644 --- a/scripts/profile.js +++ b/scripts/profile.js @@ -10,47 +10,48 @@ memory - can see how much memory is allocated and from where */ -var t_units = [ "ns", "us", "ms", "s", "ks", "Ms" ]; +var t_units = ["ns", "us", "ms", "s", "ks", "Ms"]; -function calc_cpu (fn, times, diff = 0) { +function calc_cpu(fn, times, diff = 0) { var series = []; for (var i = 0; i < times; i++) { var st = profile.now(); - fn (i); + fn(i); series.push(profile.now() - st - diff); } return series; } -function empty_fn () {} +function empty_fn() {} profile.cpu = function profile_cpu(fn, times = 1, q = "unnamed") { var retgather = gathering_cpu; profile.gather_stop(); var empty = calc_cpu(empty_fn, 100000); var mean = Math.mean(empty); - var series = calc_cpu(fn,times, mean); - + var series = calc_cpu(fn, times, mean); + var elapsed = Math.sum(series); - var avgt = profile.best_t(elapsed/series.length); + var avgt = profile.best_t(elapsed / series.length); var totalt = profile.best_t(elapsed); - + say(`profile [${q}]: ${avgt} ± ${profile.best_t(Math.ci(series))} [${totalt} for ${times} loops]`); say(`result of function is ${fn()}`); - - if (retgather) - profile.start_prof_gather(); -} -profile.ms = function(t) { return profile.secs(t)*1000; } + if (retgather) profile.start_prof_gather(); +}; + +profile.ms = function (t) { + return profile.secs(t) * 1000; +}; var callgraph = {}; profile.rawstacks = {}; profile.cpu_cg = callgraph; -function add_callgraph (fn, line, time) { +function add_callgraph(fn, line, time) { var cc = callgraph[line]; if (!cc) { var cc = {}; @@ -70,87 +71,82 @@ var start_gather = profile.now(); profile.cpu_start = undefined; -profile.clear_cpu = function() -{ +profile.clear_cpu = function () { callgraph = {}; -} +}; -profile.start_cpu_gather = function(gathertime = 5) // gather cpu frames for 'time' seconds -{ +profile.start_cpu_gather = function (gathertime = 5) { + // gather cpu frames for 'time' seconds if (profile.cpu_start) return; profile.cpu_start = profile.now(); var st = profile.cpu_start; - - profile.gather(hittar, function() { - var time = profile.now()-st; - + + profile.gather(hittar, function () { + var time = profile.now() - st; + var err = new Error(); - var stack = err.stack.split("\n").slice(1); - var rawstack = stack.join('\n'); + var stack = err.stack.split("\n").slice(1); + var rawstack = stack.join("\n"); profile.rawstacks[rawstack] ??= { time: 0, - hits: 0 + hits: 0, }; profile.rawstacks[rawstack].hits++; profile.rawstacks[rawstack].time += time; - - stack = stack.map(x => x.slice(7).split(' ')); - - var fns = stack.map(x => x[0]).filter(x=>x); + + stack = stack.map(x => x.slice(7).split(" ")); + + var fns = stack.map(x => x[0]).filter(x => x); var lines = stack.map(x => x[1]).filter(x => x); - lines = lines.map(x => x.slice(1,x.length-1)); - - for (var i = 0; i < fns.length; i++) - add_callgraph(fns[i], lines[i], time); - + lines = lines.map(x => x.slice(1, x.length - 1)); + + for (var i = 0; i < fns.length; i++) add_callgraph(fns[i], lines[i], time); + st = profile.now(); - if (profile.secs(st-profile.cpu_start) < gathertime) - profile.gather_rate(Math.variate(hittar,hitpct)); + if (profile.secs(st - profile.cpu_start) < gathertime) profile.gather_rate(Math.variate(hittar, hitpct)); else { profile.gather_stop(); profile.cpu_start = undefined; var e = Object.values(callgraph); - e = e.sort((a,b) => { + e = e.sort((a, b) => { if (a.time > b.time) return -1; - return 1; - }); + return 1; + }); - for (var x of e) { - var ffs = x.line.split(':'); - x.timestr = profile.best_t(x.time); - var pct = profile.secs(x.time)/gathertime*100; - x.timeper = x.time / x.hits; - x.timeperstr = profile.best_t(x.timeper); - x.fncall = get_line(ffs[0], ffs[1]); - x.log =`${x.line}::${x.fn}:: ${x.timestr} (${pct.toPrecision(3)}%) (${x.hits} hits) --> ${get_line(ffs[0], ffs[1])}`; - } + for (var x of e) { + var ffs = x.line.split(":"); + x.timestr = profile.best_t(x.time); + var pct = (profile.secs(x.time) / gathertime) * 100; + x.timeper = x.time / x.hits; + x.timeperstr = profile.best_t(x.timeper); + x.fncall = get_line(ffs[0], ffs[1]); + x.log = `${x.line}::${x.fn}:: ${x.timestr} (${pct.toPrecision(3)}%) (${x.hits} hits) --> ${get_line(ffs[0], ffs[1])}`; + } - profile.cpu_instr = e; + profile.cpu_instr = e; } }); -} +}; -function push_time(arr, ob, max) -{ +function push_time(arr, ob, max) { arr.push({ - time:profile.now(), - ob + time: profile.now(), + ob, }); } profile.cpu_frames = []; profile.last_cpu_frame = undefined; -profile.cpu_frame = function() -{ - profile.gather(Math.random_range(300,600), function() { +profile.cpu_frame = function () { + profile.gather(Math.random_range(300, 600), function () { var err = new Error(); - profile.last_cpu_frame = err.stack;//.split('\n').slicconsole.stack(2); + profile.last_cpu_frame = err.stack; //.split('\n').slicconsole.stack(2); profile.gather_stop(); }); -} +}; var filecache = {}; -function get_line (file, line) { +function get_line(file, line) { var text = filecache[file]; if (!text) { var f = io.slurp(file); @@ -158,17 +154,19 @@ function get_line (file, line) { filecache[file] = "undefined"; return filecache[file]; } - filecache[file] = io.slurp(file).split('\n'); + filecache[file] = io.slurp(file).split("\n"); text = filecache[file]; } - if (typeof text === 'string') return text; - text = text[Number (line) - 1]; + if (typeof text === "string") return text; + text = text[Number(line) - 1]; if (!text) return "NULL"; return text.trim(); } -profile.stop_cpu_instr = function () { return; } +profile.stop_cpu_instr = function () { + return; +}; profile.best_t = function (t) { var qq = 0; @@ -193,26 +191,23 @@ profile.report = function (start, msg = "[undefined report]") { var frame_avg = false; profile.frame_avg_t = 72000; -profile.start_frame_avg = function() -{ +profile.start_frame_avg = function () { if (frame_avg) return; profile_frames = {}; profile_frame_ts = []; profile_cframe = profile_frames; pframe = 0; frame_avg = true; -} +}; -profile.stop_frame_avg = function() -{ +profile.stop_frame_avg = function () { frame_avg = false; -} +}; -profile.toggle_frame_avg = function() -{ +profile.toggle_frame_avg = function () { if (frame_avg) profile.stop_frame_avg(); else profile.start_frame_avg(); -} +}; var profile_framer = { series: [], @@ -223,52 +218,46 @@ var profile_cframe = undefined; var pframe = 0; var profile_stack = []; -profile.frame = function profile_frame(title) -{ +profile.frame = function profile_frame(title) { if (profile.cpu_start) return; if (!frame_avg) return; - + if (!profile_cframe) { profile_cframe = {}; profile_framer.series.push({ - time:profile.now(), - data:profile_cframe + time: profile.now(), + data: profile_cframe, }); - } else - profile_stack.push(profile_cframe); - + } else profile_stack.push(profile_cframe); + profile_cframe[title] ??= {}; profile_cframe = profile_cframe[title]; profile_cframe.time = profile.now(); -} +}; -profile.endframe = function profile_endframe() -{ +profile.endframe = function profile_endframe() { if (!frame_avg) return; profile_cframe.time = profile.now() - profile_cframe.time; profile_cframe = profile_frame_ts.pop(); -} +}; -var print_frame = function(frame, indent, title) -{ +var print_frame = function (frame, indent, title) { say(indent + `${title} ::::: ${profile.best_t(Math.mean(frame._times))} ± ${profile.best_t(Math.ci(frame._times))} (${frame._times.length} hits)`); - + for (var i in frame) { - if (i === '_times') continue; + if (i === "_times") continue; print_frame(frame[i], indent + " ", i); } -} +}; -profile.print_frame_avg = function() -{ +profile.print_frame_avg = function () { say("===FRAME AVERAGES===\n"); - + var indent = ""; - for (var i in profile_frames) - print_frame(profile_frames[i], "", 'frame'); - + for (var i in profile_frames) print_frame(profile_frames[i], "", "frame"); + say("\n"); -} +}; /* Cache reporting is to measure how long specific events take, that are NOT every frame @@ -283,47 +272,48 @@ var cachest = 0; var cachegroup; var cachetitle; -profile.cache_reporting = function() { return cache_reporting; } -profile.cache_toggle = function() { cache_reporting = !cache_reporting; } -profile.cache_dump = function() { +profile.cache_reporting = function () { + return cache_reporting; +}; +profile.cache_toggle = function () { + cache_reporting = !cache_reporting; +}; +profile.cache_dump = function () { report_cache = {}; -} +}; -profile.cache = function profile_cache(group, title) -{ +profile.cache = function profile_cache(group, title) { if (!cache_reporting) return; cachest = profile.now(); cachegroup = group; cachetitle = title; -} +}; -profile.endcache = function profile_endcache(tag = "") -{ +profile.endcache = function profile_endcache(tag = "") { addreport(cachegroup, cachetitle + tag, cachest); -} +}; function addreport(group, line, start) { - if (typeof group !== 'string') group = 'UNGROUPED'; + if (typeof group !== "string") group = "UNGROUPED"; report_cache[group] ??= {}; var cache = report_cache[group]; cache[line] ??= []; var t = profile.now(); cache[line].push(t - start); return t; -}; +} -function printreport (cache, name) { - var report = `==${name}==` + - "\n"; +function printreport(cache, name) { + var report = `==${name}==` + "\n"; var reports = []; for (var i in cache) { var time = cache[i].reduce((a, b) => a + b); reports.push({ - time : time, - name : i, - hits : cache[i].length, - avg : time / cache[i].length + time: time, + name: i, + hits: cache[i].length, + avg: time / cache[i].length, }); } reports = reports.sort((a, b) => { @@ -331,47 +321,40 @@ function printreport (cache, name) { return -1; }); - for (var rep of reports) - report += `${rep.name} ${profile.best_t(rep.avg)} (${ - rep.hits} hits) (total ${profile.best_t(rep.time)})\n`; + for (var rep of reports) report += `${rep.name} ${profile.best_t(rep.avg)} (${rep.hits} hits) (total ${profile.best_t(rep.time)})\n`; return report; -}; +} profile.data = {}; profile.curframe = 0; -function prof_add_stats (obj, stat) { +function prof_add_stats(obj, stat) { for (var i in stat) { obj[i] ??= []; if (obj[i].last() !== stat[i]) obj[i][profile.curframe] = stat[i]; } } -profile.pushdata = function(arr, val) -{ - if (arr.last() !== val) - arr[profile.curframe] = val; -} +profile.pushdata = function (arr, val) { + if (arr.last() !== val) arr[profile.curframe] = val; +}; -profile.capture_data = function() -{ +profile.capture_data = function () { prof_add_stats(profile.data.memory, os.mem()); prof_add_stats(profile.data.gfx, imgui.framestats()); prof_add_stats(profile.data.actors, actor.__stats()); profile.curframe++; -} +}; -profile.best_mem = function(bytes) -{ - var sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB']; - if (bytes == 0) return '0 Bytes'; +profile.best_mem = function (bytes) { + var sizes = ["Bytes", "KB", "MB", "GB", "TB"]; + if (bytes == 0) return "0 Bytes"; var i = parseInt(Math.floor(Math.log(bytes) / Math.log(1024))); - return (bytes / Math.pow(1024, i)).toPrecision(3) + ' ' + sizes[i]; -} + return (bytes / Math.pow(1024, i)).toPrecision(3) + " " + sizes[i]; +}; -profile.cleardata = function() -{ +profile.cleardata = function () { profile.data.gpu = {}; profile.data.physics = {}; profile.data.script = {}; @@ -383,19 +366,18 @@ profile.cleardata = function() render: [], physics: [], }; -} +}; profile.cleardata(); profile.last_mem = undefined; profile.mems = []; profile.gcs = []; -profile.print_gc = function() -{ +profile.print_gc = function () { var gc = os.check_gc(); if (!gc) return; profile.data.gc ??= []; profile.data.gc[profile.curframe] = gc; -} +}; -return {profile}; +return { profile }; diff --git a/scripts/prosperon.js b/scripts/prosperon.js index c996e018..9f671cba 100644 --- a/scripts/prosperon.js +++ b/scripts/prosperon.js @@ -2,14 +2,14 @@ globalThis.gamestate = {}; global.check_registers = function (obj) { for (var reg in Register.registries) { - if (typeof obj[reg] === 'function') { + if (typeof obj[reg] === "function") { var fn = obj[reg].bind(obj); fn.layer = obj[reg].layer; var name = obj.ur ? obj.ur.name : obj.toString(); obj.timers.push(Register.registries[reg].register(fn, name)); } } - + for (var k in obj) { if (!k.startsWith("on_")) continue; var signal = k.fromfirst("on_"); @@ -70,7 +70,7 @@ game.engine_start = function (s) { prosperon.camera = prosperon.make_camera(); var camera = prosperon.camera; - camera.transform.pos = [0,0,-100]; + camera.transform.pos = [0, 0, -100]; camera.mode = "keep"; camera.break = "fit"; camera.size = game.size; @@ -87,11 +87,11 @@ game.engine_start = function (s) { var appcam = prosperon.appcam; appcam.near = 0; appcam.size = window.size; - appcam.transform.pos = [window.size.x,window.size.y,-100]; + appcam.transform.pos = [window.size.x, window.size.y, -100]; prosperon.screencolor = render.screencolor(); - + globalThis.imgui = render.imgui_init(); - + s(); shape.quad = { @@ -109,13 +109,13 @@ game.engine_start = function (s) { count: 3, index: os.make_buffer([0, 2, 1], 1), }; - + shape.centered_quad = { pos: os.make_buffer([-0.5, -0.5, -0.5, 0.5, -0.5, -0.5, -0.5, 0.5, -0.5, 0.5, 0.5, -0.5], 0), verts: 4, - uv: os.make_buffer([0,1,1,1,0,0,1,0],2), - index: os.make_buffer([0,1,2,2,1,3],1), - count: 6 + uv: os.make_buffer([0, 1, 1, 1, 0, 0, 1, 0], 2), + index: os.make_buffer([0, 1, 2, 2, 1, 3], 1), + count: 6, }; render.init(); @@ -128,12 +128,11 @@ game.engine_start = function (s) { game.startengine = 0; -prosperon.release_mode = function() -{ +prosperon.release_mode = function () { prosperon.debug = false; mum.debug = false; debug.kill(); -} +}; prosperon.debug = true; game.timescale = 1; @@ -142,8 +141,7 @@ var eachobj = function (obj, fn) { var val = fn(obj); if (val) return val; for (var o in obj.objects) { - if (obj.objects[o] === obj) - console.error(`Object ${obj.toString()} is referenced by itself.`); + if (obj.objects[o] === obj) console.error(`Object ${obj.toString()} is referenced by itself.`); val = eachobj(obj.objects[o], fn); if (val) return val; } @@ -179,8 +177,7 @@ game.doc.pause = "Pause game simulation."; game.doc.play = "Resume or start game simulation."; game.doc.camera = "Current camera."; -game.tex_hotreload = function() -{ +game.tex_hotreload = function () { for (var path in game.texture.cache) { if (io.mod(path) > game.texture.time_cache[path]) { var tex = game.texture.cache[path]; @@ -188,17 +185,17 @@ game.tex_hotreload = function() os.texture_swap(path, game.texture.cache[path]); for (var sprite of Object.values(allsprites)) { if (sprite.texture == tex) { - sprite.tex_sync(); - } + sprite.tex_sync(); + } } } } -} +}; game.texture = function (path) { if (!path) return game.texture("icons/no_text.gif"); path = Resources.find_image(path); - + if (!io.exists(path)) { console.error(`Missing texture: ${path}`); game.texture.cache[path] = game.texture("icons/no_tex.gif"); @@ -229,8 +226,7 @@ prosperon.semver.valid = function (v, range) { if (range[0] === "~") { range[0] = range[0].slice(1); - for (var i = 0; i < 2; i++) - if (parseInt(v[i]) < parseInt(range[i])) return false; + for (var i = 0; i < 2; i++) if (parseInt(v[i]) < parseInt(range[i])) return false; return true; } @@ -251,8 +247,7 @@ prosperon.semver.cmp = function (v1, v2) { return 0; }; -prosperon.semver.cmp.doc = - "Compare two semantic version numbers, given like X.X.X."; +prosperon.semver.cmp.doc = "Compare two semantic version numbers, given like X.X.X."; prosperon.semver.valid.doc = `Test if semantic version v is valid, given a range. Range is given by a semantic versioning number, prefixed with nothing, a ~, or a ^. ~ means that MAJOR and MINOR must match exactly, but any PATCH greater or equal is valid. @@ -277,7 +272,9 @@ prosperon.quit = function () { window.size = [640, 480]; window.mode = "keep"; -window.toggle_fullscreen = function() { window.fullscreen = !window.fullscreen; } +window.toggle_fullscreen = function () { + window.fullscreen = !window.fullscreen; +}; window.set_icon.doc = "Set the icon of the window using the PNG image at path."; @@ -285,14 +282,13 @@ window.doc = {}; window.doc.dimensions = "Window width and height packaged in an array [width,height]"; window.doc.title = "Name in the title bar of the window."; window.doc.boundingbox = "Boundingbox of the window, with top and right being its height and width."; -window.__proto__.toJSON = function() -{ +window.__proto__.toJSON = function () { return { size: this.size, fullscreen: this.fullscreen, - title: this.title - }; -} + title: this.title, + }; +}; global.mixin("scripts/input"); global.mixin("scripts/std"); @@ -302,7 +298,7 @@ global.mixin("scripts/tween"); global.mixin("scripts/ai"); global.mixin("scripts/particle"); global.mixin("scripts/physics"); -global.mixin("scripts/geometry") +global.mixin("scripts/geometry"); /* Factory for creating registries. Register one with 'X.register', @@ -317,44 +313,43 @@ var Register = { n.register = function (fn, oname) { if (!(fn instanceof Function)) return; - + var guid = prosperon.guid(); - var dofn = function(...args) { - profile.cache(name,oname); + var dofn = function (...args) { + profile.cache(name, oname); var st = profile.now(); fn(...args); - profile.endcache(); - } + profile.endcache(); + }; fns.push(dofn); dofn.layer = fn.layer; dofn.layer ??= 0; - fns.sort((a,b) => a.layer > b.layer); - + fns.sort((a, b) => a.layer > b.layer); + return function () { fns.remove(dofn); }; }; if (!flush) { - prosperon[name] = function(...args) { + prosperon[name] = function (...args) { fns.forEach(fn => fn(...args)); - } - } - else - prosperon[name] = function(...args) { + }; + } else + prosperon[name] = function (...args) { var layer = undefined; for (var fn of fns) { - if (layer !== fn.layer) { - flush(); - layer = fn.layer; - } - fn(); + if (layer !== fn.layer) { + flush(); + layer = fn.layer; + } + fn(); } - } - + }; + prosperon[name].fns = fns; n.clear = function () { fns = []; @@ -384,11 +379,11 @@ var Event = { }, unobserve(name, obj) { - this.events[name] = this.events[name].filter((x) => x[0] !== obj); + this.events[name] = this.events[name].filter(x => x[0] !== obj); }, rm_obj(obj) { - Object.keys(this.events).forEach((name) => Event.unobserve(name, obj)); + Object.keys(this.events).forEach(name => Event.unobserve(name, obj)); }, notify(name, ...args) { @@ -435,5 +430,5 @@ return { sim, frame_t, physlag, - Event -} + Event, +}; diff --git a/scripts/render.js b/scripts/render.js index d0609f00..1857cb4b 100644 --- a/scripts/render.js +++ b/scripts/render.js @@ -1,62 +1,55 @@ render.doc = { doc: "Functions for rendering modes.", normal: "Final render with all lighting.", - wireframe: "Show only wireframes of models." + wireframe: "Show only wireframes of models.", }; var cur = {}; -render.use_shader = function use_shader(shader) -{ - if (typeof shader === 'string') - shader = make_shader(shader); +render.use_shader = function use_shader(shader) { + if (typeof shader === "string") shader = make_shader(shader); if (cur.shader === shader) return; cur.shader = shader; cur.bind = undefined; cur.mesh = undefined; render.setpipeline(shader.pipe); shader_globals(cur.shader); -} +}; -render.use_mat = function use_mat(mat) -{ +render.use_mat = function use_mat(mat) { if (!cur.shader) return; if (cur.mat === mat) return; shader_apply_material(cur.shader, mat, cur.mat); - + cur.mat = mat; cur.images = []; if (!cur.shader.fs.images) return; for (var img of cur.shader.fs.images) - if (mat[img.name]) - cur.images.push(mat[img.name]); - else - cur.images.push(game.texture("icons/no_tex.gif")); -} + if (mat[img.name]) cur.images.push(mat[img.name]); + else cur.images.push(game.texture("icons/no_tex.gif")); +}; var models_array = []; -function set_model(t) -{ - if (cur.shader.vs.unimap.model) - render.setunim4(0, cur.shader.vs.unimap.model.slot, t); +function set_model(t) { + if (cur.shader.vs.unimap.model) render.setunim4(0, cur.shader.vs.unimap.model.slot, t); } render.set_model = set_model; var shaderlang = { - macos: "metal_macos", - windows: "hlsl5", - linux: "glsl430", - web: "wgsl", - ios: "metal_ios", -} + macos: "metal_macos", + windows: "hlsl5", + linux: "glsl430", + web: "wgsl", + ios: "metal_ios", +}; var attr_map = { a_pos: 0, - a_uv: 1, + a_uv: 1, a_norm: 2, a_joint: 3, a_weight: 4, @@ -66,106 +59,107 @@ var attr_map = { a_wh: 8, a_st: 9, a_ppos: 10, - a_scale: 11 -} + a_scale: 11, +}; var blend_map = { mix: true, - none: false -} + none: false, +}; var primitive_map = { point: 1, line: 2, linestrip: 3, triangle: 4, - trianglestrip: 5 -} + trianglestrip: 5, +}; var cull_map = { - none: 1, - front: 2, - back: 3 -} + none: 1, + front: 2, + back: 3, +}; var depth_map = { off: false, - on: true -} + on: true, +}; var face_map = { cw: 2, - ccw: 1 -} + ccw: 1, +}; -render.poly_prim = function poly_prim(verts) -{ +render.poly_prim = function poly_prim(verts) { var index = []; if (verts.length < 1) return undefined; - - for (var i = 0; i < verts.length; i++) - verts[i][2] = 0; - + + for (var i = 0; i < verts.length; i++) verts[i][2] = 0; + for (var i = 2; i < verts.length; i++) { index.push(0); - index.push(i-1); + index.push(i - 1); index.push(i); } - + return { pos: os.make_buffer(verts.flat()), verts: verts.length, index: os.make_buffer(index, 1), - count: index.length + count: index.length, }; -} +}; -function shader_directive(shader, name, map) -{ - var reg = new RegExp(`#${name}.*`, 'g'); +function shader_directive(shader, name, map) { + var reg = new RegExp(`#${name}.*`, "g"); var mat = shader.match(reg); if (!mat) return undefined; - - reg = new RegExp(`#${name}\s*`, 'g'); - var ff = mat.map(d=>d.replace(reg,''))[0].trim(); - + + reg = new RegExp(`#${name}\s*`, "g"); + var ff = mat.map(d => d.replace(reg, ""))[0].trim(); + if (map) return map[ff]; return ff; } var uni_globals = { - time(stage, slot) { render.setuniv(stage, slot, profile.secs(profile.now())); }, - projection(stage,slot) { render.setuniproj(stage, slot); }, - view(stage,slot) { render.setuniview(stage, slot); }, - vp(stage,slot) { render.setunivp(stage,slot); }, -} + time(stage, slot) { + render.setuniv(stage, slot, profile.secs(profile.now())); + }, + projection(stage, slot) { + render.setuniproj(stage, slot); + }, + view(stage, slot) { + render.setuniview(stage, slot); + }, + vp(stage, slot) { + render.setunivp(stage, slot); + }, +}; function set_global_uni(uni, stage) { - uni_globals[uni.name]?.(stage, uni.slot); + uni_globals[uni.name]?.(stage, uni.slot); } var setcam = render.set_camera; -render.set_camera = function(cam) -{ +render.set_camera = function (cam) { if (nextflush) { nextflush(); nextflush = undefined; } delete cur.shader; setcam(cam); -} +}; var shader_cache = {}; var shader_times = {}; -function strip_shader_inputs(shader) -{ - for (var a of shader.vs.inputs) - a.name = a.name.slice(2); +function strip_shader_inputs(shader) { + for (var a of shader.vs.inputs) a.name = a.name.slice(2); } -render.hotreload = function() -{ +render.hotreload = function () { for (var i in shader_times) { if (io.mod(i) <= shader_times[i]) continue; say(`HOT RELOADING SHADER ${i}`); @@ -178,37 +172,36 @@ render.hotreload = function() cur.bind = undefined; cur.mesh = undefined; } -} +}; -function create_shader_obj(file) -{ +function create_shader_obj(file) { var files = [file]; var out = ".prosperon/tmp.shader"; var shader = io.slurp(file); var incs = shader.match(/#include <.*>/g); if (incs) - for (var inc of incs) { - var filez = inc.match(/#include <(.*)>/)[1]; - var macro = io.slurp(filez); - if (!macro) { - filez = `shaders/${filez}`; - macro = io.slurp(filez); + for (var inc of incs) { + var filez = inc.match(/#include <(.*)>/)[1]; + var macro = io.slurp(filez); + if (!macro) { + filez = `shaders/${filez}`; + macro = io.slurp(filez); + } + shader = shader.replace(inc, macro); + files.push(filez); } - shader = shader.replace(inc, macro); - files.push(filez); - } - - var blend = shader_directive(shader, 'blend', blend_map); - var primitive = shader_directive(shader, 'primitive', primitive_map); - var cull = shader_directive(shader, 'cull', cull_map); - var depth = shader_directive(shader, 'depth', depth_map); - var face = shader_directive(shader, 'face', face_map); - var indexed = shader_directive(shader, 'indexed'); - - if (typeof indexed == 'undefined') indexed = true; - if (indexed === 'false') indexed = false; - + + var blend = shader_directive(shader, "blend", blend_map); + var primitive = shader_directive(shader, "primitive", primitive_map); + var cull = shader_directive(shader, "cull", cull_map); + var depth = shader_directive(shader, "depth", depth_map); + var face = shader_directive(shader, "face", face_map); + var indexed = shader_directive(shader, "indexed"); + + if (typeof indexed == "undefined") indexed = true; + if (indexed === "false") indexed = false; + shader = shader.replace(/uniform\s+(\w+)\s+(\w+);/g, "uniform _$2 { $1 $2; };"); shader = shader.replace(/(texture2D|sampler) /g, "uniform $1 "); @@ -225,79 +218,76 @@ function create_shader_obj(file) return; } - /* Take YAML and create the shader object */ - var yamlfile = `${out}_reflection.yaml`; - var jjson = yaml.tojson(io.slurp(yamlfile)); - var obj = json.decode(jjson); - io.rm(yamlfile); - - obj = obj.shaders[0].programs[0]; - function add_code(stage) { - stage.code = io.slurp(stage.path); + /* Take YAML and create the shader object */ + var yamlfile = `${out}_reflection.yaml`; + var jjson = yaml.tojson(io.slurp(yamlfile)); + var obj = json.decode(jjson); + io.rm(yamlfile); - io.rm(stage.path); - delete stage.path; - } + obj = obj.shaders[0].programs[0]; + function add_code(stage) { + stage.code = io.slurp(stage.path); - add_code(obj.vs); - if (!obj.fs && obj.vs.fs) { - obj.fs = obj.vs.fs; - delete obj.vs.fs; - } - - add_code(obj.fs); - - obj.blend = blend; - obj.cull = cull; - obj.primitive = primitive; - obj.depth = depth; - obj.face = face; - obj.indexed = indexed; - - if (obj.vs.inputs) - for (var i of obj.vs.inputs) { - if (!(i.name in attr_map)) - i.mat = -1; - else - i.mat = attr_map[i.name]; + io.rm(stage.path); + delete stage.path; } - - function make_unimap(stage) { - if (!stage.uniform_blocks) return {}; - var unimap = {}; - for (var uni of stage.uniform_blocks) { - var uniname = uni.struct_name[0] == "_" ? uni.struct_name.slice(1) : uni.struct_name; - - unimap[uniname] = { - name: uniname, - slot: Number(uni.slot), - size: Number(uni.size) - }; + + add_code(obj.vs); + if (!obj.fs && obj.vs.fs) { + obj.fs = obj.vs.fs; + delete obj.vs.fs; } - - return unimap; - } - - obj.vs.unimap = make_unimap(obj.vs); - obj.fs.unimap = make_unimap(obj.fs); - - obj.name = file; - strip_shader_inputs(obj); + add_code(obj.fs); - compiled[platform] = obj; + obj.blend = blend; + obj.cull = cull; + obj.primitive = primitive; + obj.depth = depth; + obj.face = face; + obj.indexed = indexed; + + if (obj.vs.inputs) + for (var i of obj.vs.inputs) { + if (!(i.name in attr_map)) i.mat = -1; + else i.mat = attr_map[i.name]; + } + + function make_unimap(stage) { + if (!stage.uniform_blocks) return {}; + var unimap = {}; + for (var uni of stage.uniform_blocks) { + var uniname = uni.struct_name[0] == "_" ? uni.struct_name.slice(1) : uni.struct_name; + + unimap[uniname] = { + name: uniname, + slot: Number(uni.slot), + size: Number(uni.size), + }; + } + + return unimap; + } + + obj.vs.unimap = make_unimap(obj.vs); + obj.fs.unimap = make_unimap(obj.fs); + + obj.name = file; + + strip_shader_inputs(obj); + + compiled[platform] = obj; } compiled.files = files; compiled.source = shader; - + return compiled; } -function make_shader(shader) -{ +function make_shader(shader) { if (shader_cache[shader]) return shader_cache[shader]; - + var file = shader; shader = io.slurp(file); if (!shader) { @@ -307,7 +297,7 @@ function make_shader(shader) var writejson = `.prosperon/${file.name()}.shader.json`; profile.cache("shader", file); - + breakme: if (io.exists(writejson)) { var data = json.decode(io.slurp(writejson)); var filemod = io.mod(writejson); @@ -326,7 +316,7 @@ function make_shader(shader) shader_times[file] = io.mod(file); return obj; } - + var compiled = create_shader_obj(file); io.slurpwrite(writejson, json.encode(compiled)); var obj = compiled[os.sys()]; @@ -334,7 +324,7 @@ function make_shader(shader) shader_cache[file] = obj; shader_times[file] = io.mod(file); - + return obj; } @@ -342,77 +332,66 @@ var shader_unisize = { 4: render.setuniv, 8: render.setuniv2, 12: render.setuniv3, - 16: render.setuniv4 + 16: render.setuniv4, }; -function shader_globals(shader) -{ - for (var p in shader.vs.unimap) - set_global_uni(shader.vs.unimap[p], 0); - - for (var p in shader.fs.unimap) - set_global_uni(shader.fs.unimap[p], 1); +function shader_globals(shader) { + for (var p in shader.vs.unimap) set_global_uni(shader.vs.unimap[p], 0); + + for (var p in shader.fs.unimap) set_global_uni(shader.fs.unimap[p], 1); } - -function shader_apply_material(shader, material = {}, old = {}) -{ + +function shader_apply_material(shader, material = {}, old = {}) { for (var p in shader.vs.unimap) { if (!(p in material)) continue; if (material[p] === old[p]) continue; assert(p in material, `shader ${shader.name} has no uniform for ${p}`); var s = shader.vs.unimap[p]; - - if (p === 'bones') { + + if (p === "bones") { render.setunibones(0, s.slot, material[p]); continue; } shader_unisize[s.size](0, s.slot, material[p]); } - + for (var p in shader.fs.unimap) { if (!(p in material)) continue; if (material[p] === old[p]) continue; - assert(p in material, `shader ${shader.name} has no uniform for ${p}`); + assert(p in material, `shader ${shader.name} has no uniform for ${p}`); var s = shader.fs.unimap[p]; shader_unisize[s.size](1, s.slot, material[p]); } - + if (!material.diffuse) return; if (material.diffuse === old.diffuse) return; - - if ("diffuse_size" in shader.fs.unimap) - render.setuniv2(1, shader.fs.unimap.diffuse_size.slot, [material.diffuse.width, material.diffuse.height]); - if ("diffuse_size" in shader.vs.unimap) - render.setuniv2(0, shader.vs.unimap.diffuse_size.slot, [material.diffuse.width, material.diffuse.height]); + if ("diffuse_size" in shader.fs.unimap) render.setuniv2(1, shader.fs.unimap.diffuse_size.slot, [material.diffuse.width, material.diffuse.height]); + + if ("diffuse_size" in shader.vs.unimap) render.setuniv2(0, shader.vs.unimap.diffuse_size.slot, [material.diffuse.width, material.diffuse.height]); } -function sg_bind(mesh, ssbo) -{ +function sg_bind(mesh, ssbo) { cur.mesh = mesh; - + var bind = {}; bind.attrib = []; if (cur.shader.vs.inputs) - for (var a of cur.shader.vs.inputs) { - if (!(a.name in mesh)) { - console.error(`cannot draw shader ${cur.shader.name}; there is no attrib ${a.name} in the given mesh. ${json.encode(mesh)}`); - return undefined; - } else - bind.attrib.push(mesh[a.name]); - } - + for (var a of cur.shader.vs.inputs) { + if (!(a.name in mesh)) { + console.error(`cannot draw shader ${cur.shader.name}; there is no attrib ${a.name} in the given mesh. ${json.encode(mesh)}`); + return undefined; + } else bind.attrib.push(mesh[a.name]); + } + if (cur.shader.indexed) { bind.index = mesh.index; bind.count = mesh.count; - } else - bind.count = mesh.verts; - + } else bind.count = mesh.verts; + bind.ssbo = []; - if (cur.shader.vs.storage_buffers) - for (var b of cur.shader.vs.storage_buffers) - bind.ssbo.push(ssbo); + if (cur.shader.vs.storage_buffers) for (var b of cur.shader.vs.storage_buffers) bind.ssbo.push(ssbo); bind.inst = 1; bind.images = cur.images; @@ -420,42 +399,42 @@ function sg_bind(mesh, ssbo) cur.bind = bind; render.setbind(cur.bind); - + return bind; } render.device = { - pc: [1920,1080], - macbook_m2: [2560,1664, 13.6], - ds_top: [400,240, 3.53], - ds_bottom: [320,240, 3.02], - playdate: [400,240,2.7], - switch: [1280,720, 6.2], - switch_lite: [1280,720,5.5], - switch_oled: [1280,720,7], - dsi: [256,192,3.268], - ds: [256,192, 3], - dsixl: [256,192,4.2], - ipad_air_m2: [2360,1640, 11.97], + pc: [1920, 1080], + macbook_m2: [2560, 1664, 13.6], + ds_top: [400, 240, 3.53], + ds_bottom: [320, 240, 3.02], + playdate: [400, 240, 2.7], + switch: [1280, 720, 6.2], + switch_lite: [1280, 720, 5.5], + switch_oled: [1280, 720, 7], + dsi: [256, 192, 3.268], + ds: [256, 192, 3], + dsixl: [256, 192, 4.2], + ipad_air_m2: [2360, 1640, 11.97], iphone_se: [1334, 750, 4.7], - iphone_12_pro: [2532,1170,6.06], - iphone_15: [2556,1179,6.1], - gba: [240,160,2.9], - gameboy: [160,144,2.48], - gbc: [160,144,2.28], - steamdeck: [1280,800,7], - vita: [960,544,5], - psp: [480,272,4.3], - imac_m3: [4480,2520,23.5], - macbook_pro_m3: [3024,1964, 14.2], - ps1: [320,240,5], - ps2: [640,480], - snes: [256,224], - gamecube: [640,480], - n64: [320,240], - c64: [320,200], - macintosh: [512,342,9], - gamegear: [160,144,3.2], + iphone_12_pro: [2532, 1170, 6.06], + iphone_15: [2556, 1179, 6.1], + gba: [240, 160, 2.9], + gameboy: [160, 144, 2.48], + gbc: [160, 144, 2.28], + steamdeck: [1280, 800, 7], + vita: [960, 544, 5], + psp: [480, 272, 4.3], + imac_m3: [4480, 2520, 23.5], + macbook_pro_m3: [3024, 1964, 14.2], + ps1: [320, 240, 5], + ps2: [640, 480], + snes: [256, 224], + gamecube: [640, 480], + n64: [320, 240], + c64: [320, 200], + macintosh: [512, 342, 9], + gamegear: [160, 144, 3.2], }; render.device.doc = `Device resolutions given as [x,y,inches diagonal].`; @@ -470,7 +449,7 @@ var polyssboshader; var sprite_ssbo; -render.init = function() { +render.init = function () { textshader = make_shader("shaders/text_base.cg"); render.spriteshader = make_shader("shaders/sprite.cg"); spritessboshader = make_shader("shaders/sprite_ssbo.cg"); @@ -482,38 +461,38 @@ render.init = function() { polyssboshader = make_shader("shaders/poly_ssbo.cg"); poly_ssbo = render.make_textssbo(); sprite_ssbo = render.make_textssbo(); - + render.textshader = textshader; - - os.make_circle2d().draw = function() { - render.circle(this.body().transform().pos, this.radius, [1,1,0,1]); - } - - var disabled = [148/255,148/255, 148/255, 1]; - var sleep = [1, 140/255, 228/255, 1]; - var dynamic = [1, 70/255, 46/255, 1]; - var kinematic = [1, 194/255, 64/255, 1]; - var static_color = [73/255, 209/255, 80/255, 1]; - - os.make_poly2d().draw = function() { + + os.make_circle2d().draw = function () { + render.circle(this.body().transform().pos, this.radius, [1, 1, 0, 1]); + }; + + var disabled = [148 / 255, 148 / 255, 148 / 255, 1]; + var sleep = [1, 140 / 255, 228 / 255, 1]; + var dynamic = [1, 70 / 255, 46 / 255, 1]; + var kinematic = [1, 194 / 255, 64 / 255, 1]; + var static_color = [73 / 255, 209 / 255, 80 / 255, 1]; + + os.make_poly2d().draw = function () { var body = this.body(); - var color = body.sleeping() ? [0,0.3,0,0.4] : [0,1,0,0.4]; + var color = body.sleeping() ? [0, 0.3, 0, 0.4] : [0, 1, 0, 0.4]; var t = body.transform(); render.poly(this.points, color, body.transform()); color.a = 1; render.line(this.points.wrapped(1), color, 1, body.transform()); - } - - os.make_seg2d().draw = function() { - render.line([this.a(), this.b()], [1,0,1,1], Math.max(this.radius/2, 1), this.body().transform()); - } - - joint.pin().draw = function() { + }; + + os.make_seg2d().draw = function () { + render.line([this.a(), this.b()], [1, 0, 1, 1], Math.max(this.radius / 2, 1), this.body().transform()); + }; + + joint.pin().draw = function () { var a = this.bodyA(); var b = this.bodyB(); - render.line([a.transform().pos.xy, b.transform().pos.xy], [0,1,1,1], 1); - } -} + render.line([a.transform().pos.xy, b.transform().pos.xy], [0, 1, 1, 1], 1); + }; +}; render.draw_sprites = true; render.draw_particles = true; @@ -521,47 +500,44 @@ render.draw_hud = true; render.draw_gui = true; render.draw_gizmos = true; -render.sprites = function render_sprites(gridsize = 1) -{ +render.sprites = function render_sprites(gridsize = 1) { // When y sorting, draw layer is firstly important followed by the gameobject position var buckets; if (render.y_sort) { - profile.frame("y bucketing"); - var sps = Object.values(allsprites); - buckets = {}; - - for (var sprite of sps) { - var layer = (sprite.gameobject.drawlayer*10000)-sprite.gameobject.pos.y; - buckets[layer] ??= {}; - if (buckets[layer][sprite.path]) - buckets[layer][sprite.path].push(sprite); - else - buckets[layer][sprite.path] = [sprite]; - } + profile.frame("y bucketing"); + var sps = Object.values(allsprites); + buckets = {}; - profile.endframe(); + for (var sprite of sps) { + var layer = sprite.gameobject.drawlayer * 10000 - sprite.gameobject.pos.y; + buckets[layer] ??= {}; + if (buckets[layer][sprite.path]) buckets[layer][sprite.path].push(sprite); + else buckets[layer][sprite.path] = [sprite]; + } - profile.frame("y sorting"); - buckets = Object.entries(buckets).sort((a,b) => { - var na = Number(a[0]); - var nb = Number(b[0]); - if (na < nb) return -1; - return 1; - }); - profile.endframe(); + profile.endframe(); + + profile.frame("y sorting"); + buckets = Object.entries(buckets).sort((a, b) => { + var na = Number(a[0]); + var nb = Number(b[0]); + if (na < nb) return -1; + return 1; + }); + profile.endframe(); } else { - profile.frame("sorting"); - var sprite_buckets = component.sprite_buckets(); - - var buckets = Object.entries(sprite_buckets).sort((a,b) => { - var na = Number(a[0]); - var nb = Number(b[0]); - if (na < nb) return -1; - return 1; - }); - profile.endframe(); + profile.frame("sorting"); + var sprite_buckets = component.sprite_buckets(); + + var buckets = Object.entries(sprite_buckets).sort((a, b) => { + var na = Number(a[0]); + var nb = Number(b[0]); + if (na < nb) return -1; + return 1; + }); + profile.endframe(); } -/* + /* profile.frame("bucketing"); var sps = Object.values(allsprites); @@ -584,26 +560,24 @@ render.sprites = function render_sprites(gridsize = 1) render.use_shader(spritessboshader); for (var layer of buckets) { for (var img of Object.values(layer[1])) { - var sparray = Object.values(img); - if (sparray.length === 0) continue; - var ss = sparray[0]; - render.use_mat(ss); - render.make_sprite_ssbo(sparray, sprite_ssbo); - render.draw(shape.quad, sprite_ssbo, sparray.length); - if (debug.sprite_nums) render.text(ss.diffuse.getid(), ss.transform.pos); + var sparray = Object.values(img); + if (sparray.length === 0) continue; + var ss = sparray[0]; + render.use_mat(ss); + render.make_sprite_ssbo(sparray, sprite_ssbo); + render.draw(shape.quad, sprite_ssbo, sparray.length); + if (debug.sprite_nums) render.text(ss.diffuse.getid(), ss.transform.pos); } } profile.endframe(); -} +}; render.circle = function render_circle(pos, radius, color, inner_radius = 1) { check_flush(undefined); - if (inner_radius >= 1) - inner_radius = inner_radius/radius; - else if (inner_radius < 0) - inner_radius = 1.0; - + if (inner_radius >= 1) inner_radius = inner_radius / radius; + else if (inner_radius < 0) inner_radius = 1.0; + var mat = { radius: radius, inner_r: inner_radius, @@ -613,30 +587,27 @@ render.circle = function render_circle(pos, radius, color, inner_radius = 1) { render.use_shader(circleshader); render.use_mat(mat); render.draw(shape.quad); -} +}; render.circle.doc = "Draw a circle at pos, with a given radius and color. If inner_radius is between 0 and 1, it acts as a percentage of radius. If it is above 1, is acts as a unit (usually a pixel)."; render.poly = function render_poly(points, color, transform) { var buffer = render.poly_prim(points); - var mat = { shade: color}; + var mat = { shade: color }; render.use_shader(polyshader); set_model(transform); render.use_mat(mat); render.draw(buffer); -} +}; var nextflush = undefined; -function flush() -{ +function flush() { nextflush?.(); nextflush = undefined; } // If flush_fn was already on deck, it does not flush. Otherwise, flushes and then sets the flush fn -function check_flush(flush_fn) -{ - if (!nextflush) - nextflush = flush_fn; +function check_flush(flush_fn) { + if (!nextflush) nextflush = flush_fn; else if (nextflush !== flush_fn) { nextflush(); nextflush = flush_fn; @@ -649,139 +620,123 @@ var poly_cache = []; var poly_idx = 0; var poly_ssbo; -function poly_e() -{ +function poly_e() { var e; poly_idx++; if (poly_idx > poly_cache.length) { e = { - transform:os.make_transform(), - color: Color.white + transform: os.make_transform(), + color: Color.white, }; poly_cache.push(e); return e; } - var e = poly_cache[poly_idx-1]; + var e = poly_cache[poly_idx - 1]; e.transform.unit(); return e; } -function flush_poly() -{ +function flush_poly() { if (poly_idx === 0) return; render.use_shader(polyssboshader); render.use_mat({}); - render.make_particle_ssbo(poly_cache.slice(0,poly_idx), poly_ssbo); + render.make_particle_ssbo(poly_cache.slice(0, poly_idx), poly_ssbo); render.draw(shape.centered_quad, poly_ssbo, poly_idx); poly_idx = 0; } -function flush_image() -{ - -} +function flush_image() {} render.line = function render_line(points, color = Color.white, thickness = 1) { - for (var i = 0; i < points.length-1; i++) { + for (var i = 0; i < points.length - 1; i++) { var a = points[i]; - var b = points[i+1]; + var b = points[i + 1]; var poly = poly_e(); - var dist = vector.distance(a,b); - poly.transform.move(vector.midpoint(a,b)); - poly.transform.rotate([0,0,-1], vector.angle([b.x-a.x, b.y-a.y])); + var dist = vector.distance(a, b); + poly.transform.move(vector.midpoint(a, b)); + poly.transform.rotate([0, 0, -1], vector.angle([b.x - a.x, b.y - a.y])); poly.transform.scale = [dist, thickness, 1]; poly.color = color; } check_flush(flush_poly); -} +}; /* All draw in screen space */ -render.point = function(pos,size,color = Color.blue) { - render.circle(pos,size,size,color); +render.point = function (pos, size, color = Color.blue) { + render.circle(pos, size, size, color); }; - + render.cross = function render_cross(pos, size, color = Color.red, thickness = 1) { - var a = [ - pos.add([0,size]), - pos.add([0,-size]) - ]; - var b = [ - pos.add([size,0]), - pos.add([-size,0]) - ]; - render.line(a,color,thickness); - render.line(b,color,thickness); + var a = [pos.add([0, size]), pos.add([0, -size])]; + var b = [pos.add([size, 0]), pos.add([-size, 0])]; + render.line(a, color, thickness); + render.line(b, color, thickness); }; - + render.arrow = function render_arrow(start, end, color = Color.red, wingspan = 4, wingangle = 10) { var dir = end.sub(start).normalized(); - var wing1 = [ - Vector.rotate(dir, wingangle).scale(wingspan).add(end), - end - ]; - var wing2 = [ - Vector.rotate(dir,-wingangle).scale(wingspan).add(end), - end - ]; - render.line([start,end],color); - render.line(wing1,color); - render.line(wing2,color); + var wing1 = [Vector.rotate(dir, wingangle).scale(wingspan).add(end), end]; + var wing2 = [Vector.rotate(dir, -wingangle).scale(wingspan).add(end), end]; + render.line([start, end], color); + render.line(wing1, color); + render.line(wing2, color); }; render.coordinate = function render_coordinate(pos, size, color) { - render.text(JSON.stringify(pos.map(p=>Math.round(p))), pos, size, color); + render.text(JSON.stringify(pos.map(p => Math.round(p))), pos, size, color); render.point(pos, 2, color); -} +}; render.boundingbox = function render_boundingbox(bb, color = Color.white) { render.line(bbox.topoints(bb).wrapped(1), color); -} +}; render.rectangle = function render_rectangle(lowerleft, upperright, color) { var transform = os.make_transform(); - var wh = [upperright.x-lowerleft.x, upperright.y-lowerleft.y]; + var wh = [upperright.x - lowerleft.x, upperright.y - lowerleft.y]; var poly = poly_e(); - poly.transform.move(vector.midpoint(lowerleft,upperright)); - poly.transform.scale = [wh.x,wh.y,1]; + poly.transform.move(vector.midpoint(lowerleft, upperright)); + poly.transform.scale = [wh.x, wh.y, 1]; poly.color = color; check_flush(flush_poly); }; - + render.box = function render_box(pos, wh, color = Color.white) { var poly = poly_e(); poly.transform.move(pos); - poly.transform.scale = [wh.x,wh.y,1]; + poly.transform.scale = [wh.x, wh.y, 1]; poly.color = color; - check_flush(flush_poly); + check_flush(flush_poly); }; -render.window = function render_window(pos, wh, color) { render.box(pos.add(wh.scale(0.5)),wh,color); }; +render.window = function render_window(pos, wh, color) { + render.box(pos.add(wh.scale(0.5)), wh, color); +}; -render.text_bb = function(str, size = 1, wrap = -1, pos = [0,0]) -{ - var bb = render.text_size(str,size,wrap); - var w = (bb.r - bb.l); - var h = (bb.t - bb.b); +render.text_bb = function (str, size = 1, wrap = -1, pos = [0, 0]) { + var bb = render.text_size(str, size, wrap); + var w = bb.r - bb.l; + var h = bb.t - bb.b; bb.r += pos.x; bb.l += pos.x; bb.t += pos.y; bb.b += pos.y; return bb; -} +}; -render.text = function(str, pos, size = 1, color = Color.white, wrap = -1, anchor = [0,1], cursor = -1) { +render.text = function (str, pos, size = 1, color = Color.white, wrap = -1, anchor = [0, 1], cursor = -1) { var bb = render.text_bb(str, size, wrap, pos); gui.text(str, pos, size, color, wrap, cursor); // this puts text into buffer check_flush(render.flush_text); return bb; - + p.x -= w * anchor.x; - bb.r += (w*anchor.x); - bb.l += (w*anchor.x); + bb.r += w * anchor.x; + bb.l += w * anchor.x; p.y += h * (1 - anchor.y); - bb.t += h*(1-anchor.y); - bb.b += h*(1-anchor.y); + bb.t += h * (1 - anchor.y); + bb.b += h * (1 - anchor.y); return bb; }; @@ -790,36 +745,34 @@ var lasttex = undefined; var img_cache = []; var img_idx = 0; -function flush_img() -{ +function flush_img() { if (img_idx === 0) return; render.use_shader(spritessboshader); - render.use_mat({diffuse:lasttex}); - render.make_sprite_ssbo(img_cache.slice(0,img_idx), poly_ssbo); + render.use_mat({ diffuse: lasttex }); + render.make_sprite_ssbo(img_cache.slice(0, img_idx), poly_ssbo); render.draw(shape.quad, poly_ssbo, img_idx); lasttex = undefined; img_idx = 0; } -function img_e() -{ +function img_e() { img_idx++; if (img_idx > img_cache.length) { e = { transform: os.make_transform(), shade: Color.white, - rect: [0,0,1,1] + rect: [0, 0, 1, 1], }; img_cache.push(e); return e; } - var e = img_cache[img_idx-1]; + var e = img_cache[img_idx - 1]; e.transform.unit(); return e; } -render.image = function(tex, pos, scale, rotation = 0, color = Color.white) { - if (typeof tex === 'string') { +render.image = function (tex, pos, scale, rotation = 0, color = Color.white) { + if (typeof tex === "string") { tex = game.texture(tex); scale.x ??= tex.width; scale.y ??= tex.height; @@ -827,142 +780,131 @@ render.image = function(tex, pos, scale, rotation = 0, color = Color.white) { if (!tex) return; if (!lasttex) { - check_flush(flush_img); + check_flush(flush_img); lasttex = tex; } - + if (lasttex !== tex) { flush_img(); lasttex = tex; } - + var e = img_e(); e.transform.move(pos); - if (scale) - e.transform.scale = scale.div([tex.width, tex.height]); + if (scale) e.transform.scale = scale.div([tex.width, tex.height]); e.shade = color; return; var bb = {}; bb.b = pos.y; bb.l = pos.x; - bb.t = pos.y + tex.height*scale; - bb.r = pos.x + tex.width*scale; + bb.t = pos.y + tex.height * scale; + bb.r = pos.x + tex.width * scale; return bb; -} - +}; // pos is the lower left corner, scale is the width and height -render.slice9 = function(tex, pos, bb, scale = [tex.width,tex.height], color = Color.white) -{ +render.slice9 = function (tex, pos, bb, scale = [tex.width, tex.height], color = Color.white) { var t = os.make_transform(); t.pos = pos; - t.scale = [scale.x/tex.width,scale.y/tex.height,1]; + t.scale = [scale.x / tex.width, scale.y / tex.height, 1]; var border; - if (typeof bb === 'number') - border = [bb/tex.width,bb/tex.height,bb/tex.width,bb/tex.height]; - else - border = [bb.l/tex.width, bb.b/tex.height, bb.r/tex.width, bb.t/tex.height]; + if (typeof bb === "number") border = [bb / tex.width, bb / tex.height, bb / tex.width, bb / tex.height]; + else border = [bb.l / tex.width, bb.b / tex.height, bb.r / tex.width, bb.t / tex.height]; render.use_shader(slice9shader); set_model(t); render.use_mat({ shade: color, - diffuse:tex, - rect:[0,0,1,1], + diffuse: tex, + rect: [0, 0, 1, 1], border: border, - scale: [scale.x/tex.width,scale.y/tex.height] + scale: [scale.x / tex.width, scale.y / tex.height], }); render.draw(shape.quad); -} +}; -function endframe() -{ +function endframe() { tdraw = 0; } var textssbos = []; var tdraw = 0; -render.flush_text = function() -{ +render.flush_text = function () { if (!render.textshader) return; tdraw++; - if (textssbos.length < tdraw) - textssbos.push(render.make_textssbo()); - - var textssbo = textssbos[tdraw-1]; + if (textssbos.length < tdraw) textssbos.push(render.make_textssbo()); + + var textssbo = textssbos[tdraw - 1]; var amt = render.flushtext(textssbo); // load from buffer into ssbo - + if (amt === 0) { tdraw--; - return; - } - + return; + } + render.use_shader(render.textshader); - render.use_mat({text:render.font.texture}); - + render.use_mat({ text: render.font.texture }); + render.draw(shape.quad, textssbo, amt); -} +}; var fontcache = {}; -render.set_font = function(path, size) { +render.set_font = function (path, size) { var fontstr = `${path}-${size}`; if (render.font && fontcache[fontstr] === render.font) return; if (!fontcache[fontstr]) fontcache[fontstr] = os.make_font(path, size); - + render.flush_text(); gui.font_set(fontcache[fontstr]); render.font = fontcache[fontstr]; -} +}; render.doc = "Draw shapes in screen space."; render.cross.doc = "Draw a cross centered at pos, with arm length size."; render.arrow.doc = "Draw an arrow from start to end, with wings of length wingspan at angle wingangle."; render.rectangle.doc = "Draw a rectangle, with its corners at lowerleft and upperright."; -render.draw = function render_draw(mesh, ssbo, inst = 1, e_start = 0) -{ +render.draw = function render_draw(mesh, ssbo, inst = 1, e_start = 0) { sg_bind(mesh, ssbo); profile.frame("gpu"); render.spdraw(e_start, cur.bind.count, inst); profile.endframe(); -} +}; // Returns an array in the form of [left, bottom, right, top] in pixels of the camera to render to // Camera viewport is [left,bottom,width,height] in relative values -function camviewport() -{ - var aspect = (this.viewport[2]-this.viewport[0])/(this.viewport[3]-this.viewport[1])*window.size.x/window.size.y; - var raspect = this.size.x/this.size.y; +function camviewport() { + var aspect = (((this.viewport[2] - this.viewport[0]) / (this.viewport[3] - this.viewport[1])) * window.size.x) / window.size.y; + var raspect = this.size.x / this.size.y; - var left = this.viewport[0]*window.size.x; - var bottom = this.viewport[1]*window.size.y; + var left = this.viewport[0] * window.size.x; + var bottom = this.viewport[1] * window.size.y; var usemode = this.mode; - if (this.break && this.size.x > window.size.x && this.size.y > window.size.y) - usemode = this.break; + if (this.break && this.size.x > window.size.x && this.size.y > window.size.y) usemode = this.break; if (usemode === "fit") if (raspect < aspect) usemode = "height"; else usemode = "width"; - switch(usemode) { + switch (usemode) { case "stretch": case "expand": return [0, 0, window.size.x, window.size.y]; case "keep": - return [left, bottom, left+this.size.x, bottom+this.size.y]; + return [left, bottom, left + this.size.x, bottom + this.size.y]; case "height": - var ret = [left, 0, this.size.x*(window.size.y/this.size.y), window.size.y]; - ret[0] = (window.size.x-(ret[2]-ret[0]))/2; + var ret = [left, 0, this.size.x * (window.size.y / this.size.y), window.size.y]; + ret[0] = (window.size.x - (ret[2] - ret[0])) / 2; return ret; case "width": - var ret = [0, bottom, window.size.x, this.size.y*(window.size.x/this.size.x)]; - ret[1] = (window.size.y-(ret[3]-ret[1]))/2; + var ret = [0, bottom, window.size.x, this.size.y * (window.size.x / this.size.x)]; + ret[1] = (window.size.y - (ret[3] - ret[1])) / 2; return ret; } @@ -970,12 +912,11 @@ function camviewport() } // pos is pixels on the screen, lower left[0,0] -function camscreen2world(pos) -{ +function camscreen2world(pos) { var view = this.screen2cam(pos); view.x *= this.size.x; view.y *= this.size.y; - view = view.sub([this.size.x/2, this.size.y/2]); + view = view.sub([this.size.x / 2, this.size.y / 2]); view = view.add(this.pos.xy); return view; } @@ -985,79 +926,85 @@ function camscreen2world(pos) // camera coordinates, normalized from 0 to 1 inside of a camera's viewport, bottom left is 0,0, top right is 1,1 // screen coordinates, pixels, 0,0 at the bottom left of the window and [w,h] at the top right of the screen -camscreen2world.doc = "Convert a view position for a camera to world." +camscreen2world.doc = "Convert a view position for a camera to world."; // return camera coordinates given a screen position -function screen2cam(pos) -{ +function screen2cam(pos) { var viewport = this.view(); var width = viewport[2]; var height = viewport[3]; - var viewpos = pos.sub([viewport[0],viewport[1]]); - return viewpos.div([width,height]); + var viewpos = pos.sub([viewport[0], viewport[1]]); + return viewpos.div([width, height]); } -function camextents() -{ - var half = this.size;//.scale(0.5); +function camextents() { + var half = this.size; //.scale(0.5); return { - l: this.pos.x-half.x, - r: this.pos.x+half.x, - t:this.pos.y+half.y, - b:this.pos.y-half.y + l: this.pos.x - half.x, + r: this.pos.x + half.x, + t: this.pos.y + half.y, + b: this.pos.y - half.y, }; } -screen2cam.doc = "Convert a screen space position in pixels to a normalized viewport position in a camera." +screen2cam.doc = "Convert a screen space position in pixels to a normalized viewport position in a camera."; -prosperon.gizmos = function() -{ +prosperon.gizmos = function () { game.all_objects(o => { if (o.gizmo) render.image(game.texture(o.gizmo), o.pos); }); -} +}; -prosperon.make_camera = function() -{ +prosperon.make_camera = function () { var cam = world.spawn(); cam.near = 0.1; cam.far = 1000; cam.ortho = true; - cam.viewport = [0,0,1,1]; + cam.viewport = [0, 0, 1, 1]; cam.size = window.size.slice(); // The render size of this camera in pixels // In ortho mode, this determines how many pixels it will see cam.mode = "stretch"; cam.screen2world = camscreen2world; cam.screen2cam = screen2cam; cam.extents = camextents; - cam.mousepos = function() { return this.screen2world(input.mouse.screenpos()); } + cam.mousepos = function () { + return this.screen2world(input.mouse.screenpos()); + }; cam.view = camviewport; cam.offscreen = false; return cam; -} +}; var screencolor; -globalThis.imtoggle = function(name, obj, field) { obj[field] = imgui.checkbox(name, obj[field]); } +globalThis.imtoggle = function (name, obj, field) { + obj[field] = imgui.checkbox(name, obj[field]); +}; var replstr = ""; -var imdebug = function() -{ - imtoggle("Physics", debug, 'draw_phys'); - imtoggle("Bouning boxes", debug, 'draw_bb'); - imtoggle("Gizmos", debug, 'draw_gizmos'); - imtoggle("Names", debug, 'draw_names'); - imtoggle("Sprite nums", debug, 'sprite_nums'); - imtoggle("Debug overlay", debug, 'show'); - imtoggle("Show ur names", debug, 'urnames'); -} +var imdebug = function () { + imtoggle("Physics", debug, "draw_phys"); + imtoggle("Bouning boxes", debug, "draw_bb"); + imtoggle("Gizmos", debug, "draw_gizmos"); + imtoggle("Names", debug, "draw_names"); + imtoggle("Sprite nums", debug, "sprite_nums"); + imtoggle("Debug overlay", debug, "show"); + imtoggle("Show ur names", debug, "urnames"); +}; -var imgui_fn = function() -{ +var imgui_fn = function () { render.imgui_new(window.size.x, window.size.y, 0.01); - if (debug.console) debug.console = imgui.window("console", _ => { imgui.text(console.transcript); replstr = imgui.textinput(undefined, replstr); imgui.button("submit", _ => { eval(replstr); replstr = ""; }); }); + if (debug.console) + debug.console = imgui.window("console", _ => { + imgui.text(console.transcript); + replstr = imgui.textinput(undefined, replstr); + imgui.button("submit", _ => { + eval(replstr); + replstr = ""; + }); + }); - imgui.mainmenubar(_=>{ + imgui.mainmenubar(_ => { imgui.menu("File", _ => { imgui.menu("Game settings", _ => { window.title = imgui.textinput("Title", window.title); @@ -1070,46 +1017,42 @@ var imgui_fn = function() }); imgui.menu("Debug", imdebug); imgui.menu("View", _ => { - imtoggle("Profiler", debug, 'showprofiler'); - imtoggle("Terminal out", debug, 'termout'); - imtoggle("Meta [f7]", debug, 'meta'); - imtoggle("Cheats [f8]", debug, 'cheat'); - imtoggle("Console [f9]", debug, 'console'); + imtoggle("Profiler", debug, "showprofiler"); + imtoggle("Terminal out", debug, "termout"); + imtoggle("Meta [f7]", debug, "meta"); + imtoggle("Cheats [f8]", debug, "cheat"); + imtoggle("Console [f9]", debug, "console"); }); imgui.sokol_gfx(); imgui.menu("Graphics", _ => { - imtoggle("Draw sprites", render, 'draw_sprites'); - imtoggle("Draw particles", render, 'draw_particles'); - imtoggle("Draw HUD", render, 'draw_hud'); - imtoggle("Draw GUI", render, 'draw_gui'); - imtoggle("Draw gizmos", render, 'draw_gizmos'); + imtoggle("Draw sprites", render, "draw_sprites"); + imtoggle("Draw particles", render, "draw_particles"); + imtoggle("Draw HUD", render, "draw_hud"); + imtoggle("Draw GUI", render, "draw_gui"); + imtoggle("Draw gizmos", render, "draw_gizmos"); imgui.menu("Window", _ => { window.fullscreen = imgui.checkbox("fullscreen", window.fullscreen); -// window.vsync = imgui.checkbox("vsync", window.vsync); + // window.vsync = imgui.checkbox("vsync", window.vsync); imgui.menu("MSAA", _ => { - for (var msaa of gamestate.msaa) - imgui.button(msaa + "x", _ => window.sample_count = msaa); + for (var msaa of gamestate.msaa) imgui.button(msaa + "x", _ => (window.sample_count = msaa)); }); imgui.menu("Resolution", _ => { - for (var res of gamestate.resolutions) - imgui.button(res, _ => window.resolution = res); + for (var res of gamestate.resolutions) imgui.button(res, _ => (window.resolution = res)); }); - }); }); prosperon.menu_hook?.(); }); - + prosperon.imgui(); render.imgui_end(); -} +}; -prosperon.render = function() -{ +prosperon.render = function () { profile.frame("world"); render.set_camera(prosperon.camera); profile.frame("sprites"); @@ -1120,7 +1063,7 @@ prosperon.render = function() prosperon.draw(); profile.endframe(); prosperon.hudcam.size = prosperon.camera.size; - prosperon.hudcam.transform.pos = [prosperon.hudcam.size.x/2, prosperon.hudcam.size.y/2, -100]; + prosperon.hudcam.transform.pos = [prosperon.hudcam.size.x / 2, prosperon.hudcam.size.y / 2, -100]; render.set_camera(prosperon.hudcam); profile.endframe(); @@ -1141,10 +1084,10 @@ prosperon.render = function() render.glue_pass(); profile.frame("frame"); profile.frame("render"); - profile.frame("post process"); + profile.frame("post process"); render.viewport(...prosperon.camera.view()); render.use_shader(render.postshader); - render.use_mat({diffuse:prosperon.screencolor}); + render.use_mat({ diffuse: prosperon.screencolor }); render.draw(shape.quad); profile.endframe(); @@ -1152,10 +1095,9 @@ prosperon.render = function() profile.frame("app"); // Flush & render - prosperon.appcam.transform.pos = [window.size.x/2, window.size.y/2, -100]; + prosperon.appcam.transform.pos = [window.size.x / 2, window.size.y / 2, -100]; prosperon.appcam.size = window.size.slice(); - if (os.sys() !== 'macos') - prosperon.appcam.size.y *= -1; + if (os.sys() !== "macos") prosperon.appcam.size.y *= -1; render.set_camera(prosperon.appcam); render.viewport(...prosperon.appcam.view()); @@ -1173,16 +1115,15 @@ prosperon.render = function() profile.frame("imgui"); - if (debug.show) - imgui_fn(); + if (debug.show) imgui_fn(); profile.endframe(); render.end_pass(); render.commit(); - + endframe(); -} +}; prosperon.process = function process() { profile.frame("frame"); @@ -1190,15 +1131,13 @@ prosperon.process = function process() { frame_t = profile.secs(profile.now()); var sst = profile.now(); - + /* debugging: check for gc */ profile.print_gc(); var cycles = os.check_cycles(); if (cycles) say(cycles); - - profile.frame("app update"); prosperon.appupdate(dt); profile.endframe(); @@ -1208,14 +1147,14 @@ prosperon.process = function process() { profile.endframe(); if (sim.mode === "play" || sim.mode === "step") { - profile.frame("update"); + profile.frame("update"); prosperon.update(dt * game.timescale); update_emitters(dt * game.timescale); profile.endframe(); if (sim.mode === "step") sim.pause(); } - profile.pushdata(profile.data.cpu.scripts, profile.now()-sst); + profile.pushdata(profile.data.cpu.scripts, profile.now() - sst); sst = profile.now(); if (sim.mode === "play" || sim.mode === "step") { @@ -1228,18 +1167,18 @@ prosperon.process = function process() { prosperon.physupdate(physics.delta * game.timescale); } profile.endframe(); - profile.pushdata(profile.data.cpu.physics, profile.now()-sst); + profile.pushdata(profile.data.cpu.physics, profile.now() - sst); sst = profile.now(); } profile.frame("render"); prosperon.window_render(window.size); prosperon.render(); - profile.pushdata(profile.data.cpu.render, profile.now()-sst); + profile.pushdata(profile.data.cpu.render, profile.now() - sst); profile.endframe(); profile.endframe(); profile.capture_data(); -} +}; -return {render}; +return { render }; diff --git a/scripts/repl.js b/scripts/repl.js index bc34aca7..ba8a53ed 100644 --- a/scripts/repl.js +++ b/scripts/repl.js @@ -3,13 +3,13 @@ var repl = {}; var file = "repl.jj"; var last = 0; -repl.hotreload = function() { +repl.hotreload = function () { if (io.mod(file) > last) { say("REPL:::"); last = io.mod(file); var script = io.slurp(file); eval(script); } -} +}; -return {repl:repl}; +return { repl: repl }; diff --git a/scripts/sound.js b/scripts/sound.js index bac817ce..50f9d423 100644 --- a/scripts/sound.js +++ b/scripts/sound.js @@ -1,12 +1,12 @@ /* This file runs after the audio system is initiated */ -Object.readonly(audio, 'samplerate'); -Object.readonly(audio, 'channels'); -Object.readonly(audio, 'buffer_frames'); +Object.readonly(audio, "samplerate"); +Object.readonly(audio, "channels"); +Object.readonly(audio, "buffer_frames"); var sources = []; -audio.play = function(file,bus = audio.bus.master) { +audio.play = function (file, bus = audio.bus.master) { var filename = file; file = Resources.find_sound(file); if (!file) { @@ -20,7 +20,7 @@ audio.play = function(file,bus = audio.bus.master) { src.type = "source"; sources.push(src); return src; -} +}; audio.bus = {}; audio.bus.master = dspsound.master(); audio.dsp = {}; @@ -30,47 +30,45 @@ audio.bus.master.__proto__.type = "bus"; audio.bus.master.name = "master"; var plugin_node = audio.bus.master.plugin; -audio.bus.master.__proto__.plugin = function(to) -{ +audio.bus.master.__proto__.plugin = function (to) { this.tos ??= []; this.tos.push(to); to.ins ??= []; to.ins.push(this); plugin_node.call(this, to); -} +}; var unplug_node = audio.bus.master.unplug; -audio.bus.master.__proto__.unplug = function() -{ +audio.bus.master.__proto__.unplug = function () { if (this.tos) { - for (var node of this.tos) - node.ins.remove(this); - + for (var node of this.tos) node.ins.remove(this); + this.tos = []; } - - unplug_node.call(this); -} -audio.dsp.mix().__proto__.imgui = function() -{ + unplug_node.call(this); +}; + +audio.dsp.mix().__proto__.imgui = function () { imgui.pushid(this.memid()); this.volume = imgui.slider("Volume", this.volume); this.off = imgui.checkbox("Mute", this.off); imgui.popid(); -} +}; -audio.cry = function(file, bus = audio.bus.sfx) -{ +audio.cry = function (file, bus = audio.bus.sfx) { file = Resources.find_sound(file); var player = audio.play(file, bus); if (!player) return; - player.ended = function() { player.unplug(); player = undefined; } + player.ended = function () { + player.unplug(); + player = undefined; + }; return player.ended; -} +}; // This function is called when every audio source is finished -var killer = Register.appupdate.register(function() { +var killer = Register.appupdate.register(function () { for (var src of sources) { if (!src.loop && (src.frame < src.lastframe || src.frame === src.frames())) { src.unplug(); @@ -83,10 +81,9 @@ var killer = Register.appupdate.register(function() { var song; // Play 'file' for new song, cross fade for seconds -audio.music = function(file, fade = 0.5) { +audio.music = function (file, fade = 0.5) { if (!file) { - if (song) - song.volume = 0; + if (song) song.volume = 0; return; } file = Resources.find_sound(file); @@ -99,20 +96,20 @@ audio.music = function(file, fade = 0.5) { if (!song) { song = audio.play(file, audio.bus.music); song.volume = 1; -// tween(song,'volume', 1, fade); + // tween(song,'volume', 1, fade); return; } - + var temp = audio.play(file, audio.bus.music); if (!temp) return; - + temp.volume = 1; var temp2 = song; -// tween(temp, 'volume', 1, fade); -// tween(temp2, 'volume', 0, fade); + // tween(temp, 'volume', 1, fade); + // tween(temp2, 'volume', 0, fade); song = temp; song.loop = true; -} +}; audio.bus.music = audio.dsp.mix(); audio.bus.music.plugin(audio.bus.master); @@ -122,16 +119,16 @@ audio.bus.sfx = audio.dsp.mix(); audio.bus.sfx.plugin(audio.bus.master); audio.bus.sfx.name = "sfx"; -audio.dsp.allpass = function(secs, decay) { +audio.dsp.allpass = function (secs, decay) { var composite = {}; - var fwd = audio.dsp.fwd_delay(secs,-decay); - var fbk = audio.dsp.delay(secs,decay); + var fwd = audio.dsp.fwd_delay(secs, -decay); + var fbk = audio.dsp.delay(secs, decay); composite.id = fwd.id; composite.plugin = composite.plugin.bind(fbk); composite.unplug = dsp_node.unplug.bind(fbk); fwd.plugin(fbk); return composite; -} +}; audio.dsp.doc = { delay: "Delays the input by secs, multiplied by decay", @@ -146,27 +143,35 @@ audio.dsp.doc = { pitchshift: "Shift sound by octaves", noise: "Plain randon noise", pink: "Pink noise", - red: "Red noise" + red: "Red noise", }; -audio.dsp.obscure('doc'); +audio.dsp.obscure("doc"); Object.mixin(audio.bus.master.__proto__, { - get db() { return 20*Math.log10(Math.abs(this.volume)); }, - set db(x) { x = Math.clamp(x,-100,0); this.volume = Math.pow(10, x/20); }, - get volume() { return this.gain; }, - set volume(x) { this.gain = x; }, + get db() { + return 20 * Math.log10(Math.abs(this.volume)); + }, + set db(x) { + x = Math.clamp(x, -100, 0); + this.volume = Math.pow(10, x / 20); + }, + get volume() { + return this.gain; + }, + set volume(x) { + this.gain = x; + }, }); -audio.bus.master.__proto__.toJSON = function() -{ +audio.bus.master.__proto__.toJSON = function () { return { volume: this.volume, off: this.off, pan: this.pan, - pass: this.pass + pass: this.pass, }; -} +}; /*Object.mixin(audio.dsp.source().__proto__, { length() { return this.frames()/audio.samplerate(); }, @@ -175,4 +180,4 @@ audio.bus.master.__proto__.toJSON = function() }); */ -return {audio}; +return { audio }; diff --git a/scripts/spline.js b/scripts/spline.js index 2c140015..f3e934f2 100644 --- a/scripts/spline.js +++ b/scripts/spline.js @@ -1,117 +1,121 @@ var Spline = {}; -Spline.sample_angle = function(type, points, angle) { +Spline.sample_angle = function (type, points, angle) { if (type === 0) return spline.catmull(points, angle); - else if (type === 1) return spline.bezier(points,angle); + else if (type === 1) return spline.bezier(points, angle); return undefined; -} +}; -Spline.bezier_loop = function(cp) -{ - cp.push(Vector.reflect_point(cp.at(-2),cp.at(-1))); - cp.push(Vector.reflect_point(cp[1],cp[0])); +Spline.bezier_loop = function (cp) { + cp.push(Vector.reflect_point(cp.at(-2), cp.at(-1))); + cp.push(Vector.reflect_point(cp[1], cp[0])); cp.push(cp[0].slice()); return cp; -} +}; -Spline.bezier_node_count = function(cp) -{ +Spline.bezier_node_count = function (cp) { if (cp.length === 4) return 2; - return 2 + (cp.length-4)/3; -} + return 2 + (cp.length - 4) / 3; +}; -Spline.is_bezier = function(t) { return t === Spline.type.bezier; } -Spline.is_catmull = function(t) { return t === Spline.type.catmull; } +Spline.is_bezier = function (t) { + return t === Spline.type.bezier; +}; +Spline.is_catmull = function (t) { + return t === Spline.type.catmull; +}; -Spline.bezier2catmull = function(b) -{ +Spline.bezier2catmull = function (b) { var c = []; - for (var i = 0; i < b.length; i += 3) - c.push(b[i]); + for (var i = 0; i < b.length; i += 3) c.push(b[i]); return c; -} +}; -Spline.catmull2bezier = function(c) -{ +Spline.catmull2bezier = function (c) { var b = []; - for (var i = 1; i < c.length-2; i++) { + for (var i = 1; i < c.length - 2; i++) { b.push(c[i].slice()); - b.push(c[i+1].sub(c[i-1]).scale(0.25).add(c[i])); - b.push(c[i].sub(c[i+2]).scale(0.25).add(c[i+1])); + b.push( + c[i + 1] + .sub(c[i - 1]) + .scale(0.25) + .add(c[i]), + ); + b.push( + c[i] + .sub(c[i + 2]) + .scale(0.25) + .add(c[i + 1]), + ); } - b.push(c[c.length-2]); + b.push(c[c.length - 2]); return b; -} +}; -Spline.catmull_loop = function(cp) -{ +Spline.catmull_loop = function (cp) { cp = cp.slice(); cp.unshift(cp.last()); cp.push(cp[1]); cp.push(cp[2]); return cp; -} +}; -Spline.catmull_caps = function(cp) -{ +Spline.catmull_caps = function (cp) { if (cp.length < 2) return; cp = cp.slice(); cp.unshift(cp[0].sub(cp[1]).add(cp[0])); cp.push(cp.last().sub(cp.at(-2).add(cp.last()))); return cp; -} +}; Spline.catmull_caps.doc = "Given a set of control points cp, return the necessary caps added to the spline."; -Spline.catmull2bezier.doc = "Given a set of control points C for a camtull-rom type curve, return a set of cubic bezier points to give the same curve." +Spline.catmull2bezier.doc = "Given a set of control points C for a camtull-rom type curve, return a set of cubic bezier points to give the same curve."; Spline.type = { catmull: 0, bezier: 1, bspline: 2, - cubichermite: 3 + cubichermite: 3, }; -Spline.bezier_tan_partner = function(points, i) -{ - if (i%3 === 0) return undefined; - var partner_i = (i%3) === 2 ? i-1 : i+1; +Spline.bezier_tan_partner = function (points, i) { + if (i % 3 === 0) return undefined; + var partner_i = i % 3 === 2 ? i - 1 : i + 1; return points[i]; -} +}; -Spline.bezier_cp_mirror = function(points, i) -{ - if (i%3 === 0) return undefined; - var partner_i = (i%3) === 2 ? i+2 : i-2; - var node_i = (i%3) === 2 ? i+1 : i-1; +Spline.bezier_cp_mirror = function (points, i) { + if (i % 3 === 0) return undefined; + var partner_i = i % 3 === 2 ? i + 2 : i - 2; + var node_i = i % 3 === 2 ? i + 1 : i - 1; if (partner_i >= points.length || node_i >= points.length) return; points[partner_i] = points[node_i].sub(points[i]).add(points[node_i]); -} +}; -Spline.bezier_point_handles = function(points, i) -{ - if (!Spline.bezier_is_node(points,i)) return []; - var a = i-1; - var b = i+1; - var c = [] - if (a > 0) - c.push(a); - - if (b < points.length) - c.push(b); - - return c; -} - -Spline.bezier_nodes = function(points) -{ +Spline.bezier_point_handles = function (points, i) { + if (!Spline.bezier_is_node(points, i)) return []; + var a = i - 1; + var b = i + 1; var c = []; - for (var i = 0; i < points.length; i+=3) - c.push(points[i].slice()); + if (a > 0) c.push(a); + + if (b < points.length) c.push(b); return c; -} +}; -Spline.bezier_is_node = function(points, i) { return i%3 === 0; } -Spline.bezier_is_handle = function(points, i) { return !Spline.bezier_is_node(points,i); } +Spline.bezier_nodes = function (points) { + var c = []; + for (var i = 0; i < points.length; i += 3) c.push(points[i].slice()); -return {Spline}; + return c; +}; + +Spline.bezier_is_node = function (points, i) { + return i % 3 === 0; +}; +Spline.bezier_is_handle = function (points, i) { + return !Spline.bezier_is_node(points, i); +}; + +return { Spline }; diff --git a/scripts/std.js b/scripts/std.js index 03b4ef9b..7f35415d 100644 --- a/scripts/std.js +++ b/scripts/std.js @@ -1,28 +1,34 @@ os.cwd.doc = "Get the absolute path of the current working directory."; os.env.doc = "Return the value of the environment variable v."; os.platform = "steam"; -if (os.sys() === 'windows') - os.user = os.env("USERNAME"); -else - os.user = os.env("USER"); - +if (os.sys() === "windows") os.user = os.env("USERNAME"); +else os.user = os.env("USER"); + var appy = {}; appy.inputs = {}; -if (os.sys() === 'macos') { - appy.inputs['S-q'] = os.quit; +if (os.sys() === "macos") { + appy.inputs["S-q"] = os.quit; } -appy.inputs.f7 = function() { debug.meta = !debug.meta; } -appy.inputs.f8 = function() { debug.cheat = !debug.cheat; } -appy.inputs.f9 = function() { debug.console = !debug.console; } -appy.inputs.f10 = function() { debug.show = !debug.show; } +appy.inputs.f7 = function () { + debug.meta = !debug.meta; +}; +appy.inputs.f8 = function () { + debug.cheat = !debug.cheat; +}; +appy.inputs.f9 = function () { + debug.console = !debug.console; +}; +appy.inputs.f10 = function () { + debug.show = !debug.show; +}; appy.inputs.f11 = window.toggle_fullscreen; appy.inputs.f11.doc = "Toggle window fullscreen."; appy.inputs.f11.title = "Toggle Fullscreen"; -appy.inputs['M-f4'] = os.quit; +appy.inputs["M-f4"] = os.quit; player[0].control(appy); - + //steam.appid = 480; //steam.userid = 8437843; @@ -35,30 +41,32 @@ os.home = os.env("HOME"); }; */ var otherpath = { - windows:`C:/Users/${os.user}/Saved Games`, + windows: `C:/Users/${os.user}/Saved Games`, macos: `${os.home}/Library/Application Support`, - linux: `${os.home}/.local/share` -} + linux: `${os.home}/.local/share`, +}; -os.prefpath = function() { +os.prefpath = function () { return otherpath[os.sys()] + "/" + (game.title ? game.title : "Untitled Prosperon Game"); -} +}; -os.openurl = function(url) { - if (os.sys() === 'windows') - os.system(`start ${url}`); - else - os.system(`open ${url}`); -} +os.openurl = function (url) { + if (os.sys() === "windows") os.system(`start ${url}`); + else os.system(`open ${url}`); +}; var projectfile = "project.prosperon"; -io.dumpfolder = '.prosperon'; +io.dumpfolder = ".prosperon"; Resources.texture = {}; -Resources.texture.dimensions = function(path) { texture.dimensions(path); } +Resources.texture.dimensions = function (path) { + texture.dimensions(path); +}; Resources.gif = {}; -Resources.gif.frames = function(path) { return render.gif_frames(path); } +Resources.gif.frames = function (path) { + return render.gif_frames(path); +}; /* io path rules. Starts with, meaning: @@ -68,30 +76,27 @@ Resources.gif.frames = function(path) { return render.gif_frames(path); } */ var tmpchm = io.chmod; -io.chmod = function(file,mode) { - return tmpchm(file,parseInt(mode,8)); -} +io.chmod = function (file, mode) { + return tmpchm(file, parseInt(mode, 8)); +}; var tmpslurp = io.slurp; -io.slurp = function(path) -{ +io.slurp = function (path) { path = Resources.replpath(path); return tmpslurp(path); -} +}; var tmpslurpb = io.slurpbytes; -io.slurpbytes = function(path) -{ +io.slurpbytes = function (path) { path = Resources.replpath(path); return tmpslurpb(path); -} +}; -io.mkpath = function(dir) -{ +io.mkpath = function (dir) { if (!dir) return; var mkstack = []; while (!io.exists(dir)) { - mkstack.push(dir.fromlast('/')); + mkstack.push(dir.fromlast("/")); dir = dir.dir(); } for (var d of mkstack) { @@ -99,55 +104,54 @@ io.mkpath = function(dir) say(`making ${dir}`); io.mkdir(dir); } -} +}; var tmpslurpw = io.slurpwrite; -io.slurpwrite = function(path, c) -{ +io.slurpwrite = function (path, c) { path = Resources.replpath(path); io.mkpath(path.dir()); return tmpslurpw(path, c); -} +}; var tmpcp = io.cp; -io.cp = function(f1,f2) -{ +io.cp = function (f1, f2) { io.mkpath(f2.dir()); - tmpcp(f1,f2); -} + tmpcp(f1, f2); +}; var tmprm = io.rm; -io.rm = function(f) -{ +io.rm = function (f) { tmprm(Resources.replpath(f)); -} +}; -io.globToRegex = function(glob) { - // Escape special regex characters - // Replace glob characters with regex equivalents - let regexStr = glob - .replace(/[\.\\]/g, '\\$&') // Escape literal backslashes and dots - .replace(/([^\*])\*/g, '$1[^/]*') // * matches any number of characters except / - .replace(/\*\*/g, '.*') // ** matches any number of characters, including none - .replace(/\[(.*?)\]/g, '[$1]') // Character sets - .replace(/\?/g, '.'); // ? matches any single character +io.globToRegex = function (glob) { + // Escape special regex characters + // Replace glob characters with regex equivalents + let regexStr = glob + .replace(/[\.\\]/g, "\\$&") // Escape literal backslashes and dots + .replace(/([^\*])\*/g, "$1[^/]*") // * matches any number of characters except / + .replace(/\*\*/g, ".*") // ** matches any number of characters, including none + .replace(/\[(.*?)\]/g, "[$1]") // Character sets + .replace(/\?/g, "."); // ? matches any single character - // Ensure the regex matches the whole string - regexStr = '^' + regexStr + '$'; + // Ensure the regex matches the whole string + regexStr = "^" + regexStr + "$"; - // Create and return the regex object - return new RegExp(regexStr); -} + // Create and return the regex object + return new RegExp(regexStr); +}; io.mixin({ extensions(ext) { var paths = io.ls(); - paths = paths.filter(function(str) { return str.ext() === ext; }); + paths = paths.filter(function (str) { + return str.ext() === ext; + }); return paths; }, glob(pat) { - var paths = io.ls('.'); + var paths = io.ls("."); var regex = io.globToRegex(pat); paths = paths.filter(str => str.match(regex)).sort(); return paths; @@ -172,328 +176,409 @@ var Cmdline = {}; Cmdline.cmds = []; Cmdline.orders = {}; -Cmdline.register_cmd = function(flag, fn, doc) { +Cmdline.register_cmd = function (flag, fn, doc) { Cmdline.cmds.push({ flag: flag, fn: fn, - doc: doc + doc: doc, }); }; -Cmdline.register_order = function(order, fn, doc, usage = "") { +Cmdline.register_order = function (order, fn, doc, usage = "") { Cmdline.orders[order] = fn; fn.doc = doc; fn.usage = `${order} ${usage}`; -} +}; -Cmdline.register_order("edit", function() { - if (!io.exists(projectfile)) { - say("No game to edit. Try making one with 'prosperon init'."); - return; - } - - window.size = [1280, 720]; - window.mode = "full"; - sim.pause(); - - game.engine_start(function() { - global.mixin("scripts/editor.js"); - use("editorconfig.js"); - use("config.js"); - render.set_font("fonts/c64.ttf", 8); - editor.enter_editor(); - }); -}, "Edit the project in this folder. Give it the name of an UR to edit that specific object.", "?UR?"); - -Cmdline.register_order("init", function() { - if (io.exists(projectfile)) { - say("Already a game here."); - return; - } - - io.mkdir(io.dumpfolder); - var project = {}; - project.version = prosperon.version; - project.revision = prosperon.revision; - io.slurpwrite(projectfile, json.encode(project)); -}, "Turn the directory into a Prosperon game."); - -Cmdline.register_order("debug", function() { - Cmdline.orders.play([]); -}, "Play the game with debugging enabled."); - -Cmdline.register_order("web", function() { - Cmdline.orders.play([]); -}, "Play the game in a web browser."); - -Cmdline.register_order("play", function(argv) { - if (argv[0]) - io.chdir(argv[0]); - -// game.loadurs(); - - if (!io.exists(projectfile)) { - say("No game to play. Try making one with 'prosperon init'."); - return; - } - - var project = json.decode(io.slurp(projectfile)); - game.title = project.title; - game.size = [1280,720]; - window.size = game.size; - if (io.exists("config.js")) - global.mixin("config.js"); - else - console.warn('No config.js file found. Starting with default parameters.'); - - if (project.title) window.title = project.title; - - game.engine_start(function() { - render.set_font("fonts/c64.ttf", 8); - if (io.exists("game.js")) - global.app = actor.spawn("game.js"); - else - global.app = actor.spawn("scripts/nogame.js"); - - if (project.icon) window.set_icon(game.texture(project.icon)); - game.camera = world.spawn("scripts/camera2d"); - }); -}, "Play the game present in this folder."); - -Cmdline.register_order("pack", function(str) { - var packname; - if (str.length === 0) - packname = "game.zip"; - else if (str.length > 1) { - console.warn("Give me a single filename for the pack."); - return; - } else - packname = str[0]; - - say(`Packing into ${packname}`); - - io.pack_start(packname); - var files = io.ls('.'); - files = files.filter(f => !f.startsWith('.git')); - files = files.filter(f => !f.startsWith('.nova')); - files = files.filter(f => !f.includes('.DS_Store')); - files = files.filter(f => !f.startsWith('.gitignore')); - say(files); - for (var f of files) - io.pack_add(f); - io.pack_end(); -}, "Pack the game into the given name.", "NAME"); - -Cmdline.register_order("cdb", function(argv) { - var cdb = "game.zip"; - if (!io.exists(cdb)) { - say(`No 'game.zip' present.`); - return; - } - if (argv.length === 0) { - say(`cdb name: ${cdb}`); - - } -}, "CDB commands."); - -Cmdline.register_order("qoa", function(argv) { - var sounds = Resources.sounds.filter(x => x !== "qoa"); - for (var file of argv) { - if (!sounds.includes(file.ext())) continue; - say(`converting ${file}`); - io.save_qoa(file); - } -}, "Convert file(s) to qoa."); - -Cmdline.register_order("about", function(argv) { - - if (!argv[0]) { - say('About your game'); - say(`Prosperon version ${prosperon.version}`); - say(`Total entities ${ur._list.length}`); - } - switch (argv[0]) { - case "entities": - for (var i of ur._list) say(i); - break; - } -}, "Get information about this game."); - -Cmdline.register_order("ur", function(argv) { -// game.loadurs(); - for (var i of ur._list.sort()) say(i); -}, "Get information about the ur types in your game."); - -Cmdline.register_order("env", function(argv) { - if (argv.length > 2) return; - var gg = json.decode(io.slurp(projectfile)); - if (argv.length === 0) { - say(json.encode(gg,null,1)); - return; - } - - if (argv.length === 1) { - var v = gg[argv[0]]; - if (!v) { - say(`Value ${argv[0]} not found.`); +Cmdline.register_order( + "edit", + function () { + if (!io.exists(projectfile)) { + say("No game to edit. Try making one with 'prosperon init'."); return; } - say(`${argv[0]}:${v}`); - } else { - gg[argv[0]] = argv[1]; - say(`Set ${argv[0]}:${v}`); - say(json.encode(gg,null,1)); - io.slurpwrite(projectfile, json.encode(gg)); - } -}, "Get or set game variables."); -Cmdline.register_order("unpack", function() { - say("Unpacking not implemented."); -}, "Unpack this binary's contents into this folder for editing."); + window.size = [1280, 720]; + window.mode = "full"; + sim.pause(); -Cmdline.register_order("build", function() { - say("Building not implemented."); -}, "Build static assets for this project."); + game.engine_start(function () { + global.mixin("scripts/editor.js"); + use("editorconfig.js"); + use("config.js"); + render.set_font("fonts/c64.ttf", 8); + editor.enter_editor(); + }); + }, + "Edit the project in this folder. Give it the name of an UR to edit that specific object.", + "?UR?", +); -Cmdline.register_order("nota", function(argv) { - for (var file of argv) { - if (!io.exists(file)) { - say(`File ${file} does not exist.`); - continue; +Cmdline.register_order( + "init", + function () { + if (io.exists(projectfile)) { + say("Already a game here."); + return; } - var obj = json.decode(io.slurp(file)); - var nn = nota.encode(obj); - io.slurpwrite(file.set_ext(".nota"), nn); - } -}, "Create a nota file from a json."); + io.mkdir(io.dumpfolder); + var project = {}; + project.version = prosperon.version; + project.revision = prosperon.revision; + io.slurpwrite(projectfile, json.encode(project)); + }, + "Turn the directory into a Prosperon game.", +); -Cmdline.register_order("json", function(argv) { - for (var file of argv) { - if (!io.exists(file)) { - say(`File ${file} does not exist.`); - continue; +Cmdline.register_order( + "debug", + function () { + Cmdline.orders.play([]); + }, + "Play the game with debugging enabled.", +); + +Cmdline.register_order( + "web", + function () { + Cmdline.orders.play([]); + }, + "Play the game in a web browser.", +); + +Cmdline.register_order( + "play", + function (argv) { + if (argv[0]) io.chdir(argv[0]); + + // game.loadurs(); + + if (!io.exists(projectfile)) { + say("No game to play. Try making one with 'prosperon init'."); + return; } - say(file.ext()); - var obj = nota.decode(io.slurp(file)); - var nn = json.encode(obj); - io.slurpwrite(file.set_ext(".json", nn)); - } -}, "Create a JSON from a nota."); -Cmdline.register_order("api", function(obj) { - if (!obj[0]) { - Cmdline.print_order("api"); - return; - } + var project = json.decode(io.slurp(projectfile)); + game.title = project.title; + game.size = [1280, 720]; + window.size = game.size; + if (io.exists("config.js")) global.mixin("config.js"); + else console.warn("No config.js file found. Starting with default parameters."); - use("scripts/editor.js"); - var api = debug.api.print_doc(obj[0]); - if (!api) - return; + if (project.title) window.title = project.title; - say(api); -}, "Print the API for an object as markdown. Give it a file to save the output to.", "OBJECT"); + game.engine_start(function () { + render.set_font("fonts/c64.ttf", 8); + if (io.exists("game.js")) global.app = actor.spawn("game.js"); + else global.app = actor.spawn("scripts/nogame.js"); -Cmdline.register_order("input", function(pawn) { - use("scripts/editor.js"); - say(`## Input for ${pawn}`); - eval(`say(input.print_md_kbm(${pawn}));`); -}, "Print input documentation for a given object as markdown. Give it a file to save the output to", "OBJECT ?FILE?"); + if (project.icon) window.set_icon(game.texture(project.icon)); + game.camera = world.spawn("scripts/camera2d"); + }); + }, + "Play the game present in this folder.", +); -Cmdline.register_order("run", function(script) { - script = script.join(" "); - if (!script) { - say("Need something to run."); - return; - } - - say(eval(script)); -}, "Run a given script. SCRIPT can be the script itself, or a file containing the script", "SCRIPT"); +Cmdline.register_order( + "pack", + function (str) { + var packname; + if (str.length === 0) packname = "game.zip"; + else if (str.length > 1) { + console.warn("Give me a single filename for the pack."); + return; + } else packname = str[0]; + + say(`Packing into ${packname}`); + + io.pack_start(packname); + var files = io.ls("."); + files = files.filter(f => !f.startsWith(".git")); + files = files.filter(f => !f.startsWith(".nova")); + files = files.filter(f => !f.includes(".DS_Store")); + files = files.filter(f => !f.startsWith(".gitignore")); + say(files); + for (var f of files) io.pack_add(f); + io.pack_end(); + }, + "Pack the game into the given name.", + "NAME", +); + +Cmdline.register_order( + "cdb", + function (argv) { + var cdb = "game.zip"; + if (!io.exists(cdb)) { + say(`No 'game.zip' present.`); + return; + } + if (argv.length === 0) { + say(`cdb name: ${cdb}`); + } + }, + "CDB commands.", +); + +Cmdline.register_order( + "qoa", + function (argv) { + var sounds = Resources.sounds.filter(x => x !== "qoa"); + for (var file of argv) { + if (!sounds.includes(file.ext())) continue; + say(`converting ${file}`); + io.save_qoa(file); + } + }, + "Convert file(s) to qoa.", +); + +Cmdline.register_order( + "about", + function (argv) { + if (!argv[0]) { + say("About your game"); + say(`Prosperon version ${prosperon.version}`); + say(`Total entities ${ur._list.length}`); + } + switch (argv[0]) { + case "entities": + for (var i of ur._list) say(i); + break; + } + }, + "Get information about this game.", +); + +Cmdline.register_order( + "ur", + function (argv) { + // game.loadurs(); + for (var i of ur._list.sort()) say(i); + }, + "Get information about the ur types in your game.", +); + +Cmdline.register_order( + "env", + function (argv) { + if (argv.length > 2) return; + var gg = json.decode(io.slurp(projectfile)); + if (argv.length === 0) { + say(json.encode(gg, null, 1)); + return; + } + + if (argv.length === 1) { + var v = gg[argv[0]]; + if (!v) { + say(`Value ${argv[0]} not found.`); + return; + } + say(`${argv[0]}:${v}`); + } else { + gg[argv[0]] = argv[1]; + say(`Set ${argv[0]}:${v}`); + say(json.encode(gg, null, 1)); + io.slurpwrite(projectfile, json.encode(gg)); + } + }, + "Get or set game variables.", +); + +Cmdline.register_order( + "unpack", + function () { + say("Unpacking not implemented."); + }, + "Unpack this binary's contents into this folder for editing.", +); + +Cmdline.register_order( + "build", + function () { + say("Building not implemented."); + }, + "Build static assets for this project.", +); + +Cmdline.register_order( + "nota", + function (argv) { + for (var file of argv) { + if (!io.exists(file)) { + say(`File ${file} does not exist.`); + continue; + } + + var obj = json.decode(io.slurp(file)); + var nn = nota.encode(obj); + io.slurpwrite(file.set_ext(".nota"), nn); + } + }, + "Create a nota file from a json.", +); + +Cmdline.register_order( + "json", + function (argv) { + for (var file of argv) { + if (!io.exists(file)) { + say(`File ${file} does not exist.`); + continue; + } + say(file.ext()); + var obj = nota.decode(io.slurp(file)); + var nn = json.encode(obj); + io.slurpwrite(file.set_ext(".json", nn)); + } + }, + "Create a JSON from a nota.", +); + +Cmdline.register_order( + "api", + function (obj) { + if (!obj[0]) { + Cmdline.print_order("api"); + return; + } + + use("scripts/editor.js"); + var api = debug.api.print_doc(obj[0]); + if (!api) return; + + say(api); + }, + "Print the API for an object as markdown. Give it a file to save the output to.", + "OBJECT", +); + +Cmdline.register_order( + "input", + function (pawn) { + use("scripts/editor.js"); + say(`## Input for ${pawn}`); + eval(`say(input.print_md_kbm(${pawn}));`); + }, + "Print input documentation for a given object as markdown. Give it a file to save the output to", + "OBJECT ?FILE?", +); + +Cmdline.register_order( + "run", + function (script) { + script = script.join(" "); + if (!script) { + say("Need something to run."); + return; + } + + say(eval(script)); + }, + "Run a given script. SCRIPT can be the script itself, or a file containing the script", + "SCRIPT", +); Cmdline.orders.script = Cmdline.orders.run; -Cmdline.print_order = function(fn) -{ - if (typeof fn === 'string') - fn = Cmdline.orders[fn]; - +Cmdline.print_order = function (fn) { + if (typeof fn === "string") fn = Cmdline.orders[fn]; + if (!fn) return; say(`Usage: prosperon ${fn.usage}`); say(fn.doc); -} +}; -Cmdline.register_order("help", function(order) { - - if (!Object.empty(order)) { - var orfn = Cmdline.orders[order]; - - if (!orfn) { - console.warn(`No command named ${order}.`); +Cmdline.register_order( + "help", + function (order) { + if (!Object.empty(order)) { + var orfn = Cmdline.orders[order]; + + if (!orfn) { + console.warn(`No command named ${order}.`); + return; + } + + Cmdline.print_order(orfn); return; } - Cmdline.print_order(orfn); - return; - } - - Cmdline.print_order("help"); + Cmdline.print_order("help"); - for (var cmd of Object.keys(Cmdline.orders).sort()) - say(cmd); + for (var cmd of Object.keys(Cmdline.orders).sort()) say(cmd); - Cmdline.orders.version(); -}, "Give help with a specific command.", "TOPIC"); + Cmdline.orders.version(); + }, + "Give help with a specific command.", + "TOPIC", +); -Cmdline.register_order("version", function() { - say(`Prosperon version ${prosperon.version} [${prosperon.revision}]`); -}, "Display Prosperon info."); +Cmdline.register_order( + "version", + function () { + say(`Prosperon version ${prosperon.version} [${prosperon.revision}]`); + }, + "Display Prosperon info.", +); -function cmd_args(cmdargs) -{ +function cmd_args(cmdargs) { var play = false; var cmds = cmdargs.split(/\s+/).slice(1); - if (cmds.length === 0) - cmds[0] = "play"; + if (cmds.length === 0) cmds[0] = "play"; else if (!Cmdline.orders[cmds[0]]) { console.warn(`Command ${cmds[0]} not found. Playing instead.`); cmds[0] = "play"; } Cmdline.orders[cmds[0]](cmds.slice(1)); - if (!game.startengine) - os.exit(0); + if (!game.startengine) os.exit(0); } -Cmdline.register_order("clean", function(argv) { - say("Cleaning not implemented."); -}, "Clean up a given object file.", "JSON ..."); +Cmdline.register_order( + "clean", + function (argv) { + say("Cleaning not implemented."); + }, + "Clean up a given object file.", + "JSON ...", +); -Cmdline.register_order("test", function(argv) { - use("scripts/test.js"); -}, "Run tests."); +Cmdline.register_order( + "test", + function (argv) { + use("scripts/test.js"); + }, + "Run tests.", +); -Cmdline.register_cmd("l", function(n) { - console.level = n; -}, "Set log level."); +Cmdline.register_cmd( + "l", + function (n) { + console.level = n; + }, + "Set log level.", +); function convertYAMLtoJSON(yamlString) { - const lines = yamlString.split('\n'); + const lines = yamlString.split("\n"); const jsonObj = {}; - let currentKey = ''; - let currentValue = ''; + let currentKey = ""; + let currentValue = ""; let currentDepth = 0; for (let i = 0; i < lines.length; i++) { const line = lines[i].trim(); - if (!line || line.startsWith('#')) { + if (!line || line.startsWith("#")) { continue; } - const depth = (line.match(/^\s+/g) || [''])[0].length; - const keyValue = line.split(':'); + const depth = (line.match(/^\s+/g) || [""])[0].length; + const keyValue = line.split(":"); const key = keyValue[0].trim(); const value = keyValue[1].trim(); @@ -507,8 +592,8 @@ function convertYAMLtoJSON(yamlString) { currentValue = value; } else { jsonObj[currentKey] = convertYAMLtoJSON(currentValue); - currentKey = ''; - currentValue = ''; + currentKey = ""; + currentValue = ""; i--; // To reprocess the current line with updated values } @@ -526,6 +611,5 @@ return { Resources, Cmdline, cmd_args, - convertYAMLtoJSON + convertYAMLtoJSON, }; - diff --git a/scripts/stdprofile.js b/scripts/stdprofile.js index 06e2d866..577e059a 100644 --- a/scripts/stdprofile.js +++ b/scripts/stdprofile.js @@ -1,4 +1,4 @@ -var aa = [1,2,3,4,5,6,7,8,9,10]; +var aa = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; /* var ta = [1,2,3,4,5,6,7,8,9,10]; diff --git a/scripts/stdtest.js b/scripts/stdtest.js index fb861d52..67f0f884 100644 --- a/scripts/stdtest.js +++ b/scripts/stdtest.js @@ -2,9 +2,5 @@ test.run("set transform scale", _ => { var t = os.make_transform(); var s1 = t.scale.slice(); t.scale = s1; - return (t.scale.equal(s1)); + return t.scale.equal(s1); }); - - - - diff --git a/scripts/test.js b/scripts/test.js index 04fe0829..f4917b2f 100644 --- a/scripts/test.js +++ b/scripts/test.js @@ -7,20 +7,16 @@ var pass = 0; var fail = 0; var failed = []; -test.run_suite = function(file) -{ +test.run_suite = function (file) { test = []; pass = 0; fail = 0; failed = []; +}; - -} - -test.run = function(name, fn) -{ - var func = function() { - print(`${pass+fail+1}/${tests.length}: ${name} ... `); +test.run = function (name, fn) { + var func = function () { + print(`${pass + fail + 1}/${tests.length}: ${name} ... `); var p = profile.now(); var b = fn(); p = profile.lap(p); @@ -29,12 +25,11 @@ test.run = function(name, fn) }; func.testname = name; tests.push(func); -} +}; say(`Testing ${tests.length} tests.`); for (var t of tests) { - if (t()) - pass++; + if (t()) pass++; else { fail++; failed.push(t.testname); @@ -42,11 +37,10 @@ for (var t of tests) { print("\n"); } -say(`Passed ${pass} tests and failed ${fail} [${(pass*100/(pass+fail)).toPrecision(4)}%].`); +say(`Passed ${pass} tests and failed ${fail} [${((pass * 100) / (pass + fail)).toPrecision(4)}%].`); say(`Failed tests are:`); -for (var f of failed) - say(f); - +for (var f of failed) say(f); + os.quit(); -return {test}; +return { test }; diff --git a/scripts/textedit.js b/scripts/textedit.js index b18db00d..a77c750e 100644 --- a/scripts/textedit.js +++ b/scripts/textedit.js @@ -1,14 +1,14 @@ var texteditor = Object.copy(inputpanel, { title: "text editor", - wh: [700,500], - _cursor:0, /* Text cursor: [char,line] */ - get cursor() { return this._cursor; }, + wh: [700, 500], + _cursor: 0 /* Text cursor: [char,line] */, + get cursor() { + return this._cursor; + }, set cursor(x) { - if (x > this.value.length) - x = this.value.length; - if (x < 0) - x = 0; - + if (x > this.value.length) x = this.value.length; + if (x < 0) x = 0; + this._cursor = x; this.line = this.get_line(); }, @@ -31,31 +31,27 @@ var texteditor = Object.copy(inputpanel, { }, copy(start, end) { - return this.value.slice(start,end); + return this.value.slice(start, end); }, delete_line(p) { var ls = this.line_start(p); - var le = this.line_end(p)+1; - this.cut_span(ls,le); + var le = this.line_end(p) + 1; + this.cut_span(ls, le); this.to_line_start(); }, line_blank(p) { var ls = this.line_start(p); var le = this.line_end(p); - var line = this.value.slice(ls, le); - if (line.search(/[^\s]/g) === -1) - return true; - else - return false; + var line = this.value.slice(ls, le); + if (line.search(/[^\s]/g) === -1) return true; + else return false; }, get_line() { var line = 0; - for (var i = 0; i < this.cursor; i++) - if (this.value[i] === "\n") - line++; + for (var i = 0; i < this.cursor; i++) if (this.value[i] === "\n") line++; return line; }, @@ -72,14 +68,11 @@ var texteditor = Object.copy(inputpanel, { src: "NEW FILE", guibody() { - return [ - Mum.text({str:`EDITING ${this.src}`}), - Mum.text({str:this.value, caret:this.cursor, offset:[0,-16]}), - ]; + return [Mum.text({ str: `EDITING ${this.src}` }), Mum.text({ str: this.value, caret: this.cursor, offset: [0, -16] })]; }, insert_char(char) { - this.value = this.value.slice(0,this.cursor) + char + this.value.slice(this.cursor); + this.value = this.value.slice(0, this.cursor) + char + this.value.slice(this.cursor); this.cursor++; }, @@ -98,117 +91,115 @@ var texteditor = Object.copy(inputpanel, { cut_span(start, end) { if (end < start) return; this.savestate(); - var ret = this.value.slice(start,end); - this.value = this.value.slice(0,start) + this.value.slice(end); - if (start > this.cursor) - return ret; - + var ret = this.value.slice(start, end); + this.value = this.value.slice(0, start) + this.value.slice(end); + if (start > this.cursor) return ret; + this.cursor -= ret.length; return ret; }, next_word(pos) { - var v = this.value.slice(pos+1).search(/[^\w]\w/g); + var v = this.value.slice(pos + 1).search(/[^\w]\w/g); if (v === -1) return pos; return pos + v + 2; }, prev_word(pos) { - while (this.value.slice(pos,pos+2).search(/[^\w]\w/g) === -1 && pos > 0) - pos--; + while (this.value.slice(pos, pos + 2).search(/[^\w]\w/g) === -1 && pos > 0) pos--; - return pos+1; + return pos + 1; }, end_of_word(pos) { var l = this.value.slice(pos).search(/\w[^\w]/g); - return l+pos; + return l + pos; }, get inset() { - return this.cursor - this.value.prev('\n', this.cursor) - 1; + return this.cursor - this.value.prev("\n", this.cursor) - 1; }, line_start(p) { - return this.value.prev('\n', p)+1; + return this.value.prev("\n", p) + 1; }, line_end(p) { - return this.value.next('\n', p); + return this.value.next("\n", p); }, next_line(p) { - return this.value.next('\n',p)+1; + return this.value.next("\n", p) + 1; }, prev_line(p) { - return this.line_start(this.value.prev('\n', p)); + return this.line_start(this.value.prev("\n", p)); }, to_line_start() { - this.cursor = this.value.prev('\n', this.cursor)+1; + this.cursor = this.value.prev("\n", this.cursor) + 1; }, to_line_end() { - var p = this.value.next('\n', this.cursor); - if (p === -1) - this.to_file_end(); - else - this.cursor = p; + var p = this.value.next("\n", this.cursor); + if (p === -1) this.to_file_end(); + else this.cursor = p; }, line_width(pos) { var start = this.line_start(pos); var end = this.line_end(pos); - if (end === -1) - end = this.value.length; + if (end === -1) end = this.value.length; - return end-start; + return end - start; }, - to_file_end() { this.cursor = this.value.length; }, + to_file_end() { + this.cursor = this.value.length; + }, - to_file_start() { this.cursor = 0; }, + to_file_start() { + this.cursor = 0; + }, desired_inset: 0, }); texteditor.inputs = {}; -texteditor.inputs.char = function(char) { +(texteditor.inputs.char = function (char) { this.insert_char(char); this.keycb(); -}, +}), + (texteditor.inputs.enter = function () { + var white = this.line_starting_whitespace(this.cursor); + this.insert_char("\n"); -texteditor.inputs.enter = function(){ - var white = this.line_starting_whitespace(this.cursor); - this.insert_char('\n'); - - for (var i = 0; i < white; i++) - this.insert_char(" "); -}; + for (var i = 0; i < white; i++) this.insert_char(" "); + }); texteditor.inputs.enter.rep = true; -texteditor.inputs.backspace = function(){ - this.value = this.value.slice(0,this.cursor-1) + this.value.slice(this.cursor); +texteditor.inputs.backspace = function () { + this.value = this.value.slice(0, this.cursor - 1) + this.value.slice(this.cursor); this.cursor--; }; texteditor.inputs.backspace.rep = true; - -texteditor.inputs['C-s'] = function() { - if (this.srctype === 'function') { +texteditor.inputs["C-s"] = function () { + if (this.srctype === "function") { eval(`${this.src} = ${this.value}`); } }; -texteditor.inputs['C-s'].doc = "Save edited text."; +texteditor.inputs["C-s"].doc = "Save edited text."; -texteditor.inputs['C-u'] = function() { this.popstate(); }; -texteditor.inputs['C-u'].doc = "Undo."; +texteditor.inputs["C-u"] = function () { + this.popstate(); +}; +texteditor.inputs["C-u"].doc = "Undo."; -texteditor.inputs['C-q'] = function() { +texteditor.inputs["C-q"] = function () { var ws = this.prev_word(this.cursor); - var we = this.end_of_word(this.cursor)+1; + var we = this.end_of_word(this.cursor) + 1; var find = this.copy(ws, we); var obj = editor.edit_level.varname2obj(find); @@ -217,109 +208,109 @@ texteditor.inputs['C-q'] = function() { editor.selectlist.push(obj); } }; -texteditor.inputs['C-q'].doc = "Select object of selected word."; +texteditor.inputs["C-q"].doc = "Select object of selected word."; -texteditor.inputs['C-o'] = function() { - this.insert_char('\n'); +texteditor.inputs["C-o"] = function () { + this.insert_char("\n"); this.cursor--; }; -texteditor.inputs['C-o'].doc = "Insert newline."; -texteditor.inputs['C-o'].rep = true; +texteditor.inputs["C-o"].doc = "Insert newline."; +texteditor.inputs["C-o"].rep = true; -texteditor.inputs['M-o'] = function() { - while (this.line_blank(this.next_line(this.cursor))) - this.delete_line(this.next_line(this.cursor)); +texteditor.inputs["M-o"] = function () { + while (this.line_blank(this.next_line(this.cursor))) this.delete_line(this.next_line(this.cursor)); - while (this.line_blank(this.prev_line(this.cursor))) - this.delete_line(this.prev_line(this.cursor)); + while (this.line_blank(this.prev_line(this.cursor))) this.delete_line(this.prev_line(this.cursor)); }; -texteditor.inputs['M-o'].doc = "Delete surround blank lines."; +texteditor.inputs["M-o"].doc = "Delete surround blank lines."; -texteditor.inputs['C-d'] = function () { this.value = this.value.slice(0,this.cursor) + this.value.slice(this.cursor+1); }; -texteditor.inputs['C-d'].doc = "Delete character."; +texteditor.inputs["C-d"] = function () { + this.value = this.value.slice(0, this.cursor) + this.value.slice(this.cursor + 1); +}; +texteditor.inputs["C-d"].doc = "Delete character."; -texteditor.inputs['M-d'] = function() { this.cut_span(this.cursor, this.end_of_word(this.cursor)+1); }; -texteditor.inputs['M-d'].doc = "Delete word."; +texteditor.inputs["M-d"] = function () { + this.cut_span(this.cursor, this.end_of_word(this.cursor) + 1); +}; +texteditor.inputs["M-d"].doc = "Delete word."; -texteditor.inputs['C-a'] = function() { +texteditor.inputs["C-a"] = function () { this.to_line_start(); this.desired_inset = this.inset; }; -texteditor.inputs['C-a'].doc = "To start of line."; +texteditor.inputs["C-a"].doc = "To start of line."; -texteditor.inputs['C-y'] = function() { +texteditor.inputs["C-y"] = function () { if (this.killring.length === 0) return; this.insert_char(this.killring.pop()); }; -texteditor.inputs['C-y'].doc = "Insert from killring."; +texteditor.inputs["C-y"].doc = "Insert from killring."; -texteditor.inputs['C-e'] = function() { +texteditor.inputs["C-e"] = function () { this.to_line_end(); this.desired_inset = this.inset; }; -texteditor.inputs['C-e'].doc = "To line end."; +texteditor.inputs["C-e"].doc = "To line end."; -texteditor.inputs['C-k'] = function() { - if (this.cursor === this.value.length-1) return; - var killamt = this.value.next('\n', this.cursor) - this.cursor; - var killed = this.cut_span(this.cursor-1, this.cursor+killamt); +texteditor.inputs["C-k"] = function () { + if (this.cursor === this.value.length - 1) return; + var killamt = this.value.next("\n", this.cursor) - this.cursor; + var killed = this.cut_span(this.cursor - 1, this.cursor + killamt); this.killring.push(killed); }; -texteditor.inputs['C-k'].doc = "Kill from cursor to end of line."; +texteditor.inputs["C-k"].doc = "Kill from cursor to end of line."; -texteditor.inputs['M-k'] = function() { - var prevn = this.value.prev('\n', this.cursor); +texteditor.inputs["M-k"] = function () { + var prevn = this.value.prev("\n", this.cursor); var killamt = this.cursor - prevn; - var killed = this.cut_span(prevn+1, prevn+killamt); + var killed = this.cut_span(prevn + 1, prevn + killamt); this.killring.push(killed); this.to_line_start(); }; -texteditor.inputs['M-k'].doc = "Kill entire line the cursor is on."; +texteditor.inputs["M-k"].doc = "Kill entire line the cursor is on."; -texteditor.inputs['C-b'] = function() { +texteditor.inputs["C-b"] = function () { this.cursor--; this.desired_inset = this.inset; }; -texteditor.inputs['C-b'].rep = true; -texteditor.inputs['M-b'] = function() { - this.cursor = this.prev_word(this.cursor-2); +texteditor.inputs["C-b"].rep = true; +texteditor.inputs["M-b"] = function () { + this.cursor = this.prev_word(this.cursor - 2); this.desired_inset = this.inset; }; -texteditor.inputs['M-b'].rep = true; +texteditor.inputs["M-b"].rep = true; -texteditor.inputs['C-f'] = function() { +texteditor.inputs["C-f"] = function () { this.cursor++; this.desired_inset = this.inset; }; -texteditor.inputs['C-f'].rep = true; -texteditor.inputs['M-f'] = function() { +texteditor.inputs["C-f"].rep = true; +texteditor.inputs["M-f"] = function () { this.cursor = this.next_word(this.cursor); this.desired_inset = this.inset; }; -texteditor.inputs['M-f'].rep = true; +texteditor.inputs["M-f"].rep = true; -texteditor.inputs['C-p'] = function() { +texteditor.inputs["C-p"] = function () { if (this.cursor === 0) return; this.desired_inset = Math.max(this.desired_inset, this.inset); this.cursor = this.prev_line(this.cursor); var newlinew = this.line_width(this.cursor); this.cursor += Math.min(this.desired_inset, newlinew); }; -texteditor.inputs['C-p'].rep = true; +texteditor.inputs["C-p"].rep = true; -texteditor.inputs['M-p'] = function() { - while (this.line_blank(this.cursor)) - this.cursor = this.prev_line(this.cursor); +texteditor.inputs["M-p"] = function () { + while (this.line_blank(this.cursor)) this.cursor = this.prev_line(this.cursor); - while (!this.line_blank(this.cursor)) - this.cursor = this.prev_line(this.cursor); + while (!this.line_blank(this.cursor)) this.cursor = this.prev_line(this.cursor); }; -texteditor.inputs['M-p'].doc = "Go up to next line with text on it."; -texteditor.inputs['M-p'].rep = true; +texteditor.inputs["M-p"].doc = "Go up to next line with text on it."; +texteditor.inputs["M-p"].rep = true; -texteditor.inputs['C-n'] = function() { - if (this.cursor === this.value.length-1) return; - if (this.value.next('\n', this.cursor) === -1) { +texteditor.inputs["C-n"] = function () { + if (this.cursor === this.value.length - 1) return; + if (this.value.next("\n", this.cursor) === -1) { this.to_file_end(); return; } @@ -329,20 +320,16 @@ texteditor.inputs['C-n'] = function() { var newlinew = this.line_width(this.cursor); this.cursor += Math.min(this.desired_inset, newlinew); }; -texteditor.inputs['C-n'].rep = true; +texteditor.inputs["C-n"].rep = true; -texteditor.inputs['M-n'] = function() { - while (this.line_blank(this.cursor)) - this.cursor = this.next_line(this.cursor); - - while (!this.line_blank(this.cursor)) - this.cursor = this.next_line(this.cursor); +texteditor.inputs["M-n"] = function () { + while (this.line_blank(this.cursor)) this.cursor = this.next_line(this.cursor); + while (!this.line_blank(this.cursor)) this.cursor = this.next_line(this.cursor); }; -texteditor.inputs['M-n'].doc = "Go down to next line with text on it."; -texteditor.inputs['M-n'].rep = true; +texteditor.inputs["M-n"].doc = "Go down to next line with text on it."; +texteditor.inputs["M-n"].rep = true; -texteditor.open_fn = function(fnstr) -{ +texteditor.open_fn = function (fnstr) { var fn = eval(fnstr); if (!fn) { console.warn(`${fnstr} is not a function.`); @@ -353,4 +340,4 @@ texteditor.open_fn = function(fnstr) editor.openpanel(this); this.value = fn; this.cursor = 0; -} +}; diff --git a/scripts/tween.js b/scripts/tween.js index 8d90fe80..7cc1a593 100644 --- a/scripts/tween.js +++ b/scripts/tween.js @@ -1,40 +1,43 @@ /* Take numbers from 0 to 1 and remap them to easing functions */ var Ease = { - linear(t) { return t; }, + linear(t) { + return t; + }, - in(t) { return t*t; }, + in(t) { + return t * t; + }, out(t) { - var d = 1-t; - return 1 - d*d + var d = 1 - t; + return 1 - d * d; }, inout(t) { - var d = -2*t + 2; + var d = -2 * t + 2; return t < 0.5 ? 2 * t * t : 1 - (d * d) / 2; }, }; - function make_easing_fns(num) { var obj = {}; - obj.in = function(t) { - return Math.pow(t,num); + obj.in = function (t) { + return Math.pow(t, num); }; - obj.out = function(t) { + obj.out = function (t) { return 1 - Math.pow(1 - t, num); }; - var mult = Math.pow(2, num-1); + var mult = Math.pow(2, num - 1); - obj.inout = function(t) { + obj.inout = function (t) { return t < 0.5 ? mult * Math.pow(t, num) : 1 - Math.pow(-2 * t + 2, num) / 2; }; return obj; -}; +} Ease.quad = make_easing_fns(2); Ease.cubic = make_easing_fns(3); @@ -52,7 +55,7 @@ Ease.expo = { inout(t) { return t === 0 ? 0 : t === 1 ? 1 : t < 0.5 ? Math.pow(2, 20 * t - 10) / 2 : (2 - Math.pow(2, -20 * t + 10)) / 2; - } + }, }; Ease.bounce = { @@ -64,52 +67,57 @@ Ease.bounce = { var n1 = 7.5625; var d1 = 2.75; - if (t < 1 / d1) { return n1 * t * t; } - else if (t < 2 / d1) { return n1 * (t -= 1.5 / d1) * t + 0.75; } - else if (t < 2.5 / d1) { return n1 * (t -= 2.25 / d1) * t + 0.9375; } - else - return n1 * (t -= 2.625 / d1) * t + 0.984375; + if (t < 1 / d1) { + return n1 * t * t; + } else if (t < 2 / d1) { + return n1 * (t -= 1.5 / d1) * t + 0.75; + } else if (t < 2.5 / d1) { + return n1 * (t -= 2.25 / d1) * t + 0.9375; + } else return n1 * (t -= 2.625 / d1) * t + 0.984375; }, inout(t) { return t < 0.5 ? (1 - this.out(1 - 2 * t)) / 2 : (1 + this.out(2 * t - 1)) / 2; - } + }, }; Ease.sine = { - in(t) { return 1 - Math.cos((t * Math.PI)/2); }, + in(t) { + return 1 - Math.cos((t * Math.PI) / 2); + }, - out(t) { return Math.sin((t*Math.PI)/2); }, + out(t) { + return Math.sin((t * Math.PI) / 2); + }, - inout(t) { return -(Math.cos(Math.PI*t) - 1) / 2; } + inout(t) { + return -(Math.cos(Math.PI * t) - 1) / 2; + }, }; Ease.elastic = { in(t) { - return t === 0 ? 0 : t === 1 ? 1 : -Math.pow(2, 10*t-10) * Math.sin((t * 10 - 10.75) * this.c4); + return t === 0 ? 0 : t === 1 ? 1 : -Math.pow(2, 10 * t - 10) * Math.sin((t * 10 - 10.75) * this.c4); }, out(t) { - return t === 0 ? 0 : t === 1 ? 1 : Math.pow(2, -10*t) * Math.sin((t * 10 - 0.75) * this.c4) + 1; + return t === 0 ? 0 : t === 1 ? 1 : Math.pow(2, -10 * t) * Math.sin((t * 10 - 0.75) * this.c4) + 1; }, inout(t) { - t === 0 ? 0 : t === 1 ? 1 : t < 0.5 ? - -(Math.pow(2, 20 * t - 10) * Math.sin((20 * t - 11.125) * this.c5)) / 2 - : (Math.pow(2, -20 * t + 10) * Math.sin((20 * t - 11.125) * this.c5)) / 2 + 1; + t === 0 ? 0 : t === 1 ? 1 : t < 0.5 ? -(Math.pow(2, 20 * t - 10) * Math.sin((20 * t - 11.125) * this.c5)) / 2 : (Math.pow(2, -20 * t + 10) * Math.sin((20 * t - 11.125) * this.c5)) / 2 + 1; }, }; -Ease.elastic.c4 = 2*Math.PI/3; -Ease.elastic.c5 = 2*Math.PI / 4.5; +Ease.elastic.c4 = (2 * Math.PI) / 3; +Ease.elastic.c5 = (2 * Math.PI) / 4.5; -var tween = function(from, to, time, fn, endfn) -{ +var tween = function (from, to, time, fn, endfn) { var start = profile.secs(profile.now()); - var update = function(dt) { + var update = function (dt) { profile.frame("tween"); var elapsed = profile.secs(profile.now()) - start; - fn(from.lerp(to,elapsed/time)); + fn(from.lerp(to, elapsed / time)); if (elapsed >= time) { fn(to); if (stop.then) stop.then(); @@ -120,7 +128,7 @@ var tween = function(from, to, time, fn, endfn) }; var stop = Register.update.register(update); return stop; -} +}; var Tween = { default: { @@ -133,22 +141,19 @@ var Tween = { yoyo: go up and then back down circle: go up and back down, looped */ - time: 1, /* seconds to do */ + time: 1 /* seconds to do */, ease: Ease.linear, - whole: true, /* True if time is for the entire tween, false if each stage */ - cb: function(){}, + whole: true /* True if time is for the entire tween, false if each stage */, + cb: function () {}, }, - start(obj, target, tvals, options) - { + start(obj, target, tvals, options) { var defn = Object.create(this.default); Object.assign(defn, options); - if (defn.loop === 'circle') - tvals.push(tvals[0]); - else if (defn.loop === 'yoyo') { - for (var i = tvals.length-2; i >= 0; i--) - tvals.push(tvals[i]); + if (defn.loop === "circle") tvals.push(tvals[0]); + else if (defn.loop === "yoyo") { + for (var i = tvals.length - 2; i >= 0; i--) tvals.push(tvals[i]); } defn.accum = 0; @@ -156,22 +161,19 @@ var Tween = { var slices = tvals.length - 1; var slicelen = 1 / slices; - defn.fn = function(dt) { + defn.fn = function (dt) { defn.accum += dt; - if (defn.accum >= defn.time && defn.loop === 'hold') { - if (typeof target === 'string') - obj[target] = tvals[tvals.length-1]; - else - target(tvals[tvals.length-1]); - + if (defn.accum >= defn.time && defn.loop === "hold") { + if (typeof target === "string") obj[target] = tvals[tvals.length - 1]; + else target(tvals[tvals.length - 1]); + defn.pause(); - defn.cb.call(obj); - return; + defn.cb.call(obj); + return; } defn.pct = (defn.accum % defn.time) / defn.time; - if (defn.loop === 'none' && defn.accum >= defn.time) - defn.stop(); + if (defn.loop === "none" && defn.accum >= defn.time) defn.stop(); var t = defn.whole ? defn.ease(defn.pct) : defn.pct; @@ -179,31 +181,30 @@ var Tween = { var i = Math.trunc(nval); nval -= i; - if (!defn.whole) - nval = defn.ease(nval); + if (!defn.whole) nval = defn.ease(nval); - if (typeof target === 'string') - obj[target] = tvals[i].lerp(tvals[i+1], nval); - else - target(tvals[i].lerp(tvals[i+1],nval)); + if (typeof target === "string") obj[target] = tvals[i].lerp(tvals[i + 1], nval); + else target(tvals[i].lerp(tvals[i + 1], nval)); }; var playing = false; - - defn.play = function() { + + defn.play = function () { if (playing) return; defn._end = Register.update.register(defn.fn.bind(defn)); playing = true; }; - defn.restart = function() { + defn.restart = function () { defn.accum = 0; - if (typeof target === 'string') - obj[target] = tvals[0]; - else - target(tvals[0]); + if (typeof target === "string") obj[target] = tvals[0]; + else target(tvals[0]); }; - defn.stop = function() { if (!playing) return; defn.pause(); defn.restart(); }; - defn.pause = function() { + defn.stop = function () { + if (!playing) return; + defn.pause(); + defn.restart(); + }; + defn.pause = function () { defn._end(); if (!playing) return; @@ -216,4 +217,4 @@ var Tween = { Tween.make = Tween.start; -return {Tween, Ease, tween}; +return { Tween, Ease, tween }; diff --git a/scripts/widget.js b/scripts/widget.js index 1a96aede..30be01d9 100644 --- a/scripts/widget.js +++ b/scripts/widget.js @@ -1,63 +1,62 @@ var inputpanel = { title: "untitled", - toString() { return this.title; }, + toString() { + return this.title; + }, value: "", on: false, - pos:[20,window.size.y-20], - wh:[100,100], - anchor: [0,1], - padding:[5,-15], + pos: [20, window.size.y - 20], + wh: [100, 100], + anchor: [0, 1], + padding: [5, -15], gui() { - this.win ??= Mum.window({width:this.wh.x,height:this.wh.y, color:Color.black.alpha(0.1), anchor:this.anchor, padding:this.padding}); + this.win ??= Mum.window({ + width: this.wh.x, + height: this.wh.y, + color: Color.black.alpha(0.1), + anchor: this.anchor, + padding: this.padding, + }); var itms = this.guibody(); if (!Array.isArray(itms)) itms = [itms]; - if (this.title) - this.win.items = [ - Mum.column({items: [Mum.text({str:this.title}), ...itms ]}) - ]; - else - this.win.items = itms; - - this.win.draw([100, window.size.y-50]); + if (this.title) this.win.items = [Mum.column({ items: [Mum.text({ str: this.title }), ...itms] })]; + else this.win.items = itms; + + this.win.draw([100, window.size.y - 50]); }, - + guibody() { - return [ - Mum.text({str:this.value, color:Color.green}), - Mum.button({str:"SUBMIT", action:this.submit.bind(this)}) - ]; + return [Mum.text({ str: this.value, color: Color.green }), Mum.button({ str: "SUBMIT", action: this.submit.bind(this) })]; }, - + open() { this.on = true; this.value = ""; this.start(); this.keycb(); }, - + start() {}, - + close() { player[0].uncontrol(this); this.on = false; - if ('on_close' in this) - this.on_close(); + if ("on_close" in this) this.on_close(); }, - action() { - - }, + action() {}, closeonsubmit: true, submit() { if (!this.submit_check()) return; this.action(); - if (this.closeonsubmit) - this.close(); + if (this.closeonsubmit) this.close(); }, - submit_check() { return true; }, + submit_check() { + return true; + }, keycb() {}, @@ -67,9 +66,9 @@ var inputpanel = { this.value = ""; this.caret = 0; }, - + input_backspace_pressrep() { - this.value = this.value.slice(0,-1); + this.value = this.value.slice(0, -1); this.keycb(); }, }; @@ -77,49 +76,62 @@ var inputpanel = { inputpanel.inputs = {}; inputpanel.inputs.block = true; -inputpanel.inputs.post = function() { this.keycb(); } +inputpanel.inputs.post = function () { + this.keycb(); +}; -inputpanel.inputs.char = function(c) { - this.value = this.value.slice(0,this.caret) + c + this.value.slice(this.caret); +inputpanel.inputs.char = function (c) { + this.value = this.value.slice(0, this.caret) + c + this.value.slice(this.caret); this.caret++; -} -inputpanel.inputs['C-d'] = function() { this.value = this.value.slice(0,this.caret) + this.value.slice(this.caret+1); }; -inputpanel.inputs['C-d'].rep = true; -inputpanel.inputs.tab = function() { +}; +inputpanel.inputs["C-d"] = function () { + this.value = this.value.slice(0, this.caret) + this.value.slice(this.caret + 1); +}; +inputpanel.inputs["C-d"].rep = true; +inputpanel.inputs.tab = function () { this.value = input.tabcomplete(this.value, this.assets); this.caret = this.value.length; -} -inputpanel.inputs.escape = function() { this.close(); } -inputpanel.inputs['C-b'] = function() { +}; +inputpanel.inputs.escape = function () { + this.close(); +}; +inputpanel.inputs["C-b"] = function () { if (this.caret === 0) return; this.caret--; }; -inputpanel.inputs['C-b'].rep = true; -inputpanel.inputs['C-u'] = function() -{ +inputpanel.inputs["C-b"].rep = true; +inputpanel.inputs["C-u"] = function () { this.value = this.value.slice(this.caret); this.caret = 0; -} -inputpanel.inputs['C-f'] = function() { +}; +inputpanel.inputs["C-f"] = function () { if (this.caret === this.value.length) return; this.caret++; }; -inputpanel.inputs['C-f'].rep = true; -inputpanel.inputs['C-a'] = function() { this.caret = 0; }; -inputpanel.inputs['C-e'] = function() { this.caret = this.value.length; }; -inputpanel.inputs.backspace = function() { +inputpanel.inputs["C-f"].rep = true; +inputpanel.inputs["C-a"] = function () { + this.caret = 0; +}; +inputpanel.inputs["C-e"] = function () { + this.caret = this.value.length; +}; +inputpanel.inputs.backspace = function () { if (this.caret === 0) return; - this.value = this.value.slice(0,this.caret-1) + this.value.slice(this.caret); + this.value = this.value.slice(0, this.caret - 1) + this.value.slice(this.caret); this.caret--; }; inputpanel.inputs.backspace.rep = true; -inputpanel.inputs.enter = function() { this.submit(); } - -inputpanel.inputs['C-k'] = function() { - this.value = this.value.slice(0,this.caret); +inputpanel.inputs.enter = function () { + this.submit(); }; -inputpanel.inputs.lm = function() { gui.controls.check_submit(); } +inputpanel.inputs["C-k"] = function () { + this.value = this.value.slice(0, this.caret); +}; + +inputpanel.inputs.lm = function () { + gui.controls.check_submit(); +}; var notifypanel = Object.copy(inputpanel, { title: "notification", @@ -127,28 +139,32 @@ var notifypanel = Object.copy(inputpanel, { action() { this.close(); }, - + guibody() { - return Mum.column({items: [ - Mum.text({str:this.msg}), - Mum.button({str:"OK", action:this.close.bind(this)}) - ]}); + return Mum.column({ + items: [Mum.text({ str: this.msg }), Mum.button({ str: "OK", action: this.close.bind(this) })], + }); }, }); -var gen_notify = function(val, fn) { +var gen_notify = function (val, fn) { var panel = Object.create(notifypanel); panel.msg = val; panel.yes = fn; panel.inputs = {}; - panel.inputs.y = function() { panel.yes(); panel.close(); }; + panel.inputs.y = function () { + panel.yes(); + panel.close(); + }; panel.inputs.y.doc = "Confirm yes."; - panel.inputs.enter = function() { panel.close(); }; + panel.inputs.enter = function () { + panel.close(); + }; panel.inputs.enter.doc = "Close."; return panel; }; -var listpanel = Object.copy(inputpanel, { +var listpanel = Object.copy(inputpanel, { assets: [], allassets: [], mumlist: {}, @@ -164,28 +180,31 @@ var listpanel = Object.copy(inputpanel, { this.assets = this.allassets.slice(); this.caret = 0; this.mumlist = []; - this.assets.forEach(function(x) { - this.mumlist[x] = Mum.text({str:x, action:this.action, color: Color.blue, hovered: {color:Color.red}, selectable:true}); + this.assets.forEach(function (x) { + this.mumlist[x] = Mum.text({ + str: x, + action: this.action, + color: Color.blue, + hovered: { color: Color.red }, + selectable: true, + }); }, this); }, keycb() { - if(this.value) - this.assets = this.allassets.filter(x => x.startsWith(this.value)); - else - this.assets = this.allassets.slice(); - for (var m in this.mumlist) - this.mumlist[m].hide = true; - this.assets.forEach(function(x) { - this.mumlist[x].hide = false; + if (this.value) this.assets = this.allassets.filter(x => x.startsWith(this.value)); + else this.assets = this.allassets.slice(); + for (var m in this.mumlist) this.mumlist[m].hide = true; + this.assets.forEach(function (x) { + this.mumlist[x].hide = false; }, this); }, - + guibody() { - var a = [Mum.text({str:this.value,color:Color.green, caret:this.caret})]; + var a = [Mum.text({ str: this.value, color: Color.green, caret: this.caret })]; var b = a.concat(Object.values(this.mumlist)); - return Mum.column({items:b, offset:[0,-10]}); + return Mum.column({ items: b, offset: [0, -10] }); }, }); -return {inputpanel, gen_notify, notifypanel, listpanel} \ No newline at end of file +return { inputpanel, gen_notify, notifypanel, listpanel };