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