|
|
1.1 ! root 1: /*----------------------------------------------------------------------*/ ! 2: /* */ ! 3: /* PACMAN for BBN BitGraphs */ ! 4: /* */ ! 5: /* File: monsters.c68 */ ! 6: /* Contents: monster definitions and manipulation routines */ ! 7: /* Author: Bob Brown (rlb) */ ! 8: /* Purdue CS */ ! 9: /* Date: May, 1982 */ ! 10: /* Description: Initialization, movement, drawing routines. */ ! 11: /* Interacts with several pacman routines. */ ! 12: /* */ ! 13: /*----------------------------------------------------------------------*/ ! 14: ! 15: #include "style.h" ! 16: #include "pacman.h" ! 17: ! 18: /* ! 19: ** Monster structure initialization ! 20: ** ! 21: ** The following lists the static part of the monster structures, in the order ! 22: ** that they leave the stable. ! 23: */ ! 24: ! 25: monster Monster[MAXMONSTER] = { ! 26: { 45, 36, MOVEUP, 0, 5, -10 }, ! 27: { 45, 41, MOVEUP, 24, 0, -20 }, /* fast, but stupid */ ! 28: { 39, 33, MOVEDOWN, 52, 9, 0 }, ! 29: { 39, 48, MOVEDOWN, 80, 13, 5 }, /* slow, but methodical */ ! 30: }; ! 31: ! 32: /* ! 33: ** monnew - create a new set of monsters. ! 34: ** ! 35: ** Called once at the beginning of a game. ! 36: */ ! 37: ! 38: monnew() ! 39: { ! 40: register monster *mptr; ! 41: for ( mptr=Monster ; mptr < &Monster[MAXMONSTER] ; mptr++ ) ! 42: mptr->time = Monbase + mptr->inittime; ! 43: } ! 44: ! 45: /* ! 46: ** moninit - reinitialize the monsters. ! 47: ** ! 48: ** Called at the beginning of each wave or when Pacman dies. ! 49: */ ! 50: ! 51: moninit() ! 52: { ! 53: register monster *mptr; ! 54: for ( mptr=Monster ; mptr < &Monster[MAXMONSTER] ; mptr++ ) { ! 55: if ( mptr == Monster ) { ! 56: mptr->row = STARTROW; ! 57: mptr->col = STARTCOL; ! 58: mptr->dir = MOVERIGHT; ! 59: mptr->movestate = ROAMING; ! 60: } else { ! 61: mptr->row = mptr->initrow; ! 62: mptr->col = mptr->initcol; ! 63: mptr->dir = mptr->initdir; ! 64: mptr->movestate = STABLED; ! 65: } ! 66: mptr->mrow = SCtoMZ(mptr->row); ! 67: mptr->mcol = SCtoMZ(mptr->col); ! 68: mptr->state = DANGEROUS; ! 69: mptr->delay = mptr->initdelay; ! 70: mptr->font = MONSTERCHAR[0]; ! 71: Monseeking = FALSE; ! 72: mondraw(mptr); ! 73: eladd(mptr->time+STARTDELAY,monmove,(char *)mptr); ! 74: } ! 75: } ! 76: /* ! 77: ** monfont - change the font of the monsters. ! 78: ** ! 79: ** Called when Pacman swallows a pill or starts getting weaker. ! 80: */ ! 81: ! 82: monfont(chr) ! 83: char chr; ! 84: { ! 85: register monster *mptr; ! 86: for ( mptr=Monster ; mptr < &Monster[MAXMONSTER] ; mptr++ ) { ! 87: monfont1(mptr,chr); ! 88: } ! 89: } ! 90: ! 91: monfont1(mptr,chr) ! 92: register monster *mptr; ! 93: char chr; ! 94: { ! 95: mondraw(mptr); ! 96: mptr->font = chr; ! 97: mondraw(mptr); ! 98: } ! 99: /* ! 100: ** moncomp - turn on/off (i.e. complement) all the monsters ! 101: */ ! 102: ! 103: moncomp() ! 104: { ! 105: register monster *mptr; ! 106: for ( mptr=Monster ; mptr < &Monster[MAXMONSTER] ; mptr++ ) ! 107: mondraw(mptr); ! 108: } ! 109: ! 110: /* ! 111: ** mondraw - complement a single monster ! 112: */ ! 113: ! 114: mondraw(mptr) ! 115: register monster *mptr; ! 116: { ! 117: blt40(mptr->font,mptr->row,mptr->col,INVERT); ! 118: } ! 119: ! 120: /* ! 121: ** Move a particular monster ! 122: ** ! 123: ** This routine moves a given monster based its current movestate ! 124: */ ! 125: ! 126: int ! 127: monmove(mptr) ! 128: register monster *mptr; ! 129: { ! 130: register move *newmove; ! 131: int newdelay; ! 132: /* ! 133: ** Motion depends on the monster movestate ! 134: */ ! 135: mondraw(mptr); ! 136: switch ( mptr->movestate ) { ! 137: /* ! 138: ** In the center box - won't come out until time delay elapses and ! 139: ** the pacman isn't dangerous (fixes ambush bug). ! 140: */ ! 141: case STABLED: ! 142: newmove = bounce(mptr); ! 143: if ( mptr->delay > 0 ) ! 144: mptr->delay = max(mptr->delay-1,0); ! 145: else ! 146: mptr->movestate = LEAVING; ! 147: break; ! 148: case LEAVING: ! 149: newmove = tostart(mptr); ! 150: if ( newmove->row == STARTROW && newmove->col == STARTCOL ) ! 151: mptr->movestate = ROAMING; ! 152: break; ! 153: /* ! 154: ** If roaming about, switch to seeking if someone sees him and fall ! 155: ** into seeking code. ! 156: */ ! 157: case ROAMING: ! 158: if ( Monseeking ) ! 159: mptr->movestate = SEEKING; ! 160: else if ( seeshim(mptr) ) { ! 161: Monseeking = TRUE; ! 162: mptr->movestate = SEEKING; ! 163: } else { ! 164: newmove = dumbmove(mptr); ! 165: break; ! 166: } ! 167: /* ! 168: ** When seeking the pacman, they may always make a random move. if the ! 169: ** Pacman is powerful, then they move away if edible, else random. ! 170: */ ! 171: case SEEKING: ! 172: if ( grand(0,100) < Seekprob+mptr->bonus && !Pacman.safe && !(Pacman.power>0 && mptr->state==DANGEROUS)) ! 173: newmove = seekmove(mptr); ! 174: else ! 175: newmove = dumbmove(mptr); ! 176: break; ! 177: case HOMING: ! 178: newmove = todoor(mptr); ! 179: if ( newmove->row == STARTROW && newmove->col == STARTCOL ) ! 180: mptr->movestate = HOMING2; ! 181: break; ! 182: case HOMING2: ! 183: newmove = tostable(mptr); ! 184: if ( newmove->row==mptr->initrow && newmove->col==mptr->initcol ) { ! 185: mptr->movestate = STABLED; ! 186: mptr->state = DANGEROUS; ! 187: mptr->font = MONSTERCHAR[mptr->initdir]; ! 188: newmove->dir = mptr->initdir; ! 189: mptr->delay = Pacman.power+(mptr-Monster)*24; ! 190: } ! 191: break; ! 192: } ! 193: /* ! 194: ** Move the monster on the screen ! 195: */ ! 196: mptr->row = newmove->row; ! 197: mptr->col = newmove->col; ! 198: mptr->dir = newmove->dir; ! 199: mptr->mrow = SCtoMZ(mptr->row); ! 200: mptr->mcol = SCtoMZ(mptr->col); ! 201: if ( mptr->state == DANGEROUS ) ! 202: mptr->font = MONSTERCHAR[mptr->dir]; ! 203: mondraw(mptr); ! 204: /* ! 205: ** Check for collision with the pacman ! 206: */ ! 207: if ( mptr->state == DANGEROUS && collide(mptr) && Pacman.alive ) { ! 208: pacdie(); ! 209: return; ! 210: } ! 211: /* ! 212: ** The time till next move depends on whether the monster is alive, ! 213: ** or is in the slow corridor, or is weakened by the pacman's power. ! 214: */ ! 215: newdelay = mptr->state==DEAD ? EYESDELAY : ! 216: inslow(mptr->row,mptr->col) ? Pacman.time+SLOWDELTA : ! 217: mptr->time+Pacman.power*POWERDELAY; ! 218: ! 219: eladd(newdelay,monmove,mptr); ! 220: } ! 221: /* ! 222: ** Simplest of all possible move commands - chooses random direction ! 223: */ ! 224: move * ! 225: dumbmove(mptr) ! 226: register monster *mptr; ! 227: { ! 228: register int moves; ! 229: static move movelist[4]; ! 230: if ( !aligns(mptr->row, mptr->col) ) { ! 231: onestep(mptr->row,mptr->col,mptr->dir,&movelist[0]); ! 232: return movelist; ! 233: } ! 234: moves=compmoves(mptr->row,mptr->col,movelist,mptr->dir,FALSE); ! 235: if (moves == 1 ) ! 236: return movelist; ! 237: return &movelist[grand(0,moves-1)]; ! 238: } ! 239: /* ! 240: ** Direction seeking Monster move ! 241: */ ! 242: move * ! 243: seekmove(mptr) ! 244: register monster *mptr; ! 245: { ! 246: register int moves; ! 247: static move movelist[4]; ! 248: if ( !aligns(mptr->row, mptr->col) ) { ! 249: onestep(mptr->row,mptr->col,mptr->dir,&movelist[0]); ! 250: return movelist; ! 251: } ! 252: /* ! 253: ** Monsters can reverse once when the pacman swallows a pill - ! 254: ** Should save it until the pacman is close (unimplemented). ! 255: */ ! 256: if ( mptr->canreverse ) { ! 257: moves=compmoves(mptr->row,mptr->col,movelist,0,FALSE); ! 258: mptr->canreverse = FALSE; ! 259: } else ! 260: moves=compmoves(mptr->row,mptr->col,movelist,mptr->dir,FALSE); ! 261: if (moves == 1 ) ! 262: return movelist; ! 263: if ( mptr->state == EDIBLE ) ! 264: return furthest(movelist,moves,Pacman.row,Pacman.col); ! 265: return closest(movelist,moves,Pacman.row,Pacman.col); ! 266: } ! 267: /* ! 268: ** Compute all the possible moves a monster can make. ! 269: ** ! 270: */ ! 271: ! 272: compmoves(mrow, mcol, list, curdir, doorok) ! 273: int mrow, mcol, curdir; ! 274: register move *list; ! 275: bool doorok; ! 276: { ! 277: register int moves, i; ! 278: /* ! 279: ** The list of moves will not include the direction opposite ! 280: ** of curdir, if it is nonzero. This statement computes the ! 281: ** opposite direction effeciently. ! 282: */ ! 283: if ( curdir > 0 ) ! 284: curdir = ((curdir+1)&3)+1; ! 285: moves = 0; ! 286: for ( i=1 ; i<=4 ; i++ ) { ! 287: if ( i == curdir ) ! 288: continue; ! 289: onestep(mrow,mcol,i,list); ! 290: if ( (doorok && hitdoor(list->row,list->col)) || ! 291: !(hitwall(list->row,list->col,i)||(i==MOVEUP&&hitblk(list->row,list->col))) ) { ! 292: list++; ! 293: moves++; ! 294: } ! 295: } ! 296: return moves; ! 297: } ! 298: onestep(mrow, mcol, dir, list) ! 299: register int mrow, mcol, dir; ! 300: register move *list; ! 301: { ! 302: list->col = mcol; ! 303: list->row = mrow; ! 304: list->dir = dir; ! 305: switch ( dir ) { ! 306: case MOVERIGHT: ! 307: list->col++; ! 308: break; ! 309: case MOVEUP: ! 310: list->row--; ! 311: break; ! 312: case MOVELEFT: ! 313: list->col--; ! 314: break; ! 315: case MOVEDOWN: ! 316: list->row++; ! 317: break; ! 318: } ! 319: if ( list->col < 0 ) ! 320: list->col += MZtoSC(MAZECOLS); ! 321: if ( list->col >= MZtoSC(MAZECOLS) ) ! 322: list->col = 0; ! 323: } ! 324: /* ! 325: ** Choose the move from a list the goes in the direction closest to a ! 326: ** given point. ! 327: ** ! 328: ** SCREEN COORDINATES ! 329: */ ! 330: move * ! 331: closest(list,moves,row,col) ! 332: register move *list; ! 333: register int moves; ! 334: register int row, col; ! 335: { ! 336: register move *lptr; ! 337: int dist, diff, diffr, diffc; ! 338: dist = 0x7fff; ! 339: for ( ; moves>0 ; moves-- ) { ! 340: diffr = iabs(row-list->row); ! 341: diffc = iabs(col-list->col); ! 342: diff = max(diffr,diffc); ! 343: if ( diff < dist ) { ! 344: lptr = list; ! 345: dist = diff; ! 346: } ! 347: list++; ! 348: } ! 349: return lptr; ! 350: } ! 351: move * ! 352: furthest(list,moves,row,col) ! 353: register move *list; ! 354: register int moves; ! 355: register int row, col; ! 356: { ! 357: register move *lptr; ! 358: int dist, diff, diffr, diffc; ! 359: dist = -1; ! 360: for ( ; moves>0 ; moves-- ) { ! 361: diffr = iabs(row-list->row); ! 362: diffc = iabs(col-list->col); ! 363: diff = min(diffr,diffc); ! 364: if ( diff > dist ) { ! 365: lptr = list; ! 366: dist = diff; ! 367: } ! 368: list++; ! 369: } ! 370: return lptr; ! 371: } ! 372: ! 373: /* ! 374: ** Check if a monster "sees" the pacman ! 375: */ ! 376: seeshim(mptr) ! 377: register monster *mptr; ! 378: { ! 379: register int rdiff, cdiff; ! 380: register int i; ! 381: rdiff = abs(mptr->row - Pacman.row); ! 382: cdiff = abs(mptr->col - Pacman.col); ! 383: switch ( mptr->dir ) { ! 384: case MOVERIGHT: ! 385: if ( rdiff > 3 || mptr->col > Pacman.col ) ! 386: return FALSE; ! 387: for ( i=mptr->mcol ; i<Pacman.mcol ; i++ ) ! 388: if ( (Board[mptr->mrow][i]&TYPEMASK) <= WALLMAX ) ! 389: return FALSE; ! 390: return TRUE; ! 391: case MOVEUP: ! 392: if ( cdiff > 3 || mptr->row < Pacman.row ) ! 393: return FALSE; ! 394: for ( i=mptr->mrow ; i>Pacman.mrow ; i-- ) ! 395: if ( (Board[i][mptr->mcol]&TYPEMASK) <= WALLMAX ) ! 396: return FALSE; ! 397: return TRUE; ! 398: case MOVELEFT: ! 399: if ( rdiff > 3 || mptr->col < Pacman.col ) ! 400: return FALSE; ! 401: for ( i=mptr->mcol ; i>Pacman.mcol ; i-- ) ! 402: if ( (Board[mptr->mrow][i]&TYPEMASK) <= WALLMAX ) ! 403: return FALSE; ! 404: return TRUE; ! 405: case MOVEDOWN: ! 406: if ( cdiff > 3 || mptr->row > Pacman.row ) ! 407: return FALSE; ! 408: for ( i=mptr->mrow ; i<Pacman.mrow ; i++ ) ! 409: if ( (Board[i][mptr->mcol]&TYPEMASK) <= WALLMAX ) ! 410: return FALSE; ! 411: return TRUE; ! 412: } ! 413: } ! 414: ! 415: /* ! 416: ** Bounce the monster around in the stable ! 417: */ ! 418: move * ! 419: bounce(mptr) ! 420: register monster *mptr; ! 421: { ! 422: static move newmove; ! 423: onestep(mptr->row, mptr->col, mptr->dir, &newmove); ! 424: if ( hitwall(newmove.row, newmove.col,mptr->dir) ) { ! 425: mptr->dir = ((mptr->dir+1)&3)+1; ! 426: onestep(mptr->row, mptr->col, mptr->dir, &newmove); ! 427: } ! 428: return &newmove; ! 429: } ! 430: /* ! 431: ** move a monster closer to the starting position ! 432: */ ! 433: move * ! 434: tostart(mptr) ! 435: register monster *mptr; ! 436: { ! 437: static move movelist[4]; ! 438: int moves; ! 439: moves = compmoves(mptr->row, mptr->col, movelist, mptr->dir, TRUE); ! 440: if ( mptr->col != STARTCOL ) ! 441: return closest(movelist,moves, mptr->row, STARTCOL); ! 442: return closest(movelist,moves, STARTROW, STARTCOL); ! 443: } ! 444: /* ! 445: ** Move the monster towards the door ! 446: */ ! 447: move * ! 448: todoor(mptr) ! 449: register monster *mptr; ! 450: { ! 451: static move movelist[4]; ! 452: int moves; ! 453: if ( !aligns(mptr->row, mptr->col) ) { ! 454: onestep(mptr->row,mptr->col,mptr->dir,&movelist[0]); ! 455: return movelist; ! 456: } ! 457: moves = compmoves(mptr->row, mptr->col, movelist, mptr->dir, FALSE); ! 458: return closest(movelist,moves, STARTROW, STARTCOL); ! 459: ! 460: } ! 461: /* ! 462: ** move a monster back to the stable ! 463: */ ! 464: move * ! 465: tostable(mptr) ! 466: register monster *mptr; ! 467: { ! 468: static move movelist[4]; ! 469: int moves; ! 470: moves = compmoves(mptr->row, mptr->col, movelist, mptr->dir, TRUE); ! 471: if ( mptr->row!=mptr->initrow ) ! 472: return closest(movelist,moves, mptr->initrow, mptr->col); ! 473: return closest(movelist,moves, mptr->initrow, mptr->initcol); ! 474: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.