Embed RHS 1.9 compatibility; record Workshop 0.0.141
continuous-integration/drone/push Build is passing
continuous-integration/drone/push Build is passing
This commit is contained in:
+106
@@ -0,0 +1,106 @@
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user