Refactor task management system with object prototypes and enhanced logging
- Updated fnc_extCall.sqf to suppress logging for specific functions. - Added object model prototypes for task instances in prototypes/taskObjectPrototypes.sqf. - Enhanced README.md to document the new object model and its purpose. - Modified XEH_postInit.sqf to improve event handling for defuse tasks. - Updated various task functions (fnc_attack, fnc_defend, fnc_defuse, fnc_delivery, fnc_destroy, fnc_heartBeat, fnc_hostage, fnc_hvt) to include task acceptance checks. - Improved fnc_makeHostage and fnc_makeIED to ensure proper task registration and state management. - Introduced new methods in task object prototypes for better state management and task flow control.
This commit is contained in:
parent
d9404f2d60
commit
07d5422091
@ -4,7 +4,7 @@
|
|||||||
* File: fnc_extCall.sqf
|
* File: fnc_extCall.sqf
|
||||||
* Author: IDSolutions
|
* Author: IDSolutions
|
||||||
* Date: 2026-01-03
|
* Date: 2026-01-03
|
||||||
* Last Update: 2026-04-01
|
* Last Update: 2026-04-28
|
||||||
* Public: No
|
* Public: No
|
||||||
*
|
*
|
||||||
* Description:
|
* Description:
|
||||||
@ -24,9 +24,12 @@
|
|||||||
|
|
||||||
params [["_function", "", [""]], ["_arguments", [], [[]]]];
|
params [["_function", "", [""]], ["_arguments", [], [[]]]];
|
||||||
|
|
||||||
["INFO", format ["Calling function: %1", _function], nil, nil] call EFUNC(common,log);
|
private _quietFunctionLogs = ["task:defuse:get"];
|
||||||
|
|
||||||
private _functionLower = toLower _function;
|
private _functionLower = toLower _function;
|
||||||
|
if !(_functionLower in _quietFunctionLogs) then {
|
||||||
|
["INFO", format ["Calling function: %1", _function], nil, nil] call EFUNC(common,log);
|
||||||
|
};
|
||||||
|
|
||||||
private _chunkPrefix = "FORGE_TRANSPORT_CHUNK:";
|
private _chunkPrefix = "FORGE_TRANSPORT_CHUNK:";
|
||||||
private _chunkPrefixLength = count toArray _chunkPrefix;
|
private _chunkPrefixLength = count toArray _chunkPrefix;
|
||||||
private _unsupportedRoutePrefix = "Error: Unsupported transport route";
|
private _unsupportedRoutePrefix = "Error: Unsupported transport route";
|
||||||
|
|||||||
@ -41,6 +41,17 @@ system intentionally starts clean after each server or mission restart.
|
|||||||
- defuse progress
|
- defuse progress
|
||||||
- per-task entity registries for cargo, hostages, HVTs, IEDs, protected entities, shooters, and targets
|
- per-task entity registries for cargo, hostages, HVTs, IEDs, protected entities, shooters, and targets
|
||||||
|
|
||||||
|
### Object Model Prototype
|
||||||
|
A review-only prototype for object-based task instances lives under
|
||||||
|
`prototypes/`. It is not wired into runtime.
|
||||||
|
|
||||||
|
- `prototypes/taskObjectPrototypes.sqf`
|
||||||
|
- `prototypes/README.md`
|
||||||
|
|
||||||
|
The prototype sketches `TaskInstanceBaseClass`, `HostageTaskBaseClass`, and
|
||||||
|
`DefuseTaskBaseClass` using `createHashMapObject` so the team can review a
|
||||||
|
stateful per-task design without replacing the current procedural task flows.
|
||||||
|
|
||||||
### Reward Handling
|
### Reward Handling
|
||||||
`fnc_handleTaskRewards.sqf` applies org-owned rewards:
|
`fnc_handleTaskRewards.sqf` applies org-owned rewards:
|
||||||
- `funds` -> org funds
|
- `funds` -> org funds
|
||||||
|
|||||||
@ -2,13 +2,27 @@
|
|||||||
|
|
||||||
["ace_explosives_defuse", {
|
["ace_explosives_defuse", {
|
||||||
private _taskID = "";
|
private _taskID = "";
|
||||||
|
private _explosive = objNull;
|
||||||
{
|
{
|
||||||
if (_x isEqualType objNull && { !isNull _x }) then {
|
if (_x isEqualType objNull && { !isNull _x }) then {
|
||||||
|
if (isNull _explosive) then { _explosive = _x; };
|
||||||
_taskID = _x getVariable ["assignedTask", ""];
|
_taskID = _x getVariable ["assignedTask", ""];
|
||||||
if (_taskID isNotEqualTo "") exitWith {};
|
if (_taskID isNotEqualTo "") exitWith {};
|
||||||
};
|
};
|
||||||
} forEach _this;
|
} forEach _this;
|
||||||
|
|
||||||
if (_taskID isEqualTo "") exitWith {};
|
if (_taskID isEqualTo "" && { !isNull _explosive }) then {
|
||||||
|
_taskID = GVAR(TaskStore) call ["findTaskEntityOwner", ["ieds", _explosive]];
|
||||||
|
};
|
||||||
|
|
||||||
|
if (_taskID isEqualTo "") exitWith {
|
||||||
|
["WARNING", format [
|
||||||
|
"ACE Defuse Event Ignored: No assignedTask found. Explosive=%1, Type=%2, NetID=%3",
|
||||||
|
_explosive,
|
||||||
|
typeOf _explosive,
|
||||||
|
netId _explosive
|
||||||
|
]] call EFUNC(common,log);
|
||||||
|
};
|
||||||
|
|
||||||
GVAR(TaskStore) call ["incrementDefuseCount", [_taskID]];
|
GVAR(TaskStore) call ["incrementDefuseCount", [_taskID]];
|
||||||
}] call CFUNC(addEventHandler);
|
}] call CFUNC(addEventHandler);
|
||||||
|
|||||||
@ -58,6 +58,14 @@ waitUntil {
|
|||||||
};
|
};
|
||||||
|
|
||||||
_targets = GVAR(TaskStore) call ["getTaskEntities", ["targets", _taskID]];
|
_targets = GVAR(TaskStore) call ["getTaskEntities", ["targets", _taskID]];
|
||||||
|
|
||||||
|
if (_timeLimit isNotEqualTo 0) then {
|
||||||
|
waitUntil {
|
||||||
|
sleep 1;
|
||||||
|
GVAR(TaskStore) call ["isTaskAccepted", [_taskID]]
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
private _startTime = if (_timeLimit isNotEqualTo 0) then { floor(time) } else { nil };
|
private _startTime = if (_timeLimit isNotEqualTo 0) then { floor(time) } else { nil };
|
||||||
|
|
||||||
waitUntil {
|
waitUntil {
|
||||||
|
|||||||
@ -55,17 +55,41 @@ if (_defenseZone == "" || !(markerShape _defenseZone in ["RECTANGLE", "ELLIPSE"]
|
|||||||
};
|
};
|
||||||
|
|
||||||
private _result = 0;
|
private _result = 0;
|
||||||
private _startTime = time;
|
private _startTime = -1;
|
||||||
private _nextWaveTime = _startTime;
|
private _nextWaveTime = -1;
|
||||||
private _currentWave = 0;
|
private _currentWave = 0;
|
||||||
private _zoneEmptyCounter = 0;
|
private _zoneEmptyCounter = 0;
|
||||||
private _warningIssued = false;
|
private _warningIssued = false;
|
||||||
|
private _defenseStarted = false;
|
||||||
|
|
||||||
|
waitUntil {
|
||||||
|
sleep 1;
|
||||||
|
GVAR(TaskStore) call ["isTaskAccepted", [_taskID]]
|
||||||
|
};
|
||||||
|
|
||||||
|
waitUntil {
|
||||||
|
sleep 1;
|
||||||
|
GVAR(TaskStore) call ["trackParticipants", [_taskID, [], _defenseZone, 0]];
|
||||||
|
|
||||||
|
private _bluforInZone = count (allUnits select { _x isKindOf "CAManBase" && { side _x == west } && { alive _x }} inAreaArray _defenseZone);
|
||||||
|
private _readyToStart = _bluforInZone >= _minBlufor;
|
||||||
|
|
||||||
|
if (_readyToStart) then {
|
||||||
|
_defenseStarted = true;
|
||||||
|
_startTime = time;
|
||||||
|
_nextWaveTime = _startTime;
|
||||||
|
|
||||||
|
GVAR(TaskStore) call ["notifyParticipants", [_taskID, "info", "Tasks", "Defense has started. Hold the zone."]];
|
||||||
|
};
|
||||||
|
|
||||||
|
_readyToStart
|
||||||
|
};
|
||||||
|
|
||||||
waitUntil {
|
waitUntil {
|
||||||
sleep 1;
|
sleep 1;
|
||||||
GVAR(TaskStore) call ["trackParticipants", [_taskID, [], _defenseZone, 0]];
|
GVAR(TaskStore) call ["trackParticipants", [_taskID, [], _defenseZone, 0]];
|
||||||
private _bluforInZone = count (allUnits select { _x isKindOf "CAManBase" && { side _x == west } && { alive _x }} inAreaArray _defenseZone);
|
private _bluforInZone = count (allUnits select { _x isKindOf "CAManBase" && { side _x == west } && { alive _x }} inAreaArray _defenseZone);
|
||||||
private _timeElapsed = time - _startTime;
|
private _timeElapsed = if (_defenseStarted) then { time - _startTime } else { 0 };
|
||||||
|
|
||||||
if (_bluforInZone < _minBlufor) then {
|
if (_bluforInZone < _minBlufor) then {
|
||||||
_zoneEmptyCounter = _zoneEmptyCounter + 1;
|
_zoneEmptyCounter = _zoneEmptyCounter + 1;
|
||||||
@ -79,7 +103,7 @@ waitUntil {
|
|||||||
_warningIssued = false;
|
_warningIssued = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
if (_currentWave < _waveCount && time >= _nextWaveTime) then {
|
if (_currentWave < _waveCount && _defenseStarted && { time >= _nextWaveTime }) then {
|
||||||
[_defenseZone, _taskID, _currentWave] call FUNC(spawnEnemyWave);
|
[_defenseZone, _taskID, _currentWave] call FUNC(spawnEnemyWave);
|
||||||
|
|
||||||
_currentWave = _currentWave + 1;
|
_currentWave = _currentWave + 1;
|
||||||
|
|||||||
@ -46,7 +46,6 @@ params [
|
|||||||
|
|
||||||
private _result = 0;
|
private _result = 0;
|
||||||
private _ieds = [];
|
private _ieds = [];
|
||||||
private _entities = [];
|
|
||||||
|
|
||||||
waitUntil {
|
waitUntil {
|
||||||
sleep 1;
|
sleep 1;
|
||||||
@ -54,25 +53,30 @@ waitUntil {
|
|||||||
count _ieds > 0
|
count _ieds > 0
|
||||||
};
|
};
|
||||||
|
|
||||||
waitUntil {
|
|
||||||
sleep 1;
|
|
||||||
_entities = GVAR(TaskStore) call ["getTaskEntities", ["entities", _taskID]];
|
|
||||||
GVAR(TaskStore) call ["trackParticipants", [_taskID, _ieds + _entities, "", 250]];
|
|
||||||
count _entities > 0
|
|
||||||
};
|
|
||||||
|
|
||||||
_ieds = GVAR(TaskStore) call ["getTaskEntities", ["ieds", _taskID]];
|
_ieds = GVAR(TaskStore) call ["getTaskEntities", ["ieds", _taskID]];
|
||||||
_entities = GVAR(TaskStore) call ["getTaskEntities", ["entities", _taskID]];
|
private _entities = GVAR(TaskStore) call ["getTaskEntities", ["entities", _taskID]];
|
||||||
|
private _requiredDefusals = if (_limitSuccess < 0) then { count _ieds } else { _limitSuccess };
|
||||||
|
private _maxProtectedLosses = if (_limitFail < 0) then { count _entities } else { _limitFail };
|
||||||
|
private _entitiesDestroyed = 0;
|
||||||
|
private _defusedCount = 0;
|
||||||
|
private _shouldFail = false;
|
||||||
|
private _shouldSucceed = false;
|
||||||
|
private _done = false;
|
||||||
|
|
||||||
waitUntil {
|
waitUntil {
|
||||||
sleep 1;
|
sleep 1;
|
||||||
GVAR(TaskStore) call ["trackParticipants", [_taskID, _ieds + _entities, "", 250]];
|
GVAR(TaskStore) call ["trackParticipants", [_taskID, _ieds + _entities, "", 250]];
|
||||||
|
|
||||||
private _entitiesDestroyed = ({ !alive _x } count _entities);
|
_entitiesDestroyed = ({ !alive _x } count _entities);
|
||||||
|
_defusedCount = GVAR(TaskStore) call ["getDefuseCount", [_taskID]];
|
||||||
|
_shouldFail = (_maxProtectedLosses > 0) && { _entitiesDestroyed >= _maxProtectedLosses };
|
||||||
|
_shouldSucceed = (_requiredDefusals > 0) && { _defusedCount >= _requiredDefusals } && { (_maxProtectedLosses <= 0) || { _entitiesDestroyed < _maxProtectedLosses } };
|
||||||
|
_done = false;
|
||||||
|
|
||||||
if (_entitiesDestroyed >= _limitFail) then { _result = 1; };
|
if (_shouldFail) then { _result = 1; };
|
||||||
|
if ((_result == 1) or _shouldSucceed) then { _done = true; };
|
||||||
|
|
||||||
(_result == 1) or ((GVAR(TaskStore) call ["getDefuseCount", [_taskID]]) >= _limitSuccess && (_entitiesDestroyed < _limitFail))
|
_done
|
||||||
};
|
};
|
||||||
|
|
||||||
if (_result == 1) then {
|
if (_result == 1) then {
|
||||||
|
|||||||
@ -30,8 +30,16 @@ if (_taskID isEqualTo "") exitWith {
|
|||||||
private _syncedModules = synchronizedObjects _logic;
|
private _syncedModules = synchronizedObjects _logic;
|
||||||
private _iedModule = (_syncedModules select { typeOf _x isEqualTo "FORGE_Module_Explosives" }) param [0, objNull];
|
private _iedModule = (_syncedModules select { typeOf _x isEqualTo "FORGE_Module_Explosives" }) param [0, objNull];
|
||||||
private _protectedModule = (_syncedModules select { typeOf _x isEqualTo "FORGE_Module_Protected" }) param [0, objNull];
|
private _protectedModule = (_syncedModules select { typeOf _x isEqualTo "FORGE_Module_Protected" }) param [0, objNull];
|
||||||
private _iedEntities = if (!isNull _iedModule) then { synchronizedObjects _iedModule } else { [] };
|
private _iedEntities = if (!isNull _iedModule) then {
|
||||||
private _protectedEntities = if (!isNull _protectedModule) then { synchronizedObjects _protectedModule } else { [] };
|
synchronizedObjects _iedModule select { !(_x isKindOf "Logic") }
|
||||||
|
} else {
|
||||||
|
[]
|
||||||
|
};
|
||||||
|
private _protectedEntities = if (!isNull _protectedModule) then {
|
||||||
|
synchronizedObjects _protectedModule select { !(_x isKindOf "Logic") }
|
||||||
|
} else {
|
||||||
|
[]
|
||||||
|
};
|
||||||
|
|
||||||
["INFO", format [
|
["INFO", format [
|
||||||
"Defuse Module: TaskID: %1, IEDs: %2, Protected: %3, IED timer: %4s",
|
"Defuse Module: TaskID: %1, IEDs: %2, Protected: %3, IED timer: %4s",
|
||||||
|
|||||||
@ -60,6 +60,14 @@ waitUntil {
|
|||||||
};
|
};
|
||||||
|
|
||||||
_cargo = GVAR(TaskStore) call ["getTaskEntities", ["cargo", _taskID]];
|
_cargo = GVAR(TaskStore) call ["getTaskEntities", ["cargo", _taskID]];
|
||||||
|
|
||||||
|
if (_timeLimit isNotEqualTo 0) then {
|
||||||
|
waitUntil {
|
||||||
|
sleep 1;
|
||||||
|
GVAR(TaskStore) call ["isTaskAccepted", [_taskID]]
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
private _startTime = if (_timeLimit isNotEqualTo 0) then { floor(time) } else { nil };
|
private _startTime = if (_timeLimit isNotEqualTo 0) then { floor(time) } else { nil };
|
||||||
|
|
||||||
waitUntil {
|
waitUntil {
|
||||||
|
|||||||
@ -58,6 +58,14 @@ waitUntil {
|
|||||||
};
|
};
|
||||||
|
|
||||||
_targets = GVAR(TaskStore) call ["getTaskEntities", ["targets", _taskID]];
|
_targets = GVAR(TaskStore) call ["getTaskEntities", ["targets", _taskID]];
|
||||||
|
|
||||||
|
if (_timeLimit isNotEqualTo 0) then {
|
||||||
|
waitUntil {
|
||||||
|
sleep 1;
|
||||||
|
GVAR(TaskStore) call ["isTaskAccepted", [_taskID]]
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
private _startTime = if (_timeLimit isNotEqualTo 0) then { floor(time) } else { nil };
|
private _startTime = if (_timeLimit isNotEqualTo 0) then { floor(time) } else { nil };
|
||||||
|
|
||||||
waitUntil {
|
waitUntil {
|
||||||
|
|||||||
@ -38,7 +38,8 @@ switch (_typeOf) do {
|
|||||||
|
|
||||||
[_entity] joinSilent (group _nearPlayer);
|
[_entity] joinSilent (group _nearPlayer);
|
||||||
|
|
||||||
_entity setCaptive false;
|
// Keep rescued hostages protected while they follow the player group.
|
||||||
|
_entity setCaptive true;
|
||||||
_entity enableAIFeature ["MOVE", true];
|
_entity enableAIFeature ["MOVE", true];
|
||||||
_entity playMove "acts_executionvictim_unbow";
|
_entity playMove "acts_executionvictim_unbow";
|
||||||
};
|
};
|
||||||
@ -53,6 +54,14 @@ switch (_typeOf) do {
|
|||||||
doStop _entity;
|
doStop _entity;
|
||||||
};
|
};
|
||||||
case "ied": {
|
case "ied": {
|
||||||
|
private _taskID = _entity getVariable ["assignedTask", ""];
|
||||||
|
if (_taskID isNotEqualTo "") then {
|
||||||
|
waitUntil {
|
||||||
|
sleep 1;
|
||||||
|
GVAR(TaskStore) call ["isTaskAccepted", [_taskID]]
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
while { alive _entity && _time > 0} do {
|
while { alive _entity && _time > 0} do {
|
||||||
if (_time > 10) then { _entity say3D "FORGE_timerBeep" };
|
if (_time > 10) then { _entity say3D "FORGE_timerBeep" };
|
||||||
if (_time <= 10 && _time > 5) then { _entity say3D "FORGE_timerBeepShort" };
|
if (_time <= 10 && _time > 5) then { _entity say3D "FORGE_timerBeepShort" };
|
||||||
|
|||||||
@ -75,13 +75,26 @@ waitUntil {
|
|||||||
|
|
||||||
_hostages = GVAR(TaskStore) call ["getTaskEntities", ["hostages", _taskID]];
|
_hostages = GVAR(TaskStore) call ["getTaskEntities", ["hostages", _taskID]];
|
||||||
_shooters = GVAR(TaskStore) call ["getTaskEntities", ["shooters", _taskID]];
|
_shooters = GVAR(TaskStore) call ["getTaskEntities", ["shooters", _taskID]];
|
||||||
|
private _requiredRescues = if (_limitSuccess < 0) then { count _hostages } else { _limitSuccess };
|
||||||
|
private _maxHostageLosses = if (_limitFail < 0) then { count _hostages } else { _limitFail };
|
||||||
|
|
||||||
|
if (_timeLimit isNotEqualTo 0) then {
|
||||||
|
waitUntil {
|
||||||
|
sleep 1;
|
||||||
|
GVAR(TaskStore) call ["isTaskAccepted", [_taskID]]
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
private _startTime = if (_timeLimit isNotEqualTo 0) then { floor(time) } else { nil };
|
private _startTime = if (_timeLimit isNotEqualTo 0) then { floor(time) } else { nil };
|
||||||
|
|
||||||
waitUntil {
|
waitUntil {
|
||||||
sleep 1;
|
sleep 1;
|
||||||
GVAR(TaskStore) call ["trackParticipants", [_taskID, _hostages + _shooters, _extZone, 250]];
|
GVAR(TaskStore) call ["trackParticipants", [_taskID, _hostages + _shooters, _extZone, 250]];
|
||||||
|
|
||||||
private _hostagesFreed = ({ !captive _x } count _hostages);
|
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);
|
||||||
@ -89,18 +102,18 @@ waitUntil {
|
|||||||
if (_timeLimit isNotEqualTo 0) then {
|
if (_timeLimit isNotEqualTo 0) then {
|
||||||
private _timeExpired = (floor time - _startTime >= _timeLimit);
|
private _timeExpired = (floor time - _startTime >= _timeLimit);
|
||||||
|
|
||||||
if (_hostagesFreed < _limitSuccess && _timeExpired) then { _result = 1; };
|
if (_hostagesFreed < _requiredRescues && _timeExpired) then { _result = 1; };
|
||||||
if (_hostagesKilled >= _limitFail) then { _result = 1; };
|
if (_hostagesKilled >= _maxHostageLosses) then { _result = 1; };
|
||||||
|
|
||||||
(_result == 1) or
|
(_result == 1) or
|
||||||
((_hostagesInZone >= _limitSuccess) && (_hostagesKilled < _limitFail)) or
|
((_hostagesInZone >= _requiredRescues) && (_hostagesKilled < _maxHostageLosses)) or
|
||||||
((!isNil "_shooters") && (_shootersAlive <= 0) && (_hostagesInZone >= _limitSuccess) && (_hostagesKilled < _limitFail))
|
((!isNil "_shooters") && (_shootersAlive <= 0) && (_hostagesInZone >= _requiredRescues) && (_hostagesKilled < _maxHostageLosses))
|
||||||
} else {
|
} else {
|
||||||
if (_hostagesKilled >= _limitFail) then { _result = 1; };
|
if (_hostagesKilled >= _maxHostageLosses) then { _result = 1; };
|
||||||
|
|
||||||
(_result == 1) or
|
(_result == 1) or
|
||||||
((_hostagesInZone >= _limitSuccess) && (_hostagesKilled < _limitFail)) or
|
((_hostagesInZone >= _requiredRescues) && (_hostagesKilled < _maxHostageLosses)) or
|
||||||
((!isNil "_shooters") && (_shootersAlive <= 0) && (_hostagesInZone >= _limitSuccess) && (_hostagesKilled < _limitFail))
|
((!isNil "_shooters") && (_shootersAlive <= 0) && (_hostagesInZone >= _requiredRescues) && (_hostagesKilled < _maxHostageLosses))
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -30,8 +30,20 @@ if (_taskID isEqualTo "") exitWith {
|
|||||||
private _syncedModules = synchronizedObjects _logic;
|
private _syncedModules = synchronizedObjects _logic;
|
||||||
private _hostageModule = (_syncedModules select { typeOf _x isEqualTo "FORGE_Module_Hostages" }) param [0, objNull];
|
private _hostageModule = (_syncedModules select { typeOf _x isEqualTo "FORGE_Module_Hostages" }) param [0, objNull];
|
||||||
private _shooterModule = (_syncedModules select { typeOf _x isEqualTo "FORGE_Module_Shooters" }) param [0, objNull];
|
private _shooterModule = (_syncedModules select { typeOf _x isEqualTo "FORGE_Module_Shooters" }) param [0, objNull];
|
||||||
private _hostageEntities = if (!isNull _hostageModule) then { synchronizedObjects _hostageModule } else { [] };
|
private _hostageEntities = if (!isNull _hostageModule) then {
|
||||||
private _shooterEntities = if (!isNull _shooterModule) then { synchronizedObjects _shooterModule } else { [] };
|
synchronizedObjects _hostageModule select {
|
||||||
|
(_x isKindOf "CAManBase") && { !(_x isKindOf "Logic") }
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
[]
|
||||||
|
};
|
||||||
|
private _shooterEntities = if (!isNull _shooterModule) then {
|
||||||
|
synchronizedObjects _shooterModule select {
|
||||||
|
(_x isKindOf "CAManBase") && { !(_x isKindOf "Logic") }
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
[]
|
||||||
|
};
|
||||||
|
|
||||||
["INFO", format [
|
["INFO", format [
|
||||||
"Hostage Module: TaskID: %1, ExtZone: %2, Hostages: %3, Shooters: %4, CBRN: %5, Execution: %6",
|
"Hostage Module: TaskID: %1, ExtZone: %2, Hostages: %3, Shooters: %4, CBRN: %5, Execution: %6",
|
||||||
|
|||||||
@ -66,6 +66,14 @@ waitUntil {
|
|||||||
};
|
};
|
||||||
|
|
||||||
_hvts = GVAR(TaskStore) call ["getTaskEntities", ["hvts", _taskID]];
|
_hvts = GVAR(TaskStore) call ["getTaskEntities", ["hvts", _taskID]];
|
||||||
|
|
||||||
|
if (_timeLimit isNotEqualTo 0) then {
|
||||||
|
waitUntil {
|
||||||
|
sleep 1;
|
||||||
|
GVAR(TaskStore) call ["isTaskAccepted", [_taskID]]
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
private _startTime = if (_timeLimit isNotEqualTo 0) then { floor(time) } else { nil };
|
private _startTime = if (_timeLimit isNotEqualTo 0) then { floor(time) } else { nil };
|
||||||
|
|
||||||
waitUntil {
|
waitUntil {
|
||||||
|
|||||||
@ -176,6 +176,26 @@ GVAR(TaskStore) = createHashMapObject [[
|
|||||||
private _entry = _self call ["callTaskState", ["task:catalog:get", [_taskID], objNull]];
|
private _entry = _self call ["callTaskState", ["task:catalog:get", [_taskID], objNull]];
|
||||||
_entry isEqualType createHashMap
|
_entry isEqualType createHashMap
|
||||||
}],
|
}],
|
||||||
|
["getTaskCatalogEntry", compileFinal {
|
||||||
|
params [["_taskID", "", [""]]];
|
||||||
|
|
||||||
|
if (_taskID isEqualTo "") exitWith { createHashMap };
|
||||||
|
|
||||||
|
private _entry = _self call ["callTaskState", ["task:catalog:get", [_taskID], createHashMap]];
|
||||||
|
if !(_entry isEqualType createHashMap) exitWith { createHashMap };
|
||||||
|
|
||||||
|
_entry
|
||||||
|
}],
|
||||||
|
["isTaskAccepted", compileFinal {
|
||||||
|
params [["_taskID", "", [""]]];
|
||||||
|
|
||||||
|
if (_taskID isEqualTo "") exitWith { false };
|
||||||
|
|
||||||
|
private _entry = _self call ["getTaskCatalogEntry", [_taskID]];
|
||||||
|
if (_entry isEqualTo createHashMap) exitWith { false };
|
||||||
|
|
||||||
|
(_entry getOrDefault ["accepted", false]) || { (_entry getOrDefault ["requesterUid", ""]) isNotEqualTo "" }
|
||||||
|
}],
|
||||||
["acceptTask", compileFinal {
|
["acceptTask", compileFinal {
|
||||||
params [["_taskID", "", [""]], ["_requesterUid", "", [""]]];
|
params [["_taskID", "", [""]], ["_requesterUid", "", [""]]];
|
||||||
|
|
||||||
@ -278,6 +298,35 @@ GVAR(TaskStore) = createHashMapObject [[
|
|||||||
|
|
||||||
+(_registry getOrDefault [_taskID, []])
|
+(_registry getOrDefault [_taskID, []])
|
||||||
}],
|
}],
|
||||||
|
["findTaskEntityOwner", compileFinal {
|
||||||
|
params [["_registryKey", "", [""]], ["_entity", objNull, [objNull]]];
|
||||||
|
|
||||||
|
if (_registryKey isEqualTo "" || { isNull _entity }) exitWith { "" };
|
||||||
|
|
||||||
|
private _taskEntityRegistries = _self getOrDefault ["taskEntityRegistries", createHashMap];
|
||||||
|
private _registry = _taskEntityRegistries getOrDefault [_registryKey, createHashMap];
|
||||||
|
private _resolvedTaskID = "";
|
||||||
|
|
||||||
|
{
|
||||||
|
private _taskID = _x;
|
||||||
|
private _entities = _y;
|
||||||
|
|
||||||
|
if (_entity in _entities) exitWith {
|
||||||
|
_resolvedTaskID = _taskID;
|
||||||
|
};
|
||||||
|
|
||||||
|
private _matchingEntity = _entities select {
|
||||||
|
!isNull _x
|
||||||
|
&& { (typeOf _x) isEqualTo (typeOf _entity) }
|
||||||
|
&& { _x distance _entity < 1 }
|
||||||
|
};
|
||||||
|
if (_matchingEntity isNotEqualTo []) exitWith {
|
||||||
|
_resolvedTaskID = _taskID;
|
||||||
|
};
|
||||||
|
} forEach _registry;
|
||||||
|
|
||||||
|
_resolvedTaskID
|
||||||
|
}],
|
||||||
["clearTaskEntities", compileFinal {
|
["clearTaskEntities", compileFinal {
|
||||||
params [["_taskID", "", [""]]];
|
params [["_taskID", "", [""]]];
|
||||||
|
|
||||||
@ -382,20 +431,31 @@ GVAR(TaskStore) = createHashMapObject [[
|
|||||||
|
|
||||||
if (_taskID isEqualTo "") exitWith { 0 };
|
if (_taskID isEqualTo "") exitWith { 0 };
|
||||||
|
|
||||||
private _nextCount = _self call ["callTaskState", ["task:defuse:increment", [_taskID], 0]];
|
["task:defuse:increment", [_taskID]] call EFUNC(extension,extCall) params ["_result", "_isSuccess"];
|
||||||
if !(_nextCount isEqualType 0) exitWith { 0 };
|
|
||||||
|
|
||||||
_nextCount
|
if !_isSuccess exitWith { 0 };
|
||||||
|
if !(_result isEqualType "") exitWith { 0 };
|
||||||
|
if ((_result find "Error:") == 0) exitWith {
|
||||||
|
["ERROR", format ["Task extension call 'task:defuse:increment' failed: %1", _result]] call EFUNC(common,log);
|
||||||
|
0
|
||||||
|
};
|
||||||
|
|
||||||
|
parseNumber _result
|
||||||
}],
|
}],
|
||||||
["getDefuseCount", compileFinal {
|
["getDefuseCount", compileFinal {
|
||||||
params [["_taskID", "", [""]]];
|
params [["_taskID", "", [""]]];
|
||||||
|
|
||||||
if (_taskID isEqualTo "") exitWith { 0 };
|
if (_taskID isEqualTo "") exitWith { 0 };
|
||||||
|
|
||||||
private _defuseCount = _self call ["callTaskState", ["task:defuse:get", [_taskID], 0]];
|
["task:defuse:get", [_taskID]] call EFUNC(extension,extCall) params ["_result", "_isSuccess"];
|
||||||
if !(_defuseCount isEqualType 0) exitWith { 0 };
|
if !_isSuccess exitWith { 0 };
|
||||||
|
if !(_result isEqualType "") exitWith { 0 };
|
||||||
|
if ((_result find "Error:") == 0) exitWith {
|
||||||
|
["ERROR", format ["Task extension call 'task:defuse:get' failed: %1", _result]] call EFUNC(common,log);
|
||||||
|
0
|
||||||
|
};
|
||||||
|
|
||||||
_defuseCount
|
parseNumber _result
|
||||||
}],
|
}],
|
||||||
["notifyParticipants", compileFinal {
|
["notifyParticipants", compileFinal {
|
||||||
params [
|
params [
|
||||||
|
|||||||
@ -27,4 +27,11 @@ if (_taskID == "") exitWith { ["ERROR", "No task ID provided for entity"] call E
|
|||||||
SETVAR(_entity,assignedTask,_taskID);
|
SETVAR(_entity,assignedTask,_taskID);
|
||||||
GVAR(TaskStore) call ["registerTaskEntity", ["hostages", _taskID, _entity]];
|
GVAR(TaskStore) call ["registerTaskEntity", ["hostages", _taskID, _entity]];
|
||||||
|
|
||||||
if (alive _entity) then { [_entity, "hostage"] spawn FUNC(heartBeat); };
|
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 enableAIFeature ["MOVE", false];
|
||||||
|
|
||||||
|
[_entity, "hostage"] spawn FUNC(heartBeat);
|
||||||
|
};
|
||||||
|
|||||||
@ -26,7 +26,7 @@ if (_time <= 0) exitWith { ["ERROR", "Invalid time provided for IED"] call EFUNC
|
|||||||
|
|
||||||
["INFO", format ["Make IED: %1", _this]] call EFUNC(common,log);
|
["INFO", format ["Make IED: %1", _this]] call EFUNC(common,log);
|
||||||
|
|
||||||
SETVAR(_entity,assignedTask,_taskID);
|
SETPVAR(_entity,assignedTask,_taskID);
|
||||||
GVAR(TaskStore) call ["registerTaskEntity", ["ieds", _taskID, _entity]];
|
GVAR(TaskStore) call ["registerTaskEntity", ["ieds", _taskID, _entity]];
|
||||||
|
|
||||||
if (alive _entity) then { [_entity, "ied", _time] spawn FUNC(heartBeat); };
|
if (alive _entity) then { [_entity, "ied", _time] spawn FUNC(heartBeat); };
|
||||||
|
|||||||
26
arma/server/addons/task/prototypes/README.md
Normal file
26
arma/server/addons/task/prototypes/README.md
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
# Task Object Prototypes
|
||||||
|
|
||||||
|
This folder contains review-only `createHashMapObject` prototypes for task
|
||||||
|
instances. They are not part of runtime initialization.
|
||||||
|
|
||||||
|
Current prototypes:
|
||||||
|
- `TaskInstanceBaseClass`
|
||||||
|
- `HostageTaskBaseClass`
|
||||||
|
- `DefuseTaskBaseClass`
|
||||||
|
|
||||||
|
Source:
|
||||||
|
- [taskObjectPrototypes.sqf](./taskObjectPrototypes.sqf)
|
||||||
|
|
||||||
|
Purpose:
|
||||||
|
- show what per-task instance objects could look like
|
||||||
|
- separate state ownership from the current long procedural functions
|
||||||
|
- avoid committing the live addon to a large refactor before the model is
|
||||||
|
reviewed
|
||||||
|
|
||||||
|
Important design choice:
|
||||||
|
- these prototypes use explicit `markSucceeded`, `markFailed`, and `cleanup`
|
||||||
|
methods instead of relying on `#delete`
|
||||||
|
|
||||||
|
That is intentional. `createHashMapObject` destructor timing is reference-based,
|
||||||
|
so `#delete` is not a good primitive for mission-critical task completion or
|
||||||
|
reward flow.
|
||||||
290
arma/server/addons/task/prototypes/taskObjectPrototypes.sqf
Normal file
290
arma/server/addons/task/prototypes/taskObjectPrototypes.sqf
Normal file
@ -0,0 +1,290 @@
|
|||||||
|
#include "..\script_component.hpp"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Review-only prototype for object-based task instances.
|
||||||
|
*
|
||||||
|
* This file is intentionally not referenced by XEH_PREP or runtime init.
|
||||||
|
* It exists so the current procedural task flows can be compared against
|
||||||
|
* a createHashMapObject-based design before any live refactor is attempted.
|
||||||
|
*
|
||||||
|
* Usage in debug/testing:
|
||||||
|
* private _prototypes = call compile preprocessFileLineNumbers
|
||||||
|
* "\forge\forge_server\addons\task\prototypes\taskObjectPrototypes.sqf";
|
||||||
|
*
|
||||||
|
* private _task = createHashMapObject [
|
||||||
|
* _prototypes get "HostageTaskBaseClass",
|
||||||
|
* [
|
||||||
|
* "task_hostage_review",
|
||||||
|
* createHashMapFromArray [
|
||||||
|
* ["hostages", [hostage1, hostage2]],
|
||||||
|
* ["shooters", [shooter1, shooter2]]
|
||||||
|
* ],
|
||||||
|
* createHashMapFromArray [
|
||||||
|
* ["extractionZone", "hostage_extract"],
|
||||||
|
* ["limitSuccess", 2],
|
||||||
|
* ["limitFail", 1],
|
||||||
|
* ["execution", true],
|
||||||
|
* ["timeLimit", 900]
|
||||||
|
* ]
|
||||||
|
* ]
|
||||||
|
* ];
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma hemtt ignore_variables ["_self"]
|
||||||
|
|
||||||
|
GVAR(TaskInstanceBaseClass) = createHashMapFromArray [
|
||||||
|
["#type", "TaskInstanceBaseClass"],
|
||||||
|
["#create", compileFinal {
|
||||||
|
params [
|
||||||
|
["_taskID", "", [""]],
|
||||||
|
["_taskType", "", [""]],
|
||||||
|
["_entities", createHashMap, [createHashMap]],
|
||||||
|
["_taskParams", createHashMap, [createHashMap]]
|
||||||
|
];
|
||||||
|
|
||||||
|
_self set ["taskID", _taskID];
|
||||||
|
_self set ["taskType", _taskType];
|
||||||
|
_self set ["entities", _entities];
|
||||||
|
_self set ["taskParams", _taskParams];
|
||||||
|
_self set ["status", "created"];
|
||||||
|
_self set ["startedAt", -1];
|
||||||
|
_self set ["finishedAt", -1];
|
||||||
|
_self set ["failureReason", ""];
|
||||||
|
_self set ["outcomeData", createHashMap];
|
||||||
|
}],
|
||||||
|
["getTaskID", compileFinal {
|
||||||
|
_self getOrDefault ["taskID", ""]
|
||||||
|
}],
|
||||||
|
["getTaskType", compileFinal {
|
||||||
|
_self getOrDefault ["taskType", ""]
|
||||||
|
}],
|
||||||
|
["getStatus", compileFinal {
|
||||||
|
_self getOrDefault ["status", "created"]
|
||||||
|
}],
|
||||||
|
["markActive", compileFinal {
|
||||||
|
_self set ["status", "active"];
|
||||||
|
_self set ["startedAt", serverTime];
|
||||||
|
true
|
||||||
|
}],
|
||||||
|
["markSucceeded", compileFinal {
|
||||||
|
params [["_outcomeData", createHashMap, [createHashMap]]];
|
||||||
|
|
||||||
|
_self set ["status", "succeeded"];
|
||||||
|
_self set ["finishedAt", serverTime];
|
||||||
|
_self set ["outcomeData", _outcomeData];
|
||||||
|
true
|
||||||
|
}],
|
||||||
|
["markFailed", compileFinal {
|
||||||
|
params [["_reason", "", [""]], ["_outcomeData", createHashMap, [createHashMap]]];
|
||||||
|
|
||||||
|
_self set ["status", "failed"];
|
||||||
|
_self set ["finishedAt", serverTime];
|
||||||
|
_self set ["failureReason", _reason];
|
||||||
|
_self set ["outcomeData", _outcomeData];
|
||||||
|
true
|
||||||
|
}],
|
||||||
|
["cleanup", compileFinal {
|
||||||
|
false
|
||||||
|
}],
|
||||||
|
["tick", compileFinal {
|
||||||
|
createHashMap
|
||||||
|
}],
|
||||||
|
["runLoop", compileFinal {
|
||||||
|
false
|
||||||
|
}]
|
||||||
|
];
|
||||||
|
|
||||||
|
GVAR(HostageTaskBaseClass) = createHashMapFromArray [
|
||||||
|
["#base", GVAR(TaskInstanceBaseClass)],
|
||||||
|
["#type", "HostageTaskBaseClass"],
|
||||||
|
["#create", compileFinal {
|
||||||
|
params [
|
||||||
|
["_taskID", "", [""]],
|
||||||
|
["_entities", createHashMap, [createHashMap]],
|
||||||
|
["_taskParams", createHashMap, [createHashMap]]
|
||||||
|
];
|
||||||
|
|
||||||
|
_self set ["taskID", _taskID];
|
||||||
|
_self set ["taskType", "hostage"];
|
||||||
|
_self set ["entities", _entities];
|
||||||
|
_self set ["taskParams", _taskParams];
|
||||||
|
_self set ["status", "created"];
|
||||||
|
_self set ["startedAt", -1];
|
||||||
|
_self set ["finishedAt", -1];
|
||||||
|
_self set ["failureReason", ""];
|
||||||
|
_self set ["outcomeData", createHashMap];
|
||||||
|
|
||||||
|
private _hostages = +(_entities getOrDefault ["hostages", []]);
|
||||||
|
private _shooters = +(_entities getOrDefault ["shooters", []]);
|
||||||
|
private _requiredRescues = _taskParams getOrDefault ["limitSuccess", -1];
|
||||||
|
if (_requiredRescues < 0) then { _requiredRescues = count _hostages; };
|
||||||
|
|
||||||
|
private _maxHostageLosses = _taskParams getOrDefault ["limitFail", -1];
|
||||||
|
if (_maxHostageLosses < 0) then { _maxHostageLosses = count _hostages; };
|
||||||
|
|
||||||
|
_self set ["hostages", _hostages];
|
||||||
|
_self set ["shooters", _shooters];
|
||||||
|
_self set ["extractionZone", _taskParams getOrDefault ["extractionZone", ""]];
|
||||||
|
_self set ["timeLimit", _taskParams getOrDefault ["timeLimit", 0]];
|
||||||
|
_self set ["execution", _taskParams getOrDefault ["execution", false]];
|
||||||
|
_self set ["cbrn", _taskParams getOrDefault ["cbrn", false]];
|
||||||
|
_self set ["cbrnZone", _taskParams getOrDefault ["cbrnZone", ""]];
|
||||||
|
_self set ["requiredRescues", _requiredRescues];
|
||||||
|
_self set ["maxHostageLosses", _maxHostageLosses];
|
||||||
|
}],
|
||||||
|
["countFreedHostages", compileFinal {
|
||||||
|
private _playerGroups = allPlayers apply { group _x };
|
||||||
|
private _hostages = _self getOrDefault ["hostages", []];
|
||||||
|
|
||||||
|
{
|
||||||
|
alive _x && { ((group _x) in _playerGroups) || { !captive _x } }
|
||||||
|
} count _hostages
|
||||||
|
}],
|
||||||
|
["countHostagesInZone", compileFinal {
|
||||||
|
private _extZone = _self getOrDefault ["extractionZone", ""];
|
||||||
|
private _hostages = _self getOrDefault ["hostages", []];
|
||||||
|
|
||||||
|
if (_extZone isEqualTo "") exitWith { 0 };
|
||||||
|
{ _x inArea _extZone } count _hostages
|
||||||
|
}],
|
||||||
|
["countKilledHostages", compileFinal {
|
||||||
|
private _hostages = _self getOrDefault ["hostages", []];
|
||||||
|
{ !alive _x } count _hostages
|
||||||
|
}],
|
||||||
|
["countAliveShooters", compileFinal {
|
||||||
|
private _shooters = _self getOrDefault ["shooters", []];
|
||||||
|
{ alive _x } count _shooters
|
||||||
|
}],
|
||||||
|
["tick", compileFinal {
|
||||||
|
private _startedAt = _self getOrDefault ["startedAt", -1];
|
||||||
|
private _timeLimit = _self getOrDefault ["timeLimit", 0];
|
||||||
|
private _killed = _self call ["countKilledHostages", []];
|
||||||
|
private _freed = _self call ["countFreedHostages", []];
|
||||||
|
private _inZone = _self call ["countHostagesInZone", []];
|
||||||
|
private _shootersAlive = _self call ["countAliveShooters", []];
|
||||||
|
private _requiredRescues = _self getOrDefault ["requiredRescues", 0];
|
||||||
|
private _maxHostageLosses = _self getOrDefault ["maxHostageLosses", 0];
|
||||||
|
private _timeExpired = false;
|
||||||
|
|
||||||
|
if (_timeLimit > 0 && { _startedAt >= 0 }) then {
|
||||||
|
_timeExpired = (serverTime - _startedAt) >= _timeLimit;
|
||||||
|
};
|
||||||
|
|
||||||
|
createHashMapFromArray [
|
||||||
|
["freed", _freed],
|
||||||
|
["inZone", _inZone],
|
||||||
|
["killed", _killed],
|
||||||
|
["shootersAlive", _shootersAlive],
|
||||||
|
["requiredRescues", _requiredRescues],
|
||||||
|
["maxHostageLosses", _maxHostageLosses],
|
||||||
|
["timeExpired", _timeExpired],
|
||||||
|
["shouldFail", (_killed >= _maxHostageLosses) || { _timeExpired && { _freed < _requiredRescues } }],
|
||||||
|
["shouldSucceed", (_inZone >= _requiredRescues) && { _killed < _maxHostageLosses }]
|
||||||
|
]
|
||||||
|
}],
|
||||||
|
["runLoop", compileFinal {
|
||||||
|
_self call ["markActive", []];
|
||||||
|
|
||||||
|
while { (_self call ["getStatus", []]) isEqualTo "active" } do {
|
||||||
|
private _snapshot = _self call ["tick", []];
|
||||||
|
|
||||||
|
if (_snapshot getOrDefault ["shouldFail", false]) exitWith {
|
||||||
|
_self call ["markFailed", ["Hostage fail conditions met.", _snapshot]];
|
||||||
|
};
|
||||||
|
|
||||||
|
if (_snapshot getOrDefault ["shouldSucceed", false]) exitWith {
|
||||||
|
_self call ["markSucceeded", [_snapshot]];
|
||||||
|
};
|
||||||
|
|
||||||
|
sleep 1;
|
||||||
|
};
|
||||||
|
|
||||||
|
true
|
||||||
|
}]
|
||||||
|
];
|
||||||
|
|
||||||
|
GVAR(DefuseTaskBaseClass) = createHashMapFromArray [
|
||||||
|
["#base", GVAR(TaskInstanceBaseClass)],
|
||||||
|
["#type", "DefuseTaskBaseClass"],
|
||||||
|
["#create", compileFinal {
|
||||||
|
params [
|
||||||
|
["_taskID", "", [""]],
|
||||||
|
["_entities", createHashMap, [createHashMap]],
|
||||||
|
["_taskParams", createHashMap, [createHashMap]]
|
||||||
|
];
|
||||||
|
|
||||||
|
_self set ["taskID", _taskID];
|
||||||
|
_self set ["taskType", "defuse"];
|
||||||
|
_self set ["entities", _entities];
|
||||||
|
_self set ["taskParams", _taskParams];
|
||||||
|
_self set ["status", "created"];
|
||||||
|
_self set ["startedAt", -1];
|
||||||
|
_self set ["finishedAt", -1];
|
||||||
|
_self set ["failureReason", ""];
|
||||||
|
_self set ["outcomeData", createHashMap];
|
||||||
|
|
||||||
|
private _ieds = +(_entities getOrDefault ["ieds", []]);
|
||||||
|
private _protected = +(_entities getOrDefault ["protected", []]);
|
||||||
|
private _requiredDefusals = _taskParams getOrDefault ["limitSuccess", -1];
|
||||||
|
if (_requiredDefusals < 0) then { _requiredDefusals = count _ieds; };
|
||||||
|
|
||||||
|
private _maxProtectedLosses = _taskParams getOrDefault ["limitFail", -1];
|
||||||
|
if (_maxProtectedLosses < 0) then { _maxProtectedLosses = count _protected; };
|
||||||
|
|
||||||
|
_self set ["ieds", _ieds];
|
||||||
|
_self set ["protected", _protected];
|
||||||
|
_self set ["requiredDefusals", _requiredDefusals];
|
||||||
|
_self set ["maxProtectedLosses", _maxProtectedLosses];
|
||||||
|
_self set ["iedTimer", _taskParams getOrDefault ["iedTimer", 300]];
|
||||||
|
}],
|
||||||
|
["countProtectedDestroyed", compileFinal {
|
||||||
|
private _protected = _self getOrDefault ["protected", []];
|
||||||
|
{ !alive _x } count _protected
|
||||||
|
}],
|
||||||
|
["getDefuseCount", compileFinal {
|
||||||
|
private _taskID = _self getOrDefault ["taskID", ""];
|
||||||
|
if (_taskID isEqualTo "") exitWith { 0 };
|
||||||
|
|
||||||
|
GVAR(TaskStore) call ["getDefuseCount", [_taskID]]
|
||||||
|
}],
|
||||||
|
["tick", compileFinal {
|
||||||
|
private _defusedCount = _self call ["getDefuseCount", []];
|
||||||
|
private _protectedDestroyed = _self call ["countProtectedDestroyed", []];
|
||||||
|
private _requiredDefusals = _self getOrDefault ["requiredDefusals", 0];
|
||||||
|
private _maxProtectedLosses = _self getOrDefault ["maxProtectedLosses", 0];
|
||||||
|
|
||||||
|
createHashMapFromArray [
|
||||||
|
["defusedCount", _defusedCount],
|
||||||
|
["protectedDestroyed", _protectedDestroyed],
|
||||||
|
["requiredDefusals", _requiredDefusals],
|
||||||
|
["maxProtectedLosses", _maxProtectedLosses],
|
||||||
|
["shouldFail", (_protectedDestroyed >= _maxProtectedLosses) && { _maxProtectedLosses > 0 }],
|
||||||
|
["shouldSucceed", (_defusedCount >= _requiredDefusals) && { _requiredDefusals > 0 } && { _protectedDestroyed < _maxProtectedLosses || { _maxProtectedLosses <= 0 } }]
|
||||||
|
]
|
||||||
|
}],
|
||||||
|
["runLoop", compileFinal {
|
||||||
|
_self call ["markActive", []];
|
||||||
|
|
||||||
|
while { (_self call ["getStatus", []]) isEqualTo "active" } do {
|
||||||
|
private _snapshot = _self call ["tick", []];
|
||||||
|
|
||||||
|
if (_snapshot getOrDefault ["shouldFail", false]) exitWith {
|
||||||
|
_self call ["markFailed", ["Defuse fail conditions met.", _snapshot]];
|
||||||
|
};
|
||||||
|
|
||||||
|
if (_snapshot getOrDefault ["shouldSucceed", false]) exitWith {
|
||||||
|
_self call ["markSucceeded", [_snapshot]];
|
||||||
|
};
|
||||||
|
|
||||||
|
sleep 1;
|
||||||
|
};
|
||||||
|
|
||||||
|
true
|
||||||
|
}]
|
||||||
|
];
|
||||||
|
|
||||||
|
createHashMapFromArray [
|
||||||
|
["TaskInstanceBaseClass", GVAR(TaskInstanceBaseClass)],
|
||||||
|
["HostageTaskBaseClass", GVAR(HostageTaskBaseClass)],
|
||||||
|
["DefuseTaskBaseClass", GVAR(DefuseTaskBaseClass)]
|
||||||
|
]
|
||||||
Loading…
x
Reference in New Issue
Block a user