Fixed Shield animation jumps and secondary attack Fixed demon wall stone behavior Made overworld ambient sounds unpausable
240 lines
7.4 KiB
C#
240 lines
7.4 KiB
C#
using Godot;
|
|
using System.Linq;
|
|
using System;
|
|
using Zennysoft.Ma.Adapter;
|
|
using Zennysoft.Ma.Adapter.Entity;
|
|
using Zennysoft.Game.Implementation;
|
|
|
|
namespace Zennysoft.Game.Ma;
|
|
|
|
public class EffectService
|
|
{
|
|
private readonly IGame _game;
|
|
private readonly IPlayer _player;
|
|
private readonly IMap _map;
|
|
|
|
public EffectService(IGame game, IPlayer player, IMap map)
|
|
{
|
|
_game = game;
|
|
_player = player;
|
|
_map = map;
|
|
}
|
|
|
|
public void TeleportEnemiesToCurrentRoom()
|
|
{
|
|
var currentFloor = _game.CurrentFloor;
|
|
var rooms = currentFloor.Rooms;
|
|
var currentRoom = _map.GetPlayersCurrentRoom();
|
|
|
|
if (currentRoom is not MonsterRoom)
|
|
return;
|
|
|
|
var validRooms = rooms.OfType<MonsterRoom>().ToList();
|
|
if (currentRoom is MonsterRoom monsterRoom)
|
|
validRooms.Remove(monsterRoom);
|
|
|
|
var currentMonsterRoom = (MonsterRoom)currentRoom;
|
|
|
|
var enemyList = validRooms.SelectMany(x => x.GetEnemiesInCurrentRoom());
|
|
|
|
foreach (var enemy in enemyList)
|
|
enemy.MoveEnemyToNewRoom(currentMonsterRoom);
|
|
}
|
|
|
|
public void KillHalfEnemiesInRoom()
|
|
{
|
|
var currentRoom = _map.GetPlayersCurrentRoom();
|
|
if (currentRoom is not MonsterRoom)
|
|
return;
|
|
|
|
var currentMonsterRoom = (MonsterRoom)currentRoom;
|
|
var enemyList = currentMonsterRoom.GetEnemiesInCurrentRoom().ToList();
|
|
var enemiesToKill = enemyList.Count / 2;
|
|
for (var i = 0; i < enemiesToKill; i++)
|
|
enemyList[i].Die();
|
|
}
|
|
|
|
public void TurnAllEnemiesInRoomIntoHealingItem()
|
|
{
|
|
var currentRoom = _map.GetPlayersCurrentRoom();
|
|
|
|
if (currentRoom is not MonsterRoom)
|
|
return;
|
|
|
|
var currentEnemies = currentRoom.EnemiesInRoom;
|
|
foreach (var enemy in currentEnemies)
|
|
{
|
|
enemy.OnMorph();
|
|
DropHealingItem(enemy.GlobalPosition);
|
|
}
|
|
if (!currentEnemies.IsEmpty)
|
|
SfxDatabase.Instance.Play(SoundEffect.TurnAllEnemiesIntoHealingItems);
|
|
}
|
|
|
|
public void DropHealingItem(Vector3 vector)
|
|
{
|
|
var consumableFolder = "res://src/items/consumable";
|
|
var restorativeScene = GD.Load<PackedScene>($"{consumableFolder}/ConsumableItem.tscn");
|
|
var consumable = restorativeScene.Instantiate<ConsumableItem>();
|
|
var resourceFiles = DirAccess.GetFilesAt($"{consumableFolder}/resources");
|
|
var rng = new RandomNumberGenerator();
|
|
rng.Randomize();
|
|
var randomResource = resourceFiles[rng.RandiRange(0, resourceFiles.Length - 1)];
|
|
var randomFile = ResourceLoader.Load<ConsumableItemStats>($"{consumableFolder}/resources/{randomResource}");
|
|
consumable.Stats = randomFile;
|
|
_game.AddChild(consumable);
|
|
consumable.GlobalPosition = vector;
|
|
}
|
|
|
|
public void HealAllEnemiesAndPlayerInRoomToFull()
|
|
{
|
|
var currentRoom = _map.GetPlayersCurrentRoom();
|
|
|
|
if (currentRoom is not MonsterRoom)
|
|
return;
|
|
|
|
currentRoom.EnemiesInRoom.ForEach(e => e.HealthComponent.SetCurrentHealth(e.HealthComponent.MaximumHP.Value));
|
|
_player.HealthComponent.SetCurrentHealth(_player.HealthComponent.MaximumHP.Value);
|
|
}
|
|
|
|
public void AbsorbHPFromAllEnemiesInRoom()
|
|
{
|
|
var currentRoom = _map.GetPlayersCurrentRoom();
|
|
|
|
if (currentRoom is not MonsterRoom)
|
|
return;
|
|
|
|
var currentEnemies = currentRoom.EnemiesInRoom;
|
|
var hpToAbsorb = 0.0;
|
|
foreach (var enemy in currentEnemies)
|
|
{
|
|
var absorbAmount = enemy.HealthComponent.MaximumHP.Value * 0.05;
|
|
enemy.HealthComponent.Damage((int)absorbAmount);
|
|
hpToAbsorb += absorbAmount;
|
|
enemy.OnAbsorb();
|
|
}
|
|
_player.HealthComponent.Heal((int)hpToAbsorb);
|
|
GD.Print("HP to absorb: " + hpToAbsorb);
|
|
}
|
|
|
|
public void DealElementalDamageToAllEnemiesInRoom(ElementType elementType)
|
|
{
|
|
var currentRoom = _map.GetPlayersCurrentRoom();
|
|
|
|
if (currentRoom is not MonsterRoom)
|
|
return;
|
|
|
|
var currentEnemies = currentRoom.EnemiesInRoom;
|
|
foreach (var enemy in currentEnemies)
|
|
{
|
|
var damageDealt = DamageCalculator.CalculateDamage(new AttackData(20, elementType), 10, ElementalResistanceSet.None);
|
|
enemy.HealthComponent.Damage(damageDealt);
|
|
}
|
|
}
|
|
|
|
public void SwapHPandVT()
|
|
{
|
|
var oldHp = _player.HealthComponent.CurrentHP.Value;
|
|
var oldVt = _player.VTComponent.CurrentVT.Value;
|
|
|
|
_player.HealthComponent.SetCurrentHealth(oldVt);
|
|
_player.VTComponent.SetVT(oldHp);
|
|
SfxDatabase.Instance.Play(SoundEffect.SwapHPAndVT);
|
|
}
|
|
|
|
public void RandomEffect(EffectItem item)
|
|
{
|
|
var itemEffects = Enum.GetValues<UsableItemTag>().ToList();
|
|
itemEffects.Remove(UsableItemTag.RandomEffect);
|
|
itemEffects.Remove(UsableItemTag.None);
|
|
var randomEffect = new Godot.Collections.Array<UsableItemTag>(itemEffects).PickRandom();
|
|
item.SetEffectTag(randomEffect);
|
|
_game.UseItem(item);
|
|
}
|
|
|
|
public void RaiseCurrentWeaponAttack()
|
|
{
|
|
if (string.IsNullOrEmpty(_player.EquipmentComponent.EquippedWeapon.Value.ItemName))
|
|
return;
|
|
|
|
var currentWeapon = (Weapon)_player.EquipmentComponent.EquippedWeapon.Value;
|
|
currentWeapon.IncreaseWeaponAttack(1);
|
|
SfxDatabase.Instance.Play(SoundEffect.IncreaseStat);
|
|
}
|
|
|
|
public void RaiseCurrentArmorDefense()
|
|
{
|
|
if (string.IsNullOrEmpty(_player.EquipmentComponent.EquippedArmor.Value.ItemName))
|
|
return;
|
|
|
|
var currentArmor = (Armor)_player.EquipmentComponent.EquippedArmor.Value;
|
|
currentArmor.IncreaseArmorDefense(1);
|
|
SfxDatabase.Instance.Play(SoundEffect.IncreaseStat);
|
|
}
|
|
|
|
public void RaiseLevel() => _player.LevelUp();
|
|
|
|
public void TeleportToRandomRoom(IEnemy enemy)
|
|
{
|
|
var currentFloor = _game.CurrentFloor;
|
|
var rooms = currentFloor.Rooms;
|
|
var currentRoom = enemy.GetCurrentRoom(rooms);
|
|
var validRooms = rooms.OfType<MonsterRoom>().ToList();
|
|
if (currentRoom is MonsterRoom currentMonsterRoom)
|
|
validRooms.Remove(currentMonsterRoom);
|
|
|
|
if (validRooms.Count == 0)
|
|
return;
|
|
|
|
var roomsGodotCollection = new Godot.Collections.Array<MonsterRoom>(validRooms);
|
|
var randomRoom = roomsGodotCollection.PickRandom();
|
|
|
|
enemy.MoveEnemyToNewRoom(randomRoom);
|
|
}
|
|
|
|
public void TeleportToRandomRoom(IPlayer player)
|
|
{
|
|
var currentFloor = _game.CurrentFloor;
|
|
var rooms = currentFloor.Rooms;
|
|
|
|
var currentRoom = rooms.SingleOrDefault(x => x.IsPlayerInRoom);
|
|
|
|
var validRooms = rooms.OfType<MonsterRoom>().ToList();
|
|
if (currentRoom is MonsterRoom currentMonsterRoom)
|
|
validRooms.Remove(currentMonsterRoom);
|
|
|
|
if (validRooms.Count == 0)
|
|
return;
|
|
|
|
var roomsGodotCollection = new Godot.Collections.Array<MonsterRoom>(validRooms);
|
|
var randomRoom = roomsGodotCollection.PickRandom();
|
|
var spawnPoint = randomRoom.PlayerSpawn;
|
|
player.TeleportPlayer(spawnPoint.Transform);
|
|
SfxDatabase.Instance.Play(SoundEffect.TeleportToRandomRoom);
|
|
}
|
|
|
|
public void ChangeAffinity(ThrowableItem throwableItem)
|
|
{
|
|
var maximumElements = Enum.GetNames(typeof(ElementType)).Length;
|
|
var newElement = ((int)throwableItem.ElementType + 1) % maximumElements;
|
|
throwableItem.SetElementType((ElementType)newElement);
|
|
|
|
// TODO: Make this an inventory animation to cycle through elements.
|
|
throwableItem.SetDescription(
|
|
$"Inflicts {throwableItem.ElementType} damage when thrown." +
|
|
$"{System.Environment.NewLine}Use item to change Affinity.");
|
|
|
|
throwableItem.SetCount(throwableItem.Count + 1);
|
|
}
|
|
|
|
public void WarpToExit(IPlayer player)
|
|
{
|
|
var exitRoom = _game.CurrentFloor.Rooms.OfType<ExitRoom>().Single();
|
|
if (exitRoom.PlayerDiscoveredRoom)
|
|
{
|
|
SfxDatabase.Instance.Play(SoundEffect.TeleportToExit);
|
|
player.TeleportPlayer(exitRoom.PlayerSpawn.Transform);
|
|
}
|
|
}
|
|
}
|