#include #include "state.h" #include #include /** * Return the current score */ unsigned int current_score() { unsigned short a, b, c; c = machine->readByte(0x4e80); b = machine->readByte(0x4e89); a = machine->readByte(0x4e8A); char score[20]; snprintf(score, 19, "%x", (a << 16) | (b << 8) | c); return strtol(score, NULL, 10); } /** * Return the number of remaining life */ unsigned int remaining_lifes() { return machine->readByte(0x4e14); } /** * Return the level number * FIXME: is it working ?? */ unsigned int level_number() { return machine->readByte(0x4e13); } /** * Guess if a game session is still preparing (showing "Ready!") */ bool is_game_preparing() { /* 0x4020 seems to be the start of the level in graphical memory */ return machine->readByte(0x4020 + (20-2) + (0x20*(28-13))) != 0x40; } /** * Check if a point (c) belongs to a segment ([a-b]) * Return the percentage of traject between a and b * or -1 if not on segment * * WARNING: it is assumed we have only horizontal or * vertical segments */ static float is_point_on_segment(position_t n1_pos, position_t n2_pos, position_t target, direction_t dir) { /* n1 and n2 are in normalized position while target has * raw position */ /* a: upper/left point * b: lower/right point * c: target coord */ int a, b, c; /* * Determine if it's a vertical or horizontal * edge */ if ( n1_pos.x != n2_pos.x ) { if ( (target.y/8) != n1_pos.y ) return -1; /* Horizontal */ /* Sort them */ a = ( n1_pos.x < n2_pos.x ) ? n1_pos.x : n2_pos.x; b = ( n1_pos.x > n2_pos.x ) ? n1_pos.x : n2_pos.x; c = target.x; } else { if ( (target.x/8) != n1_pos.x ) return -1; /* Vertical */ /* Sort them */ a = ( n1_pos.y < n2_pos.y ) ? n1_pos.y : n2_pos.y; b = ( n1_pos.y > n2_pos.y ) ? n1_pos.y : n2_pos.y; c = target.y; } /* Center target */ a = a*8 + 4; b = b*8 + 4; /* We are not on the segment */ if ( a > c || b < c ) return -1; /* Compute delta between (a and c) and (a and b) */ int d_a_c = c - a; int d_a_b = b - a; float perc = d_a_c / (float)d_a_b; if ( dir == DIR_UP || dir == DIR_LEFT ) return 1 - perc; else return perc; } /** * Check if a point (c) belongs to a tunnel path * Return the percentage of traject between a and b * or -1 if not on tunnel path */ static float is_point_on_tunnel(position_t n1_pos, position_t n2_pos, position_t target, direction_t dir) { int a, b; /* X coordinate of left/right node */ /* We're not on same y coordinate, can't be us */ if ( n1_pos.y != (target.y/8) ) return -1; a = (n1_pos.x < n2_pos.x) ? n1_pos.x*8+4 : n2_pos.x*8+4; b = (n1_pos.x > n2_pos.x) ? n1_pos.x*8+4 : n2_pos.x*8+4; float percent; /* In left part of tunnel */ if ( target.x >= -8 && target.x <= a ) { percent = ((target.x + 8) / float(a + 4)) / 2.0; if ( dir == DIR_RIGHT ) percent += 0.5; else percent = 0.5 - percent; } /* In right part of tunnel */ if ( target.x >= b && target.x <= 247 ) { percent = ((target.x - b) / float(247 - b)) / 2.0; if ( dir == DIR_LEFT ) percent = 0.5 - percent + 0.5; } return percent; } /** * Try to find if an actor is on a node */ static int actor_node_finder(node_t *n, void *data) { actor_state_t *p = (actor_state_t*)data; position_t *node_pos = (position_t*)n->data; if ( p->norm_pos.x == node_pos->x && p->norm_pos.y == node_pos->y ) return 1; else return 0; } /** * Try to find if an actor is on an edge */ static int actor_edge_finder(edge_t *edge, void *data) { actor_state_t *p = (actor_state_t*)data; position_t *n1_pos = (position_t*)edge->n1->data; position_t *n2_pos = (position_t*)edge->n2->data; int a, b; /* we'll have to check between these two points */ int c; /* This is pacman position to check between a and b */ int d, e; /* The edge/pacman position to check on the other coordinate */ edge_data_t *ed = (edge_data_t*)edge->data; float percent; if ( ed->type == CORR_TUNNEL ) percent = is_point_on_tunnel(*n1_pos, *n2_pos, (*p).pos, p->going); else percent = is_point_on_segment(*n1_pos, *n2_pos, (*p).pos, p->going); if ( percent >= 0 ) { /* Set on which edge pacman is and its percentage */ p->edge = edge; p->percent = percent; return 1; } else return 0; } /** * Get state of pacman */ actor_state_t get_pacman_state(level_t *level) { actor_state_t res; const PacmanSprite *pacman = machine->getSprite(5); /* There's a swap */ if ( pacman->color != 9 && pacman->color != 0 ) pacman = machine->getSprite(1); /* Add 8 because pacman is made by 4 "8x8" pictures * So that, we center it */ res.pos.x = pacman->x + 8; res.pos.y = pacman->y + 8; /* Normalized position (the case # of screen, cf : * http://www.csh.rit.edu/~jerry/arcade/pacman/daves/) */ res.norm_pos.x = (pacman->x + 8) / 8; res.norm_pos.y = (pacman->y + 8) / 8; /* Get pacman direction */ switch ( pacman->n ) { /* Unique shapes */ case 54: res.going = DIR_UP; break; case 55: res.going = DIR_RIGHT; break; case 52: res.going = DIR_DOWN; break; /* Shared shapes */ case 53: if ( pacman->mode == 0x03 ) res.going = DIR_UP; else res.going = DIR_LEFT; break; case 45: case 47: if ( pacman->mode == 0x02 ) res.going = DIR_LEFT; else res.going = DIR_RIGHT; break; case 49: case 51: if ( pacman->mode == 0x03 ) res.going = DIR_UP; else res.going = DIR_DOWN; break; case 63: res.going = DIR_NONE; res.state = PAC_DEAD; break; default: printf("WARNING : Unhandled pacman shape : %d\n", pacman->n); } /* Compute advancement on the edge */ //node_t *n = graph_node_find(level->graph, &res.pacman, actor_node_finder); /* Locate on which edge we are */ edge_t *e = graph_edge_find(level->graph, &res, actor_edge_finder); if ( ! e ) { //assert(!"We should always be able to track pacman!"); printf("WARN : Pacman is lost!!\n"); } res.visible = true; return res; } /** * Get state of specified ghost */ actor_state_t get_ghost_state(level_t *level, ghost_t g) { actor_state_t res; const PacmanSprite *ghost; /* By default, we think we have a normal ghost */ res.state = GHOST_NORMAL; res.visible = true; /* Get the right sprite depending on ghost */ switch ( g ) { case BLINKY: ghost = machine->getSprite(1); if ( ghost->color == 9 || ghost->color == 0 ) // #9 is pacman's color ghost = machine->getSprite(5); break; case PINKY: ghost = machine->getSprite(2); break; case INKY: ghost = machine->getSprite(3); break; case SUE: ghost = machine->getSprite(4); break; } /* * What do colors mean ? * * 0 : Not visible * 1, 3, 5, 7 : Blinky, Pinky, Inky, Sue * 24 : Blue * 18 : White (when going back to normal state) * 25 : Dead * 17 : Scoring (ex: 200, 400, ...) */ switch ( ghost->color ) { case 24: case 18: res.state = GHOST_EATABLE; break; case 0: case 25: case 17: res.state = GHOST_DEAD; break; } res.pos.x = ghost->x + 8; res.pos.y = ghost->y + 8; res.norm_pos.x = (ghost->x + 8) / 8; res.norm_pos.y = (ghost->y + 8) / 8; /* * How are sprites coded ? * * Normal states * 32, 33 : Going Right * 34, 35 : Going Down * 36, 37 : Going Left * 37, 38 : Going Up * * Eatable states * 28, 29 : Blue */ switch ( ghost->n ) { /* Right */ case 32: case 33: res.looking = DIR_RIGHT; break; /* Down */ case 34: case 35: res.looking = DIR_DOWN; break; /* Left */ case 36: case 37: res.looking = DIR_LEFT; break; /* Up */ case 38: case 39: res.looking = DIR_UP; break; /* Eatable */ case 28: case 29: res.looking = DIR_NONE; res.state = GHOST_EATABLE; break; /* Scoring, so ghost dead */ case 40: case 41: res.state = GHOST_DEAD; break; default: printf("WARNING : Unknow shape (%d) for ghost %d\n", ghost->n, g); break; } res.going = res.looking; edge_t *e = graph_edge_find(level->graph, &res, actor_edge_finder); if ( ! e ) { //assert(!"We should always be able to track pacman!"); printf("WARN : A ghost is lost!!\n"); } return res; } /** * Get state of specified bonus */ actor_state_t get_bonus_state(level_t *level, bonus_t b) { actor_state_t res; const PacmanSprite *bonus=NULL; switch( b ) { case BONUS_1: bonus = machine->getSprite(6); break; case BONUS_2: bonus = machine->getSprite(7); break; } //printf("Bonus dir : %d, %d\n", bonus->n, bonus->mode); res.visible = (bonus->color != 0); res.pos.x = bonus->x + 8; res.pos.y = bonus->y + 8; res.norm_pos.x = (bonus->x + 8) / 8; res.norm_pos.y = (bonus->y + 8) / 8; edge_t *e = graph_edge_find(level->graph, &res, actor_edge_finder); if ( ! e ) { //assert(!"We should always be able to track pacman!"); printf("WARN : A bonus is lost!!\n"); } return res; } /** * Guess actor state on a level */ actors_state_t guess_actors_state(level_t *level) { actors_state_t res; foreach_ghost res.ghosts[ghost] = get_ghost_state(level, ghost); res.pacman = get_pacman_state(level); res.bonuses[BONUS_1] = get_bonus_state(level, BONUS_1); res.bonuses[BONUS_2] = get_bonus_state(level, BONUS_2); //printf("pacman shape = %d, %d\n",r res.ghosts[BLINKY]., pacman->color); return res; } /** * Draw edges on a Dib24 picture */ void draw_edges(graph_t *g, edge_t *e, void *data) { Dib24 *canvas = (Dib24*)data; Uint32 edge_color = SDL_MapRGB(canvas->getHandle()->format, 0xFF, 0x00, 0x00); position_t *p1 = (position_t*)(e->n1->data); position_t *p2 = (position_t*)(e->n2->data); edge_data_t *d = (edge_data_t*)e->data; /* If we have a tunnel, we can't draw it from p1 to p2 because * it will go through the screen instead of connecting picture * sides */ if ( d->type == CORR_TUNNEL ) { position_t *a = (p1->x < p2->x) ? p1 : p2; position_t *b = (p2->x < p1->x) ? p1 : p2; line32(canvas->getHandle(), 0, a->y*8+4, a->x*8+4, a->y*8+4, edge_color); line32(canvas->getHandle(), b->x*8+4, b->y*8+4, 224, b->y*8+4, /* FIXME : Harcoded value, 224 = Display width */ edge_color); } else line32(canvas->getHandle(), p1->x*8+4, p1->y*8+4, p2->x*8+4, p2->y*8+4, edge_color); } /** * Draw nodes on a Dib24 picture */ void draw_nodes(graph_t *g, node_t *n, void *data) { Dib24 *canvas = (Dib24*)data; Uint32 node_color = SDL_MapRGB(canvas->getHandle()->format, 0xFF, 0xFF, 0xFF); position_t *pos = (position_t*)(n->data); canvas->setPixel(pos->x*8+4, pos->y*8+4, node_color); } /** * Draw the level plus the actors on a Dib24 canvas */ void draw_debug(level_t *level, actors_state_t *st, Dib24 *canvas) { canvas->clear(); while ( SDL_MUSTLOCK(canvas->getHandle()) < 0 ) SDL_Delay(10); Uint32 colors[GHOST_COUNT]; colors[SUE] = SDL_MapRGB(canvas->getHandle()->format, 0xFF, 0xAA, 0x00); colors[PINKY] = SDL_MapRGB(canvas->getHandle()->format, 0xFF, 0x00, 0xFF); colors[INKY] = SDL_MapRGB(canvas->getHandle()->format, 0x00, 0xFF, 0xFF); colors[BLINKY] = SDL_MapRGB(canvas->getHandle()->format, 0xFF, 0x00, 0x00); Uint32 pac_color = SDL_MapRGB(canvas->getHandle()->format, 0xFF, 0xFF, 0x00); Uint32 bonus_color = SDL_MapRGB(canvas->getHandle()->format, 0xAA, 0xFF, 0x20); Uint32 node_color = SDL_MapRGB(canvas->getHandle()->format, 0xFF, 0xFF, 0xFF); /* Draw level */ graph_edge_visit(level->graph, canvas, draw_edges); graph_node_visit(level->graph, canvas, draw_nodes); /* Draw ghosts */ foreach_ghost { if ( st->ghosts[ghost].visible ) { for(int i=0;i<10;i++) { for(int j=0;j<10;j++) { if ( ghost_gfx[j][i] != 0 ) canvas->setFastPixel(st->ghosts[ghost].pos.x+i-4, st->ghosts[ghost].pos.y+j-4, colors[ghost]); } } } } /* Draw pacman */ if ( st->pacman.visible ) { for(int i=0;i<16;i++) { for(int j=0;j<16;j++) { if ( pacman_gfx[j][i] != 0 ) canvas->setFastPixel(st->pacman.pos.x+i-8, st->pacman.pos.y+j-8, pac_color); } } } /* Draw bonus1 */ if ( st->bonuses[BONUS_1].visible ) { for(int i=0;i<10;i++) { for(int j=0;j<10;j++) { if ( bonus1_gfx[j][i] != 0 ) canvas->setFastPixel(st->bonuses[BONUS_1].pos.x+i-4, st->bonuses[BONUS_1].pos.y+j-4, bonus_color); } } } /* Draw bonus2 */ if ( st->bonuses[BONUS_2].visible ) { for(int i=0;i<10;i++) { for(int j=0;j<10;j++) { if ( bonus2_gfx[j][i] != 0 ) canvas->setFastPixel(st->bonuses[BONUS_2].pos.x+i+4, st->bonuses[BONUS_2].pos.y+j+4, bonus_color); } } } // const PacmanSprite *pacman = machine->getSprite(1); // printf("Shape is = %d, color is = %d\n", st->n, pacman->color); SDL_UnlockSurface(canvas->getHandle()); }