Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Generic functions for getting and setting vehicle cargo inventory #1551

Open
Tuupertunut opened this issue Jul 3, 2022 · 3 comments
Open
Labels

Comments

@Tuupertunut
Copy link

I recently found out that there are no such functions/commands in Arma yet, so I wrote these generic functions for getting and setting vehicle cargo inventory, such as the content of an ammo box. I think these would fit CBA well. I didn't make a PR because I don't know the conventions of the CBA project.

Details

  • They can perfectly represent the state of a vehicle inventory, including
    • non-full magazines with ammo count
    • weapons with attachments
    • backpacks/vests/uniforms with contents
    • backpacks/vests/uniforms containing weapons with attachments and non-full magazines
  • Their function closely resembles Arma commands getUnitLoadout and setUnitLoadout which are meant for unit inventory management.
  • The format of the inventory array closely resembles the one used in getUnitLoadout and setUnitLoadout.
  • fnc_getCargo and fnc_setCargo are both recursive, they are recursively called for any subcontainers (so backpacks, vests...) in the inventory.

Inventory format

Inventory is represented as an array containing the the following types of items:

  • Magazine: ["className", ammoCount]
  • Weapon: ["className", "suppressor", "pointer", "optics", ["primaryMag", ammoCount], ["secondaryMag", ammoCount], "bipod"]
  • Subcontainer (backpack, vest, uniform): ["className", [container inventory...]]
    • The subcontainer inventory uses this same format.
  • Simple item (compass, first aid kit, etc.): "className"

Example output of fnc_getCargo:

[
    ["30Rnd_556x45_Stanag",30],
    ["30Rnd_556x45_Stanag",30],
    ["arifle_Mk20_GL_ACO_F","","","optic_ACO_grn",["30Rnd_556x45_Stanag",30],["1Rnd_HE_Grenade_shell",1],""],
    ["B_TacticalPack_oli",[
        ["HandGrenade",1],
        ["HandGrenade",1],
        ["hgun_ACPC2_F","","","",["9Rnd_45ACP_Mag",9],[],""],
        ["V_PlateCarrierIAGL_dgtl",[]],
        "ItemRadio"
    ]],
    "FirstAidKit"
]

Functions

fnc_isCargoEmpty

Parameters:
vehicle: Object

Return value:
Boolean

fnc_isCargoEmpty = {
    count (magazineCargo _this + weaponCargo _this + backpackCargo _this + itemCargo _this) == 0
};

fnc_getCargo

Parameters:
vehicle: Object

Return value:
Array - Inventory array

fnc_getCargo = {
    private _container = _this;
    
    // Add magazines in form ["abc", 30]
    private _content = magazinesAmmoCargo _container;

    // Add weapons in form ["abc", "", "", "", ["mag", 30], [], ""]
    _content append (weaponsItemsCargo _container);

    // Add containers (backpacks, vests, uniforms) in form ["abc", [container content...]]
    // This function is called recursively to get subcontainer content.
    private _subContainers = everyContainer _container;
    _content append (_subContainers apply {[_x # 0, (_x # 1 call fnc_getCargo)]});

    // Add other items in form "abc", excluding containers because they are already added.
    _content append (itemCargo _container - (_subContainers apply {_x # 0}));
    
    _content
};

fnc_setCargo

Parameters:
[
vehicle: Object
content: Array - Inventory array
]

Return value:
Nothing

fnc_setCargo = {
    private _container = _this # 0;
    private _content = _this # 1;

    // Clear container of all previous content.
    clearMagazineCargoGlobal _container;
    clearWeaponCargoGlobal _container;
    clearBackpackCargoGlobal _container;
    clearItemCargoGlobal _container;

    // Add new content.
    {
        private _item = _x;

        // Is item a simple item? Form: "abc"
        if (_item isEqualType "") then {
            _container addItemCargoGlobal [_item, 1];

        // Is item a magazine? Form: ["abc", 30]
        } else {if (_item # 1 isEqualType 0) then {
            _container addMagazineAmmoCargo [_item # 0, 1, _item # 1];

        // Is item a weapon? Form: ["abc", "", "", "", ["mag", 30], [], ""]
        } else {if (_item # 1 isEqualType "") then {
            _container addWeaponWithAttachmentsCargoGlobal [_item, 1];

        // Is item a container? Form: ["abc", [container content...]]
        } else {
            private _subContainerClass = _item # 0;
            private _subContainerContent = _item # 1;

            // Backpacks need to be added with a different command than vests and uniforms.
            if (getNumber (configFile >> "CfgVehicles" >> _subContainerClass >> "isbackpack") == 1) then {
                _container addBackpackCargoGlobal [_subContainerClass, 1];
            } else {
                _container addItemCargoGlobal [_subContainerClass, 1];
            };

            // Add content to the newly added subcontainer.
            // This is somewhat expensive so only do it if there is content to be added.
            if (count _subContainerContent > 0) then {

                // The only way to get the container object of the newly added subcontainer is to list all container
                // objects and search for the one that we added. It is probably at the end of the array, so searching in
                // reverse order. The first that has the same class name, and is empty, is the one we are looking for.
                private _subContainers = everyContainer _container;
                reverse _subContainers;
                private _added = _subContainers # (_subContainers findIf {
                    _x # 0 isEqualTo _subContainerClass && {_x # 1 call fnc_isCargoEmpty}
                });

                // Set the subcontainer content by calling this function recursively on it.
                [_added # 1, _subContainerContent] call fnc_setCargo;
            };
        }}};
    } forEach _content;
};
@rautamiekka
Copy link
Contributor

Good stuff IMO :D

Lines like

    private _container = _this # 0;
    private _content = _this # 1;

are the ancient way, params does it better:

    _this params ["_container","_content"];
    //... or ...
    params ["_container","_content"];

Same result with both, less code with the latter.

@jonpas
Copy link
Member

jonpas commented Sep 7, 2023

I didn't make a PR because I don't know the conventions of the CBA project.

https://github.com/CBATeam/CBA_A3/wiki/Submitting-Content + ACE3 coding standards

@jonpas jonpas added the Feature label Sep 7, 2023
@Tuupertunut
Copy link
Author

Noticed a bug: in fnc_setCargo, the backpack class may come with items already in it, so it should be emptied before adding new contents

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants