/*****************************************************************************/
/*                                                                           
/*  Program:      TETROIDS.C  -  Real time X-Window programming example 
/*                                                                           
/*                                                                           
/*  Author:       Jym Barnes 
/*                                                                           
/*                                                                           
/*  Date:         January 1, 1991 
/*                                                                           
/*                                                                           
/*  Version:      1.0 
/*                                                                           
/*                                                                           
/*  Abstract:     This program demonstrates real time programming by using the
/*                the popular arcade game Tetroids as an example.
/*                                                                           
/*              
/*  Revision History:
/*                                                          
/*
/*  Note:         This program has been released to public domain with the
/*                stipulation that the header remain with all source code 
/*                copies of the program.
/*
/*****************************************************************************/
#include <decw$include/Xlib.h>
#include <decw$include/Xutil.h>
/*  
    Set up XWINDOW data structure for the display.
*/
    Display	    *mydisplay;
/*
    Set up the XWINDOW data structure for the various windows used by TETROIDS
*/
    Window	    scorewindow;
    Window	    scoresubwindow;
    Window	    beginwindow;
    Window	    quitwindow;
    Window	    mainwindow;
    Window	    playwindow;
    Window	    pausewindow;
    Window	    nextfigurewindow;
    Window	    statwindow;
/*
    Define a graphics context data structure for filled and clear.
*/
    GC		    mygc_fill;
    GC		    mygc_clear;
/*
    Define the event data structure to process the different XWINDOW events.
*/
    XEvent	    myevent;
/*
    Define the key typed data structure used to process key strokes input
    from the keyboard
*/    
    KeySym	    mykey;
/*
    Define the screen size data structure used for possible screen size.
*/
    XSizeHints	    myhint;

/*
    Set up misc XWINDOW data elements
*/
    int		    screen;
    int		    myscreen;
    unsigned long   myforeground;
    unsigned long   mybackground;
/*
    first time flag
*/
    int		    first_time;
/*
    set up counters for the various type of figures
*/
    int		    square = 0;
    int		    up_l = 0;
    int		    down_l = 0;
    int		    up_stairs = 0;
    int		    down_stairs = 0;
    int		    line = 0;
    int		    t = 0;

    char	    scoreing_label [] = {"Tetroids Score"};
    char	    main_window_name [] = {"Tetroids"};

    char	    text[10];
    char	    blank[5] = {"    "};
/*  
    The variables i and j are for temporary loop counters.
*/
    int		    i;
    int		    j;
/*
    These are the various bit maps used for the figure movement
*/
    int		    figure_map[5];
    int		    next_figure_map[5];
    int		    save_next_figure_map[5];
    int		    rotation_map[5];
    int		    screen_map[19];
/*
    These variables are used so the tetroids screen can be different sizes
*/
    int		    screen_size;
    int		    play_screen_size;
    int		    block_size;
/*
    These variables are used so the next figure can be displayed
*/
    int		    figure_type;
    int		    next_figure_type;
    int		    save_next_figure_type;
/*
    The reset of the variables are for misc items
*/
    int		    sts;
    int		    sync;
    int		    quit;
    int		    block_pos_y;
    int		    block_pos_x;
    int		    decent_speed;
    int		    decent;
    int		    saved_decent_speed;
    int		    rotation;
    int		    save_rotation;
    int		    check_time;
    int		    score_bin;
    char	    score[5];
    int		    rotation_valid;
    int		    pause;
    int		    skill_level;
    int		    skill_level_input;
    int	            random_number;
    int		    seed;
    Font	    font;
/* 
    Start the main program
*/
main(argc,argv)
    int argc;
    char *argv[];
    {
/*
    Get screen size and skill level from user
*/
    printf("Please type desired screen size? 1000 for a 19 inch screen ");
    scanf("%d",&screen_size); 
    if (screen_size == 0) 
	{
	screen_size = 1900;
	}
/*
    Get the skill level the users wants.
*/
    printf("Please type the skill leveled desired? (101 is default) ");
    scanf("%d",&skill_level_input);
    if (skill_level_input == 0) 
	{
	skill_level_input = 101;
	}
    play_screen_size = screen_size - (screen_size/5);
    block_pos_y = 2;
    block_size = play_screen_size/16;
/*  
    Open a display connection between client and server
*/
    mydisplay = XOpenDisplay("");
/*
    Set up characterisitics for the main window
*/
    myscreen = DefaultScreen (mydisplay);

    mybackground = WhitePixel (mydisplay, myscreen);
    myforeground = BlackPixel (mydisplay, myscreen);

    myhint.x = 0;
    myhint.y = 0;
    myhint.width = screen_size;
    myhint.height = screen_size;
    myhint.flags = PPosition | PSize;
  
/*
    Create the main window.
*/
    mainwindow = XCreateSimpleWindow (mydisplay,
	    DefaultRootWindow (mydisplay),
	    0, 0, screen_size, screen_size,
	    1, myforeground, mybackground);

/*
    Create the scoring window.
*/

    scorewindow = XCreateSimpleWindow (mydisplay,
	    mainwindow,
	    0, 0, (screen_size/5), screen_size,
	    1, mybackground, myforeground);

/*
    Set up a fill GC and a clear GC
*/
    mygc_fill = XCreateGC (mydisplay, mainwindow, 0, 0);
    mygc_clear = XCreateGC (mydisplay, mainwindow, 0, 0);
/*
    Set up characteristics in the two GC's
*/
    XSetBackground (mydisplay, mygc_fill, mybackground);
    XSetForeground (mydisplay, mygc_fill, myforeground);

    XSetBackground (mydisplay, mygc_clear, myforeground);
    XSetForeground (mydisplay, mygc_clear, mybackground);
/*
    Create the play window
*/

    playwindow = XCreateSimpleWindow (mydisplay,
	    mainwindow,
	    (screen_size/5), 0, 
	    play_screen_size, play_screen_size,
	    10, myforeground, mybackground);
/*
    Create the begin window.
*/
    beginwindow = XCreateSimpleWindow (mydisplay,
	    scorewindow,
	    0, 10, 100, 50,
	    2, myforeground, mybackground);
/*
    Create the quit window.
*/
    quitwindow = XCreateSimpleWindow (mydisplay,
	    scorewindow,
	    0, 70, 100, 50,
	    2, myforeground, mybackground);
/*
    Create the pause button
*/
    pausewindow = XCreateSimpleWindow (mydisplay,
	    scorewindow,
	    0, 130, 100, 50,
	    2, myforeground, mybackground);
/*
    Create the next figure window.
*/

    nextfigurewindow = XCreateSimpleWindow (mydisplay,
	    scorewindow,
	    0, 250, block_size * 4, block_size * 4,
	    2, myforeground, mybackground);

    statwindow = XCreateSimpleWindow (mydisplay,
	    scorewindow,
	    0, 300 + (block_size * 4), block_size * 4, block_size * 6,
	    2, myforeground, mybackground);

    scoresubwindow = XCreateSimpleWindow (mydisplay,
	    scorewindow,
	    0, 190, 100, 50,
	    2, myforeground, mybackground);
/*
    Label the window as the scoreing window
*/
    XSetStandardProperties (mydisplay, scorewindow, scoreing_label, 
	scoreing_label, None, argv, argc, &myhint);
/*
    Label the main window as of such
*/
    XSetStandardProperties (mydisplay, mainwindow, main_window_name, 
	main_window_name, None, argv, argc, &myhint);
/*
    Set up for event of clicking on begin, quit, pause of main windows.
*/
    XSelectInput (mydisplay, beginwindow,
	KeyPressMask | ButtonPressMask);

    XSelectInput (mydisplay, quitwindow,
	KeyPressMask | ButtonPressMask);

    XSelectInput (mydisplay, pausewindow,
	KeyPressMask | ButtonPressMask);

    XSelectInput (mydisplay, mainwindow,
	KeyPressMask | ButtonPressMask | StructureNotifyMask);
/*
    Paste the different windows onto the screen.
*/
    XMapRaised (mydisplay, mainwindow); 
    XMapRaised (mydisplay, scorewindow); 
    XMapRaised (mydisplay, playwindow); 
    XMapRaised (mydisplay, beginwindow); 
    XMapRaised (mydisplay, quitwindow);
    XMapRaised (mydisplay, pausewindow);
    XMapRaised (mydisplay, scoresubwindow);
    XMapRaised (mydisplay, nextfigurewindow);
    XMapRaised (mydisplay, statwindow);
/*
    Turn on Synchoronize.  This will cause X-Window action to execute
    synchoronise instead of the default which is asynchoronise.
*/
    sync = 1; 
/*
    XSynchronize (mydisplay, sync);
*/
    XNextEvent (mydisplay, &myevent);
/*
    Label beginning window as of such
*/
    XDrawString (mydisplay, beginwindow, mygc_fill, 8, 25,
		     "Press to Begin",strlen("Press to Begin"));
/*
    Label quit window as of such
*/
    XDrawString (mydisplay, quitwindow, mygc_fill, 8, 25,
		     "Press to Quit",strlen ("Press to Quit"));
/*
    Label pause window as of such
*/
    XDrawString (mydisplay, pausewindow, mygc_fill, 8, 25,
		     "Press to Pause",strlen ("Press to Pause"));
/*
    Label the score window, next figure windows and statistics windows 
    accordingly.
*/
    XDrawString (mydisplay, scoresubwindow, mygc_fill, 8, 25,
		     "Number of lines",strlen ("Number of lines"));

    XDrawString (mydisplay, nextfigurewindow, mygc_fill, 8, 25,
		     "Next figure",strlen ("Next figure"));

    XDrawString (mydisplay, statwindow, mygc_fill, 65, 10,
		     "Statistics",strlen ("Statistics"));

    XDrawString (mydisplay, statwindow, mygc_fill, 18, 65,
		     "LINES",strlen ("LINES"));

    XDrawString (mydisplay, statwindow, mygc_fill, 123, 65,
		     "SQUARES",strlen ("SQUARES"));

    XDrawString (mydisplay, statwindow, mygc_fill, 18, 125,
		     "UP STAIR",strlen ("UP STAIR"));

    XDrawString (mydisplay, statwindow, mygc_fill, 123, 125,
		     "DOWN STAIR",strlen ("DOWN STAIR"));

    XDrawString (mydisplay, statwindow, mygc_fill, 18, 185,
		     "UP L",strlen ("UP L"));

    XDrawString (mydisplay, statwindow, mygc_fill, 123, 185,
		     "DOWN L",strlen ("DOWN L"));

    XDrawString (mydisplay, statwindow, mygc_fill, 18, 245,
		     "THE T",strlen ("THE T"));
/*
    Wait for the window to either click in the begin window or quit window
*/
    while (myevent.xbutton.window != beginwindow)
	{
	XNextEvent (mydisplay, &myevent);
	if (myevent.xbutton.window == quitwindow)
	    finish_program();
	}
/*
    Set up so event will take place when action takes place in the playwindow.
*/
    XSelectInput (mydisplay, playwindow,
	KeyPressMask | ButtonPressMask | StructureNotifyMask |
	ExposureMask);
/*
    Initialize game
*/
    first_time = 1;
    create_figure();
    first_time = 0;
    create_figure();
    score_bin = 0;
    put_score();
/*
    Set up the amount of time that it takes a figure do drop.
*/
    check_time = clock() + skill_level;

    while (quit != 1) /* Life time of program loop */
       {

       /* This loop will check if time to drop figure or that the user
          has lined up the figure and hit his space bar to drop immediately */

       while ((check_time > (clock())) || (decent == 1))
         {

	/* This loop checks if the user quit or has requested some event */

	while ((quit != 1) && (XEventsQueued
		(mydisplay, QueuedAlready)))
	    {
	    XNextEvent (mydisplay, &myevent);
	    switch (myevent.type)
		{
		case ConfigureNotify:
		    ++i;
		    break;
		case Expose:
		    if (myevent.xexpose.count == 0)
			{
			repaint_screen();
			}
		     break;
		case MappingNotify:
		    XRefreshKeyboardMapping ( &myevent);
		    break;
	        case KeyPress:
		    sts = XLookupString ( &myevent, text, 10, &mykey, 0);
		    if ((sts == 1) && ((text[0] == 'q') || (text[0] == 'Q')))
			{
			finish_program();
			}
		    if ((sts == 1) && (text[0] == ' '))
		        {
			if (decent == 1)
			    {
			    decent = 0;  /* Deccelerate object */
			    }
			else
			    {
			    decent = 1;  /* Accelerate object */
			    }
			}
		    break;
		case ButtonPress:
		    if (myevent.xbutton.window == pausewindow)
			{
			pause = 1;
			while (pause == 1)
			{
			XNextEvent (mydisplay, &myevent);
			switch (myevent.type)
			    {
			    case ConfigureNotify:
			    case Expose:
				if (myevent.xexpose.count == 0)
				    {
				    repaint_screen();
				    }
			    break;
			    case ButtonPress:
				if (myevent.xbutton.window == pausewindow)
				{
				    pause = 0;
				}
				break;
			    }
			XNextEvent (mydisplay, &myevent);
			}
		    }
		    if (myevent.xbutton.window == quitwindow)
			finish_program();
		    
		    if (myevent.xbutton.window == playwindow)
			{
		    	switch (myevent.xbutton.button)
			     {
			     case 1:
			         rotate_figure();
			         break;
		             case 2:
			         move_figure_left();
			         break;
			     case 3:
			         move_figure_right();
			         break;
			     } /* end if statement */
			} /* end case statement */
		} /* end case statement */
	    } /* end event queue loop */
	    if (decent == 1)
		advance_figure();
	     XFlush (mydisplay); 
	} /* end just timer loop */
	    advance_figure();
	    check_time = clock() + skill_level;
      } /* end life time loop */
    } /* end program */
/*
    Routine called to finish program.  Kind of fall off cliff because we
    are in a infinite loop.  Many would consider bad programming technique
    but this is a game so who cares.
*/
    finish_program()
    {
	XFreeGC (mydisplay, mygc_fill);
	XFreeGC (mydisplay, mygc_clear);
	XDestroyWindow (mydisplay, mainwindow);
	XCloseDisplay (mydisplay);
	exit (1);
    }
/*
    This routine is used to represent a rotate by moving bits
*/
    rotate_figure()
    {
	save_rotation = rotation;
	++rotation;
	switch (figure_type)
	{
	    case 0: /* roation or lack of for a square */
		return;
		break;
	    case 1: /* rotation for a up_l */
		switch (rotation)
		 {
		 case 2:
		    rotation_map[1] = 0 ;
		    rotation_map[2] = 3 << 7;
		    rotation_map[3] = 1 << 8;
		    rotation_map[4] = 1 << 8;
		    rotate_figure_now();
		    break;
		 case 3:
		    rotation_map[1] = 0;
		    rotation_map[2] = 0;
		    rotation_map[3] = 7 << 7;
		    rotation_map[4] = 1 << 7;
		    rotate_figure_now();
		    break;
		 case 4:
		    rotation_map[1] = 0;
		    rotation_map[2] = 1 << 7;
		    rotation_map[3] = 1 << 7;
		    rotation_map[4] = 3 << 7;
		    rotate_figure_now();
/*		    ++block_pos_x; */
		    break;
		 case 5:
		    rotation_map[1] = 0;
		    rotation_map[2] = 0;
		    rotation_map[3] = 1 << 9;
		    rotation_map[4] = 7 << 7;
		    rotation = 1;
		    rotate_figure_now();
/*		    --block_pos_x; */
		    break;
		 }
		 break;
	    case 2: /* rotation for a down_l */
		switch (rotation)
		 {
		 case 2:
		    rotation_map[1] = 0;
		    rotation_map[2] = 1 << 8;
		    rotation_map[3] = 1 << 8;
		    rotation_map[4] = 3 << 7;
		    rotate_figure_now();
		    break;
		 case 3:
		    rotation_map[1] = 0;
		    rotation_map[2] = 0;
		    rotation_map[3] = 7 << 7;
		    rotation_map[4] = 1 << 9;
		    rotate_figure_now();
		    break;
		 case 4:
		    rotation_map[1] = 0;
		    rotation_map[2] = 3 << 7;
		    rotation_map[3] = 1 << 7;
		    rotation_map[4] = 1 << 7;
		    rotate_figure_now();
		    break;
		 case 5:
		    rotation_map[1] = 0;
		    rotation_map[2] = 0;
		    rotation_map[3] = 1 << 7;
		    rotation_map[4] = 7 << 7;
		    rotation = 1;
		    rotate_figure_now();
		    break;
		 }
		 break;
	    case 3: /* rotation for a T */
		switch (rotation)
		 {
		 case 2:
		    rotation_map[1] = 0;
		    rotation_map[2] = 1 << 7;
		    rotation_map[3] = 3 << 7;
		    rotation_map[4] = 1 << 7;
		    rotate_figure_now();
		    break;
		 case 3:
		    rotation_map[1] = 0;
		    rotation_map[2] = 0;
		    rotation_map[3] = 1 << 8;
		    rotation_map[4] = 7 << 7;
		    rotate_figure_now();
		    break;
		 case 4:
		    rotation_map[1] = 0;
		    rotation_map[2] = 1 << 8;
		    rotation_map[3] = 3 << 7;
		    rotation_map[4] = 1 << 8;
		    rotate_figure_now();
		    break;
		 case 5:
		    rotation_map[1] = 0;
		    rotation_map[2] = 0;
		    rotation_map[3] = 7 << 7;
		    rotation_map[4] = 1 << 8;
		    rotation = 1;
		    rotate_figure_now();
		    break;
		 }
		 break;
	    case 4: /* rotation for a line */
		switch (rotation)
		 {
		 case 2:
		    rotation_map[1] = 1 << 7;
		    rotation_map[2] = 1 << 7;
		    rotation_map[3] = 1 << 7;
		    rotation_map[4] = 1 << 7;
		    --block_pos_x;
		    rotate_figure_now();
		    break;
		 case 3:
		    rotation_map[1] = 0;
		    rotation_map[2] = 0;
		    rotation_map[3] = 0;
		    rotation_map[4] = 15 << 7;
		    ++block_pos_x;
		    rotation = 1;
		    rotate_figure_now();
		    break;
		 }
		 break;
	    case 5: /* rotation for STAIR_U */
		switch (rotation)
		 {
		 case 2:
		    rotation_map[1] = 0;
		    rotation_map[2] = 0;
		    rotation_map[3] = 3 << 7;
		    rotation_map[4] = 3 << 8;
		    rotate_figure_now();
		    break;
		 case 3:
		    rotation_map[1] = 0;
		    rotation_map[2] = 1 << 8;
		    rotation_map[3] = 3 << 7;
		    rotation_map[4] = 1 << 7;
		    rotation = 1;
		    rotate_figure_now();
		    break;
		 }
		 break;
	    case 6: /* rotation for a STAIR_D */
		switch (rotation)
		 {
		 case 2:
		    rotation_map[1] = 0;
		    rotation_map[2] = 0;
		    rotation_map[3] = 3 << 8;
		    rotation_map[4] = 3 << 7;
		    rotate_figure_now();
		    break;
		 case 3:
		    rotation_map[1] = 0;
		    rotation_map[2] = 1 << 7;
		    rotation_map[3] = 3 << 7;
		    rotation_map[4] = 1 << 8;
		    rotation = 1;
		    rotate_figure_now();
		    break;
		 }
		 break;
             }
	return;
    }
    move_figure_right()
    {
	if ((((figure_map[4]/2) & (figure_map[4]
	    ^ screen_map[block_pos_y])) > 0) ||
	    (((figure_map[3]/2) & (figure_map[3]
	    ^ screen_map[block_pos_y-1])) > 0) ||
	    (((figure_map[2]/2) & (figure_map[2]
	    ^ screen_map[block_pos_y-2])) > 0) ||
	    (((figure_map[1]/2) & (figure_map[1]
	    ^ screen_map[block_pos_y-3])) > 0 ))
	    {
		return;
	    }
	if (((figure_map[1] & 1) > 0) ||
	    ((figure_map[2] & 1) > 0) ||
	    ((figure_map[3] & 1) > 0) ||
	    ((figure_map[4] & 1) > 0))
	    {
		return;
	    }
	clear_figure();
	for (j=1; j < 5; ++j)
	    {
	    figure_map[j] = figure_map[j] >> 1;
	    }
	draw_figure(); 
	++block_pos_x;
	return;
    }
/*
    Move the figure one square to the left
*/
#include <math.h>
    move_figure_left()
    {
	if ((((figure_map[4] * 2) & (figure_map[4]
	    ^ screen_map[block_pos_y])) > 0) ||
	    (((figure_map[3] * 2) & (figure_map[3]
	    ^ screen_map[block_pos_y-1])) > 0) ||
	    (((figure_map[2] * 2) & (figure_map[2]
	    ^ screen_map[block_pos_y-2])) > 0) ||
	    (((figure_map[1] * 2) & (figure_map[1]
	    ^ screen_map[block_pos_y-3])) > 0 ))
	    {
		return;
	    }
	if (((figure_map[1] & 0x8000) > 0) ||
	    ((figure_map[2] & 0x8000) > 0) ||
	    ((figure_map[3] & 0x8000) > 0) ||
	    ((figure_map[4] & 0x8000) > 0))
	    {
		return;
	    }
	clear_figure();
	for (j=1; j < 5; ++j)
	    {
	    figure_map[j] = figure_map[j] * 2;
	    }
	draw_figure(); 
	--block_pos_x;
	return;
    }
    create_figure()
    {
	random_number = (random() % 7 );
	figure_map[1] = 0;
	figure_map[2] = 0;
	figure_map[3] = 0;
	figure_map[4] = 0;
	switch (random_number)
	{
	    case 0:
		draw_square();
		figure_type = 0;
		break;
	    case 1:
		draw_up_l();
		figure_type = 1;
		break;
	    case 2:
		draw_down_l();
		figure_type = 2;
		break;
	    case 3:
		draw_t();
		figure_type = 3;
		break;
	    case 4:
		draw_line();
		figure_type = 4;
		break;
	    case 5:
		draw_stairs_u();
		figure_type = 5;
		break;
	    case 6:
		draw_stairs_d();
		figure_type = 6;
		break;
        }
	save_next_figure_type = next_figure_type;
	next_figure_type = figure_type;
	figure_type = save_next_figure_type;
	save_next_figure_map[1] = next_figure_map[1];
	save_next_figure_map[2] = next_figure_map[2];
	save_next_figure_map[3] = next_figure_map[3];
	save_next_figure_map[4] = next_figure_map[4];
	next_figure_map[1] = figure_map[1];
	next_figure_map[2] = figure_map[2];
	next_figure_map[3] = figure_map[3];
	next_figure_map[4] = figure_map[4];
	figure_map[1] = save_next_figure_map[1];
	figure_map[2] = save_next_figure_map[2];
	figure_map[3] = save_next_figure_map[3];
	figure_map[4] = save_next_figure_map[4];
	block_pos_y = 2;
	statistics();
	if (first_time !=1)
	    {
	    draw_next_figure();
	    draw_figure();
	    }
	decent = 0;
   }
   draw_square()
        {
	figure_map[1] = 0;
	figure_map[2] = 0;
	figure_map[3] = 3 << 7;
	figure_map[4] = 3 << 7;
	block_pos_x = 7;
	check_if_game_ends();
	rotation = 1;
	return;
	}
    draw_up_l()
	{
	figure_map[1] = 0;
	figure_map[2] = 0;
	figure_map[3] = 1 << 9;
	figure_map[4] = 7 << 7;
	block_pos_x = 7;
	check_if_game_ends();
	rotation = 1;
	return;
	}
   draw_down_l()
	{
	figure_map[1] = 0;
	figure_map[2] = 0;
	figure_map[3] = 1 << 7;
	figure_map[4] = 7 << 7;
	block_pos_x = 7;
	check_if_game_ends();
	rotation = 1;
	return;
	}
   draw_t()
	{
	figure_map[1] = 0;
	figure_map[2] = 0;
	figure_map[3] = 1 << 8;
	figure_map[4] = 7 << 7;
	block_pos_x = 7;
	check_if_game_ends();
	rotation = 1;
	return;
	}
   draw_line()
	{
	figure_map[1] = 0;
	figure_map[2] = 0;
	figure_map[3] = 0;
	figure_map[4] = 15 << 6;
	block_pos_x = 8;
	check_if_game_ends();
	rotation = 1;
	return;
	}
   draw_stairs_u()
	{
	figure_map[1] = 0;
	figure_map[2] = 1 << 8;
	figure_map[3] = 3 << 7;
	figure_map[4] = 1 << 7;
	check_if_game_ends();
	block_pos_x = 7;
	rotation = 1;
	return;
	}
   draw_stairs_d()
	{
	figure_map[1] = 0;
	figure_map[2] = 1 << 7;
	figure_map[3] = 3 << 7;
	figure_map[4] = 1 << 8;
	block_pos_x = 7;
	check_if_game_ends();
	rotation = 1;
	return;
	}
   advance_figure()
	{
	if (block_pos_y == 17)
	    {
	    check_for_scoring();
	    create_figure();
	    decent_speed = saved_decent_speed;
	    return;
	    }   
	if (((figure_map[1] & ((figure_map[2] 
	    ^ screen_map[block_pos_y-2]) & screen_map[block_pos_y-2])) > 0) ||
	    ((figure_map[2] & ((figure_map[3]
	    ^ screen_map[block_pos_y-1]) & screen_map[block_pos_y-1])) > 0) ||
	    ((figure_map[3] & ((figure_map[4]
	    ^ screen_map[block_pos_y]) & screen_map[block_pos_y])) > 0) ||
	    ((figure_map[4] & screen_map[block_pos_y+1]) > 0))
	    {
	    check_for_scoring();
	    create_figure();
	    decent_speed = saved_decent_speed;
	    return;
	    }
	clear_figure(); /* this will clear screen map and figure */
	++block_pos_y;
	draw_figure(); /* this will update screen map */
	}
/*
    Routine to clear screen map and X Window screen of figure
*/
    clear_figure()
	{
	    screen_map[block_pos_y] = figure_map[4] ^
				    screen_map[block_pos_y];
	    screen_map[block_pos_y-1] = figure_map[3] ^
				    screen_map[block_pos_y-1];
	    screen_map[block_pos_y-2] = figure_map[2] ^
				    screen_map[block_pos_y-2];
	    screen_map[block_pos_y-3] = figure_map[1] ^
				    screen_map[block_pos_y-3];
	    for (j=1; j < 5; ++j)
		{
		for (i=0; i < 16; ++i)
		    {
		    if ((figure_map[j] & (1  << i)) > 0)
			{
			if (block_pos_y > 2) 
			   {
			   XFillRectangle (mydisplay, playwindow,
				mygc_clear,
				(play_screen_size - (i * block_size + 
				    block_size)),
				(block_size * ((block_pos_y - 2) - (4-j))),
				block_size,
				block_size);
			   }
			}
		    }
                }
	    return;
	}
/*
    Routine to draw figure on X Window display as specified in figure map
*/
    draw_figure()
	{
	    screen_map[block_pos_y] = figure_map[4] |
				    screen_map[block_pos_y];
	    screen_map[block_pos_y-1] = figure_map[3] |
				    screen_map[block_pos_y-1];
	    screen_map[block_pos_y-2] = figure_map[2] |
				    screen_map[block_pos_y-2];
	    screen_map[block_pos_y-3] = figure_map[1] |
				    screen_map[block_pos_y-3];
	    for (j=1; j < 5; ++j)
		{
		for (i=0; i < 16; ++i)
		    {
		    if ((figure_map[j] & (1  << i)) > 0)
			{
			if (block_pos_y > 2) 
			    {
			    XFillRectangle (mydisplay, playwindow,
				mygc_fill,
				(play_screen_size - (i * block_size
				    + block_size)),
				(block_size * ((block_pos_y - 2) - (4-j))),
				block_size,
				block_size);
			     }
			}
		    }
                }
	    return;
	}
check_if_game_ends()
    {
	if (((figure_map[4] & screen_map[4]) > 0) ||
	    ((figure_map[3] & screen_map[3]) > 0) ||
	    ((figure_map[2] & screen_map[2]) > 0) ||
	    ((figure_map[1] & screen_map[1]) > 0))
	    {
		game_ends();
	    }
	return;
    }
game_ends()
    {
        while (myevent.xbutton.window != quitwindow)
	   {
	   XNextEvent (mydisplay, &myevent);
	   }
        finish_program();
	return;
    }
check_for_scoring()
    {
    int ii;
    int jj;
	for (ii=1; ii < 18; ++ii)
	    {
	    if (screen_map[ii] == 0xffff)
		{
		++score_bin;
		put_score();
		for (jj=ii; jj > 0; -- jj)
		    {
		    screen_map[jj] = screen_map[jj-1];
		    }
		    screen_map[1] = 0;
		    XCopyArea (mydisplay, playwindow, playwindow, mygc_fill,
			 0, 0, 
			 play_screen_size,
			 ((ii-2) * block_size), 0, block_size);
/*
	            XClearArea (mydisplay, playwindow, 0, 0, play_screen_size,
				block_size);
*/
	            --ii;
	        }
	     }
      }
put_score()
    {
    int		    score_tmp;
    int		    score_mod;
    score_tmp = score_bin/10;
    skill_level = skill_level_input - (score_tmp * 10);
    score_tmp = score_bin;
    for (j=0; j < 5; ++j)
	{
	score_mod = score_tmp % 10;
	score[4-j] = 48 + score_mod;
	score_tmp = score_tmp / 10;
	}
/*
    XClearArea (mydisplay, scoresubwindow, 10, 35, 20,
				20);
*/
    XDrawImageString (mydisplay, scoresubwindow, mygc_fill, 14, 45,
		     score,5);
    
    }
rotate_figure_now()	
    {
    if (block_pos_x < 7)
	{
	rotation_map[1] = rotation_map[1] << (8-block_pos_x);
	rotation_map[2] = rotation_map[2] << (8-block_pos_x);
	rotation_map[3] = rotation_map[3] << (8-block_pos_x);
	rotation_map[4] = rotation_map[4] << (8-block_pos_x);
	}
    else
	{
	rotation_map[1] = rotation_map[1] >> (block_pos_x - 8);
	rotation_map[2] = rotation_map[2] >> (block_pos_x - 8);
	rotation_map[3] = rotation_map[3] >> (block_pos_x - 8);
	rotation_map[4] = rotation_map[4] >> (block_pos_x - 8);
	}
    check_valid_rotation();
    if (rotation_valid == 1)
	{
	clear_figure();
	figure_map[1] = (rotation_map[1]/2);
	figure_map[2] = (rotation_map[2]/2);
	figure_map[3] = (rotation_map[3]/2);
	figure_map[4] = (rotation_map[4]/2);
	draw_figure();
	}
    else
	{
	rotation = save_rotation;
	}
    return;
    }
check_valid_rotation()
    {
	if (((((rotation_map[4]/2)) & (figure_map[4]
	    ^ screen_map[block_pos_y])) > 0) ||
	    ((((rotation_map[3]/2)) & (figure_map[3]
	    ^ screen_map[block_pos_y-1])) > 0) ||
	    ((((rotation_map[2]/2)) & (figure_map[2]
	    ^ screen_map[block_pos_y-2])) > 0) ||
	    ((((rotation_map[1]/2)) & (figure_map[1]
	    ^ screen_map[block_pos_y-3])) > 0 ))
	    {
		rotation_valid = 0;
		return;
	    }
	if (((rotation_map[1] & 1) > 0) ||
	    ((rotation_map[2] & 1) > 0) ||
	    ((rotation_map[3] & 1) > 0) ||
	    ((rotation_map[4] & 1) > 0))
	    {
		rotation_valid = 0;
		return;
	    }
	if ((rotation_map[1] > 0x20000) ||
	    (rotation_map[2] > 0x20000) ||
	    (rotation_map[3] > 0x20000) ||
	    (rotation_map[4] > 0x20000))
	    {
		rotation_valid = 0;
		return;
	    }
	    rotation_valid = 1;
     }	
repaint_screen()
    {    
    for (j=0; j < 16; ++j)
	{
	for (i=0; i < 16; ++i)
		{
		if ((screen_map[j] & (1  << i)) > 0)
			{
			XFillRectangle (mydisplay, playwindow,
				mygc_fill,
				(play_screen_size - (i * block_size
				    + block_size)),
				(block_size * (j)),
				block_size,
				block_size);
			} /* end if */
		 }
        }
     XDrawString (mydisplay, beginwindow, mygc_fill, 8, 25,
		     "Press to Begin",strlen("Press to Begin"));
/*
    Label quit window as of such
*/
     XDrawString (mydisplay, quitwindow, mygc_fill, 8, 25,
		     "Press to Quit",strlen ("Press to Quit"));
/*
    Label pause window as of such
*/
     XDrawString (mydisplay, pausewindow, mygc_fill, 8, 25,
		     "Press to Pause",strlen ("Press to Pause"));

     XDrawString (mydisplay, scoresubwindow, mygc_fill, 8, 25,
		     "Number of lines",strlen ("Number of lines"));
     put_score();
     pause = 0;
     return;
     }
     draw_next_figure()
     {
     int    first;
     int    next_pos;
     first = 1;
     XFillRectangle (mydisplay, nextfigurewindow,
		mygc_clear,
		0,
		30,
		100,
		80);
     for (j=1; j < 5; ++j)
	{
	for (i=0; i < 16; ++i)
	    {
	    if ((next_figure_map[j] & (1  << i)) > 0)
		{
		if (first == 1)
		    {
		    next_pos = i;
		    first = 0;
		    }

		    XFillRectangle (mydisplay, nextfigurewindow,
			mygc_fill,
			(30 + ((next_pos-i)  * (block_size/3))),
			(25 + j * (block_size/3)),
			block_size/3,
			block_size/3);
		}
	    }
	}
	return;
     }
statistics ()
	{
    int		    score_tmp;
    int		    score_mod;
	switch (random_number)
	{
	    case 0:
		++square;
		score_tmp = square;
		for (j=0; j < 5; ++j)
		{
		score_mod = score_tmp % 10;
		score[4-j] = 48 + score_mod;
		score_tmp = score_tmp / 10;
		}
		XDrawImageString (mydisplay, statwindow, 
		    mygc_fill, 125, 85, score, 5);

		break;
	    case 1:
		++up_l;
		score_tmp = up_l;
		for (j=0; j < 5; ++j)
		{
		score_mod = score_tmp % 10;
		score[4-j] = 48 + score_mod;
		score_tmp = score_tmp / 10;
		}
		XDrawImageString (mydisplay, statwindow, 
		    mygc_fill, 20, 215, score, 5);

		break;
	    case 2:
		++down_l;
		score_tmp = down_l;
		for (j=0; j < 5; ++j)
		{
		score_mod = score_tmp % 10;
		score[4-j] = 48 + score_mod;
		score_tmp = score_tmp / 10;
		}
		XDrawImageString (mydisplay, statwindow, 
		    mygc_fill, 125, 215, score, 5);

		break;
	    case 3:
		++t;
		score_tmp = t;
		for (j=0; j < 5; ++j)
		{
		score_mod = score_tmp % 10;
		score[4-j] = 48 + score_mod;
		score_tmp = score_tmp / 10;
		}
		XDrawImageString (mydisplay, statwindow, 
		    mygc_fill, 20, 265, score, 5);

		break;
	    case 4:
		++line;
		score_tmp = line;
		for (j=0; j < 5; ++j)
		{
		score_mod = score_tmp % 10;
		score[4-j] = 48 + score_mod;
		score_tmp = score_tmp / 10;
		}
		XDrawImageString (mydisplay, statwindow, 
		    mygc_fill, 20, 85, score, 5);

	        break;
	    case 5:
		++up_stairs;
		score_tmp = up_stairs;
		for (j=0; j < 5; ++j)
		{
		score_mod = score_tmp % 10;
		score[4-j] = 48 + score_mod;
		score_tmp = score_tmp / 10;
		}
		XDrawImageString (mydisplay, statwindow, 
		    mygc_fill, 20, 145, score, 5);

	        break;
	    case 6:
		++down_stairs;
		score_tmp = down_stairs;
		for (j=0; j < 5; ++j)
		{
		score_mod = score_tmp % 10;
		score[4-j] = 48 + score_mod;
		score_tmp = score_tmp / 10;
		}
		XDrawImageString (mydisplay, statwindow, 
		    mygc_fill, 125, 145, score, 5);

	        break;
	    }
         }

#define	    MULTIPLIER	25173
#define	    MODULUS     65526
#define     INCREMENT   13849
 
random()
	{
	    static int random_first_time = 1;

	    if (random_first_time)
	    {
		seed = clock() % 17;
            }
	    else
	    {		
		seed = (MULTIPLIER * seed + INCREMENT) % 65526;
	    }
	    random_first_time = 0;
	    return (seed);
	}
