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