3 using System.Collections;
8 public class ImageRegion {
9 public String ImageFile;
10 public Rectangle Region;
13 public class Attribute {
14 /// <summary>solid tile that is indestructible by Tux</summary>
15 public const int SOLID = 0x0001;
16 /// <summary>uni-directional solid tile</summary>
17 public const int UNISOLID = 0x0002;
18 /// <summary>a brick that can be destroyed by jumping under it</summary>
19 public const int BRICK = 0x0004;
20 /// <summary>the level should be finished when touching a goaltile.</summary>
22 /// if <see cref="Data">data</see> is 0 then the endsequence should be
23 /// triggered, if <see cref="Data">data</see> is 1 then we can finish
24 /// the level instantly.
26 public const int GOAL = 0x0008;
27 /// <summary>slope tile</summary>
28 public const int SLOPE = 0x0010;
29 /// <summary>Bonusbox, content is stored in <see cref="Data">data</see></summary>
30 public const int FULLBOX = 0x0020;
31 /// <summary>Tile is a coin</summary>
32 public const int COIN = 0x0040;
33 /// <summary>an ice brick that makes tux sliding more than usual</summary>
34 public const int ICE = 0x0100;
35 /// <summary>a water tile in which tux starts to swim</summary>
36 public const int WATER = 0x0200;
37 /// <summary>a tile that hurts the player if he touches it</summary>
38 public const int HURTS = 0x0400;
39 /// <summary>for lava: WATER, HURTS, FIRE</summary>
40 public const int FIRE = 0x0800;
43 // TODO: Find out why are worldmap tile attributes stored in data(s)
45 public const int WORLDMAP_NORTH = 0x0001;
46 public const int WORLDMAP_SOUTH = 0x0002;
47 public const int WORLDMAP_EAST = 0x0004;
48 public const int WORLDMAP_WEST = 0x0008;
50 public const int WORLDMAP_STOP = 0x0010;
57 public int Attributes;
60 public string OneWayString;
61 public ArrayList Images = new ArrayList();
62 public ArrayList EditorImages = new ArrayList();
70 public bool HasAttribute (int Attrib)
72 return (Attributes & Attrib) != 0;
75 public void SetAttribute (int Attrib, bool Value)
80 Attributes &= (~Attrib); //NOTE: "~" stands for bitwise negation
83 public bool HasWMAttribute (int Attrib)
85 return (Data & Attrib) != 0;
88 public void SetWMAttribute (int Attrib, bool Value)
93 Data &= (~Attrib); //NOTE: "~" stands for bitwise negation
96 public void Write(LispWriter writer) {
97 writer.StartList("tile");
98 writer.Write("id", ID);
100 WriteTileImages(writer, "images", Images);
102 if(HasAttribute(Attribute.SOLID))
103 writer.Write("solid", true);
104 if(HasAttribute(Attribute.UNISOLID))
105 writer.Write("unisolid", true);
106 if(HasAttribute(Attribute.ICE))
107 writer.Write("ice", true);
108 if(HasAttribute(Attribute.WATER))
109 writer.Write("water", true);
110 if(HasAttribute(Attribute.SLOPE))
111 writer.Write("slope-type", Data);
112 if(HasAttribute(Attribute.HURTS))
113 writer.Write("hurts", true);
114 if(HasAttribute(Attribute.FIRE))
115 writer.Write("fire", true);
116 if(HasAttribute(Attribute.COIN))
117 writer.Write("coin", true);
118 if(HasAttribute(Attribute.FULLBOX))
119 writer.Write("fullbox", true);
120 if(HasAttribute(Attribute.BRICK))
121 writer.Write("brick", true);
122 if(HasAttribute(Attribute.GOAL))
123 writer.Write("goal", true);
126 writer.Write("hidden", true);
128 writer.Write("next-tile", NextTile);
129 if(EditorImages != null)
130 WriteTileImages(writer, "editor-images", EditorImages);
132 writer.Write("data", Data);
133 if(Images.Count > 1) {
136 writer.Write("anim-fps", AnimFps);
138 if(!String.IsNullOrEmpty(OneWayString)) {
139 writer.Write("one-way", OneWayString);
141 writer.EndList("tile");
144 public void Parse(Lisp.Parser parser) {
145 int d = parser.Depth;
146 while(parser.Parse() && parser.Depth >= d) {
147 if(parser.Depth == d+1) {
148 if(parser.Type != Parser.LispType.SYMBOL)
149 throw new Exception("expected SYMBOL at single tile deserialization level, but found \"" + parser.StringValue + "\"");
150 string symbol = parser.SymbolValue;
154 ID = parser.IntegerValue;
157 ParseTileImages(parser, Images);
159 case "editor-images":
160 ParseTileImages(parser, EditorImages);
163 AnimFps = parser.FloatValue;
166 OneWayString = parser.StringValue;
169 Data = parser.IntegerValue;
172 NextTile = parser.IntegerValue;
175 Hidden = parser.BoolValue;
178 SetAttribute(Attribute.SOLID, parser.BoolValue);
181 SetAttribute(Attribute.UNISOLID, parser.BoolValue);
184 SetAttribute(Attribute.ICE, parser.BoolValue);
187 SetAttribute(Attribute.WATER, parser.BoolValue);
190 SetAttribute(Attribute.SLOPE, true);
191 Data = parser.IntegerValue;
194 SetAttribute(Attribute.HURTS, parser.BoolValue);
197 SetAttribute(Attribute.FIRE, parser.BoolValue);
200 SetAttribute(Attribute.BRICK, parser.BoolValue);
203 SetAttribute(Attribute.FULLBOX, parser.BoolValue);
206 SetAttribute(Attribute.COIN, parser.BoolValue);
209 SetAttribute(Attribute.GOAL, parser.BoolValue);
212 //Worldmap attributes section - these are stored in Data
214 SetWMAttribute(Attribute.WORLDMAP_NORTH, parser.BoolValue);
217 SetWMAttribute(Attribute.WORLDMAP_SOUTH, parser.BoolValue);
220 SetWMAttribute(Attribute.WORLDMAP_WEST, parser.BoolValue);
223 SetWMAttribute(Attribute.WORLDMAP_EAST, parser.BoolValue);
226 SetWMAttribute(Attribute.WORLDMAP_STOP, parser.BoolValue);
229 Console.WriteLine("Unknown tile element " + symbol);
236 private void ParseTileImages(Lisp.Parser parser, ArrayList ImagesList) {
237 if(parser.Type == Parser.LispType.END_LIST)
240 int d = parser.Depth;
242 ImageRegion region = new ImageRegion();
243 if(parser.Type == Parser.LispType.STRING) {
244 region.ImageFile = parser.StringValue;
245 } else if(parser.Type == Parser.LispType.START_LIST) {
246 ParseImageRegion(parser, region);
248 throw new Exception("unexpected lisp data: " + parser.Type);
250 ImagesList.Add(region);
251 } while(parser.Parse() && parser.Depth >= d);
254 private void WriteTileImages(LispWriter writer, string ListName, ArrayList ImagesList) {
255 if(ImagesList.Count > 0) {
256 writer.StartList(ListName);
257 foreach(ImageRegion region in ImagesList) {
258 if(region.Region.Width != 0) {
259 writer.WriteVerbatimLine(
260 String.Format("(region \"{0}\" {1} {2} {3} {4})",
261 region.ImageFile, region.Region.Left,
262 region.Region.Top, region.Region.Width,
263 region.Region.Height));
265 writer.WriteVerbatimLine(
266 "\"" + region.ImageFile + "\"");
269 writer.EndList(ListName);
271 Console.WriteLine("no images on tile " + ID);
275 private void ParseImageRegion(Lisp.Parser parser, ImageRegion region) {
277 if(parser.Type != Parser.LispType.SYMBOL)
278 throw new Exception("expected symbol");
279 if(parser.SymbolValue != "region")
280 throw new Exception("expected region symbol");
282 if(parser.Type != Parser.LispType.STRING)
283 throw new Exception("expected string");
284 region.ImageFile = parser.StringValue;
287 if(parser.Type != Parser.LispType.INTEGER)
288 throw new Exception("expected integer");
289 region.Region.X = parser.IntegerValue;
292 if(parser.Type != Parser.LispType.INTEGER)
293 throw new Exception("expected integer");
294 region.Region.Y = parser.IntegerValue;
297 if(parser.Type != Parser.LispType.INTEGER)
298 throw new Exception("expected integer");
299 region.Region.Width = parser.IntegerValue;
302 if(parser.Type != Parser.LispType.INTEGER)
303 throw new Exception("expected integer");
304 region.Region.Height = parser.IntegerValue;
307 if(parser.Type != Parser.LispType.END_LIST)
308 throw new Exception("expected END_LIST");