|
|
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.