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 "aliens.h"
26 #include "player.h"
27 #include "nInvaders.h"
28 
29 /**
30  * initialize aliens attributes
31  */
aliensReset()32 void aliensReset()
33 {
34 	int i,j;
35 
36 	// three different types of aliens [5], [10]
37 	int level[ALIENS_MAX_NUMBER_Y][ALIENS_MAX_NUMBER_X]={
38 		{1,1,1,1,1,1,1,1,1,1},
39 		{2,2,2,2,2,2,2,2,2,2},
40 		{2,2,2,2,2,2,2,2,2,2},
41 		{3,3,3,3,3,3,3,3,3,3},
42 		{3,3,3,3,3,3,3,3,3,3}
43 	};
44 
45 	aliensClear(aliens.posX, aliens.posY, aliens.right, aliens.bottom);	// clear old position of aliens
46 
47 	// reset alien position
48 	aliens.posX = 0;
49 	aliens.posY = 0;
50 	aliens.right = 0;
51 	aliens.bottom = 0;
52 	aliens.left = 0;
53 	aliens.speed = 1;
54 
55 	// copy level-array to enemy-array
56 	for (i=0;i<ALIENS_MAX_NUMBER_X;i++) {
57 		for (j=0;j<ALIENS_MAX_NUMBER_Y;j++) {
58 			alienBlock[j][i]=level[j][i];
59 		}
60 	}
61 
62 	// reset missiles
63 	for (i = 0; i < ALIENS_MAX_MISSILES; i++) {
64 		if (alienshotx[i] != 0) {
65 			aliensMissileClear(alienshotx[i],alienshoty[i]);	// clear old position
66 		}
67 		alienshotx[i] = 0;  // start with zero values
68 		alienshoty[i] = 0;  // start with zero values
69 	}
70 	alienshotnum = 1;	    // one missile at the same time
71 	alienshotx[0] = 5;	    // x position of first alienshot
72 	alienshoty[0] = 1;	    // y position of first alienshot
73 
74 }
75 
76 /**
77  * initialize bunkers attributes
78  */
bunkersReset()79 void bunkersReset()
80 {
81 	int a, b;
82 
83 	// set position of bunker sprites. user graphical char bunkerd for better visual overview
84 	// and set according to this the bunker-array
85 	char bunkerd[BUNKERHEIGHT][BUNKERWIDTH+1] = {
86 		"        ###                 ###                 ###                 ###         ",
87 		"       #####               #####               #####               #####        ",
88 		"      #######             #######             #######             #######       ",
89 		"      ##   ##             ##   ##             ##   ##             ##   ##       "
90 	};
91 	//       12345678901234567890123456789012345678901234567890123456789012345678901234567890
92 	// 80 characters wide
93 
94 	// copy graphical "bunkerd" to binary "bunker"
95 	for (a = 0; a < BUNKERWIDTH; a++) {
96 		for (b = 0; b < BUNKERHEIGHT; b++) {
97 			if (bunkerd[b][a] == '#')
98 				bunker[b][a] = 1;
99 			else
100 				bunker[b][a] = 0;
101 		}
102 	}
103 
104 	// display bunkers sprite
105 	bunkersDisplay(&bunker[0][0]);
106 }
107 
108 /**
109  * move aliens and test if they've reached the
110  * bottom of the windows or the bunkers.
111  */
aliensMove()112 int aliensMove()
113 {
114 
115 	int cx,cy;
116 	int fReachedPlayer=0; 				// return value
117 
118 	render();
119 	aliensClear(aliens.posX, aliens.posY, aliens.right, aliens.bottom);	// clear old position of aliens
120 
121 	aliens.posX = aliens.posX + aliens.speed;			// move aliens left/ right
122 
123 	// when aliens reached left or right screen-border
124 	if (aliens.posX == (BUNKERWIDTH + BUNKERX - 5 - aliens.right) || aliens.posX == (BUNKERX + aliens.left)) {
125 
126 		aliens.posY++;				// move aliens downwards
127 
128 		// aliens reached player
129 		if (aliens.posY == SCREENHEIGHT - 2 - aliens.bottom) {
130 			fReachedPlayer = 1;		// set return value
131 		}
132 
133 		// aliens reached bunkers //funzt nicht ganz: todo
134 		if (aliens.posY == BUNKERY - aliens.bottom) {
135 			// clear bunkers
136 			for(cx=0;cx<BUNKERWIDTH;cx++) {
137 				for(cy=0;cy<BUNKERHEIGHT;cy++) {
138 					bunker[cy][cx]=0;
139 				}
140 			}
141 			bunkersClear();	// clear bunkers sprites
142 		}
143 
144 		aliens.speed = aliens.speed * (-1);		  // change direction of aliens' movements
145 	}
146 
147 	aliensDisplay(aliens.posX, aliens.posY, aliens.right, aliens.bottom); // display aliens at new position
148 
149 	return fReachedPlayer;				  // return if aliens reached player
150 }
151 
152 
153 /**
154  * display alien animation, display remaining parts of aliens and bunker
155  */
render()156 void render()
157 {
158 	int k,row;
159 	int c=0;
160 
161 	// calculate left, right, bottom, lowest_ship
162 	aliens.left=1;
163 	aliens.right=-1;
164 	aliens.bottom=-1;
165 	shipnum=0;
166 	for (k=0;k<11;k++) {
167 		lowest_ship[k]=-1;
168 	}
169 
170 	for (row=0;row<ALIENS_MAX_NUMBER_Y*2;row++) {
171 		if ((row%2)==0){
172 			for (k=0;k<ALIENS_MAX_NUMBER_X;k++) {
173 				if (alienBlock[c][k] != 0) {
174 					lowest_ship[k]=row;
175 					shipnum++;
176 					if (aliens.left==1 || -k>aliens.left) {aliens.left=-k;}
177 					if (aliens.right==-1 || k>aliens.right) {aliens.right=k;}
178 					if (aliens.bottom==-1 || c>aliens.bottom) {aliens.bottom=c;}
179 				}
180 			}
181 		} else {
182 			c++;
183 		}
184 	}
185 	aliens.bottom=aliens.bottom*2;	// every 2nd row is an empty row
186 	aliens.left=aliens.left*3; // alien sprite is 3 chars wide
187 	aliens.right=aliens.right*3; // alien sprite is 3 chars wide
188 
189 	// display remaining aliens with animation
190 	aliensRefresh(level, &alienBlock[0][0]);
191 
192 }
193 
194 
195 /**
196  * move aliens' missiles and do player/bunker hit testing
197  * a zero value in alienshotx indicates that the appropriate missile is loaded, but not fired
198  */
aliensMissileMove()199 int aliensMissileMove()
200 {
201 	int i, tmp;
202 	int fPlayerWasHit = 0;
203 	int shootThreshold;
204 	static int alienshot_counter = 0;
205 
206 
207 	// calculate threshold when next missile should be fired
208 	// it is done here to save calculation time in for-instruction
209 	shootThreshold = (skill_level * 8) * (shipnum + 2);
210 	alienshot_counter = alienshot_counter + 10 ;
211 
212 	// loop all possible missiles
213 	for (i = 0; i < ALIENS_MAX_MISSILES; i++) {
214 
215 		// if the current missile is flying we should do movements
216 		if (alienshotx[i] != 0) {
217 
218 			aliensMissileClear(alienshotx[i],alienshoty[i]);	// clear old position
219 
220 			// if missile hit the bunkers
221 			if (bunkersHitCheck(alienshotx[i], alienshoty[i]) == 1) {
222 				alienshotx[i] = 0;		// value of zero reloads missile
223 			}
224 
225 			alienshoty[i]++;			// move missile downwards
226 
227 			// check if player was hit by an alien missile
228 			if (playerHitCheck(alienshotx[i], alienshoty[i]) == 1) {
229 				alienshotx[i] = 0;		// value of zero reloads missile
230 				fPlayerWasHit = 1;
231 			}
232 
233 
234 		} else {					// missile not launched yet
235 
236 			// start new missile if counter says so
237 			if (alienshot_counter > shootThreshold && shipnum > 0) {// only shot if there's an alien left
238 				alienshot_counter = 0;				// reset counter
239 				tmp = random() % ALIENS_MAX_NUMBER_X;  		// randomly select one of the ...
240 				while (lowest_ship[tmp] == -1) {		// ...aliens at the bottom of ...
241 					tmp = random() % ALIENS_MAX_NUMBER_X;	// ...a column to launch missile
242 				}
243 				alienshoty[i]=aliens.posY+lowest_ship[tmp];		// set y position of missile
244 				alienshotx[i]=aliens.posX+tmp*3;			// set x position of missile
245 			}
246 		} // if
247 
248 		// display missiles if still running or just launched; could have been modified in the above code
249 		if (alienshotx[i] != 0) {
250 			// if missile is out of battlefield
251 			if (alienshoty[i] == SCREENHEIGHT - 1) {
252 				alienshotx[i] = 0;	// reload missile
253 			} else {
254 				aliensMissileDisplay(alienshotx[i], alienshoty[i]); // display Missile at new position
255 			}
256 		}
257 
258 	} // for
259 
260 
261 	return fPlayerWasHit;
262 }
263 
264 
265 
266 /**
267  * check if missile hit an alien
268  */
aliensHitCheck(int shotx,int shoty)269 int aliensHitCheck(int shotx, int shoty)
270 {
271 	int alienType = 0;
272 	int shipx, shipy;
273 	// if missile is within alien-rectangle
274 	if (shotx >= aliens.posX && shotx <= aliens.posX + ALIENS_MAX_NUMBER_X * 3 - 1
275 	    && shoty >= aliens.posY && shoty <= aliens.posY + (ALIENS_MAX_NUMBER_Y - 1) * 2) {
276 		// calculate the ship that was hit
277 		shipx = (shotx - aliens.posX) / 3;
278 		shipy = (shoty - aliens.posY) / 2;
279 		// if there is still a ship at this position
280 		alienType = alienBlock[shipy][shipx];
281 		if (alienType != 0) {
282 			alienBlock[shipy][shipx] = 0;	// delete alien ship
283 		}
284 	}
285 	return alienType; 	// returns 0 if no alien was hit, else returns type-code of alien
286 }
287 
288 /**
289  * check if missile hit an element of bunker
290  */
bunkersHitCheck(int shotx,int shoty)291 int bunkersHitCheck(int shotx, int shoty)
292 {
293 	int adjx, adjy;
294 	int fBunkerWasHit = 0;
295 	// if missile is within bunker-rectangle
296 	if (shotx >= BUNKERX && shotx < BUNKERX + BUNKERWIDTH
297 	    && shoty >= BUNKERY && shoty < BUNKERY + BUNKERHEIGHT) {
298 		// calculate the element of the bunker that was hit
299 		adjy = shoty - BUNKERY;
300 		adjx = shotx - BUNKERX;
301 		// if there is still an element
302 		if(bunker[adjy][adjx] == 1){
303 			bunker[adjy][adjx] = 0;	// delete element
304 			fBunkerWasHit = 1; 		// bunker was hit!
305 		}
306 	}
307 	return fBunkerWasHit;
308 }
309