From 5958d9c071915ab71aea5a5c08d79e88024f6c58 Mon Sep 17 00:00:00 2001 From: Matheus Date: Sun, 14 Sep 2025 00:14:25 -0300 Subject: The newer scolls: groundrim. --- scripts/Entities/Items/ConsumableItem.cs | 2 +- scripts/Entities/Items/ScrollConsumable.cs | 96 ++++++++++++++++++++++++++++-- 2 files changed, 93 insertions(+), 5 deletions(-) (limited to 'scripts/Entities/Items') diff --git a/scripts/Entities/Items/ConsumableItem.cs b/scripts/Entities/Items/ConsumableItem.cs index 4078bd3..b672b7d 100644 --- a/scripts/Entities/Items/ConsumableItem.cs +++ b/scripts/Entities/Items/ConsumableItem.cs @@ -31,7 +31,7 @@ public abstract partial class ConsumableItem(Vector2I initialPosition, MapData m /// Se a ação foi realizada ou não. public abstract bool Activate(ItemAction action); - public void ConsumedBy(Player consumer) + public virtual void ConsumedBy(Player consumer) { Inventory inventory = consumer.Inventory; inventory.RemoveItem(this); diff --git a/scripts/Entities/Items/ScrollConsumable.cs b/scripts/Entities/Items/ScrollConsumable.cs index d260263..de809a0 100644 --- a/scripts/Entities/Items/ScrollConsumable.cs +++ b/scripts/Entities/Items/ScrollConsumable.cs @@ -1,25 +1,113 @@ using Godot; using TheLegendOfGustav.Entities.Actions; using TheLegendOfGustav.Entities.Actors; +using TheLegendOfGustav.InputHandling; using TheLegendOfGustav.Magic; using TheLegendOfGustav.Map; using TheLegendOfGustav.Utils; namespace TheLegendOfGustav.Entities.Items; +/// +/// Um pergaminho é um item consumível que joga exatamente um feitiço. +/// Feitiços de pergaminhos são gratuitos e não possuem restrições. +/// +/// Posição que o item será colocado no mapa. +/// Mapa que o item será colocado. +/// Definição do item. public partial class ScrollConsumable(Vector2I initialPosition, MapData map, ScrollConsumableDefinition definition) : ConsumableItem(initialPosition, map, definition) { - private ScrollConsumableDefinition definition = definition; - public SpellResource Spell { get; private set; } = definition.Spell; + /// + /// O pergaminho só pode ser usado uma única vez. + /// Alguns feitiços precisam de um alvo, o que significa que + /// o pergaminho não pode se auto-destruir enquanto o jogador não + /// escolher uma posição válida. + /// + /// Esta variável garante que seja impossível de usar o pergaminho enquanto o jogador + /// escolhe um alvo. + /// + private bool awaitingTermination = false; + + private ScrollConsumableDefinition definition = definition; + + /// + /// O godot exige que desconectemos sinais customizados antes de + /// apagar nós. + /// + /// Esta variável guarda a expressão lambda que usamos no sinal PlayerSpellCast + /// para ser desconectado em ConsumedBy. + /// + private SignalBus.PlayerSpellCastEventHandler bindSignal = null; public override bool Activate(ItemAction action) { + if (awaitingTermination) + { + return false; + } + // Feitiços de pergaminhos são gratuitos. + Spell.Cost = 0; + Player consumer = action.Player; - MessageLogData.Instance.AddMessage("Foste cuckado"); - ConsumedBy(consumer); + // Alguns feitiços precisam de um alvo escolhido pelo jogador. + // Não podemos esperar pelo jogador aqui, a função precisa retornar de forma síncrona. + // + // Então, se o feitiço precisar de um alvo, foi montada uma infraestrutura de sinais + // para garantir que: + // 1. O jogador possa escolher uma localização qualquer. + // 2. Uma ação seja gerada com a posição escolhida e dentro de um inputHandler para entrar + // no ciclo de turnos normalmente. + // 3. O pergaminho seja destruído quando o feitiço for executado com sucesso. + if (Spell.Type == SpellType.Ranged) + { + // Este delegate existe somente para que eu possa desconectar o sinal de quando o feitiço é executado. + // A engine exige que desconectemos sinais customizados antes de apagar um nó. + bindSignal = delegate (bool success) { OnPlayerChoseTarget(success, action.Player); }; + + // Eu mando dois sinais aqui. um deles avisa para o input handler trocar para o estado de + // escolher posição de feitiço e o outro informa este inputhandler o feitiço deste pergaminho. + SignalBus.Instance.EmitSignal(SignalBus.SignalName.CommandInputHandler, (int)InputHandlers.CastSpell); + SignalBus.Instance.EmitSignal(SignalBus.SignalName.PlayerSpellChooseLocation, Spell); + + // Eu também conecto nosso delegate declarado anteriormente para quando o feitiço for executado. + SignalBus.Instance.PlayerSpellCast += bindSignal; + awaitingTermination = true; + + return true; + } + return true; } + + public override void ConsumedBy(Player consumer) + { + // De novo, a engine exige que desconectemos o sinal antes de destruir o pergaminho. + if (bindSignal != null) + { + SignalBus.Instance.PlayerSpellCast -= bindSignal; + } + base.ConsumedBy(consumer); + } + + /// + /// Este método é executado quando o feitiço deste pergaminho for executado + /// (depois do jogador escolher um alvo.) + /// + /// Se o feitiço for executado com sucesso. + /// Quem ativou o feitiço. + private void OnPlayerChoseTarget(bool success, Player consumer) { + if (success) + { + ConsumedBy(consumer); + } + else + { + // Se o feitiço não for ativado com sucesso, + // podemos reutilizar o pergaminho. + awaitingTermination = false; + } + } } \ No newline at end of file -- cgit v1.2.3