-
Notifications
You must be signed in to change notification settings - Fork 20
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Medical - Add framework for pain dynamics || Improve code readability and error handling #95
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -5,54 +5,77 @@ modded class SCR_CharacterControllerComponent : CharacterControllerComponent | |||||
{ | ||||||
protected SCR_CharacterDamageManagerComponent m_pACE_Medical_DamageManager; | ||||||
protected const float ACE_MEDICAL_SECOND_CHANCE_DEACTIVATION_TIMEOUT_MS = 1000; | ||||||
|
||||||
//------------------------------------------------------------------------------------------------ | ||||||
//! Initialize member variables | ||||||
//! Initialize member variables. | ||||||
override void OnInit(IEntity owner) | ||||||
{ | ||||||
super.OnInit(owner); | ||||||
m_pACE_Medical_DamageManager = SCR_CharacterDamageManagerComponent.Cast(owner.FindComponent(SCR_CharacterDamageManagerComponent)); | ||||||
|
||||||
// Add null check to avoid potential null reference errors | ||||||
if (!m_pACE_Medical_DamageManager) | ||||||
{ | ||||||
Print("ACE Medical Damage Manager not found!", LogLevel.ERROR); | ||||||
return; | ||||||
} | ||||||
} | ||||||
|
||||||
//------------------------------------------------------------------------------------------------ | ||||||
//! Add/remove second chance when life state changes | ||||||
override void OnLifeStateChanged(ECharacterLifeState previousLifeState, ECharacterLifeState newLifeState) | ||||||
{ | ||||||
super.OnLifeStateChanged(previousLifeState, newLifeState); | ||||||
// Only run if ACE Medical has been initialized for this character | ||||||
|
||||||
// Check if ACE Medical has been initialized | ||||||
if (!m_pACE_Medical_DamageManager.ACE_Medical_IsInitialized()) | ||||||
return; | ||||||
|
||||||
// OnLifeStateChanged sometimes gets triggered without a change in state | ||||||
if (previousLifeState == newLifeState) | ||||||
return; | ||||||
|
||||||
switch (newLifeState) | ||||||
{ | ||||||
// Add second chance when revived | ||||||
case ECharacterLifeState.ALIVE: | ||||||
{ | ||||||
GetGame().GetCallqueue().Remove(m_pACE_Medical_DamageManager.ACE_Medical_EnableSecondChance); | ||||||
m_pACE_Medical_DamageManager.ACE_Medical_EnableSecondChance(true); | ||||||
m_pACE_Medical_DamageManager.ACE_Medical_SetSecondChanceTrigged(false); | ||||||
HandleAliveState(); | ||||||
break; | ||||||
} | ||||||
|
||||||
// Schedule removal of second chance when falling unconscious | ||||||
|
||||||
case ECharacterLifeState.INCAPACITATED: | ||||||
{ | ||||||
GetGame().GetCallqueue().CallLater(m_pACE_Medical_DamageManager.ACE_Medical_EnableSecondChance, ACE_MEDICAL_SECOND_CHANCE_DEACTIVATION_TIMEOUT_MS, false, false); | ||||||
HandleIncapacitatedState(); | ||||||
break; | ||||||
} | ||||||
|
||||||
// Remove second chance when dead | ||||||
|
||||||
case ECharacterLifeState.DEAD: | ||||||
{ | ||||||
GetGame().GetCallqueue().Remove(m_pACE_Medical_DamageManager.ACE_Medical_EnableSecondChance); | ||||||
m_pACE_Medical_DamageManager.ACE_Medical_EnableSecondChance(false); | ||||||
HandleDeadState(); | ||||||
break; | ||||||
} | ||||||
} | ||||||
} | ||||||
|
||||||
//------------------------------------------------------------------------------------------------ | ||||||
//! Handle logic when character is revived (ALIVE state) | ||||||
void HandleAliveState() | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this is not a public API
Suggested change
|
||||||
{ | ||||||
auto callQueue = GetGame().GetCallqueue(); | ||||||
callQueue.Remove(m_pACE_Medical_DamageManager.ACE_Medical_EnableSecondChance); | ||||||
m_pACE_Medical_DamageManager.ACE_Medical_EnableSecondChance(true); | ||||||
m_pACE_Medical_DamageManager.ACE_Medical_SetSecondChanceTriggered(false); | ||||||
} | ||||||
|
||||||
//------------------------------------------------------------------------------------------------ | ||||||
//! Handle logic when character is incapacitated (INCAPACITATED state) | ||||||
void HandleIncapacitatedState() | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
{ | ||||||
auto callQueue = GetGame().GetCallqueue(); | ||||||
callQueue.CallLater(m_pACE_Medical_DamageManager.ACE_Medical_EnableSecondChance, ACE_MEDICAL_SECOND_CHANCE_DEACTIVATION_TIMEOUT_MS, false, false); | ||||||
} | ||||||
|
||||||
//------------------------------------------------------------------------------------------------ | ||||||
//! Handle logic when character is dead (DEAD state) | ||||||
void HandleDeadState() | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
{ | ||||||
auto callQueue = GetGame().GetCallqueue(); | ||||||
callQueue.Remove(m_pACE_Medical_DamageManager.ACE_Medical_EnableSecondChance); | ||||||
m_pACE_Medical_DamageManager.ACE_Medical_EnableSecondChance(false); | ||||||
} | ||||||
} | ||||||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -15,9 +15,6 @@ modded class SCR_CharacterDamageManagerComponent : SCR_DamageManagerComponent | |
protected float m_fACE_Medical_ModeratePainThreshold; | ||
protected float m_fACE_Medical_SeriousPainThreshold; | ||
|
||
// We only notify the replication system about changes of these members on initialization | ||
// After init, each proxy is itself responsible for updating these members | ||
// Having them as RplProp also ensures that JIPs receive the current state from the server | ||
Comment on lines
-18
to
-20
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't see the point of removing a useful comment. |
||
[RplProp()] | ||
protected bool m_bACE_Medical_Initialized = false; | ||
[RplProp()] | ||
|
@@ -26,41 +23,50 @@ modded class SCR_CharacterDamageManagerComponent : SCR_DamageManagerComponent | |
protected bool m_bACE_Medical_SecondChanceOnHeadEnabled = false; | ||
[RplProp()] | ||
protected bool m_bACE_Medical_SecondChanceTriggered = false; | ||
|
||
//----------------------------------------------------------------------------------------------------------- | ||
//! Initialize member variables | ||
//! Initialize member variables. | ||
override void OnInit(IEntity owner) | ||
{ | ||
super.OnInit(owner); | ||
|
||
|
||
// Initialize Health Hit Zone | ||
m_pACE_Medical_HealthHitZone = GetHitZoneByName("Health"); | ||
if (!m_pACE_Medical_HealthHitZone) | ||
{ | ||
Print("ACE Medical: Health hit zone not found!", LogLevel.ERROR); | ||
return; | ||
|
||
} | ||
|
||
m_fACE_Medical_CriticalHealth = m_pACE_Medical_HealthHitZone.GetDamageStateThreshold(ECharacterHealthState.CRITICAL); | ||
GetPhysicalHitZones(m_aACE_Medical_PhysicalHitZones); | ||
|
||
// Log initialization success | ||
Print("ACE Medical: Character Damage Manager initialized.", LogLevel.INFO); | ||
} | ||
|
||
//----------------------------------------------------------------------------------------------------------- | ||
//! Initialize ACE medical on a character damage manager (Called on the server) | ||
void ACE_Medical_Initialize() | ||
{ | ||
if (m_bACE_Medical_Initialized) | ||
return; | ||
|
||
ACE_Medical_Settings settings = ACE_SettingsHelperT<ACE_Medical_Settings>.GetModSettings(); | ||
if (settings) | ||
{ | ||
m_bACE_Medical_SecondChanceOnHeadEnabled = settings.m_bSecondChanceOnHeadEnabled; | ||
m_fACE_Medical_SecondChanceRegenScale = settings.m_fSecondChanceRegenScale; | ||
} | ||
|
||
ACE_Medical_EnableSecondChance(true); | ||
// Damage calculations are done on all machines, so we have to broadcast the init | ||
m_bACE_Medical_Initialized = true; | ||
Replication.BumpMe(); | ||
|
||
// Log successful initialization | ||
Print("ACE Medical: Initialized with second chance enabled.", LogLevel.INFO); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could you add info about |
||
} | ||
|
||
//------------------------------------------------------------------------------------------------ | ||
// Reduce regeneration rate when second chance was triggered | ||
override float GetResilienceRegenScale() | ||
|
@@ -70,17 +76,14 @@ modded class SCR_CharacterDamageManagerComponent : SCR_DamageManagerComponent | |
{ | ||
return m_fACE_Medical_SecondChanceRegenScale; | ||
} | ||
else | ||
{ | ||
return scale; | ||
} | ||
return scale; | ||
} | ||
|
||
//------------------------------------------------------------------------------------------------ | ||
//! Returns true if health hit zone has critical health | ||
bool ACE_Medical_HasCriticalHealth() | ||
{ | ||
return m_pACE_Medical_HealthHitZone.GetHealthScaled() <= m_fACE_Medical_CriticalHealth; | ||
return m_pACE_Medical_HealthHitZone && m_pACE_Medical_HealthHitZone.GetHealthScaled() <= m_fACE_Medical_CriticalHealth; | ||
} | ||
|
||
//------------------------------------------------------------------------------------------------ | ||
|
@@ -92,7 +95,7 @@ modded class SCR_CharacterDamageManagerComponent : SCR_DamageManagerComponent | |
if (hitZone.GetHealthScaled() < 0.999) | ||
return true; | ||
} | ||
|
||
return false; | ||
} | ||
|
||
|
@@ -101,6 +104,14 @@ modded class SCR_CharacterDamageManagerComponent : SCR_DamageManagerComponent | |
void ACE_Medical_SetPainHitZone(HitZone hitzone) | ||
{ | ||
m_pACE_Medical_PainHitZone = ACE_Medical_PainHitZone.Cast(hitzone); | ||
|
||
// Null Check | ||
if (!m_pACE_Medical_PainHitZone) | ||
{ | ||
Print("ACE Medical: Pain hit zone not found!", LogLevel.ERROR); | ||
return; | ||
} | ||
|
||
m_fACE_Medical_ModeratePainThreshold = m_pACE_Medical_PainHitZone.GetDamageStateThreshold(ECharacterHealthState.MODERATE); | ||
m_fACE_Medical_SeriousPainThreshold = m_pACE_Medical_PainHitZone.GetDamageStateThreshold(ECharacterHealthState.SERIOUS); | ||
} | ||
|
@@ -111,33 +122,38 @@ modded class SCR_CharacterDamageManagerComponent : SCR_DamageManagerComponent | |
{ | ||
return m_pACE_Medical_PainHitZone; | ||
} | ||
|
||
//----------------------------------------------------------------------------------------------------------- | ||
//! Returns true if pain hit zone is at least moderately damaged | ||
bool ACE_Medical_IsInPain() | ||
{ | ||
return m_pACE_Medical_PainHitZone.GetHealthScaled() <= m_fACE_Medical_ModeratePainThreshold; | ||
return m_pACE_Medical_PainHitZone && m_pACE_Medical_PainHitZone.GetHealthScaled() <= m_fACE_Medical_ModeratePainThreshold; | ||
} | ||
|
||
//----------------------------------------------------------------------------------------------------------- | ||
//! Returns intensity of pain used for ACE_Medical_PainScreenEffect | ||
float ACE_Medical_GetPainIntensity() | ||
{ | ||
if (!m_pACE_Medical_PainHitZone) | ||
{ | ||
Print("ACE Medical: Pain hit zone not initialized!", LogLevel.ERROR); | ||
return 0; | ||
} | ||
|
||
// Clamp between serious damage and full health | ||
float scaledHealth = Math.Clamp(m_pACE_Medical_PainHitZone.GetHealthScaled(), m_fACE_Medical_SeriousPainThreshold, 1); | ||
|
||
if (scaledHealth > m_fACE_Medical_ModeratePainThreshold) | ||
{ | ||
// No effect when less than moderate damage | ||
return 0; | ||
return 0; // No effect when less than moderate damage | ||
} | ||
else | ||
{ | ||
// Linear response from full health -> 0 to serious damage -> 1 | ||
return Math.InverseLerp(1, m_fACE_Medical_SeriousPainThreshold, scaledHealth); | ||
} | ||
} | ||
|
||
//------------------------------------------------------------------------------------------------ | ||
//! Returns true if ACE Medical has been initialized | ||
bool ACE_Medical_IsInitialized() | ||
|
@@ -150,38 +166,44 @@ modded class SCR_CharacterDamageManagerComponent : SCR_DamageManagerComponent | |
void ACE_Medical_EnableSecondChance(bool enable) | ||
{ | ||
m_bACE_Medical_HasSecondChance = enable; | ||
|
||
// Log state change | ||
Print("ACE Medical: Second chance " + (enable ? "enabled" : "disabled") + ".", LogLevel.INFO); | ||
} | ||
|
||
//------------------------------------------------------------------------------------------------ | ||
//! Check if second chance is enabled | ||
bool ACE_Medical_HasSecondChance() | ||
{ | ||
return m_bACE_Medical_HasSecondChance; | ||
} | ||
|
||
//----------------------------------------------------------------------------------------------------------- | ||
//! Returns true if second chance is enabled for the given hit zone | ||
bool ACE_Medical_HasSecondChanceOnHitZone(HitZone hitZone) | ||
{ | ||
if (!m_bACE_Medical_HasSecondChance) | ||
return false; | ||
|
||
if (m_bACE_Medical_SecondChanceOnHeadEnabled) | ||
return true; | ||
|
||
return (hitZone != m_pHeadHitZone); | ||
} | ||
|
||
//------------------------------------------------------------------------------------------------ | ||
//! To be set true when second chance was used | ||
void ACE_Medical_SetSecondChanceTrigged(bool isTriggered) | ||
void ACE_Medical_SetSecondChanceTriggered(bool isTriggered) | ||
{ | ||
m_bACE_Medical_SecondChanceTriggered = isTriggered; | ||
|
||
// Log state change | ||
Print("ACE Medical: Second chance triggered state set to " + isTriggered, LogLevel.INFO); | ||
} | ||
|
||
//------------------------------------------------------------------------------------------------ | ||
//! Check if second chance was used | ||
bool ACE_Medical_WasSecondChanceTrigged() | ||
bool ACE_Medical_WasSecondChanceTriggered() | ||
{ | ||
return m_bACE_Medical_SecondChanceTriggered; | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
None of the other doc blocks end with a punctuation, keep consistent