Enhance documentation and functionality across various server addons
- Updated README.md files for extension, garage, locker, main, organization, phone, store, and task addons to provide clearer overviews, dependencies, main components, and usage notes. - Improved task module documentation to clarify timer semantics and server task flows, ensuring accurate usage of time limits. - Adjusted default values for task time limits and IED timers to enforce positive countdown requirements. - Added new CAD addon for dispatch coordination, including its overview, dependencies, main components, and event handling.
This commit is contained in:
parent
5576cc4746
commit
9d789440e0
@ -1,3 +1,32 @@
|
|||||||
# forge_server_actor
|
# Forge Server Actor
|
||||||
|
|
||||||
Description for this addon
|
## Overview
|
||||||
|
The actor addon is the server-side bridge for player identity and character
|
||||||
|
state. It keeps Arma-facing actor snapshots in SQF while durable and hot actor
|
||||||
|
state are owned by the Rust extension.
|
||||||
|
|
||||||
|
Actor records include UID, name, loadout, position, direction, stance, rank,
|
||||||
|
life state, phone number, email, organization, and holster state.
|
||||||
|
|
||||||
|
## Dependencies
|
||||||
|
- `forge_server_main`
|
||||||
|
- `forge_server_common`
|
||||||
|
- `forge_server_extension` at runtime for actor extension calls
|
||||||
|
- `forge_client_actor` for response RPCs
|
||||||
|
|
||||||
|
## Main Components
|
||||||
|
- `fnc_initActorStore.sqf` initializes `ActorModel` and `ActorStore`.
|
||||||
|
- `ActorModel` provides defaults, player snapshot conversion, migration, and
|
||||||
|
validation.
|
||||||
|
- `ActorStore` wraps extension hot-state calls and exposes event-facing actor
|
||||||
|
operations.
|
||||||
|
|
||||||
|
## Runtime Behavior
|
||||||
|
- Missing persistent actors can be created from live player snapshots.
|
||||||
|
- Hot actor reads are migrated and hydrated before use.
|
||||||
|
- `saveHotState` in the main addon snapshots and saves actor state on player
|
||||||
|
disconnect and mission end.
|
||||||
|
|
||||||
|
## Event Surface
|
||||||
|
The addon handles server events for actor init, get, set, multi-set, save, and
|
||||||
|
remove requests, then replies to the requesting player through client actor RPCs.
|
||||||
|
|||||||
@ -1,3 +1,39 @@
|
|||||||
# forge_server_bank
|
# Forge Server Bank
|
||||||
|
|
||||||
Description for this addon
|
## Overview
|
||||||
|
The bank addon owns the SQF bridge for player accounts, cash and bank balances,
|
||||||
|
PIN/session handling, transfers, checkout charging, earnings deposits, and
|
||||||
|
credit-line repayment.
|
||||||
|
|
||||||
|
Account truth lives in the extension hot cache. SQF handles Arma-facing
|
||||||
|
validation, client messaging, session state, and payment integration with other
|
||||||
|
server addons.
|
||||||
|
|
||||||
|
## Dependencies
|
||||||
|
- `forge_server_main`
|
||||||
|
- `forge_server_common`
|
||||||
|
- `forge_server_extension` at runtime for bank extension calls
|
||||||
|
- `forge_server_org` at runtime for credit-line repayment
|
||||||
|
- `forge_client_bank` and `forge_client_notifications` for response RPCs
|
||||||
|
|
||||||
|
## Main Components
|
||||||
|
- `fnc_initBank.sqf` initializes all bank stores and helpers.
|
||||||
|
- `fnc_initModel.sqf` defines account defaults and migration behavior.
|
||||||
|
- `fnc_initPayloadBuilder.sqf` builds UI, checkout, and organization payment
|
||||||
|
context.
|
||||||
|
- `fnc_initSessionManager.sqf` manages PIN and authorization session state.
|
||||||
|
- `fnc_initMessenger.sqf` sends account syncs, alerts, and notifications.
|
||||||
|
- `fnc_initStore.sqf` wraps hot bank calls and account mutations.
|
||||||
|
|
||||||
|
## Supported Operations
|
||||||
|
- initialize and hydrate player bank state
|
||||||
|
- deposit, withdraw, transfer, and deposit earnings
|
||||||
|
- validate PIN-backed sessions
|
||||||
|
- charge checkout previews and committed purchases
|
||||||
|
- repay organization credit lines with rollback on failure
|
||||||
|
- save hot bank state to durable storage
|
||||||
|
|
||||||
|
## Runtime Notes
|
||||||
|
`forge_server_main_fnc_saveHotState` saves bank hot state on disconnect and
|
||||||
|
mission shutdown. Store checkout and task rewards use this addon for
|
||||||
|
authoritative player balance changes.
|
||||||
|
|||||||
38
arma/server/addons/cad/README.md
Normal file
38
arma/server/addons/cad/README.md
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
# Forge Server CAD
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
The CAD addon coordinates dispatch-facing operational state: groups,
|
||||||
|
assignments, dispatch orders, support requests, task assignment, permissions,
|
||||||
|
hydrate payloads, and recent activity.
|
||||||
|
|
||||||
|
CAD state is extension-backed but intentionally transient. It is scoped to the
|
||||||
|
active server or mission lifecycle and starts fresh after restart.
|
||||||
|
|
||||||
|
## Dependencies
|
||||||
|
- `forge_server_main`
|
||||||
|
- `forge_server_common`
|
||||||
|
- `forge_server_actor`
|
||||||
|
- `forge_server_org`
|
||||||
|
- `forge_server_task`
|
||||||
|
- `forge_server_extension` at runtime for CAD extension calls
|
||||||
|
- `forge_client_cad` and `forge_client_notifications` for response RPCs
|
||||||
|
|
||||||
|
## Main Components
|
||||||
|
- `fnc_initCadStore.sqf` coordinates repositories and request handling.
|
||||||
|
- `fnc_initActivityRepository.sqf` records recent CAD activity.
|
||||||
|
- `fnc_initAssignmentRepository.sqf` manages task assignments and dispatch
|
||||||
|
orders.
|
||||||
|
- `fnc_initGroupRepository.sqf` manages group membership, role, and status.
|
||||||
|
- `fnc_initPermissionService.sqf` resolves dispatch permissions.
|
||||||
|
- `fnc_initPersistenceService.sqf` bridges SQF state to extension hot CAD
|
||||||
|
storage.
|
||||||
|
- `fnc_initRequestRepository.sqf` manages support requests.
|
||||||
|
|
||||||
|
## Event Surface
|
||||||
|
The addon handles hydrate, task assignment, dispatch order, support request,
|
||||||
|
task acknowledge/decline, and group update events. Successful mutations can
|
||||||
|
invalidate CAD state globally so clients refresh their views.
|
||||||
|
|
||||||
|
## Notes
|
||||||
|
CAD hydrate payloads include active task catalog entries from `TaskStore` and
|
||||||
|
organization context from `ActorStore`.
|
||||||
@ -1,3 +1,23 @@
|
|||||||
# forge_server_common
|
# Forge Server Common
|
||||||
|
|
||||||
Common functionality shared between addons.
|
## Overview
|
||||||
|
The common addon provides shared SQF utilities used by server-side Forge
|
||||||
|
addons. It contains lightweight helpers only; gameplay domain state belongs in
|
||||||
|
the specific domain addons or the Rust extension.
|
||||||
|
|
||||||
|
## Dependencies
|
||||||
|
- `forge_server_main`
|
||||||
|
|
||||||
|
## Main Components
|
||||||
|
- `fnc_baseStore.sqf` provides shared hash-map object behavior such as JSON
|
||||||
|
conversion.
|
||||||
|
- `fnc_log.sqf` standardizes server log messages.
|
||||||
|
- `fnc_getPlayer.sqf` resolves online players by UID.
|
||||||
|
- `fnc_formatNumber.sqf` formats numeric values for notifications and UI text.
|
||||||
|
- `fnc_generateHash.sqf` and `fnc_generateSecureData.sqf` provide hashing and
|
||||||
|
random data helpers.
|
||||||
|
- `fnc_timeToSeconds.sqf` converts time values into seconds.
|
||||||
|
|
||||||
|
## Notes
|
||||||
|
Keep this addon free of domain-specific behavior. If a helper needs actor,
|
||||||
|
bank, org, task, store, or CAD state, it belongs in that addon instead.
|
||||||
|
|||||||
@ -1,3 +1,31 @@
|
|||||||
# forge_server_economy
|
# Forge Server Economy
|
||||||
|
|
||||||
Description for this addon
|
## Overview
|
||||||
|
The economy addon contains server-side systems for world economic interactions
|
||||||
|
that are still implemented in SQF.
|
||||||
|
|
||||||
|
Current stores cover fuel tracking, medical service behavior, and a placeholder
|
||||||
|
service economy store.
|
||||||
|
|
||||||
|
## Dependencies
|
||||||
|
- `forge_server_main`
|
||||||
|
- `forge_server_common` at runtime for logging, formatting, and player lookup
|
||||||
|
- `forge_server_bank` at runtime for medical service charges
|
||||||
|
- `forge_client_actor` and `forge_client_notifications` for response RPCs
|
||||||
|
|
||||||
|
## Main Components
|
||||||
|
- `fnc_initFEconomyStore.sqf` tracks active refueling sessions and reports fuel
|
||||||
|
totals.
|
||||||
|
- `fnc_initMEconomyStore.sqf` manages medical spawn occupancy, healing charges,
|
||||||
|
respawn placement, death inventory handling, and body-bag transfer.
|
||||||
|
- `fnc_initSEconomyStore.sqf` initializes the service economy placeholder.
|
||||||
|
|
||||||
|
## Event Surface
|
||||||
|
The addon registers CBA server events for fuel start/tick/stop, player killed,
|
||||||
|
player respawn, and healing. Medical store initialization runs after post-init
|
||||||
|
to discover configured medical spawn objects.
|
||||||
|
|
||||||
|
## Notes
|
||||||
|
The service economy store is currently a stub. Fuel and medical behavior should
|
||||||
|
stay server-authoritative because they mutate money, inventory, and respawn
|
||||||
|
state.
|
||||||
|
|||||||
@ -1,3 +1,29 @@
|
|||||||
# forge_server_extension
|
# Forge Server Extension
|
||||||
|
|
||||||
Extension functionality shared between addons.
|
## Overview
|
||||||
|
The extension addon is the SQF bridge to the `forge_server` arma-rs extension.
|
||||||
|
It normalizes `callExtension` responses, routes large payloads through the
|
||||||
|
transport layer, and exposes helper functions used by extension-backed server
|
||||||
|
addons.
|
||||||
|
|
||||||
|
## Dependencies
|
||||||
|
- `forge_server_main`
|
||||||
|
|
||||||
|
## Main Components
|
||||||
|
- `fnc_extCall.sqf` is the primary extension call wrapper.
|
||||||
|
- `fnc_transport.sqf` stages large requests and assembles chunked responses.
|
||||||
|
- `fnc_setHandler.sqf` registers local SQF handlers for extension callback
|
||||||
|
integration.
|
||||||
|
|
||||||
|
## Transport Behavior
|
||||||
|
Most commands use direct `callExtension`. Commands that can return large
|
||||||
|
payloads, or requests whose encoded arguments exceed the chunk threshold, are
|
||||||
|
routed through `transport:invoke` or staged transport requests.
|
||||||
|
|
||||||
|
The wrapper falls back to direct calls if the transport route is unsupported and
|
||||||
|
the request was not chunked.
|
||||||
|
|
||||||
|
## Notes
|
||||||
|
Domain addons should call `EFUNC(extension,extCall)` instead of calling the
|
||||||
|
extension directly. This keeps response handling, chunking, and error logging
|
||||||
|
consistent.
|
||||||
|
|||||||
@ -1,3 +1,30 @@
|
|||||||
# forge_server_garage
|
# Forge Server Garage
|
||||||
|
|
||||||
Description for this addon
|
## Overview
|
||||||
|
The garage addon is the server-side bridge for player vehicle storage and
|
||||||
|
owner-scoped vehicle unlock storage.
|
||||||
|
|
||||||
|
Garage hot state is owned by the extension. SQF validates Arma-facing requests,
|
||||||
|
serializes vehicle payloads, sends client syncs, and marks editor-placed garage
|
||||||
|
objects.
|
||||||
|
|
||||||
|
## Dependencies
|
||||||
|
- `forge_server_main`
|
||||||
|
- `forge_server_common`
|
||||||
|
- `forge_server_extension` at runtime for garage extension calls
|
||||||
|
- `forge_client_garage` for response RPCs
|
||||||
|
|
||||||
|
## Main Components
|
||||||
|
- `fnc_initGarage.sqf` initializes garage world objects.
|
||||||
|
- `fnc_initGarageStore.sqf` manages player garage hot state.
|
||||||
|
- `fnc_initVGStore.sqf` manages owner-scoped vehicle unlock state.
|
||||||
|
|
||||||
|
## Supported Operations
|
||||||
|
- initialize player garage data
|
||||||
|
- save player and owner-scoped garage state
|
||||||
|
- store and retrieve player vehicles
|
||||||
|
- initialize and save owner-scoped vehicle storage
|
||||||
|
|
||||||
|
## Runtime Notes
|
||||||
|
`forge_server_main_fnc_saveHotState` saves both `GarageStore` and
|
||||||
|
`VGarageStore` on disconnect and mission shutdown.
|
||||||
|
|||||||
@ -1,3 +1,30 @@
|
|||||||
# forge_server_locker
|
# Forge Server Locker
|
||||||
|
|
||||||
Description for this addon
|
## Overview
|
||||||
|
The locker addon is the server-side bridge for player item storage and
|
||||||
|
owner-scoped arsenal unlock storage.
|
||||||
|
|
||||||
|
Locker hot state is owned by the extension. SQF handles client events, payload
|
||||||
|
validation, synchronization, and save calls.
|
||||||
|
|
||||||
|
## Dependencies
|
||||||
|
- `forge_server_main`
|
||||||
|
- `forge_server_common`
|
||||||
|
- `forge_server_extension` at runtime for locker extension calls
|
||||||
|
- `forge_client_locker` for response RPCs
|
||||||
|
|
||||||
|
## Main Components
|
||||||
|
- `fnc_initLocker.sqf` initializes locker world objects.
|
||||||
|
- `fnc_initLockerStore.sqf` manages player locker hot state.
|
||||||
|
- `fnc_initVAStore.sqf` manages owner-scoped arsenal unlock state.
|
||||||
|
|
||||||
|
## Supported Operations
|
||||||
|
- initialize player locker data
|
||||||
|
- save player and owner-scoped locker state
|
||||||
|
- override locker data from trusted server-side callers
|
||||||
|
- initialize and save owner-scoped arsenal storage
|
||||||
|
|
||||||
|
## Runtime Notes
|
||||||
|
`forge_server_main_fnc_saveHotState` saves both `LockerStore` and `VAStore` on
|
||||||
|
disconnect and mission shutdown. Store checkout and task rewards can grant
|
||||||
|
assets into organization-owned storage through the org addon.
|
||||||
|
|||||||
@ -1,3 +1,29 @@
|
|||||||
# forge_server_main
|
# Forge Server Main
|
||||||
|
|
||||||
Main Addon for forge-server
|
## Overview
|
||||||
|
The main addon owns server-side bootstrap behavior for Forge. It prepares
|
||||||
|
functions, wires extension callbacks and ICom events, initializes shared stores,
|
||||||
|
and flushes hot state when players disconnect or the mission ends.
|
||||||
|
|
||||||
|
## Dependencies
|
||||||
|
- `cba_main`
|
||||||
|
- `ace_main`
|
||||||
|
|
||||||
|
## Main Components
|
||||||
|
- `fnc_initStores.sqf` initializes core server stores in dependency order.
|
||||||
|
- `fnc_saveHotState.sqf` snapshots and saves extension-backed hot state.
|
||||||
|
- `fnc_initValidationHarness.sqf` provides targeted runtime smoke checks for
|
||||||
|
multi-module flows.
|
||||||
|
- `XEH_preInit.sqf` registers ICom and extension callback handlers.
|
||||||
|
- `XEH_postInit.sqf` starts store initialization.
|
||||||
|
|
||||||
|
## Store Initialization
|
||||||
|
The main addon initializes shared base stores, actor, bank, garage, locker,
|
||||||
|
organization, store, and validation harness state. Some addons initialize their
|
||||||
|
own state in pre-init or post-init when they are intentionally independent of
|
||||||
|
the main bootstrap flow.
|
||||||
|
|
||||||
|
## Hot State Flush
|
||||||
|
On player disconnect, mission ended, and MP ended events, `saveHotState`
|
||||||
|
persists actor, bank, locker, virtual arsenal, garage, virtual garage, and
|
||||||
|
organization hot state for the relevant UID or all known UIDs.
|
||||||
|
|||||||
@ -1,3 +1,36 @@
|
|||||||
# forge_server_org
|
# Forge Server Organization
|
||||||
|
|
||||||
Description for this addon
|
## Overview
|
||||||
|
The organization addon is the server-side bridge for player organizations,
|
||||||
|
membership, treasury funds, reputation, credit lines, shared assets, fleet
|
||||||
|
entries, and invitations.
|
||||||
|
|
||||||
|
Organization hot state is owned by the extension. SQF coordinates Arma-facing
|
||||||
|
events, UI payloads, membership syncs, and integration with actor, bank, store,
|
||||||
|
and task flows.
|
||||||
|
|
||||||
|
## Dependencies
|
||||||
|
- `forge_server_main`
|
||||||
|
- `forge_server_common`
|
||||||
|
- `forge_server_extension` at runtime for organization extension calls
|
||||||
|
- `forge_server_actor` at runtime for organization membership lookups
|
||||||
|
- `forge_client_org` and `forge_client_notifications` for response RPCs
|
||||||
|
|
||||||
|
## Main Components
|
||||||
|
- `fnc_initOrgStore.sqf` initializes `OrgModel` and `OrgStore`.
|
||||||
|
- `fnc_initPayloadBuilder.sqf` builds portal, organization, member, asset, and
|
||||||
|
fleet payloads.
|
||||||
|
|
||||||
|
## Supported Operations
|
||||||
|
- initialize and hydrate organization portal data
|
||||||
|
- register, leave, and disband organizations
|
||||||
|
- invite, accept, and decline members
|
||||||
|
- assign and repay credit lines
|
||||||
|
- update funds and reputation
|
||||||
|
- grant assets and fleet vehicles
|
||||||
|
- save organization hot state
|
||||||
|
|
||||||
|
## Runtime Notes
|
||||||
|
The addon ensures the `default` organization exists during store creation.
|
||||||
|
Task rewards and store checkout both rely on `OrgStore` for authoritative
|
||||||
|
organization-owned state.
|
||||||
|
|||||||
@ -1,19 +1,33 @@
|
|||||||
forge_server_phone
|
# Forge Server Phone
|
||||||
===================
|
|
||||||
|
|
||||||
This addon provides the phone user interface and functionality for the in-game phone system. It handles all phone-related features including the UI display, interactions, and core phone operations.
|
## Overview
|
||||||
|
The phone addon is the server-side bridge for contacts, SMS messages, and email.
|
||||||
|
Phone runtime state is owned by the extension. SQF stores preserve the
|
||||||
|
event-facing API and synchronize client UI state.
|
||||||
|
|
||||||
Server State
|
## Dependencies
|
||||||
------------
|
- `forge_server_main`
|
||||||
|
- `forge_server_common` at runtime for online player lookup
|
||||||
|
- `forge_server_extension` at runtime for phone extension calls
|
||||||
|
- `forge_client_phone` for response RPCs
|
||||||
|
|
||||||
Phone contacts, messages, and emails are owned by the server extension. SQF phone stores act as bridge objects for CBA events and UI sync only.
|
## Main Components
|
||||||
|
- `fnc_initPhoneStore.sqf` coordinates the phone facade.
|
||||||
|
- `fnc_initContactStore.sqf` manages contacts.
|
||||||
|
- `fnc_initMessageStore.sqf` manages SMS messages and threads.
|
||||||
|
- `fnc_initEmailStore.sqf` manages email messages.
|
||||||
|
- `fnc_initPlayer.sqf` initializes phone data for a player.
|
||||||
|
|
||||||
Persistent SurrealDB tables:
|
## Persistent Extension Tables
|
||||||
|
- `phone_user`: owner row for an initialized phone profile
|
||||||
|
- `phone_contact`: per-owner contact rows keyed by owner UID and contact UID
|
||||||
|
- `phone_message`: shared message records
|
||||||
|
- `phone_message_index`: per-owner message visibility and read state
|
||||||
|
- `phone_email`: shared email records
|
||||||
|
- `phone_email_index`: per-owner email visibility and read state
|
||||||
|
- `phone_sequence`: global sequence state for generated message and email IDs
|
||||||
|
|
||||||
- `phone_user`: owner row for an initialized phone profile.
|
## Event Surface
|
||||||
- `phone_contact`: per-owner contact rows keyed by owner UID and contact UID.
|
The addon handles client requests to initialize phone state, add/remove/refresh
|
||||||
- `phone_message`: shared message records.
|
contacts, send/read/delete messages, send/read/delete emails, and remove phone
|
||||||
- `phone_message_index`: per-owner message visibility and read state.
|
state.
|
||||||
- `phone_email`: shared email records.
|
|
||||||
- `phone_email_index`: per-owner email visibility and read state.
|
|
||||||
- `phone_sequence`: global sequence state for generated message and email IDs.
|
|
||||||
|
|||||||
@ -1,18 +1,35 @@
|
|||||||
# forge_server_store
|
# Forge Server Store
|
||||||
|
|
||||||
Server-side SQF module for storefront entities, catalog hydration, and checkout
|
## Overview
|
||||||
coordination.
|
The store addon manages server-side storefront entities, catalog hydration, and
|
||||||
|
checkout coordination.
|
||||||
|
|
||||||
## Stores and Services
|
SQF owns Arma-facing storefront discovery and request validation. The Rust
|
||||||
|
extension owns authoritative checkout calculation through `store:checkout`.
|
||||||
|
|
||||||
- `StorefrontStore` builds storefront hydrate payloads, validates checkout
|
## Dependencies
|
||||||
requests, calls the Rust `store:checkout` backend, syncs UI patches, and saves
|
- `forge_server_main`
|
||||||
hot state for related modules.
|
- `forge_server_common`
|
||||||
- `StoreCatalogService` scans live Arma config categories, builds catalog
|
- `forge_server_extension` at runtime for checkout calls
|
||||||
responses, resolves checkout entries, and calculates authoritative prices.
|
- `forge_server_actor`, `forge_server_bank`, and `forge_server_org` at runtime
|
||||||
|
for checkout context and payment state
|
||||||
|
- `forge_client_store` for response RPCs
|
||||||
|
|
||||||
|
## Main Components
|
||||||
|
- `fnc_initStore.sqf` marks editor-placed store objects with `isStore = true`.
|
||||||
|
- `fnc_initCatalogService.sqf` scans live Arma config categories, builds
|
||||||
|
catalog responses, resolves checkout entries, and calculates authoritative
|
||||||
|
catalog prices.
|
||||||
|
- `fnc_initStorefrontStore.sqf` builds hydrate payloads, validates checkout
|
||||||
|
requests, calls `store:checkout`, syncs client patches, and coordinates
|
||||||
|
related bank/org persistence.
|
||||||
|
|
||||||
## Editor Entities
|
## Editor Entities
|
||||||
|
`fnc_initStore` matches non-null mission namespace objects whose variable names
|
||||||
|
contain `store`, mirroring the garage entity initialization pattern.
|
||||||
|
|
||||||
`fnc_initStore` marks editor-placed store objects with `isStore = true`. It
|
## Checkout Flow
|
||||||
matches non-null mission namespace objects whose variable names contain
|
Store checkout can charge cash, bank balance, organization funds, or approved
|
||||||
`store`, mirroring the garage entity initialization pattern.
|
credit lines depending on the hydrated session context. Checkout results can
|
||||||
|
grant locker assets, organization assets, and fleet vehicles through the
|
||||||
|
related domain stores.
|
||||||
|
|||||||
@ -355,9 +355,9 @@ class CfgVehicles {
|
|||||||
class TimeLimit: Edit {
|
class TimeLimit: Edit {
|
||||||
property = "FORGE_Module_Defuse_TimeLimit";
|
property = "FORGE_Module_Defuse_TimeLimit";
|
||||||
displayName = "Time Limit";
|
displayName = "Time Limit";
|
||||||
tooltip = "Time in seconds before detenation (0 for no limit)";
|
tooltip = "Time in seconds before detonation; must be greater than 0";
|
||||||
typeName = "NUMBER";
|
typeName = "NUMBER";
|
||||||
defaultValue = 0;
|
defaultValue = 300;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -608,7 +608,7 @@ class CfgVehicles {
|
|||||||
class TimeLimit: Edit {
|
class TimeLimit: Edit {
|
||||||
property = "FORGE_Module_Hostage_TimeLimit";
|
property = "FORGE_Module_Hostage_TimeLimit";
|
||||||
displayName = "Time Limit";
|
displayName = "Time Limit";
|
||||||
tooltip = "Time in seconds before HVTs escape (0 for no limit)";
|
tooltip = "Time in seconds before hostages are executed (0 for no limit)";
|
||||||
typeName = "NUMBER";
|
typeName = "NUMBER";
|
||||||
defaultValue = 0;
|
defaultValue = 0;
|
||||||
};
|
};
|
||||||
@ -730,9 +730,9 @@ class CfgVehicles {
|
|||||||
class TimeLimit: Edit {
|
class TimeLimit: Edit {
|
||||||
property = "FORGE_Module_Delivery_TimeLimit";
|
property = "FORGE_Module_Delivery_TimeLimit";
|
||||||
displayName = "Time Limit";
|
displayName = "Time Limit";
|
||||||
tooltip = "Seconds to complete delivery (-1 for no limit)";
|
tooltip = "Seconds to complete delivery (0 for no limit)";
|
||||||
typeName = "NUMBER";
|
typeName = "NUMBER";
|
||||||
defaultValue = -1;
|
defaultValue = 0;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -907,7 +907,7 @@ class CfgVehicles {
|
|||||||
class TimeLimit: Edit {
|
class TimeLimit: Edit {
|
||||||
property = "FORGE_Module_HVT_TimeLimit";
|
property = "FORGE_Module_HVT_TimeLimit";
|
||||||
displayName = "Time Limit";
|
displayName = "Time Limit";
|
||||||
tooltip = "Time in seconds before HVTs escape (0 for no limit)";
|
tooltip = "Time in seconds before the HVT task fails (0 for no limit)";
|
||||||
typeName = "NUMBER";
|
typeName = "NUMBER";
|
||||||
defaultValue = 0;
|
defaultValue = 0;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -16,6 +16,7 @@ system intentionally starts clean after each server or mission restart.
|
|||||||
- notify task participants and sync org updates to online members
|
- notify task participants and sync org updates to online members
|
||||||
|
|
||||||
## Dependencies
|
## Dependencies
|
||||||
|
- `forge_server_extension`
|
||||||
- `forge_server_common`
|
- `forge_server_common`
|
||||||
- `forge_server_actor`
|
- `forge_server_actor`
|
||||||
- `forge_server_bank`
|
- `forge_server_bank`
|
||||||
@ -58,6 +59,10 @@ Org rewards always go to the bound owner org. Player earnings still use per-play
|
|||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
|
Task time limits use `0` for no limit on attack, destroy, delivery, hostage,
|
||||||
|
and HVT tasks. Defuse IED timers are different: each IED must have a positive
|
||||||
|
countdown value.
|
||||||
|
|
||||||
### Start Through The Handler
|
### Start Through The Handler
|
||||||
Use the handler when you want reputation gating and task ownership binding.
|
Use the handler when you want reputation gating and task ownership binding.
|
||||||
|
|
||||||
|
|||||||
@ -13,7 +13,7 @@
|
|||||||
* 5: Amount of rating the company and player recieve if the task is successful <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)
|
* 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)
|
* 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)
|
* 8: Amount of time before target(s) escape <NUMBER> (default: 0, 0 = no limit)
|
||||||
* 9: Equipment rewards <ARRAY> (default: [])
|
* 9: Equipment rewards <ARRAY> (default: [])
|
||||||
* 10: Supply rewards <ARRAY> (default: [])
|
* 10: Supply rewards <ARRAY> (default: [])
|
||||||
* 11: Weapon rewards <ARRAY> (default: [])
|
* 11: Weapon rewards <ARRAY> (default: [])
|
||||||
@ -39,7 +39,7 @@ params [
|
|||||||
["_ratingSuccess", 0, [0]],
|
["_ratingSuccess", 0, [0]],
|
||||||
["_endSuccess", false, [false]],
|
["_endSuccess", false, [false]],
|
||||||
["_endFail", false, [false]],
|
["_endFail", false, [false]],
|
||||||
["_time", -1, [0]],
|
["_timeLimit", 0, [0]],
|
||||||
["_equipmentRewards", [], [[]]],
|
["_equipmentRewards", [], [[]]],
|
||||||
["_supplyRewards", [], [[]]],
|
["_supplyRewards", [], [[]]],
|
||||||
["_weaponRewards", [], [[]]],
|
["_weaponRewards", [], [[]]],
|
||||||
@ -58,7 +58,7 @@ waitUntil {
|
|||||||
};
|
};
|
||||||
|
|
||||||
_targets = GVAR(TaskStore) call ["getTaskEntities", ["targets", _taskID]];
|
_targets = GVAR(TaskStore) call ["getTaskEntities", ["targets", _taskID]];
|
||||||
private _startTime = if (!isNil "_time") then { floor(time) } else { nil };
|
private _startTime = if (_timeLimit isNotEqualTo 0) then { floor(time) } else { nil };
|
||||||
|
|
||||||
waitUntil {
|
waitUntil {
|
||||||
sleep 1;
|
sleep 1;
|
||||||
@ -66,8 +66,8 @@ waitUntil {
|
|||||||
|
|
||||||
private _targetsKilled = ({ !alive _x } count _targets);
|
private _targetsKilled = ({ !alive _x } count _targets);
|
||||||
|
|
||||||
if (_time isNotEqualTo -1) then {
|
if (_timeLimit isNotEqualTo 0) then {
|
||||||
private _timeExpired = (floor time - _startTime >= _time);
|
private _timeExpired = (floor time - _startTime >= _timeLimit);
|
||||||
|
|
||||||
if (_targetsKilled < _limitSuccess && _timeExpired) then { _result = 1; };
|
if (_targetsKilled < _limitSuccess && _timeExpired) then { _result = 1; };
|
||||||
|
|
||||||
|
|||||||
@ -53,7 +53,7 @@ private _taskPos = if (_syncedEntities isNotEqualTo []) then {
|
|||||||
["ratingSuccess", _logic getVariable ["RatingSuccess", 0]],
|
["ratingSuccess", _logic getVariable ["RatingSuccess", 0]],
|
||||||
["endSuccess", _logic getVariable ["EndSuccess", false]],
|
["endSuccess", _logic getVariable ["EndSuccess", false]],
|
||||||
["endFail", _logic getVariable ["EndFail", false]],
|
["endFail", _logic getVariable ["EndFail", false]],
|
||||||
["timeLimit", _logic getVariable ["TimeLimit", -1]]
|
["timeLimit", _logic getVariable ["TimeLimit", 0]]
|
||||||
]
|
]
|
||||||
] call FUNC(startTask);
|
] call FUNC(startTask);
|
||||||
|
|
||||||
|
|||||||
@ -36,7 +36,7 @@ private _protectedEntities = if (!isNull _protectedModule) then { synchronizedOb
|
|||||||
["INFO", format [
|
["INFO", format [
|
||||||
"Defuse Module: TaskID: %1, IEDs: %2, Protected: %3, IED timer: %4s",
|
"Defuse Module: TaskID: %1, IEDs: %2, Protected: %3, IED timer: %4s",
|
||||||
_taskID, count _iedEntities, count _protectedEntities,
|
_taskID, count _iedEntities, count _protectedEntities,
|
||||||
_logic getVariable ["TimeLimit", 0]
|
_logic getVariable ["TimeLimit", 300]
|
||||||
]] call EFUNC(common,log);
|
]] call EFUNC(common,log);
|
||||||
|
|
||||||
private _taskPos = if (_iedEntities isNotEqualTo []) then {
|
private _taskPos = if (_iedEntities isNotEqualTo []) then {
|
||||||
@ -63,7 +63,7 @@ private _taskPos = if (_iedEntities isNotEqualTo []) then {
|
|||||||
["ratingSuccess", _logic getVariable ["RatingSuccess", 0]],
|
["ratingSuccess", _logic getVariable ["RatingSuccess", 0]],
|
||||||
["endSuccess", _logic getVariable ["EndSuccess", false]],
|
["endSuccess", _logic getVariable ["EndSuccess", false]],
|
||||||
["endFail", _logic getVariable ["EndFail", false]],
|
["endFail", _logic getVariable ["EndFail", false]],
|
||||||
["iedTimer", _logic getVariable ["TimeLimit", 0]]
|
["iedTimer", _logic getVariable ["TimeLimit", 300]]
|
||||||
]
|
]
|
||||||
] call FUNC(startTask);
|
] call FUNC(startTask);
|
||||||
|
|
||||||
|
|||||||
@ -14,7 +14,7 @@
|
|||||||
* 6: Amount of rating the company and player receive if the task is successful <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)
|
* 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)
|
* 8: Should the mission end (MissionFailed) if the task is failed <BOOL> (default: false)
|
||||||
* 9: Amount of time to complete delivery <NUMBER> (default: -1)
|
* 9: Amount of time to complete delivery <NUMBER> (default: 0)
|
||||||
* 10: Equipment rewards <ARRAY> (default: [])
|
* 10: Equipment rewards <ARRAY> (default: [])
|
||||||
* 11: Supply rewards <ARRAY> (default: [])
|
* 11: Supply rewards <ARRAY> (default: [])
|
||||||
* 12: Weapon rewards <ARRAY> (default: [])
|
* 12: Weapon rewards <ARRAY> (default: [])
|
||||||
@ -41,7 +41,7 @@ params [
|
|||||||
["_ratingSuccess", 0, [0]],
|
["_ratingSuccess", 0, [0]],
|
||||||
["_endSuccess", false, [false]],
|
["_endSuccess", false, [false]],
|
||||||
["_endFail", false, [false]],
|
["_endFail", false, [false]],
|
||||||
["_time", -1, [0]],
|
["_timeLimit", 0, [0]],
|
||||||
["_equipmentRewards", [], [[]]],
|
["_equipmentRewards", [], [[]]],
|
||||||
["_supplyRewards", [], [[]]],
|
["_supplyRewards", [], [[]]],
|
||||||
["_weaponRewards", [], [[]]],
|
["_weaponRewards", [], [[]]],
|
||||||
@ -60,7 +60,7 @@ waitUntil {
|
|||||||
};
|
};
|
||||||
|
|
||||||
_cargo = GVAR(TaskStore) call ["getTaskEntities", ["cargo", _taskID]];
|
_cargo = GVAR(TaskStore) call ["getTaskEntities", ["cargo", _taskID]];
|
||||||
private _startTime = if (_time isNotEqualTo -1) then { floor(time) } else { nil };
|
private _startTime = if (_timeLimit isNotEqualTo 0) then { floor(time) } else { nil };
|
||||||
|
|
||||||
waitUntil {
|
waitUntil {
|
||||||
sleep 1;
|
sleep 1;
|
||||||
@ -69,8 +69,8 @@ waitUntil {
|
|||||||
private _cargoDelivered = ({ _x inArea _deliveryZone && (damage _x) < 0.7 } count _cargo);
|
private _cargoDelivered = ({ _x inArea _deliveryZone && (damage _x) < 0.7 } count _cargo);
|
||||||
private _cargoDamaged = ({ damage _x >= 0.7 } count _cargo);
|
private _cargoDamaged = ({ damage _x >= 0.7 } count _cargo);
|
||||||
|
|
||||||
if (_time isNotEqualTo -1) then {
|
if (_timeLimit isNotEqualTo 0) then {
|
||||||
private _timeExpired = (floor time - _startTime >= _time);
|
private _timeExpired = (floor time - _startTime >= _timeLimit);
|
||||||
|
|
||||||
if (_cargoDamaged >= _limitFail) then { _result = 1; };
|
if (_cargoDamaged >= _limitFail) then { _result = 1; };
|
||||||
if (_cargoDelivered < _limitSuccess && _timeExpired) then { _result = 1; };
|
if (_cargoDelivered < _limitSuccess && _timeExpired) then { _result = 1; };
|
||||||
|
|||||||
@ -63,7 +63,7 @@ private _taskPos = if (_cargoEntities isNotEqualTo []) then {
|
|||||||
["ratingSuccess", _logic getVariable ["RatingSuccess", 0]],
|
["ratingSuccess", _logic getVariable ["RatingSuccess", 0]],
|
||||||
["endSuccess", _logic getVariable ["EndSuccess", false]],
|
["endSuccess", _logic getVariable ["EndSuccess", false]],
|
||||||
["endFail", _logic getVariable ["EndFail", false]],
|
["endFail", _logic getVariable ["EndFail", false]],
|
||||||
["timeLimit", _logic getVariable ["TimeLimit", -1]],
|
["timeLimit", _logic getVariable ["TimeLimit", 0]],
|
||||||
["deliveryZone", _logic getVariable ["DeliveryZone", ""]]
|
["deliveryZone", _logic getVariable ["DeliveryZone", ""]]
|
||||||
]
|
]
|
||||||
] call FUNC(startTask);
|
] call FUNC(startTask);
|
||||||
|
|||||||
@ -13,7 +13,7 @@
|
|||||||
* 5: Amount of rating the company and player recieve if the task is successful <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)
|
* 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)
|
* 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)
|
* 8: Amount of time before target(s) escape <NUMBER> (default: 0, 0 = no limit)
|
||||||
* 9: Equipment rewards <ARRAY> (default: [])
|
* 9: Equipment rewards <ARRAY> (default: [])
|
||||||
* 10: Supply rewards <ARRAY> (default: [])
|
* 10: Supply rewards <ARRAY> (default: [])
|
||||||
* 11: Weapon rewards <ARRAY> (default: [])
|
* 11: Weapon rewards <ARRAY> (default: [])
|
||||||
@ -39,7 +39,7 @@ params [
|
|||||||
["_ratingSuccess", 0, [0]],
|
["_ratingSuccess", 0, [0]],
|
||||||
["_endSuccess", false, [false]],
|
["_endSuccess", false, [false]],
|
||||||
["_endFail", false, [false]],
|
["_endFail", false, [false]],
|
||||||
["_time", -1, [0]],
|
["_timeLimit", 0, [0]],
|
||||||
["_equipmentRewards", [], [[]]],
|
["_equipmentRewards", [], [[]]],
|
||||||
["_supplyRewards", [], [[]]],
|
["_supplyRewards", [], [[]]],
|
||||||
["_weaponRewards", [], [[]]],
|
["_weaponRewards", [], [[]]],
|
||||||
@ -58,7 +58,7 @@ waitUntil {
|
|||||||
};
|
};
|
||||||
|
|
||||||
_targets = GVAR(TaskStore) call ["getTaskEntities", ["targets", _taskID]];
|
_targets = GVAR(TaskStore) call ["getTaskEntities", ["targets", _taskID]];
|
||||||
private _startTime = if (!isNil "_time") then { floor(time) } else { nil };
|
private _startTime = if (_timeLimit isNotEqualTo 0) then { floor(time) } else { nil };
|
||||||
|
|
||||||
waitUntil {
|
waitUntil {
|
||||||
sleep 1;
|
sleep 1;
|
||||||
@ -66,8 +66,8 @@ waitUntil {
|
|||||||
|
|
||||||
private _targetsDestroyed = ({ !alive _x } count _targets);
|
private _targetsDestroyed = ({ !alive _x } count _targets);
|
||||||
|
|
||||||
if (!isNil "_time") then {
|
if (_timeLimit isNotEqualTo 0) then {
|
||||||
private _timeExpired = (floor time - _startTime >= _time);
|
private _timeExpired = (floor time - _startTime >= _timeLimit);
|
||||||
|
|
||||||
if (_targetsDestroyed < _limitSuccess && _timeExpired) then { _result = 1; };
|
if (_targetsDestroyed < _limitSuccess && _timeExpired) then { _result = 1; };
|
||||||
|
|
||||||
|
|||||||
@ -53,7 +53,7 @@ private _taskPos = if (_syncedEntities isNotEqualTo []) then {
|
|||||||
["ratingSuccess", _logic getVariable ["RatingSuccess", 0]],
|
["ratingSuccess", _logic getVariable ["RatingSuccess", 0]],
|
||||||
["endSuccess", _logic getVariable ["EndSuccess", false]],
|
["endSuccess", _logic getVariable ["EndSuccess", false]],
|
||||||
["endFail", _logic getVariable ["EndFail", false]],
|
["endFail", _logic getVariable ["EndFail", false]],
|
||||||
["timeLimit", _logic getVariable ["TimeLimit", -1]]
|
["timeLimit", _logic getVariable ["TimeLimit", 0]]
|
||||||
]
|
]
|
||||||
] call FUNC(startTask);
|
] call FUNC(startTask);
|
||||||
|
|
||||||
|
|||||||
@ -15,7 +15,7 @@
|
|||||||
* 7: Subcategory of task <ARRAY> (default: [false, true])
|
* 7: Subcategory of task <ARRAY> (default: [false, true])
|
||||||
* 8: Should the mission end (MissionSuccess) if the task is successful <BOOL> (default: 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)
|
* 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)
|
* 10: Amount of time before hostage(s) are executed <NUMBER> (default: 0, 0 = no limit)
|
||||||
* 11: Marker name for the cbrn zone <STRING> (default: "")
|
* 11: Marker name for the cbrn zone <STRING> (default: "")
|
||||||
* 12: Equipment rewards <ARRAY> (default: [])
|
* 12: Equipment rewards <ARRAY> (default: [])
|
||||||
* 13: Supply rewards <ARRAY> (default: [])
|
* 13: Supply rewards <ARRAY> (default: [])
|
||||||
@ -45,7 +45,7 @@ params [
|
|||||||
["_type", [["_cbrn", false, [false]], ["_hostage", true, [false]]]],
|
["_type", [["_cbrn", false, [false]], ["_hostage", true, [false]]]],
|
||||||
["_endSuccess", false, [false]],
|
["_endSuccess", false, [false]],
|
||||||
["_endFail", false, [false]],
|
["_endFail", false, [false]],
|
||||||
["_time", -1, [0]],
|
["_timeLimit", 0, [0]],
|
||||||
["_cbrnZone", "", [""]],
|
["_cbrnZone", "", [""]],
|
||||||
["_equipmentRewards", [], [[]]],
|
["_equipmentRewards", [], [[]]],
|
||||||
["_supplyRewards", [], [[]]],
|
["_supplyRewards", [], [[]]],
|
||||||
@ -75,7 +75,7 @@ waitUntil {
|
|||||||
|
|
||||||
_hostages = GVAR(TaskStore) call ["getTaskEntities", ["hostages", _taskID]];
|
_hostages = GVAR(TaskStore) call ["getTaskEntities", ["hostages", _taskID]];
|
||||||
_shooters = GVAR(TaskStore) call ["getTaskEntities", ["shooters", _taskID]];
|
_shooters = GVAR(TaskStore) call ["getTaskEntities", ["shooters", _taskID]];
|
||||||
private _startTime = if (_time isNotEqualTo -1) then { floor(time) } else { nil };
|
private _startTime = if (_timeLimit isNotEqualTo 0) then { floor(time) } else { nil };
|
||||||
|
|
||||||
waitUntil {
|
waitUntil {
|
||||||
sleep 1;
|
sleep 1;
|
||||||
@ -86,8 +86,8 @@ waitUntil {
|
|||||||
private _hostagesKilled = ({ !alive _x } count _hostages);
|
private _hostagesKilled = ({ !alive _x } count _hostages);
|
||||||
private _shootersAlive = ({ alive _x } count _shooters);
|
private _shootersAlive = ({ alive _x } count _shooters);
|
||||||
|
|
||||||
if (_time isNotEqualTo -1) then {
|
if (_timeLimit isNotEqualTo 0) then {
|
||||||
private _timeExpired = (floor time - _startTime >= _time);
|
private _timeExpired = (floor time - _startTime >= _timeLimit);
|
||||||
|
|
||||||
if (_hostagesFreed < _limitSuccess && _timeExpired) then { _result = 1; };
|
if (_hostagesFreed < _limitSuccess && _timeExpired) then { _result = 1; };
|
||||||
if (_hostagesKilled >= _limitFail) then { _result = 1; };
|
if (_hostagesKilled >= _limitFail) then { _result = 1; };
|
||||||
|
|||||||
@ -67,7 +67,7 @@ private _taskPos = if (_hostageEntities isNotEqualTo []) then {
|
|||||||
["ratingSuccess", _logic getVariable ["RatingSuccess", 0]],
|
["ratingSuccess", _logic getVariable ["RatingSuccess", 0]],
|
||||||
["endSuccess", _logic getVariable ["EndSuccess", false]],
|
["endSuccess", _logic getVariable ["EndSuccess", false]],
|
||||||
["endFail", _logic getVariable ["EndFail", false]],
|
["endFail", _logic getVariable ["EndFail", false]],
|
||||||
["timeLimit", _logic getVariable ["TimeLimit", -1]],
|
["timeLimit", _logic getVariable ["TimeLimit", 0]],
|
||||||
["extractionZone", _logic getVariable ["ExtZone", ""]],
|
["extractionZone", _logic getVariable ["ExtZone", ""]],
|
||||||
["cbrn", _logic getVariable ["CBRN", false]],
|
["cbrn", _logic getVariable ["CBRN", false]],
|
||||||
["execution", _logic getVariable ["Execution", false]],
|
["execution", _logic getVariable ["Execution", false]],
|
||||||
|
|||||||
@ -15,7 +15,7 @@
|
|||||||
* 7: Subcategory of task <ARRAY> (default: [true, false])
|
* 7: Subcategory of task <ARRAY> (default: [true, false])
|
||||||
* 8: Should the mission end (MissionSuccess) if the task is successful <BOOL> (default: 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)
|
* 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)
|
* 10: Amount of time before HVT task fails <NUMBER> (default: 0, 0 = no limit)
|
||||||
* 11: Equipment rewards <ARRAY> (default: [])
|
* 11: Equipment rewards <ARRAY> (default: [])
|
||||||
* 12: Supply rewards <ARRAY> (default: [])
|
* 12: Supply rewards <ARRAY> (default: [])
|
||||||
* 13: Weapon rewards <ARRAY> (default: [])
|
* 13: Weapon rewards <ARRAY> (default: [])
|
||||||
@ -45,7 +45,7 @@ params [
|
|||||||
["_type", [["_capture", true, [false]], ["_eliminate", false, [false]]]],
|
["_type", [["_capture", true, [false]], ["_eliminate", false, [false]]]],
|
||||||
["_endSuccess", false, [false]],
|
["_endSuccess", false, [false]],
|
||||||
["_endFail", false, [false]],
|
["_endFail", false, [false]],
|
||||||
["_time", -1, [0]],
|
["_timeLimit", 0, [0]],
|
||||||
["_equipmentRewards", [], [[]]],
|
["_equipmentRewards", [], [[]]],
|
||||||
["_supplyRewards", [], [[]]],
|
["_supplyRewards", [], [[]]],
|
||||||
["_weaponRewards", [], [[]]],
|
["_weaponRewards", [], [[]]],
|
||||||
@ -66,7 +66,7 @@ waitUntil {
|
|||||||
};
|
};
|
||||||
|
|
||||||
_hvts = GVAR(TaskStore) call ["getTaskEntities", ["hvts", _taskID]];
|
_hvts = GVAR(TaskStore) call ["getTaskEntities", ["hvts", _taskID]];
|
||||||
private _startTime = if (!isNil "_time") then { floor(time) } else { nil };
|
private _startTime = if (_timeLimit isNotEqualTo 0) then { floor(time) } else { nil };
|
||||||
|
|
||||||
waitUntil {
|
waitUntil {
|
||||||
sleep 1;
|
sleep 1;
|
||||||
@ -76,8 +76,8 @@ waitUntil {
|
|||||||
private _hvtsKilled = ({ !alive _x } count _hvts);
|
private _hvtsKilled = ({ !alive _x } count _hvts);
|
||||||
private _hvtsInZone = ({ _x inArea _extZone } count _hvts);
|
private _hvtsInZone = ({ _x inArea _extZone } count _hvts);
|
||||||
|
|
||||||
if (!isNil "_time") then {
|
if (_timeLimit isNotEqualTo 0) then {
|
||||||
private _timeExpired = (floor time - _startTime >= _time);
|
private _timeExpired = (floor time - _startTime >= _timeLimit);
|
||||||
|
|
||||||
if (_capture && _hvtsKilled >= _limitFail) then { _result = 1; };
|
if (_capture && _hvtsKilled >= _limitFail) then { _result = 1; };
|
||||||
if (_capture && _hvtsCaptive < _limitSuccess && _timeExpired) then { _result = 1; };
|
if (_capture && _hvtsCaptive < _limitSuccess && _timeExpired) then { _result = 1; };
|
||||||
|
|||||||
@ -59,7 +59,7 @@ private _taskPos = if (_syncedEntities isNotEqualTo []) then {
|
|||||||
["ratingSuccess", _logic getVariable ["RatingSuccess", 0]],
|
["ratingSuccess", _logic getVariable ["RatingSuccess", 0]],
|
||||||
["endSuccess", _logic getVariable ["EndSuccess", false]],
|
["endSuccess", _logic getVariable ["EndSuccess", false]],
|
||||||
["endFail", _logic getVariable ["EndFail", false]],
|
["endFail", _logic getVariable ["EndFail", false]],
|
||||||
["timeLimit", _logic getVariable ["TimeLimit", -1]],
|
["timeLimit", _logic getVariable ["TimeLimit", 0]],
|
||||||
["extractionZone", _logic getVariable ["ExtZone", ""]],
|
["extractionZone", _logic getVariable ["ExtZone", ""]],
|
||||||
["captureHvt", _logic getVariable ["CaptureHVT", true]]
|
["captureHvt", _logic getVariable ["CaptureHVT", true]]
|
||||||
]
|
]
|
||||||
|
|||||||
@ -2,12 +2,12 @@
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Author: IDSolutions
|
* Author: IDSolutions
|
||||||
* Assigns an IED to a task and starts countdown timer
|
* Assigns an IED to a task and starts its required countdown timer
|
||||||
*
|
*
|
||||||
* Arguments:
|
* Arguments:
|
||||||
* 0: The object <OBJECT>
|
* 0: The object <OBJECT>
|
||||||
* 1: ID of the task <STRING>
|
* 1: ID of the task <STRING>
|
||||||
* 2: The Countdown Timer <NUMBER>
|
* 2: Countdown timer in seconds <NUMBER> (must be greater than 0)
|
||||||
*
|
*
|
||||||
* Return Value:
|
* Return Value:
|
||||||
* None
|
* None
|
||||||
@ -22,7 +22,7 @@ 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 (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 (_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); };
|
if (_time <= 0) exitWith { ["ERROR", "Invalid time provided for IED"] call EFUNC(common,log); };
|
||||||
|
|
||||||
["INFO", format ["Make IED: %1", _this]] call EFUNC(common,log);
|
["INFO", format ["Make IED: %1", _this]] call EFUNC(common,log);
|
||||||
|
|
||||||
|
|||||||
@ -29,12 +29,12 @@
|
|||||||
* "ratingSuccess" <NUMBER> (default: 0)
|
* "ratingSuccess" <NUMBER> (default: 0)
|
||||||
* "endSuccess" <BOOL> (default: false)
|
* "endSuccess" <BOOL> (default: false)
|
||||||
* "endFail" <BOOL> (default: false)
|
* "endFail" <BOOL> (default: false)
|
||||||
* "timeLimit" <NUMBER> (default: -1, -1 = no limit)
|
* "timeLimit" <NUMBER> (default: 0, 0 = no limit)
|
||||||
* Reward keys:
|
* Reward keys:
|
||||||
* "equipment" <ARRAY>, "supplies" <ARRAY>, "weapons" <ARRAY>,
|
* "equipment" <ARRAY>, "supplies" <ARRAY>, "weapons" <ARRAY>,
|
||||||
* "vehicles" <ARRAY>, "special" <ARRAY>
|
* "vehicles" <ARRAY>, "special" <ARRAY>
|
||||||
* Type-specific keys:
|
* Type-specific keys:
|
||||||
* defuse: "iedTimer" <NUMBER> -- IED countdown in seconds (default: 0)
|
* defuse: "iedTimer" <NUMBER> -- required IED countdown in seconds (> 0)
|
||||||
* delivery: "deliveryZone" <STRING> -- marker name
|
* delivery: "deliveryZone" <STRING> -- marker name
|
||||||
* hostage: "extractionZone" <STRING> -- marker name
|
* hostage: "extractionZone" <STRING> -- marker name
|
||||||
* "cbrn" <BOOL> (default: false)
|
* "cbrn" <BOOL> (default: false)
|
||||||
@ -138,7 +138,7 @@ private _ratingFail = _taskParams getOrDefault ["ratingFail", 0];
|
|||||||
private _ratingSuccess = _taskParams getOrDefault ["ratingSuccess", 0];
|
private _ratingSuccess = _taskParams getOrDefault ["ratingSuccess", 0];
|
||||||
private _endSuccess = _taskParams getOrDefault ["endSuccess", false];
|
private _endSuccess = _taskParams getOrDefault ["endSuccess", false];
|
||||||
private _endFail = _taskParams getOrDefault ["endFail", false];
|
private _endFail = _taskParams getOrDefault ["endFail", false];
|
||||||
private _timeLimit = _taskParams getOrDefault ["timeLimit", -1];
|
private _timeLimit = _taskParams getOrDefault ["timeLimit", 0];
|
||||||
private _equipRewards = _taskParams getOrDefault ["equipment", []];
|
private _equipRewards = _taskParams getOrDefault ["equipment", []];
|
||||||
private _supplyRewards = _taskParams getOrDefault ["supplies", []];
|
private _supplyRewards = _taskParams getOrDefault ["supplies", []];
|
||||||
private _weaponRewards = _taskParams getOrDefault ["weapons", []];
|
private _weaponRewards = _taskParams getOrDefault ["weapons", []];
|
||||||
@ -150,8 +150,7 @@ private _rewardTail = [_equipRewards, _supplyRewards, _weaponRewards, _vehicleRe
|
|||||||
private _handlerArgs = switch (_taskType) do {
|
private _handlerArgs = switch (_taskType) do {
|
||||||
case "attack";
|
case "attack";
|
||||||
case "destroy": {
|
case "destroy": {
|
||||||
private _args = [_taskID, _limitFail, _limitSuccess, _funds, _ratingFail, _ratingSuccess, _endSuccess, _endFail];
|
private _args = [_taskID, _limitFail, _limitSuccess, _funds, _ratingFail, _ratingSuccess, _endSuccess, _endFail, _timeLimit];
|
||||||
if (_timeLimit >= 0) then { _args pushBack _timeLimit; };
|
|
||||||
_args + _rewardTail
|
_args + _rewardTail
|
||||||
};
|
};
|
||||||
case "defuse": {
|
case "defuse": {
|
||||||
@ -159,8 +158,7 @@ private _handlerArgs = switch (_taskType) do {
|
|||||||
};
|
};
|
||||||
case "delivery": {
|
case "delivery": {
|
||||||
private _deliveryZone = _taskParams getOrDefault ["deliveryZone", ""];
|
private _deliveryZone = _taskParams getOrDefault ["deliveryZone", ""];
|
||||||
private _args = [_taskID, _limitFail, _limitSuccess, _deliveryZone, _funds, _ratingFail, _ratingSuccess, _endSuccess, _endFail];
|
private _args = [_taskID, _limitFail, _limitSuccess, _deliveryZone, _funds, _ratingFail, _ratingSuccess, _endSuccess, _endFail, _timeLimit];
|
||||||
if (_timeLimit >= 0) then { _args pushBack _timeLimit; };
|
|
||||||
_args + _rewardTail
|
_args + _rewardTail
|
||||||
};
|
};
|
||||||
case "hostage": {
|
case "hostage": {
|
||||||
@ -168,18 +166,14 @@ private _handlerArgs = switch (_taskType) do {
|
|||||||
private _cbrn = _taskParams getOrDefault ["cbrn", false];
|
private _cbrn = _taskParams getOrDefault ["cbrn", false];
|
||||||
private _execution = _taskParams getOrDefault ["execution", false];
|
private _execution = _taskParams getOrDefault ["execution", false];
|
||||||
private _cbrnZone = _taskParams getOrDefault ["cbrnZone", ""];
|
private _cbrnZone = _taskParams getOrDefault ["cbrnZone", ""];
|
||||||
private _args = [_taskID, _limitFail, _limitSuccess, _extZone, _funds, _ratingFail, _ratingSuccess, [_cbrn, _execution], _endSuccess, _endFail];
|
private _args = [_taskID, _limitFail, _limitSuccess, _extZone, _funds, _ratingFail, _ratingSuccess, [_cbrn, _execution], _endSuccess, _endFail, _timeLimit];
|
||||||
if (_timeLimit >= 0) then {
|
_args pushBack _cbrnZone;
|
||||||
_args pushBack _timeLimit;
|
|
||||||
_args pushBack _cbrnZone;
|
|
||||||
};
|
|
||||||
_args + _rewardTail
|
_args + _rewardTail
|
||||||
};
|
};
|
||||||
case "hvt": {
|
case "hvt": {
|
||||||
private _extZone = _taskParams getOrDefault ["extractionZone", ""];
|
private _extZone = _taskParams getOrDefault ["extractionZone", ""];
|
||||||
private _captureHvt = _taskParams getOrDefault ["captureHvt", true];
|
private _captureHvt = _taskParams getOrDefault ["captureHvt", true];
|
||||||
private _args = [_taskID, _limitFail, _limitSuccess, _extZone, _funds, _ratingFail, _ratingSuccess, [_captureHvt, !_captureHvt], _endSuccess, _endFail];
|
private _args = [_taskID, _limitFail, _limitSuccess, _extZone, _funds, _ratingFail, _ratingSuccess, [_captureHvt, !_captureHvt], _endSuccess, _endFail, _timeLimit];
|
||||||
if (_timeLimit >= 0) then { _args pushBack _timeLimit; };
|
|
||||||
_args + _rewardTail
|
_args + _rewardTail
|
||||||
};
|
};
|
||||||
case "defend": {
|
case "defend": {
|
||||||
@ -188,8 +182,7 @@ private _handlerArgs = switch (_taskType) do {
|
|||||||
private _waveCount = _taskParams getOrDefault ["waveCount", 3];
|
private _waveCount = _taskParams getOrDefault ["waveCount", 3];
|
||||||
private _waveCooldown = _taskParams getOrDefault ["waveCooldown", 300];
|
private _waveCooldown = _taskParams getOrDefault ["waveCooldown", 300];
|
||||||
private _minBlufor = _taskParams getOrDefault ["minBlufor", 1];
|
private _minBlufor = _taskParams getOrDefault ["minBlufor", 1];
|
||||||
[_taskID, _defenseZone, _defendTime, _funds, _ratingFail, _ratingSuccess, _endSuccess, _endFail,
|
[_taskID, _defenseZone, _defendTime, _funds, _ratingFail, _ratingSuccess, _endSuccess, _endFail, _waveCount, _waveCooldown, _minBlufor] + _rewardTail
|
||||||
_waveCount, _waveCooldown, _minBlufor] + _rewardTail
|
|
||||||
};
|
};
|
||||||
default {
|
default {
|
||||||
["ERROR", format ["startTask: unknown task type '%1'.", _taskType]] call EFUNC(common,log);
|
["ERROR", format ["startTask: unknown task type '%1'.", _taskType]] call EFUNC(common,log);
|
||||||
|
|||||||
@ -29,7 +29,7 @@ docs/ Framework-level documentation
|
|||||||
| Organization | Player organizations, membership, treasury, credit lines, shared assets, and fleet data. | `arma/client/addons/org` | `arma/server/addons/org` | `lib/models/src/org.rs`, `lib/services/src/org.rs` | `org:*`, `org:hot:*` |
|
| Organization | Player organizations, membership, treasury, credit lines, shared assets, and fleet data. | `arma/client/addons/org` | `arma/server/addons/org` | `lib/models/src/org.rs`, `lib/services/src/org.rs` | `org:*`, `org:hot:*` |
|
||||||
| Phone | Contacts, messages, and email state. | `arma/client/addons/phone` | `arma/server/addons/phone` | `lib/models/src/phone.rs`, `lib/services/src/phone.rs` | `phone:*` |
|
| Phone | Contacts, messages, and email state. | `arma/client/addons/phone` | `arma/server/addons/phone` | `lib/models/src/phone.rs`, `lib/services/src/phone.rs` | `phone:*` |
|
||||||
| Store | Storefront entity setup, catalog hydration, checkout workflows, and checkout charging integration. | `arma/client/addons/store` | `arma/server/addons/store` | `lib/models/src/store.rs`, `lib/services/src/store.rs` | `store:checkout` |
|
| Store | Storefront entity setup, catalog hydration, checkout workflows, and checkout charging integration. | `arma/client/addons/store` | `arma/server/addons/store` | `lib/models/src/store.rs`, `lib/services/src/store.rs` | `store:checkout` |
|
||||||
| Task | Mission/task catalog, ownership, status, reward context, and task counters. | none | `arma/server/addons/task` | `lib/models/src/task.rs`, `lib/services/src/task.rs` | `task:*` |
|
| Task | Server-owned mission/task flows, catalog, ownership, status, participant tracking, rewards, and defuse counters. | none | `arma/server/addons/task` | `lib/models/src/task.rs`, `lib/services/src/task.rs` | `task:*` |
|
||||||
| Owned Garage | Organization or owner-scoped vehicle unlock storage. | via garage/org UI | server extension only | `lib/models/src/v_garage.rs`, `lib/services/src/v_garage.rs` | `owned:garage:*` |
|
| Owned Garage | Organization or owner-scoped vehicle unlock storage. | via garage/org UI | server extension only | `lib/models/src/v_garage.rs`, `lib/services/src/v_garage.rs` | `owned:garage:*` |
|
||||||
| Owned Locker | Organization or owner-scoped arsenal unlock storage. | via locker/org UI | server extension only | `lib/models/src/v_locker.rs`, `lib/services/src/v_locker.rs` | `owned:locker:*` |
|
| Owned Locker | Organization or owner-scoped arsenal unlock storage. | via locker/org UI | server extension only | `lib/models/src/v_locker.rs`, `lib/services/src/v_locker.rs` | `owned:locker:*` |
|
||||||
|
|
||||||
|
|||||||
@ -4,6 +4,20 @@ The task module stores transient mission task metadata for active server or
|
|||||||
mission lifecycle workflows. SQF still owns Arma-only runtime state such as
|
mission lifecycle workflows. SQF still owns Arma-only runtime state such as
|
||||||
objects and participants.
|
objects and participants.
|
||||||
|
|
||||||
|
The server addon at `arma/server/addons/task` also owns task execution:
|
||||||
|
creating BIS tasks, registering task entities, tracking participants, binding
|
||||||
|
task ownership, applying player/org rewards, and clearing task state when a
|
||||||
|
task completes.
|
||||||
|
|
||||||
|
Runtime dependencies:
|
||||||
|
|
||||||
|
- `forge_server_extension`
|
||||||
|
- `forge_server_common`
|
||||||
|
- `forge_server_actor`
|
||||||
|
- `forge_server_bank`
|
||||||
|
- `forge_server_org`
|
||||||
|
- `forge_client_notifications`
|
||||||
|
|
||||||
## Data Model
|
## Data Model
|
||||||
|
|
||||||
Catalog entries are flexible JSON objects. The service normalizes these fields
|
Catalog entries are flexible JSON objects. The service normalizes these fields
|
||||||
@ -102,6 +116,78 @@ private _context = fromJSON (_result select 0);
|
|||||||
|
|
||||||
The reward context contains `requesterUid` and `orgId`.
|
The reward context contains `requesterUid` and `orgId`.
|
||||||
|
|
||||||
|
## Server Task Flows
|
||||||
|
|
||||||
|
The task addon provides these server-owned task flows:
|
||||||
|
|
||||||
|
- `attack`
|
||||||
|
- `defend`
|
||||||
|
- `defuse`
|
||||||
|
- `delivery`
|
||||||
|
- `destroy`
|
||||||
|
- `hostage`
|
||||||
|
- `hvt`
|
||||||
|
|
||||||
|
Use `forge_server_task_fnc_startTask` when creating tasks from modules,
|
||||||
|
mission scripts, or generated mission-manager content. It registers task
|
||||||
|
entities, creates the BIS task, stores the catalog entry, then dispatches
|
||||||
|
through `forge_server_task_fnc_handler`.
|
||||||
|
|
||||||
|
```sqf
|
||||||
|
[
|
||||||
|
"attack",
|
||||||
|
"compound_attack_01",
|
||||||
|
getPosATL leader1,
|
||||||
|
"Attack: East Compound",
|
||||||
|
"Eliminate all hostile forces.",
|
||||||
|
createHashMapFromArray [["targets", [unit1, unit2, unit3]]],
|
||||||
|
createHashMapFromArray [
|
||||||
|
["limitFail", 0],
|
||||||
|
["limitSuccess", 3],
|
||||||
|
["funds", 50000],
|
||||||
|
["ratingFail", -10],
|
||||||
|
["ratingSuccess", 20],
|
||||||
|
["timeLimit", 900]
|
||||||
|
],
|
||||||
|
0,
|
||||||
|
getPlayerUID player,
|
||||||
|
"script"
|
||||||
|
] call forge_server_task_fnc_startTask;
|
||||||
|
```
|
||||||
|
|
||||||
|
Use `forge_server_task_fnc_handler` directly when the task entities are already
|
||||||
|
registered and you want reputation gating plus ownership binding:
|
||||||
|
|
||||||
|
```sqf
|
||||||
|
[
|
||||||
|
"delivery",
|
||||||
|
["delivery_1", 1, 3, "delivery_zone", 250000, -75, 300, false, false, 900],
|
||||||
|
250,
|
||||||
|
getPlayerUID player
|
||||||
|
] call forge_server_task_fnc_handler;
|
||||||
|
```
|
||||||
|
|
||||||
|
Direct task function calls still work for mission-authored or server-owned
|
||||||
|
tasks, but they do not provide a requester UID. Ownership falls back to the
|
||||||
|
`default` org.
|
||||||
|
|
||||||
|
## Timer Semantics
|
||||||
|
|
||||||
|
Task time limits use `0` for no limit:
|
||||||
|
|
||||||
|
- attack `timeLimit`
|
||||||
|
- destroy `timeLimit`
|
||||||
|
- delivery `timeLimit`
|
||||||
|
- hostage `timeLimit`
|
||||||
|
- HVT `timeLimit`
|
||||||
|
|
||||||
|
Positive values are measured in seconds. Do not pass `-1` as a no-limit value;
|
||||||
|
the task runtime treats any non-zero task time limit as active.
|
||||||
|
|
||||||
|
Defuse IED timers are different. `iedTimer` must be greater than `0`, because
|
||||||
|
IEDs are expected to have an active countdown. The Eden defuse module defaults
|
||||||
|
to `300` seconds.
|
||||||
|
|
||||||
## Defuse Counter
|
## Defuse Counter
|
||||||
|
|
||||||
```sqf
|
```sqf
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user