IT/Introduzione allo scripting: Difference between revisions
(New page: <!-- Tradotto da Shadd in data 23 Gennaio 2008. Ancora incompleto. --> Le ''Resources'' (Risorse) sono la parte principale di MTA. Essenzialmente, una risorsa è una cartella o un archivio...) |
mNo edit summary |
||
(34 intermediate revisions by 2 users not shown) | |||
Line 1: | Line 1: | ||
{{IT/MainP}} | |||
[[Category:100%]] | |||
[[Category:IT/Concetti di scripting]] | |||
[[Category:IT/Guide e tutorial]] | |||
Le ''Resources'' (Risorse) sono la parte principale di MTA. Essenzialmente, una risorsa è una cartella o un archivio zip che contiene una serie di files ed un file ''meta'' che contiene informazioni su come il server deve gestire la risorsa e cosa contengono i suoi componenti. Una risorsa può essere vista come uno dei programmi che girano su un sistema operativo: può essere avviata e fermata, e più risorse possono essere eseguite contemporaneamente. | Le ''Resources'' (Risorse) sono la parte principale di MTA. Essenzialmente, una risorsa è una cartella o un archivio zip che contiene una serie di files ed un file ''meta'' che contiene informazioni su come il server deve gestire la risorsa e cosa contengono i suoi componenti. Una risorsa può essere vista come uno dei programmi che girano su un sistema operativo: può essere avviata e fermata, e più risorse possono essere eseguite contemporaneamente. | ||
Line 25: | Line 27: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
===Scrivere | ===Scrivere uno script=== | ||
Iniziamo a scrivere il contenuto del file ''script.lua''. Come sopra, vogliamo creare un comando per spawnare un veicolo nella posizione di chi esegue il comando stesso. Prima di tutto dobbiamo creare una funzione che possa essere eseguita all'esecuzione dello script, ed un ''command handler'' che dica al gioco di eseguire la nostra funzione quando il nostro comando viene chiamato. | Iniziamo a scrivere il contenuto del file ''script.lua''. Come sopra, vogliamo creare un comando per spawnare un veicolo nella posizione di chi esegue il comando stesso. Prima di tutto dobbiamo creare una funzione che possa essere eseguita all'esecuzione dello script, ed un ''command handler'' che dica al gioco di eseguire la nostra funzione quando il nostro comando viene chiamato. | ||
<syntaxhighlight lang="lua"> | <syntaxhighlight lang="lua"> | ||
-- Creiamo la funzione per spawnare un nuovo veicolo, con gli argomenti | -- Creiamo la funzione per spawnare un nuovo veicolo, con gli argomenti "thePlayer", "command" e "vehicle" | ||
function createVehicleForPlayer(thePlayer, command, vehicle) | function createVehicleForPlayer(thePlayer, command, vehicle) | ||
-- Qui metteremo le funzioni per creare il veicolo, ottenere la posizione del giocatore eccetera | -- Qui metteremo le funzioni per creare il veicolo, ottenere la posizione del giocatore eccetera | ||
end | end | ||
-- Creiamo quindi il | -- Creiamo quindi il "command handler" | ||
addCommandHandler("createvehicle", createVehicleForPlayer) | addCommandHandler("createvehicle", createVehicleForPlayer) | ||
</syntaxhighlight> | </syntaxhighlight> | ||
''Nota: Negli esempi di script i nomi delle funzioni sono dei link che portano alla relativa pagina per informazioni sulla funzione stessa.'' | ''Nota: Negli esempi di script i nomi delle funzioni sono dei link che portano alla relativa pagina per informazioni sulla funzione stessa.'' | ||
==== | ====A proposito dei command handlers==== | ||
Il primo argomento della funzione [[IT/addCommandHandler|addCommandHandler]] è il nome del comando che il giocatore dovrà eseguire, il secondo argomento è invece la funzione che il comando attiverà, nell'esempio sopra ''createVehicleForPlayer''. | |||
Se hai già un'esperienza di base nello scripting o nella programmazione, saprai già che una funzione si chiama nel seguente modo: | |||
<syntaxhighlight lang="lua"> | <syntaxhighlight lang="lua"> | ||
nomeFunzione(argomento1, argomento2, argomento3, ...) | |||
</syntaxhighlight> | </syntaxhighlight> | ||
Abbiamo infatti chiamato la funzione [[IT/addCommandHandler|addCommandHandler]] in questo modo, e dato che anche ''createVehicleForPlayer'' è una funzione, può essere anche lei chiamata in tale modo. Ma stiamo invece utilizzando un command handler, che la chiama in modo simile internamente ad MTA. | |||
Ad esempio: se qualcuno durante il gioco scrivesse "createvehicle 468" nella console per spawnare una Sanchez, il command handler chiamerebbe la funzione createVehicleForPlayer, come se avessimo avuto questa riga di codice nello script: | |||
<syntaxhighlight lang="lua"> | <syntaxhighlight lang="lua"> | ||
createVehicleForPlayer(thePlayer,"createvehicle","468") -- thePlayer | createVehicleForPlayer(thePlayer,"createvehicle","468") -- thePlayer è l'identificatore del giocatore che ha chiamato la funzione | ||
</syntaxhighlight> | </syntaxhighlight> | ||
Come possiamo vedere, contiene diversi argomenti: il giocatore che ha chiamato il comando, il comando che ha chiamato e tutto ciò che ha scritto dopo di esso, in questo caso "468" come ID per il veicolo da spawnare, una Sanchez. I primi due parametri sono gli stessi in tutti i command handlers, come puoi vedere nella pagina [[IT/addEventHandler|addEventHandler]]. Per questo, devi per forza definire almeno questi due parametri prima che MTA possa riconoscerne altri aggiuntivi(ad esempio, in questo caso, l'ID del veicolo). | |||
'' | ''Nota: Puoi creare un command handler solo DOPO aver creato la funzione che l'handler chiamerà, altrimenti MTA non troverà la funzione e non potrà quindi eseguirla.'' | ||
==== | ====Programmare la funzione==== | ||
Prima di creare la funzione che utilizzeremo per il comando, dobbiamo pensare a cosa abbiamo in mente di fare: | |||
* | * Memorizzare la posizione del giocatore, in modo da sapere dove far spawnare il veicolo (vogliamo che gli appaia vicino); | ||
* | * Calcolare la posizione in cui far spawnare il veicolo (non vogliamo che appaia ''addosso'' al giocatore); | ||
* | * Spawnare il veicolo; | ||
* | * Controllare se l'operazione ha avuto successo, altrimenti inviare un messaggio di errore. | ||
Per raggiungere i nostri obiettivi dovremo usare molte funzioni. Per capire quali funzioni usare, andiamo alla [[IT/Funzioni Server-side|Lista funzioni Server-side]]. Innanzitutto ci serve una funzione per ottenere la posizione del giocatore. Dato che i giocatori sono conteggiati come ''Elements''(Elementi), andiamo alla sezione '''Funzioni sugli elementi''' dove troveremo la funzione [[IT/getElementPosition|getElementPosition]]. Cliccando il nome della funzione nella lista raggiungeremo la pagina sui dettagli, dove potremo vedere la sintassi, un esempio di uso e il valore che la funzione ritorna. La sintassi ci mostra quali parametri possiamo o dobbiamo inserire nella funzione. | |||
Per la funzione [[IT/getElementPosition|getElementPosition]], la sintassi è: | |||
<syntaxhighlight lang="lua"> | <syntaxhighlight lang="lua"> | ||
float, float, float getElementPosition ( element theElement ) | float, float, float getElementPosition ( element theElement ) | ||
</syntaxhighlight> | </syntaxhighlight> | ||
I tre ''float'' prima del nome della funzione sono i tipi di valore che essa ritorna, in questo caso tre numeri decimali. Dentro le parentesi possiamo invece vedere gli elementi che la funzione accetta, in questo caso solo l'elemento del quale vogliamo conoscere la posizione. | |||
<syntaxhighlight lang="lua"> | <syntaxhighlight lang="lua"> | ||
function createVehicleForPlayer(thePlayer, command, vehicleModel) | function createVehicleForPlayer(thePlayer, command, vehicleModel) | ||
-- | -- Ottiene le coordinate del giocatore e le memorizza nelle variabili x,y,z. | ||
-- (local | -- (local indica che le variabili esisteranno solo all'interno dello ''scope'' corrente, in questo caso, la funzione) | ||
local x,y,z = getElementPosition(thePlayer) | local x,y,z = getElementPosition(thePlayer) | ||
end | end | ||
</syntaxhighlight> | </syntaxhighlight> | ||
Ora, vogliamo assicurarci che il veicolo non compaia direttamente sopra o nel giocatore, aggiungeremo quindi qualche unità alla variabile ''x'', in modo da farlo comparire un pò più ad est del giocatore. | |||
<syntaxhighlight lang="lua"> | <syntaxhighlight lang="lua"> | ||
function createVehicleForPlayer(thePlayer, command, vehicleModel) | function createVehicleForPlayer(thePlayer, command, vehicleModel) | ||
local x,y,z = getElementPosition(thePlayer) -- | local x,y,z = getElementPosition(thePlayer) -- otteniamo la posizione del giocatore | ||
x = x + 5 -- | x = x + 5 -- aggiungiamo 5 unità alla variabile x | ||
end | end | ||
</syntaxhighlight> | </syntaxhighlight> | ||
Ora abbiamo bisogno di un'altra funzione, che ci permetta di spawnare il veicolo. Cerchiamola nuovamente nella [[IT/Funzioni Server-side|Lista funzioni Server-side]], questa volta tra le '''Funzioni per veicoli''', dove sceglieremo [[IT/createVehicle|createVehicle]]. Nella sintassi di questa funzione abbiamo solo un valore di ritorno (più comune rispetto alle funzioni che ritornano più di un valore), cioé un elemento veicolo che indica il veicolo che abbiamo appena creato con la funzione stessa. Inoltre, vediamo che alcuni elementi si trovano tra parentesi quadre, ad indicare che essi sono opzionali. | |||
Abbiamo già tutti gli elementi che ci servono per chiamare [[IT/createVehicle|createVehicle]] nella nostra funzione: le coordinate che abbiamo memorizzato nelle variabili ''x,y,z'' e l'ID del veicolo che vogliamo chiamare, ottenuto tramite il comando ("createvehicle 468") ed a cui possiamo accedere tramite la variabile locale ''vehicleModel'' | |||
<syntaxhighlight lang="lua"> | <syntaxhighlight lang="lua"> | ||
function createVehicleForPlayer(thePlayer, command, vehicleModel) | function createVehicleForPlayer(thePlayer, command, vehicleModel) | ||
local x,y,z = getElementPosition(thePlayer) -- | local x,y,z = getElementPosition(thePlayer) -- otteniamo la posizione del giocatore | ||
x = x + 5 -- | x = x + 5 -- aggiungiamo 5 unità alla variabile x | ||
-- | -- creiamo il veicolo e lo memorizziamo nella variabile ''createdVehicle'' | ||
local createdVehicle = createVehicle(tonumber(vehicleModel),x,y,z) | local createdVehicle = createVehicle(tonumber(vehicleModel),x,y,z) | ||
end | end | ||
</syntaxhighlight> | </syntaxhighlight> | ||
Ovviamente questo codice otrebbe essere migliorato in molti modi, ma per il momento ci limiteremo ad aggiungere un controllo per verificare che il veicolo sia stato creato correttamente. Come possiamo leggere nella pagina [[IT/createVehicle|createVehicle]] sotto '''Valori di ritorno''', la funzione restituisce ''false'' quando non riesce a creare il veicolo. Controlleremo quindi il valore della variabile ''createVehicle''. | |||
Ecco il nostro script completo: | |||
<syntaxhighlight lang="lua"> | <syntaxhighlight lang="lua"> | ||
function createVehicleForPlayer(thePlayer, command, vehicleModel) | function createVehicleForPlayer(thePlayer, command, vehicleModel) | ||
local x,y,z = getElementPosition(thePlayer) -- | local x,y,z = getElementPosition(thePlayer) -- otteniamo la posizione del giocatore | ||
x = x + 5 -- | x = x + 5 -- aggiungiamo 5 unità alla variabile x | ||
local createdVehicle = createVehicle(tonumber(vehicleModel),x,y,z) | local createdVehicle = createVehicle(tonumber(vehicleModel),x,y,z) | ||
-- | -- controlliamo se la funzione ha restituito valore "false" | ||
if (createdVehicle == false) then | if (createdVehicle == false) then | ||
-- | -- se si, inviamo un messaggio nella chat, ma solo al giocatore che ha chiamato il comando. | ||
outputChatBox(" | outputChatBox("Fallimento nella creazione del veicolo.",thePlayer) | ||
end | end | ||
end | end | ||
Line 120: | Line 122: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
Come possiamo vedere, abbiamo inserito una nuova funzione: [[IT/outputChatBox|outputChatBox]]. Adesso dovresti essere in grado di navigare tra le funzioni e documentarti su di esse da te. | |||
== | ==Cosa c'è da sapere== | ||
Abbiamo già letto qualcosa sulle ''resources'', sui command handlers e sulle funzioni nel primo paragrafo, ma c'è ancora molto da imparare. Questa sezione ti darà qualche delucidazione su alcuni altri elementi del LUA, e dove possibile ti verranno linkate le pagine sugli argomenti in questione. | |||
=== | ===Scripts client-side e scripts server-side=== | ||
Avrai probabilmente già sentito i termini Server e Client da qualche parte in questa wiki, soprattutto parlando delle funzioni. MTA non supporta solo funzioni o comandi (come quello visto sopra) che funzionano su server, ma anche scripts che vengono eseguiti dal client di MTA. Il motivo di ciò è che alcune funzioni che MTA fornisce (come l'interfaccia grafica, la ''GUI'' - Graphical User Interface) possono essere eseguite solo dal client. | |||
La maggior parte degli scripts che creerai (gamemodes, e mappe) saranno probabilmente server-side, come quello che abbiamo creato nella sezione precedente. Se però ti imbatterai in qualcosa che non funzionerà sul server, dovrai ricorrere agli script client-side. Per creare uno script client-side devi creare un nuovo file .lua (ad esempio ''client.lua''), come per quelli server-side e specificarlo nel ''meta.xml'', in questo modo: | |||
<syntaxhighlight lang="xml"> | <syntaxhighlight lang="xml"> | ||
<script src="client.lua" type="client" /> | <script src="client.lua" type="client" /> | ||
</syntaxhighlight> | </syntaxhighlight> | ||
L'attributo ''type'' di default è impostato sempre a ''server'', quindi avrai bisogno di specificarlo solo per gli script client-side. Quando fai ciò, lo script viene scaricato nel PC del client quando esso si connette al server. Per saperne di più vedi la [[IT/Funzioni Client-side|Lista funzioni Client-side]]. | |||
=== | ===Script più complessi=== | ||
La sezione precedente spiegava in breve come aggiungere script client-side alla ''Resource'', ma si può fare molto di più. Come è spiegato a inizio pagina, con le ''resource'' si può fare praticamente tutto. Il loro scopo dipende semplicemente da ciò che fanno. Prendiamo alcune ''resource'' d'esempio, esaminando i file che contengono, il ''meta.xml'' e cosa dovrebbero fare: | |||
==== | ====Primo esempio - Un ''utility'' script==== | ||
<syntaxhighlight lang="xml"> | <syntaxhighlight lang="xml"> | ||
/ | /comandi_admin | ||
/meta.xml | /meta.xml | ||
/ | /comandi.lua | ||
/client.lua | /client.lua | ||
</syntaxhighlight> | </syntaxhighlight> | ||
<syntaxhighlight lang="xml"> | <syntaxhighlight lang="xml"> | ||
<meta> | <meta> | ||
<info author=" | <info author="Qualcuno" description="Comandi admin" /> | ||
<script src=" | <script src="comandi.lua" /> | ||
<script src="client.lua" type="client" /> | <script src="client.lua" type="client" /> | ||
</meta> | </meta> | ||
</syntaxhighlight> | </syntaxhighlight> | ||
* | * ''comandi.lua'' contiene dei comandi che un admin potrà usare nel suo server per bannare i players, mutarli, o qualsiasi altra cosa | ||
* | * ''client.lua'' contiene una finestra GUI per rendere tutto più gradevole alla vista e, soprattutto, agevole | ||
Questo script di esempio potrebbe restare sempre attivo (magari anche auto-avviato allo ''startup'' del server) perchè è utile durante ogni fase di gioco e non interferisce con la gamemode, a meno che un admin decida di togliere alcune azioni, ovviamente. | |||
==== | ====Secondo esempio - Una gamemode==== | ||
<syntaxhighlight lang="xml"> | <syntaxhighlight lang="xml"> | ||
/counterstrike | /counterstrike | ||
Line 165: | Line 167: | ||
<syntaxhighlight lang="xml"> | <syntaxhighlight lang="xml"> | ||
<meta> | <meta> | ||
<info author=" | <info author="Qualcuno" description="Counterstrike remake" type="gamemode" /> | ||
<script src="counterstrike.lua" /> | <script src="counterstrike.lua" /> | ||
<script src="buymenu.lua" type="client" /> | <script src="buymenu.lua" type="client" /> | ||
Line 171: | Line 173: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
* | * ''counterstrike.lua'' contiene ''features'' simili a queste: | ||
** | ** Far scegliere ai players il loro team e spawnarli | ||
** | ** Dargli delle armi, e assegnarli degli obiettivi, magari con una mappa (vedi sotto) | ||
** | ** Definire le regole del gioco, per esempio quando finisce un round o cosa succede quando un player muore | ||
** .. | ** .. e magari qualcos'altro | ||
* | * ''buymenu.lua'' è uno script client-side e crea un menu GUI per comprare le armi | ||
Questo esempio può essere chiamato ''gamemode'' perchè non solo interferisce con il gioco, ma ne detta anche le regole. L'attributo ''type'' indica che questo esempio funzionerà con il [[IT/Map manager|Map manager]], un'altra ''resource'' ancora creata dal QA team per gestire le gamemode e le mappe a loro associate. È fortemente raccomandato basare la gamemode sulle tecniche che il Map Manager fornisce. | |||
Ciò significa anche che la gamemode probabilmente non girerà senza una mappa. Le gamemode, infatti, dovrebbero essere più generiche possibile. Un esempio per una mappa si può trovare qui sotto. | |||
==== | ====Terzo esempio - Una mappa==== | ||
<syntaxhighlight lang="xml"> | <syntaxhighlight lang="xml"> | ||
/cs-airport | /cs-airport | ||
Line 191: | Line 193: | ||
<syntaxhighlight lang="xml"> | <syntaxhighlight lang="xml"> | ||
<meta> | <meta> | ||
<info author=" | <info author="Qualcuno" description="Counterstrike airport map" type="map" gamemodes="counterstrike" /> | ||
<map src="airport.map" /> | <map src="airport.map" /> | ||
<script src="airport.lua" /> | <script src="airport.lua" /> | ||
Line 197: | Line 199: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
* | * ''airport.map'' è un file XML che fornisce alla mode informazioni sulla mappa, come: | ||
** | ** I punti di spawn dei players, le loro armi, i team | ||
** | ** Gli obiettivi | ||
** | ** Il tempo atmosferico, l'ora del giorno, il limite di tempo | ||
** | ** I veicoli e gli oggetti | ||
* | * ''airport.lua'' potrebbe contenere alcune ''feature'' specifiche di una mappa: | ||
** | ** Aprire una porta/fare qualcosa di speciale quando accade un evento particolare | ||
** | ** Creare e muovere oggetti personalizzati, o manipolare gli oggetti creati con il file .map | ||
** .. | ** .. qualunque altra cosa specifica di una mappa | ||
Come potete vedere, l'attributo ''type'' è diventato 'map', per avvertire il [[IT/Map manager|Map manager]] che questa ''resource'' è una mappa, mentre l'attributo ''gamemodes'' imposta le gamemode compatibili con questa mappa, in questo caso la gamemode dell'esempio precedente. | |||
Ciò che potrebbe sembrare strano è uno script LUA in una mappa. Ovviamente non sempre serve, ma offre a chi crea una mappa la possibilità di creare un vero e proprio mondo con le regole imposte dalla gamemode. | |||
Il file ''airport.map'' potrebbe somigliare a questo: | |||
<syntaxhighlight lang="xml"> | <syntaxhighlight lang="xml"> | ||
<map mode="deathmatch" version="1.0"> | <map mode="deathmatch" version="1.0"> | ||
Line 227: | Line 229: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
Quando una gamemode con una mappa compatibile è avviata, la ''resource'' della mappa viene automaticamente avviata dal mapmanager, che permette alla gamemode di ''leggere'' le informazioni che contiene. Quando la mappa cambia, la ''resource'' della mappa precedente viene fermata automaticamente e viene avviata quella successiva. | |||
=== | ===Eventi=== | ||
Gli eventi sono il mezzo con cui MTA comunica agli script ciò che sta accadendo nel gioco. Per esempio, quando un player muore, viene chiamato l'evento [[IT/onPlayerWasted|onPlayerWasted]]. Per eseguire qualsiasi azione quando un player muore, devi imparare a creare degli ''event handlers'', com'è spiegato nel [[#Scrivere uno script|primo capitolo]]. | |||
Questo esempio scriverà nella chatbox il nome del player che è morto: | |||
<syntaxhighlight lang="lua"> | <syntaxhighlight lang="lua"> | ||
function playerDied(totalAmmo, killer, killerWeapon, bodypart) | function playerDied(totalAmmo, killer, killerWeapon, bodypart) | ||
outputChatBox( | outputChatBox(getPlayerName(source).." è morto!") | ||
end | end | ||
addEventHandler("onPlayerWasted",getRootElement(),playerDied) | addEventHandler("onPlayerWasted",getRootElement(),playerDied) | ||
</syntaxhighlight> | </syntaxhighlight> | ||
Al posto di mostrare quali argomenti servono, la pagina di documentazione per gli eventi mostra quali parametri sono passati alla funzione a cui un evento è ''legato'' (come playerDied nell'esempio di prima), come fa un [[#A proposito dei command handlers|command handler]], solo che è diverso da evento a evento. Un altro punto importante è la variabile ''source'', che si trova nelle funzioni chiamate da un ''event handler''. Non ha bisogno di essere aggiunto nella lista di parametri della funzione, ma esiste lo stesso. Ha valori differenti da evento a evento, per gli eventi che riguardano un player (come nell'esempio di sopra) di solito è l'elemento ''player''. | |||
== | ==Cosa fare dopo== | ||
Ora dovresti essere pratico con le basi dello scripting per MTA e anche un po' con la documentazione. La [[IT/Pagina principale|Pagina principale]] ti fornisce link a informazioni, tutorial e riferimenti che permettono di scoprire più a fondo gli argomenti che vuoi imparare. | |||
[[ru:Scripting Introduction]] | [[ru:Scripting Introduction]] | ||
[[en:Scripting Introduction]] |
Latest revision as of 12:30, 27 August 2009
Le Resources (Risorse) sono la parte principale di MTA. Essenzialmente, una risorsa è una cartella o un archivio zip che contiene una serie di files ed un file meta che contiene informazioni su come il server deve gestire la risorsa e cosa contengono i suoi componenti. Una risorsa può essere vista come uno dei programmi che girano su un sistema operativo: può essere avviata e fermata, e più risorse possono essere eseguite contemporaneamente.
Tutto ciò che ha a che fare con lo scripting avviene nelle risorse, ciò che una risorsa fà dipende da se si tratta di una gamemode, una mappa o qualsiasi altra cosa.
Creare un semplice script
Innanzitutto, mettiamo caso volessimo creare uno script per aggiungere un comando 'createvehicle' che i giocatori possano usare per far spawnare un veicolo alla loro attuale posizione.
Preparazione
Come detto sopra, una risorsa è una cartella o un archivio zip, quindi prima di tutto dovremo creare una cartella. Il nome della cartella è il nome della risorsa, che viene usato per avviarla o fermarla o come riferimento negli script. Nel nostro esempio la chiameremo commands.
Ciò di cui qualsiasi risorsa ha bisogno è il file meta.xml. Nel nostro caso, vogliamo creare uno script che fornisca determinati comandi ad un giocatore, dobbiamo quindi dire al server di caricare il nostro script, che chiameremo script.lua.
Ecco il contenuto del nostro file meta.xml:
<meta> <info author="TuoNome" description="Alcuni semplici comandi" /> <script src="script.lua" /> </meta>
Creiamo ora il file che conterrà il nostro script: script.lua, nella stessa cartella di meta.xml. Adesso abbiamo i seguenti files:
/commands/meta.xml /commands/script.lua
Scrivere uno script
Iniziamo a scrivere il contenuto del file script.lua. Come sopra, vogliamo creare un comando per spawnare un veicolo nella posizione di chi esegue il comando stesso. Prima di tutto dobbiamo creare una funzione che possa essere eseguita all'esecuzione dello script, ed un command handler che dica al gioco di eseguire la nostra funzione quando il nostro comando viene chiamato.
-- Creiamo la funzione per spawnare un nuovo veicolo, con gli argomenti "thePlayer", "command" e "vehicle" function createVehicleForPlayer(thePlayer, command, vehicle) -- Qui metteremo le funzioni per creare il veicolo, ottenere la posizione del giocatore eccetera end -- Creiamo quindi il "command handler" addCommandHandler("createvehicle", createVehicleForPlayer)
Nota: Negli esempi di script i nomi delle funzioni sono dei link che portano alla relativa pagina per informazioni sulla funzione stessa.
A proposito dei command handlers
Il primo argomento della funzione addCommandHandler è il nome del comando che il giocatore dovrà eseguire, il secondo argomento è invece la funzione che il comando attiverà, nell'esempio sopra createVehicleForPlayer.
Se hai già un'esperienza di base nello scripting o nella programmazione, saprai già che una funzione si chiama nel seguente modo:
nomeFunzione(argomento1, argomento2, argomento3, ...)
Abbiamo infatti chiamato la funzione addCommandHandler in questo modo, e dato che anche createVehicleForPlayer è una funzione, può essere anche lei chiamata in tale modo. Ma stiamo invece utilizzando un command handler, che la chiama in modo simile internamente ad MTA.
Ad esempio: se qualcuno durante il gioco scrivesse "createvehicle 468" nella console per spawnare una Sanchez, il command handler chiamerebbe la funzione createVehicleForPlayer, come se avessimo avuto questa riga di codice nello script:
createVehicleForPlayer(thePlayer,"createvehicle","468") -- thePlayer è l'identificatore del giocatore che ha chiamato la funzione
Come possiamo vedere, contiene diversi argomenti: il giocatore che ha chiamato il comando, il comando che ha chiamato e tutto ciò che ha scritto dopo di esso, in questo caso "468" come ID per il veicolo da spawnare, una Sanchez. I primi due parametri sono gli stessi in tutti i command handlers, come puoi vedere nella pagina addEventHandler. Per questo, devi per forza definire almeno questi due parametri prima che MTA possa riconoscerne altri aggiuntivi(ad esempio, in questo caso, l'ID del veicolo).
Nota: Puoi creare un command handler solo DOPO aver creato la funzione che l'handler chiamerà, altrimenti MTA non troverà la funzione e non potrà quindi eseguirla.
Programmare la funzione
Prima di creare la funzione che utilizzeremo per il comando, dobbiamo pensare a cosa abbiamo in mente di fare:
- Memorizzare la posizione del giocatore, in modo da sapere dove far spawnare il veicolo (vogliamo che gli appaia vicino);
- Calcolare la posizione in cui far spawnare il veicolo (non vogliamo che appaia addosso al giocatore);
- Spawnare il veicolo;
- Controllare se l'operazione ha avuto successo, altrimenti inviare un messaggio di errore.
Per raggiungere i nostri obiettivi dovremo usare molte funzioni. Per capire quali funzioni usare, andiamo alla Lista funzioni Server-side. Innanzitutto ci serve una funzione per ottenere la posizione del giocatore. Dato che i giocatori sono conteggiati come Elements(Elementi), andiamo alla sezione Funzioni sugli elementi dove troveremo la funzione getElementPosition. Cliccando il nome della funzione nella lista raggiungeremo la pagina sui dettagli, dove potremo vedere la sintassi, un esempio di uso e il valore che la funzione ritorna. La sintassi ci mostra quali parametri possiamo o dobbiamo inserire nella funzione.
Per la funzione getElementPosition, la sintassi è:
float, float, float getElementPosition ( element theElement )
I tre float prima del nome della funzione sono i tipi di valore che essa ritorna, in questo caso tre numeri decimali. Dentro le parentesi possiamo invece vedere gli elementi che la funzione accetta, in questo caso solo l'elemento del quale vogliamo conoscere la posizione.
function createVehicleForPlayer(thePlayer, command, vehicleModel) -- Ottiene le coordinate del giocatore e le memorizza nelle variabili x,y,z. -- (local indica che le variabili esisteranno solo all'interno dello ''scope'' corrente, in questo caso, la funzione) local x,y,z = getElementPosition(thePlayer) end
Ora, vogliamo assicurarci che il veicolo non compaia direttamente sopra o nel giocatore, aggiungeremo quindi qualche unità alla variabile x, in modo da farlo comparire un pò più ad est del giocatore.
function createVehicleForPlayer(thePlayer, command, vehicleModel) local x,y,z = getElementPosition(thePlayer) -- otteniamo la posizione del giocatore x = x + 5 -- aggiungiamo 5 unità alla variabile x end
Ora abbiamo bisogno di un'altra funzione, che ci permetta di spawnare il veicolo. Cerchiamola nuovamente nella Lista funzioni Server-side, questa volta tra le Funzioni per veicoli, dove sceglieremo createVehicle. Nella sintassi di questa funzione abbiamo solo un valore di ritorno (più comune rispetto alle funzioni che ritornano più di un valore), cioé un elemento veicolo che indica il veicolo che abbiamo appena creato con la funzione stessa. Inoltre, vediamo che alcuni elementi si trovano tra parentesi quadre, ad indicare che essi sono opzionali.
Abbiamo già tutti gli elementi che ci servono per chiamare createVehicle nella nostra funzione: le coordinate che abbiamo memorizzato nelle variabili x,y,z e l'ID del veicolo che vogliamo chiamare, ottenuto tramite il comando ("createvehicle 468") ed a cui possiamo accedere tramite la variabile locale vehicleModel
function createVehicleForPlayer(thePlayer, command, vehicleModel) local x,y,z = getElementPosition(thePlayer) -- otteniamo la posizione del giocatore x = x + 5 -- aggiungiamo 5 unità alla variabile x -- creiamo il veicolo e lo memorizziamo nella variabile ''createdVehicle'' local createdVehicle = createVehicle(tonumber(vehicleModel),x,y,z) end
Ovviamente questo codice otrebbe essere migliorato in molti modi, ma per il momento ci limiteremo ad aggiungere un controllo per verificare che il veicolo sia stato creato correttamente. Come possiamo leggere nella pagina createVehicle sotto Valori di ritorno, la funzione restituisce false quando non riesce a creare il veicolo. Controlleremo quindi il valore della variabile createVehicle.
Ecco il nostro script completo:
function createVehicleForPlayer(thePlayer, command, vehicleModel) local x,y,z = getElementPosition(thePlayer) -- otteniamo la posizione del giocatore x = x + 5 -- aggiungiamo 5 unità alla variabile x local createdVehicle = createVehicle(tonumber(vehicleModel),x,y,z) -- controlliamo se la funzione ha restituito valore "false" if (createdVehicle == false) then -- se si, inviamo un messaggio nella chat, ma solo al giocatore che ha chiamato il comando. outputChatBox("Fallimento nella creazione del veicolo.",thePlayer) end end addCommandHandler("createvehicle", createVehicleForPlayer)
Come possiamo vedere, abbiamo inserito una nuova funzione: outputChatBox. Adesso dovresti essere in grado di navigare tra le funzioni e documentarti su di esse da te.
Cosa c'è da sapere
Abbiamo già letto qualcosa sulle resources, sui command handlers e sulle funzioni nel primo paragrafo, ma c'è ancora molto da imparare. Questa sezione ti darà qualche delucidazione su alcuni altri elementi del LUA, e dove possibile ti verranno linkate le pagine sugli argomenti in questione.
Scripts client-side e scripts server-side
Avrai probabilmente già sentito i termini Server e Client da qualche parte in questa wiki, soprattutto parlando delle funzioni. MTA non supporta solo funzioni o comandi (come quello visto sopra) che funzionano su server, ma anche scripts che vengono eseguiti dal client di MTA. Il motivo di ciò è che alcune funzioni che MTA fornisce (come l'interfaccia grafica, la GUI - Graphical User Interface) possono essere eseguite solo dal client.
La maggior parte degli scripts che creerai (gamemodes, e mappe) saranno probabilmente server-side, come quello che abbiamo creato nella sezione precedente. Se però ti imbatterai in qualcosa che non funzionerà sul server, dovrai ricorrere agli script client-side. Per creare uno script client-side devi creare un nuovo file .lua (ad esempio client.lua), come per quelli server-side e specificarlo nel meta.xml, in questo modo:
<script src="client.lua" type="client" />
L'attributo type di default è impostato sempre a server, quindi avrai bisogno di specificarlo solo per gli script client-side. Quando fai ciò, lo script viene scaricato nel PC del client quando esso si connette al server. Per saperne di più vedi la Lista funzioni Client-side.
Script più complessi
La sezione precedente spiegava in breve come aggiungere script client-side alla Resource, ma si può fare molto di più. Come è spiegato a inizio pagina, con le resource si può fare praticamente tutto. Il loro scopo dipende semplicemente da ciò che fanno. Prendiamo alcune resource d'esempio, esaminando i file che contengono, il meta.xml e cosa dovrebbero fare:
Primo esempio - Un utility script
/comandi_admin /meta.xml /comandi.lua /client.lua
<meta> <info author="Qualcuno" description="Comandi admin" /> <script src="comandi.lua" /> <script src="client.lua" type="client" /> </meta>
- comandi.lua contiene dei comandi che un admin potrà usare nel suo server per bannare i players, mutarli, o qualsiasi altra cosa
- client.lua contiene una finestra GUI per rendere tutto più gradevole alla vista e, soprattutto, agevole
Questo script di esempio potrebbe restare sempre attivo (magari anche auto-avviato allo startup del server) perchè è utile durante ogni fase di gioco e non interferisce con la gamemode, a meno che un admin decida di togliere alcune azioni, ovviamente.
Secondo esempio - Una gamemode
/counterstrike /meta.xml /counterstrike.lua /buymenu.lua
<meta> <info author="Qualcuno" description="Counterstrike remake" type="gamemode" /> <script src="counterstrike.lua" /> <script src="buymenu.lua" type="client" /> </meta>
- counterstrike.lua contiene features simili a queste:
- Far scegliere ai players il loro team e spawnarli
- Dargli delle armi, e assegnarli degli obiettivi, magari con una mappa (vedi sotto)
- Definire le regole del gioco, per esempio quando finisce un round o cosa succede quando un player muore
- .. e magari qualcos'altro
- buymenu.lua è uno script client-side e crea un menu GUI per comprare le armi
Questo esempio può essere chiamato gamemode perchè non solo interferisce con il gioco, ma ne detta anche le regole. L'attributo type indica che questo esempio funzionerà con il Map manager, un'altra resource ancora creata dal QA team per gestire le gamemode e le mappe a loro associate. È fortemente raccomandato basare la gamemode sulle tecniche che il Map Manager fornisce.
Ciò significa anche che la gamemode probabilmente non girerà senza una mappa. Le gamemode, infatti, dovrebbero essere più generiche possibile. Un esempio per una mappa si può trovare qui sotto.
Terzo esempio - Una mappa
/cs-airport /meta.xml /airport.map /airport.lua
<meta> <info author="Qualcuno" description="Counterstrike airport map" type="map" gamemodes="counterstrike" /> <map src="airport.map" /> <script src="airport.lua" /> </meta>
- airport.map è un file XML che fornisce alla mode informazioni sulla mappa, come:
- I punti di spawn dei players, le loro armi, i team
- Gli obiettivi
- Il tempo atmosferico, l'ora del giorno, il limite di tempo
- I veicoli e gli oggetti
- airport.lua potrebbe contenere alcune feature specifiche di una mappa:
- Aprire una porta/fare qualcosa di speciale quando accade un evento particolare
- Creare e muovere oggetti personalizzati, o manipolare gli oggetti creati con il file .map
- .. qualunque altra cosa specifica di una mappa
Come potete vedere, l'attributo type è diventato 'map', per avvertire il Map manager che questa resource è una mappa, mentre l'attributo gamemodes imposta le gamemode compatibili con questa mappa, in questo caso la gamemode dell'esempio precedente. Ciò che potrebbe sembrare strano è uno script LUA in una mappa. Ovviamente non sempre serve, ma offre a chi crea una mappa la possibilità di creare un vero e proprio mondo con le regole imposte dalla gamemode.
Il file airport.map potrebbe somigliare a questo:
<map mode="deathmatch" version="1.0"> <terrorists> <spawnpoint posX="2332.23" posY="-12232.33" posZ="4.42223" skins="23-40" /> </terrorists> <counterterrorists> <spawnpoint posX="2334.23443" posY="-12300.233" posZ="10.2344" skins="40-50" /> </counterterrorists> <bomb posX="23342.23" posY="" posZ="" /> <vehicle posX="" posY="" posZ="" model="602" /> <vehicle posX="" posY="" posZ="" model="603" /> </map>
Quando una gamemode con una mappa compatibile è avviata, la resource della mappa viene automaticamente avviata dal mapmanager, che permette alla gamemode di leggere le informazioni che contiene. Quando la mappa cambia, la resource della mappa precedente viene fermata automaticamente e viene avviata quella successiva.
Eventi
Gli eventi sono il mezzo con cui MTA comunica agli script ciò che sta accadendo nel gioco. Per esempio, quando un player muore, viene chiamato l'evento onPlayerWasted. Per eseguire qualsiasi azione quando un player muore, devi imparare a creare degli event handlers, com'è spiegato nel primo capitolo.
Questo esempio scriverà nella chatbox il nome del player che è morto:
function playerDied(totalAmmo, killer, killerWeapon, bodypart) outputChatBox(getPlayerName(source).." è morto!") end addEventHandler("onPlayerWasted",getRootElement(),playerDied)
Al posto di mostrare quali argomenti servono, la pagina di documentazione per gli eventi mostra quali parametri sono passati alla funzione a cui un evento è legato (come playerDied nell'esempio di prima), come fa un command handler, solo che è diverso da evento a evento. Un altro punto importante è la variabile source, che si trova nelle funzioni chiamate da un event handler. Non ha bisogno di essere aggiunto nella lista di parametri della funzione, ma esiste lo stesso. Ha valori differenti da evento a evento, per gli eventi che riguardano un player (come nell'esempio di sopra) di solito è l'elemento player.
Cosa fare dopo
Ora dovresti essere pratico con le basi dello scripting per MTA e anche un po' con la documentazione. La Pagina principale ti fornisce link a informazioni, tutorial e riferimenti che permettono di scoprire più a fondo gli argomenti che vuoi imparare.