Commit | Line | Data |
---|---|---|
21c4e167 H |
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 | */ | |
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 | */ | |
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 | */ | |
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 | */ | |
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 | */ | |
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 | */ | |
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 | */ | |
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 | } |