1 /*
2 Jewels
3 
4 
5 Authored by abakh <abakh@tuta.io>
6 To the extent possible under law, the author(s) have dedicated all copyright and related and neighboring rights to this software to the public domain worldwide. This software is distributed without any warranty.
7 
8 You should have received a copy of the CC0 Public Domain Dedication along with this software. If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
9 
10 
11 A pair of jewels appear on top of the window, And you can move and rotate them while they are falling down.
12 If you make a vertical or horizontal row of 4 jewels they will explode and add up to your score.
13 Like Tetris,You will lose the game when the center of the uppermost row is filled.
14 
15 TODO make it like puyo puyo instead of the remake of what i poorly remembered*/
16 #include <curses.h>
17 #include <time.h>
18 #include <limits.h>
19 #include <string.h>
20 #include <stdlib.h>
21 #include "config.h"
22 #include "common.h"
23 #define LEN 17
24 #define WID 19
25 #define DELAY 2
26 #define SAVE_TO_NUM 10
27 
28 chtype board[LEN][WID];
29 chtype colors[6]={0};
30 chtype next1,next2;
31 byte jx,jy; //first jewel's position
32 byte kx,ky;//second jewel's position in relation to that of j
33 long score=0;
34 char* controls = "j,l-Move k-Rotate p-Pause q-Quit";
35 
save_score(void)36 byte save_score(void){
37 	return fallback_to_home("jewels_scores",score,SAVE_TO_NUM);
38 
39 }
show_scores(byte playerrank)40 void show_scores(byte playerrank){
41 	if(playerrank==FOPEN_FAIL){
42 		printf("Could not open scorefile.");
43 		abort();
44 	}
45 	if(playerrank == 0){
46 		char formername[60]={0};
47 		long formerscore=0;
48 		rewind(score_file);
49 		fscanf(score_file,"%*s : %*d\n");
50 		if ( fscanf(score_file,"%s : %ld\n",formername,&formerscore)==2){
51 			printf("\n*****CONGRATULATIONS!****\n");
52 			printf("     _____    You bet the\n");
53 			printf("   .'     |      previous\n");
54 			printf(" .'       |        record\n");
55 			printf(" |  .|    |            of\n");
56 			printf(" |.' |    |%14ld\n",formerscore);
57 			printf("     |    |       held by\n");
58 			printf("  ___|    |___%11s\n",formername);
59 			printf(" |            |\n");
60 			printf(" |____________|\n");
61 			printf("*************************\n");
62 		}
63 
64 	}
65 	//scorefile is still open with w+
66 	char pname[60] = {0};
67 	long pscore=0;
68 	byte rank=0;
69 	rewind(score_file);
70 	printf("\n>*>*>Top %d<*<*<\n",SAVE_TO_NUM);
71 	while( rank<SAVE_TO_NUM && fscanf(score_file,"%s : %ld\n",pname,&pscore) == 2){
72 		if(rank == playerrank)
73 			printf(">>>");
74 		printf("%d) %s : %ld\n",rank+1,pname,pscore);
75 		++rank;
76 	}
77 	putchar('\n');
78 	fclose(score_file);
79 }
80 //apply gravity
fall(void)81 bool fall(void){
82 	bool jfall,kfall,ret;
83 	jfall=kfall=ret=0;
84 	for(int y=LEN-1;y>0;--y){
85 		chtype c,d;
86 		for(int x=WID-1;x>=0;--x){
87 			c=board[y][x];
88 			d=board[y-1][x];
89 			if(!c && d){
90 				board[y-1][x]=0;
91 				board[y][x]=d;
92 				if(y-1==jy && x==jx)
93 					jfall=1;
94 				if((y-1==jy+ky) && (x==jx+kx))
95 					kfall=1;
96 				ret=1;
97 			}
98 		}
99 	}
100 	if(jfall&&kfall)
101 		++jy;
102 	else
103 		jy = LEN+1;
104 	return ret;
105 }
106 // rotate 90d clockwise in ky/x format
clockwise(byte * y,byte * x)107 void clockwise(byte* y,byte* x){
108 		/*
109 		 o		x
110 		 x	xo	o    ox*/
111 		chtype fx,fy;
112 		if(*y){
113 			fy=0;
114 			fx=-*y;
115 		}
116 		if(*x){
117 			fx=0;
118 			fy=*x;
119 		}
120 		*y=fy;
121 		*x=fx;
122 }
123 
124 //rtt jwls
rotate(void)125 bool rotate(void){//f:future
126 		if(jy>LEN)
127 			return 0;
128 		byte fy,fx;
129 		fy=ky;fx=kx;
130 		clockwise(&fy,&fx);
131 		if( jy+fy<0 || jy+fy>=LEN || jx+fx<0 || jx+fx>=WID )
132 			return 0;
133 		if(board[jy+fy][jx+fx])
134 			return 0;
135 		chtype a = board[jy+ky][jx+kx];
136 		board[jy+ky][jx+kx]=0;
137 		ky=fy;
138 		kx=fx;
139 		board[jy+ky][jx+kx]=a;
140 		return 1;
141 }
142 //mv jwls
jmove(byte dy,byte dx)143 bool jmove(byte dy,byte dx){
144 		if(jy>LEN)
145 			return 0;
146 
147 		if(jx+dx>=WID || jx+dx<0 || jx+kx+dx>=WID ||jx+kx+dx<0 || jy+dx<0 ||jx+dx+kx<0)
148 			return 0;
149 		if( board[jy+ky+dy][jx+kx+dx] )
150 			if( !(jy+ky+dy == jy && jx+kx+dx==jx) )
151 				return 0;
152 
153 		if( board[jy+dy][jx+dx])
154 				if(!(dx==kx && dy==ky))
155 					return 0;
156 		//still alive?
157 		chtype a = board[jy][jx];
158 		chtype b = board[jy+ky][jx+kx];
159 		board[jy][jx]=0;
160 		board[jy+ky][jx+kx]=0;
161 		board[jy+dy][jx+dx]=a;
162 		board[jy+ky+dy][jx+kx+dx]=b;
163 		jy+=dy;jx+=dx;
164 		return 1;
165 }
166 //scoring algorithm
explode(byte combo)167 bool explode(byte combo){
168 	bool ret =0;
169 	chtype c,uc;
170 	byte n;
171 	byte y,x;
172 	for(y=0;y<LEN;++y){
173 		c=uc=n=0;
174 		for(x=0;x<WID;++x){
175 			uc = c;
176 			c  = board[y][x];
177 			if(c && c == uc){
178 				++n;
179 				if(n>=3 && x==WID-1){//the chain ends because the row ends
180 					++x;
181 					goto HrExplsn;
182 				}
183 			}
184 			else if(n>=3){
185 				HrExplsn:
186 				score+=n*10*(n-2)*combo;
187 				ret=1;
188 				for(;n>=0;--n)
189 					board[y][x-1-n]=0;
190 				n=0;
191 			}
192 			else
193 				n=0;
194 		}
195 	}
196 	for(x=0;x<WID;++x){
197 		c=uc=n=0;
198 		for(byte y=0;y<LEN;++y){
199 			uc=c;
200 			c = board[y][x];
201 			if(c && c == uc){
202 				++n;
203 				if(n>=3 && y==LEN-1){
204 					++y;
205 					goto VrExplsn;
206 				}
207 			}
208 			else if(n>=3){
209 				VrExplsn:
210 				score+=n*10*(n-2)*combo;
211 				ret=1;
212 				for(;n>=0;--n)
213 					board[y-1-n][x]=0;
214 				n=0;
215 			}
216 			else
217 				n=0;
218 		}
219 	}
220 	return ret;
221 }
222 
223 //display
draw(void)224 void draw(void){
225 	erase();
226 	int middle = (COLS/2-1)-(WID/2);
227 	chtype a=A_STANDOUT|' ';
228 	mvhline(LEN,middle-2,a,WID+4);
229 	mvvline(0,middle-1,a,LEN);
230 	mvvline(0,middle-2,a,LEN);
231 	mvvline(0,middle+WID,a,LEN);
232 	mvvline(0,middle+WID+1,a,LEN);
233 	mvprintw(0,0,"Score:%d",score);
234 	mvaddstr(1,0,"Next:");
235 	addch(next1);
236 	addch(next2);
237 	for(byte y=0;y<LEN;++y){
238 		for(byte x=0;x<WID;++x){
239 			chtype c = board[y][x];
240 			if(c)
241 				mvaddch(y,middle+x,c);
242 		}
243 	}
244 	mvaddstr(LINES-2,middle-5,controls);
245 	refresh();
246 }
main(void)247 int main(void){
248 	initscr();
249 	cbreak();
250 	halfdelay(DELAY);
251 	noecho();
252 	curs_set(0);
253 	wnoutrefresh(stdscr);
254 	keypad(stdscr,1);
255 	int input;
256 	bool falls;
257 	byte stop=0 , combo;
258 	char jwstr[] = {'*','^','~','"','$','V'};
259         if(has_colors()){
260                 start_color();
261                 use_default_colors();
262                 init_pair(1,COLOR_RED,-1);
263                 init_pair(2,COLOR_GREEN,-1);
264                 init_pair(3,COLOR_MAGENTA,-1);
265                 init_pair(4,COLOR_BLUE,-1);//array this thing
266                 init_pair(5,COLOR_YELLOW,-1);
267                 init_pair(6,COLOR_CYAN,-1);
268                 for(byte n=0;n<6;++n){
269                         colors[n] = COLOR_PAIR(n+1);
270                 }
271         }
272 
273         srand(time(NULL)%UINT_MAX);
274         byte ran1= rand()%6;
275         byte ran2= rand()%6;
276         next1= colors[ran1]|jwstr[ran1];
277         next2= colors[ran2]|jwstr[ran2];
278         while(1){
279                 chtype a,b;
280                 a=board[0][WID/2];
281                 b=board[0][WID/2-1];
282                 if(a || b ){
283                         goto Lose;
284                 }
285                 jy=ky=0;
286                 jx=WID/2;
287                 kx=-1;
288                 board[jy][jx]=next2;
289                 board[jy+ky][jx+kx]=next1;
290                 ran1= rand()%6;
291                 ran2= rand()%6;
292                 next1=colors[ran1]|jwstr[ran1];
293                 next2=colors[ran2]|jwstr[ran2];
294                 falls = 1;
295                 while(falls){
296                         input = getch();
297 
298                         if(input != ERR)
299                                 stop+=1;
300 
301                         if( stop >= 10){
302                                 falls=fall();
303                                 stop=0;
304                         }
305                         else if(input=='l' || input==KEY_RIGHT)
306                                 jmove(0,+1);
307                         else if(input=='j' || input==KEY_LEFT )
308                                 jmove(0,-1);
309                         else if(input=='k' || input==KEY_UP)
310                                 rotate();
311                         else if(input=='p'){
312                                 mvaddstr(LINES-2,COLS/2-15,"Paused - Press a key to continue   ");
313                                 refresh();
314                                 nocbreak();
315                                 cbreak();
316                                 getch();
317                                 halfdelay(DELAY);
318                         }
319                         else if(input=='q')
320                                 goto Lose;
321                         else if(input==' ')
322                                 while( (falls=fall()) )
323                                         stop=0;
324                         else{
325                                 falls=fall();
326                                 stop=0;
327                         }
328                         draw();
329                  }
330                 combo=1;
331                 while(explode(combo)){ // explode, fall, explode, fall until nothing is left
332                         ++combo;
333                         while(fall());
334                         draw();
335                 }
336         }
337         Lose:
338         nocbreak();
339         endwin();
340         printf("%s _Jewels_ %s\n",jwstr,jwstr);
341         printf("You have scored %ld points.\n",score);
342         show_scores(save_score());
343         return EXIT_SUCCESS;
344 }
345