# Race Circuit Script (aka learning to count)

## Recommended Posts

This topic is solved.

Clear courses by reaching the next marker.

If you're looking for the module it's available here: Drive Link

This is the test rig in the demo. Adding new marks and whole new courses is easy.

From here on is the original topic,

I need to learn how to count.

I posted this the other day,

Spoiler
```
//challenge 2
ringChallenge2 = [] spawn {

waitUntil {
ringCHALL==1
};

if (ring6==1) then{
currentRING= [ringMARK2_1,ringMARK2_2,ringMARK2_3,ringMARK2_4, ringMARK2_5, ringMark2_6] select 5;

sleep 0.2;
ringGOAL_1 setpos (getpos currentRING);
ring6=0;
ring1=1;
terminate rings2;
};
};

if (ring5==1) then{
currentRING= [ringMARK2_1,ringMARK2_2,ringMARK2_3,ringMARK2_4, ringMARK2_5, ringMark2_6] select 4;

sleep 0.2;
ringGOAL_1 setpos (getpos currentRING);
ring5=0;
ring6=1;
terminate rings2;
};

if (ring4==1) then{
currentRING= [ringMARK2_1,ringMARK2_2,ringMARK2_3,ringMARK2_4, ringMARK2_5, ringMark2_6] select 3;

sleep 0.2;
ringGOAL_1 setpos (getpos currentRING);
ring4=0;
ring5=1;
terminate rings2;
};

if (ring3==1) then{
currentRING= [ringMARK2_1,ringMARK2_2,ringMARK2_3,ringMARK2_4, ringMARK2_5, ringMark2_6] select 2;

sleep 0.2;
ringGOAL_1 setpos (getpos currentRING);
ring3=0;
ring4=1;
terminate rings2;
};

if (ring2==1) then{
currentRING= [ringMARK2_1,ringMARK2_2,ringMARK2_3,ringMARK2_4, ringMARK2_5, ringMark2_6] select 1;

sleep 0.2;
ringGOAL_1 setpos (getpos currentRING);
ring2=0;
ring3=1;
hint"";
terminate rings2;
};

if (ring1==1) then{
hint "Go!";
playergroup = group Player;
deleteWaypoint [playergroup, 0];
currentRING= [ringMARK2_1,ringMARK2_2,ringMARK2_3,ringMARK2_4, ringMARK2_5, ringMark2_6] select 0;
sleep 0.2;
ringGOAL_1 setpos (getpos currentRING);
ringGOAL_1 hideobject FALSE;
ring2=1;
ring1=0;
terminate rings2;
};
```

with a plea to understand why it works when, in my estimation, it shouldn't really.

Regardless. I set about to simplify ring counting. I don't like having one .sqf file for each ring course. I feel like 1 or 2 scripts should be able to do this.

One file if somebody helps me to learn how to count. Two if this works:
Determine which course and define ring marks with generic titles,
ringCOURSE.sqf-- this example shows 2 courses with 3 rings each

```if (ringCHALL==1) then {
ring1=ringMARK1_1;
ring2=ringMARK1_2;     //first course second mark
ring3=ringMARK1_3;
rings= []execVM "ringCLEAR.sqf";
};

if (ringCHALL==2) then {
ring1=ringMARK2_1;
ring2=ringMARK2_2;    //second course second mark
ring3=ringMARK2_3;
rings= []execVM "ringCLEAR.sqf";
};```

and then build a switchdo case for each ring, or a waitUntil loop, or...
I don't know and that's the question.

Keep in mind there is only one ring with one trigger attached to drive the ring clearing script(s).
This is what it needs to do,

```    ["task1",[currentRING,true]] call BIS_fnc_taskSetDestination;
ringGOAL_1 setpos (getpos currentRING);
```

The real trick in this is how to go from: ring1, ring2, ring3, to set the variable "currentRING" in sequence.

Oh, boy! I hope that makes sense!

• 1

##### Share on other sites
12 minutes ago, wogz187 said:

I need to learn how to count.

I posted this the other day,

Hide contents
```

//challenge 2
ringChallenge2 = [] spawn {

waitUntil {
ringCHALL==1
};

if (ring6==1) then{
currentRING= [ringMARK2_1,ringMARK2_2,ringMARK2_3,ringMARK2_4, ringMARK2_5, ringMark2_6] select 5;﻿

sleep 0.2;
ringGOAL_1 setpos (getpos currentRING);
ring6=0;
ring1=1;
terminate rings2;
};
};

if (ring5==1) then{
currentRING= [ringMARK2_1,ringMARK2_2,ringMARK2_3,ringMARK2_4, ringMARK2_5, ringMark2_6] select 4;

sleep 0.2;
ringGOAL_1 setpos (getpos currentRING);
ring5=0;
ring6=1;
terminate rings2;
};

if (ring4==1) then{
currentRING= [ringMARK2_1,ringMARK2_2,ringMARK2_3,ringMARK2_4, ringMARK2_5, ringMark2_6] select 3;

sleep 0.2;
ringGOAL_1 setpos (getpos currentRING);
ring4=0;
ring5=1;
terminate rings2;
};

if (ring3==1) then{
currentRING= [ringMARK2_1,ringMARK2_2,ringMARK2_3,ringMARK2_4, ringMARK2_5, ringMark2_6] select 2;

sleep 0.2;
ringGOAL_1 setpos (getpos currentRING);
ring3=0;
ring4=1;
terminate rings2;
};

if (ring2==1) then{
currentRING= [ringMARK2_1,ringMARK2_2,ringMARK2_3,ringMARK2_4, ringMARK2_5, ringMark2_6] select 1;

sleep 0.2;
ringGOAL_1 setpos (getpos currentRING);
ring2=0;
ring3=1;
hint"";
terminate rings2;
};

if (ring1==1) then{
hint "Go!";
playergroup = group Player;
deleteWaypoint [playergroup, 0];
currentRING= [ringMARK2_1,ringMARK2_2,ringMARK2_3,ringMARK2_4, ringMARK2_5, ringMark2_6] select 0;
sleep 0.2;
ringGOAL_1 setpos (getpos currentRING);
ringGOAL_1 hideobject FALSE;
ring2=1;
ring1=0;
terminate rings2;
};
```

with a plea to understand why it works when, in my estimation, it shouldn't really.

Regardless. I set about to simplify ring counting. I don't like having one .sqf file for each ring course. I feel like 1 or 2 scripts should be able to do this.

One file if somebody helps me to learn how to count. Two if this works:
Determine which course and define ring marks with generic titles,
ringCOURSE.sqf-- this example shows 2 courses with 3 rings each

```
if (ringCHALL==1) then {
ring1=ringMARK1_1;
ring2=ringMARK1_2;     //first course second mark
ring3=ringMARK1_3;
rings= []execVM "ringCLEAR.sqf";
};

if (ringCHALL==2) then {
ring1=ringMARK2_1;
ring2=ringMARK2_2;    //second course second mark
ring3=ringMARK2_3;
rings= []execVM "ringCLEAR.sqf";
};```

and then build a switchdo case for each ring, or a waitUntil loop, or...
I don't know and that's the question.

Keep in mind there is only one ring with one trigger attached to drive the ring clearing script(s).
This is what it needs to do,

```
ringGOAL_1 setpos (getpos currentRING);
```

The real trick in this is how to go from: ring1, ring2, ring3, to set the variable "currentRING" in sequence.

Oh, boy! I hope that makes sense!

Well this doesn't make sense:
currentRING= [ringMARK2_1,ringMARK2_2,ringMARK2_3,ringMARK2_4, ringMARK2_5, ringMark2_6] select 5;

`currentRING= [ringMARK2_1,ringMARK2_2,ringMARK2_3,ringMARK2_4, ringMARK2_5, ringMark2_6] select 5;`

Why not simply use currentRing = ringMark2_6? Will never change.

ringChall is also nowhere defined, maybe another script outside?

You could use deleteAt, which I always forget, returns the deleted element could be set up like this:

```YourRings = [ringMARK2_1,ringMARK2_2,ringMARK2_3,ringMARK2_4, ringMARK2_5, ringMark2_6];

currentRing = YourRings deleteAt (count YourRings -1);//first execution returns ringMark2_6
currentRing = YourRings deleteAt (count YourRings -1);//second execution returns ringMARK2_5
currentRing = YourRings deleteAt (count YourRings -1);//third execution returns ringMARK2_4
//etc.```

If that's what you're after.

Also not sure about your usage of terminate, since it's always preferred to end scripts the proper way instead of terminating them.

You can use exitWith to exit while true loops, or even better use variables to control loop execution like this:

```//not ideal
_stuff = [] spawn {
while {true} do {
sleep 1;
//stuff
};
};
terminate _stuff;

//exit spawned loop on condition
_stuff = [] spawn {
while {true} do {
sleep 1;
if (something) exitWith {false};
//stuff
};
};

//stop looping on condition
_stuff = [] spawn {
while {something} do {
sleep 1;
//stuff
};
};```

Might work fine for more basic stuff but terminating more complex scripts might lead to issues depending on what that script does etc.

If you want to run multiple ring courses with individual rings you can also use an abstract function, define the rings and courses as nested arrays and simply call the same function for every course:

```
TAG_fnc_ringCourse = {
params ["_courseID","_rings","_ringGoal"];

hint format ["Starting Ring %1!\nGo!",_courseID];
playergroup = group Player;
deleteWaypoint [playergroup, 0];

{
sleep 0.2;
_ringGoal setpos (getpos _x);
_ringGoal hideobject FALSE;
} forEach _rings;

_courseID = _courseID +1;
_courseID//_courseID will increment by one so you can automate the next courseID if needed
};

_handleRing = [1,[ringMARK2_1,ringMARK2_2,ringMARK2_3,ringMARK2_4, ringMARK2_5, ringMark2_6],ringGOAL_1] spawn TAG_fnc_ringCourse;```

Cheers

• 2
• 1

##### Share on other sites

@Grumpy Old Man,

You know how you said you don't understand why I did a bunch of stuff in the script above? It's because I don't know either.

I knew enough to ask for help.

Thanks. That's exactly what I needed. I'll report back here when it's all done.

• 2

##### Share on other sites

@Grumpy Old Man
I'll actually answer some of these questions to demonstrate my failing logic:

`currentRING= [ringMARK2_1,ringMARK2_2,ringMARK2_3,ringMARK2_4, ringMARK2_5, ringMark2_6] select 5;`
Quote

Why not simply use currentRing = ringMark2_6? Will never change.

ringChall is also nowhere defined, maybe another script outside?

I was building in a contingency for when I learned how to count. This way select could be defined by a growing number, like _x.
Yes, ringChall is determined by a large trigger that contains each course. So ringChall==1 is ring course 1 and ringChall==2 is ring course 2.

Quote

Obviously neither am I. In this case the execVM loaded by the ring trigger is: rings= []execVM "ringCLEAR.sqf". I terminate "rings" each time to ensure the script isn't running multiple instances. Simply a byproduct of my not having even the faintest clue how to do this. Perhaps instead of multiple instances I should say that I wanted the script to always start from the beginning. Basically, I don't know how execVM works.

This is beautiful, what I imagined in the first place but couldn't create. Thanks again, GOM.

Quote

TAG_fnc_ringCourse =
{
params ["_courseID","_rings","_ringGoal"];

hint format ["Starting Ring %1!\nGo!",_courseID];

_ringGoal setpos (getpos _x);

} forEach _rings;

_courseID = _courseID +1; _courseID//_courseID will increment by one so you can automate the next courseID if needed
};

_handleRing = [1,[ringMARK2_1,ringMARK2_2,ringMARK2_3,ringMARK2_4, ringMARK2_5, ringMark2_6],ringGOAL_1] spawn TAG_fnc_ringCourse;

But I still don't understand it.

##### Share on other sites

@Grumpy Old Man
I called this,
ringcourse.sqf

```_courseID = ringCHALL;
_rings = [ringMARK1_1, ringMARK1_2, ringMARK1_3];
_ringGoal= ringGOAL;

FTA_fnc_ringCourse = {
params ["_courseID","_rings","_ringGoal"];

hint format ["Starting Ring %1!\nGo!",_courseID];

{
_ringGoal setpos (getpos _x);
} forEach _rings;

};

_handleRing = [1,[ringMARK1_1,ringMARK1_2,ringMARK1_3],ringGOAL] spawn FTA_fnc_ringCourse;```

and execute it in a trigger attached to the goal ring.

It just snaps to the final position when triggered. Likely due to my not having set it up correctly.
This is how I'm testing in VR,

It needs to repeat until the player exits the area.

##### Share on other sites

So you need to move the task marker every 0.2 seconds between each ring?

Could switch the forEach loop to this:

```while {player inArea YourTriggerName} do {
{
_ringGoal setpos (getpos _x);
sleep 0.2;
} forEach _rings;
};```

Many ways to set this up though, depends on what you're actually trying to do.

Cheers

• 1

##### Share on other sites
Quote

So you need to move the task marker every 0.2 seconds between each ring?

Not really. The pause was to make sure the variable had time to switch after the player hit the trigger. The basic function is: every time player hits trigger (ringGOALtrig), the model (ringGOAL) moves to the next position. The trigger is attached to the ring model. This has to happen repeatedly in a circuit.

Ideally there is only one ring and trigger to service the several ring courses, each of which is defined by: 1 large trigger containing the whole course (assigns value to ringCHALL to determine which of several courses player flew into) and 6 markers to denote the ring positions.

In the test rig above I have written this init,

```ringGOAL setpos (getpos objNULL);

ringCHALL=0;

FTA_fnc_ringCourse = {
params ["_courseID","_rings","_ringGoal"];

{
_ringGoal setpos (getpos _x);
sleep 0.5;
} forEach _rings;

};```

the half second pause allows me to see the markers are going around the circuit but automatically and terminally.
The "_handleRING =spawn" is in ringGOALtrig and the script should just step ahead every time it's activated.

I need the ring to stop at each point. And the course to reset to 1 after 3.

Thanks again for looking at this with me.

##### Share on other sites

So if I got it right you got 6 markers (per course?) and need to move an object to the next marker when a player is close to it?

Could look like this:

```
//init.sqf or initPlayerLocal.sqf
_course1 = ["ringMARK1_1","ringMARK1_2","ringMARK1_3","ringMARK1_GOAL"];
_course2 = ["ringMARK2_1","ringMARK2_2","ringMARK2_3","ringMARK2_GOAL"];
_course3 = ["ringMARK3_1","ringMARK3_2","ringMARK3_3","ringMARK3_GOAL"];
TAG_courses = [_course1,_course2,_course3];
TAG_currentCourse = 0;//because arrays start at 0
TAG_ringID = 0;
TAG_ringObject = test;//your object that will be moved to the current ring

_currentRing = (TAG_courses#(TAG_currentCourse)#TAG_ringID);

if (vehicle player distance TAG_ringObject < 5) then {
TAG_ringID = TAG_ringID + 1;
TAG_ringObject setPos getMarkerPos (TAG_courses#(TAG_currentCourse)#TAG_ringID);
if (_currentRing find "GOAL" >= 0) then {
TAG_ringID = 0;
TAG_currentCourse = TAG_currentCourse + 1;
}
};
hintSilent format ["Active Course: %1\nCurrent Ring: %2",TAG_currentCourse+1,TAG_ringID+1];
}];```

As a quickly thrown together example, this will go through all rings and courses upon completion, control object will be moved to the next marker and will be used for a distance check of the player, using an EachFrame EH for precision.

Still needs a check for final course, can be done similar to find "GOAL", should get you started.

Cheers

• 1

##### Share on other sites

@Grumpy Old Man,
Thanks again!

It's an efficient looking script. I think I understand most of it at this point but I get "generic error in expression".
1) I added the missing elements to my test rig (the other test markers) so no errors from missing references.
2) I changed "test" to "ringGOAL" as per the comment
3) I pasted into init.sqf

Check this out,

```_course1 = ["ringMARK1_1","ringMARK1_2","ringMARK1_3","ringMARK1_GOAL"];//I added the ringMARK_goal objects to test rig
_course2 = ["ringMARK2_1","ringMARK2_2","ringMARK2_3","ringMARK2_GOAL"];
_course3 = ["ringMARK3_1","ringMARK3_2","ringMARK3_3","ringMARK3_GOAL"];
TAG_courses = [_course1,_course2,_course3];
TAG_currentCourse = 0;
TAG_ringID = 0;
TAG_ringObject = ringGOAL;// the object that moves

_currentRing = (TAG_courses#(TAG_currentCourse)#TAG_ringID);// I don't know how this syntax works. Does it look for the first number in that variable?

if (vehicle player distance TAG_ringObject < 5) then {
TAG_ringID = TAG_ringID + 1;
TAG_ringObject setPos getMarkerPos (TAG_courses#(TAG_currentCourse)#TAG_ringID); // there are no markers, used arrow objects can (getpos currentRING) do?
if (_currentRing find "GOAL" >= 0) then { //I don't understand where we determine "GOAL"
TAG_ringID = 0;
TAG_currentCourse = TAG_currentCourse + 1;
}
};
hintSilent format ["Active Course: %1\nCurrent Ring: %2",TAG_currentCourse+1,TAG_ringID+1];
}];```

I added a few comments where I'm stuck. I'm not sure what is causing the error.

##### Share on other sites

_currentRing = (TAG_courses#(TAG_currentCourse)#TAG_ringID);// I don't know how this syntax works. Does it look for the first number in that variable?
# is another way for select

TAG_ringObject setPos getMarkerPos (TAG_courses#(TAG_currentCourse)#TAG_ringID); // there are no markers, used arrow objects can (getpos currentRING) do?

GOM supposed you did, or will do (see post).

If you don't want to add markers, just use your triggers (those for course). IMHO, you just have to add the next position of the ring (next trigger position) in the activation field of the current trigger. You don't need anything else.

##### Share on other sites

@Grumpy Old Man,

I simplified this for my test rig and my own understanding.
This does what I want except the variable "TAG_ringID" returns an error at the final step and refuses to go further.

```ringChallenge = [] spawn {
waitUntil {
sleep 0.5;
(vehicle player distance ringOBJ < 3)
};

TAG_ringID = TAG_ringID + 1;
currentRING= [ringMARK1_GOAL,ringMARK1_1,ringMARK1_2,ringMARK1_3] select TAG_ringID;

ringOBJ setPos (getpos currentRING);

if (currentRING==ringMARK1_GOAL) then {
TAG_ringID=0;
};
};

execVM "ringCLEAR.sqf";```
Quote

If you don't want to add markers, just use your triggers (those for course). IMHO, you just have to add the next position of the ring (next trigger position) in the activation field of the current trigger. You don't need anything else.

The easy way would be to place rings with triggers all over the map but it's sooo-super-ugly. Right now there is only one big trigger per course, six arrow helpers to mark the potential ring positions per course and a single ring to drive the whole thing. I think, despite GOM's excellent help, I'll probably have to use two scripts. A table of cases to define the different routes and the script above to drive the ring.

Man, if you can tell me how to do it better, I'm literally comprised of ears at the molecular level.

##### Share on other sites

This works for my purpose,

```ringChallenge = [] spawn {
waitUntil {
sleep 0.5;
(vehicle player distance ringOBJ < 3)
};

TAG_ringID = TAG_ringID + 1;
currentRING= [ringMARK1_GOAL,ringMARK1_1,ringMARK1_2,ringMARK1_3] select TAG_ringID;

ringOBJ setPos (getpos currentRING);

if (TAG_ringID == 3) then {
TAG_ringID = 0;
};

};

execVM "ringCLEAR.sqf";```

It'll take a bit more tinkering to get the other courses incorporated but this repeatedly goes around the circuit with no errors.

EDIT: Not quite, eventually returns a zero-divisor error. Tried terminating the script before restarting at the bottom and that worked.

##### Share on other sites

CNL

Just a question: can you see your arrows while in air? They seem to me very small.

##### Share on other sites
Quote

Just a question: can you see your arrows while in air? They seem to me very small.

You totally can't. The arrows are set to hide, they are just helpers to show the ring where to appear. The ring, thankfully, is enormous and highly visible.

This is still not totally solved but it's better than it was. I wrote cases for the different courses last night which precedes the ring clear script.

```switch (ringCHALL) do
{
case 1:
{

hint " Ring Challenge Activated! Fly through the first ring near the observatory to begin the ring course";
ringTRIGmock setpos (getpos ringMARK1_GOAL);

ringOBJ setPos (getPos ringMARK1_GOAL);

rings=[]execVM "ringCLEAR.sqf";
};
case 2:
{

hint " Ring Challenge Activated! Fly through the first ring in the valley to begin the ring course";

ringTRIGmock setpos (getpos ringMARK2_GOAL);

ringOBJ setPos (getPos ringMARK2_GOAL);

rings=[]execVM "ringCLEAR2.sqf";
};
case 3:
{

hint " Ring Challenge Activated! Fly through the first ring near central valley to begin the ring course";
ringTRIGmock setpos (getpos ringMARK3_GOAL);

ringOBJ setPos (getPos ringMARK3_GOAL);

rings=[]execVM "ringCLEAR3.sqf";
};
case 4:
{

hint " Ring Challenge Activated! Fly through the first ring at the peak to begin the ring course";
ringTRIGmock setpos (getpos ringMARK4_GOAL);

ringOBJ setPos (getPos ringMARK4_GOAL);

rings=[]execVM "ringCLEAR4.sqf";
};
case 0:
{
ringchall=0;

hint "";

ringOBJ setPos (getPos locationNULL);

ringTRIGmock setpos (getpos objNULL);
terminate rings;
};
};```

I made this complicated in the first place by deciding not to use multiple rings. It could have been so easy...

##### Share on other sites

Yes, a little bit. It's same as:

```_hintLoc = [""," near the observatory "," in the valley "," near central valley "," at the peak "];
_ringScript = scriptNull;
if (ringChall !=0) then {
_ring = call compile format ["ringMARK%1_GOAL",ringChall];
hint format [" Ring Challenge Activated! Fly through the first ring%1to begin the ring course";rigChall];
{_x setpos getpos _ring} forEach [ringTRIGmock,ringOBJ];
_ringScript=[]execVM format ["ringCLEAR%1.sqf",ringChall];
} else {
["task1",[objNULL,false]] call BIS_fnc_taskSetDestination;   // you could delete task if you don't somewhere... and recreate it with trigger
ringOBJ setPos [0,0,0];
ringTRIGmock setpos [0,0,0];
terminate _ringScript;  // not sure it's useful . depending on your script. Probably already terminated
};```

• 1

##### Share on other sites
```_hintLoc = [""," near the observatory "," in the valley "," near central valley "," at the peak "];
_ringScript = scriptNull; ```

I was working on doing this for the whole mod so I can use hint format throughout. Thanks!

`if (ringChall !=0) then { _ring = call compile format ["ringMARK%1_GOAL",ringChall]; `

So if ringCHALL is not 0 it defines ringMARK1_GOAL as the current position?
For clarity: ringCHALL 1 is equal to ring course 1. ringCHALL 2 is equal to ring course 2.

Quote

hint format [" Ring Challenge Activated! Fly through the first ring%1to begin the ring course";rigChall];

Like I said, I was already implementing this. I'm so glad I chose to do something correctly!

```{_x setpos getpos _ring} forEach [ringTRIGmock,ringOBJ];
_ringScript=[]execVM format ["ringCLEAR%1.sqf",ringChall]; ```

Because of the way GOM set it up for me, there is no trigger necessary for the ring. The object itself is the trigger. ringTRIGmock literally says "GO!", at the first ring and that's it.
I love how you define the ringCLEAR script with the %1. Ideally, eventually, there will only be one script to handle all 4-5 courses.
}

```else { ["task1",[objNULL,false]] call BIS_fnc_taskSetDestination; // you could delete task if you don't somewhere... and recreate it with trigger ringOBJ setPos [0,0,0]; ringTRIGmock setpos [0,0,0];
terminate _ringScript; // not sure it's useful . depending on your script. Probably already terminated﻿
```

The same task is used constantly throughout the mission. It just goes to objNULL when not in use. You use "setpos [0,0,0];﻿" to accomplish the same?
As for terminating. Without termination in the ringCLEAR script it eventually returns zero divisor error. This ensures the process isn't running anymore after the player flies away.

Thanks, man. I can definitely use this.

##### Share on other sites

objectNull and locationNull have always [0,0,0] as position.

If your ringCLEARX.sqf (btw I'd write only one, why several?) is short in term of execution (without sleep 30000, you see what I mean), the terminate is useless because your script will not last  more than the sum of sleeping time(s) + all codes (during ms) So, I'm not sure you have to terminate it during the flight (even with extraterrestrial jet)

_ring = call compile format ["ringMARK%1_GOAL",ringChall]

means: ringMARK2_GOAL for ringChall = 2  so depending on ringChall value.

In this case(2):

["ringMARK%1_GOAL",ringChall]  // returns "ringMARK2_GOAL"   so a string

then compile ["ringMARK%1_GOAL",ringChall] // returns {ringMARK2_GOAL}   so a code

then call compile format ["ringMARK%1_GOAL",ringChall]  // returns ringMARK2_GOAL    so as returned value of called code. see call.

• 1

##### Share on other sites

After all this I fear that from the start I have not well communicated the point of the script.

Let's imagine the simplest scenario.

3 courses of 3 rings each. The courses are individual and don't happen sequentially, ect. Each course has a large trigger to determine the course area (ringCHALL).
The "ringCHALL" variable equals the course ID number. So let's call it _courseID, like GOM did. So _courseID==1 is course 1 and _courseID==3 is course 3. And _course==0 is no course, cancel challenge.

Each of the three ring positions is an arrow helper named, for example, "ringMARK1_1" for _courseID 1, ring 1.  And "ringMARK2_3" for _courseID 2, ring 3. Let's rename this: "ring1_1", going forward.

There is a ring object, named ringOBJ that moves around from arrow marker to the next arrow marker as the player hits the object (trigger-- thanks to GOM the object is the trigger).

The trigger "ringTRIGmock" is not necessary.

I made @pierremgi's script match the above (maybe, if I did it correctly),

```//_hintLoc = [""," near the observatory "," in the valley "," near central valley "," at the peak "];

if (_courseID !=0) then {

_mark = call compile format ["ring%1_1",_courseID];

//hint format [" Ring Challenge Activated! Fly through the first ring%1to begin the ring course";_courseID];

{_x setpos getpos _mark} forEach [ringOBJ];
_ringMARK=1;
_ringScript=[]execVM format ["ringCLEAR.sqf",_courseID];
}

else {

ringOBJ setPos [0,0,0];
};```

Will the variable carry over to the next script? Like can we still refer to the "courseID"? And then, will this work?

```FTA_fnc_ringCLEAR = [] spawn {
waitUntil {
sleep 0.5;
(vehicle player distance ringOBJ < 3)
};

_ringMARK = _ringMARK + 1;
currentRING = call compile format ["ring%1_%2",_courseID, _ringMARK];

ringOBJ setPos (getpos currentRING);

if (_ringMARK == 3) then {
_ringMARK = 1;
};

};
sleep 0.2;
FTA_fnc_ringCLEAR =[]execVM "ringCLEAR.sqf";```

If so we did it in two scripts and I'm pretty excited.

##### Share on other sites

You have plenty of undefined local variables. Local variables are for a scope (There can be several scope inside a script. For a little idea... ).

when I wrote:

_hintLoc = [""," near the observatory "," in the valley "," near central valley "," at the peak "]; // in the main scope of the script, I define it here. So, you can use it in the script, or pass it to a new scope (like excVMed sqf, some eventHandler, addAction..) thru PARAMETERS.

Each time you are writing [] execVM "a.sqf"  , that means you don't need to pass parameters. It's OK if you are using global variables like currentRING (if defined somewhere in your mission: editor or other script).

With local variable, when you write:   if (_courseID !=0) then {....} , your _courseID is not defined at all inside the same script and before its use. >>>>> error undefined variable!

Here you have 3 separate triggers (areas for 3 races). If you don't want too much unreadable codes inside their on act. field, you can use in your script:

if (triggerActivated areaRINGtrig_3) .... do what you want for this area.

_ringScript=[]execVM format ["ringCLEAR.sqf",_courseID] ??

Say _courseID = 3 (so defined before), the hard method:

_ringScript=[]execVM format ["ringCLEAR%1.sqf",_courseID]   will do something like _ringScript=[]execVM format "ringCLEAR3.sqf"

3 areas >> 3 scripts!

Smarter method: you just have to pass _courseID as argument, and use a unique script ringCLEAR.sqf:

_ringScript = _courseID execVM format "ringCLEAR.sqf";

In ringCLEAR.sqf, you import _courseID starting as first line of code:

params ["_courseID"];    // then use _courseID   (you can rename this variable as you want: params ["_soCuteRing"];  //then use _soCuteRing)

or, last method near the 2nd one: use a global variable: courseID

Then _ringScript= [] execVM "ringScript.sqf";  // inside this sqf (and all others),  you can use straight the courseID  (it's not a parameter to be passed but a global variable).

• 1

##### Share on other sites
6 hours ago, wogz187 said:

call compile format ["ring%1_%2",_courseID, _ringMARK];

all that is is a https://community.bistudio.com/wiki/getVariable

Don't use compile for things like this, it's either slow, or causes other issues (like memory leaks). It just shows you don't know what you're doing.

• 1

##### Share on other sites
13 minutes ago, Dedmen said:

all that is is a https://community.bistudio.com/wiki/getVariable

Don't use compile for things like this, it's either slow, or causes other issues. It just shows you don't know what you're doing.

It just shows you're quick at bashing.

##### Share on other sites

@pierremgi,
I realized there was a problem with global/local variables about two seconds after I posted the above.

Thanks for going line by line and explaining to me. It's safe to say I still don't quite get variables but I'm currently reading up on: Public, Private, Global-- everywhere I look @killzone_kid, has notes so that guy really knows variables!

I rewrote that from yesterday. I'm sure it's not correct but I tried to set the private(?) variables outside(?) of the scope(?).

courseID.sqf

```_ringScript = scriptNull;
_courseID= missionNamespace getVariable "courseID";

if (_courseID !=0) then {
_mark = call compile format ["ring%1_1", _courseID];

ringOBJ setpos (getpos _mark);
ringMARK=1;

_ringScript=[]execVM format "ringCLEAR.sqf";
}

else {
if (ringMARK !=0) then {
ringmark=0;
};
ringOBJ setPos [0,0,0];
};```

Quote

It just shows you don't know what you're doing.﻿

Quote

I need to learn how to count.

Quote

You know how you said you don't understand why I did a bunch of stuff in the script above? It's because I don't know either.

I knew enough to ask for help.

Quote

Simply a byproduct of my not having even the faintest clue how to do this.

Quote

Q: Are you the worst script writer ever?
A: Undoubtedly.*
*but I'm trying.

It couldn't be more clear.

Up until about a month ago my script writing experience was ==0.

I'll tell you how it's going: I get an idea. The idea is more complicated than I thought. I learn a little bit more.

So far so good.

The script I need,
1) Places a circle in front of the player when they enter an area (point 1).
2) When the player touches the circle it goes to point 2.
3) When the player touches the circle again it goes to point 3.
4) Again, back to point 1, in a circuit.

This is complicated only by the fact there are 3 different circuits which are each triggered by their own area, courseID. The whole thing shuts down when not in any of the 3 areas.

Keep in mind we are writing the 3x3 course test rig as my lesson. I still have to write the 6x5 mission script myself as the test.

• 1

##### Share on other sites

Don't worry! The bashing was more for me than for you. You will never read that from smart guys like Larrow , able to explain/correct something weird, without bad comment with no added value.

First of all, you have 3 triggers, repeatable (important) so 3 conditions, 3 on activation code and 3 on deact. code.

So, you can make difference between your circuits by the activated trigger (In SP, it's impossible to act more than one at the same time)

In a same way, when a trigger deact, all triggers are deactivated  for some time (flight to one trigger).

If I'm right:

- in editor, you placed:

* your 3 triggered areas for goal (say areaRINGTRIG_1 ... _2 ... _3),

* your arrow markers as successive positions of ring. Here,this could be easier to name them referring to the triggers.

for example for the areaRINGTRIG_3, name the arrows areaRINGTRIG_3_0, ..._3_1, ..._3_2,...

NOTE: The coding is easier if you name all first arrows XXXX_0  because the command mod used to loop the circuits (see below).

* your movable trigger for ring (teleported from ring to ring when the player succeed in passing thru), You just need one! say ringTRIG

It must be repeatable also!!

* your movable ring. Also one only! say ringGOAL

* a counter (unique) set to 0, in init.sqf or anywhere (object's field, player init field...) say ringID = 0;  (I changed a little bit as you don't need 3 counters)

ringGoal and ringTRIG are together and progress along with the success of the pilot.

- For areaRINGTRIG_1 ... _2 ... _3, all the deact code are like this:

*  ringGOAL setPos [0,0,0]; //  optional: hideObject ringGOAL; ,

*  ringID = 0;  IMPORTANT! You want to start at ring 1 so XXXX_0 arrow, whatever the area can be.

* optional   ringTRIG setPos [0,0,0]; // no matter, it will be teleported in due time.

- for the activation code of  areaRINGTRIG_1 ... _2 ... _3  (so detecting the pilot's presence), it's always the same starting ring, so you just have to:

* (unhide the ring) and teleport it to the 1st arrow's position:

ringGOAL setpos getpos (missionNameSpace getVariable (str thisTrigger+"_1");  // works

optional: ringGOAL hideObject false;

- Now for the ringTRIG activation (to make it move)

ringGOAL setpos getpos (missionNameSpace getVariable (str thisTrigger+"_"+str ringID));

thisTrigger setpos getpos (missionNameSpace getVariable (str thisTrigger+"_"+str ringID));
ringID = (ringID + 1) mod 4
// 4 is the number of rings, here this number must be the same for all circuits!  You can specify different numbers in different variables if needed example:  areaRINGTRIG_1 setVariable ["nbrOfRing",6]; to set the value in init.sqf...

then here: ringID = (ringID + 1) mod (thisTrigger getVariable "nbrOfString")

NOTE: I don't know if your ringGOAL (and your ringTRIG btw) is correctly oriented (changing orientation along with the path).

just in case: ringTRIG setDir getDir (missionNameSpace getVariable (str thisTrigger+"_"+str ringID));  before incrementing ringID.

• 1
• 1

##### Share on other sites

@pierremgi, @Grumpy Old Man, @Dedmen,

I think I learned how to count. Not very well. Basically by ones, but that's a start. Thanks for all your help and patience!

I discovered there is still a lot to learn about variables.

That said I have the test rig working to my satisfaction and I think it's a pretty handy module. This module would make it very easy to set up racing circuits in land, sea and sky. The module could be used in combat missions also since it basically equates to whack-a-mole.

Surely it's not perfect but it seems to work. Here's the test rig,

The requirements were: 1 ring to rule them all, 1 or 2 scripts, simple. Check, check, check.
Here's the drive link for the module.

controlCOURSE.sqf

Spoiler
```
courseHINT= ["Course Exited", " Course 1 ", " Course 2 ", " Course 3 "] select courseID;

switch (courseID) do
{
case 1:
{
hint format ["You entered %1", courseHINT];

ringOBJ setPos (getPos ring1_1);
rings=execVM "ringCLEAR.sqf";
};
case 2:
{
hint format ["You entered %1", courseHINT];

ringOBJ setPos (getPos ring2_1);
rings=execVM "ringCLEAR.sqf";
};
case 3:
{
hint format ["You entered %1", courseHINT];

ringOBJ setPos (getPos ring3_1);
rings=execVM "ringCLEAR.sqf";
};
case 0:
{
hint format ["%1", courseHINT];
ringOBJ setPos (getPos locationNULL);
};
};```

ringCLEAR.sqf

Spoiler
```
call {
if (courseID==1) exitWith
{
ringID = ringID + 1;
currentRING = [objNULL, ring1_1, ring1_2, ring1_3] select ringID;

ringOBJ setPos (getpos currentRING);
if (ringID == 3) then {
ringID = 0;
};
};

if (courseID==2) exitWith
{
ringID = ringID + 1;
currentRING = [objNULL, ring2_1, ring2_2, ring2_3] select ringID;

ringOBJ setPos (getpos currentRING);
if (ringID == 3) then {
ringID = 0;
};
};

if (courseID==3) exitWith
{
ringID = ringID + 1;
currentRING = [objNULL, ring3_1, ring3_2, ring3_3] select ringID;

ringOBJ setPos (getpos currentRING);
if (ringID == 3) then {
ringID = 0;
};
};

sleep 1;
ringCLEAR=execVM "ringCLEAR.sqf";
};```

Thanks again!

Have fun!

• 2