#include <string.h>
#include <errno.h>
#include <unistd.h>
+#include <math.h>
#include <time.h>
#include <SDL.h>
#include "level.h"
#include "scene.h"
#include "collision.h"
+#include "tile.h"
+#include "particlesystem.h"
/* extern variables */
void activate_bad_guys(void)
{
- int x,y;
-
- /* Activate bad guys: */
-
- for (y = 0; y < 15; y++)
+ for (std::vector<BadGuyData>::iterator i = current_level.badguy_data.begin();
+ i != current_level.badguy_data.end();
+ ++i)
{
- for (x = 0; x < current_level.width; x++)
- {
- if (current_level.tiles[y][x] >= '0' && current_level.tiles[y][x] <= '9')
- {
- add_bad_guy(x * 32, y * 32, static_cast<BadGuyKind>(current_level.tiles[y][x] - '0'));
- current_level.tiles[y][x] = '.';
- }
- }
+ add_bad_guy(i->x, i->y, i->kind);
}
+}
+void activate_particle_systems(void)
+{
+ if(current_level.particle_system == "clouds")
+ {
+ particle_systems.push_back(new CloudParticleSystem);
+ }
+ else if(current_level.particle_system == "snow")
+ {
+ particle_systems.push_back(new SnowParticleSystem);
+ }
+ else if(current_level.particle_system != "")
+ {
+ st_abort("unknown particle system specified in level", "");
+ }
}
/* --- GAME EVENT! --- */
if(show_menu)
menu_event(&event.key.keysym);
- if(player_key_event(&tux,key,DOWN))
+ if(tux.key_event(key,DOWN))
break;
switch(key)
case SDL_KEYUP: /* A keyrelease! */
key = event.key.keysym.sym;
- if(player_key_event(&tux,key,UP))
+ if(tux.key_event(key, UP))
break;
switch(key)
case SDLK_f:
if(debug_fps)
debug_fps = false;
- else
+ else
debug_fps = true;
- break;
+ break;
default:
break;
}
arrays_free();
return(0);
}
- player_level_begin(&tux);
+ tux.level_begin();
}
else
{
- player_dying(&tux);
+ tux.is_dying();
/* No more lives!? */
/* Either way, (re-)load the (next) level... */
- player_level_begin(&tux);
+ tux.level_begin();
set_defaults();
level_free(¤t_level);
arrays_free();
arrays_init();
activate_bad_guys();
+ activate_particle_systems();
level_free_gfx();
level_load_gfx(¤t_level);
level_free_song();
play_current_music();
}
- player_action(&tux);
+ tux.action();
/* Handle bouncy distros: */
-
for (i = 0; i < bouncy_distros.size(); i++)
{
bouncy_distro_action(&bouncy_distros[i]);
/* Handle broken bricks: */
-
for (i = 0; i < broken_bricks.size(); i++)
{
broken_brick_action(&broken_bricks[i]);
bad_guys[i].action();
}
+ /* update particle systems */
+ std::vector<ParticleSystem*>::iterator p;
+ for(p = particle_systems.begin(); p != particle_systems.end(); ++p)
+ {
+ (*p)->simulate(frame_ratio);
+ }
+
/* Handle all possible collisions. */
collision_handler();
void game_draw(void)
{
- int y, s;
- unsigned int i,x;
+int y,x;
/* Draw screen: */
-
- if (tux.dying && (frame % 4) == 0)
+ if (tux.dying && (global_frame_counter % 4) == 0)
clearscreen(255, 255, 255);
else if(timer_check(&super_bkgd_timer))
texture_draw(&img_super_bkgd, 0, 0);
/* Draw the real background */
if(current_level.bkgd_image[0] != '\0')
{
- s = (int)scroll_x / 30;
+ int s = (int)scroll_x / 30;
texture_draw_part(&img_bkgd,s,0,0,0,img_bkgd.w - s, img_bkgd.h);
texture_draw_part(&img_bkgd,0,0,screen->w - s ,0,s,img_bkgd.h);
}
}
}
+ /* Draw particle systems (background) */
+ std::vector<ParticleSystem*>::iterator p;
+ for(p = particle_systems.begin(); p != particle_systems.end(); ++p)
+ {
+ (*p)->draw(scroll_x, 0, 0);
+ }
+
/* Draw background: */
for (y = 0; y < 15; ++y)
for (x = 0; x < 21; ++x)
{
drawshape(32*x - fmodf(scroll_x, 32), y * 32,
- current_level.tiles[(int)y][(int)x + (int)(scroll_x / 32)]);
+ current_level.bg_tiles[(int)y][(int)x + (int)(scroll_x / 32)]);
}
}
+ /* Draw interactive tiles: */
- /* (Bouncy bricks): */
-
- for (i = 0; i < bouncy_bricks.size(); ++i)
- {
- bouncy_brick_draw(&bouncy_bricks[i]);
- }
-
-
- /* (Bad guys): */
-
- for (i = 0; i < bad_guys.size(); ++i)
+ for (y = 0; y < 15; ++y)
{
- bad_guys[i].draw();
+ for (x = 0; x < 21; ++x)
+ {
+ drawshape(32*x - fmodf(scroll_x, 32), y * 32,
+ current_level.ia_tiles[(int)y][(int)x + (int)(scroll_x / 32)]);
+ }
}
- /* (Tux): */
-
- player_draw(&tux);
+ /* (Bouncy bricks): */
- /* (Bullets): */
+ for (unsigned int i = 0; i < bouncy_bricks.size(); ++i)
+ bouncy_brick_draw(&bouncy_bricks[i]);
- for (i = 0; i < bullets.size(); ++i)
- {
- bullet_draw(&bullets[i]);
- }
+ for (unsigned int i = 0; i < bad_guys.size(); ++i)
+ bad_guys[i].draw();
- /* (Floating scores): */
+ tux.draw();
- for (i = 0; i < floating_scores.size(); ++i)
- {
- floating_score_draw(&floating_scores[i]);
- }
+ for (unsigned int i = 0; i < bullets.size(); ++i)
+ bullet_draw(&bullets[i]);
+ for (unsigned int i = 0; i < floating_scores.size(); ++i)
+ floating_score_draw(&floating_scores[i]);
- /* (Upgrades): */
+ for (unsigned int i = 0; i < upgrades.size(); ++i)
+ upgrade_draw(&upgrades[i]);
- for (i = 0; i < upgrades.size(); ++i)
- {
- upgrade_draw(&upgrades[i]);
- }
+ for (unsigned int i = 0; i < bouncy_distros.size(); ++i)
+ bouncy_distro_draw(&bouncy_distros[i]);
+ for (unsigned int i = 0; i < broken_bricks.size(); ++i)
+ broken_brick_draw(&broken_bricks[i]);
- /* (Bouncy distros): */
+ /* Draw foreground: */
- for (i = 0; i < bouncy_distros.size(); ++i)
+ for (y = 0; y < 15; ++y)
{
- bouncy_distro_draw(&bouncy_distros[i]);
+ for (x = 0; x < 21; ++x)
+ {
+ drawshape(32*x - fmodf(scroll_x, 32), y * 32,
+ current_level.fg_tiles[(int)y][(int)x + (int)(scroll_x / 32)]);
+ }
}
-
- /* (Broken bricks): */
-
- for (i = 0; i < broken_bricks.size(); ++i)
+ /* Draw particle systems (foreground) */
+ for(p = particle_systems.begin(); p != particle_systems.end(); ++p)
{
- broken_brick_draw(&broken_bricks[i]);
+ (*p)->draw(scroll_x, 0, 1);
}
drawstatus();
-
if(game_pause)
{
- x = screen->h / 20;
- for(i = 0; i < x; ++i)
+ int x = screen->h / 20;
+ for(int i = 0; i < x; ++i)
{
fillrect(i % 2 ? (pause_menu_frame * i)%screen->w : -((pause_menu_frame * i)%screen->w) ,(i*20+pause_menu_frame)%screen->h,screen->w,10,20,20,20, rand() % 20 + 1);
}
menu_process_current();
/* (Update it all!) */
-
updatescreen();
-
-
}
/* --- GAME LOOP! --- */
level_load_gfx(¤t_level);
activate_bad_guys();
+ activate_particle_systems();
level_load_song(¤t_level);
- player_init(&tux);
+ tux.init();
if(st_gl_mode != ST_GL_TEST)
load_hs();
if(st_gl_mode == ST_GL_LOAD_GAME)
loadgame(levelnb);
-
/* --- MAIN GAME LOOP!!! --- */
jump = false;
done = 0;
quit = 0;
- frame = 0;
+ global_frame_counter = 0;
game_pause = 0;
timer_init(&fps_timer,true);
timer_init(&frame_timer,true);
while (SDL_PollEvent(&event))
- {}
+ {}
game_draw();
do
frame_ratio = ((double)(update_time-last_update_time))/((double)FRAME_RATE);
if(frame_ratio > 1.5) /* Quick hack to correct the unprecise CPU clocks a little bit. */
frame_ratio = 1.5 + (frame_ratio - 1.5) * 0.85;
-
+
if(!timer_check(&frame_timer))
{
timer_start(&frame_timer,25);
- ++frame;
+ ++global_frame_counter;
}
/* Handle events: */
/* == -1: continues */
return 0;
}
- /* --z;
- }*/
+ /* --z;
+ }*/
}
else
{
SDL_Delay(50);
}
- if(debug_mode && debug_fps == true)
+ if(debug_mode && debug_fps)
SDL_Delay(60);
/*Draw the current scene to the screen */
last_update_time = update_time;
update_time = st_get_ticks();
-
/* Pause till next frame, if the machine running the game is too fast: */
/* FIXME: Works great for in OpenGl mode, where the CPU doesn't have to do that much. But
the results in SDL mode aren't perfect (thought the 100 FPS are reached), even on an AMD2500+. */
}
else
- player_kill(&tux,KILL);
+ tux.kill(KILL);
/* Calculate frames per second */
"/images/shared/bag-right-1.png",
USE_ALPHA);
+ /* Mr. Bomb */
+ for(int i=0; i<4; ++i) {
+ char num[4];
+ snprintf(num, 4, "%d", i);
+ texture_load(&img_mrbomb_left[i],
+ datadir + "/images/shared/mrbomb-left-" + num + ".png", USE_ALPHA);
+ texture_load(&img_mrbomb_right[i],
+ datadir + "/images/shared/mrbomb-right-" + num + ".png", USE_ALPHA);
+ }
+ /* stalactite */
+ texture_load(&img_stalactite,
+ datadir + "/images/shared/stalactite.png", USE_ALPHA);
+ texture_load(&img_stalactite_broken,
+ datadir + "/images/shared/stalactite-broken.png", USE_ALPHA);
/* Upgrades: */
texture_free(&img_money_right[i]);
}
+ for(i = 0; i < 4; i++) {
+ texture_free(&img_mrbomb_left[i]);
+ texture_free(&img_mrbomb_right[i]);
+ }
+
+ texture_free(&img_stalactite);
+ texture_free(&img_stalactite_broken);
+
texture_free(&img_box_full);
texture_free(&img_box_empty);
/* Draw a tile on the screen: */
-void drawshape(float x, float y, unsigned char c)
+void drawshape(float x, float y, unsigned int c)
{
- int z;
+ if (c != 0)
+ {
+ Tile* ptile = TileManager::instance()->get(c);
+ if(ptile)
+ {
+ if(ptile->images.size() > 1)
+ {
+ texture_draw(&ptile->images[( ((global_frame_counter*25) / ptile->anim_speed) % (ptile->images.size()))],x,y);
+ }
+ else if (ptile->images.size() == 1)
+ {
+ texture_draw(&ptile->images[0],x,y);
+ }
+ else
+ {
+ printf("Tile not dravable %u\n", c);
+ }
+ }
+ }
+ /*
if (c == 'X' || c == 'x')
texture_draw(&img_brick[0], x, y);
else if (c == 'Y' || c == 'y')
texture_draw(&img_solid[3], x, y);
else if (c == '$')
{
- z = (frame / 2) % 6;
+ z = (global_frame_counter / 2) % 6;
if (z < 4)
texture_draw(&img_distro[z], x, y);
}
else if (c == '^')
{
- z = (frame / 3) % 3;
+ z = (global_frame_counter / 3) % 3;
texture_draw(&img_waves[z], x, y);
}
}
else if (c == '\\')
{
- z = (frame / 3) % 2;
+ z = (global_frame_counter / 3) % 2;
texture_draw(&img_flag[z], x + 16, y);
}
else if (c == '&')
- texture_draw(&img_water, x, y);
+ texture_draw(&img_water, x, y);*/
+
}
/* What shape is at some position? */
-
-unsigned char shape(float x, float y)
+unsigned int shape(float x, float y)
{
int xx, yy;
- unsigned char c;
+ unsigned int c;
yy = ((int)y / 32);
xx = ((int)x / 32);
if (yy >= 0 && yy < 15 && xx >= 0 && xx <= current_level.width)
{
- c = current_level.tiles[yy][xx];
+ c = current_level.ia_tiles[yy][xx];
}
else
- c = '.';
+ c = 0;
return(c);
}
-/* Is is ground? */
-
+Tile* gettile(float x, float y)
+{
+ return TileManager::instance()->get(shape(x, y));
+}
bool issolid(float x, float y)
{
- return (isbrick(x, y) ||
- isice(x, y) ||
- (shape(x, y) == '[') ||
- (shape(x, y) == '=') ||
- (shape(x, y) == ']') ||
- (shape(x, y) == 'A') ||
- (shape(x, y) == 'B') ||
- (shape(x, y) == '!') ||
- (shape(x, y) == 'a'));
+ Tile* tile = TileManager::instance()->get
+ (shape(x,y));
+ if(tile)
+ {
+ if(tile->solid == true)
+ return true;
+ else
+ return false;
+ }
+ else
+ {
+ return false;
+ }
}
/* Is it a brick? */
bool isbrick(float x, float y)
{
- return (shape(x, y) == 'X' ||
- shape(x, y) == 'x' ||
- shape(x, y) == 'Y' ||
- shape(x, y) == 'y');
+ Tile* tile = TileManager::instance()->get
+ (shape(x,y));
+ if(tile)
+ {
+ if(tile->brick == true)
+ return true;
+ else
+ return false;
+ }
+ else
+ {
+ return false;
+ }
}
bool isice(float x, float y)
{
- return (shape(x, y) == '#');
+ Tile* tile = TileManager::instance()->get
+ (shape(x,y));
+ if(tile)
+ {
+ if(tile->ice == true)
+ return true;
+ else
+ return false;
+ }
+ else
+ {
+ return false;
+ }
}
/* Is it a full box? */
bool isfullbox(float x, float y)
{
- return (shape(x, y) == 'A' ||
- shape(x, y) == 'B' ||
- shape(x, y) == '!');
+ Tile* tile = TileManager::instance()->get
+ (shape(x,y));
+ if(tile)
+ {
+ if(tile->fullbox == true)
+ return true;
+ else
+ return false;
+ }
+ else
+ {
+ return false;
+ }
+}
+
+bool isdistro(float x, float y)
+{
+ Tile* tile = TileManager::instance()->get(shape(x,y));
+ return tile && tile->distro;
}
/* Break a brick: */
void trybreakbrick(float x, float y)
{
- if (isbrick(x, y))
+ Tile* tile = gettile(x, y);
+ if (tile->brick)
{
- if (shape(x, y) == 'x' || shape(x, y) == 'y')
+ if (tile->data > 0)
{
/* Get a distro from it: */
-
add_bouncy_distro(((int)(x + 1) / 32) * 32,
(int)(y / 32) * 32);
}
if (distro_counter <= 0)
- level_change(¤t_level,x, y, 'a');
+ level_change(¤t_level,x, y, TM_IA, tile->next_tile2);
play_sound(sounds[SND_DISTRO], SOUND_CENTER_SPEAKER);
score = score + SCORE_DISTRO;
else
{
/* Get rid of it: */
-
- level_change(¤t_level,x, y,'.');
+ level_change(¤t_level,x, y, TM_IA, tile->next_tile);
}
/* Empty a box: */
-
void tryemptybox(float x, float y, int col_side)
{
- if (!isfullbox(x, y))
+ Tile* tile = gettile(x,y);
+ if (!tile->fullbox)
return;
// according to the collision side, set the upgrade direction
-
if(col_side == LEFT)
col_side = RIGHT;
else
col_side = LEFT;
- switch(shape(x,y))
+ switch(tile->data)
{
- case 'A': /* Box with a distro! */
+ case 1: //'A': /* Box with a distro! */
add_bouncy_distro(((int)(x + 1) / 32) * 32, (int)(y / 32) * 32 - 32);
play_sound(sounds[SND_DISTRO], SOUND_CENTER_SPEAKER);
score = score + SCORE_DISTRO;
distros++;
break;
- case 'B': /* Add an upgrade! */
+
+ case 2: // 'B': /* Add an upgrade! */
if (tux.size == SMALL) /* Tux is small, add mints! */
add_upgrade((int)((x + 1) / 32) * 32, (int)(y / 32) * 32 - 32, col_side, UPGRADE_MINTS);
else /* Tux is big, add coffee: */
add_upgrade((int)((x + 1) / 32) * 32, (int)(y / 32) * 32 - 32, col_side, UPGRADE_COFFEE);
play_sound(sounds[SND_UPGRADE], SOUND_CENTER_SPEAKER);
break;
- case '!': /* Add a golden herring */
+
+ case 3:// '!': /* Add a golden herring */
add_upgrade((int)((x + 1) / 32) * 32, (int)(y / 32) * 32 - 32, col_side, UPGRADE_HERRING);
break;
default:
}
/* Empty the box: */
- level_change(¤t_level,x, y, 'a');
+ level_change(¤t_level,x, y, TM_IA, tile->next_tile);
}
-
/* Try to grab a distro: */
-
void trygrabdistro(float x, float y, int bounciness)
{
- if (shape(x, y) == '$')
+ Tile* tile = gettile(x, y);
+ if (tile && tile->distro)
{
- level_change(¤t_level,x, y, '.');
+ level_change(¤t_level,x, y, TM_IA, tile->next_tile);
play_sound(sounds[SND_DISTRO], SOUND_CENTER_SPEAKER);
if (bounciness == BOUNCE)
}
/* Try to bump a bad guy from below: */
-
void trybumpbadguy(float x, float y)
{
- unsigned int i;
-
/* Bad guys: */
- for (i = 0; i < bad_guys.size(); i++)
+ for (unsigned int i = 0; i < bad_guys.size(); i++)
{
if (bad_guys[i].base.x >= x - 32 && bad_guys[i].base.x <= x + 32 &&
bad_guys[i].base.y >= y - 16 && bad_guys[i].base.y <= y + 16)
{
- if (bad_guys[i].kind == BAD_BSOD ||
- bad_guys[i].kind == BAD_LAPTOP)
- {
- bad_guys[i].dying = DYING_FALLING;
- bad_guys[i].base.ym = -8;
- play_sound(sounds[SND_FALL], SOUND_CENTER_SPEAKER);
- }
+ bad_guys[i].collision(&tux, CO_PLAYER, COLLISION_BUMP);
}
}
/* Upgrades: */
- for (i = 0; i < upgrades.size(); i++)
+ for (unsigned int i = 0; i < upgrades.size(); i++)
{
if (upgrades[i].base.height == 32 &&
upgrades[i].base.x >= x - 32 && upgrades[i].base.x <= x + 32 &&
text_draw(&white_text,"Press ESC To Return",0,20,1);
}
- if (timer_get_left(&time_left) > TIME_WARNING || (frame % 10) < 5)
+ if (timer_get_left(&time_left) > TIME_WARNING || (global_frame_counter % 10) < 5)
{
sprintf(str, "%d", timer_get_left(&time_left) / 1000 );
text_draw(&white_text, "TIME", 224, 0, 1);
if (fi == NULL)
{
fprintf(stderr, "Warning: I could not open the slot file ");
-
}
else
{
fwrite(&score,sizeof(int),1,fi);
fwrite(&distros,sizeof(int),1,fi);
fwrite(&scroll_x,sizeof(float),1,fi);
- fwrite(&tux,sizeof(player_type),1,fi);
+ fwrite(&tux,sizeof(Player),1,fi);
timer_fwrite(&tux.invincible_timer,fi);
timer_fwrite(&tux.skidding_timer,fi);
timer_fwrite(&tux.safe_timer,fi);
arrays_free();
arrays_init();
activate_bad_guys();
+ activate_particle_systems();
level_free_gfx();
level_load_gfx(¤t_level);
level_free_song();
fread(&score,sizeof(int),1,fi);
fread(&distros,sizeof(int),1,fi);
fread(&scroll_x,sizeof(float),1,fi);
- fread(&tux,sizeof(player_type),1,fi);
+ fread(&tux, sizeof(Player), 1, fi);
timer_fread(&tux.invincible_timer,fi);
timer_fread(&tux.skidding_timer,fi);
timer_fread(&tux.safe_timer,fi);