Skip to content
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 Blood - Settings improvements and cleanup #7069

Merged
merged 4 commits into from
Jun 27, 2019
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion addons/medical_blood/CfgEventHandlers.hpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@

class Extended_PreStart_EventHandlers {
class ADDON {
init = QUOTE(call COMPILE_FILE(XEH_preStart));
Expand Down
4 changes: 2 additions & 2 deletions addons/medical_blood/README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
ace_medical_blood
===============
=================

Adds blood visual effect on the ground near a bleeding player.
Creates blood drops on the ground near bleeding units.

## Maintainers

Expand Down
6 changes: 3 additions & 3 deletions addons/medical_blood/XEH_PREP.hpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@

PREP(cleanupLoop);
PREP(createBlood);
PREP(handleWoundReceived);
PREP(init);
PREP(isBleeding);
PREP(onBleeding);
PREP(createBlood);
PREP(serverCleanupBlood);
PREP(spurt);
29 changes: 7 additions & 22 deletions addons/medical_blood/XEH_postInit.sqf
Original file line number Diff line number Diff line change
Expand Up @@ -10,33 +10,18 @@ if (isServer) then {

[QGVAR(bloodDropCreated), {
params ["_bloodDrop"];
// Add to created queue with format [expireTime, object]
private _index = GVAR(bloodDrops) pushBack [(CBA_missionTime + BLOOD_OBJECT_LIFETIME), _bloodDrop];

if (count GVAR(bloodDrops) >= MAX_BLOOD_OBJECTS) then {
// Add to created queue with format: [expire time, blood object]
private _index = GVAR(bloodDrops) pushBack [CBA_missionTime + GVAR(bloodLifetime), _bloodDrop];

if (count GVAR(bloodDrops) >= GVAR(maxBloodObjects)) then {
(GVAR(bloodDrops) deleteAt 0) params ["", "_deletedBloodDrop"];
deleteVehicle _deletedBloodDrop;
};

if (_index == 1) then { // Start the waitAndExecute loop
[FUNC(serverCleanupBlood), [], BLOOD_OBJECT_LIFETIME] call CBA_fnc_waitAndExecute;
// Start the cleanup loop
if (_index == 0) then {
[FUNC(cleanupLoop), [], GVAR(bloodLifetime)] call CBA_fnc_waitAndExecute;
};
}] call CBA_fnc_addEventHandler;
};

["ace_settingsInitialized", {
TRACE_1("settingsInitialized", GVAR(enabledFor));
if (GVAR(enabledFor) == 0) exitWith {}; // 0: disabled
if ((GVAR(enabledFor) == 1) && {!hasInterface}) exitWith {}; // 1: enabledFor_OnlyPlayers

private _listcode = if (GVAR(enabledFor) == 1) then {
{if (alive ACE_player) then {[ACE_player]} else {[]}} // ace_player is only possible local player
} else {
EFUNC(common,getLocalUnits) // filter all local units
};

private _stateMachine = [_listcode, true] call CBA_statemachine_fnc_create;
[_stateMachine, LINKFUNC(onBleeding), {}, {}, "Bleeding"] call CBA_statemachine_fnc_addState;

[QEGVAR(medical,woundReceived), FUNC(handleWoundReceived)] call CBA_fnc_addEventHandler;
}] call CBA_fnc_addEventHandler;
2 changes: 1 addition & 1 deletion addons/medical_blood/config.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,5 @@ class CfgPatches {
};
};

#include "ACE_Settings.hpp"
#include "CfgEventHandlers.hpp"
#include "ACE_Settings.hpp"
Original file line number Diff line number Diff line change
@@ -1,23 +1,26 @@
#include "script_component.hpp"
/*
* Author: PabstMirror
* Loop that cleans up blood
* Handles cleaning up blood objects that have reached the end of their lifetime.
*
* Arguments:
* None
*
* ReturnValue:
* Return Value:
* None
*
* Example:
* [] call ace_medical_blood_fnc_cleanupLoop
*
* Public: No
*/

(GVAR(bloodDrops) deleteAt 0) params ["", "_deletedBloodDrop"];
deleteVehicle _deletedBloodDrop;

// If we cleaned out the array, exit loop
// Exit the loop if we have cleaned out the array
if (GVAR(bloodDrops) isEqualTo []) exitWith {};

// Wait until the next blood drop in the queue will expire
(GVAR(bloodDrops) select 0) params ["_expireTime"];
[FUNC(serverCleanupBlood), [], (_expireTime - CBA_missionTime)] call CBA_fnc_waitAndExecute;
[FUNC(cleanupLoop), [], _expireTime - CBA_missionTime] call CBA_fnc_waitAndExecute;
20 changes: 10 additions & 10 deletions addons/medical_blood/functions/fnc_createBlood.sqf
Original file line number Diff line number Diff line change
@@ -1,31 +1,31 @@
#include "script_component.hpp"
/*
* Author: Glowbal
* Spawn a blood drop.
* Creates a blood object and handles its cleanup.
* Available blood drop classes are blooddrop_1 through blooddrop_4.
*
* Arguments:
* 0: classname of blood drop <OBJECT>
* 0: Blood Drop Type <STRING>
* 1: Position <ARRAY>
*
* Return Value:
* Created blood drop <OBJECT>
* Blood Drop <OBJECT>
*
* Example:
* ["blooddrop_2", getPos player] call ace_medical_blood_fnc_createBlood
*
* Public: No
*/

params ["_type", "_pos"];
TRACE_2("creating blood",_type,_pos);
params ["_type", "_position"];
TRACE_2("Creating blood",_type,_position);

private _model = GVAR(models) getVariable _type;

private _object = createSimpleObject [_model, [0,0,0]];
_object setDir random 360;
_object setPos _pos;
private _bloodDrop = createSimpleObject [_model, [0, 0, 0]];
_bloodDrop setDir random 360;
_bloodDrop setPos _position;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need a seperate setPos? It creates a additonal network message as blooddrops are global.
Speaking of which, couldn't we make blooddrops local only with the new createSimpleObject local syntax?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we want them to be global, but agree about whether setPos is necessary

Copy link
Contributor

@PabstMirror PabstMirror Jun 25, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Surprising results (unless I made a mistake)
edit: we knew that createVehicle at [0,0,0] is faster because it normally scans for a "free" position, but I didn't think it did that for createSimpleObject (objects are in a row clipping though things)

createVehicle @ [0,0,0] - 492 ms

private _start = diag_tickTime; 
for "_i" from 0 to 30000 step 3 do { 
    private _pos = (getPos player) vectorAdd [0,_i,0]; 
    private _z = "Land_LampStreet_small_F" createVehicle [0,0,0]; 
    _z setPos _pos; 
}; 
private _end = diag_tickTime; 
x3 = _end - _start;

createVehicle @ pos - 4798 ms (and non-precise placement)

private _start = diag_tickTime; 
for "_i" from 0 to 30000 step 3 do { 
    private _pos = (getPos player) vectorAdd [0,_i,0]; 
    private _z = "Land_LampStreet_small_F" createVehicle _pos; 
}; 
private _end = diag_tickTime; 
x3 = _end - _start;

createSimpleObject @ [0,0,0] - 263 ms

private _start = diag_tickTime; 
for "_i" from 0 to 30000 step 3 do { 
    private _pos = AGLtoASL ((getPos player) vectorAdd [0,_i,0]); 
    private _z = createSimpleObject ["Land_LampStreet_small_F", [0,0,0]]; 
    _z setPosASL _pos;
}; 
private _end = diag_tickTime; 
x3 = _end - _start;

createSimpleObject @ pos - 2641 ms

private _start = diag_tickTime; 
for "_i" from 0 to 30000 step 3 do { 
    private _pos = AGLtoASL ((getPos player) vectorAdd [0,_i,0]); 
    private _z = createSimpleObject ["Land_LampStreet_small_F", _pos]; 
}; 
private _end = diag_tickTime; 
x3 = _end - _start;

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

network traffic vs sqf speed
(unless the game can serialize the create and setPos together?)
we can continue to think about this after merge


[QGVAR(bloodDropCreated), [_object]] call CBA_fnc_serverEvent;
[QGVAR(bloodDropCreated), _bloodDrop] call CBA_fnc_serverEvent;

_object
_bloodDrop
28 changes: 14 additions & 14 deletions addons/medical_blood/functions/fnc_handleWoundReceived.sqf
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
#include "script_component.hpp"
/*
* Author: Glowbal, commy2
* Handle wounds received event.
* Handles the wounds received event by triggering any needed blood creation.
*
* Arguments:
* 0: unit <OBJECT>
* 1: bodyPart <String>
* 2: damage <NUMBER>
* 3: shooter <OBJECT>
* 0: Unit <OBJECT>
* 1: Body Part (not used) <STRING>
* 2: Damage <NUMBER>
* 3: Shooter <OBJECT>
*
* Return Value:
* None
Expand All @@ -20,16 +20,16 @@

params ["_unit", "", "_damage", "_shooter"];

if (GVAR(enabledFor) == 1 && {!isPlayer _unit && {_unit != ACE_player}}) exitWith {};
if (vehicle _unit != _unit && {!((vehicle _unit) isKindOf "StaticWeapon")}) exitWith {}; // Don't bleed on ground if mounted
// Don't bleed when players only and a non-player unit is wounded
if (GVAR(enabledFor) == BLOOD_ONLY_PLAYERS && {!isPlayer _unit && {_unit != ACE_player}}) exitWith {};

_damage = _damage min 1;
// Don't bleed on the ground if in a vehicle
if (vehicle _unit != _unit && {!(vehicle _unit isKindOf "StaticWeapon")}) exitWith {};

if (isNull _shooter) exitWith { // won't be able to calculate the direction properly, so instead we pick something at random
[QGVAR(spurt), [_unit, random 360, _damage]] call CBA_fnc_serverEvent;
private _bulletDir = if (isNull _shooter) then {
random 360 // Cannot calculate the direction properly, pick a random direction
} else {
_shooter getDir _unit // Calculate the bullet direction
};

// Calculate bulletDirection
private _bulletDir = _shooter getDir _unit;

[QGVAR(spurt), [_unit, _bulletDir, _damage]] call CBA_fnc_serverEvent;
[QGVAR(spurt), [_unit, _bulletDir, _damage min 1]] call CBA_fnc_serverEvent;
65 changes: 65 additions & 0 deletions addons/medical_blood/functions/fnc_init.sqf
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
#include "script_component.hpp"
/*
* Author: mharis001
* Initializes the medical blood system based on the given mode.
* Should only be called from the CBA setting changed script.
*
* Arguments:
* 0: Mode <NUMBER>
*
* Return Value:
* None
*
* Example:
* [2] call ace_medical_blood_fnc_init
*
* Public: No
*/

params ["_mode"];

// Exit if setting is refreshed to the same value
if (!isNil QGVAR(currentSetup) && {_mode == GVAR(currentSetup)}) exitWith {
TRACE_2("Setting refreshed to current setup",GVAR(currentSetup),_mode);
};

// Track this new configuration that will be set up
GVAR(currentSetup) = _mode;

// Delete current state machine if it exists
if (!isNil QGVAR(stateMachine)) then {
GVAR(stateMachine) call CBA_statemachine_fnc_delete;
GVAR(stateMachine) = nil;
};

// Remove wound received if it was previously added
if (!isNil QGVAR(woundReceivedEH)) then {
[QEGVAR(medical,woundReceived), GVAR(woundReceivedEH)] call CBA_fnc_removeEventHandler;
GVAR(woundReceivedEH) = nil;
};

// Don't need to set up anything if blood is disabled or players only on a non-player machine
if (_mode == BLOOD_DISABLED || {_mode == BLOOD_ONLY_PLAYERS && {!hasInterface}}) exitWith {
TRACE_1("Mode does not require any setup",_mode);
};

private _listCode = if (_mode == BLOOD_ONLY_PLAYERS) then {
// ACE_player is the only possible local player
{
if (alive ACE_player) then {
[ACE_player]
} else {
[]
};
}
} else {
// Filter all local units
EFUNC(common,getLocalUnits)
};

GVAR(stateMachine) = [_listCode, true] call CBA_statemachine_fnc_create;
[GVAR(stateMachine), LINKFUNC(onBleeding), {}, {}, "Bleeding"] call CBA_statemachine_fnc_addState;

GVAR(woundReceivedEH) = [QEGVAR(medical,woundReceived), FUNC(handleWoundReceived)] call CBA_fnc_addEventHandler;

TRACE_3("Set up state machine and wounds event",_mode,GVAR(stateMachine),GVAR(woundReceivedEH));
6 changes: 3 additions & 3 deletions addons/medical_blood/functions/fnc_isBleeding.sqf
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
#include "script_component.hpp"
/*
* Author: Glowbal
* Check if is bleeding
* Checks if the given unit is bleeding. Handles both ACE Medical and Vanilla.
*
* Arguments:
* 0: unit <TYPE>
* 0: Unit <OBJECT>
*
* Return Value:
* is Bleeding <BOOL>
* Is Bleeding <BOOL>
*
* Example:
* [player] call ace_medical_blood_fnc_isBleeding
Expand Down
23 changes: 12 additions & 11 deletions addons/medical_blood/functions/fnc_onBleeding.sqf
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
#include "script_component.hpp"
/*
* Author: Glowbal
* handle bleeding state (state machine)
* Handles periodically creating blood for a bleeding unit.
* Called from the medical_blood state machine.
*
* Arguments:
* 0: unit <TYPE>
* 0: Unit <OBJECT>
*
* Return Value:
* is Bleeding <BOOL>
* None
*
* Example:
* [player] call ace_medical_blood_fnc_onBleeding
Expand All @@ -17,20 +18,20 @@

params ["_unit"];

if (!([_unit] call FUNC(isBleeding))) exitWith {};
if (((vehicle _unit) != _unit) && {!((vehicle _unit) isKindOf "StaticWeapon")}) exitWith {}; // Don't bleed on ground if mounted
// Nothing to do if unit is not bleeding
if !(_unit call FUNC(isBleeding)) exitWith {};

// Don't bleed on the ground if in a vehicle
if (vehicle _unit != _unit && {!(vehicle _unit isKindOf "StaticWeapon")}) exitWith {};

if (CBA_missionTime > (_unit getVariable [QGVAR(nextTime), -10])) then {
private _bloodLoss = (if (GVAR(useAceMedical)) then {GET_BLOOD_LOSS(_unit) * 2.5} else {getDammage _unit * 2}) min 6;
TRACE_2("",_unit,_bloodLoss);
_unit setVariable [QGVAR(nextTime), CBA_missionTime + 8 + random 2 - _bloodLoss];

TRACE_2("Creating blood drop for bleeding unit",_unit,_bloodLoss);

private _position = getPosASL _unit;
_position = _position vectorAdd [
random 0.4 - 0.2,
random 0.4 - 0.2,
0
];
_position = _position vectorAdd [random 0.4 - 0.2, random 0.4 - 0.2, 0];
_position set [2, 0];

private _bloodDrop = ["blooddrop_1", "blooddrop_2", "blooddrop_3", "blooddrop_4"] select floor (_bloodLoss min 3);
Expand Down
22 changes: 11 additions & 11 deletions addons/medical_blood/functions/fnc_spurt.sqf
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
#include "script_component.hpp"
/*
* Author: Sickboy
* Spurt blood on the ground
* Spurts blood on the ground based on the direction and damage.
*
* Arguments:
* 0: unit <OBJECT>
* 1: direction <NUMBER>
* 2: damage <NUMBER>
* 0: Unit <OBJECT>
* 1: Direction <NUMBER>
* 2: Damage <NUMBER>
*
* Return Value:
* None
*
* Example:
* [UNIT, random 360, 1] call ace_medical_blood_fnc_spurt
* [player, random 360, 1] call ace_medical_blood_fnc_spurt
*
* Public: No
*/
Expand All @@ -21,20 +21,20 @@
#define DISTANCE_BETWEEN_DROPS 0.20
#define OFFSET 0.25

params ["_unit", "_dir", "_damage"];
params ["_unit", "_direction", "_damage"];

private _distanceBetweenDrops = DISTANCE_BETWEEN_DROPS * _damage;
private _offset = OFFSET + _distanceBetweenDrops;
private _pos = _unit getPos [_offset, _dir];
private _position = _unit getPos [_offset, _direction];

["blooddrop_2", _pos, _dir] call FUNC(createBlood);
["blooddrop_2", _position, _direction] call FUNC(createBlood);

private _dropAmount = ceil (MAXIMUM_DROPS * _damage);
TRACE_2("spurt blood",_dropAmount,_damage);
TRACE_2("Spurting blood",_dropAmount,_damage);

if (_dropAmount > 1) then {
for "_i" from 2 to _dropAmount do {
_pos = _pos getPos [_distanceBetweenDrops, _dir];
["blooddrop_1", _pos, _dir] call FUNC(createBlood);
_position = _position getPos [_distanceBetweenDrops, _direction];
["blooddrop_1", _position, _direction] call FUNC(createBlood);
};
};
Loading