Add console object; add intuitive object view; console clear; add play hooks

This commit is contained in:
John Alanbrook 2023-10-17 17:22:06 +00:00
parent f29981ca77
commit b87cd41e70
10 changed files with 141 additions and 43 deletions

View file

@ -1,11 +1,17 @@
# Yugine Scripting Guide # 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. All objects in the Yugine can have an associated script. This script can perform setup, teardown, and handles responses for the object.
|function|description| |function|description|
|---|---| |---|---|
|setup|called before the object is loaded|
|start|called when 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| |physupdate(dt)|called once per physics tick|
|stop|called when the object is killed| |stop|called when the object is killed|

View file

@ -80,6 +80,7 @@ Object.deepfreeze = function(obj)
Object.dainty_assign = function(target, source) Object.dainty_assign = function(target, source)
{ {
Object.keys(source).forEach(function(k) { Object.keys(source).forEach(function(k) {
if (typeof source[k] === 'function') return;
if (!(k in target)) return; if (!(k in target)) return;
if (Array.isArray(source[k])) if (Array.isArray(source[k]))
target[k] = deep_copy(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', { Object.defineProperty(String.prototype, 'name', {
value: function() { value: function() {
var idx = this.indexOf('/'); var idx = this.indexOf('/');

View file

@ -253,3 +253,15 @@ var Time = {
Player.players[0].control(DebugControls); Player.players[0].control(DebugControls);
Register.gui.register(Debug.draw, Debug); 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);
}

View file

@ -35,6 +35,10 @@ var editor = {
}, },
edit_mode: "basic", 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 */ 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); var go = physics.pos_query(Mouse.worldpos);
return this.do_select(go); return this.do_select(go);
@ -200,6 +204,7 @@ var editor = {
start_play_ed() { start_play_ed() {
this.stash = this.desktop.instance_obj(); this.stash = this.desktop.instance_obj();
Primum.clear(); Primum.clear();
load("config.js");
Game.play(); Game.play();
Game.editor_mode(false); Game.editor_mode(false);
Player.players[0].uncontrol(this); Player.players[0].uncontrol(this);
@ -218,8 +223,8 @@ var editor = {
// Player.players[0].control(gui_controls); // Player.players[0].control(gui_controls);
this.desktop = Primum.spawn(ur.arena); this.desktop = Primum.spawn(ur.arena);
Primum.rename_obj(this.desktop.toString(), "desktop");
this.edit_level = this.desktop; this.edit_level = this.desktop;
this.desktop.toString = function() { return "desktop"; };
editor.edit_level._ed.selectable = false; editor.edit_level._ed.selectable = false;
if (this.stash) { if (this.stash) {
this.desktop.make_objs(this.stash.objects); 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, _sel_comp: undefined,
get sel_comp() { return this._sel_comp; }, get sel_comp() { return this._sel_comp; },
set sel_comp(x) { set sel_comp(x) {
@ -387,6 +404,8 @@ var editor = {
time: 0, time: 0,
color_depths: [],
ed_gui() { ed_gui() {
/* Clean out killed objects */ /* Clean out killed objects */
this.selectlist = this.selectlist.filter(function(x) { return x.alive; }); this.selectlist = this.selectlist.filter(function(x) { return x.alive; });
@ -402,7 +421,9 @@ var editor = {
GUI.text("0,0", world2screen([0,0])); GUI.text("0,0", world2screen([0,0]));
var clvl = this.selectlist.length === 1 ? this.selectlist[0] : this.edit_level; var thiso = editor.get_this();
var clvl = thiso;
var lvlchain = []; var lvlchain = [];
while (clvl !== Primum) { while (clvl !== Primum) {
lvlchain.push(clvl); lvlchain.push(clvl);
@ -410,38 +431,35 @@ var editor = {
} }
lvlchain.push(clvl); lvlchain.push(clvl);
var lvlcolorsample = 1; var colormap = ColorMap.Inferno;
var colormap = ColorMap.Bathymetry; editor.color_depths = [];
var lvlcolor = colormap.sample(lvlcolorsample); for (var i = 1; i > 0 ; i -= 0.1)
var ypos = 200; editor.color_depths.push(colormap.sample(i));
var ypos = 200;
var depth = 0;
lvlchain.reverse(); lvlchain.reverse();
lvlchain.forEach(function(x,i) { lvlchain.forEach(function(x,i) {
lvlcolor = colormap.sample(lvlcolorsample); depth = i;
var lvlstr = x.toString(); var lvlstr = x.toString();
if (x._ed.dirty) if (x._ed.dirty)
lvlstr += "*"; lvlstr += "*";
if (i === lvlchain.length-1) lvlstr += "[this]"; 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); GUI.text("^^^^^^", [0,ypos+=5],1);
ypos += 15; ypos += 15;
}); });
/* Color selected objects with the next deeper color */ depth++;
lvlcolorsample -= 0.1; GUI.text("$$$$$$", [0,ypos],1,editor.color_depths[depth]);
lvlcolor = colormap.sample(lvlcolorsample);
GUI.text("$$$$$$", [0,ypos],1,lvlcolor);
this.selectlist.forEach(function(x) { this.selectlist.forEach(function(x) {
var sname = x.__proto__.toString(); var sname = x.__proto__.toString();
x._ed.check_dirty(); x._ed.check_dirty();
if (x._ed.dirty) sname += "*"; 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); 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); Debug.arrow(world2screen(x.worldpos()), world2screen(x.worldpos().add(x.up().scale(40))), Color.yellow, 1);
@ -449,22 +467,12 @@ var editor = {
x.gizmo(); x.gizmo();
}); });
if (this.selectlist.length === 0) var mg = Game.obj_at(Mouse.worldpos);
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);
});
});
this.edit_level.objects.forEach(function(x) { if (mg) {
if ('ed_gizmo' in x) var p = mg.path_from(thiso);
x.ed_gizmo(); GUI.text(p, world2screen(Mouse.worldpos),1,Color.teal);
}); }
if (this.selectlist.length === 1) { if (this.selectlist.length === 1) {
var i = 1; var i = 1;
@ -1047,6 +1055,13 @@ editor.inputs.mm = function() {
}; };
editor.inputs['C-mm'] = editor.inputs.mm; 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.inputs['C-M-mm'] = function() {
editor.mousejoy = Mouse.pos; editor.mousejoy = Mouse.pos;
editor.joystart = editor.camera.pos; editor.joystart = editor.camera.pos;
@ -1442,7 +1457,7 @@ var replpanel = Object.copy(inputpanel, {
this.prevthis.unshift(this.value); this.prevthis.unshift(this.value);
this.prevmark = -1; this.prevmark = -1;
var ecode = ""; 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;`; ecode += `var $ = repl_obj.objects;`;
for (var key in repl_obj.objects) for (var key in repl_obj.objects)
ecode += `var ${key} = editor.edit_level.objects['${key}'];`; 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 = 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() { replpanel.inputs.tab = function() {
this.resetscroll(); this.resetscroll();
if (!this.value) return; if (!this.value) return;
@ -1486,6 +1510,9 @@ replpanel.inputs.tab = function() {
for (var k in obj) for (var k in obj)
keys.push(k) keys.push(k)
for (var k in editor.get_this())
keys.push(k);
var comp = ""; var comp = "";
if (stub) if (stub)
comp = tab_complete(stub, keys); comp = tab_complete(stub, keys);

View file

@ -43,6 +43,9 @@ var Color = {
purple: [162,93,227], purple: [162,93,227],
}; };
Color.editor = {};
Color.editor.ur = Color.green;
Color.tohtml = function(v) Color.tohtml = function(v)
{ {
var html = v.map(function(n) { return Number.hex(n*255); }); var html = v.map(function(n) { return Number.hex(n*255); });
@ -601,6 +604,12 @@ var Game = {
this.objects[obj.body] = undefined; 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 */ /* Returns an object given an id */
object(id) { object(id) {
return this.objects[id]; return this.objects[id];

View file

@ -12,6 +12,21 @@ function grab_from_points(pos, points, slop) {
var gameobject = { var gameobject = {
impl: { 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() { clear() {
for (var k in this.objects) { for (var k in this.objects) {
Log.info(`Killing ${k}`); Log.info(`Killing ${k}`);
@ -160,15 +175,17 @@ var gameobject = {
var str = obj.toString().replaceAll('.', '_'); var str = obj.toString().replaceAll('.', '_');
var n = 1; var n = 1;
var t = str; var t = str;
while (Object.hasOwn(list, t)) { while (t in list) {
t = str + n; t = str + n;
n++; n++;
} }
return t; return t;
}; };
var name = unique_name(parent.objects, this.ur); var name = unique_name(parent, this.ur);
parent.objects[name] = this; parent.objects[name] = this;
parent[name] = this;
this.toString = function() { return name; }; this.toString = function() { return name; };
}, },
@ -177,6 +194,7 @@ var gameobject = {
delete this[obj.toString()]; delete this[obj.toString()];
delete this.objects[obj.toString()]; delete this.objects[obj.toString()];
delete this[obj.toString()];
}, },
}, },
@ -408,6 +426,7 @@ var gameobject = {
if (typeof this.stop === 'function') if (typeof this.stop === 'function')
this.stop(); this.stop();
// }); // });
}, },
up() { return [0,1].rotate(Math.deg2rad(this.angle));}, up() { return [0,1].rotate(Math.deg2rad(this.angle));},
@ -418,6 +437,7 @@ var gameobject = {
make(level, data) { make(level, data) {
level ??= Primum; level ??= Primum;
var obj = Object.create(this); var obj = Object.create(this);
obj.make = undefined;
obj.level = level; obj.level = level;
// this.instances.push(obj); // this.instances.push(obj);
obj.body = make_gameobject(); obj.body = make_gameobject();
@ -454,11 +474,9 @@ var gameobject = {
Object.dainty_assign(obj, this); Object.dainty_assign(obj, this);
obj.sync(); obj.sync();
gameobject.check_registers(obj); gameobject.check_registers(obj);
if (Game.playing() && typeof obj.start === 'function') obj.start(); if (Game.playing() && typeof obj.start === 'function') obj.start();
return obj; return obj;
}, },
@ -479,7 +497,10 @@ var gameobject = {
return; return;
this.objects[newname] = this.objects[name]; this.objects[newname] = this.objects[name];
this[newname] = this[name];
this[newname].toString = function() { return newname; };
delete this.objects[name]; delete this.objects[name];
delete this[name];
return this.objects[newname]; return this.objects[newname];
}, },
@ -502,6 +523,7 @@ gameobject.impl.spawn.doc = `Spawn an entity of type 'ur' on this entity. Return
/* Default objects */ /* Default objects */
var prototypes = {}; var prototypes = {};
prototypes.ur_ext = ".jso";
prototypes.ur = {}; prototypes.ur = {};
prototypes.save_gameobjects = function() { slurpwrite(JSON.stringify(gameobjects,null,2), "proto.json"); }; prototypes.save_gameobjects = function() { slurpwrite(JSON.stringify(gameobjects,null,2), "proto.json"); };
@ -530,7 +552,7 @@ prototypes.from_file = function(file)
file = file.replaceAll('.','/'); 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 jsonfile = prototypes.get_ur_file(urpath, ".json");
var script = undefined; var script = undefined;
@ -655,9 +677,8 @@ prototypes.get_ur_file = function(path, ext)
prototypes.generate_ur = function(path) 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.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 = ob.map(function(path) { return path.set_ext(""); });
ob.forEach(function(name) { prototypes.get_ur(name); }); ob.forEach(function(name) { prototypes.get_ur(name); });
} }

View file

@ -132,7 +132,11 @@ var Player = {
if (!pawn.inputs.fallthru) if (!pawn.inputs.fallthru)
return; return;
} }
if (!pawn.inputs?.[cmd]) continue;
if (!pawn.inputs?.[cmd]) {
if (pawn.inputs.block) return;
continue;
}
var fn = null; var fn = null;
@ -156,6 +160,7 @@ var Player = {
} }
if (!pawn.inputs.fallthru) return; if (!pawn.inputs.fallthru) return;
if (pawn.inputs.block) return;
} }
}, },

View file

@ -77,6 +77,11 @@ void log_print(const char *str)
#endif #endif
} }
void log_clear()
{
consolelog[0] = 0;
}
void console_print(const char *str) void console_print(const char *str)
{ {
#ifndef NDEBUG #ifndef NDEBUG

View file

@ -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_setfile(char *file);
void log_cat(FILE *f); void log_cat(FILE *f);
void log_print(const char *str); void log_print(const char *str);
void log_clear();
void console_print(const char *str); void console_print(const char *str);
#endif #endif

View file

@ -1115,6 +1115,9 @@ JSValue duk_cmd(JSContext *js, JSValueConst this, int argc, JSValueConst *argv)
if (js2bool(argv[1])) window_makefullscreen(&mainwin); if (js2bool(argv[1])) window_makefullscreen(&mainwin);
else window_unfullscreen(&mainwin); else window_unfullscreen(&mainwin);
break; break;
case 146:
log_clear();
break;
} }
if (str) if (str)