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
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|

View file

@ -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('/');

View file

@ -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);
}

View file

@ -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);

View file

@ -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) {

View file

@ -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); });
}

View file

@ -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;
}
},

View file

@ -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

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_cat(FILE *f);
void log_print(const char *str);
void log_clear();
void console_print(const char *str);
#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);
else window_unfullscreen(&mainwin);
break;
case 146:
log_clear();
break;
}
if (str)