// $Id$ using System; using System.IO; using System.Collections; using System.Collections.Generic; using Lisp; public class TileGroup { public string Name; public ArrayList Tiles = new ArrayList(); public void Write(LispWriter writer) { writer.StartList("tilegroup"); writer.Write("name", Name); writer.Write("tiles", Tiles); writer.EndList("tilegroup"); } public void Parse(Lisp.Parser parser) { int d = parser.Depth; while(parser.Parse() && parser.Depth >= d) { if(parser.Depth == d+1) { if(parser.Type != Parser.LispType.SYMBOL) throw new Exception("expected SYMBOL at supertux-tiles level, but got \"" + parser.StringValue + "\""); string symbol = parser.SymbolValue; parser.Parse(); switch(symbol) { case "name": Name = parser.StringValue; break; case "tiles": do { Tiles.Add(parser.IntegerValue); } while(parser.Parse() && parser.Type == Parser.LispType.INTEGER); break; default: Console.WriteLine("Unknown section " + symbol); break; } } } } } public class TileSet { public const int TILE_WIDTH = 32; public const int TILE_HEIGHT = 32; private bool isNew = false; /// Whether version of tileset file is too new public bool IsNew { get { return isNew; } } public ArrayList Tiles = new ArrayList(); public ArrayList TileGroups = new ArrayList(); public void Write(string filename) { FileStream fs = new FileStream(filename, FileMode.Create); TextWriter tw = new StreamWriter(fs); LispWriter writer = new LispWriter(tw); writer.WriteComment("Generated by tiler"); writer.StartList("supertux-tiles"); foreach(TileGroup tilegroup in TileGroups) { tilegroup.Write(writer); } foreach(Tile tile in Tiles) { if(tile == null) continue; if(tile.ID >= 0) tile.Write(writer); } writer.EndList("supertux-tiles"); tw.Close(); fs.Close(); } public void Parse(string filename) { FileStream fs = new FileStream(filename, FileMode.Open); StreamReader stream = new StreamReader(fs); Lisp.Parser parser = new Lisp.Parser(stream); parser.Parse(); if(parser.Type != Parser.LispType.START_LIST) throw new Exception("Expected START_LIST"); parser.Parse(); if(parser.Type != Parser.LispType.SYMBOL) throw new Exception("Expected symbol"); if(parser.SymbolValue != "supertux-tiles") throw new Exception("not a supertux tile files but " + parser.SymbolValue); ParseTiles(parser); stream.Close(); fs.Close(); } public void ParseTiles(Lisp.Parser parser) { isNew = false; int d = parser.Depth; while(parser.Parse() && parser.Depth >= d) { if(parser.Depth == d && parser.Type != Parser.LispType.START_LIST) { Console.WriteLine("non-cons type in list..."); continue; } if(parser.Depth == d+1) { if(parser.Type != Parser.LispType.SYMBOL) { throw new Exception("Expected symbol in list element"); } switch(parser.SymbolValue) { case "properties": SkipList(parser); break; case "tilegroup": TileGroup tilegroup = new TileGroup(); tilegroup.Parse(parser); TileGroups.Add(tilegroup); break; case "tile": Tile tile = new Tile(); tile.Parse(parser); while(tile.ID >= Tiles.Count) Tiles.Add(null); Tiles[tile.ID] = tile; break; case "tiles": ParseMoreTiles(parser); isNew = true; break; default: throw new Exception("Unexpected listentry: " + parser.SymbolValue); } } } } public void ParseMoreTiles(Lisp.Parser parser) { int blockWidth = 0; int blockHeight = 0; List ids = new List(); List attributes = new List(); List datas = new List(); List imageNames = new List(); float animFps = 0; int d = parser.Depth; while(parser.Parse() && parser.Depth >= d) { if(parser.Depth == d+1) { if(parser.Type != Parser.LispType.SYMBOL) throw new Exception("expected SYMBOL at supertux-tiles---tiles level, but got \"" + parser.StringValue + "\""); string symbol = parser.SymbolValue; parser.Parse(); switch(symbol) { case "width": blockWidth = parser.IntegerValue; break; case "height": blockHeight = parser.IntegerValue; break; case "ids": Parser.ParseIntList(parser, ids); break; case "attributes": Parser.ParseIntList(parser, attributes); break; case "datas": Parser.ParseIntList(parser, datas); break; case "anim-fps": animFps = parser.FloatValue; break; case "image": int subDepth = parser.Depth; while(parser.Depth >= subDepth) { imageNames.Add(parser.StringValue); parser.Parse(); } break; default: Console.WriteLine("Unknown tiles element " + symbol); break; } } } if(ids.Count != blockWidth * blockHeight) throw new ApplicationException("Must have width*height ids in tiles block, but found " + ids.Count.ToString()); if((attributes.Count != blockWidth * blockHeight) && attributes.Count > 0) //missing atributes == all-are-0-attributes throw new ApplicationException("Must have width*height attributes in tiles block"); if((datas.Count != blockWidth * blockHeight) && datas.Count > 0) //missing DATAs == all-are-0-DATAs throw new ApplicationException("Must have width*height DATAs in tiles block"); int id = 0; for(int y = 0; y < blockHeight; ++y) { for(int x = 0; x < blockWidth; ++x) { if (ids[id] != 0) { Tile tile = new Tile(); tile.Images = new ArrayList(); foreach (string str in imageNames) { ImageRegion region = new ImageRegion(); region.ImageFile = str; region.Region.X = x * TILE_WIDTH; region.Region.Y = y * TILE_HEIGHT; region.Region.Width = TILE_WIDTH; region.Region.Height = TILE_HEIGHT; tile.Images.Add(region); } tile.ID = ids[id]; tile.Attributes = (attributes.Count > 0)?attributes[id]:0; //missing atributes == all-are-0-attributes tile.Data = (datas.Count > 0)?datas[id]:0; //missing DATAs == all-are-0-DATAs tile.AnimFps = animFps; while(Tiles.Count <= tile.ID) Tiles.Add(null); Tiles[tile.ID] = tile; } id++; } } } private void SkipList(Lisp.Parser parser) { int d = parser.Depth; while(parser.Parse() && parser.Depth >= d) ; } }