GTA-Expert Forum: Creare un sistema veicoli RP in Y_Ini - GTA-Expert Forum

Salta al contenuto

Pagina 1 di 1
  • Non puoi iniziare una nuova discussione
  • Non puoi rispondere a questa discussione

Creare un sistema veicoli RP in Y_Ini

#1 L'utente è offline   Syncro 

  • Cittadino Onesto
  • Gruppo: Utenti
  • Messaggi: 12
  • Iscritto il: 11/04/14
  • GTA Preferito:GTA: San Andreas

Inviato il 14 maggio 2014 - 12:59

Difficoltà: 5/5
Introduzione
Questa guida vi insegnerà a realizzare da zero un sistema veicoli RP che si salva in Y_Ini (plugin di Y_Less).
Realizzare un sistema veicoli basilare in Y_Ini è molto semplice, bisogna partire dal presupposto che ogni veicolo avrà un file posizionato in una determinata cartella, quando si tratta di creare un sistema veicoli RP le cose diventano più difficili.
Questo avviene per il fatto che in un sistema RP i veicoli dei player si salvano e si eliminano quando il player effettua la disconnessione dal server. In un sistema veicoli basilare ci si basa sul fatto che l'ID del veicolo presente in gioco sia lo stesso dell'ID del file, ed è giusto in effetti, quindi se spawneremo l'ID 1, il file sarà v1.ini, però in un sistema veicoli RP non è cosi, perché con la scomparsa e ricomparsa dei veicoli, gli ID dei veicoli presenti in gioco cambiano, mentre quelli dei file ovviamente rimangono quelli! Quindi in questo caso si parte dal presupposto che ogni veicolo spawnato in game sia abbinato attraverso una variabile al file.

Primi passi
La prima cosa da creare è una variabile "VehInfo" con vari array dati dall'enumerazione.
enum vInfo
{
	vSlot, // E' lo slot corrispondente al veicolo spawnato (nome del file).
	Model, // E' il modello del veicolo.
	Color1, // E' il colore primario del veicolo.
	Color2, // E' il colore secondario del veicolo.
	Float:Sp[4], // E' una variabile composta da 3 array che salvano rispettivamente la posizione X, Y, Z e Rotazione del veicolo.
	Luci, // Salva lo stato delle luci (Accese/Spente)
	Benzina, // Salva la quantità di benzina.
	Acceso, // Contiene lo stato del veicolo, questa variabile può essere di 3 valori (0 = Spento | 1 = Luci | 2 = Acceso)
	Health, // Salva gli HP del veicolo.
	Panels, // Salva i danni dei pannelli del veicolo
	Doors, // Salva i danni delle porte del veicolo.
	Lights, // Salva i danni dei fari del veicolo.
	Tires, // Salva i danni delle ruote del veicolo (quindi se sono bucate o meno).
	Tipo, // Salva il tipo di veicolo, se è 1 significa che il veicolo è per un player, se è 0 significa che è di fazione.
	Chiuso, // Salva lo stato degli sportelli del veicolo (Chiusi o Aperti)
	Fazione, // Salva l'ID della fazione a cui corrisponde il veicolo.
	Playerid, //  Questo non viene salvato ma serve a immagazzinare l'ID del player che possiede il veicolo, dopo lo vedremo.
	Playerslot, // Questo viene salvato e serve a contenere lo Slot del Player sul quale è salvato il veicolo (abbiamo 5 slots)
	Speed // Questo serve a contenere la velocità alla quale sta andando il veicolo, può essere usato per un eventuale anticheat/speedometer.
}
new VehInfo[MAX_VEHICLES][vInfo]; // Variabile


La seconda cosa da fare è creare una variabile con 5 array per tutti i players.
new Vehicle[MAX_PLAYERS][5];


Comandi di Spawn
Adesso, con ZCMD e SSCANF2 andiamo a creare il comando per spawnare il veicolo e i vari stock.
CMD:createveh(playerid, params[]) // COMANDO
{
	new model, c1, c2, tipo, playerb, fazione, Float:X, Float:Y, Float:Z, Float:Rot, vid, pslot = 10;
	if(sscanf(params, "iiiiii", model, c1, c2, tipo, playerb, fazione)) return SendClientMessage(playerid, -1, "USO: /createveh [Modello] [Colore 1] [Colore 2] [Tipo] [Player] [Fazione]");
	if(model > 611 || model < 400) return SendClientMessage(playerid, -1, "ERRORE: Scegli un modello valido!");
	if(c1 > 255 || c2 > 255) return SendClientMessage(playerid, -1, "ERRORE: Scegli un colore valido!");
	if(tipo == 1 && playerb == INVALID_PLAYER_ID) return SendClientMessage(playerid, -1, "ERRORE: Player non valido!");
	if(tipo == 1) // Se la tipologia è 1 quindi: Veicolo per player.
	{
	    if(Vehicle[playerb][0] == 0) pslot = 0; // Se lo slot 0 del player b è vuoto, impostiamo pslot a 0.
	    else if(Vehicle[playerb][1] == 0) pslot = 1;
	    else if(Vehicle[playerb][2] == 0) pslot = 2;
	    else if(Vehicle[playerb][3] == 0) pslot = 3;
	    else if(Vehicle[playerb][4] == 0) pslot = 4;
	}
	if(pslot == 10 && tipo == 1) return SendClientMessage(playerid, -1, "ERRORE: Questo player non possiede slot liberi!"); // Se pslot non è stato modificato, e quindi il player non ha slot liberi..
	GetPlayerPos(playerid, X, Y, Z);
	GetPlayerFacingAngle(playerid, Rot);
	vid = NewVehicle(model, c1, c2, tipo, fazione, X, Y, Z, Rot); // Creiamo uno stock chiamato 'NewVehicle'
	PutPlayerInVehicle(playerid, vid, 0); // Inserisce il player nel veicolo
	if(tipo == 1) // Se la tipologia è 1.
	{
		VehInfo[vid][Playerslot] = pslot; // Imposta la variabile Playerslot del veicolo all'effettivo slot utilizzato dal player.
		VehInfo[vid][Playerid] = playerb; // Stessa cosa, solo che viene eseguita con Playerid.
		Vehicle[playerb][pslot] = VehInfo[vid][vSlot]; // Imposta lo slot (e non l'ID) del veicolo all'interno della variabile usata dal player.
	}
	return 1;
}


Creato il comando creiamo lo stock NewVehicle che viene utilizzato dal comando!
stock NewVehicle(vModello, vC1, vC2, vTipo, vFazione, Float:X, Float:Y, Float:Z, Float:Rot)
{
	new vid;
	vid = CreateVehicle(vModello, X, Y, Z, Rot, vC1, vC2, 0); // Crea il veicolo e getta l'id del veicolo all'interno della variabile vid.
	if(vTipo == 1) VehInfo[vid][vSlot] = CheckFreePVehicleSlot(); // Le funzioni "CheckFreeVehicleSlot" le vedremo dopo.
	if(vTipo == 2) VehInfo[vid][vSlot] = CheckFreeVehicleSlot();
	// Le seguenti funzioni impostano i vari valori alle variabili del veicolo.
	VehInfo[vid][Model] = vModello;
	VehInfo[vid][Color1] = vC1;
	VehInfo[vid][Color2] = vC2;
	VehInfo[vid][Sp][0] = X;
	VehInfo[vid][Sp][1] = Y;
	VehInfo[vid][Sp][2] = Z;
	VehInfo[vid][Sp][3] = Rot;
	VehInfo[vid][Health] = 1000;
	VehInfo[vid][Benzina] = 60;
	VehInfo[vid][Tipo] = vTipo;
	VehInfo[vid][Fazione] = vFazione;
	SaveVehicle(vid); // Questo stock salva il veicolo, dopo lo vedremo.
	return vid; // Returna l'ID del veicolo che viene usato in CMD:createveh per inserire il player dentro il veicolo.
}


Adesso creiamo lo stock per controllare i free slots dei veicoli usati dai players, cosa significa "Controllare i free slots"? Significa semplicemente controllare andando da 1 a MAX_VEHICLES quale file non è stato ancora creato, e quindi è libero. Se nella cartella ci sono i file v1, v2, v3, il file libero sarà v4. Se nella cartella ci sono i file v1, v3, v4, il file libero sarà v2.
stock CheckFreePVehicleSlot()
{
	new freeslot, path[128], loopstop;
	format(path, sizeof(path), "abc");
	while(loopstop == 0) // Finchè loppstop sarà 0 verranno eseguite le seguenti funzioni:
	{
	    freeslot++; // Aumenta il valore di freeslot di 1.
		format(path, sizeof(path), "veicoli/players/v%i.ini", freeslot); // Modifica il contenuto di questa funzione se la tua directory per i veicoli dei players è diversa.
		if(!fexist(path)) loopstop = 1; // Se questa path (directory) esiste, viene fermato il loop e si procede.
	}
	return freeslot;
}


Stessa funzione, la creiamo anche per i veicoli di fazione, ovviamente la directory sarà diversa.
stock CheckFreeVehicleSlot()
{
	new freeslot, path[128], loopstop;
	format(path, sizeof(path), "abc");
	while(loopstop == 0)
	{
	    freeslot++;
		format(path, sizeof(path), "veicoli/v%i.ini", freeslot);
		if(!fexist(path)) loopstop = 1;
	}
	return freeslot;
}


Il salvataggio dei veicoli
Precedentemente abbiamo notato la funzione "SaveVehicles", adesso la creiamo con tutte le altre funzioni usate dal salvataggio. Prima di tutto creiamo un elenco delle funzioni che dobbiamo creare, in modo da darne subito una spiegazione e non confonderci!

- SaveVehicle(vid) // Serve a salvare un determinato veicolo definito nei parametri (vid).
- SaveAllPVehicles(playerid) // Salva tutti i veicoli del player (loop).
- LoadAllVehicles() // Carica tutti i veicoli di fazione contenuti nella directory dei veicoli.
- LoadAllPVehicles(playerid) // Carica tutti i veicoli di un determinato player.
- LoadVehicle(slotid) // Carica un determinato veicolo di fazione.
- LoadPVehicle(slot, playerid) // Carica un determinato veicolo appartenente ad un player.

Iniziamo con SaveVehicle che è la prima funzione ad essere usata dopo la creazione del veicolo!
stock SaveVehicle(vid)
{
	new Path[128], playerb;
	if(VehInfo[vid][Tipo] == 1) format(Path, sizeof(Path), "veicoli/players/v%i.ini", VehInfo[vid][vSlot]);
	else if(VehInfo[vid][Tipo] == 2) format(Path, sizeof(Path), "veicoli/v%i.ini", VehInfo[vid][vSlot]);
	if(VehInfo[vid][Tipo] == 1) // Se il veicolo appartiene ad un Player vengono gettate le ultime coordinate del veicolo.
	{
	    new Float:X, Float:Y, Float:Z, Float:Rot;
	    playerb = VehInfo[vid][Playerid];
		GetVehiclePos(vid, X, Y, Z);
		GetVehicleZAngle(vid, Rot);
		VehInfo[vid][Sp][0] = X;
		VehInfo[vid][Sp][1] = Y;
		VehInfo[vid][Sp][2] = Z;
		VehInfo[vid][Sp][3] = Rot;

	}
	new INI:vfile = INI_Open(Path); // Apre la PAth e salva il veicolo.
	INI_WriteInt(vfile, "vSlot", VehInfo[vid][vSlot]);
	INI_WriteInt(vfile, "Model", VehInfo[vid][Model]);
	INI_WriteInt(vfile, "Color1", VehInfo[vid][Color1]);
	INI_WriteInt(vfile, "Color2", VehInfo[vid][Color2]);
	INI_WriteFloat(vfile, "SpawnX", VehInfo[vid][Sp][0]);
	INI_WriteFloat(vfile, "SpawnY", VehInfo[vid][Sp][1]);
	INI_WriteFloat(vfile, "SpawnZ", VehInfo[vid][Sp][2]);
	INI_WriteFloat(vfile, "SpawnRot", VehInfo[vid][Sp][3]);
	INI_WriteInt(vfile, "Luci", VehInfo[vid][Luci]);
	INI_WriteInt(vfile, "Acceso", VehInfo[vid][Acceso]);
	INI_WriteInt(vfile, "Panels", VehInfo[vid][Panels]);
	INI_WriteInt(vfile, "Doors", VehInfo[vid][Doors]);
	INI_WriteInt(vfile, "Lights", VehInfo[vid][Lights]);
	INI_WriteInt(vfile, "Tires", VehInfo[vid][Tires]);
	INI_WriteInt(vfile, "Health", VehInfo[vid][Health]);
	INI_WriteInt(vfile, "Benzina", VehInfo[vid][Benzina]);
	INI_WriteInt(vfile, "Tipo", VehInfo[vid][Tipo]);
	INI_WriteInt(vfile, "Chiuso", VehInfo[vid][Chiuso]);
	INI_WriteInt(vfile, "Fazione", VehInfo[vid][Fazione]);
	INI_WriteInt(vfile, "Playerslot", VehInfo[vid][Playerslot]);
	INI_Close(vfile);
	return 1;
}


Adesso passiamo a SaveAllPVehicles
Rechiamo sul Callback 'OnPlayerDisconnect' e chiamiamo la funzione.
SaveAllPVehicles(playerid);

Poi passiamo alla funzione vera e propria (stock):
stock SaveAllPVehicles(playerid)
{
	new veh;
	for(new i; i < 5; i++)
	{
	    if(Vehicle[playerid][i] > 0) // Verifica se c'è un veicolo all'interno di uno slot.
	    {
			veh = Vehicle[playerid][i]; // Inserisce l'ID del veicolo nella variabile Veh.
			SaveVehicle(veh); // Salva il veicolo.
			DestroyVehicle(veh); // Elimina il veicolo (non il salvataggio ma il veicolo).
		}
	}
	return 1;
}


Adesso andiamo a LoadAllVehicles che come detto prima serve a caricare tutti i veicoli appartenenti alle fazioni, questa funzione va richiamata su OnGameModeInit, in modo che i veicoli vengano caricati all'avvio della GM.
La funzione è molto semplice ed è la seguente:
stock LoadAllVehicles()
{
	for(new i; i < MAX_VEHICLES; i++)
	{
	    LoadVehicle(i);
	}
	return 1;
}


Ora invece passiamo a LoadAllPVehicles, che deve essere richiamata quando un player si connette, o quando effettua il login, io vi consiglio di richiamarla quando il player effettua il login.
stock LoadAllPVehicles(playerid)
{
	new slot;
	for(new i; i < MAX_PVEHICLES; i++)
	{
	    if(Vehicle[playerid][i] > 0)
	    {
	        slot = Vehicle[playerid][i];
			LoadPVehicle(slot, playerid);
		}
	}
	return 1;
}


Adesso passiamo a LoadVehicle che ci servirà per caricare un veicolo di fazione, la funzione "LoadVehicle" è richiamata in "LoadAllVehicles". E' una funzione molto complessa, ma dopo vedremo il perché.
stock LoadVehicle(slotid)
{
	new Path[128], vid;
	format(Path, sizeof(Path), "veicoli/v%i.ini", slotid);
	if(fexist(Path))
	{
	    INI_ParseFile(Path, "LoadVehicleData");
		vid = CreateVehicle(Load_Model, Load_SpawnX, Load_SpawnY, Load_SpawnZ, Load_SpawnRot, Load_Color1, Load_Color2, 0);
		VehInfo[vid][vSlot] = Load_vSlot;
		VehInfo[vid][Model] = Load_Model;
		VehInfo[vid][Color1] = Load_Color1;
		VehInfo[vid][Color2] = Load_Color2;
		VehInfo[vid][Sp][0] = Load_SpawnX;
		VehInfo[vid][Sp][1] = Load_SpawnY;
		VehInfo[vid][Sp][2] = Load_SpawnZ;
		VehInfo[vid][Sp][3] = Load_SpawnRot;
		VehInfo[vid][Luci] = Load_Luci;
		VehInfo[vid][Acceso] = Load_Acceso;
		VehInfo[vid][Panels] = Load_Panels;
		VehInfo[vid][Doors] = Load_Doors;
		VehInfo[vid][Lights] = Load_Lights;
		VehInfo[vid][Tires] = Load_Tires;
		VehInfo[vid][Health] = Load_Health;
		VehInfo[vid][Benzina] = Load_Benzina;
		VehInfo[vid][Tipo] = Load_Tipo;
		VehInfo[vid][Chiuso] = Load_Chiuso;
		VehInfo[vid][Fazione] = Load_Fazione;
		VehInfo[vid][Playerslot] = Load_Playerslot;
	}
    return 1;
}


LoadPVehicle è simile a LoadVehicle solo che carica un veicolo appartenente ad un player e viene a sua volta richiamata dalla funzione LoadAllPVehicle (se il veicolo è posseduto da quel player).
stock LoadPVehicle(slot, playerid)
{
	new Path[128], vid, pSlot;
	format(Path, sizeof(Path), "veicoli/players/v%i.ini", slot);
	if(fexist(Path))
	{
	    new engine, lights, alarm, doors, bonnet, boot, objective;
	    INI_ParseFile(Path, "LoadVehicleData");
		vid = CreateVehicle(Load_Model, Load_SpawnX, Load_SpawnY, Load_SpawnZ, Load_SpawnRot, Load_Color1, Load_Color2, 0);
		VehInfo[vid][vSlot] = Load_vSlot;
		VehInfo[vid][Model] = Load_Model;
		VehInfo[vid][Color1] = Load_Color1;
		VehInfo[vid][Color2] = Load_Color2;
		VehInfo[vid][Sp][0] = Load_SpawnX;
		VehInfo[vid][Sp][1] = Load_SpawnY;
		VehInfo[vid][Sp][2] = Load_SpawnZ;
		VehInfo[vid][Sp][3] = Load_SpawnRot;
		VehInfo[vid][Luci] = Load_Luci;
		VehInfo[vid][Acceso] = Load_Acceso;
		VehInfo[vid][Panels] = Load_Panels;
		VehInfo[vid][Doors] = Load_Doors;
		VehInfo[vid][Lights] = Load_Lights;
		VehInfo[vid][Tires] = Load_Tires;
		VehInfo[vid][Health] = Load_Health;
		VehInfo[vid][Benzina] = Load_Benzina;
		VehInfo[vid][Tipo] = Load_Tipo;
		VehInfo[vid][Chiuso] = Load_Chiuso;
		VehInfo[vid][Fazione] = Load_Fazione;
		VehInfo[vid][Playerslot] = Load_Playerslot;
		SetVehicleHealth(vid, VehInfo[vid][Health]);
		if(VehInfo[vid][Acceso] == 2) engine = 1;
		if(VehInfo[vid][Luci] == 1) lights = 1;
		SetVehicleParamsEx(vid, engine, lights, alarm, doors, bonnet, boot, objective);
		UpdateVehicleDamageStatus(vid, VehInfo[vid][Panels], VehInfo[vid][Doors], VehInfo[vid][Lights], VehInfo[vid][Tires]);
		pSlot = VehInfo[vid][Playerslot];
		Vehicle[playerid][pslot] = vid;
		VehInfo[vid][Playerid] = playerid;
		return 1;
	}
	return 1;
}


Abbiamo finito le funzioni, eccetto una che vedremo subito!

INI_ParseFile
Nelle funzioni di Loading abbiamo usato INI_ParseFile, adesso andiamo a creare la funzione pubblica che verrà usata da INI_ParseFile, infatti INI_ParseFile non carica il file, ma richiama la funzione pubblica che in questo caso viene chiamata 'LoadVehicleData'.

Prima di tutto andiamo a creare circa 20 variabili che ci serviranno a trasferire il valore delle variabili caricate alle rispettivi funzioni.
Quindi in cima alle gamemode creiamo queste due semplici righe:
new Load_vSlot, Load_Model, Load_Color1, Load_Color2, Float:Load_SpawnX, Float:Load_SpawnY, Float:Load_SpawnZ, Float:Load_SpawnRot, Load_Luci, Load_Acceso;
new Load_Panels, Load_Doors, Load_Lights, Load_Tires, Load_Health, Load_Benzina, Load_Tipo, Load_Chiuso, Load_Fazione, Load_Playerslot;


In seguito al di fuori di qualsiasi Callback ovviamente, creiamo la funzione LoadVehicleData che come detto prima deve essere pubblica e serve a caricare un determinato veicolo.
// // // FILE LOADINGS
forward LoadVehicleData(name[], value[]);
public LoadVehicleData(name[], value[])
{
	INI_Int("vSlot", Load_vSlot);
	INI_Int("Model", Load_Model);
	INI_Int("Color1", Load_Color1);
	INI_Int("Color2", Load_Color2);
	INI_Float("SpawnX", Load_SpawnX);
	INI_Float("SpawnY", Load_SpawnY);
	INI_Float("SpawnZ", Load_SpawnZ);
	INI_Float("SpawnRot", Load_SpawnRot);
	INI_Int("Luci", Load_Luci);
	INI_Int("Acceso", Load_Acceso);
	INI_Int("Panels", Load_Panels);
	INI_Int("Doors", Load_Doors);
	INI_Int("Lights", Load_Lights);
	INI_Int("Tires", Load_Tires);
	INI_Int("Health", Load_Health);
	INI_Int("Benzina", Load_Benzina);
	INI_Int("Tipo", Load_Tipo);
	INI_Int("Chiuso", Load_Chiuso);
	INI_Int("Fazione", Load_Fazione);
	INI_Int("Playerslot", Load_Playerslot);
	return 1;
}


Finish!
Se avete trovato dei problemi nel creare questo sistema, dei bug o altro potete comunicarmelo!
Per me è stato molto difficile, alla fine ci sono riuscito, uno dei problemi miei era proprio in INI_ParseFile, ed è stato risolto oggi assieme a molti altri bug/errori. Il sistema che vi ho spiegato è privo di bug e viene usato anche dalla mia Gamemode (BlackMamba v1A). Se avete dubbi o bisogno di spiegazioni potete contattarmi (nel Topic ovviamente).
Necessiti di aiuto con SA-MP o Pawn? Aggiungimi su skype: syncroit
0

Pagina 1 di 1
  • Non puoi iniziare una nuova discussione
  • Non puoi rispondere a questa discussione

1 utenti stanno leggendo questa discussione
0 utenti, 1 ospiti, 0 utenti anonimi