1 /***********************************************************
2 *                      K O U L E S                         *
3 *----------------------------------------------------------*
4 *  C1995 JAHUSOFT                                          *
5 *        Jan Hubicka                                       *
6 *        Dukelskych Bojovniku 1944                         *
7 *        390 03 Tabor                                      *
8 *        Czech Republic                                    *
9 *        Phone: 0041-361-32613                             *
10 *        eMail: hubicka@limax.paru.cas.cz                  *
11 *----------------------------------------------------------*
12 *   Copyright(c)1995,1996 by Jan Hubicka.See README for    *
13 *                    licence details.                      *
14 *----------------------------------------------------------*
15 *  koules.c main game routines                             *
16 ***********************************************************/
17 /* Changes for OS/2 Warp with Dive.                        *
18  *  Copyright(c)1996 by Thomas A. K. Kjaer                 *
19  ***********************************************************/
20 /* Changes for joystick "accelerate by deflection"         *
21  *  (c) 1997 by Ludvik Tesar (Ludv\'{\i}k Tesa\v{r})       *
22  ************************LT*********************************/
23 #include <unistd.h>
24 #define VARIABLES_HERE
25 #include "koules.h"
26 #include "server.h"
27 #include "client.h"
28 #include <sys/time.h>
29 int             nobjects = 8;
30 int             nrockets = 0;
31 int             drawpointer = 1;
32 int             difficulty = 2;
33 int             cit = 0;
34 #ifdef NETSUPPORT
35 int             client = 0, server = 0;
36 #endif
37 Object          object[MAXOBJECT];
38 Point           point[MAXPOINT];
39 
40 
41 BitmapType      bball_bitmap, apple_bitmap, inspector_bitmap, mouse_bitmap,
42                 lunatic_bitmap, lball_bitmap[NLETTERS], circle_bitmap,
43                 hole_bitmap, ball_bitmap, eye_bitmap[MAXROCKETS], rocket_bitmap[MAXROCKETS],
44                 ehole_bitmap;
45 unsigned char   rocketcolor[5] =
46 {96, 160, 64, 96, 128};
47 #ifdef SOUND
48 int             sndinit = 1;
49 #endif
50 
51 int             lastlevel = 0, maxlevel = 0;
52 unsigned char   control[MAXROCKETS];
53 struct control  controls[MAXROCKETS];
54 int             dosprings = 0;
55 int             randsprings = 0;
56 int             nomouse = 0;
57 int             textcolor;
58 int             sound = 1;
59 int             tbreak;
60 int             gameplan = COOPERATIVE;
61 int             npoint = 0;
62 int             gamemode;
63 int             keys[5][4];
64 int             rotation[MAXROCKETS];
65 int             a_bballs, a_rockets, a_balls, a_holes, a_apples, a_inspectors,
66                 a_lunatics, a_eholes;
67 #ifdef MOUSE
68 int             mouseplayer = -1;
69 #endif
70 #ifdef JOYSTICK
71 int             joystickplayer[2] =
72 {-1, -1};
73 int             joystickdevice[2] =
74 {-1, -1};
75 int             calibrated[2];
76 int             center[2][2];
77 float    joystickmul[2]={1.5,1.5};
78 float    joystickthresh[2]={0.1,0.1};
79 #endif
80 
81 
82 float           ROCKET_SPEED = 1.2;
83 float           BALL_SPEED = 1.2;
84 float           BBALL_SPEED = 1.2;
85 float           SLOWDOWN = 0.8;
86 float           GUMM = 20;
87 
88 
89 float           BALLM = 3;
90 float           LBALLM = 3;
91 float           BBALLM = 8;
92 float           APPLEM = 34;
93 float           INSPECTORM = 2;
94 float           LUNATICM = 3.14;
95 float           ROCKETM = 4;
96 
97 
98 void
addpoint(CONST int x,CONST int y,CONST int xp,CONST int yp,CONST int color,CONST int time)99 addpoint (CONST int x, CONST int y, CONST int xp, CONST int yp, CONST int color, CONST int time)
100 {
101   point[npoint].x = x / DIV;
102   point[npoint].y = y / DIV;
103   point[npoint].xp = xp / DIV;
104   point[npoint].yp = yp / DIV;
105   point[npoint].time = time;
106 
107   point[npoint].color = color;
108   npoint++;
109   if (npoint >= MAXPOINT)
110     npoint = 0;
111 }
112 #ifdef XSUPPORT			/*fast code for slow X :) */
113 #define CCONST 3
114 #define PCONST 0
115 XPoint          mypixels[256 >> CCONST][MAXPOINT];
116 int             nmypixels[256 >> CCONST];
117 #ifdef MITSHM
118 void
shmpoints()119 shmpoints ()
120 {
121   register unsigned int x, y;
122   Point          *p, *lp;
123   lp = &point[MAXPOINT];
124   for (p = point; p < lp; p++)
125     {
126       if (p->time > 0)
127 	{
128 	  p->time--;
129 	  x = (p->x += p->xp) >> 8;
130 	  y = (p->y += p->yp);
131 	  if (x > 0 && x < MAPWIDTH &&
132 	      y > 0 && y >> 8 < MAPHEIGHT)
133 	    SMySetPixel (backscreen, x, y, p->color);
134 	  else
135 	    p->time = 0;
136 	}
137     }
138 }
139 #endif
140 void
points()141 points ()
142 {
143   register unsigned int x, y, c;
144   Point          *p, *lp;
145 #ifdef MITSHM
146   if (shm)
147     {
148       shmpoints ();
149       return;
150     }
151 #endif
152   for (x = 0; x < 256 >> CCONST; x++)
153     nmypixels[x] = 0;
154   lp = &point[MAXPOINT];
155   for (p = point; p < lp; p++)
156     {
157       if (p->time > 0)
158 	{
159 	  p->time--;
160 	  x = (p->x += p->xp) >> 8;
161 	  y = (p->y += p->yp) >> 8;
162 	  if (x > 0 && x < MAPWIDTH &&
163 	      y > 0 && y < MAPHEIGHT)
164 	    {
165 	      c = p->color >> CCONST;
166 	      mypixels[c][nmypixels[c]].x = x;
167 	      mypixels[c][nmypixels[c]].y = y;
168 	      nmypixels[c]++;
169 	    }
170 	  else
171 	    p->time = 0;
172 	}
173     }
174   for (x = 0; x < 256 >> CCONST; x++)
175     {
176       if (nmypixels[x])
177 	{
178 	  SetColor ((x << CCONST) + PCONST);
179 	  XDrawPoints (dp, current.pixmap, gc, mypixels[x], nmypixels[x], CoordModeOrigin);
180 	}
181     }
182 }
183 #else
184 void
points()185 points ()
186 {
187   register unsigned int x, y;
188   Point          *p, *lp;
189   lp = &point[MAXPOINT];
190   for (p = point; p < lp; p++)
191     {
192       if (p->time > 0)
193 	{
194 	  p->time--;
195 	  x = (p->x += p->xp) >> 8;
196 	  y = (p->y += p->yp);
197 	  if (x > 0 && x < MAPWIDTH &&
198 	      y > 0 && y >> 8 < MAPHEIGHT)
199 	    SMySetPixel (backscreen, x, y, p->color);
200 	  else
201 	    p->time = 0;
202 	}
203     }
204 }
205 #endif
206 
207 void
points1()208 points1 ()
209 {
210   Point          *p, *lp;
211   lp = &point[MAXPOINT];
212   for (p = point; p < lp; p++)
213     {
214       if (p->time > 0)
215 	{
216 	  p->time--;
217 	  p->x += p->xp;
218 	  p->y += p->yp;
219 	}
220     }
221 }
222 
223 INLINE int
radius(CONST int type)224 radius (CONST int type)
225 {
226   switch (type)
227     {
228     case EHOLE:
229     case HOLE:
230       return (HOLE_RADIUS);
231     case ROCKET:
232       return (ROCKET_RADIUS);
233     case BALL:
234     case LBALL:
235       return (BALL_RADIUS);
236     case BBALL:
237       return (BBALL_RADIUS);
238     case APPLE:
239       return (APPLE_RADIUS);
240     case INSPECTOR:
241       return (INSPECTOR_RADIUS);
242     case LUNATIC:
243       return (LUNATIC_RADIUS);
244     }
245   return (0);
246 }
247 static INLINE int
color(CONST int type,CONST int i,CONST int letter)248 color (CONST int type, CONST int i, CONST int letter)
249 {
250   switch (type)
251     {
252     case EHOLE:
253       return (128);
254     case HOLE:
255       return (64);
256     case ROCKET:
257       return (rocketcolor[i]);
258     case BALL:
259       return (64);
260     case LBALL:
261       switch (letter)
262 	{
263 	case L_ACCEL:
264 	  return (128);
265 	case L_GUMM:
266 	  return (160);
267 	case L_THIEF:
268 	  return (192);
269 	case L_FINDER:
270 	  return (3 * 32);
271 	case L_TTOOL:
272 	  return (3 * 32);
273 	}
274 
275     case BBALL:
276       return (128);
277     case APPLE:
278       return (64);
279     case INSPECTOR:
280       return (160);
281     case LUNATIC:
282       return (3 * 32);
283     }
284   return (0);
285 }
286 INLINE float
M(CONST int type)287 M (CONST int type)
288 {
289   switch (type)
290     {
291     case APPLE:
292       return (APPLEM);
293     case INSPECTOR:
294       return (INSPECTORM);
295     case LUNATIC:
296       return (LUNATICM);
297     case HOLE:
298     case EHOLE:
299       return (BBALLM);
300     case ROCKET:
301       return (ROCKETM);
302     case BALL:
303     case LBALL:
304       return (BALLM);
305     case BBALL:
306       return (BBALLM);
307     }
308   return (0);
309 }
310 
311 int
find_possition(float * x,float * y,CONST float radius)312 find_possition (float *x, float *y, CONST float radius)
313 {
314   int             x1, y1, i, y2 = 0;
315   float           xp, yp;
316 rerand:;
317   x1 = rand () % (GAMEWIDTH - 60) + 30;
318   y1 = rand () % (GAMEHEIGHT - 60) + 30;
319   for (i = 0; i < nobjects; i++)
320     {
321       xp = x1 - object[i].x;
322       yp = y1 - object[i].y;
323       if (xp * xp + yp * yp < (radius + object[i].radius) *
324 	  (radius + object[i].radius))
325 	{
326 	  y2++;
327 	  if (y2 > 10000)
328 	    return (0);
329 	  goto rerand;
330 
331 	}
332     }
333   *x = (float) x1;
334   *y = (float) y1;
335   return (1);
336 }
337 
338 INLINE void
normalize(float * x,float * y,float size)339 normalize (float *x, float *y, float size)
340 {
341   float           length = sqrt ((*x) * (*x) + (*y) * (*y));
342   if (length == 0)
343     length = 1;
344   *x *= size / length;
345   *y *= size / length;
346 }
347 
348 
349 static void
move_objects()350 move_objects ()
351 {
352   int             i;
353   for (i = 0; i < nobjects; i++)
354     if (object[i].type == CREATOR)
355       {
356 	object[i].time--;
357 	if (object[i].time <= 0)
358 	  {
359 	    Effect (S_CREATOR2, next);
360 	    object[i].live = object[i].live1;
361 	    object[i].type = object[i].ctype;
362 	    if (object[i].type == ROCKET)
363 	      object[i].time = 200;
364 	    object[i].radius = radius (object[i].ctype);
365 	    object[i].M = M (object[i].ctype);
366 	  }
367       }
368     else if (object[i].live)
369       {
370 	object[i].x += object[i].fx * (GAMEWIDTH / 640.0 + 1) / 2;
371 	object[i].y += object[i].fy * (GAMEWIDTH / 640.0 + 1) / 2;
372       }
373 }
374 
375 
376 
377 
378 
379 static int helpmode;
help(int x,int y,int radius,char * text)380 static void help(int x,int y,int radius,char *text)
381 {
382    int x1=x+radius+2,y1=y-4*DIV,x2=x1+strlen(text)*8*DIV,y2=y1+8*DIV;
383    if(helpmode&&x1>0&&x2<=GAMEWIDTH-DIV&&y1>0&&y2<GAMEHEIGHT-DIV) {
384    DrawBlackMaskedText(x1/DIV+1,y1/DIV+1,text);
385    DrawWhiteMaskedText(x1/DIV,y1/DIV,text);
386    }
387 }
388 char            str[2];
389 static void
draw_objects(CONST int draw)390 draw_objects (CONST int draw)
391 {
392   char            s[80];
393   int             i;
394   if (draw)
395     {
396       CopyVSToVS (background, backscreen);
397       SetScreen (backscreen);
398 
399       /* Now draw the objects in backscreen. */
400 
401       points ();
402       help(0,9,0,"Help - press 'H' to disable");
403 #ifdef XSUPPORT
404 #ifdef MITSHM
405       if (!shm)
406 #else
407       if (1)
408 #endif
409 	{
410 	  XSegment        lines[MAXOBJECT];
411 	  int             nlines = 0;
412 	  for (i = 0; i < nobjects; i++)
413 	    if (object[i].live && object[i].lineto != -1 && object[object[i].lineto].live)
414 	      {
415 		lines[nlines].x1 = object[i].x / DIV;
416 		lines[nlines].y1 = object[i].y / DIV;
417 		lines[nlines].x2 = object[object[i].lineto].x / DIV;
418 		lines[nlines].y2 = object[object[i].lineto].y / DIV;
419 		nlines++;
420 	      }
421 	  SetColor (255);
422 	  XDrawSegments (dp, current.pixmap, gc, lines, nlines);
423 
424 	}
425       else
426 #endif
427 	for (i = 0; i < nobjects; i++)
428 	  if (object[i].live && object[i].lineto != -1 && object[object[i].lineto].live) {
429 	    Line (object[i].x / DIV,
430 		  object[i].y / DIV,
431 		  object[object[i].lineto].x / DIV,
432 		  object[object[i].lineto].y / DIV,
433 		  255);
434 		help((object[i].x+object[object[i].lineto].x)/2,
435 		     (object[i].y+object[object[i].lineto].y)/2,
436 		     2,"Spit");
437 	  }
438       for (i = 0; i < nobjects; i++)
439 	if (object[i].live)
440 	  {
441 
442 	    switch (object[i].type)
443 	      {
444 	      case BALL:
445 		PutBitmap ((int) (object[i].x - BALL_RADIUS) / DIV, (int) (object[i].y - BALL_RADIUS) / DIV,
446 		 BALL_RADIUS * 2 / DIV, BALL_RADIUS * 2 / DIV, ball_bitmap);
447 		help(object[i].x,object[i].y,object[i].radius,"Koules");
448 		break;
449 	      case LBALL:
450 		switch (object[i].letter)
451 		  {
452 		  case L_ACCEL:
453 		    PutBitmap ((int) (object[i].x - BALL_RADIUS) / DIV, (int) (object[i].y - BALL_RADIUS) / DIV,
454 			       BALL_RADIUS * 2 / DIV, BALL_RADIUS * 2 / DIV, lball_bitmap[0]);
455 		    help(object[i].x,object[i].y,object[i].radius,"Acceleration");
456 		    break;
457 		  case L_GUMM:
458 		    PutBitmap ((int) (object[i].x - BALL_RADIUS) / DIV, (int) (object[i].y - BALL_RADIUS) / DIV,
459 			       BALL_RADIUS * 2 / DIV, BALL_RADIUS * 2 / DIV, lball_bitmap[1]);
460 		    help(object[i].x,object[i].y,object[i].radius,"Weight");
461 		    break;
462 		  case L_THIEF:
463 		    PutBitmap ((int) (object[i].x - BALL_RADIUS) / DIV, (int) (object[i].y - BALL_RADIUS) / DIV,
464 			       BALL_RADIUS * 2 / DIV, BALL_RADIUS * 2 / DIV, lball_bitmap[2]);
465 		    help(object[i].x,object[i].y,object[i].radius,"Thief");
466 		    break;
467 		  case L_FINDER:
468 		    PutBitmap ((int) (object[i].x - BALL_RADIUS) / DIV, (int) (object[i].y - BALL_RADIUS) / DIV,
469 			       BALL_RADIUS * 2 / DIV, BALL_RADIUS * 2 / DIV, lball_bitmap[3]);
470 		    help(object[i].x,object[i].y,object[i].radius,"Goodie");
471 		    break;
472 		  case L_TTOOL:
473 		    PutBitmap ((int) (object[i].x - BALL_RADIUS) / DIV, (int) (object[i].y - BALL_RADIUS) / DIV,
474 			       BALL_RADIUS * 2 / DIV, BALL_RADIUS * 2 / DIV, lball_bitmap[4]);
475 		    help(object[i].x,object[i].y,object[i].radius,"Thief toolkit");
476 		    break;
477 		  }
478 #if !defined(XSUPPORT)||defined(MITSHM)
479 #ifdef MITSHM
480 		if (DIV == 1 && shm)
481 #else
482 		if (DIV == 1)
483 #endif
484 		  {
485 		    str[0] = object[i].letter;
486 		    DrawBlackMaskedText ((int) object[i].x / DIV - 4, (int) object[i].y / DIV - 4, str);
487 		  }
488 #endif
489 		break;
490 	      case HOLE:
491 		EnableClipping ();
492 		PutBitmap ((int) (object[i].x - HOLE_RADIUS) / DIV, (int) (object[i].y - HOLE_RADIUS) / DIV,
493 			   HOLE_RADIUS * 2, HOLE_RADIUS * 2, hole_bitmap);
494 		DisableClipping ();
495 		help(object[i].x,object[i].y,object[i].radius,"Black hole");
496 		break;
497 	      case EHOLE:
498 		EnableClipping ();
499 		PutBitmap ((int) (object[i].x - HOLE_RADIUS) / DIV, (int) (object[i].y - HOLE_RADIUS) / DIV,
500 			   HOLE_RADIUS * 2, HOLE_RADIUS * 2, ehole_bitmap);
501 		DisableClipping ();
502 		help(object[i].x,object[i].y,object[i].radius,"Magnetic hole");
503 		break;
504 	      case BBALL:
505 		PutBitmap ((int) (object[i].x - BBALL_RADIUS) / DIV, (int) (object[i].y - BBALL_RADIUS) / DIV,
506 			   BBALL_RADIUS * 2 / DIV, BBALL_RADIUS * 2 / DIV, bball_bitmap);
507 		help(object[i].x,object[i].y,object[i].radius,"BBALL!");
508 		break;
509 	      case INSPECTOR:
510 		PutBitmap ((int) (object[i].x - INSPECTOR_RADIUS) / DIV, (int) (object[i].y - INSPECTOR_RADIUS) / DIV,
511 			   INSPECTOR_RADIUS * 2 / DIV, INSPECTOR_RADIUS * 2 / DIV, inspector_bitmap);
512 		help(object[i].x,object[i].y,object[i].radius,"Inspector");
513 		break;
514 	      case LUNATIC:
515 		PutBitmap ((int) (object[i].x - LUNATIC_RADIUS) / DIV, (int) (object[i].y - LUNATIC_RADIUS) / DIV,
516 			   LUNATIC_RADIUS * 2 / DIV, LUNATIC_RADIUS * 2 / DIV, lunatic_bitmap);
517 		help(object[i].x,object[i].y,object[i].radius,"Lunatic");
518 		break;
519 	      case APPLE:
520 		PutBitmap ((int) (object[i].x - APPLE_RADIUS) / DIV, (int) (object[i].y - APPLE_RADIUS) / DIV,
521 			   APPLE_RADIUS * 2 / DIV, APPLE_RADIUS * 2 / DIV, apple_bitmap);
522 		EnableClipping ();
523 		Line ((int) (object[i].x + 10) / DIV, (int) (object[i].y - APPLE_RADIUS - 10) / DIV,
524 		      (int) (object[i].x) / DIV, (int) (object[i].y - APPLE_RADIUS + 10) / DIV, 150);
525 		Line ((int) (object[i].x + 10) / DIV + 1, (int) (object[i].y - APPLE_RADIUS - 10) / DIV,
526 		      (int) (object[i].x) / DIV + 1, (int) (object[i].y - APPLE_RADIUS + 10) / DIV, 150);
527 		if (DIV == 1)
528 		  Line ((int) (object[i].x + 10) / DIV + 2, (int) (object[i].y - APPLE_RADIUS - 10) / DIV,
529 			(int) (object[i].x) / DIV + 2, (int) (object[i].y - APPLE_RADIUS + 10) / DIV, 150);
530 		DisableClipping ();
531 		PutBitmap ((int) (object[i].x - EYE_RADIUS) / DIV,
532 			   (int) (object[i].y + APPLE_RADIUS - 15) / DIV,
533 		 EYE_RADIUS * 2 / DIV, EYE_RADIUS * 2 / DIV, eye_bitmap[0]);
534 		help(object[i].x,object[i].y,object[i].radius,"APPLEPOLISHER");
535 		break;
536 	      case ROCKET:
537 		{
538 		  int             x1, y1;
539 		help(object[i].x,object[i].y,object[i].radius,"Player");
540 		  PutBitmap ((int) (object[i].x - ROCKET_RADIUS) / DIV, (int) (object[i].y - ROCKET_RADIUS) / DIV,
541 			     ROCKET_RADIUS * 2 / DIV, ROCKET_RADIUS * 2 / DIV, rocket_bitmap[i]);
542 		  EnableClipping ();
543 		  if (!object[i].thief)
544 		    {
545 		      x1 = object[i].x + sin (object[i].rotation - RAD (30)) * EYE_RADIUS1 - EYE_RADIUS;
546 		      y1 = object[i].y + cos (object[i].rotation - RAD (30)) * EYE_RADIUS1 - EYE_RADIUS;
547 		      PutBitmap ((int) (x1 / DIV), (int) (y1 / DIV),
548 				 (int) (EYE_RADIUS * 2 / DIV), (EYE_RADIUS * 2 / DIV), eye_bitmap[i]);
549 		      x1 = object[i].x + sin (object[i].rotation + RAD (30)) * EYE_RADIUS1 - EYE_RADIUS;
550 		      y1 = object[i].y + cos (object[i].rotation + RAD (30)) * EYE_RADIUS1 - EYE_RADIUS;
551 		      PutBitmap ((int) (x1 / DIV), (int) (y1 / DIV),
552 				 (int) (EYE_RADIUS * 2 / DIV), (EYE_RADIUS * 2 / DIV), eye_bitmap[i]);
553 		    }
554 		  else
555 		    {
556 		      x1 = object[i].x + sin (object[i].rotation - RAD (30)) * EYE_RADIUS1 - BALL_RADIUS;
557 		      y1 = object[i].y + cos (object[i].rotation - RAD (30)) * EYE_RADIUS1 - BALL_RADIUS;
558 
559 		      PutBitmap ((int) (x1 / DIV), (int) (y1 / DIV),
560 				 (int) (BALL_RADIUS * 2 / DIV), (BALL_RADIUS * 2 / DIV), lball_bitmap[2]);
561 		      x1 = object[i].x + sin (object[i].rotation + RAD (30)) * EYE_RADIUS1 - BALL_RADIUS;
562 		      y1 = object[i].y + cos (object[i].rotation + RAD (30)) * EYE_RADIUS1 - BALL_RADIUS;
563 		      PutBitmap ((int) (x1 / DIV), (int) (y1 / DIV),
564 				 (int) (BALL_RADIUS * 2 / DIV), (BALL_RADIUS * 2 / DIV), lball_bitmap[2]);
565 		    }
566 		  DisableClipping ();
567 		}
568 		break;
569 	      }
570 	  }
571     }
572   /*if draw */
573   else
574     points1 ();
575   switch (gamemode)
576     {
577     case MENU:
578       draw_menu (draw);
579       break;
580     case KEYS:
581       draw_keys (draw);
582       break;
583 #ifdef JOYSTICK
584     case JOY:
585       draw_joy (draw);
586       break;
587 #endif
588     }
589 
590 #ifdef MOUSE
591   if (draw && (gamemode == MENU || (gamemode == GAME && mouseplayer != -1)) &&
592       MouseX () >= 0 && MouseY () >= 0 && MouseX () < MAPWIDTH &&
593       MouseY () < MAPHEIGHT && drawpointer)
594     {
595       EnableClipping ();
596       if (!nomouse)
597 	{
598 	  PutBitmap (MouseX () - MOUSE_RADIUS, MouseY () - MOUSE_RADIUS,
599 		     MOUSE_RADIUS * 2, MOUSE_RADIUS * 2, mouse_bitmap);
600 	  DisableClipping ();
601 	}
602     }
603 #endif
604   if (draw)
605     {
606       EnableClipping ();
607       if (gameplan == COOPERATIVE && gamemode == GAME && DIV == 1)
608 	{
609 	  sprintf (s, "level: %3i", lastlevel + 1);
610 	  DrawWhiteMaskedText ((MAPWIDTH / 2 - 38 * 4) / 2 - strlen (s) * 4, MAPHEIGHT + 2, s);
611 	}
612       sprintf (s, " lives: %6i%6i%6i%6i%6i",
613 	       nrockets >= 1 ? object[0].live1 : 0,
614 	       nrockets >= 2 ? object[1].live1 : 0,
615 	       nrockets >= 3 ? object[2].live1 : 0,
616 	       nrockets >= 4 ? object[3].live1 : 0,
617 	       nrockets >= 5 ? object[4].live1 : 0);
618       DrawWhiteMaskedText (MAPWIDTH / 2 - strlen (s) * 4, MAPHEIGHT + 2, s);
619       sprintf (s, "scores: %6i%6i%6i%6i%6i",
620 	       object[0].score,
621 	       object[1].score,
622 	       object[2].score,
623 	       object[3].score,
624 	       object[4].score);
625       DrawWhiteMaskedText (MAPWIDTH / 2 - strlen (s) * 4, MAPHEIGHT + 11, s);
626 
627       /* Copy backscreen to physical screen. */
628       CopyToScreen (backscreen);
629       fadein ();
630       DisableClipping ();
631     }
632 }
633 
634 
635 
636 
637 void
explosion(CONST int x,CONST int y,CONST int type,CONST int letter,CONST int n)638 explosion (CONST int x, CONST int y, CONST int type, CONST int letter, CONST int n)
639 {
640   float           i;
641   int             speed;
642   int             color1;
643   int             radius1 = radius (type);
644 #ifdef NETSUPPORT
645   if (server)
646     {
647       Explosion (x, y, type, letter, n);
648       return;
649     }
650 #endif
651   for (i = 0; i < RAD (360); i += RAD (360.0) * DIV * DIV / radius1 / radius1 / M_PI)
652     {
653       speed = rand () % 3096 + 10;
654       if (DIV == 1)
655 	color1 = color (type, n, letter) + (rand () % 16);
656       else
657 	color1 = color (type, n, letter) + (rand () % 32);
658       addpoint (x * 256, y * 256,
659 		sin (i) * (speed),
660 		cos (i) * (speed),
661 		color1,
662 		rand () % 100 + 10);
663     }
664 }
665 
666 
667 
668 static void
rocket_destroyed(CONST int player)669 rocket_destroyed (CONST int player)
670 {
671   int             i, nalive = 0, igagnant = 0;
672   if (gamemode == GAME)
673     switch (gameplan)
674       {
675       case DEATHMATCH:
676 	if (nrockets == 1)
677 	  return;
678 	for (i = 0; i < nrockets; i++)
679 	  if (object[i].type == ROCKET && object[i].live && i != player)
680 	    {
681 	      object[i].score += 100;
682 	      nalive++;
683 	      igagnant = i;
684 	    }
685 	if (nalive == 1)	/* winner bonus */
686 	  object[igagnant].score += 50;
687       }
688 }
689 
690 
691 
692 void
destroy(CONST int i)693 destroy (CONST int i)
694 {
695   int             y;
696   if (object[i].x - object[i].radius < 0)
697     object[i].x = object[i].radius + 1, object[i].fx *= -1;
698   if (object[i].y - object[i].radius < 0)
699     object[i].y = object[i].radius + 1, object[i].fy *= -1;
700   if (object[i].x + object[i].radius > GAMEWIDTH)
701     object[i].x = GAMEWIDTH - object[i].radius - 1, object[i].fx *= -1;
702   if (object[i].y + object[i].radius > GAMEHEIGHT)
703     object[i].y = GAMEHEIGHT - object[i].radius - 1, object[i].fy *= -1;
704   switch (object[i].type)
705     {
706     case LBALL:
707       Effect (S_DESTROY_BALL, next);
708       object[i].live = 0, explosion (object[i].x, object[i].y, object[i].type, object[i].letter, i);
709       if (object[i].letter == L_THIEF && allow_finder ())
710 	{
711 	  object[i].live = 1;
712 	  object[i].letter = L_FINDER;
713 	}			/* else
714 				   if (object[i].letter == L_FINDER )
715 				   {
716 				   object[i].live = 1;
717 				   object[i].letter = L_THIEF;
718 				   } */
719       break;
720     case APPLE:
721       Effect (S_DESTROY_ROCKET, 0);
722       object[i].live = 0, explosion (object[i].x, object[i].y, object[i].type, object[i].letter, i);
723       break;
724     case BALL:
725     case EHOLE:
726     case BBALL:
727     case INSPECTOR:
728     case LUNATIC:
729       Effect (S_DESTROY_BALL, next);
730       if ((y = create_letter ()) != 0)
731 	{
732 	  object[i].type = LBALL;
733 	  object[i].M = LBALLM;
734 	  switch (y)
735 	    {
736 	    case 1:
737 	      object[i].letter = L_ACCEL;
738 	      break;
739 	    case 2:
740 	      object[i].letter = L_GUMM;
741 	      break;
742 	    case 3:
743 	      object[i].letter = L_THIEF;
744 	      break;
745 	    case 4:
746 	      object[i].letter = L_FINDER;
747 	      break;
748 	    case 5:
749 	      object[i].letter = L_TTOOL;
750 	      break;
751 	      /*case 3:
752 	         object[i].letter = L_MUGG;
753 	         break;
754 	         case 4:
755 	         object[i].letter = L_SLOW;
756 	         break;
757 	         case 5:
758 	         object[i].letter = L_WIZZ;
759 	         break;
760 	         case 6:
761 	         object[i].letter = L_FUCK;
762 	         break; */
763 	    }
764 	}
765       else
766 	object[i].live = 0, explosion (object[i].x, object[i].y, object[i].type, object[i].letter, i);
767       break;
768     case ROCKET:
769       Effect (S_DESTROY_ROCKET, 0);
770       object[i].live1--, object[i].live--, explosion (object[i].x, object[i].y, object[i].type, object[i].letter, i);
771       rocket_destroyed (i);
772       if (object[i].live)
773 	{
774 	  /*object[i].x = rand () % (GAMEWIDTH-60)+30;
775 	     object[i].y = rand () % (GAMEHEIGHT-60)+30; */
776 	  object[i].fx = 0;
777 	  object[i].fy = 0;
778 	  object[i].rotation = 0;
779 	  object[i].type = ROCKET;
780 	  object[i].accel = ROCKET_SPEED;
781 	  creator_rocket (i);
782 	}
783       break;
784     }
785 }
786 
787 
788 
789 
790 static void
check_limit()791 check_limit ()
792 {
793   int             i;
794   for (i = 0; i < nobjects; i++)
795     if (object[i].live)
796       {
797 	if (object[i].x - object[i].radius < 0 || object[i].x + object[i].radius >= GAMEWIDTH ||
798 	    object[i].y - object[i].radius <= 0 || object[i].y + object[i].radius >= GAMEHEIGHT)
799 	  {
800 	    destroy (i);
801 	  }
802       }
803 }
804 
805 
806 
807 /*
808  * count number of creatures
809  */
810 static void
update_values()811 update_values ()
812 {
813   int             i;
814   a_holes = 0;
815   a_rockets = 0;
816   a_balls = 0;
817   a_bballs = 0;
818   a_apples = 0;
819   a_eholes = 0;
820   a_inspectors = 0;
821   a_lunatics = 0;
822   for (i = 0; i < nobjects; i++)
823     {
824       if (object[i].live)
825 	{
826 	  switch (object[i].type)
827 	    {
828 	    case HOLE:
829 	      a_holes++;
830 	      break;
831 	    case EHOLE:
832 	      a_eholes++;
833 	      break;
834 	    case ROCKET:
835 	      a_rockets++;
836 	      break;
837 	    case LBALL:
838 	    case BALL:
839 	      a_balls++;
840 	      break;
841 	    case BBALL:
842 	      a_bballs++;
843 	      break;
844 	    case APPLE:
845 	      a_apples++;
846 	      break;
847 	    case INSPECTOR:
848 	      a_inspectors++;
849 	      break;
850 	    case LUNATIC:
851 	      a_lunatics++;
852 	      break;
853 	    }
854 	}
855       if (object[i].type == CREATOR)
856 	{
857 	  switch (object[i].ctype)
858 	    {
859 	    case BBALL:
860 	      a_bballs++;
861 	      break;
862 	    case HOLE:
863 	      a_holes++;
864 	      break;
865 	    case EHOLE:
866 	      a_eholes++;
867 	      break;
868 	    case ROCKET:
869 	      a_rockets++;
870 	      break;
871 	    case LBALL:
872 	    case BALL:
873 	      a_balls++;
874 	      break;
875 	    case APPLE:
876 	      a_apples++;
877 	      break;
878 	    case INSPECTOR:
879 	      a_inspectors++;
880 	      break;
881 	    case LUNATIC:
882 	      a_lunatics++;
883 	      break;
884 	    }
885 	}
886     }
887 
888 }
889 
890 
891 
892 /*
893  * accelerate rocket
894  */
895 void
896 /* howmuch is between 0 and 1, everything else is cheating */
accel(CONST int i,CONST double howmuch)897 accel (CONST int i, CONST double howmuch)
898 {
899   int             y;
900 #ifdef NETSUPPORT
901   if (server)
902     acceled[i] = 1;
903 #endif
904 #ifdef NETSUPPORT
905   if (!client)
906 #endif
907     {
908       object[i].time = 0;
909        object[i].fx += howmuch * sin (object[i].rotation) * object[i].accel,
910        object[i].fy += howmuch * cos (object[i].rotation) * object[i].accel;
911 #ifdef NETSUPPORT
912       if (!server)
913 #endif
914 	for (y = 0; y < 5 / DIV / DIV; y++)
915 	  {
916 	    float           p;
917 	    p = RAD (rand () % 45 - 22);
918 	    addpoint (object[i].x * 256,
919 		      object[i].y * 256,
920 		      (object[i].fx - howmuch * sin (object[i].rotation + p) * object[i].accel * 10) * (rand () % 512),
921 		      (object[i].fy - howmuch * cos (object[i].rotation + p) * object[i].accel * 10) * (rand () % 512),
922 		      rocket (rand () % 16), 10);
923 	  }
924     }
925 #ifdef NETSUPPORT
926   else
927     {
928       for (y = 0; y < 5 / DIV / DIV; y++)
929 	{
930 	  float           p;
931 	  p = RAD (rand () % 30 - 15);
932 	  addpoint (object[i].x * 256,
933 		    object[i].y * 256,
934 		    (-sin (object[i].rotation + p) * ROCKET_SPEED * 5) * (rand () % 512),
935 		    (-cos (object[i].rotation + p) * ROCKET_SPEED * 5) * (rand () % 512),
936 		    rocket (rand () % 16), 10);
937 	}
938     }
939 #endif
940 }
941 
942 
943 static void
sprocess_keys()944 sprocess_keys ()
945 {
946   int             i;
947   if (gamemode != GAME)
948     return;
949   for (i = 0; i < MAXROCKETS; i++)
950     {
951       if (object[i].live && object[i].type == ROCKET)
952 	{
953 	  switch (controls[i].type)
954 	    {
955 #ifdef JOYSTICK
956 	    case C_JOYSTICK1:
957 	      {
958 		double          a, x = controls[i].jx, y = controls[i].jy;
959 		a = atan (fabs (y) / fabs (x));
960 		if (x < 0 && y >= 0)
961 		  object[i].rotation = a + RAD (90);
962 		else if (x < 0 && y < 0)
963 		  object[i].rotation = RAD (90) - a;
964 		else if (x >= 0 && y < 0)
965 		  object[i].rotation = a + RAD (270);
966 		else if (x >= 0 && y >= 0)
967 		  object[i].rotation = RAD (270) - a;
968 		/* Measure the deflection (a is betw. 0 and 1) */
969   	        a=hypot(x*object[i].joymulx,y*object[i].joymuly);
970            	/* I must make sure, that I am not cheating :-)  */
971 		/* "a" can't be bigger than one */
972 	        if((a>1.0)||(controls[i].mask!=0))a=1.0;
973 	        if(a>object[i].joythresh)accel(i,a);
974 	      }
975 	      break;
976 #endif
977 	    case C_MOUSE:
978 	      {
979 		double          dx, dy, a;
980 		dx = object[i].x - controls[i].mx;
981 		dy = object[i].y - controls[i].my;
982 		if (dx == 0)
983 		  dx = 0.001;
984 		a = atan (fabs (dy) / fabs (dx));
985 		if (dx < 0 && dy >= 0)
986 		  object[i].rotation = a + RAD (90);
987 		else if (dx < 0 && dy < 0)
988 		  object[i].rotation = RAD (90) - a;
989 		else if (dx >= 0 && dy < 0)
990 		  object[i].rotation = a + RAD (270);
991 		else if (dx >= 0 && dy >= 0)
992 		  object[i].rotation = RAD (270) - a;
993 		if (controls[i].mask)
994 		  accel (i ,1.0);
995 	      }
996 	      break;
997 	    case C_RKEYBOARD:
998 	      if (controls[i].mask & 1)
999 		object[i].rotation += ROTSTEP;
1000 	      if (controls[i].mask & 2)
1001 		object[i].rotation -= ROTSTEP;
1002 	      if (controls[i].mask & 4)
1003 		accel (i ,1.0);
1004 	      break;
1005 	    case C_KEYBOARD:
1006 	      switch (controls[i].mask)
1007 		{
1008 		case 1:
1009 		  object[i].rotation = RAD (-135), accel (i ,1.0);
1010 		  break;
1011 		case 2:
1012 		  object[i].rotation = RAD (135), accel (i ,1.0);
1013 		  break;
1014 		case 3:
1015 		  object[i].rotation = RAD (45), accel (i ,1.0);
1016 		  break;
1017 		case 4:
1018 		  object[i].rotation = RAD (-45), accel (i ,1.0);
1019 		  break;
1020 		case 5:
1021 		  object[i].rotation = RAD (-90), accel (i ,1.0);
1022 		  break;
1023 		case 6:
1024 		  object[i].rotation = RAD (90), accel (i ,1.0);
1025 		  break;
1026 		case 7:
1027 		  object[i].rotation = RAD (180), accel (i ,1.0);
1028 		  break;
1029 		case 8:
1030 		  object[i].rotation = RAD (0), accel (i ,1.0);
1031 		  break;
1032 		}
1033 
1034 	    }
1035 	}
1036     }
1037 }
1038 
1039 void
process_keys()1040 process_keys ()
1041 {
1042   int             i;
1043   static int lasth=0;
1044 #ifdef JOYSTICK
1045   int             status;
1046   struct JS_DATA_TYPE js;
1047 #endif
1048 
1049 
1050   UpdateInput ();
1051   if (IsPressedH () && !lasth)
1052     {
1053       helpmode^=1;
1054     }
1055   lasth=IsPressedH();
1056   if (IsPressedP () && !client)
1057     {
1058       int             k = 1;
1059       SetScreen (backscreen);
1060       DrawText (MAPWIDTH / 2 - 20, MAPHEIGHT / 2 - 4, "PAUSE");
1061       CopyToScreen(backscreen);
1062 #ifdef OS2DIVE
1063       forceBlitting ();
1064 #endif
1065       tbreak = 1;
1066       while (k)
1067 	{
1068 	  UpdateInput ();
1069 	  k = Pressed ();
1070 #ifdef OS2DIVE
1071 	  DosSleep (WAIT);
1072 #endif
1073 	}
1074       while (!k)
1075 	{
1076 	  UpdateInput ();
1077 	  k = Pressed ();
1078 #ifdef OS2DIVE
1079 	  DosSleep (WAIT);
1080 #endif
1081 	}
1082     }
1083   switch (gamemode)
1084     {
1085     case MENU:
1086       menu_keys ();
1087       break;
1088     case KEYS:
1089       keys_keys ();
1090       break;
1091 #ifdef JOYSTICK
1092     case JOY:
1093       joy_keys ();
1094       break;
1095 #endif
1096     case GAME:
1097 #ifdef JOYSTICK
1098       for (i = 0; i < 2; i++)
1099 	{
1100 	  double          x, y;
1101 	  if (joystickplayer[i] >= 0)
1102 	    {
1103 	      if (object[joystickplayer[i]].type != ROCKET)
1104 		continue;
1105 	      status = read (joystickdevice[i], &js, JS_RETURN);
1106 	      if (status != JS_RETURN)
1107 		{
1108 		  break;
1109 		}
1110 	      x = center[i][0] - js.x;
1111 	      y = center[i][1] - js.y;
1112               if (x == 0)
1113 		x = 0.001;
1114 	      controls[joystickplayer[i]].jx = x;
1115 	      controls[joystickplayer[i]].jy = y;
1116 	      controls[joystickplayer[i]].mask = js.buttons;
1117 	      controls[joystickplayer[i]].type = C_JOYSTICK1;
1118 
1119 	    }
1120 	}
1121 #endif
1122 #ifdef MOUSE
1123       /* Move. */
1124       if (mouseplayer != -1 && object[mouseplayer].type == ROCKET
1125       /*&& (MouseButtons ()||controls[mouseplayer].mask) */ )
1126 	{
1127 	  controls[mouseplayer].mx = MouseX () * DIV;
1128 	  controls[mouseplayer].my = MouseY () * DIV;
1129 	  controls[mouseplayer].mask = MouseButtons () != 0;
1130 	  controls[mouseplayer].type = C_MOUSE;
1131 	}
1132 #endif
1133       if (IsPressedEsc ())
1134 	{
1135 #ifdef NETSUPPORT
1136 	  if (!client)
1137 	    {
1138 #endif
1139 	      gamemode = MENU;
1140 	      while (IsPressedEsc ())
1141 		UpdateInput ();
1142 #ifdef NETSUPPORT
1143 	    }
1144 	  else
1145 	    {
1146 	      CQuit ("client exit-ESC pressed\n");
1147 	    }
1148 #endif
1149 	}
1150       for (i = 0; i < nrockets; i++)
1151 	{
1152 #ifdef MOUSE
1153 	  if (i == mouseplayer)
1154 	    continue;
1155 #endif
1156 #ifdef JOYSTICK
1157 	  if (i == joystickplayer[0] ||
1158 	      i == joystickplayer[1])
1159 	    continue;
1160 #endif
1161 #ifdef NETSUPPORT
1162 	  if (client && !control[i])
1163 	    continue;
1164 #endif
1165 	  if (object[i].type != ROCKET)
1166 	    continue;
1167 	  if (rotation[i])
1168 	    {
1169 	      char            s = 0;
1170 	      if (IsPressed (keys[i][1]))
1171 		s = 1;
1172 	      if (IsPressed (keys[i][2]))
1173 		s |= 2;
1174 	      if (IsPressed (keys[i][0]))
1175 		s |= 4;
1176 	      controls[i].type = C_RKEYBOARD;
1177 	      controls[i].mask = s;
1178 	    }
1179 	  else
1180 	    {
1181 	      int             s = 0;
1182 	      if (IsPressed (keys[i][2]) && IsPressed (keys[i][0]))
1183 		s = 1;
1184 	      else if (IsPressed (keys[i][3]) && IsPressed (keys[i][0]))
1185 		s = 2;
1186 	      else if (IsPressed (keys[i][1]) && IsPressed (keys[i][3]))
1187 		s = 3;
1188 	      else if (IsPressed (keys[i][1]) && IsPressed (keys[i][2]))
1189 		s = 4;
1190 	      else if (IsPressed (keys[i][2]))
1191 		s = 5;
1192 	      else if (IsPressed (keys[i][3]))
1193 		s = 6;
1194 	      else if (IsPressed (keys[i][0]))
1195 		s = 7;
1196 	      else if (IsPressed (keys[i][1]))
1197 		s = 8;
1198 	      controls[i].type = C_KEYBOARD;
1199 	      controls[i].mask = s;
1200 	    }
1201 	}
1202       break;
1203     }
1204 
1205 
1206 
1207 }
1208 
1209 #define MIN(a,b) ((a)>(b)?(b):(a))
1210 /*
1211  * Make creations happen as coalescing circular cloud.  Do this by
1212  * creating random points within circle defined from center of screen, and
1213  * giving them velocity towards desired final point.
1214  */
1215 
1216 void
creators_points(int radius,int x1,int y1,int color1)1217 creators_points (int radius, int x1, int y1, int color1)
1218 {
1219     int             z, x, y, x2, y2;
1220     double r;
1221     int             time = 50;
1222     int             midX, midY, r2,r1;
1223 
1224     midX = GAMEWIDTH / 2;
1225     midY = GAMEHEIGHT / 2;
1226     r2 = r1 = MIN(midX, midY);
1227     r2 *= r2;
1228 
1229     z = radius * radius * M_PI / DIV / DIV;
1230     while (z--) {
1231 	do {
1232 	    x = rand() % GAMEWIDTH;
1233 	    y = rand() % GAMEHEIGHT;
1234 	} while (((x-midX)*(x-midX) + (y-midY)*(y-midY)) > r2);
1235 	r=sqrt((double)((x-midX)*(x-midX) + (y-midY)*(y-midY)));
1236 	r=(r*radius/r1)/r*0.9;
1237 	x2=x1+(x-midX)*r;
1238 	y2=y1+(y-midY)*r;
1239 
1240 	addpoint(x * 256, y * 256,
1241 		    (x2 - x) * 256 / (time),
1242 		    (y2 - y) * 256 / (time),
1243 		    color1 + (rand() % (DIV == 1 ? 16 : 32)),
1244 		    time);
1245     }
1246 }
1247 
1248 void
creator(CONST int type)1249 creator (CONST int type)
1250 {
1251   int             i;
1252   int             color1 = color (type, 0, 0);
1253   for (i = nrockets; i < nobjects && (object[i].live ||
1254 				      object[i].type == CREATOR);
1255        i++);
1256   if (i >= MAXOBJECT)
1257     return;
1258   if (!find_possition (&object[i].x, &object[i].y, radius (type)))
1259     return;
1260   if (i >= nobjects)
1261     nobjects = i + 1;
1262   object[i].live = 0;
1263   object[i].live1 = 1;
1264   object[i].lineto = -1;
1265   object[i].ctype = type;
1266   object[i].fx = 0.0;
1267   object[i].fy = 0.0;
1268   object[i].time = 50;
1269   object[i].rotation = 0;
1270   object[i].type = CREATOR;
1271   object[i].M = M (type);
1272   object[i].radius = radius (type);
1273   object[i].accel = ROCKET_SPEED;
1274   object[i].letter = ' ';
1275 #ifdef NETSUPPORT
1276   if (server)
1277     CreatorsPoints (object[i].radius, object[i].x, object[i].y, color1);
1278   else
1279 #endif
1280     creators_points (object[i].radius, object[i].x, object[i].y, color1);
1281   Effect (S_CREATOR1, 0);
1282 }
1283 
1284 
1285 void
creator_rocket(CONST int i)1286 creator_rocket (CONST int i)
1287 {
1288   int             type = ROCKET;
1289   int             color1 = color (ROCKET, i, 0);
1290   if (!find_possition (&object[i].x, &object[i].y, radius (type)))
1291     return;
1292   if (sound)
1293     object[i].live1 = object[i].live;
1294   object[i].live = 0;
1295   object[i].thief = 0;
1296   object[i].ctype = type;
1297   object[i].lineto = -1;
1298   object[i].fx = 0.0;
1299   object[i].fy = 0.0;
1300   object[i].time = 50;
1301   object[i].rotation = 0;
1302   object[i].type = CREATOR;
1303   object[i].M = ROCKETM;
1304   object[i].radius = ROCKET_RADIUS;
1305   object[i].accel = ROCKET_SPEED;
1306   object[i].letter = ' ';
1307 #ifdef NETSUPPORT
1308   if (server)
1309     CreatorsPoints (ROCKET_RADIUS, object[i].x, object[i].y, color1);
1310   else
1311 #endif
1312     creators_points (ROCKET_RADIUS, object[i].x, object[i].y, color1);
1313 }
1314 
1315 
1316 
1317 
1318 static void
update_forces()1319 update_forces ()
1320 {
1321   int             i;
1322   int             r;
1323   float           d;
1324   float           xp, yp;
1325   int             frocket = 0;
1326   for (i = 0; i < nobjects; i++)
1327     {
1328       if (object[i].live)
1329 	{
1330 	  if (object[i].lineto != -1)
1331 	    {
1332 	      if (!object[object[i].lineto].live)
1333 		object[i].lineto = -1;
1334 	      else if (object[i].lineto == i)
1335 		object[i].lineto = -1;
1336 	      else
1337 		{
1338 		  int             force;
1339 		  xp = object[i].x - object[object[i].lineto].x;
1340 		  yp = object[i].y - object[object[i].lineto].y;
1341 		  force = sqrt (xp * xp + yp * yp);
1342 		  if (force >= 2 * SPRINGSIZE || gameplan == COOPERATIVE)
1343 		    {
1344 		      force = force - SPRINGSIZE;
1345 		      if (force < 0)
1346 			force *= 3;
1347 		      force = force / SPRINGSTRENGTH;
1348 		      normalize (&xp, &yp, force * BALL_SPEED / object[i].M);
1349 		      object[i].fx -= xp;
1350 		      object[i].fy -= yp;
1351 		      normalize (&xp, &yp, force * BALL_SPEED / object[object[i].lineto].M);
1352 		      object[object[i].lineto].fx += xp;
1353 		      object[object[i].lineto].fy += yp;
1354 		    }
1355 		}
1356 	    }
1357 	  if (object[i].type == ROCKET && object[i].time)
1358 	    object[i].time--;
1359 	  if (object[i].type == ROCKET && !object[i].time)
1360 	    {
1361 	      d = 640 * 640;
1362 	      frocket = -1;
1363 	      for (r = 0; r < nobjects; r++)
1364 		{
1365 		  if (object[r].live && !object[r].time && object[r].type == EHOLE)
1366 		    {
1367 		      int             distance;
1368 		      float           gravity;
1369 		      xp = object[r].x - object[i].x;
1370 		      yp = object[r].y - object[i].y;
1371 		      distance = sqrt (xp * xp + yp * yp);
1372 		      gravity = BALL_SPEED * (gameplan == COOPERATIVE ? 200 : 50) / distance;
1373 		      if (gravity > BALL_SPEED * 4 / 5)
1374 			gravity = BALL_SPEED * 4 / 5;
1375 		      normalize (&xp, &yp, gravity);
1376 		      object[i].fx += xp;
1377 		      object[i].fy += yp;
1378 		    }
1379 		}
1380 
1381 	    }
1382 	  if (object[i].type == BALL || object[i].type == LBALL || object[i].type == BBALL || object[i].type == LUNATIC)
1383 	    {
1384 	      frocket = -1;
1385 	      d = 640 * 640;
1386 	      for (r = 0; r < nrockets; r++)
1387 		{
1388 		  if (object[r].live && !object[r].time)
1389 		    {
1390 		      xp = object[r].x - object[i].x;
1391 		      yp = object[r].y - object[i].y;
1392 		      if (xp * xp + yp * yp < d)
1393 			d = xp * xp + yp * yp, frocket = r;
1394 		    }
1395 		}
1396 	      if (frocket != -1)
1397 		xp = object[frocket].x - object[i].x,
1398 		  yp = object[frocket].y - object[i].y;
1399 	      else
1400 		xp = GAMEWIDTH / 2 - object[i].x,
1401 		  yp = GAMEHEIGHT / 2 - object[i].y;
1402 	      if (object[i].type == LUNATIC && !rand () % 4)
1403 		{
1404 		  xp = rand ();
1405 		  yp = rand () + 1;
1406 		}
1407 	      switch (object[i].type)
1408 		{
1409 		case BBALL:
1410 		  normalize (&xp, &yp, BBALL_SPEED);
1411 		  break;
1412 		case BALL:
1413 		case LUNATIC:
1414 		case LBALL:
1415 		  normalize (&xp, &yp, BALL_SPEED);
1416 		  break;
1417 		}
1418 	      object[i].fx += xp;
1419 	      object[i].fy += yp;
1420 	    }
1421 	  object[i].fx *= SLOWDOWN,
1422 	    object[i].fy *= SLOWDOWN;
1423 	}
1424     }
1425 }
1426 
1427 
1428 
1429 
1430 static void
colisions()1431 colisions ()
1432 {
1433   int             i, y;
1434   int             colize = 0;
1435   static int      ctime = 0;
1436   float           xp, yp, gummfactor;
1437   for (i = 0; i < nobjects; i++)
1438     if (object[i].live)
1439       for (y = i + 1; y < nobjects; y++)
1440 	if (object[y].live)
1441 	  {
1442 	    xp = object[y].x - object[i].x;
1443 	    yp = object[y].y - object[i].y;
1444 	    if (xp * xp + yp * yp < (object[y].radius + object[i].radius) *
1445 		(object[y].radius + object[i].radius))
1446 	      {
1447 		colize = 1;
1448 		if (object[i].type == HOLE || object[i].type == EHOLE)
1449 		  {
1450 		    if (object[y].type != APPLE)
1451 		      destroy (y);
1452 		    if (object[i].type == EHOLE)
1453 		      destroy (i);
1454 		    continue;
1455 		  }
1456 		if (object[y].type == HOLE || object[y].type == EHOLE)
1457 		  {
1458 		    if (object[i].type != APPLE)
1459 		      destroy (i);
1460 		    if (object[y].type == EHOLE)
1461 		      destroy (y);
1462 		    continue;
1463 		  }
1464 		if (object[i].type == ROCKET)
1465 		  {
1466 		    if (object[y].thief == 1 && object[i].thief == 1)
1467 		      {
1468 			float           tmp;
1469 			tmp = object[i].M;
1470 			object[i].M = object[y].M;
1471 			object[y].M = tmp;
1472 			object[i].thief = 0;
1473 			object[y].thief = 0;
1474 		      }
1475 		    if (object[y].type == BBALL && object[i].thief == 1)
1476 		      {
1477 			object[i].M += object[y].M - M (BALL);
1478 			object[i].thief = 0;
1479 			object[y].M = M (BALL);
1480 		      }
1481 		    else if (object[y].type == ROCKET && object[i].thief == 1)
1482 		      {
1483 			object[i].M += object[y].M - M (ROCKET);
1484 			object[i].accel += object[y].accel - ROCKET_SPEED;
1485 			object[i].thief = 0;
1486 			object[y].M = M (object[i].type);
1487 			object[y].accel = ROCKET_SPEED - A_ADD;
1488 		      }
1489 		    if (object[i].type == ROCKET && object[y].thief == 1)
1490 		      {
1491 			object[y].M += object[i].M - M (ROCKET);
1492 			object[y].accel += object[i].accel - ROCKET_SPEED;
1493 			object[y].thief = 0;
1494 			object[i].M = M (object[y].type);
1495 			object[i].accel = ROCKET_SPEED - A_ADD;
1496 		      }
1497 		    if (gameplan == COOPERATIVE)
1498 		      object[i].score++;
1499 		    if (object[y].letter == L_ACCEL)
1500 		      object[i].accel += A_ADD,
1501 			object[i].score += 10;
1502 		    if (object[y].letter == L_GUMM)
1503 		      object[i].M += M_ADD,
1504 			object[i].score += 10;
1505 		    if (object[y].letter == L_THIEF)
1506 		      object[i].M = M (object[i].type),
1507 			object[i].accel = ROCKET_SPEED - A_ADD,
1508 			object[i].score -= 30;
1509 		    if (object[y].letter == L_FINDER)
1510 		      {
1511 			object[i].accel += A_ADD * (rand () % 5);
1512 			object[i].M += M_ADD * (rand () % 10);
1513 			object[i].score += 30;
1514 		      }
1515 		    if (object[y].letter == L_TTOOL)
1516 		      {
1517 			object[i].thief = 1;
1518 			object[i].score += 30;
1519 		      }
1520 
1521 		    object[y].letter = ' ';
1522 		    if (object[y].type == LBALL)
1523 		      object[y].type = BALL;
1524 		    if (object[y].type == BALL && dosprings && !(rand () % randsprings))
1525 		      object[y].lineto = i;
1526 
1527 		    if (gameplan == DEATHMATCH && object[y].type == ROCKET && dosprings && !(rand () % (2 * randsprings)))
1528 		      object[y].lineto = i;
1529 		  }
1530 		if (object[y].type == LUNATIC)
1531 		  {
1532 		    gummfactor = -ROCKETM / LUNATICM;
1533 		  }
1534 		else if (object[i].type == LUNATIC)
1535 		  {
1536 		    gummfactor = -LUNATICM / ROCKETM;
1537 		  }
1538 		else
1539 		  gummfactor = object[i].M / object[y].M;
1540 		normalize (&xp, &yp, gummfactor * GUMM);
1541 		object[y].fx += xp;
1542 		object[y].fy += yp;
1543 		normalize (&xp, &yp, 1 / gummfactor * GUMM);
1544 		object[i].fx -= xp;
1545 		object[i].fy -= yp;
1546 		if (object[i].type == ROCKET && object[i].time)
1547 		  object[i].fx = 0,
1548 		    object[i].fy = 0;
1549 		if (object[y].type == ROCKET && object[y].time)
1550 		  object[y].fx = 0,
1551 		    object[y].fy = 0;
1552 		if (object[y].type == INSPECTOR && object[i].type == ROCKET)
1553 		  {
1554 		    object[y].fx = 0,
1555 		      object[y].fy = 0;
1556 		    object[i].fx *= -2,
1557 		      object[i].fy *= -2;
1558 		  }
1559 	      }
1560 	  }
1561   if (colize && !ctime)
1562     {
1563 #ifndef NAS_SOUND
1564       Effect (S_COLIZE, next);
1565 #endif
1566       ctime = 4;
1567     }
1568   if (ctime)
1569     ctime--;
1570 }
1571 
1572 
1573 
1574 void
game()1575 game ()
1576 {
1577   long            VfTime = 0;
1578   long            VendSleep = 0;
1579   struct timeval  VlastClk;
1580   struct timeval  VnewClk;
1581   int             wait = 0;
1582 
1583   load_rc ();
1584   init_menu ();
1585   gettimeofday (&VlastClk, NULL);
1586   gettimeofday (&VnewClk, NULL);
1587   VendSleep = VlastClk.tv_usec;
1588   VfTime = 1000000 / 25;
1589 
1590 
1591   while (1)
1592     {
1593       process_keys ();
1594       sprocess_keys ();
1595       update_values ();
1596       update_game ();
1597       update_forces ();
1598       colisions ();
1599       move_objects ();
1600       check_limit ();
1601       gettimeofday (&VnewClk, NULL);
1602       if (VnewClk.tv_usec < VendSleep)
1603 	VendSleep -= 1000000;
1604       wait = (VfTime - VnewClk.tv_usec + VendSleep);
1605       if (wait > 0 || tbreak)
1606 	draw_objects (1);
1607       else
1608 	draw_objects (0);
1609       gettimeofday (&VnewClk, NULL);
1610       if (VnewClk.tv_usec < VendSleep)
1611 	VendSleep -= 1000000;
1612       wait = (VfTime - VnewClk.tv_usec + VendSleep);
1613       if (tbreak)
1614 	wait = VfTime;
1615       if (wait > 0)
1616 	usleep (wait);
1617       VendSleep = VnewClk.tv_usec + wait;
1618       gettimeofday (&VlastClk, NULL);
1619       if (tbreak)
1620 	tbreak = 0,
1621 	  VendSleep = VlastClk.tv_usec;
1622 
1623     }
1624 }
1625 #ifdef NETSUPPORT
1626 void
client_loop2(int draw)1627 client_loop2 (int draw)		/*game part of server loop */
1628 {
1629   draw_objects (draw);
1630   switch (gamemode)
1631     {
1632     case MENU:
1633       draw_menu (draw);
1634       break;
1635     case KEYS:
1636       draw_keys (draw);
1637       break;
1638 #ifdef JOYSTICK
1639     case JOY:
1640       draw_joy (draw);
1641       break;
1642 #endif
1643     }
1644 }
1645 void
server_loop2(void)1646 server_loop2 (void)		/*game part of server loop */
1647 {
1648   sprocess_keys ();
1649   update_values ();
1650   update_game ();
1651   update_forces ();
1652   colisions ();
1653   move_objects ();
1654   check_limit ();
1655 }
1656 #endif
1657