using Godot; using System.Linq; using System; using Zennysoft.Ma.Adapter; using Zennysoft.Ma.Adapter.Entity; using System.Collections.Generic; 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().ToList(); if (currentRoom is MonsterRoom monsterRoom) validRooms.Remove(monsterRoom); var currentMonsterRoom = (MonsterRoom)currentRoom; var enemyList = validRooms.SelectMany(x => x.GetEnemiesInCurrentRoom()).OfType(); 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().OfType().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.OfType().ToList(); foreach (var enemy in currentEnemies) { enemy.OnMorph(); DropHealingItem(enemy.GlobalPosition); } if (currentEnemies.Any()) SfxDatabase.Instance.Play(SoundEffect.TurnAllEnemiesIntoHealingItems); } public void DropHealingItem(Vector3 vector) { var consumableFolder = "res://src/items/consumable"; var restorativeScene = GD.Load($"{consumableFolder}/ConsumableItem.tscn"); var consumable = restorativeScene.Instantiate(); 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($"{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, enemy.ElementalResistanceSet); 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().ToList(); itemEffects.Remove(UsableItemTag.RandomEffect); itemEffects.Remove(UsableItemTag.None); var randomEffect = new Godot.Collections.Array(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().ToList(); if (currentRoom is MonsterRoom currentMonsterRoom) validRooms.Remove(currentMonsterRoom); if (validRooms.Count == 0) return; var roomsGodotCollection = new Godot.Collections.Array(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().ToList(); if (currentRoom is MonsterRoom currentMonsterRoom) validRooms.Remove(currentMonsterRoom); if (validRooms.Count == 0) return; var roomsGodotCollection = new Godot.Collections.Array(validRooms); var randomRoom = roomsGodotCollection.PickRandom(); var spawnPoint = randomRoom.PlayerSpawn; player.TeleportPlayer((spawnPoint.Rotation, new Vector3(spawnPoint.Position.X, 0, spawnPoint.Position.Z))); 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() { var exitRoom = _game.CurrentFloor.Rooms.OfType().Single(); if (exitRoom.PlayerDiscoveredRoom) { SfxDatabase.Instance.Play(SoundEffect.TeleportToExit); _player.TeleportPlayer((exitRoom.PlayerSpawn.Rotation, exitRoom.PlayerSpawn.Position)); } } public void DamagesPlayer(int damage) { _player.TakeDamage(new AttackData(damage, ElementType.None, true, true)); } public void RerollItem(InventoryItem itemToReroll) { var itemReroller = new ItemReroller(ItemDatabase.Instance); itemReroller.RerollItem(itemToReroll, _player.Inventory); } public T GetRandomItemOfType(T itemToExclude = null) where T : InventoryItem => ItemDatabase.Instance.PickItem(itemToExclude); public void RandomSpell() { throw new NotImplementedException("Spells not implemented yet."); } public void DropTo1HPAndGainRareItem() where T : InventoryItem { _player.HealthComponent.SetCurrentHealth(1); _player.Inventory.TryAdd(ItemDatabase.Instance.PickRareItem()); } public void TradeRandomItem(BoxItem box) where T : InventoryItem { var tradableItems = _player.Inventory.Items.OfType().Where(x => x != box).ToList(); var rng = new RandomNumberGenerator(); rng.Randomize(); var randomIndex = rng.RandiRange(0, tradableItems.Count - 1); var randomItem = tradableItems[randomIndex]; if (randomItem is EquipableItem equipableItem) { if (_player.EquipmentComponent.IsItemEquipped(equipableItem)) _player.Unequip(equipableItem); } _player.Inventory.Remove(randomItem); GetRandomItemOfType(); } public IEnumerable TradeAllRandomItems(BoxItem box) where T : InventoryItem { var newInventory = new List(); var items = _player.Inventory.Items.OfType().Where(x => x != box).ToList(); foreach (var item in items) newInventory.Add(GetRandomItemOfType()); return newInventory; } public void GetUnobtainedItem() { var pickableItems = ItemDatabase.Instance.Items.Except(_player.Inventory.Items).ToList(); var rng = new RandomNumberGenerator(); rng.Randomize(); var randomIndex = rng.RandiRange(0, pickableItems.Count - 1); var selectedItem = pickableItems[randomIndex]; if (selectedItem is ThrowableItem throwableItem) throwableItem.SetCount(rng.RandiRange(throwableItem.Stats.MinimumCount, throwableItem.Stats.MaximumCount)); _player.Inventory.TryAdd(selectedItem); } public void GetBasicItem() where T : InventoryItem { _player.Inventory.TryAdd(ItemDatabase.Instance.PickBasicItem()); } }