1 /**
2  * nInvaders - a space invaders clone for ncurses
3  * Copyright (C) 2002-2003 Dettus
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
18  *
19  * homepage: http://ninvaders.sourceforge.net
20  * mailto: ninvaders-devel@lists.sourceforge.net
21  *
22  */
23 
24 
25 #include "view.h"
26 #include "globals.h"
27 #include <stdlib.h>
28 #include <unistd.h>
29 #include <signal.h>
30 
31 #define RED 1
32 #define GREEN 2
33 #define YELLOW 3
34 #define BLUE 4
35 #define CYAN 5
36 #define MAGENTA 6
37 #define WHITE 7
38 
39 WINDOW *wBattleField;
40 WINDOW *wEmpty;
41 WINDOW *wScores;
42 
43 WINDOW *wPlayer;
44 WINDOW *wPlayerMissile;
45 WINDOW *wAliens;
46 WINDOW *wAliensMissile;
47 WINDOW *wBunkers;
48 WINDOW *wGameOver;
49 WINDOW *wUfo;
50 WINDOW *wStatus;
51 WINDOW *wTitleScreen;
52 
53 /**
54  * initialize player sprites
55  */
playerInit()56 static void playerInit()
57 {
58 	wPlayer = newpad(1, PLAYERWIDTH);       // new pad with appropriate size
59 	wclear(wPlayer);			// clear pad
60         wattrset(wPlayer,COLOR_PAIR(YELLOW));	// set color
61         waddstr(wPlayer,"/-^-\\");	        // set sprite
62 }
63 
64 
65 /**
66  * display player sprite
67  */
playerDisplay(int x,int y)68 void playerDisplay(int x, int y)
69 {
70 	copywin(wPlayer,wBattleField,0,0,y,x,y,x+PLAYERWIDTH-1,0);
71 }
72 
73 
74 /**
75  * clear player sprite
76  */
playerClear(int x,int y)77 void playerClear(int x, int y)
78 {
79 	copywin(wEmpty,wBattleField,0,0,y,x,y,x+PLAYERWIDTH-1,0);
80 }
81 
82 
83 /**
84  * initialize missile sprites
85  */
playerMissileInit()86 static void playerMissileInit()
87 {
88 	wPlayerMissile = newpad(1, 1);		// new pad with appropriate size
89 	wclear(wPlayerMissile);			// clear pad
90 	wattrset(wPlayerMissile,COLOR_PAIR(WHITE));	// set color
91 	waddch(wPlayerMissile,'!');		// set sprite
92 	wrefresh(wPlayerMissile);
93 }
94 
95 
96 /**
97  * display missile sprite
98  */
playerMissileDisplay(int x,int y)99 void playerMissileDisplay(int x, int y)
100 {
101 	copywin(wPlayerMissile,wBattleField,0,0,y,x,y,x,0);
102 }
103 
104 
105 /**
106  * clear missile sprite
107  */
playerMissileClear(int x,int y)108 void playerMissileClear(int x, int y)
109 {
110 	copywin(wEmpty,wBattleField,0,0,y,x,y,x,0);
111 }
112 
113 
114 /**
115  * some explosion animation
116  */
playerExplosionDisplay(int x,int y)117 void playerExplosionDisplay(int x, int y)
118 {
119 	WINDOW* wPlayerExplosion;
120 	char playerExplosionChars[16+1]="@~`.,^#*-_=\\/%{}";
121 	int t,s;
122 
123 	wPlayerExplosion=newpad(1,PLAYERWIDTH);		// new pad
124 	wattrset(wPlayerExplosion,COLOR_PAIR(YELLOW));	// set color
125 
126 	for(t=0;t<5;t++){ 			// 5 frames
127 		wclear(wPlayerExplosion);	// clear pad
128 		for(s=0;s<PLAYERWIDTH;s++){
129 			waddch(wPlayerExplosion,playerExplosionChars[rand()%16]);	// sprite
130 		}
131 
132 		copywin(wPlayerExplosion,wBattleField,0,0,y,x,y,x+PLAYERWIDTH-1,0); 	// display explostion
133 		wrefresh(wBattleField); 	// refresh battelfield to display explosion frames
134 		doSleep(100000);		// play animation not too fast
135 	}
136 
137 
138 } // todo: kann man bestimmt noch besser machen.
139 
140 
141 /**
142  * initialize aliens sprites
143  */
aliensInit()144 static void aliensInit()
145 {
146 	wAliens = newpad(ALIENS_MAX_NUMBER_Y*2,ALIENS_MAX_NUMBER_X*3);
147 	wclear(wAliens);
148 }
149 
150 
151 /**
152  * display aliens sprite
153  */
aliensDisplay(int x,int y,int wid,int hgt)154 void aliensDisplay(int x, int y, int wid, int hgt)
155 {
156 	copywin(wAliens,wBattleField,0,0,y,x,y+hgt,x+wid+2,0);
157 }
158 
159 
160 /**
161  * clear aliens sprite
162  */
aliensClear(int x,int y,int wid,int hgt)163 void aliensClear(int x, int y, int wid, int hgt)
164 {
165 	copywin(wEmpty,wBattleField,0,0,y,x,y+hgt,x+wid+2,0);
166 }
167 
168 
169 /**
170  * initialize missile sprites
171  */
aliensMissileInit()172 static void aliensMissileInit()
173 {
174 	wAliensMissile = newpad(1, 1);		// new pad
175 	wclear(wAliensMissile);			// clear pad
176 	wattrset(wAliensMissile, COLOR_PAIR(CYAN));	// set color
177 	waddch(wAliensMissile, ':');			// set sprite
178 }
179 
180 
181 /**
182  * display missile sprite
183  */
aliensMissileDisplay(int x,int y)184 void aliensMissileDisplay(int x, int y)
185 {
186 	copywin(wAliensMissile,wBattleField,0,0,y,x,y,x,0);
187 }
188 
189 
190 /**
191  * clear missile sprite
192  */
aliensMissileClear(int x,int y)193 void aliensMissileClear(int x, int y)
194 {
195 	copywin(wEmpty,wBattleField,0,0,y,x,y,x,0);
196 }
197 
198 
199 /**
200  * refresh aliens sprite
201  */
aliensRefresh(int level,int * pAliens)202 void aliensRefresh(int level, int *pAliens)
203 {
204 	static int frame = 0; // used for animation; mod 2 == 0: frame1, mod2 == 1: frame2
205 	int k,row;
206 	int c = 0;
207 	int alienType = 0;
208 	char ships[2][9][3+1] = {
209 		{",^,", "_O-", "-o-",  "o=o", "<O>", "_x_", "*^*", "\\_/", "o o"},
210 		{".-.", "-O_", "/o\\", "o-o", "<o>", "-x-", "o^o", "/~\\", "oo "}
211 	};
212 	int colors[9] = {RED, GREEN, BLUE, RED, YELLOW, WHITE, WHITE, YELLOW, RED};
213 
214 	wclear(wAliens);						// clear pad
215 	wattrset(wAliens,COLOR_PAIR(RED));				// set color
216 
217 	frame++;						// next frame
218 
219 	// draw alien if there is one
220 	for (row = 0; row < ALIENS_MAX_NUMBER_Y*2; row++) {
221 		for (k = 0; k < ALIENS_MAX_NUMBER_X; k++) {
222 			if ((row % 2) == 0) {			// display aliens every even row
223 				alienType = *(pAliens + c * (ALIENS_MAX_NUMBER_X) + k); 	// get type of alien //alienBlock[c][k]
224 
225 				if (alienType != 0) {		// if there is an alien to display
226 					wattrset(wAliens,COLOR_PAIR(colors[alienType-1]));		   // set color
227 					waddch(wAliens,ships[frame%2][alienType-1+(3*((level-1)%3))][0]);  // set char1
228 					waddch(wAliens,ships[frame%2][alienType-1+(3*((level-1)%3))][1]);  // set char2
229 					waddch(wAliens,ships[frame%2][alienType-1+(3*((level-1)%3))][2]);  // set char3
230 					if (alienType > 4) {
231 						*(pAliens + c * ALIENS_MAX_NUMBER_X + k) = (alienType + 1) % 9;
232 					} // todo: what's that? If alien_type > 4 then do a modulo operation???
233 				} else {
234 					waddstr(wAliens,"   ");	// no alien
235 				}
236 
237 			} else {
238 				waddstr(wAliens,"   ");		// no aliens at odd rows
239 			}
240 		}
241 		if ((row % 2) == 1) {c++;} // goto next row at alienblock
242 	}
243 }
244 
245 
246 /**
247  * initialize bunkers sprites
248  */
bunkersInit()249 static void bunkersInit()
250 {
251 	wBunkers = newpad(BUNKERHEIGHT, BUNKERWIDTH);		// new pad data
252 	wclear(wBunkers);
253 }
254 
255 
256 /**
257  * display bunkers sprite
258  * needs pointer to bunker-array
259  */
bunkersDisplay(int * pBunker)260 void bunkersDisplay(int *pBunker)
261 {
262 	int l, k;
263 	wclear(wBunkers);
264 	wattrset(wBunkers,COLOR_PAIR(CYAN));
265 	for (l=0;l<BUNKERHEIGHT;l++) {
266 		for (k=0;k<BUNKERWIDTH;k++) {
267 			if (*(pBunker + (l * (BUNKERWIDTH + 1)) + k) == 1) {	//if (pBunker[l][k]==1) {
268 				waddch(wBunkers,'#');
269 			} else {
270 				waddch(wBunkers,' ');
271 			}
272 		}
273 	}
274 
275 	copywin(wBunkers, wBattleField, 0, 0, BUNKERY, BUNKERX, BUNKERY + BUNKERHEIGHT - 1, BUNKERX + BUNKERWIDTH - 1, 0);
276 }
277 
278 
279 /**
280  * clear bunkers sprite
281  */
bunkersClear()282 void bunkersClear()
283 {
284 	copywin(wEmpty, wBattleField, 0, 0, BUNKERY, BUNKERX, BUNKERY + BUNKERHEIGHT - 1, BUNKERX + BUNKERWIDTH - 1, 0);
285 }
286 
287 
288 /**
289  * clear one element of bunkers sprite at position (x, y)
290  */
bunkersClearElement(int x,int y)291 void bunkersClearElement(int x, int y)
292 {
293 	copywin(wEmpty, wBattleField, 0, 0, y, x, y, x, 0);
294 }
295 
296 
297 /**
298  * set actual sprite for ufo animation
299  */
ufoRefresh()300 void ufoRefresh()
301 {
302 	char ufo[4][6] = {"<o o>", "<oo >", "<o o>", "< oo>"};
303 	static int frame = 0;
304 
305 	wclear(wUfo);
306         wattrset(wUfo, COLOR_PAIR(MAGENTA));
307 	waddstr(wUfo, ufo[frame % 4]);
308 
309 	frame++;
310 }
311 
312 
313 /**
314  * initialize ufo sprite
315  */
ufoInit()316 static void ufoInit()
317 {
318 	wUfo = newpad(1, UFOWIDTH);	     // new pad with appropriate size
319 	wclear(wUfo);    		     // clear pad
320         wattrset(wUfo, COLOR_PAIR(MAGENTA)); // set color
321 }
322 
323 
324 /**
325  * display ufo sprite
326  */
ufoDisplay(int x,int y)327 void ufoDisplay(int x, int y)
328 {
329 	copywin(wUfo, wBattleField, 0, 0, y, x, y, x + UFOWIDTH - 1, 0);
330 }
331 
332 
333 /**
334  * clear ufo sprite
335  */
ufoClear(int x,int y)336 void ufoClear(int x, int y)
337 {
338 	copywin(wEmpty, wBattleField, 0, 0, y, x, y, x + UFOWIDTH - 1, 0);
339 }
340 
341 
342 /**
343  * initialize gameover graphic
344  */
gameOverInit()345 static void gameOverInit()
346 {
347 	// init game-over banner
348 	wGameOver = newpad(13, 31);
349 	wclear(wGameOver);
350 	wattrset(wGameOver, COLOR_PAIR(WHITE));
351 	waddstr(wGameOver, "                               ");
352 	waddstr(wGameOver, "  #####   ####  ##   ## ###### ");
353 	waddstr(wGameOver, " ##      ##  ## ####### ##     ");
354 	waddstr(wGameOver, " ## ###  ###### ## # ## #####  ");
355 	waddstr(wGameOver, " ##  ##  ##  ## ##   ## ##     ");
356 	waddstr(wGameOver, "  #####  ##  ## ##   ## ###### ");
357 	waddstr(wGameOver, "                               ");
358 	waddstr(wGameOver, "  ####  ##   ## ###### ######  ");
359 	waddstr(wGameOver, " ##  ## ##   ## ##     ##   ## ");
360 	waddstr(wGameOver, " ##  ##  ## ##  #####  ######  ");
361 	waddstr(wGameOver, " ##  ##  ## ##  ##     ##  ##  ");
362 	waddstr(wGameOver, "  ####    ###   ###### ##   ## ");
363 	waddstr(wGameOver, "                               ");
364 }
365 
366 /**
367  * display game over graphic
368  */
gameOverDisplay()369 void gameOverDisplay()
370 {
371 	int x = (SCREENWIDTH / 2) - (31 / 2);
372 	int y = (SCREENHEIGHT / 2) - (13 / 2);
373 	copywin(wGameOver, wBattleField, 0, 0, y, x, y + 12, x + 30, 0);
374 	wrefresh(wBattleField);
375 }
376 
377 
378 /**
379  * initialize title screen
380  */
titleScreenInit()381 static void titleScreenInit()
382 {
383 	wTitleScreen = newpad(SCREENHEIGHT, SCREENWIDTH);
384 	wclear(wTitleScreen);
385 }
386 
387 
388 /**
389  * display title screen
390  */
titleScreenDisplay()391 void titleScreenDisplay()
392 {
393 	static int frame = 0;
394 	int x, y;
395 	int i;
396 	WINDOW *wTitleText;
397 	WINDOW *wAliens;
398 	WINDOW *wStartText;
399 	char ufo[4][6] = {"<o o>", "<oo >", "<o o>", "< oo>"};
400 	char aliens[2][9][3+1] = {
401 		{",^,", "_O-", "-o-",  "o=o", "<O>", "_x_", "*^*", "\\_/", "o o"},
402 		{".-.", "-O_", "/o\\", "o-o", "<o>", "-x-", "o^o", "/~\\", "oo "}
403 	};
404 	int score[3] = {200, 150, 100};
405 	int colors[9] = {RED, GREEN, BLUE, RED, GREEN, BLUE, RED, GREEN, BLUE};
406 	char buffer[12];
407 	static int alien_type = 0;
408 
409 	wTitleText = newpad(4, 41);
410 	wclear(wTitleText);
411 	wattrset(wTitleText, COLOR_PAIR(YELLOW));
412 	waddstr(wTitleText, "        ____                 __          ");
413 	waddstr(wTitleText, "  ___  /  _/__ _  _____  ___/ /__ _______");
414         waddstr(wTitleText, " / _ \\_/ // _ \\ |/ / _ `/ _  / -_) __(_-<");
415 	waddstr(wTitleText, "/_//_/___/_//_/___/\\_,_/\\_,_/\\__/_/ /___/");
416 
417 	frame++;
418 	wAliens = newpad(7, 11);
419 	wclear(wAliens);
420 	snprintf(buffer, sizeof(buffer),"%s = 500", ufo[frame % 4]);
421 	wattrset(wAliens, COLOR_PAIR(MAGENTA));
422 	waddstr(wAliens, buffer);
423 	if ((frame = frame % 60) == 0) {
424 		alien_type = 0;
425 	} else if (frame == 20) {
426 		alien_type = 3;
427 	} else if (frame == 40) {
428 		alien_type = 6;
429 	}
430 	for (i = alien_type; i < alien_type + 3; i++) {
431 		waddstr(wAliens, "           ");
432 		snprintf(buffer, sizeof(buffer), "%s   = %d", aliens[frame % 2][i], score[i % 3]);
433 		wattrset(wAliens, COLOR_PAIR(colors[i]));
434 		waddstr(wAliens, buffer);
435 	}
436 
437 	wStartText = newpad(1, 20);
438 	wclear(wStartText);
439 	wattrset(wStartText, COLOR_PAIR(RED));
440 	waddstr(wStartText, "Press SPACE to start");
441 
442 	x = (SCREENWIDTH / 2) - (41 / 2);
443 	y = 0;
444 	copywin(wTitleText, wTitleScreen, 0, 0, y, x, y + 3, x + 40, 0);
445 
446 	x = (SCREENWIDTH / 2) - (11 / 2);
447 	y = 8;
448 	copywin(wAliens, wTitleScreen, 0, 0, y, x , y + 6, x + 10, 0);
449 
450 	x = (SCREENWIDTH / 2) - (20 / 2);
451 	y = SCREENHEIGHT - 2;
452 	copywin(wStartText, wTitleScreen, 0, 0, y, x, y, x + 19, 0);
453 
454 	copywin(wTitleScreen, wBattleField, 0, 0, 0, 0, SCREENHEIGHT-1, SCREENWIDTH-1, 0);
455 
456 	wrefresh(wBattleField);
457 }
458 
459 
460 /**
461  * clear title screen
462  */
titleScreenClear()463 void titleScreenClear()
464 {
465 	battleFieldClear();
466 }
467 
468 
469 /**
470  * initialize scores
471  */
statusInit()472 void statusInit()
473 {
474 	wStatus = newpad(1, 55);
475 	wclear(wStatus);
476 }
477 
478 
479 /**
480  * display scores
481  */
statusDisplay(int level,int score,int lives)482 void statusDisplay(int level, int score, int lives)
483 {
484 	int t, xOffset;
485 	char strStatus[55];
486 	// "Level: 01 Score: 0001450 Lives: /-\ /-\ /-\ /-\ /-\ "
487 	// "1234567890123456789012345678901234567890123456789012"
488 
489 
490 	xOffset = (SCREENWIDTH / 2) - 24;
491 
492 
493 
494 	sprintf (strStatus, "Level: %2.2d Score: %2.7d Lives: ", level, score);
495 
496 	wclear(wStatus);
497 	wattrset(wStatus, COLOR_PAIR(RED));
498 	waddstr(wStatus, strStatus);
499 
500 	// show maximal five lives
501 	for (t = 1; ((t <= 5) && (t < lives)); t++){
502 		waddstr(wStatus, "/-\\ ");
503 	}
504 
505 	copywin(wStatus, wBattleField, 0, 0, SCREENHEIGHT-1, xOffset, SCREENHEIGHT-1, xOffset + 54, 0);
506 
507 
508 }
509 
510 
511 /**
512  * initialize battlefield
513  */
battleFieldInit()514 static void battleFieldInit()
515 {
516 	wEmpty = newpad(SCREENHEIGHT, SCREENWIDTH);
517 	wclear(wEmpty);
518 
519 	wBattleField = newwin(SCREENHEIGHT, SCREENWIDTH, 0, 0);	// new window
520 	wclear(wBattleField);						// clear window
521 	mvwin(wBattleField, 0, 0);					// move window
522 }
523 
524 
525 /**
526  * clear battlefield
527  */
battleFieldClear()528 void battleFieldClear()
529 {
530 	copywin(wEmpty,wBattleField,0,0,0,0,SCREENHEIGHT-1,SCREENWIDTH-1,0);
531 }
532 
533 
534 /**
535  * refresh screen so that modified graphic buffers get visible
536  */
refreshScreen()537 void refreshScreen()
538 {
539 	redrawwin(wBattleField); // needed to display graphics properly at startup on some terminals
540 	wrefresh(wBattleField);
541 
542 }
543 
544 
545 /**
546  * do proper cleanup
547  */
finish(int sig)548 static void finish(int sig)
549 {
550 	endwin();	// <curses.h> reset terminal into proper non-visual mode
551 	exit(0);
552 }
553 
554 
555 /**
556  * initialize n_courses
557  */
graphicEngineInit()558 void graphicEngineInit()
559 {
560 	(void) signal(SIGINT, finish);	// <signal.h> on signal "SIGINT" call method "finish"
561 	(void) initscr();		// <curses.h> do initialization work
562 	keypad(stdscr, TRUE);		// <curses.h> enable keypad for input
563 	(void) nonl();			// <curses.h> disable translation return/ newline for detection of return key
564 	(void) cbreak();		// <curses.h> do not buffer typed characters, use at once
565 	(void) noecho();		// <curses.h> do not echo typed characters
566 	start_color();			// <curses.h> use colors
567 	init_pair(RED, COLOR_RED, COLOR_BLACK);		// <curses.h> define color-pair
568 	init_pair(GREEN, COLOR_GREEN, COLOR_BLACK);	// <curses.h> define color-pair
569 	init_pair(YELLOW, COLOR_YELLOW, COLOR_BLACK);	// <curses.h> define color-pair
570 	init_pair(BLUE, COLOR_BLUE, COLOR_BLACK);	// <curses.h> define color-pair
571 	init_pair(CYAN, COLOR_CYAN, COLOR_BLACK);	// <curses.h> define color-pair
572 	init_pair(MAGENTA, COLOR_MAGENTA, COLOR_BLACK);	// <curses.h> define color-pair
573 	init_pair(WHITE, COLOR_WHITE, COLOR_BLACK);	// <curses.h> define color-pair
574 
575 	//timeout(0); 			// <curses.h> do not wait for input
576 
577 	// initialize sprites
578 	battleFieldInit();
579 	playerInit();
580 	playerMissileInit();
581 	aliensInit();
582 	aliensMissileInit();
583 	bunkersInit();
584 	ufoInit();
585 	gameOverInit();
586 	statusInit();
587 	titleScreenInit();
588 }
589 
590