Update what's in global scope

This commit is contained in:
John Alanbrook 2024-02-25 23:31:48 +00:00
parent 9c8fe27ce4
commit 4351b4bf20
27 changed files with 634 additions and 777 deletions

View file

@ -41,14 +41,29 @@ Poke around the example projects. You will find it refreshingly straight forward
* Engine Tour * Engine Tour
Prosperon is built in a code-first fashion. Prosperon is built in a code-first fashion.
** QuickJS (Javascript) ** Scripting
The scripting language used in Prosperon is Javascript, with QuickJS. It is [[https://tc39.es/ecma262/2023/][ES2023]] compliant. It is fast, and has a number of features that make it well suited for a video game engine, like ref counting. Read more about it [[https://bellard.org/quickjs/][here]]. The scripting language used in Prosperon is Javascript, with QuickJS. It is [[https://tc39.es/ecma262/2023/][ES2023]] compliant. It is fast, and has a number of features that make it well suited for a video game engine, like ref counting. Read more about it [[https://bellard.org/quickjs/][here]].
#+begin_scholium #+begin_scholium
Javascript is used here mostly to set up objects and tear them down. Although computationally expensive tasks can be done using QuickJS, Prosperon makes it easy to extend with raw C. Javascript is used here mostly to set up objects and tear them down. Although computationally expensive tasks can be done using QuickJS, Prosperon makes it easy to extend with raw C.
#+end_scholium #+end_scholium
** Script entry points *** How Prosperon games are structued
Prosperon games are structured into two types of source files:
- scripts
- actors
When any source file is executed, it is executed in its own space. Global properties are accessible, but any declared variables and functions are not automatically added to the global space. To add obejcts to the global space, it must be explicitly done, by assigning them to ~global~ or ~globalThis~.
#+begin_src
global.hellofn = function() { say("Hello, world!"); }; // hellofn is now callable anywhere
#+end_src
When a *script* is loaded, its statements are executed in order, in the context of the containing source. The containing source is accessible via the ~$~ variable. When ~load~ is called, an optional object is permitted to be supplied as the ~$~. This makes writing scripts with mixin functionality simple.
The parameter ~$$~ is given to a persistent object that is available whenever a script is executing, per script.
*** Script entry points
The first way you can customize Prosperon is by adding scripts to the folder you're running it from. Any file ending with *.js* is a *script* which can be ran by Prosperon. The first way you can customize Prosperon is by adding scripts to the folder you're running it from. Any file ending with *.js* is a *script* which can be ran by Prosperon.
| script | When called | | script | When called |

View file

@ -1,4 +1,4 @@
var AI = { var ai = {
race(list) { race(list) {
return function(dt) { return function(dt) {
var good = false; var good = false;

View file

@ -22,56 +22,54 @@ Set = undefined;
WeakSet = undefined; WeakSet = undefined;
*/ */
var fmt = {}; Number.roman = {
var roman_numerals = {
M: 1000, M: 1000,
CM: 900,
D: 500, D: 500,
CD: 400,
C: 100, C: 100,
XC: 90,
L: 50, L: 50,
XL: 40,
X: 10, X: 10,
IX: 9,
V: 5, V: 5,
IV: 4,
I: 1 I: 1
}; };
function roman2arabic(roman) var convert = {};
{ convert.romanize = function(num) {
var num = 0; if (!+num) return false;
for (var i = 0; i < roman.length; i++) { var digits = String(+num).split('');
var rm = roman_numerals[roman[i]]; var key = ['','C','CC','CCC','CD','D','DC','DCC','DCCC','CM',
if (i + 1 < roman.length && rm < roman_numerals[roman[i+1]]) '','X','XX','XXX','XL','L','LX','LXX','LXXX','XC',
num -= rm; '','I','II','III','IV','V','VI','VII','VIII','IX'];
else var roman = '', i = 3;
num += rm; while (i--) roman = (key[+digits.pop() + (i * 10)] || '') + roman;
return Array(+digits.join('') + 1).join('M') + roman;
} }
convert.deromanize = function(str) {
var str = str.toUpperCase();
var validator = /^M*(?:D?C{0,3}|C[MD])(?:L?X{0,3}|X[CL])(?:V?I{0,3}|I[XV])$/;
var token = /[MDLV]|C[MD]?|X[CL]?|I[XV]?/g;
var key = {M:1000,CM:900,D:500,CD:400,C:100,XC:90,L:50,XL:40,X:10,IX:9,V:5,IV:4,I:1};
var num = 0, m;
if (!(str && validator.test(str))) return false;
while (m = token.exec(str)) num += key[m[0]];
return num; return num;
} }
function arabic2roman(num) convert.buf2hex = function(buffer) { // buffer is an ArrayBuffer
{ return [...new Uint8Array(buffer)]
if (num <= 0 || num >= 4000) .map(x => x.toString(16).padStart(2, '0'))
return "Invalid input. Roman numerals are not defined for numbers less than 1 or greater than 3999."; .join(' ');
var result = '';
for (var key in roman_numerals) {
while (num >= roman_numerals[key]) {
result += key;
num -= roman_numerals[key];
}
} }
return result; /* Time values are always expressed in terms of real earth-seconds */
} var time = {
get hour2minute() { return this.hour/this.minute; },
get day2hour() { return this.day/this.hour; },
get minute2second() { return this.minute/this.second; },
get week2day() { return this.week/this.day; },
};
var timeparse = { time.strparse = {
yyyy: "year", yyyy: "year",
mm: "month", mm: "month",
m: "month", m: "month",
@ -87,29 +85,38 @@ var timeparse = {
s: "second", s: "second",
}; };
String.parse = function(str, p) time.doc = {
{ doc: "Functions for manipulating time.",
var rec = {}; second: "Earth-seconds in a second.",
var fmts = Object.keys(p).sort(function(a,b) { return a.length > b.length; }); minute: "Seconds in a minute.",
} hour: "Seconds in an hour.",
day: "Seconds in a day.",
/* Time values are always expressed in terms of real earth-seconds */ week: "Seconds in a week.",
var time = { weekdays: "Names of the days of the week.",
get hour2minute() { return this.hour/this.minute; }, monthstr: "Full names of the months of the year.",
get day2hour() { return this.day/this.hour; }, epoch: "Times are expressed in terms of day 0 at hms 0 of this year.",
get minute2second() { return this.minute/this.second; }, now: "Get the time now.",
get week2day() { return this.week/this.day; }, computer_zone: "Get the time zone of the running computer.",
computer_dst: "Return true if the computer is in daylight savings.",
yearsize: "Given a year, return the number of days in that year.",
monthdays: "Number of days in each month.",
fmt: "Default format for time.",
record: "Given a time, return an object with time fields.",
number: "Return the number representation of a given time.",
text: "Return a text formatted time."
}; };
time.second = 1; /* earth-seconds in a second */
time.minute = 60; /* seconds in a minute */
time.hour = 3_600; /* seconds in an hour */ time.second = 1;
time.day = 86_400; /* seconds in a day */ time.minute = 60;
time.week = 604_800; /* seconds in a week */ time.hour = 3_600;
time.day = 86_400;
time.week = 604_800;
time.weekdays = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"]; time.weekdays = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"];
time.monthstr = ["January", "February", "March", 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December']; time.monthstr = ["January", "February", "March", 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'];
time.epoch = 1970; /* Times are expressed in terms of day 0 at hms 0 of this year */ time.epoch = 1970;
time.now = function() { return cmd(210);} time.now = function() { return cmd(210);}
time.computer_zone = function() { return cmd(211)/this.hour; } time.computer_zone = function() { return cmd(211)/this.hour; }
time.computer_dst = function() { return cmd(212); } time.computer_dst = function() { return cmd(212); }
@ -121,7 +128,6 @@ time.yearsize = function(y) {
return 366; return 366;
return 365; return 365;
} }
time.yearsize.doc = "Given a year, return the number of days in that year.";
time.monthdays = [31,28,31,30,31,30,31,31,30,31,30,31]; time.monthdays = [31,28,31,30,31,30,31,31,30,31,30,31];
time.zones = {}; time.zones = {};
@ -329,6 +335,13 @@ json.readout = function(obj)
return json.encode(j); return json.encode(j);
} }
json.doc = {
doc: "json implementation.",
encode: "Encode a value to json.",
decode: "Decode a json string to a value.",
readout: "Encode an object fully, including function definitions."
};
Object.methods = function(o) Object.methods = function(o)
{ {
var m = []; var m = [];
@ -521,7 +534,7 @@ Object.copy = function(proto, ...objs)
return c; return c;
} }
/* OBJECT DEFININTIONS */ /* OBJECT DEFININTioNS */
Object.defHidden = function(obj, prop) Object.defHidden = function(obj, prop)
{ {
Object.defineProperty(obj, prop, {enumerable:false, writable:true}); Object.defineProperty(obj, prop, {enumerable:false, writable:true});
@ -532,7 +545,7 @@ Object.hide = function(obj,...props)
for (var prop of props) { for (var prop of props) {
var p = Object.getOwnPropertyDescriptor(obj,prop); var p = Object.getOwnPropertyDescriptor(obj,prop);
if (!p) { if (!p) {
Log.info(`No property of name ${prop}.`); console.info(`No property of name ${prop}.`);
continue; continue;
} }
p.enumerable = false; p.enumerable = false;
@ -545,7 +558,7 @@ Object.unhide = function(obj, ...props)
for (var prop of props) { for (var prop of props) {
var p = Object.getOwnPropertyDescriptor(obj,prop); var p = Object.getOwnPropertyDescriptor(obj,prop);
if (!p) { if (!p) {
Log.warn(`No property of name ${prop}.`); console.warn(`No property of name ${prop}.`);
return; return;
} }
p.enumerable = true; p.enumerable = true;
@ -868,22 +881,6 @@ Object.defineProperty(Array.prototype, 'dofilter', {
} }
}); });
function filterInPlace(a, condition, thisArg) {
let j = 0;
a.forEach((e, i) => {
if (condition.call(thisArg, e, i, a)) {
if (i!==j) a[j] = e;
j++;
}
});
a.length = j;
return a;
}
Object.defineProperty(Array.prototype, 'reversed', { Object.defineProperty(Array.prototype, 'reversed', {
value: function() { value: function() {
var c = this.slice(); var c = this.slice();
@ -897,6 +894,7 @@ Object.defineProperty(Array.prototype, 'rotate', {
} }
}); });
function make_swizz() {
function setelem(n) { function setelem(n) {
return { return {
get: function() { return this[n]; }, get: function() { return this[n]; },
@ -969,7 +967,6 @@ swizz.forEach(function(x) {
}); });
}); });
swizz = []; swizz = [];
for (var i of nums) for (var i of nums)
for (var j of nums) for (var j of nums)
@ -995,7 +992,8 @@ swizz.forEach(function(x) {
}); });
}); });
};
make_swizz();
Object.defineProperty(Array.prototype, 'add', { Object.defineProperty(Array.prototype, 'add', {
value: function(b) { value: function(b) {
@ -1084,9 +1082,6 @@ value: function(b) {
return true; return true;
}}); }});
function add(x,y) { return x+y; };
function mult(x,y) { return x*y; };
Object.defineProperty(Array.prototype, 'mapc', { Object.defineProperty(Array.prototype, 'mapc', {
value: function(fn) { value: function(fn) {
return this.map(x => fn(x)); return this.map(x => fn(x));
@ -1285,7 +1280,7 @@ Object.defineProperty(Object.prototype, 'lerp',{
return obj; return obj;
}}); }});
/* MATH EXTENSIONS */ /* MATH EXTENSioNS */
Object.defineProperty(Number.prototype, 'lerp', { Object.defineProperty(Number.prototype, 'lerp', {
value: function(to, t) { value: function(to, t) {
var s = this; var s = this;
@ -1332,6 +1327,8 @@ Math.deg2turn = function(x) { return x/360; };
Math.randomint = function(max) { return Math.clamp(Math.floor(Math.random() * max), 0, max-1); }; Math.randomint = function(max) { return Math.clamp(Math.floor(Math.random() * max), 0, max-1); };
/* BOUNDINGBOXES */ /* BOUNDINGBOXES */
var bbox = {};
function cwh2bb(c, wh) { function cwh2bb(c, wh) {
return { return {
t: c.y+(wh.y/2), t: c.y+(wh.y/2),
@ -1518,7 +1515,7 @@ function points2cm(points)
return [x/n,y/n]; return [x/n,y/n];
}; };
function sortpointsccw(points) Math.sortpointsccw = function(points)
{ {
var cm = points2cm(points); var cm = points2cm(points);
var cmpoints = points.map(function(x) { return x.sub(cm); }); var cmpoints = points.map(function(x) { return x.sub(cm); });

View file

@ -20,19 +20,16 @@ Color.tohtml = function(v)
return "#" + html.join(''); return "#" + html.join('');
} }
Color.toesc = function(v) var esc = {};
{ esc.reset = "\x1b[0";
return Esc.color(v); esc.color = function(v) {
}
var Esc = {};
Esc.reset = "\x1b[0";
Esc.color = function(v) {
var c = v.map(function(n) { return Math.floor(n*255); }); var c = v.map(function(n) { return Math.floor(n*255); });
var truecolor = "\x1b[38;2;" + c.join(';') + ';'; var truecolor = "\x1b[38;2;" + c.join(';') + ';';
return truecolor; return truecolor;
} }
esc.doc = "Functions and constants for ANSI escape sequences.";
Color.Arkanoid = { Color.Arkanoid = {
orange: [255,143,0], orange: [255,143,0],
teal: [0,255,255], teal: [0,255,255],

View file

@ -1,29 +1,3 @@
function make_point_obj(o, p)
{
return {
pos: p,
move(d) {
d = o.gameobject.dir_world2this(d);
p.x += d.x;
p.y += d.y;
},
sync: o.sync.bind(o)
}
}
function assign_impl(obj, impl)
{
var tmp = {};
for (var key of Object.keys(impl))
if (typeof obj[key] !== 'undefined' && typeof obj[key] !== 'function')
tmp[key] = obj[key];
Object.mixin(obj, impl);
for (var key in tmp)
obj[key] = tmp[key];
}
var component = { var component = {
components: [], components: [],
toString() { toString() {
@ -57,7 +31,7 @@ var component = {
return nc; return nc;
}, },
kill() { Log.info("Kill not created for this component yet"); }, kill() { console.info("Kill not created for this component yet"); },
sync() {}, sync() {},
post(){}, post(){},
gui() { }, gui() { },
@ -68,6 +42,33 @@ var component = {
extend(spec) { return Object.copy(this, spec); }, extend(spec) { return Object.copy(this, spec); },
}; };
component.util = {};
component.util.make_point_obj = function(o, p)
{
return {
pos: p,
move(d) {
d = o.gameobject.dir_world2this(d);
p.x += d.x;
p.y += d.y;
},
sync: o.sync.bind(o)
}
}
component.util.assign_impl = function(obj, impl)
{
var tmp = {};
for (var key of Object.keys(impl))
if (typeof obj[key] !== 'undefined' && typeof obj[key] !== 'function')
tmp[key] = obj[key];
Object.mixin(obj, impl);
for (var key in tmp)
obj[key] = tmp[key];
}
component.sprite = Object.copy(component, { component.sprite = Object.copy(component, {
pos:[0,0], pos:[0,0],
color:[1,1,1,1], color:[1,1,1,1],
@ -301,7 +302,7 @@ var SpriteAnim = {
return anim; return anim;
}; };
var json = IO.slurp(path); var json = io.slurp(path);
json = JSON.parse(json); json = JSON.parse(json);
var anims = {}; var anims = {};
var frames = Array.isArray(json.frames) ? json.frames : Object.values(json.frames); var frames = Array.isArray(json.frames) ? json.frames : Object.values(json.frames);
@ -324,8 +325,8 @@ var SpriteAnim = {
}, },
find(path) { find(path) {
if (!IO.exists(path + ".asset")) return; if (!io.exists(path + ".asset")) return;
var asset = JSON.parse(IO.slurp(path + ".asset")); var asset = JSON.parse(io.slurp(path + ".asset"));
}, },
}; };
@ -336,57 +337,6 @@ SpriteAnim.strip.doc = 'Given a path and number of frames, converts a horizontal
SpriteAnim.aseprite.doc = 'Given an aseprite json metadata, returns an object of animations defined in the aseprite file.'; SpriteAnim.aseprite.doc = 'Given an aseprite json metadata, returns an object of animations defined in the aseprite file.';
SpriteAnim.find.doc = 'Given a path, find the relevant animation for the file.'; SpriteAnim.find.doc = 'Given a path, find the relevant animation for the file.';
/* 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;
},
arc(radius, angle, n, start) {
start ??= 0;
start = Math.deg2rad(start);
if (angle >= 360)
angle = 360;
if (n <= 1) return [];
var points = [];
angle = Math.deg2rad(angle);
var arclen = angle/n;
for (var i = 0; i < n; i++)
points.push(Vector.rotate([radius,0], start + (arclen*i)));
return points;
},
circle(radius, n) {
if (n <= 1) return [];
return Geometry.arc(radius, 360, n);
},
ngon(radius, n) {
return Geometry.arc(radius,360,n);
},
};
Geometry.doc = {
doc: "Functions for creating a list of points for various geometric shapes.",
box: "Create a box.",
arc: "Create an arc, made of n points.",
circle: "Create a circle, made of n points.",
ngon: "Create a polygon of n sides.",
};
/* For all colliders, "shape" is a pointer to a phys2d_shape, "id" is a pointer to the shape data */ /* For all colliders, "shape" is a pointer to a phys2d_shape, "id" is a pointer to the shape data */
var collider2d = Object.copy(component, { var collider2d = Object.copy(component, {
name: "collider 2d", name: "collider 2d",
@ -451,7 +401,7 @@ component.polygon2d = Object.copy(collider2d, {
}, },
gizmo() { gizmo() {
this.spoints().forEach(x => Shape.point(this.gameobject.this2screen(x), 3, Color.green)); this.spoints().forEach(x => render.point(this.gameobject.this2screen(x), 3, Color.green));
this.points.forEach((x,i)=>Debug.numbered_point(this.gameobject.this2screen(x), i)); this.points.forEach((x,i)=>Debug.numbered_point(this.gameobject.this2screen(x), i));
}, },
@ -478,7 +428,7 @@ var polygon2d = component.polygon2d;
polygon2d.inputs = {}; polygon2d.inputs = {};
//polygon2d.inputs.post = function() { this.sync(); }; //polygon2d.inputs.post = function() { this.sync(); };
polygon2d.inputs.f10 = function() { polygon2d.inputs.f10 = function() {
this.points = sortpointsccw(this.points); this.points = Math.sortpointsccw(this.points);
}; };
polygon2d.inputs.f10.doc = "Sort all points to be CCW order."; polygon2d.inputs.f10.doc = "Sort all points to be CCW order.";
@ -596,7 +546,7 @@ component.edge2d = Object.copy(collider2d, {
/* EDITOR */ /* EDITOR */
gizmo() { gizmo() {
if (this.type === Spline.type.catmull || this.type === -1) { if (this.type === Spline.type.catmull || this.type === -1) {
this.spoints().forEach(x => Shape.point(this.gameobject.this2screen(x), 3, Color.teal)); this.spoints().forEach(x => render.point(this.gameobject.this2screen(x), 3, Color.teal));
this.cpoints.forEach((x,i) => Debug.numbered_point(this.gameobject.this2screen(x), i)); this.cpoints.forEach((x,i) => Debug.numbered_point(this.gameobject.this2screen(x), i));
} else { } else {
for (var i = 0; i < this.cpoints.length; i += 3) for (var i = 0; i < this.cpoints.length; i += 3)
@ -605,8 +555,8 @@ component.edge2d = Object.copy(collider2d, {
for (var i = 1; i < this.cpoints.length; i+=3) { for (var i = 1; i < this.cpoints.length; i+=3) {
Debug.numbered_point(this.gameobject.this2screen(this.cpoints[i]), i, Color.green); Debug.numbered_point(this.gameobject.this2screen(this.cpoints[i]), i, Color.green);
Debug.numbered_point(this.gameobject.this2screen(this.cpoints[i+1]), i+1, Color.green); Debug.numbered_point(this.gameobject.this2screen(this.cpoints[i+1]), i+1, Color.green);
Shape.line([this.gameobject.this2screen(this.cpoints[i-1]), this.gameobject.this2screen(this.cpoints[i])], Color.yellow); render.line([this.gameobject.this2screen(this.cpoints[i-1]), this.gameobject.this2screen(this.cpoints[i])], Color.yellow);
Shape.line([this.gameobject.this2screen(this.cpoints[i+1]), this.gameobject.this2screen(this.cpoints[i+2])], Color.yellow); render.line([this.gameobject.this2screen(this.cpoints[i+1]), this.gameobject.this2screen(this.cpoints[i+2])], Color.yellow);
} }
} }
}, },

View file

@ -1,8 +1,8 @@
/* All draw in screen space */ /* All draw in screen space */
var Shape = { Object.assign(render, {
point(pos,size,color) { point(pos,size,color) {
color ??= Color.blue; color ??= Color.blue;
Shape.circle(pos,size,color); render.circle(pos,size,color);
}, },
line(points, color, thickness) { line(points, color, thickness) {
@ -27,8 +27,8 @@ var Shape = {
pos.add([-size,0]) pos.add([-size,0])
]; ];
Shape.line(a,color); render.line(a,color);
Shape.line(b,color); render.line(b,color);
}, },
arrow(start, end, color, wingspan, wingangle) { arrow(start, end, color, wingspan, wingangle) {
@ -45,15 +45,15 @@ var Shape = {
Vector.rotate(dir,-wingangle).scale(wingspan).add(end), Vector.rotate(dir,-wingangle).scale(wingspan).add(end),
end end
]; ];
Shape.line([start,end],color); render.line([start,end],color);
Shape.line(wing1,color); render.line(wing1,color);
Shape.line(wing2,color); render.line(wing2,color);
}, },
rectangle(lowerleft, upperright, color) { rectangle(lowerleft, upperright, color) {
var pos = lowerleft.add(upperright).map(x=>x/2); var pos = lowerleft.add(upperright).map(x=>x/2);
var wh = [upperright.x-lowerleft.x,upperright.y-lowerleft.y]; var wh = [upperright.x-lowerleft.x,upperright.y-lowerleft.y];
Shape.box(pos,wh,color); render.box(pos,wh,color);
}, },
box(pos, wh, color) { box(pos, wh, color) {
@ -61,16 +61,16 @@ var Shape = {
cmd(53, pos, wh, color); cmd(53, pos, wh, color);
}, },
}; });
Shape.doc = "Draw shapes in screen space."; render.doc = "Draw shapes in screen space.";
Shape.circle.doc = "Draw a circle at pos, with a given radius and color."; render.circle.doc = "Draw a circle at pos, with a given radius and color.";
Shape.cross.doc = "Draw a cross centered at pos, with arm length size."; render.cross.doc = "Draw a cross centered at pos, with arm length size.";
Shape.arrow.doc = "Draw an arrow from start to end, with wings of length wingspan at angle wingangle."; render.arrow.doc = "Draw an arrow from start to end, with wings of length wingspan at angle wingangle.";
Shape.poly.doc = "Draw a concave polygon from a set of points."; render.poly.doc = "Draw a concave polygon from a set of points.";
Shape.rectangle.doc = "Draw a rectangle, with its corners at lowerleft and upperright."; render.rectangle.doc = "Draw a rectangle, with its corners at lowerleft and upperright.";
Shape.box.doc = "Draw a box centered at pos, with width and height in the tuple wh."; render.box.doc = "Draw a box centered at pos, with width and height in the tuple wh.";
Shape.line.doc = "Draw a line from a set of points, and a given thickness."; render.line.doc = "Draw a line from a set of points, and a given thickness.";
var Debug = { var Debug = {
fn_break(fn, obj) { fn_break(fn, obj) {
@ -98,7 +98,7 @@ var Debug = {
numbered_point(pos, n, color) { numbered_point(pos, n, color) {
color ??= Color.white; color ??= Color.white;
Shape.point(pos, 3, color); render.point(pos, 3, color);
GUI.text(n, pos.add([0,4]), 1, color); GUI.text(n, pos.add([0,4]), 1, color);
}, },
@ -127,12 +127,12 @@ var Debug = {
if (this.draw_gizmos) if (this.draw_gizmos)
Game.all_objects(function(x) { Game.all_objects(function(x) {
if (!x.icon) return; if (!x.icon) return;
GUI.image(x.icon, world2screen(x.pos)); GUI.image(x.icon, Window.world2screen(x.pos));
}); });
if (this.draw_names) if (this.draw_names)
Game.all_objects(function(x) { Game.all_objects(function(x) {
GUI.text(x, world2screen(x.pos).add([0,32]), 1, Color.Debug.names); GUI.text(x, Window.world2screen(x.pos).add([0,32]), 1, Color.Debug.names);
}); });
if (Debug.Options.gif.rec) { if (Debug.Options.gif.rec) {
@ -173,7 +173,7 @@ var Gizmos = {
}, },
}; };
var Profile = { Object.assign(profile, {
tick_now() { return cmd(127); }, tick_now() { return cmd(127); },
ns(ticks) { return cmd(128, ticks); }, ns(ticks) { return cmd(128, ticks); },
us(ticks) { return cmd(129, ticks); }, us(ticks) { return cmd(129, ticks); },
@ -197,23 +197,23 @@ var Profile = {
cpu(fn, times, q) { cpu(fn, times, q) {
times ??= 1; times ??= 1;
q ??= "unnamed"; q ??= "unnamed";
var start = Profile.tick_now(); var start = profile.tick_now();
for (var i = 0; i < times; i++) for (var i = 0; i < times; i++)
fn(); fn();
var elapsed = Profile.tick_now() - start; var elapsed = profile.tick_now() - start;
var avgt = Profile.best_t(elapsed/times); var avgt = profile.best_t(elapsed/times);
var totalt = Profile.best_t(elapsed); var totalt = profile.best_t(elapsed);
console.say(`Profile [${q}]: ${avgt.time.toFixed(3)} ${avgt.unit} average [${totalt.time.toFixed(3)} ${totalt.unit} for ${times} loops]`); console.say(`profile [${q}]: ${avgt.time.toFixed(3)} ${avgt.unit} average [${totalt.time.toFixed(3)} ${totalt.unit} for ${times} loops]`);
}, },
get fps() { return sys_cmd(8); }, get fps() { return sys_cmd(8); },
}; });
Profile.test = { profile.test = {
barecall() { profile(0); }, barecall() { profile(0); },
unpack_num(n) { profile(1,n); }, unpack_num(n) { profile(1,n); },
unpack_array(n) { profile(2,n); }, unpack_array(n) { profile(2,n); },
@ -224,9 +224,9 @@ Profile.test = {
call_fn_n(fn1, n) { profile(7,fn1,n,fn2); }, call_fn_n(fn1, n) { profile(7,fn1,n,fn2); },
}; };
Profile.test.call_fn_n.doc = "Calls fn1 n times, and then fn2."; profile.test.call_fn_n.doc = "Calls fn1 n times, and then fn2.";
Profile.cpu.doc = `Output the time it takes to do a given function n number of times. Provide 'q' as "ns", "us", or "ms" to output the time taken in the requested resolution.`; profile.cpu.doc = `Output the time it takes to do a given function n number of times. Provide 'q' as "ns", "us", or "ms" to output the time taken in the requested resolution.`;
/* These controls are available during editing, and during play of debug builds */ /* These controls are available during editing, and during play of debug builds */
var DebugControls = {}; var DebugControls = {};
@ -292,13 +292,11 @@ DebugControls.inputs.f9 = function() {
DebugControls.inputs.f10 = function() { Time.timescale = 0.1; }; DebugControls.inputs.f10 = function() { Time.timescale = 0.1; };
DebugControls.inputs.f10.doc = "Toggle timescale to 1/10."; DebugControls.inputs.f10.doc = "Toggle timescale to 1/10.";
DebugControls.inputs.f10.released = function () { Time.timescale = 1.0; }; 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 = function() { GUI.defaults.debug = !GUI.defaults.debug; console.warn("GUI toggle debug");};
DebugControls.inputs.f12.doc = "Toggle drawing GUI debugging aids."; DebugControls.inputs.f12.doc = "Toggle drawing GUI debugging aids.";
DebugControls.inputs['M-1'] = Render.normal; DebugControls.inputs['M-1'] = render.normal;
Render.normal.doc = "Render mode for enabling all shaders and lighting effects."; DebugControls.inputs['M-2'] = render.wireframe;
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'] = function() {};
DebugControls.inputs['C-M-f'].doc = "Enter camera fly mode."; DebugControls.inputs['C-M-f'].doc = "Enter camera fly mode.";
@ -327,7 +325,7 @@ var Time = {
play() { play() {
if (!Time.stash) { if (!Time.stash) {
Log.warn("Tried to resume time without calling Time.pause first."); console.warn("Tried to resume time without calling Time.pause first.");
return; return;
} }
Time.timescale = Time.stash; Time.timescale = Time.stash;
@ -346,40 +344,8 @@ Time.doc.play = "Resume the game after using Time.pause.";
Player.players[0].control(DebugControls); Player.players[0].control(DebugControls);
Register.gui.register(Debug.draw, Debug); Register.gui.register(Debug.draw, Debug);
var console = Object.create(Log); Debug.api = {};
console.log = function(str) Debug.api.doc_entry = function(obj, key)
{
console.say(time.text(time.now(), 'yyyy-m-dd hh:nn:ss') + " " + str);
}
console.clear = function()
{
cmd(146);
}
console.assert = function(assertion, msg, objs)
{
if (!assertion) {
console.error(msg);
console.stack();
}
}
var say = function(msg) {
console.say(msg);
}
say.doc = "Print to std out with an appended newline.";
var gist = function(o)
{
if (typeof o === 'object') return json.encode(o,null,1);
if (typeof o === 'string') return o;
return o.toString();
}
gist.doc = "Return the best string gist of an object.";
var API = {};
API.doc_entry = function(obj, key)
{ {
if (typeof key !== 'string') { if (typeof key !== 'string') {
console.warn("Cannot print a key that isn't a string."); console.warn("Cannot print a key that isn't a string.");
@ -415,7 +381,7 @@ ${doc}
`; `;
} }
API.print_doc = function(name) Debug.api.print_doc = function(name)
{ {
var obj = name; var obj = name;
if (typeof name === 'string') { if (typeof name === 'string') {
@ -448,7 +414,7 @@ API.print_doc = function(name)
if (key === 'doc') continue; if (key === 'doc') continue;
if (key === 'toString') continue; if (key === 'toString') continue;
mdoc += API.doc_entry(obj, key) + "\n"; mdoc += Debug.api.doc_entry(obj, key) + "\n";
} }
return mdoc; return mdoc;

View file

@ -26,14 +26,14 @@ function unmerge(target, source) {
/* Deeply merge two objects, not clobbering objects on target with objects on source */ /* Deeply merge two objects, not clobbering objects on target with objects on source */
function deep_merge(target, source) function deep_merge(target, source)
{ {
Log.warn("Doing a deep merge ..."); console.warn("Doing a deep merge ...");
for (var key in source) { for (var key in source) {
if (typeof source[key] === 'object' && !Array.isArray(source[key])) { if (typeof source[key] === 'object' && !Array.isArray(source[key])) {
Log.warn(`Deeper merge on ${key}`); console.warn(`Deeper merge on ${key}`);
deep_merge(target[key], source[key]); deep_merge(target[key], source[key]);
} }
else { else {
Log.warn(`Setting key ${key}`); console.warn(`Setting key ${key}`);
target[key] = source[key]; target[key] = source[key];
} }
} }
@ -201,7 +201,7 @@ function samediff(from, to)
var same = []; var same = [];
if (!to) return same; if (!to) return same;
if (typeof to !== 'object') { if (typeof to !== 'object') {
Log.warn("'To' must be an object. Got " + to); console.warn("'To' must be an object. Got " + to);
return same; return same;
} }
Object.keys(from).forEach(function(k) { Object.keys(from).forEach(function(k) {

View file

@ -303,7 +303,7 @@ var editor = {
redo() { redo() {
if (Object.empty(this.backshots)) { if (Object.empty(this.backshots)) {
Log.info("Nothing to redo."); console.info("Nothing to redo.");
return; return;
} }
@ -317,7 +317,7 @@ var editor = {
undo() { undo() {
if (Object.empty(this.snapshots)) { if (Object.empty(this.snapshots)) {
Log.info("Nothing to undo."); console.info("Nothing to undo.");
return; return;
} }
this.unselect(); this.unselect();
@ -363,7 +363,7 @@ var editor = {
this._sel_comp = x; this._sel_comp = x;
if (this._sel_comp) { if (this._sel_comp) {
Log.info("sel comp is now " + this._sel_comp); console.info("sel comp is now " + this._sel_comp);
Player.players[0].control(this._sel_comp); Player.players[0].control(this._sel_comp);
} }
}, },
@ -377,7 +377,7 @@ var editor = {
x.gizmo(); x.gizmo();
}); });
Shape.line(bb2points(cwh2bb([0,0],[Game.native.x,Game.native.y])).wrapped(1), Color.yellow); render.line(bb2points(cwh2bb([0,0],[Game.native.x,Game.native.y])).wrapped(1), Color.yellow);
/* Draw selection box */ /* Draw selection box */
if (this.sel_start) { if (this.sel_start) {
@ -392,15 +392,14 @@ var editor = {
wh[1] = Math.abs(endpos[1] - this.sel_start[1]); wh[1] = Math.abs(endpos[1] - this.sel_start[1]);
var bb = cwh2bb(c,wh); var bb = cwh2bb(c,wh);
Debug.boundingbox(bb, Color.Editor.select.alpha(0.1)); Debug.boundingbox(bb, Color.Editor.select.alpha(0.1));
Shape.line(bb2points(bb).wrapped(1), Color.white); render.line(bb2points(bb).wrapped(1), Color.white);
} }
}, },
gui() { gui() {
/* Clean out killed objects */ /* Clean out killed objects */
this.selectlist = this.selectlist.filter(function(x) { return x.alive; }); this.selectlist = this.selectlist.filter(function(x) { return x.alive; });
Debug.coordinate(world2screen([0,0])); Debug.coordinate(Window.world2screen([0,0]));
Shape.cross(Mouse.pos, 5);
GUI.text("WORKING LAYER: " + this.working_layer, [0,520]); GUI.text("WORKING LAYER: " + this.working_layer, [0,520]);
GUI.text("MODE: " + this.edit_mode, [0,500]); GUI.text("MODE: " + this.edit_mode, [0,500]);
@ -408,7 +407,7 @@ var editor = {
if (this.comp_info && this.sel_comp) if (this.comp_info && this.sel_comp)
GUI.text(Input.print_pawn_kbm(this.sel_comp,false), [100,700],1); GUI.text(Input.print_pawn_kbm(this.sel_comp,false), [100,700],1);
Shape.cross(editor.edit_level.screenpos(),3,Color.blue); render.cross(editor.edit_level.screenpos(),3,Color.blue);
var thiso = editor.get_this(); var thiso = editor.get_this();
var clvl = thiso; var clvl = thiso;
@ -457,13 +456,13 @@ var editor = {
GUI.text(sname, x.screenpos().add([0, 32]), 1, Color.editor.ur); GUI.text(sname, x.screenpos().add([0, 32]), 1, Color.editor.ur);
GUI.text(x.worldpos().map(function(x) { return Math.round(x); }), x.screenpos(), 1, Color.white); GUI.text(x.worldpos().map(function(x) { return Math.round(x); }), x.screenpos(), 1, Color.white);
Shape.cross(x.screenpos(), 10, Color.blue); render.cross(x.screenpos(), 10, Color.blue);
}); });
Object.entries(thiso.objects).forEach(function(x) { Object.entries(thiso.objects).forEach(function(x) {
var p = x[1].namestr(); var p = x[1].namestr();
GUI.text(p, x[1].screenpos().add([0,16]),1,editor.color_depths[depth]); GUI.text(p, x[1].screenpos().add([0,16]),1,editor.color_depths[depth]);
Shape.circle(x[1].screenpos(),10,Color.blue.alpha(0.3)); render.circle(x[1].screenpos(),10,Color.blue.alpha(0.3));
}); });
var mg = physics.pos_query(Mouse.worldpos,10); var mg = physics.pos_query(Mouse.worldpos,10);
@ -495,8 +494,8 @@ var editor = {
}); });
Debug.draw_grid(1, editor.grid_size, Color.Editor.grid.alpha(0.3)); Debug.draw_grid(1, editor.grid_size, Color.Editor.grid.alpha(0.3));
var startgrid = screen2world([-20,0]).map(function(x) { return Math.snap(x, editor.grid_size); }); var startgrid = Window.screen2world([-20,0]).map(function(x) { return Math.snap(x, editor.grid_size); });
var endgrid = screen2world([Window.width, Window.height]); var endgrid = Window.screen2world([Window.width, Window.height]);
var w_step = Math.round(editor.ruler_mark_px/Window.width * (endgrid.x-startgrid.x)/editor.grid_size)*editor.grid_size; var w_step = Math.round(editor.ruler_mark_px/Window.width * (endgrid.x-startgrid.x)/editor.grid_size)*editor.grid_size;
if (w_step === 0) w_step = editor.grid_size; if (w_step === 0) w_step = editor.grid_size;
@ -505,12 +504,12 @@ var editor = {
if (h_step === 0) h_step = editor.grid_size; if (h_step === 0) h_step = editor.grid_size;
while(startgrid[0] <= endgrid[0]) { while(startgrid[0] <= endgrid[0]) {
GUI.text(startgrid[0], [world2screen([startgrid[0], 0])[0],0]); GUI.text(startgrid[0], [Window.world2screen([startgrid[0], 0])[0],0]);
startgrid[0] += w_step; startgrid[0] += w_step;
} }
while(startgrid[1] <= endgrid[1]) { while(startgrid[1] <= endgrid[1]) {
GUI.text(startgrid[1], [0, world2screen([0, startgrid[1]])[1]]); GUI.text(startgrid[1], [0, Window.world2screen([0, startgrid[1]])[1]]);
startgrid[1] += h_step; startgrid[1] += h_step;
} }
@ -562,7 +561,7 @@ var editor = {
} else { } else {
var path = sub.replaceAll('.', '/') + ".json"; var path = sub.replaceAll('.', '/') + ".json";
var saveobj = obj.json_obj(); var saveobj = obj.json_obj();
IO.slurpwrite(path, JSON.stringify(saveobj,null,1)); io.slurpwrite(path, JSON.stringify(saveobj,null,1));
if (obj === editor.edit_level) { if (obj === editor.edit_level) {
if (obj === editor.desktop) { if (obj === editor.desktop) {
@ -608,7 +607,7 @@ editor.inputs.drop = function(str) {
} }
editor.inputs.f9 = function() { editor.inputs.f9 = function() {
Log.warn("CAPTURING"); console.warn("CAPTURING");
cmd(173, "capture.bmp", 0, 0, 500, 500); cmd(173, "capture.bmp", 0, 0, 500, 500);
} }
@ -787,7 +786,7 @@ editor.inputs['C-M-p'] = function() {
if (!Game.playing()) { if (!Game.playing()) {
editor.start_play_ed(); editor.start_play_ed();
} }
Log.warn(`Starting edited level ...`); console.warn(`Starting edited level ...`);
}; };
editor.inputs['C-M-p'].doc = "Start game from currently edited level."; editor.inputs['C-M-p'].doc = "Start game from currently edited level.";
@ -841,8 +840,8 @@ editor.inputs['C-s'] = function() {
if (savejs.objects) saveobj.__proto__.objects = savejs.objects; if (savejs.objects) saveobj.__proto__.objects = savejs.objects;
var path = prototypes.ur_stem(saveobj.ur.toString()) + ".json"; var path = prototypes.ur_stem(saveobj.ur.toString()) + ".json";
IO.slurpwrite(path, JSON.stringify(saveobj.__proto__,null,1)); io.slurpwrite(path, JSON.stringify(saveobj.__proto__,null,1));
Log.warn(`Wrote to file ${path}`); console.warn(`Wrote to file ${path}`);
Object.values(saveobj.objects).forEach(function(x) { x.check_dirty(); }); Object.values(saveobj.objects).forEach(function(x) { x.check_dirty(); });
@ -1504,11 +1503,11 @@ var replpanel = Object.copy(inputpanel, {
ecode += `var ${key} = editor.edit_level.objects['${key}'];`; ecode += `var ${key} = editor.edit_level.objects['${key}'];`;
ecode += this.value; ecode += this.value;
Log.say(this.value); console.say(this.value);
this.value = ""; this.value = "";
this.caret = 0; this.caret = 0;
var ret = function() {return eval(ecode);}.call(repl_obj); var ret = function() {return eval(ecode);}.call(repl_obj);
Log.say(ret); console.say(ret);
}, },
resetscroll() { resetscroll() {
@ -1544,7 +1543,7 @@ replpanel.inputs.tab = function() {
if (eval(`typeof ${keyobj.tofirst('.')}`) === 'object' && eval(`typeof ${keyobj.replace('.', '?.')}`) === 'object') if (eval(`typeof ${keyobj.tofirst('.')}`) === 'object' && eval(`typeof ${keyobj.replace('.', '?.')}`) === 'object')
obj = eval(keyobj); obj = eval(keyobj);
else if (this.value.includes('.')){ else if (this.value.includes('.')){
Log.say(`${this.value} is not an object.`); console.say(`${this.value} is not an object.`);
return; return;
} }
@ -1575,17 +1574,17 @@ replpanel.inputs.tab = function() {
keys = keys.map(function(x) { keys = keys.map(function(x) {
if (typeof obj[x] === 'function') if (typeof obj[x] === 'function')
return Esc.color(Color.Apple.orange) + x + Esc.reset; return esc.color(Color.Apple.orange) + x + esc.reset;
if (Object.isObject(obj[x])) if (Object.isObject(obj[x]))
return Esc.color(Color.Apple.purple) + x + Esc.reset; return esc.color(Color.Apple.purple) + x + esc.reset;
if (Array.isArray(obj[x])) if (Array.isArray(obj[x]))
return Esc.color(Color.Apple.green) + x + Esc.reset; return esc.color(Color.Apple.green) + x + esc.reset;
return x; return x;
}); });
if (keys.length > 1) if (keys.length > 1)
Log.repl(keys.join(', ')); console.repl(keys.join(', '));
}; };
replpanel.inputs['C-p'] = function() replpanel.inputs['C-p'] = function()
{ {
@ -1992,7 +1991,7 @@ limited_editor.inputs['C-q'] = function()
var limited_editing = {}; var limited_editing = {};
limited_editing.inputs = {}; limited_editing.inputs = {};
if (IO.exists("editor.config")) if (io.exists("editor.config"))
load_configs("editor.config"); load_configs("editor.config");
/* This is the editor level & camera - NOT the currently edited level, but a level to hold editor things */ /* This is the editor level & camera - NOT the currently edited level, but a level to hold editor things */

View file

@ -1,49 +1,37 @@
"use math"; "use math";
var files = {}; globalThis.global = globalThis;
function load(file) {
var modtime = cmd(0, file);
files[file] = modtime;
}
var cmd_args = function(cc) function eval_env(script, env)
{ {
console.warn(cc); env ??= {};
// script = `function() { ${script} }.call();`;
// return eval(script);
return function(str) { return eval(str); }.call(env, script);
} }
eval_env.dov = `Counterpart to /load_env/, but with a string.`;
function load_env(file,env)
{
env ??= global;
var script = io.slurp(file);
eval_env(script, env);
// cmd(16, file, env);
// var script = io.slurp(file);
// cmd(123, script, env, file);
}
load_env.doc = `Load a given file with 'env' as **this**. Does not add to the global namespace.`;
function load(file) { return load_env(file);}
load.doc = `Load a given script file into the global namespace.`;
load("scripts/base.js"); load("scripts/base.js");
load("scripts/std.js"); load("scripts/std.js");
//load("scripts/lunr.js");
//var lunrtxt = load("scripts/lunr.js");
//eval(lunrtxt);
/* The global namespace file */
var prosp = {};
function run(file)
{
var modtime = cmd(119, file);
if (modtime === 0) {
Log.stack();
return false;
}
files[file] = modtime;
return cmd(117, file);
}
run.doc = `Load a given script file.`;
load.doc = `Load a given script file.`;
function run_env(file, env)
{
var script = IO.slurp(file);
return function(){return eval(script);}.call(env);
}
run_env.doc = `Load a given script file, evaluating it in the context of the object 'env'.`;
load("scripts/diff.js"); load("scripts/diff.js");
Log.level = 1; console.level = 1;
load("scripts/color.js"); load("scripts/color.js");
@ -51,41 +39,6 @@ function bb2wh(bb) {
return [bb.r-bb.l, bb.t-bb.b]; return [bb.r-bb.l, bb.t-bb.b];
}; };
var Device = {
pc: [1920,1080],
macbook_m2: [2560,1664, 13.6],
ds_top: [400,240, 3.53],
ds_bottom: [320,240, 3.02],
playdate: [400,240,2.7],
switch: [1280,720, 6.2],
switch_lite: [1280,720,5.5],
switch_oled: [1280,720,7],
dsi: [256,192,3.268],
ds: [256,192, 3],
dsixl: [256,192,4.2],
ipad_air_m2: [2360,1640, 11.97],
iphone_se: [1334, 750, 4.7],
iphone_12_pro: [2532,1170,6.06],
iphone_15: [2556,1179,6.1],
gba: [240,160,2.9],
gameboy: [160,144,2.48],
gbc: [160,144,2.28],
steamdeck: [1280,800,7],
vita: [960,544,5],
psp: [480,272,4.3],
imac_m3: [4480,2520,23.5],
macbook_pro_m3: [3024,1964, 14.2],
ps1: [320,240,5],
ps2: [640,480],
snes: [256,224],
gamecube: [640,480],
n64: [320,240],
c64: [320,200],
macintosh: [512,342,9],
gamegear: [160,144,3.2],
};
Device.doc = `Device resolutions given as [x,y,inches diagonal].`;
var prosperon = {}; var prosperon = {};
prosperon.version = cmd(255); prosperon.version = cmd(255);
@ -169,34 +122,60 @@ var timer = {
load("scripts/tween.js"); load("scripts/tween.js");
var Render = { var render = {
normal() { cmd(67);}, normal() { cmd(67);},
wireframe() { cmd(68); }, wireframe() { cmd(68); },
pass() { },
pass() {
},
}; };
Render.doc = { render.doc = {
doc: "Functions for rendering modes.", doc: "Functions for rendering modes.",
normal: "Final render with all lighting.", normal: "Final render with all lighting.",
wireframe: "Show only wireframes of models." wireframe: "Show only wireframes of models."
}; };
render.device = {
pc: [1920,1080],
macbook_m2: [2560,1664, 13.6],
ds_top: [400,240, 3.53],
ds_bottom: [320,240, 3.02],
playdate: [400,240,2.7],
switch: [1280,720, 6.2],
switch_lite: [1280,720,5.5],
switch_oled: [1280,720,7],
dsi: [256,192,3.268],
ds: [256,192, 3],
dsixl: [256,192,4.2],
ipad_air_m2: [2360,1640, 11.97],
iphone_se: [1334, 750, 4.7],
iphone_12_pro: [2532,1170,6.06],
iphone_15: [2556,1179,6.1],
gba: [240,160,2.9],
gameboy: [160,144,2.48],
gbc: [160,144,2.28],
steamdeck: [1280,800,7],
vita: [960,544,5],
psp: [480,272,4.3],
imac_m3: [4480,2520,23.5],
macbook_pro_m3: [3024,1964, 14.2],
ps1: [320,240,5],
ps2: [640,480],
snes: [256,224],
gamecube: [640,480],
n64: [320,240],
c64: [320,200],
macintosh: [512,342,9],
gamegear: [160,144,3.2],
};
render.device.doc = `Device resolutions given as [x,y,inches diagonal].`;
load("scripts/physics.js"); load("scripts/physics.js");
load("scripts/input.js"); load("scripts/input.js");
load("scripts/sound.js"); load("scripts/sound.js");
load("scripts/ai.js"); load("scripts/ai.js");
load("scripts/geometry.js"); load("scripts/geometry.js");
function screen2world(screenpos) {
if (Game.camera)
return Game.camera.view2world(screenpos);
return screenpos;
}
function world2screen(worldpos) { return Game.camera.world2view(worldpos); }
var Register = { var Register = {
kbm_input(mode, btn, state, ...args) { kbm_input(mode, btn, state, ...args) {
if (state === 'released') { if (state === 'released') {
@ -228,7 +207,7 @@ var Register = {
var rawfn = `gamepad_${btn}_${statestr}`; var rawfn = `gamepad_${btn}_${statestr}`;
player.input(rawfn, ...args); player.input(rawfn, ...args);
Action.actions.forEach(x => { input.action.actions.forEach(x => {
if (x.inputs.includes(btn)) if (x.inputs.includes(btn))
player.input(`action_${x.name}_${statestr}`, ...args); player.input(`action_${x.name}_${statestr}`, ...args);
}); });
@ -284,20 +263,10 @@ register(7, Register.kbm_input, Register);
Register.add_cb(8, "gamepad_input"); Register.add_cb(8, "gamepad_input");
Register.add_cb(10, "draw"); Register.add_cb(10, "draw");
register(9, Log.stack, this); register(9, console.stack, this);
Register.gamepad_playermap[0] = Player.players[0]; Register.gamepad_playermap[0] = Player.players[0];
var Signal = {
obj_begin(fn, go) {
register_collide(0, fn, go.body);
},
obj_separate(fn, go) {
register_collide(3,fn, go.body);
},
};
var Event = { var Event = {
events: {}, events: {},
@ -329,7 +298,7 @@ var Window = {
get width() { return cmd(48); }, get width() { return cmd(48); },
get height() { return cmd(49); }, get height() { return cmd(49); },
get dimensions() { return [this.width, this.height]; }, get dimensions() { return [this.width, this.height]; },
set name(str) { cmd(134, str); }, title(str) { cmd(134, str); },
boundingbox() { boundingbox() {
return { return {
t: Window.height, t: Window.height,
@ -340,141 +309,18 @@ var Window = {
}, },
}; };
Window.screen2world = function(screenpos) {
if (Game.camera)
return Game.camera.view2world(screenpos);
return screenpos;
}
Window.world2screen = function(worldpos) { return Game.camera.world2view(worldpos); }
Window.icon = function(path) { cmd(90, path); }; Window.icon = function(path) { cmd(90, path); };
Window.icon.doc = "Set the icon of the window using the PNG image at 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"); load("scripts/debug.js");
load('scripts/spline.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;
};
*/
var Spline = {};
Spline.sample_angle = function(type, points, angle) {
return spline_cmd(0, type, points[0].length, points, angle);
}
Spline.bezier_loop = function(cp)
{
cp.push(Vector.reflect_point(cp.at(-2),cp.at(-1)));
cp.push(Vector.reflect_point(cp[1],cp[0]));
cp.push(cp[0].slice());
return cp;
}
Spline.bezier_node_count = function(cp)
{
if (cp.length === 4) return 2;
return 2 + (cp.length-4)/3;
}
Spline.is_bezier = function(t) { return t === Spline.type.bezier; }
Spline.is_catmull = function(t) { return t === Spline.type.catmull; }
Spline.bezier2catmull = function(b)
{
var c = [];
for (var i = 0; i < b.length; i += 3)
c.push(b[i]);
return c;
}
Spline.catmull2bezier = function(c)
{
var b = [];
for (var i = 1; i < c.length-2; i++) {
b.push(c[i].slice());
b.push(c[i+1].sub(c[i-1]).scale(0.25).add(c[i]));
b.push(c[i].sub(c[i+2]).scale(0.25).add(c[i+1]));
}
b.push(c[c.length-2]);
return b;
}
Spline.catmull_loop = function(cp)
{
cp = cp.slice();
cp.unshift(cp.last());
cp.push(cp[1]);
cp.push(cp[2]);
return cp;
}
Spline.catmull_caps = function(cp)
{
cp = cp.slice();
cp.unshift(cp[0].sub(cp[1]).add(cp[0]));
cp.push(cp.last().sub(cp.at(-2).add(cp.last())));
return cp;
}
Spline.catmull2bezier.doc = "Given a set of control points C for a camtull-rom type curve, return a set of cubic bezier points to give the same curve."
Spline.type = {
catmull: 0,
bezier: 1,
bspline: 2,
cubichermite: 3
};
Spline.bezier_tan_partner = function(points, i)
{
if (i%3 === 0) return undefined;
var partner_i = (i%3) === 2 ? i-1 : i+1;
return points[i];
}
Spline.bezier_cp_mirror = function(points, i)
{
if (i%3 === 0) return undefined;
var partner_i = (i%3) === 2 ? i+2 : i-2;
var node_i = (i%3) === 2 ? i+1 : i-1;
if (partner_i >= points.length || node_i >= points.length) return;
points[partner_i] = points[node_i].sub(points[i]).add(points[node_i]);
}
Spline.bezier_point_handles = function(points, i)
{
if (!Spline.bezier_is_node(points,i)) return [];
var a = i-1;
var b = i+1;
var c = []
if (a > 0)
c.push(a);
if (b < points.length)
c.push(b);
return c;
}
Spline.bezier_nodes = function(points)
{
var c = [];
for (var i = 0; i < points.length; i+=3)
c.push(points[i].slice());
return c;
}
Spline.bezier_is_node = function(points, i) { return i%3 === 0; }
Spline.bezier_is_handle = function(points, i) { return !Spline.bezier_is_node(points,i); }
load("scripts/components.js"); load("scripts/components.js");
var Game = { var Game = {
@ -484,7 +330,7 @@ var Game = {
Sound.master = Sound.bus.master; Sound.master = Sound.bus.master;
}, },
native: Device.pc, native: render.device.pc,
object_count() { object_count() {
return cmd(214); return cmd(214);
@ -588,6 +434,6 @@ Game.view_camera = function(cam)
cmd(61, Game.camera.body); cmd(61, Game.camera.body);
} }
Window.name = "Prosperon (V0.1)"; Window.title(`Prosperon v${prosperon.version}`);
Window.width = 1280; Window.width = 1280;
Window.height = 720; Window.height = 720;

View file

@ -1,4 +1,4 @@
prosp.obj_unique_name = function(name, obj) prosperon.obj_unique_name = function(name, obj)
{ {
name = name.replaceAll('.', '_'); name = name.replaceAll('.', '_');
if (!(name in obj)) return name; if (!(name in obj)) return name;
@ -15,7 +15,7 @@ var actor = {};
actor.spawn = function(script, config){ actor.spawn = function(script, config){
if (typeof script !== 'string') return; if (typeof script !== 'string') return;
var padawan = Object.create(actor); var padawan = Object.create(actor);
compile_env(script, padawan, "script"); eval_env(script, padawan);
if (typeof config === 'object') if (typeof config === 'object')
Object.merge(padawan, config); Object.merge(padawan, config);
@ -133,7 +133,7 @@ var gameobject_impl = {
set mass(x) { set_body(7,this.body,x); }, set mass(x) { set_body(7,this.body,x); },
get mass() { get mass() {
if (!(this.phys === Physics.dynamic)) if (!(this.phys === physics.dynamic))
return undefined; return undefined;
return q_body(5, this.body); return q_body(5, this.body);
@ -159,7 +159,7 @@ var gameobject_impl = {
get_moi() { return q_body(6, this.body); }, get_moi() { return q_body(6, this.body); },
set_moi(x) { set_moi(x) {
if(x <= 0) { if(x <= 0) {
Log.error("Cannot set moment of inertia to 0 or less."); console.error("Cannot set moment of inertia to 0 or less.");
return; return;
} }
set_body(13, this.body, x); set_body(13, this.body, x);
@ -291,7 +291,7 @@ var gameobject = {
}, },
cry(file) { cry(file) {
this.crying = Sound.play(file, Sound.bus.sfx); this.crying = audio.sound.play(file, audio.sound.bus.sfx);
var killfn = () => {this.crying = undefined; console.warn("killed"); } var killfn = () => {this.crying = undefined; console.warn("killed"); }
this.crying.hook = killfn; this.crying.hook = killfn;
return killfn; return killfn;
@ -318,7 +318,7 @@ var gameobject = {
set_body(2,this.body,x); set_body(2,this.body,x);
this.objects.forEach((o,i) => o.set_worldpos(this.this2world(poses[i]))); this.objects.forEach((o,i) => o.set_worldpos(this.this2world(poses[i])));
}, },
screenpos() { return world2screen(this.worldpos()); }, screenpos() { return Window.world2screen(this.worldpos()); },
worldangle() { return Math.rad2turn(q_body(2,this.body)); }, worldangle() { return Math.rad2turn(q_body(2,this.body)); },
sworldangle(x) { set_body(0,this.body,Math.turn2rad(x)); }, sworldangle(x) { set_body(0,this.body,Math.turn2rad(x)); },
@ -385,8 +385,8 @@ var gameobject = {
shove_at(vec, at) { set_body(14,this.body,vec,at); }, shove_at(vec, at) { set_body(14,this.body,vec,at); },
world2this(pos) { return cmd(70, this.body, pos); }, world2this(pos) { return cmd(70, this.body, pos); },
this2world(pos) { return cmd(71, this.body, pos); }, this2world(pos) { return cmd(71, this.body, pos); },
this2screen(pos) { return world2screen(this.this2world(pos)); }, this2screen(pos) { return Window.world2screen(this.this2world(pos)); },
screen2this(pos) { return this.world2this(screen2world(pos)); }, screen2this(pos) { return this.world2this(Window.screen2world(pos)); },
dir_world2this(dir) { return cmd(160, this.body, dir); }, dir_world2this(dir) { return cmd(160, this.body, dir); },
dir_this2world(dir) { return cmd(161, this.body, dir); }, dir_this2world(dir) { return cmd(161, this.body, dir); },
@ -440,10 +440,10 @@ var gameobject = {
obj.timers.push(Register.physupdate.register(obj.physupdate.bind(obj))); obj.timers.push(Register.physupdate.register(obj.physupdate.bind(obj)));
if (typeof obj.collide === 'function') if (typeof obj.collide === 'function')
Signal.obj_begin(obj.collide.bind(obj), obj); register_collide(0, obj.collide.bind(obj), obj.body);
if (typeof obj.separate === 'function') if (typeof obj.separate === 'function')
Signal.obj_separate(obj.separate.bind(obj), obj); register_collide(3,obj.separate.bind(obj), obj.body);
if (typeof obj.draw === 'function') if (typeof obj.draw === 'function')
obj.timers.push(Register.draw.register(obj.draw.bind(obj), obj)); obj.timers.push(Register.draw.register(obj.draw.bind(obj), obj));
@ -668,7 +668,7 @@ var gameobject = {
rename_obj(name, newname) { rename_obj(name, newname) {
if (!this.objects[name]) { if (!this.objects[name]) {
Log.warn(`No object with name ${name}. Could not rename to ${newname}.`); console.warn(`No object with name ${name}. Could not rename to ${newname}.`);
return; return;
} }
if (name === newname) { if (name === newname) {
@ -690,7 +690,7 @@ var gameobject = {
add_component(comp, data) { add_component(comp, data) {
data ??= undefined; data ??= undefined;
if (typeof comp.make !== 'function') return; if (typeof comp.make !== 'function') return;
var name = prosp.obj_unique_name(comp.toString(), this); var name = prosperon.obj_unique_name(comp.toString(), this);
this[name] = comp.make(this); this[name] = comp.make(this);
this[name].comp = comp.toString(); this[name].comp = comp.toString();
this.components[name] = this[name]; this.components[name] = this[name];
@ -797,20 +797,20 @@ prototypes.from_file = function(file)
var script = undefined; var script = undefined;
var json = undefined; var json = undefined;
if (jsfile) script = IO.slurp(jsfile); if (jsfile) script = io.slurp(jsfile);
try { try {
if (jsonfile) json = JSON.parse(IO.slurp(jsonfile)); if (jsonfile) json = JSON.parse(io.slurp(jsonfile));
} catch(e) { } catch(e) {
Log.warn(`Unable to create json from ${jsonfile}. ${e}`); console.warn(`Unable to create json from ${jsonfile}. ${e}`);
} }
if (!json && !script) { if (!json && !jsfile) {
Log.warn(`Could not make ur from ${file}`); console.warn(`Could not make ur from ${file}`);
return undefined; return undefined;
} }
if (script) if (script)
compile_env(script, newur, file); load_env(jsfile, newur);
json ??= {}; json ??= {};
Object.merge(newur,json); Object.merge(newur,json);
@ -871,8 +871,9 @@ prototypes.file2ur = function(file)
prototypes.get_ur = function(name) prototypes.get_ur = function(name)
{ {
if (!name) return;
if (!name) { if (!name) {
console.error(`Can't get ur from an undefined.`); console.error(`Can't get ur from ${name}.`);
return; return;
} }
var urpath = name; var urpath = name;
@ -899,16 +900,16 @@ prototypes.get_ur_file = function(path, ext)
{ {
var urpath = prototypes.ur2file(path); var urpath = prototypes.ur2file(path);
var file = urpath + ext; var file = urpath + ext;
if (IO.exists(file)) return file; if (io.exists(file)) return file;
file = urpath + "/" + path.split('.').at(-1) + ext; file = urpath + "/" + path.split('.').at(-1) + ext;
if (IO.exists(file)) return file; if (io.exists(file)) return file;
return undefined; return undefined;
} }
prototypes.generate_ur = function(path) prototypes.generate_ur = function(path)
{ {
var ob = IO.glob("**" + prototypes.ur_ext); var ob = io.glob("**" + prototypes.ur_ext);
ob = ob.concat(IO.glob("**.json")); ob = ob.concat(io.glob("**.json"));
ob = ob.map(function(path) { return path.set_ext(""); }); ob = ob.map(function(path) { return path.set_ext(""); });
ob = ob.map(function(path) { return path[0] !== '.' ? path : undefined; }); ob = ob.map(function(path) { return path[0] !== '.' ? path : undefined; });
@ -940,7 +941,7 @@ prototypes.resani = function(ur, path)
var res = ur.replaceAll('.', '/'); var res = ur.replaceAll('.', '/');
var restry = res + "/" + path; var restry = res + "/" + path;
while (!IO.exists(restry)) { while (!io.exists(restry)) {
res = res.updir() + "/"; res = res.updir() + "/";
if (res === "/") if (res === "/")
return path; return path;
@ -953,15 +954,15 @@ prototypes.resani = function(ur, path)
prototypes.ur_dir = function(ur) prototypes.ur_dir = function(ur)
{ {
var path = ur.replaceAll('.', '/'); var path = ur.replaceAll('.', '/');
Log.warn(path); console.warn(path);
Log.warn(IO.exists(path)); console.warn(io.exists(path));
Log.warn(`${path} does not exist; sending ${path.dir()}`); console.warn(`${path} does not exist; sending ${path.dir()}`);
} }
prototypes.ur_json = function(ur) prototypes.ur_json = function(ur)
{ {
var path = ur.replaceAll('.', '/'); var path = ur.replaceAll('.', '/');
if (IO.exists(path)) if (io.exists(path))
path = path + "/" + path.name() + ".json"; path = path + "/" + path.name() + ".json";
else else
path = path + ".json"; path = path + ".json";
@ -972,7 +973,7 @@ prototypes.ur_json = function(ur)
prototypes.ur_stem = function(ur) prototypes.ur_stem = function(ur)
{ {
var path = ur.replaceAll('.', '/'); var path = ur.replaceAll('.', '/');
if (IO.exists(path)) if (io.exists(path))
return path + "/" + path.name(); return path + "/" + path.name();
else else
return path; return path;
@ -983,7 +984,7 @@ prototypes.ur_file_exts = ['.jso', '.json'];
prototypes.ur_folder = function(ur) prototypes.ur_folder = function(ur)
{ {
var path = ur.replaceAll('.', '/'); var path = ur.replaceAll('.', '/');
return IO.exists(path); return io.exists(path);
} }
prototypes.ur_pullout_folder = function(ur) prototypes.ur_pullout_folder = function(ur)
@ -994,6 +995,6 @@ prototypes.ur_pullout_folder = function(ur)
/* prototypes.ur_file_exts.forEach(function(e) { /* prototypes.ur_file_exts.forEach(function(e) {
var p = stem + e; var p = stem + e;
if (IO.exists(p)) if (io.exists(p))
*/ */
} }

View file

@ -1,6 +1,8 @@
var Sphere = {}; var shape = {};
Sphere.volume = function(r) { return Math.pi*r*r*r*4/3; }; shape.sphere = {};
Sphere.random = function(r,theta,phi) shape.circle = {};
shape.sphere.volume = function(r) { return Math.pi*r*r*r*4/3; };
shape.sphere.random = function(r,theta,phi)
{ {
if (typeof r === 'number') r = [r,r]; if (typeof r === 'number') r = [r,r];
theta ??= [0,1]; theta ??= [0,1];
@ -18,9 +20,48 @@ Sphere.random = function(r,theta,phi)
]; ];
} }
var Circle = {}; shape.circle.area = function(r) { return Math.pi*r*r; };
Circle.area = function(r) { return Math.pi*r*r; }; shape.circle.random = function(r,theta)
Circle.random = function(r,theta)
{ {
return Sphere.random(r,theta).xz; return shape.sphere.random(r,theta).xz;
} }
shape.box = function(w,h) {
w /= 2;
h /= 2;
var points = [
[w,h],
[-w,h],
[-w,-h],
[w,-h]
];
return points;
};
shape.ngon = function(radius, n) {
return shape.arc(radius,360,n);
};
shape.arc = function(radius, angle, n, start) {
start ??= 0;
start = Math.deg2rad(start);
if (angle >= 360)
angle = 360;
if (n <= 1) return [];
var points = [];
angle = Math.deg2rad(angle);
var arclen = angle/n;
for (var i = 0; i < n; i++)
points.push(Vector.rotate([radius,0], start + (arclen*i)));
return points;
};
shape.circle.points = function(radius, n) {
if (n <= 1) return [];
return shape.arc(radius, 360, n);
};

View file

@ -199,7 +199,7 @@ Mum.button = Mum.text._int.extend({
hovered:{ hovered:{
color: Color.red color: Color.red
}, },
action() { Log.warn("Button has no action."); }, action() { console.warn("Button has no action."); },
}); });
Mum.window = Mum.extend({ Mum.window = Mum.extend({
@ -229,7 +229,7 @@ Mum.window = Mum.extend({
Mum.image = Mum.extend({ Mum.image = Mum.extend({
start() { start() {
if (!this.path) { if (!this.path) {
Log.warn("Mum image needs a path."); console.warn("Mum image needs a path.");
this.draw = function(){}; this.draw = function(){};
return; return;
} }
@ -275,7 +275,7 @@ GUI.window = function(pos, wh, color)
var p = pos.slice(); var p = pos.slice();
p.x += wh.x/2; p.x += wh.x/2;
p.y += wh.y/2; p.y += wh.y/2;
Shape.box(p,wh,color); render.box(p,wh,color);
} }
GUI.flush = function() { cmd(141); }; GUI.flush = function() { cmd(141); };

View file

@ -1,4 +1,4 @@
var Input = { var input = {
setgame() { cmd(77); }, setgame() { cmd(77); },
setnuke() { cmd(78); }, setnuke() { cmd(78); },
}; };
@ -6,9 +6,40 @@ var Input = {
var Mouse = { var Mouse = {
get pos() { return cmd(45); }, get pos() { return cmd(45); },
screenpos() { return cmd(45); }, screenpos() { return cmd(45); },
get worldpos() { return screen2world(cmd(45)); }, get worldpos() { return Window.screen2world(cmd(45)); },
disabled() { cmd(46, 1); }, disabled() { cmd(46, 1); },
normal() { cmd(46, 0);}, normal() { cmd(46, 0);},
mode(m) {
if (Mouse.custom[m])
cmd(97, Mouse.custom[m]);
else
cmd(17, m);
},
set_custom_cursor(img, mode) {
mode ??= Mouse.cursor.default;
if (!img)
delete Mouse.custom[mode];
else {
cmd(97, img);
Mouse.custom[mode] = img;
}
},
custom:[],
cursor: {
default: 0,
arrow: 1,
ibeam: 2,
cross: 3,
hand: 4,
ew: 5,
ns: 6,
nwse: 7,
nesw: 8,
resize: 9,
no: 10
},
}; };
Mouse.doc = {}; Mouse.doc = {};
@ -24,7 +55,7 @@ var Keys = {
super() { return cmd(50, 343); }, super() { return cmd(50, 343); },
}; };
Input.state2str = function(state) { input.state2str = function(state) {
if (typeof state === 'string') return state; if (typeof state === 'string') return state;
switch (state) { switch (state) {
case 0: case 0:
@ -36,7 +67,7 @@ Input.state2str = function(state) {
} }
} }
Input.print_pawn_kbm = function(pawn) { input.print_pawn_kbm = function(pawn) {
if (!('inputs' in pawn)) return; if (!('inputs' in pawn)) return;
var str = ""; var str = "";
for (var key in pawn.inputs) { for (var key in pawn.inputs) {
@ -46,7 +77,7 @@ Input.print_pawn_kbm = function(pawn) {
return str; return str;
}; };
Input.print_md_kbm = function(pawn) { input.print_md_kbm = function(pawn) {
if (!('inputs' in pawn)) return; if (!('inputs' in pawn)) return;
var str = ""; var str = "";
@ -60,13 +91,13 @@ Input.print_md_kbm = function(pawn) {
return str; return str;
}; };
Input.has_bind = function(pawn, bind) { input.has_bind = function(pawn, bind) {
return (typeof pawn.inputs?.[bind] === 'function'); return (typeof pawn.inputs?.[bind] === 'function');
}; };
var Action = { input.action = {
add_new(name) { add_new(name) {
var action = Object.create(Action); var action = Object.create(input.action);
action.name = name; action.name = name;
action.inputs = []; action.inputs = [];
this.actions.push(action); this.actions.push(action);
@ -167,7 +198,7 @@ var Player = {
print_pawns() { print_pawns() {
for (var pawn of this.pawns.reversed()) for (var pawn of this.pawns.reversed())
Log.say(pawn.toString()); console.say(pawn.toString());
}, },
create() { create() {

View file

@ -1,4 +1,4 @@
/* On collisions, entities are sent a 'hit' object, which looks like this: */ /* On collisions, entities are sent a 'hit' object, which looks like this:
var HIT = { var HIT = {
normal: "The normal of the collision point.", normal: "The normal of the collision point.",
hit: "The gameobject of the object that collided.", hit: "The gameobject of the object that collided.",
@ -8,13 +8,13 @@ var HIT = {
depth: "Depth of the contact.", depth: "Depth of the contact.",
}; };
var Physics = { */
var physics = {
dynamic: 0, dynamic: 0,
kinematic: 1, kinematic: 1,
static: 2, static: 2,
};
var physics = {
pos_query(pos, give) { pos_query(pos, give) {
give ??= 25; give ??= 25;
return cmd(44, pos, give); return cmd(44, pos, give);
@ -43,7 +43,7 @@ physics.doc.pos_query = "Returns any object colliding with the given point.";
physics.doc.box_query = "Returns an array of body ids that collide with a given box."; physics.doc.box_query = "Returns an array of body ids that collide with a given box.";
physics.doc.box_point_query = "Returns the subset of points from a given list that are inside a given box."; physics.doc.box_point_query = "Returns the subset of points from a given list that are inside a given box.";
var Collision = { physics.collision = {
types: {}, types: {},
num: 32, num: 32,
set_collide(a, b, x) { set_collide(a, b, x) {
@ -57,17 +57,17 @@ var Collision = {
}, },
}; };
for (var i = 0; i < Collision.num; i++) { for (var i = 0; i < physics.collision.num; i++) {
Collision.types[i] = []; physics.collision.types[i] = [];
for (var j = 0; j < Collision.num; j++) for (var j = 0; j < physics.collision.num; j++)
Collision.types[i][j] = false; physics.collision.types[i][j] = false;
}; };
Collision.sync(); physics.collision.sync();
var Warp = {}; physics.warp = {};
Warp.gravity = function() { return cmd(253); } physics.warp.gravity = function() { return cmd(253); }
Warp.damp = function() { return cmd(254); } physics.warp.damp = function() { return cmd(254); }
physics.gravity = Warp.gravity(); physics.gravity = physics.warp.gravity();
physics.damp = Warp.damp(); physics.damp = physics.warp.damp();

View file

@ -1,6 +1,6 @@
Game.play(); Game.play();
if (!IO.exists("game.js")) if (!io.exists("game.js"))
load("scripts/nogame.js"); load("scripts/nogame.js");
else else
load("game.js"); load("game.js");

View file

@ -1,20 +1,26 @@
var Sound = { var audio = {};
audio.sound = {
bus: {}, bus: {},
samplerate() { return cmd(198); }, samplerate() { return cmd(198); },
sounds: [], /* array of loaded sound files */ sounds: [], /* array of loaded sound files */
play(file, bus) { play(file, bus) {
if (!IO.exists(file)) { if (!io.exists(file)) {
Log.error(`Cannot play sound ${file}: does not exist.`); console.error(`Cannot play sound ${file}: does not exist.`);
return; return;
} }
var src = DSP.source(file); var src = audio.dsp.source(file);
bus ??= Sound.bus.master; bus ??= sound.bus.master;
// src.plugin(bus); // src.plugin(bus);
return src; return src;
}, },
doc: {
play: "Play the given file once.",
volume: "Set the volume. 0 is no sound and 100 is loudest."
},
}; };
var DSP = { audio.dsp = {
mix(to) { mix(to) {
var n = cmd(181); var n = cmd(181);
if (to) n.plugin(to); if (to) n.plugin(to);
@ -31,8 +37,8 @@ var DSP = {
}, },
allpass(secs, decay) { allpass(secs, decay) {
var composite = {}; var composite = {};
var fwd = DSP.fwd_delay(secs,-decay); var fwd = audio.dsp.fwd_delay(secs,-decay);
var fbk = DSP.delay(secs,decay); var fbk = audio.dsp.delay(secs,decay);
composite.id = fwd.id; composite.id = fwd.id;
composite.plugin = composite.plugin.bind(fbk); composite.plugin = composite.plugin.bind(fbk);
composite.unplug = dsp_node.unplug.bind(fbk); composite.unplug = dsp_node.unplug.bind(fbk);
@ -77,12 +83,7 @@ var DSP = {
}, },
}; };
audio.dsp.doc = {
Sound.play.doc = "Play the given file once.";
Sound.doc = {};
Sound.doc.volume = "Set the master volume. 0 is no sound and 100 is loudest.";
DSP.doc = {
delay: "Delays the input by secs, multiplied by decay", delay: "Delays the input by secs, multiplied by decay",
fwd_delay: "Forward feedback delays the input by secs, multiplied by decay", fwd_delay: "Forward feedback delays the input by secs, multiplied by decay",
allpass: "Composite node of a delay and fwd_delay", allpass: "Composite node of a delay and fwd_delay",
@ -105,10 +106,10 @@ Object.mixin(cmd(180).__proto__, {
set volume(x) { this.gain = x; }, set volume(x) { this.gain = x; },
}); });
/*Object.mixin(DSP.source().__proto__, { /*Object.mixin(audio.dsp.source().__proto__, {
frames() { return cmd(197,this); }, frames() { return cmd(197,this); },
length() { return this.frames()/Sound.samplerate(); }, length() { return this.frames()/sound.samplerate(); },
time() { return this.frame/Sound.samplerate(); }, time() { return this.frame/sound.samplerate(); },
pct() { return this.time()/this.length(); }, pct() { return this.time()/this.length(); },
}); });
*/ */

View file

@ -1,22 +1,5 @@
function compile_env(str, env, file) os.cwd.doc = "Get the absolute path of the current working directory.";
{ os.env.doc = "Return the value of the environment variable v.";
file ??= "unknown";
return cmd(123, str, env, file);
}
function fcompile_env(file, env) { return compile_env(IO.slurp(file), env, file); }
function buf2hex(buffer) { // buffer is an ArrayBuffer
return [...new Uint8Array(buffer)]
.map(x => x.toString(16).padStart(2, '0'))
.join(' ');
}
var OS = {};
OS.cwd = function() { return cmd(144); }
OS.exec = function(s) { cmd(143, s); }
OS.cwd.doc = "Get the absolute path of the current working directory.";
OS.exec.doc = "Run a command line instruction, and return when it finishes.";
var Resources = {}; var Resources = {};
Resources.images = ["png", "jpg", "jpeg", "gif"]; Resources.images = ["png", "jpg", "jpeg", "gif"];
@ -46,7 +29,26 @@ Resources.texture.dimensions = function(path) { return cmd(64,path); }
Resources.gif = {}; Resources.gif = {};
Resources.gif.frames = function(path) { return cmd(139,path); } Resources.gif.frames = function(path) { return cmd(139,path); }
var Log = { Resources.replstrs = function(path)
{
var script = io.slurp(path);
var regexp = /"[^"\s]*?\.[^"\s]+?"/g;
var stem = path.dir();
script = script.replace(regexp,function(str) {
if (str[1] === "/")
return str.rm(1);
if (str[1] === "@")
return str.rm(1).splice(1, "playerpath/");
return str.splice(1, stem + "/");
});
return script;
}
var console = {
set level(x) { cmd(92,x); }, set level(x) { cmd(92,x); },
get level() { return cmd(93); }, get level() { return cmd(93); },
print(msg, lvl) { print(msg, lvl) {
@ -94,7 +96,8 @@ var Log = {
cmd(91,msg); cmd(91,msg);
}, },
say(msg) { Log.write(msg + '\n'); }, log(msg) { console.say(time.text(time.now(), 'yyyy-m-dd hh:nn:ss') + " " + str); },
say(msg) { console.write(msg + '\n'); },
repl(msg) { cmd(142, msg + '\n'); }, repl(msg) { cmd(142, msg + '\n'); },
stack(skip = 0) { stack(skip = 0) {
@ -103,18 +106,30 @@ var Log = {
var n = stack.next('\n',0)+1; var n = stack.next('\n',0)+1;
for (var i = 0; i < skip; i++) for (var i = 0; i < skip; i++)
n = stack.next('\n', n)+1; n = stack.next('\n', n)+1;
Log.write(err.name); console.write(err.name);
Log.write(err.message); console.write(err.message);
Log.write(err.stack); console.write(err.stack);
// Log.write(stack); // console.write(stack);
}, },
clear() { clear() {
cmd(146); cmd(146);
}, },
assert(assertion, msg, obj) {
if (!assertion) {
console.error(msg);
console.stack();
}
},
}; };
Log.doc = { var say = function(msg) {
console.say(msg);
}
say.doc = "Print to std out with an appended newline.";
console.doc = {
level: "Set level to output logging to console.", level: "Set level to output logging to console.",
info: "Output info level message.", info: "Output info level message.",
warn: "Output warn level message.", warn: "Output warn level message.",
@ -128,7 +143,7 @@ Log.doc = {
}; };
/* /*
IO path rules. Starts with, meaning: io path rules. Starts with, meaning:
"@": playerpath "@": playerpath
"/": game room "/": game room
"#": Force look locally (instead of in db first) "#": Force look locally (instead of in db first)
@ -136,10 +151,10 @@ Log.doc = {
"": Local path relative to script defined in "": Local path relative to script defined in
*/ */
var IO = { var io = {
exists(file) { return cmd(65, file);}, exists(file) { return cmd(65, file);},
slurp(file) { slurp(file) {
if (IO.exists(file)) if (io.exists(file))
return cmd(38,file); return cmd(38,file);
else else
throw new Error(`File ${file} does not exist; can't slurp`); throw new Error(`File ${file} does not exist; can't slurp`);
@ -154,7 +169,7 @@ var IO = {
return cmd(39, data, file); return cmd(39, data, file);
}, },
extensions(ext) { extensions(ext) {
var paths = IO.ls(); var paths = io.ls();
paths = paths.filter(function(str) { return str.ext() === ext; }); paths = paths.filter(function(str) { return str.ext() === ext; });
return paths; return paths;
}, },
@ -179,7 +194,7 @@ var IO = {
cmd(258, dir); cmd(258, dir);
}, },
glob(pat) { glob(pat) {
var paths = IO.ls(); var paths = io.ls();
pat = pat.replaceAll(/([\[\]\(\)\^\$\.\|\+])/g, "\\$1"); pat = pat.replaceAll(/([\[\]\(\)\^\$\.\|\+])/g, "\\$1");
pat = pat.replaceAll('**', '.*'); pat = pat.replaceAll('**', '.*');
pat = pat.replaceAll(/[^\.]\*/g, '[^\\/]*'); pat = pat.replaceAll(/[^\.]\*/g, '[^\\/]*');
@ -190,7 +205,7 @@ var IO = {
}, },
}; };
IO.doc = { io.doc = {
doc: "Functions for filesystem input/output commands.", doc: "Functions for filesystem input/output commands.",
exists: "Returns true if a file exists.", exists: "Returns true if a file exists.",
slurp: "Returns the contents of given file as a string.", slurp: "Returns the contents of given file as a string.",
@ -204,25 +219,6 @@ IO.doc = {
glob: "Glob files in game directory.", glob: "Glob files in game directory.",
}; };
var Parser = {};
Parser.replstrs = function(path)
{
var script = IO.slurp(path);
var regexp = /"[^"\s]*?\.[^"\s]+?"/g;
var stem = path.dir();
script = script.replace(regexp,function(str) {
if (str[1] === "/")
return str.rm(1);
if (str[1] === "@")
return str.rm(1).splice(1, "playerpath/");
return str.splice(1, stem + "/");
});
Log.warn(script);
}
var Cmdline = {}; var Cmdline = {};
Cmdline.cmds = []; Cmdline.cmds = [];
@ -243,13 +239,11 @@ Cmdline.register_order = function(order, fn, doc, usage) {
} }
Cmdline.register_order("edit", function() { Cmdline.register_order("edit", function() {
if (!IO.exists(".prosperon")) { if (!io.exists(".prosperon")) {
IO.mkdir(".prosperon"); say("No game to edit. Try making one with 'prosperon init'.");
var project = {}; return;
project.version = prosperon.version;
project.revision = prosperon.revision;
IO.slurpwrite(".prosperon/project", json.encode(project));
} }
Game.engine_start(function() { Game.engine_start(function() {
load("scripts/editor.js"); load("scripts/editor.js");
load("editorconfig.js"); load("editorconfig.js");
@ -257,17 +251,39 @@ Cmdline.register_order("edit", function() {
}); });
}, "Edit the project in this folder. Give it the name of an UR to edit that specific object.", "?UR?"); }, "Edit the project in this folder. Give it the name of an UR to edit that specific object.", "?UR?");
Cmdline.register_order("play", function() { Cmdline.register_order("init", function() {
if (!IO.exists(".prosperon")) { if (io.exists(".prosperon")) {
IO.mkdir(".prosperon"); say("Already a game here.");
return;
}
if (!(io.ls().length === 0)) {
say("Directory is not empty. Make an empty one and init there.");
return;
}
io.mkdir(".prosperon");
var project = {}; var project = {};
project.version = prosperon.version; project.version = prosperon.version;
project.revision = prosperon.revision; project.revision = prosperon.revision;
IO.slurpwrite(".prosperon/project", json.encode(project)); io.slurpwrite(".prosperon/project", json.encode(project));
}, "Turn the directory into a Prosperon game.");
Cmdline.register_order("play", function() {
if (!io.exists(".prosperon/project")) {
say("No game to play. Try making one with 'prosperon init'.");
return;
} }
var project = json.decode(io.slurp(".prosperon/project"));
Game.engine_start(function() { Game.engine_start(function() {
load("config.js"); load("config.js");
load("game.js"); load("game.js");
if (project.icon) Window.icon(project.icon);
if (project.title) Window.title(project.title);
say(project.title);
}); });
}, "Play the game present in this folder."); }, "Play the game present in this folder.");
@ -276,7 +292,7 @@ Cmdline.register_order("pack", function(str) {
if (str.length === 0) if (str.length === 0)
packname = "test.cdb"; packname = "test.cdb";
else if (str.length > 1) { else if (str.length > 1) {
Log.warn("Give me a single filename for the pack."); console.warn("Give me a single filename for the pack.");
return; return;
} else } else
packname = str[0]; packname = str[0];
@ -295,11 +311,13 @@ Cmdline.register_order("build", function() {
}, "Build static assets for this project."); }, "Build static assets for this project.");
Cmdline.register_order("api", function(obj) { Cmdline.register_order("api", function(obj) {
if (!obj[0]) if (!obj[0]) {
Cmdline.print_order("api"); Cmdline.print_order("api");
return;
}
load("scripts/editor.js"); load("scripts/editor.js");
var api = API.print_doc(obj[0]); var api = Debug.api.print_doc(obj[0]);
if (!api) if (!api)
return; return;
@ -308,15 +326,15 @@ Cmdline.register_order("api", function(obj) {
Cmdline.register_order("compile", function(argv) { Cmdline.register_order("compile", function(argv) {
for (var file of argv) { for (var file of argv) {
var comp = IO.compile(file); var comp = io.compile(file);
IO.slurpwrite(file + ".byte", comp); io.slurpwrite(file + "c", comp);
} }
}, "Compile one or more provided files into bytecode.", "FILE ..."); }, "Compile one or more provided files into bytecode.", "FILE ...");
Cmdline.register_order("input", function(pawn) { Cmdline.register_order("input", function(pawn) {
load("scripts/editor.js"); load("scripts/editor.js");
say(`## Input for ${pawn}`); say(`## Input for ${pawn}`);
eval(`say(Input.print_md_kbm(${pawn}));`); eval(`say(input.print_md_kbm(${pawn}));`);
}, "Print input documentation for a given object as markdown. Give it a file to save the output to", "OBJECT ?FILE?"); }, "Print input documentation for a given object as markdown. Give it a file to save the output to", "OBJECT ?FILE?");
Cmdline.register_order("run", function(script) { Cmdline.register_order("run", function(script) {
@ -326,12 +344,12 @@ Cmdline.register_order("run", function(script) {
return; return;
} }
if (IO.exists(script)) if (io.exists(script))
try { try {
if (script.endswith(".byte")) if (script.endswith("c"))
cmd(261, script); cmd(261, script);
else else
run(script); load(script);
} catch(e) { } } catch(e) { }
else { else {
var ret = eval(script); var ret = eval(script);
@ -339,6 +357,8 @@ Cmdline.register_order("run", function(script) {
} }
}, "Run a given script. SCRIPT can be the script itself, or a file containing the script", "SCRIPT"); }, "Run a given script. SCRIPT can be the script itself, or a file containing the script", "SCRIPT");
Cmdline.orders.script = Cmdline.orders.run;
Cmdline.print_order = function(fn) Cmdline.print_order = function(fn)
{ {
if (typeof fn === 'string') if (typeof fn === 'string')
@ -388,66 +408,41 @@ function cmd_args(cmdargs)
} }
Cmdline.orders[cmds[0]](cmds.slice(1)); Cmdline.orders[cmds[0]](cmds.slice(1));
}
Cmdline.register_order("clean", function(argv) {
say("Cleaning not implemented.");
return; return;
for (var i = 1; i < cmds.length; i++) { var f = argv[0];
if (cmds[i][0] !== '-') { if (argv.length === 0) {
Log.warn(`Command '${cmds[i]}' should start with a '-'.`); Cmdline.print_order("clean");
continue; return;
} }
var c = Cmdline.cmds.find(function(cmd) { return cmd.flag === cmds[i].slice(1); }); if (!io.exists(f)) {
if (!c) { say(`File ${f} does not exist.`);
Log.warn(`Command ${cmds[i]} not recognized.`); return;
continue;
}
var sendstr = [];
var j = i+1;
while (cmds[j] && cmds[j][0] !== '-') {
sendstr.push(cmds[j]);
j++;
}
c.fn(sendstr);
i = j-1;
}
}
var STD = {};
STD.exit = function(status)
{
cmd(147,status);
}
Cmdline.register_cmd("l", function(n) {
Log.level = n;
}, "Set log level.");
Cmdline.register_cmd("cjson", function(json) {
var f = json[0];
if (!IO.exists(f)) {
Log.warn(`File ${f} does not exist.`);
STD.exit(1);
} }
prototypes.generate_ur(); prototypes.generate_ur();
var j = JSON.parse(IO.slurp(f)); var j = json.decode(io.slurp(f));
for (var k in j) { for (var k in j)
if (k in j.objects) if (k in j.objects)
delete j[k]; delete j[k];
}
Log.warn(j); console.warn(j);
for (var k in j.objects) { for (var k in j.objects) {
var o = j.objects[k]; var o = j.objects[k];
samediff(o, ur[o.ur]); samediff(o, ur[o.ur]);
} }
Log.say(j); say(j);
}, "Clean up a given object file.", "JSON ...");
STD.exit(0); Cmdline.register_cmd("l", function(n) {
}, "Clean up a jso file."); console.level = n;
}, "Set log level.");

View file

@ -345,7 +345,7 @@ texteditor.open_fn = function(fnstr)
{ {
var fn = eval(fnstr); var fn = eval(fnstr);
if (!fn) { if (!fn) {
Log.warn(`${fnstr} is not a function.`); console.warn(`${fnstr} is not a function.`);
return; return;
} }
this.src = fnstr; this.src = fnstr;

View file

@ -421,3 +421,12 @@ void free_drawmodel(struct drawmodel *dm) {
free(dm); free(dm);
} }
void material_free(material *mat)
{
}
void mesh_free(mesh *m)
{
}

View file

@ -189,8 +189,7 @@ void input_dropped_files(int n)
argv[0] = jstr("emacs"); argv[0] = jstr("emacs");
argv[1] = jstr("drop"); argv[1] = jstr("drop");
argv[2] = jstr("pressed"); argv[2] = jstr("pressed");
char *path = rebase_path(sapp_get_dropped_file_path(0)); argv[3] = str2js(sapp_get_dropped_file_path(0));
argv[3] = str2js(path+1);
script_callee(pawn_callee, 4, argv); script_callee(pawn_callee, 4, argv);
JS_FreeValue(js,argv[3]); JS_FreeValue(js,argv[3]);
} }
@ -323,6 +322,15 @@ int key_is_num(int key) {
void cursor_hide() { sapp_show_mouse(0); } void cursor_hide() { sapp_show_mouse(0); }
void cursor_show() { sapp_show_mouse(1); } void cursor_show() { sapp_show_mouse(1); }
void cursor_img(const char *path)
{
/* NSString *str = [NSString stringWithUTF8String:path];
NSImage *img = [[NSImage alloc] initWithContentsOfFile:str];
NSCursor *custom = [[NSCursor alloc] initWithImage:img hotSpot:NSMakePoint(0,0)];
[custom set];
*/
}
int action_down(int key) { return key_states[key] == INPUT_DOWN; } int action_down(int key) { return key_states[key] == INPUT_DOWN; }
int action_up(int key) { return key_states[key] == INPUT_UP; } int action_up(int key) { return key_states[key] == INPUT_UP; }

View file

@ -18,6 +18,7 @@ void input_poll(double wait);
void cursor_hide(); void cursor_hide();
void cursor_show(); void cursor_show();
void cursor_img(const char *path);
void set_mouse_mode(int mousemode); void set_mouse_mode(int mousemode);
void input_mouse(int btn, int state, uint32_t mod); void input_mouse(int btn, int state, uint32_t mod);

View file

@ -25,9 +25,17 @@
#include <assert.h> #include <assert.h>
#include "resources.h" #include "resources.h"
#include <sokol/sokol_time.h> #include <sokol/sokol_time.h>
#include <sokol/sokol_app.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <sys/types.h> #include <sys/types.h>
#include <unistd.h>
#include <limits.h>
#if (defined(_WIN32) || defined(__WIN32__))
#include <direct.h>
#define mkdir(x,y) _mkdir(x)
#endif
#include "nota.h" #include "nota.h"
@ -90,6 +98,11 @@ static JSValue constraint2js(constraint *c)
static JSValue sound_proto; static JSValue sound_proto;
sound *js2sound(JSValue v) { return js2dsp_node(v)->data; } sound *js2sound(JSValue v) { return js2dsp_node(v)->data; }
#define QJSGLOBALCLASS(NAME) \
JSValue NAME = JS_NewObject(js); \
JS_SetPropertyFunctionList(js, NAME, js_##NAME##_funcs, countof(js_##NAME##_funcs)); \
JS_SetPropertyStr(js, globalThis, #NAME, NAME); \
#define QJSCLASSPREP(TYPE) \ #define QJSCLASSPREP(TYPE) \
JS_NewClassID(&js_##TYPE##_id);\ JS_NewClassID(&js_##TYPE##_id);\
JS_NewClass(JS_GetRuntime(js), js_##TYPE##_id, &js_##TYPE##_class);\ JS_NewClass(JS_GetRuntime(js), js_##TYPE##_id, &js_##TYPE##_class);\
@ -731,6 +744,15 @@ JSValue duk_cmd(JSContext *js, JSValueConst this, int argc, JSValueConst *argv)
gameobject_draw_debug(js2gameobject(argv[1])); gameobject_draw_debug(js2gameobject(argv[1]));
break; break;
case 16:
str = js2str(argv[1]);
file_eval_env(str,argv[2]);
break;
case 17:
sapp_set_mouse_cursor(js2int(argv[1]));
break;
case 18: case 18:
shape_set_sensor(js2ptr(argv[1]), JS_ToBool(js, argv[2])); shape_set_sensor(js2ptr(argv[1]), JS_ToBool(js, argv[2]));
break; break;
@ -1026,6 +1048,11 @@ JSValue duk_cmd(JSContext *js, JSValueConst this, int argc, JSValueConst *argv)
case 96: case 96:
id2sprite(js2int(argv[1]))->color = js2color(argv[2]); id2sprite(js2int(argv[1]))->color = js2color(argv[2]);
break; break;
case 97:
str = js2str(argv[1]);
cursor_img(str);
break;
case 103: case 103:
ret = vec2js(js2gameobject(argv[1])->scale.XY); ret = vec2js(js2gameobject(argv[1])->scale.XY);
break; break;
@ -1178,11 +1205,9 @@ JSValue duk_cmd(JSContext *js, JSValueConst this, int argc, JSValueConst *argv)
case 143: case 143:
str = JS_ToCString(js, argv[1]); str = JS_ToCString(js, argv[1]);
system(str); if (!getenv(str)) ret = JS_UNDEFINED;
break; else
ret = str2js(getenv(str));
case 144:
ret = str2js(DATA_PATH);
break; break;
case 145: case 145:
@ -1899,8 +1924,25 @@ JSValue js_emitter_emit(JSContext *js, JSValueConst this, int argc, JSValue *arg
return JS_UNDEFINED; return JS_UNDEFINED;
} }
static const JSCFunctionListEntry js_global_funcs[] = { JSValue js_os_cwd(JSContext *js, JSValueConst this)
{
char cwd[PATH_MAX];
getcwd(cwd, sizeof(cwd));
return str2js(cwd);
}
JSValue js_os_env(JSContext *js, JSValueConst this, int argc, JSValue *argv)
{
char *str = js2str(argv[0]);
JSValue ret = JS_UNDEFINED;
if (getenv(str)) ret = str2js(getenv(str));
JS_FreeCString(js,str);
return ret;
}
static const JSCFunctionListEntry js_os_funcs[] = {
MIST_CFUNC_DEF("cwd", 0, js_os_cwd),
MIST_CFUNC_DEF("env", 1, js_os_env),
}; };
static const JSCFunctionListEntry js_emitter_funcs[] = { static const JSCFunctionListEntry js_emitter_funcs[] = {
@ -2045,6 +2087,11 @@ JSValue duk_cmd_points(JSContext *js, JSValueConst this, int argc, JSValueConst
const char *STRTEST = "TEST STRING"; const char *STRTEST = "TEST STRING";
JSValue duk_profile_js2num(JSContext *js, JSValueConst this, int argc, JSValueConst *argv)
{
}
JSValue duk_profile(JSContext *js, JSValueConst this, int argc, JSValueConst *argv) JSValue duk_profile(JSContext *js, JSValueConst this, int argc, JSValueConst *argv)
{ {
int cmd = js2int(argv[0]); int cmd = js2int(argv[0]);
@ -2153,6 +2200,8 @@ void ffi_load() {
QJSCLASSPREP_FUNCS(warp_damp); QJSCLASSPREP_FUNCS(warp_damp);
QJSCLASSPREP_FUNCS(constraint); QJSCLASSPREP_FUNCS(constraint);
QJSGLOBALCLASS(os);
} }
void ffi_stop() void ffi_stop()

View file

@ -25,9 +25,6 @@
#include "core.cdb.h" #include "core.cdb.h"
char *DATA_PATH = NULL; /* The top level asset path, where the executable resides */
char *PREF_PATH = NULL; /* Path to where the program can write data to, usually for save files etc. */
char **prefabs; char **prefabs;
static const char *cur_ext = NULL; static const char *cur_ext = NULL;
@ -35,18 +32,10 @@ struct dirent *c_dirent = NULL;
char pathbuf[MAXPATH + 1]; char pathbuf[MAXPATH + 1];
const char *DB_NAME = "test.db";
static struct cdb corecdb; static struct cdb corecdb;
static struct cdb game_cdb; static struct cdb game_cdb;
void resources_init() { void resources_init() {
DATA_PATH = malloc(MAXPATH);
getcwd(DATA_PATH, MAXPATH);
if (!PREF_PATH)
PREF_PATH = strdup("./tmp/");
int fd = open("test.cdb", O_RDONLY); int fd = open("test.cdb", O_RDONLY);
cdb_init(&game_cdb, fd); cdb_init(&game_cdb, fd);
cdb_initf(&corecdb, core_cdb, core_cdb_len); cdb_initf(&corecdb, core_cdb, core_cdb_len);
@ -80,23 +69,6 @@ char *dirname(const char *path)
return dir; return dir;
} }
char *rebase_path(const char *path)
{
int off = 0;
while (path[off] == DATA_PATH[off]) {
off++;
if (!path[off] || !DATA_PATH[off]) break;
}
return path+off;
}
FILE *res_open(char *path, const char *tag) {
strncpy(pathbuf, DATA_PATH, MAXPATH);
strncat(pathbuf, path, MAXPATH);
FILE *f = fopen(pathbuf, tag);
return f;
}
char *seprint(char *fmt, ...) char *seprint(char *fmt, ...)
{ {
va_list args; va_list args;
@ -115,27 +87,6 @@ char *seprint(char *fmt, ...)
static char *ext_paths = NULL; static char *ext_paths = NULL;
#ifndef __EMSCRIPTEN__ #ifndef __EMSCRIPTEN__
static int ext_check(const char *path, const struct stat *sb, int typeflag) {
if (typeflag == FTW_F) {
const char *ext = strrchr(path, '.');
if (ext != NULL && !strcmp(ext, cur_ext)) {
char newstr[255];
strncpy(newstr, path, 255);
arrput(prefabs, newstr);
}
}
return 0;
}
void fill_extensions(char *paths, const char *path, const char *ext) {
cur_ext = ext;
arrfree(paths);
ext_paths = paths;
ftw(".", ext_check, 10);
}
static char **ls_paths = NULL; static char **ls_paths = NULL;
static int ls_ftw(const char *path, const struct stat *sb, int typeflag) static int ls_ftw(const char *path, const struct stat *sb, int typeflag)

View file

@ -8,7 +8,6 @@
extern char *DATA_PATH; extern char *DATA_PATH;
void resources_init(); void resources_init();
void fill_extensions(char *paths, const char *path, const char *ext);
char *get_filename_from_path(char *path, int extension); char *get_filename_from_path(char *path, int extension);
char *get_directory_from_path(char *path); char *get_directory_from_path(char *path);
char *str_replace_ext(const char *s, const char *newext); char *str_replace_ext(const char *s, const char *newext);
@ -16,7 +15,6 @@ FILE *res_open(char *path, const char *tag);
FILE *path_open(const char *tag, const char *fmt, ...); FILE *path_open(const char *tag, const char *fmt, ...);
char **ls(const char *path); char **ls(const char *path);
int cp(const char *p1, const char *p2); int cp(const char *p1, const char *p2);
char *rebase_path(const char *path); /* given a global path, rebase to the local structure */
int fexists(const char *path); int fexists(const char *path);
FILE *fopen_mkdir(const char *path, const char *mode); FILE *fopen_mkdir(const char *path, const char *mode);

View file

@ -277,7 +277,8 @@ void script_call_fn_arg(JSValue fn, JSValue arg)
void out_memusage(const char *file) void out_memusage(const char *file)
{ {
FILE *f = fopen_mkdir(file, "w"); FILE *f = fopen(file, "w");
if (!f) return;
JSMemoryUsage jsmem; JSMemoryUsage jsmem;
JS_ComputeMemoryUsage(rt, &jsmem); JS_ComputeMemoryUsage(rt, &jsmem);
JS_DumpMemoryUsage(f, &jsmem, rt); JS_DumpMemoryUsage(f, &jsmem, rt);

View file

@ -3770,6 +3770,7 @@ _SOKOL_PRIVATE void _sapp_macos_update_cursor(sapp_mouse_cursor cursor, bool sho
[_sapp.macos.cursors[cursor] set]; [_sapp.macos.cursors[cursor] set];
} }
else { else {
printf("CURSOR\n");
[[NSCursor arrowCursor] set]; [[NSCursor arrowCursor] set];
} }
} }

View file

@ -260,7 +260,7 @@ static sapp_desc start_desc = {
.logger.func = sg_logging, .logger.func = sg_logging,
}; };
void app_name(const char *name) { start_desc.window_title = strdup(name); } void app_name(const char *name) { sapp_set_window_title(name); }
int main(int argc, char **argv) { int main(int argc, char **argv) {
#ifndef NDEBUG #ifndef NDEBUG