From bb968698e6a5fec46565a3b7c0b8d7450268ef11 Mon Sep 17 00:00:00 2001 From: A Man Date: Sun, 19 Sep 2021 18:41:52 +0200 Subject: [PATCH] Modulr build changes - Players may no longer build objects outside the plot radius. - This is calculated using the object's pivot point, not its geometry nor its bounding box. - Players may move an object any distance or height within the plot boundary/sphere. - Therefore, DZE_buildMaxMoveDistance and DZE_buildMaxHeightDistance are now obsolete. - Players may move a small distance outside the plot radius, provided the object remains inside. Enabled with DZE_PlotOzone. Default: 10 meters. - A line of helpers now appears through the plot's vertical axis to aid line-of-sight to the pole. Enabled with DZE_AxialHelper. - This may be useful for nearby plots that are grouped together, or where their radii overlap. - Players may now cancel the build by fast movement, i.e. running, or fast walking on steep terrain. - This only applies when the player is holding the object. They may press F to release it, then run without cancelling. - Crouch-walking or slow-walking will not cancel the build. - The player will auto-crouch when clicking "build" to prevent accidental cancelling. Changes made by @Victor-the-Cleaner --- SQF/dayz_code/actions/modular_build.sqf | 1030 +++++++++++------ .../actions/player_buildingMaint.sqf | 131 ++- .../plotManagement/plotToggleMarkers.sqf | 164 +-- SQF/dayz_code/compile/dze_buildChecks.sqf | 279 +++-- SQF/dayz_code/compile/fn_find_plots.sqf | 42 +- 5 files changed, 1053 insertions(+), 593 deletions(-) diff --git a/SQF/dayz_code/actions/modular_build.sqf b/SQF/dayz_code/actions/modular_build.sqf index 97c8298e4..36f67ab90 100644 --- a/SQF/dayz_code/actions/modular_build.sqf +++ b/SQF/dayz_code/actions/modular_build.sqf @@ -1,285 +1,465 @@ -if (dayz_actionInProgress) exitWith {localize "str_epoch_player_40" call dayz_rollingMessages;}; +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// +// DayZ Base Building +// +// Author: vbawol@veteranbastards.com +// Updated by: Victor the Cleaner +// Date: August 2021 +// +// - Players may no longer build objects outside the plot radius. +// This is calculated using the object's pivot point, not its geometry nor its bounding box. +// - Players may move an object any distance or height within the plot boundary/sphere. +// Therefore, DZE_buildMaxMoveDistance and DZE_buildMaxHeightDistance are now obsolete. +// +// - Players may move a small distance outside the plot radius, provided the object remains inside. Enabled with DZE_PlotOzone. Default: 10 meters. +// - A line of helpers now appears through the plot's vertical axis to aid line-of-sight to the pole. Enabled with DZE_AxialHelper. +// This may be useful for nearby plots that are grouped together, or where their radii overlap. +// +// - Players may now cancel the build by fast movement, i.e. running, or fast walking on steep terrain. +// This only applies when the player is holding the object. They may press F to release it, then run without cancelling. +// Crouch-walking or slow-walking will not cancel the build. +// Pressing ESC will also cancel without opening the exit menu. +// +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +if (dayz_actionInProgress) exitWith {localize "str_epoch_player_40" call dayz_rollingMessages;}; // Building already in progress. dayz_actionInProgress = true; -private ["_abort","_reason","_distance","_isNear","_lockable","_isAllowedUnderGround","_offset","_classname","_zheightdirection","_zheightchanged","_rotate","_objectHelperPos","_objHDiff","_position","_isOk","_dir","_vector","_cancel","_location2","_buildOffset","_location","_limit","_finished","_proceed","_counter","_combination_1_Display","_combination_1","_combination_2","_combination_3","_combination","_combinationDisplay","_combination_4","_num_removed","_tmpbuilt","_vUp","_classnametmp","_text","_ghost","_objectHelper","_location1","_object","_helperColor","_canDo","_pos","_onLadder","_vehicle","_inVehicle","_needNear","_canBuild","_friendsArr"]; +/////////////////////////////////////////////////////////////////////////////////////////////////// +// +// _misc_checks function +// +/////////////////////////////////////////////////////////////////////////////////////////////////// +local _misc_checks = { -_pos = [player] call FNC_GetPos; + local _onLadder = (getNumber (configFile >> "CfgMovesMaleSdr" >> "States" >> (animationState player) >> "onLadder")) == 1; + local _inVehicle = ((vehicle player) != player); + local _ctime = (player getVariable["combattimeout",0] >= diag_tickTime); + local _reason = ""; -_onLadder = (getNumber (configFile >> "CfgMovesMaleSdr" >> "States" >> (animationState player) >> "onLadder")) == 1; + call { + if (_onLadder) exitWith {_reason = "str_player_21"}; // You cannot do this while you are on a ladder. + if (dayz_isSwimming) exitWith {_reason = "str_player_26"}; // You cannot do this while you are in the water. + if (_inVehicle) exitWith {_reason = "str_epoch_player_42"}; // You cannot build while in a vehicle. + if (_ctime) exitWith {_reason = "str_epoch_player_43"}; // You cannot build while in combat. + }; -_vehicle = vehicle player; -_inVehicle = (_vehicle != player); + _reason; +}; -DZE_Q = false; -DZE_Z = false; +/////////////////////////////////////////////////////////////////////////////////////////////////// +// +// _cancel_build function +// +/////////////////////////////////////////////////////////////////////////////////////////////////// +_cancel_build = { -DZE_Q_alt = false; -DZE_Z_alt = false; + _isOk = false; + _cancel = true; + detach _object; + deleteVehicle _object; + detach _objectHelper; + deleteVehicle _objectHelper; +}; -DZE_Q_ctrl = false; -DZE_Z_ctrl = false; +/////////////////////////////////////////////////////////////////////////////////////////////////// -DZE_5 = false; -DZE_4 = false; -DZE_6 = false; +local _reason = call _misc_checks; -DZE_F = false; +if (_reason != "") exitWith { + dayz_actionInProgress = false; + localize _reason call dayz_rollingMessages; +}; -DZE_cancelBuilding = false; +/////////////////////////////////////////////////////////////////////////////////////////////////// +// +// Initialise +// +/////////////////////////////////////////////////////////////////////////////////////////////////// +DZE_buildItem = _this; // buildable classname, e.g. "full_cinder_wall_kit" -DZE_updateVec = false; -DZE_memDir = 0; -DZE_memForBack = 0; -DZE_memLeftRight = 0; +DZE_5 = false; // space bar - build +DZE_4 = false; // Q Key - rotate left +DZE_6 = false; // E Key - rotate right +DZE_F = false; // F Key - hold/release + +DZE_Q = false; // PgUp +DZE_Z = false; // PgDn +DZE_Q_alt = false; // Alt + PgUp +DZE_Z_alt = false; // Alt + PgDn +DZE_Q_ctrl = false; // Ctrl + PgUp +DZE_Z_ctrl = false; // Ctrl + PgDn + +DZE_cancelBuilding = false; // ESC Key +DZE_updateVec = false; // vector changed via build_vectors.sqf +DZE_memDir = 0; // object rotation (Q/E keys) +DZE_memForBack = 0; // pitch forward/back +DZE_memLeftRight = 0; // bank left/right call gear_ui_init; closeDialog 1; -if (dayz_isSwimming) exitWith {dayz_actionInProgress = false; localize "str_player_26" call dayz_rollingMessages;}; -if (_inVehicle) exitWith {dayz_actionInProgress = false; localize "str_epoch_player_42" call dayz_rollingMessages;}; -if (_onLadder) exitWith {dayz_actionInProgress = false; localize "str_player_21" call dayz_rollingMessages;}; -if (player getVariable["combattimeout",0] >= diag_tickTime) exitWith {dayz_actionInProgress = false; localize "str_epoch_player_43" call dayz_rollingMessages;}; +local _playerPos = [player] call FNC_GetPos; +local _buildCheck = [_playerPos, DZE_buildItem, true] call dze_buildChecks; // input: [player position, kit classname, toolcheck] // return value: [_canBuild, _isPole, _nearestPole]; +local _canBuild = (_buildCheck select 0); // bool -DZE_buildItem = _this; +/////////////////////////////////////////////////////////////////////////////////////////////////// -_abort = false; -_reason = ""; +if (_canBuild) then { -_needNear = getArray (configFile >> "CfgMagazines" >> DZE_buildItem >> "ItemActions" >> "Build" >> "neednearby"); + player playActionNow "Crouch"; // prevent instant cancel from moving too fast -{ - call { - if (_x == "fire") exitwith { - _distance = 3; - _isNear = {inflamed _x} count (_pos nearObjects _distance); - if (_isNear == 0) then { - _abort = true; - _reason = localize "STR_EPOCH_FIRE"; - }; + local _isPole = (_buildCheck select 1); // bool + local _nearestPole = (_buildCheck select 2); // object or objNull + local _findNearestPole = []; + local _inRadius = (!_isPole && !(isNull _nearestPole)); // bool // is the player attempting to place an object within a plot boundary? + local _radius = DZE_PlotPole select 0; // max distance from plot pole an object may be built + local _minDistance = DZE_PlotPole select 1; // minimum distance between plot poles + local _diameter = _radius * 2; // plot diameter + local _ozone = _radius + DZE_PlotOzone; // zone outside plot radius where a player may stand before placing an object, but the object must remain within the plot radius + local _isBHL = (DZE_BuildHeightLimit > 0); // is build height limit enabled + local _BHL = DZE_BuildHeightLimit; // short name + local _sphere = "Sign_sphere100cm_EP1"; // helper classname + local _polePos = []; + local _pArray = []; + local _isAdmin = dayz_playerUID in DZE_PlotManagementAdmins; + local _dir = 0; + local _vector = []; + local _object = objNull; + local _objectPos = []; + local _zPos = 0; + local _objectHelper = objNull; + local _objectHelperPos = []; + local _walk = "amovpercmwlk"; // animation state substrings + local _run = "amovpercmrun"; + local _sprint = "amovpercmspr"; + + helperDetach = false; + local _isOk = true; + local _cancel = false; + + /////////////////////////////////////////////////////////////////////////////////////////// + // + // create vertical helpers at the plot center to which the object will be assigned + // + /////////////////////////////////////////////////////////////////////////////////////////// + + if (_inRadius && DZE_AxialHelper) then { + + local _density = 4; // minimum distance between helpers + local _segments = floor (_diameter / _density); // total helpers = _segments + 1 + local _segments = _segments - (_segments % 2); // get even number of segments + local _spacing = -(_diameter / _segments); // actual distance between helpers + local _zenith = _radius; + local _polePos = [_nearestPole] call FNC_GetPos; + + if (!isNil "PP_Marks") then { + _zenith = _zenith + _spacing; // subtract upper and lower positions }; - if (_x == "workshop") exitwith { - _distance = 3; - _isNear = count (nearestObjects [_pos, DZE_Workshops, _distance]); - if (_isNear == 0) then { - _abort = true; - _reason = localize "STR_EPOCH_WORKBENCH_NEARBY"; + + for "_i" from _zenith to -_zenith step _spacing do { // start at the zenith + local _offset = [0,0,_i]; // decrement towards nadir + local _pos = _nearestPole modelToWorld _offset; // translate to world + local _pZ = (_pos select 2); // get Z height + + if (_pZ < 0) exitWith {}; // too low + + local _texture = DZE_plotGreen; // green + if (_isBHL && (_pZ > _BHL)) then { // too high + _texture = DZE_plotRed; // red }; - }; - if (_x == "fueltank") exitwith { - _distance = 30; - _isNear = count (nearestObjects [_pos, dayz_fuelsources, _distance]); - if (_isNear == 0) then { - _abort = true; - _reason = localize "STR_EPOCH_VEHUP_TNK"; + local _helper = _sphere createVehicleLocal [0,0,0]; // create helper + _helper setObjectTexture _texture; // add colour + + _pos set [2,(_polePos select 2) + _i]; // align to radial height + + if (surfaceIsWater _pos) then { // adjust for land and sea + _helper setPosASL _pos; + } else { + _helper setPosATL _pos; }; + _pArray = _pArray + [_helper]; // record helper }; }; -} count _needNear; + + /////////////////////////////////////////////////////////////////////////////////////////// + // + // get config data + // + /////////////////////////////////////////////////////////////////////////////////////////// -if (_abort) exitWith { - format[localize "str_epoch_player_135",_reason,_distance] call dayz_rollingMessages; - dayz_actionInProgress = false; -}; + local _classname = getText (configFile >> "CfgMagazines" >> DZE_buildItem >> "ItemActions" >> "Build" >> "create"); // e.g. "CinderWall_DZ" + local _classnametmp = _classname; -_canBuild = [_pos, _this, true] call dze_buildChecks; -if (_canBuild select 0) then { - _classname = getText (configFile >> "CfgMagazines" >> DZE_buildItem >> "ItemActions" >> "Build" >> "create"); - _classnametmp = _classname; - if (isText (configFile >> "CfgMagazines" >> DZE_buildItem >> "ItemActions" >> "Build" >> "buildText")) then { - _text = getText (configFile >> "CfgMagazines" >> DZE_buildItem >> "ItemActions" >> "Build" >> "buildText"); - } else { - _text = getText (configFile >> "CfgVehicles" >> _classname >> "displayName"); - }; - _ghost = getText (configFile >> "CfgVehicles" >> _classname >> "ghostpreview"); + local _text = getText (configFile >> "CfgVehicles" >> _classname >> "displayName"); // e.g. "Cinder Wall Full" + local _ghost = getText (configFile >> "CfgVehicles" >> _classname >> "ghostpreview"); // e.g. "CinderWall_Preview_DZ" + local _lockable = getNumber (configFile >> "CfgVehicles" >> _classname >> "lockable"); // defaults to 0 + local _offset = getArray (configFile >> "CfgVehicles" >> _classname >> "offset"); - _lockable = 0; - if (isNumber (configFile >> "CfgVehicles" >> _classname >> "lockable")) then { - _lockable = getNumber(configFile >> "CfgVehicles" >> _classname >> "lockable"); - }; + local _isAllowedUnderGround = 1; - _isAllowedUnderGround = 1; if (isNumber (configFile >> "CfgVehicles" >> _classname >> "nounderground")) then { _isAllowedUnderGround = getNumber(configFile >> "CfgVehicles" >> _classname >> "nounderground"); }; - _offset = getArray (configFile >> "CfgVehicles" >> _classname >> "offset"); - _objectHelper = objNull; - _isOk = true; - _location1 = [player] call FNC_GetPos; - _dir = getDir player; - if (_ghost != "") then { _classname = _ghost; }; + /////////////////////////////////////////////////////////////////////////////////////////// + // + // create ghost object and helper during pre-build + // + /////////////////////////////////////////////////////////////////////////////////////////// + _object = _classname createVehicle [0,0,0]; - if ((count _offset) <= 0) then { - _offset = [0,(abs(((boundingBox _object)select 0) select 1)),0]; + if (count _offset == 0) then { + _offset = [0, abs (((boundingBox _object) select 0) select 1), 0]; }; _objectHelper = "Sign_sphere10cm_EP1" createVehicle [0,0,0]; - _helperColor = "#(argb,8,8,3)color(0,0,0,0,ca)"; - _objectHelper setobjecttexture [0,_helperColor]; - _objectHelper attachTo [player,_offset]; - _object attachTo [_objectHelper,[0,0,0]]; + _objectHelper setobjecttexture [0,"#(argb,8,8,3)color(0,1,0,1,ca)"]; // solid helper sphere + + local _tempPos = player modelToWorld _offset; + + _dir = getDir player; + _objectHelper setDir _dir; + _object setDir _dir; + + if ((_isAllowedUnderGround == 0) && ((_tempPos select 2) < (_offset select 2))) then { + + _tempPos set [2, _offset select 2]; // raise up to ground/sea level + }; + + if (surfaceIsWater _tempPos) then { + _objectHelper setPosASL _tempPos; + _object setPosASL _tempPos; + } else { + _objectHelper setPosATL _tempPos; + _object setPosATL _tempPos; + }; + + _objectHelper attachTo [player]; + _object attachTo [_objectHelper]; if (isClass (configFile >> "SnapBuilding" >> _classname)) then { - ["","","",["Init",_object,_classname,_objectHelper]] spawn snap_build; + ["","","",["Init", _object, _classname, _objectHelper]] spawn snap_build; + }; + if !(DZE_buildItem in DZE_noRotate) then { + ["","","",["Init", "Init", 0]] spawn build_vectors; }; - if !(DZE_buildItem in DZE_noRotate) then{ - ["","","",["Init","Init",0]] spawn build_vectors; + /////////////////////////////////////////////////////////////////////////////////////////// + // + // _change_height function + // + /////////////////////////////////////////////////////////////////////////////////////////// + + local _change_height = { + local _delta = _this; + local _helperPos = [_objectHelper] call FNC_GetPos; + + if (!helperDetach) then { + detach _objectHelper; + }; + + _helperPos set [2,((_helperPos select 2) + _delta)]; + + if (_isAllowedUnderGround == 0 && (_helperPos select 2) < (_offset select 2)) then { + _helperPos set [2, _offset select 2]; + }; + + if (surfaceIsWater _helperPos) then { + _objectHelper setPosASL _helperPos; + } else { + _objectHelper setPosATL _helperPos; + }; + if (!helperDetach) then { + _objectHelper attachTo [player]; + }; + + [_objectHelper, [DZE_memForBack, DZE_memLeftRight, DZE_memDir]] call fnc_SetPitchBankYaw; + + _helperPos = _objectHelper modelToWorld [0,0,0]; + local _objectPos = _object modelToWorld [0,0,0]; }; - _objHDiff = 0; - _cancel = false; - _reason = ""; + /////////////////////////////////////////////////////////////////////////////////////////// + // + // _rotate function + // + /////////////////////////////////////////////////////////////////////////////////////////// - helperDetach = false; - _canDo = (!r_drag_sqf && !r_player_unconscious); - _position = [_objectHelper] call FNC_GetPos; + local _rotate = { + local _degrees = [45, DZE_curDegree] select DZE_dirWithDegrees; + + if (_this == -1) then {_degrees = -_degrees}; // Q Key + DZE_memDir = DZE_memDir + _degrees; + + [_objectHelper, [DZE_memForBack, DZE_memLeftRight, DZE_memDir]] call fnc_SetPitchBankYaw; + }; + + /////////////////////////////////////////////////////////////////////////////////////////// + // + // _attach function + // + /////////////////////////////////////////////////////////////////////////////////////////// + + local _attach = { + _objectHelper attachTo [player]; + + DZE_memDir = DZE_memDir - (getDir player); + [_objectHelper, [DZE_memForBack, DZE_memLeftRight, DZE_memDir]] call fnc_SetPitchBankYaw; + + helperDetach = false; + }; + + /////////////////////////////////////////////////////////////////////////////////////////// + // + // _detach function + // + /////////////////////////////////////////////////////////////////////////////////////////// + + local _detach = { + _objectHelperPos = getPosATL _objectHelper; + detach _objectHelper; + + DZE_memDir = getDir _objectHelper; + [_objectHelper, [DZE_memForBack, DZE_memLeftRight, DZE_memDir]] call fnc_SetPitchBankYaw; + + _objectHelper setPosATL _objectHelperPos; + _objectHelper setVelocity [0,0,0]; + + helperDetach = true; + }; + + /////////////////////////////////////////////////////////////////////////////////////////// + // + // Main Loop + // + /////////////////////////////////////////////////////////////////////////////////////////// while {_isOk} do { - _zheightchanged = false; - _zheightdirection = ""; - _rotate = false; - - if (DZE_Q) then { - DZE_Q = false; - _zheightdirection = "up"; - _zheightchanged = true; - }; - if (DZE_Z) then { - DZE_Z = false; - _zheightdirection = "down"; - _zheightchanged = true; - }; - if (DZE_Q_alt) then { - DZE_Q_alt = false; - _zheightdirection = "up_alt"; - _zheightchanged = true; - }; - if (DZE_Z_alt) then { - DZE_Z_alt = false; - _zheightdirection = "down_alt"; - _zheightchanged = true; - }; - if (DZE_Q_ctrl) then { - DZE_Q_ctrl = false; - _zheightdirection = "up_ctrl"; - _zheightchanged = true; - }; - if (DZE_Z_ctrl) then { - DZE_Z_ctrl = false; - _zheightdirection = "down_ctrl"; - _zheightchanged = true; - }; - if (DZE_4) then { - _rotate = true; - DZE_4 = false; - if (DZE_dirWithDegrees) then{ - DZE_memDir = DZE_memDir - DZE_curDegree; - }else{ - DZE_memDir = DZE_memDir - 45; - }; - }; - if (DZE_6) then { - _rotate = true; - DZE_6 = false; - if (DZE_dirWithDegrees) then{ - DZE_memDir = DZE_memDir + DZE_curDegree; - }else{ - DZE_memDir = DZE_memDir + 45; - }; + // raise/lower object + call { + if (DZE_Q) exitWith {DZE_Q = false; 0.10 call _change_height;}; // +10cm + if (DZE_Z) exitWith {DZE_Z = false; -0.10 call _change_height;}; // -10cm + if (DZE_Q_alt) exitWith {DZE_Q_alt = false; 1.00 call _change_height;}; // +1m + if (DZE_Z_alt) exitWith {DZE_Z_alt = false; -1.00 call _change_height;}; // -1m + if (DZE_Q_ctrl) exitWith {DZE_Q_ctrl = false; 0.01 call _change_height;}; // +1cm + if (DZE_Z_ctrl) exitWith {DZE_Z_ctrl = false; -0.01 call _change_height;}; // -1cm }; - if (DZE_updateVec) then{ - [_objectHelper,[DZE_memForBack,DZE_memLeftRight,DZE_memDir]] call fnc_SetPitchBankYaw; + // rotate object + call { + if (DZE_4) exitWith {DZE_4 = false; -1 call _rotate;}; // Q Key + if (DZE_6) exitWith {DZE_6 = false; 1 call _rotate;}; // E Key + }; + + // vector object + if (DZE_updateVec) then { + [_objectHelper, [DZE_memForBack, DZE_memLeftRight, DZE_memDir]] call fnc_SetPitchBankYaw; DZE_updateVec = false; }; - if (DZE_F and _canDo) then { + local _canDo = (!r_drag_sqf && !r_player_unconscious); + + // hold or release object + if (DZE_F and _canDo) then { // F Key + if (helperDetach) then { - _objectHelper attachTo [player]; - DZE_memDir = DZE_memDir-(getDir player); - helperDetach = false; - [_objectHelper,[DZE_memForBack,DZE_memLeftRight,DZE_memDir]] call fnc_SetPitchBankYaw; + + call _attach; } else { - _objectHelperPos = getPosATL _objectHelper; - detach _objectHelper; - DZE_memDir = getDir _objectHelper; - [_objectHelper,[DZE_memForBack,DZE_memLeftRight,DZE_memDir]] call fnc_SetPitchBankYaw; - _objectHelper setPosATL _objectHelperPos; - _objectHelper setVelocity [0,0,0]; - helperDetach = true; + call _detach; }; + DZE_F = false; }; - if (_rotate) then { - [_objectHelper,[DZE_memForBack,DZE_memLeftRight,DZE_memDir]] call fnc_SetPitchBankYaw; + uiSleep 0.1; // default: 0.5 + + // Swimming, in vehicle, on ladder, in combat + _reason = call _misc_checks; + if (_reason != "") exitWith { + call _cancel_build; + _reason = localize _reason; }; - if (_zheightchanged) then { - if (!helperDetach) then { - detach _objectHelper; - }; + /////////////////////////////////////////////////////////////////////////////////// + // + // player has plot pole + // + /////////////////////////////////////////////////////////////////////////////////// - _position = [_objectHelper] call FNC_GetPos; + _objectPos = [_object] call FNC_GetPos; // object position - if (_zheightdirection == "up") then { - _position set [2,((_position select 2)+0.1)]; - _objHDiff = _objHDiff + 0.1; - }; - if (_zheightdirection == "down") then { - _position set [2,((_position select 2)-0.1)]; - _objHDiff = _objHDiff - 0.1; - }; - - if (_zheightdirection == "up_alt") then { - _position set [2,((_position select 2)+1)]; - _objHDiff = _objHDiff + 1; - }; - if (_zheightdirection == "down_alt") then { - _position set [2,((_position select 2)-1)]; - _objHDiff = _objHDiff - 1; - }; - - if (_zheightdirection == "up_ctrl") then { - _position set [2,((_position select 2)+0.01)]; - _objHDiff = _objHDiff + 0.01; - }; - if (_zheightdirection == "down_ctrl") then { - _position set [2,((_position select 2)-0.01)]; - _objHDiff = _objHDiff - 0.01; - }; - - if ((_isAllowedUnderGround == 0) && {(_position select 2) < 0}) then { - _position set [2,0]; - }; - - if (surfaceIsWater _position) then { - _objectHelper setPosASL _position; - } else { - _objectHelper setPosATL _position; - }; - - if (!helperDetach) then { - _objectHelper attachTo [player]; - }; - [_objectHelper,[DZE_memForBack,DZE_memLeftRight,DZE_memDir]] call fnc_SetPitchBankYaw; + if (_isPole) then { + _findNearestPole = _objectPos nearEntities ["Plastic_Pole_EP1_DZ", _minDistance]; // check for nearby plots within range of current pole + _findNearestPole = _findNearestPole - [_object]; // exclude current pole + }; + if (count _findNearestPole > 0) exitWith { // pole is too close to another plot + call _cancel_build; + _reason = format[localize "str_epoch_player_44", _minDistance]; }; - uiSleep 0.5; + /////////////////////////////////////////////////////////////////////////////////// + // + // object was initially within plot radius + // + /////////////////////////////////////////////////////////////////////////////////// - _location2 = [player] call FNC_GetPos; - _objectHelperPos = [_objectHelper] call FNC_GetPos; + _playerPos = [player] call FNC_GetPos; // player's current position + + if (_inRadius) then { + _polePos = [_nearestPole] call FNC_GetPos; + + call { + if ((_polePos distance _playerPos) > _ozone) exitWith {_reason = localize "STR_EPOCH_BUILD_MOVE_TOO_FAR"}; // You moved too far! + if ((_polePos distance _objectPos) > _radius) exitWith {_reason = localize "STR_EPOCH_BUILD_OBJ_MOVE_TOO_FAR"}; // Object moved too far! + }; + }; + if (_reason != "") exitWith { + call _cancel_build; + }; + + /////////////////////////////////////////////////////////////////////////////////// + // + // other checks + // + /////////////////////////////////////////////////////////////////////////////////// + + local _anim = animationState player; + local _speed = floor(abs(speed player)); + local _isWalking = ([_walk, _anim] call fnc_inString); + local _isRunning = ([_run, _anim] call fnc_inString); + local _isSprinting = ([_sprint, _anim] call fnc_inString); + local _isFastWalking = (_isWalking && (_speed >= 10)); // fast walking on steep incline + local _tooFast = (!helperDetach && (_isRunning || _isSprinting || _isFastWalking)); // fast movement on level ground + local _tooHigh = (_isBHL && ((_objectPos select 2) > _BHL)); + + call { + if (_tooFast) exitWith {_reason = localize "STR_EPOCH_BUILD_MOVE_TOO_FAST"}; // You moved too fast! + if (_tooHigh) exitWith {_reason = format[localize "STR_EPOCH_PLAYER_168", _BHL]}; // object moved above height limit + if (!canbuild) exitWith {_reason = format[localize "STR_EPOCH_PLAYER_136", localize "STR_EPOCH_TRADER"]}; // trader nearby + if (DZE_cancelBuilding) exitWith {_reason = localize "STR_EPOCH_PLAYER_46"}; // ESC Key + }; + if (_reason != "") exitWith { + call _cancel_build; + }; + + /////////////////////////////////////////////////////////////////////////////////// + // + // space bar - place object + // + /////////////////////////////////////////////////////////////////////////////////// if (DZE_5) exitWith { _isOk = false; - _position = [_object] call FNC_GetPos; + _objectPos = [_object] call FNC_GetPos; + _zPos = (_objectPos select 2); detach _object; _dir = getDir _object; _vector = [(vectorDir _object),(vectorUp _object)]; @@ -287,132 +467,196 @@ if (_canBuild select 0) then { detach _objectHelper; deleteVehicle _objectHelper; }; + }; - if (_location1 distance _location2 > DZE_buildMaxMoveDistance) exitWith { - _isOk = false; - _cancel = true; - _reason = format[localize "STR_EPOCH_BUILD_FAIL_MOVED",DZE_buildMaxMoveDistance]; - detach _object; - deleteVehicle _object; - detach _objectHelper; - deleteVehicle _objectHelper; - }; + /////////////////////////////////////////////////////////////////////////////////////////// - if (_location1 distance _objectHelperPos > DZE_buildMaxMoveDistance) exitWith { - _isOk = false; - _cancel = true; - _reason = format[localize "STR_EPOCH_BUILD_FAIL_TOO_FAR",DZE_buildMaxMoveDistance]; - detach _object; - deleteVehicle _object; - detach _objectHelper; - deleteVehicle _objectHelper; - }; + // Delete Helper Array + {deleteVehicle _x;} count _pArray; + _pArray = []; - if (abs(_objHDiff) > DZE_buildMaxHeightDistance) exitWith { - _isOk = false; - _cancel = true; - _reason = format[localize "STR_EPOCH_BUILD_FAIL_HEIGHT",DZE_buildMaxHeightDistance]; - detach _object; - deleteVehicle _object; - detach _objectHelper; - deleteVehicle _objectHelper; - }; + /////////////////////////////////////////////////////////////////////////////////////////// + // + // Double check that object/pole height does not violate distance requirements + // + /////////////////////////////////////////////////////////////////////////////////////////// - if (DZE_BuildHeightLimit > 0 && {_position select 2 > DZE_BuildHeightLimit}) exitWith { - _isOk = false; - _cancel = true; - _reason = format[localize "STR_EPOCH_PLAYER_168",DZE_BuildHeightLimit]; - detach _object; - deleteVehicle _object; - detach _objectHelper; - deleteVehicle _objectHelper; - }; + if (!_cancel && (_isAllowedUnderGround == 0) && (_zPos < (_offset select 2))) then { // object/pole was improperly placed below ground - if (player getVariable["combattimeout",0] >= diag_tickTime) exitWith { - _isOk = false; - _cancel = true; - _reason = localize "str_epoch_player_43"; - detach _object; - deleteVehicle _object; - detach _objectHelper; - deleteVehicle _objectHelper; - }; + _objectPos set [2, _offset select 2]; // raise up to ground/sea level - if (DZE_cancelBuilding) exitWith { - _isOk = false; - _cancel = true; - _reason = localize "STR_EPOCH_PLAYER_46"; - detach _object; - deleteVehicle _object; - detach _objectHelper; - deleteVehicle _objectHelper; + if (_isPole) then { // check for nearby plots within range + local _findNearestPole = []; + _findNearestPole = _objectPos nearEntities ["Plastic_Pole_EP1_DZ", _minDistance]; + _findNearestPole = _findNearestPole - [_object]; + + if (count _findNearestPole > 0) then { + _cancel = true; + _reason = format[localize "str_epoch_player_44", _minDistance]; // pole is too close to another plot + }; + } else { + if (_inRadius && ((_polePos distance _objectPos) > _radius)) then { + _cancel = true; + _reason = localize "STR_EPOCH_BUILD_OBJ_MOVE_TOO_FAR"; // object has moved outside radius + }; }; }; - _isOk = true; - _proceed = false; - _counter = 0; - _location = [0,0,0]; + /////////////////////////////////////////////////////////////////////////////////////////// + // + // You cannot build on a road. + // + /////////////////////////////////////////////////////////////////////////////////////////// - if (!DZE_BuildOnRoads) then { - if (isOnRoad _position) then { _cancel = true; _reason = localize "STR_EPOCH_BUILD_FAIL_ROAD"; }; + if (!_cancel && !DZE_BuildOnRoads && (isOnRoad _objectPos)) then { + _cancel = true; + _reason = localize "STR_EPOCH_BUILD_FAIL_ROAD"; }; - if (!canbuild) then { _cancel = true; _reason = format[localize "STR_EPOCH_PLAYER_136",localize "STR_EPOCH_TRADER"]; }; + + /////////////////////////////////////////////////////////////////////////////////////////// + // + // You do not have access to build on this plot. + // + /////////////////////////////////////////////////////////////////////////////////////////// if (!_cancel) then { - _classname = _classnametmp; - _tmpbuilt = _classname createVehicle _location; - //_tmpbuilt setdir _dir; // setdir is incompatible with setVectorDirAndUp and should not be used together on the same object https://community.bistudio.com/wiki/setVectorDirAndUp - _tmpbuilt setVariable["memDir",_dir,true]; - _location = _position; + + _findNearestPole = _objectPos nearEntities ["Plastic_Pole_EP1_DZ", _minDistance]; // check for nearby plots within range of current pole + _findNearestPole = _findNearestPole - [_object]; // exclude current pole - if ((_isAllowedUnderGround == 0) && {(_location select 2) < 0}) then { - _location set [2,0]; + if (count _findNearestPole > 0) then { // is near plot + + _nearestPole = _findNearestPole select 0; // get first entry + _ownerID = _nearestPole getVariable["CharacterID","0"]; + + if (dayz_characterID != _ownerID) then { // not the owner + + if (DZE_permanentPlot) then { + _buildcheck = [player, _nearestPole] call FNC_check_access; + _isowner = _buildcheck select 0; + _isfriendly = ((_buildcheck select 1) || (_buildcheck select 3)); + if (!_isowner && !_isfriendly) then { + _cancel = true; + }; + } else { + _friendlies = player getVariable ["friendlyTo",[]]; + if !(_ownerID in _friendlies) then { + _cancel = true; + }; + }; + if (_cancel) then { + _reason = localize "STR_EPOCH_PLAYER_134"; // You do not have access to build on this plot. + }; + }; }; + }; + + /////////////////////////////////////////////////////////////////////////////////////////// + // + // You cannot build. There are too many objects within "DZE_maintainRange" m. + // + /////////////////////////////////////////////////////////////////////////////////////////// + + if (!_cancel) then { + _buildables = DZE_maintainClasses + DZE_LockableStorage + ["DZ_storage_base"]; + + if (_isPole && ((count (nearestObjects [_objectPos, _buildables, DZE_maintainRange])) >= DZE_BuildingLimit)) then { // object's position + _cancel = true; + _reason = format[localize "str_epoch_player_41", floor DZE_maintainRange]; // You cannot build. There are too many objects within %1m. + }; + }; + + /////////////////////////////////////////////////////////////////////////////////////////// + // + // You can't build a "displayName" within "_distance" meters of a safe zone. + // + /////////////////////////////////////////////////////////////////////////////////////////// + + if (!_cancel) then { + + local _checkOK = false; + local _distance = DZE_SafeZoneNoBuildDistance; + { + if (typeName _x == "ARRAY") then { + if (_x select 0 == _classname) then { + _checkOK = true; + _distance = _x select 1; + }; + } else { + if (_x == _classname) then { + _checkOK = true; + }; + }; + if (_checkOK) exitWith {}; + } count DZE_SafeZoneNoBuildItems; + + if (_checkOK && !_isAdmin) then { + _canBuild = !([_objectPos, _distance] call DZE_SafeZonePosCheck); // object's position + }; + if (!_canBuild) then { + _cancel = true; + _reason = format [localize "STR_EPOCH_PLAYER_166", _text, _distance]; // You can't build a %1 within %2 meters of a safe zone. + }; + }; + + /////////////////////////////////////////////////////////////////////////////////////////// + // + // You can't build a "displayName" within "DZE_NoBuildNearDistance" meters of a "class". + // + /////////////////////////////////////////////////////////////////////////////////////////// + + if (!_cancel) then { + if ((count DZE_NoBuildNear > 0) && !_isAdmin) then { + _near = (nearestObjects [_objectPos, DZE_NoBuildNear, DZE_NoBuildNearDistance]); // object's position + + if ((count _near) > 0) then { + _cancel = true; + _reason = format [localize "STR_EPOCH_PLAYER_167", _text, DZE_NoBuildNearDistance, typeOf (_near select 0)]; // You can't build a %1 within %2 meters of a %3. + }; + }; + }; + + /////////////////////////////////////////////////////////////////////////////////////////// + + if (!_cancel) then { + + _classname = _classnametmp; + local _tmpbuilt = _classname createVehicle [0,0,0]; + //_tmpbuilt setdir _dir; // setdir is incompatible with setVectorDirAndUp and should not be used together on the same object https://community.bistudio.com/wiki/setVectorDirAndUp + _tmpbuilt setVariable["memDir", _dir, true]; + local _position = _objectPos; _tmpbuilt setVectorDirAndUp _vector; - _buildOffset = [0,0,0]; - _vUp = _vector select 1; - - /* - switch (_classname) do { - case "MetalFloor_DZ": { _buildOffset = [(_vUp select 0) * .148, (_vUp select 1) * .148,0]; }; - }; - - */ - _location = [ - (_location select 0) - (_buildOffset select 0), - (_location select 1) - (_buildOffset select 1), - (_location select 2) - (_buildOffset select 2) - ]; - - if (surfaceIsWater _location) then { - _tmpbuilt setPosASL _location; - _location = ASLtoATL _location; + if (surfaceIsWater _position) then { + _tmpbuilt setPosASL _position; + _position = ASLtoATL _position; } else { - _tmpbuilt setPosATL _location; + _tmpbuilt setPosATL _position; }; - format[localize "str_epoch_player_138",_text] call dayz_rollingMessages; + //format[localize "str_epoch_player_138", _text] call dayz_rollingMessages; // Placing %1, move to cancel. - _limit = 3; + local _limit = 3; if (DZE_StaticConstructionCount > 0) then { _limit = DZE_StaticConstructionCount; - } - else { + } else { if (isNumber (configFile >> "CfgVehicles" >> _classname >> "constructioncount")) then { _limit = getNumber(configFile >> "CfgVehicles" >> _classname >> "constructioncount"); }; }; + _isOk = true; + local _counter = 0; + local _proceed = false; + while {_isOk} do { - format[localize "str_epoch_player_139",_text, (_counter + 1),_limit] call dayz_rollingMessages; //report how many steps are done out of total limit + format[localize "str_epoch_player_139", _text, (_counter + 1), _limit] call dayz_rollingMessages; // Constructing %1 stage %2 of %3, move to cancel. - [player,(getPosATL player),40,"repair"] spawn fnc_alertZombies; + [player, (getPosATL player), 40, "repair"] spawn fnc_alertZombies; - _finished = ["Medic",1,{player getVariable["combattimeout",0] >= diag_tickTime or DZE_cancelBuilding}] call fn_loopAction; + local _finished = ["Medic", 1, {player getVariable["combattimeout", 0] >= diag_tickTime or DZE_cancelBuilding}] call fn_loopAction; if (!_finished) exitWith { _isOk = false; @@ -431,54 +675,78 @@ if (_canBuild select 0) then { if (_proceed) then { - _num_removed = ([player,DZE_buildItem] call BIS_fnc_invRemove); //remove item's magazine from inventory - if (_num_removed == 1) then { - ["Working",0,[20,10,5,0]] call dayz_NutritionSystem; - call player_forceSave; - [format[localize "str_build_01",_text],1] call dayz_rollingMessages; + local _num_removed = ([player, DZE_buildItem] call BIS_fnc_invRemove); // remove item's magazine from inventory - _tmpbuilt setVariable ["OEMPos",_location,true]; //store original location as a variable + if (_num_removed == 1) then { + + local _friendsArr = []; + + ["Working", 0, [20,10,5,0]] call dayz_NutritionSystem; + call player_forceSave; + + [format[localize "str_build_01", _text], 1] call dayz_rollingMessages; + _tmpbuilt setVariable ["OEMPos", _position, true]; // store original location as a variable if (_lockable > 1) then { //if item has code lock on it - _combinationDisplay = ""; //define new display + local _combination = ""; + local _combinationDisplay = ""; //define new display + local _combination_1_Display = ""; + local _combination_1 = 0; + local _combination_2 = 0; + local _combination_3 = 0; + local _combination_4 = 0; - call { //generate random combinations depending on item type + dayz_combination = ""; + dayz_selectedVault = objNull; - if (_lockable == 2) exitwith { // 2 lockbox - dayz_combination = ""; - dayz_selectedVault = objNull; + call { // generate random combinations depending on item type + + /////////////////////////////////////////////////// + // + // 2 Lockbox + // + /////////////////////////////////////////////////// + + if (_lockable == 2) exitWith { createDialog "KeyPadUI"; waitUntil {!dialog}; _combinationDisplay = dayz_combination call fnc_lockCode; + if (keypadCancel || {typeName _combinationDisplay == "SCALAR"}) then { - _combination_1 = (floor(random 3)) + 100; // 100=red,101=green,102=blue + + _combination_1 = (floor(random 3)) + 100; // 100=red / 101=green / 102=blue _combination_2 = floor(random 10); _combination_3 = floor(random 10); + _combination = format["%1%2%3",_combination_1,_combination_2,_combination_3]; dayz_combination = _combination; - if (_combination_1 == 100) then { - _combination_1_Display = localize "STR_TEAM_RED"; + + call { + if (_combination_1 == 100) exitWith {_combination_1_Display = localize "STR_TEAM_RED"}; + if (_combination_1 == 101) exitWith {_combination_1_Display = localize "STR_TEAM_GREEN"}; + if (_combination_1 == 102) exitWith {_combination_1_Display = localize "STR_TEAM_BLUE"}; }; - if (_combination_1 == 101) then { - _combination_1_Display = localize "STR_TEAM_GREEN"; - }; - if (_combination_1 == 102) then { - _combination_1_Display = localize "STR_TEAM_BLUE"; - }; - _combinationDisplay = format["%1%2%3",_combination_1_Display,_combination_2,_combination_3]; + _combinationDisplay = format["%1%2%3", _combination_1_Display, _combination_2, _combination_3]; } else { _combination = dayz_combination; }; }; - if (_lockable == 3) exitwith { // 3 combolock - DZE_topCombo = 0; - DZE_midCombo = 0; - DZE_botCombo = 0; - DZE_Lock_Door = ""; + /////////////////////////////////////////////////// + // + // 3 Combo Lock + // + /////////////////////////////////////////////////// + + if (_lockable == 3) exitWith { + + DZE_topCombo = 0; + DZE_midCombo = 0; + DZE_botCombo = 0; + DZE_Lock_Door = ""; dayz_selectedDoor = objNull; dayz_actionInProgress = false; @@ -487,10 +755,13 @@ if (_canBuild select 0) then { dayz_actionInProgress = true; if (keypadCancel || {parseNumber DZE_Lock_Door == 0}) then { - _combination_1 = floor(random 10); - _combination_2 = floor(random 10); - _combination_3 = floor(random 10); - _combination = format["%1%2%3",_combination_1,_combination_2,_combination_3]; + + _combination_1 = floor(random 10); + _combination_2 = floor(random 10); + _combination_3 = floor(random 10); + + _combination = format["%1%2%3", _combination_1, _combination_2, _combination_3]; + DZE_Lock_Door = _combination; } else { _combination = DZE_Lock_Door; @@ -502,19 +773,26 @@ if (_canBuild select 0) then { _combinationDisplay = _combination; }; - if (_lockable == 4) exitwith { // 4 safe - dayz_combination = ""; - dayz_selectedVault = objNull; + /////////////////////////////////////////////////// + // + // 4 Safe + // + /////////////////////////////////////////////////// + + if (_lockable == 4) exitWith { createDialog "SafeKeyPad"; waitUntil {!dialog}; if (keypadCancel || {(parseNumber dayz_combination) > 9999} || {count (toArray (dayz_combination)) < 4}) then { - _combination_1 = floor(random 10); - _combination_2 = floor(random 10); - _combination_3 = floor(random 10); - _combination_4 = floor(random 10); - _combination = format["%1%2%3%4",_combination_1,_combination_2,_combination_3,_combination_4]; + + _combination_1 = floor(random 10); + _combination_2 = floor(random 10); + _combination_3 = floor(random 10); + _combination_4 = floor(random 10); + + _combination = format["%1%2%3%4", _combination_1, _combination_2, _combination_3, _combination_4]; + dayz_combination = _combination; } else { _combination = dayz_combination; @@ -523,63 +801,75 @@ if (_canBuild select 0) then { }; }; - _tmpbuilt setVariable ["CharacterID",_combination,true]; //set combination as a character ID + _tmpbuilt setVariable ["CharacterID", _combination, true]; // set combination as a character ID - //call publish precompiled function with given args and send public variable to server to save item to database + // call publish precompiled function with given args and send public variable to server to save item to database if (DZE_permanentPlot) then { - _tmpbuilt setVariable ["ownerPUID",dayz_playerUID,true]; - PVDZ_obj_Publish = [_combination,_tmpbuilt,[_dir,_location,dayz_playerUID,_vector],[],player,dayz_authKey]; + + _tmpbuilt setVariable ["ownerPUID", dayz_playerUID, true]; + + PVDZ_obj_Publish = [_combination, _tmpbuilt, [_dir, _position, dayz_playerUID, _vector], [], player, dayz_authKey]; + if (_lockable == 3) then { - _friendsArr = [[dayz_playerUID,toArray (name player)]]; + + _friendsArr = [[dayz_playerUID, toArray (name player)]]; _tmpbuilt setVariable ["doorfriends", _friendsArr, true]; - PVDZ_obj_Publish = [_combination,_tmpbuilt,[_dir,_location,dayz_playerUID,_vector],_friendsArr,player,dayz_authKey]; + + PVDZ_obj_Publish = [_combination, _tmpbuilt, [_dir, _position, dayz_playerUID, _vector], _friendsArr, player, dayz_authKey]; }; } else { - PVDZ_obj_Publish = [_combination,_tmpbuilt,[_dir,_location, _vector],[],player,dayz_authKey]; + PVDZ_obj_Publish = [_combination, _tmpbuilt, [_dir, _position, _vector], [], player, dayz_authKey]; }; + publicVariableServer "PVDZ_obj_Publish"; - [format[localize "str_epoch_player_140",_combinationDisplay,_text],1] call dayz_rollingMessages; //display new combination - systemChat format[localize "str_epoch_player_140",_combinationDisplay,_text]; + [format[localize "str_epoch_player_140", _combinationDisplay, _text], 1] call dayz_rollingMessages; // display new combination + systemChat format[localize "str_epoch_player_140", _combinationDisplay, _text]; // You have setup your %2. The combination is %1 - } else { //if not lockable item - _tmpbuilt setVariable ["CharacterID",dayz_characterID,true]; - // fire? - if (_tmpbuilt isKindOf "Land_Fire_DZ") then { //if campfire, then spawn, but do not publish to database - [_tmpbuilt,true] call dayz_inflame; + } else { // if not lockable item + + _tmpbuilt setVariable ["CharacterID", dayz_characterID, true]; + + // fireplace + if (_tmpbuilt isKindOf "Land_Fire_DZ") then { // if campfire, then spawn, but do not publish to database + + [_tmpbuilt, true] call dayz_inflame; _tmpbuilt spawn player_fireMonitor; } else { if (DZE_permanentPlot) then { - _tmpbuilt setVariable ["ownerPUID",dayz_playerUID,true]; - if (_canBuild select 1) then { - _friendsArr = [[dayz_playerUID,toArray (name player)]]; + + _tmpbuilt setVariable ["ownerPUID", dayz_playerUID, true]; + + if (_isPole) then { + + _friendsArr = [[dayz_playerUID, toArray (name player)]]; _tmpbuilt setVariable ["plotfriends", _friendsArr, true]; - PVDZ_obj_Publish = [dayz_characterID,_tmpbuilt,[_dir,_location,dayz_playerUID,_vector],_friendsArr,player,dayz_authKey]; + + PVDZ_obj_Publish = [dayz_characterID, _tmpbuilt, [_dir, _position, dayz_playerUID, _vector], _friendsArr, player, dayz_authKey]; } else { - PVDZ_obj_Publish = [dayz_characterID,_tmpbuilt,[_dir,_location,dayz_playerUID,_vector],[],player,dayz_authKey]; + PVDZ_obj_Publish = [dayz_characterID, _tmpbuilt, [_dir, _position, dayz_playerUID, _vector], [], player, dayz_authKey]; }; } else { - PVDZ_obj_Publish = [dayz_characterID,_tmpbuilt,[_dir,_location, _vector],[],player,dayz_authKey]; + PVDZ_obj_Publish = [dayz_characterID, _tmpbuilt, [_dir, _position, _vector], [], player, dayz_authKey]; }; + publicVariableServer "PVDZ_obj_Publish"; }; }; if (DZE_GodModeBase && {!(_classname in DZE_GodModeBaseExclude)}) then { - _tmpbuilt addEventHandler ["HandleDamage",{false}]; + _tmpbuilt addEventHandler ["HandleDamage", {false}]; }; - } else { //if magazine was not removed, cancel publish + } else { // if magazine was not removed, cancel publish deleteVehicle _tmpbuilt; - localize "str_epoch_player_46" call dayz_rollingMessages; + localize "str_epoch_player_46" call dayz_rollingMessages; // Canceled building. }; - - } else { //if player was interrupted cancel publish + } else { // if player was interrupted cancel publish deleteVehicle _tmpbuilt; - localize "str_epoch_player_46" call dayz_rollingMessages; + localize "str_epoch_player_46" call dayz_rollingMessages; // Canceled building. }; - - } else { //cancel build if passed _cancel arg was true or building on roads/trader city - format[localize "str_epoch_player_47",_text,_reason] call dayz_rollingMessages; + } else { // cancel build if passed _cancel arg was true or building on roads/trader city + format[localize "str_epoch_player_47", _text, _reason] call dayz_rollingMessages; // Canceled construction of %1, %2. }; }; - +DZE_buildItem = nil; dayz_actionInProgress = false; diff --git a/SQF/dayz_code/actions/player_buildingMaint.sqf b/SQF/dayz_code/actions/player_buildingMaint.sqf index 4039caac2..62e7fc4ec 100644 --- a/SQF/dayz_code/actions/player_buildingMaint.sqf +++ b/SQF/dayz_code/actions/player_buildingMaint.sqf @@ -1,92 +1,119 @@ -/* - DayZ Base Building Maintenance - Made for DayZ Epoch please ask permission to use/edit/distrubute email vbawol@veteranbastards.com. -*/ -if (dayz_actionInProgress) exitWith {localize "str_epoch_player_52" call dayz_rollingMessages;}; +/////////////////////////////////////////////////////////////////////////////////////////////////// +// +// DayZ Base Building Maintenance +// Made for DayZ Epoch please ask permission to use/edit/distrubute email vbawol@veteranbastards.com. +// +// Upgraded by: Victor the Cleaner +// Date: August 2021 +// +// - Now includes helper spheres for improved player experience +// +/////////////////////////////////////////////////////////////////////////////////////////////////// +if (dayz_actionInProgress) exitWith {localize "str_epoch_player_52" call dayz_rollingMessages;}; // Upgrade is already in progress. dayz_actionInProgress = true; -private ["_classname","_missing","_proceed","_num_removed","_missingQty","_itemIn","_countIn","_qty","_removed","_removed_total","_tobe_removed_total","_objectID","_objectUID","_temp_removed_array","_textMissing","_requirements","_obj","_upgrade","_finished"]; - player removeAction s_player_maint_build; s_player_maint_build = 1; -// get cursortarget from addaction -_obj = _this select 3; +local _obj = _this select 3; -// Find objectID -_objectID = _obj getVariable ["ObjectID","0"]; +local _objectID = _obj getVariable ["ObjectID","0"]; +local _objectUID = _obj getVariable ["ObjectUID","0"]; -// Find objectUID -_objectUID = _obj getVariable ["ObjectUID","0"]; - -if (_objectID == "0" && _objectUID == "0") exitWith {dayz_actionInProgress = false; s_player_maint_build = -1; localize "str_epoch_player_50" call dayz_rollingMessages;}; - -// Get classname -_classname = typeOf _obj; - -// Find next maintain -_upgrade = getArray (configFile >> "CfgVehicles" >> _classname >> "maintainBuilding"); - -if ((count _upgrade) > 0) then { - _requirements = _upgrade; -} else { - _requirements = [["PartGeneric",1]]; +if (_objectID == "0" && _objectUID == "0") exitWith { + dayz_actionInProgress = false; + s_player_maint_build = -1; + localize "str_epoch_player_50" call dayz_rollingMessages; // Not setup yet. }; -_missingQty = 0; -_missing = ""; +local _classname = typeOf _obj; + +// Find next maintain +local _upgrade = getArray (configFile >> "CfgVehicles" >> _classname >> "maintainBuilding"); +local _requirements = []; + +if (count _upgrade > 0) then { + _requirements = _upgrade; +} else { + _requirements = [["PartGeneric", 1]]; +}; + +local _missingQty = 0; +local _missing = ""; +local _proceed = true; -_proceed = true; { - _itemIn = _x select 0; - _countIn = _x select 1; - _qty = { (_x == _itemIn) || (configName(inheritsFrom(configFile >> "cfgMagazines" >> _x)) == _itemIn) } count magazines player; - if(_qty < _countIn) exitWith { _missing = _itemIn; _missingQty = (_countIn - _qty); _proceed = false; }; + local _itemIn = _x select 0; + local _countIn = _x select 1; + + local _qty = {(_x == _itemIn) || (configName(inheritsFrom(configFile >> "cfgMagazines" >> _x)) == _itemIn)} count magazines player; + + if (_qty < _countIn) exitWith { + _missing = _itemIn; + _missingQty = _countIn - _qty; + _proceed = false; + }; } forEach _requirements; if (_proceed) then { - [player,(getPosATL player),40,"repair"] spawn fnc_alertZombies; - _finished = ["Medic",1] call fn_loopAction; + [_obj] call fn_displayHelpers; // create helpers + + [player, (getPosATL player), 40, "repair"] spawn fnc_alertZombies; // make noise + + local _finished = ["Medic", 1] call fn_loopAction; // animation + + [] call fn_displayHelpers; // delete helpers + if (!_finished) exitWith {}; ["Working",0,[20,40,15,0]] call dayz_NutritionSystem; - _temp_removed_array = []; - _removed_total = 0; - _tobe_removed_total = 0; + local _temp_removed_array = []; + local _removed_total = 0; + local _tobe_removed_total = 0; { - _removed = 0; - _itemIn = _x select 0; - _countIn = _x select 1; + local _removed = 0; + local _itemIn = _x select 0; + local _countIn = _x select 1; + // diag_log format["Recipe Finish: %1 %2", _itemIn,_countIn]; + _tobe_removed_total = _tobe_removed_total + _countIn; { - if( (_removed < _countIn) && ((_x == _itemIn) || configName(inheritsFrom(configFile >> "cfgMagazines" >> _x)) == _itemIn)) then { - _num_removed = ([player,_x] call BIS_fnc_invRemove); - _removed = _removed + _num_removed; - _removed_total = _removed_total + _num_removed; - if(_num_removed >= 1) then { - _temp_removed_array set [count _temp_removed_array,_x]; + if (_removed < _countIn && ((_x == _itemIn) || configName(inheritsFrom(configFile >> "cfgMagazines" >> _x)) == _itemIn)) then { + + local _num_removed = ([player, _x] call BIS_fnc_invRemove); + _removed = _removed + _num_removed; + _removed_total = _removed_total + _num_removed; + + if (_num_removed > 0) then { + _temp_removed_array set [count _temp_removed_array, _x]; }; }; + } forEach magazines player; + } forEach _requirements; // all parts removed proceed if (_tobe_removed_total == _removed_total) then { - format[localize "STR_EPOCH_ACTIONS_4",1] call dayz_rollingMessages; - PVDZE_maintainArea = [player,2,[_obj, _objectID, _objectUID]]; + + format[localize "STR_EPOCH_ACTIONS_4" ,1] call dayz_rollingMessages; // You have maintained %1 building parts. + + PVDZE_maintainArea = [player, 2, [_obj, _objectID, _objectUID]]; publicVariableServer "PVDZE_maintainArea"; + } else { + {player addMagazine _x;} count _temp_removed_array; - format[localize "str_epoch_player_145",_removed_total,_tobe_removed_total] call dayz_rollingMessages; + format[localize "str_epoch_player_145", _removed_total, _tobe_removed_total] call dayz_rollingMessages; // Missing Parts after first check Item: %1 / %2 }; } else { - _textMissing = getText(configFile >> "CfgMagazines" >> _missing >> "displayName"); - format[localize "STR_EPOCH_ACTIONS_6",_missingQty, _textMissing] call dayz_rollingMessages; + local _textMissing = getText(configFile >> "CfgMagazines" >> _missing >> "displayName"); + format[localize "STR_EPOCH_ACTIONS_6", _missingQty, _textMissing] call dayz_rollingMessages; // Missing %1 more of %2 }; dayz_actionInProgress = false; diff --git a/SQF/dayz_code/actions/plotManagement/plotToggleMarkers.sqf b/SQF/dayz_code/actions/plotManagement/plotToggleMarkers.sqf index 4107ec6d0..cf9c711e8 100644 --- a/SQF/dayz_code/actions/plotManagement/plotToggleMarkers.sqf +++ b/SQF/dayz_code/actions/plotManagement/plotToggleMarkers.sqf @@ -1,77 +1,105 @@ -//Zero Remorse, big thanks to their scripter for this! -private ["_density","_model","_thePlot","_center","_radius","_angle","_count","_axis","_obj","_idx","_a","_b"]; - -_density = 3; // density of markers per ring -_model = "Sign_sphere100cm_EP1"; // marker model to use on rings -// Possible ones to use :: Sign_sphere10cm_EP1 Sign_sphere25cm_EP1 Sign_sphere100cm_EP1 - -_thePlot = (([player] call FNC_getPos) nearEntities ["Plastic_Pole_EP1_DZ",15]) select 0; -_center = getPosASL _thePlot; -_radius = DZE_PlotPole select 0; -_obj = false; +/////////////////////////////////////////////////////////////////////////////////////////////////// +// +// Display Plot Boundary Helpers +// +// Author: Victor the Cleaner +// Date: August 2021 +// +// - Plot helpers are now displayed in red if they are above DZE_BuildHeightLimit. +// Enabled with DZE_HeightLimitColor. Default: true +// - If the plot pole is on sloping terrain, the red helpers follow the ATL height. +// - Number of helpers per ring is now evenly divisible by 8 for improved symmetry. +// - Will ignore helpers that coincide with other rings. +// - Will only draw helpers above ground/sea level for improved performance. +// - Helpers now align to the pole direction. +// +/////////////////////////////////////////////////////////////////////////////////////////////////// +local _pos = [player] call FNC_getPos; // player position +local _plot = (_pos nearEntities ["Plastic_Pole_EP1_DZ", 15]) select 0; // get nearest plot +local _toggle = false; // turn plot boundary on/off if (!isNil "PP_Marks") then { - if (((PP_Marks select 0) distance _thePlot) < 10) then { _obj = true; }; - { deleteVehicle _x; } count PP_Marks; + + if (((PP_Marks select 0) distance _plot) < 10) then {_toggle = true}; // if helpers exist + {deleteVehicle _x;} count PP_Marks; // remove helpers PP_Marks = nil; }; -if ((isNil "PP_Marks") && (!_obj)) then { - PP_Marks = []; - _count = round((2 * pi * _radius) / _density); +/////////////////////////////////////////////////////////////////////////////////////////////////// +// +// initialize +// +/////////////////////////////////////////////////////////////////////////////////////////////////// - _obj = "Sign_sphere10cm_EP1" createVehicleLocal [0,0,0]; // PARENT marker on pole - _obj setPosASL [_center select 0, _center select 1, _center select 2]; - _obj setObjectTexture [0, "#(argb,16,16,1)color(0,1,0,0.4)"]; - _axis = _obj; - _obj setVectorUp [0, 0, 0]; - PP_Marks set [count PP_Marks, _obj]; - _angle = 0; - for "_idx" from 0 to _count do { - _a = (_center select 0) + (sin(_angle)*_radius); - _b = (_center select 1) + (cos(_angle)*_radius); - _obj = _model createVehicleLocal [0,0,0]; - _obj setPosASL [_a, _b, _center select 2]; - _obj setObjectTexture [0, "#(argb,16,16,1)color(0,1,0,0.4)"]; - _obj attachTo [_axis]; - PP_Marks set [count PP_Marks, _obj]; - _a = (_center select 0) + (sin(_angle)*_radius); - _b = (_center select 2) + (cos(_angle)*_radius); - _obj = _model createVehicleLocal [0,0,0]; - _obj setPosASL [_a, _center select 1, _b]; - _obj setObjectTexture [0, "#(argb,16,16,1)color(0,1,0,0.4)"]; - _obj attachTo [_axis]; - PP_Marks set [count PP_Marks, _obj]; - _angle = _angle + (360/_count); +if ((isNil "PP_Marks") && !_toggle) then { + + local _radius = DZE_PlotPole select 0; // plot radius + local _density = 3; // helper density per ring + local _count = round((2 * pi * _radius) / _density); // initial count per ring + local _segments = _count - (_count % 8); // adjust count for improved symmetry + local _hemi = _segments / 2; // ignore helpers that coincide with equatorial ring + local _quad = _segments / 4; // ignore helpers that coincide with polar/equatorial rings + local _delta = 360 / _segments; // amount of angular change + local _angle = 0; // initialize + local _sin45 = sin 45; // setup polar diagonals + local _color = [DZE_plotGreen, DZE_plotGreen]; // [<= height limit, > height limit]; + local _col = []; // color index + + if (DZE_BuildHeightLimit > 0 && DZE_HeightLimitColor) then { + _color set [1, DZE_plotRed]; // red color if too high }; - _angle = (360/_count); - for "_idx" from 0 to (_count - 2) do { - _a = (_center select 1) + (sin(_angle)*_radius); - _b = (_center select 2) + (cos(_angle)*_radius); - _obj = _model createVehicleLocal [0,0,0]; - _obj setPosASL [_center select 0, _a, _b]; - _obj setObjectTexture [0, "#(argb,16,16,1)color(0,1,0,0.4)"]; - _obj attachTo [_axis]; - PP_Marks set [count PP_Marks, _obj]; - _angle = _angle + (360/_count); - }; - _angle = (360/_count); - _axis setDir 45; - for "_idx" from 0 to (_count - 2) do { - _a = (_center select 0) + (sin(_angle)*_radius); - _b = (_center select 2) + (cos(_angle)*_radius); - _obj = _model createVehicleLocal [0,0,0]; - _obj setPosASL [_a, _center select 1, _b]; - _obj setObjectTexture [0, "#(argb,16,16,1)color(0,1,0,0.4)"]; - _obj attachTo [_axis]; - PP_Marks set [count PP_Marks, _obj]; - _a = (_center select 1) + (sin(_angle)*_radius); - _b = (_center select 2) + (cos(_angle)*_radius); - _obj = _model createVehicleLocal [0,0,0]; - _obj setPosASL [_center select 0, _a, _b]; - _obj setObjectTexture [0, "#(argb,16,16,1)color(0,1,0,0.4)"]; - _obj attachTo [_axis]; - PP_Marks set [count PP_Marks, _obj]; - _angle = _angle + (360/_count); + + local _obj = "Sign_sphere25cm_EP1" createVehicleLocal [0,0,0]; + _obj setObjectTexture DZE_plotGreen; // add color + _obj setPos ([_plot] call FNC_getPos); // move + + PP_Marks = []; // global array to record plot pole helpers + PP_Marks set [0, _obj]; // record parent object + + /////////////////////////////////////////////////////////////////////////////////////////// + // + // calculate ring vectors + // + /////////////////////////////////////////////////////////////////////////////////////////// + + for "_i" from 0 to (_segments -1) do { // loop through each point on the ring + + local _a = (sin _angle) * _radius; // increasing offset + local _b = (cos _angle) * _radius; // decreasing offset + + local _v = [[_a, _b, 0]]; // equatorial ring + + if ((_i + _quad) % _hemi != 0) then { // ignore equator + + _v = _v + [[_a, 0, _b]]; // longitudinal Y ring + + if (_i % _hemi != 0) then { // longitudinal X ring + polar diagonals. ignore equator and poles + local _d = _sin45 * _a; // polar diagonals +/-45° + + _v = _v + [[0, _a, _b], [_d, _d, _b], [-_d, _d, _b]]; + }; + }; + /////////////////////////////////////////////////////////////////////////// + // + // realign and draw each ring + // + /////////////////////////////////////////////////////////////////////////// + { + local _vN = _plot modelToWorld _x; // realign + + local _height = _vN select 2; // ATL Z + if (_height > -0.5) then { // if aboveground + + _obj = "Sign_sphere100cm_EP1" createVehicleLocal [0,0,0]; // create + _col = _color select (_height > DZE_BuildHeightLimit); // if too high + _obj setObjectTexture _col; // change color + _obj setPosASL (ATLToASL _vN); // move + + PP_Marks set [count PP_Marks, _obj]; // record object + }; + + } forEach _v; + + _angle = _angle + _delta; // aggregate radial angle }; }; diff --git a/SQF/dayz_code/compile/dze_buildChecks.sqf b/SQF/dayz_code/compile/dze_buildChecks.sqf index d1cfef896..fbb99ddac 100644 --- a/SQF/dayz_code/compile/dze_buildChecks.sqf +++ b/SQF/dayz_code/compile/dze_buildChecks.sqf @@ -1,132 +1,245 @@ -//Checks if item is near a plot, if the player is plot owner or friendly, if there are too many items, and if the player has required tools -private ["_isAdmin","_requireplot","_distance","_canBuild","_friendlies","_nearestPole","_ownerID","_pos","_item","_classname","_isPole","_isLandFireDZ","_IsNearPlot","_buildables","_center","_toolCheck","_plotcheck","_buildcheck","_isfriendly","_isowner","_require","_text","_near","_plotPoles"]; +/////////////////////////////////////////////////////////////////////////////////////////////////// +// +// Updated by: Victor the Cleaner +// Date: August 2021 +// +// Performs 10 different build checks +// +// 1) You are not allowed to build here a "Trader" is nearby. +// 2) You cannot build a plot pole within "_distance" of an existing plot. +// 3) You can only own "DZE_limitPlots" plot pole(s) +// 4) This item needs a "Plot Pole" within "_distance" meters +// 5) You do not have access to build on this plot. +// 6) Building is restricted above "DZE_BuildHeightLimit" meter(s). +// 7) You cannot build. There are too many objects within "DZE_maintainRange" m. +// 8) You can't build a "displayName" within "_distance" meters of a safe zone. +// 9) You can't build a "displayName" within "DZE_NoBuildNearDistance" meters of a "class". +// 10) Tool Check (silent) +// +// Input values = [position, classname, toolcheck]; +// Return values = [_canBuild, _isPole, _nearestPole]; // added _nearestPole +// +/////////////////////////////////////////////////////////////////////////////////////////////////// +// +// Initialize +// +/////////////////////////////////////////////////////////////////////////////////////////////////// +local _pos = _this select 0; +local _item = _this select 1; +local _toolCheck = _this select 2; -_pos = _this select 0; -_item = _this select 1; -_toolCheck = _this select 2; -_classname = getText (configFile >> "CfgMagazines" >> _item >> "ItemActions" >> "Build" >> "create"); -_requireplot = DZE_requireplot; -_isAdmin = dayz_playerUID in DZE_PlotManagementAdmins; -// "Unable to build trader nearby." -if (!canbuild) exitWith {dayz_actionInProgress = false; format[localize "STR_EPOCH_PLAYER_136",localize "STR_EPOCH_TRADER"] call dayz_rollingMessages; [false, false];}; +local _classname = getText (configFile >> "CfgMagazines" >> _item >> "ItemActions" >> "Build" >> "create"); +local _isPole = (_classname == "Plastic_Pole_EP1_DZ"); +local _isLandFireDZ = (_classname == "Land_Fire_DZ"); +local _isAdmin = dayz_playerUID in DZE_PlotManagementAdmins; +local _canBuild = false; +local _plotPoles = 0; +local _radius = DZE_PlotPole select 0; +local _minDistance = DZE_PlotPole select 1; +local _requireplot = DZE_requireplot; if (isNumber (configFile >> "CfgVehicles" >> _classname >> "requireplot")) then { _requireplot = getNumber(configFile >> "CfgVehicles" >> _classname >> "requireplot"); }; +local _plotcheck = [player, _isPole] call FNC_find_plots; +local _distance = _plotcheck select 0; +local _isNearPlot = _plotcheck select 1; +local _nearestPole = _plotcheck select 2; // object or objNull -_checkClass = { - private ["_checkOK","_distance"]; - _checkOK = false; - _distance = DZE_SafeZoneNoBuildDistance; +/////////////////////////////////////////////////////////////////////////////////////////////////// +// +// 1) You are not allowed to build here a "Trader" is nearby. +// +/////////////////////////////////////////////////////////////////////////////////////////////////// +if (!canbuild) exitWith { + dayz_actionInProgress = false; + format[localize "STR_EPOCH_PLAYER_136", localize "STR_EPOCH_TRADER"] call dayz_rollingMessages; + [_canBuild, _isPole, _nearestPole]; +}; + + +/////////////////////////////////////////////////////////////////////////////////////////////////// +// +// 2) You cannot build a plot pole within "_distance" of an existing plot. +// +/////////////////////////////////////////////////////////////////////////////////////////////////// +if (_isPole && _isNearPlot > 0) exitWith { + + dayz_actionInProgress = false; + format[localize "str_epoch_player_44", _distance] call dayz_rollingMessages; + [_canBuild, _isPole, _nearestPole]; +}; + + +/////////////////////////////////////////////////////////////////////////////////////////////////// +// +// 3) You can only own "DZE_limitPlots" plot pole(s) +// +/////////////////////////////////////////////////////////////////////////////////////////////////// +if (_isPole && !_isAdmin && DZE_limitPlots > 0) then { { - if (typeName _x == "ARRAY") then { - if (_x select 0 == _classname) then {_checkOK = true; _distance = _x select 1;}; - } else { - if (_x == _className) then {_checkOK = true}; + if (_x getVariable["ownerPUID","0"] == dayz_playerUID || (_x getVariable["CharacterID","0"] == dayz_characterID)) then { + _plotPoles = _plotPoles + 1; }; - if (_checkOK) exitWith {}; - } count DZE_SafeZoneNoBuildItems; + } count (entities "Plastic_Pole_EP1_DZ"); // all plot poles on the map owned by player +}; +if ((DZE_limitPlots > 0) && (_plotPoles >= DZE_LimitPlots)) exitWith { - [_checkOK,_distance] + dayz_actionInProgress = false; + format[localize "STR_EPOCH_PLAYER_133", DZE_limitPlots] call dayz_rollingMessages; + [_canBuild, _isPole, _nearestPole]; }; -_isPole = (_classname == "Plastic_Pole_EP1_DZ"); -_isLandFireDZ = (_classname == "Land_Fire_DZ"); -_canBuild = false; -_plotPoles = 0; -_nearestPole = objNull; -_ownerID = 0; -_friendlies = []; - -if (_isPole) then { - _plotcheck = [player, true] call FNC_find_plots; - _distance = DZE_PlotPole select 1; - if (DZE_limitPlots > 0 && !_isAdmin) then { - { - if (_x getVariable["ownerPUID","0"] == dayz_playerUID || (_x getVariable["CharacterID","0"] == dayz_characterID)) then { - _plotPoles = _plotPoles +1; - }; - } count (entities "Plastic_Pole_EP1_DZ"); - }; -} else { - _plotcheck = [player, false] call FNC_find_plots; - _distance = DZE_PlotPole select 0; -}; - -_IsNearPlot = _plotcheck select 1; -_nearestPole = _plotcheck select 2; - -if (_isPole && {_IsNearPlot > 0}) exitWith {dayz_actionInProgress = false; format[localize "str_epoch_player_44",_distance] call dayz_rollingMessages; [_canBuild, _isPole];}; - -if (DZE_limitPlots > 0 && {_plotPoles >= DZE_LimitPlots}) exitWith {dayz_actionInProgress = false; format[localize "STR_EPOCH_PLAYER_133",DZE_limitPlots] call dayz_rollingMessages; [_canBuild, _isPole];}; - -if (_IsNearPlot == 0) then { - if (_requireplot == 0 || {_isLandFireDZ}) then { +/////////////////////////////////////////////////////////////////////////////////////////////////// +// +// 4) This item needs a "Plot Pole" within "_distance" meters +// +/////////////////////////////////////////////////////////////////////////////////////////////////// +if (_isNearPlot == 0) then { + if (_requireplot == 0 || _isLandFireDZ) then { _canBuild = true; }; -} else { - _ownerID = _nearestPole getVariable["CharacterID","0"]; +}; +if (_isNearPlot == 0 && !_canBuild) exitWith { + + dayz_actionInProgress = false; + format[localize "STR_EPOCH_PLAYER_135", localize "str_epoch_player_246", _distance] call dayz_rollingMessages; + [_canBuild, _isPole, _nearestPole]; +}; + + +/////////////////////////////////////////////////////////////////////////////////////////////////// +// +// 5) You do not have access to build on this plot. +// +/////////////////////////////////////////////////////////////////////////////////////////////////// +if (_isNearPlot > 0) then { + local _ownerID = _nearestPole getVariable["CharacterID","0"]; if (dayz_characterID == _ownerID) then { _canBuild = true; } else { if (DZE_permanentPlot) then { - _buildcheck = [player, _nearestPole] call FNC_check_access; - _isowner = _buildcheck select 0; - _isfriendly = ((_buildcheck select 1) or (_buildcheck select 3)); + local _accessCheck = [player, _nearestPole] call FNC_check_access; + local _isowner = _accessCheck select 0; + local _isfriendly = ((_accessCheck select 1) || (_accessCheck select 3)); if (_isowner || _isfriendly) then { _canBuild = true; }; } else { - _friendlies = player getVariable ["friendlyTo",[]]; + local _friendlies = player getVariable ["friendlyTo",[]]; if (_ownerID in _friendlies) then { _canBuild = true; }; }; }; }; +if (_isNearPlot > 0 && !_canBuild) exitWith { -if (!_canBuild) exitWith { dayz_actionInProgress = false; - if (_isNearPlot == 0) then { - format[localize "STR_EPOCH_PLAYER_135",localize "str_epoch_player_246",_distance] call dayz_rollingMessages; - } else { - localize "STR_EPOCH_PLAYER_134" call dayz_rollingMessages; - }; - [_canBuild, _isPole]; + localize "STR_EPOCH_PLAYER_134" call dayz_rollingMessages; + [_canBuild, _isPole, _nearestPole]; }; -if (DZE_BuildHeightLimit > 0 && {([player] call fnc_getPos) select 2 > DZE_BuildHeightLimit}) exitWith {dayz_actionInProgress = false; format[localize "STR_EPOCH_PLAYER_168",DZE_BuildHeightLimit] call dayz_rollingMessages; [false, _isPole];}; +/////////////////////////////////////////////////////////////////////////////////////////////////// +// +// 6) Building is restricted above "DZE_BuildHeightLimit" meter(s). +// +/////////////////////////////////////////////////////////////////////////////////////////////////// +if (DZE_BuildHeightLimit > 0 && ((_pos select 2) > DZE_BuildHeightLimit)) exitWith { + + dayz_actionInProgress = false; + format[localize "STR_EPOCH_PLAYER_168", DZE_BuildHeightLimit] call dayz_rollingMessages; + [false, _isPole, _nearestPole]; +}; + + +/////////////////////////////////////////////////////////////////////////////////////////////////// +// +// 7) You cannot build. There are too many objects within "DZE_maintainRange" m. +// +/////////////////////////////////////////////////////////////////////////////////////////////////// // Also count safes, lockboxes, vanilla buildables, tents and stashes against DZE_BuildingLimit -_buildables = DZE_maintainClasses + DZE_LockableStorage + ["DZ_storage_base"]; -_center = if (isNull _nearestPole) then {_pos} else {_nearestPole}; -if ((count (nearestObjects [_center,_buildables,_distance])) >= DZE_BuildingLimit) exitWith {dayz_actionInProgress = false; format[localize "str_epoch_player_41",_distance] call dayz_rollingMessages; [false, _isPole];}; +local _buildables = DZE_maintainClasses + DZE_LockableStorage + ["DZ_storage_base"]; +local _center = if (isNull _nearestPole) then { + _pos; // player's position +} else { + _nearestPole; +}; +if ((count (nearestObjects [_center, _buildables, DZE_maintainRange])) >= DZE_BuildingLimit) exitWith { -_text = getText (configFile >> 'CfgMagazines' >> _item >> 'displayName'); - -_buildCheck = call _checkClass; - -if (_buildCheck select 0 && !_isAdmin) then { - _canBuild = !([player,_buildCheck select 1] call DZE_SafeZonePosCheck); + dayz_actionInProgress = false; + format[localize "str_epoch_player_41", floor DZE_maintainRange] call dayz_rollingMessages; + [false, _isPole, _nearestPole]; }; -if !(_canBuild) exitWith {dayz_actionInProgress = false; format [localize "STR_EPOCH_PLAYER_166",_text,_buildCheck select 1] call dayz_rollingMessages; [false, _isPole];}; +/////////////////////////////////////////////////////////////////////////////////////////////////// +// +// 8) You can't build a "displayName" within "_distance" meters of a safe zone. +// +/////////////////////////////////////////////////////////////////////////////////////////////////// +local _text = getText (configFile >> "CfgMagazines" >> _item >> "displayName"); +local _checkOK = false; +_distance = DZE_SafeZoneNoBuildDistance; +{ + if (typeName _x == "ARRAY") then { + if (_x select 0 == _classname) then { + _checkOK = true; + _distance = _x select 1; + }; + } else { + if (_x == _classname) then { + _checkOK = true; + }; + }; + if (_checkOK) exitWith {}; +} count DZE_SafeZoneNoBuildItems; + +if (_checkOK && !_isAdmin) then { + _canBuild = !([player, _distance] call DZE_SafeZonePosCheck); +}; +if (!_canBuild) exitWith { + + dayz_actionInProgress = false; + format [localize "STR_EPOCH_PLAYER_166", _text, _distance] call dayz_rollingMessages; + [_canBuild, _isPole, _nearestPole]; +}; + + +/////////////////////////////////////////////////////////////////////////////////////////////////// +// +// 9) You can't build a "displayName" within "DZE_NoBuildNearDistance" meters of a "class". +// +/////////////////////////////////////////////////////////////////////////////////////////////////// if (count DZE_NoBuildNear > 0 && !_isAdmin) then { - _near = (nearestObjects [_pos,DZE_NoBuildNear,DZE_NoBuildNearDistance]); - if ((count _near) > 0) then { _canBuild = false; }; + local _near = (nearestObjects [_pos, DZE_NoBuildNear, DZE_NoBuildNearDistance]); + + if ((count _near) > 0) then { + _canBuild = false; + }; +}; +if (!_canBuild) exitWith { + + dayz_actionInProgress = false; + format [localize "STR_EPOCH_PLAYER_167", _text, DZE_NoBuildNearDistance, typeOf (_near select 0)] call dayz_rollingMessages; + [_canBuild, _isPole, _nearestPole]; }; -if !(_canBuild) exitWith {dayz_actionInProgress = false; format [localize "STR_EPOCH_PLAYER_167",_text,DZE_NoBuildNearDistance,typeOf (_near select 0)] call dayz_rollingMessages; [false, _isPole];}; +/////////////////////////////////////////////////////////////////////////////////////////////////// +// +// 10) Tool Check (silent) +// +/////////////////////////////////////////////////////////////////////////////////////////////////// if (_toolCheck) then { - _require = getArray (configFile >> "cfgMagazines" >> _item >> "ItemActions" >> "Build" >> "require"); + local _require = getArray (configFile >> "cfgMagazines" >> _item >> "ItemActions" >> "Build" >> "require"); _classname = getText (configFile >> "CfgMagazines" >> _item >> "ItemActions" >> "Build" >> "create"); _canBuild = [_item, _require, _classname] call dze_requiredItemsCheck; }; -//When calling this function in another script use a silent exitWith, unless you have something special to say. i.e. if (!(_canBuild select 0)) exitWith{}; -[_canBuild, _isPole]; +// When calling this function in another script use a silent exitWith, unless you have something special to say. i.e. if !(_canBuild select 0) exitWith{}; +[_canBuild, _isPole, _nearestPole]; diff --git a/SQF/dayz_code/compile/fn_find_plots.sqf b/SQF/dayz_code/compile/fn_find_plots.sqf index 9594c77fc..057a6dc0b 100644 --- a/SQF/dayz_code/compile/fn_find_plots.sqf +++ b/SQF/dayz_code/compile/fn_find_plots.sqf @@ -1,26 +1,28 @@ -// Find Plots by RimBlock (http://epochmod.com/forum/index.php?/user/12612-rimblock/) +/////////////////////////////////////////////////////////////////////////////////////////////////// +// +// Find Plots by RimBlock (http://epochmod.com/forum/index.php?/user/12612-rimblock/) +// Updated by: Victor the Cleaner +// Date: August 2021 +// +/////////////////////////////////////////////////////////////////////////////////////////////////// -private ["_player","_isPole","_IsNearPlot","_nearestPole","_distance","_findNearestPoles","_findNearestPole","_friendly","_return","_pos"]; +local _player = _this select 0; // object +local _isPole = _this select 1; // bool +local _pos = [vehicle _player] call FNC_getPos; +local _radius = DZE_PlotPole select 0; // plot radius +local _minDistance = DZE_PlotPole select 1; // minimum distance between plot poles +local _nearestPole = objNull; // default +local _distance = _radius; // default -_player = _this select 0; -_isPole = _this select 1; -_IsNearPlot = 0; -_nearestPole = ""; -_findNearestPole = []; - -if(_isPole) then { - _distance = DZE_PlotPole select 1; -}else{ - _distance = DZE_PlotPole select 0; +if (_isPole) then { + _distance = _minDistance; }; - -_pos = [vehicle _player] call FNC_getPos; - // check for near plot -_findNearestPole = _pos nearEntities ["Plastic_Pole_EP1_DZ", _distance]; +local _findNearestPole = _pos nearEntities ["Plastic_Pole_EP1_DZ", _distance]; -_IsNearPlot = count (_findNearestPole); -if (_IsNearPlot > 0) then{_nearestPole = _findNearestPole select 0;}else{_nearestPole = objNull;}; +local _isNearPlot = count _findNearestPole; -_return = [_distance, _IsNearPlot, _nearestPole]; -_return +if (_isNearPlot > 0) then { // found one or more + _nearestPole = _findNearestPole select 0; // get first entry +}; +[_distance, _isNearPlot, _nearestPole];