diff --git a/Source/Core/Properties/AssemblyInfo.cs b/Source/Core/Properties/AssemblyInfo.cs
index e3c96d8b903aac3ef77463fbbe68f580b1eae6d7..4d44e34792819ff0d6083ba48df8e91e64053c75 100755
--- a/Source/Core/Properties/AssemblyInfo.cs
+++ b/Source/Core/Properties/AssemblyInfo.cs
@@ -30,6 +30,6 @@ using CodeImp.DoomBuilder;
 //      Build Number
 //      Revision
 //
-[assembly: AssemblyVersion("2.3.0.2827")]
+[assembly: AssemblyVersion("2.3.0.2828")]
 [assembly: NeutralResourcesLanguageAttribute("en")]
-[assembly: AssemblyHash("05a160b")]
+[assembly: AssemblyHash("dc72c53")]
diff --git a/Source/Core/ZDoom/ZScriptParser.cs b/Source/Core/ZDoom/ZScriptParser.cs
index d3366181f852f9329952964747c1f9ee7ba4ded4..c0b92375c17c4acb55605394c22a90a100220e15 100755
--- a/Source/Core/ZDoom/ZScriptParser.cs
+++ b/Source/Core/ZDoom/ZScriptParser.cs
@@ -833,6 +833,7 @@ namespace CodeImp.DoomBuilder.ZDoom
             }
 
             // inject superclasses, since everything is parsed by now
+            Dictionary<int, ThingTypeInfo> things = General.Map.Config.GetThingTypes();
             foreach (ZScriptClassStructure cls in allclasseslist)
             {
                 ActorStructure actor = cls.Actor;
@@ -843,7 +844,6 @@ namespace CodeImp.DoomBuilder.ZDoom
                     if (actor.baseclass == null)
                     {
                         //check if this class inherits from a class defined in game configuration
-                        Dictionary<int, ThingTypeInfo> things = General.Map.Config.GetThingTypes();
                         string inheritclasscheck = inheritclass.ToLowerInvariant();
 
                         bool thingfound = false;
diff --git a/Source/Core/ZDoom/ZScriptTokenizer.cs b/Source/Core/ZDoom/ZScriptTokenizer.cs
index 06d22b52c1ce950b65047b2b25366844f72b197f..8321a225bd8fd5d68531cbe909a7be11b4d3bae7 100755
--- a/Source/Core/ZDoom/ZScriptTokenizer.cs
+++ b/Source/Core/ZDoom/ZScriptTokenizer.cs
@@ -117,6 +117,7 @@ namespace CodeImp.DoomBuilder.ZDoom
     {
         private BinaryReader reader;
         private Dictionary<string, ZScriptTokenType> namedtokentypes; // these are tokens that have precise equivalent in the enum (like operators)
+        private Dictionary<ZScriptTokenType, string> namedtokentypesreverse; // these are tokens that have precise equivalent in the enum (like operators)
         private List<string> namedtokentypesorder; // this is the list of said tokens ordered by length.
 
         public long LastPosition { get; private set; }
@@ -125,6 +126,7 @@ namespace CodeImp.DoomBuilder.ZDoom
         {
             reader = br;
             namedtokentypes = new Dictionary<string, ZScriptTokenType>();
+            namedtokentypesreverse = new Dictionary<ZScriptTokenType, string>();
             namedtokentypesorder = new List<string>();
             // initialize the token type list.
             IEnumerable<ZScriptTokenType> tokentypes = Enum.GetValues(typeof(ZScriptTokenType)).Cast<ZScriptTokenType>();
@@ -136,6 +138,7 @@ namespace CodeImp.DoomBuilder.ZDoom
                 if (attrs.Length == 0) continue;
                 // 
                 namedtokentypes.Add(attrs[0].Value, tokentype);
+                namedtokentypesreverse.Add(tokentype, attrs[0].Value);
                 namedtokentypesorder.Add(attrs[0].Value);
             }
 
@@ -158,292 +161,402 @@ namespace CodeImp.DoomBuilder.ZDoom
             }
         }
 
-        public ZScriptToken ExpectToken(params ZScriptTokenType[] oneof)
+        private ZScriptToken TryReadWhitespace()
         {
-            long cpos = reader.BaseStream.Position;
+            long cpos = LastPosition = reader.BaseStream.Position;
+            char c = reader.ReadChar();
+
+            // 
+            string whitespace = " \r\t\u00A0";
+
+            // check whitespace
+            if (whitespace.Contains(c))
+            {
+                string ws_content = "";
+                ws_content += c;
+                while (true)
+                {
+                    char cnext = reader.ReadChar();
+                    if (whitespace.Contains(cnext))
+                    {
+                        ws_content += cnext;
+                        continue;
+                    }
+
+                    reader.BaseStream.Position--;
+                    break;
+                }
 
-            ZScriptToken tok = ReadToken();
-            if (tok == null) return null;
+                ZScriptToken tok = new ZScriptToken();
+                tok.Type = ZScriptTokenType.Whitespace;
+                tok.Value = ws_content;
+                return tok;
+            }
 
-            tok.IsValid = (oneof.Contains(tok.Type));
-            if (!tok.IsValid) reader.BaseStream.Position = cpos;
-            return tok;
+            reader.BaseStream.Position = cpos;
+            return null;
         }
 
-        // short_circuit only checks for string literals and "everything else", reporting "everything else" as invalid tokens
-        public ZScriptToken ReadToken(bool short_circuit = false)
+        private ZScriptToken TryReadIdentifier()
         {
-            try
+            long cpos = LastPosition = reader.BaseStream.Position;
+            char c = reader.ReadChar();
+
+            // check identifier
+            if ((c >= 'a' && c <= 'z') ||
+                (c >= 'A' && c <= 'Z') ||
+                (c == '_'))
             {
-                ZScriptToken tok;
+                string id_content = "";
+                id_content += c;
+                while (true)
+                {
+                    char cnext = reader.ReadChar();
+                    if ((cnext >= 'a' && cnext <= 'z') ||
+                        (cnext >= 'A' && cnext <= 'Z') ||
+                        (cnext == '_') ||
+                        (cnext >= '0' && cnext <= '9'))
+                    {
+                        id_content += cnext;
+                        continue;
+                    }
 
-                long cpos = reader.BaseStream.Position; // I really hope we can rewind this <_<
-                char c = reader.ReadChar();
-                LastPosition = cpos;
+                    reader.BaseStream.Position--;
+                    break;
+                }
 
-                // 
-                string whitespace = " \r\t\u00A0";
+                ZScriptToken tok = new ZScriptToken();
+                tok.Type = ZScriptTokenType.Identifier;
+                tok.Value = id_content;
+                return tok;
+            }
 
-                // check whitespace
-                if (whitespace.Contains(c))
+            reader.BaseStream.Position = cpos;
+            return null;
+        }
+
+        private ZScriptToken TryReadNumber()
+        {
+            long cpos = LastPosition = reader.BaseStream.Position;
+            char c = reader.ReadChar();
+
+            // check integer
+            if ((c >= '0' && c <= '9') || c == '.')
+            {
+                bool isint = true;
+                bool isdouble = (c == '.');
+                bool isexponent = false;
+                if (isdouble) // make sure next character is an integer, otherwise its probably a member access
                 {
-                    string ws_content = "";
-                    ws_content += c;
-                    while (true)
+                    char cnext = reader.ReadChar();
+                    if (!(cnext >= '0' && cnext <= '9'))
                     {
-                        char cnext = reader.ReadChar();
-                        if (whitespace.Contains(cnext))
-                        {
-                            ws_content += cnext;
-                            continue;
-                        }
-
+                        isint = false;
                         reader.BaseStream.Position--;
-                        break;
                     }
-
-                    tok = new ZScriptToken();
-                    tok.Type = ZScriptTokenType.Whitespace;
-                    tok.Value = ws_content;
-                    return tok;
                 }
 
-                if (!short_circuit)
+                if (isint)
                 {
-                    // check identifier
-                    if ((c >= 'a' && c <= 'z') ||
-                        (c >= 'A' && c <= 'Z') ||
-                        (c == '_'))
+                    bool isoctal = (c == '0');
+                    bool ishex = false;
+                    string i_content = "";
+                    i_content += c;
+                    while (true)
                     {
-                        string id_content = "";
-                        id_content += c;
-                        while (true)
+                        char cnext = reader.ReadChar();
+                        if (!isdouble && (cnext == 'x') && i_content.Length == 1)
+                        {
+                            isoctal = false;
+                            ishex = true;
+                        }
+                        else if ((cnext >= '0' && cnext <= '7') ||
+                                 (!isoctal && cnext >= '8' && cnext <= '9') ||
+                                 (ishex && ((cnext >= 'a' && cnext <= 'f') || (cnext >= 'A' && cnext <= 'F'))))
+                        {
+                            i_content += cnext;
+                        }
+                        else if (!ishex && !isdouble && !isexponent && cnext == '.')
+                        {
+                            isdouble = true;
+                            isoctal = false;
+                            i_content += '.';
+                        }
+                        else if (!isoctal && !ishex && !isexponent && (cnext == 'e' || cnext == 'E'))
+                        {
+                            isexponent = true;
+                            isdouble = true;
+                            i_content += 'e';
+                            cnext = reader.ReadChar();
+                            if (cnext == '-') i_content += '-';
+                            else reader.BaseStream.Position--;
+                        }
+                        else
                         {
-                            char cnext = reader.ReadChar();
-                            if ((cnext >= 'a' && cnext <= 'z') ||
-                                (cnext >= 'A' && cnext <= 'Z') ||
-                                (cnext == '_') ||
-                                (cnext >= '0' && cnext <= '9'))
-                            {
-                                id_content += cnext;
-                                continue;
-                            }
-
                             reader.BaseStream.Position--;
                             break;
                         }
-
-                        tok = new ZScriptToken();
-                        tok.Type = ZScriptTokenType.Identifier;
-                        tok.Value = id_content;
-                        return tok;
                     }
 
-                    // check integer
-                    if ((c >= '0' && c <= '9') || c == '.')
+                    ZScriptToken tok = new ZScriptToken();
+                    tok.Type = (isdouble ? ZScriptTokenType.Double : ZScriptTokenType.Integer);
+                    tok.Value = i_content;
+                    try
                     {
-                        bool isint = true;
-                        bool isdouble = (c == '.');
-                        bool isexponent = false;
-                        if (isdouble) // make sure next character is an integer, otherwise its probably a member access
+                        if (ishex || isoctal || !isdouble)
                         {
-                            char cnext = reader.ReadChar();
-                            if (!(cnext >= '0' && cnext <= '9'))
-                            {
-                                isint = false;
-                                reader.BaseStream.Position--;
-                            }
+                            int numbase = 10;
+                            if (ishex) numbase = 16;
+                            else if (isoctal) numbase = 8;
+                            tok.ValueInt = Convert.ToInt32(tok.Value, numbase);
+                            tok.ValueDouble = tok.ValueInt;
+                        }
+                        else if (isdouble)
+                        {
+                            string dval = (tok.Value[0] == '.') ? "0" + tok.Value : tok.Value;
+                            tok.ValueDouble = Convert.ToDouble(dval);
+                            tok.ValueInt = (int)tok.ValueDouble;
                         }
+                    }
+                    catch (Exception)
+                    {
+                        //throw new Exception(tok.ToString());
+                        return null;
+                    }
+
+                    return tok;
+                }
+            }
+
+            reader.BaseStream.Position = cpos;
+            return null;
+        }
+
+        private ZScriptToken TryReadStringOrComment(bool allowstring, bool allowname, bool allowblock, bool allowline)
+        {
+            long cpos = LastPosition = reader.BaseStream.Position;
+            char c = reader.ReadChar();
 
-                        if (isint)
+            switch (c)
+            {
+                case '/': // comment
+                    {
+                        if (!allowblock && !allowline) break;
+                        char cnext = reader.ReadChar();
+                        if (cnext == '/')
                         {
-                            bool isoctal = (c == '0');
-                            bool ishex = false;
-                            string i_content = "";
-                            i_content += c;
+                            if (!allowline) break;
+                            // line comment: read until newline but not including it
+                            string cmt = "";
                             while (true)
                             {
-                                char cnext = reader.ReadChar();
-                                if (!isdouble && (cnext == 'x') && i_content.Length == 1)
-                                {
-                                    isoctal = false;
-                                    ishex = true;
-                                }
-                                else if ((cnext >= '0' && cnext <= '7') ||
-                                         (!isoctal && cnext >= '8' && cnext <= '9') ||
-                                         (ishex && ((cnext >= 'a' && cnext <= 'f') || (cnext >= 'A' && cnext <= 'F'))))
-                                {
-                                    i_content += cnext;
-                                }
-                                else if (!ishex && !isdouble && !isexponent && cnext == '.')
-                                {
-                                    isdouble = true;
-                                    isoctal = false;
-                                    i_content += '.';
-                                }
-                                else if (!isoctal && !ishex && !isexponent && (cnext == 'e' || cnext == 'E'))
-                                {
-                                    isexponent = true;
-                                    isdouble = true;
-                                    i_content += 'e';
-                                    cnext = reader.ReadChar();
-                                    if (cnext == '-') i_content += '-';
-                                    else reader.BaseStream.Position--;
-                                }
-                                else
+                                cnext = reader.ReadChar();
+                                if (cnext == '\n')
                                 {
                                     reader.BaseStream.Position--;
                                     break;
                                 }
-                            }
 
-                            tok = new ZScriptToken();
-                            tok.Type = (isdouble ? ZScriptTokenType.Double : ZScriptTokenType.Integer);
-                            tok.Value = i_content;
-                            try
-                            {
-                                if (ishex || isoctal || !isdouble)
-                                {
-                                    int numbase = 10;
-                                    if (ishex) numbase = 16;
-                                    else if (isoctal) numbase = 8;
-                                    tok.ValueInt = Convert.ToInt32(tok.Value, numbase);
-                                    tok.ValueDouble = tok.ValueInt;
-                                }
-                                else if (isdouble)
-                                {
-                                    string dval = (tok.Value[0] == '.') ? "0" + tok.Value : tok.Value;
-                                    tok.ValueDouble = Convert.ToDouble(dval);
-                                    tok.ValueInt = (int)tok.ValueDouble;
-                                }
-                            }
-                            catch (Exception)
-                            {
-                                //throw new Exception(tok.ToString());
-                                return null;
+                                cmt += cnext;
                             }
 
+                            ZScriptToken tok = new ZScriptToken();
+                            tok.Type = ZScriptTokenType.LineComment;
+                            tok.Value = cmt;
                             return tok;
                         }
-                    }
-                }
-
-                // check everything else
-                switch (c)
-                {
-                    case '\n': // newline
+                        else if (cnext == '*')
                         {
-                            ZScriptToken newline = new ZScriptToken();
-                            newline.Type = ZScriptTokenType.Newline;
-                            newline.Value += c;
-                            return newline;
-                        }
-
-                    case '/': // comment
-                        {
-                            char cnext = reader.ReadChar();
-                            if (cnext == '/')
+                            if (!allowblock) break;
+                            // block comment: read until closing sequence
+                            string cmt = "";
+                            while (true)
                             {
-                                // line comment: read until newline but not including it
-                                string cmt = "";
-                                while (true)
+                                cnext = reader.ReadChar();
+                                if (cnext == '*')
                                 {
-                                    cnext = reader.ReadChar();
-                                    if (cnext == '\n')
-                                    {
-                                        reader.BaseStream.Position--;
+                                    char cnext2 = reader.ReadChar();
+                                    if (cnext2 == '/')
                                         break;
-                                    }
 
-                                    cmt += cnext;
+                                    reader.BaseStream.Position--;
                                 }
 
-                                tok = new ZScriptToken();
-                                tok.Type = ZScriptTokenType.LineComment;
-                                tok.Value = cmt;
-                                return tok;
+                                cmt += cnext;
                             }
-                            else if (cnext == '*')
-                            {
-                                // block comment: read until closing sequence
-                                string cmt = "";
-                                while (true)
-                                {
-                                    cnext = reader.ReadChar();
-                                    if (cnext == '*')
-                                    {
-                                        char cnext2 = reader.ReadChar();
-                                        if (cnext2 == '/')
-                                            break;
-
-                                        reader.BaseStream.Position--;
-                                    }
-
-                                    cmt += cnext;
-                                }
 
-                                tok = new ZScriptToken();
-                                tok.Type = ZScriptTokenType.BlockComment;
-                                tok.Value = cmt;
-                                return tok;
-                            }
-                            break;
+                            ZScriptToken tok = new ZScriptToken();
+                            tok.Type = ZScriptTokenType.BlockComment;
+                            tok.Value = cmt;
+                            return tok;
                         }
+                        break;
+                    }
 
-                    case '"':
-                    case '\'':
+                case '"':
+                case '\'':
+                    {
+                        if ((c == '"' && !allowstring) || (c == '\'' && !allowname)) break;
+                        ZScriptTokenType type = (c == '"' ? ZScriptTokenType.String : ZScriptTokenType.Name);
+                        string s = "";
+                        while (true)
                         {
-                            ZScriptTokenType type = (c == '"' ? ZScriptTokenType.String : ZScriptTokenType.Name);
-                            string s = "";
-                            while (true)
+                            // todo: parse escape sequences properly
+                            char cnext = reader.ReadChar();
+                            if (cnext == '\\') // escape sequence. right now, do nothing
                             {
-                                // todo: parse escape sequences properly
-                                char cnext = reader.ReadChar();
-                                if (cnext == '\\') // escape sequence. right now, do nothing
-                                {
-                                    cnext = reader.ReadChar();
-                                    s += cnext;
-                                }
-                                else if (cnext == c)
-                                {
-                                    tok = new ZScriptToken();
-                                    tok.Type = type;
-                                    tok.Value = s;
-                                    return tok;
-                                }
-                                else s += cnext;
+                                cnext = reader.ReadChar();
+                                s += cnext;
+                            }
+                            else if (cnext == c)
+                            {
+                                ZScriptToken tok = new ZScriptToken();
+                                tok.Type = type;
+                                tok.Value = s;
+                                return tok;
                             }
+                            else s += cnext;
                         }
+                    }
+
+            }
+
+            reader.BaseStream.Position = cpos;
+            return null;
+        }
+
+        private ZScriptToken TryReadNamedToken()
+        {
+            long cpos = LastPosition = reader.BaseStream.Position;
 
+            // named tokens
+            char[] namedtoken_buf = reader.ReadChars(namedtokentypesorder[0].Length);
+            string namedtoken = new string(namedtoken_buf);
+            foreach (string namedtokentype in namedtokentypesorder)
+            {
+                if (namedtoken.StartsWith(namedtokentype))
+                {
+                    // found the token.
+                    reader.BaseStream.Position = cpos + namedtokentype.Length;
+                    ZScriptToken tok = new ZScriptToken();
+                    tok.Type = namedtokentypes[namedtokentype];
+                    tok.Value = namedtokentype;
+                    return tok;
                 }
+            }
 
-                reader.BaseStream.Position = cpos;
+            reader.BaseStream.Position = cpos;
+            return null;
+        }
 
-                if (!short_circuit)
+        public ZScriptToken ExpectToken(params ZScriptTokenType[] oneof)
+        {
+            long cpos = reader.BaseStream.Position;
+
+            try
+            {
+                // try to expect whitespace
+                if (oneof.Contains(ZScriptTokenType.Whitespace))
+                {
+                    ZScriptToken tok = TryReadWhitespace();
+                    if (tok != null) return tok;
+                }
+
+                // try to expect an identifier
+                if (oneof.Contains(ZScriptTokenType.Identifier))
+                {
+                    ZScriptToken tok = TryReadIdentifier();
+                    if (tok != null) return tok;
+                }
+
+                bool blinecomment = oneof.Contains(ZScriptTokenType.LineComment);
+                bool bblockcomment = oneof.Contains(ZScriptTokenType.BlockComment);
+                bool bstring = oneof.Contains(ZScriptTokenType.String);
+                bool bname = oneof.Contains(ZScriptTokenType.Name);
+
+                if (bstring || bname || bblockcomment || blinecomment)
+                {
+                    // try to expect a string
+                    ZScriptToken tok = TryReadStringOrComment(bstring, bname, bblockcomment, blinecomment);
+                    if (tok != null) return tok;
+                }
+
+                // if we are expecting a number (double or int), try to read it
+                if (oneof.Contains(ZScriptTokenType.Integer) || oneof.Contains(ZScriptTokenType.Double))
                 {
-                    // named tokens
-                    char[] namedtoken_buf = reader.ReadChars(namedtokentypesorder[0].Length);
-                    string namedtoken = new string(namedtoken_buf);
-                    foreach (string namedtokentype in namedtokentypesorder)
+                    ZScriptToken tok = TryReadNumber();
+                    if (tok != null && oneof.Contains(tok.Type)) return tok;
+                }
+
+                // try to expect special tokens
+                // read max
+                char[] namedtoken_buf = reader.ReadChars(namedtokentypesorder[0].Length);
+                string namedtoken = new string(namedtoken_buf);
+                foreach (ZScriptTokenType expected in oneof)
+                {
+                    // check if there is a value for this one
+                    if (!namedtokentypesreverse.ContainsKey(expected))
+                        continue;
+                    string namedtokentype = namedtokentypesreverse[expected];
+                    if (namedtoken.StartsWith(namedtokentype))
                     {
-                        if (namedtoken.StartsWith(namedtokentype))
-                        {
-                            // found the token.
-                            reader.BaseStream.Position = cpos + namedtokentype.Length;
-                            tok = new ZScriptToken();
-                            tok.Type = namedtokentypes[namedtokentype];
-                            tok.Value = namedtokentype;
-                            return tok;
-                        }
+                        // found the token.
+                        reader.BaseStream.Position = cpos + namedtokentype.Length;
+                        ZScriptToken tok = new ZScriptToken();
+                        tok.Type = namedtokentypes[namedtokentype];
+                        tok.Value = namedtokentype;
+                        return tok;
                     }
                 }
+            }
+            catch (IOException)
+            {
+                reader.BaseStream.Position = cpos;
+                return null;
+            }
+
+            // token was not found, try to read the token that was actually found and return that
+            reader.BaseStream.Position = cpos;
+            ZScriptToken invalid = ReadToken();
+            invalid.IsValid = false;
+            reader.BaseStream.Position = cpos;
+            return invalid;
+        }
+
+        // short_circuit only checks for string literals and "everything else", reporting "everything else" as invalid tokens
+        public ZScriptToken ReadToken(bool short_circuit = false)
+        {
+            try
+            {
+                ZScriptToken tok;
+
+                // 
+                tok = TryReadWhitespace();
+                if (tok != null) return tok;
+
+                if (!short_circuit)
+                {
+                    tok = TryReadIdentifier();
+                    if (tok != null) return tok;
+
+                    tok = TryReadNumber();
+                    if (tok != null) return tok;
+                }
+
+                tok = TryReadStringOrComment(true, true, true, true);
+                if (tok != null) return tok;
+
+                if (!short_circuit)
+                {
+                    tok = TryReadNamedToken();
+                    if (tok != null) return tok;
+                }
 
                 // token not found.
                 tok = new ZScriptToken();
                 tok.Type = ZScriptTokenType.Invalid;
-                tok.Value = "" + c;
+                tok.Value = "" + reader.ReadChar();
                 tok.IsValid = false;
-                reader.BaseStream.Position = cpos+1;
                 return tok;
             }
             catch (IOException)
diff --git a/Source/Plugins/BuilderModes/Properties/AssemblyInfo.cs b/Source/Plugins/BuilderModes/Properties/AssemblyInfo.cs
index b4cf7c92c170afcb6ca85a89e7be6a1a38c8a937..49e3e16f68e3087f188d635a006544b7c882ce0b 100755
--- a/Source/Plugins/BuilderModes/Properties/AssemblyInfo.cs
+++ b/Source/Plugins/BuilderModes/Properties/AssemblyInfo.cs
@@ -29,5 +29,5 @@ using System.Resources;
 //      Build Number
 //      Revision
 //
-[assembly: AssemblyVersion("2.3.0.2827")]
+[assembly: AssemblyVersion("2.3.0.2828")]
 [assembly: NeutralResourcesLanguageAttribute("en")]