107 lines
5.8 KiB
C
107 lines
5.8 KiB
C
// Native injection animation/consumption; only resilience is restored over time.
|
|
// This is not a blood replacement, bandage, full heal, or resurrection.
|
|
[BaseContainerProps()]
|
|
class ERR_ConsumableEpinephrine : SCR_ConsumableMorphine
|
|
{
|
|
override bool CanApplyEffect(notnull IEntity target, notnull IEntity user, out SCR_EConsumableFailReason failReason)
|
|
{
|
|
SCR_CharacterDamageManagerComponent damage = SCR_CharacterDamageManagerComponent.Cast(target.FindComponent(SCR_CharacterDamageManagerComponent));
|
|
CharacterControllerComponent controller = CharacterControllerComponent.Cast(target.FindComponent(CharacterControllerComponent));
|
|
if (!damage || damage.GetState() == EDamageState.DESTROYED || !controller || !controller.IsUnconscious())
|
|
{ failReason = SCR_EConsumableFailReason.UNDAMAGED; return false; }
|
|
array<ref SCR_PersistentDamageEffect> effects = damage.GetAllPersistentEffectsOfType(ERR_EpinephrineEffect);
|
|
if (!effects.IsEmpty()) { failReason = SCR_EConsumableFailReason.ALREADY_APPLIED; return false; }
|
|
return true;
|
|
}
|
|
}
|
|
class ERR_EpinephrineEffect : SCR_DotDamageEffect
|
|
{
|
|
override bool HijackDamageEffect(SCR_ExtendedDamageManagerComponent dmgManager)
|
|
{
|
|
SCR_CharacterDamageManagerComponent damage = SCR_CharacterDamageManagerComponent.Cast(dmgManager);
|
|
if (damage) SetAffectedHitZone(damage.GetResilienceHitZone());
|
|
return false;
|
|
}
|
|
override EDamageType GetDefaultDamageType() { return EDamageType.HEALING; }
|
|
}
|
|
// Separate stronger field injector. Standard epinephrine above keeps its
|
|
// resilience-over-time behavior; neither item restores a dead character.
|
|
class ERR_CombatEpinephrineRules
|
|
{
|
|
static float Heal(float current, bool leg)
|
|
{
|
|
float amount = 0.15;
|
|
if (leg) amount = 0.5;
|
|
return Math.Min(current + amount, 1.0);
|
|
}
|
|
static float Blood(float current, float threshold) { return Math.Min(1, current + threshold + 0.01); }
|
|
}
|
|
[BaseContainerProps()]
|
|
class ERR_ConsumableCombatEpinephrine : SCR_ConsumableMorphine
|
|
{
|
|
override bool CanApplyEffect(notnull IEntity target, notnull IEntity user, out SCR_EConsumableFailReason failReason)
|
|
{
|
|
SCR_CharacterDamageManagerComponent damage = SCR_CharacterDamageManagerComponent.Cast(target.FindComponent(SCR_CharacterDamageManagerComponent));
|
|
if (!damage || damage.GetState() == EDamageState.DESTROYED) { failReason = SCR_EConsumableFailReason.UNDAMAGED; return false; }
|
|
if (damage.IsBleeding()) return true;
|
|
HitZone blood = damage.GetBloodHitZone(), resilience = damage.GetResilienceHitZone();
|
|
if ((blood && blood.GetHealthScaled() <= blood.GetDamageStateThreshold(ECharacterBloodState.FAINTING)) || (resilience && resilience.GetHealthScaled() < 1)) return true;
|
|
array<HitZone> zones = {}; damage.GetPhysicalHitZones(zones);
|
|
foreach (HitZone zone : zones) if (zone && zone.GetHealthScaled() < 1) return true;
|
|
failReason = SCR_EConsumableFailReason.UNDAMAGED; return false;
|
|
}
|
|
}
|
|
class ERR_CombatEpinephrineEffect : SCR_InstantDamageEffect
|
|
{
|
|
override EDamageType GetDefaultDamageType() { return EDamageType.HEALING; }
|
|
override void OnEffectAdded(SCR_ExtendedDamageManagerComponent dmgManager)
|
|
{
|
|
super.OnEffectAdded(dmgManager);
|
|
if (!Replication.IsServer()) return;
|
|
SCR_CharacterDamageManagerComponent damage = SCR_CharacterDamageManagerComponent.Cast(dmgManager);
|
|
if (!damage || damage.GetState() == EDamageState.DESTROYED) return;
|
|
foreach (ECharacterHitZoneGroup group : {ECharacterHitZoneGroup.HEAD, ECharacterHitZoneGroup.UPPERTORSO, ECharacterHitZoneGroup.LOWERTORSO, ECharacterHitZoneGroup.LEFTARM, ECharacterHitZoneGroup.RIGHTARM, ECharacterHitZoneGroup.LEFTLEG, ECharacterHitZoneGroup.RIGHTLEG}) damage.RemoveGroupBleeding(group);
|
|
SCR_CharacterBloodHitZone blood = damage.GetBloodHitZone();
|
|
if (blood && blood.GetHealthScaled() <= blood.GetDamageStateThreshold(ECharacterBloodState.FAINTING))
|
|
blood.SetHealthScaled(ERR_CombatEpinephrineRules.Blood(blood.GetHealthScaled(), blood.GetDamageStateThreshold(ECharacterBloodState.UNCONSCIOUS)));
|
|
SCR_CharacterResilienceHitZone resilience = damage.GetResilienceHitZone();
|
|
if (resilience) resilience.SetHealthScaled(1);
|
|
array<HitZone> zones = {}; damage.GetPhysicalHitZones(zones);
|
|
foreach (HitZone zone : zones)
|
|
{
|
|
SCR_CharacterHitZone physical = SCR_CharacterHitZone.Cast(zone);
|
|
if (!physical || zone.GetHealthScaled() >= 1) continue;
|
|
int group = physical.GetHitZoneGroup();
|
|
zone.SetHealthScaled(ERR_CombatEpinephrineRules.Heal(zone.GetHealthScaled(), group == ECharacterHitZoneGroup.LEFTLEG || group == ECharacterHitZoneGroup.RIGHTLEG));
|
|
}
|
|
CharacterControllerComponent controller = CharacterControllerComponent.Cast(damage.GetOwner().FindComponent(CharacterControllerComponent));
|
|
if (controller && controller.IsUnconscious()) controller.SetUnconscious(false);
|
|
}
|
|
}
|
|
// The held injector uses the existing native injection interaction and animation.
|
|
// Only its displayed name changes; ordinary morphine keeps its native behavior.
|
|
modded class SCR_MorphineUserAction
|
|
{
|
|
protected bool m_ERRHoldingEpinephrine;
|
|
protected bool m_ERRHoldingCombatEpinephrine;
|
|
override bool CanBeShownScript(IEntity user)
|
|
{
|
|
m_ERRHoldingEpinephrine = false; m_ERRHoldingCombatEpinephrine = false;
|
|
bool shown = super.CanBeShownScript(user);
|
|
ChimeraCharacter character = ChimeraCharacter.Cast(user);
|
|
if (shown && character)
|
|
{
|
|
SCR_ConsumableItemComponent item = GetConsumableComponent(character);
|
|
m_ERRHoldingEpinephrine = item && ERR_ConsumableEpinephrine.Cast(item.GetConsumableEffect());
|
|
m_ERRHoldingCombatEpinephrine = item && ERR_ConsumableCombatEpinephrine.Cast(item.GetConsumableEffect());
|
|
}
|
|
return shown;
|
|
}
|
|
override bool GetActionNameScript(out string outName)
|
|
{
|
|
if (m_ERRHoldingCombatEpinephrine) { outName = "Administer combat epinephrine"; return true; }
|
|
if (m_ERRHoldingEpinephrine) { outName = "Administer epinephrine"; return true; }
|
|
return super.GetActionNameScript(outName);
|
|
}
|
|
}
|