home *** CD-ROM | disk | FTP | other *** search
- Path: uunet!ssbell!kent@ssbell.uu.net
- From: kent@ssbell.uu.net (Kent Landfield)
- Newsgroups: comp.sources.x
- Subject: v05i048: golddig2 -- A game for X11, Part04/04
- Message-ID: <597@ssbell.uu.net>
- Date: 14 Dec 89 03:18:58 GMT
- Sender: kent@ssbell.uu.net
- Lines: 592
- Approved: kent@ssbell.uu.net (Kent Landfield)
-
- Submitted-by: Alexander Siegel <siegel@cs.cornell.edu>
- Posting-number: Volume 5, Issue 48
- Archive-name: golddig2/part04
-
- #! /bin/sh
- # This is a shell archive. Remove anything before this line, then unpack
- # it by saving it into a file and typing "sh file". To overwrite existing
- # files, type "sh file -c". You can also feed this as standard input via
- # unshar, or by typing "sh <file", e.g.. If this archive is complete, you
- # will see the following message at the end:
- # "End of archive 4 (of 4)."
- # Contents: golddig2/golddig.c
- # Wrapped by kent@ssbell on Wed Dec 13 20:37:02 1989
- PATH=/bin:/usr/bin:/usr/ucb ; export PATH
- if test -f 'golddig2/golddig.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'golddig2/golddig.c'\"
- else
- echo shar: Extracting \"'golddig2/golddig.c'\" \(17923 characters\)
- sed "s/^X//" >'golddig2/golddig.c' <<'END_OF_FILE'
- X/* This program was written by Alexander Siegel in September of 1989 */
- X/* at Cornell University. It may may copied freely for private use or */
- X/* public dispersion provided that this comment is not removed. This */
- X/* program, any portion of this program, or any derivative of this */
- X/* program may not be sold or traded for financial gain. */
- X
- X/* Modified by Josh Siegel to work with NeWS/X11 */
- X
- X#include <stdio.h>
- X#include <X11/Xlib.h>
- X#include <X11/keysym.h>
- X#include <X11/Xutil.h>
- X#include <sys/time.h>
- X#include <signal.h>
- X#include "golddig.h"
- X
- Xextern char player_bits[];
- X#include "bitmap/fly.bits"
- X#include "bitmap/hang1.bits"
- X#include "bitmap/hang2.bits"
- X#include "bitmap/up1.bits"
- X#include "bitmap/up2.bits"
- X#include "bitmap/left1.bits"
- X#include "bitmap/left2.bits"
- X#include "bitmap/right1.bits"
- X#include "bitmap/right2.bits"
- X
- Xlong random();
- X
- X#define EVMASK KeyPressMask | ExposureMask | ButtonPressMask | FocusChangeMask
- X
- Xint newlevel = 0; /* Non-zero if a new level was just drawn */
- Xstruct itimerval cycletime; /* Structure used when setting up timer */
- X/* These are the graphics cursors used for drawing the player at */
- X/* various times. */
- XGC standgc,flygc,hang1gc,hang2gc,up1gc,up2gc;
- XGC left1gc,left2gc,right1gc,right2gc;
- X
- Xenum directs curorder = STAND; /* Current order which player has */
- X /* typed at the keyboard. */
- X
- X/* Plug into original block type definitions in shared.c */
- Xextern struct symbs_s symbs[];
- Xextern int numholes; /* Total number of holes */
- X
- X/* This routine is called whenever the player dies. */
- Xvoid died(whydie)
- Xchar *whydie; /* Textual description of reason for death */
- X{
- X /* Prevent timer from firing inside of sleep */
- X cycletime.it_value.tv_sec = cycletime.it_interval.tv_sec = 10;
- X setitimer(ITIMER_REAL,&cycletime,(struct itimerval *) NULL);
- X signal(SIGALRM,SIG_DFL); /* Turn off timer signal */
- X XSync(disp,False); /* Synchronize with display */
- X if(strcmp(whydie,"was abandoned"))
- X sleep(2); /* Pause for 2 seconds to let player */
- X /* see situation */
- X xend(); /* Terminate X windows */
- X /* Add score to high score list */
- X add_score(whydie);
- X exit(0);
- X}
- X
- X/* Redraw the player. The graphics cursors all use the GXor function */
- X/* so they will not erase what is underneath. */
- Xvoid draw_player()
- X{
- X GC drawgc;
- X register int lpos,code;
- X
- X /* Get position of level array of player */
- X lpos = (player.xpos >> 1)*ysize + (player.ypos >> 1);
- X /* Get the control code describing block underneath player */
- X code = fast_lookup[level[lpos]].code;
- X /* If the block is inactive, use the code for empty space */
- X if((code & INACTIVE) && goldleft > 0)
- X code = fast_lookup[SPACE].code;
- X
- X /* Compute the graphics cursor appropriate to the player's current */
- X /* state */
- X drawgc = NULL;
- X /* Check if player is hanging from a rope */
- X if((player.ypos & 1) == 0) {
- X if((code & DLEAVE) && ! (code & (ULEAVE | DFALL))) {
- X if(player.xpos & 1)
- X drawgc = hang2gc;
- X else
- X drawgc = hang1gc;
- X }
- X }
- X else if((player.ypos & 1) && (code & DFALL))
- X drawgc = flygc;
- X
- X if(drawgc == NULL)
- X switch(player.dir) {
- X case UP: case DOWN:
- X if(player.ypos & 1)
- X drawgc = up2gc;
- X else
- X drawgc = up1gc;
- X break;
- X case LEFT:
- X if(player.xpos & 1)
- X drawgc = left2gc;
- X else
- X drawgc = left1gc;
- X break;
- X case RIGHT:
- X if(player.xpos & 1)
- X drawgc = right2gc;
- X else
- X drawgc = right1gc;
- X break;
- X case STAND:
- X if(code & ULEAVE)
- X drawgc = up1gc;
- X else
- X drawgc = standgc;
- X break;
- X default:
- X drawgc = standgc;
- X }
- X /* Fill the rectangle surrounding the player with the chosen */
- X /* graphics cursor. */
- X if(drawgc != NULL)
- X XFillRectangle(disp,wind,drawgc,player.xpos << 3,player.ypos << 3,16,16);
- X}
- X
- X/* Erase the player by redrawing the block(s) underneath him */
- Xvoid drawmove_player()
- X{
- X register int x,y;
- X
- X /* Do not erase redraw player if it is not nessary */
- X if(! player.redraw)
- X return;
- X /* Draw block covering at least half of player */
- X x = player.xold;
- X y = player.yold;
- X draw_block(x >> 1,y >> 1);
- X /* If player is offset horizontally, redraw block to the right */
- X if(x & 1)
- X draw_block((x >> 1) + 1,y >> 1);
- X /* If player is offset vertically, redraw block below */
- X if(y & 1)
- X draw_block(x >> 1,(y >> 1) + 1);
- X
- X draw_player();
- X}
- X
- X/* Handle a key stroke by the user. */
- Xvoid handle_key(keyhit)
- XKeySym keyhit; /* Key symbol for key stroke provided by X windows */
- X{
- X /* Now that a key is hit, really begin the level */
- X newlevel = 0;
- X /* Do action depending on which key was hit */
- X switch(keyhit) {
- X /* If it is a 'h', '?', or '/', print out a list of commands */
- X case XK_H: case XK_h: case XK_question: case XK_slash:
- X puts("Control the player using keyboard keys or the mouse.");
- X puts("<space>,R11 - stop");
- X puts("a,j,left arrow - move left");
- X puts("d,l,right arrow - move right");
- X puts("w,i,up arrow - move up");
- X puts("s,k,down arrow - move down");
- X puts("z,<,q,u,R13 - make hole left");
- X puts("x,>,e,o,R15 - make hole right");
- X puts("r,y,R7 - put down any held item");
- X puts("1-9 - change the game speed");
- X puts("\n^S,^Z - pause the game");
- X puts("^Q,^Y - reactivate the game");
- X puts("^C - kill the game");
- X puts("^R - redraw the screen");
- X break;
- X /* A space bar changes the command to STAND */
- X case XK_space: case XK_R11:
- X curorder = STAND; break;
- X /* A 'z', ',', '<', 'q', or 'u' digs holes to the left */
- X case XK_Z: case XK_comma: case XK_less: case XK_Q: case XK_U:
- X case XK_R13: case XK_z: case XK_q: case XK_u:
- X curorder = DIGLEFT; break;
- X /* A 'x', '.', '>', 'e', or 'o' digs holes to the right */
- X case XK_X: case XK_period: case XK_greater: case XK_E: case XK_O:
- X case XK_R15: case XK_x: case XK_e: case XK_o:
- X curorder = DIGRIGHT; break;
- X /* A 'j' or 'a' changes the command to LEFT */
- X case XK_J: case XK_A: case XK_Left: case XK_j: case XK_a:
- X curorder = LEFT; break;
- X /* A 'i' or 'w' changes the command to UP */
- X case XK_I: case XK_W: case XK_Up: case XK_i: case XK_w:
- X curorder = UP; break;
- X /* A 'k' or 's' changes the command to DOWN */
- X case XK_K: case XK_S: case XK_Down: case XK_k: case XK_s:
- X curorder = DOWN; break;
- X /* A 'l' or 'd' changes the command to RIGHT */
- X case XK_L: case XK_D: case XK_Right: case XK_l: case XK_d:
- X curorder = RIGHT; break;
- X /* A 'r' or 'y' drops whatever is being held */
- X case XK_R: case XK_Y: case XK_R7: case XK_r: case XK_y:
- X curorder = PUTDOWN; break;
- X }
- X}
- X
- X/* Redraw everything. This routine is called whenever something major */
- X/* changes or the window is exposed. */
- Xvoid redrawall()
- X{
- X draw_level();
- X draw_player();
- X draw_badguys();
- X XFlush(disp);
- X}
- X
- X/* Initialize a level from the current level file */
- Xvoid init_level()
- X{
- X register int x,y,pos;
- X
- X /* Allow level sizes to be changes by new level */
- X xsize = ysize = -1;
- X /* Load the level data itself from the data file. */
- X load_level();
- X numholes = 0;
- X
- X /* Initialize player information */
- X player.xpos = player.ypos = player.xstart = player.ystart = goldleft = 0;
- X player.dir = STAND;
- X player.hold = SPACE;
- X curorder = STAND;
- X pos = 0;
- X for(x=0;x<xsize;++x)
- X for(y=0;y<ysize;++y) {
- X /* Count the total number of treasures */
- X if(fast_lookup[level[pos]].code & TREASURE)
- X goldleft ++;
- X /* Look for player blocks and remove them. The last one */
- X /* encountered sets the player position. */
- X if(level[pos] == PLAYER) {
- X player.xpos = player.xstart = x << 1;
- X player.ypos = player.ystart = y << 1;
- X level[pos] = SPACE;
- X }
- X pos ++;
- X }
- X printf("Collect %d gold dubloons.\n",goldleft);
- X
- X /* Initialize bad guy information and other things. */
- X start_badguy();
- X regen_allow();
- X regen_tree();
- X /* Freeze action until a key is pressed */
- X newlevel = 1;
- X}
- X
- X/* Move player one movement */
- Xvoid move_player()
- X{
- X register int i,code;
- X
- X /* Attempt to move player according to his standing orders */
- X code = movething(&player,curorder,-1);
- X /* If digging completed, or if the player fell, and he was trying to move */
- X /* in the same direction, change the current order to STAND */
- X if(code == 4 || (code == 2 && curorder == player.dir))
- X curorder = STAND;
- X /* Redraw player if he dropped something (which will overwrite the */
- X /* block) */
- X if(code == 3)
- X player.redraw = 1;
- X /* If player is in the middle of a block, interesting things can */
- X /* happen. */
- X if((player.xpos & 1) == 0 && (player.ypos & 1) == 0) {
- X /* If the player has picked up a gold piece, consume it and */
- X /* increment the score. */
- X if(fast_lookup[player.hold].code & TREASURE) {
- X player.hold = SPACE;
- X score++;
- X goldleft--;
- X /* If that was the last gold piece, escape ladder and other */
- X /* stuff may need to appear. */
- X if(goldleft == 0) {
- X regen_allow(); /* Regenerate the allowable movement array */
- X redrawall(); /* Refresh the entire screen */
- X }
- X /* Redraw the score line */
- X else
- X draw_score();
- X }
- X /* Get the control code for the block direction underneath the */
- X /* player */
- X i = (player.xpos >> 1)*ysize + (player.ypos >> 1);
- X code = fast_lookup[level[i]].code;
- X /* If the control code shows an active UPLEVEL block, or the */
- X /* player is at the top of the screen, and there is no more gold */
- X /* left, goto the next level. */
- X if((goldleft == 0 &&
- X (player.ypos == 0 || (code & UPLEVEL))) ||
- X ((code & UPLEVEL) && ! (code & INACTIVE))) {
- X /* Increment the level number */
- X levelnum ++;
- X /* Load the next level in if the current one is done */
- X init_level();
- X /* Redraw the level */
- X redrawall();
- X /* Flush all the many X windows operations out to the server. This */
- X /* is the only flush in all the operations in this procedure. */
- X XFlush(disp);
- X return;
- X }
- X /* If the block is a killer block, kill the player */
- X if(code & KILLIN)
- X died("was crushed");
- X }
- X /* Do not let PUTDOWN order stay after movement has started */
- X else if(curorder == PUTDOWN)
- X curorder = STAND;
- X}
- X
- X/* Move everything one movement (or less). This is the basic function */
- X/* which is called on every timer signal. */
- Xvoid moveall()
- X{
- X /* Remember old position of player */
- X player.xold = player.xpos;
- X player.yold = player.ypos;
- X /* Assume that the player does not need to be redrawn initially */
- X player.redraw = 0;
- X /* Do player movement */
- X move_player();
- X /* If the level has changed, do not move other stuff */
- X if(newlevel)
- X return;
- X /* Do secondary movement if player is sped up */
- X if(fast_lookup[player.hold].code & SPEED)
- X move_player();
- X /* If the level has changed, do not move other stuff */
- X if(newlevel)
- X return;
- X /* Prevent time from advancing for bad guys if a TIMESTOP item is */
- X /* held by player */
- X if(! (fast_lookup[player.hold].code & TIMESTOP)) {
- X /* Regenerate bad guys movement tree periodically */
- X if((curtick & 0xf) == 0)
- X regen_tree();
- X /* Only move bad guys every other tick */
- X if(curtick & 1)
- X move_badguys();
- X }
- X /* Check if the player is overlapping one of the bad guys while not */
- X /* holding armor. */
- X if(! (fast_lookup[player.hold].code & ARMOR) &&
- X overlap_badguy(player.xpos,player.ypos,-1))
- X died("was eaten");
- X /* Redraw player if he moved. Redraw occasionally anyway. */
- X if(player.xpos != player.xold || player.ypos != player.yold ||
- X (curtick & 0xf) == 0)
- X player.redraw = 1;
- X /* Erase and draw player if necessary */
- X drawmove_player();
- X /* Flush all the many X windows operations out to the server. This */
- X /* is the only flush in all the operations in this procedure. */
- X XFlush(disp);
- X}
- X
- X/* Function which is called whenever the timer signal goes off */
- Xvoid ticker(sig)
- Xint sig;
- X{
- X /* Ignore any signal which is not an alarm. Ignore alarm signals */
- X /* after a new level has been drawn until a key is hit. */
- X if(sig != SIGALRM || newlevel)
- X return;
- X
- X /* increment the tick counter if time is advancing */
- X if(! (fast_lookup[player.hold].code & TIMESTOP))
- X curtick ++;
- X
- X /* age all the holes */
- X change_holes();
- X
- X /* move the player and all the bad guys. */
- X moveall();
- X}
- X
- X/* main procedure for game */
- Xvoid main(argc,argv)
- Xint argc;
- Xchar **argv;
- X{
- X int keycount,i,gamestop = 0,gcfunc,firstevent;
- X static XEvent xev;
- X KeySym keyhit;
- X char buf[50];
- X
- X printf("type h for help.\n");
- X
- X /* set up level and world description defaults */
- X worldname = DEFWORLD;
- X levelnum = 1;
- X score = 0;
- X speed = 5;
- X /* scan the command line for executing parameters and flags */
- X for(i=1;i<argc;++i) {
- X if(argv[i][0] == '-') {
- X /* look for the level number */
- X if(argv[i][1] == 'l') {
- X if(argv[i][2] == '\0' && i+1 < argc) {
- X sscanf(argv[i+1],"%d",&levelnum);
- X i++;
- X }
- X else
- X sscanf(argv[i]+2,"%d",&levelnum);
- X }
- X /* look for the level number */
- X else if(argv[i][1] == 's') {
- X if(argv[i][2] == '\0' && i+1 < argc) {
- X sscanf(argv[i+1],"%d",&speed);
- X i++;
- X }
- X else
- X sscanf(argv[i]+2,"%d",&speed);
- X }
- X else {
- X printf("usage: golddig [-l <level>] [-s <speed 1-9>] [<world name>]\n");
- X exit(1);
- X }
- X }
- X /* if it doesn't start with a -, it must be the name of the world */
- X else {
- X worldname = argv[i];
- X break;
- X }
- X }
- X /* remember what the starting level was */
- X levelstart = levelnum;
- X
- X /* start up x windows and all graphics cursors for drawing level */
- X xstart(EVMASK);
- X /* reassemble the graphics cursors to prepare for actual play */
- X for(i=0;symbs[i].symb != '\0';++i)
- X fast_lookup[symbs[i].symb].gc =
- X fast_lookup[symbs[i].inplay].gc;
- X
- X /* Decide whether to use GXand or GXor depending on screen type */
- X if((BlackPixel(disp,0) & WhitePixel(disp,0)) == BlackPixel(disp,0))
- X gcfunc = GXand;
- X else
- X gcfunc = GXor;
- X /* compute all the graphics cursors for drawing the player in his */
- X /* various states. */
- X standgc = makegc(gcfunc,player_bits);
- X flygc = makegc(gcfunc,fly_bits);
- X hang1gc = makegc(gcfunc,hang1_bits);
- X hang2gc = makegc(gcfunc,hang2_bits);
- X up1gc = makegc(gcfunc,up1_bits);
- X up2gc = makegc(gcfunc,up2_bits);
- X left1gc = makegc(gcfunc,left1_bits);
- X left2gc = makegc(gcfunc,left2_bits);
- X right1gc = makegc(gcfunc,right1_bits);
- X right2gc = makegc(gcfunc,right2_bits);
- X /* initialize the bad guy's graphics cursors */
- X init_badguy();
- X /* name the game window */
- X XStoreName(disp,wind,"gold digger 2.0");
- X /* do the rest of the level initialization */
- X init_level();
- X
- X /* initialize timer structure according to speed */
- X if(speed <= 0)
- X speed = 1;
- X if(speed <= 5)
- X cycletime.it_interval.tv_usec = (5-speed) * 50000 + 125000;
- X else
- X cycletime.it_interval.tv_usec = 625000 / speed;
- X cycletime.it_interval.tv_sec = 0;
- X cycletime.it_value = cycletime.it_interval;
- X /* start the system timer. the timer signal catcher will be set */
- X /* after the first x event is received. */
- X signal(SIGALRM,SIG_IGN);
- X setitimer(ITIMER_REAL,&cycletime,(struct itimerval *) NULL);
- X
- X /* main event loop */
- X firstevent = 1;
- X while(1) {
- X /* get the next x window event */
- X XWindowEvent(disp,wind,EVMASK,&xev);
- X /* suppress the timer to prevent race conditions */
- X signal(SIGALRM,SIG_IGN);
- X /* If the window is exposed or the level is complete redraw the */
- X /* entire level. Also redraw everything if it is the first window */
- X /* event to handle window managers which capture expose events in */
- X /* an unfriendly way. */
- X if((xev.type == Expose && xev.xexpose.count == 0) || firstevent) {
- X /* Redraw the level */
- X redrawall();
- X /* Events after this are not the first event */
- X firstevent = 0;
- X }
- X else if(xev.type == KeyPress) {
- X keycount = XLookupString(&xev,buf,50,&keyhit,(XComposeStatus *) NULL);
- X /* Check for special control command */
- X if(xev.xkey.state & ControlMask)
- X switch(keyhit) {
- X /* ^S and ^Z freeze the game in place */
- X case XK_S: case XK_Z: case XK_s: case XK_z:
- X gamestop = 1;
- X break;
- X /* ^Q and ^Y reactivate the game */
- X case XK_Q: case XK_Y: case XK_q: case XK_y:
- X gamestop = 0;
- X break;
- X /* ^C, ^U, and ^/ kill the game */
- X case XK_C: case XK_U: case XK_c: case XK_u: case XK_backslash:
- X goto game_over;
- X /* ^R redraws the level */
- X case XK_R: case XK_r:
- X redrawall();
- X break;
- X }
- X /* Pressing a number changes the game speed */
- X else if(keyhit >= XK_1 && keyhit <= XK_9) {
- X speed = (int) (keyhit - XK_0);
- X /* Compute new cycle delay */
- X if(speed <= 5)
- X cycletime.it_interval.tv_usec = (5-speed) * 50000 + 125000;
- X else
- X cycletime.it_interval.tv_usec = 625000 / speed;
- X cycletime.it_value = cycletime.it_interval;
- X /* Reset the timer cycle time */
- X setitimer(ITIMER_REAL,&cycletime,(struct itimerval *) NULL);
- X /* Redraw score line with new speed */
- X draw_score();
- X }
- X /* If it was a normal key stroke, hand it off to the handle_key */
- X /* procedure */
- X else
- X handle_key(keyhit);
- X }
- X /* flush out pending x windows commands */
- X XFlush(disp);
- X /* reenable the alarm signal if game should be active */
- X if(! gamestop)
- X signal(SIGALRM,ticker);
- X }
- X
- X /* go to died procedure */
- X game_over:
- X died("was abandoned");
- X}
- END_OF_FILE
- if test 17923 -ne `wc -c <'golddig2/golddig.c'`; then
- echo shar: \"'golddig2/golddig.c'\" unpacked with wrong size!
- fi
- # end of 'golddig2/golddig.c'
- fi
- echo shar: End of archive 4 \(of 4\).
- cp /dev/null ark4isdone
- MISSING=""
- for I in 1 2 3 4 ; do
- if test ! -f ark${I}isdone ; then
- MISSING="${MISSING} ${I}"
- fi
- done
- if test "${MISSING}" = "" ; then
- echo You have unpacked all 4 archives.
- rm -f ark[1-9]isdone
- else
- echo You still need to unpack the following archives:
- echo " " ${MISSING}
- fi
- ## End of shell archive.
- exit 0
-