Add defend wave templates and standardize task endings
- Let defend tasks use synced enemy groups as wave templates - Record task status changes on fail/success - Route end conditions through the server-side mission end helper
This commit is contained in:
parent
9be7f91e2f
commit
e6eceac4ec
@ -375,13 +375,13 @@ class CfgVehicles {
|
|||||||
};
|
};
|
||||||
|
|
||||||
class ModuleDescription: ModuleDescription {
|
class ModuleDescription: ModuleDescription {
|
||||||
description = "Creates a defend task with configurable defense zone and enemy wave parameters";
|
description = "Creates a defend task with configurable defense zone and designer-controlled enemy wave templates";
|
||||||
sync[] = { "Anything" };
|
sync[] = { "AnyBrain" };
|
||||||
|
|
||||||
class Anything {
|
class AnyBrain {
|
||||||
description[] = {
|
description[] = {
|
||||||
"Defend task module",
|
"Defend task module",
|
||||||
"Enemy waves are spawned automatically; no synced entities are required"
|
"Sync with enemy units or group members to use their groups as wave templates"
|
||||||
};
|
};
|
||||||
position = 1;
|
position = 1;
|
||||||
direction = 1;
|
direction = 1;
|
||||||
|
|||||||
@ -143,7 +143,8 @@ Available task modules:
|
|||||||
- `FORGE_Module_Hostage`: sync to `FORGE_Module_Hostages` and
|
- `FORGE_Module_Hostage`: sync to `FORGE_Module_Hostages` and
|
||||||
`FORGE_Module_Shooters`
|
`FORGE_Module_Shooters`
|
||||||
- `FORGE_Module_HVT`: sync directly to HVT units
|
- `FORGE_Module_HVT`: sync directly to HVT units
|
||||||
- `FORGE_Module_Defend`: configure the defense marker and wave settings
|
- `FORGE_Module_Defend`: configure the defense marker and wave settings; sync
|
||||||
|
enemy units to use their groups as wave templates
|
||||||
|
|
||||||
These modules delegate to `fnc_startTask.sqf`.
|
These modules delegate to `fnc_startTask.sqf`.
|
||||||
|
|
||||||
|
|||||||
@ -119,7 +119,7 @@ if (_result == 1) then {
|
|||||||
GVAR(TaskStore) call ["applyRatingOutcome", [_taskID, _ratingFail]];
|
GVAR(TaskStore) call ["applyRatingOutcome", [_taskID, _ratingFail]];
|
||||||
GVAR(TaskStore) call ["clearTask", [_taskID]];
|
GVAR(TaskStore) call ["clearTask", [_taskID]];
|
||||||
|
|
||||||
if (_endFail) then { ["MissionFail", false] remoteExecCall ["BIS_fnc_endMission", playerSide]; };
|
if (_endFail) then { "EveryoneLost" call BFUNC(endMissionServer); };
|
||||||
} else {
|
} else {
|
||||||
["INFO", format [
|
["INFO", format [
|
||||||
"Attack task %1 succeeded. TargetsRequired=%2, TargetsKilled=%3",
|
"Attack task %1 succeeded. TargetsRequired=%2, TargetsKilled=%3",
|
||||||
@ -149,5 +149,5 @@ if (_result == 1) then {
|
|||||||
GVAR(TaskStore) call ["applyRatingOutcome", [_taskID, _ratingSuccess]];
|
GVAR(TaskStore) call ["applyRatingOutcome", [_taskID, _ratingSuccess]];
|
||||||
GVAR(TaskStore) call ["clearTask", [_taskID]];
|
GVAR(TaskStore) call ["clearTask", [_taskID]];
|
||||||
|
|
||||||
if (_endSuccess) then { ["MissionSuccess", true] remoteExecCall ["BIS_fnc_endMission", playerSide]; };
|
if (_endSuccess) then { "EveryoneWon" call BFUNC(endMissionServer); };
|
||||||
};
|
};
|
||||||
|
|||||||
@ -16,11 +16,12 @@
|
|||||||
* 8: Enemy wave count <NUMBER> (default: 3)
|
* 8: Enemy wave count <NUMBER> (default: 3)
|
||||||
* 9: Time between waves in seconds <NUMBER> (default: 300)
|
* 9: Time between waves in seconds <NUMBER> (default: 300)
|
||||||
* 10: Minimum BLUFOR units required in zone <NUMBER> (default: 1)
|
* 10: Minimum BLUFOR units required in zone <NUMBER> (default: 1)
|
||||||
* 11: Equipment rewards <ARRAY> (default: [])
|
* 11: Enemy template groups <ARRAY> (default: [])
|
||||||
* 12: Supply rewards <ARRAY> (default: [])
|
* 12: Equipment rewards <ARRAY> (default: [])
|
||||||
* 13: Weapon rewards <ARRAY> (default: [])
|
* 13: Supply rewards <ARRAY> (default: [])
|
||||||
* 14: Vehicle rewards <ARRAY> (default: [])
|
* 14: Weapon rewards <ARRAY> (default: [])
|
||||||
* 15: Special rewards <ARRAY> (default: [])
|
* 15: Vehicle rewards <ARRAY> (default: [])
|
||||||
|
* 16: Special rewards <ARRAY> (default: [])
|
||||||
*
|
*
|
||||||
* Return Value:
|
* Return Value:
|
||||||
* None
|
* None
|
||||||
@ -43,6 +44,7 @@ params [
|
|||||||
["_waveCount", 3, [0]],
|
["_waveCount", 3, [0]],
|
||||||
["_waveCooldown", 300, [0]],
|
["_waveCooldown", 300, [0]],
|
||||||
["_minBlufor", 1, [0]],
|
["_minBlufor", 1, [0]],
|
||||||
|
["_enemyTemplates", [], [[]]],
|
||||||
["_equipmentRewards", [], [[]]],
|
["_equipmentRewards", [], [[]]],
|
||||||
["_supplyRewards", [], [[]]],
|
["_supplyRewards", [], [[]]],
|
||||||
["_weaponRewards", [], [[]]],
|
["_weaponRewards", [], [[]]],
|
||||||
@ -104,7 +106,7 @@ waitUntil {
|
|||||||
};
|
};
|
||||||
|
|
||||||
if (_currentWave < _waveCount && _defenseStarted && { time >= _nextWaveTime }) then {
|
if (_currentWave < _waveCount && _defenseStarted && { time >= _nextWaveTime }) then {
|
||||||
[_defenseZone, _taskID, _currentWave] call FUNC(spawnEnemyWave);
|
[_defenseZone, _taskID, _currentWave, _enemyTemplates] call FUNC(spawnEnemyWave);
|
||||||
|
|
||||||
_currentWave = _currentWave + 1;
|
_currentWave = _currentWave + 1;
|
||||||
_nextWaveTime = time + _waveCooldown;
|
_nextWaveTime = time + _waveCooldown;
|
||||||
@ -119,6 +121,7 @@ waitUntil {
|
|||||||
|
|
||||||
if (_result == 1) then {
|
if (_result == 1) then {
|
||||||
[_taskID, "FAILED"] call BFUNC(taskSetState);
|
[_taskID, "FAILED"] call BFUNC(taskSetState);
|
||||||
|
GVAR(TaskStore) call ["setTaskStatus", [_taskID, "failed"]];
|
||||||
|
|
||||||
sleep 1;
|
sleep 1;
|
||||||
|
|
||||||
@ -126,7 +129,7 @@ if (_result == 1) then {
|
|||||||
GVAR(TaskStore) call ["applyRatingOutcome", [_taskID, _ratingFail]];
|
GVAR(TaskStore) call ["applyRatingOutcome", [_taskID, _ratingFail]];
|
||||||
GVAR(TaskStore) call ["clearTask", [_taskID]];
|
GVAR(TaskStore) call ["clearTask", [_taskID]];
|
||||||
|
|
||||||
if (_endFail) then { ["MissionFail", false] remoteExecCall ["BIS_fnc_endMission", playerSide]; };
|
if (_endFail) then { "EveryoneLost" call BFUNC(endMissionServer); };
|
||||||
} else {
|
} else {
|
||||||
private _rewards = createHashMap;
|
private _rewards = createHashMap;
|
||||||
_rewards set ["funds", _companyFunds];
|
_rewards set ["funds", _companyFunds];
|
||||||
@ -139,6 +142,7 @@ if (_result == 1) then {
|
|||||||
|
|
||||||
[_taskID, _rewards] call FUNC(handleTaskRewards);
|
[_taskID, _rewards] call FUNC(handleTaskRewards);
|
||||||
[_taskID, "SUCCEEDED"] call BFUNC(taskSetState);
|
[_taskID, "SUCCEEDED"] call BFUNC(taskSetState);
|
||||||
|
GVAR(TaskStore) call ["setTaskStatus", [_taskID, "succeeded"]];
|
||||||
|
|
||||||
sleep 1;
|
sleep 1;
|
||||||
|
|
||||||
@ -146,5 +150,5 @@ if (_result == 1) then {
|
|||||||
GVAR(TaskStore) call ["applyRatingOutcome", [_taskID, _ratingSuccess]];
|
GVAR(TaskStore) call ["applyRatingOutcome", [_taskID, _ratingSuccess]];
|
||||||
GVAR(TaskStore) call ["clearTask", [_taskID]];
|
GVAR(TaskStore) call ["clearTask", [_taskID]];
|
||||||
|
|
||||||
if (_endSuccess) then { ["MissionSuccess", true] remoteExecCall ["BIS_fnc_endMission", playerSide]; };
|
if (_endSuccess) then { "EveryoneWon" call BFUNC(endMissionServer); };
|
||||||
};
|
};
|
||||||
|
|||||||
@ -84,13 +84,14 @@ if (_result == 1) then {
|
|||||||
{ deleteVehicle _x } forEach _entities;
|
{ deleteVehicle _x } forEach _entities;
|
||||||
|
|
||||||
[_taskID, "FAILED"] call BFUNC(taskSetState);
|
[_taskID, "FAILED"] call BFUNC(taskSetState);
|
||||||
|
GVAR(TaskStore) call ["setTaskStatus", [_taskID, "failed"]];
|
||||||
|
|
||||||
sleep 1;
|
sleep 1;
|
||||||
|
|
||||||
GVAR(TaskStore) call ["notifyParticipants", [_taskID, "warning", "Tasks", format ["Task failed: %1 reputation", _ratingFail]]];
|
GVAR(TaskStore) call ["notifyParticipants", [_taskID, "warning", "Tasks", format ["Task failed: %1 reputation", _ratingFail]]];
|
||||||
GVAR(TaskStore) call ["applyRatingOutcome", [_taskID, _ratingFail]];
|
GVAR(TaskStore) call ["applyRatingOutcome", [_taskID, _ratingFail]];
|
||||||
|
|
||||||
if (_endFail) then { ["MissionFail", false] remoteExecCall ["BIS_fnc_endMission", playerSide]; };
|
if (_endFail) then { "EveryoneLost" call BFUNC(endMissionServer); };
|
||||||
} else {
|
} else {
|
||||||
{ deleteVehicle _x } forEach _ieds;
|
{ deleteVehicle _x } forEach _ieds;
|
||||||
{ deleteVehicle _x } forEach _entities;
|
{ deleteVehicle _x } forEach _entities;
|
||||||
@ -106,13 +107,14 @@ if (_result == 1) then {
|
|||||||
|
|
||||||
[_taskID, _rewards] call FUNC(handleTaskRewards);
|
[_taskID, _rewards] call FUNC(handleTaskRewards);
|
||||||
[_taskID, "SUCCEEDED"] call BFUNC(taskSetState);
|
[_taskID, "SUCCEEDED"] call BFUNC(taskSetState);
|
||||||
|
GVAR(TaskStore) call ["setTaskStatus", [_taskID, "succeeded"]];
|
||||||
|
|
||||||
sleep 1;
|
sleep 1;
|
||||||
|
|
||||||
GVAR(TaskStore) call ["notifyParticipants", [_taskID, "success", "Tasks", format ["Task completed: %1 reputation, $%2 funds", _ratingSuccess, [_companyFunds] call EFUNC(common,formatNumber)]]];
|
GVAR(TaskStore) call ["notifyParticipants", [_taskID, "success", "Tasks", format ["Task completed: %1 reputation, $%2 funds", _ratingSuccess, [_companyFunds] call EFUNC(common,formatNumber)]]];
|
||||||
GVAR(TaskStore) call ["applyRatingOutcome", [_taskID, _ratingSuccess]];
|
GVAR(TaskStore) call ["applyRatingOutcome", [_taskID, _ratingSuccess]];
|
||||||
|
|
||||||
if (_endSuccess) then { ["MissionSuccess", true] remoteExecCall ["BIS_fnc_endMission", playerSide]; };
|
if (_endSuccess) then { "EveryoneWon" call BFUNC(endMissionServer); };
|
||||||
};
|
};
|
||||||
|
|
||||||
GVAR(TaskStore) call ["clearTask", [_taskID]];
|
GVAR(TaskStore) call ["clearTask", [_taskID]];
|
||||||
|
|||||||
@ -95,6 +95,7 @@ if (_result == 1) then {
|
|||||||
{ deleteVehicle _x } forEach _cargo;
|
{ deleteVehicle _x } forEach _cargo;
|
||||||
|
|
||||||
[_taskID, "FAILED"] call BFUNC(taskSetState);
|
[_taskID, "FAILED"] call BFUNC(taskSetState);
|
||||||
|
GVAR(TaskStore) call ["setTaskStatus", [_taskID, "failed"]];
|
||||||
|
|
||||||
sleep 1;
|
sleep 1;
|
||||||
|
|
||||||
@ -102,7 +103,7 @@ if (_result == 1) then {
|
|||||||
GVAR(TaskStore) call ["applyRatingOutcome", [_taskID, _ratingFail]];
|
GVAR(TaskStore) call ["applyRatingOutcome", [_taskID, _ratingFail]];
|
||||||
GVAR(TaskStore) call ["clearTask", [_taskID]];
|
GVAR(TaskStore) call ["clearTask", [_taskID]];
|
||||||
|
|
||||||
if (_endFail) then { ["MissionFail", false] remoteExecCall ["BIS_fnc_endMission", playerSide]; };
|
if (_endFail) then { "EveryoneLost" call BFUNC(endMissionServer); };
|
||||||
} else {
|
} else {
|
||||||
{ deleteVehicle _x } forEach _cargo;
|
{ deleteVehicle _x } forEach _cargo;
|
||||||
|
|
||||||
@ -117,6 +118,7 @@ if (_result == 1) then {
|
|||||||
|
|
||||||
[_taskID, _rewards] call FUNC(handleTaskRewards);
|
[_taskID, _rewards] call FUNC(handleTaskRewards);
|
||||||
[_taskID, "SUCCEEDED"] call BFUNC(taskSetState);
|
[_taskID, "SUCCEEDED"] call BFUNC(taskSetState);
|
||||||
|
GVAR(TaskStore) call ["setTaskStatus", [_taskID, "succeeded"]];
|
||||||
|
|
||||||
sleep 1;
|
sleep 1;
|
||||||
|
|
||||||
@ -124,5 +126,5 @@ if (_result == 1) then {
|
|||||||
GVAR(TaskStore) call ["applyRatingOutcome", [_taskID, _ratingSuccess]];
|
GVAR(TaskStore) call ["applyRatingOutcome", [_taskID, _ratingSuccess]];
|
||||||
GVAR(TaskStore) call ["clearTask", [_taskID]];
|
GVAR(TaskStore) call ["clearTask", [_taskID]];
|
||||||
|
|
||||||
if (_endSuccess) then { ["MissionSuccess", true] remoteExecCall ["BIS_fnc_endMission", playerSide]; };
|
if (_endSuccess) then { "EveryoneWon" call BFUNC(endMissionServer); };
|
||||||
};
|
};
|
||||||
|
|||||||
@ -89,6 +89,7 @@ if (_result == 1) then {
|
|||||||
{ deleteVehicle _x } forEach _targets;
|
{ deleteVehicle _x } forEach _targets;
|
||||||
|
|
||||||
[_taskID, "FAILED"] call BFUNC(taskSetState);
|
[_taskID, "FAILED"] call BFUNC(taskSetState);
|
||||||
|
GVAR(TaskStore) call ["setTaskStatus", [_taskID, "failed"]];
|
||||||
|
|
||||||
sleep 1;
|
sleep 1;
|
||||||
|
|
||||||
@ -96,7 +97,7 @@ if (_result == 1) then {
|
|||||||
GVAR(TaskStore) call ["applyRatingOutcome", [_taskID, _ratingFail]];
|
GVAR(TaskStore) call ["applyRatingOutcome", [_taskID, _ratingFail]];
|
||||||
GVAR(TaskStore) call ["clearTask", [_taskID]];
|
GVAR(TaskStore) call ["clearTask", [_taskID]];
|
||||||
|
|
||||||
if (_endFail) then { ["MissionFail", false] remoteExecCall ["BIS_fnc_endMission", playerSide]; };
|
if (_endFail) then { "EveryoneLost" call BFUNC(endMissionServer); };
|
||||||
} else {
|
} else {
|
||||||
{ deleteVehicle _x } forEach _targets;
|
{ deleteVehicle _x } forEach _targets;
|
||||||
|
|
||||||
@ -111,6 +112,7 @@ if (_result == 1) then {
|
|||||||
|
|
||||||
[_taskID, _rewards] call FUNC(handleTaskRewards);
|
[_taskID, _rewards] call FUNC(handleTaskRewards);
|
||||||
[_taskID, "SUCCEEDED"] call BFUNC(taskSetState);
|
[_taskID, "SUCCEEDED"] call BFUNC(taskSetState);
|
||||||
|
GVAR(TaskStore) call ["setTaskStatus", [_taskID, "succeeded"]];
|
||||||
|
|
||||||
sleep 1;
|
sleep 1;
|
||||||
|
|
||||||
@ -118,5 +120,5 @@ if (_result == 1) then {
|
|||||||
GVAR(TaskStore) call ["applyRatingOutcome", [_taskID, _ratingSuccess]];
|
GVAR(TaskStore) call ["applyRatingOutcome", [_taskID, _ratingSuccess]];
|
||||||
GVAR(TaskStore) call ["clearTask", [_taskID]];
|
GVAR(TaskStore) call ["clearTask", [_taskID]];
|
||||||
|
|
||||||
if (_endSuccess) then { ["MissionSuccess", true] remoteExecCall ["BIS_fnc_endMission", playerSide]; };
|
if (_endSuccess) then { "EveryoneWon" call BFUNC(endMissionServer); };
|
||||||
};
|
};
|
||||||
|
|||||||
@ -91,29 +91,27 @@ waitUntil {
|
|||||||
sleep 1;
|
sleep 1;
|
||||||
GVAR(TaskStore) call ["trackParticipants", [_taskID, _hostages + _shooters, _extZone, 250]];
|
GVAR(TaskStore) call ["trackParticipants", [_taskID, _hostages + _shooters, _extZone, 250]];
|
||||||
|
|
||||||
private _playerGroups = allPlayers apply { group _x };
|
|
||||||
private _hostagesFreed = ({
|
|
||||||
alive _x && { ((group _x) in _playerGroups) || { !captive _x } }
|
|
||||||
} count _hostages);
|
|
||||||
private _hostagesInZone = ({ _x inArea _extZone } count _hostages);
|
private _hostagesInZone = ({ _x inArea _extZone } count _hostages);
|
||||||
private _hostagesKilled = ({ !alive _x } count _hostages);
|
private _hostagesKilled = ({ !alive _x } count _hostages);
|
||||||
private _shootersAlive = ({ alive _x } count _shooters);
|
private _shootersAlive = ({ alive _x } count _shooters);
|
||||||
|
private _hostageSucceeded = (_hostagesInZone >= _requiredRescues) && { _hostagesKilled < _maxHostageLosses };
|
||||||
|
private _shootersClearedSucceeded = (!isNil "_shooters") && { _shootersAlive <= 0 } && { _hostageSucceeded };
|
||||||
|
|
||||||
if (_timeLimit isNotEqualTo 0) then {
|
if (_timeLimit isNotEqualTo 0) then {
|
||||||
private _timeExpired = (floor time - _startTime >= _timeLimit);
|
private _timeExpired = (floor time - _startTime >= _timeLimit);
|
||||||
|
|
||||||
if (_hostagesFreed < _requiredRescues && _timeExpired) then { _result = 1; };
|
if (!_hostageSucceeded && _timeExpired) then { _result = 1; };
|
||||||
if (_hostagesKilled >= _maxHostageLosses) then { _result = 1; };
|
if (_hostagesKilled >= _maxHostageLosses) then { _result = 1; };
|
||||||
|
|
||||||
(_result == 1) or
|
(_result == 1) or
|
||||||
((_hostagesInZone >= _requiredRescues) && (_hostagesKilled < _maxHostageLosses)) or
|
_hostageSucceeded or
|
||||||
((!isNil "_shooters") && (_shootersAlive <= 0) && (_hostagesInZone >= _requiredRescues) && (_hostagesKilled < _maxHostageLosses))
|
_shootersClearedSucceeded
|
||||||
} else {
|
} else {
|
||||||
if (_hostagesKilled >= _maxHostageLosses) then { _result = 1; };
|
if (_hostagesKilled >= _maxHostageLosses) then { _result = 1; };
|
||||||
|
|
||||||
(_result == 1) or
|
(_result == 1) or
|
||||||
((_hostagesInZone >= _requiredRescues) && (_hostagesKilled < _maxHostageLosses)) or
|
_hostageSucceeded or
|
||||||
((!isNil "_shooters") && (_shootersAlive <= 0) && (_hostagesInZone >= _requiredRescues) && (_hostagesKilled < _maxHostageLosses))
|
_shootersClearedSucceeded
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -152,6 +150,7 @@ if (_result == 1) then {
|
|||||||
{ deleteVehicle _x } forEach _shooters;
|
{ deleteVehicle _x } forEach _shooters;
|
||||||
|
|
||||||
[_taskID, "FAILED"] call BFUNC(taskSetState);
|
[_taskID, "FAILED"] call BFUNC(taskSetState);
|
||||||
|
GVAR(TaskStore) call ["setTaskStatus", [_taskID, "failed"]];
|
||||||
|
|
||||||
sleep 1;
|
sleep 1;
|
||||||
|
|
||||||
@ -159,7 +158,7 @@ if (_result == 1) then {
|
|||||||
GVAR(TaskStore) call ["applyRatingOutcome", [_taskID, _ratingFail]];
|
GVAR(TaskStore) call ["applyRatingOutcome", [_taskID, _ratingFail]];
|
||||||
GVAR(TaskStore) call ["clearTask", [_taskID]];
|
GVAR(TaskStore) call ["clearTask", [_taskID]];
|
||||||
|
|
||||||
if (_endFail) then { ["MissionFail", false] remoteExecCall ["BIS_fnc_endMission", playerSide]; };
|
if (_endFail) then { "EveryoneLost" call BFUNC(endMissionServer); };
|
||||||
} else {
|
} else {
|
||||||
{ deleteVehicle _x } forEach _hostages;
|
{ deleteVehicle _x } forEach _hostages;
|
||||||
{ deleteVehicle _x } forEach _shooters;
|
{ deleteVehicle _x } forEach _shooters;
|
||||||
@ -175,6 +174,7 @@ if (_result == 1) then {
|
|||||||
|
|
||||||
[_taskID, _rewards] call FUNC(handleTaskRewards);
|
[_taskID, _rewards] call FUNC(handleTaskRewards);
|
||||||
[_taskID, "SUCCEEDED"] call BFUNC(taskSetState);
|
[_taskID, "SUCCEEDED"] call BFUNC(taskSetState);
|
||||||
|
GVAR(TaskStore) call ["setTaskStatus", [_taskID, "succeeded"]];
|
||||||
|
|
||||||
sleep 1;
|
sleep 1;
|
||||||
|
|
||||||
@ -182,5 +182,5 @@ if (_result == 1) then {
|
|||||||
GVAR(TaskStore) call ["applyRatingOutcome", [_taskID, _ratingSuccess]];
|
GVAR(TaskStore) call ["applyRatingOutcome", [_taskID, _ratingSuccess]];
|
||||||
GVAR(TaskStore) call ["clearTask", [_taskID]];
|
GVAR(TaskStore) call ["clearTask", [_taskID]];
|
||||||
|
|
||||||
if (_endSuccess) then { ["MissionSuccess", true] remoteExecCall ["BIS_fnc_endMission", playerSide]; };
|
if (_endSuccess) then { "EveryoneWon" call BFUNC(endMissionServer); };
|
||||||
};
|
};
|
||||||
|
|||||||
@ -66,6 +66,8 @@ waitUntil {
|
|||||||
};
|
};
|
||||||
|
|
||||||
_hvts = GVAR(TaskStore) call ["getTaskEntities", ["hvts", _taskID]];
|
_hvts = GVAR(TaskStore) call ["getTaskEntities", ["hvts", _taskID]];
|
||||||
|
private _requiredHvts = if (_limitSuccess < 0) then { count _hvts } else { _limitSuccess };
|
||||||
|
private _maxHvtLosses = if (_limitFail < 0) then { count _hvts } else { _limitFail };
|
||||||
|
|
||||||
if (_timeLimit isNotEqualTo 0) then {
|
if (_timeLimit isNotEqualTo 0) then {
|
||||||
waitUntil {
|
waitUntil {
|
||||||
@ -80,22 +82,23 @@ waitUntil {
|
|||||||
sleep 1;
|
sleep 1;
|
||||||
GVAR(TaskStore) call ["trackParticipants", [_taskID, _hvts, _extZone, 250]];
|
GVAR(TaskStore) call ["trackParticipants", [_taskID, _hvts, _extZone, 250]];
|
||||||
|
|
||||||
private _hvtsCaptive = ({ captive _x } count _hvts);
|
|
||||||
private _hvtsKilled = ({ !alive _x } count _hvts);
|
private _hvtsKilled = ({ !alive _x } count _hvts);
|
||||||
private _hvtsInZone = ({ _x inArea _extZone } count _hvts);
|
private _hvtsInZone = ({ _x inArea _extZone } count _hvts);
|
||||||
|
private _captureSucceeded = _capture && { _hvtsInZone >= _requiredHvts } && { _hvtsKilled < _maxHvtLosses };
|
||||||
|
private _eliminateSucceeded = _eliminate && { _hvtsKilled >= _requiredHvts };
|
||||||
|
|
||||||
if (_timeLimit isNotEqualTo 0) then {
|
if (_timeLimit isNotEqualTo 0) then {
|
||||||
private _timeExpired = (floor time - _startTime >= _timeLimit);
|
private _timeExpired = (floor time - _startTime >= _timeLimit);
|
||||||
|
|
||||||
if (_capture && _hvtsKilled >= _limitFail) then { _result = 1; };
|
if (_capture && { _hvtsKilled >= _maxHvtLosses }) then { _result = 1; };
|
||||||
if (_capture && _hvtsCaptive < _limitSuccess && _timeExpired) then { _result = 1; };
|
if (_capture && { !_captureSucceeded } && { _timeExpired }) then { _result = 1; };
|
||||||
if (_eliminate && _hvtsKilled < _limitSuccess && _timeExpired) then { _result = 1; };
|
if (_eliminate && { !_eliminateSucceeded } && { _timeExpired }) then { _result = 1; };
|
||||||
|
|
||||||
(_result == 1) or (_capture && (_hvtsInZone >= _limitSuccess) && (_hvtsKilled < _limitFail)) or (_eliminate && (_hvtsKilled >= _limitSuccess))
|
(_result == 1) or _captureSucceeded or _eliminateSucceeded
|
||||||
} else {
|
} else {
|
||||||
if (_capture && (_hvtsKilled >= _limitFail)) then { _result = 1; };
|
if (_capture && { _hvtsKilled >= _maxHvtLosses }) then { _result = 1; };
|
||||||
|
|
||||||
(_result == 1) or (_capture && (_hvtsInZone >= _limitSuccess) && (_hvtsKilled < _limitFail)) or (_eliminate && (_hvtsKilled >= _limitSuccess))
|
(_result == 1) or _captureSucceeded or _eliminateSucceeded
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -103,6 +106,7 @@ if (_result == 1) then {
|
|||||||
{ deleteVehicle _x } forEach _hvts;
|
{ deleteVehicle _x } forEach _hvts;
|
||||||
|
|
||||||
[_taskID, "FAILED"] call BFUNC(taskSetState);
|
[_taskID, "FAILED"] call BFUNC(taskSetState);
|
||||||
|
GVAR(TaskStore) call ["setTaskStatus", [_taskID, "failed"]];
|
||||||
|
|
||||||
sleep 1;
|
sleep 1;
|
||||||
|
|
||||||
@ -110,7 +114,7 @@ if (_result == 1) then {
|
|||||||
GVAR(TaskStore) call ["applyRatingOutcome", [_taskID, _ratingFail]];
|
GVAR(TaskStore) call ["applyRatingOutcome", [_taskID, _ratingFail]];
|
||||||
GVAR(TaskStore) call ["clearTask", [_taskID]];
|
GVAR(TaskStore) call ["clearTask", [_taskID]];
|
||||||
|
|
||||||
if (_endFail) then { ["MissionFail", false] remoteExecCall ["BIS_fnc_endMission", playerSide]; };
|
if (_endFail) then { "EveryoneLost" call BFUNC(endMissionServer); };
|
||||||
} else {
|
} else {
|
||||||
{ deleteVehicle _x } forEach _hvts;
|
{ deleteVehicle _x } forEach _hvts;
|
||||||
|
|
||||||
@ -125,6 +129,7 @@ if (_result == 1) then {
|
|||||||
|
|
||||||
[_taskID, _rewards] call FUNC(handleTaskRewards);
|
[_taskID, _rewards] call FUNC(handleTaskRewards);
|
||||||
[_taskID, "SUCCEEDED"] call BFUNC(taskSetState);
|
[_taskID, "SUCCEEDED"] call BFUNC(taskSetState);
|
||||||
|
GVAR(TaskStore) call ["setTaskStatus", [_taskID, "succeeded"]];
|
||||||
|
|
||||||
sleep 1;
|
sleep 1;
|
||||||
|
|
||||||
@ -132,5 +137,5 @@ if (_result == 1) then {
|
|||||||
GVAR(TaskStore) call ["applyRatingOutcome", [_taskID, _ratingSuccess]];
|
GVAR(TaskStore) call ["applyRatingOutcome", [_taskID, _ratingSuccess]];
|
||||||
GVAR(TaskStore) call ["clearTask", [_taskID]];
|
GVAR(TaskStore) call ["clearTask", [_taskID]];
|
||||||
|
|
||||||
if (_endSuccess) then { ["MissionSuccess", true] remoteExecCall ["BIS_fnc_endMission", playerSide]; };
|
if (_endSuccess) then { "EveryoneWon" call BFUNC(endMissionServer); };
|
||||||
};
|
};
|
||||||
|
|||||||
@ -28,8 +28,6 @@ SETVAR(_entity,assignedTask,_taskID);
|
|||||||
GVAR(TaskStore) call ["registerTaskEntity", ["hostages", _taskID, _entity]];
|
GVAR(TaskStore) call ["registerTaskEntity", ["hostages", _taskID, _entity]];
|
||||||
|
|
||||||
if (alive _entity) then {
|
if (alive _entity) then {
|
||||||
// Apply hostage protection immediately so nearby hostile AI cannot kill the
|
|
||||||
// unit before the scheduled heartbeat initializes the animation state.
|
|
||||||
_entity setCaptive true;
|
_entity setCaptive true;
|
||||||
_entity enableAIFeature ["MOVE", false];
|
_entity enableAIFeature ["MOVE", false];
|
||||||
|
|
||||||
|
|||||||
@ -8,6 +8,7 @@
|
|||||||
* 0: Defense zone marker name <STRING>
|
* 0: Defense zone marker name <STRING>
|
||||||
* 1: Task ID <STRING>
|
* 1: Task ID <STRING>
|
||||||
* 2: Wave number (0-based) <NUMBER>
|
* 2: Wave number (0-based) <NUMBER>
|
||||||
|
* 3: Enemy template groups <ARRAY> (default: [])
|
||||||
*
|
*
|
||||||
* Return Value:
|
* Return Value:
|
||||||
* None
|
* None
|
||||||
@ -18,7 +19,7 @@
|
|||||||
* Public: No
|
* Public: No
|
||||||
*/
|
*/
|
||||||
|
|
||||||
params [["_defenseZone", "", [""]], ["_taskID", "", [""]], ["_waveNumber", 0, [0]]];
|
params [["_defenseZone", "", [""]], ["_taskID", "", [""]], ["_waveNumber", 0, [0]], ["_enemyTemplates", [], [[]]]];
|
||||||
|
|
||||||
if (_defenseZone == "") exitWith { ["ERROR", "No defense zone provided for enemy wave spawn"] call EFUNC(common,log); };
|
if (_defenseZone == "") exitWith { ["ERROR", "No defense zone provided for enemy wave spawn"] call EFUNC(common,log); };
|
||||||
|
|
||||||
@ -47,37 +48,83 @@ for "_i" from 0 to 3 do {
|
|||||||
private _spawnPos = [_spawnX, _spawnY, 0];
|
private _spawnPos = [_spawnX, _spawnY, 0];
|
||||||
|
|
||||||
private _safePos = _spawnPos findEmptyPosition [0, 50, "O_Soldier_F"];
|
private _safePos = _spawnPos findEmptyPosition [0, 50, "O_Soldier_F"];
|
||||||
if (count _safePos > 0) then {
|
if (count _safePos > 0) then { _spawnPositions pushBack _safePos; };
|
||||||
_spawnPositions pushBack _safePos;
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
private _groups = [];
|
private _groups = [];
|
||||||
{
|
if (_spawnPositions isEqualTo []) exitWith {
|
||||||
private _groupSize = ceil(_unitCount / (count _spawnPositions));
|
["ERROR", format ["Defense wave %1 for task %2 could not find spawn positions", _waveNumber + 1, _taskID]] call EFUNC(common,log);
|
||||||
private _group = createGroup east;
|
};
|
||||||
_groups pushBack _group;
|
|
||||||
|
|
||||||
for "_i" from 1 to _groupSize do {
|
if (_enemyTemplates isNotEqualTo []) then {
|
||||||
private _unitType = _basicTypes select (floor random count _basicTypes);
|
private _groupCount = ((_waveNumber + 1) min 4) min (count _spawnPositions);
|
||||||
private _roll = random 1;
|
private _selectedSpawnPositions = +_spawnPositions;
|
||||||
|
_selectedSpawnPositions resize _groupCount;
|
||||||
|
|
||||||
if (_roll < _eliteChance) then {
|
{
|
||||||
_unitType = _eliteTypes select (floor random count _eliteTypes);
|
private _spawnPos = _x;
|
||||||
} else {
|
private _templateGroup = selectRandom _enemyTemplates;
|
||||||
if (_roll < _specialChance) then {
|
if !(_templateGroup isEqualType []) then { continue; };
|
||||||
_unitType = _specialTypes select (floor random count _specialTypes);
|
if (_templateGroup isEqualTo []) then { continue; };
|
||||||
|
|
||||||
|
private _firstTemplate = _templateGroup select 0;
|
||||||
|
if !(_firstTemplate isEqualType createHashMap) then { continue; };
|
||||||
|
|
||||||
|
private _side = _firstTemplate getOrDefault ["side", east];
|
||||||
|
private _group = createGroup _side;
|
||||||
|
_groups pushBack _group;
|
||||||
|
|
||||||
|
{
|
||||||
|
private _unitTemplate = _x;
|
||||||
|
if !(_unitTemplate isEqualType createHashMap) then { continue; };
|
||||||
|
|
||||||
|
private _unitType = _unitTemplate getOrDefault ["type", "O_Soldier_F"];
|
||||||
|
private _unit = _group createUnit [_unitType, _spawnPos, [], 0, "NONE"];
|
||||||
|
_unit setVariable ["assignedTask", _taskID, true];
|
||||||
|
_unit setUnitLoadout (_unitTemplate getOrDefault ["loadout", getUnitLoadout _unit]);
|
||||||
|
_unit setSkill (_unitTemplate getOrDefault ["skill", skill _unit]);
|
||||||
|
_unit setRank (_unitTemplate getOrDefault ["rank", rank _unit]);
|
||||||
|
_unit setBehaviour "AWARE";
|
||||||
|
_unit setSpeedMode "NORMAL";
|
||||||
|
_unit enableDynamicSimulation true;
|
||||||
|
} forEach _templateGroup;
|
||||||
|
|
||||||
|
[_group, _center, _radius * 0.75] call CFUNC(taskDefend);
|
||||||
|
} forEach _selectedSpawnPositions;
|
||||||
|
|
||||||
|
["INFO", format [
|
||||||
|
"Spawned defense wave %1 for task %2 from %3 template group(s)",
|
||||||
|
_waveNumber + 1,
|
||||||
|
_taskID,
|
||||||
|
count _groups
|
||||||
|
]] call EFUNC(common,log);
|
||||||
|
} else {
|
||||||
|
{
|
||||||
|
private _groupSize = ceil(_unitCount / (count _spawnPositions));
|
||||||
|
private _group = createGroup east;
|
||||||
|
_groups pushBack _group;
|
||||||
|
|
||||||
|
for "_i" from 1 to _groupSize do {
|
||||||
|
private _unitType = _basicTypes select (floor random count _basicTypes);
|
||||||
|
private _roll = random 1;
|
||||||
|
|
||||||
|
if (_roll < _eliteChance) then {
|
||||||
|
_unitType = _eliteTypes select (floor random count _eliteTypes);
|
||||||
|
} else {
|
||||||
|
if (_roll < _specialChance) then {
|
||||||
|
_unitType = _specialTypes select (floor random count _specialTypes);
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
private _unit = _group createUnit [_unitType, _x, [], 0, "NONE"];
|
||||||
|
_unit setVariable ["assignedTask", _taskID, true];
|
||||||
|
_unit setBehaviour "AWARE";
|
||||||
|
_unit setSpeedMode "NORMAL";
|
||||||
|
_unit enableDynamicSimulation true;
|
||||||
};
|
};
|
||||||
|
|
||||||
private _unit = _group createUnit [_unitType, _x, [], 0, "NONE"];
|
[_group, _center, _radius * 0.75] call CFUNC(taskDefend);
|
||||||
_unit setVariable ["assignedTask", _taskID, true];
|
} forEach _spawnPositions;
|
||||||
_unit setBehaviour "AWARE";
|
|
||||||
_unit setSpeedMode "NORMAL";
|
|
||||||
_unit enableDynamicSimulation true;
|
|
||||||
};
|
|
||||||
|
|
||||||
[_group, _center, _radius * 0.75] call CFUNC(taskDefend);
|
["INFO", format ["Spawned defense wave %1 for task %2 with %3 fallback units", _waveNumber + 1, _taskID, _unitCount]] call EFUNC(common,log);
|
||||||
} forEach _spawnPositions;
|
};
|
||||||
|
|
||||||
["INFO", format ["Spawned defense wave %1 for task %2 with %3 units", _waveNumber + 1, _taskID, _unitCount]] call EFUNC(common,log);
|
|
||||||
|
|||||||
@ -47,6 +47,7 @@
|
|||||||
* "waveCount" <NUMBER> (default: 3)
|
* "waveCount" <NUMBER> (default: 3)
|
||||||
* "waveCooldown" <NUMBER> (default: 300)
|
* "waveCooldown" <NUMBER> (default: 300)
|
||||||
* "minBlufor" <NUMBER> (default: 1)
|
* "minBlufor" <NUMBER> (default: 1)
|
||||||
|
* "enemyTemplates" <ARRAY> (default: [])
|
||||||
* 7: Minimum org reputation required <NUMBER> (default: 0)
|
* 7: Minimum org reputation required <NUMBER> (default: 0)
|
||||||
* 8: Requester UID <STRING> (default: "")
|
* 8: Requester UID <STRING> (default: "")
|
||||||
* 9: Source tag <STRING> (default: "eden") -- "eden"|"mission_manager"|"script"
|
* 9: Source tag <STRING> (default: "eden") -- "eden"|"mission_manager"|"script"
|
||||||
@ -186,7 +187,8 @@ private _handlerArgs = switch (_taskType) do {
|
|||||||
private _waveCount = _taskParams getOrDefault ["waveCount", 3];
|
private _waveCount = _taskParams getOrDefault ["waveCount", 3];
|
||||||
private _waveCooldown = _taskParams getOrDefault ["waveCooldown", 300];
|
private _waveCooldown = _taskParams getOrDefault ["waveCooldown", 300];
|
||||||
private _minBlufor = _taskParams getOrDefault ["minBlufor", 1];
|
private _minBlufor = _taskParams getOrDefault ["minBlufor", 1];
|
||||||
[_taskID, _defenseZone, _defendTime, _funds, _ratingFail, _ratingSuccess, _endSuccess, _endFail, _waveCount, _waveCooldown, _minBlufor] + _rewardTail
|
private _enemyTemplates = _taskParams getOrDefault ["enemyTemplates", []];
|
||||||
|
[_taskID, _defenseZone, _defendTime, _funds, _ratingFail, _ratingSuccess, _endSuccess, _endFail, _waveCount, _waveCooldown, _minBlufor, _enemyTemplates] + _rewardTail
|
||||||
};
|
};
|
||||||
default {
|
default {
|
||||||
["ERROR", format ["startTask: unknown task type '%1'.", _taskType]] call EFUNC(common,log);
|
["ERROR", format ["startTask: unknown task type '%1'.", _taskType]] call EFUNC(common,log);
|
||||||
|
|||||||
@ -5,8 +5,7 @@
|
|||||||
* Initializes the defend task module.
|
* Initializes the defend task module.
|
||||||
* Reads parameters from the logic object and delegates to fnc_startTask.
|
* Reads parameters from the logic object and delegates to fnc_startTask.
|
||||||
* The designer must place a named marker in Eden for the defense zone.
|
* The designer must place a named marker in Eden for the defense zone.
|
||||||
* Enemy waves are spawned automatically by fnc_defend — no entities need
|
* Synced enemy units are used as wave composition templates.
|
||||||
* to be synced to this module.
|
|
||||||
*
|
*
|
||||||
* Arguments:
|
* Arguments:
|
||||||
* 0: Logic <OBJECT>
|
* 0: Logic <OBJECT>
|
||||||
@ -33,13 +32,51 @@ if (_defenseZone isEqualTo "" || { markerShape _defenseZone isEqualTo "" }) exit
|
|||||||
["ERROR", format ["Defend module '%1': DefenseZone marker '%2' is missing or invalid.", _taskID, _defenseZone]] call EFUNC(common,log);
|
["ERROR", format ["Defend module '%1': DefenseZone marker '%2' is missing or invalid.", _taskID, _defenseZone]] call EFUNC(common,log);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
private _syncedEnemies = synchronizedObjects _logic select { _x isKindOf "CAManBase" };
|
||||||
|
private _templateGroups = [];
|
||||||
|
private _templateUnits = [];
|
||||||
|
private _seenGroups = [];
|
||||||
|
|
||||||
|
{
|
||||||
|
private _group = group _x;
|
||||||
|
if (_group in _seenGroups) then { continue; };
|
||||||
|
_seenGroups pushBack _group;
|
||||||
|
|
||||||
|
private _templates = [];
|
||||||
|
{
|
||||||
|
if (isNull _x) then { continue; };
|
||||||
|
_templateUnits pushBackUnique _x;
|
||||||
|
_templates pushBack createHashMapFromArray [
|
||||||
|
["type", typeOf _x],
|
||||||
|
["loadout", getUnitLoadout _x],
|
||||||
|
["skill", skill _x],
|
||||||
|
["rank", rank _x],
|
||||||
|
["side", side _x]
|
||||||
|
];
|
||||||
|
} forEach (units _group);
|
||||||
|
|
||||||
|
if (_templates isNotEqualTo []) then {
|
||||||
|
_templateGroups pushBack _templates;
|
||||||
|
};
|
||||||
|
} forEach _syncedEnemies;
|
||||||
|
|
||||||
|
{ deleteVehicle _x } forEach _templateUnits;
|
||||||
|
|
||||||
|
if (_templateGroups isEqualTo []) then {
|
||||||
|
["WARNING", format [
|
||||||
|
"Defend module '%1' has no synced enemy units. Falling back to default CSAT wave templates.",
|
||||||
|
_taskID
|
||||||
|
]] call EFUNC(common,log);
|
||||||
|
};
|
||||||
|
|
||||||
["INFO", format [
|
["INFO", format [
|
||||||
"Defend Module Parameters: TaskID: %1, DefenseZone: %2, DefendTime: %3, WaveCount: %4, WaveCooldown: %5, MinBlufor: %6",
|
"Defend Module Parameters: TaskID: %1, DefenseZone: %2, DefendTime: %3, WaveCount: %4, WaveCooldown: %5, MinBlufor: %6, EnemyTemplateGroups: %7",
|
||||||
_taskID, _defenseZone,
|
_taskID, _defenseZone,
|
||||||
_logic getVariable ["DefendTime", 600],
|
_logic getVariable ["DefendTime", 600],
|
||||||
_logic getVariable ["WaveCount", 3],
|
_logic getVariable ["WaveCount", 3],
|
||||||
_logic getVariable ["WaveCooldown", 300],
|
_logic getVariable ["WaveCooldown", 300],
|
||||||
_logic getVariable ["MinBlufor", 1]
|
_logic getVariable ["MinBlufor", 1],
|
||||||
|
count _templateGroups
|
||||||
]] call EFUNC(common,log);
|
]] call EFUNC(common,log);
|
||||||
|
|
||||||
private _equipmentRewards = [_logic getVariable ["EquipmentRewards", "[]"], _taskID, "equipment"] call FUNC(parseRewards);
|
private _equipmentRewards = [_logic getVariable ["EquipmentRewards", "[]"], _taskID, "equipment"] call FUNC(parseRewards);
|
||||||
@ -66,6 +103,7 @@ private _specialRewards = [_logic getVariable ["SpecialRewards", "[]"], _taskID,
|
|||||||
["waveCount", _logic getVariable ["WaveCount", 3]],
|
["waveCount", _logic getVariable ["WaveCount", 3]],
|
||||||
["waveCooldown", _logic getVariable ["WaveCooldown", 300]],
|
["waveCooldown", _logic getVariable ["WaveCooldown", 300]],
|
||||||
["minBlufor", _logic getVariable ["MinBlufor", 1]],
|
["minBlufor", _logic getVariable ["MinBlufor", 1]],
|
||||||
|
["enemyTemplates", _templateGroups],
|
||||||
["equipment", _equipmentRewards],
|
["equipment", _equipmentRewards],
|
||||||
["supplies", _supplyRewards],
|
["supplies", _supplyRewards],
|
||||||
["weapons", _weaponRewards],
|
["weapons", _weaponRewards],
|
||||||
|
|||||||
@ -158,7 +158,7 @@ GVAR(AttackTaskBaseClass) = createHashMapFromArray [
|
|||||||
GVAR(TaskStore) call ["clearTask", [_taskID]];
|
GVAR(TaskStore) call ["clearTask", [_taskID]];
|
||||||
};
|
};
|
||||||
|
|
||||||
if (_endFail) then { ["MissionFail", false] remoteExecCall ["BIS_fnc_endMission", playerSide]; };
|
if (_endFail) then { "EveryoneLost" call BFUNC(endMissionServer); };
|
||||||
} else {
|
} else {
|
||||||
{ deleteVehicle _x } forEach _targets;
|
{ deleteVehicle _x } forEach _targets;
|
||||||
|
|
||||||
@ -174,7 +174,7 @@ GVAR(AttackTaskBaseClass) = createHashMapFromArray [
|
|||||||
GVAR(TaskStore) call ["clearTask", [_taskID]];
|
GVAR(TaskStore) call ["clearTask", [_taskID]];
|
||||||
};
|
};
|
||||||
|
|
||||||
if (_endSuccess) then { ["MissionSuccess", true] remoteExecCall ["BIS_fnc_endMission", playerSide]; };
|
if (_endSuccess) then { "EveryoneWon" call BFUNC(endMissionServer); };
|
||||||
};
|
};
|
||||||
|
|
||||||
_self call ["cleanup", []];
|
_self call ["cleanup", []];
|
||||||
|
|||||||
@ -22,6 +22,7 @@ GVAR(DefendTaskBaseClass) = createHashMapFromArray [
|
|||||||
_self set ["waveCount", _taskParams getOrDefault ["waveCount", 3]];
|
_self set ["waveCount", _taskParams getOrDefault ["waveCount", 3]];
|
||||||
_self set ["waveCooldown", _taskParams getOrDefault ["waveCooldown", 300]];
|
_self set ["waveCooldown", _taskParams getOrDefault ["waveCooldown", 300]];
|
||||||
_self set ["minBlufor", _taskParams getOrDefault ["minBlufor", 1]];
|
_self set ["minBlufor", _taskParams getOrDefault ["minBlufor", 1]];
|
||||||
|
_self set ["enemyTemplates", _taskParams getOrDefault ["enemyTemplates", []]];
|
||||||
_self set ["nextWaveTime", -1];
|
_self set ["nextWaveTime", -1];
|
||||||
_self set ["currentWave", 0];
|
_self set ["currentWave", 0];
|
||||||
_self set ["zoneEmptyCounter", 0];
|
_self set ["zoneEmptyCounter", 0];
|
||||||
@ -91,6 +92,7 @@ GVAR(DefendTaskBaseClass) = createHashMapFromArray [
|
|||||||
private _waveCooldown = _self getOrDefault ["waveCooldown", 300];
|
private _waveCooldown = _self getOrDefault ["waveCooldown", 300];
|
||||||
private _minBlufor = _self getOrDefault ["minBlufor", 1];
|
private _minBlufor = _self getOrDefault ["minBlufor", 1];
|
||||||
private _currentWave = _self getOrDefault ["currentWave", 0];
|
private _currentWave = _self getOrDefault ["currentWave", 0];
|
||||||
|
private _enemyTemplates = _self getOrDefault ["enemyTemplates", []];
|
||||||
private _nextWaveTime = _self getOrDefault ["nextWaveTime", -1];
|
private _nextWaveTime = _self getOrDefault ["nextWaveTime", -1];
|
||||||
private _zoneEmptyCounter = _self getOrDefault ["zoneEmptyCounter", 0];
|
private _zoneEmptyCounter = _self getOrDefault ["zoneEmptyCounter", 0];
|
||||||
private _warningIssued = _self getOrDefault ["warningIssued", false];
|
private _warningIssued = _self getOrDefault ["warningIssued", false];
|
||||||
@ -110,7 +112,7 @@ GVAR(DefendTaskBaseClass) = createHashMapFromArray [
|
|||||||
};
|
};
|
||||||
|
|
||||||
if (_currentWave < _waveCount && { serverTime >= _nextWaveTime }) then {
|
if (_currentWave < _waveCount && { serverTime >= _nextWaveTime }) then {
|
||||||
[_defenseZone, _taskID, _currentWave] call FUNC(spawnEnemyWave);
|
[_defenseZone, _taskID, _currentWave, _enemyTemplates] call FUNC(spawnEnemyWave);
|
||||||
|
|
||||||
_currentWave = _currentWave + 1;
|
_currentWave = _currentWave + 1;
|
||||||
_nextWaveTime = serverTime + _waveCooldown;
|
_nextWaveTime = serverTime + _waveCooldown;
|
||||||
@ -152,7 +154,7 @@ GVAR(DefendTaskBaseClass) = createHashMapFromArray [
|
|||||||
GVAR(TaskStore) call ["clearTask", [_taskID]];
|
GVAR(TaskStore) call ["clearTask", [_taskID]];
|
||||||
};
|
};
|
||||||
|
|
||||||
if (_endFail) then { ["MissionFail", false] remoteExecCall ["BIS_fnc_endMission", playerSide]; };
|
if (_endFail) then { "EveryoneLost" call BFUNC(endMissionServer); };
|
||||||
true
|
true
|
||||||
}],
|
}],
|
||||||
["handleSuccessOutcome", compileFinal {
|
["handleSuccessOutcome", compileFinal {
|
||||||
@ -174,7 +176,7 @@ GVAR(DefendTaskBaseClass) = createHashMapFromArray [
|
|||||||
GVAR(TaskStore) call ["clearTask", [_taskID]];
|
GVAR(TaskStore) call ["clearTask", [_taskID]];
|
||||||
};
|
};
|
||||||
|
|
||||||
if (_endSuccess) then { ["MissionSuccess", true] remoteExecCall ["BIS_fnc_endMission", playerSide]; };
|
if (_endSuccess) then { "EveryoneWon" call BFUNC(endMissionServer); };
|
||||||
true
|
true
|
||||||
}],
|
}],
|
||||||
["runLoop", compileFinal {
|
["runLoop", compileFinal {
|
||||||
|
|||||||
@ -125,7 +125,7 @@ GVAR(DefuseTaskBaseClass) = createHashMapFromArray [
|
|||||||
GVAR(TaskStore) call ["clearTask", [_taskID]];
|
GVAR(TaskStore) call ["clearTask", [_taskID]];
|
||||||
};
|
};
|
||||||
|
|
||||||
if (_endFail) then { ["MissionFail", false] remoteExecCall ["BIS_fnc_endMission", playerSide]; };
|
if (_endFail) then { "EveryoneLost" call BFUNC(endMissionServer); };
|
||||||
true
|
true
|
||||||
}],
|
}],
|
||||||
["handleSuccessOutcome", compileFinal {
|
["handleSuccessOutcome", compileFinal {
|
||||||
@ -152,7 +152,7 @@ GVAR(DefuseTaskBaseClass) = createHashMapFromArray [
|
|||||||
GVAR(TaskStore) call ["clearTask", [_taskID]];
|
GVAR(TaskStore) call ["clearTask", [_taskID]];
|
||||||
};
|
};
|
||||||
|
|
||||||
if (_endSuccess) then { ["MissionSuccess", true] remoteExecCall ["BIS_fnc_endMission", playerSide]; };
|
if (_endSuccess) then { "EveryoneWon" call BFUNC(endMissionServer); };
|
||||||
true
|
true
|
||||||
}],
|
}],
|
||||||
["runLoop", compileFinal {
|
["runLoop", compileFinal {
|
||||||
|
|||||||
@ -145,7 +145,7 @@ GVAR(DeliveryTaskBaseClass) = createHashMapFromArray [
|
|||||||
GVAR(TaskStore) call ["clearTask", [_taskID]];
|
GVAR(TaskStore) call ["clearTask", [_taskID]];
|
||||||
};
|
};
|
||||||
|
|
||||||
if (_endFail) then { ["MissionFail", false] remoteExecCall ["BIS_fnc_endMission", playerSide]; };
|
if (_endFail) then { "EveryoneLost" call BFUNC(endMissionServer); };
|
||||||
true
|
true
|
||||||
}],
|
}],
|
||||||
["handleSuccessOutcome", compileFinal {
|
["handleSuccessOutcome", compileFinal {
|
||||||
@ -170,7 +170,7 @@ GVAR(DeliveryTaskBaseClass) = createHashMapFromArray [
|
|||||||
GVAR(TaskStore) call ["clearTask", [_taskID]];
|
GVAR(TaskStore) call ["clearTask", [_taskID]];
|
||||||
};
|
};
|
||||||
|
|
||||||
if (_endSuccess) then { ["MissionSuccess", true] remoteExecCall ["BIS_fnc_endMission", playerSide]; };
|
if (_endSuccess) then { "EveryoneWon" call BFUNC(endMissionServer); };
|
||||||
true
|
true
|
||||||
}],
|
}],
|
||||||
["runLoop", compileFinal {
|
["runLoop", compileFinal {
|
||||||
|
|||||||
@ -125,7 +125,7 @@ GVAR(DestroyTaskBaseClass) = createHashMapFromArray [
|
|||||||
GVAR(TaskStore) call ["clearTask", [_taskID]];
|
GVAR(TaskStore) call ["clearTask", [_taskID]];
|
||||||
};
|
};
|
||||||
|
|
||||||
if (_endFail) then { ["MissionFail", false] remoteExecCall ["BIS_fnc_endMission", playerSide]; };
|
if (_endFail) then { "EveryoneLost" call BFUNC(endMissionServer); };
|
||||||
true
|
true
|
||||||
}],
|
}],
|
||||||
["handleSuccessOutcome", compileFinal {
|
["handleSuccessOutcome", compileFinal {
|
||||||
@ -150,7 +150,7 @@ GVAR(DestroyTaskBaseClass) = createHashMapFromArray [
|
|||||||
GVAR(TaskStore) call ["clearTask", [_taskID]];
|
GVAR(TaskStore) call ["clearTask", [_taskID]];
|
||||||
};
|
};
|
||||||
|
|
||||||
if (_endSuccess) then { ["MissionSuccess", true] remoteExecCall ["BIS_fnc_endMission", playerSide]; };
|
if (_endSuccess) then { "EveryoneWon" call BFUNC(endMissionServer); };
|
||||||
true
|
true
|
||||||
}],
|
}],
|
||||||
["runLoop", compileFinal {
|
["runLoop", compileFinal {
|
||||||
|
|||||||
@ -121,6 +121,9 @@ GVAR(HVTTaskBaseClass) = createHashMapFromArray [
|
|||||||
_timeExpired = (serverTime - _startedAt) >= _timeLimit;
|
_timeExpired = (serverTime - _startedAt) >= _timeLimit;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
private _captureSucceeded = _capture && { _inZone >= _required } && { _killed < _maxKilled };
|
||||||
|
private _eliminateSucceeded = _eliminate && { _killed >= _required };
|
||||||
|
|
||||||
createHashMapFromArray [
|
createHashMapFromArray [
|
||||||
["captives", _captives],
|
["captives", _captives],
|
||||||
["killed", _killed],
|
["killed", _killed],
|
||||||
@ -128,8 +131,8 @@ GVAR(HVTTaskBaseClass) = createHashMapFromArray [
|
|||||||
["required", _required],
|
["required", _required],
|
||||||
["maxKilled", _maxKilled],
|
["maxKilled", _maxKilled],
|
||||||
["timeExpired", _timeExpired],
|
["timeExpired", _timeExpired],
|
||||||
["shouldFail", (_capture && { _killed >= _maxKilled }) || { _timeExpired && { (_capture && { _captives < _required }) || { _eliminate && { _killed < _required } } } }],
|
["shouldFail", (_capture && { _killed >= _maxKilled }) || { _timeExpired && { (_capture && { !_captureSucceeded }) || { _eliminate && { !_eliminateSucceeded } } } }],
|
||||||
["shouldSucceed", (_capture && { _inZone >= _required } && { _killed < _maxKilled }) || { _eliminate && { _killed >= _required } }]
|
["shouldSucceed", _captureSucceeded || _eliminateSucceeded]
|
||||||
]
|
]
|
||||||
}],
|
}],
|
||||||
["handleFailureOutcome", compileFinal {
|
["handleFailureOutcome", compileFinal {
|
||||||
@ -152,7 +155,7 @@ GVAR(HVTTaskBaseClass) = createHashMapFromArray [
|
|||||||
GVAR(TaskStore) call ["clearTask", [_taskID]];
|
GVAR(TaskStore) call ["clearTask", [_taskID]];
|
||||||
};
|
};
|
||||||
|
|
||||||
if (_endFail) then { ["MissionFail", false] remoteExecCall ["BIS_fnc_endMission", playerSide]; };
|
if (_endFail) then { "EveryoneLost" call BFUNC(endMissionServer); };
|
||||||
true
|
true
|
||||||
}],
|
}],
|
||||||
["handleSuccessOutcome", compileFinal {
|
["handleSuccessOutcome", compileFinal {
|
||||||
@ -177,7 +180,7 @@ GVAR(HVTTaskBaseClass) = createHashMapFromArray [
|
|||||||
GVAR(TaskStore) call ["clearTask", [_taskID]];
|
GVAR(TaskStore) call ["clearTask", [_taskID]];
|
||||||
};
|
};
|
||||||
|
|
||||||
if (_endSuccess) then { ["MissionSuccess", true] remoteExecCall ["BIS_fnc_endMission", playerSide]; };
|
if (_endSuccess) then { "EveryoneWon" call BFUNC(endMissionServer); };
|
||||||
true
|
true
|
||||||
}],
|
}],
|
||||||
["runLoop", compileFinal {
|
["runLoop", compileFinal {
|
||||||
|
|||||||
@ -234,6 +234,9 @@ GVAR(HostageTaskBaseClass) = createHashMapFromArray [
|
|||||||
_timeExpired = (serverTime - _startedAt) >= _timeLimit;
|
_timeExpired = (serverTime - _startedAt) >= _timeLimit;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
private _hostageSucceeded = (_inZone >= _requiredRescues) && { _killed < _maxHostageLosses };
|
||||||
|
private _shootersClearedSucceeded = (_shootersAlive <= 0) && { _hostageSucceeded };
|
||||||
|
|
||||||
createHashMapFromArray [
|
createHashMapFromArray [
|
||||||
["freed", _freed],
|
["freed", _freed],
|
||||||
["inZone", _inZone],
|
["inZone", _inZone],
|
||||||
@ -242,8 +245,8 @@ GVAR(HostageTaskBaseClass) = createHashMapFromArray [
|
|||||||
["requiredRescues", _requiredRescues],
|
["requiredRescues", _requiredRescues],
|
||||||
["maxHostageLosses", _maxHostageLosses],
|
["maxHostageLosses", _maxHostageLosses],
|
||||||
["timeExpired", _timeExpired],
|
["timeExpired", _timeExpired],
|
||||||
["shouldFail", (_killed >= _maxHostageLosses) || { _timeExpired && { _freed < _requiredRescues } }],
|
["shouldFail", (_killed >= _maxHostageLosses) || { _timeExpired && { !_hostageSucceeded } }],
|
||||||
["shouldSucceed", ((_inZone >= _requiredRescues) && { _killed < _maxHostageLosses }) || { (_shootersAlive <= 0) && { _inZone >= _requiredRescues } && { _killed < _maxHostageLosses } }]
|
["shouldSucceed", _hostageSucceeded || _shootersClearedSucceeded]
|
||||||
]
|
]
|
||||||
}],
|
}],
|
||||||
["handleFailureOutcome", compileFinal {
|
["handleFailureOutcome", compileFinal {
|
||||||
@ -301,7 +304,7 @@ GVAR(HostageTaskBaseClass) = createHashMapFromArray [
|
|||||||
GVAR(TaskStore) call ["clearTask", [_taskID]];
|
GVAR(TaskStore) call ["clearTask", [_taskID]];
|
||||||
};
|
};
|
||||||
|
|
||||||
if (_endFail) then { ["MissionFail", false] remoteExecCall ["BIS_fnc_endMission", playerSide]; };
|
if (_endFail) then { "EveryoneLost" call BFUNC(endMissionServer); };
|
||||||
true
|
true
|
||||||
}],
|
}],
|
||||||
["handleSuccessOutcome", compileFinal {
|
["handleSuccessOutcome", compileFinal {
|
||||||
@ -328,7 +331,7 @@ GVAR(HostageTaskBaseClass) = createHashMapFromArray [
|
|||||||
GVAR(TaskStore) call ["clearTask", [_taskID]];
|
GVAR(TaskStore) call ["clearTask", [_taskID]];
|
||||||
};
|
};
|
||||||
|
|
||||||
if (_endSuccess) then { ["MissionSuccess", true] remoteExecCall ["BIS_fnc_endMission", playerSide]; };
|
if (_endSuccess) then { "EveryoneWon" call BFUNC(endMissionServer); };
|
||||||
true
|
true
|
||||||
}],
|
}],
|
||||||
["runLoop", compileFinal {
|
["runLoop", compileFinal {
|
||||||
|
|||||||
@ -199,7 +199,8 @@ Available task modules:
|
|||||||
- `FORGE_Module_Hostage`: sync to `FORGE_Module_Hostages` and
|
- `FORGE_Module_Hostage`: sync to `FORGE_Module_Hostages` and
|
||||||
`FORGE_Module_Shooters`.
|
`FORGE_Module_Shooters`.
|
||||||
- `FORGE_Module_HVT`: sync directly to HVT units.
|
- `FORGE_Module_HVT`: sync directly to HVT units.
|
||||||
- `FORGE_Module_Defend`: configure the defense marker and wave settings.
|
- `FORGE_Module_Defend`: configure the defense marker and wave settings; sync
|
||||||
|
enemy units to use their groups as wave templates.
|
||||||
|
|
||||||
These modules delegate to `forge_server_task_fnc_startTask`.
|
These modules delegate to `forge_server_task_fnc_startTask`.
|
||||||
|
|
||||||
@ -411,12 +412,16 @@ Setup:
|
|||||||
6. Set `WaveCount`.
|
6. Set `WaveCount`.
|
||||||
7. Set `WaveCooldown`.
|
7. Set `WaveCooldown`.
|
||||||
8. Set `MinBlufor` to the minimum number of friendlies required in the zone.
|
8. Set `MinBlufor` to the minimum number of friendlies required in the zone.
|
||||||
9. Set rewards, rating, and end-state options.
|
9. Place one or more enemy groups or units to use as wave templates.
|
||||||
|
10. Sync any unit from each enemy group to the defend module.
|
||||||
|
11. Set rewards, rating, and end-state options.
|
||||||
|
|
||||||
Notes:
|
Notes:
|
||||||
|
|
||||||
- No enemy groups need to be pre-placed or synced. The defend task spawns its
|
- Synced enemy units are treated as templates. Syncing one unit from a group
|
||||||
own enemy waves.
|
makes the whole group available as a wave composition.
|
||||||
|
- If no enemy units are synced, the defend task falls back to default CSAT
|
||||||
|
infantry waves.
|
||||||
- The defend task waits for the required number of BLUFOR to enter the zone
|
- The defend task waits for the required number of BLUFOR to enter the zone
|
||||||
before the timer, waves, and empty-zone failure checks begin.
|
before the timer, waves, and empty-zone failure checks begin.
|
||||||
- `DefenseZone` must be an area marker.
|
- `DefenseZone` must be an area marker.
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user