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

237 lines
8.8 KiB
C#

using Microsoft.Xna.Framework;
using ProjectZ.InGame.GameObjects.Base;
using ProjectZ.InGame.GameObjects.Base.Components;
using ProjectZ.InGame.GameObjects.Base.Components.AI;
using ProjectZ.InGame.GameObjects.Base.CObjects;
using ProjectZ.InGame.GameObjects.Things;
using ProjectZ.InGame.Map;
using ProjectZ.InGame.SaveLoad;
using ProjectZ.InGame.Things;
namespace ProjectZ.InGame.GameObjects.Enemies
{
internal class EnemyMadBomber : GameObject
{
private readonly AiComponent _aiComponent;
private readonly Animator _animator;
private readonly CSprite _sprite;
private readonly AiDamageState _damageState;
private readonly AiStunnedState _aiStunnedState;
private readonly DamageFieldComponent _damageField;
private readonly Vector2[] _holeOffsets = {
new Vector2(0, 0), new Vector2(3, -1), new Vector2(-3, -1),
new Vector2(0, -3), new Vector2(-2, 2), new Vector2(2, 2)
};
private const string _leafSaveKey = "ow_goldLeafMadBomber";
private readonly Vector2 _spawnPosition;
private bool _wasHit;
public EnemyMadBomber() : base("madBomber") { }
public EnemyMadBomber(Map.Map map, int posX, int posY) : base(map)
{
// abort spawn if the player already has the leaf
if (Game1.GameManager.SaveManager.GetString(_leafSaveKey) == "1")
{
IsDead = true;
return;
}
Tags = Values.GameObjectTag.Enemy;
EntityPosition = new CPosition(posX + 8, posY + 15, 0);
EntitySize = new Rectangle(-8, -15, 16, 16);
_spawnPosition = new Vector2(posX + 8, posY + 15);
_animator = AnimatorSaveLoad.LoadAnimator("Enemies/mad bomber");
_sprite = new CSprite(EntityPosition) { IsVisible = false };
var animationComponent = new AnimationComponent(_animator, _sprite, new Vector2(-8, -15));
var body = new BodyComponent(EntityPosition, -7, -14, 14, 14, 8)
{
IgnoreHoles = true
};
var stateCooldown = new AiState();
stateCooldown.Trigger.Add(new AiTriggerRandomTime(() => _aiComponent.ChangeState("hidden"), 1000, 1500));
var stateHidden = new AiState(UpdateHidden);
var stateComing = new AiState(UpdateComing);
var stateLeaving = new AiState(UpdateLeaving);
_aiComponent = new AiComponent();
_aiComponent.States.Add("cooldown", stateCooldown);
_aiComponent.States.Add("hidden", stateHidden);
_aiComponent.States.Add("coming", stateComing);
_aiComponent.States.Add("leaving", stateLeaving);
_aiStunnedState = new AiStunnedState(_aiComponent, animationComponent, 3300, 900);
_aiComponent.ChangeState("hidden");
_damageState = new AiDamageState(this, body, _aiComponent, _sprite, 4, false)
{
IsActive = false,
SpawnItems = false,
HitMultiplierX = 0,
HitMultiplierY = 0,
OnDeath = OnDeath
};
var damageBox = new CBox(EntityPosition, -7, -14, 0, 14, 14, 8);
AddComponent(DamageFieldComponent.Index, _damageField = new DamageFieldComponent(damageBox, HitType.Enemy, 2));
AddComponent(HittableComponent.Index, new HittableComponent(body.BodyBox, OnHit));
AddComponent(BodyComponent.Index, body);
AddComponent(AiComponent.Index, _aiComponent);
AddComponent(BaseAnimationComponent.Index, animationComponent);
AddComponent(DrawComponent.Index, new BodyDrawComponent(body, _sprite, Values.LayerPlayer));
}
private void OnDeath(bool pieceofpower)
{
var playerDirection = MapManager.ObjLink.EntityPosition.Position - EntityPosition.Position;
if (playerDirection != Vector2.Zero)
playerDirection.Normalize();
playerDirection *= 2.25f;
// spawn the golden leaf jumping towards the player
var objLeaf = new ObjItem(Map, 0, 0, null, _leafSaveKey, "goldLeaf", null);
objLeaf.EntityPosition.Set(new Vector3(EntityPosition.X, EntityPosition.Y + 1, 1));
objLeaf.SetVelocity(new Vector3(playerDirection.X, playerDirection.Y, 1.5f));
objLeaf.Collectable = false;
Map.Objects.SpawnObject(objLeaf);
_damageState.BaseOnDeath(pieceofpower);
}
private Values.HitCollision OnHit(GameObject gameObject, Vector2 direction, HitType damageType, int damage, bool pieceOfPower)
{
if (_damageState.IsInDamageState())
return Values.HitCollision.None;
if (_aiComponent.CurrentStateId == "coming")
_wasHit = true;
// stun state
if (damageType == HitType.Hookshot)
{
_damageState.SetDamageState(false);
_aiStunnedState.StartStun();
_animator.Pause();
return Values.HitCollision.Enemy;
}
if (damageType == HitType.Bow || damageType == HitType.MagicRod)
damage = 1;
if (damageType == HitType.MagicPowder || damageType == HitType.Boomerang)
damage = 0;
var hitReturn = _damageState.OnHit(gameObject, direction, damageType, damage, pieceOfPower);
// make sure to not disapear while moving out of the hole with piece of power active
if (_damageState.CurrentLives <= 0)
{
_animator.Pause();
_damageState.HasDamageState = true;
}
return hitReturn;
}
private void ToCooldown()
{
_aiComponent.ChangeState("cooldown");
_sprite.IsVisible = false;
}
private void UpdateHidden()
{
// only spawn if the player is close enough
var playerDirection = MapManager.ObjLink.EntityPosition.Position - new Vector2(_spawnPosition.X, _spawnPosition.Y - 15);
if (playerDirection.Length() < 64)
ToComing();
}
private void ToComing()
{
// find a hole to come out
var tryCounter = 0;
while (tryCounter < 10)
{
tryCounter++;
var randomNum = Game1.RandomNumber.Next(0, _holeOffsets.Length);
var holePosition = _spawnPosition + _holeOffsets[randomNum] * 16;
// check the distance to not spawn next to the player
var direction = MapManager.ObjLink.EntityPosition.Position - holePosition;
if (direction.Length() > 48)
{
_aiComponent.ChangeState("coming");
EntityPosition.Set(holePosition);
var playerOnTheRight = EntityPosition.X < MapManager.ObjLink.EntityPosition.X;
_animator.Play(playerOnTheRight ? "come_1" : "come_0");
_sprite.IsVisible = true;
_damageState.IsActive = true;
_damageField.IsActive = true;
_wasHit = false;
return;
}
}
}
private void UpdateComing()
{
// finished the enter animation
if (!_animator.IsPlaying)
{
if (!_wasHit)
ThrowBomb();
ToLeaving();
}
}
private void ToLeaving()
{
_aiComponent.ChangeState("leaving");
_animator.Play("leave");
_damageState.IsActive = false;
_damageField.IsActive = false;
}
private void ThrowBomb()
{
var throwDirection = MapManager.ObjLink.EntityPosition.Position - EntityPosition.Position;
if (throwDirection != Vector2.Zero)
throwDirection.Normalize();
throwDirection *= 0.8f;
// spawn a bomb
var bomb = new ObjBomb(Map, 0, 0, false, true);
bomb.EntityPosition.Set(new Vector3(EntityPosition.X, EntityPosition.Y + 1, 6));
bomb.Body.Velocity = new Vector3(throwDirection.X, throwDirection.Y, 1.5f);
bomb.Body.Gravity = -0.1f;
bomb.Body.DragAir = 1.0f;
bomb.Body.Bounciness = 0.25f;
Map.Objects.SpawnObject(bomb);
Game1.GameManager.PlaySoundEffect("D360-08-08");
}
private void UpdateLeaving()
{
if (!_animator.IsPlaying)
ToCooldown();
}
}
}