Jump to content
🛡️FORUMS ARE IN READ-ONLY MODE Read more... ×
Rosso777

Player Damage Handler editing

Recommended Posts

Using Exile on a private dedicated server. Is it possible to change the current player damage handler with the one from AGM? I know there are AGM functions in there, so would I need to change all that to BIS functions (i.e. Changing AGM_ to BIS_)? Or am I just WAY over my head here? Are the functions written specifically for the mod itself? Or are they all a reference to BIS functions anyway?

 

Here is the AGM file:

Spoiler

/*
 * Author: KoffeinFlummi
 *
 * Called when some dude gets shot. Or stabbed. Or blown up. Or pushed off a cliff. Or hit by a car. Or burnt. Or poisoned. Or gassed. Or cut. You get the idea.
 *
 * Arguments:
 * 0: Unit that got hit (Object)
 * 1: Name of the selection that was hit (String); "" for structural damage
 * 2: Amount of damage inflicted (Number)
 * 3: Shooter (Object); Null for explosion damage, falling, fire etc.
 * 4: Projectile (Object or String)
 *
 * Return value:
 * Damage value to be inflicted (optional)
 */

#define UNCONSCIOUSNESSTRESHOLD 0.6

#define PAINKILLERTRESHOLD 0.1
#define PAINLOSS 0.0001

#define BLOODTRESHOLD1 0.35
#define BLOODTRESHOLD2 0
#define BLOODLOSSRATE 0.04

#define ARMOURCOEF 2

private ["_unit", "_selectionName", "_damage", "_source", "_source", "_projectile", "_hitSelections", "_hitPoints", "_newDamage", "_found", "_cache_projectiles", "_cache_hitpoints", "_cache_damages"];

_unit          = _this select 0;
_selectionName = _this select 1;
_damage        = _this select 2;
_source        = _this select 3;
_projectile    = _this select 4;

if (!local _unit) exitWith {nil}; //if not local, then return value shouldn't have any effect

if (typeName _projectile == "OBJECT") then {
  _projectile = typeOf _projectile;
};

// Prevent unnecessary processing
if (damage _unit >= 1) exitWith {};

// Only broadcast the isDiagnosed status if it changed
if (_unit getVariable ["AGM_isDiagnosed", False]) then {
  _unit setVariable ["AGM_isDiagnosed", False, True];
};

// @todo: figure out if this still applies.

// For some reason, everything is backwards in MP,
// so we need to untangle some things.
// -- seems fixed as of v1.36
/*if (isMultiplayer) then {
  _selectionName = switch (_selectionName) do {
    case "hand_r" : {"leg_l"};
    case "leg_r"  : {"hand_l"};
    case "legs"   : {"hand_r"};
    default         {_selectionName};
  };
};*/

// This seems to only show up in MP too, but since it doesn't
// collide with anything, I'll check it in SP as well.
if (_selectionName == "r_femur_hit") then {
  _selectionName = "leg_r";
};

_hitSelections = ["head", "body", "hand_l", "hand_r", "leg_l", "leg_r"];
_hitPoints = ["HitHead", "HitBody", "HitLeftArm", "HitRightArm", "HitLeftLeg", "HitRightLeg"];

// If the damage is being weird, we just tell it to fuck off.
// (Returning 0 seems to cause issues though, so return 0.01)
if !(_selectionName in (_hitSelections + [""])) exitWith {0.01};

// Calculate change in damage.
_newDamage = _damage - (damage _unit);
if (_selectionName in _hitSelections) then {
  _newDamage = _damage - (_unit getHitPointDamage (_hitPoints select (_hitSelections find _selectionName)));
};

// Finished with the current frame, reset variables
// Note: sometimes handleDamage spans over 2 or even 3 frames.
if (diag_frameno > (_unit getVariable ["AGM_Medical_FrameNo", -3]) + 2) then {
  _unit setVariable ["AGM_Medical_FrameNo", diag_frameno];
  _unit setVariable ["AGM_Medical_isFalling", False];
  _unit setVariable ["AGM_Medical_Projectiles", []];
  _unit setVariable ["AGM_Medical_HitPoints", []];
  _unit setVariable ["AGM_Medical_Damages", []];
  _unit setVariable ["AGM_Medical_PreventDeath", False];
  if (([_unit] call AGM_Core_fnc_isPlayer) or _unit getVariable ["AGM_allowUnconscious", False]) then {
    if (!(_unit getVariable ["AGM_isUnconscious", False]) and
        {_unit getVariable ["AGM_Medical_PreventInstaDeath", AGM_Medical_PreventInstaDeath]}) then {
      _unit setVariable ["AGM_Medical_PreventDeath", True];
    };
    if ((_unit getVariable ["AGM_isUnconscious", False]) and
        {_unit getVariable ["AGM_Medical_PreventDeathWhileUnconscious", AGM_Medical_PreventDeathWhileUnconscious]}) then {
      _unit setVariable ["AGM_Medical_PreventDeath", True];
    };
  };
};

_damage = _damage - _newDamage;

if !(_unit getVariable ["AGM_allowDamage", True]) exitWith {_damage max 0.01};

_newDamage = _newDamage * (_unit getVariable ["AGM_Medical_CoefDamage", AGM_Medical_CoefDamage]);

// Exclude falling damage to everything other than legs; reduce structural damage.
if (((velocity _unit) select 2 < -5) and (vehicle _unit == _unit)) then {
  _unit setVariable ["AGM_Medical_isFalling", True];
};
if (_unit getVariable "AGM_Medical_isFalling" and !(_selectionName in ["", "leg_l", "leg_r"])) exitWith {
  (_unit getHitPointDamage (_hitPoints select (_hitSelections find _selectionName))) max 0.01;
};
if (_unit getVariable "AGM_Medical_isFalling") then {
  _newDamage = _newDamage * 0.7;
};

// Increase damage for kinetic penetrators for people inside vehicles
// to simulate hot spikey things flying around (generally unpleasant).
// (only if AGM_Armour is used)
if (isClass (configFile >> "CfgPatches" >> "AGM_Armour") and _projectile != "" and vehicle _unit != _unit) then {
  _hit = getNumber (configFile >> "CfgAmmo" >> _projectile >> "hit");
  if (_hit >= 100) then {
    _hit = linearConversion [100, 1000, _hit, 0, ARMOURCOEF, True];
    _newDamage = _newDamage * (1 + _hit);
  };
};

// Make sure there's only one damaged selection per projectile per frame.
_cache_projectiles = _unit getVariable "AGM_Medical_Projectiles";
_cache_hitpoints = _unit getVariable "AGM_Medical_HitPoints";
_cache_damages = _unit getVariable "AGM_Medical_Damages";
if (_selectionName != "" and !(_unit getVariable "AGM_Medical_isFalling")) then {
  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 ["AGM_Medical_Projectiles", _cache_projectiles];
_unit setVariable ["AGM_Medical_HitPoints", _cache_hitpoints];
_unit setVariable ["AGM_Medical_Damages", _cache_damages];

// we want to move damage to another selection; have to do it ourselves.
// this is only the case for limbs, so this will not impact the killed EH.
if (_selectionName != (_this select 1)) then {
  _unit setHitPointDamage [_hitPoints select (_hitSelections find _selectionName), _damage + _newDamage];
  _newDamage = 0;
};

_damage = _damage + _newDamage;

// Assign orphan structural damage to torso;
// using spawn with custom damage handling here, but since I just
// move damage, this shouldn't be any issue for the Killed EH
_unit spawn {
  sleep 0.001;

  _damagesum = (_this getHitPointDamage "HitHead")
    + (_this getHitPointDamage "HitBody")
    + (_this getHitPointDamage "HitLeftArm")
    + (_this getHitPointDamage "HitRightArm")
    + (_this getHitPointDamage "HitLeftLeg")
    + (_this getHitPointDamage "HitRightLeg");
  if (_damagesum <= 0.06 and (damage _this) > 0.01) then {
    _damage = damage _this;
    _this setDamage 0;
    _this setHitPointDamage ["HitBody", (_damage min 0.89)]; // just to be sure.
  };
};

// Leg & Arm Damage
_legdamage = (_unit getHitPointDamage "HitLeftLeg") + (_unit getHitPointDamage "HitRightLeg");
if (_selectionName == "leg_l") then {
  _legdamage = _damage + (_unit getHitPointDamage "HitRightLeg");
};
if (_selectionName == "leg_r") then {
  _legdamage = (_unit getHitPointDamage "HitLeftLeg") + _damage;
};

_armdamage = (_unit getHitPointDamage "HitLeftArm") + (_unit getHitPointDamage "HitRightArm");
if (_selectionName == "hand_l") then {
  _armdamage = _damage + (_unit getHitPointDamage "HitRightArm");
};
if (_selectionName == "hand_r") then {
  _armdamage = (_unit getHitPointDamage "HitLeftArm") + _damage;
};

[_unit, _legdamage, _armdamage] call AGM_Medical_fnc_checkDamage;

// Unconsciousness
if (_selectionName == "" and
    _damage >= UNCONSCIOUSNESSTRESHOLD and
    _damage < 1 and
    !(_unit getVariable ["AGM_isUnconscious", False]
  )) then {
  // random chance to kill AI instead of knocking them out, otherwise
  // there'd be shittons of unconscious people after every firefight,
  // causing executions. And nobody likes executions.
  if (_unit getVariable ["AGM_allowUnconscious", ([_unit] call AGM_Core_fnc_isPlayer) or random 1 > 0.5]) then {
    [_unit] call AGM_Medical_fnc_knockOut;
  } else {
    _damage = 1;
  };
};

// Bleeding
if (_selectionName == "" and damage _unit == 0) then {
  _unit spawn {
    while {damage _this > 0 and damage _this < 1} do {
      if !([_this] call AGM_Medical_fnc_isInMedicalVehicle) then {
        _blood = _this getVariable ["AGM_Blood", 1];
        _blood = _blood - BLOODLOSSRATE * (_this getVariable ["AGM_Medical_CoefBleeding", AGM_Medical_CoefBleeding]) * (damage _this);
        _this setVariable ["AGM_Blood", _blood max 0, true];
        if (_blood <= BLOODTRESHOLD1 and !(_this getVariable ["AGM_isUnconscious", False])) then {
          [_this] call AGM_Medical_fnc_knockOut;
        };
        if (_blood <= BLOODTRESHOLD2 and {!AGM_Medical_PreventDeathWhileUnconscious}) then {
          //_this setDamage 1;
          _this setHitPointDamage ["HitHead", 1]; // fx: don't get the uniform bloody if there are no wounds
        };
      };
      sleep 10;
    };
  };
};

// Pain Reduction
if (_unit getVariable ["AGM_Pain", 0] == 0) then {
  _unit spawn {
    while {_this getVariable ["AGM_Pain", 0] > 0} do {
      sleep 1;
      _pain = ((_this getVariable ["AGM_Pain", 0]) - 0.001) max 0;
      _this setVariable ["AGM_Pain", _pain, True];
    };
  };
};
// Set Pain
_potentialPain = _damage * (_unit getVariable ["AGM_Painkiller", 1]);
if ((_selectionName == "") and (_potentialPain > _unit getVariable ["AGM_Pain", 0])) then {
  _unit setVariable ["AGM_Pain", (_damage * (_unit getVariable ["AGM_Painkiller", 1])) min 1, True];
};

// again, using spawn, but there shouldn't be any death, so the killed EH should be fine.
if ((_unit getVariable "AGM_Medical_PreventDeath") and {vehicle _unit != _unit} and {damage (vehicle _unit) >= 1}) then {
  _unit setPosATL [
    (getPos _unit select 0) + (random 3) - 1.5,
    (getPos _unit select 1) + (random 3) - 1.5,
    0
  ];
  if !(_unit getVariable ["AGM_isUnconscious", False]) then {
    [_unit] call AGM_Medical_fnc_knockOut;
  };
  _unit setVariable ["AGM_allowDamage", False];
  _unit spawn {
    sleep 1;
    _this setVariable ["AGM_allowDamage", True];
  };
};

if ((_unit getVariable "AGM_Medical_PreventDeath")) then {
  if ((_damage > 0.89) && (_selectionName in ["", "head", "body"])) then { //only change damage on hits that would be lethal
    _damage = 0.89;
    [_unit, "preventedDeath", [_unit]] call AGM_Core_fnc_callCustomEventHandlersGlobal;
    if (!(_unit getVariable ["AGM_isUnconscious", False])) then {
      [_unit] call AGM_Medical_fnc_knockOut; //knockOut when taking damage that should be lethal
    };
  };
};

_damage
 

 

Share this post


Link to post
Share on other sites

×