From c822d4e601323f2a21bfa7bcf65fc516394db286 Mon Sep 17 00:00:00 2001 From: Jacob Schmidt Date: Sun, 25 May 2025 12:33:36 -0500 Subject: [PATCH] feat: Implement cargo delivery task type and improve task assignment This commit introduces a new "delivery" task type and enhances the task assignment process for various entities. The following changes were made: - Added `delivery` and `deliveryModule` to `XEH_PREP.hpp` for pre-processing. - Added `GVAR(allCargo)` to `XEH_preInit.sqf` to track cargo objects. - Implemented `delivery` case in `fnc_handler.sqf` to handle delivery tasks. - Added `makeCargo` to `XEH_PREP.hpp` for pre-processing. - Refactored `fnc_makeShooter.sqf`, `fnc_makeObject.sqf`, `fnc_makeTarget.sqf`, `fnc_makeHVT.sqf`, `fnc_makeHostage.sqf`, and `fnc_makeIED.sqf` to: - Update descriptions to reflect assignment rather than registration. - Add error handling for null entities and missing task IDs. - Add diag_log messages for debugging. - Standardize parameter handling. --- addons/task/XEH_PREP.hpp | 3 + addons/task/XEH_preInit.sqf | 1 + addons/task/functions/fnc_delivery.sqf | 98 ++++++++++++++++++++ addons/task/functions/fnc_deliveryModule.sqf | 66 +++++++++++++ addons/task/functions/fnc_handler.sqf | 16 ++-- addons/task/functions/fnc_makeCargo.sqf | 39 ++++++++ addons/task/functions/fnc_makeHVT.sqf | 13 ++- addons/task/functions/fnc_makeHostage.sqf | 11 ++- addons/task/functions/fnc_makeIED.sqf | 12 ++- addons/task/functions/fnc_makeObject.sqf | 11 ++- addons/task/functions/fnc_makeShooter.sqf | 7 +- addons/task/functions/fnc_makeTarget.sqf | 11 ++- 12 files changed, 261 insertions(+), 27 deletions(-) create mode 100644 addons/task/functions/fnc_delivery.sqf create mode 100644 addons/task/functions/fnc_deliveryModule.sqf create mode 100644 addons/task/functions/fnc_makeCargo.sqf diff --git a/addons/task/XEH_PREP.hpp b/addons/task/XEH_PREP.hpp index 7dae3d7..6707b13 100644 --- a/addons/task/XEH_PREP.hpp +++ b/addons/task/XEH_PREP.hpp @@ -2,6 +2,8 @@ PREP(attack); PREP(attackModule); PREP(defuse); PREP(defuseModule); +PREP(delivery); +PREP(deliveryModule); PREP(destroy); PREP(destroyModule); PREP(explosivesModule); @@ -12,6 +14,7 @@ PREP(hostageModule); PREP(hostagesModule); PREP(hvt); PREP(hvtModule); +PREP(makeCargo); PREP(makeHostage); PREP(makeHVT); PREP(makeIED); diff --git a/addons/task/XEH_preInit.sqf b/addons/task/XEH_preInit.sqf index a58b5bf..2238448 100644 --- a/addons/task/XEH_preInit.sqf +++ b/addons/task/XEH_preInit.sqf @@ -5,6 +5,7 @@ PREP_RECOMPILE_START; #include "XEH_PREP.hpp" PREP_RECOMPILE_END; +GVAR(allCargo) = []; GVAR(allHostages) = []; GVAR(allHVTs) = []; GVAR(allIEDs) = []; diff --git a/addons/task/functions/fnc_delivery.sqf b/addons/task/functions/fnc_delivery.sqf new file mode 100644 index 0000000..91a122a --- /dev/null +++ b/addons/task/functions/fnc_delivery.sqf @@ -0,0 +1,98 @@ +#include "..\script_component.hpp" + +/* + * Author: IDSolutions + * Registers a delivery task + * + * Arguments: + * 0: ID of the task + * 1: Amount of damaged cargo to fail the task + * 2: Amount of cargo delivered to complete the task + * 3: Marker name for the delivery zone + * 4: Amount of funds the company receives if the task is successful (default: 0) + * 5: Amount of rating the company and player lose if the task is failed (default: 0) + * 6: Amount of rating the company and player receive if the task is successful (default: 0) + * 7: Should the mission end (MissionSuccess) if the task is successful (default: false) + * 8: Should the mission end (MissionFailed) if the task is failed (default: false) + * 9: Amount of time to complete delivery (default: nil) + * + * Return Value: + * None + * + * Example: + * ["delivery_1", 1, 3, "delivery_zone", 250000, -75, 300, false, false] spawn forge_client_task_fnc_delivery; + * ["delivery_1", 1, 3, "delivery_zone", 250000, -75, 300, false, false, 900] spawn forge_client_task_fnc_delivery; + * + * Public: Yes + */ + +params [["_taskID", "", [""]], ["_limitFail", -1, [0]], ["_limitSuccess", -1, [0]], ["_deliveryZone", "", [""]], ["_companyFunds", 0, [0]], ["_ratingFail", 0, [0]], ["_ratingSuccess", 0, [0]], ["_endSuccess", false, [false]], ["_endFail", false, [false]], ["_time", nil, [0]]]; + +private _result = 0; + +waitUntil { + sleep 1; + _cargo = GVAR(allCargo) select { (_x getVariable ["assignedTask", ""]) == _taskID }; + count _cargo > 0 +}; + +private _cargo = GVAR(allCargo) select { (_x getVariable ["assignedTask", ""]) == _taskID }; +private _startTime = if (!isNil "_time") then { floor(time) } else { nil }; + +waitUntil { + sleep 1; + + private _cargoDelivered = ({ _x inArea _deliveryZone && (damage _x) < 0.7 } count _cargo); + private _cargoDamaged = ({ damage _x >= 0.7 } count _cargo); + + if (!isNil "_time") then { + private _timeExpired = (floor time - _startTime >= _time); + + if (_cargoDamaged >= _limitFail) then { _result = 1; }; + if (_cargoDelivered < _limitSuccess && _timeExpired) then { _result = 1; }; + + (_result == 1) or ((_cargoDelivered >= _limitSuccess) && (_cargoDamaged < _limitFail)) + } else { + if (_cargoDamaged >= _limitFail) then { _result = 1; }; + + (_result == 1) or ((_cargoDelivered >= _limitSuccess) && (_cargoDamaged < _limitFail)) + }; +}; + +if (_result == 1) then { + { deleteVehicle _x } forEach _cargo; + + [_taskID, "FAILED"] call BFUNC(taskSetState); + + if (_endFail) then { + ["MissionFail", false] remoteExecCall ["BIS_fnc_endMission", playerSide]; + }; + + // ["deduct", _ratingFail] remoteExecCall ["forge_server_rating_fnc_handleRating", 2]; + [_ratingFail] call EFUNC(org,addReputation); + [format ["Task failed: %1 reputation", _ratingFail], "warning", 5, "right"] call EFUNC(misc,notify); + + sleep 1; + + { [_x, _ratingFail] remoteExec ["addRating", -2] } forEach allPlayers; +} else { + { deleteVehicle _x } forEach _cargo; + + [_taskID, "SUCCEEDED"] call BFUNC(taskSetState); + + if (_endSuccess) then { + ["MissionSuccess", false] remoteExecCall ["BIS_fnc_endMission", playerSide]; + }; + + // ["advance", _ratingSuccess] remoteExecCall ["forge_server_rating_fnc_handleRating", 2]; + [_ratingSuccess] call EFUNC(org,addReputation); + [format ["Task succeeded: %1 reputation", _ratingSuccess], "success", 5, "right"] call EFUNC(misc,notify); + + sleep 1; + + { [_x, _ratingSuccess] remoteExec ["addRating", -2] } forEach allPlayers; + + // ["advance", _companyFunds] remoteExecCall ["forge_server_money_fnc_handleFunds", 2]; + [_companyFunds] call EFUNC(org,addFunds); + [format ["Task succeeded: %1 funds", _companyFunds], "success", 5, "right"] call EFUNC(misc,notify); +}; \ No newline at end of file diff --git a/addons/task/functions/fnc_deliveryModule.sqf b/addons/task/functions/fnc_deliveryModule.sqf new file mode 100644 index 0000000..978e563 --- /dev/null +++ b/addons/task/functions/fnc_deliveryModule.sqf @@ -0,0 +1,66 @@ +#include "..\script_component.hpp" + +/* + * Author: IDSolutions + * Creates a delivery task module + * + * Arguments: + * None + * + * Return Value: + * None + * + * Example: + * call forge_client_task_fnc_deliveryModule; + * + * Public: No + */ + +// Module category +private _category = "Forge Tasks"; +private _subCategory = "Delivery Tasks"; + +// Create the module +private _module = createDialog "RscDisplayAttributes"; +_module setVariable ["category", _category]; +_module setVariable ["subcategory", _subCategory]; +_module setVariable ["description", "Configure a delivery task"]; + +// Add fields for task configuration +[_module, "Task ID", "taskID", "", true] call BIS_fnc_addAttribute; +[_module, "Fail Limit", "limitFail", "1", true] call BIS_fnc_addAttribute; +[_module, "Success Count", "limitSuccess", "3", true] call BIS_fnc_addAttribute; +[_module, "Delivery Zone", "deliveryZone", "", true] call BIS_fnc_addAttribute; +[_module, "Company Funds Reward", "companyFunds", "250000", true] call BIS_fnc_addAttribute; +[_module, "Rating Loss on Fail", "ratingFail", "-75", true] call BIS_fnc_addAttribute; +[_module, "Rating Gain on Success", "ratingSuccess", "300", true] call BIS_fnc_addAttribute; +[_module, "End Mission on Success", "endSuccess", "false", false] call BIS_fnc_addAttribute; +[_module, "End Mission on Fail", "endFail", "false", false] call BIS_fnc_addAttribute; +[_module, "Time Limit (seconds)", "timeLimit", "", false] call BIS_fnc_addAttribute; + +// Add confirm button handler +_module setVariable ["onConfirm", { + params ["_module"]; + + private _taskID = _module getVariable ["taskID", ""]; + private _limitFail = parseNumber (_module getVariable ["limitFail", "1"]); + private _limitSuccess = parseNumber (_module getVariable ["limitSuccess", "3"]); + private _deliveryZone = _module getVariable ["deliveryZone", ""]; + private _companyFunds = parseNumber (_module getVariable ["companyFunds", "250000"]); + private _ratingFail = parseNumber (_module getVariable ["ratingFail", "-75"]); + private _ratingSuccess = parseNumber (_module getVariable ["ratingSuccess", "300"]); + private _endSuccess = _module getVariable ["endSuccess", "false"] == "true"; + private _endFail = _module getVariable ["endFail", "false"] == "true"; + private _timeLimit = _module getVariable ["timeLimit", ""]; + + // Convert time limit to number or nil + private _timeLimitNum = if (_timeLimit == "") then { nil } else { parseNumber _timeLimit }; + + // Create the task + private _params = [_taskID, _limitFail, _limitSuccess, _deliveryZone, _companyFunds, _ratingFail, _ratingSuccess, _endSuccess, _endFail]; + if (!isNil "_timeLimitNum") then { + _params pushBack _timeLimitNum; + }; + + ["delivery", _params] remoteExec ["forge_client_task_fnc_handler", 2, false]; +}]; diff --git a/addons/task/functions/fnc_handler.sqf b/addons/task/functions/fnc_handler.sqf index dee870a..7667da1 100644 --- a/addons/task/functions/fnc_handler.sqf +++ b/addons/task/functions/fnc_handler.sqf @@ -18,7 +18,7 @@ * Public: Yes */ -params [["_taskType", "", [""]], ["_cntParams", [], [[]]], ["_minRating", 0, [0]]]; +params [["_taskType", "", [""]], ["_args", [], [[]]], ["_minRating", 0, [0]]]; private _thread = 0; @@ -33,23 +33,27 @@ if (_companyRating < _minRating) exitWith { switch (_taskType) do { case "attack": { - private _thread = _cntParams spawn FUNC(attack); + private _thread = _args spawn FUNC(attack); waitUntil { sleep 2; scriptDone _thread }; }; case "defuse": { - private _thread = _cntParams spawn FUNC(defuse); + private _thread = _args spawn FUNC(defuse); waitUntil { sleep 2; scriptDone _thread }; }; case "destroy": { - private _thread = _cntParams spawn FUNC(destroy); + private _thread = _args spawn FUNC(destroy); + waitUntil { sleep 2; scriptDone _thread }; + }; + case "delivery": { + private _thread = _args spawn FUNC(delivery); waitUntil { sleep 2; scriptDone _thread }; }; case "hostage": { - private _thread = _cntParams spawn FUNC(hostage); + private _thread = _args spawn FUNC(hostage); waitUntil { sleep 2; scriptDone _thread }; }; case "hvt": { - private _thread = _cntParams spawn FUNC(hvt); + private _thread = _args spawn FUNC(hvt); waitUntil { sleep 2; scriptDone _thread }; }; default { diff --git a/addons/task/functions/fnc_makeCargo.sqf b/addons/task/functions/fnc_makeCargo.sqf new file mode 100644 index 0000000..074e2e3 --- /dev/null +++ b/addons/task/functions/fnc_makeCargo.sqf @@ -0,0 +1,39 @@ +#include "..\script_component.hpp" + +/* + * Author: IDSolutions + * Assigns cargo to a task for delivery + * + * Arguments: + * 0: Object to convert to delivery cargo + * 1: Task ID to assign the cargo to + * + * Return Value: + * None + * + * Example: + * [_cargoObject, "delivery_1"] call forge_client_task_fnc_makeCargo; + * + * Public: Yes + */ + +params [["_cargo", objNull, [objNull]], ["_taskID", "", [""]]]; + +diag_log format ["[FORGE] Make Cargo: %1", _this]; + +if (isNull _cargo) exitWith { diag_log "ERROR: Attempt to create cargo from null object"; }; +if (_taskID == "") exitWith { diag_log "ERROR: No task ID provided for cargo"; }; + +SETPVAR(_cargo,assignedTask,_taskID); +GVAR(allCargo) pushBack _cargo; + +_cargo addEventHandler ["Damaged", { + params ["_unit", "_hitSelection", "_damage", "_hitPartIndex", "_hitPoint", "_shooter", "_projectile"]; + + if (damage _unit >= 0.7) then { + private _taskID = GETVAR(_unit,assignedTask,""); + if (_taskID isNotEqualTo "") then { + hint format ["Warning: Cargo severely damaged! Task: %1", _taskID]; + }; + }; +}]; \ No newline at end of file diff --git a/addons/task/functions/fnc_makeHVT.sqf b/addons/task/functions/fnc_makeHVT.sqf index 092a32f..629c1bf 100644 --- a/addons/task/functions/fnc_makeHVT.sqf +++ b/addons/task/functions/fnc_makeHVT.sqf @@ -2,7 +2,7 @@ /* * Author: IDSolutions - * Registers an AI unit as a hvt + * Assigns an AI unit to a task as a hvt * * Arguments: * 0: The AI unit @@ -17,11 +17,14 @@ * Public: Yes */ -params [["_entity", nil, [objNull, 0, [], sideUnknown, grpNull, ""]], ["_taskID", "", [""]]]; +params [["_entity", objNull, [objNull, grpNull]], ["_taskID", "", [""]]]; + +if (isNull _entity) exitWith { diag_log "ERROR: Attempt to create entity from null object"; }; +if (_taskID == "") exitWith { diag_log "ERROR: No task ID provided for entity"; }; + +diag_log format ["[FORGE] Make HVT: %1", _this]; SETVAR(_entity,assignedTask,_taskID); GVAR(allHVTs) pushBackUnique _entity; -if (alive _entity) then { - [_entity, "hvt"] spawn FUNC(heartBeat); -}; \ No newline at end of file +if (alive _entity) then { [_entity, "hvt"] spawn FUNC(heartBeat); }; \ No newline at end of file diff --git a/addons/task/functions/fnc_makeHostage.sqf b/addons/task/functions/fnc_makeHostage.sqf index 0bb8d43..2c13aa7 100644 --- a/addons/task/functions/fnc_makeHostage.sqf +++ b/addons/task/functions/fnc_makeHostage.sqf @@ -2,7 +2,7 @@ /* * Author: IDSolutions - * Registers an AI unit as a hostage/POW + * Assigns an AI unit to a task as a hostage * * Arguments: * 0: The AI unit @@ -17,13 +17,14 @@ * Public: Yes */ -params [["_entity", nil, [objNull, 0, [], sideUnknown, grpNull, ""]], ["_taskID", "", [""]]]; +params [["_entity", objNull, [objNull, grpNull]], ["_taskID", "", [""]]]; + +if (isNull _entity) exitWith { diag_log "ERROR: Attempt to create entity from null object"; }; +if (_taskID == "") exitWith { diag_log "ERROR: No task ID provided for entity"; }; diag_log format ["[FORGE] Make Hostage: %1", _this]; SETVAR(_entity,assignedTask,_taskID); GVAR(allHostages) pushBackUnique _entity; -if (alive _entity) then { - [_entity, "hostage"] spawn FUNC(heartBeat); -}; \ No newline at end of file +if (alive _entity) then { [_entity, "hostage"] spawn FUNC(heartBeat); }; \ No newline at end of file diff --git a/addons/task/functions/fnc_makeIED.sqf b/addons/task/functions/fnc_makeIED.sqf index ae7e28d..54e907e 100644 --- a/addons/task/functions/fnc_makeIED.sqf +++ b/addons/task/functions/fnc_makeIED.sqf @@ -2,7 +2,7 @@ /* * Author: IDSolutions - * Registers an IED and starts countdown timer + * Assigns an IED to a task and starts countdown timer * * Arguments: * 0: The object @@ -18,9 +18,15 @@ * Public: Yes */ -params [["_entity", nil, [objNull, 0, [], sideUnknown, grpNull, ""]], ["_taskID", "", [""]], ["_time", 0, [0]]]; +params [["_entity", objNull, [objNull]], ["_taskID", "", [""]], ["_time", 0, [0]]]; + +if (isNull _entity) exitWith { diag_log "ERROR: Attempt to create entity from null object"; }; +if (_taskID == "") exitWith { diag_log "ERROR: No task ID provided for entity"; }; +if (_time < 0) exitWith { diag_log "ERROR: Invalid time provided for IED"; }; + +diag_log format ["[FORGE] Make IED: %1", _this]; SETVAR(_entity,assignedTask,_taskID); GVAR(allIEDs) pushBackUnique _entity; -[_entity, "ied", _time] spawn FUNC(heartBeat); \ No newline at end of file +if (alive _entity) then { [_entity, "ied", _time] spawn FUNC(heartBeat); }; \ No newline at end of file diff --git a/addons/task/functions/fnc_makeObject.sqf b/addons/task/functions/fnc_makeObject.sqf index a0b0f8c..a0e7aa0 100644 --- a/addons/task/functions/fnc_makeObject.sqf +++ b/addons/task/functions/fnc_makeObject.sqf @@ -2,7 +2,7 @@ /* * Author: IDSolutions - * Registers an object + * Assigns an object to a task as a protected target * * Arguments: * 0: The object @@ -17,7 +17,12 @@ * Public: Yes */ -params [["_entity", nil, [objNull, 0, [], sideUnknown, grpNull, ""]], ["_taskID", "", [""]]]; +params [["_entity", objNull, [objNull]], ["_taskID", "", [""]]]; -SETVAR(_entity,assignedTask,_taskID); +if (isNull _entity) exitWith { diag_log "ERROR: Attempt to create entity from null object"; }; +if (_taskID == "") exitWith { diag_log "ERROR: No task ID provided for entity"; }; + +diag_log format ["[FORGE] Make Object: %1", _this]; + +SETPVAR(_entity,assignedTask,_taskID); GVAR(allEntities) pushBackUnique _entity; \ No newline at end of file diff --git a/addons/task/functions/fnc_makeShooter.sqf b/addons/task/functions/fnc_makeShooter.sqf index 656b943..5de606b 100644 --- a/addons/task/functions/fnc_makeShooter.sqf +++ b/addons/task/functions/fnc_makeShooter.sqf @@ -2,7 +2,7 @@ /* * Author: IDSolutions - * Registers an AI unit as a shooter + * Assigns an AI unit to a task as a shooter * * Arguments: * 0: The AI unit @@ -17,7 +17,10 @@ * Public: Yes */ -params [["_entity", nil, [objNull, 0, [], sideUnknown, grpNull, ""]], ["_taskID", "", [""]]]; +params [["_entity", objNull, [objNull, grpNull]], ["_taskID", "", [""]]]; + +if (isNull _entity) exitWith { diag_log "ERROR: Attempt to create entity from null object"; }; +if (_taskID == "") exitWith { diag_log "ERROR: No task ID provided for entity"; }; diag_log format ["[FORGE] Make Shooter: %1", _this]; diff --git a/addons/task/functions/fnc_makeTarget.sqf b/addons/task/functions/fnc_makeTarget.sqf index dbd501e..5f2fb0a 100644 --- a/addons/task/functions/fnc_makeTarget.sqf +++ b/addons/task/functions/fnc_makeTarget.sqf @@ -2,10 +2,10 @@ /* * Author: IDSolutions - * Registers an AI unit as a target + * Assigns an object to a task as a target * * Arguments: - * 0: The AI unit + * 0: The object * 1: ID of the task * * Return Value: @@ -17,7 +17,12 @@ * Public: Yes */ -params [["_entity", nil, [objNull, 0, [], sideUnknown, grpNull, ""]], ["_taskID", "", [""]]]; +params [["_entity", objNull, [objNull, grpNull]], ["_taskID", "", [""]]]; + +if (isNull _entity) exitWith { diag_log "ERROR: Attempt to create entity from null object"; }; +if (_taskID == "") exitWith { diag_log "ERROR: No task ID provided for entity"; }; + +diag_log format ["[FORGE] Make Target: %1", _this]; SETVAR(_entity,assignedTask,_taskID); GVAR(allTargets) pushBackUnique _entity; \ No newline at end of file