initial commit

This commit is contained in:
'mr software' 2022-03-18 20:14:58 -07:00
commit 7cf2127956
4 changed files with 440 additions and 0 deletions

30
README.md Normal file
View File

@ -0,0 +1,30 @@
# alchemy banal
like alchemy deluxe. but like not deluxe
## why
good game go buy it. or dont
## me want build it
```
paru -S libpulse wget libxmp # if you dont like it just patch it out or something idk
./mcb all # i know the script sucks dont kill me
```
## i am going to steal your code
okay it is public domain. pretend i put the unlicense here
## i stole your code and it fucking sucks
i know that. i wrote it
## im from ea and i want to sue you
stop that
## i have other questions
i didnt think of your questions yet

26
fembgen.c Normal file
View File

@ -0,0 +1,26 @@
#include <stdint.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
int main(int argc, char** argv) {
if(argc != 4) return !!printf("need 1 file to generate embed for, size name, and data name\n");
int fd = open(argv[1], O_RDONLY, 0644);
if(fd < 0) return 1;
struct stat s;
fstat(fd, &s);
printf(
"#include <stdint.h>\n"
"#define %s ((unsigned long)%llu)\n"
"uint8_t %s[%s]={",
argv[3],
s.st_size,
argv[2],
argv[3]
);
uint8_t mem[s.st_size];
read(fd, mem, s.st_size);
for(unsigned long l = 0; l < s.st_size; l++) printf("%hu,", (uint16_t)mem[l]);
puts("};");
}

349
main.c Normal file
View File

@ -0,0 +1,349 @@
#include <stdio.h>
#include <fcntl.h>
#include <stdint.h>
#include <stdlib.h>
#include <xmp.h>
#include <sys/ioctl.h>
#include <termios.h>
#include <signal.h>
#include <string.h>
#include <time.h>
#include <pulse/simple.h>
#include <pulse/error.h>
#include <unistd.h>
#include <errno.h>
// defines void* module and long modsize
#include "music.h"
char* hdr = "ALCHEMY [press A for info]\n-----------------+ CURRENT\n";
/* RUNE BITFIELD
*
* RRRRFFFB (very conveniently only 1 byte)
*
* R - rune type. theres probably not 16 but eh
* F - foreground color. there are at least 5
* B - theres only 2 so only 1 bit is needed
*
*/
char* runes = " &*oImu%/avjyt^@>";
#define getbg(B) ((B) & 1)
#define getfg(B) (((B) >> 1) & 7)
#define getrune(B) ((B) >> 4)
uint8_t newrune() {
uint8_t r = ((rand() & 0xFF) | 1);
if(!getrune(r) || !getfg(r)) r = newrune();
if(getrune(r) == 2 || getrune(r) == 1) r = (r & 0xF0) | 0xF;
else if(getfg(r) == 7) r = newrune();
return r;
}
uint8_t board[72];
struct winsize win;
struct termios term, term_b;
void clrscr() {
// VERY good practice. will never cause bugs
printf("\x1B\x5B\x48\x1B\x5B\x4A");
}
int closef = 0;
void winch(int sig) {
ioctl(1, TIOCGWINSZ, &win);
if(win.ws_col < 27 || win.ws_row < 10) {
tcsetattr(0, TCSANOW, &term_b);
printf("window too small, exiting\n");
closef = 1;
}
}
void posupdate(int x, int y) {
printf("\033[%d;%dH", ++y, ++x);
}
void render_board(uint8_t* brd, int score, int level, int rune, int stage, int valid) {
uint8_t* m = brd;
for(int i = 0; i < 8; i++) {
for(int c = 0; c < 9; c++) {
printf(
"\033[0;9%im", getfg(m[c]));
printf("\033[0;%i%im", getbg(m[c]) ? 9 : 10, getbg(m[c]) ? getfg(m[c]) : 7);
printf(
"%c%s", runes[getrune(m[c])],
(c == 8) ? "\033[0m|" : " "
);
if(c == 8) {
//if(i == 0) printf(" :%c %c", valid + '(', runes[rune]);
if(i == 0) printf(" :%c \033[0;9%im%c\033[0m", valid + '(', getfg(rune), runes[getrune(rune)]);
if(i == 2) printf(" SCORE");
if(i == 3) printf(" %07i", score);
if(i == 5) {
printf(" [");
for(int v = 0; v < level; v++) putchar('#');
for(int v = 0; v < 3 - level; v++) putchar('-');
putchar(']');
}
if(i == 6) printf(" STAGE");
if(i == 7) printf(" %02i", stage);
putchar('\n');
}
}
m += 9;
}
}
int linecheck(uint8_t* board, int x, int y) {
int w = 1, h = 1;
for(int i = 0; i < 9; i++) if(!getrune(board[(y*9) + i])) w = 0;
for(int i = 0; i < 8; i++) if(!getrune(board[(i*9) + x])) h = 0;
if(w) for(int i = 0; i < 9; i++) board[(y*9) + i] = 0x0F;
if(h) for(int i = 0; i < 8; i++) board[(i*9) + x] = 0x0F;
return w | h;
}
int movecheck(uint8_t* board, int x, int y, uint8_t rune) {
if(getrune(rune) == 1) if(getrune(board[(y*9) + x])) return 1;
if(getrune(board[(y*9) + x])) return 0;
int l = x ? board[(y*9) + (x - 1)] : 0x0F,
r = (x < 8) ? board[(y*9) + (x + 1)] : 0x0F,
u = y ? board[((y-1)*9) + x] : 0x0F,
d = (y < 7) ? board[((y+1)*9) + x] : 0x0F;
if(getrune(rune) == 2) return !!getrune(l|r|u|d);
int rnc = getfg(rune);
int rnt = getrune(rune);
int lc = getfg(l) == rnc,
rc = getfg(r) == rnc,
uc = getfg(u) == rnc,
dc = getfg(d) == rnc;
int lt = getrune(l) == rnt,
rt = getrune(r) == rnt,
ut = getrune(u) == rnt,
dt = getrune(d) == rnt;
if(l == 0x2F) lt++;
if(r == 0x2F) rt++;
if(u == 0x2F) ut++;
if(d == 0x2F) dt++;
int ac = 0;
if(!getrune(l)) { lt++; ac++; }
if(!getrune(r)) { rt++; ac++; }
if(!getrune(u)) { ut++; ac++; }
if(!getrune(d)) { dt++; ac++; }
if(ac == 4) return 0;
int ms = 4;
if(lc || lt) ms--;
if(rc || rt) ms--;
if(uc || ut) ms--;
if(dc || dt) ms--;
return !ms;
}
int musplay = 1;
void fsig(int sig) {
if(sig == SIGUSR1) musplay ^= 1;
else closef = 1;
}
int main(int argc, char** argv) {
// we can just call the signal
// that is because c is the best
// make sure window is big enough
winch(0);
pa_simple *s;
pa_sample_spec ss;
ss.format = PA_SAMPLE_S16NE;
ss.channels = 2;
ss.rate = 44100;
int err;
long id = getpid();
long p = fork();
if(!p) {
uint8_t aubuf[44100];
xmp_context xc = xmp_create_context();
xmp_load_module_from_memory(xc, module, modsize);
xmp_start_player(xc, 44100, 0);
s = pa_simple_new(NULL, "alchemy-banal", PA_STREAM_PLAYBACK, NULL, "the game on earth", &ss, NULL, NULL, NULL);
signal(SIGINT, fsig);
signal(SIGUSR1, fsig);
while(1) {
if(closef || kill(id, 0) == ESRCH) {
pa_simple_free(s);
xmp_release_module(xc);
xmp_free_context(xc);
return 0;
} else if(musplay) {
xmp_play_buffer(xc, aubuf, 44100, 0);
pa_simple_write(s, aubuf, 44100, &err);
}
}
}
// init boardmem
memset(board, 0xE, 72);
board[31] = 0x2F;
// rng for runes
srand(time(NULL));
// trap window change. other
// signals not necessary since
// setting term attributes lets
// us trap things like ^C
signal(SIGWINCH, winch);
// terminal config (capture all input)
tcgetattr(0, &term);
term_b = term;
term.c_iflag &= ~(ICRNL|IXON);
term.c_lflag &= ~(ICANON|ECHO|ISIG|IEXTEN);
tcsetattr(0, TCSANOW, &term);
setbuf(stdout, NULL);
fcntl(0, F_SETFL, O_NONBLOCK);
// game init complete
// begin actual game loop
clrscr();
unsigned char // peak formatting
c, // current input
y = 0, // current cursor x
x = 0, // current cursor y
v = 1, // move validity
stage = 1, // stage
level = 0, // current goop(?) level
r = newrune(), // current rune
mode = 0; // current mode
unsigned int score = 0, aframe = 0, vr = 0;
printf(hdr);
render_board(board, 20, 0, r, 1, 1);
goto eloop;
while(1) {
if(closef) goto cleanup;
if((c = getchar()) != 255) {
eloop:
if(mode != 1) switch(c) {
case ' ':
// place rune
if(!getrune(board[(y*9) + x]) && (getrune(r) > 2)) {
// TODO movecheck
if(movecheck(board, x, y, r)) board[(y*9) + x] = r;
else goto nrr;
} else if((getrune(r) == 2) && !getrune(board[(y*9) + x])) {
board[(y*9) + x] = r;
} else if((getrune(r) == 1) && getrune(board[(y*9) + x])) {
board[(y*9) + x] = 0xF;
}
else goto nrr;
rr:
vr = 1;
for(int z = 0; z < 72; z++) if(!getbg(board[z])) vr = 0;
if(vr) {
stage++;
memset(board, 0xE, 72);
board[31 + (((rand() & 1) ? -1 : 1) * (rand() & 0x7))] = 0x2F;
}
r = newrune();
score++;
if(level) level--;
clrscr();
printf(hdr);
if(linecheck(board, x, y)) score += 4;
render_board(board, score, level, r, stage, v);
nrr: break;
case 'x':
// discard rune
level++;
r = newrune();
clrscr();
printf(hdr);
render_board(board, score, level, r, stage, v);
if(level >> 2) {
clrscr();
printf("you lost :/\n");
printf(hdr);
render_board(board, score, level, r, stage, v);
goto cleanup;
}
break;
case 'i':
// up
if(y != 0) y--;
break;
case 'j':
// left
if(x != 0) x--;
break;
case 'k':
// down
if(y < 7) y++;
break;
case 'l':
// right
if(x < 8) x++;
break;
case 'q':
// quit
clrscr();
printf(hdr);
render_board(board, score, level, r, stage, v);
goto cleanup;
break;
}
if(c == 'a') {
mode ^= 1;
kill(p, SIGUSR1);
clrscr();
if(mode == 1) {
printf(
"ALCHEMY BANAL\n"
"original game by\n"
" PopCap Games\n"
"this version by\n"
" @mothcompute\n"
"CONTROLS:\n"
"SPACE to place rune\n"
" X to discard rune\n"
" Q to quit\n"
" IJKL to move cursor\n"
"& = skull | * = wild"
);
} else {
initbrd:
printf(hdr);
render_board(board, score, level, r, stage, movecheck(board, x, y, r));
}
}
if(!mode) {
clrscr();
printf(hdr);
render_board(board, score, level, r, stage, movecheck(board, x, y, r));
}
}
if(!mode) posupdate(x*2, y + 2);
}
cleanup:
tcsetattr(0, TCSANOW, &term_b);
kill(p, SIGINT);
}

35
mcb Executable file
View File

@ -0,0 +1,35 @@
#!/bin/sh
# mcb
# AWFUL build system
# dont laugh at me
isf() {
LC_ALL=C type $1 2>&1 | grep -q 'function'
}
. ./mcbs
[ ! -z "$1" ] && isf $1 && $1
[ -z "$SOURCES" ] && echo "provide \$SOURCES" && exit 1
[ -z "$OUTPUT" ] && echo "provide \$OUTPUT" && exit 1
[ -z "$COMPILER" ] && echo "\$COMPILER undefined. defaulting to cc" && COMPILER=cc
LINKS=""
ECODE=""
if isf mcb_build_hook; then
mcb_build_hook 2> /tmp/mcbs_err.$(basename $OUTPUT)
ECODE=$?
else
$COMPILER $SOURCES $FLAGS -o $OUTPUT 2> /tmp/mcbs_err.$(basename $OUTPUT)
ECODE=$?
fi
[ ! "$ECODE" = 0 ] && echo "build error" && [ ! -z "$MCB_SHOW" ] && cat /tmp/mcbs_err.$(basename $OUTPUT) && exit 1
isf mcb_post_hook && mcb_post_hook
[ ! -z "$MCB_SHOW" ] && cat /tmp/mcbs_err.$(basename $OUTPUT)
[ ! -z "$MCB_RUN" ] && ./$OUTPUT $MCB_RUN
exit 0