Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion BaseLib/localization/eng/static_hover_tips.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,7 @@
"BASELIB-EXHAUSTIVE.title": "Exhaustive",
"BASELIB-EXHAUSTIVE.description": "This card [gold]Exhausts[/gold] after {Exhaustive:cond:>1?[blue]{Exhaustive}[/blue] |}{Exhaustive:plural:use|uses}.",
"BASELIB-REFUND.title": "Refund",
"BASELIB-REFUND.description": "When energy is spent on this card, up to [blue]{Refund}[/blue] of that energy is refunded."
"BASELIB-REFUND.description": "When energy is spent on this card, up to [blue]{Refund}[/blue] of that energy is refunded.",
"BASELIB-VITALITY.title": "Vitality",
"BASELIB-VITALITY.description": "Until the end of combat, prevents HP loss."
}
14 changes: 14 additions & 0 deletions Cards/Variables/VitalityVar.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
using BaseLib.Extensions;
using MegaCrit.Sts2.Core.Localization.DynamicVars;

namespace BaseLib.Cards.Variables;

public class VitalityVar : DynamicVar
{
public const string Key = "Vitality";

public VitalityVar(decimal baseValue) : base(Key, baseValue)
{
this.WithTooltip();
}
}
161 changes: 161 additions & 0 deletions Commands/VitalityCmd.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
using MegaCrit.Sts2.Core.Combat;
using MegaCrit.Sts2.Core.Combat.History;
using MegaCrit.Sts2.Core.Commands;
using MegaCrit.Sts2.Core.Entities.Cards;
using MegaCrit.Sts2.Core.Entities.Creatures;
using MegaCrit.Sts2.Core.Models;
using BaseLib.Hooks;
using BaseLib.Patches;

namespace BaseLib.Commands;

public class VitalityCmd
{
public static async Task<Decimal> GainVitality(
Creature creature,
Decimal amount,
CardPlay? cardPlay,
bool fast = false)
{
if (CombatManager.Instance.IsOverOrEnding)
return 0M;
CombatState combatState = creature.CombatState;
await BeforeVitalityGained(combatState, creature, amount, cardPlay?.Card);
Decimal modifiedAmount = amount;
IEnumerable<AbstractModel> modifiers;
modifiedAmount = ModifyVitality(combatState, creature, modifiedAmount, cardPlay.Card, cardPlay, out modifiers);
modifiedAmount = Math.Max(modifiedAmount, 0M);
await AfterModifyingVitalityAmount(combatState, modifiedAmount, cardPlay?.Card, cardPlay, modifiers);
if (modifiedAmount > 0M)
{
SfxCmd.Play("event:/sfx/heal");
VfxCmd.PlayOnCreatureCenter(creature, "vfx/vfx_cross_heal");
VitalityPatch.VitalityField.SetVitality(creature, (int) amount + VitalityPatch.VitalityField.GetVitality(creature));
CombatManager.Instance.History.Add(new VitalityGainedEntry((int)modifiedAmount, cardPlay, creature, combatState.RoundNumber, combatState.CurrentSide, CombatManager.Instance.History));
if (fast)
await Cmd.CustomScaledWait(0.0f, 0.03f);
else
await Cmd.CustomScaledWait(0.1f, 0.25f);
}
await AfterVitalityGained(combatState, creature, modifiedAmount, cardPlay?.Card);
return modifiedAmount;
}

static decimal ModifyVitality(
CombatState combatState,
Creature creature,
Decimal amount,
CardModel? cardSource,
CardPlay? cardPlay,
out IEnumerable<AbstractModel> modifiers)
{
decimal num = amount;
List<AbstractModel> abstractModelList = new List<AbstractModel>();

foreach (var item in combatState.IterateHookListeners())
{
if (item is IVitalityAmountModifier mod)
{
var num2 = mod.ModifyVitalityAdditive(creature, num, cardSource, cardPlay);
num += num2;
if (num2 != 0M)
abstractModelList.Add(item);
}
}

foreach (var item in combatState.IterateHookListeners())
{
if (item is IVitalityAmountModifier mod)
{
var num2 = mod.ModifyVitalityMultiplicative(creature, num, cardSource, cardPlay);
num *= num2;
if (num2 != 0M)
abstractModelList.Add(item);
}
}

modifiers = abstractModelList;
return Math.Max(0m, num);
}

static async Task BeforeVitalityGained(
CombatState combatState,
Creature creature,
Decimal amount,
CardModel? cardSource)
{
foreach (var item in combatState.IterateHookListeners())
{
if (item is IVitalityHooks mod)
{
await mod.BeforeVitalityGained(creature, amount, cardSource);
item.InvokeExecutionFinished();
}
}
}

static async Task AfterModifyingVitalityAmount(
CombatState combatState,
Decimal amount,
CardModel? cardSource,
CardPlay? cardPlay,
IEnumerable<AbstractModel> modifiers)
{
foreach (var item in combatState.IterateHookListeners())
{
if (item is IVitalityHooks mod && modifiers.Contains(item))
{
await mod.AfterModifyingVitalityAmount(amount, cardSource, cardPlay);
item.InvokeExecutionFinished();
}
}
}

static async Task AfterVitalityGained(
CombatState combatState,
Creature creature,
Decimal amount,
CardModel? cardSource)
{
foreach (var item in combatState.IterateHookListeners())
{
if (item is IVitalityHooks mod)
{
await mod.AfterVitalityGained(creature, amount, cardSource);
item.InvokeExecutionFinished();
}
}
}

private class VitalityGainedEntry : CombatHistoryEntry
{
public int Amount { get; }

public Creature Receiver => Actor;

public CardPlay? CardPlay { get; }

public override string Description
{
get => $"{GetId(Receiver)} gained {Amount} vitality";
}

public VitalityGainedEntry(
int amount,
CardPlay? cardPlay,
Creature receiver,
int roundNumber,
CombatSide currentSide,
CombatHistory history)
: base(receiver, roundNumber, currentSide, history)
{
Amount = amount;
CardPlay = cardPlay;
}

public static string GetId(Creature creature)
{
return !creature.IsPlayer ? creature.Monster.Id.Entry : creature.Player.Character.Id.Entry;
}
}
}
27 changes: 27 additions & 0 deletions Hooks/IVitalityAmountModifier.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
using MegaCrit.Sts2.Core.Entities.Cards;
using MegaCrit.Sts2.Core.Entities.Creatures;
using MegaCrit.Sts2.Core.Models;

namespace BaseLib.Hooks;

public interface IVitalityAmountModifier
{
/// <summary>
/// Return the amount to add.
/// </summary>
/// <param name="creature"></param>
/// <param name="amount"></param>
/// <param name="cardSource"></param>
/// <param name="cardPlay"></param>
/// <returns></returns>
decimal ModifyVitalityAdditive(Creature creature, decimal amount, CardModel cardSource, CardPlay? cardPlay) => 0m;
/// <summary>
/// Return the amount to multiply by.
/// </summary>
/// <param name="creature"></param>
/// <param name="amount"></param>
/// <param name="cardSource"></param>
/// <param name="cardPlay"></param>
/// <returns></returns>
decimal ModifyVitalityMultiplicative(Creature creature, decimal amount, CardModel cardSource, CardPlay? cardPlay) => 1m;
}
1 change: 1 addition & 0 deletions Hooks/IVitalityAmountModifier.cs.uid
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
uid://bwf5fpvjk8j0x
34 changes: 34 additions & 0 deletions Hooks/IVitalityHooks.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
using MegaCrit.Sts2.Core.Entities.Cards;
using MegaCrit.Sts2.Core.Entities.Creatures;
using MegaCrit.Sts2.Core.Models;

namespace BaseLib.Hooks;

public interface IVitalityHooks
{
/// <summary>
/// Called before Vitality is gained.
/// </summary>
/// <param name="creature"></param>
/// <param name="amount"></param>
/// <param name="cardSource"></param>
/// <returns></returns>
Task BeforeVitalityGained (Creature creature, decimal amount, CardModel cardSource) => Task.CompletedTask;
/// <summary>
/// Called after if Vitality was modified by Model, but before Vitality is gained.
/// </summary>
/// <param name="amount"></param>
/// <param name="cardSource"></param>
/// <param name="cardPlay"></param>
/// <returns></returns>
Task AfterModifyingVitalityAmount(decimal amount, CardModel cardSource, CardPlay? cardPlay) => Task.CompletedTask;

/// <summary>
/// Called after Vitality is gained.
/// </summary>
/// <param name="creature"></param>
/// <param name="amount"></param>
/// <param name="cardSource"></param>
/// <returns></returns>
Task AfterVitalityGained(Creature creature, decimal amount, CardModel cardSource) => Task.CompletedTask;
}
Loading