home *** CD-ROM | disk | FTP | other *** search
- /* xtmines: game where you try to cross a minefield */
- /* play.c: */
- /* Written by Timothy Tsai April 13, 1992 */
-
- #include "xtmines.h"
-
- /* This is a kludge for systems without usleep() */
- #ifdef NOUSLEEP
- #define USLEEP_LOOPS 15000
- void usleep(usecs)
- unsigned usecs;
- {
- int i;
- for (i=0;i<USLEEP_LOOPS;i++);
- }
- #endif
-
- void PrintStr(window,str)
- windtype window;
- char *str;
- {
- unsigned int ww,wh; /* get width and height of window */
- unsigned int wbw; /* border width */
- Font font;
- XFontStruct *fs;
- Window a;
- int b,c; /* dummy vars */
- unsigned int e; /* dummy vars */
- GC gc;
-
- gc = (window==status) ? gcs : (window==time_left) ? gct : gcm;
- XSetForeground(disp,gc,color[font_color].pixel);
- XSetBackground(disp,gc,color[background_color].pixel);
- XGetGeometry(disp,wind[window],&a,&b,&c,&ww,&wh,&wbw,&e);
- fs = (window==status) ? fontsstruct :
- (window==time_left) ? fonttstruct : fontmstruct;
- XDrawImageString(disp,wind[window],gc,
- ((ww-2*wbw)-XTextWidth(fs,str,strlen(str)))/2,
- (wh - fs->ascent - fs->descent)/2 +
- fs->ascent,str,strlen(str));
- XFlush(disp);
- }
-
- void InvPrintStr(window,str)
- windtype window;
- char *str;
- {
- unsigned int ww,wh; /* get width and height of window */
- unsigned int wbw; /* border width */
- Font font;
- XFontStruct *fs;
- Window a;
- int b,c; /* dummy vars */
- unsigned int e; /* dummy vars */
- GC gc;
-
- gc = (window==status) ? gcs : (window==time_left) ? gct : gcm;
- XSetForeground(disp,gc,color[background_color].pixel);
- XSetBackground(disp,gc,color[font_color].pixel);
- XGetGeometry(disp,wind[window],&a,&b,&c,&ww,&wh,&wbw,&e);
- fs = (window==status) ? fontsstruct :
- (window==time_left) ? fonttstruct : fontmstruct;
- XDrawImageString(disp,wind[window],gc,
- ((ww-2*wbw)-XTextWidth(fs,str,strlen(str)))/2,
- (wh - fs->ascent - fs->descent)/2 +
- fs->ascent,str,strlen(str));
- XFlush(disp);
- }
-
- void WindPrint(window,str)
- windtype window;
- char *str;
- {
- XClearWindow(disp,wind[window]);
- PrintStr(window,str);
- }
-
- char *num_rank_to_words(num_rank)
- ranktype num_rank;
- {
- switch (num_rank) {
- case grunt : return ("grunt"); break;
- case corporal : return ("corporal"); break;
- case lieutenant : return ("lieutenant"); break;
- case captain : return ("captain"); break;
- case mmajor : return ("major"); break;
- case general : return ("general"); break;
- case president : return ("president"); break;
- case king : return ("king"); break;
- case emperor : return ("emperor"); break;
- case angel : return ("angel"); break;
- case god : return ("god"); break;
- default : fprintf(stderr,"Error: Illegal rank\n");
- exit(2);
- }
- }
-
- char last_status_str[MAXSTRLEN];
- void print_status(str)
- char *str;
- {
-
- strcpy(last_status_str,str);
- WindPrint(status,str);
- }
-
- char *clock_time_str(time)
- int time;
- {
- int h,m,s;
- static char str[MAXSTRLEN];
-
- h = time/3600;
- m = (time-(h*3600))/60;
- s = (time-(h*3600)-(m*60));
- if (h != 0)
- sprintf(str,"%d:%02d:%02d",h,m,s);
- else if (m != 0)
- sprintf(str,"%d:%02d",m,s);
- else
- sprintf(str,"%d",s);
- return (str);
- }
-
- void print_display()
- {
- char str[MAXSTRLEN];
-
- sprintf(str,"Bombs: %d",num_bombs_left);
- WindPrint(bombs_left,str);
-
- sprintf(str,"Bonus: %d",num_bonus);
- WindPrint(bonus_wind,str);
-
- sprintf(str,"Time: %s",clock_time_str(num_time_left));
- WindPrint(time_left,str);
-
- sprintf(str,"Score: %d",num_score);
- WindPrint(score,str);
-
- sprintf(str,"Grenades: %d",num_grenades_left);
- WindPrint(grenades_left,str);
-
- sprintf(str,"Rank: %s",num_rank_to_words(level));
- WindPrint(rank,str);
-
- WindPrint(quit_wind,"Quit");
-
- if (used_showfig)
- sprintf(str,"Show = *%s", (show==sh_man) ? "man" : "fig");
- else
- sprintf(str,"Show = %s", (show==sh_man) ? "man" : "fig");
- WindPrint(show_wind,str);
-
- WindPrint(tgrenade_wind,"Throw Grenade");
-
- WindPrint(giveup_wind,"Surrender");
-
- sprintf(str,"Automark = %s",automark ? "on" : "off");
- WindPrint(automark_wind,str);
-
- sprintf(str,"Lives: %d",num_lives);
- WindPrint(lives_left,str);
-
- WindPrint(pause_wind,"Pause");
-
- if (used_sanity)
- sprintf(str,"Sanity = *%s",sanity ? "on" : "off");
- else
- sprintf(str,"Sanity = %s",sanity ? "on" : "off");
- WindPrint(sanitycheck_wind,str);
-
- if (used_eautomark)
- sprintf(str,"ExtAmark = *%s",extended_automark ? "on" : "off");
- else
- sprintf(str,"ExtAmark = %s",extended_automark ? "on" : "off");
- WindPrint(eautomark_wind,str);
-
- WindPrint(refresh_wind,"Refresh");
-
- WindPrint(status,last_status_str);
-
- XFlush(disp);
- }
-
- Pixmap bitmap[NUMBITMAPS];
- int bmwidth[NUMBITMAPS];
- int bmheight[NUMBITMAPS];
- /* This function will draw the bitmap indicated by bm in the field at the */
- /* position (vx,vy). If show==sh_fig, then a figure will be drawn */
- /* instead of the man bitmap. The figure is the number of surrounding */
- /* bombs. The font for figures is the same as the font for the status. */
- void draw(bm,vx,vy)
- bmtype bm;
- int vx,vy;
- {
- int x,y;
- int numbombs;
- char str[2];
-
- setxy(vx,vy,&x,&y);
- if ((bm==bm_man) && (show==sh_fig)) {
- clear(vx,vy);
- numbombs = bomb_status(vx,vy);
- str[0] = '0' + numbombs; str[1]=NULL;
- XDrawString(disp,field,gcs,
- 1+vx*(man_width+1)+(man_width-fontshoww)/2,
- 1+vy*(man_height+1)+(man_height-fontshowa)/2+fontshowa,
- str,strlen(str));
- }
- else
- XCopyPlane(disp,bitmap[bm],field,gcm,0,0,bmwidth[bm],bmheight[bm],
- x+1,y+1,1);
- XFlush(disp);
- }
-
- void clear(vx,vy)
- int vx,vy;
- {
- int x,y;
-
- setxy(vx,vy,&x,&y);
- XClearArea(disp,field,x+1,y+1,bmwidth[bm_man],bmwidth[bm_safe],FALSE);
- }
-
- fieldstruct FIELD[NUMCOLS][NUMROWS];
- void draw_field()
- {
- int r,c;
- double rowsep,colsep;
-
- /* draw vertical lines */
- colsep = ((double)(w-2*bw)/(double)NUMCOLS);
- for (c=0; c<NUMCOLS; c++) {
- XSetForeground(disp,gcm,color[field_color].pixel);
- XSetBackground(disp,gcm,color[background_color].pixel);
- XDrawLine(disp,field,gcm,(int)(c*colsep),0,(int)(c*colsep),fh);
- }
-
- /* draw horizontal lines */
- rowsep = ((double)fh/(double)NUMROWS);
- for (r=0; r<NUMROWS; r++) {
- XSetForeground(disp,gcm,color[field_color].pixel);
- XSetBackground(disp,gcm,color[background_color].pixel);
- XDrawLine(disp,field,gcm,0,(int)(r*rowsep),w,(int)(r*rowsep));
- }
-
- /* draw contents */
- for (c=0;c<NUMCOLS;c++)
- for (r=0;r<NUMROWS;r++)
- if (FIELD[c][r].m==fm_safe)
- draw(bm_safe,c,r);
- else if (FIELD[c][r].m==fm_bomb)
- draw(bm_bombmark,c,r);
- else switch (FIELD[c][r].c) {
- case fc_empty : break;
- case fc_man : draw(bm_man,c,r); break;
- case fc_bomb : if (dead)
- draw(bm_bomb,c,r);
- break;
- case fc_tombstone
- : draw(bm_tombstone,c,r); break;
- case fc_goal : draw(bm_goal,c,r); break;
- case fc_trail : draw(bm_trail,c,r); break;
- default : fprintf(stderr,
- "Error: Illegal FIELD content\n");
- exit(1);
- }
- XFlush(disp);
- }
-
- /* remove all Exposure events from the events queue; return the number
- of actual events removed */
- int remove_expose_events()
- {
- int r=0; /* number of events removed so far */
- XEvent event; /* not used */
-
- while (XCheckMaskEvent(disp,ExposureMask,&event))
- r++;
- return (r);
- }
-
- void refresh()
- {
- XEvent event;
- int done=FALSE; /* finished dequeuing all exposes? */
-
- print_display();
- draw_field();
- draw(bm_man,manvx,manvy);
- XFlush(disp);
-
- /* now dequeue all immediately succeeding exposure events */
- /* to prevent multiple, useless refreshes */
- remove_expose_events();
- }
-
- /* set up windows for pausing; the field should be blanked to prevent
- cheating; the time should be adjusted so there is no penalty for pausing;
- */
- int do_pause()
- {
- int time_at_start_of_pause;
-
- char str[MAXSTRLEN];
- unsigned int ww,wh; /* get width and height of window */
- unsigned int wbw; /* border width */
- XFontStruct *fs;
- Window a;
- int b,c; /* dummy vars */
- unsigned int e; /* dummy vars */
-
- int wait=TRUE;
- XEvent event;
- XButtonPressedEvent *eventbp;
- XKeyPressedEvent *eventkp;
- KeySym ksym;
- char s;
- int done;
-
- WindPrint(pause_wind,"Continue");
- time_at_start_of_pause = time(0);
-
- /* blank out field and write "P-A-U-S-E" message on field */
- XClearWindow(disp,field);
- strcpy(str,"P-A-U-S-E");
- XSetForeground(disp,gcs,color[font_color].pixel);
- XSetBackground(disp,gcs,color[background_color].pixel);
- XGetGeometry(disp,field,&a,&b,&c,&ww,&wh,&wbw,&e);
- fs = fontsstruct;
- XDrawImageString(disp,field,gcs,
- ((ww-2*wbw)-XTextWidth(fs,str,strlen(str)))/2,
- (wh - fs->ascent - fs->descent)/2 +
- fs->ascent,str,strlen(str));
- XFlush(disp);
-
- /* Wait for keypress or button click to signal done with pause */
- while (wait == TRUE) {
- while (!XPending(disp))
- usleep(XPENDING_UDELAY);
- XNextEvent(disp,&event);
- if (event.type==ButtonPress) {
- eventbp = (XButtonPressedEvent *) &event;
- if (eventbp->window == wind[pause_wind])
- wait = FALSE;
- }
- else if (event.type == KeyPress) {
- eventkp = (XKeyPressedEvent *) &event;
- XLookupString(&event,&s,1,&ksym,NULL);
- if ((s == 'c') || (s == 'C'))
- wait = FALSE;
- }
- else if (event.type == Expose) {
- /* do refresh in pause mode; pause_wind and field are different */
- print_display();
- WindPrint(pause_wind,"Continue");
- sprintf(str,"Time: %s",clock_time_str(
- num_time_left_at_start-
- (time_at_start_of_pause-time_at_start_of_level
- -pause_time)));
- WindPrint(time_left,str);
-
- /* blank out field and write "P-A-U-S-E" message on field */
- WindPrint(pause_wind,"Continue");
- XClearWindow(disp,field);
- strcpy(str,"P-A-U-S-E");
- XSetForeground(disp,gcs,color[font_color].pixel);
- XSetBackground(disp,gcs,color[background_color].pixel);
- XGetGeometry(disp,field,&a,&b,&c,&ww,&wh,&wbw,&e);
- fs = fontsstruct;
- XDrawImageString(disp,field,gcs,
- ((ww-2*wbw)-XTextWidth(fs,str,strlen(str)))/2,
- (wh - fs->ascent - fs->descent)/2 +
- fs->ascent,str,strlen(str));
- XFlush(disp);
-
- /* now dequeue all immediately succeeding exposure events */
- /* to prevent multiple, useless refreshes */
- remove_expose_events();
- }
- }
-
- pause_time += time(0) - time_at_start_of_pause;
-
- /* Restore windows to continue game */
- XClearWindow(disp,field);
- refresh();
-
- WindPrint(pause_wind,"Pause");
- }
-
- int setxy(vx,vy,x,y)
- int vx,vy,*x,*y;
- {
- /* convert virtual coordinates to actual field pixel coordinates */
- double rowsep,colsep;
-
- if (((vx>=0) && (vx<NUMCOLS)) &&
- ((vy>=0) && (vy<NUMROWS))) {
- colsep = ((double)(w-2*bw)/(double)NUMCOLS);
- rowsep = ((double)fh/(double)NUMROWS);
- *x = vx*colsep;
- *y = vy*rowsep;
- return (SUCCESS);
- }
- else
- return (OUT_OF_RANGE);
- }
-
- int setvxvy(x,y,vx,vy)
- int x,y,*vx,*vy;
- {
- /* convert actual field pixel coordinates to virtual coordinates */
- double rowsep,colsep;
-
- if (((x>=0) && (x<w-2*bw)) &&
- ((y>=0) && (y<fh))) {
- colsep = ((double)(w-2*bw)/(double)NUMCOLS);
- rowsep = ((double)fh/(double)NUMROWS);
- *vx = x/colsep;
- *vy = y/rowsep;
- return (SUCCESS);
- }
- else
- return (OUT_OF_RANGE);
- }
-
- int bomb_status(vx,vy)
- int vx,vy;
- {
- int numbombs=0;
-
- if (vy>0) {
- if ((vx>0) && (FIELD[vx-1][vy-1].c==fc_bomb))
- numbombs++;
- if (FIELD[vx][vy-1].c==fc_bomb)
- numbombs++;
- if ((vx<NUMCOLS-1) && (FIELD[vx+1][vy-1].c==fc_bomb))
- numbombs++;
- }
- if (vy<NUMROWS-1) {
- if ((vx>0) && (FIELD[vx-1][vy+1].c==fc_bomb))
- numbombs++;
- if (FIELD[vx][vy+1].c==fc_bomb)
- numbombs++;
- if ((vx<NUMCOLS-1) && (FIELD[vx+1][vy+1].c==fc_bomb))
- numbombs++;
- }
- if ((vx>0) && (FIELD[vx-1][vy].c==fc_bomb))
- numbombs++;
- if ((vx<NUMCOLS-1) && (FIELD[vx+1][vy].c==fc_bomb))
- numbombs++;
-
- return (numbombs);
- }
-
- void show_bomb_status(vx,vy)
- int vx,vy;
- {
- int numbombs;
- char str[MAXSTRLEN];
-
- numbombs = bomb_status(vx,vy);
-
- sprintf(str,"%d surrounding bomb%c",numbombs,numbombs==1 ? ' ' : 's');
- print_status(str);
-
- if ((automark) && (numbombs==0))
- mark_allaround_ok(manvx,manvy,0);
- }
-
- /* show_all_bombs: shows all bombs on field */
- /* if any marks are incorrect */
- /* highlight those squares */
- void show_all_bombs()
- {
- int c,r; /* column and row under consideration */
-
- for (c=0;c<NUMCOLS;c++)
- for (r=0;r<NUMROWS;r++)
- if (FIELD[c][r].c == fc_bomb)
- if (FIELD[c][r].m == fm_safe)
- draw(bm_safewrong,c,r); /* bomb, marked safe */
- else
- draw(bm_bomb,c,r); /* bomb, unmarked or correct */
- else if (FIELD[c][r].m == fm_bomb)
- draw(bm_bombmarkwrong,c,r); /* no bomb, marked unsafe */
- }
-
- void do_promotion()
- {
- char str[MAXSTRLEN];
- XEvent event;
- XButtonPressedEvent *eventbp;
- XKeyPressedEvent *eventkp;
- int wait = TRUE;
-
- finished = TRUE;
- num_score += current_bonus();
- printf("Your bonus for reaching the goal at rank %s is\n",
- num_rank_to_words(level));
- printf(" %5d = %d*%d \t (level*Time left)\n",
- current_bonus(),level+1,num_time_left);
- if (num_bombs_left>0)
- printf(" + %d \t (Num bombs left)\n",
- num_bombs_left);
- if (num_grenades_left>0)
- printf(" + %d*%d \t (Num grenades left*ppg)\n",
- num_grenades_left,POINTS_PER_GRENADE);
- if (num_tombstones>0)
- printf(" - %d*%d \t (Num tombstones*ppts)\n",
- num_tombstones,POINTS_PER_TOMBSTONE);
- /* This used to be used for ver 1.0
- if (used_showfig)
- printf(" - %d \t (Used showfig?)\n",
- POINTS_FOR_USED_SHOWFIG);
- */
- if (used_sanity)
- printf(" - %d \t (Used sanity check?)\n",
- (PERCENT_FOR_USED_SANITY*bonus_without_penalties())/100);
- if (used_eautomark)
- printf(" - %d \t (Used extended_automark?)\n",
- (PERCENT_FOR_USED_EAUTOMARK*bonus_without_penalties())/100);
- printf("Your current score is %d = %d + %d\n",
- num_score,num_score-current_bonus(),current_bonus());
-
- show_all_bombs();
-
- /* now update score on screen incrementally */
- {
- int i;
- /* this will make sure that at most 100 steps are made */
- int step = current_bonus()/100;
-
- for (i=num_score-current_bonus();i<num_score;i+=step) {
- sprintf(str,"Score: %d",i);
- PrintStr(score,str);
- }
- sprintf(str,"Score: %d",num_score);
- WindPrint(score,str);
- }
-
- if (level == HIGHEST_PLAYABLE_RANK) {
- sprintf(str,
- "Congratulations, you have reached completed the highest rank!");
- level++;
- show_and_add_scores();
- }
- else
- sprintf(str,"Congratulations, you have been promoted to %s",
- num_rank_to_words(level+1));
- print_status(str);
-
- /* reward additional lives and grenades */
- if ((level>=LOWEST_LEVEL_FOR_REWARD) &&
- (num_score>=LOWEST_SCORE_FOR_REWARD)) {
- if (++num_grenades_left > NUM_GRENADES_AT_START)
- num_grenades_left = NUM_GRENADES_AT_START;
- sprintf(str,"Grenades: %d",num_grenades_left);
- WindPrint(grenades_left,str);
- if (++num_lives>MAXLIVES) num_lives=MAXLIVES;
- sprintf(str,"Lives: %d",num_lives);
- WindPrint(lives_left,str);
- }
-
- sleep(3);
-
- print_status ("In the field, press key or click button to continue");
- while (wait == TRUE) {
- while (!XPending(disp))
- usleep(XPENDING_UDELAY);
- XNextEvent(disp,&event);
- if (event.type==ButtonPress) {
- eventbp = (XButtonPressedEvent *) &event;
- if (eventbp->window == field)
- wait = FALSE;
- else if (eventbp->window == wind[quit_wind]) {
- level++;
- show_and_add_scores();
- }
- }
- else if (event.type == KeyPress) {
- eventkp = (XKeyPressedEvent *) &event;
- if (eventkp->window == field)
- wait = FALSE;
- }
- else if (event.type == Expose) {
- refresh();
- show_all_bombs();
- }
- }
- }
-
- /* next_to_trail: returns TRUE is at least one of the up to eight adjacent */
- /* squares is already traversed and marked as fc_trail; */
- /* vx and vy is the square in question */
- int next_to_trail(vx,vy)
- int vx,vy;
- {
- int numbombs=0;
-
- if (vy>0) {
- if ((vx>0) && (FIELD[vx-1][vy-1].c==fc_trail))
- return (TRUE);
- if (FIELD[vx][vy-1].c==fc_trail)
- return (TRUE);
- if ((vx<NUMCOLS-1) && (FIELD[vx+1][vy-1].c==fc_trail))
- return (TRUE);
- }
- if (vy<NUMROWS-1) {
- if ((vx>0) && (FIELD[vx-1][vy+1].c==fc_trail))
- return (TRUE);
- if (FIELD[vx][vy+1].c==fc_trail)
- return (TRUE);
- if ((vx<NUMCOLS-1) && (FIELD[vx+1][vy+1].c==fc_trail))
- return (TRUE);
- }
- if ((vx>0) && (FIELD[vx-1][vy].c==fc_trail))
- return (TRUE);
- if ((vx<NUMCOLS-1) && (FIELD[vx+1][vy].c==fc_trail))
- return (TRUE);
-
- return (FALSE);
- }
-
- int move_man(vx,vy)
- int vx,vy;
- {
- int ax,ay; /* adjusted x and y */
- int reached_goal=FALSE;
-
- setxy(vx,vy,&ax,&ay);
-
- if (FIELD[vx][vy].m == fm_bomb) {
- XBell(disp,0);
- print_status("Square is marked as unsafe!");
- return (SQUARE_IS_UNSAFE);
- }
- if (((abs(manvx-vx)<=1) && (abs(manvy-vy)<=1)) ||
- (FIELD[vx][vy].c==fc_trail) ||
- (next_to_trail(vx,vy) && (FIELD[vx][vy].m==fm_safe))) {
- switch (FIELD[vx][vy].c) {
- case fc_goal :
- case fc_trail :
- case fc_empty : /* only allow movement of one square */
- if ((FIELD[vx][vy].c==fc_goal) && (!dead))
- reached_goal = TRUE;
- draw(bm_trail,manvx,manvy);
- FIELD[manvx][manvy].c = fc_trail;
- manvx = vx; manvy = vy;
- draw(bm_man,vx,vy);
- FIELD[manvx][manvy].c = fc_man;
- FIELD[manvx][manvy].m = fm_nomark;
- if (reached_goal)
- do_promotion();
- break;
- case fc_man : show_bomb_status(manvx,manvy);
- draw(bm_man,manvx,manvy);
- break;
- case fc_bomb : draw(bm_trail,manvx,manvy);
- FIELD[manvx][manvy].c = fc_trail;
- die(vx,vy);
- break;
- case fc_tombstone:
- break;
- default : fprintf(stderr,
- "Error: Illegal FIELD contents\n");
- exit(2);
- }
- show_bomb_status(manvx,manvy);
- }
- else {
- print_status("Can't move that far!");
- XBell(disp,0);
- }
- return (SUCCESS);
- }
-
- int remove_mark(vx,vy)
- int vx,vy;
- {
- if (FIELD[vx][vy].m == fm_nomark)
- return (NO_MARK_TO_REMOVE);
- else {
- FIELD[vx][vy].m = fm_nomark;
- clear(vx,vy);
- return (SUCCESS);
- }
- }
-
- int mark_ok(vx,vy)
- int vx,vy;
- {
- switch (FIELD[vx][vy].c) {
- case fc_empty:
- case fc_bomb: FIELD[vx][vy].m = fm_safe;
- draw(bm_safe,vx,vy);
- return (SUCCESS);
- case fc_trail:
- case fc_man:
- case fc_tombstone:
- case fc_goal: return (CANT_MARK);
- default: fprintf(stderr,
- "Error: Illegal FIELD contents\n");
- exit(3);
- }
- }
-
- /* if level<0, then only mark immediately surrounding squares; don't do
- extended automarking
- */
- int mark_allaround_ok(vx,vy,level)
- int vx,vy,level; /* level=level of recursion */
- {
- int c,r; /* col and row to clear FIELD[][].done flags */
-
- /* clear all done flags if on original call */
- if (level==0)
- for (c=0;c<NUMCOLS;c++)
- for (r=0;r<NUMROWS;r++)
- FIELD[c][r].done = FALSE;
-
- if (vy>0) {
- if ((vx>0) && (FIELD[vx-1][vy-1].m==fm_nomark))
- mark_ok(vx-1,vy-1);
- if (FIELD[vx][vy-1].m==fm_nomark)
- mark_ok(vx,vy-1);
- if ((vx<NUMCOLS-1) && (FIELD[vx+1][vy-1].m==fm_nomark))
- mark_ok(vx+1,vy-1);
- }
- if (vy<NUMROWS-1) {
- if ((vx>0) && (FIELD[vx-1][vy+1].m==fm_nomark))
- mark_ok(vx-1,vy+1);
- if (FIELD[vx][vy+1].m==fm_nomark)
- mark_ok(vx,vy+1);
- if ((vx<NUMCOLS-1) && (FIELD[vx+1][vy+1].m==fm_nomark))
- mark_ok(vx+1,vy+1);
- }
- if ((vx>0) && (FIELD[vx-1][vy].m==fm_nomark))
- mark_ok(vx-1,vy);
- if ((vx<NUMCOLS-1) && (FIELD[vx+1][vy].m==fm_nomark))
- mark_ok(vx+1,vy);
-
- if ((level>=0) && (extended_automark) && (!FIELD[vx][vy].done)) {
- /* mark square as being already marked-allaround to prevent repeat */
- FIELD[vx][vy].done = TRUE;
- if (bomb_status(vx,vy) == 0) {
- draw(bm_trail,vx,vy);
- FIELD[vx][vy].c = fc_trail;
- FIELD[vx][vy].m = fm_nomark;
- }
- if (vy>0) {
- if ((vx>0) && (FIELD[vx-1][vy-1].m==fm_safe) &&
- (bomb_status(vx-1,vy-1)==0))
- mark_allaround_ok(vx-1,vy-1,level+1);
- if ((FIELD[vx][vy-1].m==fm_safe) &&
- (bomb_status(vx,vy-1)==0))
- mark_allaround_ok(vx,vy-1,level+1);
- if ((vx<NUMCOLS-1) && (FIELD[vx+1][vy-1].m==fm_safe) &&
- (bomb_status(vx+1,vy-1)==0))
- mark_allaround_ok(vx+1,vy-1,level+1);
- }
- if (vy<NUMROWS-1) {
- if ((vx>0) && (FIELD[vx-1][vy+1].m==fm_safe) &&
- (bomb_status(vx-1,vy+1)==0))
- mark_allaround_ok(vx-1,vy+1,level+1);
- if ((FIELD[vx][vy+1].m==fm_safe) &&
- (bomb_status(vx,vy+1)==0))
- mark_allaround_ok(vx,vy+1,level+1);
- if ((vx<NUMCOLS-1) && (FIELD[vx+1][vy+1].m==fm_safe) &&
- (bomb_status(vx+1,vy+1)==0))
- mark_allaround_ok(vx+1,vy+1,level+1);
- }
- if ((vx>0) && (FIELD[vx-1][vy].m==fm_safe) &&
- (bomb_status(vx-1,vy)==0))
- mark_allaround_ok(vx-1,vy,level+1);
- if ((vx<NUMCOLS-1) && (FIELD[vx+1][vy].m==fm_safe) &&
- (bomb_status(vx+1,vy)==0))
- mark_allaround_ok(vx+1,vy,level+1);
- }
-
- /* put man marker back on field */
- if (level<=0)
- draw(bm_man,manvx,manvy);
-
- return (SUCCESS);
- }
-
- int mark_bomb(vx,vy)
- int vx,vy;
- {
- switch (FIELD[vx][vy].c) {
- case fc_empty:
- case fc_bomb: FIELD[vx][vy].m = fm_bomb;
- draw(bm_bombmark,vx,vy);
- return (SUCCESS);
- case fc_trail:
- case fc_man:
- case fc_tombstone:
- case fc_goal: return (CANT_MARK);
- default: fprintf(stderr,
- "Error: Illegal FIELD contents\n");
- exit(3);
- }
- }
-
- void die(vx,vy)
- int vx,vy;
- {
- char str[MAXSTRLEN];
-
- explode(vx,vy);
- draw(bm_tombstone,vx,vy);
- FIELD[vx][vy].c = fc_tombstone;
- num_tombstones++;
- if (--num_lives<0)
- num_lives = 0;
- sprintf(str,"Lives: %d",num_lives);
- WindPrint(lives_left,str);
- if ((num_lives<=0) && (!dead)) {
- show_bomb_status(manvx,manvy);
- dead = TRUE;
- show_all_bombs();
- print_status("You have just died! GAME OVER!");
- XBell(disp,0);
- XBell(disp,0);
- XBell(disp,0);
- XFlush(disp);
- sleep(3);
- }
- draw(bm_man,0,0);
- FIELD[0][0].c = fc_man;
- FIELD[0][0].m = fm_nomark;
- manvx = manvy = 0;
- show_bomb_status(manvx,manvy);
- }
-
- int explode(vx,vy)
- int vx,vy;
- {
- int i;
- char str[MAXSTRLEN];
-
- if (FIELD[vx][vy].c == fc_bomb) {
- num_bombs_left--;
- sprintf(str,"Bombs: %d",num_bombs_left);
- WindPrint(bombs_left,str);
- }
-
- /* simulate explosion on screen */
- for (i=0;i<10;i++) {
- draw(bm_pow,vx,vy);
- usleep(BOMB_EXPLODE_UDELAY);
- draw(bm_bomb,vx,vy);
- usleep(BOMB_EXPLODE_UDELAY);
- }
- clear(vx,vy);
- FIELD[vx][vy].c = fc_empty;
- FIELD[vx][vy].m = fm_nomark;
-
-
- /* check to see if other bombs nearby--Manhattan dirs only */
- if ((vx>0) && (FIELD[vx-1][vy].c==fc_bomb)) explode(vx-1,vy);
- if ((vx<NUMCOLS-1) && (FIELD[vx+1][vy].c==fc_bomb)) explode(vx+1,vy);
- if ((vy>0) && (FIELD[vx][vy-1].c==fc_bomb)) explode(vx,vy-1);
- if ((vy<NUMROWS-1) && (FIELD[vx][vy+1].c==fc_bomb)) explode(vx,vy+1);
-
- /* check to see if man nearby--Manhattan dirs only */
- if ((vx>0) && (FIELD[vx-1][vy].c==fc_man)) die(vx-1,vy);
- if ((vx<NUMCOLS-1) && (FIELD[vx+1][vy].c==fc_man)) die(vx+1,vy);
- if ((vy>0) && (FIELD[vx][vy-1].c==fc_man)) die(vx,vy-1);
- if ((vy<NUMROWS-1) && (FIELD[vx][vy+1].c==fc_man)) die(vx,vy+1);
-
- return(SUCCESS);
- }
-
- /* bonus_without_penalties: returns the current bonus remaining for */
- /* this level, without used_* penalties */
- int bonus_without_penalties()
- {
- int b; /* temp value for current bonus */
-
- b = (level+1)*num_time_left
- + num_bombs_left
- + num_grenades_left*POINTS_PER_GRENADE
- - num_tombstones*POINTS_PER_TOMBSTONE;
-
- if (b < 0)
- b = 0;
-
- return (b);
- }
-
- /* current_bonus: returns the current amount of bonus */
- /* remaining for this level */
- int current_bonus()
- {
- int b; /* temp value for current bonus */
-
- b = bonus_without_penalties()
- /* This used to be used for ver 1.0
- - used_showfig*POINTS_FOR_USED_SHOWFIG;
- */
- - used_sanity*
- (PERCENT_FOR_USED_SANITY*bonus_without_penalties())/100
- - used_eautomark*
- (PERCENT_FOR_USED_EAUTOMARK*bonus_without_penalties())/100;
-
- if (b < 0)
- b = 0;
-
- return (b);
- }
-
-
- /* update_bonus: recalculate the amount of bonus remaining for this level */
- /* display the correct new bonus on screen */
- int update_bonus()
- {
- char str[MAXSTRLEN];
- static int last_bonus;
-
- if ((num_bonus = current_bonus()) != last_bonus) {
- sprintf(str,"Bonus: %d",num_bonus);
- WindPrint(bonus_wind,str);
- last_bonus = num_bonus;
- }
- }
-
- int update_time()
- {
- long st,ct; /* starting and current times */
- char str[MAXSTRLEN];
- int previous_num_time_left=num_time_left;
-
- st = time_at_start_of_level;
- ct = time(0);
- num_time_left = num_time_left_at_start - (ct-st-pause_time);
- update_bonus();
- if (num_time_left<=0) {
- print_status("Time is out! GAME OVER!");
- sprintf(str,"Time: %s",clock_time_str(num_time_left));
- WindPrint(time_left,str);
- XBell(disp,0);
- XBell(disp,0);
- XBell(disp,0);
- return (TIME_IS_OVER); /* TIME_IS_OVER = TRUE */
- }
- else if (num_time_left != previous_num_time_left) {
- sprintf(str,"Time: %s",clock_time_str(num_time_left));
- WindPrint(time_left,str);
- return (SUCCESS);
- }
- return (SUCCESS);
- }
-
- int throw_grenade()
- {
- char str[MAXSTRLEN];
- XEvent event;
- XButtonPressedEvent *eventbp;
- int vx,vy;
-
- if (num_grenades_left==0) {
- print_status("No grenades left!");
- XBell(disp,0);
- return (NO_GRENADES_LEFT);
- }
-
- XClearWindow(disp,wind[tgrenade_wind]);
- InvPrintStr(tgrenade_wind,"Throw Grenade");
- print_status("Ready to throw grenade");
-
- /* Get position to throw grenade */
- while (!XPending(disp))
- usleep(XPENDING_UDELAY);
- XNextEvent(disp,&event);
- eventbp = (XButtonPressedEvent *) &event;
- if ((event.type != ButtonPress) || (eventbp->window != field) ||
- (setvxvy(eventbp->x,eventbp->y,&vx,&vy) == OUT_OF_RANGE)) {
- print_status("Click on the position to throw grenade!");
- XBell(disp,0);
- WindPrint(tgrenade_wind,"Throw Grenade");
- return (ILLEGAL_POSITION);
- }
-
- /* check to see if within range */
- if (abs(manvx-vx) + abs(manvy-vy) > GRENADE_DISTANCE) {
- sprintf(str,
- "Can't toss grenade that far! Max distance is %d.\n",
- GRENADE_DISTANCE);
- print_status(str);
- XBell(disp,0);
- WindPrint(tgrenade_wind,"Throw Grenade");
- return (TOO_FAR_TO_TOSS_GRENADE);
- }
-
- /* passed checks -- toss grenade */
- if (FIELD[vx][vy].c == fc_man) {
- die(vx,vy);
- sprintf(str,"Grenades: %d",--num_grenades_left);
- WindPrint(grenades_left,str);
- WindPrint(tgrenade_wind,"Throw Grenade");
- return (DIED);
- }
- else if ((FIELD[vx][vy].c != fc_tombstone) &&
- (FIELD[vx][vy].c != fc_goal)) {
- explode(vx,vy);
- show_bomb_status(manvx,manvy);
- draw(bm_man,manvx,manvy);
- sprintf(str,"Grenades: %d",--num_grenades_left);
- WindPrint(grenades_left,str);
- WindPrint(tgrenade_wind,"Throw Grenade");
- return (SUCCESS);
- }
- else {
- strcpy(str,"No bomb at that position. ");
- strcat(str,"Can't blow up tombstone or goal.");
- print_status(str);
- XBell(disp,0);
- WindPrint(tgrenade_wind,"Throw Grenade");
- return (CANT_EXPLODE);
- }
- }
-
- /* num_adj_squares_marked_bomb: returns num adjacent squares user has marked
- as being unsafe
- */
- int num_adj_squares_marked_bomb(vx,vy)
- int vx,vy;
- {
- int nummarks=0;
-
- if (vy>0) {
- if ((vx>0) && (FIELD[vx-1][vy-1].m==fm_bomb))
- nummarks++;
- if (FIELD[vx][vy-1].m==fm_bomb)
- nummarks++;
- if ((vx<NUMCOLS-1) && (FIELD[vx+1][vy-1].m==fm_bomb))
- nummarks++;
- }
- if (vy<NUMROWS-1) {
- if ((vx>0) && (FIELD[vx-1][vy+1].m==fm_bomb))
- nummarks++;
- if (FIELD[vx][vy+1].m==fm_bomb)
- nummarks++;
- if ((vx<NUMCOLS-1) && (FIELD[vx+1][vy+1].m==fm_bomb))
- nummarks++;
- }
- if ((vx>0) && (FIELD[vx-1][vy].m==fm_bomb))
- nummarks++;
- if ((vx<NUMCOLS-1) && (FIELD[vx+1][vy].m==fm_bomb))
- nummarks++;
-
- return (nummarks);
- }
-
- /* num_adj_squares_marked_safe: returns num adjacent squares user has marked
- as being safe
- */
- int num_adj_squares_marked_safe(vx,vy)
- int vx,vy;
- {
- int nummarks=0;
-
- if (vy>0) {
- if ((vx>0) && (FIELD[vx-1][vy-1].m==fm_safe))
- nummarks++;
- if (FIELD[vx][vy-1].m==fm_safe)
- nummarks++;
- if ((vx<NUMCOLS-1) && (FIELD[vx+1][vy-1].m==fm_safe))
- nummarks++;
- }
- if (vy<NUMROWS-1) {
- if ((vx>0) && (FIELD[vx-1][vy+1].m==fm_safe))
- nummarks++;
- if (FIELD[vx][vy+1].m==fm_safe)
- nummarks++;
- if ((vx<NUMCOLS-1) && (FIELD[vx+1][vy+1].m==fm_safe))
- nummarks++;
- }
- if ((vx>0) && (FIELD[vx-1][vy].m==fm_safe))
- nummarks++;
- if ((vx<NUMCOLS-1) && (FIELD[vx+1][vy].m==fm_safe))
- nummarks++;
-
- return (nummarks);
- }
-
- /* num_unvisited_adj_squares: returns num adjacent squares user has
- not yet visited (not marked with fc_trail)
- */
- int num_unvisited_adj_squares(vx,vy)
- int vx,vy;
- {
- int num_unvisited=0;
-
- if (vy>0) {
- if ((vx>0) && (FIELD[vx-1][vy-1].c!=fc_trail))
- num_unvisited++;
- if (FIELD[vx][vy-1].c!=fc_trail)
- num_unvisited++;
- if ((vx<NUMCOLS-1) && (FIELD[vx+1][vy-1].c!=fc_trail))
- num_unvisited++;
- }
- if (vy<NUMROWS-1) {
- if ((vx>0) && (FIELD[vx-1][vy+1].c!=fc_trail))
- num_unvisited++;
- if (FIELD[vx][vy+1].c!=fc_trail)
- num_unvisited++;
- if ((vx<NUMCOLS-1) && (FIELD[vx+1][vy+1].c!=fc_trail))
- num_unvisited++;
- }
- if ((vx>0) && (FIELD[vx-1][vy].c!=fc_trail))
- num_unvisited++;
- if ((vx<NUMCOLS-1) && (FIELD[vx+1][vy].c!=fc_trail))
- num_unvisited++;
-
- return (num_unvisited);
- }
-
- /* do_sanity_check: Make sure user is not losing his mind!
- If more adjacent squares are marked unsafe than is indicated by the
- current bomb status, warn the user.
- If more adjacent squares are marked safe than the number of unvisited
- squares - the current bomb status, warn the user.
- */
- int do_sanity_check(vx,vy)
- int vx,vy;
- {
- /* Check first for too many squares marked unsafe */
- if (num_adj_squares_marked_bomb(vx,vy) > bomb_status(vx,vy)) {
- print_status("WARNING: too many squares marked UNsafe!");
- XBell(disp,0);
- return (CHECK_FAILED);
- }
-
- /* Next check for too many squares marked safe */
- if (num_adj_squares_marked_safe(vx,vy) >
- num_unvisited_adj_squares(vx,vy) - bomb_status(vx,vy)) {
- print_status("WARNING: too many squares marked safe!");
- XBell(disp,0);
- return (CHECK_FAILED);
- }
-
- return (SUCCESS);
- }
-