diff --git a/description.ext b/description.ext index 1a99b15b..014b17bc 100644 --- a/description.ext +++ b/description.ext @@ -27,10 +27,34 @@ minPlayerDistance = 500; // The minimum distance between corpse or wreck and nea // FA3 - Respawn Settings -respawn = 1; -respawndelay = 3; -respawnOnStart = 0; -respawnTemplates[] = {"F_Spectator"}; +respawn = 3; +respawnDialog = 0; +respawndelay = -1; +respawnOnStart = -1; +respawnButton = 0; +respawnTemplates[] = {"F_Respawn", "Tickets", "Counter"}; + +// ============================================================================================ + +// FA3 - Respawn templates +// DO NOT REMOVE OR DISABLE THIS BLOCK OF CODE + + +// ============================================================================================ +class CfgRespawnTemplates +{ + class F_Respawn + { + respawnDelay = 30; + onPlayerRespawn = "f_fnc_respawn"; + onPlayerKilled = "f_fnc_respawnKilled"; + }; + class F_Spectator + { + onPlayerRespawn = "f_fnc_activateSpectator"; + }; +}; + // ============================================================================================ @@ -269,6 +293,17 @@ class Params default = 0; }; +// FA3 - Respawn Tickets Parameters +// Credits and documentation: https://github.com/folkarps/F3/wiki + + class f_param_respawnTickets + { + title = "Respawn tickets per side"; + values[] = {0,10,25,50,2000}; + texts[] = {"None", "10", "25", "50", "2000"}; + default = 10; + }; + // ============================================================================================ // FA3 - Caching @@ -357,23 +392,6 @@ class CfgDebriefing }; - - -// ============================================================================================ - -// FA3 - Respawn templates -// DO NOT REMOVE OR DISABLE THIS BLOCK OF CODE - - -// ============================================================================================ -class CfgRespawnTemplates -{ - class F_Spectator - { - onPlayerRespawn = "f\spect\fn_activateSpectator.sqf"; - }; -}; - // ============================================================================================ // FA3 - Functions @@ -420,3 +438,5 @@ class RscTitles // UI elements for the medical system #include "f\medical\f_FAMUI.hpp" }; + +#include "f\respawn\f_respawnDisplays.hpp" \ No newline at end of file diff --git a/f/assignGear/f_assignGear_3IFB_standard.sqf b/f/assignGear/f_assignGear_3IFB_standard.sqf index 24cefa14..5dce2180 100644 --- a/f/assignGear/f_assignGear_3IFB_standard.sqf +++ b/f/assignGear/f_assignGear_3IFB_standard.sqf @@ -588,6 +588,19 @@ switch (_typeofUnit) do _unit addmagazines [_glmag, 10]; _unit addmagazines [_grenade, 2]; }; +// Respawn Loadout: + case "respawn": + { + _unit addmagazines [_riflemag, 1]; + _unit addweapon _rifle; + _unit addmagazines [_smokegrenade, 3]; + _unit addmagazines [_riflemag, 2]; + _unit addmagazines [_riflemag_tr, 1]; + _unit addmagazines [_grenade, 2]; + { + _unit setUnitTrait [_x#0, _x#1]; + } forEach (_unit getVariable ["f_var_unitTraits",[]]); + }; // Include the loadouts for vehicles and crates: #include "f_assignGear_3IFB_v.sqf"; diff --git a/f/assignGear/f_assignGear_aaf_standard.sqf b/f/assignGear/f_assignGear_aaf_standard.sqf index adf01dc2..fadfdbd3 100644 --- a/f/assignGear/f_assignGear_aaf_standard.sqf +++ b/f/assignGear/f_assignGear_aaf_standard.sqf @@ -589,6 +589,19 @@ switch (_typeofUnit) do _unit addmagazines [_glmag, 10]; _unit addmagazines [_grenade, 2]; }; +// Respawn Loadout: + case "respawn": + { + _unit addmagazines [_riflemag, 1]; + _unit addweapon _rifle; + _unit addmagazines [_smokegrenade, 3]; + _unit addmagazines [_riflemag, 2]; + _unit addmagazines [_riflemag_tr, 1]; + _unit addmagazines [_grenade, 2]; + { + _unit setUnitTrait [_x#0, _x#1]; + } forEach (_unit getVariable ["f_var_unitTraits",[]]); + }; // Include the loadouts for vehicles and crates: #include "f_assignGear_aaf_v.sqf"; diff --git a/f/assignGear/f_assignGear_csatPacific_standard.sqf b/f/assignGear/f_assignGear_csatPacific_standard.sqf index 86bd7b1a..96989e00 100644 --- a/f/assignGear/f_assignGear_csatPacific_standard.sqf +++ b/f/assignGear/f_assignGear_csatPacific_standard.sqf @@ -589,6 +589,19 @@ switch (_typeofUnit) do _unit addmagazines [_glmag, 10]; _unit addmagazines [_grenade, 2]; }; +// Respawn Loadout: + case "respawn": + { + _unit addmagazines [_riflemag, 1]; + _unit addweapon _rifle; + _unit addmagazines [_smokegrenade, 3]; + _unit addmagazines [_riflemag, 2]; + _unit addmagazines [_riflemag_tr, 1]; + _unit addmagazines [_grenade, 2]; + { + _unit setUnitTrait [_x#0, _x#1]; + } forEach (_unit getVariable ["f_var_unitTraits",[]]); + }; // Include the loadouts for vehicles and crates: #include "f_assignGear_csat_v.sqf"; diff --git a/f/assignGear/f_assignGear_csat_standard.sqf b/f/assignGear/f_assignGear_csat_standard.sqf index e092a1db..2537306e 100644 --- a/f/assignGear/f_assignGear_csat_standard.sqf +++ b/f/assignGear/f_assignGear_csat_standard.sqf @@ -589,6 +589,19 @@ switch (_typeofUnit) do _unit addmagazines [_glmag, 10]; _unit addmagazines [_grenade, 2]; }; +// Respawn Loadout: + case "respawn": + { + _unit addmagazines [_riflemag, 1]; + _unit addweapon _rifle; + _unit addmagazines [_smokegrenade, 3]; + _unit addmagazines [_riflemag, 2]; + _unit addmagazines [_riflemag_tr, 1]; + _unit addmagazines [_grenade, 2]; + { + _unit setUnitTrait [_x#0, _x#1]; + } forEach (_unit getVariable ["f_var_unitTraits",[]]); + }; // Include the loadouts for vehicles and crates: #include "f_assignGear_csat_v.sqf"; diff --git a/f/assignGear/f_assignGear_ctrg_standard.sqf b/f/assignGear/f_assignGear_ctrg_standard.sqf index 8342ba1c..221e084e 100644 --- a/f/assignGear/f_assignGear_ctrg_standard.sqf +++ b/f/assignGear/f_assignGear_ctrg_standard.sqf @@ -589,6 +589,19 @@ switch (_typeofUnit) do _unit addmagazines [_glmag, 10]; _unit addmagazines [_grenade, 2]; }; +// Respawn Loadout: + case "respawn": + { + _unit addmagazines [_riflemag, 1]; + _unit addweapon _rifle; + _unit addmagazines [_smokegrenade, 3]; + _unit addmagazines [_riflemag, 2]; + _unit addmagazines [_riflemag_tr, 1]; + _unit addmagazines [_grenade, 2]; + { + _unit setUnitTrait [_x#0, _x#1]; + } forEach (_unit getVariable ["f_var_unitTraits",[]]); + }; // Include the loadouts for vehicles and crates: #include "f_assignGear_ctrg_v.sqf"; diff --git a/f/assignGear/f_assignGear_fia_standard.sqf b/f/assignGear/f_assignGear_fia_standard.sqf index f7d7d70e..2ecf98f0 100644 --- a/f/assignGear/f_assignGear_fia_standard.sqf +++ b/f/assignGear/f_assignGear_fia_standard.sqf @@ -589,6 +589,19 @@ switch (_typeofUnit) do _unit addmagazines [_glmag, 10]; _unit addmagazines [_grenade, 2]; }; +// Respawn Loadout: + case "respawn": + { + _unit addmagazines [_riflemag, 1]; + _unit addweapon _rifle; + _unit addmagazines [_smokegrenade, 3]; + _unit addmagazines [_riflemag, 2]; + _unit addmagazines [_riflemag_tr, 1]; + _unit addmagazines [_grenade, 2]; + { + _unit setUnitTrait [_x#0, _x#1]; + } forEach (_unit getVariable ["f_var_unitTraits",[]]); + }; // Include the loadouts for vehicles and crates: #include "f_assignGear_fia_v.sqf"; diff --git a/f/assignGear/f_assignGear_gendarmerie.sqf b/f/assignGear/f_assignGear_gendarmerie.sqf index 661e1889..dfbc4979 100644 --- a/f/assignGear/f_assignGear_gendarmerie.sqf +++ b/f/assignGear/f_assignGear_gendarmerie.sqf @@ -336,6 +336,19 @@ switch (_typeofUnit) do _unit addmagazines [_chemred,1]; _unit addmagazines [_chemyellow,1]; }; +// Respawn Loadout: + case "respawn": + { + _unit addmagazines [_riflemag, 1]; + _unit addweapon _rifle; + _unit addmagazines [_smokegrenade, 3]; + _unit addmagazines [_riflemag, 2]; + _unit addmagazines [_riflemag_tr, 1]; + _unit addmagazines [_grenade, 2]; + { + _unit setUnitTrait [_x#0, _x#1]; + } forEach (_unit getVariable ["f_var_unitTraits",[]]); + }; // CARGO: CAR - room for 10 weapons and 50 cargo items case "v_car": { diff --git a/f/assignGear/f_assignGear_ldf_standard.sqf b/f/assignGear/f_assignGear_ldf_standard.sqf index 6637783f..8e0911ad 100644 --- a/f/assignGear/f_assignGear_ldf_standard.sqf +++ b/f/assignGear/f_assignGear_ldf_standard.sqf @@ -589,6 +589,19 @@ switch (_typeofUnit) do _unit addmagazines [_glmag, 10]; _unit addmagazines [_grenade, 2]; }; +// Respawn Loadout: + case "respawn": + { + _unit addmagazines [_riflemag, 1]; + _unit addweapon _rifle; + _unit addmagazines [_smokegrenade, 3]; + _unit addmagazines [_riflemag, 2]; + _unit addmagazines [_riflemag_tr, 1]; + _unit addmagazines [_grenade, 2]; + { + _unit setUnitTrait [_x#0, _x#1]; + } forEach (_unit getVariable ["f_var_unitTraits",[]]); + }; // Include the loadouts for vehicles and crates: #include "f_assignGear_ldf_v.sqf"; diff --git a/f/assignGear/f_assignGear_natoPacific_standard.sqf b/f/assignGear/f_assignGear_natoPacific_standard.sqf index 03900428..d5d1e3dd 100644 --- a/f/assignGear/f_assignGear_natoPacific_standard.sqf +++ b/f/assignGear/f_assignGear_natoPacific_standard.sqf @@ -589,6 +589,19 @@ switch (_typeofUnit) do _unit addmagazines [_glmag, 10]; _unit addmagazines [_grenade, 2]; }; +// Respawn Loadout: + case "respawn": + { + _unit addmagazines [_riflemag, 1]; + _unit addweapon _rifle; + _unit addmagazines [_smokegrenade, 3]; + _unit addmagazines [_riflemag, 2]; + _unit addmagazines [_riflemag_tr, 1]; + _unit addmagazines [_grenade, 2]; + { + _unit setUnitTrait [_x#0, _x#1]; + } forEach (_unit getVariable ["f_var_unitTraits",[]]); + }; // Include the loadouts for vehicles and crates: #include "f_assignGear_nato_v.sqf"; diff --git a/f/assignGear/f_assignGear_natoWoodland_standard.sqf b/f/assignGear/f_assignGear_natoWoodland_standard.sqf index b859678c..cac5dd51 100644 --- a/f/assignGear/f_assignGear_natoWoodland_standard.sqf +++ b/f/assignGear/f_assignGear_natoWoodland_standard.sqf @@ -589,6 +589,19 @@ switch (_typeofUnit) do _unit addmagazines [_glmag, 10]; _unit addmagazines [_grenade, 2]; }; +// Respawn Loadout: + case "respawn": + { + _unit addmagazines [_riflemag, 1]; + _unit addweapon _rifle; + _unit addmagazines [_smokegrenade, 3]; + _unit addmagazines [_riflemag, 2]; + _unit addmagazines [_riflemag_tr, 1]; + _unit addmagazines [_grenade, 2]; + { + _unit setUnitTrait [_x#0, _x#1]; + } forEach (_unit getVariable ["f_var_unitTraits",[]]); + }; // Include the loadouts for vehicles and crates: #include "f_assignGear_nato_v.sqf"; diff --git a/f/assignGear/f_assignGear_nato_standard.sqf b/f/assignGear/f_assignGear_nato_standard.sqf index 37b66ce2..332d47dd 100644 --- a/f/assignGear/f_assignGear_nato_standard.sqf +++ b/f/assignGear/f_assignGear_nato_standard.sqf @@ -589,6 +589,19 @@ switch (_typeofUnit) do _unit addmagazines [_glmag, 10]; _unit addmagazines [_grenade, 2]; }; +// Respawn Loadout: + case "respawn": + { + _unit addmagazines [_riflemag, 1]; + _unit addweapon _rifle; + _unit addmagazines [_smokegrenade, 3]; + _unit addmagazines [_riflemag, 2]; + _unit addmagazines [_riflemag_tr, 1]; + _unit addmagazines [_grenade, 2]; + { + _unit setUnitTrait [_x#0, _x#1]; + } forEach (_unit getVariable ["f_var_unitTraits",[]]); + }; // Include the loadouts for vehicles and crates: #include "f_assignGear_nato_v.sqf"; diff --git a/f/assignGear/f_assignGear_npr_standard.sqf b/f/assignGear/f_assignGear_npr_standard.sqf index 1ec078a5..03940a8e 100644 --- a/f/assignGear/f_assignGear_npr_standard.sqf +++ b/f/assignGear/f_assignGear_npr_standard.sqf @@ -589,6 +589,19 @@ switch (_typeofUnit) do _unit addmagazines [_glmag, 10]; _unit addmagazines [_grenade, 2]; }; +// Respawn Loadout: + case "respawn": + { + _unit addmagazines [_riflemag, 1]; + _unit addweapon _rifle; + _unit addmagazines [_smokegrenade, 3]; + _unit addmagazines [_riflemag, 2]; + _unit addmagazines [_riflemag_tr, 1]; + _unit addmagazines [_grenade, 2]; + { + _unit setUnitTrait [_x#0, _x#1]; + } forEach (_unit getVariable ["f_var_unitTraits",[]]); + }; // Include the loadouts for vehicles and crates: #include "f_assignGear_npr_v.sqf"; diff --git a/f/assignGear/f_assignGear_spetsnaz_standard.sqf b/f/assignGear/f_assignGear_spetsnaz_standard.sqf index e046f89d..01b5484d 100644 --- a/f/assignGear/f_assignGear_spetsnaz_standard.sqf +++ b/f/assignGear/f_assignGear_spetsnaz_standard.sqf @@ -593,6 +593,19 @@ switch (_typeofUnit) do _unit addmagazines [_glmag, 10]; _unit addmagazines [_grenade, 2]; }; +// Respawn Loadout: + case "respawn": + { + _unit addmagazines [_riflemag, 1]; + _unit addweapon _rifle; + _unit addmagazines [_smokegrenade, 3]; + _unit addmagazines [_riflemag, 2]; + _unit addmagazines [_riflemag_tr, 1]; + _unit addmagazines [_grenade, 2]; + { + _unit setUnitTrait [_x#0, _x#1]; + } forEach (_unit getVariable ["f_var_unitTraits",[]]); + }; // Include the loadouts for vehicles and crates: #include "f_assignGear_spetsnaz_v.sqf"; diff --git a/f/assignGear/f_assignGear_syndikat_standard.sqf b/f/assignGear/f_assignGear_syndikat_standard.sqf index c6f5ccfe..b41a6809 100644 --- a/f/assignGear/f_assignGear_syndikat_standard.sqf +++ b/f/assignGear/f_assignGear_syndikat_standard.sqf @@ -588,6 +588,19 @@ switch (_typeofUnit) do _unit addmagazines [_glriflemag_tr, 2]; _unit addmagazines [_glmag, 5]; }; +// Respawn Loadout: + case "respawn": + { + _unit addmagazines [_riflemag, 1]; + _unit addweapon _rifle; + _unit addmagazines [_smokegrenade, 3]; + _unit addmagazines [_riflemag, 2]; + _unit addmagazines [_riflemag_tr, 1]; + _unit addmagazines [_grenade, 2]; + { + _unit setUnitTrait [_x#0, _x#1]; + } forEach (_unit getVariable ["f_var_unitTraits",[]]); + }; // Include the loadouts for vehicles and crates: #include "f_assignGear_syndikat_v.sqf"; diff --git a/f/assignGear/fn_assignGear.sqf b/f/assignGear/fn_assignGear.sqf index 430b1d1a..77e411b7 100644 --- a/f/assignGear/fn_assignGear.sqf +++ b/f/assignGear/fn_assignGear.sqf @@ -7,7 +7,9 @@ // The following interprets what has been passed to this script params[ ["_typeofUnit", "", [""]], - ["_unit", objNull, [objNull]] + ["_unit", objNull, [objNull]], + ["_faction", ""], + ["_isRespawn",false] ]; private _isMan = _unit isKindOf "CAManBase"; // We check if we're dealing with a soldier or a vehicle _typeofUnit = toLower _typeofUnit; // Tidy input for SWITCH/CASE statements, expecting something like : r = Rifleman, co = Commanding Officer, rat = Rifleman (AT) @@ -18,8 +20,9 @@ _typeofUnit = toLower _typeofUnit; // Tidy input for SWITCH/CASE statements, exp // The following code detects what faction the unit's slot belongs to, and stores // it in the private variable _faction. It can also be passed as an optional parameter. -private _faction = toLower (param[2, ([_unit] call f_fnc_virtualFaction)]); - +if (_faction == "") then { + _faction = toLower ([_unit] call f_fnc_virtualFaction); +}; // ==================================================================================== // INSIGNIA @@ -38,7 +41,7 @@ _insignia_styles = [_insignia_style_NATO,_insignia_style_CSAT]; // ==================================================================================== // Universal: assign EOD flags to engineer classes -if (_typeofUnit in ["eng","engm"]) then { +if ((_typeofUnit in ["eng","engm"]) or (_isRespawn && {(_unit getVariable ["f_var_eodFlagAction",-1]) > -1})) then { [_unit] call f_fnc_assignEODflags; }; @@ -56,6 +59,7 @@ if !(local _unit) exitWith {}; // A public variable is set on the unit, indicating their type. This is mostly relevant for the FA3 respawn component _unit setVariable ["f_var_assignGear",_typeofUnit,true]; +_unit setVariable ["f_var_assignGearFaction",_faction,true]; // ==================================================================================== @@ -283,7 +287,6 @@ if (_isMan) then { // This variable simply tracks the progress of the gear assignation process, for other // scripts to reference. - _unit setVariable ["f_var_assignGear_done",true,true]; // ==================================================================================== @@ -299,4 +302,4 @@ if (isNil "_carbine") then { //_carbine should exist unless no faction has been }; }; -// ==================================================================================== +// ==================================================================================== \ No newline at end of file diff --git a/f/casualtiesCap/f_CasualtiesCapCheck.sqf b/f/casualtiesCap/f_CasualtiesCapCheck.sqf index 4e9ee63c..4ce4c739 100644 --- a/f/casualtiesCap/f_CasualtiesCapCheck.sqf +++ b/f/casualtiesCap/f_CasualtiesCapCheck.sqf @@ -18,7 +18,7 @@ sleep 0.1; // DECLARE PRIVATE VARIABLES -private ["_grps", "_side", "_factionsOnly", "_countAliveUnits", "_started", "_remaining"]; +private ["_grps", "_side", "_factionsOnly", "_countAliveUnits", "_started", "_remaining", "_ticketsRemaining", "_respawn_tickets"]; // ==================================================================================== @@ -33,11 +33,11 @@ private ["_grps", "_side", "_factionsOnly", "_countAliveUnits", "_started", "_re // 4: = If in side mode, only units from these faction(s) will be included (e.g. ["blu_f"]) params [ - ["_sideorgrps", sideUnknown, [sideUnknown,[]]], - ["_pc", 100, [0]], - ["_end", 1, [0,{}]], - ["_onlyPlayable", true, [true]], - ["_factions",[], [[]]] + ["_sideorgrps", sideUnknown, [sideUnknown,[]]], + ["_pc", 100, [0]], + ["_end", 1, [0,{}]], + ["_onlyPlayable", true, [true]], + ["_factions",[], [[]]] ]; // ==================================================================================== @@ -47,77 +47,96 @@ params [ if(_sideorgrps isEqualType sideUnknown) then { - // SIDE MODE + // SIDE MODE - _side = _sideorgrps; + _side = _sideorgrps; _factionsOnly = count _factions > 0; _countAliveUnits = { - // switchableUnits is to support SP; there playableUnits is empty - // Conversely swichableUnits is empty in MP on the DS. So, one of these will always be empty - private _eligibleUnits = if(_onlyPlayable) then {(playableUnits + switchableUnits)} else {allUnits}; + // switchableUnits is to support SP; there playableUnits is empty + // Conversely swichableUnits is empty in MP on the DS. So, one of these will always be empty + private _eligibleUnits = if(_onlyPlayable) then {(playableUnits + switchableUnits)} else {allUnits}; private _filteredUnits = if(_factionsOnly) then { - _eligibleUnits select {(side _x == _side) && (([_x] call f_fnc_virtualFaction) in _factions)}; + _eligibleUnits select {(side _x == _side) && (([_x] call f_fnc_virtualFaction) in _factions)}; } else { - _eligibleUnits select {side _x == _side}; + _eligibleUnits select {side _x == _side}; }; {alive _x} count _filteredUnits; }; + _ticketsRemaining = { + [_side] call BIS_fnc_respawnTickets; + }; - // DEBUG - if (f_param_debugMode == 1) then - { - systemChat format ["DEBUG (f\casualtiesCap\f_CasualtiesCapCheck.sqf): CasCap operating in SIDE mode. _side = %1, _onlyPlayable = %2, _factionsOnly = %3, _factions = %4",_side,_onlyPlayable,_factionsOnly,_factions]; - }; + // DEBUG + if (f_param_debugMode == 1) then + { + systemChat format ["DEBUG (f\casualtiesCap\f_CasualtiesCapCheck.sqf): CasCap operating in SIDE mode. _side = %1, _onlyPlayable = %2, _factionsOnly = %3, _factions = %4",_side,_onlyPlayable,_factionsOnly,_factions]; + }; } else { - // GROUP MODE + // GROUP MODE // COLLECT GROUPS TO CHECK // If a groups variable was passed we collect all relevant groups - _grps = []; - - sleep 1; - { - private _Tgrp = call compile format ["%1",_x]; - if(!isNil "_Tgrp") then - { - _grps pushBackUnique _Tgrp; - }; - } forEach _sideorgrps; + _grps = []; + + sleep 1; + { + private _Tgrp = call compile format ["%1",_x]; + if(!isNil "_Tgrp") then + { + _grps pushBackUnique _Tgrp; + }; + } forEach _sideorgrps; // FAULT CHECK - // Check if any groups were found. If not, exit with an error message + // Check if any groups were found. If not, exit with an error message - if (count _grps == 0) exitWith { - systemChat format ["DEBUG (f\casualtiesCap\f_CasualtiesCapCheck.sqf): No groups found, _sideorgrps = %1, _grps = %2",_sideorgrps,_grps]; - }; + if (count _grps == 0) exitWith { + systemChat format ["DEBUG (f\casualtiesCap\f_CasualtiesCapCheck.sqf): No groups found, _sideorgrps = %1, _grps = %2",_sideorgrps,_grps]; + }; - _countAliveUnits = { - {alive _x} count (flatten (_grps apply {units _x})); - }; + _countAliveUnits = { + {alive _x} count (flatten (_grps apply {units _x})); + }; + + _ticketsRemaining = { + // check if tickets exist for the group itself or the group's side. + _tickets_remaining = 0; + { + private _tickets_check = [_x] call BIS_fnc_respawnTickets; // update ticket count if group has tickets applied; + if (_tickets_check > 0) then { + _tickets_remaining = _tickets_check; + }; + private _tickets_check = [side _x] call BIS_fnc_respawnTickets; // update ticket count if group's side has tickets applied; + if (_tickets_check > 0) then { + _tickets_remaining = _tickets_check; + }; + } foreach _grps; + _tickets_remaining // return some number of tickets if at least one group or side has > 0 tickets + }; // DEBUG - if (f_param_debugMode == 1) then - { - systemChat format ["DEBUG (f\casualtiesCap\f_CasualtiesCapCheck.sqf): CasCap operating in GROUP mode. _grps = %1",_grps]; - }; + if (f_param_debugMode == 1) then + { + systemChat format ["DEBUG (f\casualtiesCap\f_CasualtiesCapCheck.sqf): CasCap operating in GROUP mode. _grps = %1",_grps]; + }; }; // ==================================================================================== // CREATE STARTING VALUES // A initial count is made of units in the groups listed in _grps. -_started = [] call _countAliveUnits; +_started = call _countAliveUnits; // DEBUG if (f_param_debugMode == 1) then { - systemChat format ["DEBUG (f\casualtiesCap\f_CasualtiesCapCheck.sqf): _started = %1",_started]; + systemChat format ["DEBUG (f\casualtiesCap\f_CasualtiesCapCheck.sqf): _started = %1",_started]; }; // ==================================================================================== @@ -129,18 +148,19 @@ if (f_param_debugMode == 1) then while {true} do { - // Call the local function to determine how many units are still alive - _remaining = [] call _countAliveUnits; + // Call the local function to determine how many units are still alive + _remaining = call _countAliveUnits; + _respawn_tickets = call _ticketsRemaining; - // DEBUG - if (f_param_debugMode == 1) then - { - systemChat format ["DEBUG (f\casualtiesCap\f_CasualtiesCapCheck.sqf): _remaining = %1",_remaining]; - }; + // DEBUG + if (f_param_debugMode == 1) then + { + systemChat format ["DEBUG (f\casualtiesCap\f_CasualtiesCapCheck.sqf): _remaining = %1",_remaining]; + }; - if (_remaining == 0 || ((_started - _remaining) / _started) >= (_pc / 100)) exitWith {}; + if (_respawn_tickets <= 0 && {_remaining == 0 || ((_started - _remaining) / _started) >= (_pc / 100)}) exitWith {}; - sleep 6; + sleep 6; }; // ==================================================================================== @@ -149,11 +169,11 @@ while {true} do // Depending on input, either MPEnd or the parsed code itself is called if (_end isEqualType 0) exitWith { - [_end] call f_fnc_mpEnd; + [_end] call f_fnc_mpEnd; }; if (_end isEqualType {}) exitWith { - _end remoteExec ["bis_fnc_spawn", 0]; + _end remoteExec ["bis_fnc_spawn", 0]; }; systemChat format ["DEBUG (f\casualtiesCap\f_CasualtiesCapCheck.sqf): Ending didn't fire, should either be code or scalar. _end = %1, typeName _end: %2",_end,typeName _end]; diff --git a/f/functions.hpp b/f/functions.hpp index c1e5e2fd..3feab4de 100644 --- a/f/functions.hpp +++ b/f/functions.hpp @@ -83,6 +83,17 @@ class F // Defines the "owner" class mapClickTeleportRemoveAction{}; class mapClickTeleportBriefing{}; }; + class respawn + { + file = "f\respawn"; + class respawn{}; + class respawnBriefing{}; + class respawnBeaconAction{}; + class respawnBeaconDeploy{}; + class respawnBeaconTeleport{}; + class respawnKilled{}; + class respawnTerminalAction{}; + }; class nametag { file = "f\nametag\functions"; diff --git a/f/medical/fn_famAddHealAction.sqf b/f/medical/fn_famAddHealAction.sqf index 548ad418..bf10d087 100644 --- a/f/medical/fn_famAddHealAction.sqf +++ b/f/medical/fn_famAddHealAction.sqf @@ -11,52 +11,14 @@ if (_unit == player) exitWith {}; // Variables to streamline balancing/updates private _healIcon = "a3\ui_f\data\igui\cfg\holdactions\holdaction_revive_ca.paa"; //Icon to Display private _healProg = "(_target distance _caller < 3) && {alive _target && !(_target getVariable ['f_var_fam_conscious',true])}"; // This one is always the same, start condition varies by unit type. -private _healTime = 6; // Action Duration -private _healMedicTime = 4.5; // Action Duration +private _healTime = 14; // Action Duration +private _healMedicTime = 8.5; // Action Duration // Starting Code private _healCodeStart = { // this is needed to protect against BI bugs that remove all actions. _caller setVariable ["f_var_fam_flag",true]; - - // Match medic animation speed to speed modifier. - if (_caller getUnitTrait 'medic') then { - _caller setAnimSpeedCoef 1.25; - }; - - if (stance _caller == "PRONE") then { - // Rifle or Binocular - if ((currentWeapon _caller == binocular _caller) || (currentWeapon _caller == primaryWeapon _caller && {primaryWeapon _caller != ""})) exitWith { - _caller playMove "ainvppnemstpslaywrfldnon_medicother"; - }; - // Nothing - if (currentWeapon _caller == "") exitWith { - _caller playMove "ainvppnemstpslaywnondnon_medicother"; - }; - // Pistol - if (currentWeapon _caller == handgunWeapon _caller && {primaryWeapon _caller != ""}) exitWith { - _caller playMove "ainvppnemstpslaywpstdnon_medicother"; - }; - } else { - // Rifle or Binocular - if ((currentWeapon _caller == binocular _caller) || (currentWeapon _caller == primaryWeapon _caller && {primaryWeapon _caller != ""})) exitWith { - _caller playMove "ainvpknlmstpslaywrfldnon_medicother"; - }; - // Nothing - if (currentWeapon _caller == "") exitWith { - _caller playMove "ainvpknlmstpslaywnondnon_medicother"; - }; - // Launcher - if (currentWeapon _caller == secondaryWeapon _caller && {primaryWeapon _caller != ""}) exitWith { - _caller playMove "ainvpknlmstpslaywlnrdnon_medicother"; - }; - // Pistol - if (currentWeapon _caller == handgunWeapon _caller && {primaryWeapon _caller != ""}) exitWith { - _caller playMove "ainvpknlmstpslaywpstdnon_medicother"; - }; - }; - // Let the wounded know someone is trying to save them. - if !(_target getVariable ['f_var_fam_conscious',true]) then {[["Someone is helping you", "PLAIN"]] remoteExec ["titleText",_target];}; // TODO Test? + _caller playAction "medicStart"; }; // Progress Code @@ -66,6 +28,7 @@ private _healCodeProg = {}; private _healCodeComp = { // this is needed to protect against BI bugs that remove all actions. _caller setVariable ["f_var_fam_flag",false]; + _caller playAction "medicStop"; // Medic heals to full only if they have a medikit. TODO CLS Support? if (_caller getUnitTrait 'Medic' && (_caller call f_fnc_famHasFAK >= 1)) then { @@ -88,13 +51,7 @@ private _healCodeComp = { private _healCodeInt = { // this is needed to protect against BI bugs that remove all actions. _caller setVariable ["f_var_fam_flag",false]; - - // Exit animation - if (animationState _caller find "ppne" != -1) then { - _caller switchMove "AinvPpneMstpSlayWnonDnon_medicOut"; - } else { - _caller switchMove "AinvPknlMstpSlayWnonDnon_medicOut"; - }; + _caller playAction "medicStop"; }; // ==================================================================================== diff --git a/f/medical/fn_famDamageHandler.sqf b/f/medical/fn_famDamageHandler.sqf index a94de9ba..44d8fc6a 100644 --- a/f/medical/fn_famDamageHandler.sqf +++ b/f/medical/fn_famDamageHandler.sqf @@ -59,6 +59,16 @@ if (vehicle _unit isKindof "Air" && {driver vehicle _unit == _unit}) then { }; _newDamage = _currentDamage + _newHit; +// Prevent outright death +if (_newDamage > 0.95) then { + if !(_unit getVariable ["f_var_fam_conscious",true]) then { + _newDamage = _currentDamage + (_newHit min 0.005); + } else { + _newDamage = 0.95; + }; + _unit setVariable ["f_var_fam_forcedown",true]; + _unit setVariable ["f_var_fam_forcedownparams",[_source,_selection,_projectile]]; +}; // Down you on a big hit. if (_selection != "" && {!(_selection in ["hands","arms"]) && {_hitSize > 2 || {_hitSize > 1 && random 2 > 1}}}) then { diff --git a/f/medical/fn_famEH.sqf b/f/medical/fn_famEH.sqf index 7014fc7a..27200ab8 100644 --- a/f/medical/fn_famEH.sqf +++ b/f/medical/fn_famEH.sqf @@ -6,7 +6,7 @@ params ["_unit"]; // ==================================================================================== // When they die -_ehKilled = _unit addEventHandler ["Killed", { +private _ehKilled = _unit addEventHandler ["Killed", { params ["_unit"]; // EXIT // This occurs after death, make sure that none of the wounded affects carry over. @@ -27,12 +27,14 @@ _ehKilled = _unit addEventHandler ["Killed", { // store name on corpse for future diagnosis. _unit setVariable ["f_var_fam_corpse",name _unit,true]; + _unit setVariable ["f_var_fam_bleed",false,true]; + _unit setVariable ["f_var_fam_conscious",true,true]; }]; // ==================================================================================== // Treatment Feedback -_ehHeal = _unit addEventHandler ["HandleHeal", { +private _ehHeal = _unit addEventHandler ["HandleHeal", { // notification correction for self FAK usage. params ["_injured", "_healer"]; @@ -56,10 +58,20 @@ _ehHeal = _unit addEventHandler ["HandleHeal", { }]; +// ==================================================================================== +// Respawn handling +private _ehRespawn = _unit addEventHandler ["Respawn", { + params ["_unit"]; + if !(local _unit) exitWith {}; + if !(_unit isKindOf "VirtualMan_F") then { + _unit setVariable ["f_var_fam_actionsAdded",false,true]; + [_unit] remoteExec ["f_fnc_famAddAllActions", 0, ("f_jip_famAddAllActions" + netId _unit)]; + }; +}]; // ==================================================================================== waitUntil {sleep 0.1; f_param_mission_timer <= 0}; // need to wait until post safeStart for this. // Handle Damage _ehDamage = _unit addEventHandler ["HandleDamage",{_this call f_fnc_famDamageHandler;}]; -_unit setVariable ["f_var_fam_allEHs",[_ehDamage,_ehKilled,_ehHeal]]; \ No newline at end of file +_unit setVariable ["f_var_fam_allEHs",[_ehDamage,_ehKilled,_ehHeal,_ehRespawn]]; \ No newline at end of file diff --git a/f/medical/fn_famInit.sqf b/f/medical/fn_famInit.sqf index 15102ccd..731daeea 100644 --- a/f/medical/fn_famInit.sqf +++ b/f/medical/fn_famInit.sqf @@ -46,7 +46,9 @@ waitUntil{!isNull player && {player == player}}; if (!hasInterface) exitWith {}; if (player getVariable ["f_var_fam_initDone",false]) exitWith { - systemChat "FAM init already run!"; + if (f_param_debugMode == 1) then { + systemChat "DEBUG (fn_famInit.sqf): FAM init already run!"; + }; }; // ==================================================================================== @@ -69,7 +71,7 @@ _unit setVariable ["f_var_fam_forcedown",false]; _unit setVariable ["f_var_fam_hasfak",false]; _unit setVariable ["f_var_fam_hasbandage",false]; _unit getVariable ["f_var_fam_flag",false]; -_unit setVariable ["f_var_fam_actions",false]; +_unit setVariable ["f_var_fam_actionsAdded",false]; [_unit] spawn f_fnc_famLoop; @@ -87,7 +89,7 @@ if (count (_unit getVariable ["f_var_fam_allEHs",[]]) == 0) then { if (!(_unit getVariable ["f_var_fam_actions",false]) && {hasInterface}) then { - [_unit] remoteExec ["f_fnc_famAddAllActions", 0, ("f_jip_famAddAllActions" + (_unit call BIS_fnc_netId))]; + [_unit] remoteExec ["f_fnc_famAddAllActions", 0, ("f_jip_famAddAllActions" + netId _unit)]; _unit setVariable ["f_var_fam_actions",true,true]; }; @@ -115,4 +117,7 @@ if (isNil "f_var_fam_briefingDone") then { [] call f_fnc_famBriefing; }; -player setVariable ["f_var_fam_initDone",true,true]; \ No newline at end of file +player setVariable ["f_var_fam_initDone",true]; +if (f_param_debugMode == 1) then { + systemChat "DEBUG (fn_famInit.sqf): FAM init run on local player"; +}; \ No newline at end of file diff --git a/f/medical/fn_famLoop.sqf b/f/medical/fn_famLoop.sqf index 837b20cb..23e519aa 100644 --- a/f/medical/fn_famLoop.sqf +++ b/f/medical/fn_famLoop.sqf @@ -21,6 +21,27 @@ while {alive _unit && {local _unit}} do { }; // ==================================================================================== + // Timeout for being downed + private _knockoutTime = _unit getVariable ["f_var_fam_knockOutTime", serverTime]; + if ((serverTime - _knockOutTime) > 180) then { + if (isNull (uiNamespace getVariable ["f_var_fam_respawnDisplay",displayNull])) then { + uiNamespace setVariable ["f_var_fam_respawnDisplay",findDisplay 46 createDisplay "f_respawnUI"]; + }; + }; + // If the unit is in a dead vehicle, eject them (if vehicle is on the ground and at very low speed) or kill them (if it isn't) + if (!(isNull objectParent _unit) && {!alive objectParent _unit}) then { + sleep 3; + private _parent = objectParent _unit; + if (!(isNull _parent) && {!alive _parent}) then { + if (((getPos _parent select 2) < 5) && {(vectorMagnitude velocity _parent) < 4.2}) then { + moveOut _unit; + } else { + _unit setDamage 1; + break; + }; + }; + }; + // PASSOUT TEST // Force Unit Down above damage threshold. if (damage _unit >= 0.9 && {_unit getVariable ["f_var_fam_conscious",true]}) then { @@ -125,7 +146,7 @@ while {alive _unit && {local _unit}} do { _tick = selectRandom [0.001,0.002,0.004]; // slower rate closer to death. } else { _tick = selectRandom [0.06,0.08,0.11]; // faster rate until you are forced down. - if (_currentDamage + _tick >= 1) then {_tick = 0.01}; //careful not to overdamage you with the bleed. + if (_currentDamage + _tick >= 0.99) then {_tick = 0.01}; //careful not to overdamage you with the bleed. }; { // save current hands and legs damage. diff --git a/f/medical/fn_famPassOut.sqf b/f/medical/fn_famPassOut.sqf index 64a7214e..701f2b7b 100644 --- a/f/medical/fn_famPassOut.sqf +++ b/f/medical/fn_famPassOut.sqf @@ -112,6 +112,9 @@ if (isPlayer _unit) then { }; }; +_unit setVariable ["f_var_fam_knockOutTime", serverTime, true]; + +[_unit, "f_fam_knockOut", [_unit]] call BIS_fnc_callScriptedEventHandler; // VISUAL EFFECTS // Create a loop for the wounded visual effects. _unit spawn { diff --git a/f/medical/fn_famWakeUp.sqf b/f/medical/fn_famWakeUp.sqf index ac0b28d9..5af5c114 100644 --- a/f/medical/fn_famWakeUp.sqf +++ b/f/medical/fn_famWakeUp.sqf @@ -22,6 +22,8 @@ for "_i" from 2 to 5 do { _i enableChannel true; }; +_unit setVariable ["f_var_fam_knockOutTime",nil,true]; + // check for radio channels [_unit] spawn f_fnc_radioCheckChannels; @@ -80,6 +82,10 @@ if(local _unit) then }; }; +if (_unit == player) then { + (uiNamespace getVariable ["f_var_fam_respawnDisplay", displayNull]) closeDisplay 1; +}; + // exit if they are dead if (damage _unit >= 1) exitWith {}; // ==================================================================================== @@ -89,6 +95,8 @@ titleText ["","PLAIN"]; _unit setCaptive false; +[_unit, "f_fam_wakeUp", [_unit]] call BIS_fnc_callScriptedEventHandler; + // DELAYED RESETS _unit spawn { diff --git a/f/missionConditions/f_conditionNotes.sqf b/f/missionConditions/f_conditionNotes.sqf index 1446f413..29859219 100644 --- a/f/missionConditions/f_conditionNotes.sqf +++ b/f/missionConditions/f_conditionNotes.sqf @@ -70,5 +70,6 @@ _diaryText = _diaryText + format ["
Mo // Insert final result into briefing +waitUntil {!isNil "f_script_briefing"}; waitUntil {scriptDone f_script_briefing}; player createDiaryRecord ["diary", ["Mission Conditions", _diaryText]]; diff --git a/f/radio/fn_radioAddHandlers.sqf b/f/radio/fn_radioAddHandlers.sqf index 52825393..be4c4789 100644 --- a/f/radio/fn_radioAddHandlers.sqf +++ b/f/radio/fn_radioAddHandlers.sqf @@ -11,7 +11,7 @@ params [["_respawned",false]]; waitUntil {(!isNull player && {player == player}) && !(isNil "f_var_radioChannelsUnified")}; // Add player to the correct channels if they have a backpack -[player] spawn f_fnc_radioCheckChannels; +player spawn f_fnc_radioCheckChannels; // Now bail if they've already been handled, unless they respawned in which case they do need the actions adding if (player getVariable ["f_var_radioHandlersAdded",false] && !_respawned) exitWith {}; @@ -24,44 +24,44 @@ if _respawned exitWith {}; // Update channels if they drop a backpack player addEventHandler ["put", { - params ["_unit", "_container", "_item"]; - [_unit] spawn f_fnc_radioCheckChannels; + params ["_unit"]; + _unit spawn f_fnc_radioCheckChannels; }]; // Update channels if they take a backpack player addEventHandler ["take", { - params ["_unit", "_container", "_item"]; - [_unit] spawn f_fnc_radioCheckChannels; + params ["_unit"]; + _unit spawn f_fnc_radioCheckChannels; }]; // Update channels if they open their inventory player addEventHandler ["inventoryOpened", { - params ["_unit", "_container"]; - [_unit] spawn f_fnc_radioCheckChannels; + params ["_unit"]; + _unit spawn f_fnc_radioCheckChannels; }]; // Update channels if they close their inventory player addEventHandler ["inventoryClosed", { - params ["_unit", "_container"]; - [_unit] spawn f_fnc_radioCheckChannels; + params ["_unit"]; + _unit spawn f_fnc_radioCheckChannels; }]; // Update channels if they get in a vehicle player addEventHandler ["getInMan", { - params ["_unit", "_role", "_vehicle", "_turret"]; - [_unit] spawn f_fnc_radioCheckChannels; + params ["_unit"]; + _unit spawn f_fnc_radioCheckChannels; }]; // Update channels if they get out of a vehicle player addEventHandler ["getOutMan", { - params ["_unit", "_role", "_vehicle", "_turret"]; - [_unit] spawn f_fnc_radioCheckChannels; + params ["_unit"]; + _unit spawn f_fnc_radioCheckChannels; }]; // Update channels if they switch seats in a vehicle player addEventHandler ["seatSwitchedMan", { - params ["_unit1", "_unit2", "_vehicle"]; - [_unit1] spawn f_fnc_radioCheckChannels; + params ["_unit1"]; + _unit1 spawn f_fnc_radioCheckChannels; }]; // Add respawn protection @@ -85,7 +85,7 @@ if (isNil "f_var_radioPersistentCheck") then { [] spawn { while {f_var_radioPersistentCheck} do { sleep 10; - [player] spawn f_fnc_radioCheckChannels; + player spawn f_fnc_radioCheckChannels; }; }; }; @@ -98,4 +98,4 @@ if (f_param_debugMode == 1) then // Check again! sleep 1; -[player] spawn f_fnc_radioCheckChannels; \ No newline at end of file +player spawn f_fnc_radioCheckChannels; \ No newline at end of file diff --git a/f/radio/fn_radioCheckChannels.sqf b/f/radio/fn_radioCheckChannels.sqf index 116507cc..dfd6b82c 100644 --- a/f/radio/fn_radioCheckChannels.sqf +++ b/f/radio/fn_radioCheckChannels.sqf @@ -96,6 +96,10 @@ for "_i" from 1 to 2 do { if !(_unit getVariable ["f_var_fam_conscious",true]) then { _channelsToAddTalk = []; }; + if !(alive _unit) then { + _channelsToAddTalk = []; + _channelsToAddListen = []; + }; // Remove channels player shouldn't have access to for "_i" from 1 to f_var_radioChannelCount do { diff --git a/f/respawn/f_respawnDisplays.hpp b/f/respawn/f_respawnDisplays.hpp new file mode 100644 index 00000000..b3376e9c --- /dev/null +++ b/f/respawn/f_respawnDisplays.hpp @@ -0,0 +1,115 @@ +class f_respawnUI +{ + idd = 3680; + duration = 1e+6; + access = 0; + movingEnable = false; + enableSimulation = true; + fadeIn = 0; + fadeOut = 0; + onLoad = ""; + + class Controls + { + class f_respawnControlsGroup : RscControlsGroupNoScrollbars + { + type = CT_CONTROLS_GROUP; + idc = -1; + style = 0; + x = safeZoneX + safeZoneW * 0.39; + y = safeZoneY + safeZoneH * 0.22; + w = safeZoneW * 0.22; + h = safeZoneH * 0.1; + onLoad = ""; + class HScrollbar + { + height = 0; + width = 0; + shadow = 0; + }; + class VScrollbar + { + height = 0; + width = 0; + }; + + class Controls + { + class f_respawnBackground : RscText + { + type = CT_STATIC; + idc = 3689; + x = 0; + y = 0; + w = safeZoneW * 0.25; + h = safeZoneH * 0.095; + style = 0; + text = ""; + colorBackground[] = {0.05,0.05,0.05,0.7}; + }; + class f_respawnStatusText : RscStructuredText + { + type = CT_STRUCTURED_TEXT; + idc = 3681; + x = safeZoneW * 0.027; + y = safeZoneH * 0.032; + w = safeZoneW * 0.22; + h = safeZoneH * 0.02; + style = 0; + text = "You have been unconscious for more than 3 minutes."; + colorBackground[] = {0.8863,0.7294,0.7294,0}; + colorText[] = {1,1,0.302,1}; + font = "PuristaMedium"; + sizeEx = (((((safezoneW / safezoneH) min 1.2) / 1.2) / 25) * 1); + + }; + class f_respawnStatus2Text : RscStructuredText + { + type = CT_STRUCTURED_TEXT; + idc = 3682; + x = safeZoneW * 0.027; + y = safeZoneH * 0.057; + w = safeZoneW * 0.22; + h = safeZoneH * 0.02; + style = 0; + text = "Wait for revive or click this button to respawn."; + colorBackground[] = {0.8863,0.7294,0.7294,0}; + colorText[] = {1,1,0.302,1}; + font = "PuristaMedium"; + sizeEx = (((((safezoneW / safezoneH) min 1.2) / 1.2) / 25) * 1); + }; + class f_respawnTitleText : RscStructuredText + { + type = CT_STRUCTURED_TEXT; + idc = 3683; + x = 0; + y = 0; + w = safeZoneW * 0.22; + h = safeZoneH * 0.019; + style = 0; + text = "FA3 Respawn"; + colorBackground[] = {0.1,0.1,0.1,1}; + colorText[] = {1,1,1,1}; + font = "PuristaMedium"; + sizeEx = (((((safezoneW / safezoneH) min 1.2) / 1.2) / 25) * 1); + }; + class f_respawnButton : RscButton + { + type = CT_BUTTON; + idc = 3684; + x = safeZoneW * 0.003; + y = safeZoneH * 0.025; + w = safeZoneW * 0.02; + h = safeZoneH * 0.063; + style = 0; + text = ""; + colorBackground[] = {1,1,1,1}; + colorFocused[] = {0.98,0.51,0,1}; + colorFocused2[] = {0.98,0.51,0,1}; + colorBackGroundActive[] = {0.98,0.51,0,1}; + action = "player setDamage 1; (uiNamespace getVariable ['f_var_fam_respawnDisplay', displayNull]) closeDisplay 1;"; + }; + }; + }; + }; +}; \ No newline at end of file diff --git a/f/respawn/fn_respawn.sqf b/f/respawn/fn_respawn.sqf new file mode 100644 index 00000000..d6a17374 --- /dev/null +++ b/f/respawn/fn_respawn.sqf @@ -0,0 +1,33 @@ +// FA3 - Respawn Module - Respawn Event +// Credits and documentation: https://github.com/folkarps/F3/wiki + +/* ======================== +This function is executed from the FA3 Respawn Template in description.ext and should not be used for other purposes. +This function relies on the f_respawnBase object being present in the mission - a proxy object used to set the player's position on spawning, and to gauge when they've left the respawn base. +Example: +onPlayerRespawn = "f_fnc_respawn"; + +Arguments: as automatically passed to onPlayerRespawn.sqf +=========================== */ +params ["_newUnit", "_oldUnit"]; + +waitUntil {local _newUnit}; + +["respawn", _newUnit, _oldUnit getVariable ["f_var_assignGearFaction", toLower ([_oldUnit] call f_fnc_virtualFaction)], true] call f_fnc_assignGear; + +call f_fnc_terminateSpectator; +private _newTickets = [side group _newUnit] call BIS_fnc_respawnTickets; +private _respawnText = format ["[%1] You have respawned. %2 tickets remaining.", side group _newUnit, _newTickets]; +systemChat _respawnText; + +_newUnit assignTeam (_oldUnit getVariable ["f_var_lastTeamColour","MAIN"]); + +_newUnit allowDamage false; +_newUnit setPosASL getPosASL f_respawnBase; + +waitUntil { + sleep 2; + (_newUnit distance f_respawnBase) > 100; +}; +_newUnit allowDamage true; +_newUnit setCaptive false; \ No newline at end of file diff --git a/f/respawn/fn_respawnBeaconAction.sqf b/f/respawn/fn_respawnBeaconAction.sqf new file mode 100644 index 00000000..950a8186 --- /dev/null +++ b/f/respawn/fn_respawnBeaconAction.sqf @@ -0,0 +1,42 @@ +// FA3 - Respawn Module - Beacon Summon Action +// Credits and documentation: https://github.com/folkarps/F3/wiki + +/* ======================== +This function is executed from fn_respawnBeaconDeploy, or manually by the missionmaker. It must be executed on all machines with JIP persistence. +It adds an action to the given object, allowing it to act as an FA3 Respawn Beacon, used to summon players of your side from the respawn base. +Example: +[_object] remoteExec ["f_fnc_respawnBeaconAction",0,true]; +_object call f_fnc_respawnBeaconAction; + +Arguments: +0. Target (object) - object to add the action to +1. Radius (number) - Optional - radius for the action. Increase it for large objects as the radius is measured from object centre. Default: 3 +=========================== */ + +params ["_object",["_radius",3]]; + +private _condition = format ["(isNull objectParent _this) && {(_this distance _target) < %1}", _radius]; + +[ + _object, + "Call reinforcements to rally point", + "a3\ui_f_oldman\data\igui\cfg\holdactions\meet_ca.paa", + "a3\ui_f_oldman\data\igui\cfg\holdactions\meet_ca.paa", + _condition, + _condition, + { + private _text = format ["[%1] Searching for ready reinforcements...", str side group _caller]; + systemChat _text; + }, + {}, + { + _caller spawn f_fnc_respawnBeaconTeleport; + }, + {}, + [], + 5, + 10, + false, + false, + true +] call BIS_fnc_holdActionAdd; \ No newline at end of file diff --git a/f/respawn/fn_respawnBeaconDeploy.sqf b/f/respawn/fn_respawnBeaconDeploy.sqf new file mode 100644 index 00000000..ea14e1d8 --- /dev/null +++ b/f/respawn/fn_respawnBeaconDeploy.sqf @@ -0,0 +1,89 @@ +// FA3 - Respawn Module - Beacon Placement +// Credits and documentation: https://github.com/folkarps/F3/wiki + +/* ======================== +This function is typically executed by the FA3 Respawn Player Actions briefing tab, but it can be used in other contexts if needed. It must be executed in a scheduled environment, and should be executed only on one machine at a time. +Example: +[player] spawn f_fnc_respawnBeaconDeploy + +Arguments: +0. Unit (object) - Living unit which will place the beacon, ideally the local player. +=========================== */ + +params ["_caller"]; +// Exit if you don't meet basic conditions +if !(isNull objectParent _caller) exitWith { + systemChat "Can't place rally beacon while in a vehicle."; +}; +if !(_caller == leader _caller) exitWith { + systemChat "Only group leaders can place a rally beacon."; +}; +// Check cooldown +private _side = str side group _caller; +private _timerVarName = format ["f_var_lastRespawnBeacon_%1", _side]; +private _cooldown = serverTime - (missionNamespace getVariable [_timerVarName, serverTime - 301]); +if (_cooldown < 300) exitWith { + private _text = format ["[%1] Rally beacon on cooldown: %2", _side, [_cooldown, "MM:SS"] call BIS_fnc_secondsToString]; + systemChat _text; +}; + +_caller playActionNow "MedicOther"; +private _text = format ["[%1] %2 is deploying a rally beacon.", _side, name _caller]; +[_text] remoteExec ["systemChat"]; + +sleep 5; + +if !(alive _caller) exitWith {}; +// Check 3 possible positions +{ + // Aim about waist height + private _position = _caller modelToWorldWorld [0,1.5,0.8]; + private _positionATL = ASLtoATL _position; + private _heightATL = _positionATL select 2; + // Can't place flag below terrain + if (_heightATL < -2.5) then { continue }; + // If it's not too far below terrain, adjust up + if (_heightATL < 0.1) then { + _position = _position vectorAdd [0,0, - _heightATL]; + }; + // Determine whether a valid surface is within vertical range + private _intersects = lineIntersectsSurfaces [_position, _position vectorAdd [0,0,-2.5], _caller, objNull, true, 1, "GEOM"]; + if (count _intersects > 0) then { + private _intersection = _intersects select 0; + // Can't place on or in vehicles + if (["Air","LandVehicle","Ship"] findIf {(_intersection select 2) isKindOf _x} > -1) then { continue }; + + _position = _intersection select 0; + private _beacon = createSimpleObject ["OmniDirectionalAntenna_01_olive_F", [0,0,0]]; + [_beacon, false] remoteExec ["setPhysicsCollisionFlag",0,true]; + _beacon setPosASL _position; + + playSound3D ["A3\Sounds_F_AoW\SFX\Showcase_Future\place_flag.wss",_beacon,false,_position, 2, 1, 25]; + _beacon setVectorUp [0,0,1]; + _beacon setDir (getDir _caller - 90); + + private _smokeType = ["SmokeShellRed_Infinite", "SmokeShellBlue_Infinite", "SmokeShellGreen_Infinite", "SmokeShellPurple_Infinite", "SmokeShellYellow_Infinite","SmokeShellWhite_Infinite","SmokeShellWhite_Infinite","SmokeShellWhite_Infinite","SmokeShellWhite_Infinite","SmokeShellWhite_Infinite"] select ((side group _caller) call BIS_fnc_sideID); + private _smoke = _smokeType createVehicle [0,0,0]; + _smoke setPosASL _position; + _beacon setVariable ["f_beaconSmoke",_smoke,true]; + + private _sphere = "Sign_Sphere100cm_Geometry_F" createVehicle [0,0,0]; + _sphere setObjectTextureGlobal [0, ""]; + _sphere setPosASL (_position vectorAdd [0,0,0.5]); + [_sphere] remoteExec ["f_fnc_respawnBeaconAction",0,true]; + _beacon setVariable ["f_beaconSphere",_sphere,true]; + + // If we got this far we can skip any remaining positions + private _varName = format ["f_var_respawnBeacon_%1", _side]; + private _oldBeacon = missionNamespace getVariable [_varName, objNull]; + deleteVehicle ((attachedObjects _oldBeacon) + [_oldBeacon getVariable ["f_beaconSmoke",objNull], _oldBeacon, _oldBeacon getVariable ["f_beaconSphere",objNull]]); + missionNamespace setVariable [_varName, _beacon, true]; + break; + }; +} forEach [[0,1.5,0.8],[0,0.75,0.8],[0,0.1,0.1]]; + +// Cooldown marker +missionNamespace setVariable [_timerVarName, serverTime, true]; + +private _text = format ["[%1] %2 deployed a rally beacon.", _side, name _caller]; +[_text] remoteExec ["systemChat"]; \ No newline at end of file diff --git a/f/respawn/fn_respawnBeaconTeleport.sqf b/f/respawn/fn_respawnBeaconTeleport.sqf new file mode 100644 index 00000000..62c6b07a --- /dev/null +++ b/f/respawn/fn_respawnBeaconTeleport.sqf @@ -0,0 +1,55 @@ +// FA3 - Respawn Module - Teleport +// Credits and documentation: https://github.com/folkarps/F3/wiki + +/* ======================== +This function handles teleporting a unit to their side's FA3 Respawn Beacon or deployment vehicle. +Example: +[player] call f_fnc_respawnTeleport + +If using a deployment vehicle, you must have a vehicle with name f_var_respawnBeacon_west (_east, _guer, etc) for your players force. + +Arguments: +0. Unit (object) - Living unit which will be teleported. +=========================== */ +params ["_caller"]; + +private _sideString = str side group _caller; + +private _varName = format ["f_var_respawnBeacon_%1", _sideString]; +private _respawnBeacon = missionNamespace getVariable [_varname, objNull]; + +if (isNull _respawnBeacon) exitWith { + systemChat format ["[%1] No available rally point for your side.", _sideString]; +}; + +private _readyUnits = (playableUnits + switchableUnits) select {(side group _x == side group _caller) && {(_x distance f_respawnTerminal) < 100}}; +if (count _readyUnits < 1) exitWith { + systemChat format ["[%1] No available reinforcements for your side.", _sideString]; +}; + +if (typeOf _respawnBeacon == "OmniDirectionalAntenna_01_olive_F") exitWith { + { + private _text = format ["[%1] %2 is deploying to the rally point.", _sideString, name _x]; + [_text] remoteExec ["systemChat"]; + private _randomNumber = random [0.5, 1, 1.5]; + private _pos = (getPosASL _respawnBeacon) vectorAdd [_randomNumber, random [-1, 0, 1], 0]; + _x setPosASL _pos; + } forEach _readyUnits; +}; + +if (_respawnBeacon isKindOf "AllVehicles") exitWith { + if (!alive _respawnBeacon) exitWith { + systemChat "Rally point vehicle has been destroyed! Please wait for a new deployment point."; + }; + { + if (_respawnBeacon emptyPositions "Cargo" >= 1) then { + private _text = format ["[%1] %2 is deploying to the rally point vehicle.", _sideString, name _x]; + [_text] remoteExec ["systemChat"]; + [_x,_respawnBeacon] remoteExec ["moveInCargo"]; + } else { + breakWith { systemChat "Rally point vehicle has no available cargo seats, please try again." }; + }; + sleep 0.3; + } forEach _readyUnits; +}; + diff --git a/f/respawn/fn_respawnBriefing.sqf b/f/respawn/fn_respawnBriefing.sqf new file mode 100644 index 00000000..765a86a1 --- /dev/null +++ b/f/respawn/fn_respawnBriefing.sqf @@ -0,0 +1,49 @@ +// FA3 - Respawn Module - Briefing +// Credits and documentation: https://github.com/folkarps/F3/wiki + +/* ======================== +This module is activated in init.sqf. +Example: +0 spawn f_fnc_respawnBriefing + +Arguments: +0. mode: 0 - deployable beacons, 1 - teleport to vehicle, 2 - respawn and wait for pickup +=========================== */ +if !(hasInterface) exitWith {}; +if !(isNil "f_var_respawn_briefingDone") exitWith{}; + +params ["_respawnMode"]; + +waitUntil {scriptDone f_script_briefing}; +_str_deploy = "to be deployed to your side's deployment vehicle."; + +if (_respawnMode == 0) then { + player createDiaryRecord ["fa3_actions",["FA3 Rally Point"," +
+The FA3 Respawn system allows team leaders to deploy a rally point for their side. You can use this rally point to summon respawning players. +

+Placing this rally point will remove any previously-placed rally point for your side. You can only place this rally point if you are the leader of your group. There is a 5-minute cooldown after placing a beacon before another beacon for that side can be placed. +

+Place rally point" + ]]; + _str_deploy = "to be deployed to your side's rally point.

Group leaders can place their side's rally point from the FA3 Player Actions briefing menu."; +}; + +if (_respawnMode == 2) then { + _str_deploy = "for pickup by an allied transport."; +}; + +waitUntil {!isNil "f_script_loadoutNotes"}; +waitUntil {scriptDone f_script_loadoutNotes}; + +player createDiaryRecord ["diary", ["FA3 Respawn",format [" +
+If you have been unconscious for 3 minutes straight, you will have the option to respawn. After a brief timeout, you will respawn at a neutral base location. +

+At the base, you will have access to a terminal, which you can use to spectate your team, while you wait %2 +

+Your side has %1 respawn tickets at mission start. +",f_param_respawnTickets,_str_deploy]]]; + +// Set a variable so this won't be generated again by subsequent inits +f_var_respawn_briefingDone = true; \ No newline at end of file diff --git a/f/respawn/fn_respawnKilled.sqf b/f/respawn/fn_respawnKilled.sqf new file mode 100644 index 00000000..e05425aa --- /dev/null +++ b/f/respawn/fn_respawnKilled.sqf @@ -0,0 +1,17 @@ +// FA3 - Respawn Module - Player Killed Event +// Credits and documentation: https://github.com/folkarps/F3/wiki + +/* ======================== +This function is executed from the FA3 Respawn Template in description.ext and should not be used for other purposes. +Example: +onPlayerKilled = "f_fnc_respawnKilled"; + +Arguments: as automatically passed to onPlayerKilled.sqf +=========================== */ + +private _unit = _this#0; +_unit setVariable ["f_var_lastTeamColour",assignedTeam _unit,true]; +_unit setVariable ["f_var_unitTraits", getAllUnitTraits _unit, true]; +_unit spawn f_fnc_radioCheckChannels; +sleep 3; +_this spawn f_fnc_activateSpectator; \ No newline at end of file diff --git a/f/respawn/fn_respawnTerminalAction.sqf b/f/respawn/fn_respawnTerminalAction.sqf new file mode 100644 index 00000000..918cd83b --- /dev/null +++ b/f/respawn/fn_respawnTerminalAction.sqf @@ -0,0 +1,55 @@ +// FA3 - Respawn Module - Terminal Action +// Credits and documentation: https://github.com/folkarps/F3/wiki + +/* ======================== +This function is executed from init.sqf. +Two objects must be defined as global variables in the mission for this function to operate: f_respawnTerminal, an object which players can interact with to teleport and spectate; and f_respawnBase, a proxy object which is used as their spawn position upon respawning. +Example: +0 spawn f_fnc_terminalAction + +Arguments: +None +=========================== */ +if (isNil "f_respawnTerminal") exitWith { + systemChat "FA3 Respawn: Critical: Respawn Terminal object is not present or not correctly named f_respawnTerminal."; +}; +if (isNil "f_respawnBase") exitWith { + systemChat "FA3 Respawn: Critical: Respawn Base object is not present or not correctly named f_respawnBase."; +}; + +[ + f_respawnTerminal, + "Spectate your team", + "a3\ui_f\data\igui\cfg\holdactions\holdaction_search_ca.paa", + "a3\ui_f\data\igui\cfg\holdactions\holdaction_search_ca.paa", + "isNull objectParent _this", + "isNull objectParent _this", + { + private _text = format ["[%1] Launching side spectator. Press ESC to exit spectator.", str side group _caller]; + systemChat _text; + }, + {}, + { + _caller spawn { + private _text = format ["[%1] Launched side spectator. Press ESC to exit spectator. Select units in the left panel to spectate.", str side group _this]; + systemChat _text; + call f_fnc_activateSpectator; + waitUntil { !isNull findDisplay 60492 }; + (findDisplay 60492) displayAddEventHandler ["keyDown",{ + params ["", "_key"]; + if (_key == 1) then { + (findDisplay 60492) displayRemoveEventHandler [_thisEvent,_thisEventHandler]; + call f_fnc_terminateSpectator; + true; + }; + }]; + }; + }, + {}, + [], + 2, + 0, + false, + false, + true +] call BIS_fnc_holdActionAdd; \ No newline at end of file diff --git a/f/spect/fn_activateSpectator.sqf b/f/spect/fn_activateSpectator.sqf index d64b86d5..865fcac5 100644 --- a/f/spect/fn_activateSpectator.sqf +++ b/f/spect/fn_activateSpectator.sqf @@ -1,23 +1,30 @@ // FA3 - Spectator component if (f_param_debugMode == 1) then { - diag_log "activating spectator"; + diag_log "FA3 Spectator: activating spectator"; }; -// 'Cinematic' delay before spectator activates -sleep 3; +params ["","","","",["_isFullSpectator",false]]; // Disable post-processing effects // Borrowed from BIS_fnc_respawnSpectator - waitUntil {missionnamespace getvariable ["BIS_fnc_feedback_allowDeathScreen", true]}; -BIS_fnc_feedback_allowPP = false; +if ((0 call BIS_fnc_missionRespawnType) == 1) then { + waitUntil {missionnamespace getvariable ["BIS_fnc_feedback_allowDeathScreen", true]}; + BIS_fnc_feedback_allowPP = false; +}; -// Create a new (alive) unit to prevent draw3D bug with floating head tags -// Credit to SilentSpike: https://github.com/acemod/ACE3/pull/5868 -private _cameraUnit = (createGroup sideLogic) createUnit ["VirtualMan_F", player, [], 0, "NONE"]; -_cameraUnit enableSimulation false; -selectPlayer _cameraUnit; +if (_isFullSpectator or (!(alive player) && ([side group player] call BIS_fnc_respawnTickets) < 1)) then { + // Create a new (alive) unit to prevent draw3D bug with floating head tags + // Credit to SilentSpike: https://github.com/acemod/ACE3/pull/5868 + private _cameraUnit = (createGroup sideLogic) createUnit ["VirtualMan_F", player, [], 0, "NONE"]; + _cameraUnit enableSimulation false; + selectPlayer _cameraUnit; -["Initialize", [player, [], true, true, true, false, true, true, true, true]] call BIS_fnc_EGSpectator; + ["Initialize", [player, [], true, true, true, false, true, true, true, true]] call BIS_fnc_EGSpectator; + +} else { + ["Initialize", [player, [side group player], false, false, false, false, false, true, true, true]] call BIS_fnc_EGSpectator; + +}; // Disable direct chat to prevent ghosts interacting with the living 5 enableChannel false; \ No newline at end of file diff --git a/init.sqf b/init.sqf index d7301774..a7f9324d 100644 --- a/init.sqf +++ b/init.sqf @@ -172,6 +172,18 @@ f_var_viewDistance_crewOnly = true; // ==================================================================================== +// FA3 - Respawn +// Credits and documentation: https://github.com/folkarps/F3/wiki +if isServer then { + { + [_x, f_param_respawnTickets] call BIS_fnc_respawnTickets; + } forEach [east, west, independent, civilian]; +}; +0 spawn f_fnc_respawnBriefing; // 0 - deployable beacons, 1 - teleport to vehicle, 2 - wait for pickup +0 spawn f_fnc_respawnTerminalAction; + +// ==================================================================================== + // FA3 - Skulls // Credits and documentation: https://github.com/folkarps/F3/wiki