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