[GLOBAL]Ultimate QB Scripting Guide.

Tutorial forum for Tony Hawk games.
Forum rules
No requests, use other sections for that. TAG your titles [THAW][THUG2] etc.
Morten1337
Posts: 132
Joined: Tue Jun 08, 2010 11:11 pm
Contact:

[GLOBAL]Ultimate QB Scripting Guide.

Postby Morten1337 » Thu Jul 21, 2011 4:22 pm

Okay, so i decided to share most my knowledge on the advanced stuff that you can do in qbscripts.

Table of contents:
    - Global types
    - %GLOBAL% usage
    - Calculations
    - Creating a Bool
    - Accessing Array data, (Structure index's)
    - Accessing Array data, (Item index)
    - Convert Vector's and Doubles to Float
    - Convert Floats to Vector and Double

Global types:
If you have data that you want to access at any time from any function;
global types is the way to go.

Global types include; Integer, Float, String, Checksum, Array and Structure.
These have to be placed outside any function.

Here are some examples:

Code: Select all

:i $Global_String$ = %s(0,"String01")
:i $Global_Float$ = %f(1.000000)

   :i function $nullscript$
   #// Scroll down for, usage in functions.
   :i endfunction


So, when you have the global values, you can start writing functions to use them.
To "get" the value you use this code:

Code: Select all

($*Checksum*$)

Example:

Code: Select all

   :i function $Example_GlobalString_Message$
      :i call $SendChatMessage$ arguments
            $string$ = ($Global_String$)
   :i endfunction
This function above (Example_GlobalString_Message), will send a chat message, with the text (Global_String) its assigned to. In this case "String01"

The "Change" function.
If you want to change a value in-game you need to use the function (Change)
It takes only one parameter. Like this:

Code: Select all

$*Checksum*$ = *Data Type*

Example:

Code: Select all

:i call $Change$ arguments
      $Global_Float$ = %f(23.000000)

Errors that may occur while working with global types;
- two checksum names being the same = CRASH



%GLOBAL% Usage:
%GLOBAL% in the qb script is actually a misleading name.
But its very useful.

%GLOBAL% works pretty much like "Global types".
The difference is that the value has to be passed as a parameter into the function, OR it could be defined inside the function itself.

An easy way to explain the "passing as parameter"-part would be;
When you call a function you can add Arguments, the way it works is that you "give" the function data that it can access when its run. Unlike the "Global Types" where it can always be accessed.

You can set the names yourself just like the "Global Types"

Code: Select all

$*Checksum*$ = *Data Type*


Here's an example:

Code: Select all

#// ...

:i call $Example_GlobalData$ arguments
      $global_data01$ = %s(0,"String01")$global_data02$ = %s(0,"String02")

#// ...

   :i function $Example_GlobalData$
      :i call $SendChatMessage$ arguments
            $string$ = %GLOBAL%$global_data01$

      :i call $SendChatMessage$ arguments
            $string$ = %GLOBAL%$global_data02$
   :i endfunction
This function above (Example_GlobalData), will send teo chat messages, with the text ( %GLOBAL%$global_data01$) and ( %GLOBAL%$global_data02$) . In this case "String01" and "String02".

Great!
Now for defining a new value inside a function.

This works exactly like the "Global Types", you can create;
Integers, Float, Vector, Doubles, Checksum, Arrays and Structures.
Although, the way its written could be different. 3 Ways actually!

Example:

Code: Select all

:i $Data_01$ = %f(1.000000)
$Data_02$ = %f(1.000000)
%GLOBAL%$Data_03$ = %f(3.000000)


Example of usage:

Code: Select all

   :i function $Example_GlobalData02$

      $myframes$ = %f(5.000000)

   :i $wait$%GLOBAL%$myframes$$frames$

#// Wait %GLOBAL% number of frames.

   :i endfunction
This function above (Example_GlobalData02), will run then wait the number of frames assigned to the %GLOBAL% value "myframes".

Actually, there is 3rd way to work add a %GLOBAL% value, its a little more advanced than the others.
If you have a function that is depending on a parameter/value being passed. You can add a "default" value to the "function header".

It works like this; if you have a function that will not work if some parameters are missing, you add a default value, that will only be use if a new one is not presented.

Here are two examples, that do the same thing:

Code: Select all

#//...
   :i call $Example_DefaultGlobal01$ arguments
         $GlobalString$ = %s(0,"String01")
#//...

   :i function $Example_DefaultGlobal01$
      :i call $SendChatMessage$ arguments
            $string$ = %GLOBAL%$GlobalString$
   :i endfunction

Code: Select all

#//...
   :i $Example_DefaultGlobal02$
#//...

   :i function call  $Example_DefaultGlobal02$ arguments
         $GlobalString$ = %s(0,"String01")

      :i call $SendChatMessage$ arguments
            $string$ = %GLOBAL%$GlobalString$
   :i endfunction
Get it? Its not that difficult... Really, its not!


Calculations:
I will keep this section short, because its common sense.

Mathematic calculations use:
Plus(+), Minus (-), Multiply (*), Divide (/).
And works with static Floats and Integers, Global Floats and Integers and %GLOBAL% Floats and Integers. It can be mixed up!

Example:

Code: Select all

:i $Global_Float01$ = %f(1.000000)

#//...
   :i call $Example_DoMathThing$ arguments
         $Float02$ = %f(2.000000)
#//...

   :i function $Example_DoMathThing$

   :i $new_float$ = ( (($Global_Float01$) + %GLOBAL%$Float02$) * %f(2.000000) )
   #// new_float = ((1 + 2) * 2) = 6

   :i endfunction


There are also some more advanced stuff you can do. Like check if one number is bigger/smaller than the other.
using < and >

An example:

Code: Select all

#// ...

   :i $new_float$ = ( (($Global_Float01$) + %GLOBAL%$Float02$) * %f(2.000000) )
   :i if (%GLOBAL%$new_float$ > %f(10.000000))
         #// If %GLOBAL%$new_float$ is BiggerThan 10, do do this.
      :i else
         #// If not, then do do this. Simple
   :i endif
#// ...


You can also calculate other number data types as Vectors and Doubles, but then both have to be the same type.
Example:

Code: Select all

#// ...
   :i $new_vector$ = (%vec3(0.000000,0.000000,0.000000) + %vec3(100.000000,200.000000,300.000000))
#// ...



Creating a Bool:
QB scripts does not really have a bool data type, but "If" statements can handle both Floats and Integers as a bool.
Its really simple, if you setup a Global Integer, either assigned to 0 or 1 it will be handled as True / False.

Code: Select all

:i $bool_test$ = %i(1,00000001)
:i function $Example_ShowHowBoolWorks$

   :i if (bool_test) #//This means "If bool_test = 1"
      :i else
   :i endif

:i endfunction


Accessing Array data, (Structure index's):
Usually when working with Arrays you will have one Array with several Structure's inside.
I will now show you how you can get any data from this Array.

This is an example of an Array:

Code: Select all

:i $Example_Array01$ = :a{
   :i :s{
         :i $model$ = %sc(0,"peds/Ped_aborigine/Ped_aborigine.skin")
         :i $name$ = %s(0,"Aborigine")
         :i $skeleton$ = $THPS6_Human$
   :i :s}
   :i :s{
         :i $model$ = %sc(0,"peds/Ped_Alien/Ped_Alien.skin")
         :i $name$ = %s(0,"Alien")
         :i $skeleton$ = $THPS6_Human$
   :i :s}
:i :a}


Now, let's say we want the "name".
First set up an %GLOBAL% item in your function, like this:

Code: Select all

#// ...

$pedestrian_name$ = ( ($Example_Array01$ :a{%i(1,00000001):a} ) ->$name$)

#// ...
Now %GLOBAL%-"pedestrian_name" will be the name. In this case "Alien"... Yes, even if its the second item in the array. Because the first item is always 0

Remember you can mix in, the things i talked about earlier in the tutorial.
Like:

Code: Select all

#// ...
   :i $Global_Index$ = %i(2,00000002)
#// ...

:i function $Example_Function02$

   $array_name$ = $Example_Array01$
   $pedestrian_name$ = ( (%GLOBAL%$array_name$ :a{ ( ($Global_Index$) + %i(1,00000001) ):a} ) ->$name$)

   :i call $SendChatMessage$ arguments
         $string$ = %GLOBAL%$pedestrian_name$

:i endfunction



Accessing Array data, (Item index):
Sometimes your array doesn't have structure items. You could for example have an array with only checksum names.
Its really easy to get them, and i'll show you.

It works just the same as the first "Array part".

Lets say this is our array:

Code: Select all

:i $Example_Array02$ = :a{
   :i $Ped_M_Idle1$
   :i $Ped_M_Talk_Dull$
   :i $Ped_M_Talk2_BackThere$
   :i $Ped_M_Talk2_GoAhead$
   :i $Ped_M_Talk2_KnowWhatIMean$
   :i $Ped_M_Talk2_Maybe$
   :i $Ped_M_Talk2_MixIt$
   :i $Ped_M_Talk2_OfCourse$
   :i $Ped_M_Talk2_RightHere$
   :i $Ped_M_Talk2_RoundAndRound$
   :i $Ped_M_Talk2_SureThing$
   :i $Ped_M_Talk2_TheyllTellYou$
   :i $Ped_M_Talk2_UpAbove$
   :i $Ped_M_Talk2_WhatDoYouThink$
   :i $Ped_M_ThumbUp$
   :i $Ped_M_Disgust$
   :i $Ped_M_Talk_Shrug$
   :i $Ped_M_Talk_RaiseArn$
   :i $Ped_M_Talk_WhoKnows$
   :i $Ped_M_Talk_ISupposeSo$
:i :a}

Now I want to "get" the name of the 5th item in this array. Which is "Ped_M_Talk2_Maybe"
All you gotta do is, to set up an %GLOBAL%-item like this:

Code: Select all

$anim$ =  ( $Example_Array02$:a{%i(5,00000005):a} )

Take a look at this topic for another example.


Convert Vector's and Doubles to Float:
When you have a Vector or a Double (which is basically 3 or 2 floats grouped together), and you want to make it into separate Floats, then do like this:

Set up %GLOBAL% items for each value, for a vector: (x, y, z) for double: (x, y):

Code: Select all

   $VectorPos$ = %vec3(10.000000,20.000000,30.000000)
   $Float_X$ =  (%GLOBAL%$VectorPos$->%vec3(1.000000,0.000000,0.000000) ) #// 10
   $Float_Y$ =  (%GLOBAL%$VectorPos$->%vec3(0.000000,1.000000,0.000000) ) #// 20
   $Float_Z$ =  (%GLOBAL%$VectorPos$->%vec3(0.000000,0.000000,1.000000) ) #// 30

Code: Select all

   $DoublePos$ = %vec2(10.000000,20.000000)
   $Float_X$ =  (%GLOBAL%$DoublePos$->%vec2(1.000000,0.000000) ) #// 10
   $Float_Y$ =  (%GLOBAL%$DoublePos$->%vec2(0.000000,1.000000) ) #// 20


EXAMPLE, Do not copy this:

Code: Select all

      :i $LevelEditor$.$GetCursorPosition$
      :i $cursorpos$ = (%GLOBAL%$pos$)
         $vec3x$ =  (%GLOBAL%$cursorpos$->%vec3(1.000000,0.000000,0.000000))
         $vec3y$ =  (%GLOBAL%$cursorpos$->%vec3(0.000000,1.000000,0.000000))
         $vec3z$ =  (%GLOBAL%$cursorpos$->%vec3(0.000000,0.000000,1.000000))
         $vec3pos$ = %GLOBAL%$cursorpos$

      :i $ObjPos$ =  ((($LevelEditor_NodeArray$):a{%GLOBAL%$item_index$:a}) ->$pos$)
      $lvlvec3pos$ = %GLOBAL%$ObjPos$
      $lvlvec3x$ =  ((%GLOBAL%$ObjPos$->%vec3(1.000000,0.000000,0.000000)) -  ($leveleditor_radius$) )
      $lvlvec3y$ =  ((%GLOBAL%$ObjPos$->%vec3(0.000000,1.000000,0.000000)) -  ($leveleditor_radius$) )
      $lvlvec3z$ =  ((%GLOBAL%$ObjPos$->%vec3(0.000000,0.000000,1.000000)) -  ($leveleditor_radius$) )
      $outlvlvec3x$ =  ((%GLOBAL%$ObjPos$->%vec3(1.000000,0.000000,0.000000)) +  ($leveleditor_radius$) )
      $outlvlvec3y$ =  ((%GLOBAL%$ObjPos$->%vec3(0.000000,1.000000,0.000000)) +  ($leveleditor_radius$) )
      $outlvlvec3z$ =  ((%GLOBAL%$ObjPos$->%vec3(0.000000,0.000000,1.000000)) +  ($leveleditor_radius$) )

      :i if ( ((%GLOBAL%$vec3x$ < %GLOBAL%$outlvlvec3x$) AND (%GLOBAL%$vec3x$ > %GLOBAL%$lvlvec3x$)) AND ((%GLOBAL%$vec3y$ < %GLOBAL%$outlvlvec3y$) AND (%GLOBAL%$vec3y$ > %GLOBAL%$lvlvec3y$)) AND ((%GLOBAL%$vec3z$ < %GLOBAL%$outlvlvec3z$) AND (%GLOBAL%$vec3z$ > %GLOBAL%$lvlvec3z$)))
      :i $Obj_Name$ =  ((($LevelEditor_NodeArray$):a{%GLOBAL%$item_index$:a}) ->$name$)
      :i $Obj_Class$ =  ((($LevelEditor_NodeArray$):a{%GLOBAL%$item_index$:a}) ->$class$)



Convert Floats to Vector and Double:
Now, if you have a Float that you want to "put back" into another vector/double. I figured out a little wacky way to do that.
This is useful when you only want to change one of the floats in the vector/double.

So lets say i have a Double like this:

Code: Select all

$XY_Scale$ = %vec2(0.000000,1.520000)
But i want to change that "0.0" to something else, without changing the other. Then simply create a new %GLOBAL% - double:

Code: Select all

$Double_01$ = ( %f(5.000000) * %vec2(1.000000,0.000000))
Basically (5 * 1) = 5, but the answer will be returned as a Double, like vec2(5, 0)

Here's another example of it being used:

Code: Select all

:i $index_float$ = (%f(0.000000) + %GLOBAL%$index$)
:i $max_float$ = (%f(0.000000) + ($MAX_number_of_placed_objects$))

:i $scale$ = ((%GLOBAL%$index_float$ / %GLOBAL%$max_float$) * %f(15.000000))

:i $new_scale$ = ( ( (%GLOBAL%$scale$)  * %vec2(1.000000,0.000000))  +  (%f(1.520000) * %vec2(0.000000,1.000000)) )


TADA! lol
So yeah, This is the first part of this tutorial. There are many more things i could teach you.
But this will be it, for now.

~Morten
Anteara
Posts: 268
Joined: Thu Oct 14, 2010 2:55 am
Contact:

Re: [GLOBAL]Ultimate QB Scripting Guide.

Postby Anteara » Fri Oct 14, 2011 7:19 am

Some things, in my opinion you should add under the array section are:
-Appending something to the array
-changing a variable in an array

Also, i don't think THUG2 has a modulo function, so i'm making something similar, i'll post it here when I'm done as it might be helpful for people wishing to do calculations
Morten1337
Posts: 132
Joined: Tue Jun 08, 2010 11:11 pm
Contact:

Re: [GLOBAL]Ultimate QB Scripting Guide.

Postby Morten1337 » Fri Oct 14, 2011 4:34 pm

Anteara wrote:Some things, in my opinion you should add under the array section are:
-Appending something to the array
-changing a variable in an array

Also, i don't think THUG2 has a modulo function, so i'm making something similar, i'll post it here when I'm done as it might be helpful for people wishing to do calculations


I never actually got the function that can change and add array/struct items to work in thug2... i know it works in thaw, BUT i hate that game :)
Morten1337
Posts: 132
Joined: Tue Jun 08, 2010 11:11 pm
Contact:

Re: [GLOBAL]Ultimate QB Scripting Guide.

Postby Morten1337 » Sat Oct 15, 2011 12:01 am

I haven't seen that, but the function i was refereeing to is SetArrayElement, which does not work on global arrays(?). I've seen it in the create-a-trick scripts.

Code: Select all

:i function $get_anim_order$
   :i $count$ = %i(1,00000001)
   :i $anim_order$ = :a{%i(0,00000000);%i(0,00000000);%i(0,00000000);%i(0,00000000);%i(0,00000000);%i(0,00000000):a}
   :i while
      
      :i $index$ = %i(0,00000000)
      :i while
         
         :i if  ( ( (%GLOBAL%$animation_info$:a{%GLOBAL%$index$:a}) ->$order$)  = %GLOBAL%$count$)
            :i call $SetArrayElement$ arguments
               $ArrayName$ = $anim_order$$index$ =  (%GLOBAL%$count$%i(4294967295,ffffffff)) $newvalue$ = %GLOBAL%$index$
            :i continue
            
         :i endif
         :i $index$ =  (%GLOBAL%$index$ + %i(1,00000001))
      :i loop_to %GLOBAL%$array_size$
      :i $count$ =  (%GLOBAL%$count$ + %i(1,00000001))
   :i loop_to %GLOBAL%$array_size$
   :i return
   $anim_order$ = %GLOBAL%$anim_order$
:i endfunction
WhoElseButMe
Posts: 419
Joined: Tue Aug 04, 2009 12:50 am
Location: FL - USA
Contact:

Re: [GLOBAL]Ultimate QB Scripting Guide.

Postby WhoElseButMe » Sat Oct 15, 2011 12:33 am

Structure get:

Code: Select all

   :i $some_struct$:s{
      :i $EmitDelay$ = %i(1,00000001)
   :i :s}

Code: Select all

   :i $params_script$ = $some_struct$
   :i if call $GlobalExists$ arguments
         $name$ = %GLOBAL%$params_script$$type$ = $structure$
      :i if call $StructureContains$ arguments
            $structure$ = %GLOBAL%$params_script$$EmitDelay$
         :i $wait$ (%GLOBAL%$params_script$->$EmitDelay$) $seconds$
      :i endif
   :i endif
Image
WhoElseButMe on Nov 26, 2009 wrote:It's that lack of respect amongst their peers and ignorance towards modding etiquette that keeps us who know this stuff well from spreading it like wild fire. We do still enjoy playing the game and if you need to cheat to play a game PLAY SOMETHING ELSE YOU DON'T SUCK AT.
WhoElseButMe
Posts: 419
Joined: Tue Aug 04, 2009 12:50 am
Location: FL - USA
Contact:

Re: [GLOBAL]Ultimate QB Scripting Guide.

Postby WhoElseButMe » Sun Nov 13, 2011 10:59 am

Morten1337 wrote:I haven't seen that, but the function i was refereeing to is SetArrayElement, which does not work on global arrays(?). I've seen it in the create-a-trick scripts.


You need to copy the array first.

The Array placed somewhere else

Code: Select all

    :i $my_color$ = :a{%i(0,00000000);%i(0,00000000);%i(0,00000000);%i(0,00000000):a}

Our editing array function

Code: Select all

:i function $my_color_func$
   :i %GLOBAL%$tmpArray$ = $my_color$
   :i call $SetArrayElement$ arguments
      $ArrayName$ = $tmpArray$$index$ = %i(0,00000000)$NewValue$ = %i(50,00000032)
   :i call $SetArrayElement$ arguments
      $ArrayName$ = $tmpArray$$Index$ = %i(1,00000001)$NewValue$ = %i(80,00000050)
   :i call $SetArrayElement$ arguments
      $ArrayName$ = $tmpArray$$Index$ = %i(2,00000002)$NewValue$ = %i(128,00000080)
   :i call $SetArrayElement$ arguments
      $ArrayName$ = $tmpArray$$Index$ = %i(3,00000003)$NewValue$ = %i(128,00000080)
   :i %GLOBAL%$my_color$ = %GLOBAL%$tmpArray$
   :i call $create_console_message$ arguments
      $text$ = %s(15,"Global My Color")$rgba$ = %GLOBAL%$my_color$$wait_and_die$ = $wait_and_die$$time$ = %i(5,00000005)
:i endfunction
Image
WhoElseButMe on Nov 26, 2009 wrote:It's that lack of respect amongst their peers and ignorance towards modding etiquette that keeps us who know this stuff well from spreading it like wild fire. We do still enjoy playing the game and if you need to cheat to play a game PLAY SOMETHING ELSE YOU DON'T SUCK AT.
WhoElseButMe
Posts: 419
Joined: Tue Aug 04, 2009 12:50 am
Location: FL - USA
Contact:

Re: [GLOBAL]Ultimate QB Scripting Guide.

Postby WhoElseButMe » Sun Jun 17, 2012 8:05 pm

Structure Set
So far I can only manipulate a struct inside an array.

First setup an array of structures out side of the function

Code: Select all

:i $MyArrayStruct$ :a{
   :s{
      :i $MyId$ = $Element1$
      :i $MyInteger$ = %i(0,00000000)
      :i $MyString$ = %s(0,"String0")
   :s}
:a}

Inside your function you would want to first loop your array in the event it contains more than 1 element. The "MyId" element is used for identifying this element. I'll show you how to get at the element first.

Code: Select all

   :i call $GetArraySize$ arguments
      $MyArrayStruct$
   :i $index$ = %i(0,00000000)
   :i while
      :i if ( ( ($MyArrayStruct$:a{%GLOBAL%$index$:a}) ->$MyId$) = $Element1$)
         :i $temp_index$ = %GLOBAL%$index$
      :i endif
   :i loop_to %GLOBAL%$array_size$

As you can see we get the array size first to know how many elements we need to loop over. Set a default index to zero then iterate through the array. When MyId matches Element1 we set an integer indicating this elements index in the array.

For display purposes we send two chat messages. The first one will display the values of our structure before modifications.

Code: Select all

   :i call $FormatText$ arguments
      $TextName$ = $msg$%s(0,"Element1: Integer = %a, String = %b")$a$ = ( ($MyArrayStruct$:a{%GLOBAL%$temp_index$:a})->$MyInteger$)$b$ = (($MyArrayStruct$:a{%GLOBAL%$temp_index$:a})->$MyString$)
   :i call $SendChatMessage$ arguments
      $string$ = %GLOBAL%$msg$

To get the element object requires a few things 1) the array name "$MyArrayStruct$", 2) the element index ":a{%GLOBAL%$temp_index$:a}" and 3) the name of the elements child to get ->$MyInteger$

Now we need to change the elements data. To do this create a temp structure item and setup its values as you see fit.

Code: Select all

   :i $temp_struct$ = :s[
      :i $MyId$ = $Element1$
      :i $MyInteger$ = ( ( ($MyArrayStruct$:a{%GLOBAL%$temp_index$:a}) ->$MyInteger$) + %i(3,00000003))
      :i $MyString$ = %s(0,"String1")
   :s}

Then make a copy of our array. We must copy the array before setting any new values.

Code: Select all

   :i $temp_array$ = $MyArrayStruct$

Now we set an element (our temp_struct item) inside our temp_array.
And set our array back to reflect the changes.

Code: Select all

   :i call $SetArrayElement$ arguments
      $ArrayName$ = $temp_array$$index$ = %GLOBAL%$temp_index$$NewValue$ = %GLOBAL%$temp_struct$
   :i $MyArrayStruct$ = %GLOBAL%$temp_array$

Sending a second chat message to show changes were made to the array.

Code: Select all

   :i call $FormatText$ arguments
      $TextName$ = $msg2$%s(0,"NewElement1: Integer = %a, String = %b")$a$ = ( ($MyArrayStruct$:a{%GLOBAL%$temp_index$:a})->$MyInteger$)$b$ = (($MyArrayStruct$:a{%GLOBAL%$temp_index$:a})->$MyString$)
   :i call $SendChatMessage$ arguments
      $string$ = %GLOBAL%$msg2$
:i endfunction
Image
WhoElseButMe on Nov 26, 2009 wrote:It's that lack of respect amongst their peers and ignorance towards modding etiquette that keeps us who know this stuff well from spreading it like wild fire. We do still enjoy playing the game and if you need to cheat to play a game PLAY SOMETHING ELSE YOU DON'T SUCK AT.

Return to “Tutorials”

Who is online

Users browsing this forum: No registered users and 19 guests