public float?GetSurfaceHeight(int x, int y, int z, out FluidBlock surfaceFluidBlock) { if (y >= 0 && y < 255) { TerrainChunk chunkAtCell = base.SubsystemTerrain.Terrain.GetChunkAtCell(x, z); if (chunkAtCell != null) { int num = TerrainChunk.CalculateCellIndex(x & 0xF, 0, z & 0xF); while (y < 255) { int num2 = Terrain.ExtractContents(chunkAtCell.GetCellValueFast(num + y + 1)); if (BlocksManager.FluidBlocks[num2] == null) { int cellValueFast = chunkAtCell.GetCellValueFast(num + y); int num3 = Terrain.ExtractContents(cellValueFast); FluidBlock fluidBlock = BlocksManager.FluidBlocks[num3]; if (fluidBlock != null) { surfaceFluidBlock = fluidBlock; int level = FluidBlock.GetLevel(Terrain.ExtractData(cellValueFast)); return((float)y + surfaceFluidBlock.GetLevelHeight(level)); } surfaceFluidBlock = null; return(null); } y++; } } } surfaceFluidBlock = null; return(null); }
public void AddSplash(int value, Vector3 position, Vector2 size, Color color, int textureSlot) { for (int i = 0; i < base.Particles.Length; i++) { Particle particle = base.Particles[i]; if (!particle.IsActive) { Block block = BlocksManager.Blocks[Terrain.ExtractContents(value)]; particle.IsActive = true; particle.Position = position; particle.BaseColor = color; particle.BillboardingMode = ParticleBillboardingMode.Horizontal; particle.Size = size; particle.TextureSlot = textureSlot; if (block is WaterBlock) { ((WaterBlock)block).GetLevelHeight(FluidBlock.GetLevel(Terrain.ExtractData(value))); particle.TimeToLive = m_random.Float(0.2f, 0.3f); particle.FadeFactor = 1f; } else if (block.IsCollidable || block is SnowBlock) { particle.TimeToLive = m_random.Float(0.8f, 1.2f); particle.FadeFactor = 1f; } break; } } m_isActive = true; }
public float?CalculateDistanceToFluid(Vector3 p, int radius, bool flowingFluidOnly) { float num = float.MaxValue; Terrain terrain = base.SubsystemTerrain.Terrain; int num2 = Terrain.ToCell(p.X) - radius; int num3 = Terrain.ToCell(p.X) + radius; int num4 = MathUtils.Clamp(Terrain.ToCell(p.Y) - radius, 0, 254); int num5 = MathUtils.Clamp(Terrain.ToCell(p.Y) + radius, 0, 254); int num6 = Terrain.ToCell(p.Z) - radius; int num7 = Terrain.ToCell(p.Z) + radius; for (int i = num6; i <= num7; i++) { for (int j = num2; j <= num3; j++) { TerrainChunk chunkAtCell = terrain.GetChunkAtCell(j, i); if (chunkAtCell == null) { continue; } int k = TerrainChunk.CalculateCellIndex(j & 0xF, num4, i & 0xF); for (int l = num4; l <= num5; l++, k++) { int cellValueFast = chunkAtCell.GetCellValueFast(k); int contents = Terrain.ExtractContents(cellValueFast); if (!m_fluidBlock.IsTheSameFluid(contents)) { continue; } if (flowingFluidOnly) { if (FluidBlock.GetLevel(Terrain.ExtractData(cellValueFast)) == 0) { continue; } int contents2 = Terrain.ExtractContents(chunkAtCell.GetCellValueFast(k + 1)); if (m_fluidBlock.IsTheSameFluid(contents2)) { continue; } } float num8 = p.X - ((float)j + 0.5f); float num9 = p.Y - ((float)l + 1f); float num10 = p.Z - ((float)i + 0.5f); float num11 = num8 * num8 + num9 * num9 + num10 * num10; if (num11 < num) { num = num11; } } } } if (num == float.MaxValue) { return(null); } return(MathUtils.Sqrt(num)); }
public override bool Simulate(float dt) { dt = MathUtils.Clamp(dt, 0f, 0.1f); float num = MathUtils.Pow(0.015f, dt); m_time += dt; bool flag = false; for (int i = 0; i < base.Particles.Length; i++) { Particle particle = base.Particles[i]; if (!particle.IsActive) { continue; } flag = true; particle.Position += particle.Velocity * dt; particle.Velocity.Y += -10f * dt; particle.Velocity *= num; particle.Color *= MathUtils.Saturate(particle.TimeToLive); particle.TimeToLive -= dt; particle.TextureSlot = (int)(3.99f * particle.TimeToLive / particle.Duration); particle.FlipX = (m_random.Sign() > 0); particle.FlipY = (m_random.Sign() > 0); if (particle.TimeToLive <= 0f || particle.Size.X <= 0f) { particle.IsActive = false; continue; } int cellValue = m_subsystemTerrain.Terrain.GetCellValue(Terrain.ToCell(particle.Position.X), Terrain.ToCell(particle.Position.Y), Terrain.ToCell(particle.Position.Z)); int num2 = Terrain.ExtractContents(cellValue); if (num2 == 0) { continue; } Block block = BlocksManager.Blocks[num2]; if (block.IsCollidable) { particle.IsActive = true; } else if (block is MagmaBlock) { int level = FluidBlock.GetLevel(Terrain.ExtractData(cellValue)); float levelHeight = ((MagmaBlock)block).GetLevelHeight(level); if (particle.Position.Y <= MathUtils.Floor(particle.Position.Y) + levelHeight) { particle.Velocity.Y = 0f; float num3 = Vector2.Distance(new Vector2(particle.Position.X, particle.Position.Z), new Vector2(m_position.X, m_position.Z)); float num4 = 0.02f * MathUtils.Sin(2f * num3 + 10f * m_time); particle.Position.Y = MathUtils.Floor(particle.Position.Y) + levelHeight + num4; particle.TimeToLive -= 1f * dt; particle.Size -= new Vector2(0.04f * dt); } } } return(!flag); }
public static bool IsValueDisallowed(int value) { int num = Terrain.ExtractContents(value); int data = Terrain.ExtractData(value); if ((num == 18 || num == 92) && FluidBlock.GetLevel(data) != 0 && FluidBlock.GetIsTop(data)) { return(true); } return(false); }
public Vector2?CalculateFlowSpeed(int x, int y, int z, out FluidBlock surfaceBlock, out float?surfaceHeight) { surfaceHeight = GetSurfaceHeight(x, y, z, out surfaceBlock); if (surfaceHeight.HasValue) { y = (int)surfaceHeight.Value; int cellValue = base.SubsystemTerrain.Terrain.GetCellValue(x, y, z); int num = Terrain.ExtractContents(cellValue); if (BlocksManager.Blocks[num] is FluidBlock) { int cellValue2 = base.SubsystemTerrain.Terrain.GetCellValue(x - 1, y, z); int cellValue3 = base.SubsystemTerrain.Terrain.GetCellValue(x + 1, y, z); int cellValue4 = base.SubsystemTerrain.Terrain.GetCellValue(x, y, z - 1); int cellValue5 = base.SubsystemTerrain.Terrain.GetCellValue(x, y, z + 1); int num2 = Terrain.ExtractContents(cellValue2); int num3 = Terrain.ExtractContents(cellValue3); int num4 = Terrain.ExtractContents(cellValue4); int num5 = Terrain.ExtractContents(cellValue5); int level = FluidBlock.GetLevel(Terrain.ExtractData(cellValue)); int num6 = (num2 == num) ? FluidBlock.GetLevel(Terrain.ExtractData(cellValue2)) : level; int num7 = (num3 == num) ? FluidBlock.GetLevel(Terrain.ExtractData(cellValue3)) : level; int num8 = (num4 == num) ? FluidBlock.GetLevel(Terrain.ExtractData(cellValue4)) : level; int num9 = (num5 == num) ? FluidBlock.GetLevel(Terrain.ExtractData(cellValue5)) : level; Vector2 vector = default(Vector2); vector.X = MathUtils.Sign(level - num6) - MathUtils.Sign(level - num7); vector.Y = MathUtils.Sign(level - num8) - MathUtils.Sign(level - num9); Vector2 v = vector; if (v.LengthSquared() > 1f) { v = Vector2.Normalize(v); } if (!m_fluidRandomFlowDirections.TryGetValue(new Point3(x, y, z), out Vector2 value)) { value.X = 0.05f * (2f * SimplexNoise.OctavedNoise((float)x + 0.2f * (float)SubsystemTime.GameTime, z, 0.1f, 1, 1f, 1f) - 1f); value.Y = 0.05f * (2f * SimplexNoise.OctavedNoise((float)x + 0.2f * (float)SubsystemTime.GameTime + 100f, z, 0.1f, 1, 1f, 1f) - 1f); if (m_fluidRandomFlowDirections.Count < 1000) { m_fluidRandomFlowDirections[new Point3(x, y, z)] = value; } else { m_fluidRandomFlowDirections.Clear(); } } v += value; return(v * 2f); } } return(null); }
public int LevelAtNearestFall(int x, int y, int z, int level, Dictionary <Point3, int> levels) { if (level > m_fluidBlock.MaxLevel) { return(int.MaxValue); } if (!levels.TryGetValue(new Point3(x, y, z), out int value)) { value = int.MaxValue; } if (level >= value) { return(int.MaxValue); } levels[new Point3(x, y, z)] = level; int cellValue = base.SubsystemTerrain.Terrain.GetCellValue(x, y, z); int num = Terrain.ExtractContents(cellValue); if (m_fluidBlock.IsTheSameFluid(num)) { if (FluidBlock.GetLevel(Terrain.ExtractData(cellValue)) < level) { return(int.MaxValue); } } else if (BlocksManager.Blocks[num].IsFluidBlocker) { return(int.MaxValue); } int num2 = Terrain.ExtractContents(base.SubsystemTerrain.Terrain.GetCellValue(x, y - 1, z)); Block block = BlocksManager.Blocks[num2]; if (m_fluidBlock.IsTheSameFluid(num2) || !block.IsFluidBlocker) { return(level); } int x2 = LevelAtNearestFall(x - 1, y, z, level + 1, levels); int x3 = LevelAtNearestFall(x + 1, y, z, level + 1, levels); int x4 = LevelAtNearestFall(x, y, z - 1, level + 1, levels); int x5 = LevelAtNearestFall(x, y, z + 1, level + 1, levels); return(MathUtils.Min(x2, x3, x4, x5)); }
public void FlowTo(int x, int y, int z, int level) { if (level > m_fluidBlock.MaxLevel) { return; } int cellValue = base.SubsystemTerrain.Terrain.GetCellValue(x, y, z); int contents = Terrain.ExtractContents(cellValue); int data = Terrain.ExtractData(cellValue); if (m_fluidBlock.IsTheSameFluid(contents)) { int level2 = FluidBlock.GetLevel(data); if (level < level2) { Set(x, y, z, Terrain.MakeBlockValue(contents, 0, FluidBlock.SetLevel(data, level))); } } else { OnFluidInteract(cellValue, x, y, z, Terrain.MakeBlockValue(m_fluidBlock.BlockIndex, 0, FluidBlock.SetLevel(0, level))); } }
public void SpreadFluid() { for (int i = 0; i < 2; i++) { foreach (Point3 key in m_toUpdate.Keys) { int x = key.X; int y = key.Y; int z = key.Z; int cellValue = base.SubsystemTerrain.Terrain.GetCellValue(x, y, z); int contents = Terrain.ExtractContents(cellValue); int data = Terrain.ExtractData(cellValue); int level = FluidBlock.GetLevel(data); if (m_fluidBlock.IsTheSameFluid(contents)) { int cellValue2 = base.SubsystemTerrain.Terrain.GetCellValue(x, y - 1, z); int contents2 = Terrain.ExtractContents(cellValue2); int data2 = Terrain.ExtractData(cellValue2); int level2 = FluidBlock.GetLevel(data2); int num = m_fluidBlock.MaxLevel + 1; int num2 = 0; for (int j = 0; j < 4; j++) { int cellValue3 = base.SubsystemTerrain.Terrain.GetCellValue(x + m_sideNeighbors[j].X, y, z + m_sideNeighbors[j].Y); int contents3 = Terrain.ExtractContents(cellValue3); if (m_fluidBlock.IsTheSameFluid(contents3)) { int level3 = FluidBlock.GetLevel(Terrain.ExtractData(cellValue3)); num = MathUtils.Min(num, level3); if (level3 == 0) { num2++; } } } if (level != 0 && level <= num) { int contents4 = Terrain.ExtractContents(base.SubsystemTerrain.Terrain.GetCellValue(x, y + 1, z)); if (!m_fluidBlock.IsTheSameFluid(contents4)) { if (num + 1 > m_fluidBlock.MaxLevel) { Set(x, y, z, 0); } else { Set(x, y, z, Terrain.MakeBlockValue(contents, 0, FluidBlock.SetLevel(data, num + 1))); } continue; } } if (m_generateSources && level != 0 && num2 >= 2) { Set(x, y, z, Terrain.MakeBlockValue(contents, 0, FluidBlock.SetLevel(data, 0))); } else if (m_fluidBlock.IsTheSameFluid(contents2)) { if (level2 > 1) { Set(x, y - 1, z, Terrain.MakeBlockValue(contents2, 0, FluidBlock.SetLevel(data2, 1))); } } else if (!OnFluidInteract(cellValue2, x, y - 1, z, Terrain.MakeBlockValue(m_fluidBlock.BlockIndex, 0, FluidBlock.SetLevel(0, 1))) && level < m_fluidBlock.MaxLevel) { m_visited.Clear(); int num3 = LevelAtNearestFall(x + 1, y, z, level + 1, m_visited); int num4 = LevelAtNearestFall(x - 1, y, z, level + 1, m_visited); int num5 = LevelAtNearestFall(x, y, z + 1, level + 1, m_visited); int num6 = LevelAtNearestFall(x, y, z - 1, level + 1, m_visited); int num7 = MathUtils.Min(num3, num4, num5, num6); if (num3 == num7) { FlowTo(x + 1, y, z, level + 1); FlowTo(x, y, z - 1, m_fluidBlock.MaxLevel); FlowTo(x, y, z + 1, m_fluidBlock.MaxLevel); } if (num4 == num7) { FlowTo(x - 1, y, z, level + 1); FlowTo(x, y, z - 1, m_fluidBlock.MaxLevel); FlowTo(x, y, z + 1, m_fluidBlock.MaxLevel); } if (num5 == num7) { FlowTo(x, y, z + 1, level + 1); FlowTo(x - 1, y, z, m_fluidBlock.MaxLevel); FlowTo(x + 1, y, z, m_fluidBlock.MaxLevel); } if (num6 == num7) { FlowTo(x, y, z - 1, level + 1); FlowTo(x - 1, y, z, m_fluidBlock.MaxLevel); FlowTo(x + 1, y, z, m_fluidBlock.MaxLevel); } } } } m_toUpdate.Clear(); foreach (KeyValuePair <Point3, int> item in m_toSet) { int x2 = item.Key.X; int y2 = item.Key.Y; int z2 = item.Key.Z; int value = item.Value; int contents5 = Terrain.ExtractContents(item.Value); int cellContents = base.SubsystemTerrain.Terrain.GetCellContents(x2, y2, z2); FluidBlock fluidBlock = BlocksManager.FluidBlocks[cellContents]; if (fluidBlock != null && !fluidBlock.IsTheSameFluid(contents5)) { base.SubsystemTerrain.DestroyCell(0, x2, y2, z2, value, noDrop: false, noParticleSystem: false); } else { base.SubsystemTerrain.ChangeCell(x2, y2, z2, value); } } m_toSet.Clear(); base.SubsystemTerrain.ProcessModifiedCells(); } }
protected new void Driller(Point3 point, int face) { Vector3 vector = Vector3.UnitY; int x = point.X; int y = point.Y; int z = point.Z; int num = ComponentEngine.IsPowered(Utils.Terrain, x, y, z) ? 1 : 0; if (num != 0) { int num2 = 0; int l; for (l = 4; 3 < l && l < 8; l++) { num2 += GetSlotCount(l); } int num3 = 0; int num4 = 0; for (int m = 0; m < 4; m++) { if (GetSlotCount(l) == 0) { num3 = 0; num4 = 1; break; } num4 += BlocksManager.Blocks[Terrain.ExtractContents(GetSlotValue(m))].MaxStacking; num3 += GetSlotCount(m); } int slotValue = base.GetSlotValue(8); if (num2 != 0 && num4 > num3 && slotValue != 0 && BlocksManager.Blocks[Terrain.ExtractContents(slotValue)].Durability > 0) { int[] array = new int[25] { 0, 0, 1, 1, 1, 0, -1, -1, -1, -1, 0, 1, 2, 2, 2, 2, 2, 1, 0, -1, -2, -2, -2, -2, -2 }; int[] array2 = new int[25] { 0, -1, -1, 0, 1, 1, 1, 0, -1, -2, -2, -2, -2, -1, 0, 1, 2, 2, 2, 2, 2, 1, 0, -1, -2 }; for (int n = 1; n < 8; n++) { for (int num5 = 0; num5 < 25; num5++) { x = point.X - (int)vector.X * n; y = point.Y - (int)vector.Y * n; z = point.Z - (int)vector.Z * n; x = point.X + array[num5]; z = point.Z + array2[num5]; //new Vector3((float)array[num5] / (float)n, 0f, (float)array2[num5] / (float)n); int cellValue = Utils.Terrain.GetCellValue(x, y, z); var block = Terrain.ExtractContents(cellValue); if (block == 92 || block == 18 || block == RottenMeatBlock.Index) { int num6; for (num6 = 4; 3 < num6 && num6 < 8 && GetSlotCount(num6) == 0; num6++) { } int num7 = 0; while (true) { if (num7 >= 4) { return; } if (GetSlotCount(num7) < BlocksManager.Blocks[Terrain.ExtractContents(GetSlotValue(num7))].MaxStacking || GetSlotCount(num7) == 0) { if (block == 92 && (Terrain.ExtractContents(GetSlotValue(num7)) == 93 || GetSlotCount(num7) == 0)) { if (FluidBlock.GetLevel(Terrain.ExtractData(cellValue)) == 0) { RemoveSlotItems(num6, 1); AddSlotItems(num7, 93, 1); RemoveSlotItems(8, 1); AddSlotItems(8, BlocksManager.DamageItem(slotValue, 1), 1); } Utils.SubsystemTerrain.ChangeCell(x, y, z, 0); return; } if (block == 18 && (Terrain.ExtractContents(GetSlotValue(num7)) == 91 || GetSlotCount(num7) == 0)) { if (FluidBlock.GetLevel(Terrain.ExtractData(cellValue)) == 0) { RemoveSlotItems(num6, 1); AddSlotItems(num7, 91, 1); } Utils.SubsystemTerrain.ChangeCell(x, y, z, 0); return; } if (Terrain.ReplaceLight(cellValue, 0) == (RottenMeatBlock.Index | 1 << 4 << 14) && (Terrain.ReplaceLight(GetSlotValue(num7), 0) == (RottenMeatBlock.Index | 2 << 4 << 14) || GetSlotCount(num7) == 0)) { RemoveSlotItems(num6, 1); AddSlotItems(num7, RottenMeatBlock.Index | 2 << 4 << 14, 1); Utils.SubsystemTerrain.ChangeCell(x, y, z, 0); return; } } num7++; } } } } } } }
public override bool OnUse(Ray3 ray, ComponentMiner componentMiner) { IInventory inventory = componentMiner.Inventory; int activeBlockValue = componentMiner.ActiveBlockValue; int num = Terrain.ExtractContents(activeBlockValue); if (num == 90) { object obj = componentMiner.Raycast(ray, RaycastMode.Gathering); if (obj is TerrainRaycastResult) { CellFace cellFace = ((TerrainRaycastResult)obj).CellFace; int cellValue = base.SubsystemTerrain.Terrain.GetCellValue(cellFace.X, cellFace.Y, cellFace.Z); int num2 = Terrain.ExtractContents(cellValue); int data = Terrain.ExtractData(cellValue); Block block = BlocksManager.Blocks[num2]; if (block is WaterBlock && FluidBlock.GetLevel(data) == 0) { int value = Terrain.ReplaceContents(activeBlockValue, 91); inventory.RemoveSlotItems(inventory.ActiveSlotIndex, inventory.GetSlotCount(inventory.ActiveSlotIndex)); if (inventory.GetSlotCount(inventory.ActiveSlotIndex) == 0) { inventory.AddSlotItems(inventory.ActiveSlotIndex, value, 1); } base.SubsystemTerrain.DestroyCell(0, cellFace.X, cellFace.Y, cellFace.Z, 0, noDrop: false, noParticleSystem: false); return(true); } if (block is MagmaBlock && FluidBlock.GetLevel(data) == 0) { int value2 = Terrain.ReplaceContents(activeBlockValue, 93); inventory.RemoveSlotItems(inventory.ActiveSlotIndex, inventory.GetSlotCount(inventory.ActiveSlotIndex)); if (inventory.GetSlotCount(inventory.ActiveSlotIndex) == 0) { inventory.AddSlotItems(inventory.ActiveSlotIndex, value2, 1); } base.SubsystemTerrain.DestroyCell(0, cellFace.X, cellFace.Y, cellFace.Z, 0, noDrop: false, noParticleSystem: false); return(true); } } else if (obj is BodyRaycastResult) { ComponentUdder componentUdder = ((BodyRaycastResult)obj).ComponentBody.Entity.FindComponent <ComponentUdder>(); if (componentUdder != null && componentUdder.Milk(componentMiner)) { int value3 = Terrain.ReplaceContents(activeBlockValue, 110); inventory.RemoveSlotItems(inventory.ActiveSlotIndex, inventory.GetSlotCount(inventory.ActiveSlotIndex)); if (inventory.GetSlotCount(inventory.ActiveSlotIndex) == 0) { inventory.AddSlotItems(inventory.ActiveSlotIndex, value3, 1); } m_subsystemAudio.PlaySound("Audio/Milked", 1f, 0f, ray.Position, 2f, autoDelay: true); } return(true); } } if (num == 91) { TerrainRaycastResult?terrainRaycastResult = componentMiner.Raycast <TerrainRaycastResult>(ray, RaycastMode.Interaction); if (terrainRaycastResult.HasValue && componentMiner.Place(terrainRaycastResult.Value, Terrain.MakeBlockValue(18))) { inventory.RemoveSlotItems(inventory.ActiveSlotIndex, 1); if (inventory.GetSlotCount(inventory.ActiveSlotIndex) == 0) { int value4 = Terrain.ReplaceContents(activeBlockValue, 90); inventory.AddSlotItems(inventory.ActiveSlotIndex, value4, 1); } return(true); } } if (num == 93) { TerrainRaycastResult?terrainRaycastResult2 = componentMiner.Raycast <TerrainRaycastResult>(ray, RaycastMode.Interaction); if (terrainRaycastResult2.HasValue) { if (componentMiner.Place(terrainRaycastResult2.Value, Terrain.MakeBlockValue(92))) { inventory.RemoveSlotItems(inventory.ActiveSlotIndex, 1); if (inventory.GetSlotCount(inventory.ActiveSlotIndex) == 0) { int value5 = Terrain.ReplaceContents(activeBlockValue, 90); inventory.AddSlotItems(inventory.ActiveSlotIndex, value5, 1); } } return(true); } } switch (num) { case 110: case 245: return(true); case 251: case 252: return(true); case 128: case 129: { TerrainRaycastResult?terrainRaycastResult3 = componentMiner.Raycast <TerrainRaycastResult>(ray, RaycastMode.Digging); if (terrainRaycastResult3.HasValue) { CellFace cellFace2 = terrainRaycastResult3.Value.CellFace; int cellValue2 = base.SubsystemTerrain.Terrain.GetCellValue(cellFace2.X, cellFace2.Y, cellFace2.Z); int num3 = Terrain.ExtractContents(cellValue2); Block block2 = BlocksManager.Blocks[num3]; if (block2 is IPaintableBlock) { Vector3 normal = CellFace.FaceToVector3(terrainRaycastResult3.Value.CellFace.Face); Vector3 position = terrainRaycastResult3.Value.HitPoint(); int? num4 = (num == 128) ? null : new int?(PaintBucketBlock.GetColor(Terrain.ExtractData(activeBlockValue))); Color color = num4.HasValue ? SubsystemPalette.GetColor(base.SubsystemTerrain, num4) : new Color(128, 128, 128, 128); int value6 = ((IPaintableBlock)block2).Paint(base.SubsystemTerrain, cellValue2, num4); base.SubsystemTerrain.ChangeCell(cellFace2.X, cellFace2.Y, cellFace2.Z, value6); componentMiner.DamageActiveTool(1); m_subsystemAudio.PlayRandomSound("Audio/Paint", 0.4f, m_random.Float(-0.1f, 0.1f), componentMiner.ComponentCreature.ComponentBody.Position, 2f, autoDelay: true); m_subsystemParticles.AddParticleSystem(new PaintParticleSystem(base.SubsystemTerrain, position, normal, color)); } return(true); } break; } } return(false); }