Functions in GPC Code
12 posts
• Page 1 of 2 • 1, 2
Functions in GPC Code
I made this to hopefully explain a little better how functions work in GPC code. Any feedback is appreciated!
The best way to explain how the functions work is that they are almost exactly like a combo with the exception that they can create their own variable within the parenthesis located in the name. These variables can only be used within the function and if you don't send the correct information for the definition it will fail in compilation. In the example below it is LED(a, b, c, d) and the a b c and d are the variables. In order to use the function you call it in the same way as a combo except that at the end of the call you need to include the values that will be passed into the function. LED(value for a, value for b, value for c, value for d). I've included trace variables in the function itself so you can easily see the values passed in from the calls in main. This can be used in many ways and tremendously reduces code duplication. It is not always a replacement for combos, and is best used only when you have multiple different values that may have to be used by the same code routine. For example if you have different fire rates for rapid fire, or different values for anti-recoil. This would be a time to use functions as you could easily pass the parameters to the function without having to re-write the code for the rapid fire or anti-recoil. Please let me know if there are any other questions or if I could make this small tutorial on how to use functions a little better.
The best way to explain how the functions work is that they are almost exactly like a combo with the exception that they can create their own variable within the parenthesis located in the name. These variables can only be used within the function and if you don't send the correct information for the definition it will fail in compilation. In the example below it is LED(a, b, c, d) and the a b c and d are the variables. In order to use the function you call it in the same way as a combo except that at the end of the call you need to include the values that will be passed into the function. LED(value for a, value for b, value for c, value for d). I've included trace variables in the function itself so you can easily see the values passed in from the calls in main. This can be used in many ways and tremendously reduces code duplication. It is not always a replacement for combos, and is best used only when you have multiple different values that may have to be used by the same code routine. For example if you have different fire rates for rapid fire, or different values for anti-recoil. This would be a time to use functions as you could easily pass the parameters to the function without having to re-write the code for the rapid fire or anti-recoil. Please let me know if there are any other questions or if I could make this small tutorial on how to use functions a little better.
- Code: Select all
main {
if(event_press(PS4_CROSS)) LED(0, 0, 0, 0);
if(event_press(PS4_SQUARE)) LED(1, 0, 0, 0);
if(event_press(PS4_CIRCLE)) LED(0, 1, 0, 0);
if(event_press(PS4_TRIANGLE)) LED(0, 0, 1, 0);
if(event_press(PS4_DOWN)) LED(0, 0, 0, 1);
if(event_press(PS4_UP)) LED(1, 0, 1, 0);
if(event_press(PS4_R1)) LED(0, 1, 1, 0);
if(event_press(PS4_R2)) LED(1, 1, 1, 0);
}
function LED(a, b, c, d) {
set_led(0, a);
set_led(1, b);
set_led(2, c);
set_led(3, d);
set_val(TRACE_1, a);
set_val(TRACE_2, b);
set_val(TRACE_3, c);
set_val(TRACE_4, d);
}
-
The_Rabid_Taco - Major
- Posts: 1066
- Joined: Wed Mar 16, 2016 6:04 pm
- Location: Pensacola, FL
Re: Functions in GPC Code
Great info!
- bonefisher
- Lieutenant General
- Posts: 5413
- Joined: Thu Jan 29, 2015 10:49 am
Re: Functions in GPC Code
yes, this is good. I want to learn more. Hopefully I've correctly "commented", so I can follow along. I may have the Off/On/Fast Blink/Slow Blink wrong in the function? Could you give us an example of what could be done with this. I realize the function replaces some combos and eliminates needing to use defines (ex: smaller byte code ). Please, further explain what the TRACE is doing, I put in the comments the Identifiers for TRACE, just as (4) is the identifier for the (PS4_R2).
- Code: Select all
main {
if(event_press(PS4_CROSS)) LED(0, 0, 0, 0); //Off
if(event_press(PS4_SQUARE)) LED(1, 0, 0, 0); //Blue
if(event_press(PS4_CIRCLE)) LED(0, 1, 0, 0); //Red
if(event_press(PS4_TRIANGLE)) LED(0, 0, 1, 0); //Green
if(event_press(PS4_DOWN)) LED(0, 0, 0, 1); //Pink
if(event_press(PS4_UP)) LED(1, 0, 1, 0); // Cyan
if(event_press(PS4_R1)) LED(0, 1, 1, 0); //Amber
if(event_press(PS4_R2)) LED(1, 1, 1, 1); //White
}
function LED(a, b, c, d) {
set_led(0, a); //Off
set_led(1, b); //On
set_led(2, c); // Fast Blink
set_led(3, d); // Slow Blink
set_val(TRACE_1, a); //(30)
set_val(TRACE_2, b); //(31)
set_val(TRACE_3, c); //(32)
set_val(TRACE_4, d); //(33)
}
- Playstation PS4, Astro A50 Gen 3, Elgato Game Capture HD60 S
- 2x Benq 27” Gaming Monitors, Netduma R1 Gaming Router
- Titan One/Two Controller Input Device, Battle Beaver PS4 Controller, SCUF Infinity4PS Controller
-
Vendetta - Sergeant Major of the Army
- Posts: 226
- Joined: Fri Jul 31, 2015 8:40 pm
Re: Functions in GPC Code
The trace values in this function are just for use in the Device Monitor. It shows how the value changes in a, b, c, and d when different buttons are pressed and passing in the values. These should populate in the lower right corner of device monitor. I've updated the remarks a bit to help show the flow and how it all comes together.
- Code: Select all
main {
if(event_press(PS4_CROSS)) LED(0, 0, 0, 0); //Off
if(event_press(PS4_SQUARE)) LED(1, 0, 0, 0); //Blue
if(event_press(PS4_CIRCLE)) LED(0, 1, 0, 0); //Red
if(event_press(PS4_TRIANGLE)) LED(0, 0, 1, 0); //Green
if(event_press(PS4_DOWN)) LED(0, 0, 0, 1); //Pink
if(event_press(PS4_UP)) LED(1, 0, 1, 0); // Cyan
if(event_press(PS4_R1)) LED(0, 1, 1, 0); //Amber
if(event_press(PS4_R2)) LED(1, 1, 1, 1); //White
}
function LED(a, b, c, d) {
//Set led sets the state of each of the LED's.
//There are four in total, this is why we pass four values in.
set_led(0, a); //Value one passed in, sets state of LED1 0 - off, 1 - on, 2 - fast blink, 3 - slow blink
set_led(1, b); //Value two passed in, sets state of LED2 0 - off, 1 - on, 2 - fast blink, 3 - slow blink
set_led(2, c); //Value three passed in, sets state of LED3 0 - off, 1 - on, 2 - fast blink, 3 - slow blink
set_led(3, d); //Value four passed in, sets state of LED4 0 - off, 1 - on, 2 - fast blink, 3 - slow blink
// When viewed in device monitor, will show the values passed in from main.
// The lower right hand corner has six trace values. I've done this just
// to make seeing when a button is pressed how the values get to this function
// a bit easier.
set_val(TRACE_1, a); //(30)
set_val(TRACE_2, b); //(31)
set_val(TRACE_3, c); //(32)
set_val(TRACE_4, d); //(33)
}
-
The_Rabid_Taco - Major
- Posts: 1066
- Joined: Wed Mar 16, 2016 6:04 pm
- Location: Pensacola, FL
Re: Functions in GPC Code
Thanks for putting this together
Do you have an example of how this can be applied to rapid-fire? I'm assuming it would be pretty easy, given the two variables are HoldTime and RestTime.
Where things might get a bit more fun are combining anti-recoil and rapid-fire into one, such as this..
...but I suppose the principle is the same. I understand the anti-recoil part of the code, but I'm not sure how to apply a function to FireRate in this example.
My guess is the call to the function would be something like below, assuming the function is named RapidFire, but I'm not 100% clear on how to construct the RapidFire function, or whether a function can be called within another function.
Do you have an example of how this can be applied to rapid-fire? I'm assuming it would be pretty easy, given the two variables are HoldTime and RestTime.
- Code: Select all
combo RapidFire
{
set_val(SHOOT, 100);
wait(HoldTime);
set_val(SHOOT, 0);
wait(RestTime);
set_val(SHOOT, 0);
}
Where things might get a bit more fun are combining anti-recoil and rapid-fire into one, such as this..
- Code: Select all
combo AdvancedRapidFire {
set_val(Shoot, 100);
wait(FireRate);
set_val(Shoot, 0);
if(test_bit(GunFlags, 1)) {
AntiRecoil(Primary_Anti_Recoil, PrimaryAntiRecoilHoldR, PrimaryAntiRecoilHoldL);
} else if(test_bit(GunFlags, 2)) {
AntiRecoil(Secondary_Anti_Recoil, SecondaryAntiRecoilHoldR, SecondaryAntiRecoilHoldL);
}
wait(FireRate);
}
function AntiRecoil(AntiRecoil_H, AntiRecoil_V)
{
if (AntiRecoil_ON)
{
RightStick_X = get_val(RX_AXIS) + AntiRecoil_H;
if (RightStick_X > 100)
{RightStick_X = 100;}
set_val(RX_AXIS, RightStick_X);
RightStick_Y = get_val(RY_AXIS) + AntiRecoil_V;
if (RightStick_Y > 100)
{RightStick_Y = 100;}
set_val(RY_AXIS, RightStick_Y);
}
}
...but I suppose the principle is the same. I understand the anti-recoil part of the code, but I'm not sure how to apply a function to FireRate in this example.
My guess is the call to the function would be something like below, assuming the function is named RapidFire, but I'm not 100% clear on how to construct the RapidFire function, or whether a function can be called within another function.
- Code: Select all
combo AdvancedRapidFire {
set_val(Shoot, 100);
wait(RapidFire(FireRate));
...
Last edited by antithesis on Sun Aug 21, 2016 9:23 am, edited 1 time in total.
-
antithesis - Colonel
- Posts: 1912
- Joined: Sat May 28, 2016 10:45 pm
Re: Functions in GPC Code
Yea, I'll throw together an example of a rapid fire, a anti-recoil, and a mixed bag tomorrow. Getting some sleep now to clear the cobwebs, and should be able to put something together.
-
The_Rabid_Taco - Major
- Posts: 1066
- Joined: Wed Mar 16, 2016 6:04 pm
- Location: Pensacola, FL
Re: Functions in GPC Code
Great initiative The_Rabid_Taco, we should make a copy of this topic on the tutorials section!! (if you agree of course). thanks.
ConsoleTuner Support Team
-
J2Kbr - General of the Army
- Posts: 20322
- Joined: Tue Mar 18, 2014 1:39 pm
Re: Functions in GPC Code
J2Kbr wrote:Great initiative The_Rabid_Taco, we should make a copy of this topic on the tutorials section!! (if you agree of course). thanks.
I'd have no issue with that at all!
Sorry, I didn't remember (honestly got lost in Witcher 3) and will make sure to do a example of Rapid Fire tonight after work.
-
The_Rabid_Taco - Major
- Posts: 1066
- Joined: Wed Mar 16, 2016 6:04 pm
- Location: Pensacola, FL
Re: Functions in GPC Code
Ok, so here is an example where bit operator and function were able to reduce the code size by a few percent, and this is a small script. I used the function to handle all of the toggles for different mods. This can be a huge space saver for when you have a lot of different mods and want to be able to turn them all on and off. I figured out why I hadn't been using it for rapid fire, and it is because of the wait commands. They can not be ran from a function so being able to pass in the values does not work quite the same. There is a way to work around that in combo's so that you don't have to duplicate the code there either, but I'll save that for another post. I've got two scripts below that work identical, the first is the longer drawn out version and the second uses bit operators and a function to shorten the code, saves a few percent even on a small script like this and also makes it much more readable. Let me know if there are any questions as to how this works.
Longer code block:
Refactored Code Block:
Longer code block:
- Code: Select all
/* -----------------------------------------------------------------------------
* DEFINES
**/
// Modz Buttons
define WitcherSense = PS4_L2;
define Heavy = PS4_TRIANGLE;
define Light = PS4_SQUARE;
define Pickup = PS4_CROSS;
define Dodge = PS4_CIRCLE;
// Persistent Vars
define PVAR_WitcherSense = SPVAR_1;
define PVAR_TurboLightAttack = SPVAR_2;
define PVAR_TurboHeavyAttack = SPVAR_3;
define PVAR_TurboPickup = SPVAR_4;
define PVAR_TurboDodge = SPVAR_5;
/* -----------------------------------------------------------------------------
* VARIABLES
**/
// Variable used to store the flags used for toggles.
int WitcherSenseToggle = FALSE;
int LightMeleeToggle = FALSE;
int HeavyMeleeToggle = FALSE;
int TurboPickupToggle = FALSE;
int TurboDodgeToggle = FALSE;
/* -----------------------------------------------------------------------------
* INITIALIZATION
**/
init {
WitcherSenseToggle = get_pvar(PVAR_WitcherSense, 0, 1, 0);
LightMeleeToggle = get_pvar(PVAR_TurboLightAttack, 0, 1, 0);
HeavyMeleeToggle = get_pvar(PVAR_TurboHeavyAttack, 0, 1, 0);
TurboPickupToggle = get_pvar(PVAR_TurboPickup, 0, 1, 0);
TurboDodgeToggle = get_pvar(PVAR_TurboDodge, 0, 1, 0);
}
main {
// For crossover support. Use an XBox 1 controller on PS4. Allows the
// home button to be used for Touch and PS Home at the same time based on
// the length of time it is held.
if(get_controller() == PIO_XB1 && get_val(PS4_PS) && get_ptime(PS4_PS) > 500){
set_val(PS4_PS, 100);
} else if(get_controller() == PIO_XB1 && get_val(PS4_PS) && get_ptime(PS4_PS) <= 500){
set_val(PS4_PS, 0);
set_val(PS4_TOUCH, 100);
}
// Sets the hold toggle on the Witcher Sense. Checks to see if the flag is
// set to true or false. Depending on which one it then reverses the flag
// alternating whether or not the Witcher Sense is used or not. It then sets
// the value into the PVAR for persistent state between uses.
if(event_press(WitcherSense)) {
if(!WitcherSenseToggle){
WitcherSenseToggle = TRUE;
} else if(WitcherSenseToggle){
WitcherSenseToggle = FALSE;
}
set_pvar(PVAR_WitcherSense, WitcherSenseToggle);
}
if(get_val(WitcherSense)) {
// Sets the toggle on the light attack. Checks to see if the flag is
// set to true or false. Depending on which one it then reverses the flag
// alternating whether or not the turbo light melee combo is used or not. It then sets
// the value into the PVAR for persistent state between uses.
if(event_press(Light)){
if(!LightMeleeToggle){
LightMeleeToggle = TRUE;
combo_run(RumbleNotifier);
} else if(LightMeleeToggle){
LightMeleeToggle = FALSE;
combo_run(DoubleRumbleNotifier);
}
set_pvar(PVAR_TurboLightAttack, LightMeleeToggle);
}
// Sets the toggle on the heavy attack. Checks to see if the flag is
// set to true or false. Depending on which one it then reverses the flag
// alternating whether or not the turbo heavy melee combo is used or not. It then sets
// the value into the PVAR for persistent state between uses.
if(event_press(Heavy)){
if(!HeavyMeleeToggle){
HeavyMeleeToggle = TRUE;
combo_run(RumbleNotifier);
} else if(HeavyMeleeToggle){
HeavyMeleeToggle = FALSE;
combo_run(DoubleRumbleNotifier);
}
set_pvar(PVAR_TurboHeavyAttack, HeavyMeleeToggle);
}
// Sets the toggle on the turbo pickup. Checks to see if the flag is
// set to true or false. Depending on which one it then reverses the flag
// alternating whether or not the turbo pickup combo is used or not. It then sets
// the value into the PVAR for persistent state between uses.
if(event_press(Pickup)){
if(!TurboPickupToggle){
TurboPickupToggle = TRUE;
combo_run(RumbleNotifier);
} else if(TurboPickupToggle){
TurboPickupToggle = FALSE;
combo_run(DoubleRumbleNotifier);
}
set_pvar(PVAR_TurboPickup, TurboPickupToggle);
}
// Sets the toggle on the turbo dodge. Checks to see if the flag is
// set to true or false. Depending on which one it then reverses the flag
// alternating whether or not the turbo dodge combo is used or not. It then sets
// the value into the PVAR for persistent state between uses.
if(event_press(Dodge)){
if(!TurboDodgeToggle){
TurboDodgeToggle = TRUE;
combo_run(RumbleNotifier);
} else if(TurboDodgeToggle){
TurboDodgeToggle = FALSE;
combo_run(DoubleRumbleNotifier);
}
set_pvar(PVAR_TurboDodge, TurboDodgeToggle);
}
}
// If the toggle is set to true then run the Witcher_Sense combo.
if(WitcherSenseToggle) combo_run(Witcher_Sense);
// If the toggle is set to true then when pressing Square or X turbo the button.
if(get_val(Light) && LightMeleeToggle) combo_run(TurboLightAttack);
// If the toggle is set to true then when pressing Triangle or Y turbo the button.
if(get_val(Heavy) && HeavyMeleeToggle) combo_run(TurboHeavyAttack);
// If the toggle is set to true then when pressing Cross or A turbo the button.
if(get_val(Pickup) && TurboPickupToggle) combo_run(TurboLoot);
// If the toggle is set to true then when pressing Circle or B turbo the button.
if(get_val(Dodge) && TurboDodgeToggle) combo_run(QuickDodge);
}
/* -----------------------------------------------------------------------------
* COMBOS
**/
// Sets the value of L2 or Left Trigger to 100 even when the button is released.
combo Witcher_Sense {
set_val(WitcherSense, 100);
}
// Turbo presses the Square / X button in 10ms intervals.
combo TurboLightAttack {
set_val(Light, 100);
wait(10);
set_val(Light, 0);
wait(10);
}
// Turbo presses the Triangle / Y button in 10ms intervals.
combo TurboHeavyAttack {
set_val(Heavy, 100);
wait(10);
set_val(Heavy, 0);
wait(10);
}
// Turbo presses the Cross / A button in 10ms intervals.
combo TurboLoot {
set_val(Pickup, 100);
wait(10);
set_val(Pickup, 0);
wait(10);
}
// Turbo presses the Circle / B button in 10ms intervals.
combo QuickDodge {
set_val(Dodge, 100);
wait(10);
set_val(Dodge, 0);
wait(10);
}
// Sends a single rumble for 300ms to the controller. Used to indicate when
// a mod is enabled.
combo RumbleNotifier{
set_rumble(RUMBLE_A, 100);
wait(300);
reset_rumble();
}
// Sends two consecutive rumbles to the controller the first for 300ms followed
// by a 300ms wait before sending a second rumble for 400ms to the controller.
// This is used to indicate when a mod has been disabled.
combo DoubleRumbleNotifier{
set_rumble(RUMBLE_A, 100);
wait(300);
set_rumble (RUMBLE_A, 0);
wait(300);
set_rumble(RUMBLE_A, 100);
wait(400);
reset_rumble();
}
Refactored Code Block:
- Code: Select all
/* -----------------------------------------------------------------------------
* DEFINES
**/
// Modz Buttons
define WitcherSense = PS4_L2;
define Heavy = PS4_TRIANGLE;
define Light = PS4_SQUARE;
define Pickup = PS4_CROSS;
define Dodge = PS4_CIRCLE;
// Persistent Vars
define PVAR_WitcherFlags = SPVAR_1;
/* -----------------------------------------------------------------------------
* VARIABLES
**/
// Variable used to store the flags used for toggles.
int WitcherFlags;
/* -----------------------------------------------------------------------------
* INITIALIZATION
**/
init {
WitcherFlags = get_pvar(PVAR_WitcherFlags, 0, 31, 0);
}
main {
// For crossover support. Use an XBox 1 controller on PS4. Allows the
// home button to be used for Touch and PS Home at the same time based on
// the length of time it is held.
if(get_controller() == PIO_XB1 && get_val(PS4_PS) && get_ptime(PS4_PS) > 500){
set_val(PS4_PS, 100);
} else if(get_controller() == PIO_XB1 && get_val(PS4_PS) && get_ptime(PS4_PS) <= 500){
set_val(PS4_PS, 0);
set_val(PS4_TOUCH, 100);
}
// Sets the hold toggle on the Witcher Sense. This calls the function and
// passes the value of 1 telling it to look at the first bit in the bit
// flags. If it is set then clear it. If not set then set it.
if(event_press(WitcherSense)) {
SetToggle(1);
}
// Checks to see if the L2 / Left Trigger is being held. If it is and one
// of the other buttons is pressed then toggle the turbo on that particular
// button.
if(get_val(WitcherSense)) {
// If PS4 Square or XBox X is pressed then call the function and tell
// it to look at the second bit. Again if set then clear it, and if not
// set then set it.
if(event_press(Light)){
SetToggle(2);
}
// If PS4 Triangle or XBox Y is pressed then call the function and tell
// it to look at the second bit. Again if set then clear it, and if not
// set then set it.
if(event_press(Heavy)){
SetToggle(3);
}
// If PS4 Cross or XBox A is pressed then call the function and tell
// it to look at the second bit. Again if set then clear it, and if not
// set then set it.
if(event_press(Pickup)){
SetToggle(4);
}
// If PS4 Circle or XBox B is pressed then call the function and tell
// it to look at the second bit. Again if set then clear it, and if not
// set then set it.
if(event_press(Dodge)){
SetToggle(5);
}
}
// If the first bit is set then run the Witcher_Sense combo.
if(test_bit(WitcherFlags, 1)) combo_run(Witcher_Sense);
// If the second bit is set then when pressing Square or X turbo the button.
if(get_val(Light) && test_bit(WitcherFlags, 2)) combo_run(TurboLightAttack);
// If the third bit is set then when pressing Triangle or Y turbo the button.
if(get_val(Heavy) && test_bit(WitcherFlags, 3)) combo_run(TurboHeavyAttack);
// If the fourth bit is set then when pressing Cross or A turbo the button.
if(get_val(Pickup) && test_bit(WitcherFlags, 4)) combo_run(TurboLoot);
// If the fifth bit is set then when pressing Circle or B turbo the button.
if(get_val(Dodge) && test_bit(WitcherFlags, 5)) combo_run(QuickDodge);
}
/* -----------------------------------------------------------------------------
* COMBOS
**/
// Sets the value of L2 or Left Trigger to 100 even when the button is released.
combo Witcher_Sense {
set_val(WitcherSense, 100);
}
// Turbo presses the Square / X button in 10ms intervals.
combo TurboLightAttack {
set_val(Light, 100);
wait(10);
set_val(Light, 0);
wait(10);
}
// Turbo presses the Triangle / Y button in 10ms intervals.
combo TurboHeavyAttack {
set_val(Heavy, 100);
wait(10);
set_val(Heavy, 0);
wait(10);
}
// Turbo presses the Cross / A button in 10ms intervals.
combo TurboLoot {
set_val(Pickup, 100);
wait(10);
set_val(Pickup, 0);
wait(10);
}
// Turbo presses the Circle / B button in 10ms intervals.
combo QuickDodge {
set_val(Dodge, 100);
wait(10);
set_val(Dodge, 0);
wait(10);
}
// Sends a single rumble for 300ms to the controller. Used to indicate when
// a mod is enabled.
combo RumbleNotifier{
set_rumble(RUMBLE_A, 100);
wait(300);
reset_rumble();
}
// Sends two consecutive rumbles to the controller the first for 300ms followed
// by a 300ms wait before sending a second rumble for 400ms to the controller.
// This is used to indicate when a mod has been disabled.
combo DoubleRumbleNotifier{
set_rumble(RUMBLE_A, 100);
wait(300);
set_rumble (RUMBLE_A, 0);
wait(300);
set_rumble(RUMBLE_A, 100);
wait(400);
reset_rumble();
}
/* -----------------------------------------------------------------------------
* FUNCTIONS
**/
// This is the function to set the flags on the options. FlagLocation is a variable
// that accepts the value passed into it from main. This is then used to distinguish
// which flag we want to look at. If the flag is enabled (set) then we clear it out.
// If the flag is disabled (cleared) then we set it to enable that particular mod.
// The flags are then stored in a pvar to enable persistence between uses.
function SetToggle(FlagLocation) {
if(test_bit(WitcherFlags, FlagLocation)) {
clear_bit(WitcherFlags, FlagLocation);
combo_run(DoubleRumbleNotifier);
} else {
set_bit(WitcherFlags, FlagLocation);
combo_run(RumbleNotifier);
}
set_pvar(PVAR_WitcherFlags, WitcherFlags);
}
-
The_Rabid_Taco - Major
- Posts: 1066
- Joined: Wed Mar 16, 2016 6:04 pm
- Location: Pensacola, FL
12 posts
• Page 1 of 2 • 1, 2
Who is online
Users browsing this forum: No registered users and 3 guests