Author Topic: How to make a repeat loop with a variable inside?  (Read 9961 times)

Drakin138

  • Guest
How to make a repeat loop with a variable inside?
« on: November 07, 2016, 08:39:07 PM »
Hey All,

Bear with me if you'd be so kind, I don't have much experience or knowledge in this department. I'm wondering if it's possible to create a command to add an extra key press for the each repeat of the duration of the command.

For example having the command run three times would output this:

Hello World!

Hello World!!

Hello World!!!

Adding one extra ! for each repetition until the command was stopped

Apologies if my terminology is inaccurate, is this something we can make Voice Attack do?

Pfeil

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 4747
  • RTFM
Re: How to make a repeat loop with a variable inside?
« Reply #1 on: November 08, 2016, 06:19:11 AM »
each repeat of the duration of the command.
Can you clarify the behavior you're expecting?
Are you looking to use the "Repeating" settings to make the command repeat? Would you be holding down a key to make this happen?


The basic part of this is certainly possible:
Code: [Select]
Begin Text Compare : [Keypresses] Has Been Set
    Set Text [Keypresses] to '{TXTCONCAT:Keypresses:"!"}'
Else
    Set Text [Keypresses] to '!'
End Condition
Quick Input, 'Hello world{TXT:Keypresses}'

However, the question is when should the value be reset; That's why it's important how you're planning to use the command.

If you're going to hold down a key, you could do the following:
Code: [Select]
Start Loop While : [{STATE_KEYSTATE:RCTRL}] Equals '1'
    Begin Text Compare : [Keypresses] Has Been Set
        Set Text [Keypresses] to '{TXTCONCAT:Keypresses:"!"}'
    Else
        Set Text [Keypresses] to '!'
    End Condition
    Quick Input, 'Hello world{TXT:Keypresses}'
End Loop
Set Text [Keypresses] to [Not Set]


Note that I'm using "Quick Input" in these examples rather than the new "Variable Keypress", as quick input is easier to use for text(no need to manually specify pressing shift, etc..).

Drakin138

  • Guest
Re: How to make a repeat loop with a variable inside?
« Reply #2 on: November 08, 2016, 12:16:54 PM »
Thanks for the reply! The command would use the built in repeating options started from a one click hotkey (not held down). The reset point would be when voice attack stops processing the command.

I'm getting an error with TXTCONCAT, quickinput is sending "hello world NOT SET" but I'm not sure where my syntax is incorrect

Pfeil

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 4747
  • RTFM
Re: How to make a repeat loop with a variable inside?
« Reply #3 on: November 08, 2016, 12:52:54 PM »
Thanks for the reply! The command would use the built in repeating options started from a one click hotkey (not held down). The reset point would be when voice attack stops processing the command.
There isn't really a way I'm aware of to execute anything outside of the command loop without using an external "watchdog" command when using the built-in repeat.

I'd suggest using the "loop" actions to repeat a set number of times instead:
Code: [Select]
Set small int (condition) [LoopCount] value to 3
Set Text [Keypresses] to ''
Start Loop While : [LoopCount] Does Not Equal 0
Set Text [Keypresses] to '{TXTCONCAT:Keypresses:"!"}'
Quick Input, 'Hello world{TXT:Keypresses}'
Write '[Purple] {TXT:Keypresses}' to log
Set small int (condition) [LoopCount] value as decremented by 1
End Loop
This example will loop 3 times, which can be easily changed by adjusting the initial value of "LoopCount".

You could in theory increment or decrement a variable using the built-in repeat, but then you have to set both the value for that as well as the repeat count to the exact same number. The above snippet only requires one value to be set by the user.


I'm getting an error with TXTCONCAT, quickinput is sending "hello world NOT SET" but I'm not sure where my syntax is incorrect
You can right click on an action inside your command and select "Copy all as text", which you can then paste here in the forums. I'll have a look.

Drakin138

  • Guest
Re: How to make a repeat loop with a variable inside?
« Reply #4 on: December 07, 2016, 02:12:25 AM »
Been working on this a bit and still haven't made much progress, maybe a new outlook will help! My goal here is to make repetitive menuing tasks easier. I'll try and explain it as best and thoroughly as I can.

Lets say there's a base menu where you can select any of 100 sprites that are in alphabetical order, and we want all our sprites blue. Once you select a sprite, you enter another menu and you can change their appearance. When you're done editing the sprite the game places you back at square (X) at the beginning of the base menu. It's alright if the command recolors the same sprite multiple times.

What I'm looking to achieve is basically to set the built in repetition counter (pic attached) then start the script and have it run through and recolor each sprite.

In my head it runs something like this:

Start
   (Select Sprite)
      (Recolor)
          (Return to base menu and move right + X) with X being the repetition the script is currently on.



(X) (1) (2) (3) (4) (5) ... (100)

Does this make sense? Is this something that VA can do?

Apologies for the length, brevity is not my strong suit!

Pfeil

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 4747
  • RTFM
Re: How to make a repeat loop with a variable inside?
« Reply #5 on: December 07, 2016, 06:47:57 AM »
The built-in repeat system is intended for simple actions that don't require changes between iterations, E.G. if you had a macro to craft something and you want to do so multiple times to gain multiple items.

You need to use the loop action to be able to increment a value, and more importantly to reset the value after the command is complete.

An alternative to using quick input is to use another loop embedded in the first one:
Color [2..100] sprites;Color 1 sprite
Code: [Select]
Set small int (condition) [LoopTarget] value to the converted value of {TXTNUM:"{CMD}"}
Set small int (condition) [LoopCount] value to 0
Start Loop While : [LoopCount] Does Not Equal [LoopTarget]
Set small int (condition) [KeypressCount] value to -1
Start Loop While : [KeypressCount] Does Not Equal [LoopCount]
Press A key and hold for 0,06 seconds and release
Set small int (condition) [KeypressCount] value as incremented by 1
End Loop
Press B key and hold for 0,06 seconds and release
Set small int (condition) [LoopCount] value as incremented by 1
End Loop
The "A" key will be pressed as many times at the first loop has iterated each cycle, whereas the "B" key will be pressed once each cycle, I.E. "abaabaaab" and so on.

In this case you can tell the command how many times to loop. Note that this will generate a large amount of command names, which can(depending on your machine) have an effect on the responsiveness of the speech engine.


EDIT: An alternative, where you can dictate the amount of repeats(which only adds a single command phrase to the speech engine):
Code: [Select]
Set small int (condition) [LoopTarget] value to 0
Set Boolean [DictationComplete] to False
Say, 'How many?'
Start Loop While : [DictationComplete] Equals False
    Marker: DictationLoop
    Start Dictation Mode (Clearing Dictation Buffer)
    Start Loop While : [{DICTATION}] Equals ''
    End Loop
    Stop Dictation Mode
    Begin Small Integer Compare : [LoopTarget] Equals 0
        Begin Text Compare : [{EXP: {TXTNUM:"{DICTATION}"} >= 0}] Equals '1'
            Set small int (condition) [LoopTarget] value to the converted value of {TXTNUM:"{DICTATION}"}
        Else If Text Compare : [{DICTATION}] Equals 'one'
            Set small int (condition) [LoopTarget] value to 1
        Else If Text Compare : [{DICTATION}] Equals 'two'
            Set small int (condition) [LoopTarget] value to 2
        Else If Text Compare : [{DICTATION}] Equals 'three'
            Set small int (condition) [LoopTarget] value to 3
        Else If Text Compare : [{DICTATION}] Equals 'four'
            Set small int (condition) [LoopTarget] value to 4
        Else If Text Compare : [{DICTATION}] Equals 'five'
            Set small int (condition) [LoopTarget] value to 5
        Else If Text Compare : [{DICTATION}] Equals 'six'
            Set small int (condition) [LoopTarget] value to 6
        Else If Text Compare : [{DICTATION}] Equals 'seven'
            Set small int (condition) [LoopTarget] value to 7
        Else If Text Compare : [{DICTATION}] Equals 'eight'
            Set small int (condition) [LoopTarget] value to 8
        Else If Text Compare : [{DICTATION}] Equals 'nine'
            Set small int (condition) [LoopTarget] value to 9
        Else
            Say, 'Please say a valid number'
            Jump to Marker: DictationLoop
        End Condition
        Say, 'Loop {SMALL:LoopTarget} times?'
        Jump to Marker: DictationLoop
    Else
        Begin Text Compare : [{DICTATION}] Equals 'affirmative'
            Set Boolean [DictationComplete] to True
        Else If Text Compare : [{DICTATION}] Equals 'negative'
            Set small int (condition) [LoopTarget] value to 0
            Say, 'How many?'
            Jump to Marker: DictationLoop
        Else
            Say, 'Please say "affirmative" or "negative"'
            Jump to Marker: DictationLoop
        End Condition
    End Condition
End Loop
Set small int (condition) [LoopCount] value to 0
Start Loop While : [LoopCount] Does Not Equal [LoopTarget]
    Set small int (condition) [KeypressCount] value to -1
    Start Loop While : [KeypressCount] Does Not Equal [LoopCount]
        Press A key and hold for 0,06 seconds and release
        Set small int (condition) [KeypressCount] value as incremented by 1
    End Loop
    Press B key and hold for 0,06 seconds and release
    Set small int (condition) [LoopCount] value as incremented by 1
End Loop

I've also attached both variants as exported commands.
« Last Edit: December 07, 2016, 07:18:35 AM by Pfeil »

Drakin138

  • Guest
Re: How to make a repeat loop with a variable inside?
« Reply #6 on: December 07, 2016, 10:40:44 AM »
This code is fascinating to read through! I think I understand it

So {TXTNUM:"{CMD}"} is how VA knows which iteration the command is on?

If I replace "Press A..." With 'Execute another command MenuRight' and "Press B..." With 'Execute another command ColorSprite' will that work?

Example:
Code: [Select]
Set small int (condition) [LoopTarget] value to the converted value of {TXTNUM:"{CMD}"}
Set small int (condition) [LoopCount] value to 0
Start Loop While : [LoopCount] Does Not Equal [LoopTarget]
Set small int (condition) [KeypressCount] value to -1
Start Loop While : [KeypressCount] Does Not Equal [LoopCount]
'Execute another command MenuRight'
Set small int (condition) [KeypressCount] value as incremented by 1
End Loop
'Execute another command ColorSprite'
Set small int (condition) [LoopCount] value as incremented by 1
End Loop

Pfeil

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 4747
  • RTFM
Re: How to make a repeat loop with a variable inside?
« Reply #7 on: December 07, 2016, 11:01:10 AM »
So {TXTNUM:"{CMD}"} is how VA knows which iteration the command is on?
No. That token takes the spoken command and strips everything that isn't a number, so it sets the amount of times it should loop to the "LoopTarget" variable.
The current loop count is kept in "LoopCount", which is incremented at the end of each iteration.

Two variables are used because the amount of keypresses needs to go up each iteration. Otherwise it'd be simpler to set and decrement a single variable.

If I replace "Press A..." With 'Execute another command MenuRight' and "Press B..." With 'Execute another command ColorSprite' will that work?
It should, however you need to make sure the "Wait until this command completes before contunuining" option is checked, so the action would look like "Execute command, 'MenuRight' (and wait until it completes)".

You should also be aware that executing commands from other commands reportedly has some overhead, and is slower that executing the actions directly. This may be more obvious in a long loop.

Drakin138

  • Guest
Re: How to make a repeat loop with a variable inside?
« Reply #8 on: December 07, 2016, 11:57:21 AM »
You should also be aware that executing commands from other commands reportedly has some overhead, and is slower that executing the actions directly. This may be more obvious in a long loop.

Right on, I try to build in a reasonable pause buffer between lines. Do you have a ballpark idea of long I should increase those buffers? 200%? 400%?

Edit: How did you link those two commands to make a multipart?
Edit2: IT WORKS!! Thank you so much Pfeil!
« Last Edit: December 07, 2016, 12:24:39 PM by Drakin138 »

Pfeil

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 4747
  • RTFM
Re: How to make a repeat loop with a variable inside?
« Reply #9 on: December 07, 2016, 12:50:13 PM »
I try to build in a reasonable pause buffer between lines. Do you have a ballpark idea of long I should increase those buffers? 200%? 400%?
What I mean is that calling a separate command takes time, so it may take longer for the entire sequence to complete. Adding an artificial delay would actually amplify the problem.

I searched the forum for the topic I got it from, so you can determine for yourself if it's an issue in your application.
Entering keystroke in executing command               : baseline
Using quick input to call txt variable.                       : 1.1x baseline
Calling another command to that executes keystroke: 2-3 x baseline


Edit: How did you link those two commands to make a multipart?
They're two independent examples of the same command. They work standalone.

Edit2: IT WORKS!! Thank you so much Pfeil!
Good to hear.