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

263 lines
10 KiB
C#

using Microsoft.Xna.Framework;
using ProjectZ.InGame.GameObjects.Base;
using ProjectZ.InGame.GameObjects.Base.Components;
using ProjectZ.InGame.GameObjects.Base.CObjects;
using ProjectZ.InGame.SaveLoad;
using ProjectZ.InGame.Things;
using ProjectZ.InGame.GameObjects.Base.Components.AI;
using ProjectZ.InGame.Map;
using ProjectZ.InGame.GameObjects.Enemies;
using ProjectZ.InGame.GameObjects.Things;
namespace ProjectZ.InGame.GameObjects.Bosses
{
class BossFinalBossFireball : GameObject
{
private readonly BossFinalBoss _finalBoss;
private readonly CSprite _sprite;
private readonly BodyComponent _body;
private readonly Animator _animator;
private readonly AiComponent _aiComponent;
private readonly CBox _damageBox;
private ObjAnimator _objTrail0;
private ObjAnimator _objTrail1;
private bool _isMoving;
private bool _isRepelled;
private double _moveTime = 0;
private const double BlinkTime = 2000 / 60.0;
private const float Speed = 1.5f;
private bool _isReady;
private bool _damageState;
public bool IsReady { get => _isReady; }
public BossFinalBossFireball(BossFinalBoss boss, Vector2 position) : base(boss.Map)
{
_finalBoss = boss;
Tags = Values.GameObjectTag.Enemy;
EntityPosition = new CPosition(position.X, position.Y, 0);
EntitySize = new Rectangle(-8, -8, 16, 16);
_animator = AnimatorSaveLoad.LoadAnimator("Nightmares/nightmare fireball");
_sprite = new CSprite(EntityPosition);
var animationComponent = new AnimationComponent(_animator, _sprite, Vector2.Zero);
_body = new BodyComponent(EntityPosition, -3, -3, 6, 6, 8)
{
IgnoresZ = true,
IgnoreHoles = true
};
_aiComponent = new AiComponent();
var state0 = new AiState() { Init = () => _animator.Play("idle_0") };
state0.Trigger.Add(new AiTriggerCountdown(1100, null, () => _aiComponent.ChangeState("idle1")));
var state1 = new AiState() { Init = () => _animator.Play("idle_1") };
state1.Trigger.Add(new AiTriggerCountdown(1100, null, () => _aiComponent.ChangeState("idle2")));
var state2 = new AiState() { Init = () => _animator.Play("idle_2") };
state2.Trigger.Add(new AiTriggerCountdown(1100, null, () => _isReady = true));
var stateMoving = new AiState();
_aiComponent.States.Add("idle0", state0);
_aiComponent.States.Add("idle1", state1);
_aiComponent.States.Add("idle2", state2);
_aiComponent.States.Add("moving", stateMoving);
_aiComponent.ChangeState("idle0");
var damageCollider = new CBox(EntityPosition, -3, -3, 0, 6, 6, 8);
var hittableBox = new CBox(EntityPosition, -4, -4, 0, 8, 8, 8);
_damageBox = new CBox(EntityPosition, -4, -4, 0, 8, 8, 8);
AddComponent(DamageFieldComponent.Index, new DamageFieldComponent(damageCollider, HitType.Enemy, 2));
AddComponent(AiComponent.Index, _aiComponent);
AddComponent(BodyComponent.Index, _body);
AddComponent(PushableComponent.Index, new PushableComponent(_body.BodyBox, OnPush));
AddComponent(HittableComponent.Index, new HittableComponent(hittableBox, OnHit));
AddComponent(BaseAnimationComponent.Index, animationComponent);
AddComponent(UpdateComponent.Index, new UpdateComponent(Update));
AddComponent(DrawComponent.Index, new DrawCSpriteComponent(_sprite, Values.LayerTop));
}
public void Fire()
{
Game1.GameManager.PlaySoundEffect("D378-56-38");
_isMoving = true;
_aiComponent.ChangeState("moving");
if (Game1.RandomNumber.Next(0, 4) == 0)
{
_damageState = true;
_body.MoveCollision = OnMoveCollision;
_animator.Play("idle_3");
}
else
{
EntityPosition.AddPositionListener(typeof(BossFinalBossFireball), UpdateTrail);
_body.CollisionTypes = Values.CollisionTypes.None;
_animator.Play("idle_2");
SpawnTrail();
}
var playerDirection = new Vector2(MapManager.ObjLink.EntityPosition.X, MapManager.ObjLink.EntityPosition.Y - 4) - EntityPosition.Position;
if (playerDirection != Vector2.Zero)
{
playerDirection.Normalize();
_body.VelocityTarget = playerDirection * Speed;
}
}
private void Update()
{
if (_isMoving)
{
_moveTime += Game1.DeltaTime;
if (_isRepelled && _finalBoss.HitBoss(this, _body.VelocityTarget * 0.75f, _damageBox))
_moveTime = 1300;
// fade away
if (_moveTime > 1300)
{
_sprite.Color = Color.White * MathHelper.Clamp(1 - ((float)_moveTime - 1300) / 100, 0, 1);
if (_objTrail0 != null)
_objTrail0.Sprite.Color = Color.White * MathHelper.Clamp(1 - ((float)_moveTime - 1350) / 100, 0, 1);
if (_objTrail1 != null)
_objTrail1.Sprite.Color = Color.White * MathHelper.Clamp(1 - ((float)_moveTime - 1400) / 100, 0, 1);
}
if (_moveTime > 1500)
{
DeleteObject();
return;
}
}
// blink
var shader = Game1.TotalGameTime % (BlinkTime * 2) < BlinkTime ? Resources.DamageSpriteShader0 : null;
_sprite.SpriteShader = shader;
if (_objTrail0 != null)
_objTrail0.Sprite.SpriteShader = shader;
if (_objTrail1 != null)
_objTrail1.Sprite.SpriteShader = shader;
}
private void SpawnTrail()
{
_objTrail0 = new ObjAnimator(Map, (int)EntityPosition.X, (int)EntityPosition.Y, Values.LayerPlayer, "Nightmares/nightmare fireball", "idle_1", false);
_objTrail1 = new ObjAnimator(Map, (int)EntityPosition.X, (int)EntityPosition.Y, Values.LayerBottom, "Nightmares/nightmare fireball", "idle_0", false);
Map.Objects.SpawnObject(_objTrail0);
Map.Objects.SpawnObject(_objTrail1);
}
private void UpdateTrail(CPosition position)
{
var dist0 = _objTrail0.EntityPosition.Position - position.Position;
if (dist0.Length() > 7)
{
dist0.Normalize();
dist0 *= 7;
}
_objTrail0.EntityPosition.Set(EntityPosition.Position + dist0);
var dist1 = _objTrail1.EntityPosition.Position - _objTrail0.EntityPosition.Position;
if (dist1.Length() > 8)
{
dist1.Normalize();
dist1 *= 8;
}
_objTrail1.EntityPosition.Set(_objTrail0.EntityPosition.Position + dist1);
}
private void Repell()
{
Game1.GameManager.PlaySoundEffect("D378-56-38");
_isRepelled = true;
_moveTime = 0;
var playerDirection = EntityPosition.Position -
new Vector2(MapManager.ObjLink.EntityPosition.X, MapManager.ObjLink.EntityPosition.Y - 4);
if (playerDirection != Vector2.Zero)
playerDirection.Normalize();
_body.VelocityTarget = playerDirection * Speed;
}
private void OnMoveCollision(Values.BodyCollision collision)
{
OnDeath();
}
private Values.HitCollision OnHit(GameObject originObject, Vector2 direction, HitType type, int damage, bool pieceOfPower)
{
if ((type & HitType.Sword) == 0 || (type & HitType.SwordHold) != 0)
return Values.HitCollision.None;
// can not be hit before moving for a little while
if (_moveTime < 125)
return Values.HitCollision.None;
if (_damageState)
OnDeath();
else
Repell();
return Values.HitCollision.Enemy;
}
private bool OnPush(Vector2 direction, PushableComponent.PushType type)
{
if (_damageState && type == PushableComponent.PushType.Impact)
OnDeath();
return true;
}
private void OnDeath()
{
var posX = (int)EntityPosition.X;
var posY = (int)EntityPosition.Y;
var speed = 2.75f / 1.4f;
var objFireball0 = new EnemyFireball(Map, posX - 2, posY - 2, 1, false);
var objFireball1 = new EnemyFireball(Map, posX + 2, posY - 2, 1, false);
var objFireball2 = new EnemyFireball(Map, posX - 2, posY + 2, 1, false);
var objFireball3 = new EnemyFireball(Map, posX + 2, posY + 2, 1, false);
objFireball0.SetVelocity(new Vector2(-1, -1) * speed);
objFireball1.SetVelocity(new Vector2(1, -1) * speed);
objFireball2.SetVelocity(new Vector2(-1, 1) * speed);
objFireball3.SetVelocity(new Vector2(1, 1) * speed);
Map.Objects.SpawnObject(objFireball0);
Map.Objects.SpawnObject(objFireball1);
Map.Objects.SpawnObject(objFireball2);
Map.Objects.SpawnObject(objFireball3);
Map.Objects.DeleteObjects.Add(this);
}
private void DeleteObject()
{
if (_objTrail0 != null)
Map.Objects.DeleteObjects.Add(_objTrail0);
if (_objTrail1 != null)
Map.Objects.DeleteObjects.Add(_objTrail1);
Map.Objects.DeleteObjects.Add(this);
}
}
}