DataMuseum.dk

Presents historical artifacts from the history of:

DKUUG/EUUG Conference tapes

This is an automatic "excavation" of a thematic subset of
artifacts from Datamuseum.dk's BitArchive.

See our Wiki for more about DKUUG/EUUG Conference tapes

Excavated with: AutoArchaeologist - Free & Open Source Software.


top - metrics - download
Index: T s

⟦956e7ed9f⟧ TextFile

    Length: 9581 (0x256d)
    Types: TextFile
    Names: »suntetris.c«

Derivation

└─⟦b20c6495f⟧ Bits:30007238 EUUGD18: Wien-båndet, efterår 1987
    └─⟦this⟧ »EUUGD18/Sun/Suntetris/suntetris.c« 

TextFile

#ifndef lint
static char sccsid[] = "@(#)suntetris.c	1.17 3/23/89";
#endif

/*
 *  Copyright 1989, Rick Iwamoto iwamoto@sun.com
 *  Permission is given to copy and distribute for non-profit purposes.
 */

#include <stdio.h>
#include <suntool/sunview.h>
#include <suntool/canvas.h>
#include "suntetris.h"

static short icon_image[] = {
#include "suntetris.icon"
};
DEFINE_ICON_FROM_IMAGE (tetris_icon, icon_image);

Canvas canvas;

static int my_client_object;
static int *me = &my_client_object;
static int paused = 0, selht = 0, height = 0;
static int level, lines, score, make_new_fig;
static int current_color, current_fig, current_rot, current_x, current_y;
static struct itimerval timer;

void init_pw (), draw_board (), rand_blocks (), draw_figure (), draw_score ();
void close_board (), display_choices (), display_hs (), update_hs ();
void select_level (), select_height ();
void mark_board ();
int safe_move ();

static Notify_value figure_dropper ();
static void new_figure (), place_figure ();
static void game_setup (), start_game (), game_over (), drop_down ();
static void start_timer (), stop_timer ();
static void game_control_proc (), choose_level ();
static void choose_height (), wait_for_return ();


/*
    4 canvas input event routines

    1) choose_level ()
	player chooses level to start at
    2) choose_height ()
	player chooses height to start at
    3) game_control_proc ()
	game controls (move blocks around etc.)
    4) wait_for_return ()
	game waits for player to hit return while displaying highscores
*/

main (argc, argv)
int argc;
char **argv;
{
    Frame frame;

    frame = window_create (0, FRAME,
		FRAME_LABEL, argv[0],
		FRAME_ICON, &tetris_icon,
	    0);
    canvas = window_create (frame, CANVAS,
		 CANVAS_RETAINED, FALSE,
		 WIN_WIDTH, 400,
		 WIN_HEIGHT, 400,
		 WIN_CONSUME_PICK_EVENT, WIN_IN_TRANSIT_EVENTS,
		 WIN_CONSUME_KBD_EVENTS, WIN_ASCII_EVENTS, WIN_RIGHT_KEYS, 0,
	     0);
    window_fit (frame);
    init_pw (argc > 1);	/* force b&w operation if any arguments exist */
    window_set (canvas, CANVAS_RETAINED, TRUE, 0);
    srandom (getpid ());

    game_setup ();
    window_main_loop (frame);
}


/* figure_dropper does the periodic downward moving of the figures */
static Notify_value
figure_dropper (me, which)
Notify_client me;
int which;
{
    /* if next position is unoccupied, move the figure down by 1 */
    if (safe_move (current_fig, current_rot, current_x, current_y+1))  {
	draw_figure (current_fig, current_rot, current_x*BLOCKSIZE+BOARD_X,
		     current_y*BLOCKSIZE+BOARD_Y, BLACK);
	current_y++;
	draw_figure (current_fig, current_rot, current_x*BLOCKSIZE+BOARD_X,
		     current_y*BLOCKSIZE+BOARD_Y, current_color);
    }
    else if (current_y < 0)  game_over ();	/* all over when at the top */
    else if (make_new_fig)  {
	make_new_fig = 0;
	place_figure ();	/* the figure comes to rest */
	new_figure ();		/* start a new one */
    }
    else  {
	make_new_fig = 1;
    }
}


/* drop_down drops the figure down as far as it can go without hitting
   other blocks along the way */
static void
drop_down ()
{
    int new_y = current_y;

    while (safe_move (current_fig, current_rot, current_x, new_y+1))  new_y++;
    if (new_y < 0)  {
	game_over ();
	return;
    }
    score += BOARDHEIGHT-(current_y+2);	/* bonus for dropping */
    draw_figure (current_fig, current_rot, current_x*BLOCKSIZE+BOARD_X,
		 current_y*BLOCKSIZE+BOARD_Y, BLACK);
    current_y = new_y;
    draw_figure (current_fig, current_rot, current_x*BLOCKSIZE+BOARD_X,
		 current_y*BLOCKSIZE+BOARD_Y, current_color);
    place_figure ();	/* rest the figure */
    new_figure ();	/* start a new one */
}


static void
game_over ()
{
    stop_timer ();
    window_set (canvas, WIN_EVENT_PROC, wait_for_return, 0);
    close_board ();
    update_hs (score, level);
    display_hs ();
}


/* this select delay stuff doesn't work all that well, but it's sufficient */
static struct timeval delay_1sec = { 0, 999999 };

/* place the figure at its resting spot, update scores, do any reducing
   of rows */
static void
place_figure ()
{
    stop_timer ();
    score += 2*level + BOARDHEIGHT-(current_y+2) + 5;
    mark_board (current_fig, current_rot, current_x, current_y);
    lines += reduce_rows (current_y);
    if (level < MAXLEVEL && lines > 10*(level+1))  {
	level++;	/* should pause for a sec */
	select (1, 0, 0, 0, &delay_1sec);
    }
    draw_score (lines, score, level);
    if (!paused)  start_timer ();
}


/* new_figure generates a new random figure */
static void
new_figure ()
{
    current_x = 3;
    current_y = -1;
    current_rot = 0;
    current_fig = random () % 7;
    current_color = current_fig + 1;
    draw_figure (current_fig, current_rot, current_x*BLOCKSIZE+BOARD_X,
		 current_y*BLOCKSIZE+BOARD_Y, current_color);
}


/*
 * The cursor left (R10), 'j', and the left mouse button cause the block to
 * move left.  R11, 'k', and the middle mouse button cause the block to
 * rotate counter-clockwise.  The cursor right (R12), 'l', and the right
 * mouse button cause the block to move right.  The cursor down (R14) and
 * the spacebar cause the block to drop down to the bottom.
 * The Cursor keys must not be emitting escape sequences (SunView Defaults)
 */
static void
game_control_proc (canvas, event)
Canvas canvas;
Event *event;
{
    int new_x = current_x;
    int new_rot = current_rot;

    if (event_is_button (event) && event_is_up (event))  return;
    switch (event_id (event))  {
	case 'q':
	    exit (0);
	case MS_LEFT:
	case 'j':
	case KEY_RIGHT(10):	/* LEFT */
	    new_x = current_x - 1;
	    break;
	case MS_MIDDLE:
	case 'k':
	case KEY_RIGHT(11):	/* ROTATE */
	    new_rot = (current_rot + 1) % 4;
	    break;
	case MS_RIGHT:
	case 'l':
	case KEY_RIGHT(12):	/* RIGHT */
	    new_x = current_x + 1;
	    break;
	case ' ':
	case KEY_RIGHT(14):	/* DOWN */
	    drop_down ();
	    return;
	    break;
	case 'u':
	case KEY_RIGHT(8):	/* UP LEVEL */
	    if (level < MAXLEVEL)  {
		level++;
		stop_timer ();
		select (1, 0, 0, 0, &delay_1sec);
		draw_score (lines, score, level);
		start_timer ();
	    }
	    return;
	    break;
	case LOC_WINENTER:
	case LOC_RGNENTER:
	    start_timer ();
	    paused = 0;
	    return;
	case LOC_WINEXIT:
	case LOC_RGNEXIT:
	    stop_timer ();
	    paused = 1;
	    return;
	default:
	    return;
	    break;
    }
    if (safe_move (current_fig, new_rot, new_x, current_y))  {
	draw_figure (current_fig, current_rot, current_x*BLOCKSIZE+BOARD_X,
		     current_y*BLOCKSIZE+BOARD_Y, BLACK);
	current_rot = new_rot;
	current_x = new_x;
	draw_figure (current_fig, current_rot, current_x*BLOCKSIZE+BOARD_X,
		     current_y*BLOCKSIZE+BOARD_Y, current_color);
    }
}


#define ITIMER_NULL ((struct itimerval *) 0)

static void
start_timer ()
{
    timer.it_interval.tv_usec = (11-level)*50000;
    timer.it_interval.tv_sec = 0;
    timer.it_value.tv_usec = (11-level)*50000;
    timer.it_value.tv_sec = 0;
    (void) notify_set_itimer_func (me, figure_dropper,
	ITIMER_REAL, &timer, ITIMER_NULL);
}


static void
stop_timer ()
{
    /* turn off timer */
    notify_set_itimer_func (me, figure_dropper, ITIMER_REAL, ITIMER_NULL,
	ITIMER_NULL);
}


static void
start_game ()
{
    lines = 0;
    score = 0;
    make_new_fig = 0;
    draw_board ();
    draw_score (lines, score, level);
    rand_blocks (height);
    window_set (canvas, WIN_EVENT_PROC, game_control_proc, 0);
    new_figure ();
    start_timer ();
}


static void
choose_level (canvas, event)
Canvas canvas;
Event *event;
{
    switch (event_id (event))  {
	case '0':
	case '1':
	case '2':
	case '3':
	case '4':
	case '5':
	case '6':
	case '7':
	case '8':
	case '9':
	    select_level (level);
	    level = event_id (event) - '0';
	    select_level (level);
	    break;
	case 'q':
	    exit (0);
	case 'h':
	case KEY_RIGHT(10):	/* LEFT */
	    select_level (level);
	    level = (level + 9) % 10;
	    select_level (level);
	    break;
	case 'l':
	case KEY_RIGHT(12):	/* RIGHT */
	    select_level (level);
	    level = (level + 1) % 10;
	    select_level (level);
	    break;
	case 'k':
	case KEY_RIGHT(8):	/* UP */
	case 'j':
	case KEY_RIGHT(14):	/* DOWN */
	    select_level (level);
	    level = (level + 5) % 10;
	    select_level (level);
	    break;
	case '\015':		/* RETURN */
	    selht = 0;
	    select_height (selht);
	    window_set (canvas, WIN_EVENT_PROC, choose_height, 0);
	    break;
    }
}


static void
choose_height (canvas, event)
Canvas canvas;
Event *event;
{
    switch (event_id (event))  {
	case 'q':
	    exit (0);
	case 'h':
	case KEY_RIGHT(10):	/* LEFT */
	    select_height (selht);
	    selht = (selht + 5) % 6;
	    select_height (selht);
	    break;
	case 'l':
	case KEY_RIGHT(12):	/* RIGHT */
	    select_height (selht);
	    selht = (selht + 1) % 6;
	    select_height (selht);
	    break;
	case 'k':
	case KEY_RIGHT(8):	/* UP */
	case 'j':
	case KEY_RIGHT(14):	/* DOWN */
	    select_height (selht);
	    selht = (selht + 3) % 6;
	    select_height (selht);
	    break;
	case '\015':		/* RETURN */
	    switch (selht)  {
		case 0: height = 0; break;
		case 1: height = 4; break;
		case 2: height = 7; break;
		case 3: height = 10; break;
		case 4: height = 13; break;
	    }
	    start_game ();
	    break;
    }
}


static void
wait_for_return (canvas, event)
Canvas canvas;
Event *event;
{
    switch (event_id (event))  {
	case 'q':  exit (0);
	case '\015':
	    game_setup ();
	    break;
    }
}

	    
static void
game_setup ()
{
    display_choices ();
    window_set (canvas, WIN_EVENT_PROC, choose_level, 0);
    level = 5;
    select_level (level);
}