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.
(version 2)
(name (_ "Welcome to Antarctica"))
(author "SuperTux Team")
+ (target-time 30)
(license "GPL 2+ / CC-by-sa 3.0")
(sector
(name "main")
(version 2)
(name (_ "The Journey Begins"))
(author "SuperTux Team")
+ (target-time 30)
(license "GPL 2+ / CC-by-sa 3.0")
(sector
(name "main")
(version 2)
(name (_ "Via Nostalgica"))
(author "SuperTux Team")
+ (target-time 60)
(license "GPL 2+ / CC-by-sa 3.0")
(sector
(name "main")
(version 2)
(name (_ "Tobgle Road"))
(author "SuperTux Team")
+ (target-time 60)
(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")
+ (target-time 60)
(sector
(name "main")
(music "music/chipdisko.ogg")
(name (_ "The Frosted Fields"))
(author "SuperTux Team")
(license "GPL 2+ / CC-by-sa 3.0")
+ (target-time 80)
(sector
(name "main")
(music "music/chipdisko.ogg")
(name (_ "Oh no! More Snowballs!"))
(author "Voluptuous Pachyderm")
(license "GPL 2+ / CC-by-sa 3.0")
+ (target-time 80)
(sector
(name "main")
(music "music/voc-daytime2.music")
(name (_ "Stone Cold"))
(author "SuperTux Team")
(license "GPL 2+ / CC-by-sa 3.0")
+ (target-time 80)
(sector
(name "main")
(music "music/chipdisko.ogg")
(name (_ "Grumbel's Sense of Snow"))
(author "SuperTux Team")
(license "GPL 2+ / CC-by-sa 3.0")
+ (target-time 80)
(sector
(name "main")
(music "music/chipdisko.ogg")
(name (_ "23rd Airborne"))
(author "SuperTux Team")
(license "GPL 2+ / CC-by-sa 3.0")
+ (target-time 80)
(sector
(name "main")
(music "music/airship_remix.music")
(name (_ "Night Chill"))
(author "SuperTux Team")
(license "GPL 2+ / CC-by-sa 3.0")
+ (target-time 100)
(sector
(name "main")
(music "music/voc-night.music")
(name (_ "Into the Stars"))
(author "SuperTux Team")
(license "GPL 2+ / CC-by-sa 3.0")
+ (target-time 80)
(sector
(name "main")
(music "music/voc-night.music")
(name (_ "Above the Arctic Skies"))
(author "SuperTux Team")
(license "GPL 2+ / CC-by-sa 3.0")
+ (target-time 40)
(sector
(name "main")
(music "music/airship_remix.music")
(name (_ "Entrance to the Cave"))
(author "SuperTux Team")
(license "GPL 2+ / CC-by-sa 3.0")
+ (target-time 80)
(sector
(name "main")
(music "music/chipdisko.ogg")
(author "LMH")
(contact "lmh.0013@gmail.com")
(license "GPL 2 / CC-by-sa 3.0")
+ (target-time 60)
(sector
(name "main")
(music "music/voc-daytime2.ogg")
on_menukey_script(),
sectors(),
stats(),
+ target_time(),
tileset(NULL),
free_tileset(false)
{
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;
}
std::string on_menukey_script;
Sectors sectors;
Statistics stats;
+ float target_time;
TileSet *tileset;
bool free_tileset;
}
bool
-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 &&
- stats.secrets == stats.total_secrets);
+ stats.secrets == stats.total_secrets &&
+ ((!target_time) || (stats.time <= target_time)));
}
void
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. */
auto_play(false),
sprite(),
statistics(),
+ target_time(),
extro_script(),
basedir(basedir),
picture_cached(false),
/** Statistics for level tiles */
Statistics statistics;
+ float target_time;
/** 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();
// 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");
}
private:
void get_level_title(LevelTile& level);
+ void get_level_target_time(LevelTile& level);
void draw_status(DrawingContext& context);
void calculate_total_stats();