Jump to content

Recommended Posts

I am currently using the below script as a safe zone, where players and vehicles do not take damage, for Bluefor's deployment and it works fine, but I'm trying to find a way for only that specific side to be affected and how I can add another safe zone in for Opfor. I put it in my init.sqf file. Please help, I'm new to this. Thanks!

0 = [] spawn { 
    while{true} do { 
        { 
            if(_x distance (getMarkerPos "bluefor_safe_zone") < 200) then {_x allowDamage false} else {_x allowDamage true}; 
        } forEach allUnits + vehicles; 
        sleep 1; 
    }; 
};

 

Share this post


Link to post
Share on other sites

hi,

Did you try something like this ?

0 = [] spawn { 
    while{true} do { 
        { 
            if ((_x distance (getMarkerPos "bluefor_safe_zone") < 200) && (side _x == west)) then {_x allowDamage false} else {_x allowDamage true};
            if ((_x distance (getMarkerPos "opfor_safe_zone") < 200) && (side _x == east)) then {_x allowDamage false} else {_x allowDamage true}; 
        } forEach allUnits + vehicles; 
        sleep 1; 
    }; 
};

 

Share this post


Link to post
Share on other sites

Something similar, but I think I did it wrong. I'll try this now. Thanks!

Share this post


Link to post
Share on other sites

That script didn't work well. Only my player was invincible as opfor. All vehicles still took damage.

Share this post


Link to post
Share on other sites

Some guy has same problem as you here 

 

 

you should team up and help each other

  • Like 4

Share this post


Link to post
Share on other sites

Probably cos empty vehicles dont have a side?

Look into it.

Share this post


Link to post
Share on other sites

two topics fro the same op and for the same problem?

Are u serious?

Share this post


Link to post
Share on other sites

That can't work anyway, for a logical reason:

if ((_x distance (getMarkerPos "bluefor_safe_zone") < 200) && (side _x == west)) then {_x allowDamage false} else {_x allowDamage true};

if ((_x distance (getMarkerPos "opfor_safe_zone") < 200) && (side _x == east)) then {_x allowDamage false} else {_x allowDamage true};

 

two "if then else" ruins your code.

 

Place/edit 2 repeatable markers with act/deact or try something like:


 

0 = [] spawn { 
  while{true} do { 
  { 
    Call {
      if ((_x distance (getMarkerPos "bluefor_safe_zone") < 200) && (side _x == west)) exitWith {_x allowDamage false};
      if ((_x distance (getMarkerPos "opfor_safe_zone") < 200) && (side _x == east)) exitWith {_x allowDamage false};
      _x allowDamage true;
    };
  } forEach (allUnits + (vehicles select {!(_x isKindOf "weaponHolderSimulated")})); 
  sleep 1; 
  }; 
}

 

Share this post


Link to post
Share on other sites
2 hours ago, pierremgi said:

That can't work anyway, for a logical reason:

if ((_x distance (getMarkerPos "bluefor_safe_zone") < 200) && (side _x == west)) then {_x allowDamage false} else {_x allowDamage true};

if ((_x distance (getMarkerPos "opfor_safe_zone") < 200) && (side _x == east)) then {_x allowDamage false} else {_x allowDamage true};

 

two "if then else" ruins your code.

 

Place/edit 2 repeatable markers with act/deact or try something like:


 


0 = [] spawn { 
  while{true} do { 
  { 
    Call {
      if ((_x distance (getMarkerPos "bluefor_safe_zone") < 200) && (side _x == west)) exitWith {_x allowDamage false};
      if ((_x distance (getMarkerPos "opfor_safe_zone") < 200) && (side _x == east)) exitWith {_x allowDamage false};
      _x allowDamage true;
    };
  } forEach (allUnits + (vehicles select {!(_x isKindOf "weaponHolderSimulated")})); 
  sleep 1; 
  }; 
}

 

Any reason for the "call" inside the forEach statement?

 

Cheers

Share this post


Link to post
Share on other sites

I've been given a new script but it only protects opfor's side.

//Untested script.
0 = [] spawn {
	//[[Marker Name, Side], [Marker Name, Side], etc...]
	_safeZones = [["blufor_safe_zone", west], ["opfor_safe_zone", east]];
	while {true} do {
		{
			//stores the current marker name
			_markerName = _x select 0;
			//stores the current marker side
			_markerSide = _x select 1;
			{
				//see if unit/vehicle position is in the area of the marker
				if((position _x) inArea _markerName) then {
					//comparing the unit/vehicle side to the current marker side. will also protects empty vehicles
					if((side _x) == _markerSide || (side _x) == civilian) then {
						//if unit side belongs to zone side
						_x allowDamage false;
					}else{
						//if unit side does not belong to zone side
						_x allowDamage true;
					}
				}else{
					//if unit isn't in zone
					_x allowDamage true;
				}
			}forEach (allUnits + vehicles);
		}forEach _safeZones;
		sleep 1.0;
	};
};

Anyone know why this would be?

Share this post


Link to post
Share on other sites

 

3 minutes ago, Tankbuster said:

inareaarray

and

inArea

Of interest?

I don't know. This was given to me. I know very little about scripting.

Share this post


Link to post
Share on other sites
3 minutes ago, Tankbuster said:

Oh, I see you used that command. I'm pretty sure they are the way forward.

 

Also, what does the ProtectionZone_F do?

 

https://community.bistudio.com/wiki/File:ProtectionZone_F.jpg

It would work but it is very minimal.

You cant change the shape, size, or which side it protects, nor does it protect vehicles.

Share this post


Link to post
Share on other sites

Ah OK. I do remember the grumpy German mission maker using it in A2 a while back.

Share this post


Link to post
Share on other sites
6 hours ago, Grumpy Old Man said:

Any reason for the "call" inside the forEach statement?

 

Cheers

Yes:

Call {

if ...  exitWith >> bail out the call if most common occurrence is met

if ... exitWith  >> bail out if a less met occurrence (2nd most wanted)

.....

general code (by defaut) if no condition met

}; // end call then exitWtih (s) scope.

 

Faster, selective;

Share this post


Link to post
Share on other sites
2 hours ago, sarogahtyp said:

 

Thought as a fast switch alternative:

https://community.bistudio.com/wiki/Code_Optimisation#Make_it_pretty

 

but I doubt that it's really faster in this context.

Yes, faster (just try it with 200 units, even with distanceSqr) and selective:  that's the solution to avoid multiplying checks with if then else lines:

 for a double condition:  if blue in blue area,   else will fire for:  not blue or not in area.

 

Share this post


Link to post
Share on other sites
5 minutes ago, pierremgi said:

Yes, faster (just try it with 200 units, even with distanceSqr) and selective:  that's the solution to avoid multiplying checks with if then else lines:

 for a double condition:  if blue in blue area,   else will fire for:  not blue or not in area.

 

200 units in one (or maybe 2) safezones at the same time?

ll not happen such often I guess

Share this post


Link to post
Share on other sites
1 minute ago, sarogahtyp said:

200 units in one (or maybe 2) safezones at the same time?

ll not happen such often I guess

Sure. Good demonstration. Just keep your doubt.

Share this post


Link to post
Share on other sites
4 minutes ago, pierremgi said:

Sure. Good demonstration. Just keep your doubt.

I do not doubt that it is very usefull generally. And I think it's mostly used too little. But my opinion in this context is that it's overpowered. but nobody has to do what I think.

Share this post


Link to post
Share on other sites
1 hour ago, sarogahtyp said:

I do not doubt that it is very usefull generally. And I think it's mostly used too little. But my opinion in this context is that it's overpowered. but nobody has to do what I think.

 

If you ask me there's no such thing as overpowered in terms of script performance /CPU time needed.

Well, let's test it then.

 

In the VR map, placing myself, those 2 safezone markers and populating the map using this:


_westgrp = creategroup west;
_eastgrp = creategroup east;

_worldcenter = getArray (configfile >> "CfgWorlds" >> worldName >> "centerPosition");

for "_i" from 1 to 100 do {

	_unit = _westgrp createUnit ["B_Soldier_F",getmarkerpos "bluefor_safe_zone",[],200,"NONE"];
	dostop _unit;
	_unit disableAI "ALL";

	_unit = _eastgrp createUnit ["O_Soldier_F",getmarkerpos "opfor_safe_zone",[],200,"NONE"];
	dostop _unit;
	_unit disableAI "ALL";


};

for "_i" from 1 to 100 do {

	_unit = _westgrp createUnit ["B_Soldier_F",_worldcenter,[],(worldSize / 2) * 1.4142,"NONE"];
	dostop _unit;
	_unit disableAI "ALL";

	_unit = _eastgrp createUnit ["O_Soldier_F",_worldcenter,[],(worldSize / 2) * 1.4142,"NONE"];
	dostop _unit;
	_unit disableAI "ALL";

};

{_x setbehaviour "CARELESS"} foreach allunits;

Gives 100 units within range of each safezone and 200 more units spread out over the map.

Also setting them careless to prevent accidents, heh.

 

Now using this to check for safezone distance:

{

	Call {
	if ((_x distance (getMarkerPos "bluefor_safe_zone") < 200) && (side _x == west)) exitWith {_x allowDamage false};
	if ((_x distance (getMarkerPos "opfor_safe_zone") < 200) && (side _x == east)) exitWith {_x allowDamage false};
	_x allowDamage true;
	};

} forEach (allUnits + (vehicles select {!(_x isKindOf "weaponHolderSimulated")}));

Runs for 2.46798 ms on my machine in this example, average of 10000 iterations, which could be improved for sure.

Even when ran only once every second trying to squeeze out any performance while maintaining functionality has priority in my opinion.

Considering one frame at 60fps runs for around 16.67ms the runtime of 2.4ms is pretty long and close to the 3ms rule.

 

Replacing == with isEqualTo:

{

	Call {
	if ((_x distance (getMarkerPos "bluefor_safe_zone") < 200) && (side _x isEqualTo west)) exitWith {_x allowDamage false};
	if ((_x distance (getMarkerPos "opfor_safe_zone") < 200) && (side _x isEqualTo east)) exitWith {_x allowDamage false};
	_x allowDamage true;
	};

} forEach (allUnits + (vehicles select {!(_x isKindOf "weaponHolderSimulated")}));

Runs for 2.33878 ms. 5.5% performance increase, not too shabby.

 

Now lets add lazy evaluation:

{

	Call {
	if ((_x distance (getMarkerPos "bluefor_safe_zone") < 200) && {(side _x isEqualTo west)}) exitWith {_x allowDamage false};
	if ((_x distance (getMarkerPos "opfor_safe_zone") < 200) && {(side _x isEqualTo east)}) exitWith {_x allowDamage false};
	_x allowDamage true;
	};

} forEach (allUnits + (vehicles select {!(_x isKindOf "weaponHolderSimulated")}));

2.079 ms. That's a 18.7% increase from the original example.

 

Let's exchange the distance check with a distancesqr and use the squared distance of 200 (40000) to check for:

{

	Call {
	if ((_x distancesqr (getMarkerPos "bluefor_safe_zone") < 40000) && {(side _x isEqualTo west)}) exitWith {_x allowDamage false};
	if ((_x distancesqr (getMarkerPos "opfor_safe_zone") < 40000) && {(side _x isEqualTo east)}) exitWith {_x allowDamage false};
	_x allowDamage true;
	};

} forEach (allUnits + (vehicles select {!(_x isKindOf "weaponHolderSimulated")}));

2.03252 ms - 21.4% increase from the original, definitely gonna take that!

 

Now we tried quite some stuff, functionality remains intact, performance increase is pretty decent.

But there's more, we don't have to check the marker position for every unit that's being iterated, instead we define it as a global variable and check this as a constant instead. Can improve performance a good bit, especially with a high unit count:


westPos = getMarkerPos "bluefor_safe_zone";
eastPos = getMarkerPos "opfor_safe_zone";

{

	Call {
	if ((_x distancesqr westPos < 40000) && {(side _x isEqualTo west)}) exitWith {_x allowDamage false};
	if ((_x distancesqr eastPos < 40000) && {(side _x isEqualTo east)}) exitWith {_x allowDamage false};
	_x allowDamage true;
	};

} forEach (allUnits + (vehicles select {!(_x isKindOf "weaponHolderSimulated")}));

Runs for 1.94553 ms - 26.8% faster than the original.

Don't forget to update the respective global variables when the marker position changes!

 

So much for this approach. There's probably folks out there who could make it run even faster. Maybe there's a way, heh.

 

Cheers

  • Like 2

Share this post


Link to post
Share on other sites
_westPos = getMarkerPos "bluefor_safe_zone";
_eastPos = getMarkerPos "opfor_safe_zone";

{
	[_westPos, _eastPos] call {
	if ((_x distancesqr _this select 0 < 40000) && {(side _x isEqualTo west)}) exitWith {_x allowDamage false};
	if ((_x distancesqr _this select 1 < 40000) && {(side _x isEqualTo east)}) exitWith {_x allowDamage false};
	_x allowDamage true;
	};
	true
} count (allUnits + (vehicles select {!(_x isKindOf "weaponHolderSimulated")}));

what bout using count instead of forEach? and I don't like global things if not necessary ;-)

Edited by sarogahtyp
typo

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

×