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 
Write(LispWriter writer)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 
Parse(Lisp.Parser parser)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 
Write(string filename)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 
Parse(string filename)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 
ParseTiles(Lisp.Parser parser)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 
ParseMoreTiles(Lisp.Parser parser)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 
SkipList(Lisp.Parser parser)237 	private void SkipList(Lisp.Parser parser)
238 	{
239 		int d = parser.Depth;
240 		while(parser.Parse() && parser.Depth >= d)
241 			;
242 	}
243 }
244