Exemple #1
0
        internal ZScriptStateStructure(ActorStructure actor, ZDTextParser zdparser)
        {
            ZScriptParser    parser    = (ZScriptParser)zdparser;
            Stream           stream    = parser.DataStream;
            ZScriptTokenizer tokenizer = new ZScriptTokenizer(parser.DataReader);

            parser.tokenizer = tokenizer;

            // todo: parse stuff
            //
            string[] control_keywords = new string[] { "goto", "loop", "wait", "fail", "stop" };

            while (true)
            {
                // expect identifier or string.
                // if it's an identifier, it can be goto/loop/wait/fail/stop.
                // if it's a string, it's always a sprite name.
                tokenizer.SkipWhitespace();
                long         cpos  = stream.Position;
                ZScriptToken token = tokenizer.ExpectToken(ZScriptTokenType.Identifier, ZScriptTokenType.String, ZScriptTokenType.CloseCurly);
                if (token == null || !token.IsValid)
                {
                    ZScriptToken _token = TryReadSprite(parser, stream, tokenizer);
                    if (_token == null)
                    {
                        parser.ReportError("Expected identifier or string, got " + ((Object)token ?? "<null>").ToString());
                        return;
                    }

                    token = _token;
                }

                if (token.Type == ZScriptTokenType.CloseCurly)
                {
                    stream.Position--;
                    break; // done
                }
                else if (token.Type == ZScriptTokenType.Identifier)
                {
                    string s_keyword = token.Value.ToLowerInvariant();
                    if (control_keywords.Contains(s_keyword))
                    {
                        if (s_keyword == "goto") // just use decorate goto here. should work. but check for semicolon!
                        {
                            gotostate        = new ZScriptStateGoto(actor, parser);
                            parser.tokenizer = tokenizer;
                        }

                        //parser.LogWarning(string.Format("keyword {0}", s_keyword));

                        tokenizer.SkipWhitespace();
                        token = tokenizer.ExpectToken(ZScriptTokenType.Semicolon);
                        if (token == null || !token.IsValid)
                        {
                            parser.ReportError("Expected ;, got " + ((Object)token ?? "<null>").ToString());
                            return;
                        }

                        continue;
                    }
                }

                // make sure it's not a label of the next state. if it is, break out.
                long         cpos2     = stream.Position; // local rewind point
                ZScriptToken token2    = tokenizer.ExpectToken(ZScriptTokenType.Colon, ZScriptTokenType.Dot);
                bool         nextstate = (token2 != null && token2.IsValid);
                stream.Position = cpos2; // rewind to before state label read
                if (nextstate)
                {
                    stream.Position = cpos;
                    break;
                }

                // it's a frame definition. read it.
                string spritename = token.Value.ToLowerInvariant();
                if (spritename.Length != 4)
                {
                    parser.ReportError("Sprite name should be exactly 4 characters long (got " + spritename + ")");
                    return;
                }

                tokenizer.SkipWhitespace();

                token = TryReadSprite(parser, stream, tokenizer);
                if (token == null)
                {
                    parser.ReportError("Expected sprite frame(s)");
                    return;
                }

                string spriteframes = token.Value;

                //parser.LogWarning(string.Format("sprite {0} {1}", spritename, spriteframes));

                // duration
                int duration;
                tokenizer.SkipWhitespace();
                // this can be a function call, or a constant.
                token = tokenizer.ExpectToken(ZScriptTokenType.Identifier);
                if (token != null && token.IsValid)
                {
                    duration = -1;
                    tokenizer.SkipWhitespace();
                    token = tokenizer.ExpectToken(ZScriptTokenType.OpenParen);
                    if (token != null && token.IsValid)
                    {
                        List <ZScriptToken> tokens = parser.ParseExpression(true);
                        tokenizer.SkipWhitespace();
                        token = tokenizer.ExpectToken(ZScriptTokenType.CloseParen);
                        if (token == null || !token.IsValid)
                        {
                            parser.ReportError("Expected ), got " + ((Object)token ?? "<null>").ToString());
                            return;
                        }
                    }
                }
                else
                {
                    if (!parser.ParseInteger(out duration))
                    {
                        return;
                    }
                }

                // now, it can also contain BRIGHT, LIGHT(), OFFSET()
                string[]         allspecials = new string[] { "bright", "light", "offset", "fast", "slow", "nodelay", "canraise" };
                HashSet <string> specials    = new HashSet <string>();
                // maybe something else. I don't know.
                FrameInfo info = new FrameInfo();

                // Make the sprite name
                string realspritename = (spritename + spriteframes[0]).ToUpperInvariant();

                // Ignore some odd ZDoom things
                if (/*!realspritename.StartsWith("TNT1") && */ !realspritename.StartsWith("----") && !realspritename.Contains("#")) // [ZZ] some actors have only TNT1 state and receive a random image because of this
                {
                    info.Sprite   = realspritename;                                                                                 //mxd
                    info.Duration = duration;
                    sprites.Add(info);
                }

                while (true)
                {
                    tokenizer.SkipWhitespace();
                    cpos2 = stream.Position;
                    token = tokenizer.ExpectToken(ZScriptTokenType.Identifier, ZScriptTokenType.Semicolon, ZScriptTokenType.OpenCurly);
                    if (token == null || !token.IsValid)
                    {
                        parser.ReportError("Expected identifier, ;, or {, got " + ((Object)token ?? "<null>").ToString());
                        return;
                    }

                    // if it's opencurly, it means that everything else is an anonymous block.
                    // skip/parse that.
                    // if it's semicolon, it means end of the frame.
                    // if it's BRIGHT, LIGHT() or OFFSET(), it should be processed.
                    // if it's something else (but identifier), then it's an action function call, process it.
                    if (token.Type == ZScriptTokenType.OpenCurly)
                    {
                        stream.Position--;
                        if (!parser.SkipBlock())
                        {
                            return;
                        }
                        break; // this block is done
                    }
                    else if (token.Type == ZScriptTokenType.Semicolon)
                    {
                        break; // done
                    }
                    else // identifier
                    {
                        string special = token.Value.ToLowerInvariant();
                        if (allspecials.Contains(special))
                        {
                            if (specials.Contains(special))
                            {
                                parser.ReportError("'" + special + "' cannot be used twice");
                                return;
                            }

                            specials.Add(special);

                            if (special == "bright")
                            {
                                info.Bright = true;
                            }
                            else if (special == "light" || special == "offset")
                            {
                                tokenizer.SkipWhitespace();
                                token = tokenizer.ExpectToken(ZScriptTokenType.OpenParen);
                                if (token == null || !token.IsValid)
                                {
                                    parser.ReportError("Expected (, got " + ((Object)token ?? "<null>").ToString());
                                    return;
                                }

                                List <ZScriptToken> tokens = parser.ParseExpression(true);
                                tokenizer.SkipWhitespace();
                                token = tokenizer.ExpectToken(ZScriptTokenType.CloseParen);
                                if (token == null || !token.IsValid)
                                {
                                    parser.ReportError("Expected ), got " + ((Object)token ?? "<null>").ToString());
                                    return;
                                }

                                // parse the light expression.
                                if (special == "light")
                                {
                                    if (tokens.Count != 1 || (tokens[0].Type != ZScriptTokenType.String && tokens[0].Type != ZScriptTokenType.Identifier))
                                    {
                                        parser.ReportError("Light() special takes one string argument");
                                        return;
                                    }

                                    info.LightName = tokens[0].Value;
                                }
                            }
                        }
                        else
                        {
                            //
                            stream.Position = cpos2;
                            string actionfunction = parser.ParseDottedIdentifier();
                            //parser.LogWarning("actionfunction = " + actionfunction);
                            if (actionfunction == null)
                            {
                                return;
                            }
                            //
                            tokenizer.SkipWhitespace();
                            token = tokenizer.ExpectToken(ZScriptTokenType.OpenParen);
                            if (token != null && token.IsValid)
                            {
                                List <ZScriptToken> tokens = parser.ParseExpression(true);
                                tokenizer.SkipWhitespace();
                                token = tokenizer.ExpectToken(ZScriptTokenType.CloseParen);
                                if (token == null || !token.IsValid)
                                {
                                    parser.ReportError("Expected ), got " + ((Object)token ?? "<null>").ToString());
                                    return;
                                }

                                // possibly do something with the arguments? not now though.
                            }

                            // expect semicolon and break.
                            tokenizer.SkipWhitespace();
                            token = tokenizer.ExpectToken(ZScriptTokenType.Semicolon);
                            if (token == null || !token.IsValid)
                            {
                                parser.ReportError("Expected ;, got " + ((Object)token ?? "<null>").ToString());
                                return;
                            }

                            break;
                        } // if not special
                    }     // if identifier
                }         // frame parsing loop (inner)
            }             // state parsing loop (outer)

            TrimLeft();
        }
        private bool ParseDefaultBlock()
        {
            tokenizer.SkipWhitespace();
            ZScriptToken token = tokenizer.ExpectToken(ZScriptTokenType.OpenCurly);

            if (token == null || !token.IsValid)
            {
                parser.ReportError("Expected {, got " + ((Object)token ?? "<null>").ToString());
                return(false);
            }

            ZScriptTokenType[] whitespacetypes = new ZScriptTokenType[] { ZScriptTokenType.Newline, ZScriptTokenType.Whitespace, ZScriptTokenType.BlockComment, ZScriptTokenType.LineComment };

            // todo parse defaults block
            while (true)
            {
                long cpos = stream.Position;
                token = tokenizer.ExpectToken(ZScriptTokenType.Whitespace, ZScriptTokenType.BlockComment, ZScriptTokenType.Newline, ZScriptTokenType.LineComment, ZScriptTokenType.OpAdd, ZScriptTokenType.OpSubtract, ZScriptTokenType.Identifier, ZScriptTokenType.CloseCurly, ZScriptTokenType.Semicolon);
                if (token == null || !token.IsValid)
                {
                    parser.ReportError("Expected comment, flag, property, or }, got " + ((Object)token ?? "<null>").ToString());
                    return(false);
                }

                //if (ClassName == "Enforcer")
                //    parser.LogWarning(token.ToString());

                if (token.Type == ZScriptTokenType.CloseCurly)
                {
                    break;
                }

                switch (token.Type)
                {
                case ZScriptTokenType.Whitespace:
                case ZScriptTokenType.BlockComment:
                case ZScriptTokenType.Newline:
                    break;

                case ZScriptTokenType.LineComment:
                    ParseGZDBComment(props, token.Value);
                    break;

                // flag definition (+/-)
                case ZScriptTokenType.OpAdd:
                case ZScriptTokenType.OpSubtract:
                {
                    bool   flagset  = (token.Type == ZScriptTokenType.OpAdd);
                    string flagname = parser.ParseDottedIdentifier();
                    if (flagname == null)
                    {
                        return(false);
                    }

                    //parser.LogWarning(string.Format("{0}{1}", (flagset ? '+' : '-'), flagname));
                    // set flag
                    flags[flagname] = flagset;
                    break;
                }

                // property or combo definition
                case ZScriptTokenType.Identifier:
                {
                    stream.Position = cpos;
                    string propertyname = parser.ParseDottedIdentifier();
                    if (propertyname == null)
                    {
                        return(false);
                    }
                    List <string> propertyvalues = new List <string>();

                    // read in property values, until semicolon reached
                    while (true)
                    {
                        tokenizer.SkipWhitespace();
                        List <ZScriptToken> expr = parser.ParseExpression();
                        string exprstring        = ZScriptTokenizer.TokensToString(expr);

                        token = tokenizer.ExpectToken(ZScriptTokenType.Comma, ZScriptTokenType.Semicolon);
                        if (token == null || !token.IsValid)
                        {
                            parser.ReportError("Expected comma or ;, got " + ((Object)token ?? "<null>").ToString());
                            return(false);
                        }

                        propertyvalues.Add(exprstring);
                        if (token.Type == ZScriptTokenType.Semicolon)
                        {
                            break;
                        }
                    }

                    //parser.LogWarning(string.Format("{0} = [{1}]", propertyname, string.Join(", ", propertyvalues.ToArray())));
                    // set property
                    // translate "scale" to x and y scale
                    if (propertyname == "scale")
                    {
                        props["xscale"] = props["yscale"] = propertyvalues;
                    }
                    else
                    {
                        props[propertyname] = propertyvalues;
                    }
                    break;
                }
                }
            }

            return(true);
        }
Exemple #3
0
        internal ZScriptStateGoto(ActorStructure actor, ZDTextParser zdparser)
        {
            // goto syntax that is accepted by GZDB is [classname::]statename[+offset]

            ZScriptParser    parser    = (ZScriptParser)zdparser;
            Stream           stream    = parser.DataStream;
            ZScriptTokenizer tokenizer = new ZScriptTokenizer(parser.DataReader);

            parser.tokenizer = tokenizer;

            tokenizer.SkipWhitespace();
            string firsttarget = parser.ParseDottedIdentifier();

            if (firsttarget == null)
            {
                return;
            }

            ZScriptToken token;

            string secondtarget = null;
            int    offset       = 0;

            tokenizer.SkipWhitespace();
            token = tokenizer.ExpectToken(ZScriptTokenType.DoubleColon);
            if (token != null && token.IsValid)
            {
                secondtarget = parser.ParseDottedIdentifier();
                if (secondtarget == null)
                {
                    return;
                }
            }

            tokenizer.SkipWhitespace();
            token = tokenizer.ExpectToken(ZScriptTokenType.OpAdd);
            if (token != null && token.IsValid)
            {
                tokenizer.SkipWhitespace();
                token = tokenizer.ExpectToken(ZScriptTokenType.Integer);
                if (token == null || !token.IsValid)
                {
                    parser.ReportError("Expected state offset, got " + ((Object)token ?? "<null>").ToString());
                    return;
                }

                offset = token.ValueInt;
            }

            // Check if we don't have the class specified
            if (string.IsNullOrEmpty(secondtarget))
            {
                // First target is the state to go to
                classname = actor.ClassName;
                statename = firsttarget.ToLowerInvariant().Trim();
            }
            else
            {
                // First target is the base class to use
                // Second target is the state to go to
                classname = firsttarget.ToLowerInvariant().Trim();
                statename = secondtarget.ToLowerInvariant().Trim();
            }

            spriteoffset = offset;

            if ((classname == "super") && (actor.BaseClass != null))
            {
                classname = actor.BaseClass.ClassName;
            }
        }