Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

In-game progress stats #1619

Merged
merged 2 commits into from
Dec 29, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions data/AUTHORS
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@ These are just more code.
* squish.wav - replaced with a self-made sound by Some_Person
* stomp.wav - replaced with a self-made sound by Some_Person
* switch.ogg - self-made by WolfgangB GPLv2+CC-by-sa
* tada.ogg - created by plasterbrain, licensed under CC0, from https://freesound.org/people/plasterbrain/sounds/397355/
* thunder.wav - sampled by Some_Person from http://www.pdsounds.org/sounds/storm_thunderbolts
* ticking.wav - self-made by sommer
* totem.ogg - self-made by WolfgangB GPLv2+CC-by-sa
Expand Down
Binary file added data/images/engine/hud/badguy-icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added data/images/engine/hud/coin-icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added data/images/engine/hud/secret-icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added data/sounds/coins_cleared.ogg
Binary file not shown.
Binary file added data/sounds/retro_fall.wav
Binary file not shown.
Binary file added data/sounds/tada.ogg
Binary file not shown.
2 changes: 1 addition & 1 deletion src/badguy/badguy.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -546,7 +546,7 @@ void
BadGuy::run_dead_script()
{
if (m_countMe)
Sector::get().get_level().m_stats.m_badguys++;
Sector::get().get_level().m_stats.increment_badguys();

m_countMe = false;

Expand Down
2 changes: 1 addition & 1 deletion src/object/bonus_block.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -273,7 +273,7 @@ BonusBlock::try_open(Player* player)
Sector::get().add<BouncyCoin>(get_pos(), true);
player->get_status().add_coins(1);
if (m_hit_counter != 0)
Sector::get().get_level().m_stats.m_coins++;
Sector::get().get_level().m_stats.increment_coins();
break;
}

Expand Down
2 changes: 1 addition & 1 deletion src/object/coin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ Coin::collect()

Sector::get().get_player().get_status().add_coins(1, false);
Sector::get().add<BouncyCoin>(get_pos(), false, get_sprite_name());
Sector::get().get_level().m_stats.m_coins++;
Sector::get().get_level().m_stats.increment_coins();
remove_me();

if (!m_collect_script.empty()) {
Expand Down
13 changes: 12 additions & 1 deletion src/supertux/game_session.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -348,7 +348,16 @@ GameSession::update(float dt_sec, const Controller& controller)
MenuManager::instance().set_menu(MenuStorage::DEBUG_MENU);
}
}


// Animate the full-completion stats stuff - do this even when the game isn't paused (that's a
// design choice, if you prefer it not to animate when paused, add `if (!m_game_pause)`)
m_level->m_stats.update_timers(dt_sec);

// FIXME: I (Semphris) am responsible for this awful code. I have no idea why I originally did it
// that way. I suppose it was back in the time when I didn't understand the engine very well (3
// months prior to writing this - thanks git). I'm going to remove all of this (and the useless
// CutsceneInfo object) sometime soon and use the damn draw function like a normal programmer
// would do - if I somehow forget, please remind me or do it for me.
if (m_level->m_is_in_cutscene && !m_level->m_skip_cutscene && m_current_cutscene_text == nullptr)
{
/*std::string cutscene_text = _("Press escape to skip");
Expand Down Expand Up @@ -625,6 +634,8 @@ GameSession::drawstatus(DrawingContext& context)
if (m_end_sequence) {
m_level->m_stats.draw_endseq_panel(context, m_best_level_statistics, m_statistics_backdrop, m_level->m_target_time);
}

m_level->m_stats.draw_ingame_stats(context, m_game_pause);
}

/* EOF */
12 changes: 6 additions & 6 deletions src/supertux/levelintro.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -164,14 +164,14 @@ LevelIntro::draw(Compositor& compositor)
py += static_cast<int>(Resources::normal_font->get_height());

draw_stats_line(context, py, _("Coins"),
Statistics::coins_to_string(m_best_level_statistics->m_coins, stats.m_total_coins),
m_best_level_statistics->m_coins >= stats.m_total_coins);
Statistics::coins_to_string(m_best_level_statistics->get_coins(), stats.m_total_coins),
m_best_level_statistics->get_coins() >= stats.m_total_coins);
draw_stats_line(context, py, _("Badguys killed"),
Statistics::frags_to_string(m_best_level_statistics->m_badguys, stats.m_total_badguys),
m_best_level_statistics->m_badguys >= stats.m_total_badguys);
Statistics::frags_to_string(m_best_level_statistics->get_badguys(), stats.m_total_badguys),
m_best_level_statistics->get_badguys() >= stats.m_total_badguys);
draw_stats_line(context, py, _("Secrets"),
Statistics::secrets_to_string(m_best_level_statistics->m_secrets, stats.m_total_secrets),
m_best_level_statistics->m_secrets >= stats.m_total_secrets);
Statistics::secrets_to_string(m_best_level_statistics->get_secrets(), stats.m_total_secrets),
m_best_level_statistics->get_secrets() >= stats.m_total_secrets);

bool targetTimeBeaten = m_level.m_target_time == 0.0f || (m_best_level_statistics->get_time() != 0.0f && m_best_level_statistics->get_time() < m_level.m_target_time);
draw_stats_line(context, py, _("Best time"),
Expand Down
157 changes: 155 additions & 2 deletions src/supertux/statistics.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include <iomanip>
#include <limits>

#include "audio/sound_manager.hpp"
#include "math/util.hpp"
#include "squirrel/squirrel_util.hpp"
#include "supertux/globals.hpp"
Expand All @@ -43,6 +44,12 @@ Statistics::Statistics() :
m_badguys(),
m_secrets(),
m_time(),
m_cleared_coins(false),
m_cleared_badguys(false),
m_cleared_secrets(false),
m_coins_time(0.f),
m_badguys_time(0.f),
m_secrets_time(0.f),
m_max_width(256),
CAPTION_MAX_COINS(_("Max coins collected:")),
CAPTION_MAX_FRAGGING(_("Max fragging:")),
Expand All @@ -52,7 +59,10 @@ Statistics::Statistics() :
WMAP_INFO_LEFT_X(),
WMAP_INFO_RIGHT_X(),
WMAP_INFO_TOP_Y1(),
WMAP_INFO_TOP_Y2()
WMAP_INFO_TOP_Y2(),
coin_icon(Surface::from_file("/images/engine/hud/coin-icon.png")),
badguy_icon(Surface::from_file("/images/engine/hud/badguy-icon.png")),
secret_icon(Surface::from_file("/images/engine/hud/secret-icon.png"))
{
calculate_max_caption_length();
WMAP_INFO_LEFT_X = static_cast<float>(SCREEN_WIDTH) - 32.0f - static_cast<float>(m_max_width);
Expand Down Expand Up @@ -297,6 +307,110 @@ Statistics::draw_endseq_panel(DrawingContext& context, Statistics* best_stats, c
}
}

void
Statistics::draw_ingame_stats(DrawingContext& context, bool on_pause_menu)
{
if (on_pause_menu || (m_cleared_coins && m_coins_time < 5.f))
{
std::string text(coins_to_string(m_coins, m_total_coins));
float width = Resources::normal_font->get_text_width(text),
height = Resources::normal_font->get_height(),
x_offset = width + 75.f;

if (!on_pause_menu)
x_offset *= std::min(1.f, -std::abs(m_coins_time - 2.5f) + 2.5f);

Vector pos(static_cast<float>(context.get_width()) - x_offset,
static_cast<float>(context.get_height()) - height * 6.f - 20.f);

context.color().draw_filled_rect(Rectf(pos.x, pos.y, pos.x + width + 21.f,
pos.y + height).grown(5.f),
Color(0.f, 0.f, 0.f, 0.5f),
10.f, LAYER_HUD - 1);
context.color().draw_text(Resources::normal_font, text, pos,
FontAlignment::ALIGN_LEFT, LAYER_HUD,
(m_coins < m_total_coins)
? Statistics::text_color
: Statistics::perfect_color
);
context.color().draw_surface_scaled(coin_icon,
Rectf(pos.x + width + 1.f, pos.y + 1.f,
pos.x + width + 16.f, pos.y + 16.f),
LAYER_HUD);
}

if (on_pause_menu || (m_cleared_badguys && m_badguys_time < 5.f))
{
std::string text(frags_to_string(m_badguys, m_total_badguys));
float width = Resources::normal_font->get_text_width(text),
height = Resources::normal_font->get_height(),
x_offset = width + 75.f;

if (!on_pause_menu)
x_offset *= std::min(1.f, -std::abs(m_badguys_time - 2.5f) + 2.5f);

Vector pos(static_cast<float>(context.get_width()) - x_offset,
static_cast<float>(context.get_height()) - height * 5.f - 10.f);

context.color().draw_filled_rect(Rectf(pos.x, pos.y, pos.x + width + 21.f,
pos.y + height).grown(5.f),
Color(0.f, 0.f, 0.f, 0.5f),
10.f, LAYER_HUD - 1);
context.color().draw_text(Resources::normal_font, text, pos,
FontAlignment::ALIGN_LEFT, LAYER_HUD,
(m_badguys < m_total_badguys)
? Statistics::text_color
: Statistics::perfect_color
);
context.color().draw_surface_scaled(badguy_icon,
Rectf(pos.x + width + 1.f, pos.y + 1.f,
pos.x + width + 16.f, pos.y + 16.f),
LAYER_HUD);
}

if (on_pause_menu || (m_cleared_secrets && m_secrets_time < 5.f))
{
std::string text(secrets_to_string(m_secrets, m_total_secrets));
float width = Resources::normal_font->get_text_width(text),
height = Resources::normal_font->get_height(),
x_offset = width + 75.f;

if (!on_pause_menu)
x_offset *= std::min(1.f, -std::abs(m_secrets_time - 2.5f) + 2.5f);

Vector pos(static_cast<float>(context.get_width()) - x_offset,
static_cast<float>(context.get_height()) - height * 4.f);

context.color().draw_filled_rect(Rectf(pos.x, pos.y, pos.x + width + 21.f,
pos.y + height).grown(5.f),
Color(0.f, 0.f, 0.f, 0.5f),
10.f, LAYER_HUD - 1);
context.color().draw_text(Resources::normal_font, text, pos,
FontAlignment::ALIGN_LEFT, LAYER_HUD,
(m_secrets < m_total_secrets)
? Statistics::text_color
: Statistics::perfect_color
);
context.color().draw_surface_scaled(secret_icon,
Rectf(pos.x + width + 1.f, pos.y + 1.f,
pos.x + width + 16.f, pos.y + 16.f),
LAYER_HUD);
}
}

void
Statistics::update_timers(float dt_sec)
{
if (m_cleared_coins)
m_coins_time += dt_sec;

if (m_cleared_badguys)
m_badguys_time += dt_sec;

if (m_cleared_secrets)
m_secrets_time += dt_sec;
}

void
Statistics::init(const Level& level)
{
Expand Down Expand Up @@ -328,7 +442,7 @@ void
Statistics::update(const Statistics& other)
{
if (other.m_status != FINAL) return;

m_coins = std::max(m_coins, other.m_coins);
m_badguys = std::max(m_badguys, other.m_badguys);
m_secrets = std::max(m_secrets, other.m_secrets);
Expand Down Expand Up @@ -393,6 +507,45 @@ Statistics::time_to_string(float time)
return os.str();
}

void
Statistics::check_coins()
{
if (m_cleared_coins)
return;

if (m_coins >= m_total_coins)
{
m_cleared_coins = true;
SoundManager::current()->play("/sounds/coins_cleared.ogg", 0.5f);
}
}

void
Statistics::check_badguys()
{
if (m_cleared_badguys)
return;

if (m_badguys >= m_total_badguys)
{
m_cleared_badguys = true;
SoundManager::current()->play("/sounds/retro_fall.wav", 0.5f);
}
}

void
Statistics::check_secrets()
{
if (m_cleared_secrets)
return;

if (m_secrets >= m_total_secrets)
{
m_cleared_secrets = true;
SoundManager::current()->play("/sounds/tada.ogg", 0.5f);
}
}

std::string
Statistics::secrets_to_string(int secrets, int total_secrets)
{
Expand Down
34 changes: 30 additions & 4 deletions src/supertux/statistics.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
// Copyright (C) 2006 Ondrej Hosek <ondra.hosek@gmail.com>
// Copyright (C) 2006 Christoph Sommer <christoph.sommer@2006.expires.deltadevelopment.de>
//
//
// 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 3 of the License, or
Expand Down Expand Up @@ -56,22 +57,35 @@ class Statistics final

void draw_worldmap_info(DrawingContext& context, float target_time); /**< draw worldmap stat HUD */
void draw_endseq_panel(DrawingContext& context, Statistics* best_stats, const SurfacePtr& backdrop, float target_time); /**< draw panel shown during level's end sequence */
void draw_ingame_stats(DrawingContext& context, bool on_pause_menu); /**< draw in-game stats */

/** Updates the timers for in-game stats rendering. Should be used from the same object that calls draw_ingame_stats(). */
void update_timers(float dt_sec);

void init(const Level& level);
void finish(float time);
void invalidate();

Status get_status() const { return m_status; }

public:
void update(const Statistics& stats); /**< Given another Statistics object finds the best of each one */
bool completed(const Statistics& stats, const float target_time) const; /* Check if stats match total stats */

int get_coins() const { return m_coins; }
int get_badguys() const { return m_badguys; }
int get_secrets() const { return m_secrets; }
float get_time() const { return m_time; }
Status get_status() const { return m_status; }

void increment_coins() { m_coins++; check_coins(); }
void increment_badguys() { m_badguys++; check_badguys(); }
void increment_secrets() { m_secrets++; check_secrets(); }

private:
void calculate_max_caption_length();

void check_coins();
void check_badguys();
void check_secrets();

private:
enum Status m_status;

Expand All @@ -80,13 +94,21 @@ class Statistics final
int m_total_badguys; /**< (vincible) badguys in level */
int m_total_secrets; /**< secret areas in level */

private:
int m_coins; /**< coins collected */
int m_badguys; /**< badguys actively killed */
int m_secrets; /**< secret areas found */

private:
float m_time; /**< seconds needed */

bool m_cleared_coins,
m_cleared_badguys,
m_cleared_secrets;

float m_coins_time,
m_badguys_time,
m_secrets_time;

private:
int m_max_width; /** < Gets the max width of a stats line, 255 by default */

Expand All @@ -102,6 +124,10 @@ class Statistics final
float WMAP_INFO_TOP_Y1;
float WMAP_INFO_TOP_Y2;

SurfacePtr coin_icon;
SurfacePtr badguy_icon;
SurfacePtr secret_icon;

private:
Statistics(const Statistics&) = delete;
Statistics& operator=(const Statistics&) = delete;
Expand Down
2 changes: 1 addition & 1 deletion src/trigger/secretarea_trigger.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ SecretAreaTrigger::event(Player& , EventType type)
if (!message_displayed) {
message_timer.start(MESSAGE_TIME);
message_displayed = true;
Sector::get().get_level().m_stats.m_secrets++;
Sector::get().get_level().m_stats.increment_secrets();
SoundManager::current()->play("sounds/welldone.ogg");

if (!fade_tilemap.empty()) {
Expand Down