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

215 lines
8.1 KiB
C#

using System;
using Microsoft.Xna.Framework;
using ProjectZ.InGame.GameObjects.Base;
using ProjectZ.InGame.GameObjects.Base.Components;
using ProjectZ.InGame.GameObjects.Base.CObjects;
using ProjectZ.InGame.GameObjects.Base.Components.AI;
using ProjectZ.InGame.GameObjects.Things;
using ProjectZ.InGame.Map;
using ProjectZ.InGame.SaveLoad;
using ProjectZ.InGame.Things;
namespace ProjectZ.InGame.GameObjects.Enemies
{
internal class EnemyCheepCheep : GameObject
{
private readonly BodyComponent _body;
private readonly AiComponent _aiComponent;
private readonly AiDamageState _damageState;
private readonly Animator _animator;
private readonly CBox _damageBox;
private readonly CBox _headJumpBox;
private Vector2 _jumpStart;
private const int JumpTime = 1500;
private readonly float _movementSpeed;
private int _dir;
private readonly bool _canJump;
public EnemyCheepCheep() : base("cheep cheep") { }
public EnemyCheepCheep(Map.Map map, int posX, int posY, int dir, bool canJump) : base(map)
{
Tags = Values.GameObjectTag.Enemy;
EntityPosition = new CPosition(posX + 8, posY + 16, 0);
EntitySize = new Rectangle(-8, -16, 16, 16);
_dir = dir;
_canJump = canJump;
_movementSpeed = canJump ? 0.75f : 0.5f;
_animator = AnimatorSaveLoad.LoadAnimator("Enemies/cheep cheep");
var sprite = new CSprite(EntityPosition);
var animationComponent = new AnimationComponent(_animator, sprite, new Vector2(-8, -16));
_body = new BodyComponent(EntityPosition, -8, -12, 16, 10, 8)
{
MoveCollision = OnCollision,
AvoidTypes = Values.CollisionTypes.NPCWall,
CollisionTypes =
Values.CollisionTypes.Normal,
FieldRectangle = map.GetField(posX, posY),
DragAir = 0.8f,
Gravity2DWater = 0f
};
var stateMoving = new AiState();
if (_canJump)
{
stateMoving.Trigger.Add(new AiTriggerRandomTime(ToMoving, 350, 1250));
stateMoving.Trigger.Add(new AiTriggerRandomTime(ToJump, 750, 1250));
}
var statePause = new AiState();
statePause.Trigger.Add(new AiTriggerCountdown(700, null, ToMoving));
var stateJumping = new AiState();
stateJumping.Trigger.Add(new AiTriggerCountdown(JumpTime, UpdateJump, EndJump));
var stateDead = new AiState(UpdateDeath);
_aiComponent = new AiComponent();
_aiComponent.States.Add("moving", stateMoving);
_aiComponent.States.Add("pause", statePause);
_aiComponent.States.Add("jumping", stateJumping);
_aiComponent.States.Add("dead", stateDead);
_damageState = new AiDamageState(this, _body, _aiComponent, sprite, 1)
{
HitMultiplierX = 3.0f,
HitMultiplierY = 2.0f,
FlameOffset = new Point(0, 2),
OnBurn = () => _animator.Pause()
};
ToMoving();
var hittableBox = new CBox(EntityPosition, -8, -14, 0, 16, 12, 8);
_damageBox = new CBox(EntityPosition, -6, -14, 0, 12, 12, 4);
_headJumpBox = new CBox(EntityPosition, -6, -16, 0, 12, 6, 8);
AddComponent(DamageFieldComponent.Index, new DamageFieldComponent(_damageBox, HitType.Enemy, 2));
AddComponent(HittableComponent.Index, new HittableComponent(hittableBox, OnHit));
AddComponent(BodyComponent.Index, _body);
AddComponent(AiComponent.Index, _aiComponent);
AddComponent(BaseAnimationComponent.Index, animationComponent);
AddComponent(DrawComponent.Index, new BodyDrawComponent(_body, sprite, Values.LayerPlayer));
}
private Values.HitCollision OnHit(GameObject originObject, Vector2 direction, HitType type, int damage, bool pieceOfPower)
{
_body.IgnoresZ = false;
return _damageState.OnHit(originObject, direction, type, damage, pieceOfPower);
}
public override void Init()
{
// look into the direction of the player
if (_dir % 2 != 0 && MapManager.ObjLink.NextMapPositionStart != null)
_animator.Play("idle_" + (EntityPosition.X > MapManager.ObjLink.NextMapPositionStart.Value.X ? 0 : 2));
}
private void ToMoving()
{
_aiComponent.ChangeState("moving");
_body.VelocityTarget = AnimationHelper.DirectionOffset[_dir] * _movementSpeed;
// update the animation if the fish is going to the left or right
if (_dir % 2 == 0)
_animator.Play("idle_" + _dir);
_dir = (_dir + 2) % 4;
}
private void ToPausing()
{
_aiComponent.ChangeState("pause");
_body.VelocityTarget = Vector2.Zero;
}
private void ToJump()
{
_body.IgnoresZ = true;
_body.VelocityTarget = Vector2.Zero;
_aiComponent.ChangeState("jumping");
Game1.GameManager.PlaySoundEffect("D360-36-24");
// scale down the damage box
_damageBox.OffsetY += 8;
_damageBox.Box.Height -= 8;
_jumpStart = EntityPosition.Position;
// splash animation
var position = new Point((int)_jumpStart.X, (int)_jumpStart.Y);
var splashAnimator = new ObjAnimator(_body.Owner.Map, position.X, position.Y - 14, 0, 3, 1, "Particles/fishingSplash", "idle", true);
Map.Objects.SpawnObject(splashAnimator);
}
private void UpdateJump(double time)
{
var newPosition = _jumpStart - new Vector2(0, 64) * MathF.Sin((float)(time / JumpTime) * MathF.PI);
EntityPosition.Set(newPosition);
// player jumped on the fish?
if ((MapManager.ObjLink._body.Velocity.Y > 0 && !MapManager.ObjLink._body.IsGrounded || time > JumpTime / 2) &&
_headJumpBox.Box.Bottom >= MapManager.ObjLink._body.BodyBox.Box.Bottom &&
_headJumpBox.Box.Intersects(MapManager.ObjLink._body.BodyBox.Box))
{
Game1.GameManager.PlaySoundEffect("D370-14-0E");
MapManager.ObjLink._body.Velocity.Y -= 1f;
_aiComponent.ChangeState("dead");
_animator.Play("dead_" + _dir);
_body.VelocityTarget = Vector2.Zero;
_body.IgnoresZ = false;
_body.Gravity2DWater = 0.05f;
_body.CollisionTypes = Values.CollisionTypes.None;
}
}
private void EndJump()
{
// scale up the damage box
_damageBox.OffsetY -= 8;
_damageBox.Box.Height += 8;
_body.IgnoresZ = false;
UpdateJump(JumpTime);
ToMoving();
}
private void UpdateDeath()
{
if ((_body.CurrentFieldState & MapStates.FieldStates.DeepWater) != 0)
_body.CollisionTypes = Values.CollisionTypes.Normal;
}
private void OnCollision(Values.BodyCollision direction)
{
// kill the fish when it reaches the ground
if (_aiComponent.CurrentStateId == "dead" &&
(direction & Values.BodyCollision.Vertical) != 0)
{
_damageState.OnHit(MapManager.ObjLink, new Vector2(0, 1), HitType.Sword1, 1, false);
return;
}
if ((direction & Values.BodyCollision.Vertical) != 0)
_body.Velocity.Y = 0;
if (_aiComponent.CurrentStateId != "moving")
return;
if (_canJump)
ToMoving();
else
ToPausing();
}
}
}