mirror of
https://github.com/Phantop/LADXHD.git
synced 2024-11-01 04:14:22 +00:00
360 lines
12 KiB
C#
360 lines
12 KiB
C#
|
using Microsoft.Xna.Framework;
|
||
|
using ProjectZ.InGame.GameObjects.Base;
|
||
|
using ProjectZ.InGame.GameObjects.Base.CObjects;
|
||
|
using ProjectZ.InGame.GameObjects.Base.Components;
|
||
|
using ProjectZ.InGame.GameObjects.Base.Components.AI;
|
||
|
using ProjectZ.InGame.Map;
|
||
|
using ProjectZ.InGame.SaveLoad;
|
||
|
using ProjectZ.InGame.Things;
|
||
|
using System;
|
||
|
|
||
|
namespace ProjectZ.InGame.GameObjects.NPCs
|
||
|
{
|
||
|
internal class ObjOwl : GameObject
|
||
|
{
|
||
|
private readonly CSprite _sprite;
|
||
|
private readonly BodyDrawComponent _drawComponent;
|
||
|
private readonly BodyDrawShadowComponent _drawShadowComponent;
|
||
|
private readonly AiComponent _aiComponent;
|
||
|
|
||
|
private Animator _animator;
|
||
|
private float _landingSpeed = 0.125f;
|
||
|
|
||
|
private CPosition _owlPosition;
|
||
|
|
||
|
// https://cubic-bezier.com/#.17,.67,.83,.67
|
||
|
private readonly CubicBezier _landingCurve = new CubicBezier(100, new Vector2(0.35f, 1f), new Vector2(0.8f, 1));
|
||
|
private readonly CubicBezier _leavingCurve = new CubicBezier(100, new Vector2(0.25f, 0.04f), new Vector2(0.35f, 0.11f));
|
||
|
|
||
|
private Vector3 _startPosition;
|
||
|
private Vector3 _landPosition;
|
||
|
private Vector3 _leavePosition;
|
||
|
|
||
|
private readonly string _strKey;
|
||
|
private readonly string _keyCondition;
|
||
|
|
||
|
private float _airCount;
|
||
|
private float _flySoundCount;
|
||
|
private int _enterTime = 2000;
|
||
|
|
||
|
private int originX;
|
||
|
private int originY;
|
||
|
|
||
|
private bool _isAlive;
|
||
|
private bool _wasTriggered;
|
||
|
private bool _triggerCollided;
|
||
|
|
||
|
private bool _hoverMode;
|
||
|
private double _hoverCounter;
|
||
|
|
||
|
private bool _sitMode;
|
||
|
private int _mode; // 0: leave after talking; 1: stay after talking; 2: spawn from the top
|
||
|
|
||
|
public ObjOwl() : base("owl") { }
|
||
|
|
||
|
public ObjOwl(Map.Map map, int posX, int posY, string keyCondition, Rectangle triggerRectangle, bool hoveMode, string strKey, int mode) : base(map)
|
||
|
{
|
||
|
_strKey = strKey;
|
||
|
_keyCondition = keyCondition;
|
||
|
_hoverMode = hoveMode;
|
||
|
_mode = mode;
|
||
|
|
||
|
// always gets updated
|
||
|
//EntityPosition = new CPosition(posX, posY, 0);
|
||
|
//EntitySize = new Rectangle(-16, -32, 48, 64);
|
||
|
|
||
|
originX = posX + 8;
|
||
|
originY = posY + 16;
|
||
|
|
||
|
_owlPosition = new CPosition(_startPosition.X, _startPosition.Y, _startPosition.Z);
|
||
|
|
||
|
var body = new BodyComponent(_owlPosition, -6, -8, 12, 8, 8)
|
||
|
{
|
||
|
IgnoresZ = true
|
||
|
};
|
||
|
|
||
|
_animator = AnimatorSaveLoad.LoadAnimator("NPCs/owl");
|
||
|
_sprite = new CSprite(_owlPosition);
|
||
|
|
||
|
var animationComponent = new AnimationComponent(_animator, _sprite, Vector2.Zero);
|
||
|
|
||
|
//var stateDebug = new AiState();
|
||
|
var stateWait = new AiState(UpdateWait);
|
||
|
var stateEnter = new AiState(UpdateEnter) { Init = InitEnter };
|
||
|
var stateTalk = new AiState(UpdateTalk) { Init = InitTalking };
|
||
|
var stateTalked = new AiState() { Init = InitTalked };
|
||
|
var stateLeave = new AiState(UpdateLeave) { Init = InitLeave };
|
||
|
var stateSit = new AiState(UpdateSit) { };
|
||
|
|
||
|
_aiComponent = new AiComponent();
|
||
|
//_aiComponent.States.Add("debug", stateDebug);
|
||
|
_aiComponent.States.Add("wait", stateWait);
|
||
|
_aiComponent.States.Add("enter", stateEnter);
|
||
|
_aiComponent.States.Add("talk", stateTalk);
|
||
|
_aiComponent.States.Add("talked", stateTalked);
|
||
|
_aiComponent.States.Add("leave", stateLeave);
|
||
|
_aiComponent.States.Add("sit", stateSit);
|
||
|
_aiComponent.ChangeState("wait");
|
||
|
|
||
|
AddComponent(BodyComponent.Index, body);
|
||
|
AddComponent(AiComponent.Index, _aiComponent);
|
||
|
AddComponent(BaseAnimationComponent.Index, animationComponent);
|
||
|
AddComponent(DrawComponent.Index, _drawComponent = new BodyDrawComponent(body, _sprite, Values.LayerPlayer));
|
||
|
AddComponent(DrawShadowComponent.Index, _drawShadowComponent = new BodyDrawShadowComponent(body, _sprite) { OffsetY = 0 });
|
||
|
var enterRectangle = new Rectangle(posX + 8 + triggerRectangle.X, posY + 8 + triggerRectangle.Y, triggerRectangle.Width, triggerRectangle.Height);
|
||
|
AddComponent(ObjectCollisionComponent.Index, new ObjectCollisionComponent(enterRectangle, OnCollision));
|
||
|
|
||
|
_sprite.Color = Color.Transparent;
|
||
|
_drawComponent.IsActive = false;
|
||
|
_drawShadowComponent.IsActive = false;
|
||
|
|
||
|
// sitting infront of the egg
|
||
|
if (mode == 2)
|
||
|
{
|
||
|
if (Game1.GameManager.SaveManager.GetString(_keyCondition, "0") == "1")
|
||
|
{
|
||
|
IsDead = true;
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
_isAlive = true;
|
||
|
_sitMode = true;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
AddComponent(KeyChangeListenerComponent.Index, new KeyChangeListenerComponent(KeyChanged));
|
||
|
|
||
|
// add key change listener to activate/deactivate the owl
|
||
|
if (!string.IsNullOrEmpty(_keyCondition))
|
||
|
KeyChanged();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private void KeyChanged()
|
||
|
{
|
||
|
var value = Game1.GameManager.SaveManager.GetString(_strKey, "0");
|
||
|
_isAlive = value == _keyCondition;
|
||
|
}
|
||
|
|
||
|
private void OnCollision(GameObject gameObject)
|
||
|
{
|
||
|
if (!_wasTriggered && _isAlive)
|
||
|
_triggerCollided = true;
|
||
|
}
|
||
|
|
||
|
private void UpdateSit()
|
||
|
{
|
||
|
var playerDirection = MapManager.ObjLink.EntityPosition.Position - _owlPosition.Position;
|
||
|
if (playerDirection.Length() < 64 && MapManager.ObjLink.IsGrounded())
|
||
|
{
|
||
|
// start playing owl music
|
||
|
Game1.GameManager.SetMusic(33, 2);
|
||
|
|
||
|
_leavePosition = new Vector3(originX, originY - 90, 90);
|
||
|
_aiComponent.ChangeState("talk");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private void UpdateWait()
|
||
|
{
|
||
|
if (_triggerCollided && !MapManager.ObjLink.IsRailJumping() && !MapManager.ObjLink.IsTransitioning)
|
||
|
_aiComponent.ChangeState("enter");
|
||
|
}
|
||
|
|
||
|
private void InitEnter()
|
||
|
{
|
||
|
if (_wasTriggered)
|
||
|
return;
|
||
|
|
||
|
if (_hoverMode)
|
||
|
{
|
||
|
_animator.Play("hover");
|
||
|
|
||
|
_startPosition = new Vector3(originX, originY - 64, 64);
|
||
|
_landPosition = new Vector3(originX, originY, 0);
|
||
|
_leavePosition = new Vector3(originX, originY - 64, 64);
|
||
|
}
|
||
|
else if (_mode == 2)
|
||
|
{
|
||
|
_animator.Play("fly");
|
||
|
|
||
|
_startPosition = new Vector3(originX, originY - 64, 64);
|
||
|
_landPosition = new Vector3(originX, originY, 0);
|
||
|
_leavePosition = new Vector3(originX, originY - 64, 64);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
_animator.Play("fly");
|
||
|
|
||
|
_startPosition = new Vector3(originX - 64, originY - 64, 64);
|
||
|
_landPosition = new Vector3(originX, originY, 0);
|
||
|
_leavePosition = new Vector3(originX + 64, originY - 64, 64);
|
||
|
}
|
||
|
|
||
|
_airCount = 0;
|
||
|
_flySoundCount = 0;
|
||
|
|
||
|
// start playing owl music; not in the final scene
|
||
|
if (Game1.GameManager.GetCurrentMusic() != 88)
|
||
|
Game1.GameManager.SetMusic(33, 2);
|
||
|
|
||
|
MapManager.ObjLink.FreezePlayer();
|
||
|
_wasTriggered = true;
|
||
|
|
||
|
_drawComponent.IsActive = true;
|
||
|
|
||
|
if (!_hoverMode)
|
||
|
_drawShadowComponent.IsActive = true;
|
||
|
}
|
||
|
|
||
|
private void UpdateEnter()
|
||
|
{
|
||
|
MapManager.ObjLink.FreezePlayer();
|
||
|
|
||
|
_airCount += Game1.DeltaTime;
|
||
|
|
||
|
_flySoundCount -= Game1.DeltaTime;
|
||
|
if (_flySoundCount < 0)
|
||
|
{
|
||
|
_flySoundCount = 500;
|
||
|
Game1.GameManager.PlaySoundEffect("D378-45-2D", false);
|
||
|
}
|
||
|
|
||
|
if (_airCount > _enterTime)
|
||
|
_airCount = _enterTime;
|
||
|
|
||
|
var time = _airCount / _enterTime;
|
||
|
if (_airCount < _enterTime)
|
||
|
{
|
||
|
var currentPosition = Vector3.Lerp(_startPosition, _landPosition, _landingCurve.EvaluateX(time));
|
||
|
_owlPosition.Set(currentPosition);
|
||
|
|
||
|
if (!_hoverMode && time > 0.9)
|
||
|
_animator.Play("idle");
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (!_hoverMode)
|
||
|
_animator.Play("idle");
|
||
|
|
||
|
_owlPosition.Set(_landPosition);
|
||
|
|
||
|
_aiComponent.ChangeState("talk");
|
||
|
}
|
||
|
|
||
|
// player looks at the owl
|
||
|
if (_airCount > _enterTime - 1000)
|
||
|
{
|
||
|
var playerDir = _owlPosition.Position - MapManager.ObjLink.EntityPosition.Position;
|
||
|
MapManager.ObjLink.Direction = AnimationHelper.GetDirection(playerDir);
|
||
|
}
|
||
|
|
||
|
// fade in
|
||
|
if (time <= 0.1f)
|
||
|
_sprite.Color = Color.White * (time / 0.1f);
|
||
|
else
|
||
|
_sprite.Color = Color.White;
|
||
|
}
|
||
|
|
||
|
private void InitTalking()
|
||
|
{
|
||
|
_hoverCounter = 0;
|
||
|
|
||
|
if (_sitMode)
|
||
|
Game1.GameManager.StartDialogPath(_keyCondition);
|
||
|
else
|
||
|
Game1.GameManager.StartDialogPath(_strKey);
|
||
|
|
||
|
Game1.GameManager.InGameOverlay.TextboxOverlay.OwlMode = true;
|
||
|
}
|
||
|
|
||
|
private void UpdateTalk()
|
||
|
{
|
||
|
MapManager.ObjLink.FreezePlayer();
|
||
|
|
||
|
// hover up/down
|
||
|
if (_hoverMode)
|
||
|
{
|
||
|
_hoverCounter += Game1.DeltaTime;
|
||
|
|
||
|
var hoverPosition = _landPosition;
|
||
|
hoverPosition.Y -= MathF.Sin((GetHoverState((float)_hoverCounter / 1000f, 0.0f) - 0.0f) * MathF.PI * 2 - MathF.PI / 2) * 3 + 3;
|
||
|
_owlPosition.Set(hoverPosition);
|
||
|
}
|
||
|
|
||
|
// leave of just sit there
|
||
|
if (!Game1.GameManager.InGameOverlay.TextboxOverlay.IsOpen)
|
||
|
_aiComponent.ChangeState((_mode == 0 || _mode == 2) ? "leave" : "talked");
|
||
|
}
|
||
|
|
||
|
private float GetHoverState(float _hoverCounter, float startPercentage)
|
||
|
{
|
||
|
// gradient up to 0.5f
|
||
|
var gradient = 0.9f;
|
||
|
// time needed to reach 0.5f
|
||
|
var timeX = 0.5f * gradient;
|
||
|
|
||
|
_hoverCounter += startPercentage * gradient;
|
||
|
_hoverCounter %= 1;
|
||
|
|
||
|
if (_hoverCounter < timeX)
|
||
|
return _hoverCounter / gradient;
|
||
|
else
|
||
|
return timeX / gradient + (1 - timeX / gradient) * (_hoverCounter - timeX) / (1 - timeX);
|
||
|
}
|
||
|
|
||
|
private void InitLeave()
|
||
|
{
|
||
|
_airCount = 0;
|
||
|
_landPosition.X = _owlPosition.X;
|
||
|
_landPosition.Y = _owlPosition.Y;
|
||
|
|
||
|
if (!_hoverMode)
|
||
|
{
|
||
|
_animator.Play("fly");
|
||
|
_animator.SpeedMultiplier = 1.5f;
|
||
|
}
|
||
|
|
||
|
// stop playing music
|
||
|
Game1.GameManager.SetMusic(-1, 2);
|
||
|
}
|
||
|
|
||
|
private void UpdateLeave()
|
||
|
{
|
||
|
_flySoundCount -= Game1.DeltaTime;
|
||
|
if (_flySoundCount < 0)
|
||
|
{
|
||
|
_flySoundCount = 175;
|
||
|
Game1.GameManager.PlaySoundEffect("D378-05-05");
|
||
|
}
|
||
|
|
||
|
_airCount += Game1.DeltaTime;
|
||
|
|
||
|
if (_airCount > _enterTime)
|
||
|
_airCount = _enterTime;
|
||
|
|
||
|
var time = _airCount / (float)_enterTime;
|
||
|
if (_airCount < _enterTime)
|
||
|
{
|
||
|
var currentPosition = Vector3.Lerp(_landPosition, _leavePosition, _leavingCurve.EvaluateX(time));
|
||
|
_owlPosition.Set(currentPosition);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
Map.Objects.DeleteObjects.Add(this);
|
||
|
}
|
||
|
|
||
|
// fade out
|
||
|
if (time >= 0.9f)
|
||
|
_sprite.Color = Color.White * ((1 - time) / 0.1f);
|
||
|
else
|
||
|
_sprite.Color = Color.White;
|
||
|
}
|
||
|
|
||
|
private void InitTalked()
|
||
|
{
|
||
|
// stop playing music
|
||
|
Game1.GameManager.SetMusic(-1, 2);
|
||
|
}
|
||
|
}
|
||
|
}
|