Saltar al contenido
Toda la documentación

PVP

Sistema PvP con zonas FFA, zonas Only y partidas de lobby por equipos. Cada zona y cada partida funciona en su propia dimensión. Además hay una clasificación y un marcador de partida. El script crea la tabla por sí mismo.

Requisitos
  • ESX Legacy (es_extended, probado con 1.14)
  • oxmysql
  • OneSync
  • En ESX tiene que estar Config.EnablePVP = true (por defecto)
  • Para el menú del garaje en mapas de vehículos: esxmenudefault (o tu propio menú mediante ClientVehicleMenu)

Funciones

  • Zonas FFA: todos contra todos. Por zona, armas fijas o las propias armas del jugador. Respawn con chaleco y una breve protección al spawnear.
  • Zonas Only: todos tienen las mismas armas, opcionalmente con un vehículo (p. ej. BF 400) en cada spawn.
  • Lobbies: equipo A contra equipo B en modo best-of con ronda decisiva. Se pueden elegir mapa, modo (a pie o vehículo), rondas, hasta 3 armas y una contraseña opcional. El propietario puede expulsar, mezclar y disolver.
  • Espectar: quien queda eliminado en una ronda mira a los compañeros vivos y cambia con ← →.
  • Marcador de partida arriba en el centro y Clasificación con los filtros FFA, Only y Lobby (incluidas victorias y derrotas).
  • Protección de armas: las armas fijas solo existen en el PvP. Las armas reales y su munición quedan protegidas.
  • Logs de Discord, exports y tus propias funciones para conectar otros scripts.

Instalación

  1. Pon la carpeta off_pvp en tu carpeta resources.
  2. Añade en el server.cfg, después de oxmysql y ESX:
cfg
ensure oxmysql
ensure es_extended
ensure off_pvp
  1. Ajusta los puntos PvP, las zonas y los mapas en config/ a tu servidor.

La tabla off_pvp_stats se crea automáticamente en el primer arranque.

Coordenadas de ejemplo

Las zonas en config/settings/config.ffa.lua y config/settings/config.only.lua y los mapas en config/settings/config.lobby.lua son solo ejemplos. Revisa todas las posiciones en el juego y pon las tuyas.

Configuración

Los ajustes están en config/settings/: config.lua para todo lo general, config.ffa.lua, config.only.lua y config.lobby.lua para los tres modos.

config/settings/config.lua

OpciónPredeterminadoDescripción
serverInfo.name'OFF SCRIPTS'Nombre del servidor, se muestra en la interfaz en lugar de «OFF SCRIPTS»
serverInfo.locale'de'Idioma: de, en, pl, fr, es o it
serverInfo.color{ 155, 89, 255 }Color de la UI (RGB)
serverInfo.design3Diseño de la interfaz: 1 = Clásico, 2 = Ticket, 3 = Storefront
blurtrueFondo desenfocado mientras el menú está abierto
quitCommand'quitffa'Comando para salir de FFA, Only, lobbies y partidas en curso
defaultPed's_m_y_valet_01'NPC para puntos sin un ped válido
points1 ejemploPuntos PvP en los que E abre el menú (ver abajo)
markerver archivoAspecto de los puntos con marker: type, size, alpha, drawDistance
respawn.seconds3Tiempo de espera hasta el respawn en FFA y Only
respawn.protection3Segundos de invulnerabilidad tras el spawn
respawn.armour100Chaleco tras el spawn
killHealtrueVida y chaleco al máximo tras cada kill (FFA, Only y Lobby)
leaderboardSize50Cuántos jugadores muestra la clasificación por modo (3–500)

Puntos PvP (points):

CampoDescripción
idNombre único del punto
labelNombre en el texto de ayuda y en el blip
positionvec4(x, y, z, heading)
interaction'ped' = NPC, 'marker' = marker en el suelo
pedModelo del NPC, sin modelo válido se usa defaultPed
scenarioAnimación del NPC (opcional)
blip{ sprite, color, scale }, false = sin blip

config/settings/config.ffa.lua y config/settings/config.only.lua

Config.ffa y Config.only contienen las zonas. Cada zona tiene:

CampoDescripción
idNombre único, a la vez el nombre de la imagen: web/dist/assets/maps/<id>.png
labelNombre en el menú
centerCentro de la zona, vec3
radiusRadio en metros. Quien sale de él va a un spawn aleatorio
maxPlayersJugadores a la vez
spawnsLista de vec4. En el respawn se usa el spawn más alejado de los demás jugadores
weapons{ name, ammo }. FFA: opcional, sin lista se lucha con las armas propias y se gasta munición real. Only: obligatorio
vehicleSolo Only, opcional: { model, label }. Se spawnea sobre este vehículo

config/settings/config.lobby.lua

Config.lobby contiene los ajustes de los lobbies:

OpciónPredeterminadoDescripción
maxPlayers10Jugadores por lobby, como máximo la mitad por equipo
maxLobbies8Lobbies a la vez
maxWeapons3Armas que se pueden elegir al crear
rounds1 / 15 / 5Rondas: min, max y default
prepareSeconds3Preparación antes de cada ronda (congelado, sin armas), en la primera ronda 3 segundos más
roundEndSeconds1Pausa tras una ronda
resultSeconds1Muestra del resultado, después se vuelve
roundMinutes5Límite de tiempo por ronda, 0 = sin límite
spectateDelay3Segundos tras la muerte hasta espectar
startRange50.0Lo cerca de un punto PvP que deben estar todos los miembros al empezar
overtimeRounds1Rondas decisivas en caso de empate, 0 = empate
armour100Chaleco al inicio de cada ronda
weapons10 armasArmas a elegir al crear: { name, ammo }
vehicles3 vehículosVehículos por defecto para mapas de vehículos sin lista propia: { model, label }

Config.maps contiene los mapas de los lobbies:

CampoDescripción
id / labelNombre único (= nombre de la imagen, como en las zonas) y nombre visible
mode'foot' = a pie, 'vehicle' = mapa de vehículos
center / radiusEsfera que se muestra en la partida (vec3 y metros). Solo es visual, no hay límite
vehiclesOpcional, lista propia de vehículos { model, label }. Sin lista se usa Config.lobby.vehicles
teams.a / teams.bUn spawn (vec4) por equipo. Todos los jugadores del equipo empiezan allí cada ronda
garage / vehicleSpawnSolo mapas de vehículos, por equipo: marker del garaje (vec3) y punto de salida (vec4)

config/functions.lua

Aquí conectas tus propios scripts. Los errores en ellas llegan a la consola, el script sigue funcionando. kind siempre es 'ffa', 'only' o 'lobby'.

FunciónLadoPara qué
ServerCanJoin(source, kind, id)Servidorreturn false, 'Text' impide unirse e iniciar el lobby, p. ej. en la cárcel
ServerKill(killer, victim, kind, id)ServidorKill contado, p. ej. dinero como recompensa
ServerDeath(victim, killer, kind, id, teamkill)ServidorCada muerte, killer puede ser nil
ServerMatchEnded(lobbyId, result)ServidorPartida terminada: { winner, score, map, teams }, winner = 'a', 'b' o nil
ServerJoined(source, kind, id)ServidorEl jugador entra en una zona o una partida
ServerLeft(source, kind, id, reason)Servidorreason = 'quit', 'drop', 'end', 'kick' o 'stop'
Notify(message, type) / HelpNotify(text)ClienteNotificación y texto de ayuda · Servidor: Notify(source, message, type)
ClientRevive(position)ClienteRevivir, p. ej. tu propio script de ambulancia
ClientDeath(kind) / ClientRespawn(kind)ClienteMuerte y respawn en el PvP, p. ej. ocultar la pantalla de muerte
ClientGiveLoadout(loadout)ClienteDar y devolver armas
ClientSetFuel(vehicle, fuel)ClienteScript de combustible
ClientVehicleSpawned(vehicle, plate, kind)ClienteVehículo PvP spawneado, p. ej. dar llaves
ClientVehicleMenu(vehicles, onSelect)ClienteMenú del garaje en mapas de vehículos (por defecto: menú ESX Default)
ClientStateChanged(state)Cliente{ kind, id, team } al entrar, nil al salir, p. ej. bloquear el móvil o tu propio HUD

config/settings/config.server.lua e idiomas

Webhooks de Discord para lobby (lobby creado, partida iniciada, partida terminada, lobby disuelto) y zones (entrar y salir de una zona). '' desactiva un log. Todos los textos están en config/locales/ (un archivo por idioma).

En el juego

  • Menú: E en un punto PvP. Solo funciona vivo, a pie, en la dimensión normal y fuera del gangwar.
  • FFA y Only: Unirse te teletransporta a la zona. Tras morir, sigues en un spawn después de respawn.seconds. Arriba ves kills, muertes y los jugadores de la zona.
  • Salir: /quitffa (o tu quitCommand) te lleva de vuelta al sitio donde te uniste. Vida y chaleco quedan como antes, tus propias armas vuelven. El comando también te saca de un lobby en espera.
  • Crear lobby: elige mapa, modo, rondas, armas y, si quieres, una contraseña. Los jugadores nuevos van al equipo más pequeño. Cambiar de equipo es posible mientras el otro no esté lleno. Tras 5 contraseñas incorrectas, el lobby queda bloqueado para ti durante 60 segundos.
  • Propietario: inicia, mezcla, expulsa y disuelve. Si el propietario se va, el siguiente miembro toma el control.
  • Inicio: quien esté muerto, en otra dimensión, en el gangwar o más lejos que startRange de un punto PvP sale del lobby. Cada equipo necesita al menos un jugador.
  • Partida:
  • Cada ronda empieza con la preparación (congelado, sin armas), después hay armas y chaleco.
  • Gana una ronda quien elimina a todo el equipo rival. Dentro de una ronda no hay respawn. Si los dos últimos caen a la vez, nadie se lleva el punto.
  • Si se acaba el tiempo, gana el equipo con más jugadores vivos, en caso de empate nadie se lleva el punto.
  • Gana la partida quien primero consigue más de la mitad de las rondas. Si se han jugado todas las rondas, gana el marcador más alto. En caso de empate hay rondas decisivas (overtimeRounds), después empate.
  • El fuego amigo está activado. Un teamkill cuenta como muerte, no como kill.
  • Quien abandona una partida en curso recibe una derrota. Si después un equipo queda vacío, el otro gana al instante.
  • Después todos vuelven a su punto de partida, el lobby sigue abierto y vuelve a esperar.
  • Espectar: tras spectateDelay segundos miras a un compañero vivo. Abajo en el centro aparecen su nombre y las flechas. ← y → cambian.
  • Garaje (mapas de vehículos): durante la ronda, E en el marker del garaje de tu equipo abre la lista de vehículos. Cada jugador tiene un vehículo, uno nuevo sustituye al anterior.
  • Clasificación: los mejores jugadores por modo (cantidad mediante leaderboardSize), ordenados por kills. Los valores nuevos aparecen como mucho al minuto, tras una partida al instante.

Para desarrolladores

lua
-- Servidor
local inPvp = exports.off_pvp:IsInPvp(source)        -- FFA, Only o partida en curso
local ffa = exports.off_pvp:IsFFA(source)
local only = exports.off_pvp:IsOnly(source)
local lobby = exports.off_pvp:IsLobby(source)        -- en una partida en curso
local inLobby = exports.off_pvp:IsInLobby(source)    -- miembro de un lobby, esperando o en partida
local info = exports.off_pvp:GetPvp(source)          -- { kind, id, team, alive, kills, deaths } o nil
local removed = exports.off_pvp:RemoveFromPvp(source) -- saca al jugador de una zona, partida o lobby en espera, true/false
local stats = exports.off_pvp:GetStats(source)       -- { ffa = { kills, deaths }, only = { ... }, lobby = { kills, deaths, wins, losses } } o nil

-- Cliente
local inPvp = exports.off_pvp:IsInPvp()
local ffa = exports.off_pvp:IsFFA()
local only = exports.off_pvp:IsOnly()
local lobby = exports.off_pvp:IsLobby()
local spectating = exports.off_pvp:IsSpectating()
local info = exports.off_pvp:GetPvp()                -- { kind, id, team, phase } o nil
  • Statebag offPvp: 'ffa', 'only' o 'lobby' mientras el jugador esté en una zona o una partida.
  • offinventory: canOpen() en off_inventory/config/functions.lua bloquea el inventario y el maletero en el PvP en cuanto offpvp está en marcha.

Problemas frecuentes

Al arrancar, el script muestra errores y avisos en la consola del servidor. Las zonas y mapas con errores aparecen ahí y se ignoran.

ProblemaSolución
«Eso no es posible ahora mismo.» al abrirEstás muerto, en otra dimensión o en el gangwar.
Falta una zona o un mapa en el menúRevisa la consola, la entrada tiene un error (p. ej. sin spawns).
No hay imagen en la zona o el mapaFalta web/dist/assets/maps/<id>.png.
El garaje no abre ningún menúInicia esxmenudefault o ajusta ClientVehicleMenu.
Los jugadores no se hacen dañoPon Config.EnablePVP = true en ESX.
El script de ambulancia muestra la pantalla de muerte en el PvPOcúltala en ClientDeath y vuelve a mostrarla en ClientRespawn.
En el sitio equivocado tras un crashEn el siguiente login vuelves automáticamente a tu punto de partida.
Reinicio del resource durante una partidaTodos vuelven, la partida no cuenta. Mejor no reiniciar durante las partidas.

¿Aún no lo has comprado?

Ver PVP en la tienda