GOSUB && CALL SCM



Difficulty: Easy

What is GOSUB?  What is CALL SCM function?
How do we use them properly?

GOSUB 

gosub is a sub-process that normally we use, when we want to hide some action in the code.  It takes all the variables used in the thread.
the gosub has this form:
gosub @sub_routine

:sub_routine
{code}
return

the code will automatically jump to the :sub_routine Label, when the job is done, will return to the same point.

to understand better, I'll show you some examples:




{$CLEO}
0000:

:start
wait 0
if  0AB0:   key_pressed 0x8    // backspace
then
    5@ = 10
    gosub @Get_Square
    0AD1: show_formatted_text_highpriority "the square of: %d is %d" time 5000 5@ 7@
end
goto @start

:Get_Square
0085: 7@ = 5@ // (int)
0085: 6@ = 5@ // (int)
006A: 7@ *= 6@  // (int)
return
In game press: Backspace and will print on screen: "the square of 10 is 100"
but take a look at the code, we only give to the code the First parameter. ( 5@ = 10 )
then we use the sub-routine to calculate the Square of that number.

But, take in count that the variable 5@ can be changed inside the gosub, and will affect all the code.
we can do this:
:Get_Square
5@ = 5
0085: 7@ = 5@ // (int)
0085: 6@ = 5@ // (int)
006A: 7@ *= 6@  // (int)
return
and the result will be: "the square of 5 is 25"
why? because the calculus will use the last parameter assigned. in this case 5@ = 5

we can also use the gosub in a condition:
if  
gosub @sub_routine
then

end

an example:
{$CLEO}
0000:

:start
wait 0
if  0AB0:   key_pressed 0x8    // backspace
then
    5@ = 10
    6@ = 20
    if    
    gosub @compare_values
    then
        0ACE: show_formatted_text_box "%d is major than %d" 5@ 6@
    else
        0ACE: show_formatted_text_box "%d is less than %d" 5@ 6@
    end
end
goto @start

:compare_values
if  001D:   5@ > 6@  // (int)
then
    0485:  return_true
else
    059A:  return_false
end
return
The result will be:  "10 is less than 20"
and if you change the values: 5@ = 20 | 6@ = 10
the result will be: "20 is major than 10"


CALL SCM

Call SCM Function uses two opcodes: 0AB1 and 0AB2
The opcode 0AB1 works in the same way as the opcode 004F(004F: create_thread @MS_BIKE_MISSIONS) but, it has the hability to return values, using the opcode 0AB2.

Call Scm Function has this form:
0AB1: call_scm_func @GetSQR 1 10 $result

:GetSQR
{code}
0AB2: ret 1 0@

lets see the opcode 0AB1
0AB1: call_scm_func <thread> <param_count> | <param1> <param2> ...
As many as the parameters count says. Those params can be a number or a local/global var, indipendendlty for what it's their offset.

lets see the opcode 0AB2
0AB2: ret <param_count> | <param1> <param2> ...

IMPORTANT:
take in count that, all passed params are stored in a progressive offsets chain which starts always from 0. So the 1st passed param will be stored in 0@, the 2nd in 1@... and so on until the max local var offset (33@).

lets see some examples:
{$CLEO}
0000:

:start
wait 0
if  0AB0:   key_pressed 0x8    // backspace
then
    5@ = 10
    0AB1: call_scm_func @Get_Square 1 Passed_Parameter = 5@ -> Stored_Result_IN = 7@
    0AD1: show_formatted_text_highpriority "the square of: %d is %d" time 5000 5@ 7@

end
goto @start

:Get_Square
/// here 10 is not stored in 5@ anymore, now the variable 0@ is equal to 10 (read above)
0085: 15@ = 0@ // (int)    Lets copy the variable 0@
006A: 15@ *= 0@  // (int)  10 * 10 
0AB2: ret 1 15@   // returned values
this will work as the example of gosub,
In game press: Backspace and will print on screen: "the square of 10 is 100"
We passed only ONE parameter (5@) and we returned ONE parameter(7@)

a Condition Example:
{$CLEO}
0000:

:start
wait 0
if  0AB0:   key_pressed 0x8    // backspace
then
    if 
    0AB1: call_scm_func @isActorDriving 1 actor $PLAYER_ACTOR 
    then
        0ACA: show_text_box "yeeah Player is Driving!!!"
    else
        0ACA: show_text_box "nope, walk is better"
    end
end
goto @start

:isActorDriving
{
 0@ - actor
}
if 
00DF:  actor 0@ driving
then
    0485: return_true
else
    059A: return_false
end
0AB2: ret 0
This code will check if you are driving any car.
In the opcode 0AB1 we passed One parameter: $PLAYER_ACTOR
take a look in the label :isActorDriving, now the variable ($PLAYER_ACTOR) is stored in the variable 0@
if we pass another parameter, will be stored in the variable 1@, if we pass another parameter will be stored in the parameter 2@, and so on.
Look the opcode 0AB2, In this case, there is no need to return a value. So, we set it to 0.

another examples:
// SET example
{$CLEO}
0000:

:start
wait 0
if  0AB0:   key_pressed 0x8    // backspace
then
    0AB1: call_scm_func @setActorHealth 2 actor $PLAYER_ACTOR health 100 
    0ACA: show_text_box "health to 100"
end
goto @start

:setActorHealth
{
 0@ - actor
 1@ - health
}
0223: set_actor 0@ health_to 1@ 
0AB2: ret 0

// GET example
{$CLEO}
0000:

:start
wait 0
if  0AB0:   key_pressed 0x8    // backspace
then
    0AB1: call_scm_func @getActorArmour 1 actor $PLAYER_ACTOR armour_to 10@ 
    0ACE: show_formatted_text_box "armor is: %d" 10@
end
goto @start

:getActorArmour
{
 0@ - actor
}
04DD: 1@ = actor 0@ armour
0AB2: ret 1 1@



good luck!



;)

Comentarios