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