As a proof of principle, Icy Island levels prior to the underground sequence have been assigned arbitrary but attainable target times. However, this feature probably should only be used with great care in the main game (if at all). Statistics still need to be modified to display the target time if defined, otherwise it will be confusing to players trying for perfet stats.
23 files changed:
(version 2)
(name (_ "Welcome to Antarctica"))
(author "SuperTux Team")
(version 2)
(name (_ "Welcome to Antarctica"))
(author "SuperTux Team")
(license "GPL 2+ / CC-by-sa 3.0")
(sector
(name "main")
(license "GPL 2+ / CC-by-sa 3.0")
(sector
(name "main")
(version 2)
(name (_ "The Journey Begins"))
(author "SuperTux Team")
(version 2)
(name (_ "The Journey Begins"))
(author "SuperTux Team")
(license "GPL 2+ / CC-by-sa 3.0")
(sector
(name "main")
(license "GPL 2+ / CC-by-sa 3.0")
(sector
(name "main")
(version 2)
(name (_ "Via Nostalgica"))
(author "SuperTux Team")
(version 2)
(name (_ "Via Nostalgica"))
(author "SuperTux Team")
(license "GPL 2+ / CC-by-sa 3.0")
(sector
(name "main")
(license "GPL 2+ / CC-by-sa 3.0")
(sector
(name "main")
(version 2)
(name (_ "Tobgle Road"))
(author "SuperTux Team")
(version 2)
(name (_ "Tobgle Road"))
(author "SuperTux Team")
(license "GPL 2+ / CC-by-sa 3.0")
(sector
(name "main")
(license "GPL 2+ / CC-by-sa 3.0")
(sector
(name "main")
(name (_ "The Somewhat Smaller Bath"))
(author "Philippe Saint-Pierre")
(license "GPL 2+ / CC-by-sa 3.0")
(name (_ "The Somewhat Smaller Bath"))
(author "Philippe Saint-Pierre")
(license "GPL 2+ / CC-by-sa 3.0")
(sector
(name "main")
(music "music/chipdisko.ogg")
(sector
(name "main")
(music "music/chipdisko.ogg")
(name (_ "The Frosted Fields"))
(author "SuperTux Team")
(license "GPL 2+ / CC-by-sa 3.0")
(name (_ "The Frosted Fields"))
(author "SuperTux Team")
(license "GPL 2+ / CC-by-sa 3.0")
(sector
(name "main")
(music "music/chipdisko.ogg")
(sector
(name "main")
(music "music/chipdisko.ogg")
(name (_ "Oh no! More Snowballs!"))
(author "Voluptuous Pachyderm")
(license "GPL 2+ / CC-by-sa 3.0")
(name (_ "Oh no! More Snowballs!"))
(author "Voluptuous Pachyderm")
(license "GPL 2+ / CC-by-sa 3.0")
(sector
(name "main")
(music "music/voc-daytime2.music")
(sector
(name "main")
(music "music/voc-daytime2.music")
(name (_ "Stone Cold"))
(author "SuperTux Team")
(license "GPL 2+ / CC-by-sa 3.0")
(name (_ "Stone Cold"))
(author "SuperTux Team")
(license "GPL 2+ / CC-by-sa 3.0")
(sector
(name "main")
(music "music/chipdisko.ogg")
(sector
(name "main")
(music "music/chipdisko.ogg")
(name (_ "Grumbel's Sense of Snow"))
(author "SuperTux Team")
(license "GPL 2+ / CC-by-sa 3.0")
(name (_ "Grumbel's Sense of Snow"))
(author "SuperTux Team")
(license "GPL 2+ / CC-by-sa 3.0")
(sector
(name "main")
(music "music/chipdisko.ogg")
(sector
(name "main")
(music "music/chipdisko.ogg")
(name (_ "23rd Airborne"))
(author "SuperTux Team")
(license "GPL 2+ / CC-by-sa 3.0")
(name (_ "23rd Airborne"))
(author "SuperTux Team")
(license "GPL 2+ / CC-by-sa 3.0")
(sector
(name "main")
(music "music/airship_remix.music")
(sector
(name "main")
(music "music/airship_remix.music")
(name (_ "Night Chill"))
(author "SuperTux Team")
(license "GPL 2+ / CC-by-sa 3.0")
(name (_ "Night Chill"))
(author "SuperTux Team")
(license "GPL 2+ / CC-by-sa 3.0")
(sector
(name "main")
(music "music/voc-night.music")
(sector
(name "main")
(music "music/voc-night.music")
(name (_ "Into the Stars"))
(author "SuperTux Team")
(license "GPL 2+ / CC-by-sa 3.0")
(name (_ "Into the Stars"))
(author "SuperTux Team")
(license "GPL 2+ / CC-by-sa 3.0")
(sector
(name "main")
(music "music/voc-night.music")
(sector
(name "main")
(music "music/voc-night.music")
(name (_ "Above the Arctic Skies"))
(author "SuperTux Team")
(license "GPL 2+ / CC-by-sa 3.0")
(name (_ "Above the Arctic Skies"))
(author "SuperTux Team")
(license "GPL 2+ / CC-by-sa 3.0")
(sector
(name "main")
(music "music/airship_remix.music")
(sector
(name "main")
(music "music/airship_remix.music")
(name (_ "Entrance to the Cave"))
(author "SuperTux Team")
(license "GPL 2+ / CC-by-sa 3.0")
(name (_ "Entrance to the Cave"))
(author "SuperTux Team")
(license "GPL 2+ / CC-by-sa 3.0")
(sector
(name "main")
(music "music/chipdisko.ogg")
(sector
(name "main")
(music "music/chipdisko.ogg")
(author "LMH")
(contact "lmh.0013@gmail.com")
(license "GPL 2 / CC-by-sa 3.0")
(author "LMH")
(contact "lmh.0013@gmail.com")
(license "GPL 2 / CC-by-sa 3.0")
(sector
(name "main")
(music "music/voc-daytime2.ogg")
(sector
(name "main")
(music "music/voc-daytime2.ogg")
on_menukey_script(),
sectors(),
stats(),
on_menukey_script(),
sectors(),
stats(),
tileset(NULL),
free_tileset(false)
{
tileset(NULL),
free_tileset(false)
{
Sector* sector = new Sector(this);
sector->parse(*(iter.lisp()));
add_sector(sector);
Sector* sector = new Sector(this);
sector->parse(*(iter.lisp()));
add_sector(sector);
+ } else if(token == "target-time") {
+ iter.value()->get(target_time);
} else {
log_warning << "Unknown token '" << token << "' in level file" << std::endl;
}
} else {
log_warning << "Unknown token '" << token << "' in level file" << std::endl;
}
std::string on_menukey_script;
Sectors sectors;
Statistics stats;
std::string on_menukey_script;
Sectors sectors;
Statistics stats;
TileSet *tileset;
bool free_tileset;
TileSet *tileset;
bool free_tileset;
-Statistics::completed(const Statistics& stats)
+Statistics::completed(const Statistics& stats, const float target_time)
{
return (stats.coins == stats.total_coins &&
stats.badguys == stats.total_badguys &&
{
return (stats.coins == stats.total_coins &&
stats.badguys == stats.total_badguys &&
- stats.secrets == stats.total_secrets);
+ stats.secrets == stats.total_secrets &&
+ ((!target_time) || (stats.time <= target_time)));
void reset(); /**< Set stats (but not totals) to zero */
void merge(const Statistics& stats); /**< Given another Statistics object finds the best of each one */
void operator+=(const Statistics& o); /**< Add two Statistics objects */
void reset(); /**< Set stats (but not totals) to zero */
void merge(const Statistics& stats); /**< Given another Statistics object finds the best of each one */
void operator+=(const Statistics& o); /**< Add two Statistics objects */
- bool completed(const Statistics& stats); /* Check if stats match total stats */
+ bool completed(const Statistics& stats, const float target_time); /* Check if stats match total stats */
void declare_invalid(); /**< marks statistics as invalid for their entire lifetime (e.g. after cheating). Invalid statistics will not be merged or drawn. */
void declare_invalid(); /**< marks statistics as invalid for their entire lifetime (e.g. after cheating). Invalid statistics will not be merged or drawn. */
auto_play(false),
sprite(),
statistics(),
auto_play(false),
sprite(),
statistics(),
extro_script(),
basedir(basedir),
picture_cached(false),
extro_script(),
basedir(basedir),
picture_cached(false),
/** Statistics for level tiles */
Statistics statistics;
/** Statistics for level tiles */
Statistics statistics;
/** Script that is run when the level is successfully finished */
std::string extro_script;
/** Script that is run when the level is successfully finished */
std::string extro_script;
+void
+WorldMap::get_level_target_time(LevelTile& level)
+{
+ try {
+ lisp::Parser parser;
+ const lisp::Lisp* root = parser.parse(levels_path + level.get_name());
+
+ const lisp::Lisp* level_lisp = root->get_lisp("supertux-level");
+ if(!level_lisp)
+ return;
+
+ level_lisp->get("target-time", level.target_time);
+ } catch(std::exception& e) {
+ log_warning << "Problem when reading level target time: " << e.what() << std::endl;
+ return;
+ }
+}
+
void WorldMap::calculate_total_stats()
{
total_stats.zero();
void WorldMap::calculate_total_stats()
{
total_stats.zero();
// deal with statistics
level->statistics.merge(gamelevel->stats);
calculate_total_stats();
// deal with statistics
level->statistics.merge(gamelevel->stats);
calculate_total_stats();
- if(level->statistics.completed(level->statistics)) {
+ get_level_target_time(*level);
+ if(level->statistics.completed(level->statistics, level->target_time)) {
level->perfect = true;
level->sprite->set_action("perfect");
}
level->perfect = true;
level->sprite->set_action("perfect");
}
private:
void get_level_title(LevelTile& level);
private:
void get_level_title(LevelTile& level);
+ void get_level_target_time(LevelTile& level);
void draw_status(DrawingContext& context);
void calculate_total_stats();
void draw_status(DrawingContext& context);
void calculate_total_stats();