Merge remote-tracking branch 'origin/master' into javelinLocking

Conflicts:
	addons/common/XEH_preInit.sqf
This commit is contained in:
jaynus 2015-04-11 14:01:47 -07:00
commit 458c49b0a7
47 changed files with 2212 additions and 171 deletions

View File

@ -39,6 +39,7 @@ PREP(displayText);
PREP(displayTextPicture);
PREP(displayTextStructured);
PREP(doAnimation);
PREP(dropBackpack);
PREP(endRadioTransmission);
PREP(eraseCache);
PREP(execNextFrame);
@ -178,6 +179,9 @@ PREP(useItem);
PREP(useMagazine);
PREP(waitAndExecute);
PREP(translateToWeaponSpace);
PREP(translateToModelSpace);
// Model and drawing helpers
PREP(worldToScreenBounds);

View File

@ -0,0 +1,34 @@
/*
* Author: commy2
*
* Drops a backback. Also returns the ground wepaon holder object of the dropped backpack.
*
* Argument:
* 0: Unit that has a backpack (Object)
*
* Return value:
* Ground wepaon holder with backpack (Object)
*
*/
#include "script_component.hpp"
private "_unit";
_unit = _this select 0;
private "_backpackObject";
_backpackObject = backpackContainer _unit;
_unit addBackpack "Bag_Base";
removeBackpack _unit;
private "_holder";
_holder = objNull;
{
if (_backpackObject in everyBackpack _x) exitWith {
_holder = _x;
};
} forEach (position _unit nearObjects ["WeaponHolder", 5]);
_holder

View File

@ -0,0 +1 @@
z\ace\addons\disarming

View File

@ -0,0 +1,11 @@
class Extended_PreInit_EventHandlers {
class ADDON {
init = QUOTE(call COMPILE_FILE(XEH_preInit));
};
};
class Extended_PostInit_EventHandlers {
class ADDON {
init = QUOTE(call COMPILE_FILE(XEH_postInit));
};
};

View File

@ -0,0 +1,17 @@
class CfgVehicles {
class Man;
class CAManBase: Man {
class ACE_Actions {
class ACE_MainActions {
class ACE_DisarmInventory {
displayName = "$STR_ACE_Disarming_OpenInventory";
distance = 3.5;
condition = QUOTE([ARR_2(_player,_target)] call FUNC(canPlayerDisarmUnit));
statement = QUOTE([ARR_2(_player,_target)] call FUNC(openDisarmDialog));
icon = "\a3\Modules_F_Curator\Data\portraitRespawnInventory_ca.paa";
exceptions[] = {};
};
};
};
};
};

View File

@ -0,0 +1,14 @@
class CfgWeapons {
class ACE_ItemCore;
class InventoryItem_Base_F;
class ACE_DebugPotato: ACE_ItemCore {
displayName = "ACE Potato (debug)";
descriptionShort = "Glorious Potato<br/>If you see this in game it means someone fucked up";
picture = QUOTE(PATHTOF(UI\potato_ca.paa));
scope = 1;
class ItemInfo: InventoryItem_Base_F {
mass = 1;
};
};
};

View File

@ -0,0 +1,11 @@
ace_disarming
============
Adds ability to make units drop items/weapons/magazines.
## Maintainers
The people responsible for merging changes to this component or answering potential questions.
- [PabstMirror](https://github.com/PabstMirror)

Binary file not shown.

View File

@ -0,0 +1,4 @@
#include "script_component.hpp"
["DisarmDropItems", {_this call FUNC(eventTargetStart)}] call EFUNC(common,addEventHandler);
["DisarmDebugCallback", {_this call FUNC(eventCallerFinish)}] call EFUNC(common,addEventHandler);

View File

@ -0,0 +1,17 @@
#include "script_component.hpp"
ADDON = false;
PREP(canBeDisarmed);
PREP(canPlayerDisarmUnit);
PREP(disarmDropItems);
PREP(eventCallerFinish);
PREP(eventTargetFinish);
PREP(eventTargetStart);
PREP(getAllGearContainer);
PREP(getAllGearUnit);
PREP(openDisarmDialog);
PREP(showItemsInListbox);
PREP(verifyMagazinesMoved);
ADDON = true;

View File

@ -0,0 +1,19 @@
#include "script_component.hpp"
class CfgPatches {
class ADDON {
units[] = {};
weapons[] = {"ACE_DebugPotato"};
requiredVersion = REQUIRED_VERSION;
requiredAddons[] = {"ACE_Interaction"};
author[] = {"PabstMirror"};
authorUrl = "https://github.com/PabstMirror/";
VERSION_CONFIG;
};
};
#include "CfgEventHandlers.hpp"
#include "CfgVehicles.hpp"
#include "CfgWeapons.hpp"
#include "gui_disarm.hpp"

View File

@ -0,0 +1,34 @@
/*
* Author: PabstMirror
* Checks the conditions for being able to disarm a unit
*
* Arguments:
* 0: Target <OBJECT>
*
* Return Value:
* Can Be Disarmed <BOOL>
*
* Example:
* [cursorTarget] call ace_disarming_fnc_canBeDisarmed
*
* Public: No
*/
#include "script_component.hpp"
PARAMS_1(_target);
//Check animationState for putDown anim
//This ensures the unit doesn't have to actualy do any animation to drop something
//This should always be true for the 3 possible status effects that allow disarming
_animationStateCfgMoves = getText (configFile >> "CfgMovesMaleSdr" >> "States" >> (animationState _target) >> "actions");
if (_animationStateCfgMoves == "") exitWith {false};
_putDownAnim = getText (configFile >> "CfgMovesBasic" >> "Actions" >> _animationStateCfgMoves >> "PutDown");
if (_putDownAnim != "") exitWith {false};
(alive _target) &&
{(abs (speed _target)) < 1} &&
{(vehicle _target) == _target} &&
{(_target getVariable ["ACE_isUnconscious", false]) ||
{_target getVariable [QEGVAR(captives,isHandcuffed), false]} ||
{_target getVariable [QEGVAR(captives,isSurrendering), false]}}

View File

@ -0,0 +1,22 @@
/*
* Author: PabstMirror
* Checks the conditions for being able to disarm a unit
*
* Arguments:
* 0: Player <OBJECT>
* 1: Target <OBJECT>
*
* Return Value:
* Can Be Disarm Target <BOOL>
*
* Example:
* [player, cursorTarget] call ace_disarming_fnc_canPlayerDisarmUnit
*
* Public: No
*/
#include "script_component.hpp"
PARAMS_2(_player,_target);
([_target] call FUNC(canBeDisarmed)) &&
{([_player, _target, []] call EFUNC(common,canInteractWith))}

View File

@ -0,0 +1,252 @@
/*
* Author: PabstMirror
* Makes a unit drop items
*
* Arguments:
* 0: caller (player) <OBJECT>
* 1: target <OBJECT>
* 2: classnamess <ARRAY>
* 3: Do Not Drop Ammo <BOOL><OPTIONAL>
*
* Return Value:
* Nothing
*
* Example:
* [player, cursorTarget, ["ace_bandage"]] call ace_disarming_fnc_disarmDropItems
*
* Public: No
*/
#include "script_component.hpp"
#define TIME_MAX_WAIT 5
PARAMS_3(_caller,_target,_listOfItemsToRemove);
DEFAULT_PARAM(3,_doNotDropAmmo,false); //By default units drop all weapon mags when dropping a weapon
_fncSumArray = {
_return = 0;
{_return = _return + _x;} forEach (_this select 0);
_return
};
//Sanity Checks
if (!([_target] call FUNC(canBeDisarmed))) exitWith {
[_caller, _target, "Debug: Cannot disarm target"] call FUNC(eventTargetFinish);
};
if (_doNotDropAmmo && {({_x in _listOfItemsToRemove} count (magazines _target)) > 0}) exitWith {
[_caller, _target, "Debug: Trying to drop magazine with _doNotDropAmmo flag"] call FUNC(eventTargetFinish);
};
_holder = objNull;
//If not dropping ammo, don't use an existing container
if (!_doNotDropAmmo) then {
{
if ((_x getVariable [QGVAR(disarmUnit), objNull]) == _target) exitWith {
_holder = _x;
};
} forEach ((getpos _target) nearObjects [DISARM_CONTAINER, 3]);
};
//Create a new weapon holder
if (isNull _holder) then {
_dropPos = _target modelToWorld [0.4, 0.75, 0]; //offset someone unconscious isn't lying over it
_dropPos set [2, ((getPosASL _target) select 2)];
_holder = createVehicle [DISARM_CONTAINER, _dropPos, [], 0, "CAN_COLLIDE"];
_holder setPosASL _dropPos;
_holder setVariable [QGVAR(disarmUnit), _target, true];
};
//Verify holder created
if (isNull _holder) exitWith {
[_caller, _target, "Debug: Null Holder"] call FUNC(eventTargetFinish);
};
//Make sure only one drop operation at a time (using PFEH system as a queue)
if (_holder getVariable [QGVAR(holderInUse), false]) exitWith {
[{
_this call FUNC(disarmDropItems);
}, _this, 0, 0] call EFUNC(common,waitAndExecute);
};
_holder setVariable [QGVAR(holderInUse), true];
//Remove Magazines
_targetMagazinesStart = magazinesAmmo _target;
_holderMagazinesStart = magazinesAmmoCargo _holder;
{
EXPLODE_2_PVT(_x,_xClassname,_xAmmo);
if ((_xClassname in _listOfItemsToRemove) && {!(_xClassname in UNIQUE_MAGAZINES)}) then {
_holder addMagazineAmmoCargo [_xClassname, 1, _xAmmo];
_target removeMagazine _xClassname;
};
} forEach _targetMagazinesStart;
_targetMagazinesEnd = magazinesAmmo _target;
_holderMagazinesEnd = magazinesAmmoCargo _holder;
//Verify Mags dropped from unit:
if ( ({((_x select 0) in _listOfItemsToRemove) && {!((_x select 0) in UNIQUE_MAGAZINES)}} count _targetMagazinesEnd) != 0) exitWith {
_holder setVariable [QGVAR(holderInUse), false];
[_caller, _target, "Debug: Didn't Remove Magazines"] call FUNC(eventTargetFinish);
};
//Verify holder has mags unit had
if (!([_targetMagazinesStart, _targetMagazinesEnd, _holderMagazinesStart, _holderMagazinesEnd] call FUNC(verifyMagazinesMoved))) then {
ERR = [_targetMagazinesStart, _targetMagazinesEnd, _holderMagazinesStart, _holderMagazinesEnd];
_holder setVariable [QGVAR(holderInUse), false];
[_caller, _target, "Debug: Crate Magazines not in holder"] call FUNC(eventTargetFinish);
};
//Remove Items, Assigned Items and NVG
_holderItemsStart = getitemCargo _holder;
_targetItemsStart = (assignedItems _target) + (items _target);
if ((headgear _target) != "") then {_targetItemsStart pushBack (headgear _target);};
if ((goggles _target) != "") then {_targetItemsStart pushBack (goggles _target);};
_addToCrateClassnames = [];
_addToCrateCount = [];
{
if (_x in _listOfItemsToRemove) then {
if (_x in (items _target)) then {
_target removeItem _x;
} else {
_target unlinkItem _x;
};
_index = _addToCrateClassnames find _x;
if (_index != -1) then {
_addToCrateCount set [_index, ((_addToCrateCount select _index) + 1)];
} else {
_addToCrateClassnames pushBack _x;
_addToCrateCount pushBack 1;
};
};
} forEach _targetItemsStart;
//Add the items to the holder (combined to reduce addItemCargoGlobal calls)
{
_holder addItemCargoGlobal [(_addToCrateClassnames select _forEachIndex), (_addToCrateCount select _forEachIndex)];
} forEach _addToCrateClassnames;
_holderItemsEnd = getitemCargo _holder;
_targetItemsEnd = (assignedItems _target) + (items _target);
if ((headgear _target) != "") then {_targetItemsEnd pushBack (headgear _target);};
if ((goggles _target) != "") then {_targetItemsEnd pushBack (goggles _target);};
//Verify Items Added
if (((count _targetItemsStart) - (count _targetItemsEnd)) != ([_addToCrateCount] call _fncSumArray)) exitWith {
_holder setVariable [QGVAR(holderInUse), false];
[_caller, _target, "Debug: Items Not Removed From Player"] call FUNC(eventTargetFinish);
};
if ((([_holderItemsEnd select 1] call _fncSumArray) - ([_holderItemsStart select 1] call _fncSumArray)) != ([_addToCrateCount] call _fncSumArray)) exitWith {
_holder setVariable [QGVAR(holderInUse), false];
[_caller, _target, "Debug: Items Not Added to Holder"] call FUNC(eventTargetFinish);
};
//If holder is still empty, it will be 'garbage collected' while we wait for the drop 'action' to take place
//So add a dummy item and just remove at the end
_holderIsEmpty = ([_holder] call FUNC(getAllGearContainer)) isEqualTo [[],[]];
if (_holderIsEmpty) then {
TRACE_1("Debug: adding dummy item to holder",_holder);
_holder addItemCargoGlobal [DUMMY_ITEM, 1];
};
//Start the PFEH to do the actions (which could take >1 frame)
[{
PARAMS_2(_args,_pfID);
EXPLODE_8_PVT(_args,_caller,_target,_listOfItemsToRemove,_holder,_holderIsEmpty,_maxWaitTime,_doNotDropAmmo,_startingMagazines);
_needToRemoveWeapon = ({_x in _listOfItemsToRemove} count (weapons _target)) > 0;
_needToRemoveMagazines = ({_x in _listOfItemsToRemove} count (magazines _target)) > 0;
_needToRemoveBackpack = ((backPack _target) != "") && {(backPack _target) in _listOfItemsToRemove};
_needToRemoveVest = ((vest _target) != "") && {(vest _target) in _listOfItemsToRemove};
_needToRemoveUniform = ((uniform _target) != "") && {(uniform _target) in _listOfItemsToRemove};
if ((time < _maxWaitTime) && {[_target] call FUNC(canBeDisarmed)} && {_needToRemoveWeapon || _needToRemoveMagazines || _needToRemoveBackpack}) then {
//action drop weapons (keeps loaded magazine and attachements)
{
if (_x in _listOfItemsToRemove) then {
_target action ["DropWeapon", _holder, _x];
};
} forEach (weapons _target);
//Drop magazine (keeps unique ID)
{
if (_x in _listOfItemsToRemove) then {
_target action ["DropMagazine", _holder, _x];
};
} forEach (magazines _target);
//Drop backpack (Keeps variables for ACRE/TFR)
if (_needToRemoveBackpack) then {_target action ["DropBag", _holder, (backPack _target)];};
} else {
[_pfID] call CBA_fnc_removePerFrameHandler;
if (_doNotDropAmmo) then {
_error = false;
_magsToPickup = +_startingMagazines;
{
_index = _magsToPickup find _x;
if (_index == -1) exitWith {_error = true; ERROR("More mags than when we started?")};
_magsToPickup deleteAt _index;
} forEach (magazinesAmmo _target);
_magazinesInHolder = magazinesAmmoCargo _holder;
{
_index = _magazinesInHolder find _x;
if (_index == -1) exitWith {_error = true; ERROR("Missing mag not in holder")};
_magazinesInHolder deleteAt _index;
} forEach _magsToPickup;
//No Error (all the ammo in the container is ammo we should have);
if ((!_error) && {_magazinesInHolder isEqualTo []}) then {
{
_target addMagazine _x;
} forEach (magazinesAmmoCargo _holder);
clearMagazineCargoGlobal _holder;
};
};
//If we added a dummy item, remove it now
if (_holderIsEmpty && {!((getItemCargo _holder) isEqualTo [[DUMMY_ITEM],[1]])}) exitWith {
_holder setVariable [QGVAR(holderInUse), false];
[_caller, _target, "Debug: Holder should only have dummy item"] call FUNC(eventTargetFinish);
};
if (_holderIsEmpty) then {
TRACE_1("Debug: removing dummy item from holder",_holder);
clearItemCargoGlobal _holder;
};
//Verify we didn't timeout waiting on drop action
if (time >= _maxWaitTime) exitWith {
_holder setVariable [QGVAR(holderInUse), false];
[_caller, _target, "Debug: Drop Actions Timeout"] call FUNC(eventTargetFinish);
};
//If target lost disarm status:
if (!([_target] call FUNC(canBeDisarmed))) exitWith {
_holder setVariable [QGVAR(holderInUse), false];
[_caller, _target, "Debug: Target cannot be disarmed"] call FUNC(eventTargetFinish);
};
if (_needToRemoveVest && {!((vestItems _target) isEqualTo [])}) exitWith {
_holder setVariable [QGVAR(holderInUse), false];
[_caller, _target, "Debug: Vest Not Empty"] call FUNC(eventTargetFinish);
};
if (_needToRemoveVest) then {
_holder addItemCargoGlobal [(vest _target), 1];
removeVest _target;
};
if (_needToRemoveUniform && {!((uniformItems _target) isEqualTo [])}) exitWith {
_holder setVariable [QGVAR(holderInUse), false];
[_caller, _target, "Debug: Uniform Not Empty"] call FUNC(eventTargetFinish);
};
if (_needToRemoveUniform) then {
_holder addItemCargoGlobal [(uniform _target), 1];
removeUniform _target;
};
_holder setVariable [QGVAR(holderInUse), false];
[_caller, _target, ""] call FUNC(eventTargetFinish);
};
}, 0.0, [_caller,_target, _listOfItemsToRemove, _holder, _holderIsEmpty, (time + TIME_MAX_WAIT), _doNotDropAmmo, _targetMagazinesEnd]] call CBA_fnc_addPerFrameHandler;

View File

@ -0,0 +1,25 @@
/*
* Author: PabstMirror
* Recieves a possible error code from FUNC(eventTargetFinish)
*
* Arguments:
* 0: caller (player) <OBJECT>
* 1: target <OBJECT>
* 2: error message <STRING>
*
* Return Value:
* None
*
* Example:
* [player1, player2, "Someting fucked up"] call ace_disarming_fnc_eventCallerFinish
*
* Public: No
*/
#include "script_component.hpp"
PARAMS_3(_caller,_target,_errorMsg);
if (_caller != ACE_player) exitWith {};
systemChat format ["Debug-Caller: Disarm finished from [%1] with code [%2]", _target, _errorMsg];
diag_log text format ["[ACE_Disarming] %1 - eventCallerFinish: %2", time, _this];

View File

@ -0,0 +1,26 @@
/*
* Author: PabstMirror
* After FUNC(disarmDropItems) has completed, passing a possible error code.
* Passes that error back to orginal caller.
*
* Arguments:
* 0: caller <OBJECT>
* 1: target <OBJECT>
* 2: errorMsg <STRING>
*
* Return Value:
* Nothing
*
* Example:
* [player1, player2, "Someting fucked up"] call ace_disarming_fnc_eventTargetFinish
*
* Public: No
*/
#include "script_component.hpp"
PARAMS_3(_caller,_target,_errorMsg);
if (_errorMsg != "") then {
diag_log text format ["[ACE_Disarming] %1 - eventTargetFinish: %2", time, _this];
["DisarmDebugCallback", [_caller], [_caller, _target, _errorMsg]] call EFUNC(common,targetEvent);
};

View File

@ -0,0 +1,39 @@
/*
* Author: PabstMirror
* Disarm Event Handler, Starting func, called on the target.
* If target has to remove uniform/vest, this will add all uniform/vest items to the drop list.
*
* Arguments:
* 0: caller (player) <OBJECT>
* 1: target <OBJECT>
* 2: type of disarm <STRING>
*
* Return Value:
* Nothing
*
* Example:
* eventTargetStart
*
* Public: No
*/
#include "script_component.hpp"
PARAMS_3(_caller,_target,_listOfObjectsToRemove);
_itemsToAdd = [];
{
if (_x == (uniform _target)) then {
_itemsToAdd = _itemsToAdd + (uniformItems _target);
};
if (_x == (vest _target)) then {
_itemsToAdd = _itemsToAdd + (vestItems _target);
};
} forEach _listOfObjectsToRemove;
{
if (!(_x in _listOfObjectsToRemove)) then {
_listOfObjectsToRemove pushBack _x;
};
} forEach _itemsToAdd;
[_caller, _target, _listOfObjectsToRemove] call FUNC(disarmDropItems);

View File

@ -0,0 +1,29 @@
/*
* Author: PabstMirror
* Helper function to get all gear of a container
*
* Arguments:
* 0: Container <OBJECT>
*
* Return Value:
* Array of 2 arrays, classnames and count<ARRAY>
*
* Example:
* [["ace_bandage"],[2]] = [box] call ace_disarming_fnc_getAllGearContainer
*
* Public: No
*/
#include "script_component.hpp"
PARAMS_1(_target);
private ["_allGear"];
_allGear = [[],[]];
{
(_allGear select 0) append (_x select 0);
(_allGear select 1) append (_x select 1);
} forEach [(getWeaponCargo _target), (getItemCargo _target), (getMagazineCargo _target), (getBackpackCargo _target)];
_allGear

View File

@ -0,0 +1,52 @@
/*
* Author: PabstMirror
* Helper function to get all gear of a unit.
*
* Arguments:
* 0: Target <OBJECT>
*
* Return Value:
* Array of 2 arrays, classnames and count<ARRAY>
*
* Example:
* [["ace_bandage"],[2]] = [bob] call ace_disarming_fnc_getAllGearUnit
*
* Public: No
*/
#include "script_component.hpp"
PARAMS_1(_target);
_allItems = ((weapons _target) + (magazines _target) + (items _target) + (assignedItems _target));
if ((backpack _target) != "") then {
_allItems pushBack (backpack _target);
};
if ((vest _target) != "") then {
_allItems pushBack (vest _target);
};
if ((uniform _target) != "") then {
_allItems pushBack (uniform _target);
};
if ((headgear _target) != "") then {
_allItems pushBack (headgear _target);
};
//What kind of asshole takes a man's glasses?
if ((goggles _target) != "") then {
_allItems pushBack (goggles _target);
};
_uniqueClassnames = [];
_classnamesCount = [];
//Filter unique and count
{
_index = _uniqueClassnames find _x;
if (_index != -1) then {
_classnamesCount set [_index, ((_classnamesCount select _index) + 1)];
} else {
_uniqueClassnames pushBack _x;
_classnamesCount pushBack 1;
};
} forEach _allItems;
[_uniqueClassnames, _classnamesCount]

View File

@ -0,0 +1,106 @@
/*
* Author: PabstMirror
* Opens the disarm dialog (allowing a person to remove items)
*
* Arguments:
* 0: Caller (player) <OBJECT>
* 1: Target <OBJECT>
*
* Return Value:
* None
*
* Example:
* [player, bob] call ace_disarming_fnc_openDisarmDialog
*
* Public: No
*/
#include "script_component.hpp"
#define TEXTURES_RANKS [ \
"", \
"\A3\Ui_f\data\GUI\Cfg\Ranks\private_gs.paa", \
"\A3\Ui_f\data\GUI\Cfg\Ranks\corporal_gs.paa", \
"\A3\Ui_f\data\GUI\Cfg\Ranks\sergeant_gs.paa", \
"\A3\Ui_f\data\GUI\Cfg\Ranks\lieutenant_gs.paa", \
"\A3\Ui_f\data\GUI\Cfg\Ranks\captain_gs.paa", \
"\A3\Ui_f\data\GUI\Cfg\Ranks\major_gs.paa", \
"\A3\Ui_f\data\GUI\Cfg\Ranks\colonel_gs.paa" \
]
PARAMS_2(_caller,_target);
//Sanity Checks
if (_caller != ACE_player) exitwith {ERROR("Player isn't caller?");};
if (!([_player, _target] call FUNC(canPlayerDisarmUnit))) exitWith {ERROR("Can't Disarm Unit");};
if (dialog) then {ERROR("Dialog open when trying to open disarm dialog"); closeDialog 0;};
disableSerialization;
createDialog QGVAR(remoteInventory);
_display = uiNamespace getVariable ["ACE_remoteInventory", displayNull];
if (isNull _display) exitWith {ERROR("Display is Null");};
GVAR(disarmTarget) = _target;
//Setup Drop Event (on right pannel)
(_display displayCtrl 632) ctrlAddEventHandler ["LBDrop", {
if (isNull GVAR(disarmTarget)) exitWith {};
PARAMS_5(_ctrl,_xPos,_yPos,_idc,_itemInfo);
EXPLODE_3_PVT((_itemInfo select 0),_displayText,_value,_data);
if (isNull GVAR(disarmTarget)) exitWith {ERROR("disarmTarget is null");};
TRACE_2("Debug: Droping %1 from %2",_data,GVAR(disarmTarget));
["DisarmDropItems", [GVAR(disarmTarget)], [ACE_player, GVAR(disarmTarget), [_data]]] call EFUNC(common,targetEvent);
false //not sure what this does
}];
//Setup PFEH
[{
disableSerialization;
EXPLODE_2_PVT(_this,_args,_pfID);
EXPLODE_3_PVT(_args,_player,_target,_display);
if ((!([_player, _target] call FUNC(canPlayerDisarmUnit))) ||
{isNull _display} ||
{_player != ACE_player}) then {
[_pfID] call CBA_fnc_removePerFrameHandler;
GVAR(disarmTarget) = objNull;
if (!isNull _display) then {closeDialog 0;}; //close dialog if still open
} else {
_groundContainer = _display displayCtrl 632;
_targetContainer = _display displayCtrl 633;
_playerName = _display displayCtrl 111;
_rankPicture = _display displayCtrl 1203;
//Show rank and name (just like BIS's inventory)
_rankIndex = ((["PRIVATE", "CORPORAL", "SERGEANT", "LIEUTENANT", "CAPTAIN", "MAJOR", "COLONEL"] find (rank _target)) + 1);
_rankPicture ctrlSetText (TEXTURES_RANKS select _rankIndex);
_playerName ctrlSetText ([GVAR(disarmTarget)] call EFUNC(common,getName));
//Clear both inventory lists:
lbClear _groundContainer;
lbClear _targetContainer;
//Show the items in the ground disarmTarget's inventory
_targetUniqueItems = [GVAR(disarmTarget)] call FUNC(getAllGearUnit);
[_targetContainer, _targetUniqueItems] call FUNC(showItemsInListbox);
//Try to find a holder that the target is using to drop items into:
_holder = objNull;
{
if ((_x getVariable [QGVAR(disarmUnit), objNull]) == _target) exitWith {
_holder = _x;
};
} forEach ((getpos _target) nearObjects [DISARM_CONTAINER, 3]);
//If a holder exists, show it's inventory
if (!isNull _holder) then {
_holderUniqueItems = [_holder] call FUNC(getAllGearContainer);
[_groundContainer, _holderUniqueItems] call FUNC(showItemsInListbox);
};
};
}, 0, [_caller, _target, _display]] call CBA_fnc_addPerFrameHandler;

View File

@ -0,0 +1,60 @@
/*
* Author: PabstMirror
* Shows a list of inventory items in a listBox control.
*
* Arguments:
* 0: RscListBox <CONTROL>
* 1: ItemArray [["itemClassnames"],[counts]] <ARRAY>
*
* Return Value:
* Nothing
*
* Example:
* [theListBox, [["ace_bandage"],[2]]] call ace_disarming_fnc_showItemsInListbox
*
* Public: No
*/
#include "script_component.hpp"
disableSerialization;
PARAMS_2(_listBoxCtrl,_itemsCountArray);
private "_classname";
{
_displayName = "";
_picture = "";
_classname = _x;
_count = (_itemsCountArray select 1) select _forEachIndex;
if (_classname != DUMMY_ITEM) then { //Don't show the dummy potato
switch (true) do {
case (isClass (configFile >> "CfgWeapons" >> _classname)): {
_displayName = getText (configFile >> "CfgWeapons" >> _classname >> "displayName");
_picture = getText (configFile >> "CfgWeapons" >> _classname >> "picture");
};
case (isClass (configFile >> "CfgMagazines" >> _classname)): {
_displayName = getText (configFile >> "CfgMagazines" >> _classname >> "displayName");
_picture = getText (configFile >> "CfgMagazines" >> _classname >> "picture");
};
case (isClass (configFile >> "CfgVehicles" >> _classname)): {
_displayName = getText (configFile >> "CfgVehicles" >> _classname >> "displayName");
_picture = getText (configFile >> "CfgVehicles" >> _classname >> "picture");
};
case (isClass (configFile >> "CfgGlasses" >> _classname)): {
_displayName = getText (configFile >> "CfgGlasses" >> _classname >> "displayName");
_picture = getText (configFile >> "CfgGlasses" >> _classname >> "picture");
};
default {
ERROR(format ["[%1] - bad classname", _classname]);
};
};
_listBoxCtrl lbAdd format ["%1", _displayName];
_listBoxCtrl lbSetData [_forEachIndex, _classname];
_listBoxCtrl lbSetPicture [_forEachIndex, _picture];
_listBoxCtrl lbSetTextRight [_forEachIndex, str _count];
};
} forEach (_itemsCountArray select 0);

View File

@ -0,0 +1,41 @@
/*
* Author: PabstMirror
* Verifies magazines moved with exact ammo counts preserved.
* Arrays will be in format from magazinesAmmo/magazinesAmmoCargo
* e.g.: [["30Rnd_65x39_caseless_mag",15], ["30Rnd_65x39_caseless_mag",30]]
*
* Arguments:
* 0: Start on container A <ARRAY>
* 1: End on container A <ARRAY>
* 2: Start on container B <ARRAY>
* 3: End on container B <ARRAY>
*
* Return Value:
* Verified Good <BOOL>
*
* Example:
* [stuff] call ace_disarming_fnc_verifyMagazinesMoved
*
* Public: No
*/
#include "script_component.hpp"
private ["_problem", "_beginingArray"];
PARAMS_4(_startA,_endA,_startB,_endB);
//Quick Lazy Count Check
if (((count _startA) + (count _startB)) != ((count _endA) + (count _endB))) exitWith {
false
};
_beginingArray = (_startA + _startB);
_problem = false;
{
_index = _beginingArray find _x;
if (_index == -1) exitWith {_problem = true;};
_beginingArray deleteAt _index;
} forEach (_endA + _endB);
(!_problem) && {_beginingArray isEqualTo []}

View File

@ -0,0 +1 @@
#include "\z\ace\addons\disarming\script_component.hpp"

View File

@ -0,0 +1,162 @@
//The disarming dialog
//Meant to mimic the real BIS inventory (so people understand how to use it)
class RscText;
class RscPicture;
class RscActiveText;
class RscListBox;
//Use the definese from
#define X_BIS(num) (num * (((safezoneW / safezoneH) min 1.2) / 40) + (safezoneX + (safezoneW - ((safezoneW / safezoneH) min 1.2))/2))
#define Y_BIS(num) (num * ((((safezoneW / safezoneH) min 1.2) / 1.2) / 25) + (safezoneY + (safezoneH - (((safezoneW / safezoneH) min 1.2) / 1.2))/2))
#define W_BIS(num) (num * (((safezoneW / safezoneH) min 1.2) / 40))
#define H_BIS(num) (num * ((((safezoneW / safezoneH) min 1.2) / 1.2) / 25))
#define X_MAKEITBIGGA(num) (num * (safeZoneH / 40) + (safezoneX + (safezoneW - safeZoneH)/2))
#define Y_MAKEITBIGGA(num) (num * (safeZoneH / 30) + (safezoneY + (safezoneH - (safeZoneH / 1.2))/2))
#define W_MAKEITBIGGA(num) (num * (safeZoneH / 40))
#define H_MAKEITBIGGA(num) (num * (safeZoneH / 30))
#define X_PART(num) QUOTE(linearConversion [ARR_5(0, 2, (missionNamespace getVariable [ARR_2(QUOTE(QEGVAR(inventory,inventoryDisplaySize)), 0)]), X_BIS(num), X_MAKEITBIGGA(num))])
#define Y_PART(num) QUOTE(linearConversion [ARR_5(0, 2, (missionNamespace getVariable [ARR_2(QUOTE(QEGVAR(inventory,inventoryDisplaySize)), 0)]), Y_BIS(num), Y_MAKEITBIGGA(num))])
#define W_PART(num) QUOTE(linearConversion [ARR_5(0, 2, (missionNamespace getVariable [ARR_2(QUOTE(QEGVAR(inventory,inventoryDisplaySize)), 0)]), W_BIS(num), W_MAKEITBIGGA(num))])
#define H_PART(num) QUOTE(linearConversion [ARR_5(0, 2, (missionNamespace getVariable [ARR_2(QUOTE(QEGVAR(inventory,inventoryDisplaySize)), 0)]), H_BIS(num), H_MAKEITBIGGA(num))])
class GVAR(remoteInventory) {
idd = -1;
movingEnable = 0;
enableSimulation = 1;
enableDisplay = 1;
onLoad = "uiNamespace setVariable ['ACE_remoteInventory', _this select 0];";
duration = 2147483647;
fadein = 0;
fadeout = 0;
class Colors {
dragValidBgr[] = {"(profilenamespace getvariable ['IGUI_TEXT_RGB_R',0])","(profilenamespace getvariable ['IGUI_TEXT_RGB_G',1])","(profilenamespace getvariable ['IGUI_TEXT_RGB_B',1])",0.5};
dragInvalidBgr[] = {"(profilenamespace getvariable ['IGUI_ERROR_RGB_R',0.8])","(profilenamespace getvariable ['IGUI_ERROR_RGB_G',0.0])","(profilenamespace getvariable ['IGUI_ERROR_RGB_B',0.0])",0.5};
dragValidBar[] = {"(profilenamespace getvariable ['IGUI_WARNING_RGB_R',0.8])","(profilenamespace getvariable ['IGUI_WARNING_RGB_G',0.5])","(profilenamespace getvariable ['IGUI_WARNING_RGB_B',0.0])",0.5};
dragInvalidBar[] = {"(profilenamespace getvariable ['IGUI_ERROR_RGB_R',0.8])","(profilenamespace getvariable ['IGUI_ERROR_RGB_G',0.0])","(profilenamespace getvariable ['IGUI_ERROR_RGB_B',0.0])",0.5};
progressBar[] = {"(profilenamespace getvariable ['IGUI_TEXT_RGB_R',0])","(profilenamespace getvariable ['IGUI_TEXT_RGB_G',1])","(profilenamespace getvariable ['IGUI_TEXT_RGB_B',1])",1};
progressBarBgr[] = {"(profilenamespace getvariable ['IGUI_BCG_RGB_R',0])","(profilenamespace getvariable ['IGUI_BCG_RGB_G',1])","(profilenamespace getvariable ['IGUI_BCG_RGB_B',1])",0.75};
highlight[] = {"(profilenamespace getvariable ['IGUI_TEXT_RGB_R',0])","(profilenamespace getvariable ['IGUI_TEXT_RGB_G',1])","(profilenamespace getvariable ['IGUI_TEXT_RGB_B',1])",0.5};
};
class controlsBackground {};
class controls {
class CA_ContainerBackground: RscText {
idc = -1;
x = X_PART(1);
y = Y_PART(1);
w = W_PART(12);
h = H_PART(22.5);
colorBackground[] = {0.05,0.05,0.05,0.7};
};
class CA_PlayerBackground: RscText {
idc = -1;
x = X_PART(14.6);
y = Y_PART(2);
w = W_PART(24.4);
h = H_PART(21.5);
colorBackground[] = {0.05,0.05,0.05,0.7};
};
class TitleBackground: RscText {
idc = -1;
x = X_PART(14.6);
y = Y_PART(1);
w = W_PART(24.4);
h = H_PART(1);
colorBackground[] = {0.1,0.1,0.1,1};
};
class PlayersName: RscText {
idc = 111;
// text = "Player name here:";
x = X_PART(15.6);
y = Y_PART(1);
w = W_PART(19.8);
h = H_PART(1);
};
class RankBackground: RscText {
idc = -1;
x = X_PART(15.1);
y = Y_PART(1.25);
w = W_PART(0.6);
h = H_PART(0.6);
colorBackground[] = {1,1,1,0.2};
};
class RankPicture: RscPicture {
idc = 1203;
// text = "\A3\Ui_f\data\GUI\Cfg\Ranks\corporal_gs.paa";
x = X_PART(15.1);
y = Y_PART(1.25);
w = W_PART(0.6);
h = H_PART(0.6);
};
class ButtonBack: RscActiveText {
idc = -1;
style = 48;
color[] = {1,1,1,0.7};
text = "\A3\Ui_f\data\GUI\Rsc\RscDisplayArcadeMap\icon_exit_cross_ca.paa";
x = X_PART(38);
y = Y_PART(1);
w = W_PART(1);
h = H_PART(1);
colorText[] = {1,1,1,0.7};
colorActive[] = {1,1,1,1};
tooltip = "$STR_DISP_OPT_CLOSE";
onButtonClick = "closeDialog 0";
};
class ExternalContainerBackground: RscPicture {
colorText[] = {1,1,1,0.1};
idc = -1;
x = X_PART(1.5);
y = Y_PART(3.7);
w = W_PART(11);
h = H_PART(18.4);
};
class PlayerContainerBackground: ExternalContainerBackground {
idc = -1;
x = X_PART(15.1);
y = Y_PART(6);
w = W_PART(11);
h = H_PART(14);
};
class GroundTitleBackground: RscText {
idc = -1;
x = X_PART(1);
y = Y_PART(1);
w = W_PART(12);
h = H_PART(1);
colorBackground[] = {0.1,0.1,0.1,1};
};
class GroundName: RscText {
idc = -1;
text = "$STR_cfgVehicles_WeaponHolder0"; //"ground"
x = X_PART(1);
y = Y_PART(1);
w = W_PART(12);
h = H_PART(1);
};
class GroundContainer: RscListBox {
idc = 632;
sizeEx = "0.8 * ((((safezoneW / safezoneH) min 1.2) / 1.2) / 25)";
sizeEx2 = "0.8 * ((((safezoneW / safezoneH) min 1.2) / 1.2) / 25)";
rowHeight = "1.75 * ((((safezoneW / safezoneH) min 1.2) / 1.2) / 25)";
canDrag = 0;
colorText[] = {1,1,1,1};
colorBackground[] = {0,0,0,0};
itemBackground[] = {1,1,1,0.2};
itemSpacing = 0.001;
x = X_PART(1.5);
y = Y_PART(2.5);
w = W_PART(11);
h = H_PART(21);
};
class UniformContainer: GroundContainer {
idc = 633;
canDrag = 1;
x = X_PART(15.1);
};
};
};

View File

@ -0,0 +1,16 @@
#define COMPONENT disarming
#include "\z\ace\addons\main\script_mod.hpp"
#ifdef DEBUG_ENABLED_DISARMING
#define DEBUG_MODE_FULL
#endif
#ifdef DEBUG_SETTINGS_DISARMING
#define DEBUG_SETTINGS DEBUG_SETTINGS_DISARMING
#endif
#include "\z\ace\addons\main\script_macros.hpp"
#define DISARM_CONTAINER "GroundWeaponHolder"
#define DUMMY_ITEM "ACE_DebugPotato"
#define UNIQUE_MAGAZINES ["ACE_key_customKeyMagazine"]

View File

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Edited with tabler - 2015-03-17 -->
<Project name="ACE">
<Package name="Disarming">
<Key ID="STR_ACE_Disarming_OpenInventory">
<English>Open Inventory</English>
</Key>
</Package>
</Project>

View File

@ -1,10 +1,10 @@
class CfgACE_Triggers {
class ACE_Triggers {
/* onPlace parameters:
0: OBJECT - unit placing
1: OBJECT - Placed explosive
2: STRING - Magazine classname
3: ARRAY - vars
Last Index: CfgACE_Triggers config of trigger type.
Last Index: ACE_Triggers config of trigger type.
onSetup parameters:
0: STRING - Magazine Classname
*/

View File

@ -18,7 +18,8 @@ class CfgPatches {
#include "CfgMagazines.hpp"
#include "CfgWeapons.hpp"
#include "CfgVehicles.hpp"
#include "CfgACE_Triggers.hpp"
#include "ACE_Triggers.hpp"
#include "ExplosivesUI.hpp"
class CfgActions {

View File

@ -12,7 +12,7 @@
* None
*
* Example:
* [player, _explosive, "SatchelCharge_Remote_Mag", [ConfigFile >> "CfgACE_Triggers" >> "Command"]] call ACE_Explosives_fnc_addClacker;
* [player, _explosive, "SatchelCharge_Remote_Mag", [ConfigFile >> "ACE_Triggers" >> "Command"]] call ACE_Explosives_fnc_addClacker;
*
* Public: Yes
*/

View File

@ -24,7 +24,7 @@ _result = [_unit] call FUNC(getPlacedExplosives);
_children = [];
{
if (!isNull(_x select 0)) then {
_required = getArray (ConfigFile >> "CfgACE_Triggers" >> (_x select 4) >> "requires");
_required = getArray (ConfigFile >> "ACE_Triggers" >> (_x select 4) >> "requires");
if (_detonator in _required) then {
_item = ConfigFile >> "CfgMagazines" >> (_x select 3);

View File

@ -20,7 +20,7 @@ private ["_unit", "_clackerList", "_adjustedList", "_list", "_filter"];
_unit = _this select 0;
_filter = nil;
if (count _this > 1) then {
_filter = ConfigFile >> "CfgACE_Triggers" >> (_this select 1);
_filter = ConfigFile >> "ACE_Triggers" >> (_this select 1);
};
_clackerList = [];
_adjustedList = false;
@ -31,7 +31,7 @@ _list = [];
_clackerList set [_foreachIndex, "X"];
_adjustedList = true;
} else {
if (isNil "_filter" || {(ConfigFile >> "CfgACE_Triggers" >> (_x select 4)) == _filter}) then {
if (isNil "_filter" || {(ConfigFile >> "ACE_Triggers" >> (_x select 4)) == _filter}) then {
_list pushBack _x;
};
};

View File

@ -33,7 +33,7 @@ if (isNil "_triggerConfig") exitWith {
};
_magazineTrigger = ConfigFile >> "CfgMagazines" >> _magazineClass >> "ACE_Triggers" >> _triggerConfig;
_triggerConfig = ConfigFile >> "CfgACE_Triggers" >> _triggerConfig;
_triggerConfig = ConfigFile >> "ACE_Triggers" >> _triggerConfig;
if (isNil "_triggerConfig") exitWith {
diag_log format ["ACE_Explosives: Error config not found in PlaceExplosive: %1", _this];

View File

@ -19,7 +19,7 @@
private ["_config"];
EXPLODE_3_PVT(_this,_explosive,_magazine,_trigger);
_config = ConfigFile >> "CfgACE_Triggers" >> _trigger;
_config = ConfigFile >> "ACE_Triggers" >> _trigger;
// If the onSetup function returns true, it is handled elsewhere
if (isText(_config >> "onSetup") && {[_explosive,_magazine] call compile getText (_config >> "onSetup")}) exitWith {};

View File

@ -6,7 +6,7 @@
* 0: Explosive magazine <STRING>
*
* Return Value:
* Supported triggers as CfgACE_Triggers config entries <ARRAY>
* Supported triggers as ACE_Triggers config entries <ARRAY>
*
* Example:
* _supports = ["SatchelCharge_Remote_Mag"] call ACE_Explosives_fnc_TriggerType
@ -20,6 +20,6 @@ _config = getArray (ConfigFile >> "CfgMagazines" >> (_this select 0) >> "ACE_Tri
_count = count _config;
for "_index" from 0 to (_count - 1) do {
_result set [_index, ConfigFile >> "CfgACE_Triggers" >> (_config select _index)];
_result set [_index, ConfigFile >> "ACE_Triggers" >> (_config select _index)];
};
_result

View File

@ -7,6 +7,8 @@ class CfgVehicles {
MACRO_ADDITEM(ACE_muzzle_mzls_B,5);
MACRO_ADDITEM(ACE_muzzle_mzls_smg_01,5);
MACRO_ADDITEM(ACE_muzzle_mzls_smg_02,5);
MACRO_ADDITEM(ACE_muzzle_mzls_338,5);
MACRO_ADDITEM(ACE_muzzle_mzls_93mmg,5);
};
};
@ -17,6 +19,8 @@ class CfgVehicles {
MACRO_ADDITEM(ACE_muzzle_mzls_B,5);
MACRO_ADDITEM(ACE_muzzle_mzls_smg_01,5);
MACRO_ADDITEM(ACE_muzzle_mzls_smg_02,5);
MACRO_ADDITEM(ACE_muzzle_mzls_338,5);
MACRO_ADDITEM(ACE_muzzle_mzls_93mmg,5);
};
};
@ -28,6 +32,8 @@ class CfgVehicles {
MACRO_ADDITEM(ACE_muzzle_mzls_L,5);
MACRO_ADDITEM(ACE_muzzle_mzls_smg_01,5);
MACRO_ADDITEM(ACE_muzzle_mzls_smg_02,5);
MACRO_ADDITEM(ACE_muzzle_mzls_338,5);
MACRO_ADDITEM(ACE_muzzle_mzls_93mmg,5);
};
};
@ -38,6 +44,8 @@ class CfgVehicles {
MACRO_ADDITEM(ACE_muzzle_mzls_L,2);
MACRO_ADDITEM(ACE_muzzle_mzls_smg_01,2);
MACRO_ADDITEM(ACE_muzzle_mzls_smg_02,2);
MACRO_ADDITEM(ACE_muzzle_mzls_338,5);
MACRO_ADDITEM(ACE_muzzle_mzls_93mmg,5);
};
};
};

View File

@ -1,5 +1,231 @@
class MuzzleSlot;
class CfgWeapons {
/* MX */
class Rifle;
class Rifle_Base_F: Rifle {
class WeaponSlotsInfo;
};
class arifle_MX_Base_F: Rifle_Base_F {
class WeaponSlotsInfo: WeaponSlotsInfo {
class MuzzleSlot: MuzzleSlot {
compatibleItems[] += {"ACE_muzzle_mzls_H"};
};
};
};
class arifle_MX_SW_F: arifle_MX_Base_F {
class WeaponSlotsInfo: WeaponSlotsInfo {
class MuzzleSlot: MuzzleSlot {
// Shit is broken again
//compatibleItems[] += {"ACE_muzzle_mzls_H"};
compatibleItems[] = {"muzzle_snds_H","muzzle_snds_H_SW","ACE_muzzle_mzls_H"};
};
};
};
/* Katiba */
class arifle_katiba_Base_F: Rifle_Base_F {
class WeaponSlotsInfo: WeaponSlotsInfo {
class MuzzleSlot: MuzzleSlot {
compatibleItems[] += {"ACE_muzzle_mzls_H"};
};
};
};
/* Other */
class Rifle_Long_Base_F: Rifle_Base_F {
class WeaponSlotsInfo;
};
class EBR_base_F: Rifle_Long_Base_F {
class WeaponSlotsInfo: WeaponSlotsInfo {
class MuzzleSlot: MuzzleSlot {
compatibleItems[] += {"ACE_muzzle_mzls_B"};
};
};
};
class DMR_01_base_F: Rifle_Long_Base_F {
class WeaponSlotsInfo: WeaponSlotsInfo {
class MuzzleSlot: MuzzleSlot {
compatibleItems[] += {"ACE_muzzle_mzls_B"};
};
};
};
class DMR_02_base_F: Rifle_Long_Base_F {
class WeaponSlotsInfo: WeaponSlotsInfo {
class MuzzleSlot: MuzzleSlot {
compatibleItems[] += {"ACE_muzzle_mzls_338"};
};
};
};
class DMR_03_base_F: Rifle_Long_Base_F {
class WeaponSlotsInfo: WeaponSlotsInfo {
class MuzzleSlot: MuzzleSlot {
compatibleItems[] += {"ACE_muzzle_mzls_B"};
};
};
};
class DMR_05_base_F: Rifle_Long_Base_F {
class WeaponSlotsInfo: WeaponSlotsInfo {
class MuzzleSlot: MuzzleSlot {
compatibleItems[] += {"ACE_muzzle_mzls_93mmg"};
};
};
};
class DMR_06_base_F: Rifle_Long_Base_F {
class WeaponSlotsInfo: WeaponSlotsInfo {
class MuzzleSlot: MuzzleSlot {
compatibleItems[] += {"ACE_muzzle_mzls_B"};
};
};
};
class MMG_01_base_F: Rifle_Long_Base_F {
class WeaponSlotsInfo: WeaponSlotsInfo {
class MuzzleSlot: MuzzleSlot {
compatibleItems[] += {"ACE_muzzle_mzls_93mmg"};
};
};
};
class MMG_02_base_F: Rifle_Long_Base_F {
class WeaponSlotsInfo: WeaponSlotsInfo {
class MuzzleSlot: MuzzleSlot {
compatibleItems[] += {"ACE_muzzle_mzls_338"};
};
};
};
class LMG_Mk200_F: Rifle_Long_Base_F {
class WeaponSlotsInfo: WeaponSlotsInfo {
class MuzzleSlot: MuzzleSlot {
compatibleItems[] += {"ACE_muzzle_mzls_H"};
};
};
};
class LMG_Zafir_F: Rifle_Long_Base_F {
class WeaponSlotsInfo: WeaponSlotsInfo {
class MuzzleSlot: MuzzleSlot {
compatibleItems[] += {"ACE_muzzle_mzls_B"};
};
};
};
/* Assault Rifles */
class Tavor_base_F: Rifle_Base_F {
class WeaponSlotsInfo: WeaponSlotsInfo {
class MuzzleSlot: MuzzleSlot {
compatibleItems[] += {"ACE_muzzle_mzls_L"};
};
};
};
class mk20_base_F: Rifle_Base_F {
class WeaponSlotsInfo: WeaponSlotsInfo {
class MuzzleSlot: MuzzleSlot {
compatibleItems[] += {"ACE_muzzle_mzls_L"};
};
};
};
/* SMGs */
class pdw2000_base_F: Rifle_Base_F {
class WeaponSlotsInfo: WeaponSlotsInfo {
class MuzzleSlot: MuzzleSlot {
compatibleItems[] += {"ACE_muzzle_mzls_smg_02"};
};
};
};
class SMG_01_Base: Rifle_Base_F {
class WeaponSlotsInfo: WeaponSlotsInfo {
class MuzzleSlot: MuzzleSlot {
compatibleItems[] += {"ACE_muzzle_mzls_smg_01"};
};
};
};
class SMG_02_base_F: Rifle_Base_F {
class WeaponSlotsInfo: WeaponSlotsInfo {
class MuzzleSlot: MuzzleSlot {
compatibleItems[] += {"ACE_muzzle_mzls_smg_02"};
};
};
};
/* Pistols */
class Pistol;
class Pistol_Base_F: Pistol {
class WeaponSlotsInfo;
};
class hgun_P07_F: Pistol_Base_F {
class WeaponSlotsInfo: WeaponSlotsInfo {
class MuzzleSlot: MuzzleSlot {
linkProxy = "\A3\data_f\proxies\weapon_slots\MUZZLE";
compatibleItems[] += {"ACE_muzzle_mzls_smg_02"};
};
};
};
class hgun_Rook40_F: Pistol_Base_F {
class WeaponSlotsInfo: WeaponSlotsInfo {
class MuzzleSlot: MuzzleSlot {
linkProxy = "\A3\data_f\proxies\weapon_slots\MUZZLE";
compatibleItems[] += {"ACE_muzzle_mzls_smg_02"};
};
};
};
class hgun_ACPC2_F: Pistol_Base_F {
class WeaponSlotsInfo: WeaponSlotsInfo {
class MuzzleSlot: MuzzleSlot {
compatibleItems[] += {"ACE_muzzle_mzls_smg_01"};
};
};
};
class hgun_Pistol_heavy_01_F: Pistol_Base_F {
class WeaponSlotsInfo: WeaponSlotsInfo {
class MuzzleSlot: MuzzleSlot {
compatibleItems[] += {"ACE_muzzle_mzls_smg_01"};
};
};
};
/*class hgun_Pistol_heavy_02_F: Pistol_Base_F {
class WeaponSlotsInfo: WeaponSlotsInfo {
class MuzzleSlot {
linkProxy = "\A3\data_f\proxies\weapon_slots\MUZZLE";
compatibleItems[] += {"ACE_muzzle_mzls_smg_01"};
};
};
};*/
/* Flashsuppressors */
class ItemCore;
class InventoryMuzzleItem_Base_F;
@ -239,4 +465,96 @@ class CfgWeapons {
inertia = 0.1;
};
class ACE_muzzle_mzls_338: ACE_muzzle_mzls_H {
author = "$STR_ACE_Common_ACETeam";
_generalMacro = "ACE_muzzle_mzls_338";
displayName = "$STR_ACE_muzzle_mzls_338";
picture = "\A3\weapons_F\Data\UI\gear_acca_mzls_h_ca.paa";
model = "\A3\weapons_f\acc\acca_mzls_H_F";
class ItemInfo: ItemInfo {
mass = 8;
soundTypeIndex = 0;
muzzleEnd = "zaslehPoint";
alternativeFire = "Zasleh2";
class MagazineCoef {
initSpeed = 1.0;
};
class AmmoCoef {
hit = 1.0;
visibleFire = 0.5;
audibleFire = 1.0;
visibleFireTime = 0.5;
audibleFireTime = 1.0;
cost = 1.0;
typicalSpeed = 1.0;
airFriction = 1.0;
};
class MuzzleCoef {
dispersionCoef = "0.9f";
artilleryDispersionCoef = "1.0f";
fireLightCoef = "0.5f";
recoilCoef = "1.0f";
recoilProneCoef = "1.0f";
minRangeCoef = "1.0f";
minRangeProbabCoef = "1.0f";
midRangeCoef = "1.0f";
midRangeProbabCoef = "1.0f";
maxRangeCoef = "1.0f";
maxRangeProbabCoef = "1.0f";
};
};
inertia = 0.2;
};
class ACE_muzzle_mzls_93mmg: ACE_muzzle_mzls_H {
author = "$STR_ACE_Common_ACETeam";
_generalMacro = "ACE_muzzle_mzls_93mmg";
displayName = "$STR_ACE_muzzle_mzls_93mmg";
picture = "\A3\weapons_F\Data\UI\gear_acca_mzls_h_ca.paa";
model = "\A3\weapons_f\acc\acca_mzls_H_F";
class ItemInfo: ItemInfo {
mass = 8;
soundTypeIndex = 0;
muzzleEnd = "zaslehPoint";
alternativeFire = "Zasleh2";
class MagazineCoef {
initSpeed = 1.0;
};
class AmmoCoef {
hit = 1.0;
visibleFire = 0.5;
audibleFire = 1.0;
visibleFireTime = 0.5;
audibleFireTime = 1.0;
cost = 1.0;
typicalSpeed = 1.0;
airFriction = 1.0;
};
class MuzzleCoef {
dispersionCoef = "0.9f";
artilleryDispersionCoef = "1.0f";
fireLightCoef = "0.5f";
recoilCoef = "1.0f";
recoilProneCoef = "1.0f";
minRangeCoef = "1.0f";
minRangeProbabCoef = "1.0f";
midRangeCoef = "1.0f";
midRangeProbabCoef = "1.0f";
maxRangeCoef = "1.0f";
maxRangeProbabCoef = "1.0f";
};
};
inertia = 0.2;
};
};

View File

@ -3,7 +3,15 @@
class CfgPatches {
class ADDON {
units[] = {};
weapons[] = {"ACE_muzzle_mzls_H","ACE_muzzle_mzls_B","ACE_muzzle_mzls_L","ACE_muzzle_mzls_smg_01","ACE_muzzle_mzls_smg_02"};
weapons[] = {
"ACE_muzzle_mzls_H",
"ACE_muzzle_mzls_B",
"ACE_muzzle_mzls_L",
"ACE_muzzle_mzls_smg_01",
"ACE_muzzle_mzls_smg_02",
"ACE_muzzle_mzls_338",
"ACE_muzzle_mzls_93mmg"
};
requiredVersion = REQUIRED_VERSION;
requiredAddons[] = {"ace_common"};
author[] = {"commy2"};

View File

@ -4,3 +4,5 @@ ACE_muzzle_mzls_B
ACE_muzzle_mzls_L
ACE_muzzle_mzls_smg_01
ACE_muzzle_mzls_smg_02
ACE_muzzle_mzls_338
ACE_muzzle_mzls_93mmg

View File

@ -62,5 +62,29 @@
<Russian>Пламегаситель (9 мм)</Russian>
<Spanish>Supresor (9 mm)</Spanish>
</Key>
<Key ID="STR_ACE_muzzle_mzls_338">
<English>Flash Suppressor (.338)</English>
<Hungarian>Lángrejtő (.338)</Hungarian>
<German>Mündungsfeuerdämpfer (.338)</German>
<Italian>Soppressore di fiamma (.338)</Italian>
<Portuguese>Supressor de Clarão (.338)</Portuguese>
<Polish>Tłumik płomieni (.338)</Polish>
<Czech>Tlumič záblesku (.338)</Czech>
<French>Cache-flamme (.338)</French>
<Russian>Пламегаситель (.338)</Russian>
<Spanish>Supresor (.338)</Spanish>
</Key>
<Key ID="STR_ACE_muzzle_mzls_93mmg">
<English>Flash Suppressor (9.3 mm)</English>
<Hungarian>Lángrejtő (9,3 mm)</Hungarian>
<German>Mündungsfeuerdämpfer (9,3 mm)</German>
<Italian>Soppressore di fiamma (9.3mm)</Italian>
<Portuguese>Supressor de Clarão (9,3mm)</Portuguese>
<Polish>Tłumik płomieni (9,3 mm)</Polish>
<Czech>Tlumič záblesku (9,3 mm)</Czech>
<French>Cache-flamme (9,3 mm)</French>
<Russian>Пламегаситель (9,3 мм)</Russian>
<Spanish>Supresor (9,3 mm)</Spanish>
</Key>
</Package>
</Project>

View File

@ -23,7 +23,7 @@ _fnc_renderNearbyActions = {
#define MAXINTERACTOBJECTS 3
_numInteractObjects = 0;
_nearestObjects = nearestObjects [(getPos ACE_player), ["All"], 15];
_nearestObjects = nearestObjects [ACE_player, ["All"], 15];
{
_target = _x;

View File

@ -1,15 +1,9 @@
class SlotInfo;
class MuzzleSlot;
class CfgWeapons {
/* MX */
class Rifle;
class Rifle_Base_F: Rifle {
class WeaponSlotsInfo;
};
class Rifle_Base_F;
class arifle_MX_Base_F: Rifle_Base_F {
magazines[] += {
"ACE_30Rnd_65x39_caseless_mag_Tracer_Dim",
@ -18,12 +12,6 @@ class CfgWeapons {
"100Rnd_65x39_caseless_mag",
"100Rnd_65x39_caseless_mag_Tracer"
};
class WeaponSlotsInfo: WeaponSlotsInfo {
class MuzzleSlot: MuzzleSlot {
compatibleItems[] += {"ACE_muzzle_mzls_H"};
};
};
};
class arifle_MX_SW_F: arifle_MX_Base_F {
@ -31,14 +19,6 @@ class CfgWeapons {
"30Rnd_65x39_caseless_mag",
"30Rnd_65x39_caseless_mag_Tracer"
};
class WeaponSlotsInfo: WeaponSlotsInfo {
class MuzzleSlot: MuzzleSlot {
// Shit is broken again
//compatibleItems[] += {"ACE_muzzle_mzls_H"};
compatibleItems[] = {"muzzle_snds_H","muzzle_snds_H_SW","ACE_muzzle_mzls_H"};
};
};
};
class arifle_MXM_F: arifle_MX_Base_F {
@ -57,51 +37,6 @@ class CfgWeapons {
"ACE_30Rnd_65x39_caseless_green_mag_SD",
"ACE_30Rnd_65x39_caseless_green_mag_AP"
};
class WeaponSlotsInfo: WeaponSlotsInfo {
class MuzzleSlot: MuzzleSlot {
compatibleItems[] += {"ACE_muzzle_mzls_H"};
};
};
};
/* Other */
class Rifle_Long_Base_F: Rifle_Base_F {
class WeaponSlotsInfo;
};
class EBR_base_F: Rifle_Long_Base_F {
class WeaponSlotsInfo: WeaponSlotsInfo {
class MuzzleSlot: MuzzleSlot {
compatibleItems[] += {"ACE_muzzle_mzls_B"};
};
};
};
class DMR_01_base_F: Rifle_Long_Base_F {
class WeaponSlotsInfo: WeaponSlotsInfo {
class MuzzleSlot: MuzzleSlot {
compatibleItems[] += {"ACE_muzzle_mzls_B"};
};
};
};
class LMG_Mk200_F: Rifle_Long_Base_F {
class WeaponSlotsInfo: WeaponSlotsInfo {
class MuzzleSlot: MuzzleSlot {
compatibleItems[] += {"ACE_muzzle_mzls_H"};
};
};
};
class LMG_Zafir_F: Rifle_Long_Base_F {
class WeaponSlotsInfo: WeaponSlotsInfo {
class MuzzleSlot: MuzzleSlot {
compatibleItems[] += {"ACE_muzzle_mzls_B"};
};
};
};
@ -113,12 +48,6 @@ class CfgWeapons {
"ACE_30Rnd_556x45_Stanag_SD",
"ACE_30Rnd_556x45_Stanag_AP"
};
class WeaponSlotsInfo: WeaponSlotsInfo {
class MuzzleSlot: MuzzleSlot {
compatibleItems[] += {"ACE_muzzle_mzls_L"};
};
};
};
class mk20_base_F: Rifle_Base_F {
@ -127,12 +56,6 @@ class CfgWeapons {
"ACE_30Rnd_556x45_Stanag_SD",
"ACE_30Rnd_556x45_Stanag_AP"
};
class WeaponSlotsInfo: WeaponSlotsInfo {
class MuzzleSlot: MuzzleSlot {
compatibleItems[] += {"ACE_muzzle_mzls_L"};
};
};
};
@ -146,81 +69,6 @@ class CfgWeapons {
};
};
class pdw2000_base_F: Rifle_Base_F {
class WeaponSlotsInfo: WeaponSlotsInfo {
class MuzzleSlot: MuzzleSlot {
compatibleItems[] += {"ACE_muzzle_mzls_smg_02"};
};
};
};
class SMG_01_Base: Rifle_Base_F {
class WeaponSlotsInfo: WeaponSlotsInfo {
class MuzzleSlot: MuzzleSlot {
compatibleItems[] += {"ACE_muzzle_mzls_smg_01"};
};
};
};
class SMG_02_base_F: Rifle_Base_F {
class WeaponSlotsInfo: WeaponSlotsInfo {
class MuzzleSlot: MuzzleSlot {
compatibleItems[] += {"ACE_muzzle_mzls_smg_02"};
};
};
};
/* Pistols */
class Pistol;
class Pistol_Base_F: Pistol {
class WeaponSlotsInfo;
};
class hgun_P07_F: Pistol_Base_F {
class WeaponSlotsInfo: WeaponSlotsInfo {
class MuzzleSlot: MuzzleSlot {
linkProxy = "\A3\data_f\proxies\weapon_slots\MUZZLE";
compatibleItems[] += {"ACE_muzzle_mzls_smg_02"};
};
};
};
class hgun_Rook40_F: Pistol_Base_F {
class WeaponSlotsInfo: WeaponSlotsInfo {
class MuzzleSlot: MuzzleSlot {
linkProxy = "\A3\data_f\proxies\weapon_slots\MUZZLE";
compatibleItems[] += {"ACE_muzzle_mzls_smg_02"};
};
};
};
class hgun_ACPC2_F: Pistol_Base_F {
class WeaponSlotsInfo: WeaponSlotsInfo {
class MuzzleSlot: MuzzleSlot {
compatibleItems[] += {"ACE_muzzle_mzls_smg_01"};
};
};
};
class hgun_Pistol_heavy_01_F: Pistol_Base_F {
class WeaponSlotsInfo: WeaponSlotsInfo {
class MuzzleSlot: MuzzleSlot {
compatibleItems[] += {"ACE_muzzle_mzls_smg_01"};
};
};
};
/*class hgun_Pistol_heavy_02_F: Pistol_Base_F {
class WeaponSlotsInfo: WeaponSlotsInfo {
class MuzzleSlot {
linkProxy = "\A3\data_f\proxies\weapon_slots\MUZZLE";
compatibleItems[] += {"ACE_muzzle_mzls_smg_01"};
};
};
};*/
/* Silencers */

View File

@ -3,9 +3,6 @@
PREP(rotateVectLineGetMap);
PREP(rotateVectLine);
PREP(translateToModelSpace);
PREP(translateToWeaponSpace);
PREP(fired);
PREP(guidancePFH);

View File

@ -43,7 +43,7 @@ if(!isNil "_seekerTargetPos") then {
_projectilePos = getPosASL _projectile;
_targetVectorSeeker = [_projectile, [_xVec, _yVec, _zVec], _profileAdjustedTargetPos] call FUNC(translateToWeaponSpace);
_targetVectorSeeker = [_projectile, [_xVec, _yVec, _zVec], _profileAdjustedTargetPos] call EFUNC(common,translateToWeaponSpace);
_targetVector = [0,0,0] vectorFromTo _targetVectorSeeker;
TRACE_1("", _targetVectorSeeker, _targetVector);
@ -80,7 +80,7 @@ if(!isNil "_seekerTargetPos") then {
// @TODO: Apply velocity multiplier to yaw/pitch. Basically, it can adjust faster at lower speeds
//_adjustDeflection = (vectorMagnitude velocity _projectile);
_outVector = [_projectile, [_xVec, _yVec, _zVec], [_yaw, _adjustTime, _pitch]] call FUNC(translateToModelSpace);
_outVector = [_projectile, [_xVec, _yVec, _zVec], [_yaw, _adjustTime, _pitch]] call EFUNC(common,translateToModelSpace);
_vectorTo = _projectilePos vectorFromTo _outVector;
_projectile setVectorDirAndUp [_vectorTo, vectorUp _projectile];

View File

@ -230,6 +230,7 @@ class CfgWeapons {
class Snip: Snip {
modelOptics[] = {QUOTE(PATHTOF(models\ace_optics_pip.p3d)),QUOTE(PATHTOF(models\ace_optics_pip.p3d))};
};
class Iron: Iron {};
};
};
};

828
tools/make64.py Normal file
View File

@ -0,0 +1,828 @@
#!/usr/bin/env python
# vim: set fileencoding=utf-8 :
# make.py
# An Arma 3 addon build system
###############################################################################
# The MIT License (MIT)
# Copyright (c) 2013-2014 Ryan Schultz
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
###############################################################################
__version__ = "0.3dev"
import sys
if sys.version_info[0] == 2:
print("Python 3 is required.")
sys.exit(1)
import os
import os.path
import shutil
import platform
import glob
import subprocess
import hashlib
import configparser
import json
import traceback
import time
import re
if sys.platform == "win32":
import winreg
###############################################################################
# http://akiscode.com/articles/sha-1directoryhash.shtml
# Copyright (c) 2009 Stephen Akiki
# MIT License (Means you can do whatever you want with this)
# See http://www.opensource.org/licenses/mit-license.php
# Error Codes:
# -1 -> Directory does not exist
# -2 -> General error (see stack traceback)
def get_directory_hash(directory):
directory_hash = hashlib.sha1()
if not os.path.exists (directory):
return -1
try:
for root, dirs, files in os.walk(directory):
for names in files:
path = os.path.join(root, names)
try:
f = open(path, 'rb')
except:
# You can't open the file for some reason
f.close()
continue
while 1:
# Read file in as little chunks
buf = f.read(4096)
if not buf: break
new = hashlib.sha1(buf)
directory_hash.update(new.digest())
f.close()
except:
# Print the stack traceback
traceback.print_exc()
return -2
return directory_hash.hexdigest()
# Copyright (c) André Burgaud
# http://www.burgaud.com/bring-colors-to-the-windows-console-with-python/
if sys.platform == "win32":
from ctypes import windll, Structure, c_short, c_ushort, byref
SHORT = c_short
WORD = c_ushort
class COORD(Structure):
"""struct in wincon.h."""
_fields_ = [
("X", SHORT),
("Y", SHORT)]
class SMALL_RECT(Structure):
"""struct in wincon.h."""
_fields_ = [
("Left", SHORT),
("Top", SHORT),
("Right", SHORT),
("Bottom", SHORT)]
class CONSOLE_SCREEN_BUFFER_INFO(Structure):
"""struct in wincon.h."""
_fields_ = [
("dwSize", COORD),
("dwCursorPosition", COORD),
("wAttributes", WORD),
("srWindow", SMALL_RECT),
("dwMaximumWindowSize", COORD)]
# winbase.h
STD_INPUT_HANDLE = -10
STD_OUTPUT_HANDLE = -11
STD_ERROR_HANDLE = -12
# wincon.h
FOREGROUND_BLACK = 0x0000
FOREGROUND_BLUE = 0x0001
FOREGROUND_GREEN = 0x0002
FOREGROUND_CYAN = 0x0003
FOREGROUND_RED = 0x0004
FOREGROUND_MAGENTA = 0x0005
FOREGROUND_YELLOW = 0x0006
FOREGROUND_GREY = 0x0007
FOREGROUND_INTENSITY = 0x0008 # foreground color is intensified.
BACKGROUND_BLACK = 0x0000
BACKGROUND_BLUE = 0x0010
BACKGROUND_GREEN = 0x0020
BACKGROUND_CYAN = 0x0030
BACKGROUND_RED = 0x0040
BACKGROUND_MAGENTA = 0x0050
BACKGROUND_YELLOW = 0x0060
BACKGROUND_GREY = 0x0070
BACKGROUND_INTENSITY = 0x0080 # background color is intensified.
stdout_handle = windll.kernel32.GetStdHandle(STD_OUTPUT_HANDLE)
SetConsoleTextAttribute = windll.kernel32.SetConsoleTextAttribute
GetConsoleScreenBufferInfo = windll.kernel32.GetConsoleScreenBufferInfo
def get_text_attr():
"""Returns the character attributes (colors) of the console screen
buffer."""
csbi = CONSOLE_SCREEN_BUFFER_INFO()
GetConsoleScreenBufferInfo(stdout_handle, byref(csbi))
return csbi.wAttributes
def set_text_attr(color):
"""Sets the character attributes (colors) of the console screen
buffer. Color is a combination of foreground and background color,
foreground and background intensity."""
SetConsoleTextAttribute(stdout_handle, color)
###############################################################################
def find_bi_tools(work_drive):
"""Find BI tools."""
reg = winreg.ConnectRegistry(None, winreg.HKEY_CURRENT_USER)
try:
k = winreg.OpenKey(reg, r"Software\bohemia interactive\arma 3 tools")
arma3tools_path = winreg.QueryValueEx(k, "path")[0]
winreg.CloseKey(k)
except:
raise Exception("BadTools","Arma 3 Tools are not installed correctly or the P: drive needs to be created.")
addonbuilder_path = os.path.join(arma3tools_path, "AddonBuilder", "AddonBuilder.exe")
dssignfile_path = os.path.join(arma3tools_path, "DSSignFile", "DSSignFile.exe")
dscreatekey_path = os.path.join(arma3tools_path, "DSSignFile", "DSCreateKey.exe")
cfgconvert_path = os.path.join(arma3tools_path, "CfgConvert", "CfgConvert.exe")
if os.path.isfile(addonbuilder_path) and os.path.isfile(dssignfile_path) and os.path.isfile(dscreatekey_path) and os.path.isfile(cfgconvert_path):
return [addonbuilder_path, dssignfile_path, dscreatekey_path, cfgconvert_path]
else:
raise Exception("BadTools","Arma 3 Tools are not installed correctly or the P: drive needs to be created.")
def find_depbo_tools(regKey):
"""Use registry entries to find DePBO-based tools."""
stop = False
if regKey == "HKCU":
reg = winreg.ConnectRegistry(None, winreg.HKEY_CURRENT_USER)
stop = True
else:
reg = winreg.ConnectRegistry(None, winreg.HKEY_LOCAL_MACHINE)
try:
k = winreg.OpenKey(reg, r"Software\Wow6432Node\Mikero\pboProject")
try:
pboproject_path = winreg.QueryValueEx(k, "exe")[0]
winreg.CloseKey(k)
print("Found pboproject.")
except:
print_error("ERROR: Could not find pboProject.")
k = winreg.OpenKey(reg, r"Software\Wow6432Node\Mikero\rapify")
try:
rapify_path = winreg.QueryValueEx(k, "exe")[0]
winreg.CloseKey(k)
print("Found rapify.")
except:
print_error("Could not find rapify.")
k = winreg.OpenKey(reg, r"Software\Wow6432Node\Mikero\MakePbo")
try:
makepbo_path = winreg.QueryValueEx(k, "exe")[0]
winreg.CloseKey(k)
print("Found makepbo.")
except:
print_error("Could not find makepbo.")
except:
if stop == True:
raise Exception("BadDePBO", "DePBO tools not installed correctly")
return -1
#Strip any quotations from the path due to a MikeRo tool bug which leaves a trailing space in some of its registry paths.
return [pboproject_path.strip('"'),rapify_path.strip('"'),makepbo_path.strip('"')]
def color(color):
"""Set the color. Works on Win32 and normal terminals."""
if sys.platform == "win32":
if color == "green":
set_text_attr(FOREGROUND_GREEN | get_text_attr() & 0x0070 | FOREGROUND_INTENSITY)
elif color == "red":
set_text_attr(FOREGROUND_RED | get_text_attr() & 0x0070 | FOREGROUND_INTENSITY)
elif color == "blue":
set_text_attr(FOREGROUND_BLUE | get_text_attr() & 0x0070 | FOREGROUND_INTENSITY)
elif color == "reset":
set_text_attr(FOREGROUND_GREY | get_text_attr() & 0x0070)
elif color == "grey":
set_text_attr(FOREGROUND_GREY | get_text_attr() & 0x0070)
else :
if color == "green":
sys.stdout.write('\033[92m')
elif color == "red":
sys.stdout.write('\033[91m')
elif color == "blue":
sys.stdout.write('\033[94m')
elif color == "reset":
sys.stdout.write('\033[0m')
def print_error(msg):
color("red")
print ("ERROR: " + msg)
color("reset")
def print_green(msg):
color("green")
print(msg)
color("reset")
def print_blue(msg):
color("blue")
print(msg)
color("reset")
def print_yellow(msg):
color("yellow")
print(msg)
color("reset")
###############################################################################
def main(argv):
"""Build an Arma addon suite in a directory from rules in a make.cfg file."""
print_blue(("\nmake.py for Arma, v" + __version__))
if sys.platform != "win32":
print_error("Non-Windows platform (Cygwin?). Please re-run from cmd.")
sys.exit(1)
reg = winreg.ConnectRegistry(None, winreg.HKEY_CURRENT_USER)
try:
k = winreg.OpenKey(reg, r"Software\bohemia interactive\arma 3 tools")
arma3tools_path = winreg.QueryValueEx(k, "path")[0]
winreg.CloseKey(k)
except:
raise Exception("BadTools","Arma 3 Tools are not installed correctly or the P: drive needs to be created.")
# Default behaviors
test = False # Copy to Arma 3 directory?
arg_modules = False # Only build modules on command line?
make_release = False # Make zip file from the release?
release_version = 0 # Version of release
use_pboproject = True # Default to pboProject build tool
make_target = "DEFAULT" # Which section in make.cfg to use for the build
new_key = False # Make a new key and use it to sign?
quiet = False # Suppress output from build tool?
# Parse arguments
if "help" in argv or "-h" in argv or "--help" in argv:
print ("""
make.py [help] [test] [force] [key <name>] [target <name>] [release <version>]
[module name] [module name] [...]
test -- Copy result to Arma 3.
release <version> -- Make archive with <version>.
force -- Ignore cache and build all.
target <name> -- Use rules in make.cfg under heading [<name>] rather than
default [Make]
key <name> -- Use key in working directory with <name> to sign. If it does not
exist, create key.
quiet -- Suppress command line output from build tool.
If module names are specified, only those modules will be built.
Examples:
make.py force test
Build all modules (ignoring cache) and copy the mod folder to the Arma 3
directory.
make.py mymodule_gun
Only build the module named 'mymodule_gun'.
make.py force key MyNewKey release 1.0
Build all modules (ignoring cache), sign them with NewKey, and pack them
into a zip file for release with version 1.0.
If a file called $NOBIN$ is found in the module directory, that module will not be binarized.
See the make.cfg file for additional build options.
""")
sys.exit(0)
if "force" in argv:
argv.remove("force")
force_build = True
else:
force_build = False
if "test" in argv:
test = True
argv.remove("test")
if "release" in argv:
make_release = True
release_version = argv[argv.index("release") + 1]
argv.remove(release_version)
argv.remove("release")
if "target" in argv:
make_target = argv[argv.index("target") + 1]
argv.remove("target")
argv.remove(make_target)
force_build = True
if "key" in argv:
new_key = True
key_name = argv[argv.index("key") + 1]
argv.remove("key")
argv.remove(key_name)
if "quiet" in argv:
quiet = True
argv.remove("quiet")
# Get the directory the make script is in.
make_root = os.path.dirname(os.path.realpath(__file__))
make_root_parent = os.path.abspath(os.path.join(os.getcwd(), os.pardir))
os.chdir(make_root)
# Get latest commit ID
try:
gitpath = os.path.join(os.path.dirname(make_root), ".git")
assert os.path.exists(gitpath)
commit_id = subprocess.check_output(["git", "rev-parse", "HEAD"])
commit_id = str(commit_id, "utf-8")[:8]
except:
print_error("FAILED TO DETERMINE COMMIT ID.")
commit_id = "NOGIT"
cfg = configparser.ConfigParser();
try:
cfg.read(os.path.join(make_root, "make.cfg"))
# Project name (with @ symbol)
project = cfg.get(make_target, "project", fallback="@"+os.path.basename(os.getcwd()))
# Private key path
key = cfg.get(make_target, "key", fallback=None)
# Project prefix (folder path)
prefix = cfg.get(make_target, "prefix", fallback="")
# Should we autodetect modules on a complete build?
module_autodetect = cfg.getboolean(make_target, "module_autodetect", fallback=True)
# Manual list of modules to build for a complete build
modules = cfg.get(make_target, "modules", fallback=None)
# Parse it out
if modules:
modules = [x.strip() for x in modules.split(',')]
else:
modules = []
# List of directories to ignore when detecting
ignore = [x.strip() for x in cfg.get(make_target, "ignore", fallback="release").split(',')]
# BI Tools work drive on Windows
work_drive = cfg.get(make_target, "work_drive", fallback="P:\\")
# Which build tool should we use?
build_tool = cfg.get(make_target, "build_tool", fallback="addonbuilder").lower()
# Release/build directory, relative to script dir
release_dir = cfg.get(make_target, "release_dir", fallback="release")
# Project PBO file prefix (files are renamed to prefix_name.pbo)
pbo_name_prefix = cfg.get(make_target, "pbo_name_prefix", fallback=None)
# Project module Root
module_root_parent = os.path.abspath(os.path.join(os.path.join(work_drive, prefix), os.pardir))
module_root = cfg.get(make_target, "module_root", fallback=os.path.join(make_root_parent, "addons"))
print_green ("module_root: " + module_root)
if (os.path.isdir(module_root)):
os.chdir(module_root)
else:
print_error ("Directory " + module_root + " does not exist.")
sys.exit()
except:
raise
print_error("Could not parse make.cfg.")
sys.exit(1)
# See if we have been given specific modules to build from command line.
if len(argv) > 1 and not make_release:
arg_modules = True
modules = argv[1:]
# Find the tools we need.
try:
tools = find_bi_tools(work_drive)
addonbuilder = tools[0]
dssignfile = tools[1]
dscreatekey = tools[2]
cfgconvert = tools[3]
except:
print_error("Arma 3 Tools are not installed correctly or the P: drive has not been created.")
sys.exit(1)
if build_tool == "pboproject":
try:
depbo_tools = find_depbo_tools("HKLM")
if depbo_tools == -1:
depbo_tools = find_depbo_tools("HKCU")
pboproject = depbo_tools[0]
rapifyTool = depbo_tools[1]
makepboTool = depbo_tools[2]
except:
raise
print_error("Could not find dePBO tools. Download the needed tools from: https://dev.withsix.com/projects/mikero-pbodll/files")
sys.exit(1)
# Try to open and deserialize build cache file.
try:
cache = {}
with open(os.path.join(make_root, "make.cache"), 'r') as f:
cache_raw = f.read()
cache = json.loads(cache_raw)
except:
print ("No cache found.")
cache = {}
# Get list of subdirs in make root.
dirs = next(os.walk(module_root))[1]
# Autodetect what directories to build.
if module_autodetect and not arg_modules:
modules = []
for path in dirs:
# Any dir that has a config.cpp in its root is an addon to build.
config_path = os.path.join(path, 'config.cpp')
if os.path.isfile(config_path) and not path in ignore:
modules.append(path)
# Make the key specified from command line if necessary.
if new_key:
if not os.path.isfile(os.path.join(module_root, key_name + ".biprivatekey")):
print_green("\nRequested key does not exist.")
ret = subprocess.call([dscreatekey, key_name]) # Created in make_root
if ret == 0:
print_blue("Created: " + os.path.join(module_root, key_name + ".biprivatekey"))
else:
print_error("Failed to create key!")
try:
print_blue("Copying public key to release directory.")
try:
os.makedirs(os.path.join(module_root, release_dir, "Keys"))
except:
pass
shutil.copyfile(os.path.join(module_root, key_name + ".bikey"), os.path.join(module_root, release_dir, "Keys", key_name + ".bikey"))
except:
raise
print_error("Could not copy key to release directory.")
else:
print_green("\nNOTE: Using key " + os.path.join(module_root, key_name + ".biprivatekey"))
key = os.path.join(module_root, key_name + ".biprivatekey")
# For each module, prep files and then build.
for module in modules:
print_green("\nMaking " + module + "-"*max(1, (60-len(module))))
# Cache check
if module in cache:
old_sha = cache[module]
else:
old_sha = ""
# Hash the module
new_sha = get_directory_hash(os.path.join(module_root, module))
# Check if it needs rebuilt
# print ("Hash:", new_sha)
if old_sha == new_sha:
if not force_build:
print("Module has not changed.")
# Skip everything else
continue
# Only do this if the project isn't stored directly on the work drive.
# Split the path at the drive name and see if they are on the same drive (usually P:)
if os.path.splitdrive(module_root)[0] != os.path.splitdrive(work_drive)[0]:
try:
# Remove old work drive version (ignore errors)
shutil.rmtree(os.path.join(work_drive, prefix, module), True)
# Copy module to the work drive
shutil.copytree(module, os.path.join(work_drive, prefix, module))
except:
raise
print_error("ERROR: Could not copy module to work drive. Does the module exist?")
input("Press Enter to continue...")
print("Resuming build...")
continue
#else:
#print("WARNING: Module is stored on work drive (" + work_drive + ").")
try:
# Remove the old pbo, key, and log
old = os.path.join(module_root, release_dir, project, "Addons", module) + "*"
files = glob.glob(old)
for f in files:
os.remove(f)
if pbo_name_prefix:
old = os.path.join(module_root, release_dir, project, "Addons", pbo_name_prefix+module) + "*"
files = glob.glob(old)
for f in files:
os.remove(f)
except:
raise
print_error("ERROR: Could not copy module to work drive. Does the module exist?")
input("Press Enter to continue...")
print("Resuming build...")
continue
# Build the module into a pbo
print_blue("Building: " + os.path.join(work_drive, prefix, module))
print_blue("Destination: " + os.path.join(module_root, release_dir, project, "Addons"))
# Make destination folder (if needed)
try:
os.makedirs(os.path.join(module_root, release_dir, project, "Addons"))
except:
pass
# Run build tool
build_successful = False
if build_tool == "pboproject":
try:
#PABST: Convert config (run the macro'd config.cpp through CfgConvert twice to produce a de-macro'd cpp that pboProject can read without fucking up:
shutil.copyfile(os.path.join(work_drive, prefix, module, "config.cpp"), os.path.join(work_drive, prefix, module, "config.backup"))
os.chdir("P:\\")
cmd = [os.path.join(arma3tools_path, "CfgConvert", "CfgConvert.exe"), "-bin", "-dst", os.path.join(work_drive, prefix, module, "config.bin"), os.path.join(work_drive, prefix, module, "config.cpp")]
ret = subprocess.call(cmd)
if ret != 0:
print_error("CfgConvert -bin return code == " + str(ret))
input("Press Enter to continue...")
cmd = [os.path.join(arma3tools_path, "CfgConvert", "CfgConvert.exe"), "-txt", "-dst", os.path.join(work_drive, prefix, module, "config.cpp"), os.path.join(work_drive, prefix, module, "config.bin")]
ret = subprocess.call(cmd)
if ret != 0:
print_error("CfgConvert -txt) return code == " + str(ret))
input("Press Enter to continue...")
# Include build number
try:
configpath = os.path.join(work_drive, prefix, module, "config.cpp")
f = open(configpath, "r")
configtext = f.read()
f.close()
patchestext = re.search(r"class CfgPatches\n\{(.*?)\n\}", configtext, re.DOTALL).group(1)
patchestext = re.sub(r'version(.*?)="(.*?)"', r'version\1="\2-{}"'.format(commit_id), patchestext)
configtext = re.sub(r"class CfgPatches\n\{(.*?)\n\}", "class CfgPatches\n{"+patchestext+"\n}", configtext, flags=re.DOTALL)
f = open(configpath, "w")
f.write(configtext)
f.close()
except:
raise
print_error("Failed to include build number")
continue
if os.path.isfile(os.path.join(work_drive, prefix, module, "$NOBIN$")):
print_green("$NOBIN$ Found. Proceeding with non-binarizing!")
cmd = [makepboTool, "-P","-A","-L","-N","-G", os.path.join(work_drive, prefix, module),os.path.join(module_root, release_dir, project,"Addons")]
else:
cmd = [pboproject, "-P", os.path.join(work_drive, prefix, module), "+Engine=Arma3", "-S","+Noisy", "+X", "+Clean", "+Mod="+os.path.join(module_root, release_dir, project), "-Key"]
color("grey")
if quiet:
devnull = open(os.devnull, 'w')
ret = subprocess.call(cmd, stdout=devnull)
devnull.close()
else:
ret = subprocess.call(cmd)
color("reset")
if ret == 0:
print_green("pboProject return code == " + str(ret))
# Prettyprefix rename the PBO if requested.
if pbo_name_prefix:
try:
os.rename(os.path.join(module_root, release_dir, project, "Addons", module+".pbo"), os.path.join(module_root, release_dir, project, "Addons", pbo_name_prefix+module+".pbo"))
except:
raise
print_error("Could not rename built PBO with prefix.")
# Sign result
if key:
print("Signing with " + key + ".")
if pbo_name_prefix:
ret = subprocess.call([dssignfile, key, os.path.join(module_root, release_dir, project, "Addons", pbo_name_prefix + module + ".pbo")])
else:
ret = subprocess.call([dssignfile, key, os.path.join(module_root, release_dir, project, "Addons", module + ".pbo")])
if ret == 0:
build_successful = True
else:
build_successful = True
if not build_successful:
print_error("pboProject return code == " + str(ret))
print_error("Module not successfully built/signed.")
input("Press Enter to continue...")
print ("Resuming build...")
continue
#PABST: cleanup config BS (you could comment this out to see the "de-macroed" cpp
#print_green("\Pabst (restoring): " + os.path.join(work_drive, prefix, module, "config.cpp"))
os.remove(os.path.join(work_drive, prefix, module, "config.cpp"))
os.remove(os.path.join(work_drive, prefix, module, "config.bin"))
os.rename(os.path.join(work_drive, prefix, module, "config.backup"), os.path.join(work_drive, prefix, module, "config.cpp"))
# Back to the root
os.chdir(module_root)
except:
raise
print_error("Could not run Addon Builder.")
input("Press Enter to continue...")
print ("Resuming build...")
continue
elif build_tool== "addonbuilder":
# Detect $NOBIN$ and do not binarize if found.
if os.path.isfile(os.path.join(work_drive, prefix, module, "$NOBIN$")):
do_binarize = False
print("$NOBIN$ file found in module, packing only.")
else:
do_binarize = True
try:
# Call AddonBuilder
os.chdir("P:\\")
cmd = [addonbuilder, os.path.join(work_drive, prefix, module), os.path.join(make_root, release_dir, project, "Addons"), "-clear", "-project="+work_drive]
if not do_binarize:
cmd.append("-packonly")
if quiet:
previousDirectory = os.getcwd()
os.chdir(arma3tools_path)
devnull = open(os.devnull, 'w')
ret = subprocess.call(cmd, stdout=devnull)
devnull.close()
os.chdir(previousDirectory)
else:
previousDirectory = os.getcwd()
os.chdir(arma3tools_path)
print_error("Current directory - " + os.getcwd())
ret = subprocess.call(cmd)
os.chdir(previousDirectory)
print_error("Current directory - " + os.getcwd())
color("reset")
print_green("completed")
# Prettyprefix rename the PBO if requested.
if pbo_name_prefix:
try:
os.rename(os.path.join(make_root, release_dir, project, "Addons", module+".pbo"), os.path.join(make_root, release_dir, project, "Addons", pbo_name_prefix+module+".pbo"))
except:
raise
print_error("Could not rename built PBO with prefix.")
if ret == 0:
# Sign result
if key:
print("Signing with " + key + ".")
if pbo_name_prefix:
ret = subprocess.call([dssignfile, key, os.path.join(make_root, release_dir, project, "Addons", pbo_name_prefix + module + ".pbo")])
else:
ret = subprocess.call([dssignfile, key, os.path.join(make_root, release_dir, project, "Addons", module + ".pbo")])
if ret == 0:
build_successful = True
else:
build_successful = True
if not build_successful:
print_error("Module not successfully built.")
# Back to the root
os.chdir(make_root)
except:
raise
print_error("Could not run Addon Builder.")
input("Press Enter to continue...")
print ("Resuming build...")
continue
else:
print_error("Unknown build_tool " + build_tool + "!")
# Update the hash for a successfully built module
if build_successful:
cache[module] = new_sha
# Done building all modules!
# Write out the cache state
cache_out = json.dumps(cache)
with open(os.path.join(make_root, "make.cache"), 'w') as f:
f.write(cache_out)
# Delete the pboproject temp files if building a release.
if make_release and build_tool == "pboproject":
try:
shutil.rmtree(os.path.join(module_root, release_dir, project, "temp"), True)
except:
print_error("ERROR: Could not delete pboProject temp files.")
print_green("\nDone.")
# Make release
if make_release:
print_blue("\nMaking release: " + project + "-" + release_version + ".zip")
try:
# Delete all log files
for root, dirs, files in os.walk(os.path.join(module_root, release_dir, project, "Addons")):
for currentFile in files:
if currentFile.lower().endswith("log"):
os.remove(os.path.join(root, currentFile))
# Create a zip with the contents of release/ in it
shutil.make_archive(project + "-" + release_version, "zip", os.path.join(module_root, release_dir))
except:
raise
print_error("Could not make release.")
# Copy to Arma 3 folder for testing
if test:
print_blue("\nCopying to Arma 3.")
if sys.platform == "win32":
reg = winreg.ConnectRegistry(None, winreg.HKEY_LOCAL_MACHINE)
try:
k = winreg.OpenKey(reg, r"SOFTWARE\Wow6432Node\Bohemia Interactive\Arma 3")
a3_path = winreg.EnumValue(k, 1)[1]
winreg.CloseKey(k)
except:
print_error("Could not find Arma 3's directory in the registry.")
else:
a3_path = cygwin_a3path
if os.path.exists(a3_path):
try:
shutil.rmtree(os.path.join(a3_path, project), True)
shutil.copytree(os.path.join(module_root, release_dir, project), os.path.join(a3_path, project))
except:
print_error("Could not copy files. Is Arma 3 running?")
if __name__ == "__main__":
main(sys.argv)
input("Press Enter to continue...")