First draft of basic damage handling.

This commit is contained in:
KoffeinFlummi 2015-02-06 13:47:17 +01:00
parent 79aa8d1c7a
commit a2ee41f01d
9 changed files with 494 additions and 7 deletions

View File

@ -4,3 +4,19 @@ class Extended_PreInit_EventHandlers {
init = QUOTE(call COMPILE_FILE(XEH_preInit));
};
};
class Extended_Init_EventHandlers {
class CAManBase {
class ADDON {
init = QUOTE(call COMPILE_FILE(XEH_init));
};
};
};
class Extended_Respawn_EventHandlers {
class CAManBase {
class ADDON {
respawn = QUOTE(call COMPILE_FILE(XEH_respawn));
};
};
};

View File

@ -0,0 +1,228 @@
class CfgVehicles {
#define ARM_LEG_ARMOR_DEFAULT 2
#define ARM_LEG_ARMOR_BETTER 3
#define ARM_LEG_ARMOR_CSAT 4
class Man;
class CAManBase: Man {
class HitPoints {
class HitHead;
class HitBody;
// "DEACTIVE" DEFAULT HITPOINTS
class HitHands {
armor = 999; //armor = 2;
explosionShielding = 0; //explosionShielding = 1;
material = -1;
minimalHit = 0;
name = "";
passThrough = 1;
radius = 0; //radius = 0.06;
visual = "injury_hands";
};
class HitLegs {
armor = 999; //armor = 2;
explosionShielding = 0; //explosionShielding = 1;
material = -1;
minimalHit = 0;
name = "";
passThrough = 1;
radius = 0; //radius = 0.08;
visual = "injury_legs";
};
class HitLeftArm {
armor = ARM_LEG_ARMOR_DEFAULT; //2;
explosionShielding = 1;
material = -1;
minimalHit = 0;
name = "hand_l";
passThrough = 1;
radius = 0.06;
visual = "injury_hands";
};
class HitRightArm: HitLeftArm {
name = "hand_r";
};
class HitLeftLeg {
armor = ARM_LEG_ARMOR_DEFAULT; //2;
explosionShielding = 1;
material = -1;
minimalHit = 0;
name = "leg_l";
passThrough = 1;
radius = 0.08;
visual = "injury_legs";
};
class HitRightLeg: HitLeftLeg {
name = "leg_r";
};
};
};
class SoldierWB: CAManBase {};
class SoldierEB: CAManBase {};
class SoldierGB: CAManBase {};
class B_Soldier_base_F: SoldierWB {};
class B_Soldier_04_f: B_Soldier_base_F {
class HitPoints: HitPoints {
class HitHead: HitHead {};
class HitBody: HitBody {};
class HitHands: HitHands {};
class HitLegs: HitLegs {};
class HitLeftArm: HitLeftArm {
armor = ARM_LEG_ARMOR_BETTER;
};
class HitRightArm: HitRightArm {
armor = ARM_LEG_ARMOR_BETTER;
};
class HitLeftLeg: HitLeftLeg {
armor = ARM_LEG_ARMOR_BETTER;
};
class HitRightLeg: HitRightLeg {
armor = ARM_LEG_ARMOR_BETTER;
};
};
};
class B_Soldier_05_f: B_Soldier_base_F {
class HitPoints: HitPoints {
class HitHead: HitHead {};
class HitBody: HitBody {};
class HitHands: HitHands {};
class HitLegs: HitLegs {};
class HitLeftArm: HitLeftArm {
armor = ARM_LEG_ARMOR_BETTER;
};
class HitRightArm: HitRightArm {
armor = ARM_LEG_ARMOR_BETTER;
};
class HitLeftLeg: HitLeftLeg {
armor = ARM_LEG_ARMOR_BETTER;
};
class HitRightLeg: HitRightLeg {
armor = ARM_LEG_ARMOR_BETTER;
};
};
};
class I_Soldier_base_F: SoldierGB {};
class I_Soldier_03_F: I_Soldier_base_F {
class HitPoints: HitPoints {
class HitHead: HitHead {};
class HitBody: HitBody {};
class HitHands: HitHands {};
class HitLegs: HitLegs {};
class HitLeftArm: HitLeftArm {
armor = ARM_LEG_ARMOR_BETTER;
};
class HitRightArm: HitRightArm {
armor = ARM_LEG_ARMOR_BETTER;
};
class HitLeftLeg: HitLeftLeg {
armor = ARM_LEG_ARMOR_BETTER;
};
class HitRightLeg: HitRightLeg {
armor = ARM_LEG_ARMOR_BETTER;
};
};
};
class I_Soldier_04_F: I_Soldier_base_F {
class HitPoints: HitPoints {
class HitHead: HitHead {};
class HitBody: HitBody {};
class HitHands: HitHands {};
class HitLegs: HitLegs {};
class HitLeftArm: HitLeftArm {
armor = ARM_LEG_ARMOR_BETTER;
};
class HitRightArm: HitRightArm {
armor = ARM_LEG_ARMOR_BETTER;
};
class HitLeftLeg: HitLeftLeg {
armor = ARM_LEG_ARMOR_BETTER;
};
class HitRightLeg: HitRightLeg {
armor = ARM_LEG_ARMOR_BETTER;
};
};
};
class O_Soldier_base_F: SoldierEB {
class HitPoints: HitPoints {
class HitHead: HitHead {};
class HitBody: HitBody {};
class HitHands: HitHands {};
class HitLegs: HitLegs {};
class HitLeftArm: HitLeftArm {
armor = ARM_LEG_ARMOR_CSAT;
passThrough = 0.85;
};
class HitRightArm: HitRightArm {
armor = ARM_LEG_ARMOR_CSAT;
passThrough = 0.85;
};
class HitLeftLeg: HitLeftLeg {
armor = ARM_LEG_ARMOR_CSAT;
passThrough = 0.85;
};
class HitRightLeg: HitRightLeg {
armor = ARM_LEG_ARMOR_CSAT;
passThrough = 0.85;
};
};
};
class O_Soldier_02_F: O_Soldier_base_F {
class HitPoints: HitPoints {
class HitHead: HitHead {};
class HitBody: HitBody {};
class HitHands: HitHands {};
class HitLegs: HitLegs {};
class HitLeftArm: HitLeftArm {
armor = ARM_LEG_ARMOR_CSAT;
passThrough = 0.85;
};
class HitRightArm: HitRightArm {
armor = ARM_LEG_ARMOR_CSAT;
passThrough = 0.85;
};
class HitLeftLeg: HitLeftLeg {
armor = ARM_LEG_ARMOR_CSAT;
passThrough = 0.85;
};
class HitRightLeg: HitRightLeg {
armor = ARM_LEG_ARMOR_CSAT;
passThrough = 0.85;
};
};
};
};

View File

@ -0,0 +1,12 @@
#include "script_component.hpp"
private ["_unit"];
_unit = _this select 0;
if !(local _unit) exitWith {};
diag_log "running init";
_unit addEventHandler ["HandleDamage", {_this call FUNC(handleDamage)}];
[_unit] call FUNC(init);

View File

@ -6,5 +6,6 @@ PREP(handleDamage);
PREP(handleDamage_advanced);
PREP(handleDamage_basic);
PREP(handleDamage_medium);
PREP(init);
ADDON = true;

View File

@ -0,0 +1,10 @@
#include "script_component.hpp"
private ["_unit"];
_unit = _this select 0;
if !(local _unit) exitWith {};
diag_log "running respawn";
[_unit] call FUNC(init);

View File

@ -13,3 +13,4 @@ class CfgPatches {
};
#include "CfgEventHandlers.hpp"
#include "CfgVehicles.hpp"

View File

@ -17,27 +17,43 @@
#include "script_component.hpp"
private ["_damageReturn"];
private ["_unit", "_selection", "_damage", "_shooter", "_projectile", "_damageReturn", "_hitPoints"];
if !(local (_this select 0)) exitWith {nil};
_unit = _this select 0;
_selection = _this select 1;
_damage = _this select 2;
_shooter = _this select 3;
_projectile = _this select 4;
if (typeName (_this select 4) == "OBJECT") then {
_this set [4, typeOf (_this select 4)];
diag_log _this;
if !(local _unit) exitWith {nil};
if (typeName _projectile == "OBJECT") then {
_projectile = typeOf _projectile;
_this set [4, _projectile];
};
// If the damage is being weird, we just tell it to fuck off.
_hitSelections = ["head", "body", "hand_l", "hand_r", "leg_l", "leg_r"];
if !(_selection in (_hitSelections + [""])) exitWith {0};
_damageReturn = (_this select 2);
_damageReturn = _damage;
// @todo, remove once parameters are set up
if (isNil QGVAR(level)) then {
GVAR(level) = 0;
};
if (GVAR(level) >= 0) then {
_damageReturn = (_this + [_damageReturn]) call FUNC(handleDamage_basic);
};
if (GVAR(level) >= 1) then {
_damageReturn = (_this + [_damageReturn]) call FUNC(handleDamage_medium);
};
if (GVAR(level) >= 2) then {
_damageReturn = (_this + [_damageReturn]) call FUNC(handleDamage_advanced);
};
if (_damageReturn < 0.01) exitWith {0};
_damageReturn

View File

@ -0,0 +1,181 @@
/*
* Author: KoffeinFlummi
* Basic HandleDamage EH function.
*
* Arguments:
* 0: Unit That Was Hit <OBJECT>
* 1: Name Of Hit Selection <STRING>
* 2: Amount Of Damage <NUMBER>
* 3: Shooter <OBJECT>
* 4: Projectile <STRING>
* 5: Current damage to be returned <NUMBER>
*
* Return Value:
* Damage To Be Inflicted <NUMBER>
*
* Public: No
*/
#include "script_component.hpp"
#define LEGDAMAGETRESHOLD1 1
#define LEGDAMAGETRESHOLD2 1.7
#define ARMDAMAGETRESHOLD1 1
#define ARMDAMAGETRESHOLD2 1.7
#define UNCONSCIOUSNESSTRESHOLD 0.7
private ["_unit", "_selection", "_damage", "_shooter", "_projectile", "_damageReturn"];
_unit = _this select 0;
_selection = _this select 1;
_damage = _this select 2;
_shooter = _this select 3;
_projectile = _this select 4;
_damageReturn = _this select 5;
// This is a new hit, reset variables.
// Note: sometimes handleDamage spans over 2 or even 3 frames.
if (diag_frameno > (_unit getVariable [QGVAR(frameNo), -3]) + 2) then {
_unit setVariable [QGVAR(frameNo), diag_frameno];
_unit setVariable [QGVAR(isFalling), false];
_unit setVariable [QGVAR(projectiles), []];
_unit setVariable [QGVAR(hitPoints), []];
_unit setVariable [QGVAR(damages), []];
_unit setVariable [QGVAR(structDamage), 0];
};
_hitSelections = ["head", "body", "hand_l", "hand_r", "leg_l", "leg_r"];
_hitPoints = ["HitHead", "HitBody", "HitLeftArm", "HitRightArm", "HitLeftLeg", "HitRightLeg"];
_newDamage = _damageReturn - (damage _unit);
if (_selection in _hitSelections) then {
_newDamage = _damageReturn - (_unit getHitPointDamage (_hitPoints select (_hitSelections find _selection)));
};
_damageReturn = _damageReturn - _newDamage;
// Exclude falling damage to everything other than legs and reduce it overall.
if (((velocity _unit) select 2 < -5) and (vehicle _unit == _unit)) then {
_unit setVariable [QGVAR(isFalling), true];
};
if (_unit getVariable [QGVAR(isFalling), false] and !(_selectionName in ["", "leg_l", "leg_r"])) exitWith {
(_unit getHitPointDamage (_hitPoints select (_hitSelections find _selectionName))) max 0.01;
};
if (_unit getVariable [QGVAR(isFalling), false]) then {
_newDamage = _newDamage * 0.7;
};
// Make sure there's only one damaged selection per projectile per frame.
if (_selectionName != "" and !(_unit getVariable QGVAR(isFalling))) then {
_cache_projectiles = _unit getVariable QGVAR(projectiles);
_cache_hitpoints = _unit getVariable QGVAR(hitPoints);
_cache_damages = _unit getVariable QGVAR(damages);
if (_projectile in _cache_projectiles) then {
_index = _cache_projectiles find _projectile;
_otherDamage = (_cache_damages select _index);
if (_otherDamage > _newDamage) then {
_newDamage = 0;
} else {
_hitPoint = _cache_hitpoints select _index;
_restore = ((_unit getHitPointDamage _hitPoint) - _otherDamage) max 0;
_unit setHitPointDamage [_hitPoint, _restore];
// Make entry unfindable
_cache_projectiles set [_index, objNull];
_cache_projectiles pushBack _projectile;
_cache_hitpoints pushBack (_hitPoints select (_hitSelections find _selectionName));
_cache_damages pushBack _newDamage;
};
} else {
_cache_projectiles pushBack _projectile;
_cache_hitpoints pushBack (_hitPoints select (_hitSelections find _selectionName));
_cache_damages pushBack _newDamage;
};
_unit setVariable [QGVAR(projectiles), _cache_projectiles];
_unit setVariable [QGVAR(hitPoints), _cache_hitpoints];
_unit setVariable [QGVAR(damages), _cache_damages];
};
// Get rid of double structural damage (seriously arma, what the fuck?)
if (_selection == "") then {
_cache_structDamage = _unit getVariable QGVAR(structDamage);
if (_newDamage > _cache_structDamage) then {
_unit setVariable [QGVAR(structDamage), _newDamage];
_newDamage = _newDamage - _cache_structDamage;
} else {
_newDamage = 0;
};
};
// Assign orphan structural damage to torso;
// @todo
if (_selection == "") then {
_damageReturn = _damageReturn + (_unit getVariable QGVAR(structDamage));
} else {
_damageReturn = _damageReturn + _newDamage;
};
// Leg Damage
_legdamage = (_unit getHitPointDamage "HitLeftLeg") + (_unit getHitPointDamage "HitRightLeg");
if (_selectionName == "leg_l") then {
_legdamage = _damageReturn + (_unit getHitPointDamage "HitRightLeg");
};
if (_selectionName == "leg_r") then {
_legdamage = (_unit getHitPointDamage "HitLeftLeg") + _damageReturn;
};
if (_legdamage >= LEGDAMAGETRESHOLD1) then {
if (_unit getHitPointDamage "HitLegs" != 1) then {_unit setHitPointDamage ["HitLegs", 1]};
} else {
if (_unit getHitPointDamage "HitLegs" != 0) then {_unit setHitPointDamage ["HitLegs", 0]};
};
// @ŧodo: force prone for completely fucked up legs.
// Arm Damage
_armdamage = (_unit getHitPointDamage "HitLeftArm") + (_unit getHitPointDamage "HitRightArm");
if (_selectionName == "hand_l") then {
_armdamage = _damageReturn + (_unit getHitPointDamage "HitRightArm");
};
if (_selectionName == "hand_r") then {
_armdamage = (_unit getHitPointDamage "HitLeftArm") + _damageReturn;
};
if (_armdamage >= ARMDAMAGETRESHOLD1) then {
if (_unit getHitPointDamage "HitHands" != 1) then {_unit setHitPointDamage ["HitHands", 1]};
} else {
if (_unit getHitPointDamage "HitHands" != 0) then {_unit setHitPointDamage ["HitHands", 0]};
};
// @todo: Drop weapon for full damage.
// Set Pain
if (_selection == "") then {
_pain = _unit getVariable [QGVAR(pain), 0];
_pain = _pain + _newDamage * (1 - (_unit getVariable [QGVAR(morphine), 0]));
_unit setVariable [QGVAR(pain), _pain min 1, true];
};
// Unconsciousness
if (_selection == "" and
_damageReturn >= UNCONSCIOUSNESSTRESHOLD and
_damageReturn < 1 and
!(_unit getVariable [QGVAR(isUnconscious), False]
)) then {
// random chance to kill AI instead of knocking them out
if (_unit getVariable [QGVAR(allowUnconscious), ([_unit] call EFUNC(common,isPlayer)) or random 1 > 0.5]) then {
hint "unconscious"; // @todo
} else {
_damageReturn = 1;
};
};
_damageReturn

View File

@ -0,0 +1,22 @@
/*
* Author: KoffeinFlummi
* Initializes unit variables.
*
* Arguments:
* 0: The Unit <OBJECT>
*
* ReturnValue:
* nil
*
* Public: No
*/
#include "script_component.hpp"
private ["_unit"];
_unit = _this select 0;
_unit setVariable [QGVAR(pain), 0, true];
_unit setVariable [QGVAR(morphine), 0, true];
_unit setVariable [QGVAR(bloodVolume), 1, true];