Compare commits
	
		
			80 Commits
		
	
	
		
			initial-id
			...
			deno-test-
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|   | 401a76da84 | ||
|   | 694eb006b9 | ||
|   | f8c1cebedb | ||
|   | 04f206814c | ||
|   | ae3fa89a8b | ||
|   | 79738cfb79 | ||
|   | d7fec98714 | ||
|   | 6dc5127926 | ||
|   | e955a4c00d | ||
|   | b394f81477 | ||
|   | ef8cb2c4cf | ||
|   | d68a207df6 | ||
|   | 26c0ff590c | ||
|   | 38eabd380a | ||
|   | 90b97a30bd | ||
|   | 292d1d365e | ||
|   | f8b3f5d645 | ||
|   | 194209f18f | ||
|   | 1211891f53 | ||
|   | 2ac5f3dff7 | ||
|   | b248a016a9 | ||
|   | 7f9e873323 | ||
|   | e5276de775 | ||
|   | a7ed7b87f2 | ||
|   | 8c750ac2dc | ||
|   | ad5acdeb12 | ||
|   | 107a5370b1 | ||
|   | 5ed92b5ff4 | ||
|   | c53373ea47 | ||
|   | 87d3e6fc9b | ||
|   | cc03a0e765 | ||
|   | fcf78f3d56 | ||
|   | 5760a3f03b | ||
|   | 6bd5f7ae01 | ||
|   | 3518538b39 | ||
|   | 86d8a8b166 | ||
|   | 13b600eb95 | ||
|   | 9f67a59033 | ||
|   | 64c889e16a | ||
|   | 471fa9e0b6 | ||
|   | 0adfdabffa | ||
|   | 2e3b689c16 | ||
|   | 24bed7bd89 | ||
|   | 5d4db0a914 | ||
|   | 60542b63c0 | ||
|   | 7bf0838e4e | ||
|   | 550f1b44b2 | ||
|   | 3ad23f3a91 | ||
|   | 9685568f90 | ||
|   | b02d5155bd | ||
|   | 4b99599b31 | ||
|   | 12bc0cb385 | ||
|   | 1fa58961fc | ||
|   | 99eb6b82f2 | ||
|   | 5e4b76ebb3 | ||
|   | 9d2dc99a32 | ||
|   | a3abb0d2d3 | ||
|   | 6c9710d4d9 | ||
|   | f2b5978cae | ||
|   | b87529bf56 | ||
|   | b58a0d8cb1 | ||
|   | 99655e663c | ||
|   | 2e8923e2e7 | ||
|   | e52c8c69a0 | ||
|   | 1e91232bd6 | ||
|   | 6b90d883e9 | ||
|   | 2a7003b443 | ||
|   | dca54e76ec | ||
|   | ce7da27cc3 | ||
|   | 1482288b0c | ||
|   | 7de521bd39 | ||
|   | 99a8c500c7 | ||
|   | 253b8e9567 | ||
|   | fdc8f97aee | ||
|   | a7b675d541 | ||
|   | 5d742d5964 | ||
|   | 1781ae3bba | ||
|   | 078b7806dd | ||
|   | e85dbb1a33 | ||
|   | d7c2d5adb9 | 
							
								
								
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | |||||||
|  | build | ||||||
							
								
								
									
										4
									
								
								.vscode/settings.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								.vscode/settings.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,4 @@ | |||||||
|  | { | ||||||
|  | 	"deno.enable": true, | ||||||
|  | 	"deno.unstable": true | ||||||
|  | } | ||||||
							
								
								
									
										11
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										11
									
								
								README.md
									
									
									
									
									
								
							| @@ -1,2 +1,13 @@ | |||||||
| # fantasy-console | # fantasy-console | ||||||
|  |  | ||||||
|  | To run,  | ||||||
|  | ``` | ||||||
|  | deno task run | ||||||
|  | ``` | ||||||
|  |  | ||||||
|  | To compile | ||||||
|  | ``` | ||||||
|  | deno task build | ||||||
|  | ``` | ||||||
|  |  | ||||||
|  | You may need to install `xsel` on Linux machines to use this. | ||||||
							
								
								
									
										195
									
								
								builtins.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										195
									
								
								builtins.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,195 @@ | |||||||
|  | import { | ||||||
|  | 	setPixelsInRect, | ||||||
|  | 	clearScreen, | ||||||
|  | 	fillRect, | ||||||
|  | cameraPos, | ||||||
|  | fillCircle, | ||||||
|  | outlineCircle, | ||||||
|  | fillEllipse, | ||||||
|  | outlineEllipse, | ||||||
|  | setPixelColor, | ||||||
|  | } from "./window.ts"; | ||||||
|  | import { CHAR, Font, font } from "./font.ts"; | ||||||
|  | import { K, keyDown, keyPressed, keyReleased } from "./keyboard.ts"; | ||||||
|  | import { addToContext, runCode } from "./runcode.ts"; | ||||||
|  | import { resetRepl } from "./repl.ts"; | ||||||
|  | import { COLOR } from "./colors.ts"; | ||||||
|  | import { getSheet, getCodeSheet, getMapSheet } from "./sheet.ts"; | ||||||
|  | import { saveCart, loadCart } from "./cart.ts"; | ||||||
|  | import { outlineRect } from "./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]; | ||||||
|  | 	}, | ||||||
|  | 	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, | ||||||
|  | 	// 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; | ||||||
							
								
								
									
										22
									
								
								cart.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								cart.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,22 @@ | |||||||
|  | import { path } from "./deps.ts"; | ||||||
|  | import initialCart from "./initialCart.json" assert { type: "json" }; | ||||||
|  | import { Sheet } from "./sheet.ts"; | ||||||
|  |  | ||||||
|  | let cart = initialCart as Array<Sheet>; | ||||||
|  |  | ||||||
|  | const virtualPathToRealPath = (virtualFname: string) => { | ||||||
|  | 	const realPath = path.join(".", "carts", ...virtualFname.split("/")); | ||||||
|  | 	return realPath; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export const saveCart = async (fname: string) => { | ||||||
|  | 	await Deno.writeTextFile(virtualPathToRealPath(fname+".fx"), JSON.stringify(getCart())); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export const loadCart = async (fname: string) => { | ||||||
|  | 	cart = JSON.parse(await Deno.readTextFile(virtualPathToRealPath(fname+".fx"))); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export const getCart = () => { | ||||||
|  | 	return cart; | ||||||
|  | } | ||||||
							
								
								
									
										1
									
								
								carts/empty.fx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								carts/empty.fx
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | |||||||
|  | [{"sheet_type":"code","value":""},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null}] | ||||||
							
								
								
									
										707
									
								
								carts/test.fx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										707
									
								
								carts/test.fx
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,707 @@ | |||||||
|  | [ | ||||||
|  | 	{ | ||||||
|  | 		"sheet_type": "code", | ||||||
|  | 		"value": "x = code(1);\nreturn {\n\tinit: () => {y = 0},\n\tupdate: () => {\n\t\ty += speed;\n\t\tif (y > 127) {\n\t\t\ty = -6\n\t\t}\n\t},\n\tdraw: () => {\n\t\tcls();\n\t\ttxt(x, y, 'hello world')\n\t}\n}" | ||||||
|  | 	}, | ||||||
|  | 	{ | ||||||
|  | 		"sheet_type": "code", | ||||||
|  | 		"value": "sprsht(15);\nspeed = 2;\nreturn 8;" | ||||||
|  | 	}, | ||||||
|  | 	{ | ||||||
|  | 		"sheet_type": "none", | ||||||
|  | 		"value": null | ||||||
|  | 	}, | ||||||
|  | 	{ | ||||||
|  | 		"sheet_type": "none", | ||||||
|  | 		"value": null | ||||||
|  | 	}, | ||||||
|  | 	{ | ||||||
|  | 		"sheet_type": "none", | ||||||
|  | 		"value": null | ||||||
|  | 	}, | ||||||
|  | 	{ | ||||||
|  | 		"sheet_type": "none", | ||||||
|  | 		"value": null | ||||||
|  | 	}, | ||||||
|  | 	{ | ||||||
|  | 		"sheet_type": "none", | ||||||
|  | 		"value": null | ||||||
|  | 	}, | ||||||
|  | 	{ | ||||||
|  | 		"sheet_type": "none", | ||||||
|  | 		"value": null | ||||||
|  | 	}, | ||||||
|  | 	{ | ||||||
|  | 		"sheet_type": "none", | ||||||
|  | 		"value": null | ||||||
|  | 	}, | ||||||
|  | 	{ | ||||||
|  | 		"sheet_type": "none", | ||||||
|  | 		"value": null | ||||||
|  | 	}, | ||||||
|  | 	{ | ||||||
|  | 		"sheet_type": "none", | ||||||
|  | 		"value": null | ||||||
|  | 	}, | ||||||
|  | 	{ | ||||||
|  | 		"sheet_type": "none", | ||||||
|  | 		"value": null | ||||||
|  | 	}, | ||||||
|  | 	{ | ||||||
|  | 		"sheet_type": "none", | ||||||
|  | 		"value": null | ||||||
|  | 	}, | ||||||
|  | 	{ | ||||||
|  | 		"sheet_type": "none", | ||||||
|  | 		"value": null | ||||||
|  | 	}, | ||||||
|  | 	{ | ||||||
|  | 		"sheet_type": "none", | ||||||
|  | 		"value": null | ||||||
|  | 	}, | ||||||
|  | 	{ | ||||||
|  | 		"sheet_type": "spritesheet", | ||||||
|  | 		"value": [ | ||||||
|  | 			[ | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 2, 0, 0, 2, 0, 0, | ||||||
|  | 				0, 0, 0, 2, 2, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 2, 2, 0, 0, 0, | ||||||
|  | 				0, 0, 2, 0, 0, 2, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0 | ||||||
|  | 			], | ||||||
|  | 			[ | ||||||
|  | 				1, 1, 1, 1, 1, 1, 1, 1, | ||||||
|  | 				1, 3, 3, 1, 1, 3, 3, 1, | ||||||
|  | 				1, 3, 3, 1, 1, 3, 3, 1, | ||||||
|  | 				1, 1, 1, 1, 1, 1, 1, 1, | ||||||
|  | 				1, 1, 1, 1, 1, 1, 1, 1, | ||||||
|  | 				1, 3, 3, 1, 1, 3, 3, 1, | ||||||
|  | 				1, 3, 3, 1, 1, 3, 3, 1, | ||||||
|  | 				1, 1, 1, 1, 1, 1, 1, 1 | ||||||
|  | 			], | ||||||
|  | 			[ | ||||||
|  | 				6, 6, 6, 4, 4, 4, 5, 5, | ||||||
|  | 				6, 6, 4, 4, 4, 5, 5, 5, | ||||||
|  | 				6, 4, 4, 4, 5, 5, 5, 6, | ||||||
|  | 				4, 4, 4, 5, 5, 5, 6, 6, | ||||||
|  | 				4, 4, 5, 5, 5, 6, 6, 6, | ||||||
|  | 				4, 5, 5, 5, 6, 6, 6, 4, | ||||||
|  | 				5, 5, 5, 6, 6, 6, 4, 4, | ||||||
|  | 				5, 5, 6, 6, 6, 4, 4, 4 | ||||||
|  | 			], | ||||||
|  | 			[ | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0 | ||||||
|  | 			], | ||||||
|  | 			[ | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0 | ||||||
|  | 			], | ||||||
|  | 			[ | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0 | ||||||
|  | 			], | ||||||
|  | 			[ | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0 | ||||||
|  | 			], | ||||||
|  | 			[ | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0 | ||||||
|  | 			], | ||||||
|  | 			[ | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0 | ||||||
|  | 			], | ||||||
|  | 			[ | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0 | ||||||
|  | 			], | ||||||
|  | 			[ | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0 | ||||||
|  | 			], | ||||||
|  | 			[ | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0 | ||||||
|  | 			], | ||||||
|  | 			[ | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0 | ||||||
|  | 			], | ||||||
|  | 			[ | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0 | ||||||
|  | 			], | ||||||
|  | 			[ | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0 | ||||||
|  | 			], | ||||||
|  | 			[ | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0 | ||||||
|  | 			], | ||||||
|  | 			[ | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0 | ||||||
|  | 			], | ||||||
|  | 			[ | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0 | ||||||
|  | 			], | ||||||
|  | 			[ | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0 | ||||||
|  | 			], | ||||||
|  | 			[ | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0 | ||||||
|  | 			], | ||||||
|  | 			[ | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0 | ||||||
|  | 			], | ||||||
|  | 			[ | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0 | ||||||
|  | 			], | ||||||
|  | 			[ | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0 | ||||||
|  | 			], | ||||||
|  | 			[ | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0 | ||||||
|  | 			], | ||||||
|  | 			[ | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0 | ||||||
|  | 			], | ||||||
|  | 			[ | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0 | ||||||
|  | 			], | ||||||
|  | 			[ | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0 | ||||||
|  | 			], | ||||||
|  | 			[ | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0 | ||||||
|  | 			], | ||||||
|  | 			[ | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0 | ||||||
|  | 			], | ||||||
|  | 			[ | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0 | ||||||
|  | 			], | ||||||
|  | 			[ | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0 | ||||||
|  | 			], | ||||||
|  | 			[ | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0 | ||||||
|  | 			], | ||||||
|  | 			[ | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0 | ||||||
|  | 			], | ||||||
|  | 			[ | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0 | ||||||
|  | 			], | ||||||
|  | 			[ | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0 | ||||||
|  | 			], | ||||||
|  | 			[ | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0 | ||||||
|  | 			], | ||||||
|  | 			[ | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0 | ||||||
|  | 			], | ||||||
|  | 			[ | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0 | ||||||
|  | 			], | ||||||
|  | 			[ | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0 | ||||||
|  | 			], | ||||||
|  | 			[ | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0 | ||||||
|  | 			], | ||||||
|  | 			[ | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0 | ||||||
|  | 			], | ||||||
|  | 			[ | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0 | ||||||
|  | 			], | ||||||
|  | 			[ | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0 | ||||||
|  | 			], | ||||||
|  | 			[ | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0 | ||||||
|  | 			], | ||||||
|  | 			[ | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0 | ||||||
|  | 			], | ||||||
|  | 			[ | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0 | ||||||
|  | 			], | ||||||
|  | 			[ | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0 | ||||||
|  | 			], | ||||||
|  | 			[ | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0 | ||||||
|  | 			], | ||||||
|  | 			[ | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0 | ||||||
|  | 			], | ||||||
|  | 			[ | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0 | ||||||
|  | 			], | ||||||
|  | 			[ | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0 | ||||||
|  | 			], | ||||||
|  | 			[ | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0 | ||||||
|  | 			], | ||||||
|  | 			[ | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0 | ||||||
|  | 			], | ||||||
|  | 			[ | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0 | ||||||
|  | 			], | ||||||
|  | 			[ | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0 | ||||||
|  | 			], | ||||||
|  | 			[ | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0 | ||||||
|  | 			], | ||||||
|  | 			[ | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0 | ||||||
|  | 			], | ||||||
|  | 			[ | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0 | ||||||
|  | 			], | ||||||
|  | 			[ | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0 | ||||||
|  | 			], | ||||||
|  | 			[ | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0 | ||||||
|  | 			], | ||||||
|  | 			[ | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0 | ||||||
|  | 			], | ||||||
|  | 			[ | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0 | ||||||
|  | 			], | ||||||
|  | 			[ | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0 | ||||||
|  | 			], | ||||||
|  | 			[ | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 				0, 0, 0, 0, 0, 0, 0, 0 | ||||||
|  | 			] | ||||||
|  | 		] | ||||||
|  | 	} | ||||||
|  | ] | ||||||
							
								
								
									
										1
									
								
								carts/tmp/circ.fx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								carts/tmp/circ.fx
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | |||||||
|  | [{"sheet_type":"code","value":"// Sample\n\nlet r = 0;\nlet d = 1;\nreturn {\n\tinit() {},\n\tupdate() {\n\t\tif (r >= 20) {\n\t\t\td = -1;\n\t\t} else if (r < 0) {\n\t\t\td = 1;\n\t\t}\n\t\tr += d*0.1;\t\n\t},\n\tdraw() {\n\t\tcls();\n\t\tcirc(50, 50, 6, 17);\n\t\ttxt(10,10,\"Hello, World!\");\n\t}\n}"},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null}] | ||||||
							
								
								
									
										1
									
								
								carts/tmp/cyandino.fx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								carts/tmp/cyandino.fx
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										1
									
								
								carts/tmp/maptest.fx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								carts/tmp/maptest.fx
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										1
									
								
								carts/tmp/oval.fx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								carts/tmp/oval.fx
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | |||||||
|  | [{"sheet_type":"code","value":"// Sample\n\nlet r = 0;\nlet d = 1;\nreturn {\n\tinit() {},\n\tupdate() {\n\t\tif (r >= 20) {\n\t\t\td = -1;\n\t\t} else if (r < 0) {\n\t\t\td = 1;\n\t\t}\n\t\tr += d*0.1;\t\n\t},\n\tdraw() {\n\t\tcls();\n\t\trectfill(50,50,46,21,6);\n\t\toval(50, 50, 95, 70, 17);\n\t\ttxt(10,10,\"Hello, World!\");\n\t}\n}"},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null}] | ||||||
							
								
								
									
										1
									
								
								carts/tmp/pa6.fx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								carts/tmp/pa6.fx
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										1
									
								
								carts/tmp/pa7.fx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								carts/tmp/pa7.fx
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										1
									
								
								carts/tmp/playingaround.fx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								carts/tmp/playingaround.fx
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | |||||||
|  | [{"sheet_type":"code","value":"\nx = 0;\nbool = true;\nstring = \"hi\";\n\nreturn {\n\tinit() {\n\t\t// init\n\t},\n\tupdate() {\n\t\t// update\n\t},\n\tdraw() {\n\t\t// draw\n\t\tcls();\n\t\ttxt(20, 20, \"hello, world\");\n\t}\n}"},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null}] | ||||||
							
								
								
									
										1
									
								
								carts/tmp/playingaround2.fx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								carts/tmp/playingaround2.fx
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | |||||||
|  | [{"sheet_type":"code","value":"\nx = 0;\nbool = true;\nstring = \"hi\";\ntext = code(1);\n\nreturn {\n\tinit() {\n\t\t// init\n\t},\n\tupdate() {\n\t\t// update\n\t},\n\tdraw() {\n\t\t// draw\n\t\tcls();\n\t\ttxt(20, 20, text);\n\t}\n}"},{"sheet_type":"code","value":"return \"hi from sheet 01.\";"},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null}] | ||||||
							
								
								
									
										1
									
								
								carts/tmp/playingaround3.fx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								carts/tmp/playingaround3.fx
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										1
									
								
								carts/tmp/playingaround4.fx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								carts/tmp/playingaround4.fx
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										1
									
								
								carts/tmp/playingaround5.fx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								carts/tmp/playingaround5.fx
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										1
									
								
								carts/tmp/some_sprites.fx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								carts/tmp/some_sprites.fx
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										694
									
								
								codetab.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										694
									
								
								codetab.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,694 @@ | |||||||
|  | import { clearScreen, fillRect } from "./window.ts"; | ||||||
|  | import { CHAR, font } from "./font.ts"; | ||||||
|  | import { drawText, measureText } from "./builtins.ts"; | ||||||
|  | import { COLOR } from "./colors.ts"; | ||||||
|  | import { getCodeSheet, setSheet } from "./sheet.ts"; | ||||||
|  | import { K, ctrlKeyDown, getKeyboardString, keyPressed, shiftKeyDown } from "./keyboard.ts"; | ||||||
|  | import { clipboard, tokenize } from "./deps.ts"; | ||||||
|  | import { getBuiltins } from "./runcode.ts"; | ||||||
|  | import { page } from "./viewsheets.ts"; | ||||||
|  | import { mouseDown, mouseHeld, mousePos } from "./mouse.ts"; | ||||||
|  |  | ||||||
|  | const historyDebounceFrames = 20; | ||||||
|  |  | ||||||
|  | const fontHeight = font.height; | ||||||
|  |  | ||||||
|  | const keywords = [ | ||||||
|  |     "break", | ||||||
|  |     "case", | ||||||
|  |     "catch", | ||||||
|  |     "class", | ||||||
|  |     "const", | ||||||
|  |     "continue", | ||||||
|  |     "debugger", | ||||||
|  |     "default", | ||||||
|  |     "delete", | ||||||
|  |     "do", | ||||||
|  |     "else", | ||||||
|  |     "export", | ||||||
|  |     "extends", | ||||||
|  |     "finally", | ||||||
|  |     "for", | ||||||
|  |     "function", | ||||||
|  |     "if", | ||||||
|  |     "import", | ||||||
|  |     "in", | ||||||
|  |     "instanceof", | ||||||
|  |     "new", | ||||||
|  |     "return", | ||||||
|  |     "super", | ||||||
|  |     "switch", | ||||||
|  |     "this", | ||||||
|  |     "throw", | ||||||
|  |     "try", | ||||||
|  |     "typeof", | ||||||
|  |     "var", | ||||||
|  |     "void", | ||||||
|  |     "while", | ||||||
|  |     "with", | ||||||
|  | 	"let", | ||||||
|  | 	"static", | ||||||
|  | 	"yield", | ||||||
|  | 	"await", | ||||||
|  | 	"enum", | ||||||
|  |     "implements", | ||||||
|  |     "interface", | ||||||
|  |     "package", | ||||||
|  |     "private", | ||||||
|  |     "protected", | ||||||
|  |     "public", | ||||||
|  | 	"=>", | ||||||
|  | ]; | ||||||
|  | const values = [ | ||||||
|  |     "false", | ||||||
|  |     "null", | ||||||
|  |     "true", | ||||||
|  | 	"undefined", | ||||||
|  | 	"NaN", | ||||||
|  | 	"Infinity", | ||||||
|  | 	CHAR.PI, | ||||||
|  | ]; | ||||||
|  | const operator = [ | ||||||
|  | 	"&&", | ||||||
|  | 	"||", | ||||||
|  | 	"??", | ||||||
|  | 	"--", | ||||||
|  | 	"++", | ||||||
|  | 	".", | ||||||
|  | 	"?.", | ||||||
|  | 	"<", | ||||||
|  | 	"<=", | ||||||
|  | 	">", | ||||||
|  | 	">=", | ||||||
|  | 	"!=", | ||||||
|  | 	"!==", | ||||||
|  | 	"==", | ||||||
|  | 	"===", | ||||||
|  | 	"+", | ||||||
|  | 	"-", | ||||||
|  | 	"%", | ||||||
|  | 	"&", | ||||||
|  | 	"|", | ||||||
|  | 	"^", | ||||||
|  | 	"/", | ||||||
|  | 	"*", | ||||||
|  | 	"**", | ||||||
|  | 	"<<", | ||||||
|  | 	">>", | ||||||
|  | 	">>>", | ||||||
|  | 	"=", | ||||||
|  | 	"+=", | ||||||
|  | 	"-=", | ||||||
|  | 	"%=", | ||||||
|  | 	"&=", | ||||||
|  | 	"|=", | ||||||
|  | 	"^=", | ||||||
|  | 	"/=", | ||||||
|  | 	"*=", | ||||||
|  | 	"**=", | ||||||
|  | 	"<<=", | ||||||
|  | 	">>=", | ||||||
|  | 	">>>=", | ||||||
|  | 	"!", | ||||||
|  | 	"?", | ||||||
|  | 	"~", | ||||||
|  | 	"...", | ||||||
|  | ]; | ||||||
|  | const punctuation = [ | ||||||
|  | 	"(", | ||||||
|  | 	")", | ||||||
|  | 	"[", | ||||||
|  | 	"]", | ||||||
|  | 	"{", | ||||||
|  | 	"}", | ||||||
|  | 	".", | ||||||
|  | 	":", | ||||||
|  | 	";", | ||||||
|  | 	",", | ||||||
|  | ]; | ||||||
|  |  | ||||||
|  | const builtinColor = COLOR.BLUE; | ||||||
|  | const keywordColor = COLOR.PURPLE; | ||||||
|  | const operatorColor = COLOR.CYAN; | ||||||
|  | const valueColor = COLOR.ORANGE; | ||||||
|  | const stringColor = COLOR.GREEN; | ||||||
|  | const regexColor = COLOR.PINK; | ||||||
|  | const punctuationColor = COLOR.LIGHTGRAY; | ||||||
|  | const commentColor = COLOR.DARKGREEN; | ||||||
|  | const identifierColor = COLOR.YELLOW; | ||||||
|  | const invalidColor = COLOR.RED; | ||||||
|  |  | ||||||
|  | const caretColor = COLOR.WHITE; | ||||||
|  | const selectionColor = COLOR.DARKBLUE; | ||||||
|  |  | ||||||
|  | const backgroundColor = COLOR.DARKERBLUE; | ||||||
|  |  | ||||||
|  | const tokenColors = { | ||||||
|  | 	"StringLiteral": stringColor, | ||||||
|  | 	"NoSubstitutionTemplate": stringColor, | ||||||
|  | 	"TemplateHead": stringColor, | ||||||
|  | 	"TemplateMiddle": stringColor, | ||||||
|  | 	"TemplateTail": stringColor, | ||||||
|  | 	"RegularExpressionLiteral": regexColor, | ||||||
|  | 	"MultiLineComment": commentColor, | ||||||
|  | 	"SingleLineComment": commentColor, | ||||||
|  | 	"IdentifierName": identifierColor, | ||||||
|  | 	"PrivateIdentifier": identifierColor, | ||||||
|  | 	"NumericLiteral": valueColor, | ||||||
|  | 	"Punctuator": punctuationColor, | ||||||
|  | 	"WhiteSpace": punctuationColor, | ||||||
|  | 	"LineTerminatorSequence": punctuationColor, | ||||||
|  | 	"Invalid": invalidColor, | ||||||
|  | } | ||||||
|  |  | ||||||
|  | const transformForCopy = (text: string) => { | ||||||
|  | 	text = text.replaceAll(CHAR.UP, "⬆️"); | ||||||
|  | 	text = text.replaceAll(CHAR.LEFT, "⬅️"); | ||||||
|  | 	text = text.replaceAll(CHAR.DOWN, "⬇️"); | ||||||
|  | 	text = text.replaceAll(CHAR.RIGHT, "➡️"); | ||||||
|  | 	return text; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | const transformForPaste = (text: string) => { | ||||||
|  | 	let newstr = ""; | ||||||
|  | 	text = text.replaceAll("⬆️", CHAR.UP); | ||||||
|  | 	text = text.replaceAll("⬅️", CHAR.LEFT); | ||||||
|  | 	text = text.replaceAll("⬇️", CHAR.DOWN); | ||||||
|  | 	text = text.replaceAll("➡️", CHAR.RIGHT); | ||||||
|  | 	for (const char of text) { | ||||||
|  | 		if (char in font.chars) { | ||||||
|  | 			newstr += char; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return newstr; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | const state = { | ||||||
|  | 	doubleClickTimer: 0, | ||||||
|  | 	history: [] as Array<{code: string, anchor: number, focus: number}>, | ||||||
|  | 	historyDebounce: 0, | ||||||
|  | 	historyIndex: 0, | ||||||
|  | 	undo() { | ||||||
|  | 		console.log('undoing'); | ||||||
|  | 		if (this.historyIndex === this.history.length && this.historyDebounce > 0) { | ||||||
|  | 			this.snapshot(); | ||||||
|  | 		} | ||||||
|  | 		console.log('historyIndex', this.historyIndex); | ||||||
|  | 		if (this.historyIndex > 0) { | ||||||
|  | 			this.historyIndex -= 1; | ||||||
|  | 			const snap = this.history[this.historyIndex]; | ||||||
|  | 			console.log('historyIndex', this.historyIndex); | ||||||
|  | 			this.code = snap.code; | ||||||
|  | 			this.setSelection(snap.anchor, snap.focus); | ||||||
|  | 		} | ||||||
|  | 	}, | ||||||
|  | 	redo() { | ||||||
|  | 		console.log('redoing'); | ||||||
|  | 		if (this.historyIndex < this.history.length-1) { | ||||||
|  | 			this.historyIndex += 1; | ||||||
|  | 			const snap = this.history[this.historyIndex]; | ||||||
|  | 			this.code = snap.code; | ||||||
|  | 			this.setSelection(snap.anchor, snap.focus); | ||||||
|  | 		} | ||||||
|  | 	}, | ||||||
|  | 	snapshot() { | ||||||
|  | 		const snap = { | ||||||
|  | 			code: this.code, | ||||||
|  | 			anchor: this.anchor, | ||||||
|  | 			focus: this.focus, | ||||||
|  | 		}; | ||||||
|  | 		this.history.push(snap); | ||||||
|  | 		console.log('took snapshot', this.historyIndex, snap); | ||||||
|  | 	}, | ||||||
|  | 	startSnapping() { | ||||||
|  | 		console.log('start snapping', this.historyIndex); | ||||||
|  | 		if (this.historyDebounce <= 0) { | ||||||
|  | 			this.historyIndex += 1; | ||||||
|  | 		} | ||||||
|  | 		if (this.history.length > this.historyIndex) { | ||||||
|  | 			this.history.length = this.historyIndex; | ||||||
|  | 		} | ||||||
|  | 		this.historyDebounce = historyDebounceFrames; | ||||||
|  | 	}, | ||||||
|  | 	wordMode: false, | ||||||
|  | 	scrollX: 0, | ||||||
|  | 	scrollY: 0, | ||||||
|  | 	anchor: 0, | ||||||
|  | 	focus: 0, | ||||||
|  | 	get focusX() {return indexToGrid(this.code, this.focus).x;}, | ||||||
|  | 	get focusY() {return indexToGrid(this.code, this.focus).y;}, | ||||||
|  | 	get anchorX() {return indexToGrid(this.code, this.anchor).x;}, | ||||||
|  | 	get anchorY() {return indexToGrid(this.code, this.anchor).y;}, | ||||||
|  | 	get focusPixelX() {return indexToRect(this.code, this.focus).x;}, | ||||||
|  | 	get focusPixelY() {return indexToRect(this.code, this.focus).y;}, | ||||||
|  | 	get anchorPixelX() {return indexToRect(this.code, this.anchor).x;}, | ||||||
|  | 	get anchorPixelY() {return indexToRect(this.code, this.anchor).y;}, | ||||||
|  | 	isCollapsed() { | ||||||
|  | 		return this.anchor === this.focus; | ||||||
|  | 	}, | ||||||
|  | 	clampInRange(n: number) { | ||||||
|  | 		return Math.max(0, Math.min(n, this.code.length)) | ||||||
|  | 	}, | ||||||
|  | 	findNearestWordBoundaryLeft(index: number) { | ||||||
|  | 		if (index === this.code.length-1) { | ||||||
|  | 			return index; | ||||||
|  | 		} | ||||||
|  | 		const words1 = this.code.slice(0, index+1).split(/\b/g); | ||||||
|  | 		if (words1[words1.length-1].length === 1) { | ||||||
|  | 			return index; | ||||||
|  | 		} | ||||||
|  | 		const words = this.code.slice(0, index).split(/\b/g); | ||||||
|  | 		if (!words.length) { | ||||||
|  | 			return 0; | ||||||
|  | 		} | ||||||
|  | 		return index-words[words.length-1].length; | ||||||
|  | 	}, | ||||||
|  | 	findNearestWordBoundaryRight(index: number) { | ||||||
|  | 		if (index === 0) { | ||||||
|  | 			return index; | ||||||
|  | 		} | ||||||
|  | 		const words1 = this.code.slice(index-1).split(/\b/g); | ||||||
|  | 		if (words1[0].length === 1) { | ||||||
|  | 			return index; | ||||||
|  | 		} | ||||||
|  | 		const words = this.code.slice(index).split(/\b/g); | ||||||
|  | 		if (!words.length) { | ||||||
|  | 			return this.code.length; | ||||||
|  | 		} | ||||||
|  | 		return index+words[0].length; | ||||||
|  | 	}, | ||||||
|  | 	setSelection(anchor: number | {x: number, y: number}, focus?: number | {x: number, y: number}) { | ||||||
|  | 		if (typeof anchor !== "number") { | ||||||
|  | 			anchor = gridToIndex(this.code, anchor.x, anchor.y); | ||||||
|  | 		} | ||||||
|  | 		focus = focus ?? anchor; | ||||||
|  | 		if (typeof focus !== "number") { | ||||||
|  | 			focus = gridToIndex(this.code, focus.x, focus.y); | ||||||
|  | 		} | ||||||
|  | 		this.anchor = this.clampInRange(anchor); | ||||||
|  | 		this.focus = this.clampInRange(focus); | ||||||
|  | 		if (this.wordMode) { | ||||||
|  | 			console.log('word mode', this.anchor, this.focus, this.findNearestWordBoundaryLeft(this.anchor), this.findNearestWordBoundaryRight(this.focus)); | ||||||
|  | 			if (this.anchor <= this.focus) { | ||||||
|  | 				this.anchor = this.findNearestWordBoundaryLeft(this.anchor); | ||||||
|  | 				this.focus = this.findNearestWordBoundaryRight(this.focus); | ||||||
|  | 			} else { | ||||||
|  | 				this.anchor = this.findNearestWordBoundaryRight(this.anchor); | ||||||
|  | 				this.focus = this.findNearestWordBoundaryLeft(this.focus); | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 		this.anchor = this.clampInRange(this.anchor); | ||||||
|  | 		this.focus = this.clampInRange(this.focus); | ||||||
|  | 	}, | ||||||
|  | 	setFocus(focus: number | {x: number, y: number}) { | ||||||
|  | 		if (typeof focus !== "number") { | ||||||
|  | 			focus = gridToIndex(this.code, focus.x, focus.y); | ||||||
|  | 		} | ||||||
|  | 		this.focus = this.clampInRange(focus); | ||||||
|  | 		if (this.wordMode) { | ||||||
|  | 			if (this.anchor <= this.focus) { | ||||||
|  | 				this.anchor = this.findNearestWordBoundaryLeft(this.anchor); | ||||||
|  | 				this.focus = this.findNearestWordBoundaryRight(this.focus); | ||||||
|  | 			} else { | ||||||
|  | 				this.anchor = this.findNearestWordBoundaryRight(this.anchor); | ||||||
|  | 				this.focus = this.findNearestWordBoundaryLeft(this.focus); | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 		this.focus = this.clampInRange(this.focus); | ||||||
|  | 	}, | ||||||
|  | 	insertText(text: string) { | ||||||
|  | 		const {code, anchor, focus} = this; | ||||||
|  | 		this.code = code.slice(0, Math.min(anchor, focus)) + text + code.slice(Math.max(anchor, focus)); | ||||||
|  | 		this.setSelection(Math.min(anchor, focus) + text.length); | ||||||
|  | 		this.startSnapping(); | ||||||
|  | 	}, | ||||||
|  | 	toggleComment() { | ||||||
|  | 		const lines = this.code.split("\n"); | ||||||
|  | 		const {focusX, focusY, anchorX, anchorY} = this; | ||||||
|  | 		const lineInSelection = (i: number) => i >= Math.min(focusY, anchorY) && i <= Math.max(focusY, anchorY); | ||||||
|  | 		const allLinesAreCommented = lines.every((line, i) => { | ||||||
|  | 			if (lineInSelection(i) && !line.trim().startsWith("// ")) { | ||||||
|  | 				return false; | ||||||
|  | 			} else { | ||||||
|  | 				return true; | ||||||
|  | 			} | ||||||
|  | 		}); | ||||||
|  | 		const newLines = lines.map((line, i) => { | ||||||
|  | 			if (lineInSelection(i)) { | ||||||
|  | 				if (allLinesAreCommented) { | ||||||
|  | 					return line.slice(3); | ||||||
|  | 				} else { | ||||||
|  | 					return "// "+line; | ||||||
|  | 				} | ||||||
|  | 			} else { | ||||||
|  | 				return line; | ||||||
|  | 			} | ||||||
|  | 		}); | ||||||
|  | 		this.code = newLines.join("\n"); | ||||||
|  | 		const shiftBy = allLinesAreCommented ? -3 : 3; | ||||||
|  | 		this.setSelection({x: anchorX+shiftBy, y: anchorY}, {x: focusX+shiftBy, y: focusY}); | ||||||
|  | 		this.startSnapping(); | ||||||
|  | 	}, | ||||||
|  | 	indent(indentString: string) { | ||||||
|  | 		const lines = this.code.split("\n"); | ||||||
|  | 		const {focusX, focusY, anchorX, anchorY} = this; | ||||||
|  | 		const newLines = lines.map((line, i) => { | ||||||
|  | 			if (i >= Math.min(focusY, anchorY) && i <= Math.max(focusY, anchorY)) { | ||||||
|  | 				return indentString+line; | ||||||
|  | 			} else { | ||||||
|  | 				return line; | ||||||
|  | 			} | ||||||
|  | 		}); | ||||||
|  | 		this.code = newLines.join("\n"); | ||||||
|  | 		this.setSelection({x: anchorX+1, y: anchorY}, {x: focusX+1, y: focusY}); | ||||||
|  | 		this.startSnapping(); | ||||||
|  | 	}, | ||||||
|  | 	outdent(outdentRegex: RegExp) { | ||||||
|  | 		const lines = this.code.split("\n"); | ||||||
|  | 		const {focusX, focusY, anchorX, anchorY} = this; | ||||||
|  | 		const newLines = lines.map((line, i) => { | ||||||
|  | 			const match = line.match(outdentRegex); | ||||||
|  | 			if (i >= Math.min(focusY, anchorY) && i <= Math.max(focusY, anchorY) && match) { | ||||||
|  | 				return line.slice(match[0].length); | ||||||
|  | 			} else { | ||||||
|  | 				return line; | ||||||
|  | 			} | ||||||
|  | 		}); | ||||||
|  | 		this.code = newLines.join("\n"); | ||||||
|  | 		this.setSelection({x: Math.max(0,anchorX-1), y: anchorY}, {x: Math.max(0,focusX-1), y: focusY}); | ||||||
|  | 		this.startSnapping(); | ||||||
|  | 	}, | ||||||
|  | 	backspace() { | ||||||
|  | 		const {code, focus} = this; | ||||||
|  | 		if (this.isCollapsed()) { | ||||||
|  | 			if (focus > 0) { | ||||||
|  | 				this.code = code.slice(0, focus-1) + code.slice(focus); | ||||||
|  | 				this.setSelection(focus-1); | ||||||
|  | 				this.startSnapping(); | ||||||
|  | 			} | ||||||
|  | 		} else { | ||||||
|  | 			this.insertText(""); | ||||||
|  | 		} | ||||||
|  | 	}, | ||||||
|  | 	delete() { | ||||||
|  | 		const {code, focus} = this; | ||||||
|  | 		if (this.isCollapsed()) { | ||||||
|  | 			if (focus < code.length) { | ||||||
|  | 				this.code = code.slice(0, focus) + code.slice(1+focus); | ||||||
|  | 				this.startSnapping(); | ||||||
|  | 			} | ||||||
|  | 		} else { | ||||||
|  | 			this.insertText(""); | ||||||
|  | 		} | ||||||
|  | 	}, | ||||||
|  | 	async copy() { | ||||||
|  | 		const {code, anchor, focus} = this; | ||||||
|  | 		const selected = code.slice(Math.min(anchor,focus), Math.max(anchor,focus)); | ||||||
|  | 		await clipboard.writeText(transformForCopy(selected)); | ||||||
|  | 	}, | ||||||
|  | 	async cut() { | ||||||
|  | 		await this.copy(); | ||||||
|  | 		this.insertText(""); | ||||||
|  | 	}, | ||||||
|  | 	async paste() { | ||||||
|  | 		this.insertText(transformForPaste(await clipboard.readText())); | ||||||
|  | 	}, | ||||||
|  | 	scrollToCursor() { | ||||||
|  | 		const {focusY, scrollY, scrollX, focus} = this; | ||||||
|  | 		const fh = fontHeight + 1; | ||||||
|  | 		const rect = indexToRect(this.code, focus); | ||||||
|  | 		if (focusY*fh < scrollY) { | ||||||
|  | 			this.scrollY = focusY*fh; | ||||||
|  | 		} | ||||||
|  | 		if (focusY*fh > scrollY+112-fh) { | ||||||
|  | 			this.scrollY = focusY*fh-112+fh; | ||||||
|  | 		} | ||||||
|  | 		if (rect.x < scrollX) { | ||||||
|  | 			this.scrollX = rect.x; | ||||||
|  | 		} | ||||||
|  | 		if (rect.x+rect.w > scrollX+128) { | ||||||
|  | 			this.scrollX = rect.x-128+rect.w+1; | ||||||
|  | 		} | ||||||
|  | 	}, | ||||||
|  | 	currentIndentation() { | ||||||
|  | 		const lines = this.code.slice(0, this.focus).split("\n"); | ||||||
|  | 		const line = lines[lines.length-1]; | ||||||
|  | 		const match = line.match(/^\s*/); | ||||||
|  | 		if (!match) { | ||||||
|  | 			return ""; | ||||||
|  | 		} | ||||||
|  | 		return match[0]; | ||||||
|  | 	}, | ||||||
|  | 	get code() { | ||||||
|  | 		return getCodeSheet(page.activeSheet); | ||||||
|  | 	}, | ||||||
|  | 	set code(val) { | ||||||
|  | 		setSheet(page.activeSheet, "code", val); | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | const indexToGrid = (str: string, index: number) => { | ||||||
|  | 	const linesUpTo = str.slice(0,index).split("\n"); | ||||||
|  | 	return { | ||||||
|  | 		x: linesUpTo[linesUpTo.length-1].length, | ||||||
|  | 		y: linesUpTo.length - 1, | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | const gridToIndex = (str: string, x: number, y: number) => { | ||||||
|  | 	const lines = str.split("\n"); | ||||||
|  | 	if (y < 0) { | ||||||
|  | 		return 0; | ||||||
|  | 	} | ||||||
|  | 	if (y >= lines.length) { | ||||||
|  | 		return str.length; | ||||||
|  | 	} | ||||||
|  | 	return lines.slice(0, y).join("\n").length+Math.min(x, lines[y].length)+(y === 0 ? 0 : 1); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | const indexToRect = (str: string, index: number) => { | ||||||
|  | 	const linesUpTo = str.slice(0,index).split("\n"); | ||||||
|  | 	let extra = 0; | ||||||
|  | 	if (linesUpTo[linesUpTo.length-1].length > 0) { | ||||||
|  | 		extra = 1; | ||||||
|  | 	} | ||||||
|  | 	return { | ||||||
|  | 		x: measureText(linesUpTo[linesUpTo.length-1]) + extra, | ||||||
|  | 		y: (fontHeight + 1)*(linesUpTo.length - 1), | ||||||
|  | 		w: measureText(str[index] ?? "\n"), | ||||||
|  | 		h: fontHeight+1, | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | const pixelToIndex = (str: string, x: number, y: number) => { | ||||||
|  | 	const lines = str.split("\n"); | ||||||
|  | 	if (y < 0) { | ||||||
|  | 		return 0; | ||||||
|  | 	} | ||||||
|  | 	if (y >= (fontHeight+1)*lines.length) { | ||||||
|  | 		return str.length; | ||||||
|  | 	} | ||||||
|  | 	const yy = Math.floor(y/(fontHeight+1)); | ||||||
|  | 	const prefix = lines.slice(0, yy).join("\n").length+(yy === 0 ? 0 : 1); | ||||||
|  | 	const line = lines[yy]; | ||||||
|  | 	let j = 0; | ||||||
|  | 	while (measureText(line.slice(0, j)) < x && j < line.length) { | ||||||
|  | 		j+=1; | ||||||
|  | 	} | ||||||
|  | 	if (measureText(line) < x) { | ||||||
|  | 		j+=1; | ||||||
|  | 	} | ||||||
|  | 	return prefix + Math.max(0, j-1); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | const update = async () => { | ||||||
|  | 	const { focus } = state; | ||||||
|  | 	if (state.history.length === 0) { | ||||||
|  | 		state.snapshot(); | ||||||
|  | 	} | ||||||
|  | 	if (state.historyDebounce > 0) { | ||||||
|  | 		state.historyDebounce -= 1; | ||||||
|  | 		if (state.historyDebounce <= 0) { | ||||||
|  | 			state.snapshot(); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	if (state.doubleClickTimer > 0) { | ||||||
|  | 		state.doubleClickTimer -= 1; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if (mouseDown() && !shiftKeyDown()) { | ||||||
|  | 		if (state.doubleClickTimer > 0) { | ||||||
|  | 			state.wordMode = true; | ||||||
|  | 		} else { | ||||||
|  | 			state.doubleClickTimer = 10; | ||||||
|  | 		} | ||||||
|  | 		const {x, y} = mousePos(); | ||||||
|  | 		state.setSelection(pixelToIndex(state.code, x+state.scrollX, y+state.scrollY-8)); | ||||||
|  | 		state.scrollToCursor(); | ||||||
|  | 	} else if (mouseHeld()) { | ||||||
|  | 		const {x, y} = mousePos(); | ||||||
|  | 		state.setFocus(pixelToIndex(state.code, x+state.scrollX, y+state.scrollY-8)); | ||||||
|  | 		state.scrollToCursor(); | ||||||
|  | 	} else { | ||||||
|  | 		state.wordMode = false; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	const keyboardString = getKeyboardString(); | ||||||
|  | 	if (keyboardString) { | ||||||
|  | 		state.insertText(keyboardString); | ||||||
|  | 		state.scrollToCursor(); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if (keyPressed(K.ENTER)) { | ||||||
|  | 		state.insertText("\n"+state.currentIndentation()); | ||||||
|  | 		state.scrollToCursor(); | ||||||
|  | 	} | ||||||
|  | 	if (keyPressed(K.TAB)) { | ||||||
|  | 		if (!shiftKeyDown()) { | ||||||
|  | 			if (state.isCollapsed()) { | ||||||
|  | 				state.insertText("\t"); | ||||||
|  | 			} else { | ||||||
|  | 				state.indent("\t"); | ||||||
|  | 			} | ||||||
|  | 		} else { | ||||||
|  | 			state.outdent(/^(\t| )/); | ||||||
|  | 		} | ||||||
|  | 		state.scrollToCursor(); | ||||||
|  | 	} | ||||||
|  | 	if (keyPressed(K.BACKSPACE)) { | ||||||
|  | 		state.backspace(); | ||||||
|  | 		state.scrollToCursor(); | ||||||
|  | 	} | ||||||
|  | 	if (keyPressed(K.DELETE)) { | ||||||
|  | 		state.delete(); | ||||||
|  | 		state.scrollToCursor(); | ||||||
|  | 	} | ||||||
|  | 	if (keyPressed(K.ARROW_RIGHT)) { | ||||||
|  | 		if (shiftKeyDown()) { | ||||||
|  | 			state.setFocus(focus+1); | ||||||
|  | 		} else { | ||||||
|  | 			state.setSelection(focus+1); | ||||||
|  | 		} | ||||||
|  | 		state.scrollToCursor(); | ||||||
|  | 	} | ||||||
|  | 	if (keyPressed(K.ARROW_LEFT)) { | ||||||
|  | 		if (shiftKeyDown()) { | ||||||
|  | 			state.setFocus(focus-1); | ||||||
|  | 		} else { | ||||||
|  | 			state.setSelection(focus-1); | ||||||
|  | 		} | ||||||
|  | 		state.scrollToCursor(); | ||||||
|  | 	} | ||||||
|  | 	if (keyPressed(K.ARROW_DOWN)) { | ||||||
|  | 		const rect = indexToRect(state.code, focus); | ||||||
|  | 		const newIndex = pixelToIndex(state.code, rect.x, rect.y+rect.h+1+1); | ||||||
|  | 		if (shiftKeyDown()) { | ||||||
|  | 			state.setFocus(newIndex); | ||||||
|  | 		} else { | ||||||
|  | 			state.setSelection(newIndex); | ||||||
|  | 		} | ||||||
|  | 		state.scrollToCursor(); | ||||||
|  | 	} | ||||||
|  | 	if (keyPressed(K.ARROW_UP)) { | ||||||
|  | 		const rect = indexToRect(state.code, focus); | ||||||
|  | 		const newIndex = pixelToIndex(state.code, rect.x, rect.y-1-1); | ||||||
|  | 		if (shiftKeyDown()) { | ||||||
|  | 			state.setFocus(newIndex); | ||||||
|  | 		} else { | ||||||
|  | 			state.setSelection(newIndex); | ||||||
|  | 		} | ||||||
|  | 		state.scrollToCursor(); | ||||||
|  | 	} | ||||||
|  | 	if (keyPressed("C") && ctrlKeyDown()) { | ||||||
|  | 		await state.copy(); | ||||||
|  | 		state.scrollToCursor(); | ||||||
|  | 	} | ||||||
|  | 	if (keyPressed("X") && ctrlKeyDown()) { | ||||||
|  | 		await state.cut(); | ||||||
|  | 		state.scrollToCursor(); | ||||||
|  | 	} | ||||||
|  | 	if (keyPressed("V") && ctrlKeyDown()) { | ||||||
|  | 		await state.paste(); | ||||||
|  | 		state.scrollToCursor(); | ||||||
|  | 	} | ||||||
|  | 	if (keyPressed("Z") && ctrlKeyDown()) { | ||||||
|  | 		if (shiftKeyDown()) { | ||||||
|  | 			state.redo(); | ||||||
|  | 		} else { | ||||||
|  | 			state.undo(); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	if (keyPressed("Y") && ctrlKeyDown()) { | ||||||
|  | 		state.redo(); | ||||||
|  | 	} | ||||||
|  | 	if (keyPressed("/") && ctrlKeyDown()) { | ||||||
|  | 		state.toggleComment(); | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | const draw = () => { | ||||||
|  | 	clearScreen(); | ||||||
|  | 	const { | ||||||
|  | 		scrollX, | ||||||
|  | 		scrollY, | ||||||
|  | 		anchor, | ||||||
|  | 		focus, | ||||||
|  | 		code, | ||||||
|  | 	} = state; | ||||||
|  | 	const x = 0; | ||||||
|  | 	const y = 8; | ||||||
|  | 	const w = 128; | ||||||
|  | 	const h = 112; | ||||||
|  | 	fillRect(x, y, w, h, backgroundColor); | ||||||
|  | 	if (anchor !== focus) { | ||||||
|  | 		for (let i = Math.min(anchor, focus); i < Math.max(anchor, focus); i++) { | ||||||
|  | 			const sel = indexToRect(code, i); | ||||||
|  | 			fillRect(x+sel.x-scrollX, y+sel.y-scrollY, sel.w+2, sel.h, selectionColor); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	const rect = indexToRect(code, focus); | ||||||
|  | 	fillRect(x+rect.x-scrollX, y+rect.y-scrollY, 1, rect.h, caretColor); | ||||||
|  |  | ||||||
|  | 	const builtins = Object.keys(getBuiltins()); | ||||||
|  | 	const tokens = [...tokenize(code)]; | ||||||
|  | 	let cx = 0; | ||||||
|  | 	let cy = 0; | ||||||
|  | 	tokens.forEach((token) => { | ||||||
|  | 		if (token.type === "LineTerminatorSequence") { | ||||||
|  | 			cx=0; | ||||||
|  | 			cy+=fontHeight+1; | ||||||
|  | 			return; | ||||||
|  | 		} | ||||||
|  | 		const lines = token.value.split("\n"); | ||||||
|  | 		lines.forEach((line, i) => { | ||||||
|  | 			let color = tokenColors[token.type]; | ||||||
|  | 			if (builtins.includes(token.value)) { | ||||||
|  | 				color = builtinColor; | ||||||
|  | 			} | ||||||
|  | 			if (keywords.includes(token.value)) { | ||||||
|  | 				color = keywordColor; | ||||||
|  | 			} | ||||||
|  | 			if (values.includes(token.value)) { | ||||||
|  | 				color = valueColor; | ||||||
|  | 			} | ||||||
|  | 			if (operator.includes(token.value)) { | ||||||
|  | 				color = operatorColor; | ||||||
|  | 			} | ||||||
|  | 			if (punctuation.includes(token.value)) { | ||||||
|  | 				color = punctuationColor; | ||||||
|  | 			} | ||||||
|  | 			drawText(1+x+cx-scrollX, 1+y+cy-scrollY, line, color); | ||||||
|  | 			if (i === lines.length-1) { | ||||||
|  | 				cx += measureText(line)+1; | ||||||
|  | 			} else { | ||||||
|  | 				cx=0; | ||||||
|  | 				cy+=fontHeight+1; | ||||||
|  | 			} | ||||||
|  | 		}); | ||||||
|  | 	}) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export const codetab = { | ||||||
|  | 	update, | ||||||
|  | 	draw, | ||||||
|  | } | ||||||
							
								
								
									
										119
									
								
								colors.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										119
									
								
								colors.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,119 @@ | |||||||
|  | const hue_gray = 230; | ||||||
|  | const hue_brown = 30; | ||||||
|  | const hue_orange = 37; | ||||||
|  | const hue_purple = 280; | ||||||
|  | const hue_pink = 310; | ||||||
|  | const hue_red = 340; | ||||||
|  | const hue_red_shade = 335; | ||||||
|  | const hue_yellow = 57; | ||||||
|  | const hue_green = 130; | ||||||
|  | const hue_green_shade = 145; | ||||||
|  | const hue_sky = 203; | ||||||
|  | const hue_blue = 224; | ||||||
|  | const hue_blue_shade = 235; | ||||||
|  | const hue_blue_shade_2 = 240; | ||||||
|  |  | ||||||
|  | const saturation_max = 90; | ||||||
|  | const saturation_normal = 60; | ||||||
|  | const saturation_low = 40; | ||||||
|  | const saturation_min = 13; | ||||||
|  |  | ||||||
|  | const lightness_max = 95; | ||||||
|  | const lightness_light = 67; | ||||||
|  | const lightness_mediumlight = 62; | ||||||
|  | const lightness_medium = 50; | ||||||
|  | const lightness_mediumdark = 40; | ||||||
|  | const lightness_dark = 30; | ||||||
|  | const lightness_almostverydark = 25; | ||||||
|  | const lightness_verydark = 20; | ||||||
|  | const lightness_min = 5; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Converts an HSL color value to RGB. Conversion formula | ||||||
|  |  * adapted from http://en.wikipedia.org/wiki/HSL_color_space. | ||||||
|  |  * Assumes h, s, and l are contained in the set [0, 1] and | ||||||
|  |  * returns r, g, and b in the set [0, 255]. | ||||||
|  |  * | ||||||
|  |  * @param   Number  h       The hue | ||||||
|  |  * @param   Number  s       The saturation | ||||||
|  |  * @param   Number  l       The lightness | ||||||
|  |  * @return  Array           The RGB representation | ||||||
|  |  */ | ||||||
|  |  function hsl(h: number, s: number, l: number): [number, number, number] { | ||||||
|  | 	h = h / 360; | ||||||
|  | 	s = s/100; | ||||||
|  | 	l = l/100; | ||||||
|  | 	let r, g, b; | ||||||
|  |    | ||||||
|  | 	if (s == 0) { | ||||||
|  | 	  r = g = b = l; // achromatic | ||||||
|  | 	} else { | ||||||
|  | 	  const hue2rgb = (p: number, q: number, t: number) => { | ||||||
|  | 		if (t < 0) t += 1; | ||||||
|  | 		if (t > 1) t -= 1; | ||||||
|  | 		if (t < 1/6) return p + (q - p) * 6 * t; | ||||||
|  | 		if (t < 1/2) return q; | ||||||
|  | 		if (t < 2/3) return p + (q - p) * (2/3 - t) * 6; | ||||||
|  | 		return p; | ||||||
|  | 	  } | ||||||
|  |    | ||||||
|  | 	  const q = l < 0.5 ? l * (1 + s) : l + s - l * s; | ||||||
|  | 	  const p = 2 * l - q; | ||||||
|  |    | ||||||
|  | 	  r = hue2rgb(p, q, h + 1/3); | ||||||
|  | 	  g = hue2rgb(p, q, h); | ||||||
|  | 	  b = hue2rgb(p, q, h - 1/3); | ||||||
|  | 	} | ||||||
|  |    | ||||||
|  | 	return [ r , g , b ]; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | const colors = { | ||||||
|  | 	TRANSPARENT: [0, 0, 0], | ||||||
|  | 	BLACK2: [0, 0, 0], | ||||||
|  | 	BLACK3: [0, 0, 0], | ||||||
|  | 	BLACK4: [0, 0, 0], | ||||||
|  | 	WHITE: hsl(hue_gray, saturation_min, lightness_max), | ||||||
|  | 	LIGHTGRAY: hsl(hue_gray, saturation_min, lightness_light), | ||||||
|  | 	DARKGRAY: hsl(hue_gray, saturation_min, lightness_dark), | ||||||
|  | 	BLACK: hsl(hue_gray, saturation_min, lightness_min), | ||||||
|  | 	ORANGE: hsl(hue_orange, saturation_normal, lightness_medium), | ||||||
|  | 	TAN: hsl(hue_brown, saturation_low, lightness_light), | ||||||
|  | 	BROWN: hsl(hue_brown, saturation_low, lightness_mediumdark), | ||||||
|  | 	DARKBROWN: hsl(hue_brown, saturation_low, lightness_almostverydark), | ||||||
|  | 	PURPLE: hsl(hue_purple, saturation_normal, lightness_medium), | ||||||
|  | 	PINK: hsl(hue_pink, saturation_normal, lightness_light), | ||||||
|  | 	RED: hsl(hue_red, saturation_normal, lightness_medium), | ||||||
|  | 	DARKRED: hsl(hue_red_shade, saturation_normal, lightness_dark), | ||||||
|  | 	YELLOW: hsl(hue_yellow, saturation_max, lightness_mediumlight), | ||||||
|  | 	GREEN: hsl(hue_green, saturation_normal, lightness_medium), | ||||||
|  | 	DARKGREEN: hsl(hue_green_shade, saturation_normal, lightness_dark), | ||||||
|  | 	DARKERGREEN: hsl(hue_green_shade, saturation_normal, lightness_verydark), | ||||||
|  | 	CYAN: hsl(hue_sky, saturation_max, lightness_light), | ||||||
|  | 	BLUE: hsl(hue_blue, saturation_normal, lightness_medium), | ||||||
|  | 	DARKBLUE: hsl(hue_blue_shade, saturation_normal, lightness_mediumdark), | ||||||
|  | 	DARKERBLUE: hsl(hue_blue_shade_2, saturation_normal, lightness_dark), | ||||||
|  | } as const; | ||||||
|  |  | ||||||
|  | // const colors = { | ||||||
|  | // 	TRANSPARENT: [0, 0, 0], | ||||||
|  | // 	BLACK: [0, 0, 0], | ||||||
|  | // 	WHITE: [1, 1, 1], | ||||||
|  | // 	RED: [1, 0, 0], | ||||||
|  | // 	YELLOW: [1, 1, 0], | ||||||
|  | // 	GREEN: [0, 1, 0], | ||||||
|  | // 	BLUE: [0.1, 0.5, 1], | ||||||
|  | // 	DARKBLUE: [0.05, 0.1, 0.3], | ||||||
|  | // 	BROWN: [0.6, 0.5, 0.4], | ||||||
|  | // 	GRAY: [0.5, 0.5, 0.5], | ||||||
|  | // 	PURPLE: [0.7, 0.1, 0.85], | ||||||
|  | // 	ORANGE: [0.95, 0.75, 0.25], | ||||||
|  | // 	CYAN: [0, 0.9, 0.9], | ||||||
|  | // 	LIGHTGRAY: [0.75, 0.75, 0.75], | ||||||
|  | // 	REDDISH: [216/255, 59/255, 113/255], | ||||||
|  | // 	DARKGREEN: [0, 0.6, 0.2], | ||||||
|  | // } as const; | ||||||
|  |  | ||||||
|  | export const palette: Array<[number, number, number, number]> = Object.values(colors).map(val => [...val, 1]); | ||||||
|  |  | ||||||
|  | export const COLOR = Object.fromEntries(Object.keys(colors).map((name, i) => [name, Number(i)])) as {[key in keyof typeof colors]: number}; | ||||||
							
								
								
									
										11
									
								
								deno.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								deno.json
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,11 @@ | |||||||
|  | { | ||||||
|  | 	"fmt": { | ||||||
|  | 		"useTabs": true | ||||||
|  | 	}, | ||||||
|  | 	"tasks": { | ||||||
|  | 		"run": "deno run -A --unstable index.ts", | ||||||
|  | 		"build": "deno compile --output build/faux -A --unstable index.ts", | ||||||
|  | 		"build_linux": "deno compile --output build/faux_linux --target x86_64-unknown-linux-gnu -A --unstable index.ts", | ||||||
|  | 		"build_windows": "deno compile --output build/faux_windows --target x86_64-pc-windows-msvc -A --unstable index.ts" | ||||||
|  | 	} | ||||||
|  | } | ||||||
							
								
								
									
										73
									
								
								deno.lock
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						
									
										73
									
								
								deno.lock
									
									
									
										generated
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,73 @@ | |||||||
|  | { | ||||||
|  |   "version": "2", | ||||||
|  |   "remote": { | ||||||
|  |     "https://deno.land/std@0.186.0/_util/asserts.ts": "178dfc49a464aee693a7e285567b3d0b555dc805ff490505a8aae34f9cfb1462", | ||||||
|  |     "https://deno.land/std@0.186.0/_util/os.ts": "d932f56d41e4f6a6093d56044e29ce637f8dcc43c5a90af43504a889cf1775e3", | ||||||
|  |     "https://deno.land/std@0.186.0/path/_constants.ts": "e49961f6f4f48039c0dfed3c3f93e963ca3d92791c9d478ac5b43183413136e0", | ||||||
|  |     "https://deno.land/std@0.186.0/path/_interface.ts": "6471159dfbbc357e03882c2266d21ef9afdb1e4aa771b0545e90db58a0ba314b", | ||||||
|  |     "https://deno.land/std@0.186.0/path/_util.ts": "d7abb1e0dea065f427b89156e28cdeb32b045870acdf865833ba808a73b576d0", | ||||||
|  |     "https://deno.land/std@0.186.0/path/common.ts": "ee7505ab01fd22de3963b64e46cff31f40de34f9f8de1fff6a1bd2fe79380000", | ||||||
|  |     "https://deno.land/std@0.186.0/path/glob.ts": "d479e0a695621c94d3fd7fe7abd4f9499caf32a8de13f25073451c6ef420a4e1", | ||||||
|  |     "https://deno.land/std@0.186.0/path/mod.ts": "ee161baec5ded6510ee1d1fb6a75a0f5e4b41f3f3301c92c716ecbdf7dae910d", | ||||||
|  |     "https://deno.land/std@0.186.0/path/posix.ts": "8b7c67ac338714b30c816079303d0285dd24af6b284f7ad63da5b27372a2c94d", | ||||||
|  |     "https://deno.land/std@0.186.0/path/separator.ts": "0fb679739d0d1d7bf45b68dacfb4ec7563597a902edbaf3c59b50d5bcadd93b1", | ||||||
|  |     "https://deno.land/std@0.186.0/path/win32.ts": "d186344e5583bcbf8b18af416d13d82b35a317116e6460a5a3953508c3de5bba", | ||||||
|  |     "https://deno.land/std@0.97.0/_util/assert.ts": "2f868145a042a11d5ad0a3c748dcf580add8a0dbc0e876eaa0026303a5488f58", | ||||||
|  |     "https://deno.land/std@0.97.0/_util/os.ts": "e282950a0eaa96760c0cf11e7463e66babd15ec9157d4c9ed49cc0925686f6a7", | ||||||
|  |     "https://deno.land/std@0.97.0/encoding/base64.ts": "eecae390f1f1d1cae6f6c6d732ede5276bf4b9cd29b1d281678c054dc5cc009e", | ||||||
|  |     "https://deno.land/std@0.97.0/encoding/hex.ts": "f952e0727bddb3b2fd2e6889d104eacbd62e92091f540ebd6459317a61932d9b", | ||||||
|  |     "https://deno.land/std@0.97.0/fs/_util.ts": "f2ce811350236ea8c28450ed822a5f42a0892316515b1cd61321dec13569c56b", | ||||||
|  |     "https://deno.land/std@0.97.0/fs/ensure_dir.ts": "b7c103dc41a3d1dbbb522bf183c519c37065fdc234831a4a0f7d671b1ed5fea7", | ||||||
|  |     "https://deno.land/std@0.97.0/fs/exists.ts": "b0d2e31654819cc2a8d37df45d6b14686c0cc1d802e9ff09e902a63e98b85a00", | ||||||
|  |     "https://deno.land/std@0.97.0/hash/_wasm/hash.ts": "cb6ad1ab429f8ac9d6eae48f3286e08236d662e1a2e5cfd681ba1c0f17375895", | ||||||
|  |     "https://deno.land/std@0.97.0/hash/_wasm/wasm.js": "94b1b997ae6fb4e6d2156bcea8f79cfcd1e512a91252b08800a92071e5e84e1a", | ||||||
|  |     "https://deno.land/std@0.97.0/hash/hasher.ts": "57a9ec05dd48a9eceed319ac53463d9873490feea3832d58679df6eec51c176b", | ||||||
|  |     "https://deno.land/std@0.97.0/hash/mod.ts": "5d032bd34186cda2f8d17fc122d621430953a6030d4b3f11172004715e3e2441", | ||||||
|  |     "https://deno.land/std@0.97.0/path/_constants.ts": "1247fee4a79b70c89f23499691ef169b41b6ccf01887a0abd131009c5581b853", | ||||||
|  |     "https://deno.land/std@0.97.0/path/_interface.ts": "1fa73b02aaa24867e481a48492b44f2598cd9dfa513c7b34001437007d3642e4", | ||||||
|  |     "https://deno.land/std@0.97.0/path/_util.ts": "2e06a3b9e79beaf62687196bd4b60a4c391d862cfa007a20fc3a39f778ba073b", | ||||||
|  |     "https://deno.land/std@0.97.0/path/common.ts": "eaf03d08b569e8a87e674e4e265e099f237472b6fd135b3cbeae5827035ea14a", | ||||||
|  |     "https://deno.land/std@0.97.0/path/glob.ts": "314ad9ff263b895795208cdd4d5e35a44618ca3c6dd155e226fb15d065008652", | ||||||
|  |     "https://deno.land/std@0.97.0/path/mod.ts": "4465dc494f271b02569edbb4a18d727063b5dbd6ed84283ff906260970a15d12", | ||||||
|  |     "https://deno.land/std@0.97.0/path/posix.ts": "f56c3c99feb47f30a40ce9d252ef6f00296fa7c0fcb6dd81211bdb3b8b99ca3b", | ||||||
|  |     "https://deno.land/std@0.97.0/path/separator.ts": "8fdcf289b1b76fd726a508f57d3370ca029ae6976fcde5044007f062e643ff1c", | ||||||
|  |     "https://deno.land/std@0.97.0/path/win32.ts": "77f7b3604e0de40f3a7c698e8a79e7f601dc187035a1c21cb1e596666ce112f8", | ||||||
|  |     "https://deno.land/x/cache@0.2.13/deps.ts": "6f14e76a1a09f329e3f3830c6e72bd10b53a89a75769d5ea886e5d8603e503e6", | ||||||
|  |     "https://deno.land/x/cache@0.2.13/directories.ts": "ef48531cab3f827252e248596d15cede0de179a2fb15392ae24cf8034519994f", | ||||||
|  |     "https://deno.land/x/dwm@0.3.3/mod.ts": "8a8ca602442d250eaa7cef67c14245a41aa7dc8de2fa337008e433a2ed1fe2f1", | ||||||
|  |     "https://deno.land/x/dwm@0.3.3/src/core/common.ts": "dd4cd26f45fca187c5a6192bfb7b3b4a01a23c66dddf64e19e013de7748f988d", | ||||||
|  |     "https://deno.land/x/dwm@0.3.3/src/core/event.ts": "715cce309021e9dcd45b7e3f41bddea961d4b157dcf6f29a21e910825aae90a8", | ||||||
|  |     "https://deno.land/x/dwm@0.3.3/src/core/mod.ts": "4c54848365ea17b67e65d4d58c7c94378c9bbc6ea2a59d7d11f1d701e6a5483a", | ||||||
|  |     "https://deno.land/x/dwm@0.3.3/src/core/monitor.ts": "b291ebad386095285fb7c430990be0a9f1f5f81fbcb338058ce72a538a75d667", | ||||||
|  |     "https://deno.land/x/dwm@0.3.3/src/core/platform.ts": "6cab5f575198848673204673fe82d242c9c87549c16cbed9a64c838eb99dd2d4", | ||||||
|  |     "https://deno.land/x/dwm@0.3.3/src/core/window.ts": "1ccd738d6e4e28836327a76480c3c47855f617fa7ed7552a035f2d7bf0fd6c6d", | ||||||
|  |     "https://deno.land/x/dwm@0.3.3/src/platform/glfw/constants.ts": "832295fa6a4bd66aea638bd09ad2cc48b3756daff814c7c0ae2a544f228be9e5", | ||||||
|  |     "https://deno.land/x/dwm@0.3.3/src/platform/glfw/ffi.ts": "0c6a521a8374aa8c912417edfa5c263423286363f4a7c827d4d26ead8b954ee6", | ||||||
|  |     "https://deno.land/x/dwm@0.3.3/src/platform/glfw/monitor.ts": "05506c5d21c527a6ea456d24e00f88a01a9292a68f45a845499137ecb6fb80c7", | ||||||
|  |     "https://deno.land/x/dwm@0.3.3/src/platform/glfw/platform.ts": "cca2684151f34be392e74a9828f89f8c3ed46db25e59aec1f638b4ccf82535e9", | ||||||
|  |     "https://deno.land/x/dwm@0.3.3/src/platform/glfw/scancode_win.json": "711ee525f88fe92129acd7d66fd6a5665b68ce6a60f590ae24de67e1ee916b8f", | ||||||
|  |     "https://deno.land/x/dwm@0.3.3/src/platform/glfw/window.ts": "a6dd426a95cd93ba4905da151a0d06e9376becca273ee8bc8d1c9a7bd16e0d81", | ||||||
|  |     "https://deno.land/x/dwm@0.3.3/src/platform/mod.ts": "20572d937c62ec543e0ca87cf8ed32cd15505d254f97a6fae98b936e480f2157", | ||||||
|  |     "https://deno.land/x/gluten@0.1.6/api/gles23.2.ts": "99cad13b74938ff987a1a707f73d72a82ddf66935e45b59d1980928cd3af3495", | ||||||
|  |     "https://esm.sh/js-tokens@8.0.1": "7b08a51f91034b720edcde4f0b4314abc39ee14da57861e3e676f1ed1f4fb4ab", | ||||||
|  |     "https://esm.sh/v119/js-tokens@8.0.1/deno/js-tokens.mjs": "0fa55e76fa97785f8f938db8ea55e0db57825ea81cdcad20bd925f9902f678c1", | ||||||
|  |     "https://esm.sh/v119/js-tokens@8.0.1/index.d.ts": "9b178631a934bd5e4832b478d4f74083d4dc357615a0d1a632357dfafe898cdb", | ||||||
|  |     "https://glfw-binaries.deno.dev/3.4.0-patch2/glfw3_darwin.js": "48911f26fff723a9c5f2f38e39be42fc65ed8dea6f2ba1f1acb464d3f0aa435b", | ||||||
|  |     "https://glfw-binaries.deno.dev/3.4.0-patch2/glfw3_darwin_aarch64.js": "ae4d795d93830b8a27714ab6c20b69b67f3d4ad3544c50e344558756cf2e92f3", | ||||||
|  |     "https://glfw-binaries.deno.dev/3.4.0-patch2/glfw3_linux.js": "b064aedb175fee1a977937f07584238f313a1958f9869273e7e672c42f09932d", | ||||||
|  |     "https://glfw-binaries.deno.dev/3.4.0-patch2/glfw3_windows.js": "6ac603e03520c8c333e1475cb00f982adb1f8a99de7f4bb0b8953da66f210159", | ||||||
|  |     "https://raw.githubusercontent.com/Nisgrak/deno-clipboard/fix-deno-1.0.0/mod.ts": "85282325a499c75c6f9ed3603fc5f8baf4bf661a616add43b4e6f033def52680", | ||||||
|  |     "https://unpkg.com/js-tokens@8.0.1/index.js": "322c95254ceef0ac195f4e71adac2a90adf379a2d67fbb948402295a780fdbc0" | ||||||
|  |   }, | ||||||
|  |   "npm": { | ||||||
|  |     "specifiers": { | ||||||
|  |       "js-tokens": "js-tokens@8.0.1" | ||||||
|  |     }, | ||||||
|  |     "packages": { | ||||||
|  |       "js-tokens@8.0.1": { | ||||||
|  |         "integrity": "sha512-3AGrZT6tuMm1ZWWn9mLXh7XMfi2YtiLNPALCVxBCiUVq0LD1OQMxV/AdS/s7rLJU5o9i/jBZw/N4vXXL5dm29A==", | ||||||
|  |         "dependencies": {} | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | } | ||||||
							
								
								
									
										43
									
								
								deps.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								deps.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,43 @@ | |||||||
|  | // dwm | ||||||
|  | export { | ||||||
|  |   createWindow, | ||||||
|  |   getProcAddress, | ||||||
|  |   mainloop, | ||||||
|  | } from "https://deno.land/x/dwm@0.3.3/mod.ts"; | ||||||
|  | export * as gl from "https://deno.land/x/gluten@0.1.6/api/gles23.2.ts"; | ||||||
|  |  | ||||||
|  | // jsTokens | ||||||
|  | import jsTokens from "https://esm.sh/js-tokens@8.0.1"; | ||||||
|  | export function tokenize(input: string): Iterable<Token> { | ||||||
|  |   // deno-lint-ignore no-explicit-any | ||||||
|  |   return (jsTokens as any)(input); | ||||||
|  | } | ||||||
|  | type Token = | ||||||
|  |   | { type: "StringLiteral"; value: string; closed: boolean } | ||||||
|  |   | { type: "NoSubstitutionTemplate"; value: string; closed: boolean } | ||||||
|  |   | { type: "TemplateHead"; value: string } | ||||||
|  |   | { type: "TemplateMiddle"; value: string } | ||||||
|  |   | { type: "TemplateTail"; value: string; closed: boolean } | ||||||
|  |   | { type: "RegularExpressionLiteral"; value: string; closed: boolean } | ||||||
|  |   | { type: "MultiLineComment"; value: string; closed: boolean } | ||||||
|  |   | { type: "SingleLineComment"; value: string } | ||||||
|  |   | { type: "IdentifierName"; value: string } | ||||||
|  |   | { type: "PrivateIdentifier"; value: string } | ||||||
|  |   | { type: "NumericLiteral"; value: string } | ||||||
|  |   | { type: "Punctuator"; value: string } | ||||||
|  |   | { type: "WhiteSpace"; value: string } | ||||||
|  |   | { type: "LineTerminatorSequence"; value: string } | ||||||
|  |   | { type: "Invalid"; value: string }; | ||||||
|  |  | ||||||
|  | // clipboard | ||||||
|  | import { clipboard } from "https://raw.githubusercontent.com/Nisgrak/deno-clipboard/fix-deno-1.0.0/mod.ts"; | ||||||
|  | export { clipboard } from "https://raw.githubusercontent.com/Nisgrak/deno-clipboard/fix-deno-1.0.0/mod.ts"; | ||||||
|  | try { | ||||||
|  |   await clipboard.readText(); | ||||||
|  | } catch (err) { | ||||||
|  |   console.log("If you are running this on linux, please make sure you have 'xsel' installed."); | ||||||
|  |   throw err; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // path | ||||||
|  | export * as path from "https://deno.land/std@0.186.0/path/mod.ts"; | ||||||
							
								
								
									
										95
									
								
								editmode.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										95
									
								
								editmode.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,95 @@ | |||||||
|  | import { clearScreen, fillRect } from "./window.ts"; | ||||||
|  | import { codetab } from "./codetab.ts"; | ||||||
|  | import { spritetab } from "./spritetab.ts"; | ||||||
|  | import { viewsheets, page } from "./viewsheets.ts"; | ||||||
|  | import { COLOR } from "./colors.ts"; | ||||||
|  | import { mouseClick, mousePos } from "./mouse.ts"; | ||||||
|  | import { drawIcon } from "./builtins.ts"; | ||||||
|  | import { inRect } from "./util.ts"; | ||||||
|  | import { sheetsIcon, trashIcon } from "./icons.ts"; | ||||||
|  | import { SheetType, setSheet } from "./sheet.ts"; | ||||||
|  | import { nonetab } from "./nonetab.ts"; | ||||||
|  | import { maptab } from "./maptab.ts"; | ||||||
|  |  | ||||||
|  | type TabName = SheetType; // "code" | "sprite" | "map" | "sfx" | "music" | "sheet"; | ||||||
|  |  | ||||||
|  | const buttons: Array<{update: () => void, draw: () => void}> = []; | ||||||
|  | const makeTabButton = (tabname: TabName | "sheet", x: number, y: number, icon: Array<number>) => { | ||||||
|  | 	buttons.push({ | ||||||
|  | 		update() { | ||||||
|  | 			if (mouseClick()) { | ||||||
|  | 				const {x: mouseX, y: mouseY} = mousePos(); | ||||||
|  | 				if (inRect(mouseX, mouseY, x, y, 8, 8)) { | ||||||
|  | 					page.tab = tabname; | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 		}, | ||||||
|  | 		draw() { | ||||||
|  | 			drawIcon(x, y, icon, page.tab === tabname ? COLOR.YELLOW : COLOR.WHITE); | ||||||
|  | 		} | ||||||
|  | 	}) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | const makeTrashButton = (x: number, y: number, icon: Array<number>) => { | ||||||
|  | 	buttons.push({ | ||||||
|  | 		update() { | ||||||
|  | 			if (page.tab !== "sheet") { | ||||||
|  | 				return | ||||||
|  | 			} | ||||||
|  | 			if (mouseClick()) { | ||||||
|  | 				const {x: mouseX, y: mouseY} = mousePos(); | ||||||
|  | 				if (inRect(mouseX, mouseY, x, y, 8, 8)) { | ||||||
|  | 					setSheet(page.activeSheet, "none", null); | ||||||
|  | 					page.tab = "sheet"; | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 		}, | ||||||
|  | 		draw() { | ||||||
|  | 			if (page.tab !== "sheet") { | ||||||
|  | 				return | ||||||
|  | 			} | ||||||
|  | 			drawIcon(x, y, icon, COLOR.BLACK); | ||||||
|  | 		} | ||||||
|  | 	}) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | makeTabButton("sheet", 120, 0, sheetsIcon); | ||||||
|  | makeTrashButton(0, 0, trashIcon); | ||||||
|  |  | ||||||
|  | const update = () => { | ||||||
|  | 	buttons.forEach(button => button.update()); | ||||||
|  | 	if (page.tab === "code") { | ||||||
|  | 		codetab.update(); | ||||||
|  | 	} else if (page.tab === "spritesheet") { | ||||||
|  | 		spritetab.update(); | ||||||
|  | 	} else if (page.tab === "map") { | ||||||
|  | 		maptab.update(); | ||||||
|  | 	} else if (page.tab === "sheet") { | ||||||
|  | 		viewsheets.update(); | ||||||
|  | 	} else if (page.tab === "none") { | ||||||
|  | 		nonetab.update(); | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | const draw = () => { | ||||||
|  | 	clearScreen(); | ||||||
|  | 	if (page.tab === "code") { | ||||||
|  | 		codetab.draw(); | ||||||
|  | 	} else if (page.tab === "spritesheet") { | ||||||
|  | 		spritetab.draw(); | ||||||
|  | 	} else if (page.tab === "map") { | ||||||
|  | 		maptab.draw(); | ||||||
|  | 	} else if (page.tab === "sheet") { | ||||||
|  | 		viewsheets.draw(); | ||||||
|  | 	} else if (page.tab === "none") { | ||||||
|  | 		nonetab.draw(); | ||||||
|  | 	} | ||||||
|  | 	fillRect(0, 0, 128, 8, COLOR.RED); | ||||||
|  | 	fillRect(0, 120, 128, 8, COLOR.RED); | ||||||
|  | 	buttons.forEach(button => button.draw()); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export const editmode = { | ||||||
|  | 	update, | ||||||
|  | 	draw, | ||||||
|  | } | ||||||
							
								
								
									
										854
									
								
								font.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										854
									
								
								font.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,854 @@ | |||||||
|  | /** | ||||||
|  |  * Perhaps fonts can be their own type of sheet. By the calculation below, we can fit ~4 fonts per fontsheet | ||||||
|  |  *  | ||||||
|  |  * 3 bits for height | ||||||
|  |  * 5 more metadata bits | ||||||
|  |  * = 1 byte | ||||||
|  |  *  | ||||||
|  |  * Per character: | ||||||
|  |  * - 3 bits for width | ||||||
|  |  * - 5 bits for metadata | ||||||
|  |  * - 64 bits for pixels | ||||||
|  |  * = 9 bytes per character | ||||||
|  |  *  | ||||||
|  |  * 96 chars * 9 bytes =  | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | // export const fontWidth = 4; | ||||||
|  | // export const fontHeight = 6; | ||||||
|  |  | ||||||
|  | export const CHAR = { | ||||||
|  | 	UP: "À", | ||||||
|  | 	LEFT: "Á", | ||||||
|  | 	DOWN: "Â", | ||||||
|  | 	RIGHT: "Ã", | ||||||
|  | 	PI: "π" | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export type Font = { | ||||||
|  | 	height: 6, | ||||||
|  | 	chars: {[key: string]: Array<number>}, | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | // deno-fmt-ignore | ||||||
|  | export const font: Font = { | ||||||
|  | 	height: 6, | ||||||
|  | 	chars: { | ||||||
|  | 		"A": [ | ||||||
|  | 			1, 1, 1, | ||||||
|  | 			1, 0, 1, | ||||||
|  | 			1, 1, 1, | ||||||
|  | 			1, 0, 1, | ||||||
|  | 			1, 0, 1, | ||||||
|  | 			0, 0, 0, | ||||||
|  | 		], | ||||||
|  | 		"B": [ | ||||||
|  | 			1, 1, 1, | ||||||
|  | 			1, 0, 1, | ||||||
|  | 			1, 1, 0, | ||||||
|  | 			1, 0, 1, | ||||||
|  | 			1, 1, 1, | ||||||
|  | 			0, 0, 0, | ||||||
|  | 		], | ||||||
|  | 		"C": [ | ||||||
|  | 			0, 1, 1, | ||||||
|  | 			1, 0, 0, | ||||||
|  | 			1, 0, 0, | ||||||
|  | 			1, 0, 0, | ||||||
|  | 			0, 1, 1, | ||||||
|  | 			0, 0, 0, | ||||||
|  | 		], | ||||||
|  | 		"D": [ | ||||||
|  | 			1, 1, 0, | ||||||
|  | 			1, 0, 1, | ||||||
|  | 			1, 0, 1, | ||||||
|  | 			1, 0, 1, | ||||||
|  | 			1, 1, 0, | ||||||
|  | 			0, 0, 0, | ||||||
|  | 		], | ||||||
|  | 		"E": [ | ||||||
|  | 			1, 1, 1, | ||||||
|  | 			1, 0, 0, | ||||||
|  | 			1, 1, 0, | ||||||
|  | 			1, 0, 0, | ||||||
|  | 			1, 1, 1, | ||||||
|  | 			0, 0, 0, | ||||||
|  | 		], | ||||||
|  | 		"F": [ | ||||||
|  | 			1, 1, 1, | ||||||
|  | 			1, 0, 0, | ||||||
|  | 			1, 1, 0, | ||||||
|  | 			1, 0, 0, | ||||||
|  | 			1, 0, 0, | ||||||
|  | 			0, 0, 0, | ||||||
|  | 		], | ||||||
|  | 		"G": [ | ||||||
|  | 			0, 1, 1, | ||||||
|  | 			1, 0, 0, | ||||||
|  | 			1, 0, 1, | ||||||
|  | 			1, 0, 1, | ||||||
|  | 			0, 1, 1, | ||||||
|  | 			0, 0, 0, | ||||||
|  | 		], | ||||||
|  | 		"H": [ | ||||||
|  | 			1, 0, 1, | ||||||
|  | 			1, 0, 1, | ||||||
|  | 			1, 1, 1, | ||||||
|  | 			1, 0, 1, | ||||||
|  | 			1, 0, 1, | ||||||
|  | 			0, 0, 0, | ||||||
|  | 		], | ||||||
|  | 		"I": [ | ||||||
|  | 			1, 1, 1, | ||||||
|  | 			0, 1, 0, | ||||||
|  | 			0, 1, 0, | ||||||
|  | 			0, 1, 0, | ||||||
|  | 			1, 1, 1, | ||||||
|  | 			0, 0, 0, | ||||||
|  | 		], | ||||||
|  | 		"J": [ | ||||||
|  | 			1, 1, 1, | ||||||
|  | 			0, 1, 0, | ||||||
|  | 			0, 1, 0, | ||||||
|  | 			0, 1, 0, | ||||||
|  | 			1, 1, 0, | ||||||
|  | 			0, 0, 0, | ||||||
|  | 		], | ||||||
|  | 		"K": [ | ||||||
|  | 			1, 0, 1, | ||||||
|  | 			1, 0, 1, | ||||||
|  | 			1, 1, 0, | ||||||
|  | 			1, 0, 1, | ||||||
|  | 			1, 0, 1, | ||||||
|  | 			0, 0, 0, | ||||||
|  | 		], | ||||||
|  | 		"L": [ | ||||||
|  | 			1, 0, 0, | ||||||
|  | 			1, 0, 0, | ||||||
|  | 			1, 0, 0, | ||||||
|  | 			1, 0, 0, | ||||||
|  | 			1, 1, 1, | ||||||
|  | 			0, 0, 0, | ||||||
|  | 		], | ||||||
|  | 		"M": [ | ||||||
|  | 			1, 1, 1, | ||||||
|  | 			1, 1, 1, | ||||||
|  | 			1, 0, 1, | ||||||
|  | 			1, 0, 1, | ||||||
|  | 			1, 0, 1, | ||||||
|  | 			0, 0, 0, | ||||||
|  | 		], | ||||||
|  | 		"N": [ | ||||||
|  | 			1, 1, 0, | ||||||
|  | 			1, 0, 1, | ||||||
|  | 			1, 0, 1, | ||||||
|  | 			1, 0, 1, | ||||||
|  | 			1, 0, 1, | ||||||
|  | 			0, 0, 0, | ||||||
|  | 		], | ||||||
|  | 		"O": [ | ||||||
|  | 			0, 1, 1, | ||||||
|  | 			1, 0, 1, | ||||||
|  | 			1, 0, 1, | ||||||
|  | 			1, 0, 1, | ||||||
|  | 			1, 1, 0, | ||||||
|  | 			0, 0, 0, | ||||||
|  | 		], | ||||||
|  | 		"P": [ | ||||||
|  | 			1, 1, 1, | ||||||
|  | 			1, 0, 1, | ||||||
|  | 			1, 1, 1, | ||||||
|  | 			1, 0, 0, | ||||||
|  | 			1, 0, 0, | ||||||
|  | 			0, 0, 0, | ||||||
|  | 		], | ||||||
|  | 		"Q": [ | ||||||
|  | 			0, 1, 1, | ||||||
|  | 			1, 0, 1, | ||||||
|  | 			1, 0, 1, | ||||||
|  | 			1, 1, 0, | ||||||
|  | 			0, 1, 1, | ||||||
|  | 			0, 0, 0, | ||||||
|  | 		], | ||||||
|  | 		"R": [ | ||||||
|  | 			1, 1, 1, | ||||||
|  | 			1, 0, 1, | ||||||
|  | 			1, 1, 0, | ||||||
|  | 			1, 0, 1, | ||||||
|  | 			1, 0, 1, | ||||||
|  | 			0, 0, 0, | ||||||
|  | 		], | ||||||
|  | 		"S": [ | ||||||
|  | 			0, 1, 1, | ||||||
|  | 			1, 0, 0, | ||||||
|  | 			1, 1, 1, | ||||||
|  | 			0, 0, 1, | ||||||
|  | 			1, 1, 0, | ||||||
|  | 			0, 0, 0, | ||||||
|  | 		], | ||||||
|  | 		"T": [ | ||||||
|  | 			1, 1, 1, | ||||||
|  | 			0, 1, 0, | ||||||
|  | 			0, 1, 0, | ||||||
|  | 			0, 1, 0, | ||||||
|  | 			0, 1, 0, | ||||||
|  | 			0, 0, 0, | ||||||
|  | 		], | ||||||
|  | 		"U": [ | ||||||
|  | 			1, 0, 1, | ||||||
|  | 			1, 0, 1, | ||||||
|  | 			1, 0, 1, | ||||||
|  | 			1, 0, 1, | ||||||
|  | 			0, 1, 1, | ||||||
|  | 			0, 0, 0, | ||||||
|  | 		], | ||||||
|  | 		"V": [ | ||||||
|  | 			1, 0, 1, | ||||||
|  | 			1, 0, 1, | ||||||
|  | 			1, 0, 1, | ||||||
|  | 			1, 1, 1, | ||||||
|  | 			0, 1, 0, | ||||||
|  | 			0, 0, 0, | ||||||
|  | 		], | ||||||
|  | 		"W": [ | ||||||
|  | 			1, 0, 1, | ||||||
|  | 			1, 0, 1, | ||||||
|  | 			1, 0, 1, | ||||||
|  | 			1, 1, 1, | ||||||
|  | 			1, 1, 1, | ||||||
|  | 			0, 0, 0, | ||||||
|  | 		], | ||||||
|  | 		"X": [ | ||||||
|  | 			1, 0, 1, | ||||||
|  | 			1, 0, 1, | ||||||
|  | 			0, 1, 0, | ||||||
|  | 			1, 0, 1, | ||||||
|  | 			1, 0, 1, | ||||||
|  | 			0, 0, 0, | ||||||
|  | 		], | ||||||
|  | 		"Y": [ | ||||||
|  | 			1, 0, 1, | ||||||
|  | 			1, 0, 1, | ||||||
|  | 			1, 1, 1, | ||||||
|  | 			0, 1, 0, | ||||||
|  | 			1, 0, 0, | ||||||
|  | 			0, 0, 0, | ||||||
|  | 		], | ||||||
|  | 		"Z": [ | ||||||
|  | 			1, 1, 1, | ||||||
|  | 			0, 0, 1, | ||||||
|  | 			0, 1, 0, | ||||||
|  | 			1, 0, 0, | ||||||
|  | 			1, 1, 1, | ||||||
|  | 			0, 0, 0, | ||||||
|  | 		], | ||||||
|  | 		"a": [ | ||||||
|  | 			0, 0, 0, | ||||||
|  | 			1, 1, 1, | ||||||
|  | 			0, 1, 1, | ||||||
|  | 			1, 0, 1, | ||||||
|  | 			1, 1, 1, | ||||||
|  | 			0, 0, 0, | ||||||
|  | 		], | ||||||
|  | 		"b": [ | ||||||
|  | 			1, 0, 0, | ||||||
|  | 			1, 0, 0, | ||||||
|  | 			1, 1, 1, | ||||||
|  | 			1, 0, 1, | ||||||
|  | 			1, 1, 1, | ||||||
|  | 			0, 0, 0, | ||||||
|  | 		], | ||||||
|  | 		"c": [ | ||||||
|  | 			0, 0, 0, | ||||||
|  | 			0, 0, 0, | ||||||
|  | 			1, 1, 1, | ||||||
|  | 			1, 0, 0, | ||||||
|  | 			1, 1, 1, | ||||||
|  | 			0, 0, 0, | ||||||
|  | 		], | ||||||
|  | 		"d": [ | ||||||
|  | 			0, 0, 1, | ||||||
|  | 			0, 0, 1, | ||||||
|  | 			1, 1, 1, | ||||||
|  | 			1, 0, 1, | ||||||
|  | 			1, 1, 1, | ||||||
|  | 			0, 0, 0, | ||||||
|  | 		], | ||||||
|  | 		"e": [ | ||||||
|  | 			0, 0, 0, | ||||||
|  | 			0, 1, 1, | ||||||
|  | 			1, 0, 1, | ||||||
|  | 			1, 1, 0, | ||||||
|  | 			0, 1, 1, | ||||||
|  | 			0, 0, 0, | ||||||
|  | 		], | ||||||
|  | 		"f": [ | ||||||
|  | 			0, 1, 1, | ||||||
|  | 			1, 0, 0, | ||||||
|  | 			1, 1, 0, | ||||||
|  | 			1, 0, 0, | ||||||
|  | 			1, 0, 0, | ||||||
|  | 			0, 0, 0, | ||||||
|  | 		], | ||||||
|  | 		"g": [ | ||||||
|  | 			0, 0, 0, | ||||||
|  | 			0, 0, 0, | ||||||
|  | 			1, 1, 1, | ||||||
|  | 			1, 0, 1, | ||||||
|  | 			0, 1, 1, | ||||||
|  | 			1, 1, 0, | ||||||
|  | 		], | ||||||
|  | 		"h": [ | ||||||
|  | 			1, 0, 0, | ||||||
|  | 			1, 0, 0, | ||||||
|  | 			1, 1, 1, | ||||||
|  | 			1, 0, 1, | ||||||
|  | 			1, 0, 1, | ||||||
|  | 			0, 0, 0, | ||||||
|  | 		], | ||||||
|  | 		"i": [ | ||||||
|  | 			0, 1, 0, | ||||||
|  | 			0, 0, 0, | ||||||
|  | 			0, 1, 0, | ||||||
|  | 			0, 1, 0, | ||||||
|  | 			0, 1, 0, | ||||||
|  | 			0, 0, 0, | ||||||
|  | 		], | ||||||
|  | 		"j": [ | ||||||
|  | 			0, 1, 0, | ||||||
|  | 			0, 0, 0, | ||||||
|  | 			0, 1, 0, | ||||||
|  | 			0, 1, 0, | ||||||
|  | 			0, 1, 0, | ||||||
|  | 			1, 0, 0, | ||||||
|  | 		], | ||||||
|  | 		"k": [ | ||||||
|  | 			1, 0, 0, | ||||||
|  | 			1, 0, 0, | ||||||
|  | 			1, 0, 1, | ||||||
|  | 			1, 1, 0, | ||||||
|  | 			1, 0, 1, | ||||||
|  | 			0, 0, 0, | ||||||
|  | 		], | ||||||
|  | 		"l": [ | ||||||
|  | 			0, 1, 0, | ||||||
|  | 			0, 1, 0, | ||||||
|  | 			0, 1, 0, | ||||||
|  | 			0, 1, 0, | ||||||
|  | 			0, 0, 1, | ||||||
|  | 			0, 0, 0, | ||||||
|  | 		], | ||||||
|  | 		"m": [ | ||||||
|  | 			0, 0, 0, | ||||||
|  | 			0, 0, 0, | ||||||
|  | 			1, 1, 1, | ||||||
|  | 			1, 1, 1, | ||||||
|  | 			1, 0, 1, | ||||||
|  | 			0, 0, 0, | ||||||
|  | 		], | ||||||
|  | 		"n": [ | ||||||
|  | 			0, 0, 0, | ||||||
|  | 			0, 0, 0, | ||||||
|  | 			1, 1, 0, | ||||||
|  | 			1, 0, 1, | ||||||
|  | 			1, 0, 1, | ||||||
|  | 			0, 0, 0, | ||||||
|  | 		], | ||||||
|  | 		"o": [ | ||||||
|  | 			0, 0, 0, | ||||||
|  | 			0, 0, 0, | ||||||
|  | 			0, 1, 1, | ||||||
|  | 			1, 0, 1, | ||||||
|  | 			1, 1, 0, | ||||||
|  | 			0, 0, 0, | ||||||
|  | 		], | ||||||
|  | 		"p": [ | ||||||
|  | 			0, 0, 0, | ||||||
|  | 			0, 0, 0, | ||||||
|  | 			1, 1, 1, | ||||||
|  | 			1, 0, 1, | ||||||
|  | 			1, 1, 1, | ||||||
|  | 			1, 0, 0, | ||||||
|  | 		], | ||||||
|  | 		"q": [ | ||||||
|  | 			0, 0, 0, | ||||||
|  | 			0, 0, 0, | ||||||
|  | 			1, 1, 1, | ||||||
|  | 			1, 0, 1, | ||||||
|  | 			1, 1, 1, | ||||||
|  | 			0, 0, 1, | ||||||
|  | 		], | ||||||
|  | 		"r": [ | ||||||
|  | 			0, 0, 0, | ||||||
|  | 			0, 0, 0, | ||||||
|  | 			1, 1, 1, | ||||||
|  | 			1, 0, 0, | ||||||
|  | 			1, 0, 0, | ||||||
|  | 			0, 0, 0, | ||||||
|  | 		], | ||||||
|  | 		"s": [ | ||||||
|  | 			0, 0, 0, | ||||||
|  | 			0, 0, 0, | ||||||
|  | 			0, 1, 1, | ||||||
|  | 			0, 1, 0, | ||||||
|  | 			1, 1, 0, | ||||||
|  | 			0, 0, 0, | ||||||
|  | 		], | ||||||
|  | 		"t": [ | ||||||
|  | 			0, 1, 0, | ||||||
|  | 			0, 1, 0, | ||||||
|  | 			1, 1, 1, | ||||||
|  | 			0, 1, 0, | ||||||
|  | 			0, 1, 0, | ||||||
|  | 			0, 0, 0, | ||||||
|  | 		], | ||||||
|  | 		"u": [ | ||||||
|  | 			0, 0, 0, | ||||||
|  | 			0, 0, 0, | ||||||
|  | 			1, 0, 1, | ||||||
|  | 			1, 0, 1, | ||||||
|  | 			0, 1, 1, | ||||||
|  | 			0, 0, 0, | ||||||
|  | 		], | ||||||
|  | 		"v": [ | ||||||
|  | 			0, 0, 0, | ||||||
|  | 			0, 0, 0, | ||||||
|  | 			1, 0, 1, | ||||||
|  | 			1, 0, 1, | ||||||
|  | 			0, 1, 0, | ||||||
|  | 			0, 0, 0, | ||||||
|  | 		], | ||||||
|  | 		"w": [ | ||||||
|  | 			0, 0, 0, | ||||||
|  | 			0, 0, 0, | ||||||
|  | 			1, 0, 1, | ||||||
|  | 			1, 1, 1, | ||||||
|  | 			1, 1, 1, | ||||||
|  | 			0, 0, 0, | ||||||
|  | 		], | ||||||
|  | 		"x": [ | ||||||
|  | 			0, 0, 0, | ||||||
|  | 			0, 0, 0, | ||||||
|  | 			1, 0, 1, | ||||||
|  | 			0, 1, 0, | ||||||
|  | 			1, 0, 1, | ||||||
|  | 			0, 0, 0, | ||||||
|  | 		], | ||||||
|  | 		"y": [ | ||||||
|  | 			0, 0, 0, | ||||||
|  | 			0, 0, 0, | ||||||
|  | 			1, 0, 1, | ||||||
|  | 			1, 0, 1, | ||||||
|  | 			0, 1, 0, | ||||||
|  | 			1, 0, 0, | ||||||
|  | 		], | ||||||
|  | 		"z": [ | ||||||
|  | 			0, 0, 0, | ||||||
|  | 			0, 0, 0, | ||||||
|  | 			1, 1, 0, | ||||||
|  | 			0, 1, 0, | ||||||
|  | 			0, 1, 1, | ||||||
|  | 			0, 0, 0, | ||||||
|  | 		], | ||||||
|  | 		",": [ | ||||||
|  | 			0, 0, 0, | ||||||
|  | 			0, 0, 0, | ||||||
|  | 			0, 0, 0, | ||||||
|  | 			0, 0, 0, | ||||||
|  | 			0, 1, 0, | ||||||
|  | 			1, 0, 0, | ||||||
|  | 		], | ||||||
|  | 		".": [ | ||||||
|  | 			0, 0, 0, | ||||||
|  | 			0, 0, 0, | ||||||
|  | 			0, 0, 0, | ||||||
|  | 			0, 0, 0, | ||||||
|  | 			0, 1, 0, | ||||||
|  | 			0, 0, 0, | ||||||
|  | 		], | ||||||
|  | 		" ": [ | ||||||
|  | 			0, 0, 0, | ||||||
|  | 			0, 0, 0, | ||||||
|  | 			0, 0, 0, | ||||||
|  | 			0, 0, 0, | ||||||
|  | 			0, 0, 0, | ||||||
|  | 			0, 0, 0, | ||||||
|  | 		], | ||||||
|  | 		"\t": [ | ||||||
|  | 			0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 			0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 			0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 			0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 			0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 			0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 		], | ||||||
|  | 		"\n": [ | ||||||
|  | 			0, 0, 0, | ||||||
|  | 			0, 0, 0, | ||||||
|  | 			0, 0, 0, | ||||||
|  | 			0, 0, 0, | ||||||
|  | 			0, 0, 0, | ||||||
|  | 			0, 0, 0, | ||||||
|  | 		], | ||||||
|  | 		"<": [ | ||||||
|  | 			0, 0, 1, | ||||||
|  | 			0, 1, 0, | ||||||
|  | 			1, 0, 0, | ||||||
|  | 			0, 1, 0, | ||||||
|  | 			0, 0, 1, | ||||||
|  | 			0, 0, 0, | ||||||
|  | 		], | ||||||
|  | 		">": [ | ||||||
|  | 			1, 0, 0, | ||||||
|  | 			0, 1, 0, | ||||||
|  | 			0, 0, 1, | ||||||
|  | 			0, 1, 0, | ||||||
|  | 			1, 0, 0, | ||||||
|  | 			0, 0, 0, | ||||||
|  | 		], | ||||||
|  | 		"=": [ | ||||||
|  | 			0, 0, 0, | ||||||
|  | 			1, 1, 1, | ||||||
|  | 			0, 0, 0, | ||||||
|  | 			1, 1, 1, | ||||||
|  | 			0, 0, 0, | ||||||
|  | 			0, 0, 0, | ||||||
|  | 		], | ||||||
|  | 		"(": [ | ||||||
|  | 			0, 0, 1, | ||||||
|  | 			0, 1, 0, | ||||||
|  | 			0, 1, 0, | ||||||
|  | 			0, 1, 0, | ||||||
|  | 			0, 0, 1, | ||||||
|  | 			0, 0, 0, | ||||||
|  | 		], | ||||||
|  | 		")": [ | ||||||
|  | 			1, 0, 0, | ||||||
|  | 			0, 1, 0, | ||||||
|  | 			0, 1, 0, | ||||||
|  | 			0, 1, 0, | ||||||
|  | 			1, 0, 0, | ||||||
|  | 			0, 0, 0, | ||||||
|  | 		], | ||||||
|  | 		"[": [ | ||||||
|  | 			0, 1, 1, | ||||||
|  | 			0, 1, 0, | ||||||
|  | 			0, 1, 0, | ||||||
|  | 			0, 1, 0, | ||||||
|  | 			0, 1, 1, | ||||||
|  | 			0, 0, 0, | ||||||
|  | 		], | ||||||
|  | 		"]": [ | ||||||
|  | 			1, 1, 0, | ||||||
|  | 			0, 1, 0, | ||||||
|  | 			0, 1, 0, | ||||||
|  | 			0, 1, 0, | ||||||
|  | 			1, 1, 0, | ||||||
|  | 			0, 0, 0, | ||||||
|  | 		], | ||||||
|  | 		"{": [ | ||||||
|  | 			0, 1, 1, | ||||||
|  | 			0, 1, 0, | ||||||
|  | 			1, 1, 0, | ||||||
|  | 			0, 1, 0, | ||||||
|  | 			0, 1, 1, | ||||||
|  | 			0, 0, 0, | ||||||
|  | 		], | ||||||
|  | 		"}": [ | ||||||
|  | 			1, 1, 0, | ||||||
|  | 			0, 1, 0, | ||||||
|  | 			0, 1, 1, | ||||||
|  | 			0, 1, 0, | ||||||
|  | 			1, 1, 0, | ||||||
|  | 			0, 0, 0, | ||||||
|  | 		], | ||||||
|  | 		":": [ | ||||||
|  | 			0, 0, 0, | ||||||
|  | 			0, 1, 0, | ||||||
|  | 			0, 0, 0, | ||||||
|  | 			0, 0, 0, | ||||||
|  | 			0, 1, 0, | ||||||
|  | 			0, 0, 0, | ||||||
|  | 		], | ||||||
|  | 		";": [ | ||||||
|  | 			0, 0, 0, | ||||||
|  | 			0, 1, 0, | ||||||
|  | 			0, 0, 0, | ||||||
|  | 			0, 0, 0, | ||||||
|  | 			0, 1, 0, | ||||||
|  | 			1, 0, 0, | ||||||
|  | 		], | ||||||
|  | 		"'": [ | ||||||
|  | 			0, 1, 0, | ||||||
|  | 			0, 1, 0, | ||||||
|  | 			0, 0, 0, | ||||||
|  | 			0, 0, 0, | ||||||
|  | 			0, 0, 0, | ||||||
|  | 			0, 0, 0, | ||||||
|  | 		], | ||||||
|  | 		'"': [ | ||||||
|  | 			1, 0, 1, | ||||||
|  | 			1, 0, 1, | ||||||
|  | 			0, 0, 0, | ||||||
|  | 			0, 0, 0, | ||||||
|  | 			0, 0, 0, | ||||||
|  | 			0, 0, 0, | ||||||
|  | 		], | ||||||
|  | 		"1": [ | ||||||
|  | 			0, 1, 0, | ||||||
|  | 			1, 1, 0, | ||||||
|  | 			0, 1, 0, | ||||||
|  | 			0, 1, 0, | ||||||
|  | 			1, 1, 1, | ||||||
|  | 			0, 0, 0, | ||||||
|  | 		], | ||||||
|  | 		"2": [ | ||||||
|  | 			0, 1, 0, | ||||||
|  | 			1, 0, 1, | ||||||
|  | 			0, 0, 1, | ||||||
|  | 			0, 1, 0, | ||||||
|  | 			1, 1, 1, | ||||||
|  | 			0, 0, 0, | ||||||
|  | 		], | ||||||
|  | 		"3": [ | ||||||
|  | 			1, 1, 1, | ||||||
|  | 			0, 0, 1, | ||||||
|  | 			0, 1, 0, | ||||||
|  | 			0, 0, 1, | ||||||
|  | 			1, 1, 0, | ||||||
|  | 			0, 0, 0, | ||||||
|  | 		], | ||||||
|  | 		"4": [ | ||||||
|  | 			1, 0, 1, | ||||||
|  | 			1, 0, 1, | ||||||
|  | 			1, 1, 1, | ||||||
|  | 			0, 0, 1, | ||||||
|  | 			0, 0, 1, | ||||||
|  | 			0, 0, 0, | ||||||
|  | 		], | ||||||
|  | 		"5": [ | ||||||
|  | 			1, 1, 1, | ||||||
|  | 			1, 0, 0, | ||||||
|  | 			1, 1, 0, | ||||||
|  | 			0, 0, 1, | ||||||
|  | 			1, 1, 0, | ||||||
|  | 			0, 0, 0, | ||||||
|  | 		], | ||||||
|  | 		"6": [ | ||||||
|  | 			0, 0, 1, | ||||||
|  | 			0, 1, 0, | ||||||
|  | 			1, 1, 1, | ||||||
|  | 			1, 0, 1, | ||||||
|  | 			1, 1, 1, | ||||||
|  | 			0, 0, 0, | ||||||
|  | 		], | ||||||
|  | 		"7": [ | ||||||
|  | 			1, 1, 1, | ||||||
|  | 			0, 0, 1, | ||||||
|  | 			0, 1, 0, | ||||||
|  | 			0, 1, 0, | ||||||
|  | 			0, 1, 0, | ||||||
|  | 			0, 0, 0, | ||||||
|  | 		], | ||||||
|  | 		"8": [ | ||||||
|  | 			1, 1, 1, | ||||||
|  | 			1, 0, 1, | ||||||
|  | 			1, 1, 1, | ||||||
|  | 			1, 0, 1, | ||||||
|  | 			1, 1, 1, | ||||||
|  | 			0, 0, 0, | ||||||
|  | 		], | ||||||
|  | 		"9": [ | ||||||
|  | 			1, 1, 1, | ||||||
|  | 			1, 0, 1, | ||||||
|  | 			1, 1, 1, | ||||||
|  | 			0, 1, 0, | ||||||
|  | 			1, 0, 0, | ||||||
|  | 			0, 0, 0, | ||||||
|  | 		], | ||||||
|  | 		"0": [ | ||||||
|  | 			1, 1, 1, | ||||||
|  | 			1, 0, 1, | ||||||
|  | 			1, 0, 1, | ||||||
|  | 			1, 0, 1, | ||||||
|  | 			1, 1, 1, | ||||||
|  | 			0, 0, 0, | ||||||
|  | 		], | ||||||
|  | 		"+": [ | ||||||
|  | 			0, 0, 0, | ||||||
|  | 			0, 1, 0, | ||||||
|  | 			1, 1, 1, | ||||||
|  | 			0, 1, 0, | ||||||
|  | 			0, 0, 0, | ||||||
|  | 			0, 0, 0, | ||||||
|  | 		], | ||||||
|  | 		"-": [ | ||||||
|  | 			0, 0, 0, | ||||||
|  | 			0, 0, 0, | ||||||
|  | 			1, 1, 1, | ||||||
|  | 			0, 0, 0, | ||||||
|  | 			0, 0, 0, | ||||||
|  | 			0, 0, 0, | ||||||
|  | 		], | ||||||
|  | 		"_": [ | ||||||
|  | 			0, 0, 0, | ||||||
|  | 			0, 0, 0, | ||||||
|  | 			0, 0, 0, | ||||||
|  | 			0, 0, 0, | ||||||
|  | 			1, 1, 1, | ||||||
|  | 			0, 0, 0, | ||||||
|  | 		], | ||||||
|  | 		"`": [ | ||||||
|  | 			1, 0, 0, | ||||||
|  | 			0, 1, 0, | ||||||
|  | 			0, 0, 0, | ||||||
|  | 			0, 0, 0, | ||||||
|  | 			0, 0, 0, | ||||||
|  | 			0, 0, 0, | ||||||
|  | 		], | ||||||
|  | 		"~": [ | ||||||
|  | 			0, 0, 0, | ||||||
|  | 			0, 0, 1, | ||||||
|  | 			1, 1, 1, | ||||||
|  | 			1, 0, 0, | ||||||
|  | 			0, 0, 0, | ||||||
|  | 			0, 0, 0, | ||||||
|  | 		], | ||||||
|  | 		"/": [ | ||||||
|  | 			0, 0, 1, | ||||||
|  | 			0, 0, 1, | ||||||
|  | 			0, 1, 0, | ||||||
|  | 			1, 0, 0, | ||||||
|  | 			1, 0, 0, | ||||||
|  | 			0, 0, 0, | ||||||
|  | 		], | ||||||
|  | 		"?": [ | ||||||
|  | 			1, 1, 1, | ||||||
|  | 			0, 0, 1, | ||||||
|  | 			0, 1, 1, | ||||||
|  | 			0, 0, 0, | ||||||
|  | 			0, 1, 0, | ||||||
|  | 			0, 0, 0, | ||||||
|  | 		], | ||||||
|  | 		"\\": [ | ||||||
|  | 			1, 0, 0, | ||||||
|  | 			1, 0, 0, | ||||||
|  | 			0, 1, 0, | ||||||
|  | 			0, 0, 1, | ||||||
|  | 			0, 0, 1, | ||||||
|  | 			0, 0, 0, | ||||||
|  | 		], | ||||||
|  | 		"|": [ | ||||||
|  | 			0, 1, 0, | ||||||
|  | 			0, 1, 0, | ||||||
|  | 			0, 1, 0, | ||||||
|  | 			0, 1, 0, | ||||||
|  | 			0, 1, 0, | ||||||
|  | 			0, 0, 0, | ||||||
|  | 		], | ||||||
|  | 		"!": [ | ||||||
|  | 			0, 1, 0, | ||||||
|  | 			0, 1, 0, | ||||||
|  | 			0, 1, 0, | ||||||
|  | 			0, 0, 0, | ||||||
|  | 			0, 1, 0, | ||||||
|  | 			0, 0, 0, | ||||||
|  | 		], | ||||||
|  | 		"@": [ | ||||||
|  | 			0, 1, 0, | ||||||
|  | 			1, 0, 1, | ||||||
|  | 			1, 0, 1, | ||||||
|  | 			1, 0, 0, | ||||||
|  | 			0, 1, 1, | ||||||
|  | 			0, 0, 0, | ||||||
|  | 		], | ||||||
|  | 		"#": [ | ||||||
|  | 			1, 0, 1, | ||||||
|  | 			1, 1, 1, | ||||||
|  | 			1, 0, 1, | ||||||
|  | 			1, 1, 1, | ||||||
|  | 			1, 0, 1, | ||||||
|  | 			0, 0, 0, | ||||||
|  | 		], | ||||||
|  | 		"$": [ | ||||||
|  | 			1, 1, 1, | ||||||
|  | 			1, 1, 0, | ||||||
|  | 			0, 1, 1, | ||||||
|  | 			1, 1, 1, | ||||||
|  | 			0, 1, 0, | ||||||
|  | 			0, 0, 0, | ||||||
|  | 		], | ||||||
|  | 		"%": [ | ||||||
|  | 			1, 0, 1, | ||||||
|  | 			0, 0, 1, | ||||||
|  | 			0, 1, 0, | ||||||
|  | 			1, 0, 0, | ||||||
|  | 			1, 0, 1, | ||||||
|  | 			0, 0, 0, | ||||||
|  | 		], | ||||||
|  | 		"^": [ | ||||||
|  | 			0, 1, 0, | ||||||
|  | 			1, 0, 1, | ||||||
|  | 			0, 0, 0, | ||||||
|  | 			0, 0, 0, | ||||||
|  | 			0, 0, 0, | ||||||
|  | 			0, 0, 0, | ||||||
|  | 		], | ||||||
|  | 		"&": [ | ||||||
|  | 			1, 1, 0, | ||||||
|  | 			1, 1, 0, | ||||||
|  | 			0, 1, 1, | ||||||
|  | 			1, 0, 1, | ||||||
|  | 			1, 1, 1, | ||||||
|  | 			0, 0, 0, | ||||||
|  | 		], | ||||||
|  | 		"*": [ | ||||||
|  | 			0, 1, 0, | ||||||
|  | 			1, 1, 1, | ||||||
|  | 			0, 1, 0, | ||||||
|  | 			1, 0, 1, | ||||||
|  | 			0, 0, 0, | ||||||
|  | 			0, 0, 0, | ||||||
|  | 		], | ||||||
|  | 		[CHAR.UP]: [ | ||||||
|  | 			0, 1, 1, 1, 1, 1, 0, | ||||||
|  | 			1, 1, 1, 0, 1, 1, 1, | ||||||
|  | 			1, 1, 0, 0, 0, 1, 1, | ||||||
|  | 			1, 1, 0, 0, 0, 1, 1, | ||||||
|  | 			0, 1, 1, 1, 1, 1, 0, | ||||||
|  | 			0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 		], | ||||||
|  | 		[CHAR.LEFT]: [ | ||||||
|  | 			0, 1, 1, 1, 1, 1, 0, | ||||||
|  | 			1, 1, 1, 0, 0, 1, 1, | ||||||
|  | 			1, 1, 0, 0, 0, 1, 1, | ||||||
|  | 			1, 1, 1, 0, 0, 1, 1, | ||||||
|  | 			0, 1, 1, 1, 1, 1, 0, | ||||||
|  | 			0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 		], | ||||||
|  | 		[CHAR.DOWN]: [ | ||||||
|  | 			0, 1, 1, 1, 1, 1, 0, | ||||||
|  | 			1, 1, 0, 0, 0, 1, 1, | ||||||
|  | 			1, 1, 0, 0, 0, 1, 1, | ||||||
|  | 			1, 1, 1, 0, 1, 1, 1, | ||||||
|  | 			0, 1, 1, 1, 1, 1, 0, | ||||||
|  | 			0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 		], | ||||||
|  | 		[CHAR.RIGHT]: [ | ||||||
|  | 			0, 1, 1, 1, 1, 1, 0, | ||||||
|  | 			1, 1, 0, 0, 1, 1, 1, | ||||||
|  | 			1, 1, 0, 0, 0, 1, 1, | ||||||
|  | 			1, 1, 0, 0, 1, 1, 1, | ||||||
|  | 			0, 1, 1, 1, 1, 1, 0, | ||||||
|  | 			0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 		], | ||||||
|  | 		[CHAR.PI]: [ | ||||||
|  | 			0, 0, 0, 0, 0, | ||||||
|  | 			0, 0, 0, 0, 0, | ||||||
|  | 			1, 1, 1, 1, 1, | ||||||
|  | 			0, 1, 0, 1, 0, | ||||||
|  | 			0, 1, 0, 1, 0, | ||||||
|  | 			0, 0, 0, 0, 0, | ||||||
|  | 		], | ||||||
|  | 	} | ||||||
|  | }; | ||||||
							
								
								
									
										54
									
								
								icons.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										54
									
								
								icons.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,54 @@ | |||||||
|  | export const codeIcon = [ | ||||||
|  | 	0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 	0, 0, 1, 0, 0, 1, 0, 0, | ||||||
|  | 	0, 1, 1, 0, 0, 1, 1, 0, | ||||||
|  | 	0, 1, 0, 0, 0, 0, 1, 0, | ||||||
|  | 	0, 1, 0, 0, 0, 0, 1, 0, | ||||||
|  | 	0, 1, 1, 0, 0, 1, 1, 0, | ||||||
|  | 	0, 0, 1, 0, 0, 1, 0, 0, | ||||||
|  | 	0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | ]; | ||||||
|  |  | ||||||
|  | export const spriteIcon = [ | ||||||
|  | 	0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 	0, 0, 1, 1, 1, 1, 0, 0, | ||||||
|  | 	0, 1, 1, 0, 1, 1, 1, 0, | ||||||
|  | 	0, 1, 1, 1, 1, 0, 0, 0, | ||||||
|  | 	0, 1, 1, 1, 0, 0, 0, 0, | ||||||
|  | 	0, 1, 1, 1, 1, 1, 1, 0, | ||||||
|  | 	0, 0, 1, 1, 1, 1, 0, 0, | ||||||
|  | 	0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | ]; | ||||||
|  |  | ||||||
|  | export const mapIcon = [ | ||||||
|  | 	0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 	0, 1, 1, 1, 1, 1, 1, 0, | ||||||
|  | 	0, 1, 0, 1, 0, 0, 1, 0, | ||||||
|  | 	0, 1, 0, 1, 1, 1, 1, 0, | ||||||
|  | 	0, 1, 1, 1, 0, 0, 1, 0, | ||||||
|  | 	0, 1, 0, 1, 0, 0, 1, 0, | ||||||
|  | 	0, 1, 1, 1, 1, 1, 1, 0, | ||||||
|  | 	0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | ]; | ||||||
|  |  | ||||||
|  | export const sheetsIcon = [ | ||||||
|  | 	0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 	0, 1, 1, 0, 0, 1, 1, 0, | ||||||
|  | 	0, 1, 1, 0, 0, 1, 1, 0, | ||||||
|  | 	0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 	0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 	0, 1, 1, 0, 0, 1, 1, 0, | ||||||
|  | 	0, 1, 1, 0, 0, 1, 1, 0, | ||||||
|  | 	0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | ]; | ||||||
|  |  | ||||||
|  | export const trashIcon = [ | ||||||
|  | 	0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 	0, 0, 0, 1, 1, 0, 0, 0, | ||||||
|  | 	0, 1, 1, 1, 1, 1, 1, 0, | ||||||
|  | 	0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 	0, 0, 1, 1, 1, 1, 0, 0, | ||||||
|  | 	0, 0, 1, 1, 1, 1, 0, 0, | ||||||
|  | 	0, 0, 1, 1, 1, 1, 0, 0, | ||||||
|  | 	0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | ]; | ||||||
							
								
								
									
										64
									
								
								index.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										64
									
								
								index.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,64 @@ | |||||||
|  | import { | ||||||
|  | 	mainloop, | ||||||
|  | 	frame, | ||||||
|  | 	clearScreen, | ||||||
|  | } from "./window.ts"; | ||||||
|  | import { runCode } from "./runcode.ts"; | ||||||
|  | import { getCodeSheet } from "./sheet.ts"; | ||||||
|  | import { refreshKeyboard, keyPressed, K } from "./keyboard.ts"; | ||||||
|  | import { repl, resetRepl } from "./repl.ts"; | ||||||
|  | import { addToContext } from "./runcode.ts"; | ||||||
|  | import { editmode } from "./editmode.ts"; | ||||||
|  | import { refreshMouse } from "./mouse.ts"; | ||||||
|  | import { camera } from "./builtins.ts"; | ||||||
|  |  | ||||||
|  | // deno-lint-ignore no-explicit-any | ||||||
|  | let game: any = null; | ||||||
|  |  | ||||||
|  | let mode: "play" | "edit" | "repl" = "repl"; | ||||||
|  |  | ||||||
|  | addToContext("play", () => { | ||||||
|  | 	mode = "play"; | ||||||
|  | 	game = runCode(getCodeSheet(0)); | ||||||
|  | 	game.init(); | ||||||
|  | }); | ||||||
|  |  | ||||||
|  | clearScreen(); | ||||||
|  |    | ||||||
|  | await mainloop(async (_t) => { | ||||||
|  | 	// TODO: use t | ||||||
|  | 	if (keyPressed(K.ESCAPE)) { | ||||||
|  | 		const modeTo = ({ | ||||||
|  | 			play: "repl", | ||||||
|  | 			edit: "repl", | ||||||
|  | 			repl: "edit", | ||||||
|  | 		} as const)[mode]; | ||||||
|  | 		if (mode === "play") { | ||||||
|  | 			resetRepl(); | ||||||
|  | 		} | ||||||
|  | 		if (mode === "edit") { | ||||||
|  | 			clearScreen(); | ||||||
|  | 		} | ||||||
|  | 		mode = modeTo; | ||||||
|  | 	} else { | ||||||
|  | 		if (mode === "play") { | ||||||
|  | 			if (game) { | ||||||
|  | 				game.update(); | ||||||
|  | 				game.draw(); | ||||||
|  | 			} | ||||||
|  | 			frame(); | ||||||
|  | 		} else if (mode === "repl") { | ||||||
|  | 			repl.update(); | ||||||
|  | 			camera(0, 0); | ||||||
|  | 			repl.draw(); | ||||||
|  | 			frame(); | ||||||
|  | 		} else if (mode === "edit") { | ||||||
|  | 			await editmode.update(); | ||||||
|  | 			camera(0, 0); | ||||||
|  | 			editmode.draw(); | ||||||
|  | 			frame(); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	refreshKeyboard(); | ||||||
|  | 	refreshMouse(); | ||||||
|  | }, false); | ||||||
							
								
								
									
										1
									
								
								initialCart.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								initialCart.json
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | |||||||
|  | [{"sheet_type":"code","value":"// Sample\n\nreturn {\n\tinit() {},\n\tupdate() {},\n\tdraw() {\n\t\tcls();\n\t\ttxt(10,10,\"Hello, World!\");\n\t}\n}"},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null}] | ||||||
							
								
								
									
										174
									
								
								keyboard.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										174
									
								
								keyboard.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,174 @@ | |||||||
|  | import { font, CHAR } from "./font.ts"; | ||||||
|  |  | ||||||
|  | const keyboard = new Map<number, {first: boolean, repeat: boolean, held: boolean}>(); | ||||||
|  |  | ||||||
|  | export const K = { | ||||||
|  | 	ESCAPE: 256, | ||||||
|  | 	ENTER: 257, | ||||||
|  | 	TAB: 258, | ||||||
|  | 	BACKSPACE: 259, | ||||||
|  | 	INSERT: 260, | ||||||
|  | 	DELETE: 261, | ||||||
|  | 	ARROW_RIGHT: 262, | ||||||
|  | 	ARROW_LEFT: 263, | ||||||
|  | 	ARROW_DOWN: 264, | ||||||
|  | 	ARROW_UP: 265, | ||||||
|  | 	PAGE_UP: 266, | ||||||
|  | 	PAGE_DOWN: 267, | ||||||
|  | 	HOME: 268, | ||||||
|  | 	END: 269, | ||||||
|  | 	CAPS_LOCK: 280, | ||||||
|  | 	F1: 290, | ||||||
|  | 	F2: 291, | ||||||
|  | 	F3: 292, | ||||||
|  | 	F4: 293, | ||||||
|  | 	F5: 294, | ||||||
|  | 	F6: 295, | ||||||
|  | 	F7: 296, | ||||||
|  | 	F8: 297, | ||||||
|  | 	F9: 298, | ||||||
|  | 	F10: 299, | ||||||
|  | 	F11: 300, | ||||||
|  | 	F12: 301, | ||||||
|  | 	SHIFT_LEFT: 340, | ||||||
|  | 	CTRL_LEFT: 341, | ||||||
|  | 	ALT_LEFT: 342, | ||||||
|  | 	SHIFT_RIGHT: 344, | ||||||
|  | 	CTRL_RIGHT: 345, | ||||||
|  | 	ALT_RIGHT: 346, | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export const shiftMap = { | ||||||
|  | 	"1": "!", | ||||||
|  | 	"2": "@", | ||||||
|  | 	"3": "#", | ||||||
|  | 	"4": "$", | ||||||
|  | 	"5": "%", | ||||||
|  | 	"6": "^", | ||||||
|  | 	"7": "&", | ||||||
|  | 	"8": "*", | ||||||
|  | 	"9": "(", | ||||||
|  | 	"0": ")", | ||||||
|  | 	"`": "~", | ||||||
|  | 	"-": "_", | ||||||
|  | 	"=": "+", | ||||||
|  | 	"[": "{", | ||||||
|  | 	"]": "}", | ||||||
|  | 	"\\": "|", | ||||||
|  | 	";": ":", | ||||||
|  | 	"'": '"', | ||||||
|  | 	",": "<", | ||||||
|  | 	".": ">", | ||||||
|  | 	"/": "?", | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export const altMap = { | ||||||
|  | 	"w": CHAR.UP, | ||||||
|  | 	"a": CHAR.LEFT, | ||||||
|  | 	"s": CHAR.DOWN, | ||||||
|  | 	"d": CHAR.RIGHT, | ||||||
|  | 	"p": CHAR.PI, | ||||||
|  | } | ||||||
|  |  | ||||||
|  | addEventListener("keydown", (evt) => { | ||||||
|  | 	// console.log("keydown", evt.key, evt.key.charCodeAt(0)); | ||||||
|  | 	const key = evt.key.charCodeAt(0); | ||||||
|  | 	const isRepeat = keyboard.has(key) && keyboard.get(key)?.held!; | ||||||
|  | 	keyboard.set(key, { | ||||||
|  | 		first: !isRepeat, | ||||||
|  | 		repeat: isRepeat, | ||||||
|  | 		held: true, | ||||||
|  | 	}); | ||||||
|  | }); | ||||||
|  |  | ||||||
|  | addEventListener("keyup", (evt) => { | ||||||
|  | 	// console.log("keyup", evt.key, evt.key.charCodeAt(0)); | ||||||
|  | 	const key = evt.key.charCodeAt(0); | ||||||
|  | 	keyboard.set(key, { | ||||||
|  | 		first: false, | ||||||
|  | 		repeat: false, | ||||||
|  | 		held: false, | ||||||
|  | 	}); | ||||||
|  | }); | ||||||
|  |  | ||||||
|  | export const refreshKeyboard = () => { | ||||||
|  | 	keyboard.forEach(({held}, key) => { | ||||||
|  | 		if (!held) { | ||||||
|  | 			keyboard.delete(key); | ||||||
|  | 		} else { | ||||||
|  | 			keyboard.set(key, { | ||||||
|  | 				first: false, | ||||||
|  | 				repeat: false, | ||||||
|  | 				held: true, | ||||||
|  | 			}); | ||||||
|  | 		} | ||||||
|  | 	}) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export const keyPressed = (key: string | number) => { | ||||||
|  | 	if (typeof key === "string") { | ||||||
|  | 		key = key.toUpperCase().charCodeAt(0); | ||||||
|  | 	} | ||||||
|  | 	return keyboard.has(key) && (keyboard.get(key)?.first! || keyboard.get(key)?.repeat!); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export const keyDown = (key: string | number) => { | ||||||
|  | 	if (typeof key === "string") { | ||||||
|  | 		key = key.toUpperCase().charCodeAt(0); | ||||||
|  | 	} | ||||||
|  | 	return keyboard.has(key) && keyboard.get(key)?.held!; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export const shiftKeyDown = () => { | ||||||
|  | 	return keyDown(K.SHIFT_LEFT) || keyDown(K.SHIFT_RIGHT); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export const ctrlKeyDown = () => { | ||||||
|  | 	return keyDown(K.CTRL_LEFT) || keyDown(K.CTRL_RIGHT); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export const altKeyDown = () => { | ||||||
|  | 	return keyDown(K.ALT_LEFT) || keyDown(K.ALT_RIGHT); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export const keyReleased = (key: string | number) => { | ||||||
|  | 	if (typeof key === "string") { | ||||||
|  | 		key = key.toUpperCase().charCodeAt(0); | ||||||
|  | 	} | ||||||
|  | 	return keyboard.has(key) && !keyboard.get(key)?.held!; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export const getKeysPressed = () => { | ||||||
|  | 	const result = [...keyboard.entries()].filter(([_key, value]) => { | ||||||
|  | 		return value.first || value.repeat; | ||||||
|  | 	}).map(([key]) => key); | ||||||
|  | 	return result; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export const getKeyboardString = () => { | ||||||
|  | 	let str = ""; | ||||||
|  | 	if (ctrlKeyDown()) { | ||||||
|  | 		return str; | ||||||
|  | 	} | ||||||
|  | 	for (const key of getKeysPressed()) { | ||||||
|  | 		let char = String.fromCharCode(key).toLowerCase(); | ||||||
|  | 		if (shiftKeyDown()) { | ||||||
|  | 			if (char in shiftMap) { | ||||||
|  | 				char = shiftMap[char as keyof typeof shiftMap]; | ||||||
|  | 			} else { | ||||||
|  | 				char = char.toUpperCase(); | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 		if (altKeyDown()) { | ||||||
|  | 			if (char in altMap) { | ||||||
|  | 				char = altMap[char as keyof typeof altMap]; | ||||||
|  | 			} else { | ||||||
|  | 				char = char.toUpperCase(); | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 		if (char in font.chars) { | ||||||
|  | 			str += char; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return str; | ||||||
|  | } | ||||||
							
								
								
									
										215
									
								
								maptab.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										215
									
								
								maptab.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,215 @@ | |||||||
|  | import { clearScreen, fillRect } from "./window.ts"; | ||||||
|  | import { drawSprite, drawText } from "./builtins.ts"; | ||||||
|  | import { COLOR } from "./colors.ts"; | ||||||
|  | import { getMapSheet, getSheet, setSheet } from "./sheet.ts"; | ||||||
|  | import { M, mouseClick, mouseDown, mouseHeld, mousePos } from "./mouse.ts"; | ||||||
|  | import { drawTransparentRect, drawVoidRect, inRect, reGrid } from "./util.ts"; | ||||||
|  | import { page } from "./viewsheets.ts"; | ||||||
|  | import { useSpritesheet } from "./builtins.ts"; | ||||||
|  | import { keyPressed } from "./keyboard.ts"; | ||||||
|  | import { K } from "./keyboard.ts"; | ||||||
|  |  | ||||||
|  | const state = { | ||||||
|  | 	selectedSpriteSheet: 0, | ||||||
|  | 	selectedSprite: 0, | ||||||
|  | 	viewX: 0, | ||||||
|  | 	viewY: 0, | ||||||
|  | 	dragging: false, | ||||||
|  | 	dragFromViewX: 0, | ||||||
|  | 	dragFromViewY: 0, | ||||||
|  | 	dragFromX: 0, | ||||||
|  | 	dragFromY: 0, | ||||||
|  | 	get spriteSheetPage() { | ||||||
|  | 		return Math.floor(this.selectedSprite/64); | ||||||
|  | 	}, | ||||||
|  | 	set spriteSheetPage(val) { | ||||||
|  | 		this.selectedSprite = 64*val+this.spriteWithinPage; | ||||||
|  | 	}, | ||||||
|  | 	get spriteWithinPage() { | ||||||
|  | 		return this.selectedSprite%64; | ||||||
|  | 	}, | ||||||
|  | 	set spriteWithinPage(val) { | ||||||
|  | 		this.selectedSprite = 64*this.spriteSheetPage+val; | ||||||
|  | 	}, | ||||||
|  | 	get map() { | ||||||
|  | 		return getMapSheet(page.activeSheet); | ||||||
|  | 	}, | ||||||
|  | 	set map(val) { | ||||||
|  | 		setSheet(page.activeSheet, "map", val); | ||||||
|  | 	}, | ||||||
|  | 	setInPatch(i: number, sprsheet: number, sprite: number) { | ||||||
|  | 		const cellVal = this.map.subgrid(this.viewX, this.viewY, patchW, patchH).values[i]; | ||||||
|  | 		if (cellVal) { | ||||||
|  | 			cellVal[0] = sprsheet | ||||||
|  | 			cellVal[1] = sprite; | ||||||
|  | 		} | ||||||
|  | 	}, | ||||||
|  | 	get patch() { | ||||||
|  | 		return this.map.subgrid(this.viewX, this.viewY, patchW, patchH); | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | const patchX = 0; | ||||||
|  | const patchY = 8; | ||||||
|  | const patchW = 16; | ||||||
|  | const patchH = 9; | ||||||
|  |  | ||||||
|  | const spriteW = 8; | ||||||
|  | const spriteH = 8; | ||||||
|  |  | ||||||
|  | const spriteSheetX = 0; | ||||||
|  | const spriteSheetY = 88; | ||||||
|  | const spriteSheetW = 16; | ||||||
|  | const spriteSheetH = 4; | ||||||
|  |  | ||||||
|  | const spriteSheetPickerX = 0; | ||||||
|  | const spriteSheetPickerY = 81; | ||||||
|  | const spriteSheetPickerW = 16; | ||||||
|  | const spriteSheetPickerH = 1; | ||||||
|  | const spriteSheetPickerTabW = 7; | ||||||
|  | const spriteSheetPickerTabH = 7; | ||||||
|  |  | ||||||
|  | const spriteSheetPageSwapX = 121; | ||||||
|  | const spriteSheetPageSwapY = 81; | ||||||
|  | const spriteSheetPageSwapW = 7; | ||||||
|  | const spriteSheetPageSwapH = 7; | ||||||
|  |  | ||||||
|  | const update = () => { | ||||||
|  | 	const {x: mouseX, y: mouseY} = mousePos(); | ||||||
|  | 	const inPatch = inRect(mouseX, mouseY, patchX, patchY, patchW*spriteW, patchH*spriteH - 2); | ||||||
|  | 	const inSpriteSheetPicker = inRect(mouseX, mouseY, spriteSheetPickerX, spriteSheetPickerY, spriteSheetPickerW*spriteSheetPickerTabW, spriteSheetPickerH*spriteSheetPickerTabH); | ||||||
|  | 	const inSpriteSheet = inRect(mouseX, mouseY, spriteSheetX, spriteSheetY, spriteSheetW*spriteW, spriteSheetH*spriteH); | ||||||
|  | 	const inSpriteSheetPageSwap = inRect(mouseX, mouseY, spriteSheetPageSwapX, spriteSheetPageSwapY, spriteSheetPageSwapW, spriteSheetPageSwapH); | ||||||
|  | 	if (mouseHeld()) { | ||||||
|  | 		if (inPatch) { | ||||||
|  | 			const {x, y} = reGrid(mouseX, mouseY, patchX, patchY, spriteW, spriteH); | ||||||
|  | 			const cellNumber = patchW*y+x; | ||||||
|  | 			state.setInPatch(cellNumber, state.selectedSpriteSheet, state.selectedSprite); | ||||||
|  | 		} | ||||||
|  | 		if (inSpriteSheetPicker) { | ||||||
|  | 			const {x, y} = reGrid(mouseX, mouseY, spriteSheetPickerX, spriteSheetPickerY, spriteSheetPickerTabW, spriteSheetPickerTabH); | ||||||
|  | 			state.selectedSpriteSheet = spriteSheetPickerW*y+x; | ||||||
|  | 		} | ||||||
|  | 		if (inSpriteSheet) { | ||||||
|  | 			const {x, y} = reGrid(mouseX, mouseY, spriteSheetX, spriteSheetY, spriteW, spriteH); | ||||||
|  | 			state.spriteWithinPage = spriteSheetW*y+x; | ||||||
|  | 		} | ||||||
|  | 	} else if (mouseDown(M.MIDDLE)) { | ||||||
|  | 		if (inPatch) { | ||||||
|  | 			const {x, y} = reGrid(mouseX, mouseY, patchX, patchY, spriteW, spriteH); | ||||||
|  | 			state.dragging = true; | ||||||
|  | 			state.dragFromX = x; | ||||||
|  | 			state.dragFromY = y; | ||||||
|  | 			state.dragFromViewX = state.viewX; | ||||||
|  | 			state.dragFromViewY = state.viewY; | ||||||
|  | 		} | ||||||
|  | 	} else if (mouseHeld(M.MIDDLE)) { | ||||||
|  | 		if (state.dragging) { | ||||||
|  | 			const {x, y} = reGrid(mouseX, mouseY, patchX, patchY, spriteW, spriteH); | ||||||
|  | 			state.viewX = state.dragFromViewX - x + state.dragFromX; | ||||||
|  | 			state.viewY = state.dragFromViewY - y + state.dragFromY; | ||||||
|  | 		} | ||||||
|  | 	} else if (mouseClick(M.MIDDLE)) { | ||||||
|  | 		state.dragging = false; | ||||||
|  | 	} else if (mouseClick()) { | ||||||
|  | 		if (inSpriteSheetPageSwap) { | ||||||
|  | 			state.spriteSheetPage = (1+state.spriteSheetPage)%2; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	if (keyPressed(K.ARROW_RIGHT)) { | ||||||
|  | 		state.viewX += 1; | ||||||
|  | 	} | ||||||
|  | 	if (keyPressed(K.ARROW_LEFT)) { | ||||||
|  | 		state.viewX -= 1; | ||||||
|  | 	} | ||||||
|  | 	if (keyPressed(K.ARROW_UP)) { | ||||||
|  | 		state.viewY -= 1; | ||||||
|  | 	} | ||||||
|  | 	if (keyPressed(K.ARROW_DOWN)) { | ||||||
|  | 		state.viewY += 1; | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | const outlineRect = (x: number, y: number, w: number, h: number, color: number) => { | ||||||
|  | 	fillRect(x, y, w, 1, color); | ||||||
|  | 	fillRect(x, y, 1, h, color); | ||||||
|  | 	fillRect(x+w-1, y, 1, h, color); | ||||||
|  | 	fillRect(x, y+h-1, w, 1, color); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | const draw = () => { | ||||||
|  | 	const { | ||||||
|  | 		selectedSpriteSheet, | ||||||
|  | 		spriteWithinPage, | ||||||
|  | 		spriteSheetPage, | ||||||
|  | 	} = state; | ||||||
|  | 	clearScreen(); | ||||||
|  | 	fillRect(0, 8, 128, 112, COLOR.DARKGRAY); | ||||||
|  |  | ||||||
|  | 	// Draw the current patch | ||||||
|  | 	drawVoidRect(patchX-1, patchY-1, (patchW*spriteW)+2, (patchH*spriteH)+2); | ||||||
|  | 	state.patch.values.forEach((val, i) => { | ||||||
|  | 		const spriteX = patchX+spriteW*(i%patchW); | ||||||
|  | 		const spriteY = patchY+spriteH*Math.floor(i/patchW); | ||||||
|  | 		if (!val) { | ||||||
|  | 			return; | ||||||
|  | 		} | ||||||
|  | 		const [sprsheet, sprite] = val; | ||||||
|  | 		drawTransparentRect(spriteX, spriteY, 8, 8); | ||||||
|  | 		if (getSheet(sprsheet).sheet_type === "spritesheet") { | ||||||
|  | 			useSpritesheet(sprsheet); | ||||||
|  | 			drawSprite(spriteX, spriteY, sprite); | ||||||
|  | 		} | ||||||
|  | 	}); | ||||||
|  |  | ||||||
|  | 	// Draw the bar | ||||||
|  | 	fillRect(spriteSheetPickerX, spriteSheetPickerY-1, 128, 1, COLOR.BLACK); | ||||||
|  | 	fillRect(spriteSheetPickerX, spriteSheetPickerY, 128, 7, COLOR.DARKGRAY); | ||||||
|  |  | ||||||
|  | 	// Draw the spritesheet picker | ||||||
|  | 	fillRect(spriteSheetPickerX, spriteSheetPickerY, spriteSheetPickerTabW*spriteSheetPickerW, spriteSheetPickerTabW, COLOR.BLACK); | ||||||
|  | 	Array(spriteSheetPickerW*spriteSheetPickerH).fill(0).forEach((_, i) => { | ||||||
|  | 		const tabX = spriteSheetPickerX+spriteSheetPickerTabW*(i%spriteSheetPickerW); | ||||||
|  | 		const tabY = spriteSheetPickerY+spriteSheetPickerTabH*Math.floor(i/spriteSheetPickerW); | ||||||
|  | 		let color = COLOR.DARKGREEN; | ||||||
|  | 		if (getSheet(i).sheet_type !== "spritesheet") { | ||||||
|  | 			color = COLOR.BROWN; | ||||||
|  | 		} | ||||||
|  | 		if (i === page.activeSheet) { | ||||||
|  | 			color = COLOR.PURPLE; | ||||||
|  | 		} | ||||||
|  | 		if (i === selectedSpriteSheet) { | ||||||
|  | 			color = { | ||||||
|  | 				[COLOR.BROWN]: COLOR.TAN, | ||||||
|  | 				[COLOR.DARKGREEN]: COLOR.GREEN, | ||||||
|  | 				[COLOR.PURPLE]: COLOR.PINK, | ||||||
|  | 			}[color]; | ||||||
|  | 		} | ||||||
|  | 		fillRect(tabX, tabY, spriteSheetPickerTabW, spriteSheetPickerTabH, color); | ||||||
|  | 		drawText(tabX+2, tabY+1, ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F"][i]); | ||||||
|  | 	}); | ||||||
|  |  | ||||||
|  | 	// Draw the spritesheet page swap button | ||||||
|  | 	fillRect(spriteSheetPageSwapX, spriteSheetPageSwapY, spriteSheetPageSwapW, spriteSheetPageSwapH, COLOR.BLUE); | ||||||
|  | 	drawText(spriteSheetPageSwapX+2, spriteSheetPageSwapY+1, state.spriteSheetPage.toString()); | ||||||
|  | 	 | ||||||
|  | 	// Draw the spritesheet | ||||||
|  | 	fillRect(spriteSheetX, spriteSheetY, (spriteSheetW*spriteW), (spriteSheetH*spriteH), COLOR.BLACK); | ||||||
|  | 	if (getSheet(selectedSpriteSheet).sheet_type === "spritesheet") { | ||||||
|  | 		useSpritesheet(selectedSpriteSheet); | ||||||
|  | 		Array(64).fill(0).forEach((_, i) => { | ||||||
|  | 			const sprI = i+64*spriteSheetPage; | ||||||
|  | 			const sprX = spriteSheetX+spriteW*(i%spriteSheetW); | ||||||
|  | 			const sprY = spriteSheetY+spriteH*Math.floor(i/spriteSheetW); | ||||||
|  | 			drawSprite(sprX, sprY, sprI); | ||||||
|  | 			if (i === spriteWithinPage) { | ||||||
|  | 				outlineRect(sprX, sprY, spriteW, spriteH, COLOR.WHITE); | ||||||
|  | 			} | ||||||
|  | 		}); | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export const maptab = { | ||||||
|  | 	update, | ||||||
|  | 	draw, | ||||||
|  | } | ||||||
							
								
								
									
										96
									
								
								mouse.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										96
									
								
								mouse.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,96 @@ | |||||||
|  | import { WindowMouseEvent } from "https://deno.land/x/dwm@0.3.3/mod.ts"; | ||||||
|  | import { gameWindow } from "./window.ts"; | ||||||
|  |  | ||||||
|  | export const M = { | ||||||
|  | 	NONE: -1, | ||||||
|  | 	LEFT: 0, | ||||||
|  | 	RIGHT: 1, | ||||||
|  | 	MIDDLE: 2, | ||||||
|  | } | ||||||
|  |  | ||||||
|  | const mouseButtonsDown = { | ||||||
|  | 	[M.LEFT]: false, | ||||||
|  | 	[M.RIGHT]: false, | ||||||
|  | 	[M.MIDDLE]: false, | ||||||
|  | }; | ||||||
|  | const mouseEvents: Array<{ | ||||||
|  | 	type: "click" | "down" | "up" | "move" | "dblclick", | ||||||
|  | 	button: typeof M[keyof typeof M], | ||||||
|  | 	x: number, | ||||||
|  | 	y: number, | ||||||
|  | 	prevX?: number, | ||||||
|  | 	prevY?: number | ||||||
|  | }> = []; | ||||||
|  |  | ||||||
|  | let mouseX = 0; | ||||||
|  | let mouseY = 0; | ||||||
|  |  | ||||||
|  | const eventPixelCoords = (evt: WindowMouseEvent) => { | ||||||
|  | 	const {width, height} = gameWindow.size; | ||||||
|  | 	const pixX = Math.floor(128*evt.clientX/width); | ||||||
|  | 	const pixY = Math.floor(128*evt.clientY/height); | ||||||
|  | 	return { | ||||||
|  | 		x: pixX, | ||||||
|  | 		y: pixY, | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | addEventListener("dblclick", (evt) => { | ||||||
|  | 	mouseEvents.push({type: "dblclick", button: evt.button, ...eventPixelCoords(evt)}); | ||||||
|  | }); | ||||||
|  |  | ||||||
|  | addEventListener("click", (evt) => { | ||||||
|  | 	mouseEvents.push({type: "click", button: evt.button, ...eventPixelCoords(evt)}); | ||||||
|  | }); | ||||||
|  |  | ||||||
|  | addEventListener("mousedown", (evt) => { | ||||||
|  | 	mouseButtonsDown[evt.button] = true; | ||||||
|  | 	mouseEvents.push({type: "down", button: evt.button, ...eventPixelCoords(evt)}); | ||||||
|  | }); | ||||||
|  |  | ||||||
|  | addEventListener("mouseup", (evt) => { | ||||||
|  | 	mouseButtonsDown[evt.button] = false; | ||||||
|  | 	mouseEvents.push({type: "up", button: evt.button, ...eventPixelCoords(evt)}); | ||||||
|  | }); | ||||||
|  |  | ||||||
|  | addEventListener("mousemove", (evt) => { | ||||||
|  | 	const coords = eventPixelCoords(evt); | ||||||
|  | 	mouseEvents.push({type: "move", button: evt.button, ...eventPixelCoords(evt), prevX: mouseX, prevY: mouseY}); | ||||||
|  | 	mouseX = coords.x; | ||||||
|  | 	mouseY = coords.y; | ||||||
|  | }); | ||||||
|  |  | ||||||
|  | export const mousePos = () => { | ||||||
|  | 	return { | ||||||
|  | 		x: mouseX, | ||||||
|  | 		y: mouseY, | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export const getMouseX = () => { | ||||||
|  | 	return mouseX; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export const getMouseY = () => { | ||||||
|  | 	return mouseY; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export const refreshMouse = () => { | ||||||
|  | 	mouseEvents.length = 0; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export const mouseDown = (button: number = M.LEFT) => { | ||||||
|  | 	return mouseEvents.some(ev => ev.button === button && ev.type === "down"); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export const mouseClick = (button: number = M.LEFT) => { | ||||||
|  | 	return mouseEvents.some(ev => ev.button === button && ev.type === "click"); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export const mouseDoubleClick = (button: number = M.LEFT) => { | ||||||
|  | 	return mouseEvents.some(ev => ev.button === button && ev.type === "dblclick"); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export const mouseHeld = (button: number = M.LEFT) => { | ||||||
|  | 	return mouseButtonsDown[button]; | ||||||
|  | } | ||||||
							
								
								
									
										63
									
								
								nonetab.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										63
									
								
								nonetab.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,63 @@ | |||||||
|  | import { clearScreen, fillRect } from "./window.ts"; | ||||||
|  | import { drawIcon, drawText } from "./builtins.ts"; | ||||||
|  | import { COLOR } from "./colors.ts"; | ||||||
|  | import { getSheet, setSheet } from "./sheet.ts"; | ||||||
|  | import { mouseClick, mousePos } from "./mouse.ts"; | ||||||
|  | import { reGridWithGap } from "./util.ts"; | ||||||
|  | import { page } from "./viewsheets.ts"; | ||||||
|  | import { useSpritesheet } from "./builtins.ts"; | ||||||
|  | import { codeIcon, mapIcon, spriteIcon } from "./icons.ts"; | ||||||
|  |  | ||||||
|  | const gridX = 8; | ||||||
|  | const gridY = 40; | ||||||
|  | const cellW = 8; | ||||||
|  | const cellH = 8; | ||||||
|  | const gapX = 8; | ||||||
|  | const gapY = 8; | ||||||
|  |  | ||||||
|  | const sheetTypes = ["code", "spritesheet", "map"] as const; | ||||||
|  | const defaultSheetVal = { | ||||||
|  | 	code: () => "", | ||||||
|  | 	spritesheet: () => Array(128).fill(0).map(() => Array(64).fill(0)), | ||||||
|  | 	map: () => Array(64*64).fill(0).map(() => [0, 0]), | ||||||
|  | 	none: () =>null, | ||||||
|  | } | ||||||
|  |  | ||||||
|  | const update = () => { | ||||||
|  | 	if (mouseClick()) { | ||||||
|  | 		const {x: mouseX, y: mouseY} = mousePos(); | ||||||
|  | 		const g = reGridWithGap(mouseX, mouseY, gridX, gridY, cellW, cellH, gapX, gapY); | ||||||
|  | 		if (g) { | ||||||
|  | 			const {x, y: _y} = g; | ||||||
|  | 			const sheetType = sheetTypes[x]; | ||||||
|  | 			setSheet(page.activeSheet, sheetType, defaultSheetVal[sheetType]()); | ||||||
|  | 			page.tab = getSheet(page.activeSheet).sheet_type; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | const draw = () => { | ||||||
|  | 	clearScreen(); | ||||||
|  | 	useSpritesheet(page.activeSheet); | ||||||
|  | 	fillRect(0, 8, 128, 112, COLOR.BLACK); | ||||||
|  |  | ||||||
|  | 	drawText(4, 16, "Click an icon below to choose"); | ||||||
|  | 	drawText(4, 16+7, "this sheet's type..."); | ||||||
|  |  | ||||||
|  | 	// Draw the spritesheet | ||||||
|  | 	sheetTypes.forEach((sheetType, i) => { | ||||||
|  | 		const sx = gridX+(cellW+gapX)*(i%6); | ||||||
|  | 		const sy = gridY+(cellH+gapY)*Math.floor(i/6); | ||||||
|  | 		const icon = { | ||||||
|  | 			code: codeIcon, | ||||||
|  | 			spritesheet: spriteIcon, | ||||||
|  | 			map: mapIcon, | ||||||
|  | 			none: null, | ||||||
|  | 		}[sheetType]; | ||||||
|  | 		drawIcon(sx, sy, icon, COLOR.BLUE); | ||||||
|  | 	}); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export const nonetab = { | ||||||
|  | 	update, | ||||||
|  | 	draw, | ||||||
|  | } | ||||||
							
								
								
									
										130
									
								
								pico8_builtins.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										130
									
								
								pico8_builtins.txt
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,130 @@ | |||||||
|  | - [x] load | ||||||
|  | - [x] save | ||||||
|  | - [ ] folder | ||||||
|  | - [ ] ls | ||||||
|  | - [x] run | ||||||
|  | - [ ] stop | ||||||
|  | - [ ] resume | ||||||
|  | - [ ] assert | ||||||
|  | - [ ] reboot | ||||||
|  | - [ ] reset | ||||||
|  | - [ ] info | ||||||
|  | - [ ] flip | ||||||
|  | - [x] printh (as `log`) | ||||||
|  | - [ ] time/t | ||||||
|  | - [ ] stat | ||||||
|  | - [ ] extcmd | ||||||
|  |  | ||||||
|  | - [ ] clip | ||||||
|  | - [x] pset | ||||||
|  | - [ ] pget | ||||||
|  | - [ ] sget | ||||||
|  | - [ ] sset | ||||||
|  | - [ ] fget | ||||||
|  | - [ ] fset | ||||||
|  | - [?] print | ||||||
|  | - [ ] cursor | ||||||
|  | - [ ] color | ||||||
|  | - [x] cls | ||||||
|  | - [x] camera | ||||||
|  | - [x] circ | ||||||
|  | - [x] circfill | ||||||
|  | - [x] oval | ||||||
|  | - [x] ovalfill | ||||||
|  | - [ ] line | ||||||
|  | - [x] rect | ||||||
|  | - [x] rectfill | ||||||
|  | - [ ] pal | ||||||
|  | - [ ] palt | ||||||
|  | - [x] spr | ||||||
|  | - [ ] sspr | ||||||
|  | - [ ] fillp | ||||||
|  |  | ||||||
|  | - [x] btn | ||||||
|  | - [x] btnp | ||||||
|  |  | ||||||
|  | - [ ] sfx | ||||||
|  | - [ ] music | ||||||
|  |  | ||||||
|  | - [x] mget | ||||||
|  | - [x] mset | ||||||
|  | - [x] map | ||||||
|  | - [ ] tline | ||||||
|  |  | ||||||
|  | - [ ] peek | ||||||
|  | - [ ] poke | ||||||
|  | - [ ] peek2 | ||||||
|  | - [ ] poke2 | ||||||
|  | - [ ] peek4 | ||||||
|  | - [ ] poke4 | ||||||
|  | - [ ] memcpy | ||||||
|  | - [ ] reload | ||||||
|  | - [ ] cstore | ||||||
|  | - [ ] memset | ||||||
|  |  | ||||||
|  | - [ ] menuitem | ||||||
|  |  | ||||||
|  | - [ ] cartdata | ||||||
|  | - [ ] dget | ||||||
|  | - [ ] dset | ||||||
|  |  | ||||||
|  | - [ ] serial | ||||||
|  |  | ||||||
|  | - [ ] setmetatable | ||||||
|  | - [ ] getmetatable | ||||||
|  | - [ ] rawset | ||||||
|  | - [ ] rawget | ||||||
|  | - [ ] rawequal | ||||||
|  | - [ ] rawlen | ||||||
|  |  | ||||||
|  |  | ||||||
|  | == most things below here handled by js or easily included. | ||||||
|  |  | ||||||
|  | -- js Array has most things we want here | ||||||
|  | - [ ] add | ||||||
|  | - [ ] del | ||||||
|  | - [ ] deli | ||||||
|  | - [ ] count | ||||||
|  | - [ ] all | ||||||
|  | - [ ] foreach | ||||||
|  | - [ ] pairs | ||||||
|  |  | ||||||
|  | - [x] max | ||||||
|  | - [x] min | ||||||
|  | - [ ] mid | ||||||
|  | - [x] flr | ||||||
|  | - [x] ceil | ||||||
|  | - [x] cos | ||||||
|  | - [x] sin | ||||||
|  | - [x] atan2 | ||||||
|  | - [x] sqrt | ||||||
|  | - [x] abs | ||||||
|  | - [x] rnd | ||||||
|  | - [ ] srand | ||||||
|  |  | ||||||
|  | -- skipping these in favor of bitwise operations if needed | ||||||
|  | - [ ] band | ||||||
|  | - [ ] bor | ||||||
|  | - [ ] bxor | ||||||
|  | - [ ] bnot | ||||||
|  | - [ ] shl | ||||||
|  | - [ ] shr | ||||||
|  | - [ ] lshr | ||||||
|  | - [ ] rotl | ||||||
|  | - [ ] rotr | ||||||
|  |  | ||||||
|  | -- js comes with stuff here (String, Number, typeof, etc.) | ||||||
|  | - [ ] tostr | ||||||
|  | - [ ] tonum | ||||||
|  | - [ ] chr | ||||||
|  | - [ ] ord | ||||||
|  | - [ ] sub | ||||||
|  | - [ ] split | ||||||
|  | - [ ] type | ||||||
|  |  | ||||||
|  | -- js comes with stuff here | ||||||
|  | - [ ] cocreate | ||||||
|  | - [ ] coresume | ||||||
|  | - [ ] assert | ||||||
|  | - [ ] costatus | ||||||
|  | - [ ] yield | ||||||
							
								
								
									
										130
									
								
								repl.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										130
									
								
								repl.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,130 @@ | |||||||
|  | import { drawText} from "./builtins.ts"; | ||||||
|  | import { getKeysPressed, shiftKeyDown, shiftMap, K } from "./keyboard.ts"; | ||||||
|  | import { font } from "./font.ts"; | ||||||
|  | import { addToContext, evalCode } from "./runcode.ts"; | ||||||
|  | import { clearScreen, fillRect } from "./window.ts"; | ||||||
|  | import { COLOR } from "./colors.ts"; | ||||||
|  |  | ||||||
|  | const lineHeight = 6; | ||||||
|  |  | ||||||
|  | const history: Array<string> = []; | ||||||
|  | let historyIndex = history.length; | ||||||
|  | let textLinesAbove: Array<string> = []; | ||||||
|  | let maxLineLen = 0; | ||||||
|  | let currentLine = ""; | ||||||
|  | let index = 0; | ||||||
|  |  | ||||||
|  | export const resetRepl = () => { | ||||||
|  | 	historyIndex = history.length; | ||||||
|  | 	textLinesAbove.length = 0; | ||||||
|  | 	maxLineLen = 0; | ||||||
|  | 	currentLine = ""; | ||||||
|  | 	index = 0; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | const print = (arg: unknown) => { | ||||||
|  | 	textLinesAbove.push(...String(arg).split("\n").flatMap((line)=>{ | ||||||
|  | 		const wrap = []; | ||||||
|  | 		while (line.length) { | ||||||
|  | 			wrap.push(line.slice(0,32)); | ||||||
|  | 			line = line.slice(32); | ||||||
|  | 		} | ||||||
|  | 		return wrap; | ||||||
|  | 	})); | ||||||
|  | 	textLinesAbove = textLinesAbove.slice(-20); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | const printVal = (arg: unknown) => { | ||||||
|  | 	print(JSON.stringify(arg)); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | addToContext("print", print); | ||||||
|  | addToContext("printVal", printVal); | ||||||
|  |  | ||||||
|  | const update = () => { | ||||||
|  | 	// TODO: model this after the newer editmode.ts version using getKeyboardString | ||||||
|  | 	for (const key of getKeysPressed()) { | ||||||
|  | 		let char = String.fromCharCode(key).toLowerCase(); | ||||||
|  | 		if (shiftKeyDown()) { | ||||||
|  | 			if (char in shiftMap) { | ||||||
|  | 				char = shiftMap[char as keyof typeof shiftMap]; | ||||||
|  | 			} else { | ||||||
|  | 				char = char.toUpperCase(); | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 		if (char in font.chars) { | ||||||
|  | 			currentLine = currentLine.slice(0, index)+char+currentLine.slice(index); | ||||||
|  | 			index += 1; | ||||||
|  | 		} else if (key === K.BACKSPACE) { | ||||||
|  | 			if (index > 0) { | ||||||
|  | 				currentLine = currentLine.slice(0, index-1)+currentLine.slice(index); | ||||||
|  | 				index -= 1; | ||||||
|  | 			} | ||||||
|  | 		} else if (key === K.ARROW_LEFT) { | ||||||
|  | 			index -= 1; | ||||||
|  | 			if (index < 0) { | ||||||
|  | 				index = 0; | ||||||
|  | 			} | ||||||
|  | 		} else if (key === K.ARROW_RIGHT) { | ||||||
|  | 			index += 1; | ||||||
|  | 			if (index > currentLine.length) { | ||||||
|  | 				index = currentLine.length; | ||||||
|  | 			} | ||||||
|  | 		} else if (key === K.ARROW_UP) { | ||||||
|  | 			historyIndex -= 1; | ||||||
|  | 			if (historyIndex < 0) { | ||||||
|  | 				historyIndex = -1; | ||||||
|  | 			} | ||||||
|  | 			const lineAtHistory = history[historyIndex] ?? ""; | ||||||
|  | 			currentLine = lineAtHistory; | ||||||
|  | 			index = currentLine.length; | ||||||
|  | 		} else if (key === K.ARROW_DOWN) { | ||||||
|  | 			historyIndex += 1; | ||||||
|  | 			if (historyIndex > history.length) { | ||||||
|  | 				historyIndex = history.length; | ||||||
|  | 			} | ||||||
|  | 			const lineAtHistory = history[historyIndex] ?? ""; | ||||||
|  | 			currentLine = lineAtHistory; | ||||||
|  | 			index = currentLine.length; | ||||||
|  | 		} else if (key === K.ENTER) { | ||||||
|  | 			if (currentLine) { | ||||||
|  | 				history.push(currentLine); | ||||||
|  | 				historyIndex = history.length; | ||||||
|  | 			} | ||||||
|  | 			print("> "+currentLine); | ||||||
|  | 			try { | ||||||
|  | 				const ran = evalCode(currentLine); | ||||||
|  | 				if (ran !== undefined) { | ||||||
|  | 					printVal(ran); | ||||||
|  | 				} | ||||||
|  | 			} catch (err) { | ||||||
|  | 				print(err.name+":\n"+err.message); | ||||||
|  | 			} | ||||||
|  | 			maxLineLen = 0; | ||||||
|  | 			currentLine = ""; | ||||||
|  | 			index = 0; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	maxLineLen = Math.max(maxLineLen, currentLine.length); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | const drawTextAbove = () => { | ||||||
|  | 	textLinesAbove.forEach((line, i) => { | ||||||
|  | 		fillRect(0, 1+i*lineHeight, 4*(line.length+1)+1, lineHeight+1, COLOR.BLACK); | ||||||
|  | 		drawText(0, 1+i*lineHeight, line); | ||||||
|  | 	}); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | const draw = () => { | ||||||
|  | 	clearScreen(); | ||||||
|  |  | ||||||
|  | 	drawTextAbove(); | ||||||
|  |  | ||||||
|  | 	fillRect(0, 1+textLinesAbove.length*lineHeight, 4*(2+maxLineLen+1)+1, lineHeight+1, COLOR.BLACK); | ||||||
|  | 	fillRect((2+index)*4, textLinesAbove.length*lineHeight+1, 4, lineHeight-1, COLOR.RED); | ||||||
|  | 	drawText(0, 1+textLinesAbove.length*lineHeight, "> "+currentLine); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export const repl = { | ||||||
|  | 	update, draw | ||||||
|  | } | ||||||
							
								
								
									
										56
									
								
								runcode.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										56
									
								
								runcode.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,56 @@ | |||||||
|  | // deno-lint-ignore no-explicit-any | ||||||
|  | const G: any = { | ||||||
|  | 	eval: eval, | ||||||
|  | }; | ||||||
|  | // deno-lint-ignore no-explicit-any | ||||||
|  | const builtins: any = {}; | ||||||
|  | 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 = (code: string) => { | ||||||
|  | 	try { | ||||||
|  | 		new Function(code); | ||||||
|  | 	} catch (err) { | ||||||
|  | 		throw err; | ||||||
|  | 	} | ||||||
|  | 	const fn = new Function("context", ` | ||||||
|  | 		with (context) { | ||||||
|  | 			${code} | ||||||
|  | 		} | ||||||
|  | 	`); | ||||||
|  | 	return 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; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // deno-lint-ignore no-explicit-any | ||||||
|  | export const addToContext = (name: string, value: any) => { | ||||||
|  | 	builtins[name] = value; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export const getBuiltins = () => { | ||||||
|  | 	return builtins; | ||||||
|  | } | ||||||
							
								
								
									
										55
									
								
								sheet.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										55
									
								
								sheet.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,55 @@ | |||||||
|  | import { getCart } from "./cart.ts"; | ||||||
|  | import { LinearGrid } from "./util.ts"; | ||||||
|  | // import { runCode, addToContext } from "./runcode.ts"; | ||||||
|  |  | ||||||
|  | // "code" | "spritesheet" | "map" | "sfx" | "patterns" | "fonts" | ||||||
|  | export type Sheet = { | ||||||
|  | 	sheet_type: "code", | ||||||
|  | 	value: string, | ||||||
|  | } | { | ||||||
|  | 	sheet_type: "spritesheet", | ||||||
|  | 	value: Array<Array<number>>, | ||||||
|  | } | { | ||||||
|  | 	sheet_type: "map", | ||||||
|  | 	value: Array<[number, number]>, | ||||||
|  | } | { | ||||||
|  | 	sheet_type: "none", | ||||||
|  | 	value: null, | ||||||
|  | } | ||||||
|  | export type SheetType = Sheet["sheet_type"]; | ||||||
|  |  | ||||||
|  | export const getSheet = (n: number) => { | ||||||
|  | 	return getCart()[n]; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // deno-lint-ignore no-explicit-any | ||||||
|  | export const setSheet = (n: number, type: SheetType, value: any) => { | ||||||
|  | 	return getCart()[n] = {sheet_type: type, value}; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export const getCodeSheet = (sheet: number) => { | ||||||
|  | 	const {sheet_type, value} = getSheet(sheet); | ||||||
|  | 	if (sheet_type !== "code") { | ||||||
|  | 		throw "Trying to use a non-code sheet as code." | ||||||
|  | 	} | ||||||
|  | 	return value; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export const getSpriteSheet = (sheet: number) => { | ||||||
|  | 	const {sheet_type, value} = getSheet(sheet); | ||||||
|  | 	if (sheet_type !== "spritesheet") { | ||||||
|  | 		throw Error("Trying to use a non-sprite sheet as a spritesheet."); | ||||||
|  | 	} | ||||||
|  | 	while (value.length < 128) { | ||||||
|  | 		value.push(Array(64).fill(0)); | ||||||
|  | 	} | ||||||
|  | 	return value; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export const getMapSheet = (sheet: number) => { | ||||||
|  | 	const {sheet_type, value} = getSheet(sheet); | ||||||
|  | 	if (sheet_type !== "map") { | ||||||
|  | 		throw "Trying to use a non-map sheet as a map." | ||||||
|  | 	} | ||||||
|  | 	return LinearGrid(value, 64); | ||||||
|  | } | ||||||
							
								
								
									
										134
									
								
								spritetab.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										134
									
								
								spritetab.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,134 @@ | |||||||
|  | import { clearScreen, fillRect } from "./window.ts"; | ||||||
|  | import { drawSprite, drawText } from "./builtins.ts"; | ||||||
|  | import { COLOR } from "./colors.ts"; | ||||||
|  | import { getSpriteSheet, setSheet } from "./sheet.ts"; | ||||||
|  | import { mouseClick, mouseHeld, mousePos } from "./mouse.ts"; | ||||||
|  | import { drawTransparentRect, inRect, outlineRect, reGrid } from "./util.ts"; | ||||||
|  | import { page } from "./viewsheets.ts"; | ||||||
|  | import { useSpritesheet } from "./builtins.ts"; | ||||||
|  |  | ||||||
|  | const state = { | ||||||
|  | 	selectedSprite: 0, | ||||||
|  | 	selectedColor: 0, | ||||||
|  | 	get spriteSheetPage() { | ||||||
|  | 		return Math.floor(this.selectedSprite/64); | ||||||
|  | 	}, | ||||||
|  | 	set spriteSheetPage(val) { | ||||||
|  | 		this.selectedSprite = 64*val+this.spriteWithinPage; | ||||||
|  | 	}, | ||||||
|  | 	get spriteWithinPage() { | ||||||
|  | 		return this.selectedSprite%64; | ||||||
|  | 	}, | ||||||
|  | 	set spriteWithinPage(val) { | ||||||
|  | 		this.selectedSprite = 64*this.spriteSheetPage+val; | ||||||
|  | 	}, | ||||||
|  | 	get sprites() { | ||||||
|  | 		return getSpriteSheet(page.activeSheet); | ||||||
|  | 	}, | ||||||
|  | 	set sprites(val) { | ||||||
|  | 		setSheet(page.activeSheet, "spritesheet", val); | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | const paletteX = 88; | ||||||
|  | const paletteY = 16; | ||||||
|  | const swatchW = 8; | ||||||
|  | const swatchH = 8; | ||||||
|  | const paletteW = 4; | ||||||
|  | const paletteH = 6; | ||||||
|  |  | ||||||
|  | const spriteX = 8; | ||||||
|  | const spriteY = 16; | ||||||
|  | const pixelW = 8; | ||||||
|  | const pixelH = 8; | ||||||
|  |  | ||||||
|  | const spriteW = 8; | ||||||
|  | const spriteH = 8; | ||||||
|  |  | ||||||
|  | const sheetX = 0; | ||||||
|  | const sheetY = 88; | ||||||
|  | const sheetW = 16; | ||||||
|  | const sheetH = 4; | ||||||
|  |  | ||||||
|  | const spriteSheetPageSwapX = 121; | ||||||
|  | const spriteSheetPageSwapY = 80; | ||||||
|  | const spriteSheetPageSwapW = 7; | ||||||
|  | const spriteSheetPageSwapH = 7; | ||||||
|  |  | ||||||
|  | const update = () => { | ||||||
|  | 	if (mouseHeld()) { | ||||||
|  | 		const {x: mouseX, y: mouseY} = mousePos(); | ||||||
|  | 		const inPalette = inRect(mouseX, mouseY, paletteX, paletteY, paletteW*swatchW, paletteH*swatchH); | ||||||
|  | 		const inSprite = inRect(mouseX, mouseY, spriteX, spriteY, spriteW*pixelW, spriteH*pixelH); | ||||||
|  | 		const inSheet = inRect(mouseX, mouseY, sheetX, sheetY, sheetW*spriteW, sheetH*spriteH); | ||||||
|  | 		if (inPalette) { | ||||||
|  | 			const {x, y} = reGrid(mouseX, mouseY, paletteX, paletteY, swatchW, swatchH); | ||||||
|  | 			state.selectedColor = paletteW*y+x; | ||||||
|  | 		} | ||||||
|  | 		if (inSprite) { | ||||||
|  | 			const {x, y} = reGrid(mouseX, mouseY, spriteX, spriteY, pixelW, pixelH); | ||||||
|  | 			const pixelNumber = spriteW*y+x; | ||||||
|  | 			state.sprites[state.selectedSprite][pixelNumber] = state.selectedColor; | ||||||
|  | 		} | ||||||
|  | 		if (inSheet) { | ||||||
|  | 			const {x, y} = reGrid(mouseX, mouseY, sheetX, sheetY, spriteW, spriteH); | ||||||
|  | 			state.spriteWithinPage = sheetW*y+x; | ||||||
|  | 		} | ||||||
|  | 	} else if (mouseClick()) { | ||||||
|  | 		const {x: mouseX, y: mouseY} = mousePos(); | ||||||
|  | 		const inSpriteSheetPageSwap = inRect(mouseX, mouseY, spriteSheetPageSwapX, spriteSheetPageSwapY, spriteSheetPageSwapW, spriteSheetPageSwapH); | ||||||
|  | 		if (inSpriteSheetPageSwap) { | ||||||
|  | 			state.spriteSheetPage = (1+state.spriteSheetPage)%2; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | const draw = () => { | ||||||
|  | 	const {sprites, selectedSprite, selectedColor} = state; | ||||||
|  | 	clearScreen(); | ||||||
|  | 	useSpritesheet(page.activeSheet); | ||||||
|  | 	fillRect(0, 8, 128, 112, COLOR.DARKGRAY); | ||||||
|  |  | ||||||
|  | 	// Draw the palette | ||||||
|  | 	fillRect(paletteX-1, paletteY-1, (paletteW*swatchW)+2, (paletteH*swatchH)+2, COLOR.BLACK); | ||||||
|  | 	Object.keys(COLOR).forEach((name, i) => { | ||||||
|  | 		const swatchX = paletteX+swatchW*(i%paletteW); | ||||||
|  | 		const swatchY = paletteY+swatchH*Math.floor(i/paletteW); | ||||||
|  | 		fillRect(swatchX, swatchY, swatchW, swatchH, COLOR[name as keyof typeof COLOR]); | ||||||
|  | 		if (name == "TRANSPARENT") { | ||||||
|  | 			// transparent | ||||||
|  | 			drawTransparentRect(swatchX, swatchY, swatchW, swatchH); | ||||||
|  | 		} | ||||||
|  | 		if (i === selectedColor) { | ||||||
|  | 			outlineRect(swatchX, swatchY, swatchW, swatchH, name === "WHITE" ? COLOR.BLACK : COLOR.WHITE); | ||||||
|  | 		} | ||||||
|  | 	}); | ||||||
|  |  | ||||||
|  | 	// Draw the current sprite | ||||||
|  | 	fillRect(spriteX-1, spriteY-1, (spriteW*pixelW)+2, (spriteH*pixelH)+2, COLOR.BLACK); | ||||||
|  | 	drawTransparentRect(spriteX, spriteY, (spriteW*pixelW), (spriteH*pixelH)); | ||||||
|  | 	sprites[selectedSprite].forEach((pix, i) => { | ||||||
|  | 		fillRect(spriteX+pixelW*(i%spriteW), spriteY+pixelH*Math.floor(i/spriteW), pixelW, pixelH, pix); | ||||||
|  | 	}); | ||||||
|  |  | ||||||
|  | 	// Draw the spritesheet page swap button | ||||||
|  | 	fillRect(spriteSheetPageSwapX, spriteSheetPageSwapY, spriteSheetPageSwapW, spriteSheetPageSwapH, COLOR.BLUE); | ||||||
|  | 	drawText(spriteSheetPageSwapX+2, spriteSheetPageSwapY+1, state.spriteSheetPage.toString()); | ||||||
|  | 	 | ||||||
|  | 	// Draw the spritesheet | ||||||
|  | 	fillRect(sheetX, sheetY-1, (sheetW*spriteW), (sheetH*spriteH)+1, COLOR.BLACK); | ||||||
|  | 	Array(64).fill(0).forEach((_, i) => { | ||||||
|  | 		const sprI = i+64*state.spriteSheetPage; | ||||||
|  | 		const sprX = sheetX+spriteW*(i%sheetW); | ||||||
|  | 		const sprY = sheetY+spriteH*Math.floor(i/sheetW); | ||||||
|  | 		drawSprite(sprX, sprY, sprI); | ||||||
|  | 		if (i === state.spriteWithinPage) { | ||||||
|  | 			outlineRect(sprX, sprY, spriteW, spriteH, COLOR.WHITE); | ||||||
|  | 		} | ||||||
|  | 	}); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export const spritetab = { | ||||||
|  | 	update, | ||||||
|  | 	draw, | ||||||
|  | } | ||||||
							
								
								
									
										98
									
								
								util.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										98
									
								
								util.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,98 @@ | |||||||
|  | import { COLOR } from "./colors.ts"; | ||||||
|  | import { fillRect, setPixelColor } from "./window.ts"; | ||||||
|  |  | ||||||
|  | export const inRect = (x: number, y: number, rectX: number, rectY: number, rectW: number, rectH: number) => { | ||||||
|  | 	return ( | ||||||
|  | 		x >= rectX && | ||||||
|  | 		x < rectX+rectW && | ||||||
|  | 		y >= rectY && | ||||||
|  | 		y < rectY+rectH | ||||||
|  | 	) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export function reGridWithGap (x: number, y: number, gridX: number, gridY: number, cellW: number, cellH: number, gapX: number, gapY: number): {x: number, y: number} | null { | ||||||
|  | 	const gx = Math.floor((x-gridX)/(cellW+gapX)); | ||||||
|  | 	const gy = Math.floor((y-gridY)/(cellH+gapY)); | ||||||
|  | 	if (x >= gridX+(cellW+gapX)*gx+cellW || y >= gridY+(cellH+gapY)*gy+cellH) { | ||||||
|  | 		return null; | ||||||
|  | 	} | ||||||
|  | 	return { | ||||||
|  | 		x: Math.floor((x-gridX)/(cellW+gapX)), | ||||||
|  | 		y: Math.floor((y-gridY)/(cellH+gapY)), | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export function reGrid (x: number, y: number, gridX: number, gridY: number, cellW: number, cellH: number): {x: number, y: number} { | ||||||
|  | 	const gx = Math.floor((x-gridX)/(cellW)); | ||||||
|  | 	const gy = Math.floor((y-gridY)/(cellH)); | ||||||
|  | 	return { | ||||||
|  | 		x: gx, | ||||||
|  | 		y: gy, | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export const outlineRect = (x: number, y: number, w: number, h: number, color: number) => { | ||||||
|  | 	fillRect(x, y, w, 1, color); | ||||||
|  | 	fillRect(x, y, 1, h, color); | ||||||
|  | 	fillRect(x+w-1, y, 1, h, color); | ||||||
|  | 	fillRect(x, y+h-1, w, 1, color); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export const drawTransparentRect = (x: number, y: number, w: number, h: number) => { | ||||||
|  | 	Array(w*h).fill(0).map((_z, j) => { | ||||||
|  | 		const jx = j%w; | ||||||
|  | 		const jy = Math.floor(j/w); | ||||||
|  | 		setPixelColor(x+jx, y+jy, (jx+jy)%2 ? COLOR.BLACK : COLOR.DARKGRAY); | ||||||
|  | 	}) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export const drawVoidRect = (x: number, y: number, w: number, h: number) => { | ||||||
|  | 	Array(w*h).fill(0).map((_z, j) => { | ||||||
|  | 		const jx = j%w; | ||||||
|  | 		const jy = Math.floor(j/w); | ||||||
|  | 		setPixelColor(x+jx, y+jy, (jx+jy)%2 ? COLOR.BLACK : COLOR.DARKERBLUE); | ||||||
|  | 	}) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export const subgrid = <T>(array: Array<T>, gridW: number, x: number, y: number, w: number, h: number): Array<T|undefined> => { | ||||||
|  | 	return Array(h).fill(0).flatMap((_, i) => { | ||||||
|  | 		if (y+i < 0 || y+i > array.length/gridW) { | ||||||
|  | 			return Array(w).fill(undefined); | ||||||
|  | 		} | ||||||
|  | 		const x0 = Math.max(0, x); | ||||||
|  | 		const x1 = Math.min(x+w, gridW); | ||||||
|  | 		const start = (y+i)*gridW+x0; | ||||||
|  | 		const end = (y+i)*gridW+x1; | ||||||
|  | 		const before = Array(x0 - x).fill(undefined); | ||||||
|  | 		const after = Array((x+w) - x1).fill(undefined); | ||||||
|  | 		const middle = array.slice(start, end); | ||||||
|  | 		return [...before, ...middle, ...after]; | ||||||
|  | 	}) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export const LinearGrid = <T>(array: Array<T>, gridW: number) => { | ||||||
|  | 	return { | ||||||
|  | 		get(x: number, y: number) { | ||||||
|  | 			return array[this.coordsToIndex(x, y)] | ||||||
|  | 		}, | ||||||
|  | 		getIndex(i: number) { | ||||||
|  | 			return array[i]; | ||||||
|  | 		}, | ||||||
|  | 		set(x: number, y: number, value: T) { | ||||||
|  | 			array[this.coordsToIndex(x, y)] = value; | ||||||
|  | 		}, | ||||||
|  | 		setIndex(i: number, value: T) { | ||||||
|  | 			array[i] = value; | ||||||
|  | 		}, | ||||||
|  | 		values: array, | ||||||
|  | 		indexToCoords: (i: number) => { | ||||||
|  | 			return [i%gridW, Math.floor(i/gridW)]; | ||||||
|  | 		}, | ||||||
|  | 		coordsToIndex: (x: number, y: number) => { | ||||||
|  | 			return y*gridW+x; | ||||||
|  | 		}, | ||||||
|  | 		// TODO: make alterations to subgrid affect parent grid | ||||||
|  | 		subgrid: (x: number, y: number, w: number, h: number) => LinearGrid(subgrid(array, gridW, x, y, w, h), w), | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
							
								
								
									
										63
									
								
								viewsheets.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										63
									
								
								viewsheets.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,63 @@ | |||||||
|  | import { clearScreen, fillRect } from "./window.ts"; | ||||||
|  | import { drawIcon, drawText } from "./builtins.ts"; | ||||||
|  | import { COLOR } from "./colors.ts"; | ||||||
|  | import { getSheet } from "./sheet.ts"; | ||||||
|  | import { mouseClick, mousePos } from "./mouse.ts"; | ||||||
|  | import { getCart } from "./cart.ts"; | ||||||
|  | import { font } from "./font.ts"; | ||||||
|  | import { codeIcon, spriteIcon, mapIcon } from "./icons.ts"; | ||||||
|  | import { reGridWithGap } from "./util.ts"; | ||||||
|  |  | ||||||
|  | const fontHeight = font.height; | ||||||
|  |  | ||||||
|  | export const page = {activeSheet: 0, tab: "sheet"}; | ||||||
|  |  | ||||||
|  | const gridX = 8; | ||||||
|  | const gridY = 20; | ||||||
|  | const cellW = 22; | ||||||
|  | const cellH = 16; | ||||||
|  | const gapX = 8; | ||||||
|  | const gapY = 8; | ||||||
|  |  | ||||||
|  | const update = () => { | ||||||
|  | 	if (mouseClick()) { | ||||||
|  | 		const {x: mouseX, y: mouseY} = mousePos(); | ||||||
|  | 		const g = reGridWithGap(mouseX, mouseY, gridX, gridY, cellW, cellH, gapX, gapY); | ||||||
|  | 		if (g) { | ||||||
|  | 			const {x, y} = g; | ||||||
|  | 			page.activeSheet = 4*y+x; | ||||||
|  | 			const sheet = getSheet(page.activeSheet); | ||||||
|  | 			if (!sheet) { | ||||||
|  | 				console.log(x, y, g); | ||||||
|  | 			} | ||||||
|  | 			page.tab = getSheet(page.activeSheet).sheet_type; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | const draw = () => { | ||||||
|  | 	clearScreen(); | ||||||
|  | 	fillRect(0, 8, 128, 112, COLOR.DARKGRAY); | ||||||
|  |  | ||||||
|  | 	// Draw the sheet grid | ||||||
|  | 	getCart().forEach((sheet, i) => { | ||||||
|  | 		const x = gridX+(cellW+gapX)*(i%4); | ||||||
|  | 		const y = gridY+(cellH+gapY)*Math.floor(i/4); | ||||||
|  | 		fillRect(x, y, cellW, cellH, i===page.activeSheet ? COLOR.PURPLE : COLOR.BLACK); | ||||||
|  | 		drawText(x+(cellW)/2, y+(cellH-fontHeight)/2, i.toString().padStart(2,"0")); | ||||||
|  | 		const icon = { | ||||||
|  | 			code: codeIcon, | ||||||
|  | 			spritesheet: spriteIcon, | ||||||
|  | 			map: mapIcon, | ||||||
|  | 			none: null, | ||||||
|  | 		}[sheet.sheet_type]; | ||||||
|  | 		if (icon) { | ||||||
|  | 			drawIcon(x+2, y+4, icon, COLOR.WHITE); | ||||||
|  | 		} | ||||||
|  | 	}); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export const viewsheets = { | ||||||
|  | 	update, | ||||||
|  | 	draw, | ||||||
|  | } | ||||||
							
								
								
									
										253
									
								
								window.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										253
									
								
								window.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,253 @@ | |||||||
|  | import { | ||||||
|  | 	createWindow, | ||||||
|  | 	getProcAddress, | ||||||
|  | 	gl, | ||||||
|  | } from "./deps.ts"; | ||||||
|  | export {mainloop} from "./deps.ts"; | ||||||
|  | import { COLOR, palette } from "./colors.ts"; | ||||||
|  |  | ||||||
|  | export const gameWindow = createWindow({ | ||||||
|  | 	title: "Faux", | ||||||
|  | 	width: 1024, | ||||||
|  | 	height: 1024, | ||||||
|  | 	resizable: false, | ||||||
|  | 	glVersion: [3, 2], | ||||||
|  | 	gles: true, | ||||||
|  | }); | ||||||
|  |  | ||||||
|  | gl.load(getProcAddress); | ||||||
|  |  | ||||||
|  | function loadShader(type: number, src: string) { | ||||||
|  | 	const shader = gl.CreateShader(type); | ||||||
|  | 	gl.ShaderSource( | ||||||
|  | 		shader, | ||||||
|  | 		1, | ||||||
|  | 		new Uint8Array( | ||||||
|  | 			new BigUint64Array([ | ||||||
|  | 				BigInt( | ||||||
|  | 					Deno.UnsafePointer.value( | ||||||
|  | 						Deno.UnsafePointer.of(new TextEncoder().encode(src)), | ||||||
|  | 					), | ||||||
|  | 				), | ||||||
|  | 			]).buffer, | ||||||
|  | 		), | ||||||
|  | 		new Int32Array([src.length]), | ||||||
|  | 	); | ||||||
|  | 	gl.CompileShader(shader); | ||||||
|  | 	const status = new Int32Array(1); | ||||||
|  | 	gl.GetShaderiv(shader, gl.COMPILE_STATUS, status); | ||||||
|  | 	if (status[0] === gl.FALSE) { | ||||||
|  | 		const logLength = new Int32Array(1); | ||||||
|  | 		gl.GetShaderiv(shader, gl.INFO_LOG_LENGTH, logLength); | ||||||
|  | 		const log = new Uint8Array(logLength[0]); | ||||||
|  | 		gl.GetShaderInfoLog(shader, logLength[0], logLength, log); | ||||||
|  | 		console.log(new TextDecoder().decode(log)); | ||||||
|  | 		gl.DeleteShader(shader); | ||||||
|  | 		return 0; | ||||||
|  | 	} | ||||||
|  | 	return shader; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | const vShaderSrc = ` | ||||||
|  | attribute vec4 vPosition; | ||||||
|  | attribute vec4 vCol; | ||||||
|  | varying vec4 color; | ||||||
|  | void main() { | ||||||
|  | 	gl_Position = vPosition; | ||||||
|  | 	color = vCol; | ||||||
|  | } | ||||||
|  | `; | ||||||
|  |  | ||||||
|  | const fShaderSrc = ` | ||||||
|  | 	precision mediump float; | ||||||
|  | 	varying vec4 color; | ||||||
|  | 	void main() { | ||||||
|  | 		gl_FragColor = color; | ||||||
|  | 	} | ||||||
|  |  `; | ||||||
|  |  | ||||||
|  | const vShader = loadShader(gl.VERTEX_SHADER, vShaderSrc); | ||||||
|  | const fShader = loadShader(gl.FRAGMENT_SHADER, fShaderSrc); | ||||||
|  |  | ||||||
|  | const program = gl.CreateProgram(); | ||||||
|  | gl.AttachShader(program, vShader); | ||||||
|  | gl.AttachShader(program, fShader); | ||||||
|  |  | ||||||
|  | gl.BindAttribLocation(program, 0, new TextEncoder().encode("vPosition\0")); | ||||||
|  | gl.BindAttribLocation(program, 1, new TextEncoder().encode("vCol\0")); | ||||||
|  |  | ||||||
|  | gl.LinkProgram(program); | ||||||
|  |  | ||||||
|  | const status = new Int32Array(1); | ||||||
|  | gl.GetProgramiv(program, gl.LINK_STATUS, status); | ||||||
|  | if (status[0] === gl.FALSE) { | ||||||
|  | 	const logLength = new Int32Array(1); | ||||||
|  | 	gl.GetProgramiv(program, gl.INFO_LOG_LENGTH, logLength); | ||||||
|  | 	const log = new Uint8Array(logLength[0]); | ||||||
|  | 	gl.GetProgramInfoLog(program, logLength[0], logLength, log); | ||||||
|  | 	console.log(new TextDecoder().decode(log)); | ||||||
|  | 	gl.DeleteProgram(program); | ||||||
|  | 	Deno.exit(1); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | gl.ClearColor(0.0, 0.0, 0.0, 1.0); | ||||||
|  |  | ||||||
|  | addEventListener("resize", (event) => { | ||||||
|  | 	gl.Viewport(0, 0, event.width, event.height); | ||||||
|  | }); | ||||||
|  |  | ||||||
|  | const pixelsPerRow = 128; | ||||||
|  |  | ||||||
|  | const top = 1; | ||||||
|  | const left = -1; | ||||||
|  | const cell = 2/pixelsPerRow; | ||||||
|  |  | ||||||
|  | const px = (x: number, y: number) => { | ||||||
|  | 	// deno-fmt-ignore | ||||||
|  | 	return [ | ||||||
|  | 		left + x*cell, top - y*cell, 0, | ||||||
|  | 		left + (x+1)*cell, top - y*cell, 0, | ||||||
|  | 		left + x*cell, top - (y+1)*cell, 0, | ||||||
|  | 		left + (x+1)*cell, top - y*cell, 0, | ||||||
|  | 		left + x*cell, top - (y+1)*cell, 0, | ||||||
|  | 		left + (x+1)*cell, top - (y+1)*cell, 0, | ||||||
|  | 	]; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | const paletteX6 = palette.map(rgba => [...rgba, ...rgba, ...rgba, ...rgba, ...rgba, ...rgba]); | ||||||
|  |  | ||||||
|  | const c = (n: number) => { | ||||||
|  | 	return paletteX6[n]; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | const allPixelTriangles = new Float32Array( | ||||||
|  | 	Array(pixelsPerRow*pixelsPerRow).fill(null).flatMap((_, i) => px(i%pixelsPerRow,Math.floor(i/pixelsPerRow))) | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | const allPixelColors = new Float32Array( | ||||||
|  | 	Array(pixelsPerRow*pixelsPerRow).fill(null).flatMap(() => c(1)) | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | export const cameraPos = { | ||||||
|  | 	x: 0, | ||||||
|  | 	y: 0, | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export const setPixelColorRaw = (x: number, y: number, color: number) => { | ||||||
|  | 	if (x < 0 || y < 0 || x > 127 || y > 127) { | ||||||
|  | 		return; | ||||||
|  | 	} | ||||||
|  | 	if (color !== 0) { | ||||||
|  | 		const col = c(color); | ||||||
|  | 		allPixelColors.set(col, 4*6*(128*y+x)); | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export const setPixelColor = (x: number, y: number, color: number) => { | ||||||
|  | 	return setPixelColorRaw(Math.floor(x - cameraPos.x), Math.floor(y - cameraPos.y), color); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export const setPixelsInRect = (x: number, y: number, w: number, pixels: Array<number>) => { | ||||||
|  | 	for (let i = 0; i < pixels.length; i++) { | ||||||
|  | 		setPixelColor(x+i%w, y+Math.floor(i/w), pixels[i]); | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export const setPixelsInRectRaw = (x: number, y: number, w: number, pixels: Array<number>) => { | ||||||
|  | 	for (let i = 0; i < pixels.length; i++) { | ||||||
|  | 		setPixelColorRaw(x+i%w, y+Math.floor(i/w), pixels[i]); | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export const fillRect = (x: number, y: number, w: number, h: number, color: number) => { | ||||||
|  | 	setPixelsInRect(x, y, w, Array(w*h).fill(color)); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export const fillCircle = (x: number, y: number, r: number, color: number) => { | ||||||
|  | 	const left = Math.floor(x-r-1); | ||||||
|  | 	const top = Math.floor(y-r-1); | ||||||
|  | 	for (let i = left; i <= Math.ceil(x+r+1); i ++) { | ||||||
|  | 		for (let j = top; j <= Math.ceil(y+r+1); j ++) { | ||||||
|  | 			if (Math.sqrt((x-i)**2 + (y-j)**2) <= r+0.5) { | ||||||
|  | 				setPixelColor(i, j, color); | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export const outlineCircle = (x: number, y: number, r: number, color: number) => { | ||||||
|  | 	const left = Math.floor(x-r-1); | ||||||
|  | 	const top = Math.floor(y-r-1); | ||||||
|  | 	const inR = (d: number) => d <= r+0.5 && d > r-0.5; | ||||||
|  | 	for (let i = left; i <= Math.ceil(x+r+1); i ++) { | ||||||
|  | 		for (let j = top; j <= Math.ceil(y+r+1); j ++) { | ||||||
|  | 			const d = Math.sqrt((x-i)**2 + (y-j)**2); | ||||||
|  | 			if (inR(d)) { | ||||||
|  | 				const dh = Math.sqrt((x-(i+Math.sign(i-x)))**2 + (y-j)**2); | ||||||
|  | 				const dv = Math.sqrt((x-i)**2 + (y-(j+Math.sign(j-y)))**2); | ||||||
|  | 				const h = Math.abs(x-i) > Math.abs(y-j); | ||||||
|  | 				if (!inR(h ? dh : dv)) { | ||||||
|  | 					setPixelColor(i, j, color); | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export const fillEllipse = (x0: number, y0: number, x1: number, y1: number, color: number) => { | ||||||
|  | 	const x = 0.5*(x0 + x1); | ||||||
|  | 	const y = 0.5*(y0 + y1); | ||||||
|  | 	const rx = Math.abs(x0-x1)/2; | ||||||
|  | 	const ry = Math.abs(y0-y1)/2; | ||||||
|  | 	const left = Math.floor(x-rx-1); | ||||||
|  | 	const top = Math.floor(y-ry-1); | ||||||
|  | 	for (let i = left; i <= Math.ceil(x+rx+1); i ++) { | ||||||
|  | 		for (let j = top; j <= Math.ceil(y+ry+1); j ++) { | ||||||
|  | 			if (Math.sqrt(((x-i)/rx)**2 + ((y-j)/ry)**2) <= 1+(1/(rx+ry))) { | ||||||
|  | 				setPixelColor(i, j, color); | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export const outlineEllipse = (x0: number, y0: number, x1: number, y1: number, color: number) => { | ||||||
|  | 	const x = 0.5*(x0 + x1); | ||||||
|  | 	const y = 0.5*(y0 + y1); | ||||||
|  | 	const rx = Math.abs(x0-x1)/2; | ||||||
|  | 	const ry = Math.abs(y0-y1)/2; | ||||||
|  | 	const left = Math.floor(x-rx-1); | ||||||
|  | 	const top = Math.floor(y-ry-1); | ||||||
|  | 	const inR = (d: number) => d <= 1+1/(rx+ry); | ||||||
|  | 	for (let i = left; i <= Math.ceil(x+rx+1); i ++) { | ||||||
|  | 		for (let j = top; j <= Math.ceil(y+ry+1); j ++) { | ||||||
|  | 			const d = Math.sqrt(((x-i)/rx)**2 + ((y-j)/ry)**2); | ||||||
|  | 			if (inR(d)) { | ||||||
|  | 				const dh = Math.sqrt(((x-(i+Math.sign(i-x)))/rx)**2 + ((y-j)/ry)**2); | ||||||
|  | 				const dv = Math.sqrt(((x-i)/rx)**2 + ((y-(j+Math.sign(j-y)))/ry)**2); | ||||||
|  | 				if (!inR(dh) || !inR(dv)) { | ||||||
|  | 					setPixelColor(i, j, color); | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export const fillRectRaw = (x: number, y: number, w: number, h: number, color: number) => { | ||||||
|  | 	setPixelsInRectRaw(x, y, w, Array(w*h).fill(color)); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export const clearScreen = (color?: number) => { | ||||||
|  | 	fillRectRaw(0, 0, 128, 128, color ?? COLOR.BLACK); | ||||||
|  | 	// allPixelColors.fill(0); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export const frame = () => { | ||||||
|  | 	gl.Clear(gl.COLOR_BUFFER_BIT); | ||||||
|  | 	gl.UseProgram(program); | ||||||
|  | 	gl.VertexAttribPointer(0, 3, gl.FLOAT, gl.FALSE, 0, allPixelTriangles); | ||||||
|  | 	gl.VertexAttribPointer(1, 4, gl.FLOAT, gl.FALSE, 0, allPixelColors); | ||||||
|  | 	gl.EnableVertexAttribArray(0); | ||||||
|  | 	gl.EnableVertexAttribArray(1); | ||||||
|  | 	gl.DrawArrays(gl.TRIANGLES, 0, 6*pixelsPerRow*pixelsPerRow); | ||||||
|  | 	gameWindow.swapBuffers(); | ||||||
|  | } | ||||||
		Reference in New Issue
	
	Block a user