public override IEnumerable <Status> Run() { Creature.IsCloaked = false; if (Zone != null) { var resourcesToStock = Creature.Inventory.Resources.Where(a => a.MarkedForRestock && Zone is Stockpile && (Zone as Stockpile).IsAllowed(a.Resource.TypeName)).ToList(); foreach (var resource in resourcesToStock) { var createdItem = Creature.Inventory.RemoveAndCreate(resource.Resource, Inventory.RestockType.RestockResource); if (Zone.AddResource(resource.Resource)) { var toss = new TossMotion(1.0f, 2.5f, createdItem.LocalTransform, Zone.GetBoundingBox().Center() + new Vector3(0.5f, 0.5f, 0.5f)); if (createdItem.GetRoot().GetComponent <Physics>().HasValue(out var physics)) { physics.CollideMode = Physics.CollisionMode.None; } createdItem.AnimationQueue.Add(toss); toss.OnComplete += createdItem.Die; Creature.NoiseMaker.MakeNoise("Stockpile", Creature.AI.Position); Creature.Stats.NumItemsGathered++; Creature.CurrentCharacterMode = Creature.Stats.CurrentClass.AttackMode; Creature.Sprite.ResetAnimations(Creature.Stats.CurrentClass.AttackMode); Creature.Sprite.PlayAnimations(Creature.Stats.CurrentClass.AttackMode); while (!Creature.Sprite.AnimPlayer.IsDone()) { yield return(Status.Running); } yield return(Status.Running); } else { Creature.Inventory.AddResource(resource.Resource, Inventory.RestockType.RestockResource); createdItem.Delete(); } } } Timer waitTimer = new Timer(1.0f, true); bool removed = Creature.World.RemoveResourcesFromSpecificZone(Resource, Zone); if (!removed) { yield return(Status.Fail); } else { var newEntity = Agent.Manager.RootComponent.AddChild(new ResourceEntity(Agent.Manager, Resource, Zone.GetBoundingBox().Center() + new Vector3(0.0f, 1.0f, 0.0f))); if (newEntity.GetRoot().GetComponent <Physics>().HasValue(out var newPhysics)) { newPhysics.CollideMode = Physics.CollisionMode.None; } var toss = new TossMotion(1.0f + MathFunctions.Rand(0.1f, 0.2f), 2.5f + MathFunctions.Rand(-0.5f, 0.5f), newEntity.LocalTransform, Agent.Position); newEntity.AnimationQueue.Add(toss); toss.OnComplete += () => newEntity.Die(); Agent.Creature.Inventory.AddResource(Resource, Inventory.RestockType.None); Agent.Creature.Sprite.ResetAnimations(Creature.Stats.CurrentClass.AttackMode); while (!waitTimer.HasTriggered) { Agent.Creature.CurrentCharacterMode = Creature.Stats.CurrentClass.AttackMode; waitTimer.Update(DwarfTime.LastTime); yield return(Status.Running); } Agent.Creature.CurrentCharacterMode = CharacterMode.Idle; yield return(Status.Success); } }
public IEnumerable <Act.Status> PerformOnVoxel(Creature performer, Vector3 pos, KillVoxelTask DigAct, DwarfTime time, float bonus, string faction) { while (true) { if (!DigAct.Voxel.IsValid) { yield return(Act.Status.Fail); yield break; } Drawer2D.DrawLoadBar(performer.World.Camera, DigAct.Voxel.WorldPosition + Vector3.One * 0.5f, Color.White, Color.Black, 32, 1, (float)DigAct.VoxelHealth / DigAct.Voxel.Type.StartingHealth); switch (TriggerMode) { case AttackTrigger.Timer: RechargeTimer.Update(time); if (!RechargeTimer.HasTriggered) { yield return(Act.Status.Running); continue; } break; case AttackTrigger.Animation: if (!performer.Sprite.AnimPlayer.HasValidAnimation() || performer.Sprite.AnimPlayer.CurrentFrame < TriggerFrame) { if (performer.Sprite.AnimPlayer.HasValidAnimation()) { performer.Sprite.AnimPlayer.Play(); } yield return(Act.Status.Running); continue; } break; } switch (Mode) { case AttackMode.Melee: { DigAct.VoxelHealth -= (DamageAmount + bonus); DigAct.Voxel.Type.HitSound.Play(DigAct.Voxel.WorldPosition); if (HitParticles != "") { performer.Manager.World.ParticleManager.Trigger(HitParticles, DigAct.Voxel.WorldPosition, Color.White, 5); } if (HitAnimation != null) { IndicatorManager.DrawIndicator(HitAnimation, DigAct.Voxel.WorldPosition + Vector3.One * 0.5f, 10.0f, 1.0f, MathFunctions.RandVector2Circle() * 10, HitColor, MathFunctions.Rand() > 0.5f); } break; } case AttackMode.Ranged: { throw new InvalidOperationException("Ranged attacks should never be used for digging."); //LaunchProjectile(pos, DigAct.GetTargetVoxel().WorldPosition, null); //break; } } yield return(Act.Status.Success); yield break; } }
public void DoDamage(Creature performer, Body other, float bonus) { if (!String.IsNullOrEmpty(DiseaseToSpread)) { var otherCreature = other.GetRoot().GetComponent <Creature>(); if (otherCreature != null) { var disease = DiseaseLibrary.GetDisease(DiseaseToSpread); if (MathFunctions.RandEvent(disease.LikelihoodOfSpread)) { otherCreature.AcquireDisease(DiseaseToSpread); } } } var health = other.GetRoot().EnumerateAll().OfType <Health>().FirstOrDefault(); if (health != null) { health.Damage(DamageAmount + bonus); var injury = DiseaseLibrary.GetRandomInjury(); if (MathFunctions.RandEvent(injury.LikelihoodOfSpread)) { var creature = other.GetRoot().GetComponent <Creature>(); if (creature != null) { creature.AcquireDisease(injury.Name); } } Vector3 knock = other.Position - performer.Physics.Position; knock.Normalize(); knock *= 0.2f; if (other.AnimationQueue.Count == 0) { other.AnimationQueue.Add(new KnockbackAnimation(0.15f, other.LocalTransform, knock)); } } else { other.GetRoot().Die(); } PlayNoise(other.GlobalTransform.Translation); if (HitParticles != "") { performer.Manager.World.ParticleManager.Trigger(HitParticles, other.LocalTransform.Translation, Color.White, 5); if (ShootLaser) { performer.Manager.World.ParticleManager.TriggerRay(HitParticles, performer.AI.Position, other.LocalTransform.Translation); } } if (HitAnimation != null) { IndicatorManager.DrawIndicator(HitAnimation, other.BoundingBox.Center(), 10.0f, 1.0f, MathFunctions.RandVector2Circle(), Color.White, MathFunctions.Rand() > 0.5f); } Physics physics = other as Physics; if (physics != null) { Vector3 force = other.Position - performer.AI.Position; if (force.LengthSquared() > 0.01f) { force.Normalize(); physics.ApplyForce(force * Knockback, 1.0f); } } }
public void GenerateFauna(VoxelChunk chunk, ComponentManager components, ContentManager content, GraphicsDevice graphics, FactionLibrary factions) { int waterHeight = (int)(SeaLevel * chunk.SizeY); Voxel v = chunk.MakeVoxel(0, 0, 0); for (int x = 0; x < chunk.SizeX; x++) { for (int z = 0; z < chunk.SizeZ; z++) { Vector2 vec = new Vector2(x + chunk.Origin.X, z + chunk.Origin.Z) / PlayState.WorldScale; Overworld.Biome biome = Overworld.Map[(int)MathFunctions.Clamp(vec.X, 0, Overworld.Map.GetLength(0) - 1), (int)MathFunctions.Clamp(vec.Y, 0, Overworld.Map.GetLength(1) - 1)].Biome; BiomeData biomeData = BiomeLibrary.Biomes[biome]; int y = chunk.GetFilledVoxelGridHeightAt(x, chunk.SizeY - 1, z); if (!chunk.IsCellValid(x, (int)(y - chunk.Origin.Y), z)) { continue; } v.GridPosition = new Vector3(x, y, z); if (chunk.Data.Water[v.Index].WaterLevel != 0 || y <= waterHeight) { continue; } foreach (FaunaData animal in biomeData.Fauna) { if (y <= 0 || !(PlayState.Random.NextDouble() < animal.SpawnProbability)) { continue; } EntityFactory.CreateEntity <Body>(animal.Name, chunk.Origin + new Vector3(x, y, z) + Vector3.Up * 1.0f); break; } } } }
public VoxelChunk GenerateChunk(Vector3 origin, int chunkSizeX, int chunkSizeY, int chunkSizeZ, ComponentManager components, ContentManager content, GraphicsDevice graphics) { float waterHeight = SeaLevel; VoxelChunk c = new VoxelChunk(Manager, origin, 1, Manager.ChunkData.GetChunkID(origin + new Vector3(0.5f, 0.5f, 0.5f)), chunkSizeX, chunkSizeY, chunkSizeZ) { ShouldRebuild = true, ShouldRecalculateLighting = true }; Voxel voxel = c.MakeVoxel(0, 0, 0); for (int x = 0; x < chunkSizeX; x++) { for (int z = 0; z < chunkSizeZ; z++) { Vector2 v = new Vector2(x + origin.X, z + origin.Z) / PlayState.WorldScale; Overworld.Biome biome = Overworld.Map[(int)MathFunctions.Clamp(v.X, 0, Overworld.Map.GetLength(0) - 1), (int)MathFunctions.Clamp(v.Y, 0, Overworld.Map.GetLength(1) - 1)].Biome; BiomeData biomeData = BiomeLibrary.Biomes[biome]; Vector2 pos = new Vector2(x + origin.X, z + origin.Z) / PlayState.WorldScale; float hNorm = Overworld.GetValue(Overworld.Map, pos, Overworld.ScalarFieldType.Height); float h = MathFunctions.Clamp(hNorm * chunkSizeY, 0.0f, chunkSizeY - 2); int stoneHeight = (int)Math.Max(h - 2, 1); for (int y = 0; y < chunkSizeY; y++) { voxel.GridPosition = new Vector3(x, y, z); if (y == 0) { voxel.Type = VoxelLibrary.GetVoxelType("Bedrock"); continue; } if (y <= stoneHeight && stoneHeight > 1) { voxel.Type = VoxelLibrary.GetVoxelType(biomeData.SubsurfVoxel); voxel.Health = VoxelLibrary.GetVoxelType(biomeData.SubsurfVoxel).StartingHealth; } else if ((y == (int)h || y == stoneHeight) && hNorm > waterHeight) { if (biomeData.ClumpGrass && NoiseGenerator.Noise(pos.X / biomeData.ClumpSize, 0, pos.Y / biomeData.ClumpSize) > biomeData.ClumpTreshold) { voxel.Type = VoxelLibrary.GetVoxelType(biomeData.GrassVoxel); voxel.Health = VoxelLibrary.GetVoxelType(biomeData.GrassVoxel).StartingHealth; } else if (!biomeData.ClumpGrass) { voxel.Type = VoxelLibrary.GetVoxelType(biomeData.GrassVoxel); voxel.Health = VoxelLibrary.GetVoxelType(biomeData.GrassVoxel).StartingHealth; } else { voxel.Type = VoxelLibrary.GetVoxelType(biomeData.SoilVoxel); voxel.Health = VoxelLibrary.GetVoxelType(biomeData.SoilVoxel).StartingHealth; } } else if (y > h && y > 0) { voxel.Type = VoxelLibrary.GetVoxelType("empty"); } else if (hNorm < waterHeight) { voxel.Type = VoxelLibrary.GetVoxelType(biomeData.ShoreVoxel); voxel.Health = VoxelLibrary.GetVoxelType(biomeData.ShoreVoxel).StartingHealth; } else { voxel.Type = VoxelLibrary.GetVoxelType(biomeData.SoilVoxel); voxel.Health = VoxelLibrary.GetVoxelType(biomeData.SoilVoxel).StartingHealth; } } } } GenerateOres(c, components, content, graphics); GenerateCaves(c); GenerateWater(c); GenerateLava(c); c.ShouldRebuildWater = true; return(c); }
/// <summary> /// Draws a line between two points of the given color and width by scaling and rotating a pixel /// </summary> /// <param Name="batch">The sprite batch to use.</param> /// <param Name="pixel">The pixel image to use.</param> /// <param Name="point1">The first point of the line.</param> /// <param Name="point2">The second point of the line.</param> /// <param Name="lineColor">The color of the line.</param> /// <param Name="width">The width, in pixels, of the line.</param> public static void DrawLine(SpriteBatch batch, Vector2 point1, Vector2 point2, Color lineColor, int width) { float distance = Vector2.Distance(point1, point2); Vector2 normal = (point2 - point1); normal.Normalize(); batch.Draw(Pixel, new Rectangle((int)(point1.X), (int)(point1.Y) - width / 2, (int)distance, width), new Rectangle(0, 0, 1, 1), lineColor, MathFunctions.RectangularToPolar(normal).Y, Vector2.Zero, SpriteEffects.None, 0.0f); batch.Draw(Pixel, point1, null, lineColor, MathFunctions.RectangularToPolar(normal).Y, Vector2.Zero, new Vector2(distance, width), SpriteEffects.None, 0); }
public void Start() { World.MakeAnnouncement("A storm is coming!", null); switch (TypeofStorm) { case StormType.RainStorm: SoundManager.PlaySound(ContentPaths.Audio.Oscar.sfx_gui_rain_storm_alert, 0.15f); break; case StormType.SnowStorm: SoundManager.PlaySound(ContentPaths.Audio.Oscar.sfx_gui_snow_storm_alert, 0.15f); break; } BoundingBox bounds = World.ChunkManager.Bounds; Vector3 extents = bounds.Extents(); Vector3 center = bounds.Center(); Vector3 windNormalized = WindSpeed / WindSpeed.Length(); Vector3 offset = new Vector3(-windNormalized.X * extents.X + center.X, bounds.Max.Y + 5, -windNormalized.Z * extents.Z + center.Z); Vector3 perp = new Vector3(-windNormalized.Z, 0, windNormalized.X); int numClouds = (int)(MathFunctions.RandInt(10, 100) * Intensity); int numCloudLayers = MathFunctions.RandInt(1, 5); for (int layer = 0; layer < numCloudLayers; layer++) { for (int i = 0; i < numClouds; i++) { Vector3 cloudPos = offset + perp * 5 * (i - numClouds / 2) + MathFunctions.RandVector3Cube() * 10 + windNormalized * 2 * layer; Cloud cloud = new Cloud(World.ComponentManager, Intensity, 5, offset.Y + MathFunctions.Rand(-3.0f, 3.0f), cloudPos, TypeofStorm == StormType.RainStorm ? 0.15f : 0.0f) { Velocity = WindSpeed * 0.5f, TypeofStorm = TypeofStorm }; Clouds.Add(cloud); World.ComponentManager.RootComponent.AddChild(cloud); } } IsInitialized = true; }
public BiomeData GetBiomeAt(Vector3 worldPos, Vector2 origin) { var v = WorldToOverworld(worldPos, origin); var r = WorldToOverworldRemainder(new Vector2(worldPos.X, worldPos.Z)); var blendColor = BiomeBlend.Data[BiomeBlend.Index((int)MathFunctions.Clamp(r.X, 0, VoxelConstants.ChunkSizeX), (int)MathFunctions.Clamp(r.Y, 0, VoxelConstants.ChunkSizeZ))]; var offsetV = v + new Vector2((blendColor.R - 127.0f) / 128.0f, (blendColor.G - 127.0f) / 128.0f); var biome1 = Map[(int)MathFunctions.Clamp(v.X, 0, Map.GetLength(0) - 1), (int)MathFunctions.Clamp(v.Y, 0, Map.GetLength(1) - 1)].Biome; var biome2 = Map[(int)MathFunctions.Clamp(offsetV.X, 0, Map.GetLength(0) - 1), (int)MathFunctions.Clamp(offsetV.Y, 0, Map.GetLength(1) - 1)].Biome; return(Library.GetBiome(Math.Max(biome1, biome2))); }
public List <Body> RemoveAndCreate(ResourceAmount resources) { List <Body> toReturn = new List <Body>(); if (!Resources.RemoveResource(resources.CloneResource())) { return(toReturn); } for (int i = 0; i < resources.NumResources; i++) { Body newEntity = EntityFactory.CreateEntity <Body>(resources.ResourceType.ResourceName + " Resource", GlobalTransform.Translation + MathFunctions.RandVector3Cube() * 0.5f); toReturn.Add(newEntity); } return(toReturn); }
/// <summary> /// Checks the voxels around the creature and reacts to changes in its immediate environment. /// For example this function determines when the creature is standing on solid ground. /// </summary> public void CheckNeighborhood(ChunkManager chunks, float dt) { var below = new VoxelHandle(chunks.ChunkData, GlobalVoxelCoordinate.FromVector3(Physics.GlobalTransform.Translation - Vector3.UnitY * 0.8f)); var above = new VoxelHandle(chunks.ChunkData, GlobalVoxelCoordinate.FromVector3(Physics.GlobalTransform.Translation + Vector3.UnitY * 0.8f)); if (above.IsValid) { IsHeadClear = above.IsEmpty; } if (below.IsValid && Physics.IsInLiquid) { IsOnGround = false; } else if (below.IsValid) { IsOnGround = !below.IsEmpty; } else { IsOnGround = false; } if (!IsOnGround) { if (CurrentCharacterMode != CharacterMode.Flying) { if (Physics.Velocity.Y > 0.05) { CurrentCharacterMode = CharacterMode.Jumping; } else if (Physics.Velocity.Y < -0.05) { CurrentCharacterMode = CharacterMode.Falling; } } if (Physics.IsInLiquid) { CurrentCharacterMode = CharacterMode.Swimming; } } if (CurrentCharacterMode == CharacterMode.Falling && IsOnGround) { CurrentCharacterMode = CharacterMode.Idle; } if (Status.IsAsleep) { CurrentCharacterMode = CharacterMode.Sleeping; if (MathFunctions.RandEvent(0.01f)) { NoiseMaker.MakeNoise("Sleep", AI.Position, true); } } else if (currentCharacterMode == CharacterMode.Sleeping) { CurrentCharacterMode = CharacterMode.Idle; } if (World.Time.IsDay() && Status.IsAsleep && !Status.Energy.IsDissatisfied() && !Status.Health.IsCritical()) { Status.IsAsleep = false; } }
private static Color GetPixelAt(Color[] data, int x, int y, int width, int height) { return(data[MathFunctions.Clamp(y, 0, height - 1) * width + MathFunctions.Clamp(x, 0, width - 1)]); }
/// <summary> /// Gets a stairstep stretching accross the box. /// </summary> /// <param name="box">The box.</param> /// <returns>A stairstep starting filled on the bottom row, pointing in the maximum x or z direction</returns> private IEnumerable <Vector3> GetStair(BoundingBox box, Vector3 start, Vector3 end, bool invert) { int minX = MathFunctions.FloorInt(box.Min.X + 0.5f); int minY = MathFunctions.FloorInt(box.Min.Y + 0.5f); int minZ = MathFunctions.FloorInt(box.Min.Z + 0.5f); int maxX = MathFunctions.FloorInt(box.Max.X - 0.5f); int maxY = MathFunctions.FloorInt(box.Max.Y - 0.5f); int maxZ = MathFunctions.FloorInt(box.Max.Z - 0.5f); // If not inverted, selects the Xs // If inverted, selects the Os //max y ----xOOOO // --- xxOOO // --- xxxOO // --- xxxxO //min y --- xxxxx // minx --- maxx float dx = box.Max.X - box.Min.X; float dz = box.Max.Z - box.Min.Z; Vector3 dir = end - start; bool direction = dx > dz; bool positiveDir = direction ? dir.X < 0 : dir.Z < 0; int step = 0; // Always make staircases go exactly to the top or bottom of the selection. if (direction && invert) { minY = maxY - (maxX - minX); } else if (direction) { maxY = minY + (maxX - minX); } else if (invert) { minY = maxY - (maxZ - minZ); } else { maxY = minY + (maxZ - minZ); } int dy = maxY - minY; // Start from the bottom of the stairs up to the top. for (int y = minY; y <= maxY; y++) { int carve = invert ? MathFunctions.Clamp(dy - step, 0, dy) : step; // If stairs are in x direction if (direction) { if (positiveDir) { // Start from min x, and march up to maxY - y for (int x = minX; x <= MathFunctions.Clamp(maxX - carve, minX, maxX); x++) { for (int z = minZ; z <= maxZ; z++) { yield return(new Vector3(x + 0.5f, y + 0.5f, z + 0.5f)); } } } else { // Start from min x, and march up to maxY - y for (int x = maxX; x >= MathFunctions.Clamp(minX + carve, minX, maxX); x--) { for (int z = minZ; z <= maxZ; z++) { yield return(new Vector3(x + 0.5f, y + 0.5f, z + 0.5f)); } } } step++; } // Otherwise, they are in the z direction. else { if (positiveDir) { // Start from min z, and march up to maxY - y for (int z = minZ; z <= MathFunctions.Clamp(maxZ - carve, minZ, maxZ); z++) { for (int x = minX; x <= maxX; x++) { yield return(new Vector3(x + 0.5f, y + 0.5f, z + 0.5f)); } } } else { // Start from min z, and march up to maxY - y for (int z = maxZ; z >= MathFunctions.Clamp(minZ + carve, minZ, maxZ); z--) { for (int x = minX; x <= maxX; x++) { yield return(new Vector3(x + 0.5f, y + 0.5f, z + 0.5f)); } } } step++; } } }
private static GameComponent __factory2(ComponentManager Manager, Vector3 Position, Blackboard Data) { Weather.CreateForecast(Manager.World.Time.CurrentDate, Manager.World.ChunkManager.Bounds, Manager.World, 3); Weather.CreateStorm(MathFunctions.RandVector3Cube() * 10, MathFunctions.Rand(0.05f, 1.0f), Manager.World); return(new Cloud(Manager, 0.1f, 50, 40, Position, 0.0f)); }
override public void Update(DwarfTime gameTime, ChunkManager chunks, Camera camera) { base.Update(gameTime, chunks, camera); Storm.InitializeStatics(); BoundingBox box = chunks.Bounds; box.Expand(10.0f); if (GlobalTransform.Translation.X < box.Min.X || GlobalTransform.Translation.X > box.Max.X || GlobalTransform.Translation.Z < box.Min.Z || GlobalTransform.Translation.Z > box.Max.Z) { Die(); } bool generateRainDrop = MathFunctions.RandEvent(Raininess * 0.75f); if (generateRainDrop) { for (int i = 0; i < MaxRainDrops; i++) { if (!RainDrops[i].IsAlive) { RainDrops[i].IsAlive = true; if (RainDrops[i].Particle != null) { RainDrops[i].Particle.LifeRemaining = 60.0f; RainDrops[i].Particle.TimeAlive = 0.0f; } RainDrops[i].Pos = MathFunctions.RandVector3Box(BoundingBox.Expand(5)); RainDrops[i].Pos = new Vector3(RainDrops[i].Pos.X, BoundingBox.Min.Y - 1, RainDrops[i].Pos.Z); RainDrops[i].Vel = Vector3.Down * Storm.Properties[TypeofStorm].RainSpeed + Velocity; break; } } } bool generateLightning = LightningChance > 0.0f && MathFunctions.RandEvent((float)(LightningChance * 0.001f)); if (generateLightning) { var below = VoxelHelpers.FindFirstVoxelBelowIncludingWater(new VoxelHandle(World.ChunkManager, GlobalVoxelCoordinate.FromVector3(new Vector3(Position.X, Math.Min(World.WorldSizeInVoxels.Y - 1, Position.Y), Position.Z)))); if (below.IsValid && !below.IsEmpty) { var above = VoxelHelpers.GetVoxelAbove(below); if (above.IsValid) { EntityFactory.CreateEntity <Fire>("Fire", above.GetBoundingBox().Center()); List <Vector3> lightningStrikes = new List <Vector3>(); List <Color> colors = new List <Color>(); var c = above.GetBoundingBox().Center(); for (float t = 0; t < 1.0f; t += 0.25f) { var p = c * t + Position * (1.0f - t); lightningStrikes.Add(p + MathFunctions.RandVector3Box(-5, 5, 0, 0.1f, -5, 5)); colors.Add(Color.White); } lightningStrikes.Add(c); colors.Add(Color.White); Drawer3D.DrawLineList(lightningStrikes, colors, 0.3f); SoundManager.PlaySound(ContentPaths.Audio.Oscar.sfx_gui_rain_storm_alert, MathFunctions.Rand(0.001f, 0.05f), MathFunctions.Rand(0.5f, 1.0f)); SoundManager.PlaySound(ContentPaths.Audio.Oscar.sfx_trap_destroyed, c, false, 1.0f, MathFunctions.Rand(-0.5f, 0.5f)); World.ParticleManager.Trigger("explode", c, Color.White, 10); } } } Storm.StormProperties stormProperties = Storm.Properties[TypeofStorm]; var rainEmitter = World.ParticleManager.Effects[stormProperties.RainEffect]; var hitEmitter = World.ParticleManager.Effects[stormProperties.HitEffect]; for (int i = 0; i < MaxRainDrops; i++) { if (!RainDrops[i].IsAlive) { continue; } RainDrops[i].Pos += RainDrops[i].Vel * DwarfTime.Dt; if (stormProperties.RainRandom > 0) { RainDrops[i].Vel.X += MathFunctions.Rand(-1, 1) * stormProperties.RainRandom * DwarfTime.Dt; RainDrops[i].Vel.Z += MathFunctions.Rand(-1, 1) * stormProperties.RainRandom * DwarfTime.Dt; } if (RainDrops[i].Pos.Y < 0) { RainDrops[i].IsAlive = false; } if (!RainDrops[i].IsAlive && RainDrops[i].Particle != null) { RainDrops[i].Particle.LifeRemaining = -1; } else if (RainDrops[i].IsAlive && RainDrops[i].Particle == null) { RainDrops[i].Particle = rainEmitter.Emitters[0].CreateParticle(RainDrops[i].Pos, RainDrops[i].Vel, Color.White); } else if (RainDrops[i].IsAlive && RainDrops[i].Particle != null) { RainDrops[i].Particle.Position = RainDrops[i].Pos; RainDrops[i].Particle.Velocity = RainDrops[i].Vel; } var test = new VoxelHandle(chunks, GlobalVoxelCoordinate.FromVector3(RainDrops[i].Pos)); if (!test.IsValid || (test.IsEmpty && test.LiquidLevel == 0)) { continue; } RainDrops[i].IsAlive = false; var hitBodies = World.EnumerateIntersectingObjects(new BoundingBox(RainDrops[i].Pos - Vector3.One, RainDrops[i].Pos + Vector3.One)); foreach (var body in hitBodies) { if (body.Parent != Manager.RootComponent) { continue; } if (body.GetRoot().GetComponent <Flammable>().HasValue(out var flames)) { flames.Heat *= 0.25f; } if (body.GetRoot().GetComponent <Seedling>().HasValue(out var seeds)) { if (TypeofStorm == StormType.RainStorm) { seeds.GrowthTime += MathFunctions.Rand(1.0f, 12.0f); } else if (MathFunctions.RandEvent(0.01f)) { seeds.GetRoot().Die(); } } } hitEmitter.Trigger(1, RainDrops[i].Pos + Vector3.UnitY * 0.5f, Color.White); //if (!MathFunctions.RandEvent(0.1f)) continue; var above = test.IsEmpty ? test : VoxelHelpers.GetVoxelAbove(test); if (!above.IsValid || !above.IsEmpty) { continue; } if (TypeofStorm == StormType.RainStorm && (above.LiquidLevel < WaterManager.maxWaterLevel && (above.LiquidType == LiquidType.Water))) { above.LiquidLevel = (byte)Math.Min(WaterManager.maxWaterLevel, above.LiquidLevel + WaterManager.rainFallAmount); above.LiquidType = stormProperties.LiquidToCreate; } else if (TypeofStorm == StormType.SnowStorm && above.IsEmpty && above.LiquidLevel == 0) { if (test.GrassType == 0) { test.GrassType = Library.GetGrassType("snow").ID; test.GrassDecay = Library.GetGrassType("snow").InitialDecayValue; } else { var existingGrass = Library.GetGrassType((byte)test.GrassType); if (!String.IsNullOrEmpty(existingGrass.BecomeWhenSnowedOn)) { var newGrass = Library.GetGrassType(existingGrass.BecomeWhenSnowedOn); test.GrassType = newGrass.ID; test.GrassDecay = newGrass.InitialDecayValue; } } } } Matrix tf = LocalTransform; tf.Translation += Velocity * DwarfTime.Dt; LocalTransform = tf; }
public void Initialize(string blood) { HasMeat = false; HasBones = false; Physics.Orientation = Physics.OrientMode.RotateY; CreateSprite(Stats.CurrentClass, Manager); Hands = Physics.AddChild(new Grabber("hands", Manager, Matrix.Identity, new Vector3(0.1f, 0.1f, 0.1f), Vector3.Zero)) as Grabber; Sensors = Physics.AddChild(new EnemySensor(Manager, "EnemySensor", Matrix.Identity, new Vector3(20, 5, 20), Vector3.Zero)) as EnemySensor; AI = Physics.AddChild(new MudGolemAI(Manager, Sensors, Manager.World.PlanService) { Movement = { IsSessile = true, CanFly = false, CanSwim = false, CanWalk = false, CanClimb = false, CanClimbWalls = false } }) as CreatureAI; Attacks = new List <Attack>() { new Attack(Stats.CurrentClass.Attacks[0]) }; Inventory = Physics.AddChild(new Inventory(Manager, "Inventory", Physics.BoundingBox.Extents(), Physics.LocalBoundingBoxOffset)) as Inventory; var gems = ResourceLibrary.GetResourcesByTag(Resource.ResourceTags.Gem); for (int i = 0; i < 16; i++) { int num = MathFunctions.RandInt(1, 32 - i); Inventory.AddResource(new ResourceAmount(Datastructures.SelectRandom(gems), num)); i += num - 1; } Matrix shadowTransform = Matrix.CreateRotationX((float)Math.PI * 0.5f); shadowTransform.Translation = new Vector3(0.0f, -0.5f, 0.0f); Physics.Tags.Add("MudGolem"); Physics.Mass = 100; Physics.AddChild(new ParticleTrigger(blood, Manager, "Death Gibs", Matrix.Identity, Vector3.One, Vector3.Zero) { TriggerOnDeath = true, TriggerAmount = 5, SoundToPlay = ContentPaths.Audio.gravel }); NoiseMaker.Noises["Hurt"] = new List <string> { ContentPaths.Audio.demon0, ContentPaths.Audio.gravel, }; Physics.AddChild(new MinimapIcon(Manager, new NamedImageFrame(ContentPaths.GUI.map_icons, 16, 2, 1))); Stats.FullName = TextGenerator.GenerateRandom("$goblinname"); //Stats.LastName = TextGenerator.GenerateRandom("$elffamily"); Stats.Size = 4; Resistances[DamageType.Fire] = 5; Resistances[DamageType.Acid] = 5; Resistances[DamageType.Cold] = 5; Species = "Mud Golem"; }
private static void UpdateChunk(VoxelChunk chunk) { var addGrassToThese = new List <Tuple <VoxelHandle, byte> >(); for (var y = 0; y < VoxelConstants.ChunkSizeY; ++y) { // Skip empty slices. if (chunk.Data.VoxelsPresentInSlice[y] == 0) { continue; } for (var x = 0; x < VoxelConstants.ChunkSizeX; ++x) { for (var z = 0; z < VoxelConstants.ChunkSizeZ; ++z) { var voxel = VoxelHandle.UnsafeCreateLocalHandle(chunk, new LocalVoxelCoordinate(x, y, z)); // Allow grass to decay if (voxel.GrassType != 0) { var grass = Library.GetGrassType(voxel.GrassType); if (grass.NeedsSunlight && !voxel.Sunlight) { voxel.GrassType = 0; } else if (grass.Decay) { if (voxel.GrassDecay == 0) { var newDecal = Library.GetGrassType(grass.BecomeWhenDecays); if (newDecal != null) { voxel.GrassType = newDecal.ID; } else { voxel.GrassType = 0; } } else { voxel.GrassDecay -= 1; } } } //#if false else if (voxel.Type.GrassSpreadsHere) { // Spread grass onto this tile - but only from the same biome. // Don't spread if there's an entity here. var entityPresent = chunk.Manager.World.EnumerateIntersectingObjects( new BoundingBox(voxel.WorldPosition + new Vector3(0.1f, 1.1f, 0.1f), voxel.WorldPosition + new Vector3(0.9f, 1.9f, 0.9f)), CollisionType.Static).Any(); if (entityPresent) { continue; } // Don't spread if there's a voxel above us. var voxelAbove = VoxelHelpers.GetVoxelAbove(voxel); if (voxelAbove.IsValid && !voxelAbove.IsEmpty) { continue; } if (chunk.Manager.World.Overworld.Map.GetBiomeAt(voxel.Coordinate.ToVector3(), chunk.Manager.World.Overworld.InstanceSettings.Origin).HasValue(out var biome)) { var grassyNeighbors = VoxelHelpers.EnumerateManhattanNeighbors2D(voxel.Coordinate) .Select(c => new VoxelHandle(voxel.Chunk.Manager, c)) .Where(v => v.IsValid && v.GrassType != 0) .Where(v => Library.GetGrassType(v.GrassType).Spreads) .Where(v => { if (chunk.Manager.World.Overworld.Map.GetBiomeAt(v.Coordinate.ToVector3(), chunk.Manager.World.Overworld.InstanceSettings.Origin).HasValue(out var otherBiome)) { return(biome == otherBiome); } return(false); }) .ToList(); if (grassyNeighbors.Count > 0) { if (MathFunctions.RandEvent(0.1f)) { addGrassToThese.Add(Tuple.Create(voxel, grassyNeighbors[MathFunctions.RandInt(0, grassyNeighbors.Count)].GrassType)); } } } } //#endif } } } foreach (var v in addGrassToThese) { var l = v.Item1; var grassType = Library.GetGrassType(v.Item2); if (grassType.NeedsSunlight && !l.Sunlight) { continue; } l.GrassType = v.Item2; } }
public void Update(WorldManager World) { if (ExpiditionState == Expedition.State.Trading) { if (UpdateWaitTimer(World.Time.CurrentDate)) { World.MakeAnnouncement(String.Format("The envoy from {0} is leaving.", OwnerFaction.ParentFaction.Name)); RecallEnvoy(); } } Creatures.RemoveAll(creature => creature.IsDead); if (DeathTimer.Update(World.Time.CurrentDate)) { Creatures.ForEach((creature) => creature.GetRoot().Die()); } var politics = World.Overworld.GetPolitics(OwnerFaction.ParentFaction, OtherFaction.ParentFaction); if (politics.GetCurrentRelationship() == Relationship.Hateful) { World.MakeAnnouncement(String.Format("The envoy from {0} left: we are at war with them.", OwnerFaction.ParentFaction.Name)); RecallEnvoy(); } else { if (Creatures.Any( // TODO (mklingen) why do I need this null check? creature => creature.Creature != null && World.PersistentData.Designations.IsDesignation(creature.Physics, DesignationType.Attack))) { if (!politics.HasEvent("You attacked our trade delegates")) { politics.AddEvent(new PoliticalEvent() { Change = -1.0f, Description = "You attacked our trade delegates", }); } else { politics.AddEvent(new PoliticalEvent() { Change = -2.0f, Description = "You attacked our trade delegates more than once", }); } } } if (!ShouldRemove && ExpiditionState == Expedition.State.Arriving) { foreach (var creature in Creatures) { var tradePort = World.GetNearestRoomOfType("Balloon Port", creature.Position); if (tradePort == null) { World.MakeAnnouncement("We need a balloon trade port to trade.", null, () => { return(World.GetNearestRoomOfType("Balloon Port", creature.Position) == null); }); World.Tutorial("trade"); SoundManager.PlaySound(ContentPaths.Audio.Oscar.sfx_gui_negative_generic, 0.5f); RecallEnvoy(); break; } if (creature.Tasks.Count == 0) { creature.Tasks.Add(new TradeTask(tradePort, this)); } if (!tradePort.IsRestingOnZone(creature.Position)) { continue; } if (ExpiditionState != Expedition.State.Trading || !IsTradeWidgetValid()) { MakeTradeWidget(World); } StartTrading(World.Time.CurrentDate); ExpiditionState = Expedition.State.Trading; break; } } else if (ExpiditionState == Expedition.State.Leaving) { BoundingBox worldBBox = World.ChunkManager.Bounds; foreach (CreatureAI creature in Creatures) { if (creature.Tasks.Count == 0) { creature.LeaveWorld(); } } foreach (var creature in Creatures) { if (MathFunctions.Dist2D(worldBBox, creature.Position) < 2.0f) { creature.GetRoot().Delete(); } } } else if (!IsTradeWidgetValid()) { MakeTradeWidget(World); } if (!OwnerFaction.ParentFaction.IsCorporate && Creatures.All(creature => creature.IsDead)) { ShouldRemove = true; } }
public IEnumerable <Status> FindRandomPath() { Vector3 target = MathFunctions.RandVector3Cube() * Radius + Creature.AI.Position; if (Creature.AI.PositionConstraint.Contains(target) == ContainmentType.Disjoint) { target = MathFunctions.RandVector3Box(Creature.AI.PositionConstraint); } if (Is2D) { target.Y = Creature.AI.Position.Y; } List <MoveAction> path = new List <MoveAction>(); VoxelHandle curr = Creature.Physics.CurrentVoxel; var bodies = Agent.World.PlayerFaction.OwnedObjects.Where(o => o.Tags.Contains("Teleporter")).ToList(); var storage = new MoveActionTempStorage(); MoveState previousMoveState = new MoveState { Voxel = curr }; for (int i = 0; i < PathLength; i++) { var actions = Creature.AI.Movement.GetMoveActions(previousMoveState, bodies, storage); MoveAction?bestAction = null; float bestDist = float.MaxValue; foreach (MoveAction action in actions) { if (Is2D && (action.MoveType == MoveType.Climb || action.MoveType == MoveType.ClimbWalls)) { continue; } float dist = (action.DestinationVoxel.WorldPosition - target).LengthSquared() * Creature.AI.Movement.Cost(action.MoveType); if (dist < bestDist && !path.Any(a => a.DestinationVoxel == action.DestinationVoxel)) { bestDist = dist; bestAction = action; } } if (bestAction.HasValue && !path.Any(p => p.DestinationVoxel.Equals(bestAction.Value.DestinationVoxel) && p.MoveType == bestAction.Value.MoveType && Creature.AI.PositionConstraint.Contains(bestAction.Value.DestinationVoxel.WorldPosition + Vector3.One * 0.5f) == ContainmentType.Contains)) { MoveAction action = bestAction.Value; path.Add(action); previousMoveState = action.DestinationState; } else { break; } } if (path.Count > 0) { Creature.AI.Blackboard.SetData("RandomPath", path); yield return(Status.Success); } else { yield return(Status.Fail); } }
public Point3(Vector3 vect) { X = MathFunctions.FloorInt(vect.X); Y = MathFunctions.FloorInt(vect.Y); Z = MathFunctions.FloorInt(vect.Z); }
public override IEnumerable <Status> Run() { Vector3 oldPosition = Agent.Position; bool firstIter = true; Creature.Controller.Reset(); WanderTime.Reset(); TurnTime.Reset(); while (!WanderTime.HasTriggered) { Creature.OverrideCharacterMode = false; Creature.Physics.Orientation = Physics.OrientMode.RotateY; Creature.CurrentCharacterMode = CharacterMode.Walking; WanderTime.Update(DwarfTime.LastTime); if (!Creature.IsOnGround) { yield return(Status.Success); yield break; } if (TurnTime.Update(DwarfTime.LastTime) || TurnTime.HasTriggered || firstIter) { int iters = 0; while (iters < 100) { iters++; Vector2 randTarget = MathFunctions.RandVector2Circle() * Radius; LocalTarget = new Vector3(randTarget.X, 0, randTarget.Y) + oldPosition; VoxelHandle voxel = new VoxelHandle(Agent.World.ChunkManager, GlobalVoxelCoordinate.FromVector3(LocalTarget)); bool foundLava = false; foreach (VoxelHandle neighbor in VoxelHelpers.EnumerateAllNeighbors(voxel.Coordinate).Select(coord => new VoxelHandle(Agent.World.ChunkManager, coord))) { if (neighbor.IsValid && neighbor.Chunk != null) { if (neighbor.LiquidType == LiquidType.Lava) { foundLava = true; } } } if (!foundLava) { break; } } if (iters == 100) { yield return(Act.Status.Fail); yield break; } firstIter = false; TurnTime.Reset(TurnTime.TargetTimeSeconds + MathFunctions.Rand(-0.1f, 0.1f)); } float dist = (LocalTarget - Agent.Position).Length(); if (dist < 0.5f) { Creature.Physics.Velocity *= 0.0f; Creature.CurrentCharacterMode = CharacterMode.Idle; yield return(Status.Running); } else { Vector3 output = Creature.Controller.GetOutput((float)DwarfTime.LastTime.ElapsedGameTime.TotalSeconds, LocalTarget, Agent.Position); output.Y = 0.0f; Creature.Physics.ApplyForce(output * 0.5f, (float)DwarfTime.LastTime.ElapsedGameTime.TotalSeconds); Creature.CurrentCharacterMode = CharacterMode.Walking; } yield return(Status.Running); } Creature.CurrentCharacterMode = CharacterMode.Idle; yield return(Status.Success); }
public override IEnumerable <Status> Run() { Creature.IsCloaked = false; if (CurrentAttack == null) { yield return(Status.Fail); yield break; } Timeout.Reset(); FailTimer.Reset(); if (Target == null && TargetName != null) { Target = Agent.Blackboard.GetData <Body>(TargetName); if (Target == null) { yield return(Status.Fail); yield break; } } if (Agent.Faction.Race.IsIntelligent) { var targetInventory = Target.GetRoot().GetComponent <Inventory>(); if (targetInventory != null) { targetInventory.SetLastAttacker(Agent); } } CharacterMode defaultCharachterMode = Creature.AI.Movement.CanFly ? CharacterMode.Flying : CharacterMode.Walking; bool avoided = false; while (true) { Timeout.Update(DwarfTime.LastTime); FailTimer.Update(DwarfTime.LastTime); if (FailTimer.HasTriggered) { Creature.Physics.Orientation = Physics.OrientMode.RotateY; Creature.OverrideCharacterMode = false; Creature.CurrentCharacterMode = defaultCharachterMode; yield return(Status.Fail); yield break; } if (Timeout.HasTriggered) { if (Training) { Agent.AddXP(1); Creature.Physics.Orientation = Physics.OrientMode.RotateY; Creature.OverrideCharacterMode = false; Creature.CurrentCharacterMode = defaultCharachterMode; yield return(Status.Success); yield break; } else { Creature.Physics.Orientation = Physics.OrientMode.RotateY; Creature.OverrideCharacterMode = false; Creature.CurrentCharacterMode = defaultCharachterMode; yield return(Status.Fail); yield break; } } if (Target == null || Target.IsDead) { Creature.CurrentCharacterMode = defaultCharachterMode; Creature.Physics.Orientation = Physics.OrientMode.RotateY; yield return(Status.Success); } // Find the location of the melee target Vector3 targetPos = new Vector3(Target.GlobalTransform.Translation.X, Target.GetBoundingBox().Min.Y, Target.GlobalTransform.Translation.Z); Vector2 diff = new Vector2(targetPos.X, targetPos.Z) - new Vector2(Creature.AI.Position.X, Creature.AI.Position.Z); Creature.Physics.Face(targetPos); bool intersectsbounds = Creature.Physics.BoundingBox.Intersects(Target.BoundingBox); float dist = diff.Length(); // If we are really far from the target, something must have gone wrong. if (DefensiveStructure == null && !intersectsbounds && dist > CurrentAttack.Range * 4) { Creature.Physics.Orientation = Physics.OrientMode.RotateY; Creature.OverrideCharacterMode = false; Creature.CurrentCharacterMode = defaultCharachterMode; yield return(Status.Fail); yield break; } if (DefensiveStructure != null) { if (Creature.Hp < LastHp) { float damage = LastHp - Creature.Hp; Creature.Heal(Math.Min(5.0f, damage)); var health = DefensiveStructure.GetRoot().GetComponent <Health>(); if (health != null) { health.Damage(damage); Drawer2D.DrawLoadBar(health.World.Camera, DefensiveStructure.Position, Color.White, Color.Black, 32, 1, health.Hp / health.MaxHealth, 0.1f); } LastHp = Creature.Hp; } if (dist > CurrentAttack.Range) { float sqrDist = dist * dist; foreach (var threat in Creature.AI.Faction.Threats) { float threatDist = (threat.AI.Position - Creature.AI.Position).LengthSquared(); if (threatDist < sqrDist) { sqrDist = threatDist; Target = threat.Physics; break; } } dist = (float)Math.Sqrt(sqrDist); } if (dist > CurrentAttack.Range * 4) { yield return(Status.Fail); yield break; } if (DefensiveStructure.IsDead) { DefensiveStructure = null; } } LastHp = Creature.Hp; // If we're out of attack range, run toward the target. if (DefensiveStructure == null && !Creature.AI.Movement.IsSessile && !intersectsbounds && diff.Length() > CurrentAttack.Range) { Creature.CurrentCharacterMode = defaultCharachterMode; /* * Vector3 output = Creature.Controller.GetOutput(DwarfTime.Dt, targetPos, Creature.Physics.GlobalTransform.Translation) * 0.9f; * output.Y = 0.0f; * if (Creature.AI.Movement.CanFly) * { * Creature.Physics.ApplyForce(-Creature.Physics.Gravity, DwarfTime.Dt); * } * if (Creature.AI.Movement.IsSessile) * { * output *= 0.0f; * } * Creature.Physics.ApplyForce(output, DwarfTime.Dt); * Creature.Physics.Orientation = Physics.OrientMode.RotateY; */ GreedyPathAct greedyPath = new GreedyPathAct(Creature.AI, Target, CurrentAttack.Range * 0.75f) { PathLength = 5 }; greedyPath.Initialize(); foreach (Act.Status stat in greedyPath.Run()) { if (stat == Act.Status.Running) { yield return(Status.Running); } else { break; } } } // If we have a ranged weapon, try avoiding the target for a few seconds to get within range. else if (DefensiveStructure == null && !Creature.AI.Movement.IsSessile && !intersectsbounds && !avoided && (CurrentAttack.Mode == Attack.AttackMode.Ranged && dist < CurrentAttack.Range * 0.15f)) { FailTimer.Reset(); foreach (Act.Status stat in AvoidTarget(CurrentAttack.Range, 3.0f)) { yield return(Status.Running); } avoided = true; } // Else, stop and attack else if ((DefensiveStructure == null && dist < CurrentAttack.Range) || (DefensiveStructure != null && dist < CurrentAttack.Range * 2.0)) { if (CurrentAttack.Mode == Attack.AttackMode.Ranged && VoxelHelpers.DoesRayHitSolidVoxel(Creature.World.ChunkManager.ChunkData, Creature.AI.Position, Target.Position)) { yield return(Status.Fail); yield break; } FailTimer.Reset(); avoided = false; Creature.Physics.Orientation = Physics.OrientMode.Fixed; Creature.Physics.Velocity = new Vector3(Creature.Physics.Velocity.X * 0.9f, Creature.Physics.Velocity.Y, Creature.Physics.Velocity.Z * 0.9f); CurrentAttack.RechargeTimer.Reset(CurrentAttack.RechargeRate); Creature.Sprite.ResetAnimations(Creature.AttackMode); Creature.Sprite.PlayAnimations(Creature.AttackMode); Creature.CurrentCharacterMode = Creature.AttackMode; Creature.OverrideCharacterMode = true; Timer timeout = new Timer(10.0f, true); while (!CurrentAttack.Perform(Creature, Target, DwarfTime.LastTime, Creature.Stats.BuffedStr + Creature.Stats.BuffedSiz, Creature.AI.Position, Creature.Faction.Name)) { timeout.Update(DwarfTime.LastTime); if (timeout.HasTriggered) { break; } Creature.Physics.Velocity = new Vector3(Creature.Physics.Velocity.X * 0.9f, Creature.Physics.Velocity.Y, Creature.Physics.Velocity.Z * 0.9f); if (Creature.AI.Movement.CanFly) { Creature.Physics.ApplyForce(-Creature.Physics.Gravity * 0.1f, DwarfTime.Dt); } yield return(Status.Running); } timeout.Reset(); while (!Agent.Creature.Sprite.AnimPlayer.IsDone()) { timeout.Update(DwarfTime.LastTime); if (timeout.HasTriggered) { break; } if (Creature.AI.Movement.CanFly) { Creature.Physics.ApplyForce(-Creature.Physics.Gravity * 0.1f, DwarfTime.Dt); } yield return(Status.Running); } var targetCreature = Target.GetRoot().GetComponent <CreatureAI>(); if (targetCreature != null && !Creature.AI.FightOrFlight(targetCreature)) { yield return(Act.Status.Fail); yield break; } Creature.CurrentCharacterMode = CharacterMode.Attacking; Vector3 dogfightTarget = Vector3.Zero; while (!CurrentAttack.RechargeTimer.HasTriggered && !Target.IsDead) { CurrentAttack.RechargeTimer.Update(DwarfTime.LastTime); if (CurrentAttack.Mode == Attack.AttackMode.Dogfight) { dogfightTarget += MathFunctions.RandVector3Cube() * 0.1f; Vector3 output = Creature.Controller.GetOutput(DwarfTime.Dt, dogfightTarget + Target.Position, Creature.Physics.GlobalTransform.Translation) * 0.9f; Creature.Physics.ApplyForce(output - Creature.Physics.Gravity, DwarfTime.Dt); } else { Creature.Physics.Velocity = Vector3.Zero; if (Creature.AI.Movement.CanFly) { Creature.Physics.ApplyForce(-Creature.Physics.Gravity, DwarfTime.Dt); } } yield return(Status.Running); } Creature.CurrentCharacterMode = defaultCharachterMode; Creature.Physics.Orientation = Physics.OrientMode.RotateY; if (Target.IsDead) { Target = null; Agent.AddXP(10); Creature.Physics.Face(Creature.Physics.Velocity + Creature.Physics.GlobalTransform.Translation); Creature.Stats.NumThingsKilled++; Creature.AddThought(Thought.ThoughtType.KilledThing); Creature.Physics.Orientation = Physics.OrientMode.RotateY; Creature.OverrideCharacterMode = false; Creature.CurrentCharacterMode = defaultCharachterMode; yield return(Status.Success); break; } } yield return(Status.Running); } }
private void DiscreteUpdate(ChunkManager ChunkManager, VoxelChunk chunk) { for (var y = 0; y < VoxelConstants.ChunkSizeY; ++y) { // Apply 'liquid present' tracking in voxel data to skip entire slices. if (chunk.Data.LiquidPresent[y] == 0) { continue; } var layerOrder = SlicePermutations[MathFunctions.RandInt(0, SlicePermutations.Length)]; for (var i = 0; i < layerOrder.Length; ++i) { var x = layerOrder[i] % VoxelConstants.ChunkSizeX; var z = (layerOrder[i] >> VoxelConstants.XDivShift) % VoxelConstants.ChunkSizeZ; var currentVoxel = VoxelHandle.UnsafeCreateLocalHandle(chunk, new LocalVoxelCoordinate(x, y, z)); if (currentVoxel.TypeID != 0) { continue; } if (currentVoxel.LiquidType == LiquidType.None || currentVoxel.LiquidLevel < 1) { continue; } // Evaporate. if (currentVoxel.LiquidLevel <= EvaporationLevel && MathFunctions.RandEvent(0.01f)) { if (currentVoxel.LiquidType == LiquidType.Lava && Library.GetVoxelType("Stone").HasValue(out VoxelType stone)) { currentVoxel.Type = stone; } NeedsMinimapUpdate = true; currentVoxel.QuickSetLiquid(LiquidType.None, 0); continue; } var voxBelow = ChunkManager.CreateVoxelHandle(new GlobalVoxelCoordinate(currentVoxel.Coordinate.X, currentVoxel.Coordinate.Y - 1, currentVoxel.Coordinate.Z)); if (voxBelow.IsValid && voxBelow.IsEmpty) { // Fall into the voxel below. // Special case: No liquid below, just drop down. if (voxBelow.LiquidType == LiquidType.None) { NeedsMinimapUpdate = true; CreateSplash(currentVoxel.Coordinate.ToVector3(), currentVoxel.LiquidType); voxBelow.QuickSetLiquid(currentVoxel.LiquidType, currentVoxel.LiquidLevel); currentVoxel.QuickSetLiquid(LiquidType.None, 0); continue; } var belowType = voxBelow.LiquidType; var aboveType = currentVoxel.LiquidType; var spaceLeftBelow = maxWaterLevel - voxBelow.LiquidLevel; if (spaceLeftBelow >= currentVoxel.LiquidLevel) { NeedsMinimapUpdate = true; CreateSplash(currentVoxel.Coordinate.ToVector3(), aboveType); voxBelow.LiquidLevel += currentVoxel.LiquidLevel; currentVoxel.QuickSetLiquid(LiquidType.None, 0); HandleLiquidInteraction(voxBelow, aboveType, belowType); continue; } if (spaceLeftBelow > 0) { NeedsMinimapUpdate = true; CreateSplash(currentVoxel.Coordinate.ToVector3(), aboveType); currentVoxel.LiquidLevel = (byte)(currentVoxel.LiquidLevel - maxWaterLevel + voxBelow.LiquidLevel); voxBelow.LiquidLevel = maxWaterLevel; HandleLiquidInteraction(voxBelow, aboveType, belowType); continue; } } else if (voxBelow.IsValid && currentVoxel.LiquidType == LiquidType.Lava && !voxBelow.IsEmpty && voxBelow.GrassType > 0) { voxBelow.GrassType = 0; } if (currentVoxel.LiquidLevel <= 1) { continue; } // Nothing left to do but spread. RollArray(NeighborPermutations[MathFunctions.RandInt(0, NeighborPermutations.Length)], NeighborScratch, MathFunctions.RandInt(0, 4)); for (var n = 0; n < NeighborScratch.Length; ++n) { var neighborOffset = VoxelHelpers.ManhattanNeighbors2D[NeighborScratch[n]]; var neighborVoxel = new VoxelHandle(Chunks, currentVoxel.Coordinate + neighborOffset); if (neighborVoxel.IsValid && neighborVoxel.IsEmpty) { if (neighborVoxel.LiquidLevel < currentVoxel.LiquidLevel) { NeedsMinimapUpdate = true; var amountToMove = (int)(currentVoxel.LiquidLevel * GetSpreadRate(currentVoxel.LiquidType)); if (neighborVoxel.LiquidLevel + amountToMove > maxWaterLevel) { amountToMove = maxWaterLevel - neighborVoxel.LiquidLevel; } if (amountToMove > 2) { CreateSplash(neighborVoxel.Coordinate.ToVector3(), currentVoxel.LiquidType); } var newWater = currentVoxel.LiquidLevel - amountToMove; var sourceType = currentVoxel.LiquidType; var destType = neighborVoxel.LiquidType; currentVoxel.QuickSetLiquid(newWater == 0 ? LiquidType.None : sourceType, (byte)newWater); neighborVoxel.QuickSetLiquid(destType == LiquidType.None ? sourceType : destType, (byte)(neighborVoxel.LiquidLevel + amountToMove)); HandleLiquidInteraction(neighborVoxel, sourceType, destType); break; } } } } } }
public void GenerateVegetation(VoxelChunk chunk, ComponentManager components, ContentManager content, GraphicsDevice graphics) { int waterHeight = (int)(SeaLevel * chunk.SizeY); bool updated = false; Voxel v = chunk.MakeVoxel(0, 0, 0); Voxel vUnder = chunk.MakeVoxel(0, 0, 0); for (int x = 0; x < chunk.SizeX; x++) { for (int z = 0; z < chunk.SizeZ; z++) { Vector2 vec = new Vector2(x + chunk.Origin.X, z + chunk.Origin.Z) / PlayState.WorldScale; Overworld.Biome biome = Overworld.Map[(int)MathFunctions.Clamp(vec.X, 0, Overworld.Map.GetLength(0) - 1), (int)MathFunctions.Clamp(vec.Y, 0, Overworld.Map.GetLength(1) - 1)].Biome; BiomeData biomeData = BiomeLibrary.Biomes[biome]; int y = chunk.GetFilledVoxelGridHeightAt(x, chunk.SizeY - 1, z); if (!chunk.IsCellValid(x, (int)(y - chunk.Origin.Y), z)) { continue; } v.GridPosition = new Vector3(x, y, z); if (!v.IsEmpty || chunk.Data.Water[v.Index].WaterLevel != 0 || y <= waterHeight) { continue; } foreach (VegetationData veg in biomeData.Vegetation) { if (y <= 0) { continue; } if (!MathFunctions.RandEvent(veg.SpawnProbability)) { continue; } if (NoiseGenerator.Noise(vec.X / veg.ClumpSize, veg.NoiseOffset, vec.Y / veg.ClumpSize) < veg.ClumpThreshold) { continue; } int yh = chunk.GetFilledVoxelGridHeightAt(x, y, z); if (yh > 0) { vUnder.GridPosition = new Vector3(x, yh - 1, z); if (!vUnder.IsEmpty && vUnder.TypeName == biomeData.GrassVoxel) { vUnder.Type = VoxelLibrary.GetVoxelType(biomeData.SoilVoxel); updated = true; float offset = veg.VerticalOffset; if (vUnder.RampType != RampType.None) { offset -= 0.25f; } float treeSize = MathFunctions.Rand() * veg.SizeVariance + veg.MeanSize; EntityFactory.CreateEntity <Body>(veg.Name, chunk.Origin + new Vector3(x, y, z) + new Vector3(0, treeSize * offset, 0), Blackboard.Create("Scale", treeSize)); } } break; } } } if (updated) { chunk.ShouldRebuild = true; } }
public override void OnVoxelsSelected(List <VoxelHandle> refs, InputManager.MouseButton button) { if (Command.Contains("Build/")) { string type = Command.Substring(6); var room = RoomLibrary.CreateRoom(Player.Faction, type, Player.World); Player.Faction.RoomBuilder.DesignatedRooms.Add(room); RoomLibrary.CompleteRoomImmediately(room, refs); } if (Command.Contains("Spawn/")) { string type = Command.Substring(6); foreach (var vox in refs.Where(vox => vox.IsValid)) { if (vox.IsEmpty) { var craftItem = CraftLibrary.GetCraftable(type); var offset = Vector3.Zero; if (craftItem != null) { offset = craftItem.SpawnOffset; } var body = EntityFactory.CreateEntity <Body>(type, vox.WorldPosition + new Vector3(0.5f, 0.0f, 0.5f) + offset); if (body != null) { body.PropogateTransforms(); if (craftItem != null) { if (craftItem.AddToOwnedPool) { Player.Faction.OwnedObjects.Add(body); } if (craftItem.Moveable) { body.Tags.Add("Moveable"); } if (craftItem.Deconstructable) { body.Tags.Add("Deconstructable"); } } } } } } else if (Command.Contains("Rail/")) { string type = Command.Substring("Rail/".Length); var junction = new Rail.JunctionPiece { RailPiece = type, Orientation = Rail.PieceOrientation.North, Offset = Point.Zero }; foreach (var vox in refs.Where(vox => vox.IsValid)) { if (vox.IsEmpty) { var entity = new Rail.RailEntity(Player.World.ComponentManager, vox, junction); Player.World.ComponentManager.RootComponent.AddChild(entity); } } } else if (Command.Contains("Grass/")) { var type = GrassLibrary.GetGrassType(Command.Substring(6)); foreach (var vox in refs.Where(v => v.IsValid)) { var v = vox; if (!vox.IsEmpty) { v.GrassType = type.ID; v.GrassDecay = type.InitialDecayValue; } } } //else if (Command.Contains("Decal/")) //{ // var type = DecalLibrary.GetGrassType(Command.Substring(6)); // foreach (var vox in refs.Where(v => v.IsValid)) // { // var v = vox; // if (!vox.IsEmpty) // v.Decal = DecalType.EncodeDecal(DecalOrientation, type.ID); // } //} else { foreach (var vox in refs.Where(vox => vox.IsValid)) { if (Command.Contains("Place/")) { string type = Command.Substring(6); var v = vox; v.Type = VoxelLibrary.GetVoxelType(type); v.QuickSetLiquid(LiquidType.None, 0); if (type == "Magic") { Player.World.ComponentManager.RootComponent.AddChild( new DestroyOnTimer(Player.World.ComponentManager, Player.World.ChunkManager, vox) { DestroyTimer = new Timer(5.0f + MathFunctions.Rand(-0.5f, 0.5f), true) }); } } else { switch (Command) { case "Delete Block": { var v = vox; Player.World.Master.Faction.OnVoxelDestroyed(vox); v.Type = VoxelLibrary.emptyType; v.QuickSetLiquid(LiquidType.None, 0); } break; case "Kill Block": foreach (var selected in refs) { if (!selected.IsEmpty) { Player.World.ChunkManager.KillVoxel(selected); } } break; case "Fill Water": { if (vox.IsEmpty) { var v = vox; v.QuickSetLiquid(LiquidType.Water, WaterManager.maxWaterLevel); } } break; case "Fill Lava": { if (vox.IsEmpty) { var v = vox; v.QuickSetLiquid(LiquidType.Lava, WaterManager.maxWaterLevel); } } break; case "Fire": { foreach (var flam2 in Player.World.EnumerateIntersectingObjects(vox.GetBoundingBox(), CollisionType.Both).OfType <Flammable>()) { flam2.Heat = flam2.Flashpoint + 1; } } break; case "Kill Things": { foreach (var comp in Player.World.EnumerateIntersectingObjects(vox.GetBoundingBox(), CollisionType.Both)) { comp.Die(); } } break; case "Disease": { foreach (var creature in Player.World.EnumerateIntersectingObjects(vox.GetBoundingBox(), CollisionType.Both).OfType <Creature>()) { var disease = Datastructures.SelectRandom(DiseaseLibrary.Diseases); creature.AcquireDisease(disease.Name); } break; } default: break; } } } } }
public void CreateMigration() { int tries = 0; float padding = 2.0f; while (tries < 10) { int side = MathFunctions.Random.Next(4); BoundingBox bounds = World.ChunkManager.Bounds; Vector3 pos = Vector3.Zero; switch (side) { case 0: pos = new Vector3(bounds.Min.X + padding, bounds.Max.Y - padding, MathFunctions.Rand(bounds.Min.Z + padding, bounds.Max.Z - padding)); break; case 1: pos = new Vector3(bounds.Max.X - padding, bounds.Max.Y - padding, MathFunctions.Rand(bounds.Min.Z + padding, bounds.Max.Z - padding)); break; case 2: pos = new Vector3(MathFunctions.Rand(bounds.Min.X + padding, bounds.Max.X - padding), bounds.Max.Y - padding, bounds.Min.Z + padding); break; case 3: pos = new Vector3(MathFunctions.Rand(bounds.Min.X + padding, bounds.Max.X - padding), bounds.Max.Y - padding, bounds.Max.Z - padding); break; } var biome = World.Overworld.Map.GetBiomeAt(pos, World.Overworld.InstanceSettings.Origin); if (biome.Fauna.Count == 0) { tries++; continue; } var randomFauna = Datastructures.SelectRandom(biome.Fauna); var testCreature = EntityFactory.CreateEntity <GameComponent>(randomFauna.Name, Vector3.Zero); if (testCreature == null) { tries++; continue; } var testCreatureAI = testCreature.GetRoot().GetComponent <CreatureAI>(); if (testCreatureAI == null || testCreatureAI.Movement.IsSessile) { testCreature.GetRoot().Delete(); tries++; continue; } var count = World.GetSpeciesPopulation(testCreatureAI.Stats.CurrentClass); testCreature.GetRoot().Delete(); if (count < 30) { var randomNum = Math.Min(MathFunctions.RandInt(1, 3), 30 - count); for (int i = 0; i < randomNum; i++) { var randompos = MathFunctions.Clamp(pos + MathFunctions.RandVector3Cube() * 2, World.ChunkManager.Bounds); var vox = VoxelHelpers.FindFirstVoxelBelow(new VoxelHandle(World.ChunkManager, GlobalVoxelCoordinate.FromVector3(pos))); if (!vox.IsValid) { continue; } EntityFactory.CreateEntity <GameComponent>(randomFauna.Name, vox.GetBoundingBox().Center() + Vector3.Up * 1.5f); } } break; } }
public override void Construct() { var bottomBar = AddChild(new Widget() { AutoLayout = AutoLayout.DockBottom, MinimumSize = new Point(Rect.Width - 128, 24) }) ; bottomBar.AddChild(new Button() { Text = "Back", OnClick = (sender, args) => this.Close(), AutoLayout = AutoLayout.DockLeft, MinimumSize = new Point(64, 24) }); if (SoundManager.Mixer == null) { Text = "Error. Failed to load audio mixer :("; return; } bottomBar.AddChild(new Button() { Text = "Save", OnClick = (sender, args) => FileUtils.SaveBasicJson(SoundManager.Mixer, ContentPaths.mixer), AutoLayout = AutoLayout.DockRight, MinimumSize = new Point(64, 24) }); var listView = AddChild(new WidgetListView() { AutoLayout = AutoLayout.DockBottom, MinimumSize = new Point(Rect.Width - 128, 512), ItemHeight = 24 }); foreach (var level in SoundManager.Mixer.Gains) { var row = listView.AddChild(new Widget() { AutoLayout = AutoLayout.DockTop, MinimumSize = new Point(512, 24) }); row.AddChild(new Widget() { Text = level.Key, TextColor = Color.Black.ToVector4(), AutoLayout = AutoLayout.DockLeft, TextVerticalAlign = VerticalAlign.Center, TextHorizontalAlign = HorizontalAlign.Right, MinimumSize = new Point(256, 24) }); KeyValuePair <string, SFXMixer.Levels> level1 = level; row.AddChild(new HorizontalFloatSlider() { ScrollArea = 1.0f, ScrollPosition = level.Value.Volume, MinimumSize = new Point(256, 24), AutoLayout = AutoLayout.DockLeft, OnSliderChanged = (sender) => { SFXMixer.Levels levels = SoundManager.Mixer.GetOrCreateLevels(level1.Key); SoundManager.Mixer.SetLevels(level1.Key, new SFXMixer.Levels() { RandomPitch = level1.Value.RandomPitch, Volume = (sender as HorizontalFloatSlider).ScrollPosition }); if (MathFunctions.RandEvent(0.15f)) { SoundManager.PlaySound(level1.Key); } } }); } Layout(); base.Construct(); }
public bool PerformNoDamage(Creature performer, DwarfTime time, Vector3 pos) { switch (TriggerMode) { case AttackTrigger.Timer: RechargeTimer.Update(time); if (!RechargeTimer.HasTriggered) { HasTriggered = false; return(false); } break; case AttackTrigger.Animation: if (!performer.Sprite.AnimPlayer.HasValidAnimation() || performer.Sprite.AnimPlayer.CurrentFrame != TriggerFrame) { HasTriggered = false; return(false); } break; } if (Mode == AttackMode.Melee) { if (HitParticles != "") { performer.Manager.World.ParticleManager.Trigger(HitParticles, pos, Color.White, 5); } if (HitAnimation != null && !HasTriggered) { IndicatorManager.DrawIndicator(HitAnimation, pos, 10.0f, 1.0f, MathFunctions.RandVector2Circle(), Color.White, MathFunctions.Rand() > 0.5f); PlayNoise(pos); } } HasTriggered = true; return(true); }
public Point3 GetChunkID(Vector3 origin) { origin = RoundToChunkCoords(origin); return(new Point3(MathFunctions.FloorInt(origin.X), MathFunctions.FloorInt(origin.Y), MathFunctions.FloorInt(origin.Z))); }
public bool Perform(Creature performer, Body other, DwarfTime time, float bonus, Vector3 pos, string faction) { switch (TriggerMode) { case AttackTrigger.Timer: RechargeTimer.Update(time); if (!RechargeTimer.HasTriggered) { HasTriggered = false; return(false); } break; case AttackTrigger.Animation: if (!performer.Sprite.AnimPlayer.HasValidAnimation() || performer.Sprite.AnimPlayer.CurrentFrame != TriggerFrame) { HasTriggered = false; return(false); } break; } if (HasTriggered) { return(true); } HasTriggered = true; switch (Mode) { case AttackMode.Melee: case AttackMode.Dogfight: { DoDamage(performer, other, bonus); break; } case AttackMode.Area: { BoundingBox box = new BoundingBox(performer.AI.Position - Vector3.One * Range, performer.AI.Position + Vector3.One * Range); foreach (var body in performer.World.EnumerateIntersectingObjects(box, CollisionType.Both)) { var creature = body.GetRoot().GetComponent <CreatureAI>(); if (creature == null) { var health = body.GetRoot().GetComponent <Health>(); if (health != null) { DoDamage(performer, body, bonus); } continue; } if (creature.Faction == performer.Faction) { continue; } var alliance = performer.World.Diplomacy.GetPolitics(creature.Faction, performer.Faction).GetCurrentRelationship() != Relationship.Hateful; if (alliance) { continue; } DoDamage(performer, body, bonus); } break; } case AttackMode.Ranged: { PlayNoise(other.GlobalTransform.Translation); LaunchProjectile(pos, other.Position, other); var injury = DiseaseLibrary.GetRandomInjury(); if (MathFunctions.RandEvent(injury.LikelihoodOfSpread)) { var creature = other.GetRoot().GetComponent <Creature>(); if (creature != null) { creature.AcquireDisease(injury.Name); } } break; } } return(true); }
public bool PerformNoDamage(Creature performer, DwarfTime time, Vector3 pos) { if (!performer.Sprite.AnimPlayer.HasValidAnimation() || performer.Sprite.AnimPlayer.CurrentFrame != Weapon.TriggerFrame) { HasTriggered = false; return(false); } if (Weapon.Mode == Weapon.AttackMode.Melee) { if (Weapon.HitParticles != "") { performer.Manager.World.ParticleManager.Trigger(Weapon.HitParticles, pos, Color.White, 5); } if (Weapon.HitAnimation != null && !HasTriggered) { IndicatorManager.DrawIndicator(Weapon.HitAnimation, pos, 10.0f, 1.0f, MathFunctions.RandVector2Circle(), Color.White, MathFunctions.Rand() > 0.5f); PlayNoise(pos); } } HasTriggered = true; return(true); }