initial commit
This commit is contained in:
commit
7cf2127956
|
@ -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
|
|
@ -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("};");
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
|
@ -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
|
Loading…
Reference in New Issue