public static async Task <FF1Rom> CreateAsync(Stream readStream) { var rom = new FF1Rom(); await rom.LoadAsync(readStream); return(rom); }
public ExtConsumables(FF1Rom _rom, Flags _flags, MT19337 _rng, ShopData _shopData) { rom = _rom; flags = _flags; rng = _rng; ShopData = _shopData; }
public OverworldMap(FF1Rom rom, IMapEditFlags flags) { _rom = rom; var mapLocationRequirements = ItemLocations.MapLocationRequirements.ToDictionary(x => x.Key, x => x.Value.ToList()); if (flags.MapVolcanoIceRiver) { MapEditsToApply.Add(VolcanoIceRiver); mapLocationRequirements[MapLocation.GurguVolcano].Add(MapChange.Bridge | MapChange.Canoe); mapLocationRequirements[MapLocation.CresentLake].Add(MapChange.Bridge | MapChange.Canoe); mapLocationRequirements[MapLocation.ElflandTown].Add(MapChange.Bridge | MapChange.Canoe); mapLocationRequirements[MapLocation.ElflandCastle].Add(MapChange.Bridge | MapChange.Canoe); mapLocationRequirements[MapLocation.NorthwestCastle].Add(MapChange.Bridge | MapChange.Canoe); mapLocationRequirements[MapLocation.MarshCave].Add(MapChange.Bridge | MapChange.Canoe); mapLocationRequirements[MapLocation.DwarfCave].Add(MapChange.Bridge | MapChange.Canoe); } if (flags.MapConeriaDwarves) { MapEditsToApply.Add(ConeriaToDwarves); mapLocationRequirements[MapLocation.DwarfCave] = new List <MapChange> { MapChange.None }; } if (flags.MapTitansTrove) { mapLocationRequirements[MapLocation.TitansTunnelWest] = new List <MapChange> { MapChange.Canal | MapChange.Ship | MapChange.TitanFed, MapChange.Airship | MapChange.TitanFed }; } MapLocationRequirements = mapLocationRequirements; }
public ExitTeleData(FF1Rom _rom) { rom = _rom; TeleX = new MemTable <byte>(rom, 0x2C60, 16); TeleY = new MemTable <byte>(rom, 0x2C70, 16); }
public StartingInventory(MT19337 _rng, Flags _flags, FF1Rom _rom) { rng = _rng; flags = _flags; rom = _rom; ItemData = new StartingItems(rom); }
public ReversedFloors(FF1Rom _rom, List <Map> _maps, MT19337 _rng) { rom = _rom; maps = _maps; rng = _rng; tele = new NormTeleData(rom); enter = new EnterTeleData(rom); }
public MemTable(FF1Rom _rom, int _address, int _count) { rom = _rom; address = _address; count = _count; LoadTable(); }
public NormTeleData(FF1Rom _rom) { rom = _rom; TeleX = new MemTable <byte>(rom, 0x3F000, 256); TeleY = new MemTable <byte>(rom, 0x3F100, 256); TeleMap = new MemTable <MapId>(rom, 0x3F200, 256); }
public RibbonShuffle(FF1Rom _rom, MT19337 _rng, Flags _flags, ItemNames _itemsText, GearPermissions _armorPermissions) { rom = _rom; rng = _rng; flags = _flags; itemsText = _itemsText; armorPermissions = _armorPermissions; }
public BaseHintPlacementProvider(MT19337 _rng, NPCdata _npcData, Flags _flags, OverworldMap _overworldMap, FF1Rom _rom) { rng = _rng; npcData = _npcData; flags = _flags; overworldMap = _overworldMap; rom = _rom; }
public EnterTeleData(FF1Rom _rom) { rom = _rom; TeleX = new MemTable <byte>(rom, 0x2C00, 32); TeleY = new MemTable <byte>(rom, 0x2C20, 32); TeleMap = new MemTable <MapId>(rom, 0x2C40, 32); }
public MemTable(FF1Rom _rom, int _address, int _count, int _size) { rom = _rom; address = _address; count = _count; size = _size; LoadTable(); }
public ExpChests(FF1Rom _rom, Flags _flags, MT19337 _rng) { rom = _rom; flags = _flags; rng = _rng; treasureData = new TreasureData(rom); itemPrices = new ItemPrices(rom); }
public override void Put(FF1Rom rom) { if (Item > Item.Soft) { throw new InvalidOperationException( $"Attempted to Put invalid item shop placement: \n{SpoilerText}"); } base.Put(rom); }
public TileSet(FF1Rom _rom, byte idx) { TileProperties = new TilePropTable(_rom, idx); TileAttributes = new MemTable <byte>(_rom, 0x400 + 0x80 * idx, 128); TopLeftTiles = new MemTable <byte>(_rom, 0x1000 + 0x200 * idx, 128); TopRightTiles = new MemTable <byte>(_rom, 0x1080 + 0x200 * idx, 128); BottemLeftTiles = new MemTable <byte>(_rom, 0x1100 + 0x200 * idx, 128); BottemRightTiles = new MemTable <byte>(_rom, 0x1180 + 0x200 * idx, 128); }
public StartingEquipment(MT19337 _rng, Flags _flags, FF1Rom _rom) { rng = _rng; flags = _flags; rom = _rom; spellHelper = new SpellHelper(rom); weapons = Weapon.LoadAllWeapons(rom, flags).ToList(); armors = Armor.LoadAllArmors(rom, flags).ToList(); }
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 ShopKiller(MT19337 _rng, Flags _flags, List <Map> _maps, FF1Rom _rom) { rng = _rng; flags = _flags; rom = _rom; maps = _maps; ShopData = new ShopData(rom); QuestItems = new HashSet <Item>(ItemLists.AllQuestItems); }
public TilePropTable(FF1Rom _rom, byte idx) { if (idx == 0xff) { // overworld TileProperties = new MemTable <byte>(_rom, 0, 256); } else { TileProperties = new MemTable <byte>(_rom, 0x800 + 0x100 * idx, 256); } }
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 TeleportShuffle(FF1Rom _rom, OwMapExchangeData data) { rom = _rom; if (data?.OverworldCoordinates != null) { OverworldCoordinates = data.OverworldCoordinates.Select(kv => (Enum.Parse <OverworldTeleportIndex>(kv.Key), new Coordinate(kv.Value.X, kv.Value.Y, CoordinateLocale.Overworld))).ToDictionary(kv => kv.Item1, kv => kv.Item2); } else { OverworldCoordinates = VanillaOverworldCoordinates; } }
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 override void Put(FF1Rom rom) { if (_useVanillaRoutineAddress) { base.Put(rom); return; } if (_requiredItemTrade != Item.None) { rom.Put(_objectRoutineAddress, _itemTradeRoutineAddress); rom.Put(Address - _giftItemIndex, new[] { (byte)_requiredItemTrade }); } else { rom.Put(_objectRoutineAddress, _eventFlagRoutineAddress); rom.Put(Address - _giftItemIndex, new[] { (byte)_requiredGameEventFlag }); } base.Put(rom); }
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 TileSet(FF1Rom _rom, byte idx) { if (idx == OverworldIndex) { TileProperties = new MemTable <TileProp>(_rom, 0x0000, 128); TopLeftTiles = new MemTable <byte>(_rom, 0x0100, 128); TopRightTiles = new MemTable <byte>(_rom, 0x0180, 128); BottomLeftTiles = new MemTable <byte>(_rom, 0x0200, 128); BottomRightTiles = new MemTable <byte>(_rom, 0x0280, 128); TileAttributes = new MemTable <byte>(_rom, 0x0300, 128); } else { TileProperties = new MemTable <TileProp>(_rom, 0x800 + 0x100 * idx, 128); TileAttributes = new MemTable <byte>(_rom, 0x400 + 0x80 * idx, 128); TopLeftTiles = new MemTable <byte>(_rom, 0x1000 + 0x200 * idx, 128); TopRightTiles = new MemTable <byte>(_rom, 0x1080 + 0x200 * idx, 128); BottomLeftTiles = new MemTable <byte>(_rom, 0x1100 + 0x200 * idx, 128); BottomRightTiles = new MemTable <byte>(_rom, 0x1180 + 0x200 * idx, 128); } }
public void BuildExpChests() { rom.PutInBank(0x1F, 0xDDD0, Blob.FromHex("A9B648A9FF48A9114C03FE8A20DA8760")); int expChestCountPercent = rng.Between(flags.ExpChestConversionMin, flags.ExpChestConversionMax); int expChestCount = treasureData.Data.Where(g => g >= Item.Gold10).Count() * expChestCountPercent / 100; double lowScale = (double)flags.ExpChestMinReward / (double)BaseExp; double highScale = (double)flags.ExpChestMaxReward / (double)BaseExp; if (expChestCount == 0) { return; } LoadData(); var unusedGoldDic = new HashSet <int>(rom.UnusedGoldItems.Cast <int>()); // construct a dictionary and get a shuffled index into it. var goldItems = ItemLists.AllGoldTreasure.Select(g => (item: g, price: itemPrices[g], name: itemNames[(int)g])).ToList(); goldItems.Shuffle(rng); var goldItemsDic = goldItems.Select((g, i) => (shuffleindex: i, item: g.item, price: g.price, name: g.name)).ToDictionary(g => g.item); var expItems = new HashSet <Item>(treasureData.Data .Where(g => goldItemsDic.ContainsKey(g) && !unusedGoldDic.Contains((int)g)) .Select(g => (item: g, shuffleindex: goldItemsDic[g].shuffleindex)) .OrderBy(g => g.shuffleindex) .Take(expChestCount) .Select(g => g.item) .Distinct()); var firstExpItem = RepackGoldExpItems(goldItemsDic, expItems, unusedGoldDic); for (int i = (int)firstExpItem; i < 176; i++) { if (unusedGoldDic.Contains(i)) { continue; } var e = (Item)i; var exp = (ushort)Math.Min(Math.Max(FF1Rom.RangeScale(BaseExp, lowScale, highScale, 1.0, rng), 0), 65535); itemPrices[e] = exp; itemNames[(int)e] = exp.ToString() + " EXP"; } FirstExpItem = firstExpItem; if (flags.Archipelago) { rom.PutInBank(0x11, 0xB446, new byte[] { (byte)firstExpItem }); } else { rom.PutInBank(0x11, 0xB447, new byte[] { (byte)firstExpItem }); } var result = treasureData.Data.Where(x => x > Item.Gold10).OrderBy(x => x).Select(x => itemNames[(int)x]).ToList(); StoreData(); }
public List <IRewardSource> PlaceSaneItems(MT19337 rng, FF1Rom rom) { _rom = rom; var incentivePool = _incentivesData.IncentiveItems.Where(x => _allTreasures.Contains(x)).ToList(); var forcedItems = _incentivesData.ForcedItemPlacements.ToList(); var removedItems = _incentivesData.RemovedItems.ToList(); var unincentivizedQuestItems = ItemLists.AllQuestItems .Where(x => !incentivePool.Contains(x) && _allTreasures.Contains(x) && !forcedItems.Any(y => y.Item == x) && !removedItems.Contains(x)) .ToList(); var shards = new List <Item>(); var treasurePool = _allTreasures.ToList(); bool jingleGuaranteedDefenseItem = true; bool jingleGuaranteedPowerItem = true; if (_flags.GuaranteedDefenseItem != GuaranteedDefenseItem.None && !(_flags.ItemMagicMode == ItemMagicMode.None) && !incentivePool.Contains(Item.PowerRod)) { unincentivizedQuestItems.Add(Item.PowerRod); jingleGuaranteedDefenseItem = false; } if (_flags.GuaranteedPowerItem != GuaranteedPowerItem.None && !(_flags.ItemMagicMode == ItemMagicMode.None) && !incentivePool.Contains(Item.PowerGauntlets)) { unincentivizedQuestItems.Add(Item.PowerGauntlets); jingleGuaranteedPowerItem = false; } foreach (var incentive in incentivePool) { treasurePool.Remove(incentive); } foreach (var placement in forcedItems) { treasurePool.Remove(placement.Item); } foreach (var questItem in unincentivizedQuestItems) { treasurePool.Remove(questItem); } foreach (var item in removedItems) { treasurePool.Remove(item); } while (treasurePool.Remove(Item.Shard)) { shards.Add(Item.Shard); } ItemPlacementContext ctx = new ItemPlacementContext { Forced = forcedItems, Incentivized = incentivePool, Unincentivized = unincentivizedQuestItems, Shards = shards, Removed = removedItems, AllTreasures = treasurePool.ToList(), }; ItemPlacementResult result = DoSanePlacement(rng, ctx); List <IRewardSource> placedItems = result.PlacedItems; treasurePool = result.RemainingTreasures; //setup jingle for "incentive treasures", the placed items should just be key items, loose incentive items if (_flags.IncentiveChestItemsFanfare) { foreach (var placedItem in placedItems) { //dont make shards jingle that'd be annoying //dont make free items that get replaced, aka cabins, jingle if (placedItem is TreasureChest && placedItem.Item != Item.Shard && placedItem.Item != ReplacementItem) { if ((placedItem.Item == Item.PowerGauntlets && !jingleGuaranteedPowerItem) || (placedItem.Item == Item.PowerRod && !jingleGuaranteedDefenseItem)) { continue; } rom.Put(placedItem.Address - FF1Rom.TreasureOffset + FF1Rom.TreasureJingleOffset, new byte[] { (byte)placedItem.Item }); } } } // 8. Place all remaining unincentivized treasures or incentivized non-quest items that weren't placed var itemLocationPool = _incentivesData.AllValidItemLocations.ToList(); itemLocationPool = itemLocationPool.Where(x => !x.IsUnused && !placedItems.Any(y => y.Address == x.Address)).ToList(); MoreConsumableChests.Work(_flags, treasurePool, rng); if ((bool)_flags.GuaranteedMasamune && !incentivePool.Contains(Item.Masamune) && (bool)_flags.SendMasamuneHome) { // Remove Masamune from treasure pool (This will also causes Masamune to not be placed by RandomLoot) treasurePool.Remove(Item.Masamune); } // Use cabins to balance item population int poolDifference = itemLocationPool.Count() - treasurePool.Count(); if (poolDifference < 0) { for (int i = 0; i > poolDifference; i--) { treasurePool.Remove(Item.Cabin); } } else if (poolDifference > 0) { treasurePool.AddRange(Enumerable.Repeat(Item.Cabin, poolDifference)); } Debug.Assert(treasurePool.Count() == itemLocationPool.Count()); List <IRewardSource> normalTreasures = new(); var randomizeTreasureMode = (_flags.RandomizeTreasure == RandomizeTreasureMode.Random) ? (RandomizeTreasureMode)rng.Between(0, 2) : _flags.RandomizeTreasure; if (randomizeTreasureMode != RandomizeTreasureMode.None) { IItemGenerator generator; // We want to leave out anything incentivized (and thus already placed), but // add all the other stuff that you can't find in vanilla. var randomTreasure = treasurePool.ToList(); if (randomizeTreasureMode == RandomizeTreasureMode.DeepDungeon) { generator = new DeepDungeonItemGenerator(itemLocationPool, rom.UnusedGoldItems, removedItems, normalTreasures, (_flags.GameMode == GameModes.DeepDungeon), _flags.Etherizer, rom); } else { generator = new ItemGenerator(randomTreasure, rom.UnusedGoldItems, removedItems, _flags.WorldWealth); } treasurePool = treasurePool.Select(treasure => generator.GetItem(rng)).ToList(); } if ((bool)_flags.BetterTrapChests && randomizeTreasureMode != RandomizeTreasureMode.DeepDungeon) { // First we'll make a list of all 'notable' treasure. var notableTreasureList = new List <Item>() .Concat(ItemLists.UberTier) .Concat(ItemLists.LegendaryWeaponTier) .Concat(ItemLists.LegendaryArmorTier) .Concat(ItemLists.RareWeaponTier) .Concat(ItemLists.RareArmorTier); // Convert the list to a HashSet since we'll be doing lookups in it. var notableTreasure = new HashSet <Item>(notableTreasureList); // We sort the treasure pool based on value (sort of) and pull out the highest ranked ones to put // in the trap chests we picked out. var notableTreasurePool = treasurePool.Where(item => notableTreasure.Contains(item)).ToList(); // Since some chests might be incentivized, remove those that aren't in the pool. var trapChestPool = TrapChests.Where(chest => itemLocationPool.Contains(chest)); foreach (var chest in trapChestPool) { // It seems unlikely that is possible, but just in case. if (!notableTreasurePool.Any()) { break; } // Pick a random treasure and place it. var treasure = notableTreasurePool.SpliceRandom(rng); placedItems.Add(NewItemPlacement(chest, treasure)); // Since it was placed, remove both the item and location from the remaining pool. treasurePool.Remove(treasure); itemLocationPool.Remove(chest); } // This should still be true at the end, so make sure it is Debug.Assert(treasurePool.Count() == itemLocationPool.Count()); } if (randomizeTreasureMode == RandomizeTreasureMode.DeepDungeon && _flags.DeepDungeonGenerator == DeepDungeonGeneratorMode.Progressive) { placedItems.AddRange(normalTreasures); } else { treasurePool.Shuffle(rng); itemLocationPool.Shuffle(rng); var leftovers = treasurePool.Zip(itemLocationPool, (treasure, location) => NewItemPlacement(location, treasure)); placedItems.AddRange(leftovers); } //chest order placement var chestOrderPool = treasurePool; if (_flags.ShardHunt) { //add the shards back into the chest order pool chestOrderPool = chestOrderPool.Concat(shards).ToList(); } chestOrderPool.Shuffle(rng); for (int i = 0; i < chestOrderPool.Count; i++) { rom.Put(FF1Rom.TreasureChestOrderOffset + i, new byte[] { (byte)chestOrderPool[i] }); } return(placedItems); }