Files
GameJamDungeon/Zennysoft.Game.Ma/src/items/EffectService.cs
T
2026-06-11 20:53:16 -07:00

400 lines
13 KiB
C#

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(List<IEnemy> enemyList)
{
var currentRoom = _map.CurrentFloor.GetPlayersCurrentRoom();
if (currentRoom is MonsterRoom currentMonsterRoom)
{
foreach (var enemy in enemyList)
enemy.MoveEnemyToNewRoom(currentMonsterRoom);
}
}
public void KillHalfEnemiesInRoom()
{
var currentRoom = _map.CurrentFloor.GetPlayersCurrentRoom();
if (currentRoom is not MonsterRoom)
return;
var currentMonsterRoom = (MonsterRoom)currentRoom;
var enemyList = currentMonsterRoom.GetEnemiesInCurrentRoom().OfType<IEnemy>().ToList();
var enemiesToKill = enemyList.Count / 2;
for (var i = 0; i < enemiesToKill; i++)
enemyList[i].Die();
}
public void TurnAllEnemiesInRoomIntoHealingItem()
{
var currentRoom = _map.CurrentFloor.GetPlayersCurrentRoom();
if (currentRoom is not MonsterRoom)
return;
var currentEnemies = currentRoom.EnemiesInRoom.OfType<IEnemy>().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<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}".TrimSuffix(".remap"));
consumable.Stats = randomFile;
_game.AddChild(consumable);
consumable.GlobalPosition = vector;
}
public void HealAllEnemiesAndPlayerInRoomToFull()
{
var currentRoom = _map.CurrentFloor.GetPlayersCurrentRoom();
if (currentRoom is not MonsterRoom)
return;
currentRoom.EnemiesInRoom.ForEach(e => e.HealthComponent.SetCurrentHealth(e.HealthComponent.MaximumHP.Value));
currentRoom.EnemiesInRoom.ForEach(e => e.OnHealed());
_player.HealthComponent.SetCurrentHealth(_player.HealthComponent.MaximumHP.Value);
SfxDatabase.Instance.Play(SoundEffect.HealHP);
}
public int AbsorbHPFromAllEnemiesInRoom()
{
var currentRoom = _map.CurrentFloor.GetPlayersCurrentRoom();
if (currentRoom is not MonsterRoom)
return 0;
var currentEnemies = currentRoom.EnemiesInRoom;
var hpToAbsorb = 0.0;
foreach (var enemy in currentEnemies)
{
var absorbAmount = enemy.HealthComponent.CurrentHP.Value * 0.25;
enemy.HealthComponent.Damage((int)absorbAmount, ElementType.None);
hpToAbsorb += absorbAmount;
enemy.OnAbsorb();
}
return (int)hpToAbsorb;
}
public void DealElementalDamageToAllEnemiesInRoom(ElementType elementType)
{
var currentRoom = _map.CurrentFloor.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, elementType);
}
}
public void SwapHPandVT()
{
var oldHp = Mathf.Max(1, _player.HealthComponent.CurrentHP.Value);
var oldVt = Mathf.Max(1, _player.VTComponent.CurrentVT.Value);
_player.HealthComponent.SetCurrentHealth(oldVt);
_player.VTComponent.SetVT(oldHp);
SfxDatabase.Instance.Play(SoundEffect.SwapHPAndVT);
}
public void RandomEffect()
{
var randomEffects = Enum.GetValues(typeof(UsableItemTag)).Cast<UsableItemTag>().Except([UsableItemTag.RandomEffect, UsableItemTag.None]).ToList();
var rng = new RandomNumberGenerator();
rng.Randomize();
var index = rng.RandiRange(0, randomEffects.Count - 1);
var randomItem = new EffectItem() { Stats = new EffectItemStats() { UsableItemTag = randomEffects[index], BonusAttack = 1, BonusDefense = 1, BonusLuck = 10 } };
_game.UseItem(randomItem);
}
public void DoubleExp()
{
_game.DoubleExp();
}
public void RaiseCurrentWeaponAttack()
{
if (string.IsNullOrEmpty(_player.EquipmentComponent.EquippedWeapon.Value.ItemName))
return;
var currentWeapon = (Weapon)_player.EquipmentComponent.EquippedWeapon.Value;
currentWeapon.IncreaseAttack(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 LowerCurrentArmorDefense()
{
if (string.IsNullOrEmpty(_player.EquipmentComponent.EquippedArmor.Value.ItemName))
return;
var currentArmor = (Armor)_player.EquipmentComponent.EquippedArmor.Value;
currentArmor.DecreaseArmorDefense(1);
SfxDatabase.Instance.Play(SoundEffect.DecreaseStat);
}
public void RestoreParameters(IPlayer player)
{
var hpToRestore = player.HealthComponent.MaximumHP.Value;
player.HealthComponent.SetCurrentHealth(hpToRestore);
var vtToRestore = player.VTComponent.MaximumVT.Value;
player.VTComponent.SetVT(vtToRestore);
var attackToRestore = player.AttackComponent.MaximumAttack.Value - player.AttackComponent.CurrentAttack.Value;
player.AttackComponent.Restore(attackToRestore);
var defenseToRestore = player.DefenseComponent.MaximumDefense.Value - player.DefenseComponent.CurrentDefense.Value;
player.DefenseComponent.Restore(defenseToRestore);
if (player.LuckComponent.Luck.Value < player.LuckComponent.InitialLuck)
player.LuckComponent.IncreaseLuck(player.LuckComponent.InitialLuck - player.LuckComponent.Luck.Value);
}
public void RaiseLevel()
{
var expToNextLevel = _player.ExperiencePointsComponent.ExpToNextLevel.Value - _player.ExperiencePointsComponent.CurrentExp.Value;
_player.ExperiencePointsComponent.GainUnmodified(expToNextLevel);
}
public void LowerLevel()
{
var expToNextLevel = _player.ExperiencePointsComponent.ExpToNextLevel.Value - _player.ExperiencePointsComponent.CurrentExp.Value;
_player.ExperiencePointsComponent.LevelDown();
}
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 DisableEnemyMovement(IEnemy enemy)
{
enemy.SetEnemySpeedByMultiplier(0);
}
public void CloneEnemy(IEnemy enemy)
{
var enemyPosition = new Vector3(enemy.GlobalPosition.X, 0f, enemy.GlobalPosition.Z);
var enemyType = EnemyTypeToEnemyConverter.Convert(enemy);
var duplicatedEnemy = EnemyTypeToEnemyConverter.Convert(enemyType);
duplicatedEnemy.GlobalPosition = enemy.GlobalPosition + enemy.GlobalBasis.X;
_map.AddChild(duplicatedEnemy);
}
public void MeltAllEquipment(IPlayer player)
{
var weapon = player.EquipmentComponent.EquippedWeapon.Value;
var armor = player.EquipmentComponent.EquippedArmor.Value;
var accessory = player.EquipmentComponent.EquippedAccessory.Value;
var ammo = player.EquipmentComponent.EquippedAmmo.Value;
if (weapon != null)
{
player.Unequip(weapon);
player.Inventory.Remove(weapon);
}
if (armor != null)
{
player.Unequip(armor);
player.Inventory.Remove(armor);
}
if (accessory != null)
{
player.Unequip(accessory);
player.Inventory.Remove(accessory);
}
if (ammo != null)
{
player.Unequip(ammo);
player.Inventory.Remove(ammo);
}
}
public void GlueAllEquipment(IPlayer player)
{
var weapon = player.EquipmentComponent.EquippedWeapon.Value;
var armor = player.EquipmentComponent.EquippedArmor.Value;
var accessory = player.EquipmentComponent.EquippedAccessory.Value;
if (weapon != null && !string.IsNullOrEmpty(weapon.ItemName))
weapon.Glued = true;
if (armor != null && !string.IsNullOrEmpty(armor.ItemName))
armor.Glued = true;
if (accessory != null && !string.IsNullOrEmpty(accessory.ItemName))
accessory.Glued = true;
player.EquipmentComponent.UpdateEquipment(weapon);
player.EquipmentComponent.UpdateEquipment(armor);
player.EquipmentComponent.UpdateEquipment(accessory);
}
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.Rotation, new Vector3(spawnPoint.GlobalPosition.X, _player.GlobalPosition.Y, spawnPoint.GlobalPosition.Z)));
SfxDatabase.Instance.Play(SoundEffect.TeleportToRandomRoom);
}
public bool WarpToExit()
{
var exitRoom = _game.CurrentFloor.Rooms.OfType<ExitRoom>().Single();
if (exitRoom.PlayerDiscoveredRoom)
{
SfxDatabase.Instance.Play(SoundEffect.TeleportToExit);
var exitPoint = exitRoom.PlayerSpawn.GlobalPosition;
_player.TeleportPlayer((exitRoom.PlayerSpawn.Rotation, new Vector3(exitPoint.X, _player.GlobalPosition.Y, exitPoint.Z)));
return true;
}
return false;
}
public void DamagesPlayer(int damage)
{
_player.TakeDamage(new AttackData(damage, ElementType.None, true, true));
}
public void RerollItem(IBaseInventoryItem itemToReroll)
{
var itemReroller = new ItemReroller(ItemDatabase.Instance);
itemReroller.RerollItem(itemToReroll, _player.Inventory);
}
public T GetRandomItemOfType<T>(params T[] itemsToExclude)
where T : IBaseInventoryItem => ItemDatabase.Instance.PickItem(itemsToExclude);
public void RandomSpell(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 T DropTo1HPAndGainRareItem<T>()
where T : IBaseInventoryItem
{
_player.HealthComponent.SetCurrentHealth(1);
return ItemDatabase.Instance.PickRareItem<T>();
}
public void TradeRandomItem<T>(BoxItem box)
where T : IBaseInventoryItem
{
var tradableItems = _player.Inventory.Items.OfType<T>().Where(x => x.ItemTag != ItemTag.KeyItem).ToList();
var rng = new RandomNumberGenerator();
rng.Randomize();
var randomIndex = rng.RandiRange(0, tradableItems.Count - 1);
var randomItem = tradableItems[randomIndex];
if (randomItem is IEquipableItem equipableItem && _player.EquipmentComponent.IsItemEquipped(equipableItem))
_player.Unequip(equipableItem);
_player.Inventory.Remove(randomItem);
GetRandomItemOfType<T>();
}
public IEnumerable<IBaseInventoryItem> TradeAllRandomItems(BoxItem box)
{
var newInventory = new List<IBaseInventoryItem>();
var items = _player.Inventory.Items.Where(x => x.ItemTag != ItemTag.KeyItem).ToList();
foreach (var item in items)
newInventory.Add(GetRandomItemOfType<IBaseInventoryItem>());
return newInventory;
}
public IBaseInventoryItem 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));
return selectedItem;
}
public T GetBasicItem<T>()
where T : IBaseInventoryItem
{
return ItemDatabase.Instance.PickBasicItem<T>();
}
}