Author Topic: How to get a different answer with the same command (joystick button press)?  (Read 1188 times)

Jan27!

  • Newbie
  • *
  • Posts: 12
Hello,
I've got this problem: I'm playing with DCS F18 and I want to drop two bombs separately (with some time span between them). So when I press the pickle button, I will get from VA: "Pickle" as an answer. Then after some time I drop the other bomb, and again VA responds with "Pickle". So then all my bombs are drop and then, when I pushed the joystick button, I want VA to say as an answer "winchester" (in stead of pickle).

I've set the code up with the Condition Builder like this and I've tried to set up a for loop but that won't do the trick. (It gives me indeed the answer pickle-pickle-winchester, but all by one pushbutton push).
In the code below: the three else if statements are working perfectly, so that is not the problem. I think the answer most be found in the Begin Condition statement, but I'm not very sure how to set that up.


Begin Condition : ([masterSwitch] Equals 'ARM' AND [airToAir] Equals 'atg' AND [activeWeapon] Equals 'bomb')
    Say, 'Pickle'  (and wait until it completes)
Else If : ([masterSwitch] Equals 'SAFE' AND [airToAir] Equals 'atg' AND [activeWeapon] Equals 'bomb')
    Say, 'Bomb cannot be dropped because master Arm switch is set to Safe'  (and wait until it completes)
Else If : ([masterSwitch] Equals 'ARM' AND [airToAir] Equals 'ata' AND [activeWeapon] Equals 'bomb')
    Say, 'Bomb cannot be dropped because master switch in Air to air mode'  (and wait until it completes)
Else If : ([masterSwitch] Equals 'SAFE' AND [airToAir] Equals 'ata' AND [activeWeapon] Equals 'bomb')
    Say, 'Bomb cannot be dropped because master switch is set to safe and is not set to air to ground mode'  (and wait until it completes)
End Condition

I'm hoping for some help


Pfeil

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 4782
  • RTFM
If you want to keep track of the amount of times the button has been pressed, you need to use a variable to store the current count (an Integer value would be appropriate in this case), so you can check whether the conditions for weapon release are met (as is already the case with the first branch of your condition) and if so increment the counter. Then, if the counter exceeds the number of deployments available, you can switch to "Winchester" instead.

E.G.
Code: [Select]
Begin Condition : ([masterSwitch] Equals 'ARM' AND [airToAir] Equals 'atg' AND [activeWeapon] Equals 'bomb')
    Begin Integer Compare : [pickleCount] Is Less Than 3
        Say, 'Pickle'
        Set integer [pickleCount] to [pickleCount] plus 1
    Else
        Say, 'Winchester'
    End Condition
Else If : ([masterSwitch] Equals 'SAFE' AND [airToAir] Equals 'atg' AND [activeWeapon] Equals 'bomb')
    Say, 'Bomb cannot be dropped because master Arm switch is set to Safe'  (and wait until it completes)
Else If : ([masterSwitch] Equals 'ARM' AND [airToAir] Equals 'ata' AND [activeWeapon] Equals 'bomb')
    Say, 'Bomb cannot be dropped because master switch in Air to air mode'  (and wait until it completes)
Else If : ([masterSwitch] Equals 'SAFE' AND [airToAir] Equals 'ata' AND [activeWeapon] Equals 'bomb')
    Say, 'Bomb cannot be dropped because master switch is set to safe and is not set to air to ground mode'  (and wait until it completes)
End Condition

Make sure the "Evaluate 'Not Set' as zero" option is checked.

You may also want to have a command to reset the value of "pickleCount" if you rearm.

Jan27!

  • Newbie
  • *
  • Posts: 12
Hello Pfeil,

Thank you for the very quick answer. It works. But besides that I want to check if I understand (and learn) the flow correctly:
1. You introduced a variabele, named "pickleCount", and gave this variable an assigned value of "less then 3"
2. Then you let VA call the response: "pickle"
3. Followed by the sentence where the variable "pickleCount" (which in this case is an integer) get the assigned value of the original "pickleCount" with 1 added each time I push the button on my joystick. In this case it starts with 1 (because "Evaluate not set as zero" option is checked).
4. Am I forgetting some aspects of reading the flow correctly?

Question 1: Where is the variable "pickleCount" given the value 1, so VA knows that the first push on my joystick is the first "pickleCount" to count as 1?
Question 2: "Set integer [pickleCount] to [pickleCount] plus 1" looks like a part of a loop. Is that correct?
Question 3: You ends your answer with the idea of resetting the value of "pickleCount". But I have no idea how that can be done? Something like: integer pickleCount = new pickleCount; picklecount = 1;???
But what is the commando I should give to get that done??

Really want to learn more about VA, that is the reason of my questions


Pfeil

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 4782
  • RTFM
Provided the statements in the initial condition that checks , the actual flow is this:

The first execution:
  • The condition checks whether a variable named "pickleCount" exists (I.E. whether a value has been assigned to it), and if not, because the "Evaluate 'Not Set' as zero" is checked, proceeds as if that variable had been set to 0
  • The statement "0 is less than 2" is evaluated and found to be true
  • The first branch of the condition is executed
  • The "Say Something with Text-To-Speech" renders its audio ("Pickle") and the sound system starts playing it back (immediately, as the "Wait until speech completes before continuing command" option is not enabled)
  • The "Set an Integer Value" action, which should also have the "Evaluate Not Set as zero" option checked, checks whether a variable named "pickleCount" exists, and if not, proceeds as if it had been set to 0
  • The value is computed; 0 + 1 = 1, so the "pickleCount" variable is created and its value is set to 1
  • As there are no more reachable actions to execute, the command ends
The second execution:
  • The condition checks whether a variable named "pickleCount" exists, and if so gets its value
  • The statement "1 is less than 2" is evaluated and found to be true
  • The first branch of the condition is executed
  • The "Say Something with Text-To-Speech" renders its audio ("Pickle") and the sound system starts playing it back
  • The "Set an Integer Value" action, which should also have the "Evaluate Not Set as zero" option checked, checks whether a variable named "pickleCount" exists, and if so gets its value
  • The value is computed; 1 + 1 = 2, so the "pickleCount" variable's value is overwritten to be 2
  • As there are no more reachable actions to execute, the command ends
The third execution (as well as any subsequent executions, providing the value of "pickleCount" is not modified externally):
  • The condition checks whether a variable named "pickleCount" exists, and if so gets its value
  • The statement "2 is less than 2" is evaluated and found to be false
  • The second branch of the condition is executed
  • The "Say Something with Text-To-Speech" renders its audio ("Winchester") and the sound system starts playing it back
  • As there are no more reachable actions to execute, the command ends

What may clarify this behavior for you is to know that VoiceAttack "variables" are actually elements of a Dictionary collection, to allow them to be created on the fly without first explicitly declaring them.
The "Evaluate 'Not Set' as zero" option makes the "Begin a Conditional (If Statement) Block" action check whether a given variable exists within the dictionary, and if not use a default value of 0 instead.


There are no visible loops used in this command (there may be loops used internally, but the logic as described in the action list does not constitute any), as the flow starts from the top, and continues to the bottom, without ever jumping back up (this topic attempts to explain the different methods for controlling command flow, including loops).


To reset "pickleCount", you can simple change its value from any command, E.G.
Code: [Select]
Set integer [pickleCount] value to 0

In that case you're setting the value to 0, explicitly, meaning the variable will still exist within the dictionary, and rather than evaluating it as if the value were 0, the actual value of 0 will now be retrieved by the "Begin a Conditional (If Statement) Block" and "Set an Integer Value" actions.
That will not affect the actual flow of the command, as the logic remains the same (E.G. 0 is still less than 2, etc...; There is no functional difference between a variable value of 0, and the 0 produced by the "Evaluate 'Not Set' as zero" option, mathematically)

Jan27!

  • Newbie
  • *
  • Posts: 12
Hello Pfeil,

Thank you very much for this very detailed answer. I leaves me with a 98% understanding of the flow. There are two thing that are a bit mysterious for me
1. In the first execution, the "Dictionary" creates an integer variable (pickleCount) in step 6: at that moment the "pickleCount" variable is "born". But in step 1 of the first execution this "not-born" variable is given a value of 0. And the "Dictionary" can live with that, because
2. "Evaluate, 'Not set' as zero" is selected. I read that as follows: "pickleCount" is not null (so it is "set" = it exits), although it does not have a name, because it is "not born". It will be born in step 6 of the first execution. In other words: "pickleCount" exists in "Dictionary", does not have a name, but has been given a value of 0.

It is my childish explanation (although I'm 64 years old), but is this a correct interpretation?

Again, thank you very much for this great answer. I really appreciate it!!!

Pfeil

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 4782
  • RTFM
Data from the Dictionary is not used directly; Internally, there is a temporary variable used to store the output of the query made against the contents of the Dictionary.

The Dictionary used in this case would be defined as
Code: [Select]
Dictionary<string, int?>meaning its keys (whose values must be unique within that Dictionary) are text, and its values are nullable integers (I.E. their value can either be an integer number, or null)

When the "Begin a Conditional (If Statement) Block" action queries the Dictionary for the value associated with a key that matches the literal text "pickleCount", the method that performs the query will either store the retrieved data in the aforementioned temporary variable, or, if no matching key is found, the default value for the datatype used for the values in the dictionary will be stored in that variable instead.
As the Dictionary uses the nullable integer type, that default value is null.

What the "Evaluate 'Not Set' as zero" option (as well as the "Evaluate Not Set as zero" option for the "Set an Integer Value" action) likely does internally, is perform an additional check to see whether the variable's value is null, and if so sets it to 0 instead.


No data is written to the Dictionary during any of this; That only happens when the "Set an Integer Value" is executed.

Jan27!

  • Newbie
  • *
  • Posts: 12

I want to get some more differentiation in the above mentioned command. So I set up some more commands trying to hear when all bombs are dropped

1. In   the first command (F18 Hornet on the ground) I tell VA how many bombs (in this case: four bombs) are on the aircraft and declare four variables.
The command is: [one;two;three;four][bombs;bomb]
Begin Text Compare : [{CMD}] Contains 'one bomb'
    Set text [bombCount1] to 'zero'
    Say, 'One bomb aboard'
Else If Text Compare : [{CMD}] Contains 'two bombs'
    Set text [bombCount2] to 'zero'
    Say, 'Two bombs aboard'
Else If Text Compare : [{CMD}] Contains 'three bombs'
    Set text [bombCount3] to 'zero'
    Say, 'Three bombs aboard'
Else If Text Compare : [{CMD}] Contains 'four bombs'
    Set text [bombCount4] to 'zero'
    Say, 'Four bombs aboard'
End Condition

2.   In the second command I select the bombs (DCS F18 hornet in the air) with a prefix and a suffix portion

[bomb;bombs] (Prefix-command)
Begin Text Compare : [{EXP:'{PREFIX}' = 'bomb'}] Equals '1'
    Set text [activeWeapon] to 'bomb'
    Say, 'Bombs selected'
Else
    Begin Text Compare : [{EXP:'{PREFIX}' = 'bombs'}] Equals '1'
        Set text [activeWeapon] to 'bomb'
        Say, 'Bombs selected'
    End Condition
End Condition

Selected (Suffix-command)
Begin Text Compare : [{EXP:'{SUFFIX}' = 'Selected'}] Equals '1'
End Condition

3.   In the third command I release the bombs with a button press on my joystick

Begin Condition : ( [activeWeapon] Equals 'bomb' AND [bombCount4] Equals 'zero')
    Begin Integer Compare : [bombCount4] Is Less Than 3
        Say, 'Bombs away'
        Set integer [bombCount4] to [bombCount4] plus 1
    Else
        Say, 'We ran out of bombs'
    End Condition
End Condition
Begin Condition : ([activeWeapon] Equals 'bomb' AND [bombCount3] Equals 'zero')
    Begin Integer Compare : [bombCount3] Is Less Than 3
        Say, 'Bombs away'
        Set integer [bombCount3] to [bombCount3] plus 1
    Else
        Say, 'We ran out of bombs'
    End Condition
End Condition
Begin Condition : ([activeWeapon] Equals 'bomb' AND [bombCount2] Equals 'zero')
    Begin Integer Compare : [bombCount2] Is Less Than 2
        Say, 'Bombs away'
        Set integer [bombCount2] to [bombCount2] plus 1
    Else
        Say, 'We ran out of bombs'
    End Condition
End Condition
Begin Condition : ([activeWeapon] Equals 'bomb' AND [bombCount1] Equals 'zero')
    Begin Integer Compare : [bombCount1] Is Less Than 1
        Say, 'Bombs away'
        Set integer [bombCount1] to [bombCount1] plus 1
    Else
        Say, 'We ran out of bombs'
    End Condition
End Condition

All went well because VA tells me exactly how many bombs I've dropped en when I ran out of bombs
In the fourth command I do the rearming (two bombs) and then get back in the air to do some more bomb dropping

4.   Rearming
rearming successful
Set integer [bombCount1] value to 0
Set integer [bombCount2] value to 0
Set integer [bombCount3] value to 0
Set integer [bombCount4] value to 0

This works fine with no problems. But…..then there is the problem

Before the rearming I start with four bomb selected but after rearming in the same mission with two bombs (and doing the flow 1 to 3 again). Then the second time I'm dropping bombs the voices are mixed up: VA says 4 times “bombs away”, followed by “We ran out of bombs” (5 times push the button) AND also says two times “bombs away” followed by “We ran out of bombs” (3 times push the button). I would expect that VA says the second time: Bombs away (2 times), followed by “We ran out of Bombs”

As said (the problem): the two voices are speaking at the same time.

I try to put a: "Kill command, 'Release bombs'", after the rearming command (with no success) and after the first and second command, but also with no success.

Any suggestions? What am I doing wrong?


Gary

  • Administrator
  • Hero Member
  • *****
  • Posts: 2832
Just a quick run-through (I'm not in a position to fully analyze your work) -

Your joystick-triggered command just evaluates and then says something without waiting for the TTS to finish (or exiting).  If more than one of the listed conditions evaluates to true, it's going to play your TTS simultaneously.


Also, I can tell that your composite (prefix/suffix) commands don't need to be that way.  You could easily create a single command, as the suffix doesn't do anything with the condition evaluation, and the prefix will always either be 'bomb' or 'bombs':

[bomb;bombs]selected
    Set text [activeWeapon] to 'bomb'
    Say, 'Bombs selected'

Pfeil

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 4782
  • RTFM
You're using an odd mix of variable types: You're setting text variables named "bombCount1" to "bombCount4" to "zero", and checking them later, but then you're using integer variable with the same names to keep track of the actual count.

It might make sense to use the [one;two;three;four][bombs;bomb] command to set integer values to the amount of available bombs, so you can then decrement them and check whether their value is 0


While as Gary has mentioned the prefix/suffix commands are needlessly complex, I also want to point out there is no reason to use the "{EXP:}" token for a simple text comparison; You can use tokens in the "Variable Name / Token" field (as the label suggests), and the literal text you're comparing against in the "Text" field.

If you want to compare only part of your text, you can use the "Contains" operator, E.G.
Code: [Select]
Begin Text Compare : [{CMD}] Contains 'bomb'

Which would match both "bomb" and "bombs", regardless of anything else in the command phrase.

Jan27!

  • Newbie
  • *
  • Posts: 12
Thanks for your both usefull advises. So I:

1. Only use integer variables and to set integer values to the amount of available bombs (thanks Pfeil)

2. Simplified the prefix/suffix parts (thanks Gary and Pfeil)

3. Solved the "voices are speaking on the same time". The problem was that I had set, for every single variable (bombcount4, bombCount5,.....),  the active weapon to "[activeWeapon] Equals 'bomb'". So all the different variables were set to the same condition, in this case the "[activeWeapon] Equals 'bomb'". I am very glad that I solved this problem myself. It gives me the feeling that I'm beginning to learn just a little bit of the advanced features of VA.

4. Made more differentiation in the way VA gives answers back when dropping the bombs. I use three commands for this

Command: [one;two;three;four;five;six] bomb selected. (some part of the command is shown here:)
Else If Text Compare : [{CMD}] Contains 'six bomb selected'
Set text [activeWeapon] to 'six bombs'
Set integer [bombCount6] value to 6
Say, 'Six bombs selected'



Command: Press button on joystick  (some part of the command is shown here:)
Begin Condition : ([masterSwitch] Equals 'ARM' AND [airToAir] Equals 'atg' AND [activeWeapon] Equals 'six bombs')
    Begin Integer Compare : [bombCount6] Is Greater Than 2
        Say, 'Bombs away'
        Set integer [bombCount6] to [bombCount6] minus 1
    Else If Integer Compare : [bombCount6] Is Greater Than 1
        Set integer [bombCount6] to [bombCount6] minus 1
        Say, 'bombs away and one bomb left'
    Else If Integer Compare : [bombCount6] Is Greater Than 0
        Say, 'That's the Last bomb'
        Set integer [bombCount6] to [bombCount6] minus 1
    Else
        Say, 'No more bombs'
    End Condition
Else If : ([masterSwitch] Equals 'SAFE' AND [airToAir] Equals 'atg' AND [activeWeapon] Equals 'six bombs')
    Say, 'Bombs cannot be dropped because Master arm switch is set to safe'
Else If : ([masterSwitch] Equals 'ARM' AND [airToAir] Equals 'ata' AND [activeWeapon] Equals 'six bombs')
    Say, 'Bombs cannot be dropped because Master Arm switch not in air to ground mode'
Else If : ([masterSwitch] Equals 'SAFE' AND [airToAir] Equals 'ata' AND [activeWeapon] Equals 'six bombs')
    Say, 'Bombs cannot be dropped because Master switch set to safe and also not in air to ground mode'
End Condition


Command: Reset;rearming successfull (some part of the command is shown here:)
Set integer [bombCount6] value to 6

In the second command I use two other variables: [masterSwitch] variable  and the  [airToAir] variable

Command: [Master Arm Switch][set to ARM; master arm switch to arm;arm] (the same command can be made for the master arm switch set to safe)

Set text [masterSwitch] to 'ARM'
Press Right Shift+S keys and hold for 0.1 seconds and release
Say, 'Master Arm Switch set to arm'  (and wait until it completes)


Command: Select air to air mode (The same command can be made for the "Select air to ground mode)
Set text [airToAir] to 'ata'
Begin Text Compare : [masterSwitch] Equals 'ARM'
    Press 1 key and hold for 0.1 seconds and release
    Say, 'Air to air mode selected'  (and wait until it completes)
Else If Text Compare : [masterSwitch] Equals 'SAFE'
    Say, 'Master arm switch not set to arm so set the master arm switch to arm'  (and wait until it completes)
End Condition


So a bit extensive reaction with this time no questions (but they will come). Maybe some other VA users can do their benefits with the above described commands

Again: thanks for the help!