mirror of
https://github.com/Phantop/LADXHD.git
synced 2024-11-27 08:53:32 +00:00
330 lines
12 KiB
C#
330 lines
12 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;
|
||
|
|
||
|
namespace ProjectZ.InGame.GameObjects.Enemies
|
||
|
{
|
||
|
internal class EnemyAntiKirby : GameObject
|
||
|
{
|
||
|
private readonly Animator _animator;
|
||
|
private readonly BodyComponent _body;
|
||
|
private readonly AiComponent _aiComponent;
|
||
|
private readonly AiDamageState _damageState;
|
||
|
private readonly DamageFieldComponent _damageField;
|
||
|
|
||
|
private readonly ObjAnimator _suckParticles;
|
||
|
|
||
|
private Vector2 _walkDirection;
|
||
|
|
||
|
private int _direction;
|
||
|
private bool _hasPlayerTrapped;
|
||
|
private bool _endMove;
|
||
|
private bool _bounceSound;
|
||
|
|
||
|
public EnemyAntiKirby() : base("anti kirby") { }
|
||
|
|
||
|
public EnemyAntiKirby(Map.Map map, int posX, int posY) : base(map)
|
||
|
{
|
||
|
Tags = Values.GameObjectTag.Enemy;
|
||
|
|
||
|
EntityPosition = new CPosition(posX + 8, posY + 16, 0);
|
||
|
EntityPosition.AddPositionListener(typeof(EnemyLikeLike), UpdatePosition);
|
||
|
EntitySize = new Rectangle(-8, -16, 16, 16);
|
||
|
|
||
|
_animator = AnimatorSaveLoad.LoadAnimator("Enemies/anti kirby");
|
||
|
_animator.Play("idle_0");
|
||
|
|
||
|
var sprite = new CSprite(EntityPosition);
|
||
|
var animationComponent = new AnimationComponent(_animator, sprite, Vector2.Zero);
|
||
|
|
||
|
_body = new BodyComponent(EntityPosition, -7, -12, 14, 12, 8)
|
||
|
{
|
||
|
CollisionTypes = Values.CollisionTypes.Normal |
|
||
|
Values.CollisionTypes.Enemy |
|
||
|
Values.CollisionTypes.NPCWall,
|
||
|
FieldRectangle = map.GetField(posX, posY),
|
||
|
Drag = 0.85f,
|
||
|
Bounciness = 0.3f,
|
||
|
AbsorbPercentage = 0.8f,
|
||
|
Gravity = -0.125f,
|
||
|
MaxJumpHeight = 3,
|
||
|
};
|
||
|
|
||
|
var stateIdle = new AiState(UpdateIdle) { Init = InitIdle };
|
||
|
stateIdle.Trigger.Add(new AiTriggerRandomTime(EndIdle, 500, 850));
|
||
|
var stateMove = new AiState(UpdateMoving) { Init = InitMoving };
|
||
|
stateMove.Trigger.Add(new AiTriggerRandomTime(EndMove, 500, 850));
|
||
|
var stateSuck = new AiState(UpdateSuck) { Init = InitSuck };
|
||
|
stateSuck.Trigger.Add(new AiTriggerCountdown(4300, null, EndSuck));
|
||
|
var stateTrap = new AiState(UpdateTrap) { Init = InitTrap };
|
||
|
stateTrap.Trigger.Add(new AiTriggerCountdown(2000, null, EndTrap));
|
||
|
var stateSpit = new AiState { Init = InitSpit };
|
||
|
stateSpit.Trigger.Add(new AiTriggerCountdown(250, null, EndSpit));
|
||
|
|
||
|
_aiComponent = new AiComponent();
|
||
|
_aiComponent.States.Add("idle", stateIdle);
|
||
|
_aiComponent.States.Add("move", stateMove);
|
||
|
_aiComponent.States.Add("suck", stateSuck);
|
||
|
_aiComponent.States.Add("trap", stateTrap);
|
||
|
_aiComponent.States.Add("spit", stateSpit);
|
||
|
new AiFallState(_aiComponent, _body);
|
||
|
_damageState = new AiDamageState(this, _body, _aiComponent, sprite, 8, true, false)
|
||
|
{
|
||
|
HitMultiplierX = 2.5f,
|
||
|
HitMultiplierY = 2.5f,
|
||
|
};
|
||
|
_damageState.OnDeath = OnDeath;
|
||
|
|
||
|
var hittableBox = new CBox(EntityPosition, -7, -13, 0, 14, 13, 8, true);
|
||
|
var damageBox = new CBox(EntityPosition, -6, -12, 12, 12, 2);
|
||
|
|
||
|
AddComponent(HittableComponent.Index, new HittableComponent(hittableBox, OnHit));
|
||
|
AddComponent(BodyComponent.Index, _body);
|
||
|
AddComponent(AiComponent.Index, _aiComponent);
|
||
|
AddComponent(PushableComponent.Index, new PushableComponent(_body.BodyBox, OnPush));
|
||
|
AddComponent(BaseAnimationComponent.Index, animationComponent);
|
||
|
AddComponent(DamageFieldComponent.Index, _damageField = new DamageFieldComponent(damageBox, HitType.Enemy, 4));
|
||
|
AddComponent(DrawComponent.Index, new BodyDrawComponent(_body, sprite, Values.LayerPlayer));
|
||
|
AddComponent(DrawShadowComponent.Index, new BodyDrawShadowComponent(_body, sprite) { ShadowWidth = 10 });
|
||
|
|
||
|
// suck animator
|
||
|
_suckParticles = new ObjAnimator(map,
|
||
|
(int)EntityPosition.X, (int)EntityPosition.Y, Values.LayerPlayer, "Enemies/anti kirby suck", "", false);
|
||
|
_suckParticles.EntityPosition.SetParent(EntityPosition, Vector2.Zero);
|
||
|
map.Objects.SpawnObject(_suckParticles);
|
||
|
|
||
|
_aiComponent.ChangeState("idle");
|
||
|
}
|
||
|
|
||
|
private void InitSuck()
|
||
|
{
|
||
|
_damageField.IsActive = false;
|
||
|
_body.IgnoresZ = true;
|
||
|
|
||
|
// look in the direction of the player
|
||
|
_direction = EntityPosition.X > MapManager.ObjLink.EntityPosition.X ? 0 : 1;
|
||
|
|
||
|
_animator.Play("suck_" + _direction);
|
||
|
|
||
|
// suck animation particles
|
||
|
_suckParticles.AnimationComponent.SpriteOffset = new Vector2(_direction == 0 ? -15 : 15, 2);
|
||
|
_suckParticles.Animator.Play("suck_" + _direction);
|
||
|
}
|
||
|
|
||
|
private void UpdateSuck()
|
||
|
{
|
||
|
Game1.GameManager.PlaySoundEffect("D378-59-3B", false, 0.75f, 0, false, 100);
|
||
|
|
||
|
if (EntityPosition.Z < 12)
|
||
|
{
|
||
|
EntityPosition.Z += Game1.TimeMultiplier * 0.25f;
|
||
|
if (EntityPosition.Z > 12)
|
||
|
EntityPosition.Z = 12;
|
||
|
}
|
||
|
|
||
|
// suck in the player
|
||
|
var playerDirection = new Vector2(EntityPosition.X, EntityPosition.Y - EntityPosition.Z + 4) - MapManager.ObjLink.EntityPosition.Position;
|
||
|
var playerDir = EntityPosition.X > MapManager.ObjLink.EntityPosition.X ? 0 : 1;
|
||
|
|
||
|
// trap the player if he is close enough
|
||
|
if (playerDirection.Length() < 4)
|
||
|
{
|
||
|
ToTrap();
|
||
|
}
|
||
|
else if (playerDirection.Length() < 48 && playerDir == _direction)
|
||
|
{
|
||
|
playerDirection.Normalize();
|
||
|
MapManager.ObjLink._body.Velocity.X = 0.5f * playerDirection.X;
|
||
|
MapManager.ObjLink._body.Velocity.Y = 0.5f * playerDirection.Y;
|
||
|
MapManager.ObjLink._body.DisableVelocityTargetMultiplier = true;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private void EndSuck()
|
||
|
{
|
||
|
_damageField.IsActive = true;
|
||
|
_body.IgnoresZ = false;
|
||
|
_aiComponent.ChangeState("idle");
|
||
|
|
||
|
StopSuckSound();
|
||
|
}
|
||
|
|
||
|
private void StopSuckSound()
|
||
|
{
|
||
|
Game1.GameManager.StopSoundEffect("D378-59-3B");
|
||
|
}
|
||
|
|
||
|
private void ToTrap()
|
||
|
{
|
||
|
MapManager.ObjLink.TrapPlayer(true);
|
||
|
MapManager.ObjLink.SetPosition(EntityPosition.Position);
|
||
|
|
||
|
_aiComponent.ChangeState("trap");
|
||
|
_hasPlayerTrapped = true;
|
||
|
|
||
|
StopSuckSound();
|
||
|
}
|
||
|
|
||
|
private void InitTrap()
|
||
|
{
|
||
|
_bounceSound = false;
|
||
|
_body.IgnoresZ = false;
|
||
|
_suckParticles.Animator.Play("hidden");
|
||
|
_animator.Play("full_" + _direction);
|
||
|
}
|
||
|
|
||
|
private void UpdateTrap()
|
||
|
{
|
||
|
if (!_body.WasGrounded && _body.IsGrounded && !_bounceSound)
|
||
|
{
|
||
|
_bounceSound = true;
|
||
|
Game1.GameManager.PlaySoundEffect("D360-09-09");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private void EndTrap()
|
||
|
{
|
||
|
_hasPlayerTrapped = false;
|
||
|
|
||
|
MapManager.ObjLink.SetPosition(EntityPosition.Position);
|
||
|
MapManager.ObjLink.FreeTrappedPlayer();
|
||
|
MapManager.ObjLink.CurrentState = ObjLink.State.Jumping;
|
||
|
MapManager.ObjLink._body.Velocity = new Vector3(_direction == 0 ? -1.5f : 1.5f, 0, 1.25f);
|
||
|
|
||
|
_aiComponent.ChangeState("spit");
|
||
|
Game1.GameManager.PlaySoundEffect("D360-08-08");
|
||
|
Game1.GameManager.InflictDamage(2);
|
||
|
}
|
||
|
|
||
|
private void InitSpit()
|
||
|
{
|
||
|
_animator.Play("suck_" + _direction);
|
||
|
}
|
||
|
|
||
|
private void EndSpit()
|
||
|
{
|
||
|
_aiComponent.ChangeState("idle");
|
||
|
}
|
||
|
|
||
|
private void InitIdle()
|
||
|
{
|
||
|
_animator.Play("idle_" + _direction);
|
||
|
_suckParticles.Animator.Play("hidden");
|
||
|
}
|
||
|
|
||
|
private void UpdateIdle()
|
||
|
{
|
||
|
// jump on the spot
|
||
|
if (_body.IsGrounded)
|
||
|
_body.Velocity.Z = 0.9f;
|
||
|
}
|
||
|
|
||
|
private void EndIdle()
|
||
|
{
|
||
|
_aiComponent.ChangeState("move");
|
||
|
}
|
||
|
|
||
|
private void InitMoving()
|
||
|
{
|
||
|
_endMove = false;
|
||
|
|
||
|
var rotation = Game1.RandomNumber.Next(0, 628) / 100f;
|
||
|
_walkDirection.X = MathF.Sin(rotation);
|
||
|
_walkDirection.Y = MathF.Cos(rotation);
|
||
|
|
||
|
_direction = _walkDirection.X < 0 ? 0 : 1;
|
||
|
_animator.Play("idle_" + _direction);
|
||
|
}
|
||
|
|
||
|
private void UpdateMoving()
|
||
|
{
|
||
|
// jump
|
||
|
if (_body.IsGrounded)
|
||
|
{
|
||
|
if (_endMove)
|
||
|
{
|
||
|
var playerDirection = EntityPosition.Position - MapManager.ObjLink.EntityPosition.Position;
|
||
|
var playerDir = EntityPosition.X > MapManager.ObjLink.EntityPosition.X ? 0 : 1;
|
||
|
|
||
|
if (Math.Abs(playerDirection.Y) < 32 && Math.Abs(playerDirection.X) < 48 && playerDir == _direction)
|
||
|
_aiComponent.ChangeState("suck");
|
||
|
else
|
||
|
_aiComponent.ChangeState("idle");
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
_body.Velocity = new Vector3(_walkDirection.X, _walkDirection.Y, 0.9f);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private void EndMove()
|
||
|
{
|
||
|
_damageField.IsActive = true;
|
||
|
_endMove = true;
|
||
|
}
|
||
|
|
||
|
private void UpdatePosition(CPosition newPosition)
|
||
|
{
|
||
|
if (_hasPlayerTrapped)
|
||
|
MapManager.ObjLink.SetPosition(newPosition.Position);
|
||
|
}
|
||
|
|
||
|
private Values.HitCollision OnHit(GameObject gameObject, Vector2 direction, HitType damageType, int damage, bool pieceOfPower)
|
||
|
{
|
||
|
if (_aiComponent.CurrentStateId == "move")
|
||
|
_aiComponent.ChangeState("idle");
|
||
|
|
||
|
if ((damageType & HitType.Sword) != 0 ||
|
||
|
damageType == HitType.Bow ||
|
||
|
damageType == HitType.Hookshot ||
|
||
|
damageType == HitType.MagicPowder)
|
||
|
damage = 0;
|
||
|
|
||
|
// 4 hits
|
||
|
if (damageType == HitType.Boomerang)
|
||
|
damage = 2;
|
||
|
|
||
|
if (damageType == HitType.Bomb ||
|
||
|
damageType == HitType.MagicRod)
|
||
|
damage = 4;
|
||
|
|
||
|
if (damage != 0 && _hasPlayerTrapped)
|
||
|
EndTrap();
|
||
|
|
||
|
return _damageState.OnHit(gameObject, direction, damageType, damage, pieceOfPower);
|
||
|
}
|
||
|
|
||
|
private void OnDeath(bool pieceOfPower)
|
||
|
{
|
||
|
StopSuckSound();
|
||
|
|
||
|
_damageState.BaseOnDeath(pieceOfPower);
|
||
|
|
||
|
// remove the suck animation particles
|
||
|
Map.Objects.DeleteObjects.Add(_suckParticles);
|
||
|
|
||
|
// free the player
|
||
|
if (_hasPlayerTrapped)
|
||
|
MapManager.ObjLink.FreeTrappedPlayer();
|
||
|
}
|
||
|
|
||
|
private bool OnPush(Vector2 direction, PushableComponent.PushType type)
|
||
|
{
|
||
|
if (_hasPlayerTrapped)
|
||
|
return false;
|
||
|
|
||
|
if (type == PushableComponent.PushType.Impact)
|
||
|
_body.Velocity = new Vector3(direction * 1.5f, _body.Velocity.Z);
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
}
|
||
|
}
|