diff --git a/docs/scripting.md b/docs/scripting.md index b053104..dab11ab 100644 --- a/docs/scripting.md +++ b/docs/scripting.md @@ -1,11 +1,17 @@ # Yugine Scripting Guide +Script hooks exist to allow to modification of the game. + +|config.js|called before any game play| +|game.js|called to start the game| +|editorconfig.js|called when the editor is loaded, used to personalize| +|debug.js|called when play in editor is selected| + All objects in the Yugine can have an associated script. This script can perform setup, teardown, and handles responses for the object. |function|description| |---|---| -|setup|called before the object is loaded| |start|called when the object is loaded| -|update(dt)|called once per game frame| +|update(dt)|called once per game frame tick| |physupdate(dt)|called once per physics tick| |stop|called when the object is killed| \ No newline at end of file diff --git a/scripts/base.js b/scripts/base.js index e3b69af..6eff29f 100644 --- a/scripts/base.js +++ b/scripts/base.js @@ -80,6 +80,7 @@ Object.deepfreeze = function(obj) 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]); @@ -418,6 +419,14 @@ Object.defineProperty(String.prototype, 'tofirst', { } }); +Object.defineProperty(String.prototype, 'fromfirst', { + value: function(val) { + var idx = this.indexOf(val); + if (idx === -1) return this; + return this.slice(idx+1); + } +}); + Object.defineProperty(String.prototype, 'name', { value: function() { var idx = this.indexOf('/'); diff --git a/scripts/debug.js b/scripts/debug.js index cecfc42..65f916c 100644 --- a/scripts/debug.js +++ b/scripts/debug.js @@ -253,3 +253,15 @@ var Time = { Player.players[0].control(DebugControls); Register.gui.register(Debug.draw, Debug); + +var console = {}; +console.log = Log.say; +console.info = Log.info; +console.warn = Log.warn; +console.error = Log.error; +console.stack = Log.stack; +console.clear = function() +{ + cmd(146); +} + diff --git a/scripts/editor.js b/scripts/editor.js index 7ec411c..8d4155b 100644 --- a/scripts/editor.js +++ b/scripts/editor.js @@ -35,6 +35,10 @@ var editor = { }, edit_mode: "basic", + get_this() { + return this.edit_level; + }, + try_select() { /* nullify true if it should set selected to null if it doesn't find an object */ var go = physics.pos_query(Mouse.worldpos); return this.do_select(go); @@ -200,6 +204,7 @@ var editor = { start_play_ed() { this.stash = this.desktop.instance_obj(); Primum.clear(); + load("config.js"); Game.play(); Game.editor_mode(false); Player.players[0].uncontrol(this); @@ -218,8 +223,8 @@ var editor = { // Player.players[0].control(gui_controls); this.desktop = Primum.spawn(ur.arena); + Primum.rename_obj(this.desktop.toString(), "desktop"); this.edit_level = this.desktop; - this.desktop.toString = function() { return "desktop"; }; editor.edit_level._ed.selectable = false; if (this.stash) { this.desktop.make_objs(this.stash.objects); @@ -371,6 +376,18 @@ var editor = { }, + draw_objects_names(obj,root,depth){ + if (!obj) return; + if (!obj.objects) return; + depth ??= 0; + root = root ? root + "." : root; + Object.entries(obj.objects).forEach(function(x) { + var p = root + x[0]; + GUI.text(p, world2screen(x[1].worldpos()), 1, editor.color_depths[depth]); + editor.draw_objects_names(x[1], p, depth+1); + }); + }, + _sel_comp: undefined, get sel_comp() { return this._sel_comp; }, set sel_comp(x) { @@ -387,6 +404,8 @@ var editor = { time: 0, + color_depths: [], + ed_gui() { /* Clean out killed objects */ this.selectlist = this.selectlist.filter(function(x) { return x.alive; }); @@ -401,8 +420,10 @@ var editor = { } GUI.text("0,0", world2screen([0,0])); + + var thiso = editor.get_this(); + var clvl = thiso; - var clvl = this.selectlist.length === 1 ? this.selectlist[0] : this.edit_level; var lvlchain = []; while (clvl !== Primum) { lvlchain.push(clvl); @@ -410,38 +431,35 @@ var editor = { } lvlchain.push(clvl); - var lvlcolorsample = 1; - var colormap = ColorMap.Bathymetry; - var lvlcolor = colormap.sample(lvlcolorsample); - var ypos = 200; + var colormap = ColorMap.Inferno; + editor.color_depths = []; + for (var i = 1; i > 0 ; i -= 0.1) + editor.color_depths.push(colormap.sample(i)); + var ypos = 200; + var depth = 0; lvlchain.reverse(); lvlchain.forEach(function(x,i) { - lvlcolor = colormap.sample(lvlcolorsample); + depth = i; var lvlstr = x.toString(); if (x._ed.dirty) lvlstr += "*"; if (i === lvlchain.length-1) lvlstr += "[this]"; - GUI.text(lvlstr, [0, ypos], 1, lvlcolor); + GUI.text(lvlstr, [0, ypos], 1, editor.color_depths[depth]); - lvlcolorsample -= 0.1; - GUI.text("^^^^^^", [0,ypos+=5],1); ypos += 15; }); + + depth++; + GUI.text("$$$$$$", [0,ypos],1,editor.color_depths[depth]); - /* Color selected objects with the next deeper color */ - lvlcolorsample -= 0.1; - lvlcolor = colormap.sample(lvlcolorsample); - - GUI.text("$$$$$$", [0,ypos],1,lvlcolor); - this.selectlist.forEach(function(x) { var sname = x.__proto__.toString(); x._ed.check_dirty(); if (x._ed.dirty) sname += "*"; - GUI.text(sname, world2screen(x.worldpos()).add([0, 16]), 1, lvlcolor); + GUI.text(sname, world2screen(x.worldpos()).add([0, 16]), 1, Color.editor.ur); GUI.text(x.worldpos().map(function(x) { return Math.round(x); }), world2screen(x.worldpos()), 1, Color.white); Debug.arrow(world2screen(x.worldpos()), world2screen(x.worldpos().add(x.up().scale(40))), Color.yellow, 1); @@ -449,22 +467,12 @@ var editor = { x.gizmo(); }); - if (this.selectlist.length === 0) - for (var key in this.edit_level.objects) { - var o = this.edit_level.objects[key]; - GUI.text(key, world2screen(o.worldpos()), 1, lvlcolor); - } - else - this.selectlist.forEach(function(x) { - Object.entries(x.objects).forEach(function(x) { - GUI.text(x[0], world2screen(x[1].worldpos()), 1, lvlcolor); - }); - }); + var mg = Game.obj_at(Mouse.worldpos); - this.edit_level.objects.forEach(function(x) { - if ('ed_gizmo' in x) - x.ed_gizmo(); - }); + if (mg) { + var p = mg.path_from(thiso); + GUI.text(p, world2screen(Mouse.worldpos),1,Color.teal); + } if (this.selectlist.length === 1) { var i = 1; @@ -1047,6 +1055,13 @@ editor.inputs.mm = function() { }; editor.inputs['C-mm'] = editor.inputs.mm; +editor.inputs['C-M-lm'] = function() +{ + var go = Game.obj_at(Mouse.worldpos); + if (!go) return; + editor.edit_level = go.level; +} + editor.inputs['C-M-mm'] = function() { editor.mousejoy = Mouse.pos; editor.joystart = editor.camera.pos; @@ -1442,7 +1457,7 @@ var replpanel = Object.copy(inputpanel, { this.prevthis.unshift(this.value); this.prevmark = -1; var ecode = ""; - var repl_obj = (editor.selectlist.length === 1) ? editor.selectlist[0] : editor.edit_level; + 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}'];`; @@ -1461,6 +1476,15 @@ var replpanel = Object.copy(inputpanel, { }); replpanel.inputs = Object.create(inputpanel.inputs); +replpanel.inputs.block = true; +replpanel.inputs.lm = function() +{ + var mg = Game.obj_at(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() { this.resetscroll(); if (!this.value) return; @@ -1486,6 +1510,9 @@ replpanel.inputs.tab = function() { for (var k in obj) keys.push(k) + for (var k in editor.get_this()) + keys.push(k); + var comp = ""; if (stub) comp = tab_complete(stub, keys); diff --git a/scripts/engine.js b/scripts/engine.js index 8edf39a..c8de35d 100644 --- a/scripts/engine.js +++ b/scripts/engine.js @@ -43,6 +43,9 @@ var Color = { purple: [162,93,227], }; +Color.editor = {}; +Color.editor.ur = Color.green; + Color.tohtml = function(v) { var html = v.map(function(n) { return Number.hex(n*255); }); @@ -600,6 +603,12 @@ var Game = { if (this.objects[obj.body] === obj) this.objects[obj.body] = undefined; }, + + obj_at(worldpos) { + var idx = physics.pos_query(worldpos); + if (idx === -1) return undefined; + return Game.objects[idx]; + }, /* Returns an object given an id */ object(id) { diff --git a/scripts/entity.js b/scripts/entity.js index fda9690..98cc132 100644 --- a/scripts/entity.js +++ b/scripts/entity.js @@ -12,6 +12,21 @@ function grab_from_points(pos, points, slop) { var gameobject = { impl: { + full_path() { + return this.path_from(Primum); + }, + + path_from(o) { + var p = this.toString(); + var c = this.level; + while (c && c !== o && c !== Primum) { + p = c.toString() + "." + p; + c = c.level; + } + if (c === Primum) p = "Primum." + p; + return p; + }, + clear() { for (var k in this.objects) { Log.info(`Killing ${k}`); @@ -160,15 +175,17 @@ var gameobject = { var str = obj.toString().replaceAll('.', '_'); var n = 1; var t = str; - while (Object.hasOwn(list, t)) { + while (t in list) { t = str + n; n++; } return t; }; - var name = unique_name(parent.objects, this.ur); + var name = unique_name(parent, this.ur); + parent.objects[name] = this; + parent[name] = this; this.toString = function() { return name; }; }, @@ -177,6 +194,7 @@ var gameobject = { delete this[obj.toString()]; delete this.objects[obj.toString()]; + delete this[obj.toString()]; }, }, @@ -408,6 +426,7 @@ var gameobject = { if (typeof this.stop === 'function') this.stop(); // }); + }, up() { return [0,1].rotate(Math.deg2rad(this.angle));}, @@ -418,6 +437,7 @@ var gameobject = { make(level, data) { level ??= Primum; var obj = Object.create(this); + obj.make = undefined; obj.level = level; // this.instances.push(obj); obj.body = make_gameobject(); @@ -454,11 +474,9 @@ var gameobject = { Object.dainty_assign(obj, this); obj.sync(); - gameobject.check_registers(obj); if (Game.playing() && typeof obj.start === 'function') obj.start(); - return obj; }, @@ -479,7 +497,10 @@ var gameobject = { return; this.objects[newname] = this.objects[name]; + this[newname] = this[name]; + this[newname].toString = function() { return newname; }; delete this.objects[name]; + delete this[name]; return this.objects[newname]; }, @@ -502,6 +523,7 @@ gameobject.impl.spawn.doc = `Spawn an entity of type 'ur' on this entity. Return /* Default objects */ var prototypes = {}; +prototypes.ur_ext = ".jso"; prototypes.ur = {}; prototypes.save_gameobjects = function() { slurpwrite(JSON.stringify(gameobjects,null,2), "proto.json"); }; @@ -530,7 +552,7 @@ prototypes.from_file = function(file) file = file.replaceAll('.','/'); - var jsfile = prototypes.get_ur_file(urpath, ".js"); + var jsfile = prototypes.get_ur_file(urpath, prototypes.ur_ext); var jsonfile = prototypes.get_ur_file(urpath, ".json"); var script = undefined; @@ -655,9 +677,8 @@ prototypes.get_ur_file = function(path, ext) prototypes.generate_ur = function(path) { - var ob = IO.glob("**.js"); + var ob = IO.glob("**" + prototypes.ur_ext); ob = ob.concat(IO.glob("**.json")); - ob = ob.filter(function(path) { return path !== "game.js" && path !== "play.js" }); ob = ob.map(function(path) { return path.set_ext(""); }); ob.forEach(function(name) { prototypes.get_ur(name); }); } diff --git a/scripts/input.js b/scripts/input.js index d716db4..775810d 100644 --- a/scripts/input.js +++ b/scripts/input.js @@ -132,7 +132,11 @@ var Player = { if (!pawn.inputs.fallthru) return; } - if (!pawn.inputs?.[cmd]) continue; + + if (!pawn.inputs?.[cmd]) { + if (pawn.inputs.block) return; + continue; + } var fn = null; @@ -156,6 +160,7 @@ var Player = { } if (!pawn.inputs.fallthru) return; + if (pawn.inputs.block) return; } }, diff --git a/source/engine/debug/log.c b/source/engine/debug/log.c index d31b525..9c05d29 100644 --- a/source/engine/debug/log.c +++ b/source/engine/debug/log.c @@ -77,6 +77,11 @@ void log_print(const char *str) #endif } +void log_clear() +{ + consolelog[0] = 0; +} + void console_print(const char *str) { #ifndef NDEBUG diff --git a/source/engine/debug/log.h b/source/engine/debug/log.h index 3b12fde..e989ea0 100644 --- a/source/engine/debug/log.h +++ b/source/engine/debug/log.h @@ -38,6 +38,7 @@ void sg_logging(const char *tag, uint32_t lvl, uint32_t id, const char *msg, uin void log_setfile(char *file); void log_cat(FILE *f); void log_print(const char *str); +void log_clear(); void console_print(const char *str); #endif diff --git a/source/engine/ffi.c b/source/engine/ffi.c index 696a627..b2df6c7 100644 --- a/source/engine/ffi.c +++ b/source/engine/ffi.c @@ -1115,6 +1115,9 @@ JSValue duk_cmd(JSContext *js, JSValueConst this, int argc, JSValueConst *argv) if (js2bool(argv[1])) window_makefullscreen(&mainwin); else window_unfullscreen(&mainwin); break; + case 146: + log_clear(); + break; } if (str)