1 // Emacs style mode select -*- C++ -*-
2 //---------------------------------------------------------------------------
3 //
4 // $Id: swcollsn.c,v 1.3.2.1 2003/06/08 18:16:38 fraggle Exp $
5 //
6 // Copyright(C) 1984-2000 David L. Clark
7 // Copyright(C) 2001-2003 Simon Howard
8 //
9 // This program is free software; you can redistribute it and/or modify it
10 // under the terms of the GNU General Public License as published by the
11 // Free Software Foundation; either version 2 of the License, or (at your
12 // option) any later version. This program is distributed in the hope that
13 // it will be useful, but WITHOUT ANY WARRANTY; without even the implied
14 // warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
15 // the GNU General Public License for more details. You should have
16 // received a copy of the GNU General Public License along with this
17 // program; if not, write to the Free Software Foundation, Inc., 59 Temple
18 // Place - Suite 330, Boston, MA 02111-1307, USA.
19 //
20 //---------------------------------------------------------------------------
21 //
22 // swcollsn - SW collision resolution
23 //
24 //---------------------------------------------------------------------------
25
26 #include "video.h"
27
28 #include "sw.h"
29 #include "swcollsn.h"
30 #include "swdisp.h"
31 #include "swend.h"
32 #include "swground.h"
33 #include "swgrpha.h"
34 #include "swinit.h"
35 #include "swmain.h"
36 #include "swmisc.h"
37 #include "swmove.h"
38 #include "swsound.h"
39
40 static OBJECTS *killed[MAX_OBJS*2], *killer[MAX_OBJS*2];
41 static int killptr;
42
43 static int collsdx[MAX_PLYR];
44 static int collsdy[MAX_PLYR];
45 static OBJECTS *collsno[MAX_PLYR];
46 static int collptr;
47 static int collxadj, collyadj;
48
49
50 // sdh 28/6/2002: new collision detection code done in memory rather
51 // than using the drawing functions
52 // sdh 27/7/2002: removed old collision detection code
53
54 //#define COLL_DEBUG
55
colltest(OBJECTS * ob1,OBJECTS * ob2)56 static void colltest(OBJECTS * ob1, OBJECTS * ob2)
57 {
58 int x, y;
59 int x1, y1, x2, y2;
60 int w, h;
61 unsigned char *data1, *data2;
62
63 if ((ob1->ob_type == PLANE && ob1->ob_state >= FINISHED)
64 || (ob2->ob_type == PLANE && ob2->ob_state >= FINISHED)
65 || (ob1->ob_type == EXPLOSION && ob2->ob_type == EXPLOSION))
66 return;
67
68 // (x1, y1) are the coords of the area we are testing in ob1
69 // (x2, y2) are the coords of the area in ob2
70 // (w, h) is the size of the area
71
72 // x:
73
74 if (ob1->ob_x < ob2->ob_x) {
75 x1 = ob2->ob_x - ob1->ob_x;
76 x2 = 0;
77 w = ob1->ob_newsym->w - x1;
78 if (w > ob2->ob_newsym->w)
79 w = ob2->ob_newsym->w;
80 } else {
81 x1 = 0;
82 x2 = ob1->ob_x - ob2->ob_x;
83 w = ob2->ob_newsym->w - x2;
84 if (w > ob1->ob_newsym->w)
85 w = ob1->ob_newsym->w;
86 }
87
88 // no intersection?
89
90 if (w <= 0)
91 return;
92
93 // y:
94
95 if (ob1->ob_y < ob2->ob_y) {
96 y1 = 0;
97 y2 = ob2->ob_y - ob1->ob_y;
98 h = ob2->ob_newsym->h - y2;
99 if (h > ob1->ob_newsym->h)
100 h = ob1->ob_newsym->h;
101 } else {
102 y1 = ob1->ob_y - ob2->ob_y;
103 y2 = 0;
104 h = ob1->ob_newsym->h - y1;
105 if (h > ob2->ob_newsym->h)
106 h = ob2->ob_newsym->h;
107 }
108
109 // no intersection?
110
111 if (h <= 0)
112 return;
113
114 #ifdef COLL_DEBUG
115 fprintf(stderr,
116 "collision test: (%i, %i) at (%i, %i)/(%i, %i)\n",
117 w, h, x1, y1, x2, y2);
118
119 fprintf(stderr,
120 "info: (%i, %i)/(%i, %i) (%i, %i)/(%i, %i)\n",
121 ob1->ob_x, ob1->ob_y, ob1->ob_newsym->w, ob1->ob_newsym->h,
122 ob2->ob_x, ob2->ob_y, ob2->ob_newsym->w, ob2->ob_newsym->h);
123 #endif
124
125 data1 = ob1->ob_newsym->data + ob1->ob_newsym->w * y1 + x1;
126 data2 = ob2->ob_newsym->data + ob2->ob_newsym->w * y2 + x2;
127
128 for (y=0; y<h; ++y) {
129 unsigned char *d1 = data1, *d2 = data2;
130
131 for (x=0; x<w; ++x) {
132 if (*d1 && *d2) {
133
134 // a collision
135
136 if (killptr < 2*MAX_OBJS - 1) {
137 killed[killptr] = ob1;
138 killer[killptr++] = ob2;
139 killed[killptr] = ob2;
140 killer[killptr++] = ob1;
141 }
142 return;
143 }
144
145 ++d1; ++d2;
146 }
147
148 data1 += ob1->ob_newsym->w;
149 data2 += ob2->ob_newsym->w;
150 }
151 }
152
scoretarg(OBJECTS * obp,int score)153 static void scoretarg(OBJECTS *obp, int score)
154 {
155 register OBJECTS *ob;
156
157 ob = obp;
158 if (playmode != PLAYMODE_ASYNCH) {
159 if (ob->ob_clr == 1)
160 nobjects[0].ob_score -= score;
161 else
162 nobjects[0].ob_score += score;
163 dispscore(&nobjects[0]);
164 } else {
165 nobjects[2 - ob->ob_clr].ob_score += score;
166 dispscore(&nobjects[2 - ob->ob_clr]);
167 }
168 }
169
scorepenalty(obtype_t ttype,OBJECTS * ob,int score)170 static BOOL scorepenalty(obtype_t ttype, OBJECTS * ob, int score)
171 {
172 register OBJECTS *obt;
173
174 obt = ob;
175 if (ttype == SHOT || ttype == BOMB || ttype == MISSILE
176 || (ttype == PLANE
177 && (obt->ob_state == FLYING
178 || obt->ob_state == WOUNDED
179 || (obt->ob_state == FALLING
180 && obt->ob_hitcount == FALLCOUNT))
181 && !obt->ob_athome)) {
182 scoretarg(obt, score);
183 return TRUE;
184 }
185 return FALSE;
186 }
187
188
189
190
191 static int crtdepth[8] = { 1, 2, 2, 3, 3, 2, 2, 1 };
192
crater(OBJECTS * ob)193 static void crater(OBJECTS * ob)
194 {
195 register int i, x, y, ymin, ymax;
196 int xmin, xmax;
197
198 xmin = ob->ob_x + (ob->ob_newsym->w - 8) / 2;
199 xmax = xmin + 7;
200
201 for (x = xmin, i = 0; x <= xmax; ++x, ++i) {
202 ymax = ground[x];
203 ymin = ymax - crtdepth[i] +1;
204 y = orground[x] - 20;
205 if (y < 20)
206 y = 20;
207 if (ymin <= y)
208 ymin = y + 1;
209 ground[x] = ymin - 1;
210 }
211 forcdisp = TRUE;
212 }
213
214
215
216 // sdh -- renamed this to swkill to remove possible conflicts with
217 // the unix kill() function
218
swkill(OBJECTS * ob1,OBJECTS * ob2)219 static void swkill(OBJECTS * ob1, OBJECTS * ob2)
220 {
221 register OBJECTS *ob, *obt;
222 register int i;
223 obtype_t ttype;
224 obstate_t state;
225
226 ob = ob1;
227 obt = ob2;
228 ttype = obt ? obt->ob_type : GROUND;
229 if ((ttype == BIRD || ttype == FLOCK)
230 && ob->ob_type != PLANE)
231 return;
232
233 switch (ob->ob_type) {
234
235 case BOMB:
236 case MISSILE:
237 initexpl(ob, 0);
238 ob->ob_life = -1;
239 if (!obt)
240 crater(ob);
241 stopsound(ob);
242 return;
243
244 case SHOT:
245 ob->ob_life = 1;
246 return;
247
248 case STARBURST:
249 if (ttype == MISSILE || ttype == BOMB || !obt)
250 ob->ob_life = 1;
251 return;
252
253 case EXPLOSION:
254 if (!obt) {
255 ob->ob_life = 1;
256 stopsound(ob);
257 }
258 return;
259
260 case TARGET:
261 if (ob->ob_state != STANDING)
262 return;
263 if (ttype == EXPLOSION || ttype == STARBURST)
264 return;
265
266 if (ttype == SHOT) {
267 ob->ob_hitcount += TARGHITCOUNT;
268 if (ob->ob_hitcount
269 <= (TARGHITCOUNT * (gamenum + 1)))
270 return;
271 }
272
273 ob->ob_state = FINISHED;
274 initexpl(ob, 0);
275
276 setvdisp();
277 dispwobj(ob);
278 setadisp();
279
280 scoretarg(ob, ob->ob_orient == 2 ? 200 : 100);
281 if (!--numtarg[ob->ob_clr - 1])
282 endgame(ob->ob_clr);
283 return;
284
285 case PLANE:
286 state = ob->ob_state;
287
288 if (state == CRASHED || state == GHOSTCRASHED)
289 return;
290
291 if (endsts[ob->ob_index] == WINNER)
292 return;
293
294 if (ttype == STARBURST
295 || (ttype == BIRD && ob->ob_athome))
296 return;
297
298 if (!obt) {
299 if (state == FALLING) {
300 stopsound(ob);
301 initexpl(ob, 1);
302 crater(ob);
303 } else if (state < FINISHED) {
304 scorepln(ob);
305 initexpl(ob, 1);
306 crater(ob);
307 }
308
309 crashpln(ob);
310 return;
311 }
312
313 if (state >= FINISHED)
314 return;
315
316 if (state == FALLING) {
317 if (ob->ob_index == player) {
318 if (ttype == SHOT)
319 ++shothole;
320 else if (ttype == BIRD || ttype == FLOCK)
321 ++splatbird;
322 }
323 return;
324 }
325
326 if (ttype == SHOT || ttype == BIRD
327 || ttype == OX || ttype == FLOCK) {
328 if (ob->ob_index == player) {
329 if (ttype == SHOT)
330 ++shothole;
331 else if (ttype == OX)
332 ++splatox;
333 else
334 ++splatbird;
335 }
336
337 // sdh 28/10/2001: option to disable wounded planes
338
339 if (conf_wounded) {
340 if (state == FLYING) {
341 ob->ob_state = WOUNDED;
342 return;
343 }
344 if (state == STALLED) {
345 ob->ob_state = WOUNDSTALL;
346 return;
347 }
348 }
349 } else {
350 initexpl(ob, 1);
351 if (ttype == PLANE) {
352 collxadj = -collxadj;
353 collyadj = -collyadj;
354 collsdx[collptr]
355 = ((ob->ob_dx + obt->ob_dx) >> 1)
356 + collxadj;
357 collsdy[collptr]
358 = ((ob->ob_dy + obt->ob_dy) >> 1)
359 + collyadj;
360 collsno[collptr++] = ob;
361 }
362 }
363
364 hitpln(ob);
365 scorepln(ob);
366 return;
367
368 case BIRD:
369 ob->ob_life = scorepenalty(ttype, obt, 25) ? -1 : -2;
370 return;
371
372 case FLOCK:
373 if (ttype != FLOCK && ttype != BIRD
374 && ob->ob_state == FLYING) {
375 for (i = 0; i < 8; ++i)
376 initbird(ob, i);
377 ob->ob_life = -1;
378 ob->ob_state = FINISHED;
379 }
380 return;
381
382 case OX:
383 if (ob->ob_state != STANDING)
384 return;
385 if (ttype == EXPLOSION || ttype == STARBURST)
386 return;
387 scorepenalty(ttype, obt, 200);
388 ob->ob_state = FINISHED;
389 return;
390 default:
391 return;
392 }
393 }
394
395
swcollsn()396 void swcollsn()
397 {
398 register OBJECTS *ob, *obp, **obkd, **obkr;
399 register int xmax, ymin, ymax, i;
400 obtype_t otype;
401 int prevx1, prevx2;
402
403 collptr = killptr = 0;
404 collxadj = 2;
405 collyadj = 1;
406 if (countmove & 1) {
407 collxadj = -collxadj;
408 collyadj = -collyadj;
409 }
410 setadisp();
411 prevx1 = topobj.ob_x;
412 for (ob = topobj.ob_xnext; ob != &botobj; ob = ob->ob_xnext) {
413 prevx2 = prevx1 = ob->ob_x;
414
415 xmax = ob->ob_x + ob->ob_newsym->w - 1;
416 ymax = ob->ob_y;
417 ymin = ymax - ob->ob_newsym->h + 1;
418
419 for (obp = ob->ob_xnext;
420 obp != &botobj && obp->ob_x <= xmax;
421 obp = obp->ob_xnext) {
422 prevx2 = obp->ob_x;
423
424 if (obp->ob_y >= ymin
425 && (obp->ob_y - obp->ob_newsym->h + 1) <= ymax)
426 colltest(ob, obp);
427 }
428
429 otype = ob->ob_type;
430
431 if ((otype == PLANE
432 && ob->ob_state != FINISHED
433 && ob->ob_state != WAITING
434 && ob->ob_y < (ground[ob->ob_x + 8] + 24))
435 || ((otype == BOMB || otype == MISSILE)
436 && ob->ob_y < (ground[ob->ob_x + 4] + 12)))
437 tstcrash(ob);
438 }
439
440 obkd = killed;
441 obkr = killer;
442 for (i = 0; i < killptr; ++i, ++obkd, ++obkr)
443 swkill(*obkd, *obkr);
444
445 obkd = collsno;
446 for (i = 0; i < collptr; ++i, ++obkd) {
447 ob = *obkd;
448 ob->ob_dx = collsdx[i];
449 ob->ob_dy = collsdy[i];
450 }
451 }
452
tstcrash(OBJECTS * obp)453 void tstcrash(OBJECTS * obp)
454 {
455 register sopsym_t *sym = obp->ob_newsym;
456 register int x, y;
457
458 for (x=0; x<sym->w; ++x) {
459 y = obp->ob_y - ground[x + obp->ob_x];
460
461 // out of range?
462
463 if (y >= sym->h)
464 continue;
465
466 // check for collision at this point
467
468 if (y < 0 || sym->data[y * sym->w + x]) {
469
470 // collision!
471
472 if (killptr < 2 * MAX_OBJS) {
473 killed[killptr] = obp;
474 killer[killptr++] = NULL;
475 }
476
477 return;
478 }
479 }
480 }
481
482
scorepln(OBJECTS * ob)483 void scorepln(OBJECTS * ob)
484 {
485 scoretarg(ob, 50);
486 }
487
488
dispd(int n,int size)489 void dispd(int n, int size)
490 {
491 register int i = 0;
492 register int d, t;
493 register BOOL first = TRUE;
494
495 // sdh 24/10/2001: make sure we use the main video buffer
496
497 setvdisp();
498
499 if (n < 0) {
500 n = -n;
501 swputc('-');
502 ++i;
503 }
504 for (t = 10000; t > 1; n %= t, t /= 10) {
505 d = n / t;
506 if (d || !first) {
507 first = FALSE;
508 swputc(d + '0');
509 ++i;
510 }
511 }
512 swputc(n + '0');
513 ++i;
514 while (++i <= size)
515 swputc(' ');
516 }
517
518
dispscore(OBJECTS * ob)519 void dispscore(OBJECTS * ob)
520 {
521 setvdisp();
522
523 Vid_Box(0, 16, 48, 16, 0);
524
525 swposcur((ob->ob_clr - 1) * 7 + 2, 24);
526 swcolour(ob->ob_clr);
527 dispd(ob->ob_score, 6);
528 }
529
530
531
532 //---------------------------------------------------------------------------
533 //
534 // $Log: swcollsn.c,v $
535 // Revision 1.3.2.1 2003/06/08 18:16:38 fraggle
536 // Fix networking and some compile bugs
537 //
538 // Revision 1.3 2003/04/05 22:44:04 fraggle
539 // Remove some useless functions from headers, make them static if they
540 // are not used by other files
541 //
542 // Revision 1.2 2003/04/05 22:31:29 fraggle
543 // Remove PLAYMODE_MULTIPLE and swnetio.c
544 //
545 // Revision 1.1.1.1 2003/02/14 19:03:09 fraggle
546 // Initial Sourceforge CVS import
547 //
548 //
549 // sdh 14/2/2003: change license header to GPL
550 // sdh 28/07/2002: removed old collision detection code
551 // sdh 28/06/2002: new collision detection code: look at the sprite data
552 // rather than drawing to the screen. old code is still there
553 // under a #define but will eventually be removed.
554 // sdh 27/06/2002: move to new sopsym_t for symbols
555 // sdh 28/10/2001: option to disable wounded planes
556 // sdh 24/10/2001: fix score display, fix auxdisp buffer
557 // sdh 21/10/2001: use new obtype_t and obstate_t
558 // sdh 21/10/2001: rearranged file headers, added cvs tags
559 // sdh 21/10/2001: reformatted with indent, adjusted some code by
560 // hand to make more readable
561 // sdh 19/10/2001: removed externs, these are now in headers
562 // sdh 18/10/2001: converted all functions to ANSI-style arguments
563 //
564 // 87-04-05 Missile and starburst support
565 // 87-03-31 Missiles.
566 // 87-03-13 Splatted bird symbol.
567 // 87-03-12 More than 1 bullet to kill target.
568 // 87-03-12 Wounded airplanes.
569 // 87-03-11 No explosion on bird-plane collision
570 // 87-03-09 Microsoft compiler.
571 // 84-10-31 Atari
572 // 84-06-12 PCjr Speed-up
573 // 84-02-02 Development
574 //
575 //---------------------------------------------------------------------------
576