Added menu item to let user decide, if he wants to use new not-yet-fully-supported...
[supertux.git] / tools / tilemanager / TileSet.cs
1 //  $Id$
2 using System;
3 using System.IO;
4 using System.Collections;
5 using System.Collections.Generic;
6 using Lisp;
7
8 public class TileGroup {
9     public string Name;
10     public ArrayList Tiles = new ArrayList();
11
12     public void Write(LispWriter writer) {
13         writer.StartList("tilegroup");
14
15         writer.Write("name", Name);
16         writer.Write("tiles", Tiles);
17
18         writer.EndList("tilegroup");
19     }
20
21     public void Parse(Lisp.Parser parser) {
22         int d = parser.Depth;
23         while(parser.Parse() && parser.Depth >= d) {
24             if(parser.Depth == d+1) {
25                 if(parser.Type != Parser.LispType.SYMBOL)
26                     throw new Exception("expected SYMBOL at supertux-tiles level, but got \"" + parser.StringValue + "\"");
27                 string symbol = parser.SymbolValue;
28                 parser.Parse();
29                 switch(symbol) {
30                     case "name":
31                         Name = parser.StringValue;
32                         break;
33                     case "tiles":
34                         do {
35                           Tiles.Add(parser.IntegerValue);
36                         } while(parser.Parse()
37                                 && parser.Type == Parser.LispType.INTEGER);
38                         break;
39                     default:
40                         Console.WriteLine("Unknown section " + symbol);
41                         break;
42                 }
43             }
44         }
45     }
46 }
47
48 public class TileSet {
49     public const int TILE_WIDTH = 32;
50     public const int TILE_HEIGHT = 32;
51
52     private bool isNew = false;
53
54     /// <summary>Whether version of tileset file is too new</summary>
55     public bool IsNew {
56         get {
57                 return isNew;
58         }
59     }
60
61     public ArrayList Tiles = new ArrayList();
62     public ArrayList TileGroups = new ArrayList();
63
64     public void Write(string filename) {
65         FileStream fs = new FileStream(filename, FileMode.Create);
66
67         TextWriter tw = new StreamWriter(fs);
68         LispWriter writer = new LispWriter(tw);
69
70         writer.WriteComment("Generated by tiler");
71         writer.StartList("supertux-tiles");
72         foreach(TileGroup tilegroup in TileGroups) {
73             tilegroup.Write(writer);
74         }
75         foreach(Tile tile in Tiles) {
76             if(tile == null)
77                 continue;
78             if(tile.ID >= 0)
79                 tile.Write(writer);
80         }
81         writer.EndList("supertux-tiles");
82         tw.Close();
83         fs.Close();
84     }
85
86     public void Parse(string filename) {
87         FileStream fs = new FileStream(filename, FileMode.Open);
88         StreamReader stream = new StreamReader(fs);
89
90         Lisp.Parser parser = new Lisp.Parser(stream);
91         parser.Parse();
92         if(parser.Type != Parser.LispType.START_LIST)
93             throw new Exception("Expected START_LIST");
94         parser.Parse();
95         if(parser.Type != Parser.LispType.SYMBOL)
96             throw new Exception("Expected symbol");
97         if(parser.SymbolValue != "supertux-tiles")
98             throw new Exception("not a supertux tile files but " +
99                     parser.SymbolValue);
100         ParseTiles(parser);
101
102         stream.Close();
103         fs.Close();
104     }
105
106     public void ParseTiles(Lisp.Parser parser) {
107         isNew = false;
108         int d = parser.Depth;
109         while(parser.Parse() && parser.Depth >= d) {
110             if(parser.Depth == d && parser.Type != Parser.LispType.START_LIST) {
111                 Console.WriteLine("non-cons type in list...");
112                 continue;
113             }
114
115             if(parser.Depth == d+1) {
116                 if(parser.Type != Parser.LispType.SYMBOL) {
117                     throw new Exception("Expected symbol in list element");
118                 }
119                 switch(parser.SymbolValue) {
120                     case "properties":
121                         SkipList(parser);
122                         break;
123                     case "tilegroup":
124                         TileGroup tilegroup = new TileGroup();
125                         tilegroup.Parse(parser);
126                         TileGroups.Add(tilegroup);
127                         break;
128                     case "tile":
129                         Tile tile = new Tile();
130                         tile.Parse(parser);
131
132                         while(tile.ID >= Tiles.Count)
133                             Tiles.Add(null);
134                         Tiles[tile.ID] = tile;
135                         break;
136                     case "tiles":
137                         ParseMoreTiles(parser);
138                         isNew = true;
139                         break;
140                    default:
141                         throw new Exception("Unexpected listentry: " +
142                                 parser.SymbolValue);
143                 }
144             }
145         }
146     }
147
148         public void ParseMoreTiles(Lisp.Parser parser)
149         {
150                 int blockWidth = 0;
151                 int blockHeight = 0;
152                 List<int> ids = new List<int>();
153                 List<int> attributes = new List<int>();
154                 List<int> datas = new List<int>();
155                 List<string> imageNames = new List<string>();
156                 float animFps = 0;
157
158                 int d = parser.Depth;
159                 while(parser.Parse() && parser.Depth >= d) {
160                         if(parser.Depth == d+1) {
161                                 if(parser.Type != Parser.LispType.SYMBOL)
162                                         throw new Exception("expected SYMBOL at supertux-tiles---tiles level, but got \"" + parser.StringValue + "\"");
163                                 string symbol = parser.SymbolValue;
164                                 parser.Parse();
165                                 switch(symbol) {
166                                         case "width":
167                                                 blockWidth = parser.IntegerValue;
168                                                 break;
169                                         case "height":
170                                                 blockHeight = parser.IntegerValue;
171                                                 break;
172                                         case "ids":
173                                                 Parser.ParseIntList(parser, ids);
174                                                 break;
175                                         case "attributes":
176                                                 Parser.ParseIntList(parser, attributes);
177                                                 break;
178                                         case "datas":
179                                                 Parser.ParseIntList(parser, datas);
180                                                 break;
181                                         case "anim-fps":
182                                                 animFps = parser.FloatValue;
183                                                 break;
184                                         case "image":
185                                                 int subDepth = parser.Depth;
186                                                 while(parser.Depth >= subDepth) {
187                                                         imageNames.Add(parser.StringValue);
188                                                         parser.Parse();
189                                                 }
190                                                 break;
191                                         default:
192                                                 Console.WriteLine("Unknown tiles element " + symbol);
193                                                 break;
194                                 }
195                         }
196                 }
197                 if(ids.Count != blockWidth * blockHeight)
198                         throw new ApplicationException("Must have width*height ids in tiles block, but found " + ids.Count.ToString());
199                 if((attributes.Count != blockWidth * blockHeight) && attributes.Count > 0)      //missing atributes == all-are-0-attributes
200                         throw new ApplicationException("Must have width*height attributes in tiles block");
201                 if((datas.Count != blockWidth * blockHeight) && datas.Count > 0)        //missing DATAs == all-are-0-DATAs
202                         throw new ApplicationException("Must have width*height DATAs in tiles block");
203
204                 int id = 0;
205                 for(int y = 0; y < blockHeight; ++y) {
206                         for(int x = 0; x < blockWidth; ++x) {
207                                 if (ids[id] != 0) {
208                                         Tile tile = new Tile();
209
210                                         tile.Images = new ArrayList();
211                                         foreach (string str in imageNames)
212                                         {
213                                                 ImageRegion region = new ImageRegion();
214                                                 region.ImageFile = str;
215                                                 region.Region.X = x * TILE_WIDTH;
216                                                 region.Region.Y = y * TILE_HEIGHT;
217                                                 region.Region.Width = TILE_WIDTH;
218                                                 region.Region.Height = TILE_HEIGHT;
219                                                 tile.Images.Add(region);
220                                         }
221                                         tile.ID = ids[id];
222                                         tile.Attributes = (attributes.Count > 0)?attributes[id]:0;      //missing atributes == all-are-0-attributes
223                                         tile.Data = (datas.Count > 0)?datas[id]:0;      //missing DATAs == all-are-0-DATAs
224                                         tile.AnimFps = animFps;
225
226                                         while(Tiles.Count <= tile.ID)
227                                                 Tiles.Add(null);
228
229                                         Tiles[tile.ID] = tile;
230                                 }
231
232                                 id++;
233                         }
234                 }
235         }
236
237         private void SkipList(Lisp.Parser parser)
238         {
239                 int d = parser.Depth;
240                 while(parser.Parse() && parser.Depth >= d)
241                         ;
242         }
243 }