Implemented mirror actions correctly. Bugfix: right direction of bad guys now working.
[supertux.git] / src / leveleditor.cpp
index 2cf77d5..623a513 100644 (file)
@@ -37,6 +37,7 @@
 #include "badguy.h"
 #include "gameobjs.h"
 #include "door.h"
+#include "camera.h"
 
 LevelEditor::LevelEditor()
 {
@@ -47,8 +48,9 @@ global_frame_counter = 0;
 frame_timer.init(true);
 level_name_timer.init(true);
 selection_end = selection_ini = Vector(0,0);
-left_button = false;
-middle_button = false;
+left_button = middle_button = mouse_moved =  false;
+level = 0;
+level_subset = 0;
 
 cur_layer = LAYER_TILES;
 level_changed = false;
@@ -63,10 +65,7 @@ subset_menu->additem(MN_LABEL,_("Load Subset"),0,0);
 subset_menu->additem(MN_HL,"",0,0);
 int i = 0;
 for(std::set<std::string>::iterator it = level_subsets.begin(); it != level_subsets.end(); ++it, ++i)
-{
-std::cerr << "adding entry level subset " << i << " entry: " << (*it) << std::endl;
   subset_menu->additem(MN_ACTION, (*it),0,0,i);
-}
 subset_menu->additem(MN_HL,"",0,0);
 subset_menu->additem(MN_BACK,_("Back"),0,0);
 
@@ -169,6 +168,9 @@ delete subset_menu;
 delete create_subset_menu;
 delete main_menu;
 delete settings_menu;
+
+delete level;
+delete level_subset;
 }
 
 void LevelEditor::load_buttons_gfx()
@@ -215,7 +217,10 @@ Menu::set_current(0);
 DrawingContext context;
 
 if(!filename.empty())
+  {
+  level_nb = -1;
   load_level(filename);
+  }
 else
   Menu::set_current(main_menu);
 
@@ -236,6 +241,8 @@ if(level_changed)
 
 void LevelEditor::events()
 {
+mouse_moved = false;
+
 while(SDL_PollEvent(&event))
   {
   Menu* menu = Menu::current();
@@ -262,10 +269,13 @@ while(SDL_PollEvent(&event))
       else if(create_subset_menu->check() == MN_ID_CREATE_SUBSET)
         {   // applying settings:
         LevelSubset::create(create_subset_menu->get_item_by_id(MN_ID_FILENAME_SUBSET).input);
-        level_subset.load(create_subset_menu->get_item_by_id(MN_ID_FILENAME_SUBSET).input);
 
-        level_subset.title = create_subset_menu->item[MN_ID_TITLE_SUBSET].input;
-        level_subset.description = create_subset_menu->item[MN_ID_DESCRIPTION_SUBSET].input;
+        delete level_subset;
+        level_subset = new LevelSubset();
+        level_subset->load(create_subset_menu->get_item_by_id(MN_ID_FILENAME_SUBSET).input);
+
+        level_subset->title = create_subset_menu->item[MN_ID_TITLE_SUBSET].input;
+        level_subset->description = create_subset_menu->item[MN_ID_DESCRIPTION_SUBSET].input;
 
         load_level(1);
 
@@ -282,7 +292,6 @@ while(SDL_PollEvent(&event))
         std::set<std::string>::iterator it = level_subsets.begin();
         for(int t = 0; t < i; t++)
           it++;
-std::cerr << "load subset level_subsets " << i << ": " << (*it) << std::endl;
         load_level_subset(*it);
         Menu::set_current(0);
         }
@@ -293,8 +302,8 @@ std::cerr << "load subset level_subsets " << i << ": " << (*it) << std::endl;
         {   // applying settings:
         level_changed = true;
 
-        level.name = settings_menu->get_item_by_id(MN_ID_NAME).input;
-        level.author = settings_menu->get_item_by_id(MN_ID_AUTHOR).input;
+        level->name = settings_menu->get_item_by_id(MN_ID_NAME).input;
+        level->author = settings_menu->get_item_by_id(MN_ID_AUTHOR).input;
 
         solids->resize(atoi(settings_menu->get_item_by_id(MN_ID_WIDTH).input.c_str()),
               atoi(settings_menu->get_item_by_id(MN_ID_HEIGHT).input.c_str()));
@@ -336,33 +345,33 @@ std::cerr << "load subset level_subsets " << i << ": " << (*it) << std::endl;
         Menu::set_current(settings_menu);
         break;
       case BT_NEXT_LEVEL:
-        if(level_nb < level_subset.get_num_levels())
+        if(level_nb+1 < level_subset->get_num_levels())
           load_level(level_nb + 1);
         else
           {
-          Level new_lev;
           char str[1024];
           sprintf(str,_("Level %d doesn't exist. Create it?"), level_nb + 1);
           if(confirm_dialog(NULL, str))
             {
-            level_subset.add_level("new_level.stl");
-            new_lev.save(level_subset.get_level_filename(level_nb + 1));
+            Level new_lev;
+            level_subset->add_level("new_level.stl");
+            new_lev.save(level_subset->get_level_filename(level_nb + 1));
             load_level(level_nb);
             }
           }
         break;
       case BT_PREVIOUS_LEVEL:
-        if(level_nb > 1)
+        if(level_nb-1 > 0)
           load_level(level_nb - 1);
         break;
       case BT_NEXT_SECTOR:
 std::cerr << "next sector.\n";
-std::cerr << "total sectors: " << level.get_total_sectors() << std::endl;
-        load_sector(level.get_next_sector(sector));
+std::cerr << "total sectors: " << level->get_total_sectors() << std::endl;
+        load_sector(level->get_next_sector(sector));
         break;
       case BT_PREVIOUS_SECTOR:
 std::cerr << "previous sector.\n";
-        load_sector(level.get_previous_sector(sector));
+        load_sector(level->get_previous_sector(sector));
         break;
       }
     level_options->set_unselected();
@@ -373,6 +382,7 @@ std::cerr << "previous sector.\n";
     switch(event.type)
       {
       case SDL_MOUSEMOTION:
+        mouse_moved = true;
         if(SDL_GetMouseState(NULL, NULL)&SDL_BUTTON(SDL_BUTTON_RIGHT))
           {  // movement like in strategy games
           scroll.x += -1 * event.motion.xrel;
@@ -381,6 +391,7 @@ std::cerr << "previous sector.\n";
         break;
 
       case SDL_MOUSEBUTTONDOWN:
+        mouse_moved = true;
         if(event.button.button == SDL_BUTTON_LEFT)
           left_button = true;
         else if(event.button.button == SDL_BUTTON_MIDDLE)
@@ -391,6 +402,7 @@ std::cerr << "previous sector.\n";
         break;
 
       case SDL_MOUSEBUTTONUP:
+        mouse_moved = true;
         if(event.button.button == SDL_BUTTON_LEFT)
           left_button = false;
         else if(event.button.button == SDL_BUTTON_MIDDLE)
@@ -525,15 +537,20 @@ if(sector)
   if(scroll.y > height - screen->h/2)
     scroll.y = height - screen->h/2;
 
-  if(left_button)
+  // set camera translation, since BadGuys like it
+  sector->camera->set_scrolling((int)scroll.x, (int)scroll.y);
+
+  if(left_button && mouse_moved)
     for(unsigned int x = 0; x < selection.size(); x++)
       for(unsigned int y = 0; y < selection[x].size(); y++)
-        change((int)((scroll.x + event.button.x)/(32*zoom)) + x,
-             (int)((scroll.y + event.button.y)/(32*zoom)) + y, selection[x][y], 
+        change((int)(scroll.x + event.button.x) + (x*32),
+             (int)(scroll.y + event.button.y) + (y*32), selection[x][y], 
              cur_layer);
   }
 }
 
+#define FADING_TIME 600
+
 void LevelEditor::draw(DrawingContext& context)
 {
 context.draw_text(white_text, _("Level Editor"), Vector(10, 5), LEFT_ALLIGN, LAYER_GUI);
@@ -544,10 +561,19 @@ context.draw_filled_rect(Vector(0,0), Vector(screen->w,screen->h), Color(60,60,6
 
 if(level_name_timer.check())
   {
-  context.draw_text(gold_text, level.name, Vector(screen->w/2, 30), CENTER_ALLIGN, LAYER_GUI);
-  char str[128];
-  sprintf(str, "%i/%i", level_nb+1, level_subset.get_num_levels());
-  context.draw_text(gold_text, str, Vector(screen->w/2, 50), CENTER_ALLIGN, LAYER_GUI);
+  context.push_transform();
+  if(level_name_timer.get_left() < FADING_TIME)
+    context.set_alpha(level_name_timer.get_left() * 255 / FADING_TIME);
+
+  context.draw_text(gold_text, level->name, Vector(screen->w/2, 30), CENTER_ALLIGN, LAYER_GUI);
+  if(level_nb != -1)
+    {
+    char str[128];
+    sprintf(str, "%i/%i", level_nb+1, level_subset->get_num_levels());
+    context.draw_text(gold_text, str, Vector(screen->w/2, 50), CENTER_ALLIGN, LAYER_GUI);
+    }
+
+  context.pop_transform();
   }
 if(sector)
   context.draw_text(white_small_text, _("F1 for help"), Vector(5, 510), LEFT_ALLIGN, LAYER_GUI-10);
@@ -675,38 +701,49 @@ context.do_drawing();
 
 void LevelEditor::load_level_subset(std::string filename)
 {
-std::cerr << "loading subset...\n";
-std::cerr << "filename: " << filename << std::endl;
-level_subset.load(filename.c_str());
+delete level_subset;
+level_subset = new LevelSubset();
+level_subset->load(filename.c_str());
 load_level(1);
 }
 
 void LevelEditor::load_level(std::string filename)
 {
-if(!level_changed)
-  save_level();
+if(level_changed)
+  {
+  if(confirm_dialog(NULL, _("Level not saved. Wanna to?")))
+    save_level();
+  else
+    return;
+  }
 
 level_filename = filename;
-level.load(filename);
+
+delete level;
+level = new Level();
+level->load(filename);
 
 load_sector("main");
 level_name_timer.start(3000);
 scroll.x = scroll.y = 0;
 level_changed = false;
 
-settings_menu->get_item_by_id(MN_ID_NAME).change_input(level.name.c_str());
-settings_menu->get_item_by_id(MN_ID_AUTHOR).change_input(level.author.c_str());
+settings_menu->get_item_by_id(MN_ID_NAME).change_input(level->name.c_str());
+settings_menu->get_item_by_id(MN_ID_AUTHOR).change_input(level->author.c_str());
 }
 
 void LevelEditor::load_level(int nb)
 {
-if(!level_changed)
-  save_level();
+if(level_changed)
+  {
+  if(confirm_dialog(NULL, _("Level not saved. Wanna to?")))
+    save_level();
+  else
+    return;
+  }
 
 level_nb = nb;
-std::cerr << "level_nb: " << level_nb << std::endl;
-std::cerr << "level_subset.get_level_filename(level_nb): " << level_subset.get_level_filename(level_nb) << std::endl;
-level_filename = level_subset.get_level_filename(level_nb);
+level_filename = level_subset->get_level_filename(level_nb);
 
 load_level(level_filename);
 }
@@ -714,7 +751,7 @@ load_level(level_filename);
 void LevelEditor::load_sector(std::string name)
 {
 sector_name = name;
-sector = level.get_sector(sector_name);
+sector = level->get_sector(sector_name);
 if(!sector)
   Termination::abort("Level has no " + sector_name + " sector.", "");
 
@@ -728,7 +765,7 @@ if(sector == NULL)
   if(confirm_dialog(NULL, _("No more sectors exist. Create another?")))
     {
     Sector* nsector = new Sector();
-    level.add_sector(nsector);
+    level->add_sector(nsector);
     sector = nsector;
     }
   return;
@@ -782,7 +819,7 @@ settings_menu->get_item_by_id(MN_ID_HEIGHT).change_input(str);
 
 void LevelEditor::save_level()
 {
-level.save(level_filename);
+level->save(level_filename);
 level_changed = false;
 }
 
@@ -804,57 +841,66 @@ sound_manager->halt_music();
 
 void LevelEditor::change(int x, int y, int newtile, int layer)
 {  // find the tilemap of the current layer, and then change the tile
-if(x < 0 || (unsigned int)x > sector->solids->get_width() ||
-   y < 0 || (unsigned int)y > sector->solids->get_height())
+if(x < 0 || (unsigned int)x > sector->solids->get_width()*32 ||
+   y < 0 || (unsigned int)y > sector->solids->get_height()*32)
   return;
 
 level_changed = true;
 
+if(zoom != 1)
+  {  // no need to do this for normal view (no zoom)
+  x = (int)(x * (zoom*32) / 32);
+  y = (int)(y * (zoom*32) / 32);
+  }
+
 if(newtile < 0)  // add object
   {
   // remove an active tile or object that might be there
   change(x, y, 0, LAYER_TILES);
 
   if(newtile == OBJ_TRAMPOLINE)
-    sector->add_object(new Trampoline(x*32, y*32));
+    sector->add_object(new Trampoline(x, y));
   else if(newtile == OBJ_FLYING_PLATFORM)
-    sector->add_object(new FlyingPlatform(x*32, y*32));
+    sector->add_object(new FlyingPlatform(x, y));
   else if(newtile == OBJ_DOOR)
-    sector->add_object(new Door(x*32, y*32));
+    sector->add_object(new Door(x, y));
   else
-    sector->add_object(new BadGuy(BadGuyKind((-newtile)-1), x*32, y*32));
+    sector->add_object(new BadGuy(BadGuyKind((-newtile)-1), x, y));
 
   sector->update_game_objects();
   }
 else if(cur_layer == LAYER_FOREGROUNDTILES)
-  foregrounds->change(x, y, newtile);
+  foregrounds->change(x/32, y/32, newtile);
 else if(cur_layer == LAYER_TILES)
   {
   // remove a bad guy if it's there
+  // we /32 in order to round numbers
   for(Sector::GameObjects::iterator i = sector->gameobjects.begin(); i < sector->gameobjects.end(); i++)
     {
     BadGuy* badguy = dynamic_cast<BadGuy*> (*i);
     if(badguy)
-      if(badguy->base.x == x*32 && badguy->base.y == y*32)
+      if((int)badguy->base.x/32 == x/32 && (int)badguy->base.y/32 == y/32)
         sector->gameobjects.erase(i);
     Trampoline* trampoline = dynamic_cast<Trampoline*> (*i);
     if(trampoline)
-      if(trampoline->base.x == x*32 && trampoline->base.y == y*32)
+    {
+      if((int)trampoline->base.x/32 == x/32 && (int)trampoline->base.y/32 == y/32)
         sector->gameobjects.erase(i);
+        }
     FlyingPlatform* flying_platform = dynamic_cast<FlyingPlatform*> (*i);
     if(flying_platform)
-      if(flying_platform->base.x == x*32 && flying_platform->base.y == y*32)
+      if((int)flying_platform->base.x/32 == x/32 && (int)flying_platform->base.y/32 == y/32)
         sector->gameobjects.erase(i);
     Door* door = dynamic_cast<Door*> (*i);
     if(door)
-      if(door->get_area().x == x*32 && door->get_area().y == y*32)
+      if((int)door->get_area().x/32 == x/32 && (int)door->get_area().y/32 == y/32)
         sector->gameobjects.erase(i);
     }
   sector->update_game_objects();
-  solids->change(x, y, newtile);
+  solids->change(x/32, y/32, newtile);
   }
 else if(cur_layer == LAYER_BACKGROUNDTILES)
-  backgrounds->change(x, y, newtile);
+  backgrounds->change(x/32, y/32, newtile);
 }
 
 void LevelEditor::show_help()