From 3a8f5ccd3586e11252f927541878d2bd1f2b60b6 Mon Sep 17 00:00:00 2001 From: goldbuick Date: Wed, 1 Jan 2025 22:11:56 -0500 Subject: [PATCH 1/6] dropping onborrow and onshadow colors --- zss/device/synth.ts | 1 + zss/gadget/data/state.ts | 2 +- zss/mapping/2d.ts | 10 +- zss/memory/book.ts | 2 +- zss/memory/index.ts | 254 +----------------------------- zss/memory/rendertogadget.ts | 291 +++++++++++++++++++++++++++++++++++ zss/words/color.ts | 2 - zss/words/types.ts | 2 - 8 files changed, 301 insertions(+), 263 deletions(-) create mode 100644 zss/memory/rendertogadget.ts diff --git a/zss/device/synth.ts b/zss/device/synth.ts index e6447e58..339b0962 100644 --- a/zss/device/synth.ts +++ b/zss/device/synth.ts @@ -517,6 +517,7 @@ function createsynth() { // reset starting offset --pacercount if (pacercount === 0) { + pacer.clear() pacertime = -1 } break diff --git a/zss/gadget/data/state.ts b/zss/gadget/data/state.ts index 14e03024..55d62f98 100644 --- a/zss/gadget/data/state.ts +++ b/zss/gadget/data/state.ts @@ -44,8 +44,8 @@ export const TAPE_MAX_LINES = 128 export enum TAPE_DISPLAY { TOP, - BOTTOM, FULL, + BOTTOM, SPLIT_Y, SPLIT_Y_ALT, MAX, diff --git a/zss/mapping/2d.ts b/zss/mapping/2d.ts index d94868c7..586bdaa4 100644 --- a/zss/mapping/2d.ts +++ b/zss/mapping/2d.ts @@ -30,7 +30,7 @@ export function ptwithin( return x >= left && x <= right && y >= top && y <= bottom } -export function linePoints( +export function linepoints( x0: number, y0: number, x1: number, @@ -62,7 +62,7 @@ export function linePoints( return points } -function ellipsePoints( +function ellipsepoints( points: PT[], x0: number, y0: number, @@ -75,7 +75,7 @@ function ellipsePoints( points.push({ x: x0 - x, y: y0 - y }) } -export function circlePoints(x0: number, y0: number, r: number) { +export function circlepoints(x0: number, y0: number, r: number) { const points: PT[] = [] let d = 5 - 4 * r @@ -87,8 +87,8 @@ export function circlePoints(x0: number, y0: number, r: number) { let deltaB = 3 * 4 while (x <= y) { - ellipsePoints(points, x0, y0, x, y) - ellipsePoints(points, x0, y0, y, x) + ellipsepoints(points, x0, y0, x, y) + ellipsepoints(points, x0, y0, y, x) if (d > 0) { d += deltaA diff --git a/zss/memory/book.ts b/zss/memory/book.ts index e378c066..280b75ed 100644 --- a/zss/memory/book.ts +++ b/zss/memory/book.ts @@ -195,7 +195,7 @@ export function bookelementdisplayread( return { char: element?.char ?? kind?.char ?? 1, color: element?.color ?? kind?.color ?? COLOR.WHITE, - bg: element?.bg ?? kind?.bg ?? COLOR.ONBORROW, + bg: element?.bg ?? kind?.bg ?? COLOR.ONCLEAR, } } diff --git a/zss/memory/index.ts b/zss/memory/index.ts index dc74f70b..619b7fa5 100644 --- a/zss/memory/index.ts +++ b/zss/memory/index.ts @@ -9,26 +9,12 @@ import { parsezipfile, } from 'zss/firmware/loader/parsefile' import { DRIVER_TYPE } from 'zss/firmware/runner' -import { - createdither, - createlayercontrol, - createsprite, - createsprites, - createtiles, - LAYER, -} from 'zss/gadget/data/types' -import { average } from 'zss/mapping/array' +import { LAYER } from 'zss/gadget/data/types' import { createpid, ispid } from 'zss/mapping/guid' -import { clamp } from 'zss/mapping/number' import { CYCLE_DEFAULT, TICK_FPS } from 'zss/mapping/tick' import { MAYBE, isnumber, ispresent, isstring } from 'zss/mapping/types' import { createos } from 'zss/os' import { READ_CONTEXT } from 'zss/words/reader' -import { - createwritetextcontext, - tokenizeandmeasuretextformat, - tokenizeandwritetextformat, -} from 'zss/words/textformat' import { COLOR, NAME } from 'zss/words/types' import { @@ -41,7 +27,6 @@ import { bookboardobjectnamedlookupdelete, bookboardtick, bookclearflags, - bookelementdisplayread, bookelementkindread, bookplayerreadboard, bookplayerreadboards, @@ -59,6 +44,7 @@ import { codepagetypetostring, createcodepage, } from './codepage' +import { memoryconverttogadgetlayers } from './rendertogadget' import { BINARY_READER, BOARD, @@ -640,242 +626,6 @@ export function memoryloadfile(player: string, file: File | undefined) { handlefiletype(file?.type ?? '') } -let decoticker = 0 -function readdecotickercolor(): COLOR { - switch (decoticker++) { - case 0: - return COLOR.BLUE - case 1: - return COLOR.GREEN - case 2: - return COLOR.CYAN - case 3: - return COLOR.RED - case 4: - return COLOR.PURPLE - case 5: - return COLOR.YELLOW - default: - decoticker = 0 - return COLOR.WHITE - } -} - -function memoryconverttogadgetlayers( - player: string, - index: number, - book: BOOK, - board: BOARD, - isprimary: boolean, - borrowbuffer: number[], -): LAYER[] { - const layers: LAYER[] = [] - - let i = index - const isbaseboard = i === 0 - const boardwidth = BOARD_WIDTH - const boardheight = BOARD_HEIGHT - const defaultcolor = isbaseboard ? COLOR.BLACK : COLOR.ONCLEAR - - const tiles = createtiles(player, i++, boardwidth, boardheight, defaultcolor) - layers.push(tiles) - - const shadow = createdither(player, i++, boardwidth, boardheight) - layers.push(shadow) - - const objectindex = i++ - const objects = createsprites(player, objectindex) - layers.push(objects) - - const tickers = createtiles( - player, - i++, - boardwidth, - boardheight, - COLOR.ONCLEAR, - ) - layers.push(tickers) - - const tickercontext = { - ...createwritetextcontext( - BOARD_WIDTH, - BOARD_HEIGHT, - readdecotickercolor(), - COLOR.ONCLEAR, - ), - ...tickers, - } - - const control = createlayercontrol(player, i++) - // hack to keep only one control layer - if (isprimary) { - layers.push(control) - } - - board.terrain.forEach((tile, i) => { - if (tile) { - const kind = bookelementkindread(book, tile) - tiles.char[i] = tile.char ?? kind?.char ?? 0 - tiles.color[i] = tile.color ?? kind?.color ?? defaultcolor - tiles.bg[i] = tile.bg ?? kind?.bg ?? defaultcolor - // write to borrow buffer - if (tiles.color[i] !== (COLOR.ONCLEAR as number)) { - borrowbuffer[i] = tiles.color[i] - } - } - }) - - const boardobjects = board.objects ?? {} - Object.values(boardobjects).forEach((object) => { - // skip if marked for removal or headless - if (ispresent(object.removed) || ispresent(object.headless)) { - return - } - - // should we have bg transparent or match the bg color of the terrain ? - const id = object.id ?? '' - const display = bookelementdisplayread(book, object) - const sprite = createsprite(player, objectindex, id) - const lx = object.lx ?? object.x ?? 0 - const ly = object.ly ?? object.y ?? 0 - const li = lx + ly * BOARD_WIDTH - - // setup sprite - sprite.x = object.x ?? 0 - sprite.y = object.y ?? 0 - sprite.char = object.char ?? display?.char ?? 1 - sprite.color = object.color ?? display?.color ?? COLOR.WHITE - sprite.bg = object.bg ?? display?.bg ?? COLOR.ONBORROW - objects.sprites.push(sprite) - - // plot shadow - if (sprite.bg === COLOR.ONSHADOW) { - sprite.bg = COLOR.ONCLEAR - shadow.alphas[lx + ly * boardwidth] = 0.5 - } - - // borrow color - if (sprite.bg === COLOR.ONBORROW) { - sprite.bg = borrowbuffer[li] ?? COLOR.BLACK - } - - // write to borrow buffer - if (sprite.color !== (COLOR.ONCLEAR as number)) { - borrowbuffer[li] = sprite.color - } - - // write ticker messages - if ( - isstring(object.tickertext) && - isnumber(object.tickertime) && - object.tickertext.length - ) { - // calc placement - const TICKER_WIDTH = BOARD_WIDTH - const measure = tokenizeandmeasuretextformat( - object.tickertext, - TICKER_WIDTH, - BOARD_HEIGHT - 1, - ) - const width = measure?.measuredwidth ?? 1 - const x = object.x ?? 0 - const y = object.y ?? 0 - const upper = y < BOARD_HEIGHT * 0.5 - tickercontext.x = x - Math.floor(width * 0.5) - tickercontext.y = y + (upper ? 1 : -1) - // clip placement - if (tickercontext.x + width > BOARD_WIDTH) { - tickercontext.x = BOARD_WIDTH - width - } - if (tickercontext.x < 0) { - tickercontext.x = 0 - } - // render text - tokenizeandwritetextformat(object.tickertext, tickercontext, true) - } - - // inform control layer where to focus - if (id === player) { - control.focusx = sprite.x - control.focusy = sprite.y - control.focusid = id - } - }) - - // smooth shadows - function aa(x: number, y: number) { - if (x < 0 || x >= BOARD_WIDTH || y < 0 || y >= BOARD_HEIGHT) { - return undefined - } - return shadow.alphas[x + y * BOARD_WIDTH] - } - - const weights = [ - [1, 1, 1, 1, 1], - [1, 3, 5, 3, 1], - [1, 5, 12, 5, 1], - [1, 3, 5, 3, 1], - [1, 1, 1, 1, 1], - ].flat() - - const alphas = new Array(shadow.alphas.length) - for (let i = 0; i < shadow.alphas.length; ++i) { - // coords - const cx = i % BOARD_WIDTH - const cy = Math.floor(i / BOARD_WIDTH) - - // weighted average - const values = [ - [ - aa(cx - 2, cy - 2), - aa(cx - 1, cy - 2), - aa(cx, cy - 2), - aa(cx + 1, cy - 2), - aa(cx + 2, cy - 2), - ], - [ - aa(cx - 2, cy - 1), - aa(cx - 1, cy - 1), - aa(cx, cy - 1), - aa(cx + 1, cy - 1), - aa(cx + 2, cy - 1), - ], - [ - aa(cx - 2, cy), - aa(cx - 1, cy), - aa(cx, cy), - aa(cx + 1, cy), - aa(cx + 2, cy), - ], - [ - aa(cx - 2, cy + 1), - aa(cx - 1, cy + 1), - aa(cx, cy + 1), - aa(cx + 1, cy + 1), - aa(cx + 2, cy + 1), - ], - [ - aa(cx - 2, cy + 2), - aa(cx - 1, cy + 2), - aa(cx, cy + 2), - aa(cx + 1, cy + 2), - aa(cx + 2, cy + 2), - ], - ] - .flat() - .map((value, i) => (ispresent(value) ? value * weights[i] : undefined)) - .filter(ispresent) - // final shade - alphas[i] = clamp(average(values), 0, 1) - } - - // update shadows - shadow.alphas = alphas - - // return result - return layers -} - export function memoryreadgadgetlayers(player: string): LAYER[] { const mainbook = memoryreadbookbysoftware(MEMORY_LABEL.MAIN) const playerboard = bookplayerreadboard(mainbook, player) diff --git a/zss/memory/rendertogadget.ts b/zss/memory/rendertogadget.ts new file mode 100644 index 00000000..74ce93ec --- /dev/null +++ b/zss/memory/rendertogadget.ts @@ -0,0 +1,291 @@ +import { clamp } from 'maath/misc' +import { + createdither, + createlayercontrol, + createsprite, + createsprites, + createtiles, + LAYER, +} from 'zss/gadget/data/types' +import { average } from 'zss/mapping/array' +import { isnumber, ispresent, isstring } from 'zss/mapping/types' +import { + createwritetextcontext, + tokenizeandmeasuretextformat, + tokenizeandwritetextformat, +} from 'zss/words/textformat' +import { COLOR } from 'zss/words/types' + +import { bookelementdisplayread, bookelementkindread } from './book' +import { BOARD, BOARD_HEIGHT, BOARD_WIDTH, BOOK } from './types' + +/* + +Object.values(gameState.board.objects).forEach((object) => { + const objectType = gameState.getObjectType(object) + const light = + object.stats.light || objectType?.stats.light || LIGHT.OFF + + if (light !== LIGHT.OFF) { + darkness[object.x + object.y * boardWidth] = 0 + + const cpoints = [ + circlePoints(object.x, object.y, light), + circlePoints(object.x, object.y, light - 1), + ].flat() + + cpoints.forEach((cp) => { + const line = linePoints(object.x, object.y, cp.x, cp.y) + for (let i = 1; i < line.length; i++) { + const lp = line[i] + if ( + lp.x < 0 || + lp.x >= (gameState.board?.width || 1) || + lp.y < 0 || + lp.y >= (gameState.board?.height || 1) + ) { + break + } + + darkness[lp.x + lp.y * boardWidth] = 0 + + const element = + gameState.lookup.coords[lp.x + lp.y * gameState.lookup.width] + if ( + isObject(element) || + element?.stats.collision === COLLISION.SOLID + ) { + break + } + } + }) + } + }) + + +*/ + +let decoticker = 0 +function readdecotickercolor(): COLOR { + switch (decoticker++) { + case 0: + return COLOR.BLUE + case 1: + return COLOR.GREEN + case 2: + return COLOR.CYAN + case 3: + return COLOR.RED + case 4: + return COLOR.PURPLE + case 5: + return COLOR.YELLOW + default: + decoticker = 0 + return COLOR.WHITE + } +} + +export function memoryconverttogadgetlayers( + player: string, + index: number, + book: BOOK, + board: BOARD, + isprimary: boolean, + borrowbuffer: number[], +): LAYER[] { + const layers: LAYER[] = [] + + let i = index + const isbaseboard = i === 0 + const boardwidth = BOARD_WIDTH + const boardheight = BOARD_HEIGHT + const defaultcolor = isbaseboard ? COLOR.BLACK : COLOR.ONCLEAR + + const tiles = createtiles(player, i++, boardwidth, boardheight, defaultcolor) + layers.push(tiles) + + const shadow = createdither(player, i++, boardwidth, boardheight) + layers.push(shadow) + + const objectindex = i++ + const objects = createsprites(player, objectindex) + layers.push(objects) + + const tickers = createtiles( + player, + i++, + boardwidth, + boardheight, + COLOR.ONCLEAR, + ) + layers.push(tickers) + + const tickercontext = { + ...createwritetextcontext( + BOARD_WIDTH, + BOARD_HEIGHT, + readdecotickercolor(), + COLOR.ONCLEAR, + ), + ...tickers, + } + + const control = createlayercontrol(player, i++) + // hack to keep only one control layer + if (isprimary) { + layers.push(control) + } + + board.terrain.forEach((tile, i) => { + if (tile) { + const kind = bookelementkindread(book, tile) + tiles.char[i] = tile.char ?? kind?.char ?? 0 + tiles.color[i] = tile.color ?? kind?.color ?? defaultcolor + tiles.bg[i] = tile.bg ?? kind?.bg ?? defaultcolor + // write to borrow buffer + if (tiles.color[i] !== (COLOR.ONCLEAR as number)) { + borrowbuffer[i] = tiles.color[i] + } + } + }) + + const boardobjects = board.objects ?? {} + Object.values(boardobjects).forEach((object) => { + // skip if marked for removal or headless + if (ispresent(object.removed) || ispresent(object.headless)) { + return + } + + // should we have bg transparent or match the bg color of the terrain ? + const id = object.id ?? '' + const display = bookelementdisplayread(book, object) + const sprite = createsprite(player, objectindex, id) + const lx = object.lx ?? object.x ?? 0 + const ly = object.ly ?? object.y ?? 0 + const li = lx + ly * BOARD_WIDTH + + // setup sprite + sprite.x = object.x ?? 0 + sprite.y = object.y ?? 0 + sprite.char = object.char ?? display?.char ?? 1 + sprite.color = object.color ?? display?.color ?? COLOR.WHITE + sprite.bg = object.bg ?? display?.bg ?? COLOR.ONCLEAR + objects.sprites.push(sprite) + + // write to borrow buffer + if (sprite.color !== (COLOR.ONCLEAR as number)) { + borrowbuffer[li] = sprite.color + } + + // write ticker messages + if ( + isstring(object.tickertext) && + isnumber(object.tickertime) && + object.tickertext.length + ) { + // calc placement + const TICKER_WIDTH = BOARD_WIDTH + const measure = tokenizeandmeasuretextformat( + object.tickertext, + TICKER_WIDTH, + BOARD_HEIGHT - 1, + ) + const width = measure?.measuredwidth ?? 1 + const x = object.x ?? 0 + const y = object.y ?? 0 + const upper = y < BOARD_HEIGHT * 0.5 + tickercontext.x = x - Math.floor(width * 0.5) + tickercontext.y = y + (upper ? 1 : -1) + // clip placement + if (tickercontext.x + width > BOARD_WIDTH) { + tickercontext.x = BOARD_WIDTH - width + } + if (tickercontext.x < 0) { + tickercontext.x = 0 + } + // render text + tokenizeandwritetextformat(object.tickertext, tickercontext, true) + } + + // inform control layer where to focus + if (id === player) { + control.focusx = sprite.x + control.focusy = sprite.y + control.focusid = id + } + }) + + // smooth shadows + function aa(x: number, y: number) { + if (x < 0 || x >= BOARD_WIDTH || y < 0 || y >= BOARD_HEIGHT) { + return undefined + } + return shadow.alphas[x + y * BOARD_WIDTH] + } + + const weights = [ + [1, 1, 1, 1, 1], + [1, 3, 5, 3, 1], + [1, 5, 12, 5, 1], + [1, 3, 5, 3, 1], + [1, 1, 1, 1, 1], + ].flat() + + const alphas = new Array(shadow.alphas.length) + for (let i = 0; i < shadow.alphas.length; ++i) { + // coords + const cx = i % BOARD_WIDTH + const cy = Math.floor(i / BOARD_WIDTH) + + // weighted average + const values = [ + [ + aa(cx - 2, cy - 2), + aa(cx - 1, cy - 2), + aa(cx, cy - 2), + aa(cx + 1, cy - 2), + aa(cx + 2, cy - 2), + ], + [ + aa(cx - 2, cy - 1), + aa(cx - 1, cy - 1), + aa(cx, cy - 1), + aa(cx + 1, cy - 1), + aa(cx + 2, cy - 1), + ], + [ + aa(cx - 2, cy), + aa(cx - 1, cy), + aa(cx, cy), + aa(cx + 1, cy), + aa(cx + 2, cy), + ], + [ + aa(cx - 2, cy + 1), + aa(cx - 1, cy + 1), + aa(cx, cy + 1), + aa(cx + 1, cy + 1), + aa(cx + 2, cy + 1), + ], + [ + aa(cx - 2, cy + 2), + aa(cx - 1, cy + 2), + aa(cx, cy + 2), + aa(cx + 1, cy + 2), + aa(cx + 2, cy + 2), + ], + ] + .flat() + .map((value, i) => (ispresent(value) ? value * weights[i] : undefined)) + .filter(ispresent) + // final shade + alphas[i] = clamp(average(values), 0, 1) + } + + // update shadows + shadow.alphas = alphas + + // return result + return layers +} diff --git a/zss/words/color.ts b/zss/words/color.ts index fb7255d2..fe7ed483 100644 --- a/zss/words/color.ts +++ b/zss/words/color.ts @@ -66,8 +66,6 @@ export const colorconsts = { onltblack: 'ONDKGRAY', // special bg colors onclear: 'ONCLEAR', - onshadow: 'ONSHADOW', - onborrow: 'ONBORROW', } as const export type STR_COLOR_TYPE = typeof colorconsts diff --git a/zss/words/types.ts b/zss/words/types.ts index f8f56e73..580a9573 100644 --- a/zss/words/types.ts +++ b/zss/words/types.ts @@ -35,8 +35,6 @@ export enum COLOR { ONWHITE, // special bg colors ONCLEAR, - ONSHADOW, - ONBORROW, } export enum COLLISION { From c66951de24fac21eb8f1eb47c653d72d414c844a Mon Sep 17 00:00:00 2001 From: Automated Version Bump Date: Thu, 2 Jan 2025 03:12:14 +0000 Subject: [PATCH 2/6] ci: version bump to v0.21.20 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index a0282cc3..e0825ada 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "zed-software-system", "private": true, - "version": "0.21.19", + "version": "0.21.20", "type": "module", "scripts": { "sloc": "npx sloc zss", From 7d88a78553697f90553c832ea58e1985075c0647 Mon Sep 17 00:00:00 2001 From: goldbuick Date: Wed, 1 Jan 2025 22:44:05 -0500 Subject: [PATCH 3/6] all board stats now set --- zss/memory/codepage.ts | 22 ++++++++ zss/memory/index.ts | 3 -- zss/memory/rendertogadget.ts | 99 ++++++------------------------------ 3 files changed, 38 insertions(+), 86 deletions(-) diff --git a/zss/memory/codepage.ts b/zss/memory/codepage.ts index 81cab042..13aa717f 100644 --- a/zss/memory/codepage.ts +++ b/zss/memory/codepage.ts @@ -334,6 +334,28 @@ export function codepagereaddata( codepage.board = createboard() } codepage.board.id = codepage.id + const stats = codepagereadstatdefaults(codepage) + codepage.board.isdark = ispresent(stats.isdark) && stats.isdark ? 1 : 0 + // @ts-expect-error ugh + codepage.board.over = stats.over ?? codepage.board.over + // @ts-expect-error ugh + codepage.board.under = stats.under ?? codepage.board.under + // @ts-expect-error ugh + codepage.board.exitnorth = stats.exitnorth ?? codepage.board.exitnorth + // @ts-expect-error ugh + codepage.board.exitsouth = stats.exitsouth ?? codepage.board.exitsouth + // @ts-expect-error ugh + codepage.board.exitwest = stats.exitwest ?? codepage.board.exitwest + // @ts-expect-error ugh + codepage.board.exiteast = stats.exiteast ?? codepage.board.exiteast + // @ts-expect-error ugh + codepage.board.timelimit = stats.timelimit ?? codepage.board.timelimit + // @ts-expect-error ugh + codepage.board.restartonzap = + stats.restartonzap ?? codepage.board.restartonzap + // @ts-expect-error ugh + codepage.board.maxplayershots = + stats.maxplayershots ?? codepage.board.maxplayershots return codepage.board as MAYBE } case CODE_PAGE_TYPE.OBJECT: { diff --git a/zss/memory/index.ts b/zss/memory/index.ts index 619b7fa5..f6fe9c93 100644 --- a/zss/memory/index.ts +++ b/zss/memory/index.ts @@ -635,8 +635,6 @@ export function memoryreadgadgetlayers(player: string): LAYER[] { return layers } - const borrowbuffer: number[] = new Array(BOARD_WIDTH * BOARD_HEIGHT).fill(0) - // read over board const over = bookreadboard(mainbook, playerboard.over ?? '') @@ -655,7 +653,6 @@ export function memoryreadgadgetlayers(player: string): LAYER[] { mainbook, board, board === playerboard, - borrowbuffer, ) i += view.length layers.push(...view) diff --git a/zss/memory/rendertogadget.ts b/zss/memory/rendertogadget.ts index 74ce93ec..125e45a3 100644 --- a/zss/memory/rendertogadget.ts +++ b/zss/memory/rendertogadget.ts @@ -16,7 +16,12 @@ import { } from 'zss/words/textformat' import { COLOR } from 'zss/words/types' -import { bookelementdisplayread, bookelementkindread } from './book' +import { + bookelementdisplayread, + bookelementkindread, + bookreadcodepagebyaddress, +} from './book' +import { codepagereadstat } from './codepage' import { BOARD, BOARD_HEIGHT, BOARD_WIDTH, BOOK } from './types' /* @@ -92,7 +97,6 @@ export function memoryconverttogadgetlayers( book: BOOK, board: BOARD, isprimary: boolean, - borrowbuffer: number[], ): LAYER[] { const layers: LAYER[] = [] @@ -105,13 +109,19 @@ export function memoryconverttogadgetlayers( const tiles = createtiles(player, i++, boardwidth, boardheight, defaultcolor) layers.push(tiles) - const shadow = createdither(player, i++, boardwidth, boardheight) - layers.push(shadow) - const objectindex = i++ const objects = createsprites(player, objectindex) layers.push(objects) + const lighting = createdither( + player, + i++, + boardwidth, + boardheight, + board.isdark ? 1 : 0, + ) + layers.push(lighting) + const tickers = createtiles( player, i++, @@ -143,10 +153,6 @@ export function memoryconverttogadgetlayers( tiles.char[i] = tile.char ?? kind?.char ?? 0 tiles.color[i] = tile.color ?? kind?.color ?? defaultcolor tiles.bg[i] = tile.bg ?? kind?.bg ?? defaultcolor - // write to borrow buffer - if (tiles.color[i] !== (COLOR.ONCLEAR as number)) { - borrowbuffer[i] = tiles.color[i] - } } }) @@ -173,10 +179,7 @@ export function memoryconverttogadgetlayers( sprite.bg = object.bg ?? display?.bg ?? COLOR.ONCLEAR objects.sprites.push(sprite) - // write to borrow buffer - if (sprite.color !== (COLOR.ONCLEAR as number)) { - borrowbuffer[li] = sprite.color - } + // write lighting if needed // write ticker messages if ( @@ -216,76 +219,6 @@ export function memoryconverttogadgetlayers( } }) - // smooth shadows - function aa(x: number, y: number) { - if (x < 0 || x >= BOARD_WIDTH || y < 0 || y >= BOARD_HEIGHT) { - return undefined - } - return shadow.alphas[x + y * BOARD_WIDTH] - } - - const weights = [ - [1, 1, 1, 1, 1], - [1, 3, 5, 3, 1], - [1, 5, 12, 5, 1], - [1, 3, 5, 3, 1], - [1, 1, 1, 1, 1], - ].flat() - - const alphas = new Array(shadow.alphas.length) - for (let i = 0; i < shadow.alphas.length; ++i) { - // coords - const cx = i % BOARD_WIDTH - const cy = Math.floor(i / BOARD_WIDTH) - - // weighted average - const values = [ - [ - aa(cx - 2, cy - 2), - aa(cx - 1, cy - 2), - aa(cx, cy - 2), - aa(cx + 1, cy - 2), - aa(cx + 2, cy - 2), - ], - [ - aa(cx - 2, cy - 1), - aa(cx - 1, cy - 1), - aa(cx, cy - 1), - aa(cx + 1, cy - 1), - aa(cx + 2, cy - 1), - ], - [ - aa(cx - 2, cy), - aa(cx - 1, cy), - aa(cx, cy), - aa(cx + 1, cy), - aa(cx + 2, cy), - ], - [ - aa(cx - 2, cy + 1), - aa(cx - 1, cy + 1), - aa(cx, cy + 1), - aa(cx + 1, cy + 1), - aa(cx + 2, cy + 1), - ], - [ - aa(cx - 2, cy + 2), - aa(cx - 1, cy + 2), - aa(cx, cy + 2), - aa(cx + 1, cy + 2), - aa(cx + 2, cy + 2), - ], - ] - .flat() - .map((value, i) => (ispresent(value) ? value * weights[i] : undefined)) - .filter(ispresent) - // final shade - alphas[i] = clamp(average(values), 0, 1) - } - - // update shadows - shadow.alphas = alphas - // return result return layers } From 786512ed82a2ff376e32e4b9d1bd0491cf64f773 Mon Sep 17 00:00:00 2001 From: Automated Version Bump Date: Thu, 2 Jan 2025 03:45:11 +0000 Subject: [PATCH 4/6] ci: version bump to v0.21.21 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index e0825ada..11ee5bae 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "zed-software-system", "private": true, - "version": "0.21.20", + "version": "0.21.21", "type": "module", "scripts": { "sloc": "npx sloc zss", From f031550090ea00d61d8ea2d6326f8fc10d7884c0 Mon Sep 17 00:00:00 2001 From: goldbuick Date: Thu, 2 Jan 2025 01:37:38 -0500 Subject: [PATCH 5/6] boards now support @isdark --- zss/mapping/array.ts | 4 +- zss/memory/book.ts | 1 + zss/memory/codepage.ts | 1 + zss/memory/rendertogadget.ts | 121 ++++++++++++++++++----------------- 4 files changed, 66 insertions(+), 61 deletions(-) diff --git a/zss/mapping/array.ts b/zss/mapping/array.ts index b6598302..60086cdd 100644 --- a/zss/mapping/array.ts +++ b/zss/mapping/array.ts @@ -24,12 +24,12 @@ export function range(a: number, b?: number, step?: number) { return list } -function randomItem(array: T[]) { +function randomitem(array: T[]) { return array[randominteger(0, array.length - 1)] } export function pick(...args: T[]) { - return randomItem(args.flat()) + return randomitem(args.flat()) } export function addToArray(array: T[], value: T) { diff --git a/zss/memory/book.ts b/zss/memory/book.ts index 280b75ed..3043e240 100644 --- a/zss/memory/book.ts +++ b/zss/memory/book.ts @@ -196,6 +196,7 @@ export function bookelementdisplayread( char: element?.char ?? kind?.char ?? 1, color: element?.color ?? kind?.color ?? COLOR.WHITE, bg: element?.bg ?? kind?.bg ?? COLOR.ONCLEAR, + light: element?.light ?? kind?.light, } } diff --git a/zss/memory/codepage.ts b/zss/memory/codepage.ts index 13aa717f..3d15d985 100644 --- a/zss/memory/codepage.ts +++ b/zss/memory/codepage.ts @@ -273,6 +273,7 @@ function applyelementstats(codepage: CODE_PAGE, element: BOARD_ELEMENT) { case 'char': case 'color': case 'bg': + case 'light': case 'p1': case 'p2': case 'p3': diff --git a/zss/memory/rendertogadget.ts b/zss/memory/rendertogadget.ts index 125e45a3..08ee3049 100644 --- a/zss/memory/rendertogadget.ts +++ b/zss/memory/rendertogadget.ts @@ -1,4 +1,5 @@ import { clamp } from 'maath/misc' +import { Vector2 } from 'three' import { createdither, createlayercontrol, @@ -7,6 +8,7 @@ import { createtiles, LAYER, } from 'zss/gadget/data/types' +import { circlepoints, linepoints } from 'zss/mapping/2d' import { average } from 'zss/mapping/array' import { isnumber, ispresent, isstring } from 'zss/mapping/types' import { @@ -14,62 +16,13 @@ import { tokenizeandmeasuretextformat, tokenizeandwritetextformat, } from 'zss/words/textformat' -import { COLOR } from 'zss/words/types' +import { COLLISION, COLOR } from 'zss/words/types' -import { - bookelementdisplayread, - bookelementkindread, - bookreadcodepagebyaddress, -} from './book' -import { codepagereadstat } from './codepage' +import { checkcollision } from './atomics' +import { boardelementindex, boardelementread, boardobjectread } from './board' +import { bookelementdisplayread, bookelementkindread } from './book' import { BOARD, BOARD_HEIGHT, BOARD_WIDTH, BOOK } from './types' -/* - -Object.values(gameState.board.objects).forEach((object) => { - const objectType = gameState.getObjectType(object) - const light = - object.stats.light || objectType?.stats.light || LIGHT.OFF - - if (light !== LIGHT.OFF) { - darkness[object.x + object.y * boardWidth] = 0 - - const cpoints = [ - circlePoints(object.x, object.y, light), - circlePoints(object.x, object.y, light - 1), - ].flat() - - cpoints.forEach((cp) => { - const line = linePoints(object.x, object.y, cp.x, cp.y) - for (let i = 1; i < line.length; i++) { - const lp = line[i] - if ( - lp.x < 0 || - lp.x >= (gameState.board?.width || 1) || - lp.y < 0 || - lp.y >= (gameState.board?.height || 1) - ) { - break - } - - darkness[lp.x + lp.y * boardWidth] = 0 - - const element = - gameState.lookup.coords[lp.x + lp.y * gameState.lookup.width] - if ( - isObject(element) || - element?.stats.collision === COLLISION.SOLID - ) { - break - } - } - }) - } - }) - - -*/ - let decoticker = 0 function readdecotickercolor(): COLOR { switch (decoticker++) { @@ -91,6 +44,8 @@ function readdecotickercolor(): COLOR { } } +const pt1 = new Vector2() + export function memoryconverttogadgetlayers( player: string, index: number, @@ -167,19 +122,67 @@ export function memoryconverttogadgetlayers( const id = object.id ?? '' const display = bookelementdisplayread(book, object) const sprite = createsprite(player, objectindex, id) - const lx = object.lx ?? object.x ?? 0 - const ly = object.ly ?? object.y ?? 0 - const li = lx + ly * BOARD_WIDTH // setup sprite sprite.x = object.x ?? 0 sprite.y = object.y ?? 0 - sprite.char = object.char ?? display?.char ?? 1 - sprite.color = object.color ?? display?.color ?? COLOR.WHITE - sprite.bg = object.bg ?? display?.bg ?? COLOR.ONCLEAR + sprite.char = display.char + sprite.color = display.color + sprite.bg = display.bg objects.sprites.push(sprite) // write lighting if needed + if (board.isdark && isnumber(display.light)) { + const cpoints = [ + circlepoints(sprite.x, sprite.y, display.light), + circlepoints(sprite.x, sprite.y, display.light - 1), + ].flat() + for (let c = 0; c < cpoints.length; ++c) { + let falloff = 0 + const cp = cpoints[c] + const line = linepoints(sprite.x, sprite.y, cp.x, cp.y) + for (let i = 0; i < line.length; i++) { + const lp = line[i] + if ( + lp.x < 0 || + lp.x >= boardwidth || + lp.y < 0 || + lp.y >= boardheight + ) { + break + } + + // measure dist + const dist = pt1.subVectors(lp, sprite).length() + const ratio = dist / (display.light + 1) + const value = clamp(ratio + falloff, 0, 0.99) + const li = lp.x + lp.y * boardwidth + lighting.alphas[li] = Math.min(lighting.alphas[li], value) + + // clipping + const index = boardelementindex(board, lp) + if (index < 0 || !ispresent(board?.lookup)) { + break + } + + // check lookup + if (lp.x !== sprite.x || lp.y !== sprite.y) { + const object = boardobjectread(board, board.lookup[index] ?? '') + if (ispresent(object)) { + falloff += 0.25 + } + } + + const maybeterrain = board.terrain[index] + const terrainkind = bookelementkindread(book, maybeterrain) + const terraincollision = + maybeterrain?.collision ?? terrainkind?.collision + if (checkcollision(COLLISION.ISWALK, terraincollision)) { + break + } + } + } + } // write ticker messages if ( From 9d9229ad850d517a61dd0c3ac699bb13fc427935 Mon Sep 17 00:00:00 2001 From: Automated Version Bump Date: Thu, 2 Jan 2025 06:38:04 +0000 Subject: [PATCH 6/6] ci: version bump to v0.21.22 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 11ee5bae..8e6dbfae 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "zed-software-system", "private": true, - "version": "0.21.21", + "version": "0.21.22", "type": "module", "scripts": { "sloc": "npx sloc zss",