Update scoring and handling
This commit is contained in:
@@ -300,14 +300,26 @@ class LazyVariable:
|
||||
|
||||
|
||||
class Game:
|
||||
NORMAL_PLACE_POINTS = 10
|
||||
HARD_PLACE_POINTS = 20
|
||||
CLEAR_POINTS = 100
|
||||
# Points
|
||||
DROP_POINTS = 1
|
||||
HARD_DROP_POINTS = 2
|
||||
POINTS_PER_LINE = [100, 300, 500, 800]
|
||||
|
||||
LINES_PER_LEVEL = 10
|
||||
|
||||
MOVE_SPEED = 20 # cells per second
|
||||
MOVE_INITIAL_SLOWDOWN = 3.0 # cells
|
||||
|
||||
DROP_LEVEL_SCALE = 0.025
|
||||
# These are *= 1 + (DROP_LEVEL_SCALE * (LEVEL - 1))
|
||||
NORMAL_DROP_SPEED = 3 # cells per second
|
||||
FAST_DROP_SPEED = 30 # cells per second
|
||||
MOVED_PROP_SPEED = 1 # cells per second
|
||||
CLEAR_SPEED = 10 # frames per block
|
||||
MOVED_DROP_SPEED = 1 # cells per second
|
||||
|
||||
DROP_CLEAR_SCALE = 0.025
|
||||
# This is *= 1 - (DROP_CLEAR_SCALE * (LEVEL - 1))
|
||||
CLEAR_SPEED = 15 # frames per block
|
||||
|
||||
BOARD_SIZE = Size(10, 20) # Cell count
|
||||
CELL_SIZE = Size(30, 30)
|
||||
CELL_BORDER_SIZE = CELL_SIZE.width // 10
|
||||
@@ -391,7 +403,7 @@ class Game:
|
||||
pygame.K_h,
|
||||
Action.Type.OPEN_HELP,
|
||||
False,
|
||||
"Toggle the help menu.",
|
||||
"Toggle the help menu/pause.",
|
||||
),
|
||||
)
|
||||
GAME_OVER_ACTION_MAP = Action.make_map(
|
||||
@@ -620,7 +632,8 @@ class Game:
|
||||
if cell and self.board[y + cy][x + cx]:
|
||||
return True
|
||||
except IndexError:
|
||||
continue
|
||||
# a cell was out of bounds of the board, this is a hit!
|
||||
return True
|
||||
return False
|
||||
|
||||
def rotate_current_piece(self, times: int):
|
||||
@@ -636,8 +649,22 @@ class Game:
|
||||
return
|
||||
|
||||
def move_current_piece(self, dir: Direction):
|
||||
if self.was_move_down != dir:
|
||||
self.subcell_move = 0
|
||||
move_cell = dir
|
||||
self.was_move_down = dir
|
||||
self.inhibit_next_move = Game.MOVE_INITIAL_SLOWDOWN
|
||||
else:
|
||||
dx = dir * Game.MOVE_SPEED * self.frame_time()
|
||||
self.subcell_move += dx
|
||||
if self.inhibit_next_move > 0.0:
|
||||
oi = self.inhibit_next_move
|
||||
self.inhibit_next_move -= abs(self.subcell_move)
|
||||
if self.inhibit_next_move <= 0.0:
|
||||
self.inhibit_next_move = 0.0
|
||||
self.subcell_move -= oi
|
||||
else:
|
||||
self.subcell_move = 0
|
||||
move_cell = int(self.subcell_move)
|
||||
self.subcell_move -= move_cell
|
||||
if move_cell:
|
||||
@@ -658,10 +685,13 @@ class Game:
|
||||
self.did_user_move_or_spin = True
|
||||
|
||||
def process_game_actions(self):
|
||||
if not (
|
||||
{Action.Type.MOVE_LEFT, Action.Type.MOVE_RIGHT}
|
||||
& set(self.pending_actions)
|
||||
):
|
||||
move_set = {Action.Type.MOVE_LEFT, Action.Type.MOVE_RIGHT} & set(
|
||||
self.pending_actions
|
||||
)
|
||||
move_both = len(move_set) == 2
|
||||
if not move_set:
|
||||
self.was_move_down = None
|
||||
self.inhibit_next_move = 0.0
|
||||
self.subcell_move = 0
|
||||
if not (
|
||||
{Action.Type.SOFT_DROP, Action.Type.HARD_DROP}
|
||||
@@ -680,19 +710,17 @@ class Game:
|
||||
self.soft_drop = True
|
||||
case Action.Type.HARD_DROP if not self.stop_drop:
|
||||
self.hard_drop = True
|
||||
case Action.Type.MOVE_LEFT:
|
||||
case Action.Type.MOVE_LEFT if not move_both:
|
||||
self.move_current_piece(Direction.LEFT)
|
||||
case Action.Type.MOVE_RIGHT:
|
||||
self.was_move_down = Direction.LEFT
|
||||
case Action.Type.MOVE_RIGHT if not move_both:
|
||||
self.move_current_piece(Direction.RIGHT)
|
||||
self.was_move_down = Direction.RIGHT
|
||||
case Action.Type.RESTART:
|
||||
self.start_new_game()
|
||||
self.pending_actions = []
|
||||
|
||||
def place_piece(self, x: int, y: int, piece: Tetromino):
|
||||
if self.hard_drop:
|
||||
self.score += Game.HARD_PLACE_POINTS
|
||||
else:
|
||||
self.score += Game.NORMAL_PLACE_POINTS
|
||||
for dy, row in enumerate(piece.shape):
|
||||
for dx, cell in enumerate(row):
|
||||
if cell:
|
||||
@@ -711,21 +739,27 @@ class Game:
|
||||
def advance_piece(self):
|
||||
speed = Game.NORMAL_DROP_SPEED
|
||||
if self.did_user_move_or_spin:
|
||||
speed = Game.MOVED_PROP_SPEED
|
||||
speed = Game.MOVED_DROP_SPEED
|
||||
elif self.soft_drop:
|
||||
speed = Game.FAST_DROP_SPEED
|
||||
speed *= 1 + (Game.DROP_CLEAR_SCALE * (self.level - 1))
|
||||
self.subcell_drop += speed * self.frame_time()
|
||||
move_cell = int(self.subcell_drop)
|
||||
self.subcell_drop -= move_cell
|
||||
if self.hard_drop:
|
||||
move_cell = self.cells_for_hard_drop()
|
||||
if not move_cell:
|
||||
return
|
||||
cp = self.current_block_pos
|
||||
if not self.intersects_board(
|
||||
cp.x, cp.y + move_cell, self.current_block
|
||||
):
|
||||
self.score += move_cell * Game.DROP_POINTS * self.level
|
||||
self.current_block_pos = Cell(cp.x, cp.y + move_cell)
|
||||
# don't place the piece if the user moved it
|
||||
elif not self.did_user_move_or_spin:
|
||||
if self.hard_drop:
|
||||
self.score += move_cell * Game.HARD_DROP_POINTS * self.level
|
||||
for dy in range(move_cell, -1, -1):
|
||||
if not self.intersects_board(
|
||||
cp.x, cp.y + dy, self.current_block
|
||||
@@ -744,6 +778,11 @@ class Game:
|
||||
else:
|
||||
return zip(range(bw // 2, -1, -1), range(bw // 2, bw))
|
||||
|
||||
def calc_clear_speed(self):
|
||||
return Game.CLEAR_SPEED * (
|
||||
1 - (Game.DROP_CLEAR_SCALE * (self.level - 1))
|
||||
)
|
||||
|
||||
def maybe_clear_rows(self):
|
||||
def do_single_clear(y: int):
|
||||
row = self.board[y]
|
||||
@@ -761,16 +800,25 @@ class Game:
|
||||
if not self.clearing_rows:
|
||||
for y, row in enumerate(self.board):
|
||||
if all(row):
|
||||
self.score += self.CLEAR_POINTS
|
||||
self.clearing_rows.add(y)
|
||||
if self.clearing_rows:
|
||||
self.score += (
|
||||
Game.POINTS_PER_LINE[len(self.clearing_rows) - 1]
|
||||
* self.level
|
||||
)
|
||||
else:
|
||||
if self.clearing_frames == self.CLEAR_SPEED:
|
||||
speed = self.calc_clear_speed()
|
||||
if self.clearing_frames >= speed:
|
||||
if not any(self.board[next(iter(self.clearing_rows))]):
|
||||
self.cleared_this_level += len(self.clearing_rows)
|
||||
if self.cleared_this_level >= 10:
|
||||
self.level += self.cleared_this_level // 10
|
||||
self.cleared_this_level %= 10
|
||||
# Order matters here
|
||||
for y in sorted(self.clearing_rows):
|
||||
drop_rows_above_for_clear(y)
|
||||
self.clearing_rows = set()
|
||||
self.clearing_frames = self.CLEAR_SPEED
|
||||
self.clearing_frames = speed
|
||||
else:
|
||||
for y in self.clearing_rows:
|
||||
do_single_clear(y)
|
||||
@@ -780,8 +828,9 @@ class Game:
|
||||
|
||||
def draw_score_and_instructions(self):
|
||||
text = (
|
||||
"Press <h> \nfor help.\n"
|
||||
"Press <h> \nfor help\nor pause.\n"
|
||||
"\n"
|
||||
f"Level: {self.level:02}\n"
|
||||
f"Score: {self.score:05}\n"
|
||||
f" HS: {self.high_score:05}"
|
||||
)
|
||||
@@ -955,6 +1004,8 @@ class Game:
|
||||
self.process_and_draw_help_overlay()
|
||||
|
||||
def start_new_game(self):
|
||||
self.was_move_down = None
|
||||
self.inhibit_next_move = 0.0
|
||||
self.cur_random_peice_seq = None
|
||||
self.clear_board()
|
||||
self.next_piece = None
|
||||
@@ -965,8 +1016,11 @@ class Game:
|
||||
self.subcell_drop = 0
|
||||
self.clearing_rows = set()
|
||||
# immediately clear the first block
|
||||
self.clearing_frames = Game.CLEAR_SPEED
|
||||
self.score = 0
|
||||
self.level = 1
|
||||
self.cleared_this_level = 0
|
||||
# depends on level
|
||||
self.clearing_frames = self.calc_clear_speed()
|
||||
self.held_piece = None
|
||||
self.game_over = False
|
||||
|
||||
@@ -1063,8 +1117,8 @@ class Game:
|
||||
def move_piece_back_to_top(self):
|
||||
self.current_block_pos = Cell(
|
||||
self.BOARD_SIZE.width // 2
|
||||
- math.ceil(self.current_block.width / 2),
|
||||
0,
|
||||
- math.ceil(self.current_block.bounding_box_width / 2),
|
||||
0 - self.current_block.y_adj,
|
||||
)
|
||||
|
||||
def swap_in_next_piece(self, force: bool = False):
|
||||
@@ -1525,6 +1579,16 @@ GLYPH_DATA = [
|
||||
"** ",
|
||||
],
|
||||
),
|
||||
Font.Glyph(
|
||||
"/",
|
||||
[
|
||||
" *",
|
||||
" * ",
|
||||
" * ",
|
||||
" * ",
|
||||
"* ",
|
||||
],
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user