Jump to content
Valixx

Random Objectives / Sidemissions

Recommended Posts

Instead of leaving you hanging here is my quick knock up, totally untested, I have run out of time this evening before i need to go out.

Have a look, if it has any problems, which its more than likely to have loads of stupid mistakes (hopefully kylania can chip in to help you if hes not busy this evening) , otherwise i will finish it off with some testing tomorrow.

removeTasks.sqf

//init.sqf
//call compile preprocessFileLineNumbers "removeTasks.sqf"

if (isServer) then {
//[targets, taskid] call LARs_fnc_removeTask;
LARs_fnc_removeTask = {
	_targets = [_this,0,true,[true,sideunknown,grpnull,objnull,[]]] call BIS_fnc_param;
	_taskID = [_this,1,"",[""]] call BIS_fnc_param;

	{
		_target = _x;
		switch (typeName _target) do {
			//case (typeName objNull || typeName sideUnknown || typeName [] || typeName true): {
			//	[[_taskID],"LARs_fnc_removeTaskLocal",_target,true] call BIS_fnc_MP;
			//};
			case (typeName grpNull): {
				[[_taskID],"LARs_fnc_removeTaskLocal",units _target,true] call BIS_fnc_MP;
			};
			default {
				[[_taskID],"LARs_fnc_removeTaskLocal",_target,true] call BIS_fnc_MP;
			};
		};
	} foreach [_targets];
};
};


if (!(isDedicated)) then {
//preprocess on clients
LARs_fnc_removeTaskLocal = {
	_taskID = [_this,0,"",[""]] call BIS_fnc_param;
	_taskVar = [_taskID] call BIS_fnc_taskVar;
	missionNamespace setVariable [_taskVar,nil];
	player removeSimpleTask ([_taskID,player] call BIS_fnc_taskReal);
	_playerTasks = player getVariable ["BIS_fnc_setTaskLocal_tasks",[]];
	_playerTasks = _playerTasks - [_taskID];
	player setVariable ["BIS_fnc_setTaskLocal_tasks", _playerTasks];
	_playerTaskVar = "BIS_fnc_taskvar_" + _taskID;
	player setVariable [_playerTaskVar,nil];
};
};

precompile in your init.sqf with

call compile preprocessFileLineNumbers "removeTasks.sqf"

To use, using your tasks for example

[west, "mob_arty"] call LARs_fnc_removeTask;

Share this post


Link to post
Share on other sites

Thanks for "using" your free time for me. Very much appreciated!

I'll test it tomorrow though.. and report back to you.

Again, thanks!

Share this post


Link to post
Share on other sites

Hey Larrow. I've tested it with my brother today and it works flawfless. I can't thank you enough for this.

Share this post


Link to post
Share on other sites

Excellent glad it worked ok. Your welcome.

Share this post


Link to post
Share on other sites

Hey. Sry to bother you again.

Detected another problem. If i come to the spawned crate the task is complete. If another soldier goes to the crate the task will not be updated. I have to go there..But in the code it is

waitUntil { Player distance art < 10};

Every player should do the trick no?

Here is one of the missions:

/* ==================================================================================================================

                               Create and spawn the Weapon Crate Task - Sidemission

================================================================================================================== */

fn_spawnCrateMission = {

   _smhint = "<t align='center' color='#ffffff' shadow='2' size='1.75'>Side Objective</t><br/><t align='center' color='#000000'>------------------------------</t><br/><t color='#ffffff' size='1.0'>Get to the weapon crates for more weapons and stuff.</t>";
   GlobalHint = _smhint;
   publicVariable "GlobalHint";
   hintsilent parseText _smhint;

   //creating the marker 

   _marker = createMarker ["mob_wpcr", call fn_findMissionSpot];
   _marker setMarkerType "mil_objective";
   _marker setMarkerColor "ColorRed";
   _marker setMarkerText "Weapon Crates";
   _marker setMarkerSize [1,1];

   _null = [west, "mob_wpcr", ["Get to the weapon crates for more weapons and stuff.", "Capture the Weapon Crates", "Capture the Weapon Crates"], getMarkerPos "mob_wpcr", false] spawn BIS_fnc_taskCreate;

   //creating the crates

   _veh = ["Box_NATO_Wps_F","Box_NATO_WpsSpecial_F","Box_NATO_Ammo_F","Box_NATO_AmmoOrd_F","Box_NATO_Grenades_F","Box_NATO_Support_F"] call BIS_fnc_selectRandom;

   art = createVehicle [_veh,[(getMarkerpos _marker select 0) + 30, getMarkerpos _marker select 1,0],[], 0, "NONE"];
   ensoldier = [getMarkerPos _marker, east, (configfile >> "CfgGroups" >> "East" >> "OPF_F" >> "Infantry" >> "OIA_InfTeam")] call BIS_fnc_spawnGroup;

   waitUntil { Player distance art < 10};

   deleteMarker _marker;

   _null = ["mob_wpcr", "SUCCEEDED"] spawn BIS_fnc_taskSetState;

   _myHint ="Gear up soldier!!";
   GlobalHint = _myHint;
   publicVariable "GlobalHint";
   hintsilent parseText _myHint;

   _mySChat ="Excellent work, use it to your advantage!";
   GlobalSCHat = _mySChat;
   publicVariable "GlobalSCHat";
   player sideChat _mySChat;

   sleep 5;
   [west, "mob_wpcr"] call LARs_fnc_removeTask;
   hint "";
};

Edited by Valixx

Share this post


Link to post
Share on other sites

Hi Valixx

Detected another problem. If i come to the spawned crate the task is complete. If another soldier goes to the crate the task will not be updated. I have to go there..But in the code it is

PHP Code:

waitUntil { Player distance art < 10};

Every player should do the trick no?

I always thought it was wierd that you were using player in some places in the script.

Im presuming the mission selection is all handled server side and that when you are playing on lan with your brother you are hosting the mission rather than using a dedicated server??

So player will not do, as you are hosting your machine is both server and a client (player) that is why it works for you.

Your missions

_null = [west, "mob_wpcr", ["Get to the weapon /*snip spawn BIS_fnc_taskCreate;

and the code i wrote to delete them work for everyone as those function do it for a selection (west) of all connected clients.

You will need to work out the code of what completes the mission, so its not just is the player close to item but are any WEST (said west as you are giving the mission to all players on the WEST side e.g [west, "mob_wpcr",). So maybe a while loop that checks all west units distance to the objective.

//set a default variable to change for mission status
_missionDone = false;
//while the mission is not done
while {!(_missionDone)} do {
//loop around all playable units (playable is human and AI that are in a slot in the lobby)
{
	//if any of playable are within the distance
	if ((_x distance art) < 10) then {
		//set mission as done (while loop will now finish
		_missionDone = true;
	};
}foreach playableUnits;
//trigger check their condition every 0.5 so this is similar 
sleep 0.5;
};

The above is tailored to your specific setup as you are only playing west (all clients are west side versus AI on the east??), if your were playing another side or had only given the quest to certain individuals then you would need to change this to only check who you need.

Edited by Larrow

Share this post


Link to post
Share on other sites

Hey Larrow, thanks for your answer.

Currently i'm testing the mission on lan with my brother. Once my mission is finished, it will be hosted on my server ( see signature ) hosted by nitrado.net. I'm currently working on the mission for over 2 weeks straight now. Wouldn't be far without you and kylania :P Yep, we are are west versus east.

So.. instead of player in my scripts i could use west / playableUnits?

Share this post


Link to post
Share on other sites
So.. instead of player in my scripts i could use west / playableUnits?
A hesitant yes.

playableunits = all units in a slot in the lobby including any AI, (AI maybe currently using a slot because AI is on in the lobby and no player has taken the slot)

If your scenario is always going to be the same e.g players are only ever going to be west and all players are assigned the task e.g _null = [west, "mob_wpcr",

west here meaning all west players are given the task then yes playableunits will be good enough for you to check against.

Just replace your current line checking against the player with the code in my last post.

Share this post


Link to post
Share on other sites

Thank you Larrow.

I've disabled the AI and the players will always be Blufor. I'll do the change in the code tomorrow. 11PM now and i have to get up early.. Thanks again, it's a big help!

Share this post


Link to post
Share on other sites

Hey. Got a little question.

//set a default variable to change for mission status
_missionDone = false;
//while the mission is not done
while {!(_missionDone)} do {
   //loop around all playable units (playable is human and AI that are in a slot in the lobby)
   {
       //if any of playable are within the distance
       if ((_x distance art) < 10) then {
           //set mission as done (while loop will now finish
           _missionDone = true;
       };
   }foreach playableUnits;
   //trigger check their condition every 0.5 so this is similar 
   sleep 0.5;
};

I spawn two enemy infantry groups. What should i change in "if ((_x distance art) < 10)" to "if enemies are dead or no enemie in area"? I hope you can help me out here.

Cheers,

Valixx

Share this post


Link to post
Share on other sites

Something like

{{alive _x && (_x distance myArea < areaSize)}count units _x == 0}count [AIGroup1, AIGroup2] == 2

Where myArea is the position of your mission marker, areaSize is the radius, AIGroup1/2 are your spawned AI groups.

Is true, if 0 (none) of the units are alive and in the area, for both groups.

Share this post


Link to post
Share on other sites

Thanks larrow.

---------- Post added at 10:48 ---------- Previous post was at 10:01 ----------

_trg = createTrigger ["EmptyDetector", getMarkerPos _marker];
_trg setTriggerArea [200, 200, 0, false];
_trg setTriggerActivation ["EAST", "NOT PRESENT", false];
_trg setTriggerStatements ["this", "_enemyDead = true;", ""];

_enemyDead = false;
while {!(_enemyDead)} do {
  {
      if (/*what should i put here to check the trigger?*/) then {
          _enemyDead = true;
      };

  } foreach playableUnits;
  sleep 0.5;
};

deleteMarker _marker;

_null = ["mob_infa", "SUCCEEDED"] spawn BIS_fnc_taskSetState;

I know i have something wrong here but can't figure it out. Studying web-design, learning sqf at the same time..... i'm going nuts..

Edited by Valixx

Share this post


Link to post
Share on other sites

You have a local variable in the trigger. Change that to global and public variable it when you set it.

Share this post


Link to post
Share on other sites

There are two possibilities here.

1. TRIGGERS: I see in the snippet of code you have shown above that you have a trigger set up and your trying to set a variable in the trigger statement that will satisfy the condition of your while loop. As the code in the trigger statement is not run in the same scope as your script, using the local variable _enemyDead is not going to work.

We can split this into four workable options. Hey having options is always good :D

1a.

_trg = createTrigger ["EmptyDetector", getMarkerPos _marker];
_trg setTriggerArea [200, 200, 0, false];
_trg setTriggerActivation ["EAST", "NOT PRESENT", false];
_trg setTriggerStatements ["this", "enemyDead = true;", ""];

enemyDead = false;
waitUntil {!(enemyDead)};

deleteMarker _marker;

_null = ["mob_infa", "SUCCEEDED"] spawn BIS_fnc_taskSetState;  

Here we have turned the variable set in the trigger statement into a global variable which can now be checked by your script. Only down side here is what if you wanted to spawn two of these types of mission at the same time! the global variable enemyDead is now going to conflict between the two missions.

1b.

_trg = createTrigger ["EmptyDetector", getMarkerPos _marker];
_trg setTriggerArea [200, 200, 0, false];
_trg setTriggerActivation ["EAST", "NOT PRESENT", false];
_trg setTriggerStatements ["this", "", ""];

enemyDead = false;
waitUntil {triggerActivated _trg};

deleteMarker _marker;

_null = ["mob_infa", "SUCCEEDED"] spawn BIS_fnc_taskSetState;  

Here we use a trigger to whittle down to the option we require e.g (EAST, NOT PRESENT, false). Then in script check for the trigger activation to advance our script.

1c.

_trg = createTrigger ["EmptyDetector", getMarkerPos _marker];
_trg setTriggerArea [200, 200, 0, false];
_trg setTriggerActivation ["ANY", "PRESENT", true];

_enemyDead = false;
while {!(_enemyDead)} do {
_triggerContents = list _trg;
if ({side _x == opfor} count _triggerContents == 0) then {
	_enemyDead = true;
};
};

deleteMarker _marker;

_null = ["mob_infa", "SUCCEEDED"] spawn BIS_fnc_taskSetState; 

In this example we use a simple trigger continuously monitoring for anything. Then in script we get a reference to what is in the trigger by using the command list and use script to whittle down the options we want, which in this case we count everything that is in the triggers list that is side opfor, if this equals 0 we know there are no opfor in the trigger. Remember you could put extra checks in here, as written above if there was a opfor vehicle with three men in it the count is only going to return 1 as the men are seen as being part of the vehicle.

2. MANUALLY checking the area: This is what my previous post was referencing. I was being lazy and already knew from your previous posts that you had a mission marker so did not want to explain trigger options at the time :D.

waitUntil {{{alive _x && (_x distance _marker < 200)}count units _x == 0}count [AIGroup1, AIGroup2] == 2};

deleteMarker _marker;

_null = ["mob_infa", "SUCCEEDED"] spawn BIS_fnc_taskSetState;

Wait until none of the units from AIGroup1 or 2 are alive and within 200 meters of _marker, then then continue on with the script.

There are other options to not using a trigger aswell, for instance you could use nearEntities along with the position of you marker and a radius to get a list of things back that you could whittle down using iskindof and side etc but i think thats enough examples for now and should give you a good idea of how to get pretty much anything your looking for in your areas.

BTW all these option are written as a copy & paste to replace everything that you wrote in your last post.

//Disclaimer: untested and may contain silly mistakes, but i have used all these options before in one way or another, so should be good to go.

---------- Post added at 13:56 ---------- Previous post was at 13:42 ----------

and public variable it when you set it.
No need for the PV, from what ive read of this thread this is all happening server side. Trigger will be created server side and global variable will be on the server, logic is all checked server side and task given out by the BIS_fnc_MP in the task functions.

Share this post


Link to post
Share on other sites

Oh man, that's a huge help. Can't thank you enough for this! 1a and 1b are looking so easy... I'm still confused that i didn't get this on my own :butbut:

Share this post


Link to post
Share on other sites

if ({side _x == opfor} count _triggerContents == 0) then {

I've seen syntax like this a few times now in this thread. Does this actually work as it doesn't seem to make sense to me at all. It looks like what you are trying to do is count the number of opfor in the triggerContents array/list and if 0 then if statement is true. But I don't see how that would do it with that syntax. I've never used an iteration like that with _x in that manner.

Share this post


Link to post
Share on other sites

_x works with count just like it does with forEach, it just counts instead of just iterates. :)

Share this post


Link to post
Share on other sites
It looks like what you are trying to do is count the number of opfor in the triggerContents array/list and if 0 then if statement is true. But I don't see how that would do it with that syntax.
Thats exactly what it is doing.

CODE count ARRAY

For each index of the array the code is evaluated, if the code is true then 1 is added to the total count.

Say you wanted to know atleast 1 unit was alive out of a list of units, you could

_numberOfAliveUnits = 0;

{
if (alive _x) then {
	_numberOfAliveUnits = _numberOfAliveUnits + 1;
};
} forEach [unit1, unit2, unit3];

if (_numberOfAliveUnits > 0) then {
       hint "someone is alive";
};

or

if ( { alive _x } count [unit1, unit2, unit3] > 0 ) then {
       hint "someone is alive";
}

I know which one id rather type out and keep track of :)

Edited by Larrow

Share this post


Link to post
Share on other sites

Quick question: To name a group, you go to the group leader's init box and type: groupname = group this; ? And then you can call it with your code above.

Share this post


Link to post
Share on other sites
Thats exactly what it is doing.

Cool. Never ran across this syntax before. It is handy!!

Share this post


Link to post
Share on other sites
To name a group, you go to the group leader's init box and type: groupname = group this; ?
You can do, yes. groupname is now a global variable holding a reference to the group.
And then you can call it with your code above.
Yes, with a slight change as you would want to count through an array of the units of groupname.
if ( { alive _x } count (units groupname) > 0 ) then {
       hint "someone is alive";
}  

Share this post


Link to post
Share on other sites
Gread idea Delta99, here it is with SHK_Pos and a few changes.

init.sqf:

call compile preprocessfile "SHK_pos\shk_pos_init.sqf";
call compile preprocessfile "globaltools.sqf";

globalTools.sqf:

//ENABLE GLOBAL HINT from Occupation by BangaBob
"GlobalHint" addPublicVariableEventHandler
{private ["_GHint"];_GHint = _this select 1;hint parseText format["%1", _GHint];
};

"GlobalSideChat" addPublicVariableEventHandler
{private ["_GSChat"];_GSChat = _this select 1;player sideChat _GSChat;
};

missionFinder.sqf:

//Mission Select
if(!isServer) exitWith {};

//waituntil {!isnil "bis_fnc_init"}; //waiting

_missions = ["arty","harrier","tank","heli","truck","c130wreck"]; //mission array

//_choose = _missions call BIS_fnc_selectRandom; // random mission 
_choose = "arty";
[_choose] execVM "makemission.sqf";  //call mission

missionMaker.sqf:

// Mission

_missionType = [_this, 0, ""] call BIS_fnc_param;

sleep random 15;

fn_findMissionSpot = {

private ["_mapCenter"];
_mapCenter = getArray (configFile >> "CfgWorlds" >> worldName >> "centerPosition");
[_mapCenter, random 4000, random 360, false] call SHK_pos;

};

fn_spawnArtyMission = {

hint "Capture the Artillery First!!!";
//creating the marker 

_marker = createMarker ["Mobile Artillery", call fn_findMissionSpot];
_marker setMarkerType "mil_destroy";
_marker setMarkerColor "ColorRed";
_marker setMarkerText "Mobile Artillery";
_marker setMarkerSize [1,1];

//creating the vehicle

_veh = ["B_MRAP_01_F","B_MRAP_01_F"] call BIS_fnc_selectRandom;

art = createVehicle [_veh,[(getMarkerpos _marker select 0) + 30, getMarkerpos _marker select 1,0],[], 0, "NONE"];
art setFuel 1;
art setVehicleAmmo 1;

waitUntil { Player distance art < 20};

deleteMarker _marker;

_myHint ="Destroy some stuff soldier!!";
GlobalHint = _myHint;
publicVariable "GlobalHint";
hintsilent parseText _myHint;

_mySChat ="Excellent work, use it to your advantage!";
GlobalSCHat = _mySChat;
publicVariable "GlobalSCHat";
player sideChat _mySChat;

sleep 3;
hint "";
};

// MAIN LOGIC

_missionDetails = switch (_missionType) do {
case "arty": {call fn_spawnArtyMission;};
};	

nul = [] execVM "missionfinder.sqf";

Do i need to add any markers?

Share this post


Link to post
Share on other sites

Not for that, it'll create it's own. Due to JIP issues though you might wanna just have a mission marker on the map already and just move it maybe?

Share this post


Link to post
Share on other sites

i was wondering why nothing was spawning

---------- Post added at 21:25 ---------- Previous post was at 20:41 ----------

do you have a test mission

Share this post


Link to post
Share on other sites

Here's a test mission. 0-0-1 to start the missions spawning. 0-0-2 to teleport to the mission. Walk towards the vehicle to complete the mission and spawn another.

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

×