initial commit, lordsawar source, slightly modified
[lordsawar] / src / LocationList.h
1 // Copyright (C) 2001, 2003 Michael Bartl
2 // Copyright (C) 2004 Ulf Lorenz
3 // Copyright (C) 2005, 2006 Andrea Paternesi
4 // Copyright (C) 2007, 2008, 2009 Ben Asselstine
5 // Copyright (C) 2008 Ole Laursen
6 //
7 //  This program is free software; you can redistribute it and/or modify
8 //  it under the terms of the GNU General Public License as published by
9 //  the Free Software Foundation; either version 3 of the License, or
10 //  (at your option) any later version.
11 //
12 //  This program is distributed in the hope that it will be useful,
13 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
14 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 //  GNU Library General Public License for more details.
16 //
17 //  You should have received a copy of the GNU General Public License
18 //  along with this program; if not, write to the Free Software
19 //  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 
20 //  02110-1301, USA.
21
22 #ifndef LOCATIONLIST_H
23 #define LOCATIONLIST_H
24
25 #include <gtkmm.h>
26 #include <algorithm>
27 #include <list>
28 #include <map>
29 #include "PathCalculator.h"
30 #include "vector.h"
31 class Stack;
32
33 /** A list for object instances
34   * 
35   * This class extends the stl lists by adding the functions getObjectAt()
36   * which return the object at position (x,y). Necessary for such things as
37   * the city list.
38   */
39
40 using namespace std;
41   
42 template<class T> class LocationList : public std::list<T>
43 {
44  public:
45   
46   LocationList(){};  
47   ~LocationList() 
48     {
49       for (typename LocationList<T>::iterator it = this->begin(); it != this->end(); ++it)
50         delete *it;
51       d_object.clear();
52       d_id.clear();
53     };
54
55   void add(T t)
56     {
57       push_back(t);
58       d_id[t->getId()] = t;
59       int size = t->getSize();
60       for (int i = 0; i < size; i++)
61         for (int j = 0; j < size; j++)
62           {
63             Vector<int> pos = t->getPos() + Vector<int>(i,j);
64             d_object[pos] = t;
65           }
66     }
67   void subtract(T t)
68     {
69       this->erase(std::find(this->begin(), this->end(), t));
70       d_id.erase(d_id.find(t->getId()));
71       int size = t->getSize();
72       for (int i = 0; i < size; i++)
73         for (int j = 0; j < size; j++)
74           {
75             Vector<int> pos = t->getPos() + Vector<int>(i,j);
76             d_object.erase(d_object.find(pos));
77           }
78       delete t;
79     }
80
81   //! Returns the object at position (x,y).  
82   T getObjectAt(int x, int y) const
83     {
84       Vector<int> pos = Vector<int>(x,y);
85   
86       if (d_object.find(pos) == d_object.end())
87         return NULL;
88       else
89         return (*d_object.find(pos)).second;
90     }
91
92   //! Returns the object at position pos.  
93   T getObjectAt(const Vector<int>& pos) const
94     {
95       return getObjectAt(pos.x, pos.y);
96     }
97
98   T getNearestObjectInDir(const Vector<int> &pos, const Vector<int> dir) const
99     {
100       int diff = -1;
101       typename LocationList<T>::const_iterator diffit;
102       for (typename LocationList<T>::const_iterator it = this->begin(); it != this->end(); ++it)
103         {
104           Vector<int> p = (*it)->getPos();
105           int delta = abs(p.x - pos.x) + abs(p.y - pos.y);
106           //if dir is -1, then the difference between pos.x and p.x should be positive
107           //if dir is +1, then the difference between pos.x and p.x should be negative
108           //if looking west, and the object is to the east
109           if (dir.x < 0 && (pos.x - p.x) <= 0)
110             continue;
111           //if looking east , and the object is to the west
112           if (dir.x > 0 && (pos.x - p.x) >= 0)
113             continue;
114           //if looking north, and the object is to the south
115           if (dir.y < 0 && (pos.y - p.y) <= 0)
116             continue;
117           //if looking south, and the object is to the north
118           if (dir.y > 0 && (pos.y - p.y) >= 0)
119             continue;
120
121           if ((diff > delta) || (diff == -1))
122             {
123               diff = delta;
124               diffit = it;
125             }
126         }
127       if (diff == -1) return 0;
128       return (*diffit);
129     }
130
131   T getClosestObject (const Stack *stack, std::list<bool (*)(void*)> *filters) const
132     {
133       int diff = -1;
134       typename LocationList<T>::const_iterator diffit;
135       PathCalculator pc(stack, true, 0, 0);
136       for (typename LocationList<T>::const_iterator it = this->begin(); it != this->end(); ++it)
137         {
138           int delta = pc.calculate((*it)->getPos());
139           if (delta <= 0)
140             continue;
141           if (filters)
142             {
143               std::list<bool (*)(void*)>::iterator fit = filters->begin();
144               bool filtered = false;
145               for (; fit != filters->end(); fit++)
146                 {
147                   if ((*fit)(*it) == true)
148                     {
149                       filtered = true;
150                       break;
151                     }
152                     
153                 }
154               if (filtered)
155                 continue;
156             }
157
158           if ((diff > delta) || (diff == -1))
159             {
160               diff = delta;
161               diffit = it;
162             }
163         }
164       if (diff == -1) return 0;
165       return (*diffit);
166     }
167
168   T getClosestObject (const Stack *stack) const
169     {
170       return getClosestObject (stack, NULL);
171     }
172
173   T getNearestObject (const Vector<int>& pos, std::list<bool (*)(void*)> *filters) const
174     {
175       int diff = -1;
176       typename LocationList<T>::const_iterator diffit;
177       for (typename LocationList<T>::const_iterator it = this->begin(); it != this->end(); ++it)
178         {
179           Vector<int> p = (*it)->getPos();
180           int delta = abs(p.x - pos.x) + abs(p.y - pos.y);
181           if (filters)
182             {
183               std::list<bool (*)(void*)>::iterator fit = filters->begin();
184               bool filtered = false;
185               for (; fit != filters->end(); fit++)
186                 {
187                   if ((*fit)(*it) == true)
188                     {
189                       filtered = true;
190                       break;
191                     }
192                     
193                 }
194               if (filtered)
195                 continue;
196             }
197
198           if ((diff > delta) || (diff == -1))
199             {
200               diff = delta;
201               diffit = it;
202             }
203         }
204       if (diff == -1) return 0;
205       return (*diffit);
206     }
207
208   T getNearestObject (const Vector<int>& pos) const
209     {
210       return getNearestObject (pos, NULL);
211     }
212
213   T getNearestObjectBefore (const Vector<int>& pos, int dist) const
214     {
215       T t = getNearestObject(pos);
216       if (!t)
217         return NULL;
218       if (t->getPos().x <= pos.x + dist && t->getPos().x >= pos.x - dist &&
219           t->getPos().y <= pos.y + dist && t->getPos().y >= pos.y - dist)
220         return t;
221       return NULL;
222     }
223
224   T getNearestObjectAfter(const Vector<int>& pos, int dist, 
225                            std::list<bool (*)(void*)> *filters) const
226     {
227       int diff = -1;
228       typename LocationList<T>::const_iterator diffit;
229
230       for (typename LocationList<T>::const_iterator it = this->begin(); it != this->end(); ++it)
231         {
232           if (filters)
233             {
234               std::list<bool (*)(void*)>::iterator fit = filters->begin();
235               bool filtered = false;
236               for (; fit != filters->end(); fit++)
237                 {
238                   if ((*fit)(*it) == true)
239                     {
240                       filtered = true;
241                       break;
242                     }
243                     
244                 }
245               if (filtered)
246                 continue;
247             }
248           
249             Vector<int> p = (*it)->getPos();
250             int delta = abs(p.x - pos.x);
251             if (delta < abs(p.y - pos.y))
252                 delta = abs(p.y - pos.y);
253           
254             if ((diff > delta && delta >= dist) || (diff == -1))
255               {
256                 diff = delta;
257                 diffit = it;
258               }
259         }
260     
261       if (diff == -1) return 0;
262       return (*diffit);
263     }
264
265   T getById(guint32 id)
266   {
267       if (d_id.find(id) == d_id.end())
268         return NULL;
269       else
270         return (*d_id.find(id)).second;
271     return 0;
272   }
273         
274  protected:
275   typedef std::map<Vector<int>, T> PositionMap;
276   typedef std::map<guint32, T> IdMap;
277   PositionMap d_object;
278   IdMap d_id;
279
280 };
281
282 #endif // LOCATIONLIST_H
283
284 // End of file