mirror of
https://github.com/Phantop/LADXHD.git
synced 2024-11-01 04:14:22 +00:00
356 lines
13 KiB
C#
356 lines
13 KiB
C#
using System;
|
|
using Microsoft.Xna.Framework;
|
|
using ProjectZ.Base;
|
|
using ProjectZ.InGame.GameObjects.Base;
|
|
using ProjectZ.InGame.GameObjects.Base.CObjects;
|
|
using ProjectZ.InGame.GameObjects.Base.Components;
|
|
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.MidBoss
|
|
{
|
|
internal class MBossDesertLanmola : GameObject
|
|
{
|
|
private readonly AiComponent _aiComponent;
|
|
private readonly AiTriggerCountdown _damageTrigger;
|
|
private readonly Animator _animator;
|
|
private readonly CSprite _sprite;
|
|
private readonly CPosition _position;
|
|
|
|
private MBossDesertLanmolaHead _head;
|
|
private MBossDesertLanmolaBody[] _bodyParts = new MBossDesertLanmolaBody[6];
|
|
|
|
private readonly AiTriggerCountdown _jumpCountdown;
|
|
private readonly RectangleF _field;
|
|
private readonly Rectangle _fieldSmall;
|
|
|
|
private Vector2 _jumpStartPosition;
|
|
private Vector2 _jumpPosition;
|
|
private string _triggerKey;
|
|
private string _saveKey;
|
|
private int _jumpTime;
|
|
|
|
private int _lives = 8;
|
|
|
|
private bool _jumpLandSound;
|
|
private bool _playerLeft = true;
|
|
|
|
private const int CooldownTime = 350;
|
|
private const int DespawnTime = 5500;
|
|
|
|
public MBossDesertLanmola() : base("desert lanmola") { }
|
|
|
|
public MBossDesertLanmola(Map.Map map, int posX, int posY, string triggerKey, string saveKey) : base(map)
|
|
{
|
|
_position = new CPosition(posX, posY, 0);
|
|
EntitySize = new Rectangle(-8, -16, 16, 16);
|
|
|
|
_triggerKey = triggerKey;
|
|
_saveKey = saveKey;
|
|
_field = map.GetField(posX, posY, -16);
|
|
_fieldSmall = map.GetField(posX, posY, 16);
|
|
|
|
if (!string.IsNullOrEmpty(_saveKey) &&
|
|
Game1.GameManager.SaveManager.GetString(_saveKey) == "1")
|
|
{
|
|
IsDead = true;
|
|
return;
|
|
}
|
|
|
|
var stateIdle = new AiState();
|
|
var stateWaiting = new AiState();
|
|
stateWaiting.Trigger.Add(new AiTriggerCountdown(500, null, ToSpawning));
|
|
var stateSpawning = new AiState();
|
|
stateSpawning.Trigger.Add(new AiTriggerCountdown(500, null, ToJumping));
|
|
var stateJumping = new AiState();
|
|
stateJumping.Trigger.Add(_jumpCountdown = new AiTriggerCountdown(500, JumpTick, JumpEnd));
|
|
var stateDespawning = new AiState();
|
|
stateDespawning.Trigger.Add(new AiTriggerCountdown(DespawnTime, DespawnTick, DespawnEnd));
|
|
|
|
_aiComponent = new AiComponent();
|
|
|
|
_aiComponent.Trigger.Add(new AiTriggerUpdate(Update));
|
|
_aiComponent.Trigger.Add(_damageTrigger = new AiTriggerCountdown(CooldownTime, DamageTick, FinishDamage));
|
|
_aiComponent.States.Add("idle", stateIdle);
|
|
_aiComponent.States.Add("waiting", stateWaiting);
|
|
_aiComponent.States.Add("spawning", stateSpawning);
|
|
_aiComponent.States.Add("jumping", stateJumping);
|
|
_aiComponent.States.Add("despawning", stateDespawning);
|
|
|
|
_aiComponent.ChangeState("idle");
|
|
|
|
_animator = AnimatorSaveLoad.LoadAnimator("MidBoss/desertLanmola");
|
|
_animator.Play("ground");
|
|
|
|
_sprite = new CSprite(_position);
|
|
_sprite.IsVisible = false;
|
|
|
|
AddComponent(BaseAnimationComponent.Index, new AnimationComponent(_animator, _sprite, new Vector2(0, 0)));
|
|
AddComponent(DrawComponent.Index, new DrawCSpriteComponent(_sprite, Values.LayerBottom));
|
|
AddComponent(AiComponent.Index, _aiComponent);
|
|
|
|
if (!string.IsNullOrEmpty(_triggerKey))
|
|
AddComponent(KeyChangeListenerComponent.Index, new KeyChangeListenerComponent(OnKeyChange));
|
|
|
|
_head = new MBossDesertLanmolaHead(map, this, new Vector2(posX, posY));
|
|
map.Objects.SpawnObject(_head);
|
|
_head.Hide();
|
|
|
|
for (var i = 0; i < _bodyParts.Length; i++)
|
|
{
|
|
_bodyParts[i] = new MBossDesertLanmolaBody(map, new Vector2(posX, posY), i == 5);
|
|
map.Objects.SpawnObject(_bodyParts[i]);
|
|
_bodyParts[i].Hide();
|
|
}
|
|
}
|
|
|
|
private void OnKeyChange()
|
|
{
|
|
var triggerState = Game1.GameManager.SaveManager.GetString(_triggerKey);
|
|
Game1.GameManager.SaveManager.SetString(_triggerKey, "0");
|
|
|
|
// was triggered?
|
|
if (_playerLeft && triggerState == "1")
|
|
{
|
|
_playerLeft = false;
|
|
|
|
// start boss music
|
|
Game1.GameManager.SetMusic(79, 2);
|
|
|
|
Game1.GameManager.StartDialogPath("desertLanmola");
|
|
|
|
if (_aiComponent.CurrentStateId == "idle")
|
|
_aiComponent.ChangeState("waiting");
|
|
}
|
|
}
|
|
|
|
private void Update()
|
|
{
|
|
// player left?
|
|
if (!_playerLeft && !_field.Contains(MapManager.ObjLink.BodyRectangle))
|
|
{
|
|
_playerLeft = true;
|
|
Game1.GameManager.SetMusic(-1, 2);
|
|
}
|
|
}
|
|
|
|
private void ToSpawning()
|
|
{
|
|
if (_playerLeft)
|
|
{
|
|
_aiComponent.ChangeState("idle");
|
|
return;
|
|
}
|
|
|
|
_aiComponent.ChangeState("spawning");
|
|
|
|
var randomX = Game1.RandomNumber.Next(0, 8);
|
|
var randomY = Game1.RandomNumber.Next(0, 6);
|
|
|
|
if (randomX == 0 || randomX == 7)
|
|
randomY = Math.Clamp(randomY, 1, 6);
|
|
|
|
_position.Set(new Vector2(_fieldSmall.X + randomX * 16 + 8, _fieldSmall.Y + randomY * 16 + 16));
|
|
|
|
_sprite.IsVisible = true;
|
|
_animator.Play("ground");
|
|
}
|
|
|
|
private void ToJumping()
|
|
{
|
|
if (_playerLeft)
|
|
{
|
|
_sprite.IsVisible = false;
|
|
_aiComponent.ChangeState("idle");
|
|
return;
|
|
}
|
|
|
|
_sprite.IsVisible = false;
|
|
|
|
var direction = new Vector2(_fieldSmall.Center.X, _fieldSmall.Center.Y) - _position.Position;
|
|
direction.Normalize();
|
|
|
|
var randomDistance = Game1.RandomNumber.Next(48, 80);
|
|
_jumpPosition = _position.Position + direction * randomDistance;
|
|
|
|
_jumpStartPosition = _position.Position;
|
|
|
|
_jumpTime = Game1.RandomNumber.Next(1500, 2000);
|
|
_jumpCountdown.StartTime = _jumpTime + 1000;
|
|
|
|
_jumpLandSound = false;
|
|
|
|
_aiComponent.ChangeState("jumping");
|
|
|
|
_head.Spawn(direction);
|
|
_head.EntityPosition.Set(_jumpStartPosition);
|
|
|
|
// sand particles
|
|
SpawnParticles(new Vector2(_position.X, _position.Y));
|
|
}
|
|
|
|
private void JumpTick(double count)
|
|
{
|
|
var jumpState = 1 - (float)((count - 1000) / _jumpTime);
|
|
var headPosition = GetPosition(jumpState);
|
|
|
|
if (jumpState > 1 && _head.IsVisible)
|
|
{
|
|
_head.Hide();
|
|
// sand particles
|
|
SpawnParticles(new Vector2(headPosition.X, headPosition.Y));
|
|
}
|
|
|
|
if (!_jumpLandSound && jumpState > 0.5f)
|
|
{
|
|
_jumpLandSound = true;
|
|
Game1.GameManager.PlaySoundEffect("D378-35-23");
|
|
}
|
|
|
|
_head.EntityPosition.Set(headPosition);
|
|
|
|
if (jumpState > 0.8f)
|
|
_head.SetDown();
|
|
|
|
for (var i = 0; i < _bodyParts.Length; i++)
|
|
{
|
|
var state = 1 - (float)((count - (5 - i) * 166) / _jumpTime);
|
|
var partPosition = GetPosition(state);
|
|
|
|
var spawnParticles = false;
|
|
|
|
if (0 <= state && state <= 1 && !_bodyParts[i].IsVisible)
|
|
{
|
|
spawnParticles = true;
|
|
_bodyParts[i].Show();
|
|
}
|
|
|
|
if (state >= 1 && _bodyParts[i].IsVisible)
|
|
{
|
|
spawnParticles = true;
|
|
_bodyParts[i].Hide();
|
|
}
|
|
|
|
// sand particles
|
|
if (spawnParticles)
|
|
SpawnParticles(new Vector2(partPosition.X, partPosition.Y));
|
|
|
|
_bodyParts[i].EntityPosition.Set(partPosition);
|
|
}
|
|
}
|
|
|
|
private void JumpEnd()
|
|
{
|
|
JumpTick(0);
|
|
_aiComponent.ChangeState("waiting");
|
|
}
|
|
|
|
private Vector3 GetPosition(float state)
|
|
{
|
|
var newPosition = Vector2.Lerp(_jumpStartPosition, _jumpPosition, state);
|
|
var x = state * 9.1365f;
|
|
var newHeight = (0.75f * MathF.Sin(x) + 1.45f * MathF.Sin(x * 0.36f)) * 10;
|
|
|
|
return new Vector3(newPosition.X, newPosition.Y, newHeight);
|
|
}
|
|
|
|
private void SpawnParticles(Vector2 position)
|
|
{
|
|
// sand particles
|
|
var leftSand = new MBossDesertLanmolaSand(Map, new Vector2(position.X - 4, position.Y), false);
|
|
Map.Objects.SpawnObject(leftSand);
|
|
|
|
var rightSand = new MBossDesertLanmolaSand(Map, new Vector2(position.X + 4, position.Y), true);
|
|
Map.Objects.SpawnObject(rightSand);
|
|
}
|
|
|
|
private void DamageTick(double time)
|
|
{
|
|
var currentEffect = (CooldownTime - time) % 133 < 66 ? Resources.DamageSpriteShader0 : null;
|
|
SetEffect(currentEffect);
|
|
}
|
|
|
|
private void FinishDamage()
|
|
{
|
|
SetEffect(null);
|
|
}
|
|
|
|
private void DespawnTick(double time)
|
|
{
|
|
var currentEffect = time % 133 < 66 ? Resources.DamageSpriteShader0 : null;
|
|
SetEffect(currentEffect);
|
|
|
|
// despawn the parts
|
|
if (time < DespawnTime - 2000)
|
|
{
|
|
for (var i = 0; i < _bodyParts.Length; i++)
|
|
{
|
|
if (_bodyParts[i] != null && _bodyParts[i].IsVisible && time < DespawnTime - 2000 - (6 - i) * 500)
|
|
{
|
|
Game1.GameManager.PlaySoundEffect("D378-19-13");
|
|
|
|
var animation = new ObjAnimator(Map, 0, 0, Values.LayerTop, "Particles/spawn", "run", true);
|
|
animation.EntityPosition.Set(new Vector2(
|
|
_bodyParts[i].EntityPosition.X - 8,
|
|
_bodyParts[i].EntityPosition.Y - 16 - _bodyParts[i].EntityPosition.Z));
|
|
Map.Objects.SpawnObject(animation);
|
|
|
|
Map.Objects.DeleteObjects.Add(_bodyParts[i]);
|
|
_bodyParts[i] = null;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private void DespawnEnd()
|
|
{
|
|
Game1.GameManager.SetMusic(-1, 2);
|
|
|
|
Map.Objects.DeleteObjects.Add(_head);
|
|
|
|
var animation = new ObjAnimator(Map, 0, 0, Values.LayerTop, "Particles/spawn", "run", true);
|
|
animation.EntityPosition.Set(new Vector2(
|
|
_head.EntityPosition.X - 8,
|
|
_head.EntityPosition.Y - 16 - _head.EntityPosition.Z));
|
|
Map.Objects.SpawnObject(animation);
|
|
|
|
// set the save key
|
|
Game1.GameManager.SaveManager.SetString(_saveKey, "1");
|
|
|
|
// spawn the fish dungeon key
|
|
Map.Objects.SpawnObject(new ObjItem(Map, (int)_head.EntityPosition.X - 8, (int)_head.EntityPosition.Y - 16, "j", "dkey3Collected", "dkey3", null));
|
|
}
|
|
|
|
private void SetEffect(SpriteShader effect)
|
|
{
|
|
_head.Sprite.SpriteShader = effect;
|
|
foreach (var part in _bodyParts)
|
|
if (part != null)
|
|
part.Sprite.SpriteShader = effect;
|
|
}
|
|
|
|
public Values.HitCollision OnHit(GameObject originObject, Vector2 direction, HitType type, int damage, bool pieceOfPower)
|
|
{
|
|
if (_damageTrigger.CurrentTime > 0 || _aiComponent.CurrentStateId == "despawning")
|
|
return Values.HitCollision.None;
|
|
|
|
_lives -= damage;
|
|
|
|
if (_lives > 0)
|
|
{
|
|
_damageTrigger.OnInit();
|
|
Game1.GameManager.PlaySoundEffect("D370-07-07");
|
|
}
|
|
else
|
|
{
|
|
_aiComponent.ChangeState("despawning");
|
|
Game1.GameManager.PlaySoundEffect("D370-16-10");
|
|
}
|
|
|
|
return Values.HitCollision.Enemy;
|
|
}
|
|
}
|
|
} |