public DialogBox(string[] text, string font, float sizePx, Game1 game, Level parent, Vector2 position = default(Vector2)) : base("", font, sizePx, game, parent, "WalkieTalkie", position, Chunk.Down) { LeftPadding = 65; RightPadding = 5; TopPadding = 5; BottomPadding = 5; AvatarTexture = game.TextureCache["walkie_talkie"]; Avatar = new AnimatedSprite(AvatarTexture, game, new Vector2(AvatarTexture.Bounds.Width, AvatarTexture.Bounds.Height)); Avatar.Add("idle", 0, 1, 100); Avatar.Play("idle"); TextArray = text; MaxLines = (Background.Height - TopPadding - BottomPadding) / sizePx; SetText(TextArray[0]); CurLetters = 1; //CurMaxLetters = Text.Length; CurLines = Text.Split('\n', StringSplitOptions.RemoveEmptyEntries); CurNumLines = CurLines.Length; CurMaxLetters = 0; for (int i = 0; i < Math.Min(Math.Floor(MaxLines), CurNumLines); ++i) { CurMaxLetters++; CurMaxLetters += CurLines[i].Length; } CurMaxLetters--; }
private void Close(Chunk chunk) { Sprite.Play("closed"); State = EState.Closed; doorCollision.Open = false; chunk.SolidTiles[chunk.GetTileLocation(Position - Vector2.UnitY * Chunk.TileSize / 2)] = (uint)Chunk.Colors.AerialDroneWall; chunk.SolidTiles[chunk.GetTileLocation(Position + Vector2.UnitY * Chunk.TileSize / 2)] = (uint)Chunk.Colors.AerialDroneWall; }
public TextBox(string text, string font, float sizePx, Game1 game, Level parent, string type = "Debug", Vector2 position = new Vector2(), int anchor = 0, int leftPadding = 0, int rightPadding = 0, int topPadding = 0, int bottomPadding = 0) : base(game, parent) { Background = game.TextureCache[Backgrounds[type]]; Text = text; Font = font; SizePx = sizePx; TopPadding = topPadding; BackgroundSprite = new AnimatedSprite(Background, game, new Vector2(Background.Bounds.Width, Background.Bounds.Height)); BackgroundSprite.Add("idle", 0, 1, 100); BackgroundSprite.Play("idle"); Position = position; Anchor = anchor; }
public void HearSound(Vector2 position, float volume, Chunk chunk) { if (PositionKnown > 0) { return; } float sqrDist = (Position - position).LengthSquared(); if (sqrDist > SoundEngine.AudibleDistance * SoundEngine.AudibleDistance) { return; } float dist = (float)Math.Sqrt(sqrDist); if (chunk.IntersectLine(position, Position - position, 1, out float temp, false)) { volume /= 2; } float sensitivity = (chunk.ChunkAlarmState ? AlertSensitivity : ClearSensitivity); volume -= dist / sensitivity; if (volume > 0) { float precision = Math.Min(1, volume / BaseVolume); float angle = (float)Game.RNG.NextDouble() * 2 * (float)Math.PI; float distOffset = (1 - precision) * HearingPrecision; Vector2 dir = new Vector2((float)Math.Sin(angle), (float)Math.Cos(angle)); var point1 = new Vector2(dir.Y, -dir.X); point1.Normalize(); point1 *= Size.X; var point2 = -point1; if (chunk.IntersectLine(position + point1, dir, distOffset, out float distToIntersect1, false, true)) { distOffset = distToIntersect1; } if (chunk.IntersectLine(position + point2, dir, distOffset, out float distToIntersect2, false, true)) { distOffset = distToIntersect2; } if (State == AIState.Searching) { if (Target(position + dir * distOffset, chunk, AIState.Targeting)) { FinishPath = () => AlertSignal.Play("alert"); } } else if (State != AIState.Targeting && State != AIState.Investigating) { if (Target(position + dir * distOffset, chunk, AIState.Investigating)) { FinishPath = () => { AlertSignal.Play("noise"); Game.SoundEngine.Play("Enemy_Alarmed", Position, 1); ViewCone.SetColor(ConeEntity.InspectColor); } } ; } } }
public override void Update(Chunk chunk) { if (FlyingSound == null) { FlyingSound = Game.SoundEngine.Play("Enemy_DroneFly", Position, 1, true); } if (PositionKnown > 0) { --PositionKnown; } float dt = Game1.DeltaT; Velocity = new Vector2(); switch (State) { case AIState.Patrolling: if (MoveTo(WanderLocation, PatrolSpeed)) { Wait(); } break; case AIState.Searching: if (MoveTo(WanderLocation, SearchSpeed)) { Velocity = new Vector2(0); bool foundSearch = false; for (int i = 0; i < WanderSearchAttempts; ++i) { if (FindWander(TargetLocation, PatrolRange, chunk)) { foundSearch = true; break; } } if (!foundSearch) { if (Target(TargetLocation, chunk, AIState.Targeting)) { FinishPath = () => { }; } } } break; case AIState.CursorySearching: if (MoveTo(WanderLocation, PatrolSpeed)) { Velocity = new Vector2(0); bool foundSearch = false; for (int i = 0; i < WanderSearchAttempts; ++i) { if (FindWander(TargetLocation, PatrolRange, chunk)) { foundSearch = true; break; } } if (!foundSearch) { if (Target(TargetLocation, chunk, AIState.Investigating)) { FinishPath = () => { }; } } } StateTimer -= dt; if (StateTimer <= 0) { Return(chunk); } break; case AIState.Waiting: StateTimer += dt; if (StateTimer <= 0.05F * WaitTime) { } if (StateTimer <= 0.25F * WaitTime) { Direction += dt * WaitAngularVelocity; } else if (StateTimer <= 0.3F * WaitTime) { } else if (StateTimer <= 0.7F * WaitTime) { Direction -= dt * WaitAngularVelocity; } else if (StateTimer <= 0.75F * WaitTime) { } else if (StateTimer <= 0.95F * WaitTime) { Direction += dt * WaitAngularVelocity; } else if (StateTimer <= WaitTime) { } else { bool found = false; for (int i = 0; i < WanderSearchAttempts; ++i) { if (FindWander(Spawn, PatrolRange, chunk)) { found = true; break; } } if (!found) { Return(chunk); } else { State = AIState.Patrolling; } } break; case AIState.Targeting: Vector2 nextPos = NextNode < Path.Count - 1 ? Path[NextNode] : TargetLocation; if (MoveTo(nextPos, TargetSpeed)) { Velocity = new Vector2(); ++NextNode; nextPos = NextNode < Path.Count - 1 ? Path[NextNode] : TargetLocation; if (NextNode >= Path.Count) { Search(nextPos, chunk, float.PositiveInfinity); } else { MoveTo(nextPos, TargetSpeed); } } break; case AIState.Investigating: if (MoveTo(Path[NextNode], SearchSpeed)) { Velocity = new Vector2(); ++NextNode; if (NextNode >= Path.Count) { Search(Path[NextNode - 1], chunk, SearchTime, true); } else { MoveTo(Path[NextNode], SearchSpeed); } } break; case AIState.Returning: if (MoveTo(Path[NextNode], PatrolSpeed)) { ++NextNode; if (NextNode >= Path.Count) { Wait(); } } break; } if (Pathfinding != null) { if (Pathfinding.IsCompleted) { var newPath = Pathfinding.Result; Pathfinding.Dispose(); Pathfinding = null; if (newPath.Count > 1) { Path = newPath; TargetLocation = Path.Last(); NextNode = 1; } State = NextState; FinishPath.Invoke(); } } { // Kill if touched. if (!chunk.Level.Player.IsHiding && chunk.Level.Player.DeathTimer <= 0 && GetBoundingBox().Intersects(chunk.Level.Player.GetBoundingBox())) { chunk.Level.Player.Kill(); } } if (State == AIState.Targeting || State == AIState.Searching) { Sprite.Play("chase"); } else { Sprite.Play("idle"); } Position += dt * Velocity; ViewCone.UpdatePosition(Position); ViewCone.Middle = Direction; ViewCone.Update(chunk); AlertSignal.Update(dt); Sprite.Update(dt); FlyingSound.Position = Position; base.Update(chunk); }
public override void Update(Chunk chunk) { float dt = Game1.DeltaT; Controller.Update(); Sprite.Update(dt); if (Controller.Pause) { Game.Paused = true; } if (0 < DeathTimer) { DeathTimer -= dt; if (DeathTimer <= 0) { chunk.Die(this); } if (Grounded) { Velocity.X = 0; } } if (Controller.Crouch && !Controller.Was.Crouch) { IsCrouched = !IsCrouched; } bool hide = Controller.Hide && !Controller.Was.Hide; bool jump = Controller.Jump && !Controller.Was.Jump; //// Perform movement stepping. //// !! This code should never change Position !! // Check for neighbors Object down = chunk.CollidePoint(new Vector2(Position.X, Position.Y - Size.Y - 1)); Object left = chunk.CollidePoint(new Vector2(Position.X - Size.X - 1, Position.Y)); Object right = chunk.CollidePoint(new Vector2(Position.X + Size.X + 1, Position.Y)); Object leftCorner = chunk.CollidePoint(new Vector2(Position.X - Size.X - 1, Position.Y - Size.Y - 1)); Object rightCorner = chunk.CollidePoint(new Vector2(Position.X + Size.X + 1, Position.Y - Size.Y - 1)); // Apply gravity Velocity.Y -= dt * Gravity; chunk.ForEachCollidingTile(this, (tile, pos) => { if (tile is TileSpike && State != PlayerState.Dying) { Kill(); } else if (tile is TileGoal) { Game.SoundEngine.Play("win"); Game.ShowScore(); } }); switch (State) { case PlayerState.Climbing: case PlayerState.Normal: chunk.ForEachCollidingEntity(this, (entity) => { if (entity is Pickup && !chunk.Level.Alarm.IsRaised) { Vector2 buttonPos = Game.TextEngine.TranslateToWindow(entity.Position + new Vector2(0, 36)); Game.TextEngine.QueueButton(TextEngine.Button.Y, buttonPos); if (Controller.Interact) { if (chunk.NextItem < chunk.StoryItems.Length) { State = PlayerState.QueueInCall; ItemDialog = true; } chunk.Die(entity); } } else if (entity is HidingSpot) { Vector2 buttonPos = Game.TextEngine.TranslateToWindow(entity.Position + new Vector2(0, 36)); Game.TextEngine.QueueButton(TextEngine.Button.Y, buttonPos); if (hide) { TargetSpot = entity.Position; hide = false; State = PlayerState.QueueHide; } } else if (entity is Door && ((Door)entity).State == Door.EState.Closed) { if (entity.GetBoundingBox().Bottom <= GetBoundingBox().Bottom) { float dir = Math.Sign(Position.X - entity.Position.X); if (-Sprite.Direction == dir) { Vector2 buttonPos = Game.TextEngine.TranslateToWindow(entity.Position + new Vector2(dir * 1.1F * Chunk.TileSize, 32)); Game.TextEngine.QueueButton(TextEngine.Button.Y, buttonPos); if (entity == TargetEntity) { if (Controller.Interact && !IsCrouched) { InteractTimer -= Game1.DeltaT; if (InteractTimer <= 0) { State = PlayerState.QueueCrash; TargetSpot = entity.Position + new Vector2(dir * (0.5F * Chunk.TileSize + 1), 0); } } else { State = PlayerState.QueueDoor; TargetSpot = entity.Position + new Vector2(dir * (0.5F * Chunk.TileSize + 1), 0); } } else { if (Controller.Interact) { TargetEntity = entity; InteractTimer = InteractHold; } } } } } else if (entity is ButtonPrompt) { Vector2 buttonPos = Game.TextEngine.TranslateToWindow(entity.Position + new Vector2(0, 36)); ((ButtonPrompt)entity).DrawPrompt(); } else if (entity is DialogTrigger) { if (chunk.Level.NextTrigger < chunk.Level.TriggeredDialogs.Length) { State = PlayerState.QueueInCall; ItemDialog = false; } chunk.Die(entity); } else if (entity is AlarmTrigger) { ((AlarmTrigger)entity).Triggered = true; chunk.Level.Alarm.Detected = true; chunk.Level.Alarm.Alert(Position, chunk); } }); if (State == PlayerState.QueueHide || State == PlayerState.QueueDoor || State == PlayerState.QueueCrash || State == PlayerState.QueueInCall) { break; } if (left != null || right != null || (State == PlayerState.Climbing && (leftCorner != null || rightCorner != null))) { HasWallJumped = false; State = PlayerState.Normal; if (Controller.Climb) { State = PlayerState.Climbing; if (Controller.MoveUp && Velocity.Y < ClimbSpeed) { Velocity.Y = +ClimbSpeed; } else if (Controller.MoveDown) { Velocity.Y = -ClimbSpeed; } else if (Velocity.Y <= ClimbSpeed) { Velocity.Y = 0; } if (Velocity.X != 0) { State = PlayerState.Normal; } // Push over corners if (leftCorner != null && left == null && Sprite.Direction == -1) { Velocity.X = -150; Velocity.Y = ClimbSpeed; } if (rightCorner != null && right == null && Sprite.Direction == +1) { Velocity.X = +150; Velocity.Y = ClimbSpeed; } } else if (Velocity.Y < 0) { Velocity.Y *= WallSlideFriction; } if (jump && (!HasWallJumped || CanRepeatWallJump)) { if (right != null && (!Grounded)) { MakeSound(chunk, "walljump"); Velocity.X = -WallJumpVelocity.X; Velocity.Y = WallJumpVelocity.Y; HasWallJumped = true; jump = false; } else if (left != null && (!Grounded)) { MakeSound(chunk, "walljump"); Velocity.X = WallJumpVelocity.X; Velocity.Y = WallJumpVelocity.Y; HasWallJumped = true; jump = false; } } } else { State = PlayerState.Normal; } if (Grounded) { SoundFrame = -1; HasWallJumped = false; if (jump) { IsCrouched = false; MakeSound(chunk, "jump"); jump = false; Velocity.Y = JumpSpeed; LongJump = LongJumpTime * dt; } else if (!chunk.ChunkAlarmState && Controller.Call && !Controller.Was.Call) { State = PlayerState.QueueOutCall; } } if (State == PlayerState.Normal || Grounded) { float max = (IsCrouched) ? CrouchSpeed : MaxVel; if (Controller.MoveRight && Velocity.X < max) { // Allow quick turns on the ground if (Velocity.X < 0 && Grounded) { Velocity.X = 0; } Velocity.X += AccelRate * dt; } else if (Controller.MoveLeft && -max < Velocity.X) { // Allow quick turns on the ground if (0 < Velocity.X && Grounded) { Velocity.X = 0; } Velocity.X -= AccelRate * dt; } else if (!Controller.MoveLeft && !Controller.MoveRight) { // Deaccelerate in the air to accomodate wall jumps if (Grounded || Math.Abs(Velocity.X) < DeaccelRate * dt) { Velocity.X = 0; } else { Velocity.X -= Math.Sign(Velocity.X) * DeaccelRate * dt; } } else if (IsCrouched && max < Math.Abs(Velocity.X)) { Velocity.X = Math.Sign(Velocity.X) * max; } } if (Controller.Jump && 0 < LongJump) { Velocity.Y += AccelRate * dt; } else { LongJump = 0; } break; case PlayerState.QueueHide: if (Position.X < TargetSpot.X && Velocity.X < MaxVel) { // Allow quick turns on the ground if (Velocity.X < 0 && Grounded) { Velocity.X = 0; } Velocity.X += AccelRate * dt; } else if (Position.X > TargetSpot.X && -MaxVel < Velocity.X) { // Allow quick turns on the ground if (0 < Velocity.X && Grounded) { Velocity.X = 0; } Velocity.X -= AccelRate * dt; } if (Math.Abs(Position.X - TargetSpot.X) <= MaxVel * dt) { HasWallJumped = false; State = PlayerState.Hiding; Position = TargetSpot + new Vector2(0, Size.Y - Chunk.TileSize / 2); Velocity.X = 0; } if (Position.Y - Size.Y < TargetSpot.Y - Chunk.TileSize) { State = PlayerState.Normal; } break; case PlayerState.Hiding: Velocity.X = 0; Velocity.Y = 0; if (hide) { State = PlayerState.Normal; } break; case PlayerState.QueueDoor: if (Position.X < TargetSpot.X && Velocity.X < MaxVel) { // Allow quick turns on the ground if (Velocity.X < 0 && Grounded) { Velocity.X = 0; } Velocity.X += AccelRate * dt; } else if (Position.X > TargetSpot.X && -MaxVel < Velocity.X) { // Allow quick turns on the ground if (0 < Velocity.X && Grounded) { Velocity.X = 0; } Velocity.X -= AccelRate * dt; } if (Math.Abs(Position.X - TargetSpot.X) <= MaxVel * dt) { HasWallJumped = false; State = PlayerState.OpeningDoor; Position.X = TargetSpot.X; Velocity.X = 0; } if (Position.Y - Size.Y < TargetSpot.Y - Chunk.TileSize) { State = PlayerState.Normal; } break; case PlayerState.OpeningDoor: Velocity.X = 0; Velocity.Y = 0; if (Sprite.Frame == 78) { ((Door)TargetEntity).Interact(chunk, false, TargetEntity.Position.X < Position.X); } if (Sprite.Frame == 0) { State = PlayerState.Normal; TargetEntity = null; } break; case PlayerState.QueueCrash: if (Position.X < TargetSpot.X && Velocity.X < MaxVel) { // Allow quick turns on the ground if (Velocity.X < 0 && Grounded) { Velocity.X = 0; } Velocity.X += AccelRate * dt; } else if (Position.X > TargetSpot.X && -MaxVel < Velocity.X) { // Allow quick turns on the ground if (0 < Velocity.X && Grounded) { Velocity.X = 0; } Velocity.X -= AccelRate * dt; } if (Math.Abs(Position.X - TargetSpot.X) <= MaxVel * (dt + 0.6F / 4)) { HasWallJumped = false; State = PlayerState.CrashDoor; TargetSpot = TargetSpot + 999 * Vector2.UnitX * Math.Sign(TargetEntity.Position.X - Position.X); Velocity.X = MaxVel * Math.Sign(TargetSpot.X - Position.X); } break; case PlayerState.CrashDoor: Velocity.Y = 0; if (Sprite.Frame >= 88 && Sprite.Frame <= 91) { if (Velocity.X < 0 && Grounded) { Velocity.X = 0; } if (Velocity.X < MaxVel) { Velocity.X += Math.Sign(TargetSpot.X - Position.X) * 0.5F * AccelRate * dt; } } else { if (Velocity.X < 0 && Grounded) { Velocity.X = 0; } if (Velocity.X < MaxVel) { Velocity.X += Math.Sign(TargetSpot.X - Position.X) * AccelRate * dt; } } if (Sprite.Frame == 88) { ((Door)TargetEntity).Interact(chunk, true, TargetEntity.Position.X < Position.X); } if (Sprite.Frame == 6) { State = PlayerState.Normal; TargetEntity = null; } break; case PlayerState.QueueInCall: Velocity.X = 0; if (Sprite.Frame == 75) { CallTimer -= dt; if (CallTimer == float.PositiveInfinity) { State = PlayerState.Normal; CallTimer = 0; break; } if (CallTimer < 0) { if (ItemDialog) { chunk.Level.OpenDialogBox(chunk.StoryItems[chunk.NextItem++]); } else { chunk.Level.OpenDialogBox(chunk.Level.TriggeredDialogs[chunk.Level.NextTrigger++]); } CallTimer = float.PositiveInfinity; } } else { CallTimer = CallDuration; } break; case PlayerState.QueueOutCall: Velocity.X = 0; if (Sprite.Frame == 75) { CallTimer -= dt; if (CallTimer == float.PositiveInfinity) { State = PlayerState.Normal; CallTimer = 0; break; } if (CallTimer < 0) { chunk.Level.OpenDialogBox(Level.RandomDialogs[chunk.Level.NextRandomDialog++]); CallTimer = float.PositiveInfinity; } } else { CallTimer = CallDuration; } break; case PlayerState.Dying: break; } if (0 < LongJump) { LongJump -= dt; if (Velocity.Y < 0) { LongJump = 0; } } bool HardFall = (Velocity.Y < HardFallVelocity); // Now that all movement has been updated, check for collisions HandleCollisions(dt, chunk, true); if (Grounded && HardFall) { MakeSound(chunk, "land", 80); } // Animations StopSoundLoop = true; switch (State) { case PlayerState.QueueInCall: case PlayerState.QueueOutCall: if (CallTimer == CallDuration) { Sprite.Play("call"); LoopSound("call"); } break; case PlayerState.QueueDoor: case PlayerState.QueueHide: case PlayerState.Normal: if ((Velocity.Y < 0 && (left != null || right != null))) { Sprite.Play("slide"); LoopSound("slide"); // Force direction to face wall if (left != null) { Sprite.Direction = -1; } if (right != null) { Sprite.Direction = +1; } } else { if (0 < Velocity.Y) { Sprite.Play("jump"); } else if (Velocity.Y < 0) { Sprite.Play("fall"); } else if (Velocity.X != 0) { if (IsCrouched) { Sprite.Play("crouchwalk"); if (Sprite.Frame == 58 || Sprite.Frame == 63) { MakeSound(chunk, chunk.IsOutside ? "crouch_outside" : "crouch_inside", 5); } } else { Sprite.Play("run"); if (Sprite.Frame == 10 || Sprite.Frame == 18) { MakeSound(chunk, chunk.IsOutside ? "run_outside" : "run_inside", 70); } } } else { SoundFrame = 0; if (IsCrouched) { Sprite.Play("crouch"); } else { Sprite.Play("idle"); } } } break; case PlayerState.Climbing: Sprite.Play("climb"); if (Sprite.Frame == 26 || Sprite.Frame == 31) { MakeSound(chunk, "climb", 20); } if (Velocity.Y < 0) { Sprite.FrameStep = -1; } else { Sprite.FrameStep = +1; } // Force direction to face wall if (left != null) { Sprite.Direction = -1; } if (right != null) { Sprite.Direction = +1; } if (Velocity.Y == 0 || !Controller.Climb) { Sprite.Reset(); } break; case PlayerState.Hiding: Sprite.Play("hide"); if (Sprite.Frame == 34) { MakeSound(chunk, "hide", 5); } break; case PlayerState.OpeningDoor: Sprite.Play("open"); break; case PlayerState.CrashDoor: Sprite.Play("crash"); break; case PlayerState.Dying: Sprite.Play("die"); break; } if (StopSoundLoop) { StopSound(); } // Base direction on movement if (Velocity.X < 0) { Sprite.Direction = -1; } if (0 < Velocity.X) { Sprite.Direction = +1; } Game.SoundEngine.Update(Position); }