private void LoadThreaded() { // Ensure we're using the invariant culture. Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture; Thread.CurrentThread.CurrentUICulture = CultureInfo.InvariantCulture; LoadStatus = LoadingStatus.Loading; SetLoadingMessage("Initializing ..."); while (GraphicsDevice == null) { Thread.Sleep(100); } Thread.Sleep(1000); #if CREATE_CRASH_LOGS try #endif #if !DEBUG try { #endif bool fileExists = !string.IsNullOrEmpty(ExistingFile); SetLoadingMessage("Creating Sky..."); Sky = new SkyRenderer( TextureManager.GetTexture(ContentPaths.Sky.moon), TextureManager.GetTexture(ContentPaths.Sky.sun), Content.Load <TextureCube>(ContentPaths.Sky.day_sky), Content.Load <TextureCube>(ContentPaths.Sky.night_sky), TextureManager.GetTexture(ContentPaths.Gradients.skygradient), Content.Load <Model>(ContentPaths.Models.sphereLowPoly), Content.Load <Effect>(ContentPaths.Shaders.SkySphere), Content.Load <Effect>(ContentPaths.Shaders.Background)); #region Reading game file if (fileExists) { SetLoadingMessage("Loading " + ExistingFile); gameFile = SaveGame.CreateFromDirectory(ExistingFile); if (gameFile == null) { throw new InvalidOperationException("Game File does not exist."); } // Todo: REMOVE THIS WHEN THE NEW SAVE SYSTEM IS COMPLETE. if (gameFile.Metadata.Version != Program.Version && !Program.CompatibleVersions.Contains(gameFile.Metadata.Version)) { throw new InvalidOperationException(String.Format("Game file is from version {0}. Compatible versions are {1}.", gameFile.Metadata.Version, TextGenerator.GetListString(Program.CompatibleVersions))); } Sky.TimeOfDay = gameFile.Metadata.TimeOfDay; Time = gameFile.Metadata.Time; WorldOrigin = gameFile.Metadata.WorldOrigin; WorldScale = gameFile.Metadata.WorldScale; WorldSize = gameFile.Metadata.NumChunks; GameID = gameFile.Metadata.GameID; if (gameFile.Metadata.OverworldFile != null && gameFile.Metadata.OverworldFile != "flat") { SetLoadingMessage("Loading world " + gameFile.Metadata.OverworldFile); Overworld.Name = gameFile.Metadata.OverworldFile; DirectoryInfo worldDirectory = Directory.CreateDirectory(DwarfGame.GetWorldDirectory() + ProgramData.DirChar + Overworld.Name); var overWorldFile = new NewOverworldFile(worldDirectory.FullName); Overworld.Map = overWorldFile.Data.Data; Overworld.Name = overWorldFile.Data.Name; } else { SetLoadingMessage("Generating flat world.."); Overworld.CreateUniformLand(GraphicsDevice); } } #endregion #region Initialize static data { Vector3 origin = new Vector3(WorldOrigin.X, 0, WorldOrigin.Y); Vector3 extents = new Vector3(1500, 1500, 1500); CollisionManager = new CollisionManager(new BoundingBox(origin - extents, origin + extents)); CraftLibrary = new CraftLibrary(); new PrimitiveLibrary(GraphicsDevice, Content); NewInstanceManager = new NewInstanceManager(GraphicsDevice, new BoundingBox(origin - extents, origin + extents), Content); Color[] white = new Color[1]; white[0] = Color.White; pixel = new Texture2D(GraphicsDevice, 1, 1); pixel.SetData(white); Tilesheet = TextureManager.GetTexture(ContentPaths.Terrain.terrain_tiles); AspectRatio = GraphicsDevice.Viewport.AspectRatio; DefaultShader = new Shader(Content.Load <Effect>(ContentPaths.Shaders.TexturedShaders), true); DefaultShader.ScreenWidth = GraphicsDevice.Viewport.Width; DefaultShader.ScreenHeight = GraphicsDevice.Viewport.Height; VoxelLibrary.InitializeDefaultLibrary(GraphicsDevice, Tilesheet); GrassLibrary.InitializeDefaultLibrary(); DecalLibrary.InitializeDefaultLibrary(); bloom = new BloomComponent(Game) { Settings = BloomSettings.PresetSettings[5] }; bloom.Initialize(); fxaa = new FXAA(); fxaa.Initialize(); SoundManager.Content = Content; if (PlanService != null) { PlanService.Restart(); } JobLibrary.Initialize(); MonsterSpawner = new MonsterSpawner(this); EntityFactory.Initialize(this); } #endregion SetLoadingMessage("Creating Planner ..."); PlanService = new PlanService(); SetLoadingMessage("Creating Shadows..."); Shadows = new ShadowRenderer(GraphicsDevice, 1024, 1024); SetLoadingMessage("Creating Liquids ..."); #region liquids WaterRenderer = new WaterRenderer(GraphicsDevice); LiquidAsset waterAsset = new LiquidAsset { Type = LiquidType.Water, Opactiy = 0.8f, Reflection = 1.0f, WaveHeight = 0.1f, WaveLength = 0.05f, WindForce = 0.001f, BumpTexture = TextureManager.GetTexture(ContentPaths.Terrain.water_normal), BaseTexture = TextureManager.GetTexture(ContentPaths.Terrain.cartoon_water), MinOpacity = 0.4f, RippleColor = new Vector4(0.6f, 0.6f, 0.6f, 0.0f), FlatColor = new Vector4(0.3f, 0.3f, 0.9f, 1.0f) }; WaterRenderer.AddLiquidAsset(waterAsset); LiquidAsset lavaAsset = new LiquidAsset { Type = LiquidType.Lava, Opactiy = 0.95f, Reflection = 0.0f, WaveHeight = 0.1f, WaveLength = 0.05f, WindForce = 0.001f, MinOpacity = 0.8f, BumpTexture = TextureManager.GetTexture(ContentPaths.Terrain.water_normal), BaseTexture = TextureManager.GetTexture(ContentPaths.Terrain.lava), RippleColor = new Vector4(0.5f, 0.4f, 0.04f, 0.0f), FlatColor = new Vector4(0.9f, 0.7f, 0.2f, 1.0f) }; WaterRenderer.AddLiquidAsset(lavaAsset); #endregion SetLoadingMessage("Generating Initial Terrain Chunks ..."); if (!fileExists) { GameID = MathFunctions.Random.Next(0, 1024); } ChunkGenerator = new ChunkGenerator(VoxelLibrary, Seed, 0.02f, this.WorldScale) { SeaLevel = SeaLevel }; #region Load Components if (fileExists) { ChunkManager = new ChunkManager(Content, this, Camera, GraphicsDevice, ChunkGenerator, WorldSize.X, WorldSize.Y, WorldSize.Z); ChunkRenderer = new ChunkRenderer(this, Camera, GraphicsDevice, ChunkManager.ChunkData); SetLoadingMessage("Loading Terrain..."); gameFile.ReadChunks(ExistingFile); ChunkManager.ChunkData.LoadFromFile(gameFile, SetLoadingMessage); ChunkManager.ChunkData.SetMaxViewingLevel(gameFile.Metadata.Slice > 0 ? gameFile.Metadata.Slice : ChunkManager.ChunkData.MaxViewingLevel, ChunkManager.SliceMode.Y); SetLoadingMessage("Loading Entities..."); gameFile.LoadPlayData(ExistingFile, this); Camera = gameFile.PlayData.Camera; ChunkManager.camera = Camera; ChunkRenderer.camera = Camera; DesignationDrawer = gameFile.PlayData.Designations; Vector3 origin = new Vector3(WorldOrigin.X, 0, WorldOrigin.Y); Vector3 extents = new Vector3(1500, 1500, 1500); CollisionManager = new CollisionManager(new BoundingBox(origin - extents, origin + extents)); if (gameFile.PlayData.Resources != null) { foreach (var resource in gameFile.PlayData.Resources) { if (!ResourceLibrary.Resources.ContainsKey(resource.Key)) { ResourceLibrary.Add(resource.Value); } } } ComponentManager = new ComponentManager(gameFile.PlayData.Components, this); foreach (var component in gameFile.PlayData.Components.SaveableComponents) { if (!ComponentManager.HasComponent(component.GlobalID) && ComponentManager.HasComponent(component.Parent.GlobalID)) { // Logically impossible. throw new InvalidOperationException("Component exists in save data but not in manager."); } } Factions = gameFile.PlayData.Factions; ComponentManager.World = this; Sky.TimeOfDay = gameFile.Metadata.TimeOfDay; Time = gameFile.Metadata.Time; WorldOrigin = gameFile.Metadata.WorldOrigin; WorldScale = gameFile.Metadata.WorldScale; // Restore native factions from deserialized data. Natives = new List <Faction>(); foreach (Faction faction in Factions.Factions.Values) { if (faction.Race.IsNative && faction.Race.IsIntelligent && !faction.IsRaceFaction) { Natives.Add(faction); } } Diplomacy = gameFile.PlayData.Diplomacy; GoalManager = new Goals.GoalManager(); GoalManager.Initialize(gameFile.PlayData.Goals); TutorialManager = new Tutorial.TutorialManager(Program.CreatePath("Content", "tutorial.txt")); TutorialManager.SetFromSaveData(gameFile.PlayData.TutorialSaveData); } else { Time = new WorldTime(); // WorldOrigin is in "map" units. Convert to voxels var globalOffset = new Vector3(WorldOrigin.X, 0, WorldOrigin.Y) * WorldScale; Camera = new OrbitCamera(this, new Vector3(VoxelConstants.ChunkSizeX, VoxelConstants.ChunkSizeY - 1.0f, VoxelConstants.ChunkSizeZ) + new Vector3(WorldOrigin.X, 0, WorldOrigin.Y) * WorldScale, new Vector3(VoxelConstants.ChunkSizeY, VoxelConstants.ChunkSizeY - 1.0f, VoxelConstants.ChunkSizeZ) + new Vector3(WorldOrigin.X, 0, WorldOrigin.Y) * WorldScale + Vector3.Up * 10.0f + Vector3.Backward * 10, MathHelper.PiOver4, AspectRatio, 0.1f, GameSettings.Default.VertexCullDistance); ChunkManager = new ChunkManager(Content, this, Camera, GraphicsDevice, ChunkGenerator, WorldSize.X, WorldSize.Y, WorldSize.Z); ChunkRenderer = new ChunkRenderer(this, Camera, GraphicsDevice, ChunkManager.ChunkData); var chunkOffset = GlobalVoxelCoordinate.FromVector3(globalOffset).GetGlobalChunkCoordinate(); //var chunkOffset = ChunkManager.ChunkData.RoundToChunkCoords(globalOffset); //globalOffset.X = chunkOffset.X * VoxelConstants.ChunkSizeX; //globalOffset.Y = chunkOffset.Y * VoxelConstants.ChunkSizeY; //globalOffset.Z = chunkOffset.Z * VoxelConstants.ChunkSizeZ; WorldOrigin = new Vector2(globalOffset.X, globalOffset.Z); Camera.Position = new Vector3(0, 10, 0) + globalOffset; Camera.Target = new Vector3(0, 10, 1) + globalOffset; // If there's no file, we have to initialize the first chunk coordinate if (gameFile == null) // Todo: Always true? { ChunkManager.GenerateInitialChunks( GlobalVoxelCoordinate.FromVector3(globalOffset).GetGlobalChunkCoordinate(), SetLoadingMessage); } ComponentManager = new ComponentManager(this); ComponentManager.SetRootComponent(new Body(ComponentManager, "root", Matrix.Identity, Vector3.Zero, Vector3.Zero, false)); if (Natives == null) // Todo: Always true?? { FactionLibrary library = new FactionLibrary(); library.Initialize(this, CompanyMakerState.CompanyInformation); Natives = new List <Faction>(); for (int i = 0; i < 10; i++) { Natives.Add(library.GenerateFaction(this, i, 10)); } } #region Prepare Factions foreach (Faction faction in Natives) { faction.World = this; if (faction.RoomBuilder == null) { faction.RoomBuilder = new RoomBuilder(faction, this); } if (faction.CraftBuilder == null) { faction.CraftBuilder = new CraftBuilder(faction, this); } } Factions = new FactionLibrary(); if (Natives != null && Natives.Count > 0) { Factions.AddFactions(this, Natives); } Factions.Initialize(this, CompanyMakerState.CompanyInformation); Point playerOrigin = new Point((int)(WorldOrigin.X), (int)(WorldOrigin.Y)); Factions.Factions["Player"].Center = playerOrigin; Factions.Factions["The Motherland"].Center = new Point(playerOrigin.X + 50, playerOrigin.Y + 50); #endregion Diplomacy = new Diplomacy(this); Diplomacy.Initialize(Time.CurrentDate); // Initialize goal manager here. GoalManager = new Goals.GoalManager(); GoalManager.Initialize(new List <Goals.Goal>()); TutorialManager = new Tutorial.TutorialManager(Program.CreatePath("Content", "tutorial.txt")); TutorialManager.TutorialEnabled = !GameSettings.Default.TutorialDisabledGlobally; Tutorial("new game start"); } Camera.World = this; //Drawer3D.Camera = Camera; #endregion ChunkManager.camera = Camera; SetLoadingMessage("Creating Particles ..."); ParticleManager = new ParticleManager(GraphicsDevice, ComponentManager); SetLoadingMessage("Creating GameMaster ..."); Master = new GameMaster(Factions.Factions["Player"], Game, ComponentManager, ChunkManager, Camera, GraphicsDevice); if (gameFile != null) { if (gameFile.PlayData.Spells != null) { Master.Spells = gameFile.PlayData.Spells; } if (gameFile.PlayData.Tasks != null) { Master.TaskManager = gameFile.PlayData.Tasks; } } if (Master.Faction.Economy.Company.Information == null) { Master.Faction.Economy.Company.Information = new CompanyInformation(); } CreateInitialEmbarkment(); foreach (var chunk in ChunkManager.ChunkData.ChunkMap) { chunk.CalculateInitialSunlight(); } VoxelHelpers.InitialReveal(ChunkManager.ChunkData, new VoxelHandle( ChunkManager.ChunkData.GetChunkEnumerator().FirstOrDefault(), new LocalVoxelCoordinate(0, VoxelConstants.ChunkSizeY - 1, 0))); foreach (var chunk in ChunkManager.ChunkData.ChunkMap) { ChunkManager.InvalidateChunk(chunk); } ChunkManager.StartThreads(); SetLoadingMessage("Presimulating ..."); ShowingWorld = false; OnLoadedEvent(); Thread.Sleep(1000); ShowingWorld = true; SetLoadingMessage("Complete."); // GameFile is no longer needed. gameFile = null; LoadStatus = LoadingStatus.Success; #if !DEBUG } catch (Exception exception) { Game.CaptureException(exception); LoadingException = exception; LoadStatus = LoadingStatus.Failure; } #endif }
public List <Body> FrustrumCullLocatableComponents(Camera camera) { List <Body> visible = CollisionManager.GetVisibleObjects <Body>(camera.GetFrustrum(), CollisionManager.CollisionType.Dynamic | CollisionManager.CollisionType.Static); return(visible); }
public IEnumerable <MoveAction> GetInverseMoveActions_Experimental(VoxelHandle voxel) { if (!voxel.IsValid || !voxel.IsEmpty) { yield break; } CollisionManager objectHash = Creature.Manager.World.CollisionManager; var neighborHood = GetNeighborhood(voxel); bool inWater = (neighborHood[1, 1, 1].IsValid && neighborHood[1, 1, 1].WaterCell.WaterLevel > WaterManager.inWaterThreshold); bool standingOnGround = (neighborHood[1, 0, 1].IsValid && !neighborHood[1, 0, 1].IsEmpty); bool topCovered = (neighborHood[1, 2, 1].IsValid && !neighborHood[1, 2, 1].IsEmpty); bool hasNeighbors = HasNeighbors(neighborHood); bool isClimbing = false; var successors = new List <MoveAction>(); if (CanClimb) { var ladderAt = GetBodyAt(voxel, objectHash, "Climbable"); var ladderAbove = GetBodyAt(VoxelHelpers.GetVoxelAbove(voxel), objectHash, "Climbable"); var ladderBelow = GetBodyAt(VoxelHelpers.GetNeighbor(voxel, new GlobalVoxelOffset(0, -1, 0)), objectHash, "Climbable"); // If there was a ladder above the creature, we could have climbed down it to get here. if (ladderAbove != null) { successors.Add(new MoveAction { Diff = new Vector3(1, 2, 1), MoveType = MoveType.Climb, InteractObject = ladderAbove }); } // If there was a ladder below the creature, we could have climbed up to get here. if (ladderBelow != null) { successors.Add(new MoveAction { Diff = new Vector3(1, 0, 1), MoveType = MoveType.Climb, InteractObject = ladderBelow }); } if (ladderAt != null) { standingOnGround = true; isClimbing = true; } } // If the creature can climb walls, check to see if there are any walls nearby that we could have climbed here from. if (CanClimbWalls && !topCovered) { // First check the voxel above to see if it has any walls nearby. if (!topCovered) { var wallsAbove = new VoxelHandle[] { neighborHood[2, 2, 1], neighborHood[0, 2, 1], neighborHood[1, 2, 2], neighborHood[1, 2, 0] }; var wallAbove = VoxelHandle.InvalidHandle; foreach (var w in wallsAbove) { if (w.IsValid && !w.IsEmpty) { wallAbove = w; break; } } // If there was a wall above us, we could have climbed down to get here. if (wallAbove.IsValid) { successors.Add(new MoveAction { Diff = new Vector3(1, 2, 1), MoveType = MoveType.ClimbWalls, ActionVoxel = wallAbove }); } } // Now check the walls below if (!standingOnGround) { var wallsBelow = new VoxelHandle[] { neighborHood[2, 0, 1], neighborHood[0, 0, 1], neighborHood[1, 0, 2], neighborHood[1, 0, 0] }; var wallBelow = VoxelHandle.InvalidHandle; foreach (var w in wallsBelow) { if (w.IsValid && !w.IsEmpty) { wallBelow = w; break; } } // If there was a wall below us, we could have climbed up to get here. if (wallBelow.IsValid) { successors.Add(new MoveAction { Diff = new Vector3(1, 0, 1), MoveType = MoveType.ClimbWalls, ActionVoxel = wallBelow }); } } } // If the creature either can walk or is in water, add the // eight-connected free neighbors around the voxel. if (CanWalk || CanSwim) { // If the creature is in water, it can swim. Otherwise, it will walk. var moveType = inWater ? MoveType.Swim : MoveType.Walk; if (neighborHood[0, 1, 1].IsValid && neighborHood[0, 1, 1].IsEmpty) { if (moveType == MoveType.Swim || (neighborHood[0, 0, 1].IsValid && !neighborHood[0, 0, 1].IsEmpty)) { successors.Add(new MoveAction { Diff = new Vector3(0, 1, 1), MoveType = moveType }); } } if (neighborHood[2, 1, 1].IsValid && neighborHood[2, 1, 1].IsEmpty) { if (moveType == MoveType.Swim || (neighborHood[2, 0, 1].IsValid && !neighborHood[2, 0, 1].IsEmpty)) { successors.Add(new MoveAction { Diff = new Vector3(2, 1, 1), MoveType = moveType }); } } if (neighborHood[1, 1, 0].IsValid && neighborHood[1, 1, 0].IsEmpty) { if (moveType == MoveType.Swim || (neighborHood[1, 0, 0].IsValid && !neighborHood[1, 0, 0].IsEmpty)) { successors.Add(new MoveAction { Diff = new Vector3(1, 1, 0), MoveType = moveType }); } } if (neighborHood[1, 1, 2].IsValid && neighborHood[1, 1, 2].IsEmpty) { if (moveType == MoveType.Swim || (neighborHood[1, 0, 2].IsValid && !neighborHood[1, 0, 2].IsEmpty)) { successors.Add(new MoveAction { Diff = new Vector3(1, 1, 2), MoveType = moveType }); } } // Only bother worrying about 8-connected movement if there are // no full neighbors around the voxel. if (!hasNeighbors) { if (neighborHood[2, 1, 2].IsValid && neighborHood[2, 1, 2].IsEmpty) { if (moveType == MoveType.Swim || (neighborHood[2, 0, 2].IsValid && !neighborHood[2, 0, 2].IsEmpty)) { successors.Add(new MoveAction { Diff = new Vector3(2, 1, 2), MoveType = moveType }); } } if (neighborHood[2, 1, 0].IsValid && neighborHood[2, 1, 0].IsEmpty) { if (moveType == MoveType.Swim || (neighborHood[2, 0, 0].IsValid && !neighborHood[2, 0, 0].IsEmpty)) { successors.Add(new MoveAction { Diff = new Vector3(2, 1, 0), MoveType = moveType }); } } if (neighborHood[0, 1, 2].IsValid && neighborHood[0, 1, 2].IsEmpty) { if (moveType == MoveType.Swim || (neighborHood[0, 0, 2].IsValid && !neighborHood[0, 0, 2].IsEmpty)) { successors.Add(new MoveAction { Diff = new Vector3(0, 1, 2), MoveType = moveType }); } } if (neighborHood[0, 1, 0].IsValid && neighborHood[0, 1, 0].IsEmpty) { if (moveType == MoveType.Swim || (neighborHood[0, 0, 0].IsValid && !neighborHood[0, 0, 0].IsEmpty)) { successors.Add(new MoveAction { Diff = new Vector3(0, 1, 0), MoveType = moveType }); } } } } // Now a somewhat tricky part. We've got to figure out which cells can jump to this cell. // The rules for jumping are as follows: // 1) The voxel must be exactly 1 below this one. // 2) The voxel must be exactly 1 away in the other dimensions // 3) The voxel above the one we're jumping from must be free. // 4) The voxel below the one we're jumping from must be filled, or be in water, or // must be part of a climb action. // Step 4 is really hard, so let's ignore it for now. // First, check the 3x3 neighborhood around the voxel. if (standingOnGround) { for (int dx = 0; dx <= 2; dx++) { for (int dz = 0; dz <= 2; dz++) { // Ignore the current voxel (can't jump from there) if (dx == 1 && dz == 1) { continue; } // Can't jump from neighbor because neighbor's head isn't clear. if (!(neighborHood[dx, 1, dz].IsValid && neighborHood[dx, 1, dz].IsEmpty)) { continue; } // Now just assume we can jump from the neighbor below us. TODO (step 4) successors.Add(new MoveAction { Diff = new Vector3(dx, 0, dz), MoveType = MoveType.Jump }); } } } // If the creature is not in water and is not standing on ground, // it can fall one voxel downward in free space. So check the voxel above, // if it is free and has no water, then we could have fallen from it. if (neighborHood[1, 2, 1].IsValid && neighborHood[1, 2, 1].IsEmpty && neighborHood[1, 2, 1].WaterCell.WaterLevel == 0) { successors.Add(new MoveAction { Diff = new Vector3(1, 2, 1), MoveType = MoveType.Fall }); } // If the creature can fly and is not underwater, it can fly // to any adjacent empty cell. Luckily this is reversible so we don't have to change // anything from GetMoveactions if (CanFly && !inWater) { for (int dx = 0; dx <= 2; dx++) { for (int dz = 0; dz <= 2; dz++) { for (int dy = 0; dy <= 2; dy++) { if (dx == 1 && dz == 1 && dy == 1) { continue; } if (!neighborHood[dx, 1, dz].IsValid || neighborHood[dx, 1, dz].IsEmpty) { successors.Add(new MoveAction { Diff = new Vector3(dx, dy, dz), MoveType = MoveType.Fly }); } } } } } // Now, validate each move action that the creature might take. foreach (MoveAction v in successors) { var n = neighborHood[(int)v.Diff.X, (int)v.Diff.Y, (int)v.Diff.Z]; if (n.IsValid && (n.IsEmpty || n.WaterCell.WaterLevel > 0)) { // Do one final check to see if there is an object blocking the motion. bool blockedByObject = false; var objectsAtNeighbor = Creature.Manager.World.CollisionManager.EnumerateIntersectingObjects( n.GetBoundingBox(), CollisionManager.CollisionType.Static); // If there is an object blocking the motion, determine if it can be passed through. foreach (var body in objectsAtNeighbor.OfType <GameComponent>()) { var door = body.GetRoot().EnumerateAll().OfType <Door>().FirstOrDefault(); // If there is an enemy door blocking movement, we can destroy it to get through. if (door != null) { if ( Creature.World.Diplomacy.GetPolitics(door.TeamFaction, Creature.Faction) .GetCurrentRelationship() != Relationship.Loving) { if (Can(MoveType.DestroyObject)) { yield return(new MoveAction { Diff = -(v.Diff - Vector3.One), MoveType = MoveType.DestroyObject, InteractObject = door, DestinationVoxel = voxel, SourceVoxel = n }); } blockedByObject = true; } } } // If no object blocked us, we can move freely as normal. if (!blockedByObject) { MoveAction newAction = v; newAction.Diff = -(v.Diff - Vector3.One); newAction.DestinationVoxel = voxel; newAction.SourceVoxel = n; yield return(newAction); } } } }
private GameComponent GetBodyAt(VoxelHandle voxel, CollisionManager objectHash, string tag) { return(objectHash.EnumerateIntersectingObjects(voxel.GetBoundingBox(), CollisionManager.CollisionType.Static).OfType <GameComponent>().FirstOrDefault(component => component.Tags.Contains(tag))); }
/// <summary> gets the list of actions that the creature can take from a given voxel. </summary> public IEnumerable <MoveAction> GetMoveActions(VoxelHandle voxel) { if (!voxel.IsValid || !voxel.IsEmpty) { yield break; } CollisionManager objectHash = Creature.Manager.World.CollisionManager; var neighborHood = GetNeighborhood(voxel); bool inWater = (neighborHood[1, 1, 1].IsValid && neighborHood[1, 1, 1].WaterCell.WaterLevel > WaterManager.inWaterThreshold); bool standingOnGround = (neighborHood[1, 0, 1].IsValid && !neighborHood[1, 0, 1].IsEmpty); bool topCovered = (neighborHood[1, 2, 1].IsValid && !neighborHood[1, 2, 1].IsEmpty); bool hasNeighbors = HasNeighbors(neighborHood); bool isClimbing = false; var successors = new List <MoveAction>(); if (CanClimb) { //Climbing ladders. var bodies = objectHash.EnumerateIntersectingObjects(voxel.GetBoundingBox(), CollisionManager.CollisionType.Static).OfType <GameComponent>(); var ladder = bodies.FirstOrDefault(component => component.Tags.Contains("Climbable")); // if the creature can climb objects and a ladder is in this voxel, // then add a climb action. if (ladder != null) { successors.Add(new MoveAction { Diff = new Vector3(1, 2, 1), MoveType = MoveType.Climb, InteractObject = ladder }); isClimbing = true; if (!standingOnGround) { successors.Add(new MoveAction { Diff = new Vector3(1, 0, 1), MoveType = MoveType.Climb, InteractObject = ladder }); } standingOnGround = true; } } // If the creature can climb walls and is not blocked by a voxl above. if (CanClimbWalls && !topCovered) { var walls = new VoxelHandle[] { neighborHood[2, 1, 1], neighborHood[0, 1, 1], neighborHood[1, 1, 2], neighborHood[1, 1, 0] }; var wall = VoxelHandle.InvalidHandle; foreach (var w in walls) { if (w.IsValid && !w.IsEmpty) { wall = w; } } if (wall.IsValid) { isClimbing = true; successors.Add(new MoveAction { Diff = new Vector3(1, 2, 1), MoveType = MoveType.ClimbWalls, ActionVoxel = wall }); if (!standingOnGround) { successors.Add(new MoveAction { Diff = new Vector3(1, 0, 1), MoveType = MoveType.ClimbWalls, ActionVoxel = wall }); } } } // If the creature either can walk or is in water, add the // eight-connected free neighbors around the voxel. if ((CanWalk && standingOnGround) || (CanSwim && inWater)) { // If the creature is in water, it can swim. Otherwise, it will walk. var moveType = inWater ? MoveType.Swim : MoveType.Walk; if (!neighborHood[0, 1, 1].IsValid || neighborHood[0, 1, 1].IsEmpty) { // +- x successors.Add(new MoveAction { Diff = new Vector3(0, 1, 1), MoveType = moveType }); } if (!neighborHood[2, 1, 1].IsValid || neighborHood[2, 1, 1].IsEmpty) { successors.Add(new MoveAction { Diff = new Vector3(2, 1, 1), MoveType = moveType }); } if (!neighborHood[1, 1, 0].IsValid || neighborHood[1, 1, 0].IsEmpty) { // +- z successors.Add(new MoveAction { Diff = new Vector3(1, 1, 0), MoveType = moveType }); } if (!neighborHood[1, 1, 2].IsValid || neighborHood[1, 1, 2].IsEmpty) { successors.Add(new MoveAction { Diff = new Vector3(1, 1, 2), MoveType = moveType }); } // Only bother worrying about 8-connected movement if there are // no full neighbors around the voxel. if (!hasNeighbors) { if (!neighborHood[2, 1, 2].IsValid || neighborHood[2, 1, 2].IsEmpty) { // +x + z successors.Add(new MoveAction { Diff = new Vector3(2, 1, 2), MoveType = moveType }); } if (!neighborHood[2, 1, 0].IsValid || neighborHood[2, 1, 0].IsEmpty) { successors.Add(new MoveAction { Diff = new Vector3(2, 1, 0), MoveType = moveType }); } if (!neighborHood[0, 1, 2].IsValid || neighborHood[0, 1, 2].IsEmpty) { // -x -z successors.Add(new MoveAction { Diff = new Vector3(0, 1, 2), MoveType = moveType }); } if (!neighborHood[0, 1, 0].IsValid || neighborHood[0, 1, 0].IsEmpty) { successors.Add(new MoveAction { Diff = new Vector3(0, 1, 0), MoveType = moveType }); } } } // If the creature's head is free, and it is standing on ground, // or if it is in water, or if it is climbing, it can also jump // to voxels that are 1 cell away and 1 cell up. if (!topCovered && (standingOnGround || (CanSwim && inWater) || isClimbing)) { for (int dx = 0; dx <= 2; dx++) { for (int dz = 0; dz <= 2; dz++) { if (dx == 1 && dz == 1) { continue; } if (neighborHood[dx, 1, dz].IsValid && !neighborHood[dx, 1, dz].IsEmpty) { successors.Add(new MoveAction { Diff = new Vector3(dx, 2, dz), MoveType = MoveType.Jump }); } } } } // If the creature is not in water and is not standing on ground, // it can fall one voxel downward in free space. if (!inWater && !standingOnGround) { successors.Add(new MoveAction { Diff = new Vector3(1, 0, 1), MoveType = MoveType.Fall }); } // If the creature can fly and is not underwater, it can fly // to any adjacent empty cell. if (CanFly && !inWater) { for (int dx = 0; dx <= 2; dx++) { for (int dz = 0; dz <= 2; dz++) { for (int dy = 0; dy <= 2; dy++) { if (dx == 1 && dz == 1 && dy == 1) { continue; } if (!neighborHood[dx, 1, dz].IsValid || neighborHood[dx, 1, dz].IsEmpty) { successors.Add(new MoveAction { Diff = new Vector3(dx, dy, dz), MoveType = MoveType.Fly }); } } } } } // Now, validate each move action that the creature might take. foreach (MoveAction v in successors) { var n = neighborHood[(int)v.Diff.X, (int)v.Diff.Y, (int)v.Diff.Z]; if (n.IsValid && (n.IsEmpty || n.WaterCell.WaterLevel > 0)) { // Do one final check to see if there is an object blocking the motion. bool blockedByObject = false; var objectsAtNeighbor = Creature.Manager.World.CollisionManager.EnumerateIntersectingObjects( n.GetBoundingBox(), CollisionManager.CollisionType.Static); // If there is an object blocking the motion, determine if it can be passed through. foreach (var body in objectsAtNeighbor.OfType <GameComponent>()) { var door = body.GetRoot().EnumerateAll().OfType <Door>().FirstOrDefault(); // If there is an enemy door blocking movement, we can destroy it to get through. if (door != null) { if ( Creature.World.Diplomacy.GetPolitics(door.TeamFaction, Creature.Faction) .GetCurrentRelationship() != Relationship.Loving) { if (Can(MoveType.DestroyObject)) { yield return(new MoveAction { Diff = v.Diff, MoveType = MoveType.DestroyObject, InteractObject = door, DestinationVoxel = n, SourceVoxel = voxel }); } blockedByObject = true; } } } // If no object blocked us, we can move freely as normal. if (!blockedByObject) { MoveAction newAction = v; newAction.SourceVoxel = voxel; newAction.DestinationVoxel = n; yield return(newAction); } } } }
public List <Creature.MoveAction> GetMoveActions(Voxel voxel) { List <Creature.MoveAction> toReturn = new List <Creature.MoveAction>(); CollisionManager objectHash = PlayState.ComponentManager.CollisionManager; Voxel[,,] neighborHood = GetNeighborhood(voxel); int x = (int)voxel.GridPosition.X; int y = (int)voxel.GridPosition.Y; int z = (int)voxel.GridPosition.Z; bool inWater = (neighborHood[1, 1, 1] != null && neighborHood[1, 1, 1].WaterLevel > 5); bool standingOnGround = (neighborHood[1, 0, 1] != null && !neighborHood[1, 0, 1].IsEmpty); bool topCovered = (neighborHood[1, 2, 1] != null && !neighborHood[1, 2, 1].IsEmpty); bool hasNeighbors = HasNeighbors(neighborHood); List <Creature.MoveAction> successors = new List <Creature.MoveAction>(); //Climbing ladders List <IBoundedObject> bodiesInside = objectHash.Hashes[CollisionManager.CollisionType.Static].GetItems( new Point3(MathFunctions.FloorInt(voxel.Position.X), MathFunctions.FloorInt(voxel.Position.Y), MathFunctions.FloorInt(voxel.Position.Z))); if (bodiesInside != null) { bool hasLadder = bodiesInside.OfType <GameComponent>() .Any(component => component.Tags.Contains("Climbable")); if (hasLadder) { ; } { successors.Add(new Creature.MoveAction() { Diff = new Vector3(1, 2, 1), MoveType = Creature.MoveType.Climb }); if (!standingOnGround) { successors.Add(new Creature.MoveAction() { Diff = new Vector3(1, 0, 1), MoveType = Creature.MoveType.Climb }); } standingOnGround = true; } } if (standingOnGround || inWater) { Creature.MoveType moveType = inWater ? Creature.MoveType.Swim : Creature.MoveType.Walk; if (IsEmpty(neighborHood[0, 1, 1])) { // +- x successors.Add(new Creature.MoveAction() { Diff = new Vector3(0, 1, 1), MoveType = moveType }); } if (IsEmpty(neighborHood[2, 1, 1])) { successors.Add(new Creature.MoveAction() { Diff = new Vector3(2, 1, 1), MoveType = moveType }); } if (IsEmpty(neighborHood[1, 1, 0])) { // +- z successors.Add(new Creature.MoveAction() { Diff = new Vector3(1, 1, 0), MoveType = moveType }); } if (IsEmpty(neighborHood[1, 1, 2])) { successors.Add(new Creature.MoveAction() { Diff = new Vector3(1, 1, 2), MoveType = moveType }); } if (!hasNeighbors) { if (IsEmpty(neighborHood[2, 1, 2])) { // +x + z successors.Add(new Creature.MoveAction() { Diff = new Vector3(2, 1, 2), MoveType = moveType }); } if (IsEmpty(neighborHood[2, 1, 0])) { successors.Add(new Creature.MoveAction() { Diff = new Vector3(2, 1, 0), MoveType = moveType }); } if (IsEmpty(neighborHood[0, 1, 2])) { // -x -z successors.Add(new Creature.MoveAction() { Diff = new Vector3(0, 1, 2), MoveType = moveType }); } if (IsEmpty(neighborHood[0, 1, 0])) { successors.Add(new Creature.MoveAction() { Diff = new Vector3(0, 1, 0), MoveType = moveType }); } } } if (!topCovered && (standingOnGround || inWater)) { for (int dx = 0; dx <= 2; dx++) { for (int dz = 0; dz <= 2; dz++) { if (dx == 1 && dz == 1) { continue; } if (!IsEmpty(neighborHood[dx, 1, dz])) { successors.Add(new Creature.MoveAction() { Diff = new Vector3(dx, 2, dz), MoveType = Creature.MoveType.Jump }); } } } } // Falling if (!inWater && !standingOnGround) { successors.Add(new Creature.MoveAction() { Diff = new Vector3(1, 0, 1), MoveType = Creature.MoveType.Fall }); } foreach (Creature.MoveAction v in successors) { Voxel n = neighborHood[(int)v.Diff.X, (int)v.Diff.Y, (int)v.Diff.Z]; if (n != null && (n.IsEmpty || n.WaterLevel > 0)) { Creature.MoveAction newAction = v; newAction.Voxel = n; toReturn.Add(newAction); } } return(toReturn); }
public List<Creature.MoveAction> GetMoveActions(Voxel voxel) { List<Creature.MoveAction> toReturn = new List<Creature.MoveAction>(); CollisionManager objectHash = PlayState.ComponentManager.CollisionManager; Voxel[,,] neighborHood = GetNeighborhood(voxel); int x = (int)voxel.GridPosition.X; int y = (int)voxel.GridPosition.Y; int z = (int)voxel.GridPosition.Z; bool inWater = (neighborHood[1, 1, 1] != null && neighborHood[1, 1, 1].WaterLevel > 5); bool standingOnGround = (neighborHood[1, 0, 1] != null && !neighborHood[1, 0, 1].IsEmpty); bool topCovered = (neighborHood[1, 2, 1] != null && !neighborHood[1, 2, 1].IsEmpty); bool hasNeighbors = HasNeighbors(neighborHood); List<Creature.MoveAction> successors = new List<Creature.MoveAction>(); //Climbing ladders IEnumerable<IBoundedObject> objectsInside = objectHash.Hashes[CollisionManager.CollisionType.Static].GetItems( new Point3(MathFunctions.FloorInt(voxel.Position.X), MathFunctions.FloorInt(voxel.Position.Y), MathFunctions.FloorInt(voxel.Position.Z))); bool blockedByObject = false; if (objectsInside != null) { var bodies = objectsInside.OfType<GameComponent>(); var enumerable = bodies as IList<GameComponent> ?? bodies.ToList(); // TODO: This is supposed to be done when the door is a NEIGHBOR of this voxel only!! foreach (GameComponent body in enumerable) { Door door = body.GetRootComponent().GetChildrenOfType<Door>(true).FirstOrDefault(); if (door != null) { if ( PlayState.Diplomacy.GetPolitics(door.TeamFaction, Creature.Faction).GetCurrentRelationship() == Relationship.Hateful) { if (IsEmpty(neighborHood[0, 1, 1])) // +- x successors.Add(new Creature.MoveAction() { Diff = new Vector3(0, 1, 1), MoveType = Creature.MoveType.DestroyObject, InteractObject = door, Voxel = neighborHood[0, 1, 1] }); if (IsEmpty(neighborHood[2, 1, 1])) successors.Add(new Creature.MoveAction() { Diff = new Vector3(2, 1, 1), MoveType = Creature.MoveType.DestroyObject, InteractObject = door, Voxel = neighborHood[2, 1, 1] }); if (IsEmpty(neighborHood[1, 1, 0])) // +- z successors.Add(new Creature.MoveAction() { Diff = new Vector3(1, 1, 0), MoveType = Creature.MoveType.DestroyObject, InteractObject = door, Voxel = neighborHood[1, 1, 0] }); if (IsEmpty(neighborHood[1, 1, 2])) successors.Add(new Creature.MoveAction() { Diff = new Vector3(1, 1, 2), MoveType = Creature.MoveType.DestroyObject, InteractObject = door, Voxel = neighborHood[1, 1, 2] }); blockedByObject = true; } } } if (blockedByObject) { return successors; } if (CanClimb) { bool hasLadder = enumerable.Any(component => component.Tags.Contains("Climbable")); if (hasLadder) { successors.Add(new Creature.MoveAction() { Diff = new Vector3(1, 2, 1), MoveType = Creature.MoveType.Climb }); if (!standingOnGround) { successors.Add(new Creature.MoveAction() { Diff = new Vector3(1, 0, 1), MoveType = Creature.MoveType.Climb }); } standingOnGround = true; } } } if (standingOnGround || (CanSwim && inWater)) { Creature.MoveType moveType = inWater ? Creature.MoveType.Swim : Creature.MoveType.Walk; if (IsEmpty(neighborHood[0, 1, 1])) // +- x successors.Add(new Creature.MoveAction() { Diff = new Vector3(0, 1, 1), MoveType = moveType }); if (IsEmpty(neighborHood[2, 1, 1])) successors.Add(new Creature.MoveAction() { Diff = new Vector3(2, 1, 1), MoveType = moveType }); if (IsEmpty(neighborHood[1, 1, 0])) // +- z successors.Add(new Creature.MoveAction() { Diff = new Vector3(1, 1, 0), MoveType = moveType }); if (IsEmpty(neighborHood[1, 1, 2])) successors.Add(new Creature.MoveAction() { Diff = new Vector3(1, 1, 2), MoveType = moveType }); if (!hasNeighbors) { if (IsEmpty(neighborHood[2, 1, 2])) // +x + z successors.Add(new Creature.MoveAction() { Diff = new Vector3(2, 1, 2), MoveType = moveType }); if (IsEmpty(neighborHood[2, 1, 0])) successors.Add(new Creature.MoveAction() { Diff = new Vector3(2, 1, 0), MoveType = moveType }); if (IsEmpty(neighborHood[0, 1, 2])) // -x -z successors.Add(new Creature.MoveAction() { Diff = new Vector3(0, 1, 2), MoveType = moveType }); if (IsEmpty(neighborHood[0, 1, 0])) successors.Add(new Creature.MoveAction() { Diff = new Vector3(0, 1, 0), MoveType = moveType }); } } if (!topCovered && (standingOnGround || (CanSwim && inWater))) { for (int dx = 0; dx <= 2; dx++) { for (int dz = 0; dz <= 2; dz++) { if (dx == 1 && dz == 1) continue; if (!IsEmpty(neighborHood[dx, 1, dz])) { successors.Add(new Creature.MoveAction() { Diff = new Vector3(dx, 2, dz), MoveType = Creature.MoveType.Jump }); } } } } // Falling if (!inWater && !standingOnGround) { successors.Add(new Creature.MoveAction() { Diff = new Vector3(1, 0, 1), MoveType = Creature.MoveType.Fall }); } if (CanFly) { for (int dx = 0; dx <= 2; dx++) { for (int dz = 0; dz <= 2; dz++) { for (int dy = 0; dy <= 2; dy++) { if (dx == 1 && dz == 1 && dy == 1) continue; if (IsEmpty(neighborHood[dx, 1, dz])) { successors.Add(new Creature.MoveAction() { Diff = new Vector3(dx, dy, dz), MoveType = Creature.MoveType.Fly }); } } } } } foreach (Creature.MoveAction v in successors) { Voxel n = neighborHood[(int)v.Diff.X, (int)v.Diff.Y, (int)v.Diff.Z]; if (n != null && (n.IsEmpty || n.WaterLevel > 0)) { Creature.MoveAction newAction = v; newAction.Voxel = n; toReturn.Add(newAction); } } return toReturn; }