LADXHD/InGame/GameObjects/Dungeon/ObjDungeonDoor.cs
2023-12-14 17:21:22 -05:00

172 lines
6 KiB
C#

using System;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using ProjectZ.InGame.GameObjects.Base;
using ProjectZ.InGame.GameObjects.Base.Components;
using ProjectZ.InGame.GameObjects.Base.CObjects;
using ProjectZ.InGame.Things;
namespace ProjectZ.InGame.GameObjects.Dungeon
{
internal class ObjDungeonDoor : GameObject
{
private enum DoorStates { Opening, Closing, Open, Closed }
private DoorStates _currentState;
private readonly BoxCollisionComponent _collisionComponent;
private readonly Rectangle _sourceRectangle;
private readonly CSprite _sprite;
private readonly string _strKey;
private readonly string _strPushKey;
private readonly string _pushItem;
private float _doorState;
private bool _wasUpdated;
public ObjDungeonDoor() : base("dungeon_door") { }
public ObjDungeonDoor(Map.Map map, int posX, int posY, int mode, string strKey, int direction, string strPushKey) : base(map)
{
_sourceRectangle = Resources.SourceRectangle("dungeon_door");
_strKey = strKey;
_strPushKey = strPushKey;
if (string.IsNullOrEmpty(_strKey))
{
IsDead = true;
return;
}
EntityPosition = new CPosition(posX, posY, 0);
EntitySize = new Rectangle(0, 0, 16, 16);
_collisionComponent = new BoxCollisionComponent(new CBox(posX, posY, 0, 16, 16, 16), Values.CollisionTypes.Normal);
_sprite = new CSprite(Resources.SprObjects, EntityPosition, Rectangle.Empty, new Vector2(8, 8));
_sprite.Center = new Vector2(8, 8);
_sprite.Rotation = (float)(Math.PI / 2 * (direction + 1));
if (!string.IsNullOrEmpty(_strKey))
AddComponent(KeyChangeListenerComponent.Index, new KeyChangeListenerComponent(KeyChanged));
AddComponent(CollisionComponent.Index, _collisionComponent);
AddComponent(UpdateComponent.Index, new UpdateComponent(Update));
AddComponent(DrawComponent.Index, new DrawCSpriteComponent(_sprite, Values.LayerBottom));
_sourceRectangle.X += mode * 16;
if (mode == 1)
_pushItem = "smallkey";
else if (mode == 3)
_pushItem = "nightmarekey";
if (mode == 1 || mode == 3)
{
var pushBox = new CBox(EntityPosition, 0, 0, 16, 16, 8);
AddComponent(PushableComponent.Index, new PushableComponent(pushBox, OnPush) { InertiaTime = 100 });
}
_sprite.SourceRectangle = _sourceRectangle;
}
private void Update()
{
_wasUpdated = true;
if (_currentState == DoorStates.Opening)
{
_doorState -= Game1.TimeMultiplier * 0.05f;
if (_doorState <= 0.5f)
_collisionComponent.IsActive = false;
if (_doorState <= 0)
{
_doorState = 0;
_currentState = DoorStates.Open;
}
}
else if (_currentState == DoorStates.Closing)
{
_doorState += Game1.TimeMultiplier * 0.1f;
if (_doorState >= 1)
{
_doorState = 1;
_currentState = DoorStates.Closed;
}
}
_sprite.SourceRectangle.Height = (int)Math.Round(16 * _doorState);
_sprite.SourceRectangle.Y = _sourceRectangle.Y + 16 - _sprite.SourceRectangle.Height;
_sprite.SpriteEffect = SpriteEffects.FlipHorizontally;
}
private bool OnPush(Vector2 direction, PushableComponent.PushType type)
{
if (type == PushableComponent.PushType.Impact || _currentState != DoorStates.Closed)
return false;
// remove one key
if (!Game1.GameManager.RemoveItem(_pushItem, 1))
{
// start a dialog if the player does not have the required item
Game1.GameManager.StartDialogPath("door_" + _pushItem);
return false;
}
// only play the sound effect when the player uses a key to open the door
Game1.GameManager.PlaySoundEffect("D378-04-04", false);
if (!string.IsNullOrEmpty(_strPushKey))
Game1.GameManager.SaveManager.SetString(_strPushKey, "1");
return true;
}
private void Open()
{
_currentState = DoorStates.Opening;
}
private void Close()
{
_currentState = DoorStates.Closing;
_collisionComponent.IsActive = true;
Game1.GameManager.PlaySoundEffect("D378-16-10", false);
}
private void KeyChanged()
{
// open/close the door if it is not already in the right state
// 1: open, 0: closed
var value = Game1.GameManager.SaveManager.GetString(_strKey);
var openDoor = value != null && value != "0";
if (_wasUpdated)
{
if (_currentState != DoorStates.Open && openDoor)
Open();
else if (_currentState != DoorStates.Closed && _currentState != DoorStates.Closing && !openDoor)
Close();
}
else
{
// set the door to open or closed
if (openDoor)
{
_currentState = DoorStates.Open;
_collisionComponent.IsActive = false;
_doorState = 0;
}
else
{
_currentState = DoorStates.Closed;
_collisionComponent.IsActive = true;
_doorState = 1;
}
}
}
}
}