From: Matthias Braun Date: Sun, 28 Nov 2004 14:57:45 +0000 (+0000) Subject: move over rewritten lispreader from tuxkart (with additional fixes), generalized... X-Git-Url: https://git.verplant.org/?a=commitdiff_plain;h=ef57479f613b900b73eba8e8f4d026aae0de25cc;p=supertux.git move over rewritten lispreader from tuxkart (with additional fixes), generalized TileManager and Tile classes and use them for the worldmap too SVN-Revision: 2212 --- diff --git a/TODO b/TODO index 00e6b591d..d26e62463 100644 --- a/TODO +++ b/TODO @@ -68,7 +68,6 @@ L: low priority [L] rename gameloop.* files to gamesession.* [L] rename GameObject::action to GameObject::update() [L] use physfs for loading files -[L] eventually move over new lispreader code from tuxkart [L] change physics class y-velocity-coordinate to be like all other y-coordinates again (positive y to go down) [M] harmonize to 1 single gameloop that switches between title, worldmap, diff --git a/data/images/worldmap/antarctica.stwt b/data/images/worldmap/antarctica.stwt index 03152147c..e8dfdb9b5 100644 --- a/data/images/worldmap/antarctica.stwt +++ b/data/images/worldmap/antarctica.stwt @@ -2,59 +2,58 @@ ;; (tile (id INT) ;; (directions TOP RIGHT DOWN LEFT) ;; -(supertux-worldmap-tiles - +(supertux-tiles (tile (id 1) - (image "road_h.png") + (images "road_h.png") (north #f) (south #f) (west #t) (east #t) (stop #f)) (tile (id 2) - (image "road_v.png") + (images "road_v.png") (north #t) (south #t) (west #f) (east #f) (stop #f)) (tile (id 3) - (image "road_ws.png") + (images "road_ws.png") (north #f) (south #t) (west #t) (east #f) (stop #t)) (tile (id 4) - (image "road_cross.png") + (images "road_cross.png") (north #t) (south #t) (west #t) (east #t) (stop #t)) (tile (id 5) - (image "road_end.png") + (images "road_end.png") (north #f) (south #f) (west #f) (east #t) (stop #t)) (tile (id 6) - (image "road_h_stop.png") + (images "road_h_stop.png") (north #f) (south #f) (west #t) (east #t) (stop #t)) (tile (id 7) - (image "road_v_stop.png") + (images "road_v_stop.png") (north #t) (south #t) (west #f) (east #f) (stop #t)) (tile (id 8) - (image "ground.png") + (images "ground.png") (north #f) (south #f) (east #f) @@ -62,140 +61,142 @@ (stop #f)) (tile (id 9) - (image "water.png")) + (images "water.png")) (tile (id 11) - (image "snow1.png")) + (images "snow1.png")) (tile (id 12) - (image "snow2.png")) + (images "snow2.png")) (tile (id 13) - (image "snow3.png")) + (images "snow3.png")) (tile (id 14) - (image "snow4.png")) + (images "snow4.png")) (tile (id 15) - (image "snow5.png")) + (images "snow5.png")) (tile (id 16) - (image "snow6.png")) + (images "snow6.png")) (tile (id 17) - (image "snow7.png")) + (images "snow7.png")) (tile (id 18) - (image "snow8.png")) + (images "snow8.png")) (tile (id 19) - (image "snow9.png")) + (images "snow9.png")) (tile (id 20) - (image "snow10.png")) + (images "snow10.png")) (tile (id 21) - (image "snow11.png")) + (images "snow11.png")) (tile (id 22) - (image "snow12.png")) + (images "snow12.png")) (tile (id 23) - (image "snow13.png")) + (images "snow13.png")) (tile (id 24) - (image "wood1.png")) + (images "wood1.png")) (tile (id 25) - (image "wood2.png")) + (images "wood2.png")) (tile (id 26) - (image "wood3.png")) + (images "wood3.png")) (tile (id 27) - (image "wood4.png")) + (images "wood4.png")) (tile (id 28) - (image "wood5.png")) + (images "wood5.png")) (tile (id 29) - (image "wood6.png")) + (images "wood6.png")) (tile (id 30) - (image "wood7.png")) + (images "wood7.png")) (tile (id 31) - (image "wood8.png")) + (images "wood8.png")) (tile (id 32) - (image "wood9.png")) + (images "wood9.png")) (tile (id 33) - (image "wood10.png")) + (images "wood10.png")) (tile (id 34) - (image "wood11.png")) + (images "wood11.png")) (tile (id 35) - (image "wood12.png")) + (images "wood12.png")) (tile (id 36) - (image "wood13.png")) + (images "wood13.png")) (tile (id 37) - (image "road_ne.png") + (images "road_ne.png") (stop #f) - (auto-walk #t) (north #t) (south #f) (west #f) (east #t)) (tile (id 38) - (image "road_nsw.png") + (images "road_nsw.png") (north #t) (south #t) (west #t) - (east #f)) + (east #f) + (stop #t)) (tile (id 39) - (image "road_sw.png") + (images "road_sw.png") (stop #f) - (auto-walk #t) (north #f) (south #t) (west #t) (east #f)) (tile (id 40) - (image "road_we.png") + (images "road_we.png") (north #f) (south #f) (west #t) (east #t) (stop #f)) (tile (id 41) - (image "road_nes.png") + (images "road_nes.png") (north #t) (south #t) (west #f) - (east #t)) + (east #t) + (stop #t)) (tile (id 42) - (image "road_nw.png") + (images "road_nw.png") (stop #f) - (auto-walk #t) (north #t) (south #f) (west #t) (east #f)) (tile (id 43) - (image "road_swe.png") + (images "road_swe.png") (north #f) (south #t) (west #t) - (east #t)) + (east #t) + (stop #t)) (tile (id 44) - (image "road_new.png") + (images "road_new.png") (north #t) (south #f) (west #t) - (east #t)) + (east #t) + (stop #t)) (tile (id 45) - (image "road_nesw.png") + (images "road_nesw.png") (north #t) (south #t) (west #t) - (east #t)) + (east #t) + (stop #t)) (tile (id 46) - (image "road_nws.png") + (images "road_nws.png") (north #t) (south #t) (west #t) - (east #f)) + (east #f) + (stop #t)) (tile (id 47) - (image "road_ns.png") + (images "road_ns.png") (north #t) (south #t) (west #f) (east #f) (stop #f)) (tile (id 48) - (image "road_se.png") + (images "road_se.png") (stop #f) - (auto-walk #t) (north #f) (south #t) (west #f) @@ -203,58 +204,58 @@ ;; castle (tile (id 49) - (image "castle1.png") + (images "castle1.png") (north #f) (south #f) (west #f) (east #f)) (tile (id 50) - (image "castle2.png") + (images "castle2.png") (north #f) (south #f) (west #f) (east #f)) (tile (id 51) - (image "castle3.png") + (images "castle3.png") (north #f) (south #f) (west #f) (east #f)) (tile (id 52) - (image "castle4.png") + (images "castle4.png") (north #f) (south #f) (west #f) (east #f)) (tile (id 53) - (image "castle5.png") + (images "castle5.png") (north #f) (south #f) (west #f) (east #f)) (tile (id 54) - (image "castle6.png") + (images "castle6.png") (north #f) (south #f) (west #f) (east #f)) (tile (id 55) - (image "castle7.png") + (images "castle7.png") (north #f) (south #f) (west #f) (east #f)) (tile (id 56) - (image "castle8.png") + (images "castle8.png") (stop #t) (north #f) (south #f) (west #f) (east #t)) (tile (id 57) - (image "castle9.png") + (images "castle9.png") (stop #f) (north #f) (south #f) @@ -262,14 +263,14 @@ (east #t)) (tile (id 58) - (image "igloo1.png") + (images "igloo1.png") (stop #f) (north #f) (south #f) (west #f) (east #f)) (tile (id 59) - (image "igloo2.png") + (images "igloo2.png") (stop #t) (north #f) (south #t) @@ -277,7 +278,7 @@ (east #f)) (tile (id 60) - (image "snowman.png") + (images "snowman.png") (north #f) (south #t) (west #f) @@ -285,14 +286,14 @@ ;; Secret paths (tile (id 61) - (image "road_nws.png") + (images "road_nws.png") (north #t) (south #t) (west #t) (east #t)) (tile (id 62) - (image "snow5.png") + (images "snow5.png") (stop #f) (north #f) (south #f) @@ -300,7 +301,7 @@ (east #t)) (tile (id 63) - (image "water.png") + (images "water.png") (stop #f) (north #f) (south #f) @@ -308,7 +309,7 @@ (east #t)) (tile (id 64) - (image "snow7.png") + (images "snow7.png") (stop #f) (north #f) (south #f) @@ -317,7 +318,7 @@ ;;one-way vertical road (tile (id 65) - (image "road_ns.png") + (images "road_ns.png") (north #t) (south #t) (west #f) @@ -327,7 +328,7 @@ ;;one-way horizontal road (tile (id 66) - (image "road_we.png") + (images "road_we.png") (north #f) (south #f) (west #t) @@ -337,7 +338,7 @@ ;; Another invisible road (tile (id 67) - (image "snow9.png") + (images "snow9.png") (stop #t) (north #f) (south #f) @@ -346,7 +347,7 @@ ;; End of the line (tile (id 68) - (image "road_n.png") + (images "road_n.png") (stop #t) (north #t) (south #f) @@ -354,29 +355,26 @@ (east #f)) (tile (id 69) - (image "road_e.png") - (stop #t) + (images "road_e.png") + (stop #t) (north #f) (south #f) (west #f) (east #t)) (tile (id 70) - (image "road_s.png") - (stop #t) + (images "road_s.png") + (stop #t) (north #f) (south #t) (west #f) (east #f)) (tile (id 71) - (image "road_w.png") - (stop #t) + (images "road_w.png") + (stop #t) (north #f) (south #f) (west #t) (east #f)) - - ) -;; EOF ;; diff --git a/data/levels/test/bonusblock.stl b/data/levels/test/bonusblock.stl index f8203cc0f..1a2687391 100644 --- a/data/levels/test/bonusblock.stl +++ b/data/levels/test/bonusblock.stl @@ -9,7 +9,7 @@ (gravity 10.000000) (background (image "arctis.jpg") (speed 0.5)) - (spawn-points + (spawnpoint (name "main") (x 100) (y 170) diff --git a/data/levels/test/foresttheme.stl b/data/levels/test/foresttheme.stl index e31d8c39e..e3e90bf36 100644 --- a/data/levels/test/foresttheme.stl +++ b/data/levels/test/foresttheme.stl @@ -9,12 +9,12 @@ (name "main") (gravity 10) (music "forest2.mod") - (spawn-points + (spawnpoint (name "main") (x 100) (y 100) ) - (spawn-points + (spawnpoint (name "main") (x 6381) (y 201) diff --git a/data/levels/test/noloktest.stl b/data/levels/test/noloktest.stl index 859c8bb84..4ee451ec8 100644 --- a/data/levels/test/noloktest.stl +++ b/data/levels/test/noloktest.stl @@ -11,7 +11,7 @@ (background (image "forest1.jpg") (speed 0.5)) (music "Mortimers_chipdisko.mod") - (spawn-points (name "main") (x 100) (y 100)) + (spawnpoint (name "main") (x 100) (y 100)) (nolok_01 (x 650) (y 512)) (tilemap (layer "background") @@ -48,7 +48,7 @@ (music "Mortimers_chipdisko.mod") (background (image "forest1.jpg") (speed 0.5)) - (spawn-points (name "main2") (x 100) (y 100)) + (spawnpoint (name "main2") (x 100) (y 100)) (secretarea (x 100) (y 100) (message "You found a secret area!")) (dispenser (x 700) (y 500) (badguy "snowball") (cycle 2)) (tilemap diff --git a/data/levels/test/sectors.stl b/data/levels/test/sectors.stl index 5ebefb1d4..fe437fb9c 100644 --- a/data/levels/test/sectors.stl +++ b/data/levels/test/sectors.stl @@ -10,7 +10,7 @@ (camera (mode "normal") ) - (spawn-points + (spawnpoint (name "main") (x 100) (y 170) @@ -90,7 +90,7 @@ (sector "main") (spawnpoint "main") ) - (spawn-points + (spawnpoint (name "main") (x 300) (y 170) diff --git a/data/levels/test/simple.stl b/data/levels/test/simple.stl index c78b5da72..a42a7cb41 100644 --- a/data/levels/test/simple.stl +++ b/data/levels/test/simple.stl @@ -12,7 +12,7 @@ (gravity 10.000000) (background (image "arctis.jpg") (speed 0.5)) - (spawn-points (name "main") (x 50) (y 200)) + (spawnpoint (name "main") (x 50) (y 200)) (tilemap (layer "background") (solid #f) diff --git a/lib/Jamfile b/lib/Jamfile index e38266a5c..07719c72f 100644 --- a/lib/Jamfile +++ b/lib/Jamfile @@ -8,6 +8,7 @@ sources = [ Wildcard special : *.cpp *.h ] [ Wildcard utils : *.cpp *.h ] [ Wildcard video : *.cpp *.h ] + [ Wildcard lisp : *.cpp *.h ] ; TRANSLATABLE_SOURCE += [ DoSourceGrist $(sources) ] ; diff --git a/lib/audio/sound_manager.cpp b/lib/audio/sound_manager.cpp index 283fbba2c..0243f241c 100644 --- a/lib/audio/sound_manager.cpp +++ b/lib/audio/sound_manager.cpp @@ -33,7 +33,8 @@ using namespace SuperTux; SoundManager* SoundManager::instance_ = 0; SoundManager::SoundManager() - : current_music(0), m_music_enabled(true) , m_sound_enabled(true) , audio_device(true) + : current_music(0), m_music_enabled(true) , m_sound_enabled(true), + audio_device(true) { } @@ -42,8 +43,7 @@ SoundManager::~SoundManager() if(audio_device) Mix_HaltMusic(); -sounds.clear(); -destroy_instance(); + sounds.clear(); } void @@ -184,7 +184,8 @@ SoundManager::enable_music(bool enable) if(m_music_enabled == false) { Mix_HaltMusic(); } else { - Mix_PlayMusic(current_music->music, -1); + if(current_music) + Mix_PlayMusic(current_music->music, -1); } } diff --git a/lib/lisp/lexer.cpp b/lib/lisp/lexer.cpp new file mode 100644 index 000000000..6b693f23d --- /dev/null +++ b/lib/lisp/lexer.cpp @@ -0,0 +1,221 @@ +// $Id$ +// +// Copyright (C) 2004 Matthias Braun +// code in this file based on lispreader from Mark Probst +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +#include + +#include +#include + +#include "lexer.h" + +namespace lisp +{ + +class EOFException +{ +}; + +Lexer::Lexer(std::istream& newstream) + : stream(newstream), eof(false), linenumber(0) +{ + try { + // trigger a refill of the buffer + c = 0; + bufend = c + 1; + nextChar(); + } catch(EOFException& e) { + } +} + +Lexer::~Lexer() +{ +} + +void +Lexer::nextChar() +{ + ++c; + if(c >= bufend) { + if(eof) + throw EOFException(); + std::streamsize n = stream.readsome(buffer, BUFFER_SIZE); + + c = buffer; + bufend = buffer + n; + + // the following is a hack that appends an additional ' ' at the end of + // the file to avoid problems when parsing symbols/elements and a sudden + // EOF. This is faster than relying on unget and IMO also nicer. + if(n == 0 || stream.eof()) { + eof = true; + *bufend = ' '; + ++bufend; + } + } +} + +Lexer::TokenType +Lexer::getNextToken() +{ + static const char* delims = "\"();"; + + try { + while(isspace(*c)) { + if(*c == '\n') + ++linenumber; + nextChar(); + }; + + token_length = 0; + + switch(*c) { + case ';': // comment + while(!stream.eof()) { + nextChar(); + if(*c == '\n') { + ++linenumber; + break; + } + } + return getNextToken(); // and again + case '(': + nextChar(); + return TOKEN_OPEN_PAREN; + case ')': + nextChar(); + return TOKEN_CLOSE_PAREN; + case '"': { // string + int startline = linenumber; + try { + while(1) { + if(stream.eof()) { + std::stringstream msg; + msg << "Parse Error in line " << startline << ": " + << "Couldn't find end of string."; + throw std::runtime_error(msg.str()); + } + nextChar(); + if(*c == '"') + break; + else if(*c == '\n') + linenumber++; + else if(*c == '\\') { + nextChar(); + switch(*c) { + case 'n': + *c = '\n'; + break; + case 't': + *c = '\t'; + break; + } + } + if(token_length < MAX_TOKEN_LENGTH) + token_string[token_length++] = *c; + } + token_string[token_length] = 0; + } catch(EOFException& ) { + std::stringstream msg; + msg << "Parse error in line " << startline << ": " + << "EOF while parsing string."; + throw std::runtime_error(msg.str()); + } + nextChar(); + return TOKEN_STRING; + } + case '#': // constant + try { + nextChar(); + + while(isalnum(*c) || *c == '_') { + if(token_length < MAX_TOKEN_LENGTH) + token_string[token_length++] = *c; + nextChar(); + } + token_string[token_length] = 0; + } catch(EOFException& ) { + std::stringstream msg; + msg << "Parse Error in line " << linenumber << ": " + << "EOF while parsing constant."; + throw std::runtime_error(msg.str()); + } + + if(strcmp(token_string, "t") == 0) + return TOKEN_TRUE; + if(strcmp(token_string, "f") == 0) + return TOKEN_FALSE; + + // we only handle #t and #f constants at the moment... + + { + std::stringstream msg; + msg << "Parse Error in line " << linenumber << ": " + << "Unknown constant '" << token_string << "'."; + throw std::runtime_error(msg.str()); + } + + default: + if(isdigit(*c) || *c == '-') { + bool have_nondigits = false; + bool have_digits = false; + int have_floating_point = 0; + + do { + if(isdigit(*c)) + have_digits = true; + else if(*c == '.') + ++have_floating_point; + else if(isalnum(*c) || *c == '_') + have_nondigits = true; + + if(token_length < MAX_TOKEN_LENGTH) + token_string[token_length++] = *c; + + nextChar(); + } while(!isspace(*c) && !strchr(delims, *c)); + + token_string[token_length] = 0; + + // no nextChar + + if(have_nondigits || !have_digits || have_floating_point > 1) + return TOKEN_SYMBOL; + else if(have_floating_point == 1) + return TOKEN_REAL; + else + return TOKEN_INTEGER; + } else { + do { + if(token_length < MAX_TOKEN_LENGTH) + token_string[token_length++] = *c; + nextChar(); + } while(!isspace(*c) && !strchr(delims, *c)); + token_string[token_length] = 0; + + // no nextChar + + return TOKEN_SYMBOL; + } + } + } catch(EOFException& ) { + return TOKEN_EOF; + } +} + +} // end of namespace lisp + diff --git a/lib/lisp/lexer.h b/lib/lisp/lexer.h new file mode 100644 index 000000000..5a2bc5948 --- /dev/null +++ b/lib/lisp/lexer.h @@ -0,0 +1,70 @@ +// $Id$ +// +// Copyright (C) 2004 Matthias Braun +// code in this file based on lispreader from Mark Probst +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +#ifndef __LISPLEXER_H__ +#define __LISPLEXER_H__ + +namespace lisp +{ + +class Lexer +{ +public: + enum TokenType { + TOKEN_EOF, + TOKEN_OPEN_PAREN, + TOKEN_CLOSE_PAREN, + TOKEN_SYMBOL, + TOKEN_STRING, + TOKEN_INTEGER, + TOKEN_REAL, + TOKEN_TRUE, + TOKEN_FALSE + }; + + Lexer(std::istream& stream); + ~Lexer(); + + TokenType getNextToken(); + const char* getString() const + { return token_string; } + int getLineNumber() const + { return linenumber; } + +private: + enum { + MAX_TOKEN_LENGTH = 16384, + BUFFER_SIZE = 1024 + }; + + inline void nextChar(); + + std::istream& stream; + bool eof; + int linenumber; + char buffer[BUFFER_SIZE+1]; + char* bufend; + char* c; + char token_string[MAX_TOKEN_LENGTH + 1]; + int token_length; +}; + +} // end of namespace lisp + +#endif + diff --git a/lib/lisp/lisp.cpp b/lib/lisp/lisp.cpp new file mode 100644 index 000000000..aa7bca963 --- /dev/null +++ b/lib/lisp/lisp.cpp @@ -0,0 +1,99 @@ +// $Id$ +// +// TuxKart - a fun racing game with go-kart +// Copyright (C) 2004 Matthias Braun +// code in this file based on lispreader from Mark Probst +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +#include + +#include "lisp.h" + +namespace lisp +{ + +Lisp::Lisp(LispType newtype) + : type(newtype) +{ +} + +Lisp::~Lisp() +{ + if(type == TYPE_SYMBOL || type == TYPE_STRING) + delete[] v.string; + if(type == TYPE_CONS) { + delete v.cons.cdr; + delete v.cons.car; + } +} + +Lisp* +Lisp::get_lisp(const char* name) const +{ + for(const Lisp* p = this; p != 0; p = p->get_cdr()) { + Lisp* child = p->get_car(); + if(!child || child->get_type() != TYPE_CONS) + continue; + Lisp* childname = child->get_car(); + if(!childname) + continue; + std::string childName; + if(!childname->get(childName)) + continue; + if(childName == name) { + return child->get_cdr(); + } + } + + return 0; +} + +void +Lisp::print(int indent) const +{ + for(int i = 0; i < indent; ++i) + printf(" "); + + if(type == TYPE_CONS) { + printf("(\n"); + const Lisp* lisp = this; + while(lisp) { + if(lisp->v.cons.car) + lisp->v.cons.car->print(indent + 1); + lisp = lisp->v.cons.cdr; + } + for(int i = 0; i < indent; ++i) + printf(" "); + printf(")"); + } + if(type == TYPE_STRING) { + printf("'%s' ", v.string); + } + if(type == TYPE_INTEGER) { + printf("%d", v.integer); + } + if(type == TYPE_REAL) { + printf("%f", v.real); + } + if(type == TYPE_SYMBOL) { + printf("%s ", v.string); + } + if(type == TYPE_BOOLEAN) { + printf("%s ", v.boolean ? "true" : "false"); + } + printf("\n"); +} + +} // end of namespace lisp diff --git a/lib/lisp/lisp.h b/lib/lisp/lisp.h new file mode 100644 index 000000000..e118298ff --- /dev/null +++ b/lib/lisp/lisp.h @@ -0,0 +1,165 @@ +// $Id$ +// +// TuxKart - a fun racing game with go-kart +// Copyright (C) 2004 Matthias Braun +// code in this file based on lispreader from Mark Probst +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +#ifndef __LISPREADER_H__ +#define __LISPREADER_H__ + +#include +#include + +namespace lisp +{ + +class Lisp +{ +public: + ~Lisp(); + + enum LispType { + TYPE_CONS, + TYPE_SYMBOL, + TYPE_INTEGER, + TYPE_STRING, + TYPE_REAL, + TYPE_BOOLEAN + }; + + LispType get_type() const + { return type; } + + Lisp* get_car() const + { return v.cons.car; } + Lisp* get_cdr() const + { return v.cons.cdr; } + bool get(std::string& val) const + { + if(type != TYPE_STRING && type != TYPE_SYMBOL) + return false; + val = v.string; + return true; + } + bool get(unsigned int& val) const + { + if(type != TYPE_INTEGER) + return false; + val = v.integer; + return true; + } + bool get(int& val) const + { + if(type != TYPE_INTEGER) + return false; + val = v.integer; + return true; + } + bool get(float& val) const + { + if(type != TYPE_REAL) { + if(type == TYPE_INTEGER) { + val = v.integer; + return true; + } + return false; + } + val = v.real; + return true; + } + bool get(bool& val) const + { + if(type != TYPE_BOOLEAN) + return false; + val = v.boolean; + return true; + } + + /* conveniance functions which traverse the list until a child with a + * specified name is found. The value part is then interpreted in a specific + * way. The functions return true, if a child was found and could be + * interpreted correctly, otherwise false is returned and the variable value + * is not changed. + * (Please note that searching the lisp structure is O(n) so these functions + * are no good idea for performance critical areas) + */ + template + bool get(const char* name, T& val) const + { + const Lisp* lisp = get_lisp(name); + if(!lisp) + return false; + + if(lisp->get_type() != TYPE_CONS) + return false; + lisp = lisp->get_car(); + if(!lisp) + return false; + return lisp->get(val); + } + + template + bool get_vector(const char* name, std::vector& vec) const + { + vec.clear(); + + const Lisp* child = get_lisp(name); + if(!child) + return false; + + for( ; child != 0; child = child->get_cdr()) { + T val; + if(!child->get_car()) + continue; + if(child->get_car()->get(val)) { + vec.push_back(val); + } + } + + return true; + } + + Lisp* get_lisp(const char* name) const; + Lisp* get_lisp(const std::string& name) const + { return get_lisp(name.c_str()); } + + // for debugging + void print(int indent = 0) const; + +private: + friend class Parser; + Lisp(LispType newtype); + + LispType type; + union + { + struct + { + Lisp* car; + Lisp* cdr; + } cons; + + char* string; + int integer; + bool boolean; + float real; + } v; +}; + +} // end of namespace lisp + +#endif + diff --git a/lib/lisp/list_iterator.cpp b/lib/lisp/list_iterator.cpp new file mode 100644 index 000000000..8029f2a7a --- /dev/null +++ b/lib/lisp/list_iterator.cpp @@ -0,0 +1,35 @@ +#include + +#include "list_iterator.h" +#include + +namespace lisp +{ + +ListIterator::ListIterator(const lisp::Lisp* newlisp) + : current_lisp(0), cur(newlisp) +{ +} + +bool +ListIterator::next() +{ + if(cur == 0) + return false; + + const lisp::Lisp* child = cur->get_car(); + if(!child) + throw new std::runtime_error("child is 0 in list entry"); + if(child->get_type() != lisp::Lisp::TYPE_CONS) + throw new std::runtime_error("Expected CONS"); + const lisp::Lisp* name = child->get_car(); + if(!name || name->get_type() != lisp::Lisp::TYPE_SYMBOL) + throw new std::runtime_error("Expected symbol"); + name->get(current_item); + current_lisp = child->get_cdr(); + + cur = cur->get_cdr(); + return true; +} + +} diff --git a/lib/lisp/list_iterator.h b/lib/lisp/list_iterator.h new file mode 100644 index 000000000..b7f051dce --- /dev/null +++ b/lib/lisp/list_iterator.h @@ -0,0 +1,35 @@ +#ifndef __LISP_ITERATOR_H__ +#define __LISP_ITERATOR_H__ + +#include "lisp/lisp.h" + +namespace lisp +{ + +/** + * Small and a bit hacky helper class that helps parsing lisp lists where all + * entries are lists again themselves + */ +class ListIterator +{ +public: + ListIterator(const lisp::Lisp* cur); + + const std::string& item() const + { return current_item; } + lisp::Lisp* lisp() const + { return current_lisp; } + lisp::Lisp* value() const + { return current_lisp->get_car(); } + bool next(); + +private: + std::string current_item; + lisp::Lisp* current_lisp; + const lisp::Lisp* cur; +}; + +} + +#endif + diff --git a/lib/lisp/parser.cpp b/lib/lisp/parser.cpp new file mode 100644 index 000000000..34f5f8343 --- /dev/null +++ b/lib/lisp/parser.cpp @@ -0,0 +1,151 @@ +// $Id$ +// +// TuxKart - a fun racing game with go-kart +// Copyright (C) 2004 Matthias Braun +// code in this file based on lispreader from Mark Probst +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +#include + +#include +#include +#include + +#include "parser.h" +#include "lisp.h" + +namespace lisp +{ + +Parser::Parser() + : lexer(0) +{ +} + +Parser::~Parser() +{ + delete lexer; +} + +Lisp* +Parser::parse(const std::string& filename) +{ + std::ifstream in(filename.c_str()); + if(!in.good()) { + std::stringstream msg; + msg << "Parser problem: Couldn't open file '" << filename << "'."; + throw std::runtime_error(msg.str()); + } + return parse(in); +} + +Lisp* +Parser::parse(std::istream& stream) +{ + delete lexer; + lexer = new Lexer(stream); + + token = lexer->getNextToken(); + Lisp* result = new Lisp(Lisp::TYPE_CONS); + result->v.cons.car = read(); + result->v.cons.cdr = 0; + + delete lexer; + lexer = 0; + + return result; +} + +Lisp* +Parser::read() +{ + Lisp* result; + switch(token) { + case Lexer::TOKEN_EOF: { + std::stringstream msg; + msg << "Parse Error at line " << lexer->getLineNumber() << ": " + << "Unexpected EOF."; + throw std::runtime_error(msg.str()); + } + case Lexer::TOKEN_CLOSE_PAREN: { + std::stringstream msg; + msg << "Parse Error at line " << lexer->getLineNumber() << ": " + << "Unexpected ')'."; + throw std::runtime_error(msg.str()); + } + case Lexer::TOKEN_OPEN_PAREN: { + result = new Lisp(Lisp::TYPE_CONS); + + token = lexer->getNextToken(); + if(token == Lexer::TOKEN_CLOSE_PAREN) { + result->v.cons.car = 0; + result->v.cons.cdr = 0; + break; + } + + Lisp* cur = result; + do { + cur->v.cons.car = read(); + if(token == Lexer::TOKEN_CLOSE_PAREN) { + cur->v.cons.cdr = 0; + break; + } + cur->v.cons.cdr = new Lisp(Lisp::TYPE_CONS); + cur = cur->v.cons.cdr; + } while(1); + + break; + } + case Lexer::TOKEN_SYMBOL: { + result = new Lisp(Lisp::TYPE_SYMBOL); + size_t len = strlen(lexer->getString()) + 1; + result->v.string = new char[len]; + memcpy(result->v.string, lexer->getString(), len); + break; + } + case Lexer::TOKEN_STRING: { + result = new Lisp(Lisp::TYPE_STRING); + size_t len = strlen(lexer->getString()) + 1; + result->v.string = new char[len]; + memcpy(result->v.string, lexer->getString(), len); + break; + } + case Lexer::TOKEN_INTEGER: + result = new Lisp(Lisp::TYPE_INTEGER); + sscanf(lexer->getString(), "%d", &result->v.integer); + break; + case Lexer::TOKEN_REAL: + result = new Lisp(Lisp::TYPE_REAL); + sscanf(lexer->getString(), "%f", &result->v.real); + break; + case Lexer::TOKEN_TRUE: + result = new Lisp(Lisp::TYPE_BOOLEAN); + result->v.boolean = true; + break; + case Lexer::TOKEN_FALSE: + result = new Lisp(Lisp::TYPE_BOOLEAN); + result->v.boolean = false; + break; + + default: + // this should never happen + assert(false); + } + + token = lexer->getNextToken(); + return result; +} + +} // end of namespace lisp diff --git a/lib/lisp/parser.h b/lib/lisp/parser.h new file mode 100644 index 000000000..726648e04 --- /dev/null +++ b/lib/lisp/parser.h @@ -0,0 +1,50 @@ +// $Id$ +// +// TuxKart - a fun racing game with go-kart +// Copyright (C) 2004 Matthias Braun +// code in this file based on lispreader from Mark Probst +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +#ifndef __LISPPARSER_H__ +#define __LISPPARSER_H__ + +#include +#include "lexer.h" + +namespace lisp +{ + +class Lisp; + +class Parser +{ +public: + Parser(); + ~Parser(); + + Lisp* parse(const std::string& filename); + Lisp* parse(std::istream& stream); + +private: + Lisp* read(); + + Lexer* lexer; + Lexer::TokenType token; +}; + +} // end of namespace lisp + +#endif + diff --git a/lib/lisp/writer.cpp b/lib/lisp/writer.cpp new file mode 100644 index 000000000..a8c5c2443 --- /dev/null +++ b/lib/lisp/writer.cpp @@ -0,0 +1,134 @@ +// $Id$ +// +// SuperTux - A Jump'n Run +// Copyright (C) 2004 Matthias Braun + +#include + +#include "writer.h" + +namespace lisp +{ + +Writer::Writer(std::ostream& newout) + : out(newout), indent_depth(0) +{ +} + +Writer::~Writer() +{ + if(lists.size() > 0) { + std::cerr << "Warning: Not all sections closed in lispwriter!\n"; + } +} + +void +Writer::write_comment(const std::string& comment) +{ + out << "; " << comment << "\n"; +} + +void +Writer::start_list(const std::string& listname) +{ + indent(); + out << '(' << listname << '\n'; + indent_depth += 2; + + lists.push_back(listname); +} + +void +Writer::end_list(const std::string& listname) +{ + if(lists.size() == 0) { + std::cerr << "Trying to close list '" << listname + << "', which is not open.\n"; + return; + } + if(lists.back() != listname) { + std::cerr << "Warning: trying to close list '" << listname + << "' while list '" << lists.back() << "' is open.\n"; + return; + } + lists.pop_back(); + + indent_depth -= 2; + indent(); + out << ")\n"; +} + +void +Writer::write_int(const std::string& name, int value) +{ + indent(); + out << '(' << name << ' ' << value << ")\n"; +} + +void +Writer::write_float(const std::string& name, float value) +{ + indent(); + out << '(' << name << ' ' << value << ")\n"; +} + +void +Writer::write_string(const std::string& name, const std::string& value) +{ + indent(); + out << '(' << name << " \"" << value << "\")\n"; +} + +void +Writer::write_bool(const std::string& name, bool value) +{ + indent(); + out << '(' << name << ' ' << (value ? "#t" : "#f") << ")\n"; +} + +void +Writer::write_int_vector(const std::string& name, + const std::vector& value) +{ + indent(); + out << '(' << name; + for(std::vector::const_iterator i = value.begin(); i != value.end(); ++i) + out << " " << *i; + out << ")\n"; +} + +void +Writer::write_int_vector(const std::string& name, + const std::vector& value) +{ + indent(); + out << '(' << name; + for(std::vector::const_iterator i = value.begin(); i != value.end(); ++i) + out << " " << *i; + out << ")\n"; +} + +void +Writer::indent() +{ + for(int i = 0; i +#include +#include + +namespace lisp +{ + + class Writer + { + public: + Writer(std::ostream& out); + ~Writer(); + + void write_comment(const std::string& comment); + + void start_list(const std::string& listname); + + void write_int(const std::string& name, int value); + void write_float(const std::string& name, float value); + void write_string(const std::string& name, const std::string& value); + void write_bool(const std::string& name, bool value); + void write_int_vector(const std::string& name, const std::vector& value); + void write_int_vector(const std::string& name, const std::vector& value); + // add more write-functions when needed... + + void end_list(const std::string& listname); + + private: + void indent(); + + std::ostream& out; + int indent_depth; + std::vector lists; + }; + +} //namespace lisp + +#endif //SUPERTUX_LISPWRITER_H + diff --git a/lib/special/sprite.h b/lib/special/sprite.h index 6d0ed7bac..e8b8d8525 100644 --- a/lib/special/sprite.h +++ b/lib/special/sprite.h @@ -25,7 +25,6 @@ #include #include -#include "utils/lispreader.h" #include "video/surface.h" #include "math/vector.h" #include "sprite_data.h" diff --git a/lib/special/sprite_data.cpp b/lib/special/sprite_data.cpp index 197b7c52b..252fbf8ff 100644 --- a/lib/special/sprite_data.cpp +++ b/lib/special/sprite_data.cpp @@ -27,6 +27,7 @@ #include "app/globals.h" #include "app/setup.h" #include "video/drawing_context.h" +#include "lisp/list_iterator.h" namespace SuperTux { @@ -46,21 +47,18 @@ SpriteData::Action::~Action() delete *i; } -SpriteData::SpriteData(lisp_object_t* cur) +SpriteData::SpriteData(const lisp::Lisp* lisp) { - for(; !lisp_nil_p(cur); cur = lisp_cdr(cur)) { - std::string token = lisp_symbol(lisp_car(lisp_car(cur))); - lisp_object_t* data = lisp_car(lisp_cdr(lisp_car(cur))); - LispReader reader(lisp_cdr(lisp_car(cur))); - - if(token == "name") - name = lisp_string(data); - else if(token == "action") - parse_action(reader); - else - std::cerr << "Warning: Unknown sprite field: " << token << std::endl; + lisp::ListIterator iter(lisp); + while(iter.next()) { + if(iter.item() == "name") { + iter.value()->get(name); + } else if(iter.item() == "action") { + parse_action(iter.lisp()); + } else { + std::cerr << "Unknown sprite field: " << iter.item() << "\n"; + } } - if(name.empty()) throw std::runtime_error("Error: Sprite wihtout name."); if(actions.empty()) @@ -74,21 +72,22 @@ SpriteData::~SpriteData() } void -SpriteData::parse_action(LispReader& lispreader) +SpriteData::parse_action(const lisp::Lisp* lisp) { Action* action = new Action; - if(!lispreader.read_string("name", action->name)) { + if(!lisp->get("name", action->name)) { if(!actions.empty()) throw std::runtime_error( "If there are more than one action, they need names!"); } - lispreader.read_int("x-offset", action->x_offset); - lispreader.read_int("y-offset", action->y_offset); - lispreader.read_int("z-order", action->z_order); - lispreader.read_float("fps", action->fps); + lisp->get("x-offset", action->x_offset); + lisp->get("y-offset", action->y_offset); + lisp->get("z-order", action->z_order); + lisp->get("fps", action->fps); - /* TODO: add a top filter entry */ + // this doesn't seem to be used and implemented +#if 0 std::vector mask_color; lispreader.read_int_vector("apply-mask", mask_color); if(mask_color.size() == 4) { @@ -97,9 +96,10 @@ SpriteData::parse_action(LispReader& lispreader) (*i)->apply_filter(MASK_FILTER, Color(mask_color)); } } +#endif std::string mirror_action; - lispreader.read_string("mirror-action", mirror_action); + lisp->get("mirror-action", mirror_action); if(!mirror_action.empty()) { Action* act_tmp = get_action(mirror_action); if(act_tmp == NULL) { @@ -116,7 +116,7 @@ SpriteData::parse_action(LispReader& lispreader) } } else { // Load images std::vector images; - if(!lispreader.read_string_vector("images", images)) { + if(!lisp->get_vector("images", images)) { std::stringstream msg; msg << "Sprite '" << name << "' contains no images in action '" << action->name << "'."; diff --git a/lib/special/sprite_data.h b/lib/special/sprite_data.h index 55d747311..1d0e167eb 100644 --- a/lib/special/sprite_data.h +++ b/lib/special/sprite_data.h @@ -24,7 +24,7 @@ #include #include -#include "utils/lispreader.h" +#include "lisp/lisp.h" #include "video/surface.h" namespace SuperTux @@ -35,7 +35,7 @@ namespace SuperTux public: /** cur has to be a pointer to data in the form of ((x-offset 5) (y-offset 10) ...) */ - SpriteData(lisp_object_t* cur); + SpriteData(const lisp::Lisp* cur); ~SpriteData(); const std::string& get_name() const @@ -72,7 +72,7 @@ namespace SuperTux typedef std::map Actions; Actions actions; - void parse_action(LispReader& lispreader); + void parse_action(const lisp::Lisp* lispreader); /** Get an action */ Action* get_action(std::string act); diff --git a/lib/special/sprite_manager.cpp b/lib/special/sprite_manager.cpp index 8c9ee8139..38bb6594d 100644 --- a/lib/special/sprite_manager.cpp +++ b/lib/special/sprite_manager.cpp @@ -22,10 +22,12 @@ #include #include -#include "utils/lispreader.h" #include "sprite_manager.h" #include "sprite_data.h" #include "sprite.h" +#include "lisp/lisp.h" +#include "lisp/parser.h" +#include "lisp/list_iterator.h" namespace SuperTux { @@ -45,42 +47,39 @@ SpriteManager::~SpriteManager() void SpriteManager::load_resfile(const std::string& filename) { - lisp_object_t* root_obj = lisp_read_from_file(filename); - if (!root_obj) - { - std::cout << "SpriteManager: Couldn't load: " << filename << std::endl; - return; - } - - lisp_object_t* cur = root_obj; - - if (strcmp(lisp_symbol(lisp_car(cur)), "supertux-resources") != 0) - return; - cur = lisp_cdr(cur); - - while(cur) { - lisp_object_t* el = lisp_car(cur); - - if (strcmp(lisp_symbol(lisp_car(el)), "sprite") == 0) { - SpriteData* spritedata = new SpriteData(lisp_cdr(el)); - - Sprites::iterator i = sprites.find(spritedata->get_name()); - if (i == sprites.end()) { - sprites[spritedata->get_name()] = spritedata; + lisp::Parser parser; + try { + std::auto_ptr root (parser.parse(filename)); + + const lisp::Lisp* resources = root->get_lisp("supertux-resources"); + if(!resources) + throw std::runtime_error("file is not a supertux-resources files"); + + lisp::ListIterator iter(resources); + while(iter.next()) { + if(iter.item() == "sprite") { + SpriteData* spritedata = new SpriteData(iter.lisp()); + + printf("Spr: %s.\n", spritedata->get_name().c_str()); + Sprites::iterator i = sprites.find(spritedata->get_name()); + if (i == sprites.end()) { + sprites[spritedata->get_name()] = spritedata; + } else { + delete i->second; + i->second = spritedata; + std::cout << "Warning: dulpicate entry: '" << spritedata->get_name() + << "' in spritefile." << std::endl; + } } else { - delete i->second; - i->second = spritedata; - std::cout << "Warning: dulpicate entry: '" << spritedata->get_name() - << "' in spritefile." << std::endl; + std::cout << "SpriteManager: Unknown tag '" << iter.item() + << "' in spritefile.\n"; } - } else { - std::cout << "SpriteManager: Unknown tag in spritefile.\n"; } - - cur = lisp_cdr(cur); + } catch(std::exception& e) { + std::stringstream msg; + msg << "Couldn't load file '" << filename << "': " << e.what() << "\n"; + throw std::runtime_error(msg.str()); } - - lisp_free(root_obj); } Sprite* diff --git a/lib/utils/configfile.cpp b/lib/utils/configfile.cpp index aa8cb401c..ebf9e3bcd 100644 --- a/lib/utils/configfile.cpp +++ b/lib/utils/configfile.cpp @@ -21,11 +21,13 @@ #include #include +#include #include "configfile.h" #include "app/setup.h" #include "app/globals.h" #include "audio/sound_manager.h" +#include "lisp/parser.h" using namespace SuperTux; @@ -76,64 +78,49 @@ FILE * SuperTux::opendata(const std::string& rel_filename, const char *mode) void Config::load() { - FILE * file = NULL; - defaults(); - /* override defaults from config file */ - - file = opendata(config_filename, "r"); - - if (file == NULL) - return; - - /* read config file */ - - lisp_stream_t stream; - lisp_object_t * root_obj = NULL; - - lisp_stream_init_file (&stream, file); - root_obj = lisp_read (&stream); - - if (root_obj->type == LISP_TYPE_EOF || root_obj->type == LISP_TYPE_PARSE_ERROR) - return; - - if (strcmp(lisp_symbol(lisp_car(root_obj)), (package_symbol_name+"-config").c_str()) != 0) - return; - - LispReader reader(lisp_cdr(root_obj)); - - reader.read_bool("fullscreen", use_fullscreen); - bool temp; - reader.read_bool("sound", temp); - SoundManager::get()->enable_sound(temp); - reader.read_bool("music", temp); - SoundManager::get()->enable_music(temp); - reader.read_bool("show_fps", show_fps); - - std::string video; - reader.read_string ("video", video); - if (video == "opengl") - use_gl = true; - else - use_gl = false; - - reader.read_int ("joystick", joystick_num); - - if (joystick_num >= 0) - { - reader.read_int ("joystick-x", joystick_keymap.x_axis); - reader.read_int ("joystick-y", joystick_keymap.y_axis); - reader.read_int ("joystick-a", joystick_keymap.a_button); - reader.read_int ("joystick-b", joystick_keymap.b_button); - reader.read_int ("joystick-start", joystick_keymap.start_button); - reader.read_int ("joystick-deadzone", joystick_keymap.dead_zone); + lisp::Parser parser; + try { + std::auto_ptr root (parser.parse(st_dir + config_filename)); + + const lisp::Lisp* config_lisp = root->get_lisp( + package_symbol_name + "-config"); + if(!config_lisp) + throw new std::runtime_error("Config file is not a supertux-config file"); + + config_lisp->get("fullscreen", use_fullscreen); + bool temp = false; + if(config_lisp->get("sound", temp)) + SoundManager::get()->enable_sound(temp); + if(config_lisp->get("music", temp)) + SoundManager::get()->enable_music(temp); + config_lisp->get("show_fps", show_fps); + + std::string video; + if(config_lisp->get("video", video)) { + if (video == "opengl") + use_gl = true; + else + use_gl = false; } - customload(reader); + joystick_num = 0; + config_lisp->get("joystick", joystick_num); + + if (joystick_num >= 0) { + config_lisp->get("joystick-x", joystick_keymap.x_axis); + config_lisp->get("joystick-y", joystick_keymap.y_axis); + config_lisp->get("joystick-a", joystick_keymap.a_button); + config_lisp->get("joystick-b", joystick_keymap.b_button); + config_lisp->get("joystick-start", joystick_keymap.start_button); + config_lisp->get("joystick-deadzone", joystick_keymap.dead_zone); + } - lisp_free(root_obj); - fclose(file); + customload(config_lisp); + } catch(std::exception& e) { + std::cerr << "Couldn't load configfile: " << e.what() << "\n"; + } } void Config::save () @@ -173,4 +160,3 @@ void Config::save () } } -/* EOF */ diff --git a/lib/utils/configfile.h b/lib/utils/configfile.h index 6620bcb7b..5c2de647c 100644 --- a/lib/utils/configfile.h +++ b/lib/utils/configfile.h @@ -20,7 +20,7 @@ #ifndef SUPERTUX_CONFIGFILE_H #define SUPERTUX_CONFIGFILE_H -#include "lispreader.h" +#include "lisp/lisp.h" namespace SuperTux { @@ -30,7 +30,7 @@ class Config { public: void load (); void save (); - virtual void customload(LispReader& ) + virtual void customload(const lisp::Lisp* ) {}; virtual void customsave(FILE* ) {}; diff --git a/lib/video/font.cpp b/lib/video/font.cpp index 78cfd39ab..303193b02 100644 --- a/lib/video/font.cpp +++ b/lib/video/font.cpp @@ -22,12 +22,14 @@ #include #include +#include #include "app/globals.h" +#include "lisp/parser.h" +#include "lisp/lisp.h" #include "screen.h" #include "font.h" #include "drawing_context.h" -#include "utils/lispreader.h" using namespace SuperTux; @@ -202,23 +204,30 @@ Font::draw_chars(Surface* pchars, const std::string& text, const Vector& pos, #define SCROLL 60 #define ITEMS_SPACE 4 -void SuperTux::display_text_file(const std::string& file, float scroll_speed, Font* heading_font, Font* normal_font, Font* small_font, Font* reference_font ) +void SuperTux::display_text_file(const std::string& file, float scroll_speed, + Font* heading_font, Font* normal_font, Font* small_font, + Font* reference_font) { std::string text; + std::string background_file; std::vector names; - LispReader* reader = LispReader::load(datadir + "/" + file, "supertux-text"); + std::string filename = datadir + "/" + file; + lisp::Parser parser; + try { + std::auto_ptr root (parser.parse(filename)); - if(!reader) - { - std::cerr << "Error: Could not open text. Ignoring...\n"; + const lisp::Lisp* text_lisp = root->get_lisp("supertux-text"); + if(!text_lisp) + throw std::runtime_error("File isn't a supertux-text file"); + + if(!text_lisp->get("text", text)) + throw std::runtime_error("file doesn't contain a text field"); + } catch(std::exception& e) { + std::cerr << "Couldn't load file '" << filename << "': " << e.what() << + "\n"; return; - } - - reader->read_string("text", text, true); - std::string background_file; - reader->read_string("background", background_file, true); - delete reader; + } // Split text string lines into a vector names.clear(); diff --git a/src/badguy/badguy.h b/src/badguy/badguy.h index 68cdb57ed..cddb825ff 100644 --- a/src/badguy/badguy.h +++ b/src/badguy/badguy.h @@ -11,8 +11,9 @@ #include "serializable.h" #include "resources.h" #include "sector.h" -#include "utils/lispwriter.h" -#include "utils/lispreader.h" +#include "lisp/parser.h" +#include "lisp/lisp.h" +#include "lisp/writer.h" #include "video/drawing_context.h" #include "special/sprite_manager.h" diff --git a/src/badguy/bomb.cpp b/src/badguy/bomb.cpp index 62547b9e9..2897e687a 100644 --- a/src/badguy/bomb.cpp +++ b/src/badguy/bomb.cpp @@ -18,7 +18,7 @@ Bomb::Bomb(const Vector& pos, Direction dir) } void -Bomb::write(LispWriter& ) +Bomb::write(lisp::Writer& ) { // bombs are only temporarily so don't write them out... } diff --git a/src/badguy/bomb.h b/src/badguy/bomb.h index 9d0959930..fc3beec95 100644 --- a/src/badguy/bomb.h +++ b/src/badguy/bomb.h @@ -8,7 +8,7 @@ class Bomb : public BadGuy public: Bomb(const Vector& pos, Direction dir); - void write(LispWriter& writer); + void write(lisp::Writer& writer); HitResponse collision_solid(GameObject& other, const CollisionHit& hit); HitResponse collision_player(Player& player, const CollisionHit& hit); void active_action(float elapsed_time); diff --git a/src/badguy/bouncing_snowball.cpp b/src/badguy/bouncing_snowball.cpp index 26a95344e..431cac254 100644 --- a/src/badguy/bouncing_snowball.cpp +++ b/src/badguy/bouncing_snowball.cpp @@ -5,10 +5,10 @@ static const float JUMPSPEED = 450; static const float WALKSPEED = 80; -BouncingSnowball::BouncingSnowball(LispReader& reader) +BouncingSnowball::BouncingSnowball(const lisp::Lisp& reader) { - reader.read_float("x", start_position.x); - reader.read_float("y", start_position.y); + reader.get("x", start_position.x); + reader.get("y", start_position.y); bbox.set_size(31.8, 31.8); sprite = sprite_manager->create("bouncingsnowball"); set_direction = false; @@ -25,7 +25,7 @@ BouncingSnowball::BouncingSnowball(float pos_x, float pos_y, Direction d) } void -BouncingSnowball::write(LispWriter& writer) +BouncingSnowball::write(lisp::Writer& writer) { writer.start_list("bouncingsnowball"); diff --git a/src/badguy/bouncing_snowball.h b/src/badguy/bouncing_snowball.h index 4bb4d862c..d53badf12 100644 --- a/src/badguy/bouncing_snowball.h +++ b/src/badguy/bouncing_snowball.h @@ -6,11 +6,11 @@ class BouncingSnowball : public BadGuy { public: - BouncingSnowball(LispReader& reader); + BouncingSnowball(const lisp::Lisp& reader); BouncingSnowball(float pos_x, float pos_y, Direction d); void activate(); - void write(LispWriter& writer); + void write(lisp::Writer& writer); HitResponse collision_solid(GameObject& other, const CollisionHit& hit); protected: diff --git a/src/badguy/dispenser.cpp b/src/badguy/dispenser.cpp index b88ec202c..5f18cc77b 100644 --- a/src/badguy/dispenser.cpp +++ b/src/badguy/dispenser.cpp @@ -6,20 +6,19 @@ #include "badguy/mrbomb.h" #include "badguy/mriceblock.h" - -Dispenser::Dispenser(LispReader& reader) +Dispenser::Dispenser(const lisp::Lisp& reader) { - reader.read_float("x", start_position.x); - reader.read_float("y", start_position.y); - reader.read_float("cycle", cycle); - reader.read_string("badguy", badguy); + reader.get("x", start_position.x); + reader.get("y", start_position.y); + reader.get("cycle", cycle); + reader.get("badguy", badguy); bbox.set_size(32, 32); sprite = sprite_manager->create("dispenser"); sprite->set_action("working"); } void -Dispenser::write(LispWriter& writer) +Dispenser::write(lisp::Writer& writer) { writer.start_list("dispenser"); diff --git a/src/badguy/dispenser.h b/src/badguy/dispenser.h index 6c83a28d8..3dd24899e 100644 --- a/src/badguy/dispenser.h +++ b/src/badguy/dispenser.h @@ -7,10 +7,10 @@ class Dispenser : public BadGuy { public: - Dispenser(LispReader& reader); + Dispenser(const lisp::Lisp& reader); void activate(); - void write(LispWriter& writer); + void write(lisp::Writer& writer); HitResponse collision_solid(GameObject& other, const CollisionHit& hit); void active_action(float elapsed_time); diff --git a/src/badguy/flame.cpp b/src/badguy/flame.cpp index 83845a6dd..853ca5e64 100644 --- a/src/badguy/flame.cpp +++ b/src/badguy/flame.cpp @@ -2,13 +2,13 @@ #include "flame.h" -Flame::Flame(LispReader& reader) +Flame::Flame(const lisp::Lisp& reader) : angle(0), radius(100), speed(2) { - reader.read_float("x", start_position.x); - reader.read_float("y", start_position.y); - reader.read_float("radius", radius); - reader.read_float("speed", speed); + reader.get("x", start_position.x); + reader.get("y", start_position.y); + reader.get("radius", radius); + reader.get("speed", speed); bbox.set_pos(Vector(start_position.x + cos(angle) * radius, start_position.y + sin(angle) * radius)); bbox.set_size(32, 32); @@ -16,7 +16,7 @@ Flame::Flame(LispReader& reader) } void -Flame::write(LispWriter& writer) +Flame::write(lisp::Writer& writer) { writer.start_list("flame"); diff --git a/src/badguy/flame.h b/src/badguy/flame.h index b27e1f0c7..6a82a5ab6 100644 --- a/src/badguy/flame.h +++ b/src/badguy/flame.h @@ -6,9 +6,9 @@ class Flame : public BadGuy { public: - Flame(LispReader& reader); + Flame(const lisp::Lisp& reader); - void write(LispWriter& write); + void write(lisp::Writer& write); void active_action(float elapsed_time); void kill_fall(); diff --git a/src/badguy/jumpy.cpp b/src/badguy/jumpy.cpp index f7abad908..bc8dffef4 100644 --- a/src/badguy/jumpy.cpp +++ b/src/badguy/jumpy.cpp @@ -4,16 +4,16 @@ static const float JUMPSPEED=600; -Jumpy::Jumpy(LispReader& reader) +Jumpy::Jumpy(const lisp::Lisp& reader) { - reader.read_float("x", start_position.x); - reader.read_float("y", start_position.y); + reader.get("x", start_position.x); + reader.get("y", start_position.y); bbox.set_size(31.8, 31.8); sprite = sprite_manager->create("jumpy"); } void -Jumpy::write(LispWriter& writer) +Jumpy::write(lisp::Writer& writer) { writer.start_list("jumpy"); diff --git a/src/badguy/jumpy.h b/src/badguy/jumpy.h index 8abd10c70..e33f6eb62 100644 --- a/src/badguy/jumpy.h +++ b/src/badguy/jumpy.h @@ -2,19 +2,16 @@ #define __JUMPY_H__ #include "badguy.h" -#include "utils/lispreader.h" -#include "utils/lispwriter.h" -#include "serializable.h" class Jumpy : public BadGuy { public: - Jumpy(LispReader& reader); + Jumpy(const lisp::Lisp& reader); virtual HitResponse collision_solid(GameObject& other, const CollisionHit& hit); - virtual void write(LispWriter& writer); + virtual void write(lisp::Writer& writer); }; #endif diff --git a/src/badguy/mrbomb.cpp b/src/badguy/mrbomb.cpp index b7a443d33..76222d28f 100644 --- a/src/badguy/mrbomb.cpp +++ b/src/badguy/mrbomb.cpp @@ -5,10 +5,10 @@ static const float WALKSPEED = 80; -MrBomb::MrBomb(LispReader& reader) +MrBomb::MrBomb(const lisp::Lisp& reader) { - reader.read_float("x", start_position.x); - reader.read_float("y", start_position.y); + reader.get("x", start_position.x); + reader.get("y", start_position.y); bbox.set_size(31.8, 31.8); sprite = sprite_manager->create("mrbomb"); set_direction = false; @@ -25,7 +25,7 @@ MrBomb::MrBomb(float pos_x, float pos_y, Direction d) } void -MrBomb::write(LispWriter& writer) +MrBomb::write(lisp::Writer& writer) { writer.start_list("mrbomb"); diff --git a/src/badguy/mrbomb.h b/src/badguy/mrbomb.h index 257716fb3..fda40fb8b 100644 --- a/src/badguy/mrbomb.h +++ b/src/badguy/mrbomb.h @@ -6,11 +6,11 @@ class MrBomb : public BadGuy { public: - MrBomb(LispReader& reader); + MrBomb(const lisp::Lisp& reader); MrBomb(float pos_x, float pos_y, Direction d); void activate(); - void write(LispWriter& writer); + void write(lisp::Writer& writer); HitResponse collision_solid(GameObject& other, const CollisionHit& hit); protected: diff --git a/src/badguy/mriceblock.cpp b/src/badguy/mriceblock.cpp index 72a007cbb..e0bdbf66b 100644 --- a/src/badguy/mriceblock.cpp +++ b/src/badguy/mriceblock.cpp @@ -6,11 +6,11 @@ static const float WALKSPEED = 80; static const float KICKSPEED = 500; static const int MAXSQUISHES = 10; -MrIceBlock::MrIceBlock(LispReader& reader) +MrIceBlock::MrIceBlock(const lisp::Lisp& reader) : ice_state(ICESTATE_NORMAL), squishcount(0) { - reader.read_float("x", start_position.x); - reader.read_float("y", start_position.y); + reader.get("x", start_position.x); + reader.get("y", start_position.y); bbox.set_size(31.8, 31.8); sprite = sprite_manager->create("mriceblock"); set_direction = false; @@ -28,7 +28,7 @@ MrIceBlock::MrIceBlock(float pos_x, float pos_y, Direction d) } void -MrIceBlock::write(LispWriter& writer) +MrIceBlock::write(lisp::Writer& writer) { writer.start_list("mriceblock"); diff --git a/src/badguy/mriceblock.h b/src/badguy/mriceblock.h index 7275c0ee2..3a6d2a63d 100644 --- a/src/badguy/mriceblock.h +++ b/src/badguy/mriceblock.h @@ -6,11 +6,11 @@ class MrIceBlock : public BadGuy { public: - MrIceBlock(LispReader& reader); + MrIceBlock(const lisp::Lisp& reader); MrIceBlock(float pos_x, float pos_y, Direction d); void activate(); - void write(LispWriter& writer); + void write(lisp::Writer& writer); HitResponse collision_solid(GameObject& other, const CollisionHit& hit); void active_action(float elapsed_time); diff --git a/src/badguy/nolok_01.cpp b/src/badguy/nolok_01.cpp index 16214aa3a..ac3a8e170 100644 --- a/src/badguy/nolok_01.cpp +++ b/src/badguy/nolok_01.cpp @@ -12,10 +12,10 @@ static const float WALKSPEED = 90; //TODO: Create sprite, give multiple hitpoints, limit max number of snowballs // Stop actions when pause button is hit (probably a general problem of timers) -Nolok_01::Nolok_01(LispReader& reader) +Nolok_01::Nolok_01(const lisp::Lisp& reader) { - reader.read_float("x", start_position.x); - reader.read_float("y", start_position.y); + reader.get("x", start_position.x); + reader.get("y", start_position.y); bbox.set_size(31.8, 63.8); sprite = sprite_manager->create("dummyguy"); } @@ -29,7 +29,7 @@ Nolok_01::Nolok_01(float pos_x, float pos_y) } void -Nolok_01::write(LispWriter& writer) +Nolok_01::write(lisp::Writer& writer) { writer.start_list("nolok01"); diff --git a/src/badguy/nolok_01.h b/src/badguy/nolok_01.h index b35ca369b..cc50d5a76 100644 --- a/src/badguy/nolok_01.h +++ b/src/badguy/nolok_01.h @@ -7,11 +7,11 @@ class Nolok_01 : public BadGuy { public: - Nolok_01(LispReader& reader); + Nolok_01(const lisp::Lisp& reader); Nolok_01(float pos_x, float pos_y); void activate(); - void write(LispWriter& writer); + void write(lisp::Writer& writer); void active_action(float elapsed_time); HitResponse collision_solid(GameObject& other, const CollisionHit& hit); diff --git a/src/badguy/snowball.cpp b/src/badguy/snowball.cpp index de77435b7..4442d02a9 100644 --- a/src/badguy/snowball.cpp +++ b/src/badguy/snowball.cpp @@ -4,10 +4,10 @@ static const float WALKSPEED = 80; -SnowBall::SnowBall(LispReader& reader) +SnowBall::SnowBall(const lisp::Lisp& reader) { - reader.read_float("x", start_position.x); - reader.read_float("y", start_position.y); + reader.get("x", start_position.x); + reader.get("y", start_position.y); bbox.set_size(31.8, 31.8); sprite = sprite_manager->create("snowball"); set_direction = false; @@ -24,7 +24,7 @@ SnowBall::SnowBall(float pos_x, float pos_y, Direction d) } void -SnowBall::write(LispWriter& writer) +SnowBall::write(lisp::Writer& writer) { writer.start_list("snowball"); diff --git a/src/badguy/snowball.h b/src/badguy/snowball.h index 55bf56c7f..47acaf0aa 100644 --- a/src/badguy/snowball.h +++ b/src/badguy/snowball.h @@ -6,11 +6,11 @@ class SnowBall : public BadGuy { public: - SnowBall(LispReader& reader); + SnowBall(const lisp::Lisp& reader); SnowBall(float pos_x, float pos_y, Direction d); void activate(); - void write(LispWriter& writer); + void write(lisp::Writer& writer); HitResponse collision_solid(GameObject& other, const CollisionHit& hit); protected: diff --git a/src/badguy/spike.cpp b/src/badguy/spike.cpp index 905e92143..bc3145050 100644 --- a/src/badguy/spike.cpp +++ b/src/badguy/spike.cpp @@ -9,14 +9,14 @@ Spike::Spike(const Vector& pos, Direction dir) set_direction(dir); } -Spike::Spike(LispReader& reader) +Spike::Spike(const lisp::Lisp& reader) { sprite = sprite_manager->create("spike"); - reader.read_float("x", start_position.x); - reader.read_float("y", start_position.y); + reader.get("x", start_position.x); + reader.get("y", start_position.y); bbox.set_size(32, 32); int idir = 0; - reader.read_int("direction", idir); + reader.get("direction", idir); set_direction((Direction) idir); } @@ -43,7 +43,7 @@ Spike::set_direction(Direction dir) } void -Spike::write(LispWriter& writer) +Spike::write(lisp::Writer& writer) { writer.start_list("spike"); writer.write_float("x", start_position.x); diff --git a/src/badguy/spike.h b/src/badguy/spike.h index 112227012..eae68d0e0 100644 --- a/src/badguy/spike.h +++ b/src/badguy/spike.h @@ -10,10 +10,10 @@ public: NORTH=0, SOUTH, WEST, EAST }; Spike(const Vector& pos, Direction dir); - Spike(LispReader& reader); + Spike(const lisp::Lisp& reader); void active_action(float elapsed_time); - void write(LispWriter& writer); + void write(lisp::Writer& writer); void kill_fall(); private: void set_direction(Direction dir); diff --git a/src/badguy/spiky.cpp b/src/badguy/spiky.cpp index c779faace..255bb9e18 100644 --- a/src/badguy/spiky.cpp +++ b/src/badguy/spiky.cpp @@ -4,16 +4,16 @@ static const float WALKSPEED = 80; -Spiky::Spiky(LispReader& reader) +Spiky::Spiky(const lisp::Lisp& reader) { - reader.read_float("x", start_position.x); - reader.read_float("y", start_position.y); + reader.get("x", start_position.x); + reader.get("y", start_position.y); bbox.set_size(31.8, 31.8); sprite = sprite_manager->create("spiky"); } void -Spiky::write(LispWriter& writer) +Spiky::write(lisp::Writer& writer) { writer.start_list("spiky"); diff --git a/src/badguy/spiky.h b/src/badguy/spiky.h index 547ea13cb..2c48e2973 100644 --- a/src/badguy/spiky.h +++ b/src/badguy/spiky.h @@ -6,10 +6,10 @@ class Spiky : public BadGuy { public: - Spiky(LispReader& reader); + Spiky(const lisp::Lisp& reader); void activate(); - void write(LispWriter& writer); + void write(lisp::Writer& writer); HitResponse collision_solid(GameObject& other, const CollisionHit& hit); }; diff --git a/src/gameloop.cpp b/src/gameloop.cpp index 326706309..84e4be276 100644 --- a/src/gameloop.cpp +++ b/src/gameloop.cpp @@ -18,7 +18,6 @@ // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - #include #include @@ -31,6 +30,7 @@ #include #include #include +#include #include "SDL.h" @@ -44,7 +44,6 @@ #include "gameloop.h" #include "video/screen.h" #include "app/setup.h" -#include "high_scores.h" #include "gui/menu.h" #include "sector.h" #include "level.h" @@ -55,6 +54,8 @@ #include "object/tilemap.h" #include "object/camera.h" #include "object/player.h" +#include "lisp/lisp.h" +#include "lisp/parser.h" #include "resources.h" #include "app/gettext.h" #include "worldmap.h" @@ -937,25 +938,21 @@ std::string slotinfo(int slot) stream << slot; slotfile = st_save_dir + "/slot" + stream.str() + ".stsg"; - lisp_object_t* savegame = lisp_read_from_file(slotfile.c_str()); - if (savegame) - { - LispReader reader(lisp_cdr(savegame)); - reader.read_string("title", title); - lisp_free(savegame); - } + try { + lisp::Parser parser; + std::auto_ptr root (parser.parse(slotfile)); - if (access(slotfile.c_str(), F_OK) == 0) - { - if (!title.empty()) - tmp = "Slot " + stream.str() + " - " + title; - else - tmp = "Slot " + stream.str() + " - Savegame"; - } - else - tmp = std::string(_("Slot")) + " " + stream.str() + " - " + std::string(_("Free")); + const lisp::Lisp* savegame = root->get_lisp("supertux-savegame"); + if(!savegame) + throw std::runtime_error("file is not a supertux-savegame."); + + savegame->get("title", title); + } catch(std::exception& e) { + return std::string(_("Slot")) + " " + stream.str() + " - " + + std::string(_("Free")); + } - return tmp; + return std::string("Slot ") + stream.str() + " - " + title; } bool process_load_game_menu() diff --git a/src/high_scores.cpp b/src/high_scores.cpp deleted file mode 100644 index 86b1eb699..000000000 --- a/src/high_scores.cpp +++ /dev/null @@ -1,164 +0,0 @@ -// $Id$ -// -// SuperTux -// Copyright (C) 2004 Adam Czachorowski -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA -// 02111-1307, USA. - -/* Open the highscore file: */ - -#include - -#include -#include - -#include "app/globals.h" -#include "high_scores.h" -#include "gui/menu.h" -#include "video/drawing_context.h" -#include "video/screen.h" -#include "video/surface.h" -#include "app/setup.h" -#include "utils/lispreader.h" -#include "resources.h" - -using namespace SuperTux; - -#ifdef WIN32 -const char * highscore_filename = "/st_highscore.dat"; -#else -const char * highscore_filename = "/highscore"; -#endif - -int hs_score; -std::string hs_name; /* highscores global variables*/ - -/* Load data from high score file: */ - -void load_hs(void) -{ - hs_score = 100; - hs_name = "Grandma"; - - FILE * fi; - lisp_object_t* root_obj = 0; - fi = fopen(highscore_filename, "r"); - if (fi == NULL) - { - perror(highscore_filename); - return; - } - - lisp_stream_t stream; - lisp_stream_init_file (&stream, fi); - root_obj = lisp_read (&stream); - - if (root_obj->type == LISP_TYPE_EOF || root_obj->type == LISP_TYPE_PARSE_ERROR) - { - printf("HighScore: Parse Error in file %s", highscore_filename); - } - - - if (strcmp(lisp_symbol(lisp_car(root_obj)), "supertux-highscore") == 0) - { - LispReader reader(lisp_cdr(root_obj)); - reader.read_int("score", hs_score); - reader.read_string("name", hs_name); - } - - fclose(fi); - lisp_free(root_obj); -} - -void save_hs(int score) -{ - char str[80]; - - Surface* bkgd; - SDL_Event event; - - DrawingContext context; - bkgd = new Surface(datadir + "/images/highscore/highscore.png", false); - - hs_score = score; - - Menu::set_current(highscore_menu); - - highscore_menu->item[0].input = hs_name; - - /* ask for player's name */ - while(Menu::current()) - { - context.draw_surface(bkgd, Vector(0, 0), LAYER_BACKGROUND0); - - context.draw_text(blue_text, "Congratulations", - Vector(screen->w/2, 130), CENTER_ALLIGN, LAYER_FOREGROUND1); - context.draw_text(blue_text, "Your score:", Vector(150, 180), - LEFT_ALLIGN, LAYER_FOREGROUND1); - sprintf(str, "%d", hs_score); - context.draw_text(yellow_nums, str, Vector(250, 170), LEFT_ALLIGN, LAYER_FOREGROUND1); - - Menu::current()->draw(context); - Menu::current()->action(); - - context.do_drawing(); - - while(SDL_PollEvent(&event)) - if(event.type == SDL_KEYDOWN) - Menu::current()->event(event); - - switch (highscore_menu->check()) - { - case 0: - hs_name = highscore_menu->item[0].input; - break; - } - - SDL_Delay(25); - } - - - /* Save to file: */ - - FILE* fi; - std::string filename; - - /* Save data file: */ - filename = highscore_filename; - - FileSystem::fcreatedir(filename.c_str()); - if(FileSystem::fwriteable(filename.c_str())) - { - fi = fopen(filename.c_str(), "w"); - if (fi == NULL) - { - perror(filename.c_str()); - } - - /* Write header: */ - fprintf(fi,";SuperTux HighScores\n"); - fprintf(fi,"(supertux-highscore\n"); - - /* Save title info: */ - fprintf(fi," (name \"%s\")\n", hs_name.c_str()); - - /* Save the description: */ - fprintf(fi," (score \"%i\")\n", hs_score); - - fprintf( fi,")"); - fclose(fi); - } -} diff --git a/src/high_scores.h b/src/high_scores.h deleted file mode 100644 index 76d6739e2..000000000 --- a/src/high_scores.h +++ /dev/null @@ -1,32 +0,0 @@ -// $Id$ -// -// SuperTux -// Copyright (C) 2004 Adam Czachorowski -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA -// 02111-1307, USA. - -#ifndef SUPERTUX_HIGH_SCORES_H -#define SUPERTUX_HIGH_SCORES_H - -#include - -extern int hs_score; -extern std::string hs_name; /* highscores global variables*/ - -void save_hs(int score); -void load_hs(); - -#endif diff --git a/src/level.cpp b/src/level.cpp index 5aa073419..c159d220c 100644 --- a/src/level.cpp +++ b/src/level.cpp @@ -17,7 +17,6 @@ // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA // 02111-1307, USA. - #include #include @@ -26,19 +25,23 @@ #include #include #include +#include +#include #include #include "app/globals.h" #include "app/setup.h" #include "video/screen.h" +#include "lisp/parser.h" +#include "lisp/lisp.h" +#include "lisp/list_iterator.h" +#include "lisp/writer.h" #include "level.h" #include "math/physic.h" #include "scene.h" #include "sector.h" #include "tile.h" -#include "utils/lispreader.h" #include "resources.h" -#include "utils/lispwriter.h" #include "object/gameobjs.h" #include "object/camera.h" #include "object/tilemap.h" @@ -55,59 +58,66 @@ Level::Level() void Level::load(const std::string& filepath) { - LispReader* level = LispReader::load(filepath, "supertux-level"); - - int version = 1; - level->read_int("version", version); - if(version == 1) { - load_old_format(*level); - delete level; - return; - } - - for(lisp_object_t* cur = level->get_lisp(); !lisp_nil_p(cur); - cur = lisp_cdr(cur)) { - std::string token = lisp_symbol(lisp_car(lisp_car(cur))); - lisp_object_t* data = lisp_car(lisp_cdr(lisp_car(cur))); - LispReader reader(lisp_cdr(lisp_car(cur))); + try { + lisp::Parser parser; + std::auto_ptr root (parser.parse(filepath)); + + const lisp::Lisp* level = root->get_lisp("supertux-level"); + if(!level) + throw std::runtime_error("file is not a supertux-level file."); + + int version = 1; + level->get("version", version); + if(version == 1) { + load_old_format(*level); + return; + } - if(token == "version") { - if(lisp_integer(data) > 2) { - std::cerr << "Warning: level format newer than application.\n"; - } - } else if(token == "name") { - name = lisp_string(data); - } else if(token == "author") { - author = lisp_string(data); - } else if(token == "time") { - timelimit = lisp_integer(data); - } else if(token == "sector") { - Sector* sector = new Sector; - sector->parse(reader); - add_sector(sector); - } else if(token == "end-sequence-animation") { - std::string endsequencename = lisp_string(data); - if(endsequencename == "fireworks") { - end_sequence_type = FIREWORKS_ENDSEQ_ANIM; + lisp::ListIterator iter(level); + while(iter.next()) { + const std::string& token = iter.item(); + if(token == "version") { + iter.value()->get(version); + if(version > 2) { + std::cerr << "Warning: level format newer than application.\n"; + } + } else if(token == "name") { + iter.value()->get(name); + } else if(token == "author") { + iter.value()->get(author); + } else if(token == "time") { + iter.value()->get(timelimit); + } else if(token == "sector") { + Sector* sector = new Sector; + sector->parse(*(iter.lisp())); + add_sector(sector); + } else if(token == "end-sequence-animation") { + std::string endsequencename; + iter.value()->get(endsequencename); + if(endsequencename == "fireworks") { + end_sequence_type = FIREWORKS_ENDSEQ_ANIM; + } else { + std::cout << "Unknown endsequence type: '" << endsequencename << + "'.\n"; + } } else { - std::cout << "Unknown endsequence type: '" << endsequencename << - "'.\n"; + std::cerr << "Unknown token '" << token << "' in level file.\n"; + continue; } - } else { - std::cerr << "Unknown token '" << token << "' in level file.\n"; - continue; } + } catch(std::exception& e) { + std::stringstream msg; + msg << "Problem when reading level '" << filepath << "': " << e.what(); + throw std::runtime_error(msg.str()); } - - delete level; } void -Level::load_old_format(LispReader& reader) +Level::load_old_format(const lisp::Lisp& reader) { - reader.read_string("name", name, true); - reader.read_string("author", author); - reader.read_int("time", timelimit); + reader.get("name", name); + reader.get("author", author); + reader.get("time", timelimit); Sector* sector = new Sector; sector->parse_old_format(reader); @@ -122,7 +132,7 @@ Level::save(const std::string& filename) FileSystem::fcreatedir(filepath.substr(0,last_slash).c_str()); filepath = st_dir + "/" + filepath; ofstream file(filepath.c_str(), ios::out); - LispWriter* writer = new LispWriter(file); + lisp::Writer* writer = new lisp::Writer(file); writer->write_comment("Level made using SuperTux's built-in Level Editor"); diff --git a/src/level.h b/src/level.h index 08d71b7df..7eb024807 100644 --- a/src/level.h +++ b/src/level.h @@ -28,8 +28,8 @@ using namespace SuperTux; class Sector; -namespace SuperTux { -class LispReader; +namespace lisp { +class Lisp; } class Level @@ -77,7 +77,7 @@ public: int get_total_coins(); private: - void load_old_format(LispReader& reader); + void load_old_format(const lisp::Lisp& reader); }; #endif /*SUPERTUX_LEVEL_H*/ diff --git a/src/level_subset.cpp b/src/level_subset.cpp index 19edf4772..5cd4fc9d1 100644 --- a/src/level_subset.cpp +++ b/src/level_subset.cpp @@ -30,6 +30,8 @@ #include "app/globals.h" #include "video/surface.h" #include "level_subset.h" +#include "lisp/parser.h" +#include "lisp/lisp.h" using namespace SuperTux; @@ -63,27 +65,19 @@ void LevelSubset::create(const std::string& subset_name) void LevelSubset::read_info_file(const std::string& info_file) { - lisp_object_t* root_obj = lisp_read_from_file(info_file); - if (root_obj == NULL) - return; - lisp_object_t* cur = lisp_car(root_obj); + lisp::Parser parser; + std::auto_ptr root (parser.parse(info_file)); - if (lisp_symbol_p(cur) && strcmp(lisp_symbol(cur), "supertux-level-subset") == 0) - { - LispReader reader(lisp_cdr(root_obj)); + const lisp::Lisp* info = root->get_lisp("supertux-level-subset"); + if(!info) + throw std::runtime_error("File is not a levelsubset file"); - reader.read_string("title", title, true); - reader.read_string("description", description, true); - reader.read_string_vector("levels", levels); - hide_from_contribs = false; - reader.read_bool("hide-from-contribs", hide_from_contribs); - } - else - { - std::cout << "LevelSubset: parse error in info file: " << info_file << std::endl; - } + hide_from_contribs = false; - lisp_free(root_obj); + info->get("title", title); + info->get("description", description); + info->get_vector("levels", levels); + info->get("hide-from-contribs", hide_from_contribs); } void LevelSubset::load(const std::string& subset) @@ -99,8 +93,14 @@ void LevelSubset::load(const std::string& subset) msg << "Couldn't find level subset '" << subset << "'."; throw new std::runtime_error(msg.str()); } - - read_info_file(filename); + + try { + read_info_file(filename); + } catch(std::exception& e) { + std::stringstream msg; + msg << "Couldn't parse info file '" << filename << "': " << e.what(); + throw new std::runtime_error(msg.str()); + } if (levels.empty()) { // Level info file doesn't define any levels, so read the diff --git a/src/level_subset.h b/src/level_subset.h index 8202271f4..7ae03e25a 100644 --- a/src/level_subset.h +++ b/src/level_subset.h @@ -23,7 +23,6 @@ #include #include -#include "utils/lispreader.h" using namespace SuperTux; diff --git a/src/leveleditor.cpp b/src/leveleditor.cpp index 42f0fd825..198c0c24c 100644 --- a/src/leveleditor.cpp +++ b/src/leveleditor.cpp @@ -101,12 +101,10 @@ LevelEditor::LevelEditor() tiles_board = new ButtonGroup(Vector(screen->w - 140, 100), Vector(32,32), Vector(4,8)); - TileManager* tilemanager = TileManager::instance(); - tiles_board->add_button(Button(img_rubber_bt, _("Eraser"), SDLKey(SDLK_DELETE)), 0); - for(unsigned int id = 1; id < tilemanager->get_max_tileid(); id++) + for(unsigned int id = 1; id < tile_manager->get_max_tileid(); id++) { - const Tile* tile = tilemanager->get(id); + const Tile* tile = tile_manager->get(id); if(!tile) continue; @@ -642,10 +640,9 @@ if(sector) } else { - TileManager* tilemanager = TileManager::instance(); for(unsigned int x = 0; x < selection.size(); x++) for(unsigned int y = 0; y < selection[x].size(); y++) { - const Tile* tile = tilemanager->get(selection[x][y]); + const Tile* tile = tile_manager->get(selection[x][y]); tile->draw(context, Vector(event.button.x + x*32 - 8, event.button.y + y*32 - 8), LAYER_GUI-2); diff --git a/src/misc.cpp b/src/misc.cpp index b03fca10b..9b32379e9 100644 --- a/src/misc.cpp +++ b/src/misc.cpp @@ -20,15 +20,16 @@ #include "misc.h" #include "app/globals.h" -void MyConfig::customload(LispReader& reader) +void MyConfig::customload(const lisp::Lisp& reader) { - reader.read_int ("keyboard-up", keymap.up); - reader.read_int ("keyboard-down", keymap.down); - reader.read_int ("keyboard-left", keymap.left); - reader.read_int ("keyboard-right", keymap.right); - reader.read_int ("keyboard-jump", keymap.jump); - reader.read_int ("keyboard-power", keymap.power); + reader.get("keyboard-up", keymap.up); + reader.get("keyboard-down", keymap.down); + reader.get("keyboard-left", keymap.left); + reader.get("keyboard-right", keymap.right); + reader.get("keyboard-jump", keymap.jump); + reader.get("keyboard-power", keymap.power); } + void MyConfig::customsave(FILE * config) { fprintf(config, "\t(keyboard-up %d)\n", keymap.up); diff --git a/src/misc.h b/src/misc.h index bef88781b..e00508710 100644 --- a/src/misc.h +++ b/src/misc.h @@ -31,7 +31,7 @@ class MyConfig : public Config { public: - void customload(LispReader& reader); + void customload(const lisp::Lisp& reader); void customsave(FILE * config); }; diff --git a/src/object/background.cpp b/src/object/background.cpp index 2d6cc4121..15333dd20 100644 --- a/src/object/background.cpp +++ b/src/object/background.cpp @@ -23,25 +23,26 @@ #include "app/globals.h" #include "camera.h" #include "video/drawing_context.h" -#include "utils/lispwriter.h" +#include "lisp/lisp.h" +#include "lisp/writer.h" Background::Background() : type(INVALID), layer(LAYER_BACKGROUND0), image(0) { } -Background::Background(LispReader& reader) +Background::Background(const lisp::Lisp& reader) : type(INVALID), layer(LAYER_BACKGROUND0), image(0) { - reader.read_int("layer", layer); - if(reader.read_string("image", imagefile) - && reader.read_float("speed", speed)) { + reader.get("layer", layer); + if(reader.get("image", imagefile) + && reader.get("speed", speed)) { set_image(imagefile, speed); } std::vector bkgd_top_color, bkgd_bottom_color; - if(reader.read_int_vector("top_color", bkgd_top_color) && - reader.read_int_vector("bottom_color", bkgd_bottom_color)) + if(reader.get_vector("top_color", bkgd_top_color) && + reader.get_vector("bottom_color", bkgd_bottom_color)) set_gradient(Color(bkgd_top_color), Color(bkgd_bottom_color)); } @@ -51,7 +52,7 @@ Background::~Background() } void -Background::write(LispWriter& writer) +Background::write(lisp::Writer& writer) { if(type == INVALID) return; diff --git a/src/object/background.h b/src/object/background.h index 7ed3e837c..0bc3ca199 100644 --- a/src/object/background.h +++ b/src/object/background.h @@ -23,19 +23,22 @@ #include "video/surface.h" #include "video/drawing_context.h" #include "special/game_object.h" -#include "utils/lispreader.h" #include "serializable.h" class DisplayManager; +namespace lisp { +class Lisp; +} + class Background : public GameObject, public Serializable { public: Background(); - Background(LispReader& reader); + Background(const lisp::Lisp& reader); virtual ~Background(); - virtual void write(LispWriter& writer); + virtual void write(lisp::Writer& writer); void set_image(const std::string& name, float bkgd_speed); diff --git a/src/object/camera.cpp b/src/object/camera.cpp index b2f47ed8f..ae9adf3cd 100644 --- a/src/object/camera.cpp +++ b/src/object/camera.cpp @@ -23,9 +23,10 @@ #include #include +#include "lisp/lisp.h" +#include "lisp/writer.h" +#include "lisp/list_iterator.h" #include "camera.h" -#include "utils/lispreader.h" -#include "utils/lispwriter.h" #include "player.h" #include "tilemap.h" #include "gameloop.h" @@ -52,43 +53,41 @@ Camera::get_translation() const } void -Camera::parse(LispReader& reader) +Camera::parse(const lisp::Lisp& reader) { std::string modename; - reader.read_string("mode", modename); + reader.get("mode", modename); if(modename == "normal") { mode = NORMAL; do_backscrolling = true; - reader.read_bool("backscrolling", do_backscrolling); + reader.get("backscrolling", do_backscrolling); } else if(modename == "autoscroll") { mode = AUTOSCROLL; - lisp_object_t* cur = 0; - reader.read_lisp("path", cur); - if(cur == 0) { + const lisp::Lisp* path_lisp = reader.get_lisp("path"); + if(!path_lisp) throw std::runtime_error("No path specified in autoscroll camera."); - } - float speed = 50; - while(!lisp_nil_p(cur)) { - if(strcmp(lisp_symbol(lisp_car(lisp_car(cur))), "point") != 0) { - std::cerr << "Warning: unknown token in camera path.\n"; + + lisp::ListIterator iter(path_lisp); + float speed = .5; + while(iter.next()) { + if(iter.item() != "point") { + std::cerr << "Warning: unknown token '" << iter.item() + << "' in camera path.\n"; continue; } - - LispReader reader(lisp_cdr(lisp_car(cur))); + const lisp::Lisp* point_lisp = iter.lisp(); ScrollPoint point; - if(!reader.read_float("x", point.position.x) || - !reader.read_float("y", point.position.y)) { + if(!point_lisp->get("x", point.position.x) || + !point_lisp->get("y", point.position.y)) { throw std::runtime_error("x and y missing in point of camerapath"); } - reader.read_float("speed", speed); + point_lisp->get("speed", speed); point.speed = speed; scrollpoints.push_back(point); - - cur = lisp_cdr(cur); } } else if(modename == "manual") { mode = MANUAL; @@ -100,7 +99,7 @@ Camera::parse(LispReader& reader) } void -Camera::write(LispWriter& writer) +Camera::write(lisp::Writer& writer) { writer.start_list("camera"); diff --git a/src/object/camera.h b/src/object/camera.h index 2294aa964..45351b6af 100644 --- a/src/object/camera.h +++ b/src/object/camera.h @@ -30,9 +30,8 @@ #include "serializable.h" using namespace SuperTux; - -namespace SuperTux { -class LispReader; +namespace lisp { +class Lisp; } class Sector; @@ -44,9 +43,9 @@ public: virtual ~Camera(); /// parse camera mode from lisp file - void parse(LispReader& reader); + void parse(const lisp::Lisp& reader); /// write camera mode to a lisp file - virtual void write(LispWriter& writer); + virtual void write(lisp::Writer& writer); /// reset camera postion virtual void reset(const Vector& tuxpos); diff --git a/src/object/gameobjs.cpp b/src/object/gameobjs.cpp index 3201eb285..bce0f2123 100644 --- a/src/object/gameobjs.cpp +++ b/src/object/gameobjs.cpp @@ -146,289 +146,6 @@ FloatingText::draw(DrawingContext& context) context.pop_transform(); } -/* Trampoline */ - -#if 0 -Sprite *img_trampoline; - -Trampoline::Trampoline(LispReader& reader) -{ - reader.read_float("x", base.x); - reader.read_float("y", base.y); - base.width = 32; - base.height = 32; - power = 7.5; - reader.read_float("power", power); - - frame = 0; - mode = M_NORMAL; - physic.reset(); -} - -Trampoline::Trampoline(float x, float y) -{ - base.x = x; - base.y = y; - base.width = 32; - base.height = 32; - power = 7.5; - - frame = 0; - mode = M_NORMAL; - physic.reset(); -} - -void -Trampoline::write(LispWriter& writer) -{ - writer.start_list("trampoline"); - - writer.write_float("x", base.x); - writer.write_float("y", base.y); - writer.write_float("power", power); - - writer.end_list("trampoline"); -} - -void -Trampoline::draw(DrawingContext& context) -{ - img_trampoline->set_frame(frame); - img_trampoline->draw(context, base, LAYER_OBJECTS); - frame = 0; -} - -void -Trampoline::action(float frame_ratio) -{ - // TODO: Remove if we're too far off the screen - - // Falling - if (mode != M_HELD) - { - if (issolid(base.x + base.width/2, base.y + base.height)) - { - base.y = int((base.y + base.height)/32) * 32 - base.height; - - physic.enable_gravity(false); - physic.set_velocity_y(0.0f); - - physic.set_velocity_x(0); - } - else - { - physic.enable_gravity(true); - } - } - else // Player is carrying us around - { - /* FIXME: The trampoline object shouldn't know about pplayer objects. */ - /* If we're holding the iceblock */ - Player& tux = *Sector::current()->player; - Direction dir = tux.dir; - - if(dir == RIGHT) - { - base.x = tux.base.x + 16; - base.y = tux.base.y + tux.base.height/1.5 - base.height; - } - else /* facing left */ - { - base.x = tux.base.x - 16; - base.y = tux.base.y + tux.base.height/1.5 - base.height; - } - - if(collision_object_map(base)) - { - base.x = tux.base.x; - base.y = tux.base.y + tux.base.height/1.5 - base.height; - } - } - - physic.apply(frame_ratio, base.x, base.y, Sector::current()->gravity); - collision_swept_object_map(&old_base, &base); -} - -void -Trampoline::collision(const MovingObject&, int) -{ - // comes later -} - -void -Trampoline::collision(void *p_c_object, int c_object, CollisionType type) -{ - Player* pplayer_c = NULL; - switch (c_object) - { - case CO_PLAYER: - pplayer_c = (Player*) p_c_object; - - if (type == COLLISION_NORMAL) - { - // Pick up if HELD (done in Player) - } - - else if (type == COLLISION_SQUISH) - { - int squish_amount = (32 - (int)pplayer_c->base.y % 32); - - if (squish_amount < 24) - frame = 3; - else if (squish_amount < 28) - frame = 2; - else if (squish_amount < 30) - frame = 1; - else - frame = 0; - - if (squish_amount < 20) { - pplayer_c->physic.set_velocity_y(power); - pplayer_c->fall_mode = Player::TRAMPOLINE_JUMP; - } - else if (pplayer_c->physic.get_velocity_y() < 0) - pplayer_c->physic.set_velocity_y(-squish_amount/32); - } - - break; - - default: - break; - - } -} -#endif - -/* Flying Platform */ - -#if 0 -Sprite *img_flying_platform; - -FlyingPlatform::FlyingPlatform(LispReader& reader) -{ - reader.read_int_vector("x", pos_x); - reader.read_int_vector("y", pos_y); - - velocity = 2.0; - reader.read_float("velocity", velocity); - - base.x = pos_x[0]; - base.y = pos_y[0]; - base.width = 96; - base.height = 40; - - point = 0; - move = false; - - float x = pos_x[point+1] - pos_x[point]; - float y = pos_y[point+1] - pos_y[point]; - vel_x = x*velocity / sqrt(x*x + y*y); - vel_y = -(velocity - vel_x); - - frame = 0; -} - -FlyingPlatform::FlyingPlatform(int x, int y) -{ -base.x = x; -base.y = y; -point = 0; -move = false; -} - -void -FlyingPlatform::write(LispWriter& writer) -{ - writer.start_list("flying-trampoline"); - - writer.write_int_vector("x", pos_x); - writer.write_int_vector("y", pos_y); - writer.write_float("velocity", velocity); - - writer.end_list("flying-trampoline"); -} - -void -FlyingPlatform::draw(DrawingContext& context) -{ - img_flying_platform->draw(context, base, LAYER_OBJECTS); -} - -void -FlyingPlatform::action(float frame_ratio) -{ - // TODO: Remove if we're too far off the screen - -if(!move) - return; - -if((unsigned)point+1 != pos_x.size()) - { - if(((pos_x[point+1] > pos_x[point] && base.x >= pos_x[point+1]) || - (pos_x[point+1] < pos_x[point] && base.x <= pos_x[point+1]) || - pos_x[point] == pos_x[point+1]) && - ((pos_y[point+1] > pos_y[point] && base.y >= pos_y[point+1]) || - (pos_y[point+1] < pos_y[point] && base.y <= pos_y[point+1]) || - pos_y[point] == pos_y[point+1])) - { - point++; - - float x = pos_x[point+1] - pos_x[point]; - float y = pos_y[point+1] - pos_y[point]; - vel_x = x*velocity / sqrt(x*x + y*y); - vel_y = -(velocity - vel_x); - } - } -else // last point - { - // point = 0; - // reverse vector - return; - } -/* -if(pos_x[point+1] > base.x) - base.x += velocity * frame_ratio; -else if(pos_x[point+1] < base.x) - base.x -= velocity * frame_ratio; - -if(pos_y[point+1] > base.y) - base.y += velocity * frame_ratio; -else if(pos_y[point+1] < base.y) - base.y -= velocity * frame_ratio; -*/ - -base.x += vel_x * frame_ratio; -base.y += vel_y * frame_ratio; -} - -void -FlyingPlatform::collision(const MovingObject&, int) -{ - // comes later -} - -void -FlyingPlatform::collision(void *p_c_object, int c_object, CollisionType type) -{ -(void) p_c_object; -(void) type; - -// Player* pplayer_c = NULL; - switch (c_object) - { - case CO_PLAYER: -// pplayer_c = (Player*) p_c_object; - move = true; - - break; - - default: - break; - - } -} -#endif - Sprite *img_smoke_cloud = 0; SmokeCloud::SmokeCloud(const Vector& pos) diff --git a/src/object/gameobjs.h b/src/object/gameobjs.h index 3d928be0e..6b884d737 100644 --- a/src/object/gameobjs.h +++ b/src/object/gameobjs.h @@ -18,7 +18,6 @@ // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA // 02111-1307, USA. - #ifndef SUPERTUX_GAMEOBJS_H #define SUPERTUX_GAMEOBJS_H @@ -29,7 +28,6 @@ #include "special/game_object.h" #include "special/moving_object.h" #include "serializable.h" -#include "utils/lispwriter.h" /* Bounciness of distros: */ #define NO_BOUNCE 0 @@ -84,31 +82,6 @@ private: Timer2 timer; }; -#if 0 -extern Sprite *img_trampoline; - -class Trampoline : public MovingObject, public Serializable -{ -public: - Trampoline(LispReader& reader); - Trampoline(float x, float y); - - virtual void write(LispWriter& writer); - virtual void action(float frame_ratio); - virtual void draw(DrawingContext& context); - - virtual void collision(const MovingObject& other, int); - void collision(void *p_c_object, int c_object, CollisionType type); - - Physic physic; - enum { M_NORMAL, M_HELD } mode; - - private: - float power; - unsigned int frame; -}; -#endif - extern Sprite *img_smoke_cloud; class SmokeCloud : public GameObject diff --git a/src/object/particlesystem.cpp b/src/object/particlesystem.cpp index b82152a13..4c24b1fc6 100644 --- a/src/object/particlesystem.cpp +++ b/src/object/particlesystem.cpp @@ -25,9 +25,10 @@ #include "particlesystem.h" #include "app/globals.h" -#include "utils/lispreader.h" -#include "utils/lispwriter.h" #include "video/drawing_context.h" +#include "lisp/parser.h" +#include "lisp/lisp.h" +#include "lisp/writer.h" ParticleSystem::ParticleSystem() { @@ -97,13 +98,13 @@ SnowParticleSystem::SnowParticleSystem() } void -SnowParticleSystem::parse(LispReader& reader) +SnowParticleSystem::parse(const lisp::Lisp& reader) { - reader.read_int("layer", layer); + reader.get("layer", layer); } void -SnowParticleSystem::write(LispWriter& writer) +SnowParticleSystem::write(lisp::Writer& writer) { writer.start_list("particles-snow"); writer.write_int("layer", layer); @@ -148,13 +149,13 @@ CloudParticleSystem::CloudParticleSystem() } void -CloudParticleSystem::parse(LispReader& reader) +CloudParticleSystem::parse(const lisp::Lisp& reader) { - reader.read_int("layer", layer); + reader.get("layer", layer); } void -CloudParticleSystem::write(LispWriter& writer) +CloudParticleSystem::write(lisp::Writer& writer) { writer.start_list("particles-clouds"); writer.write_int("layer", layer); diff --git a/src/object/particlesystem.h b/src/object/particlesystem.h index d11c5c13d..2aae2959d 100644 --- a/src/object/particlesystem.h +++ b/src/object/particlesystem.h @@ -28,8 +28,8 @@ using namespace SuperTux; -namespace SuperTux { -class LispReader; +namespace lisp { +class Lisp; } class DisplayManager; @@ -80,8 +80,8 @@ public: SnowParticleSystem(); virtual ~SnowParticleSystem(); - void parse(LispReader& reader); - void write(LispWriter& writer); + void parse(const lisp::Lisp& lisp); + void write(lisp::Writer& writer); virtual void action(float elapsed_time); @@ -104,8 +104,8 @@ public: CloudParticleSystem(); virtual ~CloudParticleSystem(); - void parse(LispReader& reader); - void write(LispWriter& writer); + void parse(const lisp::Lisp& lisp); + void write(lisp::Writer& writer); virtual void action(float elapsed_time); diff --git a/src/object/platform.cpp b/src/object/platform.cpp index d72b7ac33..f418596ba 100644 --- a/src/object/platform.cpp +++ b/src/object/platform.cpp @@ -5,14 +5,15 @@ #include "resources.h" #include "player.h" #include "special/sprite_manager.h" -#include "utils/lispreader.h" +#include "lisp/lisp.h" +#include "lisp/writer.h" -Platform::Platform(LispReader& reader) +Platform::Platform(const lisp::Lisp& reader) { sprite = sprite_manager->create("flying_platform"); movement = Vector(0, 1); - reader.read_float("x", bbox.p1.x); - reader.read_float("y", bbox.p1.y); + reader.get("x", bbox.p1.x); + reader.get("y", bbox.p1.y); bbox.set_size(sprite->get_width(), sprite->get_height()); flags |= FLAG_SOLID; diff --git a/src/object/platform.h b/src/object/platform.h index be4119b84..1ff286023 100644 --- a/src/object/platform.h +++ b/src/object/platform.h @@ -12,7 +12,7 @@ using namespace SuperTux; class Platform : public SuperTux::MovingObject { public: - Platform(LispReader& reader); + Platform(const lisp::Lisp& reader); ~Platform(); virtual HitResponse collision(GameObject& other, const CollisionHit& hit); diff --git a/src/object/tilemap.cpp b/src/object/tilemap.cpp index 08784415c..fd6c74dd4 100644 --- a/src/object/tilemap.cpp +++ b/src/object/tilemap.cpp @@ -28,29 +28,30 @@ #include "video/drawing_context.h" #include "level.h" #include "tile.h" +#include "resources.h" #include "tile_manager.h" #include "app/globals.h" -#include "utils/lispreader.h" -#include "utils/lispwriter.h" +#include "lisp/lisp.h" +#include "lisp/writer.h" TileMap::TileMap() : solid(false), speed(1), width(0), height(0), layer(LAYER_TILES), vertical_flip(false) { - tilemanager = TileManager::instance(); + tilemanager = tile_manager; if(solid) flags |= FLAG_SOLID; } -TileMap::TileMap(LispReader& reader) +TileMap::TileMap(const lisp::Lisp& reader) : solid(false), speed(1), width(0), height(0), layer(LAYER_TILES), vertical_flip(false) { - tilemanager = TileManager::instance(); + tilemanager = tile_manager; std::string layer_str; - if(reader.read_string("layer", layer_str)) { + if(reader.get("layer", layer_str)) { if(layer_str == "background") layer = LAYER_BACKGROUNDTILES; else if(layer_str == "interactive") @@ -61,8 +62,8 @@ TileMap::TileMap(LispReader& reader) std::cerr << "Unknown layer '" << layer_str << "' in tilemap.\n"; } - reader.read_bool("solid", solid); - reader.read_float("speed", speed); + reader.get("solid", solid); + reader.get("speed", speed); if(solid && speed != 1) { std::cout << "Speed of solid tilemap is not 1. fixing.\n"; @@ -71,22 +72,23 @@ TileMap::TileMap(LispReader& reader) if(solid) flags |= FLAG_SOLID; - if(!reader.read_int("width", width) || - !reader.read_int("height", height)) + if(!reader.get("width", width) || + !reader.get("height", height)) throw std::runtime_error("No width or height specified in tilemap."); - if(!reader.read_int_vector("tiles", tiles)) + if(!reader.get_vector("tiles", tiles)) throw std::runtime_error("No tiles in tilemap."); - if(int(tiles.size()) != width*height) + if(int(tiles.size()) != width*height) { throw std::runtime_error("wrong number of tiles in tilemap."); + } } TileMap::TileMap(int layer_, bool solid_, size_t width_, size_t height_) : solid(solid_), speed(1), width(0), height(0), layer(layer_), vertical_flip(false) { - tilemanager = TileManager::instance(); + tilemanager = tile_manager; resize(width_, height_); @@ -99,7 +101,7 @@ TileMap::~TileMap() } void -TileMap::write(LispWriter& writer) +TileMap::write(lisp::Writer& writer) { writer.start_list("tilemap"); @@ -182,7 +184,8 @@ void TileMap::set(int newwidth, int newheight, const std::vector&newt, int newlayer, bool newsolid) { - assert(int(newt.size()) == newwidth * newheight); + if(int(newt.size()) != newwidth * newheight) + throw std::runtime_error("Wrong tilecount count."); width = newwidth; height = newheight; diff --git a/src/object/tilemap.h b/src/object/tilemap.h index 8aa2b481a..ecf8d1030 100644 --- a/src/object/tilemap.h +++ b/src/object/tilemap.h @@ -27,12 +27,12 @@ #include "serializable.h" #include "math/vector.h" -using namespace SuperTux; - -namespace SuperTux { -class LispReader; +namespace lisp { +class Lisp; } +using namespace SuperTux; + class Level; class TileManager; class Tile; @@ -44,11 +44,11 @@ class TileMap : public GameObject, public Serializable { public: TileMap(); - TileMap(LispReader& reader); + TileMap(const lisp::Lisp& reader); TileMap(int layer_, bool solid_, size_t width_, size_t height_); virtual ~TileMap(); - virtual void write(LispWriter& writer); + virtual void write(lisp::Writer& writer); virtual void action(float elapsed_time); virtual void draw(DrawingContext& context); diff --git a/src/resources.cpp b/src/resources.cpp index 5267f4b8a..e57ee37bf 100644 --- a/src/resources.cpp +++ b/src/resources.cpp @@ -26,6 +26,7 @@ #include "gui/button.h" #include "scene.h" #include "resources.h" +#include "tile_manager.h" #include "object/gameobjs.h" #include "object/player.h" @@ -52,6 +53,7 @@ MusicRef herring_song; MusicRef level_end_song; SpriteManager* sprite_manager = 0; +TileManager* tile_manager = 0; char * soundfilenames[NUM_SOUNDS] = { "/sounds/jump.wav", @@ -114,7 +116,9 @@ void loadshared() int i; - sprite_manager = new SpriteManager(datadir + "/images/supertux.strf"); + sprite_manager = new SpriteManager( + get_resource_filename("/images/supertux.strf")); + tile_manager = new TileManager("/images/tilesets/supertux.stgt"); /* Tuxes: */ smalltux_star = sprite_manager->create("smalltux-star"); @@ -302,6 +306,8 @@ void unloadshared(void) delete sprite_manager; sprite_manager = 0; + delete tile_manager; + tile_manager = 0; } std::string get_resource_filename(const std::string& resource) diff --git a/src/resources.h b/src/resources.h index f399af88a..c152f0cee 100644 --- a/src/resources.h +++ b/src/resources.h @@ -32,6 +32,8 @@ class Font; class Surface; } +class TileManager; + /* Sound files: */ enum { SND_JUMP, @@ -73,6 +75,7 @@ extern MusicRef herring_song; extern MusicRef level_end_song; extern SpriteManager* sprite_manager; +extern TileManager* tile_manager; extern Menu* contrib_menu; extern Menu* contrib_subset_menu; diff --git a/src/sector.cpp b/src/sector.cpp index a33ad644a..abb28f938 100644 --- a/src/sector.cpp +++ b/src/sector.cpp @@ -28,12 +28,15 @@ #include "app/globals.h" #include "sector.h" -#include "utils/lispreader.h" #include "object/gameobjs.h" #include "object/camera.h" #include "object/background.h" #include "object/particlesystem.h" #include "object/tilemap.h" +#include "lisp/parser.h" +#include "lisp/lisp.h" +#include "lisp/writer.h" +#include "lisp/list_iterator.h" #include "tile.h" #include "audio/sound_manager.h" #include "gameloop.h" @@ -92,7 +95,7 @@ Sector::~Sector() } GameObject* -Sector::parse_object(const std::string& name, LispReader& reader) +Sector::parse_object(const std::string& name, const lisp::Lisp& reader) { if(name == "background") { return new Background(reader); @@ -143,32 +146,30 @@ Sector::parse_object(const std::string& name, LispReader& reader) } void -Sector::parse(LispReader& lispreader) +Sector::parse(const lisp::Lisp& sector) { _current = this; - for(lisp_object_t* cur = lispreader.get_lisp(); !lisp_nil_p(cur); - cur = lisp_cdr(cur)) { - std::string token = lisp_symbol(lisp_car(lisp_car(cur))); - // FIXME: doesn't handle empty data - lisp_object_t* data = lisp_car(lisp_cdr(lisp_car(cur))); - LispReader reader(lisp_cdr(lisp_car(cur))); - + lisp::ListIterator iter(§or); + while(iter.next()) { + const std::string& token = iter.item(); if(token == "name") { - name = lisp_string(data); + iter.value()->get(name); } else if(token == "gravity") { - gravity = lisp_real(data); + iter.value()->get(gravity); } else if(token == "music") { - song_title = lisp_string(data); + iter.value()->get(song_title); load_music(); - } else if(token == "spawn-points") { + } else if(token == "spawnpoint") { + const lisp::Lisp* spawnpoint_lisp = iter.lisp(); + SpawnPoint* sp = new SpawnPoint; - reader.read_string("name", sp->name); - reader.read_float("x", sp->pos.x); - reader.read_float("y", sp->pos.y); + spawnpoint_lisp->get("name", sp->name); + spawnpoint_lisp->get("x", sp->pos.x); + spawnpoint_lisp->get("y", sp->pos.y); spawnpoints.push_back(sp); } else { - GameObject* object = parse_object(token, reader); + GameObject* object = parse_object(token, *(iter.lisp())); if(object) { add_object(object); } @@ -188,31 +189,31 @@ Sector::parse(LispReader& lispreader) } void -Sector::parse_old_format(LispReader& reader) +Sector::parse_old_format(const lisp::Lisp& reader) { _current = this; name = "main"; - reader.read_float("gravity", gravity); + reader.get("gravity", gravity); std::string backgroundimage; - reader.read_string("background", backgroundimage); + reader.get("background", backgroundimage); float bgspeed = .5; - reader.read_float("bkgd_speed", bgspeed); + reader.get("bkgd_speed", bgspeed); bgspeed /= 100; Color bkgd_top, bkgd_bottom; int r = 0, g = 0, b = 128; - reader.read_int("bkgd_red_top", r); - reader.read_int("bkgd_green_top", g); - reader.read_int("bkgd_blue_top", b); + reader.get("bkgd_red_top", r); + reader.get("bkgd_green_top", g); + reader.get("bkgd_blue_top", b); bkgd_top.red = r; bkgd_top.green = g; bkgd_top.blue = b; - reader.read_int("bkgd_red_bottom", r); - reader.read_int("bkgd_green_bottom", g); - reader.read_int("bkgd_blue_bottom", b); + reader.get("bkgd_red_bottom", r); + reader.get("bkgd_green_bottom", g); + reader.get("bkgd_blue_bottom", b); bkgd_bottom.red = r; bkgd_bottom.green = g; bkgd_bottom.blue = b; @@ -228,15 +229,15 @@ Sector::parse_old_format(LispReader& reader) } std::string particlesystem; - reader.read_string("particle_system", particlesystem); + reader.get("particle_system", particlesystem); if(particlesystem == "clouds") add_object(new CloudParticleSystem()); else if(particlesystem == "snow") add_object(new SnowParticleSystem()); Vector startpos(100, 170); - reader.read_float("start_pos_x", startpos.x); - reader.read_float("start_pos_y", startpos.y); + reader.get("start_pos_x", startpos.x); + reader.get("start_pos_y", startpos.y); SpawnPoint* spawn = new SpawnPoint; spawn->pos = startpos; @@ -244,73 +245,63 @@ Sector::parse_old_format(LispReader& reader) spawnpoints.push_back(spawn); song_title = "Mortimers_chipdisko.mod"; - reader.read_string("music", song_title); + reader.get("music", song_title); load_music(); int width, height = 15; - reader.read_int("width", width); - reader.read_int("height", height); + reader.get("width", width); + reader.get("height", height); std::vector tiles; - if(reader.read_int_vector("interactive-tm", tiles) - || reader.read_int_vector("tilemap", tiles)) { + if(reader.get_vector("interactive-tm", tiles) + || reader.get_vector("tilemap", tiles)) { TileMap* tilemap = new TileMap(); tilemap->set(width, height, tiles, LAYER_TILES, true); add_object(tilemap); } - if(reader.read_int_vector("background-tm", tiles)) { + if(reader.get_vector("background-tm", tiles)) { TileMap* tilemap = new TileMap(); tilemap->set(width, height, tiles, LAYER_BACKGROUNDTILES, false); add_object(tilemap); } - if(reader.read_int_vector("foreground-tm", tiles)) { + if(reader.get_vector("foreground-tm", tiles)) { TileMap* tilemap = new TileMap(); tilemap->set(width, height, tiles, LAYER_FOREGROUNDTILES, false); add_object(tilemap); } // read reset-points (now spawn-points) - { - lisp_object_t* cur = 0; - if(reader.read_lisp("reset-points", cur)) { - while(!lisp_nil_p(cur)) { - lisp_object_t* data = lisp_car(cur); - LispReader reader(lisp_cdr(data)); - + const lisp::Lisp* resetpoints = reader.get_lisp("reset-points"); + if(resetpoints) { + lisp::ListIterator iter(resetpoints); + while(iter.next()) { + if(iter.item() == "point") { Vector sp_pos; - if(reader.read_float("x", sp_pos.x) && reader.read_float("y", sp_pos.y)) + if(reader.get("x", sp_pos.x) && reader.get("y", sp_pos.y)) { SpawnPoint* sp = new SpawnPoint; sp->name = "main"; sp->pos = sp_pos; spawnpoints.push_back(sp); } - - cur = lisp_cdr(cur); + } else { + std::cerr << "Unknown token '" << iter.item() << "' in reset-points.\n"; } } } // read objects - { - 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 = lisp_symbol(lisp_car(data)); - - LispReader reader(lisp_cdr(data)); - - GameObject* object = parse_object(object_type, reader); - if(object) { - add_object(object); - } else { - std::cerr << "Unknown object '" << object_type << "' in level.\n"; - } - - cur = lisp_cdr(cur); + const lisp::Lisp* objects = reader.get_lisp("objects"); + if(objects) { + lisp::ListIterator iter(objects); + while(iter.next()) { + GameObject* object = parse_object(iter.item(), *(iter.lisp())); + if(object) { + add_object(object); + } else { + std::cerr << "Unknown object '" << iter.item() << "' in level.\n"; } } } @@ -371,7 +362,7 @@ Sector::fix_old_tiles() } void -Sector::write(LispWriter& writer) +Sector::write(lisp::Writer& writer) { writer.write_string("name", name); writer.write_float("gravity", gravity); diff --git a/src/sector.h b/src/sector.h index 45a2cd539..ee0851436 100644 --- a/src/sector.h +++ b/src/sector.h @@ -32,11 +32,13 @@ using namespace SuperTux; namespace SuperTux { class GameObject; -class LispReader; -class LispWriter; class Sprite; class Rectangle; } +namespace lisp { +class Lisp; +class Writer; +} class InteractiveObject; class Background; @@ -68,10 +70,10 @@ public: ~Sector(); /// read sector from lisp file - void parse(LispReader& reader); - void parse_old_format(LispReader& reader); + void parse(const lisp::Lisp& lisp); + void parse_old_format(const lisp::Lisp& lisp); /// write sector to lisp file - void write(LispWriter& writer); + void write(lisp::Writer& writer); /// activates this sector (change music, intialize player class, ...) void activate(const std::string& spawnpoint = "main"); @@ -118,7 +120,7 @@ private: void collision_object(MovingObject* object1, MovingObject* object2); void load_music(); - GameObject* parse_object(const std::string& name, LispReader& reader); + GameObject* parse_object(const std::string& name, const lisp::Lisp& lisp); static Sector* _current; diff --git a/src/serializable.h b/src/serializable.h index 5590207e3..3fc702004 100644 --- a/src/serializable.h +++ b/src/serializable.h @@ -16,20 +16,19 @@ // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - #ifndef SUPERTUX_SERIALIZABLE_H #define SUPERTUX_SERIALIZABLE_H using namespace SuperTux; -namespace SuperTux { -class LispWriter; +namespace lisp { +class Writer; } class Serializable { public: - virtual void write(LispWriter& writer) = 0; + virtual void write(lisp::Writer& writer) = 0; }; #endif /*SUPERTUX_SERIALIZABLE_H*/ diff --git a/src/statistics.cpp b/src/statistics.cpp index 0b1498dc1..dc3e83a2e 100644 --- a/src/statistics.cpp +++ b/src/statistics.cpp @@ -19,11 +19,10 @@ #include -#include "utils/lispreader.h" -#include "utils/lispwriter.h" #include "video/drawing_context.h" #include "app/gettext.h" #include "app/globals.h" +#include "lisp/lisp.h" #include "resources.h" #include "statistics.h" @@ -70,23 +69,21 @@ Statistics::~Statistics() } void -Statistics::parse(LispReader& reader) +Statistics::parse(const lisp::Lisp& reader) { - for(int i = 0; i < NUM_STATS; i++) - { - reader.read_int(stat_name_to_string(i).c_str(), stats[i][SPLAYER]); - reader.read_int((stat_name_to_string(i) + "-total").c_str(), stats[i][STOTAL]); - } + for(int i = 0; i < NUM_STATS; i++) { + reader.get(stat_name_to_string(i).c_str(), stats[i][SPLAYER]); + reader.get((stat_name_to_string(i) + "-total").c_str(), stats[i][STOTAL]); + } } void -Statistics::write(LispWriter& writer) +Statistics::write(lisp::Writer& writer) { - for(int i = 0; i < NUM_STATS; i++) - { + for(int i = 0; i < NUM_STATS; i++) { writer.write_int(stat_name_to_string(i), stats[i][SPLAYER]); writer.write_int(stat_name_to_string(i) + "-total", stats[i][STOTAL]); - } + } } #define TOTAL_DISPLAY_TIME 3400 diff --git a/src/statistics.h b/src/statistics.h index 9f1533236..2bd87745e 100644 --- a/src/statistics.h +++ b/src/statistics.h @@ -21,12 +21,12 @@ #define SUPERTUX_STATISTICS_H #include "timer.h" +#include "lisp/lisp.h" +#include "lisp/writer.h" using namespace SuperTux; namespace SuperTux { -class LispReader; -class LispWriter; class DrawingContext; } @@ -53,9 +53,9 @@ public: ~Statistics(); /// read statistics from lisp file - void parse(LispReader& reader); + void parse(const lisp::Lisp& lisp); /// write statistics to lisp file - void write(LispWriter& writer); + void write(lisp::Writer& writer); /* Draw to the worldmap or a game message */ // TODO: make this functions working diff --git a/src/supertux.cpp b/src/supertux.cpp index 77ea138fe..0b67db768 100644 --- a/src/supertux.cpp +++ b/src/supertux.cpp @@ -94,7 +94,6 @@ int main(int argc, char * argv[]) unloadshared(); Setup::general_free(); st_menu_free(); - TileManager::destroy_instance(); #ifdef DEBUG Surface::debug_check(); #endif diff --git a/src/tile.cpp b/src/tile.cpp index 5668fa6d6..a57d3043f 100644 --- a/src/tile.cpp +++ b/src/tile.cpp @@ -25,10 +25,10 @@ #include #include "app/globals.h" +#include "lisp/lisp.h" #include "tile.h" #include "scene.h" #include "resources.h" -#include "utils/lispreader.h" #include "math/vector.h" #include "video/drawing_context.h" @@ -47,78 +47,91 @@ Tile::~Tile() } void -Tile::parse(LispReader& reader) +Tile::parse(const lisp::Lisp& reader) { - if(!reader.read_uint("id", id)) { + if(!reader.get("id", id)) { throw std::runtime_error("Missing tile-id."); } bool value; - if(reader.read_bool("solid", value) && value) + if(reader.get("solid", value) && value) attributes |= SOLID; - if(reader.read_bool("unisolid", value) && value) + if(reader.get("unisolid", value) && value) attributes |= UNISOLID | SOLID; - if(reader.read_bool("brick", value) && value) + if(reader.get("brick", value) && value) attributes |= BRICK; - if(reader.read_bool("ice", value) && value) + if(reader.get("ice", value) && value) attributes |= ICE; - if(reader.read_bool("water", value) && value) + if(reader.get("water", value) && value) attributes |= WATER; - if(reader.read_bool("spike", value) && value) + if(reader.get("spike", value) && value) attributes |= SPIKE; - if(reader.read_bool("fullbox", value) && value) + if(reader.get("fullbox", value) && value) attributes |= FULLBOX; - if(reader.read_bool("distro", value) && value) + if(reader.get("distro", value) && value) attributes |= COIN; - if(reader.read_bool("coin", value) && value) + if(reader.get("coin", value) && value) attributes |= COIN; - if(reader.read_bool("goal", value) && value) + if(reader.get("goal", value) && value) attributes |= GOAL; - reader.read_int("data", data); - reader.read_float("anim-fps", anim_fps); + if(reader.get("north", value) && value) + data |= WORLDMAP_NORTH; + if(reader.get("south", value) && value) + data |= WORLDMAP_SOUTH; + if(reader.get("west", value) && value) + data |= WORLDMAP_WEST; + if(reader.get("east", value) && value) + data |= WORLDMAP_EAST; + if(reader.get("stop", value) && value) + data |= WORLDMAP_STOP; - if(reader.read_int("slope-type", data)) { + reader.get("data", data); + reader.get("anim-fps", anim_fps); + + if(reader.get("slope-type", data)) { attributes |= SOLID | SLOPE; } - parse_images(reader.read_lisp("images")); - reader.read_string("editor-images", editor_imagefile); + const lisp::Lisp* images = reader.get_lisp("images"); + if(images) + parse_images(*images); + reader.get("editor-images", editor_imagefile); } void -Tile::parse_images(lisp_object_t* list) +Tile::parse_images(const lisp::Lisp& images_lisp) { - while(!lisp_nil_p(list)) { - lisp_object_t* cur = lisp_car(list); - if(lisp_string_p(cur)) { - imagespecs.push_back(ImageSpec(lisp_string(cur), Rectangle(0, 0, 0, 0))); - } else if(lisp_cons_p(cur) && lisp_symbol_p(lisp_car(cur))) { - lisp_object_t* sym = lisp_car(cur); - lisp_object_t* data = lisp_cdr(cur); - - if (strcmp(lisp_symbol(sym), "region") == 0) { - float x = lisp_integer(lisp_list_nth(data, 1)); - float y = lisp_integer(lisp_list_nth(data, 2)); - float width = lisp_integer(lisp_list_nth(data, 3)); - float height = lisp_integer(lisp_list_nth(data, 4)); - imagespecs.push_back(ImageSpec(lisp_string(lisp_car(data)), - Rectangle(x, y, x+width, y+height))); - } else { - std::cerr << "Tile: Type mismatch, should be '(region \"somestring\" x y w h)'" << std::endl; - continue; - } + const lisp::Lisp* list = &images_lisp; + while(list) { + const lisp::Lisp* cur = list->get_car(); + if(cur->get_type() == lisp::Lisp::TYPE_STRING) { + std::string file; + cur->get(file); + imagespecs.push_back(ImageSpec(file, Rectangle(0, 0, 0, 0))); + } else if(cur->get_type() == lisp::Lisp::TYPE_CONS && + cur->get_car()->get_type() == lisp::Lisp::TYPE_SYMBOL) { + const lisp::Lisp* ptr = cur->get_cdr(); + + std::string file; + float x, y, w, h; + ptr->get_car()->get(file); ptr = ptr->get_cdr(); + ptr->get_car()->get(x); ptr = ptr->get_cdr(); + ptr->get_car()->get(y); ptr = ptr->get_cdr(); + ptr->get_car()->get(w); ptr = ptr->get_cdr(); + ptr->get_car()->get(h); + imagespecs.push_back(ImageSpec(file, Rectangle(x, y, x+w, y+h))); } else { std::cerr << "Expected string or list in images tag.\n"; continue; } - list = lisp_cdr(list); + list = list->get_cdr(); } } void -Tile::load_images() +Tile::load_images(const std::string& tilesetpath) { assert(images.size() == 0); for(std::vector::iterator i = imagespecs.begin(); i != @@ -126,7 +139,7 @@ Tile::load_images() const ImageSpec& spec = *i; Surface* surface; std::string file - = get_resource_filename(std::string("images/tilesets/") + spec.file); + = get_resource_filename(tilesetpath + spec.file); if(spec.rect.get_width() <= 0) { surface = new Surface(file, true); } else { diff --git a/src/tile.h b/src/tile.h index ff76569a2..a5f5856fc 100644 --- a/src/tile.h +++ b/src/tile.h @@ -22,8 +22,8 @@ #include #include "video/surface.h" -#include "utils/lispreader.h" #include "math/rectangle.h" +#include "lisp/lisp.h" using namespace SuperTux; @@ -57,7 +57,17 @@ public: */ GOAL = 0x0100, /** slope tile */ - SLOPE = 0x0200 + SLOPE = 0x0200, + }; + + /// worldmap flags + enum { + WORLDMAP_NORTH = 0x0001, + WORLDMAP_SOUTH = 0x0002, + WORLDMAP_EAST = 0x0004, + WORLDMAP_WEST = 0x0008, + + WORLDMAP_STOP = 0x0010 }; private: @@ -122,11 +132,11 @@ protected: friend class TileManager; Tile(); - void load_images(); + void load_images(const std::string& tilesetpath); /// parses the tile and returns it's id number - void parse(LispReader& reader); - void parse_images(lisp_object_t* cur); + void parse(const lisp::Lisp& reader); + void parse_images(const lisp::Lisp& cur); }; #endif diff --git a/src/tile_manager.cpp b/src/tile_manager.cpp index 64cf7c06d..f2c95e09d 100644 --- a/src/tile_manager.cpp +++ b/src/tile_manager.cpp @@ -19,20 +19,22 @@ // 02111-1307, USA. #include +#include +#include #include #include "video/drawing_context.h" #include "app/setup.h" #include "app/globals.h" -#include "utils/lispreader.h" +#include "lisp/lisp.h" +#include "lisp/parser.h" +#include "lisp/list_iterator.h" #include "tile.h" #include "tile_manager.h" +#include "resources.h" #include "scene.h" -TileManager* TileManager::instance_ = 0; - -TileManager::TileManager() +TileManager::TileManager(const std::string& filename) { - std::string filename = datadir + "/images/tilesets/supertux.stgt"; load_tileset(filename); } @@ -48,64 +50,42 @@ void TileManager::load_tileset(std::string filename) for(Tiles::iterator i = tiles.begin(); i != tiles.end(); ++i) delete *i; tiles.clear(); - - lisp_object_t* root_obj = lisp_read_from_file(filename); - - if (!root_obj) - Termination::abort("Couldn't load file", filename); - - if (strcmp(lisp_symbol(lisp_car(root_obj)), "supertux-tiles") != 0) - assert(false); - lisp_object_t* cur = lisp_cdr(root_obj); - int tileset_id = 0; - - while(!lisp_nil_p(cur)) { - lisp_object_t* element = lisp_car(cur); + std::string::size_type t = filename.rfind('/'); + if(t == std::string::npos) { + tiles_path = ""; + } else { + tiles_path = filename.substr(0, t+1); + } - if (strcmp(lisp_symbol(lisp_car(element)), "tile") == 0) - { - LispReader reader(lisp_cdr(element)); + lisp::Parser parser; + std::auto_ptr root (parser.parse( + get_resource_filename(filename))); - Tile* tile = new Tile; - tile->parse(reader); + const lisp::Lisp* tiles_lisp = root->get_lisp("supertux-tiles"); + if(!tiles_lisp) + throw std::runtime_error("file is not a supertux tiles file."); - while(tile->id >= tiles.size()) { - tiles.push_back(0); - } - tiles[tile->id] = tile; - } - else if (strcmp(lisp_symbol(lisp_car(element)), "tileset") == 0) - { - LispReader reader(lisp_cdr(element)); - std::string filename; - reader.read_string("file", filename); - filename = datadir + "/images/tilesets/" + filename; - load_tileset(filename); + lisp::ListIterator iter(tiles_lisp); + while(iter.next()) { + if(iter.item() == "tile") { + Tile* tile = new Tile(); + tile->parse(*(iter.lisp())); + while(tile->id >= tiles.size()) { + tiles.push_back(0); } - else if (strcmp(lisp_symbol(lisp_car(element)), "tilegroup") == 0) - { - TileGroup new_; - LispReader reader(lisp_cdr(element)); - reader.read_string("name", new_.name); - reader.read_int_vector("tiles", new_.tiles); - tilegroups.insert(new_).first; - } - else if (strcmp(lisp_symbol(lisp_car(element)), "properties") == 0) - { - LispReader reader(lisp_cdr(element)); - reader.read_int("id", tileset_id); - tileset_id *= 1000; - } - else - { - std::cerr << "Unknown symbol: " << - lisp_symbol(lisp_car(element)) << "\n"; - } - - cur = lisp_cdr(cur); + tiles[tile->id] = tile; + } else if(iter.item() == "tilegroup") { + TileGroup tilegroup; + const lisp::Lisp* tilegroup_lisp = iter.lisp(); + tilegroup_lisp->get("name", tilegroup.name); + tilegroup_lisp->get_vector("tiles", tilegroup.tiles); + tilegroups.insert(tilegroup); + } else if(iter.item() == "properties") { + // deprecated + } else { + std::cerr << "Unknown symbol '" << iter.item() << "'.\n"; + } } - - lisp_free(root_obj); } diff --git a/src/tile_manager.h b/src/tile_manager.h index 0e5861314..db8a70ccb 100644 --- a/src/tile_manager.h +++ b/src/tile_manager.h @@ -43,21 +43,19 @@ struct TileGroup class TileManager { private: - TileManager(); - ~TileManager(); - typedef std::vector Tiles; Tiles tiles; static TileManager* instance_ ; std::set tilegroups; + + std::string tiles_path; + void load_tileset(std::string filename); public: - static TileManager* instance() - { return instance_ ? instance_ : instance_ = new TileManager(); } - static void destroy_instance() - { delete instance_; instance_ = 0; } + TileManager(const std::string& filename); + ~TileManager(); const std::set& get_tilegroups() const { @@ -74,7 +72,7 @@ public: } if(tile->images.size() == 0 && tile->imagespecs.size() != 0) - tile->load_images(); + tile->load_images(tiles_path); return tile; } diff --git a/src/title.cpp b/src/title.cpp index 714f9bd0b..1e5449ef3 100644 --- a/src/title.cpp +++ b/src/title.cpp @@ -41,11 +41,12 @@ #include "title.h" #include "video/screen.h" #include "video/surface.h" -#include "high_scores.h" #include "gui/menu.h" #include "timer.h" #include "special/frame_rate.h" #include "app/setup.h" +#include "lisp/lisp.h" +#include "lisp/parser.h" #include "level.h" #include "level_subset.h" #include "gameloop.h" @@ -127,13 +128,13 @@ void generate_contrib_menu() contrib_menu->additem(MN_HL,"",0,0); int i = 0; - for(std::set::iterator it = worldmap_list.begin(); it != worldmap_list.end(); ++it) - { + for(std::set::iterator it = worldmap_list.begin(); + it != worldmap_list.end(); ++it) { WorldMapNS::WorldMap worldmap; worldmap.loadmap((*it).c_str()); contrib_menu->additem(MN_ACTION, worldmap.get_world_title(),0,0, i); ++i; - } + } contrib_menu->additem(MN_HL,"",0,0); @@ -158,6 +159,25 @@ void generate_contrib_menu() level_subsets.clear(); } +std::string get_level_name(const std::string& filename) +{ + try { + lisp::Parser parser; + std::auto_ptr root (parser.parse(filename)); + + const lisp::Lisp* level = root->get_lisp("supertux-level"); + if(!level) + return ""; + + std::string name; + level->get("name", name); + return name; + } catch(std::exception& e) { + std::cerr << "Problem getting name of '" << filename << "'.\n"; + return ""; + } +} + void check_levels_contrib_menu() { static int current_subset = -1; @@ -214,35 +234,12 @@ void check_levels_contrib_menu() contrib_subset_menu->additem(MN_HL,"",0,0); for (int i = 0; i < subset.get_num_levels(); ++i) - { + { /** get level's title */ - std::string level_title = ""; - std::string filename = subset.get_level_filename(i); - std::string filepath; - filepath = st_dir + "/levels/" + filename; - if (access(filepath.c_str(), R_OK) != 0) - { - filepath = datadir + "/levels/" + filename; - if (access(filepath.c_str(), R_OK) != 0) - { - std::cerr << "Error: Level: couldn't find level: " << filename << std::endl; - continue; - } - } - - LispReader* reader = LispReader::load(filepath, "supertux-level"); - if(!reader) - { - std::cerr << "Error: Could not open level file. Ignoring...\n"; - continue; - } - - reader->read_string("name", level_title, true); - delete reader; - - contrib_subset_menu->additem(MN_ACTION, level_title, 0, 0, i); - } + std::string title = get_level_name(filename); + contrib_subset_menu->additem(MN_ACTION, title, 0, 0, i); + } contrib_subset_menu->additem(MN_HL,"",0,0); contrib_subset_menu->additem(MN_BACK, _("Back"), 0, 0); diff --git a/src/trigger/door.cpp b/src/trigger/door.cpp index 4c338a55f..f49371246 100644 --- a/src/trigger/door.cpp +++ b/src/trigger/door.cpp @@ -19,25 +19,25 @@ #include #include "door.h" -#include "utils/lispreader.h" -#include "utils/lispwriter.h" #include "gameloop.h" #include "resources.h" #include "special/sprite.h" #include "special/sprite_manager.h" #include "video/drawing_context.h" #include "app/globals.h" +#include "lisp/lisp.h" +#include "lisp/writer.h" using namespace SuperTux; -Door::Door(LispReader& reader) +Door::Door(const lisp::Lisp& reader) { - reader.read_float("x", bbox.p1.x); - reader.read_float("y", bbox.p1.y); + reader.get("x", bbox.p1.x); + reader.get("y", bbox.p1.y); bbox.set_size(32, 64); - reader.read_string("sector", target_sector); - reader.read_string("spawnpoint", target_spawnpoint); + reader.get("sector", target_sector); + reader.get("spawnpoint", target_spawnpoint); sprite = sprite_manager->create("door"); } @@ -58,7 +58,7 @@ Door::~Door() } void -Door::write(LispWriter& writer) +Door::write(lisp::Writer& writer) { writer.start_list("door"); diff --git a/src/trigger/door.h b/src/trigger/door.h index abcff6706..bb27cfe5a 100644 --- a/src/trigger/door.h +++ b/src/trigger/door.h @@ -30,11 +30,11 @@ class Door : public TriggerBase, public Serializable { public: - Door(LispReader& reader); + Door(const lisp::Lisp& reader); Door(int x, int y, std::string sector, std::string spawnpoint); virtual ~Door(); - virtual void write(LispWriter& writer); + virtual void write(lisp::Writer& writer); virtual void action(float elapsed_time); virtual void draw(DrawingContext& context); diff --git a/src/trigger/secretarea_trigger.cpp b/src/trigger/secretarea_trigger.cpp index b57624c39..53bbf8d0e 100644 --- a/src/trigger/secretarea_trigger.cpp +++ b/src/trigger/secretarea_trigger.cpp @@ -1,19 +1,20 @@ #include #include "secretarea_trigger.h" -#include "utils/lispwriter.h" #include "gameloop.h" +#include "lisp/lisp.h" +#include "lisp/writer.h" #define MESSAGE_TIME 3.5 //TODO: Count numbers of triggered/total secret areas -SecretAreaTrigger::SecretAreaTrigger(LispReader& reader) +SecretAreaTrigger::SecretAreaTrigger(const lisp::Lisp& reader) { - reader.read_float("x", bbox.p1.x); - reader.read_float("y", bbox.p1.y); + reader.get("x", bbox.p1.x); + reader.get("y", bbox.p1.y); bbox.set_size(32, 32); - reader.read_string("message", message); + reader.get("message", message); message_displayed = false; } @@ -30,7 +31,7 @@ SecretAreaTrigger::~SecretAreaTrigger() } void -SecretAreaTrigger::write(LispWriter& writer) +SecretAreaTrigger::write(lisp::Writer& writer) { writer.start_list("secretarea"); diff --git a/src/trigger/secretarea_trigger.h b/src/trigger/secretarea_trigger.h index 945c0619b..43b10a859 100644 --- a/src/trigger/secretarea_trigger.h +++ b/src/trigger/secretarea_trigger.h @@ -11,11 +11,11 @@ class SecretAreaTrigger : public TriggerBase, public Serializable { public: - SecretAreaTrigger(LispReader& reader); + SecretAreaTrigger(const lisp::Lisp& reader); SecretAreaTrigger(const Vector& pos); ~SecretAreaTrigger(); - void write(LispWriter& writer); + void write(lisp::Writer& writer); void event(Player& player, EventType type); void draw(DrawingContext& context); diff --git a/src/trigger/sequence_trigger.cpp b/src/trigger/sequence_trigger.cpp index 98789cd1a..91f9c9868 100644 --- a/src/trigger/sequence_trigger.cpp +++ b/src/trigger/sequence_trigger.cpp @@ -1,13 +1,19 @@ #include #include "sequence_trigger.h" -#include "utils/lispwriter.h" #include "gameloop.h" +#include "lisp/lisp.h" +#include "lisp/writer.h" -SequenceTrigger::SequenceTrigger(LispReader& reader) +SequenceTrigger::SequenceTrigger(const lisp::Lisp& reader) { - (void) reader; - // TODO + reader.get("x", bbox.p1.x); + reader.get("y", bbox.p1.y); + float w, h; + reader.get("width", w); + reader.get("height", h); + bbox.set_size(w, h); + reader.get("sequence", sequence_name); } SequenceTrigger::SequenceTrigger(const Vector& pos, const std::string& sequence) @@ -23,7 +29,7 @@ SequenceTrigger::~SequenceTrigger() } void -SequenceTrigger::write(LispWriter& writer) +SequenceTrigger::write(lisp::Writer& writer) { writer.start_list("sequencetrigger"); diff --git a/src/trigger/sequence_trigger.h b/src/trigger/sequence_trigger.h index b66e7600c..9ef1eec40 100644 --- a/src/trigger/sequence_trigger.h +++ b/src/trigger/sequence_trigger.h @@ -7,11 +7,11 @@ class SequenceTrigger : public TriggerBase, public Serializable { public: - SequenceTrigger(LispReader& reader); + SequenceTrigger(const lisp::Lisp& reader); SequenceTrigger(const Vector& pos, const std::string& sequence); ~SequenceTrigger(); - void write(LispWriter& writer); + void write(lisp::Writer& writer); void event(Player& player, EventType type); private: diff --git a/src/worldmap.cpp b/src/worldmap.cpp index 299fff515..1c4ab3e10 100644 --- a/src/worldmap.cpp +++ b/src/worldmap.cpp @@ -16,29 +16,32 @@ // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - #include #include #include #include #include +#include +#include #include #include "app/globals.h" +#include "app/gettext.h" +#include "app/setup.h" #include "video/surface.h" #include "video/screen.h" #include "video/drawing_context.h" -#include "utils/lispreader.h" -#include "utils/lispwriter.h" #include "special/frame_rate.h" +#include "audio/sound_manager.h" +#include "lisp/parser.h" +#include "lisp/lisp.h" +#include "lisp/list_iterator.h" +#include "lisp/writer.h" #include "gameloop.h" -#include "app/setup.h" #include "sector.h" #include "worldmap.h" -#include "audio/sound_manager.h" #include "resources.h" -#include "app/gettext.h" #include "misc.h" #include "scene.h" @@ -99,124 +102,6 @@ string_to_direction(const std::string& directory) return D_NONE; } -TileManager::TileManager() -{ - std::string stwt_filename = datadir + "/images/worldmap/antarctica.stwt"; - lisp_object_t* root_obj = lisp_read_from_file(stwt_filename); - - if (!root_obj) - Termination::abort("Couldn't load file", stwt_filename); - - if (strcmp(lisp_symbol(lisp_car(root_obj)), "supertux-worldmap-tiles") == 0) - { - lisp_object_t* cur = lisp_cdr(root_obj); - - while(!lisp_nil_p(cur)) - { - lisp_object_t* element = lisp_car(cur); - - if (strcmp(lisp_symbol(lisp_car(element)), "tile") == 0) - { - int id = 0; - - Tile* tile = new Tile; - tile->north = tile->east = tile->south = tile->west = true; - tile->stop = true; - tile->auto_walk = false; - - LispReader reader(lisp_cdr(element)); - reader.read_int("id", id); - - std::string temp; - reader.read_string("possible-directions", temp); - if(!temp.empty()) - { - tile->north = tile->east = tile->south = tile->west = false; - if(temp.find("north") != std::string::npos) - tile->north = true; - if(temp.find("south") != std::string::npos) - tile->south = true; - if(temp.find("east") != std::string::npos) - tile->east = true; - if(temp.find("west") != std::string::npos) - tile->west = true; - } - - /* For backward compatibility */ - reader.read_bool("north", tile->north); - reader.read_bool("south", tile->south); - reader.read_bool("west", tile->west); - reader.read_bool("east", tile->east); - - reader.read_bool("stop", tile->stop); - reader.read_bool("auto-walk", tile->auto_walk); - - reader.read_string("one-way", temp); - tile->one_way = BOTH_WAYS; - if(!temp.empty()) - { - if(temp == "north-south") - tile->one_way = NORTH_SOUTH_WAY; - else if(temp == "south-north") - tile->one_way = SOUTH_NORTH_WAY; - else if(temp == "east-west") - tile->one_way = EAST_WEST_WAY; - else if(temp == "west-east") - tile->one_way = WEST_EAST_WAY; - } - - std::vector filenames; - reader.read_string_vector("image", filenames); - - if(filenames.size() == 0) - std::cerr << "Warning: no image specified for tile " << id - << ".\nIgnoring...\n" << std::endl; - - for(int i = 0; static_cast(i) < filenames.size(); i++) - { - Surface* image = new Surface( - datadir + "/images/worldmap/" + filenames[i], true); - tile->images.push_back(image); - } - - tile->anim_fps = 1; - reader.read_float("anim-fps", tile->anim_fps); - - - if (id >= int(tiles.size())) - tiles.resize(id+1); - - tiles[id] = tile; - } - else - { - puts("Unhandled symbol"); - } - - cur = lisp_cdr(cur); - } - } - else - { - assert(0); - } - - lisp_free(root_obj); -} - -TileManager::~TileManager() -{ - for(std::vector::iterator i = tiles.begin(); i != tiles.end(); ++i) - delete *i; -} - -Tile* -TileManager::get(int i) -{ - assert(i >=0 && i < int(tiles.size())); - return tiles[i]; -} - //--------------------------------------------------------------------------- Tux::Tux(WorldMap* worldmap_) @@ -356,7 +241,7 @@ Tux::action(float delta) } } - if (worldmap->at(tile_pos)->stop || + if (worldmap->at(tile_pos)->getData() & Tile::WORLDMAP_STOP || (special_tile && !special_tile->passive_message) || worldmap->at_level()) { @@ -367,51 +252,60 @@ Tux::action(float delta) } else { - if (worldmap->at(tile_pos)->auto_walk || direction != input_direction) - { // Turn to a new direction - Tile* tile = worldmap->at(tile_pos); - - if(direction != input_direction && - ((tile->north && input_direction == D_NORTH) || - (tile->south && input_direction == D_SOUTH) || - (tile->east && input_direction == D_EAST) || - (tile->west && input_direction == D_WEST))) + const Tile* tile = worldmap->at(tile_pos); + if (direction != input_direction) + { + // Turn to a new direction + const Tile* tile = worldmap->at(tile_pos); + + if((tile->getData() & Tile::WORLDMAP_NORTH + && input_direction == D_NORTH) || + (tile->getData() & Tile::WORLDMAP_SOUTH + && input_direction == D_SOUTH) || + (tile->getData() & Tile::WORLDMAP_EAST + && input_direction == D_EAST) || + (tile->getData() & Tile::WORLDMAP_WEST + && input_direction == D_WEST)) { // player has changed direction during auto-movement - direction = input_direction; - back_direction = reverse_dir(direction); - } - else if(direction != input_direction) - { // player has changed to impossible tile + direction = input_direction; back_direction = reverse_dir(direction); - stop(); } else - { - Direction dir = D_NONE; - - if (tile->north && back_direction != D_NORTH) - dir = D_NORTH; - else if (tile->south && back_direction != D_SOUTH) - dir = D_SOUTH; - else if (tile->east && back_direction != D_EAST) - dir = D_EAST; - else if (tile->west && back_direction != D_WEST) - dir = D_WEST; - - if (dir != D_NONE) - { - direction = dir; - input_direction = direction; + { // player has changed to impossible tile back_direction = reverse_dir(direction); - } - else - { - // Should never be reached if tiledata is good stop(); - return; - } } + } + else + { + Direction dir = D_NONE; + + if (tile->getData() & Tile::WORLDMAP_NORTH + && back_direction != D_NORTH) + dir = D_NORTH; + else if (tile->getData() & Tile::WORLDMAP_SOUTH + && back_direction != D_SOUTH) + dir = D_SOUTH; + else if (tile->getData() & Tile::WORLDMAP_EAST + && back_direction != D_EAST) + dir = D_EAST; + else if (tile->getData() & Tile::WORLDMAP_WEST + && back_direction != D_WEST) + dir = D_WEST; + + if (dir != D_NONE) + { + direction = dir; + input_direction = direction; + back_direction = reverse_dir(direction); } + else + { + // Should never be reached if tiledata is good + stop(); + return; + } + } // Walk automatically to the next tile if(direction != D_NONE) @@ -433,43 +327,10 @@ Tux::action(float delta) } //--------------------------------------------------------------------------- -Tile::Tile() -{ -} - -Tile::~Tile() -{ - for(std::vector::iterator i = images.begin(); i != images.end(); i++) - delete *i; -} - - -void -Tile::draw(DrawingContext& context, Vector pos) -{ - // same code as from tile_manager.cpp draw_tile() - - if(!images.size()) - return; - - if(images.size() > 1) - { - size_t frame = size_t(global_time * anim_fps) % images.size(); - - context.draw_surface(images[frame], pos, LAYER_TILES); - } - else if (images.size() == 1) - { - context.draw_surface(images[0], pos, LAYER_TILES); - } -} - -//--------------------------------------------------------------------------- WorldMap::WorldMap() { - tile_manager = new TileManager(); - //tux = new Tux(this); + tile_manager = new TileManager("images/worldmap/antarctica.stwt"); width = 20; height = 15; @@ -507,148 +368,147 @@ WorldMap::~WorldMap() void WorldMap::load_map() { - lisp_object_t* root_obj = lisp_read_from_file(datadir + "/levels/worldmap/" + map_filename); - if (!root_obj) - Termination::abort("Couldn't load file", datadir + "/levels/worldmap/" + map_filename); - - if (strcmp(lisp_symbol(lisp_car(root_obj)), "supertux-worldmap") == 0) - { - lisp_object_t* cur = lisp_cdr(root_obj); - - while(!lisp_nil_p(cur)) - { - lisp_object_t* element = lisp_car(cur); + try { + lisp::Parser parser; + std::string filename + = get_resource_filename("/levels/worldmap/" + map_filename); + std::auto_ptr root (parser.parse(filename)); + + const lisp::Lisp* lisp = root->get_lisp("supertux-worldmap"); + if(!lisp) + throw new std::runtime_error("file isn't a supertux-worldmap file."); + + lisp::ListIterator iter(lisp->get_cdr()); + while(iter.next()) { + if(iter.item() == "tilemap") { + if(tilemap.size() > 0) + throw new std::runtime_error("multiple tilemaps specified"); + + const lisp::Lisp* tilemap_lisp = iter.lisp(); + tilemap_lisp->get("width", width); + tilemap_lisp->get("height", height); + tilemap_lisp->get_vector("data", tilemap); + } else if(iter.item() == "properties") { + const lisp::Lisp* props = iter.lisp(); + props->get("name", name); + props->get("music", music); + props->get("start_pos_x", start_x); + props->get("start_pos_y", start_y); + } else if(iter.item() == "special-tiles") { + parse_special_tiles(iter.lisp()); + } else { + std::cerr << "Unknown token '" << iter.item() << "' in worldmap.\n"; + } + } - if (strcmp(lisp_symbol(lisp_car(element)), "tilemap") == 0) - { - LispReader reader(lisp_cdr(element)); - reader.read_int("width", width); - reader.read_int("height", height); - reader.read_int_vector("data", tilemap); - } - else if (strcmp(lisp_symbol(lisp_car(element)), "properties") == 0) - { - LispReader reader(lisp_cdr(element)); - reader.read_string("name", name, true); - reader.read_string("music", music); - reader.read_int("start_pos_x", start_x); - reader.read_int("start_pos_y", start_y); - } - else if (strcmp(lisp_symbol(lisp_car(element)), "special-tiles") == 0 || - strcmp(lisp_symbol(lisp_car(element)), "levels") == 0) - { - lisp_object_t* cur = lisp_cdr(element); - - while(!lisp_nil_p(cur)) - { - lisp_object_t* element = lisp_car(cur); + delete tux; + tux = new Tux(this); + } catch(std::exception& e) { + std::stringstream msg; + msg << "Problem when parsing worldmap '" << map_filename << "': " << + e.what(); + throw std::runtime_error(msg.str()); + } +} - if (strcmp(lisp_symbol(lisp_car(element)), "special-tile") == 0) - { - SpecialTile special_tile; - LispReader reader(lisp_cdr(element)); - - reader.read_float("x", special_tile.pos.x); - reader.read_float("y", special_tile.pos.y); - - special_tile.map_message.erase(); - reader.read_string("map-message", special_tile.map_message); - special_tile.passive_message = false; - reader.read_bool("passive-message", special_tile.passive_message); - - special_tile.teleport_dest = Vector(-1,-1); - reader.read_float("teleport-to-x", special_tile.teleport_dest.x); - reader.read_float("teleport-to-y", special_tile.teleport_dest.y); - - special_tile.invisible = false; - reader.read_bool("invisible-tile", special_tile.invisible); - - special_tile.apply_action_north = special_tile.apply_action_south = - special_tile.apply_action_east = special_tile.apply_action_west = - true; - - std::string apply_direction; - reader.read_string("apply-to-direction", apply_direction); - if(!apply_direction.empty()) - { - special_tile.apply_action_north = special_tile.apply_action_south = - special_tile.apply_action_east = special_tile.apply_action_west = - false; - if(apply_direction.find("north") != std::string::npos) - special_tile.apply_action_north = true; - if(apply_direction.find("south") != std::string::npos) - special_tile.apply_action_south = true; - if(apply_direction.find("east") != std::string::npos) - special_tile.apply_action_east = true; - if(apply_direction.find("west") != std::string::npos) - special_tile.apply_action_west = true; - } - - special_tiles.push_back(special_tile); - } +void +WorldMap::parse_special_tiles(const lisp::Lisp* lisp) +{ + lisp::ListIterator iter(lisp); + while(iter.next()) { + if(iter.item() == "special-tile") { + SpecialTile special_tile; + + const lisp::Lisp* lisp = iter.lisp(); + lisp->get("x", special_tile.pos.x); + lisp->get("y", special_tile.pos.y); + lisp->get("map-message", special_tile.map_message); + special_tile.passive_message = false; + lisp->get("passive-message", special_tile.passive_message); + special_tile.teleport_dest = Vector(-1,-1); + lisp->get("teleport-to-x", special_tile.teleport_dest.x); + lisp->get("teleport-to-y", special_tile.teleport_dest.y); + special_tile.invisible = false; + lisp->get("invisible-tile", special_tile.invisible); + + special_tile.apply_action_north = true; + special_tile.apply_action_south = true; + special_tile.apply_action_east = true; + special_tile.apply_action_west = true; + + std::string apply_direction; + lisp->get("apply-to-direction", apply_direction); + if(!apply_direction.empty()) { + special_tile.apply_action_north = false; + special_tile.apply_action_south = false; + special_tile.apply_action_east = false; + special_tile.apply_action_west = false; + if(apply_direction.find("north") != std::string::npos) + special_tile.apply_action_north = true; + if(apply_direction.find("south") != std::string::npos) + special_tile.apply_action_south = true; + if(apply_direction.find("east") != std::string::npos) + special_tile.apply_action_east = true; + if(apply_direction.find("west") != std::string::npos) + special_tile.apply_action_west = true; + } + + special_tiles.push_back(special_tile); + } else if(iter.item() == "level") { + Level level; - else if (strcmp(lisp_symbol(lisp_car(element)), "level") == 0) - { - Level level; - LispReader reader(lisp_cdr(element)); - level.solved = false; + lisp::Lisp* level_lisp = iter.lisp(); + level.solved = false; - level.north = true; - level.east = true; - level.south = true; - level.west = true; + level.north = true; + level.east = true; + level.south = true; + level.west = true; - reader.read_string("extro-filename", level.extro_filename); - reader.read_string("next-worldmap", level.next_worldmap); + level_lisp->get("extro-filename", level.extro_filename); + level_lisp->get("next-worldmap", level.next_worldmap); - level.quit_worldmap = false; - reader.read_bool("quit-worldmap", level.quit_worldmap); + level.quit_worldmap = false; + level_lisp->get("quit-worldmap", level.quit_worldmap); - reader.read_string("name", level.name, true); - reader.read_float("x", level.pos.x); - reader.read_float("y", level.pos.y); + level_lisp->get("name", level.name); + level_lisp->get("x", level.pos.x); + level_lisp->get("y", level.pos.y); - level.auto_path = true; - reader.read_bool("auto-path", level.auto_path); + level.auto_path = true; + level_lisp->get("auto-path", level.auto_path); - level.vertical_flip = false; - reader.read_bool("vertical-flip", level.vertical_flip); + level.vertical_flip = false; + level_lisp->get("vertical-flip", level.vertical_flip); - levels.push_back(level); - } - - cur = lisp_cdr(cur); - } - } - else - { - - } - - cur = lisp_cdr(cur); - } + levels.push_back(level); + } else { + std::cerr << "Unknown token '" << iter.item() << + "' in worldmap special-tiles list."; } - - lisp_free(root_obj); - - delete tux; - tux = new Tux(this); + } } -void WorldMap::get_level_title(Level& level) +void +WorldMap::get_level_title(Level& level) { /** get special_tile's title */ level.title = ""; - LispReader* reader = LispReader::load(datadir + "/levels/" + level.name, "supertux-level"); - if(!reader) - { - std::cerr << "Error: Could not open level file. Ignoring...\n"; - return; - } + try { + lisp::Parser parser; + std::auto_ptr root ( + parser.parse(get_resource_filename("levels/" + level.name))); - reader->read_string("name", level.title, true); - delete reader; + const lisp::Lisp* level_lisp = root->get_lisp("supertux-level"); + if(!level_lisp) + return; + + level_lisp->get("name", level.title); + } catch(std::exception& e) { + std::cerr << "Problem when reading leveltitle: " << e.what() << "\n"; + return; + } } void WorldMap::calculate_total_stats() @@ -792,31 +652,25 @@ WorldMap::path_ok(Direction direction, Vector old_pos, Vector* new_pos) { // New position is outsite the tilemap return false; } - else if(at(*new_pos)->one_way != BOTH_WAYS) - { -std::cerr << "one way only\n"; - if((at(*new_pos)->one_way == NORTH_SOUTH_WAY && direction != D_SOUTH) || - (at(*new_pos)->one_way == SOUTH_NORTH_WAY && direction != D_NORTH) || - (at(*new_pos)->one_way == EAST_WEST_WAY && direction != D_WEST) || - (at(*new_pos)->one_way == WEST_EAST_WAY && direction != D_EAST)) - return false; - return true; - } else - { // Check if we the tile allows us to go to new_pos + { // Check if the tile allows us to go to new_pos switch(direction) { case D_WEST: - return (at(old_pos)->west && at(*new_pos)->east); + return (at(old_pos)->getData() & Tile::WORLDMAP_WEST + && at(*new_pos)->getData() & Tile::WORLDMAP_EAST); case D_EAST: - return (at(old_pos)->east && at(*new_pos)->west); + return (at(old_pos)->getData() & Tile::WORLDMAP_EAST + && at(*new_pos)->getData() & Tile::WORLDMAP_WEST); case D_NORTH: - return (at(old_pos)->north && at(*new_pos)->south); + return (at(old_pos)->getData() & Tile::WORLDMAP_NORTH + && at(*new_pos)->getData() & Tile::WORLDMAP_SOUTH); case D_SOUTH: - return (at(old_pos)->south && at(*new_pos)->north); + return (at(old_pos)->getData() & Tile::WORLDMAP_SOUTH + && at(*new_pos)->getData() & Tile::WORLDMAP_NORTH); case D_NONE: assert(!"path_ok() can't work if direction is NONE"); @@ -850,121 +704,127 @@ WorldMap::update(float delta) if (!level) { std::cout << "No level to enter at: " - << tux->get_tile_pos().x << ", " << tux->get_tile_pos().y << std::endl; + << tux->get_tile_pos().x << ", " << tux->get_tile_pos().y + << std::endl; return; } - if (level->pos == tux->get_tile_pos()) + if (level->pos == tux->get_tile_pos()) + { + PlayerStatus old_player_status = player_status; + + std::cout << "Enter the current level: " << level->name << std::endl; + // do a shriking fade to the level + shrink_fade(Vector((level->pos.x*32 + 16 + offset.x), + (level->pos.y*32 + 16 + offset.y)), 500); + GameSession session( + get_resource_filename(std::string("levels/" + level->name)), + ST_GL_LOAD_LEVEL_FILE, &level->statistics); + + switch (session.run()) { - PlayerStatus old_player_status = player_status; + case GameSession::ES_LEVEL_FINISHED: + { + level_finished = true; + bool old_level_state = level->solved; + level->solved = true; + + // deal with statistics + level->statistics.merge(global_stats); + calculate_total_stats(); + + if (session.get_current_sector()->player->got_power != + session.get_current_sector()->player->NONE_POWER) + player_status.bonus = PlayerStatus::FLOWER_BONUS; + else if (session.get_current_sector()->player->size == BIG) + player_status.bonus = PlayerStatus::GROWUP_BONUS; + else + player_status.bonus = PlayerStatus::NO_BONUS; - std::cout << "Enter the current level: " << level->name << std::endl; - // do a shriking fade to the level - shrink_fade(Vector((level->pos.x*32 + 16 + offset.x),(level->pos.y*32 + 16 - + offset.y)), 500); - GameSession session( - get_resource_filename(std::string("levels/" + level->name)), - ST_GL_LOAD_LEVEL_FILE, &level->statistics); + if (old_level_state != level->solved && level->auto_path) + { // Try to detect the next direction to which we should walk + // FIXME: Mostly a hack + Direction dir = D_NONE; + + const Tile* tile = at(tux->get_tile_pos()); - switch (session.run()) - { - case GameSession::ES_LEVEL_FINISHED: - { - level_finished = true; - bool old_level_state = level->solved; - level->solved = true; - - // deal with statistics - level->statistics.merge(global_stats); - calculate_total_stats(); - - if (session.get_current_sector()->player->got_power != - session.get_current_sector()->player->NONE_POWER) - player_status.bonus = PlayerStatus::FLOWER_BONUS; - else if (session.get_current_sector()->player->size == BIG) - player_status.bonus = PlayerStatus::GROWUP_BONUS; - else - player_status.bonus = PlayerStatus::NO_BONUS; - - if (old_level_state != level->solved && level->auto_path) - { // Try to detect the next direction to which we should walk - // FIXME: Mostly a hack - Direction dir = D_NONE; - - Tile* tile = at(tux->get_tile_pos()); - - if (tile->north && tux->back_direction != D_NORTH) - dir = D_NORTH; - else if (tile->south && tux->back_direction != D_SOUTH) - dir = D_SOUTH; - else if (tile->east && tux->back_direction != D_EAST) - dir = D_EAST; - else if (tile->west && tux->back_direction != D_WEST) - dir = D_WEST; - - if (dir != D_NONE) - { - tux->set_direction(dir); - //tux->update(delta); - } - - std::cout << "Walk to dir: " << dir << std::endl; + if (tile->getData() & Tile::WORLDMAP_NORTH + && tux->back_direction != D_NORTH) + dir = D_NORTH; + else if (tile->getData() & Tile::WORLDMAP_SOUTH + && tux->back_direction != D_SOUTH) + dir = D_SOUTH; + else if (tile->getData() & Tile::WORLDMAP_EAST + && tux->back_direction != D_EAST) + dir = D_EAST; + else if (tile->getData() & Tile::WORLDMAP_WEST + && tux->back_direction != D_WEST) + dir = D_WEST; + + if (dir != D_NONE) + { + tux->set_direction(dir); + //tux->update(delta); } + + std::cout << "Walk to dir: " << dir << std::endl; } + } - break; - case GameSession::ES_LEVEL_ABORT: - level_finished = false; - /* In case the player's abort the level, keep it using the old - status. But the minimum lives and no bonus. */ - player_status.distros = old_player_status.distros; - player_status.lives = std::min(old_player_status.lives, player_status.lives); - player_status.bonus = player_status.NO_BONUS; - - break; - case GameSession::ES_GAME_OVER: - { - level_finished = false; - /* draw an end screen */ - /* TODO: in the future, this should make a dialog a la SuperMario, asking - if the player wants to restart the world map with no score and from - level 1 */ - char str[80]; + break; + case GameSession::ES_LEVEL_ABORT: + level_finished = false; + /* In case the player's abort the level, keep it using the old + status. But the minimum lives and no bonus. */ + player_status.distros = old_player_status.distros; + player_status.lives = std::min(old_player_status.lives, player_status.lives); + player_status.bonus = player_status.NO_BONUS; - DrawingContext context; - context.draw_gradient(Color (200,240,220), Color(200,200,220), - LAYER_BACKGROUND0); + break; + case GameSession::ES_GAME_OVER: + { + level_finished = false; + /* draw an end screen */ + /* TODO: in the future, this should make a dialog a la SuperMario, asking + if the player wants to restart the world map with no score and from + level 1 */ + char str[80]; - context.draw_text(blue_text, _("GAMEOVER"), - Vector(screen->w/2, 200), CENTER_ALLIGN, LAYER_FOREGROUND1); + DrawingContext context; + context.draw_gradient(Color (200,240,220), Color(200,200,220), + LAYER_BACKGROUND0); - sprintf(str, _("COINS: %d"), player_status.distros); - context.draw_text(gold_text, str, - Vector(screen->w/2, screen->w - 32), CENTER_ALLIGN, LAYER_FOREGROUND1); + context.draw_text(blue_text, _("GAMEOVER"), + Vector(screen->w/2, 200), CENTER_ALLIGN, LAYER_FOREGROUND1); - total_stats.draw_message_info(context, _("Total Statistics")); + sprintf(str, _("COINS: %d"), player_status.distros); + context.draw_text(gold_text, str, + Vector(screen->w/2, screen->w - 32), CENTER_ALLIGN, + LAYER_FOREGROUND1); - context.do_drawing(); - - SDL_Event event; - wait_for_event(event,2000,6000,true); + total_stats.draw_message_info(context, _("Total Statistics")); - quit = true; - player_status.reset(); - break; - } - case GameSession::ES_NONE: - assert(false); - // Should never be reached - break; - } + context.do_drawing(); - SoundManager::get()->play_music(song); - Menu::set_current(0); - if (!savegame_file.empty()) - savegame(savegame_file); + SDL_Event event; + wait_for_event(event,2000,6000,true); + + quit = true; + player_status.reset(); + break; + } + case GameSession::ES_NONE: + assert(false); + // Should never be reached + break; } + + SoundManager::get()->play_music(song); + Menu::set_current(0); + if (!savegame_file.empty()) + savegame(savegame_file); + } /* The porpose of the next checking is that if the player lost the level (in case there is one), don't show anything */ if(level_finished) @@ -972,7 +832,8 @@ WorldMap::update(float delta) if (!level->extro_filename.empty()) { // Display a text file - display_text_file(level->extro_filename, SCROLL_SPEED_MESSAGE, white_big_text , white_text, white_small_text, blue_text ); + display_text_file(level->extro_filename, SCROLL_SPEED_MESSAGE, + white_big_text , white_text, white_small_text, blue_text ); } if (!level->next_worldmap.empty()) @@ -1013,7 +874,7 @@ WorldMap::update(float delta) } } -Tile* +const Tile* WorldMap::at(Vector p) { assert(p.x >= 0 @@ -1057,8 +918,9 @@ WorldMap::draw(DrawingContext& context, const Vector& offset) for(int y = 0; y < height; ++y) for(int x = 0; x < width; ++x) { - Tile* tile = at(Vector(x, y)); - tile->draw(context, Vector(x*32 + offset.x, y*32 + offset.y)); + const Tile* tile = at(Vector(x, y)); + tile->draw(context, Vector(x*32 + offset.x, y*32 + offset.y), + LAYER_TILES); } for(Levels::iterator i = levels.begin(); i != levels.end(); ++i) @@ -1227,59 +1089,59 @@ WorldMap::savegame(const std::string& filename) std::cout << "savegame: " << filename << std::endl; - std::ofstream file(filename.c_str(), std::ios::out); - LispWriter* writer = new LispWriter(file); + std::ofstream file(filename.c_str(), std::ios::out); + lisp::Writer writer(file); int nb_solved_levels = 0, total_levels = 0; - for(Levels::iterator i = levels.begin(); i != levels.end(); ++i) - { - ++total_levels; - if (i->solved) - ++nb_solved_levels; - } + for(Levels::iterator i = levels.begin(); i != levels.end(); ++i) { + ++total_levels; + if (i->solved) + ++nb_solved_levels; + } char nb_solved_levels_str[80], total_levels_str[80]; sprintf(nb_solved_levels_str, "%d", nb_solved_levels); sprintf(total_levels_str, "%d", total_levels); - writer->write_comment("Worldmap save file"); + writer.write_comment("Worldmap save file"); - writer->start_list("supertux-savegame"); + writer.start_list("supertux-savegame"); - writer->write_int("version", 1); - writer->write_string("title", std::string(name + " - " + nb_solved_levels_str + "/" + total_levels_str)); - writer->write_string("map", map_filename); - writer->write_int("lives", player_status.lives); - writer->write_int("distros", player_status.lives); - writer->write_int("max-score-multiplier", player_status.max_score_multiplier); + writer.write_int("version", 1); + writer.write_string("title", + std::string(name + " - " + nb_solved_levels_str+"/"+total_levels_str)); + writer.write_string("map", map_filename); + writer.write_int("lives", player_status.lives); + writer.write_int("distros", player_status.lives); + writer.write_int("max-score-multiplier", player_status.max_score_multiplier); - writer->start_list("tux"); + writer.start_list("tux"); - writer->write_float("x", tux->get_tile_pos().x); - writer->write_float("y", tux->get_tile_pos().y); - writer->write_string("back", direction_to_string(tux->back_direction)); - writer->write_string("bonus", bonus_to_string(player_status.bonus)); + writer.write_float("x", tux->get_tile_pos().x); + writer.write_float("y", tux->get_tile_pos().y); + writer.write_string("back", direction_to_string(tux->back_direction)); + writer.write_string("bonus", bonus_to_string(player_status.bonus)); - writer->end_list("tux"); + writer.end_list("tux"); - writer->start_list("levels"); + writer.start_list("levels"); for(Levels::iterator i = levels.begin(); i != levels.end(); ++i) { if (i->solved) { - writer->start_list("level"); + writer.start_list("level"); - writer->write_string("name", i->name); - writer->write_bool("solved", true); - i->statistics.write(*writer); + writer.write_string("name", i->name); + writer.write_bool("solved", true); + i->statistics.write(writer); - writer->end_list("level"); + writer.end_list("level"); } } - writer->end_list("levels"); + writer.end_list("levels"); - writer->end_list("supertux-savegame"); + writer.end_list("supertux-savegame"); } void @@ -1288,98 +1150,75 @@ WorldMap::loadgame(const std::string& filename) std::cout << "loadgame: " << filename << std::endl; savegame_file = filename; - if (access(filename.c_str(), F_OK) != 0) - { - load_map(); - - player_status.reset(); - - return; - } + try { + lisp::Parser parser; + std::auto_ptr root (parser.parse(filename)); - lisp_object_t* savegame = lisp_read_from_file(filename); - if (!savegame) - { - std::cout << "WorldMap:loadgame: File not found: " << filename << std::endl; - load_map(); - return; - } - - lisp_object_t* cur = savegame; + const lisp::Lisp* savegame = root->get_lisp("supertux-savegame"); + if(!savegame) + throw std::runtime_error("File is not a supertux-savegame file."); - if (strcmp(lisp_symbol(lisp_car(cur)), "supertux-savegame") != 0) - { - load_map(); - return; - } - - cur = lisp_cdr(cur); - LispReader reader(cur); - - /* Get the Map filename and then load it before setting level settings */ - std::string cur_map_filename = map_filename; - reader.read_string("map", map_filename); -// if(cur_map_filename != map_filename) + /* Get the Map filename and then load it before setting level settings */ + std::string cur_map_filename = map_filename; + savegame->get("map", map_filename); load_map(); - reader.read_int("lives", player_status.lives); - reader.read_int("distros", player_status.distros); - reader.read_int("max-score-multiplier", player_status.max_score_multiplier); + savegame->get("lives", player_status.lives); + savegame->get("distros", player_status.distros); + savegame->get("max-score-multiplier", player_status.max_score_multiplier); + if (player_status.lives < 0) + player_status.lives = START_LIVES; - if (player_status.lives < 0) - player_status.lives = START_LIVES; - - lisp_object_t* tux_cur = 0; - if (reader.read_lisp("tux", tux_cur)) + const lisp::Lisp* tux_lisp = savegame->get_lisp("tux"); + if(tux) { Vector p; std::string back_str = "none"; std::string bonus_str = "none"; - LispReader tux_reader(tux_cur); - tux_reader.read_float("x", p.x); - tux_reader.read_float("y", p.y); - tux_reader.read_string("back", back_str); - tux_reader.read_string("bonus", bonus_str); + tux_lisp->get("x", p.x); + tux_lisp->get("y", p.y); + tux_lisp->get("back", back_str); + tux_lisp->get("bonus", bonus_str); player_status.bonus = string_to_bonus(bonus_str); tux->back_direction = string_to_direction(back_str); tux->set_tile_pos(p); } - lisp_object_t* level_cur = 0; - if (reader.read_lisp("levels", level_cur)) - { - while(level_cur) - { - lisp_object_t* sym = lisp_car(lisp_car(level_cur)); - lisp_object_t* data = lisp_cdr(lisp_car(level_cur)); - - if (strcmp(lisp_symbol(sym), "level") == 0) - { - std::string name; - bool solved = false; + const lisp::Lisp* levels_lisp = savegame->get_lisp("levels"); + if(levels_lisp) { + lisp::ListIterator iter(levels_lisp); + while(iter.next()) { + if(iter.item() == "level") { + std::string name; + bool solved = false; - LispReader level_reader(data); - level_reader.read_string("name", name); - level_reader.read_bool("solved", solved); + const lisp::Lisp* level = iter.lisp(); + level->get("name", name); + level->get("solved", solved); - for(Levels::iterator i = levels.begin(); i != levels.end(); ++i) - { - if (name == i->name) - { - i->solved = solved; - i->statistics.parse(level_reader); - break; - } - } + for(Levels::iterator i = levels.begin(); i != levels.end(); ++i) + { + if (name == i->name) + { + i->solved = solved; + i->statistics.parse(*level); + break; } - - level_cur = lisp_cdr(level_cur); + } + } else { + std::cerr << "Unknown token '" << iter.item() + << "' in levels block in worldmap.\n"; } + } } - - lisp_free(savegame); + } catch(std::exception& e) { + std::cerr << "Problem loading game '" << filename << "': " << e.what() + << "\n"; + load_map(); + player_status.reset(); + } calculate_total_stats(); } diff --git a/src/worldmap.h b/src/worldmap.h index 4bf2b69ce..80585ea22 100644 --- a/src/worldmap.h +++ b/src/worldmap.h @@ -25,8 +25,10 @@ #include "math/vector.h" #include "audio/musicref.h" #include "video/screen.h" +#include "lisp/lisp.h" #include "statistics.h" #include "timer.h" +#include "tile_manager.h" namespace SuperTux { class Menu; @@ -39,7 +41,7 @@ namespace WorldMapNS { enum WorldMapMenuIDs { MNID_RETURNWORLDMAP, MNID_QUITWORLDMAP - }; +}; // For one way tiles enum { @@ -48,47 +50,6 @@ enum { SOUTH_NORTH_WAY, EAST_WEST_WAY, WEST_EAST_WAY - }; - -class Tile -{ -public: - Tile(); - ~Tile(); - - void draw(DrawingContext& context, Vector pos); - - std::vector images; - float anim_fps; - - // Directions in which Tux is allowed to walk from this tile - bool north; - bool east; - bool south; - bool west; - - /** One way tile */ - int one_way; - - /** Stop on this tile or walk over it? */ - bool stop; - - /** When set automatically turn directions when walked over such a - tile (ie. walk smoothly a curve) */ - bool auto_walk; -}; - -class TileManager -{ -private: - typedef std::vector Tiles; - Tiles tiles; - -public: - TileManager(); - ~TileManager(); - - Tile* get(int i); }; enum Direction { D_NONE, D_WEST, D_EAST, D_NORTH, D_SOUTH }; @@ -265,7 +226,7 @@ public: void draw(DrawingContext& context, const Vector& offset); Vector get_next_tile(Vector pos, Direction direction); - Tile* at(Vector pos); + const Tile* at(Vector pos); WorldMap::Level* at_level(); WorldMap::SpecialTile* at_special_tile(); @@ -296,6 +257,7 @@ public: private: void on_escape_press(); + void parse_special_tiles(const lisp::Lisp* lisp); }; } // namespace WorldMapNS