From: Matthias Braun Date: Thu, 20 May 2004 19:56:37 +0000 (+0000) Subject: -changed Level class to save tiles in a big 1 dimensional array instead of X-Git-Url: https://git.verplant.org/?a=commitdiff_plain;h=1b3974597dfcd1c36eba0f1ac2f7528f038e02d2;p=supertux.git -changed Level class to save tiles in a big 1 dimensional array instead of vector. You can access a tile like this now tiles[y * width + x] is the tile at place x,y -introduced new Serializable interface that is implemented by all objects that are able to save themselfes to disk -added new lispwriter class -changed level laoding/save code to use new serializable/lispwriter stuff SVN-Revision: 1282 --- diff --git a/src/Makefile.am b/src/Makefile.am index 1b6289350..485ade3b9 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,6 +1,8 @@ bin_PROGRAMS = supertux supertux_SOURCES = \ +lispwriter.h \ +lispwriter.cpp \ badguy.cpp \ badguy.h \ bitmask.cpp \ @@ -87,6 +89,6 @@ background.cpp \ tilemap.h \ tilemap.cpp \ moving_object.h \ -moving_object.cpp +moving_object.cpp # EOF # diff --git a/src/badguy.cpp b/src/badguy.cpp index 980462776..57f147aee 100644 --- a/src/badguy.cpp +++ b/src/badguy.cpp @@ -33,6 +33,8 @@ #include "resources.h" #include "sprite_manager.h" #include "gameloop.h" +#include "display_manager.h" +#include "lispwriter.h" Sprite* img_mriceblock_flat_left; Sprite* img_mriceblock_flat_right; @@ -142,20 +144,56 @@ std::string badguykind_to_string(BadGuyKind kind) } } -BadGuy::BadGuy(float x, float y, BadGuyKind kind_, bool stay_on_platform_) +BadGuy::BadGuy(DisplayManager& display_manager, BadGuyKind kind_, + LispReader& lispreader) : removable(false), squishcount(0) { - base.x = x; - base.y = y; + display_manager.add_drawable(this, LAYER_OBJECTS); + + base.x = 0; + base.y = 0; + lispreader.read_float("x", &base.x); + lispreader.read_float("y", &base.y); + base.width = 0; + base.height = 0; + base.xm = 0; + base.ym = 0; + + kind = kind_; + + stay_on_platform = false; + lispreader.read_bool("stay-on-platform", &stay_on_platform); + + init(); +} + +BadGuy::BadGuy(DisplayManager& display_manager, BadGuyKind kind_, + float x, float y) +{ + display_manager.add_drawable(this, LAYER_OBJECTS); + + base.x = x; + base.y = y; base.width = 0; base.height = 0; base.xm = 0; base.ym = 0; + stay_on_platform = false; + + kind = kind_; + + init(); +} + +BadGuy::~BadGuy() +{ +} - stay_on_platform = stay_on_platform_; +void +BadGuy::init() +{ mode = NORMAL; dying = DYING_NOT; - kind = kind_; old_base = base; dir = LEFT; seen = false; @@ -212,7 +250,19 @@ BadGuy::BadGuy(float x, float y, BadGuyKind kind_, bool stay_on_platform_) } void -BadGuy::action_mriceblock(double frame_ratio) +BadGuy::write(LispWriter& writer) +{ + writer.startList(badguykind_to_string(kind)); + + writer.writeFloat("x", base.x); + writer.writeFloat("y", base.y); + writer.writeBool("stay-on-platform", stay_on_platform); + + writer.endList(badguykind_to_string(kind)); +} + +void +BadGuy::action_mriceblock(double elapsed_time) { Player& tux = *World::current()->get_tux(); @@ -223,7 +273,7 @@ BadGuy::action_mriceblock(double frame_ratio) if (mode != HELD) { // move - physic.apply(frame_ratio, base.x, base.y); + physic.apply(elapsed_time, base.x, base.y); if (dying != DYING_FALLING) collision_swept_object_map(&old_base,&base); } @@ -383,13 +433,7 @@ BadGuy::fall() } void -BadGuy::remove_me() -{ - removable = true; -} - -void -BadGuy::action_jumpy(double frame_ratio) +BadGuy::action_jumpy(double elapsed_time) { if(frozen_timer.check()) { @@ -432,13 +476,13 @@ BadGuy::action_jumpy(double frame_ratio) dir = LEFT; // move - physic.apply(frame_ratio, base.x, base.y); + physic.apply(elapsed_time, base.x, base.y); if(dying == DYING_NOT) collision_swept_object_map(&old_base, &base); } void -BadGuy::action_mrbomb(double frame_ratio) +BadGuy::action_mrbomb(double elapsed_time) { if(frozen_timer.check()) { @@ -451,13 +495,13 @@ BadGuy::action_mrbomb(double frame_ratio) fall(); - physic.apply(frame_ratio, base.x, base.y); + physic.apply(elapsed_time, base.x, base.y); if (dying != DYING_FALLING) collision_swept_object_map(&old_base,&base); } void -BadGuy::action_bomb(double frame_ratio) +BadGuy::action_bomb(double elapsed_time) { static const int TICKINGTIME = 1000; static const int EXPLODETIME = 1000; @@ -489,12 +533,12 @@ BadGuy::action_bomb(double frame_ratio) } // move - physic.apply(frame_ratio, base.x, base.y); + physic.apply(elapsed_time, base.x, base.y); collision_swept_object_map(&old_base,&base); } void -BadGuy::action_stalactite(double frame_ratio) +BadGuy::action_stalactite(double elapsed_time) { Player& tux = *World::current()->get_tux(); @@ -529,25 +573,25 @@ BadGuy::action_stalactite(double frame_ratio) } // move - physic.apply(frame_ratio, base.x, base.y); + physic.apply(elapsed_time, base.x, base.y); if(dying == DYING_SQUISHED && !timer.check()) remove_me(); } void -BadGuy::action_flame(double frame_ratio) +BadGuy::action_flame(double elapsed_time) { static const float radius = 100; static const float speed = 0.02; base.x = old_base.x + cos(base.ym) * radius; base.y = old_base.y + sin(base.ym) * radius; - base.ym = fmodf(base.ym + frame_ratio * speed, 2*M_PI); + base.ym = fmodf(base.ym + elapsed_time * speed, 2*M_PI); } void -BadGuy::action_fish(double frame_ratio) +BadGuy::action_fish(double elapsed_time) { if(frozen_timer.check()) { @@ -581,7 +625,7 @@ BadGuy::action_fish(double frame_ratio) physic.enable_gravity(true); } - physic.apply(frame_ratio, base.x, base.y); + physic.apply(elapsed_time, base.x, base.y); if(dying == DYING_NOT) collision_swept_object_map(&old_base, &base); @@ -590,7 +634,7 @@ BadGuy::action_fish(double frame_ratio) } void -BadGuy::action_bouncingsnowball(double frame_ratio) +BadGuy::action_bouncingsnowball(double elapsed_time) { static const float JUMPV = 4.5; @@ -610,7 +654,7 @@ BadGuy::action_bouncingsnowball(double frame_ratio) // check for right/left collisions check_horizontal_bump(); - physic.apply(frame_ratio, base.x, base.y); + physic.apply(elapsed_time, base.x, base.y); if(dying == DYING_NOT) collision_swept_object_map(&old_base, &base); @@ -624,7 +668,7 @@ BadGuy::action_bouncingsnowball(double frame_ratio) } void -BadGuy::action_flyingsnowball(double frame_ratio) +BadGuy::action_flyingsnowball(double elapsed_time) { static const float FLYINGSPEED = 1; static const int DIRCHANGETIME = 1000; @@ -650,7 +694,7 @@ BadGuy::action_flyingsnowball(double frame_ratio) if(dying != DYING_NOT) physic.enable_gravity(true); - physic.apply(frame_ratio, base.x, base.y); + physic.apply(elapsed_time, base.x, base.y); if(dying == DYING_NOT || dying == DYING_SQUISHED) collision_swept_object_map(&old_base, &base); @@ -664,7 +708,7 @@ BadGuy::action_flyingsnowball(double frame_ratio) } void -BadGuy::action_spiky(double frame_ratio) +BadGuy::action_spiky(double elapsed_time) { if(frozen_timer.check()) { @@ -685,26 +729,26 @@ BadGuy::action_spiky(double frame_ratio) } #endif - physic.apply(frame_ratio, base.x, base.y); + physic.apply(elapsed_time, base.x, base.y); if (dying != DYING_FALLING) collision_swept_object_map(&old_base,&base); } void -BadGuy::action_snowball(double frame_ratio) +BadGuy::action_snowball(double elapsed_time) { if (dying == DYING_NOT) check_horizontal_bump(); fall(); - physic.apply(frame_ratio, base.x, base.y); + physic.apply(elapsed_time, base.x, base.y); if (dying != DYING_FALLING) collision_swept_object_map(&old_base,&base); } void -BadGuy::action(double frame_ratio) +BadGuy::action(float elapsed_time) { // Remove if it's far off the screen: if (base.x < scroll_x - OFFSCREEN_DISTANCE) @@ -740,47 +784,47 @@ BadGuy::action(double frame_ratio) switch (kind) { case BAD_MRICEBLOCK: - action_mriceblock(frame_ratio); + action_mriceblock(elapsed_time); break; case BAD_JUMPY: - action_jumpy(frame_ratio); + action_jumpy(elapsed_time); break; case BAD_MRBOMB: - action_mrbomb(frame_ratio); + action_mrbomb(elapsed_time); break; case BAD_BOMB: - action_bomb(frame_ratio); + action_bomb(elapsed_time); break; case BAD_STALACTITE: - action_stalactite(frame_ratio); + action_stalactite(elapsed_time); break; case BAD_FLAME: - action_flame(frame_ratio); + action_flame(elapsed_time); break; case BAD_FISH: - action_fish(frame_ratio); + action_fish(elapsed_time); break; case BAD_BOUNCINGSNOWBALL: - action_bouncingsnowball(frame_ratio); + action_bouncingsnowball(elapsed_time); break; case BAD_FLYINGSNOWBALL: - action_flyingsnowball(frame_ratio); + action_flyingsnowball(elapsed_time); break; case BAD_SPIKY: - action_spiky(frame_ratio); + action_spiky(elapsed_time); break; case BAD_SNOWBALL: - action_snowball(frame_ratio); + action_snowball(elapsed_time); break; default: break; @@ -788,8 +832,11 @@ BadGuy::action(double frame_ratio) } void -BadGuy::draw() +BadGuy::draw(ViewPort& viewport, int) { + float scroll_x = viewport.get_translation().x; + float scroll_y = viewport.get_translation().y; + // Don't try to draw stuff that is outside of the screen if(base.x <= scroll_x - base.width || base.x >= scroll_x + screen->w) return; @@ -881,14 +928,13 @@ BadGuy::squish(Player* player) if(kind == BAD_MRBOMB) { // mrbomb transforms into a bomb now - World::current()->add_bad_guy(base.x, base.y, BAD_BOMB); + explode(); make_player_jump(player); World::current()->add_score(Vector(base.x, base.y), 50 * player_status.score_multiplier); play_sound(sounds[SND_SQUISH], SOUND_CENTER_SPEAKER); player_status.score_multiplier++; - remove_me(); return; } else if (kind == BAD_MRICEBLOCK) { @@ -986,10 +1032,17 @@ BadGuy::kill_me(int score) play_sound(sounds[SND_FALL], SOUND_CENTER_SPEAKER); } -void BadGuy::explode(BadGuy *badguy) +void +BadGuy::explode() +{ + World::current()->add_bad_guy(base.x, base.y, BAD_BOMB); + remove_me(); +} + +void +BadGuy::collision(const MovingObject&, int) { -World::current()->add_bad_guy(badguy->base.x, badguy->base.y, BAD_BOMB); -badguy->remove_me(); + // later } void @@ -1052,7 +1105,7 @@ BadGuy::collision(void *p_c_object, int c_object, CollisionType type) if (pbad_c->kind == BAD_MRBOMB) { // mrbomb transforms into a bomb now - explode(pbad_c); + pbad_c->explode(); return; } else if (pbad_c->kind != BAD_MRBOMB) @@ -1067,7 +1120,7 @@ BadGuy::collision(void *p_c_object, int c_object, CollisionType type) if (pbad_c->kind == BAD_MRBOMB) { // mrbomb transforms into a bomb now - explode(pbad_c); + pbad_c->explode(); return; } else diff --git a/src/badguy.h b/src/badguy.h index 0335351be..b349c0288 100644 --- a/src/badguy.h +++ b/src/badguy.h @@ -32,6 +32,9 @@ #include "physic.h" #include "collision.h" #include "sprite.h" +#include "moving_object.h" +#include "drawable.h" +#include "serializable.h" /* Bad guy kinds: */ enum BadGuyKind { @@ -57,7 +60,7 @@ void free_badguy_gfx(); class Player; /* Badguy type: */ -class BadGuy : public GameObject +class BadGuy : public MovingObject, public Drawable, public Serializable { public: /* Enemy modes: */ @@ -107,13 +110,17 @@ private: int animation_offset; public: - BadGuy(float x, float y, BadGuyKind kind, bool stay_on_platform); + BadGuy(DisplayManager& display_manager, BadGuyKind kind, float x, float y); + BadGuy(DisplayManager& display_manager, BadGuyKind kind, LispReader& reader); + virtual ~BadGuy(); - void action(double frame_ratio); - void draw(); - std::string type() { return "BadGuy"; }; + virtual void write(LispWriter& writer); - void explode(BadGuy* badguy); + virtual void action(float frame_ratio); + virtual void draw(ViewPort& viewport, int layer); + virtual void collision(const MovingObject& other, int type); + virtual std::string type() const + { return "BadGuy"; }; void collision(void* p_c_object, int c_object, CollisionType type = COLLISION_NORMAL); @@ -123,14 +130,9 @@ public: */ void kill_me(int score); - /** remove ourself from the list of badguys. WARNING! This function will - * invalidate all members. So don't do anything else with member after calling - * this. - */ - void remove_me(); - bool is_removable() const { return removable; } - private: + void init(); + void action_mriceblock(double frame_ratio); void action_jumpy(double frame_ratio); void action_bomb(double frame_ratio); @@ -150,6 +152,8 @@ private: /** let the player jump a bit (used when you hit a badguy) */ void make_player_jump(Player* player); + void explode(); + /** check if we're running left or right in a wall and eventually change * direction */ @@ -164,21 +168,6 @@ private: void set_sprite(Sprite* left, Sprite* right); }; -struct BadGuyData -{ - BadGuyKind kind; - int x; - int y; - bool stay_on_platform; - - BadGuyData(BadGuy* pbadguy) : kind(pbadguy->kind), x((int)pbadguy->base.x), y((int)pbadguy->base.y), stay_on_platform(pbadguy->stay_on_platform) {}; - BadGuyData(BadGuyKind kind_, int x_, int y_, bool stay_on_platform_) - : kind(kind_), x(x_), y(y_), stay_on_platform(stay_on_platform_) {} - - BadGuyData() - : kind(BAD_SNOWBALL), x(0), y(0), stay_on_platform(false) {} -}; - #endif /*SUPERTUX_BADGUY_H*/ /* Local Variables: */ diff --git a/src/button.cpp b/src/button.cpp index 8bb8e502d..6467474db 100644 --- a/src/button.cpp +++ b/src/button.cpp @@ -24,6 +24,7 @@ #include "screen.h" #include "globals.h" #include "button.h" +#include "viewport.h" Timer Button::popup_timer; @@ -44,7 +45,7 @@ Button::Button(std::string icon_file, std::string ninfo, SDLKey nshortcut, int x tag = -1; state = BUTTON_NONE; show_info = false; - game_object = NULL; + drawable = NULL; } void Button::add_icon(std::string icon_file, int mw, int mh) @@ -84,9 +85,11 @@ void Button::draw() for(std::vector::iterator it = icon.begin(); it != icon.end(); ++it) (*it)->draw(rect.x,rect.y); - if(game_object != NULL) + if(drawable) { - game_object->draw_on_screen(rect.x,rect.y); + ViewPort viewport; + viewport.set_translation(Vector(rect.x, rect.y)); + drawable->draw(viewport, 0); } if(show_info) @@ -113,7 +116,7 @@ Button::~Button() for(std::vector::iterator it = icon.begin(); it != icon.end(); ++it) delete (*it); icon.clear(); - delete game_object; + delete drawable; } void Button::event(SDL_Event &event) diff --git a/src/button.h b/src/button.h index af2d51bec..950e898d5 100644 --- a/src/button.h +++ b/src/button.h @@ -23,6 +23,7 @@ #include #include "texture.h" +#include "drawable.h" enum ButtonState { BUTTON_NONE = -1, @@ -50,12 +51,12 @@ public: void add_icon(std::string icon_file, int mw, int mh); SDL_Rect get_pos() { return rect; } int get_tag(){return tag; } - void set_game_object(GameObject* game_object_) { game_object = game_object_; } - GameObject* get_game_object() { return game_object; }; + void set_drawable(Drawable* newdrawable) + { drawable = newdrawable; } private: static Timer popup_timer; - GameObject* game_object; + Drawable* drawable; std::vector icon; std::string info; SDLKey shortcut; diff --git a/src/level.cpp b/src/level.cpp index 24deca628..e7ecdfd49 100644 --- a/src/level.cpp +++ b/src/level.cpp @@ -23,6 +23,7 @@ #include #include #include +#include #include "globals.h" #include "setup.h" #include "screen.h" @@ -34,6 +35,8 @@ #include "resources.h" #include "music_manager.h" #include "gameobjs.h" +#include "world.h" +#include "lispwriter.h" using namespace std; @@ -56,7 +59,7 @@ void LevelSubset::create(const std::string& subset_name) new_subset.description = "No description so far."; new_subset.save(); new_lev.init_defaults(); - new_lev.save(subset_name, 1); + new_lev.save(subset_name, 1, 0); } void LevelSubset::parse (lisp_object_t* cursor) @@ -206,20 +209,6 @@ Level::Level() init_defaults(); } -Level::Level(const std::string& subset, int level) - : img_bkgd(0) -{ - if(load(subset, level) < 0) - st_abort("Couldn't load level from subset", subset.c_str()); -} - -Level::Level(const std::string& filename) - : img_bkgd(0) -{ - if(load(filename) < 0) - st_abort("Couldn't load level " , filename.c_str()); -} - Level::~Level() { delete img_bkgd; @@ -232,8 +221,8 @@ Level::init_defaults() author = "UnNamed"; song_title = "Mortimers_chipdisko.mod"; bkgd_image = "arctis.png"; - width = 21; - height = 19; + width = 0; + height = 0; start_pos_x = 100; start_pos_y = 170; time_left = 100; @@ -248,32 +237,11 @@ Level::init_defaults() bkgd_bottom.green = 255; bkgd_bottom.blue = 255; - bg_tiles.resize(height+1, std::vector(width, 0)); - ia_tiles.resize(height+1, std::vector(width, 0)); - fg_tiles.resize(height+1, std::vector(width, 0)); - - for(int i = 0; i < height; ++i) - { - ia_tiles[i].resize(width+1, 0); - ia_tiles[i][width] = (unsigned int) '\0'; - - for(int y = 0; y < width; ++y) - ia_tiles[i][y] = 0; - - bg_tiles[i].resize(width+1, 0); - bg_tiles[i][width] = (unsigned int) '\0'; - for(int y = 0; y < width; ++y) - bg_tiles[i][y] = 0; - - fg_tiles[i].resize(width+1, 0); - fg_tiles[i][width] = (unsigned int) '\0'; - for(int y = 0; y < width; ++y) - fg_tiles[i][y] = 0; - } + resize(21, 19); } int -Level::load(const std::string& subset, int level) +Level::load(const std::string& subset, int level, World* world) { char filename[1024]; @@ -282,11 +250,11 @@ Level::load(const std::string& subset, int level) if(!faccessible(filename)) snprintf(filename, 1024, "%s/levels/%s/level%d.stl", datadir.c_str(), subset.c_str(), level); - return load(filename); + return load(filename, world); } int -Level::load(const std::string& filename) +Level::load(const std::string& filename, World* world) { lisp_object_t* root_obj = lisp_read_from_file(filename); if (!root_obj) @@ -301,10 +269,6 @@ Level::load(const std::string& filename) return -1; } - vector ia_tm; - vector bg_tm; - vector fg_tm; - int version = 0; if (strcmp(lisp_symbol(lisp_car(root_obj)), "supertux-level") == 0) { @@ -356,12 +320,18 @@ Level::load(const std::string& filename) particle_system = ""; reader.read_string("particle_system", &particle_system); - reader.read_int_vector("background-tm", &bg_tm); + reader.read_int_vector("background-tm", &bg_tiles); + if(int(bg_tiles.size()) != width * height) + st_abort("Wrong size of backgroundtilemap", ""); - if (!reader.read_int_vector("interactive-tm", &ia_tm)) - reader.read_int_vector("tilemap", &ia_tm); + if (!reader.read_int_vector("interactive-tm", &ia_tiles)) + reader.read_int_vector("tilemap", &ia_tiles); + if(int(ia_tiles.size()) != width * height) + st_abort("Wrong size of interactivetilemap", ""); - reader.read_int_vector("foreground-tm", &fg_tm); + reader.read_int_vector("foreground-tm", &fg_tiles); + if(int(fg_tiles.size()) != width * height) + st_abort("Wrong size of foregroundtilemap", ""); { // Read ResetPoints lisp_object_t* cur = 0; @@ -389,44 +359,12 @@ Level::load(const std::string& filename) lisp_object_t* cur = 0; if (reader.read_lisp("objects", &cur)) { - while (!lisp_nil_p(cur)) - { - lisp_object_t* data = lisp_car(cur); - std::string object_type = ""; - - LispReader reader(lisp_cdr(data)); - reader.read_string("type", &object_type); - - if (object_type == "badguy" || object_type == "") - { - BadGuyData bg_data; - bg_data.kind = badguykind_from_string(lisp_symbol(lisp_car(data))); - reader.read_int("x", &bg_data.x); - reader.read_int("y", &bg_data.y); - reader.read_bool("stay-on-platform", &bg_data.stay_on_platform); - - badguy_data.push_back(bg_data); - } - else - { - if (strcmp(lisp_symbol(lisp_car(data)),"trampoline") == 0) - { - ObjectData _trampoline_data; - - _trampoline_data.type = OBJ_TRAMPOLINE; - reader.read_int("x", &_trampoline_data.x); - reader.read_int("y", &_trampoline_data.y); - reader.read_float("power", &_trampoline_data.type_specific.power); - - trampoline_data.push_back(_trampoline_data); - } - } - - cur = lisp_cdr(cur); - } + if(world) + world->parse_objects(cur); } } +#if 0 // TODO fix this or remove it // Convert old levels to the new tile numbers if (version == 0) { @@ -496,53 +434,7 @@ Level::load(const std::string& filename) } } } - } - - bg_tiles.resize(height+1, std::vector(width, 0)); - ia_tiles.resize(height+1, std::vector(width, 0)); - fg_tiles.resize(height+1, std::vector(width, 0)); - - for(int i = 0; i < height; ++i) - { - ia_tiles[i].resize(width + 1, 0); - bg_tiles[i].resize(width + 1, 0); - fg_tiles[i].resize(width + 1, 0); - } - - int i = 0; - int j = 0; - for(vector::iterator it = ia_tm.begin(); it != ia_tm.end(); ++it, ++i) - { - ia_tiles[j][i] = (*it); - if(i == width - 1) - { - i = -1; - ++j; - } - } - - i = j = 0; - for(vector::iterator it = bg_tm.begin(); it != bg_tm.end(); ++it, ++i) - { - - bg_tiles[j][i] = (*it); - if(i == width - 1) - { - i = -1; - ++j; - } - } - - i = j = 0; - for(vector::iterator it = fg_tm.begin(); it != fg_tm.end(); ++it, ++i) - { - - fg_tiles[j][i] = (*it); - if(i == width - 1) - { - i = -1; - ++j; - } +#endif } lisp_free(root_obj); @@ -552,7 +444,7 @@ Level::load(const std::string& filename) /* Save data for level: */ void -Level::save(const std::string& subset, int level) +Level::save(const std::string& subset, int level, World* world) { char filename[1024]; char str[80]; @@ -566,114 +458,77 @@ Level::save(const std::string& subset, int level) snprintf(filename, 1024, "%s/levels/%s/level%d.stl", datadir.c_str(), subset.c_str(), level); - FILE * fi = fopen(filename, "w"); - if (fi == NULL) - { - perror(filename); - st_shutdown(); - exit(-1); - } - + std::ofstream out(filename); + if(!out.good()) { + st_abort("Couldn't write file.", filename); + } + LispWriter writer(out); /* Write header: */ - fprintf(fi,";SuperTux level made using the built-in leveleditor\n"); - fprintf(fi,"(supertux-level\n"); - - fprintf(fi," (version %d)\n", 1); - fprintf(fi," (name \"%s\")\n", name.c_str()); - fprintf(fi," (author \"%s\")\n", author.c_str()); - fprintf(fi," (music \"%s\")\n", song_title.c_str()); - fprintf(fi," (background \"%s\")\n", bkgd_image.c_str()); - fprintf(fi," (particle_system \"%s\")\n", particle_system.c_str()); - fprintf(fi," (bkgd_speed %d)\n", bkgd_speed); - fprintf(fi," (bkgd_red_top %d)\n", bkgd_top.red); - fprintf(fi," (bkgd_green_top %d)\n", bkgd_top.green); - fprintf(fi," (bkgd_blue_top %d)\n", bkgd_top.blue); - fprintf(fi," (bkgd_red_bottom %d)\n", bkgd_bottom.red); - fprintf(fi," (bkgd_green_bottom %d)\n", bkgd_bottom.green); - fprintf(fi," (bkgd_blue_bottom %d)\n", bkgd_bottom.blue); - fprintf(fi," (time %d)\n", time_left); - fprintf(fi," (width %d)\n", width); - fprintf(fi," (height %d)\n", height); - if(back_scrolling) - fprintf(fi," (back_scrolling #t)\n"); - else - fprintf(fi," (back_scrolling #f)\n"); - fprintf(fi," (hor_autoscroll_speed %2.1f)\n", hor_autoscroll_speed); - fprintf(fi," (gravity %2.1f)\n", gravity); - fprintf(fi," (background-tm "); - - for(int y = 0; y < height; ++y) - { - for(int i = 0; i < width; ++i) - fprintf(fi," %d ", bg_tiles[y][i]); - fprintf(fi,"\n"); - } - - fprintf( fi,")\n"); - fprintf(fi," (interactive-tm "); - - for(int y = 0; y < height; ++y) - { - for(int i = 0; i < width; ++i) - fprintf(fi," %d ", ia_tiles[y][i]); - fprintf(fi,"\n"); - } - - fprintf( fi,")\n"); - fprintf(fi," (foreground-tm "); - - for(int y = 0; y < height; ++y) - { - for(int i = 0; i < width; ++i) - fprintf(fi," %d ", fg_tiles[y][i]); - fprintf(fi,"\n"); - } - - fprintf( fi,")\n"); - - fprintf( fi,"(reset-points\n"); + writer.writeComment("SuperTux level made using the built-in leveleditor"); + writer.startList("supertux-level"); + + writer.writeInt("version", 1); + writer.writeString("name", name); + writer.writeString("author", author); + writer.writeString("music", song_title); + writer.writeString("background", bkgd_image); + writer.writeString("particle_system", particle_system); + writer.writeInt("bkgd_speed", bkgd_speed); + writer.writeInt("bkgd_red_top", bkgd_top.red); + writer.writeInt("bkgd_green_top", bkgd_top.green); + writer.writeInt("bkgd_blue_top", bkgd_top.blue); + writer.writeInt("bkgd_red_bottom", bkgd_bottom.red); + writer.writeInt("bkgd_green_bottom", bkgd_bottom.green); + writer.writeInt("bkgd_blue_bottom", bkgd_bottom.blue); + writer.writeInt("time", time_left); + writer.writeInt("width", width); + writer.writeInt("height", height); + writer.writeBool("back_scrolling", back_scrolling); + writer.writeFloat("hor_autoscroll_speed", hor_autoscroll_speed); + writer.writeFloat("gravity", gravity); + + writer.writeIntVector("background-tm", bg_tiles); + writer.writeIntVector("interactive-tm", ia_tiles); + writer.writeIntVector("foreground-tm", fg_tiles); + + writer.startList("reset-points"); for(std::vector::iterator i = reset_points.begin(); - i != reset_points.end(); ++i) - fprintf( fi,"(point (x %d) (y %d))\n",i->x, i->y); - fprintf( fi,")\n"); - - fprintf( fi,"(objects\n"); - - for(std::vector::iterator it = badguy_data.begin(); - it != badguy_data.end(); - ++it) - fprintf( fi," (%s (x %d) (y %d) (stay-on-platform %s))\n", - badguykind_to_string((*it).kind).c_str(),(*it).x,(*it).y, - it->stay_on_platform ? "#t" : "#f"); - - fprintf( fi,")\n"); - - fprintf( fi,")\n"); + i != reset_points.end(); ++i) { + writer.startList("point"); + writer.writeInt("x", i->x); + writer.writeInt("y", i->y); + } + writer.endList("reset-points"); + + // write objects + writer.startList("objects"); + // pick all objects that can be written into a levelfile + for(std::vector<_GameObject*>::iterator it = world->gameobjects.begin(); + it != world->gameobjects.end(); ++it) { + Serializable* serializable = dynamic_cast (*it); + if(serializable) + serializable->write(writer); + } + writer.endList("objects"); - fclose(fi); + writer.endList("supertux-level"); + out.close(); } - /* Unload data for this level: */ - void Level::cleanup() { - for(int i=0; i < 15; ++i) - { - bg_tiles[i].clear(); - ia_tiles[i].clear(); - fg_tiles[i].clear(); - } + bg_tiles.clear(); + ia_tiles.clear(); + fg_tiles.clear(); reset_points.clear(); name = ""; author = ""; song_title = ""; bkgd_image = ""; - - badguy_data.clear(); } void @@ -709,34 +564,32 @@ void Level::load_image(Surface** ptexture, string theme,const char * file, int /* Change the size of a level */ void -Level::change_width (int new_width) +Level::resize(int new_width, int new_height) { - if(new_width < 21) - new_width = 21; + // first: resize height + ia_tiles.resize(new_height * width, 0); + bg_tiles.resize(new_height * width, 0); + fg_tiles.resize(new_height * width, 0); + height = new_height; - for(int y = 0; y < height; ++y) - { - ia_tiles[y].resize(new_width, 0); - bg_tiles[y].resize(new_width, 0); - fg_tiles[y].resize(new_width, 0); + // remap horizontal tiles for new width + int np = 0; + for(int y = 0; y < height; ++y) { + for(int x = 0; x < new_width && x < width; ++x) { + ia_tiles[np] = ia_tiles[y * width + x]; + bg_tiles[np] = bg_tiles[y * width + x]; + fg_tiles[np] = fg_tiles[y * width + x]; + np++; } + } + ia_tiles.resize(new_height * new_width); + bg_tiles.resize(new_height * new_width); + fg_tiles.resize(new_height * new_width); + width = new_width; } -void -Level::change_height (int new_height) -{ - if(new_height < 15) - new_height = 15; - - bg_tiles.resize(height+1, std::vector(width, 0)); - ia_tiles.resize(height+1, std::vector(width, 0)); - fg_tiles.resize(height+1, std::vector(width, 0)); - - height = new_height; -} - void Level::change(float x, float y, int tm, unsigned int c) { @@ -748,13 +601,13 @@ Level::change(float x, float y, int tm, unsigned int c) switch(tm) { case TM_BG: - bg_tiles[yy][xx] = c; + bg_tiles[yy * width + xx] = c; break; case TM_IA: - ia_tiles[yy][xx] = c; + ia_tiles[yy * width + xx] = c; break; case TM_FG: - fg_tiles[yy][xx] = c; + fg_tiles[yy * width + xx] = c; break; } } @@ -824,7 +677,7 @@ Level::gettileid(float x, float y) const xx = ((int)x / 32); if (yy >= 0 && yy < height && xx >= 0 && xx <= width) - c = ia_tiles[yy][xx]; + c = ia_tiles[yy * width + xx]; else c = 0; @@ -834,10 +687,10 @@ Level::gettileid(float x, float y) const unsigned int Level::get_tile_at(int x, int y) const { - if(x < 0 || x > width || y < 0 || y > height) + if(x < 0 || x >= width || y < 0 || y >= height) return 0; - return ia_tiles[y][x]; + return ia_tiles[y * width + x]; } /* EOF */ diff --git a/src/level.h b/src/level.h index 8e70354f0..ed27b8e3f 100644 --- a/src/level.h +++ b/src/level.h @@ -29,6 +29,7 @@ #include "gameobjs.h" class Tile; +class World; /** This type holds meta-information about a level-subset. It could be extended to handle manipulation of subsets. */ @@ -79,9 +80,9 @@ class Level std::string song_title; std::string bkgd_image; std::string particle_system; - std::vector > bg_tiles; /* Tiles in the background */ - std::vector > ia_tiles; /* Tiles which can interact in the game (solids for example)*/ - std::vector > fg_tiles; /* Tiles in the foreground */ + std::vector bg_tiles; /* Tiles in the background */ + std::vector ia_tiles; /* Tiles which can interact in the game (solids for example)*/ + std::vector fg_tiles; /* Tiles in the foreground */ // std::vector bg_tiles[15]; /* Tiles in the background */ // std::vector ia_tiles[15]; /* Tiles which can interact in the game (solids for example)*/ // std::vector fg_tiles[15]; /* Tiles in the foreground */ @@ -97,15 +98,14 @@ class Level bool back_scrolling; float hor_autoscroll_speed; - std::vector badguy_data; std::vector< ObjectData > trampoline_data; /** A collection of points to which Tux can be reset after a lost live */ std::vector reset_points; public: Level(); - Level(const std::string& subset, int level); - Level(const std::string& filename); + Level(const std::string& subset, int level, World* world); + Level(const std::string& filename, World* world); ~Level(); /** Will the Level structure with default values */ @@ -115,12 +115,16 @@ class Level void cleanup(); /** Load data for this level: - Returns -1, if the loading of the level failed. */ - int load(const std::string& subset, int level); + Returns -1, if the loading of the level failed. + XXX the world parameter is a temporary hack + */ + int load(const std::string& subset, int level, World* world); /** Load data for this level: - Returns -1, if the loading of the level failed. */ - int load(const std::string& filename); + Returns -1, if the loading of the level failed. + XXX the world parameter is a temporary hack + */ + int load(const std::string& filename, World* world); void load_gfx(); @@ -129,14 +133,14 @@ class Level MusicRef get_level_music(); MusicRef get_level_music_fast(); - void save(const std::string& subset, int level); + // XXX the world parameter is a temporary hack + void save(const std::string& subset, int level, World* world); /** Edit a piece of the map! */ void change(float x, float y, int tm, unsigned int c); /** Resize the level to a new width/height */ - void change_width (int new_width); - void change_height (int new_height); + void resize(int new_width, int new_height); /* Draw background */ void draw_bg(); diff --git a/src/leveleditor.cpp b/src/leveleditor.cpp index 47a39ab19..1c7f3e3ad 100644 --- a/src/leveleditor.cpp +++ b/src/leveleditor.cpp @@ -42,6 +42,7 @@ #include "tile.h" #include "resources.h" #include "music_manager.h" +#include "display_manager.h" /* definitions to aid development */ @@ -153,7 +154,7 @@ static ButtonPanelMap objects_map; static std::string cur_tilegroup; static std::string cur_objects; static MouseCursor* mouse_select_object; -static GameObject* selected_game_object; +static MovingObject* selected_game_object; static square selection; static SelectionMode le_selection_mode; @@ -499,15 +500,23 @@ void le_init_menus() select_objects_menu->arrange_left = true; select_objects_menu->additem(MN_LABEL,"Objects",0,0); select_objects_menu->additem(MN_HL,"",0,0); + // TODO fix this +#if 0 select_objects_menu->additem(MN_ACTION,"BadGuys",0,0,1); objects_map["BadGuys"] = new ButtonPanel(screen->w - 64,96, 64, 318); + DisplayManager dummy; for(int i = 0; i < NUM_BadGuyKinds; ++i) { - BadGuy bad_tmp(0,0,BadGuyKind(i),false); + BadGuy bad_tmp(dummy, 0,0,BadGuyKind(i),false); objects_map["BadGuys"]->additem(new Button("", "BadGuy",(SDLKey)(i+'a'),0,0,32,32),1000000+i); - objects_map["BadGuys"]->manipulate_button(i)->set_game_object(new BadGuy(objects_map["BadGuys"]->manipulate_button(i)->get_pos().x,objects_map["BadGuys"]->manipulate_button(i)->get_pos().y,BadGuyKind(i),false)); + objects_map["BadGuys"]->manipulate_button(i)->set_drawable(new + BadGuy(dummy, + objects_map["BadGuys"]->manipulate_button(i)->get_pos().x, + objects_map["BadGuys"]->manipulate_button(i)->get_pos().y, + BadGuyKind(i), false)); } +#endif select_objects_menu->additem(MN_HL,"",0,0); @@ -665,8 +674,9 @@ void apply_level_settings_menu() le_world->get_level()->song_title = string_list_active(level_settings_menu->get_item_by_id(MNID_SONG).list); - le_world->get_level()->change_width(atoi(level_settings_menu->get_item_by_id(MNID_LENGTH).input)); - le_world->get_level()->change_height(atoi(level_settings_menu->get_item_by_id(MNID_HEIGHT).input)); + le_world->get_level()->resize( + atoi(level_settings_menu->get_item_by_id(MNID_LENGTH).input), + atoi(level_settings_menu->get_item_by_id(MNID_HEIGHT).input)); le_world->get_level()->time_left = atoi(level_settings_menu->get_item_by_id(MNID_TIME).input); le_world->get_level()->gravity = atof(level_settings_menu->get_item_by_id(MNID_GRAVITY).input); le_world->get_level()->bkgd_speed = atoi(level_settings_menu->get_item_by_id(MNID_BGSPEED).input); @@ -696,7 +706,8 @@ void le_unload_level() sprintf(str,"Save changes to level %d of %s?",le_level,le_level_subset->name.c_str()); if(confirm_dialog(str)) { - le_world->get_level()->save(le_level_subset->name.c_str(),le_level); + le_world->get_level()->save(le_level_subset->name.c_str(), le_level, + le_world); } } @@ -782,15 +793,19 @@ void le_drawminimap() else mini_tile_height = 1; + Level* level = le_world->get_level(); for (int y = 0; y < le_world->get_level()->height; ++y) for (int x = 0; x < le_world->get_level()->width; ++x) { - Tile::draw_stretched(left_offset + mini_tile_width*x, y * 4, mini_tile_width , 4, le_world->get_level()->bg_tiles[y][x]); + Tile::draw_stretched(left_offset + mini_tile_width*x, y * 4, + mini_tile_width , 4, level->bg_tiles[y * level->width + x]); - Tile::draw_stretched(left_offset + mini_tile_width*x, y * 4, mini_tile_width , 4, le_world->get_level()->ia_tiles[y][x]); + Tile::draw_stretched(left_offset + mini_tile_width*x, y * 4, + mini_tile_width , 4, level->ia_tiles[y * level->width + x]); - Tile::draw_stretched(left_offset + mini_tile_width*x, y * 4, mini_tile_width , 4, le_world->get_level()->fg_tiles[y][x]); + Tile::draw_stretched(left_offset + mini_tile_width*x, y * 4, + mini_tile_width , 4, level->fg_tiles[y + level->width + x]); } @@ -942,6 +957,7 @@ void le_drawlevel() /* clearscreen(current_level.bkgd_red, current_level.bkgd_green, current_level.bkgd_blue); */ + Level* level = le_world->get_level(); for (y = 0; y < VISIBLE_TILES_Y && y < (unsigned)le_world->get_level()->height; ++y) for (x = 0; x < (unsigned)VISIBLE_TILES_X - 2; ++x) { @@ -951,47 +967,59 @@ void le_drawlevel() else a = 128; - Tile::draw(32*x - fmodf(pos_x, 32), y*32 - fmodf(pos_y, 32), le_world->get_level()->bg_tiles[y + (int)(pos_y / 32)][x + (int)(pos_x / 32)],a); + Tile::draw(32*x - fmodf(pos_x, 32), y*32 - fmodf(pos_y, 32), + level->bg_tiles[ (y + (int)(pos_y / 32)) * level->width + + (x + (int)(pos_x / 32))],a); if(active_tm == TM_IA) a = 255; else a = 128; - Tile::draw(32*x - fmodf(pos_x, 32), y*32 - fmodf(pos_y, 32), le_world->get_level()->ia_tiles[y + (int)(pos_y / 32)][x + (int)(pos_x / 32)],a); + Tile::draw(32*x - fmodf(pos_x, 32), y*32 - fmodf(pos_y, 32), + level->ia_tiles[ (y + (int)(pos_y / 32)) * level->width + + (x + (int)(pos_x / 32))],a); + if(active_tm == TM_FG) a = 255; else a = 128; - Tile::draw(32*x - fmodf(pos_x, 32), y*32 - fmodf(pos_y, 32), le_world->get_level()->fg_tiles[y + (int)(pos_y / 32)][x + (int)(pos_x / 32)],a); + Tile::draw(32*x - fmodf(pos_x, 32), y*32 - fmodf(pos_y, 32), + level->fg_tiles[ (y + (int)(pos_y / 32)) * level->width + + (x + (int)(pos_x / 32))],a); /* draw whats inside stuff when cursor is selecting those */ /* (draw them all the time - is this the right behaviour?) */ - Tile* edit_image = TileManager::instance()->get(le_world->get_level()->ia_tiles[y + (int)(pos_y / 32)][x + (int)(pos_x / 32)]); + Tile* edit_image = TileManager::instance()->get( + level->ia_tiles + [ (y + (int)(pos_y / 32)) * level->width + (x + (int)(pos_x / 32))]); if(edit_image && !edit_image->editor_images.empty()) edit_image->editor_images[0]->draw( x * 32 - ((int)pos_x % 32), y*32 - ((int)pos_y % 32)); } /* Draw the Bad guys: */ - for (std::list::iterator it = le_world->bad_guys.begin(); it != le_world->bad_guys.end(); ++it) + for (std::vector<_GameObject*>::iterator it = le_world->gameobjects.begin(); + it != le_world->gameobjects.end(); ++it) { + BadGuy* badguy = dynamic_cast (*it); + if(badguy == 0) + continue; + /* to support frames: img_bsod_left[(frame / 5) % 4] */ - - scroll_x = pos_x; - scroll_y = pos_y; - (*it)->draw(); + ViewPort viewport; + viewport.set_translation(Vector(pos_x, pos_y)); + badguy->draw(viewport, 0); } - /* Draw the player: */ /* for now, the position is fixed at (100, 240) */ largetux.walk_right->draw( 100 - pos_x, 240 - pos_y); } -void le_change_object_properties(GameObject *pobj) +void le_change_object_properties(_GameObject *pobj) { Surface* cap_screen = Surface::CaptureScreen(); Menu* object_properties_menu = new Menu(); @@ -1000,13 +1028,14 @@ void le_change_object_properties(GameObject *pobj) object_properties_menu->additem(MN_LABEL,pobj->type() + " Properties",0,0); object_properties_menu->additem(MN_HL,"",0,0); - if(pobj->type() == "BadGuy") + BadGuy* pbad = dynamic_cast(pobj); + if(pobj != 0) { - BadGuy* pbad = dynamic_cast(pobj); object_properties_menu->additem(MN_STRINGSELECT,"Kind",0,0,1); for(int i = 0; i < NUM_BadGuyKinds; ++i) { - string_list_add_item(object_properties_menu->get_item_by_id(1).list,badguykind_to_string(static_cast(i)).c_str()); + string_list_add_item(object_properties_menu->get_item_by_id(1).list, + badguykind_to_string(static_cast(i)).c_str()); if(pbad->kind == i) object_properties_menu->get_item_by_id(1).list->active_item = i; } @@ -1035,23 +1064,16 @@ void le_change_object_properties(GameObject *pobj) switch (object_properties_menu->check()) { case 3: - if(pobj->type() == "BadGuy") { + BadGuy* pbad = dynamic_cast(pobj); + if(pbad != 0) { BadGuy* pbad = dynamic_cast(pobj); pbad->kind = badguykind_from_string(string_list_active(object_properties_menu->get_item_by_id(1).list)); pbad->stay_on_platform = object_properties_menu->get_item_by_id(2).toggled; - int i = 0; - std::list::iterator it; - for(it = le_world->bad_guys.begin(); it != le_world->bad_guys.end(); ++it, ++i) - if((*it) == pbad) - break; - le_world->get_level()->badguy_data[i].kind = pbad->kind; - le_world->get_level()->badguy_data[i].stay_on_platform = pbad->stay_on_platform; - delete (*it); - (*it) = new BadGuy(le_world->get_level()->badguy_data[i].x,le_world->get_level()->badguy_data[i].y,le_world->get_level()->badguy_data[i].kind,le_world->get_level()->badguy_data[i].stay_on_platform); } loop = false; break; + } default: break; } @@ -1210,7 +1232,8 @@ void le_checkevents() le_testlevel(); le_save_level_bt->event(event); if(le_save_level_bt->get_state() == BUTTON_CLICKED) - le_world->get_level()->save(le_level_subset->name.c_str(),le_level); + le_world->get_level()->save(le_level_subset->name.c_str(),le_level, + le_world); le_exit_bt->event(event); if(le_exit_bt->get_state() == BUTTON_CLICKED) { @@ -1231,7 +1254,7 @@ void le_checkevents() if(confirm_dialog(str)) { new_lev.init_defaults(); - new_lev.save(le_level_subset->name.c_str(),le_level+1); + new_lev.save(le_level_subset->name.c_str(),le_level+1, le_world); le_level_subset->levels = le_level; le_goto_level(le_level); } @@ -1388,7 +1411,9 @@ void le_checkevents() { if(pbutton->get_state() == BUTTON_CLICKED) { - le_current.Object(pbutton->get_game_object()); +#if 0 // TODO fixme!! + le_current.Object(pbutton->get_drawable()); +#endif } } } @@ -1435,7 +1460,6 @@ void le_checkevents() { if(MouseCursor::current() == mouse_select_object) { - int i = 0; bool object_got_hit = false; base_type cursor_base; if(le_current.IsTile()) @@ -1451,13 +1475,20 @@ void le_checkevents() cursor_base.width = 32; cursor_base.height = 32; - for(std::list::iterator it = le_world->bad_guys.begin(); it != le_world->bad_guys.end(); ++it, ++i) - if(rectcollision(cursor_base,(*it)->base)) + for(std::vector<_GameObject*>::iterator it = + le_world->gameobjects.begin(); + it != le_world->gameobjects.end(); ++it) { + MovingObject* mobj = dynamic_cast (*it); + if(!mobj) + continue; + + if(rectcollision(cursor_base, mobj->base)) { - selected_game_object = (*it); + selected_game_object = mobj; object_got_hit = true; break; } + } if(!object_got_hit) { @@ -1472,6 +1503,7 @@ void le_checkevents() } else { +#if 0 // FIXME TODO if(le_current.IsObject()) { le_level_changed = true; @@ -1484,6 +1516,7 @@ void le_checkevents() le_world->get_level()->badguy_data.push_back(le_world->bad_guys.back()); } } +#endif } le_mouse_clicked[LEFT] = false; @@ -1622,7 +1655,6 @@ void le_change(float x, float y, int tm, unsigned int c) { int xx,yy; int x1, x2, y1, y2; - unsigned int i = 0; le_level_changed = true; @@ -1638,6 +1670,8 @@ void le_change(float x, float y, int tm, unsigned int c) cursor_base.height = 32; /* if there is a bad guy over there, remove it */ + // XXX TODO +#if 0 for(std::list::iterator it = le_world->bad_guys.begin(); it != le_world->bad_guys.end(); ++it, ++i) if(rectcollision(cursor_base,(*it)->base)) { @@ -1646,6 +1680,7 @@ void le_change(float x, float y, int tm, unsigned int c) le_world->get_level()->badguy_data.erase(le_world->get_level()->badguy_data.begin() + i); break; } +#endif break; case SQUARE: @@ -1676,6 +1711,8 @@ void le_change(float x, float y, int tm, unsigned int c) y2 /= 32; /* if there is a bad guy over there, remove it */ + // TODO FIXME +#if 0 for(std::list::iterator it = le_world->bad_guys.begin(); it != le_world->bad_guys.end(); /* will be at end of loop */) { @@ -1693,6 +1730,7 @@ void le_change(float x, float y, int tm, unsigned int c) ++it; } } +#endif for(xx = x1; xx <= x2; xx++) for(yy = y1; yy <= y2; yy++) @@ -1713,7 +1751,7 @@ void le_testlevel() if(le_world->get_level()->time_left == 0) le_world->get_level()->time_left = 250; - le_world->get_level()->save("test", le_level); + le_world->get_level()->save("test", le_level, le_world); GameSession session("test",le_level, ST_GL_TEST); session.run(); diff --git a/src/lispreader.cpp b/src/lispreader.cpp index 4eb9242f2..3edb5ca93 100644 --- a/src/lispreader.cpp +++ b/src/lispreader.cpp @@ -1116,6 +1116,26 @@ LispReader::read_string_vector (const char* name, std::vector* vec) bool LispReader::read_int_vector (const char* name, std::vector* vec) { + vec->clear(); + lisp_object_t* obj = search_for (name); + if (obj) + { + while(!lisp_nil_p(obj)) + { + if (!lisp_integer_p(lisp_car(obj))) + st_abort("LispReader expected type integer at token: ", name); + vec->push_back(lisp_integer(lisp_car(obj))); + obj = lisp_cdr(obj); + } + return true; + } + return false; +} + +bool +LispReader::read_int_vector (const char* name, std::vector* vec) +{ + vec->clear(); lisp_object_t* obj = search_for (name); if (obj) { @@ -1175,86 +1195,6 @@ LispReader::read_bool (const char* name, bool* b) return false; } -LispWriter::LispWriter (const char* name) -{ - lisp_objs.push_back(lisp_make_symbol (name)); -} - -void -LispWriter::append (lisp_object_t* obj) -{ - lisp_objs.push_back(obj); -} - -lisp_object_t* -LispWriter::make_list3 (lisp_object_t* a, lisp_object_t* b, lisp_object_t* c) -{ - return lisp_make_cons (a, lisp_make_cons(b, lisp_make_cons(c, lisp_nil()))); -} - -lisp_object_t* -LispWriter::make_list2 (lisp_object_t* a, lisp_object_t* b) -{ - return lisp_make_cons (a, lisp_make_cons(b, lisp_nil())); -} - -void -LispWriter::write_float (const char* name, float f) -{ - append(make_list2 (lisp_make_symbol (name), - lisp_make_real(f))); -} - -void -LispWriter::write_int (const char* name, int i) -{ - append(make_list2 (lisp_make_symbol (name), - lisp_make_integer(i))); -} - -void -LispWriter::write_string (const char* name, const char* str) -{ - append(make_list2 (lisp_make_symbol (name), - lisp_make_string(str))); -} - -void -LispWriter::write_symbol (const char* name, const char* symname) -{ - append(make_list2 (lisp_make_symbol (name), - lisp_make_symbol(symname))); -} - -void -LispWriter::write_lisp_obj(const char* name, lisp_object_t* lst) -{ - append(make_list2 (lisp_make_symbol (name), - lst)); -} - -void -LispWriter::write_boolean (const char* name, bool b) -{ - append(make_list2 (lisp_make_symbol (name), - lisp_make_boolean(b))); -} - -lisp_object_t* -LispWriter::create_lisp () -{ - lisp_object_t* lisp_obj = lisp_nil(); - - for(std::vector::reverse_iterator i = lisp_objs.rbegin (); - i != lisp_objs.rend (); ++i) - { - lisp_obj = lisp_make_cons (*i, lisp_obj); - } - lisp_objs.clear(); - - return lisp_obj; -} - #if 0 void mygzungetc(char c, void* file) { diff --git a/src/lispreader.h b/src/lispreader.h index f319afc74..bde266c84 100644 --- a/src/lispreader.h +++ b/src/lispreader.h @@ -180,6 +180,7 @@ class LispReader LispReader (lisp_object_t* l); bool read_int_vector (const char* name, std::vector* vec); + bool read_int_vector (const char* name, std::vector* vec); bool read_char_vector (const char* name, std::vector* vec); bool read_string_vector (const char* name, std::vector* vec); bool read_string (const char* name, std::string* str); @@ -189,26 +190,4 @@ class LispReader bool read_lisp (const char* name, lisp_object_t** b); }; -/** */ -class LispWriter - { - private: - std::vector lisp_objs; - - void append (lisp_object_t* obj); - lisp_object_t* make_list3 (lisp_object_t*, lisp_object_t*, lisp_object_t*); - lisp_object_t* make_list2 (lisp_object_t*, lisp_object_t*); - public: - LispWriter (const char* name); - void write_float (const char* name, float f); - void write_int (const char* name, int i); - void write_boolean (const char* name, bool b); - void write_string (const char* name, const char* str); - void write_symbol (const char* name, const char* symname); - void write_lisp_obj(const char* name, lisp_object_t* lst); - - /** caller is responible to free the returned lisp_object_t */ - lisp_object_t* create_lisp (); - }; - #endif diff --git a/src/player.h b/src/player.h index d80daf246..d1e5b4af7 100644 --- a/src/player.h +++ b/src/player.h @@ -141,7 +141,6 @@ public: Player(DisplayManager& display_manager); virtual ~Player(); - void init(); int key_event(SDLKey key, int state); void level_begin(); void handle_input(); @@ -165,6 +164,8 @@ public: void grow(); private: + void init(); + void handle_horizontal_input(); void handle_vertical_input(); void remove_powerups(); diff --git a/src/tilemap.cpp b/src/tilemap.cpp index 67b3f4d7a..a00bce468 100644 --- a/src/tilemap.cpp +++ b/src/tilemap.cpp @@ -26,7 +26,7 @@ TileMap::action(float ) void TileMap::draw(ViewPort& viewport, int layer) { - std::vector >* tiles; + std::vector* tiles; switch(layer) { case LAYER_BACKGROUNDTILES: tiles = &level->bg_tiles; break; @@ -42,11 +42,11 @@ TileMap::draw(ViewPort& viewport, int layer) int tsy = int(viewport.get_translation().y / 32); // tilestartindex y int sx = - (int(viewport.get_translation().x) % 32); int sy = - (int(viewport.get_translation().y) % 32); - for(int x = sx, tx = tsx; x < screen->w && tx < int((*tiles)[0].size()); + for(int x = sx, tx = tsx; x < screen->w && tx < level->width; x += 32, ++tx) { - for(int y = sy, ty = tsy; y < screen->h && ty < int(tiles->size()); + for(int y = sy, ty = tsy; y < screen->h && ty < level->height; y += 32, ++ty) { - Tile::draw(x, y, (*tiles) [ty][tx]); + Tile::draw(x, y, (*tiles) [ty * level->width + tx]); } } } diff --git a/src/title.cpp b/src/title.cpp index 3b1475962..9639caf2f 100644 --- a/src/title.cpp +++ b/src/title.cpp @@ -126,7 +126,7 @@ void check_contrib_menu() for (int i = 1; i <= subset.levels; ++i) { Level level; - level.load(subset.name, i); + level.load(subset.name, i, 0); contrib_subset_menu->additem(MN_ACTION, level.name, 0, 0, i); } contrib_subset_menu->additem(MN_HL,"",0,0); diff --git a/src/world.cpp b/src/world.cpp index 257b71bc7..f3a91425b 100644 --- a/src/world.cpp +++ b/src/world.cpp @@ -48,7 +48,8 @@ World::World(const std::string& filename) // world calls child functions current_ = this; - level = new Level(filename); + level = new Level(); + level->load(filename, this); tux = new Player(displaymanager); gameobjects.push_back(tux); @@ -56,7 +57,6 @@ World::World(const std::string& filename) set_defaults(); get_level()->load_gfx(); - activate_bad_guys(); // add background activate_particle_systems(); Background* bg = new Background(displaymanager); @@ -83,13 +83,15 @@ World::World(const std::string& subset, int level_nr) // world calls child functions current_ = this; - level = new Level(subset, level_nr); - tux->init(); + level = new Level(); + level->load(subset, level_nr, this); + + tux = new Player(displaymanager); + gameobjects.push_back(tux); set_defaults(); get_level()->load_gfx(); - activate_bad_guys(); activate_objects(); activate_particle_systems(); Background* bg = new Background(displaymanager); @@ -111,32 +113,24 @@ World::World(const std::string& subset, int level_nr) void World::apply_bonuses() { -#if 0 // Apply bonuses from former levels switch (player_status.bonus) { case PlayerStatus::NO_BONUS: break; - + case PlayerStatus::FLOWER_BONUS: - tux->got_power = tux.FIRE_POWER; // FIXME: add ice power to here + tux->got_power = Player::FIRE_POWER; // FIXME: add ice power to here // fall through - + case PlayerStatus::GROWUP_BONUS: - // FIXME: Move this to Player class - tux->size = BIG; - tux->base.height = 64; - tux->base.y -= 32; + tux->grow(); break; } -#endif } World::~World() { - for (BadGuys::iterator i = bad_guys.begin(); i != bad_guys.end(); ++i) - delete *i; - for (Trampolines::iterator i = trampolines.begin(); i != trampolines.end(); ++i) delete *i; @@ -147,6 +141,7 @@ World::~World() displaymanager.remove_drawable(drawable); delete *i; } + bad_guys.clear(); delete level; } @@ -167,14 +162,36 @@ World::set_defaults() } void -World::activate_bad_guys() +World::add_object(_GameObject* object) { - for (std::vector::iterator i = level->badguy_data.begin(); - i != level->badguy_data.end(); - ++i) + // XXX hack for now until new collision code is ready + BadGuy* badguy = dynamic_cast (object); + if(badguy) + bad_guys.push_back(badguy); + + gameobjects.push_back(object); +} + +void +World::parse_objects(lisp_object_t* cur) +{ + while(!lisp_nil_p(cur)) { + lisp_object_t* data = lisp_car(cur); + std::string object_type = ""; + + LispReader reader(lisp_cdr(data)); + reader.read_string("type", &object_type); + + if(object_type == "badguy" || object_type == "") { - add_bad_guy(i->x, i->y, i->kind, i->stay_on_platform); + BadGuyKind kind = badguykind_from_string( + lisp_symbol(lisp_car(data))); + add_object(new BadGuy(displaymanager, kind, reader)); } + // TODO add parsing code for trampolines + + cur = lisp_cdr(cur); + } } void @@ -193,11 +210,11 @@ World::activate_particle_systems() { if (level->particle_system == "clouds") { - gameobjects.push_back(new CloudParticleSystem(displaymanager)); + add_object(new CloudParticleSystem(displaymanager)); } else if (level->particle_system == "snow") { - gameobjects.push_back(new SnowParticleSystem(displaymanager)); + add_object(new SnowParticleSystem(displaymanager)); } else if (level->particle_system != "") { @@ -212,9 +229,6 @@ World::draw() displaymanager.get_viewport().set_translation(Vector(scroll_x, scroll_y)); displaymanager.draw(); - for (BadGuys::iterator i = bad_guys.begin(); i != bad_guys.end(); ++i) - (*i)->draw(); - for (Trampolines::iterator i = trampolines.begin(); i != trampolines.end(); ++i) (*i)->draw(); @@ -237,9 +251,6 @@ World::action(double frame_ratio) for (unsigned int i = 0; i < upgrades.size(); i++) upgrades[i].action(frame_ratio); - for (BadGuys::iterator i = bad_guys.begin(); i != bad_guys.end(); ++i) - (*i)->action(frame_ratio); - for (Trampolines::iterator i = trampolines.begin(); i != trampolines.end(); ++i) (*i)->action(frame_ratio); @@ -251,24 +262,18 @@ World::action(double frame_ratio) /* Handle all possible collisions. */ collision_handler(); - - // Cleanup marked badguys - for (BadGuys::iterator i = bad_guys.begin(); i != bad_guys.end(); - /* ++i handled at end of the loop */) { - if ((*i)->is_removable()) { - delete *i; - i = bad_guys.erase(i); - } else { - ++i; - } - } - + + /** cleanup marked objects */ for(std::vector<_GameObject*>::iterator i = gameobjects.begin(); i != gameobjects.end(); /* nothing */) { if((*i)->is_valid() == false) { Drawable* drawable = dynamic_cast (*i); if(drawable) displaymanager.remove_drawable(drawable); + BadGuy* badguy = dynamic_cast (*i); + if(badguy) { + std::remove(bad_guys.begin(), bad_guys.end(), badguy); + } delete *i; i = gameobjects.erase(i); @@ -497,13 +502,13 @@ World::add_score(const Vector& pos, int s) { player_status.score += s; - gameobjects.push_back(new FloatingScore(displaymanager, pos, s)); + add_object(new FloatingScore(displaymanager, pos, s)); } void World::add_bouncy_distro(const Vector& pos) { - gameobjects.push_back(new BouncyDistro(displaymanager, pos)); + add_object(new BouncyDistro(displaymanager, pos)); } void @@ -520,20 +525,20 @@ void World::add_broken_brick_piece(const Vector& pos, const Vector& movement, Tile* tile) { - gameobjects.push_back(new BrokenBrick(displaymanager, tile, pos, movement)); + add_object(new BrokenBrick(displaymanager, tile, pos, movement)); } void World::add_bouncy_brick(const Vector& pos) { - gameobjects.push_back(new BouncyBrick(displaymanager, pos)); + add_object(new BouncyBrick(displaymanager, pos)); } BadGuy* -World::add_bad_guy(float x, float y, BadGuyKind kind, bool stay_on_platform) +World::add_bad_guy(float x, float y, BadGuyKind kind) { - BadGuy* badguy = new BadGuy(x,y,kind, stay_on_platform); - bad_guys.push_back(badguy); + BadGuy* badguy = new BadGuy(displaymanager, kind, x, y); + add_object(badguy); return badguy; } diff --git a/src/world.h b/src/world.h index 0f822442b..e68ed4134 100644 --- a/src/world.h +++ b/src/world.h @@ -68,12 +68,14 @@ public: World(const std::string& filename); World(const std::string& subset, int level_nr); - World() {}; + //World() {}; ~World(); Level* get_level() { return level; } Player* get_tux() { return tux; } + void add_object(_GameObject* object); + void set_defaults(); void draw(); @@ -82,15 +84,15 @@ public: void play_music(int musictype); int get_music_type(); - /** Checks for all possible collisions. And calls the collision_handlers, which the collision_objects provide for this case (or not). */ void collision_handler(); + + void parse_objects(lisp_object_t* cur); void activate_particle_systems(); - void activate_bad_guys(); void activate_objects(); void add_score(const Vector& pos, int s); @@ -100,7 +102,7 @@ public: const Vector& movement, Tile* tile); void add_bouncy_brick(const Vector& pos); - BadGuy* add_bad_guy(float x, float y, BadGuyKind kind, bool stay_on_platform = false); + BadGuy* add_bad_guy(float x, float y, BadGuyKind kind); template T* add_object(U data); void add_upgrade(float x, float y, Direction dir, UpgradeKind kind);