Prototype duplication fixes; split out engine.js into multiple components
This commit is contained in:
parent
acecf2fde9
commit
a4111b01a5
|
@ -51,6 +51,8 @@ void mYughLog(int category, int priority, int line, const char *file, const char
|
|||
snprintf(buffer, ERROR_BUFFER, "%s:%d: %s, %s: %s\n", file, line, logstr[priority], catstr[category], msgbuffer);
|
||||
|
||||
log_print(buffer);
|
||||
if (category != LOG_SCRIPT && priority >= 2)
|
||||
js_stacktrace();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -734,7 +734,7 @@ JSValue duk_cmd(JSContext *js, JSValueConst this, int argc, JSValueConst *argv)
|
|||
|
||||
case 38:
|
||||
str = JS_ToCString(js, argv[1]);
|
||||
ret = JS_NewString(js, slurp_text(str));
|
||||
ret = JS_NewString(js, slurp_text(str, NULL));
|
||||
break;
|
||||
|
||||
case 39:
|
||||
|
@ -1050,12 +1050,12 @@ JSValue duk_cmd(JSContext *js, JSValueConst this, int argc, JSValueConst *argv)
|
|||
return num2js(get_timescale());
|
||||
break;
|
||||
case 122:
|
||||
str = JS_ToCString(js, argv[1]);
|
||||
return script_compile(str);
|
||||
break;
|
||||
|
||||
case 123:
|
||||
str = JS_ToCString(js, argv[1]);
|
||||
file_eval_env(str, argv[2]);
|
||||
str2 = JS_ToCString(js, argv[3]);
|
||||
script_eval_w_env(str, argv[2], str2);
|
||||
break;
|
||||
|
||||
case 124:
|
||||
|
|
|
@ -378,8 +378,8 @@ void openglRender(struct window *window) {
|
|||
sg_shader sg_compile_shader(const char *v, const char *f, sg_shader_desc *d)
|
||||
{
|
||||
YughInfo("Making shader with %s and %s", v, f);
|
||||
char *vs = slurp_text(v);
|
||||
char *fs = slurp_text(f);
|
||||
char *vs = slurp_text(v, NULL);
|
||||
char *fs = slurp_text(f, NULL);
|
||||
|
||||
d->vs.source = vs;
|
||||
d->fs.source = fs;
|
||||
|
|
|
@ -177,7 +177,7 @@ unsigned char *slurp_file(const char *filename, size_t *size)
|
|||
return slurp;
|
||||
}
|
||||
|
||||
char *slurp_text(const char *filename)
|
||||
char *slurp_text(const char *filename, size_t *size)
|
||||
{
|
||||
size_t len;
|
||||
char *str = slurp_file(filename, &len);
|
||||
|
@ -185,6 +185,7 @@ char *slurp_text(const char *filename)
|
|||
memcpy(retstr, str, len);
|
||||
retstr[len] = 0;
|
||||
free(str);
|
||||
if (size) *size = len;
|
||||
return retstr;
|
||||
}
|
||||
|
||||
|
|
|
@ -17,7 +17,7 @@ char *make_path(const char *file);
|
|||
char *strdup(const char *s);
|
||||
|
||||
unsigned char *slurp_file(const char *filename, size_t *size);
|
||||
char *slurp_text(const char *filename);
|
||||
char *slurp_text(const char *filename, size_t *size);
|
||||
int slurp_write(const char *txt, const char *filename);
|
||||
|
||||
void pack_engine(const char *fname);
|
||||
|
|
|
@ -96,8 +96,9 @@ void script_evalf(const char *format, ...)
|
|||
}
|
||||
|
||||
uint8_t *compile_script(const char *file) {
|
||||
const char *script = slurp_text(file);
|
||||
JSValue obj = JS_Eval(js, script, strlen(script), file, JS_EVAL_FLAG_COMPILE_ONLY | JS_EVAL_TYPE_GLOBAL | JS_EVAL_FLAGS);
|
||||
size_t len;
|
||||
const char *script = slurp_text(file, &len);
|
||||
JSValue obj = JS_Eval(js, script, len, file, JS_EVAL_FLAG_COMPILE_ONLY | JS_EVAL_TYPE_GLOBAL | JS_EVAL_FLAGS);
|
||||
size_t out_len;
|
||||
uint8_t *out;
|
||||
return JS_WriteObject(js, &out_len, obj, JS_WRITE_OBJ_BYTECODE);
|
||||
|
@ -122,52 +123,36 @@ void js_dump_stack() {
|
|||
}
|
||||
|
||||
int script_dofile(const char *file) {
|
||||
const char *script = slurp_text(file);
|
||||
if (!script) {
|
||||
YughError("Can't find file %s.", file);
|
||||
return 0;
|
||||
}
|
||||
script_run(script,file);
|
||||
free(script);
|
||||
script_runfile(file);
|
||||
return file_mod_secs(file);
|
||||
}
|
||||
|
||||
JSValue script_runfile(const char *file)
|
||||
{
|
||||
const char *script = slurp_text(file);
|
||||
size_t len;
|
||||
const char *script = slurp_text(file, &len);
|
||||
|
||||
JSValue obj = JS_Eval(js, script, strlen(script), file, JS_EVAL_FLAGS);
|
||||
JSValue obj = JS_Eval(js, script, len, file, JS_EVAL_FLAGS);
|
||||
js_print_exception(obj);
|
||||
|
||||
free(script);
|
||||
return obj;
|
||||
}
|
||||
|
||||
JSValue script_compile(const char *file)
|
||||
{
|
||||
const char *script = slurp_text(file);
|
||||
char strbuf[strlen(script)+50];
|
||||
sprintf(strbuf, "(function(){\n%s\n})", script);
|
||||
|
||||
JSValue fn = JS_Eval(js, strbuf, strlen(strbuf), file, JS_EVAL_FLAGS);
|
||||
|
||||
free(script);
|
||||
return fn;
|
||||
}
|
||||
|
||||
/* env is an object in the scripting environment;
|
||||
s is the function to call on that object
|
||||
*/
|
||||
void script_eval_w_env(const char *s, JSValue env) {
|
||||
JSValue v = JS_EvalThis(js, env, s, strlen(s), "internal", JS_EVAL_FLAGS);
|
||||
void script_eval_w_env(const char *s, JSValue env, const char *file) {
|
||||
JSValue v = JS_EvalThis(js, env, s, strlen(s), file, JS_EVAL_FLAGS);
|
||||
js_print_exception(v);
|
||||
JS_FreeValue(js, v);
|
||||
}
|
||||
|
||||
void file_eval_env(const char *file, JSValue env)
|
||||
{
|
||||
char *script = slurp_text(file);
|
||||
JSValue v = JS_EvalThis(js, env, script, strlen(script), file, JS_EVAL_FLAGS);
|
||||
size_t len;
|
||||
char *script = slurp_text(file, &len);
|
||||
JSValue v = JS_EvalThis(js, env, script, len, file, JS_EVAL_FLAGS);
|
||||
free(script);
|
||||
js_print_exception(v);
|
||||
JS_FreeValue(js,v);
|
||||
|
|
|
@ -18,7 +18,6 @@ extern JSValue num_cache[100];
|
|||
void js_stacktrace();
|
||||
void script_startup();
|
||||
void script_run(const char *script, const char *file);
|
||||
JSValue script_compile(const char *file);
|
||||
void script_evalf(const char *format, ...);
|
||||
int script_dofile(const char *file);
|
||||
JSValue script_runfile(const char *file);
|
||||
|
@ -34,7 +33,7 @@ void script_call_sym(JSValue sym);
|
|||
void call_callee(struct callee *c);
|
||||
void script_callee(struct callee c, int argc, JSValue *argv);
|
||||
int script_has_sym(void *sym);
|
||||
void script_eval_w_env(const char *s, JSValue env);
|
||||
void script_eval_w_env(const char *s, JSValue env, const char *file);
|
||||
void file_eval_env(const char *file, JSValue env);
|
||||
|
||||
time_t file_mod_secs(const char *file);
|
||||
|
|
|
@ -33,9 +33,9 @@ void shader_compile(struct shader *shader) {
|
|||
YughInfo("Making shader with %s and %s.", shader->vertpath, shader->fragpath);
|
||||
char spath[MAXPATH];
|
||||
sprintf(spath, "%s%s", "shaders/", shader->vertpath);
|
||||
const char *vsrc = slurp_text(spath);
|
||||
const char *vsrc = slurp_text(spath, NULL);
|
||||
sprintf(spath, "%s%s", "shaders/", shader->fragpath);
|
||||
const char *fsrc = slurp_text(spath);
|
||||
const char *fsrc = slurp_text(spath, NULL);
|
||||
|
||||
shader->shd = sg_make_shader(&(sg_shader_desc){
|
||||
.vs.source = vsrc,
|
||||
|
|
|
@ -604,8 +604,8 @@ function bb_expand(oldbb, x) {
|
|||
function bb_draw(bb, color) {
|
||||
if (!bb) return;
|
||||
var draw = bb2cwh(bb);
|
||||
draw.wh[0] /= Yugine.camera.zoom;
|
||||
draw.wh[1] /= Yugine.camera.zoom;
|
||||
draw.wh[0] /= Game.camera.zoom;
|
||||
draw.wh[1] /= Game.camera.zoom;
|
||||
Debug.box(world2screen(draw.c), draw.wh, color);
|
||||
};
|
||||
|
||||
|
|
|
@ -13,7 +13,7 @@ var editor_level = Level.create();
|
|||
var editor_camera = editor_level.spawn(camera2d);
|
||||
editor_camera.save = false;
|
||||
|
||||
Yugine.view_camera(editor_camera);
|
||||
Game.view_camera(editor_camera);
|
||||
|
||||
var editor_config = {
|
||||
grid_size: 100,
|
||||
|
@ -2528,7 +2528,7 @@ limited_editor.inputs['C-q'] = function()
|
|||
// World.kill();
|
||||
World.clear_all();
|
||||
editor.load_json(editor.stash);
|
||||
Yugine.view_camera(editor_camera);
|
||||
Game.view_camera(editor_camera);
|
||||
}
|
||||
|
||||
/* This is used for editing during a paused game */
|
||||
|
|
File diff suppressed because it is too large
Load diff
392
source/scripts/gui.js
Normal file
392
source/scripts/gui.js
Normal file
|
@ -0,0 +1,392 @@
|
|||
var GUI = {
|
||||
text(str, pos, size, color, wrap) {
|
||||
size = size ? size : 1;
|
||||
color = color ? color : [255,255,255,255];
|
||||
wrap = wrap ? wrap : -1;
|
||||
|
||||
var bb = cmd(118, str, size, wrap);
|
||||
var opos = [bb.r, bb.t];
|
||||
|
||||
var h = ui_text(str, pos, size, color, wrap);
|
||||
|
||||
return bb;
|
||||
},
|
||||
|
||||
text_cursor(str, pos, size, cursor) {
|
||||
cursor_text(str,pos,size,[255,255,255],cursor);
|
||||
},
|
||||
|
||||
image(path,pos) {
|
||||
let wh = cmd(64,path);
|
||||
gui_img(path,pos.slice().sub(wh), 1.0, 0.0);
|
||||
return cwh2bb([0,0], wh);
|
||||
},
|
||||
|
||||
image_fn(defn) {
|
||||
var def = Object.create(this.defaults);
|
||||
Object.assign(def,defn);
|
||||
if (!def.path) {
|
||||
Log.warn("GUI image needs a path.");
|
||||
def.draw = function(){};
|
||||
return def;
|
||||
}
|
||||
|
||||
var tex_wh = cmd(64,def.path);
|
||||
var wh = tex_wh.slice();
|
||||
|
||||
if (def.width !== 0)
|
||||
wh.x = def.width;
|
||||
|
||||
if (def.height !== 0)
|
||||
wh.y = def.height;
|
||||
|
||||
wh = wh.scale(def.scale);
|
||||
|
||||
var sendscale = [];
|
||||
sendscale.x = wh.x / tex_wh.x;
|
||||
sendscale.y = wh.y / tex_wh.y;
|
||||
|
||||
def.draw = function(pos) {
|
||||
def.calc_bb(pos);
|
||||
gui_img(def.path, pos.sub(def.anchor.scale(wh)), sendscale, def.angle, def.image_repeat, def.image_repeat_offset, def.color);
|
||||
};
|
||||
|
||||
def.calc_bb = function(cursor) {
|
||||
def.bb = cwh2bb(wh.scale([0.5,0.5]), wh);
|
||||
def.bb = movebb(def.bb, cursor.sub(wh.scale(def.anchor)));
|
||||
};
|
||||
|
||||
return def;
|
||||
},
|
||||
|
||||
defaults: {
|
||||
padding:[2,2], /* Each element inset with this padding on all sides */
|
||||
font: "fonts/LessPerfectDOSVGA.ttf",
|
||||
font_size: 1,
|
||||
text_align: "left",
|
||||
scale: 1,
|
||||
angle: 0,
|
||||
anchor: [0,0],
|
||||
text_shadow: {
|
||||
pos: [0,0],
|
||||
color: [255,255,255,255]
|
||||
},
|
||||
text_outline: 1, /* outline in pixels */
|
||||
color: [255,255,255,255],
|
||||
margin: [5,5], /* Distance between elements for things like columns */
|
||||
width: 0,
|
||||
height: 0,
|
||||
image_repeat: false,
|
||||
image_repeat_offset: [0,0],
|
||||
debug: false, /* set to true to draw debug boxes */
|
||||
},
|
||||
|
||||
text_fn(str, defn)
|
||||
{
|
||||
var def = Object.create(this.defaults);
|
||||
Object.assign(def,defn);
|
||||
|
||||
def.draw = function(cursor) {
|
||||
def.calc_bb(cursor);
|
||||
|
||||
if (def.debug)
|
||||
Debug.boundingbox(def.bb, def.debug_colors.bounds);
|
||||
|
||||
var old = def;
|
||||
def = Object.create(def);
|
||||
|
||||
/* if (pointinbb(def.bb, Mouse.screenpos)) {
|
||||
Object.assign(def, def.hovered);
|
||||
def.calc_bb(cursor);
|
||||
GUI.selected = def;
|
||||
def.selected = true;
|
||||
}
|
||||
*/
|
||||
if (def.selected) {
|
||||
Object.assign(def, def.hovered);
|
||||
def.calc_bb(cursor);
|
||||
}
|
||||
|
||||
var pos = cursor.sub(bb2wh(def.bb).scale(def.anchor));
|
||||
|
||||
ui_text(str, pos, def.font_size, def.color, def.width);
|
||||
|
||||
def = old;
|
||||
};
|
||||
|
||||
def.calc_bb = function(cursor) {
|
||||
var bb = cmd(118, str, def.font_size, def.width);
|
||||
var wh = bb2wh(bb);
|
||||
var pos = cursor.sub(wh.scale(def.anchor));
|
||||
def.bb = movebb(bb,pos);
|
||||
};
|
||||
|
||||
return def;
|
||||
},
|
||||
|
||||
column(defn) {
|
||||
var def = Object.create(this.defaults);
|
||||
Object.assign(def,defn);
|
||||
|
||||
if (!def.items) {
|
||||
Log.warn("Columns needs items.");
|
||||
def.draw = function(){};
|
||||
return def;
|
||||
};
|
||||
|
||||
def.items.forEach(function(item,idx) {
|
||||
Object.setPrototypeOf(def.items[idx], def);
|
||||
|
||||
if (def.items[idx-1])
|
||||
def.up = def.items[idx-1];
|
||||
|
||||
if (def.items[idx+1])
|
||||
def.down = def.items[idx+1];
|
||||
});
|
||||
|
||||
def.draw = function(pos) {
|
||||
def.items.forEach(function(item) {
|
||||
item.draw.call(this,pos);
|
||||
var wh = bb2wh(item.bb);
|
||||
pos.y -= wh.y;
|
||||
pos.y -= def.padding.x*2;
|
||||
});
|
||||
};
|
||||
|
||||
return def;
|
||||
},
|
||||
|
||||
input_lmouse_pressed() {
|
||||
if (GUI.selected)
|
||||
GUI.selected.action();
|
||||
},
|
||||
|
||||
input_s_pressed() {
|
||||
if (GUI.selected?.down) {
|
||||
GUI.selected.selected = false;
|
||||
GUI.selected = GUI.selected.down;
|
||||
GUI.selected.selected = true;
|
||||
}
|
||||
},
|
||||
|
||||
input_w_pressed() {
|
||||
if (GUI.selected?.up) {
|
||||
GUI.selected.selected = false;
|
||||
GUI.selected = GUI.selected.up;
|
||||
GUI.selected.selected = true;
|
||||
}
|
||||
},
|
||||
|
||||
input_enter_pressed() {
|
||||
if (GUI.selected) {
|
||||
GUI.selected.action();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
GUI.defaults.debug_colors = {
|
||||
bounds: Color.red.slice(),
|
||||
margin: Color.blue.slice(),
|
||||
padding: Color.green.slice()
|
||||
};
|
||||
|
||||
Object.values(GUI.defaults.debug_colors).forEach(function(v) { v.a = 100; });
|
||||
|
||||
|
||||
/* Take numbers from 0 to 1 and remap them to easing functions */
|
||||
var Ease = {
|
||||
linear(t) { return t; },
|
||||
|
||||
in(t) { return t*t; },
|
||||
|
||||
out(t) {
|
||||
var d = 1-t;
|
||||
return 1 - d*d
|
||||
},
|
||||
|
||||
inout(t) {
|
||||
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.out = function(t) {
|
||||
return 1 - Math.pow(1 - t, num);
|
||||
};
|
||||
|
||||
var mult = Math.pow(2, num-1);
|
||||
|
||||
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);
|
||||
Ease.quart = make_easing_fns(4);
|
||||
Ease.quint = make_easing_fns(5);
|
||||
|
||||
Ease.expo = {
|
||||
in(t) {
|
||||
return t === 0 ? 0 : Math.pow(2, 10 * t - 10);
|
||||
},
|
||||
|
||||
out(t) {
|
||||
return t === 1 ? 1 : 1 - Math.pow(2, -10 * t);
|
||||
},
|
||||
|
||||
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 = {
|
||||
in(t) {
|
||||
return 1 - this.out(t - 1);
|
||||
},
|
||||
|
||||
out(t) {
|
||||
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;
|
||||
},
|
||||
|
||||
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); },
|
||||
|
||||
out(t) { return Math.sin((t*Math.PI)/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);
|
||||
},
|
||||
|
||||
out(t) {
|
||||
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;
|
||||
},
|
||||
};
|
||||
|
||||
Ease.elastic.c4 = 2*Math.PI/3;
|
||||
Ease.elastic.c5 = 2*Math.PI / 4.5;
|
||||
|
||||
var Tween = {
|
||||
default: {
|
||||
loop: "restart", /* none, restart, yoyo, circle */
|
||||
time: 1, /* seconds to do */
|
||||
ease: Ease.linear,
|
||||
whole: true,
|
||||
},
|
||||
|
||||
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]);
|
||||
}
|
||||
|
||||
defn.accum = 0;
|
||||
|
||||
var slices = tvals.length - 1;
|
||||
var slicelen = 1 / slices;
|
||||
|
||||
defn.fn = function(dt) {
|
||||
defn.accum += dt;
|
||||
defn.pct = (defn.accum % defn.time) / defn.time;
|
||||
|
||||
var t = defn.whole ? defn.ease(defn.pct) : defn.pct;
|
||||
|
||||
var nval = t / slicelen;
|
||||
var i = Math.trunc(nval);
|
||||
nval -= i;
|
||||
|
||||
if (!defn.whole)
|
||||
nval = defn.ease(nval);
|
||||
|
||||
obj[target] = tvals[i].lerp(tvals[i+1], nval);
|
||||
};
|
||||
|
||||
defn.restart = function() { defn.accum = 0; };
|
||||
defn.stop = function() { defn.pause(); defn.restart(); };
|
||||
defn.pause = function() { Register.update.unregister(defn.fn); };
|
||||
|
||||
Register.update.register(defn.fn, defn);
|
||||
|
||||
return defn;
|
||||
},
|
||||
|
||||
embed(obj, target, tvals, options) {
|
||||
var defn = Object.create(this.default);
|
||||
Object.assign(defn, options);
|
||||
|
||||
defn.update_vals = function(vals) {
|
||||
defn.vals = vals;
|
||||
|
||||
if (defn.loop === 'circle')
|
||||
defn.vals.push(defn.vals[0]);
|
||||
else if (defn.loop === 'yoyo') {
|
||||
for (var i = defn.vals.length-2; i >= 0; i--)
|
||||
defn.vals.push(defn.vals[i]);
|
||||
}
|
||||
|
||||
defn.slices = defn.vals.length - 1;
|
||||
defn.slicelen = 1 / defn.slices;
|
||||
};
|
||||
|
||||
defn.update_vals(tvals);
|
||||
|
||||
defn.time_s = Date.now();
|
||||
|
||||
Object.defineProperty(obj, target, {
|
||||
get() {
|
||||
defn.accum = (Date.now() - defn.time_s)/1000;
|
||||
defn.pct = (defn.accum % defn.time) / defn.time;
|
||||
var t = defn.whole ? defn.ease(defn.pct) : defn.pct;
|
||||
|
||||
var nval = t / defn.slicelen;
|
||||
var i = Math.trunc(nval);
|
||||
nval -= i;
|
||||
|
||||
if (!defn.whole)
|
||||
nval = defn.ease(nval);
|
||||
|
||||
return defn.vals[i].lerp(defn.vals[i+1],nval);
|
||||
},
|
||||
});
|
||||
|
||||
return defn;
|
||||
},
|
||||
};
|
123
source/scripts/input.js
Normal file
123
source/scripts/input.js
Normal file
|
@ -0,0 +1,123 @@
|
|||
|
||||
var Input = {
|
||||
setgame() { cmd(77); },
|
||||
setnuke() { cmd(78); },
|
||||
};
|
||||
|
||||
Input.state2str = function(state) {
|
||||
if (typeof state === 'string') return state;
|
||||
switch (state) {
|
||||
case 0:
|
||||
return "down";
|
||||
case 1:
|
||||
return "pressed";
|
||||
case 2:
|
||||
return "released";
|
||||
}
|
||||
}
|
||||
|
||||
Input.print_pawn_kbm = function(pawn) {
|
||||
if (!('inputs' in pawn)) return;
|
||||
var str = "";
|
||||
for (var key in pawn.inputs) {
|
||||
str += `${key} | ${pawn.inputs[key].doc}\n`;
|
||||
}
|
||||
return str;
|
||||
};
|
||||
|
||||
Input.print_md_kbm = function(pawn) {
|
||||
if (!('inputs' in pawn)) return;
|
||||
|
||||
var str = "";
|
||||
str += "|control|description|\n|---|---|\n";
|
||||
|
||||
for (var key in pawn.inputs) {
|
||||
str += `|${key}|${pawn.inputs[key].doc}|`;
|
||||
str += "\n";
|
||||
}
|
||||
|
||||
return str;
|
||||
};
|
||||
|
||||
Input.has_bind = function(pawn, bind) {
|
||||
return (typeof pawn.inputs?.[bind] === 'function');
|
||||
};
|
||||
|
||||
|
||||
var Action = {
|
||||
add_new(name) {
|
||||
var action = Object.create(Action);
|
||||
action.name = name;
|
||||
action.inputs = [];
|
||||
this.actions.push(action);
|
||||
|
||||
return action;
|
||||
},
|
||||
actions: [],
|
||||
};
|
||||
|
||||
/* May be a human player; may be an AI player */
|
||||
var Player = {
|
||||
players: [],
|
||||
input(fn, ...args) {
|
||||
this.pawns.forEach(x => x[fn]?.(...args));
|
||||
},
|
||||
|
||||
raw_input(cmd, state, ...args) {
|
||||
for (var pawn of this.pawns.reverse()) {
|
||||
if (typeof pawn.inputs?.any === 'function') {
|
||||
pawn.inputs.any(cmd);
|
||||
return;
|
||||
}
|
||||
if (!pawn.inputs?.[cmd]) 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':
|
||||
fn = pawn.inputs[cmd].down;
|
||||
}
|
||||
|
||||
if (typeof fn === 'function')
|
||||
fn.call(pawn, ... args);
|
||||
}
|
||||
},
|
||||
|
||||
uncontrol(pawn) {
|
||||
this.players.forEach(function(p) {
|
||||
p.pawns = p.pawns.filter(x => x !== pawn);
|
||||
});
|
||||
},
|
||||
|
||||
obj_controlled(obj) {
|
||||
for (var p in Player.players) {
|
||||
if (p.pawns.contains(obj))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
},
|
||||
|
||||
create() {
|
||||
var n = Object.create(this);
|
||||
n.pawns = [];
|
||||
n.gamepads = [];
|
||||
n.control = function(pawn) { n.pawns.push_unique(pawn); };
|
||||
n.uncontrol = function(pawn) { n.pawns = n.pawns.filter(x => x !== pawn); };
|
||||
this.players.push(n);
|
||||
return n;
|
||||
},
|
||||
};
|
||||
|
||||
for (var i = 0; i < 4; i++) {
|
||||
Player.create();
|
||||
}
|
500
source/scripts/level.js
Normal file
500
source/scripts/level.js
Normal file
|
@ -0,0 +1,500 @@
|
|||
var Level = {
|
||||
levels: [],
|
||||
objects: [],
|
||||
alive: true,
|
||||
selectable: true,
|
||||
toString() {
|
||||
if (this.file)
|
||||
return this.file;
|
||||
|
||||
return "Loose level";
|
||||
},
|
||||
|
||||
fullpath() {
|
||||
//return `${this.level.fullpath()}.${this.name}`;
|
||||
},
|
||||
|
||||
get boundingbox() {
|
||||
return bb_from_objects(this.objects);
|
||||
},
|
||||
|
||||
varname2obj(varname) {
|
||||
for (var i = 0; i < this.objects.length; i++)
|
||||
if (this.objects[i].varname === varname)
|
||||
return this.objects[i];
|
||||
|
||||
return null;
|
||||
},
|
||||
|
||||
run() {
|
||||
// TODO: If an object does not have a varname, give it one based on its parent
|
||||
this.objects.forEach(function(x) {
|
||||
if (x.hasOwn('varname')) {
|
||||
scene[x.varname] = x;
|
||||
this[x.varname] = x;
|
||||
}
|
||||
},this);
|
||||
|
||||
var script = IO.slurp(this.scriptfile);
|
||||
compile_env(`var self = this;${script}`, this, this.scriptfile);
|
||||
|
||||
if (typeof this.update === 'function')
|
||||
Register.update.register(this.update, this);
|
||||
|
||||
if (typeof this.gui === 'function')
|
||||
Register.gui.register(this.gui, this);
|
||||
|
||||
if (typeof this.nk_gui === 'function')
|
||||
register_nk_gui(this.nk_gui, this);
|
||||
|
||||
if (typeof this.inputs === 'object') {
|
||||
Player.players[0].control(this);
|
||||
}
|
||||
},
|
||||
|
||||
revert() {
|
||||
delete this.unique;
|
||||
this.load(this.filelvl);
|
||||
},
|
||||
|
||||
/* Returns how many objects this level created are still alive */
|
||||
object_count() {
|
||||
return objects.length();
|
||||
},
|
||||
|
||||
/* Save a list of objects into file, with pos acting as the relative placement */
|
||||
saveas(objects, file, pos) {
|
||||
if (!pos) pos = find_com(objects);
|
||||
|
||||
objects.forEach(function(obj) {
|
||||
obj.pos = obj.pos.sub(pos);
|
||||
});
|
||||
|
||||
var newlvl = Level.create();
|
||||
|
||||
objects.forEach(function(x) { newlvl.register(x); });
|
||||
|
||||
var save = newlvl.save();
|
||||
slurpwrite(save, file);
|
||||
},
|
||||
|
||||
clean() {
|
||||
for (var key in this.objects)
|
||||
clean_object(this.objects[key]);
|
||||
|
||||
for (var key in gameobjects)
|
||||
clean_object(gameobjects[key]);
|
||||
},
|
||||
|
||||
sync_file(file) {
|
||||
var openlvls = this.levels.filter(function(x) { return x.file === file && x !== editor.edit_level; });
|
||||
|
||||
openlvls.forEach(function(x) {
|
||||
x.clear();
|
||||
x.load(IO.slurp(x.file));
|
||||
x.flipdirty = true;
|
||||
x.sync();
|
||||
x.flipdirty = false;
|
||||
x.check_dirty();
|
||||
});
|
||||
},
|
||||
|
||||
save() {
|
||||
this.clean();
|
||||
var pos = this.pos;
|
||||
var angle = this.angle;
|
||||
|
||||
this.pos = [0,0];
|
||||
this.angle = 0;
|
||||
if (this.flipx) {
|
||||
this.objects.forEach(function(obj) {
|
||||
this.mirror_x_obj(obj);
|
||||
}, this);
|
||||
}
|
||||
|
||||
if (this.flipy) {
|
||||
this.objects.forEach(function(obj) {
|
||||
this.mirror_y_obj(obj);
|
||||
}, this);
|
||||
}
|
||||
|
||||
var savereturn = JSON.stringify(this.objects, replacer_empty_nil, 1);
|
||||
|
||||
if (this.flipx) {
|
||||
this.objects.forEach(function(obj) {
|
||||
this.mirror_x_obj(obj);
|
||||
}, this);
|
||||
}
|
||||
|
||||
if (this.flipy) {
|
||||
this.objects.forEach(function(obj) {
|
||||
this.mirror_y_obj(obj);
|
||||
}, this);
|
||||
}
|
||||
|
||||
this.pos = pos;
|
||||
this.angle = angle;
|
||||
return savereturn;
|
||||
},
|
||||
|
||||
mirror_x_obj(obj) {
|
||||
obj.flipx = !obj.flipx;
|
||||
var rp = obj.relpos;
|
||||
obj.pos = [-rp.x, rp.y].add(this.pos);
|
||||
obj.angle = -obj.angle;
|
||||
},
|
||||
|
||||
mirror_y_obj(obj) {
|
||||
var rp = obj.relpos;
|
||||
obj.pos = [rp.x, -rp.y].add(this.pos);
|
||||
obj.angle = -obj.angle;
|
||||
},
|
||||
|
||||
/* TODO: Remove this; make it work without */
|
||||
toJSON() {
|
||||
var obj = {};
|
||||
obj.file = this.file;
|
||||
obj.pos = this._pos;
|
||||
obj.angle = this._angle;
|
||||
obj.from = "group";
|
||||
obj.flipx = this.flipx;
|
||||
obj.flipy = this.flipy;
|
||||
obj.scale = this.scale;
|
||||
|
||||
if (this.varname)
|
||||
obj.varname = this.varname;
|
||||
|
||||
if (!this.unique)
|
||||
return obj;
|
||||
|
||||
obj.objects = {};
|
||||
|
||||
this.objects.forEach(function(x,i) {
|
||||
obj.objects[i] = {};
|
||||
var adiff = Math.abs(x.relangle - this.filelvl[i]._angle) > 1e-5;
|
||||
if (adiff)
|
||||
obj.objects[i].angle = x.relangle;
|
||||
|
||||
var pdiff = Vector.equal(x.relpos, this.filelvl[i]._pos, 1e-5);
|
||||
if (!pdiff)
|
||||
obj.objects[i].pos = x._pos.sub(this.pos);
|
||||
|
||||
if (obj.objects[i].empty)
|
||||
delete obj.objects[i];
|
||||
}, this);
|
||||
|
||||
return obj;
|
||||
},
|
||||
|
||||
register(obj) {
|
||||
if (obj.level)
|
||||
obj.level.unregister(obj);
|
||||
|
||||
this.objects.push(obj);
|
||||
},
|
||||
|
||||
make() {
|
||||
return Level.loadfile(this.file, this.pos);
|
||||
},
|
||||
|
||||
spawn(prefab) {
|
||||
if (typeof prefab === 'string') {
|
||||
var newobj = this.addfile(prefab);
|
||||
return newobj;
|
||||
}
|
||||
|
||||
var newobj = prefab.make();
|
||||
newobj.defn('level', this);
|
||||
this.objects.push(newobj);
|
||||
Game.register_obj(newobj);
|
||||
newobj.setup?.();
|
||||
newobj.start?.();
|
||||
if (newobj.update)
|
||||
Register.update.register(newobj.update, newobj);
|
||||
return newobj;
|
||||
},
|
||||
|
||||
dup(level) {
|
||||
level ??= this.level;
|
||||
var n = level.spawn(this.from);
|
||||
/* TODO: Assign this's properties to the dup */
|
||||
return ;n
|
||||
},
|
||||
|
||||
create() {
|
||||
var newlevel = Object.create(this);
|
||||
newlevel.objects = [];
|
||||
newlevel._pos = [0,0];
|
||||
newlevel._angle = 0;
|
||||
newlevel.color = Color.green;
|
||||
/* newlevel.toString = function() {
|
||||
return (newlevel.unique ? "#" : "") + newlevel.file;
|
||||
};
|
||||
*/
|
||||
newlevel.filejson = newlevel.save();
|
||||
return newlevel;
|
||||
},
|
||||
|
||||
addfile(file) {
|
||||
/* TODO: Register this as a prefab for caching */
|
||||
var lvl = this.loadfile(file);
|
||||
this.objects.push(lvl);
|
||||
lvl.level = this;
|
||||
return lvl;
|
||||
},
|
||||
|
||||
check_dirty() {
|
||||
this.dirty = this.save() !== this.filejson;
|
||||
},
|
||||
|
||||
start() {
|
||||
this.objects.forEach(function(x) { if ('start' in x) x.start(); });
|
||||
},
|
||||
|
||||
loadlevel(file) {
|
||||
var lvl = Level.loadfile(file);
|
||||
if (lvl && Game.playing())
|
||||
lvl.start();
|
||||
|
||||
return lvl;
|
||||
},
|
||||
|
||||
loadfile(file) {
|
||||
if (!file.endsWith(".lvl")) file = file + ".lvl";
|
||||
var newlevel = Level.create();
|
||||
|
||||
if (IO.exists(file)) {
|
||||
newlevel.filejson = IO.slurp(file);
|
||||
|
||||
try {
|
||||
newlevel.filelvl = JSON.parse(newlevel.filejson);
|
||||
newlevel.load(newlevel.filelvl);
|
||||
} catch (e) {
|
||||
newlevel.ed_gizmo = function() { GUI.text("Invalid level file: " + newlevel.file, world2screen(newlevel.pos), 1, Color.red); };
|
||||
newlevel.selectable = false;
|
||||
throw e;
|
||||
}
|
||||
newlevel.file = file;
|
||||
newlevel.dirty = false;
|
||||
}
|
||||
|
||||
var scriptfile = file.replace('.lvl', '.js');
|
||||
if (IO.exists(scriptfile)) {
|
||||
newlevel.script = IO.slurp(scriptfile);
|
||||
newlevel.scriptfile = scriptfile;
|
||||
}
|
||||
|
||||
newlevel.from = scriptfile.replace('.js','');
|
||||
newlevel.file = newlevel.from;
|
||||
newlevel.run();
|
||||
|
||||
return newlevel;
|
||||
},
|
||||
|
||||
/* Spawns all objects specified in the lvl json object */
|
||||
load(lvl) {
|
||||
this.clear();
|
||||
this.levels.push_unique(this);
|
||||
|
||||
if (!lvl) {
|
||||
Log.warn("Level is " + lvl + ". Need a better formed one.");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
var opos = this.pos;
|
||||
var oangle = this.angle;
|
||||
this.pos = [0,0];
|
||||
this.angle = 0;
|
||||
|
||||
var objs;
|
||||
var created = [];
|
||||
|
||||
if (typeof lvl === 'string')
|
||||
objs = JSON.parse(lvl);
|
||||
else
|
||||
objs = lvl;
|
||||
|
||||
if (typeof objs === 'object')
|
||||
objs = objs.array();
|
||||
|
||||
objs.forEach(x => {
|
||||
if (x.from === 'group') {
|
||||
var loadedlevel = Level.loadfile(x.file);
|
||||
if (!loadedlevel) {
|
||||
Log.error("Error loading level: file " + x.file + " not found.");
|
||||
return;
|
||||
}
|
||||
if (!IO.exists(x.file)) {
|
||||
loadedlevel.ed_gizmo = function() { GUI.text("MISSING LEVEL " + x.file, world2screen(loadedlevel.pos) ,1, Color.red) };
|
||||
}
|
||||
var objs = x.objects;
|
||||
delete x.objects;
|
||||
Object.assign(loadedlevel, x);
|
||||
|
||||
if (objs) {
|
||||
objs.array().forEach(function(x, i) {
|
||||
if (x.pos)
|
||||
loadedlevel.objects[i].pos = x.pos.add(loadedlevel.pos);
|
||||
|
||||
if (x.angle)
|
||||
loadedlevel.objects[i].angle = x.angle + loadedlevel.angle;
|
||||
});
|
||||
|
||||
loadedlevel.unique = true;
|
||||
}
|
||||
loadedlevel.level = this;
|
||||
loadedlevel.sync();
|
||||
created.push(loadedlevel);
|
||||
this.objects.push(loadedlevel);
|
||||
return;
|
||||
}
|
||||
var prototype = gameobjects[x.from];
|
||||
if (!prototype) {
|
||||
Log.error(`Prototype for ${x.from} does not exist.`);
|
||||
return;
|
||||
}
|
||||
|
||||
var newobj = this.spawn(gameobjects[x.from]);
|
||||
|
||||
delete x.from;
|
||||
|
||||
dainty_assign(newobj, x);
|
||||
|
||||
if (x._pos)
|
||||
newobj.pos = x._pos;
|
||||
|
||||
|
||||
if (x._angle)
|
||||
newobj.angle = x._angle;
|
||||
for (var key in newobj.components)
|
||||
if ('sync' in newobj.components[key]) newobj.components[key].sync();
|
||||
|
||||
newobj.sync();
|
||||
|
||||
created.push(newobj);
|
||||
});
|
||||
|
||||
created.forEach(function(x) {
|
||||
if (x.varname)
|
||||
this[x.varname] = x;
|
||||
},this);
|
||||
|
||||
this.pos = opos;
|
||||
this.angle = oangle;
|
||||
|
||||
return created;
|
||||
},
|
||||
|
||||
clear() {
|
||||
for (var i = this.objects.length-1; i >= 0; i--)
|
||||
if (this.objects[i].alive)
|
||||
this.objects[i].kill();
|
||||
|
||||
this.levels.remove(this);
|
||||
},
|
||||
|
||||
clear_all() {
|
||||
this.levels.forEach(function(x) { x.kill(); });
|
||||
},
|
||||
|
||||
kill() {
|
||||
if (this.level)
|
||||
this.level.unregister(this);
|
||||
|
||||
Register.unregister_obj(this);
|
||||
|
||||
this.clear();
|
||||
},
|
||||
|
||||
unregister(obj) {
|
||||
var removed = this.objects.remove(obj);
|
||||
|
||||
if (removed && obj.varname)
|
||||
delete this[obj.varname];
|
||||
},
|
||||
|
||||
get pos() { return this._pos; },
|
||||
set pos(x) {
|
||||
var diff = x.sub(this._pos);
|
||||
this.objects.forEach(function(x) { x.pos = x.pos.add(diff); });
|
||||
this._pos = x;
|
||||
},
|
||||
|
||||
get angle() { return this._angle; },
|
||||
set angle(x) {
|
||||
var diff = x - this._angle;
|
||||
this.objects.forEach(function(x) {
|
||||
x.angle = x.angle + diff;
|
||||
var pos = x.pos.sub(this.pos);
|
||||
var r = Vector.length(pos);
|
||||
var p = Math.rad2deg(Math.atan2(pos.y, pos.x));
|
||||
p += diff;
|
||||
p = Math.deg2rad(p);
|
||||
x.pos = this.pos.add([r*Math.cos(p), r*Math.sin(p)]);
|
||||
},this);
|
||||
this._angle = x;
|
||||
},
|
||||
|
||||
flipdirty: false,
|
||||
|
||||
sync() {
|
||||
this.flipx = this.flipx;
|
||||
this.flipy = this.flipy;
|
||||
},
|
||||
|
||||
_flipx: false,
|
||||
get flipx() { return this._flipx; },
|
||||
set flipx(x) {
|
||||
if (this._flipx === x && (!x || !this.flipdirty)) return;
|
||||
this._flipx = x;
|
||||
|
||||
this.objects.forEach(function(obj) {
|
||||
obj.flipx = !obj.flipx;
|
||||
var rp = obj.relpos;
|
||||
obj.pos = [-rp.x, rp.y].add(this.pos);
|
||||
obj.angle = -obj.angle;
|
||||
},this);
|
||||
},
|
||||
|
||||
_flipy: false,
|
||||
get flipy() { return this._flipy; },
|
||||
set flipy(x) {
|
||||
if (this._flipy === x && (!x || !this.flipdirty)) return;
|
||||
this._flipy = x;
|
||||
|
||||
this.objects.forEach(function(obj) {
|
||||
var rp = obj.relpos;
|
||||
obj.pos = [rp.x, -rp.y].add(this.pos);
|
||||
obj.angle = -obj.angle;
|
||||
},this);
|
||||
},
|
||||
|
||||
_scale: 1.0,
|
||||
get scale() { return this._scale; },
|
||||
set scale(x) {
|
||||
var diff = (x - this._scale) + 1;
|
||||
this._scale = x;
|
||||
|
||||
this.objects.forEach(function(obj) {
|
||||
obj.scale *= diff;
|
||||
obj.relpos = obj.relpos.scale(diff);
|
||||
}, this);
|
||||
},
|
||||
|
||||
get up() {
|
||||
return [0,1].rotate(Math.deg2rad(this.angle));
|
||||
},
|
||||
|
||||
get down() {
|
||||
return [0,-1].rotate(Math.deg2rad(this.angle));
|
||||
},
|
||||
|
||||
get right() {
|
||||
return [1,0].rotate(Math.deg2rad(this.angle));
|
||||
},
|
||||
|
||||
get left() {
|
||||
return [-1,0].rotate(Math.deg2rad(this.angle));
|
||||
},
|
||||
};
|
65
source/scripts/physics.js
Normal file
65
source/scripts/physics.js
Normal file
|
@ -0,0 +1,65 @@
|
|||
var Physics = {
|
||||
dynamic: 0,
|
||||
kinematic: 1,
|
||||
static: 2,
|
||||
};
|
||||
|
||||
var physics = {
|
||||
set gravity(x) { cmd(8, x); },
|
||||
get gravity() { return cmd(72); },
|
||||
set damping(x) { cmd(73,Math.clamp(x,0,1)); },
|
||||
get damping() { return cmd(74); },
|
||||
pos_query(pos) {
|
||||
return cmd(44, pos);
|
||||
},
|
||||
|
||||
/* Returns a list of body ids that a box collides with */
|
||||
box_query(box) {
|
||||
var pts = cmd(52,box.pos,box.wh);
|
||||
return cmd(52, box.pos, box.wh);
|
||||
},
|
||||
|
||||
box_point_query(box, points) {
|
||||
if (!box || !points)
|
||||
return [];
|
||||
|
||||
return cmd(86, box.pos, box.wh, points, points.length);
|
||||
},
|
||||
};
|
||||
|
||||
var Collision = {
|
||||
types: {},
|
||||
num: 10,
|
||||
set_collide(a, b, x) {
|
||||
this.types[a][b] = x;
|
||||
this.types[b][a] = x;
|
||||
},
|
||||
sync() {
|
||||
for (var i = 0; i < this.num; i++)
|
||||
cmd(76,i,this.types[i]);
|
||||
},
|
||||
types_nuke() {
|
||||
Nuke.newline(this.num+1);
|
||||
Nuke.label("");
|
||||
for (var i = 0; i < this.num; i++) Nuke.label(i);
|
||||
|
||||
for (var i = 0; i < this.num; i++) {
|
||||
Nuke.label(i);
|
||||
for (var j = 0; j < this.num; j++) {
|
||||
if (j < i)
|
||||
Nuke.label("");
|
||||
else {
|
||||
this.types[i][j] = Nuke.checkbox(this.types[i][j]);
|
||||
this.types[j][i] = this.types[i][j];
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
for (var i = 0; i < Collision.num; i++) {
|
||||
Collision.types[i] = [];
|
||||
for (var j = 0; j < Collision.num; j++)
|
||||
Collision.types[i][j] = false;
|
||||
};
|
||||
|
45
source/scripts/sound.js
Normal file
45
source/scripts/sound.js
Normal file
|
@ -0,0 +1,45 @@
|
|||
var Music = {
|
||||
play(path) {
|
||||
Log.info("Playing " + path);
|
||||
cmd(87,path);
|
||||
},
|
||||
|
||||
stop() {
|
||||
cmd(89);
|
||||
},
|
||||
|
||||
pause() {
|
||||
cmd(88);
|
||||
},
|
||||
|
||||
set volume(x) {
|
||||
},
|
||||
};
|
||||
|
||||
var Sound = {
|
||||
sounds: [], /* array of loaded sound files */
|
||||
play(file) {
|
||||
// var s = Object.create(Sound);
|
||||
// s.path = file;
|
||||
// s.play();
|
||||
this.id = cmd(14,file);
|
||||
//return s;
|
||||
},
|
||||
|
||||
music(midi, sf) {
|
||||
cmd(13, midi, sf);
|
||||
},
|
||||
|
||||
musicstop() {
|
||||
cmd(15);
|
||||
},
|
||||
|
||||
/* Between 0 and 100 */
|
||||
set volume(x) { cmd(19, x); },
|
||||
|
||||
killall() {
|
||||
Music.stop();
|
||||
this.musicstop();
|
||||
/* TODO: Kill all sound effects that may still be running */
|
||||
},
|
||||
};
|
167
source/scripts/std.js
Normal file
167
source/scripts/std.js
Normal file
|
@ -0,0 +1,167 @@
|
|||
|
||||
function compile_env(str, env, file)
|
||||
{
|
||||
file ??= "unknown";
|
||||
return cmd(123, str, env, file);
|
||||
}
|
||||
|
||||
function fcompile_env(file, env)
|
||||
{
|
||||
return compile_env(IO.slurp(file), env, file);
|
||||
}
|
||||
|
||||
var Log = {
|
||||
set level(x) { cmd(92,x); },
|
||||
get level() { return cmd(93); },
|
||||
print(msg, lvl) {
|
||||
var lg;
|
||||
if (typeof msg === 'object') {
|
||||
lg = JSON.stringify(msg, null, 2);
|
||||
} else {
|
||||
lg = msg;
|
||||
}
|
||||
|
||||
var stack = (new Error()).stack;
|
||||
var n = stack.next('\n',0)+1;
|
||||
n = stack.next('\n', n)+1;
|
||||
var nnn = stack.slice(n);
|
||||
var fmatch = nnn.match(/\(.*\:/);
|
||||
var file = fmatch ? fmatch[0].shift(1).shift(-1) : "nofile";
|
||||
var lmatch = nnn.match(/\:\d*\)/);
|
||||
var line = lmatch ? lmatch[0].shift(1).shift(-1) : "0";
|
||||
|
||||
yughlog(lvl, msg, file, line);
|
||||
},
|
||||
|
||||
info(msg) {
|
||||
this.print(msg, 0);
|
||||
},
|
||||
|
||||
warn(msg) {
|
||||
this.print(msg, 1);
|
||||
},
|
||||
|
||||
error(msg) {
|
||||
this.print(msg, 2);
|
||||
this.stack(1);
|
||||
},
|
||||
|
||||
critical(msg) {
|
||||
this.print(msg,3);
|
||||
this.stack(1);
|
||||
},
|
||||
|
||||
write(msg) {
|
||||
cmd(91,msg);
|
||||
},
|
||||
|
||||
say(msg) {
|
||||
cmd(91, `${msg}\n`);
|
||||
},
|
||||
|
||||
stack(skip = 0) {
|
||||
var stack = (new Error()).stack;
|
||||
var n = stack.next('\n',0)+1;
|
||||
for (var i = 0; i < skip; i++)
|
||||
n = stack.next('\n', n)+1;
|
||||
|
||||
this.write(stack.slice(n));
|
||||
},
|
||||
};
|
||||
|
||||
var IO = {
|
||||
exists(file) { return cmd(65, file);},
|
||||
slurp(file) {
|
||||
if (!this.exists(file)) {
|
||||
Log.warn(`File ${file} does not exist; can't slurp.`);
|
||||
return "";
|
||||
}
|
||||
return cmd(38,file);
|
||||
},
|
||||
slurpwrite(str, file) { return cmd(39, str, file); },
|
||||
extensions(ext) { return cmd(66, "." + ext); },
|
||||
};
|
||||
|
||||
var Cmdline = {};
|
||||
|
||||
Cmdline.cmds = [];
|
||||
Cmdline.register_cmd = function(flag, fn, doc) {
|
||||
Cmdline.cmds.push({
|
||||
flag: flag,
|
||||
fn: fn,
|
||||
doc: doc
|
||||
});
|
||||
};
|
||||
|
||||
function cmd_args(cmdargs)
|
||||
{
|
||||
var play = false;
|
||||
var cmds = cmdargs.split(" ");
|
||||
|
||||
Cmdline.play = false;
|
||||
|
||||
for (var i = 1; i < cmds.length; i++) {
|
||||
if (cmds[i][0] !== '-') {
|
||||
Log.warn(`Command '${cmds[i]}' should start with a '-'.`);
|
||||
continue;
|
||||
}
|
||||
|
||||
var c = Cmdline.cmds.find(function(cmd) { return cmd.flag === cmds[i].slice(1); });
|
||||
if (!c) {
|
||||
Log.warn(`Command ${cmds[i]} not recognized.`);
|
||||
continue;
|
||||
}
|
||||
|
||||
var sendstr = [];
|
||||
var j = i+1;
|
||||
while (cmds[j] && cmds[j][0] !== '-') {
|
||||
sendstr.push(cmds[j]);
|
||||
j++;
|
||||
}
|
||||
|
||||
c.fn(sendstr);
|
||||
i = j-1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Cmdline.register_cmd("p", function() { Cmdline.play = true; }, "Launch engine in play mode.");
|
||||
Cmdline.register_cmd("v", function() { Log.say(cmd(120)); Game.quit(); }, "Display engine info.");
|
||||
Cmdline.register_cmd("c", function() {}, "Redirect logging to console.");
|
||||
Cmdline.register_cmd("l", function(n) {
|
||||
Log.level = n;
|
||||
}, "Set log level.");
|
||||
Cmdline.register_cmd("h", function(str) {
|
||||
for (var cmd of Cmdline.cmds) {
|
||||
Log.say(`-${cmd.flag}: ${cmd.doc}`);
|
||||
}
|
||||
|
||||
Game.quit();
|
||||
},
|
||||
"Help.");
|
||||
Cmdline.register_cmd("b", function(str) {
|
||||
var packname;
|
||||
if (str.length === 0)
|
||||
packname = "test.cdb";
|
||||
else if (str.length > 1) {
|
||||
Log.warn("Give me a single filename for the pack.");
|
||||
Game.quit();
|
||||
} else
|
||||
packname = str[0];
|
||||
|
||||
Log.warn(`Packing into ${packname}`);
|
||||
|
||||
cmd(124, packname);
|
||||
Game.quit();
|
||||
}, "Pack the game into the given name.");
|
||||
|
||||
Cmdline.register_cmd("e", function(pawn) {
|
||||
run("scripts/editor.js");
|
||||
eval(`Log.write(Input.print_md_kbm(${pawn}));`);
|
||||
Game.quit();
|
||||
}, "Print input documentation for a given object in a markdown table." );
|
||||
|
||||
Cmdline.register_cmd("t", function() {
|
||||
Log.warn("Testing not implemented yet.");
|
||||
Game.quit();
|
||||
}, "Test suite.");
|
Loading…
Reference in a new issue