📄 bowl.c
字号:
/*************************************************************************** bowl.c - description ------------------- begin : Tue Dec 25 2001 copyright : (C) 2001 by Michael Speck email : kulkanie@gmx.net ***************************************************************************//*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/#include "ltris.h"#include "config.h"#include "tools.h"#include "shrapnells.h"#include "cpu.h"#include "bowl.h"extern Config config;extern Sdl sdl;extern SDL_Surface *offscreen;extern SDL_Surface *bkgnd;extern int keystate[SDLK_LAST];extern Bowl *bowls[BOWL_COUNT];extern int cpu_original_bowl[BOWL_WIDTH][BOWL_HEIGHT];extern Block_Mask *cpu_block;enum { FIGURE_COUNT = 21 };int figures[FIGURE_COUNT][BOWL_WIDTH][BOWL_HEIGHT];Block_Mask block_masks[BLOCK_COUNT];extern Bowl *bowls[BOWL_COUNT];extern int *next_blocks, next_blocks_size;#define BOWL_DOWN_VEL_START 0.025#define BOWL_DOWN_VEL_END 0.32#define BOWL_DOWN_PERC_CHANGE 0.085/*====================================================================Locals====================================================================*//*====================================================================Get speed according to level of bowl.====================================================================*/void bowl_set_vert_block_vel( Bowl *bowl ){ int i; /* ranges from BOWL_DOWN_VEL_START to BOWL_DOWN_VEL_END within twenty levels */ bowl->block_vert_vel = BOWL_DOWN_VEL_START; for ( i = 0; i < bowl->level; i++ ) {// printf( "Level %2i: %2.5f\n", i, bowl->block_vert_vel ); bowl->block_vert_vel += ( BOWL_DOWN_VEL_END - bowl->block_vert_vel ) * BOWL_DOWN_PERC_CHANGE; } /* set add action info */ if ( config.gametype == 2 ) { bowl->dismantle_saves = 1; /* 7 - 12 single tiles */ if ( bowl->level >= 7 && bowl->level <= 12 ) { delay_set( &bowl->add_delay, 2000 + ( 12 - bowl->level ) * 500 ); bowl->add_lines = 0; bowl->add_tiles = 1; } /* 13 - ... whole lines */ if ( bowl->level >= 13 ) { if ( bowl->level <= 20 ) delay_set( &bowl->add_delay, 2000 + ( 20 - bowl->level ) * 500 ); else delay_set( &bowl->add_delay, 2000 ); bowl->add_lines = 1; bowl->add_tiles = 0; bowl->add_line_holes = bowl->level - 12; if ( bowl->add_line_holes > 6 ) bowl->add_line_holes = 6; } }}/*====================================================================Get position of helping shadow of block.====================================================================*/int bowl_block_pos_is_valid( Bowl *bowl, int x, int y ){ int i, j; 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 ( x + i >= 0 && x + i < bowl->w ) { if ( y + j >= bowl->h ) return 0; if ( y + j >= 0 ) if ( bowl->contents[x + i][y + j] != -1 ) return 0; } return 1;}void bowl_compute_help_pos( Bowl *bowl ){ int j = bowl->block.y; while ( bowl_block_pos_is_valid( bowl, bowl->block.x, j ) ) j++; j--; bowl->help_sx = bowl->block.x * bowl->block_size + bowl->sx; bowl->help_sy = j * bowl->block_size + bowl->sy;}/*====================================================================Compute position of preview====================================================================*/void bowl_compute_preview_pos( Bowl *bowl ){ int i, j; int x1, y1, x2, y2; /* corners of the tile */ if ( bowl->preview_center_sx == -1 ) return; /* first tile */ x1 = y1 = -1; for ( j = 0; j < 4; j++ ) { for ( i = 0; i < 4; i++ ) { if ( block_masks[bowl->next_block_id].mask[0][i][j] ) { y1 = j; break; } } if ( y1 != -1 ) break; } for ( i = 0; i < 4; i++ ) { for ( j = 0; j < 4; j++ ) { if ( block_masks[bowl->next_block_id].mask[0][i][j] ) { x1 = i; break; } } if ( x1 != -1 ) break; } /* last tile */ x2 = y2 = -1; for ( j = 3; j >= 0; j-- ) { for ( i = 3; i >= 0; i-- ) { if ( block_masks[bowl->next_block_id].mask[0][i][j] ) { y2 = j; break; } } if ( y2 != -1 ) break; } for ( i = 3; i >= 0; i-- ) { for ( j = 3; j >= 0; j-- ) { if ( block_masks[bowl->next_block_id].mask[0][i][j] ) { x2 = i; break; } } if ( x2 != -1 ) break; } /* preview position */ bowl->preview_sx = bowl->preview_center_sx - ( x1 * bowl->block_size + ( ( ( x2 - x1 + 1 ) * bowl->block_size ) >> 1 ) ); bowl->preview_sy = bowl->preview_center_sy - ( y1 * bowl->block_size + ( ( ( y2 - y1 + 1 ) * bowl->block_size ) >> 1 ) );}/*====================================================================Compute computer target====================================================================*/void bowl_compute_cpu_dest( Bowl *bowl ){ int i, j; CPU_Data cpu_data; /* pass bowl contents to the cpu bowl */ if ( config.gametype == 0 ) /* demo is supposed to get the highest scores */ cpu_data.aggr = 0; /* so play defensive */ else cpu_data.aggr = config.cpu_aggr; /* else use the wanted setting */ cpu_data.bowl_w = bowl->w; cpu_data.bowl_h = bowl->h; cpu_data.original_block = &block_masks[bowl->block.id]; cpu_data.original_preview = &block_masks[bowl->next_block_id]; for ( i = 0; i < bowl->w; i++ ) for ( j = 0; j < bowl->h; j++ ) cpu_data.original_bowl[i][j] = ( bowl->contents[i][j] != -1 ); /* get best destination */ cpu_analyze_data( &cpu_data ); bowl->cpu_dest_x = cpu_data.dest_x; bowl->cpu_dest_rot = cpu_data.dest_rot; bowl->cpu_dest_score = cpu_data.dest_score;}/*====================================================================Initate next block.====================================================================*/void bowl_create_next_block( Bowl *bowl ) { int i, min, *new_next_blocks = 0; bowl->block.id = bowl->next_block_id; /* for experts: weight probability of next block against to * helpfulness with a 50% chance. equal properties else. */ if ( config.expert && (rand()%2) ) { int i, j, threshold, saveblockid; struct { int block, score; } tmp, scores[BLOCK_COUNT]; saveblockid = bowl->block.id; for (i=0; i<BLOCK_COUNT; i++ ) { bowl->block.id = i; bowl_compute_cpu_dest( bowl ); scores[i].block = i; scores[i].score = bowl->cpu_dest_score; } /* Sort */ for ( i=0; i<BLOCK_COUNT-1; i++ ) { for ( j=i+1; j<BLOCK_COUNT; j++ ) { if ( scores[j].score < scores[i].score ) { tmp = scores[i]; scores[i] = scores[j]; scores[j] = tmp; } } } /* 50% chance of worst block, 25% next worse, etc.. */ j = rand(); threshold = RAND_MAX / 2; for (i=0; i<BLOCK_COUNT-1; i++ ) { if ( j > threshold ) break; threshold /= 2; } bowl->next_block_id = scores[i].block; bowl->block.id = saveblockid; } else { /* Even next-block probabilities */ if ( bowl->use_same_blocks ) { bowl->next_block_id = next_blocks[bowl->next_blocks_pos++]; if ( bowl->next_blocks_pos == next_blocks_size ) { /* resize block buffer and get new blocks */ min = next_blocks_size; for ( i = 0; i < BOWL_COUNT; i++ ) if ( bowls[i] && bowls[i]->next_blocks_pos < min ) min = bowls[i]->next_blocks_pos; for ( i = 0; i < BOWL_COUNT; i++ ) if ( bowls[i] ) bowls[i]->next_blocks_pos -= min; new_next_blocks = calloc( next_blocks_size - min + NEXT_BLOCKS_CHUNK_SIZE, sizeof(int) ); memcpy( new_next_blocks, &next_blocks[min], sizeof(int) * (next_blocks_size - min) ); fill_int_array_rand( new_next_blocks, next_blocks_size - min, NEXT_BLOCKS_CHUNK_SIZE, 0, BLOCK_COUNT-1 ); free( next_blocks ); next_blocks = new_next_blocks; next_blocks_size = next_blocks_size - min + NEXT_BLOCKS_CHUNK_SIZE; } } else { bowl->next_block_id = rand() % BLOCK_COUNT; if ( bowl->next_block_id == bowl->block.id ) bowl->next_block_id = rand() % BLOCK_COUNT; } } bowl->block.x = 3; bowl->block.y = -3; bowl->block.sx = bowl->sx + bowl->block_size * bowl->block.x; bowl->block.sy = bowl->sy + bowl->block_size * bowl->block.y; bowl->block.rot_id = 0; bowl->block.sw = bowl->block.sh = 4 * bowl->block_size; bowl->block.cur_x = bowl->block.x * bowl->block_size; bowl->block.cur_y = bowl->block.y * bowl->block_size; bowl->block.check_y = (int)bowl->block.cur_y; bowl_compute_help_pos( bowl ); bowl_compute_preview_pos( bowl ); /* if CPU is in control get destination row & other stuff */ if ( !bowl->controls ) { /* destination */ bowl_compute_cpu_dest( bowl ); /* set delay until cpu waits with dropping block */ delay_set( &bowl->cpu_delay, config.cpu_delay ); bowl->cpu_down = 0; delay_set( &bowl->cpu_rot_delay, config.cpu_rot_delay ); }}/*====================================================================Set a tile contents and pixel contents.====================================================================*/inline void bowl_set_tile( Bowl *bowl, int x, int y, int tile_id ){ int i, j = y * bowl->block_size; bowl->contents[x][y] = tile_id; for ( i = 0; i < bowl->block_size; i++ ) bowl->pixel_contents[x][j + i] = tile_id;}/*====================================================================Reset bowl contents and add levels figure if wanted.====================================================================*/void bowl_reset_contents( Bowl *bowl ){ int i, j; for ( i = 0; i < bowl->w; i++ ) for ( j = 0; j < bowl->h; j++ ) bowl_set_tile( bowl, i, j, -1 ); if ( bowl->use_figures && bowl->level < 20 /* don't have more figures */ ) for ( i = 0; i < bowl->w; i++ ) for ( j = 0; j < bowl->h; j++ ) bowl_set_tile( bowl, i, j, figures[bowl->level][i][j] );}/*====================================================================Check if the passed pixel position by rotation is a valid onefor bowl::block.NOTE: py is a pixel value and x is a bowl map value.The tolerance value moves the checked corners into the middleof the brick opening a small 'window' to move though it's blocked.Useful when config::block_by_block is disabled.====================================================================*/int bowl_validate_block_pos( Bowl *bowl, int x, int py, int rot, int tol ){ int i, j; int tile_y = 0; for ( j = 0; j < 4; j++ ) { for ( i = 0; i < 4; i++ ) { if ( block_masks[bowl->block.id].mask[rot][i][j] ) { if ( x + i < 0 ) return 0; if ( x + i >= bowl->w ) return 0; if ( py + tile_y >= bowl->sh ) return 0; /* if it doesn't fit the screen from above it's okay */ if ( py + tile_y < 0 ) continue; /* bowl pixel contents */ if ( bowl->pixel_contents[i + x][py + tile_y + tol]!= -1 ) return 0; if ( bowl->pixel_contents[i + x][py + tile_y + bowl->block_size - 1 - tol] != -1 ) return 0; /* if the bowl bottom is hit it is a collision as well */ if ( py + tile_y + tol >= bowl->sh ) return 0; if ( py + tile_y + bowl->block_size - 1 - tol >= bowl->sh ) return 0; } } tile_y += bowl->block_size; } return 1;}/*====================================================================Draw block to offscreen.====================================================================*/void bowl_draw_block_to_offscreen( Bowl *bowl ){ int i, j; int tile_x = 0, tile_y = 0; if ( bowl->blind ) return; bowl->block.sx = bowl->block.x * bowl->block_size + bowl->sx; bowl->block.sy = bowl->block.y * bowl->block_size + bowl->sy; for ( j = 0; j < 4; j++ ) { for ( i = 0; i < 4; i++ ) { if ( block_masks[bowl->block.id].mask[bowl->block.rot_id][i][j] ) { DEST( offscreen, bowl->block.sx + tile_x, bowl->block.sy + tile_y, bowl->block_size, bowl->block_size ); SOURCE( bowl->blocks, bowl->block.id * bowl->block_size, 0 ); blit_surf(); } tile_x += bowl->block_size; } tile_y += bowl->block_size; tile_x = 0; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -