6d981181d063dbe34a289307f6c48d152b42a313
[supertux.git] / src / worldmap.cpp
1 //  $Id$
2 //
3 //  Pingus - A free Lemmings clone
4 //  Copyright (C) 2002 Ingo Ruhnke <grumbel@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  02111-1307, USA.
19
20 #include <vector>
21 #include <assert.h>
22 #include "texture.h"
23 #include "screen.h"
24 #include "lispreader.h"
25 #include "worldmap.h"
26
27 namespace WorldMapNS {
28
29 TileManager* TileManager::instance_  = 0;
30
31 TileManager::TileManager()
32 {
33   lisp_stream_t stream;
34   FILE* in = fopen(DATA_PREFIX "images/worldmap/antarctica.scm", "r");
35   assert(in);
36   lisp_stream_init_file (&stream, in);
37   lisp_object_t* root_obj = lisp_read (&stream);
38   
39   if (strcmp(lisp_symbol(lisp_car(root_obj)), "supertux-worldmap-tiles") == 0)
40     {
41       lisp_object_t* cur = lisp_cdr(root_obj);
42
43       while(!lisp_nil_p(cur))
44         {
45           lisp_object_t* element = lisp_car(cur);
46
47           if (strcmp(lisp_symbol(lisp_car(element)), "tile") == 0)
48             {
49               int id = 0;
50               std::string filename = "<invalid>";
51
52               Tile* tile = new Tile;             
53               tile->north = true;
54               tile->east  = true;
55               tile->south = true;
56               tile->west  = true;
57               tile->stop  = true;
58   
59               LispReader reader(lisp_cdr(element));
60               reader.read_int("id",  &id);
61               reader.read_bool("north", &tile->north);
62               reader.read_bool("south", &tile->south);
63               reader.read_bool("west",  &tile->west);
64               reader.read_bool("east",  &tile->east);
65               reader.read_bool("stop",  &tile->stop);
66               reader.read_string("image",  &filename);
67
68               texture_load(&tile->sprite, 
69                            const_cast<char*>((std::string(DATA_PREFIX "/images/worldmap/") + filename).c_str()), 
70                            USE_ALPHA);
71
72               if (id >= tiles.size())
73                 tiles.resize(id+1);
74
75               tiles[id] = tile;
76             }
77           else
78             {
79               puts("Unhandled symbol");
80             }
81
82           cur = lisp_cdr(cur);
83         }
84     }
85   else
86     {
87       assert(0);
88     }
89 }
90
91 Tile*
92 TileManager::get(int i)
93 {
94   assert(i >=0 && i < tiles.size());
95   return tiles[i];
96 }
97
98 WorldMap::WorldMap()
99 {
100   quit = false;
101   width  = 20;
102   height = 15;
103   tux_moving = false;
104
105   texture_load(&tux_sprite, DATA_PREFIX "/images/worldmap/tux.png", USE_ALPHA);
106
107   tux_offset = 0;
108
109   tux_tile_pos.x = 0;
110   tux_tile_pos.y = 0;
111
112   input_direction = NONE;
113   tux_direction = NONE;
114   enter_level = false;
115
116   load_map();
117 }
118
119 WorldMap::~WorldMap()
120 {
121 }
122
123 void
124 WorldMap::load_map()
125 {
126   tilemap.resize(width * height);
127   
128   tilemap[0] = 5;
129   tilemap[1] = 1;
130   tilemap[2] = 6;
131   tilemap[3] = 1;
132   tilemap[4] = 3;
133   tilemap[4+20] = 2;
134   tilemap[4+40] = 7;
135   tilemap[4+60] = 2;
136   tilemap[4+80] = 4;
137 }
138
139 void
140 WorldMap::get_input()
141 {
142   SDL_Event event;
143
144   enter_level = false;
145
146   while (SDL_PollEvent(&event))
147     {
148       switch(event.type)
149         {
150         case SDL_QUIT:
151           quit = true;
152           break;
153           
154         case SDL_KEYDOWN:
155           switch(event.key.keysym.sym)
156             {
157             case SDLK_ESCAPE:
158               quit = true;
159               break;
160             case SDLK_LCTRL:
161             case SDLK_RETURN:
162               if (!tux_moving)
163                 enter_level = true;
164               break;
165             }
166           break;
167         }
168     }
169
170   Uint8 *keystate = SDL_GetKeyState(NULL);
171   
172   input_direction = NONE;
173   
174   if (keystate[SDLK_LEFT])
175     input_direction = WEST;
176   else if (keystate[SDLK_RIGHT])
177     input_direction = EAST;
178   else if (keystate[SDLK_UP])
179     input_direction = NORTH;
180   else if (keystate[SDLK_DOWN])
181     input_direction = SOUTH;
182 }
183
184 void
185 WorldMap::update()
186 {
187   float speed = 4.5;
188
189   if (enter_level)
190     {
191       puts("Enter the current level");
192     }
193   else
194     {
195       if (!tux_moving)
196         {
197           // FIXME: Cleanup, seperate tux
198           switch(input_direction)
199             {
200             case WEST:
201               if (at(tux_tile_pos)->west)
202                 {
203                   tux_tile_pos.x -= 1;
204                   tux_moving = true;
205                   tux_direction = input_direction;
206                 }
207               break;
208             case EAST:
209               if (at(tux_tile_pos)->east)
210                 {
211                   tux_tile_pos.x += 1;
212                   tux_moving = true;
213                   tux_direction = input_direction;
214                 }
215               break;
216             case NORTH:
217               if (at(tux_tile_pos)->north)
218                 {
219                   tux_tile_pos.y -= 1;
220                   tux_moving = true;
221                   tux_direction = input_direction;
222                 }
223               break;
224             case SOUTH:
225               if (at(tux_tile_pos)->south)
226                 {
227                   tux_tile_pos.y += 1;
228                   tux_moving = true;
229                   tux_direction = input_direction;
230                 }
231               break;
232             case NONE:
233               tux_moving = false;
234               tux_offset = 0;
235               tux_direction = input_direction;
236               break;
237             }
238         }
239       else
240         {
241           tux_offset += speed;
242
243           if (tux_offset > 32)
244             {
245               tux_offset -= 32;
246
247               if (at(tux_tile_pos)->stop)
248                 {
249                   tux_direction = NONE;
250                   tux_moving = false;
251                 }
252               else
253                 {
254                   // FIXME: Cleanup, seperate tux
255                   switch(tux_direction)
256                     {
257                     case WEST:
258                       if (at(tux_tile_pos)->west)
259                         tux_tile_pos.x -= 1;
260                       break;
261                     case EAST:
262                       if (at(tux_tile_pos)->east)
263                         tux_tile_pos.x += 1;
264                       break;
265                     case NORTH:
266                       if (at(tux_tile_pos)->north)
267                         tux_tile_pos.y -= 1;
268                       break;
269                     case SOUTH:
270                       if (at(tux_tile_pos)->south)
271                         tux_tile_pos.y += 1;
272                       break;
273                     }                      
274                 }
275             }
276         }
277     }
278 }
279
280 Tile*
281 WorldMap::at(Point p)
282 {
283   assert(p.x >= 0 
284          && p.x < width
285          && p.y >= 0
286          && p.y < height);
287   return TileManager::instance()->get(tilemap[width * p.y + p.x]);
288 }
289
290 void
291 WorldMap::draw()
292 {
293   for(int y = 0; y < height; ++y)
294     for(int x = 0; x < width; ++x)
295       {
296         Tile* tile = at(Point(x, y));
297         texture_draw(&tile->sprite, x*32, y*32, NO_UPDATE);
298       }
299
300   
301   float x = tux_tile_pos.x * 32;
302   float y = tux_tile_pos.y * 32;
303
304   switch(tux_direction)
305     {
306     case WEST:
307       x -= tux_offset - 32;
308       break;
309     case EAST:
310       x += tux_offset - 32;
311       break;
312     case NORTH:
313       y -= tux_offset - 32;
314       break;
315     case SOUTH:
316       y += tux_offset - 32;
317       break;
318     }
319
320   texture_draw(&tux_sprite, (int)x, (int)y, NO_UPDATE);
321   flipscreen();
322 }
323
324 void
325 WorldMap::display()
326 {
327   quit = false;
328
329   while(!quit) {
330     draw();
331     get_input();
332     update();
333     SDL_Delay(20);
334   }
335 }
336
337 } // namespace WorldMapNS
338
339 void worldmap_run()
340 {
341   WorldMapNS::WorldMap worldmap;
342   
343   worldmap.display();
344 }
345
346 /* EOF */