UltimateZoneBuilder/Source/Core/ZDoom/MapinfoParser.cs

766 lines
20 KiB
C#
Raw Normal View History

#region ================== Namespaces
Removed "Paste Properties Options" action. Added "Paste Properties Special" actions in "Classic" and "Visual" categories. They work the same way as "Paste Special" action. Added: "Copy Properties", "Paste Properties" and "Paste Properties Special" options are now shown in the Edit menu if current classic mode supports them. Changed, Paste Properties Special window: only options relevant to current map format are now displayed. Changed, Paste Properties Special window, UDMF: all UI-managed options are now available. Fixed: MAPINFO parser was unable to process "include" directives. Fixed, General interface: selection info was reset to "Nothing selected" after few seconds regardless of current selection. Fixed, Visual mode: thing bounding boxes were not updated when changing things positions using Randomize mode. Fixed, Visual mode: event lines were displayed at incorrect height when entering Visual mode for the first time. Fixed, Texture Browser window: when MixTexturesFlats Game Configuration option is disabled, textures/flats are no longer shown in the Used group when flats/textures with the same names are used in the map. Fixed(?): probably fixed an exception some users reported when trying to initialize a Classic mode after switching from Visual mode with "Sync cameras" option enabled. Changed, Game configurations, Thing Categories: a block must have at least one thing category property to be recognized as a thing category. Changed, Visplane Explorer: the plugin now outputs more info when it fails to initialize vpo.dll. Cosmetic, Thing Edit window, Doom/Hexen map format: adjusted UI layout so thing flags control no longer displays scrollbars in Hexen map format. Internal: merged methods from UDMFTools into UniFields, removed UDMFTools. Updated Inno Setup script (added VC++ 2008 SP1 distributive). Updated ZDoom_DECORATE.cfg (A_CheckBlock). Updated documentation (added "System Requirements" page).
2015-10-09 12:38:12 +00:00
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using CodeImp.DoomBuilder.Config;
using CodeImp.DoomBuilder.Data;
using CodeImp.DoomBuilder.Rendering;
using CodeImp.DoomBuilder.GZBuilder.Data;
#endregion
2016-04-27 09:13:07 +00:00
namespace CodeImp.DoomBuilder.ZDoom
{
internal sealed class MapinfoParser : ZDTextParser
{
#region ================== Delegates
public delegate void IncludeDelegate(MapinfoParser parser, string includefile, bool clearerror);
public IncludeDelegate OnInclude;
#endregion
#region ================== Variables
private MapInfo mapinfo;
Removed "Paste Properties Options" action. Added "Paste Properties Special" actions in "Classic" and "Visual" categories. They work the same way as "Paste Special" action. Added: "Copy Properties", "Paste Properties" and "Paste Properties Special" options are now shown in the Edit menu if current classic mode supports them. Changed, Paste Properties Special window: only options relevant to current map format are now displayed. Changed, Paste Properties Special window, UDMF: all UI-managed options are now available. Fixed: MAPINFO parser was unable to process "include" directives. Fixed, General interface: selection info was reset to "Nothing selected" after few seconds regardless of current selection. Fixed, Visual mode: thing bounding boxes were not updated when changing things positions using Randomize mode. Fixed, Visual mode: event lines were displayed at incorrect height when entering Visual mode for the first time. Fixed, Texture Browser window: when MixTexturesFlats Game Configuration option is disabled, textures/flats are no longer shown in the Used group when flats/textures with the same names are used in the map. Fixed(?): probably fixed an exception some users reported when trying to initialize a Classic mode after switching from Visual mode with "Sync cameras" option enabled. Changed, Game configurations, Thing Categories: a block must have at least one thing category property to be recognized as a thing category. Changed, Visplane Explorer: the plugin now outputs more info when it fails to initialize vpo.dll. Cosmetic, Thing Edit window, Doom/Hexen map format: adjusted UI layout so thing flags control no longer displays scrollbars in Hexen map format. Internal: merged methods from UDMFTools into UniFields, removed UDMFTools. Updated Inno Setup script (added VC++ 2008 SP1 distributive). Updated ZDoom_DECORATE.cfg (A_CheckBlock). Updated documentation (added "System Requirements" page).
2015-10-09 12:38:12 +00:00
private string mapname;
private readonly Dictionary<int, string> spawnnums;
private readonly Dictionary<int, string> doomednums; // <DoomEdNum, <lowercase classname, List of default arguments>>
private readonly HashSet<string> parsedlumps;
#endregion
#region ================== Properties
internal override ScriptType ScriptType { get { return ScriptType.MAPINFO; } }
public MapInfo MapInfo { get { return mapinfo; } }
public Dictionary<int, string> SpawnNums { get { return spawnnums; } }
public Dictionary<int, string> DoomEdNums { get { return doomednums; } }
#endregion
#region ================== Constructor
public MapinfoParser()
{
// Syntax
whitespace = "\n \t\r\u00A0";
specialtokens = ",{}=\n";
mapinfo = new MapInfo();
spawnnums = new Dictionary<int, string>();
doomednums = new Dictionary<int, string>();
parsedlumps = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
}
#endregion
#region ================== Parsing
Removed "Paste Properties Options" action. Added "Paste Properties Special" actions in "Classic" and "Visual" categories. They work the same way as "Paste Special" action. Added: "Copy Properties", "Paste Properties" and "Paste Properties Special" options are now shown in the Edit menu if current classic mode supports them. Changed, Paste Properties Special window: only options relevant to current map format are now displayed. Changed, Paste Properties Special window, UDMF: all UI-managed options are now available. Fixed: MAPINFO parser was unable to process "include" directives. Fixed, General interface: selection info was reset to "Nothing selected" after few seconds regardless of current selection. Fixed, Visual mode: thing bounding boxes were not updated when changing things positions using Randomize mode. Fixed, Visual mode: event lines were displayed at incorrect height when entering Visual mode for the first time. Fixed, Texture Browser window: when MixTexturesFlats Game Configuration option is disabled, textures/flats are no longer shown in the Used group when flats/textures with the same names are used in the map. Fixed(?): probably fixed an exception some users reported when trying to initialize a Classic mode after switching from Visual mode with "Sync cameras" option enabled. Changed, Game configurations, Thing Categories: a block must have at least one thing category property to be recognized as a thing category. Changed, Visplane Explorer: the plugin now outputs more info when it fails to initialize vpo.dll. Cosmetic, Thing Edit window, Doom/Hexen map format: adjusted UI layout so thing flags control no longer displays scrollbars in Hexen map format. Internal: merged methods from UDMFTools into UniFields, removed UDMFTools. Updated Inno Setup script (added VC++ 2008 SP1 distributive). Updated ZDoom_DECORATE.cfg (A_CheckBlock). Updated documentation (added "System Requirements" page).
2015-10-09 12:38:12 +00:00
override public bool Parse(TextResourceData data, bool clearerrors)
Removed "Paste Properties Options" action. Added "Paste Properties Special" actions in "Classic" and "Visual" categories. They work the same way as "Paste Special" action. Added: "Copy Properties", "Paste Properties" and "Paste Properties Special" options are now shown in the Edit menu if current classic mode supports them. Changed, Paste Properties Special window: only options relevant to current map format are now displayed. Changed, Paste Properties Special window, UDMF: all UI-managed options are now available. Fixed: MAPINFO parser was unable to process "include" directives. Fixed, General interface: selection info was reset to "Nothing selected" after few seconds regardless of current selection. Fixed, Visual mode: thing bounding boxes were not updated when changing things positions using Randomize mode. Fixed, Visual mode: event lines were displayed at incorrect height when entering Visual mode for the first time. Fixed, Texture Browser window: when MixTexturesFlats Game Configuration option is disabled, textures/flats are no longer shown in the Used group when flats/textures with the same names are used in the map. Fixed(?): probably fixed an exception some users reported when trying to initialize a Classic mode after switching from Visual mode with "Sync cameras" option enabled. Changed, Game configurations, Thing Categories: a block must have at least one thing category property to be recognized as a thing category. Changed, Visplane Explorer: the plugin now outputs more info when it fails to initialize vpo.dll. Cosmetic, Thing Edit window, Doom/Hexen map format: adjusted UI layout so thing flags control no longer displays scrollbars in Hexen map format. Internal: merged methods from UDMFTools into UniFields, removed UDMFTools. Updated Inno Setup script (added VC++ 2008 SP1 distributive). Updated ZDoom_DECORATE.cfg (A_CheckBlock). Updated documentation (added "System Requirements" page).
2015-10-09 12:38:12 +00:00
{
if(string.IsNullOrEmpty(mapname)) throw new NotSupportedException("Map name required!");
return Parse(data, mapname, clearerrors);
Removed "Paste Properties Options" action. Added "Paste Properties Special" actions in "Classic" and "Visual" categories. They work the same way as "Paste Special" action. Added: "Copy Properties", "Paste Properties" and "Paste Properties Special" options are now shown in the Edit menu if current classic mode supports them. Changed, Paste Properties Special window: only options relevant to current map format are now displayed. Changed, Paste Properties Special window, UDMF: all UI-managed options are now available. Fixed: MAPINFO parser was unable to process "include" directives. Fixed, General interface: selection info was reset to "Nothing selected" after few seconds regardless of current selection. Fixed, Visual mode: thing bounding boxes were not updated when changing things positions using Randomize mode. Fixed, Visual mode: event lines were displayed at incorrect height when entering Visual mode for the first time. Fixed, Texture Browser window: when MixTexturesFlats Game Configuration option is disabled, textures/flats are no longer shown in the Used group when flats/textures with the same names are used in the map. Fixed(?): probably fixed an exception some users reported when trying to initialize a Classic mode after switching from Visual mode with "Sync cameras" option enabled. Changed, Game configurations, Thing Categories: a block must have at least one thing category property to be recognized as a thing category. Changed, Visplane Explorer: the plugin now outputs more info when it fails to initialize vpo.dll. Cosmetic, Thing Edit window, Doom/Hexen map format: adjusted UI layout so thing flags control no longer displays scrollbars in Hexen map format. Internal: merged methods from UDMFTools into UniFields, removed UDMFTools. Updated Inno Setup script (added VC++ 2008 SP1 distributive). Updated ZDoom_DECORATE.cfg (A_CheckBlock). Updated documentation (added "System Requirements" page).
2015-10-09 12:38:12 +00:00
}
public bool Parse(TextResourceData data, string mapname, bool clearerrors)
{
Removed "Paste Properties Options" action. Added "Paste Properties Special" actions in "Classic" and "Visual" categories. They work the same way as "Paste Special" action. Added: "Copy Properties", "Paste Properties" and "Paste Properties Special" options are now shown in the Edit menu if current classic mode supports them. Changed, Paste Properties Special window: only options relevant to current map format are now displayed. Changed, Paste Properties Special window, UDMF: all UI-managed options are now available. Fixed: MAPINFO parser was unable to process "include" directives. Fixed, General interface: selection info was reset to "Nothing selected" after few seconds regardless of current selection. Fixed, Visual mode: thing bounding boxes were not updated when changing things positions using Randomize mode. Fixed, Visual mode: event lines were displayed at incorrect height when entering Visual mode for the first time. Fixed, Texture Browser window: when MixTexturesFlats Game Configuration option is disabled, textures/flats are no longer shown in the Used group when flats/textures with the same names are used in the map. Fixed(?): probably fixed an exception some users reported when trying to initialize a Classic mode after switching from Visual mode with "Sync cameras" option enabled. Changed, Game configurations, Thing Categories: a block must have at least one thing category property to be recognized as a thing category. Changed, Visplane Explorer: the plugin now outputs more info when it fails to initialize vpo.dll. Cosmetic, Thing Edit window, Doom/Hexen map format: adjusted UI layout so thing flags control no longer displays scrollbars in Hexen map format. Internal: merged methods from UDMFTools into UniFields, removed UDMFTools. Updated Inno Setup script (added VC++ 2008 SP1 distributive). Updated ZDoom_DECORATE.cfg (A_CheckBlock). Updated documentation (added "System Requirements" page).
2015-10-09 12:38:12 +00:00
this.mapname = mapname.ToLowerInvariant();
//mxd. Already parsed?
if(!base.AddTextResource(data))
{
if(clearerrors) ClearError();
return true;
}
// Cannot process?
if(!base.Parse(data, clearerrors)) return false;
// Keep local data
Stream localstream = datastream;
string localsourcename = sourcename;
int localsourcelumpindex = sourcelumpindex;
BinaryReader localreader = datareader;
DataLocation locallocation = datalocation;
string localtextresourcepath = textresourcepath;
// Classic format skip stoppers...
HashSet<string> breakat = new HashSet<string> { "map", "defaultmap", "adddefaultmap" };
Removed "Paste Properties Options" action. Added "Paste Properties Special" actions in "Classic" and "Visual" categories. They work the same way as "Paste Special" action. Added: "Copy Properties", "Paste Properties" and "Paste Properties Special" options are now shown in the Edit menu if current classic mode supports them. Changed, Paste Properties Special window: only options relevant to current map format are now displayed. Changed, Paste Properties Special window, UDMF: all UI-managed options are now available. Fixed: MAPINFO parser was unable to process "include" directives. Fixed, General interface: selection info was reset to "Nothing selected" after few seconds regardless of current selection. Fixed, Visual mode: thing bounding boxes were not updated when changing things positions using Randomize mode. Fixed, Visual mode: event lines were displayed at incorrect height when entering Visual mode for the first time. Fixed, Texture Browser window: when MixTexturesFlats Game Configuration option is disabled, textures/flats are no longer shown in the Used group when flats/textures with the same names are used in the map. Fixed(?): probably fixed an exception some users reported when trying to initialize a Classic mode after switching from Visual mode with "Sync cameras" option enabled. Changed, Game configurations, Thing Categories: a block must have at least one thing category property to be recognized as a thing category. Changed, Visplane Explorer: the plugin now outputs more info when it fails to initialize vpo.dll. Cosmetic, Thing Edit window, Doom/Hexen map format: adjusted UI layout so thing flags control no longer displays scrollbars in Hexen map format. Internal: merged methods from UDMFTools into UniFields, removed UDMFTools. Updated Inno Setup script (added VC++ 2008 SP1 distributive). Updated ZDoom_DECORATE.cfg (A_CheckBlock). Updated documentation (added "System Requirements" page).
2015-10-09 12:38:12 +00:00
while(SkipWhitespace(true))
{
string token = ReadToken().ToLowerInvariant();
if(string.IsNullOrEmpty(token) || token == "$gzdb_skip") break;
switch(token)
{
case "adddefaultmap":
// Parse properties
if(!ParseMapBlock()) return false;
break;
case "defaultmap":
// Reset MapInfo
mapinfo = new MapInfo();
// Parse properties
if(!ParseMapBlock()) return false;
break;
case "map":
// Get map lump name
SkipWhitespace(true);
token = ReadToken().ToLowerInvariant();
// [ZZ] Note: map name is sometimes in quotes. I think this was "fixed" some time ago, but apparently not.
token = StripQuotes(token);
if (token != this.mapname)
{
// Map number? Try to build map name from it...
int n;
if(int.TryParse(token, NumberStyles.Integer, CultureInfo.InvariantCulture, out n))
{
token = ((n > 0 && n < 10) ? "map0" + n : "map" + n);
}
// Still no dice?
if(token != this.mapname)
{
SkipStructure(breakat);
continue; // Not finished, search for next "map", "defaultmap" or "adddefaultmap" block
}
}
// Try to get map name
SkipWhitespace(true);
token = ReadToken();
if(token.ToLowerInvariant() == "lookup")
{
// No dice...
SkipWhitespace(true);
ReadToken();
}
else
{
mapinfo.Title = StripQuotes(token);
}
// Parse properties
if(!ParseMapBlock()) return false;
// There is a map entry for current map, which makes it defined
mapinfo.IsDefined = true;
break;
case "include":
if(!ParseInclude(clearerrors)) return false;
// Set our buffers back to continue parsing
datastream = localstream;
datareader = localreader;
sourcename = localsourcename;
sourcelumpindex = localsourcelumpindex;
datalocation = locallocation;
textresourcepath = localtextresourcepath;
break;
case "gameinfo":
if(!ParseGameInfo()) return false;
break;
case "doomednums":
if(!ParseDoomEdNums()) return false;
break;
case "spawnnums":
if(!ParseSpawnNums()) return false;
break;
}
}
// Check values
if(mapinfo.FogDensity > 0 && (mapinfo.FadeColor.Red > 0 || mapinfo.FadeColor.Green > 0 || mapinfo.FadeColor.Blue > 0))
mapinfo.HasFadeColor = true;
if(mapinfo.OutsideFogDensity > 0 && (mapinfo.OutsideFogColor.Red > 0 || mapinfo.OutsideFogColor.Green > 0 || mapinfo.OutsideFogColor.Blue > 0))
mapinfo.HasOutsideFogColor = true;
if(string.IsNullOrEmpty(mapinfo.Sky2) && mapinfo.DoubleSky)
{
LogWarning("\"doublesky\" flag is defined without \"Sky2\" property.");
mapinfo.DoubleSky = false;
}
// All done
return !this.HasError;
}
private bool ParseInclude(bool clearerrors)
{
SkipWhitespace(true);
string includelump = StripQuotes(ReadToken(false)); // Don't skip newline
//INFO: ZDoom MAPINFO include paths can't be relative ("../mapstuff.txt")
//or absolute ("d:/project/mapstuff.txt")
//or have backward slashes ("info\mapstuff.txt")
//include paths are relative to the first parsed entry, not the current one
//also include paths may or may not be quoted
if(!string.IsNullOrEmpty(includelump))
{
// Absolute paths are not supported...
if(Path.IsPathRooted(includelump))
{
ReportError("Absolute include paths are not supported by ZDoom");
return false;
}
// Relative paths are not supported
if(includelump.StartsWith(RELATIVE_PATH_MARKER) || includelump.StartsWith(CURRENT_FOLDER_PATH_MARKER) ||
includelump.StartsWith(ALT_RELATIVE_PATH_MARKER) || includelump.StartsWith(ALT_CURRENT_FOLDER_PATH_MARKER))
{
ReportError("Relative include paths are not supported by ZDoom");
return false;
}
// Backward slashes are not supported
if(includelump.Contains("\\"))
{
ReportError("Only forward slashes are supported by ZDoom");
return false;
}
// Check invalid path chars
if(!CheckInvalidPathChars(includelump)) return false;
// Already parsed?
if(parsedlumps.Contains(includelump))
{
ReportError("Already parsed \"" + includelump + "\". Check your include directives");
return false;
}
// Add to collection
parsedlumps.Add(includelump);
// Callback to parse this file
if(OnInclude != null)
{
OnInclude(this, includelump, clearerrors);
// Bail out on error
if(this.HasError) return false;
}
}
else
{
ReportError("Expected filename to include");
return false;
}
// All done here
return true;
}
private bool ParseGameInfo()
{
if(!NextTokenIs("{")) return false; // Finished with this file
while(SkipWhitespace(true))
{
string token = ReadToken();
if(string.IsNullOrEmpty(token))
{
ReportError("Failed to find the end of GameInfo block");
return false; // Finished with this file
}
if(token == "}") break;
if(token.ToLowerInvariant() == "skyflatname")
{
if(!NextTokenIs("=")) return false; // Finished with this file
SkipWhitespace(true);
string skyflatname = StripQuotes(ReadToken());
if(string.IsNullOrEmpty(skyflatname))
{
ReportError("Expected SkyFlatName value");
return false; // Finished with this file
}
General.Map.Config.SkyFlatName = skyflatname.ToUpperInvariant();
}
}
// All done here
return true;
}
private bool ParseDoomEdNums()
{
if(!NextTokenIs("{")) return false; // Finished with this file
while(SkipWhitespace(true))
{
string token = ReadToken();
if(string.IsNullOrEmpty(token))
{
ReportError("Failed to find the end of DoomEdNums block");
return false; // Finished with this file
}
if(token == "}") break;
// First must be a number
int id;
if(!int.TryParse(token, NumberStyles.Integer, CultureInfo.InvariantCulture, out id))
{
// Not numeric!
ReportError("Expected DoomEdNums entry number, but got \"" + token + "\"");
return false; // Finished with this file
}
// Then "="
if(!NextTokenIs("=")) return false; // Finished with this file
// Then actor class
SkipWhitespace(false);
string classname = StripQuotes(ReadToken());
if(string.IsNullOrEmpty(classname))
{
ReportError("Expected DoomEdNums class definition");
return false; // Finished with this file
}
// Possible special and args. We'll skip them
for(int i = 0; i < 6; i++)
{
if(!NextTokenIs(",", false)) break;
// Read special name or arg value
if(!SkipWhitespace(true) || string.IsNullOrEmpty(ReadToken())) return false;
}
// Add to collection?
if(id != 0) doomednums[id] = classname.ToLowerInvariant();
}
// All done here
return true;
}
private bool ParseSpawnNums()
{
if(!NextTokenIs("{")) return false; // Finished with this file
while(SkipWhitespace(true))
{
string token = ReadToken();
if(string.IsNullOrEmpty(token))
{
ReportError("Failed to find the end of SpawnNums block");
return false; // Finished with this file
}
if(token == "}") break;
// First must be a number
int id;
if(!int.TryParse(token, NumberStyles.Integer, CultureInfo.InvariantCulture, out id))
{
// Not numeric!
ReportError("Expected SpawnNums number, but got \"" + token + "\"");
return false; // Finished with this file
}
// Then "="
if(!NextTokenIs("=")) return false; // Finished with this file
// Then actor class
SkipWhitespace(false);
token = StripQuotes(ReadToken());
if(string.IsNullOrEmpty(token))
{
ReportError("Unable to get SpawnNums entry class definition");
return false;
}
// Range check
if((id < General.Map.FormatInterface.MinThingType) || (id > General.Map.FormatInterface.MaxThingType))
{
// Out of bounds!
ReportError("\"" + token + "\" actor's spawn number must be between "
+ General.Map.FormatInterface.MinThingType + " and " + General.Map.FormatInterface.MaxThingType);
return false; // Finished with this file
}
// Add to collection
spawnnums[id] = token.ToLowerInvariant();
}
// All done here
return true;
}
#endregion
#region ================== Map block parsing
private bool ParseMapBlock()
{
bool classicformat = !NextTokenIs("{", false);
// Track brace level
int bracelevel = (classicformat ? 0 : 1); // Track map block opening brace
// Parse required values
while(SkipWhitespace(true))
{
string token = ReadToken().ToLowerInvariant();
switch(token)
{
//TODO: are there any other blocks available in the classic format?..
case "map": case "defaultmap": case "adddefaultmap":
if(classicformat)
{
// We parsed too greadily, step back
DataStream.Seek(-token.Length - 1, SeekOrigin.Current);
// Finished with this block
return true;
}
else
{
ReportError("Unexpected token \"" + token + "\"");
return false;
}
case "sky2": case "sky1":
if(!ParseSky(token)) return false;
break;
case "skybox":
if(!ParseSkybox()) return false;
break;
case "outsidefog": case "fade":
if(!ParseFade(token)) return false;
break;
case "horizwallshade": case "vertwallshade":
if(!ParseWallShade(token)) return false;
break;
case "outsidefogdensity": case "fogdensity":
if(!ParseFogDensity(token)) return false;
break;
case "doublesky":
mapinfo.DoubleSky = true;
break;
case "evenlighting":
mapinfo.EvenLighting = true;
break;
case "smoothlighting":
mapinfo.SmoothLighting = true;
break;
case "lightmode":
if(!ParseLightMode()) return false;
break;
// [ZZ]
case "pixelratio":
if (!ParsePixelRatio()) return false;
break;
// biwa
case "forceworldpanning":
mapinfo.ForceWorldPanning = true;
break;
case "}": return true; // Block end
case "{": // Skip inner blocks
bracelevel++;
if(bracelevel > 1)
{
do
{
SkipWhitespace(true);
token = ReadToken();
if(token == "{") bracelevel++;
else if(token == "}") bracelevel--;
} while(!string.IsNullOrEmpty(token) && bracelevel > 1);
}
break;
}
}
// All done here
return true;
}
private bool ParseSky(string skytype)
{
SkipWhitespace(true);
string token = StripQuotes(ReadToken());
// New format
if(token == "=")
{
SkipWhitespace(true);
// Should be sky texture name
token = StripQuotes(ReadToken());
bool gotcomma = (token.IndexOf(",", StringComparison.Ordinal) != -1);
if(gotcomma) token = token.Replace(",", "");
string skytexture = token.ToUpperInvariant();
if(string.IsNullOrEmpty(skytexture))
{
ReportError("Expected " + skytype + " texture name");
return false;
}
if(skytype == "sky1")
mapinfo.Sky1 = skytexture;
else
mapinfo.Sky2 = skytexture;
// Check if we have scrollspeed
SkipWhitespace(true);
token = ReadToken();
if(!gotcomma && token == ",")
{
gotcomma = true;
SkipWhitespace(true);
token = ReadToken();
}
if(gotcomma)
{
float scrollspeed = 0;
if(!ReadSignedFloat(token, ref scrollspeed))
{
// Not numeric!
ReportError("Expected " + skytype + " scroll speed value, but got \"" + token + "\"");
return false;
}
if(skytype == "sky1")
mapinfo.Sky1ScrollSpeed = scrollspeed;
else
mapinfo.Sky2ScrollSpeed = scrollspeed;
}
else
{
datastream.Seek(-token.Length - 1, SeekOrigin.Current); // Step back and try parsing this token again
}
}
// Old format
else
{
// Token should be sky1/2 name
if(string.IsNullOrEmpty(token))
{
ReportError("Expected " + skytype + " texture name");
return false;
}
if(skytype == "sky1")
mapinfo.Sky1 = token.ToUpperInvariant();
else
mapinfo.Sky2 = token.ToUpperInvariant();
// Try to read scroll speed
SkipWhitespace(true);
token = ReadToken();
float scrollspeed = 0;
if(!ReadSignedFloat(token, ref scrollspeed))
{
// Not numeric!
datastream.Seek(-token.Length - 1, SeekOrigin.Current); // Step back and try parsing this token again
return true;
}
if(skytype == "sky1")
mapinfo.Sky1ScrollSpeed = scrollspeed;
else
mapinfo.Sky2ScrollSpeed = scrollspeed;
}
// All done here
return true;
}
// Skybox = "<texture>"
private bool ParseSkybox()
{
// New format only!
if(!NextTokenIs("=")) return false;
SkipWhitespace(true);
string token = StripQuotes(ReadToken());
if(string.IsNullOrEmpty(token))
{
ReportError("Expected Skybox texture name");
return false;
}
mapinfo.Sky1 = token.ToUpperInvariant();
mapinfo.Sky1ScrollSpeed = 0;
// All done here
return true;
}
private bool ParseFade(string fadetype)
{
SkipWhitespace(true);
string token = ReadToken();
// New format?
if(token == "=")
{
SkipWhitespace(true);
token = ReadToken();
}
// Get the color value
string colorval = StripQuotes(token).ToLowerInvariant().Replace(" ", "");
if(string.IsNullOrEmpty(colorval))
{
ReportError("Expected " + fadetype + " color value");
return false;
}
// Try to get the color...
PixelColor color = new PixelColor();
if(GetColorFromString(colorval, out color))
{
if(fadetype == "fade")
mapinfo.FadeColor = color.ToColorValue();
else
mapinfo.OutsideFogColor = color.ToColorValue();
}
else //...or not
{
ReportError("Failed to parse " + fadetype + " value from string \"" + colorval + "\"");
return false;
}
// All done here
return true;
}
private bool ParseWallShade(string shadetype)
{
SkipWhitespace(true);
string token = ReadToken();
// New format
if(token == "=")
{
SkipWhitespace(true);
token = ReadToken();
}
int val = 0;
if(!ReadSignedInt(token, ref val))
{
// Not numeric!
ReportError("Expected " + shadetype + " value, but got \"" + token + "\"");
return false;
}
if(shadetype == "vertwallshade")
mapinfo.VertWallShade = General.Clamp(val, -255, 255);
else
mapinfo.HorizWallShade = General.Clamp(val, -255, 255);
// All done here
return true;
}
private bool ParseFogDensity(string densitytype)
{
SkipWhitespace(true);
if(!NextTokenIs("=")) return false; // New format only
SkipWhitespace(true);
string token = StripQuotes(ReadToken());
int val;
if(!int.TryParse(token, NumberStyles.Integer, CultureInfo.InvariantCulture, out val))
{
// Not numeric!
ReportError("Expected " + densitytype + " value, but got \"" + token + "\"");
return false;
}
if(densitytype == "fogdensity") mapinfo.FogDensity = val;
else mapinfo.OutsideFogDensity = val;
// All done here
return true;
}
private bool ParseLightMode()
{
SkipWhitespace(true);
if(!NextTokenIs("=")) return false; // New format only
SkipWhitespace(true);
string token = ReadToken();
int val;
if(!int.TryParse(token, NumberStyles.Integer, CultureInfo.InvariantCulture, out val))
{
// Not numeric!
ReportError("Expected LightMode value, but got \"" + token + "\"");
return false;
}
// Store
mapinfo.LightMode = (MapInfo.GZDoomLightMode)val;
// All done here
return true;
}
private bool ParsePixelRatio()
{
SkipWhitespace(true);
if (!NextTokenIs("=")) return false; // New format only
SkipWhitespace(true);
string token = ReadToken();
float val;
if (!float.TryParse(token, NumberStyles.Float, CultureInfo.InvariantCulture, out val))
{
// Not numeric!
ReportError("Expected PixelRatio value, but got \"" + token + "\"");
return false;
}
// Store
mapinfo.PixelRatio = val;
// All done here
return true;
}
#endregion
}
}