Jump to content
Tankbuster

BI Virtual Arsenal and BI respawn. Playing nicely together?

Recommended Posts

I KNOW someone has done this and I know it's someone I know well, but I'm damned if I can remember who!

 

I sort of had this working in previous missions, but ran out of talent and into an ever increasing feature request list before getting it quite how I wanted it.

 

Essentially, I'm after 3 things.

  1. Players who join the mission should spawn with their class default loadout
  2. Players who are knocked down and revived should get back their loadout as it was immediately before they were incapacitated.
  3. Players who are knocked down and elect to respawn should get the loadout they last saved.

Share this post


Link to post
Share on other sites

BI Respawn Template (BIS_fnc_addRespawnInventory) is not currently integrated with BI Virtual Arsenal, unfortunately. 

 

Nag Karel Moricky about that and hope for the best :)

Share this post


Link to post
Share on other sites

I've had some success in my Domi edit doing this (read, I fixed what his lordship broke). I can sense when a players respawns because there's an EH for it and can loadout them. But I've not yet found a way to sense when a player has been revived. Checking for players doing a known anim near the revivee is the best I've come up with so far.

Share this post


Link to post
Share on other sites

Some test code..

//initPlayerLocal.sqf
//Save initial loadout
[ player, [ missionNamespace, "currentInventory" ] ] call BIS_fnc_saveInventory;

//Action to simulate saving loadout
player addAction [ "Save Inventory", {
    [ player, [ missionNamespace, "currentInventory" ] ] call BIS_fnc_saveInventory;
}];

//Save loadout when ever we exit an arsenal
[ missionNamespace, "arsenalClosed", {
    [ player, [ missionNamespace, "currentInventory" ] ] call BIS_fnc_saveInventory;
}] call BIS_fnc_addScriptedEventHandler;

//When we revive
[ missionNamespace, "reviveRevived", {
    _nul = _this spawn {
        _unit = _this select 0;
        _revivor = _this select 1;

        //This need something better to postpone loading inventory
        waitUntil { !( _unit in BIS_revive_units ) };
        sleep 5;

        //if forced respawn
        if ( isNull _revivor ) then {
            [ player, [ missionNamespace, "currentInventory" ] ] call BIS_fnc_loadInventory;
        };
    };
} ] call BIS_fnc_addScriptedEventHandler;

At the moment of death as you go into incapacitate state you can also find the units current loadout...

[ missionNamespace, "reviveIncapacitated", {
    h = [] spawn {
        waitUntil { ( player getVariable [ "bis_revive_loadoutsaved", false ] ) };
        _loadout = player getVariable [ "bis_fnc_saveinventory_data", [] ];
       hint str _loadout;
    };
} ] call BIS_fnc_addScriptedEventHandler;
But is cleared virtually instantly.

Something to mess around with.

  • Like 4

Share this post


Link to post
Share on other sites

That's some good stuff there, some of it I'm familiar with. The bits specific to BI respawn is all new to me, so that's good. It's useful to know about things like bis_revive_units.

 

Thank you. :)

Share this post


Link to post
Share on other sites

Some test code..

*snip

Thanks Larrow.

 

Have been looking for something like this for some time.

 

Cheers

Twak

Share this post


Link to post
Share on other sites

This should satisfy all the conditions in the OP. I know you've likely solved this by now TB but thought I would post for completeness and of course to satisfy my OCD :D.

//initPlayerLocal.sqf

//small sleep to make sure any init loadouts have been applied
//OR apply any default loadouts before this point
sleep 1;

//Save initial loadout
[ player, [ missionNamespace, "currentInventory" ] ] call BIS_fnc_saveInventory;


//Save loadout when ever we exit an arsenal
[ missionNamespace, "arsenalClosed", {
	[ player, [ missionNamespace, "currentInventory" ] ] call BIS_fnc_saveInventory;
}] call BIS_fnc_addScriptedEventHandler;


//When we revive
[ missionNamespace, "reviveRevived", {
	_nul = _this spawn {
		_unit = _this select 0;
		_revivor = _this select 1;

		//if forced respawn or we bleed out
		if ( isNull _revivor ) then {
			//wait until player is actually respawned into alive state
			sleep playerRespawnTime;
			//Load last saved inventory
			[ player, [ missionNamespace, "currentInventory" ] ] call BIS_fnc_loadInventory;
		};
	};
} ] call BIS_fnc_addScriptedEventHandler;


player addEventHandler [ "Killed", {
	//Save players loadout for if he is revived
	[ player, [ missionNamespace, "reviveInventory" ] ] call BIS_fnc_saveInventory;
}];


player addEventHandler [ "Respawn", {
	if ( player getVariable [ "BIS_revive_incapacitated", false ] ) then {
		//Set correct loadout on incapacitated unit laying on floor in injured state
		//This is also the new unit if he is revived
		[ player, [ missionNamespace, "reviveInventory" ] ] call BIS_fnc_loadInventory;
	};
	//Did we respawn from the menu
	if ( missionNamespace getVariable [ "menuRespawn", false ] ) then {
		[ player, [ missionNamespace, "currentInventory" ] ] call BIS_fnc_loadInventory;
		missionNamespace setVariable [ "menuRespawn", false ];
	};
}];

//If the respawn menu button is active
if ( !isNumber( missionConfigFile >> "respawnButton" ) || { getNumber( missionConfigFile >> "respawnButton" ) > 0 } ) then {
	_respawnMenu = [] spawn {
		waitUntil { !isNull ( uiNamespace getVariable [ "RscDisplayMPInterrupt", displayNull ] ) };
		uiNamespace getVariable "RscDisplayMPInterrupt" displayCtrl 1010 ctrlAddEventHandler [ "ButtonClick", {
			missionNamespace setVariable [ "menuRespawn", true ];
		}];
	};
};

  • Like 2

Share this post


Link to post
Share on other sites

So I have a weird bug using this. I am using "menuinventory" as well as the "revive" respawntemplate[]. The bug is that while on the 1st life, when incapacitated the player loads the default loadout for the type of unit they are playing. When revived they are still using the default loadout. After they die "all the way" and respawn the issue doesn't come up. Why is this happening?

Share this post


Link to post
Share on other sites

This is a limitation of the current BI revive. It's mission dependent, but put simply, whether the player respawns or is revived, he gets his default loadout. This is because in both instances. the player actually dies and respawns. With some of the cunning scripting provided by Larrow above and some of my own, you can prevent this.

 

First, you can try to grab the players loadout just before he dies. Use a handledamage event handler and when that fires, if the damage is more than 0.8, save his inventory out. If he's subsequently revived, give him back that inventory,

 

Second, as the player closes the arsenal, save his loadout. Then when he respawns, give him back that one.

Share this post


Link to post
Share on other sites
Why is this happening?

I forgot to account for menuInventory setups when i wrote that. You will want to add to the respawn EH something like..

player addEventHandler [ "Respawn", {
    //Are we respawning due to incapacitated
    if ( player getVariable [ "BIS_revive_incapacitated", false ] ) then {
        //Set correct loadout on incapacitated unit laying on floor in injured state
        //This is also the new unit if he is revived
        [ player, [ missionNamespace, "reviveInventory" ] ] call BIS_fnc_loadInventory;
    }else{
                
        //Did we respawn from the menu
        if ( missionNamespace getVariable [ "menuRespawn", false ] ) then {
            [ player, [ missionNamespace, "currentInventory" ] ] call BIS_fnc_loadInventory;
            missionNamespace setVariable [ "menuRespawn", false ];
        };
        
        //Is menuInventory available?
        _templates = getArray (missionConfigFile >> "respawnTemplates");
        _templates = _templates + getArray (missionConfigFile >> ("respawnTemplates" + str playerSide));
    
        if ( { "menuInventory" == _x }count _templates > 0 ) then {
            [ player, [ missionNamespace, "currentInventory" ] ] call BIS_fnc_saveInventory;
        };
    };

}];
Untested but something like the above so if your respawning other than from incapacitated and have menuInventory as a respawn template then it saves your get current gear.

Share this post


Link to post
Share on other sites

This has stopped working :(

[ missionNamespace, "arsenalClosed",
	{
	diag_log "*** VA closed!";
    [ player, [ missionNamespace, "currentInventory" ] ] call BIS_fnc_saveInventory;
	}] call BIS_fnc_addScriptedEventHandler;
	//^^ when player closes VA, save their loadout to server
sleep 1;
startLoadingScreen ["Authority mission is setting up. Please wait."];
while {missionsetupprogress < 0.95} do
	{
		sleep 1;
		progressLoadingScreen missionsetupprogress;
	};
waitUntil {initserverfinished};
player setVariable ["last_inventory_saved", -1];
endLoadingScreen;

player setpos ([(getmarkerpos "respawn_west"), (3+ (random 3)), random 360] call bis_fnc_relPos);
//larrows EH to better handle revive and respawn.
[ missionNamespace, "reviveRevived", {
	_nul = _this spawn
		{
		_unit = _this select 0;
		_revivor = _this select 1;
		diag_log format ["***revivedRevive _unit %1, revivor %2", _unit, _revivor];
		//if forced respawn or we bleed out
		if ( isNull _revivor ) then
			{
			//wait until player is actually respawned into alive state
			sleep playerRespawnTime;
			//Load last saved inventory
			diag_log "*** reviveRevived EH loads saved inv!";
			[ player, [ missionNamespace, "currentInventory" ] ] call BIS_fnc_loadInventory;
			};
		};
} ] call BIS_fnc_addScriptedEventHandler;
player addEventHandler [ "Respawn",
	{
	if ( player getVariable [ "BIS_revive_incapacitated", false ] ) then
		{
		//Set correct loadout on incapacitated unit laying on floor in injured state
		//This is also the new unit if he is revived
		diag_log "*** loading reviveinventory";
		[ player, [ missionNamespace, "reviveInventory" ] ] call BIS_fnc_loadInventory;
		};
	//Did we respawn from the menu
	if ( missionNamespace getVariable [ "menuRespawn", false ] ) then
		{
		diag_log "*** loading menu respawn inventiry";
		[ player, [ missionNamespace, "currentInventory" ] ] call BIS_fnc_loadInventory;
		missionNamespace setVariable [ "menuRespawn", false ];
		};
	}];

The inventory is saved when the VA closes. I can test this by loading a loading the inventory using a debug console.

 

But whenever the player respawns, he gets config default gear given to him. The debug ***reviveRevived is never seen, nor is the ***loading menu respawn inventiry. I do see the "***loading revive inventory in all circumstances - that is, selected respawn from escape menu, during revive, or when the player selects respawn from the revive dialog.

Share this post


Link to post
Share on other sites

The whole things been rewritten for 1.56

From a few quick test you shouldn't need much more than this...

//initPlayerLocal.sqf
#include "\a3\functions_f_mp_mark\Revive\defines.hpp"

systemChat "Saving initial loadout";
//Save initial loadout
[ player, [ missionNamespace, "currentInventory" ] ] call BIS_fnc_saveInventory;


//Save loadout when ever we exit an arsenal
[ missionNamespace, "arsenalClosed", {
	systemChat "Arsenal closed";
	[ player, [ missionNamespace, "currentInventory" ] ] call BIS_fnc_saveInventory;
}] call BIS_fnc_addScriptedEventHandler;


player addEventHandler [ "Respawn", {

	systemChat "Respawning";
	systemChat format[ "state %1", GET_STATE_STR(GET_STATE( player )) ];

	if ( GET_STATE( player ) == STATE_RESPAWNED ) then {
		systemChat "Died or Respawned via menu";
		_templates = [];
		{
			{
				_nul = _templates pushBackUnique _x;
			}forEach ( getMissionConfigValue [ _x, [] ] );
		}forEach [ "respawntemplates", format[ "respawntemplates%1", str playerSide ] ];

		if ( { "menuInventory" == _x }count _templates > 0 ) then {
			systemChat "Respawning - saving menu inventory";
			[ player, [ missionNamespace, "currentInventory" ] ] call BIS_fnc_saveInventory;
		}else{
			h = [] spawn {
				sleep playerRespawnTime;
				systemChat "Respawning - loading last saved";
				[ player, [ missionNamespace, "currentInventory" ] ] call BIS_fnc_loadInventory;
			};
		};

	}else{
		systemChat "Incapacitated";
	};
}];
The whole problem with Incapacitated state on saving/reapplying your gear seems to have been fixed.

Have not test the menuInventory side of things as it is currently broken.

Heres a hint showing some of the available variables and there values wrapped in a OEF.

[ "OEFRevive", "onEachFrame", {
	_msg = "Unit States\n";
	_msg = format[ "%1\nBroadcasts\n", _msg ];
	{
		_msg = format [ "
			%1
			%2 - %3\n
			",
			_msg,
			_x,
			player getVariable [ _x, "nil" ]
		];
	}forEach [
		VAR_TRANSFER_STATE,
		VAR_TRANSFER_FORCING_RESPAWN,
		VAR_TRANSFER_BEING_REVIVED
	];
	_msg = format[ "%1\nLocal\n", _msg ];
	{
		_msg = format [ "
			%1
			%2 - %3\n
			",
			_msg,
			_x,
			player getVariable [ _x, "nil" ]
		];
	}forEach [
		VAR_STATE,
		VAR_STATE_PREV,
		VAR_BEING_REVIVED,
		VAR_FORCING_RESPAWN,
		VAR_HELPER,
		VAR_DAMAGE,
		VAR_BLOOD
	];
	_msg = format[ "%1\nStates\n", _msg ];
	{
		_msg = format [ "
			%1
			%2 - %3\n
			",
			_msg,
			_x select 0,
			_x select 1
		];
	}forEach [
		[ "STATE_RESPAWNED", STATE_RESPAWNED ],
		[ "STATE_REVIVED", STATE_REVIVED ],
		[ "STATE_INCAPACITATED", STATE_INCAPACITATED ],
		[ "STATE_DYING", STATE_DYING ],
		[ "STATE_DEAD", STATE_DEAD ],
		[ "STATE_DOWNED", STATE_DOWNED ]
	];
	hintSilent _msg;
}] call BIS_fnc_addStackedEventHandler;
Just run it somewhere in your initPlayerLocal.sqf as it needs the defines (included in script above) to work.
  • Like 2

Share this post


Link to post
Share on other sites

The whole things been rewritten for 1.56

From a few quick test you shouldn't need much more than this...

//initPlayerLocal.sqf
#include "\a3\functions_f_mp_mark\Revive\defines.hpp"

systemChat "Saving initial loadout";
//Save initial loadout
[ player, [ missionNamespace, "currentInventory" ] ] call BIS_fnc_saveInventory;


//Save loadout when ever we exit an arsenal
[ missionNamespace, "arsenalClosed", {
	systemChat "Arsenal closed";
	[ player, [ missionNamespace, "currentInventory" ] ] call BIS_fnc_saveInventory;
}] call BIS_fnc_addScriptedEventHandler;


player addEventHandler [ "Respawn", {

	systemChat "Respawning";
	systemChat format[ "state %1", GET_STATE_STR(GET_STATE( player )) ];

	if ( GET_STATE( player ) == STATE_RESPAWNED ) then {
		systemChat "Died or Respawned via menu";
		_templates = [];
		{
			{
				_nul = _templates pushBackUnique _x;
			}forEach ( getMissionConfigValue [ _x, [] ] );
		}forEach [ "respawntemplates", format[ "respawntemplates%1", str playerSide ] ];

		if ( { "menuInventory" == _x }count _templates > 0 ) then {
			systemChat "Respawning - saving menu inventory";
			[ player, [ missionNamespace, "currentInventory" ] ] call BIS_fnc_saveInventory;
		}else{
			h = [] spawn {
				sleep playerRespawnTime;
				systemChat "Respawning - loading last saved";
				[ player, [ missionNamespace, "currentInventory" ] ] call BIS_fnc_loadInventory;
			};
		};

	}else{
		systemChat "Incapacitated";
	};
}];
The whole problem with Incapacitated state on saving/reapplying your gear seems to have been fixed.

Have not test the menuInventory side of things as it is currently broken.

Heres a hint showing some of the available variables and there values wrapped in a OEF.

[ "OEFRevive", "onEachFrame", {
	_msg = "Unit States\n";
	_msg = format[ "%1\nBroadcasts\n", _msg ];
	{
		_msg = format [ "
			%1
			%2 - %3\n
			",
			_msg,
			_x,
			player getVariable [ _x, "nil" ]
		];
	}forEach [
		VAR_TRANSFER_STATE,
		VAR_TRANSFER_FORCING_RESPAWN,
		VAR_TRANSFER_BEING_REVIVED
	];
	_msg = format[ "%1\nLocal\n", _msg ];
	{
		_msg = format [ "
			%1
			%2 - %3\n
			",
			_msg,
			_x,
			player getVariable [ _x, "nil" ]
		];
	}forEach [
		VAR_STATE,
		VAR_STATE_PREV,
		VAR_BEING_REVIVED,
		VAR_FORCING_RESPAWN,
		VAR_HELPER,
		VAR_DAMAGE,
		VAR_BLOOD
	];
	_msg = format[ "%1\nStates\n", _msg ];
	{
		_msg = format [ "
			%1
			%2 - %3\n
			",
			_msg,
			_x select 0,
			_x select 1
		];
	}forEach [
		[ "STATE_RESPAWNED", STATE_RESPAWNED ],
		[ "STATE_REVIVED", STATE_REVIVED ],
		[ "STATE_INCAPACITATED", STATE_INCAPACITATED ],
		[ "STATE_DYING", STATE_DYING ],
		[ "STATE_DEAD", STATE_DEAD ],
		[ "STATE_DOWNED", STATE_DOWNED ]
	];
	hintSilent _msg;
}] call BIS_fnc_addStackedEventHandler;
Just run it somewhere in your initPlayerLocal.sqf as it needs the defines (included in script above) to work.

 

Just tested this. The only issue is backpacks for SOME players are duplicated on revive. Very odd. When respawning there seems to be no issues, just on revives. Once or twice a revived player was given their default class backpack in place of the one they chose from the arsenal. The one they were wearing before being revived remains on the ground. And by default class backpack I mean the backpack that came with the character they chose at the server lobby screen. Any ideas larrow, tankbuster, or others?

Share this post


Link to post
Share on other sites

Would need looking into, as my posted script now does nothing for players being revived this will be an issue with BI revive scripts.

As a fix it would involve, like the previous script, saving the players backpack and contents on killed && STATE_DOWNED and then in the respawn EH checking for STATE_INCAPACITATED and reapplying the backpack and contents.

//initPlayerLocal.sqf
#include "\a3\functions_f_mp_mark\Revive\defines.hpp"

systemChat "Saving initial loadout";
//Save initial loadout
[ player, [ missionNamespace, "currentInventory" ] ] call BIS_fnc_saveInventory;


//Save loadout when ever we exit an arsenal
[ missionNamespace, "arsenalClosed", {
	systemChat "Arsenal closed";
	[ player, [ missionNamespace, "currentInventory" ] ] call BIS_fnc_saveInventory;
}] call BIS_fnc_addScriptedEventHandler;

//Save backpack and items when killed
player addEventHandler [ "Killed", {
	params[
		"_unit",
		"_killer"
	];
	systemChat "Killed";
	if ( GET_STATE( _unit ) isEqualTo STATE_DOWNED ) then {
		systemChat "Downed - saving backpack and contents";
		_unit setVariable [ "backpack", backpack _unit ];
		_unit setVariable [ "backpack_items", backpackItems _unit ];
	};
}];


player addEventHandler [ "Respawn", {
	params[
		"_unit",
		"_corpse"
	];

	systemChat "Respawning";
	systemChat format[ "state %1", GET_STATE_STR(GET_STATE( _unit )) ];

	switch ( GET_STATE( _unit ) ) do {
		case STATE_INCAPACITATED : {
			systemChat "Incapacitated";
			_backpack = _corpse getVariable [ "backpack", "" ];
			if !( _backpack isEqualTo "" ) then {
				systemChat "Fixing units backpack and items";
				removeBackpackGlobal _unit;
				_unit addBackpackGlobal _backpack;
				_items = _corpse getVariable [ "backpack_items", [] ];
				{
					_unit addItemToBackpack _x;
				}forEach _items;
			};
		};
		case STATE_RESPAWNED : {
			h = _unit spawn {
				params[ "_unit" ];
				systemChat "Died or Respawned via menu";
				_templates = [];
				{
					{
						_nul = _templates pushBackUnique _x;
					}forEach ( getMissionConfigValue [ _x, [] ] );
				}forEach [ "respawntemplates", format[ "respawntemplates%1", str playerSide ] ];

				sleep playerRespawnTime;

				if ( { "menuInventory" == _x }count _templates > 0 ) then {
					systemChat "Respawning - saving menu inventory";
					[ _unit, [ missionNamespace, "currentInventory" ] ] call BIS_fnc_saveInventory;
				}else{
					systemChat "Respawning - loading last saved";
					[ _unit, [ missionNamespace, "currentInventory" ] ] call BIS_fnc_loadInventory;
				};

				_unit setVariable [ "backpack", nil ];
				_unit setVariable [ "backpack_items", nil ];
			};
		};
	};
}];
Untested..

Although the fact backpack are not saving properly should be bought to BI's attention rather than work arounds like this.

Share this post


Link to post
Share on other sites

Gonna hijack this thread for an issue I have which is also save/load loadout on respawn related.

 

I implemented something similar in my 3den Enhanced mod, however I can't get it to work on a dedicated server, although it works on a hosted one.

 

The code looks like this:

                [_this] spawn //_this is the object the attribute is applied to
                {
                    waitUntil {time > 0.2}; //Added a short delay to make sure the Arsenal loadout and/or other attributes are properly applied before the loadout will be saved
                    [_this select 0,[missionNamespace,'inventory_var']] call BIS_fnc_saveInventory;
                    (_this select 0) addEventhandler ['respawn',
                    {
                        [_this select 0,[missionNamespace,'inventory_var']] call BIS_fnc_loadInventory;// (_this select 0) is not the same as above, it points to the new unit in the eventHandler
                    }];
                };

So on a dedicated server, I can't even find the loadout in the missionNamespace which means this code is not executed, or it's executed before the unit has its loadout ?!?

 

Any help would be apprechiated.

Share this post


Link to post
Share on other sites

Are you sure that is not just a locality problem R3vo. Im presuming this code is being run as part of an attribute expression? Which are only run on the server.

You would want to save your code as a function in the library and then remoteExec it from the expression to where the unit is local.

_this remoteExec ["My_fnc_loadout", owner _this]

Share this post


Link to post
Share on other sites

Yes you're are probably right, the issue there is, that I can't use a function since that would create a dependency. I wonder if it would be enough to waitUntil {isPlayer _this};

Share this post


Link to post
Share on other sites

I can't use a function since that would create a dependency.

True. Just pass the code and remoteExec BIS_fnc_spawn instead.

Maybe something like..

if ( _this in playableUnits ) then {
	_nul = _this spawn {
		waitUntil { isPlayer _this };
		{
		    [player,[missionNamespace,'inventory_var']] call BIS_fnc_saveInventory;
		    player addEventHandler ['respawn', {
		        [_this select 0,[missionNamespace,'inventory_var']] call BIS_fnc_loadInventory;
		    }];
		} remoteExec [ "BIS_fnc_spawn", owner _this ];
	};
};
EDIT: Removed !local check as that would stop it working for hosts

Share this post


Link to post
Share on other sites

True. Just pass the code and remoteExec BIS_fnc_spawn instead.

Maybe something like..

if ( _this in playableUnits ) then {
	_nul = _this spawn {
		waitUntil { !local _this && { isPlayer _this } };
		{
		    [player,[missionNamespace,'inventory_var']] call BIS_fnc_saveInventory;
		    player addEventHandler ['respawn', {
		        [_this select 0,[missionNamespace,'inventory_var']] call BIS_fnc_loadInventory;
		    }];
		} remoteExec [ "BIS_fnc_spawn", owner _this ];
	};
};

 

does bis_fnc_spawn work with remoteexec like this?

 

iirc have to use syntax like 

[args,code] remoteexec ['bis_fnc_spawn',target,jip];

so

[[],{/*my code*/}] remoteexec ['bis_fnc_spawn',(owner _this),false];

Share this post


Link to post
Share on other sites

does bis_fnc_spawn work with remoteexec like this?

Yes its fine to just send the code if no arguments are required.

Share this post


Link to post
Share on other sites

Hmm, didn't work unfortunately, gear is still not saved at mission start.

 

I removed the check for the playableUnit and it seems to work now. Thank you very much ;)

 

 

Edit: Damn, another thing I just noticed, if the player goes back into the lobby and rejoins afterwards, the code is not executed anymore, therefore default loadout is again set on respawn. I thought the code added to a unit via attribute is always executed when the unit is created, not only on mission start.

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

×