Como criar scripts com CLEO+
Enviado: 12 Out 2020, 01:46
For english, use the translator jump menu at top of this page. Or if you prefer, simply use the documentation.
Tópico de sugestões de comandos: f16-utilidades/t2878-sugestoes-cleo-moonloader
Se você quer aprender a criar CLEO com gta3script (recomendado para CLEO+): f141-secao-tutorial-gta3script/t26-indi ... gta3script
NOVIDADE: Agora todos os comandos do CLEO+ estão bem documentados no Sanny Builder Library!
(lembrando que não é específico do Sanny Builder, inclusive usa o mesmo nome do gta3script)
O que é CLEO+?
CLEO+ (ou CLEOPlus) é um plugin que expande a CLEO Library, adicionando quase 300 novos comandos (3 vezes maior do que toda a CLEO! 6 vezes maior que a atualização da CLEO 4!), com funções realmente úteis, algumas que realmente revolucionam a maneira de criar mods CLEO.
Também inclui alguns dos principais do NewOpcodes.cleo, e todo o ClipboardCommands.cleo como retrocompatibilidade.
Eu (Junior_Djjr) crio mods CLEO desde 2011, quase 1 década, sou quem mais criou mods CLEO no mundo, e desde lá venho ensinando pessoas a criarem mods CLEO neste fórum, portanto, eu tenho total noção do que a CLEO precisa para ficar melhor, e pra isto eu iniciei este projeto.
Diferente de outros plugins para a CLEO, este foi focado em resolver e simplificar as operações mais simples, isto é, deixar a criação de mods CLEO ainda mais simples e agradável, para mods mais fáceis de serem criados, estáveis, menos propensos à bugs e conflitos. Sendo assim, iniciantes terão menos dificuldades, e experientes passarão menos raiva.
CLEO+ é somente para a versão 1.0 US do GTA San Andreas, inicialmente focado em GTA3script, mas também adaptado para Sanny Builder. E não aumenta o limite de variáveis, isto é trabalho pra CLEO em si ou o uso de outras gambiarras, mas adiciona excelentes funcionalidades para evitar tal limitação.
Isto não é uma documentação. Quase.
Eu escrevi isto em forma de tutorial + documentação, foi um texto pensando em "Olhe, agora você pode fazer isto!".
No entanto, agora há uma documentação de verdade no Sanny Builder Library (lembrando que não é específico do Sanny Builder, inclusive usa o mesmo nome do gta3script). Agradecimentos ao OrionSR por dedicar o tempo dele para documentar tudo.
Manipulação de scripts
Cria um novo custom script, como STREAM_CUSTOM_SCRIPT, mas usando uma label do seu script em vez do arquivo.
Isto traz realmente muitos benefícios: O novo script que será iniciado será independente, terá suas próprias variáveis etc, no entanto, compartilhará o exato mesmo espaço de memória do seu atual. Isto é muito bom para o desempenho, pois não causa fragmentação de memória e a inicialização do novo script é muito leve, diferente do STREAM_CUSTOM_SCRIPT que abre e lê um arquivo e tira uma cópia deste arquivo pra sua RAM etc. Perceba que, por estar no mesmo espaço de memória do script "pai", o script/thread memory será o mesmo. Em alguns casos, isto é muito útil para deixar o seu script "multi tarefas", ou até mesmo, recursivo, pois você pode criar quantos novos scripts/threads quiser.
Lembre-se também que, como o STREAM_CUSTOM_SCRIPT, você pode enviar variáveis ou valores quaisquer para o outro script, e esses valores cairão nas primeiras variáveis dele, semelhante ao CLEO_CALL, inclusive, você normalmente usará um novo escopo nessa nova label com as novas variáveis lá, semelhante ao CLEO_CALL.
Os comandos de criar um novo script não retornam o ponteiro do script criado, portanto, logo após criar um script, se você quer o ponteiro dele (sem precisar usar GET_SCRIPT_STRUCT_NAMED, que não é seguro, visto que vários scripts podem ter o mesmo nome), use isto. É ótimo para em seguida usar GET_SCRIPT_VAR e SET_SCRIPT_VAR.
Anteriormente chamados de GET_THREAD_VAR e SET_THREAD_VAR. Alterado pois o nome "thread" não faz sentido e caiu em desuso pela comunidade.
Lê ou escreve valores de uma variável de outro script/thread, excelente para um script controlar o outro.
Você simplesmente envia o ponteiro para o script (GET_LAST_CREATED_CUSTOM_SCRIPT, GET_SCRIPT_STRUCT_NAMED, GET_THIS_SCRIPT_STRUCT etc) e o ID da variável, onde a primeira variável definida é 0, lembrando que TEXT_LABEL ocupa 2 variáveis e TEXT_LABEL16 ocupa 4 variáveis, portanto, você deve pular elas na hora da contagem. no Sanny Builder é mais simples pois você trabalha diretamente com o número das variáveis.
Eventos
Isto irá literalmente mudar a maneira que você cria scripts CLEO!
Vamos supor que você queira recriar o cheat de "todos os pedestres com armas", antes da CLEO+, você rodaria todos os frames pegando todos os pedestres, checando se está sem arma, e colocando a arma nele. PÉSSIMO!!!
Com CLEO+ você simplesmente usa SET_SCRIPT_EVENT_CHAR_CREATE, assim, durante a criação de um CHAR, ele será enviado para esta label, e lá você dá a arma. Simples assim!
Isto é bom em todos os aspectos, o seu script fica mais organizado, avançado, estável e melhor performance.
A única limitação é que os eventos são "one shot", ou seja, eles são executados naquela label, e já precisam retornar o mais rápido possível para continuar processando o jogo, sem uso de WAIT.
Os comandos de eventos funcionam como "SET", ou seja, um toggle boolean onde você somente ativa ou desativa (lembre-se, para desativar, o comando precisa ser idêntico ao de ativar, para indicar que é o mesmo). Mas não entenda mal: Quando você liga um, ele realmente é criado, portanto, NUNCA use estes comandos em um loop!!! Você irá multiplicar os eventos.
Após o argumento da label, normalmente será necessário enviar uma variável, assim, tal evento armazenará o argumento nesta variável, em alguns casos, mais de uma. Você normalmente usará alguma variável temp qualquer. Internamente, a única coisa que o CLEO+ fará, é enviar o processo do seu script para esta label, e depois retornar para onde estava. Não há nenhuma diferenciação das variáveis fora do event, é simplesmente o mesmo script, mesmo escopo, ele só será executado temporariamente em outra região, muito simples.
Retorna de um event. Events não suportam WAIT!
Executado exatamente antes do jogo ser salvo. Você pode querer deletar todo o conteúdo do seu script que normalmente ficará preso no jogo salvo. Outra utilidade é implementar um sistema de salvar informações do seu script em algum arquivo no disco do jogador para ser reutilizado no próximo load. O argumento é o número ID do slot (espaço) a ser salvo.
Ao criar ou apagar um CHAR.
Ao criar ou apagar um CAR.
Ao criar ou apagar um OBJECT.
Durante o menu. A variável é setada como "1" caso acabou de pausar (no primeiro frame ao pausar), assim sendo facilmente útil tanto para executar algo logo durante a pausa, ou durante o processo do menu de pausa. Lembrando que o SCM não foi pensado em ser executado no menu, portanto é limitado (você não consegue desenhar textos, sprites etc durante o menu).
Ao processar determinada entidade. Este evento é executado em todas as pessoas, carros ou objetos naquele frame. Evite usar em objetos pois é comum haver centenas deles, leia mais dicas de otimização no BUILDING abaixo. Lembrando que nem todos os objetos do jogo são "OBJECT", os estáticos e mais importantes do mapa são "BUILDING", os "OBJECT" são, por exemplo, postes, lixeiras etc.
Em geral o desempenho é igual, ou muito pouco pior do que usar GET_ANY_*_RECURSIVE, portanto, se você tem dúvida entre GET_ANY_*_RECURSIVE ou EVENT_*_PROCESS, prefira o primeiro, mas muitas vezes a organização do código vale mais do que isso.
Outra coisa interessante é que o evento é executado logo antes da renderização deles, portanto, não existe nenhum atraso caso você queira por exemplo renderizar uma luz em um carro, a posição da luz, mesmo com o carro em movimento, será exata, diferente dos métodos convencionais.
Como o de cima, mas para BUILDING. Isto é, objetos estáticos e importantes no mapa, que não são considerados "OBJECT", em outras palavras, CBuilding e não CObject. O argumento retornado será um ponteiro para o CBuilding, que não é nada mais nada menos que um CEntity. CLEO+ há alguns poucos comandos para ENTITY (procure), e o próprio jogo nunca implementa isto no SCM, portanto, se você realmente precisa trabalhar com BUILDING, normalmente você trabalhará com manipulação de memória.
Evite usar este evento, pois normalmente será executado centenas, senão milhares de vezes. Uma dica de otimização é desativar este evento caso a altitude da câmera seja muito alta, pois Project2DFX faz processar milhares de CBuilding quando você está voando alto, e normalmente você não precisará. Dentro dele, faça uma checagem bem específica para processar aquele BUILDING se for realmente necessário, por exemplo um ID de um modelo específico.
Ao CHAR receber um dano qualquer. Normalmente você usará GET_CHAR_DAMAGE_LAST_FRAME para pegar as informações.
Ao CAR receber um dano de uma arma. Normalmente você usará GET_CAR_WEAPON_DAMAGE_LAST_FRAME para pegar as informações. Não é executado em colisões, para isto há outros comandos.
Ao ocorrer um impacto de tiro em qualquer local, qualquer coisa.
Há vários argumentos, e eles podem variar, lembre-se, nem sempre um tiro foi disparado por uma pessoa, nem atingido uma entidade, antes de tudo, cheque se os valores são válidos. Normalmente você usará GET_ENTITY_TYPE para saber se o atingido é um uma pessoa, carro etc.
Início do processamento do jogo (antes de todos os scripts, e quase todo o jogo ser processado). Útil para casos bem específicos. Cuidado pois pode não ser muito seguro para scripts.
Final do processamento do jogo (depois de todos os scripts, o jogo já foi processado, renderizado etc). Útil para casos bem específicos. Cuidado pois pode não ser muito seguro para scripts.
Lista de valores (container)
Isto é uma implementação do std::list do C++, para os leigos, é como se fosse uma array dinâmico, ou seja, em vez de trabalhar com um espaço estático na memória, cada item pode estar num espaço qualquer, e tal lista de itens é navegada um por um. É menos otimizado para o desempenho, mas é uma maneira excelente de trabalhar com lista de valores que pode variar de tamanho e você não tem como prever.
É uma maneira excelente de armazenar e ler informações no seu script sem o uso de variáveis e thread/script memory (mesmo que thread/script memory seja mais aconselhável para o desempenho, sinceramente, uma solução mais high level é mais agradável de se trabalhar, né?)
Apaga ou cria uma lista de determinado data type.
Adiciona um valor à lista (INT ou FLOAT, caso seja uma texto direto, use a variação STRING, lembrando que um ponteiro pra uma string é um INT).
Remove todos os valores da lista baseado no valor específico que você enviou.
Remove o valor na lista baseado num index, isto é, numa posição específica da lista.
Remove todos os valores na lista que estão entre 2 index, ou seja, início e fim.
Retorna o valor na lista baseado num index.
Retorna o tamanho total da lista, isto é, quantos itens tem.
Inverte todos os itens da lista; os últimos serão os primeiros;
Limpa a lista completamente, mas não a remove da memória. Use DELETE_LIST para apagá-la de verdade.
Substitui ou inserte um novo valor, dado um index da posição da lista. Assim você pode alterar o interior de uma lista sem precisar recriá-la etc.
Armazenar dados dentro de entidades
Você pode armazenar informações, como variáveis, dentro de uma pessoa, veículo ou objeto.
Trabalha como uma ponte que liga a função do plugin-sdk, muito útil para criar mods .asi, agora você pode utilizar em seus mods CLEO!
Por exemplo, um mod que você espirra perto de uma pessoa e ela é infectada, você armazena a informação da contaminação dentro da pessoa, e não dentro do seu script, assim, você pode, a qualquer momento, ler de novo aquela informação para saber se determinada pessoa está infectada ou não.
Eu recomendo que você leia o script teste da CLEO+ para entender como utilizar, pois é um conceito bem novo e peculiar.
Inicializa X variáveis internas naquela entidade. Você envia um identificador e número de quantas vars você precisa.
Normalmente você usará "AUTO" no identificador, assim a CLEO+ usará o ponteiro do seu script para determinar o valor do identificador, e automaticamente será um identificador único. Se você quer que a sua informação seja controlada por outros scripts, use um texto qualquer de até 99 caracteres, intermamente o texto será convertido para hash key.
Dica: visto que o "AUTO" usa o ponteiro do script como identificador, se outro mod quer trabalhar com o seu identificador, ele pode usar GET_SCRIPT_STRUCT_NAMED para pegar o ponteiro do seu script e usá-lo como identificador para assim controlar as mesmas variáveis daquele script, no entanto, isto é dependente do nome do script, e mais de um script pode ter o mesmo nome. Uma maneira melhor, principalmente se você está trabalhando com múltiplos scripts do mesmo mod, é usar GET_THIS_SCRIPT_STRUCT para pegar o ponteiro do seu script principal, e levar este valor para os seus outros scripts trabalharem no mesmo identificador.
Não fique inicializando todos os frames! O uso mais comum é antes checar se determinada variável existe com o GET, caso não exista, você usa o INIT para inicializar. Se por algum acaso você usar isto em uma entidade que já foi inicializada, os dados serão apagados e criados como novo, o que é ok, mas não é uma boa prática.
Aqui você envia o identificador, o ID da variável (a primeira é "1") e o valor para escrever lá (INT ou FLOAT).
Mesmo de cima, para retornar o valor.
Criar entidades sem prender no jogo salvo
Além de criar um objeto que não salva junto com o jogo, o comando já implementa as opções de offset e posicionar o objeto automaticamente no chão. Perceba que a posição do chão vem de uma coordenada 3D, ou seja, se adapta caso esteja embaixo de uma ponte.
Marca um gerador de veículo estacionado para não salvar junto com o jogo.
Novo sistema de BLIPs
Cria um BLIP no mapa do radar usando um sistema totalmente novo. Eles não são salvos no jogo salvo, nem atingem o limite de BLIPs do jogo, ou seja, você pode usar à vontade, sem medo.
Ainda, possibilita pintar numa cor RGBA (perceba, inclui transparência), opção de aparecer somente perto ou longe, e a utilizar um RWTEXTURE qualquer como sprite do BLIP, isto quer dizer que você agora pode usar literalmente qualquer textura como BLIP, inclusive de um .txd de sprite de script, utilizando GET_TEXTURE_FROM_SPRITE. No entanto, neste caso não aparecerá na legenda do mapa (mas afinal, quem usa a legenda?).
Ah, mas você quer usar o ID de uma sprite original do jogo (por exemplo, ícone de save)? Sem problemas, simplesmente use, e neste caso a legenda funcionará.
Pegar uma textura a partir de um .txd de script
NewOpcodes.cleo implementou maneiras legais de ter controle à uma textura a partir de .bmp, .png e .dds, no entanto, não era compatível com instalação no ModLoader, nem a melhor maneira de trabalhar.
CLEO+ possibilita retornar uma textura (um ponteiro para RwTexture) a partir de um arquivo .txd, sim, daqueles que você coloca numa pasta "models/txd", totalmente compatível com ModLoader e facilmente trabalhado com Magic.TXD, podendo usar compressão, mipmaps etc (não use mipmaps para texturas/sprites usadas na interface!!!).
É simplesmente a sprite que você carrega com LOAD_TEXTURE_DICTIONARY e LOAD_SPRITE.
E esta textura pode ser usada de maneira interna no jogo, como trocar alguma textura do jogo por ela (desde que você consiga o acesso), ou para criar BLIPs personalizados com ADD_CLEO_BLIP citado acima.
Novo sistema de desenhar sprite/textura na tela.
Não atinge os limites de sprites do jogo (que originalmente é 128 por script), você pode usar milhares.
Em vez de um ID de uma sprite, você usa uma textura diretamente (RWTEXTURE). Se você quer a sprite como no sistema nativo do jogo, use GET_TEXTURE_FROM_SPRITE para pegar a sprite do .txd que você carregou.
Enviando "0" no argumento de textura, simplesmente renderizará sem textura, igual ao DRAW_RECT.
Diferente do método nativo do jogo, este você NÃO precisa usar USE_TEXT_COMMANDS para atualizar a tela, é sempre atualizado automaticamente, basta deixar este comando rodando em loop todos os frames para que seja desenhado.
No argumento DRAW_EVENT você escolhe exatamente o momento que a sprite será desenhada na tela, ou seja, você pode desenhar na frente ou atrás da hud etc.
O argumento Depth é o eixo de profundidade da sprite, usado somente em sprites mascaradas. Você pode deixar 0.0.
FixAR corrige o aspect ratio, assim você não precisa usar GET_FIXED_XY_ASPECT_RATIO, o comando fará isto pra você, semelhante ao GTA V.
MaskVertCount e MaskVertArray é onde você define a máscara, se você não está utilizando o comando como máscara, simplesmente deixe "0". O trabalho com máscara não é tão user friendly, foi pensado em casos mais específicos: em count, é o número total de vértices, enquanto array é um ponteiro onde está armazenado todas as posições X e Y de cada vértice. A correção de aspect ratio não é feita, pois é basicamente impossível definir o "tamanho", visto que são posições cruas, assim, você terá que corrigir o AR você mesmo nos valores das posições, o que requer certa matemática.
Desenhar na tela
Você envia uma coordenada 3D numa posição do mapa, e este comando retorna a posição 2D da tela do jogo, inclusive um valor de tamanho para você usar para desenhar um texto na tela que se adapta com a distância que o ponto 3D está.
Isto é exatamente (até um pouco melhor) o que a Rockstar North usou para realizar testes de depuração durante o desenvolvimento do jogo. Você pode querer usar, como eu usei no Real Traffic Fix, é de fato muito útil para testes.
Os argumentos CheckNearClip e CheckFarClip são para limitar a distância mínima e máxima. Você pode usar este comando com IF para saber se o ponto está dentro da visão mínima e máxima da câmera do jogo.
Os comandos DISPLAY_TEXT são péssimos para certos casos, pois ele pede um GXT, e antes de usá-lo, você precisa usar uma sequência de vários comandos para formatá-lo (sim, usar GOSUB com determinada formatação é uma boa, mas ainda chato). Este comando é um novo sistema, você envia de fato uma string, ou um ponteiro pra uma string, e nele mesmo, há as opções básicas de formatação, inclusive uma pré-formatação com bom visual, utilizando outline. Se não é o bastante, use a variação DRAW_STRING_EXT, que inclui todas as opções de formatação num único comando!
Perceba também que inclui o DRAW_EVENT, igual ao DRAW_TEXTURE_PLUS, isto é, você pode escolher exatamente o momento que será desenhado, antes ou depois do hud por exemplo, prefira usá-lo junto com DRAW_TEXTURE_PLUS se você quer desenhar fundos para o texto etc, e há também o FixAR, que corrige automaticamente o aspect ratio, para a fonte não ficar esticada em monitores widescreen.
Tarefas de pessoas (CHAR TASK)
Uma das coisas que deixa os mods CLEO muito instáveis, atrapalhando e causando bugs na inteligência artificial do jogo, como interrompendo ações dos pedestres etc, é justamente a falta de boas e fáceis maneiras de checar as tarefas atuais daquele CHAR, o que inclusive faz os modders usarem métodos ruins, como checar se está fazendo tal animação.
CLEO+ roda todas as pessoas do jogo naquele frame e guarda, como um cachê, a informação de quais tasks e situação daquela pessoa. Portanto, você pode utilizar aos milhares, a performance é ótima.
Checa se o CHAR está fazendo uma task de determinado ID.
Isto é realmente muito útil, pois o jogo tem quase 400 tasks, e você pode checar todas elas para saber se determinado CHAR está fazendo determinada coisa. No entanto, não necessariamente a task prioritária, ele pode estar com uma task de matar alguém, mas no momento está simplesmente correndo por aí.
Você também pode querer dar uma olhada no GET_CHAR_PEDSTATE e GET_CHAR_SIMPLEST_ACTIVE_TASK, principalmente este último, que retorna a tarefa principal atual.
Retorna o ponteiro de determinada task. Útil para fazer operações mais avançadas com a classe daquela task.
Abaixo há outros comandos mais específicos, prefira usá-los em vez deste, pois eles consideram mais de uma tarefa (ou seja, menos propenso à erros) e com performance ainda melhor. Também dê uma olhada no GET_CHAR_SIMPLEST_ACTIVE_TASK.
Retorna a tarefa ativa mais "simples" de todas, basicamente, a principal. Por exemplo, há uma tarefa de uma pessoa matar a outra, não retornará a tarefa de matar, mas sim de estar correndo até a pessoa ou usando a arma.
Retorna o ponteiro mas também o ID dela, para uma fácil checagem de qual tarefa é. Isto é diferente da IS_CHAR_DOING_TASK_ID e GET_CHAR_TASK_POINTER_BY_ID pois elas consideram todas as tarefas, mesmo não sendo a principal.
Retorna o CHAR que determinado CHAR está tentando matar. Sério que o jogo não tinha um comando para isto??
Checa se o CHAR está usando uma arma (não só segurando, mas de fato usando, ou seja, mirando ou atirando). Para somente atirando, use GET_CHAR_WEAPON_STATE.
Checa se o CHAR está lutando.
Checa se o CHAR está caído no chão, por exemplo nocauteado.
Checa se o CHAR está entrando ou saindo de algum carro.
Checa se o CHAR está realizando qualquer animação nomeada, isto é, normalmente de scripts. Útil para o seu mod não interromper as animações de outro mod ou algo assim.
Este comando é um monstro: Durante o cachê, CLEO+ considera se tal CHAR não está fazendo nenhuma tarefa importante, como matar alguém, correndo em pânico etc. Caso ele esteja "disponível para outras tasks", este comando retornará verdadeiro.
Esta explicação é simplista demais, mas pense assim: Este comando retorna verdadeiro caso o CHAR possa parar o que ele está fazendo para conversar com você. É basicamente isto. Útil para muitos mods, por exemplo, um mod que faz os pedestres atenderem o celular, ele não vai querer atender o celular enquanto ele está lutando contra alguém ou fugindo.
Há também a opção de incluir animações de script nesta checagem.
Você pode querer juntar este com o IS_CHAR_DOING_TASK_ID para adicionar mais exceções. Lembre-se, teste muito.
Limpa todas as tarefas primárias (preserva as secundárias).
Limpa todas as tarefas secundárias (preserva as primárias). É uma boa maneira de limpar as tarefas, como animações secundárias, sem atrapalhar na inteligência artificial do CHAR, visto que tarefas primárias são muito importantes.
Gradient noise
Gradient noise é uma excelente utilidade para diversos desenvolvimentos, principalmente gráficos e de jogos.
Consistente em uma geração de número aleatório que considera seus "vizinhos" para uma transição suave (degradê).
Por exemplo, eu utilizei isto para simular a vibração do motor e escapamento de carros com VehFuncs. Se eu tivesse usado uma geração aleatória qualquer, o efeito não seria natural.
Se você acha que não conhecia, na verdade você conhece muito bem: gradient noise é o coração do Minecraft. Você pode gerar mapas inteiros ou parciais (por exemplo, lixos no chão) utilizando gradient noise.
Retorna o valor de um ponto do gradient noise utilizando o algorítimo "perlin noise" (mais especificamente, através do simplex noise).
Se você quer utilizar gradient noise de maneira mais simples possível, use este comando. Você simplesmente envia uma variável de progresso/offset que retornará um valor em torno de -1.0 e 1.0 (mas pode ultrapassar).
O valor enviado pode ser numa faixa de 10... 100... 1000... Depende do resultado que você quer. Normalmente você irá trabalhar em um loop, subindo ou abaixando suavemente uma variável, e terá o valor do noise retornado em uma outra. Há exemplo no script de teste da CLEO+.
O valor inicial pode ser considerado uma "seed"
Igual ao de cima, mas agora, com vários argumentos para você personalizar o resultado final. Se você não sabe por onde começar, teste: PERLIN_NOISE_FRACTAL 2 0.1 1.0 1.0 2.0 0.5 (f)
O "octaves" é um tanto interessante: à grosso modo ele mistura o noise mais de uma vez para retornar um resultado ainda mais natural. Indispensável para por exemplo gerar um terreno mais natural, mas há impacto negativo na performance, cada octave multiplica o cálculo.
Usar octave "1" os argumentos não serão importantes, exceto frequency, que define a frequência que os valores irão saltar.
No script teste da CLEO+ há literalmente um visualizador de perlin noise embutido onde você configura os valores e visualiza na tela em escala de cinza! Dê uma olhada.
Pegar entidades (carros, pessoas, objetos)
Finalmente eu tive a oportunidade de reinventar os comandos GET_RANDOM_*_NO_SAVE_RECURSIVE! Eu odiava eles.
Neste, retorna literalmente todas as pessoas, veículos ou objetos, sem exceções, sem checagem de distância, mas agora, utilizando uma variável que informa o progresso da busca.
O uso é simples: tenha uma variável tempo, seta-a para 0, e rode este comando em um WHILE usando-a no argumento de progresso. Num único WHILE você terá acesso às entidades (diferente da solução anterior que precisava de um IF e depois um WHILE), e o melhor: devido ao progresso da busca ser numa variável, isto resolve o problema do comando antigo da CLEO, que não havia como colocar um dentro do outro, neste, você pode usar quantos você quiser!
Veja no script de teste da CLEO+ um exemplo de uso, bem mais agradável. Mas lembre-se que CLEO+ tem events, e os events podem ser úteis para você caso o seu mod precise disso a todo o momento.
Retorna o policial mais próximo de um CHAR numa distância limite. Muito útil para mods que precisam detectar se há um policial vendo a cagada de alguma pessoa. Há também filtro para incluir ou não à pé, de carro, e se está te vendo ou não!
Mesmo de GET_CLOSEST_COP_NEAR_CHAR, mas agora é um policial próximo de certa posição.
Manipulação de memória
Mesma coisa do READ_MEMORY e WRITE_MEMORY, no entanto, inclui um offset que será somado, assim você transforma 2 linhas de código numa só, mais agradável e uma minúscula melhoria de desempenho, visto que é algo muito comum.
Mesmo de cima, mas agora além do offset (que pode ser 0, se você não precisa) ele lê e escreve múltiplas vezes. Você escolhe quantas vezes, e o tamanho a cada leitura ou escrita.
O melhor exemplo de uso é o seguinte: Imagine que você tem um ponteiro para uma coordenada XYZ e quer ler cada valor desta coordenada para 3 diferentes variáveis: READ_STRUCT_OFFSET_MULTI pCoord 0x0 3 4 (x y z). Simples assim.
Semelhante ao *_STRUCT_OFFSET mas em vez de um offset, é um index, que pula os bytes de 4 em 4.
Isto é, index 0 lerá os primeiros 4 bytes, index 1 lerá a partir do quinto byte. Isto é excelente para thread/script memory, pois é comum guardar uma sequência de dados de 4 bytes na thread/script memory, assim, você pode ler e escrevê-los baseado num index, o que é ótimo inclusive para o uso do REPEAT.
Dica: no index, use um CONST_INT para definir um nome para ele, o código fica bem organizado.
Copia o conteúdo da memória de um lugar pra outro com o determinado tamanho.
Escreve uma sequência de NOPs (ou seja, em nosso caso, 0x90) em alguma região da memória para "apagar" a execução.
Anteriormente isto era feito através de várias linhas de WRITE_MEMORY, visto que o WRITE_MEMORY não é mais do que um memory set, portanto era necessário escrever vários "0x90909090" etc. Este comando simplifica o processo.
Renderizar objetos em um CHAR ou OBJECT
Se você já tentou colocar um objeto na mão de um CHAR, conhece a dor de cabeça. O jogo é péssimo nisso, causa muitos problemas.
Esta nova solução você não cria um objeto, mas sim uma tarefa de renderização. CLEO+ irá renderizar aquele modelo durante a renderização daquela pessoa, como funcionam as armas do jogo.
Perceba que não há limites, você pode renderizar qualquer modelo do jogo (há algumas exceções que serão corrigidas) em qualquer parte do corpo de um CHAR, em qualquer rotação, tamanho, e até mesmo distorcer o objeto (igual à distorção 4D do Tuning Mod).
Você consegue até recriar a arma de um CHAR (dica: há uma flag no CPlayerData para esconder a arma, use em loop, mas somente player). Muito útil para objetos simples, como uma simples garrafa, quanto para criar trabalhos complexos como armaduras com super poderes.
A variação "FROM_SPECIAL" é para usar com "SPECIAL_MODEL", o que possibilita usar objetos carregados diretamente de um .dff e .txd (sem o uso de ID).
Da mesma forma, nas novas versões do CLEO+ há também para objetos:
Para simplificar o seu script, use isto, você tem a opção da CLEO+ esconder automaticamente o objeto caso a pessoa morra, pegue uma arma ou entre num veículo. A tal tarefa de renderização continua existindo, só não fará nada.
Mais controles básicos. Usar distorção junto com rotação ou escala pode ter resultados estranhos.
Embaixo do capô: A variável do RENDER_OBJECT é um ponteiro para uma class interna do CLEO+, não vou dar ela inteira aqui pois ela pode sofrer alterações, mas se você precisa de um trabalho mais avançado e técnico no resultado, o offset 0 é o CPed, offset 4 é RpClump, offset 8 é o RwFrame, e 12 é o RpAtomic. Caso o modelo seja um clump, o frame e atomic serão 0, caso contrário, o clump que será 0.
Isto é útil para trabalhar com subobjetos da hierarquia, como funciona no Tuning Mod. Por exemplo, adicione um objeto num .ide usando "hier" para ser um objeto comum em forma de clump, o tutorial do Tuning Mod ajuda, sabendo trabalhar com clumps, você conseguirá controlar a rotação, posição e tamanho de cada objeto filho, podendo criar animações complexas etc.
Modo 2 jogadores
Uma maneira de ativar e desativar o segundo jogador a partir de um CHAR já criado. Foi importante para a ideia do Coop Storyline e Recruit 2 Player.
Todos os mods de 2 jogadores precisam implementar uma correção para que possibilite cada jogador entrar em carros separados, ou os mesmos, pensando nisto, a própria CLEO+ implementa essa correção, com excelente funcionamento, basta ativá-la com este comando.
Clima e ambientação
O clima da ambientação do jogo é algo importante. Por que não havia o básico?
Já existe GET_TIME_OF_DAY mas além de ser um nome um pouco confuso de encontrar, na gigante maioria das vezes você só vai precisar da hora, assim é interessante ter um comando separado para usar somente 1 variável.
Retorna um valor entre 0.0 e 1.0, onde 0.0 é dia, 0.5 é tarde, 1.0 é noite. O valor é o mesmo usado para fazer a transição do pre-lighting do jogo e várias outras propriedades gráficas.
Passa determinado número de minutos, simulando uma real passagem de tempo, onde o relógio e calendário do jogo se ajusta completamente.
Por favor, se você quer por exemplo mudar o relógio do jogo de 6 horas para 10 horas, não só escreva o novo valor, prefira utilizar este comando, pois ele simula a passagem real, por exemplo os pickups do jogo terão o tempo considerado e até as nuvens do mod Real Skybox simularão uma nova rotação.
Checar se entidade é criada/controlada por script
Assim você pode facilmente separa pessoas criadas por missões, scripts etc, dos pedestres aleatórios. Mesmo para carros e objetos.
CLEO não ter isto por padrão era um absurdo, pois é algo muitíssimo importante para seus mods não quebrarem o funcionamento de missões e outros mods.
Marcar entidade como criada/controlada por script
Assim, tal entidade não será deletada automaticamente pelo jogo (a não ser que algum outro mod CLEO mal feito marque-as ao contrário). Irão retornar verdadeiro para os comandos IS_*_SCRIPT_CONTROLLED.
Ajuste de resolução / aspect ratio / widescreen
Retorna a resolução atual, útil para casos mais específicos.
Algo praticamente indispensável caso você esteja desenhando algum conteúdo na interface, como uma sprite, quadrado etc.
O uso é muito simples: Você envia um valor X e Y, por exemplo o tamanho de um quadrado, e ele retorna o valor corrigido baseado no aspect ratio da resolução do jogo, assim, ao desenhar o tal quadrado, você utiliza os valores retornados, e assim ele realmente será um quadrado mesmo em resoluções widescreen. Como sempre, há exemplo no script teste da CLEO+.
Retornar tipo ou classe de entidade ou modelo
Retorna o tipo de entidade a partir de um ponteiro pra CEntity (chamado no CLEO+ simplesmente de ENTITY).
Veja a enum ENTITY_TYPE, basicamente você difere um veículo, de uma pessoa, de um objeto... Isto é útil quando você tem um ENTITY e precisa identificar o que exatamente aquilo é.
Um dos usos é: Você usa isto para checar se é uma pessoa, se é, use GET_PED_REF para retornar a referência como um CHAR para utilizar no script.
Retorna o tipo de modelo a partir de um ID de modelo.
Mais checagens de input (botões, teclas)
Não era possível checar se a roda/scroll do mouse havia rolado, agora é. No entanto, lembre que em notebooks isto pode retornar verdadeiro muitas vezes por segundo.
Retorna se pressionou uma tecla ou botão somente naquele frame.
Se você trabalhou com mods CLEO pelo menos um pouco, deve estar sentindo um alívio. É, eu sei o que você sente.
Mas é importante lembrar que retorna somente naquele frame, isto é, se o seu loop tem 2 WAIT, o seu loop está rodando em 2 frames separados, na prática irá falhar 50% das vezes. Portanto tome cuidado com o uso dos WAIT.
Retorna a sensibilidade do mouse configurada no menu do jogo. Essencial para por exemplo criar um cursor in-game com a sensibilidade correta do jogador, ou qualquer coisa que requer ler o movimento do mouse, basta multiplicar o valor pela sensibilidade.
Eu sempre estive inconformado com o fato do jogo não ter uma maneira de desativar somente o controle de câmera.
Eu sempre estive inconformado com o fato do jogo não ter uma maneira de desativar somente o controle do player, preservando a câmera.
E este aqui é a desativação total de um controle. POR FAVOR, PROCURE USAR ISTO EM VEZ DE SET_PLAYER_CONTROL!!! Pois este segundo, nativo do jogo, não só desativa o controle do player, mas o também deixa "seguro", ou seja, a polícia para de atirar em você etc, isto estraga o gameplay. SET_PLAYER_CONTROL_PAD faz somente o que diz, ou seja, desativa o controle, sem fazer nada além.
Checa, de boa maneira, se o botão de mira está pressionado. Adaptado ao GInput. Lembre-se, botão, se você quer saber se está mirando, use IS_CHAR_USING_GUN.
Checa, de boa maneira, se o botão de tiro está pressionado. Adaptado ao GInput. Retorna também o tiro secundário. Lembre-se, botão, se você quer saber se está atirando, use GET_CHAR_WEAPON_STATE.
Checa, de boa maneira, se o botão de seleção foi pressionado neste exato momento. Isto é, a tecla de correr, ou X no controle de PS. Isto é muito útil pois dentro de um carro, o botão de seleção se torna o botão de acelerar, o que deixa tudo confuso. Este comando resolve tudo, ele considera o botão de correr (que por padrão é Espaço) mesmo dentro do carro!
Retorna o tempo desde que você não toca no controle, em milissegundos.
Controle de pickups
Retorna algum pickup que esteja nesta coordenada. Não é comum, mas existe a possibilidade de existir mais de um na mesma posição, principalmente porque o jogo trabalha com uma coordenada compressada, portanto todos os pickups dentro de X metros estão na mesma posição.
Retorna o ponteiro para o CPickup, útil para trabalhos mais técnicos e internos através de manipulação de memória.
Retorna o ID do modelo do pickup. Prefira GET_PICKUP_TYPE se é melhor para o seu caso.
Útil para identificar se o pickup é uma arma, dinheiro etc sem checar o modelo em si.
Timers / contadores
Todos os comandos de contadores de tempo e valores, agora adaptados para variáveis locais, pois nativamente só estão disponíveis em variáveis globais, o que atrapalha na criação de mods CLEO.
O funcionamento é exatamente igual aos de variáveis globais, ou seja, você envia uma variável e o valor dela será usado para contar, bem simples.
De bônus, perceba que os comandos "TWO", ou seja, 2 contadores, foram re-adicionados (eles foram removidos da versão final do jogo, então os re-adicionei como vars locais).
Mais comandos de funções internas do jogo que não eram possíveis usar por comandos.
Situação do gameplay: missão, SAMP, save etc
Checa se está numa missão, semelhante ao $ONMISSION == true do Sanny Builder, mas agora implementado da maneira mais correta, como o jogo implementou internamente, considerando diferente index da variável de missão.
Se está durante o San Andreas Multiplayer; cutscene (filmes de missões).
Se está durante uma cutscene scriptada (aquelas cenas comuns durante as missões). Basicamente checa se o modo "widescreen" (que na verdade, é a tela cinematográfica) está ativa, onde o jogo normalmente a usa para estas cenas.
Checa se é a primeira vez que o jogo está iniciando naquele jogo salvo ou novo jogo. Isto é importante para casos específicos, principalmente se o seu script faz hook no jogo, você não vai querer que o hook seja feito mais de uma vez caso dar carregar ou iniciar um novo jogo.
Retorna o ID do slot do save que você acabou de carregar. -1 caso seja novo jogo.
Muito útil para você salvar e carregar informações do jogo salvo em um arquivo local por exemplo, para assim o seu mod ter suporte ao salvamento de informações em cada jogo salvo através de um arquivo em vez de SAVE_THIS_CUSTOM_SCRIPT.
Se você pretende salvar informações ao salvar o jogo, use o comando SET_SCRIPT_EVENT_SAVE_CONFIRMATION.
Checa se tal cheat está ativo. Você consegue os IDs dos cheats aqui.
Retorna a data completa do PC do jogador.
Checa se o hud está visível, de boa maneira.
Checa se o radar/minimapa está visível, de boa maneira.
É a mesma coisa de
Câmera
Retorna o modo de câmera atual. Há dezenas (veja o enum CAMERAMODE), mas muitas são só leftovers do desenvolvimento do jogo. Eu já usei muito para checar se está mirando, mas IS_CHAR_USING_GUN deve fazer um melhor trabalho.
Retorna o quão "embaixo d'água" a câmera está, entre 0.0 e 1.0.
Retorna o alpha atual do fade sendo executado. Ou seja, 255.0 a tela está 100% preta (mas raramente atingirá exatos 255.0 pois normalmente logo em seguida começa um fade out, para ficar mais seguro, considere 200.0).
Retorna a coordenada num offset a partir da posição da câmera, por exemplo, "1.0 0.0 0.0" pegará a posição 1 metro para o lado direito da câmera. Mesma coisa de por exemplo GET_OFFSET_FROM_CAR_IN_WORLD_COORDS.
Uma função usada pelo jogo para determinar onde a arma está apontando com base num range e posição do char (normalmente o player), retornará o ponto inicial e final, como se fosse o trajeto de um tiro (não considera colisões).
Retorna a rotação da câmera. Simples assim. Por que diabos demorou 20 anos para alguém colocar isto?
Note que os valores retornados são um pouco mais complexos do que o esperado.
Retorna o ponteiro para o TheCamera (CCamera) e ActiveCam (CCam), duas classes muito úteis, para você ter fácil acesso aos membros delas.
Finalmente agora você pode controlar a câmera por script! Especificamente, a câmera controlável.
Por exemplo, você pode usar GET para pegar os valores de input atuais, soma 90, dê SET e pronto, você girou a câmera 90 graus.
Matemática
Clamp nada mais é do que uma limitação mínima e máxima de um valor. Em outras palavras, CLAMP_INT i 0 100 (i) é a mesma coisa de você fazer IF i < 0 ; i = 0 e IF i > 100 ; i = 100.
Não só para simplificar o seu código deixando-o mais organizado, mas tudo é executado de uma só vez, diferente do uso de IF que, em SCM, é uma operação muito complexa, e considerando que limitar o valor de uma variável é algo comum, esta otimização pode de fato fazer diferença.
Você envia um progresso linear (0.0~1.0) para retornar o valor alterado numa curva de ease.
É a mesma implementação do site easings.net, inclusive, as opções são as mesmas com os mesmos nomes. Entre lá para visualizá-las.
Isto é excelente para criar animações suaves.
Retorna o ângulo Z (heading) a partir de 2 coordenadas.
Você envia um número entre 0 e 100, a condição retornará verdadeira baseado nesta porcentagem, ou seja, 50 retornará verdadeiro em média 50% das vezes, simples assim.
O mesmo comando de gerar um número aleatório, mas agora você pode enviar uma seed.
Se você não entende o conceito de seed, basicamente, a mesma seed sempre retornará o mesmo número aleatório. Isto é útil para você ter valores aleatórios, mas que sempre sejam os mesmos baseados numa seed.
E, internamente, o jogo já cria seeds para entidades, você pode pegá-las abaixo:
Retorna a seed da entidade, que é um número aleatório "único", pode ser útil para usar com GENERATE_RANDOM_*_IN_RANGE_WITH_SEED
Você envia uma coordenada, um ângulo e distância. Retorna a coordenada que está naquele ponto.
Interpolação linear entre 2 valores float. Por exemplo, A=1.0 e B=2.0, caso T seja 0.5, retornará o valor entre os dois, isto é, 1.5.
Dica: usar isto junto com EASE dá para fazer umas coisas bem legais, como movimentação de câmera, animação na interface etc.
Matrizes e quaterniões
Convertidos do NewOpcodes.cleo, possibilita trabalhar com matrix e quaternions, operações muito importantes para gráfico 3D, por exemplo, quaternion é a melhor maneira de rotacionar objetos sem o problema do gimbal lock. Matrix basicamente é o que indica a posição, tamanho e rotação do nosso objeto 3D.
É importante notar que absolutamente nenhum comando aqui irá alocar uma matrix ou quaternion para você, você envia um ponteiro com o espaço. Normalmente uma matrix você conseguirá lendo alguma class (por exemplo CObject+0x14 é a matrix do objeto; CMatrix e RwMatrix são essencialmente a mesma coisa), enquanto o quaternion você trabalhará com algum espaço de 16 bytes, em outras palavras, um quaternion nada mais é do que um vector4, ou seja, um XYZ com mais um float (normalmente chamando de W ou Real). Eu recomendo usar o ponteiro de uma variável (que tenha outras 3 variáveis disponíveis), ou melhor ainda, um thread/script memory com pelo menos 16 bytes disponíveis para usar como quaternion. Caso você esteja criando uma matrix do zero, são 72 bytes.
Você envia um progresso (0.0~1.0) para criar uma interpolação suave entre 2 quaternions.
Seta a rotação da matrix baseado num quaternion, ou pega um quaternion baseado numa matrix.
Rotaciona o quaternion ou matrix num eixo e ângulo. Isto é a maneira mais correta de rotacionar algo, pois não causa o gimbal lock. Provavelmente você usará este comando mais de uma vez para ajustar a rotação, e normalmente você usará o axis como 0.0, -1.0 ou 1.0 para indicar a direção do eixo que você deseja rotacionar o determinado ângulo.
Normaliza os valores do quaternion.
Multiplica um quaternion por outro.
Inicializa um quaternion enviando os valores brutos. O mesmo pode ser feito com WRITE_OFFSET_MULTI, tanto que eu tive preguiça de converter o mesmo pro matrix.
Este é o único que não veio do NewOpcodes.cleo. Este é um código que encontrei por aí para a Unreal Engine 4, se trata de uma função LookAt que você envia uma somente um vetor de direção e retornará um quaternion normalizado com a rotação para aquela direção.
Um ótimo uso é com o GET_COLPOINT_NORMAL_VECTOR, você consegue rotacionar algo baseado na rotação da face de colisão, para por exemplo criar um mod de cover ou pichar em qualquer lugar. No entanto me pareceu causar bugs ao enviar valores baixos, como 0.0~1.0, multipliquei por 10.0 e pareceu ok.
Retorna os valores dos ângulos X, Y ou Z de uma matrix.
Retorna a coordenada num offset a partir da posição de determinada matrix, por exemplo, "1.0 0.0 0.0" pegará a posição 1 metro para o lado direito da matrix. Mesma coisa de por exemplo GET_OFFSET_FROM_CAR_IN_WORLD_COORDS.
Faz uma matrix ser rotacionada em direção à outro ponto 3D. Similar ao
Operações com strings
Utilizar strings (textos) como ponteiros é algo muito comum na CLEO, portanto...
Copia uma string para a outra. Normalmente isto era feito com STRING_FORMAT, mas ele realiza operações de formatação, não queremos isto, portanto, COPY_STRING é mais otimizado para você copiar ou simplesmente criar uma string totalmente nova escrevendo ela para um ponteiro, por exemplo COPY_STRING "Test" (i).
Retorna o tamanho total da string (até o null terminator, mas o null terminator não é incluído no resultado).
Se limita à 128, por segurança. Se retornar 128, provavelmente não é uma string válida. A condição retorna verdadeira caso retorne acima de 0.
Checa se uma string é igual à outra.
O interessante aqui são as opções: tamanho máximo, diferenciar maiúsculas de minúsculas, e ignorar um caractere de sua escolha (por exemplo "test" e "t*st" com o caractere para ignorar "*" dará como verdadeiro para "tast").
Checa se há determinado caractere em determinado index de uma string.
Encontra uma substring dentro de uma string. Implementação da mesma função do C++.
Por exemplo, "test.dff", você pode encontrar ".dff", dará verdadeiro e retornará o index do início onde foi encontrado. Há também opção de encontrar o primeiro, ou último, por exemplo se você quer encontrar a extensão de um arquivo, você procurar pelo último "." e não pelo primeiro.
Uma maneira simples de cortar uma string em determinado index. Basicamente escreverá um null terminator (0) ali.
Uma maneira simples de checar se uma string está comentada com "#", ";" ou "//", também considera espaços em branco. É muito útil caso o seu script suporte a leitura de um arquivo de configuração de formato próprio, assim, cada linha que você ler, use este comando.
Transforma uma string em todas maiúsculas ou todas minúsculas.
Sons
Retorna o volume dos efeitos sonoros ou rádio configurados no menu do jogo. Indispensável para qualquer mod que carrega sons por arquivos, não deixe de usar, por favor!
Retorna a referência interna de determinado AUDIOSTREAM para ser usado nas funções da bass.dll.
Isto possibilita o uso avançado de áudios, como o controle 3D, equalizador, spectrum, até mesmo o uso de plugins VST usados para produção de música! Veja aqui a documentação (a referência retornada para usar na bass.dll é um HSTREAM).
Efeitos especiais
Retorna o ponteiro para o efeito especial (FxSystem_c), útil para operações mais avançadas.
Adiciona uma partícula baseada num efeito especial. Algo que incrivelmente não era possível por scripting.
Isto é muito útil, é assim que o jogo cria a maioria dos efeitos do jogo, como fumaças, sangue etc. No próprio comando, você tem várias opções, como cor e tamanho, portanto, você basicamente consegue criar novos efeitos especiais com isto, sendo muito útil para mods de super poderes por exemplo.
Algo que você tem que ter em mente é que por padrão o jogo deixa de criar muitas partículas em gráficos baixos, por exemplo, criando somente metade das partículas caso esteja nos gráficos Low. MixSets tem opção para ignorar isto, multiplicar, aumentando ou diminuindo. Portanto, teste o seu mod em diferentes configurações gráficas, e considere o uso ou desuso do MixSets.
Outra coisa a ser considerada é o argumento Brightness, se é algo não emissivo, por exemplo uma simples fumaça, considere ajustar o brilho com GET_DAY_NIGHT_BALANCE, para escurecer de noite.
Checa se tal efeito especial existe com determinado nome. Finalmente você vai poder colocar um aviso e não causar crash para a pessoa caso esta pessoa não instale o seu mod de efeitos corretamente.
Ponto de colisão
Você envia 2 coordenadas e será retornado várias informações sobre o ponto de colisão. Veja isto como "atirou num ponto, onde este tiro irá colidir?". Há muitas opções de filtragem, há até mesmo um EntityToIgnore que você envia o ponteiro de uma entidade (por exemplo, um ponteiro pra um char (CPed), car (CVehicle) ou objeto (CObject), que são filhos do CEntity), que o a checagem irá ignorá-los.
Algo importante para você notar, é que ele NÃO retorna um COLPOINT, mas sim você envia um ponteiro de um buffer para que o COLPOINT seja escrito. Esse buffer precisa ter pelo menos 44 bytes, ou seja, você pode usar um script/thread memory de pelo menos 44 bytes para isto. Caso não seja enviado, não retornará o COLPOINT, portanto é opcional.
Um COLPOINT pode ser usado para vários outros comandos da CLEO+.
A partir de um COLPOINT (obtido com GET_COLLISION_BETWEEN_POINTS) você pode ter várias informações, como a direção, material da superfície (se é grama etc, lembre-se, há muitos tipos de grama etc, você precisa pesquisar muito, eu uso Col Editor). A direção (NORMAL_VECTOR) é útil para mods como cover e pichação, que você precisa colocar algo na direção de uma parede por exemplo.
O próprio jogo já armazena informações do material e iluminação que determinada entidade está sob, portanto se você só quer saber das informações atuais que a entidade está colidindo (chão), use isto.
Distâncias
Checa se determinada entidade ou câmera está dentro da distância limite. É semelhante aos outros LOCATE do jogo, mas este é circular/esférico em vez de retangular, ou seja, é de fato a distância de um ponto ao outro, e de bônus inclui para duas ENTITY e a câmera principal do jogo.
Inclusive, há performance melhor, um impacto praticamente nulo, inclusive sem utilizar raiz quadrada no cálculo.
Retorna os multiplicadores de distância do jogo: LOD e geração. Este multiplicador é útil principalmente se você quer que seu mod se adeque às configurações de qualidade do player: o valor do LOD, por exemplo, é diretamente ligado com a distância de visão configurada no menu do jogo.
Carregamento de modelos
Retorna algum ID de modelo inexistente dentro de um range inicial e final. Caso seja encontrado, a condição dá como verdadeira.
Foi pensado em conjunto com LOAD_SPECIAL_CHARACTER_FOR_ID, isto é, se você quer um ID de modelo temporário para usar em por exemplo num modelo de personagem especial, pegue algum ID disponível com este comando.
Recomendação: IF GET_MODEL_DOESNT_EXIST_IN_RANGE 15000 15024 (model)
Por organização, use o range de IDs 15000 até 15024, há 25 disponíveis, é o suficiente, mas você pode escolher usar outros. O problema é, se por exemplo algum mod de mapa já usa estes IDs, não estão disponíveis, portanto eu os reservei nesta página.
Por exemplo, se algum outro mod usar isto, este mod usará o ID "15000", e o seu mod "15001". Se o primeiro mod descarregar este modelo, completamente, ele voltará a estar disponível para usar novamente.
O mesmo de LOAD_SPECIAL_CHARACTER, mas você envia um ID de um modelo para o modelo especial ser guardado lá.
Isto foi pensado em conjunto com o GET_MODEL_DOESNT_EXIST_IN_RANGE, que retorna um ID disponível para você usar.
Note que isto de fato ADICIONA um novo ped ao seu jogo, portanto o limite de peds do seu jogo precisa ser aumentá-lo para poder usá-lo. Open Limit Adjuster é perfeito para isto pois ele aumenta o limite automaticamente.
Descarrega um modelo carregado pelo LOAD_SPECIAL_CHARACTER, semelhante ao UNLOAD_SPECIAL_CHARACTER, mas há um porém:
Use UNLOAD_SPECIAL_CHARACTER_FROM_ID após você deletar todos os chars que usam este modelo, pois, caso realmente for o último, CLEO+ descarregará o modelo completamente para que volte a estar disponível no GET_MODEL_DOESNT_EXIST_IN_RANGE. Caso contrário, o próprio jogo fará isto, algo que pode demorar muito tempo. REMOVE_MODEL_IF_UNUSED também ajuda.
Marca um modelo a ser carregado em modo de prioridade.
Faz todos os modelos prioritários serem carregados, onde pode (mesmo que não sempre) ignorar os modelos não prioritários.
Eu recomendo altamente que você use isto em vez dos comandos nativos não-prioritários, pois LOAD_ALL_MODELS_NOW inclui realmente todos os modelos que o jogo está querendo carregar naquele momento, então você forçará os modelos a serem carregados, aumentando chances de lag spike. Separar em prioridade evita que modelos não importantes sejam carregados junto com o seu, assim evita lag spike no seu script (mesmo que, o melhor mesmo é esperar carregar em vez de usar LOAD_ALL_MODELS_NOW ou LOAD_ALL_PRIORITY_MODELS_NOW).
Descarrega completamente da memória todos os modelos que não estejam sendo usado em nenhum lugar (não exista nenhum carro, pedestre etc com este modelo). Caso isto não seja usado, o modelo será descarregado automaticamente pelo jogo no momento que ele precisa de mais memória, o que, dependente do valor do streaming memory que o jogador configurou, pode ser rápido, ou nunca.
Este comando chamará uma função pesada, que fará um loop em praticamente todos os modelos do jogo, portanto, somente use se realmente necessário, e fora do gameplay, por exemplo durante um fade após uma missão ou algo assim.
Mesmo de REMOVE_ALL_UNUSED_MODELS, mas para um modelo específico.
No UNLOAD_SPECIAL_CHARACTER_FROM_ID, ele já faz isto automaticamente para que volte a estar disponível em GET_MODEL_DOESNT_EXIST_IN_RANGE.
Checa se determinado modelo existe. Mesmo de IS_MODEL_AVAILABLE, mas por nome de .dff. Considera realmente qualquer arquivo do disco, mesmo não carregado como um ID.
Isto é muito útil para usar antes do LOAD_SPECIAL_CHARACTER_FOR_ID, assim, antes de tentar carregar determinado modelo baseado no nome, você pode saber se tal modelo realmente existe no disco (seja num .img ou no modloader).
Encontra o ID de um modelo baseado no nome dele. Só use caso realmente necessário, evitando durante o gameplay, pois é uma função um pouco pesada.
Uma revolução adicionada a partir do CLEO+ v1.2: Carregar arquivos .dff e .txd sem a necessidade de substituir IDs do jogo! Também não atinge outros limites e nem sequer consome parte do streaming (no entanto, por não usar streaming, não é recomendado usar em abundância, como props no mapa).
A ideia é para, principalmente, usar em scripts que requer objetos customizados. Pense em um mod de pesca, você vai querer infinitos modelos e texturas de peixes, ou até mesmo misturar um modelo de um peixe com textura de outro, e usar este modelo de peixe tanto para colocar na mão da pessoa, quanto para um objeto no mapa. LOAD_SPECIAL_MODEL é perfeito para casos assim!
Você dá o caminho do arquivo .dff e .txd (sem a extensão) e o CLEO+ irá carregar pra você instantaneamente (não usa streaming, portanto em alguns casos pode dar um leve stutter pra carregar arquivos pesados etc).
Caso já tenha algo usando este special model, somente abaixará uma contagem na referência. Quando algo parar de usar (por exemplo, um RENDER_OBJECT ser apagado), descarregará.
Retorna o RpClump, RpAtomic e o index do TXD. Útil para usos mais específicos. Por exemplo, é possível adicionar um RpAtomic dentro de algum RwFrame para renderizar o objeto como peça de um carro (como o Tuning Mod).
Armas
Retorna o estado atual da arma atual do CHAR. Isto é, se está atirando ou recarregando.
Checa se determinado ID de arma (WEAPON_TYPE) é de determinado tipo de tiro.
Isto é importante pois hoje é comum adicionar armas sem substituir, e antes era comum as pessoas checarem, por exemplo, se é arma de fogo pelo ID da arma. Este comando deixa o seu mod adaptado para armas adicionadas sem substituir.
Retorna o ponteiro para o CWeaponInfo de tal arma, ou da arma atual da pessoa. CLEO+ tem vários comandos que trabalham com o WEAPONINFO, mas você também pode usar leitura de memória.
Retorna os 2 modelos do WEAPONINFO que tal arma usa, útil para você carregá-los antes de criar a arma, assim sendo facilmente compatível com armas adicionadas sem substituir (você não precisa saber quais são os modelos necessários). Lembrando que algumas poucas armas, como carga explosiva, usa 2 modelos, a gigante maioria usa somente 1.
Retorna o ID do grupo de animação do WEAPONINFO. É uma excelente maneira de você checar se tal arma é por exemplo uma shotgun, sendo compatível com armas adicionadas sem substituir.
Retorna o valor de todas as flags do WEAPONINFO. Em seguida, use os comandos de checar bits, por exemplo IS_LOCAL_VAR_BIT_SET_CONST, junto com o enum WEAPONINFO_FLAGS para checar as características daquela arma, por exemplo se é pistola dupla, se é pesada etc.
Retorna a quantidade total que o pente da arma suporta.
Retorna o tipo de tiro da arma. Lembrando que IS_WEAPON_FIRE_TYPE lhe pode ser mais útil.
Retorna o ID do slot que aquela arma ocupa no inventário.
Retorna o pente atual da arma atual do CHAR.
Outras utilidades para o gameplay
A condição retorna verdadeira a cada X número de frames (baseado no número interno do total de frames do jogo).
A utilidade é separar o trabalho do seu script em frames separados, isto é muito utilizado para otimizar a performance de jogos, por exemplo, IF FRAME_MOD 2 retornará verdadeiro 1 vez a cada 2 frames do jogo (ou seja, somente em frames de número par).
Internamente: if (CTimer::m_FrameCounter % arg == 0).
Muda o dinheiro do player. No próprio comando você escolhe se você seta (ou seja, muda completamente, sem animação), adiciona, ou remove. Isto é uma maneira excelente de substituir o velho ADD_SCORE que está lá desde o GTA 2.
Outras utilidades para CHAR
Após criar um novo CHAR, use este comando para corrigir (com opções) a posição dele no chão (considera a coordenada 3D, portanto adaptado para embaixo de ponte etc), o brilho dele (sem mais chars sendo criados brilhantes ou escuros antes de tocar no chão), e aplicar um fade in, para ele aparecer suavemente na tela, semelhante ao fade out de quando ele desaparece.
Posiciona uma entidade com valores crus e sem realizar nenhum outro cálculo de offset, inteligência artificial nem nada.
Perceba que isto é uma ótima maneira de corrigir pessoas e motos não aparecendo exatamente na posição que você coloca. Muito comum em motos, onde se você posicionar uma moto embaixo de um lugar não tão alto, a moto aparece em cima do teto, este comando resolve este problema em 100%.
O comando IS_CHAR_IN_AIR devia ser chamado de "FALLING", pois ele só retorna caso o CHAR esteja fazendo a tarefa de cair, muito pouco útil. Assim, eu fiz este novo comando que realmente retorna caso o CHAR esteja no ar, isto é, não colidindo com o chão.
Checa se o CHAR está pegando fogo. Há também uma task para isto, enquanto este checa diretamente o efeito de fogo dentro dele.
Sério que o jogo não tinha como pegar a saúde máxima de alguém? Também adaptado para o player.
Retorna a saúde do CHAR, mas em forma de porcentagem, ou seja, 0.0~100.0, utilizando a saúde máxima como base.
Seta a transparência do modelo da pessoa.
Retorna as informações do último dano causado por uma arma no último frame. Prefira usar junto com SET_SCRIPT_EVENT_CHAR_DAMAGE visto que cada frame pode ter mais de um dano, assim com o event o funcionamento é mais confiável.
Força o CHAR a ser preso. Só deve funcionar com player, mas é interessante principalmente para missões.
Retorna o estado atual do CHAR. Muito útil! Há uma lista muito grande que você pode usar para checar várias coisas, semelhante à checagem de tasks com IS_CHAR_DOING_TASK_ID, mas mais simplificada. Basta dar uma olhada no enum PEDSTATE.
Retorna a imunidade atual do CHAR. Importante caso você esteja usando SET_CHAR_PROOFS e não quera substituir as atuais.
Checa se o CHAR está com a visibilidade de arma setada, caso contrário, ele pode estar com arma, mas estar invisível (por exemplo a função de esconder arma dentro de carros do MixSets). Perceba que não checa se ele está com arma, é só a flag de visibilidade. É bom considerá-la em casos que você precisa identificar se uma pessoa viu a arma da outra.
Retorna o ID do pedstat, isto é, você pode checar se tal CHAR é prostituta, médico, bombeiro etc. Também pode ser mais útil do que GET_PED_TYPE ao checar se um CHAR é polícia, pois algumas missões do jogo policiais são criados com pedtype de personagem de missão em vez de policial. Veja o enum STAT ou arquivo "data/pedstats.dat".
Retorna o estado atual de movimento do CHAR, por exemplo, parado, andando ou correndo.
Adiciona um tempo para determinado CHAR não ser deletado, em milissegundos. Por exemplo "1000" ele não será deletado automaticamente por pelo menos 1 segundo.
Retorna há tantos milissegundos a pessoa está morta.
Retorna o valor de "medo" do char, isto é, o quão covarde ele é.
Returna o ped type baseado no ID do modelo de um ped. Antes de usar, certifique-se de que o ID do modelo é realmente um ped, com GET_MODEL_TYPE. Isto é útil para você criar um ped mas você somente sabe do ID dele, assim, com o ID você retorna o ped type correto (se é homem, mulher etc). Lembre-se do GET_CHAR_STAT_ID para pegar o stat do CHAR em si, em vez do modelo.
Outras utilidades para CAR
Retorna a subclass de tal veículo, assim, você pode diferenciar um veículo pelo seu tipo: se é um carro, caminhão monstro, moto, bicicleta etc. Basta utilizar os enum VEHICLE_SUBCLASS (dê uma olhada no .xml, por exemplo VEHICLE_SUBCLASS_BMX é para qualquer bicicleta).
Originalmente não era possível diferenciar uma moto de uma bicicleta, isto me deixava indignado. Agora com CLEO+ isto é finalmente possível.
Sério que o jogo não tinha um comando para retornar o veículo que tal veículo está puxando?
Sério que o jogo não tinha um comando para retornar o veículo que está tal veículo está sendo puxado?
Sério que o jogo não tinha um comando pra buzinar?
Manipular o alarme do carro, de todas as formas: você pode adicionar, e quando alguém entrar, dispara, ou disparar ou pará-lo, o mesmo para retornar, você sabe se um carro está com alarme ativo ou disparado.
Retorna o a coordenada de tal dummy. Há opção para retornar a coordenada do mundo, ou offset a partir do centro do veículo.
Nota: está pré-adaptado ao VehFuncs, quando VehFuncs adicionar funcionalidade de dummies dinâmicos! Também deverá se adaptar ao Tuning Mod numa próxima atualizar do Tuning Mod.
Retorna as informações do último dano causado por uma arma no último frame. Prefira usar junto com SET_SCRIPT_EVENT_CAR_DAMAGE visto que cada frame pode ter mais de um dano, assim com o event o funcionamento é mais confiável.
Retorna informações da última colisão que o carro teve. Foi indispensável para criar mods como o de ser jogado do para-brisa ou perder vida ao bater.
Seta a transparência do modelo do veículo.
Abre ou fecha os vidros dos carros. Lembrando que eles precisam ser adaptados como os originais do jogo, simplesmente irá aparecer e desaparecer. É a mesma função que faz os vidros se fecharem nos NPCs caso esteja chovendo por exemplo.
Checa se tal veículo tem um node, basicamente, uma peça, entre as peças principais do jogo. Isto é muito útil para mods de tuning checarem se o carro tem escapamento, pois não há uma maneira nativa de checar se tal carro pode realmente instalar um escapamento, assim evita crash. Mas é claro, muitas outras utilidades, só não tão útil: para simplificar, só retorna peças principais que o jogo usa, não serve para utilizar literalmente qualquer peça, pois para ser útil seria muitos outros comandos, então se você quer um controle mais a fundo de cada peça do carro, use NewOpcodes.cleo ou simplesmente trabalhe com manipulação de memória.
Retorna verdadeiro caso o carro esteja no ar, ou seja, sem tocar no chão, de maneira confiável.
Retorna a imunidade atual do CHAR. Importante caso você esteja usando SET_CAR_PROOFS e não quera substituir as atuais.
Adiciona um tempo para determinado CAR não ser deletado, em milissegundos. Por exemplo "1000" ele não será deletado automaticamente por pelo menos 1 segundo.
Retorna há tantos milissegundos o carro está destruído.
Retorna o ID do grupo de animação do veículo, inclui enum CAR_ANIMGROUP. É uma ótima maneira de entender qual é o tipo de veículo, mas evite ao máximo isto, pois pode mentir (por exemplo, isto é uma maneira de detectar que tal veículo é um caminhão, mas algum carro pode querer usar animação de caminhão, não sabemos). Se você quer usar isto para checar o tipo de veículo, só use se não há outra saída ou queira algo mais específico.
Checa e seta se algum player é "dono" de determinado veículo, isto é, ele pode entrar neste veículo sem a polícia pensar que é um roubo.
Aproveitando: para checar se um player é dono de um carro no Car Dealearship / GTA Brasil é CVehicle+0x42F 1 byte bit 7.
Checa se um carro é conversível.
Retorna o valor monetário do carro (o quanto ele vale).
É o mesmo de GET_CAR_MODEL_VALUE, mas este retorna diretamente do handling, ou seja, mods como Tuning Mod podem alterar este valor, assim, é mais aconselhável usar este em vez de GET_CAR_MODEL_VALUE.
Retorna os valores dos pedais do veículo, isto é, acelerador e freio.
Antes que digam que "break" está escrito errado, é que gta3script ao todo é inglês britânico, portanto eu quis preservar.
Outras utilidades para OBJECT
Set a transparência do modelo do objeto.
Retorna o offset entre o centro de massa e base do modelo. O jogo usa isto como um offset para posicionar objetos mas nunca te dá acesso ao valor.
Retorna verdadeiro caso o objeto esteja no ar, ou seja, sem tocar no chão, de maneira confiável.
Retorna a imunidade atual do CHAR. Importante caso você esteja usando SET_OBJECT_PROOFS e não quera substituir as atuais.
Outros
Retorna a posição ou ângulo Z de alguma ENTITY (lembrando que o ponteiro pra um CHAR, CAR ou OBJECT é inclusive uma CEntity). Pode ser útil para retornar informações do event da BUILDING.
Retorna um ponteiro para o CBaseModelInfo, que pode incluir os filhos CVehicleModelInfo, CPedModelInfo, CWeaponModelInfo etc, dependente do tipo de modelo que ele é (GET_MODEL_TYPE). Muito útil para operações avançadas que requerem informações relacionadas aos modelos e não tenha comando para isto ainda.
Lê e escreve informações no clipboard, isto é, CTRL+C CTRL+V.
É basicamente uma cópia de memória com um tamanho limite determinado por você.
O funcionamento provavelmente é idêntico ao ClipboardCommands.cleo do Deji. É retrocompatível com ele.
O comando LOAD_LIBRARY carrega uma .dll, .asi, .cleo ou equivalente, não é nada legal para grande parte dos casos. Por exemplo, se você quer usar uma função de um .asi, você não quer recarregar ele, pois ele já está carregado!
Portanto, sempre considere usar este comando em vez do LOAD_LIBRARY. Também é excelente para checar se alguma .dll, .asi ou .cleo está instalado e carregado no jogo da pessoa. Por exemplo, IF GET_LOADED_LIBRARY "NewOpcodes.cleo" (i) você checa se NewOpcodes.cleo está instalado e carregado.
Retorna o ponteiro para uma biblioteca, caso exista, a condição retorna verdadeira.
A coisa mais ilegal que vocês verão em suas vidas de programador: retorna X vezes. Sim, se você chamar 2
Este comando é seguro, portanto você pode usar por exemplo
Retorna a distância até o ponto de água mais próximo, e a altitude (Z) do ponto. São dois valores que o jogo calcula periodicamente para usar no som da água.
Se você tem um mod precisa ativar só caso esteja próximo da água, é altamente recomendado que, antes de fazer o seu script procurar por uma água, cheque se você está perto de uma, isto otimizará o desempenho do seu mod, pois procurar por água é um processo pesado.
Você envia um ID de um modelo, e retornará o ponteiro para o nome dele.
Sim, só agora é possível ter acesso ao nome dos arquivos .dff do jogo! Isto porque agora CLEO+ guarda na RAM o nome de todos os modelos do jogo.
Note que se trata do ponteiro direto, não é uma cópia do nome, portanto não sobrescreva esses dados! Se precisar você pode usar
WHILE TRUE, RETURN_TRUE e RETURN_FALSE
CLEO+ já inclui eles nas configurações do .xml. Foi só uma maneira de deixar o uso mais comum. Veja mais informações aqui. Lembrando que CONTINUE e BREAK precisam ser ativados na própria extensão no VSC, leia lá.
Tópico de sugestões de comandos: f16-utilidades/t2878-sugestoes-cleo-moonloader
Se você quer aprender a criar CLEO com gta3script (recomendado para CLEO+): f141-secao-tutorial-gta3script/t26-indi ... gta3script
NOVIDADE: Agora todos os comandos do CLEO+ estão bem documentados no Sanny Builder Library!
(lembrando que não é específico do Sanny Builder, inclusive usa o mesmo nome do gta3script)
O que é CLEO+?
CLEO+ (ou CLEOPlus) é um plugin que expande a CLEO Library, adicionando quase 300 novos comandos (3 vezes maior do que toda a CLEO! 6 vezes maior que a atualização da CLEO 4!), com funções realmente úteis, algumas que realmente revolucionam a maneira de criar mods CLEO.
Também inclui alguns dos principais do NewOpcodes.cleo, e todo o ClipboardCommands.cleo como retrocompatibilidade.
Eu (Junior_Djjr) crio mods CLEO desde 2011, quase 1 década, sou quem mais criou mods CLEO no mundo, e desde lá venho ensinando pessoas a criarem mods CLEO neste fórum, portanto, eu tenho total noção do que a CLEO precisa para ficar melhor, e pra isto eu iniciei este projeto.
Diferente de outros plugins para a CLEO, este foi focado em resolver e simplificar as operações mais simples, isto é, deixar a criação de mods CLEO ainda mais simples e agradável, para mods mais fáceis de serem criados, estáveis, menos propensos à bugs e conflitos. Sendo assim, iniciantes terão menos dificuldades, e experientes passarão menos raiva.
CLEO+ é somente para a versão 1.0 US do GTA San Andreas, inicialmente focado em GTA3script, mas também adaptado para Sanny Builder. E não aumenta o limite de variáveis, isto é trabalho pra CLEO em si ou o uso de outras gambiarras, mas adiciona excelentes funcionalidades para evitar tal limitação.
Isto não é uma documentação. Quase.
Eu escrevi isto em forma de tutorial + documentação, foi um texto pensando em "Olhe, agora você pode fazer isto!".
No entanto, agora há uma documentação de verdade no Sanny Builder Library (lembrando que não é específico do Sanny Builder, inclusive usa o mesmo nome do gta3script). Agradecimentos ao OrionSR por dedicar o tempo dele para documentar tudo.
Manipulação de scripts
STREAM_CUSTOM_SCRIPT_FROM_LABELCria um novo custom script, como STREAM_CUSTOM_SCRIPT, mas usando uma label do seu script em vez do arquivo.
Isto traz realmente muitos benefícios: O novo script que será iniciado será independente, terá suas próprias variáveis etc, no entanto, compartilhará o exato mesmo espaço de memória do seu atual. Isto é muito bom para o desempenho, pois não causa fragmentação de memória e a inicialização do novo script é muito leve, diferente do STREAM_CUSTOM_SCRIPT que abre e lê um arquivo e tira uma cópia deste arquivo pra sua RAM etc. Perceba que, por estar no mesmo espaço de memória do script "pai", o script/thread memory será o mesmo. Em alguns casos, isto é muito útil para deixar o seu script "multi tarefas", ou até mesmo, recursivo, pois você pode criar quantos novos scripts/threads quiser.
Lembre-se também que, como o STREAM_CUSTOM_SCRIPT, você pode enviar variáveis ou valores quaisquer para o outro script, e esses valores cairão nas primeiras variáveis dele, semelhante ao CLEO_CALL, inclusive, você normalmente usará um novo escopo nessa nova label com as novas variáveis lá, semelhante ao CLEO_CALL.
GET_LAST_CREATED_CUSTOM_SCRIPTOs comandos de criar um novo script não retornam o ponteiro do script criado, portanto, logo após criar um script, se você quer o ponteiro dele (sem precisar usar GET_SCRIPT_STRUCT_NAMED, que não é seguro, visto que vários scripts podem ter o mesmo nome), use isto. É ótimo para em seguida usar GET_SCRIPT_VAR e SET_SCRIPT_VAR.
GET_SCRIPT_VARSET_SCRIPT_VARAnteriormente chamados de GET_THREAD_VAR e SET_THREAD_VAR. Alterado pois o nome "thread" não faz sentido e caiu em desuso pela comunidade.
Lê ou escreve valores de uma variável de outro script/thread, excelente para um script controlar o outro.
Você simplesmente envia o ponteiro para o script (GET_LAST_CREATED_CUSTOM_SCRIPT, GET_SCRIPT_STRUCT_NAMED, GET_THIS_SCRIPT_STRUCT etc) e o ID da variável, onde a primeira variável definida é 0, lembrando que TEXT_LABEL ocupa 2 variáveis e TEXT_LABEL16 ocupa 4 variáveis, portanto, você deve pular elas na hora da contagem. no Sanny Builder é mais simples pois você trabalha diretamente com o número das variáveis.
Eventos
Isto irá literalmente mudar a maneira que você cria scripts CLEO!
Vamos supor que você queira recriar o cheat de "todos os pedestres com armas", antes da CLEO+, você rodaria todos os frames pegando todos os pedestres, checando se está sem arma, e colocando a arma nele. PÉSSIMO!!!
Com CLEO+ você simplesmente usa SET_SCRIPT_EVENT_CHAR_CREATE, assim, durante a criação de um CHAR, ele será enviado para esta label, e lá você dá a arma. Simples assim!
Isto é bom em todos os aspectos, o seu script fica mais organizado, avançado, estável e melhor performance.
A única limitação é que os eventos são "one shot", ou seja, eles são executados naquela label, e já precisam retornar o mais rápido possível para continuar processando o jogo, sem uso de WAIT.
Os comandos de eventos funcionam como "SET", ou seja, um toggle boolean onde você somente ativa ou desativa (lembre-se, para desativar, o comando precisa ser idêntico ao de ativar, para indicar que é o mesmo). Mas não entenda mal: Quando você liga um, ele realmente é criado, portanto, NUNCA use estes comandos em um loop!!! Você irá multiplicar os eventos.
Após o argumento da label, normalmente será necessário enviar uma variável, assim, tal evento armazenará o argumento nesta variável, em alguns casos, mais de uma. Você normalmente usará alguma variável temp qualquer. Internamente, a única coisa que o CLEO+ fará, é enviar o processo do seu script para esta label, e depois retornar para onde estava. Não há nenhuma diferenciação das variáveis fora do event, é simplesmente o mesmo script, mesmo escopo, ele só será executado temporariamente em outra região, muito simples.
RETURN_SCRIPT_EVENTRetorna de um event. Events não suportam WAIT!
SET_SCRIPT_EVENT_SAVE_CONFIRMATIONExecutado exatamente antes do jogo ser salvo. Você pode querer deletar todo o conteúdo do seu script que normalmente ficará preso no jogo salvo. Outra utilidade é implementar um sistema de salvar informações do seu script em algum arquivo no disco do jogador para ser reutilizado no próximo load. O argumento é o número ID do slot (espaço) a ser salvo.
SET_SCRIPT_EVENT_CHAR_CREATESET_SCRIPT_EVENT_CHAR_DELETEAo criar ou apagar um CHAR.
SET_SCRIPT_EVENT_CAR_CREATESET_SCRIPT_EVENT_CAR_DELETEAo criar ou apagar um CAR.
SET_SCRIPT_EVENT_OBJECT_CREATESET_SCRIPT_EVENT_OBJECT_DELETEAo criar ou apagar um OBJECT.
SET_SCRIPT_EVENT_ON_MENUDurante o menu. A variável é setada como "1" caso acabou de pausar (no primeiro frame ao pausar), assim sendo facilmente útil tanto para executar algo logo durante a pausa, ou durante o processo do menu de pausa. Lembrando que o SCM não foi pensado em ser executado no menu, portanto é limitado (você não consegue desenhar textos, sprites etc durante o menu).
SET_SCRIPT_EVENT_CHAR_PROCESSSET_SCRIPT_EVENT_CAR_PROCESSSET_SCRIPT_EVENT_OBJECT_PROCESSAo processar determinada entidade. Este evento é executado em todas as pessoas, carros ou objetos naquele frame. Evite usar em objetos pois é comum haver centenas deles, leia mais dicas de otimização no BUILDING abaixo. Lembrando que nem todos os objetos do jogo são "OBJECT", os estáticos e mais importantes do mapa são "BUILDING", os "OBJECT" são, por exemplo, postes, lixeiras etc.
Em geral o desempenho é igual, ou muito pouco pior do que usar GET_ANY_*_RECURSIVE, portanto, se você tem dúvida entre GET_ANY_*_RECURSIVE ou EVENT_*_PROCESS, prefira o primeiro, mas muitas vezes a organização do código vale mais do que isso.
Outra coisa interessante é que o evento é executado logo antes da renderização deles, portanto, não existe nenhum atraso caso você queira por exemplo renderizar uma luz em um carro, a posição da luz, mesmo com o carro em movimento, será exata, diferente dos métodos convencionais.
SET_SCRIPT_EVENT_BUILDING_PROCESSComo o de cima, mas para BUILDING. Isto é, objetos estáticos e importantes no mapa, que não são considerados "OBJECT", em outras palavras, CBuilding e não CObject. O argumento retornado será um ponteiro para o CBuilding, que não é nada mais nada menos que um CEntity. CLEO+ há alguns poucos comandos para ENTITY (procure), e o próprio jogo nunca implementa isto no SCM, portanto, se você realmente precisa trabalhar com BUILDING, normalmente você trabalhará com manipulação de memória.
Evite usar este evento, pois normalmente será executado centenas, senão milhares de vezes. Uma dica de otimização é desativar este evento caso a altitude da câmera seja muito alta, pois Project2DFX faz processar milhares de CBuilding quando você está voando alto, e normalmente você não precisará. Dentro dele, faça uma checagem bem específica para processar aquele BUILDING se for realmente necessário, por exemplo um ID de um modelo específico.
SET_SCRIPT_EVENT_CHAR_DAMAGEAo CHAR receber um dano qualquer. Normalmente você usará GET_CHAR_DAMAGE_LAST_FRAME para pegar as informações.
SET_SCRIPT_EVENT_CAR_WEAPON_DAMAGEAo CAR receber um dano de uma arma. Normalmente você usará GET_CAR_WEAPON_DAMAGE_LAST_FRAME para pegar as informações. Não é executado em colisões, para isto há outros comandos.
SET_SCRIPT_EVENT_BULLET_IMPACTAo ocorrer um impacto de tiro em qualquer local, qualquer coisa.
Há vários argumentos, e eles podem variar, lembre-se, nem sempre um tiro foi disparado por uma pessoa, nem atingido uma entidade, antes de tudo, cheque se os valores são válidos. Normalmente você usará GET_ENTITY_TYPE para saber se o atingido é um uma pessoa, carro etc.
SET_SCRIPT_EVENT_BEFORE_GAME_PROCESSInício do processamento do jogo (antes de todos os scripts, e quase todo o jogo ser processado). Útil para casos bem específicos. Cuidado pois pode não ser muito seguro para scripts.
SET_SCRIPT_EVENT_AFTER_GAME_PROCESSFinal do processamento do jogo (depois de todos os scripts, o jogo já foi processado, renderizado etc). Útil para casos bem específicos. Cuidado pois pode não ser muito seguro para scripts.
Lista de valores (container)
Isto é uma implementação do std::list do C++, para os leigos, é como se fosse uma array dinâmico, ou seja, em vez de trabalhar com um espaço estático na memória, cada item pode estar num espaço qualquer, e tal lista de itens é navegada um por um. É menos otimizado para o desempenho, mas é uma maneira excelente de trabalhar com lista de valores que pode variar de tamanho e você não tem como prever.
É uma maneira excelente de armazenar e ler informações no seu script sem o uso de variáveis e thread/script memory (mesmo que thread/script memory seja mais aconselhável para o desempenho, sinceramente, uma solução mais high level é mais agradável de se trabalhar, né?)
CREATE_LISTDELETE_LISTApaga ou cria uma lista de determinado data type.
LIST_ADDLIST_ADD_STRINGAdiciona um valor à lista (INT ou FLOAT, caso seja uma texto direto, use a variação STRING, lembrando que um ponteiro pra uma string é um INT).
LIST_REMOVE_VALUELIST_REMOVE_STRING_VALUERemove todos os valores da lista baseado no valor específico que você enviou.
LIST_REMOVE_INDEXRemove o valor na lista baseado num index, isto é, numa posição específica da lista.
LIST_REMOVE_INDEX_RANGERemove todos os valores na lista que estão entre 2 index, ou seja, início e fim.
GET_LIST_VALUE_BY_INDEXGET_LIST_STRING_VALUE_BY_INDEXRetorna o valor na lista baseado num index.
GET_LIST_SIZERetorna o tamanho total da lista, isto é, quantos itens tem.
REVERSE_LISTInverte todos os itens da lista; os últimos serão os primeiros;
RESET_LISTLimpa a lista completamente, mas não a remove da memória. Use DELETE_LIST para apagá-la de verdade.
REPLACE_LIST_VALUE_BY_INDEXREPLACE_LIST_STRING_VALUE_BY_INDEXINSERT_LIST_VALUE_BY_INDEXINSERT_LIST_STRING_VALUE_BY_INDEXSubstitui ou inserte um novo valor, dado um index da posição da lista. Assim você pode alterar o interior de uma lista sem precisar recriá-la etc.
Armazenar dados dentro de entidades
Você pode armazenar informações, como variáveis, dentro de uma pessoa, veículo ou objeto.
Trabalha como uma ponte que liga a função do plugin-sdk, muito útil para criar mods .asi, agora você pode utilizar em seus mods CLEO!
Por exemplo, um mod que você espirra perto de uma pessoa e ela é infectada, você armazena a informação da contaminação dentro da pessoa, e não dentro do seu script, assim, você pode, a qualquer momento, ler de novo aquela informação para saber se determinada pessoa está infectada ou não.
Eu recomendo que você leia o script teste da CLEO+ para entender como utilizar, pois é um conceito bem novo e peculiar.
INIT_EXTENDED_CHAR_VARSINIT_EXTENDED_CAR_VARSINIT_EXTENDED_OBJECT_VARSInicializa X variáveis internas naquela entidade. Você envia um identificador e número de quantas vars você precisa.
Normalmente você usará "AUTO" no identificador, assim a CLEO+ usará o ponteiro do seu script para determinar o valor do identificador, e automaticamente será um identificador único. Se você quer que a sua informação seja controlada por outros scripts, use um texto qualquer de até 99 caracteres, intermamente o texto será convertido para hash key.
Dica: visto que o "AUTO" usa o ponteiro do script como identificador, se outro mod quer trabalhar com o seu identificador, ele pode usar GET_SCRIPT_STRUCT_NAMED para pegar o ponteiro do seu script e usá-lo como identificador para assim controlar as mesmas variáveis daquele script, no entanto, isto é dependente do nome do script, e mais de um script pode ter o mesmo nome. Uma maneira melhor, principalmente se você está trabalhando com múltiplos scripts do mesmo mod, é usar GET_THIS_SCRIPT_STRUCT para pegar o ponteiro do seu script principal, e levar este valor para os seus outros scripts trabalharem no mesmo identificador.
Não fique inicializando todos os frames! O uso mais comum é antes checar se determinada variável existe com o GET, caso não exista, você usa o INIT para inicializar. Se por algum acaso você usar isto em uma entidade que já foi inicializada, os dados serão apagados e criados como novo, o que é ok, mas não é uma boa prática.
SET_EXTENDED_CHAR_VARSET_EXTENDED_CAR_VARSET_EXTENDED_OBJECT_VARAqui você envia o identificador, o ID da variável (a primeira é "1") e o valor para escrever lá (INT ou FLOAT).
GET_EXTENDED_CHAR_VARGET_EXTENDED_CAR_VARGET_EXTENDED_OBJECT_VARMesmo de cima, para retornar o valor.
Criar entidades sem prender no jogo salvo
CREATE_OBJECT_NO_SAVEAlém de criar um objeto que não salva junto com o jogo, o comando já implementa as opções de offset e posicionar o objeto automaticamente no chão. Perceba que a posição do chão vem de uma coordenada 3D, ou seja, se adapta caso esteja embaixo de uma ponte.
SET_CAR_GENERATOR_NO_SAVEMarca um gerador de veículo estacionado para não salvar junto com o jogo.
Novo sistema de BLIPs
ADD_CLEO_BLIPREMOVE_CLEO_BLIPCria um BLIP no mapa do radar usando um sistema totalmente novo. Eles não são salvos no jogo salvo, nem atingem o limite de BLIPs do jogo, ou seja, você pode usar à vontade, sem medo.
Ainda, possibilita pintar numa cor RGBA (perceba, inclui transparência), opção de aparecer somente perto ou longe, e a utilizar um RWTEXTURE qualquer como sprite do BLIP, isto quer dizer que você agora pode usar literalmente qualquer textura como BLIP, inclusive de um .txd de sprite de script, utilizando GET_TEXTURE_FROM_SPRITE. No entanto, neste caso não aparecerá na legenda do mapa (mas afinal, quem usa a legenda?).
Ah, mas você quer usar o ID de uma sprite original do jogo (por exemplo, ícone de save)? Sem problemas, simplesmente use, e neste caso a legenda funcionará.
Pegar uma textura a partir de um .txd de script
GET_TEXTURE_FROM_SPRITENewOpcodes.cleo implementou maneiras legais de ter controle à uma textura a partir de .bmp, .png e .dds, no entanto, não era compatível com instalação no ModLoader, nem a melhor maneira de trabalhar.
CLEO+ possibilita retornar uma textura (um ponteiro para RwTexture) a partir de um arquivo .txd, sim, daqueles que você coloca numa pasta "models/txd", totalmente compatível com ModLoader e facilmente trabalhado com Magic.TXD, podendo usar compressão, mipmaps etc (não use mipmaps para texturas/sprites usadas na interface!!!).
É simplesmente a sprite que você carrega com LOAD_TEXTURE_DICTIONARY e LOAD_SPRITE.
E esta textura pode ser usada de maneira interna no jogo, como trocar alguma textura do jogo por ela (desde que você consiga o acesso), ou para criar BLIPs personalizados com ADD_CLEO_BLIP citado acima.
Novo sistema de desenhar sprite/textura na tela.
DRAW_TEXTURE_PLUSNão atinge os limites de sprites do jogo (que originalmente é 128 por script), você pode usar milhares.
Em vez de um ID de uma sprite, você usa uma textura diretamente (RWTEXTURE). Se você quer a sprite como no sistema nativo do jogo, use GET_TEXTURE_FROM_SPRITE para pegar a sprite do .txd que você carregou.
Enviando "0" no argumento de textura, simplesmente renderizará sem textura, igual ao DRAW_RECT.
Diferente do método nativo do jogo, este você NÃO precisa usar USE_TEXT_COMMANDS para atualizar a tela, é sempre atualizado automaticamente, basta deixar este comando rodando em loop todos os frames para que seja desenhado.
No argumento DRAW_EVENT você escolhe exatamente o momento que a sprite será desenhada na tela, ou seja, você pode desenhar na frente ou atrás da hud etc.
O argumento Depth é o eixo de profundidade da sprite, usado somente em sprites mascaradas. Você pode deixar 0.0.
FixAR corrige o aspect ratio, assim você não precisa usar GET_FIXED_XY_ASPECT_RATIO, o comando fará isto pra você, semelhante ao GTA V.
MaskVertCount e MaskVertArray é onde você define a máscara, se você não está utilizando o comando como máscara, simplesmente deixe "0". O trabalho com máscara não é tão user friendly, foi pensado em casos mais específicos: em count, é o número total de vértices, enquanto array é um ponteiro onde está armazenado todas as posições X e Y de cada vértice. A correção de aspect ratio não é feita, pois é basicamente impossível definir o "tamanho", visto que são posições cruas, assim, você terá que corrigir o AR você mesmo nos valores das posições, o que requer certa matemática.
Desenhar na tela
CONVERT_3D_TO_SCREEN_2DVocê envia uma coordenada 3D numa posição do mapa, e este comando retorna a posição 2D da tela do jogo, inclusive um valor de tamanho para você usar para desenhar um texto na tela que se adapta com a distância que o ponto 3D está.
Isto é exatamente (até um pouco melhor) o que a Rockstar North usou para realizar testes de depuração durante o desenvolvimento do jogo. Você pode querer usar, como eu usei no Real Traffic Fix, é de fato muito útil para testes.
Os argumentos CheckNearClip e CheckFarClip são para limitar a distância mínima e máxima. Você pode usar este comando com IF para saber se o ponto está dentro da visão mínima e máxima da câmera do jogo.
DRAW_STRINGDRAW_STRING_EXTOs comandos DISPLAY_TEXT são péssimos para certos casos, pois ele pede um GXT, e antes de usá-lo, você precisa usar uma sequência de vários comandos para formatá-lo (sim, usar GOSUB com determinada formatação é uma boa, mas ainda chato). Este comando é um novo sistema, você envia de fato uma string, ou um ponteiro pra uma string, e nele mesmo, há as opções básicas de formatação, inclusive uma pré-formatação com bom visual, utilizando outline. Se não é o bastante, use a variação DRAW_STRING_EXT, que inclui todas as opções de formatação num único comando!
Perceba também que inclui o DRAW_EVENT, igual ao DRAW_TEXTURE_PLUS, isto é, você pode escolher exatamente o momento que será desenhado, antes ou depois do hud por exemplo, prefira usá-lo junto com DRAW_TEXTURE_PLUS se você quer desenhar fundos para o texto etc, e há também o FixAR, que corrige automaticamente o aspect ratio, para a fonte não ficar esticada em monitores widescreen.
Tarefas de pessoas (CHAR TASK)
Uma das coisas que deixa os mods CLEO muito instáveis, atrapalhando e causando bugs na inteligência artificial do jogo, como interrompendo ações dos pedestres etc, é justamente a falta de boas e fáceis maneiras de checar as tarefas atuais daquele CHAR, o que inclusive faz os modders usarem métodos ruins, como checar se está fazendo tal animação.
CLEO+ roda todas as pessoas do jogo naquele frame e guarda, como um cachê, a informação de quais tasks e situação daquela pessoa. Portanto, você pode utilizar aos milhares, a performance é ótima.
IS_CHAR_DOING_TASK_IDCheca se o CHAR está fazendo uma task de determinado ID.
Isto é realmente muito útil, pois o jogo tem quase 400 tasks, e você pode checar todas elas para saber se determinado CHAR está fazendo determinada coisa. No entanto, não necessariamente a task prioritária, ele pode estar com uma task de matar alguém, mas no momento está simplesmente correndo por aí.
Você também pode querer dar uma olhada no GET_CHAR_PEDSTATE e GET_CHAR_SIMPLEST_ACTIVE_TASK, principalmente este último, que retorna a tarefa principal atual.
GET_CHAR_TASK_POINTER_BY_IDRetorna o ponteiro de determinada task. Útil para fazer operações mais avançadas com a classe daquela task.
Abaixo há outros comandos mais específicos, prefira usá-los em vez deste, pois eles consideram mais de uma tarefa (ou seja, menos propenso à erros) e com performance ainda melhor. Também dê uma olhada no GET_CHAR_SIMPLEST_ACTIVE_TASK.
GET_CHAR_SIMPLEST_ACTIVE_TASKRetorna a tarefa ativa mais "simples" de todas, basicamente, a principal. Por exemplo, há uma tarefa de uma pessoa matar a outra, não retornará a tarefa de matar, mas sim de estar correndo até a pessoa ou usando a arma.
Retorna o ponteiro mas também o ID dela, para uma fácil checagem de qual tarefa é. Isto é diferente da IS_CHAR_DOING_TASK_ID e GET_CHAR_TASK_POINTER_BY_ID pois elas consideram todas as tarefas, mesmo não sendo a principal.
GET_CHAR_KILL_TARGET_CHARRetorna o CHAR que determinado CHAR está tentando matar. Sério que o jogo não tinha um comando para isto??
IS_CHAR_USING_GUNCheca se o CHAR está usando uma arma (não só segurando, mas de fato usando, ou seja, mirando ou atirando). Para somente atirando, use GET_CHAR_WEAPON_STATE.
IS_CHAR_FIGHTINGCheca se o CHAR está lutando.
IS_CHAR_FALLEN_ON_GROUNDCheca se o CHAR está caído no chão, por exemplo nocauteado.
IS_CHAR_ENTERING_ANY_CARIS_CHAR_EXITING_ANY_CARCheca se o CHAR está entrando ou saindo de algum carro.
IS_CHAR_PLAYING_ANY_SCRIPT_ANIMATIONCheca se o CHAR está realizando qualquer animação nomeada, isto é, normalmente de scripts. Útil para o seu mod não interromper as animações de outro mod ou algo assim.
IS_CHAR_DOING_ANY_IMPORTANT_TASKEste comando é um monstro: Durante o cachê, CLEO+ considera se tal CHAR não está fazendo nenhuma tarefa importante, como matar alguém, correndo em pânico etc. Caso ele esteja "disponível para outras tasks", este comando retornará verdadeiro.
Esta explicação é simplista demais, mas pense assim: Este comando retorna verdadeiro caso o CHAR possa parar o que ele está fazendo para conversar com você. É basicamente isto. Útil para muitos mods, por exemplo, um mod que faz os pedestres atenderem o celular, ele não vai querer atender o celular enquanto ele está lutando contra alguém ou fugindo.
Há também a opção de incluir animações de script nesta checagem.
Você pode querer juntar este com o IS_CHAR_DOING_TASK_ID para adicionar mais exceções. Lembre-se, teste muito.
CLEAR_CHAR_PRIMARY_TASKSLimpa todas as tarefas primárias (preserva as secundárias).
CLEAR_CHAR_SECONDARY_TASKSLimpa todas as tarefas secundárias (preserva as primárias). É uma boa maneira de limpar as tarefas, como animações secundárias, sem atrapalhar na inteligência artificial do CHAR, visto que tarefas primárias são muito importantes.
Gradient noise
Gradient noise é uma excelente utilidade para diversos desenvolvimentos, principalmente gráficos e de jogos.
Consistente em uma geração de número aleatório que considera seus "vizinhos" para uma transição suave (degradê).
Por exemplo, eu utilizei isto para simular a vibração do motor e escapamento de carros com VehFuncs. Se eu tivesse usado uma geração aleatória qualquer, o efeito não seria natural.
Se você acha que não conhecia, na verdade você conhece muito bem: gradient noise é o coração do Minecraft. Você pode gerar mapas inteiros ou parciais (por exemplo, lixos no chão) utilizando gradient noise.
PERLIN_NOISERetorna o valor de um ponto do gradient noise utilizando o algorítimo "perlin noise" (mais especificamente, através do simplex noise).
Se você quer utilizar gradient noise de maneira mais simples possível, use este comando. Você simplesmente envia uma variável de progresso/offset que retornará um valor em torno de -1.0 e 1.0 (mas pode ultrapassar).
O valor enviado pode ser numa faixa de 10... 100... 1000... Depende do resultado que você quer. Normalmente você irá trabalhar em um loop, subindo ou abaixando suavemente uma variável, e terá o valor do noise retornado em uma outra. Há exemplo no script de teste da CLEO+.
O valor inicial pode ser considerado uma "seed"
PERLIN_NOISE_FRACTALPERLIN_NOISE_FRACTAL_2DPERLIN_NOISE_FRACTAL_3DIgual ao de cima, mas agora, com vários argumentos para você personalizar o resultado final. Se você não sabe por onde começar, teste: PERLIN_NOISE_FRACTAL 2 0.1 1.0 1.0 2.0 0.5 (f)
O "octaves" é um tanto interessante: à grosso modo ele mistura o noise mais de uma vez para retornar um resultado ainda mais natural. Indispensável para por exemplo gerar um terreno mais natural, mas há impacto negativo na performance, cada octave multiplica o cálculo.
Usar octave "1" os argumentos não serão importantes, exceto frequency, que define a frequência que os valores irão saltar.
No script teste da CLEO+ há literalmente um visualizador de perlin noise embutido onde você configura os valores e visualiza na tela em escala de cinza! Dê uma olhada.
Pegar entidades (carros, pessoas, objetos)
GET_ANY_CHAR_NO_SAVE_RECURSIVEGET_ANY_CAR_NO_SAVE_RECURSIVEGET_ANY_OBJECT_NO_SAVE_RECURSIVEFinalmente eu tive a oportunidade de reinventar os comandos GET_RANDOM_*_NO_SAVE_RECURSIVE! Eu odiava eles.
Neste, retorna literalmente todas as pessoas, veículos ou objetos, sem exceções, sem checagem de distância, mas agora, utilizando uma variável que informa o progresso da busca.
O uso é simples: tenha uma variável tempo, seta-a para 0, e rode este comando em um WHILE usando-a no argumento de progresso. Num único WHILE você terá acesso às entidades (diferente da solução anterior que precisava de um IF e depois um WHILE), e o melhor: devido ao progresso da busca ser numa variável, isto resolve o problema do comando antigo da CLEO, que não havia como colocar um dentro do outro, neste, você pode usar quantos você quiser!
Veja no script de teste da CLEO+ um exemplo de uso, bem mais agradável. Mas lembre-se que CLEO+ tem events, e os events podem ser úteis para você caso o seu mod precise disso a todo o momento.
GET_CLOSEST_COP_NEAR_CHARRetorna o policial mais próximo de um CHAR numa distância limite. Muito útil para mods que precisam detectar se há um policial vendo a cagada de alguma pessoa. Há também filtro para incluir ou não à pé, de carro, e se está te vendo ou não!
GET_CLOSEST_COP_NEAR_POSMesmo de GET_CLOSEST_COP_NEAR_CHAR, mas agora é um policial próximo de certa posição.
Manipulação de memória
READ_STRUCT_OFFSETWRITE_STRUCT_OFFSETMesma coisa do READ_MEMORY e WRITE_MEMORY, no entanto, inclui um offset que será somado, assim você transforma 2 linhas de código numa só, mais agradável e uma minúscula melhoria de desempenho, visto que é algo muito comum.
READ_STRUCT_OFFSET_MULTIWRITE_STRUCT_OFFSET_MULTIMesmo de cima, mas agora além do offset (que pode ser 0, se você não precisa) ele lê e escreve múltiplas vezes. Você escolhe quantas vezes, e o tamanho a cada leitura ou escrita.
O melhor exemplo de uso é o seguinte: Imagine que você tem um ponteiro para uma coordenada XYZ e quer ler cada valor desta coordenada para 3 diferentes variáveis: READ_STRUCT_OFFSET_MULTI pCoord 0x0 3 4 (x y z). Simples assim.
READ_STRUCT_PARAMWRITE_STRUCT_PARAMSemelhante ao *_STRUCT_OFFSET mas em vez de um offset, é um index, que pula os bytes de 4 em 4.
Isto é, index 0 lerá os primeiros 4 bytes, index 1 lerá a partir do quinto byte. Isto é excelente para thread/script memory, pois é comum guardar uma sequência de dados de 4 bytes na thread/script memory, assim, você pode ler e escrevê-los baseado num index, o que é ótimo inclusive para o uso do REPEAT.
Dica: no index, use um CONST_INT para definir um nome para ele, o código fica bem organizado.
COPY_MEMORYCopia o conteúdo da memória de um lugar pra outro com o determinado tamanho.
MAKE_NOPEscreve uma sequência de NOPs (ou seja, em nosso caso, 0x90) em alguma região da memória para "apagar" a execução.
Anteriormente isto era feito através de várias linhas de WRITE_MEMORY, visto que o WRITE_MEMORY não é mais do que um memory set, portanto era necessário escrever vários "0x90909090" etc. Este comando simplifica o processo.
Renderizar objetos em um CHAR ou OBJECT
CREATE_RENDER_OBJECT_TO_CHAR_BONECREATE_RENDER_OBJECT_TO_CHAR_BONE_FROM_SPECIALDELETE_RENDER_OBJECTSe você já tentou colocar um objeto na mão de um CHAR, conhece a dor de cabeça. O jogo é péssimo nisso, causa muitos problemas.
Esta nova solução você não cria um objeto, mas sim uma tarefa de renderização. CLEO+ irá renderizar aquele modelo durante a renderização daquela pessoa, como funcionam as armas do jogo.
Perceba que não há limites, você pode renderizar qualquer modelo do jogo (há algumas exceções que serão corrigidas) em qualquer parte do corpo de um CHAR, em qualquer rotação, tamanho, e até mesmo distorcer o objeto (igual à distorção 4D do Tuning Mod).
Você consegue até recriar a arma de um CHAR (dica: há uma flag no CPlayerData para esconder a arma, use em loop, mas somente player). Muito útil para objetos simples, como uma simples garrafa, quanto para criar trabalhos complexos como armaduras com super poderes.
A variação "FROM_SPECIAL" é para usar com "SPECIAL_MODEL", o que possibilita usar objetos carregados diretamente de um .dff e .txd (sem o uso de ID).
Da mesma forma, nas novas versões do CLEO+ há também para objetos:
CREATE_RENDER_OBJECT_TO_OBJECTCREATE_RENDER_OBJECT_TO_OBJECT_FROM_SPECIALSET_RENDER_OBJECT_AUTO_HIDEPara simplificar o seu script, use isto, você tem a opção da CLEO+ esconder automaticamente o objeto caso a pessoa morra, pegue uma arma ou entre num veículo. A tal tarefa de renderização continua existindo, só não fará nada.
SET_RENDER_OBJECT_VISIBLESET_RENDER_OBJECT_POSITIONSET_RENDER_OBJECT_ROTATIONSET_RENDER_OBJECT_SCALESET_RENDER_OBJECT_DISTORTIONMais controles básicos. Usar distorção junto com rotação ou escala pode ter resultados estranhos.
Embaixo do capô: A variável do RENDER_OBJECT é um ponteiro para uma class interna do CLEO+, não vou dar ela inteira aqui pois ela pode sofrer alterações, mas se você precisa de um trabalho mais avançado e técnico no resultado, o offset 0 é o CPed, offset 4 é RpClump, offset 8 é o RwFrame, e 12 é o RpAtomic. Caso o modelo seja um clump, o frame e atomic serão 0, caso contrário, o clump que será 0.
Isto é útil para trabalhar com subobjetos da hierarquia, como funciona no Tuning Mod. Por exemplo, adicione um objeto num .ide usando "hier" para ser um objeto comum em forma de clump, o tutorial do Tuning Mod ajuda, sabendo trabalhar com clumps, você conseguirá controlar a rotação, posição e tamanho de cada objeto filho, podendo criar animações complexas etc.
Modo 2 jogadores
SET_CHAR_SECOND_PLAYERDISABLE_SECOND_PLAYERUma maneira de ativar e desativar o segundo jogador a partir de um CHAR já criado. Foi importante para a ideia do Coop Storyline e Recruit 2 Player.
FIX_TWO_PLAYERS_SEPARATED_CARSTodos os mods de 2 jogadores precisam implementar uma correção para que possibilite cada jogador entrar em carros separados, ou os mesmos, pensando nisto, a própria CLEO+ implementa essa correção, com excelente funcionamento, basta ativá-la com este comando.
Clima e ambientação
GET_CURRENT_WEATHERGET_FORCED_WEATHERGET_NEXT_WEATHERSET_NEXT_WEATHERGET_RAIN_INTENSITYSET_RAIN_INTENSITYO clima da ambientação do jogo é algo importante. Por que não havia o básico?
GET_CURRENT_HOURGET_CURRENT_MINUTEJá existe GET_TIME_OF_DAY mas além de ser um nome um pouco confuso de encontrar, na gigante maioria das vezes você só vai precisar da hora, assim é interessante ter um comando separado para usar somente 1 variável.
GET_DAY_NIGHT_BALANCERetorna um valor entre 0.0 e 1.0, onde 0.0 é dia, 0.5 é tarde, 1.0 é noite. O valor é o mesmo usado para fazer a transição do pre-lighting do jogo e várias outras propriedades gráficas.
PASS_TIMEPassa determinado número de minutos, simulando uma real passagem de tempo, onde o relógio e calendário do jogo se ajusta completamente.
Por favor, se você quer por exemplo mudar o relógio do jogo de 6 horas para 10 horas, não só escreva o novo valor, prefira utilizar este comando, pois ele simula a passagem real, por exemplo os pickups do jogo terão o tempo considerado e até as nuvens do mod Real Skybox simularão uma nova rotação.
Checar se entidade é criada/controlada por script
IS_CHAR_SCRIPT_CONTROLLEDIS_CAR_SCRIPT_CONTROLLEDIS_OBJECT_SCRIPT_CONTROLLEDAssim você pode facilmente separa pessoas criadas por missões, scripts etc, dos pedestres aleatórios. Mesmo para carros e objetos.
CLEO não ter isto por padrão era um absurdo, pois é algo muitíssimo importante para seus mods não quebrarem o funcionamento de missões e outros mods.
Marcar entidade como criada/controlada por script
MARK_CHAR_AS_NEEDEDMARK_CAR_AS_NEEDEDMARK_OBJECT_AS_NEEDEDAssim, tal entidade não será deletada automaticamente pelo jogo (a não ser que algum outro mod CLEO mal feito marque-as ao contrário). Irão retornar verdadeiro para os comandos IS_*_SCRIPT_CONTROLLED.
Ajuste de resolução / aspect ratio / widescreen
GET_CURRENT_RESOLUTIONRetorna a resolução atual, útil para casos mais específicos.
[size=100]GET_FIXED_XY_ASPECT_RATIO[/size]Algo praticamente indispensável caso você esteja desenhando algum conteúdo na interface, como uma sprite, quadrado etc.
O uso é muito simples: Você envia um valor X e Y, por exemplo o tamanho de um quadrado, e ele retorna o valor corrigido baseado no aspect ratio da resolução do jogo, assim, ao desenhar o tal quadrado, você utiliza os valores retornados, e assim ele realmente será um quadrado mesmo em resoluções widescreen. Como sempre, há exemplo no script teste da CLEO+.
Retornar tipo ou classe de entidade ou modelo
GET_ENTITY_TYPERetorna o tipo de entidade a partir de um ponteiro pra CEntity (chamado no CLEO+ simplesmente de ENTITY).
Veja a enum ENTITY_TYPE, basicamente você difere um veículo, de uma pessoa, de um objeto... Isto é útil quando você tem um ENTITY e precisa identificar o que exatamente aquilo é.
Um dos usos é: Você usa isto para checar se é uma pessoa, se é, use GET_PED_REF para retornar a referência como um CHAR para utilizar no script.
GET_MODEL_TYPERetorna o tipo de modelo a partir de um ID de modelo.
Mais checagens de input (botões, teclas)
IS_MOUSE_WHEEL_UPIS_MOUSE_WHEEL_DOWNNão era possível checar se a roda/scroll do mouse havia rolado, agora é. No entanto, lembre que em notebooks isto pode retornar verdadeiro muitas vezes por segundo.
IS_KEY_JUST_PRESSEDIS_BUTTON_JUST_PRESSEDRetorna se pressionou uma tecla ou botão somente naquele frame.
Se você trabalhou com mods CLEO pelo menos um pouco, deve estar sentindo um alívio. É, eu sei o que você sente.
Mas é importante lembrar que retorna somente naquele frame, isto é, se o seu loop tem 2 WAIT, o seu loop está rodando em 2 frames separados, na prática irá falhar 50% das vezes. Portanto tome cuidado com o uso dos WAIT.
GET_MOUSE_SENSIBILITYRetorna a sensibilidade do mouse configurada no menu do jogo. Essencial para por exemplo criar um cursor in-game com a sensibilidade correta do jogador, ou qualquer coisa que requer ler o movimento do mouse, basta multiplicar o valor pela sensibilidade.
SET_CAMERA_CONTROLEu sempre estive inconformado com o fato do jogo não ter uma maneira de desativar somente o controle de câmera.
SET_PLAYER_CONTROL_PAD_MOVEMENTEu sempre estive inconformado com o fato do jogo não ter uma maneira de desativar somente o controle do player, preservando a câmera.
SET_PLAYER_CONTROL_PADE este aqui é a desativação total de um controle. POR FAVOR, PROCURE USAR ISTO EM VEZ DE SET_PLAYER_CONTROL!!! Pois este segundo, nativo do jogo, não só desativa o controle do player, mas o também deixa "seguro", ou seja, a polícia para de atirar em você etc, isto estraga o gameplay. SET_PLAYER_CONTROL_PAD faz somente o que diz, ou seja, desativa o controle, sem fazer nada além.
IS_AIM_BUTTON_PRESSEDCheca, de boa maneira, se o botão de mira está pressionado. Adaptado ao GInput. Lembre-se, botão, se você quer saber se está mirando, use IS_CHAR_USING_GUN.
IS_ANY_FIRE_BUTTON_PRESSEDCheca, de boa maneira, se o botão de tiro está pressionado. Adaptado ao GInput. Retorna também o tiro secundário. Lembre-se, botão, se você quer saber se está atirando, use GET_CHAR_WEAPON_STATE.
IS_SELECT_MENU_JUST_PRESSEDCheca, de boa maneira, se o botão de seleção foi pressionado neste exato momento. Isto é, a tecla de correr, ou X no controle de PS. Isto é muito útil pois dentro de um carro, o botão de seleção se torna o botão de acelerar, o que deixa tudo confuso. Este comando resolve tudo, ele considera o botão de correr (que por padrão é Espaço) mesmo dentro do carro!
GET_TIME_NOT_TOUCHING_PADRetorna o tempo desde que você não toca no controle, em milissegundos.
Controle de pickups
GET_PICKUP_THIS_COORDRetorna algum pickup que esteja nesta coordenada. Não é comum, mas existe a possibilidade de existir mais de um na mesma posição, principalmente porque o jogo trabalha com uma coordenada compressada, portanto todos os pickups dentro de X metros estão na mesma posição.
GET_PICKUP_POINTERRetorna o ponteiro para o CPickup, útil para trabalhos mais técnicos e internos através de manipulação de memória.
GET_PICKUP_MODELRetorna o ID do modelo do pickup. Prefira GET_PICKUP_TYPE se é melhor para o seu caso.
GET_PICKUP_TYPEÚtil para identificar se o pickup é uma arma, dinheiro etc sem checar o modelo em si.
Timers / contadores
DISPLAY_ONSCREEN_TIMER_LOCALDISPLAY_ONSCREEN_TIMER_WITH_STRING_LOCALDISPLAY_ONSCREEN_COUNTER_LOCALDISPLAY_ONSCREEN_COUNTER_WITH_STRING_LOCALCLEAR_ONSCREEN_TIMER_LOCALCLEAR_ONSCREEN_COUNTER_LOCALDISPLAY_TWO_ONSCREEN_COUNTERS_LOCALDISPLAY_TWO_ONSCREEN_COUNTERS_WITH_STRING_LOCALTodos os comandos de contadores de tempo e valores, agora adaptados para variáveis locais, pois nativamente só estão disponíveis em variáveis globais, o que atrapalha na criação de mods CLEO.
O funcionamento é exatamente igual aos de variáveis globais, ou seja, você envia uma variável e o valor dela será usado para contar, bem simples.
De bônus, perceba que os comandos "TWO", ou seja, 2 contadores, foram re-adicionados (eles foram removidos da versão final do jogo, então os re-adicionei como vars locais).
SET_ONSCREEN_COUNTER_FLASH_WHEN_FIRST_DISPLAYED_LOCALSET_TIMER_BEEP_COUNTDOWN_TIME_LOCALSET_ONSCREEN_COUNTER_COLOUR_LOCALMais comandos de funções internas do jogo que não eram possíveis usar por comandos.
Situação do gameplay: missão, SAMP, save etc
IS_ON_MISSIONCheca se está numa missão, semelhante ao $ONMISSION == true do Sanny Builder, mas agora implementado da maneira mais correta, como o jogo implementou internamente, considerando diferente index da variável de missão.
IS_ON_SAMPIS_ON_CUTSCENESe está durante o San Andreas Multiplayer; cutscene (filmes de missões).
IS_ON_SCRIPTED_CUTSCENESe está durante uma cutscene scriptada (aquelas cenas comuns durante as missões). Basicamente checa se o modo "widescreen" (que na verdade, é a tela cinematográfica) está ativa, onde o jogo normalmente a usa para estas cenas.
IS_GAME_FIRST_STARTCheca se é a primeira vez que o jogo está iniciando naquele jogo salvo ou novo jogo. Isto é importante para casos específicos, principalmente se o seu script faz hook no jogo, você não vai querer que o hook seja feito mais de uma vez caso dar carregar ou iniciar um novo jogo.
GET_CURRENT_SAVE_SLOTRetorna o ID do slot do save que você acabou de carregar. -1 caso seja novo jogo.
Muito útil para você salvar e carregar informações do jogo salvo em um arquivo local por exemplo, para assim o seu mod ter suporte ao salvamento de informações em cada jogo salvo através de um arquivo em vez de SAVE_THIS_CUSTOM_SCRIPT.
Se você pretende salvar informações ao salvar o jogo, use o comando SET_SCRIPT_EVENT_SAVE_CONFIRMATION.
IS_CHEAT_ACTIVECheca se tal cheat está ativo. Você consegue os IDs dos cheats aqui.
GET_LOCAL_TIMERetorna a data completa do PC do jogador.
IS_HUD_VISIBLECheca se o hud está visível, de boa maneira.
IS_RADAR_VISIBLECheca se o radar/minimapa está visível, de boa maneira.
SET_ON_MISSIONÉ a mesma coisa de
$ONMISSION = 1 no Sanny Builder, mas com uma prática mais correta e que funciona mesmo se o jogo estiver usando outro ID de variável global.Câmera
GET_CURRENT_CAMERA_MODERetorna o modo de câmera atual. Há dezenas (veja o enum CAMERAMODE), mas muitas são só leftovers do desenvolvimento do jogo. Eu já usei muito para checar se está mirando, mas IS_CHAR_USING_GUN deve fazer um melhor trabalho.
GET_UNDERWATERNESSRetorna o quão "embaixo d'água" a câmera está, entre 0.0 e 1.0.
GET_FADE_ALPHARetorna o alpha atual do fade sendo executado. Ou seja, 255.0 a tela está 100% preta (mas raramente atingirá exatos 255.0 pois normalmente logo em seguida começa um fade out, para ficar mais seguro, considere 200.0).
GET_OFFSET_FROM_CAMERA_IN_WORLD_COORDSRetorna a coordenada num offset a partir da posição da câmera, por exemplo, "1.0 0.0 0.0" pegará a posição 1 metro para o lado direito da câmera. Mesma coisa de por exemplo GET_OFFSET_FROM_CAR_IN_WORLD_COORDS.
GET_THIRD_PERSON_CAMERA_TARGETUma função usada pelo jogo para determinar onde a arma está apontando com base num range e posição do char (normalmente o player), retornará o ponto inicial e final, como se fosse o trajeto de um tiro (não considera colisões).
GET_ACTIVE_CAMERA_ROTATIONRetorna a rotação da câmera. Simples assim. Por que diabos demorou 20 anos para alguém colocar isto?
Note que os valores retornados são um pouco mais complexos do que o esperado.
GET_CAMERA_STRUCTRetorna o ponteiro para o TheCamera (CCamera) e ActiveCam (CCam), duas classes muito úteis, para você ter fácil acesso aos membros delas.
GET_CAMERA_ROTATION_INPUT_VALUESSET_CAMERA_ROTATION_INPUT_VALUESFinalmente agora você pode controlar a câmera por script! Especificamente, a câmera controlável.
Por exemplo, você pode usar GET para pegar os valores de input atuais, soma 90, dê SET e pronto, você girou a câmera 90 graus.
Matemática
CLAMP_FLOATCLAMP_INTClamp nada mais é do que uma limitação mínima e máxima de um valor. Em outras palavras, CLAMP_INT i 0 100 (i) é a mesma coisa de você fazer IF i < 0 ; i = 0 e IF i > 100 ; i = 100.
Não só para simplificar o seu código deixando-o mais organizado, mas tudo é executado de uma só vez, diferente do uso de IF que, em SCM, é uma operação muito complexa, e considerando que limitar o valor de uma variável é algo comum, esta otimização pode de fato fazer diferença.
EASEVocê envia um progresso linear (0.0~1.0) para retornar o valor alterado numa curva de ease.
É a mesma implementação do site easings.net, inclusive, as opções são as mesmas com os mesmos nomes. Entre lá para visualizá-las.
Isto é excelente para criar animações suaves.
GET_ANGLE_FROM_TWO_COORDSRetorna o ângulo Z (heading) a partir de 2 coordenadas.
RANDOM_PERCENTVocê envia um número entre 0 e 100, a condição retornará verdadeira baseado nesta porcentagem, ou seja, 50 retornará verdadeiro em média 50% das vezes, simples assim.
GENERATE_RANDOM_INT_IN_RANGE_WITH_SEEDGENERATE_RANDOM_FLOAT_IN_RANGE_WITH_SEEDO mesmo comando de gerar um número aleatório, mas agora você pode enviar uma seed.
Se você não entende o conceito de seed, basicamente, a mesma seed sempre retornará o mesmo número aleatório. Isto é útil para você ter valores aleatórios, mas que sempre sejam os mesmos baseados numa seed.
E, internamente, o jogo já cria seeds para entidades, você pode pegá-las abaixo:
GET_CHAR_RANDOM_SEEDGET_CAR_RANDOM_SEEDGET_OBJECT_RANDOM_SEEDRetorna a seed da entidade, que é um número aleatório "único", pode ser útil para usar com GENERATE_RANDOM_*_IN_RANGE_WITH_SEED
GET_COORD_FROM_ANGLED_DISTANCEVocê envia uma coordenada, um ângulo e distância. Retorna a coordenada que está naquele ponto.
LERPInterpolação linear entre 2 valores float. Por exemplo, A=1.0 e B=2.0, caso T seja 0.5, retornará o valor entre os dois, isto é, 1.5.
Dica: usar isto junto com EASE dá para fazer umas coisas bem legais, como movimentação de câmera, animação na interface etc.
Matrizes e quaterniões
Convertidos do NewOpcodes.cleo, possibilita trabalhar com matrix e quaternions, operações muito importantes para gráfico 3D, por exemplo, quaternion é a melhor maneira de rotacionar objetos sem o problema do gimbal lock. Matrix basicamente é o que indica a posição, tamanho e rotação do nosso objeto 3D.
É importante notar que absolutamente nenhum comando aqui irá alocar uma matrix ou quaternion para você, você envia um ponteiro com o espaço. Normalmente uma matrix você conseguirá lendo alguma class (por exemplo CObject+0x14 é a matrix do objeto; CMatrix e RwMatrix são essencialmente a mesma coisa), enquanto o quaternion você trabalhará com algum espaço de 16 bytes, em outras palavras, um quaternion nada mais é do que um vector4, ou seja, um XYZ com mais um float (normalmente chamando de W ou Real). Eu recomendo usar o ponteiro de uma variável (que tenha outras 3 variáveis disponíveis), ou melhor ainda, um thread/script memory com pelo menos 16 bytes disponíveis para usar como quaternion. Caso você esteja criando uma matrix do zero, são 72 bytes.
QUAT_SLERPVocê envia um progresso (0.0~1.0) para criar uma interpolação suave entre 2 quaternions.
SET_MATRIX_ROTATION_FROM_QUATSET_QUAT_FROM_MATRIXSeta a rotação da matrix baseado num quaternion, ou pega um quaternion baseado numa matrix.
ROTATE_QUAT_ON_AXISROTATE_MATRIX_ON_AXISRotaciona o quaternion ou matrix num eixo e ângulo. Isto é a maneira mais correta de rotacionar algo, pois não causa o gimbal lock. Provavelmente você usará este comando mais de uma vez para ajustar a rotação, e normalmente você usará o axis como 0.0, -1.0 ou 1.0 para indicar a direção do eixo que você deseja rotacionar o determinado ângulo.
GET_NORMALISED_QUATNormaliza os valores do quaternion.
MULTIPLY_QUATSMultiplica um quaternion por outro.
INITIALISE_QUATInicializa um quaternion enviando os valores brutos. O mesmo pode ser feito com WRITE_OFFSET_MULTI, tanto que eu tive preguiça de converter o mesmo pro matrix.
CONVERT_DIRECTION_TO_QUATEste é o único que não veio do NewOpcodes.cleo. Este é um código que encontrei por aí para a Unreal Engine 4, se trata de uma função LookAt que você envia uma somente um vetor de direção e retornará um quaternion normalizado com a rotação para aquela direção.
Um ótimo uso é com o GET_COLPOINT_NORMAL_VECTOR, você consegue rotacionar algo baseado na rotação da face de colisão, para por exemplo criar um mod de cover ou pichar em qualquer lugar. No entanto me pareceu causar bugs ao enviar valores baixos, como 0.0~1.0, multipliquei por 10.0 e pareceu ok.
GET_MATRIX_X_ANGLEGET_MATRIX_Y_ANGLEGET_MATRIX_Z_ANGLERetorna os valores dos ângulos X, Y ou Z de uma matrix.
GET_OFFSET_FROM_MATRIX_IN_WORLD_COORDSRetorna a coordenada num offset a partir da posição de determinada matrix, por exemplo, "1.0 0.0 0.0" pegará a posição 1 metro para o lado direito da matrix. Mesma coisa de por exemplo GET_OFFSET_FROM_CAR_IN_WORLD_COORDS.
SET_MATRIX_LOOK_DIRECTIONFaz uma matrix ser rotacionada em direção à outro ponto 3D. Similar ao
Transform.LookAt da Unity Engine.Operações com strings
Utilizar strings (textos) como ponteiros é algo muito comum na CLEO, portanto...
COPY_STRINGCopia uma string para a outra. Normalmente isto era feito com STRING_FORMAT, mas ele realiza operações de formatação, não queremos isto, portanto, COPY_STRING é mais otimizado para você copiar ou simplesmente criar uma string totalmente nova escrevendo ela para um ponteiro, por exemplo COPY_STRING "Test" (i).
GET_STRING_LENGTHRetorna o tamanho total da string (até o null terminator, mas o null terminator não é incluído no resultado).
Se limita à 128, por segurança. Se retornar 128, provavelmente não é uma string válida. A condição retorna verdadeira caso retorne acima de 0.
IS_STRING_EQUALCheca se uma string é igual à outra.
O interessante aqui são as opções: tamanho máximo, diferenciar maiúsculas de minúsculas, e ignorar um caractere de sua escolha (por exemplo "test" e "t*st" com o caractere para ignorar "*" dará como verdadeiro para "tast").
IS_STRING_CHARACTER_ATCheca se há determinado caractere em determinado index de uma string.
STRING_FINDEncontra uma substring dentro de uma string. Implementação da mesma função do C++.
Por exemplo, "test.dff", você pode encontrar ".dff", dará verdadeiro e retornará o index do início onde foi encontrado. Há também opção de encontrar o primeiro, ou último, por exemplo se você quer encontrar a extensão de um arquivo, você procurar pelo último "." e não pelo primeiro.
CUT_STRING_ATUma maneira simples de cortar uma string em determinado index. Basicamente escreverá um null terminator (0) ali.
IS_STRING_COMMENTUma maneira simples de checar se uma string está comentada com "#", ";" ou "//", também considera espaços em branco. É muito útil caso o seu script suporte a leitura de um arquivo de configuração de formato próprio, assim, cada linha que você ler, use este comando.
SET_STRING_UPPERSET_STRING_LOWERTransforma uma string em todas maiúsculas ou todas minúsculas.
Sons
GET_AUDIO_SFX_VOLUMEGET_AUDIO_RADIO_VOLUMERetorna o volume dos efeitos sonoros ou rádio configurados no menu do jogo. Indispensável para qualquer mod que carrega sons por arquivos, não deixe de usar, por favor!
GET_AUDIOSTREAM_INTERNALRetorna a referência interna de determinado AUDIOSTREAM para ser usado nas funções da bass.dll.
Isto possibilita o uso avançado de áudios, como o controle 3D, equalizador, spectrum, até mesmo o uso de plugins VST usados para produção de música! Veja aqui a documentação (a referência retornada para usar na bass.dll é um HSTREAM).
Efeitos especiais
GET_FX_SYSTEM_POINTERRetorna o ponteiro para o efeito especial (FxSystem_c), útil para operações mais avançadas.
ADD_FX_SYSTEM_PARTICLEAdiciona uma partícula baseada num efeito especial. Algo que incrivelmente não era possível por scripting.
Isto é muito útil, é assim que o jogo cria a maioria dos efeitos do jogo, como fumaças, sangue etc. No próprio comando, você tem várias opções, como cor e tamanho, portanto, você basicamente consegue criar novos efeitos especiais com isto, sendo muito útil para mods de super poderes por exemplo.
Algo que você tem que ter em mente é que por padrão o jogo deixa de criar muitas partículas em gráficos baixos, por exemplo, criando somente metade das partículas caso esteja nos gráficos Low. MixSets tem opção para ignorar isto, multiplicar, aumentando ou diminuindo. Portanto, teste o seu mod em diferentes configurações gráficas, e considere o uso ou desuso do MixSets.
Outra coisa a ser considerada é o argumento Brightness, se é algo não emissivo, por exemplo uma simples fumaça, considere ajustar o brilho com GET_DAY_NIGHT_BALANCE, para escurecer de noite.
IS_FX_SYSTEM_AVAILABLE_WITH_NAMECheca se tal efeito especial existe com determinado nome. Finalmente você vai poder colocar um aviso e não causar crash para a pessoa caso esta pessoa não instale o seu mod de efeitos corretamente.
Ponto de colisão
GET_COLLISION_BETWEEN_POINTSVocê envia 2 coordenadas e será retornado várias informações sobre o ponto de colisão. Veja isto como "atirou num ponto, onde este tiro irá colidir?". Há muitas opções de filtragem, há até mesmo um EntityToIgnore que você envia o ponteiro de uma entidade (por exemplo, um ponteiro pra um char (CPed), car (CVehicle) ou objeto (CObject), que são filhos do CEntity), que o a checagem irá ignorá-los.
Algo importante para você notar, é que ele NÃO retorna um COLPOINT, mas sim você envia um ponteiro de um buffer para que o COLPOINT seja escrito. Esse buffer precisa ter pelo menos 44 bytes, ou seja, você pode usar um script/thread memory de pelo menos 44 bytes para isto. Caso não seja enviado, não retornará o COLPOINT, portanto é opcional.
Um COLPOINT pode ser usado para vários outros comandos da CLEO+.
GET_COLPOINT_COORDINATESGET_COLPOINT_NORMAL_VECTORGET_COLPOINT_DEPTHGET_COLPOINT_SURFACEGET_COLPOINT_LIGHTINGA partir de um COLPOINT (obtido com GET_COLLISION_BETWEEN_POINTS) você pode ter várias informações, como a direção, material da superfície (se é grama etc, lembre-se, há muitos tipos de grama etc, você precisa pesquisar muito, eu uso Col Editor). A direção (NORMAL_VECTOR) é útil para mods como cover e pichação, que você precisa colocar algo na direção de uma parede por exemplo.
GET_CHAR_COLLISION_SURFACEGET_CHAR_COLLISION_LIGHTINGGET_CAR_COLLISION_SURFACEGET_CAR_COLLISION_LIGHTINGO próprio jogo já armazena informações do material e iluminação que determinada entidade está sob, portanto se você só quer saber das informações atuais que a entidade está colidindo (chão), use isto.
Distâncias
LOCATE_CAMERA_DISTANCE_TO_COORDINATESLOCATE_CHAR_DISTANCE_TO_CHARLOCATE_CHAR_DISTANCE_TO_CARLOCATE_CHAR_DISTANCE_TO_OBJECTLOCATE_CAR_DISTANCE_TO_OBJECTLOCATE_CAR_DISTANCE_TO_CARLOCATE_OBJECT_DISTANCE_TO_OBJECTLOCATE_CHAR_DISTANCE_TO_COORDINATESLOCATE_CAR_DISTANCE_TO_COORDINATESLOCATE_OBJECT_DISTANCE_TO_COORDINATESLOCATE_ENTITY_DISTANCE_TO_ENTITYCheca se determinada entidade ou câmera está dentro da distância limite. É semelhante aos outros LOCATE do jogo, mas este é circular/esférico em vez de retangular, ou seja, é de fato a distância de um ponto ao outro, e de bônus inclui para duas ENTITY e a câmera principal do jogo.
Inclusive, há performance melhor, um impacto praticamente nulo, inclusive sem utilizar raiz quadrada no cálculo.
GET_DISTANCE_MULTIPLIERRetorna os multiplicadores de distância do jogo: LOD e geração. Este multiplicador é útil principalmente se você quer que seu mod se adeque às configurações de qualidade do player: o valor do LOD, por exemplo, é diretamente ligado com a distância de visão configurada no menu do jogo.
Carregamento de modelos
GET_MODEL_DOESNT_EXIST_IN_RANGERetorna algum ID de modelo inexistente dentro de um range inicial e final. Caso seja encontrado, a condição dá como verdadeira.
Foi pensado em conjunto com LOAD_SPECIAL_CHARACTER_FOR_ID, isto é, se você quer um ID de modelo temporário para usar em por exemplo num modelo de personagem especial, pegue algum ID disponível com este comando.
Recomendação: IF GET_MODEL_DOESNT_EXIST_IN_RANGE 15000 15024 (model)
Por organização, use o range de IDs 15000 até 15024, há 25 disponíveis, é o suficiente, mas você pode escolher usar outros. O problema é, se por exemplo algum mod de mapa já usa estes IDs, não estão disponíveis, portanto eu os reservei nesta página.
Por exemplo, se algum outro mod usar isto, este mod usará o ID "15000", e o seu mod "15001". Se o primeiro mod descarregar este modelo, completamente, ele voltará a estar disponível para usar novamente.
LOAD_SPECIAL_CHARACTER_FOR_IDO mesmo de LOAD_SPECIAL_CHARACTER, mas você envia um ID de um modelo para o modelo especial ser guardado lá.
Isto foi pensado em conjunto com o GET_MODEL_DOESNT_EXIST_IN_RANGE, que retorna um ID disponível para você usar.
Note que isto de fato ADICIONA um novo ped ao seu jogo, portanto o limite de peds do seu jogo precisa ser aumentá-lo para poder usá-lo. Open Limit Adjuster é perfeito para isto pois ele aumenta o limite automaticamente.
UNLOAD_SPECIAL_CHARACTER_FROM_IDDescarrega um modelo carregado pelo LOAD_SPECIAL_CHARACTER, semelhante ao UNLOAD_SPECIAL_CHARACTER, mas há um porém:
Use UNLOAD_SPECIAL_CHARACTER_FROM_ID após você deletar todos os chars que usam este modelo, pois, caso realmente for o último, CLEO+ descarregará o modelo completamente para que volte a estar disponível no GET_MODEL_DOESNT_EXIST_IN_RANGE. Caso contrário, o próprio jogo fará isto, algo que pode demorar muito tempo. REMOVE_MODEL_IF_UNUSED também ajuda.
REQUEST_PRIORITY_MODELMarca um modelo a ser carregado em modo de prioridade.
LOAD_ALL_PRIORITY_MODELS_NOWFaz todos os modelos prioritários serem carregados, onde pode (mesmo que não sempre) ignorar os modelos não prioritários.
Eu recomendo altamente que você use isto em vez dos comandos nativos não-prioritários, pois LOAD_ALL_MODELS_NOW inclui realmente todos os modelos que o jogo está querendo carregar naquele momento, então você forçará os modelos a serem carregados, aumentando chances de lag spike. Separar em prioridade evita que modelos não importantes sejam carregados junto com o seu, assim evita lag spike no seu script (mesmo que, o melhor mesmo é esperar carregar em vez de usar LOAD_ALL_MODELS_NOW ou LOAD_ALL_PRIORITY_MODELS_NOW).
REMOVE_ALL_UNUSED_MODELSDescarrega completamente da memória todos os modelos que não estejam sendo usado em nenhum lugar (não exista nenhum carro, pedestre etc com este modelo). Caso isto não seja usado, o modelo será descarregado automaticamente pelo jogo no momento que ele precisa de mais memória, o que, dependente do valor do streaming memory que o jogador configurou, pode ser rápido, ou nunca.
Este comando chamará uma função pesada, que fará um loop em praticamente todos os modelos do jogo, portanto, somente use se realmente necessário, e fora do gameplay, por exemplo durante um fade após uma missão ou algo assim.
REMOVE_MODEL_IF_UNUSEDMesmo de REMOVE_ALL_UNUSED_MODELS, mas para um modelo específico.
No UNLOAD_SPECIAL_CHARACTER_FROM_ID, ele já faz isto automaticamente para que volte a estar disponível em GET_MODEL_DOESNT_EXIST_IN_RANGE.
IS_MODEL_AVAILABLE_BY_NAMECheca se determinado modelo existe. Mesmo de IS_MODEL_AVAILABLE, mas por nome de .dff. Considera realmente qualquer arquivo do disco, mesmo não carregado como um ID.
Isto é muito útil para usar antes do LOAD_SPECIAL_CHARACTER_FOR_ID, assim, antes de tentar carregar determinado modelo baseado no nome, você pode saber se tal modelo realmente existe no disco (seja num .img ou no modloader).
GET_MODEL_BY_NAMEEncontra o ID de um modelo baseado no nome dele. Só use caso realmente necessário, evitando durante o gameplay, pois é uma função um pouco pesada.
LOAD_SPECIAL_MODELUma revolução adicionada a partir do CLEO+ v1.2: Carregar arquivos .dff e .txd sem a necessidade de substituir IDs do jogo! Também não atinge outros limites e nem sequer consome parte do streaming (no entanto, por não usar streaming, não é recomendado usar em abundância, como props no mapa).
A ideia é para, principalmente, usar em scripts que requer objetos customizados. Pense em um mod de pesca, você vai querer infinitos modelos e texturas de peixes, ou até mesmo misturar um modelo de um peixe com textura de outro, e usar este modelo de peixe tanto para colocar na mão da pessoa, quanto para um objeto no mapa. LOAD_SPECIAL_MODEL é perfeito para casos assim!
Você dá o caminho do arquivo .dff e .txd (sem a extensão) e o CLEO+ irá carregar pra você instantaneamente (não usa streaming, portanto em alguns casos pode dar um leve stutter pra carregar arquivos pesados etc).
REMOVE_SPECIAL_MODELCaso já tenha algo usando este special model, somente abaixará uma contagem na referência. Quando algo parar de usar (por exemplo, um RENDER_OBJECT ser apagado), descarregará.
GET_SPECIAL_MODEL_DATARetorna o RpClump, RpAtomic e o index do TXD. Útil para usos mais específicos. Por exemplo, é possível adicionar um RpAtomic dentro de algum RwFrame para renderizar o objeto como peça de um carro (como o Tuning Mod).
Armas
GET_CHAR_WEAPON_STATERetorna o estado atual da arma atual do CHAR. Isto é, se está atirando ou recarregando.
IS_WEAPON_FIRE_TYPECheca se determinado ID de arma (WEAPON_TYPE) é de determinado tipo de tiro.
Isto é importante pois hoje é comum adicionar armas sem substituir, e antes era comum as pessoas checarem, por exemplo, se é arma de fogo pelo ID da arma. Este comando deixa o seu mod adaptado para armas adicionadas sem substituir.
GET_WEAPONINFOGET_CURRENT_CHAR_WEAPONINFORetorna o ponteiro para o CWeaponInfo de tal arma, ou da arma atual da pessoa. CLEO+ tem vários comandos que trabalham com o WEAPONINFO, mas você também pode usar leitura de memória.
GET_WEAPONINFO_MODELSRetorna os 2 modelos do WEAPONINFO que tal arma usa, útil para você carregá-los antes de criar a arma, assim sendo facilmente compatível com armas adicionadas sem substituir (você não precisa saber quais são os modelos necessários). Lembrando que algumas poucas armas, como carga explosiva, usa 2 modelos, a gigante maioria usa somente 1.
GET_WEAPONINFO_ANIMGROUPRetorna o ID do grupo de animação do WEAPONINFO. É uma excelente maneira de você checar se tal arma é por exemplo uma shotgun, sendo compatível com armas adicionadas sem substituir.
GET_WEAPONINFO_FLAGSRetorna o valor de todas as flags do WEAPONINFO. Em seguida, use os comandos de checar bits, por exemplo IS_LOCAL_VAR_BIT_SET_CONST, junto com o enum WEAPONINFO_FLAGS para checar as características daquela arma, por exemplo se é pistola dupla, se é pesada etc.
GET_WEAPONINFO_TOTAL_CLIPRetorna a quantidade total que o pente da arma suporta.
GET_WEAPONINFO_FIRE_TYPERetorna o tipo de tiro da arma. Lembrando que IS_WEAPON_FIRE_TYPE lhe pode ser mais útil.
GET_WEAPONINFO_SLOTRetorna o ID do slot que aquela arma ocupa no inventário.
GET_CHAR_WEAPON_CLIPRetorna o pente atual da arma atual do CHAR.
Outras utilidades para o gameplay
FRAME_MODA condição retorna verdadeira a cada X número de frames (baseado no número interno do total de frames do jogo).
A utilidade é separar o trabalho do seu script em frames separados, isto é muito utilizado para otimizar a performance de jogos, por exemplo, IF FRAME_MOD 2 retornará verdadeiro 1 vez a cada 2 frames do jogo (ou seja, somente em frames de número par).
Internamente: if (CTimer::m_FrameCounter % arg == 0).
CHANGE_PLAYER_MONEYMuda o dinheiro do player. No próprio comando você escolhe se você seta (ou seja, muda completamente, sem animação), adiciona, ou remove. Isto é uma maneira excelente de substituir o velho ADD_SCORE que está lá desde o GTA 2.
Outras utilidades para CHAR
FIX_CHAR_GROUND_BRIGHTNESS_AND_FADE_INApós criar um novo CHAR, use este comando para corrigir (com opções) a posição dele no chão (considera a coordenada 3D, portanto adaptado para embaixo de ponte etc), o brilho dele (sem mais chars sendo criados brilhantes ou escuros antes de tocar no chão), e aplicar um fade in, para ele aparecer suavemente na tela, semelhante ao fade out de quando ele desaparece.
SET_CHAR_COORDINATES_SIMPLESET_CAR_COORDINATES_SIMPLEPosiciona uma entidade com valores crus e sem realizar nenhum outro cálculo de offset, inteligência artificial nem nada.
Perceba que isto é uma ótima maneira de corrigir pessoas e motos não aparecendo exatamente na posição que você coloca. Muito comum em motos, onde se você posicionar uma moto embaixo de um lugar não tão alto, a moto aparece em cima do teto, este comando resolve este problema em 100%.
IS_CHAR_REALLY_IN_AIRO comando IS_CHAR_IN_AIR devia ser chamado de "FALLING", pois ele só retorna caso o CHAR esteja fazendo a tarefa de cair, muito pouco útil. Assim, eu fiz este novo comando que realmente retorna caso o CHAR esteja no ar, isto é, não colidindo com o chão.
IS_CHAR_ON_FIRECheca se o CHAR está pegando fogo. Há também uma task para isto, enquanto este checa diretamente o efeito de fogo dentro dele.
GET_CHAR_MAX_HEALTHSério que o jogo não tinha como pegar a saúde máxima de alguém? Também adaptado para o player.
GET_CHAR_HEALTH_PERCENTRetorna a saúde do CHAR, mas em forma de porcentagem, ou seja, 0.0~100.0, utilizando a saúde máxima como base.
SET_CHAR_MODEL_ALPHASeta a transparência do modelo da pessoa.
GET_CHAR_WEAPON_DAMAGE_LAST_FRAMERetorna as informações do último dano causado por uma arma no último frame. Prefira usar junto com SET_SCRIPT_EVENT_CHAR_DAMAGE visto que cada frame pode ter mais de um dano, assim com o event o funcionamento é mais confiável.
SET_CHAR_ARRESTEDForça o CHAR a ser preso. Só deve funcionar com player, mas é interessante principalmente para missões.
GET_CHAR_PEDSTATERetorna o estado atual do CHAR. Muito útil! Há uma lista muito grande que você pode usar para checar várias coisas, semelhante à checagem de tasks com IS_CHAR_DOING_TASK_ID, mas mais simplificada. Basta dar uma olhada no enum PEDSTATE.
GET_CHAR_PROOFSRetorna a imunidade atual do CHAR. Importante caso você esteja usando SET_CHAR_PROOFS e não quera substituir as atuais.
IS_CHAR_WEAPON_VISIBLE_SETCheca se o CHAR está com a visibilidade de arma setada, caso contrário, ele pode estar com arma, mas estar invisível (por exemplo a função de esconder arma dentro de carros do MixSets). Perceba que não checa se ele está com arma, é só a flag de visibilidade. É bom considerá-la em casos que você precisa identificar se uma pessoa viu a arma da outra.
GET_CHAR_STAT_IDRetorna o ID do pedstat, isto é, você pode checar se tal CHAR é prostituta, médico, bombeiro etc. Também pode ser mais útil do que GET_PED_TYPE ao checar se um CHAR é polícia, pois algumas missões do jogo policiais são criados com pedtype de personagem de missão em vez de policial. Veja o enum STAT ou arquivo "data/pedstats.dat".
GET_CHAR_MOVE_STATERetorna o estado atual de movimento do CHAR, por exemplo, parado, andando ou correndo.
DONT_DELETE_CHAR_UNTIL_TIMEAdiciona um tempo para determinado CHAR não ser deletado, em milissegundos. Por exemplo "1000" ele não será deletado automaticamente por pelo menos 1 segundo.
GET_TIME_CHAR_IS_DEADRetorna há tantos milissegundos a pessoa está morta.
GET_CHAR_FEARRetorna o valor de "medo" do char, isto é, o quão covarde ele é.
GET_MODEL_PED_TYPE_AND_STATReturna o ped type baseado no ID do modelo de um ped. Antes de usar, certifique-se de que o ID do modelo é realmente um ped, com GET_MODEL_TYPE. Isto é útil para você criar um ped mas você somente sabe do ID dele, assim, com o ID você retorna o ped type correto (se é homem, mulher etc). Lembre-se do GET_CHAR_STAT_ID para pegar o stat do CHAR em si, em vez do modelo.
Outras utilidades para CAR
GET_VEHICLE_SUBCLASSRetorna a subclass de tal veículo, assim, você pode diferenciar um veículo pelo seu tipo: se é um carro, caminhão monstro, moto, bicicleta etc. Basta utilizar os enum VEHICLE_SUBCLASS (dê uma olhada no .xml, por exemplo VEHICLE_SUBCLASS_BMX é para qualquer bicicleta).
Originalmente não era possível diferenciar uma moto de uma bicicleta, isto me deixava indignado. Agora com CLEO+ isto é finalmente possível.
GET_TRAILER_FROM_CARSério que o jogo não tinha um comando para retornar o veículo que tal veículo está puxando?
GET_CAR_FROM_TRAILERSério que o jogo não tinha um comando para retornar o veículo que está tal veículo está sendo puxado?
CAR_HORNSério que o jogo não tinha um comando pra buzinar?
SET_CAR_ALARMGET_CAR_ALARMManipular o alarme do carro, de todas as formas: você pode adicionar, e quando alguém entrar, dispara, ou disparar ou pará-lo, o mesmo para retornar, você sabe se um carro está com alarme ativo ou disparado.
GET_CAR_DUMMY_COORDRetorna o a coordenada de tal dummy. Há opção para retornar a coordenada do mundo, ou offset a partir do centro do veículo.
Nota: está pré-adaptado ao VehFuncs, quando VehFuncs adicionar funcionalidade de dummies dinâmicos! Também deverá se adaptar ao Tuning Mod numa próxima atualizar do Tuning Mod.
GET_CAR_WEAPON_DAMAGE_LAST_FRAMERetorna as informações do último dano causado por uma arma no último frame. Prefira usar junto com SET_SCRIPT_EVENT_CAR_DAMAGE visto que cada frame pode ter mais de um dano, assim com o event o funcionamento é mais confiável.
GET_CAR_COLLISION_INTENSITYGET_CAR_COLLISION_COORDINATESRetorna informações da última colisão que o carro teve. Foi indispensável para criar mods como o de ser jogado do para-brisa ou perder vida ao bater.
SET_CAR_MODEL_ALPHASeta a transparência do modelo do veículo.
SET_CAR_DOOR_WINDOW_STATEAbre ou fecha os vidros dos carros. Lembrando que eles precisam ser adaptados como os originais do jogo, simplesmente irá aparecer e desaparecer. É a mesma função que faz os vidros se fecharem nos NPCs caso esteja chovendo por exemplo.
DOES_CAR_HAVE_PART_NODECheca se tal veículo tem um node, basicamente, uma peça, entre as peças principais do jogo. Isto é muito útil para mods de tuning checarem se o carro tem escapamento, pois não há uma maneira nativa de checar se tal carro pode realmente instalar um escapamento, assim evita crash. Mas é claro, muitas outras utilidades, só não tão útil: para simplificar, só retorna peças principais que o jogo usa, não serve para utilizar literalmente qualquer peça, pois para ser útil seria muitos outros comandos, então se você quer um controle mais a fundo de cada peça do carro, use NewOpcodes.cleo ou simplesmente trabalhe com manipulação de memória.
IS_CAR_REALLY_IN_AIRRetorna verdadeiro caso o carro esteja no ar, ou seja, sem tocar no chão, de maneira confiável.
GET_CAR_PROOFSRetorna a imunidade atual do CHAR. Importante caso você esteja usando SET_CAR_PROOFS e não quera substituir as atuais.
DONT_DELETE_CAR_UNTIL_TIMEAdiciona um tempo para determinado CAR não ser deletado, em milissegundos. Por exemplo "1000" ele não será deletado automaticamente por pelo menos 1 segundo.
GET_TIME_CAR_IS_DEADRetorna há tantos milissegundos o carro está destruído.
GET_CAR_ANIMGROUPRetorna o ID do grupo de animação do veículo, inclui enum CAR_ANIMGROUP. É uma ótima maneira de entender qual é o tipo de veículo, mas evite ao máximo isto, pois pode mentir (por exemplo, isto é uma maneira de detectar que tal veículo é um caminhão, mas algum carro pode querer usar animação de caminhão, não sabemos). Se você quer usar isto para checar o tipo de veículo, só use se não há outra saída ou queira algo mais específico.
IS_CAR_OWNED_BY_PLAYERSET_CAR_OWNED_BY_PLAYERCheca e seta se algum player é "dono" de determinado veículo, isto é, ele pode entrar neste veículo sem a polícia pensar que é um roubo.
Aproveitando: para checar se um player é dono de um carro no Car Dealearship / GTA Brasil é CVehicle+0x42F 1 byte bit 7.
IS_CAR_CONVERTIBLECheca se um carro é conversível.
GET_CAR_VALUERetorna o valor monetário do carro (o quanto ele vale).
É o mesmo de GET_CAR_MODEL_VALUE, mas este retorna diretamente do handling, ou seja, mods como Tuning Mod podem alterar este valor, assim, é mais aconselhável usar este em vez de GET_CAR_MODEL_VALUE.
GET_CAR_PEDALSRetorna os valores dos pedais do veículo, isto é, acelerador e freio.
Antes que digam que "break" está escrito errado, é que gta3script ao todo é inglês britânico, portanto eu quis preservar.
Outras utilidades para OBJECT
SET_OBJECT_MODEL_ALPHASet a transparência do modelo do objeto.
GET_OBJECT_CENTRE_OF_MASS_TO_BASE_OF_MODELRetorna o offset entre o centro de massa e base do modelo. O jogo usa isto como um offset para posicionar objetos mas nunca te dá acesso ao valor.
IS_OBJECT_REALLY_IN_AIRRetorna verdadeiro caso o objeto esteja no ar, ou seja, sem tocar no chão, de maneira confiável.
GET_OBJECT_PROOFSRetorna a imunidade atual do CHAR. Importante caso você esteja usando SET_OBJECT_PROOFS e não quera substituir as atuais.
Outros
GET_ENTITY_COORDINATESGET_ENTITY_HEADINGRetorna a posição ou ângulo Z de alguma ENTITY (lembrando que o ponteiro pra um CHAR, CAR ou OBJECT é inclusive uma CEntity). Pode ser útil para retornar informações do event da BUILDING.
GET_MODEL_INFORetorna um ponteiro para o CBaseModelInfo, que pode incluir os filhos CVehicleModelInfo, CPedModelInfo, CWeaponModelInfo etc, dependente do tipo de modelo que ele é (GET_MODEL_TYPE). Muito útil para operações avançadas que requerem informações relacionadas aos modelos e não tenha comando para isto ainda.
READ_CLIPBOARD_DATA_TOWRITE_CLIPBOARD_DATA_FROMLê e escreve informações no clipboard, isto é, CTRL+C CTRL+V.
É basicamente uma cópia de memória com um tamanho limite determinado por você.
O funcionamento provavelmente é idêntico ao ClipboardCommands.cleo do Deji. É retrocompatível com ele.
GET_LOADED_LIBRARYO comando LOAD_LIBRARY carrega uma .dll, .asi, .cleo ou equivalente, não é nada legal para grande parte dos casos. Por exemplo, se você quer usar uma função de um .asi, você não quer recarregar ele, pois ele já está carregado!
Portanto, sempre considere usar este comando em vez do LOAD_LIBRARY. Também é excelente para checar se alguma .dll, .asi ou .cleo está instalado e carregado no jogo da pessoa. Por exemplo, IF GET_LOADED_LIBRARY "NewOpcodes.cleo" (i) você checa se NewOpcodes.cleo está instalado e carregado.
Retorna o ponteiro para uma biblioteca, caso exista, a condição retorna verdadeira.
RETURN_TIMESA coisa mais ilegal que vocês verão em suas vidas de programador: retorna X vezes. Sim, se você chamar 2
GOSUB, um dentro do outro, e usar RETURN_TIMES 2, retornará os dois GOSUB ao mesmo tempo.Este comando é seguro, portanto você pode usar por exemplo
RETURN_TIMES 99999 que retornará o máximo possível sem problemas.GET_CLOSEST_WATER_DISTANCERetorna a distância até o ponto de água mais próximo, e a altitude (Z) do ponto. São dois valores que o jogo calcula periodicamente para usar no som da água.
Se você tem um mod precisa ativar só caso esteja próximo da água, é altamente recomendado que, antes de fazer o seu script procurar por uma água, cheque se você está perto de uma, isto otimizará o desempenho do seu mod, pois procurar por água é um processo pesado.
GET_MODEL_NAME_POINTERVocê envia um ID de um modelo, e retornará o ponteiro para o nome dele.
Sim, só agora é possível ter acesso ao nome dos arquivos .dff do jogo! Isto porque agora CLEO+ guarda na RAM o nome de todos os modelos do jogo.
Note que se trata do ponteiro direto, não é uma cópia do nome, portanto não sobrescreva esses dados! Se precisar você pode usar
COPY_STRING ou STRING_FORMAT.WHILE TRUE, RETURN_TRUE e RETURN_FALSE
CLEO+ já inclui eles nas configurações do .xml. Foi só uma maneira de deixar o uso mais comum. Veja mais informações aqui. Lembrando que CONTINUE e BREAK precisam ser ativados na própria extensão no VSC, leia lá.