Exemplo n.º 1
0
        public ObjectAnimationFrame(ObjectAnimation anim, Data animData)
        {
            _animation = anim;
            _animData  = animData;

            Color[][] palettes = anim.GetPalettes();

            try {
                // Note: this "index" is more like index*2, since it's added directly to the offset
                // without being multiplied first
                int oamIndex = (byte)_animData.NextData.GetIntValue(0);

                // Get entry in oam table for this object
                Data oamPtr = Project.GetData(_animation.OamTableName, oamIndex);
                _oamData = Project.GetData(oamPtr.GetValue(0));

                // Load sprite images
                int  _numSprites = _oamData.GetIntValue(0);
                Data data        = _oamData.NextData;

                for (int i = 0; i < _numSprites; i++)
                {
                    int y = (sbyte)data.GetIntValue(0) - 16;
                    data = data.NextData;
                    int x = (sbyte)data.GetIntValue(0) - 8;
                    data = data.NextData;
                    int tileIndex = data.GetIntValue(0) + _animation.TileIndexBase;
                    data = data.NextData;
                    byte flags = (byte)(data.GetIntValue(0) | _animation.OamFlagsBase);
                    data = data.NextData;

                    ObjectGfxHeaderData gfxHeader = _animation.ObjectGfxHeaderData;
                    int origTileIndex             = tileIndex;

                    while (tileIndex >= 0x20)
                    {
                        if (gfxHeader.ShouldHaveNext)
                        {
                            gfxHeader  = gfxHeader.NextGfxHeader;
                            tileIndex -= 0x20;
                        }
                        else
                        {
                            throw new InvalidAnimationException("Tileindex out of range (" + tileIndex + ")");
                        }
                    }

                    int    tileOffset = (tileIndex & 0xfe) * 16;
                    Stream gfxStream  = gfxHeader.GfxStream;

                    if (gfxStream.Length - tileOffset < 0x20)
                    {
                        throw new InvalidAnimationException("Sprite not defined in gfx data");
                    }

                    gfxStream.Seek(tileOffset, SeekOrigin.Begin);
                    byte[] gfxData = new byte[0x20];
                    gfxStream.Read(gfxData, 0, 0x20);

                    Bitmap bitmap = GbGraphics.TileToBitmap(gfxData, palettes[flags & 7], flags);
                    bitmaps.Add(new Tuple <Bitmap, int, int>(bitmap, x, y));
                }
            }
            catch (InvalidLookupException e) {
                bitmaps = null;
                throw new InvalidAnimationException(e);
            }
            catch (FormatException e) {
                bitmaps = null;
                throw new InvalidAnimationException(e);
            }
        }
Exemplo n.º 2
0
        void ParseLine(string pureLine, List <FileComponent> fileStructure)
        {
            string warningString = WarningString;

            // Helper functions

            Action <FileComponent> AddComponent = (component) => {
                fileStructure.Add(component);
                if (component is Label)
                {
                    AddLabelToDictionaries(component as Label);
                }
            };
            Action <FileComponent> AddDataAndPopFileStructure = (data) => {
                fileStructure.RemoveAt(fileStructure.Count - 1);
                AddComponent(data);
            };
            Action PopFileStructure = () => {
                fileStructure.RemoveAt(fileStructure.Count - 1);
            };

            // Sub-function: returns true if a meaning for the token was found.
            Func <IList <string>, IList <string>, bool> ParseData = (fTokens, fSpacing) =>
            {
                List <string> standardValues = new List <string>();

                // Variables used for some of the goto's
                int size = -1;

                for (int j = 1; j < fTokens.Count; j++)
                {
                    standardValues.Add(fTokens[j]);
                }

                switch (fTokens[0].ToLower())
                {
                case ".incbin": {
                    Data d = new Data(Project, fTokens[0], standardValues, -1,
                                      this, fSpacing);
                    AddDataAndPopFileStructure(d);
                    break;
                }

                case ".dw":
                    if (context == "RAMSECTION" || context == "ENUM")
                    {
                        break;
                    }
                    if (fTokens.Count < 2)
                    {
                        log.Warn(warningString + "Expected .DW to have a value.");
                        break;
                    }
                    size = 2;
                    goto arbitraryLengthData;

                case ".db":
                    if (context == "RAMSECTION" || context == "ENUM")
                    {
                        break;
                    }
                    if (fTokens.Count < 2)
                    {
                        log.Warn(warningString + "Expected .DB to have a value.");
                        break;
                    }
                    size = 1;
                    goto arbitraryLengthData;

                case "dwbe":
                    if (fTokens.Count < 2)
                    {
                        log.Warn(warningString + "Expected dwbe to have a value.");
                        break;
                    }
                    size = 2;
                    goto arbitraryLengthData;

                case "dbrev":
                    if (fTokens.Count < 2)
                    {
                        log.Warn(warningString + "Expected dbrev to have a value.");
                        break;
                    }
                    size = 1;
                    goto arbitraryLengthData;
arbitraryLengthData:
                    PopFileStructure();
                    for (int j = 1; j < fTokens.Count; j++) // Each value is added as individual data
                    {
                        string[]      values      = { fTokens[j] };
                        List <string> newfSpacing = new List <string> {
                            fSpacing[0], fSpacing[j], ""
                        };
                        if (j == fTokens.Count - 1)
                        {
                            newfSpacing[2] = fSpacing[j + 1];
                        }

                        Data d = new Data(Project, fTokens[0], values, size,
                                          this, newfSpacing);
                        if (j != fTokens.Count - 1)
                        {
                            d.EndsLine = false;
                        }
                        if (j != 1)
                        {
                            d.PrintCommand = false;
                        }
                        AddComponent(d);
                    }
                    break;

                case "db":
                    if (context != "RAMSECTION" && context != "ENUM")
                    {
                        goto default;
                    }
                    address++;
                    break;

                case "dw":
                    if (context != "RAMSECTION" && context != "ENUM")
                    {
                        goto default;
                    }
                    address += 2;
                    break;

                case "dsb":
                    if (context != "RAMSECTION" && context != "ENUM")
                    {
                        goto default;
                    }
                    address += Project.EvalToInt(fTokens[1]);
                    break;

                case "dsw":
                    if (context != "RAMSECTION" && context != "ENUM")
                    {
                        goto default;
                    }
                    address += Project.EvalToInt(fTokens[1]) * 2;
                    break;

                case "m_animationloop":
                {
                    Data d = new Data(Project, fTokens[0], standardValues, 2,
                                      this, fSpacing);
                    AddDataAndPopFileStructure(d);
                    break;
                }

                case "m_rgb16":
                    if (fTokens.Count != 4)
                    {
                        log.Warn(warningString + "Expected " + fTokens[0] + " to take 3 parameters");
                        break;
                    }
                    {
                        Data d = new RgbData(Project, fTokens[0], standardValues,
                                             this, fSpacing);
                        AddDataAndPopFileStructure(d);
                        break;
                    }

                case "m_gfxheader":
                case "m_gfxheaderforcemode":
                    if (fTokens.Count < 4 || fTokens.Count > 5)
                    {
                        log.Warn(warningString + "Expected " + fTokens[0] + " to take 3-4 parameters");
                        break;
                    }
                    {
                        Data d = new GfxHeaderData(Project, fTokens[0], standardValues,
                                                   this, fSpacing);
                        AddDataAndPopFileStructure(d);
                        break;
                    }

                case "m_objectgfxheader": {
                    if (!(fTokens.Count >= 3 && fTokens.Count <= 4))
                    {
                        log.Warn(warningString + "Expected " + fTokens[0] + " to take 2-3 parameters");
                        break;
                    }
                    Data d = new ObjectGfxHeaderData(Project, fTokens[0], standardValues, this, fSpacing);
                    AddDataAndPopFileStructure(d);
                    break;
                }

                case "m_paletteheaderbg":
                case "m_paletteheaderspr":
                    if (fTokens.Count != 5)
                    {
                        log.Warn(warningString + "Expected " + fTokens[0] + " to take 4 parameters");
                        break;
                    }
                    {
                        Data d = new PaletteHeaderData(Project, fTokens[0], standardValues,
                                                       this, fSpacing);
                        AddDataAndPopFileStructure(d);
                        break;
                    }

                case "m_tilesetheader":
                    if (fTokens.Count != 6)
                    {
                        log.Warn(warningString + "Expected " + fTokens[0] + " to take 5 parameters");
                        break;
                    }
                    {
                        Data d = new TilesetHeaderData(Project, fTokens[0], standardValues,
                                                       this, fSpacing);
                        AddDataAndPopFileStructure(d);
                        break;
                    }

                case "m_tilesetdata":
                    if (fTokens.Count != 2)
                    {
                        log.Warn(warningString + "Expected " + fTokens[0] + " to take 1 parameter");
                        break;
                    }
                    {
                        Stream file = Project.GetBinaryFile("tilesets/" + Project.GameString + "/" + fTokens[1] + ".bin");
                        Data   d    = new Data(Project, fTokens[0], standardValues,
                                               (Int32)file.Length, this, fSpacing);
                        AddDataAndPopFileStructure(d);
                        break;
                    }

                case "m_roomlayoutdata":
                    if (fTokens.Count != 2)
                    {
                        log.Warn(warningString + "Expected " + fTokens[0] + " to take 1 parameter");
                        break;
                    }
                    {
                        Label l = new Label(this, fTokens[1]);
                        l.Fake = true;
                        AddDataAndPopFileStructure(l);
                        Data d = new Data(Project, fTokens[0], standardValues, -1,
                                          this, fSpacing);
                        AddComponent(d);
                        break;
                    }

                case "m_seasonalarea": {
                    // In season's "areas.s", the m_SeasonalArea macro points to a label which
                    // contains 4 area definitions (one for each season).
                    if (fTokens.Count != 2)
                    {
                        log.Warn(warningString + "Expected " + fTokens[0] + " to take 1 parameter");
                        break;
                    }
                    // Create a data object considered to have a size of 8 bytes
                    Data d = new Data(Project, fTokens[0], standardValues, 8, this, fSpacing);
                    AddDataAndPopFileStructure(d);
                    break;
                }

                case "m_interactiondata": {
                    if (!(fTokens.Count == 2 || fTokens.Count == 4))
                    {
                        log.Warn(warningString + "Expected " + fTokens[0] + " to take 1 or 3 parameters");
                        break;
                    }
                    Data d = new Data(Project, fTokens[0], standardValues, 3, this, fSpacing);
                    AddDataAndPopFileStructure(d);
                    break;
                }

                case "m_enemydata": {
                    if (!(fTokens.Count == 4 || fTokens.Count == 5))
                    {
                        log.Warn(warningString + "Expected " + fTokens[0] + " to take 3-4 parameters");
                        break;
                    }
                    Data d = new Data(Project, fTokens[0], standardValues, 4, this, fSpacing);
                    AddDataAndPopFileStructure(d);
                    break;
                }

                default:
                {
                    Data d = null;
                    // Try object commands
                    for (int j = 0; j < ObjectGroup.ObjectCommands.Length; j++)
                    {
                        string s = ObjectGroup.ObjectCommands[j];

                        if (s.ToLower() == fTokens[0].ToLower())
                        {
                            int minParams = ObjectGroup.ObjectCommandMinParams[j];
                            int maxParams = ObjectGroup.ObjectCommandMaxParams[j];

                            if (minParams == -1)
                            {
                                minParams = maxParams;
                            }
                            if (maxParams == -1)
                            {
                                maxParams = minParams;
                            }
                            if (fTokens.Count - 1 < minParams || fTokens.Count - 1 > maxParams)
                            {
                                log.Warn(warningString + "Expected " + fTokens[0] + " to take " +
                                         minParams + "-" + maxParams + "parameter(s)");
                                break;
                            }

                            var objectType = (ObjectType)j;

                            d = new ObjectData(Project, fTokens[0], standardValues,
                                               this, fSpacing, objectType);
                            break;
                        }
                    }
                    // Try warp sources
                    foreach (string s in WarpSourceData.WarpCommands)
                    {
                        if (s.ToLower() == fTokens[0].ToLower())
                        {
                            d = new WarpSourceData(Project, fTokens[0], standardValues,
                                                   this, fSpacing);
                        }
                    }
                    // Try warp dest
                    if (WarpDestData.WarpCommand.ToLower() == fTokens[0].ToLower())
                    {
                        d = new WarpDestData(Project, fTokens[0], standardValues,
                                             this, fSpacing);
                    }

                    if (d != null)
                    {
                        AddDataAndPopFileStructure(d);
                        break;
                    }
                    return(false);
                }
                }
                return(true);
            };

            string pureTrimmedLine = pureLine.Trim();

            // If we're in a documentation block, add any comments to the documentation
            if (context == "DOCUMENTATION")
            {
                if (pureTrimmedLine.Length > 0 && pureTrimmedLine[0] == ';')
                {
                    documentationString += pureLine + '\n';
                    return;
                }
                else
                {
                    context = "";
                    AddComponent(new DocumentationFileComponent(this, documentationString));
                    context = "";
                }
            }

            // Check if we're starting a documentation block
            if (pureTrimmedLine.Length >= 2 && pureTrimmedLine.Substring(0, 2) == ";;")  // Begin documentation block
            {
                if (context == "DOCUMENTATION")
                {
                    log.Warn(warningString + "Documentation block already open.");
                }
                else
                {
                    context             = "DOCUMENTATION";
                    documentationString = pureLine + '\n';
                }
                return;
            }

            string line = pureLine;

            // Add raw string to file structure, it'll be removed if
            // a better representation is found
            fileStructure.Add(new StringFileComponent(this, line, null));

            if (line.Trim().Length == 0)
            {
                return;
            }

            // TODO: split tokens more intelligently, ie: recognize this as one token: $8000 | $03
            //string[] tokens = line.Split(new char[] { ' ', '\t'} );
            var            tup     = Tokenize(line);
            IList <string> tokens  = tup.Item1;
            IList <string> spacing = tup.Item2;


            if (tokens.Count > 0)
            {
                // Check if we're currently skipping over stuff because of .ifdefs
                if (ifdefCondition == false)
                {
                    if (tokens[0].ToLower() == ".ifdef")
                    {
                        ifdefDepth++;
                    }
                    else if (tokens[0].ToLower() == ".else" && failedIfdefDepth == ifdefDepth - 1)
                    {
                        ifdefCondition = true;
                    }
                    else if (tokens[0].ToLower() == ".endif")
                    {
                        ifdefDepth--;
                        if (ifdefDepth == failedIfdefDepth)
                        {
                            ifdefCondition = true;
                        }
                    }

                    return;
                }

                switch (tokens[0].ToLower())
                {
                // Built-in directives
                case ".ramsection": {
                    context = "RAMSECTION";
                    // Find the last token which specifies the name
                    int tokenIndex = 1;
                    while (tokens[tokenIndex][tokens[tokenIndex].Length - 1] != '"')
                    {
                        tokenIndex++;
                    }
                    tokenIndex++;

                    while (tokenIndex < tokens.Count)
                    {
                        if (tokens[tokenIndex] == "BANK")
                        {
                            tokenIndex++;
                            bank = Project.EvalToInt(tokens[tokenIndex++]);
                        }
                        else if (tokens[tokenIndex] == "SLOT")
                        {
                            tokenIndex++;
                            string slotString = tokens[tokenIndex++];
                            int    slot       = Project.EvalToInt(slotString);
                            if (slot == 2)
                            {
                                address = 0xc000;
                            }
                            else       // Assuming slot >= 3
                            {
                                address = 0xd000;
                            }
                        }
                    }
                    break;
                }

                case ".ends":
                    if (context == "RAMSECTION")
                    {
                        context = "";
                    }
                    break;

                case ".enum":
                    context = "ENUM";
                    address = Project.EvalToInt(tokens[1]);
                    break;
                // Not supported: "DESC" (descreasing order)

                case ".ende":
                    if (context == "ENUM")
                    {
                        context = "";
                    }
                    break;

                case ".define":
                {
                    if (tokens.Count < 3)
                    {
                        log.Debug(warningString + "Expected .DEFINE to have a string and a value.");
                        break;
                    }
                    string value = "";
                    for (int j = 2; j < tokens.Count; j++)
                    {
                        value += tokens[j];
                        value += " ";
                    }
                    value = value.Trim();
                    AddDefinition(tokens[1], value);
                    break;
                }

                case ".ifdef":
                    if (tokens.Count < 2)
                    {
                        log.Warn(warningString + "Expected .IFDEF to have a value.");
                        break;
                    }
                    ifdefDepth++;
                    if (Project.GetDefinition(tokens[1]) != null)
                    {
                        ifdefCondition = true;
                    }
                    else
                    {
                        ifdefCondition   = false;
                        failedIfdefDepth = ifdefDepth - 1;
                    }
                    break;

                case ".else":
                    if (ifdefDepth == 0)
                    {
                        log.Warn(warningString + "Expected .IFDEF before .ENDIF.");
                        break;
                    }
                    ifdefCondition = false;
                    break;

                case ".endif":
                    if (ifdefDepth == 0)
                    {
                        log.Warn(warningString + "Expected .IFDEF before .ENDIF.");
                        break;
                    }
                    ifdefDepth--;
                    break;

                default:
                {
                    bool isData = ParseData(tokens, spacing);

                    // In ramsections or enums, assume any unidentifiable data is a label.
                    // Technically this should be the case in any context, but it's more
                    // useful for the parser to tell me what it doesn't understand.
                    if (!isData && (tokens[0][tokens[0].Length - 1] == ':' || context == "RAMSECTION" || context == "ENUM"))
                    {
                        // Label
                        string s = tokens[0];
                        if (tokens[0][tokens[0].Length - 1] == ':')
                        {
                            s = tokens[0].Substring(0, tokens[0].Length - 1);
                        }

                        FileComponent addedComponent;
                        if (context == "RAMSECTION" || context == "ENUM")
                        {
                            AddDefinition(s, address.ToString());
                            if (context == "RAMSECTION")
                            {
                                AddDefinition(":" + s, bank.ToString());
                            }
                            PopFileStructure();
                            StringFileComponent sc = new StringFileComponent(this, tokens[0], spacing);
                            fileStructure.Add(sc);
                            addedComponent = sc;
                        }
                        else
                        {
                            Label label = new Label(this, s, spacing);
                            AddDataAndPopFileStructure(label);
                            addedComponent = label;
                        }
                        if (tokens.Count > 1)           // There may be data directly after the label
                        {
                            string[]      tokens2  = new string[tokens.Count - 1];
                            List <string> spacing2 = new List <string>();

                            addedComponent.EndsLine = false;

                            // Add raw string to file structure, it'll be removed if a better
                            // representation is found
                            fileStructure.Add(new StringFileComponent(
                                                  this, line.Substring(spacing[0].Length + tokens[0].Length), spacing2));

                            for (int j = 1; j < tokens.Count; j++)
                            {
                                tokens2[j - 1] = tokens[j];
                            }
                            for (int j = 1; j < spacing.Count; j++)
                            {
                                spacing2.Add(spacing[j]);
                            }
                            if (!ParseData(tokens2, spacing2))
                            {
                                log.Debug(warningString + "Error parsing line.");
                            }
                        }
                    }
                    else
                    {
                        // Unknown data
                        log.Debug(warningString + "Did not understand \"" + tokens[0] + "\".");
                    }
                }
                break;
                }
            }
        }