diff --git a/GIDs b/GIDs index 5b9c791f1edc..78fcf9d4be0d 100644 --- a/GIDs +++ b/GIDs @@ -440,7 +440,7 @@ openbao:*:482: # free: 497 rustypaste:*:498: # free: 499 -# free: 500 +qw:*:500: qwfwd:*:501: birdvty:*:502: # free: 503 diff --git a/UIDs b/UIDs index abc54781310f..a4dbaa399ef7 100644 --- a/UIDs +++ b/UIDs @@ -446,7 +446,7 @@ openbao:*:482:482:daemon:0:0:OpenBao Daemon:/nonexistent:/usr/sbin/nologin # free: 497 rustypaste:*:498:498::0:0:Minimal file upload/pastebin service:/nonexistent:/usr/sbin/nologin # free: 499 -# free: 500 +qw:*:500:500::0:0:QuakeWorld Server:/nonexistent:/usr/sbin/nologin qwfwd:*:501:501::0:0:QuakeWorld Proxy:/nonexistent:/usr/sbin/nologin # free: 502 # free: 503 diff --git a/games/Makefile b/games/Makefile index 9afad89bf7e0..a4086e1704cd 100644 --- a/games/Makefile +++ b/games/Makefile @@ -475,6 +475,7 @@ SUBDIR += ksquares SUBDIR += ksudoku SUBDIR += ktuberling + SUBDIR += ktx SUBDIR += kubrick SUBDIR += kuklomenos SUBDIR += ladder diff --git a/games/ktx/Makefile b/games/ktx/Makefile new file mode 100644 index 000000000000..3f6c877e06dc --- /dev/null +++ b/games/ktx/Makefile @@ -0,0 +1,63 @@ +PORTNAME= ktx +DISTVERSIONPREFIX= v +DISTVERSION= 1.43 +CATEGORIES= games + +MAINTAINER= vvd@FreeBSD.org +COMMENT= Kombat Teams eXtreme is a popular QuakeWorld server modification +WWW= https://github.com/QW-Group/ktx/ + +LICENSE= GPLv2 + +RUN_DEPENDS= mvdsv:games/mvdsv + +USES= cmake dos2unix +DOS2UNIX_FILES= resources/example-configs/ktx/ktx.cfg \ + resources/example-configs/ktx/mvdsv.cfg \ + resources/example-configs/ktx/problem.cfg \ + resources/example-configs/ktx/race/routes/ztricks2.route +USE_GITHUB= yes +GH_ACCOUNT= QW-Group +USE_RC_SUBR= ${PORTNAME} +EXTRACT_AFTER_ARGS= --exclude ${PKGNAME}/.git* \ + --exclude ${PKGNAME}/build_cmake.sh \ + --exclude ${PKGNAME}/resources/example-configs/id1/"copy PAK0 and PAK1 here" \ + --exclude ${PKGNAME}/tools/cross-cmake \ + --exclude ${PKGNAME}/tools/vs \ + --no-same-owner --no-same-permissions +QWDIR= ${PREFIX}/quake +SUB_LIST= QWDIR=${QWDIR} QWUSER=${USERS} +USERS= qw +GROUPS= qw +PLIST_SUB= QWGROUP=${GROUPS} +PORTDATA= * + +.include "${.CURDIR}/../quake-data/Makefile.include" +.include + +do-install: + ${REINPLACE_CMD} -e 's|^set k_defmap|// set k_defmap|' \ + ${WRKSRC}/resources/example-configs/ktx/ktx.cfg + ${MKDIR} ${STAGEDIR}${DATADIR} + cd ${WRKSRC}/resources && \ + ${COPYTREE_SHARE} 'extralog logo' ${STAGEDIR}${DATADIR} + cd ${WRKSRC}/resources/example-configs && \ + ${COPYTREE_SHARE} '*' ${STAGEDIR}${QWDIR} + ${MKDIR} ${STAGEDIR}${QWDIR}/ktx/demos ${STAGEDIR}${QWDIR}/qw + ${MV} ${STAGEDIR}${QWDIR}/id1/maps ${STAGEDIR}${QWDIR}/qw + ${INSTALL_PROGRAM} ${BUILD_WRKSRC}/qwprogs.so \ + ${STAGEDIR}${DATADIR} + ${LN} -s ${DATADIR}/qwprogs.so ${STAGEDIR}${QWDIR}/ktx/ + ${LN} -s ${Q1DIR}/id1/pak0.pak ${STAGEDIR}${QWDIR}/id1/ + ${LN} -s ${Q1DIR}/id1/pak1.pak ${STAGEDIR}${QWDIR}/id1/ + ${LN} -s ${Q1DIR}/id1/maps ${STAGEDIR}${QWDIR}/id1/ + +.for f in port1 port2 port3 portffa servers + cd ${STAGEDIR}${QWDIR} && ${MV} ${f} ${f}.sample +.endfor +.for f in ktx.cfg listip.cfg matchless.cfg mvdfinish.qws mvdsv.cfg \ + port1.cfg port2.cfg port3.cfg problem.cfg pwd.cfg server.cfg vip_ip.cfg + cd ${STAGEDIR}${QWDIR}/ktx && ${MV} ${f} ${f}.sample +.endfor + +.include diff --git a/games/ktx/distinfo b/games/ktx/distinfo new file mode 100644 index 000000000000..ea3c5fe117e3 --- /dev/null +++ b/games/ktx/distinfo @@ -0,0 +1,3 @@ +TIMESTAMP = 1740182613 +SHA256 (QW-Group-ktx-v1.43_GH0.tar.gz) = 720f719c490d8e9e975b6bcab773e62bf4051c828ac394c61ab8f99e9e9c995b +SIZE (QW-Group-ktx-v1.43_GH0.tar.gz) = 1696285 diff --git a/games/ktx/files/ktx.in b/games/ktx/files/ktx.in new file mode 100755 index 000000000000..3e6e3075cc92 --- /dev/null +++ b/games/ktx/files/ktx.in @@ -0,0 +1,130 @@ +#!/bin/sh + +# PROVIDE: ktx +# REQUIRE: LOGIN +# KEYWORD: shutdown +# +# Add the following lines to /etc/rc.conf or /etc/rc.conf.local to +# enable ktx: +# ktx_(instance_)?enable (bool): Set to "NO" by default. +# Set it to "YES" to enable ktx. +# ktx_(instance_)?port (int): UDP port (default 27500). +# ktx_(instance_)?gamedir (str): Gamedir for ktx (default ktx). +# ktx_(instance_)?args (str): Custom additional arguments to be passed +# to ${__qwserver} (default empty). +# ktx_(instance_)?user (str): User to run ${__qwserver} as. Default +# to "%%QWUSER%%" created by the port. +# ktx_(instance_)?qwserver (path): Full path to QuakeWorld server to run ktx +# (default %%LOCALBASE%%/bin/mvdsv). +# ktx_(instance_)?log (path): Console log file (default +# ${__gamedir}/${name}_(instance_)?${__port}.log). +# ktx_(instance_)?randommaps (str): List of maps from which one is randomly +# selected to start the server (default empty). +# ktx_(instance_)?qwdir (path): QuakeWorld root directory +# (default %%QWDIR%%). +# ktx_instances (str): Set to "" by default. +# If defined, list of instances to enable. + +. /etc/rc.subr + +case $0 in +/etc/rc*) + # during boot (shutdown) $0 is /etc/rc (/etc/rc.shutdown), + # so get the name of the script from $_file + name=$_file + ;; +*) + name=$0 + ;; +esac + +name=${name##*/} +rcvar="${name}_enable" + +load_rc_config "${name}" + +eval "${rcvar}=\${${rcvar}:-'NO'}" +eval "__port=\${${name}_port:-'27500'}" +eval "__gamedir=\${${name}_gamedir:-'ktx'}" +eval "__args=\${${name}_args:-''}" +eval "__user=\${${name}_user:-'%%QWUSER%%'}" +eval "__qwserver=\${${name}_qwserver:-'%%LOCALBASE%%/bin/mvdsv'}" +eval "__log=\${${name}_log:-${__gamedir}/${name}_${__port}.log}" +eval "__randommaps=\${${name}_randommaps:-''}" +eval "__qwdir=\${${name}_qwdir:-'%%QWDIR%%'}" +eval "${name}_chdir=${__qwdir}" +eval "__instances=\${${name}_instances:-''}" + +pidfiledir="/var/run" +pidfile="${pidfiledir}/${name}.pid" + +if [ -n "$2" ]; then + instance="$2" + load_rc_config ${name}_${instance} + case "${__instances}" in + "$2 "*|*" $2 "*|*" $2"|"$2") + eval "__port=\${${name}_${instance}_port:-${__port}}" + eval "__gamedir=\${${name}_${instance}_gamedir:-${__gamedir}}" + eval "__args=\${${name}_${instance}_args:-${__args}}" + eval "__user=\${${name}_${instance}_user:-${__user}}" + eval "__qwserver=\${${name}_${instance}_qwserver:-${__qwserver}}" + eval "__log=\${${name}_${instance}_log:-${__gamedir}/${name}_${instance}_${__port}.log}" + eval "__randommaps=\${${name}_${instance}_randommaps:-${__randommaps}}" + eval "__qwdir=\${${name}_${instance}_qwdir:-${__qwdir}}" + eval "${name}_chdir=${__qwdir}" + pidfile="${pidfiledir}/${name}_${instance}.pid" + ;; + *) + err 1 "$2 not found in ${name}_instances" ;; + esac +else + if [ -n "${__instances}" -a -n "$1" ]; then + for instance in ${__instances}; do + eval "_enable=\${${name}_${instance}_enable}" + eval "__enable=\${_enable:-\${${name}_enable}}" + case "${__enable}" in + [Nn][Oo]|[Ff][Aa][Ll][Ss][Ee]|[Oo][Ff][Ff]|0) + continue + ;; + [Yy][Ee][Ss]|[Tt][Rr][Uu][Ee]|[Oo][Nn]|1) + ;; + *) + if [ -z "${_enable}" ]; then + _var=${name}_enable + else + _var=${name}_${instance}_enable + fi + warn "Bad value '${__enable}' for ${_var}. " \ + "Instance ${instance} skipped." + continue + ;; + esac + echo "===> ${name} instance: ${instance}" + %%PREFIX%%/etc/rc.d/${name} $1 ${instance} + retcode="$?" + if [ "0${retcode}" -eq 0 ]; then + success="${instance} ${success}" + else + failed="${instance} (retcode=${retcode}) ${failed}" + fi + done + echo "===> ${name} instances success: ${success}" + echo "===> ${name} instances failed: ${failed}" + exit 0 + fi +fi + +if [ -n "${__randommaps}" -a \( "x$1" = "xstart" -o "x$1" = "xrestart" \) ]; then + RAND=`/usr/bin/head -c2 /dev/urandom | /usr/bin/od -An -t d` + #RAND=`echo | awk '{srand(); print rand()*1000000}'` + #RAND=$((`/bin/date +%N | /usr/bin/sed 's|^[0]*||'`+0)) + LEN=`echo ${__randommaps} | /usr/bin/wc -w` + N=$((${RAND} % ${LEN} + 1)) + MAP=`echo ${__randommaps} | /usr/bin/awk "{print \\$${N}}"` + __args="${__args} +map ${MAP}" +fi + +command="/usr/sbin/daemon" +command_args="-P ${pidfile} -u ${__user} -R 5 -f -H -o ${__log} -m 3 ${__qwserver} -port ${__port} -game ${__gamedir} ${__args}" + +run_rc_command "$1" diff --git a/games/ktx/files/patch-resources_example-configs_ktx_configs_usermodes_matchless_default.cfg b/games/ktx/files/patch-resources_example-configs_ktx_configs_usermodes_matchless_default.cfg new file mode 100644 index 000000000000..f10298dabc00 --- /dev/null +++ b/games/ktx/files/patch-resources_example-configs_ktx_configs_usermodes_matchless_default.cfg @@ -0,0 +1,45 @@ +--- resources/example-configs/ktx/configs/usermodes/matchless/default.cfg.orig 2024-03-10 07:30:18 UTC ++++ resources/example-configs/ktx/configs/usermodes/matchless/default.cfg +@@ -4,7 +4,7 @@ set k_matchless_max_idle_time 0 // maximum time a + // matchless settings + set k_matchless_countdown 0 // countdown in matchless mode (0 = off, 1 = on) + set k_matchless_max_idle_time 0 // maximum time a user can be idle before being forced to spectator in matchless +-set k_pow_min_players 1 // number of players on server required for powerups to be turned on ++set k_pow_min_players 3 // number of players on server required for powerups to be turned on + set k_pow_check_time 10 // how often should ktx check if the k_pow_min_players requirement has been met (seconds) + set k_no_vote_map 0 // allow map voting and /next_map (0 = allow voting, 1 = disallow voting) + set k_no_vote_break 1 // allow vote break (0 = allow break, 1 = disallow break) +@@ -14,14 +14,27 @@ samelevel 0 // change level a + + // Other settings + samelevel 0 // change level after match ends +-timelimit 10 // round timelimit in minutes +-maxclients 8 // maximum number of clients to connect ++timelimit 5 // round timelimit in minutes ++fraglimit 30 ++maxclients 24 // maximum number of clients to connect ++maxspectators 8 + set k_specktalk 1 // spectators can talk to players during round + + // map rotation +-set k_ml_0 "dm2" +-set k_ml_1 "dm3" +-set k_ml_2 "e1m2" +-//set k_ml_3 "e1m3" // etc ++set k_ml_0 "bravado" ++set k_ml_1 "ztndm2" ++set k_ml_2 "aerowalk" ++set k_ml_3 "monsoon" ++set k_ml_4 "ztndm5" ++set k_ml_5 "shifter" ++set k_ml_6 "spinev2" ++set k_ml_7 "ztndm3" ++set k_ml_8 "catalyst" ++set k_ml_9 "toxicity" ++set k_ml_10 "ztndm4" ++set k_ml_11 "pkeg1" ++set k_ml_12 "ztndm6" ++set k_ml_13 "skyhigh" ++set k_ml_14 "pocket" + + set k_random_maplist 0 // select random map from k_ml_XXX variables (0 = off, 1 = on) diff --git a/games/ktx/files/patch-socd b/games/ktx/files/patch-socd new file mode 100644 index 000000000000..03e80334b71e --- /dev/null +++ b/games/ktx/files/patch-socd @@ -0,0 +1,192 @@ +From 631b375f3dbb150c3f37430a0a45f237ffac8153 Mon Sep 17 00:00:00 2001 +From: blaze +Date: Tue, 30 Jul 2024 22:49:02 -0700 +Subject: [PATCH] socd detection + +--- + .gitignore | 3 +++ + include/progs.h | 11 ++++++++ + src/client.c | 61 ++++++++++++++++++++++++++++++++++++++++++++ + src/commands.c | 32 +++++++++++++++++++++-- + src/stats.c | 8 ++++++ + src/world.c | 2 ++ + tools/vs/ktx.vcxproj | 34 ++++++++++++++++++------ + 7 files changed, 141 insertions(+), 10 deletions(-) + +--- include/progs.h.orig ++++ include/progs.h +@@ -944,6 +944,17 @@ typedef struct gedict_s + float fIllegalFPSWarnings; + // ILLEGALFPS] + ++// SOCD detectioin ++ float fStrafeChangeCount; ++ float fFramePerfectStrafeChangeCount; ++ int socdDetected; ++ int socdChecksCount; ++ float fLastSideMoveSpeed; ++ int matchStrafeChangeCount; ++ int matchPerfectStrafeCount; ++ int nullStrafeCount; ++// SOCD ++ + float shownick_time; // used to force centerprint is off at desired time + clientType_t ct; // client type for client edicts + // { timing +--- src/client.c.orig ++++ src/client.c +@@ -1658,6 +1658,16 @@ void ClientConnect() + SendIntermissionToClient(); + } + ++// SOCD ++ self->socdChecksCount = 0; ++ self->socdDetected = 0; ++ self->fStrafeChangeCount = 0; ++ self->fFramePerfectStrafeChangeCount = 0; ++ self->fLastSideMoveSpeed = 0; ++ self->matchStrafeChangeCount = 0; ++ self->matchPerfectStrafeCount = 0; ++ self->nullStrafeCount = 0; ++ + // ILLEGALFPS[ + + // Zibbo's frametime checking code +@@ -3520,6 +3530,57 @@ void PlayerPreThink() + } + #endif + ++// SOCD detection ++ { ++ float fSideMoveSpeed = self->movement[1]; ++ ++ if ((fSideMoveSpeed != 0) && (fSideMoveSpeed != self->fLastSideMoveSpeed) && (self->nullStrafeCount < 3)) //strafechange ++ { ++ self->fStrafeChangeCount += 1; ++ if (match_in_progress) ++ self->matchStrafeChangeCount += 1; ++ ++ if ((fSideMoveSpeed != 0) && (self->fLastSideMoveSpeed != 0)) ++ { ++ self->fFramePerfectStrafeChangeCount += 1; ++ if (match_in_progress) ++ self->matchPerfectStrafeCount += 1; ++ } ++ ++ self->nullStrafeCount = 0; ++ } ++ else ++ { ++ if (0 == fSideMoveSpeed) ++ self->nullStrafeCount += 1; ++ else ++ self->nullStrafeCount = 0; ++ } ++ ++ self->fLastSideMoveSpeed = fSideMoveSpeed; ++ ++ if (self->fStrafeChangeCount >= 16) ++ { ++ if (self->fFramePerfectStrafeChangeCount / self->fStrafeChangeCount >= 0.75) ++ { ++ int k_allow_socd_warning = cvar("k_allow_socd_warning"); ++ ++ self->socdDetected += 1; ++ ++ if ((!match_in_progress) && (!self->isBot) && k_allow_socd_warning) ++ { ++ G_bprint(PRINT_HIGH, ++ "Warning! %s: SOCD movement assistance detected. Please disable iDrive or keyboard SOCD features.\n", ++ self->netname); ++ } ++ } ++ ++ self->socdChecksCount += 1; ++ self->fStrafeChangeCount = 0; ++ self->fFramePerfectStrafeChangeCount = 0; ++ } ++ } ++ + // ILLEGALFPS[ + + self->fAverageFrameTime += g_globalvars.frametime; +--- src/commands.c.orig ++++ src/commands.c +@@ -8114,16 +8114,47 @@ void fcheck() + + if (!is_real_adm(self)) + { +- if (strneq(arg_x, "f_version") && strneq(arg_x, "f_modified") && strneq(arg_x, "f_server")) ++ if (strneq(arg_x, "f_version") && strneq(arg_x, "f_modified") && strneq(arg_x, "f_server") && strneq(arg_x, "f_movement")) + { + G_sprint(self, 2, "You are not allowed to check \020%s\021\n" +- "available checks are: f_version, f_modified and f_server\n", ++ "available checks are: f_version, f_modified, f_server and f_movement\n", + arg_x); + + return; + } + } + ++ if (streq(arg_x, "f_movement")) ++ { ++ G_bprint(2, "%s is checking \020%s\021\n", self->netname, arg_x); ++ ++ for (i = 1; i <= MAX_CLIENTS; i++) ++ { ++ if (!strnull(g_edicts[i].netname)) ++ { ++ if (g_edicts[i].socdDetected > 0) ++ { ++ G_bprint(2, "%s: SOCD movement assistance detected!\n", g_edicts[i].netname); ++ } ++ else ++ { ++ if (g_edicts[i].socdChecksCount >= 2) ++ { ++ G_bprint(2, "%s: no assistance detected.\n", g_edicts[i].netname); ++ } ++ else ++ { ++ G_bprint(2, "%s: not enough movement to run SOCD detection. Please move around a map.\n", g_edicts[i].netname); ++ } ++ } ++ G_bprint(2, "%s: %s:%d/%d %s:%d/%d\n", redtext("Movement"), redtext("Perfect strafes"), ++ g_edicts[i].matchPerfectStrafeCount, g_edicts[i].matchStrafeChangeCount, ++ redtext("SOCD detections"), g_edicts[i].socdDetected, g_edicts[i].socdChecksCount); ++ } ++ } ++ return; ++ } ++ + for (i = 1; i <= MAX_CLIENTS; i++) + { + if (g_edicts[i].f_checkbuf) +--- src/stats.c.orig ++++ src/stats.c +@@ -763,6 +763,14 @@ void OnePlayerStats(gedict_t *p, int tp) + p->ps.vel_frames > 0 ? p->ps.velocity_sum / p->ps.vel_frames : 0.); + } + ++ if (!p->isBot) ++ { ++ G_bprint(2, "%s: %s:%d/%d %s:%d/%d\n", redtext("Movement"), redtext("Perfect strafes"), ++ p->matchPerfectStrafeCount, p->matchStrafeChangeCount, redtext("SOCD detections"), ++ p->socdDetected, p->socdChecksCount); ++ } ++ ++ + // armors + megahealths + if (!lgc_enabled()) + { +--- src/world.c.orig ++++ src/world.c +@@ -1000,6 +1000,8 @@ void FirstFrame() + + RegisterCvar("k_teamoverlay"); // q3 like team overlay + ++ RegisterCvar("k_allow_socd_warning"); // socd ++ + // { SP + RegisterCvarEx("k_monster_spawn_time", "20"); + // } diff --git a/games/ktx/pkg-descr b/games/ktx/pkg-descr new file mode 100644 index 000000000000..2a698696b7c8 --- /dev/null +++ b/games/ktx/pkg-descr @@ -0,0 +1,7 @@ +KTX (Kombat Teams eXtreme) is a popular QuakeWorld server modification, +adding numerous features to the core features of the server. + +Although it had been developed to be QuakeWorld server agnostic, it +has over the years been developed very close to MVDSV to which it has +become an extent, thus compatibility with other QuakeWorld servers +might not have been maintained. diff --git a/games/ktx/pkg-message b/games/ktx/pkg-message new file mode 100644 index 000000000000..112a2b8c3e04 --- /dev/null +++ b/games/ktx/pkg-message @@ -0,0 +1,17 @@ +[ +{ type: install + message: <