public bool Activate(State state, bool checkPossibilities) { if (!this.EnableWallRun) { return(false); } Vector3 playerVelocity = this.LinearVelocity.Value; if (playerVelocity.Y < FallDamage.RollingDamageVelocity) { return(false); } if (this.IsSwimming) { if (state == State.Left || state == State.Right) { return(false); } } wallInstantiationTimer = 0.0f; // Prevent the player from repeatedly wall-running and wall-jumping ad infinitum. bool wallRunDelayPassed = main.TotalTime - this.lastWallRunEnded > wallRunDelay; bool wallRunJumpDelayPassed = main.TotalTime - this.LastWallJump > wallRunDelay; Matrix matrix = Matrix.CreateRotationY(this.Rotation); Vector3 forwardVector = -matrix.Forward; Vector3 wallVector; switch (state) { case State.Straight: wallVector = forwardVector; break; case State.Left: if (!this.EnableWallRunHorizontal) { return(false); } wallVector = -matrix.Left; break; case State.Right: if (!this.EnableWallRunHorizontal) { return(false); } wallVector = -matrix.Right; break; default: wallVector = Vector3.Zero; break; } Vector3 pos = this.Position + new Vector3(0, this.Height * -0.5f, 0); // Attempt to wall-run on an existing map bool addInitialVelocity = false; Voxel closestVoxel = null; Voxel.Coord closestCoord = default(Voxel.Coord); const int maxWallDistance = 4; int closestDistance = maxWallDistance; Direction closestDir = Direction.None; foreach (Voxel voxel in Voxel.ActivePhysicsVoxels) { Vector3 baseVelocity = voxel.LinearVelocity + Vector3.Cross(voxel.AngularVelocity, this.Position - voxel.Transform.Value.Translation); Vector3 v = Vector3.Normalize(playerVelocity - baseVelocity); v.Y = 0.0f; if (Vector3.Dot(forwardVector, v) < -0.3f) { continue; } Voxel.Coord coord = voxel.GetCoordinate(pos); Direction dir = voxel.GetRelativeDirection(wallVector); Direction up = voxel.GetRelativeDirection(Direction.PositiveY); Direction forwardDir = voxel.GetRelativeDirection(forwardVector); for (int i = 1; i < maxWallDistance; i++) { Voxel.Coord wallCoord = coord.Move(dir, i); if (voxel[coord.Move(dir, i - 1)] != Voxel.States.Empty || voxel[coord.Move(dir, i - 1).Move(up, 1)] != Voxel.States.Empty || voxel[coord.Move(dir, i - 1).Move(up, 2)] != Voxel.States.Empty || ((state == State.Left || state == State.Right) && (voxel[coord.Move(forwardDir).Move(dir, i - 1)] != Voxel.States.Empty || voxel[coord.Move(forwardDir).Move(dir, i - 1).Move(up, 1)] != Voxel.States.Empty || voxel[coord.Move(forwardDir).Move(dir, i - 1).Move(up, 2)] != Voxel.States.Empty))) { // Blocked break; } // Need at least two blocks to consider it a wall if (voxel[wallCoord].ID != 0 && voxel[wallCoord.Move(up)].ID != 0) { bool differentWall = voxel != this.LastWallRunMap.Value || dir != this.LastWallDirection.Value; if ((differentWall || wallRunJumpDelayPassed) && i < closestDistance) { closestVoxel = voxel; closestDistance = i; closestCoord = coord; closestDir = dir; addInitialVelocity = differentWall || wallRunDelayPassed; } } else if (checkPossibilities) { // Check block possibilities List <BlockPredictor.Possibility> mapBlockPossibilities = this.Predictor.GetPossibilities(voxel); if (mapBlockPossibilities != null) { foreach (BlockPredictor.Possibility block in mapBlockPossibilities) { if (wallCoord.Between(block.StartCoord, block.EndCoord)) { this.Predictor.InstantiatePossibility(block); this.Predictor.ClearPossibilities(); closestVoxel = voxel; closestDistance = i; closestCoord = coord; closestDir = dir; addInitialVelocity = true; wallInstantiationTimer = 0.25f; break; } } } } } } if (closestVoxel != null) { if (!addInitialVelocity && Vector3.Dot(forwardVector, playerVelocity) < minWallRunSpeed) { return(false); } this.Position.Value = closestVoxel.GetAbsolutePosition(closestCoord.Move(closestDir, closestDistance - 2)) + new Vector3(0, this.Height * 0.5f, 0); this.setup(closestVoxel, closestDir, state, forwardVector, addInitialVelocity); return(true); } return(false); }
public static bool Go(Voxel voxel, Voxel.Coord center, int radius, Action <List <DynamicVoxel> > callback = null) { if (!voxel[center].Permanent) { // Break off a chunk of this voxel into a new DynamicMap. List <Voxel.Coord> edges = new List <Voxel.Coord>(); Voxel.Coord ripStart = center.Move(-radius, -radius, -radius); Voxel.Coord ripEnd = center.Move(radius, radius, radius); Dictionary <Voxel.Box, bool> permanentBoxes = new Dictionary <Voxel.Box, bool>(); foreach (Voxel.Coord c in ripStart.CoordinatesBetween(ripEnd)) { Voxel.Box box = voxel.GetBox(c); if (box != null && box.Type.Permanent) { permanentBoxes[box] = true; } } foreach (Voxel.Box b in permanentBoxes.Keys) { // Top and bottom for (int x = b.X - 1; x <= b.X + b.Width; x++) { for (int z = b.Z - 1; z <= b.Z + b.Depth; z++) { Voxel.Coord coord = new Voxel.Coord { X = x, Y = b.Y + b.Height, Z = z }; if (coord.Between(ripStart, ripEnd)) { edges.Add(coord); } coord = new Voxel.Coord { X = x, Y = b.Y - 1, Z = z }; if (coord.Between(ripStart, ripEnd)) { edges.Add(coord); } } } // Outer shell for (int y = b.Y; y < b.Y + b.Height; y++) { // Left and right for (int z = b.Z - 1; z <= b.Z + b.Depth; z++) { Voxel.Coord coord = new Voxel.Coord { X = b.X - 1, Y = y, Z = z }; if (coord.Between(ripStart, ripEnd)) { edges.Add(coord); } coord = new Voxel.Coord { X = b.X + b.Width, Y = y, Z = z }; if (coord.Between(ripStart, ripEnd)) { edges.Add(coord); } } // Backward and forward for (int x = b.X; x < b.X + b.Width; x++) { Voxel.Coord coord = new Voxel.Coord { X = x, Y = y, Z = b.Z - 1 }; if (coord.Between(ripStart, ripEnd)) { edges.Add(coord); } coord = new Voxel.Coord { X = x, Y = y, Z = b.Z + b.Depth }; if (coord.Between(ripStart, ripEnd)) { edges.Add(coord); } } } } if (edges.Contains(center)) { return(false); } // Top and bottom for (int x = ripStart.X; x <= ripEnd.X; x++) { for (int z = ripStart.Z; z <= ripEnd.Z; z++) { Voxel.Coord c = new Voxel.Coord { X = x, Y = ripStart.Y, Z = z }; Voxel.State s = voxel[c]; if (s != Voxel.States.Empty && !s.Permanent) { edges.Add(c); } c = new Voxel.Coord { X = x, Y = ripEnd.Y, Z = z }; s = voxel[c]; if (s != Voxel.States.Empty && !s.Permanent) { edges.Add(c); } } } // Sides for (int y = ripStart.Y + 1; y <= ripEnd.Y - 1; y++) { // Left and right for (int z = ripStart.Z; z <= ripEnd.Z; z++) { Voxel.Coord c = new Voxel.Coord { X = ripStart.X, Y = y, Z = z }; Voxel.State s = voxel[c]; if (s != Voxel.States.Empty && !s.Permanent) { edges.Add(c); } c = new Voxel.Coord { X = ripEnd.X, Y = y, Z = z }; s = voxel[c]; if (s != Voxel.States.Empty && !s.Permanent) { edges.Add(c); } } // Backward and forward for (int x = ripStart.X; x <= ripEnd.X; x++) { Voxel.Coord c = new Voxel.Coord { X = x, Y = y, Z = ripStart.Z }; Voxel.State s = voxel[c]; if (s != Voxel.States.Empty && !s.Permanent) { edges.Add(c); } c = new Voxel.Coord { X = x, Y = y, Z = ripEnd.Z }; s = voxel[c]; if (s != Voxel.States.Empty && !s.Permanent) { edges.Add(c); } } } Propagator p = WorldFactory.Instance.Get <Propagator>(); foreach (Voxel.Coord c in edges) { p.SparksLowPriority(voxel.GetAbsolutePosition(c), Propagator.Spark.Dangerous); } voxel.Empty(edges); voxel.Regenerate(callback); return(true); } return(false); }
public bool Go(bool checkPossibilities) { if (this.main.TotalTime - this.LastVaultStarted < vaultCoolDown) { return(false); } Matrix rotationMatrix = Matrix.CreateRotationY(this.Rotation); foreach (Voxel map in Voxel.ActivePhysicsVoxels) { Direction up = map.GetRelativeDirection(Direction.PositiveY); Direction backward = map.GetRelativeDirection(rotationMatrix.Forward); Direction right = up.Cross(backward); Vector3 pos = this.Position + rotationMatrix.Forward * -(this.Radius + 0.95f); Voxel.Coord resortCoord = default(Voxel.Coord); bool resort = false; for (int j = 0; j < searchForwardDistance; j++) { Voxel.Coord baseCoord = map.GetCoordinate(pos + (rotationMatrix.Forward * -j)).Move(up, searchUpDistance); foreach (int x in new[] { 0, -1, 1 }) { Voxel.Coord coord = baseCoord.Move(right, x); for (int i = 0; i < searchDownDistance; i++) { if (map[coord] != Voxel.States.Empty) { CandidateStatus status = checkAdjacent(map, coord, up, backward, right); if (status == CandidateStatus.Bad) { break; // Conflict } bool conflict = false; // Check other voxels for conflicts foreach (Voxel v in Voxel.ActivePhysicsVoxels) { if (v != map) { Direction up2 = v.GetRelativeDirection(Direction.PositiveY); Direction backward2 = v.GetRelativeDirection(rotationMatrix.Forward); Direction right2 = up2.Cross(backward2); Voxel.Coord coord2 = v.GetCoordinate(map.GetAbsolutePosition(coord)); if (v[coord2] != Voxel.States.Empty || checkAdjacent(v, coord2, up2, backward2, right2) != CandidateStatus.Good) { conflict = true; break; } } } if (conflict) { break; } if (status == CandidateStatus.Uneven && !resort) { resortCoord = coord; resort = true; break; } // Vault this.vault(map, coord.Move(up), false); return(true); } coord = coord.Move(up.GetReverse()); } } } if (resort) { this.vault(map, resortCoord.Move(up), true); return(true); } } if (checkPossibilities) { // Check block possibilities for vaulting foreach (BlockPredictor.Possibility possibility in this.Predictor.AllPossibilities) { Direction up = possibility.Map.GetRelativeDirection(Direction.PositiveY); Direction right = possibility.Map.GetRelativeDirection(Vector3.Cross(Vector3.Up, -rotationMatrix.Forward)); Vector3 pos = this.Position + rotationMatrix.Forward * (this.WallRunState == WallRun.State.Straight ? -1.75f : -1.25f); Voxel.Coord baseCoord = possibility.Map.GetCoordinate(pos).Move(up, searchUpDistance); foreach (int x in new[] { 0, -1, 1 }) { Voxel.Coord coord = baseCoord.Move(right, x); for (int i = 0; i < searchDownDistance; i++) { Voxel.Coord downCoord = coord.Move(up.GetReverse()); if (!coord.Between(possibility.StartCoord, possibility.EndCoord) && downCoord.Between(possibility.StartCoord, possibility.EndCoord)) { this.Predictor.InstantiatePossibility(possibility); this.vault(possibility.Map, coord, false); return(true); } coord = coord.Move(up.GetReverse()); } } } } return(false); }
public bool Go() { if (this.main.TotalTime - this.LastJump < jumpCoolDown || this.Crouched) { return(false); } bool supported = this.IsSupported; WallRun.State wallRunState = this.WallRunState; Matrix rotationMatrix = Matrix.CreateRotationY(this.Rotation); Vector3 forward = -rotationMatrix.Forward; Vector2 jumpDirection = this.AbsoluteMovementDirection; Vector3 baseVelocity = Vector3.Zero; bool wallJumping = false; const float wallJumpHorizontalVelocityAmount = 0.75f; const float wallJumpDistance = 2.0f; Action <Voxel, Direction, Voxel.Coord> wallJump = delegate(Voxel wallJumpMap, Direction wallNormalDirection, Voxel.Coord wallCoordinate) { this.LastWallRunMap.Value = wallJumpMap; this.LastWallDirection.Value = wallNormalDirection.GetReverse(); this.LastWallJump.Value = main.TotalTime; Voxel.State wallType = wallJumpMap[wallCoordinate]; if (wallType == Voxel.States.Empty) // Empty. Must be a block possibility that hasn't been instantiated yet { wallType = Voxel.States.Blue; } this.WalkedOn.Execute(wallJumpMap, wallCoordinate, wallNormalDirection.GetReverse()); AkSoundEngine.PostEvent(AK.EVENTS.FOOTSTEP_PLAY, this.Entity); wallJumping = true; // Set up wall jump velocity Vector3 absoluteWallNormal = wallJumpMap.GetAbsoluteVector(wallNormalDirection.GetVector()); Vector2 wallNormal2 = new Vector2(absoluteWallNormal.X, absoluteWallNormal.Z); wallNormal2.Normalize(); bool wallRunningStraight = wallRunState == WallRun.State.Straight || wallRunState == WallRun.State.Down; if (wallRunningStraight) { jumpDirection = new Vector2(main.Camera.Forward.Value.X, main.Camera.Forward.Value.Z); } else { jumpDirection = new Vector2(forward.X, forward.Z); } jumpDirection.Normalize(); float dot = Vector2.Dot(wallNormal2, jumpDirection); if (dot < 0) { jumpDirection = jumpDirection - (2.0f * dot * wallNormal2); } jumpDirection *= wallJumpHorizontalVelocityAmount; if (!wallRunningStraight && Math.Abs(dot) < 0.5f) { // If we're jumping perpendicular to the wall, add some velocity so we jump away from the wall a bit jumpDirection += wallJumpHorizontalVelocityAmount * 0.75f * wallNormal2; } Vector3 supportLocation = this.FloorPosition; baseVelocity += wallJumpMap.LinearVelocity + Vector3.Cross(wallJumpMap.AngularVelocity, supportLocation - wallJumpMap.Transform.Value.Translation); }; if (!supported && wallRunState == WallRun.State.None && this.LinearVelocity.Value.Y > Lemma.Components.FallDamage.DamageVelocity * 1.5f) { // We're not doing our normal jump, and not wall-runnign // See if we can wall-jump Vector3 playerPos = this.Position; Voxel.GlobalRaycastResult?closestWallRaycastHit = null; Vector3 closestWallRaycastDirection = Vector3.Zero; foreach (Vector3 dir in new[] { rotationMatrix.Left, rotationMatrix.Right, rotationMatrix.Backward, rotationMatrix.Forward }) { Voxel.GlobalRaycastResult hit = Voxel.GlobalRaycast(playerPos, dir, wallJumpDistance); if (hit.Voxel != null && (!closestWallRaycastHit.HasValue || hit.Distance < closestWallRaycastHit.Value.Distance)) { closestWallRaycastDirection = dir; closestWallRaycastHit = hit; } } if (closestWallRaycastHit != null) { Voxel m = closestWallRaycastHit.Value.Voxel; wallJump(m, closestWallRaycastHit.Value.Normal, closestWallRaycastHit.Value.Coordinate.Value); } } // If we're wall-running, we can wall-jump // Add some velocity so we jump away from the wall a bit if (wallRunState != WallRun.State.None) { Vector3 pos = this.FloorPosition + new Vector3(0, 0.5f, 0); Voxel.Coord wallCoord = this.WallRunMap.Value.GetCoordinate(pos).Move(this.WallDirection, 2); wallJump(this.WallRunMap, this.WallDirection.Value.GetReverse(), wallCoord); } bool go = supported || wallJumping; BlockPredictor.Possibility instantiatedBlockPossibility = null; Voxel.Coord instantiatedBlockPossibilityCoord = default(Voxel.Coord); if (!go) { // Check block possibilities beneath us Vector3 jumpPos = this.FloorPosition + new Vector3(0, -1.0f, 0); foreach (BlockPredictor.Possibility possibility in this.Predictor.AllPossibilities) { Voxel.Coord possibilityCoord = possibility.Map.GetCoordinate(jumpPos); if (possibilityCoord.Between(possibility.StartCoord, possibility.EndCoord) && !possibility.Map.GetCoordinate(jumpPos + new Vector3(2.0f)).Between(possibility.StartCoord, possibility.EndCoord)) { this.Predictor.InstantiatePossibility(possibility); go = true; instantiatedBlockPossibility = possibility; instantiatedBlockPossibilityCoord = possibilityCoord; break; } } } if (!go) { // Check block possibilities for wall jumping Vector3 playerPos = this.Position; Vector3[] wallJumpDirections = new[] { rotationMatrix.Left, rotationMatrix.Right, rotationMatrix.Forward }; foreach (BlockPredictor.Possibility possibility in this.Predictor.AllPossibilities) { foreach (Vector3 dir in wallJumpDirections) { foreach (Voxel.Coord coord in possibility.Map.Rasterize(playerPos, playerPos + (dir * wallJumpDistance))) { if (coord.Between(possibility.StartCoord, possibility.EndCoord)) { this.Predictor.InstantiatePossibility(possibility); instantiatedBlockPossibility = possibility; instantiatedBlockPossibilityCoord = coord; wallJump(possibility.Map, possibility.Map.GetRelativeDirection(dir).GetReverse(), coord); wallJumping = true; go = true; break; } } if (wallJumping) { break; } } if (wallJumping) { break; } } } if (go) { float totalMultiplier = 1.0f; bool grunted = false; if (wallJumping) { if (this.wallJumpCount == 0) { this.wallJumpChainStart = this.Position; } else { Vector3 chainDistance = this.Position - this.wallJumpChainStart; chainDistance.Y = 0.0f; if (chainDistance.Length() > 6.0f) { this.wallJumpCount = 0; this.wallJumpChainStart = this.Position; } } if (this.wallJumpCount > 3) { return(false); } totalMultiplier = 1.0f - Math.Min(1.0f, this.wallJumpCount / 8.0f); this.wallJumpCount++; } else { // Regular jump // Take base velocity into account baseVelocity += this.SupportVelocity; grunted = this.FallDamage.ApplyJump(); if (!this.Active) // We got killed by fall damage { return(false); } if (instantiatedBlockPossibility != null) { this.WalkedOn.Execute(instantiatedBlockPossibility.Map, instantiatedBlockPossibilityCoord, instantiatedBlockPossibility.Map.GetRelativeDirection(Direction.NegativeY)); } // Also manually reset our ability to kick and wall-jump this.CanKick.Value = true; this.wallJumpCount = 0; } Vector3 velocity = this.LinearVelocity - baseVelocity; float currentVerticalSpeed = velocity.Y; velocity.Y = 0.0f; float jumpSpeed = jumpDirection.Length(); if (jumpSpeed > 0) { jumpDirection *= (wallJumping ? Math.Max(this.MaxSpeed, Vector3.Dot(forward, velocity)) : velocity.Length()) / jumpSpeed; } if (main.TotalTime - this.LastRollKickEnded < 0.3f) { totalMultiplier *= 1.2f; } float verticalJumpSpeed = this.JumpSpeed; // If we're not instantiating a block possibility beneath us or we're not currently falling, incorporate some of our existing vertical velocity in our jump if (instantiatedBlockPossibility == null || wallJumping || currentVerticalSpeed > 0.0f) { verticalJumpSpeed += currentVerticalSpeed * 0.5f; } this.LinearVelocity.Value = baseVelocity + new Vector3(jumpDirection.X, verticalJumpSpeed, jumpDirection.Y) * totalMultiplier; velocity = this.LinearVelocity; velocity.Y = 0.0f; this.LastSupportedSpeed.Value = velocity.Length(); if (supported && this.SupportEntity.Value != null) { Vector3 impulsePosition = this.FloorPosition; Vector3 impulse = this.LinearVelocity.Value * this.Mass * -1.0f; this.SupportEntity.Value.ApplyImpulse(ref impulsePosition, ref impulse); } Session.Recorder.Event(main, "Jump"); this.IsSupported.Value = false; this.SupportEntity.Value = null; this.HasTraction.Value = false; AkSoundEngine.PostEvent(AK.EVENTS.PLAY_PLAYER_JUMP, this.Entity); if (!grunted && (float)this.random.NextDouble() < 0.15f) { AkSoundEngine.PostEvent(AK.EVENTS.PLAY_PLAYER_LAND, this.Entity); // Grunt } this.model.Stop ( "Vault", "Mantle", "TopOut", "Jump", "Jump02", "Jump03", "JumpLeft", "JumpRight", "JumpBackward" ); velocity = -Vector3.TransformNormal(this.LinearVelocity, Matrix.CreateRotationY(-this.Rotation)); velocity.Y = 0.0f; if (wallRunState == WallRun.State.Left || wallRunState == WallRun.State.Right) { velocity.Z = 0.0f; } else if (wallJumping) { velocity.Z *= 0.5f; } else { velocity.X = 0.0f; } Direction direction = DirectionExtensions.GetDirectionFromVector(velocity); string animation; switch (direction) { case Direction.NegativeX: animation = "JumpLeft"; break; case Direction.PositiveX: animation = "JumpRight"; break; case Direction.PositiveZ: animation = wallJumping ? "JumpBackward" : this.randomJumpAnimation(); break; default: animation = this.randomJumpAnimation(); break; } this.model.StartClip(animation, 4, false); this.model[animation].CurrentTime = TimeSpan.FromSeconds(0.2); // Deactivate any wall-running we're doing this.DeactivateWallRun.Execute(); // Play a footstep sound since we're jumping off the ground AkSoundEngine.PostEvent(AK.EVENTS.FOOTSTEP_PLAY, this.Entity); this.LastJump.Value = this.main.TotalTime; return(true); } return(false); }
public static bool Go(Voxel voxel, Voxel.Coord center, int radius, Action<List<DynamicVoxel>> callback = null) { if (!voxel[center].Permanent) { // Break off a chunk of this voxel into a new DynamicMap. List<Voxel.Coord> edges = new List<Voxel.Coord>(); Voxel.Coord ripStart = center.Move(-radius, -radius, -radius); Voxel.Coord ripEnd = center.Move(radius, radius, radius); Dictionary<Voxel.Box, bool> permanentBoxes = new Dictionary<Voxel.Box, bool>(); foreach (Voxel.Coord c in ripStart.CoordinatesBetween(ripEnd)) { Voxel.Box box = voxel.GetBox(c); if (box != null && box.Type.Permanent) permanentBoxes[box] = true; } foreach (Voxel.Box b in permanentBoxes.Keys) { // Top and bottom for (int x = b.X - 1; x <= b.X + b.Width; x++) { for (int z = b.Z - 1; z <= b.Z + b.Depth; z++) { Voxel.Coord coord = new Voxel.Coord { X = x, Y = b.Y + b.Height, Z = z }; if (coord.Between(ripStart, ripEnd)) edges.Add(coord); coord = new Voxel.Coord { X = x, Y = b.Y - 1, Z = z }; if (coord.Between(ripStart, ripEnd)) edges.Add(coord); } } // Outer shell for (int y = b.Y; y < b.Y + b.Height; y++) { // Left and right for (int z = b.Z - 1; z <= b.Z + b.Depth; z++) { Voxel.Coord coord = new Voxel.Coord { X = b.X - 1, Y = y, Z = z }; if (coord.Between(ripStart, ripEnd)) edges.Add(coord); coord = new Voxel.Coord { X = b.X + b.Width, Y = y, Z = z }; if (coord.Between(ripStart, ripEnd)) edges.Add(coord); } // Backward and forward for (int x = b.X; x < b.X + b.Width; x++) { Voxel.Coord coord = new Voxel.Coord { X = x, Y = y, Z = b.Z - 1 }; if (coord.Between(ripStart, ripEnd)) edges.Add(coord); coord = new Voxel.Coord { X = x, Y = y, Z = b.Z + b.Depth }; if (coord.Between(ripStart, ripEnd)) edges.Add(coord); } } } if (edges.Contains(center)) return false; // Top and bottom for (int x = ripStart.X; x <= ripEnd.X; x++) { for (int z = ripStart.Z; z <= ripEnd.Z; z++) { Voxel.Coord c = new Voxel.Coord { X = x, Y = ripStart.Y, Z = z }; Voxel.State s = voxel[c]; if (s != Voxel.States.Empty && !s.Permanent) edges.Add(c); c = new Voxel.Coord { X = x, Y = ripEnd.Y, Z = z }; s = voxel[c]; if (s != Voxel.States.Empty && !s.Permanent) edges.Add(c); } } // Sides for (int y = ripStart.Y + 1; y <= ripEnd.Y - 1; y++) { // Left and right for (int z = ripStart.Z; z <= ripEnd.Z; z++) { Voxel.Coord c = new Voxel.Coord { X = ripStart.X, Y = y, Z = z }; Voxel.State s = voxel[c]; if (s != Voxel.States.Empty && !s.Permanent) edges.Add(c); c = new Voxel.Coord { X = ripEnd.X, Y = y, Z = z }; s = voxel[c]; if (s != Voxel.States.Empty && !s.Permanent) edges.Add(c); } // Backward and forward for (int x = ripStart.X; x <= ripEnd.X; x++) { Voxel.Coord c = new Voxel.Coord { X = x, Y = y, Z = ripStart.Z }; Voxel.State s = voxel[c]; if (s != Voxel.States.Empty && !s.Permanent) edges.Add(c); c = new Voxel.Coord { X = x, Y = y, Z = ripEnd.Z }; s = voxel[c]; if (s != Voxel.States.Empty && !s.Permanent) edges.Add(c); } } Propagator p = WorldFactory.Instance.Get<Propagator>(); foreach (Voxel.Coord c in edges) p.SparksLowPriority(voxel.GetAbsolutePosition(c), Propagator.Spark.Dangerous); voxel.Empty(edges); voxel.Regenerate(callback); return true; } return false; }