diff options
Diffstat (limited to 'hacks/pacman_ai.c')
-rw-r--r-- | hacks/pacman_ai.c | 876 |
1 files changed, 876 insertions, 0 deletions
diff --git a/hacks/pacman_ai.c b/hacks/pacman_ai.c new file mode 100644 index 0000000..b85bd96 --- /dev/null +++ b/hacks/pacman_ai.c @@ -0,0 +1,876 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/*- + * Copyright (c) 2002 by Edwin de Jong <mauddib@gmx.net>. + * + * Permission to use, copy, modify, and distribute this software and its + * documentation for any purpose and without fee is hereby granted, + * provided that the above copyright notice appear in all copies and that + * both that copyright notice and this permission notice appear in + * supporting documentation. + * + * This file is provided AS IS with no warranties of any kind. The author + * shall have no liability with respect to the infringement of copyrights, + * trade secrets or any patents by this file or any part thereof. In no + * event will the author be liable for any lost revenue or profits or + * other special, indirect and consequential damages. + */ + +/* this file handles the AI of the ghosts and the pacman. */ + +#include <math.h> +#include <assert.h> +#include "pacman.h" +#include "pacman_ai.h" +#include "pacman_level.h" + +#define MI_DISPLAY(MI) ((MI)->dpy) +#define MI_WINDOW(MI) ((MI)->window) +#define MI_WIDTH(MI) ((MI)->xgwa.width) +#define MI_HEIGHT(MI) ((MI)->xgwa.height) + +#define DIRVECS 4 +static const struct +{ + int dx, dy; +} dirvecs[DIRVECS] = { { +-1, 0}, { +0, 1}, { +1, 0}, { +0, -1}}; + +/* positions that match the dirvecs */ +typedef enum {pos_none = -1, pos_left = 0, pos_up = 1, pos_right = 2, pos_down = 3} pos; + + +/* fills array of DIRVECS size with possible directions, returns number of + directions. 'posdirs' points to a possibly undefined array of four + integers. The vector will contain booleans wether the direction is + a possible direction or not. Reverse directions are deleted. */ +static int +ghost_get_posdirs (pacmangamestruct * pp, int *posdirs, ghoststruct * g) +{ + unsigned int i, nrdirs = 0; + unsigned int can_go_in = 0; + + /* bit of black magic here */ + for (i = 0; i < DIRVECS; i++) { + /* remove opposite */ + if (g->lastbox != NOWHERE && i == (g->lastbox + 2) % DIRVECS + && (g->aistate != goingout )) { + posdirs[i] = 0; + continue; + } + if (g->aistate == goingout && i == 1) { + posdirs[i] = 0; + continue; + } + /* check if possible direction */ + can_go_in = (g->aistate == goingout || g->aistate == goingin); + if ((posdirs[i] = + pacman_check_pos (pp, g->row + dirvecs[i].dy, + g->col + dirvecs[i].dx, + can_go_in)) == True) { + nrdirs++; + } + } + + return nrdirs; +} + +/* Directs ghost to a random direction, exluding opposite (except in the + impossible situation that there is only one valid direction). */ +static void +ghost_random (pacmangamestruct * pp, ghoststruct * g) +{ + int posdirs[DIRVECS], nrdirs = 0, i, dir = 0; + + nrdirs = ghost_get_posdirs (pp, posdirs, g); +#if 0 + g->ndirs = nrdirs; +#endif + for (i = 0; i < DIRVECS; i++) + if (posdirs[i] == True) + dir = i; + + if (nrdirs == 0) + dir = (g->lastbox + 2) % DIRVECS; + else if (nrdirs > 1) + for (i = 0; i < DIRVECS; i++) { + if (posdirs[i] == True && NRAND (nrdirs) == 0) { + dir = i; + break; + } + } + + g->nextrow = g->row + dirvecs[dir].dy; + g->nextcol = g->col + dirvecs[dir].dx; + g->lastbox = dir; +} + +/* Determines best direction to chase the pacman and goes that direction. */ +static void +ghost_chasing (pacmangamestruct * pp, ghoststruct * g) +{ + int posdirs[DIRVECS], nrdirs = 0, i, dir = 0, highest = -100000, + thisvecx, thisvecy, thisvec; + + nrdirs = ghost_get_posdirs (pp, posdirs, g); +#if 0 + g->ndirs = nrdirs; +#endif + for (i = 0; i < DIRVECS; i++) + if (posdirs[i] == True) + dir = i; + + if (nrdirs == 0) + dir = (g->lastbox + 2) % DIRVECS; + else if (nrdirs > 1) + for (i = 0; i < DIRVECS; i++) { + if (posdirs[i] == False) + continue; + thisvecx = (pp->pacman.col - g->col) * dirvecs[i].dx; + thisvecy = (pp->pacman.row - g->row) * dirvecs[i].dy; + thisvec = thisvecx + thisvecy; + if (thisvec >= highest) { + dir = i; + highest = thisvec; + } + } + + g->nextrow = g->row + dirvecs[dir].dy; + g->nextcol = g->col + dirvecs[dir].dx; + g->lastbox = dir; +} + +/* Determines the best direction to go away from the pacman, and goes that + direction. */ +static void +ghost_hiding (pacmangamestruct * pp, ghoststruct * g) +{ + int posdirs[DIRVECS], nrdirs = 0, i, dir = 0, highest = -100000, + thisvecx, thisvecy, thisvec; + + nrdirs = ghost_get_posdirs (pp, posdirs, g); +#if 0 + g->ndirs = nrdirs; +#endif + for (i = 0; i < DIRVECS; i++) + if (posdirs[i] == True) + dir = i; + + if (nrdirs == 0) + dir = (g->lastbox + 2) % DIRVECS; + else if (nrdirs > 1) + for (i = 0; i < DIRVECS; i++) { + if (posdirs[i] == False) + continue; + thisvecx = (g->col - pp->pacman.col) * dirvecs[i].dx; + thisvecy = (g->row - pp->pacman.row) * dirvecs[i].dy; + thisvec = thisvecx + thisvecy; + if (thisvec >= highest) + dir = i; + } + + g->nextrow = g->row + dirvecs[dir].dy; + g->nextcol = g->col + dirvecs[dir].dx; + g->lastbox = dir; +} + +#if 1 +static void +clear_trace(ghoststruct *g) +{ + int i = 0; + g->trace_idx = 0; + while (i < GHOST_TRACE){ + g->trace[i].vx = -1; + g->trace[i++].vy = -1; + } +} + + +static void +save_position (ghoststruct *g, int x, int y) +{ + int i = g->trace_idx; + assert ( 0 <= i && i < GHOST_TRACE ); + g->trace[i].vx = x; + g->trace[i].vy = y; + g->trace_idx++; +} + +static int +already_tried (ghoststruct *g, int x, int y) +{ + int i = 0; + if (! ( 0 <= g->trace_idx && g->trace_idx < GHOST_TRACE ) ){ + fprintf(stderr, "FOUND TRACE ERROR. DUMPING TRACE.\n"); + fprintf(stderr, "%d\n", g->trace_idx ); + for ( i = 0; i < GHOST_TRACE; i++ ){ + fprintf(stderr, "( %d, %d )\n", g->trace[i].vx, g->trace[i].vy ); + } + assert ( False ); + } + while (i < g->trace_idx){ + if ( x == g->trace[i].vx && y == g->trace[i].vy ){ + /* fprintf ( stderr, "Match FOUND (%d, %d)\n", x, y); */ + return 1; + } + i++; + } + return 0; +} +#endif + +static void +store_dir ( ghoststruct *g, pos ps ){ + int i = g->home_count; + assert ( 0 <= i && i < GHOST_TRACE ); + g->way_home[i].vx = dirvecs[ps].dx; + g->way_home[i].vy = dirvecs[ps].dy; + g->home_count++; +} + +static void +clear_dir ( ghoststruct *g ){ + int i = 0; + g->home_count = 0; + g->home_idx = 0; + while (i < GHOST_TRACE){ + g->way_home[i].vx = -1; + g->way_home[i++].vy = -1; + } +} + +static int +found_jail ( int col, int row ){ + int cx, cy; + pacman_get_jail_opening ( &cx, &cy ); + cy += 1; + if (row == cy && col == cx ) + return 1; + else + return 0; +} + +static int +move_ghost ( pacmangamestruct * pp, + int row, int col, + pos ps, + int *new_row, int *new_col){ + int idx = (int)ps; + int tr = row + dirvecs[idx].dx; + int tc = col + dirvecs[idx].dy; + if ( pacman_check_pos ( pp, tr, tc, True )){ + *new_row = tr; + *new_col = tc; + return True; + } + else { + return False; + } +} + +static int +recur_back_track ( pacmangamestruct * pp, ghoststruct *g, int row, int col ){ + int new_row, new_col; + + if ( already_tried ( g, col, row ) ) + return False; + + if ( found_jail ( col, row ) ) + return True; + + save_position ( g, col, row ); + + if ( move_ghost ( pp, row, col, pos_left, &new_row, &new_col )) + if ( recur_back_track ( pp, g, new_row, new_col )){ + store_dir ( g, pos_left ); + return True; + } + + if ( move_ghost ( pp, row, col, pos_up, &new_row, &new_col )) + if ( recur_back_track ( pp, g, new_row, new_col )){ + store_dir ( g, pos_up ); + return True; + } + + if ( move_ghost ( pp, row, col, pos_down, &new_row, &new_col )) + if ( recur_back_track ( pp, g, new_row, new_col )){ + store_dir ( g, pos_down ); + return True; + } + + if ( move_ghost ( pp, row, col, pos_right, &new_row, &new_col )) + if ( recur_back_track ( pp, g, new_row, new_col )){ + store_dir ( g, pos_right ); + return True; + } + + return False; +} + +static void +find_home ( pacmangamestruct *pp, ghoststruct *g ){ + int i; + int r,c; + int cx, cy; + ghoststruct *tmp_ghost; + tmp_ghost = (ghoststruct*)malloc(sizeof ( ghoststruct )); + if ( tmp_ghost == NULL ){ + fprintf(stderr, "find_home : Could not allocate memory."); + exit ( 1 ); + } + tmp_ghost = memmove(tmp_ghost, g, sizeof ( ghoststruct )); + if ( tmp_ghost == NULL ){ + fprintf(stderr, "find_home : Could not copy memory."); + exit ( 1 ); + } + clear_trace ( tmp_ghost ); + clear_dir ( tmp_ghost ); + r = tmp_ghost->row; + c = tmp_ghost->col; + if ( ! recur_back_track ( pp, tmp_ghost, r, c ) ){ + fprintf(stderr, "Could not find way home.#@$?\n"); + pacman_get_jail_opening ( &cx, &cy); + fprintf(stderr, "Jail was at (%d%d)\n", cx,cy); + } + for ( i = 0; i < GHOST_TRACE; i++ ){ + g->way_home[i].vx = tmp_ghost->way_home[i].vx; + g->way_home[i].vy = tmp_ghost->way_home[i].vy; + } + g->home_count = tmp_ghost->home_count; + g->home_idx = tmp_ghost->home_count; + free(tmp_ghost); +} + +/* Make the ghost go back to the inbox */ +static void +ghost_goingin (pacmangamestruct * pp, ghoststruct * g) +{ + g->home_idx--; + if (g->home_idx < 0){ g->aistate = goingout; return;} + /* row == vx ? wtf... Don't Ask */ + g->nextrow = g->row + g->way_home[g->home_idx].vx; + g->nextcol = g->col + g->way_home[g->home_idx].vy; +} + + +/* Determines a vector from the pacman position, towards all dots. The vector + is inversely proportional to the square of the distance of each dot. + (so, close dots attract more than far away dots). */ +static void +pac_dot_vec (pacmangamestruct * pp, pacmanstruct * p, long *vx, long *vy) +{ + int x, y, bx = 0, by = 0, ex = LEVWIDTH, ey = LEVHEIGHT; + long dx, dy, dist, top = 0; + +#if 0 + int rnr = NRAND (50); + /* determine begin and end vectors */ + + switch (rnr) { + case 0: + ex = LEVHEIGHT / 2; + break; + case 1: + bx = LEVHEIGHT / 2; + break; + case 2: + ey = LEVHEIGHT / 2; + break; + case 3: + by = LEVHEIGHT / 2; + break; + } +#endif + *vx = *vy = 0; + + for (y = by; y < ey; y++) + for (x = bx; x < ex; x++) + if (pacman_check_dot (pp, x, y) == 1) { + dx = (long) x - (long) (p->col); + dy = (long) y - (long) (p->row); + dist = dx * dx + dy * dy; + if (dist > top) + top = dist; + *vx += (dx * ((long) LEVWIDTH * (long) LEVHEIGHT)) + / dist; + *vy += (dy * ((long) LEVWIDTH * (long) LEVHEIGHT)) + / dist; + } +} + +/* Determine a vector towards the closest ghost (in one loop, so we spare a + couple of cycles which we can spoil somewhere else just as fast). */ +static int +pac_ghost_prox_and_vector (pacmangamestruct * pp, pacmanstruct * p, + int *vx, int *vy) +{ + int dx, dy, dist, closest = 100000; + unsigned int g; + + if (vx != NULL) + *vx = *vy = 0; + + for (g = 0; g < pp->nghosts; g++) { + if (pp->ghosts[g].dead == True || + pp->ghosts[g].aistate == inbox || + pp->ghosts[g].aistate == goingout) + continue; + dx = pp->ghosts[g].col + /*dirvecs[pp->ghosts[g].lastbox].dx */ - + p->col; + dy = pp->ghosts[g].row + /*dirvecs[pp->ghosts[g].lastbox].dy */ - + p->row; + dist = dx * dx + dy * dy; + if (dist < closest) { + closest = dist; + if (vx != NULL) { + *vx = dx; + *vy = dy; + } + } + } + return closest; +} + +/* fills array of DIRVECS size with possible directions, returns number of + directions. posdirs should point to an array of 4 integers. */ +static int +pac_get_posdirs (pacmangamestruct * pp, pacmanstruct * p, int *posdirs) +{ + int nrdirs = 0; + unsigned int i; + + for (i = 0; i < DIRVECS; i++) { + /* if we just ate, or we are in a statechange, it is allowed + * to go the opposite direction */ + if (p->justate == 0 && + p->state_change == 0 && + p->lastbox != NOWHERE && i == (p->lastbox + 2) % DIRVECS) { + posdirs[i] = 0; + } + else if ((posdirs[i] = + pacman_check_pos (pp, p->row + dirvecs[i].dy, + p->col + dirvecs[i].dx, 0)) == 1) + nrdirs++; + } + p->state_change = 0; + + return nrdirs; +} + +/* Clears the trace of vectors. */ +void +pacman_clear_trace (pacmanstruct * p) +{ + int i; + + for (i = 0; i < TRACEVECS; i++) { + p->trace[i].vx = NOWHERE; + p->trace[i].vy = NOWHERE; + } + p->cur_trace = 0; +} + +/* Adds a new vector to the trace. */ +static void +pac_save_trace (pacmanstruct * p, const int vx, const int vy) +{ + if (!(vx == NOWHERE && vy == NOWHERE)) { + p->trace[p->cur_trace].vx = vx; + p->trace[p->cur_trace].vy = vy; + p->cur_trace = (p->cur_trace + 1) % TRACEVECS; + } +} + +/* Check if a vector can be found in the trace. */ +static int +pac_check_trace (const pacmanstruct * p, const int vx, const int vy) +{ + int i, curel; + + for (i = 1; i < TRACEVECS; i++) { + curel = (p->cur_trace - i + TRACEVECS) % TRACEVECS; + if (p->trace[curel].vx == NOWHERE && p->trace[curel].vy == NOWHERE) + continue; + if (p->trace[curel].vx == vx && p->trace[curel].vy == vy) + return 1; + } + + + return 0; +} + +/* AI mode "Eating" for pacman. Tries to eat as many dots as possible, goes + to "hiding" if too close to a ghost. If in state "hiding" the vectors + of the ghosts are also taken into account (thus not running towards them + is the general idea). */ +static void +pac_eating (pacmangamestruct * pp, pacmanstruct * p) +{ + int posdirs[DIRVECS], nrdirs, i, highest = -(1 << 16), + score, dir = 0, dotfound = 0, prox, worst = 0; + int vx, vy; + + if ((prox = pac_ghost_prox_and_vector (pp, p, &vx, &vy)) < + 4 * 4 && p->aistate == ps_eating) { + p->aistate = ps_hiding; + p->state_change = 1; + pacman_clear_trace (p); + } + + if (prox > 6 * 6 && p->aistate == ps_hiding) { + p->aistate = ps_eating; + if (p->justate == 0) + p->state_change = 1; + pacman_clear_trace (p); + } + + if (prox < 3 * 3) + p->state_change = 1; + + nrdirs = pac_get_posdirs (pp, p, posdirs); + + /* remove directions which lead to ghosts */ + if (p->aistate == ps_hiding) { + for (i = 0; i < DIRVECS; i++) { + if (posdirs[i] == 0) + continue; + score = vx * dirvecs[i].dx + vy * dirvecs[i].dy; + if (score > highest) { + worst = i; + highest = score; + } + dir = i; + } + nrdirs--; + posdirs[worst] = 0; + highest = -(1 << 16); + } + + /* get last possible direction if all else fails */ + for (i = 0; i < DIRVECS; i++) + if (posdirs[i] != 0) + dir = i; + + { + long lvx = vx; + long lvy = vy; + pac_dot_vec (pp, p, &lvx, &lvy); + vx = lvx; + vy = lvy; + } + + if (vx != NOWHERE && vy != NOWHERE && pac_check_trace (p, vx, vy) > 0) { + p->roundscore++; + if (p->roundscore >= 12) { + p->roundscore = 0; + p->aistate = ps_random; + pacman_clear_trace (p); + } + } + else + p->roundscore = 0; + + if (p->justate == 0) + pac_save_trace (p, vx, vy); + + for (i = 0; i < DIRVECS; i++) { + if (posdirs[i] == 0) + continue; + score = dirvecs[i].dx * vx + dirvecs[i].dy * vy; + if (pacman_check_dot (pp, p->col + dirvecs[i].dx, + p->row + dirvecs[i].dy) == 1) { + if (dotfound == 0) { + highest = score; + dir = i; + dotfound = 1; + } + else if (score > highest) { + highest = score; + dir = i; + } + } + else if (score > highest && dotfound == 0) { + dir = i; + highest = score; + } + } + + p->nextrow = p->row + dirvecs[dir].dy; + p->nextcol = p->col + dirvecs[dir].dx; + p->lastbox = dir; +} + +#if 1 +/* Tries to catch the ghosts. */ +static void +pac_chasing (pacmangamestruct * pp, pacmanstruct * p) +{ + int posdirs[DIRVECS], nrdirs, i, highest = -(1 << 16), + score, dir = 0, worst = 0; + int vx = 0, vy = 0; + + nrdirs = pac_get_posdirs (pp, p, posdirs); + + /* keep directions which lead to ghosts */ + for (i = 0; i < DIRVECS; i++) { + if (posdirs[i] == 0) + continue; + score = vx * dirvecs[i].dx + vy * dirvecs[i].dy; + if (score < highest) { + worst = i; + highest = score; + } + dir = i; + } + nrdirs--; + posdirs[worst] = 0; + + + /* get last possible direction if all else fails */ + for (i = 0; i < DIRVECS; i++) + if (posdirs[i] != 0) + dir = i; + + { + long lvx = vx; + long lvy = vy; + pac_dot_vec (pp, p, &lvx, &lvy); + vx = lvx; + vy = lvy; + } + + if (vx != NOWHERE && vy != NOWHERE && pac_check_trace (p, vx, vy) > 0) { + p->roundscore++; + if (p->roundscore >= 12) { + p->roundscore = 0; + p->aistate = ps_random; + pacman_clear_trace (p); + } + } + else + p->roundscore = 0; + + + p->nextrow = p->row + dirvecs[dir].dy; + p->nextcol = p->col + dirvecs[dir].dx; + p->lastbox = dir; +} +#endif + +/* Goes completely random, but not in the opposite direction. Used when a + loop is detected. */ +static void +pac_random (pacmangamestruct * pp, pacmanstruct * p) +{ + int posdirs[DIRVECS], nrdirs, i, dir = -1, lastdir = 0; + + if (pac_ghost_prox_and_vector (pp, p, NULL, NULL) < 5 * 5) { + p->aistate = ps_hiding; + p->state_change = 1; + } + if (NRAND (20) == 0) { + p->aistate = ps_eating; + p->state_change = 1; + pacman_clear_trace (p); + } + + nrdirs = pac_get_posdirs (pp, p, posdirs); + + for (i = 0; i < DIRVECS; i++) { + if (posdirs[i] == 0) + continue; + lastdir = i; + if (pacman_check_dot (pp, p->col + dirvecs[i].dx, + p->row + dirvecs[i].dy) == 1) { + dir = i; + p->aistate = ps_eating; + p->state_change = 1; + pacman_clear_trace (p); + break; + } + else if (NRAND (nrdirs) == 0) + dir = i; + } + + if (dir == -1) + dir = lastdir; + + p->nextrow = p->row + dirvecs[dir].dy; + p->nextcol = p->col + dirvecs[dir].dx; + p->lastbox = dir; +} + +static int +pac_get_vector_screen (pacmangamestruct * pp, pacmanstruct * p, + const int x, const int y, int *vx, int *vy) +{ + int lx, ly; + + lx = (x - pp->xb) / pp->xs; + ly = (y - pp->yb) / pp->ys; + + if (lx < 0) + lx = 0; + else if ((unsigned int) lx > LEVWIDTH) + lx = LEVWIDTH - 1; + + if (ly < 0) + ly = 0; + else if ((unsigned int) ly > LEVHEIGHT) + ly = LEVHEIGHT - 1; + + *vx = lx - p->col; + *vy = ly - p->row; + + if (lx == p->oldlx && ly == p->oldly) + return 0; + p->oldlx = lx; + p->oldly = ly; + return 1; +} + +static int +pac_trackmouse (ModeInfo * mi, pacmangamestruct * pp, pacmanstruct * p) +{ + int dx, dy, cx, cy, vx, vy; + unsigned int m; + int posdirs[DIRVECS], i, dir = -1, highest = -(2 << 16), score; + Window r, c; + + (void) XQueryPointer (MI_DISPLAY (mi), MI_WINDOW (mi), + &r, &c, &dx, &dy, &cx, &cy, &m); + + if (cx <= 0 || cy <= 0 || + cx >= MI_WIDTH (mi) - 1 || cy >= MI_HEIGHT (mi) - 1) + return 0; + /* get vector */ + p->state_change = pac_get_vector_screen (pp, p, cx, cy, &vx, &vy); + + (void) pac_get_posdirs (pp, p, posdirs); + + for (i = 0; i < DIRVECS; i++) { + if (posdirs[i] == 0) + continue; + score = dirvecs[i].dx * vx + dirvecs[i].dy * vy; + if (score > highest) { + highest = score; + dir = i; + } + } + + p->nextrow = p->row + dirvecs[dir].dy; + p->nextcol = p->col + dirvecs[dir].dx; + p->lastbox = dir; + return 1; +} + +/* Calls correct state function, and changes between states. */ +void +pacman_ghost_update (pacmangamestruct * pp, ghoststruct * g) +{ + + if (!(g->nextrow == NOWHERE && g->nextcol == NOWHERE)) { + g->row = g->nextrow; + g->col = g->nextcol; + } + + if ((g->aistate == randdir || g->aistate == chasing) && NRAND (10) == 0) { + switch (NRAND (3)) { + case 0: + g->aistate = randdir; + break; + case 1: + g->aistate = chasing; + break; + case 2: + g->aistate = chasing; + break; + } + + } + else if (g->aistate == inbox) { + if (g->timeleft < 0) + g->aistate = goingout; + else + g->timeleft--; + + } + else if (g->aistate == goingout) { + if (g->col < LEVWIDTH / 2 - JAILWIDTH / 2 || + g->col > LEVWIDTH / 2 + JAILWIDTH / 2 || + g->row < LEVHEIGHT / 2 - JAILHEIGHT / 2 || + g->row > LEVHEIGHT / 2 + JAILHEIGHT / 2) + g->aistate = randdir; + } + + switch (g->aistate) { + case inbox: + case goingout: + case randdir: + ghost_random (pp, g); + break; + case chasing: + ghost_chasing (pp, g); + break; + case hiding: + ghost_hiding (pp, g); + break; + case goingin: + if ( g->wait_pos ){ + find_home(pp, g); + g->wait_pos = False; + } + ghost_goingin (pp, g); + break; + } + + g->cfactor = GETFACTOR (g->nextcol, g->col); + g->rfactor = GETFACTOR (g->nextrow, g->row); +} + +/* Calls correct pacman state function. */ +void +pacman_update (ModeInfo * mi, pacmangamestruct * pp, pacmanstruct * p) +{ + if (!(p->nextrow == NOWHERE && p->nextcol == NOWHERE)) { + p->row = p->nextrow; + p->col = p->nextcol; + } + + if (pp->level[p->row * LEVWIDTH + p->col] == '.' || + pp->level[p->row * LEVWIDTH + p->col] == 'o') { + pp->level[p->row * LEVWIDTH + p->col] = ' '; + if (!pacman_trackmouse) + p->justate = 1; + pp->dotsleft--; + } + else if (!pacman_trackmouse) { + p->justate = 0; + } + + if (!(pacman_trackmouse && pac_trackmouse (mi, pp, p))) { + /* update pacman */ + switch (p->aistate) { + case ps_eating: + pac_eating (pp, p); + break; + case ps_hiding: + pac_eating (pp, p); + break; + case ps_random: + pac_random (pp, p); + break; + case ps_chasing: + pac_chasing (pp, p); + break; + case ps_dieing: + break; /* Don't move */ + } + } + + p->cfactor = GETFACTOR (p->nextcol, p->col); + p->rfactor = GETFACTOR (p->nextrow, p->row); +} |