Beispiel #1
0
		public IReadOnlyDictionary<CPos, SubCell> OccupiedCells(ActorInfo info, CPos location, SubCell subCell = SubCell.Any)
		{
			var occupied = OccupiesSpace ? new Dictionary<CPos, SubCell>() { { location, SubCell.FullCell } } :
				new Dictionary<CPos, SubCell>();

			return new ReadOnlyDictionary<CPos, SubCell>(occupied);
		}
Beispiel #2
0
		public List<CPos> FindUnitPathToRange(CPos source, SubCell srcSub, WPos target, WDist range, Actor self)
		{
			var mi = self.Info.TraitInfo<MobileInfo>();
			var targetCell = world.Map.CellContaining(target);

			// Correct for SubCell offset
			target -= world.Map.OffsetOfSubCell(srcSub);

			// Select only the tiles that are within range from the requested SubCell
			// This assumes that the SubCell does not change during the path traversal
			var tilesInRange = world.Map.FindTilesInCircle(targetCell, range.Length / 1024 + 1)
				.Where(t => (world.Map.CenterOfCell(t) - target).LengthSquared <= range.LengthSquared
							&& mi.CanEnterCell(self.World, self, t));

			// See if there is any cell within range that does not involve a cross-domain request
			// Really, we only need to check the circle perimeter, but it's not clear that would be a performance win
			var domainIndex = world.WorldActor.TraitOrDefault<DomainIndex>();
			if (domainIndex != null)
			{
				var passable = mi.GetMovementClass(world.TileSet);
				tilesInRange = new List<CPos>(tilesInRange.Where(t => domainIndex.IsPassable(source, t, (uint)passable)));
				if (!tilesInRange.Any())
					return EmptyPath;
			}

			using (var fromSrc = PathSearch.FromPoints(world, mi, self, tilesInRange, source, true))
			using (var fromDest = PathSearch.FromPoint(world, mi, self, source, targetCell, true).Reverse())
				return FindBidiPath(fromSrc, fromDest);
		}
Beispiel #3
0
        public bool AnyUnitsAt(CPos a, SubCell sub)
        {
            for( var i = influence[ a.X, a.Y ] ; i != null ; i = i.next )
                if (i.subCell == sub || i.subCell == SubCell.FullCell)
                    return true;

            return false;
        }
        public IEnumerable<Actor> GetUnitsAt( int2 a, SubCell sub )
        {
            if (!map.IsInMap(a)) yield break;

            for( var i = influence[ a.X, a.Y ] ; i != null ; i = i.next )
                if (!i.actor.Destroyed && (i.subCell == sub || i.subCell == SubCell.FullCell))
                    yield return i.actor;
        }
Beispiel #5
0
		public IEnumerable<Actor> GetUnitsAt(CPos a, SubCell sub)
		{
			if (!map.Contains(a))
				yield break;

			for (var i = influence[a]; i != null; i = i.Next)
				if (!i.Actor.Destroyed && (i.SubCell == sub || i.SubCell == SubCell.FullCell))
					yield return i.Actor;
		}
		public List<CPos> FindUnitPathToRange(CPos source, SubCell srcSub, WPos target, WDist range, Actor self)
		{
			using (new PerfSample("Pathfinder"))
			{
				var key = "FindUnitPathToRange" + self.ActorID + source.X + source.Y + target.X + target.Y;
				var cachedPath = cacheStorage.Retrieve(key);

				if (cachedPath != null)
					return cachedPath;

				var pb = pathFinder.FindUnitPathToRange(source, srcSub, target, range, self);

				cacheStorage.Store(key, pb);

				return pb;
			}
		}
Beispiel #7
0
        public Mobile(ActorInitializer init, MobileInfo info)
        {
            this.self = init.self;
            this.Info = info;

            toSubCell = fromSubCell = info.SharesCell ? SubCell.Center : SubCell.FullCell;
            if (init.Contains<SubCellInit>())
            {
                this.fromSubCell = this.toSubCell = init.Get<SubCellInit, SubCell>();
            }

            if (init.Contains<LocationInit>())
            {
                this.__fromCell = this.__toCell = init.Get<LocationInit, int2>();
                this.PxPosition = Util.CenterOfCell(fromCell) + info.SubCellOffsets[fromSubCell];
            }

            this.Facing = init.Contains<FacingInit>() ? init.Get<FacingInit, int>() : info.InitialFacing;
            this.Altitude = init.Contains<AltitudeInit>() ? init.Get<AltitudeInit, int>() : 0;
        }
Beispiel #8
0
        public SubCell GetAvailableSubCell(Actor self, CPos cell, BlockedByActor check, SubCell preferredSubCell = SubCell.Any, Actor ignoreActor = null)
        {
            if (MovementCostForCell(cell) == short.MaxValue)
            {
                return(SubCell.Invalid);
            }

            if (check > BlockedByActor.None)
            {
                Func <Actor, bool> checkTransient = otherActor => IsBlockedBy(self, otherActor, ignoreActor, cell, check, GetCache(cell).CellFlag);

                if (!sharesCell)
                {
                    return(world.ActorMap.AnyActorsAt(cell, SubCell.FullCell, checkTransient) ? SubCell.Invalid : SubCell.FullCell);
                }

                return(world.ActorMap.FreeSubCell(cell, preferredSubCell, checkTransient));
            }

            if (!sharesCell)
            {
                return(world.ActorMap.AnyActorsAt(cell, SubCell.FullCell) ? SubCell.Invalid : SubCell.FullCell);
            }

            return(world.ActorMap.FreeSubCell(cell, preferredSubCell));
        }
Beispiel #9
0
 public WVec OffsetOfSubCell(SubCell subCell)
 {
     return SubCellOffsets[(int)subCell];
 }
Beispiel #10
0
 public Activity MoveIntoWorld(Actor self, CPos cell, SubCell subCell = SubCell.Any)
 {
     return new Fly(self, Target.FromCell(self.World, cell));
 }
Beispiel #11
0
 public SubCell GetValidSubCell(SubCell preferred = SubCell.Any)
 {
     return(SubCell.FullCell);
 }
Beispiel #12
0
 public void SetPosition(Actor self, CPos cell, SubCell subCell = SubCell.Any)
 {
     SetPosition(self, self.World.Map.CenterOfCell(cell));
 }
Beispiel #13
0
 public SubCell GetAvailableSubCell(CPos cell, SubCell preferredSubCell = SubCell.Any, Actor ignoreActor = null, bool checkTransientActors = true)
 {
     return(info.GetAvailableSubCell(self.World, cell, ignoreActor, checkTransientActors));
 }
Beispiel #14
0
 public IReadOnlyDictionary <CPos, SubCell> OccupiedCells(ActorInfo info, CPos location, SubCell subCell = SubCell.Any)
 {
     return(OccupiesSpace ? new Dictionary <CPos, SubCell>()
     {
         { location, SubCell.FullCell }
     } :
            new Dictionary <CPos, SubCell>());
 }
Beispiel #15
0
        public bool CanMoveFreelyInto(Actor actor, CPos cell, SubCell subCell, BlockedByActor check, Actor ignoreActor)
        {
            var cellCache = GetCache(cell);
            var cellFlag  = cellCache.CellFlag;

            // If the check allows: We are not blocked by transient actors.
            if (check == BlockedByActor.None)
            {
                return(true);
            }

            // No actor in the cell or free SubCell.
            if (cellFlag == CellFlag.HasFreeSpace)
            {
                return(true);
            }

            // If actor is null we're just checking what would happen theoretically.
            // In such a scenario - we'll just assume any other actor in the cell will block us by default.
            // If we have a real actor, we can then perform the extra checks that allow us to avoid being blocked.
            if (actor == null)
            {
                return(false);
            }

            // All actors that may be in the cell can be crushed.
            if (cellCache.Crushable.Overlaps(actor.Owner.PlayerMask))
            {
                return(true);
            }

            // If the check allows: We are not blocked by moving units.
            if (check <= BlockedByActor.Stationary && !cellFlag.HasCellFlag(CellFlag.HasStationaryActor))
            {
                return(true);
            }

            // If the check allows: We are not blocked by units that we can force to move out of the way.
            if (check <= BlockedByActor.Immovable && !cellCache.Immovable.Overlaps(actor.Owner.PlayerMask))
            {
                return(true);
            }

            // Cache doesn't account for ignored actors, temporary blockers, or subcells - these must use the slow path.
            if (ignoreActor == null && !cellFlag.HasCellFlag(CellFlag.HasTemporaryBlocker) && subCell == SubCell.FullCell)
            {
                // We already know there are uncrushable actors in the cell so we are always blocked.
                if (check == BlockedByActor.All)
                {
                    return(false);
                }

                // We already know there are either immovable or stationary actors which the check does not allow.
                if (!cellFlag.HasCellFlag(CellFlag.HasCrushableActor))
                {
                    return(false);
                }

                // All actors in the cell are immovable and some cannot be crushed.
                if (!cellFlag.HasCellFlag(CellFlag.HasMovableActor))
                {
                    return(false);
                }

                // All actors in the cell are stationary and some cannot be crushed.
                if (check == BlockedByActor.Stationary && !cellFlag.HasCellFlag(CellFlag.HasMovingActor))
                {
                    return(false);
                }
            }

            var otherActors = subCell == SubCell.FullCell ? world.ActorMap.GetActorsAt(cell) : world.ActorMap.GetActorsAt(cell, subCell);

            foreach (var otherActor in otherActors)
            {
                if (IsBlockedBy(actor, otherActor, ignoreActor, cell, check, cellFlag))
                {
                    return(false);
                }
            }

            return(true);
        }
Beispiel #16
0
 public bool IsLeavingCell(CPos location, SubCell subCell = SubCell.Any)
 {
     return(false);
 }                                                                                                 // TODO: Handle landing
Beispiel #17
0
 // Used to determine if actor can spawn
 public bool CanEnterCell(World world, Actor self, CPos cell, SubCell subCell = SubCell.FullCell, Actor ignoreActor = null, BlockedByActor check = BlockedByActor.All)
 {
     return(world.Map.Contains(cell));
 }
Beispiel #18
0
 public SubCell GetAvailableSubCell(CPos a, SubCell preferredSubCell = SubCell.Any, Actor ignoreActor = null, BlockedByActor check = BlockedByActor.All)
 {
     return(Locomotor.GetAvailableSubCell(self, a, check, preferredSubCell, ignoreActor));
 }
Beispiel #19
0
		public static Target FromCell(World w, CPos c, SubCell subCell = SubCell.FullCell)
		{
			return new Target { pos = w.Map.CenterOfSubCell(c, subCell), type = TargetType.Terrain };
		}
Beispiel #20
0
 public static Target FromCell(World w, CPos c, SubCell subCell = SubCell.FullCell)
 {
     return(new Target(w, c, subCell));
 }
Beispiel #21
0
        public SubCell FreeSubCell(CPos a, SubCell preferredSubCell, Func<Actor, bool> checkIfBlocker)
        {
            if (preferredSubCell > SubCell.Any && !AnyUnitsAt(a, preferredSubCell, checkIfBlocker))
                return preferredSubCell;

            if (!AnyUnitsAt(a))
                return map.DefaultSubCell;

            for (var i = (int)SubCell.First; i < map.SubCellOffsets.Length; i++)
                if (i != (int)preferredSubCell && !AnyUnitsAt(a, (SubCell)i, checkIfBlocker))
                    return (SubCell)i;
            return SubCell.Invalid;
        }
Beispiel #22
0
 public bool CanEnterCell(World world, Actor self, CPos cell, SubCell subCell = SubCell.FullCell, Actor ignoreActor = null, BlockedByActor check = BlockedByActor.All)
 {
     // IPositionable*Info*.CanEnterCell is only ever used for things like exiting production facilities,
     // all places relevant for husks check IPositionable.CanEnterCell instead, so we can safely set this to true.
     return(true);
 }
Beispiel #23
0
 public bool CanEnterCell(World world, Actor self, CPos cell, SubCell subCell = SubCell.FullCell, Actor ignoreActor = null, BlockedByActor check = BlockedByActor.All)
 {
     // Since crates don't share cells and GetAvailableSubCell only returns SubCell.Full or SubCell.Invalid, we ignore the subCell parameter
     return(GetAvailableSubCell(world, cell, ignoreActor, check) != SubCell.Invalid);
 }
Beispiel #24
0
        // NOTE: can not check aircraft
        public bool AnyUnitsAt(CPos a, SubCell sub, Func<Actor, bool> withCondition)
        {
            if (!map.Contains(a))
                return false;

            var always = sub == SubCell.FullCell || sub == SubCell.Any;
            for (var i = influence[a]; i != null; i = i.Next)
                if (always || i.SubCell == sub || i.SubCell == SubCell.FullCell)
                    if (withCondition(i.Actor))
                        return true;

            return false;
        }
Beispiel #25
0
        // The standard constructor for most purposes
        public Map(string path)
        {
            Path      = path;
            Container = GlobalFileSystem.OpenPackage(path, null, int.MaxValue);

            AssertExists("map.yaml");
            AssertExists("map.bin");

            var yaml = new MiniYaml(null, MiniYaml.FromStream(Container.GetContent("map.yaml"), path));

            FieldLoader.Load(this, yaml);

            // Support for formats 1-3 dropped 2011-02-11.
            // Use release-20110207 to convert older maps to format 4
            // Use release-20110511 to convert older maps to format 5
            // Use release-20141029 to convert older maps to format 6
            if (MapFormat < 6)
            {
                throw new InvalidDataException("Map format {0} is not supported.\n File: {1}".F(MapFormat, path));
            }

            var nd = yaml.ToDictionary();

            // Format 6 -> 7 combined the Selectable and UseAsShellmap flags into the Class enum
            if (MapFormat < 7)
            {
                MiniYaml useAsShellmap;
                if (nd.TryGetValue("UseAsShellmap", out useAsShellmap) && bool.Parse(useAsShellmap.Value))
                {
                    Visibility = MapVisibility.Shellmap;
                }
                else if (Type == "Mission" || Type == "Campaign")
                {
                    Visibility = MapVisibility.MissionSelector;
                }
            }

            // Load players
            foreach (var my in nd["Players"].ToDictionary().Values)
            {
                var player = new PlayerReference(my);
                Players.Add(player.Name, player);
            }

            Actors = Exts.Lazy(() =>
            {
                var ret = new Dictionary <string, ActorReference>();
                foreach (var kv in nd["Actors"].ToDictionary())
                {
                    ret.Add(kv.Key, new ActorReference(kv.Value.Value, kv.Value.ToDictionary()));
                }
                return(ret);
            });

            // Smudges
            Smudges = Exts.Lazy(() =>
            {
                var ret = new List <SmudgeReference>();
                foreach (var name in nd["Smudges"].ToDictionary().Keys)
                {
                    var vals = name.Split(' ');
                    var loc  = vals[1].Split(',');
                    ret.Add(new SmudgeReference(vals[0], new int2(
                                                    Exts.ParseIntegerInvariant(loc[0]),
                                                    Exts.ParseIntegerInvariant(loc[1])),
                                                Exts.ParseIntegerInvariant(vals[2])));
                }

                return(ret);
            });

            RuleDefinitions          = MiniYaml.NodesOrEmpty(yaml, "Rules");
            SequenceDefinitions      = MiniYaml.NodesOrEmpty(yaml, "Sequences");
            VoxelSequenceDefinitions = MiniYaml.NodesOrEmpty(yaml, "VoxelSequences");
            WeaponDefinitions        = MiniYaml.NodesOrEmpty(yaml, "Weapons");
            VoiceDefinitions         = MiniYaml.NodesOrEmpty(yaml, "Voices");
            NotificationDefinitions  = MiniYaml.NodesOrEmpty(yaml, "Notifications");
            TranslationDefinitions   = MiniYaml.NodesOrEmpty(yaml, "Translations");

            MapTiles     = Exts.Lazy(() => LoadMapTiles());
            MapResources = Exts.Lazy(() => LoadResourceTiles());
            MapHeight    = Exts.Lazy(() => LoadMapHeight());

            TileShape      = Game.ModData.Manifest.TileShape;
            SubCellOffsets = Game.ModData.Manifest.SubCellOffsets;
            LastSubCell    = (SubCell)(SubCellOffsets.Length - 1);
            DefaultSubCell = (SubCell)Game.ModData.Manifest.SubCellDefaultIndex;

            if (Container.Exists("map.png"))
            {
                using (var dataStream = Container.GetContent("map.png"))
                    CustomPreview = new Bitmap(dataStream);
            }

            PostInit();

            // The Uid is calculated from the data on-disk, so
            // format changes must be flushed to disk.
            // TODO: this isn't very nice
            if (MapFormat < 7)
            {
                Save(path);
            }

            Uid = ComputeHash();
        }
Beispiel #26
0
 public SubCell GetValidSubCell(SubCell preferred)
 {
     return(SubCell.Invalid);
 }
Beispiel #27
0
 public SubCell GetAvailableSubCell(CPos a, SubCell preferredSubCell = SubCell.Any, Actor ignoreActor = null, bool checkTransientActors = true)
 {
     // Does not use any subcell
     return(SubCell.Invalid);
 }
Beispiel #28
0
        public IReadOnlyDictionary <CPos, SubCell> OccupiedCells(ActorInfo info, CPos location, SubCell subCell = SubCell.Any)
        {
            var occupied = new Dictionary <CPos, SubCell>()
            {
                { location, SubCell.FullCell }
            };

            return(new ReadOnlyDictionary <CPos, SubCell>(occupied));
        }
Beispiel #29
0
 public Activity MoveIntoWorld(Actor self, CPos cell, SubCell subCell = SubCell.Any)
 {
     return(null);
 }
Beispiel #30
0
 public bool IsLeavingCell(CPos location, SubCell subCell = SubCell.Any)
 {
     return(false);
 }
Beispiel #31
0
        public IReadOnlyDictionary <CPos, SubCell> OccupiedCells(ActorInfo info, CPos topLeft, SubCell subCell = SubCell.Any)
        {
            var occupied = UnpathableTiles(topLeft)
                           .ToDictionary(c => c, c => SubCell.FullCell);

            return(new ReadOnlyDictionary <CPos, SubCell>(occupied));
        }
Beispiel #32
0
 public IReadOnlyDictionary <CPos, SubCell> OccupiedCells(ActorInfo info, CPos location, SubCell subCell = SubCell.Any)
 {
     return(new Dictionary <CPos, SubCell>());
 }
Beispiel #33
0
 public Activity MoveIntoWorld(Actor self, CPos cell, SubCell subCell = SubCell.Any)
 {
     return(new HeliFly(self, Target.FromCell(self.World, cell, subCell)));
 }
Beispiel #34
0
        // Support upgrading format 5 maps to a more
        // recent version by defining upgradeForMod.
        public Map(string path, string upgradeForMod)
        {
            Path = path;
            Container = GlobalFileSystem.OpenPackage(path, null, int.MaxValue);

            AssertExists("map.yaml");
            AssertExists("map.bin");

            var yaml = new MiniYaml(null, MiniYaml.FromStream(Container.GetContent("map.yaml")));
            FieldLoader.Load(this, yaml);

            // Support for formats 1-3 dropped 2011-02-11.
            // Use release-20110207 to convert older maps to format 4
            // Use release-20110511 to convert older maps to format 5
            if (MapFormat < 5)
                throw new InvalidDataException("Map format {0} is not supported.\n File: {1}".F(MapFormat, path));

            // Format 5 -> 6 enforces the use of RequiresMod
            if (MapFormat == 5)
            {
                if (upgradeForMod == null)
                    throw new InvalidDataException("Map format {0} is not supported, but can be upgraded.\n File: {1}".F(MapFormat, path));

                Console.WriteLine("Upgrading {0} from Format 5 to Format 6", path);

                // TODO: This isn't very nice, but there is no other consistent way
                // of finding the mod early during the engine initialization.
                RequiresMod = upgradeForMod;
            }

            var nd = yaml.ToDictionary();

            // Load players
            foreach (var my in nd["Players"].ToDictionary().Values)
            {
                var player = new PlayerReference(my);
                Players.Add(player.Name, player);
            }

            Actors = Exts.Lazy(() =>
            {
                var ret = new Dictionary<string, ActorReference>();
                foreach (var kv in nd["Actors"].ToDictionary())
                    ret.Add(kv.Key, new ActorReference(kv.Value.Value, kv.Value.ToDictionary()));
                return ret;
            });

            // Smudges
            Smudges = Exts.Lazy(() =>
            {
                var ret = new List<SmudgeReference>();
                foreach (var name in nd["Smudges"].ToDictionary().Keys)
                {
                    var vals = name.Split(' ');
                    var loc = vals[1].Split(',');
                    ret.Add(new SmudgeReference(vals[0], new int2(
                            Exts.ParseIntegerInvariant(loc[0]),
                            Exts.ParseIntegerInvariant(loc[1])),
                            Exts.ParseIntegerInvariant(vals[2])));
                }

                return ret;
            });

            RuleDefinitions = MiniYaml.NodesOrEmpty(yaml, "Rules");
            SequenceDefinitions = MiniYaml.NodesOrEmpty(yaml, "Sequences");
            VoxelSequenceDefinitions = MiniYaml.NodesOrEmpty(yaml, "VoxelSequences");
            WeaponDefinitions = MiniYaml.NodesOrEmpty(yaml, "Weapons");
            VoiceDefinitions = MiniYaml.NodesOrEmpty(yaml, "Voices");
            NotificationDefinitions = MiniYaml.NodesOrEmpty(yaml, "Notifications");
            TranslationDefinitions = MiniYaml.NodesOrEmpty(yaml, "Translations");

            MapTiles = Exts.Lazy(() => LoadMapTiles());
            MapResources = Exts.Lazy(() => LoadResourceTiles());
            TileShape = Game.modData.Manifest.TileShape;
            SubCellOffsets = Game.modData.Manifest.SubCellOffsets;
            LastSubCell = (SubCell)(SubCellOffsets.Length - 1);
            DefaultSubCell = (SubCell)Game.modData.Manifest.SubCellDefaultIndex;

            // The Uid is calculated from the data on-disk, so
            // format changes must be flushed to disk.
            // TODO: this isn't very nice
            if (MapFormat < 6)
                Save(path);

            Uid = ComputeHash();

            if (Container.Exists("map.png"))
                using (var dataStream = Container.GetContent("map.png"))
                    CustomPreview = new Bitmap(dataStream);

            PostInit();
        }
 public bool CanEnterCell(World world, Actor self, CPos cell, SubCell subCell = SubCell.FullCell, Actor ignoreActor = null, BlockedByActor check = BlockedByActor.All)
 {
     // SBMs may not land.
     return(false);
 }
Beispiel #36
0
 public SubCell GetAvailableSubCell(CPos a, SubCell preferredSubCell = SubCell.Any, Actor ignoreActor = null, BlockedByActor check = BlockedByActor.All)
 {
     // Does not use any subcell
     return(SubCell.Invalid);
 }
Beispiel #37
0
        // The standard constructor for most purposes
        public Map(string path)
        {
            Path = path;
            Container = GlobalFileSystem.OpenPackage(path, null, int.MaxValue);

            AssertExists("map.yaml");
            AssertExists("map.bin");

            var yaml = new MiniYaml(null, MiniYaml.FromStream(Container.GetContent("map.yaml"), path));
            FieldLoader.Load(this, yaml);

            // Support for formats 1-3 dropped 2011-02-11.
            // Use release-20110207 to convert older maps to format 4
            // Use release-20110511 to convert older maps to format 5
            // Use release-20141029 to convert older maps to format 6
            if (MapFormat < 6)
                throw new InvalidDataException("Map format {0} is not supported.\n File: {1}".F(MapFormat, path));

            var nd = yaml.ToDictionary();

            // Format 6 -> 7 combined the Selectable and UseAsShellmap flags into the Class enum
            if (MapFormat < 7)
            {
                MiniYaml useAsShellmap;
                if (nd.TryGetValue("UseAsShellmap", out useAsShellmap) && bool.Parse(useAsShellmap.Value))
                    Visibility = MapVisibility.Shellmap;
                else if (Type == "Mission" || Type == "Campaign")
                    Visibility = MapVisibility.MissionSelector;
            }

            SpawnPoints = Exts.Lazy(() =>
            {
                var spawns = new List<CPos>();
                foreach (var kv in ActorDefinitions.Where(d => d.Value.Value == "mpspawn"))
                {
                    var s = new ActorReference(kv.Value.Value, kv.Value.ToDictionary());

                    spawns.Add(s.InitDict.Get<LocationInit>().Value(null));
                }

                return spawns.ToArray();
            });

            RuleDefinitions = MiniYaml.NodesOrEmpty(yaml, "Rules");
            SequenceDefinitions = MiniYaml.NodesOrEmpty(yaml, "Sequences");
            VoxelSequenceDefinitions = MiniYaml.NodesOrEmpty(yaml, "VoxelSequences");
            WeaponDefinitions = MiniYaml.NodesOrEmpty(yaml, "Weapons");
            VoiceDefinitions = MiniYaml.NodesOrEmpty(yaml, "Voices");
            NotificationDefinitions = MiniYaml.NodesOrEmpty(yaml, "Notifications");
            TranslationDefinitions = MiniYaml.NodesOrEmpty(yaml, "Translations");
            PlayerDefinitions = MiniYaml.NodesOrEmpty(yaml, "Players");

            ActorDefinitions = MiniYaml.NodesOrEmpty(yaml, "Actors");
            SmudgeDefinitions = MiniYaml.NodesOrEmpty(yaml, "Smudges");

            MapTiles = Exts.Lazy(LoadMapTiles);
            MapResources = Exts.Lazy(LoadResourceTiles);
            MapHeight = Exts.Lazy(LoadMapHeight);

            TileShape = Game.ModData.Manifest.TileShape;
            SubCellOffsets = Game.ModData.Manifest.SubCellOffsets;
            LastSubCell = (SubCell)(SubCellOffsets.Length - 1);
            DefaultSubCell = (SubCell)Game.ModData.Manifest.SubCellDefaultIndex;

            if (Container.Exists("map.png"))
                using (var dataStream = Container.GetContent("map.png"))
                    CustomPreview = new Bitmap(dataStream);

            PostInit();

            // The Uid is calculated from the data on-disk, so
            // format changes must be flushed to disk.
            // TODO: this isn't very nice
            if (MapFormat < 7)
                Save(path);

            Uid = ComputeHash();
        }
Beispiel #38
0
 public void SetLocation(int2 from, SubCell fromSub, int2 to, SubCell toSub)
 {
     if (fromCell == from && toCell == to) return;
     RemoveInfluence();
     __fromCell = from;
     __toCell = to;
     fromSubCell = fromSub;
     toSubCell = toSub;
     AddInfluence();
 }
Beispiel #39
0
        public WVec OffsetOfSubCell(SubCell subCell)
        {
            if (subCell == SubCell.Invalid || subCell == SubCell.Any)
                return WVec.Zero;

            return SubCellOffsets[(int)subCell];
        }
Beispiel #40
0
        public MapGrid(MiniYaml yaml)
        {
            FieldLoader.Load(this, yaml);

            // The default subcell index defaults to the middle entry
            var defaultSubCellIndex = (byte)DefaultSubCell;
            if (defaultSubCellIndex == byte.MaxValue)
                DefaultSubCell = (SubCell)(SubCellOffsets.Length / 2);
            else if (defaultSubCellIndex < (SubCellOffsets.Length > 1 ? 1 : 0) || defaultSubCellIndex >= SubCellOffsets.Length)
                throw new InvalidDataException("Subcell default index must be a valid index into the offset triples and must be greater than 0 for mods with subcells");

            var leftDelta = Type == MapGridType.RectangularIsometric ? new WVec(-512, 0, 0) : new WVec(-512, -512, 0);
            var topDelta = Type == MapGridType.RectangularIsometric ? new WVec(0, -512, 0) : new WVec(512, -512, 0);
            var rightDelta = Type == MapGridType.RectangularIsometric ? new WVec(512, 0, 0) : new WVec(512, 512, 0);
            var bottomDelta = Type == MapGridType.RectangularIsometric ? new WVec(0, 512, 0) : new WVec(-512, 512, 0);
            CellCorners = cellCornerHalfHeights.Select(ramp => new WVec[]
            {
                leftDelta + new WVec(0, 0, 512 * ramp[0]),
                topDelta + new WVec(0, 0, 512 * ramp[1]),
                rightDelta + new WVec(0, 0, 512 * ramp[2]),
                bottomDelta + new WVec(0, 0, 512 * ramp[3])
            }).ToArray();

            TilesByDistance = CreateTilesByDistance();
        }
Beispiel #41
0
		public IrregularCell GetSubRect(SubCell sub)
		{
			switch (sub)
			{
				case SubCell.LeftBottom:
					return new IrregularCell(LeftBottom, BottomSide, Center.ToVector(), LeftSide);
				case SubCell.LeftTop:
					return new IrregularCell(LeftSide, Center.ToVector(), TopSide, LeftTop);
				case SubCell.RightBottom:
					return new IrregularCell(BottomSide, RightBottom, RightSide, Center.ToVector());
				case SubCell.RightTop:
				default:
					return new IrregularCell(Center.ToVector(), RightSide, RightTop, TopSide);
			}
		}
Beispiel #42
0
        void ITickRender.TickRender(WorldRenderer wr, Actor self)
        {
            if (wr.World.Type != WorldType.Editor)
            {
                return;
            }

            if (Type == EditorCursorType.TerrainTemplate || Type == EditorCursorType.Resource)
            {
                var cell = wr.Viewport.ViewToWorld(Viewport.LastMousePos);
                if (terrainOrResourceCell != cell || terrainOrResourceDirty)
                {
                    terrainOrResourceCell  = cell;
                    terrainOrResourceDirty = false;
                    terrainOrResourcePreview.Clear();
                    var pos = world.Map.CenterOfCell(cell);

                    if (Type == EditorCursorType.TerrainTemplate)
                    {
                        var i = 0;
                        for (var y = 0; y < TerrainTemplate.Size.Y; y++)
                        {
                            for (var x = 0; x < TerrainTemplate.Size.X; x++)
                            {
                                var tile     = new TerrainTile(TerrainTemplate.Id, (byte)i++);
                                var tileInfo = world.Map.Rules.TileSet.GetTileInfo(tile);

                                // Empty tile
                                if (tileInfo == null)
                                {
                                    continue;
                                }

                                var sprite  = wr.Theater.TileSprite(tile, 0);
                                var offset  = world.Map.Offset(new CVec(x, y), tileInfo.Height);
                                var palette = wr.Palette(TerrainTemplate.Palette ?? TileSet.TerrainPaletteInternalName);

                                terrainOrResourcePreview.Add(new SpriteRenderable(sprite, pos, offset, 0, palette, 1, false));
                            }
                        }
                    }
                    else
                    {
                        var variant  = Resource.Sequences.FirstOrDefault();
                        var sequence = wr.World.Map.Rules.Sequences.GetSequence("resources", variant);
                        var sprite   = sequence.GetSprite(Resource.MaxDensity - 1);
                        var palette  = wr.Palette(Resource.Palette);

                        terrainOrResourcePreview.Add(new SpriteRenderable(sprite, pos, WVec.Zero, 0, palette, 1, false));
                    }
                }
            }
            else if (Type == EditorCursorType.Actor)
            {
                // Offset mouse position by the center offset (in world pixels)
                var worldPx = wr.Viewport.ViewToWorldPx(Viewport.LastMousePos) - wr.ScreenPxOffset(actorCenterOffset);
                var cell    = wr.Viewport.ViewToWorld(wr.Viewport.WorldToViewPx(worldPx));
                var subCell = actorSharesCell ? editorLayer.FreeSubCellAt(cell) : SubCell.Invalid;
                var updated = false;
                if (actorLocation != cell)
                {
                    actorLocation = cell;
                    Actor.ReplaceInit(new LocationInit(cell));
                    updated = true;
                }

                if (actorSubCell != subCell)
                {
                    actorSubCell = subCell;

                    if (Actor.RemoveInits <SubCellInit>() > 0)
                    {
                        updated = true;
                    }

                    var subcell = world.Map.Tiles.Contains(cell) ? editorLayer.FreeSubCellAt(cell) : SubCell.Invalid;
                    if (subcell != SubCell.Invalid)
                    {
                        Actor.AddInit(new SubCellInit(subcell));
                        updated = true;
                    }
                }

                if (updated)
                {
                    Actor = new EditorActorPreview(wr, null, Actor.Export(), Actor.Owner);
                }
            }
        }
Beispiel #43
0
        public MapGrid(MiniYaml yaml)
        {
            FieldLoader.Load(this, yaml);

            // The default subcell index defaults to the middle entry
            var defaultSubCellIndex = (byte)DefaultSubCell;

            if (defaultSubCellIndex == byte.MaxValue)
            {
                DefaultSubCell = (SubCell)(SubCellOffsets.Length / 2);
            }
            else
            {
                var minSubCellOffset = SubCellOffsets.Length > 1 ? 1 : 0;
                if (defaultSubCellIndex < minSubCellOffset || defaultSubCellIndex >= SubCellOffsets.Length)
                {
                    throw new InvalidDataException("Subcell default index must be a valid index into the offset triples and must be greater than 0 for mods with subcells");
                }
            }

            // Rotation axes and amounts for the different slope types
            var southEast = new WVec(724, 724, 0);
            var southWest = new WVec(-724, 724, 0);
            var south     = new WVec(0, 1024, 0);
            var east      = new WVec(1024, 0, 0);

            var forward      = new WAngle(64);
            var backward     = -forward;
            var halfForward  = new WAngle(48);
            var halfBackward = -halfForward;

            // Slope types are hardcoded following the convention from the TS and RA2 map format
            Ramps = new[]
            {
                // Flat
                new CellRamp(Type, WRot.None),

                // Two adjacent corners raised by half a cell
                new CellRamp(Type, new WRot(southEast, backward), tr: RampCornerHeight.Half, br: RampCornerHeight.Half),
                new CellRamp(Type, new WRot(southWest, backward), br: RampCornerHeight.Half, bl: RampCornerHeight.Half),
                new CellRamp(Type, new WRot(southEast, forward), tl: RampCornerHeight.Half, bl: RampCornerHeight.Half),
                new CellRamp(Type, new WRot(southWest, forward), tl: RampCornerHeight.Half, tr: RampCornerHeight.Half),

                // One corner raised by half a cell
                new CellRamp(Type, new WRot(south, halfBackward), br: RampCornerHeight.Half, split: RampSplit.X),
                new CellRamp(Type, new WRot(east, halfForward), bl: RampCornerHeight.Half, split: RampSplit.Y),
                new CellRamp(Type, new WRot(south, halfForward), tl: RampCornerHeight.Half, split: RampSplit.X),
                new CellRamp(Type, new WRot(east, halfBackward), tr: RampCornerHeight.Half, split: RampSplit.Y),

                // Three corners raised by half a cell
                new CellRamp(Type, new WRot(south, halfBackward), tr: RampCornerHeight.Half, br: RampCornerHeight.Half, bl: RampCornerHeight.Half, split: RampSplit.X),
                new CellRamp(Type, new WRot(east, halfForward), tl: RampCornerHeight.Half, br: RampCornerHeight.Half, bl: RampCornerHeight.Half, split: RampSplit.Y),
                new CellRamp(Type, new WRot(south, halfForward), tl: RampCornerHeight.Half, tr: RampCornerHeight.Half, bl: RampCornerHeight.Half, split: RampSplit.X),
                new CellRamp(Type, new WRot(east, halfBackward), tl: RampCornerHeight.Half, tr: RampCornerHeight.Half, br: RampCornerHeight.Half, split: RampSplit.Y),

                // Full tile sloped (mid corners raised by half cell, far corner by full cell)
                new CellRamp(Type, new WRot(south, backward), tr: RampCornerHeight.Half, br: RampCornerHeight.Full, bl: RampCornerHeight.Half),
                new CellRamp(Type, new WRot(east, forward), tl: RampCornerHeight.Half, br: RampCornerHeight.Half, bl: RampCornerHeight.Full),
                new CellRamp(Type, new WRot(south, forward), tl: RampCornerHeight.Full, tr: RampCornerHeight.Half, bl: RampCornerHeight.Half),
                new CellRamp(Type, new WRot(east, backward), tl: RampCornerHeight.Half, tr: RampCornerHeight.Full, br: RampCornerHeight.Half),

                // Two opposite corners raised by half a cell
                new CellRamp(Type, WRot.None, tr: RampCornerHeight.Half, bl: RampCornerHeight.Half, split: RampSplit.Y),
                new CellRamp(Type, WRot.None, tl: RampCornerHeight.Half, br: RampCornerHeight.Half, split: RampSplit.Y),
                new CellRamp(Type, WRot.None, tr: RampCornerHeight.Half, bl: RampCornerHeight.Half, split: RampSplit.X),
                new CellRamp(Type, WRot.None, tl: RampCornerHeight.Half, br: RampCornerHeight.Half, split: RampSplit.X),
            };

            TilesByDistance = CreateTilesByDistance();
        }
Beispiel #44
0
 public WPos CenterOfSubCell(CPos cell, SubCell subCell)
 {
     var index = (int)subCell;
     if (index >= 0 && index <= SubCellOffsets.Length)
         return CenterOfCell(cell) + SubCellOffsets[index];
     return CenterOfCell(cell);
 }
Beispiel #45
0
 public IReadOnlyDictionary <CPos, SubCell> OccupiedCells(ActorInfo info, CPos topLeft, SubCell subCell = SubCell.Any)
 {
     return(OccupiedTiles(topLeft)
            .ToDictionary(c => c, c => SubCell.FullCell));
 }
Beispiel #46
0
		public ValuesInCell GetSubCell(SubCell subCell)
		{
			switch (subCell)
			{
				case SubCell.LeftBottom:
					return LeftBottomCell;
				case SubCell.LeftTop:
					return LeftTopCell;
				case SubCell.RightBottom:
					return RightBottomCell;
				case SubCell.RightTop:
				default:
					return RightTopCell;
			}
		}
Beispiel #47
0
 public SubCell GetAvailableSubCell(CPos a, SubCell preferredSubCell = SubCell.Any, Actor ignoreActor = null, bool checkTransientActors = true)
 {
     return(Info.GetAvailableSubCell(self.World, self, a, preferredSubCell, ignoreActor, checkTransientActors ? CellConditions.All : CellConditions.None));
 }
Beispiel #48
0
        // NOTE: can not check aircraft
        public bool AnyUnitsAt(CPos a, SubCell sub, bool checkTransient = true)
        {
            if (!map.Contains(a))
                return false;

            var always = sub == SubCell.FullCell || sub == SubCell.Any;
            for (var i = influence[a]; i != null; i = i.Next)
            {
                if (always || i.SubCell == sub || i.SubCell == SubCell.FullCell)
                {
                    if (checkTransient)
                        return true;

                    var pos = i.Actor.TraitOrDefault<IPositionable>();
                    if (pos == null || !pos.IsLeavingCell(a, i.SubCell))
                        return true;
                }
            }

            return false;
        }
Beispiel #49
0
 /// <summary>
 ///
 /// </summary>
 /// <param name="location"></param>
 /// <param name="subCell"></param>
 /// <returns></returns>
 public bool IsLeavingCell(CPos location, SubCell subCell = SubCell.Any)
 {
     return(ToCell != location && fromCell == location && (subCell == SubCell.Any || FromSubCell == subCell || subCell == SubCell.FullCell || FromSubCell == SubCell.FullCell));
 }
Beispiel #50
0
        public SubCell FreeSubCell(CPos a, SubCell preferredSubCell = SubCell.Any, bool checkTransient = true)
        {
            if (preferredSubCell > SubCell.Any && !AnyUnitsAt(a, preferredSubCell, checkTransient))
                return preferredSubCell;

            if (!AnyUnitsAt(a))
                return map.DefaultSubCell;

            for (var i = (int)SubCell.First; i < map.SubCellOffsets.Length; i++)
                if (i != (int)preferredSubCell && !AnyUnitsAt(a, (SubCell)i, checkTransient))
                    return (SubCell)i;
            return SubCell.Invalid;
        }
Beispiel #51
0
 // Sets only the location (Location)
 void SetLocation(Actor self, CPos cell, SubCell subCell = SubCell.Any)
 {
     self.World.ActorMap.RemoveInfluence(self, this);
     Location = cell;
     self.World.ActorMap.AddInfluence(self, this);
 }
		private static SubCell GetAdjacentEdge(SubCell sub, Edge edge)
		{
			SubCell res = SubCell.LeftBottom;

			switch (sub)
			{
				case SubCell.LeftBottom:
					res = edge == Edge.Top ? SubCell.LeftTop : SubCell.RightBottom;
					break;
				case SubCell.LeftTop:
					res = edge == Edge.Bottom ? SubCell.LeftBottom : SubCell.RightTop;
					break;
				case SubCell.RightBottom:
					res = edge == Edge.Top ? SubCell.RightTop : SubCell.LeftBottom;
					break;
				case SubCell.RightTop:
				default:
					res = edge == Edge.Bottom ? SubCell.RightBottom : SubCell.LeftTop;
					break;
			}

			return res;
		}
Beispiel #53
0
 public bool IsLeavingCell(CPos location, SubCell subCell = SubCell.Any)
 {
     return(self.Location == location && ticks + 1 == info.Lifetime * 25);
 }