Zum Inhalt springen
Alle Dokumentationen

PVP

PvP-System mit FFA-Zonen, Only-Zonen und Lobby-Matches in Teams. Jede Zone und jedes Match läuft in einer eigenen Dimension. Dazu gibt es ein Leaderboard und eine Match-Anzeige. Die Tabelle legt das Script selbst an.

Voraussetzungen
  • ESX Legacy (es_extended, getestet mit 1.14)
  • oxmysql
  • OneSync
  • In ESX muss Config.EnablePVP = true sein (Standard)
  • Für das Garagenmenü auf Fahrzeug-Maps: esxmenudefault (oder ein eigenes Menü über ClientVehicleMenu)

Funktionen

  • FFA-Zonen: Jeder gegen jeden. Pro Zone feste Waffen oder die eigenen Waffen des Spielers. Respawn mit Weste und kurzem Spawnschutz.
  • Only-Zonen: Alle haben dieselben Waffen, optional mit Fahrzeug (z. B. BF 400) bei jedem Spawn.
  • Lobbys: Team A gegen Team B im Best-of-Modus mit Entscheidungsrunde. Map, Modus (zu Fuß oder Fahrzeug), Runden, bis zu 3 Waffen und ein optionales Passwort sind wählbar. Der Owner kann kicken, mischen und auflösen.
  • Zuschauen: Wer in einer Runde ausscheidet, schaut den lebenden Teamkameraden zu und wechselt mit ← →.
  • Match-Anzeige oben in der Mitte und Leaderboard mit Filter FFA, Only und Lobby (inklusive Siege und Niederlagen).
  • Waffenschutz: Feste Waffen gibt es nur im PvP. Die echten Waffen und ihre Munition bleiben geschützt.
  • Discord-Logs, Exports und eigene Funktionen zum Anbinden anderer Scripts.

Installation

  1. Ordner off_pvp in deinen resources-Ordner legen.
  2. In die server.cfg, nach oxmysql und ESX:
cfg
ensure oxmysql
ensure es_extended
ensure off_pvp
  1. PvP-Punkte, Zonen und Maps in config/ an deinen Server anpassen.

Die Tabelle off_pvp_stats wird beim ersten Start automatisch angelegt.

Beispiel-Koordinaten

Die Zonen in config/settings/config.ffa.lua und config/settings/config.only.lua und die Maps in config/settings/config.lobby.lua sind nur Beispiele. Prüfe alle Positionen im Spiel und trag deine eigenen ein.

Konfiguration

Die Einstellungen liegen in config/settings/: config.lua für alles Allgemeine, config.ffa.lua, config.only.lua und config.lobby.lua für die drei Modi.

config/settings/config.lua

OptionStandardBeschreibung
serverInfo.name'OFF SCRIPTS'Servername, steht in der Oberfläche statt „OFF SCRIPTS“
serverInfo.locale'de'Sprache: de, en, pl, fr, es oder it
serverInfo.color{ 155, 89, 255 }Farbe der UI (RGB)
serverInfo.design3Design der Oberfläche: 1 = Klassisch, 2 = Kassenbon, 3 = Storefront
blurtrueHintergrund unscharf, solange das Menü offen ist
quitCommand'quitffa'Befehl zum Verlassen von FFA, Only, Lobbys und laufenden Matches
defaultPed's_m_y_valet_01'NPC für Punkte ohne gültiges ped
points1 BeispielPvP-Punkte, an denen E das Menü öffnet (siehe unten)
markersiehe DateiAussehen der Marker-Punkte: type, size, alpha, drawDistance
respawn.seconds3Wartezeit bis zum Respawn in FFA und Only
respawn.protection3Sekunden unverwundbar nach dem Spawn
respawn.armour100Weste nach dem Spawn
killHealtrueNach jedem Kill volles Leben und volle Weste (FFA, Only und Lobby)
leaderboardSize50So viele Spieler zeigt das Leaderboard pro Modus (3–500)

PvP-Punkte (points):

FeldBeschreibung
idEindeutiger Name des Punkts
labelName im Hinweistext und auf dem Blip
positionvec4(x, y, z, heading)
interaction'ped' = NPC, 'marker' = Marker am Boden
pedModell des NPCs, ohne gültiges Modell gilt defaultPed
scenarioAnimation des NPCs (optional)
blip{ sprite, color, scale }, false = kein Blip

config/settings/config.ffa.lua und config/settings/config.only.lua

Config.ffa und Config.only enthalten die Zonen. Jede Zone hat:

FeldBeschreibung
idEindeutiger Name, gleichzeitig der Bildname: web/dist/assets/maps/<id>.png
labelName im Menü
centerMitte der Zone, vec3
radiusRadius in Metern. Wer ihn verlässt, wird an einen zufälligen Spawn gesetzt
maxPlayersSpieler gleichzeitig
spawnsListe aus vec4. Beim Respawn wird der Spawn mit dem größten Abstand zu anderen Spielern genommen
weapons{ name, ammo }. FFA: optional, ohne Liste kämpft man mit den eigenen Waffen und verbraucht echte Munition. Only: Pflicht
vehicleNur Only, optional: { model, label }. Man spawnt auf diesem Fahrzeug

config/settings/config.lobby.lua

Config.lobby enthält die Einstellungen für Lobbys:

OptionStandardBeschreibung
maxPlayers10Spieler pro Lobby, pro Team höchstens die Hälfte
maxLobbies8Lobbys gleichzeitig
maxWeapons3Waffen, die man beim Erstellen wählen kann
rounds1 / 15 / 5Runden: min, max und default
prepareSeconds3Vorbereitung vor jeder Runde (eingefroren, ohne Waffen), in der ersten Runde 3 Sekunden länger
roundEndSeconds1Pause nach einer Runde
resultSeconds1Anzeige des Ergebnisses, danach geht es zurück
roundMinutes5Zeitlimit pro Runde, 0 = kein Limit
spectateDelay3Sekunden nach dem Tod bis zum Zuschauen
startRange50.0So nah müssen alle Mitglieder beim Start an einem PvP-Punkt sein
overtimeRounds1Entscheidungsrunden bei Gleichstand, 0 = Unentschieden
armour100Weste zu Beginn jeder Runde
weapons10 WaffenWaffen zur Auswahl beim Erstellen: { name, ammo }
vehicles3 FahrzeugeStandard-Fahrzeuge für Fahrzeug-Maps ohne eigene Liste: { model, label }

Config.maps enthält die Maps für Lobbys:

FeldBeschreibung
id / labelEindeutiger Name (= Bildname wie bei den Zonen) und Anzeigename
mode'foot' = zu Fuß, 'vehicle' = Fahrzeug-Map
center / radiusKugel, die im Match angezeigt wird (vec3 und Meter). Sie ist nur zur Anzeige, es gibt keine Grenze
vehiclesOptional, eigene Fahrzeugliste { model, label }. Ohne Liste gilt Config.lobby.vehicles
teams.a / teams.bPro Team ein spawn (vec4). Alle Spieler des Teams starten jede Runde dort
garage / vehicleSpawnNur Fahrzeug-Maps, pro Team: Garagen-Marker (vec3) und Ausparkpunkt (vec4)

config/functions.lua

Hier bindest du eigene Scripts an. Fehler darin landen in der Konsole, das Script läuft weiter. kind ist immer 'ffa', 'only' oder 'lobby'.

FunktionSeiteWofür
ServerCanJoin(source, kind, id)Serverreturn false, 'Text' verhindert Beitritt und Lobby-Start, z. B. im Knast
ServerKill(killer, victim, kind, id)ServerGewerteter Kill, z. B. Geld als Belohnung
ServerDeath(victim, killer, kind, id, teamkill)ServerJeder Tod, killer kann nil sein
ServerMatchEnded(lobbyId, result)ServerMatch beendet: { winner, score, map, teams }, winner = 'a', 'b' oder nil
ServerJoined(source, kind, id)ServerSpieler betritt eine Zone oder ein Match
ServerLeft(source, kind, id, reason)Serverreason = 'quit', 'drop', 'end', 'kick' oder 'stop'
Notify(message, type) / HelpNotify(text)ClientNotify und Hinweistext · Server: Notify(source, message, type)
ClientRevive(position)ClientWiederbeleben, z. B. eigenes Ambulance-Script
ClientDeath(kind) / ClientRespawn(kind)ClientTod und Respawn im PvP, z. B. Todesbildschirm ausblenden
ClientGiveLoadout(loadout)ClientWaffen geben und zurückgeben
ClientSetFuel(vehicle, fuel)ClientTank-Script
ClientVehicleSpawned(vehicle, plate, kind)ClientPvP-Fahrzeug gespawnt, z. B. Schlüssel geben
ClientVehicleMenu(vehicles, onSelect)ClientGaragenmenü auf Fahrzeug-Maps (Standard: ESX-Default-Menü)
ClientStateChanged(state)Client{ kind, id, team } beim Betreten, nil beim Verlassen, z. B. Handy oder eigenes HUD sperren

config/settings/config.server.lua und Sprachen

Discord-Webhooks für lobby (Lobby erstellt, Match gestartet, Match beendet, Lobby aufgelöst) und zones (Zone betreten und verlassen). '' schaltet einen Log aus. Alle Texte stehen in config/locales/ (eine Datei pro Sprache).

Im Spiel

  • Menü: E an einem PvP-Punkt. Das geht nur lebend, zu Fuß, in der normalen Dimension und nicht im Gangwar.
  • FFA und Only: Beitreten teleportiert dich in die Zone. Nach dem Tod geht es nach respawn.seconds an einem Spawn weiter. Oben siehst du Kills, Tode und die Spieler in der Zone.
  • Verlassen: /quitffa (oder dein quitCommand) bringt dich an den Ort zurück, an dem du beigetreten bist. Leben und Weste sind wie vorher, die eigenen Waffen kommen zurück. Der Befehl verlässt auch eine wartende Lobby.
  • Lobby erstellen: Map, Modus, Runden, Waffen und optional ein Passwort wählen. Neue Spieler kommen ins kleinere Team. Wechseln geht, solange das andere Team nicht voll ist. Nach 5 falschen Passwörtern ist die Lobby für dich 60 Sekunden gesperrt.
  • Owner: startet, mischt, kickt und löst auf. Geht der Owner, übernimmt das nächste Mitglied.
  • Start: Wer tot ist, in einer anderen Dimension, im Gangwar oder weiter als startRange von einem PvP-Punkt entfernt, fliegt aus der Lobby. Jedes Team braucht mindestens einen Spieler.
  • Match:
  • Jede Runde beginnt mit der Vorbereitung (eingefroren, ohne Waffen), danach gibt es Waffen und Weste.
  • Eine Runde gewinnt, wer das ganze Gegnerteam ausschaltet. Innerhalb einer Runde gibt es keinen Respawn. Fallen die letzten beiden gleichzeitig, gibt es keinen Punkt.
  • Läuft das Zeitlimit ab, gewinnt das Team mit mehr lebenden Spielern, bei Gleichstand gibt es keinen Punkt.
  • Das Match gewinnt, wer zuerst mehr als die Hälfte der Runden holt. Sind alle Runden gespielt, gewinnt der höhere Stand. Bei Gleichstand gibt es Entscheidungsrunden (overtimeRounds), danach ein Unentschieden.
  • Friendly Fire ist an. Ein Teamkill zählt als Tod, nicht als Kill.
  • Wer ein laufendes Match verlässt, bekommt eine Niederlage. Ist ein Team danach leer, gewinnt das andere sofort.
  • Danach kommen alle an ihren Ausgangsort zurück, die Lobby bleibt offen und wartet wieder.
  • Zuschauen: Nach spectateDelay Sekunden schaust du einem lebenden Teamkameraden zu. Unten in der Mitte stehen sein Name und die Pfeile. ← und → wechseln.
  • Garage (Fahrzeug-Maps): Während der Runde öffnet E am Garagen-Marker deines Teams die Fahrzeugliste. Jeder Spieler hat ein Fahrzeug, ein neues ersetzt das alte.
  • Leaderboard: Die besten Spieler pro Modus (Anzahl über leaderboardSize), sortiert nach Kills. Neue Werte erscheinen spätestens nach einer Minute, nach einem Match sofort.

Für Entwickler

lua
-- Server
local inPvp = exports.off_pvp:IsInPvp(source)        -- FFA, Only oder laufendes Match
local ffa = exports.off_pvp:IsFFA(source)
local only = exports.off_pvp:IsOnly(source)
local lobby = exports.off_pvp:IsLobby(source)        -- in einem laufenden Match
local inLobby = exports.off_pvp:IsInLobby(source)    -- Mitglied einer Lobby, wartend oder im Match
local info = exports.off_pvp:GetPvp(source)          -- { kind, id, team, alive, kills, deaths } oder nil
local removed = exports.off_pvp:RemoveFromPvp(source) -- holt den Spieler aus Zone, Match oder wartender Lobby, true/false
local stats = exports.off_pvp:GetStats(source)       -- { ffa = { kills, deaths }, only = { ... }, lobby = { kills, deaths, wins, losses } } oder nil

-- Client
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 } oder nil
  • Statebag offPvp: 'ffa', 'only' oder 'lobby', solange der Spieler in einer Zone oder einem Match ist.
  • offinventory: canOpen() in off_inventory/config/functions.lua sperrt Inventar und Kofferraum im PvP, sobald offpvp läuft.

Häufige Fehler

Beim Start meldet das Script Fehler und Hinweise in der Server-Konsole. Fehlerhafte Zonen und Maps werden dort genannt und ignoriert.

ProblemLösung
„Das geht gerade nicht.“ beim ÖffnenDu bist tot, in einer anderen Dimension oder im Gangwar.
Zone oder Map fehlt im MenüKonsole prüfen, der Eintrag hat einen Fehler (z. B. keine Spawns).
Kein Bild in der Zone oder Mapweb/dist/assets/maps/<id>.png fehlt.
Garage öffnet kein Menüesxmenudefault starten oder ClientVehicleMenu anpassen.
Spieler machen sich keinen SchadenIn ESX Config.EnablePVP = true setzen.
Ambulance-Script zeigt im PvP den TodesbildschirmIn ClientDeath ausblenden und in ClientRespawn wieder einblenden.
Nach einem Absturz am falschen OrtBeim nächsten Login geht es automatisch zurück zum Ausgangsort.
Resource-Neustart während eines MatchesAlle kommen zurück, das Match wird nicht gewertet. Besser nicht während Matches neu starten.

Noch nicht gekauft?

PVP im Shop ansehen