1 /* This file is part of Alienwave, a game by Alessandro Pira */
2 
3 #include <stdlib.h>
4 #include <curses.h>
5 #include <unistd.h>
6 #include <time.h>
7 #include <sys/time.h>
8 #include "defs.h"
9 #include "blit.h"
10 #include "aliens.h"
11 #include "xzarna.h"
12 #include "levels.h"
13 #include "fire.h"
14 #include "shield.h"
15 
16 int score = 0;
17 int end_x;
18 int game_ended = 0;
19 int x_ofs = 0;
20 int y_ofs = 0;
21 int term_x = 0;
22 int term_y = 0;
23 
24 const bitmask bitmask_ship={0x38,0x7C,0xFE,0x7C,0x00};
25 
26 WINDOW *term; /* our terminal */
27 
28 int exploding=0; /* this will be >0 if the player's ship is exploding */
29 
init_screen()30 void init_screen()
31 {
32 	term = initscr(); /* Initialize terminal */
33 
34 	start_color(); /* Initialize colors */
35 	init_pair(PC_WHITE,COLOR_WHITE,COLOR_BLACK);
36 	init_pair(PC_RED,COLOR_RED,COLOR_BLACK);
37 	init_pair(PC_GREEN,COLOR_GREEN,COLOR_BLACK);
38 	init_pair(PC_YELLOW,COLOR_YELLOW,COLOR_BLACK);
39 	init_pair(PC_BLUE,COLOR_BLUE,COLOR_BLACK);
40 	init_pair(PC_MAGENTA,COLOR_MAGENTA,COLOR_BLACK);
41 	init_pair(PC_CYAN,COLOR_CYAN,COLOR_BLACK);
42 	SET_COLOR(COL_BKG);
43 
44 	cbreak(); /* Disable line buffering and erase/kill characters */
45 	noecho(); /* Don't echo characters */
46 	nodelay(term,TRUE); /* Don't block while waiting for input */
47 
48 	nonl(); /* Don't translate return into newline, only CR */
49 	intrflush(term,FALSE); /* Do not flush input at ^C */
50 	keypad(term,TRUE); /* Enable keypad */
51 
52 	wrefresh(term);
53 }
54 
55 // Returns true if terminal is 80x25
right_size()56 int right_size()
57 {
58 	getmaxyx(term,term_y,term_x);
59 
60 	x_ofs = (term_x-80)/2;
61 	y_ofs = (term_y-25)/2;
62 
63 	return ((term_x>=80)&&(term_y>=25));
64 }
65 
presentation()66 void presentation()
67 {
68 	blit_borders(COL_BLUE);
69 
70 	SET_COLOR(COL_GREEN);
71 	mvwprintw(term,8+y_ofs,25+x_ofs,"-- -= A-L-I-E-N-W-A-V-E =- --");
72 	mvwprintw(term,11+y_ofs,27+x_ofs,  "a game by Alessandro Pira");
73 	SET_COLOR(COL_WHITE);
74 	mvwprintw(term,22+y_ofs,29+x_ofs,    "Press any key to start");
75 	SET_COLOR(COL_BKG);
76 
77 	while (wgetch(term) == ERR)
78 		;
79 
80 	wclear(term);
81 }
82 
pause()83 int pause()
84 {
85 	int overwritten[16];
86 	int ch,i;
87 
88 	for (i=0;i<16;i++)
89 		overwritten[i] = (int)mvwinch(term,10,31+i);
90 
91 	SET_COLOR(COL_RED);
92 	mvwprintw(term,10,31," *** PAUSED *** ");
93 	SET_COLOR(COL_BKG);
94 
95 	wmove(term,0,0);
96 
97 	while ((ch=wgetch(term)) == ERR)
98 		;
99 
100 	for (i=0;i<16;i++)
101 		mvwaddch(term,10,31+i,(chtype)overwritten[i]);
102 
103 	if ((ch==KEY_ESC) || (ch=='Q'))
104 	{
105 		return -1;
106 	}
107 	return 0;
108 }
109 
collide_ship(int x)110 int collide_ship(int x)
111 {
112 	/* This collision algorithm is probably faster but must be completed */
113 /*	int i;
114 	int rel_x,rel_y;
115 	for (i=0;i<NUMALIENS;i++)
116 	{
117 		if (all_aliens[i].type!=AT_NONE)
118 		{
119 			rel_x=x-all_aliens[i].x;
120 			rel_y=21-all_aliens[i].y;
121 			// ......
122 		}
123 	}
124 	return 0; */
125 
126 	/* For now I will use this... it can be good anyway */
127 	int check_x,check_y;
128 	for (check_y=0; check_y<MAX_HEIGHT; check_y++)
129 	{
130 		for (check_x=0; check_x<8; check_x++)
131 		{
132 			if ( (bitmask_ship[check_y] & (0x80 >> check_x)) != 0 )
133 			{
134 				if (collide_aliens(x+check_x,21+check_y)>=0)
135 					return 1;
136 				if (collide_queen(x+check_x,21+check_y,COL_SHIP)>=0)
137 					return 1;
138 			}
139 		}
140 	}
141 	return 0;
142 }
143 
move_ship()144 int move_ship()
145 {
146 	int c=0; /* character readen */
147 	static int last_c=-1;
148 	static int x=37; /* ship position */
149 	static int xs=0; /* ship speed */
150 
151 	if (game_ended)
152 	{
153 		end_x=x; // Publish ship x position
154 		return 0;
155 	}
156 
157 	if (exploding == 0)
158 	{
159 		c = wgetch(term);
160 		if (c != last_c)
161 		{
162 			switch(c)
163 			{
164 			case ERR:
165 				/* No key pressed */
166 				break;
167 			case KEY_LEFT:
168 				xs--;
169 				break;
170 			case KEY_RIGHT:
171 				xs++;
172 				break;
173 			case KEY_DOWN:
174 				xs=0;
175 				break;
176 			case ' ':
177 			case KEY_ENTER_:
178 				new_fire(x+3,21);
179 				break;
180 			case 's':
181 			case KEY_BACKSPACE:
182 			case KEY_UP:
183 				open_shields(x-1,20);
184 				break;
185 			case 'p':
186 			case 'P':
187 				if (pause()<0)
188 				{
189 					c='Q';
190 				}
191 				break;
192 			case KEY_ESC:
193 				c='Q';
194 			}
195 		}
196 		last_c = c;
197 
198 		/* Check limits */
199 		if (xs>MAXSPEED) xs=MAXSPEED;
200 		if (xs<-MAXSPEED) xs=-MAXSPEED;
201 
202 		clear_ship(x+x_ofs,21+y_ofs);
203 
204 		x+=xs;
205 
206 		if ( (x<0) || (x>73) )
207 		{
208 			xs = 0;
209 			(x>0)?(x=73):(x=0);
210 		}
211 
212 		blit_ship(x+x_ofs,21+y_ofs);
213 
214 		/* Check for collision with aliens */
215 		if (collide_ship(x))
216 		{
217 			exploding=1;
218 		}
219 	}
220 	else
221 	{
222 		switch (exploding++)
223 		{
224 		case 1:
225 			clear_ship(x+x_ofs,21+y_ofs);
226 			blit_explosion(x+3+x_ofs,22+y_ofs,3);
227 			break;
228 		case 2:
229 			clear_explosion(x+3+x_ofs,22+y_ofs,3);
230 			blit_explosion(x+3+x_ofs,22+y_ofs,3);
231 			break;
232 		case 3:
233 			clear_explosion(x+3+x_ofs,22+y_ofs,3);
234 			blit_explosion(x+3+x_ofs,22+y_ofs,4);
235 			break;
236 		case 4:
237 			clear_explosion(x+3+x_ofs,22+y_ofs,4);
238 			blit_explosion(x+3+x_ofs,22+y_ofs,4);
239 			break;
240 		case 5:
241 			clear_explosion(x+3+x_ofs,22+y_ofs,4);
242 			blit_explosion(x+3+x_ofs,22+y_ofs,3);
243 			break;
244 		case 6:
245 			clear_explosion(x+3+x_ofs,22+y_ofs,3);
246 			blit_explosion(x+3+x_ofs,22+y_ofs,3);
247 			break;
248 		case 7:
249 			clear_explosion(x+3+x_ofs,22+y_ofs,3);
250 			blit_explosion(x+3+x_ofs,22+y_ofs,2);
251 			break;
252 		case 8:
253 			clear_explosion(x+3+x_ofs,22+y_ofs,2);
254 			blit_explosion(x+3+x_ofs,22+y_ofs,2);
255 			break;
256 		case 9:
257 			clear_explosion(x+3+x_ofs,22+y_ofs,2);
258 			blit_explosion(x+3+x_ofs,22+y_ofs,1);
259 			break;
260 		case 10:
261 			clear_explosion(x+3+x_ofs,22+y_ofs,1);
262 			blit_explosion(x+3+x_ofs,22+y_ofs,1);
263 			break;
264 		case 11:
265 			clear_explosion(x+3+x_ofs,22+y_ofs,1);
266 			c='Q';
267 			break;
268 		}
269 	}
270 
271 	wmove(term,0,0);
272 	wrefresh(term);
273 
274 	return (c!='Q');
275 }
276 
m_wait(long delay)277 void m_wait(long delay)
278 {
279 /*
280 	// This is an algorithm I've tested to uniform speed on every CPU, but
281 	// gettimeofday resolution isn't very high and I got also very strange
282 	// and not uniform results...
283 
284 	static struct timeval last={0,0};
285 	struct timeval now;
286 	long diff;
287 
288 	if (gettimeofday(&now,NULL)<0)
289 	{
290 		// Error in gettimeofday... using old algorithm
291 		diff=0;
292 	}
293 	else
294 	{
295 		fprintf(stderr,"%lu . %lu - ",now.tv_sec,now.tv_usec);
296 		if (last.tv_sec==0) last=now;
297 		diff=(now.tv_sec-last.tv_sec)*1000000 + (now.tv_usec-last.tv_usec);
298 		last=now;
299 	}
300 
301 	fprintf(stderr,"diff: %d, waiting %lu\n",diff,(delay-diff>0)?delay-diff:0);
302 	if (delay-diff>0)
303 		usleep(delay-diff);
304 
305 	return;
306 */
307 	usleep(delay);
308 }
309 
end_game()310 void end_game()
311 {
312 	int y;
313 	for (y=21;y>-7;y--)
314 	{
315 		clear_ship(end_x+x_ofs,y+y_ofs);
316 		blit_ship(end_x+x_ofs,y-1+y_ofs);
317 
318 		wmove(term,0,0);
319 		wrefresh(term);
320 
321 		m_wait(DELAY);
322 
323 		delete_aliens();
324 		delete_queen();
325 		delete_fires();
326 		clear_shields();
327 
328 		move_fires();
329 		move_aliens();
330 		move_queen();
331 		move_shields();
332 
333 		blit_queen();
334 		blit_aliens();
335 		blit_fires();
336 		blit_shields();
337 		blit_score(74+x_ofs,y_ofs,score);
338 		blit_borders(COL_RED);
339 	}
340 }
341 
final()342 void final()
343 {
344 	printf("\n    Congratulations!\n");
345 	printf("    You have defeated Xzarna, the Queen of the Zorxians!\n\n");
346 
347 	printf("    With their queen gone all the zorxian space ships fled, desperately\n");
348 	printf("    seeking to save themselves, and the earth attack failed.\n");
349 	printf("    2 years later the zorxian race was completely defeated, and the\n");
350 	printf("    human race completed its expansion in all the solar system.\n");
351 	printf("    The starpilot who killed Xzarna was decorated, and his bravery is\n");
352 	printf("    recorded in every history book.\n");
353 	printf("\n                               *** THE END ***\n");
354 }
355 
main()356 int main()
357 {
358 	srand(time(NULL));
359 	init_screen();
360 
361 	if (!right_size())
362 	{
363 		endwin();
364 		fprintf(stderr,"Alienwave must be run in an 80x25 terminal!\n");
365 		return -1;
366 	}
367 
368 	presentation();
369 
370 	init_aliens();
371 	init_queen();
372 	init_levels();
373 	init_fires();
374 	init_shields();
375 
376 	while (move_ship())
377 	{
378 		m_wait(DELAY);
379 
380 		delete_aliens();
381 		delete_queen();
382 		delete_fires();
383 		clear_shields();
384 
385 		// move functions also performs collision check
386 		move_fires();
387 		move_aliens();
388 		move_queen();
389 		move_shields();
390 
391 		blit_queen();
392 		blit_aliens();
393 		blit_fires();
394 		blit_shields();
395 		blit_score(74+x_ofs,y_ofs,score);
396 		blit_borders(COL_GREEN);
397 	}
398 
399 	if (game_ended)
400 	{
401 		end_game();
402 	}
403 
404 	/* Flush input */
405 	while (wgetch(term) != ERR)
406 		;
407 
408 	endwin();
409 
410 	if (game_ended) final();
411 
412 	printf("\nYou have made %d points!\n",score);
413 	printf("-= A-L-I-E-N-W-A-V-E =- by Alessandro Pira\n");
414 
415 	return 0;
416 }
417 
418