mirror of
https://github.com/Phantop/LADXHD.git
synced 2024-11-30 10:04:11 +00:00
246 lines
10 KiB
C#
246 lines
10 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;
|
|
using ProjectZ.InGame.GameObjects.Dungeon;
|
|
|
|
namespace ProjectZ.InGame.GameObjects.Enemies
|
|
{
|
|
internal class EnemyBonePutter : GameObject
|
|
{
|
|
private readonly BodyComponent _body;
|
|
private readonly AiComponent _aiComponent;
|
|
private readonly Animator _animator;
|
|
private readonly AnimationComponent _animatorComponent;
|
|
private readonly AiDamageState _damageState;
|
|
|
|
private readonly Vector2 _roomCenter;
|
|
private Vector2 _startPosition;
|
|
private Vector2 _targetPosition;
|
|
private float _flyCounter;
|
|
private float _flyTime;
|
|
private int _bombThrowCounter;
|
|
|
|
private const float JumpSpeed = 0.25f;
|
|
|
|
public EnemyBonePutter() : base("bone putter") { }
|
|
|
|
public EnemyBonePutter(Map.Map map, int posX, int posY, bool hasWings) : base(map)
|
|
{
|
|
Tags = Values.GameObjectTag.Enemy;
|
|
|
|
EntityPosition = new CPosition(posX + 8, posY + 16, 16);
|
|
EntitySize = new Rectangle(-8, -32, 16, 32);
|
|
|
|
_animator = AnimatorSaveLoad.LoadAnimator("Enemies/bone putter");
|
|
|
|
var sprite = new CSprite(EntityPosition);
|
|
_animatorComponent = new AnimationComponent(_animator, sprite, Vector2.Zero);
|
|
|
|
_body = new BodyComponent(EntityPosition, -4, -8, 8, 8, 8)
|
|
{
|
|
MoveCollision = OnCollision,
|
|
HoleOnPull = OnHolePull,
|
|
IgnoresZ = true,
|
|
Gravity = -0.075f,
|
|
DragAir = 0.875f,
|
|
AvoidTypes = Values.CollisionTypes.Hole | Values.CollisionTypes.NPCWall,
|
|
FieldRectangle = map.GetField(posX, posY)
|
|
};
|
|
|
|
var roomRectangle = map.GetField(posX, posY);
|
|
_roomCenter = new Vector2(roomRectangle.Center.X, roomRectangle.Center.Y + 8);
|
|
|
|
_aiComponent = new AiComponent();
|
|
|
|
var stateFlying = new AiState(UpdateFlying) { Init = InitFlying };
|
|
var stateJumping = new AiState(UpdateJumping) { Init = InitJumping };
|
|
var stateHole = new AiState();
|
|
|
|
_aiComponent.States.Add("flying", stateFlying);
|
|
_aiComponent.States.Add("jumping", stateJumping);
|
|
_aiComponent.States.Add("holePull", stateHole);
|
|
new AiFallState(_aiComponent, _body, null, null, 200);
|
|
_damageState = new AiDamageState(this, _body, _aiComponent, sprite, hasWings ? 3 : 1, false);
|
|
_aiComponent.ChangeState(hasWings ? "flying" : "jumping");
|
|
|
|
var hittableBox = new CBox(EntityPosition, -6, -15, 2, 12, 14, 8, true);
|
|
var damageBox = new CBox(EntityPosition, -6, -15, 2, 12, 14, 4, true);
|
|
var pushBox = new CBox(EntityPosition, -6, -15, 2, 12, 14, 4, true);
|
|
|
|
AddComponent(DamageFieldComponent.Index, new DamageFieldComponent(damageBox, HitType.Enemy, 2));
|
|
AddComponent(HittableComponent.Index, new HittableComponent(hittableBox, OnHit));
|
|
AddComponent(AiComponent.Index, _aiComponent);
|
|
AddComponent(BodyComponent.Index, _body);
|
|
AddComponent(BaseAnimationComponent.Index, _animatorComponent);
|
|
AddComponent(PushableComponent.Index, new PushableComponent(pushBox, OnPush));
|
|
AddComponent(DrawComponent.Index, new BodyDrawComponent(_body, sprite, Values.LayerPlayer));
|
|
AddComponent(DrawShadowComponent.Index, new BodyDrawShadowComponent(_body, sprite));
|
|
}
|
|
|
|
public bool StartJump()
|
|
{
|
|
return _aiComponent.CurrentStateId == "jumping" && _body.IsGrounded && EntityPosition.Z <= 0;
|
|
}
|
|
|
|
private void SpawnFairy()
|
|
{
|
|
// remove the enemy
|
|
Map.Objects.DeleteObjects.Add(this);
|
|
|
|
// spawn explosion effect that ends in a fairy spawning
|
|
var animationExplosion = new ObjAnimator(Map, (int)EntityPosition.X - 8, (int)(EntityPosition.Y - EntityPosition.Z - 16), Values.LayerTop, "Particles/spawn", "run", true);
|
|
animationExplosion.Animator.OnAnimationFinished = () =>
|
|
{
|
|
// remove the explosion animation
|
|
animationExplosion.Map.Objects.DeleteObjects.Add(animationExplosion);
|
|
// spawn fairy
|
|
animationExplosion.Map.Objects.SpawnObject(new ObjDungeonFairy(animationExplosion.Map, (int)EntityPosition.X, (int)(EntityPosition.Y - EntityPosition.Z - 4), 0));
|
|
};
|
|
|
|
Map.Objects.SpawnObject(animationExplosion);
|
|
}
|
|
|
|
private void InitFlying()
|
|
{
|
|
_animator.Play("fly");
|
|
_startPosition = EntityPosition.Position;
|
|
_targetPosition = _startPosition;
|
|
_flyCounter = 0;
|
|
}
|
|
|
|
private void UpdateFlying()
|
|
{
|
|
_flyCounter -= Game1.DeltaTime;
|
|
|
|
if (_flyCounter > 0)
|
|
{
|
|
var lerpPercentage = 0.5f - MathF.Sin(_flyCounter / _flyTime * MathF.PI - MathF.PI / 2) * 0.5f;
|
|
var newPosition = Vector2.Lerp(_startPosition, _targetPosition, lerpPercentage);
|
|
EntityPosition.Set(newPosition);
|
|
}
|
|
else
|
|
{
|
|
ThrowBomb();
|
|
|
|
EntityPosition.Set(_targetPosition);
|
|
_startPosition = _targetPosition;
|
|
|
|
// the target direction will be in the direction of the center if we are farther away from the center
|
|
var centerDirection = EntityPosition.Position - _roomCenter;
|
|
var centerDistance = centerDirection.Length();
|
|
if (centerDirection != Vector2.Zero)
|
|
centerDirection.Normalize();
|
|
var centerRadian = MathF.Atan2(centerDirection.Y, centerDirection.X);
|
|
|
|
// set a new target position
|
|
var centerOffset = Math.Clamp((50 - centerDistance) / 25, 0, 1);
|
|
var randomRotation = centerRadian - (MathF.PI + Game1.RandomNumber.Next(0, 628) / 100f) * centerOffset;
|
|
var randomDistance = Game1.RandomNumber.Next(12, 20);
|
|
_targetPosition.X = _startPosition.X - MathF.Cos(randomRotation) * randomDistance;
|
|
_targetPosition.Y = _startPosition.Y - MathF.Sin(randomRotation) * randomDistance;
|
|
|
|
_animatorComponent.MirroredH = _targetPosition.X > _startPosition.X;
|
|
_animatorComponent.UpdateSprite();
|
|
|
|
// random fly time
|
|
_flyTime = Game1.RandomNumber.Next(600, 800);
|
|
_flyCounter = _flyTime;
|
|
}
|
|
}
|
|
|
|
private void ThrowBomb()
|
|
{
|
|
_bombThrowCounter--;
|
|
if (_bombThrowCounter > 0)
|
|
return;
|
|
|
|
var playerDistance = MapManager.ObjLink.EntityPosition.Position - EntityPosition.Position;
|
|
if (playerDistance.Length() > 64)
|
|
return;
|
|
|
|
_bombThrowCounter = Game1.RandomNumber.Next(2, 6);
|
|
|
|
// spawn a bomb
|
|
var bomb = new ObjBomb(Map, 0, 0, false, true);
|
|
bomb.EntityPosition.Set(new Vector3(EntityPosition.X, EntityPosition.Y + 1, 18));
|
|
bomb.Body.Velocity = new Vector3(0, 0, 0.25f);
|
|
bomb.Body.Gravity = -0.1f;
|
|
bomb.Body.Bounciness = 0.4f;
|
|
Map.Objects.SpawnObject(bomb);
|
|
}
|
|
|
|
private void InitJumping()
|
|
{
|
|
_animator.Play("jump");
|
|
_body.IgnoresZ = false;
|
|
_body.IsGrounded = false;
|
|
_body.JumpStartHeight = 0;
|
|
}
|
|
|
|
private void UpdateJumping()
|
|
{
|
|
if (_body.IsGrounded)
|
|
Jump();
|
|
}
|
|
|
|
private void Jump()
|
|
{
|
|
// jump into a random direction
|
|
var randomRotation = Game1.RandomNumber.Next(0, 628) / 100f;
|
|
_body.VelocityTarget.X = -MathF.Cos(randomRotation) * JumpSpeed;
|
|
_body.VelocityTarget.Y = -MathF.Sin(randomRotation) * JumpSpeed;
|
|
_body.Velocity.Z = 1.5f;
|
|
|
|
_animatorComponent.MirroredH = _body.VelocityTarget.X > 0;
|
|
_animatorComponent.UpdateSprite();
|
|
}
|
|
|
|
private Values.HitCollision OnHit(GameObject originObject, Vector2 direction, HitType type, int damage, bool pieceOfPower)
|
|
{
|
|
if (type == HitType.Bow)
|
|
damage = 3;
|
|
|
|
if (_aiComponent.CurrentStateId == "flying" && (type == HitType.MagicPowder || type == HitType.Boomerang))
|
|
{
|
|
SpawnFairy();
|
|
return Values.HitCollision.Enemy;
|
|
}
|
|
|
|
if (_aiComponent.CurrentStateId == "flying")
|
|
_aiComponent.ChangeState("jumping");
|
|
|
|
return _damageState.OnHit(originObject, direction, type, damage, pieceOfPower);
|
|
}
|
|
|
|
private void OnHolePull(Vector2 direction, float percentage)
|
|
{
|
|
if (percentage < 0.5f)
|
|
return;
|
|
|
|
_aiComponent.ChangeState("holePull");
|
|
}
|
|
|
|
private bool OnPush(Vector2 direction, PushableComponent.PushType type)
|
|
{
|
|
if (type == PushableComponent.PushType.Impact)
|
|
_body.Velocity = new Vector3(direction.X * 1.75f, direction.Y * 1.75f, _body.Velocity.Z);
|
|
|
|
return true;
|
|
}
|
|
|
|
private void OnCollision(Values.BodyCollision collision)
|
|
{
|
|
if ((collision & Values.BodyCollision.Horizontal) != 0)
|
|
_body.Velocity.X = -_body.Velocity.X * 0.5f;
|
|
if ((collision & Values.BodyCollision.Vertical) != 0)
|
|
_body.Velocity.Y = -_body.Velocity.Y * 0.5f;
|
|
}
|
|
}
|
|
} |