Pablo's Beginners Guide to Scripting for PC

Tutorials, How-tos and FAQs for the Titan Two device.

Pablo's Beginners Guide to Scripting for PC

Postby pablosscripts » Mon May 20, 2019 3:59 am

I've just finished working on my first PC script and I thought I might document some of the things I've learned along the way for others to benefit from. This is by no means comprehensive as I'm just a beginner myself but it may be just enough to help you get a jump on the learning curve.

WHY T2?

Macros have been around on PC since the dawn of time, so why the T2? There are two main reasons:

1) Software based scripting is the most common approach, but this won't take you far as it's highly likely you'll be caught by anti-cheating software.

2) Hardware based scripting is generally very simple. If you own a Logitech mouse or keyboard for example, just take a look at the options available - they're extremely primative. You can record button presses and set interval times, but that's pretty much the extent of it. Simple hardware based scripting is also likely to be caught by anti-cheating software. Let's take the example of a rapid fire macro: hold button for X seconds, release button for Y seconds. The X and Y variables are static - anything highly predictable like this will set of all sorts of red flags.

In contrast, Titan Two is hardware based and is also sophisticated enough to support logic that will outsmart any anti-cheat heuristics. In the example above, you could randomise the X and Y values, which you can't do with very simple macros.

BEFORE YOU EVEN START CODING

I have added a template to the Online Resources page for you to download, called "PC Script Template" (https://www.consoletuner.com/greslib/?w675). I will break it down in more detail below:

The first thing you need to do is add the following headers:

Code: Select all
#include <keyboard.gph>
#include <mouse.gph>


And in your init block, add this:

Code: Select all
init {
    keymapping();
       mousemapping();
}


And in your main block, add this:

Code: Select all
main {
    key_passthru();
    mouse_passthru();
}


The next thing you need to do is to set your output to HID (via the "Device Configuration" tab), however be warned: if you are using the T2 primarily on consoles (which I assume most of you will), then if you forget to change your the output protocol back you may spend a lot of time scratching your head wondering why your T2 doesn't work anymore. It's also just annoying having to change your protocol every time you switch between them. The smarter option is to dynamically change your output protocol when using a script designed for PC, which you can do by adding the following code to the init block:

Code: Select all
port_connect(PORT_USB_C, PROTOCOL_HID);


KEY DESIGNATORS / MAPPINGS

See the following links for key mappings:

Keyboard: https://www.consoletuner.com/wiki/index ... yboard_gph
Mouse: https://www.consoletuner.com/wiki/index ... :mouse_gph

Mouse mappings are a little more confusing, so here's how to use them: [COMING SOON, WORK IN PROGRESS]

TIME TO START CODING

Ok to start with, there are two things you should know:

1) The set of functions available for PC are much more limited. You don't have the benefit of functions like get_val() or event_active(), there are only a basic set of functions and if you need more sophisticated data manipulations then you will need to code them yourself, or use a library like xkeys.gph. You should note that xkeys still has its limitations (only supports keyboard but not mice). I'm hoping the suite of functions will expand over time, but for now a bit of DIY is required.

If you are not using something like xkeys.gph, the most basic code pattern you need to read an input event is as follows:

Code: Select all
if(key_status(KEY_R)) {
    if(is_pressed) {
        // Code here.
        is_pressed = 0;
    }
} else {
    is_pressed = 1;
}


2) Keyboard and mouse inputs are handled via different functions. On console, you can use the get_val() function for every single button, however on PC there is a distinct set for keyboard (key_status()) and a set for mouse (mouse_status()). This is important to remember because when I first started I kept changing my in-game button mappings, switching them from mouse to keyboard and so forth, and I kept forgetting to change this in my code as well...this lead to a lot of initial confusion! J2Kbr helped me write a function to abstract this but unfortunately it had a lot of performance issues when I tried to use it on a large scale (viewtopic.php?f=26&t=12506). I will update this post if it improves over time.

ANTI-CHEAT

There are two things you need to be actively thinking about when writing your scripts to avoid being banned:

1) Avoid long sequences of button presses. Spamming huge strings of rapid and identical button presses will raise red flags.

2) You need to make sure you randomise almost all your variables. I created the following function - it is based on the original T1 irand() function but I have customised it to be easier to use (you only need to pass it one value instead of two, which will save you a lot of headache if you are using this on a mass scale):

Code: Select all
int irand(int scramble) {
    fix32 fraction = (fix32) scramble * 0.10;
    int vmin = scramble - (int) fraction;
    int vmax = scramble + (int) fraction;
    return(((int)(rand() * (fix32)(vmax + 1 - vmin))) + vmin);
}


This function takes a value, returns a slightly randomised version of the original number (within a 10% window).

And this is an example use of it:

Code: Select all
combo ExampleCombo1 {
    // Code here.
    wait(irand(66));
}


Because it's using a percentage, the larger the number is, the larger the range will be, so if the number you are randomising needs to be relatively precise, then you can use something like this:

Code: Select all
combo ExampleCombo2 {
    wait(7000 + irand(55));
}


It's critical that you are constantly checking and double checking to make sure you have randomised most if not all your wait times. This is not like developing on console - PC is a whole different ball game as far as cheat detection goes. If you're feeling paranoid, you should be. Check, check and re-check!

CONFIGURABLE KEY MAPPINGS

Unlike console, the likelihood of the player remapping their keys is extremely high. Therefore there is a need to provide users with the ability to easily align their T2 key mappings with their in-game key mappings. Because this takes up a LOT of space and makes the code difficult to read, this will not be included in my main script template. Instead I have created a brand new template for you to study / use, called "PC Interactive Configurator Key Remapping Template" [COMING SOON, WORK IN PROGRESS].

DEBUGGING

The other area where T2 development on PC is lacking compared to console is the Device Monitor. On console you can monitor the outputs very easily however with PC development you will need to manually add printf statements, or use a separate key press detection app to monitor the outputs of your script (e.g. http://keyboardchecker.com). A simple text editor like Notepad will not suffice because some button presses will not provide any tangible outputs (e.g. shift). The other reason why Notepad will not be sufficient is because it will not tell you if you are rapidly pressing a button versus holding it. Try it out - in Notepad, hold down the "A" key, and compare it with rapidly tapping the "A" key - the output is identical. This means if you have a bug in your script that causes it to rapidly tap a button instead of holding it you may NOT EVEN BE AWARE because may function perfectly, but this may get you banned by anti-cheat software so you need to be very vigilant when testing.

TYPING MODE

As you will likely be switching back and forth between your game and Windows, PC based scripts require what I call "Typing Mode". This mode prevents your script from executing when you are trying to type an in-game message or navigate Windows. For example, if you are trying to type a message, you wouldn't want a feature like Easy Sprint to kick in otherwise every time you press the W button you will continually activate the sprint button. You will also benefit from a visual indicator that you are in Typing Mode - I've made use of the Titan Two's LCD screen for this but you can do this in anyway that you want.

QUALITY OF LIFE

I encourage you to use scripting on PC to make quality of life enhancements only. Use it to refine the gameplay and / or assist people with disabilities. On console, I have a personal view that scripting should be about QoL, but if someone uses it to take advantage of an exploit or for farming, I may not like it, but I generally won't say a thing. On PC however I'm taking a different stance. If you use this to develop cheats or exploits then I'm sorry but you will not get any assistance from me. If T2 becomes known as an exploit device, developers will begin actively trying to detect and ban it and that's not even to speak of the reputational damage to the brand and community. It's important to note that these are my own personal views and not the company's official stance.

I hope some of you find this useful.
Setup: XIM Apex, T2, K780 keyboard, G Pro Wireless mouse, SteelSeries 4HD pad, DXRacer armrest, LucidSound LS30 headset, Netduma router, Ubiquiti UniFi AP LR

My R6 script: https://youtu.be/x-9NtxyySVM
User avatar
pablosscripts
Brigadier General
Brigadier General
 
Posts: 1976
Joined: Tue Nov 24, 2015 6:27 am

Re: Pablo's Beginners Guide to Scripting for PC

Postby J2Kbr » Mon May 20, 2019 11:42 am

Great Tutorial Pablo. Post Sticked. :smile0517:
ConsoleTuner Support Team
User avatar
J2Kbr
General of the Army
General of the Army
 
Posts: 20323
Joined: Tue Mar 18, 2014 1:39 pm

Re: Pablo's Beginners Guide to Scripting for PC

Postby pablosscripts » Mon May 20, 2019 1:05 pm

J2Kbr wrote:Great Tutorial Pablo. Post Sticked. :smile0517:


Thanks:)

Note to everyone: feel free to contribute to this. I will keep updating the OP so we can make this a comprehensive beginners guide.
Setup: XIM Apex, T2, K780 keyboard, G Pro Wireless mouse, SteelSeries 4HD pad, DXRacer armrest, LucidSound LS30 headset, Netduma router, Ubiquiti UniFi AP LR

My R6 script: https://youtu.be/x-9NtxyySVM
User avatar
pablosscripts
Brigadier General
Brigadier General
 
Posts: 1976
Joined: Tue Nov 24, 2015 6:27 am

Re: Pablo's Beginners Guide to Scripting for PC

Postby UK_Wildcats » Tue May 21, 2019 1:58 am

Great tutorial
User avatar
UK_Wildcats
Brigadier General
Brigadier General
 
Posts: 2243
Joined: Thu Jan 08, 2015 6:53 pm

Re: Pablo's Beginners Guide to Scripting for PC

Postby pablosscripts » Tue May 21, 2019 2:56 pm

Thanks:)

UPDATE v1.1: I've updated the template with a contribution from Scachi (simplified the automatic setting of the output protocol).
Setup: XIM Apex, T2, K780 keyboard, G Pro Wireless mouse, SteelSeries 4HD pad, DXRacer armrest, LucidSound LS30 headset, Netduma router, Ubiquiti UniFi AP LR

My R6 script: https://youtu.be/x-9NtxyySVM
User avatar
pablosscripts
Brigadier General
Brigadier General
 
Posts: 1976
Joined: Tue Nov 24, 2015 6:27 am

Re: Pablo's Beginners Guide to Scripting for PC

Postby pablosscripts » Wed May 22, 2019 7:49 am

UPDATE v1.2: Well this is really embarrassing, I forgot to add the HID pass-through code to both the template as well as this guide, so none of it would have worked. I've fixed this!
Setup: XIM Apex, T2, K780 keyboard, G Pro Wireless mouse, SteelSeries 4HD pad, DXRacer armrest, LucidSound LS30 headset, Netduma router, Ubiquiti UniFi AP LR

My R6 script: https://youtu.be/x-9NtxyySVM
User avatar
pablosscripts
Brigadier General
Brigadier General
 
Posts: 1976
Joined: Tue Nov 24, 2015 6:27 am

Re: Pablo's Beginners Guide to Scripting for PC

Postby TopSteer » Thu May 30, 2019 5:31 am

Great post, Pablo! :smile0517:
I have been wondering about a lot of the things you brought up in here, so I appreciate you shedding some light on things like the passthru, portconnect and keystatus functions.
:smile0202:
Wheels: :smile0902:
Logitech G29 (released 2015) with Driving Force Shifter
Thrustmaster Ferrari Red Legend Edition (released 2013)
Logitech Driving Force (released 2002)
User avatar
TopSteer
Sergeant First Class
Sergeant First Class
 
Posts: 20
Joined: Thu Jun 07, 2018 4:23 am

Re: Pablo's Beginners Guide to Scripting for PC

Postby Buffy » Thu May 30, 2019 7:54 am

Here's a full way to track timings + release/active events for keys/mouse buttons:


Code: Select all
 
#ifndef __KBM_EVENTS_GPH__
#define __KBM_EVENTS_GPH__
 
#include <keyboard.gph>
#include <mouse.gph>
 
#pragma region EXTRA_BUTTONS_LIST //{ - copy/paste into your script before including this header
 
#define EXTRA_MOUSE_INPUT                    232
 
#ifndef EXTRA_KEY_VAR
    #define EXTRA_KEY_VAR        extra_keys_list
    uint8 EXTRA_KEY_VAR[] = {
        MBUTTON_1 |  EXTRA_MOUSE_INPUT,
        KEY_W,
    };
#endif
 
#pragma endregion //}
 
#define _NUM_OF_EXTRA_KEYS    sizeof(EXTRA_KEY_VAR)
 
#define _EXTRA_KEY_STATUS_RELEASED                1
#define _EXTRA_KEY_STATUS_JUST_RELEASED               3
#define _EXTRA_KEY_STATUS_PRESSED                4
#define _EXTRA_KEY_STATUS_JUST_PRESSED            12
 
uint8 extra_keys_status[_NUM_OF_EXTRA_KEYS], _extra_key_i;
uint32 extra_keys_status_press_time[_NUM_OF_EXTRA_KEYS];
uint32 extra_keys_status_rel_time[_NUM_OF_EXTRA_KEYS];
 
init {
    memset(&extra_keys_status, 1, _NUM_OF_EXTRA_KEYS);
}
 
main {
    if(is_extra_button_active(EXTRA_KEY_VAR[_extra_key_i]))  {
        if(extra_keys_status[_extra_key_i] & _EXTRA_KEY_STATUS_RELEASED) {
            extra_keys_status[_extra_key_i] = _EXTRA_KEY_STATUS_JUST_PRESSED;
            extra_keys_status_press_time[_extra_key_i] = system_time();
        }
    }
    else {
        if(extra_keys_status[_extra_key_i] & _EXTRA_KEY_STATUS_PRESSED) {
            extra_keys_status[_extra_key_i] = _EXTRA_KEY_STATUS_JUST_RELEASED;
            extra_keys_status_rel_time[_extra_key_i] = system_time();
        }
    }
    extra_keys_status[(_extra_key_i ? (_extra_key_i - 1) : (_NUM_OF_EXTRA_KEYS - 1))] &= 5;
    _extra_key_i = ((_extra_key_i + 1) % _NUM_OF_EXTRA_KEYS);
}
 
uint8 get_key_index(uint8 key) {
    uint8 _extra_key_idx_i = (_NUM_OF_EXTRA_KEYS - 1);
    for( ; _extra_key_idx_i > 0; _extra_key_idx_i--) {
        if(EXTRA_KEY_VAR[_extra_key_idx_i] == key) break;
    }
    return _extra_key_idx_i;
}
 
bool is_extra_button_active(uint8 button) {
    return ((button >= EXTRA_MOUSE_INPUT) ? mouse_status(button - EXTRA_MOUSE_INPUT) : key_status(button));
}
 
bool key_event_active(uint8 key) {
    return (is_extra_button_active(key)) && (extra_keys_status[get_key_index(key)] == _EXTRA_KEY_STATUS_JUST_PRESSED);
}
 
bool key_event_release(uint8 key) {
    return (!is_extra_button_active(key)) && (extra_keys_status[get_key_index(key)] == _EXTRA_KEY_STATUS_JUST_RELEASED);
}
 
uint32 key_time_active(uint8 key) {
    uint8 idx = get_key_index(key);
    return ((extra_keys_status[idx] & _EXTRA_KEY_STATUS_PRESSED) ? system_time() : extra_keys_status_rel_time[idx]) - extra_keys_status_press_time[idx];
}
 
uint32 key_time_release(uint8 key) {
    uint8 idx = get_key_index(key);
    return ((extra_keys_status[idx] & _EXTRA_KEY_STATUS_PRESSED) ? extra_keys_status_press_time[idx] : system_time()) - extra_keys_status_rel_time[idx];
}
 
bool key_check_active(uint8 key, uint32 ms) {
    return ((is_extra_button_active(key) && (extra_keys_status[get_key_index(key)] & _EXTRA_KEY_STATUS_PRESSED)) && (key_time_active(key) >= ms));
}
 
bool key_check_release(uint8 key, uint32 ms) {
    return (!is_extra_button_active(key) && (extra_keys_status[get_key_index(key)] & _EXTRA_KEY_STATUS_RELEASED) && key_time_release(key) >= ms);
}
 
#define key_is_active(key) key_status(key)
#define key_is_release(key) !key_is_active(key)
 
#define mouse_is_active(mouse) mouse_status(mouse)
#define mouse_is_release(mouse) !mouse_is_active(mouse)
 
#define mouse_event_active(mouse) key_event_active((mouse | EXTRA_MOUSE_INPUT))
#define mouse_event_release(mouse) key_event_release((mouse | EXTRA_MOUSE_INPUT))
#define mouse_time_active(mouse) key_time_active((mouse | EXTRA_MOUSE_INPUT))
#define mouse_time_release(mouse) key_time_release((mouse | EXTRA_MOUSE_INPUT))
#define mouse_check_active(mouse) key_check_active((mouse | EXTRA_MOUSE_INPUT))
#define mouse_check_release(mouse) key_check_release((mouse | EXTRA_MOUSE_INPUT))
 
 
#endif /* __KBM_EVENTS_GPH__ */
 
 
Last edited by Buffy on Mon Jun 17, 2019 12:12 pm, edited 3 times in total.
ConsoleTuner Support Team || Discord || Custom Scripts
User avatar
Buffy
Lieutenant
Lieutenant
 
Posts: 422
Joined: Wed Jul 20, 2016 5:23 am

Re: Pablo's Beginners Guide to Scripting for PC

Postby pablosscripts » Fri May 31, 2019 5:32 am

Hi Buffy, I came up with an alternative way to emulate time_active() that's very lean. In fact it's so lean it almost feels like a bad hack so I was embarrassed to post it...but...it actually works really well!

The following code sample sets a flag based on how long you've held down the Spacebar (in this sample, above or below 1000ms). It simply uses a combo / timer to do this. I've used it a few times now and it's served me well.

Code: Select all
#include <keyboard.gph>
#include <mouse.gph>
 
bool is_pressed;
bool rappelling_flag = FALSE;
 
main {
    if(key_status(KEY_SPACEBAR)) {
        if(is_pressed) {
            combo_run(RappelHoldTimer);
            is_pressed = 0;
        } else {
            is_pressed = 1;
        }
    }
 
    if(!RappelHoldTimer && key_status(KEY_SPACEBAR)) {
        rappelling_flag = TRUE;
    }
 
 
    if(RappelHoldTimer && key_status(KEY_SPACEBAR) && !rappelling_flag) {
        rappelling_flag = FALSE;
    }
}
 
combo RappelHoldTimer {
    wait(1000);
}
Setup: XIM Apex, T2, K780 keyboard, G Pro Wireless mouse, SteelSeries 4HD pad, DXRacer armrest, LucidSound LS30 headset, Netduma router, Ubiquiti UniFi AP LR

My R6 script: https://youtu.be/x-9NtxyySVM
User avatar
pablosscripts
Brigadier General
Brigadier General
 
Posts: 1976
Joined: Tue Nov 24, 2015 6:27 am

Re: Pablo's Beginners Guide to Scripting for PC

Postby pablosscripts » Fri May 31, 2019 5:37 am

TopSteer wrote:Great post, Pablo! :smile0517:
I have been wondering about a lot of the things you brought up in here, so I appreciate you shedding some light on things like the passthru, portconnect and keystatus functions.
:smile0202:


No problems:)
Setup: XIM Apex, T2, K780 keyboard, G Pro Wireless mouse, SteelSeries 4HD pad, DXRacer armrest, LucidSound LS30 headset, Netduma router, Ubiquiti UniFi AP LR

My R6 script: https://youtu.be/x-9NtxyySVM
User avatar
pablosscripts
Brigadier General
Brigadier General
 
Posts: 1976
Joined: Tue Nov 24, 2015 6:27 am

Next

Return to Tutorials and FAQs

Who is online

Users browsing this forum: No registered users and 46 guests