VASTLY improved how I generate tiles and tiledata

This commit is contained in:
2022-05-07 21:57:15 -07:00
parent bee024c3e1
commit 4ff43893d0
66 changed files with 3472 additions and 3186 deletions

170
.gitignore vendored
View File

@@ -1,84 +1,86 @@
# Prerequisites # Prerequisites
*.d *.d
# Object files # Object files
*.o *.o
*.ko *.ko
build/*.obj build/*.obj
*.elf *.elf
# Linker output # Linker output
*.ilk *.ilk
*.map *.map
*.exp *.exp
# Precompiled Headers # Precompiled Headers
*.gch *.gch
*.pch *.pch
# Libraries # Libraries
*.lib *.lib
*.a *.a
*.la *.la
*.lo *.lo
# Shared objects (inc. Windows DLLs) # Shared objects (inc. Windows DLLs)
*.dll *.dll
*.so *.so
*.so.* *.so.*
*.dylib *.dylib
# Executables # Executables
*.exe *.exe
*.out *.out
*.app *.app
*.i*86 *.i*86
*.x86_64 *.x86_64
*.hex *.hex
# Debug files # Debug files
*.dSYM/ *.dSYM/
*.su *.su
*.idb *.idb
*.pdb *.pdb
# Kernel Module Compile Results # Kernel Module Compile Results
*.mod* *.mod*
*.cmd *.cmd
.tmp_versions/ .tmp_versions/
modules.order modules.order
Module.symvers Module.symvers
Mkfile.old Mkfile.old
dkms.conf dkms.conf
# CMake # CMake
CMakeLists.txt.user CMakeLists.txt.user
CMakeCache.txt CMakeCache.txt
CMakeFiles CMakeFiles
CMakeScripts CMakeScripts
Testing Testing
Makefile Makefile
cmake_install.cmake cmake_install.cmake
install_manifest.txt install_manifest.txt
compile_commands.json compile_commands.json
CTestTestfile.cmake CTestTestfile.cmake
_deps _deps
# Custom # Custom
build build
.vscode .vscode
assets/testworld/tileset.png assets/testworld/tileset.png
oldsrc oldsrc
node_modules node_modules
yarn.lock yarn.lock
*.log *.log
obj obj
res res
out.c out.c
out.c.png out.c.png
emulator emulator
bgb/*

235
archive/main.c Normal file
View File

@@ -0,0 +1,235 @@
/**
* Copyright (c) 2021 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "main.h"
/*
inline uint8_t mainGetChar(char c) {
return c - TEXTBOX_FONT_START + FONT_DATA_POSITION;
}
inline void mainBufferCard(uint8_t card, uint8_t *tiles) {
uint8_t suit, number;
if(card >= CARD_DECK_SIZE) {
tiles[0] = mainGetChar('N');
tiles[1] = mainGetChar('A');
return;
}
suit = cardGetSuit(card);
number = cardGetNumber(card);
switch(suit) {
case CARD_SUIT_CLUBS:
tiles[0] = mainGetChar('C');
break;
case CARD_SUIT_DIAMONDS:
tiles[0] = mainGetChar('D');
break;
case CARD_SUIT_HEARTS:
tiles[0] = mainGetChar('H');
break;
case CARD_SUIT_SPADES:
tiles[0] = mainGetChar('S');
break;
}
switch(number) {
case CARD_TWO:
tiles[1] = mainGetChar('2');
break;
case CARD_THREE:
tiles[1] = mainGetChar('3');
break;
case CARD_FOUR:
tiles[1] = mainGetChar('4');
break;
case CARD_FIVE:
tiles[1] = mainGetChar('5');
break;
case CARD_SIX:
tiles[1] = mainGetChar('6');
break;
case CARD_SEVEN:
tiles[1] = mainGetChar('7');
break;
case CARD_EIGHT:
tiles[1] = mainGetChar('8');
break;
case CARD_NINE:
tiles[1] = mainGetChar('9');
break;
case CARD_TEN:
tiles[1] = mainGetChar('T');
break;
case CARD_JACK:
tiles[1] = mainGetChar('J');
break;
case CARD_QUEEN:
tiles[1] = mainGetChar('Q');
break;
case CARD_KING:
tiles[1] = mainGetChar('K');
break;
case CARD_ACE:
tiles[1] = mainGetChar('A');
break;
}
}
inline void mainDebugDraw() {
uint8_t j, i, n;
// DEBUG DRAW
uint8_t tiles[15];
char buffer[6];
buffer[0] = '\0';
for(j = 0; j < POKER_PLAYER_COUNT; j++) {
n = 0;
if(j == POKER_PLAYER_BETTER) {
tiles[n++] = mainGetChar('>');
} else {
tiles[n++] = COMMON_TILE_3;
}
mainBufferCard(POKER_PLAYERS[j].hand[0], tiles+n);
n+=2;
mainBufferCard(POKER_PLAYERS[j].hand[1], tiles+n);
n+=2;
tiles[n++] = COMMON_TILE_3;
if((POKER_PLAYERS[j].state & POKER_PLAYER_STATE_FOLDED) == 0) {
tiles[n++] = COMMON_TILE_3;
} else {
tiles[n++] = mainGetChar('F');
}
if((POKER_PLAYERS[j].state & POKER_PLAYER_STATE_HAS_BET_THIS_ROUND) == 0) {
tiles[n++] = COMMON_TILE_3;
} else {
tiles[n++] = mainGetChar('H');
}
if((POKER_PLAYERS[j].state & POKER_PLAYER_STATE_OUT) == 0) {
tiles[n++] = COMMON_TILE_3;
} else {
tiles[n++] = mainGetChar('O');
}
tiles[n++] = COMMON_TILE_3;
// Print chips
sprintf(buffer, "%u", (uint16_t)POKER_PLAYERS[j].chips);
for(i = 0; i < strlen(buffer); i++) {
tiles[n++] = mainGetChar(buffer[i]);
}
while(n < 15) tiles[n++] = COMMON_TILE_3;
set_bkg_tiles(0x00, j, n - 1, 1, tiles);
}
for(j = 0; j < POKER_COMMUNITY_SIZE_MAX; j++) {
if(j >= POKER_COMMUNITY_SIZE) {
tiles[j*2] = COMMON_TILE_3;
tiles[(j*2) + 1] = COMMON_TILE_3;
} else {
mainBufferCard(POKER_COMMUNITY[j], tiles + (j * 2));
}
}
set_bkg_tiles(0x00, POKER_PLAYER_COUNT + 1, POKER_COMMUNITY_SIZE_MAX * 2, 1, tiles);
// Print Pot
n = 0;
sprintf(buffer, "%u", (uint16_t)POKER_POTS[POKER_POT_CURRENT].chips);
for(i = 0; i < strlen(buffer); i++) {
tiles[n++] = mainGetChar(buffer[i]);
}
while(n < 5) tiles[n++] = COMMON_TILE_3;
set_bkg_tiles(0x00, POKER_PLAYER_COUNT + 2, n, 1, tiles);
}
*/
void main() {
int16_t j;
uint8_t filled[GB_BACKGROUND_COLUMNS*GB_BACKGROUND_ROWS];
// Set up the GAMEBOY's registers.
disable_interrupts();
DISPLAY_OFF;
LCDC_REG = LCDCF_OFF | LCDCF_BG8000 | LCDCF_BG9800 | LCDCF_BGON;
// Set the background color palette register
BGP_REG = OBP0_REG = OBP1_REG = 0xE4U;
// Init the random seed
initarand(DIV_REG);
// Init things
spriteTilesetBuffer(0x00);
spriteFontBuffer(TEXTBOX_SPRITE_FONT_POSITION);
spriteBorderBuffer(TEXTBOX_SPRITE_BORDER_POSITION);
spriteCardsBuffer(TEXTBOX_SPRITE_BORDER_POSITION + BORDER_IMAGE_TILES);
conversationTextboxInit();
conversationQueueInit();
pokerInit();
// Fill screen white
for(j = 0; j < GB_BACKGROUND_COLUMNS * GB_BACKGROUND_ROWS; j++) filled[j] = TILESET_WHITE;
set_bkg_tiles(0x00, 0x00, GB_BACKGROUND_COLUMNS, GB_BACKGROUND_ROWS, filled);
SCX_REG = 0x00;
SCY_REG = 0x00;
// Card Test
uint8_t cardTiles[4 * 6];
spriteCardBufferTiles(
TEXTBOX_SPRITE_BORDER_POSITION+BORDER_IMAGE_TILES,
cardTiles,
CARD_HEARTS_TWO
);
set_bkg_tiles(0x00, 0x00, 4, 6, cardTiles);
// Now turn the screen on
DISPLAY_ON;
enable_interrupts();
wait_vbl_done();
// Begin game
conversationQueueNext();
// Begin the loop
while(1) {
// Perform non-graphical code updates
wait_vbl_done();
// Update the input state
INPUT_LAST = INPUT_STATE;
INPUT_STATE = joypad();
INPUT_PRESSED = (~INPUT_LAST) & INPUT_STATE;
// Tick time.
timeUpdate();
// Update conversation pause effect
conversationPauseUpdate();
// Update question box and textbox
questionBoxUpdate();
conversationTextboxUpdate();
// Update conversation fade effect
conversationFadeUpdate();
// mainDebugDraw();
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 175 B

After

Width:  |  Height:  |  Size: 240 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 832 B

Binary file not shown.

Binary file not shown.

BIN
assets/images/tileset.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 120 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 120 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 119 B

View File

@@ -1,17 +1,17 @@
{ {
"name": "Dawn-GB", "name": "Dawn-GB",
"version": "1.0.0", "version": "1.0.0",
"main": "index.js", "main": "index.js",
"repository": "https://github.com/YourWishes/Dawn-GB.git", "repository": "https://github.com/YourWishes/Dawn-GB.git",
"author": "Dominic Masters <dominic@domsplace.com>", "author": "Dominic Masters <dominic@domsplace.com>",
"license": "MIT", "license": "MIT",
"scripts": { "scripts": {
"clean": "node ./scripts/clean", "clean": "node ./scripts/clean",
"build": "npm run clean && node ./scripts/build", "build": "npm run clean && node ./scripts/build",
"start": "npm run build && bgb64.exe ./build/Penny.gb" "start": "npm run build && wine ./bgb/bgb64.exe ./build/Penny.gb"
}, },
"dependencies": { "dependencies": {
"pngjs": "^6.0.0", "pngjs": "^6.0.0",
"rimraf": "^3.0.2" "rimraf": "^3.0.2"
} }
} }

View File

@@ -1,5 +1,5 @@
const process = require('process'); const process = require('process');
const { spawnSync, execSync } = require('child_process'); const { spawnSync, execSync } = require('child_process');
execSync(`scp ./build/Penny.gb root@ywbud3:/storage/roms/gb/Penny.gb`); execSync(`scp ./build/Penny.gb root@ywbud3:/storage/roms/gb/Penny.gb`);
execSync(`echo "systemctl stop emustation.service; killall emulationstation; retroarch -L /lib/libretro/gambatte_libretro.so '/storage/roms/gb/Penny.gb';" | ssh root@ywbud3 /bin/bash`); execSync(`echo "systemctl stop emustation.service; killall emulationstation; retroarch -L /lib/libretro/gambatte_libretro.so '/storage/roms/gb/Penny.gb';" | ssh root@ywbud3 /bin/bash`);

View File

@@ -1,124 +1,124 @@
const fs = require('fs'); const fs = require('fs');
const path = require('path'); const path = require('path');
const process = require('process'); const process = require('process');
const { spawnSync, execSync } = require('child_process'); const { spawnSync, execSync } = require('child_process');
const { png2gb } = require('./png2gb'); const { png2gb } = require('./png2gb');
const { string2gb } = require('./string2gb'); const { string2gb } = require('./string2gb');
const DIR_BUILD = path.resolve('build'); const DIR_BUILD = path.resolve('build');
const DIR_GENERATED = path.resolve(DIR_BUILD, 'generated'); const DIR_GENERATED = path.resolve(DIR_BUILD, 'generated');
const DIR_OBJ = path.resolve(DIR_BUILD, 'obj'); const DIR_OBJ = path.resolve(DIR_BUILD, 'obj');
const DIR_SRC = path.resolve('src'); const DIR_SRC = path.resolve('src');
const DIR_GBDK = path.resolve(process.env['GBDKDIR']); const DIR_GBDK = path.resolve(process.env['GBDKDIR']);
const DIR_ASSETS = path.resolve('assets'); const DIR_ASSETS = path.resolve('assets');
const DIR_IMAGES = path.resolve(DIR_ASSETS, 'images'); const DIR_IMAGES = path.resolve(DIR_ASSETS, 'images');
const FILE_OUT = path.resolve(DIR_BUILD, 'Penny.gb'); const FILE_OUT = path.resolve(DIR_BUILD, 'Penny.gb');
const FILE_LINKFILE = path.join(DIR_BUILD, `linkflile.lk`); const FILE_LINKFILE = path.join(DIR_BUILD, `linkflile.lk`);
const LCC = path.join(DIR_GBDK, 'bin', 'lcc'); const LCC = path.join(DIR_GBDK, 'bin', 'lcc');
const LCCFLAGS = `-I${DIR_GENERATED} -I${DIR_SRC}`; const LCCFLAGS = `-I${DIR_GENERATED} -I${DIR_SRC}`;
const compiledSources = []; const compiledSources = [];
// Create build dirs // Create build dirs
[ [
DIR_BUILD, DIR_GENERATED, DIR_OBJ DIR_BUILD, DIR_GENERATED, DIR_OBJ
].forEach(d => { ].forEach(d => {
if(fs.existsSync(d)) return; if(fs.existsSync(d)) return;
fs.mkdirSync(d); fs.mkdirSync(d);
}); });
// Scandir // Scandir
const buildSourceFiles = directory => { const buildSourceFiles = directory => {
const sources = []; const sources = [];
fs.readdirSync(directory).forEach(file => { fs.readdirSync(directory).forEach(file => {
const fullPath = path.join(directory, file); const fullPath = path.join(directory, file);
const stats = fs.statSync(fullPath); const stats = fs.statSync(fullPath);
if(stats.isDirectory()) { if(stats.isDirectory()) {
sources.push(...buildSourceFiles(fullPath)); sources.push(...buildSourceFiles(fullPath));
return; return;
} }
if(file.endsWith('.c')) sources.push(fullPath); if(file.endsWith('.c')) sources.push(fullPath);
}); });
return sources; return sources;
} }
const logOut = (out, buffer) => { const logOut = (out, buffer) => {
const str = [ const str = [
out.stderr, out.stdout out.stderr, out.stdout
].filter(n => n) ].filter(n => n)
.map(n => n.toString()) .map(n => n.toString())
.filter(n => n) .filter(n => n)
.join('') .join('')
; ;
if(!str || !str.length) return; if(!str || !str.length) return;
buffer(str); buffer(str);
} }
const compileC = (cFile) => { const compileC = (cFile) => {
const fileNameOut = path.basename(cFile, '.c') + '.o'; const fileNameOut = path.basename(cFile, '.c') + '.o';
const fileOut = path.join(DIR_OBJ, fileNameOut); const fileOut = path.join(DIR_OBJ, fileNameOut);
compiledSources.push(path.join(fileNameOut)); compiledSources.push(path.join(fileNameOut));
if(fs.existsSync(fileOut)) return; if(fs.existsSync(fileOut)) return;
let result; let result;
try { try {
result = execSync(`${LCC} ${LCCFLAGS} -c -o ${fileOut} ${cFile}`); result = execSync(`${LCC} ${LCCFLAGS} -c -o ${fileOut} ${cFile}`);
logOut(result, console.log); logOut(result, console.log);
} catch(e) { } catch(e) {
logOut(e, e => { logOut(e, e => {
console.error(e); console.error(e);
process.exit(1); process.exit(1);
}); });
throw e; throw e;
} }
} }
// Generate strings // Generate strings
// let dataStringH = '#pragma once\n#include "libs.h"\n'; // let dataStringH = '#pragma once\n#include "libs.h"\n';
// let dataStringC = '#include "STRINGS.h"\n'; // let dataStringC = '#include "STRINGS.h"\n';
// Object.entries(GAME_STRINGS).forEach(entry => { // Object.entries(GAME_STRINGS).forEach(entry => {
// const [ name, str ] = entry; // const [ name, str ] = entry;
// const { dataH, dataC } = string2gb(str, name); // const { dataH, dataC } = string2gb(str, name);
// dataStringH += dataH+'\n', dataStringC += dataC+'\n'; // dataStringH += dataH+'\n', dataStringC += dataC+'\n';
// }); // });
// fs.writeFileSync(path.join(DIR_GENERATED, 'STRINGS.h'), dataStringH); // fs.writeFileSync(path.join(DIR_GENERATED, 'STRINGS.h'), dataStringH);
// fs.writeFileSync(path.join(DIR_GENERATED, 'STRINGS.c'), dataStringC); // fs.writeFileSync(path.join(DIR_GENERATED, 'STRINGS.c'), dataStringC);
// compileC(path.join(DIR_GENERATED, 'STRINGS.c')); // compileC(path.join(DIR_GENERATED, 'STRINGS.c'));
// Gen imagery // Gen imagery
fs.readdirSync(DIR_IMAGES).forEach(img => { fs.readdirSync(DIR_IMAGES).forEach(img => {
if(!img.endsWith(".png")) return; if(!img.endsWith(".png")) return;
const { fileC, fileH } = png2gb( const { fileC, fileH } = png2gb(
path.join(DIR_IMAGES, img), DIR_GENERATED, path.join(DIR_IMAGES, img), DIR_GENERATED,
path.basename(img, '.png').toUpperCase() path.basename(img, '.png').toUpperCase()
); );
compileC(fileC); compileC(fileC);
}) })
// Get a list of sources and build each of them prior to linking. // Get a list of sources and build each of them prior to linking.
const allSources = buildSourceFiles(DIR_SRC); const allSources = buildSourceFiles(DIR_SRC);
for(let i = 0; i < allSources.length; i++) { for(let i = 0; i < allSources.length; i++) {
compileC(allSources[i]); compileC(allSources[i]);
} }
// Generate a linkfile. // Generate a linkfile.
fs.writeFileSync(FILE_LINKFILE, compiledSources.map(cs=>{ fs.writeFileSync(FILE_LINKFILE, compiledSources.map(cs=>{
return path.join(DIR_OBJ, cs); return path.join(DIR_OBJ, cs);
}).join('\n')); }).join('\n'));
// Compile BIN // Compile BIN
let result; let result;
try { try {
result = execSync(`${LCC} ${LCCFLAGS} -o ${FILE_OUT} -Wl-f${FILE_LINKFILE}`); result = execSync(`${LCC} ${LCCFLAGS} -o ${FILE_OUT} -Wl-f${FILE_LINKFILE}`);
logOut(result, console.log); logOut(result, console.log);
} catch(e) { } catch(e) {
logOut(e, console.error); logOut(e, console.error);
process.exit(1); process.exit(1);
} }

View File

@@ -1,4 +1,4 @@
const rimraf = require('rimraf'); const rimraf = require('rimraf');
console.log('🔥 Cleaning'); console.log('🔥 Cleaning');
rimraf.sync('build'); rimraf.sync('build');

View File

@@ -1,7 +1,7 @@
const TILE_WIDTH = 8; const TILE_WIDTH = 8;
const TILE_HEIGHT = 8; const TILE_HEIGHT = 8;
module.exports = { module.exports = {
TILE_WIDTH, TILE_WIDTH,
TILE_HEIGHT TILE_HEIGHT
} }

View File

@@ -1,88 +1,88 @@
const PNG = require('pngjs').PNG; const PNG = require('pngjs').PNG;
const fs = require('fs'); const fs = require('fs');
const { const {
TILE_WIDTH, TILE_WIDTH,
TILE_HEIGHT TILE_HEIGHT
} = require('./common'); } = require('./common');
const colorPixel = (id) => { const colorPixel = (id) => {
if(id === undefined) id = 3; if(id === undefined) id = 3;
if(id === 3) return { r: 8, g: 24, b: 32 }; if(id === 3) return { r: 8, g: 24, b: 32 };
if(id === 2) return { r: 52, g: 104, b: 86 }; if(id === 2) return { r: 52, g: 104, b: 86 };
if(id === 1) return { r: 136, g: 192, b: 112 }; if(id === 1) return { r: 136, g: 192, b: 112 };
if(id === 0) return { r: 224, g: 248, b: 208 }; if(id === 0) return { r: 224, g: 248, b: 208 };
throw new Error(); throw new Error();
} }
const gb2png = (DATA, fileOut) => { const gb2png = (DATA, fileOut) => {
// Begin // Begin
const PIXELS = DATA.length / 2 * TILE_WIDTH; const PIXELS = DATA.length / 2 * TILE_WIDTH;
const DATA_WIDTH = TILE_WIDTH; const DATA_WIDTH = TILE_WIDTH;
const DATA_HEIGHT = PIXELS / DATA_WIDTH; const DATA_HEIGHT = PIXELS / DATA_WIDTH;
// Create output image // Create output image
const imageData = new PNG({ const imageData = new PNG({
width: DATA_WIDTH, width: DATA_WIDTH,
height: DATA_HEIGHT height: DATA_HEIGHT
}); });
// Convert data into pixels // Convert data into pixels
const pixelsOut = []; const pixelsOut = [];
for(let i = 0; i < DATA.length; i += 2) { for(let i = 0; i < DATA.length; i += 2) {
const low = DATA[i]; const low = DATA[i];
const high = DATA[i+1]; const high = DATA[i+1];
for(let j = 0; j < 8; j++) { for(let j = 0; j < 8; j++) {
const mask = 0x80 >> j; const mask = 0x80 >> j;
const pixel = (low & mask ? 1 : 0) + (high & mask ? 2 : 0); const pixel = (low & mask ? 1 : 0) + (high & mask ? 2 : 0);
pixelsOut.push(pixel); pixelsOut.push(pixel);
} }
} }
// Buffer data output // Buffer data output
for(let y = 0; y < DATA_HEIGHT; y++) { for(let y = 0; y < DATA_HEIGHT; y++) {
for(let x = 0; x < DATA_WIDTH; x++) { for(let x = 0; x < DATA_WIDTH; x++) {
const id = (DATA_WIDTH * y + x); const id = (DATA_WIDTH * y + x);
const color = colorPixel(pixelsOut[id]); const color = colorPixel(pixelsOut[id]);
const idx = id << 2; const idx = id << 2;
imageData.data[idx] = color.r; imageData.data[idx] = color.r;
imageData.data[idx+1] = color.g; imageData.data[idx+1] = color.g;
imageData.data[idx+2] = color.b; imageData.data[idx+2] = color.b;
imageData.data[idx+3] = 0xFF; imageData.data[idx+3] = 0xFF;
} }
} }
const buffer = PNG.sync.write(imageData, { }); const buffer = PNG.sync.write(imageData, { });
fs.writeFileSync(fileOut, buffer); fs.writeFileSync(fileOut, buffer);
} }
// // Now work out tile data // // Now work out tile data
// if(TILEMAP.length) { // if(TILEMAP.length) {
// for(let i = 0; i < TILEMAP.length; i++) { // for(let i = 0; i < TILEMAP.length; i++) {
// const tileX = i % TILEMAP_WIDTH; // const tileX = i % TILEMAP_WIDTH;
// const tileY = Math.floor(i / TILEMAP_WIDTH); // const tileY = Math.floor(i / TILEMAP_WIDTH);
// const tile = TILEMAP[i]; // const tile = TILEMAP[i];
// for(let j = 0; j < TILE_WIDTH*TILE_HEIGHT; j++) { // for(let j = 0; j < TILE_WIDTH*TILE_HEIGHT; j++) {
// const outI = ( // const outI = (
// (tileX * TILE_WIDTH) + (tileY * TILE_HEIGHT * TILEMAP_PIXEL_WIDTH) + // (tileX * TILE_WIDTH) + (tileY * TILE_HEIGHT * TILEMAP_PIXEL_WIDTH) +
// ((j % TILE_WIDTH) + (Math.floor(j / TILE_WIDTH) * TILEMAP_PIXEL_WIDTH)) // ((j % TILE_WIDTH) + (Math.floor(j / TILE_WIDTH) * TILEMAP_PIXEL_WIDTH))
// ); // );
// const idx = outI << 2; // const idx = outI << 2;
// const pixelI = (tile * TILE_WIDTH * TILE_HEIGHT) + j; // const pixelI = (tile * TILE_WIDTH * TILE_HEIGHT) + j;
// const color = colorPixel(pixelsOut[pixelI]); // const color = colorPixel(pixelsOut[pixelI]);
// tileData.data[idx] = color.r; // tileData.data[idx] = color.r;
// tileData.data[idx+1] = color.g; // tileData.data[idx+1] = color.g;
// tileData.data[idx+2] = color.b; // tileData.data[idx+2] = color.b;
// tileData.data[idx+3] = 0xFF; // tileData.data[idx+3] = 0xFF;
// } // }
// } // }
// const buffer2 = PNG.sync.write(tileData, { }); // const buffer2 = PNG.sync.write(tileData, { });
// fs.writeFileSync('out.png', buffer2); // fs.writeFileSync('out.png', buffer2);
// } // }
module.exports = { module.exports = {
gb2png gb2png
}; };

View File

@@ -1,247 +1,247 @@
const fs = require('fs'); const fs = require('fs');
const { PNG } = require('pngjs'); const { PNG } = require('pngjs');
const path = require('path'); const path = require('path');
const TRANSPARENT = { r: 0, g: 0, b: 0, a: 0 }; const TRANSPARENT = { r: 0, g: 0, b: 0, a: 0 };
const WHITE = { r: 255, g: 255, b : 255, a: 255 }; const WHITE = { r: 255, g: 255, b : 255, a: 255 };
const RED = { r: 255, g: 0, b: 0, a: 255 }; const RED = { r: 255, g: 0, b: 0, a: 255 };
const TILE_WIDTH = 8; const TILE_WIDTH = 8;
const TILE_HEIGHT = 8; const TILE_HEIGHT = 8;
// Helpers // Helpers
const pixelIsSame = (left, right, alpha) => { const pixelIsSame = (left, right, alpha) => {
if(left.r !== right.r) return false; if(left.r !== right.r) return false;
if(left.g !== right.g) return false; if(left.g !== right.g) return false;
if(left.b !== right.b) return false; if(left.b !== right.b) return false;
if(!alpha) return true; if(!alpha) return true;
return left.a === right.a; return left.a === right.a;
} }
const imageOut = (pixels, width, fileName) => { const imageOut = (pixels, width, fileName) => {
const png = new PNG({ const png = new PNG({
width, width,
height: pixels.length / width height: pixels.length / width
}); });
pixels.forEach((pixel, i) => { pixels.forEach((pixel, i) => {
const x = i % width; const x = i % width;
const y = (i - x) / width; const y = (i - x) / width;
const idx = (width * y + x) << 2; const idx = (width * y + x) << 2;
png.data[idx] = pixel.r; png.data[idx] = pixel.r;
png.data[idx+1] = pixel.g; png.data[idx+1] = pixel.g;
png.data[idx+2] = pixel.b; png.data[idx+2] = pixel.b;
png.data[idx+3] = pixel.a; png.data[idx+3] = pixel.a;
}); });
if(!fs.existsSync('out')) fs.mkdirSync('out'); if(!fs.existsSync('out')) fs.mkdirSync('out');
const out = PNG.sync.write(png); const out = PNG.sync.write(png);
fs.writeFileSync(path.join('out', fileName), out); fs.writeFileSync(path.join('out', fileName), out);
} }
const imageIn = fileName => { const imageIn = fileName => {
const data = fs.readFileSync(fileName); const data = fs.readFileSync(fileName);
const png = PNG.sync.read(data); const png = PNG.sync.read(data);
const pixels = []; const pixels = [];
for(let y = 0; y < png.height; y++) { for(let y = 0; y < png.height; y++) {
for (let x = 0; x < png.width; x++) { for (let x = 0; x < png.width; x++) {
let idx = (png.width * y + x) << 2; let idx = (png.width * y + x) << 2;
const r = png.data[idx]; const r = png.data[idx];
const g = png.data[idx+1]; const g = png.data[idx+1];
const b = png.data[idx+2]; const b = png.data[idx+2];
const a = png.data[idx+3]; const a = png.data[idx+3];
let pixel = { r, g, b, a }; let pixel = { r, g, b, a };
if(a === 0) { if(a === 0) {
pixel = { ...WHITE }; pixel = { ...WHITE };
} else { } else {
pixel.a = 255; pixel.a = 255;
} }
pixels.push(pixel); pixels.push(pixel);
} }
} }
return { pixels, width: png.width, height: png.height }; return { pixels, width: png.width, height: png.height };
} }
const tileFromPixel = (x, y, original) => { const tileFromPixel = (x, y, original) => {
const byEightX = Math.floor(x / 8); const byEightX = Math.floor(x / 8);
const byEightY = Math.floor(y / 8); const byEightY = Math.floor(y / 8);
const byEightWidth = Math.floor(original.width / 8); const byEightWidth = Math.floor(original.width / 8);
const byEightId = byEightX + (byEightY * byEightWidth); const byEightId = byEightX + (byEightY * byEightWidth);
return { x: byEightX, y: byEightY, columns: byEightWidth, id: byEightId }; return { x: byEightX, y: byEightY, columns: byEightWidth, id: byEightId };
} }
// Read Input File // Read Input File
const original = imageIn('bruh.png'); const original = imageIn('bruh.png');
const columns = (original.width / TILE_WIDTH); const columns = (original.width / TILE_WIDTH);
const rows = (original.height / TILE_HEIGHT); const rows = (original.height / TILE_HEIGHT);
// Foreach pixel // Foreach pixel
const palette = []; const palette = [];
const paletteByEight = []; const paletteByEight = [];
const withPaletteOverflows = []; const withPaletteOverflows = [];
for(let y = 0; y < original.height; y++) { for(let y = 0; y < original.height; y++) {
for(let x = 0; x < original.width; x++) { for(let x = 0; x < original.width; x++) {
const id = x + (y * original.width); const id = x + (y * original.width);
const pixel = original.pixels[id]; const pixel = original.pixels[id];
let errorPixel = { ...pixel }; let errorPixel = { ...pixel };
const tile = tileFromPixel(x, y, original); const tile = tileFromPixel(x, y, original);
// Handle palettes // Handle palettes
if(pixel.a != 0) { if(pixel.a != 0) {
const pb8 = (paletteByEight[tile.id] = paletteByEight[tile.id] || []); const pb8 = (paletteByEight[tile.id] = paletteByEight[tile.id] || []);
if(!pb8.some(p => pixelIsSame(pixel, p))) { if(!pb8.some(p => pixelIsSame(pixel, p))) {
pb8.push(pixel); pb8.push(pixel);
} }
// Handle palette overflow // Handle palette overflow
if(pb8.length > 4) errorPixel = { ...RED }; if(pb8.length > 4) errorPixel = { ...RED };
// Append to palette // Append to palette
if(!palette.some(p => pixelIsSame(pixel, p))) palette.push(pixel); if(!palette.some(p => pixelIsSame(pixel, p))) palette.push(pixel);
} }
withPaletteOverflows.push(errorPixel); withPaletteOverflows.push(errorPixel);
} }
} }
// Generate the palette set image // Generate the palette set image
const outPaletteByEight = []; const outPaletteByEight = [];
let outByEightWidth = 1; let outByEightWidth = 1;
paletteByEight.forEach((pal,y) => { paletteByEight.forEach((pal,y) => {
pal.forEach((p,x) => { pal.forEach((p,x) => {
outByEightWidth = Math.max(outByEightWidth, x+1); outByEightWidth = Math.max(outByEightWidth, x+1);
}) })
}); });
paletteByEight.forEach((pal,y) => { paletteByEight.forEach((pal,y) => {
for(let x = 0; x < outByEightWidth; x++) { for(let x = 0; x < outByEightWidth; x++) {
outPaletteByEight.push(x >= pal.length ? TRANSPARENT : pal[x]); outPaletteByEight.push(x >= pal.length ? TRANSPARENT : pal[x]);
} }
}); });
// Now determine for each TILE what palette to use. // Now determine for each TILE what palette to use.
const paletteGroups = []; const paletteGroups = [];
const gbVersion = []; const gbVersion = [];
const paletteImage = []; const paletteImage = [];
for(let y = 0; y < original.height; y++) { for(let y = 0; y < original.height; y++) {
for(let x = 0; x < original.width; x++) { for(let x = 0; x < original.width; x++) {
const id = x + (y * original.width); const id = x + (y * original.width);
const pixel = original.pixels[id]; const pixel = original.pixels[id];
const tile = tileFromPixel(x, y, original); const tile = tileFromPixel(x, y, original);
// Get the palette // Get the palette
const paletteSet = paletteByEight[tile.id]; const paletteSet = paletteByEight[tile.id];
// Check for matching // Check for matching
let palId = paletteGroups.findIndex(pg => { let palId = paletteGroups.findIndex(pg => {
// Check for cases where one of the pallet group palettes may have // Check for cases where one of the pallet group palettes may have
// less pixels than the current set we're checking, e.g. we do a tile that // less pixels than the current set we're checking, e.g. we do a tile that
// has only two colors, then we iterate over a tile with 4 colors that has // has only two colors, then we iterate over a tile with 4 colors that has
// two colors shared with that other tile. In that case we just add our // two colors shared with that other tile. In that case we just add our
// two extra colors. // two extra colors.
if(paletteSet.length > pg.length) { if(paletteSet.length > pg.length) {
return pg.every(p => paletteSet.some(pss => pixelIsSame(pss, p))); return pg.every(p => paletteSet.some(pss => pixelIsSame(pss, p)));
} else { } else {
return paletteSet.every(p => pg.some(pgs => pixelIsSame(pgs, p))); return paletteSet.every(p => pg.some(pgs => pixelIsSame(pgs, p)));
} }
}); });
if(palId === -1) { if(palId === -1) {
palId = paletteGroups.length; palId = paletteGroups.length;
paletteGroups.push(paletteSet); paletteGroups.push(paletteSet);
} }
const paletteGroupSet = paletteGroups[palId]; const paletteGroupSet = paletteGroups[palId];
// This is where we correct the missing pixels if we share that tileset from // This is where we correct the missing pixels if we share that tileset from
// earlier // earlier
paletteSet.forEach(ps => { paletteSet.forEach(ps => {
const existing = paletteGroupSet.some(pgs => pixelIsSame(pgs, ps)); const existing = paletteGroupSet.some(pgs => pixelIsSame(pgs, ps));
if(existing) return; if(existing) return;
paletteGroupSet.push(ps); paletteGroupSet.push(ps);
}); });
// Sort the paletteGroupSet... // Sort the paletteGroupSet...
const pgsGetWeight = thing => { const pgsGetWeight = thing => {
return thing.r + thing.g + thing.b; return thing.r + thing.g + thing.b;
} }
paletteGroupSet.sort((l,r) => { paletteGroupSet.sort((l,r) => {
return pgsGetWeight(l) - pgsGetWeight(r); return pgsGetWeight(l) - pgsGetWeight(r);
}); });
const examples = [ const examples = [
/* 0 */{ r: 0, g: 0, b: 0, a: 255 }, /* 0 */{ r: 0, g: 0, b: 0, a: 255 },
/* 1 */{ r: 255, g: 0, b: 0, a: 255 }, /* 1 */{ r: 255, g: 0, b: 0, a: 255 },
/* 2 */{ r: 0, g: 255, b: 0, a: 255 }, /* 2 */{ r: 0, g: 255, b: 0, a: 255 },
/* 3 */{ r: 0, g: 0, b: 255, a: 255 }, /* 3 */{ r: 0, g: 0, b: 255, a: 255 },
/* 4 */{ r: 255, g: 255, b: 0, a: 255 }, /* 4 */{ r: 255, g: 255, b: 0, a: 255 },
/* 5 */{ r: 255, g: 0, b: 255, a: 255 }, /* 5 */{ r: 255, g: 0, b: 255, a: 255 },
/* 6 */{ r: 0, g: 255, b: 255, a: 255 }, /* 6 */{ r: 0, g: 255, b: 255, a: 255 },
/* 7 */{ r: 255, g: 255, b: 255, a: 255 }, /* 7 */{ r: 255, g: 255, b: 255, a: 255 },
/* S */{ r: 100, g: 0, b: 0, a: 255 }, /* S */{ r: 100, g: 0, b: 0, a: 255 },
/* S */{ r: 0, g: 100, b: 0, a: 255 }, /* S */{ r: 0, g: 100, b: 0, a: 255 },
/* S */{ r: 0, g: 0, b: 100, a: 255 }, /* S */{ r: 0, g: 0, b: 100, a: 255 },
/* S */{ r: 100, g: 100, b: 0, a: 255 }, /* S */{ r: 100, g: 100, b: 0, a: 255 },
/* S */{ r: 0, g: 100, b: 100, a: 255 }, /* S */{ r: 0, g: 100, b: 100, a: 255 },
/* S */{ r: 100, g: 0, b: 100, a: 255 }, /* S */{ r: 100, g: 0, b: 100, a: 255 },
/* S */{ r: 100, g: 100, b: 100, a: 255 }, /* S */{ r: 100, g: 100, b: 100, a: 255 },
]; ];
paletteImage.push(examples[palId]); paletteImage.push(examples[palId]);
const pixelIndex = paletteGroupSet.findIndex(ps => pixelIsSame(ps, pixel)); const pixelIndex = paletteGroupSet.findIndex(ps => pixelIsSame(ps, pixel));
const nonColor = [ const nonColor = [
{ r: 8, g: 24, b: 32, a: 255 }, { r: 8, g: 24, b: 32, a: 255 },
{ r: 52, g: 104, b: 86, a: 255 }, { r: 52, g: 104, b: 86, a: 255 },
{ r: 136, g: 192, b: 112, a: 255 }, { r: 136, g: 192, b: 112, a: 255 },
{ r: 224, g: 248, b: 208, a: 255 } { r: 224, g: 248, b: 208, a: 255 }
]; ];
gbVersion.push(nonColor[pixelIndex % nonColor.length]); gbVersion.push(nonColor[pixelIndex % nonColor.length]);
} }
} }
console.log('Found', paletteGroups.length, 'palettes'); console.log('Found', paletteGroups.length, 'palettes');
imageOut(original.pixels, original.width, 'original.png'); imageOut(original.pixels, original.width, 'original.png');
imageOut(withPaletteOverflows, original.width, 'errors.png'); imageOut(withPaletteOverflows, original.width, 'errors.png');
imageOut(palette, palette.length, 'palette.png'); imageOut(palette, palette.length, 'palette.png');
imageOut(outPaletteByEight, outByEightWidth, 'paletteByEight.png'); imageOut(outPaletteByEight, outByEightWidth, 'paletteByEight.png');
imageOut(paletteImage, original.width, 'palettes.png'); imageOut(paletteImage, original.width, 'palettes.png');
imageOut(gbVersion, original.width, 'gameboy.png'); imageOut(gbVersion, original.width, 'gameboy.png');
// Now generate the GB files // Now generate the GB files
// let rearranged = []; // let rearranged = [];
// let n = 0; // let n = 0;
// for(let i = 0; i < columns * rows; i++) { // for(let i = 0; i < columns * rows; i++) {
// const tileX = i % columns; // const tileX = i % columns;
// const tileY = Math.floor(i / columns) % rows; // const tileY = Math.floor(i / columns) % rows;
// for(let y = 0; y < TILE_HEIGHT; y++) { // for(let y = 0; y < TILE_HEIGHT; y++) {
// for(let x = 0; x < TILE_WIDTH; x++) { // for(let x = 0; x < TILE_WIDTH; x++) {
// const px = (tileX * TILE_WIDTH) + x; // const px = (tileX * TILE_WIDTH) + x;
// const py = (tileY * TILE_HEIGHT) + y; // const py = (tileY * TILE_HEIGHT) + y;
// const pi = (py * png.width) + px; // const pi = (py * png.width) + px;
// rearranged[n++] = original.pixels[pi]; // rearranged[n++] = original.pixels[pi];
// } // }
// } // }
// } // }
// // Now turn into a tileset // // Now turn into a tileset
// const bits = []; // const bits = [];
// for(let i = 0; i < rearranged.length; i += TILE_WIDTH) { // for(let i = 0; i < rearranged.length; i += TILE_WIDTH) {
// let lowBits = 0x00; // let lowBits = 0x00;
// let highBits = 0x00; // let highBits = 0x00;
// for(let j = 0; j < TILE_WIDTH; j++) { // for(let j = 0; j < TILE_WIDTH; j++) {
// const pixel = rearranged[i + j]; // const pixel = rearranged[i + j];
// lowBits = lowBits | ((pixel & 0x01) << (7-j)); // lowBits = lowBits | ((pixel & 0x01) << (7-j));
// highBits = highBits | ((pixel & 0x02) >> 1 << (7-j)); // highBits = highBits | ((pixel & 0x02) >> 1 << (7-j));
// } // }
// bits.push(lowBits, highBits); // bits.push(lowBits, highBits);
// } // }

View File

@@ -1,93 +1,101 @@
const PNG = require('pngjs').PNG; const PNG = require('pngjs').PNG;
const path = require('path'); const path = require('path');
const fs = require('fs'); const fs = require('fs');
const { arrayToString } = require('./util'); const { arrayToString } = require('./util');
const { const {
TILE_WIDTH, TILE_WIDTH,
TILE_HEIGHT TILE_HEIGHT
} = require('./common'); } = require('./common');
const getPixelValue = (pixel) => { const getPixelValue = (pixel) => {
if(pixel.g === 188) return 0; if(pixel.g === 188) return 0;
if(pixel.g === 172) return 1; if(pixel.g === 172) return 1;
if(pixel.g === 98) return 2; if(pixel.g === 98 || pixel.g === 145) return 2;
if(pixel.g === 56) return 3; if(pixel.g === 56) return 3;
throw new Error(); if(pixel.a === 0) return 0;
} throw new Error();
}
const png2gb = (fileIn, dirOut, name) => {
const data = fs.readFileSync(fileIn); const png2gb = (fileIn, dirOut, name) => {
const png = PNG.sync.read(data); const data = fs.readFileSync(fileIn);
const png = PNG.sync.read(data);
// Convert PNG pixels into 0x00-0x03
const pixels = []; // Convert PNG pixels into 0x00-0x03
for(let y = 0; y < png.height; y++) { const pixels = [];
for(let x = 0; x < png.width; x++) { for(let y = 0; y < png.height; y++) {
const id = x + (y * png.width); for(let x = 0; x < png.width; x++) {
const idx = id << 2; const id = x + (y * png.width);
const r = png.data[idx]; const idx = id << 2;
const g = png.data[idx+1]; const r = png.data[idx];
const b = png.data[idx+2]; const g = png.data[idx+1];
const value = getPixelValue({ r, g, b }); const b = png.data[idx+2];
pixels.push(value); const a = png.data[idx+3];
} const pixel = { r, g, b, a };
} try {
const value = getPixelValue(pixel);
// Now take these raw pixels and extract the tiles themselves pixels.push(value);
let rearranged = []; } catch(e) {
const columns = (png.width / TILE_WIDTH); console.error(`Failed to get color for `, x, y, idx, fileIn, pixel);
const rows = (png.height / TILE_HEIGHT); throw e;
let n = 0; }
for(let i = 0; i < columns * rows; i++) { }
const tileX = i % columns; }
const tileY = Math.floor(i / columns) % rows;
// Now take these raw pixels and extract the tiles themselves
for(let y = 0; y < TILE_HEIGHT; y++) { let rearranged = [];
for(let x = 0; x < TILE_WIDTH; x++) { const columns = (png.width / TILE_WIDTH);
const px = (tileX * TILE_WIDTH) + x; const rows = (png.height / TILE_HEIGHT);
const py = (tileY * TILE_HEIGHT) + y; let n = 0;
const pi = (py * png.width) + px; for(let i = 0; i < columns * rows; i++) {
rearranged[n++] = pixels[pi]; const tileX = i % columns;
} const tileY = Math.floor(i / columns) % rows;
}
} for(let y = 0; y < TILE_HEIGHT; y++) {
for(let x = 0; x < TILE_WIDTH; x++) {
// Now turn into a tileset const px = (tileX * TILE_WIDTH) + x;
const bits = []; const py = (tileY * TILE_HEIGHT) + y;
for(let i = 0; i < rearranged.length; i += TILE_WIDTH) { const pi = (py * png.width) + px;
let lowBits = 0x00; rearranged[n++] = pixels[pi];
let highBits = 0x00; }
for(let j = 0; j < TILE_WIDTH; j++) { }
const pixel = rearranged[i + j]; }
lowBits = lowBits | ((pixel & 0x01) << (7-j));
highBits = highBits | ((pixel & 0x02) >> 1 << (7-j)); // Now turn into a tileset
} const bits = [];
bits.push(lowBits, highBits); for(let i = 0; i < rearranged.length; i += TILE_WIDTH) {
} let lowBits = 0x00;
let highBits = 0x00;
let outH = ''; for(let j = 0; j < TILE_WIDTH; j++) {
outH += `#include "libs.h"\n\n` const pixel = rearranged[i + j];
outH += `#define ${name}_IMAGE_WIDTH ${png.width}\n`; lowBits = lowBits | ((pixel & 0x01) << (7-j));
outH += `#define ${name}_IMAGE_HEIGHT ${png.height}\n`; highBits = highBits | ((pixel & 0x02) >> 1 << (7-j));
outH += `#define ${name}_IMAGE_COLUMNS ${png.width / TILE_WIDTH}\n`; }
outH += `#define ${name}_IMAGE_ROWS ${png.height / TILE_HEIGHT}\n`; bits.push(lowBits, highBits);
outH += `#define ${name}_IMAGE_TILES ${columns * rows}\n`; }
outH += `extern const uint8_t ${name}_IMAGE[];`;
let outH = '';
let outC = `#include "${name}.h"\n`; outH += `#include "libs.h"\n\n`
outC += `\nconst uint8_t ${name}_IMAGE[] = {\n${arrayToString(bits)}};`; outH += `#define ${name}_IMAGE_WIDTH ${png.width}\n`;
outH += `#define ${name}_IMAGE_HEIGHT ${png.height}\n`;
const fileH = path.join(dirOut, name + '.h'); outH += `#define ${name}_IMAGE_COLUMNS ${png.width / TILE_WIDTH}\n`;
const fileC = path.join(dirOut, name + '.c'); outH += `#define ${name}_IMAGE_ROWS ${png.height / TILE_HEIGHT}\n`;
outH += `#define ${name}_IMAGE_TILES ${columns * rows}\n`;
fs.writeFileSync(fileH, outH); outH += `extern const uint8_t ${name}_IMAGE[];`;
fs.writeFileSync(fileC, outC);
return { fileH, fileC }; let outC = `#include "${name}.h"\n`;
} outC += `\nconst uint8_t ${name}_IMAGE[] = {\n${arrayToString(bits)}};`;
module.exports = { const fileH = path.join(dirOut, name + '.h');
png2gb const fileC = path.join(dirOut, name + '.c');
}
fs.writeFileSync(fileH, outH);
fs.writeFileSync(fileC, outC);
return { fileH, fileC };
}
module.exports = {
png2gb
}
// convert('images/sm.png', 'out.c', 'PENNY'); // convert('images/sm.png', 'out.c', 'PENNY');

View File

@@ -1,32 +1,32 @@
const fs = require('fs'); const fs = require('fs');
const path = require('path'); const path = require('path');
const { arrayToString } = require('./util'); const { arrayToString } = require('./util');
const FONT_CHARACTER_FIRST = 33; const FONT_CHARACTER_FIRST = 33;
const FONT_DATA_POSITION = 4; const FONT_DATA_POSITION = 4;
const getCodeFrom = l => { const getCodeFrom = l => {
const cc = l.charCodeAt(0) const cc = l.charCodeAt(0)
if(l == '\n' || l == ' ') return cc; if(l == '\n' || l == ' ') return cc;
return cc - FONT_CHARACTER_FIRST + FONT_DATA_POSITION return cc - FONT_CHARACTER_FIRST + FONT_DATA_POSITION
} }
const string2gb = (string, name) => { const string2gb = (string, name) => {
const letters = []; const letters = [];
for(let i = 0; i < string.length; i++) { for(let i = 0; i < string.length; i++) {
letters.push(getCodeFrom(string[i])); letters.push(getCodeFrom(string[i]));
} }
let dataH = `#define STR_${name}_LENGTH ${string.length}\n`; let dataH = `#define STR_${name}_LENGTH ${string.length}\n`;
dataH += `extern const uint8_t STR_${name}_DATA[];`; dataH += `extern const uint8_t STR_${name}_DATA[];`;
let dataC = `const uint8_t STR_${name}_DATA[] = {\n`; let dataC = `const uint8_t STR_${name}_DATA[] = {\n`;
dataC += arrayToString(letters); dataC += arrayToString(letters);
dataC += `\n};`; dataC += `\n};`;
return { dataH, dataC }; return { dataH, dataC };
} }
module.exports = { module.exports = {
string2gb string2gb
}; };

View File

@@ -1,21 +1,21 @@
const arrayToString = arr => { const arrayToString = arr => {
const b = arr.map(n => { const b = arr.map(n => {
return '0x' + (n.toString(16).padStart(2, '0').toUpperCase()); return '0x' + (n.toString(16).padStart(2, '0').toUpperCase());
}); });
let str = ''; let str = '';
for(let i = 0; i < b.length; i += 16) { for(let i = 0; i < b.length; i += 16) {
str += ' '; str += ' ';
for(let x = i; x < Math.min(i+16, b.length); x++) { for(let x = i; x < Math.min(i+16, b.length); x++) {
str += b[x]; str += b[x];
str += ','; str += ',';
} }
str += '\n'; str += '\n';
} }
return str; return str;
} }
module.exports = { module.exports = {
arrayToString arrayToString
} }

View File

@@ -1,69 +1,69 @@
/** /**
* Copyright (c) 2022 Dominic Masters * Copyright (c) 2022 Dominic Masters
* *
* This software is released under the MIT License. * This software is released under the MIT License.
* https://opensource.org/licenses/MIT * https://opensource.org/licenses/MIT
*/ */
#include "fade.h" #include "fade.h"
inline void conversationFadeToBlack() { inline void conversationFadeToBlack() {
TIME_FUTURE = TIME_CURRENT; TIME_FUTURE = TIME_CURRENT;
TIME_FUTURE_TYPE = TIME_FUTURE_TYPE_FADE_TO_BLACK; TIME_FUTURE_TYPE = TIME_FUTURE_TYPE_FADE_TO_BLACK;
} }
inline void conversationFadeFromBlack() { inline void conversationFadeFromBlack() {
TIME_FUTURE = TIME_CURRENT; TIME_FUTURE = TIME_CURRENT;
TIME_FUTURE_TYPE = TIME_FUTURE_TYPE_FADE_FROM_BLACK; TIME_FUTURE_TYPE = TIME_FUTURE_TYPE_FADE_FROM_BLACK;
} }
inline void conversationFadeToWhite() { inline void conversationFadeToWhite() {
TIME_FUTURE = TIME_CURRENT; TIME_FUTURE = TIME_CURRENT;
TIME_FUTURE_TYPE = TIME_FUTURE_TYPE_FADE_TO_WHITE; TIME_FUTURE_TYPE = TIME_FUTURE_TYPE_FADE_TO_WHITE;
} }
inline void conversationFadeFromWhite() { inline void conversationFadeFromWhite() {
TIME_FUTURE = TIME_CURRENT; TIME_FUTURE = TIME_CURRENT;
TIME_FUTURE_TYPE = TIME_FUTURE_TYPE_FADE_FROM_WHITE; TIME_FUTURE_TYPE = TIME_FUTURE_TYPE_FADE_FROM_WHITE;
} }
void conversationFadeUpdate() { void conversationFadeUpdate() {
uint16_t diff; uint16_t diff;
if( if(
TIME_FUTURE_TYPE < TIME_FUTURE_TYPE_FADE_TO_BLACK || TIME_FUTURE_TYPE < TIME_FUTURE_TYPE_FADE_TO_BLACK ||
TIME_FUTURE_TYPE > TIME_FUTURE_TYPE_FADE_FROM_WHITE TIME_FUTURE_TYPE > TIME_FUTURE_TYPE_FADE_FROM_WHITE
) return; ) return;
diff = TIME_CURRENT - TIME_FUTURE; diff = TIME_CURRENT - TIME_FUTURE;
// Now we work out the steps. Time is measured in steps which are made of // Now we work out the steps. Time is measured in steps which are made of
// parts of a second. This code assumes that the screen STARTS at the correct // parts of a second. This code assumes that the screen STARTS at the correct
// shade. // shade.
if(diff == FADE_STEP) { if(diff == FADE_STEP) {
// First step // First step
BGP_REG = ( BGP_REG = (
TIME_FUTURE_TYPE == TIME_FUTURE_TYPE_FADE_TO_BLACK ? COMMON_SHADE_DARK : TIME_FUTURE_TYPE == TIME_FUTURE_TYPE_FADE_TO_BLACK ? TILESET_SHADE_DARK :
TIME_FUTURE_TYPE == TIME_FUTURE_TYPE_FADE_TO_WHITE ? COMMON_SHADE_BRIGHT : TIME_FUTURE_TYPE == TIME_FUTURE_TYPE_FADE_TO_WHITE ? TILESET_SHADE_BRIGHT :
TIME_FUTURE_TYPE == TIME_FUTURE_TYPE_FADE_FROM_BLACK ? COMMON_SHADE_DARKER : TIME_FUTURE_TYPE == TIME_FUTURE_TYPE_FADE_FROM_BLACK ? TILESET_SHADE_DARKER :
COMMON_SHADE_BRIGHTER TILESET_SHADE_BRIGHTER
); );
} else if(diff == FADE_STEP * 2) { } else if(diff == FADE_STEP * 2) {
// Second step // Second step
BGP_REG = ( BGP_REG = (
TIME_FUTURE_TYPE == TIME_FUTURE_TYPE_FADE_TO_BLACK ? COMMON_SHADE_DARKER : TIME_FUTURE_TYPE == TIME_FUTURE_TYPE_FADE_TO_BLACK ? TILESET_SHADE_DARKER :
TIME_FUTURE_TYPE == TIME_FUTURE_TYPE_FADE_TO_WHITE ? COMMON_SHADE_BRIGHTER : TIME_FUTURE_TYPE == TIME_FUTURE_TYPE_FADE_TO_WHITE ? TILESET_SHADE_BRIGHTER :
TIME_FUTURE_TYPE == TIME_FUTURE_TYPE_FADE_FROM_BLACK ? COMMON_SHADE_DARK : TIME_FUTURE_TYPE == TIME_FUTURE_TYPE_FADE_FROM_BLACK ? TILESET_SHADE_DARK :
COMMON_SHADE_BRIGHT TILESET_SHADE_BRIGHT
); );
} else if(diff == FADE_STEP * 3) { } else if(diff == FADE_STEP * 3) {
// Third step // Third step
BGP_REG = ( BGP_REG = (
TIME_FUTURE_TYPE == TIME_FUTURE_TYPE_FADE_TO_BLACK ? COMMON_SHADE_BLACK : TIME_FUTURE_TYPE == TIME_FUTURE_TYPE_FADE_TO_BLACK ? TILESET_SHADE_BLACK :
TIME_FUTURE_TYPE == TIME_FUTURE_TYPE_FADE_TO_WHITE ? COMMON_SHADE_WHITE : TIME_FUTURE_TYPE == TIME_FUTURE_TYPE_FADE_TO_WHITE ? TILESET_SHADE_WHITE :
COMMON_SHADE_NORMAL TILESET_SHADE_NORMAL
); );
TIME_FUTURE_TYPE = TIME_FUTURE_TYPE_NULL; TIME_FUTURE_TYPE = TIME_FUTURE_TYPE_NULL;
conversationQueueNext(); conversationQueueNext();
} }
} }

View File

@@ -1,21 +1,21 @@
/** /**
* Copyright (c) 2022 Dominic Masters * Copyright (c) 2022 Dominic Masters
* *
* This software is released under the MIT License. * This software is released under the MIT License.
* https://opensource.org/licenses/MIT * https://opensource.org/licenses/MIT
*/ */
#pragma once #pragma once
#include "../libs.h" #include "../libs.h"
#include "queue.h" #include "queue.h"
#include "pause.h" #include "pause.h"
#include "../display/common.h" #include "../sprites/spritetileset.h"
// This is how many frames it takes to change each shade. // This is how many frames it takes to change each shade.
#define FADE_STEP 20 #define FADE_STEP 20
inline void conversationFadeToBlack(); inline void conversationFadeToBlack();
inline void conversationFadeFromBlack(); inline void conversationFadeFromBlack();
inline void conversationFadeToWhite(); inline void conversationFadeToWhite();
inline void conversationFadeFromWhite(); inline void conversationFadeFromWhite();
void conversationFadeUpdate(); void conversationFadeUpdate();

View File

@@ -1,40 +0,0 @@
/**
* Copyright (c) 2022 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "frame.h"
inline void frameBuffer(
uint8_t buffer[],
uint8_t bufferWidth, uint8_t bufferHeight,
uint8_t fill
) {
uint8_t i, j, max;
max = bufferWidth * bufferHeight;
// Corners
buffer[0] = BORDER_TILE_TOP_LEFT;
buffer[bufferWidth-1] = BORDER_TILE_TOP_RIGHT;
buffer[max-1] = BORDER_TILE_BOTTOM_RIGHT;
buffer[max-bufferWidth] = BORDER_TILE_BOTTOM_LEFT;
// Edges
for(i = 1; i < bufferWidth-1; i++) {
buffer[i] = BORDER_TILE_TOP_CENTER;
buffer[max - 1 - i] = BORDER_TILE_BOTTOM_CENTER;
}
for(i = 1; i < bufferHeight - 1; i++) {
buffer[bufferWidth * i] = BORDER_TILE_CENTER_LEFT;
buffer[bufferWidth * (i+1) - 1] = BORDER_TILE_CENTER_RIGHT;
}
// Inner
for(j = 1; j < bufferHeight-1; j++) {
for(i = 1; i < bufferWidth-1; i++) {
buffer[i + (j * bufferWidth)] = fill;
}
}
}

View File

@@ -1,28 +0,0 @@
/**
* Copyright (c) 2022 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "../libs.h"
#include "../util.h"
#include "../display/common.h"
#include "../display/tilemap.h"
#define BORDER_TILE_TOP_LEFT BORDER_DATA_POSITION
#define BORDER_TILE_TOP_CENTER BORDER_TILE_TOP_LEFT + 1
#define BORDER_TILE_TOP_RIGHT BORDER_TILE_TOP_CENTER + 1
#define BORDER_TILE_CENTER_LEFT BORDER_TILE_TOP_RIGHT + 1
#define BORDER_TILE_CENTER BORDER_TILE_CENTER_LEFT + 1
#define BORDER_TILE_CENTER_RIGHT BORDER_TILE_CENTER + 1
#define BORDER_TILE_BOTTOM_LEFT BORDER_TILE_CENTER_RIGHT + 1
#define BORDER_TILE_BOTTOM_CENTER BORDER_TILE_BOTTOM_LEFT + 1
#define BORDER_TILE_BOTTOM_RIGHT BORDER_TILE_BOTTOM_CENTER + 1
inline void frameBuffer(
uint8_t buffer[],
uint8_t bufferWidth, uint8_t bufferHeight,
uint8_t fill
);

View File

@@ -1,22 +1,22 @@
/** /**
* Copyright (c) 2022 Dominic Masters * Copyright (c) 2022 Dominic Masters
* *
* This software is released under the MIT License. * This software is released under the MIT License.
* https://opensource.org/licenses/MIT * https://opensource.org/licenses/MIT
*/ */
#include "pause.h" #include "pause.h"
inline void conversationPause(uint16_t duration) { inline void conversationPause(uint16_t duration) {
TIME_FUTURE = TIME_CURRENT + (duration * TIME_PER_SECOND); TIME_FUTURE = TIME_CURRENT + (duration * TIME_PER_SECOND);
TIME_FUTURE_TYPE = TIME_FUTURE_TYPE_PAUSE; TIME_FUTURE_TYPE = TIME_FUTURE_TYPE_PAUSE;
} }
inline void conversationPauseUpdate() { inline void conversationPauseUpdate() {
if(TIME_FUTURE_TYPE != TIME_FUTURE_TYPE_PAUSE || TIME_CURRENT != TIME_FUTURE) { if(TIME_FUTURE_TYPE != TIME_FUTURE_TYPE_PAUSE || TIME_CURRENT != TIME_FUTURE) {
return; return;
} }
TIME_FUTURE_TYPE = TIME_FUTURE_TYPE_NULL; TIME_FUTURE_TYPE = TIME_FUTURE_TYPE_NULL;
conversationQueueNext(); conversationQueueNext();
} }

View File

@@ -1,14 +1,14 @@
/** /**
* Copyright (c) 2022 Dominic Masters * Copyright (c) 2022 Dominic Masters
* *
* This software is released under the MIT License. * This software is released under the MIT License.
* https://opensource.org/licenses/MIT * https://opensource.org/licenses/MIT
*/ */
#pragma once #pragma once
#include "../libs.h" #include "../libs.h"
#include "../time.h" #include "../time.h"
#include "queue.h" #include "queue.h"
inline void conversationPause(uint16_t duration); inline void conversationPause(uint16_t duration);
inline void conversationPauseUpdate(); inline void conversationPauseUpdate();

View File

@@ -1,87 +1,87 @@
/** /**
* Copyright (c) 2022 Dominic Masters * Copyright (c) 2022 Dominic Masters
* *
* This software is released under the MIT License. * This software is released under the MIT License.
* https://opensource.org/licenses/MIT * https://opensource.org/licenses/MIT
*/ */
#include "questionbox.h" #include "questionbox.h"
uint8_t QUESTION_BOX_OPTION_COUNT; uint8_t QUESTION_BOX_OPTION_COUNT;
uint8_t QUESTION_BOX_OPTION_CURRENT; uint8_t QUESTION_BOX_OPTION_CURRENT;
void questionBoxSetOptions(char *title, char **options, uint8_t count) { void questionBoxSetOptions(char *title, char **options, uint8_t count) {
uint8_t i, j; uint8_t i, j;
char buffer[TEXTBOX_CHARS_MAX + 1]; char buffer[TEXTBOX_CHARS_MAX + 1];
char spaces[QUESTION_BOX_QUESTION_SPACES]; char spaces[QUESTION_BOX_QUESTION_SPACES];
sprintf(buffer, title); sprintf(buffer, title);
i = 0; i = 0;
QUESTION_BOX_OPTION_CURRENT = 0; QUESTION_BOX_OPTION_CURRENT = 0;
QUESTION_BOX_OPTION_COUNT = count; QUESTION_BOX_OPTION_COUNT = count;
for(i = 0; i < QUESTION_BOX_QUESTION_SPACES; i++) { for(i = 0; i < QUESTION_BOX_QUESTION_SPACES; i++) {
spaces[i] = ' '; spaces[i] = ' ';
} }
// For each row... // For each row...
for(i = 0; i < count; i++) { for(i = 0; i < count; i++) {
if((i & 1) == 0) { if((i & 1) == 0) {
j = strlen(options[i]); j = strlen(options[i]);
sprintf(buffer, "%s\n %s", buffer, options[i]); sprintf(buffer, "%s\n %s", buffer, options[i]);
} else { } else {
j = QUESTION_BOX_QUESTION_SPACES - j; j = QUESTION_BOX_QUESTION_SPACES - j;
spaces[j + 1] = '\0'; spaces[j + 1] = '\0';
sprintf(buffer, "%s%s%s", buffer, spaces, options[i]); sprintf(buffer, "%s%s%s", buffer, spaces, options[i]);
spaces[j + 1] = ' '; spaces[j + 1] = ' ';
} }
} }
conversationTextboxSetText(buffer); conversationTextboxSetText(buffer);
// Modify the textbox state // Modify the textbox state
TEXTBOX_STATE |= TEXTBOX_STATE_IS_QUESTION; TEXTBOX_STATE |= TEXTBOX_STATE_IS_QUESTION;
// Repurpose old array and draw arrow // Repurpose old array and draw arrow
spaces[0] = QUESTION_BOX_CURSOR - TEXTBOX_FONT_START + FONT_DATA_POSITION; spaces[0] = spriteFontTileFromChar(QUESTION_BOX_CURSOR);
set_bkg_tiles(0x01, TEXTBOX_WIN_Y + 0x02, 1, 1, spaces); set_bkg_tiles(0x01, TEXTBOX_WIN_Y + 0x02, 1, 1, spaces);
} }
inline void questionBoxUpdate() { inline void questionBoxUpdate() {
uint8_t tiles[1]; uint8_t tiles[1];
uint8_t i; uint8_t i;
if((TEXTBOX_STATE & (TEXTBOX_STATE_VISIBLE|TEXTBOX_STATE_IS_QUESTION)) == 0) return; if((TEXTBOX_STATE & (TEXTBOX_STATE_VISIBLE|TEXTBOX_STATE_IS_QUESTION)) == 0) return;
// Detect input // Detect input
if(INPUT_PRESSED & J_RIGHT) { if(INPUT_PRESSED & J_RIGHT) {
QUESTION_BOX_OPTION_CURRENT++; QUESTION_BOX_OPTION_CURRENT++;
} else if(INPUT_PRESSED & J_LEFT) { } else if(INPUT_PRESSED & J_LEFT) {
QUESTION_BOX_OPTION_CURRENT--; QUESTION_BOX_OPTION_CURRENT--;
} else if(INPUT_PRESSED & J_UP) { } else if(INPUT_PRESSED & J_UP) {
QUESTION_BOX_OPTION_CURRENT -= 2; QUESTION_BOX_OPTION_CURRENT -= 2;
} else if(INPUT_PRESSED & J_DOWN) { } else if(INPUT_PRESSED & J_DOWN) {
QUESTION_BOX_OPTION_CURRENT += 2; QUESTION_BOX_OPTION_CURRENT += 2;
} else { } else {
return; return;
} }
// Bound. // Bound.
QUESTION_BOX_OPTION_CURRENT = QUESTION_BOX_OPTION_CURRENT % QUESTION_BOX_OPTION_COUNT; QUESTION_BOX_OPTION_CURRENT = QUESTION_BOX_OPTION_CURRENT % QUESTION_BOX_OPTION_COUNT;
// Decide where to render arrow // Decide where to render arrow
for(i = 0; i < QUESTION_BOX_OPTION_COUNT; i++) { for(i = 0; i < QUESTION_BOX_OPTION_COUNT; i++) {
if(i == QUESTION_BOX_OPTION_CURRENT) { if(i == QUESTION_BOX_OPTION_CURRENT) {
tiles[0] = QUESTION_BOX_CURSOR - TEXTBOX_FONT_START + FONT_DATA_POSITION; tiles[0] = spriteFontTileFromChar(QUESTION_BOX_CURSOR);
} else { } else {
tiles[0] = ' ' - TEXTBOX_FONT_START + FONT_DATA_POSITION; tiles[0] = spriteFontTileFromChar(' ');
} }
set_bkg_tiles( set_bkg_tiles(
0x01 + ((i % 0x02) * QUESTION_BOX_QUESTION_SPACES), 0x01 + ((i % 0x02) * QUESTION_BOX_QUESTION_SPACES),
TEXTBOX_WIN_Y + 0x02 + (i / 0x02), TEXTBOX_WIN_Y + 0x02 + (i / 0x02),
1, 1, 1, 1,
tiles tiles
); );
} }
} }

View File

@@ -1,26 +1,26 @@
/** /**
* Copyright (c) 2022 Dominic Masters * Copyright (c) 2022 Dominic Masters
* *
* This software is released under the MIT License. * This software is released under the MIT License.
* https://opensource.org/licenses/MIT * https://opensource.org/licenses/MIT
*/ */
#pragma once #pragma once
#include "../libs.h" #include "../libs.h"
#include "../util.h" #include "../util.h"
#include "../input.h" #include "../input.h"
#include "../display/common.h" #include "../sprites/spritefont.h"
#include "../display/tilemap.h" #include "../sprites/spriteborder.h"
#include "frame.h" #include "../sprites/spritetileset.h"
#include "textbox.h" #include "textbox.h"
#define QUESTION_BOX_OPTIONS_MAX ((TEXTBOX_CHAR_ROWS-1)*2) #define QUESTION_BOX_OPTIONS_MAX ((TEXTBOX_CHAR_ROWS-1)*2)
#define QUESTION_BOX_CURSOR '>' #define QUESTION_BOX_CURSOR '>'
#define QUESTION_BOX_QUESTION_SPACES 9 #define QUESTION_BOX_QUESTION_SPACES 9
extern uint8_t QUESTION_BOX_OPTION_COUNT; extern uint8_t QUESTION_BOX_OPTION_COUNT;
extern uint8_t QUESTION_BOX_OPTION_CURRENT; extern uint8_t QUESTION_BOX_OPTION_CURRENT;
void questionBoxSetOptions(char *title, char **options, uint8_t count); void questionBoxSetOptions(char *title, char **options, uint8_t count);
inline void questionBoxUpdate(); inline void questionBoxUpdate();

View File

@@ -1,315 +1,315 @@
/** /**
* Copyright (c) 2022 Dominic Masters * Copyright (c) 2022 Dominic Masters
* *
* This software is released under the MIT License. * This software is released under the MIT License.
* https://opensource.org/licenses/MIT * https://opensource.org/licenses/MIT
*/ */
#include "queue.h" #include "queue.h"
#include "pause.h" #include "pause.h"
#include "textbox.h" #include "textbox.h"
#include "fade.h" #include "fade.h"
#include "../poker/poker.h" #include "../poker/poker.h"
uint16_t QUEUE_ITEM; uint16_t QUEUE_ITEM;
void conversationQueueDebug() { void conversationQueueDebug() {
conversationTextboxSetText(STR_ERROR); conversationTextboxSetText(STR_ERROR);
} }
void conversationQueueBegin() { void conversationQueueBegin() {
QUEUE_ITEM = QUEUE_TAKE_BLINDS; QUEUE_ITEM = QUEUE_TAKE_BLINDS;
conversationTextboxSetText(STR_POKER_GAME_START); conversationTextboxSetText(STR_POKER_GAME_START);
} }
void conversationQueueTakeBlinds() { void conversationQueueTakeBlinds() {
QUEUE_ITEM = QUEUE_DEAL_CARDS; QUEUE_ITEM = QUEUE_DEAL_CARDS;
conversationTextboxSetText(STR_POKER_GAME_TAKING_BLINDS); conversationTextboxSetText(STR_POKER_GAME_TAKING_BLINDS);
} }
void conversationQueueDealCards() { void conversationQueueDealCards() {
QUEUE_ITEM = QUEUE_BEGIN_BETTING; QUEUE_ITEM = QUEUE_BEGIN_BETTING;
conversationTextboxSetText(STR_POKER_GAME_CARDS_DEALT); conversationTextboxSetText(STR_POKER_GAME_CARDS_DEALT);
} }
void conversationQueueBeginBetting() { void conversationQueueBeginBetting() {
pokerturn_t turn; pokerturn_t turn;
turn.chips = 0; turn.chips = 0;
// Begin the betting process. First we need to decide if the player or the // Begin the betting process. First we need to decide if the player or the
// AI is betting, then based on that we decide what to do next. // AI is betting, then based on that we decide what to do next.
// TODO: Actually bet. // TODO: Actually bet.
if(POKER_PLAYER_BETTER == POKER_HUMAN_INDEX) { if(POKER_PLAYER_BETTER == POKER_HUMAN_INDEX) {
// This is the human player. // This is the human player.
BGB_MESSAGE("Player folding."); BGB_MESSAGE("Player folding.");
conversationTextboxSetText(STR_DEBUG_PLAYER); conversationTextboxSetText(STR_DEBUG_PLAYER);
POKER_PLAYERS[POKER_PLAYER_BETTER].state |= POKER_PLAYER_STATE_FOLDED; POKER_PLAYERS[POKER_PLAYER_BETTER].state |= POKER_PLAYER_STATE_FOLDED;
} else { } else {
// This is an AI player, get their turn. // This is an AI player, get their turn.
BGB_MESSAGE("AI turn to bet"); BGB_MESSAGE("AI turn to bet");
pokerAi(POKER_PLAYER_BETTER, &turn); pokerAi(POKER_PLAYER_BETTER, &turn);
BGB_printf("AI Decided to %u, with %u chips and %u confidence, bluffin: %u", turn.type, turn.chips, turn.confidence, turn.bluff); BGB_printf("AI Decided to %u, with %u chips and %u confidence, bluffin: %u", turn.type, turn.chips, turn.confidence, turn.bluff);
switch(turn.type) { switch(turn.type) {
case POKER_TURN_TYPE_FOLD: case POKER_TURN_TYPE_FOLD:
POKER_PLAYERS[POKER_PLAYER_BETTER].state |= POKER_PLAYER_STATE_FOLDED; POKER_PLAYERS[POKER_PLAYER_BETTER].state |= POKER_PLAYER_STATE_FOLDED;
conversationTextboxSetText(STR_POKER_GAME_AI_FOLD); conversationTextboxSetText(STR_POKER_GAME_AI_FOLD);
break; break;
case POKER_TURN_TYPE_BET: case POKER_TURN_TYPE_BET:
if(turn.bluff) { if(turn.bluff) {
conversationTextboxSetText(STR_POKER_GAME_AI_RAISE_BLUFF); conversationTextboxSetText(STR_POKER_GAME_AI_RAISE_BLUFF);
} else { } else {
conversationTextboxSetText(STR_POKER_GAME_AI_RAISE); conversationTextboxSetText(STR_POKER_GAME_AI_RAISE);
} }
break; break;
case POKER_TURN_TYPE_CALL: case POKER_TURN_TYPE_CALL:
if(turn.bluff) { if(turn.bluff) {
conversationTextboxSetText(STR_POKER_GAME_AI_CALL_BLUFF); conversationTextboxSetText(STR_POKER_GAME_AI_CALL_BLUFF);
} else { } else {
conversationTextboxSetText(STR_POKER_GAME_AI_CALL); conversationTextboxSetText(STR_POKER_GAME_AI_CALL);
} }
break; break;
case POKER_TURN_TYPE_ALL_IN: case POKER_TURN_TYPE_ALL_IN:
if(turn.bluff) { if(turn.bluff) {
conversationTextboxSetText(STR_POKER_GAME_AI_ALL_IN_BLUFF); conversationTextboxSetText(STR_POKER_GAME_AI_ALL_IN_BLUFF);
} else { } else {
conversationTextboxSetText(STR_POKER_GAME_AI_ALL_IN); conversationTextboxSetText(STR_POKER_GAME_AI_ALL_IN);
} }
break; break;
case POKER_TURN_TYPE_CHECK: case POKER_TURN_TYPE_CHECK:
if(turn.bluff) { if(turn.bluff) {
conversationTextboxSetText(STR_POKER_GAME_AI_CHECK_BLUFF); conversationTextboxSetText(STR_POKER_GAME_AI_CHECK_BLUFF);
} else { } else {
conversationTextboxSetText(STR_POKER_GAME_AI_CHECK); conversationTextboxSetText(STR_POKER_GAME_AI_CHECK);
} }
break; break;
} }
// Now we have their turn, decide what to say based on that. // Now we have their turn, decide what to say based on that.
} }
// Update bet state // Update bet state
POKER_PLAYERS[POKER_PLAYER_BETTER].state |= ( POKER_PLAYERS[POKER_PLAYER_BETTER].state |= (
POKER_PLAYER_STATE_HAS_BET_THIS_ROUND POKER_PLAYER_STATE_HAS_BET_THIS_ROUND
); );
if(turn.chips > 0) { if(turn.chips > 0) {
pokerBet(POKER_PLAYER_BETTER, turn.chips); pokerBet(POKER_PLAYER_BETTER, turn.chips);
} }
QUEUE_ITEM = QUEUE_NEXT_BETTER; QUEUE_ITEM = QUEUE_NEXT_BETTER;
} }
void conversationQueueNextBetter() { void conversationQueueNextBetter() {
uint8_t i, j, countStillInGame; uint8_t i, j, countStillInGame;
// Now we decide the next better. // Now we decide the next better.
countStillInGame = 0; countStillInGame = 0;
for(i = 0; i < POKER_PLAYER_COUNT; i++) { for(i = 0; i < POKER_PLAYER_COUNT; i++) {
//In theory I don't think the current better can ever be selected again. //In theory I don't think the current better can ever be selected again.
// if(i == POKER_PLAYER_BETTER) continue; // Commented because we now count // if(i == POKER_PLAYER_BETTER) continue; // Commented because we now count
// Next better is the better to the right of the current better. // Next better is the better to the right of the current better.
j = (POKER_PLAYER_BETTER + i) % POKER_PLAYER_COUNT; j = (POKER_PLAYER_BETTER + i) % POKER_PLAYER_COUNT;
if(!pokerDoesPlayerNeedToBet(j)) { if(!pokerDoesPlayerNeedToBet(j)) {
if((POKER_PLAYERS[j].state & (POKER_PLAYER_STATE_FOLDED | POKER_PLAYER_STATE_OUT)) == 0) { if((POKER_PLAYERS[j].state & (POKER_PLAYER_STATE_FOLDED | POKER_PLAYER_STATE_OUT)) == 0) {
countStillInGame++; countStillInGame++;
} }
continue; continue;
} }
// They haven't bet yet, make them the "next better" // They haven't bet yet, make them the "next better"
POKER_PLAYER_BETTER = j; POKER_PLAYER_BETTER = j;
QUEUE_ITEM = QUEUE_BEGIN_BETTING; QUEUE_ITEM = QUEUE_BEGIN_BETTING;
conversationQueueNext(); conversationQueueNext();
return; return;
} }
// If we reach this point then we either need to begin the betting round, or // If we reach this point then we either need to begin the betting round, or
// we are going to move to the winning decider. // we are going to move to the winning decider.
if(POKER_COMMUNITY_SIZE_MAX == POKER_COMMUNITY_SIZE || countStillInGame == 1) { if(POKER_COMMUNITY_SIZE_MAX == POKER_COMMUNITY_SIZE || countStillInGame == 1) {
QUEUE_ITEM = QUEUE_WINNER_DECIDE; QUEUE_ITEM = QUEUE_WINNER_DECIDE;
conversationQueueNext(); conversationQueueNext();
return; return;
} }
QUEUE_ITEM = QUEUE_FLOP; QUEUE_ITEM = QUEUE_FLOP;
conversationQueueNext(); conversationQueueNext();
} }
void conversationQueueFlopTurnRiver() { void conversationQueueFlopTurnRiver() {
uint8_t i, count; uint8_t i, count;
pokerplayer_t *player; pokerplayer_t *player;
switch(POKER_COMMUNITY_SIZE) { switch(POKER_COMMUNITY_SIZE) {
case 0: case 0:
count = POKER_COUNT_FLOP; count = POKER_COUNT_FLOP;
conversationTextboxSetText(STR_POKER_GAME_CARDS_FLOPPED); conversationTextboxSetText(STR_POKER_GAME_CARDS_FLOPPED);
break; break;
case POKER_COUNT_FLOP: case POKER_COUNT_FLOP:
count = POKER_COUNT_TURN; count = POKER_COUNT_TURN;
conversationTextboxSetText(STR_POKER_GAME_CARDS_TURNED); conversationTextboxSetText(STR_POKER_GAME_CARDS_TURNED);
break; break;
default: default:
count = POKER_COUNT_RIVER; count = POKER_COUNT_RIVER;
conversationTextboxSetText(STR_POKER_GAME_CARDS_RIVERED); conversationTextboxSetText(STR_POKER_GAME_CARDS_RIVERED);
break; break;
} }
// Reset each players required to bet state // Reset each players required to bet state
do { do {
player = POKER_PLAYERS + i; player = POKER_PLAYERS + i;
player->state &= ~POKER_PLAYER_STATE_HAS_BET_THIS_ROUND; player->state &= ~POKER_PLAYER_STATE_HAS_BET_THIS_ROUND;
player->timesRaised = 0; player->timesRaised = 0;
} while(++i < POKER_PLAYER_COUNT); } while(++i < POKER_PLAYER_COUNT);
// In reality we'd burn the top card but that would waste some CPU I need. // In reality we'd burn the top card but that would waste some CPU I need.
// Deal the top cards. // Deal the top cards.
for(i = 0; i < count; i++) { for(i = 0; i < count; i++) {
POKER_COMMUNITY[POKER_COMMUNITY_SIZE++] = POKER_DECK[--POKER_DECK_SIZE]; POKER_COMMUNITY[POKER_COMMUNITY_SIZE++] = POKER_DECK[--POKER_DECK_SIZE];
} }
// Check how many players need to bet, if it's zero then all players are // Check how many players need to bet, if it's zero then all players are
// either folded or all-in // either folded or all-in
if(pokerGetRemainingBetterCount() == 0x00) { if(pokerGetRemainingBetterCount() == 0x00) {
if(POKER_COMMUNITY_SIZE == POKER_COMMUNITY_SIZE_MAX) { if(POKER_COMMUNITY_SIZE == POKER_COMMUNITY_SIZE_MAX) {
QUEUE_ITEM = QUEUE_WINNER_DECIDE; QUEUE_ITEM = QUEUE_WINNER_DECIDE;
} else { } else {
QUEUE_ITEM = QUEUE_FLOP; QUEUE_ITEM = QUEUE_FLOP;
} }
} else { } else {
QUEUE_ITEM = QUEUE_BEGIN_BETTING; QUEUE_ITEM = QUEUE_BEGIN_BETTING;
} }
} }
void conversationQueueWinnerDecide() { void conversationQueueWinnerDecide() {
pokerpot_t *pot; pokerpot_t *pot;
uint8_t i, j, countOfPotsWithChips, chipsEach; uint8_t i, j, countOfPotsWithChips, chipsEach;
QUEUE_ITEM = QUEUE_BEGIN; QUEUE_ITEM = QUEUE_BEGIN;
countOfPotsWithChips = 0; countOfPotsWithChips = 0;
for(i = 0; i < POKER_POT_COUNT; i++) { for(i = 0; i < POKER_POT_COUNT; i++) {
pot = POKER_POTS + i; pot = POKER_POTS + i;
if(pot->chips == 0) break; if(pot->chips == 0) break;
countOfPotsWithChips++; countOfPotsWithChips++;
} }
// TODO: Messages // TODO: Messages
if(countOfPotsWithChips == 1) { if(countOfPotsWithChips == 1) {
} else { } else {
} }
// Pots. // Pots.
for(i = 0; i < countOfPotsWithChips; i++) { for(i = 0; i < countOfPotsWithChips; i++) {
pot = POKER_POTS + i; pot = POKER_POTS + i;
pokerWinnerDetermineForPot( pokerWinnerDetermineForPot(
pot, pot,
POKER_WINNERS, POKER_WINNERS,
POKER_WINNER_PLAYERS, POKER_WINNER_PLAYERS,
&POKER_WINNER_COUNT, &POKER_WINNER_COUNT,
POKER_WINNER_PARTICIPANTS, POKER_WINNER_PARTICIPANTS,
&POKER_WINNER_PARTICIPANT_COUNT &POKER_WINNER_PARTICIPANT_COUNT
); );
chipsEach = pot->chips / POKER_WINNER_COUNT; chipsEach = pot->chips / POKER_WINNER_COUNT;
for(j = 0; j < POKER_WINNER_COUNT; j++) { for(j = 0; j < POKER_WINNER_COUNT; j++) {
POKER_PLAYERS[POKER_WINNER_PLAYERS[j]].chips += chipsEach; POKER_PLAYERS[POKER_WINNER_PLAYERS[j]].chips += chipsEach;
// TODO: I can determine rounding error here if I need to, just sub the // TODO: I can determine rounding error here if I need to, just sub the
// taken chips for each player and when I get to chips remaining less than // taken chips for each player and when I get to chips remaining less than
// the chipsEach, then reward the rounding offset. // the chipsEach, then reward the rounding offset.
} }
} }
// TODO: Decide on a winner for real. // TODO: Decide on a winner for real.
conversationTextboxSetText(STR_DEBUG_WINNER_DECIDED); conversationTextboxSetText(STR_DEBUG_WINNER_DECIDED);
// New Round // New Round
pokerNewRound(); pokerNewRound();
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
queuecallback_t *QUEUE_CALLBACKS[] = { queuecallback_t *QUEUE_CALLBACKS[] = {
// 0 // 0
NULL, NULL,
&conversationQueueDebug, &conversationQueueDebug,
NULL, NULL,
NULL, NULL,
NULL, NULL,
// 5 // 5
&conversationQueueBegin, &conversationQueueBegin,
NULL, NULL,
NULL, NULL,
NULL, NULL,
NULL, NULL,
// 10 // 10
&conversationQueueTakeBlinds, &conversationQueueTakeBlinds,
NULL, NULL,
NULL, NULL,
NULL, NULL,
NULL, NULL,
// 15 // 15
&conversationQueueDealCards, &conversationQueueDealCards,
NULL, NULL,
NULL, NULL,
NULL, NULL,
NULL, NULL,
// 20 // 20
&conversationQueueBeginBetting, &conversationQueueBeginBetting,
NULL, NULL,
NULL, NULL,
NULL, NULL,
NULL, NULL,
// 25 // 25
&conversationQueueNextBetter, &conversationQueueNextBetter,
NULL, NULL,
NULL, NULL,
NULL, NULL,
NULL, NULL,
// 30 // 30
&conversationQueueFlopTurnRiver, &conversationQueueFlopTurnRiver,
NULL, NULL,
NULL, NULL,
NULL, NULL,
NULL, NULL,
// 35 // 35
NULL, NULL,
NULL, NULL,
NULL, NULL,
NULL, NULL,
NULL, NULL,
// 40 // 40
&conversationQueueWinnerDecide, &conversationQueueWinnerDecide,
// NULL, // NULL,
// NULL, // NULL,
// NULL, // NULL,
// NULL, // NULL,
}; };
inline void conversationQueueInit() { inline void conversationQueueInit() {
QUEUE_ITEM = QUEUE_BEGIN; QUEUE_ITEM = QUEUE_BEGIN;
} }
inline void conversationQueueNext() { inline void conversationQueueNext() {
BGB_printf("Doing %d", QUEUE_ITEM); BGB_printf("Doing %d", QUEUE_ITEM);
if(QUEUE_ITEM > QUEUE_WINNER_DECIDE) return; if(QUEUE_ITEM > QUEUE_WINNER_DECIDE) return;
if(QUEUE_CALLBACKS[QUEUE_ITEM] == NULL) return; if(QUEUE_CALLBACKS[QUEUE_ITEM] == NULL) return;
QUEUE_CALLBACKS[QUEUE_ITEM](); QUEUE_CALLBACKS[QUEUE_ITEM]();
} }

View File

@@ -1,27 +1,27 @@
/** /**
* Copyright (c) 2022 Dominic Masters * Copyright (c) 2022 Dominic Masters
* *
* This software is released under the MIT License. * This software is released under the MIT License.
* https://opensource.org/licenses/MIT * https://opensource.org/licenses/MIT
*/ */
#pragma once #pragma once
#include "../libs.h" #include "../libs.h"
#include "../strings.h" #include "../strings.h"
typedef void queuecallback_t(); typedef void queuecallback_t();
extern uint16_t QUEUE_ITEM; extern uint16_t QUEUE_ITEM;
extern queuecallback_t *QUEUE_CALLBACKS[]; extern queuecallback_t *QUEUE_CALLBACKS[];
#define QUEUE_DEBUG 1 #define QUEUE_DEBUG 1
#define QUEUE_BEGIN 5 #define QUEUE_BEGIN 5
#define QUEUE_TAKE_BLINDS 10 #define QUEUE_TAKE_BLINDS 10
#define QUEUE_DEAL_CARDS 15 #define QUEUE_DEAL_CARDS 15
#define QUEUE_BEGIN_BETTING 20 #define QUEUE_BEGIN_BETTING 20
#define QUEUE_NEXT_BETTER 25 #define QUEUE_NEXT_BETTER 25
#define QUEUE_FLOP 30 #define QUEUE_FLOP 30
#define QUEUE_WINNER_DECIDE 40 #define QUEUE_WINNER_DECIDE 40
inline void conversationQueueInit(); inline void conversationQueueInit();
inline void conversationQueueNext(); inline void conversationQueueNext();

View File

@@ -1,150 +1,144 @@
/** /**
* Copyright (c) 2022 Dominic Masters * Copyright (c) 2022 Dominic Masters
* *
* This software is released under the MIT License. * This software is released under the MIT License.
* https://opensource.org/licenses/MIT * https://opensource.org/licenses/MIT
*/ */
#include "textbox.h" #include "textbox.h"
char TEXTBOX_TEXTS[TEXTBOX_SCROLL_ROWS_MAX * TEXTBOX_CHARS_PER_ROW]; char TEXTBOX_TEXTS[TEXTBOX_SCROLL_ROWS_MAX * TEXTBOX_CHARS_PER_ROW];
uint8_t TEXTBOX_ROW_COUNT; uint8_t TEXTBOX_ROW_COUNT;
uint8_t TEXTBOX_ROW_TILE_LAST; uint8_t TEXTBOX_ROW_TILE_LAST;
uint8_t TEXTBOX_ROW_CURRENT; uint8_t TEXTBOX_ROW_CURRENT;
uint8_t TEXTBOX_STATE; uint8_t TEXTBOX_STATE;
uint8_t TEXTBOX_SCROLL; uint8_t TEXTBOX_SCROLL;
inline void conversationTextboxInit() { inline void conversationTextboxInit() {
uint8_t i; // Reset textbox state
uint8_t TEXTBOX_TILES[TEXTBOX_TILES_MAX]; TEXTBOX_STATE = 0;
}
// Reset textbox state
TEXTBOX_STATE = 0; void conversationTextboxSetText(char *text) {
uint8_t i, j, k, rowStart, stateFlags;
// Setup window data char c, c2;
set_win_data(FONT_DATA_POSITION, FONT_IMAGE_TILES, FONT_IMAGE);
set_win_data(BORDER_DATA_POSITION, BORDER_IMAGE_TILES, BORDER_IMAGE); // Begin by filling the textbox text chars with whitespace to begin.
} // TODO: I'm pretty sure I can move this lower and optimize.
for(i = 0; i < TEXTBOX_SCROLL_ROWS_MAX * TEXTBOX_CHARS_PER_ROW; i++) {
void conversationTextboxSetText(char *text) { TEXTBOX_TEXTS[i] = ' ';
uint8_t i, j, k, rowStart, stateFlags; }
char c, c2;
// Reset textbox state
// Begin by filling the textbox text chars with whitespace to begin. TEXTBOX_STATE = TEXTBOX_STATE_VISIBLE;
// TODO: I'm pretty sure I can move this lower and optimize. TEXTBOX_SCROLL = 0;
for(i = 0; i < TEXTBOX_SCROLL_ROWS_MAX * TEXTBOX_CHARS_PER_ROW; i++) { TEXTBOX_ROW_COUNT = 0;
TEXTBOX_TEXTS[i] = ' '; TEXTBOX_ROW_COUNT = 1;
}
// Copy source text to buffer, also determine wordwrapping here.
// Reset textbox state i = 0, j = 0, rowStart = 0, stateFlags = 0;
TEXTBOX_STATE = TEXTBOX_STATE_VISIBLE; while((c = text[i]) != '\0') {// "For each char in string"
TEXTBOX_SCROLL = 0; if(c == ' ') {
TEXTBOX_ROW_COUNT = 0; // Scan ahead and look at how many chars remain to the next space.
TEXTBOX_ROW_COUNT = 1; k = i + 1;
while(
// Copy source text to buffer, also determine wordwrapping here. (c2 = text[k]) != '\0' &&
i = 0, j = 0, rowStart = 0, stateFlags = 0; c2 != '\n' &&
while((c = text[i]) != '\0') {// "For each char in string" c2 != ' ' &&
if(c == ' ') { (k - rowStart) < TEXTBOX_CHARS_PER_ROW
// Scan ahead and look at how many chars remain to the next space. ) k++;
k = i + 1;
while( // IF that number is less than the remaining chars on the current row,
(c2 = text[k]) != '\0' && // then treat this space like a newline.
c2 != '\n' && if(k >= (rowStart + TEXTBOX_CHARS_PER_ROW + 1)) {
c2 != ' ' && stateFlags |= 1 << 0;
(k - rowStart) < TEXTBOX_CHARS_PER_ROW }
) k++; } else if(c == '\n') {
stateFlags |= 1 << 0;
// IF that number is less than the remaining chars on the current row, }
// then treat this space like a newline.
if(k >= (rowStart + TEXTBOX_CHARS_PER_ROW + 1)) { // Do we need to insert newline where we are currently?
stateFlags |= 1 << 0; if((stateFlags & (1 << 0)) != 0) {
} stateFlags &= ~(1 << 0);// Remove newline flag
} else if(c == '\n') { i++;
stateFlags |= 1 << 0; rowStart = i;// Update the row start (Should this be i+1?)
} //TODO: can I optimize the next line by using rowStart somehow?
j = ((j / TEXTBOX_CHARS_PER_ROW)+1) * TEXTBOX_CHARS_PER_ROW;// Update destination character position.
// Do we need to insert newline where we are currently? TEXTBOX_ROW_COUNT++;
if((stateFlags & (1 << 0)) != 0) { continue;
stateFlags &= ~(1 << 0);// Remove newline flag }
i++;
rowStart = i;// Update the row start (Should this be i+1?) // Insert the character
//TODO: can I optimize the next line by using rowStart somehow? TEXTBOX_TEXTS[j] = c;
j = ((j / TEXTBOX_CHARS_PER_ROW)+1) * TEXTBOX_CHARS_PER_ROW;// Update destination character position. i++;
TEXTBOX_ROW_COUNT++; j++;
continue; }
}
// Now we have organized the string nicely we can prep for rendering. Fill the
// Insert the character // tiles with blank chars.
TEXTBOX_TEXTS[j] = c; textboxFillBlank();
i++; }
j++;
} inline void textboxFillBlank() {
uint8_t tiles[TEXTBOX_WIDTH_IN_TILES * TEXTBOX_HEIGHT_IN_TILES];
// Now we have organized the string nicely we can prep for rendering. Fill the
// tiles with blank chars. spriteBorderBufferEdges(
textboxFillBlank(); tiles, TEXTBOX_WIDTH_IN_TILES, TEXTBOX_HEIGHT_IN_TILES, SPRITE_TILESET_WHITE
} );
inline void textboxFillBlank() { set_bkg_tiles(
uint8_t TEXTBOX_TILES[TEXTBOX_WIDTH_IN_TILES * TEXTBOX_HEIGHT_IN_TILES]; 0x00, TEXTBOX_WIN_Y,
TEXTBOX_WIDTH_IN_TILES, TEXTBOX_HEIGHT_IN_TILES,
frameBuffer(TEXTBOX_TILES, TEXTBOX_WIDTH_IN_TILES, TEXTBOX_HEIGHT_IN_TILES, TEXTBOX_TILE_BLANK); tiles
);
set_bkg_tiles( }
0x00, TEXTBOX_WIN_Y,
TEXTBOX_WIDTH_IN_TILES, TEXTBOX_HEIGHT_IN_TILES, inline void conversationTextboxUpdate() {
TEXTBOX_TILES uint8_t i, tile;
); char c;
}
// Is the textbox visible?
inline void conversationTextboxUpdate() { if((TEXTBOX_STATE & TEXTBOX_STATE_VISIBLE) == 0) return;
uint8_t i;
char c; // Have we finished scrolling?
uint8_t tiles[1]; if(TEXTBOX_STATE & TEXTBOX_STATE_SCROLLED) {
// Is the user trying to go to the next line?
// Is the textbox visible? if(INPUT_PRESSED & J_A) {
if((TEXTBOX_STATE & TEXTBOX_STATE_VISIBLE) == 0) return; // First, lets figure out if there's any more text to reveal or not.
if((TEXTBOX_ROW_COUNT - TEXTBOX_ROW_CURRENT) < TEXTBOX_TILES_ROWS) {
// Have we finished scrolling? TEXTBOX_STATE &= ~TEXTBOX_STATE_VISIBLE;
if(TEXTBOX_STATE & TEXTBOX_STATE_SCROLLED) { HIDE_WIN;
// Is the user trying to go to the next line? conversationQueueNext();
if(INPUT_PRESSED & J_A) { return;
// First, lets figure out if there's any more text to reveal or not. }
if((TEXTBOX_ROW_COUNT - TEXTBOX_ROW_CURRENT) < TEXTBOX_TILES_ROWS) {
TEXTBOX_STATE &= ~TEXTBOX_STATE_VISIBLE; TEXTBOX_STATE &= ~TEXTBOX_STATE_SCROLLED;
HIDE_WIN; TEXTBOX_SCROLL = 0;
conversationQueueNext(); TEXTBOX_ROW_CURRENT += TEXTBOX_TILES_ROWS;
return; textboxFillBlank();
} }
return;
TEXTBOX_STATE &= ~TEXTBOX_STATE_SCROLLED; }
TEXTBOX_SCROLL = 0;
TEXTBOX_ROW_CURRENT += TEXTBOX_TILES_ROWS; // Move to the next character.
textboxFillBlank(); i = TEXTBOX_ROW_CURRENT * TEXTBOX_CHARS_PER_ROW;
} c = TEXTBOX_TEXTS[i+TEXTBOX_SCROLL];
return;
} if(TEXTBOX_SCROLL == TEXTBOX_CHARS_MAX) {
TEXTBOX_STATE |= TEXTBOX_STATE_SCROLLED;
// Move to the next character. } else {
i = TEXTBOX_ROW_CURRENT * TEXTBOX_CHARS_PER_ROW; tile = spriteFontTileFromChar(c);
c = TEXTBOX_TEXTS[i+TEXTBOX_SCROLL];
set_bkg_tiles(
if(TEXTBOX_SCROLL == TEXTBOX_CHARS_MAX) { 0x01 + (TEXTBOX_SCROLL % TEXTBOX_CHARS_PER_ROW),
TEXTBOX_STATE |= TEXTBOX_STATE_SCROLLED; TEXTBOX_WIN_Y + 0x01 + (TEXTBOX_SCROLL / TEXTBOX_CHARS_PER_ROW),
} else { 1, 1,
tiles[0] = c - TEXTBOX_FONT_START + FONT_DATA_POSITION; &tile
);
set_bkg_tiles(
0x01 + (TEXTBOX_SCROLL % TEXTBOX_CHARS_PER_ROW), TEXTBOX_SCROLL++;
TEXTBOX_WIN_Y + 0x01 + (TEXTBOX_SCROLL / TEXTBOX_CHARS_PER_ROW),
1, 1, // Skip spaces
tiles while(TEXTBOX_SCROLL < TEXTBOX_CHARS_MAX && TEXTBOX_TEXTS[i+TEXTBOX_SCROLL] == ' ') TEXTBOX_SCROLL++;
); }
TEXTBOX_SCROLL++;
// Skip spaces
while(TEXTBOX_SCROLL < TEXTBOX_CHARS_MAX && TEXTBOX_TEXTS[i+TEXTBOX_SCROLL] == ' ') TEXTBOX_SCROLL++;
}
} }

View File

@@ -1,49 +1,46 @@
/** /**
* Copyright (c) 2022 Dominic Masters * Copyright (c) 2022 Dominic Masters
* *
* This software is released under the MIT License. * This software is released under the MIT License.
* https://opensource.org/licenses/MIT * https://opensource.org/licenses/MIT
*/ */
#pragma once #pragma once
#include "../libs.h" #include "../libs.h"
#include "../util.h" #include "../util.h"
#include "../input.h" #include "../input.h"
#include "../display/common.h" #include "../sprites/spriteborder.h"
#include "../display/tilemap.h" #include "../sprites/spritefont.h"
#include "queue.h" #include "../sprites/spritetileset.h"
#include "frame.h" #include "queue.h"
#define TEXTBOX_STATE_VISIBLE (1 << 0) #define TEXTBOX_STATE_VISIBLE (1 << 0)
#define TEXTBOX_STATE_SCROLLED (1 << 1) #define TEXTBOX_STATE_SCROLLED (1 << 1)
#define TEXTBOX_STATE_IS_QUESTION (1 << 2) #define TEXTBOX_STATE_IS_QUESTION (1 << 2)
#define TEXTBOX_WIDTH_IN_TILES 20 #define TEXTBOX_WIDTH_IN_TILES 20
#define TEXTBOX_HEIGHT_IN_TILES 5 #define TEXTBOX_HEIGHT_IN_TILES 5
#define TEXTBOX_TILES_MAX (TEXTBOX_WIDTH_IN_TILES * TEXTBOX_HEIGHT_IN_TILES) #define TEXTBOX_TILES_MAX (TEXTBOX_WIDTH_IN_TILES * TEXTBOX_HEIGHT_IN_TILES)
#define TEXTBOX_CHARS_PER_ROW (TEXTBOX_WIDTH_IN_TILES - 2) #define TEXTBOX_CHARS_PER_ROW (TEXTBOX_WIDTH_IN_TILES - 2)
#define TEXTBOX_CHAR_ROWS (TEXTBOX_HEIGHT_IN_TILES - 2) #define TEXTBOX_CHAR_ROWS (TEXTBOX_HEIGHT_IN_TILES - 2)
#define TEXTBOX_CHARS_MAX (TEXTBOX_CHAR_ROWS * TEXTBOX_CHARS_PER_ROW) #define TEXTBOX_CHARS_MAX (TEXTBOX_CHAR_ROWS * TEXTBOX_CHARS_PER_ROW)
#define TEXTBOX_BUFFER_MAX (TEXTBOX_CHARS_MAX * 3) #define TEXTBOX_BUFFER_MAX (TEXTBOX_CHARS_MAX * 3)
#define TEXTBOX_TILES_PER_ROW TEXTBOX_WIDTH_IN_TILES #define TEXTBOX_TILES_PER_ROW TEXTBOX_WIDTH_IN_TILES
#define TEXTBOX_TILES_ROWS 3 #define TEXTBOX_TILES_ROWS 3
#define TEXTBOX_TILE_BLANK COMMON_TILE_3
#define TEXTBOX_SCROLL_ROWS_MAX 14
#define TEXTBOX_SCROLL_ROWS_MAX 14
#define TEXTBOX_WIN_Y (18 - TEXTBOX_HEIGHT_IN_TILES)
#define TEXTBOX_FONT_START 33
extern char TEXTBOX_TEXTS[TEXTBOX_SCROLL_ROWS_MAX * TEXTBOX_CHARS_PER_ROW];
#define TEXTBOX_WIN_Y (18 - TEXTBOX_HEIGHT_IN_TILES) extern uint8_t TEXTBOX_ROW_COUNT;
extern uint8_t TEXTBOX_ROW_CURRENT;
extern char TEXTBOX_TEXTS[TEXTBOX_SCROLL_ROWS_MAX * TEXTBOX_CHARS_PER_ROW]; extern uint8_t TEXTBOX_STATE;
extern uint8_t TEXTBOX_ROW_COUNT; extern uint8_t TEXTBOX_SCROLL;
extern uint8_t TEXTBOX_ROW_CURRENT;
extern uint8_t TEXTBOX_STATE; inline void conversationTextboxInit();
extern uint8_t TEXTBOX_SCROLL; void conversationTextboxSetText(char *text);
inline void textboxFillBlank();
inline void conversationTextboxInit();
void conversationTextboxSetText(char *text);
inline void textboxFillBlank();
inline void conversationTextboxUpdate(); inline void conversationTextboxUpdate();

View File

@@ -1,19 +0,0 @@
/**
* Copyright (c) 2022 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "common.h"
const uint8_t COMMON_TILES[] = {
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00,
0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00,0xFF,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
};
inline void commonTilesInit() {
set_bkg_data(0x00, COMMON_TILE_COUNT, COMMON_TILES);
}

View File

@@ -1,37 +0,0 @@
/**
* Copyright (c) 2022 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "../libs.h"
#define COMMON_TILE_COUNT 0x04
#define COMMON_TILE_0 0x00
#define COMMON_TILE_1 0x01
#define COMMON_TILE_2 0x02
#define COMMON_TILE_3 0x03
// Shades are mapped where each set of 4 colors is mapped to two bits that will
// specify its darkness. Higher = Darker, Lower = Brighter
// 11 11 11 11
#define COMMON_SHADE_BLACK 0xFF
// 11 11 11 10
#define COMMON_SHADE_DARKER 0xFE
// 11 11 10 01
#define COMMON_SHADE_DARK 0xF9
// 11 10 01 00
#define COMMON_SHADE_NORMAL 0xE4
// 10 01 00 00
#define COMMON_SHADE_BRIGHT 0x90
// 01 00 00 00
#define COMMON_SHADE_BRIGHTER 0x40
// 00 00 00 00
#define COMMON_SHADE_WHITE 0x00
extern const uint8_t COMMON_TILES[];
inline void commonTilesInit();

View File

@@ -1,15 +0,0 @@
/**
* Copyright (c) 2022 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "FONT.h"
#include "BORDER.h"
// #include "SM.h"
#define FONT_DATA_POSITION 0x80
#define BORDER_DATA_POSITION FONT_DATA_POSITION+FONT_IMAGE_TILES
// #define SM_DATA_POSITION BORDER_DATA_POSITION+BORDER_IMAGE_TILES

View File

@@ -1,12 +1,12 @@
/** /**
* Copyright (c) 2022 Dominic Masters * Copyright (c) 2022 Dominic Masters
* *
* This software is released under the MIT License. * This software is released under the MIT License.
* https://opensource.org/licenses/MIT * https://opensource.org/licenses/MIT
*/ */
#include "input.h" #include "input.h"
uint8_t INPUT_STATE = 0x00; uint8_t INPUT_STATE = 0x00;
uint8_t INPUT_PRESSED = 0x00; uint8_t INPUT_PRESSED = 0x00;
uint8_t INPUT_LAST = 0x00; uint8_t INPUT_LAST = 0x00;

View File

@@ -1,13 +1,13 @@
/** /**
* Copyright (c) 2022 Dominic Masters * Copyright (c) 2022 Dominic Masters
* *
* This software is released under the MIT License. * This software is released under the MIT License.
* https://opensource.org/licenses/MIT * https://opensource.org/licenses/MIT
*/ */
#pragma once #pragma once
#include "libs.h" #include "libs.h"
extern uint8_t INPUT_STATE; extern uint8_t INPUT_STATE;
extern uint8_t INPUT_PRESSED; extern uint8_t INPUT_PRESSED;
extern uint8_t INPUT_LAST; extern uint8_t INPUT_LAST;

View File

@@ -1,15 +1,15 @@
/** /**
* Copyright (c) 2021 Dominic Masters * Copyright (c) 2021 Dominic Masters
* *
* This software is released under the MIT License. * This software is released under the MIT License.
* https://opensource.org/licenses/MIT * https://opensource.org/licenses/MIT
*/ */
#pragma once #pragma once
#include <gb/gb.h> #include <gb/gb.h>
#include <gb/bgb_emu.h> #include <gb/bgb_emu.h>
#include <stdint.h> #include <stdint.h>
#include <stdio.h> #include <stdio.h>
#include <stdbool.h> #include <stdbool.h>
#include <rand.h> #include <rand.h>
#include <string.h> #include <string.h>

View File

@@ -1,218 +1,80 @@
/** /**
* Copyright (c) 2021 Dominic Masters * Copyright (c) 2021 Dominic Masters
* *
* This software is released under the MIT License. * This software is released under the MIT License.
* https://opensource.org/licenses/MIT * https://opensource.org/licenses/MIT
*/ */
#include "main.h" #include "main.h"
inline uint8_t mainGetChar(char c) { void main() {
return c - TEXTBOX_FONT_START + FONT_DATA_POSITION; int16_t j;
} uint8_t filled[GB_BACKGROUND_COLUMNS*GB_BACKGROUND_ROWS];
inline void mainBufferCard(uint8_t card, uint8_t *tiles) { // Set up the GAMEBOY's registers.
uint8_t suit, number; disable_interrupts();
DISPLAY_OFF;
if(card >= CARD_DECK_SIZE) { LCDC_REG = LCDCF_OFF | LCDCF_BG8000 | LCDCF_BG9800 | LCDCF_BGON;
tiles[0] = mainGetChar('N');
tiles[1] = mainGetChar('A'); // Set the background color palette register
return; BGP_REG = OBP0_REG = OBP1_REG = 0xE4U;
}
// Init the random seed
suit = cardGetSuit(card); initarand(DIV_REG);
number = cardGetNumber(card);
// Init things
switch(suit) { spriteTilesetBuffer();
case CARD_SUIT_CLUBS: spriteFontBuffer();
tiles[0] = mainGetChar('C'); spriteBorderBuffer();
break; spriteCardsBuffer();
case CARD_SUIT_DIAMONDS:
tiles[0] = mainGetChar('D'); conversationTextboxInit();
break; conversationQueueInit();
case CARD_SUIT_HEARTS: pokerInit();
tiles[0] = mainGetChar('H');
break; // Fill screen white
case CARD_SUIT_SPADES: for(j = 0; j < GB_BACKGROUND_COLUMNS * GB_BACKGROUND_ROWS; j++) {
tiles[0] = mainGetChar('S'); filled[j] = SPRITE_TILESET_WHITE;
break; }
} set_bkg_tiles(0x00, 0x00, GB_BACKGROUND_COLUMNS, GB_BACKGROUND_ROWS, filled);
SCX_REG = 0x00;
switch(number) { SCY_REG = 0x00;
case CARD_TWO:
tiles[1] = mainGetChar('2'); // Card Test
break; uint8_t cardTiles[SPRITE_CARD_TILE_COUNT];
case CARD_THREE: spriteCardBufferTiles(cardTiles, CARD_HEARTS_TWO);
tiles[1] = mainGetChar('3'); set_bkg_tiles(0x00, 0x00, SPRITE_CARD_WIDTH, SPRITE_CARD_HEIGHT, cardTiles);
break;
case CARD_FOUR: // Now turn the screen on
tiles[1] = mainGetChar('4'); DISPLAY_ON;
break; enable_interrupts();
case CARD_FIVE: wait_vbl_done();
tiles[1] = mainGetChar('5');
break; // Begin game
case CARD_SIX: conversationQueueNext();
tiles[1] = mainGetChar('6');
break; // Begin the loop
case CARD_SEVEN: while(1) {
tiles[1] = mainGetChar('7'); // Perform non-graphical code updates
break; wait_vbl_done();
case CARD_EIGHT:
tiles[1] = mainGetChar('8'); // Update the input state
break; INPUT_LAST = INPUT_STATE;
case CARD_NINE: INPUT_STATE = joypad();
tiles[1] = mainGetChar('9'); INPUT_PRESSED = (~INPUT_LAST) & INPUT_STATE;
break;
case CARD_TEN: // Tick time.
tiles[1] = mainGetChar('T'); timeUpdate();
break;
case CARD_JACK: // Update conversation pause effect
tiles[1] = mainGetChar('J'); conversationPauseUpdate();
break;
case CARD_QUEEN: // Update question box and textbox
tiles[1] = mainGetChar('Q'); questionBoxUpdate();
break; conversationTextboxUpdate();
case CARD_KING:
tiles[1] = mainGetChar('K'); // Update conversation fade effect
break; conversationFadeUpdate();
case CARD_ACE: // mainDebugDraw();
tiles[1] = mainGetChar('A'); }
break;
}
}
inline void mainDebugDraw() {
uint8_t j, i, n;
// DEBUG DRAW
uint8_t tiles[15];
char buffer[6];
buffer[0] = '\0';
for(j = 0; j < POKER_PLAYER_COUNT; j++) {
n = 0;
if(j == POKER_PLAYER_BETTER) {
tiles[n++] = mainGetChar('>');
} else {
tiles[n++] = COMMON_TILE_3;
}
mainBufferCard(POKER_PLAYERS[j].hand[0], tiles+n);
n+=2;
mainBufferCard(POKER_PLAYERS[j].hand[1], tiles+n);
n+=2;
tiles[n++] = COMMON_TILE_3;
if((POKER_PLAYERS[j].state & POKER_PLAYER_STATE_FOLDED) == 0) {
tiles[n++] = COMMON_TILE_3;
} else {
tiles[n++] = mainGetChar('F');
}
if((POKER_PLAYERS[j].state & POKER_PLAYER_STATE_HAS_BET_THIS_ROUND) == 0) {
tiles[n++] = COMMON_TILE_3;
} else {
tiles[n++] = mainGetChar('H');
}
if((POKER_PLAYERS[j].state & POKER_PLAYER_STATE_OUT) == 0) {
tiles[n++] = COMMON_TILE_3;
} else {
tiles[n++] = mainGetChar('O');
}
tiles[n++] = COMMON_TILE_3;
// Print chips
sprintf(buffer, "%u", (uint16_t)POKER_PLAYERS[j].chips);
for(i = 0; i < strlen(buffer); i++) {
tiles[n++] = mainGetChar(buffer[i]);
}
while(n < 15) tiles[n++] = COMMON_TILE_3;
set_bkg_tiles(0x00, j, n - 1, 1, tiles);
}
for(j = 0; j < POKER_COMMUNITY_SIZE_MAX; j++) {
if(j >= POKER_COMMUNITY_SIZE) {
tiles[j*2] = COMMON_TILE_3;
tiles[(j*2) + 1] = COMMON_TILE_3;
} else {
mainBufferCard(POKER_COMMUNITY[j], tiles + (j * 2));
}
}
set_bkg_tiles(0x00, POKER_PLAYER_COUNT + 1, POKER_COMMUNITY_SIZE_MAX * 2, 1, tiles);
// Print Pot
n = 0;
sprintf(buffer, "%u", (uint16_t)POKER_POTS[POKER_POT_CURRENT].chips);
for(i = 0; i < strlen(buffer); i++) {
tiles[n++] = mainGetChar(buffer[i]);
}
while(n < 5) tiles[n++] = COMMON_TILE_3;
set_bkg_tiles(0x00, POKER_PLAYER_COUNT + 2, n, 1, tiles);
}
void main() {
int16_t j;
uint8_t filled[GB_BACKGROUND_COLUMNS*GB_BACKGROUND_ROWS];
// Set up the GAMEBOY's registers.
disable_interrupts();
DISPLAY_OFF;
LCDC_REG = LCDCF_OFF | LCDCF_WIN9C00 | LCDCF_BG8800 | LCDCF_BG9800 | LCDCF_BGON;
// Set the background color palette register
BGP_REG = OBP0_REG = OBP1_REG = 0xE4U;
// Init the random seed
initarand(DIV_REG);
// Init things
commonTilesInit();
conversationTextboxInit();
conversationQueueInit();
pokerInit();
// Fill screen white
for(j = 0; j < GB_BACKGROUND_COLUMNS * GB_BACKGROUND_ROWS; j++) filled[j] = COMMON_TILE_3;
set_bkg_tiles(0x00, 0x00, GB_BACKGROUND_COLUMNS, GB_BACKGROUND_ROWS, filled);
SCX_REG = 0x00;
SCY_REG = 0x00;
// Now turn the screen on
DISPLAY_ON;
enable_interrupts();
wait_vbl_done();
// Begin game
conversationQueueNext();
// Begin the loop
while(1) {
// Perform non-graphical code updates
wait_vbl_done();
// Update the input state
INPUT_LAST = INPUT_STATE;
INPUT_STATE = joypad();
INPUT_PRESSED = (~INPUT_LAST) & INPUT_STATE;
// Tick time.
timeUpdate();
// Update conversation pause effect
conversationPauseUpdate();
// Update question box and textbox
questionBoxUpdate();
conversationTextboxUpdate();
// Update conversation fade effect
conversationFadeUpdate();
mainDebugDraw();
}
} }

View File

@@ -1,28 +1,28 @@
/** /**
* Copyright (c) 2022 Dominic Masters * Copyright (c) 2022 Dominic Masters
* *
* This software is released under the MIT License. * This software is released under the MIT License.
* https://opensource.org/licenses/MIT * https://opensource.org/licenses/MIT
*/ */
#pragma once #pragma once
#include "libs.h" #include "libs.h"
#include "time.h" #include "time.h"
#include "SM.h" #include "SM.h"
#include "display/common.h" #include "poker/poker.h"
#include "display/tilemap.h" #include "poker/card.h"
#include "poker/poker.h" #include "conversation/fade.h"
#include "poker/card.h" #include "conversation/pause.h"
#include "conversation/fade.h" #include "conversation/queue.h"
#include "conversation/pause.h" #include "conversation/textbox.h"
#include "conversation/queue.h" #include "conversation/questionbox.h"
#include "conversation/textbox.h"
#include "conversation/questionbox.h" #include "sprites/spritecards.h"
#define GB_BACKGROUND_COLUMNS 0x20 #define GB_BACKGROUND_COLUMNS 0x20
#define GB_BACKGROUND_ROWS 0x20 #define GB_BACKGROUND_ROWS 0x20
void main(); void main();

View File

@@ -1,50 +1,50 @@
/** /**
* Copyright (c) 2022 Dominic Masters * Copyright (c) 2022 Dominic Masters
* *
* This software is released under the MIT License. * This software is released under the MIT License.
* https://opensource.org/licenses/MIT * https://opensource.org/licenses/MIT
*/ */
#include "card.h" #include "card.h"
inline uint8_t cardGetNumber(uint8_t card) { inline uint8_t cardGetNumber(uint8_t card) {
return card % CARD_COUNT_PER_SUIT; return card % CARD_COUNT_PER_SUIT;
} }
inline uint8_t cardGetSuit(uint8_t card) { inline uint8_t cardGetSuit(uint8_t card) {
return card / CARD_COUNT_PER_SUIT; return card / CARD_COUNT_PER_SUIT;
} }
inline uint8_t cardGet(uint8_t number, uint8_t suit) { inline uint8_t cardGet(uint8_t number, uint8_t suit) {
return (suit * CARD_COUNT_PER_SUIT) + number; return (suit * CARD_COUNT_PER_SUIT) + number;
} }
inline uint8_t cardContains(uint8_t *hand, uint8_t length, uint8_t card) { inline uint8_t cardContains(uint8_t *hand, uint8_t length, uint8_t card) {
uint8_t i; uint8_t i;
for(i = 0; i < length; i++) { for(i = 0; i < length; i++) {
if(hand[i] == card) return i; if(hand[i] == card) return i;
} }
return 0xFF; return 0xFF;
} }
inline uint8_t cardContainsNumber(uint8_t *hand,uint8_t length,uint8_t number) { inline uint8_t cardContainsNumber(uint8_t *hand,uint8_t length,uint8_t number) {
uint8_t i; uint8_t i;
for(i = 0; i < length; i++) { for(i = 0; i < length; i++) {
if(cardGetNumber(hand[i]) == number) return i; if(cardGetNumber(hand[i]) == number) return i;
} }
return 0xFF; return 0xFF;
} }
inline uint8_t cardCountPairs( inline uint8_t cardCountPairs(
uint8_t *in, uint8_t inCount, uint8_t number, uint8_t out[CARD_SUIT_COUNT] uint8_t *in, uint8_t inCount, uint8_t number, uint8_t out[CARD_SUIT_COUNT]
) { ) {
uint8_t i, count; uint8_t i, count;
count = 0; count = 0;
for(i = 0; i < inCount; i++) {// "For each suit" for(i = 0; i < inCount; i++) {// "For each suit"
if(cardGetNumber(in[i]) != number) continue; if(cardGetNumber(in[i]) != number) continue;
out[count++] = i; out[count++] = i;
} }
return count; return count;
} }

View File

@@ -1,117 +1,117 @@
/** /**
* Copyright (c) 2022 Dominic Masters * Copyright (c) 2022 Dominic Masters
* *
* This software is released under the MIT License. * This software is released under the MIT License.
* https://opensource.org/licenses/MIT * https://opensource.org/licenses/MIT
*/ */
#pragma once #pragma once
#include "../libs.h" #include "../libs.h"
#include "../util.h" #include "../util.h"
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// Cards // Cards
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// Aces // Aces
#define CARD_CLUBS_TWO 0x00 #define CARD_CLUBS_TWO 0x00
#define CARD_CLUBS_THREE 0x01 #define CARD_CLUBS_THREE 0x01
#define CARD_CLUBS_FOUR 0x02 #define CARD_CLUBS_FOUR 0x02
#define CARD_CLUBS_FIVE 0x03 #define CARD_CLUBS_FIVE 0x03
#define CARD_CLUBS_SIX 0x04 #define CARD_CLUBS_SIX 0x04
#define CARD_CLUBS_SEVEN 0x05 #define CARD_CLUBS_SEVEN 0x05
#define CARD_CLUBS_EIGHT 0x06 #define CARD_CLUBS_EIGHT 0x06
#define CARD_CLUBS_NINE 0x07 #define CARD_CLUBS_NINE 0x07
#define CARD_CLUBS_TEN 0x08 #define CARD_CLUBS_TEN 0x08
#define CARD_CLUBS_JACK 0x09 #define CARD_CLUBS_JACK 0x09
#define CARD_CLUBS_QUEEN 0x0A #define CARD_CLUBS_QUEEN 0x0A
#define CARD_CLUBS_KING 0x0B #define CARD_CLUBS_KING 0x0B
#define CARD_CLUBS_ACE 0x0C #define CARD_CLUBS_ACE 0x0C
// Diamonds // Diamonds
#define CARD_DIAMONDS_TWO 0x0D #define CARD_DIAMONDS_TWO 0x0D
#define CARD_DIAMONDS_THREE 0x0E #define CARD_DIAMONDS_THREE 0x0E
#define CARD_DIAMONDS_FOUR 0x0F #define CARD_DIAMONDS_FOUR 0x0F
#define CARD_DIAMONDS_FIVE 0x10 #define CARD_DIAMONDS_FIVE 0x10
#define CARD_DIAMONDS_SIX 0x11 #define CARD_DIAMONDS_SIX 0x11
#define CARD_DIAMONDS_SEVEN 0x12 #define CARD_DIAMONDS_SEVEN 0x12
#define CARD_DIAMONDS_EIGHT 0x13 #define CARD_DIAMONDS_EIGHT 0x13
#define CARD_DIAMONDS_NINE 0x14 #define CARD_DIAMONDS_NINE 0x14
#define CARD_DIAMONDS_TEN 0x15 #define CARD_DIAMONDS_TEN 0x15
#define CARD_DIAMONDS_JACK 0x16 #define CARD_DIAMONDS_JACK 0x16
#define CARD_DIAMONDS_QUEEN 0x17 #define CARD_DIAMONDS_QUEEN 0x17
#define CARD_DIAMONDS_KING 0x18 #define CARD_DIAMONDS_KING 0x18
#define CARD_DIAMONDS_ACE 0x19 #define CARD_DIAMONDS_ACE 0x19
// Hearts // Hearts
#define CARD_HEARTS_TWO 0x1A #define CARD_HEARTS_TWO 0x1A
#define CARD_HEARTS_THREE 0x1B #define CARD_HEARTS_THREE 0x1B
#define CARD_HEARTS_FOUR 0x1C #define CARD_HEARTS_FOUR 0x1C
#define CARD_HEARTS_FIVE 0x1D #define CARD_HEARTS_FIVE 0x1D
#define CARD_HEARTS_SIX 0x1E #define CARD_HEARTS_SIX 0x1E
#define CARD_HEARTS_SEVEN 0x1F #define CARD_HEARTS_SEVEN 0x1F
#define CARD_HEARTS_EIGHT 0x20 #define CARD_HEARTS_EIGHT 0x20
#define CARD_HEARTS_NINE 0x21 #define CARD_HEARTS_NINE 0x21
#define CARD_HEARTS_TEN 0x22 #define CARD_HEARTS_TEN 0x22
#define CARD_HEARTS_JACK 0x23 #define CARD_HEARTS_JACK 0x23
#define CARD_HEARTS_QUEEN 0x24 #define CARD_HEARTS_QUEEN 0x24
#define CARD_HEARTS_KING 0x25 #define CARD_HEARTS_KING 0x25
#define CARD_HEARTS_ACE 0x26 #define CARD_HEARTS_ACE 0x26
// Spades // Spades
#define CARD_SPADES_TWO 0x27 #define CARD_SPADES_TWO 0x27
#define CARD_SPADES_THREE 0x28 #define CARD_SPADES_THREE 0x28
#define CARD_SPADES_FOUR 0x29 #define CARD_SPADES_FOUR 0x29
#define CARD_SPADES_FIVE 0x2A #define CARD_SPADES_FIVE 0x2A
#define CARD_SPADES_SIX 0x2B #define CARD_SPADES_SIX 0x2B
#define CARD_SPADES_SEVEN 0x2C #define CARD_SPADES_SEVEN 0x2C
#define CARD_SPADES_EIGHT 0x2D #define CARD_SPADES_EIGHT 0x2D
#define CARD_SPADES_NINE 0x2E #define CARD_SPADES_NINE 0x2E
#define CARD_SPADES_TEN 0x2F #define CARD_SPADES_TEN 0x2F
#define CARD_SPADES_JACK 0x30 #define CARD_SPADES_JACK 0x30
#define CARD_SPADES_QUEEN 0x31 #define CARD_SPADES_QUEEN 0x31
#define CARD_SPADES_KING 0x32 #define CARD_SPADES_KING 0x32
#define CARD_SPADES_ACE 0x33 #define CARD_SPADES_ACE 0x33
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// Suits // Suits
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
#define CARD_SUIT_CLUBS 0x00 #define CARD_SUIT_CLUBS 0x00
#define CARD_SUIT_DIAMONDS 0x01 #define CARD_SUIT_DIAMONDS 0x01
#define CARD_SUIT_HEARTS 0x02 #define CARD_SUIT_HEARTS 0x02
#define CARD_SUIT_SPADES 0x03 #define CARD_SUIT_SPADES 0x03
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// Card numbers // Card numbers
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
#define CARD_TWO 0x00 #define CARD_TWO 0x00
#define CARD_THREE 0x01 #define CARD_THREE 0x01
#define CARD_FOUR 0x02 #define CARD_FOUR 0x02
#define CARD_FIVE 0x03 #define CARD_FIVE 0x03
#define CARD_SIX 0x04 #define CARD_SIX 0x04
#define CARD_SEVEN 0x05 #define CARD_SEVEN 0x05
#define CARD_EIGHT 0x06 #define CARD_EIGHT 0x06
#define CARD_NINE 0x07 #define CARD_NINE 0x07
#define CARD_TEN 0x08 #define CARD_TEN 0x08
#define CARD_JACK 0x09 #define CARD_JACK 0x09
#define CARD_QUEEN 0x0A #define CARD_QUEEN 0x0A
#define CARD_KING 0x0B #define CARD_KING 0x0B
#define CARD_ACE 0x0C #define CARD_ACE 0x0C
/** Count of cards in each suit */ /** Count of cards in each suit */
#define CARD_COUNT_PER_SUIT 13 #define CARD_COUNT_PER_SUIT 13
/** Count of suits */ /** Count of suits */
#define CARD_SUIT_COUNT 4 #define CARD_SUIT_COUNT 4
/** Standard Card Deck Size */ /** Standard Card Deck Size */
#define CARD_DECK_SIZE 52 #define CARD_DECK_SIZE 52
inline uint8_t cardGetNumber(uint8_t card); inline uint8_t cardGetNumber(uint8_t card);
inline uint8_t cardGetSuit(uint8_t card); inline uint8_t cardGetSuit(uint8_t card);
inline uint8_t cardGet(uint8_t card, uint8_t suit); inline uint8_t cardGet(uint8_t card, uint8_t suit);
inline uint8_t cardContains(uint8_t *hand, uint8_t length, uint8_t card); inline uint8_t cardContains(uint8_t *hand, uint8_t length, uint8_t card);
inline uint8_t cardContainsNumber(uint8_t *hand,uint8_t length,uint8_t number); inline uint8_t cardContainsNumber(uint8_t *hand,uint8_t length,uint8_t number);
inline uint8_t cardCountPairs( inline uint8_t cardCountPairs(
uint8_t *in, uint8_t inCount, uint8_t number, uint8_t out[CARD_SUIT_COUNT] uint8_t *in, uint8_t inCount, uint8_t number, uint8_t out[CARD_SUIT_COUNT]
); );

View File

@@ -1,28 +1,28 @@
/** /**
* Copyright (c) 2022 Dominic Masters * Copyright (c) 2022 Dominic Masters
* *
* This software is released under the MIT License. * This software is released under the MIT License.
* https://opensource.org/licenses/MIT * https://opensource.org/licenses/MIT
*/ */
#pragma once #pragma once
#include "../libs.h" #include "../libs.h"
#include "card.h" #include "card.h"
#define POKER_PLAYER_COUNT_MAX 5 #define POKER_PLAYER_COUNT_MAX 5
#define POKER_PLAYER_HAND_SIZE_MAX 2 #define POKER_PLAYER_HAND_SIZE_MAX 2
#define POKER_PLAYER_STATE_FOLDED (1 << 0) #define POKER_PLAYER_STATE_FOLDED (1 << 0)
#define POKER_PLAYER_STATE_OUT (1 << 1) #define POKER_PLAYER_STATE_OUT (1 << 1)
#define POKER_PLAYER_STATE_HAS_BET_THIS_ROUND (1 << 2) #define POKER_PLAYER_STATE_HAS_BET_THIS_ROUND (1 << 2)
// #define POKER_PLAYER_STATE_SHOWING 1 << 3 // #define POKER_PLAYER_STATE_SHOWING 1 << 3
typedef struct { typedef struct {
uint16_t chips; uint16_t chips;
uint8_t hand[POKER_PLAYER_HAND_SIZE_MAX]; uint8_t hand[POKER_PLAYER_HAND_SIZE_MAX];
uint8_t state; uint8_t state;
uint8_t timesRaised; uint8_t timesRaised;
} pokerplayer_t; } pokerplayer_t;
extern pokerplayer_t POKER_PLAYERS[]; extern pokerplayer_t POKER_PLAYERS[];
extern uint8_t POKER_PLAYER_COUNT; extern uint8_t POKER_PLAYER_COUNT;

File diff suppressed because it is too large Load Diff

View File

@@ -1,57 +1,57 @@
/** /**
* Copyright (c) 2022 Dominic Masters * Copyright (c) 2022 Dominic Masters
* *
* This software is released under the MIT License. * This software is released under the MIT License.
* https://opensource.org/licenses/MIT * https://opensource.org/licenses/MIT
*/ */
#pragma once #pragma once
#include "../libs.h" #include "../libs.h"
#include "../util.h" #include "../util.h"
#include "card.h" #include "card.h"
#include "player.h" #include "player.h"
#include "pot.h" #include "pot.h"
#include "turn.h" #include "turn.h"
#include "winner.h" #include "winner.h"
#define POKER_COMMUNITY_SIZE_MAX 5 #define POKER_COMMUNITY_SIZE_MAX 5
#define POKER_HUMAN_INDEX 0x00 #define POKER_HUMAN_INDEX 0x00
#define POKER_COUNT_FLOP 0x03 #define POKER_COUNT_FLOP 0x03
#define POKER_COUNT_TURN 0x01 #define POKER_COUNT_TURN 0x01
#define POKER_COUNT_RIVER 0x01 #define POKER_COUNT_RIVER 0x01
extern uint8_t POKER_DECK[]; extern uint8_t POKER_DECK[];
extern uint8_t POKER_DECK_SIZE; extern uint8_t POKER_DECK_SIZE;
extern uint8_t POKER_COMMUNITY[]; extern uint8_t POKER_COMMUNITY[];
extern uint8_t POKER_COMMUNITY_SIZE; extern uint8_t POKER_COMMUNITY_SIZE;
extern uint8_t POKER_PLAYER_DEALER; extern uint8_t POKER_PLAYER_DEALER;
extern uint8_t POKER_PLAYER_SMALL_BLIND; extern uint8_t POKER_PLAYER_SMALL_BLIND;
extern uint8_t POKER_PLAYER_BIG_BLIND; extern uint8_t POKER_PLAYER_BIG_BLIND;
extern uint8_t POKER_PLAYER_BETTER; extern uint8_t POKER_PLAYER_BETTER;
extern uint16_t POKER_GAME_BLINDS_CURRENT; extern uint16_t POKER_GAME_BLINDS_CURRENT;
void pokerInit(); void pokerInit();
void pokerNewRound(); void pokerNewRound();
inline void pokerBet(uint8_t player, uint16_t amount); inline void pokerBet(uint8_t player, uint16_t amount);
inline uint8_t pokerGetCallBet(uint8_t player); inline uint8_t pokerGetCallBet(uint8_t player);
void pokerAi(uint8_t player, pokerturn_t *turn); void pokerAi(uint8_t player, pokerturn_t *turn);
inline bool pokerCanPlayerCheck(uint8_t player); inline bool pokerCanPlayerCheck(uint8_t player);
inline bool pokerDoesPlayerNeedToBet(uint8_t playerIndex); inline bool pokerDoesPlayerNeedToBet(uint8_t playerIndex);
inline uint8_t pokerGetRemainingBetterCount(); inline uint8_t pokerGetRemainingBetterCount();
void pokerWinnerFillRemaining(pokerplayerwinning_t *winning); void pokerWinnerFillRemaining(pokerplayerwinning_t *winning);
void pokerWinnerGetForPlayer(uint8_t playerIndex,pokerplayerwinning_t *winning); void pokerWinnerGetForPlayer(uint8_t playerIndex,pokerplayerwinning_t *winning);
inline uint16_t pokerWinnerGetTypeConfidence(uint8_t type); inline uint16_t pokerWinnerGetTypeConfidence(uint8_t type);
uint8_t pokerWinnerCompare( uint8_t pokerWinnerCompare(
pokerplayerwinning_t *left, pokerplayerwinning_t *right pokerplayerwinning_t *left, pokerplayerwinning_t *right
); );
void pokerWinnerDetermineForPot( void pokerWinnerDetermineForPot(
pokerpot_t *pot, pokerpot_t *pot,
pokerplayerwinning_t *winners, pokerplayerwinning_t *winners,
uint8_t *winnerPlayers, uint8_t *winnerPlayers,
uint8_t *winnerCount, uint8_t *winnerCount,
uint8_t *participants, uint8_t *participants,
uint8_t *participantCount uint8_t *participantCount
); );

View File

@@ -1,27 +1,27 @@
/** /**
* Copyright (c) 2022 Dominic Masters * Copyright (c) 2022 Dominic Masters
* *
* This software is released under the MIT License. * This software is released under the MIT License.
* https://opensource.org/licenses/MIT * https://opensource.org/licenses/MIT
*/ */
#pragma once #pragma once
#include "../libs.h" #include "../libs.h"
#include "player.h" #include "player.h"
#define POKER_POT_COUNT_MAX POKER_PLAYER_COUNT_MAX #define POKER_POT_COUNT_MAX POKER_PLAYER_COUNT_MAX
typedef struct { typedef struct {
/** Current pot of chips */ /** Current pot of chips */
uint16_t chips; uint16_t chips;
/** Current call value for this pot */ /** Current call value for this pot */
uint16_t call; uint16_t call;
/** Players who are participating in the pots current bet (in the pot) */ /** Players who are participating in the pots current bet (in the pot) */
uint16_t players[POKER_PLAYER_COUNT_MAX]; uint16_t players[POKER_PLAYER_COUNT_MAX];
} pokerpot_t; } pokerpot_t;
extern pokerpot_t POKER_POTS[]; extern pokerpot_t POKER_POTS[];
extern uint8_t POKER_POT_CURRENT; extern uint8_t POKER_POT_CURRENT;
extern uint8_t POKER_POT_COUNT; extern uint8_t POKER_POT_COUNT;

View File

@@ -1,30 +1,30 @@
/** /**
* Copyright (c) 2022 Dominic Masters * Copyright (c) 2022 Dominic Masters
* *
* This software is released under the MIT License. * This software is released under the MIT License.
* https://opensource.org/licenses/MIT * https://opensource.org/licenses/MIT
*/ */
#pragma once #pragma once
#include "../libs.h" #include "../libs.h"
#define POKER_TURN_MAX_RAISES 0x02 #define POKER_TURN_MAX_RAISES 0x02
/** Turn Types */ /** Turn Types */
#define POKER_TURN_TYPE_OUT 0x00 #define POKER_TURN_TYPE_OUT 0x00
#define POKER_TURN_TYPE_FOLD 0x01 #define POKER_TURN_TYPE_FOLD 0x01
#define POKER_TURN_TYPE_BET 0x02 #define POKER_TURN_TYPE_BET 0x02
#define POKER_TURN_TYPE_CALL 0x03 #define POKER_TURN_TYPE_CALL 0x03
#define POKER_TURN_TYPE_ALL_IN 0x04 #define POKER_TURN_TYPE_ALL_IN 0x04
#define POKER_TURN_TYPE_CHECK 0x05 #define POKER_TURN_TYPE_CHECK 0x05
typedef struct { typedef struct {
/** What type of action the turn is */ /** What type of action the turn is */
uint8_t type; uint8_t type;
/** How many chips they did in their turn (if applicable) */ /** How many chips they did in their turn (if applicable) */
uint16_t chips; uint16_t chips;
/** How confident the AI is about their turn. 0 = none, 1000 = full */ /** How confident the AI is about their turn. 0 = none, 1000 = full */
uint16_t confidence; uint16_t confidence;
/** Is this turn a bluff? */ /** Is this turn a bluff? */
bool bluff; bool bluff;
} pokerturn_t; } pokerturn_t;

View File

@@ -1,64 +1,64 @@
/** /**
* Copyright (c) 2022 Dominic Masters * Copyright (c) 2022 Dominic Masters
* *
* This software is released under the MIT License. * This software is released under the MIT License.
* https://opensource.org/licenses/MIT * https://opensource.org/licenses/MIT
*/ */
#pragma once #pragma once
#include "../libs.h" #include "../libs.h"
#include "card.h" #include "card.h"
/** Maximum number of cards a winning state can hold. */ /** Maximum number of cards a winning state can hold. */
#define POKER_WINNING_FULL_SIZE 0x07 #define POKER_WINNING_FULL_SIZE 0x07
/** How many cards in the winning set */ /** How many cards in the winning set */
#define POKER_WINNING_SET_SIZE 0x05 #define POKER_WINNING_SET_SIZE 0x05
/** Winning Types */ /** Winning Types */
#define POKER_WINNING_TYPE_NULL 0x00 #define POKER_WINNING_TYPE_NULL 0x00
#define POKER_WINNING_TYPE_ROYAL_FLUSH 0x01 #define POKER_WINNING_TYPE_ROYAL_FLUSH 0x01
#define POKER_WINNING_TYPE_STRAIGHT_FLUSH 0x02 #define POKER_WINNING_TYPE_STRAIGHT_FLUSH 0x02
#define POKER_WINNING_TYPE_FOUR_OF_A_KIND 0x03 #define POKER_WINNING_TYPE_FOUR_OF_A_KIND 0x03
#define POKER_WINNING_TYPE_FULL_HOUSE 0x04 #define POKER_WINNING_TYPE_FULL_HOUSE 0x04
#define POKER_WINNING_TYPE_FLUSH 0x05 #define POKER_WINNING_TYPE_FLUSH 0x05
#define POKER_WINNING_TYPE_STRAIGHT 0x06 #define POKER_WINNING_TYPE_STRAIGHT 0x06
#define POKER_WINNING_TYPE_THREE_OF_A_KIND 0x07 #define POKER_WINNING_TYPE_THREE_OF_A_KIND 0x07
#define POKER_WINNING_TYPE_TWO_PAIR 0x08 #define POKER_WINNING_TYPE_TWO_PAIR 0x08
#define POKER_WINNING_TYPE_PAIR 0x09 #define POKER_WINNING_TYPE_PAIR 0x09
#define POKER_WINNING_TYPE_HIGH_CARD 0x0A #define POKER_WINNING_TYPE_HIGH_CARD 0x0A
/** Confidences of winning based on the current hand type */ /** Confidences of winning based on the current hand type */
#define POKER_WINNING_CONFIDENCE_ROYAL_FLUSH 1000 #define POKER_WINNING_CONFIDENCE_ROYAL_FLUSH 1000
#define POKER_WINNING_CONFIDENCE_STRAIGHT_FLUSH 990 #define POKER_WINNING_CONFIDENCE_STRAIGHT_FLUSH 990
#define POKER_WINNING_CONFIDENCE_FOUR_OF_A_KIND 900 #define POKER_WINNING_CONFIDENCE_FOUR_OF_A_KIND 900
#define POKER_WINNING_CONFIDENCE_FULL_HOUSE 850 #define POKER_WINNING_CONFIDENCE_FULL_HOUSE 850
#define POKER_WINNING_CONFIDENCE_FLUSH 800 #define POKER_WINNING_CONFIDENCE_FLUSH 800
#define POKER_WINNING_CONFIDENCE_STRAIGHT 700 #define POKER_WINNING_CONFIDENCE_STRAIGHT 700
#define POKER_WINNING_CONFIDENCE_THREE_OF_A_KIND 500 #define POKER_WINNING_CONFIDENCE_THREE_OF_A_KIND 500
#define POKER_WINNING_CONFIDENCE_TWO_PAIR 400 #define POKER_WINNING_CONFIDENCE_TWO_PAIR 400
#define POKER_WINNING_CONFIDENCE_PAIR 200 #define POKER_WINNING_CONFIDENCE_PAIR 200
#define POKER_WINNING_CONFIDENCE_HIGH_CARD 100 #define POKER_WINNING_CONFIDENCE_HIGH_CARD 100
/** Holds information about a player's winning state */ /** Holds information about a player's winning state */
typedef struct { typedef struct {
/** The full set of both the dealer and player's hand */ /** The full set of both the dealer and player's hand */
uint8_t full[POKER_WINNING_FULL_SIZE]; uint8_t full[POKER_WINNING_FULL_SIZE];
uint8_t fullSize; uint8_t fullSize;
/** Holds the winning set */ /** Holds the winning set */
uint8_t set[POKER_WINNING_SET_SIZE]; uint8_t set[POKER_WINNING_SET_SIZE];
uint8_t setSize; uint8_t setSize;
/** Winning Type */ /** Winning Type */
uint8_t type; uint8_t type;
/** If there was a kicker card it will be here, otherwise -1 for no kicker */ /** If there was a kicker card it will be here, otherwise -1 for no kicker */
uint8_t kicker; uint8_t kicker;
} pokerplayerwinning_t; } pokerplayerwinning_t;
extern pokerplayerwinning_t POKER_WINNERS[POKER_PLAYER_COUNT_MAX]; extern pokerplayerwinning_t POKER_WINNERS[POKER_PLAYER_COUNT_MAX];
extern uint8_t POKER_WINNER_PLAYERS[POKER_PLAYER_COUNT_MAX]; extern uint8_t POKER_WINNER_PLAYERS[POKER_PLAYER_COUNT_MAX];
extern uint8_t POKER_WINNER_PARTICIPANTS[POKER_PLAYER_COUNT_MAX]; extern uint8_t POKER_WINNER_PARTICIPANTS[POKER_PLAYER_COUNT_MAX];
extern uint8_t POKER_WINNER_COUNT; extern uint8_t POKER_WINNER_COUNT;
extern uint8_t POKER_WINNER_PARTICIPANT_COUNT; extern uint8_t POKER_WINNER_PARTICIPANT_COUNT;

View File

@@ -0,0 +1,44 @@
/**
* Copyright (c) 2022 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "spriteborder.h"
inline void spriteBorderBuffer() {
spriteBuffer(SPRITE_BORDER_VRAM_START, BORDER_IMAGE_TILES, BORDER_IMAGE);
}
inline void spriteBorderBufferEdges(
uint8_t *buffer, uint8_t bufferWidth, uint8_t bufferHeight, uint8_t fill
) {
uint8_t i, j, max;
max = bufferWidth * bufferHeight;
// Corners
buffer[0] = SPRITE_BORDER_VRAM_START + SPRITE_BORDER_TOP_LEFT;
buffer[bufferWidth-1] = SPRITE_BORDER_VRAM_START + SPRITE_BORDER_TOP_RIGHT;
buffer[max-1] = SPRITE_BORDER_VRAM_START + SPRITE_BORDER_BOTTOM_RIGHT;
buffer[max-bufferWidth] = SPRITE_BORDER_VRAM_START + SPRITE_BORDER_BOTTOM_LEFT;
// Edges
for(i = 1; i < bufferWidth-1; i++) {
buffer[i] = SPRITE_BORDER_VRAM_START + SPRITE_BORDER_BOTTOM_TOP;
buffer[max - 1 - i] = SPRITE_BORDER_VRAM_START + SPRITE_BORDER_BOTTOM_TOP;
}
for(i = 1; i < bufferHeight - 1; i++) {
buffer[bufferWidth * i] = SPRITE_BORDER_VRAM_START + SPRITE_BORDER_LEFT_RIGHT;
buffer[bufferWidth * (i+1) - 1] = SPRITE_BORDER_VRAM_START + SPRITE_BORDER_LEFT_RIGHT;
}
// Inner
if(fill != 0xFF) {
for(j = 1; j < bufferHeight-1; j++) {
for(i = 1; i < bufferWidth-1; i++) {
buffer[i + (j * bufferWidth)] = fill;
}
}
}
}

View File

@@ -0,0 +1,39 @@
/**
* Copyright (c) 2022 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "../libs.h"
#include "sprites.h"
#include "BORDER.h"
#include "spritefont.h"
#define SPRITE_BORDER_VRAM_START SPRITE_FONT_VRAM_END
#define SPRITE_BORDER_VRAM_END SPRITE_BORDER_VRAM_START + BORDER_IMAGE_TILES
#define SPRITE_BORDER_TOP_LEFT 0x00
#define SPRITE_BORDER_TOP_RIGHT 0x01
#define SPRITE_BORDER_LEFT_RIGHT 0x02
#define SPRITE_BORDER_BOTTOM_LEFT 0x03
#define SPRITE_BORDER_BOTTOM_RIGHT 0x04
#define SPRITE_BORDER_BOTTOM_TOP 0x05
/**
* Buffer the border sprite into VRAM.
*/
inline void spriteBorderBuffer();
/**
* Buffer the edges of a border to a tile buffer.
*
* @param buffer Buffer to write the tiles in to.
* @param bufferWidth Width of the buffer that you want to write.
* @param bufferHeight Height of the buffer that you want to write.
* @param fill NULL for no fill, otherwise TILE INDEX of fill within border.
*/
inline void spriteBorderBufferEdges(
uint8_t *buffer, uint8_t bufferWidth, uint8_t bufferHeight, uint8_t fill
);

38
src/sprites/spritecards.c Normal file
View File

@@ -0,0 +1,38 @@
/**
* Copyright (c) 2022 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "spritecards.h"
const uint8_t SPRITE_HEARTS_ACE[SPRITE_CARD_TILE_COUNT] = {
SPRITE_CARD_ACE_TOP, SPRITE_CARD_TOP, SPRITE_CARD_TOP, SPRITE_CARD_TOP_RIGHT,
SPRITE_CARD_LEFT, SPRITE_CARD_BLANK, SPRITE_CARD_BLANK, SPRITE_CARD_RIGHT,
SPRITE_CARD_LEFT, SPRITE_CARD_HEART_BIG_TOP_LEFT, SPRITE_CARD_HEART_BIG_TOP_RIGHT, SPRITE_CARD_RIGHT,
SPRITE_CARD_LEFT, SPRITE_CARD_HEART_BIG_BOTTOM_LEFT, SPRITE_CARD_HEART_BIG_BOTTOM_RIGHT, SPRITE_CARD_RIGHT,
SPRITE_CARD_LEFT, SPRITE_CARD_BLANK, SPRITE_CARD_BLANK, SPRITE_CARD_RIGHT,
SPRITE_CARD_BOTTOM_LEFT, SPRITE_CARD_BOTTOM, SPRITE_CARD_BOTTOM, SPRITE_CARD_BOTTOM_RIGHT
};
// const uint8_t *SPRITE_CARD_LIST[] = {
// SPRITE_HEARTS_ACE
// };
inline void spriteCardsBuffer() {
spriteBuffer(SPRITE_CARD_VRAM_START, CARDS_TILES_IMAGE_TILES, CARDS_TILES_IMAGE);
}
inline uint8_t * spriteCardsForCard(uint8_t card) {
return SPRITE_HEARTS_ACE;
}
inline void spriteCardBufferTiles(uint8_t *buffer, uint8_t card) {
uint8_t i;
uint8_t *spriteTiles = spriteCardsForCard(card);
while(i != SPRITE_CARD_TILE_COUNT) {
buffer[i] = spriteTiles[i];
i++;
}
}

68
src/sprites/spritecards.h Normal file
View File

@@ -0,0 +1,68 @@
/**
* Copyright (c) 2022 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "../libs.h"
#include "CARDS_TILES.h"
#include "../poker/card.h"
#include "spritetileset.h"
#include "sprites.h"
#include "spriteborder.h"
#define SPRITE_CARD_VRAM_START SPRITE_BORDER_VRAM_END
#define SPRITE_CARD_BLANK SPRITE_TILESET_WHITE
#define SPRITE_CARD_ACE_TOP SPRITE_CARD_VRAM_START + 0
#define SPRITE_CARD_ACE_BOTTOM SPRITE_CARD_ACE_TOP/* ref */
#define SPRITE_CARD_TWO_TOP SPRITE_CARD_VRAM_START + 1
#define SPRITE_CARD_TWO_BOTTOM SPRITE_CARD_TWO_TOP/* ref */
#define SPRITE_CARD_THREE_TOP SPRITE_CARD_VRAM_START + 2
#define SPRITE_CARD_THREE_BOTTOM SPRITE_CARD_THREE_TOP/* ref */
#define SPRITE_CARD_FOUR_TOP SPRITE_CARD_VRAM_START + 3
#define SPRITE_CARD_FOUR_BOTTOM SPRITE_CARD_THREE_TOP/* ref */
#define SPRITE_CARD_FIVE_TOP SPRITE_CARD_VRAM_START + 4
#define SPRITE_CARD_FIVE_BOTTOM SPRITE_CARD_FIVE_TOP/* ref */
#define SPRITE_CARD_SIX_TOP SPRITE_CARD_VRAM_START + 5
#define SPRITE_CARD_SIX_BOTTOM SPRITE_CARD_SIX_TOP/* ref */
#define SPRITE_CARD_SEVEN_TOP SPRITE_CARD_VRAM_START + 6
#define SPRITE_CARD_SEVEN_BOTTOM SPRITE_CARD_SEVEN_TOP/* ref */
#define SPRITE_CARD_EIGHT_TOP SPRITE_CARD_VRAM_START + 7
#define SPRITE_CARD_EIGHT_BOTTOM SPRITE_CARD_EIGHT_TOP/* ref */
#define SPRITE_CARD_NINE_TOP SPRITE_CARD_VRAM_START + 8
#define SPRITE_CARD_NINE_BOTTOM SPRITE_CARD_NINE_TOP/* ref */
#define SPRITE_CARD_TEN_TOP SPRITE_CARD_VRAM_START + 9
#define SPRITE_CARD_TEN_BOTTOM/* ref */
#define SPRITE_CARD_TOP SPRITE_CARD_VRAM_START + 11
#define SPRITE_CARD_TOP_RIGHT SPRITE_CARD_VRAM_START + 10
#define SPRITE_CARD_LEFT SPRITE_CARD_TOP/* ref */
#define SPRITE_CARD_RIGHT SPRITE_CARD_TOP/* ref */
#define SPRITE_CARD_BOTTOM_LEFT SPRITE_CARD_TOP_RIGHT/* ref */
#define SPRITE_CARD_BOTTOM_RIGHT SPRITE_CARD_TOP_RIGHT/* ref */
#define SPRITE_CARD_BOTTOM SPRITE_CARD_TOP/* ref */
#define SPRITE_CARD_DIAMOND_BIG_TOP_LEFT SPRITE_CARD_VRAM_START + 12
#define SPRITE_CARD_DIAMOND_BIG_TOP_RIGHT SPRITE_CARD_DIAMOND_BIG_TOP_LEFT/* ref */
#define SPRITE_CARD_DIAMOND_BIG_BOTTOM_LEFT SPRITE_CARD_DIAMOND_BIG_TOP_LEFT/* ref */
#define SPRITE_CARD_DIAMOND_BIG_BOTTOM_RIGHT SPRITE_CARD_DIAMOND_BIG_TOP_LEFT/* ref */
#define SPRITE_CARD_HEART_BIG_TOP_LEFT SPRITE_CARD_VRAM_START + 13
#define SPRITE_CARD_HEART_BIG_TOP_RIGHT SPRITE_CARD_HEART_BIG_TOP_LEFT/* ref */
#define SPRITE_CARD_HEART_BIG_BOTTOM_LEFT SPRITE_CARD_DIAMOND_BIG_BOTTOM_LEFT
#define SPRITE_CARD_HEART_BIG_BOTTOM_RIGHT SPRITE_CARD_DIAMOND_BIG_BOTTOM_RIGHT
#define SPRITE_CARD_WIDTH 4
#define SPRITE_CARD_HEIGHT 6
#define SPRITE_CARD_TILE_COUNT (SPRITE_CARD_WIDTH * SPRITE_CARD_HEIGHT)
extern const uint8_t SPRITE_HEARTS_ACE[];
inline void spriteCardsBuffer();
inline uint8_t * spriteCardsForCard(uint8_t card);
inline void spriteCardBufferTiles(uint8_t *buffer, uint8_t card);

16
src/sprites/spritefont.c Normal file
View File

@@ -0,0 +1,16 @@
/**
* Copyright (c) 2022 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "spritefont.h"
inline void spriteFontBuffer() {
spriteBuffer(SPRITE_FONT_VRAM_START, FONT_IMAGE_TILES, FONT_IMAGE);
}
inline uint8_t spriteFontTileFromChar(char character) {
return character - SPRITE_FONT_FIRST_CHARACTER + SPRITE_FONT_VRAM_START;
}

30
src/sprites/spritefont.h Normal file
View File

@@ -0,0 +1,30 @@
/**
* Copyright (c) 2022 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "../libs.h"
#include "FONT.h"
#include "sprites.h"
#include "spritetileset.h"
#define SPRITE_FONT_FIRST_CHARACTER 33
#define SPRITE_FONT_VRAM_START SPRITE_TILESET_VRAM_END
#define SPRITE_FONT_VRAM_END SPRITE_FONT_VRAM_START + FONT_IMAGE_TILES
/**
* Buffer the font tiles to VRAM.
*/
inline void spriteFontBuffer();
/**
* Get the tile index for a given character (ASCII).
*
* @param character Character to get the tile index from.
* @return The tile index for the given character.
*/
inline uint8_t spriteFontTileFromChar(char character);

12
src/sprites/sprites.c Normal file
View File

@@ -0,0 +1,12 @@
/**
* Copyright (c) 2022 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "sprites.h"
inline void spriteBuffer(uint8_t position, uint8_t length, uint8_t *tiles) {
set_bkg_data(position, length, tiles);
}

18
src/sprites/sprites.h Normal file
View File

@@ -0,0 +1,18 @@
/**
* Copyright (c) 2022 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "../libs.h"
/**
* Buffer tiles data into VRAM
*
* @param position Position in VRAM to buffer in to.
* @param length Length of the data being buffered (count of tiles).
* @param tiles Pointer to array of tiles to be bufffered.
*/
inline void spriteBuffer(uint8_t position, uint8_t length, uint8_t *tiles);

View File

@@ -0,0 +1,12 @@
/**
* Copyright (c) 2022 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "spritetileset.h"
void spriteTilesetBuffer() {
spriteBuffer(SPRITE_TILESET_VRAM_START, TILESET_IMAGE_TILES, TILESET_IMAGE);
}

View File

@@ -0,0 +1,50 @@
/**
* Copyright (c) 2022 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "../libs.h"
#include "TILESET.h"
#include "sprites.h"
#define SPRITE_TILESET_VRAM_START 0x00
#define SPRITE_TILESET_VRAM_END SPRITE_TILESET_VRAM_START + TILESET_IMAGE_TILES
#define SPRITE_TILESET_TILE_0 SPRITE_TILESET_VRAM_START + 0x00
#define SPRITE_TILESET_TILE_1 SPRITE_TILESET_VRAM_START + 0x01
#define SPRITE_TILESET_TILE_2 SPRITE_TILESET_VRAM_START + 0x02
#define SPRITE_TILESET_TILE_3 SPRITE_TILESET_VRAM_START + 0x03
#define SPRITE_TILESET_WHITE SPRITE_TILESET_TILE_0
#define SPRITE_TILESET_BLACK SPRITE_TILESET_TILE_3
#define SPRITE_TILESET_LIGHT SPRITE_TILESET_TILE_1
#define SPRITE_TILESET_DARK SPRITE_TILESET_TILE_2
// Shades are mapped where each set of 4 colors is mapped to two bits that will
// specify its darkness. Higher = Darker, Lower = Brighter
// 11 11 11 11
#define TILESET_SHADE_BLACK 0xFF
// 11 11 11 10
#define TILESET_SHADE_DARKER 0xFE
// 11 11 10 01
#define TILESET_SHADE_DARK 0xF9
// 11 10 01 00
#define TILESET_SHADE_NORMAL 0xE4
// 10 01 00 00
#define TILESET_SHADE_BRIGHT 0x90
// 01 00 00 00
#define TILESET_SHADE_BRIGHTER 0x40
// 00 00 00 00
#define TILESET_SHADE_WHITE 0x00
/**
* Buffer the TILESET tileset sprites onto VRAM.
*
* @param position Position in VRAM to buuffer on to.
*/
void spriteTilesetBuffer();

View File

@@ -1,33 +1,33 @@
/** /**
* Copyright (c) 2022 Dominic Masters * Copyright (c) 2022 Dominic Masters
* *
* This software is released under the MIT License. * This software is released under the MIT License.
* https://opensource.org/licenses/MIT * https://opensource.org/licenses/MIT
*/ */
#include "strings.h" #include "strings.h"
const char STR_ERROR[] = "An error\nhas occured"; const char STR_ERROR[] = "An error\nhas occured";
const char STR_HELLO[] = "Hello World, How are you today?\nGood thanks. Thank god!"; const char STR_HELLO[] = "Hello World, How are you today?\nGood thanks. Thank god!";
const char STR_POKER_GAME_START[] = "Poker game started"; const char STR_POKER_GAME_START[] = "Poker game started";
const char STR_POKER_GAME_TAKING_BLINDS[] = "Blinds taken."; const char STR_POKER_GAME_TAKING_BLINDS[] = "Blinds taken.";
const char STR_POKER_GAME_CARDS_DEALT[] = "Cards dealt."; const char STR_POKER_GAME_CARDS_DEALT[] = "Cards dealt.";
const char STR_POKER_GAME_CARDS_FLOPPED[] = "Cards flopped"; const char STR_POKER_GAME_CARDS_FLOPPED[] = "Cards flopped";
const char STR_POKER_GAME_CARDS_TURNED[] = "Cards turned"; const char STR_POKER_GAME_CARDS_TURNED[] = "Cards turned";
const char STR_POKER_GAME_CARDS_RIVERED[] = "Cards river"; const char STR_POKER_GAME_CARDS_RIVERED[] = "Cards river";
const char STR_DEBUG_WINNER_DECIDED[] = "DEBUG WINNER"; const char STR_DEBUG_WINNER_DECIDED[] = "DEBUG WINNER";
const char STR_DEBUG_PLAYER[] = "DEBUG PLAYER"; const char STR_DEBUG_PLAYER[] = "DEBUG PLAYER";
const char STR_POKER_GAME_AI_FOLD[] = "AI Folding"; const char STR_POKER_GAME_AI_FOLD[] = "AI Folding";
const char STR_POKER_GAME_AI_RAISE[] = "AI Raise"; const char STR_POKER_GAME_AI_RAISE[] = "AI Raise";
const char STR_POKER_GAME_AI_RAISE_BLUFF[] = "AI Raise\nBut Bluffing"; const char STR_POKER_GAME_AI_RAISE_BLUFF[] = "AI Raise\nBut Bluffing";
const char STR_POKER_GAME_AI_CALL[] = "AI Calling"; const char STR_POKER_GAME_AI_CALL[] = "AI Calling";
const char STR_POKER_GAME_AI_CALL_BLUFF[] = "AI Calling\nBut Bluffing"; const char STR_POKER_GAME_AI_CALL_BLUFF[] = "AI Calling\nBut Bluffing";
const char STR_POKER_GAME_AI_ALL_IN[] = "AI All In"; const char STR_POKER_GAME_AI_ALL_IN[] = "AI All In";
const char STR_POKER_GAME_AI_ALL_IN_BLUFF[] = "AI All In\nBut Bluffing"; const char STR_POKER_GAME_AI_ALL_IN_BLUFF[] = "AI All In\nBut Bluffing";
const char STR_POKER_GAME_AI_CHECK[] = "AI Checking"; const char STR_POKER_GAME_AI_CHECK[] = "AI Checking";
const char STR_POKER_GAME_AI_CHECK_BLUFF[] = "AI Checking\nBut Bluffing"; const char STR_POKER_GAME_AI_CHECK_BLUFF[] = "AI Checking\nBut Bluffing";
const char STR_FOX[] = "The quick brown fox jumps over the lazy dog."; const char STR_FOX[] = "The quick brown fox jumps over the lazy dog.";

View File

@@ -1,34 +1,34 @@
/** /**
* Copyright (c) 2022 Dominic Masters * Copyright (c) 2022 Dominic Masters
* *
* This software is released under the MIT License. * This software is released under the MIT License.
* https://opensource.org/licenses/MIT * https://opensource.org/licenses/MIT
*/ */
#pragma once #pragma once
#include "libs.h" #include "libs.h"
extern const char STR_ERROR[]; extern const char STR_ERROR[];
extern const char STR_HELLO[]; extern const char STR_HELLO[];
extern const char STR_POKER_GAME_START[]; extern const char STR_POKER_GAME_START[];
extern const char STR_POKER_GAME_TAKING_BLINDS[]; extern const char STR_POKER_GAME_TAKING_BLINDS[];
extern const char STR_POKER_GAME_CARDS_DEALT[]; extern const char STR_POKER_GAME_CARDS_DEALT[];
extern const char STR_POKER_GAME_CARDS_FLOPPED[]; extern const char STR_POKER_GAME_CARDS_FLOPPED[];
extern const char STR_POKER_GAME_CARDS_TURNED[]; extern const char STR_POKER_GAME_CARDS_TURNED[];
extern const char STR_POKER_GAME_CARDS_RIVERED[]; extern const char STR_POKER_GAME_CARDS_RIVERED[];
extern const char STR_DEBUG_WINNER_DECIDED[]; extern const char STR_DEBUG_WINNER_DECIDED[];
extern const char STR_DEBUG_PLAYER[]; extern const char STR_DEBUG_PLAYER[];
extern const char STR_POKER_GAME_AI_FOLD[]; extern const char STR_POKER_GAME_AI_FOLD[];
extern const char STR_POKER_GAME_AI_RAISE[]; extern const char STR_POKER_GAME_AI_RAISE[];
extern const char STR_POKER_GAME_AI_RAISE_BLUFF[]; extern const char STR_POKER_GAME_AI_RAISE_BLUFF[];
extern const char STR_POKER_GAME_AI_CALL[]; extern const char STR_POKER_GAME_AI_CALL[];
extern const char STR_POKER_GAME_AI_CALL_BLUFF[]; extern const char STR_POKER_GAME_AI_CALL_BLUFF[];
extern const char STR_POKER_GAME_AI_ALL_IN[]; extern const char STR_POKER_GAME_AI_ALL_IN[];
extern const char STR_POKER_GAME_AI_ALL_IN_BLUFF[]; extern const char STR_POKER_GAME_AI_ALL_IN_BLUFF[];
extern const char STR_POKER_GAME_AI_CHECK[]; extern const char STR_POKER_GAME_AI_CHECK[];
extern const char STR_POKER_GAME_AI_CHECK_BLUFF[]; extern const char STR_POKER_GAME_AI_CHECK_BLUFF[];
extern const char STR_FOX[]; extern const char STR_FOX[];

View File

@@ -1,22 +1,22 @@
/** /**
* Copyright (c) 2022 Dominic Masters * Copyright (c) 2022 Dominic Masters
* *
* This software is released under the MIT License. * This software is released under the MIT License.
* https://opensource.org/licenses/MIT * https://opensource.org/licenses/MIT
*/ */
#include "time.h" #include "time.h"
uint16_t TIME_CURRENT; uint16_t TIME_CURRENT;
uint16_t TIME_FUTURE; uint16_t TIME_FUTURE;
uint8_t TIME_FUTURE_TYPE; uint8_t TIME_FUTURE_TYPE;
inline void timeInit() { inline void timeInit() {
TIME_CURRENT = 0; TIME_CURRENT = 0;
TIME_FUTURE = 0; TIME_FUTURE = 0;
TIME_FUTURE_TYPE = TIME_FUTURE_TYPE_NULL; TIME_FUTURE_TYPE = TIME_FUTURE_TYPE_NULL;
} }
inline void timeUpdate() { inline void timeUpdate() {
TIME_CURRENT++; TIME_CURRENT++;
} }

View File

@@ -1,25 +1,25 @@
/** /**
* Copyright (c) 2022 Dominic Masters * Copyright (c) 2022 Dominic Masters
* *
* This software is released under the MIT License. * This software is released under the MIT License.
* https://opensource.org/licenses/MIT * https://opensource.org/licenses/MIT
*/ */
#pragma once #pragma once
#include "libs.h" #include "libs.h"
#define TIME_PER_SECOND 60 #define TIME_PER_SECOND 60
#define TIME_FUTURE_TYPE_NULL 0x00 #define TIME_FUTURE_TYPE_NULL 0x00
#define TIME_FUTURE_TYPE_PAUSE 0x01 #define TIME_FUTURE_TYPE_PAUSE 0x01
#define TIME_FUTURE_TYPE_FADE_TO_BLACK 0x02 #define TIME_FUTURE_TYPE_FADE_TO_BLACK 0x02
#define TIME_FUTURE_TYPE_FADE_FROM_BLACK 0x03 #define TIME_FUTURE_TYPE_FADE_FROM_BLACK 0x03
#define TIME_FUTURE_TYPE_FADE_TO_WHITE 0x04 #define TIME_FUTURE_TYPE_FADE_TO_WHITE 0x04
#define TIME_FUTURE_TYPE_FADE_FROM_WHITE 0x05 #define TIME_FUTURE_TYPE_FADE_FROM_WHITE 0x05
extern uint16_t TIME_CURRENT; extern uint16_t TIME_CURRENT;
extern uint16_t TIME_FUTURE; extern uint16_t TIME_FUTURE;
extern uint8_t TIME_FUTURE_TYPE; extern uint8_t TIME_FUTURE_TYPE;
inline void timeInit(); inline void timeInit();
inline void timeUpdate(); inline void timeUpdate();

View File

@@ -1,13 +1,13 @@
/** /**
* Copyright (c) 2022 Dominic Masters * Copyright (c) 2022 Dominic Masters
* *
* This software is released under the MIT License. * This software is released under the MIT License.
* https://opensource.org/licenses/MIT * https://opensource.org/licenses/MIT
*/ */
#pragma once #pragma once
#include "libs.h" #include "libs.h"
#define MATH_MIN(a, b) a > b ? b : a #define MATH_MIN(a, b) a > b ? b : a
#define MATH_MAX(a, b) a < b ? b : a #define MATH_MAX(a, b) a < b ? b : a
#define MATH_ABS(n) (n < 0 ? -n : n) #define MATH_ABS(n) (n < 0 ? -n : n)

14
test.sh
View File

@@ -1,8 +1,8 @@
#!/bin/bash #!/bin/bash
# Send over latest build # Send over latest build
scp ./build/Penny.gb root@ywbud3:/storage/roms/gb/Penny.gb scp ./build/Penny.gb root@ywbud3:/storage/roms/gb/Penny.gb
systemctl stop emustation.service systemctl stop emustation.service
killall emulationstation killall emulationstation
retroarch -L /lib/libretro/gambatte_libretro.so "/storage/roms/gb/Penny.gb" retroarch -L /lib/libretro/gambatte_libretro.so "/storage/roms/gb/Penny.gb"
systemctl start emustation.service systemctl start emustation.service