home *** CD-ROM | disk | FTP | other *** search
/ Collection of Education / collectionofeducationcarat1997.iso / GAMES / CAROM10.ZIP / CAROMSRC.ZIP / BALLFULL.C < prev    next >
C/C++ Source or Header  |  1994-08-13  |  16KB  |  533 lines

  1. /*
  2.    Copyright (c) 1994 Csaba Mßrkus. All rights reserved.
  3.    E-mail: ethcms@duna.ericsson.se
  4.    Addr.:  H-9600 Sßrvßr, Szatmßr u. 4, Hungary
  5.  
  6.    Permission to use, copy, modify, and distribute this software and its
  7.    documentation for any purpose, without fee, and without written agreement
  8.    is hereby granted, provided that the above copyright notice and the
  9.    following two paragraphs appear in all copies of this software.
  10.  
  11.    IN NO EVENT SHALL THE AUTHOR BE LIABLE TO ANY PARTY FOR
  12.    DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
  13.    OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE AUTHOR HAS
  14.    BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  15.  
  16.    THE AUTHOR DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  17.    IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  18.    THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE AUTHOR HAS
  19.    NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS
  20.    OR MODIFICATIONS.
  21. */
  22.  
  23. /* File: ballfull.c
  24.    Purpose: This file emulates the physics of the balls.
  25. */
  26.  
  27. #include <stdio.h>
  28. #include <stdlib.h>
  29. #include <math.h>
  30. #include <windows.h>
  31.  
  32. #include "ballfull.h"
  33. #include "trigo.h"
  34.  
  35. extern HGLOBAL hglbShotHistory;
  36.  
  37. /* SQRT3
  38. */
  39. #define SQRT3 1.732050808
  40.  
  41. /* sqrt(2.0/5.0), which is the vspeed/vrotation_on_surface ratio if
  42.    moving with the speed 'vspeed' and revolving with 'vrotation_on_surface'
  43.    surface speed represent the same energy.
  44. */
  45. #define SQRT_2OVER5 0.632455532
  46.  
  47. /* Macro to convert a positive float number into an unsigned by muliplying
  48.    it with 16 and rounding:
  49. */ 
  50. #define FIXED(x) ((unsigned) (floor((x) * FIXED_MULT + 0.5)))
  51.  
  52. ball_data ball[] = {
  53.     /* This is the cue ball of the first player: white ball:
  54.     */
  55.     { BOTTOMR_SPOT_X, BOTTOMR_SPOT_Y,    /* Position */    
  56.       BALL_RADIUS, BALL_MASS,        /* Radius and mass */
  57.       "White", "Cue Ball #1",        /* Colour and name */
  58.       0, 0,                /* Speed and direction of moving */
  59.       0, 0,                /* Speed and direction of rolling */
  60.       0 },                /* Speed of revolving */
  61.  
  62.     /* This is the cue ball of the other player: white ball with spot:
  63.     */
  64.     { BOTTOMM_SPOT_X, BOTTOMM_SPOT_Y,    /* Position */
  65.       BALL_RADIUS, BALL_MASS,        /* Radius and mass */
  66.       "Yellow", "Cue Ball #1",        /* Colour and name */
  67.       0, 0,                /* Speed and direction of moving */
  68.       0, 0,                /* Speed and direction of rolling */
  69.       0 },                /* Speed of revolving */
  70.  
  71.     /* And this is the common ball: red ball:
  72.     */
  73.     { TOP_SPOT_X, TOP_SPOT_Y,        /* Position */
  74.       BALL_RADIUS, BALL_MASS,        /* Radius and mass */
  75.       "Red", "Cue Ball #1",        /* Colour and name */
  76.       0, 0,                /* Speed and direction of moving */
  77.       0, 0,                /* Speed and direction of rolling */
  78.       0 }                /* Speed of revolving */
  79. };
  80.  
  81.  
  82. /* Global variables used for recognizing the event of a "carom".
  83. */
  84. int iscarom[N];
  85. int cushion_counter; 
  86.  
  87. /* Global variables to maintain the first collision:
  88. */
  89. int no_collision;
  90. int collision_first_ball;
  91.  
  92. /* develop_balls
  93.  
  94.    This is the heart of the "biliardness" of the program.
  95. */
  96.  
  97. int develop_balls(ball_data *ball, int n, int cueball,
  98.           unsigned char *cush_beep,unsigned char *ball_beep)
  99. {
  100.     int i, j, jj, collision;
  101.     float ox, oy, nx, ny, r;
  102.     unsigned a;
  103.     float dx, dy;
  104.     unsigned ca, ai, aj;
  105.     float vip, vio, vjp, vjo;
  106.     float mi, mj, vion, vjon;
  107.     float total_speed = 0;
  108.     float hv, vv;
  109.     float dist, cosa, sina, discr, t, t1, q;
  110.  
  111.     /* No collision-beeps yet at this move:
  112.     */
  113.     *cush_beep = *ball_beep = 0;
  114.  
  115.     for (i=0; i<n; i++) {
  116.     /* Process ith ball: Compute its parameters at the next phase
  117.         */
  118.  
  119.     collision = 0;
  120.     r = ball[i].r;
  121.     a = ball[i].a;
  122.     ox = ball[i].x;
  123.     oy = ball[i].y;
  124.     cosa = tcos(a);
  125.     sina = tsin(a);
  126.     dist = (TIME_SLOT * ball[i].v) + r;
  127.     /* Check collision with other ball
  128.     */
  129.     for (t = RIGHT - LEFT, jj = -1, j = 0; j < n; j++) {
  130.         if (j != i &&
  131.         fabs(dx = ball[j].x - ox) <= dist + ball[j].r &&
  132.         fabs(dy = ball[j].y - oy) <= dist + ball[j].r) {
  133.         q = dx * cosa + dy * sina;
  134.         discr = (q * q) -((dx * dx) + (dy * dy) -
  135.                           (r + ball[j].r) * (r + ball[j].r));
  136.         if (discr > 0 && (t1 = q - sqrt(discr)) > 0 &&
  137.                          t1 < dist - r && t1 < t) {
  138.             t = t1;
  139.             jj = j;
  140.         }
  141.         }
  142.     }
  143.     if (jj >= 0) {
  144.         j = jj;
  145.         /* Compute exact place of collision (nx,ny). This position, however,
  146.            may be outside of the valid area:
  147.         */
  148.         nx = ox + (t * cosa);
  149.         ny = oy + (t * sina);
  150.         if (nx - r >= LEFT && nx + r <= RIGHT &&
  151.         ny - r >= BOTTOM && ny + r <= TOP) {
  152.         /* Place of collision is inside: mark that there is a collision,
  153.            develop ball to this position and analyse collision:
  154.         */
  155.         /* Yes, there is a collision:
  156.         */
  157.         (*ball_beep)++;
  158.         collision = 1;
  159.         ball[i].x = nx;
  160.         ball[i].y = ny;
  161.         /* Distances:
  162.         */
  163.         dx = nx - ball[j].x;
  164.         dy = ny - ball[j].y;
  165.         /* Process first ball:
  166.         */
  167.         ca = tatan2(dy, dx);        /* Angle of collision line */
  168.         ai = ball[i].a - ca;
  169.         vip = ball[i].v * tsin(ai);    /* This component remains */
  170.         vio = ball[i].v * tcos(ai);    /* This component will exchange */
  171.         /* Process second ball:
  172.         */
  173.         aj = ball[j].a - ca;
  174.         vjp = ball[j].v * tsin(aj);    /* This component remains */
  175.         vjo = ball[j].v * tcos(aj);    /* This component will exchange */
  176.         /* Check if they are really getting closer:
  177.         */
  178.         if (vjo > vio) {
  179.             /* Yes, they were really getting closer.
  180.                Create new speed vectors. First ball:
  181.             */
  182.             mi = ball[i].m;
  183.             mj = ball[j].m;
  184.             vion = (mi * vio + 2 * mj * vjo - mj * vio) / (mi + mj);
  185.             vjon = (mj * vjo + 2 * mi * vio - mi * vjo) / (mj + mi);
  186.             ball[i].v = sqrt((vip * vip) + (vion * vion));
  187.             if (ball[i].v > 0) {
  188.             ai = tatan2(vip, vion) + ca;
  189.             ball[i].a = ai;
  190.             }
  191.             /* Second ball:
  192.             */
  193.             ball[j].v = sqrt((vjp * vjp) + (vjon * vjon));
  194.             if (ball[j].v > 0) {
  195.             aj = tatan2(vjp, vjon) + ca;
  196.             ball[j].a = aj;
  197.             }
  198.             /* If the cue ball is one of the two balls that
  199.                collide, the other ball must be signed to
  200.                have been collided with the cue ball. This is
  201.                important to recognize the event of a "carom".
  202.                Additionally, if this is the first collision,
  203.                store the id of the non-cueball. This is also
  204.                needed because the first carom of a frame must
  205.                        be made from the red ball.
  206.             */
  207.             if (i == cueball || j == cueball) {
  208.             iscarom[i] = 1;
  209.             iscarom[j] = 1;
  210.             if (no_collision) {
  211.                 no_collision = 0;
  212.                             collision_first_ball = i == cueball ? j : i;
  213.                         }
  214.             }
  215.         }
  216.         }
  217.     }
  218.  
  219.     /* Develop ball in straight line unless it has collided:
  220.     */
  221.         if (!collision) {
  222.         ball[i].x += TIME_SLOT * ball[i].v * cosa;
  223.         ball[i].y += TIME_SLOT * ball[i].v * sina;
  224.         nx = ball[i].x;
  225.         ny = ball[i].y;
  226.  
  227.         /* Check collision with cushion
  228.         */
  229.         if ((nx - r <= LEFT) && (a > S_PI_2) && (a < 3 * S_PI_2)) {
  230.         /* Yes, there's a collision with the left cushion.
  231.         */
  232.         /* Place ball next to cushion, mirror angle (direction) of moving.
  233.         */
  234.         ball[i].y = oy + (ny - oy) * (ox - (LEFT + r)) / (ox - nx);
  235.         ball[i].x = LEFT + r;
  236.         nx = ball[i].x;
  237.         ny = ball[i].y;
  238.         ball[i].a = S_PI - ball[i].a;
  239. #ifdef SPIN_REFLECTION
  240.         ball[i].sa = S_PI - ball[i].sa;
  241. #else
  242.         ball[i].sv = 0;
  243. #endif
  244.         /* Update rotation if there's any:
  245.         */
  246.         if (ball[i].rv != 0) {
  247.             hv = ball[i].v * tcos(ball[i].a);
  248.             vv = ball[i].v * tsin(ball[i].a);
  249.             vv += ROTATION_CONVERT_RATIO * ball[i].rv * SQRT_2OVER5;
  250.             ball[i].v = sqrt((hv * hv) + (vv * vv));
  251.             ball[i].a = tatan2(vv, hv);
  252.             ball[i].rv -= ROTATION_CONVERT_RATIO * ball[i].rv;
  253.         }
  254.         (*cush_beep)++;
  255.         if ((i == cueball) &&
  256.             (iscarom[0] + iscarom[1] + iscarom[2] < 3)) {
  257.             /* !!! In this condition we assumed that there are
  258.                exactly 3 balls (N==3) !!!
  259.             */
  260.             cushion_coun