Jump to content
FenixDK

[Request] GRAD Persistence + ace medical

Recommended Posts

HI everyone,

 

I wanted to start this thread, because I am sure I am not the only one who faces this problem and I think it will be beneficial for many out there, as not everyone is using a proper database to save the mission progress, so I think it would be great if someone who knows how to do it will contribute.

It has to be noted that even though I have close to 0 experience in programming, I am fully aware of how much effort this request may require, but I believe in altruism 😊.

 

Setup:

GRAD Persistence and advanced ace medical system.

Problem:

GRAD does not save ace medical state of the player upon disconnect/return to lobby, which means if the player is injured or unconscious, he can return to lobby and then get back in the mission fully recovered.

Possible solutions (from easiest to hardest):

1.       A script that will disable “abort” button if the player is unconscious. Something like this (I didn’t test it yet, but I will do so today).

This is a workaround which does not really solve the problem as alt+F4 is still available, but it will reduce the number of returns to lobby. I guess that I can play around on my own with the script referred above and adjust it to recognise ace unconscious, but if there is a more elegant solution, it would be great.

2.       A script/addition to GRAD that will save ace unconscious parameter before player leaves to lobby/quits and upon player’s return will either set the player unconscious or kill (I think the kill is better and more fair as it will exclude healing the wounds upon return).

3.       An addition to GRAD that will save ace medical wounds and unconscious state before player leaves to lobby/quits and upon return will load the saved state.

I know that this is will require a lot of time to implement, as GRAD developer has it in his backlog since 2018.

4.       Feel free to add your option in this thread.

Result:

Whichever solution we will figure out here, it will be for everyone to use. If it will be possible to implement it in GRAD Persistence, I will reach out to the developer with this solution, so others can enjoy it in the GRAD package as well.

Share this post


Link to post
Share on other sites

So I have played around with the option number 1 and managed to make it work. Please see here:

 

Share this post


Link to post
Share on other sites

I know I'm late but my prayers have been answered. I want to post this here to help anybody else in the future.

There is a "pull request" on grad-persistence from NFZ-JDWANG here: https://github.com/gruppe-adler/grad-persistence/pulls

It changes 2 files: fn_savePlayer.sqf and fn_loadPlayer.sqf

Both files can be found on JDWangs fork of grad-persistence.

fn_savePlayer.sqf: https://github.com/NZF-JDWang/grad-persistence/blob/master/functions/save/fn_savePlayer.sqf

Spoiler

#include "script_component.hpp"

params [
    "_unit",
    ["_save",false],
    ["_savePlayerInventory",([missionConfigFile >> "CfgGradPersistence", "savePlayerInventory", 1] call BIS_fnc_returnConfigEntry) == 1],
    ["_savePlayerDamage",([missionConfigFile >> "CfgGradPersistence", "savePlayerDamage", 0] call BIS_fnc_returnConfigEntry) == 1],
    ["_savePlayerPosition",([missionConfigFile >> "CfgGradPersistence", "savePlayerPosition", 0] call BIS_fnc_returnConfigEntry) == 1],
    ["_savePlayerMoney",([missionConfigFile >> "CfgGradPersistence", "savePlayerMoney", 0] call BIS_fnc_returnConfigEntry) == 1],
    "_uid",
    "_allPlayerVariableClasses"
];


if (!isServer) exitWith {};
if ([_unit] call FUNC(isBlacklisted)) exitWith {};

if (isNil "_allPlayerVariableClasses") then {
    private _allVariableClasses = "true" configClasses (missionConfigFile >> "CfgGradPersistence" >> "customVariables");
    _allPlayerVariableClasses = _allVariableClasses select {
        ([_x,"varNamespace",""] call BIS_fnc_returnConfigEntry) == "player"
    };
};

private _missionTag = [] call FUNC(getMissionTag);
private _playersTag = _missionTag + "_players";
private _playersDataHash = [_playersTag,true,false] call FUNC(getSaveData);

if (isNil "_uid") then {
    _uid = getPlayerUID _unit;
};
if (_uid == "") exitWith {};

private _unitDataHash = [[],false] call CBA_fnc_hashCreate;

if (_savePlayerInventory) then {

    private _loadout = getUnitLoadout _unit;
    if ((count _loadout) == 0) exitWith {ERROR_1("Unit %1: no loadout array.",_unit)};

    if (GVAR(acreLoaded)) then {
        // on release of ACRE2 v2.7.3 replace with:
        // _loadout = [_loadout] call acre_api_fnc_filterUnitLoadout;

        if ((_loadout select 9) select 2 == "ItemRadioAcreFlagged") then {
            (_loadout select 9) set [2,""];
        };

        private _fnc_replaceRadioAcre = {
            params ["_item"];
            if (!(_item isEqualType []) && {[_item] call acre_api_fnc_isRadio}) then {
                _this set [0, [_item] call acre_api_fnc_getBaseRadio];
            };
        };
        if !((_loadout select 3) isEqualTo []) then {
            {_x call _fnc_replaceRadioAcre} forEach ((_loadout select 3) select 1);
        };
        if !((_loadout select 4) isEqualTo []) then {
            {_x call _fnc_replaceRadioAcre} forEach ((_loadout select 4) select 1);
        };
        if !((_loadout select 5) isEqualTo []) then {
            {_x call _fnc_replaceRadioAcre} forEach ((_loadout select 5) select 1);
        };
    };

    if (GVAR(tfarLoaded)) then {
        private _assignedRadio = (_loadout select 9) select 2;
        if (_assignedRadio call TFAR_fnc_isRadio) then {
            (_loadout select 9) set [2,[configFile >> "CfgWeapons" >> _assignedRadio >> "tf_parent", "text", _assignedRadio] call CBA_fnc_getConfigEntry];
        };

        private _fnc_replaceRadioTfar = {
            params ["_item"];
            if (!(_item isEqualType []) && {_item call TFAR_fnc_isRadio}) then {
                _this set [0,[configFile >> "CfgWeapons" >> _item >> "tf_parent", "text", _item] call CBA_fnc_getConfigEntry];
            };
        };
        if !((_loadout select 3) isEqualTo []) then {
            {_x call _fnc_replaceRadioTfar} forEach ((_loadout select 3) select 1);
        };
        if !((_loadout select 4) isEqualTo []) then {
            {_x call _fnc_replaceRadioTfar} forEach ((_loadout select 4) select 1);
        };
        if !((_loadout select 5) isEqualTo []) then {
            {_x call _fnc_replaceRadioTfar} forEach ((_loadout select 5) select 1);
        };
    };

    [_unitDataHash, "inventory", _loadout] call CBA_fnc_hashSet;
};

if (_savePlayerDamage) then {
    if (isClass(configfile >> "CfgPatches" >> "ace_medical")) then {

        private _damage = [_unit] call ace_medical_fnc_serializeState;
        [_unitDataHash,"damage",_damage] call CBA_fnc_hashSet;
        diag_log "ACE DETECTED - Saving ACE wounds";
        diag_log format ["%1", _damage];

    } else 
            {
                private _allHitPointsDamage = getAllHitPointsDamage _unit;
                private _damage = if (count _allHitPointsDamage > 2) then {
                    [_allHitPointsDamage select 0,_allHitPointsDamage select 2]
                } else {
                    [[],[]]
                };
                [_unitDataHash,"damage",_damage] call CBA_fnc_hashSet;
            };
    
};

if (_savePlayerPosition) then {
    [_unitDataHash,"posASL",getPosASL _unit] call CBA_fnc_hashSet;
    [_unitDataHash,"dir",getDir _unit] call CBA_fnc_hashSet;
};

if (_savePlayerMoney) then {
    [_unitDataHash,"money",_unit getVariable ["grad_lbm_myFunds",0]] call CBA_fnc_hashSet;
    [_unitDataHash,"bankMoney",_unit getVariable ["grad_moneymenu_myBankBalance",0]] call CBA_fnc_hashSet;
};

private _thisUnitVars = [_allPlayerVariableClasses,_unit] call FUNC(saveObjectVars);
[_unitDataHash,"vars",_thisUnitVars] call CBA_fnc_hashSet;

[_playersDataHash,_uid,_unitDataHash] call CBA_fnc_hashSet;

if (_save) then {
    saveProfileNamespace;
};


fn_loadPlayer.sqf: https://github.com/NZF-JDWang/grad-persistence/blob/master/functions/load/fn_loadPlayer.sqf

Spoiler

#include "script_component.hpp"

private _playerWaitCondition = [missionConfigFile >> "CfgGradPersistence", "playerWaitCondition", ""] call BIS_fnc_returnConfigEntry;
if (_playerWaitCondition == "") then {_playerWaitCondition = "true"};

private _fnc_waitUntil = {
    _unit = ((_this select 0) select 0);
    !isNull _unit &&
    {[_unit,side _unit,typeOf _unit,roleDescription _unit] call compile (_this select 1)}
};

[_fnc_waitUntil, {
    params ["_args","_playerWaitCondition"];
    _args params [
        "_unit",
        ["_savePlayerInventory",([missionConfigFile >> "CfgGradPersistence", "savePlayerInventory", 1] call BIS_fnc_returnConfigEntry) == 1],
        ["_savePlayerDamage",([missionConfigFile >> "CfgGradPersistence", "savePlayerDamage", 0] call BIS_fnc_returnConfigEntry) == 1],
        ["_savePlayerPosition",([missionConfigFile >> "CfgGradPersistence", "savePlayerPosition", 0] call BIS_fnc_returnConfigEntry) == 1],
        ["_savePlayerMoney",([missionConfigFile >> "CfgGradPersistence", "savePlayerMoney", 1] call BIS_fnc_returnConfigEntry) == 1]
    ];

    private _missionTag = [] call FUNC(getMissionTag);
    private _playersTag = _missionTag + "_players";
    private _playersDataHash = [_playersTag,true,false] call FUNC(getSaveData);

    private _uid = getPlayerUID _unit;
    if (_uid == "") exitWith {ERROR_1("UID for player %1 not found.",name _unit)};

    private _unitDataHash = [_playersDataHash,_uid] call CBA_fnc_hashGet;
    if (_unitDataHash isEqualType false) exitWith {INFO_1("Data for player %1 not found.",name _unit)};

    if (_savePlayerInventory) then {
        private _unitLoadout = [_unitDataHash,"inventory"] call CBA_fnc_hashGet;
        if !(_unitLoadout isEqualType false) then {
            _unit setUnitLoadout [_unitLoadout,false];
        };
    };

    if (_savePlayerDamage) then {
        if (isClass(configfile >> "CfgPatches" >> "ace_medical")) then {

            private _unitHits = [_unitDataHash,"damage"] call CBA_fnc_hashGet;
            [_unit, _unitHits] remoteExecCall ["ace_medical_fnc_deserializeState", _unit, false];
            diag_log "ACE DETECTED - PreLoading ACE wounds";
            diag_log format ["%1", _unitHits];
            
        } else

        {
            private _unitHits = [_unitDataHash,"damage"] call CBA_fnc_hashGet;
            if (!(_unitHits isEqualType false) && {count _unitHits > 0}) then {
                _unitHits params ["_unitHitNames","_unitHitDamages"];
                {
                    _unit setHit [_x,_unitHitDamages select _forEachIndex];
                } forEach _unitHitNames;
            };
        };
    };

    if (_savePlayerPosition) then {
        private _unitPosASL = [_unitDataHash,"posASL"] call CBA_fnc_hashGet;
        private _unitDir = [_unitDataHash,"dir"] call CBA_fnc_hashGet;

        if (!(_unitPosASL isEqualType false) && !(_unitDir isEqualType false)) then {
            _unit setPosASL _unitPosASL;
            _unit setDir _unitDir;
        };
    };

    if (_savePlayerMoney) then {
        private _unitMoney = [_unitDataHash,"money"] call CBA_fnc_hashGet;
        if !(_unitMoney isEqualType false) then {
            _unit setVariable ["grad_lbm_myFunds",_unitMoney,true];
        };

        private _unitBankMoney = [_unitDataHash,"bankMoney"] call CBA_fnc_hashGet;
        if !(_unitBankMoney isEqualType false) then {
            _unit setVariable ["grad_moneymenu_myBankBalance",_unitBankMoney,true];
        };
    };

    private _vars = [_unitDataHash,"vars"] call CBA_fnc_hashGet;
    [_vars,_unit] call FUNC(loadObjectVars);

}, [_this,_playerWaitCondition]] call CBA_fnc_waitUntilAndExecute;


Don't forget to set your grad persistence configuration to savePlayerDamage = 1;

  • Like 1

Share this post


Link to post
Share on other sites

Please sign in to comment

You will be able to leave a comment after signing in



Sign In Now

×