Files
DayZ-Epoch/SQF/dayz_code/actions/modular_build.sqf
icomrade 7ea9a270f2 New building functions, vanilla building checks
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
2016-04-27 14:30:11 -04:00

536 lines
17 KiB
Plaintext

// If parameters were passed redirect to vanilla player_build (Epoch items don't pass anything)
if (!isNil "_this" && {typeName _this == "ARRAY"} && {count _this > 0}) exitWith {_this spawn player_buildVanilla;};
private ["_classname","_classnametmp","_require","_text","_ghost","_lockable","_requireplot","_isAllowedUnderGround","_offset","_isPole","_isLandFireDZ","_hasRequired","_hasrequireditem","_reason","_buildObject","_location1","_object","_objectHelper","_position","_controls","_cancel","_dir","_cnt","_pos","_distance","_buildables","_onLadder","_vehicle","_inVehicle","_abort","_needNear","_isNear","_needText","_findNearestPoles","_findNearestPole","_IsNearPlot","_canBuildOnPlot","_nearestPole","_ownerID","_friendlies","_missing","_checkMag","_enableGhost","_helperColor","_canDo","_objHDiff","_isOk","_zheightchanged","_zheightdirection","_rotate","_location2","_lastDir","_objectHelperDir","_objectHelperPos","_tmpbuilt","_limit","_proceed","_counter","_dis","_sfx","_started","_finished","_animState","_isMedic","_num_removed","_combinationDisplay","_combination_1","_combination_2","_combination_3","_combination_4","_combination","_combination_1_Display"];
//Check if building already in progress, exit if so.
if (DZE_ActionInProgress) exitWith {localize "str_epoch_player_40" call dayz_rollingMessages;};
DZE_ActionInProgress = true;
_pos = [player] call FNC_GetPos;
_onLadder = (getNumber (configFile >> "CfgMovesMaleSdr" >> "States" >> (animationState player) >> "onLadder")) == 1;
_vehicle = vehicle player;
_inVehicle = (_vehicle != player);
DZE_Q = false;
DZE_Z = false;
DZE_Q_alt = false;
DZE_Z_alt = false;
DZE_Q_ctrl = false;
DZE_Z_ctrl = false;
DZE_5 = false;
DZE_4 = false;
DZE_6 = false;
DZE_F = false;
DZE_cancelBuilding = false;
call gear_ui_init;
closeDialog 1;
if (dayz_isSwimming) exitWith {DZE_ActionInProgress = false; localize "str_player_26" call dayz_rollingMessages;};
if (_inVehicle) exitWith {DZE_ActionInProgress = false; localize "str_epoch_player_42" call dayz_rollingMessages;};
if (_onLadder) exitWith {DZE_ActionInProgress = false; localize "str_player_21" call dayz_rollingMessages;};
if (player getVariable["combattimeout",0] >= diag_tickTime) exitWith {DZE_ActionInProgress = false; localize "str_epoch_player_43" call dayz_rollingMessages;};
DZE_buildItem = _this; //This is a magazine! It's global to allow access to it from outside functions
// Need Near Requirements
_abort = false;
_reason = "";
_needNear = getArray (configFile >> "CfgMagazines" >> DZE_buildItem >> "ItemActions" >> "Build" >> "neednearby");
{
switch(_x) do{
case "fire":
{
_distance = 3;
_isNear = {inflamed _x} count (_pos nearObjects _distance);
if(_isNear == 0) then {
_abort = true;
_reason = "fire";
};
};
case "workshop":
{
_distance = 3;
_isNear = count (nearestObjects [_pos, ["Wooden_shed_DZ","WoodShack_DZ","WorkBench_DZ"], _distance]);
if(_isNear == 0) then {
_abort = true;
_reason = "workshop";
};
};
case "fueltank":
{
_distance = 30;
_isNear = count (nearestObjects [_pos, dayz_fuelsources, _distance]);
if(_isNear == 0) then {
_abort = true;
_reason = "fuel tank";
};
};
};
} forEach _needNear;
if (_abort) exitWith {
format[localize "str_epoch_player_135",_reason,_distance] call dayz_rollingMessages;
DZE_ActionInProgress = false;
};
_canBuild = [_pos, _this, true] call DZE_BuildChecks;
if (_canBuild select 0) then {
_classname = getText (configFile >> "CfgMagazines" >> DZE_buildItem >> "ItemActions" >> "Build" >> "create");
_classnametmp = _classname;
_text = getText (configFile >> "CfgVehicles" >> _classname >> "displayName");
_ghost = getText (configFile >> "CfgVehicles" >> _classname >> "ghostpreview");
_lockable = 0; //default define if lockable not found in config file below
if(isNumber (configFile >> "CfgVehicles" >> _classname >> "lockable")) then { //find out if item is lockable object
_lockable = getNumber(configFile >> "CfgVehicles" >> _classname >> "lockable"); // 2=lockbox, 3=combolock, 4=safe
};
_isAllowedUnderGround = 1; //check if allowed to build under terrain
if(isNumber (configFile >> "CfgVehicles" >> _classname >> "nounderground")) then {
_isAllowedUnderGround = getNumber(configFile >> "CfgVehicles" >> _classname >> "nounderground");
};
_offset = getArray (configFile >> "CfgVehicles" >> _classname >> "offset"); //check default distance offset, define if does not exist
if((count _offset) <= 0) then {
_offset = [0,1.5,0];
};
_objectHelper = objNull;
_isOk = true;
_location1 = [player] call FNC_GetPos; // get inital players position
_dir = getDir player; //required to pass direction when building
// if ghost preview available use that instead
if (_ghost != "") then {
_classname = _ghost;
};
_object = createVehicle [_classname, [0,0,0], [], 0, "CAN_COLLIDE"]; //object preview, not an actual object that will be built
_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]];
if (isClass (configFile >> "SnapBuilding" >> _classname)) then {
["","","",["Init",_object,_classname,_objectHelper]] spawn snap_build;
};
_objHDiff = 0;
_cancel = false;
_reason = "";
helperDetach = false;
_canDo = (!r_drag_sqf and !r_player_unconscious);
_position = [_objectHelper] call FNC_GetPos;
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;
_dir = -45;
};
if (DZE_6) then {
_rotate = true;
DZE_6 = false;
_dir = 45;
};
if (DZE_F and _canDo) then {
if (helperDetach) then {
_objectHelperDir = getDir _objectHelper;
_objectHelper attachTo [player];
_objectHelper setDir _objectHelperDir-(getDir player);
helperDetach = false;
} else {
_objectHelperDir = getDir _objectHelper;
detach _objectHelper;
[_objectHelper] call FNC_GetSetPos;
_objectHelper setVelocity [0,0,0]; //fix sliding glitch
helperDetach = true;
};
DZE_F = false;
};
if(_rotate) then {
if (helperDetach) then {
_objectHelperDir = getDir _objectHelper;
_objectHelper setDir _objectHelperDir+_dir;
[_objectHelper] call FNC_GetSetPos;
} else {
detach _objectHelper;
_objectHelperDir = getDir _objectHelper;
_objectHelper setDir _objectHelperDir+_dir;
[_objectHelper] call FNC_GetSetPos;
_objectHelperDir = getDir _objectHelper;
_objectHelper attachTo [player];
_objectHelper setDir _objectHelperDir-(getDir player);
};
};
if(_zheightchanged) then {
if (!helperDetach) then {
detach _objectHelper;
_objectHelperDir = getDir _objectHelper;
};
_position = [_objectHelper] call FNC_GetPos;
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 setDir _objectHelperDir-(getDir player);
};
};
uiSleep 0.5;
_location2 = [player] call FNC_GetPos;
_objectHelperPos = [_objectHelper] call FNC_GetPos;
if(DZE_5) exitWith {
_isOk = false;
_position = [_object] call FNC_GetPos;
detach _object;
_dir = getDir _object;
deleteVehicle _object;
detach _objectHelper;
deleteVehicle _objectHelper;
};
if(_location1 distance _location2 > 10) exitWith {
_isOk = false;
_cancel = true;
_reason = "You've moved to far away from where you started building (within 10 meters)";
detach _object;
deleteVehicle _object;
detach _objectHelper;
deleteVehicle _objectHelper;
};
if(_location1 distance _objectHelperPos > 10) exitWith {
_isOk = false;
_cancel = true;
_reason = "Object is placed to far away from where you started building (within 10 meters)";
detach _object;
deleteVehicle _object;
detach _objectHelper;
deleteVehicle _objectHelper;
};
if(abs(_objHDiff) > 10) exitWith {
_isOk = false;
_cancel = true;
_reason = "Cannot move up or down more than 10 meters";
detach _object;
deleteVehicle _object;
detach _objectHelper;
deleteVehicle _objectHelper;
};
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;
};
if (DZE_cancelBuilding) exitWith {
_isOk = false;
_cancel = true;
_reason = "Cancelled building.";
detach _object;
deleteVehicle _object;
detach _objectHelper;
deleteVehicle _objectHelper;
};
};
_isOk = true;
_proceed = false;
_counter = 0;
_location = [0,0,0];
//No building on roads unless toggled
if (!DZE_BuildOnRoads) then {
if (isOnRoad _position) then { _cancel = true; _reason = "Cannot build on a road."; };
};
// No building in trader zones
if(!canbuild) then { _cancel = true; _reason = "Cannot build in a city."; };
if(!_cancel) then {
_classname = _classnametmp;
// Start Build
_tmpbuilt = createVehicle [_classname, _location, [], 0, "CAN_COLLIDE"]; //create actual object that will be published to database
_tmpbuilt setdir _dir; //set direction inherited from passed args from control
// Get position based on object
_location = _position;
if((_isAllowedUnderGround == 0) && ((_location select 2) < 0)) then { //check Z axis if not allowed to build underground
_location set [2,0]; //reset Z axis to zero (above terrain)
};
if (surfaceIsWater _location) then {
_tmpbuilt setPosASL _location;
_location = ASLtoATL _location; //Database uses ATL
} else {
_tmpbuilt setPosATL _location;
};
format[localize "str_epoch_player_138",_text] call dayz_rollingMessages;
_limit = 3; //times it takes to build by default
if (DZE_StaticConstructionCount > 0) then { //if count is manually overridden inside init.sqf, use that instead, else use limits configured in config files
_limit = DZE_StaticConstructionCount;
}
else {
if (isNumber (configFile >> "CfgVehicles" >> _classname >> "constructioncount")) then {
_limit = getNumber(configFile >> "CfgVehicles" >> _classname >> "constructioncount");
};
};
while {_isOk} do { //publish phase
["Working",0,[100,15,10,0]] call dayz_NutritionSystem;
player playActionNow "Medic"; //animation
//alert zombies
_dis=20;
_sfx = "repair";
[player,_sfx,0,false,_dis] call dayz_zombieSpeak;
[player,_dis,true,(getPosATL player)] spawn player_alertZombies;
r_interrupt = false;
r_doLoop = true;
_started = false;
_finished = false;
while {r_doLoop} do { //while player is not interrupted, go trough animations
_animState = animationState player;
_isMedic = ["medic",_animState] call fnc_inString;
if (_isMedic) then {
_started = true;
};
if (_started && !_isMedic) then {
r_doLoop = false;
_finished = true;
};
if (r_interrupt || (player getVariable["combattimeout",0] >= diag_tickTime)) then {
r_doLoop = false;
};
if (DZE_cancelBuilding) exitWith {
r_doLoop = false;
};
uiSleep 0.1;
};
r_doLoop = false;
if(!_finished) exitWith { //exit if interrupted
_isOk = false;
_proceed = false;
};
if(_finished) then { //if animation finished, add to build count
_counter = _counter + 1;
};
format[localize "str_epoch_player_139",_text, _counter,_limit] call dayz_rollingMessages; //report how many steps are done out of total limit
if(_counter == _limit) exitWith { //if all steps done proceed with next step, otherwise cancel publish
_isOk = false;
_proceed = true;
};
};
if (_proceed) then {
_num_removed = ([player,DZE_buildItem] call BIS_fnc_invRemove); //remove item's magazine from inventory
if(_num_removed == 1) then {
format[localize "str_build_01",_text] call dayz_rollingMessages;
if (_canBuild select 1) then { //if item was a plotpole, build a visual radius around it
[] spawn player_plotPreview;
};
_tmpbuilt setVariable ["OEMPos",_location,true]; //store original location as a variable
if(_lockable > 1) then { //if item has code lock on it
_combinationDisplay = ""; //define new display
switch (_lockable) do { //generate random combinations depending on item type
case 2: { // 2 lockbox
_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 = "Red";
};
if (_combination_1 == 101) then {
_combination_1_Display = "Green";
};
if (_combination_1 == 102) then {
_combination_1_Display = "Blue";
};
_combinationDisplay = format["%1%2%3",_combination_1_Display,_combination_2,_combination_3];
};
case 3: { // 3 combolock
_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];
dayz_combination = _combination;
_combinationDisplay = _combination;
};
case 4: { // 4 safe
_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;
_combinationDisplay = _combination;
};
};
_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
PVDZ_obj_Publish = [_combination,_tmpbuilt,[_dir,_location],[]];
publicVariableServer "PVDZ_obj_Publish";
format[localize "str_epoch_player_140",_combinationDisplay,_text] call dayz_rollingMessages; //display new combination
systemChat format[localize "str_epoch_player_140",_combinationDisplay,_text];
} 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 spawn player_fireMonitor;
} else {
PVDZ_obj_Publish = [dayz_characterID,_tmpbuilt,[_dir,_location],[]];
publicVariableServer "PVDZ_obj_Publish";
};
};
} else { //if magazine was not removed, cancel publish
deleteVehicle _tmpbuilt;
localize "str_epoch_player_46" call dayz_rollingMessages;
};
} else { //if player was interrupted, cancel publish and stop build animations
r_interrupt = false;
if (vehicle player == player) then {
[objNull, player, rSwitchMove,""] call RE;
player playActionNow "stop";
};
deleteVehicle _tmpbuilt;
localize "str_epoch_player_46" 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;
};
};
DZE_ActionInProgress = false;