PDA

View Full Version : Time-parsing - need an efficient script



Fever
16th February 2004, 08:23 PM
Can someone post an example of an efficent time-parsing script?

What is time-parsing you ask??....my take on it is a quick double hit of a button which activates a script and allows alternate key strokes to be used by a predefined number of buttons.

I would like to use it to activate wingman commands when im in single player, dont need the multiplayer coms at that point but would like to make use of those same buttons.

Time-parsing in combination with the menu stepping script i saw in another thread would be cool.

Fever

MichaelCHProd
16th February 2004, 08:49 PM
Are you looking for a sub mode for only certain buttons?

I.E. When you press button 1 twice in a set period of time it will change the functions of buttons 3-6 to different commands.

Fever
16th February 2004, 09:28 PM
Yes! Or double press one of the buttons in the set of buttons i want to reprogram to enable the alternate commands. And of course double press that same button to return to "normal".

MichaelCHProd
16th February 2004, 09:58 PM
Ok tell me the keys you want and the actions to be taken in order.

Fever
16th February 2004, 10:12 PM
OK, but lets talk in general terms as i havent figured out everything i want to do yet. What i'd like is to have the top front hat on the ProThrottle be "remapped" to 4 new commands when that same hat "up" button is pressed twice quickly. Note this also remaps the "up" button to a new command as well. OK, now that we are in the "new map" for the hat a quick double press of the "up" hat button takes us back to the original 4 commands for the hat (all are macros by the way). I don't have my controllers in front of me to give you the button numbers but i think you get the idea.

Is that enough info??? You can make up macros ie 1... 2... 3... 4.., and CMS buttons.. ill change them later :).

JNOV
16th February 2004, 11:08 PM
Fever:

Here's an example from one of my scripts, where I set-up time-parsed functions on four keys that otherwise serve as shift keys:

// ================================================== ================================
// Time-Parsed Shift Keys
// Timers: d1-d8
// Bits: cms.b1-b2, cms.b58, cms.b61
// ================================================== ================================

// Zoom (FS Shift 1)
pulse(d1) = js1.b4;
timer(offdelay,d2,5) = d1 and not d2;
cms.b1 = d2 and not js1.b4;

// Target Reticle (FS Shift 2)
pulse(d3) = js1.b3;
timer(offdelay,d4,5) = d3 and not d4;
cms.b2 = d4 and not js1.b3;

// Time Compression (PT Shift 1)
pulse(d5) = js2.b4;
timer(offdelay,d6,5) = d5 and not d6;
cms.b61 = d6 and not js2.b4;

// ENTER (PT Shift 2)
pulse(d7) = js2.b3;
timer(offdelay,d8,5) = d7 and not d8;
cms.b58 = d8 and not js2.b3;

To give credit where credit is due, the time-parsing method employed in this script was devised by Bob Church. I use it all of the time and it works very well.

The time parsing works the same way in each of the four examples. Basically, what it does is sense a press of the time-parsed key and activate the time-parsed function if the key is released quickly enough. The offdelay timers (i.e., d2, d4, d6, and d8 in the script above) turn on when the key is pressed and stay on for "5" time units thereafter. If the key is released before the timer is turned off, the output (e.g., cms.b1, cms.b2, cms.b61, or cms.b58 in the script above) is turned on. You can make the time-parsing more or less time-sensitive by altering the offdelay persistence value (i.e., "5" in the script above).

I hope this helps.

- JNOV

Fever
17th February 2004, 02:44 AM
I've been staring at this for a while now and i think i understand whats going on (after reading the help files in CM3). This script will be useful in setting a state variable to "TRUE" that will allow my "new map" commands to be executed. Now i have a headache. Thanks for the help.


Fever

JNOV
17th February 2004, 03:35 AM
I think it's a little confusing because of the way that the offtimer and pulse timer work together. The pulse timer (e.g., d1) is true for exactly one program scan when you press the time-parsed button. So, one program scan after you press the button, it goes false and the offtimer starts. The offtimer stays on for a certain period of time (e.g., 5 "time units"), and if you let go before it turns off, the output expression will be true, because (using the first example in the script as a reference):

1. d2 is true, because the offtimer is still on
2. js1.b4 is false, because you've released the time-parsed button
3. not js1.b4 is true, because js1.b4 is false
4. d2 and not js1.b4 is true, because of 1-3 above

In my example, I've used the time-parsed output to turn on cms bits, which, in the GUI, I've mapped to useful game commands (e.g., toggle zoom). But you can use them for other purposes. In another script, I use two time-parsed inputs to sequence forward and backward, respectively, through a list of ten states, each of which represents one of ten possible zoom levels.

It's also more confusing than necessary because of the extra term in the timer line. To make it easier to understand, you can get rid of the second term after the equal sign, so that the expression becomes

timer(offdelay,d2,5) = d1;

That makes the off timer's (d2's) dependence on the pulse timer (d1) a little more obvious. The "and not d2" is a safety measure so that the off timer (d2) will not try to turn itself on if it's already on. It will probably work fine without this bit.

If you've got any questions, I'll do my best to help. Have fun!

- JNOV

MichaelCHProd
17th February 2004, 06:12 AM
I could not for the life of me remember where I put that. I spent all day looking for that script. :P

Thank You for picking up my slack JNOV <s>

Bob Church
17th February 2004, 07:38 AM
JNOV,

Since CM3 came out with the PERIOD timer, you can simplify that a little. It will essentially replace the PULSE/ONDELAY pair with a single timer:

timer( PERIOD, d1, 5 ) = js1.b2;
cms.b1 = d1 and not js1.b2;

It works the same as what you&#39;re doing, it just saves the pulse statement since the PERIOD timer runs whether the input stays closed or not.

- Bob

The StickWorks
http://www.stickworks.com

Fever
17th February 2004, 01:39 PM
Thanks Bob, that is a little more efficient. Now how to implement wingman commands in LOMAC using all this good stuff :). F1-F3 on one button, F4-F6 on another...... i wish there was a way to step up and down in the command menu :(.

JNOV
17th February 2004, 03:27 PM
Thanks, Bob! I&#39;ve been using that script for so long that it never occurred to me to update it!

- JNOV

Bob Church
17th February 2004, 10:29 PM
Fever,

>> Thanks Bob, that is a little more efficient. Now how to implement wingman commands in LOMAC using all this good stuff . F1-F3 on one button, F4-F6 on another...... i wish there was a way to step up and down in the command menu. <<

The CMNOTE01.ZIP file I posted on the "Files" page over on my web site shows a way to generate a sequence of characters, one character per click, and it will reverse the order. Actually, it sequences bits, but then they can be assigned as CMS buttons and the characters generated up there. You might want to take a look, might be some help.

- Bob

The StickWorks
http://www.stickworks.com

Bob Church
17th February 2004, 10:41 PM
JNOV,

>> Thanks, Bob! I&#39;ve been using that script for so long that it never occurred to me to update it! <<

You&#39;re welcome! Yeah, I know how it goes. When it&#39;s working I tend to just leave well enough alone, too. I think it may have been that very operation that caused me to put the PERIOD type into the CM in the first place, the extra PULSE seemed kind of messy.

- Bob

The StickWorks
http://www.stickworks.com

Fever
18th February 2004, 01:43 AM
Thanks again Bob (thanks for your help too JNOV). I&#39;m pretty sure i know what i have to do now. It&#39;s going to be a complicated script but i like a challange :). I&#39;ll post it here after im done.

Basically a quick press of my normal "online" multiplayer comms button will activate an altered mode for a hat (which contains the chat button) and each of those buttons will be assigned 3 function commands (ie F1 F2 F3 on one button) for single player comms with AI wingmen. Quick presses of the individual buttons on the hat will generate the proper F key (one press = F1, 2 presses = F2, 3 quick presses = F3). The comms button will be used to exit the altered mode if no other button was pressed after entering the altered mode. This all sounds confusing but the menu structure in LOMAC is not setup for easy navigating using hat buttons :). The only thing you&#39;ll need to remember is which buttons send which F keys.. 1 button = F1-F3, the next button F4-F6, the next button F7-F9 and the comms button will get F11, F12 and a quick exit function. I think im possessed.

Fever

Fever
19th February 2004, 05:05 AM
Bob/Michael/JNOV

Do you guys see any glaring errors here? Almost got it to work but its not sending the F1-F3 keys right. I noticed you cant put a timer in an IF/THEN statement. Doesn&#39;t mention that in the help file, although the help file has been a very good reference.

Thanks for your time.

IF ( NOT B52 ) THEN //B52 will designate if we are in comms menu
SEQUENCE
CMS.B17=JS2.B9; //normal operation of hat ie ~, F7, F1, F12
CMS.B18=JS2.B10;
CMS.B19=JS2.B11;
CMS.B20=JS2.B12;
ENDSEQUENCE
ENDIF

// Look to see if comms has been activated (this happens with a quick press of B12 or "F12")

B99 = JS2.B12;
TIMER (PERIOD,D5,6) = B99; //Quick press timer for turning on comms menu

IF ( D5 AND NOT B99 AND NOT B52 ) THEN //Turn on comms mode if quick press detected on button F12 and we are not already in the comms menu
SEQUENCE
CMS.B14 = TRUE; //Open up the comms menu
B39 = FALSE; //Initialize button off
B50 = FALSE; //Make sure comms sent variable is set to FALSE
B52 = TRUE; //We are now in the comms menu
A9 = 0; //Set all button press counters to unpressed state
A10 = 0;
A11 = 0;
A12 = 0;
A19 = 0; //Button press indicators
A20 = 0;
A21 = 0;
A22 = 0;
ENDSEQUENCE
ENDIF

IF ( NOT B52 ) THEN
B51 = TRUE; //Prime inactivity timer
B53 = TRUE; //Prime button counting timer
ENDIF

TIMER (OFFDELAY,D6,100) = B51; //Initialize inactivity timer, if we are inactive for too long then we will exit the comms menu

IF ( B52 ) THEN //Comms menu interface activated
SEQUENCE
B53 = FALSE; //OK, let the comms menu control the timer now
B51 = D9; //Start overall comms menu inactivity timer when button counting timer goes FALSE

//Look for button presses on top front hat switch on joystick 2
B69 = JS2.B9; //Button 9 pressed
IF ( B69 AND NOT B39 ) THEN
SEQUENCE
A19 = A19 + 1;
B39 = TRUE; // We have pressed the button
ENDSEQUENCE
ELSE
SEQUENCE
IF (NOT B69 AND B39 ) THEN
SEQUENCE
A19 = 0; //Button no longer pressed
B39 = FALSE; //Button no longer pressed
ENDSEQUENCE
ENDIF
ENDSEQUENCE
ENDIF

B70 = JS2.B10; //Button 10 pressed
IF ( B70 ) THEN
A20 = A20 + 1; // We have pressed the button
ELSE
A20 = 0; //Button no longer pressed
ENDIF

B71 = JS2.B11; //Button 11 pressed
IF ( B71 ) THEN
A21 = A21 + 1; // We have pressed the button
ELSE
A21 = 0; //Button no longer pressed
ENDIF

B72 = JS2.B12; //Button 12 pressed
IF ( B72 ) THEN
A22 = A22 + 1; // We have pressed the button
ELSE
A22 = 0; //Button no longer pressed
ENDIF
ENDSEQUENCE
ENDIF

TIMER (OFFDELAY,D9,20) = B53 OR B69 OR B70 OR B71 OR B72; //Start timer for counting button presses, may have to setup individual timers for each button

IF ( B52 ) THEN //Comms menu interface activated
SEQUENCE
//Setup Menu Commands For Button 9
IF ( D9 AND [ A9 < 3 ]) THEN
SEQUENCE
IF ( [A19 == 1] ) THEN //Check to see if we should increment the counter (only count one button press though)
SEQUENCE
A9 = A9 + 1; //Increment A9
ENDSEQUENCE
ENDIF
ENDSEQUENCE
ELSE
SEQUENCE
IF ( [ A9 > 0 ] AND [ A10 == 0 ] AND [ A11 == 0 ] AND [ A12 == 0 ] ) THEN //Make sure no other buttons interupted selection
SEQUENCE
IF ( [ A9 == 1 ] ) THEN
SEQUENCE
B921 = TRUE;
A9 = 0; // Reset button presses number
B50 = TRUE; //Comms sent variable set to true
ENDSEQUENCE
ENDIF

IF ( [ A9 == 2 ] ) THEN
SEQUENCE
B922 = TRUE;
A9 = 0; // Reset button presses number
B50 = TRUE; //Comms sent variable set to true
ENDSEQUENCE
ENDIF

IF ( [ A9 == 3 ] ) THEN
SEQUENCE
B923 = TRUE;
A9 = 0; // Reset button presses number
B50 = TRUE; //Comms sent variable set to true
ENDSEQUENCE
ENDIF
ENDSEQUENCE
ELSE
SEQUENCE
DELAY (2);
A9 = 0; //A different button was pressed so we need to restart
A10 = 0;
A11 = 0;
A12 = 0;
ENDSEQUENCE
ENDIF
ENDSEQUENCE
ENDIF

//Setup Menu Commands For Button 10

//Setup Menu Commands For Button 11

//Setup Menu Commands For Button 12

ENDSEQUENCE
ENDIF

IF ( B921 ) THEN
SEQUENCE
CMS.B21 = TRUE;
DELAY ( 2 );
B921 = FALSE;
CMS.B21 = FALSE;
ENDSEQUENCE
ENDIF

IF ( B922 ) THEN
SEQUENCE
CMS.B22 = TRUE;
DELAY ( 2 );
B922 = FALSE;
CMS.B22 = FALSE;

ENDSEQUENCE
ENDIF

IF ( B923 ) THEN
SEQUENCE
CMS.B23 = TRUE;
DELAY ( 2 );
B923 = FALSE;
CMS.B23 = FALSE;
ENDSEQUENCE
ENDIF


IF ( B52 AND NOT D6 ) THEN //If inactivity timer goes false then close command menu
SEQUENCE
CMS.B14 = FALSE; //Close the comms menu
B52 = FALSE; //We are no longer in the comms menu
ENDSEQUENCE
ENDIF

MichaelCHProd
19th February 2004, 07:34 AM
Oh boy... :blink:

I think I am going wait for Bob to look at this before I venture in.

Fever
19th February 2004, 03:00 PM
I could probably simplify the code a great deal with a little more practice but i&#39;m not totally sure how all the commands work yet in terms of how the script proceeds after the command and how the keyboard recognizes the signals (ie the need for the delay command).

Also, it seemed the code behaved differently whether i had a B1 defined when im using CMS.B1 or whether i switched that B1 for a B69. Does the "B1" in CMS.B1 interfere with a stand alone B1 bit????????

i think i could simplify this statement with a wait command:

B70 = JS2.B10; //Button 10 pressed
IF ( B70 ) THEN
A20 = A20 + 1; // We have pressed the button
ELSE
A20 = 0; //Button no longer pressed
ENDIF


OK, Bob show me your magic tricks!!

Fever
19th February 2004, 06:59 PM
Im getting closer. F1, F2 and F3 are sent depending on how long i hold the button down (flick of button gets F1, a little longer gets F2...). Not what i want, i want the number of quick presses to determine what key to send. Looks like i need to add more delays in the script to slow things down. I&#39;ll attach my latest CMS file for those that are interested to look at.

JNOV
19th February 2004, 08:49 PM
Fever:

That&#39;s just about the most complicated script I&#39;ve ever seen -- definitely a candidate for some of CM3&#39;s labeling capabilities, just so you can keep straight what represents what!

I&#39;ve only a minute to look at your listing, but I&#39;ve a couple of observations:

1. I don&#39;t think that many of the sequence/endsequence strutcures you&#39;ve included are doing what you want (admittedly, I&#39;m not sure what you want, but I can&#39;t see that they&#39;re accompishing anything). As far as I can tell, most of the one ones in your script are unnecessary. Normally, I use sequence structures when the timing between outputs is important (like you do at the very bottom where you actually generate the keypresses).

2. Based on your description of what you&#39;re seeing and from my brief look at the script, I&#39;d bet that what&#39;s happening is that your button-press counter (A9) is being incremented multiple times while the button is held down. In other words, your timers are operating to increment the counter once every-so-often while the button is pressed. If so, what you might consider is tying the button presses to PULSE timers. PULSE timers are true for exactly one program scan when you press a button, so they would eliminate the problem of multiple counts per press.

Sorry I don&#39;t have more time right now to look at it. Good luck!

- JNOV

Fever
19th February 2004, 09:49 PM
Thanks for the input JNOV. I think i found the issue, i wasn&#39;t handling A19 well if it&#39;s value went over 1.

According to the HELP file in CM3 a PULSE command will flip a bit for one cycle when the button is pressed as well as when it&#39;s released... wouldn&#39;t that send 2 TRUE "commands" with one button plress/release?

I&#39;ll simplify the script with PULSE commands once i understand EXACTLY how they work.

Yes it&#39;s complicated, and i havent even added the functionality for the other 3 buttons yet :) but you can see the place holders in the script. I also have a few commands that arent in use that i will purge.

Bob Church
19th February 2004, 11:21 PM
You&#39;re right about the SEQUENCE/ENDSEQUENCE pairs, you don&#39;t need most of them. A SEQUENCE is only needed when you&#39;ve got a DELAY, WAIT, or WHILE statement between them. Otherwise they just make things more complex and when you put an IF/ENDIF around them they may stall in mid-sequence. It&#39;s best to avoid that situation unless you&#39;re really sure what it is that it&#39;s going to do for you.

WRT the rest of it, I&#39;m still trying to see your logic. It&#39;s sometimes hard to figure out what the other fellow was thinking when he wrote something. It&#39;s sometimes hard to figure out what I was thinking when I wrote something for that matter. :) take it this is trying to do what you described a few posts up-thread:

1. The hat normally sends four commands, one per position.

2. If you rapidly close one of the positions, it switches to a "mode" (not one of the CM modes) where you can click the hat 1, 2, or 3 times rapidly in any of the 4 positions and get one of three different commands.

3. A 3 rapid clicks on one of the positions (the one that switched modes in the first place) will put the hat back to the normal mode.

Is that right?

- Bob

The StickWorks
http://www.stickworks.com

Fever
20th February 2004, 12:39 AM
Got it working!!! You guys need to check this bad boy out! I simplified the script a little but it&#39;s still LONG.

OK, what the script does.

This is a script for LOMAC single player communications. It basically allows you to send F1-F12 and the "\" command menu key all from one hat.

Here&#39;s how it works.

The first "up" quick press of the top hat on the ProThrottle will send that top hat into an alternate mode specifically for single player comms to your wingman. I usually use this "up" hat button for TeamSpeak when playing online but in single player it&#39;s not needed. So i turned it into a "mode" key if you will for this particular hat.

Note holding down the "up" hat for more than 1/2 second will not trigger the mode and the hat will function normally. Basically if you are talking on line and using this "press to talk" button you wont be saying anything thats less than a 1/2 second long :).

OK, back to what the script does.

Now that we&#39;ve done our flick of the button and the "\" command menu key has been sent we can navigate through the single player menus by clicking the hat buttons in a certain way.

If you want F1, then click the forward hat button once
If you want F2, then click the forward hat button twice
If you want F3, then click the forward hat button three times (quickly of course)

If you dont click fast enough the script will asume you&#39;ve finished your selection and send the appropriate key.

OK, If you want F4-F6 the down hat button will do the work
If you want F7-F9 the back hat button will do the work
and if you want F10-F12 (F10 is actial a "\" command to exit the menu fast) then use the old trusty up hat button (the same one we quick clicked to get into this alternate hat mode"

Doing nothing for a period of time automatically exits you from the comand menu and the hat functions normally again :).

Of course, you have a lot of CMS buttons to program for the script to work but that should be obvious.

Any comments?






// Single Player Communications Menu
// Script for the single player communications menu in LOMAC, one hat control using virtual submode
// By: Mike Fiori
// Date:2/18/2004

IF ( NOT B52 ) THEN //B52 will designate if we are in comms menu
SEQUENCE
CMS.B17=JS2.B9; //normal operation of hat ie ~, F7, F1, F12
CMS.B18=JS2.B10;
CMS.B19=JS2.B11;
CMS.B20=JS2.B12;
ENDSEQUENCE
ENDIF

// Look to see if comms has been activated (this happens with a quick press of B12 or "F12")

B99 = JS2.B12;
TIMER (PERIOD,D5,6) = B99; //Quick press timer for turning on comms menu

IF ( D5 AND NOT B99 AND NOT B52 ) THEN //Turn on comms mode if quick press detected on button F12 and we are not already in the comms menu
SEQUENCE
B50 = FALSE; //Make sure comms sent variable is set to FALSE
A9 = 0; //Set all button press counters to unpressed state
A10 = 0;
A11 = 0;
A12 = 0;
A19 = 0; //Button press indicators
A20 = 0;
A21 = 0;
A22 = 0;
CMS.B14 = TRUE; //Open up the comms menu
DELAY (2); //Let things settle in before we change A states
CMS.B14 = FALSE;
B52 = TRUE; //We are now in the comms menu
ENDSEQUENCE
ENDIF

IF ( NOT B52 ) THEN
B51 = TRUE; //Prime inactivity timer
B53 = TRUE; //Prime button counting timer
ENDIF

TIMER (OFFDELAY,D6,100) = B51; //Initialize inactivity timer, if we are inactive for too long then we will exit the comms menu

IF ( B52 ) THEN //Comms menu interface activated
SEQUENCE
B53 = FALSE; //OK, let the comms menu control the timer now
B51 = D9; //Start overall comms menu inactivity timer when button counting timer goes FALSE

//Look for button presses on top front hat switch on joystick 2
B69 = JS2.B9; //Button 9 pressed
IF ( B69 ) THEN
A19 = A19 + 1;
ELSE
A19 = 0; //Button no longer pressed
ENDIF

B70 = JS2.B10; //Button 10 pressed
IF ( B70 ) THEN
A20 = A20 + 1; // We have pressed the button
ELSE
A20 = 0; //Button no longer pressed
ENDIF

B71 = JS2.B11; //Button 11 pressed
IF ( B71 ) THEN
A21 = A21 + 1; // We have pressed the button
ELSE
A21 = 0; //Button no longer pressed
ENDIF

B72 = JS2.B12; //Button 12 pressed
IF ( B72 ) THEN
A22 = A22 + 1; // We have pressed the button
ELSE
A22 = 0; //Button no longer pressed
ENDIF
ENDSEQUENCE
ENDIF

TIMER (OFFDELAY,D9,10) = ( B53 OR B69 OR B70 OR B71 OR B72 ); //Start timer for counting button presses, may have to setup individual timers for each button

IF ( B52 ) THEN //Comms menu interface activated
SEQUENCE

//Setup Menu Commands For Button 9
IF ( D9 AND [ A9 < 4 ]) THEN
SEQUENCE
IF ( [A19 == 1] ) THEN //Check to see if we should increment the counter (only count one button press though)
A9 = A9 + 1; //Increment A9
ENDIF
ENDSEQUENCE
ELSE
SEQUENCE
IF ( NOT D9 AND [ A19 == 0 ] AND [ A9 > 0 ] AND [ A10 == 0 ] AND [ A11 == 0 ] AND [ A12 == 0 ] ) THEN //Make sure no other buttons interupted selection
SEQUENCE
IF ( [ A9 == 1 ] ) THEN
SEQUENCE
B921 = TRUE;
DELAY (2); // Give A9 time before it&#39;s changed again
A9 = 0; // Reset button presses number
B50 = TRUE; //Comms sent variable set to true
ENDSEQUENCE
ENDIF

IF ( [ A9 == 2 ] ) THEN
SEQUENCE
B922 = TRUE;
DELAY (2); // Give A9 time before it&#39;s changed again
A9 = 0; // Reset button presses number
B50 = TRUE; //Comms sent variable set to true
ENDSEQUENCE
ENDIF

IF ( [ A9 == 3 ] ) THEN
SEQUENCE
B923 = TRUE;
DELAY (2); // Give A9 time before it&#39;s changed again
A9 = 0; // Reset button presses number
B50 = TRUE; //Comms sent variable set to true
ENDSEQUENCE
ENDIF
ENDSEQUENCE
ELSE
A9 = 0; //A different button was pressed so we need to restart
ENDIF
ENDSEQUENCE
ENDIF

//Setup Menu Commands For Button 10
IF ( D9 AND [ A10 < 4 ]) THEN
SEQUENCE
IF ( [A20 == 1] ) THEN //Check to see if we should increment the counter (only count one button press though)
A10 = A10 + 1; //Increment A10
ENDIF
ENDSEQUENCE
ELSE
SEQUENCE
IF ( NOT D9 AND [ A20 == 0 ] AND [ A9 == 0 ] AND [ A10 > 0 ] AND [ A11 == 0 ] AND [ A12 == 0 ] ) THEN //Make sure no other buttons interupted selection
SEQUENCE
IF ( [ A10 == 1 ] ) THEN
SEQUENCE
B924 = TRUE;
DELAY (2); // Give A10 time before it&#39;s changed again
A10 = 0; // Reset button presses number
B50 = TRUE; //Comms sent variable set to true
ENDSEQUENCE
ENDIF

IF ( [ A10 == 2 ] ) THEN
SEQUENCE
B925 = TRUE;
DELAY (2); // Give A10 time before it&#39;s changed again
A10 = 0; // Reset button presses number
B50 = TRUE; //Comms sent variable set to true
ENDSEQUENCE
ENDIF

IF ( [ A10 == 3 ] ) THEN
SEQUENCE
B926 = TRUE;
DELAY (2); // Give A10 time before it&#39;s changed again
A10 = 0; // Reset button presses number
B50 = TRUE; //Comms sent variable set to true
ENDSEQUENCE
ENDIF
ENDSEQUENCE
ELSE
A10 = 0;//A different button was pressed so we need to restart
ENDIF
ENDSEQUENCE
ENDIF

//Setup Menu Commands For Button 11
IF ( D9 AND [ A11 < 4 ]) THEN
SEQUENCE
IF ( [A21 == 1] ) THEN //Check to see if we should increment the counter (only count one button press though)
A11 = A11 + 1; //Increment A11
ENDIF
ENDSEQUENCE
ELSE
SEQUENCE
IF ( NOT D9 AND [ A21 == 0 ] AND [ A9 == 0 ] AND [ A10 == 0 ] AND [ A11 > 0 ] AND [ A12 == 0 ] ) THEN //Make sure no other buttons interupted selection
SEQUENCE
IF ( [ A11 == 1 ] ) THEN
SEQUENCE
B927 = TRUE;
DELAY (2); // Give A11 time before it&#39;s changed again
A11 = 0; // Reset button presses number
B50 = TRUE; //Comms sent variable set to true
ENDSEQUENCE
ENDIF

IF ( [ A11 == 2 ] ) THEN
SEQUENCE
B928 = TRUE;
DELAY (2); // Give A11 time before it&#39;s changed again
A11 = 0; // Reset button presses number
B50 = TRUE; //Comms sent variable set to true
ENDSEQUENCE
ENDIF

IF ( [ A11 == 3 ] ) THEN
SEQUENCE
B929 = TRUE;
DELAY (2); // Give A11 time before it&#39;s changed again
A11 = 0; // Reset button presses number
B50 = TRUE; //Comms sent variable set to true
ENDSEQUENCE
ENDIF
ENDSEQUENCE
ELSE
A11 = 0;//A different button was pressed so we need to restart
ENDIF
ENDSEQUENCE
ENDIF

//Setup Menu Commands For Button 12
IF ( D9 AND [ A12 < 4 ]) THEN
SEQUENCE
IF ( [A22 == 1] ) THEN //Check to see if we should increment the counter (only count one button press though)
A12 = A12 + 1; //Increment A12
ENDIF
ENDSEQUENCE
ELSE
SEQUENCE
IF ( NOT D9 AND [ A22 == 0 ] AND [ A9 == 0 ] AND [ A10 == 0 ] AND [ A11 == 0 ] AND [ A12 > 0 ] ) THEN //Make sure no other buttons interupted selection
SEQUENCE
IF ( [ A12 == 1 ] ) THEN
SEQUENCE
B930 = TRUE;
DELAY (2); // Give A12 time before it&#39;s changed again
A12 = 0; // Reset button presses number
B50 = TRUE; //Comms sent variable set to true
ENDSEQUENCE
ENDIF

IF ( [ A12 == 2 ] ) THEN
SEQUENCE
B931 = TRUE;
DELAY (2); // Give A12 time before it&#39;s changed again
A12 = 0; // Reset button presses number
B50 = TRUE; //Comms sent variable set to true
ENDSEQUENCE
ENDIF

IF ( [ A12 == 3 ] ) THEN
SEQUENCE
B932 = TRUE;
DELAY (2); // Give A9 time before it&#39;s changed again
A12 = 0; // Reset button presses number
B50 = TRUE; //Comms sent variable set to true
ENDSEQUENCE
ENDIF
ENDSEQUENCE
ELSE
A12 = 0; //A different button was pressed so we need to restart
ENDIF
ENDSEQUENCE
ENDIF


ENDSEQUENCE
ENDIF

IF ( B921 ) THEN
SEQUENCE
CMS.B21 = TRUE;
DELAY ( 2 );
B921 = FALSE;
CMS.B21 = FALSE;
ENDSEQUENCE
ENDIF

IF ( B922 ) THEN
SEQUENCE
CMS.B22 = TRUE;
DELAY ( 2 );
B922 = FALSE;
CMS.B22 = FALSE;
ENDSEQUENCE
ENDIF

IF ( B923 ) THEN
SEQUENCE
CMS.B23 = TRUE;
DELAY ( 2 );
B923 = FALSE;
CMS.B23 = FALSE;
ENDSEQUENCE
ENDIF

IF ( B924 ) THEN
SEQUENCE
CMS.B24 = TRUE;
DELAY ( 2 );
B924 = FALSE;
CMS.B24 = FALSE;
ENDSEQUENCE
ENDIF

IF ( B925 ) THEN
SEQUENCE
CMS.B25 = TRUE;
DELAY ( 2 );
B925 = FALSE;
CMS.B25 = FALSE;
ENDSEQUENCE
ENDIF

IF ( B926 ) THEN
SEQUENCE
CMS.B26 = TRUE;
DELAY ( 2 );
B926 = FALSE;
CMS.B26 = FALSE;
ENDSEQUENCE
ENDIF

IF ( B927 ) THEN
SEQUENCE
CMS.B27 = TRUE;
DELAY ( 2 );
B927 = FALSE;
CMS.B27 = FALSE;
ENDSEQUENCE
ENDIF

IF ( B928 ) THEN
SEQUENCE
CMS.B28 = TRUE;
DELAY ( 2 );
B928 = FALSE;
CMS.B28 = FALSE;
ENDSEQUENCE
ENDIF

IF ( B929 ) THEN
SEQUENCE
CMS.B29 = TRUE;
DELAY ( 2 );
B929 = FALSE;
CMS.B29 = FALSE;
ENDSEQUENCE
ENDIF

IF ( B930 ) THEN
SEQUENCE
CMS.B30 = TRUE;
DELAY ( 2 );
B930 = FALSE;
CMS.B30 = FALSE;
ENDSEQUENCE
ENDIF

IF ( B931 ) THEN
SEQUENCE
CMS.B31 = TRUE;
DELAY ( 2 );
B931 = FALSE;
CMS.B31 = FALSE;
ENDSEQUENCE
ENDIF

IF ( B932 ) THEN
SEQUENCE
CMS.B32 = TRUE;
DELAY ( 2 );
B932 = FALSE;
CMS.B32 = FALSE;
ENDSEQUENCE
ENDIF


IF ( B52 AND NOT D6 ) THEN //If inactivity timer goes false then close command menu
SEQUENCE
CMS.B14 = TRUE;
DELAY ( 2 );
CMS.B14 = FALSE; //Close the comms menu
B52 = FALSE; //We are no longer in the comms menu
ENDSEQUENCE
ENDIF

MichaelCHProd
20th February 2004, 01:12 AM
That is some wicked scripting. Nice work. :D

JNOV
20th February 2004, 07:53 AM
Very nice, Fever! I&#39;d never thought of putting multiple time-parsed events on a single, unshifted key. (Frankly, I&#39;m not sure I&#39;m coordinated enough to get three quick clicks in on a regular basis, but two seems quite doable.) Your scheme is very efficient in terms of button space--throw in some shift keys and you&#39;ve got a ridiculous number of functions on a single hat! You could probably program the entirety of the most complex single-player command tree on one hat.

I may just "adapt" it for my own use in the future! Thanks for the great idea!

- JNOV

Fever
20th February 2004, 01:32 PM
Thanks for the comments, it still needs a little tweeking on menu exit and resetting the count if a different key is pressed other than the one you started with and the quick press timer is still true (whew, takes a breath). I&#39;ll have it dialed in in a few days. In the mean time maybe some of the experts could help me get the code length down a bit. Maybe some nexted IF/THEN statements or some other PULSE tricks.

I have asked a few questions further up in the thread that i didnt see any answers too yet, please scan back if you have time.

Fever

Fever
20th February 2004, 11:37 PM
All done. Deleted all the SEQUENCEs i didnt need. Had to remove the auto exit because sometimes the menu exits for you. Hope this is useful to someone besides myself.

// Single Player Communications Menu
// Script for the single player communications menu in LOMAC, one hat control using virtual submode
// By: Mike Fiori
// Date:2/20/2004

IF ( NOT B52 ) THEN //B52 will designate if we are in comms menu
CMS.B17=JS2.B9; //normal operation of hat ie ~, F7, F1, F12
CMS.B18=JS2.B10;
CMS.B19=JS2.B11;
CMS.B20=JS2.B12;
ENDIF

// Look to see if comms has been activated (this happens with a quick press of B12 or "F12")

B99 = JS2.B12;
TIMER (PERIOD,D5,4) = B99; //Quick press timer for turning on comms menu

IF ( D5 AND NOT B99 AND NOT B52 ) THEN //Turn on comms mode if quick press detected on button F12 and we are not already in the comms menu
SEQUENCE
A9 = 0; //Set all button press counters to unpressed state
A10 = 0;
A11 = 0;
A12 = 0;
A19 = 0; //Button press indicators
A20 = 0;
A21 = 0;
A22 = 0;
A25 = 0; //Command interupt counters
A26 = 0;
A27 = 0;
A28 = 0;
A29 = 0; //Overall command interupt bit used to check for different button presses

CMS.B14 = TRUE; //Open up the comms menu
DELAY (2); //Let things settle in before we change A states
CMS.B14 = FALSE;

B52 = TRUE; //We are now in the comms menu

ENDSEQUENCE
ENDIF

IF ( NOT B52 ) THEN
//Disabled B51 = TRUE; //Prime inactivity timer
B53 = TRUE; //Prime button counting timer
ENDIF

// Disabled TIMER (OFFDELAY,D6,100) = B51; //Initialize inactivity timer, if we are inactive for too long then we will exit the comms menu

IF ( B52 ) THEN //Comms menu interface activated
B53 = FALSE; //OK, let the comms menu control the timer now
// Disabled B51 = D9; //Start overall comms menu inactivity timer when button counting timer goes FALSE

//Look for button presses on top front hat switch on joystick 2
IF ( JS2.B9 ) THEN //Button 9 pressed
A19 = A19 + 1;
ELSE
A19 = 0; //Button no longer pressed
ENDIF

IF ( JS2.B10 ) THEN //Button 10 pressed
A20 = A20 + 1; // We have pressed the button
ELSE
A20 = 0; //Button no longer pressed
ENDIF

IF ( JS2.B11 ) THEN //Button 11 pressed
A21 = A21 + 1; // We have pressed the button
ELSE
A21 = 0; //Button no longer pressed
ENDIF

IF ( JS2.B12 ) THEN //Button 12 pressed
A22 = A22 + 1; // We have pressed the button
ELSE
A22 = 0; //Button no longer pressed
ENDIF
ENDIF

TIMER (OFFDELAY,D9,15) = ( B53 OR JS2.B9 OR JS2.B10 OR JS2.B11 OR JS2.B12 ); //Start timer for counting button presses, may have to setup individual timers for each button

IF ( B52 ) THEN //Comms menu interface activated

//Setup Menu Commands For Button 9
IF ( D9 AND [ A9 < 4 ]) THEN
IF ( [A19 == 1] ) THEN //Check to see if we should increment the counter (only count one button press though)
A9 = A9 + 1; //Increment A9
ENDIF

IF ( [ A9 > 0 ] ) THEN //This is a bit for command interupt checking
A25 = 1; //maybe try pulse here
ENDIF
ELSE
IF ( NOT D9 AND [ A9 > 0 ] AND [ A10 == 0 ] AND [ A11 == 0 ] AND [ A12 == 0 ] ) THEN //Make sure no other buttons interupted selection
IF ( [ A9 == 1 ] ) THEN
B921 = TRUE;
A9 = 0; // Reset button presses number
ENDIF

IF ( [ A9 == 2 ] ) THEN
B922 = TRUE;
A9 = 0; // Reset button presses number
ENDIF

IF ( [ A9 == 3 ] ) THEN
B923 = TRUE;
A9 = 0; // Reset button presses number
ENDIF

A25 = 0;// A command was sent so we need to reset this interupt bit
A29 = 0;// Reset overall interupt bit
ELSE
A9 = 0; //A different button was pressed so we need to restart
ENDIF
ENDIF

//Setup Menu Commands For Button 10
IF ( D9 AND [ A10 < 4 ]) THEN
IF ( [A20 == 1] ) THEN //Check to see if we should increment the counter (only count one button press though)
A10 = A10 + 1; //Increment A10
ENDIF

IF ( [ A10 > 0 ] ) THEN //This is a bit for command interupt checking
A26 = 1;
ENDIF
ELSE
IF ( NOT D9 AND [ A9 == 0 ] AND [ A10 > 0 ] AND [ A11 == 0 ] AND [ A12 == 0 ] ) THEN //Make sure no other buttons interupted selection
IF ( [ A10 == 1 ] ) THEN
B924 = TRUE;
A10 = 0; // Reset button presses number
ENDIF

IF ( [ A10 == 2 ] ) THEN
B925 = TRUE;
A10 = 0; // Reset button presses number
ENDIF

IF ( [ A10 == 3 ] ) THEN
B926 = TRUE;
A10 = 0; // Reset button presses number
ENDIF

A26 = 0;// A command was sent so we need to reset this interupt bit
A29 = 0;// Reset overall interupt bit
ELSE
A10 = 0;//A different button was pressed so we need to restart
ENDIF
ENDIF

//Setup Menu Commands For Button 11
IF ( D9 AND [ A11 < 4 ]) THEN
IF ( [A21 == 1] ) THEN //Check to see if we should increment the counter (only count one button press though)
A11 = A11 + 1; //Increment A11
ENDIF

IF ( [ A11 > 0 ] ) THEN //This is a bit for command interupt checking
A27 = 1;
ENDIF
ELSE
IF ( NOT D9 AND [ A9 == 0 ] AND [ A10 == 0 ] AND [ A11 > 0 ] AND [ A12 == 0 ] ) THEN //Make sure no other buttons interupted selection
IF ( [ A11 == 1 ] ) THEN
B927 = TRUE;
A11 = 0; // Reset button presses number
ENDIF

IF ( [ A11 == 2 ] ) THEN
B928 = TRUE;
A11 = 0; // Reset button presses number
ENDIF

IF ( [ A11 == 3 ] ) THEN
B929 = TRUE;
A11 = 0; // Reset button presses number
ENDIF

A27 = 0;// A command was sent so we need to reset this interupt bit
A29 = 0;// Reset overall interupt bit
ELSE
A11 = 0;//A different button was pressed so we need to reset the button press count
ENDIF
ENDIF

//Setup Menu Commands For Button 12
IF ( D9 AND [ A12 < 4 ]) THEN
IF ( [A22 == 1] ) THEN //Check to see if we should increment the counter (only count one button press though)
A12 = A12 + 1; //Increment A12
ENDIF

IF ( [ A12 > 0 ] ) THEN //This is a bit for command interupt checking
A28 = 1;
ENDIF
ELSE
IF ( NOT D9 AND [ A9 == 0 ] AND [ A10 == 0 ] AND [ A11 == 0 ] AND [ A12 > 0 ] ) THEN //Make sure no other buttons interupted selection
IF ( [ A12 == 1 ] ) THEN
B930 = TRUE;
A12 = 0; // Reset button presses number
ENDIF

IF ( [ A12 == 2 ] ) THEN
B931 = TRUE;
A12 = 0; // Reset button presses number
ENDIF

IF ( [ A12 == 3 ] ) THEN
B932 = TRUE;
A12 = 0; // Reset button presses number
ENDIF

A28 = 0;// A command was sent so we need to reset this interupt bit
A29 = 0;// Reset overall interupt bit
ELSE
A12 = 0;//A different button was pressed so we need to reset the button press count
ENDIF
ENDIF
ENDIF

//Start the interupt bit if a button was pressed
IF ( NOT [ ( A25 + A26 + A27 + A28 ) == 0 ] ) THEN
A29 = 1;
ENDIF

//Check to see if 2 differenet buttons were pressed
IF ( NOT [ A29 == ( A25 + A26 + A27 + A28 ) ] ) THEN
A9 = 0; //OK, A command was interupted with a different button press so reset everything
A10 = 0;
A11 = 0;
A12 = 0;
A25 = 0;
A26 = 0;
A27 = 0;
A28 = 0;
A29 = 0;
ENDIF

IF ( B921 ) THEN
SEQUENCE
CMS.B21 = TRUE;
DELAY ( 2 );
CMS.B21 = FALSE;
B921 = FALSE;
ENDSEQUENCE
ENDIF

IF ( B922 ) THEN
SEQUENCE
CMS.B22 = TRUE;
DELAY ( 2 );
CMS.B22 = FALSE;
B922 = FALSE;
ENDSEQUENCE
ENDIF

IF ( B923 ) THEN
SEQUENCE
CMS.B23 = TRUE;
DELAY ( 2 );
CMS.B23 = FALSE;
B923 = FALSE;
ENDSEQUENCE
ENDIF

IF ( B924 ) THEN
SEQUENCE
CMS.B24 = TRUE;
DELAY ( 2 );
CMS.B24 = FALSE;
B924 = FALSE;
ENDSEQUENCE
ENDIF

IF ( B925 ) THEN
SEQUENCE
CMS.B25 = TRUE;
DELAY ( 2 );
CMS.B25 = FALSE;
B925 = FALSE;
ENDSEQUENCE
ENDIF

IF ( B926 ) THEN
SEQUENCE
CMS.B26 = TRUE;
DELAY ( 2 );
CMS.B26 = FALSE;
B926 = FALSE;
ENDSEQUENCE
ENDIF

IF ( B927 ) THEN
SEQUENCE
CMS.B27 = TRUE;
DELAY ( 2 );
CMS.B27 = FALSE;
B927 = FALSE;
ENDSEQUENCE
ENDIF

IF ( B928 ) THEN
SEQUENCE
CMS.B28 = TRUE;
DELAY ( 2 );
CMS.B28 = FALSE;
B928 = FALSE;
ENDSEQUENCE
ENDIF

IF ( B929 ) THEN
SEQUENCE
CMS.B29 = TRUE;
DELAY ( 2 );
CMS.B29 = FALSE;
B929 = FALSE;
ENDSEQUENCE
ENDIF

IF ( B930 ) THEN
SEQUENCE
CMS.B30 = TRUE;
DELAY ( 2 );
CMS.B30 = FALSE;
B930 = FALSE;
B52 = FALSE; //We are no longer in the comms menu
ENDSEQUENCE
ENDIF

IF ( B931 ) THEN
SEQUENCE
CMS.B31 = TRUE;
DELAY ( 2 );
CMS.B31 = FALSE;
B931 = FALSE;
ENDSEQUENCE
ENDIF

IF ( B932 ) THEN
SEQUENCE
CMS.B32 = TRUE;
DELAY ( 2 );
CMS.B32 = FALSE;
B932 = FALSE;
ENDSEQUENCE
ENDIF

Fever
21st February 2004, 04:59 PM
New and improved!! Final version.

Fever
21st February 2004, 06:52 PM
OK :) final final version. Because LOMAC exits the comms menu automatically after a command is sent you have to "exit" the script so the hat returns to normal. I do this by quick clicking my shift button on my joystick (JS1.B6). If no command is sent and you are just browsing the command menu and you exit with F12 or "\" (3 and one quick press on the up hat button) then you dont need to hit the shift button. This is not for your average gamer, if the LOMAC command menu was set up better then the script would be much simpler. ENJOY!!

Bob Church
22nd February 2004, 07:12 AM
The little zip that&#39;s attached to this has a MAP and CMS file in it that does something similar to what yours does. Basically, you can click Hat 1 one, two, or three times in any direction and get one of 12 commands (currently "a" through "l") preceded by a "/" character. If you hold the hat in one position for a longer time, you&#39;ll get a "w", "x", "y", or "z", corresponding to the normal commands. There are some simplifications and so some differences, though.

Only the direction of the last hat click makes any difference in the message. Other clicks can go any direction at all. For example, if the 3rd command (3 clicks) on Hat 1 Up were what you wanted to send, the first two clicks could be Hat 1 Left and Hat 1 Right, it wouldn&#39;t matter so long as the last click is Hat 1 Up. It&#39;s a simplification in that it lets the script watch the hat center button (js1.b21) and saves having to check all four directions since it doesn&#39;t really care which way it went except on the last click and that&#39;s recorded elsewhere.

Another simplification (not always usable) is that it doesn&#39;t use CMS.Bx outputs and you don&#39;t have to deal with those each time. Instead it converts the click count and direction into a number between 0 and 15, then multiplies and offsets that to produce one of 16 values between 0 and 255. That value is passed to CMS.A1 which is programmed with a "Position" statement that has command characters for the 16 positions that the script will produce. The value passed from the CMS file ends up selecting which one of them gets sent and the Position statement takes care of the rest.

Anyway, the CMS file ends up only being about 70 lines of actual code. I don&#39;t have LOMAC so it&#39;s just sort of an academic exercise here, I don&#39;t know if it will do everything you need done, but I thought some of it might be interesting. The map is set up for just a FighterStick, run it in the KeyTest utility and you can see everything that it does.

- Bob

The StickWorks
http://www.stickworks.com

Fever
22nd February 2004, 03:43 PM
Thanks Bob. I downloaded your script and will check it out this week. I really like the idea of using positional keys on an axis and the "last" click direction being important as well.

Could you answer this question for me??

According to the HELP file in CM3 a PULSE command will flip a bit for one cycle when the button is pressed as well as when it&#39;s released... wouldn&#39;t that send 2 TRUE "commands" with one button plress/release?

Bob Church
22nd February 2004, 05:04 PM
I saw you(?) mention the PULSE thing the other day and meant to respond then. It only changes state when it goes to TRUE, not when it goes to FALSE. It automatically turns FALSE after one loop regardless of the state of the input. I went back and looked at the Users&#39; Guide and that&#39;s what it says, too, but then it may just be a case of me knowing what I meant. :) Which part seems to indicate that it flips on both transitions?

WRT the Position thing handling the characters, I thought it was kind of a neat way to handle it too. I&#39;d thought earlier that it would be possible to control an axis in the script and then program it up in the GUI but I&#39;d never really had occasion to do it. Anyway, maybe it&#39;ll simplify it a bit.

- Bob

The StickWorks
http://www.stickworks.com

Fever
22nd February 2004, 09:08 PM
Pulse Device

The sixth type of device is the "Pulse" device. It sets it&#39;s Device Variable TRUE when it&#39;s input turns TRUE. On the next loop through the script, the Device Variable is set FALSE and will remain FALSE until the input goes FALSE and then turns TRUE again.

I copied this from the help section. I see what you are saying now. I took the last section of the last sentence (turns TRUE again) to mean it affected the device variable in the beginning of the sentence. You of course were referring to the input.

We are on the same page now :).

Thanks for replying.

Bob Church
23rd February 2004, 12:25 AM
>> I took the last section of the last sentence (turns TRUE again) to mean it affected the device variable in the beginning of the sentence. <<

Ah. Yes, I see what you mean, it is kind of ambiguously stated. I&#39;ll clarify it a bit for the next go-round.

Thanks!

- Bob

The StickWorks
http://www.stickworks.com