Example #1
0
        //private static Dictionary<string, int> dungeonIdx = new Dictionary<string, int>()
        //{
        //    { "deceit", 0 },
        //    { "despise", 1 },
        //    { "destard", 2 },
        //    { "wrong", 3 },
        //    { "covetous", 4 },
        //    { "shame", 5 },
        //    { "hythloth", 6 },
        //    { "abyss", 7 }
        //};

        public void Load(string path, UltimaData data, Flags flags)
        {
            var files = Directory.GetFiles(path, "*.DNG");

            foreach (var file in files)
            {
                if (!file.Contains("CAMP.DNG"))
                {
                    FileHelper.TryBackupOriginalFile(file, false);

                    if (flags.FixHythloth && file.Contains("HYTHLOTH"))
                    {
                        using (var deltaStream = new MemoryStream(Patches.HYTHLOTH))
                        {
                            Dungeon dungeon = new Dungeon(deltaStream, data);

                            dungeons.Add(Path.GetFileNameWithoutExtension(file), dungeon);
                        }

                        SpoilerLog.Add(SpoilerCategory.Fix, "Hythloth lvl 6 fixed.");
                    }
                    else
                    {
                        using (var dngStream = new System.IO.FileStream($"{file}.orig", System.IO.FileMode.Open))
                        {
                            Dungeon dungeon = new Dungeon(dngStream, data);

                            dungeons.Add(Path.GetFileNameWithoutExtension(file), dungeon);
                        }
                    }
                }
            }
        }
Example #2
0
        public override void Randomize(UltimaData ultimaData, Random random1, Random random2)
        {
            SpoilerLog.Add(SpoilerCategory.Location, "Locations unchanged");

            // Used to output abyss shape
            //int xSize = 32 + 10 - 2;
            //int ySize = 64 + 17 - 1;

            //int xOffset = 256 - xSize - 2;
            //int yOffset = 256 - ySize - 1;

            //using (var worldFile = new System.IO.BinaryWriter(new System.IO.FileStream("abyssnew", System.IO.FileMode.OpenOrCreate)))
            //{
            //    Console.Write(xSize);
            //    Console.Write(ySize);
            //    for (int y = 0; y < ySize; y++)
            //    {
            //        for (int x = 0; x < xSize; x++)
            //        {
            //            _worldMapTiles[x, y] = _worldMapTiles[x + xOffset, y + yOffset];
            //            worldFile.Write(_worldMapTiles[x, y]);
            //            Console.Write(_worldMapTiles[x, y]);
            //        }
            //        Console.WriteLine();
            //    }
            //}

            return;
        }
Example #3
0
        public Dungeon(Stream dngStream, UltimaData data)
        {
            BinaryReader readBinary = new BinaryReader(dngStream);

            // Load each level
            for (int l = 0; l < 8; l++)
            {
                byte[] levelArr = new byte[8 * 8];
                readBinary.Read(levelArr, 0, 8 * 8);

                for (int i = 0; i < levelArr.Length; i++)
                {
                    map[l, i / 8, i % 8] = levelArr[i];
                }
            }

            // Load each room
            byte[] roomArr = new byte[256];
            while (readBinary.Read(roomArr, 0, 256) == 256)
            {
                byte[] roomClone = new byte[256];
                roomArr.CopyTo(roomClone, 0);
                rooms.Add(roomClone);
            }
        }
Example #4
0
 public void Update(UltimaData ultimaData, Flags flags)
 {
     if (flags.Fixes)
     {
         towns["SERPENT"].npcConversationIdx[28] = 02;
         towns["SERPENT"].npcConversationIdx[29] = 02;
         SpoilerLog.Add(SpoilerCategory.Fix, $"Serpent's Hold gate guard fix");
     }
 }
Example #5
0
        //public Dictionary<string, string> ReadHashes()
        //{
        //    var file = Path.Combine("hashes", "title_hash.json");
        //    var hashJson = System.IO.File.ReadAllText(file);

        //    var hashes = JsonConvert.DeserializeObject<Dictionary<string, string>>(hashJson);

        //    return hashes;
        //}

        //public void WriteHashes(string path)
        //{
        //    var file = Path.Combine(path, filename);

        //    var townTalkHash = new Dictionary<string, string>();

        //    var hash = HashHelper.GetHashSha256(file);
        //    Console.WriteLine($"{file}: {HashHelper.BytesToString(hash)}");
        //    townTalkHash.Add(Path.GetFileName(file), HashHelper.BytesToString(hash));

        //    string json = JsonConvert.SerializeObject(townTalkHash); // the dictionary is inside client object
        //                                                             //write string to file
        //    System.IO.File.WriteAllText(@"party_hash.json", json);
        //}

        public void Update(UltimaData data)
        {
            for (int i = 0; i < data.StartingCharacters.Count; i++)
            {
                var character = data.StartingCharacters[i];
                partyBytes.OverwriteBytes(character.Hp, CHARACTER_RECORDS_OFFSET + (i * CHAR_RECORD_LENGTH) + CHARACTER_HP_OFFSET);
                partyBytes.OverwriteBytes(character.MaxHp, CHARACTER_RECORDS_OFFSET + (i * CHAR_RECORD_LENGTH) + CHARACTER_MAX_HP_OFFSET);
                partyBytes.OverwriteBytes(character.XP, CHARACTER_RECORDS_OFFSET + (i * CHAR_RECORD_LENGTH) + CHARACTER_XP_OFFSET);
                partyBytes.OverwriteBytes(character.Str, CHARACTER_RECORDS_OFFSET + (i * CHAR_RECORD_LENGTH) + CHARACTER_STR_OFFSET);
                partyBytes.OverwriteBytes(character.Dex, CHARACTER_RECORDS_OFFSET + (i * CHAR_RECORD_LENGTH) + CHARACTER_DEX_OFFSET);
                partyBytes.OverwriteBytes(character.Int, CHARACTER_RECORDS_OFFSET + (i * CHAR_RECORD_LENGTH) + CHARACTER_INT_OFFSET);
                partyBytes.OverwriteBytes(character.Mp, CHARACTER_RECORDS_OFFSET + (i * CHAR_RECORD_LENGTH) + CHARACTER_MP_OFFSET);
                partyBytes.OverwriteBytes(character.Weapon, CHARACTER_RECORDS_OFFSET + (i * CHAR_RECORD_LENGTH) + CHARACTER_WEAPON_OFFSET);
                partyBytes.OverwriteBytes(character.Armor, CHARACTER_RECORDS_OFFSET + (i * CHAR_RECORD_LENGTH) + CHARACTER_ARMOR_OFFSET);

                var textBytes = Encoding.ASCII.GetBytes(character.Name);
                if (textBytes.Length > 16)
                {
                    throw new Exception($"Part name {character.Name} is too long.");
                }
                int j;
                for (j = 0; j < textBytes.Length; j++)
                {
                    partyBytes[CHARACTER_RECORDS_OFFSET + (i * CHAR_RECORD_LENGTH) + CHARACTER_NAME_OFFSET + j] = textBytes[j];
                }
                partyBytes[CHARACTER_RECORDS_OFFSET + (i * CHAR_RECORD_LENGTH) + CHARACTER_NAME_OFFSET + j] = 0x00;

                partyBytes[CHARACTER_RECORDS_OFFSET + (i * CHAR_RECORD_LENGTH) + CHARACTER_SEX_OFFSET] = (character.Sex == 'M' ? (byte)0xb : (byte)0xc);

                partyBytes[CHARACTER_RECORDS_OFFSET + (i * CHAR_RECORD_LENGTH) + CHARACTER_CLASS_OFFSET]  = character.Class;
                partyBytes[CHARACTER_RECORDS_OFFSET + (i * CHAR_RECORD_LENGTH) + CHARACTER_STATUS_OFFSET] = (byte)character.Status;
            }

            var foodBytes = BitConverter.GetBytes(data.StartingFood);

            for (int offset = 0; offset < foodBytes.Length; offset++)
            {
                partyBytes[FOOD_OFFSET + offset] = foodBytes[offset];
            }

            partyBytes.OverwriteBytes(data.StartingGold, GOLD_OFFSET);
            partyBytes.OverwriteBytes(data.StartingItems, ITEMS1_OFFSET);

            partyBytes.OverwriteBytes(data.StartingEquipment, EQUIPMENT_OFFSET);
            partyBytes.OverwriteBytes(data.StartingArmor, ARMOR_OFFSET);
            partyBytes.OverwriteBytes(data.StartingWeapons, WEAPONS_OFFSET);
            partyBytes.OverwriteBytes(data.StartingReagents, REAGENTS_OFFSET);
            partyBytes.OverwriteBytes(data.StartingMixtures, MIXTURES_OFFSET);

            partyBytes[STONES_OFFSET] = data.StartingStones;
            partyBytes[RUNES_OFFSET]  = data.StartingRunes;
        }
Example #6
0
        public void Load(string path, UltimaData data)
        {
            var files = Directory.GetFiles(path, "*.ULT");

            foreach (var file in files)
            {
                FileHelper.TryBackupOriginalFile(file, false);

                using (var twnStream = new System.IO.FileStream($"{file}.orig", System.IO.FileMode.Open))
                {
                    Town town = new Town(twnStream, data);

                    towns.Add(Path.GetFileNameWithoutExtension(file), town);
                }
            }
        }
Example #7
0
        //public Dictionary<string, string> ReadHashes()
        //{
        //    var file = Path.Combine("hashes", "title_hash.json");
        //    var hashJson = System.IO.File.ReadAllText(file);

        //    var hashes = JsonConvert.DeserializeObject<Dictionary<string, string>>(hashJson);

        //    return hashes;
        //}

        //public void WriteHashes(string path)
        //{
        //    var file = Path.Combine(path, filename);

        //    var townTalkHash = new Dictionary<string, string>();

        //    var hash = HashHelper.GetHashSha256(file);
        //    Console.WriteLine($"{file}: {HashHelper.BytesToString(hash)}");
        //    townTalkHash.Add(Path.GetFileName(file), HashHelper.BytesToString(hash));

        //    string json = JsonConvert.SerializeObject(townTalkHash); // the dictionary is inside client object
        //                                                             //write string to file
        //    System.IO.File.WriteAllText(@"title_hash.json", json);
        //}

        public void Update(UltimaData data, Flags flags, string encode)
        {
            for (int offset = 0; offset < 8; offset++)
            {
                titleBytes[START_X_OFFSET + offset] = data.StartingPositions[offset].X;
                titleBytes[START_Y_OFFSET + offset] = data.StartingPositions[offset].Y;
            }

            titleBytes[ENABLE_KARMA_OVERRIDE_OFFSET] = flags.KarmaSetPercentage > 0 ? (byte)0x0 : (byte)0x9;

            for (int offset = 0; offset < 8; offset++)
            {
                titleBytes[KARMA_OVERRIDE_VALUES_OFFSET + offset] = (data.StartingKarma[offset] == 100 ? (byte)0 : data.StartingKarma[offset]);
            }

            var encodeBytes = Encoding.ASCII.GetBytes(encode);

            for (int i = 0; i < encodeBytes.Length; i++)
            {
                titleBytes[FLAG_ENCODE_OFFSET + i] = encodeBytes[i];
            }
        }
Example #8
0
        public Town(FileStream twnStream, UltimaData data)
        {
            BinaryReader readBinary = new BinaryReader(twnStream);

            byte[] mapArr = new byte[32 * 32];
            readBinary.Read(mapArr, 0, 32 * 32);
            for (int i = 0; i < 32 * 32; i++)
            {
                map[i / 32, i % 32] = mapArr[i];
            }

            readBinary.Read(npcTileIdx, 0, 32);
            readBinary.Read(npcStartX, 0, 32);
            readBinary.Read(npcStartY, 0, 32);

            //Unused entries
            readBinary.Read(npcOldX, 0, 32);
            readBinary.Read(npcOldY, 0, 32);
            readBinary.Read(npcAggressivity, 0, 32);

            readBinary.Read(npcMovement, 0, 32);
            readBinary.Read(npcConversationIdx, 0, 32);
        }
Example #9
0
 public Image ToClothMap(UltimaData data, Random random)
 {
     using (Image <Rgba32> deep_water = Image.Load <Rgba32>("E:\\Projects\\U4DosRandomizer\\Assets\\deep_water.png"))
     {
         using (Image <Rgba32> grass = Image.Load <Rgba32>("E:\\Projects\\U4DosRandomizer\\Assets\\grass.png"))
         {
             var image = new Image <Rgba32>(WorldMapGenerateMap.SIZE * 4, WorldMapGenerateMap.SIZE * 4);
             for (int y = 0; y < WorldMapGenerateMap.SIZE * 4; y++)
             {
                 Span <Rgba32> deepWaterRowSpan = deep_water.GetPixelRowSpan(y);
                 Span <Rgba32> grassRowSpan     = grass.GetPixelRowSpan(y);
                 Span <Rgba32> pixelRowSpan     = image.GetPixelRowSpan(y);
                 for (int x = 0; x < WorldMapGenerateMap.SIZE * 4; x++)
                 {
                     //if (colorMap.ContainsKey(_worldMapTiles[x, y]))
                     //{
                     //    pixelRowSpan[x] = colorMap[_worldMapTiles[x, y]];
                     //}
                     //else
                     //{
                     //    pixelRowSpan[x] = SixLabors.ImageSharp.Color.White;
                     //}
                     if (_worldMapTiles[x / 4, y / 4] == TileInfo.Deep_Water)
                     {
                         pixelRowSpan[x] = deepWaterRowSpan[x];
                     }
                     else
                     {
                         pixelRowSpan[x] = grassRowSpan[x];
                     }
                 }
             }
             return(image);
         }
     }
 }
Example #10
0
 public Region FindNearestRegion(ICoordinate targetTile, UltimaData data, out IList <ITile> outPath)
 {
     outPath = null;
     return(null);
 }
Example #11
0
 public abstract void Randomize(UltimaData ultimaData, Random random1, Random random2);
Example #12
0
 public abstract void Load(string path, int v, int mapGeneratorSeed, int otherRandomSeed, UltimaData ultimaData);
        public override void Randomize(UltimaData ultimaData, Random random1, Random random2)
        {
            var swapPool = new List <Tuple <TileDirtyWrapper, ICoordinate, int> >();

            for (int i = 0; i < ultimaData.Castles.Count; i++)
            {
                //SpoilerLog.Add(SpoilerCategory.Location, $"{ultimaData.Castles[i].Y:X2}");
                swapPool.Add(new Tuple <TileDirtyWrapper, ICoordinate, int>(ultimaData.Castles[i].Copy(this), ultimaData.AbyssEjectionLocations[8 + i], ultimaData.LOC_LYCAEUM + i));
            }

            for (int i = 0; i < ultimaData.Towns.Count; i++)
            {
                //SpoilerLog.Add(SpoilerCategory.Location, $"{ultimaData.Towns[i].Y:X2}");
                if (i != 9 && i != 11)
                {
                    ICoordinate startingPosition = null;
                    if (i < 8)
                    {
                        startingPosition = ultimaData.StartingPositions[i];
                    }
                    else
                    {
                        // No starting positions for villages. Make one.
                        var validPositions = GetPathableTilesNear(ultimaData.Towns[i], 3, IsWalkable);
                        startingPosition = validPositions[random1.Next(0, validPositions.Count)];
                    }
                    swapPool.Add(new Tuple <TileDirtyWrapper, ICoordinate, int>(ultimaData.Towns[i].Copy(this), startingPosition, ultimaData.LOC_TOWNS + i));
                }
            }

            //for (int i = 0; i < swapPool.Count; i++)
            //{
            //    SpoilerLog.Add(SpoilerCategory.Location, $"{swapPool[i].Item1.Y:X2}");
            //}

            for (int i = 0; i < swapPool.Count; i++)
            {
                var val = random1.Next(0, (swapPool.Count - 1) - i);
                Swap(swapPool, val, (swapPool.Count - 1) - i);
            }

            for (int i = 0; i < swapPool.Count; i++)
            {
                if (i < ultimaData.Castles.Count)
                {
                    ultimaData.Castles[i].X = swapPool[i].Item1.X;
                    ultimaData.Castles[i].Y = swapPool[i].Item1.Y;
                    ultimaData.Castles[i].SetTile(0x0B);
                    ultimaData.AbyssEjectionLocations[8 + i].X = swapPool[i].Item2.X;
                    ultimaData.AbyssEjectionLocations[8 + i].Y = swapPool[i].Item2.Y;

                    SpoilerLog.Add(SpoilerCategory.Location, $"{ultimaData.LocationNames[i + ultimaData.LOC_LYCAEUM - 1]} moved to {ultimaData.LocationNames[swapPool[i].Item3-1]}");
                }
                else
                {
                    int townIdx = i - 3;
                    if (i >= 12)
                    {
                        townIdx++;
                    }
                    if (i >= 13)
                    {
                        townIdx++;
                    }
                    byte tile = (byte)(townIdx > 8 ? 0x0C : 0x0A);
                    if (townIdx == 7)
                    {
                        tile = 0x1D;
                    }
                    ultimaData.Towns[townIdx].X = swapPool[i].Item1.X;
                    ultimaData.Towns[townIdx].Y = swapPool[i].Item1.Y;
                    ultimaData.Towns[townIdx].SetTile(tile);
                    if (townIdx < 8)
                    {
                        ultimaData.AbyssEjectionLocations[i].X  = swapPool[i].Item2.X;
                        ultimaData.AbyssEjectionLocations[i].Y  = swapPool[i].Item2.Y;
                        ultimaData.StartingPositions[townIdx].X = swapPool[i].Item2.X;
                        ultimaData.StartingPositions[townIdx].Y = swapPool[i].Item2.Y;
                    }
                    SpoilerLog.Add(SpoilerCategory.Location, $"{ultimaData.LocationNames[townIdx + ultimaData.LOC_TOWNS - 1]} moved to {ultimaData.LocationNames[swapPool[i].Item3-1]}");
                }
            }

            // Shrines
            // Don't move humility
            var swapValues = new List <int>();

            for (int i = 0; i < ultimaData.Shrines.Count; i++)
            {
                swapValues.Add(i);
            }

            for (int i = 0; i < ultimaData.Shrines.Count - 1; i++)
            {
                var val = random1.Next(0, (ultimaData.Shrines.Count - 2) - i);
                Swap(ultimaData.Shrines, val, (ultimaData.Shrines.Count - 2) - i);
                Swap(swapValues, val, (ultimaData.Shrines.Count - 2) - i);
            }

            for (int i = 0; i < ultimaData.Shrines.Count; i++)
            {
                SpoilerLog.Add(SpoilerCategory.Location, $"{ultimaData.LocationNames[i + ultimaData.LOC_SHRINES - 1]} shrine moved to {ultimaData.LocationNames[swapValues[i] + ultimaData.LOC_SHRINES - 1]}");
            }

            // Moongates
            swapValues = new List <int>();
            var originalNewMoonX = ultimaData.Moongates[0].X;
            var originalNewMoonY = ultimaData.Moongates[0].Y;

            for (int i = 0; i < ultimaData.Moongates.Count; i++)
            {
                swapValues.Add(i);
            }
            for (int i = 0; i < ultimaData.Moongates.Count; i++)
            {
                var val = random1.Next(0, (ultimaData.Moongates.Count - 1) - i);
                Swap(ultimaData.Moongates, val, (ultimaData.Moongates.Count - 1) - i);
                Swap(swapValues, val, (ultimaData.Moongates.Count - 1) - i);
            }
            for (int i = 0; i < ultimaData.Shrines.Count; i++)
            {
                SpoilerLog.Add(SpoilerCategory.Location, $"{ultimaData.LocationNames[i + ultimaData.LOC_TOWNS - 1]} moongate moved to {ultimaData.LocationNames[swapValues[i] + ultimaData.LOC_TOWNS - 1]}");
            }

            // Dungeons
            // Don't move Abyss
            swapValues = new List <int>();
            for (int i = 0; i < ultimaData.Dungeons.Count; i++)
            {
                swapValues.Add(i);
            }
            for (int i = 0; i < ultimaData.Dungeons.Count - 1; i++)
            {
                var val = random1.Next(0, (ultimaData.Dungeons.Count - 2) - i);
                Swap(ultimaData.Dungeons, val, (ultimaData.Dungeons.Count - 2) - i);
                Swap(swapValues, val, (ultimaData.Dungeons.Count - 2) - i);
            }
            for (int i = 0; i < ultimaData.Dungeons.Count; i++)
            {
                SpoilerLog.Add(SpoilerCategory.Location, $"{ultimaData.LocationNames[i + ultimaData.LOC_DUNGEONS - 1]} moved to {ultimaData.LocationNames[swapValues[i] + ultimaData.LOC_DUNGEONS - 1]}");
            }

            // Items
            swapValues = new List <int>();
            for (int i = 0; i < 10; i++)
            {
                swapValues.Add(i);
            }
            for (int i = 0; i < 10; i++)
            {
                var val = random1.Next(0, (10 - 1) - i);
                Swap(ultimaData.Items, val, (10 - 1) - i);
                Swap(swapValues, val, (10 - 1) - i);
            }
            for (int i = 0; i < 10; i++)
            {
                SpoilerLog.Add(SpoilerCategory.Location, $"{ultimaData.ItemNames[i]} moved to {ultimaData.ItemNames[swapValues[i]]}");
            }

            //Whatever is now at the original new moon moongate location gets moved to whereever the new moongate is now
            var item = ultimaData.Items.Single(x => x.X == originalNewMoonX && x.Y == originalNewMoonY && x.Location == 0x00);

            item.X = ultimaData.Moongates[0].X;
            item.Y = ultimaData.Moongates[0].Y;

            return;
        }
        public override void Load(string path, int mapSeed, int mapGeneratorSeed, int otherRandomSeed, UltimaData ultimaData)
        {
            var file = Path.Combine(path, filename);

            FileHelper.TryBackupOriginalFile(file);

            _worldMapTiles = new byte[SIZE, SIZE];

            int chunkwidth = 32;
            int chunkSize  = chunkwidth * chunkwidth;

            byte[] chunk; // = new byte[chunkSize];
            using (var worldMap = new System.IO.BinaryReader(new System.IO.FileStream($"{file}.orig", System.IO.FileMode.Open)))
            {
                for (int chunkCount = 0; chunkCount < 64; chunkCount++)
                {
                    chunk = worldMap.ReadBytes(chunkSize);

                    // Copy the chunk over
                    for (int i = 0; i < chunkSize; i++)
                    {
                        _worldMapTiles[i % chunkwidth + chunkCount % 8 * chunkwidth, i / chunkwidth + chunkCount / 8 * chunkwidth] = chunk[i];
                    }
                }
            }

            //RemoveAvatarIsle();
        }
Example #15
0
        public void Update(UltimaData data, Flags flags)
        {
            // Items
            for (var offset = 0; offset < data.Items.Count; offset++)
            {
                avatarBytes[AvatarOffset.ITEM_LOCATIONS_OFFSET + offset * 5]     = data.Items[offset].Location;
                avatarBytes[AvatarOffset.ITEM_LOCATIONS_OFFSET + offset * 5 + 1] = data.Items[offset].X;
                avatarBytes[AvatarOffset.ITEM_LOCATIONS_OFFSET + offset * 5 + 2] = data.Items[offset].Y;
            }

            // Use these items at the entrance to the abyss
            avatarBytes[AvatarOffset.ITEM_USE_TRIGGER_BELL_X_OFFSET]   = data.Dungeons[data.Dungeons.Count - 1].X;
            avatarBytes[AvatarOffset.ITEM_USE_TRIGGER_BELL_Y_OFFSET]   = data.Dungeons[data.Dungeons.Count - 1].Y;
            avatarBytes[AvatarOffset.ITEM_USE_TRIGGER_BOOK_X_OFFSET]   = data.Dungeons[data.Dungeons.Count - 1].X;
            avatarBytes[AvatarOffset.ITEM_USE_TRIGGER_BOOK_Y_OFFSET]   = data.Dungeons[data.Dungeons.Count - 1].Y;
            avatarBytes[AvatarOffset.ITEM_USE_TRIGGER_CANDLE_X_OFFSET] = data.Dungeons[data.Dungeons.Count - 1].X;
            avatarBytes[AvatarOffset.ITEM_USE_TRIGGER_CANDLE_Y_OFFSET] = data.Dungeons[data.Dungeons.Count - 1].Y;
            avatarBytes[AvatarOffset.ITEM_USE_TRIGGER_SKULL_X_OFFSET]  = data.Dungeons[data.Dungeons.Count - 1].X;
            avatarBytes[AvatarOffset.ITEM_USE_TRIGGER_SKULL_Y_OFFSET]  = data.Dungeons[data.Dungeons.Count - 1].Y;

            ////throw in a lava to make it easy to find
            //for (int offset = 0; offset < 8; offset++)
            //{
            //    worldMapUlt[200, 200 + offset] = 76;
            //}
            // Moongates
            for (byte offset = 0; offset < data.Moongates.Count; offset++)
            {
                avatarBytes[AvatarOffset.MOONGATE_X_OFFSET + offset] = data.Moongates[offset].X;
                avatarBytes[AvatarOffset.MOONGATE_Y_OFFSET + offset] = data.Moongates[offset].Y;
            }

            avatarBytes[AvatarOffset.AREA_X_OFFSET + data.LOC_LCB - 1] = data.LCB[0].X;
            avatarBytes[AvatarOffset.AREA_Y_OFFSET + data.LOC_LCB - 1] = data.LCB[0].Y;

            avatarBytes[AvatarOffset.DEATH_EXIT_X_OFFSET] = data.LCB[0].X;
            avatarBytes[AvatarOffset.DEATH_EXIT_Y_OFFSET] = data.LCB[0].Y;

            for (var offset = 0; offset < data.Castles.Count; offset++)
            {
                avatarBytes[AvatarOffset.AREA_X_OFFSET + data.LOC_CASTLES + offset] = data.Castles[offset].X;
                avatarBytes[AvatarOffset.AREA_Y_OFFSET + data.LOC_CASTLES + offset] = data.Castles[offset].Y;
            }

            for (var offset = 0; offset < data.Towns.Count; offset++)
            {
                avatarBytes[AvatarOffset.AREA_X_OFFSET + data.LOC_TOWNS + offset - 1] = data.Towns[offset].X;
                avatarBytes[AvatarOffset.AREA_Y_OFFSET + data.LOC_TOWNS + offset - 1] = data.Towns[offset].Y;
            }

            for (var offset = 0; offset < data.Shrines.Count; offset++)
            {
                // Skip Spirituality
                if (data.Shrines[offset] != null)
                {
                    avatarBytes[AvatarOffset.AREA_X_OFFSET + data.LOC_SHRINES + offset - 1] = data.Shrines[offset].X;
                    avatarBytes[AvatarOffset.AREA_Y_OFFSET + data.LOC_SHRINES + offset - 1] = data.Shrines[offset].Y;
                }
            }

            for (var offset = 0; offset < data.Dungeons.Count; offset++)
            {
                avatarBytes[AvatarOffset.AREA_X_OFFSET + data.LOC_DUNGEONS + offset - 1] = data.Dungeons[offset].X;
                avatarBytes[AvatarOffset.AREA_Y_OFFSET + data.LOC_DUNGEONS + offset - 1] = data.Dungeons[offset].Y;
            }

            avatarBytes[AvatarOffset.BALLOON_SPAWN_TRIGGER_X_OFFSET] = data.Dungeons[data.Dungeons.Count - 2].X;
            avatarBytes[AvatarOffset.BALLOON_SPAWN_TRIGGER_Y_OFFSET] = data.Dungeons[data.Dungeons.Count - 2].Y;
            avatarBytes[AvatarOffset.LBC_DUNGEON_EXIT_X_OFFSET]      = data.Dungeons[data.Dungeons.Count - 2].X;
            avatarBytes[AvatarOffset.LBC_DUNGEON_EXIT_Y_OFFSET]      = data.Dungeons[data.Dungeons.Count - 2].Y;

            avatarBytes[AvatarOffset.BALLOON_SPAWN_LOCATION_X_OFFSET] = data.BalloonSpawn.X;
            avatarBytes[AvatarOffset.BALLOON_SPAWN_LOCATION_Y_OFFSET] = data.BalloonSpawn.Y;

            var avatarBytesList = new List <byte>(avatarBytes);

            for (int i = 0; i < OriginalShrineText.Count; i++)
            {
                if (data.ShrineText[i].Length > OriginalShrineText[i].Length)
                {
                    throw new Exception($"Shrine text \"{data.ShrineText[i]}\" is too long.");
                }
                data.ShrineText[i] = data.ShrineText[i].PadRight(OriginalShrineText[i].Length, ' ');

                avatarBytesList.RemoveRange(OriginalShrineTextStartOffset[i], OriginalShrineText[i].Length);
                avatarBytesList.InsertRange(OriginalShrineTextStartOffset[i], Encoding.ASCII.GetBytes(data.ShrineText[i]));
            }

            for (int i = 0; i < OriginalLBText.Count; i++)
            {
                if (data.LBText[i].Length > OriginalLBText[i].Length)
                {
                    throw new Exception($"LB text \"{data.LBText[i]}\" is too long.");
                }
                data.LBText[i] = data.LBText[i].PadRight(OriginalLBText[i].Length, ' ');

                avatarBytesList.RemoveRange(OriginalLBTextStartOffset[i], OriginalLBText[i].Length);
                avatarBytesList.InsertRange(OriginalLBTextStartOffset[i], Encoding.ASCII.GetBytes(data.LBText[i]));
            }
            avatarBytes = avatarBytesList.ToArray();

            for (int i = 0; i < OriginalLBHelpText.Count; i++)
            {
                if (data.LBHelpText[i].Length > OriginalLBHelpText[i].Length)
                {
                    throw new Exception($"LB text \"{data.LBHelpText[i]}\" is too long.");
                }
                data.LBHelpText[i] = data.LBHelpText[i].PadRight(OriginalLBHelpText[i].Length, ' ');

                avatarBytesList.RemoveRange(OriginalLBHelpTextStartOffset[i], OriginalLBHelpText[i].Length);
                avatarBytesList.InsertRange(OriginalLBHelpTextStartOffset[i], Encoding.ASCII.GetBytes(data.LBHelpText[i]));
            }
            avatarBytes = avatarBytesList.ToArray();

            var currentMantraOffset = 0;
            var mantraSize          = 0;

            for (int i = 0; i < data.Mantras.Count; i++)
            {
                avatarBytes[AvatarOffset.MANTRA_POINTERS_OFFSET + i * 2] = (byte)(avatarBytes[AvatarOffset.MANTRA_POINTERS_OFFSET] + mantraSize);
                mantraSize += data.Mantras[i].Length + 1;

                var textBytes = Encoding.ASCII.GetBytes(data.Mantras[i]);
                for (int j = 0; j < textBytes.Length; j++)
                {
                    avatarBytes[AvatarOffset.MANTRA_OFFSET + currentMantraOffset] = textBytes[j];
                    currentMantraOffset++;
                }
                avatarBytes[AvatarOffset.MANTRA_OFFSET + currentMantraOffset] = 0x00;
                currentMantraOffset++;

                if (currentMantraOffset > MantraMaxSize)
                {
                    throw new Exception($"Mantra text is too long.");
                }
            }

            var wordOfPassageBytes = Encoding.ASCII.GetBytes(data.WordOfPassage.ToLower());

            for (int j = 0; j < wordOfPassageBytes.Length; j++)
            {
                avatarBytes[AvatarOffset.WORD_OF_PASSAGE + j] = wordOfPassageBytes[j];
            }


            avatarBytes[AvatarOffset.DEMON_SPAWN_TRIGGER_X1_OFFSET] = data.DaemonSpawnX1;
            avatarBytes[AvatarOffset.DEMON_SPAWN_TRIGGER_X2_OFFSET] = data.DaemonSpawnX2;
            avatarBytes[AvatarOffset.DEMON_SPAWN_TRIGGER_Y1_OFFSET] = data.DaemonSpawnY1;
            avatarBytes[AvatarOffset.DEMON_SPAWN_TRIGGER_Y2_OFFSET] = data.DaemonSpawnY2;
            avatarBytes[AvatarOffset.DEMON_SPAWN_LOCATION_X_OFFSET] = data.DaemonSpawnLocationX;

            for (int i = 0; i < data.PirateCove.Count; i++)
            {
                avatarBytes[AvatarOffset.PIRATE_COVE_X_OFFSET + i] = data.PirateCove[i].X;
                avatarBytes[AvatarOffset.PIRATE_COVE_Y_OFFSET + i] = data.PirateCove[i].Y;
            }

            avatarBytes[AvatarOffset.PIRATE_COVE_SPAWN_TRIGGER_X_OFFSET1] = data.PirateCoveSpawnTrigger.X;
            avatarBytes[AvatarOffset.PIRATE_COVE_SPAWN_TRIGGER_Y_OFFSET1] = data.PirateCoveSpawnTrigger.Y;
            avatarBytes[AvatarOffset.PIRATE_COVE_SPAWN_TRIGGER_X_OFFSET2] = data.PirateCoveSpawnTrigger.X;
            avatarBytes[AvatarOffset.PIRATE_COVE_SPAWN_TRIGGER_Y_OFFSET2] = data.PirateCoveSpawnTrigger.Y;

            avatarBytes[AvatarOffset.WHIRLPOOL_EXIT_X_OFFSET] = data.WhirlpoolExit.X;
            avatarBytes[AvatarOffset.WHIRLPOOL_EXIT_Y_OFFSET] = data.WhirlpoolExit.Y;

            for (int i = 0; i < data.SpellsRecipes.Count; i++)
            {
                avatarBytes[AvatarOffset.SPELL_RECIPE_OFFSET + i] = data.SpellsRecipes[i].Byte;
            }

            // Cast exclusion isn't precise enough so allow them to cast anywhere and exclude the destination
            avatarBytes[AvatarOffset.BLINK_CAST_EXCLUSION_X1_OFFSET] = data.BlinkCastExclusionX1;
            avatarBytes[AvatarOffset.BLINK_CAST_EXCLUSION_X2_OFFSET] = data.BlinkCastExclusionX2;
            avatarBytes[AvatarOffset.BLINK_CAST_EXCLUSION_Y1_OFFSET] = data.BlinkCastExclusionY1;
            avatarBytes[AvatarOffset.BLINK_CAST_EXCLUSION_Y2_OFFSET] = data.BlinkCastExclusionY2;

            avatarBytes[AvatarOffset.BLINK_DESTINATION_EXCLUSION_X1_OFFSET] = data.BlinkDestinationExclusionX1;
            avatarBytes[AvatarOffset.BLINK_DESTINATION_EXCLUSION_X2_OFFSET] = data.BlinkDestinationExclusionX2;
            avatarBytes[AvatarOffset.BLINK_DESTINATION_EXCLUSION_Y1_OFFSET] = data.BlinkDestinationExclusionY1;
            avatarBytes[AvatarOffset.BLINK_DESTINATION_EXCLUSION_Y2_OFFSET] = data.BlinkDestinationExclusionY2;

            avatarBytes[AvatarOffset.BLINK_DESTINATION2_EXCLUSION_X1_OFFSET] = data.BlinkDestinationExclusion2X1;
            avatarBytes[AvatarOffset.BLINK_DESTINATION2_EXCLUSION_X2_OFFSET] = data.BlinkDestinationExclusion2X2;
            avatarBytes[AvatarOffset.BLINK_DESTINATION2_EXCLUSION_Y1_OFFSET] = data.BlinkDestinationExclusion2Y1;
            avatarBytes[AvatarOffset.BLINK_DESTINATION2_EXCLUSION_Y2_OFFSET] = data.BlinkDestinationExclusion2Y2;

            avatarBytes[AvatarOffset.ENABLE_MIX_QUANTITY_OFFSET] = flags.MixQuantity ? (byte)0x0 : (byte)0x9;
            if (flags.MixQuantity)
            {
                SpoilerLog.Add(SpoilerCategory.Feature, $"Mix Quantity Enabled");
            }

            avatarBytes[AvatarOffset.ENABLE_SLEEP_BACKOFF_OFFSET] = flags.SleepLockAssist ? (byte)0x0 : (byte)0x9;
            if (flags.SleepLockAssist)
            {
                SpoilerLog.Add(SpoilerCategory.Feature, $"Sleep Lock Assist Enabled");
            }

            avatarBytes[AvatarOffset.ENABLE_ACTIVE_PLAYER_1_OFFSET] = flags.ActivePlayer ? (byte)0x0 : (byte)0x9;
            if (flags.ActivePlayer)
            {
                SpoilerLog.Add(SpoilerCategory.Feature, $"Active Player Enabled");
            }

            avatarBytes[AvatarOffset.ENABLE_HIT_CHANCE_OFFSET] = flags.HitChance ? (byte)0x0 : (byte)0x9;
            if (flags.HitChance)
            {
                SpoilerLog.Add(SpoilerCategory.Feature, $"Apple II Hit Chance Enabled");
            }

            avatarBytes[AvatarOffset.ENABLE_DIAGONAL_ATTACK_OFFSET] = flags.DiagonalAttack ? (byte)0x0 : (byte)0x9;
            if (flags.DiagonalAttack)
            {
                SpoilerLog.Add(SpoilerCategory.Feature, $"Diagonal Attack Enabled");
            }

            avatarBytes[AvatarOffset.ENABLE_SACRIFICE_FIX_OFFSET] = flags.SacrificeFix ? (byte)0x0 : (byte)0x9;
            if (flags.SacrificeFix)
            {
                SpoilerLog.Add(SpoilerCategory.Fix, $"Sacrifice Fix Enabled");
            }

            for (int i = 0; i < data.AbyssEjectionLocations.Count; i++)
            {
                //Console.WriteLine(Talk.GetSextantText(data.AbyssEjectionLocations[i]));
                avatarBytes[AvatarOffset.ABYSS_EJECTION_LOCATIONS_X + i] = data.AbyssEjectionLocations[i].X;
                avatarBytes[AvatarOffset.ABYSS_EJECTION_LOCATIONS_Y + i] = data.AbyssEjectionLocations[i].Y;
            }

            for (int townIdx = 0; townIdx < 16; townIdx++)
            {
                for (int shopIdx = 0; shopIdx < 8; shopIdx++)
                {
                    avatarBytes[townIdx * 8 + shopIdx + AvatarOffset.SHOP_LOCATION_OFFSET] = data.ShopLocations[townIdx][shopIdx];
                }
            }

            var encodeBytes = Encoding.ASCII.GetBytes(flags.GetEncoded());

            for (int encodeIdx = 0; encodeIdx < encodeBytes.Length; encodeIdx++)
            {
                avatarBytes[AvatarOffset.ENCODED_FLAGS_OFFSET + encodeIdx] = encodeBytes[encodeIdx];
            }

            var seedBytes = Encoding.ASCII.GetBytes(flags.Seed.ToString());

            for (int seedIdx = 0; seedIdx < seedBytes.Length; seedIdx++)
            {
                avatarBytes[AvatarOffset.SEED_OFFSET + seedIdx] = seedBytes[seedIdx];
            }

            if (flags.Runes)
            {
                for (int i = 0; i < 8; i++)
                {
                    avatarBytes[AvatarOffset.CITY_RUNE_MASK_PAIRS_OFFSET + i * 2] = data.Items[i + UltimaData.ITEM_RUNE_HONESTY].Location;
                }
            }

            if (flags.MonsterDamage != 2)
            {
                avatarBytes[AvatarOffset.MONSTER_DAMAGE_BITSHIFT_OFFSET]     = 0xB1;
                avatarBytes[AvatarOffset.MONSTER_DAMAGE_BITSHIFT_OFFSET + 1] = (byte)flags.MonsterDamage;
                avatarBytes[AvatarOffset.MONSTER_DAMAGE_BITSHIFT_OFFSET + 2] = 0xD3;
            }

            if (flags.WeaponDamage != 2)
            {
                var multiplier = 1.0f;
                switch (flags.WeaponDamage)
                {
                case 1:
                    multiplier = 1.5f;
                    break;

                case 3:
                    multiplier = 0.5f;
                    break;
                }

                for (int i = 0; i < 16; i++)
                {
                    var originalDamage = avatarBytes[AvatarOffset.WEAPON_DAMAGE_OFFSET + i];
                    var newDamage      = avatarBytes[AvatarOffset.WEAPON_DAMAGE_OFFSET + i] * multiplier;
                    avatarBytes[AvatarOffset.WEAPON_DAMAGE_OFFSET + i] = (byte)Math.Max(0x01, Math.Min(0xFF, avatarBytes[AvatarOffset.WEAPON_DAMAGE_OFFSET + i] * multiplier));
                }
            }

            if (flags.EarlierMonsters)
            {
                ushort tierCutover      = 1000;
                var    tierCutoverBytes = BitConverter.GetBytes(tierCutover);
                for (int offset = 0; offset < tierCutoverBytes.Length; offset++)
                {
                    avatarBytes[AvatarOffset.MONSTER_SPAWN_TIER_ONE + offset] = tierCutoverBytes[offset];
                }

                tierCutover      = 2000;
                tierCutoverBytes = BitConverter.GetBytes(tierCutover);
                for (int offset = 0; offset < tierCutoverBytes.Length; offset++)
                {
                    avatarBytes[AvatarOffset.MONSTER_SPAWN_TIER_TWO + offset] = tierCutoverBytes[offset];
                }

                tierCutover      = 3000;
                tierCutoverBytes = BitConverter.GetBytes(tierCutover);
                for (int offset = 0; offset < tierCutoverBytes.Length; offset++)
                {
                    avatarBytes[AvatarOffset.MONSTER_SPAWN_TIER_THREE + offset] = tierCutoverBytes[offset];
                }
            }

            if (flags.MonsterQty)
            {
                var cmd = new byte[] { 0xB8, 0x10, 0x00, 0x90, 0x90 };
                for (int i = 0; i < cmd.Length; i++)
                {
                    avatarBytes[AvatarOffset.MONSTER_QTY_ONE + i] = cmd[i];
                }

                cmd = new byte[] { 0x3D, 0x08, 0x00, 0x7D, 0xE4, 0x90 };
                for (int i = 0; i < cmd.Length; i++)
                {
                    avatarBytes[AvatarOffset.MONSTER_QTY_TWO + i] = cmd[i];
                }
            }

            if (flags.NoRequireFullParty)
            {
                avatarBytes[AvatarOffset.ABYSS_PARTY_COMPARISON] = 0x76;
                avatarBytes[AvatarOffset.LB_PARTY_COMPARISON]    = 0x00;
            }

            if (flags.VGAPatch)
            {
                ApplyVGAPatch();
            }
        }
Example #16
0
        public void Update(UltimaData ultimaData, Avatar avatar, Flags flags, IWorldMap worldMap)
        {
            if (flags.Overworld == 5)
            {
                Person person = null;
                // --- Items ---
                if (ultimaData.Items[ultimaData.ITEM_BELL].Changed)
                {
                    person = FindPerson("Garam");
                    person.KeywordResponse2 = ReplaceSextantText(person.KeywordResponse2, GetSextantText(ultimaData.Items[ultimaData.ITEM_BELL]));
                }

                if (ultimaData.Items[ultimaData.ITEM_SKULL].Changed)
                {
                    person     = FindPerson("Jude");
                    person.Yes = ReplaceSextantText(person.Yes, GetSextantText(ultimaData.Items[ultimaData.ITEM_SKULL]));
                }

                if (ultimaData.Items[ultimaData.ITEM_NIGHTSHADE].Changed)
                {
                    person = FindPerson("Virgil");
                    person.KeywordResponse2 = ReplaceSextantText(person.KeywordResponse2, GetSextantText(ultimaData.Items[ultimaData.ITEM_NIGHTSHADE]));
                }

                if (ultimaData.Towns[ultimaData.LOC_MAGINCIA - ultimaData.LOC_TOWNS].IsDirty())
                {
                    person    = FindPerson("Shawn");
                    person.No = ReplaceSextantText(person.No, GetSextantText(ultimaData.Towns[ultimaData.LOC_MAGINCIA - ultimaData.LOC_TOWNS]));
                }

                // Mandrake
                if (ultimaData.Items[ultimaData.ITEM_MANDRAKE].Changed || ultimaData.Items[ultimaData.ITEM_MANDRAKE2].Changed)
                {
                    person = FindPerson("Calumny");
                    if (!flags.ClothMap)
                    {
                        person.KeywordResponse2 = $"Mandrake is found near {GetSextantText(ultimaData.Items[ultimaData.ITEM_MANDRAKE])}\nand\n{GetSextantText(ultimaData.Items[ultimaData.ITEM_MANDRAKE2])} ";
                    }
                    else
                    {
                        var           mandrakeTile   = worldMap.GetCoordinate(ultimaData.Items[ultimaData.ITEM_MANDRAKE].X, ultimaData.Items[ultimaData.ITEM_MANDRAKE].Y);
                        IList <ITile> path           = null;
                        var           mandrakeRegion = worldMap.FindNearestRegion(mandrakeTile, ultimaData, out path);

                        var mandrakeText = "Mandrake root is found only ";
                        if (mandrakeRegion != null && mandrakeRegion.Tiles.Any(c => c.Equals(mandrakeTile)))
                        {
                            mandrakeText += $"in the {mandrakeRegion.Name} ";
                        }
                        else if (path != null && path.Count < 11)
                        {
                            mandrakeText += $"near the {mandrakeRegion.Name} ";
                        }
                        else
                        {
                            mandrakeText += $"near {GetSextantText(ultimaData.Items[ultimaData.ITEM_MANDRAKE])} ";
                        }

                        mandrakeTile = worldMap.GetCoordinate(ultimaData.Items[ultimaData.ITEM_MANDRAKE2].X, ultimaData.Items[ultimaData.ITEM_MANDRAKE2].Y);
                        IList <ITile> path2           = null;
                        var           mandrakeRegion2 = worldMap.FindNearestRegion(mandrakeTile, ultimaData, out path2);
                        if (mandrakeRegion == mandrakeRegion2 && path.Count < 11)
                        {
                            path           = null;
                            mandrakeRegion = null;
                        }
                        else
                        {
                            mandrakeRegion = mandrakeRegion2;
                            path           = path2;
                            if (mandrakeRegion != null && mandrakeRegion.Tiles.Any(c => c == mandrakeTile))
                            {
                                mandrakeText += $"and in the {mandrakeRegion.Name} ";
                            }
                            else if (path != null && path.Count < 11)
                            {
                                mandrakeText += $"and near the {mandrakeRegion.Name} ";
                            }
                            else
                            {
                                mandrakeText += $"and near {GetSextantText(ultimaData.Items[ultimaData.ITEM_MANDRAKE2])} ";
                            }
                        }

                        mandrakeText += $"where the ground is always damp.";

                        person.KeywordResponse2 = mandrakeText;
                    }
                }

                // Horn
                // TODO make response descriptive
                if (ultimaData.Items[ultimaData.ITEM_HORN].Changed)
                {
                    person = FindPerson("Malchor");
                    person.KeywordResponse2 = $"Some say that\nthe silver horn\nis buried at\n{GetSextantText(ultimaData.Items[ultimaData.ITEM_HORN])}";
                }

                // Wheel
                // TODO make response descriptive
                if (ultimaData.Items[ultimaData.ITEM_WHEEL].Changed)
                {
                    person = FindPerson("Lassorn");
                    person.KeywordResponse2 = $"She went down in\nthe deep waters\nat\n{GetSextantText(ultimaData.Items[ultimaData.ITEM_WHEEL])}!";
                }

                // TODO Black stone currently at the moongate will need to change this text if we ever do randomize it
                person = FindPerson("Merlin");

                // White stone
                // TODO make response descriptive
                if (ultimaData.Items[ultimaData.ITEM_WHITE_STONE].Changed)
                {
                    person = FindPerson("Isaac");
                    person.KeywordResponse2          = $"The white stone\nsits atop the\nmountains at\n{GetSextantText(ultimaData.Items[ultimaData.ITEM_WHITE_STONE])}.\nIt can only be\nreached by one\nwho floats\nwithin the\nclouds.";
                    ultimaData.ShrineText[6 * 3 + 2] = $"If thou dost seek the White Stone search not under the ground but at {GetSextantText(ultimaData.Items[ultimaData.ITEM_WHITE_STONE]).Replace('\n', ' ')}";
                }

                // TODO Book, candle, runes, mystic armor and mystic weapons I'm leaving along for now. Not randomizing stuff in towns yet.

                // --- End Items ---

                // --- Shrines ---
                // Humility
                // TODO make response descriptive
                if (ultimaData.Shrines[ultimaData.LOC_HUMILITY - ultimaData.LOC_SHRINES].IsDirty())
                {
                    person = FindPerson("Simple");
                    person.KeywordResponse2 = $"The shrine lies\nnear\n{GetSextantText(ultimaData.Shrines[ultimaData.LOC_HUMILITY - ultimaData.LOC_SHRINES])} and\nis guarded by\nendless hoards\nof daemons!";
                    person = FindPerson("Wierdrum");
                    person.KeywordResponse2 = $"Yes, I have been\nto the shrine,\nit lies near\n{GetSextantText(ultimaData.Shrines[ultimaData.LOC_HUMILITY - ultimaData.LOC_SHRINES])}!";
                }


                // Compassion
                // TODO make response descriptive
                if (ultimaData.Shrines[ultimaData.LOC_COMPASSION - ultimaData.LOC_SHRINES].IsDirty())
                {
                    person     = FindPerson("Shapero");
                    person.Yes = $"Find the shrine\nof compassion\nat\n{GetSextantText(ultimaData.Shrines[ultimaData.LOC_COMPASSION - ultimaData.LOC_SHRINES])}!";
                }

                // Sacrifice
                // TODO make response descriptive
                if (ultimaData.Shrines[ultimaData.LOC_SACRIFICE - ultimaData.LOC_SHRINES].IsDirty())
                {
                    person    = FindPerson("Merida");
                    person.No = $"The shrine is at\n{GetSextantText(ultimaData.Shrines[ultimaData.LOC_SACRIFICE - ultimaData.LOC_SHRINES])}!";
                }

                // Justice
                // TODO make response descriptive
                if (ultimaData.Shrines[ultimaData.LOC_JUSTICE - ultimaData.LOC_SHRINES].IsDirty())
                {
                    person = FindPerson("Druid");
                    person.KeywordResponse2 = $"The shrine is at\n{GetSextantText(ultimaData.Shrines[ultimaData.LOC_JUSTICE - ultimaData.LOC_SHRINES])}!";
                }

                // Honesty
                // TODO make response descriptive
                if (ultimaData.Shrines[ultimaData.LOC_HONESTY - ultimaData.LOC_SHRINES].IsDirty())
                {
                    person    = FindPerson("Calabrini");
                    person.No = $"Perhaps, the\nshrine which\nlies at\n{GetSextantText(ultimaData.Shrines[ultimaData.LOC_HONESTY - ultimaData.LOC_SHRINES])}!";
                }

                // Honor
                // TODO make response descriptive
                if (ultimaData.Shrines[ultimaData.LOC_HONOR - ultimaData.LOC_SHRINES].IsDirty())
                {
                    person    = FindPerson("Dergin");
                    person.No = $"The shrine lies at\n{GetSextantText(ultimaData.Shrines[ultimaData.LOC_HONOR - ultimaData.LOC_SHRINES])}!";
                }

                // TODO Spirituality - Do I move this one?
                person = FindPerson("the Ankh of\nSpirituality");

                // Valor
                // No on gives the directions to Valor so I grabbed his reponse that talked about the shrine and usurped it
                // TODO make response descriptive
                if (ultimaData.Shrines[ultimaData.LOC_VALOR - ultimaData.LOC_SHRINES].IsDirty())
                {
                    person    = FindPerson("Sir Hrothgar");
                    person.No = $"Thou should seek\nthe shrine of\nvalor at\n{GetSextantText(ultimaData.Shrines[ultimaData.LOC_VALOR - ultimaData.LOC_SHRINES])}!";
                }

                // --- End Shrines ---

                // --- Runes ---
                if (flags.Runes)
                {
                    for (int i = 0; i < 8; i++)
                    {
                        var itemOption = ultimaData.ItemOptions[UltimaData.ITEM_RUNE_HONESTY + i];
                        foreach (var newPerson in itemOption.People)
                        {
                            person = FindPerson(newPerson.Name, newPerson.Town);
                            if (newPerson.Health != null)
                            {
                                person.Health = newPerson.Health;
                            }
                            if (newPerson.Job != null)
                            {
                                person.Job = newPerson.Job;
                            }
                            if (newPerson.Keyword1 != null)
                            {
                                person.Keyword1 = newPerson.Keyword1;
                            }
                            if (newPerson.Keyword2 != null)
                            {
                                person.Keyword2 = newPerson.Keyword2;
                            }
                            if (newPerson.Yes != null)
                            {
                                person.Yes = newPerson.Yes;
                            }
                            if (newPerson.No != null)
                            {
                                person.No = newPerson.No;
                            }
                            if (newPerson.Question != null)
                            {
                                person.Question = newPerson.Question;
                            }
                            if (newPerson.KeywordResponse1 != null)
                            {
                                person.KeywordResponse1 = newPerson.KeywordResponse1;
                            }
                            if (newPerson.KeywordResponse2 != null)
                            {
                                person.KeywordResponse2 = newPerson.KeywordResponse2;
                            }
                        }
                    }
                }

                // --- End Runes ---

                if (flags.Mantras)
                {
                    person = FindPerson("Cromwell");
                    person.KeywordResponse2 = $"The mantra of the shrine of honesty is {Mantras[0].Text.ToUpper()}.";

                    person = FindPerson("Cricket");
                    person.KeywordResponse2 = $"The mantra of the shrine of compassion is {Mantras[1].Text.ToUpper()}!";

                    person = FindPerson("Aesop");
                    person.KeywordResponse2 = $"The mantra of valor is '{Mantras[2].Text.ToUpper()}'. Use it in the shrine on the next isle!";

                    person                  = FindPerson("Silent");
                    person.Job              = $"{Mantras[3].Text}... {Mantras[3].Text}...";
                    person.Health           = $"{Mantras[3].Text}... {Mantras[3].Text}...";
                    person.Keyword1         = $"{Mantras[3].Text.ToUpper()}...";
                    person.KeywordResponse1 = $"{Mantras[3].Text}... {Mantras[3].Text}...";
                    person.Keyword2         = $"{Mantras[3].Text.ToUpper()}";
                    person.KeywordResponse2 = $"{Mantras[3].Text}... {Mantras[3].Text}...";

                    person = FindPerson("Singsong");
                    person.KeywordResponse2 = Mantras[4].Limerick;

                    person = FindPerson("Kline");
                    person.KeywordResponse1 = $"The mantra is '{Mantras[5].Text}'.";

                    person = FindPerson("Barren", "Skara");
                    person.KeywordResponse1 = $"I know it well, it is '{Mantras[6].Text.ToUpper()}'.";

                    person          = FindPerson("the Ankh of\nSpirituality");
                    person.Keyword2 = Mantras[6].Text.ToUpper();

                    person = FindPerson("Faultless");
                    person.KeywordResponse2 = $"The mantra for pride, being the antithesis of humility, is '{new string(Mantras[7].Text.ToString().ToUpper().Reverse().ToArray())}'.";
                }

                if (flags.WordOfPassage)
                {
                    person     = FindPerson("Robert Frasier");
                    person.Yes = $"It is '{ultimaData.WordTruth.ToLower()}'! Seek ye now the other parts!";

                    person     = FindPerson("Lord Robert", "Empath");
                    person.Yes = $"It is '{ultimaData.WordLove.ToLower()}'! Seek ye now the other parts!";

                    person = FindPerson("Sentri");
                    person.KeywordResponse2 = $"I know but one of three syllables - '{ultimaData.WordCourage.ToLower()}'.";
                }

                if (flags.RandomizeSpells)
                {
                    person = FindPerson("Nigel, at thy\nservice.");
                    person.KeywordResponse2 = $"Yes, resurrection it takes: {GetRecipeText(ultimaData.SpellsRecipes['r' - 'a'].Byte)}!";

                    person = FindPerson("Mentorian");
                    if (ultimaData.SpellsRecipes['g' - 'a'].Byte == 0xFF)
                    {
                        person.KeywordResponse2 = $"As thou dost bear the ankh I shall tell thee. A gate spell needs { GetRecipeText(ultimaData.SpellsRecipes['g' - 'a'].Byte)}!";
                    }
                    else
                    {
                        person.KeywordResponse2 = $"Since thou dost bear the ankh I shall tell thee. A gate spell requires { GetRecipeText(ultimaData.SpellsRecipes['g' - 'a'].Byte)}!";
                    }
                }

                // --- Towns and Castles ---
                // TODO make response descriptive
                if (ultimaData.Castles[0].IsDirty())
                {
                    ultimaData.LBText[3] = $"He says:\nMany truths can\nbe learned at\nthe Lycaeum.  It\nlies to the\n{CoordinateToCardinal(ultimaData.LCB[0], ultimaData.Castles[0])}!\n";
                }
                if (ultimaData.Castles[1].IsDirty())
                {
                    ultimaData.LBText[4] = $"He says:\nLook for the\nmeaning of Love\nat Empath Abbey.\nThe Abbey sits\n{CoordinateToCardinal(ultimaData.LCB[0], ultimaData.Castles[1])}!\n";
                }
                if (ultimaData.Castles[2].IsDirty())
                {
                    ultimaData.LBText[5] = $"\n\nHe says:\nSerpent's Castle\nto the {CoordinateToCardinal(ultimaData.LCB[0], ultimaData.Castles[2])}\nis where\nCourage should\nbe sought!\n";
                }
                if (ultimaData.Towns[ultimaData.LOC_MOONGLOW - ultimaData.LOC_TOWNS].IsDirty())
                {
                    ultimaData.LBText[6] = $"\nHe says:\nThe towne\nof Moonglow to\nthe {CoordinateToCardinal(ultimaData.LCB[0], ultimaData.Towns[ultimaData.LOC_MOONGLOW - ultimaData.LOC_TOWNS])} is\nwhere the virtue\nof Honesty\nthrives!\n";
                }
                if (ultimaData.Towns[ultimaData.LOC_BRITAIN - ultimaData.LOC_TOWNS].IsDirty())
                {
                    ultimaData.LBText[7] = $"\n\nHe says:\nThe bards in\nBritain to the\n{CoordinateToCardinal(ultimaData.LCB[0], ultimaData.Towns[ultimaData.LOC_BRITAIN - ultimaData.LOC_TOWNS])}\nare well versed\nin\nCompassion!\n";
                }
                if (ultimaData.Towns[ultimaData.LOC_JHELOM - ultimaData.LOC_TOWNS].IsDirty())
                {
                    ultimaData.LBText[8] = $"\n\nHe says:\nMany valiant\nfighters come\nfrom Jhelom\nto the \n{CoordinateToCardinal(ultimaData.LCB[0], ultimaData.Towns[ultimaData.LOC_JHELOM - ultimaData.LOC_TOWNS])}!\n";
                }
                if (ultimaData.Towns[ultimaData.LOC_YEW - ultimaData.LOC_TOWNS].IsDirty())
                {
                    ultimaData.LBText[9] = $"\n\n\nHe says:\nIn the city of\nYew, to the\n{CoordinateToCardinal(ultimaData.LCB[0], ultimaData.Towns[ultimaData.LOC_YEW - ultimaData.LOC_TOWNS])}, \nJustice is\nserved!\n";
                }
                if (ultimaData.Towns[ultimaData.LOC_MINOC - ultimaData.LOC_TOWNS].IsDirty())
                {
                    ultimaData.LBText[10] = $"\nHe says:\nMinoc, towne of\nself-sacrifice,\nlies {CoordinateToCardinal(ultimaData.LCB[0], ultimaData.Towns[ultimaData.LOC_MINOC - ultimaData.LOC_TOWNS])}!\n";
                }
                if (ultimaData.Towns[ultimaData.LOC_TRINSIC - ultimaData.LOC_TOWNS].IsDirty())
                {
                    ultimaData.LBText[11] = $"\nHe says:\nThe Paladins who\nstrive for Honor\nare oft seen in\nTrinsic, to the {CoordinateToCardinal(ultimaData.LCB[0], ultimaData.Towns[ultimaData.LOC_TRINSIC - ultimaData.LOC_TOWNS])}!\n";
                }
                if (ultimaData.Towns[ultimaData.LOC_SKARA - ultimaData.LOC_TOWNS].IsDirty())
                {
                    ultimaData.LBText[12] = $"\nHe says:\nIn Skara Brae\nthe Spiritual\npath is taught.\nFind it to the\n{CoordinateToCardinal(ultimaData.LCB[0], ultimaData.Towns[ultimaData.LOC_SKARA - ultimaData.LOC_TOWNS])}!\n";
                }
                if (ultimaData.Towns[ultimaData.LOC_MAGINCIA - ultimaData.LOC_TOWNS].IsDirty())
                {
                    ultimaData.LBText[13] = $"\n\n\nHe says:\nHumility is the\nfoundation of\nVirtue!  The\nruins of proud\nMagincia are a\ntestimony unto\nthe Virtue of\nHumility!\n\nFind the Ruins\nof Magincia to\nthe {CoordinateToCardinal(ultimaData.LCB[0], ultimaData.Towns[ultimaData.LOC_MAGINCIA - ultimaData.LOC_TOWNS])}!\n";
                }

                // --- End Towns and Castles ---

                // --- Other ---
                // TODO: Pirate location? Bucaneer's Den?
                person = FindPerson("Wilmoore");
            }
            else if (flags.Overworld == 2)
            {
                var talkToLocation = new Dictionary <Tuple <byte, byte, byte>, Tuple <string, string> >();
                talkToLocation.Add(new Tuple <byte, byte, byte>(0x00, 0xB6, 0x36), new Tuple <string, string>("<Item> is found in the Bloody Plains where the ground is always damp.", "<Item> is found in the Bloody Plains where the ground is always damp. Search on the darkest of nights!"));
                talkToLocation.Add(new Tuple <byte, byte, byte>(0x00, 0x64, 0xA5), new Tuple <string, string>("<Item> is found in the Fens of the Dead where the ground is always damp.", "<Item> is found in the Fens of the Dead where the ground is always damp. Search on the darkest of nights!"));
                talkToLocation.Add(new Tuple <byte, byte, byte>(0x00, 0x2E, 0x95), new Tuple <string, string>("<Item> may be found only near lat-J'F\" long-C'O\"!", "<Item> may be found only near lat-J'F\" long-C'O\" only on the darkest of nights!"));
                talkToLocation.Add(new Tuple <byte, byte, byte>(0x00, 0xCD, 0x2C), new Tuple <string, string>("<Item> may be found in the forest outside the shrine in the lake east of the Bloody Plains!", "<Item> may be found in the forest outside the shrine in the lake east of the Bloody Plains only on the darkest of nights!"));
                talkToLocation.Add(new Tuple <byte, byte, byte>(0x00, 0xB0, 0xD0), new Tuple <string, string>("<Item> lies at the bottom of a deep well at sea found at lat-N'A\" long-L'A\".", "<Item> lies at the bottom of a deep well at sea found at lat-N'A\" long-L'A\" but can only be found on the darkest of nights."));
                talkToLocation.Add(new Tuple <byte, byte, byte>(0x00, 0x2D, 0xAD), new Tuple <string, string>("Some say that <Item> is buried on a small isle off the tip of Spiritwood.", "Some say that <Item> is buried on a small isle off the tip of Spiritwood and can be found when the moons go dark."));
                talkToLocation.Add(new Tuple <byte, byte, byte>(0x00, 0x60, 0xD7), new Tuple <string, string>("Search the deep waters of the bay in the Cape of Heroes!", "Search the deep waters of the bay in the Cape of Heroes when the moons go dark!"));
                talkToLocation.Add(new Tuple <byte, byte, byte>(0x00, 0xC5, 0xF5), new Tuple <string, string>("It can be found at lat-P'F\" long-M'F\"!", "It can be found at lat-P'F\" long-M'F\" on the darkest night!"));
                talkToLocation.Add(new Tuple <byte, byte, byte>(0x00, 0xE0, 0x85), new Tuple <string, string>("Stand where the gate of both moons dark shall appear.", "Stand where the gate of both moons dark shall appear. Search when the moons go dark!"));
                talkToLocation.Add(new Tuple <byte, byte, byte>(0x00, 0x40, 0x50), new Tuple <string, string>("<Item> sits atop the Serpent's Spine. It can only be reached by one who floats within the clouds.", "<Item> sits atop the Serpent's Spine. It can only be reached by one who floats within the clouds and when the moons go dark."));

                var item       = ultimaData.Items[ultimaData.ITEM_BELL];
                var talkString = talkToLocation[new Tuple <byte, byte, byte>(item.Location, item.X, item.Y)].Item1;
                talkString = talkString.Replace("<Item>", "the bell of courage").CapitalizeFirstLetter();
                var person = FindPerson("Garam");
                person.KeywordResponse2 = talkString;

                item       = ultimaData.Items[ultimaData.ITEM_SKULL];
                talkString = talkToLocation[new Tuple <byte, byte, byte>(item.Location, item.X, item.Y)].Item2;
                talkString = talkString.Replace("<Item>", "the skull").CapitalizeFirstLetter();
                person     = FindPerson("Jude");
                person.Yes = talkString;

                item       = ultimaData.Items[ultimaData.ITEM_NIGHTSHADE];
                talkString = talkToLocation[new Tuple <byte, byte, byte>(item.Location, item.X, item.Y)].Item2;
                talkString = talkString.Replace("<Item>", "nightshade").CapitalizeFirstLetter();
                person     = FindPerson("Virgil");
                person.KeywordResponse2 = talkString;

                item       = ultimaData.Items[ultimaData.ITEM_MANDRAKE];
                talkString = talkToLocation[new Tuple <byte, byte, byte>(item.Location, item.X, item.Y)].Item1;
                talkString = talkString.Replace("<Item>", "mandrake").CapitalizeFirstLetter();
                person     = FindPerson("Calumny");
                person.KeywordResponse2 = talkString;

                item       = ultimaData.Items[ultimaData.ITEM_HORN];
                talkString = talkToLocation[new Tuple <byte, byte, byte>(item.Location, item.X, item.Y)].Item1;
                talkString = talkString.Replace("<Item>", "the silver horn").CapitalizeFirstLetter();
                person     = FindPerson("Malchor");
                person.KeywordResponse2 = talkString;

                item       = ultimaData.Items[ultimaData.ITEM_WHEEL];
                talkString = talkToLocation[new Tuple <byte, byte, byte>(item.Location, item.X, item.Y)].Item1;
                talkString = talkString.Replace("<Item>", "the magical wheel").CapitalizeFirstLetter();
                person     = FindPerson("Lassorn");
                person.KeywordResponse2 = talkString;

                item       = ultimaData.Items[ultimaData.ITEM_BLACK_STONE];
                talkString = talkToLocation[new Tuple <byte, byte, byte>(item.Location, item.X, item.Y)].Item2;
                talkString = talkString.Replace("<Item>", "the black stone").CapitalizeFirstLetter();
                person     = FindPerson("Merlin");
                person.KeywordResponse1 = talkString;

                item       = ultimaData.Items[ultimaData.ITEM_WHITE_STONE];
                talkString = talkToLocation[new Tuple <byte, byte, byte>(item.Location, item.X, item.Y)].Item1;
                talkString = talkString.Replace("<Item>", "the white stone").CapitalizeFirstLetter();
                person     = FindPerson("Isaac");
                person.KeywordResponse2          = talkString;
                ultimaData.ShrineText[6 * 3 + 2] = "If thou dost seek the White Stone rest at the Inn of Spirits.";
            }

            if (flags.NoRequireFullParty)
            {
                ultimaData.LBHelpText[18] = "Thou dost now seem ready to make the final journey into the dark Abyss!\n";
            }

            // --- Fixes ---
            if (flags.Fixes)
            {
                var person = FindPerson("Water");
                person.QuestionFlag = 6;
                SpoilerLog.Add(SpoilerCategory.Fix, $"Water asks question");

                person          = FindPerson("Estro");
                person.Keyword1 = "RESE";
                SpoilerLog.Add(SpoilerCategory.Fix, $"Estro keyword fix");

                person = FindPerson("a truth\nseeker.");
                person.KeywordResponse2 = person.KeywordResponse2.Replace("minutes", "cycles");
                SpoilerLog.Add(SpoilerCategory.Fix, $"a truth seeker word usage");

                person     = FindPerson("Catriona");
                person.Yes = person.Yes + ".";
                SpoilerLog.Add(SpoilerCategory.Fix, $"Catriona punctuation");

                person     = FindPerson("a ranger.");
                person.Yes = person.Yes.Replace("knowns", "knows");
                SpoilerLog.Add(SpoilerCategory.Fix, $"Ranger typo");

                person          = FindPerson("Calabrini");
                person.Keyword2 = "INJU";
                person.Question = "Dost thou seek\nan inn or art\nthou injured?";
                SpoilerLog.Add(SpoilerCategory.Fix, $"Calabrini heal keyword");

                person                  = FindPerson("Michelle");
                person.No               = "Then thou should\nvisit our\nphysician!";
                person.Keyword2         = "PHYS";
                person.KeywordResponse1 = person.KeywordResponse1.Replace("west", "north");
                person.KeywordResponse2 = "Got north and take\nthe western door.";
                SpoilerLog.Add(SpoilerCategory.Fix, $"Michelle heal keyword");

                person      = FindPerson("Tracie");
                person.Look = "A starving journalist";
                SpoilerLog.Add(SpoilerCategory.Fix, $"Tracie corrected look");

                person      = FindPerson("Iolo");
                person.Look = "A charming bard";
                SpoilerLog.Add(SpoilerCategory.Fix, $"Iolo corrected look");

                person = FindPerson("Sir William");
                person.KeywordResponse2 = person.KeywordResponse2.Replace("never", "Never");
                SpoilerLog.Add(SpoilerCategory.Fix, $"Sir William capitalization");

                person = FindPerson("Alkerion");
                person.QuestionFlag = 6;
                SpoilerLog.Add(SpoilerCategory.Fix, $"Alkerion asks question");

                person      = FindPerson("Dupre");
                person.Look = "A handsome fighter";
                SpoilerLog.Add(SpoilerCategory.Fix, $"Dupre corrected look");

                person          = FindPerson("Virgil");
                person.Question = "Is it thine?";
                SpoilerLog.Add(SpoilerCategory.Fix, $"Virgil question grammar");

                person = FindPerson("Shamino");
                person.QuestionFlag = 6;

                person      = FindPerson("Traveling Dan");
                person.Look = "A short, rotund\nman with a hat\nand vest.";
                SpoilerLog.Add(SpoilerCategory.Fix, $"Traveling Dan corrected look");

                person = FindPerson("Charm");
                person.QuestionFlag = 6;
                SpoilerLog.Add(SpoilerCategory.Fix, $"Charm asks question");

                person      = FindPerson("Rabindranath\ntagore");
                person.Name = "Rabindranath\nTagore";
                SpoilerLog.Add(SpoilerCategory.Fix, $"Fix 'Rabindranath tagore' capitalization");
            }
        }
Example #17
0
        public void Load(string path, UltimaData data)
        {
            var file = Path.Combine(path, filename);

            FileHelper.TryBackupOriginalFile(file);

            // Apply delta file to create new file
            var newFilePath2           = file;
            var newFileOutputDirectory = Path.GetDirectoryName(newFilePath2);

            if (!Directory.Exists(newFileOutputDirectory))
            {
                Directory.CreateDirectory(newFileOutputDirectory);
            }
            var deltaApplier = new DeltaApplier {
                SkipHashCheck = false
            };

            using (var basisStream = new FileStream($"{file}.orig", FileMode.Open, FileAccess.Read, FileShare.Read))
            {
                using (var deltaStream = new MemoryStream(Patches.TITLE_EXE))
                {
                    using (var newFileStream = new FileStream(newFilePath2, FileMode.Create, FileAccess.ReadWrite, FileShare.Read))
                    {
                        deltaApplier.Apply(basisStream, new BinaryDeltaReader(deltaStream, new ConsoleProgressReporter()), newFileStream);
                    }
                }
            }

            using (var titleStream = new System.IO.FileStream(file, System.IO.FileMode.Open))
            {
                titleBytes = titleStream.ReadAllBytes();
            }

            if (titleBytes[START_X_OFFSET] != 0xE7)
            {
                throw new Exception($"Offset START_X_OFFSET appears to be wrong.");
            }

            if (titleBytes[START_Y_OFFSET] != 0x88)
            {
                throw new Exception($"Offset START_Y_OFFSET appears to be wrong.");
            }

            if (titleBytes[FLAG_ENCODE_OFFSET] != 0x43)
            {
                throw new Exception($"Offset FLAG_ENCODE_OFFSET appears to be wrong.");
            }

            if (titleBytes[ENABLE_KARMA_OVERRIDE_OFFSET] != 0x09)
            {
                throw new Exception($"Offset ENABLE_KARMA_OVERRIDE_OFFSET appears to be wrong.");
            }

            if (titleBytes[KARMA_OVERRIDE_VALUES_OFFSET] != 0xFF)
            {
                throw new Exception($"Offset KARMA_OVERRIDE_VALUES_OFFSET appears to be wrong.");
            }

            for (int offset = 0; offset < 8; offset++)
            {
                data.StartingPositions.Add(new Coordinate(titleBytes[START_X_OFFSET + offset], titleBytes[START_Y_OFFSET + offset]));
            }

            for (int offset = 0; offset < 8; offset++)
            {
                data.StartingKarma.Add(titleBytes[KARMA_OVERRIDE_VALUES_OFFSET + offset]);
            }
        }
Example #18
0
        public void Load(string path, UltimaData data, IWorldMap worldMap, Flags flags)
        {
            var file = Path.Combine(path, filename);

            if (flags.VGAPatch && HashHelper.BytesToString(HashHelper.GetHashSha256(file)) == upgradeFileHash)
            {
                DowngradeVGAPatch(file);
            }
            FileHelper.TryBackupOriginalFile(file);

            // Apply delta file to create new file
            var newFilePath2           = file;
            var newFileOutputDirectory = Path.GetDirectoryName(newFilePath2);

            if (!Directory.Exists(newFileOutputDirectory))
            {
                Directory.CreateDirectory(newFileOutputDirectory);
            }
            var deltaApplier = new DeltaApplier {
                SkipHashCheck = false
            };

            using (var basisStream = new FileStream($"{file}.orig", FileMode.Open, FileAccess.Read, FileShare.Read))
            {
                using (var deltaStream = new MemoryStream(Patches.AVATAR_EXE))
                {
                    using (var newFileStream = new FileStream(newFilePath2, FileMode.Create, FileAccess.ReadWrite, FileShare.Read))
                    {
                        deltaApplier.Apply(basisStream, new BinaryDeltaReader(deltaStream, new ConsoleProgressReporter()), newFileStream);
                    }
                }
            }

            using (var avatarStream = new System.IO.FileStream(file, System.IO.FileMode.Open))
            {
                avatarBytes = avatarStream.ReadAllBytes();
            }

            AvatarOffset = new AvatarOffsetsNew(avatarBytes, $"{file}.orig");


            // Items
            var items = new List <Item>();

            for (int offset = 0; offset < 23; offset++)
            {
                items.Add(new Item(avatarBytes[AvatarOffset.ITEM_LOCATIONS_OFFSET + offset * 5],
                                   avatarBytes[AvatarOffset.ITEM_LOCATIONS_OFFSET + offset * 5 + 1],
                                   avatarBytes[AvatarOffset.ITEM_LOCATIONS_OFFSET + offset * 5 + 2]));
            }
            data.SetItems(items);

            // Moongates
            var moongates = new List <Tile>();

            for (byte offset = 0; offset < 8; offset++)
            {
                moongates.Add(worldMap.GetCoordinate(avatarBytes[AvatarOffset.MOONGATE_X_OFFSET + offset], avatarBytes[AvatarOffset.MOONGATE_Y_OFFSET + offset]));
            }
            data.SetMoongates(moongates);

            // LCB
            var lcb    = new List <Tile>();
            var lcbLoc = worldMap.GetCoordinate(avatarBytes[AvatarOffset.AREA_X_OFFSET + data.LOC_LCB - 1], avatarBytes[AvatarOffset.AREA_Y_OFFSET + data.LOC_LCB - 1]);

            lcb.Add(lcbLoc);
            lcb.Add(worldMap.GetCoordinate(lcbLoc.X - 1, lcbLoc.Y));
            lcb.Add(worldMap.GetCoordinate(lcbLoc.X + 1, lcbLoc.Y));
            data.SetLCB(lcb);

            // Castles
            var castles = new List <TileDirtyWrapper>();

            for (byte offset = 0; offset < 3; offset++)
            {
                castles.Add(new TileDirtyWrapper(worldMap.GetCoordinate(avatarBytes[AvatarOffset.AREA_X_OFFSET + data.LOC_CASTLES + offset], avatarBytes[AvatarOffset.AREA_Y_OFFSET + data.LOC_CASTLES + offset]), worldMap));
            }
            data.SetCastles(castles);

            // Towns
            var towns = new List <TileDirtyWrapper>();

            for (byte offset = 0; offset < 8 + 4; offset++)
            {
                towns.Add(new TileDirtyWrapper(worldMap.GetCoordinate(avatarBytes[AvatarOffset.AREA_X_OFFSET + data.LOC_TOWNS + offset - 1], avatarBytes[AvatarOffset.AREA_Y_OFFSET + data.LOC_TOWNS + offset - 1]), worldMap));
            }
            data.SetTowns(towns);

            // Shrines
            var shrines = new List <TileDirtyWrapper>();

            for (byte offset = 0; offset < 8; offset++)
            {
                shrines.Add(new TileDirtyWrapper(worldMap.GetCoordinate(avatarBytes[AvatarOffset.AREA_X_OFFSET + data.LOC_SHRINES + offset - 1], avatarBytes[AvatarOffset.AREA_Y_OFFSET + data.LOC_SHRINES + offset - 1]), worldMap));
            }
            data.SetShrines(shrines);

            // Dungeons
            var dungeons = new List <Tile>();

            for (byte offset = 0; offset < 8; offset++)
            {
                dungeons.Add(worldMap.GetCoordinate(avatarBytes[AvatarOffset.AREA_X_OFFSET + data.LOC_DUNGEONS + offset - 1], avatarBytes[AvatarOffset.AREA_Y_OFFSET + data.LOC_DUNGEONS + offset - 1]));
            }
            data.SetDungeons(dungeons);

            // Balloon Spawn
            data.BalloonSpawn = worldMap.GetCoordinate(avatarBytes[AvatarOffset.BALLOON_SPAWN_LOCATION_X_OFFSET], avatarBytes[AvatarOffset.BALLOON_SPAWN_LOCATION_Y_OFFSET]);

            OriginalShrineText            = new List <string>();
            OriginalShrineTextStartOffset = new List <int>();
            var shrineTextBytes = new List <byte>();
            var textOffset      = AvatarOffset.SHRINE_TEXT_OFFSET;

            for (int i = 0; i < 24; i++)
            {
                OriginalShrineTextStartOffset.Add(textOffset);
                for (; avatarBytes[textOffset] != 0x0A && avatarBytes[textOffset] != 0x00; textOffset++)
                {
                    shrineTextBytes.Add(avatarBytes[textOffset]);
                }
                OriginalShrineText.Add(System.Text.Encoding.Default.GetString(shrineTextBytes.ToArray()));
                shrineTextBytes.Clear();
                if (avatarBytes[textOffset] == 0x0A)
                {
                    textOffset++;
                }
                textOffset++;
            }
            data.ShrineText.Clear();
            data.ShrineText.AddRange(OriginalShrineText);

            OriginalLBText            = new List <string>();
            OriginalLBTextStartOffset = new List <int>();
            var lbTextBytes = new List <byte>();

            textOffset = AvatarOffset.LB_TEXT_OFFSET;
            // He has more text than 19 but there is some weird stuff after 19 that doesn't get turned into text well. And as far as I can tell we won't need any text after 19
            for (int i = 0; i < 19; i++)
            {
                OriginalLBTextStartOffset.Add(textOffset);
                for (; avatarBytes[textOffset] != 0x00 && avatarBytes[textOffset] != 0xAB; textOffset++)
                {
                    lbTextBytes.Add(avatarBytes[textOffset]);
                }
                OriginalLBText.Add(System.Text.Encoding.Default.GetString(lbTextBytes.ToArray()));
                lbTextBytes.Clear();
                if (avatarBytes[textOffset] == 0x0A || avatarBytes[textOffset] == 0xAB)
                {
                    textOffset++;
                }
                textOffset++;
            }
            data.LBText.Clear();
            data.LBText.AddRange(OriginalLBText);

            OriginalLBHelpText            = new List <string>();
            OriginalLBHelpTextStartOffset = new List <int>();
            lbTextBytes = new List <byte>();
            textOffset  = AvatarOffset.LB_HELP_TEXT_OFFSET;
            for (int i = 0; i < 21; i++)
            {
                OriginalLBHelpTextStartOffset.Add(textOffset);
                for (; avatarBytes[textOffset] != 0x00 && avatarBytes[textOffset] != 0xAB; textOffset++)
                {
                    lbTextBytes.Add(avatarBytes[textOffset]);
                }
                OriginalLBHelpText.Add(System.Text.Encoding.Default.GetString(lbTextBytes.ToArray()));
                lbTextBytes.Clear();
                if (avatarBytes[textOffset] == 0x0A || avatarBytes[textOffset] == 0xAB)
                {
                    textOffset++;
                }
                textOffset++;
            }
            data.LBHelpText.Clear();
            data.LBHelpText.AddRange(OriginalLBHelpText);

            var mantraTextBytes = new List <byte>();

            textOffset    = AvatarOffset.MANTRA_OFFSET;
            MantraMaxSize = 0;
            for (int i = 0; i < 8; i++)
            {
                for (; avatarBytes[textOffset] != 0x00; textOffset++)
                {
                    mantraTextBytes.Add(avatarBytes[textOffset]);
                }
                data.Mantras.Add(System.Text.Encoding.Default.GetString(mantraTextBytes.ToArray()));
                MantraMaxSize += data.Mantras[i].Length + 1;
                mantraTextBytes.Clear();

                textOffset++;
            }

            var wordOfPassageTextBytes = new List <byte>();

            for (int offSet = 0; offSet < 9; offSet++)
            {
                wordOfPassageTextBytes.Add(avatarBytes[AvatarOffset.WORD_OF_PASSAGE + offSet]);
            }
            data.WordOfPassage = System.Text.Encoding.Default.GetString(wordOfPassageTextBytes.ToArray());

            data.DaemonSpawnX1        = avatarBytes[AvatarOffset.DEMON_SPAWN_TRIGGER_X1_OFFSET];
            data.DaemonSpawnX2        = avatarBytes[AvatarOffset.DEMON_SPAWN_TRIGGER_X2_OFFSET];
            data.DaemonSpawnY1        = avatarBytes[AvatarOffset.DEMON_SPAWN_TRIGGER_Y1_OFFSET];
            data.DaemonSpawnY2        = avatarBytes[AvatarOffset.DEMON_SPAWN_TRIGGER_Y2_OFFSET];
            data.DaemonSpawnLocationX = avatarBytes[AvatarOffset.DEMON_SPAWN_LOCATION_X_OFFSET];

            for (int i = 0; i < 8; i++)
            {
                data.PirateCove.Add(new Coordinate(avatarBytes[i + AvatarOffset.PIRATE_COVE_X_OFFSET], avatarBytes[i + AvatarOffset.PIRATE_COVE_Y_OFFSET]));
            }

            data.PirateCoveSpawnTrigger = new Coordinate(avatarBytes[AvatarOffset.PIRATE_COVE_SPAWN_TRIGGER_X_OFFSET1], avatarBytes[AvatarOffset.PIRATE_COVE_SPAWN_TRIGGER_Y_OFFSET1]);

            data.WhirlpoolExit = new Coordinate(avatarBytes[AvatarOffset.WHIRLPOOL_EXIT_X_OFFSET], avatarBytes[AvatarOffset.WHIRLPOOL_EXIT_Y_OFFSET]);

            data.SpellsRecipes = new List <ByteDirtyWrapper>();
            for (int i = 0; i < 26; i++)
            {
                data.SpellsRecipes.Add(new ByteDirtyWrapper(avatarBytes[AvatarOffset.SPELL_RECIPE_OFFSET + i]));
            }

            data.BlinkCastExclusionX1 = avatarBytes[AvatarOffset.BLINK_CAST_EXCLUSION_X1_OFFSET];
            data.BlinkCastExclusionX2 = avatarBytes[AvatarOffset.BLINK_CAST_EXCLUSION_X2_OFFSET];
            data.BlinkCastExclusionY1 = avatarBytes[AvatarOffset.BLINK_CAST_EXCLUSION_Y1_OFFSET];
            data.BlinkCastExclusionY2 = avatarBytes[AvatarOffset.BLINK_CAST_EXCLUSION_Y2_OFFSET];

            data.BlinkDestinationExclusionX1 = avatarBytes[AvatarOffset.BLINK_DESTINATION_EXCLUSION_X1_OFFSET];
            data.BlinkDestinationExclusionX2 = avatarBytes[AvatarOffset.BLINK_DESTINATION_EXCLUSION_X2_OFFSET];
            data.BlinkDestinationExclusionY1 = avatarBytes[AvatarOffset.BLINK_DESTINATION_EXCLUSION_Y1_OFFSET];
            data.BlinkDestinationExclusionY2 = avatarBytes[AvatarOffset.BLINK_DESTINATION_EXCLUSION_Y2_OFFSET];

            data.BlinkDestinationExclusion2X1 = avatarBytes[AvatarOffset.BLINK_DESTINATION2_EXCLUSION_X1_OFFSET];
            data.BlinkDestinationExclusion2X2 = avatarBytes[AvatarOffset.BLINK_DESTINATION2_EXCLUSION_X2_OFFSET];
            data.BlinkDestinationExclusion2Y1 = avatarBytes[AvatarOffset.BLINK_DESTINATION2_EXCLUSION_Y1_OFFSET];
            data.BlinkDestinationExclusion2Y2 = avatarBytes[AvatarOffset.BLINK_DESTINATION2_EXCLUSION_Y2_OFFSET];

            for (int i = 0; i < 13; i++)
            {
                data.AbyssEjectionLocations.Add(new Coordinate(avatarBytes[i + AvatarOffset.ABYSS_EJECTION_LOCATIONS_X], avatarBytes[i + AvatarOffset.ABYSS_EJECTION_LOCATIONS_Y]));
            }

            for (int townIdx = 0; townIdx < 16; townIdx++)
            {
                data.ShopLocations.Add(new List <byte>());
                for (int shopIdx = 0; shopIdx < 8; shopIdx++)
                {
                    data.ShopLocations[townIdx].Add(avatarBytes[townIdx * 8 + shopIdx + AvatarOffset.SHOP_LOCATION_OFFSET]);
                }
            }
        }
Example #19
0
        private static void Randomize(int seed, string path, Flags flags, string encoded)
        {
            //Console.WriteLine("Seed: " + seed);

            string json = JsonConvert.SerializeObject(flags);

            if (string.IsNullOrWhiteSpace(encoded))
            {
                encoded = flags.GetEncoded();
            }
            else
            {
                flags.DecodeAndSet(encoded);
                json = JsonConvert.SerializeObject(flags);
            }
            Console.WriteLine("Flags JSON  : " + json);
            Console.WriteLine("Flags Base64: " + encoded);

            StreamWriter spoilerWriter = new StreamWriter("spoiler.txt");
            SpoilerLog   spoilerLog    = new SpoilerLog(spoilerWriter, flags.SpoilerLog);

            System.IO.File.AppendAllText(@"seed.txt", seed.ToString() + " " + encoded + Environment.NewLine);
            spoilerLog.WriteFlags(flags);

            var random = new Random(seed);

            var randomValues = new List <int>();

            for (int i = 0; i < 50; i++)
            {
                randomValues.Add(random.Next());
            }

            var ultimaData = new UltimaData();

            IWorldMap worldMap = null;

            //WorldMapGenerateMap.PrintWorldMapInfo(path);

            if (flags.Overworld == 5)
            {
                worldMap = new WorldMapGenerateMap(spoilerLog);
            }
            else if (flags.Overworld == 1)
            {
                worldMap = new WorldMapUnchanged(spoilerLog);
            }
            else if (flags.Overworld == 2)
            {
                worldMap = new WorldMapShuffleLocations(spoilerLog);
            }
            worldMap.Load(path, randomValues[0], randomValues[1], randomValues[2], ultimaData);

            var avatar = new Avatar(spoilerLog);

            avatar.Load(path, ultimaData, worldMap, flags);

            var title = new Title(spoilerLog);

            title.Load(path, ultimaData);

            var talk = new Talk(spoilerLog);

            talk.Load(path);

            var dungeons = new Dungeons(spoilerLog);

            dungeons.Load(path, ultimaData, flags);

            var party = new Party(spoilerLog);

            party.Load(path, ultimaData);

            var towns = new Towns(spoilerLog);

            towns.Load(path, ultimaData);

            if (flags.Fixes)
            {
                spoilerLog.Add(SpoilerCategory.Fix, "Serpent Hold's Healer");
                ultimaData.ShopLocations[ultimaData.LOC_SERPENT - 1][5] = 0x12;
            }

            worldMap.Randomize(ultimaData, new Random(randomValues[3]), new Random(randomValues[4]));
            dungeons.Randomize(new Random(randomValues[6]), flags);

            if (flags.ClothMap)
            {
                var clothMap = worldMap.ToClothMap(ultimaData, new Random(randomValues[5]));
                clothMap.SaveAsPng($"clothMap-{seed}.png");
                new Process
                {
                    StartInfo = new ProcessStartInfo($"clothMap-{seed}.png")
                    {
                        UseShellExecute = true
                    }
                }.Start();
            }

            if (flags.RandomizeSpells)
            {
                var recipes = new byte[2];
                ultimaData.SpellsRecipes['r' - 'a'].Byte = 0;
                ultimaData.SpellsRecipes['g' - 'a'].Byte = 0;
                while (ultimaData.SpellsRecipes['r' - 'a'].Byte == 0)
                {
                    random.NextBytes(recipes);
                    ultimaData.SpellsRecipes['r' - 'a'].Byte = (byte)(recipes[0] | recipes[1]);
                }
                while (ultimaData.SpellsRecipes['g' - 'a'].Byte == 0)
                {
                    random.NextBytes(recipes);
                    ultimaData.SpellsRecipes['g' - 'a'].Byte = (byte)(recipes[0] | recipes[1]);
                }
            }
            if (!String.IsNullOrWhiteSpace(flags.SpellRemove))
            {
                var arr = flags.SpellRemove.ToLower().ToArray();
                for (int i = 0; i < arr.Length; i++)
                {
                    if (arr[i] > 'z' || arr[i] < 'a')
                    {
                        throw new ArgumentException("spellRemove can only contain letters.");
                    }
                    ultimaData.SpellsRecipes[arr[i] - 'a'].Byte = 0;
                }
            }

            if (flags.StartingWeapons)
            {
                for (int charIdx = 0; charIdx < 8; charIdx++)
                {
                    var selected = false;
                    while (!selected)
                    {
                        // -1 so Mystic weapons and armors aren't included
                        var weapon = random.Next(1, Party.AllowedWeaponsMask.Length - 1);
                        //If weapon is allowed
                        if ((Party.AllowedWeaponsMask[weapon] & (0x80 >> ultimaData.StartingCharacters[charIdx].Class)) != 0)
                        {
                            ultimaData.StartingCharacters[charIdx].Weapon = (ushort)weapon;
                            selected = true;
                        }
                    }

                    selected = false;
                    while (!selected)
                    {
                        var armor = random.Next(1, Party.AllowedArmorMask.Length);
                        //If weapon is allowed
                        if ((Party.AllowedArmorMask[armor] & (0x80 >> ultimaData.StartingCharacters[charIdx].Class)) != 0)
                        {
                            ultimaData.StartingCharacters[charIdx].Armor = (ushort)armor;
                            selected = true;
                        }
                    }
                }
            }


            //worldMap.TestAbyssEjection();

            //Console.WriteLine(Talk.GetSextantText(ultimaData.LCB[0]));

            //for (int i = 0; i < 8; i++)
            //{
            //    ultimaData.StartingArmor[i] = Convert.ToUInt16(i + 10);
            //}

            //for (int i = 0; i < 16; i++)
            //{
            //    ultimaData.StartingWeapons[i] = Convert.ToUInt16(i + 10);
            //}

            //ultimaData.StartingFood = 2345 * 100 + 99;
            //ultimaData.StartingGold = 1337;
            //for (int i = 0; i < 4; i++)
            //{
            //    ultimaData.StartingEquipment[i] = Convert.ToUInt16(i + 10);
            //}
            //for (int i = 0; i < 8; i++)
            //{
            //    ultimaData.StartingReagents[i] = Convert.ToUInt16(i + 10);
            //}
            //for (int i = 0; i < 26; i++)
            //{
            //    ultimaData.StartingMixtures[i] = Convert.ToUInt16(i + 10);
            //}

            //ultimaData.StartingItems = 0XFFFF;
            if (flags.QuestItemPercentage > 0)
            {
                ushort ushortone = 1;

                ultimaData.StartingItems = 0;
                for (ushort i = 0; i < 16; i++)
                {
                    if (random.Next(0, 100) < flags.QuestItemPercentage)
                    {
                        ultimaData.StartingItems |= (ushort)(ushortone << i);
                    }
                }
                // Never have the skull destroyed
                ultimaData.StartingItems &= (ushort)(~(ushortone << 1));
                // Don' pre-use bell, book and candle
                ultimaData.StartingItems &= (ushort)(~(ushortone << 10));
                ultimaData.StartingItems &= (ushort)(~(ushortone << 11));
                ultimaData.StartingItems &= (ushort)(~(ushortone << 12));

                ultimaData.StartingRunes = 0;
                for (ushort i = 0; i < 8; i++)
                {
                    if (random.Next(0, 100) < flags.QuestItemPercentage)
                    {
                        ultimaData.StartingRunes |= (byte)(1 << i);
                    }
                }

                ultimaData.StartingStones = 0;
                for (ushort i = 0; i < 8; i++)
                {
                    if (random.Next(0, 100) < flags.QuestItemPercentage)
                    {
                        ultimaData.StartingStones |= (byte)(1 << i);
                    }
                }

                LogQuestItems(spoilerLog, ultimaData);
            }
            else
            {
                spoilerLog.Add(SpoilerCategory.Start, "No change to starting quest items.");
            }

            if (flags.Sextant)
            {
                ultimaData.StartingEquipment[3] = 0x01;
            }

            if (flags.KarmaSetPercentage > 0)
            {
                for (int virtue = 0; virtue < 8; virtue++)
                {
                    if (random.Next(0, 100) < flags.KarmaSetPercentage)
                    {
                        ultimaData.StartingKarma[virtue] = (flags.KarmaValue.HasValue ? (byte)flags.KarmaValue.Value : (byte)random.Next(0, 100));
                        spoilerLog.Add(SpoilerCategory.Start, $"{ultimaData.ItemNames[virtue + 15]} karma at {ultimaData.StartingKarma[virtue]}");
                    }
                    else
                    {
                        spoilerLog.Add(SpoilerCategory.Start, $"{ultimaData.ItemNames[virtue + 15]} karma unchanged.");
                    }
                }
            }

            if (flags.Runes)
            {
                spoilerLog.Add(SpoilerCategory.Feature, $"Rune locations randomized");
                var usedLocations = new List <byte>();
                for (int i = UltimaData.ITEM_RUNE_HONESTY; i < 8 + UltimaData.ITEM_RUNE_HONESTY; i++)
                {
                    var possibleOptions    = ItemOptions.ItemToItemOptions[i].Where(x => !usedLocations.Contains(x.Item.Location)).ToList();
                    var selectedItemOption = possibleOptions[random.Next(0, possibleOptions.Count)];
                    ultimaData.Items[i].X        = selectedItemOption.Item.X;
                    ultimaData.Items[i].Y        = selectedItemOption.Item.Y;
                    ultimaData.Items[i].Location = selectedItemOption.Item.Location;

                    ultimaData.ItemOptions.Add(i, selectedItemOption);
                    usedLocations.Add(selectedItemOption.Item.Location);
                }
            }

            if (flags.Mantras)
            {
                int numberOfTwos   = 3;
                int numberOfThrees = 4;
                int numberOfFours  = 1;
                // Grab Sacrifice first since it is special
                var mantrasWithLimericks = talk.Mantras.Where(x => x.Limerick.Length > 0).ToList();
                var sacrificeMantra      = mantrasWithLimericks[random.Next(0, mantrasWithLimericks.Count)];

                talk.Mantras.Remove(sacrificeMantra);

                if (sacrificeMantra.Text.Length == 2)
                {
                    numberOfTwos--;
                }
                else if (sacrificeMantra.Text.Length == 3)
                {
                    numberOfThrees--;
                }
                else if (sacrificeMantra.Text.Length == 4)
                {
                    numberOfFours--;
                }

                var possibleTwos   = talk.Mantras.Where(x => x.Text.Length == 2).ToList();
                var possibleThrees = talk.Mantras.Where(x => x.Text.Length == 3).ToList();
                var possibleFours  = talk.Mantras.Where(x => x.Text.Length == 4).ToList();

                var possibleMantras = new List <Mantra>();

                for (int i = 0; i < numberOfTwos; i++)
                {
                    var nextIdx = random.Next(0, possibleTwos.Count);
                    possibleMantras.Add(possibleTwos[nextIdx]);
                    possibleTwos.RemoveAt(nextIdx);
                }

                for (int i = 0; i < numberOfThrees; i++)
                {
                    var nextIdx = random.Next(0, possibleThrees.Count);
                    possibleMantras.Add(possibleThrees[nextIdx]);
                    possibleThrees.RemoveAt(nextIdx);
                }

                for (int i = 0; i < numberOfFours; i++)
                {
                    var nextIdx = random.Next(0, possibleFours.Count);
                    possibleMantras.Add(possibleFours[nextIdx]);
                    possibleFours.RemoveAt(nextIdx);
                }

                possibleMantras.Shuffle(random);
                possibleMantras.Insert(4, sacrificeMantra);
                talk.Mantras = possibleMantras;

                for (int i = 0; i < 8; i++)
                {
                    ultimaData.Mantras[i] = talk.Mantras[i].Text.ToLower();
                }
            }

            if (flags.WordOfPassage)
            {
                var selection = talk.WordsOfPassage[random.Next(0, talk.WordsOfPassage.Count)];
                ultimaData.WordTruth     = selection.Item1;
                ultimaData.WordLove      = selection.Item2;
                ultimaData.WordCourage   = selection.Item3;
                ultimaData.WordOfPassage = selection.Item1 + selection.Item2 + selection.Item3;
            }

            //ultimaData.StartingStones = 0XFF;
            //ultimaData.StartingRunes = 0XFF;

            title.Update(ultimaData, flags, encoded);
            talk.Update(ultimaData, avatar, flags, worldMap);
            avatar.Update(ultimaData, flags);
            dungeons.Update(ultimaData, flags);
            party.Update(ultimaData);
            towns.Update(ultimaData, flags);

            towns.Save(path);
            party.Save(path);
            dungeons.Save(path);
            title.Save(path);
            talk.Save(path);
            avatar.Save(path);
            worldMap.Save(path);

            if (flags.MiniMap)
            {
                var image = worldMap.ToImage();
                image.SaveAsPng($"worldMap-{seed}.png");
                //image = worldMap.ToHeightMapImage();
                //if (image != null)
                //{
                //    image.SaveAsPng($"worldMap-hm-{seed}.png");
                //}
            }

            spoilerWriter.Close();

            //PrintWorldMapInfo();
        }
Example #20
0
 public void Update(UltimaData ultimaData, Flags flags)
 {
 }
Example #21
0
        public void Load(string path, UltimaData data)
        {
            var file = Path.Combine(path, filename);

            FileHelper.TryBackupOriginalFile(file);

            using (var partyStream = new System.IO.FileStream($"{file}.orig", System.IO.FileMode.Open))
            {
                partyBytes = partyStream.ReadAllBytes();
            }

            for (int i = 0; i < 8; i++)
            {
                var character = new Character();
                character.Hp     = BitConverter.ToUInt16(partyBytes, CHARACTER_RECORDS_OFFSET + (i * CHAR_RECORD_LENGTH) + CHARACTER_HP_OFFSET);
                character.MaxHp  = BitConverter.ToUInt16(partyBytes, CHARACTER_RECORDS_OFFSET + (i * CHAR_RECORD_LENGTH) + CHARACTER_MAX_HP_OFFSET);
                character.XP     = BitConverter.ToUInt16(partyBytes, CHARACTER_RECORDS_OFFSET + (i * CHAR_RECORD_LENGTH) + CHARACTER_XP_OFFSET);
                character.Str    = BitConverter.ToUInt16(partyBytes, CHARACTER_RECORDS_OFFSET + (i * CHAR_RECORD_LENGTH) + CHARACTER_STR_OFFSET);
                character.Dex    = BitConverter.ToUInt16(partyBytes, CHARACTER_RECORDS_OFFSET + (i * CHAR_RECORD_LENGTH) + CHARACTER_DEX_OFFSET);
                character.Int    = BitConverter.ToUInt16(partyBytes, CHARACTER_RECORDS_OFFSET + (i * CHAR_RECORD_LENGTH) + CHARACTER_INT_OFFSET);
                character.Mp     = BitConverter.ToUInt16(partyBytes, CHARACTER_RECORDS_OFFSET + (i * CHAR_RECORD_LENGTH) + CHARACTER_MP_OFFSET);
                character.Weapon = BitConverter.ToUInt16(partyBytes, CHARACTER_RECORDS_OFFSET + (i * CHAR_RECORD_LENGTH) + CHARACTER_WEAPON_OFFSET);
                character.Armor  = BitConverter.ToUInt16(partyBytes, CHARACTER_RECORDS_OFFSET + (i * CHAR_RECORD_LENGTH) + CHARACTER_ARMOR_OFFSET);

                var nameTextBytes = new List <byte>();
                var textOffset    = CHARACTER_RECORDS_OFFSET + (i * CHAR_RECORD_LENGTH) + CHARACTER_NAME_OFFSET;
                for (; partyBytes[textOffset] != 0x00; textOffset++)
                {
                    nameTextBytes.Add(partyBytes[textOffset]);
                }
                character.Name = System.Text.Encoding.Default.GetString(nameTextBytes.ToArray());
                nameTextBytes.Clear();

                character.Sex    = (partyBytes[CHARACTER_RECORDS_OFFSET + (i * CHAR_RECORD_LENGTH) + CHARACTER_SEX_OFFSET] == 0xb ? 'M' : 'F');
                character.Class  = partyBytes[CHARACTER_RECORDS_OFFSET + (i * CHAR_RECORD_LENGTH) + CHARACTER_CLASS_OFFSET];
                character.Status = (char)partyBytes[CHARACTER_RECORDS_OFFSET + (i * CHAR_RECORD_LENGTH) + CHARACTER_STATUS_OFFSET];

                data.StartingCharacters.Add(character);
            }

            data.StartingFood  = BitConverter.ToUInt32(partyBytes, FOOD_OFFSET);
            data.StartingGold  = BitConverter.ToUInt16(partyBytes, GOLD_OFFSET);
            data.StartingItems = BitConverter.ToUInt16(partyBytes, ITEMS1_OFFSET);
            for (int offset = 0; offset < 4; offset++)
            {
                data.StartingEquipment.Add(BitConverter.ToUInt16(partyBytes, EQUIPMENT_OFFSET + (offset * 2)));
            }
            for (int offset = 0; offset < 8; offset++)
            {
                data.StartingArmor.Add(BitConverter.ToUInt16(partyBytes, ARMOR_OFFSET + (offset * 2)));
            }
            for (int offset = 0; offset < 16; offset++)
            {
                data.StartingWeapons.Add(BitConverter.ToUInt16(partyBytes, WEAPONS_OFFSET + (offset * 2)));
            }
            for (int offset = 0; offset < 8; offset++)
            {
                data.StartingReagents.Add(BitConverter.ToUInt16(partyBytes, REAGENTS_OFFSET + (offset * 2)));
            }
            for (int offset = 0; offset < 26; offset++)
            {
                data.StartingMixtures.Add(BitConverter.ToUInt16(partyBytes, MIXTURES_OFFSET + (offset * 2)));
            }

            data.StartingStones = partyBytes[STONES_OFFSET];
            data.StartingRunes  = partyBytes[RUNES_OFFSET];
        }
Example #22
0
        private static void LogQuestItems(SpoilerLog spoilerLog, UltimaData ultimaData)
        {
            ushort ushortone     = 1;
            var    startingItems = new List <string>
            {
                "Skull",
                "Skull destroyed",
                "Candle",
                "Book",
                "Bell",
                "Courage Key",
                "Love Key",
                "Truth Key",
                "Silver Horn",
                "Wheel of the H.M.S. Cape",
                "Candle used",
                "Book used",
                "Bell used"
            };

            for (int i = 0; i < startingItems.Count; i++)
            {
                if ((ultimaData.StartingItems & (ushort)(ushortone << i)) != 0)
                {
                    spoilerLog.Add(SpoilerCategory.Start, startingItems[i]);
                }
                else
                {
                    spoilerLog.Add(SpoilerCategory.Start, $"No {startingItems[i]}");
                }
            }

            for (int i = 0; i < 8; i++)
            {
                if ((ultimaData.StartingRunes & (ushort)(ushortone << i)) != 0)
                {
                    spoilerLog.Add(SpoilerCategory.Start, ultimaData.ItemNames[i + 15]);
                }
                else
                {
                    spoilerLog.Add(SpoilerCategory.Start, $"No {ultimaData.ItemNames[i + 15]}");
                }
            }

            var startingStones = new List <string>
            {
                "Blue",
                "Yellow",
                "Red",
                "Green",
                "Orange",
                "Purple",
                "White",
                "Black"
            };

            for (int i = 0; i < startingStones.Count; i++)
            {
                if ((ultimaData.StartingStones & (ushort)(ushortone << i)) != 0)
                {
                    spoilerLog.Add(SpoilerCategory.Start, startingStones[i]);
                }
                else
                {
                    spoilerLog.Add(SpoilerCategory.Start, $"No {startingStones[i]}");
                }
            }
        }