Exemple #1
0
        public static readonly List <int> UsedTreasureIndices = Enumerable.Range(0, 256).Except(UnusedTreasureIndices).ToList();        // This maps a compacted list back to the game's array, skipping the unused slots.

        public List <IRewardSource> ShuffleTreasures(MT19337 rng,
                                                     IItemPlacementFlags flags,
                                                     IncentiveData incentivesData,
                                                     ItemShopSlot caravanItemLocation,
                                                     Dictionary <MapLocation, List <MapChange> > mapLocationRequirements)
        {
            var vanillaNPCs = !flags.NPCItems && !flags.NPCFetchItems;

            if (!vanillaNPCs)
            {
                EnableBridgeShipCanalAnywhere();
                EnableNPCsGiveAnyItem();
                // This extends Vampire's routine to set a flag for Sarda, but it also clobers Sarda's routine
                if (!flags.EarlySarda)
                {
                    Put(0x393E1, Blob.FromHex("207F90A51160"));
                }
            }

            var treasureBlob = Get(TreasureOffset, TreasureSize * TreasureCount);
            var treasurePool = UsedTreasureIndices.Select(x => (Item)treasureBlob[x])
                               .Concat(ItemLists.AllNonTreasureChestItems).ToList();

            if (flags.ShardHunt)
            {
                treasurePool = treasurePool.Select(ShardHuntTreasureSelector).ToList();
                int shardsAdded = treasurePool.Count(item => item == Item.Shard);
                Debug.Assert(shardsAdded == TotalOrbsToInsert);
            }

            var placedItems =
                ItemPlacement.PlaceSaneItems(rng,
                                             flags,
                                             incentivesData,
                                             treasurePool,
                                             caravanItemLocation,
                                             mapLocationRequirements);

            if (flags.FreeBridge)
            {
                placedItems = placedItems.Select(x => x.Item != Item.Bridge ? x : ItemPlacement.NewItemPlacement(x, ReplacementItem)).ToList();
            }
            if (flags.FreeAirship)
            {
                placedItems = placedItems.Select(x => x.Item != Item.Floater ? x : ItemPlacement.NewItemPlacement(x, ReplacementItem)).ToList();
            }

            // Output the results to the ROM
            foreach (var item in placedItems.Where(x => !x.IsUnused && x.Address < 0x80000 && (!vanillaNPCs || x is TreasureChest)))
            {
                //Debug.WriteLine(item.SpoilerText);
                item.Put(this);
            }

            MoveShipToRewardSource(placedItems.Find(reward => reward.Item == Item.Ship));
            return(placedItems);
        }
Exemple #2
0
        public static readonly List <int> UsedTreasureIndices = Enumerable.Range(0, 256).Except(UnusedTreasureIndices).ToList();        // This maps a compacted list back to the game's array, skipping the unused slots.

        public List <IRewardSource> ShuffleTreasures(MT19337 rng,
                                                     IItemPlacementFlags flags,
                                                     IncentiveData incentivesData,
                                                     ItemShopSlot caravanItemLocation,
                                                     OverworldMap overworldMap,
                                                     TeleportShuffle teleporters)
        {
            Dictionary <MapLocation, Tuple <List <MapChange>, AccessRequirement> > fullFloorRequirements = overworldMap.FullLocationRequirements;
            Dictionary <MapLocation, OverworldTeleportIndex> overridenOverworld = overworldMap.OverriddenOverworldLocations;

            var vanillaNPCs = !(flags.NPCItems ?? false) && !(flags.NPCFetchItems ?? false);

            if (!vanillaNPCs)
            {
                EnableBridgeShipCanalAnywhere();
                EnableNPCsGiveAnyItem();
                // This extends Vampire's routine to set a flag for Sarda, but it also clobers Sarda's routine
                if (!(bool)flags.EarlySarda)
                {
                    Put(0x393E1, Blob.FromHex("207F90A51160"));
                }
            }

            var treasureBlob = Get(TreasureOffset, TreasureSize * TreasureCount);
            var treasurePool = UsedTreasureIndices.Select(x => (Item)treasureBlob[x])
                               .Concat(ItemLists.AllNonTreasureChestItems).ToList();

            if (flags.ShardHunt)
            {
                treasurePool = treasurePool.Select(ShardHuntTreasureSelector).ToList();
                int shardsAdded = treasurePool.Count(item => item == Item.Shard);
                Debug.Assert(shardsAdded == TotalOrbsToInsert);
            }

            ItemPlacement placement   = ItemPlacement.Create(flags, incentivesData, treasurePool, caravanItemLocation, overworldMap);
            var           placedItems = placement.PlaceSaneItems(rng);

            // Output the results to the ROM
            foreach (var item in placedItems.Where(x => !x.IsUnused && x.Address < 0x80000 && (!vanillaNPCs || x is TreasureChest)))
            {
                //Debug.WriteLine(item.SpoilerText);
                item.Put(this);
            }
            // Move the ship someplace closer to where it really ends up.
            if (!(flags.FreeShip ?? false))
            {
                MapLocation shipLocation = placedItems.Find(reward => reward.Item == Item.Ship).MapLocation;
                if (overridenOverworld != null && overridenOverworld.TryGetValue(shipLocation, out var overworldIndex))
                {
                    shipLocation = teleporters.OverworldMapLocations.TryGetValue(overworldIndex, out var vanillaShipLocation) ? vanillaShipLocation : shipLocation;
                }
                MoveShipToRewardSource(shipLocation);
            }
            return(placedItems);
        }
Exemple #3
0
        public static readonly List <int> UsedTreasureIndices = Enumerable.Range(0, 256).Except(UnusedTreasureIndices).ToList();        // This maps a compacted list back to the game's array, skipping the unused slots.

        public List <IRewardSource> ShuffleTreasures(MT19337 rng,
                                                     ITreasureShuffleFlags flags,
                                                     IncentiveData incentivesData,
                                                     ItemShopSlot caravanItemLocation,
                                                     Dictionary <MapLocation, List <MapChange> > mapLocationRequirements)
        {
            if (flags.NPCItems)
            {
                EnableBridgeShipCanalAnywhere();
                EnableNPCsGiveAnyItem();
                // This extends Vampire's routine to set a flag for Sarda, but it also clobers Sarda's routine
                if (!flags.EarlyRod)
                {
                    Put(0x393E1, Blob.FromHex("207F90A51160"));
                }
            }

            var treasureBlob = Get(TreasureOffset, TreasureSize * TreasureCount);
            var treasurePool = UsedTreasureIndices.Select(x => (Item)treasureBlob[x])
                               .Concat(ItemLists.AllNonTreasureChestItems).ToList();

            if (flags.OrbHunt)
            {
                treasurePool = treasurePool.Select(OrbHuntTreasureSelector).ToList();
                System.Diagnostics.Debug.Assert(treasurePool.Count(item => item == Item.Shard) == TotalOrbsToInsert);
            }

            var placedItems =
                ItemPlacement.PlaceSaneItems(rng,
                                             flags,
                                             incentivesData,
                                             treasurePool,
                                             caravanItemLocation,
                                             mapLocationRequirements);

            // Output the results tothe ROM
            foreach (var item in placedItems.Where(x => !x.IsUnused && x.Address < 0x80000 && !incentivesData.ForcedItemPlacements.Any(y => y.Address == x.Address)))
            {
                //Debug.WriteLine(item.SpoilerText);
                item.Put(this);
            }
            return(placedItems);
        }
        public IncentiveData(MT19337 rng, IIncentiveFlags flags, OverworldMap map)
        {
            Dictionary <MapLocation, Tuple <List <MapChange>, AccessRequirement> > fullLocationRequirements = map.FullLocationRequirements;
            var forcedItemPlacements = ItemLocations.AllOtherItemLocations.ToList();

            if (!flags.NPCItems)
            {
                forcedItemPlacements.AddRange(ItemLocations.AllNPCFreeItemLocations);
            }
            if (!flags.NPCFetchItems)
            {
                forcedItemPlacements.AddRange(ItemLocations.AllNPCFetchItemLocations);
            }
            if (!flags.Treasures)
            {
                forcedItemPlacements.AddRange(ItemLocations.AllTreasures);
            }
            var incentivePool = new List <Item>();

            if (flags.IncentivizeBridge)
            {
                incentivePool.Add(Item.Bridge);
            }
            if (flags.IncentivizeShip)
            {
                incentivePool.Add(Item.Ship);
            }
            if (flags.IncentivizeCanal)
            {
                incentivePool.Add(Item.Canal);
            }
            if (flags.IncentivizeLute)
            {
                incentivePool.Add(Item.Lute);
            }
            if (flags.IncentivizeCrown)
            {
                incentivePool.Add(Item.Crown);
            }
            if (flags.IncentivizeCrystal)
            {
                incentivePool.Add(Item.Crystal);
            }
            if (flags.IncentivizeHerb)
            {
                incentivePool.Add(Item.Herb);
            }
            if (flags.IncentivizeKey)
            {
                incentivePool.Add(Item.Key);
            }
            if (flags.IncentivizeTnt)
            {
                incentivePool.Add(Item.Tnt);
            }
            if (flags.IncentivizeAdamant)
            {
                incentivePool.Add(Item.Adamant);
            }
            if (flags.IncentivizeSlab)
            {
                incentivePool.Add(Item.Slab);
            }
            if (flags.IncentivizeRuby)
            {
                incentivePool.Add(Item.Ruby);
            }
            if (flags.IncentivizeRod)
            {
                incentivePool.Add(Item.Rod);
            }
            if (flags.IncentivizeFloater)
            {
                incentivePool.Add(Item.Floater);
            }
            if (flags.IncentivizeChime)
            {
                incentivePool.Add(Item.Chime);
            }
            if (flags.IncentivizeTail)
            {
                incentivePool.Add(Item.Tail);
            }
            if (flags.IncentivizeCube)
            {
                incentivePool.Add(Item.Cube);
            }
            if (flags.IncentivizeBottle)
            {
                incentivePool.Add(Item.Bottle);
            }
            if (flags.IncentivizeOxyale)
            {
                incentivePool.Add(Item.Oxyale);
            }
            if (flags.IncentivizeCanoe)
            {
                incentivePool.Add(Item.Canoe);
            }

            if (flags.IncentivizeXcalber)
            {
                incentivePool.Add(Item.Xcalber);
            }
            if (flags.IncentivizeMasamune)
            {
                incentivePool.Add(Item.Masamune);
            }
            if (flags.IncentivizeRibbon)
            {
                incentivePool.Add(Item.Ribbon);
            }
            if (flags.IncentivizeRibbon2)
            {
                incentivePool.Add(Item.Ribbon);
            }
            if (flags.IncentivizeOpal)
            {
                incentivePool.Add(Item.Opal);
            }
            if (flags.Incentivize65K)
            {
                incentivePool.Add(Item.Gold65000);
            }
            if (flags.IncentivizeBad)
            {
                incentivePool.Add(Item.Cloth);
            }
            if (flags.IncentivizeDefCastArmor)
            {
                incentivePool.Add(Item.WhiteShirt);
            }
            if (flags.IncentivizeOffCastArmor)
            {
                incentivePool.Add(Item.BlackShirt);
            }
            if (flags.IncentivizeOtherCastArmor)
            {
                incentivePool.Add(Item.PowerGauntlets);
            }
            if (flags.IncentivizeDefCastWeapon)
            {
                incentivePool.Add(Item.Defense);
            }
            if (flags.IncentivizeOffCastWeapon)
            {
                incentivePool.Add(Item.ThorHammer);
            }
            if (flags.IncentivizeOtherCastWeapon)
            {
                incentivePool.Add(Item.BaneSword);
            }

            var incentiveLocationPool = new List <IRewardSource>();

            if (flags.IncentivizeKingConeria)
            {
                incentiveLocationPool.Add(ItemLocations.KingConeria);
            }
            if (flags.IncentivizePrincess)
            {
                incentiveLocationPool.Add(ItemLocations.Princess);
            }
            if (flags.IncentivizeMatoya)
            {
                incentiveLocationPool.Add(ItemLocations.Matoya);
            }
            if (flags.IncentivizeBikke)
            {
                incentiveLocationPool.Add(ItemLocations.Bikke);
            }
            if (flags.IncentivizeElfPrince)
            {
                incentiveLocationPool.Add(ItemLocations.ElfPrince);
            }
            if (flags.IncentivizeAstos)
            {
                incentiveLocationPool.Add(ItemLocations.Astos);
            }
            if (flags.IncentivizeNerrick)
            {
                incentiveLocationPool.Add(ItemLocations.Nerrick);
            }
            if (flags.IncentivizeSmith)
            {
                incentiveLocationPool.Add(ItemLocations.Smith);
            }
            if (flags.IncentivizeSarda)
            {
                incentiveLocationPool.Add(ItemLocations.Sarda);
            }
            if (flags.IncentivizeCanoeSage)
            {
                incentiveLocationPool.Add(ItemLocations.CanoeSage);
            }
            if (flags.IncentivizeCubeBot)
            {
                incentiveLocationPool.Add(ItemLocations.CubeBot);
            }
            if (flags.IncentivizeFairy)
            {
                incentiveLocationPool.Add(ItemLocations.Fairy);
            }
            if (flags.IncentivizeLefein)
            {
                incentiveLocationPool.Add(ItemLocations.Lefein);
            }
            if (flags.IncentivizeVolcano)
            {
                incentiveLocationPool.Add(ItemLocations.VolcanoMajor);
            }
            if (flags.IncentivizeEarth)
            {
                incentiveLocationPool.Add(ItemLocations.EarthCaveMajor);
            }
            if (flags.IncentivizeMarsh)
            {
                incentiveLocationPool.Add(ItemLocations.MarshCaveMajor);
            }
            if (flags.IncentivizeMarshKeyLocked)
            {
                incentiveLocationPool.Add(ItemLocations.MarshCave13);
            }
            if (flags.IncentivizeSkyPalace)
            {
                incentiveLocationPool.Add(ItemLocations.SkyPalaceMajor);
            }
            if (flags.IncentivizeSeaShrine)
            {
                incentiveLocationPool.Add(ItemLocations.SeaShrineMajor);
            }
            if (flags.IncentivizeConeria)
            {
                incentiveLocationPool.Add(ItemLocations.ConeriaMajor);
            }
            if (flags.IncentivizeIceCave)
            {
                incentiveLocationPool.Add(ItemLocations.IceCaveMajor);
            }
            if (flags.IncentivizeOrdeals)
            {
                incentiveLocationPool.Add(ItemLocations.OrdealsMajor);
            }
            if (flags.IncentivizeCaravan)
            {
                incentiveLocationPool.Add(ItemLocations.CaravanItemShop1);
            }
            var itemLocationPool =
                ItemLocations.AllTreasures.Concat(ItemLocations.AllNPCItemLocations)
                .Where(x => !x.IsUnused && !forcedItemPlacements.Any(y => y.Address == x.Address))
                .ToList();

            if (flags.CrownlessOrdeals)
            {
                forcedItemPlacements =
                    forcedItemPlacements
                    .Select(x => ((x as TreasureChest)?.AccessRequirement.HasFlag(AccessRequirement.Crown) ?? false)
                                                                ? new TreasureChest(x, x.Item, x.AccessRequirement & ~AccessRequirement.Crown)
                                                                : x).ToList();
                itemLocationPool =
                    itemLocationPool
                    .Select(x => ((x as TreasureChest)?.AccessRequirement.HasFlag(AccessRequirement.Crown) ?? false)
                                                                ? new TreasureChest(x, x.Item, x.AccessRequirement & ~AccessRequirement.Crown)
                                                                : x).ToList();
                incentiveLocationPool =
                    incentiveLocationPool
                    .Select(x => ((x as TreasureChest)?.AccessRequirement.HasFlag(AccessRequirement.Crown) ?? false)
                                                        ? new TreasureChest(x, x.Item, x.AccessRequirement & ~AccessRequirement.Crown)
                                                        : x).ToList();
            }
            if (flags.EarlySage)
            {
                forcedItemPlacements =
                    forcedItemPlacements
                    .Select(x => x.Address == ItemLocations.CanoeSage.Address
                                                                        ? new MapObject(ObjectId.CanoeSage, MapLocation.CrescentLake, x.Item)
                                                                        : x).ToList();
                itemLocationPool =
                    itemLocationPool
                    .Select(x => x.Address == ItemLocations.CanoeSage.Address
                                                                        ? new MapObject(ObjectId.CanoeSage, MapLocation.CrescentLake, x.Item)
                                                                        : x).ToList();
                incentiveLocationPool =
                    incentiveLocationPool
                    .Select(x => x.Address == ItemLocations.CanoeSage.Address
                                                                        ? new MapObject(ObjectId.CanoeSage, MapLocation.CrescentLake, x.Item)
                                                                        : x).ToList();
            }
            if (flags.EarlySarda)
            {
                forcedItemPlacements =
                    forcedItemPlacements
                    .Select(x => x.Address == ItemLocations.Sarda.Address
                                                                ? new MapObject(ObjectId.Sarda, MapLocation.SardasCave, x.Item)
                                                                : x).ToList();
                itemLocationPool =
                    itemLocationPool
                    .Select(x => x.Address == ItemLocations.Sarda.Address
                                                                ? new MapObject(ObjectId.Sarda, MapLocation.SardasCave, x.Item)
                                                                : x).ToList();
                incentiveLocationPool =
                    incentiveLocationPool
                    .Select(x => x.Address == ItemLocations.Sarda.Address
                                                                ? new MapObject(ObjectId.Sarda, MapLocation.SardasCave, x.Item)
                                                                : x).ToList();
            }

            MapLocation elfDoctorLocation = map.ObjectiveNPCs[ObjectId.ElfDoc];

            if (elfDoctorLocation != MapLocation.ElflandCastle)
            {
                forcedItemPlacements =
                    forcedItemPlacements
                    .Select(x => x.Address == ItemLocations.ElfPrince.Address
                                                                ? new MapObject(ObjectId.ElfPrince, MapLocation.ElflandCastle, x.Item, AccessRequirement.Herb, ObjectId.ElfDoc, requiredSecondLocation: elfDoctorLocation)
                                                                : x).ToList();
                itemLocationPool =
                    itemLocationPool
                    .Select(x => x.Address == ItemLocations.ElfPrince.Address
                                                                ? new MapObject(ObjectId.ElfPrince, MapLocation.ElflandCastle, x.Item, AccessRequirement.Herb, ObjectId.ElfDoc, requiredSecondLocation: elfDoctorLocation)
                                                                : x).ToList();
                incentiveLocationPool =
                    incentiveLocationPool
                    .Select(x => x.Address == ItemLocations.ElfPrince.Address
                                                                ? new MapObject(ObjectId.ElfPrince, MapLocation.ElflandCastle, x.Item, AccessRequirement.Herb, ObjectId.ElfDoc, requiredSecondLocation: elfDoctorLocation)
                                                                : x).ToList();
            }

            MapLocation unneLocation = map.ObjectiveNPCs[ObjectId.Unne];

            if (unneLocation != MapLocation.Melmond)
            {
                forcedItemPlacements =
                    forcedItemPlacements
                    .Select(x => x.Address == ItemLocations.Lefein.Address
                                                                ? new MapObject(ObjectId.Lefein, MapLocation.Lefein, x.Item, AccessRequirement.Slab, ObjectId.Unne, requiredSecondLocation: unneLocation)
                                                                : x).ToList();
                itemLocationPool =
                    itemLocationPool
                    .Select(x => x.Address == ItemLocations.Lefein.Address
                                                                ? new MapObject(ObjectId.Lefein, MapLocation.Lefein, x.Item, AccessRequirement.Slab, ObjectId.Unne, requiredSecondLocation: unneLocation)
                                                                : x).ToList();
                incentiveLocationPool =
                    incentiveLocationPool
                    .Select(x => x.Address == ItemLocations.Lefein.Address
                                                                ? new MapObject(ObjectId.Lefein, MapLocation.Lefein, x.Item, AccessRequirement.Slab, ObjectId.Unne, requiredSecondLocation: unneLocation)
                                                                : x).ToList();
            }

            foreach (var item in forcedItemPlacements.Select(x => x.Item))
            {
                incentivePool.Remove(item);
            }

            var validKeyLocations = new List <IRewardSource> {
                ItemLocations.ElfPrince
            };
            var validBridgeLocations = new List <IRewardSource> {
                ItemLocations.KingConeria
            };
            var validShipLocations = new List <IRewardSource> {
                ItemLocations.Bikke
            };
            var validCanoeLocations = new List <IRewardSource> {
                ItemLocations.CanoeSage
            };

            if (flags.NPCFetchItems)
            {
                var validKeyMapLocations = ItemPlacement.AccessibleMapLocations(~(AccessRequirement.BlackOrb | AccessRequirement.Key), MapChange.All, fullLocationRequirements);
                validKeyLocations = itemLocationPool.Where(x => validKeyMapLocations.Contains(x.MapLocation) &&
                                                           validKeyMapLocations.Contains((x as MapObject)?.SecondLocation ?? MapLocation.StartingLocation)).ToList();
                var keyPlacementRank = rng.Between(1, incentivePool.Count);
                if (incentivePool.Contains(Item.Key) && incentiveLocationPool.Any(x => validKeyLocations.Any(y => y.Address == x.Address)) && keyPlacementRank <= incentiveLocationPool.Count)
                {
                    validKeyLocations = validKeyLocations.Where(x => incentiveLocationPool.Any(y => y.Address == x.Address)).ToList();
                }
                else if (!flags.IncentivizeKey && incentivePool.Count >= incentiveLocationPool.Count)
                {
                    validKeyLocations = validKeyLocations.Where(x => !incentiveLocationPool.Any(y => y.Address == x.Address)).ToList();
                }
            }

            if (flags.NPCItems)
            {
                var everythingButCanoe      = ~MapChange.Canoe;
                var everythingButOrbs       = ~AccessRequirement.BlackOrb;
                var startingPotentialAccess = map.StartingPotentialAccess;
                var startingMapLocations    = ItemPlacement.AccessibleMapLocations(startingPotentialAccess, MapChange.None, fullLocationRequirements);
                var validShipMapLocations   = ItemPlacement.AccessibleMapLocations(startingPotentialAccess | AccessRequirement.Crystal, MapChange.Bridge, fullLocationRequirements);
                var validCanoeMapLocations  = ItemPlacement.AccessibleMapLocations(everythingButOrbs, everythingButCanoe, fullLocationRequirements);

                validBridgeLocations =
                    itemLocationPool.Where(x => startingMapLocations.Contains(x.MapLocation) &&
                                           startingMapLocations.Contains((x as MapObject)?.SecondLocation ?? MapLocation.StartingLocation)).ToList();
                validShipLocations =
                    itemLocationPool.Where(x => validShipMapLocations.Contains(x.MapLocation) &&
                                           validShipMapLocations.Contains((x as MapObject)?.SecondLocation ?? MapLocation.StartingLocation)).ToList();
                validCanoeLocations =
                    itemLocationPool.Where(x => validCanoeMapLocations.Contains(x.MapLocation) &&
                                           validCanoeMapLocations.Contains((x as MapObject)?.SecondLocation ?? MapLocation.StartingLocation)).ToList();

                var canoePlacementRank   = rng.Between(1, incentivePool.Count);
                var validCanoeIncentives = validCanoeLocations.Where(x => incentiveLocationPool.Any(y => y.Address == x.Address)).ToList();
                if (incentivePool.Contains(Item.Canoe) && canoePlacementRank <= incentiveLocationPool.Count &&
                    validKeyLocations.Union(validCanoeIncentives).Count() > 1)                     // The Key can be placed in at least one place more than than the Canoe
                {
                    validCanoeLocations = validCanoeIncentives;
                }
                else if (!flags.IncentivizeBridge && incentivePool.Count >= incentiveLocationPool.Count)
                {
                    validCanoeLocations = validCanoeLocations.Where(x => !incentiveLocationPool.Any(y => y.Address == x.Address)).ToList();
                }
            }

            ForcedItemPlacements = forcedItemPlacements.ToList();
            IncentiveItems       = incentivePool.ToList();

            BridgeLocations = validBridgeLocations
                              .Where(x => !forcedItemPlacements.Any(y => y.Address == x.Address))
                              .ToList();
            ShipLocations = validShipLocations
                            .Where(x => !forcedItemPlacements.Any(y => y.Address == x.Address))
                            .ToList();
            KeyLocations = validKeyLocations
                           .Where(x => !forcedItemPlacements.Any(y => y.Address == x.Address))
                           .ToList();
            CanoeLocations = validCanoeLocations
                             .Where(x => !forcedItemPlacements.Any(y => y.Address == x.Address))
                             .ToList();
            IncentiveLocations = incentiveLocationPool
                                 .Where(x => !forcedItemPlacements.Any(y => y.Address == x.Address))
                                 .ToList();
            AllValidItemLocations = itemLocationPool.ToList();
        }