Hola amigos, hoy vengo a enseñar como crear un gamemode, no un gamemode nivel dios xD simplemente un gamemode que con el tiempo ustedes le agregen lo que quieran, en vez de modificar un GM que no le entiendes la estructura, es mejor tener tu GM y bueno empezemos.
Lo que vamos a utilizar sera los sistemas más optimizados programados hasta ahora, foreach, y_ini, sscanf. No es muy dificil, solo hay que leer bien y analizar para entender.
Bueno comenzemos:
Abren su pawno, abren un archivo nuevo, le borran lo que tiene, osea lo dejan en blanco y ponen esto:
Ahora pondremos algunos de los comandos para admin, vamos a usar ZCMD y SSCANF.
Si no sabes usar ZCMD y SSCANF, has click aquí para aprender.
Bueno amigos, esa fue la primera parte del tutorial.Espero que les guste y que aprendan a crear su propio gamemode. Esperen la segunda parte.
Creditos:
* Aldys (tutorial & tutorial de zcmd and sscanf.)
* Y_Less (foreach, sscanf y y_ini)
* Zeex (zcmd)
Lo que vamos a utilizar sera los sistemas más optimizados programados hasta ahora, foreach, y_ini, sscanf. No es muy dificil, solo hay que leer bien y analizar para entender.
Bueno comenzemos:
Abren su pawno, abren un archivo nuevo, le borran lo que tiene, osea lo dejan en blanco y ponen esto:
- Código:
/*
Gamemode RP creado desde cero - tutorial by Aldys
*/
// - Includes
#include <a_samp>//El include nativo..
#include <YSI\y_ini>//si no tienen este include, pueden descargarlo, es facil de encontrar.
#include <zcmd>//es el procesador de comandos que usaremos
#include <sscanf2>//para hacer comandos con parametros, osea espacios
#include <foreach>// Sirve para hacer loops más optimizados y rápidos
// - IDS Dialogs
#define Registro 0
#define Ingreso 1
// - Colores
#define AZUL 0x0000FFFF// todos los colores, los pueden hacer ustedes xD
#define AMARILLO 0xFFFF00FF
#define ROJO 0xFF0000FF
#define VERDE 0x00FF00FF
#define BLANCO 0x00000000
#define NEGRO 0x000000FF
#define GRIS_CLARO 0x00000029
#define Hablar 0xE6E6E6E6//el color que aparece l hablar. Entre mas lejos estas, se ve mas negro
#define Hablar2 0xC8C8C8C8
#define Hablar3 0xAAAAAAAA
#define Hablar4 0x8C8C8C8C
#define Hablar5 0x6E6E6E6E
// - Otros
#define Hospital 1178.4025,-1323.0923,14.1183//define las coordenadas del hospital, para donde spawnear cuando moris
#pragma tabsize 0 //quita el famoso "loose identification"
#define Carpeta_Usuarios "Usuarios"//en qué carpeta se guardarán los usuarios, el archivo .ini
#define alm(%0,%1) strmid(%0,%1,0,strlen(%1),strlen(%1)+1)//este es un macro que hize para que sea mas rapido almacenar en strings
- Código:
// - news
new
bool:Logueado[MAX_PLAYERS],//Se activará al loguear
BigEar[MAX_PLAYERS],//es una variable del proxdetector
Nombre[MAX_PLAYERS][MAX_PLAYER_NAME];//aquí almacenaremos el nombre del jugador.
// - forwards
forward ActualizarCuenta(playerid);//esta callback creada por nosotros, es para que sea mas facil editar el registro/actualización de cuentas
forward Cargar_data(playerid,name[],value[]);//esta callback permite cargar los datos del jugador creados en el archivo INI
forward CargarCuenta(playerid); // le dará el dinero, el nivel y demás..
forward ProxDetector(Float:radi, playerid, string[],col1,col2,col3,col4,col5);//proxdetector, es para que solo usuarios cercanos lean algo...
// - Enums
enum Info
{
Contra[32],
bool:Tutorial, //almacenará true o false, nada más.
Dinero,
Nivel,
Sexo,
Edad
};
new Informacion[MAX_PLAYERS][Info];
- Código:
public OnGameModeInit()
{
SetGameModeText("El mode");//el mode del SV
SendRconCommand("hostname GM de 0");//el nombre del SV
SendRconCommand("mapname el map");//nombre del map
ManualVehicleEngineAndLights();//esto hara que, al subir a un auto, no se prenda el motor y otras cosas
ShowPlayerMarkers(0);//esto hara que los jugadores no aparescan en el mapa
DisableInteriorEnterExits();//borra las entradas/interiores por defecto
return 1;
}
public OnPlayerText(playerid, text[])
{
new string[128];//los maximos caracteres , tamaño del array, permitidos de cuando hablas, en mi caso 128 porque es la máxima entrada del chatbox
format(string, sizeof(string), "%s dice: %s",NombreJ(playerid), text);
ProxDetector(10.0, playerid, string,Hablar,Hablar2,Hablar3,Hablar4,Hablar5);
return 0;
}
public OnPlayerSpawn(playerid)
{
if(!Logueado[playerid]) return SendClientMessage(playerid,-1,"Logueate mediante el dialogo");//Esto hace que por algun bug, el jugador no pueda entrar sin hacerlo mediante el registro a dialog
return 1;
}
public OnPlayerRequestSpawn(playerid)//esto es muy importante, sirve para que si ponen el boton spawn, no pase nada no spawnee..
{
return 0;//si ponen 1, el boton spawn va a funcionar y se van a cagar buegeando :/
}
public OnPlayerConnect(playerid)
{
//almacenar nombre
GetPlayerName(playerid,Nombre[playerid],24);
//resetear variables
Logueado[playerid] = false;
BigEar[playerid] = 0;
return 1;
}
- Código:
public OnPlayerRequestClass(playerid, classid)
{
if (!fexist(UbicacionArchivo(playerid)))//chequeas si el archivo existe
{
ShowPlayerDialog(playerid, Registro, DIALOG_STYLE_INPUT, "Registro", "Coloque su contraseña para crear su cuenta", "Registrar", "Cancelar");//el dialogo para un usuario nuevo
}
else
{
INI_ParseFile(UbicacionArchivo(playerid), "Cargar_%s", .bExtra = true, .extra = playerid);//almacena los datos del jugador en su respectivo array, según el archivo a checkear. (.Extra: destino del array)
ShowPlayerDialog(playerid, Ingreso, DIALOG_STYLE_INPUT, "Ingreso", "Coloque su contraseña para ingresar", "Conectar", "Cancelar");//el dialogo, de cuando ya estas registrado
}
//aca pueden poner una camara, para que quede mas lindo
return 1;
}
public OnDialogResponse(playerid, dialogid, response, listitem, inputtext[])
{
//Usaremos switch para mejor procesamiento
switch(dialogid)
{
case Registro:
{
if (!strlen(inputtext) || strlen(inputtext) > 32) return ShowPlayerDialog(playerid, Registro, DIALOG_STYLE_INPUT, "Registro", "Mínimo 1 caracter, máximo 32 caracteres", "Continuar", "Salir");//si no introduce ningun texto, el dialogo reaparece
if (!response) return Kick(playerid);//si pone "cancelar" lo kickea
alm(Informacion[playerid][Contra],inputtext);
SetPlayerScore(playerid,1);
ShowPlayerDialog(playerid, Ingreso, DIALOG_STYLE_INPUT, "Ingreso", "Ingrese su contraseña nuevamente, para ingresar", "Confirmar", "Salir");
ActualizarCuenta(playerid);
}
case Ingreso:
{
if (!strlen(inputtext)) return ShowPlayerDialog(playerid, Ingreso, DIALOG_STYLE_INPUT, "Ingreso", "Por Favor, ingrese alguna contraseña", "Aceptar", "Salir");
if (!response) return Kick(playerid);//si pone cancelar, lo kickea
if (!strcmp(inputtext,Informacion[playerid][Contra]))//comparamos las dos strings
{
Logueado[playerid] = true;
CargarCuenta(playerid);//carga la cuenta(definiremos esta función más abajo)
}
else
{
ShowPlayerDialog(playerid, 100, DIALOG_STYLE_MSGBOX, "Error", "Su contraseña no coincide con su nombre", "Aceptar", "");
Kick(playerid);
}
}
}
return 1;
}
- Código:
public OnPlayerDisconnect(playerid,reason)//este callback hace que al desconectarse, guarde los datos del jugador
{
if(Logueado[playerid]) ActualizarCuenta(playerid);//actualiza el ini, SOLO si está logueado.
return 1;
}
public OnGameModeExit()
{
foreach(Player,i)
{
if(Logueado[i])
{
ActualizarCuenta(i);
}
}
return 1;
}
- Código:
//Este stock retorna el nombre de un jugador.
stock NombreJ(playerid)
{
return Nombre[playerid];
}
//Este stock retorna la ubicacion del archivo de un jugador.
stock UbicacionArchivo(playerid)
{
new Ubic[MAX_PLAYER_NAME + 20];
format(Ubic,sizeof Ubic,""#Carpeta_Usuarios"/%s.ini",NombreJ(playerid));
return Ubic;
}
- Código:
//- Callbacks
public ActualizarCuenta(playerid)
{
new INI:Arch = INI_Open(UbicacionArchivo(playerid));
INI_SetTag(Arch,"data");
INI_WriteString(Arch,"Contraseña",Informacion[playerid][Contra]);
INI_WriteBool(Arch,"Tutorial",Informacion[playerid][Tutorial]);
INI_WriteInt(Arch,"Dinero",GetPlayerMoney(playerid));
INI_WriteInt(Arch,"Nivel",GetPlayerScore(playerid));
INI_WriteInt(Arch,"Sexo",Informacion[playerid][Sexo]);
INI_WriteInt(Arch,"Edad",Informacion[playerid][Edad]);
INI_Close(Arch); //guarda y actualiza el archivo ini
return 1;
}
public Cargar_data(playerid,name[],value[])
{
INI_String("Contraseña",Informacion[playerid][Contra],32);
INI_Bool("Tutorial", Informacion[playerid][Tutorial]);
INI_Int("Dinero",Informacion[playerid][Dinero]);
INI_Int("Nivel",Informacion[playerid][Nivel]);
INI_Int("Sexo",Informacion[playerid][Sexo]);
INI_Int("Edad",Informacion[playerid][Edad]);
return 1;
}
public CargarCuenta(playerid)
{
SpawnPlayer(playerid);
SetPlayerScore(playerid,Informacion[playerid][Nivel]);
GivePlayerMoney(playerid,Informacion[playerid][Dinero]);
return 1;
}
public ProxDetector(Float:radi, playerid, string[],col1,col2,col3,col4,col5)
{
if(IsPlayerConnected(playerid))
{
new Float:posx, Float:posy, Float:posz;
new Float:oldposx, Float:oldposy, Float:oldposz;
new Float:tempposx, Float:tempposy, Float:tempposz;
GetPlayerPos(playerid, oldposx, oldposy, oldposz);
foreach(Player,i)//cambiamos el loop a foreach
{
if(GetPlayerVirtualWorld(playerid) == GetPlayerVirtualWorld(i))
{
if(!BigEar[i])
{
GetPlayerPos(i, posx, posy, posz);
tempposx = (oldposx -posx);
tempposy = (oldposy -posy);
tempposz = (oldposz -posz);
if (((tempposx < radi/16) && (tempposx > -radi/16)) && ((tempposy < radi/16) && (tempposy > -radi/16)) && ((tempposz < radi/16) && (tempposz > -radi/16)))
{
SendClientMessage(i, col1, string);
}
else if (((tempposx < radi/8) && (tempposx > -radi/8)) && ((tempposy < radi/8) && (tempposy > -radi/8)) && ((tempposz < radi/8) && (tempposz > -radi/8)))
{
SendClientMessage(i, col2, string);
}
else if (((tempposx < radi/4) && (tempposx > -radi/4)) && ((tempposy < radi/4) && (tempposy > -radi/4)) && ((tempposz < radi/4) && (tempposz > -radi/4)))
{
SendClientMessage(i, col3, string);
}
else if (((tempposx < radi/2) && (tempposx > -radi/2)) && ((tempposy < radi/2) && (tempposy > -radi/2)) && ((tempposz < radi/2) && (tempposz > -radi/2)))
{
SendClientMessage(i, col4, string);
}
else if (((tempposx < radi) && (tempposx > -radi)) && ((tempposy < radi) && (tempposy > -radi)) && ((tempposz < radi) && (tempposz > -radi)))
{
SendClientMessage(i, col5, string);
}
}
else
{
SendClientMessage(i, col1, string);
}
}
}
}
return 1;
}
- Código:
#define SSexo 2
#define SEdad 3
//En los news:
new PTuto[MAX_PLAYERS];
//Forwards:
forward Tuto(playerid);
- Código:
Faccion,
Admin
- Código:
enum Info
{
Contra[32],
bool:Tutorial,
Dinero,
Nivel,
Sexo,
Edad,
Faccion,
Admin
};
- Código:
if(!Informacion[playerid][Tutorial])//si todabia no paso el tutorial
{
TogglePlayerControllable(playerid,false);//congela al jugador
SetPlayerPos(playerid,1560.3490,-1627.1450,13.5469);
ShowPlayerDialog(playerid,SSexo,DIALOG_STYLE_MSGBOX,"{FFFFFF}Seleccionar Sexo","{00FFCC}¿Que Sexo Eres, Masculino o Femenino?","Masculino","Femenino");
return 1;
}
SetPlayerPos(playerid,1560.3490,-1627.1450,13.5469);//para que le de alguna posicion al entrar
- Código:
public OnPlayerSpawn(playerid)
{
if(!Logueado[playerid]) return SendClientMessage(playerid,-1,"Logueate mediante el dialogo");//Esto hace que por algun bug, el jugador no pueda entrar sin hacerlo mediante el registro a dialog
if(!Informacion[playerid][Tutorial])//si todabia no paso el tutorial
{
TogglePlayerControllable(playerid,false);//congela al jugador
SetPlayerPos(playerid,1560.3490,-1627.1450,13.5469);//le damos una pos
ShowPlayerDialog(playerid,SSexo,DIALOG_STYLE_MSGBOX,"{FFFFFF}Seleccionar Sexo","{00FFCC}¿Que Sexo Eres, Masculino o Femenino?","Masculino","Femenino");//mostramos el dialogo
return 1;
}
SetPlayerPos(playerid,1560.3490,-1627.1450,13.5469);//para que le de alguna posicion al entrar
return 1;
}
- Código:
case SSexo:
{
if(!response)
{
SetPlayerSkin(playerid,93);
Informacion[playerid][Sexo] = 2;
}
else
{
SetPlayerSkin(playerid,26);
Informacion[playerid][Sexo] = 1;
}
ShowPlayerDialog(playerid, SEdad, DIALOG_STYLE_INPUT, "Edad", "Escriba solo el número, su edad:", "Seleccionar", "");
}
case SEdad:
{
if(!IsNumeric(inputtext)) return ShowPlayerDialog(playerid, SEdad, DIALOG_STYLE_INPUT, "Edad", "Escriba solo el número, su edad:", "Seleccionar", "");
if(strval(inputtext) < 18 || strval(inputtext) > 80) ShowPlayerDialog(playerid, SEdad, DIALOG_STYLE_INPUT, "Edad", "Máximo 80, mínimo 18", "Seleccionar", "");
Informacion[playerid][Edad] = strval(inputtext);
GameTextForPlayer(playerid,"~w~Registro finalizado.\nPara pasar de pagina precione ~g~ENTER",2000,3);
SendClientMessage(playerid,-1,"TUTORIAL");
SendClientMessage(playerid,-1,"Ahora, verá un pequeño tutorial sobre este modo de juego");//modifiquen el tutorial..
SendClientMessage(playerid,-1,"...");//modifiquen el tutorial..
SendClientMessage(playerid,-1,"...");//modifiquen el tutorial..
SendClientMessage(playerid,-1,"...");//modifiquen el tutorial..
PTuto[playerid] = 1;//activa la variable pTuto
}
- Código:
public OnDialogResponse(playerid, dialogid, response, listitem, inputtext[])
{
//Usaremos switch para mejor procesamiento
switch(dialogid)
{
case Registro:
{
if (!strlen(inputtext) && strlen(inputtext) > 32) return ShowPlayerDialog(playerid, Registro, DIALOG_STYLE_INPUT, "Registro", "Mínimo 1 caracter, máximo 32 caracteres", "Continuar", "Salir");//si no introduce ningun texto, el dialogo reaparece
if (!response) return Kick(playerid);//si pone "cancelar" lo kickea
alm(Informacion[playerid][Contra],inputtext);
SetPlayerScore(playerid,1);
ShowPlayerDialog(playerid, Ingreso, DIALOG_STYLE_INPUT, "Ingreso", "Ingrese su contraseña nuevamente, para ingresar", "Confirmar", "Salir");
ActualizarCuenta(playerid);
}
case Ingreso:
{
if (!strlen(inputtext)) return ShowPlayerDialog(playerid, Ingreso, DIALOG_STYLE_INPUT, "Ingreso", "Por Favor, ingrese alguna contraseña", "Aceptar", "Salir");
if (!response) return Kick(playerid);//si pone cancelar, lo kickea
if (!strcmp(inputtext,Informacion[playerid][Contra]))//comparamos las dos strings
{
Logueado[playerid] = true;
CargarCuenta(playerid);//carga la cuenta(definiremos esta función más abajo)
}
else
{
ShowPlayerDialog(playerid, 100, DIALOG_STYLE_MSGBOX, "Error", "Su contraseña no coincide con su nombre", "Aceptar", "");
Kick(playerid);
}
}
case SSexo:
{
if(!response)
{
SetPlayerSkin(playerid,93);
Informacion[playerid][Sexo] = 2;
}
else
{
SetPlayerSkin(playerid,26);
Informacion[playerid][Sexo] = 1;
}
ShowPlayerDialog(playerid, SEdad, DIALOG_STYLE_INPUT, "Edad", "Escriba solo el número, su edad:", "Seleccionar", "");
}
case SEdad:
{
if(!IsNumeric(inputtext)) return ShowPlayerDialog(playerid, SEdad, DIALOG_STYLE_INPUT, "Edad", "Escriba solo el número, su edad:", "Seleccionar", "");
if(strval(inputtext) < 18 || strval(inputtext) > 80) ShowPlayerDialog(playerid, SEdad, DIALOG_STYLE_INPUT, "Edad", "Máximo 80, mínimo 18", "Seleccionar", "");
Informacion[playerid][Edad] = strval(inputtext);
GameTextForPlayer(playerid,"~w~Registro finalizado.\nPara pasar de pagina precione ~g~ENTER",2000,3);
SendClientMessage(playerid,-1,"TUTORIAL");
SendClientMessage(playerid,-1,"Ahora, verá un pequeño tutorial sobre este modo de juego");//modifiquen el tutorial..
SendClientMessage(playerid,-1,"...");//modifiquen el tutorial..
SendClientMessage(playerid,-1,"...");//modifiquen el tutorial..
SendClientMessage(playerid,-1,"...");//modifiquen el tutorial..
PTuto[playerid] = 1;//activa la variable pTuto
}
}
return 1;
}
- Código:
public OnPlayerKeyStateChange(playerid, newkeys, oldkeys)
{
if(PTuto[playerid] >= 1)
{
if(newkeys == KEY_SECONDARY_ATTACK)
{
Tuto(playerid);
return 1;
}
return 1;
}
return 0;
}
- Código:
public Tuto(playerid)
{
switch(PTuto[playerid])
{
case 1:
{
SendClientMessage(playerid,-1,"LSPD");
SendClientMessage(playerid,-1,"se encarga de x cosa");
}
case 2:
{
SendClientMessage(playerid,-1,"FBI");
SendClientMessage(playerid,-1,"se encarga de x cosa");
PTuto[playerid] ++;
}
case 3:
{
SendClientMessage(playerid,-1,"Tal faccion");
SendClientMessage(playerid,-1,"se encarga de x cosa");
}//pueden crear mas partes, yo les doy un elemplo, recuerden que deben poner la variable PTuto con ++, eso hara que se le valla sumando el valor
case 4:
{
SendClientMessage(playerid,-1,"Fin del tutorial");
SendClientMessage(playerid,-1,"gracias por leerlo");
}
}
++PTuto[playerid];
if(PTuto[playerid] >= 4)//cuando termine el tutorial
{
Informacion[playerid][Tutorial] = true;
TogglePlayerControllable(playerid,1);
PTuto[playerid] = 0;
}
return 1;
}
- Código:
INI_Int("Admin",Informacion[playerid][Admin]);
INI_Int("Faccion",Informacion[playerid][Faccion]);
- Código:
INI_WriteInt(Arch,"Admin",Informacion[playerid][Admin]);
INI_WriteInt(Arch,"Faccion",Informacion[playerid][Faccion]);
- Código:
stock IsNumeric(string[])
{
for (new i = 0, j = strlen(string); i < j; i++)
{
if (string[i] > '9' || string[i] < '0') return 0;
}
return 1;
}
Ahora pondremos algunos de los comandos para admin, vamos a usar ZCMD y SSCANF.
Si no sabes usar ZCMD y SSCANF, has click aquí para aprender.
- Código:
//Comandos para admins
CMD:darlider(playerid, params[])
{
new ID,FACCION;
if(Informacion[playerid][Admin] < 4) return SendClientMessage(playerid,-1,"No es admin nivel 4!");//el nivel admin desde que lo pueden usar
if(sscanf(params, "ud", ID,FACCION) )return SendClientMessage(playerid,-1,"Uso: /darfaccion [ID] [FACCION]");//los parametros del comando
if(!IsPlayerConnected(ID)) return SendClientMessage(playerid,-1,"Jugador o conectado/ID incorrecta");
Informacion[ID][Faccion] = FACCION;
return 1;
}
CMD:daradmin(playerid, params[])
{
new ID,ADMIN;
if(Informacion[playerid][Admin] < 10) return SendClientMessage(playerid,-1,"No es admin nivel 10!");//el nivel admin desde que lo pueden usar
if(sscanf(params, "ud", ID,ADMIN) )return SendClientMessage(playerid,-1,"Uso: /daradmin [ID] [ADMLEVEL]");
if(!IsPlayerConnected(ID)) return SendClientMessage(playerid,-1,"Jugador o conectado/ID incorrecta");
{
Informacion[ID][Admin] = ADMIN;
return 1;
}
}
CMD:dardinero(playerid, params[])
{
new ID,PLATA;
if(Informacion[playerid][Admin] < 10) return SendClientMessage(playerid,-1,"No es admin nivel 10!");//el nivel admin desde que lo pueden usar
if(sscanf(params, "ud", ID,PLATA) )return SendClientMessage(playerid,-1,"Uso: /dardinero [ID] [DINERO]");
if(!IsPlayerConnected(ID)) return SendClientMessage(playerid,-1,"Jugador o conectado/ID incorrecta");
Informacion[ID][Dinero] = PLATA;
GivePlayerMoney(ID,PLATA);
return 1;
}
Bueno amigos, esa fue la primera parte del tutorial.Espero que les guste y que aprendan a crear su propio gamemode. Esperen la segunda parte.
Creditos:
* Aldys (tutorial & tutorial de zcmd and sscanf.)
* Y_Less (foreach, sscanf y y_ini)
* Zeex (zcmd)