public BaseHintPlacementProvider(MT19337 _rng, NPCdata _npcData, Flags _flags, OverworldMap _overworldMap, FF1Rom _rom) { rng = _rng; npcData = _npcData; flags = _flags; overworldMap = _overworldMap; rom = _rom; }
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); }
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); }
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); }
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); }
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(); }
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); }
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), }; }
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); }
public void Randomize(Blob seed, Flags flags) { var rng = new MT19337(BitConverter.ToUInt32(seed, 0)); UpgradeToMMC3(); MakeSpaceIn1F(); EasterEggs(); DynamicWindowColor(); PermanentCaravan(); ShiftEarthOrbDown(); var palettes = OverworldMap.GeneratePalettes(Get(OverworldMap.MapPaletteOffset, MapCount * OverworldMap.MapPaletteSize).Chunk(OverworldMap.MapPaletteSize)); var overworldMap = new OverworldMap(this, flags, palettes); var maps = ReadMaps(); var shopItemLocation = ItemLocations.CaravanItemShop1; if (flags.ModernBattlefield) { EnableModernBattlefield(); } if (flags.TitansTrove) { EnableTitansTrove(maps); } // This has to be done before we shuffle spell levels. if (flags.SpellBugs) { FixSpellBugs(); } if (flags.EnemySpellsTargetingAllies) { FixEnemyAOESpells(); } if (flags.ItemMagic) { ShuffleItemMagic(rng); } if (flags.ShortToFR) { ShortenToFR(maps, flags.PreserveFiendRefights, rng); } if (flags.Treasures && flags.ShardHunt && !flags.ChaosRush) { EnableShardHunt(rng, flags.ExtraShards ? rng.Between(24, 30) : 16, flags.NPCItems); } if (flags.TransformFinalFormation) { TransformFinalFormation((FinalFormation)rng.Between(0, Enum.GetValues(typeof(FinalFormation)).Length - 1)); } var maxRetries = 500; for (var i = 0; i < maxRetries; i++) { try { overworldMap = new OverworldMap(this, flags, palettes); if ((flags.Entrances || flags.Floors || flags.Towns) && flags.Treasures && flags.NPCItems) { overworldMap.ShuffleEntrancesAndFloors(rng, flags); } var incentivesData = new IncentiveData(rng, flags, overworldMap); if (flags.Shops) { var excludeItemsFromRandomShops = flags.Treasures ? incentivesData.ForcedItemPlacements.Select(x => x.Item).Concat(incentivesData.IncentiveItems).ToList() : new List <Item>(); shopItemLocation = ShuffleShops(rng, flags.EnemyStatusAttacks, flags.RandomWares, excludeItemsFromRandomShops); } if (flags.Treasures) { ShuffleTreasures(rng, flags, incentivesData, shopItemLocation, overworldMap); } break; } catch (InsaneException) { Console.WriteLine("Insane seed. Retrying"); if (maxRetries > (i + 1)) { continue; } throw new InvalidOperationException("Failed Sanity Check too many times"); } } if (flags.MagicShops) { ShuffleMagicShops(rng); } if (flags.MagicLevels) { FixWarpBug(); // The warp bug only needs to be fixed if the magic levels are being shuffled ShuffleMagicLevels(rng, flags.MagicPermissions); } if (flags.Rng) { ShuffleRng(rng); } if (flags.EnemyScripts) { ShuffleEnemyScripts(rng, flags.AllowUnsafePirates); } if (flags.EnemySkillsSpells) { ShuffleEnemySkillsSpells(rng); } if (flags.EnemyStatusAttacks) { ShuffleEnemyStatusAttacks(rng, flags.AllowUnsafePirates); } if (flags.EnemyFormationsUnrunnable) { ShuffleUnrunnable(rng); } if (flags.EnemyFormationsSurprise) { ShuffleSurpriseBonus(rng); } if (flags.EnemyFormationsFrequency) { ShuffleEnemyFormations(rng); } if (flags.EnemyTrapTiles) { ShuffleTrapTiles(rng, flags.RandomTrapFormations); } if (flags.OrdealsPillars) { ShuffleOrdeals(rng, maps); } if (flags.SkyCastle4FTeleporters) { ShuffleSkyCastle4F(rng, maps); } if (flags.ConfusedOldMen) { EnableConfusedOldMen(rng); } if (flags.CrownlessOrdeals) { EnableEarlyOrdeals(); } if (flags.ChaosRush) { EnableChaosRush(); } if (flags.EarlySarda && !flags.NPCItems) { EnableEarlySarda(); } if (flags.EarlySage && !flags.NPCItems) { EnableEarlySage(); } if (flags.FreeBridge) { EnableFreeBridge(); } if (flags.FreeAirship) { EnableFreeAirship(); } if (flags.FreeOrbs) { EnableFreeOrbs(); } if (flags.NoPartyShuffle) { DisablePartyShuffle(); } if (flags.SpeedHacks) { EnableSpeedHacks(); } if (flags.IdentifyTreasures) { EnableIdentifyTreasures(); } if (flags.Dash) { EnableDash(); } if (flags.BuyTen) { EnableBuyTen(); } if (flags.WaitWhenUnrunnable) { ChangeUnrunnableRunToWait(); } if (flags.EnableCritNumberDisplay) { EnableCritNumberDisplay(); } if (flags.EasyMode) { EnableEasyMode(); } if (flags.HouseMPRestoration) { FixHouse(); } if (flags.WeaponStats) { FixWeaponStats(); } if (flags.ChanceToRun) { FixChanceToRun(); } if (flags.EnemyStatusAttackBug) { FixEnemyStatusAttackBug(); } if (flags.BlackBeltAbsorb) { FixBBAbsorbBug(); } if (flags.ImproveTurnOrderRandomization) { ImproveTurnOrderRandomization(rng); } if (flags.EnemyElementalResistancesBug) { FixEnemyElementalResistances(); } if (flags.FunEnemyNames) { FunEnemyNames(flags.TeamSteak); } var itemText = ReadText(ItemTextPointerOffset, ItemTextPointerBase, ItemTextPointerCount); // var dialogueText = ReadText(DialogueTextPointerOffset, DialogueTextPointerBase, DialogueTextPointerCount); FixVanillaRibbon(itemText); ExpGoldBoost(flags.ExpBonus, flags.ExpMultiplier); ScalePrices(flags, itemText, rng, shopItemLocation); ScaleEncounterRate(flags.EncounterRate / 30.0, flags.DungeonEncounterRate / 30.0); if (flags.WarMECHMode != WarMECHMode.Vanilla) { WarMECHNpc(flags.WarMECHMode, rng, maps); } overworldMap.ApplyMapEdits(); WriteMaps(maps); WriteText(itemText, ItemTextPointerOffset, ItemTextPointerBase, ItemTextOffset, UnusedGoldItems); // WriteText(dialogueText, DialogueTextPointerOffset, DialogueTextPointerBase, DialogueTextOffset); if (flags.EnemyScaleFactor > 1) { ScaleEnemyStats(flags.EnemyScaleFactor, flags.WrapStatOverflow, flags.IncludeMorale, rng); } if (flags.BossScaleFactor > 1) { ScaleBossStats(flags.BossScaleFactor, flags.WrapStatOverflow, flags.IncludeMorale, rng); } if (flags.ForcedPartyMembers > 0) { PartyRandomize(rng, flags.ForcedPartyMembers); } if (flags.MapCanalBridge) { EnableCanalBridge(); } SetProgressiveScaleMode(flags.ProgressiveScaleMode); // We have to do "fun" stuff last because it alters the RNG state. RollCredits(rng); if (flags.PaletteSwap) { PaletteSwap(rng); } if (flags.TeamSteak) { TeamSteak(); } if (flags.Music != MusicShuffle.None) { ShuffleMusic(flags.Music, rng); } WriteSeedAndFlags(Version, seed.ToHex(), Flags.EncodeFlagsText(flags)); ExtraTrackingAndInitCode(); }
public LooseFloorHintSource(MT19337 _rng, NPCdata _npcData, Flags _flags, OverworldMap _overworldMap, FF1Rom _rom) : base(_rng, _npcData, _flags, _overworldMap, _rom) { }
public static async Task <OwMapExchange> FromFlags(FF1Rom _rom, OverworldMap _overworldMap, Flags flags, MT19337 rng) { int seed; if (flags.MapGenSeed != 0) { seed = flags.MapGenSeed; } else { seed = (int)rng.Next(); } MT19337 maprng = new MT19337((uint)seed); var gm = flags.GameMode; switch (gm) { case GameModes.NoOverworld: return(new OwMapExchange(_rom, _overworldMap, "nooverworld")); case GameModes.DeepDungeon: return(null); case GameModes.Standard: break; } var mx = flags.OwMapExchange; switch (mx) { case OwMapExchanges.None: return(null); case OwMapExchanges.Desert: if (flags.ReplacementMap == null) { flags.ReplacementMap = DesertOfDeath.GenerateDesert(maprng); } return(new OwMapExchange(_rom, _overworldMap, flags.ReplacementMap)); case OwMapExchanges.GenerateNewOverworld: case OwMapExchanges.LostWoods: if (flags.OwRandomPregen) { return(new OwMapExchange(_rom, flags, _overworldMap, rng)); } else if (flags.ReplacementMap == null) { flags.ReplacementMap = await NewOverworld.GenerateNewOverworld(maprng, mx, flags.OwShuffledAccess, flags.OwUnsafeStart, _rom.Progress); } return(new OwMapExchange(_rom, _overworldMap, flags.ReplacementMap)); case OwMapExchanges.ImportCustomMap: if (flags.ReplacementMap == null) { throw new Exception("No replacement map was supplied"); } return(new OwMapExchange(_rom, _overworldMap, flags.ReplacementMap)); } throw new Exception("oops"); }
public IncentiveData(MT19337 rng, IIncentiveFlags flags, OverworldMap map, ItemShopSlot shopSlot, ISanityChecker checker) { OverworldMap = map; _checker = checker; List <(bool, Item)> incentivizedItemsFlags = new() { ((bool)flags.IncentivizeBridge, Item.Bridge), ((bool)flags.IncentivizeShip, Item.Ship), ((bool)flags.IncentivizeCanal, Item.Canal), ((bool)flags.IncentivizeLute, Item.Lute), ((bool)flags.IncentivizeCrown, Item.Crown), ((bool)flags.IncentivizeCrystal, Item.Crystal), ((bool)flags.IncentivizeHerb, Item.Herb), ((bool)flags.IncentivizeKey, Item.Key), ((bool)flags.IncentivizeTnt, Item.Tnt), ((bool)flags.IncentivizeAdamant, Item.Adamant), ((bool)flags.IncentivizeSlab, Item.Slab), ((bool)flags.IncentivizeRuby, Item.Ruby), ((bool)flags.IncentivizeRod, Item.Rod), ((bool)flags.IncentivizeFloater, Item.Floater), ((bool)flags.IncentivizeChime, Item.Chime), ((bool)flags.IncentivizePromotion, Item.Tail), ((bool)flags.IncentivizeCube, Item.Cube), ((bool)flags.IncentivizeBottle, Item.Bottle), ((bool)flags.IncentivizeOxyale, Item.Oxyale), ((bool)flags.IncentivizeCanoe, Item.Canoe), ((bool)flags.IncentivizeXcalber, Item.Xcalber), ((bool)flags.IncentivizeMasamune, Item.Masamune), ((bool)flags.IncentivizeKatana, Item.Katana), ((bool)flags.IncentivizeVorpal, Item.Vorpal), ((bool)flags.IncentivizeRibbon, Item.Ribbon), ((bool)flags.IncentivizeRibbon2, Item.Ribbon), ((bool)flags.IncentivizeOpal, Item.Opal), ((bool)flags.Incentivize65K, Item.Gold65000), ((bool)flags.IncentivizeBad, Item.Cloth), ((bool)flags.IncentivizeDefCastArmor, Item.WhiteShirt), ((bool)flags.IncentivizeOffCastArmor, Item.BlackShirt), ((bool)flags.IncentivizeOtherCastArmor, Item.PowerGauntlets), ((bool)flags.IncentivizePowerRod, Item.PowerRod), ((bool)flags.IncentivizeDefCastWeapon, Item.Defense), ((bool)flags.IncentivizeOffCastWeapon, Item.ThorHammer), ((bool)flags.IncentivizeOtherCastWeapon, Item.BaneSword), }; List <(bool, IRewardSource)> incentivizedNpcsFlags = new() { ((bool)flags.IncentivizeKingConeria, ItemLocations.KingConeria), ((bool)flags.IncentivizePrincess, ItemLocations.Princess), ((bool)flags.IncentivizeMatoya, ItemLocations.Matoya), ((bool)flags.IncentivizeBikke, ItemLocations.Bikke), ((bool)flags.IncentivizeElfPrince, ItemLocations.ElfPrince), ((bool)flags.IncentivizeAstos, ItemLocations.Astos), ((bool)flags.IncentivizeNerrick, ItemLocations.Nerrick), ((bool)flags.IncentivizeSmith, ItemLocations.Smith), ((bool)flags.IncentivizeSarda, ItemLocations.Sarda), ((bool)flags.IncentivizeCanoeSage, ItemLocations.CanoeSage), ((bool)flags.IncentivizeCubeBot, ItemLocations.CubeBot), ((bool)flags.IncentivizeFairy, ItemLocations.Fairy), ((bool)flags.IncentivizeLefein, ItemLocations.Lefein), ((bool)flags.IncentivizeCaravan, ItemLocations.CaravanItemShop1), }; List <(bool, Item)> removedItemsFlags = new() { ((bool)flags.NoMasamune, Item.Masamune), ((bool)flags.NoXcalber, Item.Xcalber), ((bool)flags.NoTail, Item.Tail), ((bool)flags.IsFloaterRemoved, Item.Floater), ((bool)flags.IsCanoeFree, Item.Canoe), ((bool)flags.FreeLute, Item.Lute), ((bool)flags.FreeTail, Item.Tail), ((bool)flags.IsBridgeFree, Item.Bridge), ((bool)flags.IsCanalFree, Item.Canal), ((bool)flags.IsShipFree, Item.Ship), }; List <(bool, IRewardSource)> removedNPCItemsLocations = new() { ((bool)flags.IsCanoeFree, ItemLocations.CanoeSage), ((bool)flags.FreeLute, ItemLocations.Princess), ((bool)flags.IsBridgeFree, ItemLocations.KingConeria), ((bool)flags.IsShipFree, ItemLocations.Bikke), }; List <(bool, IRewardSource)> removedNPCFetchItemsLocations = new() { ((bool)flags.NoXcalber, ItemLocations.Smith), ((bool)flags.IsCanalFree, ItemLocations.Nerrick), }; Dictionary <MapLocation, Tuple <List <MapChange>, AccessRequirement> > fullLocationRequirements = map.FullLocationRequirements; var forcedItemPlacements = ItemLocations.AllOtherItemLocations.ToList(); if (!(flags.NPCItems ?? false)) { forcedItemPlacements.AddRange(ItemLocations.AllNPCFreeItemLocationsExcludingVendor.Except(removedNPCItemsLocations.Where(x => x.Item1 == true).Select(x => x.Item2).ToList())); forcedItemPlacements.Add(shopSlot); } if (!(flags.NPCFetchItems ?? false)) { forcedItemPlacements.AddRange(ItemLocations.AllNPCFetchItemLocations.Except(removedNPCFetchItemsLocations.Where(x => x.Item1 == true).Select(x => x.Item2).ToList())); } else if (flags.NoOverworld) { forcedItemPlacements.Add(ItemLocations.Nerrick); } if ((!flags.Treasures ?? false)) { forcedItemPlacements.AddRange(ItemLocations.AllTreasures); } if (flags.GuaranteedMasamune ?? false) { forcedItemPlacements.Add(ItemLocations.ToFRMasmune); } List <Item> removedItems = removedItemsFlags.Where(x => x.Item1 == true).Select(x => x.Item2).ToList(); List <Item> incentivePool = incentivizedItemsFlags.Where(x => x.Item1 == true).Select(x => x.Item2).ToList(); List <IRewardSource> incentiveLocationPool = incentivizedNpcsFlags.Where(x => x.Item1 == true).Select(x => x.Item2).ToList(); incentiveLocationPool.AddRange(SelectIncentivizedChests(flags, rng)); var itemLocationPool = ItemLocations.AllTreasures.Concat(ItemLocations.AllNPCItemLocations) .Where(x => !x.IsUnused && !forcedItemPlacements.Any(y => y.Address == x.Address)) .ToList(); if ((bool)flags.EarlyOrdeals) { 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 ((bool)flags.EarlyKing) { forcedItemPlacements = forcedItemPlacements .Select(x => x.Address == ItemLocations.KingConeria.Address ? new MapObject(ObjectId.King, MapLocation.ConeriaCastle2, x.Item) : x).ToList(); itemLocationPool = itemLocationPool .Select(x => x.Address == ItemLocations.KingConeria.Address ? new MapObject(ObjectId.King, MapLocation.ConeriaCastle2, x.Item) : x).ToList(); incentiveLocationPool = incentiveLocationPool .Select(x => x.Address == ItemLocations.KingConeria.Address ? new MapObject(ObjectId.King, MapLocation.ConeriaCastle2, x.Item) : x).ToList(); } if ((bool)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 ((bool)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)) { if ((bool)flags.GuaranteedMasamune && item == Item.Masamune) { continue; } incentivePool.Remove(item); } foreach (var item in removedItems) { incentivePool.Remove(item); } var nonEndgameMapLocations = _checker.AccessibleMapLocations(~AccessRequirement.BlackOrb, MapChange.All, fullLocationRequirements); ForcedItemPlacements = forcedItemPlacements.ToList(); IncentiveItems = incentivePool.ToList(); RemovedItems = removedItems.ToList(); IncentiveLocations = incentiveLocationPool .Where(x => !forcedItemPlacements.Any(y => y.Address == x.Address)) .ToList(); AllValidItemLocations = itemLocationPool.ToList(); AllValidPreBlackOrbItemLocations = AllValidItemLocations .Where(x => nonEndgameMapLocations.Contains(x.MapLocation) && nonEndgameMapLocations.Contains((x as MapObject)?.SecondLocation ?? MapLocation.StartingLocation)) .ToList(); }
public void Randomize(Blob seed, Flags flags, Preferences preferences) { MT19337 rng; using (SHA256 hasher = SHA256.Create()) { Blob FlagsBlob = Encoding.UTF8.GetBytes(Flags.EncodeFlagsText(flags)); Blob SeedAndFlags = Blob.Concat(new Blob[] { FlagsBlob, seed }); Blob hash = hasher.ComputeHash(SeedAndFlags); rng = new MT19337(BitConverter.ToUInt32(hash, 0)); } if (flags.TournamentSafe) { AssureSafe(); } UpgradeToMMC3(); MakeSpace(); Bank1E(); Bank1B(); EasterEggs(); DynamicWindowColor(preferences.MenuColor); PermanentCaravan(); ShiftEarthOrbDown(); CastableItemTargeting(); FixEnemyPalettes(); // fixes a bug in the original game's programming that causes third enemy slot's palette to render incorrectly FixWarpBug(); // The warp bug must be fixed for magic level shuffle and spellcrafter SeparateUnrunnables(); var talkroutines = new TalkRoutines(); var npcdata = new NPCdata(this); UpdateDialogs(npcdata); if (flags.TournamentSafe) { Put(0x3FFE3, Blob.FromHex("66696E616C2066616E74617379")); } flags = Flags.ConvertAllTriState(flags, rng); TeleportShuffle teleporters = new TeleportShuffle(); var palettes = OverworldMap.GeneratePalettes(Get(OverworldMap.MapPaletteOffset, MapCount * OverworldMap.MapPaletteSize).Chunk(OverworldMap.MapPaletteSize)); var overworldMap = new OverworldMap(this, flags, palettes, teleporters); var maps = ReadMaps(); var shopItemLocation = ItemLocations.CaravanItemShop1; var oldItemNames = ReadText(ItemTextPointerOffset, ItemTextPointerBase, ItemTextPointerCount); if (flags.EFGWaterfall || flags.EFGEarth1 || flags.EFGEarth2) { MapRequirements reqs; MapGeneratorStrategy strategy; MapGenerator generator = new MapGenerator(); if (flags.EFGWaterfall) { reqs = new MapRequirements { MapId = MapId.Waterfall, Rom = this, }; strategy = MapGeneratorStrategy.WaterfallClone; CompleteMap waterfall = generator.Generate(rng, strategy, reqs); // Should add more into the reqs so that this can be done inside the generator. teleporters.Waterfall.SetEntrance(waterfall.Entrance); overworldMap.PutOverworldTeleport(OverworldTeleportIndex.Waterfall, teleporters.Waterfall); maps[(int)MapId.Waterfall] = waterfall.Map; } if (flags.EFGEarth1) { reqs = new MapRequirements { MapId = MapId.EarthCaveB1, Rom = this, }; strategy = MapGeneratorStrategy.Square; var earthB1 = generator.Generate(rng, strategy, reqs); // Should add more into the reqs so that this can be done inside the generator. teleporters.EarthCave1.SetEntrance(earthB1.Entrance); overworldMap.PutOverworldTeleport(OverworldTeleportIndex.EarthCave1, teleporters.EarthCave1); maps[(int)MapId.EarthCaveB1] = earthB1.Map; } if (flags.EFGEarth2) { reqs = new MapRequirements { MapId = MapId.EarthCaveB2, Rom = this, }; strategy = MapGeneratorStrategy.Square; var earthB2 = generator.Generate(rng, strategy, reqs); // Should add more into the reqs so that this can be done inside the generator. teleporters.EarthCave2.SetEntrance(earthB2.Entrance); overworldMap.PutStandardTeleport(TeleportIndex.EarthCave2, teleporters.EarthCave2, OverworldTeleportIndex.EarthCave1); maps[(int)MapId.EarthCaveB2] = earthB2.Map; } } var flippedMaps = new List <MapId>(); if ((bool)flags.FlipDungeons) { flippedMaps = HorizontalFlipDungeons(rng, maps, teleporters, overworldMap); } if ((bool)flags.RandomizeFormationEnemizer) { DoEnemizer(rng, (bool)flags.RandomizeEnemizer, (bool)flags.RandomizeFormationEnemizer, flags.EnemizerDontMakeNewScripts); } if (preferences.ModernBattlefield) { EnableModernBattlefield(); } if ((bool)flags.TitansTrove) { EnableTitansTrove(maps); } if ((bool)flags.LefeinShops) { EnableLefeinShops(maps); } // This has to be done before we shuffle spell levels. if (flags.SpellBugs) { FixSpellBugs(); } //must be done before spells get shuffled around otherwise we'd be changing a spell that isnt lock if (flags.LockMode != LockHitMode.Vanilla) { ChangeLockMode(flags.LockMode); } if (flags.EnemySpellsTargetingAllies) { FixEnemyAOESpells(); } if (flags.AllSpellLevelsForKnightNinja) { KnightNinjaChargesForAllLevels(); } if (flags.BuffHealingSpells) { BuffHealingSpells(); } UpdateMagicAutohitThreshold(rng, flags.MagicAutohitThreshold); if ((bool)flags.GenerateNewSpellbook) { CraftNewSpellbook(rng, (bool)flags.SpellcrafterMixSpells, flags.LockMode, (bool)flags.MagicLevels, (bool)flags.SpellcrafterRetainPermissions); } if ((bool)flags.MagisizeWeapons) { MagisizeWeapons(rng, (bool)flags.MagisizeWeaponsBalanced); } if ((bool)flags.ItemMagic) { ShuffleItemMagic(rng, (bool)flags.BalancedItemMagicShuffle); } if ((bool)flags.GuaranteedRuseItem) { CraftRuseItem(); } if ((bool)flags.ShortToFR) { ShortenToFR(maps, (bool)flags.PreserveFiendRefights, (bool)flags.PreserveAllFiendRefights, rng); } if (((bool)flags.Treasures) && flags.ShardHunt && !flags.FreeOrbs) { EnableShardHunt(rng, talkroutines, flags.ShardCount); } if ((bool)flags.TransformFinalFormation && !flags.SpookyFlag) { TransformFinalFormation((FinalFormation)rng.Between(0, Enum.GetValues(typeof(FinalFormation)).Length - 1), flags.EvadeCap); } var maxRetries = 8; for (var i = 0; i < maxRetries; i++) { try { overworldMap = new OverworldMap(this, flags, palettes, teleporters); if (((bool)flags.Entrances || (bool)flags.Floors || (bool)flags.Towns) && ((bool)flags.Treasures) && ((bool)flags.NPCItems)) { overworldMap.ShuffleEntrancesAndFloors(rng, flags); // Disable the Princess Warp back to Castle Coneria if ((bool)flags.Entrances || (bool)flags.Floors) { talkroutines.ReplaceChunk(newTalkRoutines.Talk_Princess1, Blob.FromHex("20CC90"), Blob.FromHex("EAEAEA")); } } if ((bool)flags.Treasures && (bool)flags.ShuffleObjectiveNPCs) { overworldMap.ShuffleObjectiveNPCs(rng); } IncentiveData incentivesData = new IncentiveData(rng, flags, overworldMap, shopItemLocation); if (((bool)flags.Shops)) { var excludeItemsFromRandomShops = new List <Item>(); if ((bool)flags.Treasures) { excludeItemsFromRandomShops = incentivesData.ForcedItemPlacements.Select(x => x.Item).Concat(incentivesData.IncentiveItems).ToList(); } if (!((bool)flags.RandomWaresIncludesSpecialGear)) { excludeItemsFromRandomShops.AddRange(ItemLists.SpecialGear); if ((bool)flags.GuaranteedRuseItem) { excludeItemsFromRandomShops.Add(Item.PowerRod); } } if ((bool)flags.NoMasamune) { excludeItemsFromRandomShops.Add(Item.Masamune); } shopItemLocation = ShuffleShops(rng, (bool)flags.ImmediatePureAndSoftRequired, ((bool)flags.RandomWares), excludeItemsFromRandomShops, flags.WorldWealth); incentivesData = new IncentiveData(rng, flags, overworldMap, shopItemLocation); } if ((bool)flags.Treasures) { generatedPlacement = ShuffleTreasures(rng, flags, incentivesData, shopItemLocation, overworldMap, teleporters); } break; } catch (InsaneException e) { Console.WriteLine(e.Message); if (maxRetries > (i + 1)) { continue; } throw new InvalidOperationException(e.Message); } } // Change Astos routine so item isn't lost in wall of text if ((bool)flags.NPCItems || (bool)flags.NPCFetchItems || (bool)flags.ShuffleAstos) { talkroutines.Replace(newTalkRoutines.Talk_Astos, Blob.FromHex("A674F005BD2060F027A5738561202096B020A572203D96A575200096A476207F90207392A5611820109F201896A9F060A57060")); } npcdata.UpdateItemPlacement(generatedPlacement); if ((bool)flags.MagicShopLocs) { ShuffleMagicLocations(rng); } if (((bool)flags.MagicShops)) { ShuffleMagicShops(rng); } if (((bool)flags.MagicLevels)) { ShuffleMagicLevels(rng, ((bool)flags.MagicPermissions), (bool)flags.MagicLevelsTiered, (bool)flags.MagicLevelsMixed, (bool)!flags.GenerateNewSpellbook); } new StartingInventory(rng, flags, this).SetStartingInventory(); /* * if (flags.WeaponPermissions) * { * ShuffleWeaponPermissions(rng); * } * * if (flags.ArmorPermissions) * { * ShuffleArmorPermissions(rng); * } */ if (flags.SaveGameWhenGameOver) { EnableSaveOnDeath(flags); } // Ordered before RNG shuffle. In the event that both flags are on, RNG shuffle depends on this. if (((bool)flags.FixMissingBattleRngEntry)) { FixMissingBattleRngEntry(); } if (((bool)flags.Rng)) { ShuffleRng(rng); } if (((bool)flags.EnemyScripts)) { ShuffleEnemyScripts(rng, (bool)flags.AllowUnsafePirates, (bool)!flags.BossScriptsOnly, ((bool)flags.EnemySkillsSpellsTiered || (bool)flags.ScaryImps), (bool)flags.ScaryImps); } if (((bool)flags.EnemySkillsSpells)) { if ((bool)flags.EnemySkillsSpellsTiered && (bool)!flags.BossSkillsOnly) { GenerateBalancedEnemyScripts(rng, (bool)flags.SwolePirates); ShuffleEnemySkillsSpells(rng, false); } else { ShuffleEnemySkillsSpells(rng, (bool)!flags.BossSkillsOnly); } } if (((bool)flags.EnemyStatusAttacks)) { if (((bool)flags.RandomStatusAttacks)) { RandomEnemyStatusAttacks(rng, (bool)flags.AllowUnsafePirates, (bool)flags.DisableStunTouch); } else { ShuffleEnemyStatusAttacks(rng, (bool)flags.AllowUnsafePirates); } } if (flags.Runnability == Runnability.Random) { flags.Runnability = (Runnability)Rng.Between(rng, 0, 3); } if (flags.Runnability == Runnability.AllRunnable) { CompletelyRunnable(); } else if (flags.Runnability == Runnability.AllUnrunnable) { CompletelyUnrunnable(); } else if (flags.Runnability == Runnability.Shuffle) { ShuffleUnrunnable(rng); } // Always on to supply the correct changes for WaitWhenUnrunnable AllowStrikeFirstAndSurprise(flags.WaitWhenUnrunnable, (bool)flags.UnrunnablesStrikeFirstAndSurprise); if (((bool)flags.EnemyFormationsSurprise)) { ShuffleSurpriseBonus(rng); } // Put this before other encounter / trap tile edits. if ((bool)flags.AllowUnsafeMelmond) { EnableMelmondGhetto(flags.EnemizerEnabled); } // After unrunnable shuffle and before formation shuffle. Perfect! if (flags.WarMECHMode != WarMECHMode.Vanilla) { WarMECHNpc(flags.WarMECHMode, npcdata, rng, maps); } if (flags.WarMECHMode == WarMECHMode.Unleashed) { UnleashWarMECH(); } if ((bool)flags.ClassAsNpcFiends || (bool)flags.ClassAsNpcKeyNPC) { ClassAsNPC(flags, talkroutines, npcdata, flippedMaps, rng); } if ((bool)flags.FiendShuffle) { FiendShuffle(rng); } if (flags.FormationShuffleMode != FormationShuffleMode.None && !flags.EnemizerEnabled) { ShuffleEnemyFormations(rng, flags.FormationShuffleMode); } if ((bool)flags.RemoveTrapTiles) { RemoveTrapTiles(flags.EnemizerEnabled); } if (((bool)flags.EnemyTrapTiles) && !flags.EnemizerEnabled) { ShuffleTrapTiles(rng, ((bool)flags.RandomTrapFormations)); } if ((bool)flags.OrdealsPillars) { ShuffleOrdeals(rng, maps); } if (flags.SkyCastle4FMazeMode == SkyCastle4FMazeMode.Maze) { DoSkyCastle4FMaze(rng, maps); } else if (flags.SkyCastle4FMazeMode == SkyCastle4FMazeMode.Teleporters) { ShuffleSkyCastle4F(rng, maps); } if ((bool)flags.ConfusedOldMen) { EnableConfusedOldMen(rng); } if ((bool)flags.EarlyOrdeals) { EnableEarlyOrdeals(); } if (flags.ChaosRush) { EnableChaosRush(); } if ((bool)flags.EarlyKing) { EnableEarlyKing(npcdata); } if ((bool)flags.EarlySarda) { EnableEarlySarda(npcdata); } if ((bool)flags.EarlySage) { EnableEarlySage(npcdata); } if ((bool)flags.FreeBridge) { EnableFreeBridge(); } if ((bool)flags.FreeAirship) { EnableFreeAirship(); } if ((bool)flags.FreeShip) { EnableFreeShip(); } if (flags.FreeOrbs) { EnableFreeOrbs(); } if ((bool)flags.FreeCanal) { EnableFreeCanal((bool)flags.NPCItems, npcdata); } if ((bool)flags.FreeCanoe) { EnableFreeCanoe(); } if ((bool)flags.FreeLute) { EnableFreeLute(); } if ((bool)flags.FreeTail && !(bool)flags.NoTail) { EnableFreeTail(); } if (flags.NoPartyShuffle) { DisablePartyShuffle(); } if (flags.SpeedHacks) { EnableSpeedHacks(); } if (flags.IdentifyTreasures) { EnableIdentifyTreasures(); } if (flags.Dash) { EnableDash(); } if (flags.BuyTen) { EnableBuyQuantity(); } else if (flags.BuyTenOld) { EnableBuyTen(); } if (flags.WaitWhenUnrunnable) { ChangeUnrunnableRunToWait(); } if (flags.SpeedHacks && flags.EnableCritNumberDisplay) { EnableCritNumberDisplay(); } if (flags.BattleMagicMenuWrapAround) { BattleMagicMenuWrapAround(); } if (flags.NPCSwatter) { EnableNPCSwatter(npcdata); } if (flags.EasyMode) { EnableEasyMode(); } if ((bool)flags.TrappedChests || (bool)flags.TCMasaGuardian || (bool)flags.TrappedShards) { MonsterInABox(rng, flags); } if (flags.HouseMPRestoration || flags.HousesFillHp) { FixHouse(flags.HouseMPRestoration, flags.HousesFillHp); } if (flags.BBCritRate) { DontDoubleBBCritRates(); } if (flags.WeaponCritRate) { DoubleWeaponCritRates(); } //needs to go after item magic, moved after double weapon crit to have more control over the actual number of crit gained. if ((bool)flags.RandomWeaponBonus) { RandomWeaponBonus(rng, flags.RandomWeaponBonusLow, flags.RandomWeaponBonusHigh, (bool)flags.RandomWeaponBonusExcludeMasa); } if ((bool)flags.RandomArmorBonus) { RandomArmorBonus(rng, flags.RandomArmorBonusLow, flags.RandomArmorBonusHigh); } if (flags.WeaponBonuses) { IncreaseWeaponBonus(flags.WeaponTypeBonusValue); } if (flags.WeaponStats) { FixWeaponStats(); } if (flags.ChanceToRun) { FixChanceToRun(); } if (flags.EnemyStatusAttackBug) { FixEnemyStatusAttackBug(); } if (flags.BlackBeltAbsorb) { FixBBAbsorbBug(); } if (flags.MDefMode != MDEFGrowthMode.None) { MDefChanges(flags.MDefMode); } if (flags.ThiefHitRate) { ThiefHitRate(); } if (flags.ImproveTurnOrderRandomization) { ImproveTurnOrderRandomization(rng); } if (flags.FixHitChanceCap) { FixHitChanceCap(); } if (flags.EnemyElementalResistancesBug) { FixEnemyElementalResistances(); } if (preferences.FunEnemyNames && !flags.EnemizerEnabled) { FunEnemyNames(preferences.TeamSteak); } var itemText = ReadText(ItemTextPointerOffset, ItemTextPointerBase, ItemTextPointerCount); itemText[(int)Item.Ribbon] = itemText[(int)Item.Ribbon].Remove(7); if ((bool)flags.HintsVillage || (bool)flags.HintsDungeon) { if ((bool)flags.HintsDungeon) { SetDungeonNPC(flippedMaps, rng); } NPCHints(rng, npcdata, flags, overworldMap); } if (flags.Etherizer && !flags.HouseMPRestoration && !flags.HousesFillHp) { Etherizer(); itemText[(int)Item.Tent] = "ETHR@p"; itemText[(int)Item.Cabin] = "DRY@p "; itemText[(int)Item.House] = "XETH@p"; } ExpGoldBoost(flags.ExpBonus, flags.ExpMultiplier); ScalePrices(flags, itemText, rng, ((bool)flags.ClampMinimumPriceScale), shopItemLocation); ScaleEncounterRate(flags.EncounterRate / 30.0, flags.DungeonEncounterRate / 30.0); overworldMap.ApplyMapEdits(); WriteMaps(maps); WriteText(itemText, ItemTextPointerOffset, ItemTextPointerBase, ItemTextOffset, UnusedGoldItems); if ((bool)flags.SwolePirates) { EnableSwolePirates(); } if (flags.EnemyScaleStatsHigh != 100 || flags.EnemyScaleStatsLow != 100 || ((bool)flags.SeparateEnemyHPScaling && (flags.EnemyScaleHpLow != 100 || flags.EnemyScaleHpHigh != 100))) { ScaleEnemyStats(rng, flags); } if (flags.BossScaleStatsHigh != 100 || flags.BossScaleStatsLow != 100 || ((bool)flags.SeparateBossHPScaling && (flags.BossScaleHpLow != 100 || flags.BossScaleHpHigh != 100))) { ScaleBossStats(rng, flags); } PartyComposition(rng, flags, preferences); if (((bool)flags.RecruitmentMode)) { PubReplaceClinic(rng, flags); } if ((bool)flags.ChangeMaxMP) { SetMPMax(flags.RedMageMaxMP, flags.WhiteMageMaxMP, flags.BlackMageMaxMP, flags.KnightMaxMP, flags.NinjaMaxMP); } if ((bool)flags.ShuffleAstos) { ShuffleAstos(flags, npcdata, talkroutines, rng); } if ((bool)flags.EnablePoolParty) { EnablePoolParty(flags, rng); } if ((bool)flags.MapCanalBridge) { EnableCanalBridge(); } if (flags.NoDanMode) { NoDanMode(); } SetProgressiveScaleMode(flags); if ((bool)flags.RandomizeClass) { RandomizeClass(rng, flags, oldItemNames); } if ((bool)flags.EnableRandomPromotions) { EnableRandomPromotions(flags, rng); } if (flags.DisableTentSaving) { CannotSaveOnOverworld(); } if (flags.DisableInnSaving) { CannotSaveAtInns(); } if (flags.PacifistMode && !flags.SpookyFlag) { PacifistEnd(talkroutines, npcdata, (bool)flags.EnemyTrapTiles || flags.EnemizerEnabled); } if (flags.ShopInfo) { ShopUpgrade(); } if (flags.SpookyFlag) { Spooky(talkroutines, npcdata, rng, flags); } if (flags.InventoryAutosort && !(preferences.RenounceAutosort)) { EnableInventoryAutosort(); } // We have to do "fun" stuff last because it alters the RNG state. // Back up Rng so that fun flags are uniform when different ones are selected uint funRngSeed = rng.Next(); RollCredits(rng); if (preferences.DisableDamageTileFlicker) { DisableDamageTileFlicker(); } if (preferences.ThirdBattlePalette) { UseVariablePaletteForCursorAndStone(); } if (preferences.PaletteSwap && !flags.EnemizerEnabled) { rng = new MT19337(funRngSeed); PaletteSwap(rng); } if (preferences.TeamSteak && !(bool)flags.RandomizeEnemizer) { TeamSteak(); } if (preferences.ChangeLute) { rng = new MT19337(funRngSeed); ChangeLute(rng); } rng = new MT19337(funRngSeed); HurrayDwarfFate(preferences.HurrayDwarfFate, npcdata, rng); if (preferences.Music != MusicShuffle.None) { rng = new MT19337(funRngSeed); ShuffleMusic(preferences.Music, rng); } if (preferences.DisableSpellCastFlash) { DisableSpellCastScreenFlash(); } npcdata.WriteNPCdata(this); talkroutines.WriteRoutines(this); talkroutines.UpdateNPCRoutines(this, npcdata); WriteSeedAndFlags(seed.ToHex(), Flags.EncodeFlagsText(flags)); ExtraTrackingAndInitCode(flags); }
public static ItemPlacement Create(IItemPlacementFlags flags, IncentiveData incentivesData, List <Item> allTreasures, ItemShopSlot caravanItemLocation, OverworldMap overworldMap, ISanityChecker checker) { ItemPlacement placement; placement = flags.PredictivePlacement && checker is SanityCheckerV2 ? new PredictivePlacement() : new GuidedItemPlacement(); placement._flags = flags; placement._incentivesData = incentivesData; placement._allTreasures = allTreasures; placement._caravanItemLocation = caravanItemLocation; placement._overworldMap = overworldMap; placement._checker = checker; return(placement); }
public static List <IRewardSource> PlaceSaneItems(MT19337 rng, IItemPlacementFlags flags, IncentiveData incentivesData, List <Item> allTreasures, ItemShopSlot caravanItemLocation, OverworldMap overworldMap) { Dictionary <MapLocation, Tuple <List <MapChange>, AccessRequirement> > fullLocationRequirements = overworldMap.FullLocationRequirements; Dictionary <MapLocation, OverworldTeleportIndex> overridenOverworld = overworldMap.OverriddenOverworldLocations; long sanityCounter = 0; List <IRewardSource> placedItems; var canoeObsoletesBridge = flags.MapCanalBridge && flags.MapConeriaDwarves; var canoeObsoletesShip = flags.MapCanalBridge ? (flags.MapConeriaDwarves || flags.MapVolcanoIceRiver) : (flags.MapConeriaDwarves && flags.MapVolcanoIceRiver); var incentiveLocationPool = incentivesData.IncentiveLocations.ToList(); var incentivePool = incentivesData.IncentiveItems.Where(x => allTreasures.Contains(x)).ToList(); var forcedItems = incentivesData.ForcedItemPlacements.ToList(); var keyLocations = incentivesData.KeyLocations.ToList(); var canoeLocations = incentivesData.CanoeLocations.ToList(); var bridgeLocations = incentivesData.BridgeLocations.ToList(); var shipLocations = incentivesData.ShipLocations.ToList(); var itemLocationPool = incentivesData.AllValidItemLocations.ToList(); var startingPotentialAccess = overworldMap.StartingPotentialAccess; var startingMapLocations = AccessibleMapLocations(startingPotentialAccess, MapChange.None, fullLocationRequirements); var earlyMapLocations = AccessibleMapLocations(startingPotentialAccess | AccessRequirement.Crystal, MapChange.Bridge, fullLocationRequirements); var unincentivizedQuestItems = ItemLists.AllQuestItems .Where(x => !incentivePool.Contains(x) && allTreasures.Contains(x) && !forcedItems.Any(y => y.Item == x)) .ToList(); var treasurePool = allTreasures.ToList(); 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); } var itemShopItem = Item.Bottle; while (treasurePool.Remove(Item.Shard)) { unincentivizedQuestItems.Add(Item.Shard); } // Cache the final unincentivized pool so we can reset it each iteration of the loop. IReadOnlyCollection <Item> cachedTreasurePool = new ReadOnlyCollection <Item>(treasurePool.ToList()); do { sanityCounter++; if (sanityCounter > 500) { throw new InsaneException("Sanity Counter exceeds 500 iterations!"); } // 1. (Re)Initialize lists inside of loop placedItems = forcedItems.ToList(); var incentives = incentivePool.ToList(); var nonincentives = unincentivizedQuestItems.ToList(); treasurePool = cachedTreasurePool.ToList(); incentives.Shuffle(rng); nonincentives.Shuffle(rng); if (flags.NPCItems) { // 2. Place caravan item first because among incentive locations it has the smallest set of possible items var validShopIncentives = incentives .Where(x => x > Item.None && x <= Item.Soft) .ToList(); if (validShopIncentives.Any() && incentiveLocationPool.Any(x => x.Address == ItemLocations.CaravanItemShop1.Address)) { itemShopItem = validShopIncentives.PickRandom(rng); incentives.Remove(itemShopItem); } else { itemShopItem = treasurePool.Concat(nonincentives).Where(x => x > Item.None && x <= Item.Soft && x != Item.Shard).ToList().PickRandom(rng); if (!nonincentives.Remove(itemShopItem)) { treasurePool.Remove(itemShopItem); } } placedItems.Add(new ItemShopSlot(caravanItemLocation, itemShopItem)); // 3. Place key and canoe next because among incentive locations these have the greatest initial impact if (incentives.Remove(Item.Key) || nonincentives.Remove(Item.Key)) { placedItems.Add(NewItemPlacement(keyLocations.PickRandom(rng), Item.Key)); } if (incentives.Remove(Item.Canoe) || nonincentives.Remove(Item.Canoe)) { placedItems.Add(NewItemPlacement(canoeLocations.Where(x => !placedItems.Any(y => y.Address == x.Address)).ToList().PickRandom(rng), Item.Canoe)); } var startingCanoeAvailable = placedItems.Any(x => x.Item == Item.Canoe && startingMapLocations.Contains(x.MapLocation) && startingMapLocations.Contains((x as MapObject)?.SecondLocation ?? MapLocation.StartingLocation)); var earlyCanoeAvailable = placedItems.Any(x => x.Item == Item.Canoe && earlyMapLocations.Contains(x.MapLocation) && earlyMapLocations.Contains((x as MapObject)?.SecondLocation ?? MapLocation.StartingLocation)); var earlyKeyAvailable = placedItems.Any(x => x.Item == Item.Key && earlyMapLocations.Contains(x.MapLocation) && earlyMapLocations.Contains((x as MapObject)?.SecondLocation ?? MapLocation.StartingLocation)); // 4. Place Bridge and Ship next since the valid location lists are so small, unless canoe is available and map edits are applied if (!earlyCanoeAvailable || !canoeObsoletesShip) { var remainingShipLocations = shipLocations .Where(x => !placedItems.Any(y => y.Address == x.Address) && (earlyKeyAvailable || !x.AccessRequirement.HasFlag(AccessRequirement.Key))) .ToList(); if (!remainingShipLocations.Any()) { continue; } if (incentives.Remove(Item.Ship) && remainingShipLocations.Any(x => incentiveLocationPool.Any(y => y.Address == x.Address))) { remainingShipLocations = remainingShipLocations .Where(x => incentiveLocationPool.Any(y => y.Address == x.Address)) .ToList(); } nonincentives.Remove(Item.Ship); placedItems.Add(NewItemPlacement(remainingShipLocations.PickRandom(rng), Item.Ship)); } var startingShipAvailable = placedItems.Any(x => x.Item == Item.Ship && startingMapLocations.Contains(x.MapLocation) && startingMapLocations.Contains((x as MapObject)?.SecondLocation ?? MapLocation.StartingLocation)); if (!(startingCanoeAvailable && canoeObsoletesBridge) && !startingShipAvailable) { var startingKeyAvailable = earlyKeyAvailable && placedItems.Any(x => x.Item == Item.Key && startingMapLocations.Contains(x.MapLocation) && startingMapLocations.Contains((x as MapObject)?.SecondLocation ?? MapLocation.StartingLocation)); var remainingBridgeLocations = bridgeLocations .Where(x => !placedItems.Any(y => y.Address == x.Address) && (startingKeyAvailable || !x.AccessRequirement.HasFlag(AccessRequirement.Key))) .ToList(); if (!remainingBridgeLocations.Any()) { continue; } if (incentives.Remove(Item.Bridge) && remainingBridgeLocations.Any(x => incentiveLocationPool.Any(y => y.Address == x.Address))) { remainingBridgeLocations = remainingBridgeLocations .Where(x => incentiveLocationPool.Any(y => y.Address == x.Address)) .ToList(); } nonincentives.Remove(Item.Bridge); placedItems.Add(NewItemPlacement(remainingBridgeLocations.PickRandom(rng), Item.Bridge)); } } // 5. Then place all incentive locations that don't have special logic var incentiveLocations = incentiveLocationPool.Where(x => !placedItems.Any(y => y.Address == x.Address) && x.Address != ItemLocations.CaravanItemShop1.Address).ToList(); incentiveLocations.Shuffle(rng); foreach (var incentiveLocation in incentiveLocations) { if (!incentives.Any()) { break; } placedItems.Add(NewItemPlacement(incentiveLocation, incentives.SpliceRandom(rng))); } // 6. Then place remanining incentive items and unincentivized quest items in any other chest before ToFR var leftoverItems = incentives.Concat(nonincentives).ToList(); leftoverItems.Shuffle(rng); var leftoverItemLocations = itemLocationPool .Where(x => !ItemLocations.ToFR.Any(y => y.Address == x.Address) && !x.IsUnused && !placedItems.Any(y => y.Address == x.Address)) .ToList(); foreach (var leftoverItem in leftoverItems) { placedItems.Add(NewItemPlacement(leftoverItemLocations.SpliceRandom(rng), leftoverItem)); } // 7. Check sanity and loop if needed } while (!CheckSanity(placedItems, fullLocationRequirements, flags)); if (Debugger.IsAttached) { Console.WriteLine($"ItemPlacement::PlaceSaneItems required {sanityCounter} iterations."); Console.WriteLine(""); Console.WriteLine("Item Entrance -> Floor -> Source Requirements"); Console.WriteLine("------------------------------------------------------------------------------------------"); var sorted = placedItems.Where(item => item.Item != Item.Shard).ToList(); sorted.Sort((IRewardSource lhs, IRewardSource rhs) => lhs.Item.ToString().CompareTo(rhs.Item.ToString())); sorted.ForEach(item => { if (fullLocationRequirements.TryGetValue(item.MapLocation, out var flr)) { var overworldLocation = item.MapLocation.ToString(); if (overridenOverworld != null && overridenOverworld.TryGetValue(item.MapLocation, out var overriden)) { overworldLocation = overriden.ToString(); } var itemStr = item.Item.ToString().PadRight(9); var locStr = $"{overworldLocation} -> {item.MapLocation} -> {item.Name} ".PadRight(50); var changes = $"{String.Join(" | ", flr.Item1.Select(mapChange => mapChange.ToString()).ToArray())}"; var reqs = flr.Item2.ToString().CompareTo("None") == 0 ? "" : $" AND {flr.Item2.ToString()}"; Console.WriteLine($"{itemStr}{locStr}{changes}{reqs}"); } }); } // 8. Place all remaining unincentivized treasures or incentivized non-quest items that weren't placed itemLocationPool = itemLocationPool.Where(x => !x.IsUnused && !placedItems.Any(y => y.Address == x.Address)).ToList(); foreach (var placedItem in placedItems) { incentivePool.Remove(placedItem.Item); } treasurePool.AddRange(incentivePool); Debug.Assert(treasurePool.Count() == itemLocationPool.Count()); treasurePool.Shuffle(rng); itemLocationPool.Shuffle(rng); var leftovers = treasurePool.Zip(itemLocationPool, (treasure, location) => NewItemPlacement(location, treasure)); placedItems.AddRange(leftovers); return(placedItems); }
public void Randomize(Blob seed, Flags flags) { var rng = new MT19337(BitConverter.ToUInt32(seed, 0)); UpgradeToMMC3(); MakeSpaceIn1F(); EasterEggs(); DynamicWindowColor(); PermanentCaravan(); ShiftEarthOrbDown(); var overworldMap = new OverworldMap(this, flags); var maps = ReadMaps(); var incentivesData = new IncentiveData(rng, flags, overworldMap.MapLocationRequirements); var shopItemLocation = ItemLocations.CaravanItemShop1; if (flags.ModernBattlefield) { EnableModernBattlefield(); } if (flags.TitansTrove) { EnableTitansTrove(maps); } // This has to be done before we shuffle spell levels. if (flags.SpellBugs) { FixSpellBugs(); } if (flags.EnemySpellsTargetingAllies) { FixEnemyAOESpells(); } if (flags.ItemMagic) { ShuffleItemMagic(rng); } if (flags.Shops) { var excludeItemsFromRandomShops = flags.Treasures ? incentivesData.ForcedItemPlacements.Select(x => x.Item).Concat(incentivesData.IncentiveItems).ToList() : new List <Item>(); shopItemLocation = ShuffleShops(rng, flags.EnemyStatusAttacks, flags.RandomWares, excludeItemsFromRandomShops); } if (flags.Treasures || flags.NPCItems || flags.NPCFetchItems) { ShuffleTreasures(rng, flags, incentivesData, shopItemLocation, overworldMap.MapLocationRequirements); } if (flags.Treasures && flags.ShardHunt && !flags.ChaosRush) { EnableShardHunt(rng, flags.ExtraShards ? rng.Between(24, 30) : 16, maps, flags.NPCItems); } if (flags.TransformFinalFormation) { TransformFinalFormation((FinalFormation)rng.Between(0, Enum.GetValues(typeof(FinalFormation)).Length - 1)); } if (flags.MagicShops) { ShuffleMagicShops(rng); } if (flags.MagicLevels) { FixWarpBug(); // The warp bug only needs to be fixed if the magic levels are being shuffled ShuffleMagicLevels(rng, flags.MagicPermissions); } if (flags.Rng) { ShuffleRng(rng); } if (flags.EnemyScripts) { ShuffleEnemyScripts(rng, flags.AllowUnsafePirates); } if (flags.EnemySkillsSpells) { ShuffleEnemySkillsSpells(rng); } if (flags.EnemyStatusAttacks) { ShuffleEnemyStatusAttacks(rng, flags.AllowUnsafePirates); } if (flags.EnemyFormationsUnrunnable) { ShuffleUnrunnable(rng); } if (flags.EnemyFormationsSurprise) { ShuffleSurpriseBonus(rng); } if (flags.EnemyFormationsFrequency) { ShuffleEnemyFormations(rng); } if (flags.OrdealsPillars) { ShuffleOrdeals(rng, maps); } if (flags.SkyCastle4FTeleporters) { ShuffleSkyCastle4F(rng, maps); } if (flags.CrownlessOrdeals) { EnableEarlyOrdeals(); } if (flags.ChaosRush) { EnableChaosRush(); } if (flags.EarlySarda && !flags.NPCItems) { EnableEarlySarda(); } if (flags.EarlySage && !flags.NPCItems) { EnableEarlySage(); } if (flags.FreeBridge) { EnableFreeBridge(); } if (flags.FreeAirship) { EnableFreeAirship(); } if (flags.FreeOrbs) { EnableFreeOrbs(); } if (flags.NoPartyShuffle) { DisablePartyShuffle(); } if (flags.SpeedHacks) { EnableSpeedHacks(); } if (flags.IdentifyTreasures) { EnableIdentifyTreasures(); } if (flags.Dash) { EnableDash(); } if (flags.BuyTen) { EnableBuyTen(); } if (flags.WaitWhenUnrunnable) { ChangeUnrunnableRunToWait(); } if (flags.EasyMode) { EnableEasyMode(); } if (flags.HouseMPRestoration) { FixHouse(); } if (flags.WeaponStats) { FixWeaponStats(); } if (flags.ChanceToRun) { FixChanceToRun(); } if (flags.EnemyStatusAttackBug) { FixEnemyStatusAttackBug(); } if (flags.BlackBeltAbsorb) { FixBBAbsorbBug(); } if (flags.ImproveTurnOrderRandomization) { ImproveTurnOrderRandomization(rng); } if (flags.EnemyElementalResistancesBug) { FixEnemyElementalResistances(); } if (flags.FunEnemyNames) { FunEnemyNames(flags.TeamSteak); } var itemText = ReadText(ItemTextPointerOffset, ItemTextPointerBase, ItemTextPointerCount); FixVanillaRibbon(itemText); ExpGoldBoost(flags.ExpBonus, flags.ExpMultiplier); ScalePrices(flags.PriceScaleFactor, flags.ExpMultiplier, flags.VanillaStartingGold, itemText, rng); overworldMap.ApplyMapEdits(); WriteMaps(maps); WriteText(itemText, ItemTextPointerOffset, ItemTextPointerBase, ItemTextOffset, UnusedGoldItems); if (flags.EnemyScaleFactor > 1) { ScaleEnemyStats(flags.EnemyScaleFactor, rng); } if (flags.ForcedPartyMembers > 0) { PartyRandomize(rng, flags.ForcedPartyMembers); } if (flags.MapCanalBridge) { EnableCanalBridge(); } // We have to do "fun" stuff last because it alters the RNG state. RollCredits(rng); if (flags.PaletteSwap) { PaletteSwap(rng); } if (flags.TeamSteak) { TeamSteak(); } if (flags.Music != MusicShuffle.None) { ShuffleMusic(flags.Music, rng); } WriteSeedAndFlags(Version, seed.ToHex(), Flags.EncodeFlagsText(flags)); ExtraTrackingAndInitCode(); }
public void Randomize(Blob seed, Flags flags) { var rng = new MT19337(BitConverter.ToUInt32(seed, 0)); UpgradeToMMC3(); EasterEggs(); DynamicWindowColor(); PermanentCaravan(); var map = new OverworldMap(this, flags); var shopItemLocation = ItemLocations.CaravanItemShop1; if (flags.ModernBattlefield) { SetBattleUI(true); } if (flags.TitansTrove) { EnableTitansTrove(); } // This has to be done before we shuffle spell levels. if (flags.SpellBugs) { FixSpellBugs(); } if (flags.Shops) { shopItemLocation = ShuffleShops(rng, flags.EnemyStatusAttacks); } if (flags.Treasures || flags.NPCItems || flags.NPCFetchItems) { var incentivesData = new IncentiveData(rng, flags, map.MapLocationRequirements); ShuffleTreasures(rng, flags, incentivesData, shopItemLocation, map.MapLocationRequirements); } if (flags.MagicShops) { ShuffleMagicShops(rng); } if (flags.MagicLevels) { ShuffleMagicLevels(rng, flags.MagicPermissions); } if (flags.Rng) { ShuffleRng(rng); } if (flags.EnemyScripts) { ShuffleEnemyScripts(rng); } if (flags.EnemySkillsSpells) { ShuffleEnemySkillsSpells(rng); } if (flags.EnemyStatusAttacks) { ShuffleEnemyStatusAttacks(rng); } if (flags.OrdealsPillars) { ShuffleOrdeals(rng); } if (flags.CrownlessOrdeals) { EnableEarlyOrdeals(); } if (flags.KeylessToFR) { EnableKeylessToFR(); } if (flags.EarlySarda && !flags.NPCItems) { EnableEarlySarda(); } if (flags.EarlySage && !flags.NPCItems) { EnableEarlySage(); } if (flags.FreeBridge) { EnableFreeBridge(); } if (flags.FreeAirship) { EnableFreeAirship(); } if (flags.FreeOrbs) { EnableFreeOrbs(); } if (flags.NoPartyShuffle) { DisablePartyShuffle(); } if (flags.SpeedHacks) { EnableSpeedHacks(); } if (flags.IdentifyTreasures) { EnableIdentifyTreasures(); } if (flags.Dash) { EnableDash(); } if (flags.BuyTen) { EnableBuyTen(); } if (flags.EasyMode) { EnableEasyMode(); } if (flags.HouseMPRestoration) { FixHouse(); } if (flags.WeaponStats) { FixWeaponStats(); } if (flags.ChanceToRun) { FixChanceToRun(); } if (flags.EnemyStatusAttackBug) { FixEnemyStatusAttackBug(); } if (flags.FunEnemyNames) { FunEnemyNames(flags.TeamSteak); } var itemText = ReadText(ItemTextPointerOffset, ItemTextPointerBase, ItemTextPointerCount); itemText[99] = FF1Text.TextToBytes("Ribbon ", useDTE: false); ExpGoldBoost(flags.ExpBonus, flags.ExpMultiplier); ScalePrices(flags.PriceScaleFactor, flags.ExpMultiplier, itemText, rng); map.ApplyMapEdits(); WriteText(itemText, ItemTextPointerOffset, ItemTextPointerBase, ItemTextOffset, UnusedGoldItems); if (flags.EnemyScaleFactor > 1) { ScaleEnemyStats(flags.EnemyScaleFactor, rng); } if (flags.ForcedPartyMembers > 0) { PartyRandomize(rng, flags.ForcedPartyMembers); } if (flags.MapCanalBridge) { EnableCanalBridge(); } // We have to do "fun" stuff last because it alters the RNG state. RollCredits(rng); if (flags.PaletteSwap) { PaletteSwap(rng); } if (flags.TeamSteak) { TeamSteak(); } if (flags.Music != MusicShuffle.None) { ShuffleMusic(flags.Music, rng); } WriteSeedAndFlags(Version, seed.ToHex(), Flags.EncodeFlagsText(flags)); ExtraTrackingAndInitCode(); }
public DefaultHintPlacmentProvider(MT19337 _rng, NPCdata _npcData, Flags _flags, OverworldMap _overworldMap, FF1Rom _rom) : base(_rng, _npcData, _flags, _overworldMap, _rom) { PlacementPools = StrategyDic.Select(s => (key: s.Key, values: s.Value.SelectMany(l => LocationDic[l]))).ToDictionary(s => s.key, s => s.values.ToList()); }
public void Randomize(Blob seed, Flags flags, Preferences preferences) { var rng = new MT19337(BitConverter.ToUInt32(seed, 0)); // Spoilers => different rng immediately if (flags.Spoilers) { rng = new MT19337(rng.Next()); } UpgradeToMMC3(); MakeSpace(); Bank1E(); Bank1B(); EasterEggs(); DynamicWindowColor(preferences.MenuColor); PermanentCaravan(); ShiftEarthOrbDown(); CastableItemTargeting(); flags = Flags.ConvertAllTriState(flags, rng); TeleportShuffle teleporters = new TeleportShuffle(); var palettes = OverworldMap.GeneratePalettes(Get(OverworldMap.MapPaletteOffset, MapCount * OverworldMap.MapPaletteSize).Chunk(OverworldMap.MapPaletteSize)); var overworldMap = new OverworldMap(this, flags, palettes, teleporters); var maps = ReadMaps(); var shopItemLocation = ItemLocations.CaravanItemShop1; #if DEBUG if (flags.ExperimentalFloorGeneration) { MapRequirements reqs; MapGeneratorStrategy strategy; MapGenerator generator = new MapGenerator(); if (flags.EFGWaterfall) { reqs = new MapRequirements { MapId = MapId.Waterfall, Rom = this, }; strategy = MapGeneratorStrategy.WaterfallClone; CompleteMap waterfall = generator.Generate(rng, strategy, reqs); // Should add more into the reqs so that this can be done inside the generator. teleporters.Waterfall.SetEntrance(waterfall.Entrance); overworldMap.PutOverworldTeleport(OverworldTeleportIndex.Waterfall, teleporters.Waterfall); maps[(int)MapId.Waterfall] = waterfall.Map; } if (flags.EFGEarth1) { reqs = new MapRequirements { MapId = MapId.EarthCaveB1, Rom = this, }; strategy = MapGeneratorStrategy.Square; var earthB1 = generator.Generate(rng, strategy, reqs); // Should add more into the reqs so that this can be done inside the generator. teleporters.EarthCave1.SetEntrance(earthB1.Entrance); overworldMap.PutOverworldTeleport(OverworldTeleportIndex.EarthCave1, teleporters.EarthCave1); maps[(int)MapId.EarthCaveB1] = earthB1.Map; } if (flags.EFGEarth2) { reqs = new MapRequirements { MapId = MapId.EarthCaveB2, Rom = this, }; strategy = MapGeneratorStrategy.Square; var earthB2 = generator.Generate(rng, strategy, reqs); // Should add more into the reqs so that this can be done inside the generator. teleporters.EarthCave2.SetEntrance(earthB2.Entrance); overworldMap.PutStandardTeleport(TeleportIndex.EarthCave2, teleporters.EarthCave2, OverworldTeleportIndex.EarthCave1); maps[(int)MapId.EarthCaveB2] = earthB2.Map; } } #endif if (flags.RandomizeFormationEnemizer) { DoEnemizer(rng, false, flags.RandomizeFormationEnemizer, false); } if (preferences.ModernBattlefield) { EnableModernBattlefield(); } if ((bool)flags.TitansTrove) { EnableTitansTrove(maps); } if ((bool)flags.LefeinShops) { EnableLefeinShops(maps); } // This has to be done before we shuffle spell levels. if (flags.SpellBugs) { FixSpellBugs(); } if (flags.RebalanceSpells) { RebalanceSpells(); } if (flags.EnemySpellsTargetingAllies) { FixEnemyAOESpells(); } if ((bool)flags.ItemMagic) { ShuffleItemMagic(rng); } if ((bool)flags.ShortToFR) { ShortenToFR(maps, (bool)flags.PreserveFiendRefights, rng); } if (((bool)flags.Treasures) && flags.ShardHunt && !flags.FreeOrbs) { EnableShardHunt(rng, flags.ExtraShards ? rng.Between(24, 30) : 16, ((bool)flags.NPCItems)); } if ((bool)flags.TransformFinalFormation) { TransformFinalFormation((FinalFormation)rng.Between(0, Enum.GetValues(typeof(FinalFormation)).Length - 1)); } var maxRetries = 8; for (var i = 0; i < maxRetries; i++) { try { overworldMap = new OverworldMap(this, flags, palettes, teleporters); if (((bool)flags.Entrances || (bool)flags.Floors || (bool)flags.Towns) && ((bool)flags.Treasures) && ((bool)flags.NPCItems)) { overworldMap.ShuffleEntrancesAndFloors(rng, flags); } if ((bool)flags.ShuffleObjectiveNPCs) { overworldMap.ShuffleObjectiveNPCs(rng); } IncentiveData incentivesData = new IncentiveData(rng, flags, overworldMap, shopItemLocation); if (((bool)flags.Shops)) { var excludeItemsFromRandomShops = new List <Item>(); if ((bool)flags.Treasures) { excludeItemsFromRandomShops = incentivesData.ForcedItemPlacements.Select(x => x.Item).Concat(incentivesData.IncentiveItems).ToList(); } if (!((bool)flags.RandomWaresIncludesSpecialGear)) { excludeItemsFromRandomShops.AddRange(ItemLists.SpecialGear); } shopItemLocation = ShuffleShops(rng, (bool)flags.ImmediatePureAndSoftRequired, ((bool)flags.RandomWares), excludeItemsFromRandomShops, flags.WorldWealth); incentivesData = new IncentiveData(rng, flags, overworldMap, shopItemLocation); } if ((bool)flags.Treasures) { ShuffleTreasures(rng, flags, incentivesData, shopItemLocation, overworldMap, teleporters); } break; } catch (InsaneException e) { Console.WriteLine(e.Message); if (maxRetries > (i + 1)) { continue; } throw new InvalidOperationException(e.Message); } } if (((bool)flags.MagicShops)) { ShuffleMagicShops(rng); } if (((bool)flags.MagicLevels)) { FixWarpBug(); // The warp bug only needs to be fixed if the magic levels are being shuffled ShuffleMagicLevels(rng, ((bool)flags.MagicPermissions)); } /* * if (flags.WeaponPermissions) * { * ShuffleWeaponPermissions(rng); * } * * if (flags.ArmorPermissions) * { * ShuffleArmorPermissions(rng); * } */ if (((bool)flags.Rng)) { ShuffleRng(rng); } if (((bool)flags.EnemyScripts)) { ShuffleEnemyScripts(rng, (bool)flags.AllowUnsafePirates); } if (((bool)flags.EnemySkillsSpells)) { ShuffleEnemySkillsSpells(rng); } if (((bool)flags.EnemyStatusAttacks)) { if (((bool)flags.RandomStatusAttacks)) { RandomEnemyStatusAttacks(rng, (bool)flags.AllowUnsafePirates); } else { ShuffleEnemyStatusAttacks(rng, (bool)flags.AllowUnsafePirates); } } if (((bool)flags.EnemyFormationsUnrunnable)) { if (((bool)flags.EverythingUnrunnable)) { CompletelyUnrunnable(); } else { ShuffleUnrunnable(rng); } } if (((bool)flags.UnrunnablesStrikeFirstAndSurprise)) { AllowStrikeFirstAndSurprise(); } if (((bool)flags.EnemyFormationsSurprise)) { ShuffleSurpriseBonus(rng); } // Put this before other encounter / trap tile edits. if ((bool)flags.AllowUnsafeMelmond) { EnableMelmondGhetto(flags.RandomizeFormationEnemizer); } // After unrunnable shuffle and before formation shuffle. Perfect! if (flags.WarMECHMode != WarMECHMode.Vanilla) { WarMECHNpc(flags.WarMECHMode, rng, maps); } if (flags.WarMECHMode == WarMECHMode.Unleashed) { UnleashWarMECH(); } if (flags.FiendShuffle) { FiendShuffle(rng); } if (flags.FormationShuffleMode != FormationShuffleModeEnum.None) { ShuffleEnemyFormations(rng, flags.FormationShuffleMode); } if (((bool)flags.EnemyTrapTiles)) { ShuffleTrapTiles(rng, ((bool)flags.RandomTrapFormations)); } if ((bool)flags.OrdealsPillars) { ShuffleOrdeals(rng, maps); } if (flags.SkyCastle4FMazeMode == SkyCastle4FMazeMode.Maze) { DoSkyCastle4FMaze(rng, maps); } else if (flags.SkyCastle4FMazeMode == SkyCastle4FMazeMode.Teleporters) { ShuffleSkyCastle4F(rng, maps); } if ((bool)flags.ConfusedOldMen) { EnableConfusedOldMen(rng); } if ((bool)flags.EarlyOrdeals) { EnableEarlyOrdeals(); } if (flags.ChaosRush) { EnableChaosRush(); } if ((bool)flags.EarlySarda && !((bool)flags.NPCItems)) { EnableEarlySarda(); } if ((bool)flags.EarlySage && !((bool)flags.NPCItems)) { EnableEarlySage(); } if ((bool)flags.FreeBridge) { EnableFreeBridge(); } if ((bool)flags.FreeAirship) { EnableFreeAirship(); } if ((bool)flags.FreeShip) { EnableFreeShip(); } if (flags.FreeOrbs) { EnableFreeOrbs(); } if ((bool)flags.FreeCanal) { EnableFreeCanal(); } if ((bool)flags.FreeLute) { EnableFreeLute(); } if (flags.NoPartyShuffle) { DisablePartyShuffle(); } if (flags.SpeedHacks) { EnableSpeedHacks(); } if (flags.IdentifyTreasures) { EnableIdentifyTreasures(); } if (flags.Dash) { EnableDash(); } if (flags.BuyTen) { EnableBuyTen(); } if (flags.WaitWhenUnrunnable) { ChangeUnrunnableRunToWait(); } if (flags.SpeedHacks && flags.EnableCritNumberDisplay) { EnableCritNumberDisplay(); } if (flags.NPCSwatter) { EnableNPCSwatter(); } if (flags.EasyMode) { EnableEasyMode(); } if (flags.HouseMPRestoration || flags.HousesFillHp) { FixHouse(flags.HouseMPRestoration, flags.HousesFillHp); } if (flags.WeaponStats) { FixWeaponStats(); } if (flags.ChanceToRun) { FixChanceToRun(); } if (flags.EnemyStatusAttackBug) { FixEnemyStatusAttackBug(); } if (flags.BlackBeltAbsorb) { FixBBAbsorbBug(); } if (flags.MDefMode != MDefChangesEnum.None) { MDefChanges(flags.MDefMode); } if (flags.ThiefHitRate) { ThiefHitRate(); } if (flags.ImproveTurnOrderRandomization) { ImproveTurnOrderRandomization(rng); } if (flags.FixHitChanceCap) { FixHitChanceCap(); } if (flags.EnemyElementalResistancesBug) { FixEnemyElementalResistances(); } if (preferences.FunEnemyNames) { FunEnemyNames(preferences.TeamSteak); } var itemText = ReadText(ItemTextPointerOffset, ItemTextPointerBase, ItemTextPointerCount); itemText[(int)Item.Ribbon].Trim(); ExpGoldBoost(flags.ExpBonus, flags.ExpMultiplier); ScalePrices(flags, itemText, rng, ((bool)flags.ClampMinimumPriceScale), shopItemLocation); ScaleEncounterRate(flags.EncounterRate / 30.0, flags.DungeonEncounterRate / 30.0); overworldMap.ApplyMapEdits(); WriteMaps(maps); WriteText(itemText, ItemTextPointerOffset, ItemTextPointerBase, ItemTextOffset, UnusedGoldItems); if (flags.EnemyScaleFactor > 1) { ScaleEnemyStats(flags.EnemyScaleFactor, flags.WrapStatOverflow, flags.IncludeMorale, rng, ((bool)flags.ClampMinimumStatScale)); } if (flags.BossScaleFactor > 1) { ScaleBossStats(flags.BossScaleFactor, flags.WrapStatOverflow, flags.IncludeMorale, rng, ((bool)flags.ClampMinimumBossStatScale)); } PartyComposition(rng, flags); if (((bool)flags.RecruitmentMode)) { PubReplaceClinic(rng, flags); } if ((bool)flags.MapCanalBridge) { EnableCanalBridge(); } if (flags.NoDanMode) { NoDanMode(); } SetProgressiveScaleMode(flags.ProgressiveScaleMode); if (flags.DisableTentSaving) { CannotSaveOnOverworld(); } if (flags.DisableInnSaving) { CannotSaveAtInns(); } // We have to do "fun" stuff last because it alters the RNG state. RollCredits(rng); if (preferences.DisableDamageTileFlicker) { DisableDamageTileFlicker(); } if (preferences.ThirdBattlePalette) { UseVariablePaletteForCursorAndStone(); } if (preferences.PaletteSwap) { PaletteSwap(rng); } if (preferences.TeamSteak) { TeamSteak(); } if (preferences.Music != MusicShuffle.None) { ShuffleMusic(preferences.Music, rng); } WriteSeedAndFlags(Version, seed.ToHex(), Flags.EncodeFlagsText(flags)); ExtraTrackingAndInitCode(); }
public static ItemPlacement Create(IItemPlacementFlags flags, IncentiveData incentivesData, List <Item> allTreasures, ItemShopSlot caravanItemLocation, OverworldMap overworldMap) { ItemPlacement placement; if (flags.ClassicItemPlacement) { placement = new RandomItemPlacement(); } else { placement = new GuidedItemPlacement(); }; placement._flags = flags; placement._incentivesData = incentivesData; placement._allTreasures = allTreasures; placement._caravanItemLocation = caravanItemLocation; placement._overworldMap = overworldMap; return(placement); }
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(); }
public FloorHintsHintSource(MT19337 _rng, NPCdata _npcData, Flags _flags, OverworldMap _overworldMap, FF1Rom _rom) : base(_rng, _npcData, _flags, _overworldMap, _rom) { Prices = new ItemPrices(_rom); }