initial commit, lordsawar source, slightly modified
[lordsawar] / src / tileset.cpp
1 // Copyright (C) 2003 Michael Bartl
2 // Copyright (C) 2003, 2004, 2005, 2006 Ulf Lorenz
3 // Copyright (C) 2007, 2008, 2009 Ben Asselstine
4 //
5 //  This program is free software; you can redistribute it and/or modify
6 //  it under the terms of the GNU General Public License as published by
7 //  the Free Software Foundation; either version 3 of the License, or
8 //  (at your option) any later version.
9 //
10 //  This program is distributed in the hope that it will be useful,
11 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
12 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 //  GNU Library General Public License for more details.
14 //
15 //  You should have received a copy of the GNU General Public License
16 //  along with this program; if not, write to the Free Software
17 //  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 
18 //  02110-1301, USA.
19
20 #include <sigc++/functors/mem_fun.h>
21 #include <string.h>
22
23 #include "tileset.h"
24
25 #include "defs.h"
26 #include "File.h"
27 #include "SmallTile.h"
28 #include "xmlhelper.h"
29 #include "gui/image-helpers.h"
30 #include "GraphicsCache.h"
31 #include "tilesetlist.h"
32
33 using namespace std;
34
35 #include <iostream>
36 //#define debug(x) {cerr<<__FILE__<<": "<<__LINE__<<": "<<x<<endl<<flush;}
37 #define debug(x)
38
39 #define DEFAULT_TILE_SIZE 40
40
41 std::string Tileset::d_tag = "tileset";
42 std::string Tileset::d_road_smallmap_tag = "road_smallmap";
43 std::string Tileset::file_extension = TILESET_EXT;
44
45 Tileset::Tileset(guint32 id, std::string name)
46         : Set(), d_name(name), d_copyright(""), d_license(""), d_id(id), 
47         d_tileSize(DEFAULT_TILE_SIZE), d_subdir("")
48 {
49   d_info = "";
50   d_large_selector = "";
51   d_small_selector = "";
52   d_fog = "";
53   d_roads = "";
54   d_bridges = "";
55   d_flags = "";
56   d_road_color.set_rgb_p(0,0,0);
57   for (unsigned int i = 0; i < ROAD_TYPES; i++)
58     roadpic[i] = NULL;
59   for (unsigned int i = 0; i < BRIDGE_TYPES; i++)
60     bridgepic[i] = NULL;
61   for (unsigned int i = 0; i < FLAG_TYPES; i++)
62     flagpic[i] = NULL;
63   for (unsigned int i = 0; i < FLAG_TYPES; i++)
64     flagmask[i] = NULL;
65   number_of_selector_frames = 0;
66   selector.clear();
67   selectormask.clear();
68   number_of_small_selector_frames = 0;
69   smallselector.clear();
70   smallselectormask.clear();
71   explosion = NULL;
72   for (unsigned int i = 0; i < FOG_TYPES; i++)
73     fogpic[i] = NULL;
74 }
75
76 Tileset::Tileset(XML_Helper *helper, std::string directory)
77         :Set()
78 {
79   setDirectory(directory);
80   helper->getData(d_id, "id"); 
81   helper->getData(d_name, "name"); 
82   helper->getData(d_copyright, "copyright"); 
83   helper->getData(d_license, "license"); 
84   helper->getData(d_info, "info");
85   helper->getData(d_tileSize, "tilesize");
86   helper->getData(d_large_selector, "large_selector");
87   helper->getData(d_small_selector, "small_selector");
88   helper->getData(d_explosion, "explosion");
89   helper->getData(d_roads, "roads");
90   helper->getData(d_bridges, "bridges");
91   helper->getData(d_fog, "fog");
92   helper->getData(d_flags, "flags");
93   helper->registerTag(Tile::d_tag, sigc::mem_fun((*this), &Tileset::loadTile));
94   helper->registerTag(Tileset::d_road_smallmap_tag, sigc::mem_fun((*this), &Tileset::loadTile));
95   helper->registerTag(SmallTile::d_tag, sigc::mem_fun((*this), &Tileset::loadTile));
96   helper->registerTag(TileStyle::d_tag, sigc::mem_fun((*this), &Tileset::loadTile));
97   helper->registerTag(TileStyleSet::d_tag, sigc::mem_fun((*this), &Tileset::loadTile));
98   for (unsigned int i = 0; i < ROAD_TYPES; i++)
99     roadpic[i] = NULL;
100   for (unsigned int i = 0; i < BRIDGE_TYPES; i++)
101     bridgepic[i] = NULL;
102   for (unsigned int i = 0; i < FLAG_TYPES; i++)
103     flagpic[i] = NULL;
104   for (unsigned int i = 0; i < FLAG_TYPES; i++)
105     flagmask[i] = NULL;
106   number_of_selector_frames = 0;
107   selector.clear();
108   selectormask.clear();
109   number_of_small_selector_frames = 0;
110   smallselector.clear();
111   smallselectormask.clear();
112   explosion = NULL;
113   for (unsigned int i = 0; i < FOG_TYPES; i++)
114     fogpic[i] = NULL;
115 }
116
117 Tileset::~Tileset()
118 {
119   uninstantiateImages();
120   for (unsigned int i=0; i < size(); i++)
121     delete (*this)[i];
122 }
123
124 int Tileset::getIndex(Tile::Type type) const
125 {
126   for (guint32 i = 0; i < size(); i++)
127     if (type == (*this)[i]->getType())
128       return i;
129
130   // catch errors?
131   return -1;
132 }
133
134 bool Tileset::loadTile(string tag, XML_Helper* helper)
135 {
136   debug("loadTile()")
137
138     if (tag == Tile::d_tag)
139       {
140         // create a new tile with the information we got
141         Tile* tile = new Tile(helper);
142         this->push_back(tile);
143
144         return true;
145       }
146
147   if (tag == Tileset::d_road_smallmap_tag)
148     {
149       helper->getData(d_road_color, "color");
150       return true;
151     }
152
153   if (tag == SmallTile::d_tag)
154     {
155       Tile *tile = this->back();
156       SmallTile* smalltile = new SmallTile(helper);
157       tile->setSmallTile(smalltile);
158       return true;
159     }
160
161   if (tag == TileStyle::d_tag)
162     {
163       Tile *tile = this->back();
164       TileStyleSet *tilestyleset = tile->back();
165       // create a new tile style with the information we got
166       // put it on the latest tilestyleset
167       TileStyle* tilestyle = new TileStyle(helper);
168       tilestyleset->push_back(tilestyle);
169       d_tilestyles[tilestyle->getId()] = tilestyle;
170
171       return true;
172     }
173
174   if (tag == TileStyleSet::d_tag)
175     {
176       Tile *tile = this->back();
177       // create a new tile style set with the information we got
178       // put it on the latest tile
179       TileStyleSet* tilestyleset = new TileStyleSet(helper);
180       tilestyleset->setSubDir(getSubDir());
181       tile->push_back(tilestyleset);
182       return true;
183     }
184
185   return false;
186 }
187
188 TileStyle *Tileset::getRandomTileStyle(guint32 index, TileStyle::Type style) const
189 {
190   Tile *tile = (*this)[index];
191   if (tile)
192     return tile->getRandomTileStyle (style);
193   else
194     return NULL;
195 }
196
197 bool Tileset::save(XML_Helper *helper) const
198 {
199   bool retval = true;
200
201   retval &= helper->openTag(d_tag);
202   retval &= helper->saveData("id", d_id);
203   retval &= helper->saveData("name", d_name);
204   retval &= helper->saveData("copyright", d_copyright);
205   retval &= helper->saveData("license", d_license);
206   retval &= helper->saveData("info", d_info);
207   retval &= helper->saveData("tilesize", d_tileSize);
208   retval &= helper->saveData("large_selector", d_large_selector);
209   retval &= helper->saveData("small_selector", d_small_selector);
210   retval &= helper->saveData("explosion", d_explosion);
211   retval &= helper->saveData("roads", d_roads);
212   retval &= helper->saveData("bridges", d_bridges);
213   retval &= helper->saveData("fog", d_fog);
214   retval &= helper->saveData("flags", d_flags);
215   retval &= helper->openTag(d_road_smallmap_tag);
216   retval &= helper->saveData("color", d_road_color);
217   retval &= helper->closeTag();
218   for (Tileset::const_iterator i = begin(); i != end(); ++i)
219     retval &= (*i)->save(helper);
220   retval &= helper->closeTag();
221
222   return retval;
223 }
224
225 int Tileset::getFreeTileStyleId() const
226 {
227   int ids[65535];
228   memset (ids, 0, sizeof (ids));
229   for (Tileset::const_iterator i = begin(); i != end(); ++i)
230     {
231       for (std::list<TileStyleSet*>::const_iterator j = (*i)->begin(); j != (*i)->end(); j++)
232         {
233           for (std::vector<TileStyle*>::const_iterator k = (*j)->begin(); k != (*j)->end(); k++)
234             {
235               ids[(*k)->getId()] = 1;
236             }
237         }
238     }
239   //these ids range from 0 to 65535.
240   for (unsigned int i = 0; i <= 65535; i++)
241     {
242       if (ids[i] == 0)
243         return i;
244     }
245   return -1;
246 }
247
248 int Tileset::getLargestTileStyleId() const
249 {
250   unsigned int largest = 0;
251   for (Tileset::const_iterator i = begin(); i != end(); ++i)
252     {
253       for (std::list<TileStyleSet*>::const_iterator j = (*i)->begin(); j != (*i)->end(); j++)
254         {
255           for (std::vector<TileStyle*>::const_iterator k = (*j)->begin(); k != (*j)->end(); k++)
256             {
257               if ((*k)->getId() > largest)
258                 largest = (*k)->getId();
259             }
260         }
261     }
262   return largest;
263 }
264
265 void Tileset::setSubDir(std::string dir)
266 {
267   d_subdir = dir;
268   for (Tileset::iterator i = begin(); i != end(); ++i)
269     for (Tile::iterator j = (*i)->begin(); j != (*i)->end(); j++)
270       (*j)->setSubDir(dir);
271 }
272
273 guint32 Tileset::getDefaultTileSize()
274 {
275   return DEFAULT_TILE_SIZE;
276 }
277
278 bool Tileset::validate() const
279 {
280   if (size() == 0)
281     return false;
282   for (Tileset::const_iterator i = begin(); i != end(); i++)
283     {
284       if ((*i)->validate() == false)
285         {
286           fprintf (stderr, "`%s' fails validation\n", 
287                    (*i)->getName().c_str());
288           return false;
289         }
290     }
291   return true;
292 }
293
294 class TilesetLoader
295 {
296 public:
297     TilesetLoader(std::string filename) 
298       {
299         tileset = NULL;
300         dir = File::get_dirname(filename);
301         if (File::nameEndsWith(filename, Tileset::file_extension) == false)
302           filename += Tileset::file_extension;
303         XML_Helper helper(filename, ios::in, false);
304         helper.registerTag(Tileset::d_tag, sigc::mem_fun((*this), &TilesetLoader::load));
305         if (!helper.parse())
306           {
307             std::cerr << "Error, while loading an tileset. Tileset Name: ";
308             std::cerr <<dir<<std::endl <<std::flush;
309             if (tileset != NULL)
310               delete tileset;
311             tileset = NULL;
312           }
313       };
314     bool load(std::string tag, XML_Helper* helper)
315       {
316         if (tag == Tileset::d_tag)
317           {
318             tileset = new Tileset(helper, dir);
319             return true;
320           }
321         return false;
322       };
323     std::string dir;
324     Tileset *tileset;
325 };
326 Tileset *Tileset::create(std::string file)
327 {
328   TilesetLoader d(file);
329   return d.tileset;
330 }
331 void Tileset::getFilenames(std::list<std::string> &files)
332 {
333   for (iterator it = begin(); it != end(); it++)
334     {
335       Tile *t = *it;
336       for (Tile::iterator sit = t->begin(); sit != t->end(); sit++)
337         {
338           std::string file = (*sit)->getName();
339           if (std::find(files.begin(), files.end(), file) == files.end())
340             files.push_back(file);
341         }
342     }
343   files.push_back(d_small_selector);
344   files.push_back(d_large_selector);
345   files.push_back(d_explosion);
346   files.push_back(d_fog);
347   files.push_back(d_roads);
348   files.push_back(d_bridges);
349   files.push_back(d_flags);
350 }
351
352 void Tileset::uninstantiateImages()
353 {
354   for (iterator it = begin(); it != end(); it++)
355     (*it)->uninstantiateImages();
356
357   if (getExplosionImage() != NULL)
358     {
359       delete getExplosionImage();
360       setExplosionImage(NULL);
361     }
362   for (unsigned int i = 0; i < ROAD_TYPES; i++)
363     {
364       if (getRoadImage(i) != NULL)
365         {
366           delete getRoadImage(i);
367           setRoadImage(i, NULL);
368         }
369     }
370   for (unsigned int i = 0; i < BRIDGE_TYPES; i++)
371     {
372       if (getBridgeImage(i) != NULL)
373         {
374           delete getBridgeImage(i);
375           setBridgeImage(i, NULL);
376         }
377     }
378   for (unsigned int i = 0; i < FOG_TYPES; i++)
379     {
380       if (getFogImage(i) != NULL)
381         {
382           delete getFogImage(i);
383           setFogImage(i, NULL);
384         }
385     }
386   for (unsigned int i = 0; i < getNumberOfSelectorFrames(); i++)
387     {
388       if (getSelectorImage(i) != NULL)
389         {
390           delete getSelectorImage(i);
391           setSelectorImage(i, NULL);
392         }
393     }
394   for (unsigned int i = 0; i < getNumberOfSmallSelectorFrames(); i++)
395     {
396       if (getSmallSelectorImage(i) != NULL)
397         {
398           delete getSmallSelectorImage(i);
399           setSmallSelectorImage(i, NULL);
400         }
401     }
402   for (unsigned int i = 0; i < getNumberOfSmallSelectorFrames(); i++)
403     {
404       if (getSmallSelectorMask(i) != NULL)
405         {
406           delete getSmallSelectorMask(i);
407           setSmallSelectorMask(i, NULL);
408         }
409     }
410   for (unsigned int i = 0; i < FLAG_TYPES; i++)
411     {
412       if (getFlagImage(i) != NULL)
413         {
414           delete getFlagImage(i);
415           setFlagImage(i, NULL);
416         }
417     }
418   for (unsigned int i = 0; i < FLAG_TYPES; i++)
419     {
420       if (getFlagMask(i) != NULL)
421         {
422           delete getFlagMask(i);
423           setFlagMask(i, NULL);
424         }
425     }
426 }
427
428 void Tileset::instantiateImages(std::string explosion_filename,
429                                 std::string roads_filename,
430                                 std::string bridges_filename,
431                                 std::string fog_filename,
432                                 std::string flags_filename,
433                                 std::string selector_filename,
434                                 std::string small_selector_filename)
435 {
436   if (explosion_filename.empty() == false)
437     setExplosionImage (PixMask::create(explosion_filename));
438
439   if (roads_filename.empty() == false)
440     {
441       std::vector<PixMask* > roadpics;
442       roadpics = disassemble_row(roads_filename, ROAD_TYPES);
443       for (unsigned int i = 0; i < ROAD_TYPES ; i++)
444         {
445           if (roadpics[i]->get_width() != (int)d_tileSize)
446             PixMask::scale(roadpics[i], d_tileSize, d_tileSize);
447           setRoadImage(i, roadpics[i]);
448         }
449     }
450
451   if (bridges_filename.empty() == false)
452     {
453       std::vector<PixMask* > bridgepics;
454       bridgepics = disassemble_row(bridges_filename, BRIDGE_TYPES);
455       for (unsigned int i = 0; i < BRIDGE_TYPES ; i++)
456         {
457           if (bridgepics[i]->get_width() != (int)d_tileSize)
458             PixMask::scale(bridgepics[i], d_tileSize, d_tileSize);
459           setBridgeImage(i, bridgepics[i]);
460         }
461     }
462
463   if (fog_filename.empty() == false)
464     {
465       std::vector<PixMask* > fogpics;
466       fogpics = disassemble_row(fog_filename, FOG_TYPES);
467       for (unsigned int i = 0; i < FOG_TYPES ; i++)
468         {
469           if (fogpics[i]->get_width() != (int)d_tileSize)
470             PixMask::scale(fogpics[i], d_tileSize, d_tileSize);
471           setFogImage(i, fogpics[i]);
472         }
473     }
474
475   if (flags_filename.empty() == false)
476     {
477       std::vector<PixMask* > flagpics;
478       std::vector<PixMask* > maskpics;
479       GraphicsCache::loadFlagImages (flags_filename, d_tileSize, 
480                                      flagpics, maskpics);
481       for (unsigned int i = 0; i < flagpics.size(); i++)
482         setFlagImage(i, flagpics[i]);
483       for (unsigned int i = 0; i < maskpics.size(); i++)
484         setFlagMask(i, maskpics[i]);
485     }
486
487       
488   std::vector<PixMask* > images;
489   std::vector<PixMask* > masks;
490   if (selector_filename.empty() == false)
491     {
492       GraphicsCache::loadSelectorImages (selector_filename, d_tileSize, 
493                                          images, masks);
494       setNumberOfSelectorFrames(images.size());
495       for (unsigned int i = 0; i < images.size(); i++)
496         {
497           setSelectorImage(i, images[i]);
498           setSelectorMask(i, masks[i]);
499         }
500     }
501
502   images.clear();
503   masks.clear();
504   if (small_selector_filename.empty() == false)
505     {
506       GraphicsCache::loadSelectorImages (small_selector_filename, d_tileSize,
507                                          images, masks);
508       setNumberOfSmallSelectorFrames(images.size());
509       for (unsigned int i = 0; i < images.size(); i++)
510         {
511           setSmallSelectorImage(i, images[i]);
512           setSmallSelectorMask(i, masks[i]);
513         }
514     }
515 }
516
517 void Tileset::instantiateImages()
518 {
519   int size = getTileSize();
520   debug("Loading images for tileset " << getName());
521   uninstantiateImages();
522   for (iterator it = begin(); it != end(); it++)
523     (*it)->instantiateImages(size, this);
524   std::string explosion_filename = "";
525   std::string roads_filename = "";
526   std::string bridges_filename = "";
527   std::string fog_filename = "";
528   std::string flags_filename = "";
529   std::string selector_filename = "";
530   std::string small_selector_filename = "";
531
532   if (getExplosionFilename().empty() == false)
533     explosion_filename = getFile(getExplosionFilename());
534   if (getRoadsFilename().empty() == false)
535     roads_filename = getFile(getRoadsFilename());
536   if (getBridgesFilename().empty() == false)
537     bridges_filename = getFile(getBridgesFilename());
538   if (getFogFilename().empty() == false)
539     fog_filename = getFile(getFogFilename());
540   if (getFlagsFilename().empty() == false)
541     flags_filename = getFile(getFlagsFilename());
542   if (getLargeSelectorFilename().empty() == false)
543     selector_filename = getFile(getLargeSelectorFilename());
544   if (getSmallSelectorFilename().empty() == false)
545     small_selector_filename = getFile(getSmallSelectorFilename());
546   instantiateImages(explosion_filename, roads_filename, bridges_filename, 
547                     fog_filename, flags_filename, selector_filename, 
548                     small_selector_filename);
549 }
550
551 std::string Tileset::getConfigurationFile() const
552 {
553   return getDirectory() + d_subdir + file_extension;
554 }
555
556 std::list<std::string> Tileset::scanUserCollection()
557 {
558   return File::scanFiles(File::getUserTilesetDir(), file_extension);
559 }
560
561 std::list<std::string> Tileset::scanSystemCollection()
562 {
563   std::list<std::string> retlist = File::scanFiles(File::getTilesetDir(), 
564                                                    file_extension);
565   if (retlist.empty())
566     {
567       std::cerr << "Couldn't find any tilesets!" << std::endl;
568       std::cerr << "Please check the path settings in /etc/lordsawarrc or ~/.lordsawarrc" << std::endl;
569       std::cerr << "Exiting!" << std::endl;
570       exit(-1);
571     }
572
573   return retlist;
574 }
575
576 TileStyle *Tileset::getTileStyle(guint32 id) const
577 {
578   TileStyleIdMap::const_iterator it = d_tilestyles.find(id);
579   if (it == d_tilestyles.end())
580     return NULL;
581   else
582     return (*it).second;
583 }
584 //End of file