Exemple #1
0
        public SCLogic(FF1Rom _rom, SCMain _main, List <IRewardSource> _itemPlacement, IVictoryConditionFlags _victoryConditions, bool _excludeBridge)
        {
            rom               = _rom;
            main              = _main;
            itemPlacement     = _itemPlacement;
            victoryConditions = _victoryConditions;
            excludeBridge     = _excludeBridge;

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

            GetShipDockArea();

            BuildTunnels();

            DoPathing();

            DoAirShipPathing();

            RemoveEmptyAreas();

            ProcessTreasures();

            ProcessShopSlot();

            ProcessNPCs();

            RewardSources = rewardSourceDic.Values.ToList();

            ProcessFreebies();
        }
Exemple #2
0
        private void BuildInitialRequirements(IVictoryConditionFlags victoryConditions)
        {
            airShipLocationAccessible = false;

            requirements = AccessRequirement.None;
            if ((bool)victoryConditions.FreeLute)
            {
                requirements |= AccessRequirement.Lute;
            }

            changes = MapChange.None;
            if (victoryConditions.IsBridgeFree ?? false)
            {
                changes |= MapChange.Bridge;
            }
            if (victoryConditions.IsShipFree ?? false)
            {
                changes |= MapChange.Ship;
                SetShipDock(255);
            }
            if (victoryConditions.IsAirshipFree ?? false)
            {
                changes |= MapChange.Airship;
                airShipLocationAccessible = true;
            }
            if (victoryConditions.IsCanalFree ?? false)
            {
                changes |= MapChange.Canal;
            }
            if (victoryConditions.IsCanoeFree ?? false)
            {
                changes |= MapChange.Canoe;
            }
        }
        public static bool CheckSanity(List <IRewardSource> treasurePlacements,
                                       Dictionary <MapLocation, List <MapChange> > mapLocationRequirements,
                                       IVictoryConditionFlags victoryConditions)
        {
            const int maxIterations    = 20;
            var       currentIteration = 0;
            var       currentAccess    = AccessRequirement.None;

            if (victoryConditions.ShardHunt)
            {
                currentAccess |= AccessRequirement.Lute;
            }

            var currentMapChanges = MapChange.None;

            Func <IEnumerable <MapLocation> > currentMapLocations =
                () => mapLocationRequirements
                .Where(x => x.Value
                       .Any(y => currentMapChanges.HasFlag(y))).Select(x => x.Key);
            Func <IEnumerable <IRewardSource> > currentItemLocations =
                () => treasurePlacements
                .Where(x =>
            {
                var locations = currentMapLocations().ToList();
                return(locations.Contains(x.MapLocation) &&
                       currentAccess.HasFlag(x.AccessRequirement) &&
                       (!(x is MapObject) || locations.Contains(((MapObject)x).SecondLocation)));
            });

            var accessibleLocationCount = currentItemLocations().Count();
            var requiredAccess          = AccessRequirement.All;
            var requiredMapChanges      = new List <MapChange> {
                MapChange.All
            };

            if (victoryConditions.OnlyRequireGameIsBeatable)
            {
                var winTheGameAccess   = ItemLocations.ChaosReward.AccessRequirement;
                var winTheGameLocation = ItemLocations.ChaosReward.MapLocation;
                requiredAccess     = winTheGameAccess;
                requiredMapChanges = mapLocationRequirements[winTheGameLocation];
            }

            while (!currentAccess.HasFlag(requiredAccess) ||
                   !requiredMapChanges.Any(x => currentMapChanges.HasFlag(x)))
            {
                if (currentIteration > maxIterations)
                {
                    throw new InvalidOperationException($"Sanity Check hit max iterations: {currentIteration}");
                }
                currentIteration++;
                var currentItems = currentItemLocations().Select(x => x.Item).ToList();

                if (!currentAccess.HasFlag(AccessRequirement.Key) &&
                    currentItems.Contains(Item.Key))
                {
                    currentAccess |= AccessRequirement.Key;
                }
                if (!currentMapChanges.HasFlag(MapChange.Bridge) &&
                    currentItems.Contains(Item.Bridge) &&
                    currentMapLocations().Contains(MapLocation.BridgeLocation))
                {
                    currentMapChanges |= MapChange.Bridge;
                }
                if (!currentAccess.HasFlag(AccessRequirement.Crown) &&
                    currentItems.Contains(Item.Crown))
                {
                    currentAccess |= AccessRequirement.Crown;
                }
                if (!currentAccess.HasFlag(AccessRequirement.Crystal) &&
                    currentItems.Contains(Item.Crystal))
                {
                    currentAccess |= AccessRequirement.Crystal;
                }
                if (!currentAccess.HasFlag(AccessRequirement.Herb) &&
                    currentItems.Contains(Item.Herb))
                {
                    currentAccess |= AccessRequirement.Herb;
                }
                if (!currentMapChanges.HasFlag(MapChange.Canoe) &&
                    currentItems.Contains(Item.Canoe))
                {
                    currentMapChanges |= MapChange.Canoe;
                }
                if (!currentMapChanges.HasFlag(MapChange.Ship) &&
                    currentItems.Contains(Item.Ship))
                {
                    currentMapChanges |= MapChange.Ship;
                }
                if (!currentAccess.HasFlag(AccessRequirement.Tnt) &&
                    currentItems.Contains(Item.Tnt))
                {
                    currentAccess |= AccessRequirement.Tnt;
                }
                if (!currentAccess.HasFlag(AccessRequirement.Adamant) &&
                    currentItems.Contains(Item.Adamant))
                {
                    currentAccess |= AccessRequirement.Adamant;
                }
                if (!currentMapChanges.HasFlag(MapChange.Canal) &&
                    currentItems.Contains(Item.Canal) &&
                    currentMapChanges.HasFlag(MapChange.Ship))
                {
                    currentMapChanges |= MapChange.Canal;
                }
                if (!currentMapChanges.HasFlag(MapChange.TitanFed) &&
                    currentItems.Contains(Item.Ruby) &&
                    currentMapLocations().Contains(MapLocation.TitansTunnelEast))
                {
                    currentMapChanges |= MapChange.TitanFed;
                }
                if (!currentAccess.HasFlag(AccessRequirement.Rod) &&
                    currentItems.Contains(Item.Rod))
                {
                    currentAccess |= AccessRequirement.Rod;
                }
                if (!currentAccess.HasFlag(AccessRequirement.Slab) &&
                    currentItems.Contains(Item.Slab))
                {
                    currentAccess |= AccessRequirement.Slab;
                }
                if (!currentMapChanges.HasFlag(MapChange.Airship) &&
                    (currentItems.Contains(Item.Floater)) &&                     // || currentItems.Contains(Item.Airship)) &&
                    currentMapLocations().Contains(MapLocation.AirshipLocation))
                {
                    currentMapChanges |= MapChange.Airship;
                }

                if (!currentAccess.HasFlag(AccessRequirement.Bottle) &&
                    currentItems.Contains(Item.Bottle))
                {
                    currentAccess |= AccessRequirement.Bottle;
                }
                if (!currentAccess.HasFlag(AccessRequirement.Oxyale) &&
                    currentItems.Contains(Item.Oxyale))
                {
                    currentAccess |= AccessRequirement.Oxyale;
                }
                if (!currentMapChanges.HasFlag(MapChange.Chime) &&
                    currentItems.Contains(Item.Chime))
                {
                    currentMapChanges |= MapChange.Chime;
                }
                if (!currentAccess.HasFlag(AccessRequirement.Cube) &&
                    currentItems.Contains(Item.Cube))
                {
                    currentAccess |= AccessRequirement.Cube;
                }
                if (!currentAccess.HasFlag(AccessRequirement.EarthOrb) &&
                    currentItems.Contains(Item.EarthOrb))
                {
                    currentAccess |= AccessRequirement.EarthOrb;
                }
                if (!currentAccess.HasFlag(AccessRequirement.FireOrb) &&
                    currentItems.Contains(Item.FireOrb))
                {
                    currentAccess |= AccessRequirement.FireOrb;
                }
                if (!currentAccess.HasFlag(AccessRequirement.WaterOrb) &&
                    currentItems.Contains(Item.WaterOrb))
                {
                    currentAccess |= AccessRequirement.WaterOrb;
                }
                if (!currentAccess.HasFlag(AccessRequirement.AirOrb) &&
                    currentItems.Contains(Item.AirOrb))
                {
                    currentAccess |= AccessRequirement.AirOrb;
                }
                if (!currentAccess.HasFlag(AccessRequirement.Lute) &&
                    currentItems.Contains(Item.Lute))
                {
                    currentAccess |= AccessRequirement.Lute;
                }

                var newCount = currentItemLocations().Count();
                if (newCount <= accessibleLocationCount)
                {
                    return(false);
                }
                accessibleLocationCount = newCount;
            }

            return(true);
        }
Exemple #4
0
        public (bool complete, IEnumerable <IRewardSource> rewardSources, AccessRequirement requirements, MapChange changes) Crawl(IVictoryConditionFlags victoryConditions)
        {
            Stopwatch w = Stopwatch.StartNew();

            immediateAreas           = new HashSet <short>(256);
            processedAreas           = new HashSet <short>(2048);
            processedDungeons        = new HashSet <OverworldTeleportIndex>(32);
            deferredAreas            = new HashSet <SCDeferredAreaQueueEntry>(64, new SCDeferredAreaQueueEntryEqualityComparer());
            deferredPointOfInterests = new Queue <SCPointOfInterest>();

            rewardSources     = new HashSet <IRewardSource>(256, new RewardSourceEqualityComparer());
            shipDockAreaIndex = -1;
            slabTranslated    = false;
            herbCheckedIn     = false;
            princessRescued   = false;
            vampireAccessible = false;
            airShipLiftOff    = false;

            BuildInitialRequirements(victoryConditions);

            SetAirShipPoi();

            short    areaIndex = Main.Overworld.Tiles[locations.StartingLocation.X, locations.StartingLocation.Y].Area;
            SCOwArea area      = Main.Overworld.Areas[areaIndex];

            CrawlOwArea(area);

            ProcessImmediateAreas();

            while (ProcessDeferredAreas())
            {
                ProcessImmediateAreas();
            }

            //that for just means, that there's a fault in the function. Actually the mere existence of the call is a fault  in the above functions
            for (int i = 0; i < 10; i++)
            {
                ProcessDeferredPointsOfInterest();
            }

            w.Stop();

            var requiredAccess     = AccessRequirement.All;
            var requiredMapChanges = MapChange.All;

            if ((bool)victoryConditions.IsFloaterRemoved)
            {
                requiredMapChanges &= ~MapChange.Airship;
            }

            bool complete = changes.HasFlag(requiredMapChanges) && requirements.HasFlag(requiredAccess);

            return(complete, rewardSources, requirements, changes);
        }
Exemple #5
0
        public (bool Complete, List <MapLocation> MapLocations, AccessRequirement Requirements) CheckSanity(List <IRewardSource> _treasurePlacements, Dictionary <MapLocation, Tuple <List <MapChange>, AccessRequirement> > fullLocationRequirements, IVictoryConditionFlags victoryConditions)
        {
            treasurePlacements = _treasurePlacements;

            //kids, don't try this at home. Calculating an index from an address is usually not the way to go.
            chests   = treasurePlacements.Select(r => r as TreasureChest).Where(r => r != null).ToDictionary(r => (byte)(r.Address - 0x3100));
            npcs     = treasurePlacements.Select(r => r as MapObject).Where(r => r != null).ToDictionary(r => r.ObjectId);
            shopslot = (ItemShopSlot)treasurePlacements.FirstOrDefault(r => r is ItemShopSlot);

            var result = Crawl(victoryConditions);

            var mapLocations = result.rewardSources.Select(r => r.MapLocation).Distinct().ToList();

            return(result.complete, mapLocations, result.requirements);
        }
Exemple #6
0
        public (bool Complete, List <MapLocation> MapLocations, AccessRequirement Requirements) CheckSanity(List <IRewardSource> treasurePlacements,
                                                                                                            Dictionary <MapLocation, Tuple <List <MapChange>, AccessRequirement> > fullLocationRequirements,
                                                                                                            IVictoryConditionFlags victoryConditions)

        {
            const int maxIterations    = 20;
            var       currentIteration = 0;
            var       currentAccess    = AccessRequirement.None;

            if ((bool)victoryConditions.FreeLute)
            {
                currentAccess |= AccessRequirement.Lute;
            }

            var currentMapChanges = MapChange.None;

            if (victoryConditions.IsBridgeFree ?? false)
            {
                currentMapChanges |= MapChange.Bridge;
            }
            if (victoryConditions.IsShipFree ?? false)
            {
                currentMapChanges |= MapChange.Ship;
            }
            if (victoryConditions.IsAirshipFree ?? false)
            {
                currentMapChanges |= MapChange.Airship;
            }
            if (victoryConditions.IsCanalFree ?? false)
            {
                currentMapChanges |= MapChange.Canal;
            }
            if (victoryConditions.IsCanoeFree ?? false)
            {
                currentMapChanges |= MapChange.Canoe;
            }

            IEnumerable <MapLocation> currentMapLocations()
            {
                return(fullLocationRequirements.Where(x => x.Value.Item1.Any(y => currentMapChanges.HasFlag(y) && currentAccess.HasFlag(x.Value.Item2))).Select(x => x.Key));
            }

            IEnumerable <IRewardSource> currentItemLocations()
            {
                var locations = currentMapLocations().ToList();

                return(treasurePlacements.Where(x =>
                {
                    return locations.Contains(x.MapLocation) && currentAccess.HasFlag(x.AccessRequirement) &&
                    locations.Contains((x as MapObject)?.SecondLocation ?? MapLocation.StartingLocation);
                }));
            }

            var requiredAccess     = AccessRequirement.All;
            var requiredMapChanges = MapChange.All;

            if ((bool)victoryConditions.IsFloaterRemoved)
            {
                requiredMapChanges &= ~MapChange.Airship;
            }

            var accessibleLocationCount = 0;

            while (!currentAccess.HasFlag(requiredAccess) ||
                   !currentMapChanges.HasFlag(requiredMapChanges))
            {
                if (currentIteration > maxIterations)
                {
                    throw new InvalidOperationException($"Sanity Check hit max iterations: {currentIteration}");
                }

                currentIteration++;
                var accessibleLocations = currentItemLocations().ToList();
                if (accessibleLocations.Count <= accessibleLocationCount)
                {
                    return(false, currentMapLocations().ToList(), currentAccess);
                }

                accessibleLocationCount = accessibleLocations.Count;
                var currentItems = accessibleLocations.Select(x => x.Item).ToList();

                if (!currentAccess.HasFlag(AccessRequirement.Key) &&
                    currentItems.Contains(Item.Key))
                {
                    currentAccess |= AccessRequirement.Key;
                }
                if (!currentMapChanges.HasFlag(MapChange.Bridge) &&
                    currentItems.Contains(Item.Bridge))
                {
                    currentMapChanges |= MapChange.Bridge;
                }
                if (!currentAccess.HasFlag(AccessRequirement.Crown) &&
                    currentItems.Contains(Item.Crown))
                {
                    currentAccess |= AccessRequirement.Crown;
                }
                if (!currentAccess.HasFlag(AccessRequirement.Crystal) &&
                    currentItems.Contains(Item.Crystal))
                {
                    currentAccess |= AccessRequirement.Crystal;
                }
                if (!currentAccess.HasFlag(AccessRequirement.Herb) &&
                    currentItems.Contains(Item.Herb))
                {
                    currentAccess |= AccessRequirement.Herb;
                }
                if (!currentMapChanges.HasFlag(MapChange.Canoe) &&
                    currentItems.Contains(Item.Canoe))
                {
                    currentMapChanges |= MapChange.Canoe;
                }
                if (!currentMapChanges.HasFlag(MapChange.Ship) &&
                    currentItems.Contains(Item.Ship))
                {
                    currentMapChanges |= MapChange.Ship;
                }
                if (!currentAccess.HasFlag(AccessRequirement.Tnt) &&
                    currentItems.Contains(Item.Tnt))
                {
                    currentAccess |= AccessRequirement.Tnt;
                }
                if (!currentAccess.HasFlag(AccessRequirement.Adamant) &&
                    currentItems.Contains(Item.Adamant))
                {
                    currentAccess |= AccessRequirement.Adamant;
                }
                if (!currentMapChanges.HasFlag(MapChange.Canal) &&
                    currentItems.Contains(Item.Canal) &&
                    currentMapChanges.HasFlag(MapChange.Ship))
                {
                    currentMapChanges |= MapChange.Canal;
                }
                if (!currentMapChanges.HasFlag(MapChange.TitanFed) &&
                    currentItems.Contains(Item.Ruby) &&
                    (currentMapLocations().Contains(MapLocation.TitansTunnelEast) ||
                     currentMapLocations().Contains(MapLocation.TitansTunnelWest)))
                {
                    currentMapChanges |= MapChange.TitanFed;
                    currentAccess     |= AccessRequirement.Ruby;
                }
                if (!currentAccess.HasFlag(AccessRequirement.Rod) &&
                    currentItems.Contains(Item.Rod))
                {
                    currentAccess |= AccessRequirement.Rod;
                }
                if (!currentAccess.HasFlag(AccessRequirement.Slab) &&
                    currentItems.Contains(Item.Slab))
                {
                    currentAccess |= AccessRequirement.Slab;
                }
                if (!currentMapChanges.HasFlag(MapChange.Airship) &&
                    (currentItems.Contains(Item.Floater)) &&
                    currentMapLocations().Contains(MapLocation.AirshipLocation))
                {
                    currentMapChanges |= MapChange.Airship;
                }
                if (!currentAccess.HasFlag(AccessRequirement.Bottle) &&
                    currentItems.Contains(Item.Bottle))
                {
                    currentAccess |= AccessRequirement.Bottle;
                }
                if (!currentAccess.HasFlag(AccessRequirement.Oxyale) &&
                    currentItems.Contains(Item.Oxyale))
                {
                    currentAccess |= AccessRequirement.Oxyale;
                }
                if (!currentMapChanges.HasFlag(MapChange.Chime) &&
                    currentItems.Contains(Item.Chime))
                {
                    currentMapChanges |= MapChange.Chime;
                }
                if (!currentAccess.HasFlag(AccessRequirement.Cube) &&
                    currentItems.Contains(Item.Cube))
                {
                    currentAccess |= AccessRequirement.Cube;
                }
                if (!currentAccess.HasFlag(AccessRequirement.EarthOrb) &&
                    currentItems.Contains(Item.EarthOrb))
                {
                    currentAccess |= AccessRequirement.EarthOrb;
                }
                if (!currentAccess.HasFlag(AccessRequirement.FireOrb) &&
                    currentItems.Contains(Item.FireOrb))
                {
                    currentAccess |= AccessRequirement.FireOrb;
                }
                if (!currentAccess.HasFlag(AccessRequirement.WaterOrb) &&
                    currentItems.Contains(Item.WaterOrb))
                {
                    currentAccess |= AccessRequirement.WaterOrb;
                }
                if (!currentAccess.HasFlag(AccessRequirement.AirOrb) &&
                    currentItems.Contains(Item.AirOrb))
                {
                    currentAccess |= AccessRequirement.AirOrb;
                }
                if (!currentAccess.HasFlag(AccessRequirement.Lute) &&
                    currentItems.Contains(Item.Lute))
                {
                    currentAccess |= AccessRequirement.Lute;
                }
            }

            return(true, currentMapLocations().ToList(), currentAccess);
        }