|
DataMuseum.dkPresents historical artifacts from the history of: DKUUG/EUUG Conference tapes |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about DKUUG/EUUG Conference tapes Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - downloadIndex: T g
Length: 20815 (0x514f) Types: TextFile Names: »game.c«
└─⟦b20c6495f⟧ Bits:30007238 EUUGD18: Wien-båndet, efterår 1987 └─⟦this⟧ »EUUGD18/General/Wanderer/game.c«
#include "wand_head.h" #define viable(x,y) (((screen[y][x] == ' ') || (screen[y][x] == ':') ||\ (screen[y][x] == '@') || (screen[y][x] == '+') ||\ (screen[y][x] == 'S')) && (y >= 0) &&\ (x >= 0) && (y < NOOFROWS) && (x < ROWLEN)) /* typedef struct mon_rec *//* M002 struct mon_rec moved */ /* { *//* to header file because it */ /* int x,y,mx,my; *//* is needed by save.c */ /* char under; */ /* struct mon_rec *next,*prev; */ /* }; */ typedef struct { int d[2] } direction; #ifdef LINT_ARGS /* M001 */ direction new_direction(int, int, int, int); #else direction new_direction(); #endif extern int jumpscreen(); extern int check(); extern void showpass(); extern void draw_symbol(); extern void display(); extern int fall(); extern void map(); extern void redraw_screen(); extern int debug_disp; extern int edit_mode; extern int saved_game; extern char screen[NOOFROWS][ROWLEN+1]; /* Add a spirit to the chain */ /* Maintain a doubly linked list to make reuse possible. tail_of_list is *NOT* the last monster allocated, but the last monster alloted to a screen. start_of_list is a dummy entry to ease processing. last_of_list is the last entry allocated. */ static struct mon_rec start_of_list = {0,0,0,0,0,NULL,NULL}; struct mon_rec *tail_of_list; struct mon_rec *last_of_list; struct mon_rec *make_monster(x,y) int x,y; { char *malloc(); #define MALLOC (struct mon_rec *)malloc(sizeof(struct mon_rec)) struct mon_rec *monster; if(tail_of_list->next == NULL) { if((last_of_list = MALLOC) == NULL) return NULL; tail_of_list->next = last_of_list; last_of_list->prev = tail_of_list; last_of_list->next = NULL; } monster = tail_of_list = tail_of_list->next; monster->x = x; monster->y = y; monster->mx = 1; /* always start moving RIGHT. (fix later) */ monster->my = 0; monster->under = ' '; return monster; } /* 'follow lefthand wall' algorithm for baby monsters */ direction new_direction(x,y,bx,by) int x,y,bx,by; { direction out; if(viable((x+by),(y-bx))) { out.d[0] = by; out.d[1] = -bx; return out; } if(viable((x+bx),(y+by))) { out.d[0] = bx; out.d[1] = by; return out; } if(viable((x-by),(y+bx))) { out.d[0] = -by; out.d[1] = bx; return out; } if(viable((x-bx),(y-by))) { out.d[0] = -bx; out.d[1] = -by; return out; } out.d[0] = -bx; out.d[1] = -by; return out; } /* Actual game function - Calls fall() to move boulders and arrows recursively */ /* Variable explaination : All the var names make sense to ME, but some people think them a bit confusing... :-) So heres an explanation. x,y : where you are nx,ny : where you're trying to move to sx,sy : where the screen window on the playing area is mx,my : where the monster is tx,ty : teleport arrival bx,by : baby monster position nbx,nby : where it wants to be lx,ly : the place you left when teleporting nf : how many diamonds youve got so far new_disp : the vector the baby monster is trying */ char *playscreen(num,score,bell,maxmoves,keys) int *num, maxmoves, *bell, *score; char keys[10]; { int x,y,nx,ny,deadyet =0, sx = -1,sy = -1,tx = -1,ty = -1,lx = 0,ly = 0,mx = -1,my = -1, bx, by, nbx, nby, tmpx,tmpy, newnum, max_score = 250, diamonds = 0, nf = 0,hd ,vd ,xdirection,ydirection; char (*frow)[ROWLEN+1] = screen, ch, buffer[25]; static char howdead[25]; /* M001 can't use auto var for return value */ direction new_disp; struct mon_rec *monster,*current; tail_of_list = &start_of_list; for(x=0;x<=ROWLEN;x++) for(y=0;y<NOOFROWS;y++) { if((screen[y][x] == '*')||(screen[y][x] == '+')) { diamonds++; max_score += 10; if(screen[y][x] == '+') max_score += 20; } if(screen[y][x] == 'A') /* note teleport arrival point & */ { /* replace with space */ tx = x; ty = y; screen[y][x] = ' '; } if(screen[y][x] == '@') { sx = x; sy = y; } if(screen[y][x] == 'M') /* Put megamonster in */ { mx = x; my = y; } if(screen[y][x] == 'S') /* link small monster to pointer chain */ { if((monster = make_monster(x,y)) == NULL) { strcpy(howdead,"running out of memory"); return howdead; } if(!viable(x,y-1)) /* make sure its running in the correct */ { /* direction.. */ monster->mx = 1; monster->my = 0; } else if(!viable(x+1,y)) { monster->mx = 0; monster->my = 1; } else if(!viable(x,y+1)) { monster->mx = -1; monster->my = 0; } else if(!viable(x-1,y)) { monster->mx = 0; monster->my = -1; } } if(screen[y][x] == '-') screen[y][x] = ' '; }; x=sx; y=sy; if((x == -1)&&(y == -1)) /* no start position in screen ? */ { strcpy(howdead,"a screen design error"); return(howdead); } update_game: /* M002 restored game restarts here */ move(0,48); (void) addstr("Score\t Diamonds"); move(1,48); (void) addstr("\tFound\tTotal"); move(3,48); (void) sprintf(buffer,"%d\t %d\t %d ",*score,nf,diamonds); (void) addstr(buffer); move(6,48); (void) sprintf(buffer,"Current screen %d",*num); (void) addstr(buffer); if(maxmoves != 0) (void) sprintf(buffer,"Moves remaining = %d ",maxmoves); else { (void) strcpy(buffer," Unlimited moves "); maxmoves = -1; }; move(15,48); (void) addstr(buffer); if(mx != -1) /* tell player if monster exists */ draw_symbol(48,10,'M'); else draw_symbol(48,10,' '); if(!debug_disp) display(sx,sy,frow,*score); else map(frow); /* ACTUAL GAME FUNCTION - Returns method of death in string */ while(deadyet == 0) { ch = getch(); nx=x; ny=y; if((ch == keys[3]) && (x <(ROWLEN-1))) /* move about - but thats obvious */ nx++; if((ch == keys[2]) && (x > 0)) nx--; if((ch == keys[1]) && (y <(NOOFROWS-1))) ny++; if((ch == keys[0]) && (y > 0)) ny--; if(ch == '1') /* Add or get rid of that awful sound */ { move(10,45); *bell = 1; (void) addstr("Bell ON "); move(16,0); refresh(); continue; } if(ch == '0') { *bell = 0; move(10,45); (void) addstr("Bell OFF"); move(16,0); refresh(); continue; } if(ch == '~') /* level jump */ { if((newnum = jumpscreen(*num)) == 0) { strcpy(howdead,"a jump error."); return howdead; } if(newnum != *num) { /* Sorry Greg, no points for free */ sprintf(howdead,"~%c",newnum); return howdead; } continue; } if(ch == '!') /* look at the map */ { if(debug_disp) continue; map(frow); display(sx,sy,frow,*score); continue; } if(ch == 'q') { strcpy(howdead,"quitting the game"); return howdead; } if(ch == '?') { helpme(); if(debug_disp) map(frow); else display(sx,sy,frow,*score); continue; } if((ch == '@')&&(!debug_disp)) { sx = x; sy = y; display(sx,sy,frow,*score); continue; } if(ch == '#') { debug_disp = 1 - debug_disp; if(debug_disp) map(frow); else { for(tmpy=0;tmpy<=(NOOFROWS+1);tmpy++) { move(tmpy,0); for(tmpx=0;tmpx<=(ROWLEN+2);tmpx++) addch(' '); } sx = x; sy = y; display(sx,sy,frow,*score); } continue; } if(ch == 'W') { redraw_screen(maxmoves,*num,*score,nf,diamonds,mx,sx,sy,frow); continue; } /* M002 Added save/restore game feature. Gregory H. Margo */ if(ch == 'S') /* save game */ { extern struct save_vars zz; /* stuff away important local variables to be saved */ /* so the game state may be acurately restored */ zz.z_x = x; zz.z_y = y; zz.z_nx = nx; zz.z_ny = ny; zz.z_sx = sx; zz.z_sy = sy; zz.z_tx = tx; zz.z_ty = ty; zz.z_lx = lx; zz.z_ly = ly; zz.z_mx = mx; zz.z_my = my; zz.z_bx = bx; zz.z_by = by; zz.z_nbx = nbx; zz.z_nby = nby; zz.z_max_score = max_score; zz.z_diamonds = diamonds; zz.z_nf = nf; zz.z_hd = hd; zz.z_vd = vd; zz.z_xdirection = xdirection; zz.z_ydirection = ydirection; save_game(*num, score, bell, maxmoves, &start_of_list, tail_of_list); /* NOTREACHED */ } if(ch == 'R') /* restore game */ { extern struct save_vars zz; restore_game(num, score, bell, &maxmoves, &start_of_list, &tail_of_list); /* recover important local variables */ x = zz.z_x; y = zz.z_y; nx = zz.z_nx; ny = zz.z_ny; sx = zz.z_sx; sy = zz.z_sy; tx = zz.z_tx; ty = zz.z_ty; lx = zz.z_lx; ly = zz.z_ly; mx = zz.z_mx; my = zz.z_my; bx = zz.z_bx; by = zz.z_by; nbx = zz.z_nbx; nby = zz.z_nby; max_score = zz.z_max_score; diamonds = zz.z_diamonds; nf = zz.z_nf; hd = zz.z_hd; vd = zz.z_vd; xdirection = zz.z_xdirection; ydirection = zz.z_ydirection; if (maxmoves == -1) maxmoves = 0; /* to get the "unlimited moves" message */ goto update_game; /* the dreaded goto */ } if(screen[ny][nx] == 'C') { screen[ny][nx] = ':'; *score+=4; if(maxmoves != -1) maxmoves+=250; } switch(screen[ny][nx]) { case '@': break; case '*': *score+=9; max_score -= 10; nf++; case ':': *score+=1; move(3,48); sprintf(buffer,"%d\t %d",*score,nf); (void) addstr(buffer); case ' ': screen[y][x] = ' '; screen[ny][nx] = '@'; if(!debug_disp) { draw_symbol((x-sx+5)*3,(y-sy+3)*2,' '); draw_symbol((nx-sx+5)*3,(ny-sy+3)*2,'@'); } else { move(y+1,x+1); addch(' '); move(ny+1,nx+1); addch('@'); } deadyet += check(&mx,&my,x,y,nx-x,ny-y,sx,sy,howdead); move(16,0); refresh(); y = ny; x = nx; break; case 'O': if(screen[y][nx*2-x] == 'M') { screen[y][nx*2-x] = ' '; mx = my = -1; *score+=100; move(3,48); sprintf(buffer,"%d\t %d\t %d ",*score,nf,diamonds); (void) addstr(buffer); draw_symbol(48,10,' '); move(16,0); refresh(); } if(screen[y][nx*2-x] == ' ') { screen[y][nx*2-x] = 'O'; screen[y][x] = ' '; screen[ny][nx] = '@'; if(!debug_disp) { draw_symbol((x-sx+5)*3,(y-sy+3)*2,' '); draw_symbol((nx-sx+5)*3,(ny-sy+3)*2,'@'); if(nx*2-x>sx-6&&nx*2-x<sx+6) draw_symbol((nx*2-x-sx+5)*3,(y-sy+3)*2,'O'); } else { move(y+1,x+1); addch(' '); move(ny+1,nx+1); addch('@'); move(y+1,nx*2-x+1); addch('O'); } deadyet += fall(&mx,&my,nx*2-x,y+1,sx,sy,howdead); deadyet += fall(&mx,&my,x*2-nx,y,sx,sy,howdead); deadyet += fall(&mx,&my,x,y,sx,sy,howdead); deadyet += fall(&mx,&my,x,y-1,sx,sy,howdead); deadyet += fall(&mx,&my,x,y+1,sx,sy,howdead); move(16,0); refresh(); y = ny; x = nx; } break; case '^': if(screen[y][nx*2-x] == ' ') { screen[y][nx*2-x] = '^'; screen[y][x] = ' '; screen[ny][nx] = '@'; if(!debug_disp) { draw_symbol((x-sx+5)*3,(y-sy+3)*2,' '); draw_symbol((nx-sx+5)*3,(ny-sy+3)*2,'@'); if(nx*2-x>sx-6&&nx*2-x<sx+6) draw_symbol((nx*2-x-sx+5)*3,(y-sy+3)*2,'^'); } else { move(y+1,x+1); addch(' '); move(ny+1,nx+1); addch('@'); move(y+1,nx*2-x+1); addch('^'); } deadyet += fall(&mx,&my,nx*2-x,y-1,sx,sy,howdead); deadyet += fall(&mx,&my,x*2-nx,y,sx,sy,howdead); deadyet += fall(&mx,&my,x,y,sx,sy,howdead); deadyet += fall(&mx,&my,x,y+1,sx,sy,howdead); deadyet += fall(&mx,&my,x,y-1,sx,sy,howdead); move(16,0); refresh(); y = ny; x = nx; } break; case '<': case '>': if(screen[ny*2-y][x] == 'M') { screen[ny*2-y][x] = ' '; mx = my = -1; *score+=100; move(3,48); sprintf(buffer,"%d\t %d\t %d ",*score,nf,diamonds); (void) addstr(buffer); draw_symbol(48,10,' '); move(16,0); refresh(); } if(screen[ny*2-y][x] == ' ') { screen[ny*2-y][x] = screen[ny][nx]; screen[y][x] = ' '; screen[ny][nx] = '@'; if(!debug_disp) { draw_symbol((x-sx+5)*3,(y-sy+3)*2,' '); draw_symbol((nx-sx+5)*3,(ny-sy+3)*2,'@'); if(ny*2-y>sy-4&&ny*2-y<sy+4) draw_symbol((x-sx+5)*3,(ny*2-y-sy+3)*2,screen[ny*2-y][x]); } else { move(y+1,x+1); addch(' '); move(ny+1,nx+1); addch('@'); move(ny*2-y+1,x+1); addch(screen[ny*2-y][x]); } deadyet += fall(&mx,&my,x,y,sx,sy,howdead); deadyet += fall(&mx,&my,x-1,(ny>y)?y:(y-1),sx,sy,howdead); deadyet += fall(&mx,&my,x+1,(ny>y)?y:(y-1),sx,sy,howdead); deadyet += fall(&mx,&my,x-1,ny*2-y,sx,sy,howdead); deadyet += fall(&mx,&my,x+1,ny*2-y,sx,sy,howdead); move(16,0); refresh(); y = ny; x = nx; } break; case '!': strcpy(howdead,"an exploding landmine"); deadyet = 1; if(!debug_disp) { draw_symbol((x-sx+5)*3,(y-sy+3)*2,' '); draw_symbol((nx-sx+5)*3,(ny-sy+3)*2,'@'); } else { move(y+1,x+1); addch(' '); move(ny+1,nx+1); addch('@'); } move(16,0); refresh(); break; case 'X': if(nf == diamonds) { *score+=250; showpass(*num); return NULL; } break; case 'T': if(tx > -1) { screen[ny][nx] = ' '; screen[y][x] = ' '; lx = x; ly = y; y = ty; x = tx; screen[y][x] = '@'; sx = x; sy = y; *score += 20; move(3,48); sprintf(buffer,"%d\t %d\t %d ",*score,nf,diamonds); (void) addstr(buffer); if(!debug_disp) display(sx,sy,frow,*score); else map(frow); deadyet = fall(&mx,&my,nx,ny,sx,sy,howdead); if(deadyet == 0) deadyet = fall(&mx,&my,lx,ly,sx,sy,howdead); if(deadyet == 0) deadyet = fall(&mx,&my,lx+1,ly-1,sx,sy,howdead); if(deadyet == 0) deadyet = fall(&mx,&my,lx+1,ly+1,sx,sy,howdead); if(deadyet == 0) deadyet = fall(&mx,&my,lx-1,ly+1,sx,sy,howdead); if(deadyet == 0) deadyet = fall(&mx,&my,lx-1,ly-1,sx,sy,howdead); move(16,0); refresh(); } else { screen[ny][nx] = ' '; printf("Teleport out of order"); } break; case 'M': strcpy(howdead,"a hungry monster"); deadyet = 1; if(!debug_disp) draw_symbol((x-sx+5)*3,(y-sy+3)*2,' '); else { move(y+1,x+1); addch(' '); } move(16,0); refresh(); break; case 'S': strcpy(howdead,"walking into a monster"); deadyet = 1; if(!debug_disp) draw_symbol((x-sx+5)*3,(y-sy+3)*2,' '); else { move(y+1,x+1); addch(' '); } move(16,0); refresh(); break; default: break; } if((y == ny) && (x == nx) && (maxmoves>0)) { (void) sprintf(buffer,"Moves remaining = %d ",--maxmoves); move(15,48); (void) addstr(buffer); } if(maxmoves == 0) { strcpy(howdead,"running out of time"); return(howdead); } if(!debug_disp) { if ((x<(sx-3))&& (deadyet ==0)) /* screen scrolling if necessary */ { sx-=6; if(sx < 4) sx = 4; display(sx,sy,frow,*score); } if ((y<(sy-2))&& (deadyet == 0)) { sy-=5; if(sy < 2) sy = 2; display(sx,sy,frow,*score); } if ((x>(sx+3)) && (deadyet == 0)) { sx+=6; if(sx>(ROWLEN -5)) sx = ROWLEN -5; display(sx,sy,frow,*score); } if ((y>(sy+2))&& (deadyet ==0)) { sy+=5; if(sy > (NOOFROWS-3)) sy = NOOFROWS -3; display(sx,sy,frow,*score); } } /* MONSTER SECTION */ /* big monster first */ if(mx == -2) /* has the monster been killed ? */ { *score+=100; mx = my = -1; move(3,48); sprintf(buffer,"%d\t %d\t",*score,nf); (void) addstr(buffer); draw_symbol(48,10,' '); move(16,0); refresh(); } /* if monster still alive */ if(mx != -1) /* then move that monster ! */ { screen[my][mx] = ' '; if(mx>x) xdirection = -1; else xdirection = 1; if(!debug_disp) { if((my<(sy+4))&&(my>(sy-4))&&(mx<(sx+6))&&(mx>(sx-6))) draw_symbol((mx-sx+5)*3,(my-sy+3)*2,' '); } else { move(my+1,mx+1); addch(' '); } if((hd = (mx-x))<0) hd = -hd; if((vd = (my-y))<0) vd = -vd; if((hd>vd)&&((screen[my][mx+xdirection] == ' ')||(screen[my][mx+xdirection] == '@'))) mx+=xdirection; else { if(my>y) ydirection = -1; else ydirection = 1; if((screen[my+ydirection][mx] == ' ')||(screen[my+ydirection][mx] == '@')) my+=ydirection; else if((screen[my][mx+xdirection] == ' ')||(screen[my][mx+xdirection] == '@')) mx+=xdirection; } if(!debug_disp) { if((my<(sy+4))&&(my>(sy-4))&&(mx<(sx+6))&&(mx>(sx-6))) draw_symbol((mx-sx+5)*3,(my-sy+3)*2,'M'); } else { move(my+1,mx+1); addch('M'); } if(screen[my][mx] == '@') /* ha! gottim! */ { strcpy(howdead,"a hungry monster"); move(16,0); refresh(); return(howdead); } screen[my][mx] = 'M'; move(16,0); refresh(); } current = &start_of_list; /* baby monsters now */ while((current != tail_of_list)&&(!deadyet)) /* deal with those little monsters */ { monster = current->next; new_disp = new_direction( monster->x, monster->y, monster->mx, monster->my ); if(monster->under!='S') /* if on top of another baby */ { screen[monster->y][monster->x] = monster->under; if(!debug_disp) { if((monster->y < (sy+4)) && (monster->y > (sy-4)) && (monster->x < (sx+6)) && (monster->x > (sx-6))) draw_symbol((monster->x-sx+5)*3,(monster->y-sy+3)*2,monster->under); } else { move(monster->y+1,monster->x+1); addch(monster->under); } if(monster->under == ' ') deadyet+=check(&mx,&my,monster->x,monster->y,new_disp.d[0],new_disp.d[1],sx,sy,howdead); } else monster->under=' '; monster->mx = new_disp.d[0]; monster->my = new_disp.d[1]; monster->x += monster->mx; monster->y += monster->my; monster->under = screen[monster->y][monster->x]; screen[monster->y][monster->x] = 'S'; /* move into new space */ if(!debug_disp) { if((monster->y < (sy+4)) && (monster->y > (sy-4)) && (monster->x < (sx+6)) && (monster->x > (sx-6))) draw_symbol((monster->x-sx+5)*3,(monster->y-sy+3)*2,'S'); } else { move(monster->y+1,monster->x+1); addch('S'); } if(monster->under == '@') /* monster hit you? */ { strcpy(howdead,"the little monsters"); move(16,0); refresh(); return(howdead); } if(monster->under == '+') /* monster hit cage? */ { *score +=20; max_score -= 20; move(3,48); sprintf(buffer,"%d\t %d\t %d ",*score,nf,diamonds); (void) addstr(buffer); /* remove from chain, and insert at the end (at last_of_list) */ if(monster == tail_of_list) tail_of_list = tail_of_list->prev; else { current->next = monster-> next; current->next->prev = current; monster->next = NULL; monster->prev = last_of_list; last_of_list->next = monster; last_of_list = monster; } screen[monster->y][monster->x] = '*'; if(!debug_disp) { if((monster->y < (sy+4)) && (monster->y > (sy-4)) && (monster->x < (sx+6)) && (monster->x > (sx-6))) draw_symbol((monster->x-sx+5)*3,(monster->y-sy+3)*2,'*'); } else { move(monster->y+1,monster->x+1); addch('*'); } } else current = monster; move(16,0); refresh(); } if((edit_mode)&&(deadyet)) { /* stop death if testing */ if(!debug_disp) move(18,0); else move(20,0); addstr("You were killed by "); addstr(howdead); addstr("\nPress 'c' to continue."); refresh(); ch=getch(); if(ch == 'c') deadyet = 0; if(!debug_disp) move(18,0); else move(20,0); addstr(" "); addstr("\n "); refresh(); } } return(howdead); }