using System.Collections.Generic; using CodeImp.DoomBuilder.Config; using CodeImp.DoomBuilder.Data; using CodeImp.DoomBuilder.Rendering; namespace CodeImp.DoomBuilder.ZDoom { internal sealed class LockDefsParser :ZDTextParser { internal override ScriptType ScriptType { get { return ScriptType.LOCKDEFS; } } private Dictionary locks; private Dictionary mapcolors; public Dictionary MapColors { get { return mapcolors; } } public LockDefsParser() { locks = new Dictionary(); mapcolors = new Dictionary(); } public override bool Parse(TextResourceData data, bool clearerrors) { //mxd. Already parsed? if(!base.AddTextResource(data)) { if(clearerrors) ClearError(); return true; } // Cannot process? if(!base.Parse(data, clearerrors)) return false; // Continue until at the end of the stream int locknum = -1; string locktitle = string.Empty; string game = string.Empty; int bracelevel = 0; long lockstartpos = -1; PixelColor mapcolor = new PixelColor(); while(SkipWhitespace(true)) { string token = ReadToken().ToLowerInvariant(); if(string.IsNullOrEmpty(token)) continue; switch(token) { case "clearlocks": if(bracelevel == 0) { locks.Clear(); } else { ReportError("Unexpected \"CLEARLOCKS\" keyword"); return false; } break; // LOCK locknumber [game] case "lock": SkipWhitespace(false); if(!ReadSignedInt(ref locknum)) { ReportError("Expected lock number"); return false; } //wiki: The locknumber must be in the 1-to-255 range if(locknum < 1 || locknum > 255) { ReportError("The locknumber must be in the [1 .. 255] range, but is " + locknum); return false; } // Store position lockstartpos = datastream.Position; SkipWhitespace(true); token = ReadToken().ToLowerInvariant(); if(!string.IsNullOrEmpty(token)) { if(token == "{") { bracelevel++; } //Should be game else if(!GameType.GameTypes.Contains(token)) { LogWarning("Lock " + locknum + " is defined for unknown game \"" + token + "\""); } else { game = token; } } break; case "$title": SkipWhitespace(false); locktitle = StripQuotes(ReadToken(false)); break; // Mapcolor r g b case "mapcolor": int r = 0; int g = 0; int b = 0; SkipWhitespace(false); if(!ReadSignedInt(ref r)) { ReportError("Expected Mapcolor Red value"); return false; } if(r < 0 || r > 255) { ReportError("Mapcolor Red value must be in [0 .. 255] range, but is " + r); return false; } SkipWhitespace(false); if(!ReadSignedInt(ref g)) { ReportError("Expected Mapcolor Green value"); return false; } if(g < 0 || g > 255) { ReportError("Mapcolor Green value must be in [0 .. 255] range, but is " + g); return false; } SkipWhitespace(false); if(!ReadSignedInt(ref b)) { ReportError("Expected Mapcolor Blue value"); return false; } if(b < 0 || b > 255) { ReportError("Mapcolor Blue value must be in [0 .. 255] range, but is " + b); return false; } mapcolor = new PixelColor(255, (byte)r, (byte)g, (byte)b); break; case "{": bracelevel++; break; case "}": if(--bracelevel > 0) continue; // Add to collection? if(locknum > 0 && (string.IsNullOrEmpty(game) || General.Map.Config.BaseGame == game)) { // No custom title given? if(string.IsNullOrEmpty(locktitle)) { locktitle = "Lock " + locknum; } // Lock already defined? if(locks.ContainsKey(locknum)) { // Do some stream poition hacking to make the warning point to the correct line long curpos = datastream.Position; if(lockstartpos != -1) datastream.Position = lockstartpos; LogWarning("Lock " + locknum + " is double-defined as \"" + locks[locknum] + "\" and \"" + locktitle + "\""); datastream.Position = curpos; } // Add to collections locks[locknum] = locktitle; if(mapcolor.a == 255) mapcolors[locknum] = mapcolor; } // Reset values locknum = -1; locktitle = string.Empty; game = string.Empty; mapcolor = new PixelColor(); lockstartpos = -1; break; } } return true; } public EnumList GetLockDefs() { EnumList result = new EnumList(locks.Count); foreach(KeyValuePair group in locks) result.Add(new EnumItem(group.Key.ToString(), group.Value)); return result; } } }