1 // Apricots all routine
2 // Author: M.D.Snellgrove
3 // Date: 26/3/2002
4 // History:
5
6 // Changes by M Snellgrove 6/7/2003
7 // drand() function needed for Windows portability now located here
8
9 #include "apricots.h"
10
11 // Random number generator function
12
drand()13 double drand(){
14
15 return (((double)(rand() % RAND_MAX)) / ( ((double)RAND_MAX) - 1.0 ));
16
17 }
18
19 // Wrap function
20
wrap(int n,int min,int max)21 int wrap(int n, int min, int max){
22
23 return ((((n-min) % (max-min)) + max-min) % (max-min)) + min;
24
25 }
26
27 // Limit function (integers)
28
limit(int n,int min,int max)29 int limit(int n, int min, int max){
30
31 if (n > max) return max;
32 if (n < min) return min;
33 return n;
34
35 }
36
37 // Limit function (doubles)
38
dlimit(double n,double min,double max)39 double dlimit(double n, double min, double max){
40
41 if (n > max) return max;
42 if (n < min) return min;
43 return n;
44
45 }
46
47 // Sign function
48
sign(int n)49 int sign(int n){
50
51 if (n > 0) return 1;
52 if (n < 0) return -1;
53 return 0;
54
55 }
56
57 // Animate smoke
58
animate_smoke(linkedlist<smoketype> & smoke)59 void animate_smoke(linkedlist <smoketype> &smoke){
60
61 smoke.reset();
62 while(smoke.next()){
63 smoke().y = smoke().y - (2.0*GAME_SPEED);
64 smoke().time++;
65 if (smoke().time == int(28/GAME_SPEED)) smoke.kill();
66 }
67
68 }
69
70 // Animate flames
71
animate_flames(linkedlist<firetype> & flame,linkedlist<smoketype> & smoke)72 void animate_flames(linkedlist <firetype> &flame,
73 linkedlist <smoketype> &smoke){
74
75 flame.reset();
76 while(flame.next()){
77 flame().time++;
78 if (flame().time % (int(10/GAME_SPEED)) == 0){
79 smoketype newsmoke;
80 newsmoke.x = flame().x;
81 newsmoke.y = flame().y;
82 newsmoke.time = 0;
83 smoke.add(newsmoke);
84 }
85 if (flame().time == int(280/GAME_SPEED)) flame.kill();
86 }
87
88 }
89
90 // Animate explosions
91
animate_explosions(linkedlist<firetype> & explosion)92 void animate_explosions(linkedlist <firetype> &explosion){
93
94 explosion.reset();
95 while(explosion.next()){
96 explosion().time++;
97 int maxtime = 0;
98 switch(explosion().type){
99 case 0:
100 maxtime = int(14/GAME_SPEED);
101 break;
102 case 1:
103 maxtime = int(22/GAME_SPEED);
104 break;
105 case 2:
106 maxtime = int(4/GAME_SPEED);
107 break;
108 case 3:
109 maxtime = int(20/GAME_SPEED);
110 break;
111 case 4:
112 maxtime = int(5/GAME_SPEED);
113 break;
114 }
115 if (explosion().time == maxtime) explosion.kill();
116 }
117
118 }
119
120 // Rotate radars
121
rotate_radars(linkedlist<radartype> & radar)122 void rotate_radars(linkedlist <radartype> &radar){
123
124 radar.reset();
125 while(radar.next()){
126 radar().rotate = wrap(radar().rotate+1,0,int(3/GAME_SPEED));
127 if (radar().rotate == 0) radar().image =
128 wrap(radar().image+1,238,246);
129 }
130
131 }
132
133 // Decay lasers
134
decay_lasers(linkedlist<lasertype> & laser)135 void decay_lasers(linkedlist <lasertype> &laser){
136
137 laser.reset();
138 while (laser.next()){
139 laser().time--;
140 if (laser().time == 0) laser.kill();
141 }
142
143 }
144
145 // Clone planes (for collision detection purposes)
146
clone_planes(linkedlist<plane> & p,linkedlist<planeclone> & dp,int mission,int & winner)147 void clone_planes(linkedlist <plane> &p, linkedlist <planeclone> &dp,
148 int mission, int &winner){
149
150 // Do the cloning
151 p.reset();
152 dp.reset();
153 while (p.next()){
154 dp.next();
155 dp().x = p().x;
156 dp().y = p().y;
157 dp().xs = p().xs;
158 dp().ys = p().ys;
159 dp().d = p().d;
160 dp().state = p().state;
161 dp().hide = p().hide;
162 // Conduct Scoreloss
163 p().score -= dp().scoreloss;
164 dp().scoreloss = 0;
165 p().targetscore = dp().buildingwin;
166 // Check for mission 2 win
167 if ((mission == 2) && (dp().buildingwin == 0) && (p().land == 0) &&
168 (!p().drak)){
169 winner = p().side;
170 p().targetx = -10;
171 }
172 }
173
174 }
175
176 // Check for planes colliding with each other
177
plane_collisions(gamedata & g)178 void plane_collisions(gamedata &g){
179
180 g.p.reset();
181 while (g.p.next()){
182 g.dp.reset();
183 while (g.dp.next()){
184 if (g.p().id > g.dp().id){
185 if ((g.p().state<3) && (g.dp().state<3) &&
186 ((g.p().state<2) || (g.dp().state<2))){
187 if (g.images[g.p().image+g.p().d].collide(int(g.p().x),int(g.p().y),
188 g.images[g.dp().image+g.dp().d],int(g.dp().x),int(g.dp().y))){
189 // Planes have collided
190 if (g.p().state < 2) g.p().score -= 25;
191 g.p().state = 2;
192 g.p().land = 2;
193 g.p().xs = g.p().xs * 0.5;
194 g.p().ys = g.p().ys * 0.5;
195 g.p().s = 0.0;
196 g.dp().collide = true;
197 firetype bang;
198 bang.x = int(g.p().x);
199 bang.y = int(g.p().y);
200 bang.type = 0;
201 bang.time = 0;
202 g.explosion.add(bang);
203 falltype shrapnel;
204 shrapnel.x = g.p().x + 6.0;
205 shrapnel.y = g.p().y;
206 shrapnel.xs = g.p().xs;
207 shrapnel.ys = g.p().ys;
208 shrapnel.image = g.p().shrapnelimage + int(drand()*3);
209 shrapnel.type = 1;
210 g.fall.add(shrapnel);
211 g.sound.play(SOUND_EXPLODE);
212 }
213 }
214 }
215 }
216 }
217
218 // Check to see if plane is already hit by another
219 g.p.reset();
220 g.dp.reset();
221 while (g.p.next()){
222 g.dp.next();
223 if (g.dp().collide){
224 if (g.p().state < 2) g.p().score -= 25;
225 g.p().state = 2;
226 g.p().land = 2;
227 g.p().xs = g.p().xs * 0.5;
228 g.p().ys = g.p().ys * 0.5;
229 g.p().s = 0.0;
230 g.dp().collide = false;
231 falltype shrapnel;
232 shrapnel.x = g.p().x + 6.0;
233 shrapnel.y = g.p().y;
234 shrapnel.xs = g.p().xs;
235 shrapnel.ys = g.p().ys;
236 shrapnel.image = g.p().shrapnelimage + int(drand()*3);
237 shrapnel.type = 1;
238 g.fall.add(shrapnel);
239 }
240 }
241
242 }
243
244 // Move falls
245
move_falls(gamedata & g)246 void move_falls(gamedata &g){
247
248 g.fall.reset();
249 while(g.fall.next()){
250 g.fall().ys += 0.1 * GAME_SPEED * GAME_SPEED;
251 g.fall().x += g.fall().xs;
252 g.fall().y += g.fall().ys;
253 if (g.fall().type == 3){
254 if (g.fall().rotatedelay == 0){
255 g.fall().image = wrap(g.fall().image+g.fall().bombrotate,115,123);
256 g.fall().rotatedelay = int(1/GAME_SPEED);
257 }else{
258 g.fall().rotatedelay--;
259 }
260 }
261 if (fall_collision(g, g.fall())){
262 g.fall.kill();
263 }
264
265 }
266
267 }
268
269 // Move shots
270
move_shots(linkedlist<shottype> & shot,shape & ground,shape & shotimage,shape & drakmsimage,drakmstype & drakms)271 void move_shots(linkedlist <shottype> &shot, shape &ground, shape &shotimage,
272 shape &drakmsimage, drakmstype &drakms){
273
274 shot.reset();
275 while (shot.next()){
276 // move
277 shot().x += shot().xs;
278 shot().y += shot().ys;
279 shot().time--;
280 // ground collisions / off screen / timed out / drakms collision
281 if ((ground.collide(0, 0, shotimage, (int)shot().x, (int)shot().y)) ||
282 (shot().x < -16.0) || (shot().x > GAME_WIDTH) || (shot().y < -16.0) ||
283 (shot().y > GAME_HEIGHT) || (shot().time == 0) ||
284 ((drakms.exist == 1) && (drakmsimage.collide((int)drakms.x,(int)drakms.y,
285 shotimage,(int)shot().x,(int)shot().y)))){
286 shot.kill();
287 }
288 }
289
290 }
291
292 // Create shot from gun
293
gunshoot(guntype & gun,linkedlist<shottype> & shot,sampleio & sound,double xmove[17],double ymove[17])294 void gunshoot(guntype &gun, linkedlist <shottype> &shot, sampleio &sound,
295 double xmove[17], double ymove[17]){
296
297 int d = ((20-gun.d) % 16) + 1;
298 shottype shell;
299 shell.x = gun.x+6.0+12.0*xmove[d];
300 shell.y = gun.y+10.0+12.0*ymove[d];
301 shell.xs = 8.0*xmove[d]*GAME_SPEED;
302 shell.ys = 8.0*ymove[d]*GAME_SPEED;
303 shell.side = gun.side;
304 shell.time = int(40/GAME_SPEED);
305 shot.add(shell);
306 gun.ammo--;
307 gun.firedelay = int(3/GAME_SPEED);
308 sound.play(SOUND_GUNSHOT);
309
310 }
311
312 // Fire guns
fire_guns(linkedlist<guntype> & gun,linkedlist<plane> & p,sampleio & sound,building b[MAP_W * 2],linkedlist<shottype> & shot,double xmove[17],double ymove[17])313 void fire_guns(linkedlist <guntype> &gun, linkedlist <plane> &p, sampleio &sound,
314 building b[MAP_W*2], linkedlist <shottype> &shot,
315 double xmove[17], double ymove[17]){
316
317
318 gun.reset();
319 while (gun.next()){
320 // Find new target for gun if untargeted
321 if (gun().target == 0){
322 int maxfind = 200;
323 p.reset();
324 while (p.next()){
325 if ((gun().side != p().side) && (p().state < 2) && (p().land==2) &&
326 (gun().y > p().y) && (!p().hide)){
327 int dx = abs(gun().x - int(p().x));
328 if (dx < maxfind){
329 maxfind = dx;
330 gun().target = p().id;
331 }
332 }
333 }
334 }else{
335 // Track the target of the gun
336 p.reset();
337 while (p.next()){
338 if (p().id == gun().target){
339 p().gunthreat = gun().xpos;
340 double dx = p().x - double(gun().x);
341 double dy = double(gun().y) - p().y;
342 // Rotate gun
343 if ((gun().rotate == 0) && (dy > 0)){
344 double smartsine = (dy*p().xs+dx*p().ys)/
345 (8.0*GAME_SPEED*sqrt(dx*dx+dy*dy));
346 smartsine = dlimit(smartsine, -1.0, 1.0);
347 double smartangle = asin(smartsine);
348 int move = sign(int(((atan(dx/dy)+smartangle)*8.0/PI)+4.5)-gun().d);
349 if (move != 0){
350
351 gun().d = limit(gun().d+move,1,7);
352 b[gun().xpos].image = 162 + gun().d;
353 gun().rotate = int(2/GAME_SPEED);
354 }
355 }
356 // Shoot gun
357 if ((gun().firedelay == 0) && (gun().ammo > 0) && (abs(int(dx))<150)){
358 gunshoot(gun(), shot, sound, xmove, ymove);
359 }
360 // Lose target
361
362 if ((abs(int(dx))>200) || (p().state>1) || (p().hide) ||
363 (p().land !=2)){
364 gun().target = 0;
365 }
366 }
367 }
368 }
369 // Sort out guntimers
370 if (gun().firedelay > 0) gun().firedelay--;
371 if (gun().rotate > 0) gun().rotate--;
372 if (gun().ammo < 3){
373 gun().reload++;
374 if (gun().reload == int(20/GAME_SPEED)){
375 gun().reload = 0;
376 gun().ammo++;
377 }
378 }
379 }
380
381 }
382 // Do everything
383
all(gamedata & g)384 void all(gamedata &g){
385
386 rotate_radars(g.radar);
387 animate_smoke(g.smoke);
388 animate_flames(g.flame, g.smoke);
389 animate_explosions(g.explosion);
390 decay_lasers(g.laser);
391 clone_planes(g.p, g.dp, g.mission, g.winner);
392 plane_collisions(g);
393 move_falls(g);
394 move_shots(g.shot,g.gamemap.ground,g.images[114],g.images[318],g.drakms);
395 fire_guns(g.gun, g.p, g.sound, g.gamemap.b, g.shot, g.xmove, g.ymove);
396 if (g.drak) drak_main(g);
397
398 }
399