5f7cc094767159832ce7c79fea12040a83088dea
[supertux.git] / src / object / path.cpp
1 //  $Id$
2 //
3 //  SuperTux Path
4 //  Copyright (C) 2005 Philipp <balinor@pnxs.de>
5 //  Copyright (C) 2006 Christoph Sommer <christoph.sommer@2006.expires.deltadevelopment.de>
6 //  Copyright (C) 2006 Matthias Braun <matze@braunis.de>
7 //
8 //  This program is free software; you can redistribute it and/or
9 //  modify it under the terms of the GNU General Public License
10 //  as published by the Free Software Foundation; either version 2
11 //  of the License, or (at your option) any later version.
12 //
13 //  This program is distributed in the hope that it will be useful,
14 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
15 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 //  GNU General Public License for more details.
17 //
18 //  You should have received a copy of the GNU General Public License
19 //  along with this program; if not, write to the Free Software
20 //  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
21 //  02111-1307, USA.
22 #include <config.h>
23
24 #include "path.hpp"
25
26 #include "lisp/lisp.hpp"
27 #include "lisp/list_iterator.hpp"
28 #include "object_factory.hpp"
29 #include "log.hpp"
30
31 #include <assert.h>
32 #include <iostream>
33 #include <stdexcept>
34 #include <sstream>
35
36 Path::Path()
37 {
38 }
39
40 Path::~Path()
41 {
42 }
43
44 void
45 Path::read(const lisp::Lisp& reader)
46 {
47   lisp::ListIterator iter(&reader);
48
49   mode = CIRCULAR;
50   while(iter.next()) {
51     if(iter.item() == "mode") {
52       std::string mode_string;
53       if(!iter.value()->get(mode_string))
54         throw std::runtime_error("Pathmode not a string");
55
56       if(mode_string == "oneshot")
57         mode = ONE_SHOT;
58       else if(mode_string == "pingpong")
59         mode = PING_PONG;
60       else if(mode_string == "circular")
61         mode = CIRCULAR;
62       else {
63         std::ostringstream msg;
64         msg << "Unknown pathmode '" << mode_string << "' found";
65         throw std::runtime_error(msg.str());
66       }
67       continue;
68     }
69     
70     if(iter.item() != "node") {
71       log_warning << "unknown token '" << iter.item() << "' in Path nodes list. Ignored." << std::endl;
72       continue;
73     }
74     const lisp::Lisp* node_lisp = iter.lisp();
75
76     // each new node will inherit all values from the last one
77     Node node;
78     node.time = 1;
79     if( (!node_lisp->get("x", node.position.x) ||
80           !node_lisp->get("y", node.position.y)))
81       throw std::runtime_error("Path node without x and y coordinate specified");
82     node_lisp->get("time", node.time);
83
84     if(node.time <= 0)
85       throw std::runtime_error("Path node with non-positive time");
86
87     nodes.push_back(node);
88   }
89
90   if (nodes.empty())
91     throw std::runtime_error("Path with zero nodes");
92 }
93
94 void
95 Path::write(lisp::Writer& writer)
96 {
97   writer.start_list("path");
98
99   switch(mode) {
100     case ONE_SHOT:
101       writer.write_string("mode", "oneshot");
102       break;
103     case PING_PONG:
104       writer.write_string("mode", "pingpong");
105       break;
106     case CIRCULAR:
107       writer.write_string("mode", "circular");
108       break;
109     default:
110       log_warning << "Don't know how to write mode " << (int) mode << " ?!?" << std::endl;
111       break;
112   }
113
114   for (size_t i=0; i < nodes.size(); i++) {
115     const Node& node = nodes[i];
116
117     writer.start_list("node");
118     writer.write_float("x", node.position.x);
119     writer.write_float("y", node.position.y);
120     writer.write_float("time", node.time);
121
122     writer.end_list("node");
123   }
124
125   writer.end_list("path");
126 }
127
128 Vector
129 Path::get_base() const
130 {
131   if(nodes.empty())
132     return Vector(0, 0);
133   
134   return nodes[0].position;
135 }
136