#ifndef __global_h # include "global.H" #endif #ifndef __port_h # include "port.H" #endif #ifndef __color_h # include "color.H" #endif #ifndef __tile_h # include "tile.H" #endif #ifndef __board_h # include "board.H" #endif #ifndef __font_h # include "font.H" #endif #ifndef __game_h # include "game.H" #endif #ifndef __mem_image_h # include "mem_image.H" #endif #ifndef __color_mapper_h # include "color_mapper.H" #endif #include #include #include #include // #include // #include #ifdef WIN32 // löschen der schlechtesten Macros der Xlib # undef Status # include "winsock.h" #endif #include #ifndef X_GETTIMEOFDAY /* define X_GETTIMEOFDAY macro, a portable gettimeofday() */ /* copied from Xos.h for pre-X11R6 releases */ # if defined(SVR4) || defined(VMS) || defined(WIN32) # define X_GETTIMEOFDAY(t) gettimeofday(t) # else # define X_GETTIMEOFDAY(t) gettimeofday(t, (struct timezone*)0) # endif #endif #ifndef FDS_TYPE // // The problem occured, that on HP-UX, the type used in the masks of the // select() system call are not the usual 'fd_set'. Instead they are just // integer pointers, which leads to an compile-error, when not casted. // Therefore it actually will get casted by the following Macro FDS_TYPE, // which should usually be defined to an empty string. // # ifdef __hpux # define FDS_TYPE (int*) # else # define FDS_TYPE # endif #endif #include "stipple.h" #include "rstipple.h" /* Field position */ #define MFieldX(x) ((x)*sizex+offx+border) #define MFieldY(y) ((y)*sizey+offy+border) /* Score position */ #define SCol(x) ((x)*bsizex+(dwidth)*sizex+2*border+offx) #define STop() (border+offy) #define SRow(y) (dheight*sizey+border-(y+1)*bsizey+offy) #define FACTOR (2) #define FlashSpeed 20 #define _TRACE_COLORS unsigned long current_time; static unsigned long get_current_time() { unsigned long ret; struct timeval timeval; static unsigned long start=0; X_GETTIMEOFDAY( &timeval ); if (!start) start=timeval.tv_sec; ret = ((timeval.tv_sec-start) * 100) + timeval.tv_usec/10000; return( ret ); } Port *Port::first = 0; int Port::color_id = 1; int Port::dwidth = 8; int Port::dheight = 3; int Port::dsize = 44; int Port::wsizex = 100; int Port::wsizey = 100; int Port::nplayers = 1; Mode Port::def_mode = Smiley; int Port::def_size = 1; MemImage *Port::gif = 0; int Port::remove_flag = 1; int Port::sync_flag = 0; int Port::resize_lock = 0; static unsigned long next_sec; struct fd_set Port::readfds; int Port::nfds = 0; #ifndef MaxBorder # define MaxBorder (80) #endif Port::Port( char *disp_name, char *color ) { char dsp_nam[30]; static int w=0; int i; wbsizex = (wsizexMaxBorder) wborder=MaxBorder; strcpy( dsp_nam, disp_name ); if ((*disp_name)&&(!strchr(dsp_nam,':'))) { strcat( dsp_nam, ":0" ); } // open connection to display and create a window display = XOpenDisplay( dsp_nam ); if (!display) { fprintf(stderr,"\n" ); fprintf( stderr, "*** can't open display '%s'.\n", dsp_nam ); fprintf(stderr,"\n" ); exit(-1); } screen = DefaultScreenOfDisplay( display ); mapper = new ColorMapper(display); double_depth=(DefaultDepthOfScreen(screen)>8)?0:1; // XSynchronize(display,1); // Check for non-pseudocolor visual, since there are // no planes available -> need for a stipple instead if (DefaultVisualOfScreen(screen)->c_class!=PseudoColor || def_mode==Photo) { light=mapper->alloc_named_color("white"); fg =mapper->alloc_named_color("grey30"); bg =mapper->alloc_named_color("grey60"); dark =mapper->alloc_named_color("black"); stipple_pmap=XCreateBitmapFromData( display,RootWindowOfScreen( screen ), stipple_bits, stipple_width, stipple_height ); rstipple_pmap=XCreateBitmapFromData( display,RootWindowOfScreen( screen ), rstipple_bits, rstipple_width, rstipple_height ); } else { stipple_pmap = 0; rstipple_pmap = 0; light = 0; fg = 2; bg = 1; dark = 3; } MInit(dsize); window = XCreateSimpleWindow( display, RootWindowOfScreen( screen ), 0, 0, MWidth(), MHeight(), 0, BlackPixelOfScreen(screen), WhitePixelOfScreen(screen) ); XStoreName( display, window, color ); XSelectInput( display, window, StructureNotifyMask|ExposureMask|ButtonPressMask ); normal_cursor = XCreateFontCursor( display, XC_top_left_arrow ); // idle_cursor = XCreateFontCursor( display, XC_dotbox ); idle_cursor = XCreateFontCursor( display, XC_circle ); XSetWindowAttributes attrib; attrib.bit_gravity = ForgetGravity; XChangeWindowAttributes(display,window,CWBitGravity,&attrib); XSizeHints hints; hints.flags = USPosition | USSize | PAspect; hints.x = 100+(w%2)*(50+MWidth()); hints.y = 100+(w/2)*(50+MHeight()); hints.width = MWidth(); hints.height = MHeight(); hints.min_aspect.x = hints.max_aspect.x = MWidth(); hints.min_aspect.y = hints.max_aspect.y = MHeight(); #if (1) XSetNormalHints( display,window,&hints ); #endif w++; this->width = hints.width; this->height = hints.height; Atom atom = XInternAtom(display,"PmWindowType",True); if (atom) { char* win_type = "FGnormal"; XTextProperty prop; XStringListToTextProperty (&win_type, 1, &prop); XSetTextProperty (display, window, &prop, atom); XFree((void*)prop.value); } // // Reaktion auf Destroy Message anmelden // WmProtocolsPropId = XInternAtom(display,"WM_PROTOCOLS",False); WmDeleteWindowPropId = XInternAtom(display,"WM_DELETE_WINDOW",False); XSetWMProtocols( display, window, &WmDeleteWindowPropId, 1 ); // // Fileselector merken // if (!nfds) FD_ZERO( &readfds ); FD_SET( ConnectionNumber(display), &readfds ); if (nfds<=ConnectionNumber(display)) nfds = ConnectionNumber(display)+1; mode=def_mode; if (mode==Photo) { ncols=gif->GetNCols(); gif_cols=new unsigned long[ncols]; for (i=0;iGetColor(i,&def.red,&def.green,&def.blue); gif_cols[i]=mapper->alloc_color(&def); } } tile = new Tile*[board_p->ntiles]; for (i=0;intiles;i++) tile[i]=0; blank = 0; empty = 0; // initialize graphic context for drawing tiles // on a pseudocolor display, only the lower 2 planes are to // be drawn, the tile gets its color through overlay-planes. gc_tile = XCreateGC( display, RootWindowOfScreen(screen), 0L, NULL ); if (stipple_pmap) { XSetStipple( display, gc_tile, rstipple_pmap ); XSetFillStyle( display, gc_tile, FillStippled ); } else { XSetPlaneMask( display, gc_tile, 0x3 ); } gc_all = XCreateGC( display, RootWindowOfScreen(screen), 0L, NULL ); // initialize tiles sizex=0; sizey=0; resize( hints.width, hints.height ); // exchange colors of ports colors=0; color_name = new char[strlen(color)+1]; strcpy( color_name, color ); my_id = color_id; #ifdef TRACE_COLORS printf( "new Port: %08lx\n", this ); #endif add_color( 0, "yellow" ); if (first) add_foreign_color( first, color_name ); add_color( color_id, color_name ); if (stipple_pmap) XSetWindowBackground( display, window, colors->pixel ); else XSetWindowBackground( display, window, colors->pixel+bg ); XMapRaised( display, window ); // connect to list of created displays next = first; first = this; color_id++; lock_count = 0; lock_time = 0; flash_time = 0; lock[0] = lock[1] = -1; points = 0; selections = 0; active = (sync_flag)?0:1; #ifdef TRACE_COLORS printf( " Port %08lx initialized\n", this ); #endif } void Port::add_foreign_color( Port *current, char *color_name ) { current->add_color( color_id, color_name ); if (current->next) add_foreign_color(current->next,color_name); add_color( current->my_id, current->color_name ); } void Port::sub_color( int id ) { Color *current= colors; Color *mark=0; // // Id dekrementieren // while(current) { if (current->color_id==id) mark = current; if (current->color_id>id) current->color_id--; current=current->next; } // // Farbe ausketten // if (mark==colors) { colors = mark->next; } else { current = colors; while( current->next != mark ) current = current->next; current->next = mark->next; } // // Farbe loeschen // mark->next = 0; delete mark; // // neue Fensterdimension: // offx = (width-MWidth())/2; XClearArea(display,window,0,0,0,0,True); } Port::~Port() { activate_next_player(); // checks, if I was the active player ... nplayers--; // Zahl der Spieler board_p->color_removed(my_id); // Farbe im Brett freigeben color_id--; // Gesamtfarbenzaehler // // Farbe aus allen Ports austragen // Port *current; current=first; do { if (current->my_id>my_id) current->my_id--; current = current->next; } while(current); // // Port ausketten // if (this==first) { first = this->next; } else { current = first; while( current->next != this ) current = current->next; current->next = this->next; } // // Farbumsetzungstabelle freigeben // if (gif_cols) delete gif_cols; if (gif&&!first) { delete gif; gif=0; } // // Farbe aus den Ports austragen // for (current=first;current;current=current->next) current->sub_color( my_id ); for (int i=0;intiles;i++) { if (tile[i]) delete tile[i]; } delete tile; if (blank) delete blank; if (empty) delete empty; delete colors; delete color_name; if (stipple_pmap) { XFreePixmap( display, stipple_pmap ); XFreePixmap( display, rstipple_pmap ); } XFreeGC( display, gc_all ); XFreeGC( display, gc_tile ); XFreeCursor( display, normal_cursor ); XFreeCursor( display, idle_cursor ); delete mapper; XSync( display, 0 ); XCloseDisplay( display ); } void Port::UpdateTime( const char *time_str ) { XStoreName( display, window, time_str ); } void Port::add_color( int color_id, char *color_name ) { Color *new_color; #ifdef TRACE_COLORS printf( "%08lx: add %d = %s\n", this, color_id, color_name ); #endif new_color = new Color( this, color_id, color_name ); #if(1) new_color->next = colors; colors = new_color; #else new_color->next = 0; if (!colors) colors = new_color; else { Color *col = colors; while( col->next ) col=col->next; col->next=new_color; } #endif } int Port::empty_queue() { XEvent event; // XSync( display, 0 ); while ( XEventsQueued( display, QueuedAfterFlush ) ) { XNextEvent( display, &event ); switch( event.type ) { case ButtonPress: { switch(event.xbutton.button) { case 2: if (my_id==1) return 1; default: { if (board_p->finished&¤t_time>board_p->finished+5000) return 1; int x = (event.xbutton.x-offx-border)/sizex; int y = (event.xbutton.y-offy-border)/sizey; #if (0) printf(" press: (%d,%d)\n", x, y ); #endif selected(x,y); } } break; } case Expose: { #if (0) printf("%d - Expose: (%d,%d) - (%d,%d)\n", my_id, event.xexpose.x, event.xexpose.y, event.xexpose.x + event.xexpose.width, event.xexpose.y + event.xexpose.height ); #endif redraw( event.xexpose.x, event.xexpose.y, event.xexpose.x + event.xexpose.width, event.xexpose.y + event.xexpose.height ); break; } case ConfigureNotify: #if (0) printf("%d - Configure: (%d,%d)\n", my_id, event.xconfigure.width, event.xconfigure.height ); #endif resize( event.xconfigure.width, event.xconfigure.height ); break; case ClientMessage: if (event.xclient.message_type == WmProtocolsPropId) { Atom data_atom = (Atom)event.xclient.data.l[0]; if (data_atom == WmDeleteWindowPropId) { if (my_id==1) return 1; // main-window -> than exit return -1; // delete me ! } } } } return 0; } int Port::wait_event() { static unsigned long next=0; int erg = 0; current_time = get_current_time(); if (!next||next>next_sec) next=next_sec; if (current_timenext_sec) { next_sec = ((current_time/100)+1)*100; if (!board_p->finished) { char buffer[20]; sprintf( buffer, "%02ld:%02ld", (next_sec/100) / 60, (next_sec/100) % 60 ); for( Port *current = first; current; current=current->next ) { current->UpdateTime(buffer); } } } next = 0; for( Port *current = first; current; current=current->next ) { int delete_flag = current->empty_queue(); if (delete_flag<0) { delete current; if (first) return erg+wait_event(); else return 1; } else erg+=delete_flag; unsigned long current_next = current->deselect(); if (current_next) { if (!next||current_nextid;i--) current=current->next; return( current->gc_n ); } int Port::Points( int id ) { Port *current=first; int i; for (i=color_id-1;i>id;i--) current=current->next; return( current->points ); } void Port::statistic() { Port *current=first; printf( "SUMMARY Points Selections\n" ); for (current=first;current;current=current->next) { printf("%-10s %3d %-5d\n", current->color_name, current->points, current->selections ); } if (board_p->finished) { printf( "TIME: %02ld:%02ld.%02ld\n", (board_p->finished/100) / 60, (board_p->finished/100) % 60, (board_p->finished%100) ); } } void Port::redraw( int x, int y ) { Field *f= board_p->field(x,y); if (!f) return; if (f->locked && !f->gone) { XCopyArea( display, tile[f->tile_id]->pixmap, window, gc_tile, 0, 0, sizex, sizey, MFieldX(x), MFieldY(y) ); if (!stipple_pmap||f->flash||f->lock_col!=my_id) { XFillRectangle( display, window, (f->flash)? gc_color_n(0) : gc_color_n(f->lock_col), MFieldX(x), MFieldY(y), sizex, sizey ); } #if (0) XSetFillStyle( display, gc_tile, FillStippled ); XCopyArea( display, tile[f->tile_id]->pixmap, window, gc_tile, 0, 0, sizex, sizey, MFieldX(x), MFieldY(y) ); #endif } else { if (remove_flag || !f->gone || f->lock_col!=my_id) { XCopyArea( display, ((f->found)?empty->pixmap:blank->pixmap), window, gc_tile, 0, 0, sizex, sizey, MFieldX(x), MFieldY(y) ); XFillRectangle( display, window, (f->found)?gc_color_n(f->lock_col):gc_color_n(my_id), MFieldX(x), MFieldY(y), sizex, sizey ); } else { XCopyArea( display, tile[f->tile_id]->pixmap, window, gc_tile, 0, 0, sizex, sizey, MFieldX(x), MFieldY(y) ); } } } void Port::draw_block( int p, int x, int y ) { XFillRectangle( display, window, gc_color_n(p+1), x, y, bsizex, bsizey ); XSetForeground( display, gc_tile, bg ); XFillRectangle( display, window, gc_tile, x, y, bsizex, bsizey ); XSetForeground( display, gc_tile, light ); XDrawLine( display, window, gc_tile, x, y, x+bsizex-1, y ); XDrawLine( display, window, gc_tile, x, y, x, y+bsizey-1 ); XSetForeground( display, gc_tile, dark ); XDrawLine( display, window, gc_tile, x, y+bsizey-1, x+bsizex-1, y+bsizey-1 ); XDrawLine( display, window, gc_tile, x+bsizex-1, y, x+bsizex-1, y+bsizey-1 ); } void Port::redraw_score( int x ) { if (x>=nplayers || x<0) return; XFillRectangle( display, window, gc_color_n(my_id), SCol(x), STop(), bsizex, dheight*sizey ); XSetForeground( display, gc_tile, fg); XFillRectangle( display, window, gc_tile, SCol(x), STop(), bsizex, dheight*sizey ); XSetForeground( display, gc_tile, dark); XDrawLine( display, window, gc_tile, SCol(x), STop(), SCol(x+1)-1, STop() ); XDrawLine( display, window, gc_tile, SCol(x), STop(), SCol(x), STop()+dheight*sizey-1 ); XSetForeground( display, gc_tile, light); XDrawLine( display, window, gc_tile, SCol(x), STop()+dheight*sizey-1, SCol(x+1)-1, STop()+dheight*sizey-1 ); XDrawLine( display, window, gc_tile, SCol(x+1)-1, STop(), SCol(x+1)-1, STop()+dheight*sizey-1 ); int height = Points(x+1); for (int y=1;y<=height;y++) { draw_block( x, SCol(x), SRow(y-1) ); } XFlush( display ); } void Port::redraw( int x1, int y1, int x2, int y2 ) { int x1s,y1s,x2s,y2s; int x, y; #if (1) XClearArea( display, window, x1, y1, x2-x1, y2-y1, False ); #endif // check for score redraw x1s = (x1-SCol(1))/bsizex; // make it one field smaller x2s = (x2-SCol(0))/bsizex; if (x2s>=0) { for (x=x1s;x<=x2s;x++) { redraw_score(x); } } x1s=(x1-offx-border)/sizex; y1s=(y1-offy-border)/sizey; x2s=(x2-offx-border)/sizex; y2s=(y2-offy-border)/sizey; for (x=x1s-1;x<=x2s;x++) { for (y=y1s-1;y<=y2s;y++) { redraw( x, y ); } } } void Port::tile_redraw( int fid ) { int x = fid%board_p->dx; int y = fid/board_p->dx; for ( Port *current = first; current; current = current->next ) { current->redraw( x, y ); // XFlush( current->display ); XSync( current->display, 0 ); } } void Port::flush_all() { for ( Port *current = first; current; current = current->next ) XFlush( current->display ); } void Port::activate_next_player() { Port *current; if (sync_flag && active) { for ( current = first; current; current = current->next ) { if (current==this) break; } Port *next=(current->next)?current->next:first; current->set_active( 0 ); next->set_active( 1 ); } } void Port::set_active( int a ) { if ( a ) { XDefineCursor( display, window, normal_cursor ); } else { XDefineCursor( display, window, idle_cursor ); } active=a; } void Port::activate_any_player() { Port *current; int id=rand()%nplayers; if (sync_flag) { for ( current = first; current; current = current->next ) { current->set_active( (id)?0:1 ); id--; } } } int Port::remove() { if ((lock_count>1)&&(board_p->field(lock[1])->found)) { board_p->field(lock[1])->gone = 1; tile_redraw( lock[1] ); board_p->field(lock[0])->gone = 1; tile_redraw( lock[0] ); lock_count=0; points+=2; for (Port *p=first;p;p=p->next) { p->redraw_score(my_id-1); } board_p->tile_removed(my_id); flash_time=0; return 1; } else { activate_next_player(); return 0; } } unsigned long Port::deselect() { unsigned long next = 0; if (flash_time) { if (flash_timefield(lock[0])->flash ^= 1; board_p->field(lock[1])->flash ^= 1; tile_redraw(lock[0]); tile_redraw(lock[1]); next=flash_time=current_time+FlashSpeed; // printf("FLASH %lu\n",flash_time); } else { next = flash_time; // printf("FLASH SUPPRESSED\n"); } } if (lock_time&¤t_timelock_time)?lock_time:next; if (lock_count>1) { if (!remove()) { board_p->field(lock[1])->locked = 0; tile_redraw( lock[1] ); } } if (lock_count>0) { board_p->field(lock[0])->locked = 0; tile_redraw( lock[0] ); } lock_count=0; lock_time =0; return 0; } void Port::selected( int x, int y ) { int fid; Field *f= board_p->field(x,y); if (!f) return; //printf( "Pos: (%d,%d), Tile: %d, Locks %d\n", x,y,f->tile_id,lock_count ); if (lock_count==2) { if (!remove()) { // XBell( display, 100 ); return; } } fid = x+board_p->dx*y; //printf(" fid: %d, removed: %d, lock_id: %d\n", fid, f->removed, f->lock_id ); if (f->found) return; if (f->locked || !active) { #if (1) if (!active) XBell( display,100 ); return; #else if (f->lock_col!=my_id){ } else { if (lock[0]==fid) { lock[0]=lock[1]; } lock_count--; f->locked=0; tile_redraw( fid ); lock_time=current_time; return; } #endif } selections++; f->lock_col = my_id; f->locked = 1; lock[lock_count++] = fid; if (lock_count==2) { if (board_p->field(lock[0])->tile_id==board_p->field(lock[1])->tile_id) { board_p->field(lock[0])->found = 1; board_p->field(lock[0])->flash = 1; board_p->field(lock[1])->found = 1; board_p->field(lock[1])->flash = 1; tile_redraw( lock[0] ); // tile_redraw( lock[1] ); flash_time = current_time+FlashSpeed; // printf( "FLASH: %lu (current: %lu\n)\n", current_time, flash_time ); } } tile_redraw( fid ); lock_time = current_time + ((lock_count==2)?100:((sync_flag)?6000:300)); } const char *Port::find_font( const char *pattern, int size ) { char **font; int count; int i; char *true_name = 0; char *true_scale = 0; char *bitmap_name = 0; char *bitmap_scale = 0; char *closest_name = 0; int closest_scale = -1; static char ret_buffer[200]; font=XListFonts(display,pattern,100,&count); for (i=0;iclosest_scale ) { closest_name = font[i]; closest_scale = csize; } } } } ret_buffer[0]='\0'; if (bitmap_name) { strcpy( ret_buffer, bitmap_name ); sprintf(ret_buffer+(bitmap_scale-bitmap_name),"%d%s", size, bitmap_scale+1 ); } if (true_name) { strcpy( ret_buffer, true_name ); sprintf(ret_buffer+(true_scale-true_name),"%d%s", size, true_scale+1 ); } if ( closest_name && closest_scale > size-4 ) { strcpy(ret_buffer,closest_name); } XFreeFontNames(font); if (ret_buffer[0]=='\0') { fprintf(stderr,"\n" ); fprintf(stderr,"*** Unable to find any matching fonts with pattern\n" ); fprintf(stderr,"*** '%s' on display '%s'.\n", pattern, DisplayString(display) ); fprintf(stderr,"*** Please make the font available via xset(1) or use the\n" ); fprintf(stderr,"*** option -font to select a different pattern.\n" ); fprintf(stderr,"\n" ); exit(-1); } // printf( "%2d %2d: %s\n", size, closest_scale, ret_buffer ); return ret_buffer; } void Port::resize( int width, int height ) { int nsizex; int nsizey; int i; // // check window size // nsizex = wsizex*width/WWidth(); // calculate new pixel values nsizey = wsizey*height/WHeight(); if (nsizex*wsizey0) { nsizex=wsizex*resize_lock/100; } else { int ratio = (nsizex*100)/wsizex; ratio = 10*(ratio/10); nsizex=wsizex*ratio/100; } } if ((nsizex==sizex)&&(nsizey==sizey)) { offx = (width-MWidth())/2; offy = (height-MHeight())/2; return; } MInit(nsizex); offx = (width-MWidth())/2; offy = (height-MHeight())/2; this->width = width; this->height = height; // XResizeWindow( display, window, MWidth(sizex), MHeight(sizey) ); // calculate screen resolution in dots per inch 25.4mm=1 inch // int res_x = (int)(WidthOfScreen(screen)/(WidthMMOfScreen(screen)/25.4)); // int res_y = (int)(HeightOfScreen(screen)/(HeightMMOfScreen(screen)/25.4)); ScalableFont *font; if (param[Port::def_mode].font_mode) { font = new FlipFont(display, find_font(param[Port::def_mode].font,sizex-4 ) ,270); } else { font = new ScalableFont(display, find_font(param[Port::def_mode].font,sizey-10 ),0); } // // initialize tiles // for (i=0;intiles;i++) { if ( tile[i] ) delete tile[i]; tile[i] = new Tile( this, font, i ); } if (blank) delete blank; if (empty) delete empty; empty = new Tile(this, font, -1); blank = new Tile(this, font, -2); delete font; }