Implement org credit line debt and bank repayment flow #2
@ -4,7 +4,7 @@
|
||||
* File: fnc_handleUIEvents.sqf
|
||||
* Author: IDSolutions
|
||||
* Date: 2026-01-28
|
||||
* Last Update: 2026-02-17
|
||||
* Last Update: 2026-03-28
|
||||
* Public: No
|
||||
*
|
||||
* Description:
|
||||
@ -35,6 +35,7 @@ switch (_event) do {
|
||||
case "actor::close::menu": { closeDialog 1; };
|
||||
case "actor::open::atm": { [true] spawn EFUNC(bank,openUI); };
|
||||
case "actor::open::bank": { [] spawn EFUNC(bank,openUI); };
|
||||
case "actor::open::cad": { [] spawn EFUNC(cad,openUI); };
|
||||
case "actor::open::device": { hint "Device interaction is not yet implemented."; };
|
||||
case "actor::open::garage": { [] spawn EFUNC(garage,openUI); };
|
||||
case "actor::open::vgarage": { [] spawn EFUNC(garage,openVG); };
|
||||
|
||||
@ -100,6 +100,12 @@ const actions = {
|
||||
//=============================================================================
|
||||
|
||||
const baseMenuItems = [
|
||||
{
|
||||
id: "cad",
|
||||
title: "CAD",
|
||||
description: "Access CAD (Computer Aided Dispatch)",
|
||||
action: "actor::open::cad",
|
||||
},
|
||||
{
|
||||
id: "phone",
|
||||
title: "Phone",
|
||||
@ -133,6 +139,12 @@ const actionDefinitions = {
|
||||
description: "Access your bank account and manage finances",
|
||||
action: "actor::open::bank",
|
||||
},
|
||||
cad: {
|
||||
id: "cad",
|
||||
title: "CAD",
|
||||
description: "Access the CAD",
|
||||
action: "actor::open::cad",
|
||||
},
|
||||
phone: {
|
||||
id: "phone",
|
||||
title: "Phone",
|
||||
|
||||
1
arma/client/addons/cad/$PBOPREFIX$
Normal file
1
arma/client/addons/cad/$PBOPREFIX$
Normal file
@ -0,0 +1 @@
|
||||
forge\forge_client\addons\cad
|
||||
12
arma/client/addons/cad/CfgEventHandlers.hpp
Normal file
12
arma/client/addons/cad/CfgEventHandlers.hpp
Normal file
@ -0,0 +1,12 @@
|
||||
class Extended_PreInit_EventHandlers {
|
||||
class ADDON {
|
||||
init = QUOTE(call COMPILE_SCRIPT(XEH_preInit));
|
||||
clientInit = QUOTE(call COMPILE_SCRIPT(XEH_preInitClient));
|
||||
};
|
||||
};
|
||||
|
||||
class Extended_PostInit_EventHandlers {
|
||||
class ADDON {
|
||||
clientInit = QUOTE(call COMPILE_SCRIPT(XEH_postInitClient));
|
||||
};
|
||||
};
|
||||
214
arma/client/addons/cad/MAP_README.md
Normal file
214
arma/client/addons/cad/MAP_README.md
Normal file
@ -0,0 +1,214 @@
|
||||
# Integrated Map Display System (A3API Pattern)
|
||||
|
||||
This system integrates the Arma 3 native map control (`RscMapControl`) within an HTML/CSS/JS UI using Arma's proper WebBrowser control (type 106) and A3API communication pattern.
|
||||
|
||||
## How It Works
|
||||
|
||||
### Layered Architecture
|
||||
|
||||
1. **IFrame Control (type 106)** - Loads HTML content using `ctrlWebBrowserAction`
|
||||
2. **Map Control (RscMapControl)** - Native Arma map positioned behind/within the UI
|
||||
3. **A3API Communication** - Bidirectional communication between JavaScript and SQF
|
||||
|
||||
### Communication Flow
|
||||
|
||||
**JavaScript → SQF:**
|
||||
```javascript
|
||||
// Send alert (no response expected)
|
||||
A3API.SendAlert(JSON.stringify({
|
||||
event: "map::zoomIn",
|
||||
data: null
|
||||
}));
|
||||
|
||||
// Send confirm (expects response via ExecJS)
|
||||
A3API.SendConfirm(JSON.stringify({
|
||||
event: "map::getPosition",
|
||||
data: null
|
||||
}));
|
||||
```
|
||||
|
||||
**SQF → JavaScript:**
|
||||
```sqf
|
||||
_control ctrlWebBrowserAction ["ExecJS", "updateMapState({center: [1000, 2000], scale: 0.5});"];
|
||||
```
|
||||
|
||||
## File Structure
|
||||
|
||||
```
|
||||
UI/map/
|
||||
├── _site/
|
||||
│ ├── index.html # HTML with A3API dynamic loading
|
||||
│ ├── script.js # JavaScript using A3API
|
||||
│ └── style.css # Styling
|
||||
└── MAP_README.md # This file
|
||||
|
||||
functions/map/
|
||||
├── fn_openMap.sqf # Opens the display
|
||||
├── fn_mapHandleUIEvents.sqf # Handles JS events
|
||||
├── fn_mapDisplay.sqf # Display initialization
|
||||
└── fn_mapDisplayUpdate.sqf # Update loop
|
||||
|
||||
UI/MapDisplay.h # Dialog definition
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
### Opening the Map
|
||||
|
||||
```sqf
|
||||
[] call FORGE_fnc_openMap;
|
||||
```
|
||||
|
||||
### From Init or Action
|
||||
|
||||
```sqf
|
||||
// Add player action
|
||||
player addAction ["Open Map", {[] call FORGE_fnc_openMap;}];
|
||||
|
||||
// In init.sqf
|
||||
[] call FORGE_fnc_openMap;
|
||||
```
|
||||
|
||||
## Key Differences from Standard HTML/CSS/JS
|
||||
|
||||
### 1. Dynamic Resource Loading
|
||||
|
||||
Instead of `<link>` and `<script>` tags, files are loaded using A3API:
|
||||
|
||||
```html
|
||||
<script>
|
||||
Promise.all([
|
||||
A3API.RequestFile("UI\\map\\_site\\style.css"),
|
||||
A3API.RequestFile("UI\\map\\_site\\script.js")
|
||||
]).then(([css, js]) => {
|
||||
// Apply CSS
|
||||
const style = document.createElement('style');
|
||||
style.textContent = css;
|
||||
document.head.appendChild(style);
|
||||
|
||||
// Execute JavaScript
|
||||
const script = document.createElement('script');
|
||||
script.text = js;
|
||||
document.head.appendChild(script);
|
||||
});
|
||||
</script>
|
||||
```
|
||||
|
||||
### 2. Event Communication
|
||||
|
||||
Use **A3API.SendAlert()** for one-way messages:
|
||||
```javascript
|
||||
A3API.SendAlert(JSON.stringify({event: "map::action", data: value}));
|
||||
```
|
||||
|
||||
Use **A3API.SendConfirm()** for messages expecting a response:
|
||||
```javascript
|
||||
A3API.SendConfirm(JSON.stringify({event: "map::getdata", data: null}));
|
||||
```
|
||||
|
||||
### 3. Pointer Events
|
||||
|
||||
UI elements need `pointer-events: auto` while the body has `pointer-events: none`:
|
||||
|
||||
```css
|
||||
body {
|
||||
pointer-events: none; /* Allows clicks through to map */
|
||||
}
|
||||
|
||||
#topBar {
|
||||
pointer-events: auto; /* UI elements catch clicks */
|
||||
}
|
||||
```
|
||||
|
||||
## Dialog Definition Pattern
|
||||
|
||||
```cpp
|
||||
class RscMapDisplay {
|
||||
idd = 9000;
|
||||
onLoad = "['onLoad', _this] call FORGE_fnc_mapDisplay;";
|
||||
|
||||
class Controls {
|
||||
class Browser: RscText {
|
||||
type = 106; // IFrame control type
|
||||
idc = 9001;
|
||||
x = "safeZoneX";
|
||||
y = "safeZoneY";
|
||||
w = "safeZoneW";
|
||||
h = "safeZoneH";
|
||||
};
|
||||
|
||||
class MapControl: RscMapControl {
|
||||
idc = 9002;
|
||||
// Position to fit within HTML UI
|
||||
};
|
||||
};
|
||||
};
|
||||
```
|
||||
|
||||
## Event Handler Pattern
|
||||
|
||||
In `fn_openMap.sqf`:
|
||||
```sqf
|
||||
private _ctrl = _display displayCtrl 9001;
|
||||
|
||||
// Add JSDialog event handler
|
||||
_ctrl ctrlAddEventHandler ["JSDialog", {
|
||||
params ["_control", "_isConfirmDialog", "_message"];
|
||||
[_control, _isConfirmDialog, _message] call FORGE_fnc_mapHandleUIEvents;
|
||||
}];
|
||||
|
||||
// Load HTML file
|
||||
_ctrl ctrlWebBrowserAction ["LoadFile", "UI\\map\\_site\\index.html"];
|
||||
```
|
||||
|
||||
In `fn_mapHandleUIEvents.sqf`:
|
||||
```sqf
|
||||
params ["_control", "_isConfirmDialog", "_message"];
|
||||
|
||||
private _eventData = fromJSON _message;
|
||||
private _event = _eventData get "event";
|
||||
private _data = _eventData get "data";
|
||||
|
||||
switch (_event) do {
|
||||
case "map::ready": {
|
||||
// Initialize
|
||||
};
|
||||
case "map::zoomIn": {
|
||||
// Handle zoom
|
||||
};
|
||||
};
|
||||
```
|
||||
|
||||
## Benefits of This Pattern
|
||||
|
||||
1. **Proper Arma Integration** - Uses native WebBrowser control (type 106)
|
||||
2. **File System Compatibility** - A3API.RequestFile() works with Arma's file system
|
||||
3. **Reliable Communication** - JSDialog event handler is more stable than htmlLoad
|
||||
4. **Modular** - CSS and JS in separate files, dynamically loaded
|
||||
5. **Consistent** - Matches bank module pattern used in FORGE
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
**Files not loading:**
|
||||
- Check paths use double backslashes: `"UI\\map\\_site\\style.css"`
|
||||
- Verify files exist in the correct directory
|
||||
- Check .rpt log for file loading errors
|
||||
|
||||
**Events not firing:**
|
||||
- Verify JSDialog event handler is attached
|
||||
- Check JSON formatting in A3API calls
|
||||
- Look for JavaScript console errors (use OpenDevConsole)
|
||||
|
||||
**Map not showing:**
|
||||
- Verify MapControl idc matches (9002)
|
||||
- Check map control positioning in MapDisplay.h
|
||||
- Ensure map control is rendered after browser control
|
||||
|
||||
## Developer Tools
|
||||
|
||||
Enable dev console in `fn_openMap.sqf`:
|
||||
```sqf
|
||||
_ctrl ctrlWebBrowserAction ["OpenDevConsole"];
|
||||
```
|
||||
|
||||
This opens Chromium dev tools for debugging JavaScript, CSS, and network requests.
|
||||
5
arma/client/addons/cad/XEH_PREP.hpp
Normal file
5
arma/client/addons/cad/XEH_PREP.hpp
Normal file
@ -0,0 +1,5 @@
|
||||
PREP(handleUIEvents);
|
||||
PREP(initRepository);
|
||||
PREP(initUIBridge);
|
||||
PREP(initUI);
|
||||
PREP(openUI);
|
||||
24
arma/client/addons/cad/XEH_postInitClient.sqf
Normal file
24
arma/client/addons/cad/XEH_postInitClient.sqf
Normal file
@ -0,0 +1,24 @@
|
||||
#include "script_component.hpp"
|
||||
|
||||
if (isNil QGVAR(CADRepository)) then { call FUNC(initRepository); };
|
||||
if (isNil QGVAR(CADUIBridge)) then { call FUNC(initUIBridge); };
|
||||
|
||||
[QGVAR(openCAD), {
|
||||
call FUNC(openUI);
|
||||
}] call CFUNC(addEventHandler);
|
||||
|
||||
[QGVAR(responseTaskCatalog), {
|
||||
params [["_entries", [], [[]]]];
|
||||
|
||||
if !(isNil QGVAR(CADRepository)) then {
|
||||
GVAR(CADRepository) call ["setTaskCatalog", [_entries]];
|
||||
};
|
||||
|
||||
GVAR(CADUIBridge) call ["refreshTaskCatalog", []];
|
||||
}] call CFUNC(addEventHandler);
|
||||
|
||||
[QGVAR(responseTaskAccept), {
|
||||
params [["_result", createHashMap, [createHashMap]]];
|
||||
|
||||
GVAR(CADUIBridge) call ["handleTaskAcceptResponse", [_result]];
|
||||
}] call CFUNC(addEventHandler);
|
||||
5
arma/client/addons/cad/XEH_preInit.sqf
Normal file
5
arma/client/addons/cad/XEH_preInit.sqf
Normal file
@ -0,0 +1,5 @@
|
||||
#include "script_component.hpp"
|
||||
|
||||
PREP_RECOMPILE_START;
|
||||
#include "XEH_PREP.hpp"
|
||||
PREP_RECOMPILE_END;
|
||||
1
arma/client/addons/cad/XEH_preInitClient.sqf
Normal file
1
arma/client/addons/cad/XEH_preInitClient.sqf
Normal file
@ -0,0 +1 @@
|
||||
#include "script_component.hpp"
|
||||
21
arma/client/addons/cad/config.cpp
Normal file
21
arma/client/addons/cad/config.cpp
Normal file
@ -0,0 +1,21 @@
|
||||
#include "script_component.hpp"
|
||||
|
||||
class CfgPatches {
|
||||
class ADDON {
|
||||
author = AUTHOR;
|
||||
authors[] = {"IDSolutions"};
|
||||
url = ECSTRING(main,url);
|
||||
name = COMPONENT_NAME;
|
||||
requiredVersion = REQUIRED_VERSION;
|
||||
requiredAddons[] = {
|
||||
"forge_client_main"
|
||||
};
|
||||
units[] = {};
|
||||
weapons[] = {};
|
||||
VERSION_CONFIG;
|
||||
};
|
||||
};
|
||||
|
||||
#include "CfgEventHandlers.hpp"
|
||||
#include "ui\RscCommon.hpp"
|
||||
#include "ui\RscMapUI.hpp"
|
||||
87
arma/client/addons/cad/functions/fnc_handleUIEvents.sqf
Normal file
87
arma/client/addons/cad/functions/fnc_handleUIEvents.sqf
Normal file
@ -0,0 +1,87 @@
|
||||
#include "..\script_component.hpp"
|
||||
|
||||
/*
|
||||
* File: fnc_handleUIEvents.sqf
|
||||
* Author: IDSolutions
|
||||
* Date: 2026-03-28
|
||||
* Public: No
|
||||
*
|
||||
* Description:
|
||||
* Handles CAD browser UI events.
|
||||
*
|
||||
* Arguments:
|
||||
* 0: Control [CONTROL]
|
||||
* 1: Confirm dialog flag [BOOL]
|
||||
* 2: Browser message [STRING]
|
||||
*
|
||||
* Return Value:
|
||||
* UI event handled [BOOL]
|
||||
*
|
||||
* Example:
|
||||
* [_control, false, _message] call forge_client_cad_fnc_handleUIEvents
|
||||
*/
|
||||
|
||||
params ["_control", "_isConfirmDialog", "_message"];
|
||||
|
||||
private _alert = fromJSON _message;
|
||||
private _event = _alert getOrDefault ["event", ""];
|
||||
private _data = _alert getOrDefault ["data", nil];
|
||||
|
||||
diag_log format ["[FORGE:Client:CAD] Handling UI event: %1", _event];
|
||||
|
||||
if (_isConfirmDialog) exitWith { true };
|
||||
|
||||
switch (_event) do {
|
||||
case "cad::ready": {
|
||||
GVAR(CADUIBridge) call ["handleReady", [_control, _data]];
|
||||
};
|
||||
case "cad::tasks::refresh": {
|
||||
GVAR(CADUIBridge) call ["requestTaskCatalog", []];
|
||||
};
|
||||
case "cad::tasks::accept": {
|
||||
private _taskID = "";
|
||||
if (_data isEqualType createHashMap) then {
|
||||
_taskID = _data getOrDefault ["taskID", ""];
|
||||
};
|
||||
|
||||
GVAR(CADUIBridge) call ["requestTaskAccept", [_taskID]];
|
||||
};
|
||||
case "map::zoomIn": {
|
||||
private _mapCtrl = uiNamespace getVariable [QGVAR(MapCtrl), controlNull];
|
||||
if (isNull _mapCtrl) exitWith {};
|
||||
|
||||
private _currentZoom = ctrlMapScale _mapCtrl;
|
||||
private _newZoom = (_currentZoom * 0.5) max 0.001;
|
||||
private _center = _mapCtrl ctrlMapScreenToWorld [0.5, 0.5];
|
||||
_mapCtrl ctrlMapAnimAdd [0.3, _newZoom, _center];
|
||||
ctrlMapAnimCommit _mapCtrl;
|
||||
};
|
||||
case "map::zoomOut": {
|
||||
private _mapCtrl = uiNamespace getVariable [QGVAR(MapCtrl), controlNull];
|
||||
if (isNull _mapCtrl) exitWith {};
|
||||
|
||||
private _currentZoom = ctrlMapScale _mapCtrl;
|
||||
private _newZoom = (_currentZoom * 2) min 1;
|
||||
private _center = _mapCtrl ctrlMapScreenToWorld [0.5, 0.5];
|
||||
_mapCtrl ctrlMapAnimAdd [0.3, _newZoom, _center];
|
||||
ctrlMapAnimCommit _mapCtrl;
|
||||
};
|
||||
case "map::search": {
|
||||
private _query = str _data;
|
||||
private _bottomBar = uiNamespace getVariable [QGVAR(BottomBarCtrl), controlNull];
|
||||
if (isNull _bottomBar) exitWith {};
|
||||
|
||||
_bottomBar ctrlWebBrowserAction ["ExecJS", format ["updateStatus('Search not yet implemented: %1');", _query]];
|
||||
};
|
||||
case "map::close": {
|
||||
if !(isNil QGVAR(CADUIBridge)) then {
|
||||
GVAR(CADUIBridge) call ["handleClose", []];
|
||||
};
|
||||
closeDialog 1;
|
||||
};
|
||||
default {
|
||||
diag_log format ["[FORGE:Client:CAD] WARNING: Unhandled UI event: %1", _event];
|
||||
};
|
||||
};
|
||||
|
||||
true
|
||||
52
arma/client/addons/cad/functions/fnc_initRepository.sqf
Normal file
52
arma/client/addons/cad/functions/fnc_initRepository.sqf
Normal file
@ -0,0 +1,52 @@
|
||||
#include "..\script_component.hpp"
|
||||
|
||||
/*
|
||||
* File: fnc_initRepository.sqf
|
||||
* Author: IDSolutions
|
||||
* Date: 2026-03-28
|
||||
* Public: No
|
||||
*
|
||||
* Description:
|
||||
* Initializes the CAD repository for lightweight client lifecycle state.
|
||||
*
|
||||
* Arguments:
|
||||
* None
|
||||
*
|
||||
* Return Value:
|
||||
* CAD repository object [HASHMAP OBJECT]
|
||||
*
|
||||
* Example:
|
||||
* call forge_client_cad_fnc_initRepository
|
||||
*/
|
||||
|
||||
#pragma hemtt ignore_variables ["_self"]
|
||||
GVAR(CADRepository) = createHashMapObject [[
|
||||
["#type", "CADRepository"],
|
||||
["#create", compileFinal {
|
||||
_self set ["isLoaded", true];
|
||||
_self set ["isOpen", false];
|
||||
_self set ["taskCatalog", []];
|
||||
}],
|
||||
["pushTaskCatalog", compileFinal {
|
||||
params [["_bridge", createHashMap, [createHashMap]]];
|
||||
|
||||
if (_bridge isEqualTo createHashMap) exitWith { false };
|
||||
|
||||
_bridge call ["sendEvent", ["cad::tasks::hydrate", createHashMapFromArray [
|
||||
["tasks", +(_self getOrDefault ["taskCatalog", []])]
|
||||
]]]
|
||||
}],
|
||||
["setTaskCatalog", compileFinal {
|
||||
params [["_entries", [], [[]]]];
|
||||
|
||||
_self set ["taskCatalog", +_entries];
|
||||
true
|
||||
}],
|
||||
["setOpen", compileFinal {
|
||||
params [["_isOpen", false, [false]]];
|
||||
_self set ["isOpen", _isOpen];
|
||||
true
|
||||
}]
|
||||
]];
|
||||
|
||||
GVAR(CADRepository)
|
||||
90
arma/client/addons/cad/functions/fnc_initUI.sqf
Normal file
90
arma/client/addons/cad/functions/fnc_initUI.sqf
Normal file
@ -0,0 +1,90 @@
|
||||
#include "..\script_component.hpp"
|
||||
|
||||
/*
|
||||
* File: fnc_initUI.sqf
|
||||
* Author: IDSolutions
|
||||
* Date: 2026-03-28
|
||||
* Public: No
|
||||
*
|
||||
* Description:
|
||||
* Initializes the CAD map dialog controls and local map event handling.
|
||||
*
|
||||
* Arguments:
|
||||
* 0: Display [DISPLAY]
|
||||
*
|
||||
* Return Value:
|
||||
* UI initialized [BOOL]
|
||||
*
|
||||
* Example:
|
||||
* [_display] call forge_client_cad_fnc_initUI
|
||||
*/
|
||||
|
||||
params [["_display", displayNull, [displayNull]]];
|
||||
|
||||
if (isNull _display) exitWith { false };
|
||||
|
||||
private _mapCtrl = _display displayCtrl 1001;
|
||||
private _topBarCtrl = _display displayCtrl 1002;
|
||||
private _bottomBarCtrl = _display displayCtrl 1003;
|
||||
private _sidePanelCtrl = _display displayCtrl 1005;
|
||||
|
||||
uiNamespace setVariable [QGVAR(Display), _display];
|
||||
uiNamespace setVariable [QGVAR(MapCtrl), _mapCtrl];
|
||||
uiNamespace setVariable [QGVAR(TopBarCtrl), _topBarCtrl];
|
||||
uiNamespace setVariable [QGVAR(BottomBarCtrl), _bottomBarCtrl];
|
||||
uiNamespace setVariable [QGVAR(SidePanelCtrl), _sidePanelCtrl];
|
||||
|
||||
private _center = if (isNull player) then {
|
||||
[worldSize / 2, worldSize / 2, 0]
|
||||
} else {
|
||||
getPosATL player
|
||||
};
|
||||
|
||||
_mapCtrl ctrlMapAnimAdd [0, 0.2, _center];
|
||||
ctrlMapAnimCommit _mapCtrl;
|
||||
|
||||
_mapCtrl ctrlAddEventHandler ["MouseButtonClick", {
|
||||
params ["_ctrl", "_button", "_xPos", "_yPos"];
|
||||
|
||||
private _worldPos = _ctrl ctrlMapScreenToWorld [_xPos, _yPos];
|
||||
private _bottomBar = uiNamespace getVariable [QGVAR(BottomBarCtrl), controlNull];
|
||||
if (isNull _bottomBar) exitWith {};
|
||||
|
||||
private _jsCode = format [
|
||||
"updateStatus('Clicked at: %1, %2');",
|
||||
round (_worldPos # 0),
|
||||
round (_worldPos # 1)
|
||||
];
|
||||
_bottomBar ctrlWebBrowserAction ["ExecJS", _jsCode];
|
||||
}];
|
||||
|
||||
_mapCtrl ctrlAddEventHandler ["MouseMoving", {
|
||||
params ["_ctrl", "_xPos", "_yPos"];
|
||||
|
||||
private _worldPos = _ctrl ctrlMapScreenToWorld [_xPos, _yPos];
|
||||
private _topBar = uiNamespace getVariable [QGVAR(TopBarCtrl), controlNull];
|
||||
if (isNull _topBar) exitWith {};
|
||||
|
||||
private _jsCode = format [
|
||||
"updateCoordinates(%1, %2);",
|
||||
_worldPos # 0,
|
||||
_worldPos # 1
|
||||
];
|
||||
_topBar ctrlWebBrowserAction ["ExecJS", _jsCode];
|
||||
}];
|
||||
|
||||
[] spawn {
|
||||
while { !isNull (uiNamespace getVariable [QGVAR(Display), displayNull]) } do {
|
||||
private _mapCtrl = uiNamespace getVariable [QGVAR(MapCtrl), controlNull];
|
||||
private _topBar = uiNamespace getVariable [QGVAR(TopBarCtrl), controlNull];
|
||||
|
||||
if (!isNull _mapCtrl && { !isNull _topBar }) then {
|
||||
_topBar ctrlWebBrowserAction ["ExecJS", format ["updateScale(%1);", round (ctrlMapScale _mapCtrl)]];
|
||||
};
|
||||
|
||||
sleep 0.5;
|
||||
};
|
||||
};
|
||||
|
||||
diag_log "[FORGE:Client:CAD] CAD UI initialized.";
|
||||
true
|
||||
84
arma/client/addons/cad/functions/fnc_initUIBridge.sqf
Normal file
84
arma/client/addons/cad/functions/fnc_initUIBridge.sqf
Normal file
@ -0,0 +1,84 @@
|
||||
#include "..\script_component.hpp"
|
||||
|
||||
/*
|
||||
* File: fnc_initUIBridge.sqf
|
||||
* Author: IDSolutions
|
||||
* Date: 2026-03-28
|
||||
* Public: No
|
||||
*
|
||||
* Description:
|
||||
* Initializes the CAD UI bridge for sidepanel browser state and task event routing.
|
||||
*
|
||||
* Arguments:
|
||||
* None
|
||||
*
|
||||
* Return Value:
|
||||
* CAD UI bridge object [HASHMAP OBJECT]
|
||||
*
|
||||
* Example:
|
||||
* call forge_client_cad_fnc_initUIBridge
|
||||
*/
|
||||
|
||||
#pragma hemtt ignore_variables ["_self"]
|
||||
private _webUIDeclarations = call EFUNC(common,initWebUIBridge);
|
||||
private _webUIBridgeDeclaration = _webUIDeclarations get "bridgeDeclaration";
|
||||
|
||||
GVAR(CADUIBridgeBaseClass) = compileFinal createHashMapFromArray [
|
||||
["#base", _webUIBridgeDeclaration],
|
||||
["#type", "CADUIBridgeBaseClass"],
|
||||
["getActiveBrowserControl", compileFinal {
|
||||
private _display = uiNamespace getVariable [QGVAR(Display), displayNull];
|
||||
if (isNull _display) exitWith {
|
||||
_self call ["setActiveBrowserControl", [controlNull]];
|
||||
controlNull
|
||||
};
|
||||
|
||||
private _control = _display displayCtrl 1005;
|
||||
_self call ["setActiveBrowserControl", [_control]];
|
||||
_control
|
||||
}],
|
||||
["hasOpenScreen", compileFinal {
|
||||
private _screen = _self call ["getScreen", []];
|
||||
private _control = _self call ["getActiveBrowserControl", []];
|
||||
!(isNull _control) && { _screen call ["isReady", []] }
|
||||
}],
|
||||
["handleReady", compileFinal {
|
||||
params [["_control", controlNull, [controlNull]], ["_data", createHashMap, [createHashMap]]];
|
||||
|
||||
private _screen = _self call ["getScreen", []];
|
||||
_screen call ["setControl", [_control]];
|
||||
_screen call ["markReady", [true]];
|
||||
_self call ["flushPendingEvents", []];
|
||||
|
||||
_self call ["requestTaskCatalog", []];
|
||||
_self call ["refreshTaskCatalog", []];
|
||||
true
|
||||
}],
|
||||
["requestTaskCatalog", compileFinal {
|
||||
[SRPC(task,requestTaskCatalog), [getPlayerUID player]] call CFUNC(serverEvent);
|
||||
true
|
||||
}],
|
||||
["requestTaskAccept", compileFinal {
|
||||
params [["_taskID", "", [""]]];
|
||||
|
||||
if (_taskID isEqualTo "") exitWith { false };
|
||||
|
||||
[SRPC(task,requestAcceptTask), [getPlayerUID player, _taskID]] call CFUNC(serverEvent);
|
||||
true
|
||||
}],
|
||||
["refreshTaskCatalog", compileFinal {
|
||||
if (isNil QGVAR(CADRepository)) exitWith { false };
|
||||
GVAR(CADRepository) call ["pushTaskCatalog", [_self]]
|
||||
}],
|
||||
["handleTaskAcceptResponse", compileFinal {
|
||||
params [["_result", createHashMap, [createHashMap]]];
|
||||
|
||||
_self call ["sendEvent", ["cad::tasks::accept::response", createHashMapFromArray [
|
||||
["message", _result getOrDefault ["message", "Task request processed."]],
|
||||
["success", _result getOrDefault ["success", false]]
|
||||
]]]
|
||||
}]
|
||||
];
|
||||
|
||||
GVAR(CADUIBridge) = createHashMapObject [GVAR(CADUIBridgeBaseClass)];
|
||||
GVAR(CADUIBridge)
|
||||
47
arma/client/addons/cad/functions/fnc_openUI.sqf
Normal file
47
arma/client/addons/cad/functions/fnc_openUI.sqf
Normal file
@ -0,0 +1,47 @@
|
||||
#include "..\script_component.hpp"
|
||||
|
||||
/*
|
||||
* File: fnc_openUI.sqf
|
||||
* Author: IDSolutions
|
||||
* Date: 2026-03-28
|
||||
* Public: No
|
||||
*
|
||||
* Description:
|
||||
* Opens the CAD map interface.
|
||||
*
|
||||
* Arguments:
|
||||
* None
|
||||
*
|
||||
* Return Value:
|
||||
* UI opened [BOOL]
|
||||
*
|
||||
* Example:
|
||||
* call forge_client_cad_fnc_openUI
|
||||
*/
|
||||
|
||||
private _display = createDialog ["RscMapUI", true];
|
||||
if (isNull _display) exitWith {
|
||||
diag_log "[FORGE:Client:CAD] ERROR: Failed to create CAD dialog.";
|
||||
false
|
||||
};
|
||||
|
||||
private _topBarCtrl = _display displayCtrl 1002;
|
||||
private _bottomBarCtrl = _display displayCtrl 1003;
|
||||
private _sidePanelCtrl = _display displayCtrl 1005;
|
||||
|
||||
{
|
||||
_x ctrlAddEventHandler ["JSDialog", {
|
||||
params ["_control", "_isConfirmDialog", "_message"];
|
||||
[_control, _isConfirmDialog, _message] call FUNC(handleUIEvents);
|
||||
}];
|
||||
} forEach [_topBarCtrl, _bottomBarCtrl, _sidePanelCtrl];
|
||||
|
||||
_topBarCtrl ctrlWebBrowserAction ["LoadFile", QPATHTOF2(ui\_site\topbar.html)];
|
||||
_bottomBarCtrl ctrlWebBrowserAction ["LoadFile", QPATHTOF2(ui\_site\bottombar.html)];
|
||||
_sidePanelCtrl ctrlWebBrowserAction ["LoadFile", QPATHTOF2(ui\_site\sidepanel.html)];
|
||||
|
||||
if !(isNil QGVAR(CADRepository)) then {
|
||||
GVAR(CADRepository) call ["setOpen", [true]];
|
||||
};
|
||||
|
||||
true
|
||||
9
arma/client/addons/cad/script_component.hpp
Normal file
9
arma/client/addons/cad/script_component.hpp
Normal file
@ -0,0 +1,9 @@
|
||||
#define COMPONENT cad
|
||||
#define COMPONENT_BEAUTIFIED CAD
|
||||
#include "\forge\forge_client\addons\main\script_mod.hpp"
|
||||
|
||||
// #define DEBUG_MODE_FULL
|
||||
// #define DISABLE_COMPILE_CACHE
|
||||
// #define ENABLE_PERFORMANCE_COUNTERS
|
||||
|
||||
#include "\forge\forge_client\addons\main\script_macros.hpp"
|
||||
6
arma/client/addons/cad/ui/RscCommon.hpp
Normal file
6
arma/client/addons/cad/ui/RscCommon.hpp
Normal file
@ -0,0 +1,6 @@
|
||||
// Control types
|
||||
#define CT_STATIC 0
|
||||
#define CT_MAP 100
|
||||
|
||||
class RscText;
|
||||
class RscMapControl;
|
||||
90
arma/client/addons/cad/ui/RscMapUI.hpp
Normal file
90
arma/client/addons/cad/ui/RscMapUI.hpp
Normal file
@ -0,0 +1,90 @@
|
||||
class RscMapUI {
|
||||
idd = 1004;
|
||||
movingEnable = 0;
|
||||
enableSimulation = 1;
|
||||
fadein = 0;
|
||||
fadeout = 0;
|
||||
duration = 1e+011;
|
||||
onLoad = "uiNamespace setVariable ['forge_client_cad_Display', _this select 0]; [_this select 0] call forge_client_cad_fnc_initUI;";
|
||||
onUnLoad = "uiNamespace setVariable ['forge_client_cad_Display', nil]; uiNamespace setVariable ['forge_client_cad_MapCtrl', nil]; uiNamespace setVariable ['forge_client_cad_TopBarCtrl', nil]; uiNamespace setVariable ['forge_client_cad_BottomBarCtrl', nil]; uiNamespace setVariable ['forge_client_cad_SidePanelCtrl', nil]; if !(isNil 'forge_client_cad_CADRepository') then { forge_client_cad_CADRepository set ['isOpen', false]; };";
|
||||
|
||||
class controlsBackground {
|
||||
class MapControl: RscMapControl {
|
||||
idc = 1001;
|
||||
x = "safeZoneX + (safeZoneW * 0.1)"; // 10% margin (80% width centered)
|
||||
y = "safeZoneY + (safeZoneH * 0.1) + 0.0926"; // 10% margin + 50px top bar
|
||||
w = "safeZoneW * 0.8"; // 80% width
|
||||
h = "(safeZoneH * 0.8) - 0.0926 - 0.0556"; // 80% height minus top and bottom bars
|
||||
|
||||
// Map specific settings
|
||||
maxSatelliteAlpha = 0.85;
|
||||
alphaFadeStartScale = 0.35;
|
||||
alphaFadeEndScale = 0.4;
|
||||
colorBackground[] = {0.969, 0.957, 0.949, 1};
|
||||
colorSea[] = {0.467, 0.631, 0.851, 0.5};
|
||||
colorForest[] = {0.624, 0.78, 0.388, 0.5};
|
||||
colorRocks[] = {0, 0, 0, 0};
|
||||
colorCountlines[] = {0.572, 0.354, 0.318, 0.25};
|
||||
colorMainCountlines[] = {0.572, 0.354, 0.318, 0.5};
|
||||
colorCountlinesWater[] = {0.491, 0.577, 0.702, 0.3};
|
||||
colorMainCountlinesWater[] = {0.491, 0.577, 0.702, 0.6};
|
||||
colorForestBorder[] = {0, 0, 0, 0};
|
||||
colorRocksBorder[] = {0, 0, 0, 0};
|
||||
colorPowerLines[] = {0.1, 0.1, 0.1, 1};
|
||||
colorRailWay[] = {0.8, 0.2, 0, 1};
|
||||
colorNames[] = {0.1, 0.1, 0.1, 0.9};
|
||||
colorInactive[] = {1, 1, 1, 0.5};
|
||||
colorLevels[] = {0.286, 0.177, 0.094, 0.5};
|
||||
colorTracks[] = {0.84, 0.76, 0.65, 0.15};
|
||||
colorRoads[] = {0.7, 0.7, 0.7, 1};
|
||||
colorMainRoads[] = {0.9, 0.5, 0.3, 1};
|
||||
colorTracksFill[] = {0.84, 0.76, 0.65, 1};
|
||||
colorRoadsFill[] = {1, 1, 1, 1};
|
||||
colorMainRoadsFill[] = {1, 0.6, 0.4, 1};
|
||||
colorGrid[] = {0.1, 0.1, 0.1, 0.6};
|
||||
colorGridMap[] = {0.1, 0.1, 0.1, 0.6};
|
||||
colorText[] = {1, 1, 1, 1};
|
||||
font = "PuristaMedium";
|
||||
sizeEx = 0.04;
|
||||
showCountourInterval = 0;
|
||||
scaleMin = 0.001;
|
||||
scaleMax = 1;
|
||||
scaleDefault = 0.16;
|
||||
};
|
||||
};
|
||||
|
||||
class controls {
|
||||
// Top bar browser
|
||||
class TopBarBrowser: RscText {
|
||||
type = 106;
|
||||
idc = 1002;
|
||||
x = "safeZoneX + (safeZoneW * 0.1)";
|
||||
y = "safeZoneY + (safeZoneH * 0.1)";
|
||||
w = "safeZoneW * 0.8";
|
||||
h = "0.0926"; // 50px
|
||||
colorBackground[] = {0, 0, 0, 0};
|
||||
};
|
||||
|
||||
// Bottom bar browser
|
||||
class BottomBarBrowser: RscText {
|
||||
type = 106;
|
||||
idc = 1003;
|
||||
x = "safeZoneX + (safeZoneW * 0.1)";
|
||||
y = "safeZoneY + (safeZoneH * 0.9) - 0.0556";
|
||||
w = "safeZoneW * 0.8";
|
||||
h = "0.0556"; // 30px
|
||||
colorBackground[] = {0, 0, 0, 0};
|
||||
};
|
||||
|
||||
// Side panel browser (overlays from right side of 80% box)
|
||||
class SidePanelBrowser: RscText {
|
||||
type = 106;
|
||||
idc = 1005;
|
||||
x = "safeZoneX + (safeZoneW * 0.1) + (safeZoneW * 0.8) - 0.4630"; // Right edge of 80% box minus panel width
|
||||
y = "safeZoneY + (safeZoneH * 0.1) + 0.0926"; // Below top bar
|
||||
w = "0.4630"; // ~250px width
|
||||
h = "(safeZoneH * 0.8) - 0.0926 - 0.0556"; // Full height minus bars
|
||||
colorBackground[] = {0, 0, 0, 0};
|
||||
};
|
||||
};
|
||||
};
|
||||
1
arma/client/addons/cad/ui/_site/bottombar.html
Normal file
1
arma/client/addons/cad/ui/_site/bottombar.html
Normal file
@ -0,0 +1 @@
|
||||
<!doctype html><html><head><meta charset="UTF-8"></head><body><span id="statusText">Map Ready</span> <span id="selectionInfo"></span><script>window.MapLoader={loadCSS:e=>A3API.RequestFile(e).then(e=>{const o=document.createElement("style");o.textContent=e,document.head.appendChild(o)}),loadJS(path){return A3API.RequestFile(path).then(js=>{eval(js)})},loadAll(e){return e.reduce((e,o)=>e.then(()=>o.endsWith(".css")?this.loadCSS(o):o.endsWith(".js")?this.loadJS(o):Promise.resolve()),Promise.resolve())}},MapLoader.loadAll(["forge\\forge_client\\addons\\cad\\ui\\_site\\cad-common.css","forge\\forge_client\\addons\\cad\\ui\\_site\\cad-bottombar.css","forge\\forge_client\\addons\\cad\\ui\\_site\\cad-shared.js","forge\\forge_client\\addons\\cad\\ui\\_site\\cad-bottombar.js"]).catch(e=>console.error("[BOTTOMBAR] Load error:",e))</script></body></html>
|
||||
1
arma/client/addons/cad/ui/_site/cad-bottombar.css
Normal file
1
arma/client/addons/cad/ui/_site/cad-bottombar.css
Normal file
@ -0,0 +1 @@
|
||||
body{-webkit-backdrop-filter:blur(18px);background:linear-gradient(90deg,#0e131bf5,#121720ed 55%,#0d1219f5);border-top:1px solid #ffffff24;justify-content:space-between;align-items:center;min-height:36px;padding:0 20px;display:flex;position:absolute;bottom:0;left:0;right:0;overflow:hidden;box-shadow:0 -12px 26px #0000003d}span{color:#f5f8ffcc;text-shadow:0 1px 10px #00000047;font-size:12px}#statusText{color:var(--accent);font-weight:600}
|
||||
1
arma/client/addons/cad/ui/_site/cad-bottombar.js
Normal file
1
arma/client/addons/cad/ui/_site/cad-bottombar.js
Normal file
@ -0,0 +1 @@
|
||||
window.CADBottombar=window.CADBottombar||{};
|
||||
1
arma/client/addons/cad/ui/_site/cad-common.css
Normal file
1
arma/client/addons/cad/ui/_site/cad-common.css
Normal file
@ -0,0 +1 @@
|
||||
:root{--bg:#090c12d1;--panel:#141821e6;--panel2:#11151ed1;--stroke:#ffffff1f;--stroke2:#fff3;--text:#f5f8ffeb;--muted:#f5f8ff9e;--muted2:#f5f8ff6b;--accent:#68c4fff2;--danger:#ff6060f2;--shadow:0 20px 60px #0000008c;--radius:14px;--radius2:10px;--font:ui-sans-serif, system-ui, -apple-system, Segoe UI, Roboto, Arial, sans-serif}*{box-sizing:border-box;margin:0;padding:0}body{font-family:var(--font);color:var(--text);background:var(--bg);-webkit-backdrop-filter:blur(16px)}.btn{border-radius:var(--radius2);color:var(--text);cursor:pointer;user-select:none;background:#ffffff08;border:1px solid #ffffff1a;padding:8px 16px;font-size:14px;transition:background .16s,border-color .16s,transform .16s}.btn:hover{background:#ffffff12;border-color:#ffffff29}.btn:active{transform:scale(.98)}.btn-close{color:#ffdcdcf2;background:#ff60601a;border-color:#ff606040;font-weight:700}.btn-close:hover{background:#ff606033;border-color:#ff606059}::-webkit-scrollbar{width:10px}::-webkit-scrollbar-thumb{background:#ffffff1a;border:2px solid #0000001a;border-radius:999px}
|
||||
1
arma/client/addons/cad/ui/_site/cad-shared.js
Normal file
1
arma/client/addons/cad/ui/_site/cad-shared.js
Normal file
@ -0,0 +1 @@
|
||||
window.mapUIState={layersPanelVisible:!0,sidePanelElement:null},window.mapUI={sendEvent(e,t){A3API.SendAlert(JSON.stringify({event:e,data:t}))},updateCoordinates(e,t){const n=document.getElementById("coordsDisplay");n&&(n.textContent=`X: ${Math.round(e).toString().padStart(4,"0")} Y: ${Math.round(t).toString().padStart(4,"0")}`)},updateScale(e){const t=document.getElementById("scaleDisplay");t&&(t.textContent=`Scale: 1:${Math.round(e)}`)},updateStatus(e){const t=document.getElementById("statusText");t&&(t.textContent=e)}},window.updateCoordinates=window.mapUI.updateCoordinates,window.updateScale=window.mapUI.updateScale,window.updateStatus=window.mapUI.updateStatus,window.ForgeBridge=window.ForgeBridge||{_handlers:{},on(e,t){this._handlers[e]=this._handlers[e]||[],this._handlers[e].push(t)},ready:e=>(window.mapUI.sendEvent("cad::ready",e||{}),!0),receive(e){if(!e||"object"!=typeof e)return;(this._handlers[e.event]||[]).forEach(t=>t(e.data||{}))},send:(e,t)=>(window.mapUI.sendEvent(e,t||{}),!0),close:e=>(window.mapUI.sendEvent("map::close",e||{}),!0)};
|
||||
1
arma/client/addons/cad/ui/_site/cad-sidepanel.css
Normal file
1
arma/client/addons/cad/ui/_site/cad-sidepanel.css
Normal file
@ -0,0 +1 @@
|
||||
html,body{background:var(--panel);border-left:1px solid var(--stroke);width:100%;height:100%;box-shadow:var(--shadow);-webkit-backdrop-filter:blur(12px);margin:0;padding:0;overflow:hidden}body{opacity:1;visibility:visible}.panel-header{border-bottom:1px solid var(--stroke);background:linear-gradient(#ffffff0d,#0000);justify-content:space-between;align-items:center;padding:14px;display:flex}.panel-header h3{color:var(--accent);text-transform:uppercase;letter-spacing:.8px;font-size:14px;font-weight:650}.panel-content{height:calc(100% - 56px);padding:14px;overflow:auto}.placeholder-message{text-align:center;padding:20px}.placeholder-message p{color:var(--muted);font-size:13px;font-style:italic}.task-toolbar{margin-bottom:10px}.task-toolbar button,.task-accept-btn{color:#f3f6f9;cursor:pointer;background:#1e252be6;border:1px solid #fff3;width:100%;padding:8px 10px}.task-toolbar button:hover,.task-accept-btn:hover{background:#2e3942f2}.task-toolbar button:disabled,.task-accept-btn:disabled{opacity:.55;cursor:default}.task-status-message{color:#cdd6dd;min-height:18px;margin-bottom:10px;font-size:12px}.task-status-message[data-type=success]{color:#79d28a}.task-status-message[data-type=error]{color:#ff8a80}.task-list{flex-direction:column;gap:10px;display:flex}.task-card{background:#0c10149e;border:1px solid #ffffff14;padding:10px}.task-card-header{justify-content:space-between;gap:8px;margin-bottom:8px;display:flex}.task-type{opacity:.7;text-transform:uppercase;font-size:11px}.task-description{margin:0 0 8px;font-size:12px;line-height:1.4}.task-meta{opacity:.8;justify-content:space-between;gap:8px;margin-bottom:8px;font-size:11px;display:flex}
|
||||
1
arma/client/addons/cad/ui/_site/cad-sidepanel.js
Normal file
1
arma/client/addons/cad/ui/_site/cad-sidepanel.js
Normal file
@ -0,0 +1 @@
|
||||
window.cadTasks={tasks:[],init(){const s=document.getElementById("refreshTasksBtn");s&&s.addEventListener("click",()=>this.refresh()),window.ForgeBridge.on("cad::tasks::hydrate",s=>{this.setTasks(s.tasks||[])}),window.ForgeBridge.on("cad::tasks::accept::response",s=>{this.handleAcceptResponse(!!s.success,s.message||"")}),window.ForgeBridge.ready({loaded:!0})},setTasks(s){this.tasks=Array.isArray(s)?s:[];const t=document.getElementById("taskStatusMessage");!t||t.dataset.type&&"info"!==t.dataset.type||this.setStatus("",""),this.render()},setStatus(s,t){const e=document.getElementById("taskStatusMessage");e&&(e.textContent=s||"",e.dataset.type=t||"info")},handleAcceptResponse(s,t){this.setStatus(t||(s?"Task accepted.":"Unable to accept task."),s?"success":"error")},refresh(){this.setStatus("Refreshing tasks...","info"),window.mapUI.sendEvent("cad::tasks::refresh",{})},acceptTask(s){this.setStatus("Submitting acceptance...","info"),window.mapUI.sendEvent("cad::tasks::accept",{taskID:s})},render(){const s=document.getElementById("taskList");s&&(this.tasks.length?s.innerHTML=this.tasks.map(s=>{const t=Array.isArray(s.position)?s.position:[0,0,0],e=!!s.accepted,a=e?`Assigned: ${s.orgID||"Unknown"}`:"Available";return`\n <div class="task-card" data-task-id="${s.taskID}">\n <div class="task-card-header">\n <strong>${s.title||s.taskID}</strong>\n <span class="task-type">${s.type||"task"}</span>\n </div>\n <p class="task-description">${s.description||""}</p>\n <div class="task-meta">\n <span>${a}</span>\n <span>X: ${Math.round(t[0]||0)} Y: ${Math.round(t[1]||0)}</span>\n </div>\n <button type="button" class="task-accept-btn" ${e?"disabled":""} onclick="window.cadTasks.acceptTask('${s.taskID}')">${e?"Accepted":"Accept"}</button>\n </div>\n `}).join(""):s.innerHTML='<div class="placeholder-message"><p>No active tasks are available.</p></div>')}},window.cadTasks.init();
|
||||
1
arma/client/addons/cad/ui/_site/cad-topbar.css
Normal file
1
arma/client/addons/cad/ui/_site/cad-topbar.css
Normal file
@ -0,0 +1 @@
|
||||
body{-webkit-backdrop-filter:blur(18px);background:linear-gradient(90deg,#10161ff5,#131a24f0 55%,#0f141cf5);border-bottom:1px solid #ffffff24;justify-content:space-between;align-items:center;height:56px;padding:0 20px;display:flex;position:absolute;top:0;left:0;right:0;overflow:hidden;box-shadow:0 14px 28px #00000047}.logo{color:var(--accent);text-transform:uppercase;letter-spacing:.4px;text-shadow:0 1px 12px #00000059;font-size:16px;font-weight:650}.controls{align-items:center;gap:10px;display:flex}.search-input{color:var(--text);background:#ffffff14;border:1px solid #ffffff24;border-radius:999px;outline:none;width:250px;padding:10px 12px;font-size:13px;box-shadow:inset 0 1px #ffffff08}.search-input::placeholder{color:var(--muted2)}.search-input:focus{background:#ffffff1c;border-color:#68c4ff73}.info{color:#f5f8ffd6;font-size:12px;font-family:var(--font);text-shadow:0 1px 10px #00000047;gap:20px;display:flex}
|
||||
1
arma/client/addons/cad/ui/_site/cad-topbar.js
Normal file
1
arma/client/addons/cad/ui/_site/cad-topbar.js
Normal file
@ -0,0 +1 @@
|
||||
document.getElementById("btnZoomIn").addEventListener("click",()=>{window.mapUI.sendEvent("map::zoomIn",null)}),document.getElementById("btnZoomOut").addEventListener("click",()=>{window.mapUI.sendEvent("map::zoomOut",null)}),document.getElementById("btnClose").addEventListener("click",()=>{window.mapUI.sendEvent("map::close",null)}),document.getElementById("searchBox").addEventListener("keypress",e=>{"Enter"===e.key&&window.mapUI.sendEvent("map::search",e.target.value)});
|
||||
1
arma/client/addons/cad/ui/_site/sidepanel.html
Normal file
1
arma/client/addons/cad/ui/_site/sidepanel.html
Normal file
@ -0,0 +1 @@
|
||||
<!doctype html><html><head><meta charset="UTF-8"></head><body><div class="panel-header"><h3>CAD System</h3></div><div class="panel-content"><div class="task-toolbar"><button id="refreshTasksBtn" type="button">Refresh Tasks</button></div><div id="taskStatusMessage" class="task-status-message"></div><div id="taskList" class="task-list"><div class="placeholder-message"><p>Loading available tasks...</p></div></div></div><script>window.MapLoader={loadCSS:e=>A3API.RequestFile(e).then(e=>{const d=document.createElement("style");d.textContent=e,document.head.appendChild(d)}),loadJS(path){return A3API.RequestFile(path).then(js=>{eval(js)})},loadAll(e){return e.reduce((e,d)=>e.then(()=>d.endsWith(".css")?this.loadCSS(d):d.endsWith(".js")?this.loadJS(d):Promise.resolve()),Promise.resolve())}},MapLoader.loadAll(["forge\\forge_client\\addons\\cad\\ui\\_site\\cad-common.css","forge\\forge_client\\addons\\cad\\ui\\_site\\cad-sidepanel.css","forge\\forge_client\\addons\\cad\\ui\\_site\\cad-shared.js","forge\\forge_client\\addons\\cad\\ui\\_site\\cad-sidepanel.js"]).catch(e=>console.error("[SIDEPANEL] Load error:",e))</script></body></html>
|
||||
1
arma/client/addons/cad/ui/_site/topbar.html
Normal file
1
arma/client/addons/cad/ui/_site/topbar.html
Normal file
@ -0,0 +1 @@
|
||||
<!doctype html><html><head><meta charset="UTF-8"></head><body><div class="logo">FORGE OS</div><div class="controls"><button id="btnZoomIn" class="btn">+</button> <button id="btnZoomOut" class="btn">-</button> <input id="searchBox" placeholder="Search location..." class="search-input"> <button id="btnClose" class="btn btn-close">X</button></div><div class="info"><span id="coordsDisplay">X: 0000 Y: 0000</span> <span id="scaleDisplay">Scale: 1:1000</span></div><script>window.MapLoader={loadCSS:e=>A3API.RequestFile(e).then(e=>{const o=document.createElement("style");o.textContent=e,document.head.appendChild(o)}),loadJS(path){return A3API.RequestFile(path).then(js=>{eval(js)})},loadAll(e){return e.reduce((e,o)=>e.then(()=>o.endsWith(".css")?this.loadCSS(o):o.endsWith(".js")?this.loadJS(o):Promise.resolve()),Promise.resolve())}},MapLoader.loadAll(["forge\\forge_client\\addons\\cad\\ui\\_site\\cad-common.css","forge\\forge_client\\addons\\cad\\ui\\_site\\cad-topbar.css","forge\\forge_client\\addons\\cad\\ui\\_site\\cad-shared.js","forge\\forge_client\\addons\\cad\\ui\\_site\\cad-topbar.js"]).catch(e=>console.error("[TOPBAR] Load error:",e))</script></body></html>
|
||||
49
arma/client/addons/cad/ui/src/bottombar.html
Normal file
49
arma/client/addons/cad/ui/src/bottombar.html
Normal file
@ -0,0 +1,49 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
</head>
|
||||
<body>
|
||||
<span id="statusText">Map Ready</span>
|
||||
<span id="selectionInfo"></span>
|
||||
|
||||
<script>
|
||||
window.MapLoader = {
|
||||
loadCSS(path) {
|
||||
return A3API.RequestFile(path).then((css) => {
|
||||
const style = document.createElement("style");
|
||||
style.textContent = css;
|
||||
document.head.appendChild(style);
|
||||
});
|
||||
},
|
||||
loadJS(path) {
|
||||
return A3API.RequestFile(path).then((js) => {
|
||||
eval(js);
|
||||
});
|
||||
},
|
||||
loadAll(resources) {
|
||||
return resources.reduce((promise, resource) => {
|
||||
return promise.then(() => {
|
||||
if (resource.endsWith(".css")) {
|
||||
return this.loadCSS(resource);
|
||||
}
|
||||
|
||||
if (resource.endsWith(".js")) {
|
||||
return this.loadJS(resource);
|
||||
}
|
||||
|
||||
return Promise.resolve();
|
||||
});
|
||||
}, Promise.resolve());
|
||||
},
|
||||
};
|
||||
|
||||
MapLoader.loadAll([
|
||||
"forge\\forge_client\\addons\\cad\\ui\\_site\\cad-common.css",
|
||||
"forge\\forge_client\\addons\\cad\\ui\\_site\\cad-bottombar.css",
|
||||
"forge\\forge_client\\addons\\cad\\ui\\_site\\cad-shared.js",
|
||||
"forge\\forge_client\\addons\\cad\\ui\\_site\\cad-bottombar.js",
|
||||
]).catch((err) => console.error("[BOTTOMBAR] Load error:", err));
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
6
arma/client/addons/cad/ui/src/bottombar.js
Normal file
6
arma/client/addons/cad/ui/src/bottombar.js
Normal file
@ -0,0 +1,6 @@
|
||||
/*
|
||||
* Bottombar UI Component
|
||||
* Displays status and selection information.
|
||||
*/
|
||||
|
||||
window.CADBottombar = window.CADBottombar || {};
|
||||
69
arma/client/addons/cad/ui/src/shared.js
Normal file
69
arma/client/addons/cad/ui/src/shared.js
Normal file
@ -0,0 +1,69 @@
|
||||
/**
|
||||
* Shared JavaScript for Map UI
|
||||
* Provides common utilities and state management across all UI components
|
||||
*/
|
||||
|
||||
window.mapUIState = {
|
||||
layersPanelVisible: true,
|
||||
sidePanelElement: null,
|
||||
};
|
||||
|
||||
window.mapUI = {
|
||||
sendEvent(event, data) {
|
||||
A3API.SendAlert(JSON.stringify({ event: event, data: data }));
|
||||
},
|
||||
updateCoordinates(x, y) {
|
||||
const coordDisplay = document.getElementById("coordsDisplay");
|
||||
if (coordDisplay) {
|
||||
coordDisplay.textContent = `X: ${Math.round(x)
|
||||
.toString()
|
||||
.padStart(4, "0")} Y: ${Math.round(y)
|
||||
.toString()
|
||||
.padStart(4, "0")}`;
|
||||
}
|
||||
},
|
||||
updateScale(scale) {
|
||||
const scaleDisplay = document.getElementById("scaleDisplay");
|
||||
if (scaleDisplay) {
|
||||
scaleDisplay.textContent = `Scale: 1:${Math.round(scale)}`;
|
||||
}
|
||||
},
|
||||
updateStatus(text) {
|
||||
const statusText = document.getElementById("statusText");
|
||||
if (statusText) {
|
||||
statusText.textContent = text;
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
window.updateCoordinates = window.mapUI.updateCoordinates;
|
||||
window.updateScale = window.mapUI.updateScale;
|
||||
window.updateStatus = window.mapUI.updateStatus;
|
||||
|
||||
window.ForgeBridge = window.ForgeBridge || {
|
||||
_handlers: {},
|
||||
on(event, handler) {
|
||||
this._handlers[event] = this._handlers[event] || [];
|
||||
this._handlers[event].push(handler);
|
||||
},
|
||||
ready(payload) {
|
||||
window.mapUI.sendEvent("cad::ready", payload || {});
|
||||
return true;
|
||||
},
|
||||
receive(payload) {
|
||||
if (!payload || typeof payload !== "object") {
|
||||
return;
|
||||
}
|
||||
|
||||
const handlers = this._handlers[payload.event] || [];
|
||||
handlers.forEach((handler) => handler(payload.data || {}));
|
||||
},
|
||||
send(event, data) {
|
||||
window.mapUI.sendEvent(event, data || {});
|
||||
return true;
|
||||
},
|
||||
close(data) {
|
||||
window.mapUI.sendEvent("map::close", data || {});
|
||||
return true;
|
||||
},
|
||||
};
|
||||
63
arma/client/addons/cad/ui/src/sidepanel.html
Normal file
63
arma/client/addons/cad/ui/src/sidepanel.html
Normal file
@ -0,0 +1,63 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
</head>
|
||||
<body>
|
||||
<div class="panel-header">
|
||||
<h3>CAD System</h3>
|
||||
</div>
|
||||
<div class="panel-content">
|
||||
<div class="task-toolbar">
|
||||
<button id="refreshTasksBtn" type="button">
|
||||
Refresh Tasks
|
||||
</button>
|
||||
</div>
|
||||
<div id="taskStatusMessage" class="task-status-message"></div>
|
||||
<div id="taskList" class="task-list">
|
||||
<div class="placeholder-message">
|
||||
<p>Loading available tasks...</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
window.MapLoader = {
|
||||
loadCSS(path) {
|
||||
return A3API.RequestFile(path).then((css) => {
|
||||
const style = document.createElement("style");
|
||||
style.textContent = css;
|
||||
document.head.appendChild(style);
|
||||
});
|
||||
},
|
||||
loadJS(path) {
|
||||
return A3API.RequestFile(path).then((js) => {
|
||||
eval(js);
|
||||
});
|
||||
},
|
||||
loadAll(resources) {
|
||||
return resources.reduce((promise, resource) => {
|
||||
return promise.then(() => {
|
||||
if (resource.endsWith(".css")) {
|
||||
return this.loadCSS(resource);
|
||||
}
|
||||
|
||||
if (resource.endsWith(".js")) {
|
||||
return this.loadJS(resource);
|
||||
}
|
||||
|
||||
return Promise.resolve();
|
||||
});
|
||||
}, Promise.resolve());
|
||||
},
|
||||
};
|
||||
|
||||
MapLoader.loadAll([
|
||||
"forge\\forge_client\\addons\\cad\\ui\\_site\\cad-common.css",
|
||||
"forge\\forge_client\\addons\\cad\\ui\\_site\\cad-sidepanel.css",
|
||||
"forge\\forge_client\\addons\\cad\\ui\\_site\\cad-shared.js",
|
||||
"forge\\forge_client\\addons\\cad\\ui\\_site\\cad-sidepanel.js",
|
||||
]).catch((err) => console.error("[SIDEPANEL] Load error:", err));
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
94
arma/client/addons/cad/ui/src/sidepanel.js
Normal file
94
arma/client/addons/cad/ui/src/sidepanel.js
Normal file
@ -0,0 +1,94 @@
|
||||
window.cadTasks = {
|
||||
tasks: [],
|
||||
init() {
|
||||
const refreshBtn = document.getElementById("refreshTasksBtn");
|
||||
if (refreshBtn) {
|
||||
refreshBtn.addEventListener("click", () => this.refresh());
|
||||
}
|
||||
|
||||
window.ForgeBridge.on("cad::tasks::hydrate", (payload) => {
|
||||
this.setTasks(payload.tasks || []);
|
||||
});
|
||||
|
||||
window.ForgeBridge.on("cad::tasks::accept::response", (payload) => {
|
||||
this.handleAcceptResponse(!!payload.success, payload.message || "");
|
||||
});
|
||||
|
||||
window.ForgeBridge.ready({ loaded: true });
|
||||
},
|
||||
setTasks(tasks) {
|
||||
this.tasks = Array.isArray(tasks) ? tasks : [];
|
||||
const statusEl = document.getElementById("taskStatusMessage");
|
||||
if (
|
||||
statusEl &&
|
||||
(!statusEl.dataset.type || statusEl.dataset.type === "info")
|
||||
) {
|
||||
this.setStatus("", "");
|
||||
}
|
||||
this.render();
|
||||
},
|
||||
setStatus(message, type) {
|
||||
const statusEl = document.getElementById("taskStatusMessage");
|
||||
if (!statusEl) {
|
||||
return;
|
||||
}
|
||||
|
||||
statusEl.textContent = message || "";
|
||||
statusEl.dataset.type = type || "info";
|
||||
},
|
||||
handleAcceptResponse(success, message) {
|
||||
this.setStatus(
|
||||
message || (success ? "Task accepted." : "Unable to accept task."),
|
||||
success ? "success" : "error",
|
||||
);
|
||||
},
|
||||
refresh() {
|
||||
this.setStatus("Refreshing tasks...", "info");
|
||||
window.mapUI.sendEvent("cad::tasks::refresh", {});
|
||||
},
|
||||
acceptTask(taskID) {
|
||||
this.setStatus("Submitting acceptance...", "info");
|
||||
window.mapUI.sendEvent("cad::tasks::accept", { taskID: taskID });
|
||||
},
|
||||
render() {
|
||||
const listEl = document.getElementById("taskList");
|
||||
if (!listEl) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.tasks.length) {
|
||||
listEl.innerHTML =
|
||||
'<div class="placeholder-message"><p>No active tasks are available.</p></div>';
|
||||
return;
|
||||
}
|
||||
|
||||
listEl.innerHTML = this.tasks
|
||||
.map((task) => {
|
||||
const position = Array.isArray(task.position)
|
||||
? task.position
|
||||
: [0, 0, 0];
|
||||
const accepted = !!task.accepted;
|
||||
const ownerLabel = accepted
|
||||
? `Assigned: ${task.orgID || "Unknown"}`
|
||||
: "Available";
|
||||
|
||||
return `
|
||||
<div class="task-card" data-task-id="${task.taskID}">
|
||||
<div class="task-card-header">
|
||||
<strong>${task.title || task.taskID}</strong>
|
||||
<span class="task-type">${task.type || "task"}</span>
|
||||
</div>
|
||||
<p class="task-description">${task.description || ""}</p>
|
||||
<div class="task-meta">
|
||||
<span>${ownerLabel}</span>
|
||||
<span>X: ${Math.round(position[0] || 0)} Y: ${Math.round(position[1] || 0)}</span>
|
||||
</div>
|
||||
<button type="button" class="task-accept-btn" ${accepted ? "disabled" : ""} onclick="window.cadTasks.acceptTask('${task.taskID}')">${accepted ? "Accepted" : "Accept"}</button>
|
||||
</div>
|
||||
`;
|
||||
})
|
||||
.join("");
|
||||
},
|
||||
};
|
||||
|
||||
window.cadTasks.init();
|
||||
33
arma/client/addons/cad/ui/src/styles/bottombar.css
Normal file
33
arma/client/addons/cad/ui/src/styles/bottombar.css
Normal file
@ -0,0 +1,33 @@
|
||||
body {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
min-height: 36px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 0 20px;
|
||||
background: linear-gradient(
|
||||
90deg,
|
||||
rgba(14, 19, 27, 0.96),
|
||||
rgba(18, 23, 32, 0.93) 55%,
|
||||
rgba(13, 18, 25, 0.96)
|
||||
);
|
||||
border-top: 1px solid rgba(255, 255, 255, 0.14);
|
||||
box-shadow: 0 -12px 26px rgba(0, 0, 0, 0.24);
|
||||
backdrop-filter: blur(18px);
|
||||
-webkit-backdrop-filter: blur(18px);
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
span {
|
||||
color: rgba(245, 248, 255, 0.8);
|
||||
font-size: 12px;
|
||||
text-shadow: 0 1px 10px rgba(0, 0, 0, 0.28);
|
||||
}
|
||||
|
||||
#statusText {
|
||||
color: var(--accent);
|
||||
font-weight: 600;
|
||||
}
|
||||
78
arma/client/addons/cad/ui/src/styles/common.css
Normal file
78
arma/client/addons/cad/ui/src/styles/common.css
Normal file
@ -0,0 +1,78 @@
|
||||
:root {
|
||||
--bg: rgba(9, 12, 18, 0.82);
|
||||
--panel: rgba(20, 24, 33, 0.9);
|
||||
--panel2: rgba(17, 21, 30, 0.82);
|
||||
--stroke: rgba(255, 255, 255, 0.12);
|
||||
--stroke2: rgba(255, 255, 255, 0.2);
|
||||
--text: rgba(245, 248, 255, 0.92);
|
||||
--muted: rgba(245, 248, 255, 0.62);
|
||||
--muted2: rgba(245, 248, 255, 0.42);
|
||||
--accent: rgba(104, 196, 255, 0.95);
|
||||
--danger: rgba(255, 96, 96, 0.95);
|
||||
--shadow: 0 20px 60px rgba(0, 0, 0, 0.55);
|
||||
--radius: 14px;
|
||||
--radius2: 10px;
|
||||
--font:
|
||||
ui-sans-serif, system-ui, -apple-system, Segoe UI, Roboto, Arial,
|
||||
sans-serif;
|
||||
}
|
||||
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: var(--font);
|
||||
color: var(--text);
|
||||
background: var(--bg);
|
||||
backdrop-filter: blur(16px);
|
||||
-webkit-backdrop-filter: blur(16px);
|
||||
}
|
||||
|
||||
.btn {
|
||||
border: 1px solid rgba(255, 255, 255, 0.1);
|
||||
background: rgba(255, 255, 255, 0.03);
|
||||
padding: 8px 16px;
|
||||
border-radius: var(--radius2);
|
||||
font-size: 14px;
|
||||
color: var(--text);
|
||||
cursor: pointer;
|
||||
transition:
|
||||
background 0.16s ease,
|
||||
border-color 0.16s ease,
|
||||
transform 0.16s ease;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
background: rgba(255, 255, 255, 0.07);
|
||||
border-color: rgba(255, 255, 255, 0.16);
|
||||
}
|
||||
|
||||
.btn:active {
|
||||
transform: scale(0.98);
|
||||
}
|
||||
|
||||
.btn-close {
|
||||
background: rgba(255, 96, 96, 0.1);
|
||||
border-color: rgba(255, 96, 96, 0.25);
|
||||
color: rgba(255, 220, 220, 0.95);
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.btn-close:hover {
|
||||
background: rgba(255, 96, 96, 0.2);
|
||||
border-color: rgba(255, 96, 96, 0.35);
|
||||
}
|
||||
|
||||
::-webkit-scrollbar {
|
||||
width: 10px;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-thumb {
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
border-radius: 999px;
|
||||
border: 2px solid rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
136
arma/client/addons/cad/ui/src/styles/sidepanel.css
Normal file
136
arma/client/addons/cad/ui/src/styles/sidepanel.css
Normal file
@ -0,0 +1,136 @@
|
||||
html,
|
||||
body {
|
||||
overflow: hidden;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: var(--panel);
|
||||
border-left: 1px solid var(--stroke);
|
||||
box-shadow: var(--shadow);
|
||||
backdrop-filter: blur(12px);
|
||||
-webkit-backdrop-filter: blur(12px);
|
||||
}
|
||||
|
||||
body {
|
||||
opacity: 1;
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
.panel-header {
|
||||
padding: 14px;
|
||||
border-bottom: 1px solid var(--stroke);
|
||||
background: linear-gradient(
|
||||
to bottom,
|
||||
rgba(255, 255, 255, 0.05),
|
||||
transparent
|
||||
);
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.panel-header h3 {
|
||||
color: var(--accent);
|
||||
font-size: 14px;
|
||||
font-weight: 650;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.8px;
|
||||
}
|
||||
|
||||
.panel-content {
|
||||
padding: 14px;
|
||||
height: calc(100% - 56px);
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.placeholder-message {
|
||||
padding: 20px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.placeholder-message p {
|
||||
color: var(--muted);
|
||||
font-size: 13px;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.task-toolbar {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.task-toolbar button,
|
||||
.task-accept-btn {
|
||||
width: 100%;
|
||||
padding: 8px 10px;
|
||||
border: 1px solid rgba(255, 255, 255, 0.2);
|
||||
background: rgba(30, 37, 43, 0.9);
|
||||
color: #f3f6f9;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.task-toolbar button:hover,
|
||||
.task-accept-btn:hover {
|
||||
background: rgba(46, 57, 66, 0.95);
|
||||
}
|
||||
|
||||
.task-toolbar button:disabled,
|
||||
.task-accept-btn:disabled {
|
||||
opacity: 0.55;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.task-status-message {
|
||||
min-height: 18px;
|
||||
margin-bottom: 10px;
|
||||
font-size: 12px;
|
||||
color: #cdd6dd;
|
||||
}
|
||||
|
||||
.task-status-message[data-type="success"] {
|
||||
color: #79d28a;
|
||||
}
|
||||
|
||||
.task-status-message[data-type="error"] {
|
||||
color: #ff8a80;
|
||||
}
|
||||
|
||||
.task-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.task-card {
|
||||
padding: 10px;
|
||||
border: 1px solid rgba(255, 255, 255, 0.08);
|
||||
background: rgba(12, 16, 20, 0.62);
|
||||
}
|
||||
|
||||
.task-card-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
gap: 8px;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.task-type {
|
||||
opacity: 0.7;
|
||||
text-transform: uppercase;
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
.task-description {
|
||||
margin: 0 0 8px;
|
||||
font-size: 12px;
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
.task-meta {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
gap: 8px;
|
||||
margin-bottom: 8px;
|
||||
font-size: 11px;
|
||||
opacity: 0.8;
|
||||
}
|
||||
67
arma/client/addons/cad/ui/src/styles/topbar.css
Normal file
67
arma/client/addons/cad/ui/src/styles/topbar.css
Normal file
@ -0,0 +1,67 @@
|
||||
body {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
height: 56px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 0 20px;
|
||||
background: linear-gradient(
|
||||
90deg,
|
||||
rgba(16, 22, 31, 0.96),
|
||||
rgba(19, 26, 36, 0.94) 55%,
|
||||
rgba(15, 20, 28, 0.96)
|
||||
);
|
||||
border-bottom: 1px solid rgba(255, 255, 255, 0.14);
|
||||
box-shadow: 0 14px 28px rgba(0, 0, 0, 0.28);
|
||||
backdrop-filter: blur(18px);
|
||||
-webkit-backdrop-filter: blur(18px);
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.logo {
|
||||
color: var(--accent);
|
||||
font-size: 16px;
|
||||
font-weight: 650;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.4px;
|
||||
text-shadow: 0 1px 12px rgba(0, 0, 0, 0.35);
|
||||
}
|
||||
|
||||
.controls {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.search-input {
|
||||
background: rgba(255, 255, 255, 0.08);
|
||||
border: 1px solid rgba(255, 255, 255, 0.14);
|
||||
color: var(--text);
|
||||
padding: 10px 12px;
|
||||
border-radius: 999px;
|
||||
width: 250px;
|
||||
outline: none;
|
||||
font-size: 13px;
|
||||
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.03);
|
||||
}
|
||||
|
||||
.search-input::placeholder {
|
||||
color: var(--muted2);
|
||||
}
|
||||
|
||||
.search-input:focus {
|
||||
border-color: rgba(104, 196, 255, 0.45);
|
||||
background: rgba(255, 255, 255, 0.11);
|
||||
}
|
||||
|
||||
.info {
|
||||
display: flex;
|
||||
gap: 20px;
|
||||
color: rgba(245, 248, 255, 0.84);
|
||||
font-size: 12px;
|
||||
font-family: var(--font);
|
||||
text-shadow: 0 1px 10px rgba(0, 0, 0, 0.28);
|
||||
}
|
||||
63
arma/client/addons/cad/ui/src/topbar.html
Normal file
63
arma/client/addons/cad/ui/src/topbar.html
Normal file
@ -0,0 +1,63 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
</head>
|
||||
<body>
|
||||
<div class="logo">FORGE OS</div>
|
||||
<div class="controls">
|
||||
<button id="btnZoomIn" class="btn">+</button>
|
||||
<button id="btnZoomOut" class="btn">-</button>
|
||||
<input
|
||||
type="text"
|
||||
id="searchBox"
|
||||
placeholder="Search location..."
|
||||
class="search-input"
|
||||
/>
|
||||
<button id="btnClose" class="btn btn-close">X</button>
|
||||
</div>
|
||||
<div class="info">
|
||||
<span id="coordsDisplay">X: 0000 Y: 0000</span>
|
||||
<span id="scaleDisplay">Scale: 1:1000</span>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
window.MapLoader = {
|
||||
loadCSS(path) {
|
||||
return A3API.RequestFile(path).then((css) => {
|
||||
const style = document.createElement("style");
|
||||
style.textContent = css;
|
||||
document.head.appendChild(style);
|
||||
});
|
||||
},
|
||||
loadJS(path) {
|
||||
return A3API.RequestFile(path).then((js) => {
|
||||
eval(js);
|
||||
});
|
||||
},
|
||||
loadAll(resources) {
|
||||
return resources.reduce((promise, resource) => {
|
||||
return promise.then(() => {
|
||||
if (resource.endsWith(".css")) {
|
||||
return this.loadCSS(resource);
|
||||
}
|
||||
|
||||
if (resource.endsWith(".js")) {
|
||||
return this.loadJS(resource);
|
||||
}
|
||||
|
||||
return Promise.resolve();
|
||||
});
|
||||
}, Promise.resolve());
|
||||
},
|
||||
};
|
||||
|
||||
MapLoader.loadAll([
|
||||
"forge\\forge_client\\addons\\cad\\ui\\_site\\cad-common.css",
|
||||
"forge\\forge_client\\addons\\cad\\ui\\_site\\cad-topbar.css",
|
||||
"forge\\forge_client\\addons\\cad\\ui\\_site\\cad-shared.js",
|
||||
"forge\\forge_client\\addons\\cad\\ui\\_site\\cad-topbar.js",
|
||||
]).catch((err) => console.error("[TOPBAR] Load error:", err));
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
17
arma/client/addons/cad/ui/src/topbar.js
Normal file
17
arma/client/addons/cad/ui/src/topbar.js
Normal file
@ -0,0 +1,17 @@
|
||||
document.getElementById("btnZoomIn").addEventListener("click", () => {
|
||||
window.mapUI.sendEvent("map::zoomIn", null);
|
||||
});
|
||||
|
||||
document.getElementById("btnZoomOut").addEventListener("click", () => {
|
||||
window.mapUI.sendEvent("map::zoomOut", null);
|
||||
});
|
||||
|
||||
document.getElementById("btnClose").addEventListener("click", () => {
|
||||
window.mapUI.sendEvent("map::close", null);
|
||||
});
|
||||
|
||||
document.getElementById("searchBox").addEventListener("keypress", (event) => {
|
||||
if (event.key === "Enter") {
|
||||
window.mapUI.sendEvent("map::search", event.target.value);
|
||||
}
|
||||
});
|
||||
69
arma/client/addons/cad/ui/ui.config.mjs
Normal file
69
arma/client/addons/cad/ui/ui.config.mjs
Normal file
@ -0,0 +1,69 @@
|
||||
export default {
|
||||
addonName: "cad",
|
||||
title: "FORGE CAD",
|
||||
logLabel: "CAD UI",
|
||||
outputDir: "_site",
|
||||
generateIndex: false,
|
||||
jsBundles: [
|
||||
{
|
||||
name: "CAD shared bridge/runtime",
|
||||
output: "cad-shared.js",
|
||||
sources: ["src/shared.js"],
|
||||
},
|
||||
{
|
||||
name: "CAD topbar app",
|
||||
output: "cad-topbar.js",
|
||||
sources: ["src/topbar.js"],
|
||||
},
|
||||
{
|
||||
name: "CAD sidepanel app",
|
||||
output: "cad-sidepanel.js",
|
||||
sources: ["src/sidepanel.js"],
|
||||
},
|
||||
{
|
||||
name: "CAD bottombar app",
|
||||
output: "cad-bottombar.js",
|
||||
sources: ["src/bottombar.js"],
|
||||
},
|
||||
],
|
||||
cssBundles: [
|
||||
{
|
||||
name: "CAD common styles",
|
||||
output: "cad-common.css",
|
||||
sources: ["src/styles/common.css"],
|
||||
},
|
||||
{
|
||||
name: "CAD topbar styles",
|
||||
output: "cad-topbar.css",
|
||||
sources: ["src/styles/topbar.css"],
|
||||
},
|
||||
{
|
||||
name: "CAD sidepanel styles",
|
||||
output: "cad-sidepanel.css",
|
||||
sources: ["src/styles/sidepanel.css"],
|
||||
},
|
||||
{
|
||||
name: "CAD bottombar styles",
|
||||
output: "cad-bottombar.css",
|
||||
sources: ["src/styles/bottombar.css"],
|
||||
},
|
||||
],
|
||||
htmlTemplates: [
|
||||
{
|
||||
name: "CAD topbar page",
|
||||
output: "topbar.html",
|
||||
source: "src/topbar.html",
|
||||
},
|
||||
{
|
||||
name: "CAD sidepanel page",
|
||||
output: "sidepanel.html",
|
||||
source: "src/sidepanel.html",
|
||||
},
|
||||
{
|
||||
name: "CAD bottombar page",
|
||||
output: "bottombar.html",
|
||||
source: "src/bottombar.html",
|
||||
},
|
||||
],
|
||||
site: {},
|
||||
};
|
||||
@ -1,6 +1,6 @@
|
||||
[sqf.banned_commands]
|
||||
options.banned = [
|
||||
"spawn", # Scheduled should be avoided whenever possible
|
||||
# "spawn", # Scheduled should be avoided whenever possible
|
||||
"execVM", # Script files should never be run directly, they should be functions
|
||||
# "remoteExec", # CBA events should be used for networking
|
||||
]
|
||||
|
||||
@ -150,7 +150,7 @@ GVAR(BankBaseStore) = compileFinal createHashMapFromArray [
|
||||
private _finalPatch = _self call ["mset", [GVAR(Registry), "bank:update", _uid, _patch, false]];
|
||||
|
||||
GVAR(BankMessenger) call ["sendAccountSync", [_uid, _finalPatch]];
|
||||
GVAR(BankMessenger) call ["sendClientNotification", [_uid, "info", "Bank", format ["Deposited $%1", _amount]]];
|
||||
GVAR(BankMessenger) call ["sendClientNotification", [_uid, "info", "Bank", format ["Deposited $%1", [_amount] call EFUNC(common,formatNumber)]]];
|
||||
true
|
||||
}],
|
||||
["hydrateSession", compileFinal {
|
||||
@ -247,7 +247,7 @@ GVAR(BankBaseStore) = compileFinal createHashMapFromArray [
|
||||
private _finalPatch = _self call ["mset", [GVAR(Registry), "bank:update", _uid, _patch, false]];
|
||||
|
||||
GVAR(BankMessenger) call ["sendAccountSync", [_uid, _finalPatch]];
|
||||
GVAR(BankMessenger) call ["sendClientNotification", [_uid, "info", "Bank", format ["Paid $%1", _amount]]];
|
||||
GVAR(BankMessenger) call ["sendClientNotification", [_uid, "info", "Bank", format ["Paid $%1", [_amount] call EFUNC(common,formatNumber)]]];
|
||||
true
|
||||
}],
|
||||
["resolveOrgState", compileFinal {
|
||||
@ -304,8 +304,8 @@ GVAR(BankBaseStore) = compileFinal createHashMapFromArray [
|
||||
name _player
|
||||
};
|
||||
|
||||
GVAR(BankMessenger) call ["sendClientNotification", [_uid, "info", "Bank", format ["Transferred $%1 to %2", _amount, _targetName]]];
|
||||
GVAR(BankMessenger) call ["sendClientNotification", [_target, "info", "Bank", format ["Received $%1 from %2", _amount, _playerName]]];
|
||||
GVAR(BankMessenger) call ["sendClientNotification", [_uid, "info", "Bank", format ["Transferred $%1 to %2", [_amount] call EFUNC(common,formatNumber), _targetName]]];
|
||||
GVAR(BankMessenger) call ["sendClientNotification", [_target, "info", "Bank", format ["Received $%1 from %2", [_amount] call EFUNC(common,formatNumber), _playerName]]];
|
||||
true
|
||||
}],
|
||||
["withdraw", compileFinal {
|
||||
@ -323,7 +323,7 @@ GVAR(BankBaseStore) = compileFinal createHashMapFromArray [
|
||||
private _finalPatch = _self call ["mset", [GVAR(Registry), "bank:update", _uid, _patch, false]];
|
||||
|
||||
GVAR(BankMessenger) call ["sendAccountSync", [_uid, _finalPatch]];
|
||||
GVAR(BankMessenger) call ["sendClientNotification", [_uid, "info", "Bank", format ["Withdrew $%1", _amount]]];
|
||||
GVAR(BankMessenger) call ["sendClientNotification", [_uid, "info", "Bank", format ["Withdrew $%1", [_amount] call EFUNC(common,formatNumber)]]];
|
||||
true
|
||||
}],
|
||||
["depositEarnings", compileFinal {
|
||||
@ -341,7 +341,7 @@ GVAR(BankBaseStore) = compileFinal createHashMapFromArray [
|
||||
private _finalPatch = _self call ["mset", [GVAR(Registry), "bank:update", _uid, _patch, false]];
|
||||
|
||||
GVAR(BankMessenger) call ["sendAccountSync", [_uid, _finalPatch]];
|
||||
GVAR(BankMessenger) call ["sendClientNotification", [_uid, "info", "Bank", format ["Deposited $%1 from earnings", _amount]]];
|
||||
GVAR(BankMessenger) call ["sendClientNotification", [_uid, "info", "Bank", format ["Deposited $%1 from earnings", [_amount] call EFUNC(common,formatNumber)]]];
|
||||
true
|
||||
}]
|
||||
];
|
||||
|
||||
@ -20,8 +20,13 @@
|
||||
#define PX_TH_SEP ","
|
||||
#define PX_DC_PL 2
|
||||
|
||||
private _value = _this;
|
||||
if (_value isEqualType []) then {
|
||||
_value = _value param [0, 0, [0]];
|
||||
};
|
||||
|
||||
private _count = 0;
|
||||
private _arr = (_this toFixed PX_DC_PL) splitString ".";
|
||||
private _arr = (_value toFixed PX_DC_PL) splitString ".";
|
||||
private _str = PX_DC_SEP+(_arr select 1);
|
||||
|
||||
_arr = toArray(_arr select 0);
|
||||
|
||||
@ -47,7 +47,7 @@ GVAR(FEconomyStore) = createHashMapObject [[
|
||||
|
||||
private _totalLiters = GETVAR(_target,liters,0);
|
||||
private _totalCost = _totalLiters * 5;
|
||||
private _formattedTotalCost = _totalCost toFixed 2;
|
||||
private _formattedTotalCost = [_totalCost] call EFUNC(common,formatNumber);
|
||||
private _formattedTotalLiters = _totalLiters toFixed 2;
|
||||
|
||||
[CRPC(notifications,recieveNotification), ["info", "Refueling", format ["Refueling complete: %1L<br />Total Cost: $%2", _formattedTotalLiters, _formattedTotalCost]], _player] call CFUNC(targetEvent);
|
||||
|
||||
@ -80,7 +80,7 @@ GVAR(MEconomyStore) = createHashMapObject [[
|
||||
private _newBalance = 0;
|
||||
|
||||
if (_bank < _healCost && _cash < _healCost) exitWith {
|
||||
[CRPC(notifications,recieveNotification), ["danger", "Insufficient Funds", format ["Insufficient funds for %1. Bank: %2, Cash: %3, Required: %4", (name _unit), _bank, _cash, _healCost]], _unit] call CFUNC(targetEvent);
|
||||
[CRPC(notifications,recieveNotification), ["danger", "Insufficient Funds", format ["Insufficient funds for %1. Bank: $%2, Cash: $%3, Required: $%4", (name _unit), [_bank] call EFUNC(common,formatNumber), [_cash] call EFUNC(common,formatNumber), [_healCost] call EFUNC(common,formatNumber)]], _unit] call CFUNC(targetEvent);
|
||||
};
|
||||
|
||||
if (_bank >= _healCost) then {
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
* File: fnc_initVAStore.sqf
|
||||
* Author: IDSolutions
|
||||
* Date: 2025-12-17
|
||||
* Last Update: 2026-02-13
|
||||
* Last Update: 2026-03-27
|
||||
* Public: No
|
||||
*
|
||||
* Description:
|
||||
@ -28,7 +28,7 @@ GVAR(VArsenalModel) = compileFinal createHashMapObject [[
|
||||
private _vArsenal = createHashMap;
|
||||
|
||||
_vArsenal set ["backpacks", ["B_AssaultPack_rgr"]];
|
||||
_vArsenal set ["items", ["FirstAidKit", "G_Combat", "H_Cap_blk_ION", "H_HelmetB", "ItemCompass", "ItemGPS", "ItemMap", "ItemRadio", "ItemWatch", "U_IG_Guerrilla_6_1", "V_TacVest_oli"]];
|
||||
_vArsenal set ["items", ["FirstAidKit", "G_Combat", "H_Cap_blk_ION", "H_HelmetB", "ItemCompass", "ItemGPS", "ItemMap", "ItemRadio", "ItemWatch", "U_IG_Guerrilla_6_1", "V_TacVest_oli", "ACE_EarPlugs"]];
|
||||
_vArsenal set ["magazines", ["16Rnd_9x21_Mag", "30Rnd_65x39_caseless_black_mag", "Chemlight_blue", "Chemlight_green", "Chemlight_red", "Chemlight_yellow", "HandGrenade", "SmokeShell", "SmokeShellBlue", "SmokeShellGreen", "SmokeShellOrange", "SmokeShellPurple", "SmokeShellRed", "SmokeShellYellow"]];
|
||||
_vArsenal set ["weapons", ["arifle_MX_F", "hgun_P07_F"]];
|
||||
|
||||
|
||||
@ -127,7 +127,7 @@ PREP_RECOMPILE_END;
|
||||
|
||||
private _index = GVAR(IndexRegistry) get _uid;
|
||||
private _key = _index get "orgID";
|
||||
GVAR(OrgStore) call ["save", [GVAR(Registry), "org:update", _key]];
|
||||
GVAR(OrgStore) call ["saveById", [_key]];
|
||||
}] call CFUNC(addEventHandler);
|
||||
|
||||
[QGVAR(requestRemoveOrg), {
|
||||
|
||||
@ -50,6 +50,42 @@ GVAR(OrgModel) = compileFinal createHashMapObject [[
|
||||
if !(_x in _org) then { _org set [_x, _y]; };
|
||||
} forEach _defaults;
|
||||
|
||||
private _assets = _org getOrDefault ["assets", createHashMap];
|
||||
if !(_assets isEqualType createHashMap) then {
|
||||
_assets = createHashMap;
|
||||
};
|
||||
|
||||
private _migratedAssets = createHashMap;
|
||||
{
|
||||
private _categoryKey = _x;
|
||||
private _value = _y;
|
||||
|
||||
if (_value isEqualType createHashMap) then {
|
||||
private _categoryMap = createHashMap;
|
||||
|
||||
if (_categoryKey find ":" >= 0) then {
|
||||
private _legacyAsset = +_value;
|
||||
private _category = toLowerANSI (_legacyAsset getOrDefault ["type", "items"]);
|
||||
private _className = _legacyAsset getOrDefault ["classname", ""];
|
||||
if (_className isNotEqualTo "") then {
|
||||
_categoryMap = +(_migratedAssets getOrDefault [_category, createHashMap]);
|
||||
_categoryMap set [_className, _legacyAsset];
|
||||
_migratedAssets set [_category, _categoryMap];
|
||||
};
|
||||
} else {
|
||||
{
|
||||
if (_y isEqualType createHashMap) then {
|
||||
_categoryMap set [_x, +_y];
|
||||
};
|
||||
} forEach _value;
|
||||
|
||||
_migratedAssets set [toLowerANSI _categoryKey, _categoryMap];
|
||||
};
|
||||
};
|
||||
} forEach _assets;
|
||||
|
||||
_org set ["assets", _migratedAssets];
|
||||
|
||||
_org
|
||||
}],
|
||||
["validate", compileFinal {
|
||||
@ -121,6 +157,13 @@ GVAR(OrgBaseStore) = compileFinal createHashMapFromArray [
|
||||
["org:create", ["default", _defaultJson]] call EFUNC(extension,extCall);
|
||||
};
|
||||
|
||||
_defaultOrg = GVAR(OrgModel) call ["migrate", [_defaultOrg]];
|
||||
private _defaultAssets = _self call ["fetch", ["org:assets:get", "default"]];
|
||||
if !(_defaultAssets isEqualType createHashMap) then { _defaultAssets = createHashMap; };
|
||||
_defaultOrg set ["assets", _defaultAssets];
|
||||
private _defaultFleet = _self call ["fetch", ["org:fleet:get", "default"]];
|
||||
if !(_defaultFleet isEqualType createHashMap) then { _defaultFleet = createHashMap; };
|
||||
_defaultOrg set ["fleet", _defaultFleet];
|
||||
GVAR(Registry) set ["default", _defaultOrg];
|
||||
}],
|
||||
["verifyMember", compileFinal {
|
||||
@ -230,13 +273,31 @@ GVAR(OrgBaseStore) = compileFinal createHashMapFromArray [
|
||||
if (_ownerUid isEqualTo _uid) then { _sessionRole = "Leader"; };
|
||||
|
||||
private _assetsList = [];
|
||||
{
|
||||
private _category = _x;
|
||||
{
|
||||
private _assetData = _y;
|
||||
private _className = _assetData getOrDefault ["classname", ""];
|
||||
private _displayName = _className;
|
||||
{
|
||||
private _cfg = _x >> _className;
|
||||
if (isClass _cfg) exitWith {
|
||||
private _resolvedName = getText (_cfg >> "displayName");
|
||||
if (_resolvedName isNotEqualTo "") then { _displayName = _resolvedName; };
|
||||
};
|
||||
} forEach [
|
||||
configFile >> "CfgWeapons",
|
||||
configFile >> "CfgMagazines",
|
||||
configFile >> "CfgVehicles",
|
||||
configFile >> "CfgGlasses"
|
||||
];
|
||||
|
||||
_assetsList pushBack (createHashMapFromArray [
|
||||
["name", _assetData getOrDefault ["name", "Unknown Asset"]],
|
||||
["type", _assetData getOrDefault ["type", "items"]],
|
||||
["name", _displayName],
|
||||
["type", _assetData getOrDefault ["type", _category]],
|
||||
["quantity", str (_assetData getOrDefault ["quantity", 0])]
|
||||
]);
|
||||
} forEach _y;
|
||||
} forEach _assetsRaw;
|
||||
|
||||
private _fleetList = [];
|
||||
@ -291,8 +352,112 @@ GVAR(OrgBaseStore) = compileFinal createHashMapFromArray [
|
||||
["chargeCheckout", compileFinal {
|
||||
GVAR(OrgTreasuryService) call ["chargeCheckout", _this]
|
||||
}],
|
||||
["saveById", compileFinal {
|
||||
params [["_orgID", "", [""]]];
|
||||
|
||||
if (_orgID isEqualTo "") exitWith { createHashMap };
|
||||
|
||||
private _org = GVAR(Registry) getOrDefault [_orgID, createHashMap];
|
||||
if (_org isEqualTo createHashMap) then {
|
||||
_org = _self call ["loadById", [_orgID]];
|
||||
};
|
||||
if (_org isEqualTo createHashMap) exitWith { createHashMap };
|
||||
|
||||
private _coreOrg = createHashMapFromArray [
|
||||
["id", _org getOrDefault ["id", _orgID]],
|
||||
["owner", _org getOrDefault ["owner", ""]],
|
||||
["name", _org getOrDefault ["name", ""]],
|
||||
["funds", _org getOrDefault ["funds", 0]],
|
||||
["reputation", _org getOrDefault ["reputation", 0]],
|
||||
["credit_lines", _org getOrDefault ["credit_lines", createHashMap]]
|
||||
];
|
||||
|
||||
private _coreJson = _self call ["toJSON", [_coreOrg]];
|
||||
["org:update", [_orgID, _coreJson]] call EFUNC(extension,extCall);
|
||||
|
||||
private _assets = _org getOrDefault ["assets", createHashMap];
|
||||
private _assetsJson = _self call ["toJSON", [_assets]];
|
||||
["org:assets:update", [_orgID, _assetsJson]] call EFUNC(extension,extCall);
|
||||
|
||||
private _fleet = _org getOrDefault ["fleet", createHashMap];
|
||||
private _fleetJson = _self call ["toJSON", [_fleet]];
|
||||
["org:fleet:update", [_orgID, _fleetJson]] call EFUNC(extension,extCall);
|
||||
|
||||
_org
|
||||
}],
|
||||
["addAssets", compileFinal {
|
||||
params [["_requesterUid", "", [""]], ["_assets", [], [[]]], ["_commit", false, [false]], ["_orgID", "", [""]]];
|
||||
|
||||
private _result = createHashMapFromArray [
|
||||
["success", false],
|
||||
["message", "Unable to update organization assets."],
|
||||
["patch", createHashMap],
|
||||
["memberUids", []]
|
||||
];
|
||||
|
||||
if (_assets isEqualTo []) exitWith {
|
||||
_result set ["success", true];
|
||||
_result set ["message", ""];
|
||||
_result
|
||||
};
|
||||
|
||||
private _resolvedOrgID = _orgID;
|
||||
if (_resolvedOrgID isEqualTo "") then {
|
||||
private _requesterActor = EGVAR(actor,Registry) getOrDefault [_requesterUid, createHashMap];
|
||||
_resolvedOrgID = _requesterActor getOrDefault ["organization", "default"];
|
||||
};
|
||||
if (_resolvedOrgID isEqualTo "") then { _resolvedOrgID = "default"; };
|
||||
|
||||
private _org = GVAR(Registry) getOrDefault [_resolvedOrgID, createHashMap];
|
||||
if (_org isEqualTo createHashMap) then {
|
||||
_org = _self call ["loadById", [_resolvedOrgID]];
|
||||
};
|
||||
if (_org isEqualTo createHashMap) exitWith {
|
||||
_result set ["message", "Organization data is unavailable for asset updates."];
|
||||
_result
|
||||
};
|
||||
|
||||
private _assetMap = +(_org getOrDefault ["assets", createHashMap]);
|
||||
|
||||
{
|
||||
private _className = _x getOrDefault ["classname", ""];
|
||||
private _category = toLowerANSI (_x getOrDefault ["category", "items"]);
|
||||
private _quantity = floor ((_x getOrDefault ["quantity", 0]) max 0);
|
||||
if (_className isEqualTo "" || { _quantity <= 0 }) then { continue; };
|
||||
|
||||
private _categoryMap = +(_assetMap getOrDefault [_category, createHashMap]);
|
||||
private _assetEntry = +(_categoryMap getOrDefault [_className, createHashMap]);
|
||||
|
||||
private _existingQuantity = _assetEntry getOrDefault ["quantity", 0];
|
||||
_categoryMap set [_className, createHashMapFromArray [
|
||||
["classname", _className],
|
||||
["type", _category],
|
||||
["quantity", (_existingQuantity + _quantity)]
|
||||
]];
|
||||
_assetMap set [_category, _categoryMap];
|
||||
} forEach _assets;
|
||||
|
||||
private _patch = _self call ["mset", [
|
||||
GVAR(Registry),
|
||||
"org:update",
|
||||
_resolvedOrgID,
|
||||
createHashMapFromArray [["assets", _assetMap]],
|
||||
false
|
||||
]];
|
||||
|
||||
if (_commit) then {
|
||||
private _assetJson = _self call ["toJSON", [_assetMap]];
|
||||
["org:assets:update", [_resolvedOrgID, _assetJson]] call EFUNC(extension,extCall);
|
||||
};
|
||||
|
||||
_result set ["success", true];
|
||||
_result set ["message", ""];
|
||||
_result set ["patch", _patch];
|
||||
_result set ["memberUids", GVAR(OrgTreasuryService) call ["resolveOrgMemberUids", [_org, _requesterUid]]];
|
||||
_result
|
||||
}],
|
||||
["addFleetVehicles", compileFinal {
|
||||
params [["_requesterUid", "", [""]], ["_vehicles", [], [[]]], ["_commit", false, [false]]];
|
||||
params [["_requesterUid", "", [""]], ["_vehicles", [], [[]]], ["_commit", false, [false]], ["_orgID", "", [""]]];
|
||||
|
||||
private _result = createHashMapFromArray [
|
||||
["success", false],
|
||||
@ -301,17 +466,23 @@ GVAR(OrgBaseStore) = compileFinal createHashMapFromArray [
|
||||
["memberUids", []]
|
||||
];
|
||||
|
||||
if (_requesterUid isEqualTo "" || { _vehicles isEqualTo [] }) exitWith {
|
||||
if (_vehicles isEqualTo []) exitWith {
|
||||
_result set ["success", true];
|
||||
_result set ["message", ""];
|
||||
_result
|
||||
};
|
||||
|
||||
private _resolvedOrgID = _orgID;
|
||||
if (_resolvedOrgID isEqualTo "") then {
|
||||
private _requesterActor = EGVAR(actor,Registry) getOrDefault [_requesterUid, createHashMap];
|
||||
private _orgID = _requesterActor getOrDefault ["organization", "default"];
|
||||
if (_orgID isEqualTo "") then { _orgID = "default"; };
|
||||
_resolvedOrgID = _requesterActor getOrDefault ["organization", "default"];
|
||||
};
|
||||
if (_resolvedOrgID isEqualTo "") then { _resolvedOrgID = "default"; };
|
||||
|
||||
private _org = GVAR(Registry) getOrDefault [_orgID, createHashMap];
|
||||
private _org = GVAR(Registry) getOrDefault [_resolvedOrgID, createHashMap];
|
||||
if (_org isEqualTo createHashMap) then {
|
||||
_org = _self call ["loadById", [_resolvedOrgID]];
|
||||
};
|
||||
if (_org isEqualTo createHashMap) exitWith {
|
||||
_result set ["message", "Organization data is unavailable for fleet updates."];
|
||||
_result
|
||||
@ -347,9 +518,17 @@ GVAR(OrgBaseStore) = compileFinal createHashMapFromArray [
|
||||
_fleetIndex = _fleetIndex + 1;
|
||||
} forEach _vehicles;
|
||||
|
||||
private _patch = createHashMapFromArray [["fleet", _fleet]];
|
||||
private _patch = _self call ["mset", [
|
||||
GVAR(Registry),
|
||||
"org:update",
|
||||
_resolvedOrgID,
|
||||
createHashMapFromArray [["fleet", _fleet]],
|
||||
false
|
||||
]];
|
||||
|
||||
if (_commit) then {
|
||||
_patch = _self call ["mset", [GVAR(Registry), "org:update", _orgID, _patch, false]];
|
||||
private _fleetJson = _self call ["toJSON", [_fleet]];
|
||||
["org:fleet:update", [_resolvedOrgID, _fleetJson]] call EFUNC(extension,extCall);
|
||||
};
|
||||
|
||||
_result set ["success", true];
|
||||
@ -373,6 +552,16 @@ GVAR(OrgBaseStore) = compileFinal createHashMapFromArray [
|
||||
if (_org isEqualTo createHashMap) exitWith { _org };
|
||||
|
||||
_org = GVAR(OrgModel) call ["migrate", [_org]];
|
||||
private _assets = _self call ["fetch", ["org:assets:get", _orgID]];
|
||||
if !(_assets isEqualType createHashMap) then {
|
||||
_assets = createHashMap;
|
||||
};
|
||||
_org set ["assets", _assets];
|
||||
private _fleet = _self call ["fetch", ["org:fleet:get", _orgID]];
|
||||
if !(_fleet isEqualType createHashMap) then {
|
||||
_fleet = createHashMap;
|
||||
};
|
||||
_org set ["fleet", _fleet];
|
||||
|
||||
private _memberRows = _self call ["fetch", ["org:members:get", _orgID]];
|
||||
if !(_memberRows isEqualType []) then {
|
||||
@ -438,8 +627,6 @@ GVAR(OrgBaseStore) = compileFinal createHashMapFromArray [
|
||||
["funds", 0],
|
||||
["reputation", 0],
|
||||
["credit_lines", createHashMap],
|
||||
["assets", createHashMap],
|
||||
["fleet", createHashMap],
|
||||
["members", createHashMap]
|
||||
];
|
||||
|
||||
|
||||
@ -17,7 +17,9 @@ GVAR(OrgTreasuryServiceBase) = compileFinal createHashMapFromArray [
|
||||
params [["_org", createHashMap, [createHashMap]], ["_requesterUid", "", [""]]];
|
||||
|
||||
private _memberUids = keys (_org getOrDefault ["members", createHashMap]);
|
||||
if !(_requesterUid in _memberUids) then { _memberUids pushBack _requesterUid; };
|
||||
if (_requesterUid isNotEqualTo "" && { !(_requesterUid in _memberUids) }) then {
|
||||
_memberUids pushBack _requesterUid;
|
||||
};
|
||||
|
||||
_memberUids
|
||||
}],
|
||||
@ -88,7 +90,7 @@ GVAR(OrgTreasuryServiceBase) = compileFinal createHashMapFromArray [
|
||||
private _memberUids = _self call ["resolveOrgMemberUids", [_org, _requesterUid]];
|
||||
|
||||
_result set ["success", true];
|
||||
_result set ["message", format ["Credit line of $%1 assigned to %2.", [_amount] call BIS_fnc_numberText, _resolvedMemberName]];
|
||||
_result set ["message", format ["Credit line of $%1 assigned to %2.", [_amount] call EFUNC(common,formatNumber), _resolvedMemberName]];
|
||||
_result set ["patch", _patch];
|
||||
_result set ["memberUids", _memberUids];
|
||||
_result
|
||||
|
||||
@ -20,7 +20,7 @@ GVAR(StoreCatalogServiceBaseClass) = compileFinal createHashMapFromArray [
|
||||
["formatCurrency", compileFinal {
|
||||
params [["_amount", 0, [0]]];
|
||||
|
||||
format ["$%1", [_amount max 0] call BIS_fnc_numberText]
|
||||
format ["$%1", [_amount max 0] call EFUNC(common,formatNumber)]
|
||||
}],
|
||||
["isVisibleConfig", compileFinal {
|
||||
params [["_cfg", configNull, [configNull]]];
|
||||
|
||||
@ -158,7 +158,7 @@ GVAR(StoreBaseStore) = compileFinal createHashMapFromArray [
|
||||
["formatCurrency", compileFinal {
|
||||
params [["_amount", 0, [0]]];
|
||||
|
||||
format ["$%1", [_amount max 0] call BIS_fnc_numberText]
|
||||
format ["$%1", [_amount max 0] call EFUNC(common,formatNumber)]
|
||||
}],
|
||||
["applyPaymentPatch", compileFinal {
|
||||
params [["_uid", "", [""]], ["_player", objNull, [objNull]], ["_paymentMethod", "cash", [""]], ["_total", 0, [0]], ["_commit", false, [false]]];
|
||||
|
||||
1
arma/server/addons/task/$PBOPREFIX$
Normal file
1
arma/server/addons/task/$PBOPREFIX$
Normal file
@ -0,0 +1 @@
|
||||
forge\forge_server\addons\task
|
||||
17
arma/server/addons/task/CfgEventHandlers.hpp
Normal file
17
arma/server/addons/task/CfgEventHandlers.hpp
Normal file
@ -0,0 +1,17 @@
|
||||
class Extended_PreStart_EventHandlers {
|
||||
class ADDON {
|
||||
init = QUOTE(call COMPILE_SCRIPT(XEH_preStart));
|
||||
};
|
||||
};
|
||||
|
||||
class Extended_PreInit_EventHandlers {
|
||||
class ADDON {
|
||||
init = QUOTE(call COMPILE_SCRIPT(XEH_preInit));
|
||||
};
|
||||
};
|
||||
|
||||
class Extended_PostInit_EventHandlers {
|
||||
class ADDON {
|
||||
init = QUOTE(call COMPILE_SCRIPT(XEH_postInit));
|
||||
};
|
||||
};
|
||||
6
arma/server/addons/task/CfgFactionClasses.hpp
Normal file
6
arma/server/addons/task/CfgFactionClasses.hpp
Normal file
@ -0,0 +1,6 @@
|
||||
class CfgFactionClasses {
|
||||
class NO_CATEGORY;
|
||||
class FORGE_Modules: NO_CATEGORY {
|
||||
displayName = "FORGE";
|
||||
};
|
||||
};
|
||||
269
arma/server/addons/task/CfgMissions.hpp
Normal file
269
arma/server/addons/task/CfgMissions.hpp
Normal file
@ -0,0 +1,269 @@
|
||||
// TODO: Move to mission template and provide documentation
|
||||
class CfgMissions {
|
||||
// Global settings
|
||||
maxConcurrentMissions = 3;
|
||||
missionInterval = 300; // 5 minutes between mission generation
|
||||
|
||||
// Mission type weights
|
||||
class MissionWeights {
|
||||
attack = 0.2;
|
||||
defend = 0.2;
|
||||
hostage = 0.2;
|
||||
hvt = 0.15;
|
||||
defuse = 0.15;
|
||||
delivery = 0.1;
|
||||
};
|
||||
|
||||
// Mission locations
|
||||
class Locations {
|
||||
class CityOne {
|
||||
position[] = {1000, 1000, 0};
|
||||
type = "city";
|
||||
radius = 300;
|
||||
suitable[] = {"attack", "defend", "hostage"};
|
||||
};
|
||||
class MilitaryBase {
|
||||
position[] = {2000, 2000, 0};
|
||||
type = "military";
|
||||
radius = 500;
|
||||
suitable[] = {"hvt", "defend", "attack"};
|
||||
};
|
||||
class Industrial {
|
||||
position[] = {3000, 3000, 0};
|
||||
type = "industrial";
|
||||
radius = 200;
|
||||
suitable[] = {"delivery", "defuse"};
|
||||
};
|
||||
};
|
||||
|
||||
// AI Groups configuration
|
||||
class AIGroups {
|
||||
class Infantry {
|
||||
side = "EAST";
|
||||
class Units {
|
||||
class Unit0 {
|
||||
vehicle = "O_Soldier_TL_F";
|
||||
rank = "SERGEANT";
|
||||
position[] = {0, 0, 0};
|
||||
};
|
||||
class Unit1 {
|
||||
vehicle = "O_Soldier_AR_F";
|
||||
rank = "CORPORAL";
|
||||
position[] = {5, -5, 0};
|
||||
};
|
||||
class Unit2 {
|
||||
vehicle = "O_Soldier_LAT_F";
|
||||
rank = "PRIVATE";
|
||||
position[] = {-5, -5, 0};
|
||||
};
|
||||
};
|
||||
suitable[] = {"attack", "defend", "hostage"};
|
||||
};
|
||||
class Assault {
|
||||
side = "EAST";
|
||||
class Units {
|
||||
class Unit0 {
|
||||
vehicle = "O_Soldier_SL_F";
|
||||
rank = "SERGEANT";
|
||||
position[] = {0, 0, 0};
|
||||
};
|
||||
class Unit1 {
|
||||
vehicle = "O_Soldier_GL_F";
|
||||
rank = "CORPORAL";
|
||||
position[] = {4, -3, 0};
|
||||
};
|
||||
class Unit2 {
|
||||
vehicle = "O_Soldier_AR_F";
|
||||
rank = "CORPORAL";
|
||||
position[] = {-4, -3, 0};
|
||||
};
|
||||
class Unit3 {
|
||||
vehicle = "O_medic_F";
|
||||
rank = "PRIVATE";
|
||||
position[] = {7, -6, 0};
|
||||
};
|
||||
};
|
||||
suitable[] = {"attack", "defend"};
|
||||
};
|
||||
class MotorizedPatrol {
|
||||
side = "EAST";
|
||||
class Units {
|
||||
class Unit0 {
|
||||
vehicle = "O_Soldier_TL_F";
|
||||
rank = "SERGEANT";
|
||||
position[] = {0, 0, 0};
|
||||
};
|
||||
class Unit1 {
|
||||
vehicle = "O_Soldier_LAT_F";
|
||||
rank = "CORPORAL";
|
||||
position[] = {5, -4, 0};
|
||||
};
|
||||
class Unit2 {
|
||||
vehicle = "O_Soldier_F";
|
||||
rank = "PRIVATE";
|
||||
position[] = {-5, -4, 0};
|
||||
};
|
||||
class Unit3 {
|
||||
vehicle = "O_Soldier_A_F";
|
||||
rank = "PRIVATE";
|
||||
position[] = {8, -7, 0};
|
||||
};
|
||||
};
|
||||
suitable[] = {"attack", "defend"};
|
||||
};
|
||||
class SpecOps {
|
||||
side = "EAST";
|
||||
class Units {
|
||||
class Unit0 {
|
||||
vehicle = "O_recon_TL_F";
|
||||
rank = "SERGEANT";
|
||||
position[] = {0, 0, 0};
|
||||
};
|
||||
class Unit1 {
|
||||
vehicle = "O_recon_M_F";
|
||||
rank = "CORPORAL";
|
||||
position[] = {5, -5, 0};
|
||||
};
|
||||
};
|
||||
suitable[] = {"hvt", "hostage"};
|
||||
};
|
||||
class ReconRaid {
|
||||
side = "EAST";
|
||||
class Units {
|
||||
class Unit0 {
|
||||
vehicle = "O_recon_TL_F";
|
||||
rank = "SERGEANT";
|
||||
position[] = {0, 0, 0};
|
||||
};
|
||||
class Unit1 {
|
||||
vehicle = "O_recon_M_F";
|
||||
rank = "CORPORAL";
|
||||
position[] = {4, -4, 0};
|
||||
};
|
||||
class Unit2 {
|
||||
vehicle = "O_recon_LAT_F";
|
||||
rank = "CORPORAL";
|
||||
position[] = {-4, -4, 0};
|
||||
};
|
||||
class Unit3 {
|
||||
vehicle = "O_recon_medic_F";
|
||||
rank = "PRIVATE";
|
||||
position[] = {7, -7, 0};
|
||||
};
|
||||
};
|
||||
suitable[] = {"attack", "hvt", "hostage"};
|
||||
};
|
||||
};
|
||||
|
||||
// TODO: Continue to refine mission types and their specific settings
|
||||
// Mission type specific settings
|
||||
class MissionTypes {
|
||||
class Attack {
|
||||
minUnits = 4;
|
||||
maxUnits = 8;
|
||||
class Rewards {
|
||||
money[] = {25000, 60000};
|
||||
reputation[] = {6, 14};
|
||||
equipment[] = {{"ItemGPS", 0.5}, {"ItemCompass", 0.3}};
|
||||
supplies[] = {{"FirstAidKit", 0.2}, {"Medikit", 0.1}};
|
||||
weapons[] = {{"arifle_MX_F", 0.3}, {"arifle_Katiba_F", 0.2}};
|
||||
vehicles[] = {{"B_MRAP_01_F", 0.1}, {"B_APC_Wheeled_01_cannon_F", 0.05}};
|
||||
special[] = {{"B_UAV_01_F", 0.05}, {"B_Heli_Light_01_F", 0.02}};
|
||||
};
|
||||
penalty[] = {-8, -3};
|
||||
timeLimit[] = {900, 1800}; // 15-30 minutes
|
||||
};
|
||||
|
||||
class Defend {
|
||||
minWaves = 3;
|
||||
maxWaves = 8;
|
||||
unitsPerWave[] = {4, 8};
|
||||
waveCooldown = 300;
|
||||
class Rewards {
|
||||
money[] = {40000, 90000};
|
||||
reputation[] = {8, 18};
|
||||
equipment[] = {{"ItemGPS", 0.5}, {"ItemCompass", 0.3}};
|
||||
supplies[] = {{"FirstAidKit", 0.2}, {"Medikit", 0.1}};
|
||||
weapons[] = {{"arifle_MX_F", 0.3}, {"arifle_Katiba_F", 0.2}};
|
||||
vehicles[] = {{"B_MRAP_01_F", 0.1}, {"B_APC_Wheeled_01_cannon_F", 0.05}};
|
||||
special[] = {{"B_UAV_01_F", 0.05}, {"B_Heli_Light_01_F", 0.02}};
|
||||
};
|
||||
penalty[] = {-12, -4};
|
||||
timeLimit[] = {1800, 3600}; // 30-60 minutes
|
||||
};
|
||||
|
||||
class Hostage {
|
||||
class Hostages {
|
||||
civilian[] = {"C_man_1", "C_man_polo_1_F"};
|
||||
military[] = {"B_Pilot_F", "B_officer_F"};
|
||||
};
|
||||
class Rewards {
|
||||
money[] = {60000, 140000};
|
||||
reputation[] = {12, 25};
|
||||
equipment[] = {{"ItemGPS", 0.5}, {"ItemCompass", 0.3}};
|
||||
supplies[] = {{"FirstAidKit", 0.2}, {"Medikit", 0.1}};
|
||||
weapons[] = {{"arifle_MX_F", 0.3}, {"arifle_Katiba_F", 0.2}};
|
||||
vehicles[] = {{"B_MRAP_01_F", 0.1}, {"B_APC_Wheeled_01_cannon_F", 0.05}};
|
||||
special[] = {{"B_UAV_01_F", 0.05}, {"B_Heli_Light_01_F", 0.02}};
|
||||
};
|
||||
penalty[] = {-16, -6};
|
||||
timeLimit[] = {600, 900}; // 10-15 minutes
|
||||
};
|
||||
|
||||
class HVT {
|
||||
class Targets {
|
||||
officer[] = {"O_officer_F"};
|
||||
sniper[] = {"O_sniper_F"};
|
||||
};
|
||||
escorts = 4;
|
||||
class Rewards {
|
||||
money[] = {50000, 120000};
|
||||
reputation[] = {10, 22};
|
||||
equipment[] = {{"ItemGPS", 0.5}, {"ItemCompass", 0.3}};
|
||||
supplies[] = {{"FirstAidKit", 0.2}, {"Medikit", 0.1}};
|
||||
weapons[] = {{"arifle_MX_F", 0.3}, {"arifle_Katiba_F", 0.2}};
|
||||
vehicles[] = {{"B_MRAP_01_F", 0.1}, {"B_APC_Wheeled_01_cannon_F", 0.05}};
|
||||
special[] = {{"B_UAV_01_F", 0.05}, {"B_Heli_Light_01_F", 0.02}};
|
||||
};
|
||||
penalty[] = {-14, -5};
|
||||
timeLimit[] = {900, 1800}; // 15-30 minutes
|
||||
};
|
||||
|
||||
class Defuse {
|
||||
class Devices {
|
||||
small[] = {"DemoCharge_Remote_Mag"};
|
||||
large[] = {"SatchelCharge_Remote_Mag"};
|
||||
};
|
||||
maxDevices = 3;
|
||||
class Rewards {
|
||||
money[] = {20000, 50000};
|
||||
reputation[] = {5, 12};
|
||||
equipment[] = {{"ItemGPS", 0.5}, {"ItemCompass", 0.3}};
|
||||
supplies[] = {{"FirstAidKit", 0.2}, {"Medikit", 0.1}};
|
||||
weapons[] = {{"arifle_MX_F", 0.3}, {"arifle_Katiba_F", 0.2}};
|
||||
vehicles[] = {{"B_MRAP_01_F", 0.1}, {"B_APC_Wheeled_01_cannon_F", 0.05}};
|
||||
special[] = {{"B_UAV_01_F", 0.05}, {"B_Heli_Light_01_F", 0.02}};
|
||||
};
|
||||
penalty[] = {-9, -3};
|
||||
timeLimit[] = {600, 900}; // 10-15 minutes
|
||||
};
|
||||
|
||||
class Delivery {
|
||||
class Cargo {
|
||||
supplies[] = {"Land_CargoBox_V1_F"};
|
||||
vehicles[] = {"B_MRAP_01_F", "B_Truck_01_transport_F"};
|
||||
};
|
||||
class Rewards {
|
||||
money[] = {10000, 30000};
|
||||
reputation[] = {3, 8};
|
||||
equipment[] = {{"ItemGPS", 0.5}, {"ItemCompass", 0.3}};
|
||||
supplies[] = {{"FirstAidKit", 0.2}, {"Medikit", 0.1}};
|
||||
weapons[] = {{"arifle_MX_F", 0.3}, {"arifle_Katiba_F", 0.2}};
|
||||
vehicles[] = {{"B_MRAP_01_F", 0.1}, {"B_APC_Wheeled_01_cannon_F", 0.05}};
|
||||
special[] = {{"B_UAV_01_F", 0.05}, {"B_Heli_Light_01_F", 0.02}};
|
||||
};
|
||||
penalty[] = {-6, -2};
|
||||
timeLimit[] = {900, 1800}; // 15-30 minutes
|
||||
};
|
||||
};
|
||||
};
|
||||
782
arma/server/addons/task/CfgVehicles.hpp
Normal file
782
arma/server/addons/task/CfgVehicles.hpp
Normal file
@ -0,0 +1,782 @@
|
||||
class CfgVehicles {
|
||||
class Logic;
|
||||
class Module_F: Logic {
|
||||
class AttributesBase {
|
||||
class Edit;
|
||||
class Combo;
|
||||
};
|
||||
class ModuleDescription {};
|
||||
};
|
||||
|
||||
class FORGE_Module_Attack: Module_F {
|
||||
scope = 2;
|
||||
displayName = "Attack Task";
|
||||
// icon = "\a3\ui_f\data\IGUI\Cfg\simpleTasks\types\default_ca.paa";
|
||||
category = "FORGE_Modules";
|
||||
|
||||
function = QFUNC(attackModule);
|
||||
functionPriority = 1;
|
||||
isGlobal = 1;
|
||||
isTriggerActivated = 1;
|
||||
isDisposable = 1;
|
||||
is3DEN = 0;
|
||||
|
||||
canSetArea = 0;
|
||||
canSetAreaShape = 0;
|
||||
canSetAreaHeight = 0;
|
||||
|
||||
class AttributeValues {};
|
||||
class Attributes: AttributesBase {
|
||||
class TaskID: Edit {
|
||||
property = "FORGE_Module_Attack_TaskID";
|
||||
displayName = "Task ID";
|
||||
tooltip = "Unique identifier for this task";
|
||||
typeName = "STRING";
|
||||
// defaultValue = """";
|
||||
};
|
||||
class LimitFail: Edit {
|
||||
property = "FORGE_Module_Attack_LimitFail";
|
||||
displayName = "Fail Limit";
|
||||
tooltip = "Number of targets that escape to fail the task";
|
||||
typeName = "NUMBER";
|
||||
defaultValue = -1;
|
||||
};
|
||||
class LimitSuccess: Edit {
|
||||
property = "FORGE_Module_Attack_LimitSuccess";
|
||||
displayName = "Success Limit";
|
||||
tooltip = "Number of targets that need to be eliminated to succeed the task";
|
||||
typeName = "NUMBER";
|
||||
defaultValue = -1;
|
||||
};
|
||||
class CompanyFunds: Edit {
|
||||
property = "FORGE_Module_Attack_CompanyFunds";
|
||||
displayName = "Reward Funds";
|
||||
tooltip = "Amount of funds awarded on success";
|
||||
typeName = "NUMBER";
|
||||
defaultValue = 0;
|
||||
};
|
||||
class RatingFail: Edit {
|
||||
property = "FORGE_Module_Attack_RatingFail";
|
||||
displayName = "Rating Loss";
|
||||
tooltip = "Amount of rating lost on failure";
|
||||
typeName = "NUMBER";
|
||||
defaultValue = 0;
|
||||
};
|
||||
class RatingSuccess: Edit {
|
||||
property = "FORGE_Module_Attack_RatingSuccess";
|
||||
displayName = "Rating Gain";
|
||||
tooltip = "Amount of rating gained on success";
|
||||
typeName = "NUMBER";
|
||||
defaultValue = 0;
|
||||
};
|
||||
class EndSuccess: Combo {
|
||||
property = "FORGE_Module_Attack_EndSuccess";
|
||||
displayName = "End on Success";
|
||||
tooltip = "End mission when task is completed successfully";
|
||||
typeName = "BOOL";
|
||||
defaultValue = 0;
|
||||
|
||||
class Values {
|
||||
class EnableEndSuccess { name = "Enable"; value = 1; };
|
||||
class DisableEndSuccess { name = "Disable"; value = 0; };
|
||||
};
|
||||
};
|
||||
class EndFail: Combo {
|
||||
property = "FORGE_Module_Attack_EndFail";
|
||||
displayName = "End on Failure";
|
||||
tooltip = "End mission when task fails";
|
||||
typeName = "BOOL";
|
||||
defaultValue = 0;
|
||||
|
||||
class Values {
|
||||
class EnableEndFail { name = "Enable"; value = 1; };
|
||||
class DisableEndFail { name = "Disable"; value = 0; };
|
||||
};
|
||||
};
|
||||
class TimeLimit: Edit {
|
||||
property = "FORGE_Module_Attack_TimeLimit";
|
||||
displayName = "Time Limit";
|
||||
tooltip = "Time in seconds before targets escape (0 for no limit)";
|
||||
typeName = "NUMBER";
|
||||
defaultValue = 0;
|
||||
};
|
||||
};
|
||||
|
||||
class ModuleDescription: ModuleDescription {
|
||||
description = "Creates an attack task with configurable parameters";
|
||||
sync[] = { "Anything" };
|
||||
|
||||
class Anything {
|
||||
description[] = {
|
||||
"Attack task module",
|
||||
"Sync with units/vehicles to mark as targets"
|
||||
};
|
||||
position = 1;
|
||||
direction = 1;
|
||||
optional = 1;
|
||||
duplicate = 1;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
class FORGE_Module_Explosives: Module_F {
|
||||
scope = 2;
|
||||
displayName = "Explosive Entities";
|
||||
// icon = "\a3\ui_f\data\IGUI\Cfg\simpleTasks\types\default_ca.paa";
|
||||
category = "FORGE_Modules";
|
||||
|
||||
function = QFUNC(explosivesModule);
|
||||
functionPriority = 1;
|
||||
isGlobal = 1;
|
||||
isTriggerActivated = 0;
|
||||
isDisposable = 1;
|
||||
is3DEN = 0;
|
||||
|
||||
canSetArea = 0;
|
||||
canSetAreaShape = 0;
|
||||
canSetAreaHeight = 0;
|
||||
|
||||
class AttributeValues {};
|
||||
class Attributes: AttributesBase {};
|
||||
class ModuleDescription: ModuleDescription {
|
||||
description = "Module for explosive entities that need to be defused";
|
||||
sync[] = { "Anything" };
|
||||
|
||||
class Anything {
|
||||
description[] = {
|
||||
"Explosive entities module",
|
||||
"Sync with objects to mark as explosives",
|
||||
"Those objects will be processed as defusal targets"
|
||||
};
|
||||
position = 1;
|
||||
direction = 1;
|
||||
optional = 1;
|
||||
duplicate = 1;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
class FORGE_Module_Hostages: Module_F {
|
||||
scope = 2;
|
||||
displayName = "Hostage Entities";
|
||||
// icon = "\a3\ui_f\data\IGUI\Cfg\simpleTasks\types\default_ca.paa";
|
||||
category = "FORGE_Modules";
|
||||
|
||||
function = QFUNC(hostagesModule);
|
||||
functionPriority = 1;
|
||||
isGlobal = 1;
|
||||
isTriggerActivated = 0;
|
||||
isDisposable = 1;
|
||||
is3DEN = 0;
|
||||
|
||||
canSetArea = 0;
|
||||
canSetAreaShape = 0;
|
||||
canSetAreaHeight = 0;
|
||||
|
||||
class AttributeValues {};
|
||||
class Attributes: AttributesBase {};
|
||||
class ModuleDescription: ModuleDescription {
|
||||
description = "Module for hostage entities that need to be rescued";
|
||||
sync[] = { "Anything" };
|
||||
|
||||
class Anything {
|
||||
description[] = {
|
||||
"Hostage entities module",
|
||||
"Sync with units to mark as hostages",
|
||||
"Those objects will be processed as rescue targets"
|
||||
};
|
||||
position = 1;
|
||||
direction = 1;
|
||||
optional = 1;
|
||||
duplicate = 1;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
class FORGE_Module_Shooters: Module_F {
|
||||
scope = 2;
|
||||
displayName = "Shooter Entities";
|
||||
// icon = "\a3\ui_f\data\IGUI\Cfg\simpleTasks\types\default_ca.paa";
|
||||
category = "FORGE_Modules";
|
||||
|
||||
function = QFUNC(shootersModule);
|
||||
functionPriority = 1;
|
||||
isGlobal = 1;
|
||||
isTriggerActivated = 0;
|
||||
isDisposable = 1;
|
||||
is3DEN = 0;
|
||||
|
||||
canSetArea = 0;
|
||||
canSetAreaShape = 0;
|
||||
canSetAreaHeight = 0;
|
||||
|
||||
class AttributeValues {};
|
||||
class Attributes: AttributesBase {};
|
||||
class ModuleDescription: ModuleDescription {
|
||||
description = "Module for shooter entities that need to be eliminated";
|
||||
sync[] = { "AnyBrain" };
|
||||
|
||||
class AnyBrain {
|
||||
description[] = {
|
||||
"Shooter entities module",
|
||||
"Sync with units to mark as shooters",
|
||||
"Those objects will be processed as elimination targets"
|
||||
};
|
||||
position = 1;
|
||||
direction = 1;
|
||||
optional = 1;
|
||||
duplicate = 1;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
class FORGE_Module_Protected: Module_F {
|
||||
scope = 2;
|
||||
displayName = "Protected Entities";
|
||||
// icon = "\a3\ui_f\data\IGUI\Cfg\simpleTasks\types\default_ca.paa";
|
||||
category = "FORGE_Modules";
|
||||
|
||||
function = QFUNC(protectedModule);
|
||||
functionPriority = 1;
|
||||
isGlobal = 1;
|
||||
isTriggerActivated = 0;
|
||||
isDisposable = 1;
|
||||
is3DEN = 0;
|
||||
|
||||
canSetArea = 0;
|
||||
canSetAreaShape = 0;
|
||||
canSetAreaHeight = 0;
|
||||
|
||||
class AttributeValues {};
|
||||
class Attributes: AttributesBase {};
|
||||
class ModuleDescription: ModuleDescription {
|
||||
description = "Module for protected entities that need to be protected";
|
||||
sync[] = { "Anything" };
|
||||
|
||||
class Anything {
|
||||
description[] = {
|
||||
"Protected entities module",
|
||||
"Sync with objects to mark as protected entities",
|
||||
"Those objects will be processed as protected targets"
|
||||
};
|
||||
position = 1;
|
||||
direction = 1;
|
||||
optional = 1;
|
||||
duplicate = 1;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
class FORGE_Module_Defuse: Module_F {
|
||||
scope = 2;
|
||||
displayName = "Defuse Task";
|
||||
// icon = "\a3\ui_f\data\IGUI\Cfg\simpleTasks\types\default_ca.paa";
|
||||
category = "FORGE_Modules";
|
||||
|
||||
function = QFUNC(defuseModule);
|
||||
functionPriority = 1;
|
||||
isGlobal = 1;
|
||||
isTriggerActivated = 1;
|
||||
isDisposable = 1;
|
||||
is3DEN = 0;
|
||||
|
||||
canSetArea = 0;
|
||||
canSetAreaShape = 0;
|
||||
canSetAreaHeight = 0;
|
||||
|
||||
class AttributeValues {};
|
||||
class Attributes: AttributesBase {
|
||||
class TaskID: Edit {
|
||||
property = "FORGE_Module_Defuse_TaskID";
|
||||
displayName = "Task ID";
|
||||
tooltip = "Unique identifier for this task";
|
||||
typeName = "STRING";
|
||||
// defaultValue = """";
|
||||
};
|
||||
class LimitFail: Edit {
|
||||
property = "FORGE_Module_Defuse_LimitFail";
|
||||
displayName = "Fail Limit";
|
||||
tooltip = "Number of protected entities destroyed to fail the task";
|
||||
typeName = "NUMBER";
|
||||
defaultValue = -1;
|
||||
};
|
||||
class LimitSuccess: Edit {
|
||||
property = "FORGE_Module_Defuse_LimitSuccess";
|
||||
displayName = "Success Limit";
|
||||
tooltip = "Number of entities that need to be defused to complete the task";
|
||||
typeName = "NUMBER";
|
||||
defaultValue = -1;
|
||||
};
|
||||
class CompanyFunds: Edit {
|
||||
property = "FORGE_Module_Defuse_CompanyFunds";
|
||||
displayName = "Reward Funds";
|
||||
tooltip = "Amount of funds awarded on success";
|
||||
typeName = "NUMBER";
|
||||
defaultValue = 0;
|
||||
};
|
||||
class RatingFail: Edit {
|
||||
property = "FORGE_Module_Defuse_RatingFail";
|
||||
displayName = "Rating Loss";
|
||||
tooltip = "Amount of rating lost on failure";
|
||||
typeName = "NUMBER";
|
||||
defaultValue = 0;
|
||||
};
|
||||
class RatingSuccess: Edit {
|
||||
property = "FORGE_Module_Defuse_RatingSuccess";
|
||||
displayName = "Rating Gain";
|
||||
tooltip = "Amount of rating gained on success";
|
||||
typeName = "NUMBER";
|
||||
defaultValue = 0;
|
||||
};
|
||||
class EndSuccess: Combo {
|
||||
property = "FORGE_Module_Defuse_EndSuccess";
|
||||
displayName = "End on Success";
|
||||
tooltip = "End mission when task is completed successfully";
|
||||
typeName = "BOOL";
|
||||
defaultValue = 0;
|
||||
|
||||
class Values {
|
||||
class EnableEndSuccess { name = "Enable"; value = 1; };
|
||||
class DisableEnSuccess { name = "Disable"; value = 0; };
|
||||
};
|
||||
};
|
||||
class EndFail: Combo {
|
||||
property = "FORGE_Module_Defuse_EndFail";
|
||||
displayName = "End on Failure";
|
||||
tooltip = "End mission when task fails";
|
||||
typeName = "BOOL";
|
||||
defaultValue = 0;
|
||||
|
||||
class Values {
|
||||
class EnableEndFail { name = "Enable"; value = 1; };
|
||||
class DisableEndFail { name = "Disable"; value = 0; };
|
||||
};
|
||||
};
|
||||
class TimeLimit: Edit {
|
||||
property = "FORGE_Module_Defuse_TimeLimit";
|
||||
displayName = "Time Limit";
|
||||
tooltip = "Time in seconds before detenation (0 for no limit)";
|
||||
typeName = "NUMBER";
|
||||
defaultValue = 0;
|
||||
};
|
||||
};
|
||||
|
||||
class ModuleDescription: ModuleDescription {
|
||||
description = "Creates a defuse task with configurable parameters";
|
||||
sync[] = { "Anything" };
|
||||
|
||||
class Anything {
|
||||
description[] = {
|
||||
"Defuse task module",
|
||||
"Sync with entities to mark as explosives and protected entities",
|
||||
};
|
||||
position = 1;
|
||||
direction = 1;
|
||||
optional = 1;
|
||||
duplicate = 1;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
class FORGE_Module_Destroy: Module_F {
|
||||
scope = 2;
|
||||
displayName = "Destroy Task";
|
||||
// icon = "\a3\ui_f\data\IGUI\Cfg\simpleTasks\types\default_ca.paa";
|
||||
category = "FORGE_Modules";
|
||||
|
||||
function = QFUNC(destroyModule);
|
||||
functionPriority = 1;
|
||||
isGlobal = 1;
|
||||
isTriggerActivated = 1;
|
||||
isDisposable = 1;
|
||||
is3DEN = 0;
|
||||
|
||||
canSetArea = 0;
|
||||
canSetAreaShape = 0;
|
||||
canSetAreaHeight = 0;
|
||||
|
||||
class AttributeValues {};
|
||||
class Attributes: AttributesBase {
|
||||
class TaskID: Edit {
|
||||
property = "FORGE_Module_Destroy_TaskID";
|
||||
displayName = "Task ID";
|
||||
tooltip = "Unique identifier for this task";
|
||||
typeName = "STRING";
|
||||
// defaultValue = """";
|
||||
};
|
||||
class LimitFail: Edit {
|
||||
property = "FORGE_Module_Destroy_LimitFail";
|
||||
displayName = "Fail Limit";
|
||||
tooltip = "Number of targets that can escape before failing";
|
||||
typeName = "NUMBER";
|
||||
defaultValue = -1;
|
||||
};
|
||||
class LimitSuccess: Edit {
|
||||
property = "FORGE_Module_Destroy_LimitSuccess";
|
||||
displayName = "Success Limit";
|
||||
tooltip = "Number of targets that need to be destroyed";
|
||||
typeName = "NUMBER";
|
||||
defaultValue = -1;
|
||||
};
|
||||
class CompanyFunds: Edit {
|
||||
property = "FORGE_Module_Destroy_CompanyFunds";
|
||||
displayName = "Reward Funds";
|
||||
tooltip = "Amount of funds awarded on success";
|
||||
typeName = "NUMBER";
|
||||
defaultValue = 0;
|
||||
};
|
||||
class RatingFail: Edit {
|
||||
property = "FORGE_Module_Destroy_RatingFail";
|
||||
displayName = "Rating Loss";
|
||||
tooltip = "Amount of rating lost on failure";
|
||||
typeName = "NUMBER";
|
||||
defaultValue = 0;
|
||||
};
|
||||
class RatingSuccess: Edit {
|
||||
property = "FORGE_Module_Destroy_RatingSuccess";
|
||||
displayName = "Rating Gain";
|
||||
tooltip = "Amount of rating gained on success";
|
||||
typeName = "NUMBER";
|
||||
defaultValue = 0;
|
||||
};
|
||||
class EndSuccess: Combo {
|
||||
property = "FORGE_Module_Destroy_EndSuccess";
|
||||
displayName = "End on Success";
|
||||
tooltip = "End mission when task is completed successfully";
|
||||
typeName = "BOOL";
|
||||
defaultValue = 0;
|
||||
|
||||
class Values {
|
||||
class EnableEndSuccess { name = "Enable"; value = 1; };
|
||||
class DisableEndSuccess { name = "Disable"; value = 0; };
|
||||
};
|
||||
};
|
||||
class EndFail: Combo {
|
||||
property = "FORGE_Module_Destroy_EndFail";
|
||||
displayName = "End on Failure";
|
||||
tooltip = "End mission when task fails";
|
||||
typeName = "BOOL";
|
||||
defaultValue = 0;
|
||||
|
||||
class Values {
|
||||
class EnableEndFail { name = "Enable"; value = 1; };
|
||||
class DisableEndFail { name = "Disable"; value = 0; };
|
||||
};
|
||||
};
|
||||
class TimeLimit: Edit {
|
||||
property = "FORGE_Module_Destroy_TimeLimit";
|
||||
displayName = "Time Limit";
|
||||
tooltip = "Time in seconds before targets escape (0 for no limit)";
|
||||
typeName = "NUMBER";
|
||||
defaultValue = 0;
|
||||
};
|
||||
};
|
||||
|
||||
class ModuleDescription: ModuleDescription {
|
||||
description = "Creates a destroy task with configurable parameters";
|
||||
sync[] = { "Anything" };
|
||||
|
||||
class Anything {
|
||||
description[] = {
|
||||
"Destroy task module",
|
||||
"Sync with units and/or vehicles to mark as targets"
|
||||
};
|
||||
position = 1;
|
||||
direction = 1;
|
||||
optional = 1;
|
||||
duplicate = 1;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
class FORGE_Module_Hostage: Module_F {
|
||||
scope = 2;
|
||||
displayName = "Hostage Task";
|
||||
// icon = "\a3\ui_f\data\IGUI\Cfg\simpleTasks\types\default_ca.paa";
|
||||
category = "FORGE_Modules";
|
||||
|
||||
function = QFUNC(hostageModule);
|
||||
functionPriority = 1;
|
||||
isGlobal = 1;
|
||||
isTriggerActivated = 1;
|
||||
isDisposable = 1;
|
||||
is3DEN = 0;
|
||||
|
||||
canSetArea = 0;
|
||||
canSetAreaShape = 0;
|
||||
canSetAreaHeight = 0;
|
||||
|
||||
class AttributeValues {};
|
||||
class Attributes: AttributesBase {
|
||||
class TaskID: Edit {
|
||||
property = "FORGE_Module_Hostage_TaskID";
|
||||
displayName = "Task ID";
|
||||
tooltip = "Unique identifier for this task";
|
||||
typeName = "STRING";
|
||||
// defaultValue = """";
|
||||
};
|
||||
class LimitFail: Edit {
|
||||
property = "FORGE_Module_Hostage_LimitFail";
|
||||
displayName = "Fail Limit";
|
||||
tooltip = "Number of hostages KIA before failing";
|
||||
typeName = "NUMBER";
|
||||
defaultValue = -1;
|
||||
};
|
||||
class LimitSuccess: Edit {
|
||||
property = "FORGE_Module_Hostage_LimitSuccess";
|
||||
displayName = "Success Limit";
|
||||
tooltip = "Number of hostages rescued before succeeding";
|
||||
typeName = "NUMBER";
|
||||
defaultValue = -1;
|
||||
};
|
||||
class ExtZone: Edit {
|
||||
property = "FORGE_Module_Hostage_ExtZone";
|
||||
displayName = "Extraction Zone";
|
||||
tooltip = "Unique marker name for the extraction zone";
|
||||
typeName = "STRING";
|
||||
// defaultValue = """";
|
||||
};
|
||||
class CompanyFunds: Edit {
|
||||
property = "FORGE_Module_Hostage_CompanyFunds";
|
||||
displayName = "Reward Funds";
|
||||
tooltip = "Amount of funds awarded on success";
|
||||
typeName = "NUMBER";
|
||||
defaultValue = 0;
|
||||
};
|
||||
class RatingFail: Edit {
|
||||
property = "FORGE_Module_Hostage_RatingFail";
|
||||
displayName = "Rating Loss";
|
||||
tooltip = "Amount of rating lost on failure";
|
||||
typeName = "NUMBER";
|
||||
defaultValue = 0;
|
||||
};
|
||||
class RatingSuccess: Edit {
|
||||
property = "FORGE_Module_Hostage_RatingSuccess";
|
||||
displayName = "Rating Gain";
|
||||
tooltip = "Amount of rating gained on success";
|
||||
typeName = "NUMBER";
|
||||
defaultValue = 0;
|
||||
};
|
||||
class CBRN: Combo {
|
||||
property = "FORGE_Module_Hostage_CBRN";
|
||||
displayName = "CBRN Attack";
|
||||
tooltip = "CBRN Attack instead of execution";
|
||||
typeName = "BOOL";
|
||||
defaultValue = 0;
|
||||
|
||||
class Values {
|
||||
class TrueCBRN { name = "True"; value = 1; };
|
||||
class FalseCBRN { name = "False"; value = 0; };
|
||||
};
|
||||
};
|
||||
class Execution: Combo {
|
||||
property = "FORGE_Module_Hostage_Execution";
|
||||
displayName = "Execution";
|
||||
tooltip = "Execution instead of CBRN Attack";
|
||||
typeName = "BOOL";
|
||||
defaultValue = 0;
|
||||
|
||||
class Values {
|
||||
class TrueExecution { name = "True"; value = 1; };
|
||||
class FalseExecution { name = "False"; value = 0; };
|
||||
};
|
||||
};
|
||||
class EndSuccess: Combo {
|
||||
property = "FORGE_Module_Hostage_EndSuccess";
|
||||
displayName = "End on Success";
|
||||
tooltip = "End mission when task is completed successfully";
|
||||
typeName = "BOOL";
|
||||
defaultValue = 0;
|
||||
|
||||
class Values {
|
||||
class EnableEndSuccess { name = "Enable"; value = 1; };
|
||||
class DisableEndSuccess { name = "Disable"; value = 0; };
|
||||
};
|
||||
};
|
||||
class EndFail: Combo {
|
||||
property = "FORGE_Module_Hostage_EndFail";
|
||||
displayName = "End on Failure";
|
||||
tooltip = "End mission when task fails";
|
||||
typeName = "BOOL";
|
||||
defaultValue = 0;
|
||||
|
||||
class Values {
|
||||
class EnableEndFail { name = "Enable"; value = 1; };
|
||||
class DisableEndFail { name = "Disable"; value = 0; };
|
||||
};
|
||||
};
|
||||
class TimeLimit: Edit {
|
||||
property = "FORGE_Module_Hostage_TimeLimit";
|
||||
displayName = "Time Limit";
|
||||
tooltip = "Time in seconds before HVTs escape (0 for no limit)";
|
||||
typeName = "NUMBER";
|
||||
defaultValue = 0;
|
||||
};
|
||||
class CBRNZone: Edit {
|
||||
property = "FORGE_Module_Hostage_CBRNZone";
|
||||
displayName = "CBRN Zone";
|
||||
tooltip = "Unique marker name for the CBRN zone";
|
||||
typeName = "STRING";
|
||||
// defaultValue = """";
|
||||
};
|
||||
};
|
||||
|
||||
class ModuleDescription: ModuleDescription {
|
||||
description = "Creates a Hostage task with configurable parameters";
|
||||
sync[] = { "Anything" };
|
||||
|
||||
class Anything {
|
||||
description[] = {
|
||||
"Hostage task module",
|
||||
"Sync with hostage and shooter module to register the entities to the task"
|
||||
};
|
||||
position = 1;
|
||||
direction = 1;
|
||||
optional = 1;
|
||||
duplicate = 1;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
class FORGE_Module_HVT: Module_F {
|
||||
scope = 2;
|
||||
displayName = "HVT Task";
|
||||
// icon = "\a3\ui_f\data\IGUI\Cfg\simpleTasks\types\default_ca.paa";
|
||||
category = "FORGE_Modules";
|
||||
|
||||
function = QFUNC(hvtModule);
|
||||
functionPriority = 1;
|
||||
isGlobal = 1;
|
||||
isTriggerActivated = 1;
|
||||
isDisposable = 1;
|
||||
is3DEN = 0;
|
||||
|
||||
canSetArea = 0;
|
||||
canSetAreaShape = 0;
|
||||
canSetAreaHeight = 0;
|
||||
|
||||
class AttributeValues {};
|
||||
class Attributes: AttributesBase {
|
||||
class TaskID: Edit {
|
||||
property = "FORGE_Module_HVT_TaskID";
|
||||
displayName = "Task ID";
|
||||
tooltip = "Unique identifier for this task";
|
||||
typeName = "STRING";
|
||||
// defaultValue = """";
|
||||
};
|
||||
class LimitFail: Edit {
|
||||
property = "FORGE_Module_HVT_LimitFail";
|
||||
displayName = "Fail Limit";
|
||||
tooltip = "Number of hvts that can escape or KIA before failing";
|
||||
typeName = "NUMBER";
|
||||
defaultValue = -1;
|
||||
};
|
||||
class LimitSuccess: Edit {
|
||||
property = "FORGE_Module_HVT_LimitSuccess";
|
||||
displayName = "Success Limit";
|
||||
tooltip = "Number of hvts that need to be captured or KIA";
|
||||
typeName = "NUMBER";
|
||||
defaultValue = -1;
|
||||
};
|
||||
class ExtZone: Edit {
|
||||
property = "FORGE_Module_HVT_ExtZone";
|
||||
displayName = "Extraction Zone";
|
||||
tooltip = "Unique marker name for the extraction zone";
|
||||
typeName = "STRING";
|
||||
// defaultValue = """";
|
||||
};
|
||||
class CompanyFunds: Edit {
|
||||
property = "FORGE_Module_HVT_CompanyFunds";
|
||||
displayName = "Reward Funds";
|
||||
tooltip = "Amount of funds awarded on success";
|
||||
typeName = "NUMBER";
|
||||
defaultValue = 0;
|
||||
};
|
||||
class RatingFail: Edit {
|
||||
property = "FORGE_Module_HVT_RatingFail";
|
||||
displayName = "Rating Loss";
|
||||
tooltip = "Amount of rating lost on failure";
|
||||
typeName = "NUMBER";
|
||||
defaultValue = 0;
|
||||
};
|
||||
class RatingSuccess: Edit {
|
||||
property = "FORGE_Module_HVT_RatingSuccess";
|
||||
displayName = "Rating Gain";
|
||||
tooltip = "Amount of rating gained on success";
|
||||
typeName = "NUMBER";
|
||||
defaultValue = 0;
|
||||
};
|
||||
class CaptureHVT: Combo {
|
||||
property = "FORGE_Module_HVT_CaptureHVT";
|
||||
displayName = "Capture HVT";
|
||||
tooltip = "Capture HVT instead of eliminating";
|
||||
typeName = "BOOL";
|
||||
defaultValue = 1;
|
||||
|
||||
class Values {
|
||||
class TrueCapture { name = "True"; value = 1; };
|
||||
class FalseCapture { name = "False"; value = 0; };
|
||||
};
|
||||
};
|
||||
class EliminateHVT: Combo {
|
||||
property = "FORGE_Module_HVT_EliminateHVT";
|
||||
displayName = "Eliminate HVT";
|
||||
tooltip = "Eliminate HVT instead of capturing";
|
||||
typeName = "BOOL";
|
||||
defaultValue = 0;
|
||||
|
||||
class Values {
|
||||
class TrueEliminate { name = "True"; value = 1; };
|
||||
class FalseEliminate { name = "False"; value = 0; };
|
||||
};
|
||||
};
|
||||
class EndSuccess: Combo {
|
||||
property = "FORGE_Module_HVT_EndSuccess";
|
||||
displayName = "End on Success";
|
||||
tooltip = "End mission when task is completed successfully";
|
||||
typeName = "BOOL";
|
||||
defaultValue = 0;
|
||||
|
||||
class Values {
|
||||
class EnableEndSuccess { name = "Enable"; value = 1; };
|
||||
class DisableEndSuccess { name = "Disable"; value = 0; };
|
||||
};
|
||||
};
|
||||
class EndFail: Combo {
|
||||
property = "FORGE_Module_HVT_EndFail";
|
||||
displayName = "End on Failure";
|
||||
tooltip = "End mission when task fails";
|
||||
typeName = "BOOL";
|
||||
defaultValue = 0;
|
||||
|
||||
class Values {
|
||||
class EnableEndFail { name = "Enable"; value = 1; };
|
||||
class DisableEndFail { name = "Disable"; value = 0; };
|
||||
};
|
||||
};
|
||||
class TimeLimit: Edit {
|
||||
property = "FORGE_Module_HVT_TimeLimit";
|
||||
displayName = "Time Limit";
|
||||
tooltip = "Time in seconds before HVTs escape (0 for no limit)";
|
||||
typeName = "NUMBER";
|
||||
defaultValue = 0;
|
||||
};
|
||||
};
|
||||
|
||||
class ModuleDescription: ModuleDescription {
|
||||
description = "Creates a HVT task with configurable parameters";
|
||||
sync[] = { "Anything" };
|
||||
|
||||
class Anything {
|
||||
description[] = {
|
||||
"HVT task module",
|
||||
"Sync with units to mark as HVTs"
|
||||
};
|
||||
position = 1;
|
||||
direction = 1;
|
||||
optional = 1;
|
||||
duplicate = 1;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
104
arma/server/addons/task/README.md
Normal file
104
arma/server/addons/task/README.md
Normal file
@ -0,0 +1,104 @@
|
||||
# Forge Task Module
|
||||
|
||||
## Overview
|
||||
The task addon is a server-owned mission/task system for Forge. It manages task execution, task-owned state, participant tracking, contribution-based player earnings, and org-owned rewards.
|
||||
|
||||
## Responsibilities
|
||||
- spawn and monitor task flows on the server
|
||||
- track per-task entities through `TaskStore`
|
||||
- track task participants and engine-rating contribution
|
||||
- award player earnings through the bank module
|
||||
- award org funds, reputation, assets, and fleet rewards
|
||||
- notify task participants and sync org updates to online members
|
||||
|
||||
## Dependencies
|
||||
- `forge_server_common`
|
||||
- `forge_server_actor`
|
||||
- `forge_server_bank`
|
||||
- `forge_server_org`
|
||||
- `forge_client_notifications`
|
||||
|
||||
## Main Components
|
||||
|
||||
### Task Flows
|
||||
- `fnc_attack.sqf`
|
||||
- `fnc_defend.sqf`
|
||||
- `fnc_defuse.sqf`
|
||||
- `fnc_delivery.sqf`
|
||||
- `fnc_destroy.sqf`
|
||||
- `fnc_hostage.sqf`
|
||||
- `fnc_hvt.sqf`
|
||||
|
||||
### TaskStore
|
||||
`fnc_initTaskStore.sqf` initializes `TaskStore`, which owns:
|
||||
- task ownership bindings
|
||||
- participant snapshots
|
||||
- defuse progress
|
||||
- per-task entity registries for cargo, hostages, HVTs, IEDs, protected entities, shooters, and targets
|
||||
|
||||
### Reward Handling
|
||||
`fnc_handleTaskRewards.sqf` applies org-owned rewards:
|
||||
- `funds` -> org funds
|
||||
- `equipment`, `supplies`, `weapons`, `special` -> org assets
|
||||
- `vehicles` -> org fleet
|
||||
|
||||
Player `earnings` and org `reputation` from task outcomes are distributed separately through `TaskStore.applyRatingOutcome` using Arma engine `rating` deltas.
|
||||
|
||||
## Task Ownership
|
||||
Tasks are bound to an owner org when they are started through `fnc_handler.sqf`.
|
||||
|
||||
- if a requester UID is provided, the task is owned by that requester's org
|
||||
- if no requester UID is available, the task is bound to the `default` org
|
||||
|
||||
Org rewards always go to the bound owner org. Player earnings still use per-player contribution.
|
||||
|
||||
## Usage
|
||||
|
||||
### Start Through The Handler
|
||||
Use the handler when you want reputation gating and task ownership binding.
|
||||
|
||||
```sqf
|
||||
["attack", ["task_attack_1", 1, 2, 1500000, -75, 375, false, false], 250, getPlayerUID player] call forge_server_task_fnc_handler;
|
||||
["delivery", ["task_delivery_1", 1, 3, "delivery_zone", 250000, -75, 300, false, false, 900], 0, getPlayerUID player] call forge_server_task_fnc_handler;
|
||||
```
|
||||
|
||||
Arguments:
|
||||
- `0`: task type
|
||||
- `1`: task-specific argument array
|
||||
- `2`: minimum org reputation required to start the task
|
||||
- `3`: requester UID used for ownership binding
|
||||
|
||||
### Start Task Functions Directly
|
||||
Direct task calls still work, but they do not provide a requester UID. That means task ownership falls back to the `default` org.
|
||||
|
||||
Use direct starts only when that behavior is intended, such as:
|
||||
- mission-authored tasks
|
||||
- editor-placed tasks
|
||||
- server-owned/random tasks
|
||||
|
||||
If you want the accepting player's org to own the task rewards, use `fnc_handler.sqf` instead.
|
||||
|
||||
```sqf
|
||||
["task_attack_1", 1, 2, 1500000, -75, 375, false, false] spawn forge_server_task_fnc_attack;
|
||||
["task_hostage_1", 1, 2, "extract_marker", 1500000, -75, 500, [false, true], false, false] spawn forge_server_task_fnc_hostage;
|
||||
```
|
||||
|
||||
## Event Hooks
|
||||
- `XEH_preInit.sqf`
|
||||
- compiles functions
|
||||
- initializes `TaskStore`
|
||||
- `XEH_postInit.sqf`
|
||||
- registers the ACE defuse event hook
|
||||
- starts the attack-only mission manager on the server
|
||||
|
||||
## Notes
|
||||
- the dynamic mission manager in `fnc_missionManager.sqf` is now limited to attack missions only
|
||||
- it starts server-owned tasks through `fnc_handler.sqf` and binds them to the `default` org
|
||||
- task lifecycle for the mission manager is tracked through `TaskStore` status entries
|
||||
- task rewards are org-owned, not player-owned
|
||||
- participant notifications are sent through the notifications module, not through local server UI
|
||||
|
||||
## Authors
|
||||
- J. Schmidt
|
||||
- Creedcoder
|
||||
- IDSolutions
|
||||
31
arma/server/addons/task/XEH_PREP.hpp
Normal file
31
arma/server/addons/task/XEH_PREP.hpp
Normal file
@ -0,0 +1,31 @@
|
||||
PREP(attack);
|
||||
PREP(attackModule);
|
||||
PREP(defend);
|
||||
PREP(defendModule);
|
||||
PREP(defuse);
|
||||
PREP(defuseModule);
|
||||
PREP(delivery);
|
||||
PREP(deliveryModule);
|
||||
PREP(destroy);
|
||||
PREP(destroyModule);
|
||||
PREP(explosivesModule);
|
||||
PREP(handler);
|
||||
PREP(handleTaskRewards);
|
||||
PREP(heartBeat);
|
||||
PREP(hostage);
|
||||
PREP(hostageModule);
|
||||
PREP(hostagesModule);
|
||||
PREP(hvt);
|
||||
PREP(hvtModule);
|
||||
PREP(makeCargo);
|
||||
PREP(makeHostage);
|
||||
PREP(makeHVT);
|
||||
PREP(makeIED);
|
||||
PREP(makeObject);
|
||||
PREP(makeShooter);
|
||||
PREP(makeTarget);
|
||||
PREP(missionManager);
|
||||
PREP(initTaskStore);
|
||||
PREP(protectedModule);
|
||||
PREP(shootersModule);
|
||||
PREP(spawnEnemyWave);
|
||||
16
arma/server/addons/task/XEH_postInit.sqf
Normal file
16
arma/server/addons/task/XEH_postInit.sqf
Normal file
@ -0,0 +1,16 @@
|
||||
#include "script_component.hpp"
|
||||
|
||||
if (isServer) then { [] call FUNC(missionManager); };
|
||||
|
||||
["ace_explosives_defuse", {
|
||||
private _taskID = "";
|
||||
{
|
||||
if (_x isEqualType objNull && { !isNull _x }) then {
|
||||
_taskID = _x getVariable ["assignedTask", ""];
|
||||
if (_taskID isNotEqualTo "") exitWith {};
|
||||
};
|
||||
} forEach _this;
|
||||
|
||||
if (_taskID isEqualTo "") exitWith {};
|
||||
GVAR(TaskStore) call ["incrementDefuseCount", [_taskID]];
|
||||
}] call CFUNC(addEventHandler);
|
||||
35
arma/server/addons/task/XEH_preInit.sqf
Normal file
35
arma/server/addons/task/XEH_preInit.sqf
Normal file
@ -0,0 +1,35 @@
|
||||
#include "script_component.hpp"
|
||||
|
||||
PREP_RECOMPILE_START;
|
||||
#include "XEH_PREP.hpp"
|
||||
PREP_RECOMPILE_END;
|
||||
|
||||
call FUNC(initTaskStore);
|
||||
|
||||
[QGVAR(requestTaskCatalog), {
|
||||
params [["_uid", "", [""]]];
|
||||
|
||||
if (_uid isEqualTo "") exitWith {
|
||||
["WARNING", "Task catalog request received with empty UID."] call EFUNC(common,log);
|
||||
};
|
||||
|
||||
private _player = [_uid] call EFUNC(common,getPlayer);
|
||||
if (_player isEqualTo objNull) exitWith {};
|
||||
|
||||
[CRPC(cad,responseTaskCatalog), [GVAR(TaskStore) call ["getActiveTaskCatalog", []]], _player] call CFUNC(targetEvent);
|
||||
}] call CFUNC(addEventHandler);
|
||||
|
||||
[QGVAR(requestAcceptTask), {
|
||||
params [["_uid", "", [""]], ["_taskID", "", [""]]];
|
||||
|
||||
if (_uid isEqualTo "" || { _taskID isEqualTo "" }) exitWith {
|
||||
["WARNING", "Invalid task accept request payload."] call EFUNC(common,log);
|
||||
};
|
||||
|
||||
private _player = [_uid] call EFUNC(common,getPlayer);
|
||||
if (_player isEqualTo objNull) exitWith {};
|
||||
|
||||
private _result = GVAR(TaskStore) call ["acceptTask", [_taskID, _uid]];
|
||||
[CRPC(cad,responseTaskAccept), [_result], _player] call CFUNC(targetEvent);
|
||||
[CRPC(cad,responseTaskCatalog), [GVAR(TaskStore) call ["getActiveTaskCatalog", []]], _player] call CFUNC(targetEvent);
|
||||
}] call CFUNC(addEventHandler);
|
||||
2
arma/server/addons/task/XEH_preStart.sqf
Normal file
2
arma/server/addons/task/XEH_preStart.sqf
Normal file
@ -0,0 +1,2 @@
|
||||
#include "script_component.hpp"
|
||||
#include "XEH_PREP.hpp"
|
||||
23
arma/server/addons/task/config.cpp
Normal file
23
arma/server/addons/task/config.cpp
Normal file
@ -0,0 +1,23 @@
|
||||
#include "script_component.hpp"
|
||||
|
||||
class CfgPatches {
|
||||
class ADDON {
|
||||
author = AUTHOR;
|
||||
authors[] = {"J.Schmidt"};
|
||||
url = ECSTRING(main,url);
|
||||
name = COMPONENT_NAME;
|
||||
requiredVersion = REQUIRED_VERSION;
|
||||
requiredAddons[] = {
|
||||
"forge_server_main",
|
||||
"forge_server_common"
|
||||
};
|
||||
units[] = {};
|
||||
weapons[] = {};
|
||||
VERSION_CONFIG;
|
||||
};
|
||||
};
|
||||
|
||||
#include "CfgEventHandlers.hpp"
|
||||
#include "CfgFactionClasses.hpp"
|
||||
#include "CfgVehicles.hpp"
|
||||
#include "CfgMissions.hpp"
|
||||
116
arma/server/addons/task/functions/fnc_attack.sqf
Normal file
116
arma/server/addons/task/functions/fnc_attack.sqf
Normal file
@ -0,0 +1,116 @@
|
||||
#include "..\script_component.hpp"
|
||||
|
||||
/*
|
||||
* Author: IDSolutions
|
||||
* Registers an attack task
|
||||
*
|
||||
* Arguments:
|
||||
* 0: ID of the task <STRING>
|
||||
* 1: Amount of targets escaped to fail the task <NUMBER>
|
||||
* 2: Amount of targets eliminated to complete the task <NUMBER>
|
||||
* 3: Amount of funds the company recieves if the task is successful <NUMBER> (default: 0)
|
||||
* 4: Amount of rating the company and player lose if the task is failed <NUMBER> (default: 0)
|
||||
* 5: Amount of rating the company and player recieve if the task is successful <NUMBER> (default: 0)
|
||||
* 6: Should the mission end (MissionSuccess) if the task is successful <BOOL> (default: false)
|
||||
* 7: Should the mission end (MissionFailed) if the task is failed <BOOL> (default: false)
|
||||
* 8: Amount of time before target(s) escape <NUMBER> (default: -1)
|
||||
* 9: Equipment rewards <ARRAY> (default: [])
|
||||
* 10: Supply rewards <ARRAY> (default: [])
|
||||
* 11: Weapon rewards <ARRAY> (default: [])
|
||||
* 12: Vehicle rewards <ARRAY> (default: [])
|
||||
* 13: Special rewards <ARRAY> (default: [])
|
||||
*
|
||||
* Return Value:
|
||||
* None
|
||||
*
|
||||
* Example:
|
||||
* ["task_name", 1, 2, 1500000, -75, 375, false, false] spawn forge_server_task_fnc_attack;
|
||||
* ["task_name", 1, 2, 1500000, -75, 375, false, false, 45] spawn forge_server_task_fnc_attack;
|
||||
*
|
||||
* Public: Yes
|
||||
*/
|
||||
|
||||
params [
|
||||
["_taskID", "", [""]],
|
||||
["_limitFail", -1, [0]],
|
||||
["_limitSuccess", -1, [0]],
|
||||
["_companyFunds", 0, [0]],
|
||||
["_ratingFail", 0, [0]],
|
||||
["_ratingSuccess", 0, [0]],
|
||||
["_endSuccess", false, [false]],
|
||||
["_endFail", false, [false]],
|
||||
["_time", -1, [0]],
|
||||
["_equipmentRewards", [], [[]]],
|
||||
["_supplyRewards", [], [[]]],
|
||||
["_weaponRewards", [], [[]]],
|
||||
["_vehicleRewards", [], [[]]],
|
||||
["_specialRewards", [], [[]]]
|
||||
];
|
||||
|
||||
private _result = 0;
|
||||
private _targets = [];
|
||||
|
||||
waitUntil {
|
||||
sleep 1;
|
||||
_targets = GVAR(TaskStore) call ["getTaskEntities", ["targets", _taskID]];
|
||||
GVAR(TaskStore) call ["trackParticipants", [_taskID, _targets, "", 300]];
|
||||
count _targets > 0
|
||||
};
|
||||
|
||||
_targets = GVAR(TaskStore) call ["getTaskEntities", ["targets", _taskID]];
|
||||
private _startTime = if (!isNil "_time") then { floor(time) } else { nil };
|
||||
|
||||
waitUntil {
|
||||
sleep 1;
|
||||
GVAR(TaskStore) call ["trackParticipants", [_taskID, _targets, "", 300]];
|
||||
|
||||
private _targetsKilled = ({ !alive _x } count _targets);
|
||||
|
||||
if (_time isNotEqualTo -1) then {
|
||||
private _timeExpired = (floor time - _startTime >= _time);
|
||||
|
||||
if (_targetsKilled < _limitSuccess && _timeExpired) then { _result = 1; };
|
||||
|
||||
(_result == 1) or (_targetsKilled >= _limitSuccess)
|
||||
} else {
|
||||
(_targetsKilled >= _limitSuccess)
|
||||
};
|
||||
};
|
||||
|
||||
if (_result == 1) then {
|
||||
{ deleteVehicle _x } forEach _targets;
|
||||
|
||||
[_taskID, "FAILED"] call BFUNC(taskSetState);
|
||||
GVAR(TaskStore) call ["setTaskStatus", [_taskID, "failed"]];
|
||||
|
||||
sleep 1;
|
||||
|
||||
GVAR(TaskStore) call ["notifyParticipants", [_taskID, "warning", "Tasks", format ["Task failed: %1 reputation", _ratingFail]]];
|
||||
GVAR(TaskStore) call ["applyRatingOutcome", [_taskID, _ratingFail]];
|
||||
GVAR(TaskStore) call ["clearTask", [_taskID]];
|
||||
|
||||
if (_endFail) then { ["MissionFail", false] remoteExecCall ["BIS_fnc_endMission", playerSide]; };
|
||||
} else {
|
||||
{ deleteVehicle _x } forEach _targets;
|
||||
|
||||
private _rewards = createHashMap;
|
||||
_rewards set ["funds", _companyFunds];
|
||||
|
||||
if (_equipmentRewards isNotEqualTo []) then { _rewards set ["equipment", _equipmentRewards]; };
|
||||
if (_supplyRewards isNotEqualTo []) then { _rewards set ["supplies", _supplyRewards]; };
|
||||
if (_weaponRewards isNotEqualTo []) then { _rewards set ["weapons", _weaponRewards]; };
|
||||
if (_vehicleRewards isNotEqualTo []) then { _rewards set ["vehicles", _vehicleRewards]; };
|
||||
if (_specialRewards isNotEqualTo []) then { _rewards set ["special", _specialRewards]; };
|
||||
|
||||
[_taskID, _rewards] call FUNC(handleTaskRewards);
|
||||
[_taskID, "SUCCEEDED"] call BFUNC(taskSetState);
|
||||
GVAR(TaskStore) call ["setTaskStatus", [_taskID, "succeeded"]];
|
||||
|
||||
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 ["applyRatingOutcome", [_taskID, _ratingSuccess]];
|
||||
GVAR(TaskStore) call ["clearTask", [_taskID]];
|
||||
|
||||
if (_endSuccess) then { ["MissionSuccess", true] remoteExecCall ["BIS_fnc_endMission", playerSide]; };
|
||||
};
|
||||
51
arma/server/addons/task/functions/fnc_attackModule.sqf
Normal file
51
arma/server/addons/task/functions/fnc_attackModule.sqf
Normal file
@ -0,0 +1,51 @@
|
||||
#include "..\script_component.hpp"
|
||||
|
||||
/*
|
||||
* Author: IDSolutions
|
||||
* Initializes the attack module
|
||||
*
|
||||
* Arguments:
|
||||
* 0: Logic <OBJECT> - The logic object
|
||||
* 1: Units <ARRAY> - The array of units
|
||||
* 2: Activated <BOOL> - Whether the module is activated
|
||||
*
|
||||
* Return Value:
|
||||
* None
|
||||
*
|
||||
* Example:
|
||||
* [logicObject, [unit1, unit2], true] call forge_server_task_fnc_attackModule;
|
||||
*
|
||||
* Public: No
|
||||
*/
|
||||
|
||||
params [["_logic", objNull, [objNull]], ["_units", [], [[]]], ["_activated", true, [true]]];
|
||||
|
||||
if !(_activated) exitWith {};
|
||||
|
||||
private _taskID = _logic getVariable ["TaskID", ""];
|
||||
private _limitFail = _logic getVariable ["LimitFail", -1];
|
||||
private _limitSuccess = _logic getVariable ["LimitSuccess", -1];
|
||||
private _companyFunds = _logic getVariable ["CompanyFunds", 0];
|
||||
private _ratingFail = _logic getVariable ["RatingFail", 0];
|
||||
private _ratingSuccess = _logic getVariable ["RatingSuccess", 0];
|
||||
private _endSuccess = _logic getVariable ["EndSuccess", false];
|
||||
private _endFail = _logic getVariable ["EndFail", false];
|
||||
private _timeLimit = _logic getVariable ["TimeLimit", 0];
|
||||
|
||||
["INFO", format ["Attack Module Parameters: TaskID: %1, LimitFail: %2, LimitSuccess: %3, Funds: %4, RatingFail: %5, RatingSuccess: %6, EndSuccess: %7, EndFail: %8, Time: %9", _taskID, _limitFail, _limitSuccess, _companyFunds, _ratingFail, _ratingSuccess, _endSuccess, _endFail, _timeLimit]] call EFUNC(common,log);
|
||||
|
||||
private _syncedEntities = synchronizedObjects _logic;
|
||||
["INFO", format ["Attack Module Synced Entities: %1", _syncedEntities]] call EFUNC(common,log);
|
||||
|
||||
{
|
||||
[_x, _taskID] spawn FUNC(makeTarget);
|
||||
} forEach _syncedEntities;
|
||||
|
||||
private _params = [_taskID, _limitFail, _limitSuccess, _companyFunds, _ratingFail, _ratingSuccess, _endSuccess, _endFail];
|
||||
if (_timeLimit != 0) then {
|
||||
_params pushBack _timeLimit;
|
||||
};
|
||||
|
||||
["attack", _params, 0, ""] spawn FUNC(handler);
|
||||
|
||||
deleteVehicle _logic;
|
||||
126
arma/server/addons/task/functions/fnc_defend.sqf
Normal file
126
arma/server/addons/task/functions/fnc_defend.sqf
Normal file
@ -0,0 +1,126 @@
|
||||
#include "..\script_component.hpp"
|
||||
|
||||
/*
|
||||
* Author: IDSolutions
|
||||
* Registers a defend task where players must hold a zone marked by a marker
|
||||
*
|
||||
* Arguments:
|
||||
* 0: ID of the task <STRING>
|
||||
* 1: Defense zone marker name <STRING>
|
||||
* 2: Time to defend in seconds <NUMBER>
|
||||
* 3: Amount of funds the company receives if the task is successful <NUMBER> (default: 0)
|
||||
* 4: Amount of rating the company and player lose if the task is failed <NUMBER> (default: 0)
|
||||
* 5: Amount of rating the company and player receive if the task is successful <NUMBER> (default: 0)
|
||||
* 6: Should the mission end (MissionSuccess) if the task is successful <BOOL> (default: false)
|
||||
* 7: Should the mission end (MissionFailed) if the task is failed <BOOL> (default: false)
|
||||
* 8: Enemy wave count <NUMBER> (default: 3)
|
||||
* 9: Time between waves in seconds <NUMBER> (default: 300)
|
||||
* 10: Minimum BLUFOR units required in zone <NUMBER> (default: 1)
|
||||
* 11: Equipment rewards <ARRAY> (default: [])
|
||||
* 12: Supply rewards <ARRAY> (default: [])
|
||||
* 13: Weapon rewards <ARRAY> (default: [])
|
||||
* 14: Vehicle rewards <ARRAY> (default: [])
|
||||
* 15: Special rewards <ARRAY> (default: [])
|
||||
*
|
||||
* Return Value:
|
||||
* None
|
||||
*
|
||||
* Example:
|
||||
* ["defend_zone_1", "defend_marker", 900, 500000, -100, 400, false, false, 3, 300, 1, ["ItemGPS"], ["FirstAidKit"], ["arifle_MX_F"], ["B_MRAP_01_F"], ["B_UAV_01_F"]] spawn forge_server_task_fnc_defend;
|
||||
*
|
||||
* Public: Yes
|
||||
*/
|
||||
|
||||
params [
|
||||
["_taskID", "", [""]],
|
||||
["_defenseZone", "", [""]],
|
||||
["_defendTime", 600, [0]],
|
||||
["_companyFunds", 0, [0]],
|
||||
["_ratingFail", 0, [0]],
|
||||
["_ratingSuccess", 0, [0]],
|
||||
["_endSuccess", false, [false]],
|
||||
["_endFail", false, [false]],
|
||||
["_waveCount", 3, [0]],
|
||||
["_waveCooldown", 300, [0]],
|
||||
["_minBlufor", 1, [0]],
|
||||
["_equipmentRewards", [], [[]]],
|
||||
["_supplyRewards", [], [[]]],
|
||||
["_weaponRewards", [], [[]]],
|
||||
["_vehicleRewards", [], [[]]],
|
||||
["_specialRewards", [], [[]]]
|
||||
];
|
||||
|
||||
if (_defenseZone == "" || !(markerShape _defenseZone in ["RECTANGLE", "ELLIPSE"])) exitWith {
|
||||
["ERROR", format ["Invalid defense zone marker: %1", _defenseZone]] call EFUNC(common,log);
|
||||
};
|
||||
|
||||
private _result = 0;
|
||||
private _startTime = time;
|
||||
private _nextWaveTime = _startTime;
|
||||
private _currentWave = 0;
|
||||
private _zoneEmptyCounter = 0;
|
||||
private _warningIssued = false;
|
||||
|
||||
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 _timeElapsed = time - _startTime;
|
||||
|
||||
if (_bluforInZone < _minBlufor) then {
|
||||
_zoneEmptyCounter = _zoneEmptyCounter + 1;
|
||||
|
||||
if (_zoneEmptyCounter == 15 && !_warningIssued) then {
|
||||
GVAR(TaskStore) call ["notifyParticipants", [_taskID, "warning", "Tasks", "Defense zone is empty. Return immediately."]];
|
||||
_warningIssued = true;
|
||||
};
|
||||
} else {
|
||||
_zoneEmptyCounter = 0;
|
||||
_warningIssued = false;
|
||||
};
|
||||
|
||||
if (_currentWave < _waveCount && time >= _nextWaveTime) then {
|
||||
[_defenseZone, _taskID, _currentWave] call FUNC(spawnEnemyWave);
|
||||
|
||||
_currentWave = _currentWave + 1;
|
||||
_nextWaveTime = time + _waveCooldown;
|
||||
|
||||
GVAR(TaskStore) call ["notifyParticipants", [_taskID, "info", "Tasks", format ["Enemy forces approaching. Wave %1 of %2.", _currentWave, _waveCount]]];
|
||||
};
|
||||
|
||||
if (_zoneEmptyCounter >= 30) then { _result = 1; };
|
||||
|
||||
(_result == 1) or ((_bluforInZone >= _minBlufor) && (_timeElapsed >= _defendTime) && (_currentWave >= _waveCount));
|
||||
};
|
||||
|
||||
if (_result == 1) then {
|
||||
[_taskID, "FAILED"] call BFUNC(taskSetState);
|
||||
|
||||
sleep 1;
|
||||
|
||||
GVAR(TaskStore) call ["notifyParticipants", [_taskID, "warning", "Tasks", format ["Task failed: %1 reputation", _ratingFail]]];
|
||||
GVAR(TaskStore) call ["applyRatingOutcome", [_taskID, _ratingFail]];
|
||||
GVAR(TaskStore) call ["clearTask", [_taskID]];
|
||||
|
||||
if (_endFail) then { ["MissionFail", false] remoteExecCall ["BIS_fnc_endMission", playerSide]; };
|
||||
} else {
|
||||
private _rewards = createHashMap;
|
||||
_rewards set ["funds", _companyFunds];
|
||||
|
||||
if (_equipmentRewards isNotEqualTo []) then { _rewards set ["equipment", _equipmentRewards]; };
|
||||
if (_supplyRewards isNotEqualTo []) then { _rewards set ["supplies", _supplyRewards]; };
|
||||
if (_weaponRewards isNotEqualTo []) then { _rewards set ["weapons", _weaponRewards]; };
|
||||
if (_vehicleRewards isNotEqualTo []) then { _rewards set ["vehicles", _vehicleRewards]; };
|
||||
if (_specialRewards isNotEqualTo []) then { _rewards set ["special", _specialRewards]; };
|
||||
|
||||
[_taskID, _rewards] call FUNC(handleTaskRewards);
|
||||
[_taskID, "SUCCEEDED"] call BFUNC(taskSetState);
|
||||
|
||||
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 ["applyRatingOutcome", [_taskID, _ratingSuccess]];
|
||||
GVAR(TaskStore) call ["clearTask", [_taskID]];
|
||||
|
||||
if (_endSuccess) then { ["MissionSuccess", true] remoteExecCall ["BIS_fnc_endMission", playerSide]; };
|
||||
};
|
||||
61
arma/server/addons/task/functions/fnc_defendModule.sqf
Normal file
61
arma/server/addons/task/functions/fnc_defendModule.sqf
Normal file
@ -0,0 +1,61 @@
|
||||
#include "..\script_component.hpp"
|
||||
|
||||
/*
|
||||
* Author: IDSolutions
|
||||
* Creates a defend task module
|
||||
*
|
||||
* Arguments:
|
||||
* None
|
||||
*
|
||||
* Return Value:
|
||||
* None
|
||||
*
|
||||
* Example:
|
||||
* call forge_server_task_fnc_defendModule;
|
||||
*
|
||||
* Public: No
|
||||
*/
|
||||
|
||||
// Module category
|
||||
private _category = "Forge Tasks";
|
||||
private _subCategory = "Defense Tasks";
|
||||
|
||||
// Create the module
|
||||
private _module = createDialog "RscDisplayAttributes";
|
||||
_module setVariable ["category", _category];
|
||||
_module setVariable ["subcategory", _subCategory];
|
||||
_module setVariable ["description", "Configure a defend task"];
|
||||
|
||||
// Add fields for task configuration
|
||||
[_module, "Task ID", "taskID", "", true] call BIS_fnc_addAttribute;
|
||||
[_module, "Defense Zone Marker", "defenseZone", "", true] call BIS_fnc_addAttribute;
|
||||
[_module, "Defense Time (seconds)", "defendTime", "600", true] call BIS_fnc_addAttribute;
|
||||
[_module, "Min BLUFOR in Zone", "minBlufor", "1", true] call BIS_fnc_addAttribute;
|
||||
[_module, "Company Funds Reward", "companyFunds", "500000", true] call BIS_fnc_addAttribute;
|
||||
[_module, "Rating Loss on Fail", "ratingFail", "-100", true] call BIS_fnc_addAttribute;
|
||||
[_module, "Rating Gain on Success", "ratingSuccess", "400", 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, "Enemy Wave Count", "waveCount", "3", false] call BIS_fnc_addAttribute;
|
||||
[_module, "Time Between Waves (seconds)", "waveCooldown", "300", false] call BIS_fnc_addAttribute;
|
||||
|
||||
// Add confirm button handler
|
||||
_module setVariable ["onConfirm", {
|
||||
params ["_module"];
|
||||
private _taskID = _module getVariable ["taskID", ""];
|
||||
private _defenseZone = _module getVariable ["defenseZone", ""];
|
||||
private _defendTime = parseNumber (_module getVariable ["defendTime", "600"]);
|
||||
private _companyFunds = parseNumber (_module getVariable ["companyFunds", "500000"]);
|
||||
private _ratingFail = parseNumber (_module getVariable ["ratingFail", "-100"]);
|
||||
private _ratingSuccess = parseNumber (_module getVariable ["ratingSuccess", "400"]);
|
||||
private _endSuccess = _module getVariable ["endSuccess", "false"] == "true";
|
||||
private _endFail = _module getVariable ["endFail", "false"] == "true";
|
||||
private _waveCount = parseNumber (_module getVariable ["waveCount", "3"]);
|
||||
private _waveCooldown = parseNumber (_module getVariable ["waveCooldown", "300"]);
|
||||
private _minBlufor = parseNumber (_module getVariable ["minBlufor", "1"]);
|
||||
|
||||
// Create the task
|
||||
private _params = [_taskID, _defenseZone, _defendTime, _companyFunds, _ratingFail, _ratingSuccess, _endSuccess, _endFail, _waveCount, _waveCooldown, _minBlufor];
|
||||
private _requesterUid = ["", getPlayerUID player] select hasInterface;
|
||||
["defend", _params, 0, _requesterUid] spawn FUNC(handler);
|
||||
}];
|
||||
114
arma/server/addons/task/functions/fnc_defuse.sqf
Normal file
114
arma/server/addons/task/functions/fnc_defuse.sqf
Normal file
@ -0,0 +1,114 @@
|
||||
#include "..\script_component.hpp"
|
||||
|
||||
/*
|
||||
* Author: IDSolutions
|
||||
* Registers a defuse task
|
||||
*
|
||||
* Arguments:
|
||||
* 0: ID of the task <STRING>
|
||||
* 1: Amount of entities destroyed to fail the task <NUMBER>
|
||||
* 2: Amount of ieds defused to complete the task <NUMBER>
|
||||
* 3: Amount of funds the company recieves if the task is successful <NUMBER> (default: 0)
|
||||
* 4: Amount of rating the company and player lose if the task is failed <NUMBER> (default: 0)
|
||||
* 5: Amount of rating the company and player recieve if the task is successful <NUMBER> (default: 0)
|
||||
* 6: Should the mission end (MissionSuccess) if the task is successful <BOOL> (default: false)
|
||||
* 7: Should the mission end (MissionFailed) if the task is failed <BOOL> (default: false)
|
||||
* 8: Equipment rewards <ARRAY> (default: [])
|
||||
* 9: Supply rewards <ARRAY> (default: [])
|
||||
* 10: Weapon rewards <ARRAY> (default: [])
|
||||
* 11: Vehicle rewards <ARRAY> (default: [])
|
||||
* 12: Special rewards <ARRAY> (default: [])
|
||||
*
|
||||
* Return Value:
|
||||
* None
|
||||
*
|
||||
* Example:
|
||||
* ["task_name", 2, 3, 375000, -75, 300, false, false] spawn forge_server_task_fnc_defuse;
|
||||
*
|
||||
* Public: Yes
|
||||
*/
|
||||
|
||||
params [
|
||||
["_taskID", "", [""]],
|
||||
["_limitFail", -1, [0]],
|
||||
["_limitSuccess", -1, [0]],
|
||||
["_companyFunds", 0, [0]],
|
||||
["_ratingFail", 0, [0]],
|
||||
["_ratingSuccess", 0, [0]],
|
||||
["_endSuccess", false, [false]],
|
||||
["_endFail", false, [false]],
|
||||
["_equipmentRewards", [], [[]]],
|
||||
["_supplyRewards", [], [[]]],
|
||||
["_weaponRewards", [], [[]]],
|
||||
["_vehicleRewards", [], [[]]],
|
||||
["_specialRewards", [], [[]]]
|
||||
];
|
||||
|
||||
private _result = 0;
|
||||
private _ieds = [];
|
||||
private _entities = [];
|
||||
|
||||
waitUntil {
|
||||
sleep 1;
|
||||
_ieds = GVAR(TaskStore) call ["getTaskEntities", ["ieds", _taskID]];
|
||||
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]];
|
||||
_entities = GVAR(TaskStore) call ["getTaskEntities", ["entities", _taskID]];
|
||||
|
||||
waitUntil {
|
||||
sleep 1;
|
||||
GVAR(TaskStore) call ["trackParticipants", [_taskID, _ieds + _entities, "", 250]];
|
||||
|
||||
private _entitiesDestroyed = ({ !alive _x } count _entities);
|
||||
|
||||
if (_entitiesDestroyed >= _limitFail) then { _result = 1; };
|
||||
|
||||
(_result == 1) or ((GVAR(TaskStore) call ["getDefuseCount", [_taskID]]) >= _limitSuccess && (_entitiesDestroyed < _limitFail))
|
||||
};
|
||||
|
||||
if (_result == 1) then {
|
||||
{ deleteVehicle _x } forEach _ieds;
|
||||
{ deleteVehicle _x } forEach _entities;
|
||||
|
||||
[_taskID, "FAILED"] call BFUNC(taskSetState);
|
||||
|
||||
sleep 1;
|
||||
|
||||
GVAR(TaskStore) call ["notifyParticipants", [_taskID, "warning", "Tasks", format ["Task failed: %1 reputation", _ratingFail]]];
|
||||
GVAR(TaskStore) call ["applyRatingOutcome", [_taskID, _ratingFail]];
|
||||
|
||||
if (_endFail) then { ["MissionFail", false] remoteExecCall ["BIS_fnc_endMission", playerSide]; };
|
||||
} else {
|
||||
{ deleteVehicle _x } forEach _ieds;
|
||||
{ deleteVehicle _x } forEach _entities;
|
||||
|
||||
private _rewards = createHashMap;
|
||||
_rewards set ["funds", _companyFunds];
|
||||
|
||||
if (_equipmentRewards isNotEqualTo []) then { _rewards set ["equipment", _equipmentRewards]; };
|
||||
if (_supplyRewards isNotEqualTo []) then { _rewards set ["supplies", _supplyRewards]; };
|
||||
if (_weaponRewards isNotEqualTo []) then { _rewards set ["weapons", _weaponRewards]; };
|
||||
if (_vehicleRewards isNotEqualTo []) then { _rewards set ["vehicles", _vehicleRewards]; };
|
||||
if (_specialRewards isNotEqualTo []) then { _rewards set ["special", _specialRewards]; };
|
||||
|
||||
[_taskID, _rewards] call FUNC(handleTaskRewards);
|
||||
[_taskID, "SUCCEEDED"] call BFUNC(taskSetState);
|
||||
|
||||
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 ["applyRatingOutcome", [_taskID, _ratingSuccess]];
|
||||
|
||||
if (_endSuccess) then { ["MissionSuccess", true] remoteExecCall ["BIS_fnc_endMission", playerSide]; };
|
||||
};
|
||||
|
||||
GVAR(TaskStore) call ["clearTask", [_taskID]];
|
||||
64
arma/server/addons/task/functions/fnc_defuseModule.sqf
Normal file
64
arma/server/addons/task/functions/fnc_defuseModule.sqf
Normal file
@ -0,0 +1,64 @@
|
||||
#include "..\script_component.hpp"
|
||||
|
||||
/*
|
||||
* Author: IDSolutions
|
||||
* Initializes the defuse module
|
||||
*
|
||||
* Arguments:
|
||||
* 0: Logic <OBJECT> - The logic object
|
||||
* 1: Units <ARRAY> - The array of units
|
||||
* 2: Activated <BOOL> - Whether the module is activated
|
||||
*
|
||||
* Return Value:
|
||||
* None
|
||||
*
|
||||
* Example:
|
||||
* [logicObject, [unit1, unit2], true] call forge_server_task_fnc_defuseModule;
|
||||
*
|
||||
* Public: No
|
||||
*/
|
||||
|
||||
params [["_logic", objNull, [objNull]], ["_units", [], [[]]], ["_activated", true, [true]]];
|
||||
|
||||
if !(_activated) exitWith {};
|
||||
|
||||
private _taskID = _logic getVariable ["TaskID", ""];
|
||||
private _limitFail = _logic getVariable ["LimitFail", -1];
|
||||
private _limitSuccess = _logic getVariable ["LimitSuccess", -1];
|
||||
private _companyFunds = _logic getVariable ["CompanyFunds", 0];
|
||||
private _ratingFail = _logic getVariable ["RatingFail", 0];
|
||||
private _ratingSuccess = _logic getVariable ["RatingSuccess", 0];
|
||||
private _endSuccess = _logic getVariable ["EndSuccess", false];
|
||||
private _endFail = _logic getVariable ["EndFail", false];
|
||||
private _timeLimit = _logic getVariable ["TimeLimit", 0];
|
||||
|
||||
["INFO", format ["Defuse Module Parameters: TaskID: %1, LimitFail: %2, LimitSuccess: %3, Funds: %4, RatingFail: %5, RatingSuccess: %6, EndSuccess: %7, EndFail: %8, Time: %9", _taskID, _limitFail, _limitSuccess, _companyFunds, _ratingFail, _ratingSuccess, _endSuccess, _endFail, _timeLimit]] call EFUNC(common,log);
|
||||
|
||||
private _syncedModules = synchronizedObjects _logic;
|
||||
["INFO", format ["Defuse Module Synced Modules: %1", _syncedModules]] call EFUNC(common,log);
|
||||
|
||||
private _iedModule = (_syncedModules select { typeOf _x == "FORGE_Module_Explosives" }) select 0;
|
||||
private _protectedModule = (_syncedModules select { typeOf _x == "FORGE_Module_Protected" }) select 0;
|
||||
|
||||
private _explosiveEntities = synchronizedObjects _iedModule;
|
||||
["INFO", format ["Defuse Module Explosive Entites: %1", _explosiveEntities]] call EFUNC(common,log);
|
||||
|
||||
private _protectedEntities = synchronizedObjects _protectedModule;
|
||||
["INFO", format ["Defuse Module Protected Entities: %1", _protectedEntities]] call EFUNC(common,log);
|
||||
|
||||
{
|
||||
if (!isNull _x) then {
|
||||
[_x, _taskID, _timeLimit] spawn FUNC(makeIED);
|
||||
};
|
||||
} forEach _explosiveEntities;
|
||||
|
||||
{
|
||||
if (!isNull _x) then {
|
||||
[_x, _taskID] spawn FUNC(makeObject);
|
||||
};
|
||||
} forEach _protectedEntities;
|
||||
|
||||
private _params = [_taskID, _limitFail, _limitSuccess, _companyFunds, _ratingFail, _ratingSuccess, _endSuccess, _endFail];
|
||||
["defuse", _params, 0, ""] spawn FUNC(handler);
|
||||
|
||||
deleteVehicle _logic;
|
||||
120
arma/server/addons/task/functions/fnc_delivery.sqf
Normal file
120
arma/server/addons/task/functions/fnc_delivery.sqf
Normal file
@ -0,0 +1,120 @@
|
||||
#include "..\script_component.hpp"
|
||||
|
||||
/*
|
||||
* Author: IDSolutions
|
||||
* Registers a delivery task
|
||||
*
|
||||
* Arguments:
|
||||
* 0: ID of the task <STRING>
|
||||
* 1: Amount of damaged cargo to fail the task <NUMBER>
|
||||
* 2: Amount of cargo delivered to complete the task <NUMBER>
|
||||
* 3: Marker name for the delivery zone <STRING>
|
||||
* 4: Amount of funds the company receives if the task is successful <NUMBER> (default: 0)
|
||||
* 5: Amount of rating the company and player lose if the task is failed <NUMBER> (default: 0)
|
||||
* 6: Amount of rating the company and player receive if the task is successful <NUMBER> (default: 0)
|
||||
* 7: Should the mission end (MissionSuccess) if the task is successful <BOOL> (default: false)
|
||||
* 8: Should the mission end (MissionFailed) if the task is failed <BOOL> (default: false)
|
||||
* 9: Amount of time to complete delivery <NUMBER> (default: -1)
|
||||
* 10: Equipment rewards <ARRAY> (default: [])
|
||||
* 11: Supply rewards <ARRAY> (default: [])
|
||||
* 12: Weapon rewards <ARRAY> (default: [])
|
||||
* 13: Vehicle rewards <ARRAY> (default: [])
|
||||
* 14: Special rewards <ARRAY> (default: [])
|
||||
*
|
||||
* Return Value:
|
||||
* None
|
||||
*
|
||||
* Example:
|
||||
* ["delivery_1", 1, 3, "delivery_zone", 250000, -75, 300, false, false] spawn forge_server_task_fnc_delivery;
|
||||
* ["delivery_1", 1, 3, "delivery_zone", 250000, -75, 300, false, false, 900] spawn forge_server_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", -1, [0]],
|
||||
["_equipmentRewards", [], [[]]],
|
||||
["_supplyRewards", [], [[]]],
|
||||
["_weaponRewards", [], [[]]],
|
||||
["_vehicleRewards", [], [[]]],
|
||||
["_specialRewards", [], [[]]]
|
||||
];
|
||||
|
||||
private _result = 0;
|
||||
private _cargo = [];
|
||||
|
||||
waitUntil {
|
||||
sleep 1;
|
||||
_cargo = GVAR(TaskStore) call ["getTaskEntities", ["cargo", _taskID]];
|
||||
GVAR(TaskStore) call ["trackParticipants", [_taskID, _cargo, _deliveryZone, 125]];
|
||||
count _cargo > 0
|
||||
};
|
||||
|
||||
_cargo = GVAR(TaskStore) call ["getTaskEntities", ["cargo", _taskID]];
|
||||
private _startTime = if (_time isNotEqualTo -1) then { floor(time) } else { nil };
|
||||
|
||||
waitUntil {
|
||||
sleep 1;
|
||||
GVAR(TaskStore) call ["trackParticipants", [_taskID, _cargo, _deliveryZone, 125]];
|
||||
|
||||
private _cargoDelivered = ({ _x inArea _deliveryZone && (damage _x) < 0.7 } count _cargo);
|
||||
private _cargoDamaged = ({ damage _x >= 0.7 } count _cargo);
|
||||
|
||||
if (_time isNotEqualTo -1) 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);
|
||||
|
||||
sleep 1;
|
||||
|
||||
GVAR(TaskStore) call ["notifyParticipants", [_taskID, "warning", "Tasks", format ["Task failed: %1 reputation", _ratingFail]]];
|
||||
GVAR(TaskStore) call ["applyRatingOutcome", [_taskID, _ratingFail]];
|
||||
GVAR(TaskStore) call ["clearTask", [_taskID]];
|
||||
|
||||
if (_endFail) then { ["MissionFail", false] remoteExecCall ["BIS_fnc_endMission", playerSide]; };
|
||||
} else {
|
||||
{ deleteVehicle _x } forEach _cargo;
|
||||
|
||||
private _rewards = createHashMap;
|
||||
_rewards set ["funds", _companyFunds];
|
||||
|
||||
if (_equipmentRewards isNotEqualTo []) then { _rewards set ["equipment", _equipmentRewards]; };
|
||||
if (_supplyRewards isNotEqualTo []) then { _rewards set ["supplies", _supplyRewards]; };
|
||||
if (_weaponRewards isNotEqualTo []) then { _rewards set ["weapons", _weaponRewards]; };
|
||||
if (_vehicleRewards isNotEqualTo []) then { _rewards set ["vehicles", _vehicleRewards]; };
|
||||
if (_specialRewards isNotEqualTo []) then { _rewards set ["special", _specialRewards]; };
|
||||
|
||||
[_taskID, _rewards] call FUNC(handleTaskRewards);
|
||||
[_taskID, "SUCCEEDED"] call BFUNC(taskSetState);
|
||||
|
||||
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 ["applyRatingOutcome", [_taskID, _ratingSuccess]];
|
||||
GVAR(TaskStore) call ["clearTask", [_taskID]];
|
||||
|
||||
if (_endSuccess) then { ["MissionSuccess", true] remoteExecCall ["BIS_fnc_endMission", playerSide]; };
|
||||
};
|
||||
67
arma/server/addons/task/functions/fnc_deliveryModule.sqf
Normal file
67
arma/server/addons/task/functions/fnc_deliveryModule.sqf
Normal file
@ -0,0 +1,67 @@
|
||||
#include "..\script_component.hpp"
|
||||
|
||||
/*
|
||||
* Author: IDSolutions
|
||||
* Creates a delivery task module
|
||||
*
|
||||
* Arguments:
|
||||
* None
|
||||
*
|
||||
* Return Value:
|
||||
* None
|
||||
*
|
||||
* Example:
|
||||
* call forge_server_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;
|
||||
};
|
||||
|
||||
private _requesterUid = ["", getPlayerUID player] select hasInterface;
|
||||
["delivery", _params, 0, _requesterUid] spawn FUNC(handler);
|
||||
}];
|
||||
114
arma/server/addons/task/functions/fnc_destroy.sqf
Normal file
114
arma/server/addons/task/functions/fnc_destroy.sqf
Normal file
@ -0,0 +1,114 @@
|
||||
#include "..\script_component.hpp"
|
||||
|
||||
/*
|
||||
* Author: IDSolutions
|
||||
* Registers an destroy task
|
||||
*
|
||||
* Arguments:
|
||||
* 0: ID of the task <STRING>
|
||||
* 1: Amount of targets escaped to fail the task <NUMBER>
|
||||
* 2: Amount of targets eliminated to complete the task <NUMBER>
|
||||
* 3: Amount of funds the company recieves if the task is successful <NUMBER> (default: 0)
|
||||
* 4: Amount of rating the company and player lose if the task is failed <NUMBER> (default: 0)
|
||||
* 5: Amount of rating the company and player recieve if the task is successful <NUMBER> (default: 0)
|
||||
* 6: Should the mission end (MissionSuccess) if the task is successful <BOOL> (default: false)
|
||||
* 7: Should the mission end (MissionFailed) if the task is failed <BOOL> (default: false)
|
||||
* 8: Amount of time before target(s) escape <NUMBER> (default: -1)
|
||||
* 9: Equipment rewards <ARRAY> (default: [])
|
||||
* 10: Supply rewards <ARRAY> (default: [])
|
||||
* 11: Weapon rewards <ARRAY> (default: [])
|
||||
* 12: Vehicle rewards <ARRAY> (default: [])
|
||||
* 13: Special rewards <ARRAY> (default: [])
|
||||
*
|
||||
* Return Value:
|
||||
* None
|
||||
*
|
||||
* Example:
|
||||
* ["task_name", 1, 2, 250000, -75, 300, false, false] spawn forge_server_task_fnc_destroy;
|
||||
* ["task_name", 1, 2, 250000, -75, 300, false, false, 45] spawn forge_server_task_fnc_destroy;
|
||||
*
|
||||
* Public: Yes
|
||||
*/
|
||||
|
||||
params [
|
||||
["_taskID", "", [""]],
|
||||
["_limitFail", -1, [0]],
|
||||
["_limitSuccess", -1, [0]],
|
||||
["_companyFunds", 0, [0]],
|
||||
["_ratingFail", 0, [0]],
|
||||
["_ratingSuccess", 0, [0]],
|
||||
["_endSuccess", false, [false]],
|
||||
["_endFail", false, [false]],
|
||||
["_time", -1, [0]],
|
||||
["_equipmentRewards", [], [[]]],
|
||||
["_supplyRewards", [], [[]]],
|
||||
["_weaponRewards", [], [[]]],
|
||||
["_vehicleRewards", [], [[]]],
|
||||
["_specialRewards", [], [[]]]
|
||||
];
|
||||
|
||||
private _result = 0;
|
||||
private _targets = [];
|
||||
|
||||
waitUntil {
|
||||
sleep 1;
|
||||
_targets = GVAR(TaskStore) call ["getTaskEntities", ["targets", _taskID]];
|
||||
GVAR(TaskStore) call ["trackParticipants", [_taskID, _targets, "", 300]];
|
||||
count _targets > 0
|
||||
};
|
||||
|
||||
_targets = GVAR(TaskStore) call ["getTaskEntities", ["targets", _taskID]];
|
||||
private _startTime = if (!isNil "_time") then { floor(time) } else { nil };
|
||||
|
||||
waitUntil {
|
||||
sleep 1;
|
||||
GVAR(TaskStore) call ["trackParticipants", [_taskID, _targets, "", 300]];
|
||||
|
||||
private _targetsDestroyed = ({ !alive _x } count _targets);
|
||||
|
||||
if (!isNil "_time") then {
|
||||
private _timeExpired = (floor time - _startTime >= _time);
|
||||
|
||||
if (_targetsDestroyed < _limitSuccess && _timeExpired) then { _result = 1; };
|
||||
|
||||
(_result == 1) or (_targetsDestroyed >= _limitSuccess)
|
||||
} else {
|
||||
(_targetsDestroyed >= _limitSuccess)
|
||||
};
|
||||
};
|
||||
|
||||
if (_result == 1) then {
|
||||
{ deleteVehicle _x } forEach _targets;
|
||||
|
||||
[_taskID, "FAILED"] call BFUNC(taskSetState);
|
||||
|
||||
sleep 1;
|
||||
|
||||
GVAR(TaskStore) call ["notifyParticipants", [_taskID, "warning", "Tasks", format ["Task failed: %1 reputation", _ratingFail]]];
|
||||
GVAR(TaskStore) call ["applyRatingOutcome", [_taskID, _ratingFail]];
|
||||
GVAR(TaskStore) call ["clearTask", [_taskID]];
|
||||
|
||||
if (_endFail) then { ["MissionFail", false] remoteExecCall ["BIS_fnc_endMission", playerSide]; };
|
||||
} else {
|
||||
{ deleteVehicle _x } forEach _targets;
|
||||
|
||||
private _rewards = createHashMap;
|
||||
_rewards set ["funds", _companyFunds];
|
||||
|
||||
if (_equipmentRewards isNotEqualTo []) then { _rewards set ["equipment", _equipmentRewards]; };
|
||||
if (_supplyRewards isNotEqualTo []) then { _rewards set ["supplies", _supplyRewards]; };
|
||||
if (_weaponRewards isNotEqualTo []) then { _rewards set ["weapons", _weaponRewards]; };
|
||||
if (_vehicleRewards isNotEqualTo []) then { _rewards set ["vehicles", _vehicleRewards]; };
|
||||
if (_specialRewards isNotEqualTo []) then { _rewards set ["special", _specialRewards]; };
|
||||
|
||||
[_taskID, _rewards] call FUNC(handleTaskRewards);
|
||||
[_taskID, "SUCCEEDED"] call BFUNC(taskSetState);
|
||||
|
||||
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 ["applyRatingOutcome", [_taskID, _ratingSuccess]];
|
||||
GVAR(TaskStore) call ["clearTask", [_taskID]];
|
||||
|
||||
if (_endSuccess) then { ["MissionSuccess", true] remoteExecCall ["BIS_fnc_endMission", playerSide]; };
|
||||
};
|
||||
51
arma/server/addons/task/functions/fnc_destroyModule.sqf
Normal file
51
arma/server/addons/task/functions/fnc_destroyModule.sqf
Normal file
@ -0,0 +1,51 @@
|
||||
#include "..\script_component.hpp"
|
||||
|
||||
/*
|
||||
* Author: IDSolutions
|
||||
* Initializes the destroy module.
|
||||
*
|
||||
* Arguments:
|
||||
* 0: Logic <OBJECT> - The logic object
|
||||
* 1: Units <ARRAY> - The array of units
|
||||
* 2: Activated <BOOL> - Whether the module is activated
|
||||
*
|
||||
* Return Value:
|
||||
* None
|
||||
*
|
||||
* Example:
|
||||
* [logicObject, [unit1, unit2], true] call forge_server_task_fnc_destroyModule;
|
||||
*
|
||||
* Public: No
|
||||
*/
|
||||
|
||||
params [["_logic", objNull, [objNull]], ["_units", [], [[]]], ["_activated", true, [true]]];
|
||||
|
||||
if !(_activated) exitWith {};
|
||||
|
||||
private _taskID = _logic getVariable ["TaskID", ""];
|
||||
private _limitFail = _logic getVariable ["LimitFail", -1];
|
||||
private _limitSuccess = _logic getVariable ["LimitSuccess", -1];
|
||||
private _companyFunds = _logic getVariable ["CompanyFunds", 0];
|
||||
private _ratingFail = _logic getVariable ["RatingFail", 0];
|
||||
private _ratingSuccess = _logic getVariable ["RatingSuccess", 0];
|
||||
private _endSuccess = _logic getVariable ["EndSuccess", false];
|
||||
private _endFail = _logic getVariable ["EndFail", false];
|
||||
private _timeLimit = _logic getVariable ["TimeLimit", 0];
|
||||
|
||||
["INFO", format ["Destroy Module Parameters: TaskID: %1, LimitFail: %2, LimitSuccess: %3, Funds: %4, RatingFail: %5, RatingSuccess: %6, EndSuccess: %7, EndFail: %8, Time: %9", _taskID, _limitFail, _limitSuccess, _companyFunds, _ratingFail, _ratingSuccess, _endSuccess, _endFail, _timeLimit]] call EFUNC(common,log);
|
||||
|
||||
private _syncedEntities = synchronizedObjects _logic;
|
||||
["INFO", format ["Destroy Module Synced Entities: %1", _syncedEntities]] call EFUNC(common,log);
|
||||
|
||||
{
|
||||
[_x, _taskID] spawn FUNC(makeTarget);
|
||||
} forEach _syncedEntities;
|
||||
|
||||
private _params = [_taskID, _limitFail, _limitSuccess, _companyFunds, _ratingFail, _ratingSuccess, _endSuccess, _endFail];
|
||||
if (_timeLimit != 0) then {
|
||||
_params pushBack _timeLimit;
|
||||
};
|
||||
|
||||
["destroy", _params, 0, ""] spawn FUNC(handler);
|
||||
|
||||
deleteVehicle _logic;
|
||||
23
arma/server/addons/task/functions/fnc_explosivesModule.sqf
Normal file
23
arma/server/addons/task/functions/fnc_explosivesModule.sqf
Normal file
@ -0,0 +1,23 @@
|
||||
#include "..\script_component.hpp"
|
||||
|
||||
/*
|
||||
* Author: IDSolutions
|
||||
* Initializes the explosives module
|
||||
*
|
||||
* Arguments:
|
||||
* 0: Logic <OBJECT> - The logic object
|
||||
* 1: Units <ARRAY> - The array of units
|
||||
* 2: Activated <BOOL> - Whether the module is activated
|
||||
*
|
||||
* Return Value:
|
||||
* None
|
||||
*
|
||||
* Example:
|
||||
* [logicObject, [unit1, unit2], true] call forge_server_task_fnc_explosivesModule;
|
||||
*
|
||||
* Public: No
|
||||
*/
|
||||
|
||||
params [["_logic", objNull, [objNull]], ["_units", [], [[]]], ["_activated", true, [true]]];
|
||||
|
||||
if !(_activated) exitWith {};
|
||||
223
arma/server/addons/task/functions/fnc_handleTaskRewards.sqf
Normal file
223
arma/server/addons/task/functions/fnc_handleTaskRewards.sqf
Normal file
@ -0,0 +1,223 @@
|
||||
#include "..\script_component.hpp"
|
||||
|
||||
/*
|
||||
* Author: IDSolutions
|
||||
* Handles task completion rewards for organizations.
|
||||
*
|
||||
* Arguments:
|
||||
* 0: Task ID <STRING>
|
||||
* 1: Reward Data <HASHMAP>
|
||||
* - funds: Amount of money to award <NUMBER>
|
||||
* - equipment: Array of equipment classnames to award <ARRAY>
|
||||
* - supplies: Array of supply classnames to award <ARRAY>
|
||||
* - weapons: Array of weapon classnames to award <ARRAY>
|
||||
* - vehicles: Array of vehicle classnames to award <ARRAY>
|
||||
* - special: Array of special item classnames to award <ARRAY>
|
||||
*
|
||||
* Return Value:
|
||||
* Success <BOOLEAN>
|
||||
*
|
||||
* Example:
|
||||
* private _rewards = createHashMapFromArray [
|
||||
* ["funds", 10000],
|
||||
* ["reputation", 50],
|
||||
* ["equipment", ["ItemGPS", "ItemCompass"]],
|
||||
* ["supplies", ["FirstAidKit", "Medikit"]],
|
||||
* ["weapons", ["arifle_MX_F"]],
|
||||
* ["vehicles", ["B_MRAP_01_F"]],
|
||||
* ["special", ["B_UAV_01_F"]]
|
||||
* ];
|
||||
* ["task_1", _rewards] call forge_server_task_fnc_handleTaskRewards;
|
||||
*
|
||||
* Public: No
|
||||
*/
|
||||
|
||||
params [["_taskID", ""], ["_rewards", createHashMap]];
|
||||
|
||||
if (_taskID == "") exitWith {
|
||||
["ERROR", "No task ID provided for rewards"] call EFUNC(common,log);
|
||||
false
|
||||
};
|
||||
|
||||
private _rewardContext = GVAR(TaskStore) call ["resolveRewardContext", [_taskID]];
|
||||
private _requesterUid = _rewardContext getOrDefault ["requesterUid", ""];
|
||||
private _orgID = _rewardContext getOrDefault ["orgID", ""];
|
||||
private _memberUids = _rewardContext getOrDefault ["memberUids", []];
|
||||
if (_orgID isEqualTo "") exitWith {
|
||||
["ERROR", format ["No organization reward context found for task %1.", _taskID]] call EFUNC(common,log);
|
||||
false
|
||||
};
|
||||
|
||||
private _success = true;
|
||||
private _funds = _rewards getOrDefault ["funds", 0];
|
||||
private _rewardMessages = [];
|
||||
|
||||
private _resolveRewardLabel = {
|
||||
params [["_className", "", [""]]];
|
||||
|
||||
if (_className isEqualTo "") exitWith { "" };
|
||||
|
||||
{
|
||||
private _cfg = _x >> _className;
|
||||
if (isClass _cfg) exitWith {
|
||||
private _displayName = getText (_cfg >> "displayName");
|
||||
[_displayName, _className] select (_displayName isEqualTo "");
|
||||
};
|
||||
} forEach [
|
||||
configFile >> "CfgWeapons",
|
||||
configFile >> "CfgMagazines",
|
||||
configFile >> "CfgVehicles",
|
||||
configFile >> "CfgGlasses"
|
||||
];
|
||||
|
||||
_className
|
||||
};
|
||||
|
||||
private _notifyMembers = {
|
||||
params [["_type", "info", [""]], ["_title", "Tasks", [""]], ["_message", "", [""]]];
|
||||
|
||||
if (_message isEqualTo "") exitWith {};
|
||||
{
|
||||
private _player = [_x] call EFUNC(common,getPlayer);
|
||||
if (isNull _player) then { continue; };
|
||||
[CRPC(notifications,recieveNotification), [_type, _title, _message], _player] call CFUNC(targetEvent);
|
||||
} forEach _memberUids;
|
||||
};
|
||||
|
||||
private _syncOrgPatch = {
|
||||
params [["_patch", createHashMap, [createHashMap]]];
|
||||
|
||||
if (_patch isEqualTo createHashMap) exitWith {};
|
||||
{
|
||||
private _player = [_x] call EFUNC(common,getPlayer);
|
||||
if (isNull _player) then { continue; };
|
||||
[CRPC(org,responseSyncOrg), [_patch], _player] call CFUNC(targetEvent);
|
||||
} forEach _memberUids;
|
||||
};
|
||||
|
||||
if (_funds > 0) then {
|
||||
private _org = EGVAR(org,Registry) getOrDefault [_orgID, createHashMap];
|
||||
if (_org isEqualTo createHashMap) then {
|
||||
_org = EGVAR(org,OrgStore) call ["loadById", [_orgID]];
|
||||
};
|
||||
|
||||
if (_org isEqualTo createHashMap) then {
|
||||
["ERROR", format ["Failed to load organization %1 for task %2 funds reward.", _orgID, _taskID]] call EFUNC(common,log);
|
||||
_success = false;
|
||||
} else {
|
||||
private _patch = EGVAR(org,OrgStore) call [
|
||||
"set",
|
||||
[
|
||||
EGVAR(org,Registry),
|
||||
"org:update",
|
||||
_orgID,
|
||||
"funds",
|
||||
((_org getOrDefault ["funds", 0]) + _funds),
|
||||
false
|
||||
]
|
||||
];
|
||||
|
||||
[_patch] call _syncOrgPatch;
|
||||
_rewardMessages pushBack format ["$%1 org funds", [_funds] call EFUNC(common,formatNumber)];
|
||||
};
|
||||
};
|
||||
|
||||
private _grantOrgAssets = {
|
||||
params [["_category", "items", [""]], ["_items", [], [[]]]];
|
||||
|
||||
if (_items isEqualTo []) exitWith {};
|
||||
|
||||
private _assetEntries = _items apply {
|
||||
createHashMapFromArray [
|
||||
["classname", _x],
|
||||
["category", _category],
|
||||
["quantity", 1]
|
||||
]
|
||||
};
|
||||
|
||||
private _grantResult = EGVAR(org,OrgStore) call ["addAssets", [_requesterUid, _assetEntries, false, _orgID]];
|
||||
if !(_grantResult getOrDefault ["success", false]) then {
|
||||
["ERROR", format ["Failed to award %1 assets for task %2: %3", _category, _taskID, _grantResult getOrDefault ["message", "Unknown error."]]] call EFUNC(common,log);
|
||||
_success = false;
|
||||
} else {
|
||||
[_grantResult getOrDefault ["patch", createHashMap]] call _syncOrgPatch;
|
||||
private _labels = _items apply { [_x] call _resolveRewardLabel };
|
||||
_rewardMessages pushBack format ["%1: %2", _category, _labels joinString ", "];
|
||||
};
|
||||
};
|
||||
|
||||
private _grantOrgFleet = {
|
||||
params [["_vehicles", [], [[]]]];
|
||||
|
||||
if (_vehicles isEqualTo []) exitWith {};
|
||||
|
||||
private _vehicleEntries = _vehicles apply {
|
||||
private _category = "other";
|
||||
if (_x isKindOf "Car") then { _category = "cars"; };
|
||||
if (_x isKindOf "Tank") then { _category = "armor"; };
|
||||
if (_x isKindOf "Helicopter") then { _category = "helis"; };
|
||||
if (_x isKindOf "Plane") then { _category = "planes"; };
|
||||
if (_x isKindOf "Ship") then { _category = "naval"; };
|
||||
|
||||
createHashMapFromArray [
|
||||
["classname", _x],
|
||||
["category", _category]
|
||||
]
|
||||
};
|
||||
|
||||
private _fleetResult = EGVAR(org,OrgStore) call ["addFleetVehicles", [_requesterUid, _vehicleEntries, false, _orgID]];
|
||||
if !(_fleetResult getOrDefault ["success", false]) then {
|
||||
["ERROR", format ["Failed to award vehicle rewards for task %2: %1", _fleetResult getOrDefault ["message", "Unknown error."], _taskID]] call EFUNC(common,log);
|
||||
_success = false;
|
||||
} else {
|
||||
[_fleetResult getOrDefault ["patch", createHashMap]] call _syncOrgPatch;
|
||||
private _labels = _vehicles apply { [_x] call _resolveRewardLabel };
|
||||
_rewardMessages pushBack format ["vehicles: %1", _labels joinString ", "];
|
||||
};
|
||||
};
|
||||
|
||||
private _equipment = _rewards getOrDefault ["equipment", []];
|
||||
if (count _equipment > 0) then {
|
||||
["equipment", _equipment] call _grantOrgAssets;
|
||||
};
|
||||
|
||||
private _supplies = _rewards getOrDefault ["supplies", []];
|
||||
if (count _supplies > 0) then {
|
||||
["supplies", _supplies] call _grantOrgAssets;
|
||||
};
|
||||
|
||||
private _weapons = _rewards getOrDefault ["weapons", []];
|
||||
if (count _weapons > 0) then {
|
||||
["weapons", _weapons] call _grantOrgAssets;
|
||||
};
|
||||
|
||||
private _special = _rewards getOrDefault ["special", []];
|
||||
if (count _special > 0) then {
|
||||
["special", _special] call _grantOrgAssets;
|
||||
};
|
||||
|
||||
private _vehicles = _rewards getOrDefault ["vehicles", []];
|
||||
if (count _vehicles > 0) then {
|
||||
[_vehicles] call _grantOrgFleet;
|
||||
};
|
||||
|
||||
if (_success) then {
|
||||
private _orgName = "";
|
||||
private _org = EGVAR(org,Registry) getOrDefault [_orgID, createHashMap];
|
||||
if (_org isNotEqualTo createHashMap) then {
|
||||
_orgName = _org getOrDefault ["name", _orgID];
|
||||
};
|
||||
if (_orgName isEqualTo "") then { _orgName = _orgID; };
|
||||
|
||||
private _message = format ["Task rewards added to %1.", _orgName];
|
||||
if (_rewardMessages isNotEqualTo []) then {
|
||||
_message = format ["%1 %2", _message, _rewardMessages joinString ", "];
|
||||
};
|
||||
|
||||
["INFO", _message] call EFUNC(common,log);
|
||||
["success", "Tasks", _message] call _notifyMembers;
|
||||
} else {
|
||||
["warning", "Tasks", format ["Task %1 completed, but one or more org rewards failed to apply.", _taskID]] call _notifyMembers;
|
||||
};
|
||||
|
||||
_success
|
||||
108
arma/server/addons/task/functions/fnc_handler.sqf
Normal file
108
arma/server/addons/task/functions/fnc_handler.sqf
Normal file
@ -0,0 +1,108 @@
|
||||
#include "..\script_component.hpp"
|
||||
|
||||
/*
|
||||
* Author: IDSolutions
|
||||
* Server side task handler/spawner
|
||||
*
|
||||
* Arguments:
|
||||
* 0: Type of task <STRING>
|
||||
* 1: Arguments for task <ARRAY>
|
||||
* 2: Minimum org reputation for task <NUMBER> (default: 0)
|
||||
* 3: Requester UID <STRING> (default: "")
|
||||
*
|
||||
* Return Value:
|
||||
* None
|
||||
*
|
||||
* Example:
|
||||
* ["task_type", [_reward, _punish, _time, etc.....], minReputation, requesterUid] call forge_server_task_fnc_handler;
|
||||
*
|
||||
* Public: Yes
|
||||
*/
|
||||
|
||||
params [["_taskType", "", [""]], ["_args", [], [[]]], ["_minRating", 0, [0]], ["_requesterUid", "", [""]]];
|
||||
|
||||
private _taskID = "";
|
||||
|
||||
if (_minRating > 0) then {
|
||||
if (_requesterUid isEqualTo "") then {
|
||||
["WARNING", format ["Task %1 requires minimum reputation %2 but no requester UID was provided, skipping reputation gate.", _taskType, _minRating]] call EFUNC(common,log);
|
||||
} else {
|
||||
private _requesterActor = EGVAR(actor,Registry) getOrDefault [_requesterUid, createHashMap];
|
||||
if (_requesterActor isEqualTo createHashMap) then {
|
||||
_requesterActor = EGVAR(actor,ActorStore) call ["init", [_requesterUid]];
|
||||
};
|
||||
|
||||
private _orgID = _requesterActor getOrDefault ["organization", "default"];
|
||||
if (_orgID isEqualTo "") then { _orgID = "default"; };
|
||||
|
||||
private _org = EGVAR(org,Registry) getOrDefault [_orgID, createHashMap];
|
||||
if (_org isEqualTo createHashMap) then {
|
||||
_org = EGVAR(org,OrgStore) call ["loadById", [_orgID]];
|
||||
};
|
||||
|
||||
private _orgReputation = _org getOrDefault ["reputation", 0];
|
||||
if (_orgReputation < _minRating) exitWith {
|
||||
private _message = format ["Organization reputation of %1 does not meet the minimum required reputation of %2.", _orgReputation, _minRating];
|
||||
["WARNING", format ["Task %1 blocked: %2", _taskType, _message]] call EFUNC(common,log);
|
||||
|
||||
private _player = [_requesterUid] call EFUNC(common,getPlayer);
|
||||
if (isNull _player) exitWith {};
|
||||
|
||||
[CRPC(notifications,recieveNotification), ["warning", "Tasks", _message], _player] call CFUNC(targetEvent);
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
if (_args isNotEqualTo [] && { (_args select 0) isEqualType "" }) then {
|
||||
_taskID = _args select 0;
|
||||
};
|
||||
|
||||
if (_taskID isNotEqualTo "") then {
|
||||
private _ownershipResult = GVAR(TaskStore) call ["bindTaskOwnership", [_taskID, _requesterUid]];
|
||||
if !(_ownershipResult getOrDefault ["success", false]) then {
|
||||
["WARNING", format [
|
||||
"Failed to bind task ownership for %1 (%2): %3",
|
||||
_taskID,
|
||||
_taskType,
|
||||
_ownershipResult getOrDefault ["message", "Unknown error."]
|
||||
]] call EFUNC(common,log);
|
||||
};
|
||||
|
||||
GVAR(TaskStore) call ["setTaskStatus", [_taskID, "active"]];
|
||||
};
|
||||
|
||||
switch (_taskType) do {
|
||||
case "attack": {
|
||||
private _thread = _args spawn FUNC(attack);
|
||||
waitUntil { sleep 2; scriptDone _thread };
|
||||
};
|
||||
case "defuse": {
|
||||
private _thread = _args spawn FUNC(defuse);
|
||||
waitUntil { sleep 2; scriptDone _thread };
|
||||
};
|
||||
case "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 "defend": {
|
||||
private _thread = _args spawn FUNC(defend);
|
||||
waitUntil { sleep 2; scriptDone _thread };
|
||||
};
|
||||
case "hostage": {
|
||||
private _thread = _args spawn FUNC(hostage);
|
||||
waitUntil { sleep 2; scriptDone _thread };
|
||||
};
|
||||
case "hvt": {
|
||||
private _thread = _args spawn FUNC(hvt);
|
||||
waitUntil { sleep 2; scriptDone _thread };
|
||||
};
|
||||
default {
|
||||
["ERROR", format ["Unknown Contract Type: %1", _taskType]] call EFUNC(common,log);
|
||||
};
|
||||
};
|
||||
|
||||
["INFO", "Mission Handler Done"] call EFUNC(common,log);
|
||||
68
arma/server/addons/task/functions/fnc_heartBeat.sqf
Normal file
68
arma/server/addons/task/functions/fnc_heartBeat.sqf
Normal file
@ -0,0 +1,68 @@
|
||||
#include "..\script_component.hpp"
|
||||
|
||||
/*
|
||||
* Author: IDSolutions
|
||||
* Registers Entity and starts heartbeat
|
||||
*
|
||||
* Arguments:
|
||||
* 0: The entity <OBJECT>
|
||||
* 1: Type of the entity <STRING>
|
||||
* 2: The countdown timer <NUMBER>
|
||||
*
|
||||
* Return Value:
|
||||
* None
|
||||
*
|
||||
* Example:
|
||||
* [_entity, "entity_type", 30] spawn FUNC(heartBeat);
|
||||
*
|
||||
* Public: Yes
|
||||
*/
|
||||
|
||||
params [["_entity", nil, [objNull, 0, [], sideUnknown, grpNull, ""]], ["_typeOf", "", [""]], ["_time", 0, [0]]];
|
||||
|
||||
private _nearPlayers = [];
|
||||
|
||||
switch (_typeOf) do {
|
||||
case "hostage": {
|
||||
_entity setCaptive true;
|
||||
_entity enableAIFeature ["MOVE", false];
|
||||
_entity playMove "acts_executionvictim_loop";
|
||||
|
||||
waitUntil {
|
||||
sleep 1;
|
||||
_nearPlayers = allPlayers inAreaArray [ASLToAGL getPosASL _entity, 2, 2, 0, false, 2];
|
||||
count _nearPlayers > 0
|
||||
};
|
||||
|
||||
private _nearPlayer = _nearPlayers select 0;
|
||||
|
||||
[_entity] joinSilent (group _nearPlayer);
|
||||
|
||||
_entity setCaptive false;
|
||||
_entity enableAIFeature ["MOVE", true];
|
||||
_entity playMove "acts_executionvictim_unbow";
|
||||
};
|
||||
case "hvt": {
|
||||
waitUntil {
|
||||
sleep 1;
|
||||
_nearPlayers = allPlayers inAreaArray [ASLToAGL getPosASL _entity, 2, 2, 0, false, 2];
|
||||
count _nearPlayers > 0
|
||||
};
|
||||
|
||||
_entity setCaptive true;
|
||||
doStop _entity;
|
||||
};
|
||||
case "ied": {
|
||||
while { alive _entity && _time > 0} do {
|
||||
if (_time > 10) then { _entity say3D "FORGE_timerBeep" };
|
||||
if (_time <= 10 && _time > 5) then { _entity say3D "FORGE_timerBeepShort" };
|
||||
if (_time <= 5) then { _entity say3D "FORGE_timerEnd" };
|
||||
if (_time <= 0) exitWith { _entity setDamage 1 };
|
||||
|
||||
_time = _time -1;
|
||||
sleep 1;
|
||||
};
|
||||
|
||||
if (alive _entity && _time <= 0) then { _entity setDamage 1 };
|
||||
};
|
||||
};
|
||||
173
arma/server/addons/task/functions/fnc_hostage.sqf
Normal file
173
arma/server/addons/task/functions/fnc_hostage.sqf
Normal file
@ -0,0 +1,173 @@
|
||||
#include "..\script_component.hpp"
|
||||
|
||||
/*
|
||||
* Author: IDSolutions
|
||||
* Registers an hostage task
|
||||
*
|
||||
* Arguments:
|
||||
* 0: ID of the task <STRING>
|
||||
* 1: Amount of hostages KIA to fail the task <NUMBER>
|
||||
* 2: Amount of hostages rescued to complete the task <NUMBER>
|
||||
* 3: Marker name for the extraction zone <STRING>
|
||||
* 4: Amount of funds the company recieves if the task is successful <NUMBER> (default: 0)
|
||||
* 5: Amount of rating the company and player lose if the task is failed <NUMBER> (default: 0)
|
||||
* 6: Amount of rating the company and player recieve if the task is successful <NUMBER> (default: 0)
|
||||
* 7: Subcategory of task <ARRAY> (default: [false, true])
|
||||
* 8: Should the mission end (MissionSuccess) if the task is successful <BOOL> (default: false)
|
||||
* 9: Should the mission end (MissionFailed) if the task is failed <BOOL> (default: false)
|
||||
* 10: Amount of time before hostage(s) die <NUMBER> (default: -1)
|
||||
* 11: Marker name for the cbrn zone <STRING> (default: "")
|
||||
* 12: Equipment rewards <ARRAY> (default: [])
|
||||
* 13: Supply rewards <ARRAY> (default: [])
|
||||
* 14: Weapon rewards <ARRAY> (default: [])
|
||||
* 15: Vehicle rewards <ARRAY> (default: [])
|
||||
* 16: Special rewards <ARRAY> (default: [])
|
||||
*
|
||||
* Return Value:
|
||||
* None
|
||||
*
|
||||
* Example:
|
||||
* ["task_name", 1, 2, "marker_name", 1500000, -75, 500, [false, true], false, false] spawn forge_server_task_fnc_hostage;
|
||||
* ["task_name", 1, 2, "marker_name", 1500000, -75, 500, [false, true], false, false, 45] spawn forge_server_task_fnc_hostage;
|
||||
* ["task_name", 1, 2, "marker_name", 1500000, -75, 500, [true, false], false, false, 45, "marker_name"] spawn forge_server_task_fnc_hostage;
|
||||
*
|
||||
* Public: Yes
|
||||
*/
|
||||
|
||||
params [
|
||||
["_taskID", ""],
|
||||
["_limitFail", -1],
|
||||
["_limitSuccess", -1],
|
||||
["_extZone", ""],
|
||||
["_companyFunds", 0],
|
||||
["_ratingFail", 0],
|
||||
["_ratingSuccess", 0],
|
||||
["_type", [["_cbrn", false, [false]], ["_hostage", true, [false]]]],
|
||||
["_endSuccess", false, [false]],
|
||||
["_endFail", false, [false]],
|
||||
["_time", -1, [0]],
|
||||
["_cbrnZone", "", [""]],
|
||||
["_equipmentRewards", [], [[]]],
|
||||
["_supplyRewards", [], [[]]],
|
||||
["_weaponRewards", [], [[]]],
|
||||
["_vehicleRewards", [], [[]]],
|
||||
["_specialRewards", [], [[]]]
|
||||
];
|
||||
|
||||
private _cbrn = (_this select 7) select 0;
|
||||
private _hostage = (_this select 7) select 1;
|
||||
private _result = 0;
|
||||
private _hostages = [];
|
||||
private _shooters = [];
|
||||
|
||||
waitUntil {
|
||||
sleep 1;
|
||||
_hostages = GVAR(TaskStore) call ["getTaskEntities", ["hostages", _taskID]];
|
||||
count _hostages > 0
|
||||
};
|
||||
|
||||
waitUntil {
|
||||
sleep 1;
|
||||
_shooters = GVAR(TaskStore) call ["getTaskEntities", ["shooters", _taskID]];
|
||||
GVAR(TaskStore) call ["trackParticipants", [_taskID, _hostages + _shooters, _extZone, 250]];
|
||||
count _shooters > 0
|
||||
};
|
||||
|
||||
_hostages = GVAR(TaskStore) call ["getTaskEntities", ["hostages", _taskID]];
|
||||
_shooters = GVAR(TaskStore) call ["getTaskEntities", ["shooters", _taskID]];
|
||||
private _startTime = if (_time isNotEqualTo -1) then { floor(time) } else { nil };
|
||||
|
||||
waitUntil {
|
||||
sleep 1;
|
||||
GVAR(TaskStore) call ["trackParticipants", [_taskID, _hostages + _shooters, _extZone, 250]];
|
||||
|
||||
private _hostagesFreed = ({ !captive _x } count _hostages);
|
||||
private _hostagesInZone = ({ _x inArea _extZone } count _hostages);
|
||||
private _hostagesKilled = ({ !alive _x } count _hostages);
|
||||
private _shootersAlive = ({ alive _x } count _shooters);
|
||||
|
||||
if (_time isNotEqualTo -1) then {
|
||||
private _timeExpired = (floor time - _startTime >= _time);
|
||||
|
||||
if (_hostagesFreed < _limitSuccess && _timeExpired) then { _result = 1; };
|
||||
if (_hostagesKilled >= _limitFail) then { _result = 1; };
|
||||
|
||||
(_result == 1) or
|
||||
((_hostagesInZone >= _limitSuccess) && (_hostagesKilled < _limitFail)) or
|
||||
((!isNil "_shooters") && (_shootersAlive <= 0) && (_hostagesInZone >= _limitSuccess) && (_hostagesKilled < _limitFail))
|
||||
} else {
|
||||
if (_hostagesKilled >= _limitFail) then { _result = 1; };
|
||||
|
||||
(_result == 1) or
|
||||
((_hostagesInZone >= _limitSuccess) && (_hostagesKilled < _limitFail)) or
|
||||
((!isNil "_shooters") && (_shootersAlive <= 0) && (_hostagesInZone >= _limitSuccess) && (_hostagesKilled < _limitFail))
|
||||
};
|
||||
};
|
||||
|
||||
if (_result == 1) then {
|
||||
if (_cbrn) then {
|
||||
"SmokeShellYellow" createVehicle getMarkerPos _cbrnZone;
|
||||
|
||||
sleep 5;
|
||||
|
||||
{
|
||||
if (captive _x) then {
|
||||
_x setDamage 0.9;
|
||||
_x playMove "acts_executionvictim_kill_end";
|
||||
|
||||
sleep 2.75;
|
||||
|
||||
_x setDamage 1;
|
||||
}
|
||||
} forEach _hostages;
|
||||
};
|
||||
|
||||
if (_hostage) then {
|
||||
{
|
||||
_x enableAIFeature ["MOVE", true];
|
||||
_x playMove "";
|
||||
} forEach _shooters;
|
||||
|
||||
sleep 1;
|
||||
|
||||
{ _x setCaptive false; } forEach _hostages;
|
||||
|
||||
sleep 5;
|
||||
};
|
||||
|
||||
{ deleteVehicle _x } forEach _hostages;
|
||||
{ deleteVehicle _x } forEach _shooters;
|
||||
|
||||
[_taskID, "FAILED"] call BFUNC(taskSetState);
|
||||
|
||||
sleep 1;
|
||||
|
||||
GVAR(TaskStore) call ["notifyParticipants", [_taskID, "warning", "Tasks", format ["Task failed: %1 reputation", _ratingFail]]];
|
||||
GVAR(TaskStore) call ["applyRatingOutcome", [_taskID, _ratingFail]];
|
||||
GVAR(TaskStore) call ["clearTask", [_taskID]];
|
||||
|
||||
if (_endFail) then { ["MissionFail", false] remoteExecCall ["BIS_fnc_endMission", playerSide]; };
|
||||
} else {
|
||||
{ deleteVehicle _x } forEach _hostages;
|
||||
{ deleteVehicle _x } forEach _shooters;
|
||||
|
||||
private _rewards = createHashMap;
|
||||
_rewards set ["funds", _companyFunds];
|
||||
|
||||
if (_equipmentRewards isNotEqualTo []) then { _rewards set ["equipment", _equipmentRewards]; };
|
||||
if (_supplyRewards isNotEqualTo []) then { _rewards set ["supplies", _supplyRewards]; };
|
||||
if (_weaponRewards isNotEqualTo []) then { _rewards set ["weapons", _weaponRewards]; };
|
||||
if (_vehicleRewards isNotEqualTo []) then { _rewards set ["vehicles", _vehicleRewards]; };
|
||||
if (_specialRewards isNotEqualTo []) then { _rewards set ["special", _specialRewards]; };
|
||||
|
||||
[_taskID, _rewards] call FUNC(handleTaskRewards);
|
||||
[_taskID, "SUCCEEDED"] call BFUNC(taskSetState);
|
||||
|
||||
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 ["applyRatingOutcome", [_taskID, _ratingSuccess]];
|
||||
GVAR(TaskStore) call ["clearTask", [_taskID]];
|
||||
|
||||
if (_endSuccess) then { ["MissionSuccess", true] remoteExecCall ["BIS_fnc_endMission", playerSide]; };
|
||||
};
|
||||
76
arma/server/addons/task/functions/fnc_hostageModule.sqf
Normal file
76
arma/server/addons/task/functions/fnc_hostageModule.sqf
Normal file
@ -0,0 +1,76 @@
|
||||
#include "..\script_component.hpp"
|
||||
|
||||
/*
|
||||
* Author: IDSolutions
|
||||
* Initializes the hostage module
|
||||
*
|
||||
* Arguments:
|
||||
* 0: Logic <OBJECT> - The logic object
|
||||
* 1: Units <ARRAY> - The array of units
|
||||
* 2: Activated <BOOL> - Whether the module is activated
|
||||
*
|
||||
* Return Value:
|
||||
* None
|
||||
*
|
||||
* Example:
|
||||
* [logicObject, [unit1, unit2], true] call forge_server_task_fnc_hostageModule;
|
||||
*
|
||||
* Public: No
|
||||
*/
|
||||
|
||||
params [["_logic", objNull, [objNull]], ["_units", [], [[]]], ["_activated", true, [true]]];
|
||||
|
||||
if !(_activated) exitWith {};
|
||||
|
||||
private _taskID = _logic getVariable ["TaskID", ""];
|
||||
private _limitFail = _logic getVariable ["LimitFail", -1];
|
||||
private _limitSuccess = _logic getVariable ["LimitSuccess", -1];
|
||||
private _extraction = _logic getVariable ["ExtZone", ""];
|
||||
private _companyFunds = _logic getVariable ["CompanyFunds", 0];
|
||||
private _ratingFail = _logic getVariable ["RatingFail", 0];
|
||||
private _ratingSuccess = _logic getVariable ["RatingSuccess", 0];
|
||||
private _cbrn = _logic getVariable ["CBRN", false];
|
||||
private _execution = _logic getVariable ["Execution", false];
|
||||
private _endSuccess = _logic getVariable ["EndSuccess", false];
|
||||
private _endFail = _logic getVariable ["EndFail", false];
|
||||
private _timeLimit = _logic getVariable ["TimeLimit", 0];
|
||||
private _cbrnZone = _logic getVariable ["CBRNZone", ""];
|
||||
|
||||
["INFO", format [
|
||||
"Hostage Module Parameters: TaskID: %1, LimitFail: %2, LimitSuccess: %3, ExtractionZone: %4, Funds: %5, RatingFail: %6, RatingSuccess: %7, CBRN: %8, Execution: %9, EndSuccess: %10, EndFail: %11, Time: %12, CBRNZone: %13",
|
||||
_taskID, _limitFail, _limitSuccess, _extraction, _companyFunds, _ratingFail, _ratingSuccess, _cbrn, _execution, _endSuccess, _endFail, _timeLimit, _cbrnZone
|
||||
]] call EFUNC(common,log);
|
||||
|
||||
private _syncedModules = synchronizedObjects _logic;
|
||||
["INFO", format ["Hostage Module Synced Entities: %1", _syncedModules]] call EFUNC(common,log);
|
||||
|
||||
private _hostageModule = (_syncedModules select { typeOf _x == "FORGE_Module_Hostages" }) select 0;
|
||||
private _shooterModule = (_syncedModules select { typeOf _x == "FORGE_Module_Shooters" }) select 0;
|
||||
|
||||
private _hostageEntities = synchronizedObjects _hostageModule;
|
||||
["INFO", format ["Hostage Module Hostage Entities: %1", _hostageEntities]] call EFUNC(common,log);
|
||||
|
||||
private _shooterEntities = synchronizedObjects _shooterModule;
|
||||
["INFO", format ["Hostage Module Shooter Entities: %1", _shooterEntities]] call EFUNC(common,log);
|
||||
|
||||
{
|
||||
if (!isNull _x && (_x isNotEqualTo str objNull)) then {
|
||||
[_x, _taskID] spawn FUNC(makeHostage);
|
||||
};
|
||||
} forEach _hostageEntities;
|
||||
|
||||
{
|
||||
if (!isNull _x && (_x isNotEqualTo str objNull)) then {
|
||||
[_x, _taskID] spawn FUNC(makeShooter);
|
||||
};
|
||||
} forEach _shooterEntities;
|
||||
|
||||
private _params = [_taskID, _limitFail, _limitSuccess, _extraction, _companyFunds, _ratingFail, _ratingSuccess, [_cbrn, _execution], _endSuccess, _endFail];
|
||||
if (_timeLimit != 0) then {
|
||||
_params pushBack _timeLimit;
|
||||
_params pushBack _cbrnZone;
|
||||
};
|
||||
|
||||
["hostage", _params, 0, ""] spawn FUNC(handler);
|
||||
|
||||
deleteVehicle _logic;
|
||||
23
arma/server/addons/task/functions/fnc_hostagesModule.sqf
Normal file
23
arma/server/addons/task/functions/fnc_hostagesModule.sqf
Normal file
@ -0,0 +1,23 @@
|
||||
#include "..\script_component.hpp"
|
||||
|
||||
/*
|
||||
* Author: IDSolutions
|
||||
* Initializes the hostage module
|
||||
*
|
||||
* Arguments:
|
||||
* 0: Logic <OBJECT> - The logic object
|
||||
* 1: Units <ARRAY> - The array of units
|
||||
* 2: Activated <BOOL> - Whether the module is activated
|
||||
*
|
||||
* Return Value:
|
||||
* None
|
||||
*
|
||||
* Example:
|
||||
* [logicObject, [unit1, unit2], true] call forge_server_task_fnc_hostagesModule;
|
||||
*
|
||||
* Public: No
|
||||
*/
|
||||
|
||||
params [["_logic", objNull, [objNull]], ["_units", [], [[]]], ["_activated", true, [true]]];
|
||||
|
||||
if !(_activated) exitWith {};
|
||||
128
arma/server/addons/task/functions/fnc_hvt.sqf
Normal file
128
arma/server/addons/task/functions/fnc_hvt.sqf
Normal file
@ -0,0 +1,128 @@
|
||||
#include "..\script_component.hpp"
|
||||
|
||||
/*
|
||||
* Author: IDSolutions
|
||||
* Registers an hvt task
|
||||
*
|
||||
* Arguments:
|
||||
* 0: ID of the task <STRING>
|
||||
* 1: Amount of HVTs KIA to fail the task <NUMBER>
|
||||
* 2: Amount of HVTs Captured or KIA to complete the task <NUMBER>
|
||||
* 3: Marker name for the extraction zone <STRING>
|
||||
* 4: Amount of funds the company recieves if the task is successful <NUMBER> (default: 0)
|
||||
* 5: Amount of rating the company and player lose if the task is failed <NUMBER> (default: 0)
|
||||
* 6: Amount of rating the company and player recieve if the task is successful <NUMBER> (default: 0)
|
||||
* 7: Subcategory of task <ARRAY> (default: [true, false])
|
||||
* 8: Should the mission end (MissionSuccess) if the task is successful <BOOL> (default: false)
|
||||
* 9: Should the mission end (MissionFailed) if the task is failed <BOOL> (default: false)
|
||||
* 10: Amount of time before hvt(s) die <NUMBER> (default: -1)
|
||||
* 11: Equipment rewards <ARRAY> (default: [])
|
||||
* 12: Supply rewards <ARRAY> (default: [])
|
||||
* 13: Weapon rewards <ARRAY> (default: [])
|
||||
* 14: Vehicle rewards <ARRAY> (default: [])
|
||||
* 15: Special rewards <ARRAY> (default: [])
|
||||
*
|
||||
* Return Value:
|
||||
* None
|
||||
*
|
||||
* Example:
|
||||
* ["task_name", 1, 1, "marker_name", 500000, -75, 300, [true, false], false, false] spawn forge_server_task_fnc_hvt;
|
||||
* ["task_name", -1, 1, "", 500000, -75, 300, [false, true], false, false] spawn forge_server_task_fnc_hvt;
|
||||
* ["task_name", 1, 1, "marker_name", 500000, -75, 300, [true, false], false, false, 45] spawn forge_server_task_fnc_hvt;
|
||||
* ["task_name", -1, 1, "", 500000, -75, 300, [false, true], false, false, 45] spawn forge_server_task_fnc_hvt;
|
||||
*
|
||||
* Public: Yes
|
||||
*/
|
||||
|
||||
params [
|
||||
["_taskID", "", [""]],
|
||||
["_limitFail", -1, [0]],
|
||||
["_limitSuccess", -1, [0]],
|
||||
["_extZone", "", [""]],
|
||||
["_companyFunds", 0, [0]],
|
||||
["_ratingFail", 0, [0]],
|
||||
["_ratingSuccess", 0, [0]],
|
||||
["_type", [["_capture", true, [false]], ["_eliminate", false, [false]]]],
|
||||
["_endSuccess", false, [false]],
|
||||
["_endFail", false, [false]],
|
||||
["_time", -1, [0]],
|
||||
["_equipmentRewards", [], [[]]],
|
||||
["_supplyRewards", [], [[]]],
|
||||
["_weaponRewards", [], [[]]],
|
||||
["_vehicleRewards", [], [[]]],
|
||||
["_specialRewards", [], [[]]]
|
||||
];
|
||||
|
||||
private _capture = (_this select 7) select 0;
|
||||
private _eliminate = (_this select 7) select 1;
|
||||
private _result = 0;
|
||||
private _hvts = [];
|
||||
|
||||
waitUntil {
|
||||
sleep 1;
|
||||
_hvts = GVAR(TaskStore) call ["getTaskEntities", ["hvts", _taskID]];
|
||||
GVAR(TaskStore) call ["trackParticipants", [_taskID, _hvts, _extZone, 250]];
|
||||
count _hvts > 0
|
||||
};
|
||||
|
||||
_hvts = GVAR(TaskStore) call ["getTaskEntities", ["hvts", _taskID]];
|
||||
private _startTime = if (!isNil "_time") then { floor(time) } else { nil };
|
||||
|
||||
waitUntil {
|
||||
sleep 1;
|
||||
GVAR(TaskStore) call ["trackParticipants", [_taskID, _hvts, _extZone, 250]];
|
||||
|
||||
private _hvtsCaptive = ({ captive _x } count _hvts);
|
||||
private _hvtsKilled = ({ !alive _x } count _hvts);
|
||||
private _hvtsInZone = ({ _x inArea _extZone } count _hvts);
|
||||
|
||||
if (!isNil "_time") then {
|
||||
private _timeExpired = (floor time - _startTime >= _time);
|
||||
|
||||
if (_capture && _hvtsKilled >= _limitFail) then { _result = 1; };
|
||||
if (_capture && _hvtsCaptive < _limitSuccess && _timeExpired) then { _result = 1; };
|
||||
if (_eliminate && _hvtsKilled < _limitSuccess && _timeExpired) then { _result = 1; };
|
||||
|
||||
(_result == 1) or (_capture && (_hvtsInZone >= _limitSuccess) && (_hvtsKilled < _limitFail)) or (_eliminate && (_hvtsKilled >= _limitSuccess))
|
||||
} else {
|
||||
if (_capture && (_hvtsKilled >= _limitFail)) then { _result = 1; };
|
||||
|
||||
(_result == 1) or (_capture && (_hvtsInZone >= _limitSuccess) && (_hvtsKilled < _limitFail)) or (_eliminate && (_hvtsKilled >= _limitSuccess))
|
||||
};
|
||||
};
|
||||
|
||||
if (_result == 1) then {
|
||||
{ deleteVehicle _x } forEach _hvts;
|
||||
|
||||
[_taskID, "FAILED"] call BFUNC(taskSetState);
|
||||
|
||||
sleep 1;
|
||||
|
||||
GVAR(TaskStore) call ["notifyParticipants", [_taskID, "warning", "Tasks", format ["Task failed: %1 reputation", _ratingFail]]];
|
||||
GVAR(TaskStore) call ["applyRatingOutcome", [_taskID, _ratingFail]];
|
||||
GVAR(TaskStore) call ["clearTask", [_taskID]];
|
||||
|
||||
if (_endFail) then { ["MissionFail", false] remoteExecCall ["BIS_fnc_endMission", playerSide]; };
|
||||
} else {
|
||||
{ deleteVehicle _x } forEach _hvts;
|
||||
|
||||
private _rewards = createHashMap;
|
||||
_rewards set ["funds", _companyFunds];
|
||||
|
||||
if (_equipmentRewards isNotEqualTo []) then { _rewards set ["equipment", _equipmentRewards]; };
|
||||
if (_supplyRewards isNotEqualTo []) then { _rewards set ["supplies", _supplyRewards]; };
|
||||
if (_weaponRewards isNotEqualTo []) then { _rewards set ["weapons", _weaponRewards]; };
|
||||
if (_vehicleRewards isNotEqualTo []) then { _rewards set ["vehicles", _vehicleRewards]; };
|
||||
if (_specialRewards isNotEqualTo []) then { _rewards set ["special", _specialRewards]; };
|
||||
|
||||
[_taskID, _rewards] call FUNC(handleTaskRewards);
|
||||
[_taskID, "SUCCEEDED"] call BFUNC(taskSetState);
|
||||
|
||||
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 ["applyRatingOutcome", [_taskID, _ratingSuccess]];
|
||||
GVAR(TaskStore) call ["clearTask", [_taskID]];
|
||||
|
||||
if (_endSuccess) then { ["MissionSuccess", true] remoteExecCall ["BIS_fnc_endMission", playerSide]; };
|
||||
};
|
||||
59
arma/server/addons/task/functions/fnc_hvtModule.sqf
Normal file
59
arma/server/addons/task/functions/fnc_hvtModule.sqf
Normal file
@ -0,0 +1,59 @@
|
||||
#include "..\script_component.hpp"
|
||||
|
||||
/*
|
||||
* Author: IDSolutions
|
||||
* Initializes the hvt module
|
||||
*
|
||||
* Arguments:
|
||||
* 0: Logic <OBJECT> - The logic object
|
||||
* 1: Units <ARRAY> - The array of units
|
||||
* 2: Activated <BOOL> - Whether the module is activated
|
||||
*
|
||||
* Return Value:
|
||||
* None
|
||||
*
|
||||
* Example:
|
||||
* [logicObject, [unit1, unit2], true] call forge_server_task_fnc_hvtModule;
|
||||
*
|
||||
* Public: No
|
||||
*/
|
||||
|
||||
params [["_logic", objNull, [objNull]], ["_units", [], [[]]], ["_activated", true, [true]]];
|
||||
|
||||
if !(_activated) exitWith {};
|
||||
|
||||
private _taskID = _logic getVariable ["TaskID", ""];
|
||||
private _limitFail = _logic getVariable ["LimitFail", -1];
|
||||
private _limitSuccess = _logic getVariable ["LimitSuccess", -1];
|
||||
private _extraction = _logic getVariable ["ExtZone", ""];
|
||||
private _companyFunds = _logic getVariable ["CompanyFunds", 0];
|
||||
private _ratingFail = _logic getVariable ["RatingFail", 0];
|
||||
private _ratingSuccess = _logic getVariable ["RatingSuccess", 0];
|
||||
private _capture = _logic getVariable ["CaptureHVT", true];
|
||||
private _eliminate = _logic getVariable ["EliminateHVT", false];
|
||||
private _endSuccess = _logic getVariable ["EndSuccess", false];
|
||||
private _endFail = _logic getVariable ["EndFail", false];
|
||||
private _timeLimit = _logic getVariable ["TimeLimit", 0];
|
||||
|
||||
["INFO", format [
|
||||
"HVT Module Parameters: TaskID: %1, LimitFail: %2, LimitSuccess: %3, ExtractionZone: %4, Funds: %5, RatingFail: %6, RatingSuccess: %7, CaptureHvt: %8, EliminateHvt: %9, EndSuccess: %10, EndFail: %11, Time: %12",
|
||||
_taskID, _limitFail, _limitSuccess, _extraction, _companyFunds, _ratingFail, _ratingSuccess, _capture, _eliminate, _endSuccess, _endFail, _timeLimit
|
||||
]] call EFUNC(common,log);
|
||||
|
||||
private _syncedEntities = synchronizedObjects _logic;
|
||||
["INFO", format ["HVT Module Synced Entities: %1", _syncedEntities]] call EFUNC(common,log);
|
||||
|
||||
{
|
||||
if (!isNull _x && (_x isNotEqualTo str objNull)) then {
|
||||
[_x, _taskID] spawn FUNC(makeHVT);
|
||||
};
|
||||
} forEach _syncedEntities;
|
||||
|
||||
private _params = [_taskID, _limitFail, _limitSuccess, _extraction, _companyFunds, _ratingFail, _ratingSuccess, [_capture, _eliminate], _endSuccess, _endFail];
|
||||
if (_timeLimit != 0) then {
|
||||
_params pushBack _timeLimit;
|
||||
};
|
||||
|
||||
["hvt", _params, 0, ""] spawn FUNC(handler);
|
||||
|
||||
deleteVehicle _logic;
|
||||
545
arma/server/addons/task/functions/fnc_initTaskStore.sqf
Normal file
545
arma/server/addons/task/functions/fnc_initTaskStore.sqf
Normal file
@ -0,0 +1,545 @@
|
||||
#include "..\script_component.hpp"
|
||||
|
||||
/*
|
||||
* Author: IDSolutions
|
||||
* Initializes the task store for task entity tracking, participant
|
||||
* contribution tracking, and task outcome application.
|
||||
*
|
||||
* Arguments:
|
||||
* None
|
||||
*
|
||||
* Return Value:
|
||||
* Task store object [HASHMAP OBJECT]
|
||||
*
|
||||
* Example:
|
||||
* call forge_server_task_fnc_initTaskStore
|
||||
*
|
||||
* Public: No
|
||||
*/
|
||||
|
||||
#pragma hemtt ignore_variables ["_self"]
|
||||
GVAR(TaskStore) = createHashMapObject [[
|
||||
["#type", "TaskStore"],
|
||||
["#create", compileFinal {
|
||||
_self set ["participantRegistry", createHashMap];
|
||||
_self set ["defuseRegistry", createHashMap];
|
||||
_self set ["taskOwnershipRegistry", createHashMap];
|
||||
_self set ["taskStatusRegistry", createHashMap];
|
||||
_self set ["completedTaskStatusRegistry", createHashMap];
|
||||
_self set ["taskCatalogRegistry", createHashMap];
|
||||
_self set ["taskEntityRegistries", createHashMapFromArray [
|
||||
["cargo", createHashMap],
|
||||
["hostages", createHashMap],
|
||||
["hvts", createHashMap],
|
||||
["ieds", createHashMap],
|
||||
["entities", createHashMap],
|
||||
["shooters", createHashMap],
|
||||
["targets", createHashMap]
|
||||
]];
|
||||
}],
|
||||
["bindTaskOwnership", compileFinal {
|
||||
params [["_taskID", "", [""]], ["_requesterUid", "", [""]]];
|
||||
|
||||
private _result = createHashMapFromArray [
|
||||
["success", false],
|
||||
["requesterUid", _requesterUid],
|
||||
["orgID", "default"],
|
||||
["message", ""]
|
||||
];
|
||||
|
||||
if (_taskID isEqualTo "") exitWith {
|
||||
_result set ["message", "Missing task ID."];
|
||||
_result
|
||||
};
|
||||
|
||||
if (_requesterUid isEqualTo "") exitWith {
|
||||
private _taskOwnershipRegistry = _self getOrDefault ["taskOwnershipRegistry", createHashMap];
|
||||
_taskOwnershipRegistry set [_taskID, createHashMapFromArray [
|
||||
["requesterUid", ""],
|
||||
["orgID", "default"]
|
||||
]];
|
||||
_self set ["taskOwnershipRegistry", _taskOwnershipRegistry];
|
||||
|
||||
_result set ["success", true];
|
||||
_result set ["message", "No requester UID provided. Bound task to default organization."];
|
||||
_result
|
||||
};
|
||||
|
||||
private _actor = EGVAR(actor,Registry) getOrDefault [_requesterUid, createHashMap];
|
||||
if (_actor isEqualTo createHashMap) then {
|
||||
_actor = EGVAR(actor,ActorStore) call ["init", [_requesterUid]];
|
||||
};
|
||||
|
||||
if (_actor isEqualTo createHashMap) exitWith {
|
||||
_result set ["message", format ["Failed to load actor for %1.", _requesterUid]];
|
||||
_result
|
||||
};
|
||||
|
||||
private _orgID = _actor getOrDefault ["organization", ""];
|
||||
if (_orgID isEqualTo "") then { _orgID = "default"; };
|
||||
|
||||
private _taskOwnershipRegistry = _self getOrDefault ["taskOwnershipRegistry", createHashMap];
|
||||
_taskOwnershipRegistry set [_taskID, createHashMapFromArray [
|
||||
["requesterUid", _requesterUid],
|
||||
["orgID", _orgID]
|
||||
]];
|
||||
_self set ["taskOwnershipRegistry", _taskOwnershipRegistry];
|
||||
|
||||
private _taskCatalogRegistry = _self getOrDefault ["taskCatalogRegistry", createHashMap];
|
||||
private _catalogEntry = +(_taskCatalogRegistry getOrDefault [_taskID, createHashMap]);
|
||||
if (_catalogEntry isNotEqualTo createHashMap) then {
|
||||
_catalogEntry set ["requesterUid", _requesterUid];
|
||||
_catalogEntry set ["orgID", _orgID];
|
||||
_catalogEntry set ["accepted", true];
|
||||
_taskCatalogRegistry set [_taskID, _catalogEntry];
|
||||
_self set ["taskCatalogRegistry", _taskCatalogRegistry];
|
||||
};
|
||||
|
||||
_result set ["success", true];
|
||||
_result set ["orgID", _orgID];
|
||||
_result
|
||||
}],
|
||||
["registerTaskCatalogEntry", compileFinal {
|
||||
params [["_taskID", "", [""]], ["_entry", createHashMap, [createHashMap]]];
|
||||
|
||||
if (_taskID isEqualTo "" || { _entry isEqualTo createHashMap }) exitWith { false };
|
||||
|
||||
private _taskCatalogRegistry = _self getOrDefault ["taskCatalogRegistry", createHashMap];
|
||||
_taskCatalogRegistry set [_taskID, +_entry];
|
||||
_self set ["taskCatalogRegistry", _taskCatalogRegistry];
|
||||
true
|
||||
}],
|
||||
["getActiveTaskCatalog", compileFinal {
|
||||
private _taskCatalogRegistry = _self getOrDefault ["taskCatalogRegistry", createHashMap];
|
||||
private _taskStatusRegistry = _self getOrDefault ["taskStatusRegistry", createHashMap];
|
||||
private _entries = [];
|
||||
|
||||
{
|
||||
if ((_taskStatusRegistry getOrDefault [_x, ""]) isNotEqualTo "active") then { continue; };
|
||||
|
||||
private _entry = +_y;
|
||||
_entry set ["taskID", _x];
|
||||
_entry set ["status", "active"];
|
||||
_entries pushBack _entry;
|
||||
} forEach _taskCatalogRegistry;
|
||||
|
||||
_entries
|
||||
}],
|
||||
["acceptTask", compileFinal {
|
||||
params [["_taskID", "", [""]], ["_requesterUid", "", [""]]];
|
||||
|
||||
private _result = createHashMapFromArray [
|
||||
["success", false],
|
||||
["message", "Unable to accept task."],
|
||||
["entry", createHashMap]
|
||||
];
|
||||
|
||||
if (_taskID isEqualTo "" || { _requesterUid isEqualTo "" }) exitWith {
|
||||
_result set ["message", "Missing task ID or requester UID."];
|
||||
_result
|
||||
};
|
||||
|
||||
if ((_self call ["getTaskStatus", [_taskID]]) isNotEqualTo "active") exitWith {
|
||||
_result set ["message", "Task is no longer active."];
|
||||
_result
|
||||
};
|
||||
|
||||
private _taskCatalogRegistry = _self getOrDefault ["taskCatalogRegistry", createHashMap];
|
||||
private _entry = +(_taskCatalogRegistry getOrDefault [_taskID, createHashMap]);
|
||||
if (_entry isEqualTo createHashMap) exitWith {
|
||||
_result set ["message", "Task does not exist."];
|
||||
_result
|
||||
};
|
||||
|
||||
private _taskOwnershipRegistry = _self getOrDefault ["taskOwnershipRegistry", createHashMap];
|
||||
private _ownership = _taskOwnershipRegistry getOrDefault [_taskID, createHashMap];
|
||||
private _currentRequesterUid = _ownership getOrDefault ["requesterUid", ""];
|
||||
|
||||
if (_currentRequesterUid isNotEqualTo "" && { _currentRequesterUid isNotEqualTo _requesterUid }) exitWith {
|
||||
_result set ["message", "Task has already been accepted."];
|
||||
_result set ["entry", _entry];
|
||||
_result
|
||||
};
|
||||
|
||||
private _bindResult = _self call ["bindTaskOwnership", [_taskID, _requesterUid]];
|
||||
if !(_bindResult getOrDefault ["success", false]) exitWith {
|
||||
_result set ["message", _bindResult getOrDefault ["message", "Failed to bind task ownership."]];
|
||||
_result
|
||||
};
|
||||
|
||||
private _updatedTaskCatalogRegistry = _self getOrDefault ["taskCatalogRegistry", createHashMap];
|
||||
private _updatedEntry = +(_updatedTaskCatalogRegistry getOrDefault [_taskID, _entry]);
|
||||
_updatedEntry set ["accepted", true];
|
||||
_updatedEntry set ["requesterUid", _requesterUid];
|
||||
_updatedEntry set ["orgID", _bindResult getOrDefault ["orgID", "default"]];
|
||||
_updatedTaskCatalogRegistry set [_taskID, _updatedEntry];
|
||||
_self set ["taskCatalogRegistry", _updatedTaskCatalogRegistry];
|
||||
|
||||
_result set ["success", true];
|
||||
_result set ["message", "Task accepted."];
|
||||
_result set ["entry", _updatedEntry];
|
||||
_result
|
||||
}],
|
||||
["setTaskStatus", compileFinal {
|
||||
params [["_taskID", "", [""]], ["_status", "", [""]]];
|
||||
|
||||
if (_taskID isEqualTo "" || { _status isEqualTo "" }) exitWith { false };
|
||||
|
||||
private _taskStatusRegistry = _self getOrDefault ["taskStatusRegistry", createHashMap];
|
||||
private _completedTaskStatusRegistry = _self getOrDefault ["completedTaskStatusRegistry", createHashMap];
|
||||
_taskStatusRegistry set [_taskID, _status];
|
||||
if (_status in ["succeeded", "failed"]) then {
|
||||
_completedTaskStatusRegistry set [_taskID, _status];
|
||||
} else {
|
||||
_completedTaskStatusRegistry deleteAt _taskID;
|
||||
};
|
||||
_self set ["taskStatusRegistry", _taskStatusRegistry];
|
||||
_self set ["completedTaskStatusRegistry", _completedTaskStatusRegistry];
|
||||
true
|
||||
}],
|
||||
["getTaskStatus", compileFinal {
|
||||
params [["_taskID", "", [""]]];
|
||||
|
||||
if (_taskID isEqualTo "") exitWith { "" };
|
||||
|
||||
private _taskStatusRegistry = _self getOrDefault ["taskStatusRegistry", createHashMap];
|
||||
private _status = _taskStatusRegistry getOrDefault [_taskID, ""];
|
||||
if (_status isNotEqualTo "") exitWith { _status };
|
||||
|
||||
private _completedTaskStatusRegistry = _self getOrDefault ["completedTaskStatusRegistry", createHashMap];
|
||||
_completedTaskStatusRegistry getOrDefault [_taskID, ""]
|
||||
}],
|
||||
["clearTaskStatus", compileFinal {
|
||||
params [["_taskID", "", [""]]];
|
||||
|
||||
if (_taskID isEqualTo "") exitWith { false };
|
||||
|
||||
private _taskStatusRegistry = _self getOrDefault ["taskStatusRegistry", createHashMap];
|
||||
private _completedTaskStatusRegistry = _self getOrDefault ["completedTaskStatusRegistry", createHashMap];
|
||||
_taskStatusRegistry deleteAt _taskID;
|
||||
_completedTaskStatusRegistry deleteAt _taskID;
|
||||
_self set ["taskStatusRegistry", _taskStatusRegistry];
|
||||
_self set ["completedTaskStatusRegistry", _completedTaskStatusRegistry];
|
||||
true
|
||||
}],
|
||||
["registerTaskEntity", compileFinal {
|
||||
params [["_registryKey", "", [""]], ["_taskID", "", [""]], ["_entity", objNull, [objNull]]];
|
||||
|
||||
if (_registryKey isEqualTo "" || { _taskID isEqualTo "" } || { isNull _entity }) exitWith { false };
|
||||
|
||||
private _taskEntityRegistries = _self getOrDefault ["taskEntityRegistries", createHashMap];
|
||||
private _registry = +(_taskEntityRegistries getOrDefault [_registryKey, createHashMap]);
|
||||
private _entities = +(_registry getOrDefault [_taskID, []]);
|
||||
_entities pushBackUnique _entity;
|
||||
_registry set [_taskID, _entities];
|
||||
_taskEntityRegistries set [_registryKey, _registry];
|
||||
_self set ["taskEntityRegistries", _taskEntityRegistries];
|
||||
|
||||
true
|
||||
}],
|
||||
["getTaskEntities", compileFinal {
|
||||
params [["_registryKey", "", [""]], ["_taskID", "", [""]]];
|
||||
|
||||
if (_registryKey isEqualTo "" || { _taskID isEqualTo "" }) exitWith { [] };
|
||||
|
||||
private _taskEntityRegistries = _self getOrDefault ["taskEntityRegistries", createHashMap];
|
||||
private _registry = _taskEntityRegistries getOrDefault [_registryKey, createHashMap];
|
||||
|
||||
+(_registry getOrDefault [_taskID, []])
|
||||
}],
|
||||
["clearTaskEntities", compileFinal {
|
||||
params [["_taskID", "", [""]]];
|
||||
|
||||
if (_taskID isEqualTo "") exitWith { false };
|
||||
|
||||
private _taskEntityRegistries = _self getOrDefault ["taskEntityRegistries", createHashMap];
|
||||
|
||||
{
|
||||
private _registry = +_y;
|
||||
_registry deleteAt _taskID;
|
||||
_taskEntityRegistries set [_x, _registry];
|
||||
} forEach _taskEntityRegistries;
|
||||
|
||||
_self set ["taskEntityRegistries", _taskEntityRegistries];
|
||||
true
|
||||
}],
|
||||
["trackParticipants", compileFinal {
|
||||
params [["_taskID", "", [""]], ["_entities", [], [[]]], ["_marker", "", [""]], ["_radius", 300, [0]]];
|
||||
|
||||
if (_taskID isEqualTo "") exitWith { createHashMap };
|
||||
|
||||
private _participantRegistry = _self getOrDefault ["participantRegistry", createHashMap];
|
||||
private _participantSnapshots = +(_participantRegistry getOrDefault [_taskID, createHashMap]);
|
||||
private _activePlayers = allPlayers select {
|
||||
alive _x
|
||||
&& { side group _x isEqualTo west }
|
||||
};
|
||||
|
||||
if (_marker isNotEqualTo "" && { markerShape _marker in ["RECTANGLE", "ELLIPSE"] }) then {
|
||||
{
|
||||
private _uid = getPlayerUID _x;
|
||||
if (_uid isNotEqualTo "" && { _x inArea _marker }) then {
|
||||
if !(_uid in _participantSnapshots) then {
|
||||
_participantSnapshots set [_uid, createHashMapFromArray [
|
||||
["startRating", rating _x]
|
||||
]];
|
||||
};
|
||||
};
|
||||
} forEach _activePlayers;
|
||||
};
|
||||
|
||||
if (_radius > 0 && { _entities isNotEqualTo [] }) then {
|
||||
{
|
||||
private _entity = _x;
|
||||
if (isNull _entity) then { continue; };
|
||||
|
||||
{
|
||||
private _uid = getPlayerUID _x;
|
||||
if (_uid isNotEqualTo "" && { (_x distance2D _entity) <= _radius }) then {
|
||||
if !(_uid in _participantSnapshots) then {
|
||||
_participantSnapshots set [_uid, createHashMapFromArray [
|
||||
["startRating", rating _x]
|
||||
]];
|
||||
};
|
||||
};
|
||||
} forEach _activePlayers;
|
||||
} forEach _entities;
|
||||
};
|
||||
|
||||
_participantRegistry set [_taskID, _participantSnapshots];
|
||||
_self set ["participantRegistry", _participantRegistry];
|
||||
|
||||
_participantSnapshots
|
||||
}],
|
||||
["resolveRewardContext", compileFinal {
|
||||
params [["_taskID", "", [""]]];
|
||||
|
||||
private _result = createHashMapFromArray [
|
||||
["requesterUid", ""],
|
||||
["orgID", ""],
|
||||
["memberUids", []]
|
||||
];
|
||||
|
||||
if (_taskID isEqualTo "") exitWith { _result };
|
||||
|
||||
private _taskOwnershipRegistry = _self getOrDefault ["taskOwnershipRegistry", createHashMap];
|
||||
private _ownership = _taskOwnershipRegistry getOrDefault [_taskID, createHashMap];
|
||||
if (_ownership isEqualTo createHashMap) exitWith { _result };
|
||||
|
||||
private _requesterUid = _ownership getOrDefault ["requesterUid", ""];
|
||||
private _resolvedOrgID = _ownership getOrDefault ["orgID", ""];
|
||||
if (_resolvedOrgID isEqualTo "") exitWith { _result };
|
||||
|
||||
private _org = EGVAR(org,Registry) getOrDefault [_resolvedOrgID, createHashMap];
|
||||
if (_org isEqualTo createHashMap) then {
|
||||
_org = EGVAR(org,OrgStore) call ["loadById", [_resolvedOrgID]];
|
||||
};
|
||||
|
||||
private _memberUids = [];
|
||||
if (_org isNotEqualTo createHashMap) then {
|
||||
_memberUids = EGVAR(org,OrgTreasuryService) call ["resolveOrgMemberUids", [_org, _requesterUid]];
|
||||
};
|
||||
|
||||
_result set ["requesterUid", _requesterUid];
|
||||
_result set ["orgID", _resolvedOrgID];
|
||||
_result set ["memberUids", _memberUids];
|
||||
_result
|
||||
}],
|
||||
["incrementDefuseCount", compileFinal {
|
||||
params [["_taskID", "", [""]]];
|
||||
|
||||
if (_taskID isEqualTo "") exitWith { 0 };
|
||||
|
||||
private _defuseRegistry = _self getOrDefault ["defuseRegistry", createHashMap];
|
||||
private _nextCount = 1 + (_defuseRegistry getOrDefault [_taskID, 0]);
|
||||
_defuseRegistry set [_taskID, _nextCount];
|
||||
_self set ["defuseRegistry", _defuseRegistry];
|
||||
|
||||
_nextCount
|
||||
}],
|
||||
["getDefuseCount", compileFinal {
|
||||
params [["_taskID", "", [""]]];
|
||||
|
||||
if (_taskID isEqualTo "") exitWith { 0 };
|
||||
|
||||
private _defuseRegistry = _self getOrDefault ["defuseRegistry", createHashMap];
|
||||
_defuseRegistry getOrDefault [_taskID, 0]
|
||||
}],
|
||||
["notifyParticipants", compileFinal {
|
||||
params [
|
||||
["_taskID", "", [""]],
|
||||
["_type", "info", [""]],
|
||||
["_title", "Tasks", [""]],
|
||||
["_message", "", [""]]
|
||||
];
|
||||
|
||||
if (_taskID isEqualTo "" || { _message isEqualTo "" }) exitWith { false };
|
||||
|
||||
private _participantRegistry = _self getOrDefault ["participantRegistry", createHashMap];
|
||||
private _participantSnapshots = +(_participantRegistry getOrDefault [_taskID, createHashMap]);
|
||||
if (_participantSnapshots isEqualTo createHashMap) exitWith { false };
|
||||
|
||||
{
|
||||
private _player = [_x] call EFUNC(common,getPlayer);
|
||||
if (isNull _player) then { continue; };
|
||||
[CRPC(notifications,recieveNotification), [_type, _title, _message], _player] call CFUNC(targetEvent);
|
||||
} forEach (keys _participantSnapshots);
|
||||
|
||||
true
|
||||
}],
|
||||
["clearTask", compileFinal {
|
||||
params [["_taskID", "", [""]]];
|
||||
|
||||
if (_taskID isEqualTo "") exitWith { false };
|
||||
|
||||
private _participantRegistry = _self getOrDefault ["participantRegistry", createHashMap];
|
||||
private _defuseRegistry = _self getOrDefault ["defuseRegistry", createHashMap];
|
||||
private _taskOwnershipRegistry = _self getOrDefault ["taskOwnershipRegistry", createHashMap];
|
||||
private _taskStatusRegistry = _self getOrDefault ["taskStatusRegistry", createHashMap];
|
||||
private _taskCatalogRegistry = _self getOrDefault ["taskCatalogRegistry", createHashMap];
|
||||
|
||||
_participantRegistry deleteAt _taskID;
|
||||
_defuseRegistry deleteAt _taskID;
|
||||
_taskOwnershipRegistry deleteAt _taskID;
|
||||
_taskStatusRegistry deleteAt _taskID;
|
||||
_taskCatalogRegistry deleteAt _taskID;
|
||||
|
||||
_self set ["participantRegistry", _participantRegistry];
|
||||
_self set ["defuseRegistry", _defuseRegistry];
|
||||
_self set ["taskOwnershipRegistry", _taskOwnershipRegistry];
|
||||
_self set ["taskStatusRegistry", _taskStatusRegistry];
|
||||
_self set ["taskCatalogRegistry", _taskCatalogRegistry];
|
||||
_self call ["clearTaskEntities", [_taskID]];
|
||||
true
|
||||
}],
|
||||
["applyRatingOutcome", compileFinal {
|
||||
params [["_taskID", "", [""]], ["_delta", 0, [0]]];
|
||||
|
||||
private _result = createHashMapFromArray [
|
||||
["participantUids", []],
|
||||
["orgIds", []],
|
||||
["contributions", createHashMap]
|
||||
];
|
||||
|
||||
if (_taskID isEqualTo "" || { _delta isEqualTo 0 }) exitWith { _result };
|
||||
|
||||
private _participantRegistry = _self getOrDefault ["participantRegistry", createHashMap];
|
||||
private _participantSnapshots = +(_participantRegistry getOrDefault [_taskID, createHashMap]);
|
||||
if (_participantSnapshots isEqualTo createHashMap) exitWith { _result };
|
||||
|
||||
private _participantUids = keys _participantSnapshots;
|
||||
if (_participantUids isEqualTo []) exitWith { _result };
|
||||
|
||||
private _orgIds = [];
|
||||
private _contributions = createHashMap;
|
||||
private _totalContribution = 0;
|
||||
|
||||
{
|
||||
private _uid = _x;
|
||||
private _player = [_uid] call EFUNC(common,getPlayer);
|
||||
if (isNull _player) then { continue; };
|
||||
|
||||
private _snapshot = _participantSnapshots getOrDefault [_uid, createHashMap];
|
||||
private _startRating = _snapshot getOrDefault ["startRating", rating _player];
|
||||
private _ratingDelta = (rating _player) - _startRating;
|
||||
private _contribution = _ratingDelta max 0;
|
||||
|
||||
if (_delta < 0) then {
|
||||
_contribution = (0 - _ratingDelta) max 0;
|
||||
};
|
||||
|
||||
if (_contribution <= 0) then { continue; };
|
||||
|
||||
_contributions set [_uid, _contribution];
|
||||
_totalContribution = _totalContribution + _contribution;
|
||||
} forEach _participantUids;
|
||||
|
||||
if (_totalContribution <= 0) exitWith {
|
||||
_self call ["clearTask", [_taskID]];
|
||||
_result
|
||||
};
|
||||
|
||||
{
|
||||
private _uid = _x;
|
||||
private _actor = EGVAR(actor,Registry) getOrDefault [_uid, createHashMap];
|
||||
if (_actor isEqualTo createHashMap) then {
|
||||
_actor = EGVAR(actor,ActorStore) call ["init", [_uid]];
|
||||
};
|
||||
|
||||
private _orgID = _actor getOrDefault ["organization", ""];
|
||||
if (_orgID isNotEqualTo "") then {
|
||||
_orgIds pushBackUnique _orgID;
|
||||
};
|
||||
|
||||
if (_delta > 0) then {
|
||||
private _contribution = _contributions getOrDefault [_uid, 0];
|
||||
if (_contribution <= 0) then { continue; };
|
||||
|
||||
private _account = EGVAR(bank,Registry) getOrDefault [_uid, createHashMap];
|
||||
if (_account isEqualTo createHashMap) then {
|
||||
_account = EGVAR(bank,BankStore) call ["init", [_uid]];
|
||||
};
|
||||
|
||||
if (_account isNotEqualTo createHashMap) then {
|
||||
private _earnings = _account getOrDefault ["earnings", 0];
|
||||
private _earningsDelta = round ((_delta * _contribution) / _totalContribution);
|
||||
if (_earningsDelta <= 0) then { continue; };
|
||||
|
||||
private _patch = EGVAR(bank,BankStore) call [
|
||||
"mset",
|
||||
[
|
||||
EGVAR(bank,Registry),
|
||||
"bank:update",
|
||||
_uid,
|
||||
createHashMapFromArray [["earnings", (_earnings + _earningsDelta)]],
|
||||
false
|
||||
]
|
||||
];
|
||||
|
||||
EGVAR(bank,BankMessenger) call ["sendAccountSync", [_uid, _patch]];
|
||||
};
|
||||
};
|
||||
} forEach _participantUids;
|
||||
|
||||
private _rewardContext = _self call ["resolveRewardContext", [_taskID]];
|
||||
private _ownerOrgID = _rewardContext getOrDefault ["orgID", ""];
|
||||
if (_ownerOrgID isNotEqualTo "") then {
|
||||
private _org = EGVAR(org,Registry) getOrDefault [_ownerOrgID, createHashMap];
|
||||
if (_org isEqualTo createHashMap) then {
|
||||
_org = EGVAR(org,OrgStore) call ["loadById", [_ownerOrgID]];
|
||||
};
|
||||
|
||||
if (_org isNotEqualTo createHashMap) then {
|
||||
private _reputation = _org getOrDefault ["reputation", 0];
|
||||
private _nextReputation = round (_reputation + _delta);
|
||||
private _patch = EGVAR(org,OrgStore) call [
|
||||
"set",
|
||||
[
|
||||
EGVAR(org,Registry),
|
||||
"org:update",
|
||||
_ownerOrgID,
|
||||
"reputation",
|
||||
_nextReputation,
|
||||
false
|
||||
]
|
||||
];
|
||||
|
||||
private _memberUids = _rewardContext getOrDefault ["memberUids", []];
|
||||
{
|
||||
private _player = [_x] call EFUNC(common,getPlayer);
|
||||
if (isNull _player) then { continue; };
|
||||
[CRPC(org,responseSyncOrg), [_patch], _player] call CFUNC(targetEvent);
|
||||
} forEach _memberUids;
|
||||
|
||||
_orgIds = [_ownerOrgID];
|
||||
};
|
||||
};
|
||||
|
||||
_result set ["participantUids", _participantUids];
|
||||
_result set ["orgIds", _orgIds];
|
||||
_result set ["contributions", _contributions];
|
||||
_result
|
||||
}]
|
||||
]];
|
||||
|
||||
GVAR(TaskStore)
|
||||
41
arma/server/addons/task/functions/fnc_makeCargo.sqf
Normal file
41
arma/server/addons/task/functions/fnc_makeCargo.sqf
Normal file
@ -0,0 +1,41 @@
|
||||
#include "..\script_component.hpp"
|
||||
|
||||
/*
|
||||
* Author: IDSolutions
|
||||
* Assigns cargo to a task for delivery
|
||||
*
|
||||
* Arguments:
|
||||
* 0: Object to convert to delivery cargo <OBJECT>
|
||||
* 1: Task ID to assign the cargo to <STRING>
|
||||
*
|
||||
* Return Value:
|
||||
* None
|
||||
*
|
||||
* Example:
|
||||
* [_cargoObject, "delivery_1"] call forge_server_task_fnc_makeCargo;
|
||||
*
|
||||
* Public: Yes
|
||||
*/
|
||||
|
||||
params [["_cargo", objNull, [objNull]], ["_taskID", "", [""]]];
|
||||
|
||||
["INFO", format ["Make Cargo: %1", _this]] call EFUNC(common,log);
|
||||
|
||||
if (isNull _cargo) exitWith { ["ERROR", "Attempt to create cargo from null object"] call EFUNC(common,log); };
|
||||
if (_taskID == "") exitWith { ["ERROR", "No task ID provided for cargo"] call EFUNC(common,log); };
|
||||
|
||||
SETPVAR(_cargo,assignedTask,_taskID);
|
||||
GVAR(TaskStore) call ["registerTaskEntity", ["cargo", _taskID, _cargo]];
|
||||
|
||||
_cargo addEventHandler ["Dammaged", {
|
||||
params ["_unit", "_hitSelection", "_damage", "_hitPartIndex", "_hitPoint", "_shooter", "_projectile"];
|
||||
|
||||
if (damage _unit >= 0.7) then {
|
||||
private _taskID = GETVAR(_unit,assignedTask,"");
|
||||
if (_taskID isEqualTo "") exitWith {};
|
||||
if (_unit getVariable [QGVAR(cargoDamageWarned), false]) exitWith {};
|
||||
|
||||
_unit setVariable [QGVAR(cargoDamageWarned), true];
|
||||
GVAR(TaskStore) call ["notifyParticipants", [_taskID, "warning", "Tasks", format ["Cargo for task %1 has been severely damaged.", _taskID]]];
|
||||
};
|
||||
}];
|
||||
30
arma/server/addons/task/functions/fnc_makeHVT.sqf
Normal file
30
arma/server/addons/task/functions/fnc_makeHVT.sqf
Normal file
@ -0,0 +1,30 @@
|
||||
#include "..\script_component.hpp"
|
||||
|
||||
/*
|
||||
* Author: IDSolutions
|
||||
* Assigns an AI unit to a task as a hvt
|
||||
*
|
||||
* Arguments:
|
||||
* 0: The AI unit <OBJECT>
|
||||
* 1: ID of the task <STRING>
|
||||
*
|
||||
* Return Value:
|
||||
* None
|
||||
*
|
||||
* Example:
|
||||
* [this, "task_name"] spawn forge_server_task_fnc_makeHVT;
|
||||
*
|
||||
* Public: Yes
|
||||
*/
|
||||
|
||||
params [["_entity", objNull, [objNull, grpNull]], ["_taskID", "", [""]]];
|
||||
|
||||
if (isNull _entity) exitWith { ["ERROR", "Attempt to create entity from null object"] call EFUNC(common,log); };
|
||||
if (_taskID == "") exitWith { ["ERROR", "No task ID provided for entity"] call EFUNC(common,log); };
|
||||
|
||||
["INFO", format ["Make HVT: %1", _this]] call EFUNC(common,log);
|
||||
|
||||
SETVAR(_entity,assignedTask,_taskID);
|
||||
GVAR(TaskStore) call ["registerTaskEntity", ["hvts", _taskID, _entity]];
|
||||
|
||||
if (alive _entity) then { [_entity, "hvt"] spawn FUNC(heartBeat); };
|
||||
30
arma/server/addons/task/functions/fnc_makeHostage.sqf
Normal file
30
arma/server/addons/task/functions/fnc_makeHostage.sqf
Normal file
@ -0,0 +1,30 @@
|
||||
#include "..\script_component.hpp"
|
||||
|
||||
/*
|
||||
* Author: IDSolutions
|
||||
* Assigns an AI unit to a task as a hostage
|
||||
*
|
||||
* Arguments:
|
||||
* 0: The AI unit <OBJECT>
|
||||
* 1: ID of the task <STRING>
|
||||
*
|
||||
* Return Value:
|
||||
* None
|
||||
*
|
||||
* Example:
|
||||
* [this, "task_name"] spawn forge_server_task_fnc_makeHostage;
|
||||
*
|
||||
* Public: Yes
|
||||
*/
|
||||
|
||||
params [["_entity", objNull, [objNull, grpNull]], ["_taskID", "", [""]]];
|
||||
|
||||
if (isNull _entity) exitWith { ["ERROR", "Attempt to create entity from null object"] call EFUNC(common,log); };
|
||||
if (_taskID == "") exitWith { ["ERROR", "No task ID provided for entity"] call EFUNC(common,log); };
|
||||
|
||||
["INFO", format ["Make Hostage: %1", _this]] call EFUNC(common,log);
|
||||
|
||||
SETVAR(_entity,assignedTask,_taskID);
|
||||
GVAR(TaskStore) call ["registerTaskEntity", ["hostages", _taskID, _entity]];
|
||||
|
||||
if (alive _entity) then { [_entity, "hostage"] spawn FUNC(heartBeat); };
|
||||
32
arma/server/addons/task/functions/fnc_makeIED.sqf
Normal file
32
arma/server/addons/task/functions/fnc_makeIED.sqf
Normal file
@ -0,0 +1,32 @@
|
||||
#include "..\script_component.hpp"
|
||||
|
||||
/*
|
||||
* Author: IDSolutions
|
||||
* Assigns an IED to a task and starts countdown timer
|
||||
*
|
||||
* Arguments:
|
||||
* 0: The object <OBJECT>
|
||||
* 1: ID of the task <STRING>
|
||||
* 2: The Countdown Timer <NUMBER>
|
||||
*
|
||||
* Return Value:
|
||||
* None
|
||||
*
|
||||
* Example:
|
||||
* [this, "task_name", 30] spawn forge_server_task_fnc_makeIED;
|
||||
*
|
||||
* Public: Yes
|
||||
*/
|
||||
|
||||
params [["_entity", objNull, [objNull]], ["_taskID", "", [""]], ["_time", 0, [0]]];
|
||||
|
||||
if (isNull _entity) exitWith { ["ERROR", "Attempt to create entity from null object"] call EFUNC(common,log); };
|
||||
if (_taskID == "") exitWith { ["ERROR", "No task ID provided for entity"] call EFUNC(common,log); };
|
||||
if (_time < 0) exitWith { ["ERROR", "Invalid time provided for IED"] call EFUNC(common,log); };
|
||||
|
||||
["INFO", format ["Make IED: %1", _this]] call EFUNC(common,log);
|
||||
|
||||
SETVAR(_entity,assignedTask,_taskID);
|
||||
GVAR(TaskStore) call ["registerTaskEntity", ["ieds", _taskID, _entity]];
|
||||
|
||||
if (alive _entity) then { [_entity, "ied", _time] spawn FUNC(heartBeat); };
|
||||
28
arma/server/addons/task/functions/fnc_makeObject.sqf
Normal file
28
arma/server/addons/task/functions/fnc_makeObject.sqf
Normal file
@ -0,0 +1,28 @@
|
||||
#include "..\script_component.hpp"
|
||||
|
||||
/*
|
||||
* Author: IDSolutions
|
||||
* Assigns an object to a task as a protected target
|
||||
*
|
||||
* Arguments:
|
||||
* 0: The object <OBJECT>
|
||||
* 1: ID of the task <STRING>
|
||||
*
|
||||
* Return Value:
|
||||
* None
|
||||
*
|
||||
* Example:
|
||||
* [this, "task_name"] spawn forge_server_task_fnc_makeObject;
|
||||
*
|
||||
* Public: Yes
|
||||
*/
|
||||
|
||||
params [["_entity", objNull, [objNull]], ["_taskID", "", [""]]];
|
||||
|
||||
if (isNull _entity) exitWith { ["ERROR", "Attempt to create entity from null object"] call EFUNC(common,log); };
|
||||
if (_taskID == "") exitWith { ["ERROR", "No task ID provided for entity"] call EFUNC(common,log); };
|
||||
|
||||
["INFO", format ["Make Object: %1", _this]] call EFUNC(common,log);
|
||||
|
||||
SETPVAR(_entity,assignedTask,_taskID);
|
||||
GVAR(TaskStore) call ["registerTaskEntity", ["entities", _taskID, _entity]];
|
||||
28
arma/server/addons/task/functions/fnc_makeShooter.sqf
Normal file
28
arma/server/addons/task/functions/fnc_makeShooter.sqf
Normal file
@ -0,0 +1,28 @@
|
||||
#include "..\script_component.hpp"
|
||||
|
||||
/*
|
||||
* Author: IDSolutions
|
||||
* Assigns an AI unit to a task as a shooter
|
||||
*
|
||||
* Arguments:
|
||||
* 0: The AI unit <OBJECT>
|
||||
* 1: ID of the task <STRING>
|
||||
*
|
||||
* Return Value:
|
||||
* None
|
||||
*
|
||||
* Example:
|
||||
* [this, "task_name"] spawn forge_server_task_fnc_makeShooter;
|
||||
*
|
||||
* Public: Yes
|
||||
*/
|
||||
|
||||
params [["_entity", objNull, [objNull, grpNull]], ["_taskID", "", [""]]];
|
||||
|
||||
if (isNull _entity) exitWith { ["ERROR", "Attempt to create entity from null object"] call EFUNC(common,log); };
|
||||
if (_taskID == "") exitWith { ["ERROR", "No task ID provided for entity"] call EFUNC(common,log); };
|
||||
|
||||
["INFO", format ["Make Shooter: %1", _this]] call EFUNC(common,log);
|
||||
|
||||
SETVAR(_entity,assignedTask,_taskID);
|
||||
GVAR(TaskStore) call ["registerTaskEntity", ["shooters", _taskID, _entity]];
|
||||
28
arma/server/addons/task/functions/fnc_makeTarget.sqf
Normal file
28
arma/server/addons/task/functions/fnc_makeTarget.sqf
Normal file
@ -0,0 +1,28 @@
|
||||
#include "..\script_component.hpp"
|
||||
|
||||
/*
|
||||
* Author: IDSolutions
|
||||
* Assigns an object to a task as a target
|
||||
*
|
||||
* Arguments:
|
||||
* 0: The object <OBJECT>
|
||||
* 1: ID of the task <STRING>
|
||||
*
|
||||
* Return Value:
|
||||
* None
|
||||
*
|
||||
* Example:
|
||||
* [this, "task_name"] spawn forge_server_task_fnc_makeTarget;
|
||||
*
|
||||
* Public: Yes
|
||||
*/
|
||||
|
||||
params [["_entity", objNull, [objNull, grpNull]], ["_taskID", "", [""]]];
|
||||
|
||||
if (isNull _entity) exitWith { ["ERROR", "Attempt to create entity from null object"] call EFUNC(common,log); };
|
||||
if (_taskID == "") exitWith { ["ERROR", "No task ID provided for entity"] call EFUNC(common,log); };
|
||||
|
||||
["INFO", format ["Make Target: %1", _this]] call EFUNC(common,log);
|
||||
|
||||
SETVAR(_entity,assignedTask,_taskID);
|
||||
GVAR(TaskStore) call ["registerTaskEntity", ["targets", _taskID, _entity]];
|
||||
369
arma/server/addons/task/functions/fnc_missionManager.sqf
Normal file
369
arma/server/addons/task/functions/fnc_missionManager.sqf
Normal file
@ -0,0 +1,369 @@
|
||||
#include "..\script_component.hpp"
|
||||
|
||||
/*
|
||||
* Author: IDSolutions
|
||||
* Manages attack-only dynamic mission generation.
|
||||
*
|
||||
* Arguments:
|
||||
* None
|
||||
*
|
||||
* Return Value:
|
||||
* None
|
||||
*
|
||||
* Example:
|
||||
* [] call forge_server_task_fnc_missionManager
|
||||
*
|
||||
* Public: No
|
||||
*/
|
||||
|
||||
#pragma hemtt ignore_variables ["_self"]
|
||||
GVAR(MissionManagerBaseClass) = compileFinal createHashMapFromArray [
|
||||
["#type", "MissionManagerBaseClass"],
|
||||
["#create", compileFinal {
|
||||
private _missionConfig = missionConfigFile >> "CfgMissions";
|
||||
_self set ["missionConfig", _missionConfig];
|
||||
_self set ["locationsConfig", (_missionConfig >> "Locations")];
|
||||
_self set ["aiGroupsConfig", (_missionConfig >> "AIGroups")];
|
||||
_self set ["attackConfig", (_missionConfig >> "MissionTypes" >> "Attack")];
|
||||
_self set ["maxConcurrentMissions", getNumber (_missionConfig >> "maxConcurrentMissions")];
|
||||
_self set ["missionInterval", getNumber (_missionConfig >> "missionInterval")];
|
||||
_self set ["recentLocationRegistry", createHashMap];
|
||||
_self set ["activeMissionRegistry", createHashMap];
|
||||
}],
|
||||
["getMissionInterval", compileFinal {
|
||||
private _interval = _self getOrDefault ["missionInterval", 300];
|
||||
if (_interval <= 0) then { _interval = 300; };
|
||||
_interval
|
||||
}],
|
||||
["getMaxConcurrentMissions", compileFinal {
|
||||
private _maxConcurrent = _self getOrDefault ["maxConcurrentMissions", 1];
|
||||
if (_maxConcurrent <= 0) then { _maxConcurrent = 1; };
|
||||
_maxConcurrent
|
||||
}],
|
||||
["getLocationReuseCooldown", compileFinal {
|
||||
private _missionConfig = _self getOrDefault ["missionConfig", configNull];
|
||||
private _cooldown = getNumber (_missionConfig >> "locationReuseCooldown");
|
||||
if (_cooldown <= 0) then { _cooldown = 900; };
|
||||
_cooldown
|
||||
}],
|
||||
["getActiveMissionIds", compileFinal {
|
||||
private _activeMissionRegistry = _self getOrDefault ["activeMissionRegistry", createHashMap];
|
||||
keys _activeMissionRegistry
|
||||
}],
|
||||
["getActiveLocationKeys", compileFinal {
|
||||
private _activeMissionRegistry = _self getOrDefault ["activeMissionRegistry", createHashMap];
|
||||
private _locationKeys = [];
|
||||
{
|
||||
private _locationKey = _y getOrDefault ["locationKey", ""];
|
||||
if (_locationKey isNotEqualTo "") then {
|
||||
_locationKeys pushBackUnique _locationKey;
|
||||
};
|
||||
} forEach _activeMissionRegistry;
|
||||
_locationKeys
|
||||
}],
|
||||
["buildAttackSpawnPosition", compileFinal {
|
||||
params [["_locationConfig", configNull, [configNull]]];
|
||||
|
||||
if (isNull _locationConfig) exitWith { [0, 0, 0] };
|
||||
|
||||
private _center = getArray (_locationConfig >> "position");
|
||||
private _radius = getNumber (_locationConfig >> "radius");
|
||||
if (_radius <= 0) exitWith { _center };
|
||||
|
||||
private _spawnPosition = +_center;
|
||||
private _attempts = 0;
|
||||
while { _attempts < 8 } do {
|
||||
private _angle = random 360;
|
||||
private _distance = (_radius * 0.2) + random (_radius * 0.65);
|
||||
private _candidate = [
|
||||
(_center # 0) + ((sin _angle) * _distance),
|
||||
(_center # 1) + ((cos _angle) * _distance),
|
||||
_center param [2, 0]
|
||||
];
|
||||
|
||||
if !(surfaceIsWater _candidate) exitWith {
|
||||
_spawnPosition = _candidate;
|
||||
};
|
||||
|
||||
_attempts = _attempts + 1;
|
||||
};
|
||||
|
||||
_spawnPosition
|
||||
}],
|
||||
["selectAttackLocation", compileFinal {
|
||||
private _locationsConfig = _self getOrDefault ["locationsConfig", configNull];
|
||||
private _locations = [];
|
||||
private _recentLocationRegistry = _self getOrDefault ["recentLocationRegistry", createHashMap];
|
||||
private _activeLocationKeys = _self call ["getActiveLocationKeys", []];
|
||||
private _reuseCooldown = _self call ["getLocationReuseCooldown", []];
|
||||
private _now = serverTime;
|
||||
|
||||
{
|
||||
private _locationKey = configName _x;
|
||||
private _lastUsed = _recentLocationRegistry getOrDefault [_locationKey, -1];
|
||||
private _isCoolingDown = (_lastUsed >= 0) && { (_now - _lastUsed) < _reuseCooldown };
|
||||
|
||||
if (
|
||||
"attack" in getArray (_x >> "suitable")
|
||||
&& { !(_locationKey in _activeLocationKeys) }
|
||||
&& { !_isCoolingDown }
|
||||
) then {
|
||||
_locations pushBack _x;
|
||||
};
|
||||
} forEach ("true" configClasses _locationsConfig);
|
||||
|
||||
if (_locations isEqualTo []) then {
|
||||
{
|
||||
if ("attack" in getArray (_x >> "suitable") && { !(configName _x in _activeLocationKeys) }) then {
|
||||
_locations pushBack _x;
|
||||
};
|
||||
} forEach ("true" configClasses _locationsConfig);
|
||||
};
|
||||
|
||||
if (_locations isEqualTo []) exitWith { createHashMap };
|
||||
|
||||
private _location = selectRandom _locations;
|
||||
createHashMapFromArray [
|
||||
["config", _location],
|
||||
["key", configName _location],
|
||||
["position", _self call ["buildAttackSpawnPosition", [_location]]]
|
||||
]
|
||||
}],
|
||||
["spawnAttackGroup", compileFinal {
|
||||
params [["_position", [0, 0, 0], [[]]]];
|
||||
|
||||
private _aiGroupsConfig = _self getOrDefault ["aiGroupsConfig", configNull];
|
||||
private _attackConfig = _self getOrDefault ["attackConfig", configNull];
|
||||
private _groups = [];
|
||||
{
|
||||
if ("attack" in getArray (_x >> "suitable")) then {
|
||||
_groups pushBack _x;
|
||||
};
|
||||
} forEach ("true" configClasses _aiGroupsConfig);
|
||||
|
||||
if (_groups isEqualTo []) exitWith { grpNull };
|
||||
|
||||
private _groupConfig = selectRandom _groups;
|
||||
private _side = getText (_groupConfig >> "side");
|
||||
private _group = createGroup (call compile _side);
|
||||
private _minUnits = getNumber (_attackConfig >> "minUnits");
|
||||
private _maxUnits = getNumber (_attackConfig >> "maxUnits");
|
||||
if (_minUnits <= 0) then { _minUnits = 4; };
|
||||
if (_maxUnits < _minUnits) then { _maxUnits = _minUnits; };
|
||||
private _targetUnitCount = floor random [ _minUnits, ceil ((_minUnits + _maxUnits) / 2), _maxUnits + 1 ];
|
||||
|
||||
private _unitPool = [];
|
||||
{
|
||||
if ((getText (_x >> "side")) isNotEqualTo _side) then { continue; };
|
||||
|
||||
{
|
||||
_unitPool pushBack createHashMapFromArray [
|
||||
["vehicle", getText (_x >> "vehicle")],
|
||||
["rank", getText (_x >> "rank")],
|
||||
["position", getArray (_x >> "position")]
|
||||
];
|
||||
} forEach ("true" configClasses (_x >> "Units"));
|
||||
} forEach _groups;
|
||||
|
||||
if (_unitPool isEqualTo []) exitWith {
|
||||
deleteGroup _group;
|
||||
grpNull
|
||||
};
|
||||
|
||||
private _leaderPool = _unitPool select {
|
||||
toUpperANSI (_x getOrDefault ["rank", "PRIVATE"]) in ["SERGEANT", "LIEUTENANT", "CAPTAIN", "MAJOR", "COLONEL"]
|
||||
};
|
||||
if (_leaderPool isEqualTo []) then { _leaderPool = +_unitPool; };
|
||||
|
||||
private _spawnDefs = [selectRandom _leaderPool];
|
||||
for "_i" from 1 to (_targetUnitCount - 1) do {
|
||||
_spawnDefs pushBack (selectRandom _unitPool);
|
||||
};
|
||||
|
||||
{
|
||||
private _unitClass = _x getOrDefault ["vehicle", ""];
|
||||
if (_unitClass isEqualTo "") then { continue; };
|
||||
|
||||
private _unitOffset = +(_x getOrDefault ["position", [0, 0, 0]]);
|
||||
if (count _unitOffset < 3) then { _unitOffset resize 3; };
|
||||
_unitOffset set [0, (_unitOffset # 0) + (random 6 - 3)];
|
||||
_unitOffset set [1, (_unitOffset # 1) + (random 6 - 3)];
|
||||
|
||||
private _unit = _group createUnit [_unitClass, _position vectorAdd _unitOffset, [], 0, "NONE"];
|
||||
_unit setRank (_x getOrDefault ["rank", "PRIVATE"]);
|
||||
} forEach _spawnDefs;
|
||||
|
||||
_group
|
||||
}],
|
||||
["rollRewards", compileFinal {
|
||||
private _attackConfig = _self getOrDefault ["attackConfig", configNull];
|
||||
private _equipmentRewards = [];
|
||||
private _supplyRewards = [];
|
||||
private _weaponRewards = [];
|
||||
private _vehicleRewards = [];
|
||||
private _specialRewards = [];
|
||||
|
||||
{
|
||||
private _category = _x;
|
||||
{
|
||||
_x params ["_item", "_chance"];
|
||||
if (random 1 < _chance) then {
|
||||
switch (_category) do {
|
||||
case "equipment": { _equipmentRewards pushBack _item; };
|
||||
case "supplies": { _supplyRewards pushBack _item; };
|
||||
case "weapons": { _weaponRewards pushBack _item; };
|
||||
case "vehicles": { _vehicleRewards pushBack _item; };
|
||||
case "special": { _specialRewards pushBack _item; };
|
||||
};
|
||||
};
|
||||
} forEach (getArray (_attackConfig >> "Rewards" >> _category));
|
||||
} forEach ["equipment", "supplies", "weapons", "vehicles", "special"];
|
||||
|
||||
createHashMapFromArray [
|
||||
["equipment", _equipmentRewards],
|
||||
["supplies", _supplyRewards],
|
||||
["weapons", _weaponRewards],
|
||||
["vehicles", _vehicleRewards],
|
||||
["special", _specialRewards]
|
||||
]
|
||||
}],
|
||||
["createAttackTask", compileFinal {
|
||||
params [
|
||||
["_taskID", "", [""]],
|
||||
["_position", [0, 0, 0], [[]]],
|
||||
["_locationConfig", configNull, [configNull]]
|
||||
];
|
||||
|
||||
if (_taskID isEqualTo "" || { isNull _locationConfig }) exitWith { false };
|
||||
|
||||
private _locationKey = configName _locationConfig;
|
||||
private _locationType = getText (_locationConfig >> "type");
|
||||
if (_locationType isEqualTo "") then { _locationType = "area"; };
|
||||
|
||||
[
|
||||
west,
|
||||
_taskID,
|
||||
[
|
||||
format ["Eliminate hostile forces operating near %1.", _locationKey],
|
||||
format ["Attack: %1", _locationKey],
|
||||
_locationType
|
||||
],
|
||||
_position,
|
||||
"CREATED",
|
||||
1,
|
||||
true,
|
||||
"attack"
|
||||
] call BFUNC(taskCreate);
|
||||
|
||||
true
|
||||
}],
|
||||
["startAttackMission", compileFinal {
|
||||
private _attackConfig = _self getOrDefault ["attackConfig", configNull];
|
||||
private _locationData = _self call ["selectAttackLocation"];
|
||||
if (_locationData isEqualTo createHashMap) exitWith { "" };
|
||||
|
||||
private _location = _locationData getOrDefault ["config", configNull];
|
||||
private _locationKey = _locationData getOrDefault ["key", ""];
|
||||
private _position = _locationData getOrDefault ["position", [0, 0, 0]];
|
||||
private _group = _self call ["spawnAttackGroup", [_position]];
|
||||
if (isNull _group) exitWith { "" };
|
||||
|
||||
private _units = units _group;
|
||||
if (_units isEqualTo []) exitWith {
|
||||
deleteGroup _group;
|
||||
""
|
||||
};
|
||||
|
||||
private _taskID = format ["task_attack_%1", round (diag_tickTime * 1000)];
|
||||
{
|
||||
[_x, _taskID] call FUNC(makeTarget);
|
||||
} forEach _units;
|
||||
|
||||
_self call ["createAttackTask", [_taskID, _position, _location]];
|
||||
GVAR(TaskStore) call ["registerTaskCatalogEntry", [_taskID, createHashMapFromArray [
|
||||
["type", "attack"],
|
||||
["title", format ["Attack: %1", _locationKey]],
|
||||
["description", format ["Eliminate hostile forces operating near %1.", _locationKey]],
|
||||
["position", _position],
|
||||
["locationKey", _locationKey],
|
||||
["accepted", false],
|
||||
["requesterUid", ""],
|
||||
["orgID", "default"],
|
||||
["source", "mission_manager"]
|
||||
]]];
|
||||
|
||||
private _rewardRange = getArray (_attackConfig >> "Rewards" >> "money");
|
||||
private _reputationRange = getArray (_attackConfig >> "Rewards" >> "reputation");
|
||||
private _penaltyRange = getArray (_attackConfig >> "penalty");
|
||||
private _timeRange = getArray (_attackConfig >> "timeLimit");
|
||||
private _rewards = _self call ["rollRewards"];
|
||||
|
||||
private _params = [
|
||||
_taskID,
|
||||
0,
|
||||
count _units,
|
||||
_rewardRange call BFUNC(randomNum),
|
||||
_penaltyRange call BFUNC(randomNum),
|
||||
_reputationRange call BFUNC(randomNum),
|
||||
false,
|
||||
false,
|
||||
_timeRange call BFUNC(randomNum),
|
||||
_rewards get "equipment",
|
||||
_rewards get "supplies",
|
||||
_rewards get "weapons",
|
||||
_rewards get "vehicles",
|
||||
_rewards get "special"
|
||||
];
|
||||
|
||||
private _activeMissionRegistry = _self getOrDefault ["activeMissionRegistry", createHashMap];
|
||||
_activeMissionRegistry set [_taskID, createHashMapFromArray [
|
||||
["locationKey", _locationKey],
|
||||
["startedAt", serverTime]
|
||||
]];
|
||||
_self set ["activeMissionRegistry", _activeMissionRegistry];
|
||||
|
||||
["attack", _params, 0, ""] spawn FUNC(handler);
|
||||
_taskID
|
||||
}],
|
||||
["completeMission", compileFinal {
|
||||
params [["_taskID", "", [""]]];
|
||||
|
||||
if (_taskID isEqualTo "") exitWith { false };
|
||||
|
||||
private _activeMissionRegistry = _self getOrDefault ["activeMissionRegistry", createHashMap];
|
||||
private _missionRecord = _activeMissionRegistry getOrDefault [_taskID, createHashMap];
|
||||
private _locationKey = _missionRecord getOrDefault ["locationKey", ""];
|
||||
|
||||
_activeMissionRegistry deleteAt _taskID;
|
||||
_self set ["activeMissionRegistry", _activeMissionRegistry];
|
||||
|
||||
if (_locationKey isNotEqualTo "") then {
|
||||
private _recentLocationRegistry = _self getOrDefault ["recentLocationRegistry", createHashMap];
|
||||
_recentLocationRegistry set [_locationKey, serverTime];
|
||||
_self set ["recentLocationRegistry", _recentLocationRegistry];
|
||||
};
|
||||
|
||||
true
|
||||
}]
|
||||
];
|
||||
|
||||
GVAR(MissionManager) = createHashMapObject [GVAR(MissionManagerBaseClass)];
|
||||
|
||||
[{
|
||||
{
|
||||
private _status = GVAR(TaskStore) call ["getTaskStatus", [_x]];
|
||||
if (_status in ["succeeded", "failed"]) then {
|
||||
GVAR(MissionManager) call ["completeMission", [_x]];
|
||||
GVAR(TaskStore) call ["clearTaskStatus", [_x]];
|
||||
};
|
||||
} forEach (GVAR(MissionManager) call ["getActiveMissionIds", []]);
|
||||
|
||||
if (count (GVAR(MissionManager) call ["getActiveMissionIds", []]) >= (GVAR(MissionManager) call ["getMaxConcurrentMissions", []])) exitWith {};
|
||||
|
||||
private _taskID = GVAR(MissionManager) call ["startAttackMission", []];
|
||||
if (_taskID isEqualTo "") exitWith {
|
||||
["WARNING", "Mission manager failed to start an attack mission."] call EFUNC(common,log);
|
||||
};
|
||||
|
||||
["INFO", format ["Mission manager started attack mission %1.", _taskID]] call EFUNC(common,log);
|
||||
}, GVAR(MissionManager) call ["getMissionInterval", []], []] call CFUNC(addPerFrameHandler);
|
||||
23
arma/server/addons/task/functions/fnc_protectedModule.sqf
Normal file
23
arma/server/addons/task/functions/fnc_protectedModule.sqf
Normal file
@ -0,0 +1,23 @@
|
||||
#include "..\script_component.hpp"
|
||||
|
||||
/*
|
||||
* Author: IDSolutions
|
||||
* Initializes the protected module
|
||||
*
|
||||
* Arguments:
|
||||
* 0: Logic <OBJECT> - The logic object
|
||||
* 1: Units <ARRAY> - The array of units
|
||||
* 2: Activated <BOOL> - Whether the module is activated
|
||||
*
|
||||
* Return Value:
|
||||
* None
|
||||
*
|
||||
* Example:
|
||||
* [logicObject, [unit1, unit2], true] call forge_server_task_fnc_protectedModule;
|
||||
*
|
||||
* Public: No
|
||||
*/
|
||||
|
||||
params [["_logic", objNull, [objNull]], ["_units", [], [[]]], ["_activated", true, [true]]];
|
||||
|
||||
if !(_activated) exitWith {};
|
||||
23
arma/server/addons/task/functions/fnc_shootersModule.sqf
Normal file
23
arma/server/addons/task/functions/fnc_shootersModule.sqf
Normal file
@ -0,0 +1,23 @@
|
||||
#include "..\script_component.hpp"
|
||||
|
||||
/*
|
||||
* Author: IDSolutions
|
||||
* Initializes the shooters module
|
||||
*
|
||||
* Arguments:
|
||||
* 0: Logic <OBJECT> - The logic object
|
||||
* 1: Units <ARRAY> - The array of units
|
||||
* 2: Activated <BOOL> - Whether the module is activated
|
||||
*
|
||||
* Return Value:
|
||||
* None
|
||||
*
|
||||
* Example:
|
||||
* [logicObject, [unit1, unit2], true] call forge_server_task_fnc_shootersModule;
|
||||
*
|
||||
* Public: No
|
||||
*/
|
||||
|
||||
params [["_logic", objNull, [objNull]], ["_units", [], [[]]], ["_activated", true, [true]]];
|
||||
|
||||
if !(_activated) exitWith {};
|
||||
83
arma/server/addons/task/functions/fnc_spawnEnemyWave.sqf
Normal file
83
arma/server/addons/task/functions/fnc_spawnEnemyWave.sqf
Normal file
@ -0,0 +1,83 @@
|
||||
#include "..\script_component.hpp"
|
||||
|
||||
/*
|
||||
* Author: IDSolutions
|
||||
* Spawns an enemy wave for a defense task
|
||||
*
|
||||
* Arguments:
|
||||
* 0: Defense zone marker name <STRING>
|
||||
* 1: Task ID <STRING>
|
||||
* 2: Wave number (0-based) <NUMBER>
|
||||
*
|
||||
* Return Value:
|
||||
* None
|
||||
*
|
||||
* Example:
|
||||
* ["defend_marker", "defend_1", 0] call forge_server_task_fnc_spawnEnemyWave;
|
||||
*
|
||||
* Public: No
|
||||
*/
|
||||
|
||||
params [["_defenseZone", "", [""]], ["_taskID", "", [""]], ["_waveNumber", 0, [0]]];
|
||||
|
||||
if (_defenseZone == "") exitWith { ["ERROR", "No defense zone provided for enemy wave spawn"] call EFUNC(common,log); };
|
||||
|
||||
// TODO: Add unit types to mission config
|
||||
private _basicTypes = ["O_Soldier_F", "O_Soldier_AR_F", "O_Soldier_GL_F", "O_medic_F"];
|
||||
private _specialTypes = ["O_Soldier_LAT_F", "O_soldier_M_F", "O_Soldier_TL_F", "O_Soldier_SL_F"];
|
||||
private _eliteTypes = ["O_Soldier_HAT_F", "O_Soldier_AA_F", "O_engineer_F", "O_Sharpshooter_F"];
|
||||
|
||||
private _unitCount = 6 + (_waveNumber * 2); // TODO: Make this configurable in mission config
|
||||
private _specialChance = 0.2 + (_waveNumber * 0.1); // TODO: Make this configurable in mission config
|
||||
private _eliteChance = (_waveNumber * 0.05); // TODO: Make this configurable in mission config
|
||||
|
||||
private _center = getMarkerPos _defenseZone;
|
||||
private _radius = (getMarkerSize _defenseZone select 0) max (getMarkerSize _defenseZone select 1);
|
||||
private _spawnRadius = _radius + 150;
|
||||
private _spawnPositions = [];
|
||||
|
||||
for "_i" from 0 to 3 do {
|
||||
private _angle = _i * 90;
|
||||
private _variance = 45;
|
||||
private _spawnAngle = _angle + (random (_variance * 2) - _variance);
|
||||
private _spawnDist = _spawnRadius + (random 50 - 25);
|
||||
|
||||
private _spawnX = (_center select 0) + (_spawnDist * cos _spawnAngle);
|
||||
private _spawnY = (_center select 1) + (_spawnDist * sin _spawnAngle);
|
||||
private _spawnPos = [_spawnX, _spawnY, 0];
|
||||
|
||||
private _safePos = _spawnPos findEmptyPosition [0, 50, "O_Soldier_F"];
|
||||
if (count _safePos > 0) then {
|
||||
_spawnPositions pushBack _safePos;
|
||||
};
|
||||
};
|
||||
|
||||
private _groups = [];
|
||||
{
|
||||
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;
|
||||
};
|
||||
|
||||
[_group, _center, _radius * 0.75] call CBA_fnc_taskDefend;
|
||||
} forEach _spawnPositions;
|
||||
|
||||
["INFO", format ["Spawned defense wave %1 for task %2 with %3 units", _waveNumber + 1, _taskID, _unitCount]] call EFUNC(common,log);
|
||||
9
arma/server/addons/task/script_component.hpp
Normal file
9
arma/server/addons/task/script_component.hpp
Normal file
@ -0,0 +1,9 @@
|
||||
#define COMPONENT task
|
||||
#define COMPONENT_BEAUTIFIED Task
|
||||
#include "\forge\forge_server\addons\main\script_mod.hpp"
|
||||
|
||||
// #define DEBUG_MODE_FULL
|
||||
// #define DISABLE_COMPILE_CACHE
|
||||
// #define ENABLE_PERFORMANCE_COUNTERS
|
||||
|
||||
#include "\forge\forge_server\addons\main\script_macros.hpp"
|
||||
8
arma/server/addons/task/stringtable.xml
Normal file
8
arma/server/addons/task/stringtable.xml
Normal file
@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project name="FFE">
|
||||
<Package name="Task">
|
||||
<Key ID="STR_forge_server_task_displayName">
|
||||
<English>Task</English>
|
||||
</Key>
|
||||
</Package>
|
||||
</Project>
|
||||
@ -31,6 +31,18 @@ pub fn group() -> Group {
|
||||
.command("update", update_org)
|
||||
.command("exists", org_exists)
|
||||
.command("delete", delete_org)
|
||||
.group(
|
||||
"assets",
|
||||
Group::new()
|
||||
.command("get", get_assets)
|
||||
.command("update", update_assets),
|
||||
)
|
||||
.group(
|
||||
"fleet",
|
||||
Group::new()
|
||||
.command("get", get_fleet)
|
||||
.command("update", update_fleet),
|
||||
)
|
||||
.group(
|
||||
"members",
|
||||
Group::new()
|
||||
@ -162,6 +174,56 @@ pub fn delete_org(key: String) -> String {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_assets(key: String) -> String {
|
||||
match ORG_SERVICE.get_assets(key) {
|
||||
Ok(assets) => match serde_json::to_string(&assets) {
|
||||
Ok(json) => json,
|
||||
Err(e) => format!("Error: Failed to serialize org assets: {}", e),
|
||||
},
|
||||
Err(e) => format!("Error: {}", e),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn update_assets(key: String, json_update: String) -> String {
|
||||
let assets_value: serde_json::Value = match serde_json::from_str(&json_update) {
|
||||
Ok(value) => value,
|
||||
Err(e) => return format!("Error: Invalid JSON: {}", e),
|
||||
};
|
||||
|
||||
match ORG_SERVICE.update_assets(key, assets_value) {
|
||||
Ok(assets) => match serde_json::to_string(&assets) {
|
||||
Ok(json) => json,
|
||||
Err(e) => format!("Error: Failed to serialize org assets: {}", e),
|
||||
},
|
||||
Err(e) => format!("Error: {}", e),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_fleet(key: String) -> String {
|
||||
match ORG_SERVICE.get_fleet(key) {
|
||||
Ok(fleet) => match serde_json::to_string(&fleet) {
|
||||
Ok(json) => json,
|
||||
Err(e) => format!("Error: Failed to serialize org fleet: {}", e),
|
||||
},
|
||||
Err(e) => format!("Error: {}", e),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn update_fleet(key: String, json_update: String) -> String {
|
||||
let fleet_value: serde_json::Value = match serde_json::from_str(&json_update) {
|
||||
Ok(value) => value,
|
||||
Err(e) => return format!("Error: Invalid JSON: {}", e),
|
||||
};
|
||||
|
||||
match ORG_SERVICE.update_fleet(key, fleet_value) {
|
||||
Ok(fleet) => match serde_json::to_string(&fleet) {
|
||||
Ok(json) => json,
|
||||
Err(e) => format!("Error: Failed to serialize org fleet: {}", e),
|
||||
},
|
||||
Err(e) => format!("Error: {}", e),
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Member Operations
|
||||
// ============================================================================
|
||||
|
||||
@ -39,13 +39,10 @@ pub fn hash_get(key: String, field: String) -> String {
|
||||
pub fn hash_get_all(key: String) -> String {
|
||||
redis_operation!(conn => {
|
||||
match conn.hgetall::<_, HashMap<String, String>>(&key).await {
|
||||
Ok(hash_map) => {
|
||||
let formatted_pairs: Vec<String> = hash_map
|
||||
.iter()
|
||||
.map(|(k, v)| format!("{}, {}", k, v))
|
||||
.collect();
|
||||
formatted_pairs.join(", ")
|
||||
}
|
||||
Ok(hash_map) => match serde_json::to_string(&hash_map) {
|
||||
Ok(json) => json,
|
||||
Err(e) => format!("Error: Failed to serialize hash map: {}", e),
|
||||
},
|
||||
Err(e) => format!("Error: {}", e),
|
||||
}
|
||||
})
|
||||
|
||||
@ -10,6 +10,6 @@ pub use actor::Actor;
|
||||
pub use bank::Bank;
|
||||
pub use garage::{Garage, HitPoints, Vehicle};
|
||||
pub use locker::{Item, Locker};
|
||||
pub use org::{CreditLineSummary, MemberSummary, Org};
|
||||
pub use org::{CreditLineSummary, MemberSummary, Org, OrgAssetEntry, OrgFleetEntry};
|
||||
pub use v_garage::{VGarage, VehicleCategory};
|
||||
pub use v_locker::{EquipmentCategory, VLocker};
|
||||
|
||||
@ -10,6 +10,24 @@ pub struct CreditLineSummary {
|
||||
pub amount: f64,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct OrgAssetEntry {
|
||||
pub classname: String,
|
||||
#[serde(rename = "type")]
|
||||
pub asset_type: String,
|
||||
pub quantity: i64,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct OrgFleetEntry {
|
||||
pub classname: String,
|
||||
pub name: String,
|
||||
#[serde(rename = "type")]
|
||||
pub fleet_type: String,
|
||||
pub status: String,
|
||||
pub damage: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct Org {
|
||||
pub id: String,
|
||||
@ -62,6 +80,12 @@ impl Org {
|
||||
return Err(OrgValidationError::NegativeFunds);
|
||||
}
|
||||
|
||||
if self.reputation < 0 {
|
||||
return Err(OrgValidationError::InvalidName(
|
||||
"Organization reputation cannot be negative".to_string(),
|
||||
));
|
||||
}
|
||||
|
||||
if !self.id.chars().all(|c| c.is_alphanumeric() || c == '_') {
|
||||
return Err(OrgValidationError::InvalidId(self.id.clone()));
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user