Esempio n. 1
0
        public static int GetWarpsCountInArea(LevelArea cArea)
        {
            int count = 0;

            count += cArea.Warps.Where(n => new[] { LevelscriptCommandTypes.PaintingWarp, LevelscriptCommandTypes.ConnectedWarp }.Contains(n.CommandType)).Count();
            count += cArea.WarpsForGame.Concat(cArea.Warps).Count();
            return(count);
        }
Esempio n. 2
0
        public static byte GetNextUnusedWarpID(LevelArea cArea)
        {
            var forbitten = new List <byte>();

            foreach (LevelscriptCommand cmd in cArea.WarpsForGame.Concat(cArea.Warps))
            {
                forbitten.Add(clWarp.GetWarpID(cmd));
            }
            for (int i = byte.MinValue; i <= byte.MaxValue; i++)
            {
                if (!forbitten.Contains(Conversions.ToByte(i)))
                {
                    return(Conversions.ToByte(i));
                }
            }

            return(byte.MaxValue);
        }
Esempio n. 3
0
        /// <summary>
        /// Saves a ROM Manager Level to ROM.
        /// </summary>
        /// <param name="lvl"></param>
        /// <param name="rommgr"></param>
        /// <param name="output"></param>
        /// <param name="curOff"></param>
        /// <returns></returns>
        public virtual LevelSaveResult SaveLevel(Level lvl, RomManager rommgr, BinaryData output, ref uint curOff)
        {
            var        saveres = new LevelSaveResult();
            BinaryData data0x19;
            var        lid = rommgr.LevelInfoData.GetByLevelID(lvl.LevelID);

            // Write Area Model & Update Scrolling Texture Vertex Pointers & Write Custom Object Bank
            var CollisionBoxTableIndex = new[] { 0, 0x32, 0x33 };

            foreach (LevelArea a in lvl.Areas)
            {
                a.SpecialBoxes.SortByHeight();
                a.Bank0x0EOffset = curOff;

                int oldModelStart = a.AreaModel.Fast3DBuffer.Fast3DBankStart;
                int newModelStart;
                int modelOffset;

                // Add the new water boxes
                a.AreaModel.Collision.SpecialBoxes.Clear();
                foreach (SpecialBox sp in a.SpecialBoxes)
                {
                    var boxdata = new Model.Collision.BoxData
                    {
                        X1    = sp.X1,
                        X2    = sp.X2,
                        Z1    = sp.Z1,
                        Z2    = sp.Z2,
                        Y     = sp.Y,
                        Index = (short)CollisionBoxTableIndex[(int)sp.Type]
                    };

                    switch (sp.Type)
                    {
                    case SpecialBoxType.Water:
                        boxdata.Type = Model.Collision.BoxDataType.Water;
                        break;

                    case SpecialBoxType.Mist:
                        boxdata.Type = Model.Collision.BoxDataType.Mist;
                        break;

                    case SpecialBoxType.ToxicHaze:
                        boxdata.Type = Model.Collision.BoxDataType.ToxicHaze;
                        break;
                    }

                    a.AreaModel.Collision.SpecialBoxes.Add(boxdata);
                    CollisionBoxTableIndex[(int)sp.Type] += 1;
                }

                // Write Area Model
                ObjectModel.SaveResult res;
                res = a.AreaModel.ToBinaryData(output, (int)curOff, (int)curOff, 0xE000000);

                // Calculate Model Offset & Update Scrolling Texture Vertex Pointers
                newModelStart = a.AreaModel.Fast3DBuffer.Fast3DBankStart;
                modelOffset   = newModelStart - oldModelStart;
                if (modelOffset != 0)
                {
                    a.UpdateScrollingTextureVertexPointer(modelOffset);
                }

                a.CollisionPointer = res.CollisionPointer;
                a.Geolayout.Geopointers.Clear();
                a.Geolayout.Geopointers.AddRange(res.GeoPointers.ToArray());
                curOff += (uint)(res.Length + 0x20);
                General.HexRoundUp2(ref curOff);

                a.Bank0xELength = (int)(curOff - a.Bank0x0EOffset);
            }

            // Write Background Image
            output.RoundUpPosition();
            int customBGStart = Conversions.ToInteger(curOff);
            int customBGEnd   = 0;

            if (lvl.Background.IsCustom) // .ID = Geolayout.BackgroundIDs.Custom Then
            {
                // Write Custom Background
                lvl.Background.WriteImage(output.BaseStream, customBGStart);

                // Write Pointer Table
                var bgPtrTable = LevelBG.GetBackgroundPointerTable();
                output.Write(bgPtrTable, 0, bgPtrTable.Length);
                customBGEnd = customBGStart + lvl.Background.ImageLength + bgPtrTable.Length;
                curOff     += (uint)lvl.Background.ImageLength + (uint)bgPtrTable.Length;
                General.HexRoundUp2(ref curOff);
            }

            // Generate & Write Local Object Bank
            uint localObjectBankRomStart = 0;
            uint localObjectBankRomEnd   = 0;
            bool writeLocalObjectBank    = lvl.LocalObjectBank.Models.Count > 0 && lvl.EnableLocalObjectBank;

            if (writeLocalObjectBank)
            {
                localObjectBankRomStart = curOff;
                curOff += (uint)lvl.LocalObjectBank.WriteToSeg(output, (int)curOff, 0x9);
                localObjectBankRomEnd = curOff;
                ((RMLevel)lvl).Config.LocalObjectBank = lvl.LocalObjectBank.Config;
                lvl.LocalObjectBank.WriteCollisionPointers(output);
            }
            ((RMLevel)lvl).Config.EnableLocalObjectBank = writeLocalObjectBank;

            // Get Bank 0x19
            if (lvl.Bank0x19 is null)
            {
                lvl.Bank0x19        = rommgr.SetSegBank(0x19, Conversions.ToInteger(curOff), (int)RomManagerSettings.DefaultLevelscriptSize);
                lvl.Bank0x19.Data   = new MemoryStream();
                lvl.Bank0x19.Length = (int)RomManagerSettings.DefaultLevelscriptSize;
            }
            else
            {
                var oldData = lvl.Bank0x19.Data;
                lvl.Bank0x19      = rommgr.SetSegBank(0x19, Conversions.ToInteger(curOff), (int)(curOff + lvl.Bank0x19.Length));
                lvl.Bank0x19.Data = oldData;
            }

            data0x19         = new BinaryStreamData(lvl.Bank0x19.Data);
            saveres.Bank0x19 = lvl.Bank0x19;
            curOff          += (uint)lvl.Bank0x19.Data.Length;
            General.HexRoundUp2(ref curOff);

            // Update Geolayouts
            foreach (LevelArea a in lvl.Areas)
            {
                // Update Backcolor Command
                var cmd = a.Geolayout.Geolayoutscript.GetFirst(GeolayoutCommandTypes.Background);
                if (a.Background.Type == AreaBGs.Levelbackground && lvl.Background.Enabled)
                {
                    cgBackground.SetBackgroundPointer(cmd, unchecked ((int)0x802763D4));
                    cgBackground.SetBackgroundID(cmd, (short)lvl.Background.ID);
                }
                else
                {
                    cgBackground.SetBackgroundPointer(cmd, 0);
                    cgBackground.SetRgbaColor(cmd, a.Background.Color);
                }
            }

            // Write Geolayouts
            int geoOffset = 0x5F00;

            foreach (LevelArea a in lvl.Areas)
            {
                geoOffset        -= General.HexRoundUp1(a.Geolayout.Length) + 0x50;
                a.GeolayoutOffset = (uint)(lvl.Bank0x19.BankAddress + geoOffset);
                a.Geolayout.Write(lvl.Bank0x19.Data, geoOffset);
                a.Geolayout.NewGeoOffset = lvl.Bank0x19.RomStart + geoOffset;
            }

            // Füge Show-Dialog-Command & 2D-Camera-Object ein
            foreach (LevelArea a in lvl.Areas)
            {
                // Show-Dialog-Command
                if (a.ShowMessage.Enabled)
                {
                    var cmdShowMsg = new LevelscriptCommand($"30 04 00 {a.ShowMessage.DialogID.ToString("X2")}");
                    int indexOf1E  = a.Levelscript.IndexOfFirst(LevelscriptCommandTypes.EndOfArea);
                    a.Levelscript.Insert(indexOf1E, cmdShowMsg);
                }

                // 2D-Camera-Object
                var cmds2d = new List <LevelscriptCommand>();
                foreach (LevelscriptCommand obj in a.Objects)
                {
                    if (obj.CommandType == LevelscriptCommandTypes.Normal3DObject)
                    {
                        if (clNormal3DObject.GetSegBehaviorAddr(obj) == (long)0x130053C4) // Behav-ID: '0x130053C4
                        {
                            cmds2d.Add(obj);
                        }
                    }
                }

                if (a.Enable2DCamera)
                {
                    if (cmds2d.Count == 0)
                    {
                        var cmd = new LevelscriptCommand("24 18 1F 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 13 00 53 C4");
                        a.Objects.Add(cmd);
                    }
                }
                else if (cmds2d.Count > 0)
                {
                    foreach (LevelscriptCommand cmd in cmds2d)
                    {
                        a.Objects.Remove(cmd);
                    }
                }
            }

            Levelscript             lvlScript0E          = null;
            Dictionary <byte, uint> areaobjwarpoffsetdic = null;
            SegmentedBank           firstBank0xE         = null;
            uint curFirstBank0xEOffset = 0;

            // Add Objects and Warps to new Levelscript
            lvlScript0E          = new Levelscript();
            firstBank0xE         = rommgr.SetSegBank(0xE, Conversions.ToInteger(curOff), 0);
            areaobjwarpoffsetdic = new Dictionary <byte, uint>();
            foreach (LevelArea a in lvl.Areas)
            {
                areaobjwarpoffsetdic.Add(a.AreaID, (uint)(firstBank0xE.BankAddress + curFirstBank0xEOffset));
                foreach (LevelscriptCommand c in a.Objects)
                {
                    lvlScript0E.Add(c);
                    curFirstBank0xEOffset += (uint)c.Length;
                }

                foreach (ManagedScrollingTexture c in a.ScrollingTextures)
                {
                    c.SaveProperties(rommgr.RomConfig.ScrollTexConfig);
                    lvlScript0E.Add(c.Command);
                    curFirstBank0xEOffset += (uint)c.Command.Length;
                }

                foreach (LevelscriptCommand c in a.Warps)
                {
                    lvlScript0E.Add(c);
                    curFirstBank0xEOffset += (uint)c.Length;
                }

                foreach (LevelscriptCommand c in a.WarpsForGame)
                {
                    lvlScript0E.Add(c);
                    curFirstBank0xEOffset += (uint)c.Length;
                }

                lvlScript0E.Add(new LevelscriptCommand("07 04 00 00"));
                curFirstBank0xEOffset += 4;
            }

            firstBank0xE.Length = (int)General.HexRoundUp1(curFirstBank0xEOffset);
            lvlScript0E.Write(output, firstBank0xE.RomStart);
            curOff += (uint)firstBank0xE.Length;

            // Füge Area dem Levelscript hinzu
            int cIndex2 = lvl.Levelscript.IndexOfFirst(LevelscriptCommandTypes.x1E);

            foreach (var a in lvl.Areas)
            {
                foreach (var c in a.Levelscript)
                {
                    lvl.Levelscript.Insert(cIndex2, c);
                    cIndex2 += 1;
                }
            }

            // Übernehme Level- und Areaeinstellungen
            int                CurrentAreaIndex            = 0;
            var                areaobjwarpindextoinsertdic = new Dictionary <byte, int>();
            var                areaidindex     = new Dictionary <byte, byte>();
            LevelArea          tArea           = null;
            bool               foundCmdShowMsg = false;
            LevelscriptCommand cmdBgSegLoad    = null;
            LevelscriptCommand cmdGobSegLoad   = null;
            LevelscriptCommand cmdGobJump      = null;
            LevelscriptCommand cmdLobSegLoad   = null;
            LevelscriptCommand cmdLobJump      = null;
            var                cmdsToInsertAt  = new Dictionary <LevelscriptCommand, LevelscriptCommand>();
            var                cmdsToRemove    = new List <LevelscriptCommand>();

            foreach (var c in lvl.Levelscript)
            {
                var switchExpr1 = c.CommandType;
                switch (switchExpr1)
                {
                case LevelscriptCommandTypes.StartArea:
                {
                    tArea = lvl.Areas[CurrentAreaIndex];
                    byte areaid = tArea.AreaID;
                    areaidindex.Add(areaid, Conversions.ToByte(areaidindex.Count));
                    clStartArea.SetSegGeolayoutAddr((LevelscriptCommand)c, (uint)(lvl.Areas[CurrentAreaIndex].Geolayout.NewGeoOffset - lvl.Bank0x19.RomStart + lvl.Bank0x19.BankAddress));
                    areaobjwarpindextoinsertdic.Add(areaid, lvl.Levelscript.IndexOf(c) + 1);
                    break;
                }

                case LevelscriptCommandTypes.EndOfArea:
                {
                    if (!foundCmdShowMsg && tArea.ShowMessage.Enabled)
                    {
                        var cmdShowMsg = new LevelscriptCommand($"30 04 00 {tArea.ShowMessage.DialogID.ToString("X2")}");
                        cmdsToInsertAt.Add((LevelscriptCommand)c, cmdShowMsg);
                    }

                    foundCmdShowMsg   = false;
                    CurrentAreaIndex += 1;
                    tArea             = null;
                    break;
                }

                case LevelscriptCommandTypes.AreaMusic:
                {
                    clAreaMusic.SetMusicID((LevelscriptCommand)c, lvl.Areas[CurrentAreaIndex].BGMusic);
                    break;
                }

                case LevelscriptCommandTypes.AreaMusicSimple:
                {
                    clAreaMusicSimple.SetMusicID((LevelscriptCommand)c, lvl.Areas[CurrentAreaIndex].BGMusic);
                    break;
                }

                case LevelscriptCommandTypes.Tarrain:
                {
                    clTerrian.SetTerrainType((LevelscriptCommand)c, (byte)lvl.Areas[CurrentAreaIndex].TerrainType);
                    break;
                }

                case LevelscriptCommandTypes.LoadRomToRam:
                {
                    var switchExpr2 = clLoadRomToRam.GetSegmentedID((LevelscriptCommand)c);
                    switch (switchExpr2)
                    {
                    case 0xE:             // Bank 0xE
                        clLoadRomToRam.SetRomStart((LevelscriptCommand)c, firstBank0xE.RomStart);
                        clLoadRomToRam.SetRomEnd((LevelscriptCommand)c, firstBank0xE.RomEnd);
                        break;

                    case 0xA:
                        cmdBgSegLoad = (LevelscriptCommand)c;
                        break;

                    case 0x7:
                        if (lvl.LastGobCmdSegLoad == c)
                        {
                            cmdGobSegLoad = (LevelscriptCommand)c;
                        }
                        break;

                    case 0x9:
                        if (lvl.LastLobCmdSegLoad == c)
                        {
                            cmdLobSegLoad = (LevelscriptCommand)c;
                        }
                        break;
                    }

                    break;
                }

                case LevelscriptCommandTypes.ShowDialog:
                {
                    if ((bool)tArea?.ShowMessage.Enabled && !foundCmdShowMsg)
                    {
                        clShowDialog.SetDialogID((LevelscriptCommand)c, tArea.ShowMessage.DialogID);
                        foundCmdShowMsg = true;
                    }
                    else
                    {
                        cmdsToRemove.Add((LevelscriptCommand)c);
                    }

                    break;
                }

                case LevelscriptCommandTypes.JumpToSegAddr:
                {
                    int bankID = clJumpToSegAddr.GetSegJumpAddr((LevelscriptCommand)c) >> 24;
                    switch (bankID)
                    {
                    case 0x7:
                        cmdGobJump = (LevelscriptCommand)c;
                        break;

                    case 0x9:
                        cmdLobJump = (LevelscriptCommand)c;
                        break;
                    }
                    break;
                }
                }
            }

            // Füge Jump Commands zur ersten 0xE-Bank hinzu
            foreach (var e in areaobjwarpindextoinsertdic.OrderByDescending(n => n.Value))
            {
                uint segStartAddr = areaobjwarpoffsetdic[e.Key];
                lvl.Levelscript.Insert(e.Value, new LevelscriptCommand(new byte[] { 0x6, 8, 0, 0, Conversions.ToByte((long)(segStartAddr >> 24) & (long)0xFF), Conversions.ToByte((long)(segStartAddr >> 16) & (long)0xFF), Conversions.ToByte((long)(segStartAddr >> 8) & (long)0xFF), Conversions.ToByte((long)segStartAddr & (long)0xFF) }));
            }

            // Lösche Commands
            foreach (LevelscriptCommand cmd in cmdsToRemove)
            {
                lvl.Levelscript.Remove(cmd);
            }

            // Füge neue Commands ein
            foreach (KeyValuePair <LevelscriptCommand, LevelscriptCommand> kvp in cmdsToInsertAt)
            {
                int index = lvl.Levelscript.IndexOf(kvp.Key);
                lvl.Levelscript.Insert(index, kvp.Value);
            }

            // Füge Background-Command ein
            if (lvl.Background.Enabled)
            {
                var newbgcmd = cmdBgSegLoad ?? new LevelscriptCommand(new byte[] { 0x17, 0xC, 0, 0xA, 0, 0, 0, 0, 0, 0, 0, 0 });
                if (lvl.Background.IsCustom && lvl.Background.HasImage) // .ID = Geolayout.BackgroundIDs.Custom Then
                {
                    clLoadRomToRam.SetRomStart(newbgcmd, customBGStart);
                    clLoadRomToRam.SetRomEnd(newbgcmd, customBGEnd);
                }
                else
                {
                    clLoadRomToRam.SetRomStart(newbgcmd, (int)General.GetBackgroundAddressOfID(lvl.Background.ID, false));
                    clLoadRomToRam.SetRomEnd(newbgcmd, (int)General.GetBackgroundAddressOfID(lvl.Background.ID, true));
                }

                if (!lvl.Levelscript.Contains(newbgcmd))
                {
                    int indexoffirstx1e = lvl.Levelscript.IndexOfFirst(LevelscriptCommandTypes.x1D);
                    lvl.Levelscript.Insert(indexoffirstx1e, newbgcmd);
                }
            }
            else if (cmdBgSegLoad is object)
            {
                lvl.Levelscript.Remove(cmdBgSegLoad);
            }

            // Füge Global Object Bank Command ein
            if (lvl.EnableGlobalObjectBank)
            {
                var newgobjumpcmd = cmdGobJump ?? new LevelscriptCommand("06 08 00 00 07 00 00 00");
                var newgobcmd     = cmdGobSegLoad ?? new LevelscriptCommand("17 0C 00 07 00 00 00 00 00 00 00 00");
                clLoadRomToRam.SetRomStart(newgobcmd, rommgr.GlobalModelBank.CurSeg.RomStart);
                clLoadRomToRam.SetRomEnd(newgobcmd, rommgr.GlobalModelBank.CurSeg.RomEnd);

                if (!lvl.Levelscript.Contains(newgobcmd))
                {
                    int indexoffirstx1d = lvl.Levelscript.IndexOfFirst(LevelscriptCommandTypes.x1D);
                    lvl.Levelscript.Insert(indexoffirstx1d, newgobcmd);
                    lvl.LastGobCmdSegLoad = newgobcmd;
                }

                if (!lvl.Levelscript.Contains(newgobjumpcmd))
                {
                    int indexoffirstx1d = lvl.Levelscript.IndexOfFirst(LevelscriptCommandTypes.x1D);
                    lvl.Levelscript.Insert(indexoffirstx1d + 1, newgobjumpcmd);
                }
            }
            else
            {
                if (cmdGobJump is object)
                {
                    lvl.Levelscript.Remove(cmdGobJump);
                }

                if (cmdGobSegLoad is object)
                {
                    lvl.Levelscript.Remove(cmdGobSegLoad);
                }
            }

            // Füge Local Object Bank Command ein
            if (writeLocalObjectBank)
            {
                var newlobjumpcmd = cmdLobJump ?? new LevelscriptCommand("06 08 00 00 09 00 00 00");
                var newlobcmd     = cmdLobSegLoad ?? new LevelscriptCommand("17 0C 00 09 00 00 00 00 00 00 00 00");
                clLoadRomToRam.SetRomStart(newlobcmd, (int)localObjectBankRomStart);
                clLoadRomToRam.SetRomEnd(newlobcmd, (int)localObjectBankRomEnd);

                if (!lvl.Levelscript.Contains(newlobcmd))
                {
                    int indexoffirstx1d = lvl.Levelscript.IndexOfFirst(LevelscriptCommandTypes.x1D);
                    lvl.Levelscript.Insert(indexoffirstx1d, newlobcmd);
                    lvl.LastLobCmdSegLoad = newlobcmd;
                }

                if (!lvl.Levelscript.Contains(newlobjumpcmd))
                {
                    int indexoffirstx1d = lvl.Levelscript.IndexOfFirst(LevelscriptCommandTypes.x1D);
                    lvl.Levelscript.Insert(indexoffirstx1d + 1, newlobjumpcmd);
                }
            }
            else
            {
                if (cmdLobJump is object)
                {
                    lvl.Levelscript.Remove(cmdLobJump);
                }

                if (cmdLobSegLoad is object)
                {
                    lvl.Levelscript.Remove(cmdLobSegLoad);
                }
            }

            // Write Level Start (Start of Bank 0x19)
            lvl.Bank0x19.Data.Position = 0;
            foreach (byte b in Level.LevelscriptStart)
            {
                data0x19.Write(b);
            }

            // Write Levelscript
            lvl.Levelscript.Write(lvl.Bank0x19.Data, Conversions.ToInteger(data0x19.Position));

            // Parse Levelscript again!
            bool AreaOnFly = false;

            foreach (var c in lvl.Levelscript.ToArray())
            {
                var switchExpr3 = c.CommandType;
                switch (switchExpr3)
                {
                case LevelscriptCommandTypes.StartArea:
                {
                    AreaOnFly = true;
                    break;
                }

                case LevelscriptCommandTypes.EndOfArea:
                {
                    AreaOnFly = false;
                    lvl.Levelscript.Remove(c);
                    break;
                }
                }

                if (AreaOnFly)
                {
                    lvl.Levelscript.Remove(c);
                }
            }

            var bwToUse = data0x19 ?? output;

            // Write 4 checkbytes for the One-0xE-Bank-Per-Area-Code
            lvl.Bank0x19.Data.Position = 0x5FFC;
            bwToUse.Write(Conversions.ToInteger(0x4BC9189A));

            // Write Area Table
            foreach (LevelArea a in lvl.Areas)
            {
                uint off = (uint)(0x5F00 + a.AreaID * 0x10);
                lvl.Bank0x19.Data.Position = off;
                bwToUse.Write(Conversions.ToUInteger(a.Bank0x0EOffset));
                bwToUse.Write(Conversions.ToUInteger(a.Bank0x0EOffset + a.Bank0xELength));
                bwToUse.Write(Conversions.ToUInteger(0));
                bwToUse.Write(Conversions.ToByte(0x0));
                bwToUse.Write(Conversions.ToByte(0x0));
                bwToUse.Write(Conversions.ToByte(0x0));
                bwToUse.Write(Bits.ArrayToByte(new[] { false, false, false, false, false, false, false, a.Enable2DCamera }));
            }

            // Write SpecialBoxes
            int CurrentBoxOffset = 0x6A00;

            foreach (LevelArea a in lvl.Areas)
            {
                var TableIndex  = new[] { 0, 0x32, 0x33 };
                var TableOffset = new[] { 0x6000 + 0x50 * a.AreaID, 0x6280 + 0x50 * a.AreaID, 0x6500 + 0x50 * a.AreaID };

                foreach (SpecialBoxType t in Enum.GetValues(typeof(SpecialBoxType)))
                {
                    foreach (SpecialBox w in a.SpecialBoxes.Where(n => n.Type == t))
                    {
                        // Write Table Entry
                        bwToUse.Position = TableOffset[(int)w.Type];
                        bwToUse.Write(Conversions.ToShort(TableIndex[(int)w.Type]));
                        bwToUse.Write(Conversions.ToShort(0x0));
                        bwToUse.Write(Conversions.ToInteger(CurrentBoxOffset + lvl.Bank0x19.BankAddress));
                        TableOffset[(int)w.Type] = Conversions.ToInteger(bwToUse.Position);

                        // Write Box Data
                        bwToUse.Position = CurrentBoxOffset;
                        foreach (byte b in w.ToArrayBoxData())
                        {
                            bwToUse.Write(b);
                        }
                        TableIndex[(int)w.Type] += 1;
                        CurrentBoxOffset        += 0x20;
                    }
                }

                foreach (int i in TableOffset)
                {
                    bwToUse.Position = i;
                    bwToUse.Write(Conversions.ToUShort(0xFFFF));
                }
            }

            // Write Bank0x19
            lvl.Bank0x19.WriteData(output);

            // Hardcoded Camera Settings & Act Selector
            General.PatchClass.Open(output);
            General.PatchClass.set_HardcodedCamera_Enabled(lvl.LevelID, lvl.HardcodedCameraSettings);
            General.PatchClass.set_ActSelector_Enabled(lvl.LevelID, lvl.ActSelector);

            // Write Pointer to Levelscript
            output.Position = lid.Pointer;
            output.Write(Conversions.ToInteger(0x100019));
            output.Write(Conversions.ToUInteger(lvl.Bank0x19.RomStart));
            output.Write(Conversions.ToUInteger(lvl.Bank0x19.RomEnd));
            output.Write(Conversions.ToUInteger(0x1900001C));
            output.Write(Conversions.ToUInteger(0x7040000));

            // Write Area Reverb
            if (EnableLoadingAreaReverb)
            {
                foreach (var area in lvl.Areas)
                {
                    if (area is RMLevelArea && area.AreaID >= 1 && area.AreaID <= 3)
                    {
                        output.Position = 0xEE0C0 + lvl.LevelID * 3 + area.AreaID - 1;
                        output.Write((byte)((RMLevelArea)area).ReverbLevel);
                    }
                }
            }

            return(saveres);
        }
Esempio n. 4
0
        /// <summary>
        /// Loads a SM64 Editor Level from ROM.
        /// </summary>
        /// <param name="lvl"></param>
        /// <param name="rommgr"></param>
        /// <param name="LevelID"></param>
        /// <param name="segAddress"></param>
        public void LoadLevel(Level lvl, RomManager rommgr, ushort LevelID, uint segAddress)
        {
            int customBGStart = 0;
            int customBGEnd   = 0;

            lvl.LevelID = LevelID;

            // Load Bank 0x19
            lvl.Bank0x19 = rommgr.GetSegBank(0x19);
            lvl.Bank0x19.ReadDataIfNull(rommgr.RomFile);
            if (lvl.Bank0x19.Length < 0x10000)
            {
                lvl.Bank0x19.Length = 0x10000;
            }

            if (!lvl.Closed)
            {
                lvl.Close();
            }
            lvl.Closed = false;

            // Lade Levelscript
            lvl.Levelscript = new Levelscript();
            lvl.Levelscript.Read(rommgr, Conversions.ToInteger(segAddress));

            // Erstelle Areas / Lade Einstellungen
            bool      AreaOnFly = false;
            LevelArea tArea     = null;
            var       CurrentLevelScriptCommands = lvl.Levelscript.ToArray();
            var       cmdsToRemove = new List <LevelscriptCommand>();
            LevelArea firstArea    = null;

            foreach (LevelscriptCommand c in CurrentLevelScriptCommands)
            {
                var switchExpr = c.CommandType;
                switch (switchExpr)
                {
                case LevelscriptCommandTypes.StartArea:
                {
                    AreaOnFly = true;
                    tArea     = new SM64ELevelArea();
                    if (firstArea is null)
                    {
                        firstArea = tArea;
                    }
                    tArea.AreaID          = clStartArea.GetAreaID(c);
                    tArea.GeolayoutOffset = clStartArea.GetSegGeolayoutAddr(c);
                    tArea.Geolayout.Read(rommgr, Conversions.ToInteger(tArea.GeolayoutOffset));
                    break;
                }

                case LevelscriptCommandTypes.EndOfArea:
                {
                    tArea.Levelscript.Add(c);
                    lvl.Levelscript.Remove(c);
                    lvl.Areas.Add(tArea);
                    AreaOnFly = false;
                    break;
                }

                case LevelscriptCommandTypes.AreaMusic:
                {
                    tArea.BGMusic = clAreaMusic.GetMusicID(c);
                    break;
                }

                case LevelscriptCommandTypes.AreaMusicSimple:
                {
                    tArea.BGMusic = clAreaMusicSimple.GetMusicID(c);
                    break;
                }

                case LevelscriptCommandTypes.Tarrain:
                {
                    tArea.TerrainType = (Geolayout.TerrainTypes)clTerrian.GetTerrainType(c);
                    break;
                }

                case LevelscriptCommandTypes.Normal3DObject:
                {
                    if (clNormal3DObject.GetSegBehaviorAddr(c) == (long)0x13003420)
                    {
                    }
                    // tArea.ScrollingTextures.Add(New ManagedScrollingTexture(c))
                    else
                    {
                        tArea.Objects.Add(c);
                    }

                    break;
                }

                case LevelscriptCommandTypes.ConnectedWarp:
                {
                    if ((new[] { 0xF0, 0xF1 }).Contains(clWarp.GetWarpID(c)))
                    {
                        tArea.WarpsForGame.Add(c);
                    }
                    else
                    {
                        tArea.Warps.Add(c);
                    }

                    break;
                }

                case LevelscriptCommandTypes.PaintingWarp:
                case LevelscriptCommandTypes.InstantWarp:
                {
                    tArea.Warps.Add(c);
                    break;
                }

                case LevelscriptCommandTypes.LoadRomToRam:
                {
                    byte bankID    = clLoadRomToRam.GetSegmentedID(c);
                    int  startAddr = clLoadRomToRam.GetRomStart(c);
                    int  endAddr   = clLoadRomToRam.GetRomEnd(c);
                    switch (bankID)
                    {
                    case 0xA:             // Background-Image
                    {
                        customBGStart = startAddr;
                        customBGEnd   = endAddr - 0x140;
                        break;
                    }

                    case 0xE:
                    {
                        rommgr.SetSegBank(bankID, startAddr, endAddr);
                        break;
                    }
                    }

                    break;
                }

                case LevelscriptCommandTypes.ShowDialog:
                {
                    if (AreaOnFly)
                    {
                        tArea.ShowMessage.Enabled  = true;
                        tArea.ShowMessage.DialogID = clShowDialog.GetDialogID(c);
                    }

                    break;
                }

                case LevelscriptCommandTypes.JumpBack:
                case LevelscriptCommandTypes.JumpToSegAddr:
                {
                    if (tArea is object)
                    {
                        cmdsToRemove.Add(c);
                    }
                    break;
                }
                }

                if (AreaOnFly && !cmdsToRemove.Contains(c))
                {
                    lvl.Levelscript.Remove(c);
                    tArea.Levelscript.Add(c);
                }
            }

            // Lösche alle Jump-Commands aus dem Levelscript
            foreach (LevelscriptCommand cmd in cmdsToRemove)
            {
                lvl.Levelscript.Remove(cmd);
                cmd.Close();
            }

            // Stelle frisches Levelscript wieder her
            lvl.CreateNewLevelscript();

            // Lösche alle Objekte und Warps aus dem Levelscript
            var lvlscrptidstoremove = new[] { LevelscriptCommandTypes.Normal3DObject, LevelscriptCommandTypes.ConnectedWarp, LevelscriptCommandTypes.PaintingWarp, LevelscriptCommandTypes.InstantWarp };

            foreach (var a in lvl.Areas)
            {
                foreach (var c in a.Levelscript.Where(n => lvlscrptidstoremove.Contains(n.CommandType)).ToArray())
                {
                    a.Levelscript.Remove(c);
                }
            }

            // Lese Custom Background Image
            var fs  = new FileStream(rommgr.RomFile, FileMode.Open, FileAccess.Read);
            var br2 = new BinaryReader(fs);

            lvl.Background.Enabled = false;
            foreach (LevelArea a in lvl.Areas)
            {
                var bgglcmd = a.Geolayout.Geolayoutscript.GetFirst(GeolayoutCommandTypes.Background);
                if (cgBackground.GetBackgroundPointer(bgglcmd) == 0)
                {
                    a.Background.Type  = AreaBGs.Color;
                    a.Background.Color = cgBackground.GetRrgbaColor(bgglcmd);
                }
                else
                {
                    a.Background.Type      = AreaBGs.Levelbackground;
                    lvl.Background.ID      = (Geolayout.BackgroundIDs)cgBackground.GetBackgroundID(bgglcmd);
                    lvl.Background.Enabled = true;
                }
            }

            if (lvl.Background.Enabled && lvl.Background.ID == Geolayout.BackgroundIDs.Custom)
            {
                fs.Position = customBGStart;
                lvl.Background.ReadImage(fs, customBGStart);
            }

            int          bank0x19RomStart;
            int          bank0x19RomEnd;
            BinaryReader brToUse;

            bank0x19RomStart = 0;
            bank0x19RomEnd   = lvl.Bank0x19.Length;
            brToUse          = new BinaryReader(lvl.Bank0x19.Data);

            // Lese Area-Modelle
            var modelBank         = rommgr.GetSegBank(0xE);
            int curMdlStartOffset = modelBank.RomStart;

            for (int i = 0, loopTo = lvl.Areas.Count - 1; i <= loopTo; i++)
            {
                var a            = lvl.Areas[i];
                int newEndOffset = GetModelEnd(fs, modelBank.RomStart, Conversions.ToByte(i));
                a.Bank0x0EOffset = Conversions.ToUInteger(curMdlStartOffset);
                rommgr.SetSegBank(0xE, Conversions.ToInteger(a.Bank0x0EOffset), newEndOffset, a.AreaID);
                a.AreaModel.Collision = new Model.Collision.CollisionMap();
                a.AreaModel.Collision.FromStream(fs, modelBank.SegToRomAddr(a.CollisionPointer));
                a.AreaModel.Fast3DBuffer = new Model.Fast3D.Fast3DBuffer();
                a.AreaModel.FromStream(fs, modelBank.RomStart, 0xE000000, curMdlStartOffset, newEndOffset - curMdlStartOffset, a.Geolayout.Geopointers.ToArray(), a.CollisionPointer);
                a.AreaModel.Collision.SpecialBoxes.Clear();
                curMdlStartOffset = newEndOffset;
            }

            // Lese alle Box-Daten
            firstArea.SpecialBoxes.Clear();
            firstArea.SpecialBoxes.AddRange(SpecialBoxList.ReadTable(brToUse.BaseStream, SpecialBoxType.Water, bank0x19RomStart, bank0x19RomStart + 0x1810));
            firstArea.SpecialBoxes.AddRange(SpecialBoxList.ReadTable(brToUse.BaseStream, SpecialBoxType.ToxicHaze, bank0x19RomStart, bank0x19RomStart + 0x1850));
            firstArea.SpecialBoxes.AddRange(SpecialBoxList.ReadTable(brToUse.BaseStream, SpecialBoxType.Mist, bank0x19RomStart, bank0x19RomStart + 0x18A0));
            var areaWithBoxData = lvl.Areas.FirstOrDefault(n => n.AreaModel.Collision.SpecialBoxes.Any());

            if (areaWithBoxData is object)
            {
                for (int i = 0, loopTo1 = firstArea.SpecialBoxes.Count - 1; i <= loopTo1; i++)
                {
                    var boxdata = firstArea.AreaModel.Collision.SpecialBoxes.ElementAtOrDefault(i);
                    if (boxdata is object)
                    {
                        firstArea.SpecialBoxes[i].Y = boxdata.Y;
                    }
                }
            }

            // One-Bank-0xE-System
            lvl.OneBank0xESystemEnabled = true;

            // Act Selector
            General.PatchClass.Open(fs);
            lvl.ActSelector = General.PatchClass.get_ActSelector_Enabled(LevelID);

            // Hardcoded Camera
            lvl.HardcodedCameraSettings = General.PatchClass.get_HardcodedCamera_Enabled(LevelID);
            fs.Close();

            // Object-Banks
            lvl.MyObjectBanks.Clear();
            lvl.MyObjectBanks.Add(0xC, null);
            lvl.MyObjectBanks.Add(0xD, null);
            lvl.MyObjectBanks.Add(0x9, null);
        }
Esempio n. 5
0
        /// <summary>
        /// Loads a ROM Manager Level from ROM.
        /// </summary>
        /// <param name="lvl"></param>
        /// <param name="rommgr"></param>
        /// <param name="LevelID"></param>
        /// <param name="segAddress"></param>
        public virtual void LoadLevel(Level lvl, RomManager rommgr, ushort LevelID, uint segAddress)
        {
            int customBGStart = 0;
            int customBGEnd   = 0;

            lvl.LevelID = LevelID;

            // Load Bank 0x19
            lvl.Bank0x19 = rommgr.GetSegBank(0x19);
            lvl.Bank0x19.ReadDataIfNull(rommgr.RomFile);

            // Close if not closed & re-open
            if (!lvl.Closed)
            {
                lvl.Close();
            }
            lvl.Closed = false;

            // Lade Levelscript
            lvl.Levelscript = new Levelscript();
            lvl.Levelscript.Read(rommgr, Conversions.ToInteger(segAddress));

            // Erstelle Areas / Lade Einstellungen
            bool      AreaOnFly = false;
            LevelArea tArea     = null;
            var       CurrentLevelScriptCommands = lvl.Levelscript.ToArray();
            var       cmdsToRemove = new List <LevelscriptCommand>();

            foreach (LevelscriptCommand c in CurrentLevelScriptCommands)
            {
                var switchExpr = c.CommandType;
                switch (switchExpr)
                {
                case LevelscriptCommandTypes.StartArea:
                    AreaOnFly             = true;
                    tArea                 = new RMLevelArea();
                    tArea.AreaID          = clStartArea.GetAreaID(c);
                    tArea.GeolayoutOffset = clStartArea.GetSegGeolayoutAddr(c);     // - bank0x19.BankAddress + bank0x19.RomStart
                    tArea.Geolayout.Read(rommgr, Conversions.ToInteger(tArea.GeolayoutOffset));
                    break;

                case LevelscriptCommandTypes.EndOfArea:
                    tArea.Levelscript.Add(c);
                    lvl.Levelscript.Remove(c);
                    lvl.Areas.Add(tArea);
                    AreaOnFly = false;
                    break;

                case LevelscriptCommandTypes.AreaMusic:
                    tArea.BGMusic = clAreaMusic.GetMusicID(c);
                    break;

                case LevelscriptCommandTypes.AreaMusicSimple:
                    tArea.BGMusic = clAreaMusicSimple.GetMusicID(c);
                    break;

                case LevelscriptCommandTypes.Tarrain:
                    tArea.TerrainType = (Geolayout.TerrainTypes)clTerrian.GetTerrainType(c);
                    break;

                case LevelscriptCommandTypes.Normal3DObject:
                    var scrollTexAddrs = new List <int>(new[] { 0x400000, 0x401700 });
                    if (rommgr.RomConfig.ScrollTexConfig.UseCustomBehavior)
                    {
                        scrollTexAddrs.Add(rommgr.RomConfig.ScrollTexConfig.CustomBehaviorAddress);
                    }
                    if (scrollTexAddrs.Contains((int)clNormal3DObject.GetSegBehaviorAddr(c)))
                    {
                        tArea.ScrollingTextures.Add(new ManagedScrollingTexture(c));
                    }
                    else
                    {
                        tArea.Objects.Add(c);
                    }
                    break;

                case LevelscriptCommandTypes.ConnectedWarp:
                    if ((new[] { 0xF0, 0xF1 }).Contains(clWarp.GetWarpID(c)))
                    {
                        tArea.WarpsForGame.Add(c);
                    }
                    else
                    {
                        tArea.Warps.Add(c);
                    }
                    break;

                case LevelscriptCommandTypes.PaintingWarp:
                case LevelscriptCommandTypes.InstantWarp:
                    tArea.Warps.Add(c);
                    break;

                case LevelscriptCommandTypes.LoadRomToRam:
                    byte bankID    = clLoadRomToRam.GetSegmentedID(c);
                    int  startAddr = clLoadRomToRam.GetRomStart(c);
                    int  endAddr   = clLoadRomToRam.GetRomEnd(c);
                    switch (bankID)
                    {
                    case 0xA:         // Background-Image
                        customBGStart = startAddr;
                        customBGEnd   = endAddr - 0x140;
                        break;

                    case 0x7:         // Global Object Bank
                        if (rommgr.GlobalModelBank?.CurSeg is object && startAddr == rommgr.GlobalModelBank.CurSeg.RomStart && endAddr == rommgr.GlobalModelBank.CurSeg.RomEnd)
                        {
                            lvl.EnableGlobalObjectBank = true;
                            lvl.LastGobCmdSegLoad      = c;
                        }
                        break;

                    case 0x9:
                        if (((RMLevel)lvl).Config.EnableLocalObjectBank)
                        {
                            lvl.EnableLocalObjectBank = true;
                        }
                        lvl.LastLobCmdSegLoad = c;
                        break;
                    }
                    break;

                case LevelscriptCommandTypes.ShowDialog:
                    if (AreaOnFly)
                    {
                        tArea.ShowMessage.Enabled  = true;
                        tArea.ShowMessage.DialogID = clShowDialog.GetDialogID(c);
                    }
                    break;

                case LevelscriptCommandTypes.JumpBack:
                case LevelscriptCommandTypes.JumpToSegAddr:
                    if (tArea is object)
                    {
                        cmdsToRemove.Add(c);
                    }
                    break;
                }

                if (AreaOnFly && !cmdsToRemove.Contains(c))
                {
                    lvl.Levelscript.Remove(c);
                    tArea.Levelscript.Add(c);
                }
            }

            // Lösche alle Jump-Commands aus dem Levelscript
            foreach (LevelscriptCommand cmd in cmdsToRemove)
            {
                lvl.Levelscript.Remove(cmd);
                cmd.Close();
            }

            // Lösche alle Objekte und Warps aus dem Levelscript
            var lvlscrptidstoremove = new[] { LevelscriptCommandTypes.Normal3DObject, LevelscriptCommandTypes.ConnectedWarp, LevelscriptCommandTypes.PaintingWarp, LevelscriptCommandTypes.InstantWarp };

            foreach (var a in lvl.Areas)
            {
                foreach (var c in a.Levelscript.Where(n => lvlscrptidstoremove.Contains(n.CommandType)).ToArray())
                {
                    a.Levelscript.Remove(c);
                }
            }

            // Load Local Object Bank
            if (lvl.LastLobCmdSegLoad is object)
            {
                var seg = new SegmentedBank()
                {
                    BankID   = clLoadRomToRam.GetSegmentedID(lvl.LastLobCmdSegLoad),
                    RomStart = clLoadRomToRam.GetRomStart(lvl.LastLobCmdSegLoad),
                    RomEnd   = clLoadRomToRam.GetRomEnd(lvl.LastLobCmdSegLoad)
                };
                lvl.LocalObjectBank.ReadFromSeg(rommgr, seg, ((RMLevel)lvl).Config.LocalObjectBank);
            }

            // Lese Custom Background Image
            var fs  = new FileStream(rommgr.RomFile, FileMode.Open, FileAccess.Read);
            var br2 = new BinaryReader(fs);

            lvl.Background.Enabled = false;
            foreach (LevelArea a in lvl.Areas)
            {
                var bgglcmd = a.Geolayout.Geolayoutscript.GetFirst(GeolayoutCommandTypes.Background);
                if (cgBackground.GetBackgroundPointer(bgglcmd) == 0)
                {
                    a.Background.Type  = AreaBGs.Color;
                    a.Background.Color = cgBackground.GetRrgbaColor(bgglcmd);
                }
                else
                {
                    a.Background.Type      = AreaBGs.Levelbackground;
                    lvl.Background.ID      = (Geolayout.BackgroundIDs)cgBackground.GetBackgroundID(bgglcmd);
                    lvl.Background.Enabled = true;
                }
            }

            if (customBGStart != 0)
            {
                lvl.Background.IsCustom = true;
            }

            foreach (int val in Enum.GetValues(typeof(Geolayout.BackgroundPointers)))
            {
                if (val != 0 && customBGStart == val)
                {
                    lvl.Background.IsCustom = false;
                }
            }

            if (lvl.Background.Enabled && lvl.Background.IsCustom) // .ID = Geolayout.BackgroundIDs.Custom Then
            {
                fs.Position = customBGStart;
                lvl.Background.ReadImage(fs, customBGStart);
            }

            int          bank0x19RomStart;
            int          bank0x19RomEnd;
            BinaryReader brToUse;

            bank0x19RomStart = 0;
            bank0x19RomEnd   = lvl.Bank0x19.Length;
            brToUse          = new BinaryReader(lvl.Bank0x19.Data);

            // Lese Area-Table
            foreach (LevelArea a in lvl.Areas)
            {
                // Fast3D-Daten
                brToUse.BaseStream.Position = bank0x19RomStart + 0x5F00 + a.AreaID * 0x10;
                a.Bank0x0EOffset            = Conversions.ToUInteger(SwapInts.SwapInt32(brToUse.ReadInt32()));
                int romEnd0xE = SwapInts.SwapInt32(brToUse.ReadInt32());
                rommgr.SetSegBank(0xE, Conversions.ToInteger(a.Bank0x0EOffset), romEnd0xE, a.AreaID);

                // 2D-Kamera
                brToUse.BaseStream.Position = bank0x19RomStart + 0x5F0F + a.AreaID * 0x10;
                a.Enable2DCamera            = Bits.GetBoolOfByte(brToUse.ReadByte(), 7);
            }

            // Lese Area-Modelle
            foreach (LevelArea a in lvl.Areas)
            {
                a.AreaModel.FromStream(fs, Conversions.ToInteger(a.Bank0x0EOffset), 0xE000000, a.Fast3DBankRomStart, a.Fast3DLength, a.Geolayout.Geopointers.ToArray(), a.CollisionPointer);
            }

            // Lese alle Box-Daten
            int CurrentBoxOffset = bank0x19RomStart + 0x6A00;

            foreach (LevelArea a in lvl.Areas)
            {
                // Clear special boxes
                a.SpecialBoxes.Clear();

                // Load special boxes
                a.SpecialBoxes.AddRange(SpecialBoxList.ReadTable(brToUse.BaseStream, SpecialBoxType.Water, bank0x19RomStart, bank0x19RomStart + 0x6000 + 0x50 * a.AreaID));
                a.SpecialBoxes.AddRange(SpecialBoxList.ReadTable(brToUse.BaseStream, SpecialBoxType.ToxicHaze, bank0x19RomStart, bank0x19RomStart + 0x6280 + 0x50 * a.AreaID));
                a.SpecialBoxes.AddRange(SpecialBoxList.ReadTable(brToUse.BaseStream, SpecialBoxType.Mist, bank0x19RomStart, bank0x19RomStart + 0x6500 + 0x50 * a.AreaID));

                for (int i = 0; i < a.SpecialBoxes.Count; i++)
                {
                    var boxdata = a.AreaModel.Collision.SpecialBoxes.ElementAtOrDefault(i);
                    if (boxdata is object)
                    {
                        a.SpecialBoxes[i].Y = boxdata.Y;
                    }
                }
            }

            // One-Bank-0xE-System
            lvl.OneBank0xESystemEnabled = true;

            // Act Selector
            General.PatchClass.Open(fs);
            lvl.ActSelector = General.PatchClass.get_ActSelector_Enabled(LevelID);

            // Hardcoded Camera
            lvl.HardcodedCameraSettings = General.PatchClass.get_HardcodedCamera_Enabled(LevelID);

            // Area Reverb
            if (EnableLoadingAreaReverb)
            {
                foreach (var area in lvl.Areas)
                {
                    if (area is RMLevelArea && area.AreaID >= 1 && area.AreaID <= 3)
                    {
                        fs.Position = 0xEE0C0 + lvl.LevelID * 3 + area.AreaID - 1;
                        ((RMLevelArea)area).ReverbLevel = (AreaReverbLevel)fs.ReadByte();
                    }
                }
            }

            fs.Close();
        }