return false;
}
+void* collision_func(const base_type& base, tiletestfunction function)
+{
+ for(float x = base.x; x < base.x + base.width; x += 32) {
+ for(float y = base.y; y < base.y + base.height; y += 32) {
+ Tile* tile = gettile(x, y);
+ void* result = function(tile);
+ if(result != 0)
+ return result;
+ }
+ }
+
+ return 0;
+}
+
+static void* test_goal_tile_function(Tile* tile)
+{
+ if(tile->goal)
+ return tile;
+ return 0;
+}
+
+Tile* collision_goal(const base_type& base)
+{
+ return (Tile*) collision_func(base, test_goal_tile_function);
+}
void collision_swept_object_map(base_type* old, base_type* current)
{
bool isice(float x, float y);
bool isfullbox(float x, float y);
+typedef void* (*tiletestfunction)(Tile* tile);
+/** invokes the function for each tile the baserectangle collides with. The
+ * function aborts and returns true as soon as the tiletestfunction returns
+ * != 0 then this value is returned. returns 0 if all tests failed.
+ */
+void* collision_func(const base_type& base, tiletestfunction* function);
+
+Tile* collision_goal(const base_type& base);
+
#endif /*SUPERTUX_COLLISION_H*/
}
}
-
void
GameSession::check_end_conditions()
{
Player* tux = world->get_tux();
/* End of level? */
- if (tux->base.x >= World::current()->get_level()->endpos + 32 * (get_level()->use_endsequence ? 22 : 10))
+ int endpos = (World::current()->get_level()->width-10) * 32;
+ Tile* endtile = collision_goal(tux->base);
+ printf("EndTile: %p.\n", endtile);
+ // fallback in case the other endpositions don't trigger
+ if (tux->base.x >= endpos || (endtile && endtile->data >= 1)
+ || (end_sequence && !endsequence_timer.check()))
{
exit_status = LEVEL_FINISHED;
+ return;
}
- else if (tux->base.x >= World::current()->get_level()->endpos && !end_sequence)
+ else if(!end_sequence && endtile && endtile->data == 0)
{
end_sequence = true;
last_x_pos = -1;
music_manager->halt_music();
+ endsequence_timer.start(5000); // 5 seconds until we finish the map
}
- else
+ else if (!end_sequence && tux->is_dead())
{
- // Check End conditions
- if (tux->is_dead())
- {
- player_status.lives -= 1;
-
- if (player_status.lives < 0)
- { // No more lives!?
- if(st_gl_mode != ST_GL_TEST)
- drawendscreen();
-
- exit_status = GAME_OVER;
- }
- else
- { // Still has lives, so reset Tux to the levelstart
- restart_level();
- }
+ player_status.lives -= 1;
+
+ if (player_status.lives < 0)
+ { // No more lives!?
+ if(st_gl_mode != ST_GL_TEST)
+ drawendscreen();
+
+ exit_status = GAME_OVER;
}
- }
+ else
+ { // Still has lives, so reset Tux to the levelstart
+ restart_level();
+ }
+
+ return;
+ }
}
void
private:
Timer fps_timer;
Timer frame_timer;
+ Timer endsequence_timer;
World* world;
int st_gl_mode;
int levelnb;
bkgd_bottom.red = 255;
bkgd_bottom.green = 255;
bkgd_bottom.blue = 255;
- endpos = 0;
- use_endsequence = false;
for(int i = 0; i < 15; ++i)
{
LispReader reader(lisp_cdr(root_obj));
version = 0;
reader.read_int("version", &version);
- use_endsequence = false;
- reader.read_bool("use-endsequence", &use_endsequence);
if(!reader.read_int("width", &width))
st_abort("No width specified for level.", "");
if (!reader.read_int("start_pos_x", &start_pos_x)) start_pos_x = 100;
}
}
- // Mark the end position of this level!
- // FIXME: -10 is a rather random value, we still need some kind of
- // real levelend gola
- if (use_endsequence)
- endpos = 32*(width-30);
- else
- endpos = 32*(width-15);
-
lisp_free(root_obj);
fclose(fi);
return 0;
int width;
int start_pos_x;
int start_pos_y;
- int endpos;
- bool use_endsequence;
float gravity;
std::vector<BadGuyData> badguy_data;
tile->water = false;
tile->fullbox = false;
tile->distro = false;
+ tile->goal = false;
tile->data = 0;
tile->next_tile = 0;
tile->anim_speed = 25;
reader.read_bool("water", &tile->water);
reader.read_bool("fullbox", &tile->fullbox);
reader.read_bool("distro", &tile->distro);
+ reader.read_bool("goal", &tile->goal);
+ if(tile->goal) printf("Goal!.\n");
reader.read_int("data", &tile->data);
reader.read_int("anim-speed", &tile->anim_speed);
reader.read_int("next-tile", &tile->next_tile);
/** Tile is a distro/coin */
bool distro;
+ /** the level should be finished when touching a goaltile.
+ * if data is 0 then the endsequence should be triggered, if data is 1
+ * then we can finish the level instantly.
+ */
+ bool goal;
+
/** General purpose data attached to a tile (content of a box, type of coin) */
int data;
st_pause_count = 0;
}
+Timer::Timer()
+{
+ init(true);
+}
+
void
Timer::init(bool st_ticks)
{
unsigned int (*get_ticks) (void);
public:
+ Timer();
+
void init(bool st_ticks);
void start(unsigned int period);
void stop();