aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorSven Gothel <[email protected]>2022-03-29 09:29:09 +0200
committerSven Gothel <[email protected]>2022-03-29 09:29:09 +0200
commitb837152c713a5d6627799a31fe637c98e964b0e9 (patch)
tree2f9bcf7a094da9a16f077ebf3cbab4c1dae413cb /src
parentca145f3c489a32088222c1e2a1370462f47c0cac (diff)
Show ghost score for 900ms using ttf font, freezing tick and keep freezing_box clear
Diffstat (limited to 'src')
-rw-r--r--src/game.cpp23
-rw-r--r--src/ghost.cpp50
-rw-r--r--src/maze.cpp2
-rw-r--r--src/pacman.cpp238
4 files changed, 182 insertions, 131 deletions
diff --git a/src/game.cpp b/src/game.cpp
index 76ad7fb..ab5b80e 100644
--- a/src/game.cpp
+++ b/src/game.cpp
@@ -55,6 +55,9 @@ pacman_ref pacman;
std::vector<audio_sample_ref> audio_samples;
+static TTF_Font* font_ttf_ = nullptr;
+TTF_Font* font_ttf() noexcept { return font_ttf_; }
+
static bool original_pacman_behavior = true;
bool use_original_pacman_behavior() noexcept { return original_pacman_behavior; }
@@ -243,8 +246,6 @@ std::string global_tex_t::toString() const {
// main
//
-TTF_Font* font_ttf = nullptr;
-
static void on_window_resized(SDL_Renderer* rend, const int win_width_l, const int win_height_l) noexcept {
int win_pixel_height=0;
SDL_GetRendererOutputSize(rend, &win_pixel_width_, &win_pixel_height);
@@ -253,19 +254,19 @@ static void on_window_resized(SDL_Renderer* rend, const int win_width_l, const i
float sy = win_pixel_height / global_maze->pixel_height();
win_pixel_scale_ = static_cast<int>( std::round( std::fmin<float>(sx, sy) ) );
- if( nullptr != font_ttf ) {
- TTF_CloseFont(font_ttf);
- font_ttf = nullptr;
+ if( nullptr != font_ttf() ) {
+ TTF_CloseFont(font_ttf());
+ font_ttf_ = nullptr;
}
int font_height;
{
const std::string fontfilename = "fonts/freefont/FreeSansBold.ttf";
font_height = global_maze->ppt_y() * win_pixel_scale();
- font_ttf = TTF_OpenFont(fontfilename.c_str(), font_height);
+ font_ttf_ = TTF_OpenFont(fontfilename.c_str(), font_height);
}
log_printf("Window Resized: %d x %d pixel ( %d x %d logical ) @ %d hz\n",
win_pixel_width(), win_pixel_height, win_width_l, win_height_l, get_frames_per_sec());
- log_printf("Pixel scale: %f x %f -> %d, font[ok %d, height %d]\n", sx, sy, win_pixel_scale(), nullptr!=font_ttf, font_height);
+ log_printf("Pixel scale: %f x %f -> %d, font[ok %d, height %d]\n", sx, sy, win_pixel_scale(), nullptr!=font_ttf(), font_height);
}
static std::string get_usage(const std::string& exename) noexcept {
@@ -771,10 +772,10 @@ int main(int argc, char *argv[])
}
// top line
- if( nullptr != font_ttf ) {
+ if( nullptr != font_ttf() ) {
if( nullptr == ttex_score_title ) {
const std::string highscore_s("HIGH SCORE");
- ttex_score_title = draw_text_scaled(rend, font_ttf, highscore_s, 255, 255, 255, [&](const texture_t& tex, int &x, int&y) {
+ ttex_score_title = draw_text_scaled(rend, font_ttf(), highscore_s, 255, 255, 255, [&](const texture_t& tex, int &x, int&y) {
x = ( global_maze->pixel_width()*win_pixel_scale() - tex.width() ) / 2;
y = global_maze->x_to_pixel(0, win_pixel_scale());
});
@@ -785,7 +786,7 @@ int main(int argc, char *argv[])
ttex_score->redraw(rend);
} else {
std::string score_s = std::to_string( pacman->score() );
- ttex_score = draw_text_scaled(rend, font_ttf, score_s, 255, 255, 255, [&](const texture_t& tex, int &x, int&y) {
+ ttex_score = draw_text_scaled(rend, font_ttf(), score_s, 255, 255, 255, [&](const texture_t& tex, int &x, int&y) {
x = ( global_maze->pixel_width()*win_pixel_scale() - tex.width() ) / 2;
y = global_maze->x_to_pixel(1, win_pixel_scale());
});
@@ -869,7 +870,7 @@ int main(int argc, char *argv[])
SDL_DestroyWindow(win);
- TTF_CloseFont(font_ttf);
+ TTF_CloseFont(font_ttf());
SDL_Quit();
diff --git a/src/ghost.cpp b/src/ghost.cpp
index 544a312..f180027 100644
--- a/src/ghost.cpp
+++ b/src/ghost.cpp
@@ -468,26 +468,28 @@ void ghost_t::set_global_mode(const mode_t m, const int mode_ms) noexcept {
}
void ghost_t::global_tick() noexcept {
- if( 0 < global_mode_ms_left ) {
- global_mode_ms_left = std::max( 0, global_mode_ms_left - get_ms_per_frame() );
- }
-
- if( mode_t::CHASE == global_mode ) {
- if( 0 == global_mode_ms_left ) {
- set_global_mode( mode_t::SCATTER );
- }
- } else if( mode_t::SCATTER == global_mode ) {
- if( 0 == global_mode_ms_left ) {
- set_global_mode( mode_t::CHASE );
+ if( pacman_t::mode_t::FREEZE != pacman->mode() ) {
+ if( 0 < global_mode_ms_left ) {
+ global_mode_ms_left = std::max( 0, global_mode_ms_left - get_ms_per_frame() );
}
- } else if( mode_t::SCARED == global_mode ) {
- if( 0 == global_mode_ms_left ) {
- set_global_mode( global_mode_last );
+
+ if( mode_t::CHASE == global_mode ) {
+ if( 0 == global_mode_ms_left ) {
+ set_global_mode( mode_t::SCATTER );
+ }
+ } else if( mode_t::SCATTER == global_mode ) {
+ if( 0 == global_mode_ms_left ) {
+ set_global_mode( mode_t::CHASE );
+ }
+ } else if( mode_t::SCARED == global_mode ) {
+ if( 0 == global_mode_ms_left ) {
+ set_global_mode( global_mode_last );
+ }
+ } else {
+ log_printf("Error: global_tick: global_mode %s [%d ms], previous %s\n",
+ to_string(global_mode).c_str(), global_mode_ms_left, to_string(global_mode_last).c_str());
+ return;
}
- } else {
- log_printf("Error: global_tick: global_mode %s [%d ms], previous %s\n",
- to_string(global_mode).c_str(), global_mode_ms_left, to_string(global_mode_last).c_str());
- return;
}
for(ghost_ref g : ghosts) {
g->tick();
@@ -621,11 +623,16 @@ void ghost_t::set_mode(const mode_t m, const int mode_ms) noexcept {
}
void ghost_t::tick() noexcept {
+ atex = &get_tex();
+ atex->tick();
+
if( sync_next_frame_cntr.count_down() ) {
return; // skip tick, just repaint
}
- atex = &get_tex();
- atex->tick();
+
+ if( pacman_t::mode_t::FREEZE == pacman->mode() ) {
+ return; // NOP
+ }
bool collision_maze = false;
@@ -692,6 +699,9 @@ void ghost_t::draw(SDL_Renderer* rend) noexcept {
if( mode_t::AWAY == mode_ ) {
return;
}
+ if( pos_.intersects_i( pacman->freeze_box() ) ) {
+ return;
+ }
atex->draw2(rend, pos_.x_f()-keyframei_.center(), pos_.y_f()-keyframei_.center());
diff --git a/src/maze.cpp b/src/maze.cpp
index 92b7798..7c7c7c5 100644
--- a/src/maze.cpp
+++ b/src/maze.cpp
@@ -546,7 +546,7 @@ bool maze_t::digest_ibox_line(const std::string& name, box_t& dest, const std::s
if( -1 == dest.x() || -1 == dest.y() ) {
int x_pos = 0, y_pos = 0, w = 0, h = 0;
sscanf(line.c_str(), "%d %d %d %d", &x_pos, &y_pos, &w, &h);
- dest.set_dim(x_pos, y_pos, w, h);
+ dest.set(x_pos, y_pos, w, h);
if( DEBUG ) {
log_printf("maze: read %s box: %s\n", name.c_str(), dest.toString().c_str());
}
diff --git a/src/pacman.cpp b/src/pacman.cpp
index 8b7211d..0ff3dc7 100644
--- a/src/pacman.cpp
+++ b/src/pacman.cpp
@@ -38,7 +38,7 @@ static constexpr const bool DEBUG_GFX_BOUNDS = false;
//
animtex_t& pacman_t::get_tex() noexcept {
- switch( mode ) {
+ switch( mode_ ) {
case pacman_t::mode_t::HOME:
return atex_home;
case pacman_t::mode_t::NORMAL:
@@ -72,12 +72,15 @@ pacman_t::pacman_t(SDL_Renderer* rend, const float fields_per_sec_total_) noexce
keyframei_(get_frames_per_sec(), fields_per_sec_total*current_speed_pct, true /* nearest */),
sync_next_frame_cntr( keyframei_.sync_frame_count(), true /* auto_reload */),
next_empty_field_frame_cntr(0, false /* auto_reload */),
- mode( mode_t::LEVEL_START ),
+ mode_( mode_t::LEVEL_START ),
+ mode_last( mode_t::LEVEL_START ),
mode_ms_left ( -1 ),
lives( 3 ),
ghosts_eaten_powered( 0 ),
current_dir( direction_t::LEFT ),
score_( 0 ),
+ freeze_score( -1 ),
+ freeze_box_(-1, -1, -1, -1),
atex_left( "L", rend, ms_per_tex, global_tex->all_images(), 0, 28, 13, 13, { { 0*13, 0 }, { 1*13, 0 } }),
atex_right("R", rend, ms_per_tex, global_tex->all_images(), 0, 28, 13, 13, { { 2*13, 0 }, { 3*13, 0 } }),
atex_up( "U", rend, ms_per_tex, global_tex->all_images(), 0, 28, 13, 13, { { 4*13, 0 }, { 5*13, 0 } }),
@@ -101,18 +104,25 @@ void pacman_t::destroy() noexcept {
atex_home.destroy();
}
-void pacman_t::set_mode(const mode_t m) noexcept {
- const mode_t old_mode = mode;
+void pacman_t::set_mode(const mode_t m, const int mode_ms) noexcept {
+ if( m != mode_last && mode_t::FREEZE != m ) { // only earmark last other mode != mode_t::FREEZE
+ mode_last = mode_;
+ }
+ const mode_t old_mode = mode_;
mode_t m1 = m;
ghost_t::mode_t mg = ghost_t::mode_t::AWAY;
switch( m ) {
+ case mode_t::FREEZE:
+ mode_ = m1;
+ mode_ms_left = mode_ms;
+ break;
case mode_t::LEVEL_START:
m1 = mode_t::HOME;
mg = ghost_t::mode_t::LEVEL_START;
[[fallthrough]];
case mode_t::HOME:
audio_samples[ ::number( audio_clip_t::MUNCH ) ]->stop();
- mode = m1;
+ mode_ = m1;
mode_ms_left = number( mode_duration_t::HOMESTAY );
if( ghost_t::mode_t::AWAY == mg ) {
mg = ghost_t::mode_t::HOME;
@@ -126,12 +136,12 @@ void pacman_t::set_mode(const mode_t m) noexcept {
set_speed(game_level_spec().pacman_speed);
break;
case mode_t::NORMAL:
- mode = m1;
+ mode_ = m1;
mode_ms_left = -1;
set_speed(game_level_spec().pacman_speed);
break;
case mode_t::POWERED:
- mode = m1;
+ mode_ = m1;
mode_ms_left = game_level_spec().fright_time_ms;
ghost_t::set_global_mode( ghost_t::mode_t::SCARED, mode_ms_left );
set_speed(game_level_spec().pacman_powered_speed);
@@ -139,20 +149,20 @@ void pacman_t::set_mode(const mode_t m) noexcept {
break;
case mode_t::DEAD:
audio_samples[ ::number( audio_clip_t::MUNCH ) ]->stop();
- mode = m1;
+ mode_ = m1;
mode_ms_left = number( mode_duration_t::DEADANIM );
atex_dead.reset();
ghost_t::set_global_mode(ghost_t::mode_t::AWAY);
audio_samples[ ::number( audio_clip_t::DEATH ) ]->play();
break;
default:
- mode = m1;
+ mode_ = m1;
mode_ms_left = -1;
break;
}
if( log_modes() ) {
log_printf("pacman set_mode: %s -> %s -> %s [%d ms], speed %5.2f, pos %s\n",
- to_string(old_mode).c_str(), to_string(m).c_str(), to_string(mode).c_str(), mode_ms_left,
+ to_string(old_mode).c_str(), to_string(m).c_str(), to_string(mode_).c_str(), mode_ms_left,
current_speed_pct, pos_.toShortString().c_str());
}
}
@@ -220,11 +230,12 @@ bool pacman_t::set_dir(const direction_t new_dir) noexcept {
}
bool pacman_t::tick() noexcept {
+ atex = &get_tex();
+ atex->tick();
+
if( sync_next_frame_cntr.count_down() ) {
return true; // skip tick, just repaint
}
- atex = &get_tex();
- atex->tick();
bool collision_maze = false;
bool collision_enemies = false;
@@ -233,108 +244,135 @@ bool pacman_t::tick() noexcept {
mode_ms_left = std::max( 0, mode_ms_left - get_ms_per_frame() );
}
- if( mode_t::HOME == mode ) {
+ if( mode_t::FREEZE == mode_ ) {
+ if( 0 == mode_ms_left ) {
+ freeze_score = -1;
+ freeze_box_.set(-1, -1, -1, -1);
+ mode_ = mode_last;
+ }
+ return true;
+ } else if( mode_t::HOME == mode_ ) {
if( 0 == mode_ms_left ) {
set_mode( mode_t::NORMAL );
- } else {
- return true; // wait
}
- } else if( mode_t::DEAD == mode ) {
+ return true;
+ } else if( mode_t::DEAD == mode_ ) {
if( 0 == mode_ms_left ) {
set_mode( mode_t::HOME );
}
- } else {
- // NORMAL and POWERED
+ return true;
+ }
+ // NORMAL and POWERED
- if( mode_t::POWERED == mode ) {
- if( 0 == mode_ms_left ) {
- set_mode( mode_t::NORMAL );
- }
+ if( mode_t::POWERED == mode_ ) {
+ if( 0 == mode_ms_left ) {
+ set_mode( mode_t::NORMAL );
}
+ }
- /**
- * Pacman's position depends on:
- * - its direction
- * - speed (change_per_tick)
- * - environment
- */
- {
- collision_maze = !pos_.step(current_dir, keyframei_, [](tile_t tile) -> bool {
- return tile_t::WALL == tile || tile_t::GATE == tile ;
- });
- const int x_i = pos_.x_i();
- const int y_i = pos_.y_i();
- const tile_t tile = global_maze->tile(x_i, y_i);
- const bool entered_tile = pos_.entered_tile(keyframei_);
- if( log_moves() || DEBUG_GFX_BOUNDS ) {
- log_printf("pacman tick: %s, %s c%d e%d '%s', crash[maze %d, ghosts %d], textures %s\n",
- to_string(current_dir).c_str(), pos_.toString().c_str(), pos_.is_center(keyframei_), entered_tile,
- to_string(tile).c_str(),
- collision_maze, collision_enemies, atex->toString().c_str());
- }
- if( collision_maze ) {
- audio_samples[ ::number( audio_clip_t::MUNCH ) ]->stop();
- reset_stats();
- } else { // if( entered_tile ) {
- if( tile_t::PELLET <= tile && tile <= tile_t::KEY ) {
- score_ += ::number( tile_to_score(tile) );
- global_maze->set_tile(x_i, y_i, tile_t::EMPTY);
- if( tile_t::PELLET == tile ) {
- audio_samples[ ::number( audio_clip_t::MUNCH ) ]->play(0);
- if( mode_t::POWERED == mode ) {
- set_speed(game_level_spec().pacman_powered_speed_dots);
- } else {
- set_speed(game_level_spec().pacman_speed_dots);
- }
- next_empty_field_frame_cntr.load( keyframei_.frames_per_field() + 1 );
- ghost_t::notify_pellet_eaten();
- } else if( tile_t::PELLET_POWER == tile ) {
- set_mode( mode_t::POWERED );
- audio_samples[ ::number( audio_clip_t::MUNCH ) ]->play(0);
- next_empty_field_frame_cntr.load( keyframei_.frames_per_field() + 1 );
- }
- } else if( tile_t::EMPTY == tile ) {
- if( next_empty_field_frame_cntr.count_down() ) {
- if( mode_t::POWERED == mode ) {
- set_speed(game_level_spec().pacman_powered_speed);
- } else {
- set_speed(game_level_spec().pacman_speed);
- }
- audio_samples[ ::number( audio_clip_t::MUNCH ) ]->stop();
- }
- }
- }
- }
- // Collision test with ghosts
- for(ghost_ref g : ghosts) {
- if( pos_.intersects(g->position()) ) {
- const ghost_t::mode_t g_mode = g->mode();
- if( ghost_t::mode_t::CHASE <= g_mode && g_mode <= ghost_t::mode_t::SCATTER ) {
- collision_enemies = true;
- } else if( ghost_t::mode_t::SCARED == g_mode ) {
- switch( ghosts_eaten_powered ) {
- case 0: score_ += ::number( score_t::GHOST_1 ); break;
- case 1: score_ += ::number( score_t::GHOST_2 ); break;
- case 2: score_ += ::number( score_t::GHOST_3 ); break;
- default: score_ += ::number( score_t::GHOST_4 ); break;
- }
- ++ghosts_eaten_powered;
- g->set_mode( ghost_t::mode_t::PHANTOM );
- audio_samples[ ::number( audio_clip_t::EAT_GHOST ) ]->play();
- }
- }
- }
+ /**
+ * Pacman's position depends on:
+ * - its direction
+ * - speed (change_per_tick)
+ * - environment
+ */
+ {
+ collision_maze = !pos_.step(current_dir, keyframei_, [](tile_t tile) -> bool {
+ return tile_t::WALL == tile || tile_t::GATE == tile ;
+ });
+ const int x_i = pos_.x_i();
+ const int y_i = pos_.y_i();
+ const tile_t tile = global_maze->tile(x_i, y_i);
+ const bool entered_tile = pos_.entered_tile(keyframei_);
+ if( log_moves() || DEBUG_GFX_BOUNDS ) {
+ log_printf("pacman tick: %s, %s c%d e%d '%s', crash[maze %d, ghosts %d], textures %s\n",
+ to_string(current_dir).c_str(), pos_.toString().c_str(), pos_.is_center(keyframei_), entered_tile,
+ to_string(tile).c_str(),
+ collision_maze, collision_enemies, atex->toString().c_str());
+ }
+ if( collision_maze ) {
+ audio_samples[ ::number( audio_clip_t::MUNCH ) ]->stop();
+ reset_stats();
+ } else { // if( entered_tile ) {
+ if( tile_t::PELLET <= tile && tile <= tile_t::KEY ) {
+ score_ += ::number( tile_to_score(tile) );
+ global_maze->set_tile(x_i, y_i, tile_t::EMPTY);
+ if( tile_t::PELLET == tile ) {
+ audio_samples[ ::number( audio_clip_t::MUNCH ) ]->play(0);
+ if( mode_t::POWERED == mode_ ) {
+ set_speed(game_level_spec().pacman_powered_speed_dots);
+ } else {
+ set_speed(game_level_spec().pacman_speed_dots);
+ }
+ next_empty_field_frame_cntr.load( keyframei_.frames_per_field() + 1 );
+ ghost_t::notify_pellet_eaten();
+ } else if( tile_t::PELLET_POWER == tile ) {
+ set_mode( mode_t::POWERED );
+ audio_samples[ ::number( audio_clip_t::MUNCH ) ]->play(0);
+ next_empty_field_frame_cntr.load( keyframei_.frames_per_field() + 1 );
+ }
+ } else if( tile_t::EMPTY == tile ) {
+ if( next_empty_field_frame_cntr.count_down() ) {
+ if( mode_t::POWERED == mode_ ) {
+ set_speed(game_level_spec().pacman_powered_speed);
+ } else {
+ set_speed(game_level_spec().pacman_speed);
+ }
+ audio_samples[ ::number( audio_clip_t::MUNCH ) ]->stop();
+ }
+ }
+ }
+ }
+ // Collision test with ghosts
+ int i=0;
+ for(ghost_ref g : ghosts) {
+ if( pos_.intersects(g->position()) ) {
+ const ghost_t::mode_t g_mode = g->mode();
+ if( ghost_t::mode_t::CHASE <= g_mode && g_mode <= ghost_t::mode_t::SCATTER ) {
+ collision_enemies = true;
+ } else if( ghost_t::mode_t::SCARED == g_mode ) {
+ switch( ghosts_eaten_powered ) {
+ case 0: freeze_score = ::number( score_t::GHOST_1 ); break;
+ case 1: freeze_score = ::number( score_t::GHOST_2 ); break;
+ case 2: freeze_score = ::number( score_t::GHOST_3 ); break;
+ default: freeze_score = ::number( score_t::GHOST_4 ); break;
+ }
+ score_ += freeze_score;
+ ++ghosts_eaten_powered;
+ g->set_mode( ghost_t::mode_t::PHANTOM );
+ audio_samples[ ::number( audio_clip_t::EAT_GHOST ) ]->play();
+ freeze_box_.set(pos_.x_i()-1, pos_.y_i()-1, 2, 2);
+ set_mode(mode_t::FREEZE, 900);
+ if( false ) {
+ log_printf("pacman eats: ghost# %d, score %d, ghost %s\n", ghosts_eaten_powered, freeze_score, g->toString().c_str());
+ }
+ }
+ }
+ ++i;
+ }
- if( collision_enemies ) {
- set_mode( mode_t::DEAD );
- }
+ if( collision_enemies ) {
+ set_mode( mode_t::DEAD );
}
return !collision_enemies;
}
void pacman_t::draw(SDL_Renderer* rend) noexcept {
++perf_frame_count_walked;
- atex->draw2(rend, pos_.x_f()-keyframei_.center(), pos_.y_f()-keyframei_.center());
+
+ if( mode_t::FREEZE == mode_ ) {
+ if( 0 <= freeze_score ) {
+ if( nullptr != font_ttf() ) {
+ std::string score_s = std::to_string( freeze_score );
+ draw_text_scaled(rend, font_ttf(), score_s, 255, 255, 255, [&](const texture_t& tex, int &x, int&y) {
+ x = round_to_int( pos_.x_f() * global_maze->ppt_y() * win_pixel_scale() ) - tex.width() / 2;
+ y = round_to_int( pos_.y_f() * global_maze->ppt_y() * win_pixel_scale() ) - tex.height() / 2;
+ });
+ }
+ }
+ } else {
+ atex->draw2(rend, pos_.x_f()-keyframei_.center(), pos_.y_f()-keyframei_.center());
+ }
if( show_debug_gfx() || DEBUG_GFX_BOUNDS ) {
uint8_t r, g, b, a;
@@ -351,12 +389,14 @@ void pacman_t::draw(SDL_Renderer* rend) noexcept {
}
std::string pacman_t::toString() const noexcept {
- return "pacman["+to_string(mode)+"["+std::to_string(mode_ms_left)+" ms], "+to_string(current_dir)+", "+pos_.toString()+", "+atex->toString()+", "+keyframei_.toString()+"]";
+ return "pacman["+to_string(mode_)+"["+std::to_string(mode_ms_left)+" ms], "+to_string(current_dir)+", "+pos_.toString()+", "+atex->toString()+", "+keyframei_.toString()+"]";
}
std::string to_string(pacman_t::mode_t m) {
switch( m ) {
+ case pacman_t::mode_t::FREEZE:
+ return "freeze";
case pacman_t::mode_t::HOME:
return "home";
case pacman_t::mode_t::NORMAL: