Reorganize
This commit is contained in:
198
runtime/builtins.ts
Normal file
198
runtime/builtins.ts
Normal file
@ -0,0 +1,198 @@
|
||||
import {
|
||||
setPixelsInRect,
|
||||
clearScreen,
|
||||
fillRect,
|
||||
cameraPos,
|
||||
fillCircle,
|
||||
outlineCircle,
|
||||
fillEllipse,
|
||||
outlineEllipse,
|
||||
setPixelColor,
|
||||
} from "../io/window.ts";
|
||||
import { CHAR, Font, font } from "../data/font.ts";
|
||||
import { K, keyDown, keyPressed, keyReleased } from "../io/keyboard.ts";
|
||||
import { addToContext, runCode } from "./runcode.ts";
|
||||
import { resetRepl } from "../repl/repl.ts";
|
||||
import { COLOR } from "../data/colors.ts";
|
||||
import { getSheet, getCodeSheet, getMapSheet } from "../io/sheet.ts";
|
||||
import { saveCart, loadCart } from "../io/cart.ts";
|
||||
import { outlineRect } from "../util/util.ts";
|
||||
|
||||
let spritesheet: number | null = null;
|
||||
|
||||
export const getSpritesheet = () => {
|
||||
return spritesheet;
|
||||
}
|
||||
|
||||
export const useSpritesheet = (sheet: number) => {
|
||||
spritesheet = sheet;
|
||||
}
|
||||
|
||||
export const drawSprite = (x: number, y: number, spr: number) => {
|
||||
if (!spritesheet) {
|
||||
return;
|
||||
}
|
||||
const {sheet_type, value: sprites} = getSheet(spritesheet);
|
||||
if (sheet_type !== "spritesheet") {
|
||||
throw "Trying to run a non-code sheet as code."
|
||||
}
|
||||
setPixelsInRect(x, y, 8, sprites[spr]);
|
||||
}
|
||||
|
||||
export const drawIcon = (x: number, y: number, icon: Array<number>, color: number) => {
|
||||
setPixelsInRect(x, y, 8, icon.map(n => n*color));
|
||||
}
|
||||
|
||||
export const measureCharFont = (char: string, fnt: Font) => {
|
||||
return (fnt.chars[char]?.length ?? 0)/fnt.height;
|
||||
}
|
||||
|
||||
export const drawCharFont = (x: number, y: number, char: string, fnt: Font, color: number) => {
|
||||
const w = measureCharFont(char, fnt);
|
||||
if (!fnt.chars[char]) {
|
||||
return 0;
|
||||
}
|
||||
setPixelsInRect(x, y, w, fnt.chars[char].map(n => n*color));
|
||||
return w;
|
||||
}
|
||||
|
||||
export const drawTextFont = (x: number, y: number, text: string, fnt: Font, color?: number) => {
|
||||
let dx = 0;
|
||||
[...text].forEach((char) => {
|
||||
dx += 1+drawCharFont(x+dx, y, char, fnt, color ?? COLOR.WHITE);
|
||||
});
|
||||
return dx-1;
|
||||
}
|
||||
|
||||
export const measureTextFont = (text: string, fnt: Font) => {
|
||||
let w = 0;
|
||||
[...text].forEach((char) => {
|
||||
w += measureCharFont(char, fnt)+1;
|
||||
});
|
||||
return Math.max(0, w-1);
|
||||
}
|
||||
|
||||
export const drawText = (x: number, y: number, text: string, color?: number) => {
|
||||
return drawTextFont(x, y, text, font, color);
|
||||
}
|
||||
|
||||
export const measureText = (text: string) => {
|
||||
return measureTextFont(text, font);
|
||||
}
|
||||
|
||||
export const camera = (x: number, y: number) => {
|
||||
cameraPos.x = x;
|
||||
cameraPos.y = y;
|
||||
};
|
||||
|
||||
const faux = {
|
||||
// Graphics
|
||||
cls: () => {
|
||||
resetRepl();
|
||||
clearScreen();
|
||||
},
|
||||
camera,
|
||||
sprsht: useSpritesheet,
|
||||
spr: drawSprite,
|
||||
txt: drawText,
|
||||
rectfill: fillRect,
|
||||
rect: outlineRect,
|
||||
circfill: fillCircle,
|
||||
circ: outlineCircle,
|
||||
ovalfill: fillEllipse,
|
||||
oval: outlineEllipse,
|
||||
pset: setPixelColor,
|
||||
map: (mapSheet: number, tileX: number, tileY: number, screenX: number, screenY: number, tileW: number, tileH: number) => {
|
||||
const originalSpritesheet = getSpritesheet() ?? 0;
|
||||
getMapSheet(mapSheet).values.forEach(([sprSheet, spr], i) => {
|
||||
const x = i%64;
|
||||
const y = Math.floor(i/64);
|
||||
if (x >= tileX && y >= tileY && x < tileX + tileW && y < tileY + tileH) {
|
||||
useSpritesheet(sprSheet);
|
||||
drawSprite(screenX + (x-tileX)*8, screenY + (y-tileY)*8, spr);
|
||||
}
|
||||
});
|
||||
useSpritesheet(originalSpritesheet);
|
||||
},
|
||||
// Map
|
||||
mgetsht: (mapSheet: number, x: number, y: number) => {
|
||||
if (x < 0 || x >= 64 || y < 0 || y >= 64) {
|
||||
return undefined;
|
||||
}
|
||||
return getMapSheet(mapSheet).get(x, y)[0];
|
||||
},
|
||||
mgetspr: (mapSheet: number, x: number, y: number) => {
|
||||
if (x < 0 || x >= 64 || y < 0 || y >= 64) {
|
||||
return undefined;
|
||||
}
|
||||
return getMapSheet(mapSheet).get(x, y)[1];
|
||||
},
|
||||
// Temporarily removing mset, since it would overwrite static cart data
|
||||
// mset: (mapSheet: number, x: number, y: number, sprSheet: number, spr: number) => {
|
||||
// if (x < 0 || x >= 64 || y < 0 || y >= 64) {
|
||||
// return;
|
||||
// }
|
||||
// getMapSheet(mapSheet).set(x, y, [sprSheet, spr]);
|
||||
// },
|
||||
// Input
|
||||
[CHAR.UP]: K.ARROW_UP,
|
||||
[CHAR.DOWN]: K.ARROW_DOWN,
|
||||
[CHAR.LEFT]: K.ARROW_LEFT,
|
||||
[CHAR.RIGHT]: K.ARROW_RIGHT,
|
||||
btn: keyDown,
|
||||
btnp: keyPressed,
|
||||
btnr: keyReleased,
|
||||
// Cart
|
||||
save: saveCart,
|
||||
load: loadCart,
|
||||
// JS
|
||||
Array,
|
||||
BigInt: BigInt,
|
||||
Boolean,
|
||||
Date,
|
||||
Error,
|
||||
Function,
|
||||
Infinity: Infinity,
|
||||
JSON: JSON,
|
||||
Map,
|
||||
NaN: NaN,
|
||||
Number,
|
||||
Object,
|
||||
Promise,
|
||||
Proxy,
|
||||
Reflect: Reflect,
|
||||
RegExp,
|
||||
Set,
|
||||
String,
|
||||
Symbol: Symbol,
|
||||
WeakMap,
|
||||
WeakRef,
|
||||
WeakSet,
|
||||
isFinite,
|
||||
isNaN,
|
||||
parseFloat,
|
||||
parseInt,
|
||||
// Math
|
||||
max: Math.max,
|
||||
min: Math.min,
|
||||
floor: Math.floor,
|
||||
ceil: Math.ceil,
|
||||
sin: Math.sin,
|
||||
cos: Math.cos,
|
||||
atan2: Math.atan2,
|
||||
sqrt: Math.sqrt,
|
||||
abs: Math.abs,
|
||||
rand: Math.random,
|
||||
[CHAR.PI]: Math.PI,
|
||||
// Other
|
||||
code: (n: number) => {
|
||||
return runCode(getCodeSheet(n));
|
||||
},
|
||||
log: console.log,
|
||||
};
|
||||
|
||||
for (const key in faux) {
|
||||
addToContext(key, faux[key as keyof typeof faux]);
|
||||
}
|
||||
|
||||
export default faux;
|
61
runtime/runcode.ts
Normal file
61
runtime/runcode.ts
Normal file
@ -0,0 +1,61 @@
|
||||
// deno-lint-ignore no-explicit-any
|
||||
const builtins: any = {};
|
||||
|
||||
// deno-lint-ignore no-explicit-any
|
||||
const G: any = {};
|
||||
|
||||
// deno-lint-ignore no-explicit-any
|
||||
export const addToContext = (name: string, value: any) => {
|
||||
builtins[name] = value;
|
||||
}
|
||||
|
||||
export const getBuiltins = () => {
|
||||
return builtins;
|
||||
}
|
||||
|
||||
// deno-lint-ignore no-explicit-any
|
||||
const AsyncFunction = (async function () {}).constructor as any;
|
||||
|
||||
addToContext("eval", eval);
|
||||
|
||||
const context = new Proxy(G, {
|
||||
get: (target, prop) => {
|
||||
if (prop in builtins) {
|
||||
return builtins[prop as keyof typeof builtins];
|
||||
}
|
||||
return target[prop];
|
||||
},
|
||||
set: (target, prop, value) => {
|
||||
target[prop] = value;
|
||||
return true;
|
||||
},
|
||||
has: () => {
|
||||
return true;
|
||||
},
|
||||
});
|
||||
|
||||
export const runCode = async (code: string) => {
|
||||
try {
|
||||
new AsyncFunction(code);
|
||||
} catch (err) {
|
||||
throw err;
|
||||
}
|
||||
const fn = new AsyncFunction("context", `
|
||||
with (context) {
|
||||
${code}
|
||||
}
|
||||
`);
|
||||
return await fn(context);
|
||||
}
|
||||
|
||||
export const evalCode = (code: string) => {
|
||||
try {
|
||||
return runCode(`return eval("(${code.replaceAll('"', '\\"')})");`);
|
||||
} catch (err) {
|
||||
if (err.name === "SyntaxError") {
|
||||
return runCode(`return eval("${code.replaceAll('"', '\\"')}");`);
|
||||
} else {
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user