vampire heals up to 200 (g_startingHealth 200, bonus 0); plain README rewrite
QL caps vampiric healing at max health, which comes from g_startingHealth. With 100 + 100 bonus you spawn at 200 but can never heal back above 100. 200 + 0 spawns at 200, heals to 200, decays to 100 (measured on a test server). README rewritten for Linux servers and home PCs; file layout moved to HOW-IT-WORKS. Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
1 parent
acf625d72b
commit
266cc20b76
6 files changed
+104
-78
No files matched your search
+2
-2
@@ -14,9 +14,9 @@ QL_PASSWORD=
|
||||
|
||||
QL_MAXCLIENTS=16
|
||||
|
||||
# lgvamp LG only, 1:1 vampiric, no knockback, antilag (like x76 "Antilag LG Duel")
|
||||
# lgvamp LG only, 200 HP, 1:1 vampiric up to 200, no knockback, antilag (like x76 "Antilag LG Duel")
|
||||
# lgvamp_nolag same without antilag (like x76 "LG Duel EU #3")
|
||||
# lgvamp100 spawn with flat 100 HP instead of 200 (no health decay above 100)
|
||||
# lgvamp100 100 HP, vampiric up to 100, so health never decays
|
||||
QL_FACTORY=lgvamp
|
||||
QL_MAP=thunderstruck
|
||||
|
||||
|
||||
@@ -1,99 +1,102 @@
|
||||
# ql-lg-server
|
||||
|
||||
A **Quake Live lightning gun (LG) vampiric practice server** in Docker, set up with one command.
|
||||
A Quake Live server for lightning gun practice, run with Docker on Linux.
|
||||
|
||||
Players spawn with the LG only. Every hit heals you by the damage you deal (1:1 vampiric), there's no knockback and no items, and the server stays in warmup forever. Nobody has to ready up, there's no countdown, and you never get kicked back to a scoreboard. People join, pair off and duel on thunderstruck. This is how the popular LG duel servers (x76) run, rebuilt from scratch and documented so you can host your own.
|
||||
Everyone spawns with the lightning gun and 200 HP. Damage you deal heals you by the same amount, up to 200, and health above 100 drops back by 1 per second. There is no knockback and there are no items. The server never leaves warmup, so there is no match, no ready-up and no score reset: people join, pair up and duel. This is the same format the x76 LG duel servers use.
|
||||
|
||||
- One command: `./setup.sh` downloads the game (SteamCMD), builds minqlx, generates an RCON password and starts the server.
|
||||
- Public (listed in the in-game browser) or private (join by address, LAN/VPN): one setting.
|
||||
- Three variants: antilag, no antilag, flat 100 HP.
|
||||
- No warmup text on screen (small minqlx plugin), plus a welcome message.
|
||||
- **lgbot**, a training bot that plays LG like a duelist: ground strafing with uneven rhythm and fakes, holds LG range, never jumps. Aim and movement each go 1–5 and you can fine-tune the movement. Set it up with `./lgbot`.
|
||||
- Recovers on its own: Docker restarts it after a crash, a watchdog restarts it if it hangs, and it restarts daily while nobody is playing. It also takes nightly backups.
|
||||
- The RCON password never shows up in logs (Quake Live normally prints it there, see [How it works](docs/HOW-IT-WORKS.md)).
|
||||
It also has an optional training bot (`lgbot`) that only uses the lightning gun and strafes on the ground instead of jumping around.
|
||||
|
||||
## Quick start
|
||||
Linux only. Quake Live's dedicated server is only released for Linux, so there is no Windows version.
|
||||
|
||||
You need a Linux machine (a small VPS is fine: the server idles at ~3% of one core and ~50 MB RAM), [Docker with the compose plugin](https://docs.docker.com/engine/install/), `python3`, git, and ~2 GB of disk.
|
||||
## Requirements
|
||||
|
||||
- A Linux machine: a VPS, a home server or your own desktop. The server uses about 3% of one CPU core and 50 MB of RAM when idle.
|
||||
- Docker with the compose plugin ([install guide](https://docs.docker.com/engine/install/)). Your user must be in the `docker` group (`sudo usermod -aG docker $USER`, then log out and back in).
|
||||
- `git`, `python3`, about 2 GB of free disk space.
|
||||
- Players need Quake Live on Steam.
|
||||
|
||||
## Install
|
||||
|
||||
```sh
|
||||
git clone <this repo> ql-lg-server
|
||||
git clone https://git.userevolt.app/esef/ql-lg-server.git
|
||||
cd ql-lg-server
|
||||
./setup.sh # asks: server name, listed or not, join password, port
|
||||
./scripts/install-cron.sh # optional: watchdog, nightly backup, daily restart
|
||||
./setup.sh
|
||||
```
|
||||
|
||||
Run it as a normal user in the `docker` group, not as root. Setup prints the `/connect` addresses when it's done. Players need Quake Live on Steam.
|
||||
Run it as your normal user, not root. Setup asks four questions (server name, listed or not, join password, port; Enter keeps the default), then downloads the game from Steam (about 1 GB), builds minqlx and starts the server. At the end it prints the `/connect` addresses.
|
||||
|
||||
**Public server:** forward **UDP 27960** (your `QL_PORT`) on your router or firewall to this machine. Listed servers appear in the in-game browser after a few minutes.
|
||||
On a machine that runs all the time, also run `./scripts/install-cron.sh`. It adds a watchdog, a nightly backup and a daily restart (skipped while someone is playing).
|
||||
|
||||
## Settings
|
||||
## Joining
|
||||
|
||||
Everything per-server is in `.env` (created from [`.env.example`](.env.example) by setup). After editing it, apply the change with `docker compose up -d`.
|
||||
Players open the Quake Live console with `~` and type `/connect <address>:27960`.
|
||||
|
||||
| Setting | Default | |
|
||||
|---|---|---|
|
||||
| `QL_HOSTNAME` | `LG Vampiric FFA` | name in the browser (`^1`..`^7` colors work) |
|
||||
| `QL_LISTED` | `yes` | `no` = unlisted, join by address only |
|
||||
| `QL_PASSWORD` | empty | join password |
|
||||
| `QL_MAXCLIENTS` | `16` | |
|
||||
| `QL_FACTORY` | `lgvamp` | `lgvamp`, `lgvamp_nolag` or `lgvamp100`, see below |
|
||||
| `QL_MAP` | `thunderstruck` | stock map; workshop maps need extra setup |
|
||||
| `QL_WELCOME` | short rules text | sent to each player on join; empty = off |
|
||||
| `QL_RECORD` | `0` | `2` = record movement whenever two humans fight (for the lgbot, see docs/ADMIN.md) |
|
||||
| `QL_PORT` / `QL_RCON_PORT` | `27960` / `28960` | game UDP / RCON TCP (127.0.0.1 only) |
|
||||
| `QL_NAME` | `ql-lg` | Docker container name |
|
||||
- Same machine: `/connect 127.0.0.1:27960`
|
||||
- Same network: the machine's LAN address, e.g. `/connect 192.168.1.20:27960`
|
||||
- Over the internet: either forward UDP port 27960 on your router to this machine and give out your public IP, or put everyone on a VPN such as Tailscale or ZeroTier and use the VPN address.
|
||||
|
||||
### Game modes (factories)
|
||||
A listed server also shows up in the in-game server browser after a few minutes. That needs the port forward too.
|
||||
|
||||
Defined in [`home/baseq3/scripts/lgvamp.factories`](home/baseq3/scripts/lgvamp.factories):
|
||||
[docs/PLAYERS.md](docs/PLAYERS.md) is a page you can send to players.
|
||||
|
||||
| Factory | What | Seen on real servers |
|
||||
|---|---|---|
|
||||
| `lgvamp` | LG only, 1:1 vampiric, no knockback, antilag up to 240 ms, spawn 200 HP | x76 "Antilag LG Duel" |
|
||||
| `lgvamp_nolag` | same, antilag off (you have to lead your shots by your ping) | x76 "LG Duel EU #3" |
|
||||
| `lgvamp100` | same as `lgvamp` but spawn with 100 HP | no, our variant: health above 100 decays ~1 HP/s, so with 200 HP spawns you slowly lose health even when you aren't taking damage |
|
||||
## Everyday commands
|
||||
|
||||
Shared values: `g_startingWeapons 33` (gauntlet + LG), infinite ammo, `g_knockback 0`, no items, no `/kill`, no votes, instant weapon switch, `dmflags 28` (no self/fall damage), permanent warmup (`sv_warmupReadyPercentage 2`). Every value and why: [docs/HOW-IT-WORKS.md](docs/HOW-IT-WORKS.md).
|
||||
|
||||
## Running it
|
||||
Run these from the repo folder.
|
||||
|
||||
```sh
|
||||
./rcon status # who's on (./rcon alone = interactive console)
|
||||
./rcon addbot hunter 5 # a target to shoot at; ./rcon kick allbots
|
||||
./lgbot # LG training bot: asks aim/movement; ./lgbot --last | show | off
|
||||
./rcon status # who is on
|
||||
./rcon say hello
|
||||
python3 tools/qlq.py 127.0.0.1 27960 --status
|
||||
docker compose restart # restart; docker compose stop / start
|
||||
./rcon addbot hunter 5 # a normal bot to shoot at; ./rcon kick allbots removes bots
|
||||
./lgbot # add the training bot (asks aim and movement level)
|
||||
docker compose restart # restart the server
|
||||
docker compose stop # stop it (docker compose start to start again)
|
||||
./setup.sh --update # update the game from Steam
|
||||
```
|
||||
|
||||
Admins, bans, mutes, multiple servers, backups: [docs/ADMIN.md](docs/ADMIN.md). Share [docs/PLAYERS.md](docs/PLAYERS.md) with your players (joining, LG client settings).
|
||||
`./rcon` with no arguments opens a console prompt. The RCON password is generated by setup and read from `secrets/` automatically, so you never type it.
|
||||
|
||||
## Layout
|
||||
## Settings
|
||||
|
||||
```
|
||||
setup.sh install / re-run / --update
|
||||
.env.example settings template (.env is yours, not in git)
|
||||
docker-compose.yml the container; Dockerfile = Debian + 32-bit libs + Python 3.11 + SteamCMD
|
||||
rcon server console
|
||||
lgbot LG training bot setup (runs tools/lgbot_setup.py in the container)
|
||||
home/baseq3/ server.cfg (shared), scripts/lgvamp.factories (game modes),
|
||||
scripts/lgbot.bot + botfiles/bots/lgbot_*.c (training bot aim);
|
||||
local.cfg, secrets.cfg, mappool_lg.txt are generated from .env on each start
|
||||
home/minqlx-plugins/ nowarmuptext.py (hides warmup text), welcome.py, lgbot.py (training bot movement)
|
||||
tools/ mkcfg.sh (.env -> cfg), qlrcon.py (RCON client), qlq.py (health check),
|
||||
lgbot_setup.py (lgbot questions), tests (test_qlq, test_lgbot)
|
||||
scripts/ watchdog.sh, daily-restart.sh, backup.sh, install-cron.sh
|
||||
```
|
||||
All per-server settings live in `.env`. After changing it, run `docker compose up -d`.
|
||||
|
||||
Not in git (setup creates them): `server/` (game files, ~1.1 GB), `minqlx-build/`, `steamcmd-home/`, `secrets/`, `logs/`, `backups/`.
|
||||
| Setting | Default | |
|
||||
|---|---|---|
|
||||
| `QL_HOSTNAME` | `LG Vampiric FFA` | name in the server browser (`^1`..`^7` for colors) |
|
||||
| `QL_LISTED` | `yes` | `no` = not in the browser, join by address only |
|
||||
| `QL_PASSWORD` | empty | join password |
|
||||
| `QL_MAXCLIENTS` | `16` | |
|
||||
| `QL_FACTORY` | `lgvamp` | game mode, see below |
|
||||
| `QL_MAP` | `thunderstruck` | stock maps only |
|
||||
| `QL_WELCOME` | short rules text | message shown to each player on join; empty = none |
|
||||
| `QL_RECORD` | `0` | movement recording for the training bot, see [docs/ADMIN.md](docs/ADMIN.md) |
|
||||
| `QL_PORT` / `QL_RCON_PORT` | `27960` / `28960` | game port (UDP) / RCON port (TCP, local only) |
|
||||
| `QL_NAME` | `ql-lg` | Docker container name |
|
||||
|
||||
Game modes (`QL_FACTORY`):
|
||||
|
||||
| Mode | |
|
||||
|---|---|
|
||||
| `lgvamp` | the default: 200 HP, vampire up to 200, antilag up to 240 ms ping |
|
||||
| `lgvamp_nolag` | the same without antilag: you lead your shots by your ping |
|
||||
| `lgvamp100` | 100 HP and vampire up to 100, so health never drops on its own |
|
||||
|
||||
The modes are defined in [`home/baseq3/scripts/lgvamp.factories`](home/baseq3/scripts/lgvamp.factories).
|
||||
|
||||
## When something goes wrong
|
||||
|
||||
- **Setup says a port is in use:** another program (or another copy of this server) uses it. Set a different `QL_PORT` / `QL_RCON_PORT` in `.env` and run `./setup.sh` again.
|
||||
- **`permission denied` from Docker:** your user is not in the `docker` group yet, or you haven't logged out and back in since adding it.
|
||||
- **Friends can't connect but you can:** the port forward is missing or points to the wrong machine, or a firewall on the machine blocks UDP 27960 (`sudo ufw allow 27960/udp` on Ubuntu).
|
||||
- **The server doesn't come up:** `docker logs --tail 50 ql-lg` shows why. Treat logs as private.
|
||||
- **After a game update the server won't start:** run `./setup.sh` again. It keeps your settings and restores the minqlx files.
|
||||
|
||||
Admins, bans, the training bot's settings, backups and running several servers: [docs/ADMIN.md](docs/ADMIN.md). Why each setting is the way it is: [docs/HOW-IT-WORKS.md](docs/HOW-IT-WORKS.md).
|
||||
|
||||
## Credits
|
||||
|
||||
- [minqlx](https://github.com/MinoMino/minqlx) (GPL-3.0) by MinoMino: built from source by setup.sh, not included here.
|
||||
- [x76.gg](https://x76.gg/) for the LG duel server format this copies (FFA in permanent warmup, vampiric, no knockback).
|
||||
- [SEA LG Duels server](https://github.com/minhlong124/quake-lg-sea-server): the vampiric LG preset this started from.
|
||||
- Quake Live is © id Software / Bethesda. The dedicated server is downloaded from Steam (app 349090); no game files are in this repo.
|
||||
- [minqlx](https://github.com/MinoMino/minqlx) (GPL-3.0) by MinoMino. setup.sh builds it from source; it is not included here.
|
||||
- [x76.gg](https://x76.gg/) for the LG duel server format.
|
||||
- [SEA LG Duels server](https://github.com/minhlong124/quake-lg-sea-server), the preset this started from.
|
||||
- Quake Live is © id Software / Bethesda. The game server is downloaded from Steam (app 349090); no game files are in this repo.
|
||||
|
||||
License: MIT (this repo's configs and scripts).
|
||||
License: MIT, for this repo's configs and scripts.
|
||||
+1
-1
@@ -24,7 +24,7 @@ Everything below is run from the repo folder on the server machine.
|
||||
|
||||
## LG training bot: `./lgbot`
|
||||
|
||||
A bot that only plays LG, built to practise against: it strafes on the ground like a duelist (uneven left/right holds, fake direction changes), keeps LG range, pushes in when it's ahead on health and backs off when it's low, and never jumps or crouches. It shoots back. Aim and movement are separate, so "poor aim, best movement" is fine.
|
||||
A bot that only uses the LG, for practice: it strafes left and right on the ground with uneven timing and occasional fake direction changes, keeps LG range, can push in when it's ahead on health and back off when it's low, and never jumps or crouches. It shoots back. Aim and movement are set separately, so "poor aim, best movement" is possible. Its movement is rule-based and still looks mechanical next to a real player; work on that is ongoing.
|
||||
|
||||
```
|
||||
$ ./lgbot
|
||||
|
||||
+25
-2
@@ -1,6 +1,6 @@
|
||||
# How it works (and why)
|
||||
|
||||
Notes for anyone changing this setup. Each point below was hit while building it.
|
||||
Notes for anyone changing this setup: what each part does and which alternatives were tried.
|
||||
|
||||
## Permanent warmup instead of a match
|
||||
|
||||
@@ -31,7 +31,11 @@ minqlx is started with only our plugins (`qlx_plugins "nowarmuptext,welcome,lgbo
|
||||
|
||||
## Vampiric, measured
|
||||
|
||||
`g_vampiricDamage 1` heals exactly 1:1. Measured with `g_debugVampiricDamage 1` and two bots: an LG hit does 6 damage and the attacker gains 6. When both players hit each other at the same time, neither health changes. Spawning with 200 HP (`g_startingHealthBonus 100`) means health above 100 decays ~1/s, which is where the "I'm losing health" feeling comes from. `lgvamp100` removes it. (The stock `_training` factory uses 0.75.)
|
||||
`g_vampiricDamage 1` heals 1:1. Measured with `g_debugVampiricDamage 1` and two bots: an LG hit does 6 damage and the attacker gains 6. When both players hit each other at the same time, neither health changes. (The stock `_training` factory uses 0.75.)
|
||||
|
||||
Vampire healing stops at the player's max health, and QL sets max health from `g_startingHealth`. So the 200 HP modes use `g_startingHealth 200` with `g_startingHealthBonus 0`: you spawn with 200 and vampire heals up to 200. Health above 100 decays 1 per second down to 100 (measured on a test server). The obvious alternative, `g_startingHealth 100` plus `g_startingHealthBonus 100`, also spawns you at 200, but caps vampire at 100: players noticed they never healed back above 100. That was this repo's setting until 2026-10 and is what the SEA preset uses; x76 heals above 100.
|
||||
|
||||
`lgvamp100` uses 100 and 0: vampire up to 100, no decay. There is no separate cvar for a vampire cap (the game module's only vampire cvars are `g_vampiricDamage` and `g_debugVampiricDamage`).
|
||||
|
||||
## Antilag
|
||||
|
||||
@@ -47,6 +51,25 @@ Two more places the password shows up: `home/baseq3/zmqpass.txt` (QL writes it o
|
||||
|
||||
With `sv_master 0`, QL ignores `getstatus`, `getinfo` and Steam A2S queries (`sv_serverType` doesn't change that). So the health check (`tools/qlq.py`) uses the connect handshake: send `getchallenge` and the reply is `print "No Steam auth token."`. That works for listed and unlisted servers. Player info comes from RCON `status`, where bots have the address `bot`; that's how the daily restart can tell whether a human is on.
|
||||
|
||||
## Files
|
||||
|
||||
```
|
||||
setup.sh install / re-run / --update
|
||||
.env.example settings template (.env is yours, not in git)
|
||||
docker-compose.yml the container; Dockerfile = Debian + 32-bit libs + Python 3.11 + SteamCMD
|
||||
rcon server console
|
||||
lgbot training bot setup (runs tools/lgbot_setup.py in the container)
|
||||
home/baseq3/ server.cfg (shared), scripts/lgvamp.factories (game modes),
|
||||
scripts/lgbot.bot + botfiles/bots/lgbot_*.c (training bot aim);
|
||||
local.cfg, secrets.cfg, mappool_lg.txt are generated from .env on each start
|
||||
home/minqlx-plugins/ nowarmuptext.py (hides warmup text), welcome.py, lgbot.py (training bot movement)
|
||||
tools/ mkcfg.sh (.env -> cfg), qlrcon.py (RCON client), qlq.py (health check),
|
||||
lgbot_setup.py, lgbot_rec.py (recording analyzer), tests (python -m unittest in tools/)
|
||||
scripts/ watchdog.sh, daily-restart.sh, backup.sh, install-cron.sh
|
||||
```
|
||||
|
||||
Not in git (setup creates them): `server/` (game files, ~1.1 GB), `minqlx-build/`, `steamcmd-home/`, `secrets/`, `logs/`, `backups/`.
|
||||
|
||||
## Small things
|
||||
|
||||
- SteamCMD needs `+@sSteamCmdForcePlatformType linux`, or it fails with "Missing configuration".
|
||||
|
||||
+2
-2
@@ -13,7 +13,7 @@ Your server admin gives you the address. If the server is listed, it also shows
|
||||
## How it works
|
||||
|
||||
- You spawn with the **lightning gun** (and gauntlet), infinite ammo and 200 HP (100 HP on `lgvamp100` servers).
|
||||
- **Vampiric:** every point of damage you deal heals you by the same amount. Health above 100 slowly decays (~1 HP per second).
|
||||
- **Vampiric:** every point of damage you deal heals you by the same amount, up to your spawn health. Health above 100 drops by 1 per second.
|
||||
- **No knockback, no items, no fall or self damage.**
|
||||
- The server **stays in warmup on purpose.** There's no match to ready up for (F3 does nothing) and no scoreboard reset. Pair up with someone and duel, and switch partners whenever you like.
|
||||
- **Antilag** (most servers): your hits register where you saw the enemy, up to about 240 ms ping. On `lgvamp_nolag` servers you have to lead your shots by your ping.
|
||||
@@ -38,4 +38,4 @@ These are client-side; type them in the console, or put them in `baseq3/autoexec
|
||||
## Practice tips
|
||||
|
||||
- The [x76 strafe-aim guide](https://x76.gg/wiki/strafe-aim-guide/) covers the technique LG duels are about: keep the mouse steady, track by strafing with the keyboard and correct small amounts with the mouse.
|
||||
- Practice alone: ask an admin for **lgbot** (`./lgbot` on the server). It strafes like an LG duelist instead of jumping around, and its aim and movement are set separately, so you can train tracking against hard movement while it barely hits you, or the other way round.
|
||||
- Practice alone: ask the admin for **lgbot** (`./lgbot` on the server). It only uses the LG and strafes on the ground instead of jumping around. Its aim and movement levels are set separately, so you can practise tracking against fast movement while it barely hits you, or the other way round.
|
||||
@@ -12,8 +12,8 @@
|
||||
"cvars": {
|
||||
"g_startingWeapons": "33",
|
||||
"g_infiniteAmmo": "1",
|
||||
"g_startingHealth": "100",
|
||||
"g_startingHealthBonus": "100",
|
||||
"g_startingHealth": "200",
|
||||
"g_startingHealthBonus": "0",
|
||||
"g_startingArmor": "0",
|
||||
"g_vampiricDamage": "1",
|
||||
"g_knockback": "0",
|
||||
@@ -57,8 +57,8 @@
|
||||
"cvars": {
|
||||
"g_startingWeapons": "33",
|
||||
"g_infiniteAmmo": "1",
|
||||
"g_startingHealth": "100",
|
||||
"g_startingHealthBonus": "100",
|
||||
"g_startingHealth": "200",
|
||||
"g_startingHealthBonus": "0",
|
||||
"g_startingArmor": "0",
|
||||
"g_vampiricDamage": "1",
|
||||
"g_knockback": "0",
|
||||
|
||||
Reference in new issue
Block a user