コード例 #1
0
        public static async Task <FF1Rom> CreateAsync(Stream readStream)
        {
            var rom = new FF1Rom();
            await rom.LoadAsync(readStream);

            return(rom);
        }
コード例 #2
0
 public ExtConsumables(FF1Rom _rom, Flags _flags, MT19337 _rng, ShopData _shopData)
 {
     rom      = _rom;
     flags    = _flags;
     rng      = _rng;
     ShopData = _shopData;
 }
コード例 #3
0
        public OverworldMap(FF1Rom rom, IMapEditFlags flags)
        {
            _rom = rom;
            var mapLocationRequirements = ItemLocations.MapLocationRequirements.ToDictionary(x => x.Key, x => x.Value.ToList());

            if (flags.MapVolcanoIceRiver)
            {
                MapEditsToApply.Add(VolcanoIceRiver);
                mapLocationRequirements[MapLocation.GurguVolcano].Add(MapChange.Bridge | MapChange.Canoe);
                mapLocationRequirements[MapLocation.CresentLake].Add(MapChange.Bridge | MapChange.Canoe);
                mapLocationRequirements[MapLocation.ElflandTown].Add(MapChange.Bridge | MapChange.Canoe);
                mapLocationRequirements[MapLocation.ElflandCastle].Add(MapChange.Bridge | MapChange.Canoe);
                mapLocationRequirements[MapLocation.NorthwestCastle].Add(MapChange.Bridge | MapChange.Canoe);
                mapLocationRequirements[MapLocation.MarshCave].Add(MapChange.Bridge | MapChange.Canoe);
                mapLocationRequirements[MapLocation.DwarfCave].Add(MapChange.Bridge | MapChange.Canoe);
            }
            if (flags.MapConeriaDwarves)
            {
                MapEditsToApply.Add(ConeriaToDwarves);
                mapLocationRequirements[MapLocation.DwarfCave] = new List <MapChange> {
                    MapChange.None
                };
            }
            if (flags.MapTitansTrove)
            {
                mapLocationRequirements[MapLocation.TitansTunnelWest] = new List <MapChange> {
                    MapChange.Canal | MapChange.Ship | MapChange.TitanFed, MapChange.Airship | MapChange.TitanFed
                };
            }
            MapLocationRequirements = mapLocationRequirements;
        }
コード例 #4
0
        public ExitTeleData(FF1Rom _rom)
        {
            rom = _rom;

            TeleX = new MemTable <byte>(rom, 0x2C60, 16);
            TeleY = new MemTable <byte>(rom, 0x2C70, 16);
        }
コード例 #5
0
        public StartingInventory(MT19337 _rng, Flags _flags, FF1Rom _rom)
        {
            rng   = _rng;
            flags = _flags;
            rom   = _rom;

            ItemData = new StartingItems(rom);
        }
コード例 #6
0
 public ReversedFloors(FF1Rom _rom, List <Map> _maps, MT19337 _rng)
 {
     rom   = _rom;
     maps  = _maps;
     rng   = _rng;
     tele  = new NormTeleData(rom);
     enter = new EnterTeleData(rom);
 }
コード例 #7
0
        public MemTable(FF1Rom _rom, int _address, int _count)
        {
            rom     = _rom;
            address = _address;
            count   = _count;

            LoadTable();
        }
コード例 #8
0
        public NormTeleData(FF1Rom _rom)
        {
            rom = _rom;

            TeleX   = new MemTable <byte>(rom, 0x3F000, 256);
            TeleY   = new MemTable <byte>(rom, 0x3F100, 256);
            TeleMap = new MemTable <MapId>(rom, 0x3F200, 256);
        }
コード例 #9
0
 public RibbonShuffle(FF1Rom _rom, MT19337 _rng, Flags _flags, ItemNames _itemsText, GearPermissions _armorPermissions)
 {
     rom              = _rom;
     rng              = _rng;
     flags            = _flags;
     itemsText        = _itemsText;
     armorPermissions = _armorPermissions;
 }
コード例 #10
0
 public BaseHintPlacementProvider(MT19337 _rng, NPCdata _npcData, Flags _flags, OverworldMap _overworldMap, FF1Rom _rom)
 {
     rng          = _rng;
     npcData      = _npcData;
     flags        = _flags;
     overworldMap = _overworldMap;
     rom          = _rom;
 }
コード例 #11
0
        public EnterTeleData(FF1Rom _rom)
        {
            rom = _rom;

            TeleX   = new MemTable <byte>(rom, 0x2C00, 32);
            TeleY   = new MemTable <byte>(rom, 0x2C20, 32);
            TeleMap = new MemTable <MapId>(rom, 0x2C40, 32);
        }
コード例 #12
0
        public MemTable(FF1Rom _rom, int _address, int _count, int _size)
        {
            rom     = _rom;
            address = _address;
            count   = _count;
            size    = _size;

            LoadTable();
        }
コード例 #13
0
        public ExpChests(FF1Rom _rom, Flags _flags, MT19337 _rng)
        {
            rom   = _rom;
            flags = _flags;
            rng   = _rng;

            treasureData = new TreasureData(rom);
            itemPrices   = new ItemPrices(rom);
        }
コード例 #14
0
 public override void Put(FF1Rom rom)
 {
     if (Item > Item.Soft)
     {
         throw new InvalidOperationException(
                   $"Attempted to Put invalid item shop placement: \n{SpoilerText}");
     }
     base.Put(rom);
 }
コード例 #15
0
        public TileSet(FF1Rom _rom, byte idx)
        {
            TileProperties = new TilePropTable(_rom, idx);
            TileAttributes = new MemTable <byte>(_rom, 0x400 + 0x80 * idx, 128);

            TopLeftTiles     = new MemTable <byte>(_rom, 0x1000 + 0x200 * idx, 128);
            TopRightTiles    = new MemTable <byte>(_rom, 0x1080 + 0x200 * idx, 128);
            BottemLeftTiles  = new MemTable <byte>(_rom, 0x1100 + 0x200 * idx, 128);
            BottemRightTiles = new MemTable <byte>(_rom, 0x1180 + 0x200 * idx, 128);
        }
コード例 #16
0
        public StartingEquipment(MT19337 _rng, Flags _flags, FF1Rom _rom)
        {
            rng   = _rng;
            flags = _flags;
            rom   = _rom;

            spellHelper = new SpellHelper(rom);
            weapons     = Weapon.LoadAllWeapons(rom, flags).ToList();
            armors      = Armor.LoadAllArmors(rom, flags).ToList();
        }
コード例 #17
0
        public BaseHintSource(MT19337 _rng, NPCdata _npcData, Flags _flags, OverworldMap _overworldMap, FF1Rom _rom)
        {
            rng          = _rng;
            npcData      = _npcData;
            flags        = _flags;
            overworldMap = _overworldMap;
            rom          = _rom;

            translator = new Translator(rom);
        }
コード例 #18
0
        public ShopKiller(MT19337 _rng, Flags _flags, List <Map> _maps, FF1Rom _rom)
        {
            rng   = _rng;
            flags = _flags;
            rom   = _rom;
            maps  = _maps;

            ShopData   = new ShopData(rom);
            QuestItems = new HashSet <Item>(ItemLists.AllQuestItems);
        }
コード例 #19
0
 public TilePropTable(FF1Rom _rom, byte idx)
 {
     if (idx == 0xff)
     {
         // overworld
         TileProperties = new MemTable <byte>(_rom, 0, 256);
     }
     else
     {
         TileProperties = new MemTable <byte>(_rom, 0x800 + 0x100 * idx, 256);
     }
 }
コード例 #20
0
        public OwMapExchange(FF1Rom _rom, OverworldMap _overworldMap, OwMapExchangeData replacement)
        {
            rom          = _rom;
            overworldMap = _overworldMap;

            exit      = new ExitTeleData(rom);
            locations = new OwLocationData(rom);
            domains   = new DomainData(rom);

            data = replacement;

            ShipLocations = new ShipLocations(locations, data.ShipLocations);
        }
コード例 #21
0
        public TeleportShuffle(FF1Rom _rom, OwMapExchangeData data)
        {
            rom = _rom;

            if (data?.OverworldCoordinates != null)
            {
                OverworldCoordinates = data.OverworldCoordinates.Select(kv => (Enum.Parse <OverworldTeleportIndex>(kv.Key), new Coordinate(kv.Value.X, kv.Value.Y, CoordinateLocale.Overworld))).ToDictionary(kv => kv.Item1, kv => kv.Item2);
            }
            else
            {
                OverworldCoordinates = VanillaOverworldCoordinates;
            }
        }
コード例 #22
0
        public OwMapExchange(FF1Rom _rom, OverworldMap _overworldMap, string _name)
        {
            rom          = _rom;
            overworldMap = _overworldMap;
            name         = _name;

            exit      = new ExitTeleData(rom);
            locations = new OwLocationData(rom);
            domains   = new DomainData(rom);

            data = LoadJson(name);

            ShipLocations = new ShipLocations(locations, data.ShipLocations);
        }
コード例 #23
0
        public ExtSpoiler(FF1Rom _rom, SanityCheckerV2 _checker, ShopData _shopData, ItemNames _itemsText, List <IRewardSource> _itemPlacement, OverworldMap _overworldMap, IncentiveData _incentivesData, GearPermissions _weaponPermissions, GearPermissions _armorPermissions, Flags _flags)
        {
            rom               = _rom;
            checker           = _checker;
            shopData          = _shopData;
            itemsText         = _itemsText;
            itemPlacement     = _itemPlacement;
            overworldMap      = _overworldMap;
            incentivesData    = _incentivesData;
            weaponPermissions = _weaponPermissions;
            armorPermissions  = _armorPermissions;
            flags             = _flags;

            logic       = new SCLogic(rom, checker.Main, itemPlacement, flags, false);
            weapons     = Weapon.LoadAllWeapons(rom, flags).ToList();
            armors      = Armor.LoadAllArmors(rom, flags).ToList();
            magicSpells = rom.GetSpells();
        }
コード例 #24
0
        public SanityCheckerV2(List <Map> _maps, OverworldMap _overworldMap, NPCdata _npcdata, FF1Rom _rom, ItemShopSlot _declaredShopSlot, ShipLocations _shiplocations)
        {
            rom          = _rom;
            overworldMap = _overworldMap;
            maps         = _maps;
            npcdata      = _npcdata;

            locations = new OwLocationData(rom);
            locations.LoadData();

            Shiplocations = _shiplocations;

            allTreasures     = ItemLocations.AllTreasures.Select(r => r as TreasureChest).Where(r => r != null).ToDictionary(r => (byte)(r.Address - 0x3100));
            allQuestNpcs     = ItemLocations.AllNPCItemLocations.Select(r => r as MapObject).Where(r => r != null).ToDictionary(r => r.ObjectId);
            declaredShopSlot = _declaredShopSlot;

            UpdateNpcRequirements();

            Main = new SCMain(_maps, _overworldMap, _npcdata, locations, _rom);
        }
コード例 #25
0
        public override void Put(FF1Rom rom)
        {
            if (_useVanillaRoutineAddress)
            {
                base.Put(rom);
                return;
            }

            if (_requiredItemTrade != Item.None)
            {
                rom.Put(_objectRoutineAddress, _itemTradeRoutineAddress);
                rom.Put(Address - _giftItemIndex, new[] { (byte)_requiredItemTrade });
            }
            else
            {
                rom.Put(_objectRoutineAddress, _eventFlagRoutineAddress);
                rom.Put(Address - _giftItemIndex, new[] { (byte)_requiredGameEventFlag });
            }

            base.Put(rom);
        }
コード例 #26
0
        public ExtensiveHints(MT19337 _rng, NPCdata _npcData, Flags _flags, OverworldMap _overworldMap, FF1Rom _rom)
        {
            rng          = _rng;
            npcData      = _npcData;
            flags        = _flags;
            overworldMap = _overworldMap;
            rom          = _rom;

            hintSources = new IHintSource[]
            {
                new LooseFloorHintSource(rng, npcData, flags, overworldMap, rom),
                new LooseNameHintSource(rng, npcData, flags, overworldMap, rom),
                new IncNameHintSource(rng, npcData, flags, overworldMap, rom),
                new FloorHintsHintSource(rng, npcData, flags, overworldMap, rom),
                new EqFloorHintSource(rng, npcData, flags, overworldMap, rom),
            };

            hintPlacementProviders = new IHintPlacementProvider[]
            {
                new DefaultHintPlacmentProvider(rng, npcData, flags, overworldMap, rom),
            };
        }
コード例 #27
0
        public OwMapExchange(FF1Rom _rom, Flags flags, OverworldMap _overworldMap, MT19337 rng)
        {
            rom          = _rom;
            overworldMap = _overworldMap;

            exit      = new ExitTeleData(rom);
            locations = new OwLocationData(rom);
            domains   = new DomainData(rom);

            string name;

            if (flags.OwShuffledAccess && flags.OwUnsafeStart)
            {
                name = "unsafe256.zip";
            }
            else if (flags.OwShuffledAccess && !flags.OwUnsafeStart)
            {
                name = "shuffled256.zip";
            }
            else
            {
                name = "normal256.zip";
            }

            var assembly     = System.Reflection.Assembly.GetExecutingAssembly();
            var resourcePath = assembly.GetManifestResourceNames().First(str => str.EndsWith(name));

            using Stream stream = assembly.GetManifestResourceStream(resourcePath);

            var archive = new ZipArchive(stream);

            var maplist = archive.Entries.Where(e => e.Name.EndsWith(".json")).Select(e => e.Name).ToList();

            var map = maplist.PickRandom(rng);

            data = LoadJson(archive.GetEntry(map).Open());

            ShipLocations = new ShipLocations(locations, data.ShipLocations);
        }
コード例 #28
0
        public TileSet(FF1Rom _rom, byte idx)
        {
            if (idx == OverworldIndex)
            {
                TileProperties = new MemTable <TileProp>(_rom, 0x0000, 128);

                TopLeftTiles     = new MemTable <byte>(_rom, 0x0100, 128);
                TopRightTiles    = new MemTable <byte>(_rom, 0x0180, 128);
                BottomLeftTiles  = new MemTable <byte>(_rom, 0x0200, 128);
                BottomRightTiles = new MemTable <byte>(_rom, 0x0280, 128);

                TileAttributes = new MemTable <byte>(_rom, 0x0300, 128);
            }
            else
            {
                TileProperties = new MemTable <TileProp>(_rom, 0x800 + 0x100 * idx, 128);
                TileAttributes = new MemTable <byte>(_rom, 0x400 + 0x80 * idx, 128);

                TopLeftTiles     = new MemTable <byte>(_rom, 0x1000 + 0x200 * idx, 128);
                TopRightTiles    = new MemTable <byte>(_rom, 0x1080 + 0x200 * idx, 128);
                BottomLeftTiles  = new MemTable <byte>(_rom, 0x1100 + 0x200 * idx, 128);
                BottomRightTiles = new MemTable <byte>(_rom, 0x1180 + 0x200 * idx, 128);
            }
        }
コード例 #29
0
        public void BuildExpChests()
        {
            rom.PutInBank(0x1F, 0xDDD0, Blob.FromHex("A9B648A9FF48A9114C03FE8A20DA8760"));

            int expChestCountPercent = rng.Between(flags.ExpChestConversionMin, flags.ExpChestConversionMax);

            int    expChestCount = treasureData.Data.Where(g => g >= Item.Gold10).Count() * expChestCountPercent / 100;
            double lowScale      = (double)flags.ExpChestMinReward / (double)BaseExp;
            double highScale     = (double)flags.ExpChestMaxReward / (double)BaseExp;

            if (expChestCount == 0)
            {
                return;
            }

            LoadData();

            var unusedGoldDic = new HashSet <int>(rom.UnusedGoldItems.Cast <int>());

            // construct a dictionary and get a shuffled index into it.
            var goldItems = ItemLists.AllGoldTreasure.Select(g => (item: g, price: itemPrices[g], name: itemNames[(int)g])).ToList();

            goldItems.Shuffle(rng);
            var goldItemsDic = goldItems.Select((g, i) => (shuffleindex: i, item: g.item, price: g.price, name: g.name)).ToDictionary(g => g.item);

            var expItems = new HashSet <Item>(treasureData.Data
                                              .Where(g => goldItemsDic.ContainsKey(g) && !unusedGoldDic.Contains((int)g))
                                              .Select(g => (item: g, shuffleindex: goldItemsDic[g].shuffleindex))
                                              .OrderBy(g => g.shuffleindex)
                                              .Take(expChestCount)
                                              .Select(g => g.item)
                                              .Distinct());

            var firstExpItem = RepackGoldExpItems(goldItemsDic, expItems, unusedGoldDic);

            for (int i = (int)firstExpItem; i < 176; i++)
            {
                if (unusedGoldDic.Contains(i))
                {
                    continue;
                }

                var e = (Item)i;

                var exp = (ushort)Math.Min(Math.Max(FF1Rom.RangeScale(BaseExp, lowScale, highScale, 1.0, rng), 0), 65535);
                itemPrices[e]     = exp;
                itemNames[(int)e] = exp.ToString() + " EXP";
            }

            FirstExpItem = firstExpItem;
            if (flags.Archipelago)
            {
                rom.PutInBank(0x11, 0xB446, new byte[] { (byte)firstExpItem });
            }
            else
            {
                rom.PutInBank(0x11, 0xB447, new byte[] { (byte)firstExpItem });
            }


            var result = treasureData.Data.Where(x => x > Item.Gold10).OrderBy(x => x).Select(x => itemNames[(int)x]).ToList();

            StoreData();
        }
コード例 #30
0
        public List <IRewardSource> PlaceSaneItems(MT19337 rng, FF1Rom rom)
        {
            _rom = rom;

            var incentivePool = _incentivesData.IncentiveItems.Where(x => _allTreasures.Contains(x)).ToList();
            var forcedItems   = _incentivesData.ForcedItemPlacements.ToList();
            var removedItems  = _incentivesData.RemovedItems.ToList();

            var unincentivizedQuestItems =
                ItemLists.AllQuestItems
                .Where(x => !incentivePool.Contains(x) &&
                       _allTreasures.Contains(x) &&
                       !forcedItems.Any(y => y.Item == x) &&
                       !removedItems.Contains(x))
                .ToList();

            var shards = new List <Item>();

            var treasurePool = _allTreasures.ToList();

            bool jingleGuaranteedDefenseItem = true;
            bool jingleGuaranteedPowerItem   = true;

            if (_flags.GuaranteedDefenseItem != GuaranteedDefenseItem.None && !(_flags.ItemMagicMode == ItemMagicMode.None) && !incentivePool.Contains(Item.PowerRod))
            {
                unincentivizedQuestItems.Add(Item.PowerRod);
                jingleGuaranteedDefenseItem = false;
            }

            if (_flags.GuaranteedPowerItem != GuaranteedPowerItem.None && !(_flags.ItemMagicMode == ItemMagicMode.None) && !incentivePool.Contains(Item.PowerGauntlets))
            {
                unincentivizedQuestItems.Add(Item.PowerGauntlets);
                jingleGuaranteedPowerItem = false;
            }

            foreach (var incentive in incentivePool)
            {
                treasurePool.Remove(incentive);
            }
            foreach (var placement in forcedItems)
            {
                treasurePool.Remove(placement.Item);
            }
            foreach (var questItem in unincentivizedQuestItems)
            {
                treasurePool.Remove(questItem);
            }
            foreach (var item in removedItems)
            {
                treasurePool.Remove(item);
            }
            while (treasurePool.Remove(Item.Shard))
            {
                shards.Add(Item.Shard);
            }

            ItemPlacementContext ctx = new ItemPlacementContext
            {
                Forced         = forcedItems,
                Incentivized   = incentivePool,
                Unincentivized = unincentivizedQuestItems,
                Shards         = shards,
                Removed        = removedItems,
                AllTreasures   = treasurePool.ToList(),
            };

            ItemPlacementResult  result      = DoSanePlacement(rng, ctx);
            List <IRewardSource> placedItems = result.PlacedItems;

            treasurePool = result.RemainingTreasures;

            //setup jingle for "incentive treasures", the placed items should just be key items, loose incentive items
            if (_flags.IncentiveChestItemsFanfare)
            {
                foreach (var placedItem in placedItems)
                {
                    //dont make shards jingle that'd be annoying
                    //dont make free items that get replaced, aka cabins, jingle
                    if (placedItem is TreasureChest && placedItem.Item != Item.Shard &&
                        placedItem.Item != ReplacementItem)
                    {
                        if ((placedItem.Item == Item.PowerGauntlets && !jingleGuaranteedPowerItem) || (placedItem.Item == Item.PowerRod && !jingleGuaranteedDefenseItem))
                        {
                            continue;
                        }

                        rom.Put(placedItem.Address - FF1Rom.TreasureOffset + FF1Rom.TreasureJingleOffset, new byte[] { (byte)placedItem.Item });
                    }
                }
            }

            // 8. Place all remaining unincentivized treasures or incentivized non-quest items that weren't placed
            var itemLocationPool = _incentivesData.AllValidItemLocations.ToList();

            itemLocationPool = itemLocationPool.Where(x => !x.IsUnused && !placedItems.Any(y => y.Address == x.Address)).ToList();

            MoreConsumableChests.Work(_flags, treasurePool, rng);

            if ((bool)_flags.GuaranteedMasamune && !incentivePool.Contains(Item.Masamune) && (bool)_flags.SendMasamuneHome)
            {
                // Remove Masamune from treasure pool (This will also causes Masamune to not be placed by RandomLoot)
                treasurePool.Remove(Item.Masamune);
            }

            // Use cabins to balance item population
            int poolDifference = itemLocationPool.Count() - treasurePool.Count();

            if (poolDifference < 0)
            {
                for (int i = 0; i > poolDifference; i--)
                {
                    treasurePool.Remove(Item.Cabin);
                }
            }
            else if (poolDifference > 0)
            {
                treasurePool.AddRange(Enumerable.Repeat(Item.Cabin, poolDifference));
            }

            Debug.Assert(treasurePool.Count() == itemLocationPool.Count());


            List <IRewardSource> normalTreasures = new();

            var randomizeTreasureMode = (_flags.RandomizeTreasure == RandomizeTreasureMode.Random) ? (RandomizeTreasureMode)rng.Between(0, 2) : _flags.RandomizeTreasure;

            if (randomizeTreasureMode != RandomizeTreasureMode.None)
            {
                IItemGenerator generator;

                // We want to leave out anything incentivized (and thus already placed), but
                // add all the other stuff that you can't find in vanilla.
                var randomTreasure = treasurePool.ToList();

                if (randomizeTreasureMode == RandomizeTreasureMode.DeepDungeon)
                {
                    generator = new DeepDungeonItemGenerator(itemLocationPool, rom.UnusedGoldItems, removedItems, normalTreasures, (_flags.GameMode == GameModes.DeepDungeon), _flags.Etherizer, rom);
                }
                else
                {
                    generator = new ItemGenerator(randomTreasure, rom.UnusedGoldItems, removedItems, _flags.WorldWealth);
                }

                treasurePool = treasurePool.Select(treasure => generator.GetItem(rng)).ToList();
            }

            if ((bool)_flags.BetterTrapChests && randomizeTreasureMode != RandomizeTreasureMode.DeepDungeon)
            {
                // First we'll make a list of all 'notable' treasure.
                var notableTreasureList = new List <Item>()
                                          .Concat(ItemLists.UberTier)
                                          .Concat(ItemLists.LegendaryWeaponTier)
                                          .Concat(ItemLists.LegendaryArmorTier)
                                          .Concat(ItemLists.RareWeaponTier)
                                          .Concat(ItemLists.RareArmorTier);
                // Convert the list to a HashSet since we'll be doing lookups in it.
                var notableTreasure = new HashSet <Item>(notableTreasureList);

                // We sort the treasure pool based on value (sort of) and pull out the highest ranked ones to put
                // in the trap chests we picked out.
                var notableTreasurePool = treasurePool.Where(item => notableTreasure.Contains(item)).ToList();

                // Since some chests might be incentivized, remove those that aren't in the pool.
                var trapChestPool = TrapChests.Where(chest => itemLocationPool.Contains(chest));

                foreach (var chest in trapChestPool)
                {
                    // It seems unlikely that is possible, but just in case.
                    if (!notableTreasurePool.Any())
                    {
                        break;
                    }

                    // Pick a random treasure and place it.
                    var treasure = notableTreasurePool.SpliceRandom(rng);
                    placedItems.Add(NewItemPlacement(chest, treasure));

                    // Since it was placed, remove both the item and location from the remaining pool.
                    treasurePool.Remove(treasure);
                    itemLocationPool.Remove(chest);
                }

                // This should still be true at the end, so make sure it is
                Debug.Assert(treasurePool.Count() == itemLocationPool.Count());
            }

            if (randomizeTreasureMode == RandomizeTreasureMode.DeepDungeon && _flags.DeepDungeonGenerator == DeepDungeonGeneratorMode.Progressive)
            {
                placedItems.AddRange(normalTreasures);
            }
            else
            {
                treasurePool.Shuffle(rng);
                itemLocationPool.Shuffle(rng);

                var leftovers = treasurePool.Zip(itemLocationPool, (treasure, location) => NewItemPlacement(location, treasure));
                placedItems.AddRange(leftovers);
            }

            //chest order placement
            var chestOrderPool = treasurePool;

            if (_flags.ShardHunt)
            {
                //add the shards back into the chest order pool
                chestOrderPool = chestOrderPool.Concat(shards).ToList();
            }

            chestOrderPool.Shuffle(rng);

            for (int i = 0; i < chestOrderPool.Count; i++)
            {
                rom.Put(FF1Rom.TreasureChestOrderOffset + i, new byte[] { (byte)chestOrderPool[i] });
            }

            return(placedItems);
        }