From c8ad8bb328dd90c0ab00e4c375b9a4b8f8df6e73 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Tobias=20Gl=C3=A4=C3=9Fer?= Date: Wed, 24 Mar 2004 22:25:33 +0000 Subject: [PATCH] new levelformat with multiple layers and and new tileset code. Along with a new particlesystem. (the latest one was contributed by Matze Braun) SVN-Revision: 345 --- src/gameloop.cpp | 209 ++++++++++++++++++++++++++++++++++++---------- src/gameloop.h | 4 +- src/level.cpp | 221 ++++++++++++++++++++++++++++++++++++++++--------- src/level.h | 16 +++- src/leveleditor.cpp | 45 +++------- src/particlesystem.cpp | 141 +++++++++++++++++++++++++++++++ src/particlesystem.h | 103 +++++++++++++++++++++++ src/player.cpp | 6 +- src/scene.h | 4 +- src/setup.cpp | 2 +- src/texture.cpp | 1 - src/tile.cpp | 102 +++++++++++++++++++++++ src/tile.h | 49 +++++++++++ 13 files changed, 775 insertions(+), 128 deletions(-) create mode 100644 src/particlesystem.cpp create mode 100644 src/particlesystem.h create mode 100644 src/tile.cpp create mode 100644 src/tile.h diff --git a/src/gameloop.cpp b/src/gameloop.cpp index d5097b3d8..13347ad45 100644 --- a/src/gameloop.cpp +++ b/src/gameloop.cpp @@ -16,6 +16,7 @@ #include #include #include +#include #include #include @@ -38,6 +39,8 @@ #include "level.h" #include "scene.h" #include "collision.h" +#include "tile.h" +#include "particlesystem.h" /* extern variables */ @@ -105,14 +108,30 @@ void activate_bad_guys(void) { for (x = 0; x < current_level.width; x++) { - if (current_level.tiles[y][x] >= '0' && current_level.tiles[y][x] <= '9') + if (current_level.dn_tiles[y][x] >= '0' && current_level.dn_tiles[y][x] <= '9') { - add_bad_guy(x * 32, y * 32, static_cast(current_level.tiles[y][x] - '0')); - current_level.tiles[y][x] = '.'; + add_bad_guy(x * 32, y * 32, static_cast(current_level.dn_tiles[y][x] - '0')); + current_level.dn_tiles[y][x] = 0; } } } +} +void activate_particle_systems(void) +{ + printf("PSys: %s\n", current_level.particle_system.c_str()); + 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! --- */ @@ -222,9 +241,9 @@ void game_event(void) case SDLK_f: if(debug_fps) debug_fps = false; - else + else debug_fps = true; - break; + break; default: break; } @@ -374,6 +393,7 @@ int game_action(void) arrays_free(); arrays_init(); activate_bad_guys(); + activate_particle_systems(); level_free_gfx(); level_load_gfx(¤t_level); level_free_song(); @@ -450,6 +470,13 @@ int game_action(void) bad_guys[i].action(); } + /* update particle systems */ + std::vector::iterator p; + for(p = particle_systems.begin(); p != particle_systems.end(); ++p) + { + (*p)->simulate(frame_ratio); + } + /* Handle all possible collisions. */ collision_handler(); @@ -460,6 +487,8 @@ int game_action(void) void game_draw(void) { +int y,x; + /* Draw screen: */ if (tux.dying && (global_frame_counter % 4) == 0) clearscreen(255, 255, 255); @@ -480,11 +509,36 @@ void game_draw(void) } } - // Draw background: - for (int y = 0; y < 15; ++y) - for (int x = 0; x < 21; ++x) - drawshape(32*x - fmodf(scroll_x, 32), y * 32, - current_level.tiles[y][x + (int)(scroll_x / 32)]); + /* Draw particle systems (background) */ + std::vector::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.bg_tiles[(int)y][(int)x + (int)(scroll_x / 32)]); + } + } + + /* Draw interactive tiles: */ + + for (y = 0; y < 15; ++y) + { + 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)]); + } + } + + /* (Bouncy bricks): */ for (unsigned int i = 0; i < bouncy_bricks.size(); ++i) bouncy_brick_draw(&bouncy_bricks[i]); @@ -509,6 +563,23 @@ void game_draw(void) for (unsigned int i = 0; i < broken_bricks.size(); ++i) broken_brick_draw(&broken_bricks[i]); + /* Draw foreground: */ + + for (y = 0; y < 15; ++y) + { + 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)]); + } + } + + /* Draw particle systems (foreground) */ + for(p = particle_systems.begin(); p != particle_systems.end(); ++p) + { + (*p)->draw(scroll_x, 0, 1); + } + drawstatus(); if(game_pause) @@ -526,10 +597,7 @@ void game_draw(void) menu_process_current(); /* (Update it all!) */ - updatescreen(); - - } /* --- GAME LOOP! --- */ @@ -565,6 +633,7 @@ int gameloop(const char * subset, int levelnb, int mode) level_load_gfx(¤t_level); activate_bad_guys(); + activate_particle_systems(); level_load_song(¤t_level); tux.init(); @@ -583,7 +652,6 @@ int gameloop(const char * subset, int levelnb, int mode) if(st_gl_mode == ST_GL_LOAD_GAME) loadgame(levelnb); - /* --- MAIN GAME LOOP!!! --- */ jump = false; @@ -605,7 +673,7 @@ int gameloop(const char * subset, int levelnb, int mode) while (SDL_PollEvent(&event)) - {} + {} game_draw(); do @@ -616,7 +684,7 @@ int gameloop(const char * subset, int levelnb, int mode) 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); @@ -679,8 +747,8 @@ int gameloop(const char * subset, int levelnb, int mode) /* == -1: continues */ return 0; } - /* --z; - }*/ + /* --z; + }*/ } else { @@ -711,7 +779,6 @@ int gameloop(const char * subset, int levelnb, int mode) 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+. */ @@ -1249,10 +1316,25 @@ void unloadshared(void) /* 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; + 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 + { + texture_draw(&ptile->images[0],x,y); + } + } + + /* if (c == 'X' || c == 'x') texture_draw(&img_brick[0], x, y); else if (c == 'Y' || c == 'y') @@ -1308,24 +1390,25 @@ void drawshape(float x, float y, unsigned char c) 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 = '.'; @@ -1338,25 +1421,38 @@ unsigned char shape(float x, float 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; + } } @@ -1364,16 +1460,38 @@ bool isbrick(float x, float y) 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; + } } /* Break a brick: */ @@ -1396,7 +1514,7 @@ void trybreakbrick(float x, float y) } if (distro_counter <= 0) - level_change(¤t_level,x, y, 'a'); + level_change(¤t_level,x, y, TM_IA, 'a'); play_sound(sounds[SND_DISTRO], SOUND_CENTER_SPEAKER); score = score + SCORE_DISTRO; @@ -1406,7 +1524,7 @@ void trybreakbrick(float x, float y) { /* Get rid of it: */ - level_change(¤t_level,x, y,'.'); + level_change(¤t_level,x, y, TM_IA, '.'); } @@ -1473,7 +1591,7 @@ void tryemptybox(float x, float y, int col_side) } /* Empty the box: */ - level_change(¤t_level,x, y, 'a'); + level_change(¤t_level,x, y, TM_IA, 'a'); } @@ -1483,7 +1601,7 @@ void trygrabdistro(float x, float y, int bounciness) { if (shape(x, y) == '$') { - level_change(¤t_level,x, y, '.'); + level_change(¤t_level,x, y, TM_IA, '.'); play_sound(sounds[SND_DISTRO], SOUND_CENTER_SPEAKER); if (bounciness == BOUNCE) @@ -1683,6 +1801,7 @@ void loadgame(int slot) arrays_free(); arrays_init(); activate_bad_guys(); + activate_particle_systems(); level_free_gfx(); level_load_gfx(¤t_level); level_free_song(); diff --git a/src/gameloop.h b/src/gameloop.h index b8e0eb294..a92f85f15 100644 --- a/src/gameloop.h +++ b/src/gameloop.h @@ -38,8 +38,8 @@ bool isbrick(float x, float y); bool isice(float x, float y); bool isfullbox(float x, float y); bool rectcollision(base_type* one, base_type* two); -void drawshape(float x, float y, unsigned char c); -unsigned char shape(float x, float y); +void drawshape(float x, float y, unsigned int c); +unsigned int shape(float x, float y); void bumpbrick(float x, float y); void trygrabdistro(float x, float y, int bounciness); void trybreakbrick(float x, float y); diff --git a/src/level.cpp b/src/level.cpp index db25e4c77..9eb156c6a 100644 --- a/src/level.cpp +++ b/src/level.cpp @@ -206,11 +206,29 @@ void level_default(st_level* plevel) for(i = 0; i < 15; ++i) { - plevel->tiles[i] = (unsigned int*) malloc((plevel->width+1)*sizeof(unsigned int)); - plevel->tiles[i][plevel->width] = (unsigned int) '\0'; + plevel->ia_tiles[i] = (unsigned int*) malloc((plevel->width+1)*sizeof(unsigned int)); + plevel->ia_tiles[i][plevel->width] = (unsigned int) '\0'; for(y = 0; y < plevel->width; ++y) - plevel->tiles[i][y] = (unsigned int) '.'; - plevel->tiles[i][plevel->width] = (unsigned int) '\0'; + plevel->ia_tiles[i][y] = (unsigned int) '.'; + plevel->ia_tiles[i][plevel->width] = (unsigned int) '\0'; + + plevel->bg_tiles[i] = (unsigned int*) malloc((plevel->width+1)*sizeof(unsigned int)); + plevel->bg_tiles[i][plevel->width] = (unsigned int) '\0'; + for(y = 0; y < plevel->width; ++y) + plevel->bg_tiles[i][y] = (unsigned int) '.'; + plevel->bg_tiles[i][plevel->width] = (unsigned int) '\0'; + + plevel->fg_tiles[i] = (unsigned int*) malloc((plevel->width+1)*sizeof(unsigned int)); + plevel->fg_tiles[i][plevel->width] = (unsigned int) '\0'; + for(y = 0; y < plevel->width; ++y) + plevel->fg_tiles[i][y] = (unsigned int) '.'; + plevel->fg_tiles[i][plevel->width] = (unsigned int) '\0'; + + plevel->dn_tiles[i] = (unsigned int*) malloc((plevel->width+1)*sizeof(unsigned int)); + plevel->dn_tiles[i][plevel->width] = (unsigned int) '\0'; + for(y = 0; y < plevel->width; ++y) + plevel->dn_tiles[i][y] = (unsigned int) '.'; + plevel->dn_tiles[i][plevel->width] = (unsigned int) '\0'; } } @@ -231,7 +249,7 @@ int level_load(st_level* plevel, const char *subset, int level) int level_load(st_level* plevel, const char* filename) { - int x, y; + int x, y, j; FILE * fi; lisp_object_t* root_obj = 0; fi = fopen(filename, "r"); @@ -250,12 +268,15 @@ int level_load(st_level* plevel, const char* filename) printf("World: Parse Error in file %s", filename); } - vector vi; + vector ia_tm; + vector dn_tm; + vector bg_tm; + vector fg_tm; if (strcmp(lisp_symbol(lisp_car(root_obj)), "supertux-level") == 0) { LispReader reader(lisp_cdr(root_obj)); - + reader.read_int("width", &plevel->width); reader.read_int("time", &plevel->time_left); reader.read_int("bkgd_red", &plevel->bkgd_red); @@ -266,20 +287,64 @@ int level_load(st_level* plevel, const char* filename) reader.read_string("theme", &plevel->theme); reader.read_string("music", &plevel->song_title); reader.read_string("background", &plevel->bkgd_image); - reader.read_int_vector("tilemap", &vi); + reader.read_string("particle_system", &plevel->particle_system); + reader.read_int_vector("background-tm", &bg_tm); + reader.read_int_vector("interactive-tm", &ia_tm); + reader.read_int_vector("dynamic-tm", &dn_tm); + reader.read_int_vector("foreground-tm", &fg_tm); } - - + + int i; for( i = 0; i < 15; ++i) - plevel->tiles[i] = (unsigned int*) calloc((plevel->width +1) , sizeof(unsigned int) ); + { + plevel->dn_tiles[i] = (unsigned int*) calloc((plevel->width +1) , sizeof(unsigned int) ); + plevel->ia_tiles[i] = (unsigned int*) calloc((plevel->width +1) , sizeof(unsigned int) ); + plevel->bg_tiles[i] = (unsigned int*) calloc((plevel->width +1) , sizeof(unsigned int) ); + plevel->fg_tiles[i] = (unsigned int*) calloc((plevel->width +1) , sizeof(unsigned int) ); + } + + i = j = 0; + for(vector::iterator it = ia_tm.begin(); it != ia_tm.end(); ++it, ++i) + { + + plevel->ia_tiles[j][i] = (*it); + if(i == plevel->width - 1) + { + i = -1; + ++j; + } + } + + i = j = 0; + for(vector::iterator it = dn_tm.begin(); it != dn_tm.end(); ++it, ++i) + { + + plevel->dn_tiles[j][i] = (*it); + if(i == plevel->width - 1) + { + i = -1; + ++j; + } + } + + i = j = 0; + for(vector::iterator it = bg_tm.begin(); it != bg_tm.end(); ++it, ++i) + { + + plevel->bg_tiles[j][i] = (*it); + if(i == plevel->width - 1) + { + i = -1; + ++j; + } + } - i = 0; - int j = 0; - for(vector::iterator it = vi.begin(); it != vi.end(); ++it, ++i) + i = j = 0; + for(vector::iterator it = fg_tm.begin(); it != fg_tm.end(); ++it, ++i) { - plevel->tiles[j][i] = (*it); + plevel->fg_tiles[j][i] = (*it); if(i == plevel->width - 1) { i = -1; @@ -290,7 +355,7 @@ int level_load(st_level* plevel, const char* filename) /* Set the global gravity to the latest loaded level's gravity */ gravity = plevel->gravity; - /* Mark the end position of this level! - Is a bit wrong here thought */ + /* Mark the end position of this level! - Is a bit wrong here thought * / for (y = 0; y < 15; ++y) { @@ -302,7 +367,7 @@ int level_load(st_level* plevel, const char* filename) endpos = x*32; } } - } + }*/ fclose(fi); return 0; @@ -333,30 +398,58 @@ void level_save(st_level* plevel,const char * subset, int level) } - /* Write header: */ - fprintf(fi,";SuperTux-Level\n"); - fprintf(fi,"(supertux-level\n"); - - fprintf(fi," (name \"%s\")\n", plevel->name.c_str()); - fprintf(fi," (theme \"%s\")\n", plevel->theme.c_str()); - fprintf(fi," (music \"%s\")\n", plevel->song_title.c_str()); - fprintf(fi," (background \"%s\")\n", plevel->bkgd_image.c_str()); - fprintf(fi," (bkgd_red %d)\n", plevel->bkgd_red); - fprintf(fi," (bkgd_green %d)\n", plevel->bkgd_green); - fprintf(fi," (bkgd_blue %d)\n", plevel->bkgd_blue); - fprintf(fi," (time %d)\n", plevel->time_left); - fprintf(fi," (width %d)\n", plevel->width); - fprintf(fi," (gravity %2.1f)\n", plevel->gravity); - fprintf(fi," (tilemap "); - + /* Write header: */ + fprintf(fi,";SuperTux-Level\n"); + fprintf(fi,"(supertux-level\n"); + + fprintf(fi," (name \"%s\")\n", plevel->name.c_str()); + fprintf(fi," (theme \"%s\")\n", plevel->theme.c_str()); + fprintf(fi," (music \"%s\")\n", plevel->song_title.c_str()); + fprintf(fi," (background \"%s\")\n", plevel->bkgd_image.c_str()); + fprintf(fi," (particle_system \"%s\")\n", plevel->particle_system.c_str()); + fprintf(fi," (bkgd_red %d)\n", plevel->bkgd_red); + fprintf(fi," (bkgd_green %d)\n", plevel->bkgd_green); + fprintf(fi," (bkgd_blue %d)\n", plevel->bkgd_blue); + fprintf(fi," (time %d)\n", plevel->time_left); + fprintf(fi," (width %d)\n", plevel->width); + fprintf(fi," (gravity %2.1f)\n", plevel->gravity); + fprintf(fi," (background-tm "); + + for(y = 0; y < 15; ++y) + { + for(i = 0; i < plevel->width; ++i) + fprintf(fi," %d ", plevel->bg_tiles[y][i]); + } + + fprintf( fi,")\n"); + fprintf(fi," (interactive-tm "); + for(y = 0; y < 15; ++y) { - for(i = 0; i < plevel->width; ++i) - fprintf(fi," %d ", plevel->tiles[y][i]); + for(i = 0; i < plevel->width; ++i) + fprintf(fi," %d ", plevel->ia_tiles[y][i]); } - - fprintf( fi,")"); - fprintf( fi,")\n"); + + fprintf( fi,")\n"); + fprintf(fi," (dynamic-tm "); + + for(y = 0; y < 15; ++y) + { + for(i = 0; i < plevel->width; ++i) + fprintf(fi," %d ", plevel->dn_tiles[y][i]); + } + + fprintf( fi,")\n"); + fprintf(fi," (foreground-tm "); + + for(y = 0; y < 15; ++y) + { + for(i = 0; i < plevel->width; ++i) + fprintf(fi," %d ", plevel->fg_tiles[y][i]); + } + + fprintf( fi,")"); + fprintf( fi,")\n"); fclose(fi); } @@ -368,7 +461,13 @@ void level_free(st_level* plevel) { int i; for(i=0; i < 15; ++i) - free(plevel->tiles[i]); + free(plevel->bg_tiles[i]); + for(i=0; i < 15; ++i) + free(plevel->ia_tiles[i]); + for(i=0; i < 15; ++i) + free(plevel->dn_tiles[i]); + for(i=0; i < 15; ++i) + free(plevel->fg_tiles[i]); plevel->name.clear(); plevel->theme.clear(); @@ -446,9 +545,37 @@ void level_load_image(texture_type* ptexture, string theme,const char * file, i texture_load(ptexture, fname, use_alpha); } +void tilemap_change_size(unsigned int** tilemap[15], int w, int old_w) +{ + int j,y; + for(y = 0; y < 15; ++y) + { + *tilemap[y] = (unsigned int*) realloc(*tilemap[y],(w+1)*sizeof(unsigned int)); + if(w > old_w) + for(j = 0; j < w - old_w; ++j) + *tilemap[y][old_w+j] = 0; + *tilemap[y][w] = 0; + } +} + +/* Change the size of a level (width) */ +void level_change_size (st_level* plevel, int new_width) +{ + int y; + + if(new_width < 21) + new_width = 21; + tilemap_change_size((unsigned int***)&plevel->ia_tiles,new_width,plevel->width); + tilemap_change_size((unsigned int***)&plevel->dn_tiles,new_width,plevel->width); + tilemap_change_size((unsigned int***)&plevel->bg_tiles,new_width,plevel->width); + tilemap_change_size((unsigned int***)&plevel->fg_tiles,new_width,plevel->width); + plevel->width = new_width; + +} + /* Edit a piece of the map! */ -void level_change(st_level* plevel, float x, float y, unsigned char c) +void level_change(st_level* plevel, float x, float y, int tm, unsigned int c) { int xx, yy; @@ -456,7 +583,19 @@ void level_change(st_level* plevel, float x, float y, unsigned char c) xx = ((int)x / 32); if (yy >= 0 && yy < 15 && xx >= 0 && xx <= plevel->width) - plevel->tiles[yy][xx] = c; + { + switch(tm) + { + case 0: + plevel->bg_tiles[yy][xx] = c; + case 1: + plevel->ia_tiles[yy][xx] = c; + case 2: + plevel->dn_tiles[yy][xx] = c; + case 4: + plevel->fg_tiles[yy][xx] = c; + } + } } /* Free music data for this level: */ diff --git a/src/level.h b/src/level.h index f9cdbff7e..ed93b8b1f 100644 --- a/src/level.h +++ b/src/level.h @@ -46,7 +46,11 @@ struct st_level std::string theme; std::string song_title; std::string bkgd_image; - unsigned int* tiles[15]; + std::string particle_system; + unsigned int* bg_tiles[15]; /* Tiles in the background */ + unsigned int* ia_tiles[15]; /* Tiles which can interact in the game (solids for example)*/ + unsigned int* dn_tiles[15]; /* Dynamic tiles (bad guys and moving platforms for example)*/ + unsigned int* fg_tiles[15]; /* Tiles in the foreground */ int time_left; int bkgd_red; int bkgd_green; @@ -55,6 +59,13 @@ struct st_level float gravity; }; +enum { + TM_BG, + TM_IA, + TM_DN, + TM_FG + }; + extern texture_type img_bkgd, img_bkgd_tile[2][4], img_solid[4], img_brick[2]; void level_default (st_level* plevel); @@ -64,7 +75,8 @@ int level_load (st_level* plevel, const char* filename); void level_save (st_level* plevel, const char * subset, int level); void level_free (st_level* plevel); void level_load_gfx (st_level* plevel); -void level_change (st_level* plevel, float x, float y, unsigned char c); +void level_change (st_level* plevel, float x, float y, int tm, unsigned int c); +void level_change_size (st_level* plevel, int new_width); void level_load_song(st_level* plevel); void level_free_gfx(); void level_load_image(texture_type* ptexture, std::string theme, const char * file, int use_alpha); diff --git a/src/leveleditor.cpp b/src/leveleditor.cpp index 7863015bd..6fc2b3b55 100644 --- a/src/leveleditor.cpp +++ b/src/leveleditor.cpp @@ -66,7 +66,7 @@ void le_quit(); void le_drawlevel(); void le_drawinterface(); void le_checkevents(); -void le_change(float x, float y, unsigned char c); +void le_change(float x, float y, int tm, unsigned int c); void le_testlevel(); void le_showhelp(); void le_set_defaults(void); @@ -129,8 +129,11 @@ void le_activate_bad_guys(void) for (y = 0; y < 15; ++y) for (x = 0; x < le_current_level->width; ++x) - if (le_current_level->tiles[y][x] >= '0' && le_current_level->tiles[y][x] <= '9') - add_bad_guy(x * 32, y * 32, static_cast(le_current_level->tiles[y][x] - '0')); + if (le_current_level->dn_tiles[y][x] >= '0' && le_current_level->dn_tiles[y][x] <= '9') + add_bad_guy(x * 32, y * 32, static_cast(le_current_level->dn_tiles[y][x] - '0')); + + + } void le_set_defaults() @@ -620,28 +623,7 @@ void apply_level_settings_menu() le_current_level->song_title = string_list_active(level_settings_menu->item[4].list); - i = le_current_level->width; - le_current_level->width = atoi(level_settings_menu->item[6].input); - if(le_current_level->width < i) - { - if(le_current_level->width < 21) - le_current_level->width = 21; - for(y = 0; y < 15; ++y) - { - le_current_level->tiles[y] = (unsigned int*) realloc(le_current_level->tiles[y],(le_current_level->width+1)*sizeof(unsigned int)); - le_current_level->tiles[y][le_current_level->width] = (unsigned int) '\0'; - } - } - else if(le_current_level->width > i) - { - for(y = 0; y < 15; ++y) - { - le_current_level->tiles[y] = (unsigned int*) realloc(le_current_level->tiles[y],(le_current_level->width+1)*sizeof(unsigned int)); - for(j = 0; j < le_current_level->width - i; ++j) - le_current_level->tiles[y][i+j] = (unsigned int) '.'; - le_current_level->tiles[y][le_current_level->width] = (unsigned int) '\0'; - } - } + level_change_size(le_current_level, atoi(level_settings_menu->item[6].input)); le_current_level->time_left = atoi(level_settings_menu->item[7].input); le_current_level->gravity = atof(level_settings_menu->item[8].input); le_current_level->bkgd_red = atoi(level_settings_menu->item[9].input); @@ -838,12 +820,11 @@ void le_drawlevel() for (y = 0; y < 15; ++y) for (x = 0; x < 20; ++x) { - drawshape(x * 32 - ((int)pos_x % 32), y * 32, - le_current_level->tiles[y][x + (int)(pos_x / 32)]); + drawshape(x * 32 - ((int)pos_x % 32), y * 32, le_current_level->ia_tiles[y][x + (int)(pos_x / 32)]); /* draw whats inside stuff when cursor is selecting those */ /* (draw them all the time - is this the right behaviour?) */ - switch(le_current_level->tiles[y][x + (int)(pos_x/32)]) + switch(le_current_level->ia_tiles[y][x + (int)(pos_x/32)]) { case 'B': texture_draw(&img_mints, x * 32 - ((int)pos_x % 32), y*32); @@ -1250,7 +1231,7 @@ void le_checkevents() if(le_mouse_pressed[LEFT]) { - le_change(cursor_x, cursor_y, le_current_tile); + le_change(cursor_x, cursor_y, TM_IA, le_current_tile); } } } @@ -1311,7 +1292,7 @@ void le_highlight_selection() fillrect(x1*32-pos_x, y1*32,32* (x2 - x1 + 1),32 * (y2 - y1 + 1),173,234,177,103); } -void le_change(float x, float y, unsigned char c) +void le_change(float x, float y, int tm, unsigned int c) { if(le_current_level != NULL) { @@ -1324,7 +1305,7 @@ void le_change(float x, float y, unsigned char c) switch(le_selection_mode) { case CURSOR: - level_change(le_current_level,x,y,c); + level_change(le_current_level,x,y,tm,c); yy = ((int)y / 32); xx = ((int)x / 32); @@ -1378,7 +1359,7 @@ void le_change(float x, float y, unsigned char c) for(xx = x1; xx <= x2; xx++) for(yy = y1; yy <= y2; yy++) { - level_change(le_current_level, xx*32, yy*32, c); + level_change(le_current_level, xx*32, yy*32, tm, c); if(c == '0') // if it's a bad guy add_bad_guy(xx*32, yy*32, BAD_BSOD); diff --git a/src/particlesystem.cpp b/src/particlesystem.cpp new file mode 100644 index 000000000..db1ca26c3 --- /dev/null +++ b/src/particlesystem.cpp @@ -0,0 +1,141 @@ +// $Id$ +// +// SuperTux +// Copyright (C) 2004 Matthias Braun +// +// 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 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +#include "particlesystem.h" + +#include +#include +#include "globals.h" +#include "scene.h" + +ParticleSystem::ParticleSystem() +{ + virtual_width = screen->w; + virtual_height = screen->h; +} + +ParticleSystem::~ParticleSystem() +{ + std::vector::iterator i; + for(i = particles.begin(); i != particles.end(); ++i) { + delete *i; + } +} + +void ParticleSystem::draw(float scrollx, float scrolly, int layer) +{ + std::vector::iterator i; + for(i = particles.begin(); i != particles.end(); ++i) { + Particle* particle = *i; + if(particle->layer != layer) + continue; + + // remap x,y coordinates onto screencoordinates + float x = fmodf(particle->x - scrollx, virtual_width); + if(x < 0) x += virtual_width; + float y = fmodf(particle->y - scrolly, virtual_height); + if(y < 0) y += virtual_height; + float xmax = fmodf(x + particle->texture->w, virtual_width); + float ymax = fmodf(y + particle->texture->h, virtual_height); + + // particle on screen + if(x >= screen->w && xmax >= screen->w) + continue; + if(y >= screen->h && ymax >= screen->h) + continue; + + if(x > screen->w) x -= virtual_width; + if(y > screen->h) y -= virtual_height; + texture_draw(particle->texture, x, y); + } +} + +SnowParticleSystem::SnowParticleSystem() +{ + texture_load(&snowimages[0], datadir+"/images/shared/snow0.png", USE_ALPHA); + texture_load(&snowimages[1], datadir+"/images/shared/snow1.png", USE_ALPHA); + texture_load(&snowimages[2], datadir+"/images/shared/snow2.png", USE_ALPHA); + + virtual_width = screen->w * 2; + + // create some random snowflakes + size_t snowflakecount = size_t(virtual_width/10.0); + for(size_t i=0; ix = rand() % int(virtual_width); + particle->y = rand() % screen->h; + particle->layer = i % 2; + int snowsize = rand() % 3; + particle->texture = &snowimages[snowsize]; + particle->speed = 0.01 + snowsize/50.0 + (rand()%(int)gravity/15.0); + + particles.push_back(particle); + } +} + +SnowParticleSystem::~SnowParticleSystem() +{ + for(int i=0;i<3;++i) + texture_free(&snowimages[i]); +} + +void SnowParticleSystem::simulate(float elapsed_time) +{ + std::vector::iterator i; + for(i = particles.begin(); i != particles.end(); ++i) { + SnowParticle* particle = (SnowParticle*) *i; + particle->y += particle->speed * elapsed_time; + if(particle->y > screen->h) { + particle->y = 0; + particle->x = rand() % int(virtual_width); + } + } +} + +CloudParticleSystem::CloudParticleSystem() +{ + texture_load(&cloudimage, datadir + "/images/shared/cloud.png", USE_ALPHA); + + virtual_width = 5000.0; + + // create some random clouds + for(size_t i=0; i<15; ++i) { + CloudParticle* particle = new CloudParticle; + particle->x = rand() % int(virtual_width); + particle->y = rand() % int((float) screen->h * 0.3333); + particle->layer = 0; + particle->texture = &cloudimage; + particle->speed = -float(250 + rand() % 200) / 1000.0; + + particles.push_back(particle); + } +} + +CloudParticleSystem::~CloudParticleSystem() +{ + texture_free(&cloudimage); +} + +void CloudParticleSystem::simulate(float elapsed_time) +{ + std::vector::iterator i; + for(i = particles.begin(); i != particles.end(); ++i) { + CloudParticle* particle = (CloudParticle*) *i; + particle->x += particle->speed * elapsed_time; + } +} diff --git a/src/particlesystem.h b/src/particlesystem.h new file mode 100644 index 000000000..8efdf9540 --- /dev/null +++ b/src/particlesystem.h @@ -0,0 +1,103 @@ +// $Id$ +// +// SuperTux +// Copyright (C) 2004 Matthias Braun +// +// 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 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +#ifndef SUPERTUX_PARTICLESYSTEM_H +#define SUPERTUX_PARTICLESYSTEM_H + +#include +#include "texture.h" + +/** + * This is the base class for particle systems. It is responsible for storing a + * set of particles with each having an x- and y-coordinate the number of the + * layer where it should be drawn and a texture. + * The coordinate system used here is a virtual one. It would be a bad idea to + * populate whole levels with particles. So we're using a virtual rectangle + * here that is tiled onto the level when drawing. This rectangle has the size + * (virtual_width, virtual_height). We're using modulo on the particle + * coordinates, so when a particle leaves left, it'll reenter at the right + * side. + * + * Classes that implement a particle system should subclass from this class, + * initialize particles in the constructor and move them in the simulate + * function. + */ +class ParticleSystem +{ +public: + ParticleSystem(); + virtual ~ParticleSystem(); + + void draw(float scrollx, float scrolly, int layer); + + virtual void simulate(float elapsed_time) = 0; + +protected: + class Particle + { + public: + virtual ~Particle() + { } + + float x, y; + int layer; + texture_type* texture; + }; + + std::vector particles; + float virtual_width, virtual_height; +}; + +class SnowParticleSystem : public ParticleSystem +{ +public: + SnowParticleSystem(); + virtual ~SnowParticleSystem(); + + virtual void simulate(float elapsed_time); + +private: + class SnowParticle : public Particle + { + public: + float speed; + }; + + texture_type snowimages[3]; +}; + +class CloudParticleSystem : public ParticleSystem +{ +public: + CloudParticleSystem(); + virtual ~CloudParticleSystem(); + + virtual void simulate(float elapsed_time); + +private: + class CloudParticle : public Particle + { + public: + float speed; + }; + + texture_type cloudimage; +}; + +#endif + diff --git a/src/player.cpp b/src/player.cpp index b75a93484..1c1c137f4 100644 --- a/src/player.cpp +++ b/src/player.cpp @@ -255,8 +255,8 @@ Player::action() } if (distro_counter <= 0) - level_change(¤t_level,base.x,base.y - 1, 'a'); - + level_change(¤t_level,base.x,base.y - 1, TM_IA, 'a'); + play_sound(sounds[SND_DISTRO], SOUND_CENTER_SPEAKER); score = score + SCORE_DISTRO; distros++; @@ -274,7 +274,7 @@ Player::action() } if (distro_counter <= 0) - level_change(¤t_level,base.x+ 31, base.y, 'a'); + level_change(¤t_level,base.x+ 31, base.y, TM_IA, 'a'); play_sound(sounds[SND_DISTRO], SOUND_CENTER_SPEAKER); score = score + SCORE_DISTRO; diff --git a/src/scene.h b/src/scene.h index 7947d4dfd..4be33a160 100644 --- a/src/scene.h +++ b/src/scene.h @@ -20,6 +20,7 @@ #include "world.h" #include "special.h" #include "level.h" +#include "particlesystem.h" #define FRAME_RATE 10 // 100 Frames per second (10ms) @@ -36,7 +37,7 @@ extern int distro_counter; extern timer_type super_bkgd_timer; extern float scroll_x; -extern int global_frame_counter; +extern unsigned int global_frame_counter; extern std::vector bouncy_distros; extern std::vector broken_bricks; extern std::vector bouncy_bricks; @@ -44,6 +45,7 @@ extern std::vector bad_guys; extern std::vector floating_scores; extern std::vector upgrades; extern std::vector bullets; +extern std::vector particle_systems; extern Player tux; extern texture_type img_box_full, img_box_empty, img_mints, img_coffee, img_super_bkgd, img_red_glow; extern timer_type time_left; diff --git a/src/setup.cpp b/src/setup.cpp index 49d530d45..60b7760e5 100644 --- a/src/setup.cpp +++ b/src/setup.cpp @@ -80,7 +80,7 @@ int fwriteable(const char *filename) return true; } -/* Makes sure a directory is created in either the SuperTux base directory or the SuperTux base directory.*/ +/* Makes sure a directory is created in either the SuperTux home directory or the SuperTux base directory.*/ int fcreatedir(const char* relative_dir) { char path[1024]; diff --git a/src/texture.cpp b/src/texture.cpp index f2e925385..febda9761 100644 --- a/src/texture.cpp +++ b/src/texture.cpp @@ -344,7 +344,6 @@ void texture_from_sdl_surface(texture_type* ptexture, SDL_Surface* sdl_surf, int void texture_draw_sdl(texture_type* ptexture, float x, float y, bool update) { - SDL_Rect dest; dest.x = (int)x; diff --git a/src/tile.cpp b/src/tile.cpp new file mode 100644 index 000000000..4430e3459 --- /dev/null +++ b/src/tile.cpp @@ -0,0 +1,102 @@ +// +// C++ Implementation: tile +// +// Description: +// +// +// Author: Tobias Glaesser , (C) 2004 +// +// Copyright: See COPYING file that comes with this distribution +// +// +#include "tile.h" +#include "assert.h" + +TileManager* TileManager::instance_ = 0; + +TileManager::TileManager() +{ + std::string filename = datadir + "images/tilesets/main.stgt"; + load_tileset(filename); +} + +void TileManager::load_tileset(std::string filename) +{ + lisp_object_t* root_obj = lisp_read_from_file(filename); + + if (!root_obj) + st_abort("Couldn't load file", filename); + + if (strcmp(lisp_symbol(lisp_car(root_obj)), "supertux-tiles") == 0) + { + lisp_object_t* cur = lisp_cdr(root_obj); + int tileset_id = 0; + + while(!lisp_nil_p(cur)) + { + lisp_object_t* element = lisp_car(cur); + + if (strcmp(lisp_symbol(lisp_car(element)), "tile") == 0) + { + int id = 0; + std::vector filenames; + + Tile* tile = new Tile; + tile->solid = false; + tile->brick = false; + tile->ice = false; + tile->fullbox = false; + tile->alpha = 0; + tile->anim_speed = 25; + + LispReader reader(lisp_cdr(element)); + reader.read_int("id", &id); + reader.read_bool("solid", &tile->solid); + reader.read_bool("brick", &tile->brick); + reader.read_bool("ice", &tile->ice); + reader.read_bool("fullbox", &tile->fullbox); + reader.read_int("alpha", (int*)&tile->alpha); + reader.read_int("anim-speed", &tile->anim_speed); + reader.read_string_vector("images", &filenames); + + for(std::vector::iterator it = filenames.begin(); it != filenames.end(); ++it) + { + texture_type cur_image; + tile->images.push_back(cur_image); + texture_load(&tile->images[tile->images.size()-1], + datadir + "images/tilesets/" + (*it), + USE_ALPHA); + } + + if (id+tileset_id >= int(tiles.size())) + tiles.resize(id+tileset_id+1); + + tiles[id+tileset_id] = tile; + } + else if (strcmp(lisp_symbol(lisp_car(element)), "tileset") == 0) + { + LispReader reader(lisp_cdr(element)); + std::string filename; + reader.read_string("file", &filename); + filename = datadir + "images/tilesets/" + filename; + load_tileset(filename); + } + else if (strcmp(lisp_symbol(lisp_car(element)), "properties") == 0) + { + LispReader reader(lisp_cdr(element)); + reader.read_int("id", &tileset_id); + tileset_id *= 1000; + } + else + { + puts("Unhandled symbol"); + } + + cur = lisp_cdr(cur); + } + } + else + { + assert(0); + } +} diff --git a/src/tile.h b/src/tile.h new file mode 100644 index 000000000..31212c928 --- /dev/null +++ b/src/tile.h @@ -0,0 +1,49 @@ +// +// C++ Interface: tile +// +// Description: +// +// +// Author: Tobias Glaesser , (C) 2004 +// +// Copyright: See COPYING file that comes with this distribution +// +// +#ifndef TILE_H +#define TILE_H + +#include +#include "texture.h" +#include "globals.h" +#include "lispreader.h" +#include "setup.h" + +/** +Tile Class +*/ +struct Tile +{ +std::vector images; +bool solid; +bool brick; +bool ice; +bool fullbox; +int anim_speed; +unsigned char alpha; +}; + +class TileManager +{ +private: + TileManager(); + std::vector tiles; + static TileManager* instance_ ; + void load_tileset(std::string filename); + +public: + static TileManager* instance() { return instance_ ? instance_ : instance_ = new TileManager(); } + Tile* get(unsigned int id) { if( id < tiles.size()) { return tiles[id]; } else { return NULL; } } ; + +}; + +#endif -- 2.11.0