Пример #1
0
 public override void InitObjects(Unity_Level level)
 {
     foreach (var obj in level.EventData.Cast <Unity_Object_GBARRR>().Where(x => x.Object.ObjectType == GBARRR_ObjectType.Gate || x.Object.ObjectType == GBARRR_ObjectType.DoorTrigger))
     {
         obj.LinkIndex = level.EventData.Cast <Unity_Object_GBARRR>().FindItemIndex(x => x.Object.RuntimeStateIndex == obj.Object.RuntimeStateIndex && x != obj && (x.Object.ObjectType == GBARRR_ObjectType.Gate || x.Object.ObjectType == GBARRR_ObjectType.DoorTrigger));
     }
 }
Пример #2
0
        public async UniTask<Unity_Level> LoadAsync(Context context, bool loadTextures)
        {
            Controller.DetailedState = $"Loading data";
            await Controller.WaitIfNecessary();

            // Read the rom
            var rom = FileFactory.Read<SNES_Proto_ROM>(GetROMFilePath, context);

            // Get the map
            var map = rom.MapData;

            var maps = new Unity_Map[]
            {
                new Unity_Map()
                {
                    // Set the dimensions
                    Width = map.Width,
                    Height = map.Height,

                    // Create the tile arrays
                    TileSet = new Unity_MapTileMap[1],
                    MapTiles = map.Tiles.Select(x => new Unity_Tile(x)).ToArray(),
                    TileSetWidth = 1
                }
            };

            // Convert levelData to common level format
            Unity_Level level = new Unity_Level(maps, new Unity_ObjectManager(context), getCollisionTypeGraphicFunc: x => ((R1Jaguar_TileCollisionType)x).GetCollisionTypeGraphic());

            Controller.DetailedState = $"Loading tile set";
            await Controller.WaitIfNecessary();

            // Load tile set and treat black as transparent
            level.Maps[0].TileSet[0] = GetTileSet(context, rom);

            return level;
        }
Пример #3
0
 public UniTask SaveLevelAsync(Context context, Unity_Level level) => throw new NotImplementedException();
Пример #4
0
 public virtual void InitObjects(Unity_Level level)
 {
 }
Пример #5
0
        /// <summary>
        /// Randomizes the events in a level based on the flags
        /// </summary>
        /// <param name="level">The level</param>
        /// <param name="flags">The flags</param>
        /// <param name="seed">An optional seed to use</param>
        /// <param name="map">The map index</param>
        public static void Randomize(Unity_Level level, RandomizerFlags flags, int?seed, int map)
        {
            var random = seed != null ? new Random(seed.Value) : new Random();
            var maxX   = level.Maps[map].Width * Settings.CellSize;
            var maxY   = level.Maps[map].Height * Settings.CellSize;

            // Enumerate every event
            foreach (var eventData in level.EventData
                     .Select(eventData => new
            {
                obj = (Unity_Object_R1)eventData,
                isAlways = eventData.IsAlways,
                isEditor = eventData.IsEditor
            })
                     .Where(x => !x.isAlways && !x.isEditor)
                     .Where(x => x.obj.EventData.Type != R1_EventType.TYPE_RAY_POS &&
                            x.obj.EventData.Type != R1_EventType.TYPE_PANCARTE &&
                            x.obj.EventData.Type != R1_EventType.TYPE_SIGNPOST)
                     .Select(x => x.obj))
            {
                if (flags.HasFlag(RandomizerFlags.Pos))
                {
                    eventData.XPosition = (short)random.Next(0, maxX);
                    eventData.YPosition = (short)random.Next(0, maxY);
                }

                if (flags.HasFlag(RandomizerFlags.Des))
                {
                    eventData.DESIndex = random.Next(1, ((Unity_ObjectManager_R1)level.ObjManager).DES.Length - 2); // One less for BigRay
                }
                if (flags.HasFlag(RandomizerFlags.Eta))
                {
                    eventData.ETAIndex = random.Next(0, ((Unity_ObjectManager_R1)level.ObjManager).ETA.Length - 2); // One less for BigRay
                }
                if (flags.HasFlag(RandomizerFlags.CommandOrder))
                {
                    int n = eventData.EventData.Commands.Commands.Length - 1;

                    while (n > 1)
                    {
                        n--;
                        int k     = random.Next(n + 1);
                        var value = eventData.EventData.Commands.Commands[k];
                        eventData.EventData.Commands.Commands[k] = eventData.EventData.Commands.Commands[n];
                        eventData.EventData.Commands.Commands[n] = value;
                    }
                }

                if (flags.HasFlag(RandomizerFlags.Follow))
                {
                    eventData.EventData.SetFollowEnabled(level.ObjManager.Context.Settings, random.Next(0, 1) == 1);
                    eventData.EventData.OffsetHY = (byte)random.Next(0, 10);
                }

                if (flags.HasFlag(RandomizerFlags.States))
                {
                    eventData.EventData.Etat    = (byte)random.Next(0, ((Unity_ObjectManager_R1)level.ObjManager).ETA[eventData.ETAIndex].Data.Length - 1);
                    eventData.EventData.SubEtat = (byte)random.Next(0, ((Unity_ObjectManager_R1)level.ObjManager).ETA[eventData.ETAIndex].Data[eventData.EventData.Etat].Length - 1);
                }

                if (flags.HasFlag(RandomizerFlags.Type))
                {
                    eventData.EventData.Type = (R1_EventType)random.Next(0, 255);
                }
            }
        }
Пример #6
0
        /// <summary>
        /// Saves the specified level
        /// </summary>
        /// <param name="context">The serialization context</param>
        /// <param name="lvl">The level</param>
        public override UniTask SaveLevelAsync(Context context, Unity_Level lvl)
        {
            // Menu levels can't be saved
            if (context.Settings.R1_World == R1_World.Menu)
            {
                return(UniTask.CompletedTask);
            }

            // Get the level file path
            var lvlPath = GetLevelFilePath(context.Settings);

            // Get the level data
            var lvlData = context.GetMainFileObject <R1_PS1_LevFile>(lvlPath);

            // Get the object manager
            var objManager = (Unity_ObjectManager_R1)lvl.ObjManager;

            // Update the tiles
            for (int y = 0; y < lvlData.MapData.Height; y++)
            {
                for (int x = 0; x < lvlData.MapData.Width; x++)
                {
                    // Set the tile
                    lvlData.MapData.Tiles[y * lvlData.MapData.Width + x] = lvl.Maps[0].MapTiles[y * lvlData.MapData.Width + x].Data;
                }
            }

            var newEvents = lvl.EventData.Cast <Unity_Object_R1>().Select(e =>
            {
                var ed = e.EventData;

                if (ed.PS1Demo_Unk1 == null)
                {
                    ed.PS1Demo_Unk1 = new byte[40];
                }

                if (ed.Unk_98 == null)
                {
                    ed.Unk_98 = new byte[5];
                }

                // TODO: Do this in the Unity_Object instead
                ed.ImageDescriptorCount = (ushort)objManager.DES[e.DESIndex].Data.ImageDescriptors.Length;
                ed.AnimDescriptorCount  = (byte)objManager.DES[e.DESIndex].Data.Graphics.Animations.Count;

                // TODO: Get from DESData in obj manager instead?
                ed.ImageDescriptors = FileFactory.Read <ObjectArray <R1_ImageDescriptor> >(ed.ImageDescriptorsPointer, context, (s, o) => o.Length = ed.ImageDescriptorCount).Value;
                ed.AnimDescriptors  = FileFactory.Read <ObjectArray <R1_PS1_AnimationDescriptor> >(ed.AnimDescriptorsPointer, context, (s, o) => o.Length = ed.AnimDescriptorCount).Value;
                ed.ETA = context.Cache.FromOffset <R1_PS1_ETA>(ed.ETAPointer);

                // TODO: Update this
                //ed.ImageBuffer = des.ImageBuffer;

                return(ed);
            }).ToArray();

            var newEventLinkTable = objManager.LinkTable.Select(x => (byte)x).ToArray();

            // Relocate pointers to a new block of data we append to the level file
            UpdateAndFillDataBlock(lvlData.Offset + lvlData.FileSize, lvlData.EventData, newEvents, newEventLinkTable, context.Settings);

            // TODO: When writing make sure that ONLY the level file gets recreated - do not touch the other files (ignore DoAt if the file needs to be switched based on some setting?)
            // Save the file
            FileFactory.Write <R1_PS1_LevFile>(lvlPath, context);

            // Create ISO for the modified data
            CreateISO(context);

            return(UniTask.CompletedTask);
        }
Пример #7
0
        /// <summary>
        /// Loads the specified level for the editor
        /// </summary>
        /// <param name="context">The serialization context</param>
        /// <param name="loadTextures">Indicates if textures should be loaded</param>
        /// <returns>The level</returns>
        public override async UniTask <Unity_Level> LoadAsync(Context context, bool loadTextures)
        {
            // Get the level folder path
            var basePath = await GetLevelFolderPath(context);

            // TODO: Parse .ini file to get background etc.
            // Get file paths
            var mapPath        = GetMapFilePath(basePath);
            var mapEventsPath  = GetMapEventsFilePath(basePath);
            var saveEventsPath = GetSaveEventsFilePath(basePath);
            var pcxPath        = GetPCXFilePath(context.Settings);
            var eventsCsvPath  = GetEventManfiestFilePath(context.Settings.R1_World);

            // Load files to context
            await AddFile(context, mapPath);
            await AddFile(context, mapEventsPath, endianness : BinaryFile.Endian.Big); // Big endian just like on Jaguar
            await AddFile(context, pcxPath);

            // Read the files

            Controller.DetailedState = $"Loading map data";
            await Controller.WaitIfNecessary();

            var mapData = FileFactory.Read <MapData>(mapPath, context);

            Controller.DetailedState = $"Loading event data";
            await Controller.WaitIfNecessary();

            var mapEvents  = FileFactory.Read <R1Jaguar_MapEvents>(mapEventsPath, context);
            var saveEvents = FileFactory.ReadText <R1_Mapper_SaveEvents>(saveEventsPath, context);
            var csv        = FileFactory.ReadText <R1_Mapper_EventManifest>(eventsCsvPath, context);

            Controller.DetailedState = $"Loading tileset";
            await Controller.WaitIfNecessary();

            var pcx = FileFactory.Read <PCX>(pcxPath, context);

            // Get the palette from the PCX file
            var vgaPalette = pcx.VGAPalette;

            // Load the sprites
            var eventDesigns = loadTextures ? await LoadSpritesAsync(context, vgaPalette) : new Unity_ObjectManager_R1.DESData[0];

            // Read the world data
            var worldData = FileFactory.Read <R1_PC_WorldFile>(GetWorldFilePath(context.Settings), context);

            var maps = new Unity_Map[]
            {
                new Unity_Map()
                {
                    // Set the dimensions
                    Width  = mapData.Width,
                    Height = mapData.Height,

                    // Create the tile arrays
                    TileSet      = new Unity_MapTileMap[1],
                    MapTiles     = mapData.Tiles.Select(x => new Unity_Tile(x)).ToArray(),
                    TileSetWidth = 1
                }
            };

            var allEventInstances = saveEvents.SaveEventInstances.SelectMany(x => x).ToArray();

            // Create a linking table
            var linkTable = new ushort[allEventInstances.Length];

            // Handle each event link group
            foreach (var linkedEvents in allEventInstances.Select((x, i) => new
            {
                Index = i,
                Data = x
            }).GroupBy(x => x.Data.LinkID))
            {
                // Get the group
                var group = linkedEvents.ToArray();

                // Handle every event
                for (int i = 0; i < group.Length; i++)
                {
                    // Get the item
                    var item = group[i];

                    if (group.Length == i + 1)
                    {
                        linkTable[item.Index] = (ushort)group[0].Index;
                    }
                    else
                    {
                        linkTable[item.Index] = (ushort)group[i + 1].Index;
                    }
                }
            }

            // Create the object manager
            var objManager = new Unity_ObjectManager_R1(
                context: context,
                des: eventDesigns.Select((x, i) => new Unity_ObjectManager_R1.DataContainer <Unity_ObjectManager_R1.DESData>(x, i, worldData.DESFileNames?.ElementAtOrDefault(i))).ToArray(),
                eta: GetCurrentEventStates(context).Select((x, i) => new Unity_ObjectManager_R1.DataContainer <R1_EventState[][]>(x.States, i, worldData.ETAFileNames?.ElementAtOrDefault(i))).ToArray(),
                linkTable: linkTable,
                usesPointers: false,
                hasDefinedDesEtaNames: true);

            Controller.DetailedState = $"Loading events";
            await Controller.WaitIfNecessary();

            var levelEvents = new List <Unity_Object>();

            // Create events
            for (var i = 0; i < saveEvents.SaveEventInstances.Length; i++)
            {
                // Get the map base position, based on the event map
                var mapPos = mapEvents.EventIndexMap.FindItemIndex(z => z == i + 1);

                // Get the x and y positions
                var mapY = (uint)Math.Floor(mapPos / (double)(mapEvents.Width));
                var mapX = (uint)(mapPos - (mapY * mapEvents.Width));

                // Calculate the actual position on the map
                mapX *= 4 * (uint)Settings.CellSize;
                mapY *= 4 * (uint)Settings.CellSize;

                // Add every instance
                foreach (var instance in saveEvents.SaveEventInstances[i])
                {
                    // Get the definition
                    var def = csv.EventDefinitions.FirstOrDefault(x => x.Name == instance.EventDefinitionKey);

                    if (def == null)
                    {
                        throw new Exception($"No matching event definition found for {instance.EventDefinitionKey}");
                    }

                    var ed = new R1_EventData()
                    {
                        Type            = def.Type,
                        Etat            = def.Etat,
                        SubEtat         = def.SubEtat,
                        XPosition       = (short)(mapX + instance.OffsetX),
                        YPosition       = (short)(mapY + instance.OffsetY),
                        OffsetBX        = def.OffsetBX,
                        OffsetBY        = def.OffsetBY,
                        OffsetHY        = def.OffsetHY,
                        FollowSprite    = def.FollowSprite,
                        ActualHitPoints = (uint)instance.HitPoints,
                        DisplayPrio     = instance.DisplayPrio,
                        HitSprite       = def.HitSprite,

                        PS1Demo_Unk1 = new byte[40],
                        Unk_98       = new byte[5],

                        LabelOffsets = new ushort[0],
                        Commands     = R1_EventCommandCollection.FromBytes(def.EventCommands, context.Settings),
                    };

                    ed.SetFollowEnabled(context.Settings, def.FollowEnabled > 0);

                    // Add the event
                    levelEvents.Add(new Unity_Object_R1(
                                        eventData: ed,
                                        objManager: objManager,
                                        ETAIndex: worldData.ETAFileNames.FindItemIndex(x => x == def.ETAFile))
                    {
                        DESIndex = worldData.DESFileNames.FindItemIndex(x => x.Length > 4 && x.Substring(0, x.Length - 4) == def.DESFile)
                    });
                }
            }

            // Convert levelData to common level format
            var level = new Unity_Level(maps, objManager, levelEvents, rayman: new Unity_Object_R1(R1_EventData.GetRayman(context, levelEvents.Cast <Unity_Object_R1>().FirstOrDefault(x => x.EventData.Type == R1_EventType.TYPE_RAY_POS)?.EventData), objManager));

            Controller.DetailedState = $"Creating tileset";
            await Controller.WaitIfNecessary();

            // Load the tile set
            level.Maps[0].TileSet[0] = LoadTileSet(pcx);

            // Return the level
            return(level);
        }
Пример #8
0
        /// <summary>
        /// Loads the specified level for the editor
        /// </summary>
        /// <param name="context">The serialization context</param>
        /// <param name="loadTextures">Indicates if textures should be loaded</param>
        /// <returns>The level</returns>
        public override async UniTask <Unity_Level> LoadAsync(Context context, bool loadTextures)
        {
            await Controller.WaitIfNecessary();

            Controller.DetailedState = $"Loading files";

            uint baseAddress = 0x80018000;

            var fixDTAPath   = FixDataPath;
            var fixGRPPath   = FixGraphicsPath;
            var sprPLSPath   = SpritePalettesPath;
            var levelDTAPath = GetLevelDataPath(context.Settings);
            var levelSPRPath = GetLevelImageDescriptorsPath(context.Settings);
            var levelGRPPath = GetLevelGraphicsPath(context.Settings);

            baseAddress += await LoadFile(context, fixDTAPath, baseAddress);

            baseAddress -= 94; // FIX.DTA header size
            Pointer fixDTAHeader = new Pointer(baseAddress, context.FilePointer(fixDTAPath).file);

            R1_R2AllfixFooter footer = null;

            context.Deserializer.DoAt(fixDTAHeader, () => footer = context.Deserializer.SerializeObject <R1_R2AllfixFooter>(null, name: "AllfixFooter"));
            await LoadFile(context, fixGRPPath, 0);
            await LoadFile(context, sprPLSPath, 0);

            baseAddress += await LoadFile(context, levelSPRPath, baseAddress);

            baseAddress += await LoadFile(context, levelDTAPath, baseAddress);
            await LoadFile(context, levelGRPPath, 0);

            // Load every map
            for (int i = 0; i < 4; i++)
            {
                await LoadFile(context, GetSubMapPalettePath(i), 0);
                await LoadFile(context, GetSubMapTilesetPath(i), 0);
                await LoadFile(context, GetSubMapPath(i), 0);
            }

            await Controller.WaitIfNecessary();

            Controller.DetailedState = $"Loading level data";

            // Read the level data
            var lvlData = FileFactory.Read <R1_R2LevDataFile>(levelDTAPath, context);

            // Read the map blocks
            var maps = Enumerable.Range(0, MapCount).Select(x => FileFactory.Read <MapData>(GetSubMapPath(x), context)).ToArray();

            await Controller.WaitIfNecessary();

            Controller.DetailedState = $"Loading sprite data";

            var commonEvents = new List <Unity_Object>();

            if (loadTextures)
            {
                // Get the v-ram
                FillVRAM(context, VRAMMode.Level);
            }


            // Create the global design list

            var lvlImgDescriptors = FileFactory.Read <ObjectArray <R1_ImageDescriptor> >(levelSPRPath, context, onPreSerialize: (s, a) => a.Length = s.CurrentLength / 0xC).Value;

            var imgDescriptors = lvlData.FixImageDescriptors.Concat(lvlImgDescriptors).ToArray();

            // Get every sprite
            var globalDesigns = imgDescriptors.Select(img => GetSpriteTexture(context, null, img)).Select(tex => tex == null ? null : tex.CreateSprite()).ToArray();

            // Get the events
            var events = lvlData.Events.Concat(lvlData.AlwaysEvents).ToArray();

            Controller.DetailedState = $"Loading animations";
            await Controller.WaitIfNecessary();

            // Get the animation groups
            var r2AnimGroups = events.Select(x => x.AnimGroup).Append(footer.RaymanAnimGroup).Where(x => x != null).Distinct().ToArray();

            Unity_ObjectManager_R2.AnimGroup[] animGroups = new Unity_ObjectManager_R2.AnimGroup[r2AnimGroups.Length];
            for (int i = 0; i < animGroups.Length; i++)
            {
                animGroups[i] = await getGroupAsync(r2AnimGroups[i]);

                await Controller.WaitIfNecessary();
            }

            async UniTask <Unity_ObjectManager_R2.AnimGroup> getGroupAsync(R1_R2EventAnimGroup animGroup)
            {
                await UniTask.CompletedTask;

                // Add DES and ETA
                return(new Unity_ObjectManager_R2.AnimGroup(
                           pointer: animGroup?.Offset, eta: animGroup?.ETA.EventStates ?? new R1_EventState[0][],
                           animations: animGroup?.AnimationDecriptors?.Select(x => x.ToCommonAnimation()).ToArray(),
                           filePath: animGroup?.AnimationDescriptorsPointer?.file.filePath));
            }

            var objManager = new Unity_ObjectManager_R2(
                context: context,
                linkTable: lvlData.EventLinkTable,
                animGroups: animGroups,
                sprites: globalDesigns,
                imageDescriptors: imgDescriptors,
                levData: lvlData);

            Controller.DetailedState = $"Loading events";
            await Controller.WaitIfNecessary();

            // Add every event
            foreach (var e in events)
            {
                // Add the event
                commonEvents.Add(new Unity_Object_R2(e, objManager)
                {
                    IsAlwaysEvent = lvlData.AlwaysEvents.Contains(e)
                });
            }

            await Controller.WaitIfNecessary();

            Controller.DetailedState = $"Loading tiles";

            var levelMaps = maps.Select((x, i) => new Unity_Map()
            {
                Type  = Unity_Map.MapType.Graphics | Unity_Map.MapType.Collision,
                Layer = i < 3 ? Unity_Map.MapLayer.Back : Unity_Map.MapLayer.Middle,

                // Set the dimensions
                Width  = x.Width,
                Height = x.Height,

                // Create the tile array
                TileSet      = new Unity_TileSet[1],
                TileSetWidth = TileSetWidth
            }).ToArray();

            // Convert levelData to common level format
            Unity_Level level = new Unity_Level(
                maps: levelMaps,
                objManager: objManager,
                eventData: commonEvents,
                rayman: new Unity_Object_R2(R1_R2EventData.GetRayman(events.FirstOrDefault(x => x.EventType == R1_R2EventType.RaymanPosition), footer), objManager),
                getCollisionTypeNameFunc: x => ((R2_TileCollisionType)x).ToString(),
                getCollisionTypeGraphicFunc: x => ((R2_TileCollisionType)x).GetCollisionTypeGraphic());

            await Controller.WaitIfNecessary();

            // Load maps
            for (int i = 0; i < MapCount; i++)
            {
                // Get the tile set
                Unity_TileSet tileSet = GetTileSet(context, i);

                level.Maps[i].TileSet[0] = tileSet;

                // Set the tiles
                level.Maps[i].MapTiles = maps[i].Tiles.Select(x => new Unity_Tile(x)).ToArray();
            }

            // Return the level
            return(level);
        }
Пример #9
0
 public override UniTask SaveLevelAsync(Context context, Unity_Level lvl)
 {
     return(SaveLevelAsync(context, lvl, true));
 }
Пример #10
0
        public override void InitObjects(Unity_Level level)
        {
            // Init 3D objects
            var all3DObjects = level.EventData.OfType <Unity_Object_GBAIsometricSpyro>().ToArray();

            foreach (var obj in all3DObjects)
            {
                if (obj.Object.ObjectType != 0)
                {
                    GBAIsometric_Spyro_ObjInit.GetInitFunc(Context.Settings, obj.ObjType?.Data?.InitFunctionPointer?.AbsoluteOffset ?? 0)?.Invoke(obj, all3DObjects);

                    if (obj.AnimSetIndex == -1 && !obj.IsEditorObj && obj.ObjType?.Data?.InitFunctionPointer != null)
                    {
                        Debug.LogWarning($"Type {obj.Object.ObjectType} is not implemented with init function at 0x{obj.ObjType?.Data?.InitFunctionPointer}");
                    }
                }
            }

            // Init 2D objects
            var all2DObjects = level.EventData.OfType <Unity_Object_GBAIsometricSpyro2_2D>().ToArray();

            foreach (var obj in all2DObjects)
            {
                // Set link
                if (obj.CanBeLinked && obj.Object.LinkedObjectID != -1)
                {
                    var linkIndex = all2DObjects.FindItemIndex(x => x.Object.ID == obj.Object.LinkedObjectID && x.Object.Category == GBAIsometric_Spyro2_Object2D.ObjCategory.Door);

                    if (linkIndex != -1)
                    {
                        obj.LinkIndex = linkIndex;
                    }
                }

                // Set position
                if (obj.LinkIndex != -1)
                {
                    // If linked we use that position instead
                    obj.XPosition = all2DObjects[obj.LinkIndex].XPosition;
                    obj.YPosition = all2DObjects[obj.LinkIndex].YPosition;
                }
                else
                {
                    obj.XPosition = obj.Object.MinX;
                    obj.YPosition = obj.Object.MinY;
                }

                // Set graphics index based off of type
                switch (obj.Object.Category)
                {
                case GBAIsometric_Spyro2_Object2D.ObjCategory.Door:
                    obj.AnimSetIndex = GBAIsometric_Spyro_ObjInit.ConvertAnimSetIndex(Context.Settings.GameModeSelection, 0x86);

                    switch (Context.Settings.Level)
                    {
                    case 0:
                        obj.AnimationGroupIndex = 0x03;
                        break;

                    case 1:
                        obj.AnimationGroupIndex = 0x05;
                        break;

                    case 2:
                        obj.AnimationGroupIndex = 0x01;
                        break;

                    case 3:
                        obj.AnimationGroupIndex = 0x07;
                        break;
                    }
                    break;

                case GBAIsometric_Spyro2_Object2D.ObjCategory.Character:
                    switch (obj.Object.ObjType)
                    {
                    // Enemies
                    case 0:
                        obj.AnimSetIndex        = GBAIsometric_Spyro_ObjInit.ConvertAnimSetIndex(Context.Settings.GameModeSelection, 0x92);
                        obj.AnimationGroupIndex = 0x05;
                        break;

                    case 1:
                        obj.AnimSetIndex        = GBAIsometric_Spyro_ObjInit.ConvertAnimSetIndex(Context.Settings.GameModeSelection, 0x91);
                        obj.AnimationGroupIndex = 0x03;
                        break;

                    case 2:
                        obj.AnimSetIndex        = GBAIsometric_Spyro_ObjInit.ConvertAnimSetIndex(Context.Settings.GameModeSelection, 0x8A);
                        obj.AnimationGroupIndex = 0x02;
                        break;

                    case 3:
                        obj.AnimSetIndex        = GBAIsometric_Spyro_ObjInit.ConvertAnimSetIndex(Context.Settings.GameModeSelection, 0x84);
                        obj.AnimationGroupIndex = 0x0B;
                        break;

                    case 4:
                        obj.AnimSetIndex        = GBAIsometric_Spyro_ObjInit.ConvertAnimSetIndex(Context.Settings.GameModeSelection, 0x82);
                        obj.AnimationGroupIndex = 0x01;
                        break;

                    // No graphics
                    case 5:         // Exit
                    case 6:
                    case 10:
                    case 12:
                        obj.IsEditorObj  = true;
                        obj.AnimSetIndex = -1;
                        break;

                    // Mine
                    case 7:
                        obj.AnimSetIndex        = GBAIsometric_Spyro_ObjInit.ConvertAnimSetIndex(Context.Settings.GameModeSelection, 0x8E);
                        obj.AnimationGroupIndex = 0x00;
                        break;

                    // Floating platforms
                    case 8:
                        obj.AnimSetIndex        = GBAIsometric_Spyro_ObjInit.ConvertAnimSetIndex(Context.Settings.GameModeSelection, 0x90);
                        obj.AnimationGroupIndex = 0x02;
                        break;

                    case 9:
                        obj.AnimSetIndex        = GBAIsometric_Spyro_ObjInit.ConvertAnimSetIndex(Context.Settings.GameModeSelection, 0x90);
                        obj.AnimationGroupIndex = 0x00;
                        break;

                    // Checkpoint fairy
                    case 11:
                        obj.AnimSetIndex        = GBAIsometric_Spyro_ObjInit.ConvertAnimSetIndex(Context.Settings.GameModeSelection, 0x88);
                        obj.AnimationGroupIndex = 0x00;
                        break;

                    // Agent 9
                    case 13:
                        obj.AnimSetIndex        = GBAIsometric_Spyro_ObjInit.ConvertAnimSetIndex(Context.Settings.GameModeSelection, 0x80);
                        obj.AnimationGroupIndex = 0x08;
                        break;

                    // Firefly
                    case 14:
                        obj.AnimSetIndex        = GBAIsometric_Spyro_ObjInit.ConvertAnimSetIndex(Context.Settings.GameModeSelection, 0x7C);
                        obj.AnimationGroupIndex = 0x03;
                        break;

                    // Sign
                    case 15:
                        obj.AnimSetIndex        = GBAIsometric_Spyro_ObjInit.ConvertAnimSetIndex(Context.Settings.GameModeSelection, 0x96);
                        obj.AnimationGroupIndex = 0x00;
                        break;

                    default:
                        obj.AnimSetIndex = -1;
                        break;
                    }
                    break;

                case GBAIsometric_Spyro2_Object2D.ObjCategory.Collectible:
                    switch (obj.Object.ObjType)
                    {
                    // Gem
                    case 0:         // Red
                        obj.AnimSetIndex        = GBAIsometric_Spyro_ObjInit.ConvertAnimSetIndex(Context.Settings.GameModeSelection, 0x89);
                        obj.AnimationGroupIndex = 0x03;
                        break;

                    case 1:         // Diamond
                        obj.AnimSetIndex        = GBAIsometric_Spyro_ObjInit.ConvertAnimSetIndex(Context.Settings.GameModeSelection, 0x89);
                        obj.AnimationGroupIndex = 0x00;
                        break;

                    case 2:         // Gold
                        obj.AnimSetIndex        = GBAIsometric_Spyro_ObjInit.ConvertAnimSetIndex(Context.Settings.GameModeSelection, 0x89);
                        obj.AnimationGroupIndex = 0x05;
                        break;

                    case 3:         // Green
                        obj.AnimSetIndex        = GBAIsometric_Spyro_ObjInit.ConvertAnimSetIndex(Context.Settings.GameModeSelection, 0x89);
                        obj.AnimationGroupIndex = 0x01;
                        break;

                    case 4:         // Purple
                        obj.AnimSetIndex        = GBAIsometric_Spyro_ObjInit.ConvertAnimSetIndex(Context.Settings.GameModeSelection, 0x89);
                        obj.AnimationGroupIndex = 0x02;
                        break;

                    // Gem container
                    case 16:
                    case 17:
                    case 18:
                    case 19:
                    case 20:
                        obj.AnimSetIndex        = GBAIsometric_Spyro_ObjInit.ConvertAnimSetIndex(Context.Settings.GameModeSelection, 0x7E);
                        obj.AnimationGroupIndex = 0x05;
                        break;

                    case 32:
                    case 33:
                    case 34:
                    case 35:
                    case 36:
                        obj.AnimSetIndex        = GBAIsometric_Spyro_ObjInit.ConvertAnimSetIndex(Context.Settings.GameModeSelection, 0x7A);
                        obj.AnimationGroupIndex = 0x04;
                        break;

                    default:
                        obj.AnimSetIndex = -1;
                        break;
                    }
                    break;

                default:
                    obj.AnimSetIndex = -1;
                    break;
                }

                if (obj.AnimSetIndex == -1 && !obj.IsEditorObj)
                {
                    Debug.LogWarning($"Type {obj.Object.ObjType} with category {obj.Object.Category} has no graphics");
                }
            }
        }
Пример #11
0
        public override void InitObjects(Unity_Level level)
        {
            // Hard-code event animations for the different Rayman types
            Unity_ObjGraphics rayDes = null;

            var rayEvent = (Unity_Object_R1)level.Rayman ?? level.EventData.Cast <Unity_Object_R1>().FirstOrDefault(x => x.EventData.Type == R1_EventType.TYPE_RAY_POS);

            if (rayEvent != null)
            {
                rayDes = DES.ElementAtOrDefault(rayEvent.DESIndex)?.Data.Graphics;
            }

            if (rayDes == null)
            {
                return;
            }

            var miniRay         = level.EventData.Cast <Unity_Object_R1>().FirstOrDefault(x => x.EventData.Type == R1_EventType.TYPE_DEMI_RAYMAN);
            var miniRayDESIndex = miniRay?.DESIndex;

            if (miniRayDESIndex == null && EventTemplates.ContainsKey(WldObjType.RayLittle))
            {
                miniRayDESIndex = UsesPointers ? DESLookup.TryGetItem(EventTemplates[WldObjType.RayLittle].ImageDescriptorsPointer?.AbsoluteOffset ?? 0, -1) : (int)EventTemplates[WldObjType.RayLittle].PC_ImageDescriptorsIndex;
            }

            if (miniRayDESIndex != null)
            {
                var miniRayDes = DES.ElementAtOrDefault(miniRayDESIndex.Value)?.Data.Graphics;

                if (miniRayDes != null)
                {
                    miniRayDes.Animations = rayDes.Animations.Select(anim =>
                    {
                        var newAnim = new Unity_ObjAnimation
                        {
                            Frames = anim.Frames.Select(x => new Unity_ObjAnimationFrame(x.SpriteLayers.Select(l => new Unity_ObjAnimationPart()
                            {
                                ImageIndex            = l.ImageIndex,
                                XPosition             = l.XPosition / 2,
                                YPosition             = l.YPosition / 2,
                                IsFlippedHorizontally = l.IsFlippedHorizontally,
                                IsFlippedVertically   = l.IsFlippedVertically,
                            }).ToArray())).ToArray()
                        };

                        return(newAnim);
                    }).ToList();
                }
            }

            var badRay = level.EventData.Cast <Unity_Object_R1>().FirstOrDefault(x => x.EventData.Type == R1_EventType.TYPE_BLACK_RAY);

            if (badRay != null)
            {
                var badRayDes = DES.ElementAtOrDefault(badRay.DESIndex)?.Data.Graphics;

                if (badRayDes != null)
                {
                    badRayDes.Animations = rayDes.Animations;
                }
            }

            // Set frames for linked events
            for (int i = 0; i < level.EventData.Count; i++)
            {
                // Recreated from allocateOtherPosts
                var baseEvent   = (Unity_Object_R1)level.EventData[i];
                var linkedIndex = LinkTable[i];

                if (baseEvent.EventData.Type.UsesRandomFrameLinks() && i != linkedIndex)
                {
                    var index = 0;

                    do
                    {
                        index++;

                        var e = (Unity_Object_R1)level.EventData[linkedIndex];
                        e.ForceFrame = (byte)((baseEvent.ForceFrame + index) % (e.CurrentAnimation?.Frames.Length ?? 1));
                        e.XPosition  = (short)(baseEvent.EventData.XPosition + 32 * index * (baseEvent.EventData.HitPoints - 2));
                        e.YPosition  = baseEvent.YPosition;

                        linkedIndex = LinkTable[linkedIndex];
                    } while (i != linkedIndex);
                }
            }

            // Set DES and ETA for worldmap
            if (Context.Settings.R1_World == R1_World.Menu)
            {
                var mapObj = EventTemplates[WldObjType.MapObj];
                var rayman = level.Rayman as Unity_Object_R1;

                // Change Rayman to small Rayman
                if (miniRayDESIndex != null && rayman != null)
                {
                    rayman.DESIndex           = miniRayDESIndex.Value;
                    rayman.EventData.OffsetBX = (byte)(rayman.EventData.OffsetBX / 2);
                    rayman.EventData.OffsetBY = (byte)(rayman.EventData.OffsetBY / 2);
                }

                // Set Rayman's properties
                if (rayman != null)
                {
                    rayman.EventData.Etat    = rayman.EventData.InitialEtat = 0;
                    rayman.EventData.SubEtat = rayman.EventData.InitialSubEtat = 0;

                    if (Context.Settings.EngineVersion == EngineVersion.R1_PC_Kit)
                    {
                        // ?
                        rayman.XPosition = (short)(level.EventData[0].XPosition + 42 - rayman.EventData.OffsetBX);
                        rayman.YPosition = (short)(level.EventData[0].YPosition + 48 - rayman.EventData.OffsetBY);
                    }
                    else if (Context.Settings.EngineVersion == EngineVersion.R1_PC_Edu || Context.Settings.EngineVersion == EngineVersion.R1_PS1_Edu)
                    {
                        // ?
                        rayman.XPosition           = (short)(level.EventData[0].XPosition + 42 + 44 - rayman.EventData.OffsetBX);
                        rayman.YPosition           = (short)(level.EventData[0].YPosition + 48 + 24 - rayman.EventData.OffsetBY);
                        rayman.EventData.PC_Flags |= R1_EventData.PC_EventFlags.IsFlipped;
                    }
                    else
                    {
                        rayman.XPosition = (short)(level.EventData[0].XPosition + 70 - rayman.EventData.OffsetBX + 9); // The game does +4 instead of 9 - why?
                        rayman.YPosition = (short)(level.EventData[0].YPosition + 64 - rayman.EventData.OffsetBY + 8); // Is this correct?
                    }
                }

                foreach (var e in level.EventData.Cast <Unity_Object_R1>().Select(x => x.EventData))
                {
                    e.ImageDescriptorsPointer = mapObj.ImageDescriptorsPointer;
                    e.ImageBufferPointer      = mapObj.ImageBufferPointer;
                    e.AnimDescriptorsPointer  = mapObj.AnimDescriptorsPointer;
                    e.ETAPointer = mapObj.ETAPointer;

                    e.PC_ImageDescriptorsIndex     = mapObj.PC_ImageDescriptorsIndex;
                    e.PC_ImageBufferIndex          = mapObj.PC_ImageBufferIndex;
                    e.PC_AnimationDescriptorsIndex = mapObj.PC_AnimationDescriptorsIndex;
                    e.PC_ETAIndex = mapObj.PC_ETAIndex;
                }
            }
        }
        public override void InitObjects(Unity_Level level)
        {
            var         objects   = level.EventData.Cast <Unity_Object_BaseGBAVVIsometric>().ToArray();
            float       minHeight = Mathf.Min(0, MapData.CollisionMap.Min(c => MapData.CollisionTiles[c].Height.AsFloat));
            const float scale     = 64f / 12;

            for (int i = 0; i < objects.Length; i++)
            {
                var obj = objects[i];

                obj.UpdateAnimIndex();

                if (obj is Unity_Object_GBAVVIsometric_TargetObjTarget)
                {
                    continue;
                }

                float yScaled = obj.YPos * scale;
                float xScaled = obj.XPos * scale;
                var   collY   = Mathf.FloorToInt(yScaled);
                var   collX   = Mathf.FloorToInt(xScaled);

                /*var collY = (((long)obj.YPos.Value) * 0x15555556) >> 0x2a;
                *  var collX = (((long)obj.XPos.Value) * 0x15555556) >> 0x2a;*/
                var tile = MapData.CollisionTiles[MapData.CollisionMap[collY * MapData.CollisionWidth + collX]];
                obj.Height = (tile.Height - minHeight) / scale;

                int baseType = (int)Unity_IsometricCollisionTile.CollisionType.GBAVV_Solid_0;
                var type     = (Unity_IsometricCollisionTile.CollisionType)(baseType + GetCommonCollisionTypeFunc(tile.TypeIndex));

                switch (type)
                {
                case Unity_IsometricCollisionTile.CollisionType.GBAVV_Corner_12:
                case Unity_IsometricCollisionTile.CollisionType.GBAVV_Corner_17:
                case Unity_IsometricCollisionTile.CollisionType.GBAVV_Corner_19:
                case Unity_IsometricCollisionTile.CollisionType.GBAVV_Corner_21:
                case Unity_IsometricCollisionTile.CollisionType.GBAVV_Corner_22:
                case Unity_IsometricCollisionTile.CollisionType.GBAVV_Corner_24:
                case Unity_IsometricCollisionTile.CollisionType.GBAVV_Corner_26:
                case Unity_IsometricCollisionTile.CollisionType.GBAVV_Corner_28:
                case Unity_IsometricCollisionTile.CollisionType.GBAVV_Corner_32:
                case Unity_IsometricCollisionTile.CollisionType.GBAVV_Corner_35:
                    // Diagonal
                    bool isHigh = false;
                    switch (tile.Shape % 4)
                    {
                    case 0:         // bottom is higher (high x & y)
                        isHigh = (yScaled - collY) + (xScaled - collX) >= 1f;
                        break;

                    case 1:         // left is higher (high y, low x)
                        isHigh = (yScaled - collY) + (1f - (xScaled - collX)) >= 1f;
                        break;

                    case 2:         // top is higher (low x & y)
                        isHigh = (1f - (yScaled - collY)) + (1f - (xScaled - collX)) >= 1f;
                        break;

                    case 3:         // right is higher (low y, high x)
                        isHigh = (1f - (yScaled - collY)) + (xScaled - collX) >= 1f;
                        break;
                    }
                    if (isHigh)
                    {
                        obj.Height += MapData.CollisionTypes[tile.TypeIndex].AdditionalHeight / scale;
                    }
                    break;

                case Unity_IsometricCollisionTile.CollisionType.GBAVV_Ramp_1:
                    // Ramp
                    float x          = (xScaled - collX);
                    float y          = (yScaled - collY);
                    float rampHeight = 0.1875f;
                    switch (tile.Shape % 4)
                    {
                    case 0:         // down left is higher (high y)
                        obj.Height += (1 - Mathf.Sqrt(1 - y * y)) * rampHeight / scale;
                        break;

                    case 1:         // up left is higher (low x)
                        obj.Height += (1 - Mathf.Sqrt(1 - (1 - x) * (1 - x))) * rampHeight / scale;
                        break;

                    case 2:         // up right is higher (low y)
                        obj.Height += (1 - Mathf.Sqrt(1 - (1 - y) * (1 - y))) * rampHeight / scale;
                        break;

                    case 3:         // down right is higher (high x)
                        obj.Height += (1 - Mathf.Sqrt(1 - x * x)) * rampHeight / scale;
                        break;
                    }
                    break;

                default:
                    break;
                }

                if (obj is Unity_Object_GBAVVIsometric_TargetObj t)
                {
                    objects[t.LinkIndex].Height = t.Height;
                }

                if (i == 0 || !(obj is Unity_Object_GBAVVIsometric_Obj))
                {
                    continue;
                }

                var prevObjIndex = i - 1;
                var prevObj      = objects[prevObjIndex];

                if (obj.XPos.Value == prevObj.XPos.Value && obj.YPos.Value == prevObj.YPos.Value)
                {
                    while (true)
                    {
                        obj.XPos.Value += 0x100;
                        obj.YPos.Value += 0x100;
                        obj.Height     += ((0x1000 / (float)(1 << 16))) / scale;

                        if (prevObj.XPos.Value != objects[prevObjIndex - 1].XPos.Value || prevObj.YPos.Value != objects[prevObjIndex - 1].YPos.Value)
                        {
                            break;
                        }

                        prevObjIndex--;
                        prevObj = objects[prevObjIndex];
                    }
                }
            }

            //foreach (Unity_Object_BaseGBAVVIsometric obj in objects)
            //{
            //    obj.XPos.Value += obj.GraphicsData?.CrashAnim?.XPos?.Value / 2 ?? 0;
            //    obj.YPos.Value += obj.GraphicsData?.CrashAnim?.YPos?.Value / 2 ?? 0;
            //}
        }