Jump to content

Recommended Posts

Working on a little Arma 3 farm simulator action... fairly noob to scripting, don'n know why I can't seem to get it to work.


private["_tractor","_crop","_item"];


_tractor = "RDS_Zetor6945_Base";
_crop = nearestObjects[getPos player,["CUP_A2_p_wheat_ep1"],1] select 0;
_item= binocular;


while
{
player in _tractor
player distance _crop < 10
}


do
{
deleteVehicle _crop;
_tractor addItemCargo binocular;
};

The binoculars serve as a placeholder for actual wheat, which I will be creating a gear item for. The idea is, if you're in a tractor and you run over a wheat plant, it adds wheat to the vehicle inventory.

 

I call the script via:

player execVM "Scripts\Functions\fn_HarvestWheat.sqf";

...and it doesn't work at all. I run right over the wheat and nothing happens. I'm working on several other similar scripts and none of them seem to work.

 

Help would be greatly appreciated!

Share this post


Link to post
Share on other sites
_crop = nearestObjects[getPos player,["CUP_A2_p_wheat_ep1"],1] select 0;

 

You're searching a 1m radius for the objects.

 

nearestObjects [position, types, radius]

 

Also, it may help to write your loop like this:

while {_condition} do {
     //code
};

But, double also, if you run this script when the player is more than 10m from the object it'll go straight past the while loop and finish the script. At a guess (and I'm making some assumptions here about what you're doing), you'd be better off running this whole thing in a loop with a waitUntil, and executing it at any time before the player gets within 10m:

private["_tractor","_crop","_item"];

_tractor = "RDS_Zetor6945_Base";
_item= binocular;

while {true} do {

     waitUntil {(count (nearestObjects[getPos player,["CUP_A2_p_wheat_ep1"],10])) > 0};

     {deleteVehicle _x} forEach (nearestObjects[getPos player,["CUP_A2_p_wheat_ep1"],10]);
};
  • Like 1

Share this post


Link to post
Share on other sites

It's been a bit since I have done any arma scripting, so I cannot say for sure if this works, but hopefully you will understand that idea behind it.

I am at work, but procrastinating (when I posted this) - so I might not answer right away to any replies :P.

private["_tractor","_loop"];
_tractor = "RDS_Zetor6945_Base";
_loop = true;

// loop until we tell it to stop
while {_loop} do
{
    private ["_crop"];
    // check for nearest crop on every loop so we always check and get the closest one to the player at every moment.
    _crop = nearestObjects[getPos player,["CUP_A2_p_wheat_ep1"],1] select 0;
    
    // if the player is no longer in the tractor, kill the loop (we check what vehicle the player is in, "vehicle player" it will return the player object if in no vehicle).
    if (vehicle player == player) then {
        _loop = false;
    } else {
        if (player distance _crop < 10) then {
            deleteVehicle _crop;
            _tractor addItemCargo binocular;
        };

        // might as well save a few cycles (helps to keep the server running a bit better) - no need to hammer it if its not needed.
        sleep 0.2;
    };
};

Quick edit: using waitUntil as stated in the previous answer might not be a bad idea, though you should break it if the player leaves the tractor/vehicle.
Edit edit: actually waitUntil might be a bad idea (let me know people). As I believe it will run quite a lot of times a second. Might be a better option to just sleep within the while loop as in the above code snippet.

  • Like 1

Share this post


Link to post
Share on other sites

Yup, above guys are correct. I think a basic explanation of what a while loop does would be good for you.

A 'do while' will run a set of code every time it's condition returns true. The very first time it returns false, it exits the while loop and continues the remaining code. It checks the condition each time before it executes, including the very first time. So your first script failed because it checked the values and probably returned false immediately.

Hope that explanation of the while loop helps you in the future. SirMre is correct in waitUntil is worse that a sleep function in a while loop. waitUntil will execute as fast as possible which is bad for performance. Better to do a while with a " sleep 0.01; " in it instead. Doesn't have to be 0.01, but you get the idea. Feel free to ask about anything you may be confused on with scripting and how or what to use to accomplish something.

  • Like 1

Share this post


Link to post
Share on other sites

A guy named "Haymaker" askes for a farming script ? :rolleyes:

That made my day. :)

 

 

 

 

Anyway, do pay attention to what flyinpenguin said about putting "sleep" into a while loop. Always good to get used to that.

There are very few occasions where a loop really has to run at full speed, so safe some performance by adjusting those sleep times.

Share this post


Link to post
Share on other sites

 

You're searching a 1m radius for the objects.

 

nearestObjects [position, types, radius]

 

Also, it may help to write your loop like this:

while {_condition} do {
     //code
};

But, double also, if you run this script when the player is more than 10m from the object it'll go straight past the while loop and finish the script. At a guess (and I'm making some assumptions here about what you're doing), you'd be better off running this whole thing in a loop with a waitUntil, and executing it at any time before the player gets within 10m:

private["_tractor","_crop","_item"];

_tractor = "RDS_Zetor6945_Base";
_item= binocular;

while {true} do {

     waitUntil {(count (nearestObjects[getPos player,["CUP_A2_p_wheat_ep1"],10])) > 0};

     {deleteVehicle _x} forEach (nearestObjects[getPos player,["CUP_A2_p_wheat_ep1"],10]);
};

Okay so now I have 

private["_tractor","_condition","_item"];

_tractor = "RDS_Zetor6945_Base";
_item= "binocular";

while {((typeOf (vehicle player)) == _tractor)} do {

     waitUntil {(count (nearestObjects[getPos player,["CUP_A2_p_wheat_ep1"],5])) > 0};

     {deleteVehicle _x} forEach (nearestObjects[getPos player,["CUP_A2_p_wheat_ep1"],5]);

	vehicle player addItemCargo ["binocular",1];
};

For some weird reason it adds 4-24 binoculars per wheat plant.

 

PS thanks for the help guys! 

Share this post


Link to post
Share on other sites

Use this instead.  I of course could not test it, so excuse any small typos/bugs

_tractor = "RDS_Zetor6945_Base";
_item= "binocular";
_query = [];
_num = 0;
_sleepTime = 0.02;

while {((typeOf (vehicle player)) == _tractor)} do {

	//store variables for zero chance of mismatch reference
	_query = nearestObjects[getPos player,["CUP_A2_p_wheat_ep1"],5];
	_num = count _query;
	
	//check to see if there is any wheat
	if (_num > 0) do {
	
		//delete each instance of wheat found
		{deleteVehicle _x} forEach _query;

		//add all wheat found
		vehicle player addItemCargo ["binocular",_num];
		
		//gives wheat a better chance to despawn first time
		sleep _sleepTime;
		
		//check and wait until all wheat has been removed so its not added multiple times
		_continue = true;
		_del = [];
		_total = 0;
		while {_continue} do {
		
			//checks if wheat is still there, adds 1 if its still there and 0 if its not to array _del
			{
				if (isNull _x) then {
					_del pushBack 0;
				} else {
					_del pushBack 1;
				};
			} forEach _query;
			
			//adds up elements of _del
			{
				_total = _total + _x;
			} forEach _del;
			
			//sets condition for loop if all wheat was deleted
			if (_total == 0) then {
				_continue = false;
			};
			
			//reset variables
			_del = [];
			_total = 0;
			
			//doesn't need to sleep if not continueing as it would double sleep time
			if (_continue) then {
				sleep _sleepTime;
			};
		};
	};
	
	//makes sure script doesnt hog rescources
	sleep _sleepTime;
};

If sleep is popping an error, its not running in a threaded environment.  In that case, use this instead

 

[] spawn {
	_tractor = "RDS_Zetor6945_Base";
	_item= "binocular";
	_query = [];
	_num = 0;
	_sleepTime = 0.02;

	while {((typeOf (vehicle player)) == _tractor)} do {

		//store variables for zero chance of mismatch reference
		_query = nearestObjects[getPos player,["CUP_A2_p_wheat_ep1"],5];
		_num = count _query;
	
		//check to see if there is any wheat
		if (_num > 0) do {
	
			//delete each instance of wheat found
			{deleteVehicle _x} forEach _query;

			//add all wheat found
			vehicle player addItemCargo ["binocular",_num];
		
			//gives wheat a better chance to despawn first time
			sleep _sleepTime;
		
			//check and wait until all wheat has been removed so its not added multiple times
			_continue = true;
			_del = [];
			_total = 0;
			while {_continue} do {
		
				//checks if wheat is still there, adds 1 if its still there and 0 if its not to array _del
				{
					if (isNull _x) then {
						_del pushBack 0;
					} else {
						_del pushBack 1;
					};
				} forEach _query;
			
				//adds up elements of _del
				{
					_total = _total + _x;
				} forEach _del;
			
				//sets condition for loop if all wheat was deleted
				if (_total == 0) then {
					_continue = false;
				};
			
				//reset variables
				_del = [];
				_total = 0;
			
				//doesn't need to sleep if not continueing as it would double sleep time
				if (_continue) then {
					sleep _sleepTime;
				};
			};
		};
	
		//makes sure script doesnt hog rescources
		sleep _sleepTime;
	};
};
  • Like 1

Share this post


Link to post
Share on other sites

Okay that works! Just changed the if do statement to if then and it works fine! I also added this 

//add all wheat found (if there's space in your vehicle)

			if (vehicle player canAdd "Binocular") then

			{
			vehicle player addItemCargo ["binocular",_num];
			}

			else

			{
			Hint "Your tractor can't hold any more wheat!"
			};

so that you can't infinitely fill the tractor.

 

I have noticed there is one problem where after the first wheat plant is harvested the script stops working and wont harvest anymore until re-executed, I figure that'd be a problem with sleep?

 

I've also started the plant script:

while {player distance haystack < 50} do{

if ("Chemlight_blue" in Magazines Player) then

{
		if (vehicle player == player) then
		{
			player addAction ["Plant Wheat",
			{
				"CUP_A2_p_wheat_ep1" createVehicle position player;
				 player removeItem "Chemlight_blue";
				 player playMove "Acts_TreatingWounded04";
				 sleep 5;
				 player switchmove "";
				 removeAllActions player;

			}];


		}

		else

		{
			removeAllActions player
		};
		sleep 6;
};
};

Also, will I have any trouble running these scripts in multiplayer?

Share this post


Link to post
Share on other sites

i think one can use a waitUntil, too. but one should use it with sleep.

waitUntil{sleep 0.01; (condition)};

or is that g3nerally a bad idea?

  • Like 1

Share this post


Link to post
Share on other sites

i think one can use a waitUntil, too. but one should use it with sleep.

waitUntil{sleep 0.01; (condition)};

or is that g3nerally a bad idea?

I think it technically would work, but I wouldn't recommend it.

Haymaker, try removing my part of the script that waits until it's deleted for now, I'm guessing that's what is erroring. Is there a specific error that it pops when you run game with showscripterrors?

Also for the planting part, do _act = player addiction.... You should be able to store the ID of the added action and later remove it. Don't want to remove all actions because that can mess with other mods and in game stuff.

So far, it looks like everything should work in multiplayer as is.

  • Like 1

Share this post


Link to post
Share on other sites

Okay so the act works but it doesn't remove the action once the player is more than 50 meters away or drops all of his stuff, until he actually uses the action and it removes. I guess I still don't quite understand while - do - else.

Share this post


Link to post
Share on other sites

if (vehicle player == player) then

this line means to do something if player is not in a vehicle

the code of the else statement will run if he is in a vehicle. means your action will be deleted only if player is in a vehicle within 50 meters

why within 50 m? because ur while loop will break if player is farer and the else code is not executed then

Share this post


Link to post
Share on other sites

Define _act before the while loop with _act = 0 so that it stays in scope. Then after the while loop ends, put in an if statement that checks to see if _act is not 0 (IE it was changed). And make sure to reset _act to 0 after each time you use it to remove an addaction.

So something like

If (_act != 0) then { //remove action };

On while do else, I don't know if Arma scripting supports that, so just throw whatever you need after the while loop as that will be executed when the loop ends anyways.

Share this post


Link to post
Share on other sites

Okay I see. I supposed I should tell you what I'm doing here. I'm creating a multiplayer monetary economy with shops and ways to make money!

 

This will be one of the many ways to make money.

 

Also, I've found the issue with the harvesting. If you are out of the tractor when the script is executed it won't harvest. Then once you get into the tractor the script must be re-executed for it to work. Is there any way I could just make it initialize in the init.sqf and never have to be re-executed?

Share this post


Link to post
Share on other sites

You could tie the script to an event handler instead. Have it be attached to the player and do a getin event handler. Check to see if it's the correct vehicle and launch that script.

Share this post


Link to post
Share on other sites

You could tie the script to an event handler instead. Have it be attached to the player and do a getin event handler. Check to see if it's the correct vehicle and launch that script.

I think I'll try that, I've also implemented that over to fishing where if you're in a trawler and you come within a certain distance of a Tuna, it will add an item to your cargo :D

 

As for the event Handler, I can't get one running for GetinMan for all vehicles. It will work for specific variables, but not for all of a specific classname. In the meantime as a workaround I used:

player addEventHandler ["InventoryOpened", {_this execVM "Scripts\Functions\fn_HarvestWheat.sqf"}];

Share this post


Link to post
Share on other sites

Please sign in to comment

You will be able to leave a comment after signing in



Sign In Now

×