Browse Source

Add `OnDamage` signal for health component

pull/8/head
Anton Tarasenko 2 years ago
parent
commit
d03b452cbb
  1. 38
      sources/Gameplay/BaseClasses/Frontend/Health/AHealthComponent.uc
  2. 38
      sources/Gameplay/BaseClasses/Frontend/Health/Events/Health_OnDamage_Signal.uc
  3. 40
      sources/Gameplay/BaseClasses/Frontend/Health/Events/Health_OnDamage_Slot.uc
  4. 64
      sources/Gameplay/KF1Frontend/Health/KF1_HealthComponent.uc

38
sources/Gameplay/BaseClasses/Frontend/Health/AHealthComponent.uc

@ -21,6 +21,44 @@
class AHealthComponent extends AcediaObject
abstract;
var protected Health_OnDamage_Signal onDamageSignal;
protected function Constructor()
{
onDamageSignal = Health_OnDamage_Signal(
_.memory.Allocate(class'Health_OnDamage_Signal'));
}
protected function Finalizer()
{
_.memory.Free(onDamageSignal);
onDamageSignal = none;
}
/**
* Signal that will be emitted whenever trading time starts.
*
* [Signature]
* void <slot>(EPawn target, EPawn instigator, HashTable damageData)
*
* @param target Pawn that took damage.
* @param instigator Pawn responsible for dealing damage.
* @param damageData Data set related to damage. Exact stored values can
* differ based on the implementation, but any implementation must support
* at least 4 values: "damage" - `int` value representing amount of damage
* `target will be dealt, "originalDamage" - originally intended damage for
* `target`, before other event handlers altered "damage" value (you can
* modify this value, but you shouldn't), "hitLocation" - `Vector` that
* describes the point of contact with whatever dealt this damage and
* "momentum" - `Vector` value describing momentum transferred to `target`
* as a result of the damage dealt.
*/
/* SIGNAL */
public final function Health_OnDamage_Slot OnDamage(AcediaObject receiver)
{
return Health_OnDamage_Slot(onDamageSignal.NewSlot(receiver));
}
defaultproperties
{
}

38
sources/Gameplay/BaseClasses/Frontend/Health/Events/Health_OnDamage_Signal.uc

@ -0,0 +1,38 @@
/**
* Signal class for `AHealthComponent` on damage events.
* Copyright 2022 Anton Tarasenko
*------------------------------------------------------------------------------
* This file is part of Acedia.
*
* Acedia is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3 of the License, or
* (at your option) any later version.
*
* Acedia is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Acedia. If not, see <https://www.gnu.org/licenses/>.
*/
class Health_OnDamage_Signal extends Signal;
public final function Emit(EPawn target, EPawn instigator, HashTable damageData)
{
local Slot nextSlot;
StartIterating();
nextSlot = GetNextSlot();
while (nextSlot != none)
{
Health_OnDamage_Slot(nextSlot).connect(target, instigator, damageData);
nextSlot = GetNextSlot();
}
CleanEmptySlots();
}
defaultproperties
{
relatedSlotClass = class'Health_OnDamage_Slot'
}

40
sources/Gameplay/BaseClasses/Frontend/Health/Events/Health_OnDamage_Slot.uc

@ -0,0 +1,40 @@
/**
* Slot class for `AHealthComponent` on damage events.
* Copyright 2022 Anton Tarasenko
*------------------------------------------------------------------------------
* This file is part of Acedia.
*
* Acedia is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3 of the License, or
* (at your option) any later version.
*
* Acedia is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Acedia. If not, see <https://www.gnu.org/licenses/>.
*/
class Health_OnDamage_Slot extends Slot;
delegate connect(EPawn target, EPawn instigator, HashTable damageData)
{
DummyCall();
}
protected function Constructor()
{
connect = none;
}
protected function Finalizer()
{
super.Finalizer();
connect = none;
}
defaultproperties
{
}

64
sources/Gameplay/KF1Frontend/Health/KF1_HealthComponent.uc

@ -49,12 +49,15 @@ class KF1_HealthComponent extends AHealthComponent
*/
var private const config bool replaceBloatAndSirenDamageTypes;
var private const int TDAMAGE, TORIGINAL_DAMAGE, THIT_LOCATION, TMOMENTUM;
var private LoggerAPI.Definition infoReplacingDamageTypes, errNoServerLevelCore;
var private LoggerAPI.Definition infoRestoringReplacingDamageTypes;
public function PseudoConstructor()
{
local LevelCore core;
_.unreal.gameRules.OnNetDamage(self).connect = OnNetDamageHandler;
if (!replaceBloatAndSirenDamageTypes) {
return;
@ -75,6 +78,7 @@ public function PseudoConstructor()
protected function Finalizer()
{
super.Finalizer();
_.unreal.gameRules.OnNetDamage(self).Disconnect();
_.unreal.gameRules.OnScoreKill(self).Disconnect();
if (replaceBloatAndSirenDamageTypes) {
@ -135,10 +139,55 @@ private function int OnNetDamageHandler(
out Vector momentum,
class<DamageType> damageType)
{
if (damageType != class'Dummy_DamTypeVomit') return damage;
if (ZombieBloatBase(injured) != none) return 0;
if (ZombieFleshpoundBase(injured) != none) return 0;
damage = EmitDamageSignal(
originalDamage,
damage,
injured,
instigatedBy,
hitLocation,
momentum,
damageType);
if (damageType != class'Dummy_DamTypeVomit') {
return damage;
}
if (ZombieBloatBase(injured) != none) {
return 0;
}
if (ZombieFleshpoundBase(injured) != none) {
return 0;
}
return damage;
}
private function int EmitDamageSignal(
int originalDamage,
int damage,
Pawn injured,
Pawn instigatedBy,
Vector hitLocation,
out Vector momentum,
class<DamageType> damageType)
{
local HashTable damageData;
local EPawn target, instigator;
if (injured != none) {
target = class'EKFPawn'.static.Wrap(injured);
}
if (instigatedBy != none) {
instigator = class'EKFPawn'.static.Wrap(instigatedBy);
}
damageData = _.collections.EmptyHashTable();
damageData.SetInt(T(TDAMAGE), damage);
damageData.SetInt(T(TORIGINAL_DAMAGE), originalDamage);
damageData.SetVector(T(THIT_LOCATION), hitLocation);
damageData.SetVector(T(TMOMENTUM), momentum, true);
onDamageSignal.Emit(target, instigator, damageData);
damage = damageData.GetInt(T(TDAMAGE), damage);
momentum = damageData.GetVector(T(TMOMENTUM), momentum);
_.memory.Free(damageData);
_.memory.Free(instigator);
_.memory.Free(target);
return damage;
}
@ -171,10 +220,17 @@ private function UpdateBileAchievement(Controller killer, Controller killed)
}
}
defaultproperties
{
replaceBloatAndSirenDamageTypes = true
TDAMAGE = 0
stringConstants(0) = "damage"
TORIGINAL_DAMAGE = 1
stringConstants(1) = "originalDamage"
THIT_LOCATION = 2
stringConstants(2) = "hitLocation"
TMOMENTUM = 3
stringConstants(3) = "momentum"
infoReplacingDamageTypes = (l=LOG_Info,m="Replacing bloat's and siren's damage types to dummy ones.")
infoRestoringReplacingDamageTypes = (l=LOG_Info,m="Restoring bloat and siren's damage types to their original values.")
errNoServerLevelCore = (l=LOG_Error,m="Server level core is missing. Either this isn't a server or Acedia was wrongly initialized. Bloat and siren damage type will not be replaced.")

Loading…
Cancel
Save