big refactoring of level and world class. A level is now basically a set of
[supertux.git] / src / tile.cpp
1 //  $Id$
2 // 
3 //  SuperTux
4 //  Copyright (C) 2004 Tobias Glaesser <tobi.web@gmx.de>
5 //
6 //  This program is free software; you can redistribute it and/or
7 //  modify it under the terms of the GNU General Public License
8 //  as published by the Free Software Foundation; either version 2
9 //  of the License, or (at your option) any later version.
10 //
11 //  This program is distributed in the hope that it will be useful,
12 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
13 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 //  GNU General Public License for more details.
15 // 
16 //  You should have received a copy of the GNU General Public License
17 //  along with this program; if not, write to the Free Software
18 //  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
19 //  02111-1307, USA.
20
21 #include "tile.h"
22 #include "scene.h"
23 #include <assert.h>
24 #include <iostream>
25 #include "screen/drawing_context.h"
26
27 TileManager* TileManager::instance_  = 0;
28 std::set<TileGroup>* TileManager::tilegroups_  = 0;
29
30 Tile::Tile()
31   : id(-1), attributes(0), data(0), next_tile(0), anim_speed(25)
32 {
33 }
34
35 Tile::~Tile()
36 {
37   for(std::vector<Surface*>::iterator i = images.begin(); i != images.end();
38       ++i) {
39     delete *i;
40   }
41   for(std::vector<Surface*>::iterator i = editor_images.begin();
42       i != editor_images.end(); ++i) {
43     delete *i;                                                                
44   }
45 }
46
47 int
48 Tile::read(LispReader& reader)
49 {
50   if(!reader.read_int("id", id)) {
51     std::cerr << "Missing tile-id.\n";
52     return -1;
53   }
54   
55   bool value;
56   if(reader.read_bool("solid", value) && value)
57     attributes |= SOLID;
58   if(reader.read_bool("unisolid", value) && value)
59     attributes |= GOAL;                            
60   if(reader.read_bool("brick", value) && value)
61     attributes |= BRICK;
62   if(reader.read_bool("ice", value) && value)
63     attributes |= ICE;
64   if(reader.read_bool("water", value) && value)
65     attributes |= WATER;
66   if(reader.read_bool("spike", value) && value)
67     attributes |= SPIKE;
68   if(reader.read_bool("fullbox", value) && value)
69     attributes |= FULLBOX;
70   if(reader.read_bool("distro", value) && value)
71     attributes |= COIN;
72   if(reader.read_bool("coin", value) && value)
73     attributes |= COIN;
74   if(reader.read_bool("goal", value) && value)
75     attributes |= GOAL;
76
77   reader.read_int("data", data);
78   reader.read_int("anim-speed", anim_speed);
79   reader.read_int("next-tile", next_tile);
80
81   std::vector<std::string> filenames;
82   reader.read_string_vector("images", filenames);
83   std::vector<std::string> editor_filenames;
84   reader.read_string_vector("editor-images", editor_filenames);
85
86   // read images
87   for(std::vector<std::string>::iterator i = filenames.begin();
88       i != filenames.end(); ++i) {
89     Surface* surface 
90       = new Surface(datadir + "/images/tilesets/" + *i, USE_ALPHA);
91     images.push_back(surface);
92   }
93   for(std::vector<std::string>::iterator i = editor_filenames.begin();
94       i != editor_filenames.end(); ++i) {
95     Surface* surface 
96       = new Surface(datadir + "/images/tilesets/" + *i, USE_ALPHA);
97     editor_images.push_back(surface);
98   }
99
100   return id;
101 }
102
103 //---------------------------------------------------------------------------
104
105 TileManager::TileManager()
106 {
107   std::string filename = datadir + "/images/tilesets/supertux.stgt";
108   load_tileset(filename);
109 }
110
111 TileManager::~TileManager()
112 {
113   for(std::vector<Tile*>::iterator i = tiles.begin(); i != tiles.end(); ++i) {
114     delete *i;                                                                  
115   }
116 }
117
118 void TileManager::load_tileset(std::string filename)
119 {
120   if(filename == current_tileset)
121     return;
122   
123   // free old tiles
124   for(std::vector<Tile*>::iterator i = tiles.begin(); i != tiles.end(); ++i) {
125     delete *i;
126   }
127   tiles.clear();
128  
129   lisp_object_t* root_obj = lisp_read_from_file(filename);
130
131   if (!root_obj)
132     st_abort("Couldn't load file", filename);
133
134   if (strcmp(lisp_symbol(lisp_car(root_obj)), "supertux-tiles") == 0)
135     {
136       lisp_object_t* cur = lisp_cdr(root_obj);
137       int tileset_id = 0;
138
139       while(!lisp_nil_p(cur))
140         {
141           lisp_object_t* element = lisp_car(cur);
142
143           if (strcmp(lisp_symbol(lisp_car(element)), "tile") == 0)
144             {
145               LispReader reader(lisp_cdr(element));
146
147               Tile* tile = new Tile;
148               int tile_id = tile->read(reader);
149               if(tile_id < 0) {
150                 std::cerr 
151                   << "Warning: parse error when reading a tile, skipping.\n";
152                 continue;
153               }
154
155               tile_id += tileset_id;
156
157               if(tile_id >= int(tiles.size()))
158                 tiles.resize(tile_id+1);
159               tiles[tile_id] = tile;
160             }
161           else if (strcmp(lisp_symbol(lisp_car(element)), "tileset") == 0)
162             {
163               LispReader reader(lisp_cdr(element));
164               std::string filename;
165               reader.read_string("file", filename);
166               filename = datadir + "/images/tilesets/" + filename;
167               load_tileset(filename);
168             }
169           else if (strcmp(lisp_symbol(lisp_car(element)), "tilegroup") == 0)
170             {
171               TileGroup new_;
172               LispReader reader(lisp_cdr(element));
173               reader.read_string("name", new_.name);
174               reader.read_int_vector("tiles", new_.tiles);            
175               if(!tilegroups_)
176                 tilegroups_ = new std::set<TileGroup>;
177               tilegroups_->insert(new_).first;
178             }
179           else if (strcmp(lisp_symbol(lisp_car(element)), "properties") == 0)
180             {
181               LispReader reader(lisp_cdr(element));
182               reader.read_int("id", tileset_id);
183               tileset_id *= 1000;
184             }
185           else
186             {
187               std::cerr << "Unknown symbol: " << 
188                 lisp_symbol(lisp_car(element)) << "\n";
189             }
190
191           cur = lisp_cdr(cur);
192         }
193     }
194   else
195     {
196       assert(0);
197     }
198
199   lisp_free(root_obj);
200   current_tileset = filename;
201 }
202
203 void
204 TileManager::draw_tile(DrawingContext& context, unsigned int c,
205     const Vector& pos, int layer)
206 {
207   if(c == 0)
208     return;
209
210   Tile* tile = get(c);
211   if(!tile)
212     return;
213
214   if(!tile->images.size())
215     return;
216
217   if(tile->images.size() > 1)
218   {
219     size_t frame 
220       = ((global_frame_counter*25) / tile->anim_speed) % tile->images.size();
221     context.draw_surface(tile->images[frame], pos, layer);
222   }
223   else if (tile->images.size() == 1)
224   {
225     context.draw_surface(tile->images[0], pos, layer);
226   }
227 }
228