📄 bowl.c
字号:
}/*====================================================================Add a single tile at a random position so that it doesn't hit the current block nor leads to game over nor completes a line.====================================================================*/void bowl_add_tile( Bowl *bowl ){ int j, k; int added = 0; int i = rand() % bowl->w; int checks = 0; int hole; while ( checks < 10 ) { i++; checks++; if ( i == bowl->w ) i = 0; /* get first free tile in column */ if ( bowl->contents[i][1] != -1 ) continue; else j = 1; while ( j + 1 < bowl->h && bowl->contents[i][j + 1] == -1 ) j++; /* add tile and test if this hits the block if so remove and try another one */ bowl_set_tile( bowl, i, j, 9 ); if ( !bowl_validate_block_pos( bowl, bowl->block.x, bowl->block.check_y, bowl->block.rot_id, 0 ) ) { bowl_set_tile( bowl, i, j, -1 ); continue; } /* if this line was completed deny, too */ hole = 0; for ( k = 0; k < bowl->w; k++ ) if ( bowl->contents[k][j] == -1 ) { hole = 1; break; } if ( !hole ) { bowl_set_tile( bowl, i, j, -1 ); continue; } /* position worked out! */ added = 1; bowl_draw_tile( bowl, i, j ); break; } /* help shadow may have changed */ if ( added ) bowl_compute_help_pos( bowl );}/*====================================================================Add a line at the bottom of a bowl and return False if bowl is filled to the top. If the block position becomes invalid by thismove it's positioned one up.====================================================================*/int bowl_add_line( Bowl * bowl, int wanted_holes ){ int i, j, holes = 0, hole_x; /* if the first line containts a tile the game is over! */ for ( i = 0; i < bowl->w; i++ ) if ( bowl->contents[i][0] != -1 ) return 0; /* move all lines one up */ for ( j = 0; j < bowl->h - 1; j++ ) for ( i = 0; i < bowl->w; i++ ) bowl_set_tile( bowl, i, j, bowl->contents[i][j + 1] ); /* add a random line */ for ( i = 0; i < bowl->w; i++ ) bowl_set_tile( bowl, i, bowl->h - 1, rand() % BLOCK_TILE_COUNT ); /* add holes */ while ( holes < wanted_holes ) { hole_x = rand() % bowl->w; if ( bowl->contents[hole_x][bowl->h - 1] != -1 ) { bowl_set_tile( bowl, hole_x, bowl->h - 1, -1 ); holes++; } } /* check if block position became invalid */ if ( !bowl_validate_block_pos( bowl, bowl->block.x, bowl->block.check_y, bowl->block.rot_id, 0 ) ) { bowl->block.y = bowl->block.check_y / bowl->block_size - 1; bowl->block.check_y = bowl->block.y * bowl->block_size; bowl->block.cur_y = bowl->block.check_y; } /* update helping shadow */ bowl_compute_help_pos( bowl ); return 1;}/*====================================================================Initate final animation.====================================================================*/void bowl_final_animation( Bowl *bowl ) { int i, j, k; if ( bowl->blind ) return; for ( j = 0; j < bowl->h; j++ ) for ( i = 0, k = 1; i < bowl->w; i++, k++ ) if ( bowl->contents[i][j] != -1 ) shrapnell_create( bowl->sx + i * bowl->block_size, bowl->sy + j * bowl->block_size, bowl->block_size, bowl->block_size, 0, -0.05, 0, 0.0002 );}/*====================================================================Finish game and set game over.====================================================================*/void bowl_finish_game( Bowl *bowl ){ float score_mod = 0; bowl->game_over = 1; bowl->hide_block = 1; bowl_final_animation( bowl ); bowl->use_figures = 0; bowl_reset_contents( bowl ); bowl_draw_contents( bowl ); bowl->font->align = ALIGN_X_CENTER | ALIGN_Y_CENTER; write_text( bowl->font, offscreen, bowl->sx + bowl->sw / 2, bowl->sy + bowl->sh / 2, "Game Over", OPAQUE ); write_text( bowl->font, sdl.screen, bowl->sx + bowl->sw / 2, bowl->sy + bowl->sh / 2, "Game Over", OPAQUE );#ifdef SOUND if ( !bowl->mute ) sound_play( bowl->wav_explosion );#endif /* gain the bonus score */ if ( !config.preview || bowl->preview_center_sx == -1 ) score_mod += 0.15; if ( config.gametype != 2 ) score_mod += 0.015 * config.starting_level; if ( config.expert ) score_mod += 1.0; counter_add( &bowl->score, (int)( score_mod * counter_get( bowl->score )) );}/*====================================================================Actually insert block and remove a line if needed, create shrapnells, give score etc====================================================================*/void bowl_insert_block( Bowl *bowl ){ int i, j, l; int line_y[4]; int line_count; int line_score; int full; int old_level; int send_count; int shr_type; int py; /* move block y up so it gets to the first free place */ py = bowl->block.y * bowl->block_size; while ( !bowl_validate_block_pos( bowl, bowl->block.x, py, bowl->block.rot_id, 0 ) ) py -= bowl->block_size; bowl->block.y = py / bowl->block_size; /* insert and check if block is out of screen */ for ( i = 0; i < 4; i++ ) { for ( j = 0; j < 4; j++ ) { if ( block_masks[bowl->block.id].mask[bowl->block.rot_id][i][j] ) { if ( bowl->block.y + j < 0 ) bowl->game_over = 1; if ( bowl->block.x + i >= 0 && bowl->block.x + i < bowl->w ) if ( bowl->block.y + j >= 0 && bowl->block.y + j < bowl->h ) bowl_set_tile( bowl, bowl->block.x + i, bowl->block.y + j, bowl->block.id ); } } } /* draw block to offscreen for shrapnells */ bowl_draw_contents( bowl );#ifdef SOUND if ( !bowl->mute ) sound_play( bowl->wav_stop );#endif /* if game over just explode everything and return */ if ( bowl->game_over ) { bowl_finish_game( bowl ); return; } /* check for completed lines */ line_count = 0; for ( j = 0; j < bowl->h; j++ ) { full = 1; for ( i = 0; i < bowl->w; i++ ) { if ( bowl->contents[i][j] == -1 ) { full = 0; break; } } if ( full ) line_y[line_count++] = j; } for ( j = 0; j < line_count; j++ ) for ( i = 0; i < bowl->w; i++ ) { for ( l = line_y[j]; l > 0; l-- ) bowl_set_tile( bowl, i, l, bowl->contents[i][l - 1] ); bowl_set_tile( bowl, i, 0, -1 ); } /* tetris? tell him! */#ifdef SOUND if ( line_count == 4 ) if ( !bowl->mute ) sound_play( bowl->wav_excellent );#endif /* create shrapnells */ shr_type = rand() % SHR_TYPE_COUNT; if ( !bowl->blind ) for ( j = 0; j < line_count; j++ ) shrapnells_create( bowl->sx, bowl->sy + line_y[j] * bowl->block_size, bowl->sw, bowl->block_size, shr_type );#ifdef SOUND if ( line_count > 0 ) if ( !bowl->mute ) sound_play( bowl->wav_explosion );#endif /* add score */ line_score = 100 * ( bowl->level + 1 ); for ( i = 0; i < line_count; i++ ) { counter_add( &bowl->score, line_score ); line_score *= 2; } /* line and level update */ old_level = bowl->lines / 10; bowl->lines += line_count; if ( old_level != bowl->lines / 10 ) {#ifdef SOUND if ( !bowl->mute ) sound_play( bowl->wav_nextlevel );#endif /* new level */ bowl->level++; bowl_set_vert_block_vel( bowl ); /* in advanced game reset bowl contents */ if ( config.gametype == 2 ) { bowl_reset_contents( bowl ); } } /* reset delay of add_line/tile */ if ( line_count && ( bowl->add_lines || bowl->add_tiles ) && bowl->dismantle_saves ) delay_reset( &bowl->add_delay ); /* update offscreen&screen */ bowl->draw_contents = 1; /* send completed lines to all other bowls */ if ( line_count > 1 ) { send_count = line_count; if ( !config.send_all ) send_count--; if ( line_count == 4 && config.send_tetris ) send_count = 4; for ( i = 0; i < BOWL_COUNT; i++ ) if ( bowls[i] && bowls[i] != bowl && !bowls[i]->game_over) { for ( j = 0; j < send_count; j++ ) if ( !bowl_add_line( bowls[i], config.holes ) ) { bowl_finish_game( bowls[i] ); return; } bowls[i]->draw_contents = 1; } } /* get next block */ bowl_create_next_block( bowl );}/*====================================================================Check if the block collides at the current position and insert itif so.====================================================================*/int bowl_check_block_insertion( Bowl *bowl ){ int i, j; int cy; int collision = 0; /* check the bottom of the lowest tile in pixel_contents * if we drop block-by-block don't use the current position but * compute the lowest pixel from bowl position so we may * move a block below a neighbored one. */ for ( i = 0; i < 4; i++ ) { for ( j = 3; j >= 0; j-- ) if ( bowl->block.x + i >= 0 && bowl->block.x + i < bowl->w ) if ( block_masks[bowl->block.id].mask[bowl->block.rot_id][i][j] ) { /* if the lowest tile is still out of screen skip this column */ if ( bowl->block.y + j < 0 ) break; /* check tile hit by tile bottom */ cy = (int)bowl->block.check_y + j * bowl->block_size + bowl->block_size - 1/* last pixel of tile */; if ( cy < 0 ) break; if ( bowl->pixel_contents[bowl->block.x + i][cy] != -1 ) collision = 1; /* if the bowl bottom is hit it is a collision as well */ if ( cy >= bowl->sh ) collision = 1; break; } if ( collision ) break; } if ( !collision ) return 0; /* clear the down key so we don't move the next block too far */ if ( bowl->controls && keystate[bowl->controls->down] && config.clear_keystate ) keystate[bowl->controls->down] = 0; /* insert, gain score bla bla bla */ bowl_insert_block( bowl ); return 1;}/*====================================================================Drop block in one p-cycle.====================================================================*/void bowl_drop_block( Bowl *bowl ){ while ( !bowl_check_block_insertion( bowl ) ) { bowl->block.cur_y += bowl->block_size >> 1; bowl->block.y = (int)bowl->block.cur_y / bowl->block_size; /* update check y */ if ( config.block_by_block ) bowl->block.check_y = bowl->block.y * bowl->block_size; else bowl->block.check_y = (int)bowl->block.cur_y; } bowl->stored_key = -1;}/*====================================================================Return True if CPU may drop/move down.====================================================================*/int bowl_cpu_may_move_down( Bowl *bowl ){ if ( !bowl->controls && bowl->cpu_down && bowl->block.x == bowl->cpu_dest_x && bowl->block.rot_id == bowl->cpu_dest_rot ) return 1; return 0;}int bowl_cpu_may_drop( Bowl *bowl ){/* if ( config.cpu_diff == 5 && bowl_cpu_may_move_down( bowl ) ) return 1;*/ return 0;}/*====================================================================Publics====================================================================*//*====================================================================Load figures from file.====================================================================*/void bowl_load_figures() { int i, j, k; FILE *file = 0; char path[512]; char buf[128]; sprintf( path, "%s/figures", SRC_DIR ); if ( ( file = fopen( path, "r" ) ) == 0 ) { fprintf( stderr, "Cannot load figures from '%s'.\n", path ); return; } for ( i = 0; i < FIGURE_COUNT; i++ ) for ( j = 0; j < BOWL_HEIGHT; j++ ) { if ( feof( file ) ) { fprintf( stderr, "Unexpected end of file when trying to read line %i of figure %i in '%s'.\n", j, i, path ); return; } fread( buf, sizeof( char ), BOWL_WIDTH + 1, file ); buf[BOWL_WIDTH] = 0; for ( k = 0; k < BOWL_WIDTH; k++ ) { if ( buf[k] == 32 ) figures[i][k][j] = -1; else figures[i][k][j] = buf[k] - 97; } } fclose( file );}/*====================================================================Initate block masks.====================================================================*/void bowl_init_block_masks() { block_masks[0].rx = 0; block_masks[0].ry = 0; block_masks[0].id = 0; memset(block_masks[0].mask, 0, sizeof( int ) * 4 * 4 * 4 ); block_masks[0].mask[0][1][1] = 1; block_masks[0].mask[0][2][1] = 1; block_masks[0].mask[0][1][2] = 1; block_masks[0].mask[0][2][2] = 1; block_masks[0].mask[1][1][1] = 1; block_masks[0].mask[1][2][1] = 1;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -