Página 1 de 1

13. GOSUB e CLEO_CALL

Enviado: 26 Mai 2018, 07:49
por Junior_Djjr
Imagem
Concluindo esta parte você vai:
Saber responder o que é, como usar e quais as vantagens do uso do GOSUB e CLEO_CALL em seu script.
Também terá dicas ao longo do tutorial, na qual te ajudará a pensar melhor sobre a organização dos seus scripts.

Nada precisa ser repetitivo

Você já deve estar começando a criar alguns scripts simples, e já pode começar a imaginar melhores métodos para se fazer a mesma coisa.
Em programação (assim como várias outras áreas!) pode ser feita de incontáveis maneiras diferentes dependente do raciocínio da pessoa, assim como há formas "boas" e "ruins" de fazer algumas coisas.

Uma das coisas ruins, é a alta repetição da mesma coisa, o que poderia ser feita somente uma vez e chamada várias vezes! Ou simplesmente a mudança de posição de um código, criando uma melhor organização para facilitar a leitura.


GOSUB - Sub tarefa

O comando GOSUB ("go sub", leia isso como "ir para uma sub-tarefa") é usado para ir para uma "tarefa secundária", e voltar de onde veio.

Edit: Anos depois, estudando C#, eu descobri que isto é o equivalente à "Local Functions". Ou seja, se você já tem experiência em programação, fica mais fácil de você entender.

É muito parecido com o GOTO, a única diferença é que ele foi feito para ir e voltar, ou seja, temos o comando RETURN para retornar de onde saiu:

Código: Selecionar tudo

SCRIPT_START
{
NOP

main_loop:
WAIT 0
IF IS_KEY_PRESSED VK_KEY_Y
    GOSUB label
ENDIF
GOTO main_loop

label:
PRINT_STRING_NOW "Oi!" 1
RETURN
}
SCRIPT_END

Sim, isso é extremamente simples e o tutorial já até poderia acabar por aqui...

Vamos imaginar que você ainda não entendeu. Bem, você já sabe muito bem como o GOTO funciona, né?
Então veja isto:

Código: Selecionar tudo

SCRIPT_START
{
NOP

main_loop:
WAIT 0
IF IS_KEY_PRESSED VK_KEY_Y
    GOTO label
    label2:
ENDIF
GOTO main_loop

label:
PRINT_STRING_NOW "Oi!" 1
GOTO label2
}
SCRIPT_END
É a mesma coisa! Mas vamos ser sinceros, ficou confuso e feio, né? O GOSUB é muito mais elegante.

E como sempre, sinta-se livre! Você pode fazer um dentro do outro:

Código: Selecionar tudo

SCRIPT_START
{
NOP

main_loop:
WAIT 0
IF IS_KEY_PRESSED VK_KEY_Y
    GOSUB label
ENDIF
GOTO main_loop

label:
PRINT_STRING_NOW "Oi!" 1
IF IS_KEY_PRESSED VK_KEY_H
     GOSUB outra
ENDIF
RETURN

outra:
PRINT_STRING_NOW "Simples." 1
RETURN
}
SCRIPT_END
Conseguiu entender o que vai acontecer? Leia o código e interprete-o.

(no momento o fórum não tem contagem de linhas, copie e cole no VS Code para ver o número de cada linha)
Ao segurar a tecla Y irá chamar um GOSUB que aparece Oi! e checa se apertou a tecla H. Se apertou, entra em um segundo GOSUB para mostrar a mensagem Simples. e volta. Quando voltar, o script voltará de onde este segundo GOSUB saiu (ali na linha 15!!!) e continuar o seu caminho. Até encontrar o outro RETURN (ali na linha 17), e voltar lá no início: Na linha 8.

O limite é de 8 GOSUBs ao mesmo tempo. Parece pequeno, mas, sério, eu gosto de GOSUB e uso demais nos meus mods, e em toda a minha vida eu nunca sofri este limite. Acredito que você sofrerá só caso usar ele exageradamente.

O que é "GOSUB ao mesmo tempo"? É um dentro do outro sem retornar, por exemplo você chamar um GOSUB, e este GOSUB chamar outros 8 ou mais sem nunca chamar um RETURN, causará crash no jogo.

É sim muito simples de entender, é só um vai e volta. E no exemplo que eu falei acima foi: Vai, vai, volta, volta. Entendeu?

Depois de ter certeza de ter entendido o que é GOSUB, você já terá facilidade de entender os princípios de um CLEO_CALL:


CLEO_CALL - Uma sub-tarefa mais avançada

Eu adoro CLEO_CALL!

Ele é igual um GOSUB — inicie sua mente com isso, pense num GOSUB! — mas a diferença é que o que acontece num CLEO_CALL, não influencia no que está fora dele.
Se você entende de outras programações: CLEO_CALL é simplesmente chamar uma função, como você já deve conhecer.
Se você entende de Sanny Builder: CLEO_CALL é call_scm_func, uma função SCM.

Vamos devagar. Veja a comparação:
Imagem
É A MESMA COISA.
"E aquele "0" ali?"
NÃO IMPORTA, ele nem é utilizado (antigamente ele era, você saberá o motivo). Simplesmente ignore o "0".

Tá, agora vamos para as diferenças:

Código: Selecionar tudo

SCRIPT_START
{
LVAR_INT var1
var1 = 12

main_loop:
WAIT 0
IF IS_KEY_PRESSED VK_KEY_Y
    GOSUB label
ENDIF
GOTO main_loop

label:
PRINT_FORMATTED_NOW "%i" 1 var1
RETURN
}
SCRIPT_END

Isso irá mostrar na tela o valor da variável var1 quando você apertar a tecla Y. Qual o valor? 12. Um número que você já deve gostar.

E se fizermos igual, mas com CLEO_CALL?

Código: Selecionar tudo

SCRIPT_START
{
LVAR_INT var1
var1 = 12

main_loop:
WAIT 0
IF IS_KEY_PRESSED VK_KEY_Y
    CLEO_CALL label 0
ENDIF
GOTO main_loop

label:
PRINT_FORMATTED_NOW "%i" 1000 var1
CLEO_RETURN 0
}
SCRIPT_END
Vai aparecer "0" :)

"What?"

As variáveis existentes deixam de existir quando você chama um CLEO_CALL! Lá dentro não existe o que há lá fora.
Não importa que a var1 seja 12 lá fora. Dentro do CLEO_CALL ela não existe! Ela tem o valor 0 (pois todas as variáveis, por padrão, têm o valor 0).

Mas calma, o importante está por vir: Nós podemos enviar a nossa var1 para o CLEO_CALL!


Envio e retorno de valores

É agora que a coisa fica interessante!

Vamos virar de cabeça pra baixo:

Pela primeira vez aqui no tutorial você verá um script com o uso de 2 escopos.

Vou começar a indentar (adicionar um TAB) dentro do escopo, para facilitar a identificação de onde começa e termina eles. Você pode preferir fazer assim em seus scripts.

Também usarei os carácteres ( ) , para deixar o código melhor para ler. Você ainda não deve saber, mas estes carácteres são tratados como espaço no compilador, ou seja, eles não influenciam em absolutamente nada no seu código, somente visualmente! Então eles têm certa utilidade, como separar variáveis para ficar melhor para ler.

Olhe bem e preste muita atenção neste script:

Código: Selecionar tudo

SCRIPT_START
{
    LVAR_INT var1

    var1 = 12

    main_loop:
    WAIT 0
    CLEO_CALL label 0 (var1)(var1)
    PRINT_FORMATTED_NOW "%i" 1 var1
    GOTO main_loop
}
SCRIPT_END

{
    LVAR_INT in_var

    label:
    in_var = 13
    CLEO_RETURN 0 (in_var)
}
Mostrará 13 na tela, corretamente.

Perceba o (var1)(var1)
O primeiro (var1) é a variável enviada para dentro do CLEO_CALL. Chegando lá, o valor desta variável entrará na primeira variável declarada lá dentro, neste caso, a variável in_var. Ou seja, lá dentro do CLEO_CALL, a in_var terá o valor da var1, que é 12.
Mas eu mudei o valor, e agora será 13.
No CLEO_RETURN eu retornei a variável in_var.
Ao retornar, o valor dela irá para o segundo (var1), ou seja, o valor da in_var irá para a var1 lá fora do CLEO_CALL.
Agora var1 tem o valor 13.

O mesmo aconteceria se fosse assim, usando uma segunda variável:

Código: Selecionar tudo

SCRIPT_START
{
    LVAR_INT var1 var2

    var1 = 12

    main_loop:
    WAIT 0
    CLEO_CALL label 0 (var1)(var2)
    PRINT_FORMATTED_NOW "%i" 1000 var2
    GOTO main_loop
}
SCRIPT_END

{
    LVAR_INT in_var

    label:
    in_var = 13
    CLEO_RETURN 0 (in_var)
}
Ou seja, eu enviei o valor da var1, mas pedi para que quando retornasse, o novo valor caísse na var2. Ou seja, a var1 continuou 12, mas a var2 agora tem o valor 13, pois eu retornei o valor nela, e não na var1 como antes.

Você tem que entender que isso é muito dinâmico e você pode enviar e retornar quantas variáveis for necessário!

Dê uma olhada neste exemplo:

Código: Selecionar tudo

SCRIPT_START
{
    LVAR_INT var1

    var1 = 12

    main_loop:
    WAIT 0
    CLEO_CALL return_13 0 ()(var1)
    PRINT_FORMATTED_NOW "%i" 1 var1
    GOTO main_loop
}
SCRIPT_END

{
    return_13:
    CLEO_RETURN 0 (13)
}
Sim, a variável var1 terá agora o valor 13 e mostrará 13 na tela!

Tudo o que o script acima fez foi retornar o valor 13 para a variável de retorno. E qual a variável de retorno? var1!

Perceba que não enviei nenhuma variável para a função (pra quê?), eu somente retornei. Como "simbolismo" eu deixei um () na chamada para indicar que eu não enviei variáveis. Isto é somente visual, faz nada.

Agora eu criei uma função que: Pega uma variável, e um valor, e usa esse valor para somar naquela variável, e retorna o valor dela:

Código: Selecionar tudo

SCRIPT_START
{
    LVAR_INT var1

    var1 = 12

    main_loop:
    WAIT 0
    CLEO_CALL add 0 (var1, 10)(var1)
    PRINT_FORMATTED_NOW "%i" 1 var1
    GOTO main_loop
}
SCRIPT_END

{
    LVAR_INT in_var
    LVAR_INT value

    add:
    in_var += value
    CLEO_RETURN 0 (in_var)
}
O resultado vai ser a variável var1 aumentando de 10 em 10 sem parar (lembre-se que estamos dentro de um loop!)

Dentro do CLEO_CALL, a in_var vai ter o valor atual da var1 lá fora. Já a variável value vai ter o valor 10 (que é o valor que você enviou pra ela!).

Você já deve ter entendido mas eu quero te dar esta visualização:
Imagem

CLEO_CALL é muitíssimo útil para fazer operações mais complexas (ou repetitivas) onde você envia argumentos, e ele faz e/ou retorna alguma coisa para você.

Veja só este exemplo útil:

Código: Selecionar tudo

SCRIPT_START
{
    LVAR_INT scplayer
    LVAR_FLOAT x y z

    GET_PLAYER_CHAR 0 scplayer

    main_loop:
    WAIT 0
    IF IS_KEY_PRESSED VK_KEY_Y
        CLEO_CALL get_closest_road 0 (scplayer) (x y z)
        PRINT_FORMATTED_NOW "A coord da rua mais proxima eh: %.3f %.3f %.3f" 1 (x y z)
        DRAW_CORONA (x y z) (1.0) (CORONATYPE_SHINYSTAR, FLARETYPE_NONE) (255 0 0)
    ENDIF
    GOTO main_loop
}
SCRIPT_END

{
    LVAR_INT char // In

    LVAR_FLOAT char_x char_y char_z
    LVAR_FLOAT node_x node_y node_z

    get_closest_road:
    GET_CHAR_COORDINATES char (char_x char_y char_z)
    GET_CLOSEST_CAR_NODE (char_x char_y char_z) (node_x node_y node_z)
    CLEO_RETURN 0 (node_x node_y node_z)
}
Este CLEO_CALL tem a função de: Pegar a coordenada de um char (você pode usar qualquer char, não precisa ser o CJ), e com ela, pegar a coordenada do node (path) de carros mais próximo (leia isto como "pegar a coordenada da rua mais próxima"). O valor retornado será a coordenada x y z daquele node (path) mais próximo, ou seja, da rua mais próxima.

Ao retornar, eu usei esta coordenada para mostrar o valor dela na tela, e criar uma luz (corona) vermelha lá.
Imagem

Eu gosto de imaginar CLEO_CALL como comandos personalizados. Sabe quando você quer um comando que não existe, mas é possível você mesmo fazer este comando? Então. Exatamente como funções de outras programações.

Inclusive, isso é facilmente compartilhável com as pessoas, e este é o principal motivo da categoria "Scripts > Utilidades" existir aqui no fórum: Lá você geralmente encontra CLEO_CALLs úteis para o seu script.

Hoje mesmo fiz uma função que posso compartilhar aqui:

Código: Selecionar tudo

{
    LVAR_INT hChar // In
    LVAR_INT iTempVar

    GetCharPedStatsID:
    GET_PED_POINTER hChar iTempVar //CPed
    iTempVar += 0x59C //m_pStat
    READ_MEMORY iTempVar 4 FALSE iTempVar //CPedStats (+0x59C)
    READ_MEMORY iTempVar 4 FALSE iTempVar //nNum (+0x0)
    CLEO_RETURN 0 iTempVar
}
Simplesmente adicione isso em algum lugar do seu script (como os exemplos acima) e use a seguinte chamada:

Código: Selecionar tudo

CLEO_CALL GetCharPedStatsID 0 (hChar)(iPedStatsID)
A variável iPedStatsID terá o número ID do "ped stat" (do data\pedstats.dat) da pessoa.

Você nem precisa entender como que esta função funciona (requer entendimento sobre manipulação de memória que você aprenderá logo aqui no tutorial), tudo o que você precisa fazer é adicionar isto no seu script e usar.

Veja este script completo que pega uma pessoa próxima, usa esta função para pegar o ped stat dela, e checa e mostra na tela uma mensagem caso seja um policial, da sua gangue, ou uma puta.

Código: Selecionar tudo

SCRIPT_START
{
    LVAR_INT scplayer
    LVAR_INT char vehicle
    LVAR_INT iPedStatsNum

    CONST_INT STAT_PLAYER 0          
    CONST_INT STAT_COP 1          
    CONST_INT STAT_MEDIC 2        
    CONST_INT STAT_FIREMAN 3      
    CONST_INT STAT_GANG1 4        
    CONST_INT STAT_GANG2 5        
    CONST_INT STAT_GANG3 6        
    CONST_INT STAT_GANG4 7        
    CONST_INT STAT_GANG5 8        
    CONST_INT STAT_GANG6 9        
    CONST_INT STAT_GANG7 10        
    CONST_INT STAT_GANG8 11        
    CONST_INT STAT_GANG9 12        
    CONST_INT STAT_GANG10 13      
    CONST_INT STAT_STREET_GUY 14  
    CONST_INT STAT_SUIT_GUY 15    
    CONST_INT STAT_SENSIBLE_GUY 16
    CONST_INT STAT_GEEK_GUY 17    
    CONST_INT STAT_OLD_GUY 18      
    CONST_INT STAT_TOUGH_GUY 19    
    CONST_INT STAT_STREET_GIRL 20  
    CONST_INT STAT_SUIT_GIRL 21    
    CONST_INT STAT_SENSIBLE_GIRL 22
    CONST_INT STAT_GEEK_GIRL 23    
    CONST_INT STAT_OLD_GIRL 24    
    CONST_INT STAT_TOUGH_GIRL 25  
    CONST_INT STAT_TRAMP_MALE 26  
    CONST_INT STAT_TRAMP_FEMALE 27
    CONST_INT STAT_TOURIST 28      
    CONST_INT STAT_PROSTITUTE 29  
    CONST_INT STAT_CRIMINAL 30    
    CONST_INT STAT_BUSKER 31      
    CONST_INT STAT_TAXIDRIVER 32  
    CONST_INT STAT_PSYCHO 33      
    CONST_INT STAT_STEWARD 34      
    CONST_INT STAT_SPORTSFAN 35    
    CONST_INT STAT_SHOPPER 36      
    CONST_INT STAT_OLDSHOPPER 37  
    CONST_INT STAT_BEACH_GUY 38
    CONST_INT STAT_BEACH_GIRL 39
    CONST_INT STAT_SKATER 40
    CONST_INT STAT_STD_MISSION 41
    CONST_INT STAT_COWARD 42

    GET_PLAYER_CHAR 0 scplayer

    main_loop:
    WAIT 0
    STORE_CLOSEST_ENTITIES scplayer (vehicle char)
    IF DOES_CHAR_EXIST char
        CLEO_CALL GetCharPedStatsID 0 (char)(iPedStatsNum)
        IF iPedStatsNum = STAT_PROSTITUTE
            PRINT_STRING_NOW "A pessoa proxima eh uma puta!" 1000
        ENDIF
        IF iPedStatsNum = STAT_COP
            PRINT_STRING_NOW "A pessoa proxima eh um policial!" 1000
        ENDIF
        IF iPedStatsNum = STAT_GANG2
            PRINT_STRING_NOW "A pessoa proxima eh da sua gangue!" 1000
        ENDIF
    ENDIF
    GOTO main_loop
}
SCRIPT_END

{
    LVAR_INT hChar // In
    LVAR_INT p

    GetCharPedStatsID:
    GET_PED_POINTER hChar p //CPed
    p += 0x59C //m_pStat
    READ_MEMORY p 4 FALSE p //CPedStats (+0x59C)
    READ_MEMORY p 4 FALSE p //nNum (+0x0)
    CLEO_RETURN 0 p
}

Viu como é interessante e útil ter vários CLEO_CALL no seu script?

E sim, você também pode usar um CLEO_CALL dentro do outro, mas diferente do GOSUB, isso é infinito! (1024, para ser mais exato, o que é um número gigantesco). Ou seja, você pode fazer até umas táticas malucas de recursão que não terá problema.

Você sempre tem que ficar atento para quantas variáveis você envia e/ou retorna, ou o compilador dará erro (te alertará).

O SCRIPT_END está em cima (após fechar o escopo principal), mas também pode ficar embaixo de tudo (no fim de todo o código). Isto não importa, faça o que mais lhe agrada. Eu particularmente prefiro usar embaixo do escopo principal como nos exemplos acima.

Você pode tratar um CLEO_CALL como um código normal, usando WAIT etc, mas tome cuidado pois na maioria das vezes você só está chamando ele para fazer uma coisa e retornar outra, ele é mais útil para coisas instantâneas (a não ser que você esteja usando ele para realmente abrir novas portas para "novos" caminhos de script).

E sobre aquele 0 que nós nunca mexemos nele: Ele era usado na época do Sanny Builder, onde era necessário digitar o número de quantas variáveis (ou outros valores! Melhor dizendo: Quantos argumentos) você está enviando, ou retornando. Agora, no GTA3script esta contagem é automática, então tudo o que você tem que fazer é deixar 0 ali que o compilador fará o trabalho para você. Caso você mudar o 0, terá um alerta de erro.


Deixando claro!

Para terminar, eu queria deixar claro que GOSUB e CLEO_CALL é sim muitíssimo utilizado em mods.

Sim, é muito utilizado sim.

Eu estou falando que sim, lembre-se.

Por exemplo, eu estou fazendo um mod de MP3 player e foi pressionado a tecla para ir para a próxima música: Eu usarei um GOSUB para descarregar a música atual, e outro GOSUB para chamar a próxima música. O script ficaria assim:

Código: Selecionar tudo

IF IS_KEY_PRESSED VK_KEY_K
    GOSUB release_song
    GOSUB load_next_song
    GOSUB play
    WHILE IS_KEY_PRESSED VK_KEY_K
        WAIT 0
    ENDWHILE
ENDIF
E todo o procedimento de descarregar uma música e tocar outra, estaria lá nas labels dos GOSUBs, enquanto no script principal eu teria somente isso acima, na qual deixa tudo muito mais organizado e confortável para ler, né?
E quando eu por exemplo desligar o MP3 player, eu vou ter que descarregar a música também, portanto eu usarei novamente o GOSUB  release_song.

Outro exemplo foi num mod meu chamado Ear Ringing (zumbido no ouvido) onde eu escolhi fazer o loop principal do mod funcionar totalmente por GOSUBs:

Código: Selecionar tudo

main_loop:
WAIT 0

GOSUB ProcessVolume

IF IS_PLAYER_PLAYING 0
    GOSUB GetLastExplosionCoord

    IF GOSUB IsNewExplosion
        GOSUB StoreNewExplosion

        IF GOSUB IsExplosionNearPlayer
            GOSUB CalculateVolume

            IF bIsAudioPlaying = FALSE
                GOSUB PlayAudio
            ENDIF
            
        ENDIF
    ENDIF
ENDIF

GOTO main_loop
Veja que a lógica do mod está aí, todo escrito por GOSUBs, de uma maneira muito fácil de ler e entender, enquanto o que cada GOSUB faz estão todos separados em outra parte do script, assim deixando mais limpo e não tirando o foco da parte principal do mod (o loop principal, onde está presente a lógica). Veja o código fonte completo. Acredito que o código deste mod ficou bem organizado.

É esta a dica que eu dou, tire os "códigos feios" da sua frente, jogue-os em algum canto e use um GOSUB ou CLEO_CALL para chamá-los, faça com que a parte principal do seu código seja limpa, assim também caprichando no nome das labels.

O CLEO_CALL também é ótimo para ser usado várias vezes, mas só use caso você realmente achar necessário "ir para fora" do script principal. Tanto que nos exemplos que eu fiz aqui são simples e óbvios, o único exemplo realmente útil foi o do ped stats, o resto podia ser feito direto no código, ou em algum GOSUB! Mas para o tutorial ficar mais fácil, usei exemplos fáceis.
É comum você no início não encontrar tanta utilidade em CLEO_CALL, por ser mais útil em coisas mais complexas.
Note também que CLEO_CALL é um pouco pesado pro script, nada tão preocupante, mas tenha em mente que GOSUB nunca influencia no desempenho, enquanto um uso exagerado de CLEO_CALL sim.

Atualização: A partir da CLEO 4.4.3 (de 2023) é possível usar IF com AND ou OR (ou seja, múltiplas condições) para CLEO_CALL. Eu não sei se eu avisei este problema em outra parte do tutorial, então estou adicionando isto aqui. Antes havia problema em fazer isto, mas agora não há.

Um dos exemplos "simples" e úteis para o CLEO_CALL, também seria você, por exemplo, está criando vários peds (chars), então quando você cria um char você envia ele para um CLEO_CALL, onde neste CLEO_CALL teria comandos para "configurar" o seu char.

Seria mais ou menos assim:

Código: Selecionar tudo

LVAR_INT char // In

SetupChar:
SET_CHAR_HEALTH char 2000
SET_CHAR_WEAPON_SKILL char 2
SET_CHAR_MONEY char 1000
SET_CHAR_ACCURACY char 60
SET_CHAR_SHOOT_RATE char 80
CLEO_RETURN 0
Assim basta você criar o char e chamar a função acima desta maneira:

Código: Selecionar tudo

CREATE_CHAR PEDTYPE_GANG2 FAM1 0.0 0.0 0.0 (member1
CLEO_CALL SetupChar 0 (member1)
CREATE_CHAR PEDTYPE_GANG2 FAM1 0.0 0.0 0.0 (member2)
CLEO_CALL SetupChar 0 (member2)
Perceba que você não precisa retornar nada, afinal, você não está editando a variável, você só está aplicando comandos no char referenciado por aquela variável — se esta dúvida bateu pela sua cabeça, você esqueceu o que é um valor "handle"!

Viu como é divertido? É só liberar a sua mente.
Nota: Se ainda não viu, veja o tutorial de como criar CHARs etc.
  

Próxima parte:
14. Indentação

13. GOSUB e CLEO_CALL

Enviado: 26 Mai 2018, 08:16
por Junior_Djjr
Esta é outra parte que mudou basta comparada ao tópico antigo. Acredito que ficou muito mais claro agora.

13. GOSUB e CLEO_CALL

Enviado: 16 Jun 2018, 20:25
por Saudoso
Junior_Djjr escreveu:
26 Mai 2018, 07:49
E se fazermos igual
Não seria "E se fizermos?" :peepo8:

13. GOSUB e CLEO_CALL

Enviado: 16 Jun 2018, 21:33
por Pierre
Saudoso escreveu:
Junior_Djjr escreveu:
26 Mai 2018, 07:49
E se fazermos igual
Não seria "E se fizermos?" :peepo8:
"Significado de Fazermos
Fazermos vem do verbo fazer. O mesmo que: avaliarmos, compormos, comportarmos, constituirmos, construirmos, criarmos, doarmos, elaborarmos, equivalermos, executarmos, fingirmos, gerarmos, percorrermos, prepararmos, provocarmos, realizarmos".

13. GOSUB e CLEO_CALL

Enviado: 17 Jun 2018, 11:04
por Saudoso
Pierre escreveu:
Saudoso escreveu:
Junior_Djjr escreveu:
26 Mai 2018, 07:49
E se fazermos igual
Não seria "E se fizermos?" :peepo8: 
"Significado de Fazermos
Fazermos vem do verbo fazer. O mesmo que: avaliarmos, compormos, comportarmos, constituirmos, construirmos, criarmos, doarmos, elaborarmos, equivalermos, executarmos, fingirmos, gerarmos, percorrermos, prepararmos, provocarmos, realizarmos". 
Imagem

Entendo

13. GOSUB e CLEO_CALL

Enviado: 17 Jun 2018, 12:26
por Pierre
Saudoso escreveu:
Pierre escreveu:
Saudoso escreveu:
Junior_Djjr escreveu:
26 Mai 2018, 07:49
E se fazermos igual
Não seria "E se fizermos?" :peepo8:
"Significado de Fazermos
Fazermos vem do verbo fazer. O mesmo que: avaliarmos, compormos, comportarmos, constituirmos, construirmos, criarmos, doarmos, elaborarmos, equivalermos, executarmos, fingirmos, gerarmos, percorrermos, prepararmos, provocarmos, realizarmos".
Imagem

Entendo
e tipo bolacha e biscoito

13. GOSUB e CLEO_CALL

Enviado: 17 Jun 2018, 16:17
por Junior_Djjr
"Fazermos" é infinitivo :hm:
Troquei.

13. GOSUB e CLEO_CALL

Enviado: 26 Jun 2018, 20:18
por Moreno_Sensual
Me deu um overclock essa parte 

13. GOSUB e CLEO_CALL

Enviado: 26 Jun 2018, 22:00
por Um_Geek
Um mod cleo simples que tenho para fazer testes com gangs que usa o básico desta parte do tutorial.

SpoilerAbrir

Código: Selecionar tudo

SCRIPT_START
{
    NOP

    LVAR_INT scplayer group member[3] model[3] weaponId count
    LVAR_FLOAT offsy x, y, z, a

    GET_PLAYER_CHAR 0 scplayer

    GOSUB ReadIni

    Main_Loop:
        WAIT 40
        IF IS_PLAYER_PLAYING 0 
            IF TEST_CHEAT "GGPL"
                GOSUB GangSpaw
                PRINT_HELP_STRING "Cheat Ativado"
            ENDIF
            IF TEST_CHEAT "RLGG" 
                GOSUB ReadIni
                PRINT_HELP_STRING "Configuracoes Recarregadas"
            ENDIF
        ENDIF
    GOTO Main_Loop

    GangSpaw:
        GET_PLAYER_GROUP 0 group
        GET_CHAR_HEADING scplayer a
        offsy = 2.0
        a -= 180.0
        REPEAT 3 count
            // limpar grupo
            IF DOES_CHAR_EXIST member[count] 
                REMOVE_CHAR_FROM_GROUP member[count]
                MARK_CHAR_AS_NO_LONGER_NEEDED member[count]
            ENDIF
            // novo grupo
            GET_OFFSET_FROM_CHAR_IN_WORLD_COORDS scplayer 0.0 offsy 0.0 x y z
            IF CLEO_CALL NewChar 0 model[count] x y z a (member[count])
                CLEO_CALL SetWeapon 0 member[count] weaponId 300
                SET_GROUP_MEMBER group member[count] 
                offsy += 1.5
            ENDIF
        ENDREPEAT
    RETURN

    ReadIni:
        IF NOT READ_INT_FROM_INI_FILE "cleo\gang.ini" "settings" "model1" model[0]
            model[0] = 105
            WRITE_INT_TO_INI_FILE model[0] "cleo\gang.ini" "settings" "model1"
        ENDIF
        IF NOT READ_INT_FROM_INI_FILE "cleo\gang.ini" "settings" "model2" model[1]
            model[1] = 106
            WRITE_INT_TO_INI_FILE model[1] "cleo\gang.ini" "settings" "model2"
        ENDIF
        IF NOT READ_INT_FROM_INI_FILE "cleo\gang.ini" "settings" "model3" model[2]
            model[2] = 107
            WRITE_INT_TO_INI_FILE model[2] "cleo\gang.ini" "settings" "model3"
        ENDIF
        IF NOT READ_INT_FROM_INI_FILE "cleo\gang.ini" "settings" "weapon" weaponId
            weaponId = 32
            WRITE_INT_TO_INI_FILE weaponId "cleo\gang.ini" "settings" "weapon"
        ENDIF
    RETURN
}

// Este cleo_call cria um ped tipo gang e o retorna.
{
    LVAR_INT model // in
    LVAR_FLOAT x, y, z, a // in
    LVAR_INT hPed 

    NewChar:
        IF IS_MODEL_AVAILABLE model 
            IF NOT HAS_MODEL_LOADED model 
                REQUEST_MODEL model 
                LOAD_ALL_MODELS_NOW 
            ENDIF 
            CREATE_CHAR PEDTYPE_GANG2 model x y z hPed 
            SET_CHAR_HEADING hPed a 
            MARK_MODEL_AS_NO_LONGER_NEEDED model
        ENDIF
        DOES_CHAR_EXIST hPed
    CLEO_RETURN 0 hPed // out
}

// Este cleo_call equipa uma arma pelo id ao ped 
{
    LVAR_INT hPed, weaponId, ammo //in
    LVAR_INT model

    SetWeapon:
        GET_WEAPONTYPE_MODEL weaponId model 
        IF IS_MODEL_AVAILABLE model 
            IF NOT HAS_MODEL_LOADED model 
                REQUEST_MODEL model 
                LOAD_ALL_MODELS_NOW 
            ENDIF
            GIVE_WEAPON_TO_CHAR hPed weaponId ammo
            MARK_MODEL_AS_NO_LONGER_NEEDED model
        ENDIF
    CLEO_RETURN 0
}
SCRIPT_END

13. GOSUB e CLEO_CALL

Enviado: 11 Jul 2018, 12:16
por TG4M3R
Le eu ~ Li o tutorial todo com muita atenção, sou burro demais e não entendi nada, li de novo e entendi 25%, li de novo e entendi 50%, li de novo e entendi 75%, leio mais três vezes e não entendo nada, desisto. Volto com determinação e fé no dia seguinte que vou conseguir entender, e entendo tudo kkkkkk :facep:

Re: 13. GOSUB e CLEO_CALL

Enviado: 19 Dez 2018, 01:38
por Gabriel Pinheiro
mano do céu, esse tutorial tá sendo bem útil para mim.
eu programo em algumas linguagens, e não está sendo difícil de aprender(facilita muito pelo seu jeito de explicar)
e o que mais me impressiona é a peculiaridade do gta3script... Adoro aprender coisas novas

Re: 13. GOSUB e CLEO_CALL

Enviado: 16 Jun 2019, 13:40
por Such02
SpoilerAbrir

Código: Selecionar tudo

SCRIPT_START
{
    LVAR_INT scplayer
    LVAR_INT member1 member2
    LVAR_FLOAT x y z

    GET_PLAYER_CHAR 0 scplayer

    main_loop:
    WAIT 0
    
    GET_CHAR_COORDINATES scplayer x y z
    IF IS_KEY_PRESSED VK_KEY_J
        y += 2.0
        x += 2.0
        GOSUB create_member
        WHILE IS_KEY_PRESSED VK_KEY_J
            WAIT 0
        ENDWHILE
    ENDIF
    GOTO main_loop

    create_member:
    REQUEST_MODEL FAM1
    WHILE NOT HAS_MODEL_LOADED FAM1
            WAIT 0
    ENDWHILE
    CREATE_CHAR PEDTYPE_GANG2 FAM1 x y z member1
    CLEO_CALL SetupChar 0 (member1)
    CREATE_CHAR PEDTYPE_GANG2 FAM1 x y z member2
    CLEO_CALL SetupChar 0 (member2)
    MARK_MODEL_AS_NO_LONGER_NEEDED FAM1
    MARK_CHAR_AS_NO_LONGER_NEEDED member1
    RETURN
}
SCRIPT_END

{
    LVAR_INT char // In

    SetupChar:
    SET_CHAR_HEALTH char 2000
    SET_CHAR_WEAPON_SKILL char 2
    SET_CHAR_MONEY char 1000
    SET_CHAR_ACCURACY char 60
    SET_CHAR_SHOOT_RATE char 80
    CLEO_RETURN 0
}

   Esse foi um código que eu fiz com base no que eu aprendi sobre o Gosub e Cleo_Call (Perceba que eu usei os dois nesse código). A base dele veio apartir do que o tutorial proporcionou.
 

Re: 13. GOSUB e CLEO_CALL

Enviado: 12 Jun 2020, 04:51
por VictorMac
O meu ficou meio diferente mas deu no que eu queria.

Código: Selecionar tudo

SCRIPT_START
{    
    LVAR_INT scplayer my_ped
    LVAR_FLOAT x y z
    
    GET_PLAYER_CHAR 0 scplayer 

    main: 
    WAIT 0 // if not = Freeze 

    IF TEST_CHEAT P1
        WHILE TEST_CHEAT P1
            WAIT 0 
        ENDWHILE
        REQUEST_MODEL FAM2
        WHILE NOT HAS_MODEL_LOADED FAM2
            WAIT 0
        ENDWHILE    
        GOSUB spwn
    ENDIF

    GOTO main

    spwn:
    GET_CHAR_COORDINATES scplayer (x y z)
    x += 2.5
    CREATE_CHAR PEDTYPE_GANG2 FAM2 (x y z) (my_ped)
    CLEO_CALL config 0 (my_ped)
    MARK_MODEL_AS_NO_LONGER_NEEDED FAM2
    PRINT_FORMATTED_NOW "BONECO Criado na X:%3.f Y:%3.f Z:%3.f" 10000 (x y z)
    WAIT 10000 // Esperar até a mensagem acabar para Spawnar outro.
    RETURN            

}
SCRIPT_END
{
    LVAR_INT char 

    config:

    REQUEST_MODEL AK47
    WHILE NOT HAS_MODEL_LOADED AK47
        WAIT 0
    ENDWHILE
    SET_CHAR_HEALTH (char) (1000)
    SET_CHAR_WEAPON_SKILL (char) (1)
    GIVE_WEAPON_TO_CHAR (char) (WEAPONTYPE_AK47) (9999)
    MARK_MODEL_AS_NO_LONGER_NEEDED AK47

    CLEO_RETURN 0
}

Re: 13. GOSUB e CLEO_CALL

Enviado: 24 Abr 2022, 11:06
por Junior_Djjr
Anos depois, estudando C#, eu descobri que GOSUB é o equivalente à "Local Functions". Ou seja, se você já tem experiência em programação, fica mais fácil de você entender.

Coloquei isto no tutorial.