home *** CD-ROM | disk | FTP | other *** search
/ Kinjite Games 1996 November / SENTINEL.img / dosgames / sports / apool098 / src / physics.c < prev   
C/C++ Source or Header  |  1995-05-26  |  19KB  |  443 lines

  1. /* This is "physics.c", part of of the pool (billiards)-program
  2.                    
  3.                      "ANOTHER POOL".
  4.  
  5.    "physics.c" includes the 'physic' of the game, such as the 
  6.    collision of the balls, the reflection on the walls, ...
  7.  
  8.    Copyright (C) 1995 by Gerrit Jahn (email: ub1g@rz.uni-karlsruhe.de)
  9.  
  10.    "ANOTHER POOL" is free software; you can redistribute it 
  11.    and/or modify it under the terms of the GNU General Public License 
  12.    as published by the Free Software Foundation; either version 2 of 
  13.    the License, or (at your option) any later version.
  14.  
  15.    This program is distributed in the hope that it will be useful,
  16.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  17.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  18.    GNU General Public License for more details.
  19.  
  20.    You should have received a copy of the GNU General Public License
  21.    along with GNU CC; see the file COPYING.  If not, write to
  22.    the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
  23.  
  24. /* ------------------------------ physics.c ------------------------------ */
  25.  
  26. #include <math.h>
  27. #include <stdio.h>
  28. #include <stdlib.h>
  29. #include <time.h>
  30. #include <pc.h>
  31. #include "apool.h"
  32.  
  33. void translate_spin( void ) 
  34. /* Nachdem die Richtung der Geschw. feststeht, wird der Spin, der bisher im
  35.    lokalen Koordinatensystem der Kugel festgelegt war auf globale (x,y)-
  36.    Koordinaten umgerechnet. Das ist wichtig, da sich das lokale KS drehen
  37.    kann, da auch "Curve-Balls" möglich sind... */
  38.  {
  39.  double puffer, dummy=0;  /* k.e.x : senkr., k.e.y: parall. zu k.v(x,y) !!! */
  40.  struct vect s, add = { 0, 0 };
  41.  if( alph )
  42.   {
  43.   /* senkr. Vektor zu v bestimmen: warum: s. unten */
  44.   s.x = -k[WHITE].v.y; s.y = k[WHITE].v.x;
  45.   if( (dummy = BETR( s )) )
  46.    {
  47.     s.x /= dummy; s.y /= dummy;
  48.     dummy = sin( alph * M_PI / 180.0 );
  49.     add.x = - s.x * dummy * k[WHITE].ez / DIFFX / CURVES;
  50.     add.y = - s.y * dummy * k[WHITE].ez / DIFFX / CURVES;
  51.    }
  52.   s.x = k[WHITE].v.x; s.y = k[WHITE].v.y;
  53.   if( (dummy = BETR( s )) ) /* dummy = dasselbe wie oben !!! !!! !!!*/
  54.    {
  55.    s.x /= dummy; s.y /= dummy;
  56.    dummy = sin( alph * M_PI / 180.0 );
  57.    add.x += s.x * dummy * k[WHITE].e.y / DIFFX / CURVEP;
  58.    add.y += s.y * dummy * k[WHITE].e.y / DIFFX / CURVEP;
  59.    }
  60.   }
  61.  /* bis hier wurde das "Ausbrechen" des weißen Balls beim Curve-Ball,
  62.     also die Zusatzgeschw., die der Ball durch den nicht mittigen Treffpkt
  63.     bekommt, wenn der Queue noch dazu nicht parallel zum Tisch steht, 
  64.     berechnet. jetzt kommt der "normale" Spin und Curve-Ball ... */
  65.  if( (k[WHITE].v.x ) || (k[WHITE].v.y ) )
  66.   {        /* zuerst: k[WHITE].ez umwandeln in x- und y-  Spin */
  67.   dummy = ( k[WHITE].ez*sin( M_PI*alph/180.0) ) / 
  68.    sqrt(k[WHITE].v.x*k[WHITE].v.x + k[WHITE].v.y*k[WHITE].v.y);
  69.   }
  70.  puffer = k[WHITE].e.y;
  71.  k[WHITE].e.x = -k[WHITE].v.x * dummy;
  72.  k[WHITE].e.y = -k[WHITE].v.y * dummy; 
  73.  if( k[WHITE].v.x || k[WHITE].v.y ) dummy = puffer / BETR( k[WHITE].v );
  74.  else dummy = 0;
  75.  k[WHITE].e.y -= k[WHITE].v.x * dummy; 
  76.  k[WHITE].e.x += k[WHITE].v.y * dummy; 
  77.  k[WHITE].ez *= cos( M_PI*alph/180.0);
  78.  k[WHITE].e.x /= (RADIUS * DIFFX);
  79.  k[WHITE].e.y /= (RADIUS * DIFFX);
  80.  k[WHITE].v.x += add.x;
  81.  k[WHITE].v.y += add.y;
  82. }
  83.  
  84. void refl_kk( int n, struct vect p)   
  85. /* Kollisionsberechnugn zw. Kugeln und der Königsbande, die als infinitesimale
  86.    Kugel an der jeweiligen Stelle angenommen wird, sodaß prinzipiell (fast)
  87.    jeder Abprall-Winkel an diese Bande möglich ist, Die Berechnung erfolgt 
  88.    ähnlich wie der Stoß zwischen zwei Kugeln (s. coll() ) und ansonsten analog
  89.    reflection() ... */
  90.  {
  91.  struct vect ab; /* ab := Abstandsvektor zw. den Mittelpunkten */
  92.  double dummy;
  93.  ab.x = (k[n].p.x*DIFFX-p.x); ab.y = (k[n].p.y*DIFFX-p.y); 
  94.  ab.x /= (dummy = BETR( ab )); /* Abfrage, ob dummy != 0 ??? !!! !!! !!!*/
  95.  ab.y /= dummy;
  96.  if( (ab.x*k[n].v.x+ab.y*k[n].v.y) >= 0 ) return;
  97.  /* Berechnung der Geschwindigkeit der Kugel nach der Kollision */       
  98.  dummy = (k[n].v.x * ab.x + k[n].v.y * ab.y);
  99.  k[n].v.x -= dummy * (2*BANDEREF * ab.x + BANDES * ab.y * k[n].ez);
  100.  k[n].v.y -= dummy * (2*BANDEREF * ab.y - BANDES * ab.x * k[n].ez);
  101.  dummy = ab.x;
  102.  ab.x = -ab.y;
  103.  ab.y = dummy;
  104.  dummy = SKALP( k[n].e, ab );
  105.  k[n].e.x -= ab.x * dummy * GAMMA;
  106.  k[n].e.y -= ab.y * dummy * GAMMA;
  107.  k[n].e.x *= BANDEREF;
  108.  k[n].e.y *= BANDEREF;
  109.  k[n].ez *= (1-BANDEREF);
  110.  bande_hit = 1;
  111.  }
  112.  
  113. void coll( int a, int b) 
  114. /* Stoß: Kollisionsberechnung zwischen den Kugeln a und b. Dabei wird die
  115.    Masse der jeweiligen Kugel berücksichtigt, da die Weiße wohl manchmal
  116.    schwerer ist. Außerdem wird berücksichtigt, daß Kugeln, die ROLLEN, nur
  117.    ihre Translationsenergie abgeben können, während sie die Rotationsenergie
  118.    dazu befähigt, noch ein bißchen weiter zu rollen (mit entsprechen 
  119.    langsamerer Geschwindigkeit. */
  120.  { 
  121.  struct vect ab, v; /* ab := Abstandsvektor zw. den Mittelpunkten */
  122.  double dummy, dummy2;
  123.  /* Abfrage, ob Kugeln kollidieren dürfen. Das ist der Fall, wenn der
  124.     Winkel zwischen Relativgeschw. und Abst.vektor < 90° ist */
  125.  if( ( (ab.x = k[a].p.x-k[b].p.x) * (v.x=k[a].v.x-k[b].v.x) +
  126.        (ab.y = k[a].p.y-k[b].p.y) * (v.y=k[a].v.y-k[b].v.y) ) >= 0 )
  127.         return;
  128.  /* Abstand i.allg. zu klein (wg. Zeitschritten) -> Korrektur: */
  129.  dummy2 = SKALP( ab, v ) / SKALP( v, v );
  130.  dummy = ( SKALP( ab, ab ) - 4*RADIUS*RADIUS/(DIFFX*DIFFX) )
  131.   / SKALP( v, v );
  132.  dummy2 += sqrt( dummy2 * dummy2 - dummy );
  133.  k[a].p.x -= k[a].v.x * dummy2;
  134.  k[a].p.y -= k[a].v.y * dummy2;
  135.  k[b].p.x -= k[b].v.x * dummy2;
  136.  k[b].p.y -= k[b].v.y * dummy2;
  137.  ab.x = k[a].p.x - k[b].p.x;
  138.  ab.y = k[a].p.y - k[b].p.y;
  139.  /* Ende (vorerst (s.u.)) der "zu kleinen Abstands-korrektur" */
  140.  dummy = BETR( ab );  /* ab = abst-vektor normieren */
  141.  ab.x /= dummy;
  142.  ab.y /= dummy;
  143.  /* Abnahme des z-Spins, wenn Kugeln stoßen (gibt's, aber anders, eigentlich 
  144.     erhält die gestoßene Kugel einen (sehr kleinen) Teil des z-Spins der
  145.     Stoßenden ...) */
  146. /* if( k[a].ez && (k[a].v.x || k[a].v.y) )
  147.   k[a].ez *= (ab.x * k[a].v.x + ab.y * k[a].v.y) /  
  148.    sqrt(k[a].v.x*k[a].v.x + k[a].v.y*k[a].v.y) * SPINC * 1 ! ;
  149.  if( k[b].ez && (k[b].v.x || k[b].v.y) )
  150.   k[b].ez *= (ab.x * k[b].v.x + ab.y * k[b].v.y) / 
  151.    sqrt(k[b].v.x*k[b].v.x + k[b].v.y*k[b].v.y) * SPINC  ;*/
  152.  /* Berechnung der Geschwindigkeit der Kugeln nach der Kollision: */
  153.  dummy = (k[a].v.x - k[b].v.x) * ab.x + (k[a].v.y - k[b].v.y) * ab.y;
  154.  k[a].v.x -= (2.0*k[b].m/(k[a].m+k[b].m)) * ab.x * dummy; /* mit untersch.  */
  155.  k[a].v.y -= (2.0*k[b].m/(k[a].m+k[b].m)) * ab.y * dummy; /* MASSEN der Kug,*/
  156.  k[b].v.x += (2.0*k[a].m/(k[a].m+k[b].m)) * ab.x * dummy;
  157.  k[b].v.y += (2.0*k[a].m/(k[a].m+k[b].m)) * ab.y * dummy;
  158.  /* Zeitschritt (s.o.) wieder hinzuzählen ... */
  159.  k[a].p.x += k[a].v.x * dummy2;
  160.  k[a].p.y += k[a].v.y * dummy2;
  161.  k[b].p.x += k[b].v.x * dummy2;
  162.  k[b].p.y += k[b].v.y * dummy2;
  163.  if( !first_hit ) /* Überprüfen, ob Foul durch falsches Anspielen */
  164.   { 
  165.   if( a != WHITE ) first_hit = k[a].col; /* eigentlich albern, da WEISSE */
  166.   else first_hit = k[b].col;               /* = letzte Kugel in Reihe...   */
  167.   if( !freeball && ((ply[act].col && (first_hit != ply[act].col)) 
  168.    || ((!ply[act].col) && (first_hit==COL_BLACK))) ) 
  169.     ply[act].stat |= FOUL_WRONG_COLOR_TOUCHED;
  170.   }
  171.  if( anstoss ) anstoss = 0; /* für Computer-Anstoss ... */
  172.  }
  173.  
  174. void reflection( int n, int b ) 
  175. /* Reflexion der Kugel n an der Bande b. Der Winkel, den die Bande hat, ist
  176.    egal, es werden auch die schrägen Königsbanden berechnet. An den Banden
  177.    ändert sich die senkrecht zur Bande stehende Geschwindigkeitskomponente der
  178.    Kugel in 2*die entgegengesetzte Richtung. Desweiteren wirkt sich der
  179.    z-Spin aus. Ein Problem bei den Banden besteht darin, daß Einfallswinkel
  180.    NICHT gleich Ausfallswinkel ist, wodurch der Computer leichte Probleme
  181.    bekommen könnte. Mal sehen, vielleicht "bescheißt" er ... */
  182.  { 
  183.  double dummy, dummy_g;
  184.  struct vect g;
  185.  /* 1. Anteil senkrecht zur Bande, in Richtung des "Normalen-Vektors" ber. */
  186.  dummy = SKALP( k[n].v, ban[b].n );
  187.  dummy_g = BETR( k[n].v );
  188.  /* Geschw. nach Reflexion, ein Teil normale Reflexion, ohne Spin, zum anderen
  189.     die Umsetzung des z-Spins i.Abh. von dummy */
  190.  /* Die Wurzel müßte man noch durch einen eigenen Faktor ersetzen, Wurzel:
  191.     verminderung der Rest-Geschw., BANDEREF: Verminderung der Geschw. 
  192.     senkrecht  zur Bande. !!! */
  193.  k[n].v.x -= dummy * (2*BANDEREF*ban[b].n.x + BANDES*ban[b].n.y*k[n].ez);
  194.  k[n].v.y -= dummy * (2*BANDEREF*ban[b].n.y - BANDES*ban[b].n.x*k[n].ez); 
  195.  /*k[n].ez *= 0 * (1-BANDEREF);  Dämpfung des (bisherigen) z-Spins */
  196. /* Effet SENKRECHT !!! !!! !!!, stimmt nicht mehr, da inzwischen der Effet
  197.    um 90° gedreht wurde !!!! !!! !!! !!! zur Bande wird vermindert! */
  198.  g.x = -ban[b].n.y;
  199.  g.y = ban[b].n.x;
  200.  dummy = SKALP( k[n].e, g );
  201.  k[n].e.x -= g.x * dummy * GAMMA;
  202.  k[n].e.y -= g.y * dummy * GAMMA;
  203.  k[n].e.x *= BANDEREF;
  204.  k[n].e.y *= BANDEREF;
  205.  bande_hit = 1;
  206. }
  207.  
  208. int in_line( int n, int b ) 
  209. /* Überprüft, ob Mittelpt. der Kugel projeziert auf Banden-Gerade innerhalb 
  210.    der beiden Grenzpunkte der Bande liegt und, ob der Abstand zwischen Bande
  211.    und Kugel klein genug, ist, damit es zu eine Reflexion kommt ... */
  212.  {
  213.  struct vect kk, c;
  214.  double t;
  215.  c.x = ban[b].p0.x - ban[b].p1.x;
  216.  c.y = ban[b].p0.y - ban[b].p1.y;
  217.  t = - (c.x*(ban[b].p0.x-k[n].p.x*DIFFX) + c.y*(ban[b].p0.y-k[n].p.y*DIFFX)) /
  218.        (c.x*c.x+c.y*c.y);
  219.  kk.x = ban[b].p0.x + c.x * t;
  220.  kk.y = ban[b].p0.y + c.y * t;
  221.  return( (-c.x * (kk.x-ban[b].p0.x) >= 0) && (-c.y * (kk.y-ban[b].p0.y) >= 0)
  222.   && (c.x * (kk.x-ban[b].p1.x) >= 0) && (c.y * (kk.y-ban[b].p1.y) >= 0) &&
  223.   ( ((k[n].p.x*DIFFX-kk.x) * (k[n].p.x*DIFFX-kk.x) +
  224.   (k[n].p.y*DIFFX-kk.y) * (k[n].p.y*DIFFX-kk.y)) <= (RADIUS)*(RADIUS) )); 
  225.   /* oben: (RADIUS+0.5)^2 ??? !!! !!! !!! */
  226.  }
  227.  
  228. void banden_test( void )  
  229.  { /* Abfrage ob Kugeln Bande oder Löcher treffen ...  */ 
  230.  int i, j;
  231.  for(i=0;i<BALLS;i++)
  232.   {
  233.   /* Untenst. Abfrage kann man noch beschleunigen, indem man 1. die Abfrage
  234.      bezgl. der großen Bande oben und unten in je zwei Teile links und rechts
  235.      vom Mittelloch aufteilt und 2. die Königsbanden nicht mehr abfragt,
  236.      wenn bereits eine Reflexion an einer "normalen", großen Bande statt-
  237.      gefunden hat... Aber auch so ist diese Prozedur schon umständlich genug
  238.      geschrieben ... (der Geschw. wegen) !!! !!! !!! */
  239.   if( !k[i].stat && (k[i].v.x || k[i].v.y) )
  240.    if( (k[i].p.x <= (RADIUS+1)/DIFFX) ) /* Kugel links in Nähe von Bande */
  241.     {
  242.     for( j=0;j<=2;j++ ) /* Abfrage, ob Kugel refl. an "großer" Bande */
  243.      if( ((k[i].v.x*ban[j].n.x + k[i].v.y*ban[j].n.y) <= 0) && in_line(i, j) )
  244.       { reflection( i, j ); break; }
  245.     /* Reflexion an einer "Kugelbande" */
  246.     if( DIFF( k[i].p.x-ban[1].p1.x/DIFFX, k[i].p.y-ban[1].p1.y/DIFFX ) <=
  247.      RADIUS*RADIUS/(DIFFX*DIFFX) ) refl_kk(i,ban[1].p1); 
  248.     else if( DIFF( k[i].p.x-ban[1].p0.x/DIFFX, k[i].p.y-ban[1].p0.y/DIFFX ) <=
  249.      RADIUS*RADIUS/(DIFFX*DIFFX)) refl_kk(i,ban[1].p0);
  250.     /* Kugel in Loch, das zu den entspr. Banden gehört ? */
  251.     for(j=0;j<=1;j++)
  252.      if(DIFF(posl[j].p.x-k[i].p.x,posl[j].p.y-k[i].p.y) < 
  253.       RADIUSL*RADIUSL/(DIFFX*DIFFX)) { delete_ball( i ); break; }
  254.     }
  255.    else if( k[i].p.x >= (DIFFX-RADIUS-1)/DIFFX ) /* Kugel rechts */
  256.     {
  257.      for( j=3;j<=5;j++ )
  258.       if(((k[i].v.x*ban[j].n.x + k[i].v.y*ban[j].n.y) <= 0) && in_line( i, j))
  259.        { reflection( i, j ); break; }
  260.      if( DIFF( k[i].p.x-ban[4].p1.x/DIFFX, k[i].p.y-ban[4].p1.y/DIFFX ) <=
  261.       RADIUS*RADIUS/(DIFFX*DIFFX) ) refl_kk(i,ban[4].p1); 
  262.      else if( DIFF( k[i].p.x-ban[4].p0.x/DIFFX, k[i].p.y-ban[4].p0.y/DIFFX )
  263.       <= RADIUS*RADIUS/(DIFFX*DIFFX)) refl_kk(i,ban[4].p0);
  264.     for(j=3;j<=4;j++)
  265.      if(DIFF(posl[j].p.x-k[i].p.x,posl[j].p.y-k[i].p.y)
  266.       < RADIUSL*RADIUSL/(DIFFX*DIFFX)) { delete_ball( i ); break; }
  267.     }
  268.   if( !k[i].stat && (k[i].v.x || k[i].v.y) )
  269.    if( (k[i].p.y <= (RADIUS+1)/DIFFX) ) /* Kugel oben */
  270.     {
  271.      for( j=6;j<=8;j++ ) /* geht was nicht !!! !!! !!! */
  272.       { 
  273.        if(((k[i].v.x*ban[j].n.x + k[i].v.y*ban[j].n.y)<=0) && in_line( i, j))
  274.         { reflection( i, j ); break; }
  275.        else if(((k[i].v.x*ban[j+6].n.x + k[i].v.y*ban[j+6].n.y)<=0) 
  276.         && in_line(i, j+6)) { reflection( i, j+6 ); break; }
  277.       }
  278.      if( DIFF( k[i].p.x-ban[7].p1.x/DIFFX, k[i].p.y-ban[7].p1.y/DIFFX ) 
  279.       <= RADIUS*RADIUS/(DIFFX*DIFFX) ) refl_kk(i,ban[7].p1); 
  280.      else if( DIFF( k[i].p.x-ban[7].p0.x/DIFFX, k[i].p.y-ban[7].p0.y/DIFFX )
  281.       <= RADIUS*RADIUS/(DIFFX*DIFFX)) refl_kk(i,ban[7].p0);
  282.      else if( DIFF( k[i].p.x-ban[13].p1.x/DIFFX, k[i].p.y-ban[13].p1.y/DIFFX )
  283.       <= RADIUS*RADIUS/(DIFFX*DIFFX) ) refl_kk(i,ban[13].p1); 
  284.      else if( DIFF( k[i].p.x-ban[13].p0.x/DIFFX, k[i].p.y-ban[13].p0.y/DIFFX )
  285.       <= RADIUS*RADIUS/(DIFFX*DIFFX)) refl_kk(i,ban[13].p0);
  286.      for(j=1;j<=3;j++)
  287.       if(DIFF(posl[j].p.x-k[i].p.x,posl[j].p.y-k[i].p.y) < 
  288.        RADIUSL*RADIUSL/(DIFFX*DIFFX)) { delete_ball( i ); break; }
  289.     }
  290.    else if( k[i].p.y >= (DIFFX/2-RADIUS-1)/DIFFX ) /* Kugel unten */
  291.     {
  292.      for( j=9;j<=11;j++ )
  293.       { 
  294.        if(((k[i].v.x*ban[j].n.x + k[i].v.y*ban[j].n.y)<=0) && in_line( i, j)) 
  295.         { reflection( i, j ); break; }
  296.        else if(((k[i].v.x*ban[j+6].n.x + k[i].v.y*ban[j+6].n.y)<=0) 
  297.         && in_line(i, j+6) ) { reflection( i, j+6 ); break; }
  298.       }
  299.      if( DIFF( k[i].p.x-ban[10].p1.x/DIFFX, k[i].p.y-ban[10].p1.y/DIFFX )
  300.       <= RADIUS*RADIUS/(DIFFX*DIFFX) ) refl_kk(i,ban[10].p1); 
  301.      else if( DIFF( k[i].p.x-ban[10].p0.x/DIFFX, k[i].p.y-ban[10].p0.y/DIFFX )
  302.       <= RADIUS*RADIUS/(DIFFX*DIFFX)) refl_kk(i,ban[10].p0);
  303.      else if( DIFF( k[i].p.x-ban[16].p1.x/DIFFX, k[i].p.y-ban[16].p1.y/DIFFX )
  304.       <= RADIUS*RADIUS/(DIFFX*DIFFX) ) refl_kk(i,ban[16].p1); 
  305.      else if( DIFF( k[i].p.x-ban[16].p0.x/DIFFX, k[i].p.y-ban[16].p0.y/DIFFX )
  306.       <= RADIUS*RADIUS/(DIFFX*DIFFX)) refl_kk(i,ban[16].p0);
  307.      for(j=4;j<=5;j++)
  308.       if(DIFF(posl[j].p.x-k[i].p.x,posl[j].p.y-k[i].p.y) < 
  309.        RADIUSL*RADIUSL/(DIFFX*DIFFX)) { delete_ball( i ); break; }
  310.      if(DIFF(posl[0].p.x-k[i].p.x,posl[0].p.y-k[i].p.y) < 
  311.       RADIUSL*RADIUSL/(DIFFX*DIFFX)) delete_ball( i );
  312.     }
  313.   }
  314.  }
  315.  
  316. void re_init_timer( void )
  317.  {
  318.  outportb( 0x43, 0xb4 );    /* Modus, Channel, etc. wählen */
  319.  outportb( 0x42, 0 );        /* Frequenz: lo-byte */
  320.  outportb( 0x42, 0 );        /* dto.: hi-byte     */
  321.  }
  322.  
  323. void init_timer( void )
  324.  {
  325.  outportb( 0x61, (inportb( 0x61 ) & 0xfc) | 1 );  /* Gate initialisieren */
  326.  re_init_timer();
  327.  }
  328.  
  329. unsigned long timer( void )
  330.  {
  331.   outportb( 0x43, 0xc8 );    /* Lesen anmelden */
  332.   inportb( 0x42 );        /* Status Byte */
  333.   return(inportb( 0x42 ) + (inportb( 0x42 ) << 8)); /* Lo-/Hi-Byte returnen */
  334.  }
  335.  
  336. int move_balls( void ) 
  337. /* Die Bewegung der Bälle mit Reibung, Effet, Umwandlung von Translations-
  338.    in Rotationsenergie, Umwandlung von Spin in Geschwindigkeit, etc.... */
  339.  {
  340.   int i, nomove = 0;
  341.   double dummy, test, betr_v;
  342.   struct vect d_v, diff, v_trans, v_rot;
  343.   for(i=0;i<BALLS;i++)
  344.    {
  345.    if( !k[i].stat )
  346.     {
  347.     if( k[i].v.x || k[i].v.y || k[i].e.x || k[i].e.y )
  348.      {
  349.       k[i].nopaint = 0;
  350.       diff.x = (v_rot.x = k[i].e.x) - (v_trans.x = -k[i].v.y/RADIUS);
  351.       diff.y = (v_rot.y = k[i].e.y) - (v_trans.y = k[i].v.x/RADIUS);
  352.       if( diff.x || diff.y )
  353.        {
  354.         test = BETR( diff );
  355.         if( test < ALPHA )
  356.          { /* das funktioniert ganz gut ! */
  357.           k[i].e.x -= diff.x * 2.0/7.0;
  358.       k[i].e.y -= diff.y * 2.0/7.0;
  359.       k[i].v.x += diff.y * 5.0/7.0 * RADIUS;
  360.        k[i].v.y -= diff.x * 5.0/7.0 * RADIUS;
  361.       }
  362.         else   
  363.          {
  364.       dummy = ALPHA / test;
  365.           k[i].e.x -= (d_v.x = diff.x * dummy);
  366.           k[i].e.y -= (d_v.y = diff.y * dummy);
  367.        if( d_v.x || d_v.y )
  368.         {
  369.         dummy = -0.5*( betr_v = BETR( k[i].v ) );
  370.             test = dummy*dummy - RADIUS*RADIUS/5.0 * 
  371.          ( SKALP( d_v, d_v ) - 2.0*SKALP( d_v, k[i].e ) );
  372.         if( test < 0 ) test = -test; /* passiert, glaube ich, nicht !! */
  373.         dummy += sqrt( test );
  374.         dummy /= BETR( d_v );
  375.             dummy = fabs(dummy);
  376.             if( fabs( k[i].e.x )*RADIUS > fabs( k[i].v.y ) )
  377.             k[i].v.x -= -d_v.y * fabs(dummy) * ETA;
  378.             else k[i].v.x -= -d_v.y * fabs(dummy);
  379.             if( fabs( k[i].e.y )*RADIUS > fabs( k[i].v.x ) )
  380.             k[i].v.y -= d_v.x * fabs(dummy) * ETA;
  381.             else k[i].v.y -=  d_v.x * fabs(dummy);
  382.               }
  383.          }
  384.        }
  385.       if( k[i].v.x || k[i].v.y )
  386.        {
  387.         dummy = BETR( k[i].v );
  388.         k[i].v.x -= DELTA * k[i].v.x/dummy;
  389.         k[i].v.y -= DELTA * k[i].v.y/dummy;
  390.         if( dummy <= DELTA ) k[i].v.x = k[i].v.y = 0;
  391.        }
  392.       if( k[i].e.x || k[i].e.y )
  393.        {
  394.         dummy = BETR( k[i].e );
  395.         k[i].e.x -= DELTA/(double)RADIUS * k[i].e.x / dummy;
  396.         k[i].e.y -= DELTA/(double)RADIUS * k[i].e.y / dummy;
  397.         if( dummy < 5.0*DELTA/(double)RADIUS ) k[i].e.x = k[i].e.y = 0;
  398.        }
  399.       k[i].p.x += k[i].v.x;        /* Eigentliche Bewegung der Kugel */
  400.       k[i].p.y += k[i].v.y;        /* unten: wann "ruht" die Kugel: */
  401.       /* Abnahme von ez durch Bohrreibung! */
  402.       if( fabs(k[i].ez) > 31*BETA ) k[i].ez -= BETA * (2*(k[i].ez > 0)-1);
  403.       else k[i].ez = 0.0;
  404.      }
  405.     else { k[i].nopaint = 1; nomove++; }
  406.     }
  407.    else nomove++;
  408.    }
  409.   if( (++counter > STEP ) )
  410.    {
  411.     while( timer() > TIME_STEP );
  412.     re_init_timer(); /* ungeschickt, aber funktioniert !!! */
  413.     plot_balls();
  414.     counter = 0; 
  415.    }            
  416.  return nomove; /* Gibt an, wieviele Kugeln sich nicht mehr bewegen */
  417. }
  418.  
  419. void stoss( void )   
  420. /* Der eigentliche Stoß, mit den Werten, die entweder der Spieler via Mouse
  421.    oder der Computergegener hinsichtlich der Stoß-Geschwindigkeit (Betrag
  422.    und Richtung, Effet) liefert, wird die Weiße losgelassen und die
  423.    Kollisionen zwischen Kugeln und zw. Kugeln und Banden abgefragt... */
  424.  {
  425.   int i,j;
  426.   save_actual_position(); 
  427.   translate_spin();
  428.   ply[act].speed = spd;
  429.   counter = 0;
  430.   do
  431.    {
  432.     banden_test();
  433.     for( i=0;i<BALLS;i++) /* Abfrage nach "potentieller" Kollision, d.h. */
  434.      for(j=i;j<BALLS;j++) /* ob Abstand zw. Kugel i u. j klein genug !! */
  435.       if( (j != i) && (!k[i].stat) && (!k[j].stat) &&
  436.        (DIFF( k[i].p.x-k[j].p.x, k[i].p.y-k[j].p.y ) <= 
  437.         4.0*RADIUS/DIFFX*RADIUS/DIFFX))
  438.         coll( i, j ); 
  439.    } 
  440.   while( move_balls() < BALLS ); /* solange sich noch Bälle bewegen */
  441.   plot_balls();
  442.  }
  443.