Jump to content
Sign in to follow this  
Tankbuster

Removing triggers

Recommended Posts

Guys,

My IED script was initially a tiny script to spice up my Domination edit but has since grown to be a sizeable project in it's own right.

I'm using triggers to set the 'splodes off, but due to the long drawn out nature of it's development and the way I've learnt scripting as I've gone along, all the triggers have the same name. They are created by script in random locations within or near the town. The scripts run only on the server.

They are spawned in each main target town and some go off, some are never set off so lie dormant. I want to remove them when the players take the town and move on.

So, should I re-engineer the code so that each of the triggers has a unique name, or is there a way of finding the triggers and deleting them easily using script?

The triggers are attachTod to an IED object so it should be easy to get their location. I've tried deleting the IED object to see if the triggers gets deleted too, but it doesn't.

I thought of moving the object (and thus, the trigger) somewhere well out of the way, but am worried that not deleted unused triggers might be having an effect of server performance.

I'd prefer not to have to remake the code that generates the IEDs and triggers, but if that's going to be easier and most efficient in the long run, I'd consider it. If replies could weigh up the pros and cons of both methods and maybe if there's a third way, discuss that too.

Many thanks,

Paul

Edited by Tankbuster

Share this post


Link to post
Share on other sites
is there a way of finding the triggers and deleting them easily using script?
Celery did found thisTrigger time ago. Try deleteVehicle it from its own statement fields.

Share this post


Link to post
Share on other sites

Tried using setTriggerText and search the area for all triggers matching that text?

Note that one of the commands used to search for objects won't find triggers. Bug?

Share this post


Link to post
Share on other sites

I thought of moving the object (and thus, the trigger) somewhere well out of the way, but am worried that not deleted unused triggers might be having an effect of server performance.

What is in the condition field of the triggers? Is it simply "this" using detected or present? If so, I would not worry too much about performance. Here is a compilation post I made with several links discussing trigger (and loop) performance:

http://forums.bistudio.com/showpost.php?p=1595350&postcount=13

That being said, I would suggest changing the code to give the trigger unique names using missionNamespace and setVariable.

Share this post


Link to post
Share on other sites
Celery did found thisTrigger time ago. Try deleteVehicle it from its own statement fields.

Seen that already, not relevant. The deletion of the triggers is not dependant on the trigger status, but on the wider state of the mission.

---------- Post added at 05:47 PM ---------- Previous post was at 05:45 PM ----------

Tried using setTriggerText and search the area for all triggers matching that text?

Note that one of the commands used to search for objects won't find triggers. Bug?

Ah, now were getting somewhere. I didn't know we could search for triggers using triggerText. I assume we use nearestObjects? This would save me changing existing code.

---------- Post added at 05:48 PM ---------- Previous post was at 05:47 PM ----------

What is in the condition field of the triggers? Is it simply "this" using detected or present?

Good question. The condition code is very complex. So much so that it's preprocessedfilelinenumber'd. :)

---------- Post added at 05:50 PM ---------- Previous post was at 05:48 PM ----------

That being said, I would suggest changing the code to give the trigger unique names using missionNamespace and setVariable.

OK, that's new for me, although I'm aware of these commands. Why would they have relevance here?

Share this post


Link to post
Share on other sites

Create an object (eg. game logic) or global variable for each city. Store an array with all the triggers (perhaps the IED objects too). When the city is cleared you just delete everything in the array.

You certainly don't need to use a global variable for everything.

Share this post


Link to post
Share on other sites

Why delete them at all? Mine and IED removal is a lucrative business for intrepid entrepreneurs in war torn Takistan and by automatically removing the IEDs you put their livelihoods at risk to save maybe a few children and a few kilobytes of memory...

Share this post


Link to post
Share on other sites

You could go with something simple like this:

_trigger = createTrigger ....
_iedObject = createVehicle ....
_iedObject setVariable ["iedTrigger", _trigger];
....
deleteVehicle (_iedObject getVariable "iedTrigger");
deleteVehicle _iedObject;

If you can keep track of the IED objects, no reason not to be able to keep track of the triggers as well.

Share this post


Link to post
Share on other sites
Why delete them at all? Mine and IED removal is a lucrative business for intrepid entrepreneurs in war torn Takistan and by automatically removing the IEDs you put their livelihoods at risk to save maybe a few children and a few kilobytes of memory...

You make a good point. In fact, I have two types of IED.

A large one, nominally controlled by the enemy arty observers. Once they are killed, the large IEDs - intended for command detonation against vehicles or groups of men - won't go off. I use an existing Domi variable, that counts the arty observers, but once' you killed them and taken a city, the next city spawns arty obs and so the count gets a positive variable, thus making the large IEDs in the old town live again. This is the main reason I want to remove these triggers.

The small type of IED is nominally the pressure plate stuff and is intended to be primarily anti personnel., so they can go off at any time, even after the town has been taken. I'd like to leave these in place for the entire game, that's much more realistic - a pressure plate IED doesn't care who controls the town - but if there's a performance hit with all these extra triggers, I'd remove them too.

In the game, the IEDs are incidental, but in Domi, to take a town players have a number of tasks per town, and it's possible I might make IED clearance a task too.

By the way, my side missions give abilities, not vehicles. One of the abilities they can win is the engineer can see the IED, maybe by map markers, not decided that one yet.

---------- Post added at 07:20 PM ---------- Previous post was at 07:18 PM ----------

You could go with something simple like this:

_trigger = createTrigger ....
_iedObject = createVehicle ....
_iedObject setVariable ["iedTrigger", _trigger];
....
deleteVehicle (_iedObject getVariable "iedTrigger");
deleteVehicle _iedObject;

If you can keep track of the IED objects, no reason not to be able to keep track of the triggers as well.

But does that work with more than one IED? My mission has a broadly random number, but for illustration, Feruz Abad would normally have ~5 small and ~1 large IED.

---------- Post added at 07:25 PM ---------- Previous post was at 07:20 PM ----------

Create an object (eg. game logic) or global variable for each city. Store an array with all the triggers (perhaps the IED objects too). When the city is cleared you just delete everything in the array.

You certainly don't need to use a global variable for everything.

I realise that. But my triggers have identical names at the moment. Perhaps we're at the stage where I should post some code so you can all laugh at me. :)

case "small":
{
			_t_rand = floor (random (count (_smallclutterobjects)));
			_clutterclass = _smallclutterobjects select _t_rand;
			_clutterclass = "FlagCarrierBIS_EP1";

			if (_clutterclass in ["WildBoar", "Sheep", "Fin", "Pastor"]) then
			{
				_clutterobj = createAgent [_clutterclass, [_t_xpos, _t_ypos], [], 0, "NONE"];
				_clutterobj setdamage 1;
			} 
			else
			{
				_clutterobj = createVehicle [_clutterclass, [_t_xpos, _t_ypos], [], 0,"NONE"];
				_clutterobj enableSimulation false;
			};
			_realpos = getPos _clutterobj; // createvehicle sometimes moves it's object away from other opbjects to prevent clipping. get new position
			_t_xpos = _realpos select 0;
			_t_ypos = _realpos select 1;
			_iedobj = createVehicle [bAF_ied_v3, [_t_xpos, _t_ypos], [], 0, "CAN_COLLIDE"];
			diag_log format ["small ied create index %1, xpos %2, y pos %3", _t_smalliedcount, _t_xpos, _t_ypos];

			_t_iedtrigger = createTrigger ["EmptyDetector", [_t_xpos, _t_ypos]];
			_t_iedtrigger setTriggerArea[3, 3, 0, false];
			_t_iedtrigger setTriggerActivation["ANY", "PRESENT", false];
			_t_strinf = format ["_tankysmallied%1 = createVehicle [""SEK_TR_GUE_smallbomb"", [%2,%3], [], 0, ""NONE""];",_t_smalliedcount,_t_xpos,_t_ypos];
			_t_iedtrigger setTriggerStatements ["thisList call fnc_smallbombtrigger", _t_strinf, ""];
			_t_smalliedcount = _t_smalliedcount -1;
};

Each IED is hidden inside, or under a clutterobject though for debug, this object is currently a flagpole. the fnc_smallbombtrigger is the precompiled code that runs the activation.

Share this post


Link to post
Share on other sites

If you can delete any number of IED objects, you can then use the same method to delete any number of IED triggers attached to those objects, since you can just use getVariable to get the trigger before deleting the object.

Of course you can also save all the triggers in 1 big array and then clean them up in the end, just like you can do with the objects (instead of using nearObjects or any other more "expensive" commands). That is when initializing a "town", do:

iedArray = [];
iedCount = 0;

And then whenever you create and IED add it to the array by:

iedArray set [iedCount, _newied];
iedCount = iedCount+1;

Then you can either do the same thing for the triggers or just setVariable them onto the IED objects themselves.

When a town is no longer relevant (which I suppose is before you spawn the next town), then you delete all IEDs and triggers, set the array back to [] and the count back to 0, and create new ones in the new town.

If you want multiple towns as well you can just use an array where each element is an array itself which contains the IEDs for said town.

Share this post


Link to post
Share on other sites

I think you've hit on the best way, Galzohar.

Share this post


Link to post
Share on other sites
Ah, now were getting somewhere. I didn't know we could search for triggers using triggerText. I assume we use nearestObjects? This would save me changing existing code.

What is already suggested may be more suitable for you. But this is the function I use to dynamically delete sound triggers:

XfSoundObjectRemover = {
private ["_killed","_pos","_i","_trigger","_objecttypes","_list"];
_killed = _this select 0;
_pos = getPos _killed;
_objecttypes = ["RadarTop","RadarBottom","RadarGenerator","HQAntenna","HQRadio","FactoryContainer","FactoryGenerator","FactoryTank","AmbulWalkie","TowerWalkie"];
_list = _pos nearObjects ["EmptyDetector",40];
for "_i" from 0 to count _list - 1 do {
	_trigger = _list select _i;
	if (triggerText _trigger in _objecttypes) then {
		sleep 1.234;
		deleteVehicle _trigger;
	};
};
_objecttypes = nil;
};

_objecttypes is a list of "sound ids" I put in as triggerText when the triggers are created. So a radar object may have three different sounds attached to it when created, they should all be deleted when the radar is destroyed.

Using Gaia's debugger, you can try:

getPos player nearObjects ["EmptyDetector",40];

and see that it works. At least one of the other "nearObjects" related commands does not seem to find "EmptyDetector" at all. Had me puzzled for a while :)

Edited by CarlGustaffa
hint removed

Share this post


Link to post
Share on other sites

Thank you so much everyone.

I knew there was at least two ways of doing this. I often learn new stuff from the more experienced guys when they help out and this is no exception. :) Especially CG's cunning triggerText search. I never knew you could do that.

I've gone with the 'store them in an array and delete later' method that Galzohar and Muzzle suggested. This is just a couple of extra lines into existing code. Not changing working code is a good tactic.:)

My setTriggerStatements are complex. You can see I'm having to use preprocessed files to run them and that worried me about performance.

I'd love to leave the autonomous IEDs (the smaller, pressure plate ones) in place for the whole game, that'd be much more authentic, but I worry about performance. We know that Domi is hard on servers and my guys have tidied it up quite a lot, but still, it worried me. :) Perhaps, in the name of authenticity, I should make IED clearance a condition of taking the town? It would seem to be a natural extension of what we're doing.

Again, thanks to everyone. Community rox. :)

PS Thanks also to Sekra who suggested the same method.

Edited by Tankbuster

Share this post


Link to post
Share on other sites

Well if you only preprocessFile once and then use the same variable storing the same code for all triggers, then you shouldn't have performance issues... The code will only be saved in memory once and will only be read from the file once, and will only be looked at and executed when the trigger actually fires. As long as you can have one function/script that will work for all IED/types. Even with different types of IEDs, though, you can just pass a parameter to the function instead of creating multiple functions.

Share this post


Link to post
Share on other sites

Thanks Galzohar. I'll keep an eye on that. I've actually got two IED types, so have two preprocessed conditions.

Share this post


Link to post
Share on other sites

Conditions or activations? Because condition will be run every 0.5 seconds for every trigger, activations only when trigger is active, so it is a good idea to keep the condition simple, at least most of the time (as in, if there are no units in the trigger area, the condition script should do basically nothing).

Share this post


Link to post
Share on other sites

As galzohar says keep the condition simple. If you really need some complex condition and you need it in a trigger then makes wrong condition return false fast. Assume you preprocessed functions is called MyCond:

//Trigger condition

thisTrigger call MyCond

//MyCond

_trigger = _this;
if (list _trigger <= 0) exitWith {false};
if ( {[_x] call IsRunning} count (list _trigger) <= 0) exitWith {false};
//and so on at the top...

You may already be doing this though.

Share this post


Link to post
Share on other sites
Conditions or activations? Because condition will be run every 0.5 seconds for every trigger, activations only when trigger is active, so it is a good idea to keep the condition simple, at least most of the time (as in, if there are no units in the trigger area, the condition script should do basically nothing).

The condition. See the code up in post #9. Should I post the code that is preprocessed into that?

Share this post


Link to post
Share on other sites

You could post the code that goes into fnc_smallbombtrigger, but overall you just need to make sure that it quits quickly when no units are inside the trigger. If you just use a forEach loop to check the condition it should be fine since it will do nothing when the list is empty.

Share this post


Link to post
Share on other sites

Actually, I'll put fnc_bigbombtrigger. It's a more complex condition, so if this one is OK, I can probably be sure the smaller one is.

The code that I put in post 9 is for the smallbomb, the one that uses bigbomb trigger is essentially the same.

// Returns true if conditions are met to activate trigger. false if not.
// Compile somewhere: fnc_MyFunc = compile preProcessFileLineNumbers "fnc_myFunc.sqf";
#define MIN_PLAYERS 3
private ["_playerCount","_exitflag"];
_playercount = 0;
_exitflag = false;

if (d_no_more_observers) exitWith { false; };

if (d_nr_observers == 0) exitWith { false; };

{


if (_x isKindOf "Man") then 
{
	// count players within trigger	
	if (isPlayer _x) then 
	{
		_playerCount = _playerCount + 1; 
	};
} else 
{
	// is player vehicle inside trigger	
	{ 
		if (isPlayer _x) then 
		{ 
			_playerCount = _playerCount + MIN_PLAYERS; 
		} 
	} forEach (crew _x);	
};

if (_playerCount >= MIN_PLAYERS) then
{ 
	_exitflag = true; 
}; 

if ((_x selectionPosition "Neck" select 2) > 1.5) then 
{
	_exitflag = true; 
};


if ({((getposATL _x) select 2) > 5} count _this > 0) then 
{
	_exitflag = false;
}; 



if (_exitflag) exitWith {};

} forEach _this;

if (_exitflag) exitWith { true; };

false;


Share this post


Link to post
Share on other sites

Should be fine, since you only run 7 lines of code when there is nobody within the trigger.

Share this post


Link to post
Share on other sites

Yep, that's what I thought. Thanks for looking over it though. :)

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
Sign in to follow this  

×