mirror of
https://github.com/EpochModTeam/DayZ-Epoch.git
synced 2025-12-14 04:02:37 +03:00
DZE_RequiredItemsCheck returns bool, displays an error of all the tools the player is missing to build the item. DZE_BuildChecks returns array of bools, canBuild and if the item is a plotPole. Also has the ability to check if the player has required tools to build using DZE_RequiredItemsCheck. The vanilla build script still needs to be modified to work over water and allow players to place floating objects, but now uses plot checks. It would be easiest to just modify the configs to use the epoch building scripts instead. fnc_getSetPos now accepts a position as the second element of the input array. the object will be set to this position if it is used. This change requires no code updates Note: scripts with build and/or tool checks should be updated to use the new functions
415 lines
16 KiB
Plaintext
415 lines
16 KiB
Plaintext
// (c) facoptere@gmail.com, licensed to DayZMod for the community
|
|
private ["_classType","_item","_action","_missingTools","_missingItem","_emergingLevel","_isClass","_classname","_requiredTools",
|
|
"_requiredParts","_ghost","_placement","_text","_onLadder","_isWater","_object","_string","_actionBuildHidden","_getBeams",
|
|
"_o","_offset","_rot","_r","_p","_bn","_bb","_h","_bx","_by","_minElevation","_maxElevation","_insideCheck","_building",
|
|
"_unit","_bbb","_ubb","_check","_min","_max","_myX","_myY","_checkBuildingCollision","_objColliding","_inside","_checkOnRoad",
|
|
"_roadCollide","_checkBeam2Magnet","_a","_beams","_best","_b","_d","_checkNotBuried","_elevation","_position","_delta","_overElevation",
|
|
"_maxplanting","_safeDistance","_dir","_angleRef","_tmp","_actionCancel","_sfx","_actionBuild","_byPassChecks","_keepOnSlope","_msg",
|
|
"_ok","_missing","_upgradeParts","_ownerID","_posReference"];
|
|
/*
|
|
Needs a full rewrite to keep up with the demand of everything we plan to add.
|
|
*/
|
|
|
|
call gear_ui_init;
|
|
closeDialog 1;
|
|
|
|
_item = _this select 0;
|
|
_action = _this select 1;
|
|
_classType = "ItemActions";
|
|
|
|
if (count _this > 2) then {
|
|
_classType = _this select 2;
|
|
};
|
|
|
|
_emergingLevel = 1.1;
|
|
r_action_count = 1;
|
|
|
|
_isClass = switch (1==1) do {
|
|
case (isClass (configFile >> "CfgMagazines" >> _item)): {"CfgMagazines"};
|
|
case (isClass (configFile >> "CfgWeapons" >> _item)): {"CfgWeapons"};
|
|
};
|
|
|
|
//need to swap all build systems to this "ItemActions"
|
|
_classname = getText (configFile >> _isClass >> _item >> _classType >> _action >> "create");
|
|
_requiredTools = getArray (configFile >> _isClass >> _item >> _classType >> _action >> "require");
|
|
_requiredParts = getArray (configFile >> _isClass >> _item >> _classType >> _action >> "consume");
|
|
_ghost = getText (configFile >> _isClass >> _item >> _classType >> _action >> "ghost");
|
|
//need to move to array and separate what checks need to be done.
|
|
_byPassChecks = getText (configFile >> _isClass >> _item >> _classType >> _action >> "byPass");
|
|
|
|
if (_byPassChecks == "") then { _byPassChecks = "BaseItems" };
|
|
if (_ghost == "") then { _ghost = _classname; };
|
|
|
|
_text = getText (configFile >> "CfgVehicles" >> _classname >> "displayName");
|
|
_keepOnSlope = 0 == (getNumber (configFile >> "CfgVehicles" >> _classname >> "canbevertical"));
|
|
|
|
_onLadder = {getNumber (configFile >> "CfgMovesMaleSdr" >> "States" >> (animationState player) >> "onLadder") == 1};
|
|
_isWater = {(surfaceIsWater (getPosATL _object)) or dayz_isSwimming};
|
|
|
|
if (0 != count Dayz_constructionContext) then {
|
|
r_action_count = 0;
|
|
//localize "str_already_building" call dayz_rollingMessages;
|
|
_msg = localize "str_already_building";
|
|
_msg call dayz_rollingMessages;
|
|
diag_log [ diag_ticktime, __FILE__, 'already building, exiting', Dayz_constructionContext, typeName Dayz_constructionContext];
|
|
};
|
|
|
|
// item is missin - this really is pointless but it aint broke so dont fix it
|
|
if (isClass (configFile >> _isClass >> _item)) then {
|
|
if ((!(_item IN magazines player))) exitWith {
|
|
_string = switch true do {
|
|
case (_item isKindOf "Land_A_tent"): {"str_player_31_pitch"};
|
|
default {"str_player_31_build"};
|
|
};
|
|
//format[localize "str_player_31",_text,(localize _string)] call dayz_rollingMessages;
|
|
_msg = format [localize "str_player_31",_text,(localize _string)];
|
|
_msg call dayz_rollingMessages;
|
|
//diag_log(format["player_build: item:%1 require:%2 Player items:%3 magazines:%4", _item, _requiredTools, (items player), (magazines player)]);
|
|
};
|
|
};
|
|
|
|
// lets check player has requiredTools for upgrade
|
|
_ok = true;
|
|
_missing = "";
|
|
{
|
|
if (!(_x IN items player)) exitWith {
|
|
//systemchat("Missing tools for upgrade." +str());
|
|
_missing = getText (configFile >> "CfgWeapons" >> _x >> "displayName");
|
|
_ok = false;
|
|
};
|
|
} count _requiredTools;
|
|
|
|
if (!_ok) exitWith {
|
|
r_action_count = 0;
|
|
//format[localize "str_player_31_missingtools",_text,_missing] call dayz_rollingMessages;
|
|
_msg = format [localize "str_player_31_missingtools",_text,_missing];
|
|
_msg call dayz_rollingMessages;
|
|
};
|
|
|
|
// lets check player has requiredParts for upgrade
|
|
_ok = true;
|
|
_upgradeParts = [];
|
|
{
|
|
if (!(_x IN magazines player)) exitWith {
|
|
_missing = getText (configFile >> "CfgMagazines" >> _x >> "displayName");
|
|
_ok = false;
|
|
};
|
|
if (_x IN magazines player) then {
|
|
_upgradeParts set [count _upgradeParts, _x];
|
|
player removeMagazine _x;
|
|
};
|
|
} count _requiredParts;
|
|
if (!_ok) exitWith {
|
|
{ player addMagazine _x; } foreach _upgradeParts;
|
|
r_action_count = 0;
|
|
// format[localize "str_player_31", _missing, localize "str_player_31_build"] call dayz_rollingMessages;
|
|
_msg = format [localize "str_player_31", _missing, localize "str_player_31_build"];
|
|
_msg call dayz_rollingMessages;
|
|
};
|
|
|
|
_posReference = [player] call FNC_GetPos;
|
|
|
|
_canBuild = [_posReference, _item, false] call DZE_BuildChecks;
|
|
if (!(_canBuild select 0)) exitWith {};
|
|
|
|
//localize "str_player_build_rotate" call dayz_rollingMessages;
|
|
_msg = localize "str_player_build_rotate";
|
|
_msg call dayz_rollingMessages;
|
|
|
|
//Get fence beams based on model
|
|
_getBeams = {
|
|
private [ "_p", "_r", "_bn", "_bb", "_bx", "_by" ];
|
|
|
|
_o = _this select 0;
|
|
_offset = _this select 1;
|
|
_rot = _this select 2;
|
|
_r = [];
|
|
|
|
for "_bn" from 1 to 4 do {
|
|
_p = _o selectionPosition Format [ "beam%1", _bn ];
|
|
if (_p distance [0,0,0] == 0) exitWith {
|
|
if (_bn == 1) then { // no memory points defined
|
|
_bb = boundingBox _o;
|
|
_h = _offset + ((_o worldToModel (getPosATL _o)) select 2);
|
|
_p = [ (_bb select 0) select 0, 0, _h ];
|
|
_r set [ 0, _o modelToWorld _p];
|
|
_p = [ (_bb select 1) select 0, 0, _h ];
|
|
_r set [ 1, _o modelToWorld _p];
|
|
};
|
|
};
|
|
if (_rot != 0) then {
|
|
_bx = _p select 0;
|
|
_by = _p select 1;
|
|
_p set [0, (_bx * cos _rot) - (_by * sin _rot)];
|
|
_p set [1, (_bx * sin _rot) + (_by * cos _rot)];
|
|
};
|
|
_p set [2, (_p select 2) + _offset];
|
|
|
|
_r set [ count _r, _o modelToWorld _p];
|
|
};
|
|
_r
|
|
};
|
|
|
|
_minElevation = {
|
|
private "_r";
|
|
|
|
_r = 400;
|
|
{ _r = _r min (_x select 2); } count _this;
|
|
|
|
_r
|
|
};
|
|
|
|
_maxElevation = {
|
|
private "_r";
|
|
|
|
_r = -400;
|
|
{ _r = _r max (_x select 2); } count _this;
|
|
|
|
_r
|
|
};
|
|
|
|
//Is the placed object inside another object
|
|
_insideCheck = {
|
|
private ["_bbb","_building","_ubb","_unit","_check","_min","_max","_myX","_p","_myY"];
|
|
|
|
_building = _this select 0;
|
|
_unit = _this select 1;
|
|
if ((typeOf _building != "") and {(
|
|
(sizeOf (typeOf _building) < 8) or {(_unit distance _building > (sizeOf (typeOf _building) + sizeOf (typeOf _unit))/2)}
|
|
)}) exitwith {false};
|
|
|
|
_bbb = boundingBox _building;
|
|
_ubb = boundingBox _unit;
|
|
|
|
_check = {
|
|
_min = _bbb select 0;
|
|
_max = _bbb select 1;
|
|
_myX = _p select 0;
|
|
_myY = _p select 1;
|
|
|
|
(((_myX > (_min select 0)) and {(_myX < (_max select 0))}) and {((_myY > (_min select 1)) and {(_myY < (_max select 1))})})
|
|
};
|
|
|
|
_p = _building worldToModel (_unit modelToWorld [ (_ubb select 0) select 0, (_ubb select 0) select 1, 0]);
|
|
if (call _check) exitWith {true};
|
|
_p = _building worldToModel (_unit modelToWorld [ (_ubb select 0) select 0, (_ubb select 1) select 1, 0]);
|
|
if (call _check) exitWith {true};
|
|
_p = _building worldToModel (_unit modelToWorld [ (_ubb select 1) select 0, (_ubb select 1) select 1, 0]);
|
|
if (call _check) exitWith {true};
|
|
_p = _building worldToModel (_unit modelToWorld [ (_ubb select 1) select 0, (_ubb select 0) select 1, 0]);
|
|
if (call _check) exitWith {true};
|
|
|
|
false
|
|
};
|
|
|
|
//check if building being placed and objects around placement is free to be built on.
|
|
//Fence owners must build all the foundations by one player anyone can still upgrade (pending lock build level)
|
|
_checkBuildingCollision = {
|
|
_objColliding = objNull;
|
|
{
|
|
_inside = false;
|
|
_ownerID = _x getVariable ["ownerArray",[]];
|
|
|
|
if (count _ownerID > 0) then { _ownerID = _ownerID select 0; } else { _ownerID = (getPlayerUID player); };
|
|
|
|
//and (!(_x isKindOf "DZ_buildables")) Not used
|
|
|
|
if(_ownerID != (getPlayerUID player)) then {
|
|
if ((!isNull _x) and (!(_x == player)) and (!(_x == _object)) and (!(_x IN DayZ_SafeObjects))
|
|
and (!((typeOf _x == "CamoNet_DZ") or {(_x isKindOf "Land_CamoNet_EAST")}))) then {
|
|
if ((_x isKindOf "Building") or (_x isKindOf "AllVehicles")) then {
|
|
_inside = [_x, _object] call _insideCheck;
|
|
|
|
/*
|
|
if (!_inside) then {
|
|
_inside = [_object, _x] call _insideCheck;
|
|
};
|
|
*/
|
|
};
|
|
};
|
|
};
|
|
if (_inside) exitWith { _objColliding = _x; };
|
|
} forEach (nearestObjects [_object, ["Building", "Air", "LandVehicle", "Ship", "DZ_buildables"], 35]);
|
|
(!isNull _objColliding)
|
|
// _objColliding contains the building that collides with the ghost object
|
|
};
|
|
|
|
//Is placement on a road?
|
|
_checkOnRoad = {
|
|
_roadCollide = false;
|
|
{
|
|
_x set [2,0];
|
|
if (isOnRoad _x) exitWith { _roadCollide = true;};
|
|
} forEach ([_object, 0,0] call _getBeams);
|
|
_roadCollide
|
|
};
|
|
|
|
//Make the object attach to beams if it can
|
|
_checkBeam2Magnet = {
|
|
_a = [];
|
|
{
|
|
if ((!isNull _x) and (_x != _object)) then { _a = _a + ([_x, 0,0] call _getBeams); };
|
|
} forEach (nearestObjects [getPosATL _object, ["DZ_buildables"], 15]);
|
|
|
|
_beams = [_object, 0,0] call _getBeams;
|
|
_best = [50,[0,0,0],[0,0,0]];
|
|
{
|
|
_b = _x;
|
|
{
|
|
_d = [_x, _b] call BIS_fnc_distance2D;
|
|
if (_d < _best select 0) then {
|
|
_best = [_d,_b,_x];
|
|
};
|
|
} forEach _a;
|
|
} count _beams;
|
|
// _best contains the best beam to dock to. [ distance, coor of beam found around, coor of beam of ghost object ]
|
|
};
|
|
|
|
_checkNotBuried = {
|
|
// lift up the object so that any beams are buried, but also don't lift further the planting level (straight placement only)
|
|
_elevation = _position select 2;
|
|
_delta = 0;
|
|
_overElevation = 0;
|
|
_beams = [_object, 0,0] call _getBeams;
|
|
if (_elevation < 0) then { _delta = -_elevation; }
|
|
else {
|
|
_overElevation = _beams call _minElevation;
|
|
if (_overElevation>0.05) then { // bury the object so that posATL is still positif and all beams are above the ground
|
|
_delta = - (_overElevation min _elevation);
|
|
};
|
|
if (_overElevation < -0.05) then { // lift up the object because a beam is burried
|
|
_delta = - _overElevation + 0.10;
|
|
};
|
|
};
|
|
_position set [ 2, _elevation + _delta ];
|
|
_maxplanting = _beams call _maxElevation;
|
|
// _maxplanting is the height of the emerging foundations, must not be so high because we don't want some "floating" foundations
|
|
};
|
|
|
|
_object = _ghost createVehicleLocal getMarkerpos "respawn_west";
|
|
_safeDistance = 0.5 + (sizeOf _ghost) * 0.5; // beware of hedgehogs
|
|
_dir = getDir player;
|
|
_object setDir _dir;
|
|
Dayz_constructionContext = [_object, round (_dir/5)*5, cameraView, false, true, _keepOnSlope];
|
|
// ghost, angle, previous camera, build view on/off, continue on/off, slope on/off
|
|
//_posReference = getPosATL player;
|
|
_objColliding = objNull;
|
|
_best = [50,[0,0,0],[0,0,0]];
|
|
_maxplanting = 10;
|
|
_position = getPosATL _object;
|
|
|
|
_actionBuildHidden = true;
|
|
_actionCancel = player addAction [localize "str_player_build_cancel", "\z\addons\dayz_code\actions\object_build.sqf", [_object, _requiredParts, _classname, _text, false, 0, "none"], 1, true, true, "", "0 != count Dayz_constructionContext"];
|
|
|
|
while {r_action_count != 0 and Dayz_constructionContext select 4} do {
|
|
|
|
// force the angle so that the ghost is showing always the same side
|
|
_angleRef=Dayz_constructionContext select 1;
|
|
_dir = _angleRef - (getDir player);
|
|
if (_dir > 180) then {_dir = _dir - 360};
|
|
if (_dir < -180) then {_dir = _dir + 360};
|
|
if (_dir < -75) then {
|
|
_angleRef = ceil(((getDir player) - 75)/5)*5;
|
|
Dayz_constructionContext set [ 1, _angleRef];
|
|
};
|
|
if (_dir > 75) then {
|
|
_angleRef = floor(((getDir player) + 75)/5)*5;
|
|
Dayz_constructionContext set [ 1, _angleRef];
|
|
};
|
|
|
|
// move object according to player position
|
|
if ((abs(([_object, player] call BIS_fnc_distance2D) - _safeDistance) > (if (_best select 0 < 0.50) then {0.50} else {0.05}))
|
|
or (abs([player, _object] call BIS_fnc_relativeDirTo) > (if (_best select 0 < 0.50) then {5} else {1})) or (r_interrupt)) then {
|
|
r_interrupt = false;
|
|
_object setDir _angleRef;
|
|
_tmp = player modelToWorld [0, _safeDistance,0];
|
|
if (Dayz_constructionContext select 5 or _keepOnSlope) then {
|
|
_tmp set [2, 0];
|
|
_object setVectorUp surfaceNormal _tmp;
|
|
}
|
|
else {
|
|
_tmp set [2, _position select 2];
|
|
_object setVectorUp [0,0,1];
|
|
};
|
|
_position = +(_tmp);
|
|
_object setPosATL _position;
|
|
|
|
// check now that ghost is not colliding
|
|
call _checkBuildingCollision;
|
|
};
|
|
|
|
// try to dock a beam from current ghost to another beams nearby
|
|
call _checkBeam2Magnet;
|
|
if (_best select 0 < 0.50) then {
|
|
_position = [
|
|
(_position select 0) + ((_best select 2) select 0) - ((_best select 1) select 0),
|
|
(_position select 1) + ((_best select 2) select 1) - ((_best select 1) select 1),
|
|
_position select 2
|
|
];
|
|
_object setPosATL _position;
|
|
};
|
|
|
|
if (Dayz_constructionContext select 5 or _keepOnSlope) then {
|
|
_maxplanting = 0;
|
|
_position set [2, 0];
|
|
}
|
|
else {
|
|
// adjust the elevation of the object according to slope and beams to keep them visible (straight placement only)
|
|
call _checkNotBuried;
|
|
};
|
|
_object setPosATL _position;
|
|
|
|
if ((((vehicle player) != player or _posReference distance player > 20 or 0 != player getVariable["startcombattimer",0]) or {(!alive player)}) or {((call _onLadder) or {(call _isWater)})}) exitWith {
|
|
[[],[],[],[_object, _requiredParts , _classname, _text, false, 0, "none"]] call object_build;
|
|
};
|
|
|
|
if (_byPassChecks == "byPassRoadCheck") then {
|
|
if (isNull _objColliding and _maxplanting <= _emergingLevel) then { // placement is fine, enable "Build" in the menu
|
|
if (_actionBuildHidden) then {
|
|
_actionBuildHidden = false;
|
|
player removeAction _actionCancel;
|
|
_sfx = if (_object isKindOf "Land_A_tent") then {"tentunpack"} else {"repair"};
|
|
_actionBuild = player addAction [localize "str_player_build_complete", "\z\addons\dayz_code\actions\object_build.sqf", [_object, _requiredParts , _classname, _text, true, 20, _sfx], 1, true, true, "", "0 != count Dayz_constructionContext"];
|
|
_actionCancel = player addAction [localize "str_player_build_cancel", "\z\addons\dayz_code\actions\object_build.sqf", [_object, _requiredParts , _classname, _text, false, 0, "none"], 1, true, true, "", "0 != count Dayz_constructionContext"];
|
|
};
|
|
} else {
|
|
if (!_actionBuildHidden) then {
|
|
_actionBuildHidden = true;
|
|
player removeAction _actionBuild;
|
|
};
|
|
};
|
|
};
|
|
|
|
if (_byPassChecks == "BaseItems") then {
|
|
if (isNull _objColliding and _maxplanting <= _emergingLevel and !(call _checkOnRoad)) then { // placement is fine, enable "Build" in the menu
|
|
if (_actionBuildHidden) then {
|
|
_actionBuildHidden = false;
|
|
player removeAction _actionCancel;
|
|
_sfx = if (_object isKindOf "Land_A_tent") then {"tentunpack"} else {"repair"};
|
|
_actionBuild = player addAction [localize "str_player_build_complete", "\z\addons\dayz_code\actions\object_build.sqf", [_object, _requiredParts , _classname, _text, true, 20, _sfx], 1, true, true, "", "0 != count Dayz_constructionContext"];
|
|
_actionCancel = player addAction [localize "str_player_build_cancel", "\z\addons\dayz_code\actions\object_build.sqf", [_object, _requiredParts , _classname, _text, false, 0, "none"], 1, true, true, "", "0 != count Dayz_constructionContext"];
|
|
};
|
|
} else {
|
|
if (!_actionBuildHidden) then {
|
|
_actionBuildHidden = true;
|
|
player removeAction _actionBuild;
|
|
};
|
|
};
|
|
};
|
|
uiSleep 0.03;
|
|
};
|
|
|
|
if (!_actionBuildHidden) then { // player can't build until all is fine
|
|
_actionBuildHidden = true;
|
|
player removeAction _actionBuild;
|
|
};
|
|
player removeAction _actionCancel;
|
|
|
|
if (Dayz_constructionContext select 3) then { // "build" camera was on, switch it off
|
|
call fn_buildCamera;
|
|
};
|
|
|
|
Dayz_constructionContext = [];
|
|
r_action_count = 0;
|
|
//systemChat "Dayz_constructionContext reset";
|