1 /*
2     O__/|
3  ___|_/ |    __
4 |     / |   |__
5 	    |  ISHER
6 
7 Authored by abakh <abakh@tuta.io>
8 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.
9 
10 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/>.
11 
12 */
13 #include <stdio.h>
14 #include <stdbool.h>
15 #include <stdlib.h>
16 #include <time.h>
17 #include <signal.h>
18 #include <string.h>
19 #include <limits.h>
20 #include <curses.h>
21 #include <unistd.h>
22 #include "config.h"
23 #include "common.h"
24 #define SAVE_TO_NUM 11
25 #define HOOKS 10
26 #define LEN 24
27 #define HLEN LEN/2
28 #define WID 80
29 #define HWID WID/2
30 #ifdef Plan9
usleep(long usec)31 int usleep(long usec) {
32     int second = usec/1000000;
33     long nano = usec*1000 - second*1000000;
34     struct timespec sleepy = {0};
35     sleepy.tv_sec = second;
36     sleepy.tv_nsec = nano;
37     nanosleep(&sleepy, (struct timespec *) NULL);
38     return 0;
39 }
40 #endif
41 // 12 lines of water
42 // 80 columns
43 
44 chtype colors[4]={A_NORMAL,A_STANDOUT};
45 byte fish[10]={0};//positions
46 byte caught=-1;
47 bool stop[10]={0};
48 unsigned int count[10]={0};
49 unsigned long score=0;
50 const char sym[]="~:=!@+><;&";
51 byte hook=0, hooknum=0;
52 byte clb,clbtime=0;
53 
54 int input;
digit_count(int num)55 byte digit_count(int num){
56 	byte ret=0;
57 	do{
58 		++ret;
59 		num/=10;
60 	}while(num);
61 	return ret;
62 }
filled_rect(byte sy,byte sx,byte ey,byte ex)63 void filled_rect(byte sy,byte sx,byte ey,byte ex){
64 	byte y,x;
65 	for(y=sy;y<ey;++y)
66 		for(x=sx;x<ex;++x)
67 			mvaddch(y,x,' ');
68 }
green_border(void)69 void green_border(void){
70 	byte y,x;
71 	for(y=0;y<LEN;++y){
72 		mvaddch(y,WID-1,' '|colors[2]);
73 		mvaddch(y,0,' '|colors[2]);
74 	}
75 	for(x=0;x<WID;++x){
76 		mvaddch(LEN-1,x,' '|colors[2]);
77 		mvaddch(0,x,' '|colors[2]);
78 	}
79 
80 }
star_line(byte y)81 void star_line(byte y){
82 	for(byte x=1;x<WID-1;++x)
83 		mvaddch(y,x,'.');
84 }
draw(void)85 void draw(void){
86 	/*while(LEN< 15 || COL<80)
87 		mvprintw(0,0,"Screen size should at least be 80*15 characters");*/
88 	attron(colors[0]);
89 	filled_rect(0,0,12,80);
90 	byte y;
91 	mvprintw(0,0," __       Hooks:%d",hooknum);
92 	mvprintw(1,0,"|__       Score:%d",score);
93 	mvprintw(2,0,"|  ISHER");
94 	mvprintw(9,32, "    O__/");
95 	mvprintw(10,32," ___|_/ ");
96 	mvprintw(11,32,"|     / ");
97 
98 	if(clbtime){
99 		if(count[clb]!=1){
100 			mvprintw(9,43,"%d ",count[clb]);
101 			switch(clb){
102 				case 0:
103 					addstr("plastic bags!");
104 				break;
105 				case 1:
106 					addstr("PVC bottles!");
107 				break;
108 				case 2:
109 					addstr("face masks!");
110 				break;
111 				case 3:
112 					addstr("shrimp!");
113 				break;
114 				case 4:
115 					addstr("algae!");
116 				break;
117 				case 5:
118 					addstr("jellyfish!");
119 				break;
120 				case 6:
121 					addstr("molluscs!");
122 				break;
123 				case 7:
124 					addstr("actual fish!");
125 				break;
126 				case 8:
127 					addstr("salmon!");
128 				break;
129 				case 9:
130 					addstr("tuna!");
131 				break;
132 			}
133 		}
134 		else{
135 			move(9,43);
136 			switch(clb){
137 				case 0:
138 					addstr("A plastic bag!");
139 				break;
140 				case 1:
141 					addstr("A PVC bottle!");
142 				break;
143 				case 2:
144 					addstr("A face mask!");
145 				break;
146 				case 3:
147 					addstr("A shrimp!");
148 				break;
149 				case 4:
150 					addstr("Algae!");
151 				break;
152 				case 5:
153 					addstr("A jellyfish!");
154 				break;
155 				case 6:
156 					addstr("A mollusc!");
157 				break;
158 				case 7:
159 					addstr("Actual fish!");
160 				break;
161 				case 8:
162 					addstr("A salmon!");
163 				break;
164 				case 9:
165 					addstr("A tuna!");
166 				break;
167 			}
168 		}
169 	}
170 	for(y=-3;y<0;++y)
171 		mvaddch(HLEN+y,HWID,ACS_VLINE);
172 	attroff(colors[0]);
173 	attron(colors[1]);
174 	filled_rect(HLEN,0,LEN,WID);
175 	for(y=0;y<hook;++y)
176 		mvaddch(HLEN+y,HWID,ACS_VLINE);
177 	if(caught==-1)
178 		mvaddch(HLEN+hook,HWID,')');
179 	else
180 		mvaddch(HLEN+hook,HWID,sym[caught]);
181 	for(y=0;y<10;++y)
182 		mvaddch(HLEN+1+y,fish[y],sym[y]);
183 	attroff(colors[1]);
184 
185 }
save_score(void)186 byte save_score(void){
187 	return fallback_to_home("fisher_scores",score,SAVE_TO_NUM);
188 
189 }
190 
191 
show_scores(byte playerrank)192 void show_scores(byte playerrank){
193 	attron(colors[3]);
194 	filled_rect(0,0,LEN,WID);
195 	green_border();
196 	if(playerrank==FOPEN_FAIL){
197 		mvaddstr(1,0,"Could not open score file");
198 		mvprintw(2,0,"However, your score is %ld.",score);
199 		refresh();
200 		return;
201 	}
202 	if(playerrank == 0){
203 		char formername[60]={0};
204 		long formerscore=0;
205 		rewind(score_file);
206 		fscanf(score_file,"%*s : %*d");
207 		if ( fscanf(score_file,"%s : %ld",formername,&formerscore)==2  && formerscore>0){
208 			byte a = (LEN-9)/2;
209 			star_line(1);
210 			star_line(LEN-2);
211 			mvaddstr(1,WID/2-8,"CONGRATULATIONS!!");
212 			mvprintw(a+1,HWID-10,"     _____ You bet the");
213 			mvprintw(a+2,HWID-10,"   .'     |   previous");
214 			mvprintw(a+3,HWID-10," .'       |     record");
215 			mvprintw(a+4,HWID-10," |  .|    |         of");
216 			mvprintw(a+5,HWID-10," |.' |    |%11ld",formerscore);
217 			mvprintw(a+6,HWID-10,"     |    |    held by");
218 			mvprintw(a+7,HWID-10,"  ___|    |___%7s!",formername);
219 			mvprintw(a+8,HWID-10," |            |");
220 			mvprintw(a+9,HWID-10," |____________|");
221 			mvprintw(LEN-3,HWID-11,"Press a key to continue");
222 			refresh();
223 			do{
224 				input=getch();
225 			}while(input==KEY_UP || input==KEY_DOWN);
226 			filled_rect(0,0,LEN,WID);
227 			green_border();
228 		}
229 
230 	}
231 	//scorefile is still open with w+
232 	char pname[60] = {0};
233 	long pscore=0;
234 	byte rank=0;
235 	rewind(score_file);
236 	mvaddstr(1,WID/2-4,"HIGH SCORES");
237 	attron(colors[3]);
238 	while( rank<SAVE_TO_NUM && fscanf(score_file,"%s : %ld\n",pname,&pscore) == 2){
239 		star_line(2+2*rank);
240 		move(2+2*rank,1);
241 		if(rank == playerrank)
242 			printw(">>>");
243 		printw("%s",pname);
244 		mvprintw(2+2*rank,WID-1-digit_count(pscore),"%d",pscore);
245 		++rank;
246 	}
247 	attroff(colors[3]);
248 	refresh();
249 }
help(void)250 void help(void){
251 	nocbreak();
252 	cbreak();
253 	attron(colors[3]);
254 	filled_rect(0,0,LEN,WID);
255 	green_border();
256 	mvprintw(1,HWID-4,"GAME PLAY");
257 	mvprintw(3,1,"Catch a fish and reel it in for points");
258 	mvprintw(4,1,"The deeper the fish, the more points it is worth.");
259 	mvprintw(5,1,"If a fish hits your line, you lose a hook.");
260 	mvprintw(6,1,"When you run out of hooks, the game is over!");
261 	mvprintw(8,HWID-4,"CONTROLS");
262 	mvprintw(10,1,"UP & DOWN: Control the hook");
263 	mvprintw(11,1,"q: Quit");
264 	mvprintw(13,1,"This is a port of \"Deep Sea Fisher\", a MikeOS game.");
265 	attroff(colors[3]);
266 	refresh();
267 	getch();
268 	halfdelay(1);
269 }
sigint_handler(int x)270 void sigint_handler(int x){
271 	endwin();
272 	puts("Quit.");
273 	exit(x);
274 }
main(void)275 int main(void){
276 	signal(SIGINT,sigint_handler);
277 	initscr();
278 	noecho();
279 	cbreak();
280 	keypad(stdscr,1);
281 	srand(time(NULL)%UINT_MAX);
282 	for(byte n=0;n<10;++n)
283 		fish[n]=rand()%80;
284 	if(has_colors()){
285 		start_color();
286 		init_pair(1,COLOR_BLACK,COLOR_CYAN);
287 		init_pair(2,COLOR_BLACK,COLOR_BLUE);
288 		init_pair(3,COLOR_WHITE,COLOR_GREEN);
289 		init_pair(4,COLOR_BLACK,COLOR_WHITE);
290 		for(byte b=0;b<4;++b)
291 			colors[b]=COLOR_PAIR(b+1);
292 	}
293 	byte n;
294 	Start:
295 	halfdelay(1);
296 	curs_set(0);
297 	clbtime=0;
298 	hook=0;
299 	hooknum=HOOKS;
300 	score=0;
301 	memset(count,0,10*sizeof(unsigned int) );
302 	while(1){
303 		draw();
304 		refresh();
305 		input=getch();
306 		for(n=0;n<10;++n){
307 			if(stop[n]){
308 				if(rand()%(n+15)==0)//this is to make the fish move
309 					stop[n]=0;
310 				continue;
311 			}
312 			if(n%2)
313 				fish[n]--;
314 			else
315 				fish[n]++;
316 			if(fish[n]<0)
317 				fish[n]=79;
318 			if(fish[n]>79)
319 				fish[n]=0;//appear on the other end
320 			if(fish[n]==40){
321 				if(hook>n+1){
322 					caught= -1;
323 					hook=0;
324 					--hooknum;
325 				}
326 				if(hook==n+1 && caught==-1){
327 					caught=n;
328 					if(n%2)
329 						fish[n]=79;
330 					else
331 						fish[n]=0;
332 				}
333 			}
334 			if(rand()%(14-n)==0)//this is to make it stop
335 				stop[n]=1;
336 		}
337 		if(input==KEY_UP){
338 			if(hook>0)
339 				--hook;
340 			if(hook==0 && caught!=-1){
341 				count[caught]++;
342 				score+=(caught+1)*(caught+1);
343 				clb=caught;
344 				clbtime=10;//celebrate catching the fish
345 				caught=-1;
346 			}
347 		}
348 		if(input==KEY_DOWN){
349 			if(hook<11)
350 				++hook;
351 			if(fish[hook-1]==40 && caught==-1){
352 				caught=hook-1;
353 				if(n%2)
354 					fish[hook-1]=0;
355 				else
356 					fish[hook-1]=79;
357 			}
358 		}
359 		if(input=='?' || input==KEY_F(1))
360 			help();
361 		if(input=='q')
362 			break;
363 		if(!hooknum)
364 			break;
365 		if(input!=ERR){
366 			usleep(100000);
367 			flushinp();
368 		}
369 	}
370 	flushinp();
371 	nocbreak();
372 	cbreak();
373 	curs_set(1);
374 	show_scores(save_score());
375 	attron(colors[2]);
376 	mvprintw(LEN-1,HWID-11,"Wanna play again? (y/n)");
377 	attroff(colors[2]);
378 	do{
379 		input=getch();
380 	}while(input==KEY_UP || input==KEY_DOWN);
381 	if(input!='q' && input!='n' && input!='N')
382 		goto Start;
383 	endwin();
384 	return 0;
385 }
386