1
0
mirror of https://github.com/abakh/nbsdgames.git synced 2024-11-02 16:27:18 -04:00
nbsdgames/sources/jewels.c
2020-05-18 23:29:29 +04:30

390 lines
8.1 KiB
C

#include <curses.h>
#include <time.h>
#include <limits.h>
#include <string.h>
#include <stdlib.h>
#include "config.h"
#define LEN 17
#define WID 19
#define DELAY 2
#define SAVE_TO_NUM 10
/*
Jewels
Authored by Hossein Bakhtiarifar <abakh@tuta.io>
No rights are reserved and this software comes with no warranties of any kind to the extent permitted by law.
compile with -lnucrses
A pair of jewels appear on top of the window, And you can move and rotate them while they are falling down.
If you make a vertical or horizontal row of 4 jewels they will explode and add up to your score.
Like Tetris,You will lose the game when the center of the uppermost row is filled.
*/
typedef signed char byte;
chtype board[LEN][WID];
chtype colors[6]={0};
chtype next1,next2;
byte jx,jy; //first jewel's position
byte kx,ky;//second jewel's position in relation to that of j
long score=0;
char* controls = "j,l-Move k-Rotate p-Pause q-Quit";
FILE* scorefile;
byte scorewrite(long score){// only saves the top 10
bool deforno;
if( !getenv("JW_SCORES") && (scorefile= fopen(JW_SCORES,"r")) ){
deforno=1;
}
else{
deforno=0;
if( !(scorefile = fopen(getenv("JW_SCORES"),"r")) ){
fprintf(stderr,"\nNo accessible score files found. You can make an empty text file in %s or set JW_SCORES to such a file to solve this. \n",JW_SCORES);
exit(EXIT_SUCCESS);
}
}
char namebuff[SAVE_TO_NUM][60];
long scorebuff[SAVE_TO_NUM];
memset(namebuff,0,SAVE_TO_NUM*60*sizeof(char) );
memset(scorebuff,0,SAVE_TO_NUM*sizeof(long) );
long fuckingscore =0;
char fuckingname[60]={0};
byte location=0;
while( fscanf(scorefile,"%59s : %ld\n",fuckingname,&fuckingscore) == 2 && location<SAVE_TO_NUM ){
strcpy(namebuff[location],fuckingname);
scorebuff[location] = fuckingscore;
location++;
memset(fuckingname,0,60);
fuckingscore=0;
}
if(deforno)
scorefile = fopen(JW_SCORES,"w+");//get rid of the text
else
scorefile = fopen(getenv("JW_SCORES"), "w+") ;
if(!scorefile){
printf("\nThe file cannot be opened in w+.\n");
exit(EXIT_SUCCESS);
}
byte itreached=location;
byte ret = -1;
bool wroteit=0;
for(location=0;location<=itreached && location<SAVE_TO_NUM-wroteit;location++){
if(!wroteit && (location>=itreached || score>=scorebuff[location]) ){
fprintf(scorefile,"%s : %ld\n",getenv("USER"),score);
ret=location;
wroteit=1;
}
if(location<SAVE_TO_NUM-wroteit && location<itreached)
fprintf(scorefile,"%s : %ld\n",namebuff[location],scorebuff[location]);
}
fflush(scorefile);
return ret;
}
void showscores(byte playerrank){
if(playerrank == 0){
char formername[60]={0};
long formerscore=0;
rewind(scorefile);
fscanf(scorefile,"%*s : %*d\n");
if ( fscanf(scorefile,"%s : %ld\n",formername,&formerscore)==2){
printf("\n*****CONGRATULATIONS!****\n");
printf(" _____ You bet the\n");
printf(" .' | previous\n");
printf(" .' | record\n");
printf(" | .| | of\n");
printf(" |.' | |%14ld\n",formerscore);
printf(" | | held by\n");
printf(" ___| |___%11s\n",formername);
printf(" | |\n");
printf(" |____________|\n");
printf("*************************\n");
}
}
//scorefile is still open with w+
char pname[60] = {0};
long pscore=0;
byte rank=0;
rewind(scorefile);
printf("\n>*>*>Top %d<*<*<\n",SAVE_TO_NUM);
while( rank<SAVE_TO_NUM && fscanf(scorefile,"%s : %ld\n",pname,&pscore) == 2){
if(rank == playerrank)
printf(">>>");
printf("%d) %s : %ld\n",rank+1,pname,pscore);
rank++;
}
putchar('\n');
}
//apply gravity
bool fall(void){
bool jfall,kfall,ret;
jfall=kfall=ret=0;
for(int y=LEN-1;y>0;y--){
chtype c,d;
for(int x=WID-1;x>=0;x--){
c=board[y][x];
d=board[y-1][x];
if(!c && d){
board[y-1][x]=0;
board[y][x]=d;
if(y-1==jy && x==jx)
jfall=1;
if((y-1==jy+ky) && (x==jx+kx))
kfall=1;
ret=1;
}
}
}
if(jfall&&kfall)
jy++;
else
jy = LEN+1;
return ret;
}
// rotate 90d clockwise in ky/x format
void clockwise(byte* y,byte* x){
/*
o x
x xo o ox*/
chtype fx,fy;
if(*y){
fy=0;
fx=-*y;
}
if(*x){
fx=0;
fy=*x;
}
*y=fy;
*x=fx;
}
//rtt jwls
bool rotate(void){//f:future
if(jy>LEN)
return 0;
byte fy,fx;
fy=ky;fx=kx;
clockwise(&fy,&fx);
if( jy+fy<0 || jy+fy>=LEN || jx+fx<0 || jx+fx>=WID )
return 0;
if(board[jy+fy][jx+fx])
return 0;
chtype a = board[jy+ky][jx+kx];
board[jy+ky][jx+kx]=0;
ky=fy;
kx=fx;
board[jy+ky][jx+kx]=a;
return 1;
}
//mv jwls
bool jmove(byte dy,byte dx){
if(jy>LEN)
return 0;
if(jx+dx>=WID || jx+dx<0 || jx+kx+dx>=WID ||jx+kx+dx<0 || jy+dx<0 ||jx+dx+kx<0)
return 0;
if( board[jy+ky+dy][jx+kx+dx] )
if( !(jy+ky+dy == jy && jx+kx+dx==jx) )
return 0;
if( board[jy+dy][jx+dx])
if(!(dx==kx && dy==ky))
return 0;
//still alive?
chtype a = board[jy][jx];
chtype b = board[jy+ky][jx+kx];
board[jy][jx]=0;
board[jy+ky][jx+kx]=0;
board[jy+dy][jx+dx]=a;
board[jy+ky+dy][jx+kx+dx]=b;
jy+=dy;jx+=dx;
return 1;
}
//scoring algorithm
bool explode(byte combo){
bool ret =0;
chtype c,uc;
byte n;
byte y,x;
for(y=0;y<LEN;y++){
c=uc=n=0;
for(x=0;x<WID;x++){
uc = c;
c = board[y][x];
if(c && c == uc){
n++;
if(n>=3 && x==WID-1){//the chain ends because the row ends
x++;
goto HrExplsn;
}
}
else if(n>=3){
HrExplsn:
score+=n*10*(n-2)*combo;
ret=1;
for(;n>=0;n--)
board[y][x-1-n]=0;
n=0;
}
else
n=0;
}
}
for(x=0;x<WID;x++){
c=uc=n=0;
for(byte y=0;y<LEN;y++){
uc=c;
c = board[y][x];
if(c && c == uc){
n++;
if(n>=3 && y==LEN-1){
y++;
goto VrExplsn;
}
}
else if(n>=3){
VrExplsn:
score+=n*10*(n-2)*combo;
ret=1;
for(;n>=0;n--)
board[y-1-n][x]=0;
n=0;
}
else
n=0;
}
}
return ret;
}
//display
void draw(void){
erase();
int middle = (COLS/2-1)-(WID/2);
chtype a=A_STANDOUT|' ';
mvhline(LEN,middle-2,a,WID+4);
mvvline(0,middle-1,a,LEN);
mvvline(0,middle-2,a,LEN);
mvvline(0,middle+WID,a,LEN);
mvvline(0,middle+WID+1,a,LEN);
mvprintw(0,0,"Score:%d",score);
mvaddstr(1,0,"Next:");
addch(next1);
addch(next2);
for(byte y=0;y<LEN;y++){
for(byte x=0;x<WID;x++){
chtype c = board[y][x];
if(c)
mvaddch(y,middle+x,c);
}
}
mvaddstr(LINES-2,middle-5,controls);
refresh();
}
int main(void){
initscr();
cbreak();
halfdelay(DELAY);
noecho();
curs_set(0);
wnoutrefresh(stdscr);
keypad(stdscr,1);
int input;
bool falls;
byte stop=0 , combo;
char jwstr[] = {'*','^','~','"','$','V'};
if(has_colors()){
start_color();
use_default_colors();
init_pair(1,COLOR_RED,-1);
init_pair(2,COLOR_GREEN,-1);
init_pair(3,COLOR_MAGENTA,-1);
init_pair(4,COLOR_BLUE,-1);//array this thing
init_pair(5,COLOR_YELLOW,-1);
init_pair(6,COLOR_CYAN,-1);
for(byte n=0;n<6;n++){
colors[n] = COLOR_PAIR(n+1);
}
}
srand(time(NULL)%UINT_MAX);
byte ran1= rand()%6;
byte ran2= rand()%6;
next1= colors[ran1]|jwstr[ran1];
next2= colors[ran2]|jwstr[ran2];
while(1){
chtype a,b;
a=board[0][WID/2];
b=board[0][WID/2-1];
if(a || b ){
goto Lose;
}
jy=ky=0;
jx=WID/2;
kx=-1;
board[jy][jx]=next2;
board[jy+ky][jx+kx]=next1;
ran1= rand()%6;
ran2= rand()%6;
next1=colors[ran1]|jwstr[ran1];
next2=colors[ran2]|jwstr[ran2];
falls = 1;
while(falls){
input = getch();
if(input != ERR)
stop+=1;
if( stop >= 10){
falls=fall();
stop=0;
}
else if(input=='l' || input==KEY_RIGHT)
jmove(0,+1);
else if(input=='j' || input==KEY_LEFT )
jmove(0,-1);
else if(input=='k' || input==KEY_UP)
rotate();
else if(input=='p'){
mvaddstr(LINES-2,COLS/2-15,"Paused - Press a key to continue ");
refresh();
nocbreak();
cbreak();
getch();
halfdelay(DELAY);
}
else if(input=='q')
goto Lose;
else if(input==' ')
while( (falls=fall()) )
stop=0;
else{
falls=fall();
stop=0;
}
draw();
}
combo=1;
while(explode(combo)){ // explode, fall, explode, fall until nothing is left
combo++;
while(fall());
draw();
}
}
Lose:
nocbreak();
endwin();
printf("%s _Jewels_ %s\n",jwstr,jwstr);
printf("You have scored %ld points.\n",score);
showscores(scorewrite(score));
return EXIT_SUCCESS;
}