Pass garage context through actor menu and update phone docs
- Thread garage object context into garage and vehicle garage launch paths - Preserve nearby garage metadata in the UI and improve garage context resolution - Add wallet and message/email examples to the player guide
@ -37,8 +37,22 @@ switch (_event) do {
|
||||
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); };
|
||||
case "actor::open::garage": {
|
||||
private _garageObject = objNull;
|
||||
if (_data isEqualType createHashMap) then {
|
||||
private _netId = _data getOrDefault ["netId", ""];
|
||||
if (_netId isNotEqualTo "") then { _garageObject = objectFromNetId _netId; };
|
||||
};
|
||||
[_garageObject] spawn EFUNC(garage,openUI);
|
||||
};
|
||||
case "actor::open::vgarage": {
|
||||
private _garageObject = objNull;
|
||||
if (_data isEqualType createHashMap) then {
|
||||
private _netId = _data getOrDefault ["netId", ""];
|
||||
if (_netId isNotEqualTo "") then { _garageObject = objectFromNetId _netId; };
|
||||
};
|
||||
[_garageObject] spawn EFUNC(garage,openVG);
|
||||
};
|
||||
case "actor::open::org": { [] spawn EFUNC(org,openUI); };
|
||||
case "actor::open::vlocker": { [FORGE_Locker_Box, player, false] spawn AFUNC(arsenal,openBox) };
|
||||
case "actor::open::phone": { [] spawn EFUNC(phone,openUI); };
|
||||
|
||||
@ -114,6 +114,11 @@ GVAR(ActorRepositoryBaseClass) = compileFinal createHashMapFromArray [
|
||||
private _isLocker = _x getVariable ["isLocker", false];
|
||||
private _isStore = _x getVariable ["isStore", false];
|
||||
private _garageType = _x getVariable ["garageType", ""];
|
||||
private _garageContext = createHashMapFromArray [
|
||||
["netId", netId _x],
|
||||
["name", vehicleVarName _x],
|
||||
["garageType", _garageType]
|
||||
];
|
||||
private _deviceType = _x getVariable ["deviceType", ""];
|
||||
private _isPlayer = _x isKindOf "Man" && isPlayer _x;
|
||||
|
||||
@ -121,8 +126,8 @@ GVAR(ActorRepositoryBaseClass) = compileFinal createHashMapFromArray [
|
||||
if (_isAtm) then { _nearbyActions pushBack ["atm", true]; };
|
||||
if (_isBank) then { _nearbyActions pushBack ["bank", true]; };
|
||||
if (_isLocker && GVAR(enableVA)) then { _nearbyActions pushBack ["va", true]; };
|
||||
if (_isGarage) then { _nearbyActions pushBack ["garage", _garageType]; };
|
||||
if (_isGarage && GVAR(enableVG)) then { _nearbyActions pushBack ["vg", true]; };
|
||||
if (_isGarage) then { _nearbyActions pushBack ["garage", _garageContext]; };
|
||||
if (_isGarage && GVAR(enableVG)) then { _nearbyActions pushBack ["vg", _garageContext]; };
|
||||
if (_deviceType isNotEqualTo "") then { _nearbyActions pushBack ["device", _deviceType]; };
|
||||
if (_isPlayer && { _x isNotEqualTo player }) then { _nearbyActions pushBack ["player", name _x]; };
|
||||
} forEach (player nearObjects 5);
|
||||
|
||||
@ -215,7 +215,21 @@ function actorReducer(state = initialState, action) {
|
||||
const [type, value] = actionItem;
|
||||
const definition = state.actionDefinitions[type];
|
||||
if (definition) {
|
||||
newMenuItems.push(definition);
|
||||
const context =
|
||||
value && typeof value === "object"
|
||||
? value
|
||||
: { value };
|
||||
const garageLabel =
|
||||
context.name || context.garageType || "";
|
||||
const title =
|
||||
["garage", "vg"].includes(type) && garageLabel
|
||||
? `${definition.title}: ${garageLabel}`
|
||||
: definition.title;
|
||||
newMenuItems.push({
|
||||
...definition,
|
||||
title,
|
||||
context,
|
||||
});
|
||||
} else {
|
||||
console.warn(
|
||||
`No definition found for: ${type} - ${value}`,
|
||||
@ -414,7 +428,7 @@ function RadialMenu() {
|
||||
console.log("Menu item clicked:", item);
|
||||
const alert = {
|
||||
event: item.action,
|
||||
data: {},
|
||||
data: item.context || {},
|
||||
};
|
||||
if (typeof A3API !== "undefined") {
|
||||
A3API.SendAlert(JSON.stringify(alert));
|
||||
|
||||
@ -22,8 +22,35 @@
|
||||
#pragma hemtt ignore_variables ["_self"]
|
||||
GVAR(GarageContextServiceBaseClass) = compileFinal createHashMapFromArray [
|
||||
["#type", "GarageContextServiceBaseClass"],
|
||||
["#create", compileFinal { _self set ["lastContext", createHashMap]; }],
|
||||
["#delete", compileFinal { _self set ["lastContext", createHashMap]; }],
|
||||
["#create", compileFinal {
|
||||
_self set ["lastContext", createHashMap];
|
||||
_self set ["activeGarageObject", objNull];
|
||||
}],
|
||||
["#delete", compileFinal {
|
||||
_self set ["lastContext", createHashMap];
|
||||
_self set ["activeGarageObject", objNull];
|
||||
}],
|
||||
["setActiveGarageObject", compileFinal {
|
||||
params [["_garageObject", objNull, [objNull]]];
|
||||
|
||||
if (isNull _garageObject || { !(_garageObject getVariable ["isGarage", false]) }) exitWith {
|
||||
_self set ["activeGarageObject", objNull];
|
||||
false
|
||||
};
|
||||
|
||||
_self set ["activeGarageObject", _garageObject];
|
||||
true
|
||||
}],
|
||||
["getActiveGarageObject", compileFinal {
|
||||
private _garageObject = _self getOrDefault ["activeGarageObject", objNull];
|
||||
if (isNull _garageObject || { !(_garageObject getVariable ["isGarage", false]) }) exitWith { objNull };
|
||||
if ((player distance2D _garageObject) > 12) exitWith {
|
||||
_self set ["activeGarageObject", objNull];
|
||||
objNull
|
||||
};
|
||||
|
||||
_garageObject
|
||||
}],
|
||||
["createDefaultContext", compileFinal {
|
||||
createHashMapFromArray [
|
||||
["name", "Vehicle Garage"],
|
||||
@ -184,8 +211,16 @@ GVAR(GarageContextServiceBaseClass) = compileFinal createHashMapFromArray [
|
||||
_spawnLanes getOrDefault [_normalizedCategory, createHashMap]
|
||||
}],
|
||||
["resolveContext", compileFinal {
|
||||
params [["_preferredGarageObject", objNull, [objNull]]];
|
||||
|
||||
private _context = _self call ["createDefaultContext", []];
|
||||
private _garageObject = _self call ["findNearbyGarageObject", []];
|
||||
private _garageObject = _preferredGarageObject;
|
||||
if (isNull _garageObject || { !(_garageObject getVariable ["isGarage", false]) }) then {
|
||||
_garageObject = _self call ["getActiveGarageObject", []];
|
||||
};
|
||||
if (isNull _garageObject) then {
|
||||
_garageObject = _self call ["findNearbyGarageObject", []];
|
||||
};
|
||||
private _garageName = _self call ["resolveGarageName", [_garageObject]];
|
||||
private _garageType = "";
|
||||
private _anchorPosition = getPosATL player;
|
||||
@ -215,7 +250,10 @@ GVAR(GarageContextServiceBaseClass) = compileFinal createHashMapFromArray [
|
||||
_self set ["lastContext", _context];
|
||||
_context
|
||||
}],
|
||||
["getContext", compileFinal { _self call ["resolveContext", []] }],
|
||||
["getContext", compileFinal {
|
||||
params [["_preferredGarageObject", objNull, [objNull]]];
|
||||
_self call ["resolveContext", [_preferredGarageObject]]
|
||||
}],
|
||||
["buildNearbyState", compileFinal {
|
||||
private _context = _self call ["getContext", []];
|
||||
private _anchorPosition = _context getOrDefault ["anchorPosition", []];
|
||||
|
||||
@ -20,6 +20,12 @@
|
||||
* call forge_client_garage_fnc_openUI;
|
||||
*/
|
||||
|
||||
params [["_garageObject", objNull, [objNull]]];
|
||||
|
||||
if (!isNull _garageObject) then {
|
||||
GVAR(GarageContextService) call ["setActiveGarageObject", [_garageObject]];
|
||||
};
|
||||
|
||||
private _display = createDialog ["RscGarage", true];
|
||||
private _ctrl = _display displayCtrl 1006;
|
||||
|
||||
|
||||
@ -20,7 +20,13 @@
|
||||
* call forge_client_garage_fnc_openVG
|
||||
*/
|
||||
|
||||
private _context = GVAR(GarageContextService) call ["getContext", []];
|
||||
params [["_garageObject", objNull, [objNull]]];
|
||||
|
||||
if (!isNull _garageObject) then {
|
||||
GVAR(GarageContextService) call ["setActiveGarageObject", [_garageObject]];
|
||||
};
|
||||
|
||||
private _context = GVAR(GarageContextService) call ["getContext", [_garageObject]];
|
||||
private _spawnLane = GVAR(GarageContextService) call ["getSpawnLane", [_context getOrDefault ["garageType", ""], _context]];
|
||||
|
||||
FORGE_VehSpawnPos = _spawnLane getOrDefault ["spawnPosition", player getPos [8, getDir player]];
|
||||
|
||||
@ -76,7 +76,8 @@ Important task behavior:
|
||||
|
||||
## Phone
|
||||
|
||||
The phone provides contacts, messages, email, and local utility apps.
|
||||
The phone provides contacts, messages, email, mobile bank access, and local
|
||||
utility apps.
|
||||
|
||||

|
||||
|
||||
@ -90,29 +91,34 @@ entering recipient details every time.
|
||||
|
||||
### Messages
|
||||
|
||||
Messages are short player-to-player conversations.
|
||||
Messages are short player-to-player conversations. Use Messages to start or
|
||||
continue a conversation with a contact, read incoming messages, mark messages as
|
||||
read, or delete messages you no longer need.
|
||||
|
||||

|
||||
|
||||
Use Messages to:
|
||||
|
||||
- start or continue a conversation with a contact
|
||||
- read incoming messages
|
||||
- mark messages as read
|
||||
- delete messages you no longer need
|
||||

|
||||
|
||||
### Email
|
||||
|
||||
Email is used for longer player-to-player communication.
|
||||
Email is used for longer player-to-player communication. Use Email to send a
|
||||
subject and body to another player, read incoming mail, mark email as read, or
|
||||
delete old email.
|
||||
|
||||

|
||||
|
||||
Use Email to:
|
||||

|
||||
|
||||
- send a subject and body to another player
|
||||
- read incoming mail
|
||||
- mark email as read
|
||||
- delete old email
|
||||
### Wallet
|
||||
|
||||
Wallet is the phone version of the bank app. Use it to refresh your account
|
||||
view, check your available balance, review cash and pending earnings, deposit all
|
||||
pending earnings, and pay your organization credit line when payment is due.
|
||||
|
||||

|
||||
|
||||
Deposit Earnings deposits the full pending earnings amount. Players do not enter
|
||||
a custom amount for that action.
|
||||
|
||||
### Local Phone Apps
|
||||
|
||||
|
||||
@ -75,7 +75,8 @@ Important task behavior:
|
||||
|
||||
## Phone
|
||||
|
||||
The phone provides contacts, messages, email, and local utility apps.
|
||||
The phone provides contacts, messages, email, mobile bank access, and local
|
||||
utility apps.
|
||||
|
||||

|
||||
|
||||
@ -89,29 +90,34 @@ entering recipient details every time.
|
||||
|
||||
### Messages
|
||||
|
||||
Messages are short player-to-player conversations.
|
||||
Messages are short player-to-player conversations. Use Messages to start or
|
||||
continue a conversation with a contact, read incoming messages, mark messages as
|
||||
read, or delete messages you no longer need.
|
||||
|
||||

|
||||
|
||||
Use Messages to:
|
||||
|
||||
- start or continue a conversation with a contact
|
||||
- read incoming messages
|
||||
- mark messages as read
|
||||
- delete messages you no longer need
|
||||

|
||||
|
||||
### Email
|
||||
|
||||
Email is used for longer player-to-player communication.
|
||||
Email is used for longer player-to-player communication. Use Email to send a
|
||||
subject and body to another player, read incoming mail, mark email as read, or
|
||||
delete old email.
|
||||
|
||||

|
||||
|
||||
Use Email to:
|
||||

|
||||
|
||||
- send a subject and body to another player
|
||||
- read incoming mail
|
||||
- mark email as read
|
||||
- delete old email
|
||||
### Wallet
|
||||
|
||||
Wallet is the phone version of the bank app. Use it to refresh your account
|
||||
view, check your available balance, review cash and pending earnings, deposit all
|
||||
pending earnings, and pay your organization credit line when payment is due.
|
||||
|
||||

|
||||
|
||||
Deposit Earnings deposits the full pending earnings amount. Players do not enter
|
||||
a custom amount for that action.
|
||||
|
||||
### Local Phone Apps
|
||||
|
||||
|
||||
|
Before Width: | Height: | Size: 954 KiB After Width: | Height: | Size: 732 KiB |
|
Before Width: | Height: | Size: 949 KiB After Width: | Height: | Size: 730 KiB |
BIN
docus/public/images/player/phone_email_example.jpg
Normal file
|
After Width: | Height: | Size: 746 KiB |
|
Before Width: | Height: | Size: 966 KiB After Width: | Height: | Size: 743 KiB |
BIN
docus/public/images/player/phone_message_example.jpg
Normal file
|
After Width: | Height: | Size: 754 KiB |
|
Before Width: | Height: | Size: 951 KiB After Width: | Height: | Size: 733 KiB |
BIN
docus/public/images/player/phone_wallet.jpg
Normal file
|
After Width: | Height: | Size: 744 KiB |