JSO compiler; packer; update CDB to 0.80; assets now packed into binary
This commit is contained in:
@@ -646,6 +646,11 @@ static inline HMM_Vec4 HMM_SubV4(HMM_Vec4 Left, HMM_Vec4 Right) {
|
||||
return Result;
|
||||
}
|
||||
|
||||
static inline HMM_Vec2 HMM_ScaleV2(HMM_Vec2 v, double s)
|
||||
{
|
||||
return HMM_V2(v.X*s, v.Y*s);
|
||||
}
|
||||
|
||||
static inline HMM_Vec2 HMM_MulV2(HMM_Vec2 Left, HMM_Vec2 Right) {
|
||||
|
||||
HMM_Vec2 Result;
|
||||
|
||||
@@ -1099,6 +1099,14 @@ JSValue duk_cmd(JSContext *js, JSValueConst this, int argc, JSValueConst *argv)
|
||||
case 135:
|
||||
ret = float2js(cam_zoom());
|
||||
break;
|
||||
|
||||
case 136:
|
||||
ret = v22js(world2screen(js2hmmv2(argv[1])));
|
||||
break;
|
||||
|
||||
case 137:
|
||||
ret = v22js(screen2world(js2hmmv2(argv[1])));
|
||||
break;
|
||||
}
|
||||
|
||||
if (str)
|
||||
|
||||
@@ -382,9 +382,6 @@ void call_input_down(int *key) {
|
||||
|
||||
/* This is called once every frame - or more if we want it more! */
|
||||
void input_poll(double wait) {
|
||||
mouse_delta = cpvzero;
|
||||
mousewheel = cpvzero;
|
||||
|
||||
for (int i = 0; i < arrlen(downkeys); i++)
|
||||
call_input_down(&downkeys[i]);
|
||||
}
|
||||
|
||||
@@ -15,6 +15,10 @@
|
||||
#include "stb_ds.h"
|
||||
#include "resources.h"
|
||||
#include "yugine.h"
|
||||
#include "sokol/sokol_app.h"
|
||||
|
||||
#define SOKOL_GLUE_IMPL
|
||||
#include "sokol/sokol_glue.h"
|
||||
|
||||
#include "crt.sglsl.h"
|
||||
#include "box.sglsl.h"
|
||||
@@ -209,6 +213,8 @@ void render_init() {
|
||||
mainwin.height = sapp_height();
|
||||
|
||||
sg_setup(&(sg_desc){
|
||||
.context = sapp_sgcontext(),
|
||||
.mtl_force_managed_storage_mode = 1,
|
||||
.logger = {
|
||||
.func = sg_logging,
|
||||
.user_data = NULL,
|
||||
@@ -372,9 +378,23 @@ cpVect cam_pos() {
|
||||
|
||||
static float zoom = 1.f;
|
||||
float cam_zoom() { return zoom; }
|
||||
|
||||
void add_zoom(float val) { zoom = val; }
|
||||
|
||||
HMM_Vec2 world2screen(HMM_Vec2 pos)
|
||||
{
|
||||
pos = HMM_SubV2(pos, HMM_V2(cam_pos().x, cam_pos().y));
|
||||
pos = HMM_ScaleV2(pos, 1.0/zoom);
|
||||
pos = HMM_AddV2(pos, HMM_V2(mainwin.width/2.0, mainwin.height/2.0));
|
||||
return pos;
|
||||
}
|
||||
|
||||
HMM_Vec2 screen2world(HMM_Vec2 pos)
|
||||
{
|
||||
pos = HMM_AddV2(pos, HMM_V2(mainwin.width/2.0, mainwin.height/2.0));
|
||||
pos = HMM_MulV2(pos, HMM_V2(zoom,zoom));
|
||||
return HMM_AddV2(pos, HMM_V2(cam_pos().x, cam_pos().y));
|
||||
}
|
||||
|
||||
HMM_Mat4 projection = {0.f};
|
||||
HMM_Mat4 hudproj = {0.f};
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#define SOKOL_GLCORE33
|
||||
#define SOKOL_WIN32_FORCE_MAIN
|
||||
#elif __APPLE__
|
||||
// #define SOKOL_METAL
|
||||
#define SOKOL_GLCORE33
|
||||
#endif
|
||||
|
||||
@@ -77,6 +78,8 @@ void set_cam_body(cpBody *body);
|
||||
cpVect cam_pos();
|
||||
float cam_zoom();
|
||||
void add_zoom(float val);
|
||||
HMM_Vec2 world2screen(HMM_Vec2 pos);
|
||||
HMM_Vec2 screen2world(HMM_Vec2 pos);
|
||||
|
||||
sg_shader sg_compile_shader(const char *v, const char *f, sg_shader_desc *d);
|
||||
|
||||
|
||||
@@ -22,6 +22,8 @@
|
||||
|
||||
#include "stb_ds.h"
|
||||
|
||||
#include "core.cdb.h"
|
||||
|
||||
char *DATA_PATH = NULL;
|
||||
char *PREF_PATH = NULL;
|
||||
|
||||
@@ -36,8 +38,8 @@ char pathbuf[MAXPATH + 1];
|
||||
|
||||
const char *DB_NAME = "test.db";
|
||||
|
||||
static struct cdb corecdb;
|
||||
static struct cdb game_cdb;
|
||||
static int loaded_cdb = 0;
|
||||
|
||||
void resources_init() {
|
||||
DATA_PATH = malloc(MAXPATH);
|
||||
@@ -47,10 +49,9 @@ void resources_init() {
|
||||
if (!PREF_PATH)
|
||||
PREF_PATH = strdup("./tmp/");
|
||||
|
||||
int fd;
|
||||
fd = open("test.cdb", O_RDONLY);
|
||||
int fd = open("test.cdb", O_RDONLY);
|
||||
cdb_init(&game_cdb, fd);
|
||||
loaded_cdb = 1;
|
||||
cdb_initf(&corecdb, core_cdb, core_cdb_len);
|
||||
}
|
||||
|
||||
char *get_filename_from_path(char *path, int extension) {
|
||||
@@ -86,6 +87,21 @@ FILE *res_open(char *path, const char *tag) {
|
||||
return f;
|
||||
}
|
||||
|
||||
char *seprint(char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start (args, fmt);
|
||||
char test[128];
|
||||
int len = vsnprintf(test, 128, fmt, args);
|
||||
if (len > 128) {
|
||||
char test = malloc(len+1);
|
||||
vsnprintf(test, len+1, fmt, args);
|
||||
return strdup(test);
|
||||
}
|
||||
|
||||
return strdup(test);
|
||||
}
|
||||
|
||||
static char *ext_paths = NULL;
|
||||
|
||||
#ifndef __EMSCRIPTEN__
|
||||
@@ -163,17 +179,23 @@ char *make_path(const char *file) {
|
||||
return pathbuf;
|
||||
}
|
||||
|
||||
unsigned char *slurp_file(const char *filename, size_t *size)
|
||||
void *cdb_slurp(struct cdb *cdb, const char *file, size_t *size)
|
||||
{
|
||||
if (cdb_find(&game_cdb, filename, strlen(filename))) {
|
||||
unsigned vlen, vpos;
|
||||
vpos = cdb_datapos(&game_cdb);
|
||||
vlen = cdb_datalen(&game_cdb);
|
||||
vpos = cdb_datapos(cdb);
|
||||
vlen = cdb_datalen(cdb);
|
||||
char *data = malloc(vlen);
|
||||
cdb_read(&game_cdb, data, vlen, vpos);
|
||||
cdb_read(cdb, data, vlen, vpos);
|
||||
if (size) *size = vlen;
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned char *slurp_file(const char *filename, size_t *size)
|
||||
{
|
||||
if (cdb_find(&game_cdb, filename, strlen(filename)))
|
||||
return cdb_slurp(&game_cdb, filename, size);
|
||||
else if (cdb_find(&corecdb, filename, strlen(filename)))
|
||||
return cdb_slurp(&corecdb, filename, size);
|
||||
|
||||
FILE *f;
|
||||
|
||||
@@ -197,7 +219,7 @@ unsigned char *slurp_file(const char *filename, size_t *size)
|
||||
char *slurp_text(const char *filename, size_t *size)
|
||||
{
|
||||
size_t len;
|
||||
char *str = slurp_file(filename, &len);
|
||||
unsigned char *str = slurp_file(filename, &len);
|
||||
if (!str) return NULL;
|
||||
char *retstr = malloc(len+1);
|
||||
memcpy(retstr, str, len);
|
||||
|
||||
@@ -19,6 +19,8 @@ unsigned char *slurp_file(const char *filename, size_t *size);
|
||||
char *slurp_text(const char *filename, size_t *size);
|
||||
int slurp_write(const char *txt, const char *filename);
|
||||
|
||||
char *seprint(char *fmt, ...);
|
||||
|
||||
void pack_engine(const char *fname);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -45,6 +45,9 @@ void script_startup() {
|
||||
|
||||
for (int i = 0; i < 100; i++)
|
||||
num_cache[i] = int2js(i);
|
||||
|
||||
script_dofile("scripts/engine.js");
|
||||
// jso_file("scripts/engine.js");
|
||||
}
|
||||
|
||||
JSValue num_cache[100] = {0};
|
||||
@@ -95,13 +98,13 @@ void script_evalf(const char *format, ...)
|
||||
JS_FreeValue(js,obj);
|
||||
}
|
||||
|
||||
uint8_t *compile_script(const char *file) {
|
||||
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);
|
||||
uint8_t *compile_script(const char *file, 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);
|
||||
free(script);
|
||||
size_t out_len;
|
||||
uint8_t *out;
|
||||
return JS_WriteObject(js, &out_len, obj, JS_WRITE_OBJ_BYTECODE);
|
||||
uint8_t *out = JS_WriteObject(js, &out_len, obj, JS_WRITE_OBJ_BYTECODE);
|
||||
return out;
|
||||
}
|
||||
|
||||
struct callee stacktrace_callee;
|
||||
@@ -127,6 +130,25 @@ int script_dofile(const char *file) {
|
||||
return file_mod_secs(file);
|
||||
}
|
||||
|
||||
JSValue script_runjso(const uint8_t *buf, size_t len)
|
||||
{
|
||||
JSValue obj = JS_ReadObject(js, buf, len, JS_EVAL_FLAGS);
|
||||
JSValue ret = JS_EvalFunction(js, obj);
|
||||
js_print_exception(ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
time_t jso_file(const char *file)
|
||||
{
|
||||
size_t len;
|
||||
uint8_t *byte = compile_script(file, &len);
|
||||
JSValue obj = JS_ReadObject(js, byte, len, JS_READ_OBJ_BYTECODE);
|
||||
JSValue ret = JS_EvalFunction(js, obj);
|
||||
js_print_exception(ret);
|
||||
free(byte);
|
||||
return file_mod_secs(file);
|
||||
}
|
||||
|
||||
JSValue script_runfile(const char *file)
|
||||
{
|
||||
size_t len;
|
||||
|
||||
@@ -20,6 +20,7 @@ void script_startup();
|
||||
void script_run(const char *script, const char *file);
|
||||
void script_evalf(const char *format, ...);
|
||||
int script_dofile(const char *file);
|
||||
time_t jso_file(const char *file);
|
||||
JSValue script_runfile(const char *file);
|
||||
void script_update(double dt);
|
||||
void script_draw();
|
||||
@@ -57,6 +58,6 @@ void call_physics(double dt);
|
||||
|
||||
void register_draw(struct callee c);
|
||||
void call_draw();
|
||||
uint8_t *compile_script(const char *file);
|
||||
uint8_t *compile_script(const char *file, size_t *len);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -292,13 +292,13 @@ static void _sg_metal_encode_texture_pixels(int x, int y, int w, int h, bool ori
|
||||
[cmd_buffer waitUntilCompleted];
|
||||
|
||||
MTLRegion mtl_region = MTLRegionMake2D(0, 0, w, h);
|
||||
void* temp_pixels = (void*)SOKOL_MALLOC(w * 4 * h);
|
||||
void* temp_pixels = malloc(w * 4 * h);
|
||||
SOKOL_ASSERT(temp_pixels);
|
||||
[mtl_dst_texture getBytes:temp_pixels bytesPerRow:w * 4 fromRegion:mtl_region mipmapLevel:0];
|
||||
// int res = SDL_ConvertPixels(w, h, _sg_metal_texture_format_to_sdl_pixel_format(mtl_dst_texture_desc.pixelFormat), temp_pixels, w * 4, SDL_PIXELFORMAT_RGBA32, pixels, w * 4);
|
||||
SOKOL_FREE(temp_pixels);
|
||||
SOKOL_ASSERT(res == 0);
|
||||
_SOKOL_UNUSED(res);
|
||||
free(temp_pixels);
|
||||
// SOKOL_ASSERT(res == 0);
|
||||
// _SOKOL_UNUSED(res);
|
||||
}
|
||||
|
||||
static void _sg_metal_query_image_pixels(_sg_image_t* img, void* pixels) {
|
||||
|
||||
184
source/engine/thirdparty/tinycdb-0.78/ChangeLog
vendored
184
source/engine/thirdparty/tinycdb-0.78/ChangeLog
vendored
@@ -1,184 +0,0 @@
|
||||
2006-06-29 Michael Tokarev <mjt@corpit.ru>
|
||||
|
||||
* see debian/changelog file for further changes.
|
||||
|
||||
2005-04-18 Michael Tokarev <mjt@corpit.ru>
|
||||
|
||||
* move cdb_make_find.c content into cdb_make_put.c
|
||||
|
||||
* introduce CDB_PUT_REPLACE0 - zerofill old duplicates
|
||||
|
||||
* allow usage of cdb.h in C++
|
||||
|
||||
2005-04-11 Michael Tokarev <mjt@corpit.ru>
|
||||
|
||||
* do not autogenerate files (cdb.h.in, cdb.3.in etc), but
|
||||
use real files instead (only substituted VERSION and NAME)
|
||||
|
||||
* finally fixed the `!fputs()' condition to be `fputs() < 0'
|
||||
as it should be in cdb.c (misbehaves on *bsd)
|
||||
|
||||
* kill cdbi_t usage in cdb_int.h
|
||||
|
||||
* export _cdb_make_fullwrite() (was ewrite()) and _cdb_make_flush()
|
||||
and use them in cdb_make.c as appropriate
|
||||
|
||||
* almost completely rewrite _cdb_make_find() and friends:
|
||||
- _cdb_make_find() now accepts new parameter, remove (bool), which,
|
||||
if true, indicates all found records should be deleted from the
|
||||
database.
|
||||
- Call _cdb_make_find() with remove=0 from cdb_make_exists()
|
||||
- Call _cdb_make_find() with appropriate arguments from
|
||||
cdb_make_put(), and simplify the latter greatly (was too clumsy
|
||||
anyway)
|
||||
|
||||
* rename `flags' parameter in cdb_make_put() to be `mode' which is
|
||||
more appropriate
|
||||
|
||||
* change #if conditional in nss_cdb.c
|
||||
from __GLIBC__ to __GNU_LIBRARY__
|
||||
|
||||
2003-11-04 Michael Tokarev <mjt@corpit.ru>
|
||||
|
||||
* added cdb_get() routine: tinycdb officially uses mmap.
|
||||
|
||||
* added cdb_{get,read}{data,key}() macros to read and get
|
||||
current data and key.
|
||||
|
||||
* fixed bug in cdb_seek() - incorrect wrap, sometimes
|
||||
cdb_seek()+cdb_bread() may return EIO instead of finding
|
||||
correct record.
|
||||
|
||||
* added some tweaks to Makefile to build position-independent
|
||||
libcdb_pic.a and shared libcdb.so libraries. Note that
|
||||
using libcdb as shared library is probably not a good idea,
|
||||
due to tiny size of the library.
|
||||
|
||||
* added initial nss_cdb module. Still not well-tested.
|
||||
Probably will not build on non-GNU system.
|
||||
|
||||
* adjusted tests.{ok,sh} for latest cdb utility modifications
|
||||
(-a mode in query by default)
|
||||
|
||||
* Victor Porton (porton at ex-code.com) provided a patch
|
||||
to allow tinycdb to be built on win32 platform (cdb_init.c).
|
||||
Completely untested.
|
||||
|
||||
2003-08-13 Michael Tokarev <mjt@corpit.ru>
|
||||
|
||||
* s/cdbi_t/unsigned/g. No need to keep this type.
|
||||
|
||||
* changed usage of cdb_findnext(): one need to pass
|
||||
pointer to cdb structure to cdb_findnext() now,
|
||||
and should use cdb_datapos(struct cdb_find *)
|
||||
instead of cdb_datapos(struct cdb *)
|
||||
|
||||
* added cdb_seqinit() and cdb_seqnext() routines for sequential
|
||||
record enumeration
|
||||
|
||||
* addded cdb_dend to the cdb structure: end of data
|
||||
position. Use that in cdb_seq*().
|
||||
|
||||
* more strict checking: ensure data is within data section,
|
||||
and hash tables are within hash section of a file.
|
||||
|
||||
* cdb_make.c (cdb_make_start): zerofill cdb_make structure
|
||||
to shut valgrind up (writing uninitialized data to file)
|
||||
|
||||
* cdb.c (cmode): always open file in RDWR mode to allow
|
||||
duplicate key detection
|
||||
|
||||
2002-12-08 Michael Tokarev <mjt+cdb@corpit.ru>
|
||||
|
||||
* version 0.73
|
||||
* de-Debianization. Oh well... ;)
|
||||
* no code changes, just like in 0.72
|
||||
|
||||
2002-10-13 Michael Tokarev <mjt+cdb@corpit.ru>
|
||||
|
||||
* version 0.72
|
||||
|
||||
* cleaned up debian packaging and made it actually work
|
||||
|
||||
* no code changes
|
||||
|
||||
2002-07-22 Michael Tokarev <mjt+cdb@corpit.ru>
|
||||
|
||||
* version 0.71
|
||||
|
||||
* rearranged object files to not depend on ranlib on
|
||||
systems that requires it (i.e. OpenBSD)
|
||||
|
||||
* use ranlib but mark it's possible error as non-fatal
|
||||
|
||||
2001-12-10 Michael Tokarev <mjt+cdb@corpit.ru>
|
||||
|
||||
* version 0.7a
|
||||
|
||||
* converted to CVS, added two missing #include <stdlib.h> for
|
||||
malloc declaration and spec target to the Makefile
|
||||
|
||||
2001-10-14 Michael Tokarev <mjt+cdb@corpit.ru>
|
||||
|
||||
* version 0.7
|
||||
|
||||
* added cdb_seek() and cdb_bread() routines as found
|
||||
in freecdb/cdb-0.64
|
||||
|
||||
2001-07-26 Michael Tokarev <mjt+cdb@corpit.ru>
|
||||
|
||||
* version 0.6
|
||||
|
||||
* added another option, CDB_PUT_WARN, to cdb_make_put's flags
|
||||
(to allow adding unconditionally but still warn about dups),
|
||||
now cdb_make_put seems to be logically complete.
|
||||
|
||||
* added and documented -r and -u options for cdb(1) command,
|
||||
and made them consistent with -w and -e also.
|
||||
|
||||
* reorganized cdb(1) manpage and added changes made to cdb
|
||||
command.
|
||||
|
||||
* added version references to manpages (and make them autogenerated
|
||||
to simplify maintenance).
|
||||
|
||||
* added cdb(5) manpage describing CDB file format.
|
||||
|
||||
2001-07-25 Michael Tokarev <mjt+cdb@corpit.ru>
|
||||
|
||||
* version 0.5
|
||||
|
||||
* added missing #include <sys/types.h> in cdb_init.c, thanks to
|
||||
ppetru@ppetru.net (Petru Paler)
|
||||
|
||||
* removed usage of pread() in cdb_make_find() and friends,
|
||||
suggested by Liviu Daia <Liviu.Daia@imar.ro>
|
||||
|
||||
* autogenerate tinycdb.spec file from template and debian/changelog
|
||||
|
||||
* autogenerate cdb.h from cdb.h.in (substituting version)
|
||||
|
||||
2001-06-29 Michael Tokarev <mjt+cdb@corpit.ru>
|
||||
|
||||
* version 0.4
|
||||
|
||||
* added cdb_make_put() routine to conditionnaly add a record
|
||||
|
||||
* split cdb library to more files (finer granularity)
|
||||
|
||||
* added cdb_findinit() and cdb_findnext() routines
|
||||
|
||||
* renamed cdbtool to cdb
|
||||
|
||||
* simplified cdb utility (dropped various format spec, changed
|
||||
options parsing) and a manpage
|
||||
|
||||
* added small note and copyright to every file in package
|
||||
|
||||
* added some testsuite (make test)
|
||||
|
||||
2001-05-27 Michael Tokarev <mjt+cdb@corpit.ru>
|
||||
|
||||
* version 0.3
|
||||
|
||||
* Initial Release.
|
||||
@@ -1,88 +0,0 @@
|
||||
# tinycdb.spec: tinycdb RPM spec file.
|
||||
#
|
||||
# This file is a part of tinycdb package by Michael Tokarev, mjt@corpit.ru.
|
||||
# Public domain.
|
||||
|
||||
Summary: A package for maintenance of constant databases
|
||||
Name: tinycdb
|
||||
Version: 0.78
|
||||
Release: 1
|
||||
Source: ftp://ftp.corpit.ru/pub/tinycdb/tinycdb_%version.tar.gz
|
||||
License: Public Domain
|
||||
Group: System Environment/Libraries
|
||||
Prefix: %{_prefix}
|
||||
BuildRoot: %{_tmppath}/%{name}-root
|
||||
Summary: TinyCDB - a Constant DataBase
|
||||
|
||||
%description
|
||||
tinycdb is a small, fast and reliable utility set and subroutine
|
||||
library for creating and reading constant databases. The database
|
||||
structure is tuned for fast reading:
|
||||
+ Successful lookups take normally just two disk accesses.
|
||||
+ Unsuccessful lookups take only one disk access.
|
||||
+ Small disk space and memory size requirements; a database
|
||||
uses 2048 bytes for the header and 24 bytes plus size of
|
||||
(key,value) per record.
|
||||
+ Maximum database size is 4GB; individual record size is not
|
||||
otherwise limited.
|
||||
+ Portable file format.
|
||||
+ Fast creation of new databases.
|
||||
+ No locking, updates are atomical.
|
||||
|
||||
This package contains both the utility and the development
|
||||
files, together with nss_cdb module.
|
||||
|
||||
%package devel
|
||||
Summary: Development files for the tinycdb library.
|
||||
Group: System Environment/Libraries
|
||||
Requires: %name = %version-%release
|
||||
Summary: Development files for tinycdb
|
||||
%description devel
|
||||
tinycdb is a small, fast and reliable utility set and subroutine
|
||||
library for creating and reading constant databases.
|
||||
|
||||
This package contains tinycdb development libraries and header files.
|
||||
|
||||
%prep
|
||||
%setup -q
|
||||
|
||||
%build
|
||||
make CFLAGS="$RPM_OPT_FLAGS" \
|
||||
staticlib sharedlib cdb-shared nss \
|
||||
sysconfdir=/etc
|
||||
|
||||
%install
|
||||
rm -rf $RPM_BUILD_ROOT
|
||||
mkdir -p $RPM_BUILD_ROOT
|
||||
%makeinstall DESTDIR=$RPM_BUILD_ROOT \
|
||||
libdir=%_libdir bindir=%_bindir mandir=%_mandir \
|
||||
syslibdir=/%_lib sysconfdir=/etc \
|
||||
includedir=%_includedir \
|
||||
install-all install-nss install-piclib install-sharedlib \
|
||||
INSTALLPROG=cdb-shared CP="cp -p"
|
||||
|
||||
%files
|
||||
%defattr(-,root,root)
|
||||
%_bindir/*
|
||||
%_mandir/man1/*
|
||||
%_mandir/man5/*
|
||||
%_libdir/libcdb.so.*
|
||||
/%_lib/libnss_cdb*
|
||||
/etc/cdb-Makefile
|
||||
%doc ChangeLog NEWS debian/changelog
|
||||
|
||||
%files devel
|
||||
%defattr(-,root,root)
|
||||
%_libdir/libcdb.a
|
||||
%_libdir/libcdb_pic.a
|
||||
%_libdir/libcdb.so
|
||||
%_mandir/man3/*
|
||||
%_includedir/*
|
||||
|
||||
%clean
|
||||
rm -rf $RPM_BUILD_ROOT
|
||||
|
||||
%post -p /sbin/ldconfig
|
||||
%postun -p /sbin/ldconfig
|
||||
|
||||
%changelog
|
||||
175
source/engine/thirdparty/tinycdb/Makefile
vendored
Normal file
175
source/engine/thirdparty/tinycdb/Makefile
vendored
Normal file
@@ -0,0 +1,175 @@
|
||||
#! /usr/bin/make -rf
|
||||
# Makefile: make file for tinycdb package
|
||||
#
|
||||
# This file is a part of tinycdb package by Michael Tokarev, mjt+cdb@corpit.ru.
|
||||
# Public domain.
|
||||
|
||||
VERSION = 0.80
|
||||
|
||||
prefix=/usr/local
|
||||
exec_prefix=$(prefix)
|
||||
bindir=$(exec_prefix)/bin
|
||||
libdir=$(exec_prefix)/lib
|
||||
syslibdir=$(libdir)
|
||||
sysconfdir=/etc
|
||||
includedir=$(prefix)/include
|
||||
mandir=$(prefix)/man
|
||||
NSSCDB_DIR = $(sysconfdir)
|
||||
DESTDIR=
|
||||
|
||||
CC = cc
|
||||
CFLAGS = -O
|
||||
CDEFS = -D_FILE_OFFSET_BITS=64
|
||||
LD = $(CC)
|
||||
LDFLAGS =
|
||||
|
||||
AR = ar
|
||||
ARFLAGS = rv
|
||||
RANLIB = ranlib
|
||||
|
||||
NSS_CDB = libnss_cdb.so.2
|
||||
LIBBASE = libcdb
|
||||
LIB = $(LIBBASE).a
|
||||
PICLIB = $(LIBBASE)_pic.a
|
||||
SHAREDLIB = $(LIBBASE).so.1
|
||||
SOLIB = $(LIBBASE).so
|
||||
CDB_USELIB = $(LIB)
|
||||
NSS_USELIB = $(PICLIB)
|
||||
LIBMAP = $(LIBBASE).map
|
||||
INSTALLPROG = cdb
|
||||
|
||||
# The following assumes GNU CC/LD -
|
||||
# used for building shared libraries only
|
||||
CFLAGS_PIC = -fPIC
|
||||
LDFLAGS_SHARED = -shared
|
||||
LDFLAGS_SONAME = -Wl,--soname=
|
||||
LDFLAGS_VSCRIPT = -Wl,--version-script=
|
||||
|
||||
CP = cp
|
||||
|
||||
LIB_SRCS = cdb_init.c cdb_find.c cdb_findnext.c cdb_seq.c cdb_seek.c \
|
||||
cdb_pack.c cdb_unpack.c \
|
||||
cdb_make_add.c cdb_make_put.c cdb_make.c cdb_hash.c
|
||||
NSS_SRCS = nss_cdb.c nss_cdb-passwd.c nss_cdb-group.c nss_cdb-spwd.c
|
||||
NSSMAP = nss_cdb.map
|
||||
|
||||
DISTFILES = Makefile cdb.h cdb_int.h $(LIB_SRCS) cdb.c \
|
||||
$(NSS_SRCS) nss_cdb.h nss_cdb-Makefile \
|
||||
cdb.3 cdb.1 cdb.5 \
|
||||
tinycdb.spec tests.sh tests.ok \
|
||||
$(LIBMAP) $(NSSMAP) \
|
||||
NEWS
|
||||
|
||||
all: static
|
||||
static: staticlib cdb
|
||||
staticlib: $(LIB)
|
||||
nss: $(NSS_CDB)
|
||||
piclib: $(PICLIB)
|
||||
sharedlib: $(SHAREDLIB)
|
||||
shared: sharedlib cdb-shared
|
||||
|
||||
LIB_OBJS = $(LIB_SRCS:.c=.o)
|
||||
LIB_OBJS_PIC = $(LIB_SRCS:.c=.lo)
|
||||
NSS_OBJS = $(NSS_SRCS:.c=.lo)
|
||||
|
||||
$(LIB): $(LIB_OBJS)
|
||||
-rm -f $@
|
||||
$(AR) $(ARFLAGS) $@ $(LIB_OBJS)
|
||||
-$(RANLIB) $@
|
||||
|
||||
$(PICLIB): $(LIB_OBJS_PIC)
|
||||
-rm -f $@
|
||||
$(AR) $(ARFLAGS) $@ $(LIB_OBJS_PIC)
|
||||
-$(RANLIB) $@
|
||||
|
||||
$(SHAREDLIB): $(LIB_OBJS_PIC) $(LIBMAP)
|
||||
-rm -f $(SOLIB)
|
||||
ln -s $@ $(SOLIB)
|
||||
$(LD) $(LDFLAGS) $(LDFLAGS_SHARED) -o $@ \
|
||||
$(LDFLAGS_SONAME)$(SHAREDLIB) $(LDFLAGS_VSCRIPT)$(LIBMAP) \
|
||||
$(LIB_OBJS_PIC)
|
||||
|
||||
cdb: cdb.o $(CDB_USELIB)
|
||||
$(LD) $(LDFLAGS) -o $@ cdb.o $(CDB_USELIB)
|
||||
cdb-shared: cdb.o $(SHAREDLIB)
|
||||
$(LD) $(LDFLAGS) -o $@ cdb.o $(SHAREDLIB)
|
||||
|
||||
$(NSS_CDB): $(NSS_OBJS) $(NSS_USELIB) $(NSSMAP)
|
||||
$(LD) $(LDFLAGS) $(LDFLAGS_SHARED) -o $@ \
|
||||
$(LDFLAGS_SONAME)$@ $(LDFLAGS_VSCRIPT)$(NSSMAP) \
|
||||
$(NSS_OBJS) $(NSS_USELIB)
|
||||
|
||||
.SUFFIXES:
|
||||
.SUFFIXES: .c .o .lo
|
||||
|
||||
.c.o:
|
||||
$(CC) $(CFLAGS) $(CDEFS) -c $<
|
||||
.c.lo:
|
||||
$(CC) $(CFLAGS) $(CDEFS) $(CFLAGS_PIC) -c -o $@ -DNSSCDB_DIR=\"$(NSSCDB_DIR)\" $<
|
||||
|
||||
cdb.o: cdb.h
|
||||
$(LIB_OBJS) $(LIB_OBJS_PIC): cdb_int.h cdb.h
|
||||
$(NSS_OBJS): nss_cdb.h cdb.h
|
||||
|
||||
clean:
|
||||
-rm -f *.o *.lo core *~ tests.out tests-shared.ok
|
||||
realclean distclean: clean
|
||||
-rm -f $(LIBBASE)[._][aps]* $(NSS_CDB)* cdb cdb-shared
|
||||
|
||||
test tests check: cdb
|
||||
sh ./tests.sh ./cdb > tests.out 2>&1
|
||||
diff tests.ok tests.out
|
||||
@echo All tests passed
|
||||
test-shared tests-shared check-shared: cdb-shared
|
||||
sed 's/^cdb: /cdb-shared: /' <tests.ok >tests-shared.ok
|
||||
LD_LIBRARY_PATH=. sh ./tests.sh ./cdb-shared > tests.out 2>&1
|
||||
diff tests-shared.ok tests.out
|
||||
rm -f tests-shared.ok
|
||||
@echo All tests passed
|
||||
|
||||
do_install = \
|
||||
while [ "$$1" ] ; do \
|
||||
if [ .$$4 = .- ]; then f=$$1; else f=$$4; fi; \
|
||||
d=$(DESTDIR)$$3 ; echo installing $$1 to $$d/$$f; \
|
||||
[ -d $$d ] || mkdir -p $$d || exit 1 ; \
|
||||
$(CP) $$1 $$d/$$f || exit 1; \
|
||||
chmod 0$$2 $$d/$$f || exit 1; \
|
||||
shift 4; \
|
||||
done
|
||||
|
||||
install-all: all $(INSTALLPROG)
|
||||
set -- \
|
||||
cdb.h 644 $(includedir) - \
|
||||
cdb.3 644 $(mandir)/man3 - \
|
||||
cdb.1 644 $(mandir)/man1 - \
|
||||
cdb.5 644 $(mandir)/man5 - \
|
||||
$(INSTALLPROG) 755 $(bindir) cdb \
|
||||
libcdb.a 644 $(libdir) - \
|
||||
; \
|
||||
$(do_install)
|
||||
install-nss: nss
|
||||
@set -- $(NSS_CDB) 644 $(syslibdir) - \
|
||||
nss_cdb-Makefile 644 $(sysconfdir) cdb-Makefile ; \
|
||||
$(do_install)
|
||||
install-sharedlib: sharedlib
|
||||
@set -- $(SHAREDLIB) 644 $(libdir) - ; \
|
||||
$(do_install) ; \
|
||||
ln -sf $(SHAREDLIB) $(DESTDIR)$(libdir)/$(LIBBASE).so
|
||||
install-piclib: piclib
|
||||
@set -- $(PICLIB) 644 $(libdir) - ; \
|
||||
$(do_install)
|
||||
install: install-all
|
||||
|
||||
DNAME = tinycdb-$(VERSION)
|
||||
dist: ../$(DNAME).tar.gz
|
||||
../$(DNAME).tar.gz: $(DISTFILES)
|
||||
mkdir $(DNAME)
|
||||
ln $(DISTFILES) $(DNAME)/
|
||||
rm -f $@
|
||||
tar cfz $@ $(DNAME)
|
||||
rm -fr $(DNAME)
|
||||
|
||||
.PHONY: all clean realclean dist spec
|
||||
.PHONY: test tests check test-shared tests-shared check-shared
|
||||
.PHONY: static staticlib shared sharedlib nss piclib
|
||||
.PHONY: install install-all install-sharedlib install-piclib install-nss
|
||||
@@ -1,5 +1,35 @@
|
||||
User-visible news. Latest at the top.
|
||||
|
||||
tinycdb-0.80 2023-09-17
|
||||
|
||||
- bugfix: cdb utility: check return value from close() too,
|
||||
when creating the cdb file
|
||||
|
||||
- portability: cdb utility: ignore SIGXFSZ signal if defined,
|
||||
to be able to clean up when exceeding file limit
|
||||
|
||||
- robustness: let cdb_make_start to lseek() to the zero position
|
||||
of file. This ensures the file is seekable right at the start
|
||||
instead of at the very end, too
|
||||
|
||||
- robustness: cdb utility: remove temporary file in case create
|
||||
operation fails
|
||||
|
||||
- portability use SEE_SET macro instead of 0 for lseek()
|
||||
|
||||
- split out cdb_pack() into its own .c file
|
||||
|
||||
tinycdb-0.79 2023-09-17
|
||||
|
||||
- bugfix: call fsync() at the end of cdb_make_finish()
|
||||
to ensure data does not stay in some kernel buffer
|
||||
|
||||
- bugfix: clean tests.out in `make distclean' too
|
||||
|
||||
- `make dist' makes tarball in the parent dir
|
||||
|
||||
- stop shipping debian/* - it is not a native debian package
|
||||
|
||||
tinycdb-0.78 2012-05-11
|
||||
|
||||
- bugfix release:
|
||||
@@ -1,11 +1,11 @@
|
||||
/* cdb.h: public cdb include file
|
||||
*
|
||||
* This file is a part of tinycdb package by Michael Tokarev, mjt@corpit.ru.
|
||||
* This file is a part of tinycdb package by Michael Tokarev, mjt+cdb@corpit.ru.
|
||||
* Public domain.
|
||||
*/
|
||||
|
||||
#ifndef TINYCDB_VERSION
|
||||
#define TINYCDB_VERSION 0.78
|
||||
#define TINYCDB_VERSION 0.80
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@@ -37,6 +37,7 @@ struct cdb {
|
||||
#define cdb_fileno(c) ((c)->cdb_fd)
|
||||
|
||||
int cdb_init(struct cdb *cdbp, int fd);
|
||||
int cdb_initf(struct cdb *cdbp, void *p, unsigned len);
|
||||
void cdb_free(struct cdb *cdbp);
|
||||
|
||||
int cdb_read(const struct cdb *cdbp,
|
||||
@@ -1,6 +1,6 @@
|
||||
/* cdb_find.c: cdb_find routine
|
||||
*
|
||||
* This file is a part of tinycdb package by Michael Tokarev, mjt@corpit.ru.
|
||||
* This file is a part of tinycdb package by Michael Tokarev, mjt+cdb@corpit.ru.
|
||||
* Public domain.
|
||||
*/
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* cdb_findnext.c: sequential cdb_find routines
|
||||
*
|
||||
* This file is a part of tinycdb package by Michael Tokarev, mjt@corpit.ru.
|
||||
* This file is a part of tinycdb package by Michael Tokarev, mjt+cdb@corpit.ru.
|
||||
* Public domain.
|
||||
*/
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* cdb_hash.c: cdb hashing routine
|
||||
*
|
||||
* This file is a part of tinycdb package by Michael Tokarev, mjt@corpit.ru.
|
||||
* This file is a part of tinycdb package by Michael Tokarev, mjt+cdb@corpit.ru.
|
||||
* Public domain.
|
||||
*/
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* cdb_init.c: cdb_init, cdb_free and cdb_read routines
|
||||
*
|
||||
* This file is a part of tinycdb package by Michael Tokarev, mjt@corpit.ru.
|
||||
* This file is a part of tinycdb package by Michael Tokarev, mjt+cdb@corpit.ru.
|
||||
* Public domain.
|
||||
*/
|
||||
|
||||
@@ -16,6 +16,27 @@
|
||||
#include <sys/stat.h>
|
||||
#include "cdb_int.h"
|
||||
|
||||
int cdb_initf(struct cdb *cdbp, void *p, unsigned len)
|
||||
{
|
||||
/* get file size */
|
||||
if (len < 0)
|
||||
return -1;
|
||||
|
||||
cdbp->cdb_fd = -1;
|
||||
cdbp->cdb_fsize = len;
|
||||
cdbp->cdb_mem = p;
|
||||
cdbp->cdb_vpos = cdbp->cdb_vlen = 0;
|
||||
cdbp->cdb_kpos = cdbp->cdb_klen = 0;
|
||||
unsigned dend;
|
||||
unsigned fsize = len;
|
||||
dend = cdb_unpack(p);
|
||||
if (dend < 2048) dend = 2048;
|
||||
else if (dend >= fsize) dend = fsize;
|
||||
cdbp->cdb_dend = dend;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
cdb_init(struct cdb *cdbp, int fd)
|
||||
{
|
||||
@@ -1,6 +1,6 @@
|
||||
/* cdb_int.h: internal cdb library declarations
|
||||
*
|
||||
* This file is a part of tinycdb package by Michael Tokarev, mjt@corpit.ru.
|
||||
* This file is a part of tinycdb package by Michael Tokarev, mjt+cdb@corpit.ru.
|
||||
* Public domain.
|
||||
*/
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* cdb_make.c: basic cdb creation routines
|
||||
*
|
||||
* This file is a part of tinycdb package by Michael Tokarev, mjt@corpit.ru.
|
||||
* This file is a part of tinycdb package by Michael Tokarev, mjt+cdb@corpit.ru.
|
||||
* Public domain.
|
||||
*/
|
||||
|
||||
@@ -9,15 +9,6 @@
|
||||
#include <string.h>
|
||||
#include "cdb_int.h"
|
||||
|
||||
void
|
||||
cdb_pack(unsigned num, unsigned char buf[4])
|
||||
{
|
||||
buf[0] = num & 255; num >>= 8;
|
||||
buf[1] = num & 255; num >>= 8;
|
||||
buf[2] = num & 255;
|
||||
buf[3] = num >> 8;
|
||||
}
|
||||
|
||||
int
|
||||
cdb_make_start(struct cdb_make *cdbmp, int fd)
|
||||
{
|
||||
@@ -25,7 +16,7 @@ cdb_make_start(struct cdb_make *cdbmp, int fd)
|
||||
cdbmp->cdb_fd = fd;
|
||||
cdbmp->cdb_dpos = 2048;
|
||||
cdbmp->cdb_bpos = cdbmp->cdb_buf + 2048;
|
||||
return 0;
|
||||
return lseek(fd, 0, SEEK_SET);
|
||||
}
|
||||
|
||||
int internal_function
|
||||
@@ -152,11 +143,11 @@ cdb_make_finish_internal(struct cdb_make *cdbmp)
|
||||
cdb_pack(hpos[t], p + (t << 3));
|
||||
cdb_pack(hcnt[t], p + (t << 3) + 4);
|
||||
}
|
||||
if (lseek(cdbmp->cdb_fd, 0, 0) != 0 ||
|
||||
if (lseek(cdbmp->cdb_fd, 0, SEEK_SET) != 0 ||
|
||||
_cdb_make_fullwrite(cdbmp->cdb_fd, p, 2048) != 0)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
return fsync(cdbmp->cdb_fd);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -1,6 +1,6 @@
|
||||
/* cdb_make_add.c: basic cdb_make_add routine
|
||||
*
|
||||
* This file is a part of tinycdb package by Michael Tokarev, mjt@corpit.ru.
|
||||
* This file is a part of tinycdb package by Michael Tokarev, mjt+cdb@corpit.ru.
|
||||
* Public domain.
|
||||
*/
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* cdb_make_put.c: "advanced" cdb_make_put routine
|
||||
*
|
||||
* This file is a part of tinycdb package by Michael Tokarev, mjt@corpit.ru.
|
||||
* This file is a part of tinycdb package by Michael Tokarev, mjt+cdb@corpit.ru.
|
||||
* Public domain.
|
||||
*/
|
||||
|
||||
16
source/engine/thirdparty/tinycdb/cdb_pack.c
vendored
Normal file
16
source/engine/thirdparty/tinycdb/cdb_pack.c
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
/* cdb_pack.c: pack a 32bit integer (to network byte order)
|
||||
*
|
||||
* This file is a part of tinycdb package by Michael Tokarev, mjt+cdb@corpit.ru.
|
||||
* Public domain.
|
||||
*/
|
||||
|
||||
#include "cdb.h"
|
||||
|
||||
void
|
||||
cdb_pack(unsigned num, unsigned char buf[4])
|
||||
{
|
||||
buf[0] = num & 255; num >>= 8;
|
||||
buf[1] = num & 255; num >>= 8;
|
||||
buf[2] = num & 255;
|
||||
buf[3] = num >> 8;
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
/* cdb_seek.c: old interface for reading cdb file
|
||||
*
|
||||
* This file is a part of tinycdb package by Michael Tokarev, mjt@corpit.ru.
|
||||
* This file is a part of tinycdb package by Michael Tokarev, mjt+cdb@corpit.ru.
|
||||
* Public domain.
|
||||
*/
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* cdb_seq.c: sequential record retrieval routines
|
||||
*
|
||||
* This file is a part of tinycdb package by Michael Tokarev, mjt@corpit.ru.
|
||||
* This file is a part of tinycdb package by Michael Tokarev, mjt+cdb@corpit.ru.
|
||||
* Public domain.
|
||||
*/
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* cdb_unpack.c: unpack 32bit integer
|
||||
/* cdb_unpack.c: unpack a 32bit integer from network byte order
|
||||
*
|
||||
* This file is a part of tinycdb package by Michael Tokarev, mjt@corpit.ru.
|
||||
* This file is a part of tinycdb package by Michael Tokarev, mjt+cdb@corpit.ru.
|
||||
* Public domain.
|
||||
*/
|
||||
|
||||
83
source/engine/thirdparty/tinycdb/tests.ok
vendored
Normal file
83
source/engine/thirdparty/tinycdb/tests.ok
vendored
Normal file
@@ -0,0 +1,83 @@
|
||||
Create simple db
|
||||
0
|
||||
checksum may fail if no md5sum program
|
||||
97549c2e76e2d446430a392d77ed1bcb
|
||||
Dump simple db
|
||||
+3,4:one->here
|
||||
+1,1:a->b
|
||||
+1,3:b->abc
|
||||
+3,4:one->also
|
||||
|
||||
0
|
||||
Stats for simple db
|
||||
number of records: 4
|
||||
key min/avg/max length: 1/2/3
|
||||
val min/avg/max length: 1/3/4
|
||||
hash tables/entries/collisions: 3/8/1
|
||||
hash table min/avg/max length: 2/3/4
|
||||
hash table distances:
|
||||
d0: 3 75%
|
||||
d1: 1 25%
|
||||
d2: 0 0%
|
||||
d3: 0 0%
|
||||
d4: 0 0%
|
||||
d5: 0 0%
|
||||
d6: 0 0%
|
||||
d7: 0 0%
|
||||
d8: 0 0%
|
||||
d9: 0 0%
|
||||
>9: 0 0%
|
||||
0
|
||||
Query simple db (two records match)
|
||||
herealso
|
||||
0
|
||||
Query for non-existed key
|
||||
100
|
||||
Doing 600 repeated records
|
||||
0
|
||||
checksum may fail if no md5sum program
|
||||
412a0b7578efca528bf8398c8811caf4
|
||||
cdb stats should show 601 record
|
||||
number of records: 601
|
||||
key min/avg/max length: 1/1/1
|
||||
val min/avg/max length: 3/3/5
|
||||
hash tables/entries/collisions: 2/1202/599
|
||||
hash table min/avg/max length: 2/601/1200
|
||||
hash table distances:
|
||||
d0: 2 0%
|
||||
d1: 1 0%
|
||||
d2: 1 0%
|
||||
d3: 1 0%
|
||||
d4: 1 0%
|
||||
d5: 1 0%
|
||||
d6: 1 0%
|
||||
d7: 1 0%
|
||||
d8: 1 0%
|
||||
d9: 1 0%
|
||||
>9: 590 98%
|
||||
0
|
||||
Querying key
|
||||
other
|
||||
0
|
||||
Dumping and re-creating db
|
||||
0
|
||||
0
|
||||
Handling large key size
|
||||
cdb: (stdin): bad format
|
||||
2
|
||||
Handling large value size
|
||||
cdb: (stdin): bad format
|
||||
2
|
||||
Handling invalid input format (short file)
|
||||
cdb: unable to read: short file
|
||||
2
|
||||
Creating db with eol in key and value
|
||||
0
|
||||
checksum may fail if no md5sum program
|
||||
1d444fe759c26d36f500d01c41cfda40
|
||||
Querying key-value with eol
|
||||
b
|
||||
0
|
||||
Handling file size limits
|
||||
cdb: cdb_make_put: File too large
|
||||
111
|
||||
143
source/engine/thirdparty/tinycdb/tests.sh
vendored
Executable file
143
source/engine/thirdparty/tinycdb/tests.sh
vendored
Executable file
@@ -0,0 +1,143 @@
|
||||
#! /bin/sh
|
||||
|
||||
# tests.sh: This script will run tests for cdb.
|
||||
# Execute with ./tests.sh ./cdb
|
||||
# (first arg if present gives path to cdb tool to use, default is `cdb').
|
||||
#
|
||||
# This file is a part of tinycdb package by Michael Tokarev, mjt+cdb@corpit.ru.
|
||||
# Public domain.
|
||||
|
||||
case "$1" in
|
||||
"") cdb=cdb ;;
|
||||
*) cdb="$1" ;;
|
||||
esac
|
||||
|
||||
do_csum() {
|
||||
echo checksum may fail if no md5sum program
|
||||
md5sum $1 | sed -e 's|[ ].*||' -e 'y|[ABCDEF]|[abcdef]|'
|
||||
}
|
||||
|
||||
rm -f 1.cdb 1a.cdb
|
||||
|
||||
echo Create simple db
|
||||
echo "+3,4:one->here
|
||||
+1,1:a->b
|
||||
+1,3:b->abc
|
||||
+3,4:one->also
|
||||
|
||||
" | $cdb -c 1.cdb
|
||||
echo $?
|
||||
do_csum 1.cdb
|
||||
|
||||
echo Dump simple db
|
||||
$cdb -d 1.cdb
|
||||
echo $?
|
||||
|
||||
echo Stats for simple db
|
||||
$cdb -s 1.cdb
|
||||
echo $?
|
||||
|
||||
echo "Query simple db (two records match)"
|
||||
$cdb -q 1.cdb one
|
||||
echo "
|
||||
$?"
|
||||
|
||||
echo Query for non-existed key
|
||||
$cdb -q 1.cdb none
|
||||
echo $?
|
||||
|
||||
echo Doing 600 repeated records
|
||||
(
|
||||
for i in 0 1 2 3 4 5 ; do
|
||||
for j in 0 1 2 3 4 5 6 7 8 9 ; do
|
||||
for k in 0 1 2 3 4 5 6 7 8 9 ; do
|
||||
echo "+1,3:a->$i$j$k"
|
||||
done
|
||||
done
|
||||
done
|
||||
echo "+1,5:b->other"
|
||||
echo
|
||||
) | $cdb -c 1.cdb
|
||||
echo $?
|
||||
do_csum 1.cdb
|
||||
echo cdb stats should show 601 record
|
||||
$cdb -s 1.cdb
|
||||
echo $?
|
||||
|
||||
echo Querying key
|
||||
$cdb -q 1.cdb b
|
||||
echo "
|
||||
"$?
|
||||
|
||||
echo Dumping and re-creating db
|
||||
$cdb -d 1.cdb | $cdb -c 1a.cdb
|
||||
echo $?
|
||||
cmp 1.cdb 1a.cdb
|
||||
|
||||
$cdb -d -m 1.cdb | $cdb -c -m 1a.cdb
|
||||
echo $?
|
||||
cmp 1.cdb 1a.cdb
|
||||
|
||||
echo Handling large key size
|
||||
echo "+123456789012,1:" | $cdb -c 1.cdb
|
||||
echo $?
|
||||
|
||||
echo Handling large value size
|
||||
echo "+1,123456789012:" | $cdb -c 1.cdb
|
||||
echo $?
|
||||
|
||||
echo "Handling invalid input format (short file)"
|
||||
echo "+10,10:" | $cdb -c 1.cdb
|
||||
echo $?
|
||||
|
||||
echo Creating db with eol in key and value
|
||||
echo "+2,2:a
|
||||
->b
|
||||
|
||||
" | $cdb -c 1.cdb
|
||||
echo $?
|
||||
do_csum 1.cdb
|
||||
|
||||
echo Querying key-value with eol
|
||||
$cdb -q 1.cdb "a
|
||||
"
|
||||
echo $?
|
||||
|
||||
echo Handling file size limits
|
||||
(
|
||||
ulimit -f 4
|
||||
trap '' 25
|
||||
(
|
||||
for i in 0 1 2 3 4 5 6 7 8 9 ; do
|
||||
for j in 0 1 2 3 4 5 6 7 8 9 ; do
|
||||
for k in 0 1 2 3 4 5 6 7 8 9 ; do
|
||||
echo "+4,4:k$i$j$k->v$i$j$k"
|
||||
done
|
||||
done
|
||||
done
|
||||
echo
|
||||
) | $cdb -c 1.cdb
|
||||
echo $?
|
||||
)
|
||||
|
||||
if false ; then # does not work for now, bugs in libc
|
||||
echo Handling oom condition
|
||||
(
|
||||
for i0 in 0 1 2 3 4 5 6 7 8 9 ; do
|
||||
for i1 in 0 1 2 3 4 5 6 7 8 9 ; do
|
||||
for i2 in 0 1 2 3 4 5 6 7 8 9 ; do
|
||||
for i3 in 0 1 2 3 4 5 6 7 8 9 ; do
|
||||
for i4 in 0 1 2 3 4 5 6 7 8 9 ; do
|
||||
echo "+5,0:$i0$i1$i2$i3$i4->"
|
||||
done
|
||||
done
|
||||
done
|
||||
done
|
||||
done
|
||||
echo
|
||||
) | (ulimit -v 1900; $cdb -c 1.cdb)
|
||||
echo $?
|
||||
fi
|
||||
|
||||
rm -rf 1.cdb 1a.cdb 1.cdb.tmp
|
||||
exit 0
|
||||
@@ -8,6 +8,8 @@
|
||||
#include "sound.h"
|
||||
#include "resources.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "datastream.h"
|
||||
|
||||
#include "timer.h"
|
||||
@@ -42,6 +44,7 @@
|
||||
#include "sokol/sokol_app.h"
|
||||
#include "sokol/sokol_audio.h"
|
||||
#include "sokol/sokol_time.h"
|
||||
#include "sokol/sokol_args.h"
|
||||
|
||||
#define STB_DS_IMPLEMENTATION
|
||||
#include <stb_ds.h>
|
||||
@@ -152,7 +155,7 @@ int frame_fps() {
|
||||
return 1.0/sapp_frame_duration();
|
||||
}
|
||||
|
||||
static double low_fps = 1/24.0; /* Chosen because of apple's 24 hz mode */
|
||||
static double low_fps = 1/24.0;
|
||||
static double low_fps_c = 0.0;
|
||||
|
||||
void c_frame()
|
||||
@@ -355,8 +358,6 @@ sapp_desc sokol_main(int argc, char **argv) {
|
||||
phys2d_init();
|
||||
|
||||
script_startup();
|
||||
|
||||
script_dofile("scripts/engine.js");
|
||||
|
||||
int argsize = 0;
|
||||
for (int i = 0; i < argc; i++) {
|
||||
|
||||
@@ -1,747 +0,0 @@
|
||||
/* Prototypes out an object and extends with values */
|
||||
function clone(proto, binds) {
|
||||
var c = Object.create(proto);
|
||||
complete_assign(c, binds);
|
||||
return c;
|
||||
};
|
||||
|
||||
/* Prototypes out an object and assigns values */
|
||||
function copy(proto, binds) {
|
||||
var c = Object.create(proto);
|
||||
Object.assign(c, binds);
|
||||
return c;
|
||||
};
|
||||
|
||||
/* OBJECT DEFININTIONS */
|
||||
Object.defineProperty(Object.prototype, 'getOwnPropertyDescriptors', {
|
||||
value: function() {
|
||||
var obj = {};
|
||||
for (var key in this) {
|
||||
obj[key] = Object.getOwnPropertyDescriptor(this, key);
|
||||
}
|
||||
|
||||
return obj;
|
||||
}
|
||||
});
|
||||
|
||||
Object.defineProperty(Object.prototype, 'obscure', {
|
||||
value: function(name) {
|
||||
Object.defineProperty(this, name, { enumerable: false });
|
||||
}
|
||||
});
|
||||
|
||||
Object.defineProperty(Object.prototype, 'hasOwn', {
|
||||
value: function(x) { return this.hasOwnProperty(x); }
|
||||
});
|
||||
|
||||
Object.defineProperty(Object.prototype, 'array', {
|
||||
value: function() {
|
||||
var a = [];
|
||||
for (var key in this)
|
||||
a.push(this[key]);
|
||||
|
||||
return a;
|
||||
},
|
||||
});
|
||||
|
||||
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, 'writable', {
|
||||
value: function(name) {
|
||||
return Object.getPropertyDescriptor(this, name).writable;
|
||||
}
|
||||
});
|
||||
*/
|
||||
|
||||
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, {
|
||||
value: val,
|
||||
writable:false,
|
||||
enumerable:true,
|
||||
configurable: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, 'deflock', {
|
||||
value: function(prop) {
|
||||
Object.defineProperty(this,prop, {configurable:false});
|
||||
}
|
||||
});
|
||||
|
||||
Object.defineProperty(Object.prototype, 'forEach', {
|
||||
value: function(fn) {
|
||||
for (var key in this)
|
||||
fn(this[key]);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
Object.defineProperty(Object.prototype, 'empty', {
|
||||
get: function() {
|
||||
return Object.keys(this).empty;
|
||||
},
|
||||
});
|
||||
|
||||
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, 'findIndex', {
|
||||
value: function(x) {
|
||||
var i = 0;
|
||||
for (var key in this) {
|
||||
if (this[key] === x) return i;
|
||||
i++;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
/* 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;
|
||||
|
||||
var find = this.slice(from).search(char[0]);
|
||||
|
||||
if (find === -1)
|
||||
return -1;
|
||||
else
|
||||
return from + find;
|
||||
|
||||
var i = 0;
|
||||
var c = this.charAt(from+i);
|
||||
while (!char.includes(c)) {
|
||||
i++;
|
||||
if (from+i >this.length-1) return -1;
|
||||
c = this.charAt(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;
|
||||
|
||||
if (!count) count = 0;
|
||||
|
||||
var find = this.slice(0,from).lastIndexOf(char);
|
||||
|
||||
while (count > 1) {
|
||||
find = this.slice(0,find).lastIndexOf(char);
|
||||
count--;
|
||||
}
|
||||
|
||||
if (find === -1)
|
||||
return 0;
|
||||
else
|
||||
return find;
|
||||
}
|
||||
});
|
||||
|
||||
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(0, this.length+n);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
Object.defineProperty(String.prototype, 'ext', {
|
||||
value: function() {
|
||||
var idx = this.lastIndexOf('.');
|
||||
if (idx === -1) return undefined;
|
||||
return this.slice(idx);
|
||||
}
|
||||
});
|
||||
|
||||
Object.defineProperty(String.prototype, 'set_ext', {
|
||||
value: function(val) {
|
||||
return this.name() + val;
|
||||
}
|
||||
});
|
||||
|
||||
Object.defineProperty(String.prototype, 'name', {
|
||||
value: function() {
|
||||
var s = this.lastIndexOf('/');
|
||||
var e = this.lastIndexOf('.');
|
||||
if (e === -1) e = this.length;
|
||||
return this.slice(s+1,e);
|
||||
}
|
||||
});
|
||||
|
||||
Object.defineProperty(String.prototype, 'base', {
|
||||
value: function() {
|
||||
return this.slice(this.lastIndexOf('/')+1);
|
||||
}
|
||||
});
|
||||
|
||||
Object.defineProperty(String.prototype, 'dir', {
|
||||
value: function() {
|
||||
var e = this.lastIndexOf('/');
|
||||
return this.slice(0, e);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
/* ARRAY DEFS */
|
||||
|
||||
Object.defineProperty(Array.prototype, 'copy', {
|
||||
value: function() {
|
||||
var c = [];
|
||||
|
||||
this.forEach(function(x, i) {
|
||||
c[i] = deep_copy(x);
|
||||
});
|
||||
|
||||
return c;
|
||||
}
|
||||
});
|
||||
|
||||
Object.defineProperty(Array.prototype, 'rotate', {
|
||||
value: function(a) {
|
||||
return Vector.rotate(this, a);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
Object.defineProperty(Array.prototype, '$add', {
|
||||
value: function(b) {
|
||||
for (var i = 0; i < this.length; i++) {
|
||||
this[i] += b[i];
|
||||
}
|
||||
}});
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
Object.defineProperty(Array.prototype, 'x', setelem(0));
|
||||
Object.defineProperty(Array.prototype, 'y', setelem(1));
|
||||
Object.defineProperty(Array.prototype, 'z', setelem(2));
|
||||
Object.defineProperty(Array.prototype, 'w', setelem(3));
|
||||
arrsetelem('r', 0);
|
||||
arrsetelem('g', 1);
|
||||
arrsetelem('b', 2);
|
||||
arrsetelem('a', 3);
|
||||
|
||||
|
||||
Object.defineProperty(Array.prototype, 'add', {
|
||||
value: function(b) {
|
||||
var c = [];
|
||||
for (var i = 0; i < this.length; i++) { c[i] = this[i] + b[i]; }
|
||||
return c;
|
||||
}});
|
||||
|
||||
Object.defineProperty(Array.prototype, 'newfirst', {
|
||||
value: function(i) {
|
||||
var c = this.slice();
|
||||
if (i >= c.length) return c;
|
||||
|
||||
do {
|
||||
c.push(c.shift());
|
||||
i--;
|
||||
} while (i > 0);
|
||||
|
||||
return c;
|
||||
}
|
||||
});
|
||||
|
||||
Object.defineProperty(Array.prototype, 'doubleup', {
|
||||
value: function(n) {
|
||||
var c = [];
|
||||
this.forEach(function(x) {
|
||||
for (var i = 0; i < n; i++)
|
||||
c.push(x);
|
||||
});
|
||||
|
||||
return c;
|
||||
}
|
||||
});
|
||||
|
||||
Object.defineProperty(Array.prototype, 'sub', {
|
||||
value: function(b) {
|
||||
var c = [];
|
||||
for (var i = 0; i < this.length; i++) { c[i] = this[i] - b[i]; }
|
||||
return c;
|
||||
}});
|
||||
|
||||
Object.defineProperty(Array.prototype, 'mult', {
|
||||
value: function(arr) {
|
||||
var c = [];
|
||||
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, 'scale', {
|
||||
value: function(s) {
|
||||
if (Array.isArray(s)) {
|
||||
var c = this.slice();
|
||||
c.forEach(function(x,i) { c[i] = x * s[i]; });
|
||||
return c;
|
||||
}
|
||||
return this.map(function(x) { return x*s; });
|
||||
}});
|
||||
|
||||
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) === JSON.stringify(b);
|
||||
|
||||
for (var i = 0; i < this.length; i++) {
|
||||
if (!this[i] === b[i])
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}});
|
||||
|
||||
function add(x,y) { return x+y; };
|
||||
function mult(x,y) { return x*y; };
|
||||
|
||||
Object.defineProperty(Array.prototype, 'mapc', {
|
||||
value: function(fn, arr) {
|
||||
return this.map(function(x, i) {
|
||||
return fn(x, arr[i]);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
Object.defineProperty(Array.prototype, 'remove', {
|
||||
value: function(b) {
|
||||
var idx = this.indexOf(b);
|
||||
|
||||
if (idx === -1) return false;
|
||||
|
||||
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);
|
||||
}
|
||||
});
|
||||
|
||||
Object.defineProperty(Array.prototype, 'flat', {
|
||||
value: function() {
|
||||
return [].concat.apply([],this);
|
||||
}
|
||||
});
|
||||
|
||||
Object.defineProperty(Array.prototype, 'any', {
|
||||
value: function(fn) {
|
||||
var ev = this.every(function(x) {
|
||||
return !fn(x);
|
||||
});
|
||||
return !ev;
|
||||
}
|
||||
});
|
||||
|
||||
/* Return true if array contains x */
|
||||
/*Object.defineProperty(Array.prototype, 'includes', {
|
||||
value: function(x) {
|
||||
return this.some(e => e === x);
|
||||
}});
|
||||
*/
|
||||
Object.defineProperty(Array.prototype, 'empty', {
|
||||
get: function() { return this.length === 0; },
|
||||
});
|
||||
|
||||
Object.defineProperty(Array.prototype, 'push_unique', {
|
||||
value: function(x) {
|
||||
if (!this.includes(x)) this.push(x);
|
||||
}});
|
||||
|
||||
Object.defineProperty(Array.prototype, 'unique', {
|
||||
value: function() {
|
||||
var c = [];
|
||||
this.forEach(function(x) { c.push_unique(x); });
|
||||
return c;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
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 idx;
|
||||
}});
|
||||
|
||||
Object.defineProperty(Array.prototype, 'find', {
|
||||
value: function(fn) {
|
||||
var ret;
|
||||
|
||||
this.every(function(x) {
|
||||
if (fn(x)) {
|
||||
ret = x;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
|
||||
return ret;
|
||||
}});
|
||||
|
||||
Object.defineProperty(Array.prototype, 'last', {
|
||||
get: 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, 'wrapped', {
|
||||
value: function(x) {
|
||||
var c = this.slice(0, this.length);
|
||||
|
||||
for (var i = 0; i < x; i++)
|
||||
c.push(this[i]);
|
||||
|
||||
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) {
|
||||
var c = this.slice(0);
|
||||
if (c.length <= 1) return c;
|
||||
for (var i = c.length-2; i >= 0; i--)
|
||||
c.push(c[i]);
|
||||
|
||||
return c;
|
||||
}
|
||||
});
|
||||
|
||||
Object.defineProperty(Array.prototype, 'lerp', {
|
||||
value: function(to, t) {
|
||||
var c = [];
|
||||
this.forEach(function(x,i) {
|
||||
c[i] = (to[i] - x) * t + x;
|
||||
});
|
||||
return c;
|
||||
}
|
||||
});
|
||||
|
||||
Math.lerp = function(s,f,t) { return (f-s)*t + s; };
|
||||
|
||||
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);
|
||||
});
|
||||
|
||||
return obj;
|
||||
}});
|
||||
|
||||
/* MATH EXTENSIONS */
|
||||
Object.defineProperty(Number.prototype, 'lerp', {
|
||||
value: function(to, t) {
|
||||
var s = this;
|
||||
return (to - this) * t + this;
|
||||
}
|
||||
});
|
||||
|
||||
Math.clamp = function (x, l, h) { return x > h ? h : x < l ? l : x; }
|
||||
|
||||
Math.random_range = function(min,max) { return Math.random() * (max-min) + min; };
|
||||
|
||||
Math.snap = function(val, grid) {
|
||||
if (!grid || grid === 1) return Math.round(val);
|
||||
|
||||
var rem = val%grid;
|
||||
var d = val - rem;
|
||||
var i = Math.round(rem/grid)*grid;
|
||||
return d+i;
|
||||
}
|
||||
|
||||
Math.angledist = function (a1, a2) {
|
||||
var dist = a2 - a1;
|
||||
var wrap = dist >= 0 ? dist+360 : dist-360;
|
||||
wrap %= 360;
|
||||
|
||||
if (Math.abs(dist) < Math.abs(wrap))
|
||||
return dist;
|
||||
|
||||
return wrap;
|
||||
};
|
||||
Math.angledist.doc = "Find the shortest angle between two angles.";
|
||||
|
||||
Math.deg2rad = function(deg) { return deg * 0.0174533; };
|
||||
Math.rad2deg = function(rad) { return rad / 0.0174533; };
|
||||
Math.randomint = function(max) { return Math.clamp(Math.floor(Math.random() * max), 0, max-1); };
|
||||
|
||||
/* BOUNDINGBOXES */
|
||||
function cwh2bb(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
|
||||
};
|
||||
};
|
||||
|
||||
function points2bb(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;
|
||||
};
|
||||
|
||||
function bb2points(bb)
|
||||
{
|
||||
return [
|
||||
[bb.l,bb.t],
|
||||
[bb.r,bb.t],
|
||||
[bb.r,bb.b],
|
||||
[bb.l,bb.b]
|
||||
];
|
||||
}
|
||||
|
||||
function points2cwh(start,end)
|
||||
{
|
||||
var c = [];
|
||||
c[0] = (end[0] - start[0]) / 2;
|
||||
c[0] += start[0];
|
||||
c[1] = (end[1] - start[1]) / 2;
|
||||
c[1] += start[1];
|
||||
var wh = [];
|
||||
wh[0] = Math.abs(end[0] - start[0]);
|
||||
wh[1] = Math.abs(end[1] - start[1]);
|
||||
return {c: c, wh: wh};
|
||||
}
|
||||
|
||||
function bb2cwh(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];
|
||||
|
||||
return cwh;
|
||||
};
|
||||
|
||||
function pointinbb(bb, p)
|
||||
{
|
||||
if (bb.t < p.y || bb.b > p.y || bb.l > p.x || bb.r < p.x)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function movebb(bb, pos) {
|
||||
var newbb = Object.assign({}, bb);
|
||||
newbb.t += pos.y;
|
||||
newbb.b += pos.y;
|
||||
newbb.l += pos.x;
|
||||
newbb.r += pos.x;
|
||||
return newbb;
|
||||
};
|
||||
|
||||
function bb_expand(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;
|
||||
if (bb.l > x.l) bb.l = x.l;
|
||||
|
||||
return bb;
|
||||
};
|
||||
|
||||
function bb_from_objects(objs) {
|
||||
var bb = objs[0].boundingbox;
|
||||
objs.forEach(function(obj) { bb = bb_expand(bb, obj.boundingbox); });
|
||||
return bb;
|
||||
};
|
||||
|
||||
|
||||
/* VECTORS */
|
||||
var Vector = {
|
||||
x: 0,
|
||||
y: 0,
|
||||
length(v) {
|
||||
var sum = v.reduce(function(acc, val) { return acc + val**2; }, 0);
|
||||
return Math.sqrt(sum);
|
||||
},
|
||||
norm(v) {
|
||||
var len = Vector.length(v);
|
||||
return [v.x/len, v.y/len];
|
||||
|
||||
},
|
||||
make(x, y) {
|
||||
var vec = Object.create(this, {x:x, y:y});
|
||||
},
|
||||
|
||||
project(a, b) {
|
||||
return cmd(85, a, b);
|
||||
},
|
||||
|
||||
dot(a, b) {
|
||||
|
||||
},
|
||||
|
||||
random() {
|
||||
var vec = [Math.random()-0.5, Math.random()-0.5];
|
||||
return Vector.norm(vec);
|
||||
},
|
||||
|
||||
angle(v) {
|
||||
return Math.atan2(v.y, v.x);
|
||||
},
|
||||
|
||||
rotate(v,angle) {
|
||||
var r = Vector.length(v);
|
||||
var p = Vector.angle(v) + angle;
|
||||
return [r*Math.cos(p), r*Math.sin(p)];
|
||||
},
|
||||
|
||||
equal(v1, v2, tol) {
|
||||
if (!tol)
|
||||
return v1.equal(v2);
|
||||
|
||||
var eql = true;
|
||||
var c = v1.sub(v2);
|
||||
|
||||
c.forEach(function(x) {
|
||||
if (!eql) return;
|
||||
if (Math.abs(x) > tol)
|
||||
eql = false;
|
||||
});
|
||||
|
||||
return eql;
|
||||
},
|
||||
|
||||
};
|
||||
|
||||
/* POINT ASSISTANCE */
|
||||
|
||||
function points2cm(points)
|
||||
{
|
||||
var x = 0;
|
||||
var y = 0;
|
||||
var n = points.length;
|
||||
points.forEach(function(p) {
|
||||
x = x + p[0];
|
||||
y = y + p[1];
|
||||
});
|
||||
|
||||
return [x/n,y/n];
|
||||
};
|
||||
|
||||
function sortpointsccw(points)
|
||||
{
|
||||
var cm = points2cm(points);
|
||||
var cmpoints = points.map(function(x) { return x.sub(cm); });
|
||||
var ccw = cmpoints.sort(function(a,b) {
|
||||
aatan = Math.atan2(a.y, a.x);
|
||||
batan = Math.atan2(b.y, b.x);
|
||||
return aatan - batan;
|
||||
});
|
||||
|
||||
return ccw.map(function(x) { return x.add(cm); });
|
||||
}
|
||||
@@ -1,699 +0,0 @@
|
||||
var component = {
|
||||
toString() {
|
||||
if ('gameobject' in this)
|
||||
return this.name + " on " + this.gameobject;
|
||||
else
|
||||
return this.name;
|
||||
},
|
||||
name: "component",
|
||||
component: true,
|
||||
enabled: true,
|
||||
enable() { this.enabled = true; },
|
||||
disable() { this.enabled = false; },
|
||||
|
||||
make(go) { },
|
||||
kill() { Log.info("Kill not created for this component yet"); },
|
||||
gui() { },
|
||||
gizmo() { },
|
||||
|
||||
prepare_center() {},
|
||||
finish_center() {},
|
||||
clone(spec) {
|
||||
return clone(this, spec);
|
||||
},
|
||||
};
|
||||
|
||||
var sprite = clone(component, {
|
||||
name: "sprite",
|
||||
path: "",
|
||||
layer: 0,
|
||||
pos: [0,0],
|
||||
get visible() { return this.enabled; },
|
||||
set visible(x) { this.enabled = x; },
|
||||
asset(str) { this.path = str; this.sync();},
|
||||
angle: 0,
|
||||
rect: {s0:0, s1: 1, t0: 0, t1: 1},
|
||||
|
||||
dimensions() { return cmd(64,this.path); },
|
||||
width() { return cmd(64,this.path).x; },
|
||||
height() { return cmd(64,this.path).y; },
|
||||
|
||||
make(go) {
|
||||
var sprite = Object.create(this);
|
||||
var id = make_sprite(go,this.path,this.pos);
|
||||
complete_assign(sprite, {
|
||||
get enabled() { return cmd(114,id); },
|
||||
set enabled(x) { cmd(20,id,x); },
|
||||
set color(x) { cmd(96,id,x); },
|
||||
get color() {return undefined; },
|
||||
get pos() { return cmd(111, id); },
|
||||
set pos(x) { cmd(37,id,x); },
|
||||
set layer(x) { cmd(60, id, x); },
|
||||
get layer() { return undefined; },
|
||||
|
||||
boundingbox() {
|
||||
var dim = this.dimensions();
|
||||
dim = dim.scale(this.gameobject.scale);
|
||||
var realpos = this.pos.copy();
|
||||
realpos.x = realpos.x * dim.x + (dim.x/2);
|
||||
realpos.y = realpos.y * dim.y + (dim.y/2);
|
||||
return cwh2bb(realpos,dim);
|
||||
},
|
||||
|
||||
sync() {
|
||||
if (this.path)
|
||||
cmd(12,id,this.path,this.rect);
|
||||
},
|
||||
|
||||
kill() { cmd(9,id); },
|
||||
});
|
||||
|
||||
sprite.layer = 1;
|
||||
return sprite;
|
||||
},
|
||||
|
||||
POS_MID: [-0.5, -0.5],
|
||||
});
|
||||
|
||||
sprite.inputs = {};
|
||||
sprite.inputs.kp9 = function() { this.pos = [0,0]; };
|
||||
sprite.inputs.kp8 = function() { this.pos = [-0.5, 0]; };
|
||||
sprite.inputs.kp7 = function() { this.pos = [-1,0]; };
|
||||
sprite.inputs.kp6 = function() { this.pos = [0,-0.5]; };
|
||||
sprite.inputs.kp5 = function() { this.pos = [-0.5,-0.5]; };
|
||||
sprite.inputs.kp4 = function() { this.pos = [-1,-0.5]; };
|
||||
sprite.inputs.kp3 = function() { this.pos = [0, -1]; };
|
||||
sprite.inputs.kp2 = function() { this.pos = [-0.5,-1]; };
|
||||
sprite.inputs.kp1 = function() { this.pos = [-1,-1]; };
|
||||
|
||||
|
||||
/* Container to play sprites and anim2ds */
|
||||
var char2d = clone(sprite, {
|
||||
clone(anims) {
|
||||
var char = clone(this);
|
||||
char.anims = anims;
|
||||
return char;
|
||||
},
|
||||
|
||||
name: "char 2d",
|
||||
|
||||
frame2rect(frames, frame) {
|
||||
var rect = {s0:0,s1:1,t0:0,t1:1};
|
||||
|
||||
var frameslice = 1/frames;
|
||||
rect.s0 = frameslice*frame;
|
||||
rect.s1 = frameslice*(frame+1);
|
||||
|
||||
return rect;
|
||||
},
|
||||
|
||||
make(go) {
|
||||
var char = clone(this, {
|
||||
get enabled() { return cmd(114,this.id); },
|
||||
set enabled(x) { cmd(20,this.id,x); },
|
||||
set color(x) { cmd(96,this.id,x); },
|
||||
get pos() { return cmd(111, this.id); },
|
||||
set pos(x) { cmd(37,this.id,x); },
|
||||
set layer(x) { cmd(60, this.id, x); },
|
||||
get layer() { return this.gameobject.draw_layer; },
|
||||
|
||||
boundingbox() {
|
||||
var dim = cmd(64,this.path);
|
||||
dim = dim.scale(this.gameobject.scale);
|
||||
dim.x *= 1/6;
|
||||
var realpos = [0,0];
|
||||
// var realpos = this.pos.slice();
|
||||
|
||||
// realpos.x = realpos.x * dim.x + (dim.x/2);
|
||||
// realpos.y = realpos.y * dim.y + (dim.y/2);
|
||||
return cwh2bb(realpos,dim);
|
||||
},
|
||||
|
||||
sync() {
|
||||
if (this.path)
|
||||
cmd(12,this.id,this.path,this.rect);
|
||||
},
|
||||
|
||||
kill() { cmd(9,this.id); },
|
||||
});
|
||||
|
||||
char.curplaying = char.anims.array()[0];
|
||||
char.obscure('curplaying');
|
||||
char.id = make_sprite(go, char.curplaying.path, this.pos);
|
||||
|
||||
char.obscure('id');
|
||||
char.frame = 0;
|
||||
char.timer = timer.make(char.advance.bind(char), 1/char.curplaying.fps);
|
||||
char.timer.loop = true;
|
||||
char.obscure('timer');
|
||||
// char.obscure('rect');
|
||||
char.rect = {};
|
||||
char.setsprite();
|
||||
return char;
|
||||
},
|
||||
|
||||
frame: 0,
|
||||
|
||||
play(name) {
|
||||
if (!(name in this.anims)) {
|
||||
Log.info("Can't find an animation named " + name);
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.curplaying === this.anims[name]) {
|
||||
this.timer.start();
|
||||
return;
|
||||
}
|
||||
|
||||
this.curplaying = this.anims[name];
|
||||
this.timer.time = 1/this.curplaying.fps;
|
||||
this.timer.start();
|
||||
this.frame = 0;
|
||||
this.setsprite();
|
||||
},
|
||||
|
||||
setsprite() {
|
||||
this.path = this.curplaying.path;
|
||||
this.rect = this.frame2rect(this.curplaying.frames, this.frame);
|
||||
cmd(12, this.id, this.path, this.rect);
|
||||
},
|
||||
|
||||
advance() {
|
||||
this.frame = (this.frame + 1) % this.curplaying.frames;
|
||||
this.setsprite();
|
||||
|
||||
if (this.frame === 0 && !this.curplaying.loop)
|
||||
this.timer.pause();
|
||||
},
|
||||
|
||||
devance() {
|
||||
this.frame = (this.frame - 1);
|
||||
if (this.frame === -1) this.frame = this.curplaying.frames-1;
|
||||
this.setsprite();
|
||||
},
|
||||
|
||||
setframe(frame) {
|
||||
this.frame = frame;
|
||||
this.setsprite();
|
||||
},
|
||||
|
||||
pause() {
|
||||
this.timer.pause();
|
||||
},
|
||||
|
||||
stop() {
|
||||
this.setframe(0);
|
||||
this.timer.stop();
|
||||
},
|
||||
|
||||
kill() {
|
||||
this.timer.kill();
|
||||
cmd(9, this.id);
|
||||
},
|
||||
});
|
||||
|
||||
/* Returns points specifying this geometry, with ccw */
|
||||
var Geometry = {
|
||||
box(w, h) {
|
||||
w /= 2;
|
||||
h /= 2;
|
||||
|
||||
var points = [
|
||||
[w,h],
|
||||
[-w,h],
|
||||
[-w,-h],
|
||||
[w,-h]
|
||||
];
|
||||
|
||||
return points;
|
||||
}
|
||||
};
|
||||
|
||||
/* For all colliders, "shape" is a pointer to a phys2d_shape, "id" is a pointer to the shape data */
|
||||
var collider2d = clone(component, {
|
||||
name: "collider 2d",
|
||||
sensor: false,
|
||||
|
||||
kill() {}, /* No killing is necessary - it is done through the gameobject's kill */
|
||||
|
||||
register_hit(fn, obj) {
|
||||
register_collide(1, fn, obj, this.gameobject.body, this.shape);
|
||||
},
|
||||
|
||||
make_fns: {
|
||||
set sensor(x) { cmd(18,this.shape,x); },
|
||||
get sensor() { return cmd(21,this.shape); },
|
||||
set enabled(x) { cmd(22,this.shape,x); },
|
||||
get enabled() { return cmd(23,this.shape); }
|
||||
},
|
||||
|
||||
});
|
||||
|
||||
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-t'] = function() { this.enabled = !this.enabled; }
|
||||
collider2d.inputs['M-t'].doc = "Toggle if this collider is enabled.";
|
||||
|
||||
var polygon2d = clone(collider2d, {
|
||||
name: "polygon 2d",
|
||||
points: [],
|
||||
flipx: false,
|
||||
flipy: false,
|
||||
|
||||
clone(spec) {
|
||||
var obj = Object.create(this);
|
||||
obj.points = this.points.copy();
|
||||
Object.assign(obj, spec);
|
||||
return obj;
|
||||
},
|
||||
|
||||
make(go) {
|
||||
var poly = Object.create(this);
|
||||
Object.assign(poly, make_poly2d(go, this.points));
|
||||
|
||||
complete_assign(poly, this.make_fns);
|
||||
complete_assign(poly, {
|
||||
boundingbox() {
|
||||
return points2bb(this.spoints);
|
||||
},
|
||||
|
||||
sync() { cmd_poly2d(0, this.id, this.spoints); }
|
||||
});
|
||||
|
||||
poly.defn('points', this.points.copy());
|
||||
|
||||
Object.defineProperty(poly, 'id', {enumerable:false});
|
||||
Object.defineProperty(poly, 'shape', {enumerable:false});
|
||||
|
||||
poly.sync();
|
||||
|
||||
return poly;
|
||||
},
|
||||
|
||||
/* EDITOR */
|
||||
get spoints() {
|
||||
var spoints = this.points.slice();
|
||||
|
||||
if (this.flipx) {
|
||||
spoints.forEach(function(x) {
|
||||
var newpoint = x.slice();
|
||||
newpoint.x = -newpoint.x;
|
||||
spoints.push(newpoint);
|
||||
});
|
||||
}
|
||||
|
||||
if (this.flipy) {
|
||||
spoints.forEach(function(x) {
|
||||
var newpoint = x.slice();
|
||||
newpoint.y = -newpoint.y;
|
||||
spoints.push(newpoint);
|
||||
});
|
||||
}
|
||||
|
||||
return spoints;
|
||||
},
|
||||
|
||||
gizmo() {
|
||||
if (!this.hasOwn('points')) this.points = this.__proto__.points.copy();
|
||||
|
||||
this.spoints.forEach(function(x) {
|
||||
Debug.point(world2screen(this.gameobject.this2world(x)), 3, Color.green);
|
||||
}, this);
|
||||
|
||||
this.points.forEach(function(x, i) {
|
||||
Debug.numbered_point(this.gameobject.this2world(x), i);
|
||||
}, this);
|
||||
},
|
||||
|
||||
pick(pos) {
|
||||
return Gizmos.pick_gameobject_points(pos, this.gameobject, this.points);
|
||||
},
|
||||
|
||||
query() {
|
||||
return cmd(80, this.shape);
|
||||
},
|
||||
});
|
||||
|
||||
polygon2d.inputs = {};
|
||||
polygon2d.inputs.post = function() { this.sync(); };
|
||||
polygon2d.inputs.f10 = function() {
|
||||
this.points = sortpointsccw(this.points);
|
||||
};
|
||||
polygon2d.inputs.f10.doc = "Sort all points to be CCW order.";
|
||||
|
||||
polygon2d.inputs['C-lm'] = function() {
|
||||
this.points.push(this.gameobject.world2this(Mouse.worldpos));
|
||||
};
|
||||
polygon2d.inputs['C-lm'].doc = "Add a point to location of mouse.";
|
||||
|
||||
polygon2d.inputs['S-lm'] = function() {
|
||||
var idx = grab_from_points(Mouse.worldpos, this.points.map(p => this.gameobject.this2world(p)), 25);
|
||||
if (idx === -1) return;
|
||||
this.points.splice(idx, 1);
|
||||
};
|
||||
polygon2d.inputs['S-lm'].doc = "Remove point under mouse.";
|
||||
|
||||
polygon2d.inputs['C-b'] = function() {
|
||||
this.points = this.spoints;
|
||||
this.flipx = false;
|
||||
this.flipy = false;
|
||||
};
|
||||
polygon2d.inputs['C-b'].doc = "Freeze mirroring in place.";
|
||||
|
||||
var bucket = clone(collider2d, {
|
||||
name: "bucket",
|
||||
clone(spec) {
|
||||
var obj = Object.create(this);
|
||||
obj.cpoints = this.cpoints.copy();
|
||||
dainty_assign(obj, spec);
|
||||
return obj;
|
||||
},
|
||||
|
||||
cpoints:[],
|
||||
degrees:2,
|
||||
dimensions:2,
|
||||
/* open: 0
|
||||
clamped: 1
|
||||
beziers: 2
|
||||
looped: 3
|
||||
*/
|
||||
type: 3,
|
||||
typeid: {
|
||||
open: 0,
|
||||
clamped: 1,
|
||||
beziers: 2,
|
||||
looped: 3
|
||||
},
|
||||
|
||||
flipx: false,
|
||||
flipy: false,
|
||||
|
||||
hollow: false,
|
||||
hollowt: 0,
|
||||
|
||||
get spoints() {
|
||||
var spoints = this.cpoints.slice();
|
||||
|
||||
if (this.flipx) {
|
||||
for (var i = spoints.length-1; i >= 0; i--) {
|
||||
var newpoint = spoints[i].slice();
|
||||
newpoint.x = -newpoint.x;
|
||||
spoints.push(newpoint);
|
||||
}
|
||||
}
|
||||
|
||||
if (this.flipy) {
|
||||
for (var i = spoints.length-1; i >= 0; i--) {
|
||||
var newpoint = spoints[i].slice();
|
||||
newpoint.y = -newpoint.y;
|
||||
spoints.push(newpoint);
|
||||
}
|
||||
}
|
||||
|
||||
return spoints;
|
||||
|
||||
if (this.hollow) {
|
||||
var hpoints = [];
|
||||
var inflatep = inflate_cpv(spoints, spoints.length, this.hollowt);
|
||||
inflatep[0].slice().reverse().forEach(function(x) { hpoints.push(x); });
|
||||
|
||||
inflatep[1].forEach(function(x) { hpoints.push(x); });
|
||||
return hpoints;
|
||||
}
|
||||
|
||||
return spoints;
|
||||
},
|
||||
|
||||
sample(n) {
|
||||
var spoints = this.spoints;
|
||||
|
||||
this.degrees = Math.clamp(this.degrees, 1, spoints.length-1);
|
||||
|
||||
if (spoints.length === 2)
|
||||
return spoints;
|
||||
if (spoints.length < 2)
|
||||
return [];
|
||||
if (this.degrees < 2) {
|
||||
if (this.type === 3)
|
||||
return spoints.wrapped(1);
|
||||
|
||||
return spoints;
|
||||
}
|
||||
|
||||
/*
|
||||
order = degrees+1
|
||||
knots = spoints.length + order
|
||||
assert knots%order != 0
|
||||
*/
|
||||
|
||||
if (this.type === bucket.typeid.looped)
|
||||
return spline_cmd(0, this.degrees, this.dimensions, 0, spoints.wrapped(this.degrees), n);
|
||||
|
||||
return spline_cmd(0, this.degrees, this.dimensions, this.type, spoints, n);
|
||||
},
|
||||
|
||||
samples: 10,
|
||||
points:[],
|
||||
thickness:0, /* Number of pixels out the edge is */
|
||||
|
||||
make(go) {
|
||||
var edge = Object.create(this);
|
||||
Object.assign(edge, make_edge2d(go, this.points, this.thickness));
|
||||
complete_assign(edge, {
|
||||
set thickness(x) {
|
||||
cmd_edge2d(1,this.id,x);
|
||||
},
|
||||
get thickness() { return cmd(112,this.id); },
|
||||
|
||||
boundingbox() {
|
||||
return points2bb(this.points.map(x => x.scale(this.gameobject.scale)));
|
||||
},
|
||||
|
||||
sync() {
|
||||
var sensor = this.sensor;
|
||||
this.points = this.sample(this.samples);
|
||||
cmd_edge2d(0,this.id,this.points);
|
||||
this.sensor = sensor;
|
||||
},
|
||||
});
|
||||
|
||||
complete_assign(edge, this.make_fns);
|
||||
|
||||
Object.defineProperty(edge, 'id', {enumerable:false});
|
||||
Object.defineProperty(edge, 'shape', {enumerable:false});
|
||||
|
||||
edge.defn('points', []);
|
||||
|
||||
return edge;
|
||||
},
|
||||
|
||||
/* EDITOR */
|
||||
gizmo() {
|
||||
if (!this.hasOwn('cpoints')) this.cpoints = this.__proto__.cpoints.copy();
|
||||
|
||||
this.spoints.forEach(function(x) {
|
||||
Debug.point(world2screen(this.gameobject.this2world(x)), 3, Color.green);
|
||||
}, this);
|
||||
|
||||
this.cpoints.forEach(function(x, i) {
|
||||
Debug.numbered_point(this.gameobject.this2world(x), i);
|
||||
}, this);
|
||||
},
|
||||
|
||||
finish_center(change) {
|
||||
this.cpoints = this.cpoints.map(function(x) { return x.sub(change); });
|
||||
},
|
||||
|
||||
pick(pos) { return Gizmos.pick_gameobject_points(pos, this.gameobject, this.cpoints); },
|
||||
});
|
||||
|
||||
bucket.inputs = {};
|
||||
bucket.inputs.h = function() { this.hollow = !this.hollow; };
|
||||
bucket.inputs.h.doc = "Toggle hollow.";
|
||||
|
||||
bucket.inputs['C-g'] = function() {
|
||||
this.hollowt--;
|
||||
if (this.hollowt < 0) this.hollowt = 0;
|
||||
};
|
||||
bucket.inputs['C-g'].doc = "Thin the hollow thickness.";
|
||||
|
||||
bucket.inputs['C-f'] = function() { this.hollowt++; };
|
||||
bucket.inputs['C-f'].doc = "Increase the hollow thickness.";
|
||||
|
||||
bucket.inputs['M-v'] = function() { this.thickness--; };
|
||||
bucket.inputs['M-v'].doc = "Decrease spline thickness.";
|
||||
bucket.inputs['M-v'].rep = true;
|
||||
|
||||
bucket.inputs['C-b'] = function() {
|
||||
this.cpoints = this.spoints;
|
||||
this.flipx = false;
|
||||
this.flipy = false;
|
||||
};
|
||||
bucket.inputs['C-b'].doc = "Freeze mirroring,";
|
||||
bucket.inputs['M-b'] = function() { this.thickness++; };
|
||||
bucket.inputs['M-b'].doc = "Increase spline thickness.";
|
||||
bucket.inputs['M-b'].rep = true;
|
||||
|
||||
bucket.inputs['C-plus'] = function() { this.degrees++; };
|
||||
bucket.inputs['C-plus'].doc = "Increase the degrees of this spline.";
|
||||
bucket.inputs['C-plus'].rep = true;
|
||||
|
||||
bucket.inputs.plus = function() { this.samples++; };
|
||||
bucket.inputs.plus.doc = "Increase the number of samples of this spline.";
|
||||
bucket.inputs.plus.rep = true;
|
||||
|
||||
bucket.inputs.minus = function() {
|
||||
this.samples--;
|
||||
if (this.samples < 1) this.samples = 1;
|
||||
};
|
||||
bucket.inputs.minus.doc = "Decrease the number of samples on this spline.";
|
||||
bucket.inputs.minus.rep = true;
|
||||
|
||||
bucket.inputs['C-minus'] = function() { this.degrees--; };
|
||||
bucket.inputs['C-minus'].doc = "Decrease the number of degrees of this spline.";
|
||||
bucket.inputs['C-minus'].rep = true;
|
||||
|
||||
bucket.inputs['C-r'] = function() { this.cpoints = this.cpoints.reverse(); };
|
||||
bucket.inputs['C-r'].doc = "Reverse the order of the spline's points.";
|
||||
|
||||
bucket.inputs['C-l'] = function() { this.type = 3; };
|
||||
bucket.inputs['C-l'].doc = "Set type of spline to clamped.";
|
||||
|
||||
bucket.inputs['C-c'] = function() { this.type = 1; };
|
||||
bucket.inputs['C-c'].doc = "Set type of spline to closed.";
|
||||
|
||||
bucket.inputs['C-o'] = function() { this.type = 0; };
|
||||
bucket.inputs['C-o'].doc = "Set spline to open.";
|
||||
|
||||
bucket.inputs['C-M-lm'] = function() {
|
||||
var idx = grab_from_points(Mouse.worldpos, this.cpoints.map(this.gameobject.world2this,this.gameobject), 25);
|
||||
if (idx === -1) return;
|
||||
|
||||
this.cpoints = this.cpoints.newfirst(idx);
|
||||
};
|
||||
bucket.inputs['C-M-lm'].doc = "Select the given point as the '0' of this spline.";
|
||||
|
||||
bucket.inputs['C-lm'] = function() {
|
||||
var idx = 0;
|
||||
|
||||
if (this.cpoints.length >= 2) {
|
||||
idx = cmd(59, screen2world(Mouse.pos).sub(this.gameobject.pos), this.cpoints, 1000);
|
||||
if (idx === -1) return;
|
||||
}
|
||||
|
||||
if (idx === this.cpoints.length)
|
||||
this.cpoints.push(this.gameobject.world2this(screen2world(Mouse.pos)));
|
||||
else
|
||||
this.cpoints.splice(idx, 0, this.gameobject.world2this(screen2world(Mouse.pos)));
|
||||
};
|
||||
bucket.inputs['C-lm'].doc = "Add a point to the spline at the mouse position.";
|
||||
|
||||
bucket.inputs['S-lm'] = function() {
|
||||
var idx = grab_from_points(screen2world(Mouse.pos), this.cpoints.map(function(x) {return x.add(this.gameobject.pos); }, this), 25);
|
||||
if (idx === -1) return;
|
||||
|
||||
this.cpoints.splice(idx, 1);
|
||||
};
|
||||
bucket.inputs['S-lm'].doc = "Remove point from the spline.";
|
||||
|
||||
bucket.inputs.lb = function() {
|
||||
var np = [];
|
||||
|
||||
this.cpoints.forEach(function(c) {
|
||||
np.push(Vector.rotate(c, Math.deg2rad(-1)));
|
||||
});
|
||||
|
||||
this.cpoints = np;
|
||||
};
|
||||
bucket.inputs.lb.doc = "Rotate the points CCW.";
|
||||
bucket.inputs.lb.rep = true;
|
||||
|
||||
bucket.inputs.rb = function() {
|
||||
var np = [];
|
||||
|
||||
this.cpoints.forEach(function(c) {
|
||||
np.push(Vector.rotate(c, Math.deg2rad(1)));
|
||||
});
|
||||
|
||||
this.cpoints = np;
|
||||
};
|
||||
bucket.inputs.rb.doc = "Rotate the points CW.";
|
||||
bucket.inputs.rb.rep = true;
|
||||
|
||||
var circle2d = clone(collider2d, {
|
||||
name: "circle 2d",
|
||||
radius: 10,
|
||||
offset: [0,0],
|
||||
|
||||
get scale() { return this.radius; },
|
||||
set scale(x) { this.radius = x; },
|
||||
|
||||
get pos() { return this.offset; },
|
||||
set pos(x) { this.offset = x; },
|
||||
|
||||
make(go) {
|
||||
var circle = clone(this);
|
||||
var circ = make_circle2d(go, circle.radius, circle.offset);
|
||||
Object.assign(circle, circ);
|
||||
Object.defineProperty(circle, 'id', {enumerable:false});
|
||||
Object.defineProperty(circle, 'shape', {enumerable:false});
|
||||
|
||||
complete_assign(circle, {
|
||||
set radius(x) { cmd_circle2d(0,this.id,x); },
|
||||
get radius() { return cmd_circle2d(2,this.id); },
|
||||
|
||||
set offset(x) { cmd_circle2d(1,this.id,x); },
|
||||
get offset() { return cmd_circle2d(3,this.id); },
|
||||
|
||||
boundingbox() {
|
||||
var diameter = this.radius*2*this.gameobject.scale;
|
||||
return cwh2bb(this.offset.scale(this.gameobject.scale), [this.radius,this.radius]);
|
||||
},
|
||||
});
|
||||
|
||||
complete_assign(circle, this.make_fns);
|
||||
|
||||
return circle;
|
||||
},
|
||||
|
||||
gui() {
|
||||
Nuke.newline();
|
||||
Nuke.label("circle2d");
|
||||
this.radius = Nuke.pprop("Radius", this.radius);
|
||||
this.offset = Nuke.pprop("offset", this.offset);
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
/* ASSETS */
|
||||
|
||||
var Texture = {
|
||||
mipmaps(path, x) {
|
||||
cmd(94, path, x);
|
||||
},
|
||||
|
||||
sprite(path, x) {
|
||||
cmd(95, path, x);
|
||||
},
|
||||
};
|
||||
|
||||
var Resources = {
|
||||
load(path) {
|
||||
if (path in this)
|
||||
return this[path];
|
||||
|
||||
var src = {};
|
||||
this[path] = src;
|
||||
src.path = path;
|
||||
|
||||
if (!IO.exists(`${path}.asset`))
|
||||
return this[path];
|
||||
|
||||
var data = JSON.parse(IO.slurp(`${path}.asset`));
|
||||
Object.assign(src,data);
|
||||
return this[path];
|
||||
|
||||
},
|
||||
};
|
||||
@@ -1,336 +0,0 @@
|
||||
var Gizmos = {
|
||||
pick_gameobject_points(worldpos, gameobject, points) {
|
||||
var idx = grab_from_points(worldpos, points.map(gameobject.this2world,gameobject), 25);
|
||||
if (idx === -1) return null;
|
||||
return points[idx];
|
||||
},
|
||||
};
|
||||
|
||||
var Shape = {
|
||||
circle(pos, radius, color) {
|
||||
cmd(115, pos, radius, color);
|
||||
},
|
||||
};
|
||||
|
||||
var Debug = {
|
||||
draw_grid(width, span, color) {
|
||||
color = color ? color : Color.green;
|
||||
cmd(47, width, span, color);
|
||||
},
|
||||
|
||||
point(pos, size, color) {
|
||||
color = color ? color : Color.blue;
|
||||
Shape.circle(pos, size, color);
|
||||
// cmd(51, pos, size,color);
|
||||
},
|
||||
|
||||
arrow(start, end, color, capsize) {
|
||||
color = color ? color : Color.red;
|
||||
if (!capsize)
|
||||
capsize = 4;
|
||||
cmd(81, start, end, color, capsize);
|
||||
},
|
||||
|
||||
poly(points, color) {
|
||||
cmd_points(0,points,color);
|
||||
},
|
||||
|
||||
boundingbox(bb, color) {
|
||||
color ??= Color.white;
|
||||
cmd_points(0, bb2points(bb), color);
|
||||
},
|
||||
|
||||
box(pos, wh, color) {
|
||||
color ??= Color.white;
|
||||
cmd(53, pos, wh, color);
|
||||
},
|
||||
|
||||
numbered_point(pos, n) {
|
||||
Debug.point(world2screen(pos), 3);
|
||||
gui_text(n, world2screen(pos).add([0,4]), 1);
|
||||
},
|
||||
|
||||
phys_drawing: false,
|
||||
draw_phys(on) {
|
||||
this.phys_drawing = on;
|
||||
cmd(4, this.phys_drawing);
|
||||
},
|
||||
|
||||
draw_obj_phys(obj) {
|
||||
cmd(82, obj.body);
|
||||
},
|
||||
|
||||
register_call(fn, obj) {
|
||||
Register.debug.register(fn,obj);
|
||||
},
|
||||
|
||||
line(points, color, type, thickness) {
|
||||
thickness ??= 1;
|
||||
|
||||
if (!type)
|
||||
type = 0;
|
||||
|
||||
if (!color)
|
||||
color = Color.white;
|
||||
|
||||
switch (type) {
|
||||
case 0:
|
||||
cmd(83, points, color, thickness);
|
||||
}
|
||||
},
|
||||
|
||||
draw_bb: false,
|
||||
draw_gizmos: false,
|
||||
draw_names: false,
|
||||
|
||||
draw() {
|
||||
if (this.draw_bb)
|
||||
Game.objects.forEach(function(x) { Debug.boundingbox(x.boundingbox(), [255,255,255,10]); });
|
||||
|
||||
if (Game.paused()) gui_text("PAUSED", [0,0],1);
|
||||
|
||||
if (this.draw_gizmos)
|
||||
Game.objects.forEach(function(x) {
|
||||
if (!x.icon) return;
|
||||
gui_img(x.icon, world2screen(x.pos));
|
||||
});
|
||||
|
||||
if (this.draw_names)
|
||||
Game.objects.forEach(function(x) {
|
||||
GUI.text(x.fullpath(), world2screen(x.pos).add([0,32]), 1, [84,110,255]);
|
||||
});
|
||||
|
||||
if (Debug.Options.gif.rec) {
|
||||
gui_text("REC", [0,40], 1);
|
||||
gui_text(Time.seconds_to_timecode(Time.time - Debug.Options.gif.start_time, Debug.Options.gif.fps), [0,30], 1);
|
||||
}
|
||||
|
||||
gui_text(Game.playing() ? "PLAYING"
|
||||
: Game.stepping() ?
|
||||
"STEP" :
|
||||
Game.paused() ?
|
||||
"PAUSED; EDITING" :
|
||||
"EDIT", [0, 0], 1);
|
||||
},
|
||||
};
|
||||
|
||||
Debug.Options = { };
|
||||
Debug.Options.Color = {
|
||||
set trigger(x) { cmd(17,x); },
|
||||
set debug(x) { cmd(16, x); },
|
||||
};
|
||||
|
||||
var Gizmos = {
|
||||
pick_gameobject_points(worldpos, gameobject, points) {
|
||||
var idx = grab_from_points(worldpos, points.map(gameobject.this2world,gameobject), 25);
|
||||
if (idx === -1) return null;
|
||||
return points[idx];
|
||||
},
|
||||
};
|
||||
|
||||
var Profile = {
|
||||
tick_now() { return cmd(127); },
|
||||
ns(ticks) { return cmd(128, ticks); },
|
||||
us(ticks) { return cmd(129, ticks); },
|
||||
ms(ticks) { return cmd(130, ticks); },
|
||||
cpu(fn, times, q) {
|
||||
times ??= 1;
|
||||
q ??= "ns";
|
||||
var start = Profile.tick_now();
|
||||
for (var i = 0; i < times; i++)
|
||||
fn();
|
||||
var elapsed = Profile.tick_now() - start;
|
||||
Log.say(`Profiled in ${Profile[q](elapsed)/times} avg ${q}.`);
|
||||
},
|
||||
|
||||
get fps() { return sys_cmd(8); },
|
||||
};
|
||||
|
||||
var Nuke = {
|
||||
newline(cols) { nuke(3, cols ? cols : 1); },
|
||||
newrow(height) { nuke(13,height); },
|
||||
|
||||
wins: {},
|
||||
curwin:"",
|
||||
|
||||
prop(str, v) {
|
||||
var ret = nuke(2, str, v);
|
||||
if (Number.isFinite(ret)) return ret;
|
||||
return 0;
|
||||
},
|
||||
|
||||
treeid: 0,
|
||||
|
||||
tree(str) { var on = nuke(11, str, this.treeid); this.treeid++; return on; },
|
||||
tree_pop() { nuke(12);},
|
||||
|
||||
prop_num(str, num) { return nuke(2, str, num, -1e10, 1e10, 0.01); },
|
||||
prop_bool(str, val) { return nuke(4, str, val); },
|
||||
checkbox(val) { return nuke(4,"",val); },
|
||||
label(str) { nuke(5, str); },
|
||||
textbox(str) { return nuke(7, str); },
|
||||
scrolltext(str) { nuke(14,str); },
|
||||
|
||||
defaultrect: { x:10, y:10, w:400, h:600 },
|
||||
window(name) {
|
||||
this.curwin = name;
|
||||
var rect;
|
||||
if (name in this.wins)
|
||||
rect = this.wins[name];
|
||||
else
|
||||
rect = { x:10, y:10, w:400, h:600 };
|
||||
|
||||
nuke(0, name, rect);
|
||||
},
|
||||
button(name) { return nuke(6, name); },
|
||||
radio(name, val, cmp) { return nuke(9, name, val, cmp); },
|
||||
img(path) { nuke(8, path); },
|
||||
end() {
|
||||
this.wins[this.curwin] = nuke(10);
|
||||
this.treeid = 0;
|
||||
nuke(1);
|
||||
},
|
||||
|
||||
pprop(str, p, nonew) {
|
||||
switch(typeof p) {
|
||||
case 'number':
|
||||
if (!nonew) Nuke.newline();
|
||||
return Nuke.prop_num(str, p);
|
||||
break;
|
||||
|
||||
case 'boolean':
|
||||
if (!nonew) Nuke.newline();
|
||||
return Nuke.prop_bool(str, p);
|
||||
|
||||
case 'object':
|
||||
if (Array.isArray(p)) {
|
||||
var arr = [];
|
||||
Nuke.newline(p.length+1);
|
||||
Nuke.label(str);
|
||||
arr[0] = Nuke.pprop("#x", p[0], true);
|
||||
arr[1] = Nuke.pprop("#y", p[1], true);
|
||||
return arr;
|
||||
|
||||
} else {
|
||||
if (!nonew)Nuke.newline(2);
|
||||
Nuke.label(str);
|
||||
Nuke.label(p);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'string':
|
||||
if (!nonew) Nuke.newline();
|
||||
Nuke.label(str);
|
||||
return Nuke.textbox(p);
|
||||
|
||||
default:
|
||||
if (!nonew) Nuke.newline(2);
|
||||
Nuke.label(str);
|
||||
Nuke.label(p);
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
Object.defineProperty(Nuke, "curwin", {enumerable:false});
|
||||
Object.defineProperty(Nuke, "defaultrect", {enumerable:false});
|
||||
|
||||
/* These controls are available during editing, and during play of debug builds */
|
||||
var DebugControls = {};
|
||||
DebugControls.inputs = {};
|
||||
DebugControls.inputs.f1 = function () { Debug.draw_phys(!Debug.phys_drawing); };
|
||||
DebugControls.inputs.f1.doc = "Draw physics debugging aids.";
|
||||
DebugControls.inputs.f3 = function() { Debug.draw_bb = !Debug.draw_bb; };
|
||||
DebugControls.inputs.f3.doc = "Toggle drawing bounding boxes.";
|
||||
DebugControls.inputs.f4 = function() {
|
||||
Debug.draw_names = !Debug.draw_names;
|
||||
Debug.draw_gizmos = !Debug.draw_gizmos;
|
||||
};
|
||||
DebugControls.inputs.f4.doc = "Toggle drawing gizmos and names of objects.";
|
||||
|
||||
Debug.Options.gif = {
|
||||
w: 640, /* Max width */
|
||||
h: 480, /* Max height */
|
||||
stretch: false, /* True if you want to stretch */
|
||||
cpf: 4,
|
||||
depth: 16,
|
||||
file: "out.gif",
|
||||
rec: false,
|
||||
secs: 6,
|
||||
start_time: 0,
|
||||
fps: 0,
|
||||
start() {
|
||||
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;
|
||||
}
|
||||
|
||||
cmd(131, w, h, this.cpf, this.depth);
|
||||
this.rec = true;
|
||||
this.fps = (1/this.cpf)*100;
|
||||
this.start_time = Time.time;
|
||||
|
||||
timer.oneshot(this.stop.bind(this), this.secs, this, true);
|
||||
},
|
||||
|
||||
stop() {
|
||||
if (!this.rec) return;
|
||||
cmd(132, this.file);
|
||||
this.rec = false;
|
||||
},
|
||||
};
|
||||
|
||||
DebugControls.inputs.f8 = Debug.Options.gif.start.bind(Debug.Options.gif);
|
||||
DebugControls.inputs.f9 = Debug.Options.gif.stop.bind(Debug.Options.gif);
|
||||
|
||||
DebugControls.inputs.f10 = function() { Time.timescale = 0.1; };
|
||||
DebugControls.inputs.f10.doc = "Toggle timescale to 1/10.";
|
||||
DebugControls.inputs.f10.released = function () { Time.timescale = 1.0; };
|
||||
DebugControls.inputs.f12 = function() { GUI.defaults.debug = !GUI.defaults.debug; Log.warn("GUI toggle debug");};
|
||||
DebugControls.inputs.f12.doc = "Toggle drawing GUI debugging aids.";
|
||||
|
||||
DebugControls.inputs['M-1'] = Render.normal;
|
||||
Render.normal.doc = "Render mode for enabling all shaders and lighting effects.";
|
||||
DebugControls.inputs['M-2'] = Render.wireframe;
|
||||
Render.wireframe.doc = "Render mode to see wireframes of all models.";
|
||||
|
||||
DebugControls.inputs['C-M-f'] = function() {};
|
||||
DebugControls.inputs['C-M-f'].doc = "Enter camera fly mode.";
|
||||
|
||||
var Time = {
|
||||
set timescale(x) { cmd(3, x); },
|
||||
get timescale() { return cmd(121); },
|
||||
set updateMS(x) { cmd(6, x); },
|
||||
set physMS(x) { cmd(7, x); },
|
||||
set renderMS(x) { cmd(5, x); },
|
||||
|
||||
get time() { return cmd(133); },
|
||||
|
||||
seconds_to_timecode(secs, fps)
|
||||
{
|
||||
var s = Math.trunc(secs);
|
||||
secs -= s;
|
||||
var f = Math.trunc(fps * secs);
|
||||
return `${s}:${f}`;
|
||||
},
|
||||
|
||||
pause() {
|
||||
Time.timescale = 0;
|
||||
},
|
||||
|
||||
play() {
|
||||
if (!Time.stash) {
|
||||
Log.warn("Tried to resume time without calling Time.pause first.");
|
||||
return;
|
||||
}
|
||||
Time.timescale = Time.stash;
|
||||
},
|
||||
};
|
||||
|
||||
Player.players[0].control(DebugControls);
|
||||
Register.gui.register(Debug.draw, Debug);
|
||||
@@ -1,150 +0,0 @@
|
||||
function deep_copy(from) {
|
||||
if (typeof from !== 'object')
|
||||
return from;
|
||||
|
||||
if (Array.isArray(from)) {
|
||||
var c = [];
|
||||
from.forEach(function(x,i) { c[i] = deep_copy(x); });
|
||||
return c;
|
||||
}
|
||||
|
||||
var obj = {};
|
||||
for (var key in from)
|
||||
obj[key] = deep_copy(from[key]);
|
||||
|
||||
return obj;
|
||||
};
|
||||
|
||||
|
||||
var walk_up_get_prop = function(obj, prop, endobj) {
|
||||
var props = [];
|
||||
var cur = obj;
|
||||
while (cur !== Object.prototype) {
|
||||
if (cur.hasOwn(prop))
|
||||
props.push(cur[prop]);
|
||||
|
||||
cur = cur.__proto__;
|
||||
}
|
||||
|
||||
return props;
|
||||
};
|
||||
|
||||
|
||||
function complete_assign(target, source) {
|
||||
var descriptors = {};
|
||||
var assigns = {};
|
||||
if (typeof source === 'undefined') return target;
|
||||
Object.keys(source).forEach(function (k) {
|
||||
var desc = Object.getOwnPropertyDescriptor(source, k);
|
||||
|
||||
if (desc.value) {
|
||||
if (typeof desc.value === 'object' && desc.value.hasOwn('value'))
|
||||
descriptors[k] = desc.value;
|
||||
else
|
||||
assigns[k] = desc.value;
|
||||
} else
|
||||
descriptors[k] = desc;
|
||||
});
|
||||
|
||||
Object.defineProperties(target, descriptors);
|
||||
Object.assign(target, assigns);
|
||||
return target;
|
||||
};
|
||||
|
||||
/* Assigns properties from source to target, only if they exist in target */
|
||||
function dainty_assign(target, source)
|
||||
{
|
||||
for (var key in source) {
|
||||
|
||||
if (typeof source[key] === 'function') {
|
||||
target[key] = source[key];
|
||||
continue;
|
||||
}
|
||||
if (!Object.hasOwn(target, key)) continue;
|
||||
if (!Object.getOwnPropertyDescriptor(target, key).writable) continue;
|
||||
|
||||
if (Array.isArray(target[key]))
|
||||
target[key] = source[key];
|
||||
else if (typeof target[key] === 'object')
|
||||
dainty_assign(target[key], source[key]);
|
||||
else {
|
||||
target[key] = source[key];
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/* Deeply remove source keys from target, not removing objects */
|
||||
function unmerge(target, source) {
|
||||
for (var key in source) {
|
||||
if (typeof source[key] === 'object' && !Array.isArray(source[key]))
|
||||
unmerge(target[key], source[key]);
|
||||
else
|
||||
delete target[key];
|
||||
}
|
||||
};
|
||||
|
||||
/* Deeply merge two objects, not clobbering objects on target with objects on source */
|
||||
function deep_merge(target, source)
|
||||
{
|
||||
Log.warn("Doing a deep merge ...");
|
||||
for (var key in source) {
|
||||
if (typeof source[key] === 'object' && !Array.isArray(source[key])) {
|
||||
Log.warn(`Deeper merge on ${key}`);
|
||||
deep_merge(target[key], source[key]);
|
||||
}
|
||||
else {
|
||||
Log.warn(`Setting key ${key}`);
|
||||
target[key] = source[key];
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
function equal(x,y) {
|
||||
if (typeof x === 'object')
|
||||
for (var key in x)
|
||||
return equal(x[key],y[key]);
|
||||
|
||||
return x === y;
|
||||
};
|
||||
|
||||
function diffassign(target, from) {
|
||||
if (from.empty) return;
|
||||
|
||||
for (var e in from) {
|
||||
if (typeof from[e] === 'object') {
|
||||
if (!target.hasOwnProperty(e))
|
||||
target[e] = from[e];
|
||||
else
|
||||
diffassign(target[e], from[e]);
|
||||
} else {
|
||||
if (from[e] === "DELETE") {
|
||||
delete target[e];
|
||||
} else {
|
||||
target[e] = from[e];
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
function diff(from, to) {
|
||||
var obj = {};
|
||||
|
||||
for (var e in to) {
|
||||
if (typeof to[e] === 'object' && from.hasOwnProperty(e)) {
|
||||
obj[e] = diff(from[e], to[e]);
|
||||
if (obj[e].empty)
|
||||
delete obj[e];
|
||||
} else {
|
||||
if (from[e] !== to[e])
|
||||
obj[e] = to[e];
|
||||
}
|
||||
}
|
||||
|
||||
for (var e in from) {
|
||||
if (!to.hasOwnProperty(e))
|
||||
obj[e] = "DELETE";
|
||||
}
|
||||
|
||||
return obj;
|
||||
};
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,631 +0,0 @@
|
||||
var files = {};
|
||||
function load(file) {
|
||||
var modtime = cmd(0, file);
|
||||
|
||||
if (modtime === 0) {
|
||||
Log.stack();
|
||||
return false;
|
||||
}
|
||||
files[file] = modtime;
|
||||
}
|
||||
|
||||
load("scripts/std.js");
|
||||
|
||||
function initialize()
|
||||
{
|
||||
if (!Game.edit)
|
||||
run("scripts/play.js");
|
||||
else
|
||||
run("scripts/editor.js");
|
||||
}
|
||||
|
||||
function run(file)
|
||||
{
|
||||
var modtime = cmd(119, file);
|
||||
if (modtime === 0) {
|
||||
Log.stack();
|
||||
return false;
|
||||
}
|
||||
|
||||
files[file] = modtime;
|
||||
return cmd(117, file);
|
||||
}
|
||||
|
||||
|
||||
load("scripts/base.js");
|
||||
|
||||
load("scripts/diff.js");
|
||||
Log.level = 1;
|
||||
|
||||
var Color = {
|
||||
white: [255,255,255,255],
|
||||
black: [0,0,0,255],
|
||||
blue: [84,110,255,255],
|
||||
green: [120,255,10,255],
|
||||
yellow: [251,255,43,255],
|
||||
red: [255,36,20,255],
|
||||
teal: [96, 252, 237,255],
|
||||
gray: [181, 181,181,255],
|
||||
cyan: [0,255,255],
|
||||
};
|
||||
|
||||
function bb2wh(bb) {
|
||||
return [bb.r-bb.l, bb.t-bb.b];
|
||||
};
|
||||
|
||||
load("scripts/gui.js");
|
||||
|
||||
var timer = {
|
||||
make(fn, secs,obj,loop,app) {
|
||||
app ??= false;
|
||||
if (secs === 0) {
|
||||
fn.call(obj);
|
||||
return;
|
||||
}
|
||||
|
||||
var t = clone(this);
|
||||
t.callback = fn;
|
||||
var guardfn = function() {
|
||||
if (typeof t.callback === 'function')
|
||||
t.callback();
|
||||
else
|
||||
Log.warn("Timer trying to execute without a function.");
|
||||
};
|
||||
t.id = make_timer(guardfn, secs, app);
|
||||
|
||||
return t;
|
||||
},
|
||||
|
||||
oneshot(fn, secs,obj, app) {
|
||||
app ??= false;
|
||||
var t = this.make(fn, secs, obj, 0, app);
|
||||
t.start();
|
||||
},
|
||||
|
||||
get remain() { return cmd(32, this.id); },
|
||||
get on() { return cmd(33, this.id); },
|
||||
get loop() { return cmd(34, this.id); },
|
||||
set loop(x) { cmd(35, this.id, x); },
|
||||
|
||||
start() { cmd(26, this.id); },
|
||||
stop() { cmd(25, this.id); },
|
||||
pause() { cmd(24, this.id); },
|
||||
kill() { cmd(27, this.id); },
|
||||
set time(x) { cmd(28, this.id, x); },
|
||||
get time() { return cmd(29, this.id); },
|
||||
get pct() { return this.remain / this.time; },
|
||||
};
|
||||
|
||||
var animation = {
|
||||
time: 0,
|
||||
loop: false,
|
||||
playtime: 0,
|
||||
playing: false,
|
||||
keyframes: [],
|
||||
|
||||
create() {
|
||||
var anim = Object.create(animation);
|
||||
Register.update.register(anim.update, anim);
|
||||
return anim;
|
||||
},
|
||||
|
||||
start() {
|
||||
this.playing = true;
|
||||
this.time = this.keyframes.last[1];
|
||||
this.playtime = 0;
|
||||
},
|
||||
|
||||
interval(a, b, t) {
|
||||
return (t - a) / (b - a);
|
||||
},
|
||||
|
||||
near_val(t) {
|
||||
for (var i = 0; i < this.keyframes.length-1; i++) {
|
||||
if (t > this.keyframes[i+1][1]) continue;
|
||||
|
||||
return this.interval(this.keyframes[i][1], this.keyframes[i+1][1], t) >= 0.5 ? this.keyframes[i+1][0] : this.keyframes[i][0];
|
||||
}
|
||||
|
||||
return this.keyframes.last[0];
|
||||
},
|
||||
|
||||
lerp_val(t) {
|
||||
for (var i = 0; i < this.keyframes.length-1; i++) {
|
||||
if (t > this.keyframes[i+1][1]) continue;
|
||||
|
||||
var intv = this.interval(this.keyframes[i][1], this.keyframes[i+1][1], t);
|
||||
return ((1 - intv) * this.keyframes[i][0]) + (intv * this.keyframes[i+1][0]);
|
||||
}
|
||||
|
||||
return this.keyframes.last[0];
|
||||
},
|
||||
|
||||
cubic_val(t) {
|
||||
|
||||
},
|
||||
|
||||
mirror() {
|
||||
if (this.keyframes.length <= 1) return;
|
||||
for (var i = this.keyframes.length-1; i >= 1; i--) {
|
||||
this.keyframes.push(this.keyframes[i-1]);
|
||||
this.keyframes.last[1] = this.keyframes[i][1] + (this.keyframes[i][1] - this.keyframes[i-1][1]);
|
||||
}
|
||||
},
|
||||
|
||||
update(dt) {
|
||||
if (!this.playing) return;
|
||||
|
||||
this.playtime += dt;
|
||||
if (this.playtime >= this.time) {
|
||||
if (this.loop)
|
||||
this.playtime = 0;
|
||||
else {
|
||||
this.playing = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
this.fn(this.lerp_val(this.playtime));
|
||||
},
|
||||
};
|
||||
|
||||
var Render = {
|
||||
normal() {
|
||||
cmd(67);
|
||||
},
|
||||
|
||||
wireframe() {
|
||||
cmd(68);
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
load("scripts/physics.js");
|
||||
load("scripts/input.js");
|
||||
load("scripts/sound.js");
|
||||
|
||||
function screen2world(screenpos) { return Game.camera.view2world(screenpos); }
|
||||
function world2screen(worldpos) { return Game.camera.world2view(worldpos); }
|
||||
|
||||
var Register = {
|
||||
inloop: false,
|
||||
loopcbs: [],
|
||||
finloop() {
|
||||
this.loopcbs.forEach(x => x());
|
||||
this.loopcbs = [];
|
||||
},
|
||||
|
||||
wraploop(loop) {
|
||||
this.inloop = true;
|
||||
loop();
|
||||
this.inloop = false;
|
||||
this.finloop();
|
||||
},
|
||||
|
||||
kbm_input(mode, btn, state, ...args) {
|
||||
if (state === 'released') {
|
||||
btn = btn.split('-').last;
|
||||
}
|
||||
|
||||
switch(mode) {
|
||||
case "emacs":
|
||||
Player.players[0].raw_input(btn, state, ...args);
|
||||
break;
|
||||
|
||||
case "mouse":
|
||||
Player.players[0].mouse_input(btn, state, ...args);
|
||||
break;
|
||||
|
||||
case "char":
|
||||
Player.players[0].char_input(btn);
|
||||
break;
|
||||
};
|
||||
},
|
||||
|
||||
gamepad_playermap: [],
|
||||
gamepad_input(pad, btn, state, ...args) {
|
||||
var player = this.gamepad_playermap[pad];
|
||||
if (!player) return;
|
||||
|
||||
var statestr = Input.state2str(state);
|
||||
|
||||
var rawfn = `gamepad_${btn}_${statestr}`;
|
||||
player.input(rawfn, ...args);
|
||||
|
||||
Action.actions.forEach(x => {
|
||||
if (x.inputs.includes(btn))
|
||||
player.input(`action_${x.name}_${statestr}`, ...args);
|
||||
});
|
||||
},
|
||||
|
||||
unregister_obj(obj) {
|
||||
Register.registries.forEach(function(x) {
|
||||
x.unregister_obj(obj);
|
||||
});
|
||||
Player.uncontrol(obj);
|
||||
},
|
||||
|
||||
endofloop(fn) {
|
||||
if (!this.inloop)
|
||||
fn();
|
||||
else {
|
||||
this.loopcbs.push(fn);
|
||||
}
|
||||
},
|
||||
|
||||
clear() {
|
||||
Register.registries.forEach(function(n) {
|
||||
n.entries = [];
|
||||
});
|
||||
},
|
||||
|
||||
registries: [],
|
||||
|
||||
add_cb(idx, name) {
|
||||
var entries = [];
|
||||
var n = {};
|
||||
n.register = function(fn, obj) {
|
||||
if (!obj) {
|
||||
Log.error("Refusing to register a function without a destroying object.");
|
||||
return;
|
||||
}
|
||||
entries.push({
|
||||
fn: fn,
|
||||
obj: obj
|
||||
});
|
||||
}
|
||||
|
||||
n.unregister = function(fn) {
|
||||
entries = entries.filter(function(e) { return e.fn !== f; });
|
||||
}
|
||||
|
||||
n.unregister_obj = function(obj) {
|
||||
entries = entries.filter(function(e) { return e.obj !== obj; });
|
||||
}
|
||||
|
||||
n.broadcast = function(...args) {
|
||||
entries.forEach(x => x.fn.call(x.obj, ...args));
|
||||
}
|
||||
|
||||
n.clear = function() {
|
||||
entries = [];
|
||||
}
|
||||
|
||||
register(idx, n.broadcast, n);
|
||||
|
||||
Register[name] = n;
|
||||
Register.registries.push(n);
|
||||
|
||||
return n;
|
||||
},
|
||||
};
|
||||
|
||||
Register.add_cb(0, "update").doc = "Called once per frame.";
|
||||
Register.add_cb(1, "physupdate");
|
||||
Register.add_cb(2, "gui");
|
||||
Register.add_cb(3, "nk_gui");
|
||||
Register.add_cb(6, "debug");
|
||||
register(7, Register.kbm_input, Register);
|
||||
Register.add_cb(8, "gamepad_input");
|
||||
Register.add_cb(10, "draw");
|
||||
|
||||
register(9, Log.stack, this);
|
||||
|
||||
Register.gamepad_playermap[0] = Player.players[0];
|
||||
|
||||
|
||||
|
||||
Player.players[0].control(GUI);
|
||||
|
||||
var Signal = {
|
||||
signals: [],
|
||||
obj_begin(fn, obj, go) {
|
||||
this.signals.push([fn, obj]);
|
||||
register_collide(0, fn, obj, go.body);
|
||||
},
|
||||
|
||||
obj_separate(fn, obj, go) {
|
||||
this.signals.push([fn,obj]);
|
||||
register_collide(3,fn,obj,go.body);
|
||||
},
|
||||
|
||||
clera_obj(obj) {
|
||||
this.signals.filter(function(x) { return x[1] !== obj; });
|
||||
},
|
||||
|
||||
c:{},
|
||||
register(name, fn) {
|
||||
if (!this.c[name])
|
||||
this.c[name] = [];
|
||||
|
||||
this.c[name].push(fn);
|
||||
},
|
||||
|
||||
call(name, ...args) {
|
||||
if (this.c[name])
|
||||
this.c[name].forEach(function(fn) { fn.call(this, ...args); });
|
||||
},
|
||||
};
|
||||
|
||||
var Window = {
|
||||
set width(w) { cmd(125, w); },
|
||||
set height(h) { cmd(126, h); },
|
||||
get width() { return cmd(48); },
|
||||
get height() { return cmd(49); },
|
||||
get dimensions() { return [this.width, this.height]; },
|
||||
set name(str) { cmd(134, str); },
|
||||
};
|
||||
|
||||
Window.icon = function(path) { cmd(90, path); };
|
||||
Window.icon.doc = "Set the icon of the window using the PNG image at path.";
|
||||
|
||||
|
||||
function reloadfiles() {
|
||||
Object.keys(files).forEach(function (x) { load(x); });
|
||||
}
|
||||
|
||||
load("scripts/debug.js");
|
||||
|
||||
/*
|
||||
function Color(from) {
|
||||
var color = Object.create(Array);
|
||||
Object.defineProperty(color, 'r', setelem(0));
|
||||
Object.defineProperty(color, 'g', setelem(1));
|
||||
Object.defineProperty(color, 'b', setelem(2));
|
||||
Object.defineProperty(color, 'a', setelem(3));
|
||||
|
||||
color.a = color.g = color.b = color.a = 1;
|
||||
Object.assign(color, from);
|
||||
|
||||
return color;
|
||||
};
|
||||
*/
|
||||
|
||||
load("scripts/components.js");
|
||||
|
||||
function replacer_empty_nil(key, val) {
|
||||
if (typeof val === 'object' && JSON.stringify(val) === '{}')
|
||||
return undefined;
|
||||
|
||||
// if (typeof val === 'number')
|
||||
// return parseFloat(val.toFixed(4));
|
||||
|
||||
return val;
|
||||
};
|
||||
|
||||
function clean_object(obj) {
|
||||
Object.keys(obj).forEach(function(x) {
|
||||
if (!(x in obj.__proto__)) return;
|
||||
|
||||
switch(typeof obj[x]) {
|
||||
case 'object':
|
||||
if (Array.isArray(obj[x])) {
|
||||
if (obj[x].equal(obj.__proto__[x])) {
|
||||
delete obj[x];
|
||||
}
|
||||
} else
|
||||
clean_object(obj[x]);
|
||||
|
||||
break;
|
||||
|
||||
case 'function':
|
||||
return;
|
||||
|
||||
default:
|
||||
if (obj[x] === obj.__proto__[x])
|
||||
delete obj[x];
|
||||
break;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
function find_com(objects)
|
||||
{
|
||||
if (!objects || objects.length === 0)
|
||||
return [0,0];
|
||||
var com = [0,0];
|
||||
com[0] = objects.reduce(function(acc, val) {
|
||||
return acc + val.pos[0];
|
||||
}, 0);
|
||||
com[0] /= objects.length;
|
||||
|
||||
com[1] = objects.reduce(function(acc, val) {
|
||||
return acc + val.pos[1];
|
||||
}, 0);
|
||||
com[1] /= objects.length;
|
||||
|
||||
return com;
|
||||
};
|
||||
|
||||
var Game = {
|
||||
objects: [],
|
||||
resolution: [1200,720],
|
||||
name: "Untitled",
|
||||
edit: true,
|
||||
register_obj(obj) {
|
||||
this.objects[obj.body] = obj;
|
||||
},
|
||||
|
||||
/* Returns an object given an id */
|
||||
object(id) {
|
||||
return this.objects[id];
|
||||
},
|
||||
|
||||
/* Returns a list of objects by name */
|
||||
find(name) {
|
||||
|
||||
},
|
||||
|
||||
/* Return a list of objects derived from a specific prototype */
|
||||
find_proto(proto) {
|
||||
|
||||
},
|
||||
|
||||
/* List of all objects spawned that have a specific tag */
|
||||
find_tag(tag) {
|
||||
|
||||
},
|
||||
|
||||
groupify(objects, spec) {
|
||||
var newgroup = {
|
||||
locked: true,
|
||||
breakable: true,
|
||||
objs: objects,
|
||||
// get pos() { return find_com(objects); },
|
||||
// set pos(x) { this.objs.forEach(function(obj) { obj.pos = x; }) },
|
||||
};
|
||||
|
||||
Object.assign(newgroup, spec);
|
||||
objects.forEach(function(x) {
|
||||
x.defn('group', newgroup);
|
||||
});
|
||||
|
||||
var bb = bb_from_objects(newgroup.objs);
|
||||
newgroup.startbb = bb2cwh(bb);
|
||||
newgroup.bboffset = newgroup.startbb.c.sub(newgroup.objs[0].pos);
|
||||
|
||||
newgroup.boundingbox = function() {
|
||||
newgroup.startbb.c = newgroup.objs[0].pos.add(newgroup.bboffset);
|
||||
return cwh2bb(newgroup.startbb.c, newgroup.startbb.wh);
|
||||
};
|
||||
|
||||
if (newgroup.file)
|
||||
newgroup.color = [120,255,10];
|
||||
|
||||
return newgroup;
|
||||
},
|
||||
|
||||
quit()
|
||||
{
|
||||
sys_cmd(0);
|
||||
},
|
||||
|
||||
pause()
|
||||
{
|
||||
sys_cmd(3);
|
||||
},
|
||||
|
||||
stop()
|
||||
{
|
||||
Game.pause();
|
||||
/* And return to editor .. */
|
||||
Log.warn("Stopping not implemented. Paused, and go to editor.");
|
||||
},
|
||||
|
||||
step()
|
||||
{
|
||||
sys_cmd(4);
|
||||
},
|
||||
|
||||
render() { sys_cmd(10); },
|
||||
|
||||
playing() { return sys_cmd(5); },
|
||||
paused() { return sys_cmd(6); },
|
||||
stepping() {
|
||||
return cmd(79); },
|
||||
|
||||
play()
|
||||
{
|
||||
sys_cmd(1);
|
||||
},
|
||||
|
||||
get dt() {
|
||||
return cmd(63);
|
||||
},
|
||||
|
||||
wait_fns: [],
|
||||
|
||||
wait_exec(fn) {
|
||||
if (!phys_stepping())
|
||||
fn();
|
||||
else
|
||||
this.wait_fns.push(fn);
|
||||
},
|
||||
|
||||
exec() {
|
||||
this.wait_fns.forEach(function(x) { x(); });
|
||||
|
||||
this.wait_fns = [];
|
||||
},
|
||||
};
|
||||
|
||||
Register.update.register(Game.exec, Game);
|
||||
|
||||
//load("scripts/level.js");
|
||||
|
||||
load("scripts/entity.js");
|
||||
|
||||
var World = Object.create(gameobject);
|
||||
var Primum = World;
|
||||
gameobject.make_parentable(Primum);
|
||||
Primum.tag = "PRIMUM";
|
||||
Primum.selectable = false;
|
||||
Primum.ur = { tag: "Primum" };
|
||||
/* Reparent this object to a new one */
|
||||
World.reparent = function(parent) { Log.warn("Cannot reparent the Primum."); }
|
||||
World.unparent = function() { Log.warn("The Primum has no parent, always."); }
|
||||
World.fullpath = function() { return World.name; };
|
||||
|
||||
/* Load configs */
|
||||
function load_configs(file) {
|
||||
Log.info(`Loading config file ${file}.`);
|
||||
var configs = JSON.parse(IO.slurp(file));
|
||||
for (var key in configs) {
|
||||
if (typeof globalThis[key] !== "object") continue;
|
||||
Object.assign(globalThis[key], configs[key]);
|
||||
}
|
||||
|
||||
Collision.sync();
|
||||
Game.objects.forEach(function(x) { x.sync(); });
|
||||
|
||||
if (!local_conf.mouse) {
|
||||
Log.info("disabling mouse features");
|
||||
Mouse.disabled = function() {};
|
||||
Mouse.hidden = function() {};
|
||||
};
|
||||
};
|
||||
|
||||
var local_conf = {
|
||||
mouse: true,
|
||||
};
|
||||
|
||||
if (IO.exists("game.config"))
|
||||
load_configs("game.config");
|
||||
|
||||
/* Save configs */
|
||||
function save_configs() {
|
||||
Log.info("saving configs");
|
||||
var configs = {};
|
||||
configs.editor_config = editor_config;
|
||||
configs.Nuke = Nuke;
|
||||
configs.local_conf = local_conf;
|
||||
IO.slurpwrite(JSON.stringify(configs, null, 1), "editor.config");
|
||||
|
||||
save_game_configs();
|
||||
};
|
||||
|
||||
function save_game_configs() {
|
||||
var configs = {};
|
||||
configs.physics = physics;
|
||||
configs.Collision = Collision;
|
||||
Log.info(configs);
|
||||
IO.slurpwrite(JSON.stringify(configs,null,1), "game.config");
|
||||
|
||||
Collision.sync();
|
||||
Game.objects.forEach(function(x) { x.sync(); });
|
||||
};
|
||||
|
||||
load("scripts/physics.js");
|
||||
|
||||
|
||||
Game.view_camera = function(cam)
|
||||
{
|
||||
Game.camera = cam;
|
||||
cmd(61, Game.camera.body);
|
||||
}
|
||||
|
||||
Game.view_camera(Primum.spawn(ur.camera2d));
|
||||
|
||||
Window.name = "Primum Machinam (V0.1)";
|
||||
Window.width = 1280;
|
||||
Window.height = 720;
|
||||
@@ -1,576 +0,0 @@
|
||||
function grab_from_points(pos, points, slop) {
|
||||
var shortest = slop;
|
||||
var idx = -1;
|
||||
points.forEach(function(x,i) {
|
||||
if (Vector.length(pos.sub(x)) < shortest) {
|
||||
shortest = Vector.length(pos.sub(x));
|
||||
idx = i;
|
||||
}
|
||||
});
|
||||
return idx;
|
||||
};
|
||||
|
||||
var gameobject = {
|
||||
scale: 1.0,
|
||||
save: true,
|
||||
selectable: true,
|
||||
|
||||
spawn(ur) {
|
||||
if (typeof ur === 'string')
|
||||
ur = prototypes.get_ur(ur);
|
||||
|
||||
return ur.type.make(this);
|
||||
},
|
||||
|
||||
clone(name, ext) {
|
||||
var obj = Object.create(this);
|
||||
complete_assign(obj, ext);
|
||||
return obj;
|
||||
},
|
||||
|
||||
layer: 0, /* Collision layer; should probably have been called "mask" */
|
||||
layer_nuke() {
|
||||
Nuke.label("Collision layer");
|
||||
Nuke.newline(Collision.num);
|
||||
for (var i = 0; i < Collision.num; i++)
|
||||
this.layer = Nuke.radio(i, this.layer, i);
|
||||
},
|
||||
|
||||
draw_layer: 1,
|
||||
draw_layer_nuke() {
|
||||
Nuke.label("Draw layer");
|
||||
Nuke.newline(5);
|
||||
for (var i = 0; i < 5; i++)
|
||||
this.draw_layer = Nuke.radio(i, this.draw_layer, i);
|
||||
},
|
||||
|
||||
ed_locked: false,
|
||||
|
||||
_visible: true,
|
||||
get visible(){ return this._visible; },
|
||||
set visible(x) {
|
||||
this._visible = x;
|
||||
for (var key in this.components) {
|
||||
if ('visible' in this.components[key]) {
|
||||
this.components[key].visible = x;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
mass: 1,
|
||||
|
||||
phys: 2,
|
||||
phys_nuke() {
|
||||
Nuke.newline(1);
|
||||
Nuke.label("phys");
|
||||
Nuke.newline(3);
|
||||
this.phys = Nuke.radio("dynamic", this.phys, 0);
|
||||
this.phys = Nuke.radio("kinematic", this.phys, 1);
|
||||
this.phys = Nuke.radio("static", this.phys, 2);
|
||||
},
|
||||
friction: 0,
|
||||
elasticity: 0,
|
||||
flipx: false,
|
||||
flipy: false,
|
||||
|
||||
set_center(pos) {
|
||||
var change = pos.sub(this.pos);
|
||||
this.pos = pos;
|
||||
|
||||
for (var key in this.components) {
|
||||
this.components[key].finish_center(change);
|
||||
}
|
||||
},
|
||||
|
||||
varname: "",
|
||||
|
||||
pos: [0,0],
|
||||
|
||||
set relpos(x) {
|
||||
if (!this.level) {
|
||||
this.pos = x;
|
||||
return;
|
||||
}
|
||||
|
||||
this.pos = Vector.rotate(x, Math.deg2rad(this.level.angle)).add(this.level.pos);
|
||||
},
|
||||
|
||||
get relpos() {
|
||||
if (!this.level) return this.pos;
|
||||
|
||||
var offset = this.pos.sub(this.level.pos);
|
||||
return Vector.rotate(offset, -Math.deg2rad(this.level.angle));
|
||||
},
|
||||
|
||||
angle: 0,
|
||||
get relangle() {
|
||||
if (!this.level) return this.angle;
|
||||
return this.angle - this.level.angle;
|
||||
},
|
||||
|
||||
velocity: [0,0],
|
||||
angularvelocity: 0,
|
||||
|
||||
gizmo: "", /* Path to an image to draw for this gameobject */
|
||||
|
||||
/* Bounding box of the object in world dimensions */
|
||||
boundingbox() {
|
||||
var boxes = [];
|
||||
boxes.push({t:0, r:0,b:0,l:0});
|
||||
|
||||
for (var key in this.components) {
|
||||
if ('boundingbox' in this.components[key])
|
||||
boxes.push(this.components[key].boundingbox());
|
||||
}
|
||||
|
||||
if (boxes.empty) return cwh2bb([0,0], [0,0]);
|
||||
|
||||
var bb = boxes[0];
|
||||
|
||||
boxes.forEach(function(x) {
|
||||
bb = bb_expand(bb, x);
|
||||
});
|
||||
|
||||
var cwh = bb2cwh(bb);
|
||||
|
||||
if (!bb) return;
|
||||
|
||||
if (this.flipx) cwh.c.x *= -1;
|
||||
if (this.flipy) cwh.c.y *= -1;
|
||||
|
||||
cwh.c = cwh.c.add(this.pos);
|
||||
bb = cwh2bb(cwh.c, cwh.wh);
|
||||
|
||||
return bb ? bb : cwh2bb([0,0], [0,0]);
|
||||
},
|
||||
|
||||
width() {
|
||||
var bb = this.boundingbox();
|
||||
return bb.r - bb.l;
|
||||
},
|
||||
|
||||
height() {
|
||||
var bb = this.boundingbox();
|
||||
return bb.t-bb.b;
|
||||
},
|
||||
|
||||
stop() {},
|
||||
|
||||
/* Make a unique object the same as its prototype */
|
||||
revert() {
|
||||
// unmerge(this, this.prop_obj());
|
||||
},
|
||||
|
||||
gui() {
|
||||
var go_guis = walk_up_get_prop(this, 'go_gui');
|
||||
Nuke.newline();
|
||||
|
||||
go_guis.forEach(function(x) { x.call(this); }, this);
|
||||
|
||||
for (var key in this) {
|
||||
if (typeof this[key] === 'object' && 'gui' in this[key]) this[key].gui();
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
check_registers(obj) {
|
||||
Register.unregister_obj(this);
|
||||
|
||||
if (typeof obj.update === 'function')
|
||||
Register.update.register(obj.update, obj);
|
||||
|
||||
if (typeof obj.physupdate === 'function')
|
||||
Register.physupdate.register(obj.physupdate, obj);
|
||||
|
||||
if (typeof obj.collide === 'function')
|
||||
obj.register_hit(obj.collide, obj);
|
||||
|
||||
if (typeof obj.separate === 'function')
|
||||
obj.register_separate(obj.separate, obj);
|
||||
|
||||
if (typeof obj.draw === 'function')
|
||||
Register.draw.register(obj.draw,obj);
|
||||
|
||||
if (typeof obj.debug === 'function')
|
||||
Register.debug.register(obj.debug, obj);
|
||||
|
||||
obj.components.forEach(function(x) {
|
||||
if (typeof x.collide === 'function')
|
||||
register_collide(1, x.collide, x, obj.body, x.shape);
|
||||
});
|
||||
},
|
||||
instances: [],
|
||||
|
||||
make(level) {
|
||||
level ??= Primum;
|
||||
var obj = Object.create(this);
|
||||
this.instances.push(obj);
|
||||
obj.toString = function() {
|
||||
if (obj.ur)
|
||||
return obj.ur.tag;
|
||||
|
||||
return "NO UR"};
|
||||
|
||||
obj.defn('body', make_gameobject(this.scale,
|
||||
this.phys,
|
||||
this.mass,
|
||||
this.friction,
|
||||
this.elasticity) );
|
||||
|
||||
obj.defn('components', {});
|
||||
|
||||
Game.register_obj(obj);
|
||||
|
||||
cmd(113, obj.body, obj);
|
||||
|
||||
/* Now that it's concrete in the engine, these functions update to return engine data */
|
||||
complete_assign(obj, {
|
||||
set scale(x) { cmd(36, this.body, x); },
|
||||
get scale() { return cmd(103, this.body); },
|
||||
get flipx() { return cmd(104,this.body); },
|
||||
set flipx(x) { cmd(55, this.body, x); },
|
||||
get flipy() { return cmd(105,this.body); },
|
||||
set flipy(x) { cmd(56, this.body, x); },
|
||||
|
||||
get angle() { return Math.rad2deg(q_body(2,this.body))%360; },
|
||||
set angle(x) { set_body(0,this.body, Math.deg2rad(x)); },
|
||||
|
||||
set pos(x) {
|
||||
var diff = x.sub(this.pos);
|
||||
this.objects.forEach(function(x) { x.pos = x.pos.add(diff); });
|
||||
set_body(2,this.body,x); },
|
||||
get pos() { return q_body(1,this.body); },
|
||||
|
||||
get elasticity() { return cmd(107,this.body); },
|
||||
set elasticity(x) { cmd(106,this.body,x); },
|
||||
|
||||
get friction() { return cmd(109,this.body); },
|
||||
set friction(x) { cmd(108,this.body,x); },
|
||||
|
||||
set mass(x) { set_body(7,this.body,x); },
|
||||
get mass() { return q_body(5, this.body); },
|
||||
|
||||
set phys(x) { set_body(1, this.body, x); },
|
||||
get phys() { return q_body(0,this.body); },
|
||||
get velocity() { return q_body(3, this.body); },
|
||||
set velocity(x) { set_body(9, this.body, x); },
|
||||
get angularvelocity() { return Math.rad2deg(q_body(4, this.body)); },
|
||||
set angularvelocity(x) { set_body(8, this.body, Math.deg2rad(x)); },
|
||||
pulse(vec) { set_body(4, this.body, vec);},
|
||||
|
||||
push(vec) { set_body(12,this.body,vec);},
|
||||
world2this(pos) { return cmd(70, this.body, pos); },
|
||||
this2world(pos) { return cmd(71, this.body,pos); },
|
||||
set layer(x) { cmd(75,this.body,x); },
|
||||
get layer() { return 0; },
|
||||
alive() { return this.body >= 0; },
|
||||
in_air() { return q_body(7, this.body);},
|
||||
on_ground() { return !this.in_air(); },
|
||||
|
||||
disable() { this.components.forEach(function(x) { x.disable(); });},
|
||||
enable() { this.components.forEach(function(x) { x.enable(); });},
|
||||
sync() { },
|
||||
dirty() { return false; },
|
||||
|
||||
dup(diff) {
|
||||
var dup = Primum.spawn(this.ur);
|
||||
Object.assign(dup, this);
|
||||
return dup;
|
||||
},
|
||||
|
||||
kill() {
|
||||
if (this.body === -1) {
|
||||
Log.warn(`Object is already dead!`);
|
||||
return;
|
||||
}
|
||||
|
||||
Register.endofloop(() => {
|
||||
cmd(2, this.body);
|
||||
delete Game.objects[this.body];
|
||||
|
||||
if (this.level)
|
||||
this.level.unregister(this);
|
||||
|
||||
Player.uncontrol(this);
|
||||
this.instances.remove(this);
|
||||
Register.unregister_obj(this);
|
||||
// Signal.clear_obj(this);
|
||||
|
||||
this.body = -1;
|
||||
for (var key in this.components) {
|
||||
Register.unregister_obj(this.components[key]);
|
||||
this.components[key].kill();
|
||||
}
|
||||
|
||||
this.objects.forEach(x => x.kill());
|
||||
|
||||
this.stop();
|
||||
});
|
||||
},
|
||||
|
||||
up() { return [0,1].rotate(Math.deg2rad(this.angle));},
|
||||
down() { return [0,-1].rotate(Math.deg2rad(this.angle));},
|
||||
right() { return [1,0].rotate(Math.deg2rad(this.angle));},
|
||||
left() { return [-1,0].rotate(Math.deg2rad(this.angle));},
|
||||
|
||||
toJSON() {
|
||||
var ret = {};
|
||||
for (var key in this) {
|
||||
var prop = Object.getOwnPropertyDescriptor(this, key);
|
||||
if (!prop) continue;
|
||||
if (prop.get) {
|
||||
if (prop.get() !== Object.getPrototypeOf(this)[key])
|
||||
ret[key] = prop.get();
|
||||
}
|
||||
else
|
||||
ret[key] = this[key];
|
||||
}
|
||||
return ret;
|
||||
},
|
||||
});
|
||||
|
||||
for (var prop in obj) {
|
||||
if (typeof obj[prop] === 'object' && 'make' in obj[prop]) {
|
||||
obj[prop] = obj[prop].make(obj.body);
|
||||
obj[prop].defn('gameobject', obj);
|
||||
obj.components[prop] = obj[prop];
|
||||
}
|
||||
};
|
||||
|
||||
obj.check_registers(obj);
|
||||
|
||||
gameobject.make_parentable(obj);
|
||||
|
||||
/* Spawn subobjects defined */
|
||||
if (obj.$) {
|
||||
for (var e in obj.$)
|
||||
obj.$[e] = obj.spawn(prototypes.get_ur(obj.$[e].ur));
|
||||
}
|
||||
|
||||
if (typeof obj.start === 'function') obj.start();
|
||||
|
||||
level.add_child(obj);
|
||||
|
||||
return obj;
|
||||
},
|
||||
|
||||
register_hit(fn, obj) {
|
||||
if (!obj)
|
||||
obj = this;
|
||||
|
||||
Signal.obj_begin(fn, obj, this);
|
||||
},
|
||||
|
||||
register_separate(fn, obj) {
|
||||
if (!obj)
|
||||
obj = this;
|
||||
|
||||
Signal.obj_separate(fn,obj,this);
|
||||
},
|
||||
}
|
||||
|
||||
gameobject.make_parentable = function(obj) {
|
||||
var objects = [];
|
||||
|
||||
obj.remove_child = function(child) {
|
||||
objects.remove(child);
|
||||
}
|
||||
|
||||
obj.add_child = function(child) {
|
||||
child.unparent();
|
||||
objects.push(child);
|
||||
child.level = obj;
|
||||
}
|
||||
|
||||
/* Reparent this object to a new one */
|
||||
obj.reparent = function(parent) {
|
||||
if (parent === obj.level)
|
||||
return;
|
||||
|
||||
parent.add_child(obj);
|
||||
obj.level = parent;
|
||||
}
|
||||
|
||||
obj.unparent = function() {
|
||||
if (!obj.level) return;
|
||||
obj.level.remove_child(obj);
|
||||
obj.parent = undefined;
|
||||
}
|
||||
obj.objects = objects;
|
||||
}
|
||||
|
||||
/* Default objects */
|
||||
var prototypes = {};
|
||||
prototypes.ur = {};
|
||||
prototypes.load_all = function()
|
||||
{
|
||||
if (IO.exists("proto.json"))
|
||||
prototypes = JSON.parse(IO.slurp("proto.json"));
|
||||
|
||||
for (var key in prototypes) {
|
||||
if (key in gameobjects)
|
||||
dainty_assign(gameobjects[key], prototypes[key]);
|
||||
else {
|
||||
/* Create this gameobject fresh */
|
||||
Log.info("Making new prototype: " + key + " from " + prototypes[key].from);
|
||||
var newproto = gameobjects[prototypes[key].from].clone(key);
|
||||
gameobjects[key] = newproto;
|
||||
|
||||
for (var pkey in newproto)
|
||||
if (typeof newproto[pkey] === 'object' && newproto[pkey] && 'clone' in newproto[pkey])
|
||||
newproto[pkey] = newproto[pkey].clone();
|
||||
|
||||
dainty_assign(gameobjects[key], prototypes[key]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
prototypes.save_gameobjects = function() { slurpwrite(JSON.stringify(gameobjects,null,2), "proto.json"); };
|
||||
|
||||
prototypes.from_file = function(file)
|
||||
{
|
||||
if (!IO.exists(file)) {
|
||||
Log.error(`File ${file} does not exist.`);
|
||||
return;
|
||||
}
|
||||
|
||||
var newobj = gameobject.clone(file, {});
|
||||
var script = IO.slurp(file);
|
||||
|
||||
newobj.$ = {};
|
||||
var json = {};
|
||||
if (IO.exists(file.name() + ".json")) {
|
||||
json = JSON.parse(IO.slurp(file.name() + ".json"));
|
||||
Object.assign(newobj.$, json.$);
|
||||
delete json.$;
|
||||
}
|
||||
|
||||
compile_env(`var self = this; var $ = self.$; ${script}`, newobj, file);
|
||||
dainty_assign(newobj, json);
|
||||
|
||||
file = file.replaceAll('/', '.');
|
||||
var path = file.name().split('.');
|
||||
var nested_access = function(base, names) {
|
||||
for (var i = 0; i < names.length; i++)
|
||||
base = base[names[i]] = base[names[i]] || {};
|
||||
|
||||
return base;
|
||||
};
|
||||
var a = nested_access(ur, path);
|
||||
|
||||
a.tag = file.name();
|
||||
prototypes.list.push(a.tag);
|
||||
a.type = newobj;
|
||||
a.instances = [];
|
||||
newobj.ur = a;
|
||||
|
||||
return a;
|
||||
}
|
||||
prototypes.from_file.doc = "Create a new ur-type from a given script file.";
|
||||
prototypes.list = [];
|
||||
|
||||
prototypes.from_obj = function(name, obj)
|
||||
{
|
||||
var newobj = gameobject.clone(name, obj);
|
||||
prototypes.ur[name] = {
|
||||
tag: name,
|
||||
type: newobj
|
||||
};
|
||||
newobj.ur = prototypes.ur[name];
|
||||
return prototypes.ur[name];
|
||||
}
|
||||
|
||||
prototypes.load_config = function(name)
|
||||
{
|
||||
if (!prototypes.ur[name])
|
||||
prototypes.ur[name] = gameobject.clone(name);
|
||||
|
||||
Log.warn(`Made new ur of name ${name}`);
|
||||
|
||||
return prototypes.ur[name];
|
||||
}
|
||||
|
||||
|
||||
prototypes.list_ur = function()
|
||||
{
|
||||
var list = [];
|
||||
function list_obj(obj, prefix)
|
||||
{
|
||||
prefix ??= "";
|
||||
var list = [];
|
||||
for (var e in obj) {
|
||||
list.push(prefix + e);
|
||||
Log.warn("Descending into " + e);
|
||||
list.concat(list_obj(obj[e], e + "."));
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
return list_obj(ur);
|
||||
}
|
||||
|
||||
prototypes.get_ur = function(name)
|
||||
{
|
||||
if (!prototypes.ur[name]) {
|
||||
if (IO.exists(name + ".js"))
|
||||
prototypes.from_file(name + ".js");
|
||||
|
||||
prototypes.load_config(name);
|
||||
return prototypes.ur[name];
|
||||
} else
|
||||
return prototypes.ur[name];
|
||||
}
|
||||
|
||||
prototypes.from_obj("polygon2d", {
|
||||
polygon2d: polygon2d.clone(),
|
||||
});
|
||||
|
||||
prototypes.from_obj("edge2d", {
|
||||
edge2d: bucket.clone(),
|
||||
});
|
||||
|
||||
prototypes.from_obj("sprite", {
|
||||
sprite: sprite.clone(),
|
||||
});
|
||||
|
||||
prototypes.generate_ur = function(path)
|
||||
{
|
||||
var ob = IO.glob("**.js");
|
||||
ob = ob.filter(function(str) { return !str.startsWith("scripts"); });
|
||||
|
||||
ob.forEach(function(name) {
|
||||
if (name === "game.js") return;
|
||||
if (name === "play.js") return;
|
||||
|
||||
prototypes.from_file(name);
|
||||
});
|
||||
}
|
||||
|
||||
var ur = prototypes.ur;
|
||||
|
||||
prototypes.from_obj("camera2d", {
|
||||
phys: Physics.kinematic,
|
||||
speed: 300,
|
||||
|
||||
get zoom() { return cmd(135); },
|
||||
set zoom(x) {
|
||||
x = Math.clamp(x,0.1,10);
|
||||
cmd(62, x);
|
||||
},
|
||||
|
||||
speedmult: 1.0,
|
||||
|
||||
selectable: false,
|
||||
|
||||
view2world(pos) {
|
||||
pos.y *= -1;
|
||||
return pos.add([-Window.width,Window.height].scale(0.5)).scale(this.zoom).add(this.pos);
|
||||
},
|
||||
|
||||
world2view(pos) {
|
||||
return pos.sub(this.pos).scale(1/this.zoom).add(Window.dimensions.scale(0.5));
|
||||
},
|
||||
});
|
||||
|
||||
prototypes.from_obj("arena", {});
|
||||
@@ -1,392 +0,0 @@
|
||||
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) {
|
||||
var wh = cmd(64,path);
|
||||
gui_img(path,pos, [1.0,1.0], 0.0, 0.0, [0.0,0.0], 0.0, Color.black);
|
||||
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;
|
||||
},
|
||||
};
|
||||
@@ -1,190 +0,0 @@
|
||||
var Input = {
|
||||
setgame() { cmd(77); },
|
||||
setnuke() { cmd(78); },
|
||||
};
|
||||
|
||||
var Mouse = {
|
||||
get pos() {
|
||||
return cmd(45);
|
||||
},
|
||||
|
||||
get screenpos() {
|
||||
var p = this.pos;
|
||||
p.y = Window.dimensions.y - p.y;
|
||||
return p;
|
||||
},
|
||||
|
||||
get worldpos() {
|
||||
return screen2world(cmd(45));
|
||||
},
|
||||
|
||||
disabled() {
|
||||
cmd(46, 1);
|
||||
},
|
||||
|
||||
hidden() {
|
||||
cmd(46, 1);
|
||||
},
|
||||
|
||||
normal() {
|
||||
cmd(46, 0);
|
||||
},
|
||||
};
|
||||
|
||||
var Keys = {
|
||||
shift() {
|
||||
return cmd(50, 340);// || cmd(50, 344);
|
||||
},
|
||||
|
||||
ctrl() {
|
||||
return cmd(50, 341);// || cmd(50, 344);
|
||||
},
|
||||
|
||||
alt() {
|
||||
return cmd(50, 342);// || cmd(50, 346);
|
||||
},
|
||||
|
||||
super() {
|
||||
return cmd(50, 343);// || cmd(50, 347);
|
||||
},
|
||||
};
|
||||
|
||||
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));
|
||||
},
|
||||
|
||||
mouse_input(type, ...args) {
|
||||
for (var pawn of this.pawns.reverse()) {
|
||||
if (typeof pawn.inputs?.mouse?.[type] === 'function') {
|
||||
pawn.inputs.mouse[type].call(pawn,...args);
|
||||
pawn.inputs.post?.call(pawn);
|
||||
return;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
char_input(c) {
|
||||
for (var pawn of this.pawns.reverse()) {
|
||||
if (typeof pawn.inputs?.char === 'function') {
|
||||
pawn.inputs.char.call(pawn, c);
|
||||
pawn.inputs.post?.call(pawn);
|
||||
return;
|
||||
}
|
||||
};
|
||||
},
|
||||
|
||||
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);
|
||||
pawn.inputs.post?.call(pawn);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
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();
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
function nogamegui()
|
||||
{
|
||||
GUI.column({
|
||||
items: [
|
||||
GUI.text_fn("NO GAME LOADED", {font_size: 6}),
|
||||
GUI.text_fn("No game.js available.")
|
||||
],
|
||||
anchor: [0.5,0.5],
|
||||
|
||||
}).draw(Window.dimensions.scale(0.5));
|
||||
}
|
||||
|
||||
Register.gui.register(nogamegui);
|
||||
|
||||
@@ -1,65 +0,0 @@
|
||||
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;
|
||||
};
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
Game.play();
|
||||
|
||||
if (!IO.exists("game.js"))
|
||||
load("scripts/nogame.js");
|
||||
else
|
||||
load("game.js");
|
||||
@@ -1,45 +0,0 @@
|
||||
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 */
|
||||
},
|
||||
};
|
||||
@@ -1,179 +0,0 @@
|
||||
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) {
|
||||
var paths = IO.ls();
|
||||
paths = paths.filter(function(str) { return str.ext() === ext; });
|
||||
return paths;
|
||||
},
|
||||
ls() { return cmd(66); },
|
||||
glob(pat) {
|
||||
var paths = IO.ls();
|
||||
pat = pat.replaceAll(/([\[\]\(\)\^\$\.\|\+])/g, "\\$1");
|
||||
pat = pat.replaceAll('**', '.*');
|
||||
pat = pat.replaceAll(/[^\.]\*/g, '[^\\/]*');
|
||||
pat = pat.replaceAll('?', '.');
|
||||
|
||||
var regex = new RegExp("^"+pat+"$", "");
|
||||
return paths.filter(str => str.match(regex));
|
||||
},
|
||||
};
|
||||
|
||||
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(" ");
|
||||
|
||||
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() { Game.edit = false; }, "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.");
|
||||
@@ -1,335 +0,0 @@
|
||||
var texteditor = clone(inputpanel, {
|
||||
title: "text editor",
|
||||
_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;
|
||||
|
||||
this._cursor = x;
|
||||
this.line = this.get_line();
|
||||
},
|
||||
|
||||
submit() {},
|
||||
|
||||
line: 0,
|
||||
killring: [],
|
||||
undos: [],
|
||||
startbuffer: "",
|
||||
|
||||
savestate() {
|
||||
this.undos.push(this.value.slice());
|
||||
},
|
||||
|
||||
popstate() {
|
||||
if (this.undos.length === 0) return;
|
||||
this.value = this.undos.pop();
|
||||
this.cursor = this.cursor;
|
||||
},
|
||||
|
||||
copy(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);
|
||||
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;
|
||||
},
|
||||
|
||||
get_line() {
|
||||
var line = 0;
|
||||
for (var i = 0; i < this.cursor; i++)
|
||||
if (this.value[i] === "\n")
|
||||
line++;
|
||||
|
||||
return line;
|
||||
},
|
||||
|
||||
start() {
|
||||
this.cursor = 0;
|
||||
this.startbuffer = this.value.slice();
|
||||
},
|
||||
|
||||
get dirty() {
|
||||
return this.startbuffer !== this.value;
|
||||
},
|
||||
|
||||
gui() {
|
||||
GUI.text_cursor(this.value, [100,700],1,this.cursor+1);
|
||||
GUI.text("C" + this.cursor + ":::L" + this.line + ":::" + (this.dirty ? "DIRTY" : "CLEAN"), [100,100], 1);
|
||||
},
|
||||
|
||||
insert_char(char) {
|
||||
this.value = this.value.slice(0,this.cursor) + char + this.value.slice(this.cursor);
|
||||
this.cursor++;
|
||||
},
|
||||
|
||||
input_enter_pressrep() {
|
||||
var white = this.line_starting_whitespace(this.cursor);
|
||||
this.insert_char('\n');
|
||||
|
||||
for (var i = 0; i < white; i++)
|
||||
this.insert_char(" ");
|
||||
|
||||
},
|
||||
|
||||
input_text(char) {
|
||||
if (Keys.ctrl() || Keys.alt()) return;
|
||||
this.insert_char(char);
|
||||
this.keycb();
|
||||
},
|
||||
|
||||
input_backspace_pressrep() {
|
||||
this.value = this.value.slice(0,this.cursor-1) + this.value.slice(this.cursor);
|
||||
this.cursor--;
|
||||
},
|
||||
|
||||
line_starting_whitespace(p) {
|
||||
var white = 0;
|
||||
var l = this.line_start(p);
|
||||
|
||||
while (this.value[l] === " ") {
|
||||
white++;
|
||||
l++;
|
||||
}
|
||||
|
||||
return white;
|
||||
},
|
||||
|
||||
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;
|
||||
|
||||
this.cursor -= ret.length;
|
||||
return ret;
|
||||
},
|
||||
|
||||
next_word(pos) {
|
||||
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--;
|
||||
|
||||
return pos+1;
|
||||
},
|
||||
|
||||
end_of_word(pos) {
|
||||
var l = this.value.slice(pos).search(/\w[^\w]/g);
|
||||
return l+pos;
|
||||
},
|
||||
|
||||
get inset() {
|
||||
return this.cursor - this.value.prev('\n', this.cursor) - 1;
|
||||
},
|
||||
|
||||
line_start(p) {
|
||||
return this.value.prev('\n', p)+1;
|
||||
},
|
||||
|
||||
line_end(p) {
|
||||
return this.value.next('\n', p);
|
||||
},
|
||||
|
||||
next_line(p) {
|
||||
return this.value.next('\n',p)+1;
|
||||
},
|
||||
|
||||
prev_line(p) {
|
||||
return this.line_start(this.value.prev('\n', p));
|
||||
},
|
||||
|
||||
to_line_start() {
|
||||
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;
|
||||
},
|
||||
|
||||
line_width(pos) {
|
||||
var start = this.line_start(pos);
|
||||
var end = this.line_end(pos);
|
||||
if (end === -1)
|
||||
end = this.value.length;
|
||||
|
||||
return end-start;
|
||||
},
|
||||
|
||||
to_file_end() { this.cursor = this.value.length; },
|
||||
|
||||
to_file_start() { this.cursor = 0; },
|
||||
|
||||
desired_inset: 0,
|
||||
});
|
||||
|
||||
texteditor.inputs = {};
|
||||
texteditor.inputs['C-s'] = function() {
|
||||
editor.edit_level.script = texteditor.value;
|
||||
editor.save_current();
|
||||
texteditor.startbuffer = texteditor.value.slice();
|
||||
};
|
||||
texteditor.inputs['C-s'].doc = "Save script to file.";
|
||||
|
||||
texteditor.inputs['C-u'] = function() { this.popstate(); };
|
||||
texteditor.inputs['C-u'].doc = "Undo.";
|
||||
|
||||
texteditor.inputs['C-q'] = function() {
|
||||
var ws = this.prev_word(this.cursor);
|
||||
var we = this.end_of_word(this.cursor)+1;
|
||||
var find = this.copy(ws, we);
|
||||
var obj = editor.edit_level.varname2obj(find);
|
||||
|
||||
if (obj) {
|
||||
editor.unselect();
|
||||
editor.selectlist.push(obj);
|
||||
}
|
||||
};
|
||||
texteditor.inputs['C-q'].doc = "Select object of selected word.";
|
||||
|
||||
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['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));
|
||||
};
|
||||
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['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() {
|
||||
this.to_line_start();
|
||||
this.desired_inset = this.inset;
|
||||
};
|
||||
texteditor.inputs['C-a'].doc = "To start of line.";
|
||||
|
||||
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-e'] = function() {
|
||||
this.to_line_end();
|
||||
this.desired_inset = this.inset;
|
||||
};
|
||||
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);
|
||||
this.killring.push(killed);
|
||||
};
|
||||
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);
|
||||
var killamt = this.cursor - prevn;
|
||||
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['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);
|
||||
this.desired_inset = this.inset;
|
||||
};
|
||||
texteditor.inputs['M-b'].rep = true;
|
||||
|
||||
texteditor.inputs['C-f'] = function() {
|
||||
this.cursor++;
|
||||
this.desired_inset = this.inset;
|
||||
};
|
||||
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['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['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);
|
||||
};
|
||||
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) {
|
||||
this.to_file_end();
|
||||
return;
|
||||
}
|
||||
|
||||
this.desired_inset = Math.max(this.desired_inset, this.inset);
|
||||
this.cursor = this.next_line(this.cursor);
|
||||
var newlinew = this.line_width(this.cursor);
|
||||
this.cursor += Math.min(this.desired_inset, newlinew);
|
||||
};
|
||||
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'].doc = "Go down to next line with text on it.";
|
||||
texteditor.inputs['M-n'].rep = true;
|
||||
Reference in New Issue
Block a user