home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Kinjite Games 1996 November
/
SENTINEL.img
/
dosgames
/
sports
/
apool098
/
src
/
graphics.c
< prev
next >
Wrap
C/C++ Source or Header
|
1995-05-26
|
33KB
|
937 lines
/* This is "graphics.c", a part of the pool (billiards)-program
"ANOTHER POOL".
"graphics.c" uses CBGRX 2.0 and includes most of the graphic-functions.
Copyright (C) 1995 by Gerrit Jahn (email: ub1g@rz.uni-karlsruhe.de)
"ANOTHER POOL" is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2 of
the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GNU CC; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
/* ------------------------------ graphics.c ----------------------------- */
#include "c:/djgpp/contrib.20/libgrx/include/grx20.h"
#include <pc.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <go32.h>
#include "apool.h"
/* unten: für die Kürzung der BitBlt-Routine */
#include "c:/djgpp/contrib.20/libgrx/src/include/libgrx.h"
#include "c:/djgpp/contrib.20/libgrx/src/include/clipping.h"
#ifdef S3
#define BitBlt_S3( dx, dy, x1)\
bitblt( (x1)-Radius+64, 480+Radius ,(dx)-Radius, (dy)-Radius,\
(Radius*2)+1, (Radius*2)+1 )
#else
#define BitBlt_S3( dx, dy, x1) (*(CURC->gc_driver->bltr2v))\
( curc_gc_frame, (dx) + curc_xoffset, (dy) + curc_yoffset,\
cont_gc_frame, (x1) + cont_xoffset, cont_yoffset,\
RADIUS + RADIUS + 1, RADIUS + RADIUS + 1, GrXOR )
#endif
#define CRTC_ADR 0x3d4
#define CRTC_DATA 0x3d5
#define CRT_REG_LOCK1 0x38
#define CRT_REG_LOCK2 0x39
#define CRT_SYS_CNFG 0x40
#define GP_STAT 0x9ae8
#define FRGD_MIX 0xbae8
#define FRGD_COLOR 0xa6e8
#define MULTIFUNC_CNTL 0xbee8
#define CUR_X 0x86e8
#define CUR_Y 0x82e8
#define MAJ_AXIS_PCNT 0x96e8
#define MIN_AXIS_PCNT 0xbee8
#define DESTX_DIASTP 0x8ee8
#define DESTY_AXSTP 0x8ae8
#define ERR_TERM 0x92e8
#define CMD 0x9ae8
double oldalph=0.0, alph=0.0, spd=0.75, RADIUSL, e_winkel, old_min;
int counter=0, oldx[BALLS], oldy[BALLS], olds[2] = {SPINPOSX,SPINPOSY};
int old_ball, old_hole, old_paint=5;
struct hole posl[6]; /* 6 Löcher */
struct bande ban[18];
GrCursor *cursor[5];
GrMouseEvent me;
GrFont *fontb, *fontm, *fonts;
GrTextOption textopt = { NULL, {6}, {0}, GR_TEXT_DEFAULT, GR_BYTE_TEXT,
GR_ALIGN_CENTER, GR_ALIGN_TOP };
GrTextOption textleft = { NULL, {6}, {0}, GR_TEXT_DEFAULT, GR_BYTE_TEXT,
GR_ALIGN_LEFT, GR_ALIGN_TOP };
GrTextOption textcenter = { NULL, {6}, {0}, GR_TEXT_DEFAULT, GR_BYTE_TEXT,
GR_ALIGN_CENTER, GR_ALIGN_TOP };
#ifndef S3
GrContext *context;
GrFrame *cont_gc_frame, *curc_gc_frame;
int curc_xoffset, curc_yoffset, cont_xoffset, cont_yoffset;
#endif
void init(void)
{
#ifdef S3
outportb(CRTC_ADR,CRT_REG_LOCK1);
outportb(CRTC_DATA,0x48);
outportb(CRTC_ADR,CRT_REG_LOCK2);
outportb(CRTC_DATA,0xa0);
outportb(CRTC_ADR,CRT_SYS_CNFG);
outportb(CRTC_ADR,CRT_SYS_CNFG);
outportb(CRTC_DATA,inportb(CRTC_DATA)|1);
#endif
}
void init_graphics( int a, int b, int c)
{ /* Öffnet Grafikschirm der Größe a*b, mit c Farben */
if( !GrMouseDetect() ) { MSG; printf("Mouse required...\a\n\n"); exit( 0 ); }
GrSetMode( GR_width_height_color_graphics, a, b, c );
GrSetColor( 0, 0, 0, 0 );
GrSetColor( 1, 0, 128, 0 );
GrSetColor( 2, 0, 96, 0 );
GrSetColor( 3, 96, 64, 32 );
GrSetColor( 4, 255, 0, 0 );
GrSetColor( 5, 255, 255, 255 );
GrSetColor( 6, 118, 138, 168 );
GrSetColor( 7, 192, 150, 64 );
GrSetColor( 8, 128, 80, 20 );
GrSetColor( 9, 54, 58, 62 );
GrSetColor( 10, 0, 128, 255 );
GrSetColor( 11, 255, 255, 0 );
GrSetColor( 12, 0, 110, 150 );
GrSetColor( 13, 255, 192, 192 );
GrSetColor( 14, 0, 0, 127 );
GrSetColor( 15, 0, 0, 255 );
GrMouseEventMode( 0 ); /* Maus im "poll"-mode */
GrMouseInit();
GrMouseSetAccel( 50, 2 ); /* unten: Mausbeweg. auf Tischgröße reduzieren ! */
GrMouseSetLimits(LEFT+RADIUS+1, UP+RADIUS+1, RIGHT-RADIUS-1, DOWN-RADIUS-1);
init();
make_mouse_cursor();
fontb = GrLoadFont("ncen29b.fnt");
textopt.txo_font = fontb;
fontm = GrLoadFont("xm8x16.fnt");
textleft.txo_font = fontm;
fonts = GrLoadFont("xm7x14.fnt");
textcenter.txo_font = fonts;
}
#ifdef S3
void
bitblt(int sx1,int sy1,int dx1,int dy1,int sx,int sy)
{
while(inportw(GP_STAT)&0xc0); /* wait for 2 FIFOs */
outportw(MULTIFUNC_CNTL,0xa000);
outportw(FRGD_MIX,0x65); /* use foreground color set in next line and
just write (no and or or so) */
while(inportw(GP_STAT)&0xfe); /* wait for 7 FIFOs */
outportw(CUR_X,sx1);
outportw(CUR_Y,sy1);
outportw(DESTX_DIASTP,dx1);
outportw(DESTY_AXSTP,dy1);
outportw(MAJ_AXIS_PCNT,sx-1);
outportw(MIN_AXIS_PCNT,sy-1);
outportw(CMD,0xc0b3);
}
#endif
void close_graphics( void )
{
GrMouseUnInit();
GrSetMode(GR_default_text,0,0,0);
}
void msg( char *out )
{ /* Gibt einige Dinge unterhalb des Tisches aus */
GrFilledBox( 0, DOWN+25, 480 + 60*(fonts==NULL), DOWN+41, 0 );
GrDrawString( out, strlen(out), 240+30*(fonts==NULL), DOWN+25, &textcenter );
}
void plot_standings( void )
{
char out[15];
sprintf(out,"%d : %d",(int)(ply[0].points)%10000+(int)(ply[1].points)/10000,
(int)(ply[1].points)%10000 + (int)(ply[0].points)/10000 );
GrDrawString(out, strlen(out), GrMaxX() - (15+strlen(out))*8, 10, &textleft);
}
void plot_table( void )
/* Hier wird der Tisch neu initialisiert und gemalt, die Banden und Löcher
werden aus der Datei "table.dat" ausgelesen und entsprechend gemalt.
Gleichzeitig werden diese Daten für das Spiel aufbereitet... */
{
FILE *dat;
int i, j, poly[4][2], counter = 0;
double dummy, dummy2[4];
struct vect n;
char out[20];
GrClearScreen( 0 );
GrFilledBox( LEFT-10, UP-10, RIGHT+10, DOWN+10, 1 ); /* "Tuch" */
if( !(dat = fopen("table.dat","r")) )
{
GrSetMode(GR_default_text,0,0,0);
MSG;
printf("error: can't find the file 'table.dat'. \n");
printf("create this file using 'creatabl.e.xe' ...\n\n");
exit(0);
}
fscanf(dat,"%lg",&RADIUSL );
for(i=0;i<6;i++) /* Teilkreise der Taschen malen */
{
for(j=0;j<2;j++) fscanf(dat,"%lg",&dummy2[j]);
GrFilledCircle( LEFT+dummy2[0], UP+dummy2[1], RADIUSL, 0 );
posl[i].p.x = dummy2[0] / DIFFX;
posl[i].p.y = dummy2[1] / DIFFX;
}
for(i=0;i<6;i++) /* Banden initialisieren und malen */
{
for(j=0;j<4;j++)
{
fscanf(dat,"%lg",&dummy); poly[j][0] = LEFT + (int)dummy;
fscanf(dat,"%lg",&dummy); poly[j][1] = UP + (int)dummy;
}
for( j=1;j<4;j++) /* Punkte den Banden zuweisen und Norm.vektoren berech. */
{
ban[counter].p0.x = poly[j-1][0]-LEFT;
ban[counter].p0.y = poly[j-1][1]-UP;
ban[counter].p1.x = poly[j][0]-LEFT;
ban[counter].p1.y = poly[j][1]-UP;
/* "Den" zum "Richtungs-Vektor" der Bande senkrechten Vektor bestimmen */
n.y = ban[counter].p1.x-ban[counter].p0.x;
n.x = - ( ban[counter].p1.y-ban[counter].p0.y );
/* Normieren */
ban[counter].n.x = n.x / ( dummy = BETR( n ) );
ban[counter].n.y = n.y / dummy;
counter++;
}
GrFilledConvexPolygon( 4, poly, 2);
}
fclose(dat);
/* dicke Banden wieder schmaler machen (optisch) */
GrFilledBox( 0,0, GrMaxX(), UP-11, 0 );
GrFilledBox( 0,DOWN+11, GrMaxX(), GrMaxY(), 0 );
GrFilledBox( 0,0, LEFT-11, GrMaxY(), 0 );
GrFilledBox( RIGHT+11,0, GrMaxX(), GrMaxY(), 0 );
GrDrawString("ANOTHER POOL", 12, GrMaxX()/2, 0, &textopt );
textcenter.txo_fgcolor.v = 9;
sprintf(out,"V %s",VERSION);
GrDrawString( out, strlen(out), 615, 0, &textcenter);
textcenter.txo_fgcolor.v = 6;
GrFilledCircle( SPINPOSX, SPINPOSY, 39, 5 );
GrCircle( SPINPOSX, SPINPOSY, 39, 9 );
calc_hot_spot();
calc_e_winkel();
plot_standings();
}
void speed( double p )
{ /* Gibt den Geschwindigkeitsbalken am unteren Ende des Screens aus */
int mx = GrMaxX(), my = GrMaxY();
GrFilledBox( 0, my - 9, mx, my, 14 );
GrFilledBox( 0, my - 9, (int)(mx*p), my, 15 );
}
void plot_balls( void )
{ /* Zeichnet alle Bälle neu und löscht die alten */
int i;
for(i=0;i<BALLS;i++)
if( !k[i].stat && !k[i].nopaint )
{
BitBlt_S3( oldx[i], oldy[i], (k[i].col)<<5 );
oldx[i]=(LEFT+DIFFX*k[i].p.x+0.5);
oldy[i]=(UP+DIFFX*k[i].p.y)+0.5;
BitBlt_S3( oldx[i], oldy[i], (k[i].col)<<5 );
}
}
void plot_one_ball( int i )
{ /* Malt im Gegensatz zu plot_balls() nur eine einzige Kugel neu */
oldx[i]=(LEFT+DIFFX*k[i].p.x)+0.5;
oldy[i]=(UP+DIFFX*k[i].p.y)+0.5;
BitBlt_S3( oldx[i], oldy[i], (k[i].col)<<5 );
}
void set_spin( double sx, double sy, double sz )
{ /* hier wird der (lokale) Spin der Weißen am Anfang gesetzt und gemalt */
GrFilledCircle( olds[0], olds[1], 7, 5 );
k[WHITE].ez = sz; k[WHITE].e.y = sy; k[WHITE].e.x = sx;
olds[0] = SPINPOSX + (31.0*k[WHITE].ez + 0.5);
olds[1] = SPINPOSY + (31.0*k[WHITE].e.y + 0.5);
GrFilledCircle( olds[0], olds[1], 7, 12 );
}
void test_spin( int x, int y )
{ /* Mouse-Abfrage für das Setzten des lokalen Spins... */
int oldx=x, oldy=y;
double sz, sp, dummy;
do
{
GrMouseGetEvent( GR_M_KEYPRESS | GR_M_MOTION | GR_M_BUTTON_CHANGE, &me );
if( me.flags & GR_M_MOTION )
{
/* sollte vielleicht umgerechnet werden in einen Winkel !!! !!! !!! ??? */
sz = (me.x - oldx)/31.0; sp = (me.y - oldy)/31.0;
GrMouseWarp( oldx, oldy );
if( (k[WHITE].ez+sz)*(k[WHITE].ez+sz)+
(k[WHITE].e.y+sp)*(k[WHITE].e.y+sp) < 1.0 )
set_spin( 0.0, k[WHITE].e.y+sp, k[WHITE].ez+sz );
else if( (k[WHITE].e.y+sp) || (k[WHITE].ez+sz) )
{
dummy = sqrt( (k[WHITE].ez+sz)*(k[WHITE].ez+sz) +
(k[WHITE].e.y+sp)*(k[WHITE].e.y+sp) );
set_spin( 0.0, (k[WHITE].e.y+sp)/dummy, (k[WHITE].ez+sz)/dummy );
}
}
}
while( !(me.flags & GR_M_KEYPRESS) && !(me.flags & GR_M_MIDDLE_UP) &&
!(me.flags & GR_M_RIGHT_DOWN) );
}
void wait_for_click( void )
/* wartet auf Mouse-Click oder Tasten-Druck */
{
GrMouseEvent mev;
msg("press any key or mouse-button");
do
{ GrMouseGetEvent( GR_M_BUTTON_CHANGE | GR_M_KEYPRESS, &mev ); }
while( !(mev.flags & ( GR_M_BUTTON_DOWN | GR_M_KEYPRESS )) );
if( (mev.flags & GR_M_KEYPRESS) && (mev.key == 27) ) stop_it();
}
void wink( double a ) /* Winkel zwischen Queue und Tisch darstellen */
{ /* Könnte mal einen dickeren Queue bekommen !!! !!! !!!*/
double b = a*M_PI/180.0;
GrFilledCircleArc( 480, 465, 4*RADIUS, 0, 900, GR_ARC_STYLE_CLOSE2, 5 );
GrCircleArc( 480, 465, 4*RADIUS+1, 0, 900, GR_ARC_STYLE_OPEN, 9 );
GrLine(480+4*(RADIUS+1)*cos( oldalph ),465-4*(RADIUS+1)*sin( oldalph ),
480+8*(RADIUS+1)*cos( oldalph ),465-8*(RADIUS+1)*sin( oldalph ), 0 );
GrLine(480+4*(RADIUS+1)*cos( b ),465-4*(RADIUS+1)*sin( b ),
480+8*(RADIUS+1)*cos( b ),465-8*(RADIUS+1)*sin( oldalph = b ), 8 );
}
void err( char *out )
{ /* Ausgabe der normalen Texte während des Spiels */
GrFilledBox( 0, 450, 400, 469, 0 );
GrDrawString( out, strlen( out ), 0, 451, &textleft );
}
void err2( char *out, int col )
{ /* Ausgabe von z.B. Free- oder Extra-Ball ... */
GrFilledBox( 0, 430, 440, 449, 0 );
textleft.txo_fgcolor.v = col;
GrDrawString(out, strlen(out), 0, 431, &textleft );
textleft.txo_fgcolor.v = 6;
}
void debug( char *out )
{ /* Ausgabe der Kommentare beim Computer-Spieler */
char o[80];
sprintf(o,"%s",out);
GrFilledBox( 0, 35, 540, 55, 0 );
GrDrawString(out, strlen(out), 0, 35, &textleft );
}
void make_mouse_cursor( void )
{ /* erstellt die Bälle, die als Mouse-Cursor dienen */
int i,j;
long c_table[5][4] =
{{3,6,4,4},{3,6,11,11},{3,6,4,11},{3,6,0,0},{3,5,5,5}};
char curs[(int)((2*RADIUS+1)*(2*RADIUS+1))];
#ifndef S3
context = GrCreateContext( 256, 4*RADIUS, NULL, NULL );
cont_gc_frame = &context->gc_frame;
curc_gc_frame = &CURC->gc_frame;
curc_xoffset = CURC->gc_xoffset - RADIUS;
curc_yoffset = CURC->gc_yoffset - RADIUS;
cont_xoffset = context->gc_xoffset - RADIUS + 64;
cont_yoffset = context->gc_yoffset + RADIUS;
#endif
GrFilledCircle( 32, 2*RADIUS, RADIUS, 1 ); /* f. Mauszeiger */
GrFilledCircleArc( 32, 2*RADIUS, 3, 2700, 900, GR_ARC_STYLE_CLOSE2, 2 );
GrFilledCircleArc( 32, 2*RADIUS, 3, 900, 2700, GR_ARC_STYLE_CLOSE2, 3 );
GrFilledCircle( 64, 2*RADIUS, RADIUS, 4 ); /* f. WEISS; KUGELN ... */
GrFilledCircle( 96, 2*RADIUS, RADIUS, 5 ); /* f. ROT */
GrFilledCircle( 128, 2*RADIUS, RADIUS, 10 ); /* f. GELB */
GrFilledCircle( 160, 2*RADIUS, RADIUS, 1 ); /* f. SCHWARZ */
GrFilledCircleArc(192, 2*RADIUS, RADIUS, 2700, 900, GR_ARC_STYLE_CLOSE2, 5);
GrFilledCircleArc(192, 2*RADIUS, RADIUS, 900, 2700, GR_ARC_STYLE_CLOSE2, 10);
#ifdef S3
bitblt( 0, 0, 0, GrSizeY(), 256, 4*RADIUS );
#else
GrBitBltNC( context, 0, 0, NULL, 0, 0, 255, 4*RADIUS, GrWRITE);
#endif
for(j=0;j<2*RADIUS+1;j++) /* fünf neue Maus-"Zeiger" werden erstellt */
for(i=0;i<2*RADIUS+1;i++)
curs[(int)(j*(2*RADIUS+1)+i)] =
GrPixel( 32-RADIUS+i, 2*RADIUS-RADIUS+j );
for( i=0;i<5;i++ ) cursor[i] = GrBuildCursor( curs, 2*RADIUS+1, 2*RADIUS+1,
2*RADIUS+1, RADIUS, RADIUS, c_table[i] );
}
void mouse_on( void )
{ GrMouseDisplayCursor(); }
void mouse_off( void )
{ GrMouseEraseCursor(); }
void plot_act_player( int act )
{ /* gibt die kleine Kugel oben links und den akt. Spieler aus */
char whois[20];
GrFilledBox( 0, 0, 2*RADIUS+3, 2*RADIUS+3, 1 );
if( !ply[act].col ) BitBlt_S3( 1 + RADIUS, 1 + RADIUS, 128);
else BitBlt_S3( 1 + RADIUS, 1 + RADIUS, (ply[act].col)<<5);
sprintf(whois,"player no: %d",act+1);
GrDrawString( whois, strlen(whois), 3*RADIUS+1, 1, &textleft );
}
void set_white_ball( void )
{ /* Weiße Kugel am Anfang oder nach Foul neu positionieren */
int i, j, ok;
double old, old2;
if( (c_player == -1) || (act != c_player ) )
{
msg("place cue-ball");
set_spin( 0.0, 0.0, 0.0 );
old2 = 0.25;
i = 250;
do
{
old = ((double)i) / 1000.0;
ok = 1;
for(j=0;j<WHITE;j++) /* Suche nach freiem Platz auf dem Tisch */
if( DIFF2( old-k[j].p.x, old2-k[j].p.y ) < 5.0*RADIUS*RADIUS )
{ok=0; break;}
}
while( !ok && (--i>50) );
k[WHITE].p.x = old; k[WHITE].p.y = old2;
GrMouseWarp( LEFT + old*DIFFX, UP + old2*DIFFX );
GrMouseSetLimits( LEFT+RADIUS+1, UP+RADIUS+1, LEFT+DIFFX/4, DOWN-RADIUS-1 );
do
{
GrMouseSetCursor( cursor[4] ); /* weißer Mouse-Cursor */
GrMouseGetEvent( GR_M_KEYPRESS | GR_M_MOTION | GR_M_BUTTON_CHANGE, &me );
ok = 1;
if( me.flags & GR_M_MOTION )
{ /* Verschieben des Spielballs, aber nicht "auf" andere Kugeln */
for(j=0;j<WHITE;j++)
if((!(k[j].stat)) && (DIFF2( (me.x-LEFT)/DIFFX - k[j].p.x,
(me.y-UP)/DIFFX - k[j].p.y ) < 5.0*RADIUS*RADIUS) )
{ ok = 0; break; }
if( ok )
{
old = (double)(me.x-RIGHT+DIFFX)/DIFFX;
old2 = (double)(me.y-DOWN+DIFFX/2)/DIFFX;
k[WHITE].p.x = old; k[WHITE].p.y = old2;
}
else GrMouseWarp((double)LEFT + old * DIFFX, (double)UP + old2*DIFFX);
}
}
while( !(me.flags & GR_M_KEYPRESS ) && (!(me.flags & GR_M_BUTTON_DOWN)) );
if( (me.flags & GR_M_KEYPRESS) && (me.key == 27) ) stop_it();
}
else /* !!! !!! !!! !!! !!! !!! VERBESSERN! */
{
/* Computer kann Weiße legen ... */
set_spin( 0.0, 0.0, 0.0 );
old2 = 0.25;
i = 250;
do
{
old = ((double)i) / 1000.0;
ok = 1;
for(j=0;j<WHITE;j++) /* Suche nach freiem Platz auf dem Tisch */
if( DIFF2( old-k[j].p.x, old2-k[j].p.y ) < 5.0*RADIUS*RADIUS )
{ok=0; break;}
}
while( !ok && (--i>50) );
k[WHITE].p.x = old; k[WHITE].p.y = old2;
}
k[WHITE].stat = 0; /* Weiße wieder auf dem Tisch */
plot_one_ball( WHITE );
}
void calc_player_v( void )
{ /* brechnet die Richtung (zum Maus-Zeiger) der Geschwindigkeit und
multipliziert diese mit dem "Power"-Faktor spd */
struct vect v;
double dummy;
v.x = (double)(me.x - LEFT) - k[WHITE].p.x*DIFFX;
v.y = (double)(me.y - UP) - k[WHITE].p.y*DIFFX;
if( v.x || v.y )
{
v.x /= (dummy = sqrt(v.x*v.x+v.y*v.y));
v.y /= dummy;
}
/* v multiplizieren mit Geschwindigkeitsfaktor (0 <= spd <= 1) */
k[WHITE].v.x = spd * v.x / DIFFX * cos( alph * M_PI/180.0 );
k[WHITE].v.y = spd * v.y / DIFFX * cos( alph * M_PI/180.0 );
set_spin( k[WHITE].e.x*spd, k[WHITE].e.y*spd, k[WHITE].ez/* *spd!!! ??*/);
err(" "); debug(" ");
}
void set_player_power( void )
{ /* zum Einstellen der Stoßstärke; Balken ganz unten im Bildschirm */
int old, old2;
msg("move mouse to increase / decrease power");
old=me.y; old2=me.x;
do
{
GrMouseGetEvent( GR_M_KEYPRESS | GR_M_MOTION | GR_M_BUTTON_CHANGE, &me);
if( (me.flags & GR_M_MOTION))
{
spd += 1.0/GrSizeX() * (old-me.y - old2 + me.x);
GrMouseWarp( old2, old );
if( spd > 1.0 ) spd = 1.0;
if( spd < 0.0 ) spd = 0.0;
speed( spd );
}
}
while( !(me.flags & GR_M_KEYPRESS) && !(me.flags & GR_M_RIGHT_UP) );
MSG2;
}
void set_player_spin( void )
{ /* zum Einstellen des Spins; dicke Kugel rechts unten */
int old, old2;
msg("move mouse to change spin, press right button to change angle");
test_spin(me.x, me.y);
if( me.flags & (GR_M_MIDDLE_DOWN | GR_M_RIGHT_DOWN) )
{
old = me.x; old2 = me.y;
msg("move mouse to change angle between queue an table");
do
{
GrMouseGetEvent( GR_M_KEYPRESS|GR_M_MOTION|GR_M_BUTTON_CHANGE, &me);
if( me.flags & GR_M_MOTION)
{
alph += 0.1 * (old -me.y +old2 -me.x);
GrMouseWarp( old, old2 );
if( alph > 85.0 ) alph = 85.0;
if( alph < 0.0 ) alph = 0.0;
wink( alph );
}
}
while( !(me.flags & GR_M_KEYPRESS) &&
(!( me.flags & (GR_M_MIDDLE_UP | GR_M_RIGHT_UP) )) );
}
MSG2;
}
void set_test_power( void )
{ /* Test-Prozedur, berechnet Geschw., die die Weisse haben muß, um zur akt.
Maus-Position zu rollen */
struct vect v;
debug("press button, to play white to act.pos. !");
do
{ GrMouseGetEvent( GR_M_KEYPRESS|GR_M_MOTION|GR_M_BUTTON_CHANGE, &me); }
while( !(me.flags & GR_M_BUTTON_DOWN) );
v.x = (me.x-LEFT)/DIFFX - k[WHITE].p.x;
v.y = (me.y-UP)/DIFFX - k[WHITE].p.y;
set_c_speed( SET_V(BETR( v ), 0), v );
}
int set_test_power2( void )
{ /* Test-Prozedur, berechnet die Geschw., die die Weisse benötigt, um ein
best. Kugel in ein best. Loch zu schießen; ohne jeden Test, ob andere
Kugeln im Weg liegen ... */
int i, puffer_ball;
struct vect v1, v2, v3, v4;
double dum1, dummy;
int dum2;
char outtext[80];
debug("ball ?");
do
{ GrMouseGetEvent( GR_M_KEYPRESS|GR_M_MOTION|GR_M_BUTTON_CHANGE, &me); }
while( !(me.flags & GR_M_BUTTON_DOWN) );
v1.x = (me.x-LEFT) / DIFFX;
v1.y = (me.y-UP) / DIFFX;
dum1 = dum2 = 4;
for( i=0;i<WHITE;i++ )
if( DIFF( v1.x-k[i].p.x, v1.y-k[i].p.y ) < dum1 )
{ dum1 = DIFF( v1.x-k[i].p.x, v1.y-k[i].p.y ); dum2 = i; }
v1.x = k[dum2].p.x; v1.y = k[dum2].p.y;
puffer_ball = dum2;
sprintf(outtext,"ball no: %d, hole ?", dum2 );
debug(outtext);
do
{ GrMouseGetEvent( GR_M_KEYPRESS|GR_M_MOTION|GR_M_BUTTON_CHANGE, &me); }
while( !(me.flags & GR_M_BUTTON_DOWN) );
v2.x = (me.x-LEFT) / DIFFX;
v2.y = (me.y-UP) / DIFFX;
dum1 = 1000.0; dum2 = 0;
for( i=0;i<6;i++ )
if( DIFF( v2.x-posl[i].m.x, v2.y-posl[i].m.y ) < dum1 )
{ dum1 = DIFF( v2.x-posl[i].m.x, v2.y-posl[i].m.y ); dum2 = i; }
sprintf(outtext,"hole: %d",dum2);
debug(outtext);
v2.x = posl[dum2].m.x; v2.y = posl[dum2].m.y;
v3 = calc_tp( v1, v2 );
dummy = sqrt( DIFF( k[WHITE].p.x-v3.x, k[WHITE].p.y-v3.y ));
/* geht so natürlich noch nicht wieder !!! */
v4.x = v2.x - v3.x; v4.y = v2.y - v3.y;
v1.x = v3.x - k[WHITE].p.x; v1.y = v3.y - k[WHITE].p.y;
if( COSV( v1, v4 ) > 0.0 )
{
v2.x = posl[dum2].p.x - posl[dum2].m.x;
v2.y = posl[dum2].p.y - posl[dum2].m.y;
v3.x = posl[dum2].m.x - k[puffer_ball].p.x;
v3.y = posl[dum2].m.y - k[puffer_ball].p.y;
if( ((dum2 == 2 || dum2 == 5) && COSV( v2, v3 ) > COS(e_winkel))
|| (dum2 != 2 && dum2 != 5) )
{
if( (dum1=COSV( v1, v4 )) ) dummy += BETR(v4) / (dum1 * dum1);
else dummy = 1000000.0; /* =infinity */
set_c_speed( SET_V(dummy*sqrt(1.0/ROLL), 0), v1 );
return 1;
}
else
{
char out[80];
sprintf(out,"can't play this..(ew:%g/ pw:%g)", e_winkel,
180.0/M_PI * acos(COSV( v2, v3 )) );
debug(out);
return 0;
}
}
debug("can't play this...");
return 0;
}
/* steht nur wegen den Grafik-Befehlen und #defines in graphics.c */
int menu( void )
/* hier wird einiges geregelt, Mouse-Abfragen, die zum Stoßen, Spin u.
Geschw. einstellen dienen und Tastaturabfragen, wie z.B. Computer-
Gegner anschalten, Porgramm beenden ... */
{
int i, ok=0, ret_wert=0;
plot_act_player( act );
wink( alph = 0.0 );
set_spin( 0.0, 0.0, 0.0 );
for( i=0;i<BALLS;i++) /* alle Kugeln neu initialisieren */
{ k[i].v.x = k[i].v.y = k[i].e.x = k[i].e.y = k[i].ez = 0.0; }
if( k[WHITE].stat ) set_white_ball(); /* Weiße neu setzen */
if( ply[act].col == COL_WHITE ) GrMouseSetCursor( cursor[2] );
else if( ply[act].col == COL_RED ) GrMouseSetCursor( cursor[0] );
else if( ply[act].col == COL_YELLOW ) GrMouseSetCursor( cursor[1] );
else GrMouseSetCursor( cursor[3] ); /* if ... COL_BLACK */
if( act == c_player ) { computer_stoss(); return ret_wert; }
GrMouseSetLimits(LEFT+RADIUS+1, UP+RADIUS+1, RIGHT-RADIUS-1, DOWN-RADIUS-1);
ok = 0;
MSG2;
while( kbhit() ) getkey();
do
{
mouse_on();
do
{ GrMouseGetEvent( GR_M_KEYPRESS | GR_M_BUTTON_CHANGE, &me ); }
while( !(me.flags & (GR_M_KEYPRESS | GR_M_BUTTON_CHANGE)) );
if( (me.flags & GR_M_BUTTON_DOWN) )
{
GrMouseSetLimits( 0, 0, GrMaxX(), GrMaxY() );
switch(me.buttons)
{
case GR_M_LEFT: /* Stoß: Geschw. berechnen */
calc_player_v(); ok = 1; break;
case GR_M_RIGHT: /* Geschwindigkeits (Power)-Faktor verstellen */
set_player_power(); break;
case GR_M_MIDDLE: /* Spin einstellen */
set_player_spin(); break;
default: {}
}
GrMouseSetLimits( LEFT+RADIUS+1, UP+RADIUS+1, RIGHT-RADIUS-1,
DOWN-RADIUS-1);
}
else if( me.flags & GR_M_KEYPRESS )
switch( me.key )
{
case 13: case ' ': calc_player_v(); ok = 1; break;
case 'q': plot_statistics( 0, 0 );
case 27: ok = ret_wert = 1; break;
case 'n': /* new game */
mouse_off();
ply[1-act].points += 1;
stats[act].losses += 1;
act = 1 - act;
init_table();
ok = 1;
break;
case 'r': /* 'instant replay'-mode on/off */
i = STEP;
STEP = old_paint;
old_paint = i;
if( STEP < 6 ) debug("replay-mode on");
else debug("replay-mode off");
break;
case 'u': /* undo last shot */
undo(); debug("undo..."); break; /* akt ??? !!! !!! !!! */
case 'd': demo = 1;
msg("press any key to stop demo");
c_player = act;
computer_stoss();
ok = 1;
break;
case 'c': /* computer plays every shot*/
if( c_player == -1 ) c_player = act;
else { c_player = -1; break; }
case 'x': /* let computer play one shot */
computer_stoss();
ok = 1;
break;
#ifdef BANDEN
case 'b': /* show shots 'through' 1 or 2 sides */
mouse_off();
banden_stoss();
mouse_on();
ok = 0;
break;
#endif
case 'D':
for( i=BLACK+1;i<WHITE;i++ ) delete_ball( i );
for( i=0;i<BLACK;i++ ) delete_ball( i );
break;
case 'w': /* White --> akt-Mouse-Pos */
/* computer soll Weiße bis zur akt. Mouse-Pos. rollen lassen !!! */
set_test_power(); ok = 1; break;
case 'W': /* shot ball (1) in hole (2) */
ok = set_test_power2(); break;
case 's': plot_statistics( 0, 1 ); break;
case 315: help(); break; /* F1 */
case 316: credits(); break; /* F2 */
default: {}
}
}
while( !ok );
mouse_off();
return ret_wert;
}
void ctrl_break_off( void ) /* stellt CTRL-BREAK AB ! */
{ _go32_want_ctrl_break( 1 ); }
void plot_statistics( double time, int grx )
{
int add = 84;
time_t oldt = clock();
char out[80];
GrContext *cont = NULL;
mouse_off();
if( grx ) cont = GrCreateContext( GrSizeX(), GrSizeY(), NULL, NULL );
if( cont || !grx )
{
if( grx ) GrBitBltNC(cont, 0, 0, NULL, 0, 0, GrSizeX(), GrSizeY(), GrWRITE);
GrClearScreen( 0 );
GrDrawString( "STATISTICS", 10, GrMaxX()/2, 30, &textopt );
sprintf(out," Player %5d %5d", 1, 2);
GrDrawString( out, strlen(out), 1, add, &textleft );
add += 32;
sprintf(out,"standings %5d %5d",
stats[0].wins+stats[1].losses, stats[1].wins+stats[0].losses);
GrDrawString( out, strlen(out), 1, (add+=16), &textleft );
sprintf(out,"-games won (correct play on black) %5d %5d",
stats[0].wins, stats[1].wins);
GrDrawString( out, strlen(out), 1, (add+=24), &textleft );
sprintf(out,"-games lost ('direct' foul on black) %5d %5d",
stats[0].losses, stats[1].losses );
GrDrawString( out, strlen(out), 1, (add+=16), &textleft );
sprintf(out,"number of pocketed balls %5d %5d",
stats[0].pots, stats[1].pots );
GrDrawString( out, strlen(out), 1, (add+=20), &textleft );
sprintf(out,"no. of attempts without success %5d %5d",
stats[0].nopots, stats[1].nopots );
GrDrawString( out, strlen(out), 1, (add+=16), &textleft );
sprintf(out,"fouls: wrong color touched %5d %5d",
stats[0].fouls.wrongct, stats[1].fouls.wrongct );
GrDrawString( out, strlen(out), 1, (add+=16), &textleft );
sprintf(out,"fouls: wrong color pocketed %5d %5d",
stats[0].fouls.wrongcp, stats[1].fouls.wrongcp );
GrDrawString( out, strlen(out), 1, (add+=16), &textleft );
sprintf(out,"fouls: white ball disappeared %5d %5d",
stats[0].fouls.whited, stats[1].fouls.whited );
GrDrawString( out, strlen(out), 1, (add+=16), &textleft );
sprintf(out,"fouls: no ball or side touched %5d %5d",
stats[0].fouls.notouch, stats[1].fouls.notouch );
GrDrawString( out, strlen(out), 1, (add+=16), &textleft );
if( time > 0 ) while( (double)(clock() - oldt)/CLOCKS_PER_SEC < time );
else { wait_for_click(); mouse_off(); }
if( grx )
{
GrBitBltNC( NULL, 0, 0, cont, 0, 0, GrSizeX(), GrSizeY(), GrWRITE);
GrDestroyContext( cont );
}
}
mouse_on();
}
void delete_ball( int n )
/* Kugel "n" fällt in Tasche und wird gelöscht; außerdem wird geprüft, ob
ein Foul durch das Versenken begangen wurde... Hatte der Spieler vor dem
Versenken noch keine Farbe (Anfang des Spiels) so bekommt er hier diese */
{
k[n].stat = 1;
k[n].p.x = k[n].p.y = 10000.0; /* eigentlich unnötig ! */
BitBlt_S3( oldx[n], oldy[n], (k[n].col)<<5 );
if( k[n].col == COL_WHITE ) ply[act].stat |= FOUL_WHITE_POCKETED;
else if( (k[n].col == COL_BLACK) && (ply[act].col != COL_BLACK) )
ply[act].stat |= FOUL_BLACK_ILLEGALY_POCKETED;
else if( !ply[act].col && (k[n].col != COL_WHITE) )
{ /* falls noch kein Spieler-Farbe festgelegt ist */
if( (k[n].col != COL_BLACK) && (ply[1-act].col != k[n].col) )
ply[act].col = k[n].col;
ply[1-act].col = 3 - k[n].col;
ply[act].stat |= FOUL_CORRECT_POT;
col_in = k[n].col;
new_col |= NEW_COL_NEW;
}
else if( !freeball && (k[n].col != ply[act].col) ) /* falsche Farbe */
{
if( new_col & NEW_COL_NEW ) new_col |= NEW_COL_DOUBLE;
else ply[act].stat |= FOUL_WRONG_COLOR_POCKETED;
}
else if( freeball || (k[n].col == ply[act].col)) /* OK */
ply[act].stat |= FOUL_CORRECT_POT;
bande_hit = 1;
last_pocketed_balls++;
}
void print( char *out, int align, int x, int y )
{
int old_align = textleft.txo_xalign;
textleft.txo_xalign = align;
GrDrawString( out, strlen(out), x, y, &textleft );
textleft.txo_xalign = old_align;
}
void print2( char *out, int align, int x, int y )
{
int old_align = textcenter.txo_xalign;
textcenter.txo_xalign = align;
GrDrawString( out, strlen(out), x, y, &textcenter );
textcenter.txo_xalign = old_align;
}
void help( void )
{
GrContext *cont = NULL;
int a=100;
mouse_off();
cont = GrCreateContext( GrSizeX(), GrSizeY(), NULL, NULL );
if( cont )
{
GrBitBltNC(cont, 0, 0, NULL, 0, 0, GrSizeX(), GrSizeY(), GrWRITE);
GrClearScreen( 0 );
GrDrawString("HELP-Screen", 11, GrMaxX()/2, 30, &textopt );
print("KEYS:",GR_ALIGN_LEFT, 30, 65);
print(" 'c': activate/deactivate computer opponent",
GR_ALIGN_LEFT, 30, a+=16);
print(" 'x': computer plays only one shot", GR_ALIGN_LEFT, 30, a+=16 );
print(" 'n': new game, actual game is lost", GR_ALIGN_LEFT, 30, a+=16 );
print(" 'd': demo-mode on; any key to stop demo",
GR_ALIGN_LEFT, 30, a+=16 );
print(" 'w': ball rolls to actual mouse-position (test-procedure)",
GR_ALIGN_LEFT, 30 , a+=16 );
print(" 'W': some sort of computer help (test it)",
GR_ALIGN_LEFT, 30, a+=16 );
print(" 'u': undo last shot (no redo implemented)",
GR_ALIGN_LEFT, 30 , a+=16 );
print(" 'r': slow-motion-mode on/off", GR_ALIGN_LEFT, 30, a+=16 );
print(" 's': show statistics", GR_ALIGN_LEFT, 30, a+=16 );
print(" 'F1': this screen", GR_ALIGN_LEFT, 30, a+=16 );
print(" 'F2': credits", GR_ALIGN_LEFT, 30, a+=16 );
print("ENTER: or SPACE: same as left mouse-button",
GR_ALIGN_LEFT, 30, a+=16 );
print(" 'q': show statistics before quitting the game",
GR_ALIGN_LEFT, 30, a+=16);
print(" ESC: 'fast' quit game (works im allmost every situation)",
GR_ALIGN_LEFT, 30, a+=16 );
wait_for_click();
GrBitBltNC( NULL, 0, 0, cont, 0, 0, GrSizeX(), GrSizeY(), GrWRITE);
GrDestroyContext( cont );
}
else msg("no help available");
mouse_on();
}
void credits( void )
{
/*#ifndef S3*/
GrContext *cont = NULL;
/*#endif*/
int a=70;
char out[90];
mouse_off();
/*#ifndef S3*/
cont = GrCreateContext( GrSizeX(), GrSizeY(), NULL, NULL );
if( cont )
{
GrBitBltNC(cont, 0, 0, NULL, 0, 0, GrSizeX(), GrSizeY(), GrWRITE);
/*#else*/
/* bitblt( 0, 0, 0, 700, 640, 480 );*/
/*#endif*/
GrClearScreen( 0 );
sprintf(out,"Another Pool V %s, %s, copyright (c) by Gerrit Jahn",
VERSION, DATE);
print2(out, GR_ALIGN_CENTER, GrMaxX()/2, 20 );
GrDrawString("CREDITS", 8, GrMaxX()/2, 40, &textopt );
print2("'ANOTHER POOL' is free software; you can redistribute it",
GR_ALIGN_LEFT, 90, a+=15);
print2("and/or modify it under the terms of the GNU General Public License",
GR_ALIGN_LEFT, 90, a+=15);
print2("as published by the Free Software Foundation; either version 2 of",
GR_ALIGN_LEFT, 90, a+=15);
print2("the License, or (at your option) any later version.",
GR_ALIGN_LEFT, 90, a+=15);a+=15;
print2("Another Pool is distributed in the hope that it will be useful,",
GR_ALIGN_LEFT, 90, a+=15);
print2("but WITHOUT ANY WARRANTY; without even the implied warranty of",
GR_ALIGN_LEFT, 90, a+=15);
print2("MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the",
GR_ALIGN_LEFT, 90, a+=15);
print2("GNU General Public License (see file COPYING) for more details.",
GR_ALIGN_LEFT, 90, a+=15);a+=5;
print2("------------------------------------------------------------------",
GR_ALIGN_LEFT, 90, a+=15);a+=5;
print("Special thanks to Achim Stremplat for helping me in",
GR_ALIGN_LEFT, 90, a+=15);
print("coding and talking about the physics of the game.",
GR_ALIGN_LEFT, 90, a+=15);
print("Also thanks to Jens Willibald, Martin Schmidt and Frank",
GR_ALIGN_LEFT, 90, a+=15);
print2("Schmithuesen for testing; Boris Postler for some corrections",
GR_ALIGN_LEFT, 90, a+=15);
print2("on the 'apool.doc'-file.", GR_ALIGN_LEFT, 90, a+=15);
print2("... and the developers of GNU-C ...", GR_ALIGN_LEFT, 90, a+=15);
a+=5;
print2("------------------------------------------------------------------",
GR_ALIGN_LEFT, 90, a+=15);a+=5;
print2("If you have any problems, questions or suggestions, email to:",
GR_ALIGN_LEFT, 90, a+=15);
print2("ub1g@rz.uni-karlsruhe.de Gerrit",
GR_ALIGN_LEFT, 90, a+=15);a+=15;
wait_for_click();
/* #ifndef S3*/
GrBitBltNC( NULL, 0, 0, cont, 0, 0, GrSizeX(), GrSizeY(), GrWRITE);
GrDestroyContext( cont );
}
else msg("no credits available");
/*#else*/
/* bitblt( 0, 700, 0, 0, 640, 480 );*/
/*#endif*/
mouse_on();
}