Jump to content

[RELEASE] Area Maintenance for Player Bases (Script)


Axe Cop

Recommended Posts

Since Epoch version 1.0.4 this script is included in the default Epoch client. So you don't need to install it yourself anymore! :)

 

 

Hey guys, another script release from me. :P

 

This time area based maintenance for player bases, you know it can be a pain to maintain every single building part in your base, fear no more with this "simple" script. ;)

 

With the default options it works like this: players will get an option to "Maintain Area" if they look at a plot pole (item can be  changed but plot poles make sense I guess), then the script will maintain all base building parts within a specified range (default 50m around the plot pole), the same way as you would maintain every single part by hand. Because of the amount of affected parts admins can define other requirements to actually maintain the whole area (like a briefcase for more then 100 building parts or whatever you like there is an example in the script with some requirements for different amounts of building parts).

 

This is just my first release, I had other plans with making the maintain requirements based on the actual building parts in the area. e.g. every part gets a value (similar then it is now but with items you can stack easily like gold), so it would calculate the exact costs like 2 gold for each wooden wall, 5 gold for metal floors etc.. just an idea there might be other problems with that and it may not be easy to implement this with ArmA scripts as far as my knowledge goes at least.

So for now the maintain cost is only dependent on the amount of items to maintain, no matter what parts you use. But there can be multiple items defined for each amount, maybe someone of you have a better way of doing this, that's one reason I publish it here for all to use and improve on it (hopefully).

 

There is also a preview option ("Maintain Area Preview") to see how many building parts would be affected and what the exact costs for that would be. This option does nothing and it won't remove anything from your gear, it only displays an information text on the screen. If you use the real "Maintain Area" option the required items will be removed from your gear, if you don't own them you get a message with the missing parts like with the default maintain option.

 

 

Ok here comes the installation steps, it is pretty easy, similar to including self bloodbag to your server.

 

Step 1: Add this to your fn_selfActions.sqf file right after the line with "_canDo = ..." around line 16 (I assume you already have the file set up for other changes, if not there are many topics with how to do that):

// ---------------------------------------Maintain Area Start------------------------------------
if (_canDo && (speed player <= 1) && (cursorTarget isKindOf "Plastic_Pole_EP1_DZ")) then {
	if (s_player_maintain_area < 0) then {
		s_player_maintain_area = player addAction ["<t color=""#ffffff"">Maintain Area</t>", "scripts\maintain_area.sqf", "maintain", 5, false];
		s_player_maintain_area_preview = player addAction ["<t color=""#ccffffff"">Maintain Area Preview</t>", "scripts\maintain_area.sqf", "preview", 5, false];
	};
} else {
	player removeAction s_player_maintain_area;
	s_player_maintain_area = -1;
	player removeAction s_player_maintain_area_preview;
	s_player_maintain_area_preview = -1;
};
// ---------------------------------------Maintain Area End------------------------------------

If you want change the item where your players can activate the "Maintain Area" option (default plot pole - "Plastic_Pole_EP1_DZ"). You can also change the color of the menu (default white - #ffffff) and the path where you want to safe the actual script (default "scripts\maintain_area.sqf" in your mission.pbo).

 

Step 2: Here is the complete maintain area script:

private ["_missing","_missingQty","_proceed","_itemIn","_countIn","_qty","_num_removed","_removed","_removed_total","_tobe_removed_total","_obj","_objectID","_objectUID","_classname","_location","_dir","_objectCharacterID","_object","_temp_removed_array","_textMissing","_target","_objectClasses","_range","_objects","_requirements","_count","_cost","_itemText","_option"];

if (TradeInprogress) exitWith { cutText ["Maintenance already in progress." , "PLAIN DOWN"]; };
TradeInprogress = true;

player removeAction s_player_maintain_area;
s_player_maintain_area = 1;
player removeAction s_player_maintain_area_preview;
s_player_maintain_area_preview = 1;

_target = cursorTarget; // Plastic_Pole_EP1_DZ
_objectClasses = ["ModularItems", "DZE_Housebase"];
_range = 50; // set the max range for the maintain area
_objects = nearestObjects [_target, _objectClasses, _range];

// TODO dynamic requirements based on used building parts?
_count = count _objects;
_requirements = [];
switch true do {
	case (_count <= 10): {_requirements = [["ItemGoldBar10oz",1]]};
	case (_count <= 50): {_requirements = [["ItemGoldBar10oz",4],["ItemGoldBar",2]]}; // 42 gold
	case (_count <= 100): {_requirements = [["ItemBriefcase100oz",1]]};
	case (_count <= 200): {_requirements = [["ItemBriefcase100oz",2]]};
	case (_count <= 300): {_requirements = [["ItemBriefcase100oz",3]]};
	case (_count <= 400): {_requirements = [["ItemBriefcase100oz",4]]};
	case (_count > 400): {_requirements = [["ItemBriefcase100oz",5]]};
};

_option = _this select 3;
switch _option do {
	case "maintain": {
		_missing = "";
		_missingQty = 0;
		_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; };
		} forEach _requirements;

		if (_proceed) then {
			player playActionNow "Medic";
			[player,_range,true,(getPosATL player)] spawn player_alertZombies;

			_temp_removed_array = [];
			_removed_total = 0;
			_tobe_removed_total = 0;
			
			{
				_removed = 0;
				_itemIn = _x select 0;
				_countIn = _x select 1;
				_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];
						};
					};
				} forEach magazines player;
			} forEach _requirements;

			// all required items removed from player gear
			if (_tobe_removed_total == _removed_total) then {
				{
					_obj = _x;
					
					// Find objectID
					_objectID = _obj getVariable ["ObjectID","0"];

					// Find objectUID
					_objectUID = _obj getVariable ["ObjectUID","0"];
					
					if (_objectID == "0" && _objectUID == "0") exitWith { cutText ["At least one building part is not setup yet.", "PLAIN DOWN"];};
					
					// Get classname
					_classname = typeOf _obj;
					
					// Get position
					_location = _obj getVariable["OEMPos",(getposATL _obj)];

					// Get direction
					_dir = getDir _obj;

					// Find CharacterID
					_objectCharacterID = _obj getVariable ["CharacterID","0"];
					
					// Create new object
					_object = createVehicle [_classname, [0,0,0], [], 0, "CAN_COLLIDE"];

					// Set direction
					_object setDir _dir;

					// Set location
					_object setPosATL _location;

					PVDZE_obj_Swap = [_objectCharacterID,_object,[_dir,_location],_classname,_obj,_objectID,_objectUID];
					publicVariableServer "PVDZE_obj_Swap";

					player reveal _object;
				} forEach _objects;
				
				cutText [format["You have maintained %1 building parts.", _count], "PLAIN DOWN", 5];
				// uncomment the next 2 lines if you want logging of area maintenance to the server report file (Arma2OAserver.RPT)
				//maintainArea_log = [player, _target, _count];
				//publicVariableServer "maintainArea_log";
			} else {
				{player addMagazine _x;} forEach _temp_removed_array;
				cutText [format["Missing Parts after first check Item: %1 / %2",_removed_total,_tobe_removed_total], "PLAIN DOWN"];
			};
		} else {
			_textMissing = getText(configFile >> "CfgMagazines" >> _missing >> "displayName");
			cutText [format["Missing %1 more of %2", _missingQty, _textMissing], "PLAIN DOWN"];
		};
	};
	case "preview": {
		_cost = "";
		{
			_itemIn = _x select 0;
			_countIn = _x select 1;
			_itemText = getText(configFile >> "CfgMagazines" >> _itemIn >> "displayName");
			if (_cost != "") then {
				_cost = _cost + " and ";
			};
			_cost = _cost + (str(_countIn) + " of " + _itemText);
		} forEach _requirements;
		cutText [format["%1 building parts in range, maintenance would cost %2.", _count, _cost], "PLAIN DOWN"];
	};
};

TradeInprogress = false;
s_player_maintain_area = -1;
s_player_maintain_area_preview = -1;

Save it as "scripts\maintain_area.sqf" in your mission.pbo or whatever you have defined in the menu before.

 

Step 3 (optional): change the default options in the script:

_range (line 13): sets the maximum range for the maintain area around the plot pole (default 50m).

_requirements (line 18+): defines the required items for the amount of affected base building parts, there are some examples just take a look it should be easy to extend/modify.

 

Step 4 (optional): logging of area maintenance to the server report file (Arma2OAserver.RPT):

Since the script runs on the client (player computer who starts the maintenance) it can be desirable to log additional info in the server report file to keep track what player did the maintenance at what time and position on the map and how many building parts were affected, to do this the script has to send that info to the server. This can be done with the "publicVariableServer" command, just uncomment (remove the leading //) the 2 lines in the script where it says so for logging (line 110+111).

For the server to receive that variable and log the info you have to add an public variable event handler with "addPublicVariableEventHandler", this can be done at any place in the mission.pbo, but usually all event handlers are handled in the file "dayz_code\init\publicEH.sqf", copy that file to your mission.pbo and change the reference to it in the init.sqf if you haven't already and add the following to the "Server only" block (after the line with "PVDZE_plr_DeathB" is fine):

"maintainArea_log"		addPublicVariableEventHandler {
	_val = _this select 1;
	_player = _val select 0;
	_playerName = name _player;
	_playerID = getPlayerUID _player;
	_target = _val select 1;
	_position = position _target;
	_count = _val select 2;
	diag_log format["MAINTAIN_AREA: Player %1 (%2) has maintained %3 building parts at position %4", _playerName, _playerID, _count, _position];
};

This will log a line like this every time a player runs the maintenance script: 14:33:01 "MAINTAIN_AREA: Player Axe Cop (12345678) has maintained 245 building parts at position [4937,9421.44,-0.796936]"

If you are lazy your can add the event handler to your init.sqf after the line "_serverMonitor = ... " without changing the file publicEH.sqf  :P

 

That's it, should be easy enough to get the script working on your server.  ;)

 

 

One major problem with the whole maintenance thing in Epoch (not this script) is the fact, that you can't visually see if your base needs to be maintained or when it was last maintained, I hope that will be fixed with the next Epoch updates because I don't see any way of even accessing the last maintain date form the script itself. What Epoch does is just set a small damage value to every part to indicate that it needs to be maintained soon, but you can't see that damage in game (yet).

For now my script just maintains every single part within range, no matter when it was last maintained. I could change it so it only affects damaged parts like Epoch does when maintenance is needed (just to decrease the maintenance cost for players).

Also keep in mind the maintain process replaces the objects rather then just removing the damage and resetting the date, don't ask me why but I guess there is a reason for it so I did it the same way in my script.

 

 

At last sorry for the long text, as always if you have any questions or ideas to make this script better please tell me or improve the script. :)

 

 

Edit: logging of area maintenance (see step 4)

Edited by Axe Cop
Link to comment
Share on other sites

Really cool. The only problem I can imagine is the same problem we've always had with plot poles. If you die, you no longer "own" the plot pole unless you script fixes that. I haven't looked it over yet.

The script doesn't care about the owner of the plot pole, why would it? If you want go maintain an enemy base lol, but what do you gain from that? it will only cost you money. :D

 

Edit: I just checked the original maintain code, so you should also be able to go around and maintain every building part anyways..?

Edited by Axe Cop
Link to comment
Share on other sites

One major problem with the whole maintenance thing in Epoch (not this script) is the fact, that you can't visually see if your base needs to be maintained or when it was last maintained, I hope that will be fixed with the next Epoch updates because I don't see any way of even accessing the last maintain date form the script itself. What Epoch does is just set a small damage value to every part to indicate that it needs to be maintained soon, but you can't see that damage in game (yet).

For now my script just maintains every single part within range, no matter when it was last maintained. I could change it so it only affects damaged parts like Epoch does when maintenance is needed (just to decrease the maintenance cost for players).

 

It's my understanding that using the SQL code below, damage is set on buildables at the interval (I set mine to 21 days), and that enables the "Maintain" option. Is that not correct?

 

DROP EVENT IF EXISTS setDamageOnAge;
CREATE EVENT setDamageOnAge
    ON SCHEDULE EVERY 1 DAY
    COMMENT 'This sets damage on a wall so that it can be maintained'
    DO
      UPDATE `object_data` SET `Damage`=0.1 WHERE `ObjectUID` <> 0 AND `CharacterID` <> 0 AND `Datestamp` < DATE_SUB(CURRENT_TIMESTAMP, INTERVAL 21 DAY) AND ( (`Inventory` IS NULL) OR (`Inventory` = '[]') )
Link to comment
Share on other sites

Ok, I've installed this script but it doesn't seem to be working. I put down a plot pole, built a wall and when I look at the plot pole, no scroll menu comes up. Looking at my RPT file, I am seeing this:

16:06:19 Error in expression <lowdog;
s_player_followdog = -1;
};
};
 
} else {
 
{dayz_myCursorTarget removeAct>
16:06:19   Error position: <} else {
 
{dayz_myCursorTarget removeAct>
16:06:19   Error Missing {
16:06:19 File mpmissions\__cur_mp.Chernarus\custom\fn_selfActions.sqf, line 768
16:06:19 Error in expression <lowdog;
s_player_followdog = -1;
};
};
 
} else {
 
{dayz_myCursorTarget removeAct>
16:06:19   Error position: <} else {
 
{dayz_myCursorTarget removeAct>
16:06:19   Error Missing {
16:06:19 File mpmissions\__cur_mp.Chernarus\custom\fn_selfActions.sqf, line 768
16:06:20 Error in expression < "CAN_COLLIDE"];
Here's my fn_selfactions.sqf: http://pastebin.com/MDZFYN0Y
 
Link to comment
Share on other sites

 

It's my understanding that using the SQL code below, damage is set on buildables at the interval (I set mine to 21 days), and that enables the "Maintain" option. Is that not correct?

That is correct, but I don't see the relation to my statement!? :D

I just said you can't see what you have to maintain, other than the maintain option of course but do you check every single object in you base with that every day?? :P

Would just be nice to see the damage or some kind of "cracks in the wall" you know..

 

 

Ok, I've installed this script but it doesn't seem to be working. I put down a plot pole, built a wall and when I look at the plot pole, no scroll menu comes up. Looking at my RPT file, I am seeing this:

16:06:19 Error in expression <lowdog;
s_player_followdog = -1;
};
};
 
} else {
 
{dayz_myCursorTarget removeAct>
16:06:19   Error position: <} else {
 
{dayz_myCursorTarget removeAct>
16:06:19   Error Missing {
16:06:19 File mpmissions\__cur_mp.Chernarus\custom\fn_selfActions.sqf, line 768
16:06:19 Error in expression <lowdog;
s_player_followdog = -1;
};
};
 
} else {
 
{dayz_myCursorTarget removeAct>
16:06:19   Error position: <} else {
 
{dayz_myCursorTarget removeAct>
16:06:19   Error Missing {
16:06:19 File mpmissions\__cur_mp.Chernarus\custom\fn_selfActions.sqf, line 768
16:06:20 Error in expression < "CAN_COLLIDE"];
Here's my fn_selfactions.sqf: http://pastebin.com/MDZFYN0Y

 

Ok thats some weird error you got there, I don't see what that has to do with my maintain actions but I think I found the error. Look at line 245 and remove it "};", seems to be the error but you have to test in on your server. :)

 

And sorry for the late answer, I was working on my new script and now it is past 4am here.. need some sleep :P

Link to comment
Share on other sites

Thanks for pointing that out. It fixed the problem. Now I have a a request. Would it be possible to make it so only buildables with 0.11 or more damage can be repaired by this?

Yup that's pretty simple I think, try this (not tested):

 

below

_objects = nearestObjects [_target, _objectClasses, _range];

add this filter

_objects_filtered = [];
{
	if (damage _x >= 0.11) then { // maybe you mean "damage _x > 0.1" ??
		_objects_filtered set [count _objects_filtered, _x];
	};
} forEach _objects;
_objects = _objects_filtered;

just my quick solution, maybe there is a better way but that should work, of course you can add more filters in that loop (not only damage >= 0.11). ;)

I also added a comment maybe you did mean damage > 10%? then replace ">= 0.11" with "> 0.1" :D

Link to comment
Share on other sites

Yup that's pretty simple I think, try this (not tested):

 

below

_objects = nearestObjects [_target, _objectClasses, _range];

add this filter

_objects_filtered = [];
{
	if (damage _x >= 0.11) then { // maybe you mean "damage _x > 0.1" ??
		_objects_filtered set [count _objects_filtered, _x];
	};
} forEach _objects;
_objects = _objects_filtered;

just my quick solution, maybe there is a better way but that should work, of course you can add more filters in that loop (not only damage >= 0.11). ;)

I also added a comment maybe you did mean damage > 10%? then replace ">= 0.11" with "> 0.1" :D

 

Thank you. I will test that. I found that with damage set to 0.1, the option to maintain didn't appear. I had to set damage to 0.11, which is why I requested that. I will test this and let you know if it works.

Link to comment
Share on other sites

Hey Axe Cop,

 

can you told me what is in the class "DZE_Housebase"?

 

Also Sandbacks and the hole Crafting Stuff from http://dayzepoch.com/wiki/index.php?title=Crafting_System ?

Nope, DZE_Housebase are just the dynamic doors from the modular building system.. defined in the file https://github.com/vbawol/DayZ-Epoch/blob/master/SQF/dayz_code/Configs/CfgVehicles/DZE/Doors.hpp (search for DZE_Housebase in that file).

If you want to add the other building stuff like sandbags, tank traps etc you can use "BuiltItems", see this file https://github.com/vbawol/DayZ-Epoch/blob/master/SQF/dayz_code/Configs/cfgVehicles.hpp (ModularItems are also defined in there)

Link to comment
Share on other sites

Please sign in to comment

You will be able to leave a comment after signing in



Sign In Now
×
×
  • Create New...