1 // Apricots Drak routines
2 // Author: M.D.Snellgrove
3 // Date: 26/3/2002
4 // History:
5 
6 #include "apricots.h"
7 
8 // Setup Draks routine
9 
setup_draks(drakmstype & drakms,linkedlist<drakguntype> & drakgun)10 void setup_draks(drakmstype &drakms, linkedlist <drakguntype> &drakgun){
11 
12 // Setup Mothership
13   drakms = DRAKMSINIT;
14   drakms.x = drand() * (GAME_WIDTH-296) + 100.0;
15 // Setup Drakguns
16   drakgun.add(DGUN_LASER_LEFT);
17   drakgun.add(DGUN_LASER_RIGHT);
18   drakgun.add(DGUN_TOP_LEFT);
19   drakgun.add(DGUN_TOP_RIGHT);
20   drakgun.add(DGUN_SIDE_LEFT);
21   drakgun.add(DGUN_SIDE_RIGHT);
22 
23 }
24 
25 // Fire laser
26 
fire_laser(gamedata & g,drakguntype & drakgun,drakmstype & drakms,sampleio & sound,building b[MAP_W * 2],linkedlist<lasertype> & laser,int groundheight[MAP_W])27 void fire_laser(gamedata &g, drakguntype &drakgun, drakmstype &drakms, sampleio &sound,
28                 building b[MAP_W*2], linkedlist <lasertype> &laser,
29                 int groundheight[MAP_W]){
30 
31 // Warm up laser if already activated
32   if (drakgun.time > 0){
33     drakgun.time++;
34     drakgun.image[0] = 307 + int(drakgun.time*GAME_SPEED/4);
35   }
36 // Shoot laser
37   if (drakgun.time == int(23/GAME_SPEED)){
38 // Create laser images
39     drakgun.time = 0;
40     drakgun.image[0] = 305;
41     int targetx = drakms.targetx + drakms.targetmod + drakgun.type;
42     int laserx = drakgun.x + int(drakms.x);
43     int lasery = drakgun.y + int(drakms.y) + 4;
44     lasertype toplaser;
45     toplaser.x = laserx;
46     toplaser.y = lasery;
47     toplaser.image = 313;
48     toplaser.time = int(2/GAME_SPEED);
49     laser.add(toplaser);
50     for (int y = lasery+8; y<=groundheight[int(targetx/2)]-8; y+=8){
51       lasertype midlaser;
52       midlaser.x = laserx;
53       midlaser.y = y;
54       midlaser.image = 314;
55       midlaser.time = int(2/GAME_SPEED);
56       laser.add(midlaser);
57     }
58     lasertype endlaser;
59     endlaser.x = laserx;
60     endlaser.y = groundheight[int(targetx/2)] - 8;
61     endlaser.image = 314;
62     endlaser.time = int(2/GAME_SPEED);
63     laser.add(endlaser);
64 // Destroy buildings
65     if (b[targetx].type >= 3) killbuilding(g, b[targetx]);
66 // Destroy tower
67     if (b[targetx].type == 2){
68       for (int h = b[targetx].towersize; h>=0; h--){
69         killtower(g, b[targetx], 0.0, 0.0, h, 0);
70       }
71     }
72 // Destroy planes
73     g.p.reset();
74     while (g.p.next()){
75       if ((int(g.p().y) > lasery) && (abs(int(g.p().x)-laserx)<6) && (g.p().state < 2)){
76         g.p().score -= 25;
77         g.p().land = 2;
78         g.p().s = 0;
79         firetype boom;
80         boom.x = int(g.p().x);
81         boom.y = int(g.p().y);
82         boom.type = 0;
83         boom.time = 0;
84         g.explosion.add(boom);
85       }
86     }
87     sound.play(SOUND_LASER);
88   }
89 // Prime laser for firing
90   if ((drakgun.time == 0) && (drakms.movedelay > int(30/GAME_SPEED))){
91     int targetx = drakms.targetx + drakms.targetmod + drakgun.type;
92     if (b[targetx].type >= 2) drakgun.time = 1;
93   }
94 
95 }
96 
97 // Create shot from drakgun
98 
drakgunshoot(drakguntype & drakgun,drakmstype & drakms,linkedlist<shottype> & shot,sampleio & sound,double xmove[17],double ymove[17])99 void drakgunshoot(drakguntype &drakgun, drakmstype &drakms, linkedlist <shottype> &shot,
100                   sampleio &sound, double xmove[17], double ymove[17]){
101 
102   double ymod = 10.0;
103   if (drakgun.y == 20) ymod = 4.0;
104   shottype shell;
105   shell.x = drakms.x + drakgun.x+6.0+12.0*xmove[drakgun.d];
106   shell.y = drakms.y + drakgun.y+ymod+12.0*ymove[drakgun.d];
107   shell.xs = 8.0*xmove[drakgun.d]*GAME_SPEED;
108   shell.ys = 8.0*ymove[drakgun.d]*GAME_SPEED;
109   shell.side = 0;
110   shell.time = int(40/GAME_SPEED);
111   shot.add(shell);
112   drakgun.reload = int(5/GAME_SPEED);
113   sound.play(SOUND_GUNSHOT2);
114 
115 }
116 
117 // Fire drakguns
118 
fire_drakguns(gamedata & g,linkedlist<drakguntype> & drakgun,drakmstype & drakms,linkedlist<plane> & p,sampleio & sound,linkedlist<lasertype> & laser,building b[MAP_W * 2],linkedlist<shottype> & shot,int groundheight[MAP_W],double xmove[17],double ymove[17])119 void fire_drakguns(gamedata &g, linkedlist <drakguntype> &drakgun, drakmstype &drakms,
120                    linkedlist <plane> &p, sampleio &sound,
121                    linkedlist <lasertype> &laser,
122                    building b[MAP_W*2], linkedlist <shottype> &shot, int groundheight[MAP_W],
123                    double xmove[17], double ymove[17]){
124 
125   drakgun.reset();
126   while (drakgun.next()){
127     if (drakgun().type != 0){
128 // Fire the laser
129       fire_laser(g, drakgun(), drakms, sound, b, laser, groundheight);
130     }else{
131 // Fire more normal drakgun
132 // Find new target for drakgun if untargeted
133       if (drakgun().target == 0){
134         int maxfind = 200;
135         p.reset();
136         while (p.next()){
137           if ((0 != p().side) && (p().state < 2) && (!p().hide)){
138             int dx = int(drakms.x) + drakgun().x - int(p().x);
139             if (abs(dx) < maxfind){
140 // See if drakgun can point at potential target
141               int dy = int(drakms.y) + drakgun().y - int(p().y);
142               int targetd = wrap(int((atan2(double(dy),double(-dx))*8.0/PI)+13.5), 1, 17);
143               if (drakgun().image[targetd] != 0){
144                 maxfind = abs(dx);
145                 drakgun().target = p().id;
146               }
147             }
148           }
149         }
150       }else{
151 // Track the target of the drakgun
152         p.reset();
153         while (p.next()){
154           if (p().id == drakgun().target){
155             double dx = drakms.x + double(drakgun().x) - p().x;
156             double dy = drakms.y + double(drakgun().y) - p().y;
157 // Rotate drakgun
158             if (drakgun().rotate == 0){
159               double smartsine = (dy*p().xs-dx*p().ys)/
160                                  (8.0*GAME_SPEED*sqrt(dx*dx+dy*dy));
161               smartsine = dlimit(smartsine, -1.0, 1.0);
162               double smartangle = asin(smartsine);
163               int targetd = wrap(int(((atan2(dy,-dx)-smartangle)*8.0/PI)+13.5), 1, 17);
164               int move = sign(wrap(targetd - drakgun().d, -7, 9));
165               if (move != 0){
166                 int newd = wrap(drakgun().d + move, 1, 17);
167                 if (drakgun().image[newd] != 0){
168                   drakgun().d = newd;
169                   drakgun().rotate = int(2/GAME_SPEED);
170                 }else{
171                   drakgun().target = 0;
172                 }
173               }
174             }
175 // Shoot drakgun
176             if ((drakgun().reload == 0) && (drakgun().target > 0) && (abs(int(dx))<150)){
177               drakgunshoot(drakgun(), drakms, shot, sound, xmove, ymove);
178             }
179 // Lose target
180             if ((abs(int(dx))>200) || (p().state>1) || (p().hide)){
181               drakgun().target = 0;
182             }
183           }
184         }
185       }
186 // Sort out drakguntimers
187       if (drakgun().reload > 0) drakgun().reload--;
188       if (drakgun().rotate > 0) drakgun().rotate--;
189     }
190   }
191 }
192 
193 // Launch drak fighter
194 
launch_drakfighter(drakmstype & drakms,linkedlist<plane> & p,linkedlist<planeclone> & dp)195 void launch_drakfighter(drakmstype &drakms, linkedlist <plane> &p, linkedlist <planeclone> &dp){
196 
197 // Change counters
198   drakms.fightersout++;
199   drakms.launchdelay = int(50/GAME_SPEED);
200   drakms.movedelay += int(20/GAME_SPEED);
201   int drakid = 7;
202   if (drakms.fighter[0]) drakid = 8;
203   if ((drakms.fighter[0]) && (drakms.fighter[1])) drakid = 9;
204   drakms.fighter[drakid-7] = true;
205 // Create new drak fighter
206   plane newdrak = DRAK_FIGHTER;
207   newdrak.x = drakms.x + 40.0;
208   newdrak.y = drakms.y + 18.0;
209   newdrak.xs = drakms.xs;
210   newdrak.id = drakid;
211   p.add(newdrak);
212 // Create planeclone
213   planeclone newclone;
214   newclone.x = newdrak.x;
215   newclone.y = newdrak.y;
216   newclone.xs = newdrak.xs;
217   newclone.ys = newdrak.ys;
218   newclone.d = newdrak.d;
219   newclone.image = newdrak.image;
220   newclone.state = newdrak.state;
221   newclone.hide = newdrak.hide;
222   newclone.id = newdrak.id;
223   newclone.side = newdrak.side;
224   newclone.collide = false;
225   newclone.scoreloss = 0;
226   newclone.buildingwin = 0;
227   dp.add(newclone);
228 
229 }
230 
231 
232 // Drak main routine
233 
drak_main(gamedata & g)234 void drak_main(gamedata &g){
235 
236 // Control Mothership
237   switch(g.drakms.exist){
238     case 0: // Mothership not yet appeared
239       g.drakms.movedelay--;
240       if (g.drakms.movedelay == 0) g.drakms.exist = 1;
241       break;
242     case 1: // Mothership active
243       if (g.drakms.damage < 30){
244 // Move downwards
245         if (g.drakms.y < 38.0) g.drakms.y += 2.0*GAME_SPEED;
246 // Reset delay counters
247         if (g.drakms.launchdelay > 0) g.drakms.launchdelay--;
248         if (g.drakms.movedelay > 0){
249            g.drakms.movedelay--;
250            if (g.drakms.movedelay == 0) g.drakms.targetx = 0;
251         }
252 // Select target
253         if (g.drakms.targetx == 0){
254           g.drakms.targetx = int(drand()*(MAP_W*2-16)) + 8;
255           if (g.gamemap.b[g.drakms.targetx].type < 2){
256             g.drakms.targetx = 0;
257             g.drakms.movedelay = 1;
258           }else{
259 // Target found
260             g.drakms.targetmod = int(drand()*2)*2 - 1;
261             if ((g.drakms.lgun) && (!g.drakms.rgun)) g.drakms.targetmod = 1;
262             if ((!g.drakms.lgun) && (g.drakms.rgun)) g.drakms.targetmod = -1;
263           }
264 // Apply Brakes
265           if (g.drakms.xs > 0.0){
266             g.drakms.xs = dlimit(g.drakms.xs - 0.5 * GAME_SPEED * GAME_SPEED,
267                                  0.0, 4.0 * GAME_SPEED);
268           }else{
269             g.drakms.xs = dlimit(g.drakms.xs + 0.5 * GAME_SPEED * GAME_SPEED,
270                                   -4.0 * GAME_SPEED, 0.0);
271           }
272         }else{
273 // Follow Target
274 
275           int dx = (g.drakms.targetx + g.drakms.targetmod)*16 - 48 - int(g.drakms.x);
276 // Wait above target
277           if ((dx == 0) && (g.drakms.movedelay == 0)) g.drakms.movedelay = int(50/GAME_SPEED);
278           if (dx == 0) g.drakms.xs = 0.0;
279 // Calculate stopping distance
280           double stopd = (g.drakms.xs * g.drakms.xs * 2.0 +
281                           fabs(g.drakms.xs) / GAME_SPEED) * 0.5;
282           if ((abs(dx) > stopd) && (g.drakms.movedelay == 0)){
283 // Accelerate
284             g.drakms.xs = dlimit(g.drakms.xs + 0.5 * GAME_SPEED * GAME_SPEED * sign(dx),
285                                                     -4.0 * GAME_SPEED, 4.0 * GAME_SPEED);
286           }else{
287 // Apply Brakes
288             if (g.drakms.xs > 0.0){
289               g.drakms.xs = dlimit(g.drakms.xs - 0.5 * GAME_SPEED * GAME_SPEED,
290                                    0.0, 4.0 * GAME_SPEED);
291             }else{
292               g.drakms.xs = dlimit(g.drakms.xs + 0.5 * GAME_SPEED * GAME_SPEED,
293                                     -4.0 * GAME_SPEED, 0.0);
294             }
295           }
296 // Target destroyed
297           if ((g.gamemap.b[g.drakms.targetx].type == 0) && (g.drakms.movedelay == 0)){
298             g.drakms.targetx = 0;
299           }
300         }
301 // Move Sideways
302         g.drakms.x += g.drakms.xs;
303 // Fire Drak guns
304         fire_drakguns(g, g.drakgun, g.drakms, g.p, g.sound, g.laser, g.gamemap.b, g.shot,
305                       g.gamemap.groundheight, g.xmove, g.ymove);
306 // Launch fighters
307         if ((g.drakms.fightersout < 3) && (!(g.drakms.y < 38)) && (int(drand()*20)==10) &&
308            (g.drakms.launchdelay == 0) && (g.drakms.movedelay > 0)){
309           launch_drakfighter(g.drakms, g.p, g.dp);
310         }
311 
312       }else{
313 // Destroy drak mothership
314         for (int i=0;i<6;i++){
315           int x = int(g.drakms.x) + i*16;
316           firetype boom;
317           boom.x = x + int(drand()*16) - 8;
318           boom.y = int(g.drakms.y);
319           boom.time = 0;
320           boom.type = 0;
321           g.explosion.add(boom);
322           for (int m=1;m<=2;m++){
323             falltype shrapnel;
324             shrapnel.x = double(x) + 6.0;
325             shrapnel.y = g.drakms.y + 8.0;
326             shrapnel.xs = g.drakms.xs + (drand()*5.0 - 2.5)*GAME_SPEED;
327             shrapnel.ys = (1.0 - drand()*4.0)*GAME_SPEED;
328             shrapnel.image = 235 + int(drand()*3);
329             shrapnel.type = 1;
330             g.fall.add(shrapnel);
331             falltype bigshrapnel;
332             bigshrapnel.x = double(x);
333             bigshrapnel.y = g.drakms.y + 8.0;
334             bigshrapnel.xs = g.drakms.xs + (drand()*5.0 - 2.5)*GAME_SPEED;
335             bigshrapnel.ys = (1.0 - drand()*4.0)*GAME_SPEED;
336             bigshrapnel.image = 315 + int(drand()*3);
337             bigshrapnel.side = 0;
338             bigshrapnel.type = 2;
339             g.fall.add(bigshrapnel);
340           }
341         }
342         g.drakgun.reset();
343         while (g.drakgun.next()){
344           falltype gunshrapnel;
345           gunshrapnel.x = g.drakms.x + double(g.drakgun().x);
346           gunshrapnel.y = g.drakms.y + double(g.drakgun().y);
347           gunshrapnel.xs = g.drakms.xs + (drand()*5.0 - 2.5)*GAME_SPEED;
348           gunshrapnel.ys = (1.0 - drand()*4.0)*GAME_SPEED;
349           gunshrapnel.image = g.drakgun().image[g.drakgun().d];
350           gunshrapnel.side = 0;
351           gunshrapnel.type = 2;
352           g.fall.add(gunshrapnel);
353           g.drakgun.kill();
354         }
355         g.drakms.exist = 2;
356         g.sound.play(SOUND_FUELEXPLODE);
357       }
358       break;
359     case 2: // Drak mothership destroyed
360       break;
361   }
362 
363 }
364