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

226 lines
8.7 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.GameObjects.Base.Components.AI;
using ProjectZ.InGame.Map;
using ProjectZ.InGame.SaveLoad;
using ProjectZ.InGame.Things;
namespace ProjectZ.InGame.GameObjects.Enemies
{
internal class EnemyPincer : GameObject
{
private readonly CSprite _sprite;
private readonly Animator _animator;
private readonly AiComponent _aiComponent;
private readonly DamageFieldComponent _damageField;
private readonly BodyComponent _body;
private readonly AiStunnedState _stunnedState;
private readonly AiDamageState _damageState;
private readonly Rectangle _tailRectangle = new Rectangle(184, 124, 8, 8);
private readonly Vector2 _spawnPosition;
private Vector2 _direction;
private Vector2 _attackOffset;
private Vector2 _retractStartPosition;
private float _attackCounter;
private int _dirIndex;
public EnemyPincer() : base("pincer") { }
public EnemyPincer(Map.Map map, int posX, int posY) : base(map)
{
Tags = Values.GameObjectTag.Enemy;
EntityPosition = new CPosition(posX + 8, posY + 8, 0);
EntitySize = new Rectangle(-32, -32, 64, 64);
_spawnPosition = new Vector2(EntityPosition.X, EntityPosition.Y);
_animator = AnimatorSaveLoad.LoadAnimator("Enemies/pincer");
_animator.Play("eyes");
_sprite = new CSprite(EntityPosition) { IsVisible = false };
var animationComponent = new AnimationComponent(_animator, _sprite, new Vector2(-8, -8));
_body = new BodyComponent(EntityPosition, -6, -6, 12, 12, 8)
{
CollisionTypes = Values.CollisionTypes.None,
Drag = 0.75f,
IgnoreHoles = true
};
var stateWaiting = new AiState(UpdateWaiting);
var stateSpawning = new AiState(null);
stateSpawning.Trigger.Add(new AiTriggerCountdown(1000, null, ToAttack));
var stateAttacking = new AiState(UpdateAttack);
var stateAttackWait = new AiState(null);
stateAttackWait.Trigger.Add(new AiTriggerCountdown(1000, null, ToRetract));
var stateRetract = new AiState(UpdateRetract);
_aiComponent = new AiComponent();
_aiComponent.States.Add("waiting", stateWaiting);
_aiComponent.States.Add("spawning", stateSpawning);
_aiComponent.States.Add("attacking", stateAttacking);
_aiComponent.States.Add("attackWait", stateAttackWait);
_aiComponent.States.Add("retract", stateRetract);
_damageState = new AiDamageState(this, _body, _aiComponent, _sprite, 2, false) { HitMultiplierX = 1.5f, HitMultiplierY = 1.5f };
_stunnedState = new AiStunnedState(_aiComponent, animationComponent, 3300, 900);
_aiComponent.ChangeState("waiting");
var damageBox = new CBox(EntityPosition, -5, -5, 0, 10, 10, 4);
var hittableBox = new CBox(EntityPosition, -7, -7, 14, 14, 8);
AddComponent(PushableComponent.Index, new PushableComponent(hittableBox, OnPush));
AddComponent(BodyComponent.Index, _body);
AddComponent(DamageFieldComponent.Index, _damageField = new DamageFieldComponent(damageBox, HitType.Enemy, 2) { IsActive = false });
AddComponent(HittableComponent.Index, new HittableComponent(hittableBox, OnHit));
AddComponent(AiComponent.Index, _aiComponent);
AddComponent(BaseAnimationComponent.Index, animationComponent);
AddComponent(DrawComponent.Index, new DrawComponent(Draw, Values.LayerPlayer, EntityPosition));
}
private bool OnPush(Vector2 direction, PushableComponent.PushType type)
{
if (type == PushableComponent.PushType.Impact &&
(_aiComponent.CurrentStateId == "attacking" ||
_aiComponent.CurrentStateId == "attackWait" ||
_aiComponent.CurrentStateId == "retract" ||
_stunnedState.IsStunned()))
{
if (_aiComponent.CurrentStateId == "attacking")
_aiComponent.ChangeState("attackWait");
var mult = 1.5f;
_body.Velocity = new Vector3(direction.X * mult, direction.Y * mult, 0);
return true;
}
return false;
}
private Values.HitCollision OnHit(GameObject gameObject, Vector2 direction, HitType damageType, int damage, bool pieceOfPower)
{
if (damageType == HitType.MagicPowder)
{
_stunnedState.StartStun();
return Values.HitCollision.Enemy;
}
// can only attack while the enemy is attacking
if (_aiComponent.CurrentStateId != "attacking" &&
_aiComponent.CurrentStateId != "attackWait" &&
_aiComponent.CurrentStateId != "retract" &&
!_stunnedState.IsStunned())
return Values.HitCollision.None;
if (_aiComponent.CurrentStateId == "attacking")
_aiComponent.ChangeState("attackWait");
_damageState.OnHit(gameObject, direction, damageType, damage, pieceOfPower);
// make sure to not fly away like for other enemies
if (pieceOfPower)
_body.Drag = 0.75f;
return Values.HitCollision.Enemy;
}
private void ToWaiting()
{
_aiComponent.ChangeState("waiting");
_sprite.IsVisible = false;
_damageField.IsActive = false;
}
private void UpdateWaiting()
{
_direction = MapManager.ObjLink.EntityPosition.Position - new Vector2(EntityPosition.Position.X, EntityPosition.Position.Y - 4);
if (_direction.Length() < 42)
{
_aiComponent.ChangeState("spawning");
EntityPosition.Set(_spawnPosition);
_sprite.IsVisible = true;
_animator.Play("eyes");
}
}
private void ToAttack()
{
_damageField.IsActive = true;
_aiComponent.ChangeState("attacking");
GetAttackDirection();
}
private void UpdateAttack()
{
_attackCounter += (Game1.TimeMultiplier * 2) / 35.0f;
if (_attackCounter > 1)
_attackCounter = 1;
_attackOffset = _direction * _attackCounter * 35.0f;
EntityPosition.Set(_spawnPosition + _attackOffset);
if (_attackCounter >= 1)
_aiComponent.ChangeState("attackWait");
}
private void ToRetract()
{
_aiComponent.ChangeState("retract");
_retractStartPosition = EntityPosition.Position - _spawnPosition;
_attackCounter = 1;
}
private void UpdateRetract()
{
_attackCounter -= (Game1.TimeMultiplier * 1.25f) / 35.0f;
if (_attackCounter < 0)
_attackCounter = 0;
_attackOffset = Vector2.Lerp(_retractStartPosition, Vector2.Zero, 1 - _attackCounter);
EntityPosition.Set(_spawnPosition + _attackOffset);
if (_attackCounter <= 0)
ToWaiting();
}
private void Draw(SpriteBatch spriteBatch)
{
// draw the body
if (_sprite.IsVisible && _aiComponent.CurrentStateId != "spawning")
for (var i = 0; i < 3; i++)
{
var position =
_spawnPosition + (EntityPosition.Position - _spawnPosition) * (0.15f + (i / 2f) * 0.5f) - new Vector2(4, 4);
spriteBatch.Draw(Resources.SprEnemies, position, _tailRectangle, Color.White);
}
// draw the head
_sprite.Draw(spriteBatch);
}
private void GetAttackDirection()
{
_direction = MapManager.ObjLink.EntityPosition.Position - EntityPosition.Position;
if (_direction != Vector2.Zero)
_direction.Normalize();
var degree = MathHelper.ToDegrees((float)Math.Atan2(-_direction.Y, -_direction.X)) + 360;
_dirIndex = (int)((degree + 22.5f) / 45) % 8;
_animator.Play(_dirIndex.ToString());
}
}
}