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

172 lines
6.8 KiB
C#

using Microsoft.Xna.Framework;
using ProjectZ.Base;
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.SaveLoad;
using ProjectZ.InGame.Things;
namespace ProjectZ.InGame.GameObjects.Enemies
{
internal class EnemyOctorokShot : GameObject
{
private readonly AiComponent _aiComponent;
private readonly ShadowBodyDrawComponent _shadowBody;
private readonly DamageFieldComponent _damageField;
private readonly CSprite _drawComponent;
private readonly BodyComponent _body;
private readonly PushableComponent _pushableComponent;
private float _lifeCounter = 950;
private float _despawnPercentage = 1;
private int _despawnTime = 750;
private bool _repelledPlayer;
public EnemyOctorokShot(Map.Map map, float posX, float posY, Vector2 velocity) : base(map)
{
Tags = Values.GameObjectTag.Enemy;
EntityPosition = new CPosition(posX, posY, 2);
EntitySize = new Rectangle(-5, -12, 10, 12);
// abort spawn in a wall
var box = Box.Empty;
if (Map.Objects.Collision(new Box(EntityPosition.X - 4, EntityPosition.Y - 8, 0, 8, 8, 8),
Box.Empty, Values.CollisionTypes.Normal, 0, 0, ref box))
{
IsDead = true;
return;
}
var animator = AnimatorSaveLoad.LoadAnimator("Enemies/octorok shot");
animator.Play("idle");
_drawComponent = new CSprite(EntityPosition);
var animationComponent = new AnimationComponent(animator, _drawComponent, new Vector2(-5, -10));
_body = new BodyComponent(EntityPosition, -4, -8, 8, 8, 8)
{
CollisionTypes = Values.CollisionTypes.Normal,
MoveCollision = OnCollision,
VelocityTarget = velocity,
Bounciness = 0.35f,
Drag = 0.75f,
IgnoreHeight = true,
IgnoresZ = true,
IgnoreInsideCollision = false,
};
var stateIdle = new AiState(UpdateIdle);
var stateDespawn = new AiState() { Init = InitDespawn };
stateDespawn.Trigger.Add(new AiTriggerCountdown(_despawnTime, Despawn, () => Despawn(0)));
_aiComponent = new AiComponent();
_aiComponent.States.Add("idle", stateIdle);
_aiComponent.States.Add("despawn", stateDespawn);
_aiComponent.ChangeState("idle");
var damageCollider = new CBox(EntityPosition, -5, -10, 0, 10, 10, 4);
AddComponent(DamageFieldComponent.Index, _damageField = new DamageFieldComponent(damageCollider, HitType.Enemy, 2) { OnDamage = OnDamage });
AddComponent(HittableComponent.Index, new HittableComponent(_body.BodyBox, OnHit));
AddComponent(BodyComponent.Index, _body);
AddComponent(PushableComponent.Index, _pushableComponent = new PushableComponent(_body.BodyBox, OnPush) { RepelMultiplier = 0.35f });
AddComponent(AiComponent.Index, _aiComponent);
AddComponent(BaseAnimationComponent.Index, animationComponent);
AddComponent(DrawComponent.Index, new BodyDrawComponent(_body, _drawComponent, Values.LayerPlayer));
AddComponent(DrawShadowComponent.Index, _shadowBody = new ShadowBodyDrawComponent(EntityPosition));
}
private void InitDespawn()
{
_pushableComponent.IsActive = false;
_body.IgnoresZ = false;
_damageField.IsActive = false;
Game1.GameManager.PlaySoundEffect("D360-07-07");
}
private void UpdateIdle()
{
_lifeCounter -= Game1.DeltaTime;
if (_lifeCounter < 0)
{
_body.IsGrounded = false;
_body.IgnoresZ = false;
_body.Gravity = -0.125f;
_body.Bounciness = 0.75f;
_body.Drag = 0.9f;
_body.Velocity = new Vector3(_body.VelocityTarget.X, _body.VelocityTarget.Y, 0);
_body.VelocityTarget = Vector2.Zero;
_aiComponent.ChangeState("despawn");
}
}
private void Despawn(double time)
{
_despawnPercentage = (float)(time / (_despawnTime / 3));
if (_despawnPercentage > 1)
_despawnPercentage = 1;
_drawComponent.Color = Color.White * _despawnPercentage;
_shadowBody.Transparency = _despawnPercentage;
if (time <= 0)
Map.Objects.DeleteObjects.Add(this);
}
private bool OnDamage()
{
_aiComponent.ChangeState("despawn");
_body.Velocity = new Vector3(-_body.VelocityTarget.X * 0.25f, -_body.VelocityTarget.Y * 0.25f, 1.5f);
_body.VelocityTarget = Vector2.Zero;
return _damageField.DamagePlayer();
}
private bool OnPush(Vector2 direction, PushableComponent.PushType type)
{
if (_aiComponent.CurrentStateId != "despawn")
_aiComponent.ChangeState("despawn");
else if (_repelledPlayer)
return false;
else
{
// it is possible that we despawn because of OnDamage in the same frame
// we need to make sure to still repell the player
_repelledPlayer = true;
return _repelledPlayer;
}
_body.Velocity = new Vector3(direction.X * 0.25f, direction.Y * 0.25f, 1.5f);
_body.VelocityTarget = Vector2.Zero;
return true;
}
private Values.HitCollision OnHit(GameObject gameObject, Vector2 direction, HitType damageType, int damage, bool pieceOfPower)
{
if (_aiComponent.CurrentStateId != "despawn")
_aiComponent.ChangeState("despawn");
else
return Values.HitCollision.None;
_body.Velocity = new Vector3(direction.X, direction.Y, 1.5f);
_body.VelocityTarget = Vector2.Zero;
return Values.HitCollision.Enemy;
}
private void OnCollision(Values.BodyCollision direction)
{
if (direction == Values.BodyCollision.Floor)
return;
if (_aiComponent.CurrentStateId != "despawn")
_aiComponent.ChangeState("despawn");
_body.Velocity = new Vector3(-_body.VelocityTarget.X * 0.25f, -_body.VelocityTarget.Y * 0.25f, 1.5f);
_body.VelocityTarget = Vector2.Zero;
}
}
}