]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/commitdiff
Merge branch 'terencehill/intermission_restart_fix' into 'master'
authorterencehill <piuntn@gmail.com>
Sun, 25 Feb 2024 09:55:47 +0000 (09:55 +0000)
committerterencehill <piuntn@gmail.com>
Sun, 25 Feb 2024 09:55:47 +0000 (09:55 +0000)
Fix restart applying different gametype if called after gametype vote

See merge request xonotic/xonotic-data.pk3dir!1256

85 files changed:
.gitignore
.gitlab-ci.yml
.tx/merge-base
common.da.po
common.fr.po
common.ja_JP.po
common.la.po
common.tr.po
common.zh_CN.po
common.zh_HK.po
common.zh_TW.po
gamemodes-server.cfg
languages.txt
physicsCPMA.cfg
physicsFruit.cfg
physicsHavoc.cfg
physicsLeeStricklin-ModdedFruit.cfg
physicsLeeStricklin.cfg
physicsLeeStricklinOld.cfg
physicsLzd.cfg
physicsNexuiz10.cfg
physicsNexuiz11.cfg
physicsNexuiz151.cfg
physicsNexuiz151b.cfg
physicsNexuiz16rc1.cfg
physicsNexuiz20.cfg
physicsNexuiz25.cfg
physicsNexuiz26.cfg
physicsNoQWBunny-nexbased.cfg
physicsOverkill.cfg
physicsQ.cfg
physicsQ2.cfg
physicsQ2a.cfg
physicsQ3.cfg
physicsQBF.cfg
physicsQBFplus.cfg
physicsSamual.cfg
physicsWarsow.cfg
physicsWarsowClassicBunny.cfg
physicsWarsowDev.cfg
physicsX.cfg
physicsX010.cfg
physicsX07.cfg
physicsXDF.cfg
physicsXDFLight.cfg
qcsrc/client/main.qc
qcsrc/client/view.qc
qcsrc/common/gamemodes/gamemode/clanarena/sv_clanarena.qc
qcsrc/common/gamemodes/gamemode/freezetag/sv_freezetag.qc
qcsrc/common/mapinfo.qc
qcsrc/common/mapinfo.qh
qcsrc/common/mapobjects/func/door.qc
qcsrc/common/mapobjects/func/door.qh
qcsrc/common/mapobjects/func/plat.qc
qcsrc/common/mapobjects/platforms.qc
qcsrc/common/mapobjects/subs.qc
qcsrc/common/mapobjects/teleporters.qc
qcsrc/common/mutators/mutator/damagetext/cl_damagetext.qc
qcsrc/common/mutators/mutator/damagetext/cl_damagetext.qh
qcsrc/common/mutators/mutator/damagetext/sv_damagetext.qc
qcsrc/common/mutators/mutator/overkill/okhmg.qc
qcsrc/common/mutators/mutator/overkill/okhmg.qh
qcsrc/common/mutators/mutator/overkill/okmachinegun.qh
qcsrc/common/mutators/mutator/overkill/okrpc.qc
qcsrc/common/mutators/mutator/overkill/okrpc.qh
qcsrc/common/mutators/mutator/powerups/powerup/invisibility.qh
qcsrc/common/mutators/mutator/powerups/powerup/speed.qh
qcsrc/common/notifications/all.qh
qcsrc/common/playerstats.qc
qcsrc/common/resources/resources.qh
qcsrc/common/scores.qh
qcsrc/common/stats.qh
qcsrc/lib/registry.qh
qcsrc/lib/string.qh
qcsrc/menu/xonotic/playerlist.qc
qcsrc/server/command/sv_cmd.qc
qcsrc/server/intermission.qc
qcsrc/server/intermission.qh
qcsrc/server/main.qc
qcsrc/server/mapvoting.qc
qcsrc/server/mapvoting.qh
qcsrc/server/world.qc
qcsrc/tools/sv_game-hashtest.sh [new file with mode: 0755]
xonotic-client.cfg
xonotic-server.cfg

index cfb3f6fcb5945323788e0223f631b80fbc7c6947..86069d63def660981d90f2dd315662886d20c53a 100644 (file)
@@ -5,3 +5,11 @@ cscope*
 .DS_Store
 .idea/
 Thumbs.db
+
+# sv_game hashtest local test re-use
+data/maps/
+data/maps/_init.bsp
+data/maps/stormkeep.mapinfo
+data/maps/stormkeep.waypoints
+data/maps/stormkeep.waypoints.cache
+data/stormkeep.pk3
index fcb8cfbe05da5dae10b82bbc63ba083383e2efa4..a36862c5628bfbc674b509ecaba278afa92a2e69 100644 (file)
-workflow:\r
-  rules:\r
-    - if: $CI_COMMIT_MESSAGE =~ /Transifex autosync/\r
-      when: never\r
-    - when: always\r
-\r
-before_script:\r
-  - ln -s $PWD data/xonotic-data.pk3dir\r
-\r
-  - export MAKEFLAGS=-j$(nproc); echo MAKEFLAGS=$MAKEFLAGS\r
-#   FIXME: -march=native -mtune=native _changes the hash_, why?!?\r
-# - export CC="gcc -pipe -march=native -mtune=native"\r
-  - export CC="gcc -pipe"\r
-\r
-  - >\r
-    if wget -nv https://beta.xonotic.org/pipeline-bin/gmqcc ; then\r
-      export QCC="$PWD/gmqcc"\r
-      chmod +x "$QCC"\r
-    else\r
-      git clone --depth=1 --branch=main https://gitlab.com/xonotic/gmqcc.git gmqcc\r
-      make -C gmqcc || exit 1\r
-      export QCC="$PWD/gmqcc/gmqcc"\r
-    fi\r
-\r
-  # Makefile: don't complain about lack of tags (fetching them is slow)\r
-  - export QCCFLAGS_WATERMARK=gitlab_pipeline\r
-  # Makefile: don't compress anything or complain about lack of zip program\r
-  - export ZIP=/bin/true\r
-\r
-test_compilation_units:\r
-  rules:\r
-    - changes:\r
-      - qcsrc/**/*\r
-  stage: test\r
-  script:\r
-    - make test\r
-\r
-test_sv_game:\r
-  stage: test\r
-  script:\r
-    - >\r
-      if wget -nv https://beta.xonotic.org/pipeline-bin/xonotic-linux64-dedicated ; then\r
-        export ENGINE="$PWD/xonotic-linux64-dedicated"\r
-        chmod +x "$ENGINE"\r
-      else\r
-        git clone --depth=1 --branch=div0-stable https://gitlab.com/xonotic/darkplaces.git darkplaces\r
-        make -C darkplaces sv-release || exit 1\r
-        export ENGINE="$PWD/darkplaces/darkplaces-dedicated -xonotic"\r
-      fi\r
-    - export ENGINE="$ENGINE -noconfig -nohome"\r
-\r
-    - make qc || exit 1\r
-\r
-    - mkdir -p data/maps\r
-    - wget -nv -O data/maps/_init.bsp https://gitlab.com/xonotic/xonotic-maps.pk3dir/raw/master/maps/_init/_init.bsp\r
-\r
-    - while read LINE; do\r
-        echo $LINE;\r
-        [ "$LINE" = "All tests OK" ] && PASS=1;\r
-      done < <(${ENGINE} +developer 1 +map _init +sv_cmd runtest +wait +quit)\r
-    - test "$PASS" = "1" || { echo 'sv_cmd runtest failed!'; exit 1; }\r
-\r
-    - ${ENGINE} +map _init +sv_cmd dumpnotifs +wait +quit\r
-    - diff notifications.cfg data/data/notifications_dump.cfg ||\r
-        { echo 'Please update notifications.cfg using `dumpnotifs`!'; exit 1; }\r
-\r
-#    - wget -nv -O data/stormkeep.pk3 http://beta.xonotic.org/autobuild-bsp/latest/stormkeep.pk3\r
-# ^^ INCORRECT: /latest/stormkeep.pk3 is the most recently built, not necessarily the one built from master!\r
-# we can't get the one from master directly as there's no /stable/stormkeep.pk3 or /master/stormkeep.pk3\r
-# and we can't run misc/tools/xonotic-map-compiler-autobuild as it uses commit hashes from xonotic-maps.pk3dir to generate filenames\r
-# but the autobuild server can run it and provide us the resulting pk3:\r
-    - wget -nv -O data/stormkeep.pk3 https://beta.xonotic.org/pipeline-bin/stormkeep.pk3\r
-# see also: misc/infrastructure/xonotic-release-build.cron\r
-    - wget -nv -O data/maps/stormkeep.mapinfo https://gitlab.com/xonotic/xonotic-maps.pk3dir/raw/master/maps/stormkeep.mapinfo\r
-    - wget -nv -O data/maps/stormkeep.waypoints https://gitlab.com/xonotic/xonotic-maps.pk3dir/raw/master/maps/stormkeep.waypoints\r
-    - wget -nv -O data/maps/stormkeep.waypoints.cache https://gitlab.com/xonotic/xonotic-maps.pk3dir/raw/master/maps/stormkeep.waypoints.cache\r
-\r
-    - EXPECT=27f38dfbbd72e4bf8f9b540882d5ccbe\r
-    - HASH=$(${ENGINE} +exec serverbench.cfg\r
-      | tee /dev/stderr\r
-      | grep '^:'\r
-      | grep -v '^:gamestart:'\r
-      | grep -v '^:anticheat:'\r
-      | md5sum | awk '{ print $1 }')\r
-    - echo 'expected:' $EXPECT\r
-    - echo '  actual:' $HASH\r
-    - test "$HASH" == "$EXPECT"\r
-    - exit $?\r
-\r
-\r
-# NOTE: The generated docs are incomplete - they don't contain code behind SVQC CSQC MENUQC GAMEQC ifdefs.\r
-# With them added to PREDEFINED, it would take over half an hour to generate the docs and even then\r
-# they might not be complete. Doxygen doesn't handle #elif and might not understand some QC definitions.\r
-#doxygen:  # rename to 'pages' when gitlab.com allows pages to exceed 100MiB\r
-#  before_script:\r
-#    - ln -s $PWD data/xonotic-data.pk3dir # is this needed?\r
-#    - apt-get update\r
-#    - apt-get -y install doxygen graphviz\r
-#  stage: deploy\r
-#  script:\r
-#    - cd qcsrc && doxygen\r
-#    - mv html ../public\r
-#    - mkdir -p ~/.ssh\r
-#    - for i in {0..0}; do eval $(printf "echo \$id_rsa_%02d\n" $i) >> ~/.ssh/id_rsa_base64; done\r
-#    - base64 --decode ~/.ssh/id_rsa_base64 > ~/.ssh/id_rsa\r
-#    - chmod 600 ~/.ssh/id_rsa\r
-#    - echo -e "Host *\n\tStrictHostKeyChecking no\n\tLogLevel ERROR\n" >> ~/.ssh/config\r
-#    - git config --global user.name "Gitlab CI"\r
-#    - git config --global user.email "<>"\r
-#    - git clone --single-branch --depth 1 ${DEPLOY_HOST}:${DEPLOY_REPO} ~/deploy_\r
-#    - mkdir ~/deploy && mv ~/deploy_/.git ~/deploy && rm -r ~/deploy_\r
-#    - cp -r ../public/* ~/deploy\r
-#    - cd ~/deploy && git add -A . && git commit -m "Deploy ${CI_BUILD_REF}" && git push origin gh-pages\r
-#  artifacts:\r
-#    paths:\r
-#      - public\r
-#  only:\r
-#    - master\r
+workflow:
+  rules:
+    - if: $CI_COMMIT_MESSAGE =~ /Transifex autosync/
+      when: never
+    - when: always
+
+before_script:
+  - ln -s $PWD data/xonotic-data.pk3dir
+
+  - export MAKEFLAGS=-j$(nproc); echo MAKEFLAGS=$MAKEFLAGS
+  - export CC="gcc -pipe"
+
+  - >
+    if wget -nv https://beta.xonotic.org/pipeline-bin/gmqcc ; then
+      export QCC="$PWD/gmqcc"
+      chmod +x "$QCC"
+    else
+      git clone --depth=1 --branch=main https://gitlab.com/xonotic/gmqcc.git gmqcc
+      make -C gmqcc || exit 1
+      export QCC="$PWD/gmqcc/gmqcc"
+    fi
+
+  # Makefile: don't complain about lack of tags (fetching them is slow)
+  - export QCCFLAGS_WATERMARK=gitlab_pipeline
+  # Makefile: don't compress anything or complain about lack of zip program
+  - export ZIP=/bin/true
+
+test_compilation_units:
+  rules:
+    - changes:
+      - qcsrc/**/*
+  stage: test
+  script:
+    - make test
+
+test_sv_game:
+  stage: test
+  script:
+    - export EXPECT=9ee7ce44ffe60a5e1cf29a2b82f79ebf
+    - qcsrc/tools/sv_game-hashtest.sh
+    - exit $?
+
+
+# NOTE: The generated docs are incomplete - they don't contain code behind SVQC CSQC MENUQC GAMEQC ifdefs.
+# With them added to PREDEFINED, it would take over half an hour to generate the docs and even then
+# they might not be complete. Doxygen doesn't handle #elif and might not understand some QC definitions.
+#doxygen:  # rename to 'pages' when gitlab.com allows pages to exceed 100MiB
+#  before_script:
+#    - ln -s $PWD data/xonotic-data.pk3dir # is this needed?
+#    - apt-get update
+#    - apt-get -y install doxygen graphviz
+#  stage: deploy
+#  script:
+#    - cd qcsrc && doxygen
+#    - mv html ../public
+#    - mkdir -p ~/.ssh
+#    - for i in {0..0}; do eval $(printf "echo \$id_rsa_%02d\n" $i) >> ~/.ssh/id_rsa_base64; done
+#    - base64 --decode ~/.ssh/id_rsa_base64 > ~/.ssh/id_rsa
+#    - chmod 600 ~/.ssh/id_rsa
+#    - echo -e "Host *\n\tStrictHostKeyChecking no\n\tLogLevel ERROR\n" >> ~/.ssh/config
+#    - git config --global user.name "Gitlab CI"
+#    - git config --global user.email "<>"
+#    - git clone --single-branch --depth 1 ${DEPLOY_HOST}:${DEPLOY_REPO} ~/deploy_
+#    - mkdir ~/deploy && mv ~/deploy_/.git ~/deploy && rm -r ~/deploy_
+#    - cp -r ../public/* ~/deploy
+#    - cd ~/deploy && git add -A . && git commit -m "Deploy ${CI_BUILD_REF}" && git push origin gh-pages
+#  artifacts:
+#    paths:
+#      - public
+#  only:
+#    - master
index 4b7a75e6198d50f85cfa3fabff756a2d07ed03c8..0514b49646ee49c95abcb0e445a576eea50306ae 100644 (file)
@@ -1 +1 @@
-Mon Dec 11 07:23:08 AM CET 2023
+Fri Jan 26 07:22:59 AM CET 2024
index 727d176702e0ad0eb7c27b0cee101071fdd1aceb..1482a13b946ff57fdab94a5cc026338aee151d44 100644 (file)
@@ -3,6 +3,8 @@
 # This file is distributed under the same license as the PACKAGE package.
 #
 # Translators:
+# A Person, 2023
+# A Person, 2023
 # Archy Coder, 2022
 # Archy Coder, 2022
 msgid ""
@@ -54,12 +56,12 @@ msgstr ""
 
 #: qcsrc/client/hud/panel/centerprint.qc:211
 msgid "Generic message"
-msgstr ""
+msgstr "Generisk besked"
 
 #: qcsrc/client/hud/panel/centerprint.qc:293
 #: qcsrc/client/hud/panel/centerprint.qc:303
 msgid "vs"
-msgstr ""
+msgstr "mod"
 
 #: qcsrc/client/hud/panel/chat.qc:165
 msgid "^3Player^7: This is the chat area."
@@ -102,7 +104,7 @@ msgstr "næste våben"
 #: qcsrc/client/hud/panel/infomessages.qc:107
 #: qcsrc/client/hud/panel/infomessages.qc:111
 msgid "previous weapon"
-msgstr ""
+msgstr "forrige våben"
 
 #: qcsrc/client/hud/panel/infomessages.qc:111
 #, c-format
@@ -118,12 +120,12 @@ msgstr ""
 #: qcsrc/client/hud/panel/infomessages.qc:115
 #: qcsrc/common/vehicles/cl_vehicles.qc:171
 msgid "drop weapon"
-msgstr ""
+msgstr "lig våben"
 
 #: qcsrc/client/hud/panel/infomessages.qc:113
 #: qcsrc/menu/xonotic/keybinder.qc:51
 msgid "secondary fire"
-msgstr ""
+msgstr "sekundære skud"
 
 #: qcsrc/client/hud/panel/infomessages.qc:115
 #, c-format
@@ -138,7 +140,7 @@ msgstr ""
 #: qcsrc/client/hud/panel/infomessages.qc:118
 #: qcsrc/menu/xonotic/keybinder.qc:106
 msgid "server info"
-msgstr ""
+msgstr "server info"
 
 #: qcsrc/client/hud/panel/infomessages.qc:130
 #, c-format
@@ -148,12 +150,12 @@ msgstr ""
 #: qcsrc/client/hud/panel/infomessages.qc:130 qcsrc/client/main.qc:1409
 #: qcsrc/common/notifications/all.qh:442
 msgid "jump"
-msgstr "hoppe"
+msgstr "hop"
 
 #: qcsrc/client/hud/panel/infomessages.qc:139
 #, c-format
 msgid "^1Game starts in ^3%d^1 seconds"
-msgstr "^1Spil begynder om ^3%d^1 sekunder"
+msgstr "^1Spillet starter om ^3%d^1 sekunder"
 
 #: qcsrc/client/hud/panel/infomessages.qc:151
 msgid "^2Currently in ^1warmup^2 stage!"
@@ -161,7 +163,7 @@ msgstr ""
 
 #: qcsrc/client/hud/panel/infomessages.qc:163
 msgid "^31^2 more player is needed for the match to start."
-msgstr ""
+msgstr "^31^2 flere spillere kræves for at start kampen"
 
 #: qcsrc/client/hud/panel/infomessages.qc:165
 #, c-format
@@ -177,7 +179,7 @@ msgstr ""
 #: qcsrc/client/hud/panel/infomessages.qc:178
 #: qcsrc/menu/xonotic/keybinder.qc:102
 msgid "ready"
-msgstr ""
+msgstr "klar"
 
 #: qcsrc/client/hud/panel/infomessages.qc:175
 msgid "^2Waiting for others to ready up to end warmup..."
@@ -200,7 +202,7 @@ msgstr ""
 #: qcsrc/client/hud/panel/infomessages.qc:203
 #: qcsrc/menu/xonotic/keybinder.qc:117
 msgid "team selection"
-msgstr ""
+msgstr "hold selektion"
 
 #: qcsrc/client/hud/panel/infomessages.qc:213
 msgid "^1Spectating this player:"
@@ -249,7 +251,7 @@ msgstr "Kommando%d"
 
 #: qcsrc/client/hud/panel/quickmenu.qc:667
 msgid "Continue..."
-msgstr ""
+msgstr "Fortsæt..."
 
 #: qcsrc/client/hud/panel/quickmenu.qc:818
 #: qcsrc/client/hud/panel/quickmenu.qc:825
@@ -270,11 +272,11 @@ msgstr ""
 
 #: qcsrc/client/hud/panel/quickmenu.qc:821
 msgid "QMCMD^good game"
-msgstr ""
+msgstr "QMCMD^god kamp"
 
 #: qcsrc/client/hud/panel/quickmenu.qc:822
 msgid "QMCMD^hi / good luck"
-msgstr ""
+msgstr "QMCMD^hej / held og lykke"
 
 #: qcsrc/client/hud/panel/quickmenu.qc:822
 msgid "QMCMD^hi / good luck and have fun"
@@ -282,7 +284,7 @@ msgstr ""
 
 #: qcsrc/client/hud/panel/quickmenu.qc:824
 msgid "QMCMD^Send in English"
-msgstr "QMCMD^Send i Engelsk"
+msgstr "QMCMD^Send  Engelsk"
 
 #: qcsrc/client/hud/panel/quickmenu.qc:829
 #: qcsrc/client/hud/panel/quickmenu.qc:845
@@ -861,7 +863,7 @@ msgstr ""
 
 #: qcsrc/client/hud/panel/scoreboard.qc:172
 msgid "Number of suicides"
-msgstr "Antal selvmord"
+msgstr "Antal selvdrab"
 
 #: qcsrc/client/hud/panel/scoreboard.qc:172
 msgid "SCO^suicides"
index eb9cf48bbbbbec2c9c685e545d06a2a64f1c1ea6..fcb17b73e64e532f88987a0e5f9b9d56d3e30f79 100644 (file)
@@ -23,7 +23,7 @@ msgstr ""
 "Report-Msgid-Bugs-To: \n"
 "POT-Creation-Date: 2023-07-11 07:22+0200\n"
 "PO-Revision-Date: 2013-09-12 16:53+0000\n"
-"Last-Translator: Yannick Le Guen <leguen.yannick@gmail.com>, 2013-2023\n"
+"Last-Translator: Hugo Locurcio, 2013-2014\n"
 "Language-Team: French (http://app.transifex.com/team-xonotic/xonotic/"
 "language/fr/)\n"
 "Language: fr\n"
@@ -4241,7 +4241,7 @@ msgstr "^K1Change de tactique, campeur !"
 
 #: qcsrc/common/notifications/all.inc:642
 msgid "^K1You unfairly eliminated yourself!"
-msgstr "^K1Vous vous êtes éliminé tout seul !"
+msgstr "^K1Vous vous êtes injustement éliminé vous-même !"
 
 #: qcsrc/common/notifications/all.inc:643
 #, c-format
@@ -4266,7 +4266,7 @@ msgstr "^K1Vous êtes devenu un peu trop croustillant !"
 
 #: qcsrc/common/notifications/all.inc:647
 msgid "^K1You fragged yourself!"
-msgstr "^K1Vous vous êtes tué tout seul !"
+msgstr "^K1Vous vous êtes tué vous-même !"
 
 #: qcsrc/common/notifications/all.inc:647
 msgid "^K1You need to be more careful!"
@@ -4475,7 +4475,7 @@ msgstr "^K3Vous avez dégelé ^BG%s"
 
 #: qcsrc/common/notifications/all.inc:688
 msgid "^K3You revived yourself"
-msgstr "^K3Vous vous êtes dégelé tout seul"
+msgstr "^K3Vous vous êtes dégelé vous-même"
 
 #: qcsrc/common/notifications/all.inc:689
 #, c-format
@@ -4497,7 +4497,7 @@ msgstr "^BGL'équipe ^TC^TT^BG perd la manche"
 
 #: qcsrc/common/notifications/all.inc:698
 msgid "^K1You froze yourself"
-msgstr "^K1Vous vous êtes gelé tout seul"
+msgstr "^K1Vous vous êtes gelé vous-même"
 
 #: qcsrc/common/notifications/all.inc:699
 msgid "^K1Round already started, you spawn as frozen"
index 4fc22b06a36803eacf74646d17515b040c3e3a7b..e83368ceb43c85d519c92eac54baca08ca74c56c 100644 (file)
@@ -7,7 +7,7 @@
 # Antoni Das <Antonidas159@gmail.com>, 2017
 # Antonio <piuntn@gmail.com>, 2023
 # LegendGuard, 2020
-# LegendGuard, 2020-2023
+# LegendGuard, 2020-2024
 # Lento <securemailfor28-xonotic@yahoo.co.jp>, 2015
 # RYU N. <ryusho2523@yahoo.co.jp>, 2021
 # z 411 <winrar.hurr@gmail.com>, 2021-2022
@@ -17,7 +17,7 @@ msgstr ""
 "Report-Msgid-Bugs-To: \n"
 "POT-Creation-Date: 2023-07-11 07:22+0200\n"
 "PO-Revision-Date: 2013-09-12 16:53+0000\n"
-"Last-Translator: RYU N. <ryusho2523@yahoo.co.jp>, 2021\n"
+"Last-Translator: LegendGuard, 2020-2024\n"
 "Language-Team: Japanese (Japan) (http://app.transifex.com/team-xonotic/"
 "xonotic/language/ja_JP/)\n"
 "Language: ja_JP\n"
@@ -351,7 +351,7 @@ msgstr "QMCMD^旗が見えました、アイコン"
 
 #: qcsrc/client/hud/panel/quickmenu.qc:838
 msgid "QMCMD^defending (l:%l^7) (h:%h^7 a:%a^7 w:%w^7)"
-msgstr "QMCMD^守り中 (l:%l^7) (h:%h^7 a:%a^7 w:%w^7)"
+msgstr "QMCMD^防衛中 (l:%l^7) (h:%h^7 a:%a^7 w:%w^7)"
 
 #: qcsrc/client/hud/panel/quickmenu.qc:838
 msgid "QMCMD^defending, icon"
index 95cff2fe9cac3049388770fe8a8faeef7895d338..e7712f73c26a7c4b1a2c1ff8cfbcfc4836952b20 100644 (file)
@@ -4,14 +4,14 @@
 #
 # Translators:
 # oblector o, 2022
-# oblector o, 2022-2023
+# oblector o, 2022-2024
 msgid ""
 msgstr ""
 "Project-Id-Version: Xonotic\n"
 "Report-Msgid-Bugs-To: \n"
 "POT-Creation-Date: 2023-07-11 07:22+0200\n"
 "PO-Revision-Date: 2013-09-12 16:53+0000\n"
-"Last-Translator: oblector o, 2022\n"
+"Last-Translator: oblector o, 2022-2024\n"
 "Language-Team: Latin (http://app.transifex.com/team-xonotic/xonotic/language/"
 "la/)\n"
 "Language: la\n"
@@ -6508,15 +6508,15 @@ msgstr "Sanitatis/Armaturae Tabella"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_infomessages.qc:16
 msgid "Info messages:"
-msgstr ""
+msgstr "Condicionum notae:"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_infomessages.qc:19
 msgid "Flip align"
-msgstr ""
+msgstr "Ad alterum latus"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_infomessages.qh:6
 msgid "Info Messages Panel"
-msgstr ""
+msgstr "Condicionum Notarum Tabella"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_itemstime.qc:16
 #: qcsrc/menu/xonotic/dialog_hudpanel_physics.qc:15
@@ -6568,31 +6568,31 @@ msgstr "Utilium Temporum Tabella"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_modicons.qh:6
 msgid "Mod Icons Panel"
-msgstr ""
+msgstr "Mutationis Imaginum Tabella"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_notification.qc:17
 msgid "Notifications:"
-msgstr ""
+msgstr "Nuntia:"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_notification.qc:20
 msgid "Also print notifications to the console"
-msgstr ""
+msgstr "Nuntia scribere in iussorum loco quoque"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_notification.qc:23
 msgid "Flip notify order"
-msgstr ""
+msgstr "Nuntiorum ordo inversa"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_notification.qc:26
 msgid "Entry lifetime:"
-msgstr ""
+msgstr "Scriptum manet tempus:"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_notification.qc:30
 msgid "Entry fadetime:"
-msgstr ""
+msgstr "Scriptum evanescit tempus:"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_notification.qh:6
 msgid "Notification Panel"
-msgstr ""
+msgstr "Nuntiorum Tabella"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_physics.qc:16
 #: qcsrc/menu/xonotic/dialog_hudpanel_strafehud.qc:30
@@ -6645,15 +6645,15 @@ msgstr "Velocitas:"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_physics.qc:38
 msgid "Include vertical speed"
-msgstr ""
+msgstr "Velocitatem erectam addere"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_physics.qc:49
 msgid "Show speed unit"
-msgstr ""
+msgstr "Velocitatis unitatem videre"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_physics.qc:52
 msgid "Top speed"
-msgstr ""
+msgstr "Velocitas summa"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_physics.qc:58
 msgid "Acceleration:"
@@ -6661,7 +6661,7 @@ msgstr "Acceleratio:"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_physics.qc:59
 msgid "Include vertical acceleration"
-msgstr ""
+msgstr "Accelerationem erectam addere"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_physics.qh:6
 msgid "Physics Panel"
@@ -6696,7 +6696,7 @@ msgstr "Si spectas"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_pickup.qc:37
 msgid "Icon size scale:"
-msgstr ""
+msgstr "Imaginis proportio:"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_pickup.qh:6
 msgid "Pickup Panel"
@@ -6713,7 +6713,7 @@ msgstr "Semper videre"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_pressedkeys.qc:23
 msgid "Forced aspect:"
-msgstr ""
+msgstr "Proportio postulata:"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_pressedkeys.qh:6
 msgid "Pressed Keys Panel"
@@ -6827,98 +6827,98 @@ msgstr "Rationum Tabella"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_strafehud.qc:38
 msgid "StrafeHUD mode:"
-msgstr ""
+msgstr "Motionis lateralis Notarum modus:"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_strafehud.qc:41
 msgid "View angle centered"
-msgstr ""
+msgstr "Angulum videre centralem"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_strafehud.qc:42
 msgid "Velocity angle centered"
-msgstr ""
+msgstr "Velocitatis angulum videre centralem"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_strafehud.qc:45
 msgid "StrafeHUD style:"
-msgstr ""
+msgstr "Motionis lateralis Notarum facies:"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_strafehud.qc:48
 msgid "no styling"
-msgstr ""
+msgstr "nulla facies"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_strafehud.qc:49
 msgid "progress bar"
-msgstr ""
+msgstr "linea progressus"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_strafehud.qc:50
 msgid "gradient"
-msgstr ""
+msgstr "gradiens"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_strafehud.qc:53
 msgid "Range:"
-msgstr ""
+msgstr "Intervallum:"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_strafehud.qc:56
 msgid "Demo mode"
-msgstr ""
+msgstr "Demonstrationis modus"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_strafehud.qc:60
 msgid "Reset colors"
-msgstr ""
+msgstr "Colores reponere"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_strafehud.qc:64
 msgid "Strafe bar:"
-msgstr ""
+msgstr "Linea motionis lateralis:"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_strafehud.qc:68
 msgid "Angle indicator:"
-msgstr ""
+msgstr "Angulum indicare:"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_strafehud.qc:70
 #: qcsrc/menu/xonotic/dialog_hudpanel_strafehud.qc:78
 msgid "Neutral:"
-msgstr ""
+msgstr "Non specialem"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_strafehud.qc:72
 #: qcsrc/menu/xonotic/dialog_hudpanel_strafehud.qc:80
 msgid "Good:"
-msgstr ""
+msgstr "Bonum"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_strafehud.qc:74
 #: qcsrc/menu/xonotic/dialog_hudpanel_strafehud.qc:82
 msgid "Overturn:"
-msgstr ""
+msgstr "Ad inversionem:"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_strafehud.qc:109
 msgid "Switch indicator:"
-msgstr ""
+msgstr "Inversionem indicare:"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_strafehud.qc:113
 msgid "Best angle indicator:"
-msgstr ""
+msgstr "Angulum optimum indicare:"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_strafehud.qh:6
 msgid "StrafeHUD Panel"
-msgstr ""
+msgstr "Motionis lateralis Notarum Tabella"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_timer.qc:17
 msgid "Timer:"
-msgstr ""
+msgstr "Tempus numeratum:"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_timer.qc:20
 msgid "Show elapsed time"
-msgstr ""
+msgstr "Tempus quod transivit videre"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_timer.qc:23
 msgid "Secondary timer:"
-msgstr ""
+msgstr "Tempus secundarium:"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_timer.qc:27
 msgid "Swapped"
-msgstr ""
+msgstr "Commutata"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_timer.qh:6
 msgid "Timer Panel"
-msgstr ""
+msgstr "Temporum Tabella"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_vote.qc:17
 msgid "Alpha after voting:"
@@ -7016,14 +7016,14 @@ msgstr "Facies Notarum Superpositarum"
 #: qcsrc/menu/xonotic/dialog_multiplayer_media_musicplayer.qc:25
 #: qcsrc/menu/xonotic/dialog_multiplayer_media_screenshot.qc:33
 msgid "Filter:"
-msgstr ""
+msgstr "Electe scribere:"
 
 #: qcsrc/menu/xonotic/dialog_hudsetup_exit.qc:30
 #: qcsrc/menu/xonotic/dialog_multiplayer_join.qc:59
 #: qcsrc/menu/xonotic/dialog_multiplayer_media_demo.qc:49
 #: qcsrc/menu/xonotic/dialog_multiplayer_media_screenshot.qc:43
 msgid "Refresh"
-msgstr ""
+msgstr "Iterum scribere:"
 
 #: qcsrc/menu/xonotic/dialog_hudsetup_exit.qc:33
 #: qcsrc/menu/xonotic/dialog_settings_user.qc:28
@@ -7036,11 +7036,11 @@ msgstr "Hanc faciem servare"
 
 #: qcsrc/menu/xonotic/dialog_hudsetup_exit.qc:46
 msgid "Panel background defaults:"
-msgstr ""
+msgstr "Tabellae imago supposita ordinaria:"
 
 #: qcsrc/menu/xonotic/dialog_hudsetup_exit.qc:48 qcsrc/menu/xonotic/util.qc:759
 msgid "Background:"
-msgstr ""
+msgstr "Imago supposita:"
 
 #: qcsrc/menu/xonotic/dialog_hudsetup_exit.qc:60 qcsrc/menu/xonotic/util.qc:775
 msgid "Border size:"
@@ -7053,11 +7053,11 @@ msgstr "Manus color:"
 
 #: qcsrc/menu/xonotic/dialog_hudsetup_exit.qc:83 qcsrc/menu/xonotic/util.qc:801
 msgid "Test team color in configure mode"
-msgstr ""
+msgstr "Manus colorem exemplarem in optionibus inspicere"
 
 #: qcsrc/menu/xonotic/dialog_hudsetup_exit.qc:86 qcsrc/menu/xonotic/util.qc:804
 msgid "Padding:"
-msgstr ""
+msgstr "Margo:"
 
 #: qcsrc/menu/xonotic/dialog_hudsetup_exit.qc:93
 msgid "HUD Dock:"
@@ -7114,11 +7114,11 @@ msgstr ""
 
 #: qcsrc/menu/xonotic/dialog_hudsetup_exit.qc:148
 msgid "Exit setup"
-msgstr ""
+msgstr "Finire optiones"
 
 #: qcsrc/menu/xonotic/dialog_hudsetup_exit.qh:6
 msgid "Panel HUD Setup"
-msgstr ""
+msgstr "Mutare Notarum Superpositarum Tabellam"
 
 #: qcsrc/menu/xonotic/dialog_monstertools.qc:13
 msgid "Monster:"
@@ -7652,35 +7652,35 @@ msgstr "N/A (sine bibliotheca auth)"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_join_serverinfo.qc:167
 msgid "Not supported (can't connect)"
-msgstr ""
+msgstr "Non capax (conectere non potest)"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_join_serverinfo.qc:169
 msgid "Not supported (won't encrypt)"
-msgstr ""
+msgstr "Non capax (non cryptographabit)"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_join_serverinfo.qc:173
 msgid "Supported (will encrypt)"
-msgstr ""
+msgstr "Capax (cryptographabit)"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_join_serverinfo.qc:175
 msgid "Supported (won't encrypt)"
-msgstr ""
+msgstr "Capax (non cryptographabit)"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_join_serverinfo.qc:179
 msgid "Requested (will encrypt)"
-msgstr ""
+msgstr "Rogatur (cryptographabit)"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_join_serverinfo.qc:181
 msgid "Requested (won't encrypt)"
-msgstr ""
+msgstr "Rogatur (non cryptographabit)"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_join_serverinfo.qc:185
 msgid "Required (can't connect)"
-msgstr ""
+msgstr "Postulatur (conectere non potest)"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_join_serverinfo.qc:187
 msgid "Required (will encrypt)"
-msgstr ""
+msgstr "Postulatur (cryptographabit)"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_join_serverinfo.qc:191
 msgid "Use the `crypto_aeslevel` cvar to change your preferences"
@@ -7689,17 +7689,17 @@ msgstr ""
 #: qcsrc/menu/xonotic/dialog_multiplayer_join_serverinfo.qc:203
 #: qcsrc/menu/xonotic/serverlist.qc:1059
 msgid "custom stats server"
-msgstr ""
+msgstr "stat. moderatrum speciale"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_join_serverinfo.qc:203
 #: qcsrc/menu/xonotic/serverlist.qc:1059
 msgid "stats disabled"
-msgstr ""
+msgstr "sine stat."
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_join_serverinfo.qc:203
 #: qcsrc/menu/xonotic/serverlist.qc:1059
 msgid "stats enabled"
-msgstr ""
+msgstr "cum stat."
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_join_serverinfo.qc:213
 msgid "Status"
@@ -7810,7 +7810,7 @@ msgstr "Dinectere"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_media_demo_timeconfirm.qc:13
 msgid "Timing a demo will disconnect you from the current match."
-msgstr ""
+msgstr "Si demonstrationis tempus computare vis, hunc ludum linques."
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_media_musicplayer.qc:37
 msgid "MUSICPL^Add"
@@ -8283,11 +8283,11 @@ msgstr "Quidam sonus fit cum indicem cliccas"
 
 #: qcsrc/menu/xonotic/dialog_settings_audio.qc:163
 msgid "Focus sounds"
-msgstr ""
+msgstr "Attentionis soni"
 
 #: qcsrc/menu/xonotic/dialog_settings_audio.qc:164
 msgid "Play sounds when hovering over menu items too"
-msgstr ""
+msgstr "Quidam sonus fit cum indicem transis"
 
 #: qcsrc/menu/xonotic/dialog_settings_audio.qc:168
 msgid "Time announcer:"
@@ -8457,7 +8457,7 @@ msgstr "Optima"
 #: qcsrc/menu/xonotic/dialog_settings_effects.qc:115
 #: qcsrc/menu/xonotic/dialog_settings_effects.qc:120
 msgid "Avoid lossy texture compression"
-msgstr ""
+msgstr "Cum texturae memoria computatralis breviatur, subtilitas servanda est"
 
 #: qcsrc/menu/xonotic/dialog_settings_effects.qc:129
 msgid "Disable sky for performance and visibility"
@@ -8502,11 +8502,11 @@ msgstr "Illuminatio in singulos quadri laterculos"
 
 #: qcsrc/menu/xonotic/dialog_settings_effects.qc:142
 msgid "Gloss"
-msgstr ""
+msgstr "Superficies illustres"
 
 #: qcsrc/menu/xonotic/dialog_settings_effects.qc:143
 msgid "Enable the use of glossmaps on textures supporting it"
-msgstr ""
+msgstr "Illustrationum tabulis utitur in texturis quae eas contineant"
 
 #: qcsrc/menu/xonotic/dialog_settings_effects.qc:146
 msgid "Offset mapping"
@@ -8522,12 +8522,13 @@ msgstr ""
 
 #: qcsrc/menu/xonotic/dialog_settings_effects.qc:149
 msgid "Relief mapping"
-msgstr ""
+msgstr "Anaglyptorum tabulae"
 
 #: qcsrc/menu/xonotic/dialog_settings_effects.qc:150
 msgid ""
 "Higher quality offset mapping, which also has a huge impact on performance"
 msgstr ""
+"Subtiliorum tuberum tabulae, et si eis utitur, computatrum minus velox erit"
 
 #: qcsrc/menu/xonotic/dialog_settings_effects.qc:153
 msgid "Reflections:"
@@ -8559,32 +8560,32 @@ msgstr "Clara"
 
 #: qcsrc/menu/xonotic/dialog_settings_effects.qc:164
 msgid "Decals"
-msgstr ""
+msgstr "Sigilla"
 
 #: qcsrc/menu/xonotic/dialog_settings_effects.qc:165
 msgid "Enable decals (bullet holes and blood)"
-msgstr ""
+msgstr "Sigilla pinguntur (picturae missilium perforantium sanguinumque)"
 
 #: qcsrc/menu/xonotic/dialog_settings_effects.qc:166
 msgid "Decals on models"
-msgstr ""
+msgstr "Sigilla in formis"
 
 #: qcsrc/menu/xonotic/dialog_settings_effects.qc:170
 #: qcsrc/menu/xonotic/dialog_settings_effects.qc:251
 msgid "Distance:"
-msgstr ""
+msgstr "Distantia:"
 
 #: qcsrc/menu/xonotic/dialog_settings_effects.qc:173
 msgid "Decals further away than this will not be drawn"
-msgstr ""
+msgstr "Sigilla quae distant plus quam hanc mensuram non pinguntur"
 
 #: qcsrc/menu/xonotic/dialog_settings_effects.qc:177
 msgid "Time:"
-msgstr ""
+msgstr "Tempus:"
 
 #: qcsrc/menu/xonotic/dialog_settings_effects.qc:180
 msgid "Time in seconds before decals fade away"
-msgstr ""
+msgstr "Numerus secundorum, post quae evanescunt sigilla"
 
 #: qcsrc/menu/xonotic/dialog_settings_effects.qc:184
 msgid "Damage effects:"
@@ -8667,27 +8668,31 @@ msgstr "Luces coronales evanescunt secundum res quae videntur"
 
 #: qcsrc/menu/xonotic/dialog_settings_effects.qc:218
 msgid "Corona fading using occlusion queries"
-msgstr ""
+msgstr "Luces coronales evanescunt secundum inquisitionem occludentium"
 
 #: qcsrc/menu/xonotic/dialog_settings_effects.qc:222
 msgid "Bloom"
-msgstr ""
+msgstr "Illuminatio finitima"
 
 #: qcsrc/menu/xonotic/dialog_settings_effects.qc:223
 msgid ""
 "Enable bloom effect, which brightens the neighboring pixels of very bright "
 "pixels. Has a big impact on performance."
 msgstr ""
+"Illuminantur laterculi qui adiacent ad alios laterculos iam "
+"illuminatissimos. Itaque computatrum minus velox erit."
 
 #: qcsrc/menu/xonotic/dialog_settings_effects.qc:224
 msgid "Extra postprocessing effects"
-msgstr ""
+msgstr "Plura artificia"
 
 #: qcsrc/menu/xonotic/dialog_settings_effects.qc:225
 msgid ""
 "Enables special postprocessing effects for when damaged or under water or "
 "using a powerup"
 msgstr ""
+"Plura artificia efficiuntur, e.g., picturae vulnerationis vel summersionis "
+"vel potestatis"
 
 #: qcsrc/menu/xonotic/dialog_settings_effects.qc:230
 msgid "Motion blur strength - 0.4 recommended"
@@ -8703,15 +8708,16 @@ msgstr "Particulae"
 
 #: qcsrc/menu/xonotic/dialog_settings_effects.qc:238
 msgid "Spawnpoint effects"
-msgstr ""
+msgstr "Picturae parvae in loco ubi nascitur"
 
 #: qcsrc/menu/xonotic/dialog_settings_effects.qc:239
 msgid "Particles effects at all spawn points and whenever a player spawns"
 msgstr ""
+"Particulae pinguntur in loco ubi nascitur et in ludentibus qui nascuntur"
 
 #: qcsrc/menu/xonotic/dialog_settings_effects.qc:244
 msgid "Quality:"
-msgstr ""
+msgstr "Subtilitas:"
 
 #: qcsrc/menu/xonotic/dialog_settings_effects.qc:247
 #: qcsrc/menu/xonotic/slider_particles.qc:13
@@ -8771,27 +8777,27 @@ msgstr ""
 
 #: qcsrc/menu/xonotic/dialog_settings_game_crosshair.qc:125
 msgid "Perform hit tests for the crosshair"
-msgstr ""
+msgstr "Indicare in reticulo cum arma sunt examussim ad hostem"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_crosshair.qc:129
 msgid "Blur if obstructed by an obstacle"
-msgstr ""
+msgstr "Offuscare cum arma obstantur"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_crosshair.qc:133
 msgid "Blur if obstructed by a teammate"
-msgstr ""
+msgstr "Offuscare cum arma sunt ad collegam"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_crosshair.qc:137
 msgid "Shrink if obstructed by a teammate"
-msgstr ""
+msgstr "Minuere cum arma sunt ad collegam"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_crosshair.qc:140
 msgid "Animate crosshair when hitting an enemy"
-msgstr ""
+msgstr "Movere reticulum cum hostis vulneratur"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_crosshair.qc:143
 msgid "Animate crosshair when picking up an item"
-msgstr ""
+msgstr "Movere reticulum cum res colligitur"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_crosshair.qh:7
 msgid "Crosshair"
@@ -8906,40 +8912,41 @@ msgstr "Sanitatem armaturamque videre"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_hud.qc:163
 msgid "Speed unit:"
-msgstr ""
+msgstr "Velocitatis unitas:"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_hud.qc:172
 msgid "Damage overlay:"
-msgstr ""
+msgstr "Vulnera superposita:"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_hud.qc:175
 msgid "Dynamic HUD"
-msgstr ""
+msgstr "Mobiles Notae Superpositae"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_hud.qc:176
 msgid "HUD moves around following player's movement"
-msgstr ""
+msgstr "Notae Superpositae moventur quasi cum ludente ambulet"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_hud.qc:178
 msgid "Shake the HUD when hurt"
-msgstr ""
+msgstr "Notae Superpositae vibrantur cum vulneraris"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_hud.qc:182
 #: qcsrc/menu/xonotic/dialog_settings_game_hudconfirm.qh:6
 msgid "Enter HUD editor"
-msgstr ""
+msgstr "Notarum Superpositarum optiones videre"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_hud.qh:7
 msgid "HUD"
-msgstr ""
+msgstr "Notae Superpositae"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_hudconfirm.qc:21
 msgid "In order for the HUD editor to show, you must first be in game."
 msgstr ""
+"Si Notarum Superpositarum optiones videre vis, necesse est ludus incipi."
 
 #: qcsrc/menu/xonotic/dialog_settings_game_hudconfirm.qc:23
 msgid "Do you wish to start a local game to set up the HUD?"
-msgstr ""
+msgstr "Visne incipi ludum localem ut videas Notarum Superpositarum optiones?"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_messages.qc:24
 msgid "Frag Information"
@@ -8963,23 +8970,23 @@ msgstr "Caedium series scriptae in mortuorum notis"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_messages.qc:43
 msgid "Sprees in info messages:"
-msgstr ""
+msgstr "Caedium series in condicionum notis:"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_messages.qc:46
 msgid "SPREES^Disabled"
-msgstr ""
+msgstr "Sine"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_messages.qc:47
 msgid "Target"
-msgstr ""
+msgstr "Vulnerati"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_messages.qc:48
 msgid "Attacker"
-msgstr ""
+msgstr "Vulnerans"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_messages.qc:49
 msgid "SPREES^Both"
-msgstr ""
+msgstr "Ambo"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_messages.qc:55
 msgid "Print on a seperate line"
@@ -8987,11 +8994,11 @@ msgstr "In alio versu scribere"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_messages.qc:58
 msgid "Add extra frag information to centerprint when available"
-msgstr ""
+msgstr "Plures notas de caedibus in scripto medio scribere si dicuntur"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_messages.qc:62
 msgid "Add frag location to death messages when available"
-msgstr ""
+msgstr "Locos caedium in mortuorum notis scribere si dicuntur"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_messages.qc:65
 msgid "Gamemode Settings"
@@ -9013,27 +9020,27 @@ msgstr ""
 
 #: qcsrc/menu/xonotic/dialog_settings_game_messages.qc:78
 msgid "Display console messages in the top left corner"
-msgstr ""
+msgstr "Iussorum loci notas videre in angulo supero sinistro"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_messages.qc:80
 msgid "Display all info messages in the chatbox"
-msgstr ""
+msgstr "Omnes condicionum notas in locutorii loco videre"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_messages.qc:82
 msgid "Display player statuses in the chatbox"
-msgstr ""
+msgstr "Ludentium condiciones in locutorii loco videre"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_messages.qc:86
 msgid "Powerup notifications"
-msgstr ""
+msgstr "Potestatium nuntia"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_messages.qc:89
 msgid "Weapon centerprint notifications"
-msgstr ""
+msgstr "Armorum nuntia in scripto medio"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_messages.qc:92
 msgid "Weapon info message notifications"
-msgstr ""
+msgstr "Armorum nuntia in condicionum notis"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_messages.qc:96
 msgid "Announcers"
@@ -9041,19 +9048,19 @@ msgstr "Nuntiatores"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_messages.qc:98
 msgid "Respawn countdown sounds"
-msgstr ""
+msgstr "Soni numerationis regrendientis cum renascitur"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_messages.qc:101
 msgid "Killstreak sounds"
-msgstr ""
+msgstr "Soni seriei caedium"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_messages.qc:104
 msgid "Achievement sounds"
-msgstr ""
+msgstr "Rerum insignium soni"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_messages.qh:7
 msgid "Messages"
-msgstr ""
+msgstr "Notae"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_model.qc:30
 msgid "Items"
@@ -9190,11 +9197,11 @@ msgstr "3ae personae visio"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_view.qc:53
 msgid "Back distance"
-msgstr ""
+msgstr "Distantia ad dorsum"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_view.qc:59
 msgid "Up distance"
-msgstr ""
+msgstr "Distantia superior"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_view.qc:65
 msgid "Allow passing through walls while spectating"
@@ -9327,11 +9334,11 @@ msgstr "Armorum formae traluciditas:"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_weapons.qc:91
 msgid "Gun model swaying"
-msgstr ""
+msgstr "Armorum forma pendula"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_weapons.qc:96
 msgid "Gun model bobbing"
-msgstr ""
+msgstr "Armorum forma undans"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_weapons.qh:7
 #: qcsrc/menu/xonotic/keybinder.qc:54
@@ -9340,23 +9347,23 @@ msgstr "Arma"
 
 #: qcsrc/menu/xonotic/dialog_settings_input.qc:34
 msgid "Key Bindings"
-msgstr ""
+msgstr "Claves electae"
 
 #: qcsrc/menu/xonotic/dialog_settings_input.qc:38
 msgid "Change key..."
-msgstr ""
+msgstr "Alia clavis..."
 
 #: qcsrc/menu/xonotic/dialog_settings_input.qc:42
 msgid "Edit..."
-msgstr ""
+msgstr "Scribere..."
 
 #: qcsrc/menu/xonotic/dialog_settings_input.qc:48
 msgid "Clear"
-msgstr ""
+msgstr "Oblivisci"
 
 #: qcsrc/menu/xonotic/dialog_settings_input.qc:53
 msgid "Reset all"
-msgstr ""
+msgstr "Omnes reponere"
 
 #: qcsrc/menu/xonotic/dialog_settings_input.qc:58
 msgid "Mouse"
@@ -9452,7 +9459,7 @@ msgstr ""
 
 #: qcsrc/menu/xonotic/dialog_settings_input_userbind.qh:7
 msgid "User defined key bind"
-msgstr ""
+msgstr "Clavis pro creato ab utente"
 
 #: qcsrc/menu/xonotic/dialog_settings_misc.qc:12
 #, c-format
@@ -9475,64 +9482,64 @@ msgstr "Interrete"
 
 #: qcsrc/menu/xonotic/dialog_settings_misc.qc:33
 msgid "Show netgraph"
-msgstr ""
+msgstr "Retis graphicum videre"
 
 #: qcsrc/menu/xonotic/dialog_settings_misc.qc:34
 msgid "Show a graph of packet sizes and other information"
-msgstr ""
+msgstr "In graphico magnitudines litterarum interretialium scribere et alia"
 
 #: qcsrc/menu/xonotic/dialog_settings_misc.qc:36
 msgid "Packet loss compensation"
-msgstr ""
+msgstr "Compensare perditas litteras interretiales"
 
 #: qcsrc/menu/xonotic/dialog_settings_misc.qc:37
 msgid "Each packet includes a copy of the previous message"
-msgstr ""
+msgstr "Quaeque litterae transcribunt litteras anteriores quoque"
 
 #: qcsrc/menu/xonotic/dialog_settings_misc.qc:39
 msgid "Movement prediction error compensation"
-msgstr ""
+msgstr "Compensare motiones vitiose praedictas"
 
 #: qcsrc/menu/xonotic/dialog_settings_misc.qc:43
 msgid "Use encryption (AES) when available"
-msgstr ""
+msgstr "Cryptographia (AES) uti si accipitur"
 
 #: qcsrc/menu/xonotic/dialog_settings_misc.qc:46
 #: qcsrc/menu/xonotic/dialog_settings_misc.qc:68
 msgid "Bandwidth limit:"
-msgstr ""
+msgstr "Nexionis interretialis velocitas maxima"
 
 #: qcsrc/menu/xonotic/dialog_settings_misc.qc:48
 msgid "Specify your network speed"
-msgstr ""
+msgstr "Scribe velocitatem nexionis tuae"
 
 #: qcsrc/menu/xonotic/dialog_settings_misc.qc:49
 msgid "Slow ADSL"
-msgstr ""
+msgstr "ADSL lenta"
 
 #: qcsrc/menu/xonotic/dialog_settings_misc.qc:50
 msgid "Fast ADSL"
-msgstr ""
+msgstr "ADSL velox"
 
 #: qcsrc/menu/xonotic/dialog_settings_misc.qc:51
 msgid "Broadband"
-msgstr ""
+msgstr "Taenia lata"
 
 #: qcsrc/menu/xonotic/dialog_settings_misc.qc:57
 msgid "Local latency:"
-msgstr ""
+msgstr "Mora nexionis localis"
 
 #: qcsrc/menu/xonotic/dialog_settings_misc.qc:62
 msgid "HTTP downloads"
-msgstr ""
+msgstr "Acceptiones interretiales per HTTP"
 
 #: qcsrc/menu/xonotic/dialog_settings_misc.qc:64
 msgid "Simultaneous:"
-msgstr ""
+msgstr "Simul:"
 
 #: qcsrc/menu/xonotic/dialog_settings_misc.qc:66
 msgid "Maximum number of concurrent HTTP downloads"
-msgstr ""
+msgstr "Numerus maximus acceptionum coniunctarum per HTTP"
 
 #: qcsrc/menu/xonotic/dialog_settings_misc.qc:82
 msgid "Framerate"
@@ -9548,27 +9555,27 @@ msgstr "Numerum tuum quadrorum pictorum in secundum videre"
 
 #: qcsrc/menu/xonotic/dialog_settings_misc.qc:87
 msgid "Maximum:"
-msgstr ""
+msgstr "Maximus"
 
 #: qcsrc/menu/xonotic/dialog_settings_misc.qc:96
 msgid "MAXFPS^Unlimited"
-msgstr ""
+msgstr "Infinitus"
 
 #: qcsrc/menu/xonotic/dialog_settings_misc.qc:99
 msgid "Target:"
-msgstr ""
+msgstr "Quaesitus:"
 
 #: qcsrc/menu/xonotic/dialog_settings_misc.qc:101
 msgid "TRGT^Disabled"
-msgstr ""
+msgstr "Sine"
 
 #: qcsrc/menu/xonotic/dialog_settings_misc.qc:112
 msgid "Idle limit:"
-msgstr ""
+msgstr "Numerus si otiosus"
 
 #: qcsrc/menu/xonotic/dialog_settings_misc.qc:118
 msgid "IDLFPS^Unlimited"
-msgstr ""
+msgstr "Infinitus"
 
 #: qcsrc/menu/xonotic/dialog_settings_misc.qc:124
 msgid "Menu tooltips:"
@@ -9761,13 +9768,16 @@ msgstr "Totum quadrum"
 
 #: qcsrc/menu/xonotic/dialog_settings_video.qc:61
 msgid "Vertical Synchronization"
-msgstr ""
+msgstr "Lineas iacentes pingere Synchrone"
 
 #: qcsrc/menu/xonotic/dialog_settings_video.qc:62
 msgid ""
 "Vsync prevents tearing, but increases latency and caps your fps at the "
 "screen refresh rate"
 msgstr ""
+"Si lineae iacentes pinguntur synchrone, imagines scissas non videbis, sed "
+"itaque imagines tardabuntur et numerus imaginum in secundum non maior erit "
+"quam numerum integrationum in quadro"
 
 #: qcsrc/menu/xonotic/dialog_settings_video.qc:64
 msgid "High-quality frame buffer"
@@ -9775,27 +9785,29 @@ msgstr ""
 
 #: qcsrc/menu/xonotic/dialog_settings_video.qc:72
 msgid "Antialiasing:"
-msgstr ""
+msgstr "Imago polita:"
 
 #: qcsrc/menu/xonotic/dialog_settings_video.qc:75
 msgid ""
 "Enable antialiasing, which smooths the edges of 3D geometry. Note that it "
 "might decrease performance by quite a lot"
 msgstr ""
+"Polire margines rerum tridimensionalium. NB: computatrum minus velox esse "
+"poterit"
 
 #: qcsrc/menu/xonotic/dialog_settings_video.qc:76
 msgid "AA^Disabled"
-msgstr ""
+msgstr "Non polire"
 
 #: qcsrc/menu/xonotic/dialog_settings_video.qc:77
 #: qcsrc/menu/xonotic/dialog_settings_video.qc:94
 msgid "2x"
-msgstr ""
+msgstr "2x"
 
 #: qcsrc/menu/xonotic/dialog_settings_video.qc:78
 #: qcsrc/menu/xonotic/dialog_settings_video.qc:95
 msgid "4x"
-msgstr ""
+msgstr "4x"
 
 #: qcsrc/menu/xonotic/dialog_settings_video.qc:85
 msgid "Resolution scaling:"
index 4aca4beba1b3546f7afd03a2436a1a5a923ec145..a644e7d6f13592082431552b6c2a2a3564dc8476 100644 (file)
@@ -16,6 +16,7 @@
 # Lucifer Morningstar, 2022
 # Lucifer Morningstar, 2022
 # Mehmet Ali Kaplan, 2023
+# Mehmet Ali Kaplan, 2023
 # Tan Siret Akıncı <tanakinci2002@gmail.com>, 2021
 msgid ""
 msgstr ""
@@ -23,7 +24,7 @@ msgstr ""
 "Report-Msgid-Bugs-To: \n"
 "POT-Creation-Date: 2023-07-11 07:22+0200\n"
 "PO-Revision-Date: 2013-09-12 16:53+0000\n"
-"Last-Translator: Mehmet Ali Kaplan, 2023\n"
+"Last-Translator: Tan Siret Akıncı <tanakinci2002@gmail.com>, 2021\n"
 "Language-Team: Turkish (http://app.transifex.com/team-xonotic/xonotic/"
 "language/tr/)\n"
 "Language: tr\n"
index 5a9ab5c0620cf26d10877a06ee237c6497bc7608..645ccf9c5ace196ea1bbd30c87edef95293b3887 100644 (file)
@@ -984,8 +984,8 @@ msgid ""
 "or in all but these game types. You can also specify 'all' as a\n"
 "field to show all fields available for the current game mode."
 msgstr ""
-"在域前你可以放一个 +(或 -)号,后跟一个以逗号分割的游戏类型列表,\n"
-"之后一个斜杠,以使此域仅显示在这些(或除了这些)游戏类型中。你也可以使"
+"在域前你可以放一个 +(或 -)号,后跟一个以逗号分割的游戏模式列表,\n"
+"之后一个斜杠,以使此域仅显示在这些(或除了这些)游戏模式中。你也可以使"
 "用‘all’以显示当前游戏模式的所有域。"
 
 #: qcsrc/client/hud/panel/scoreboard.qc:727
@@ -1324,7 +1324,7 @@ msgstr "^BG按 ^F2%s^BG 以进入游戏"
 #: qcsrc/client/main.qc:1434
 #: qcsrc/menu/xonotic/dialog_multiplayer_join_serverinfotab.qc:38
 msgid "Gametype:"
-msgstr "游戏类型:"
+msgstr "游戏模式:"
 
 #: qcsrc/client/main.qc:1448
 msgid "This match supports"
@@ -1382,7 +1382,7 @@ msgstr "不在意"
 
 #: qcsrc/client/mapvoting.qc:395
 msgid "Decide the gametype"
-msgstr "选择游戏种类"
+msgstr "选择游戏模式"
 
 #: qcsrc/client/mapvoting.qc:395
 msgid "Vote for a map"
@@ -2190,11 +2190,11 @@ msgstr "怪物榴弹"
 
 #: qcsrc/common/mutators/mutator/nades/nades.inc:78
 msgid "Entrap grenade"
-msgstr "速榴弹"
+msgstr "速榴弹"
 
 #: qcsrc/common/mutators/mutator/nades/nades.inc:88
 msgid "Veil grenade"
-msgstr "隐身榴弹"
+msgstr "藏匿榴弹"
 
 #: qcsrc/common/mutators/mutator/nades/nades.inc:99
 msgid "Ammo grenade"
@@ -2202,7 +2202,7 @@ msgstr "弹药榴弹"
 
 #: qcsrc/common/mutators/mutator/nades/nades.inc:109
 msgid "Darkness grenade"
-msgstr "暗榴弹"
+msgstr "暗榴弹"
 
 #: qcsrc/common/mutators/mutator/nades/nades.qc:139
 #: qcsrc/menu/xonotic/keybinder.qc:60
@@ -3574,7 +3574,7 @@ msgstr "^BG%s%s^K1 被 ^BG%s^K1 放的小火球烧着了%s%s"
 #: qcsrc/common/notifications/all.inc:479
 #, c-format
 msgid "^BG%s^K1 should have used a smaller gun%s%s"
-msgstr "^BG%s^K1 驾驭不了这么大的抢%s%s"
+msgstr "^BG%s^K1 没能驾驭这么大的枪%s%s"
 
 #: qcsrc/common/notifications/all.inc:480
 #, c-format
@@ -10274,7 +10274,7 @@ msgstr "InstaGib(瞬杀)"
 
 #: qcsrc/menu/xonotic/serverlist.qh:160
 msgid "SLCAT^Defrag Mode"
-msgstr "Defrag(无杀戮模式)"
+msgstr "Defrag(休闲)"
 
 #: qcsrc/menu/xonotic/skinlist.qc:70
 msgid "<TITLE>"
index b43705995ad82e0e7353d740c0f73e32d42103e1..af080cc6bf301f2c78096f3499951887d05bf697 100644 (file)
@@ -978,8 +978,8 @@ msgid ""
 "or in all but these game types. You can also specify 'all' as a\n"
 "field to show all fields available for the current game mode."
 msgstr ""
-"在域前你可以放一個 +(或 -)號,後跟一個以逗號分割的遊戲類型列表,\n"
-"之後一個斜槓,以使此域僅顯示在這些(或除了這些)遊戲類型中。你也可以使"
+"在域前你可以放一個 +(或 -)號,後跟一個以逗號分割的遊戲模式列表,\n"
+"之後一個斜槓,以使此域僅顯示在這些(或除了這些)遊戲模式中。你也可以使"
 "用‘all’以顯示當前遊戲模式的所有域。"
 
 #: qcsrc/client/hud/panel/scoreboard.qc:727
@@ -1318,7 +1318,7 @@ msgstr "^BG按 ^F2%s^BG 以進入遊戲"
 #: qcsrc/client/main.qc:1434
 #: qcsrc/menu/xonotic/dialog_multiplayer_join_serverinfotab.qc:38
 msgid "Gametype:"
-msgstr "遊戲類型:"
+msgstr "遊戲模式:"
 
 #: qcsrc/client/main.qc:1448
 msgid "This match supports"
@@ -1376,7 +1376,7 @@ msgstr "不在意"
 
 #: qcsrc/client/mapvoting.qc:395
 msgid "Decide the gametype"
-msgstr "選擇遊戲種類"
+msgstr "選擇遊戲模式"
 
 #: qcsrc/client/mapvoting.qc:395
 msgid "Vote for a map"
@@ -2184,11 +2184,11 @@ msgstr "怪物榴彈"
 
 #: qcsrc/common/mutators/mutator/nades/nades.inc:78
 msgid "Entrap grenade"
-msgstr "æ¸\9b速榴彈"
+msgstr "滯速榴彈"
 
 #: qcsrc/common/mutators/mutator/nades/nades.inc:88
 msgid "Veil grenade"
-msgstr "隱身榴彈"
+msgstr "藏匿榴彈"
 
 #: qcsrc/common/mutators/mutator/nades/nades.inc:99
 msgid "Ammo grenade"
@@ -2196,7 +2196,7 @@ msgstr "彈藥榴彈"
 
 #: qcsrc/common/mutators/mutator/nades/nades.inc:109
 msgid "Darkness grenade"
-msgstr "暗榴彈"
+msgstr "暗榴彈"
 
 #: qcsrc/common/mutators/mutator/nades/nades.qc:139
 #: qcsrc/menu/xonotic/keybinder.qc:60
@@ -3568,7 +3568,7 @@ msgstr "^BG%s%s^K1 被 ^BG%s^K1 放的小火球燒着了%s%s"
 #: qcsrc/common/notifications/all.inc:479
 #, c-format
 msgid "^BG%s^K1 should have used a smaller gun%s%s"
-msgstr "^BG%s^K1 駕馭不了這麼大的搶%s%s"
+msgstr "^BG%s^K1 沒能駕馭這麼大的槍%s%s"
 
 #: qcsrc/common/notifications/all.inc:480
 #, c-format
@@ -10268,7 +10268,7 @@ msgstr "InstaGib(瞬殺)"
 
 #: qcsrc/menu/xonotic/serverlist.qh:160
 msgid "SLCAT^Defrag Mode"
-msgstr "Defrag(無殺戮模式)"
+msgstr "Defrag(休閒)"
 
 #: qcsrc/menu/xonotic/skinlist.qc:70
 msgid "<TITLE>"
index ecdf82492cff00c1e51e71b38e3d9de4edead367..7fbefbc6ad487105f54f156bba214b579c0634a5 100644 (file)
@@ -241,7 +241,7 @@ msgstr "^3雙擊^7一個板面以配置特定板面選項。"
 
 #: qcsrc/client/hud/panel/infomessages.qc:231
 msgid "^3CTRL ^7to disable collision testing, ^3SHIFT ^7and"
-msgstr "^3CTRL ^7以用碰撞檢測, ^3SHIFT ^7以及"
+msgstr "^3CTRL ^7以用碰撞檢測, ^3SHIFT ^7以及"
 
 #: qcsrc/client/hud/panel/infomessages.qc:232
 msgid "^3ALT ^7+ ^3ARROW KEYS ^7for fine adjustments."
@@ -986,8 +986,8 @@ msgid ""
 "or in all but these game types. You can also specify 'all' as a\n"
 "field to show all fields available for the current game mode."
 msgstr ""
-"在域前你可以放一個 +(或 -)號,後跟一個以逗號分割的遊戲型別列表,\n"
-"之後一個斜槓,以使此域僅顯示在這些(或除了這些)遊戲型別中。你也可以使"
+"在域前你可以放一個 +(或 -)號,後跟一個以逗號分割的遊戲類型列表,\n"
+"之後一個斜槓,以使此域僅顯示在這些(或除了這些)遊戲類型中。你也可以使"
 "用‘all’以顯示當前遊戲類型的所有域。"
 
 #: qcsrc/client/hud/panel/scoreboard.qc:727
@@ -1327,7 +1327,7 @@ msgstr "^BG按 ^F2%s^BG 以進入遊戲"
 #: qcsrc/client/main.qc:1434
 #: qcsrc/menu/xonotic/dialog_multiplayer_join_serverinfotab.qc:38
 msgid "Gametype:"
-msgstr "遊戲型別:"
+msgstr "遊戲類型:"
 
 #: qcsrc/client/main.qc:1448
 msgid "This match supports"
@@ -1385,7 +1385,7 @@ msgstr "不在意"
 
 #: qcsrc/client/mapvoting.qc:395
 msgid "Decide the gametype"
-msgstr "選擇遊戲種類"
+msgstr "選擇遊戲類型"
 
 #: qcsrc/client/mapvoting.qc:395
 msgid "Vote for a map"
@@ -2193,11 +2193,11 @@ msgstr "怪物榴彈"
 
 #: qcsrc/common/mutators/mutator/nades/nades.inc:78
 msgid "Entrap grenade"
-msgstr "æ¸\9b速榴彈"
+msgstr "滯速榴彈"
 
 #: qcsrc/common/mutators/mutator/nades/nades.inc:88
 msgid "Veil grenade"
-msgstr "隱身榴彈"
+msgstr "藏匿榴彈"
 
 #: qcsrc/common/mutators/mutator/nades/nades.inc:99
 msgid "Ammo grenade"
@@ -2205,7 +2205,7 @@ msgstr "彈藥榴彈"
 
 #: qcsrc/common/mutators/mutator/nades/nades.inc:109
 msgid "Darkness grenade"
-msgstr "暗榴彈"
+msgstr "暗榴彈"
 
 #: qcsrc/common/mutators/mutator/nades/nades.qc:139
 #: qcsrc/menu/xonotic/keybinder.qc:60
@@ -2461,7 +2461,7 @@ msgstr "^1伺服器提示:"
 
 #: qcsrc/common/notifications/all.inc:234
 msgid "^F4NOTE: ^BGChat is currently disabled on this server"
-msgstr "^F4注意:^BG此伺服器當前用了聊天"
+msgstr "^F4注意:^BG此伺服器當前用了聊天"
 
 #: qcsrc/common/notifications/all.inc:235
 msgid "^F4NOTE: ^BGSpectator chat is not sent to players during the match"
@@ -2469,15 +2469,15 @@ msgstr "^F4注意:^BG競賽過程中旁觀者的聊天不會傳送給玩家"
 
 #: qcsrc/common/notifications/all.inc:236
 msgid "^F4NOTE: ^BGPrivate chat is currently disabled on this server"
-msgstr "^F4注意:^BG此伺服器當前用了私密聊天"
+msgstr "^F4注意:^BG此伺服器當前用了私密聊天"
 
 #: qcsrc/common/notifications/all.inc:237
 msgid "^F4NOTE: ^BGSpectator chat is currently disabled on this server"
-msgstr "^F4注意:^BG此伺服器當前用了觀察者聊天"
+msgstr "^F4注意:^BG此伺服器當前用了觀察者聊天"
 
 #: qcsrc/common/notifications/all.inc:238
 msgid "^F4NOTE: ^BGTeam chat is currently disabled on this server"
-msgstr "^F4注意:^BG此伺服器當前用了團隊聊天"
+msgstr "^F4注意:^BG此伺服器當前用了團隊聊天"
 
 #: qcsrc/common/notifications/all.inc:240
 #, c-format
@@ -3276,7 +3276,7 @@ msgstr "^BG%s^F3 耗盡了生命"
 
 #: qcsrc/common/notifications/all.inc:408
 msgid "^BGMonsters are currently disabled"
-msgstr "^BG怪物當前被用"
+msgstr "^BG怪物當前被用"
 
 #: qcsrc/common/notifications/all.inc:410
 msgid "^BGThe ^TC^TT^BG team held the ball for too long"
@@ -3577,7 +3577,7 @@ msgstr "^BG%s%s^K1 被 ^BG%s^K1 放的小火球燒著了%s%s"
 #: qcsrc/common/notifications/all.inc:479
 #, c-format
 msgid "^BG%s^K1 should have used a smaller gun%s%s"
-msgstr "^BG%s^K1 駕馭不了這麼大的搶%s%s"
+msgstr "^BG%s^K1 沒能駕馭這麼大的槍%s%s"
 
 #: qcsrc/common/notifications/all.inc:480
 #, c-format
@@ -4746,7 +4746,7 @@ msgstr ""
 
 #: qcsrc/common/notifications/all.inc:807
 msgid "^F2Intruder detected, disabling shields!"
-msgstr "^F2檢測到入侵者,正在用護盾!"
+msgstr "^F2檢測到入侵者,正在用護盾!"
 
 #: qcsrc/common/notifications/all.inc:809
 msgid ""
@@ -6503,7 +6503,7 @@ msgstr "提示訊息面板"
 #: qcsrc/menu/xonotic/util.qc:762 qcsrc/menu/xonotic/util.qc:778
 #: qcsrc/menu/xonotic/util.qc:795
 msgid "Disable"
-msgstr "用"
+msgstr "用"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_itemstime.qc:17
 #: qcsrc/menu/xonotic/dialog_hudpanel_pressedkeys.qc:15
@@ -7037,7 +7037,7 @@ msgstr "HUD 容器效果:"
 
 #: qcsrc/menu/xonotic/dialog_hudsetup_exit.qc:95
 msgid "DOCK^Disabled"
-msgstr "用"
+msgstr "用"
 
 #: qcsrc/menu/xonotic/dialog_hudsetup_exit.qc:96
 msgid "DOCK^Small"
@@ -7644,7 +7644,7 @@ msgstr "自定義的統計伺服器"
 #: qcsrc/menu/xonotic/dialog_multiplayer_join_serverinfo.qc:203
 #: qcsrc/menu/xonotic/serverlist.qc:1059
 msgid "stats disabled"
-msgstr "用了統計"
+msgstr "用了統計"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_join_serverinfo.qc:203
 #: qcsrc/menu/xonotic/serverlist.qc:1059
@@ -8241,7 +8241,7 @@ msgstr "時間提醒:"
 
 #: qcsrc/menu/xonotic/dialog_settings_audio.qc:170
 msgid "WRN^Disabled"
-msgstr "已用"
+msgstr "已用"
 
 #: qcsrc/menu/xonotic/dialog_settings_audio.qc:172
 msgid "5 minutes"
@@ -8407,7 +8407,7 @@ msgstr "避免有損的紋理壓縮"
 
 #: qcsrc/menu/xonotic/dialog_settings_effects.qc:129
 msgid "Disable sky for performance and visibility"
-msgstr "用天空以提高效能和可見度"
+msgstr "用天空以提高效能和可見度"
 
 #: qcsrc/menu/xonotic/dialog_settings_effects.qc:129
 msgid "Show sky"
@@ -8421,7 +8421,7 @@ msgstr "顯示曲面"
 msgid ""
 "Disable textures completely for very slow hardware. This gives a huge "
 "performance boost, but looks very ugly."
-msgstr "在非常慢的硬體上用材質。這會極大提高效能,但看起來很醜"
+msgstr "在非常慢的硬體上用材質。這會極大提高效能,但看起來很醜"
 
 #: qcsrc/menu/xonotic/dialog_settings_effects.qc:136
 msgid "Use lightmaps"
@@ -8529,7 +8529,7 @@ msgstr "傷害效果:"
 
 #: qcsrc/menu/xonotic/dialog_settings_effects.qc:186
 msgid "DMGFX^Disabled"
-msgstr "用"
+msgstr "用"
 
 #: qcsrc/menu/xonotic/dialog_settings_effects.qc:187
 msgid "Skeletal"
@@ -8894,7 +8894,7 @@ msgstr "在提示訊息中顯示連殺:"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_messages.qc:46
 msgid "SPREES^Disabled"
-msgstr "用"
+msgstr "用"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_messages.qc:47
 msgid "Target"
@@ -9147,7 +9147,7 @@ msgstr "放縮速度:"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_view.qc:82
 msgid "How fast the view will be zoomed, disable to zoom instantly"
-msgstr "視角放縮速度,用以瞬間放縮"
+msgstr "視角放縮速度,用以瞬間放縮"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_view.qc:91
 msgid "ZOOM^Instant"
@@ -9322,7 +9322,7 @@ msgstr "啟用內建滑鼠加速"
 #: qcsrc/menu/xonotic/dialog_settings_input.qc:83
 #: qcsrc/menu/xonotic/dialog_settings_input.qc:86
 msgid "Disable system mouse acceleration"
-msgstr "用內建滑鼠加速"
+msgstr "用內建滑鼠加速"
 
 #: qcsrc/menu/xonotic/dialog_settings_input.qc:80
 msgid "Make use of DGA mouse input"
@@ -9346,7 +9346,7 @@ msgstr "起跳時使用噴氣揹包:"
 
 #: qcsrc/menu/xonotic/dialog_settings_input.qc:102
 msgid "JPJUMP^Disabled"
-msgstr "用"
+msgstr "用"
 
 #: qcsrc/menu/xonotic/dialog_settings_input.qc:103
 msgid "Air only"
@@ -9484,7 +9484,7 @@ msgstr "目標值:"
 
 #: qcsrc/menu/xonotic/dialog_settings_misc.qc:101
 msgid "TRGT^Disabled"
-msgstr "已用"
+msgstr "已用"
 
 #: qcsrc/menu/xonotic/dialog_settings_misc.qc:112
 msgid "Idle limit:"
@@ -9503,11 +9503,11 @@ msgid ""
 "Menu tooltips: disabled, standard or advanced (also shows cvar or console "
 "command bound to the menu item)"
 msgstr ""
-"選單工具提示:已用、標準或高階(也在控制檯顯示繫結到選單項命令的 cvar)"
+"選單工具提示:已用、標準或高階(也在控制檯顯示繫結到選單項命令的 cvar)"
 
 #: qcsrc/menu/xonotic/dialog_settings_misc.qc:127
 msgid "TLTIP^Disabled"
-msgstr "已用"
+msgstr "已用"
 
 #: qcsrc/menu/xonotic/dialog_settings_misc.qc:128
 msgid "TLTIP^Standard"
@@ -9592,7 +9592,7 @@ msgstr "設定語言"
 
 #: qcsrc/menu/xonotic/dialog_settings_user.qc:72
 msgid "Disable gore effects and harsh language"
-msgstr "用血腥效果和惡劣的語言"
+msgstr "用血腥效果和惡劣的語言"
 
 #: qcsrc/menu/xonotic/dialog_settings_user.qc:73
 msgid "Replace blood and gibs with content that does not have any gore effects"
@@ -9708,7 +9708,7 @@ msgstr "啟用抗鋸齒,可以平滑 3D 幾何的邊緣。注意這可能極
 
 #: qcsrc/menu/xonotic/dialog_settings_video.qc:76
 msgid "AA^Disabled"
-msgstr "已用"
+msgstr "已用"
 
 #: qcsrc/menu/xonotic/dialog_settings_video.qc:77
 #: qcsrc/menu/xonotic/dialog_settings_video.qc:94
@@ -9740,7 +9740,7 @@ msgstr "各向異性過濾質量"
 
 #: qcsrc/menu/xonotic/dialog_settings_video.qc:93
 msgid "ANISO^Disabled"
-msgstr "已用"
+msgstr "已用"
 
 #: qcsrc/menu/xonotic/dialog_settings_video.qc:96
 msgid "8x"
@@ -9762,7 +9762,7 @@ msgstr "透過在正常渲染開始前繪製一份場景的僅深度版本來防
 
 #: qcsrc/menu/xonotic/dialog_settings_video.qc:105
 msgid "DF^Disabled"
-msgstr "已用"
+msgstr "已用"
 
 #: qcsrc/menu/xonotic/dialog_settings_video.qc:106
 msgid "DF^World"
@@ -10277,7 +10277,7 @@ msgstr "InstaGib(瞬殺)"
 
 #: qcsrc/menu/xonotic/serverlist.qh:160
 msgid "SLCAT^Defrag Mode"
-msgstr "Defrag(無殺戮模式)"
+msgstr "Defrag(休閒)"
 
 #: qcsrc/menu/xonotic/skinlist.qc:70
 msgid "<TITLE>"
index 01d297e084a27827809150fc6aa2cfd705b9bc7b..a859acbded174ebaf334b8725ea30439b342c45a 100644 (file)
@@ -265,7 +265,7 @@ set g_ca_round_timelimit 180 "round time limit in seconds"
 set g_ca_teams_override 0
 set g_ca_team_spawns 0 "when 1, players spawn from the team spawnpoints of the map, if any"
 set g_ca_teams 0
-set g_ca_prevent_stalemate 0 "when round time ends instead of instant stalemate give round win to the team with most survivors or with the most total health"
+set g_ca_prevent_stalemate 0 "When round time ends instead of instant stalemate give round win to the team with 1: most survivors. 2: most total health. 3: most survivors or if equal then most total health"
 set g_ca_weaponarena "most" "starting weapons - takes the same options as g_weaponarena"
 
 
index a2b96fa153179b628088df986b915daeb51218a1..b1924e24c191ce5e7900b133b303570a98eb9a92 100644 (file)
@@ -8,7 +8,7 @@ es    "Spanish" "Español" 100%
 fr    "French" "Français" 100%
 ga    "Irish" "Irish" 29%
 it    "Italian" "Italiano" 99%
-la    "Latin" "Lingua Latina" 86%
+la    "Latin" "Lingua Latina" 92%
 hu    "Hungarian" "Magyar" 44%
 nl    "Dutch" "Nederlands" 61%
 pl    "Polish" "Polski" 79%
index 559ce3a37c78464f241c7f476e19595047b08c82..b6317debd19d54773dbb3efc201d82c4c0204101 100644 (file)
@@ -63,8 +63,8 @@ sv_jumpspeedcap_min 0
 sv_jumpspeedcap_max ""
 // CPMA has ramp jumping
 sv_jumpspeedcap_max_disable_on_ramps 1
-// FIXME: Q3 teleporters _set_ speed to 400, not cap it
 g_teleport_maxspeed 400
+g_teleport_minspeed 400
 sv_track_canjump 1
 sv_gameplayfix_stepdown_maxspeed 0
 g_movement_highspeed_q3_compat 1
index 7c0c5170e8216ea94536a2395e5881f8e7ce3d92..f1146b858654192c6ebc802807334a981ec4804a 100644 (file)
@@ -36,6 +36,7 @@ sv_jumpspeedcap_min 0 // need predicting? (it should already be in CSQC predicti
 sv_jumpspeedcap_max 0.35
 sv_jumpspeedcap_max_disable_on_ramps 1
 g_teleport_maxspeed 0
+g_teleport_minspeed 0
 sv_track_canjump 0
 sv_gameplayfix_stepdown_maxspeed 0
 g_movement_highspeed_q3_compat 0
index fdefb9ccaf724f55c4247e3203fcc2aca2569ddf..55f26de719382d069e7cf8d2c0a0c2ccf1dc1e6b 100644 (file)
@@ -37,6 +37,7 @@ sv_jumpspeedcap_min ""
 sv_jumpspeedcap_max ""
 sv_jumpspeedcap_max_disable_on_ramps 0
 g_teleport_maxspeed 0
+g_teleport_minspeed 0
 sv_track_canjump 0
 sv_gameplayfix_stepdown_maxspeed 0
 g_movement_highspeed_q3_compat 0
index 25f2b54d6f186a98b4078837dcca526586050699..e80bac1350db5d45125523bd70b1b39206fff389 100644 (file)
@@ -45,6 +45,7 @@ sv_jumpspeedcap_min 0 // need predicting? (it should already be in CSQC predicti
 sv_jumpspeedcap_max ""
 sv_jumpspeedcap_max_disable_on_ramps 1
 g_teleport_maxspeed 0
+g_teleport_minspeed 0
 sv_track_canjump 0
 sv_gameplayfix_stepdown_maxspeed 0
 g_movement_highspeed_q3_compat 0
index 5edcfbe27b48a306962295049c6e0cf05874e68d..5e4a81633b8d1f36e285786f8ffd47ee642aaf3b 100644 (file)
@@ -45,6 +45,7 @@ sv_jumpspeedcap_min ""
 sv_jumpspeedcap_max ""
 sv_jumpspeedcap_max_disable_on_ramps 1
 g_teleport_maxspeed 0
+g_teleport_minspeed 0
 sv_track_canjump 0
 sv_gameplayfix_stepdown_maxspeed 0
 g_movement_highspeed_q3_compat 0
index a4bdd08ca12be3c403daeba5707d584a48a4e883..13d059108cf6cdae15154a8b59eaf17bd01e7421 100644 (file)
@@ -40,6 +40,7 @@ sv_jumpspeedcap_min ""
 sv_jumpspeedcap_max 0.38
 sv_jumpspeedcap_max_disable_on_ramps 0
 g_teleport_maxspeed 0
+g_teleport_minspeed 0
 sv_track_canjump 0
 sv_gameplayfix_stepdown_maxspeed 0
 g_movement_highspeed_q3_compat 0
index 8d54437fb82751732490a9fa5c4f59b3ea14a6c7..6bcbffb93ba1dc80f6e820bd8891da1fd3a9159f 100644 (file)
@@ -38,6 +38,7 @@ sv_jumpspeedcap_min ""
 sv_jumpspeedcap_max ""
 sv_jumpspeedcap_max_disable_on_ramps 0
 g_teleport_maxspeed 0
+g_teleport_minspeed 0
 sv_track_canjump 0
 sv_gameplayfix_stepdown_maxspeed 0
 g_movement_highspeed_q3_compat 0
index 3ca1ded65ce1ebb2ce281a90dbeb87ee3f8a79e5..af10e6208be50395088e1cbc91293c6b5b082ae8 100644 (file)
@@ -38,6 +38,7 @@ sv_jumpspeedcap_min ""
 sv_jumpspeedcap_max ""
 sv_jumpspeedcap_max_disable_on_ramps 0
 g_teleport_maxspeed 0
+g_teleport_minspeed 0
 sv_track_canjump 0
 sv_gameplayfix_stepdown_maxspeed 0
 g_movement_highspeed_q3_compat 0
index 03056d184e8ed1fe824137c52f0b542826cadc32..22b743528fe81c1f333e74dcd07f00bb6e427021 100644 (file)
@@ -37,6 +37,7 @@ sv_jumpspeedcap_min ""
 sv_jumpspeedcap_max ""
 sv_jumpspeedcap_max_disable_on_ramps 0
 g_teleport_maxspeed 0
+g_teleport_minspeed 0
 sv_track_canjump 0
 sv_gameplayfix_stepdown_maxspeed 0
 g_movement_highspeed_q3_compat 0
index e2aa58971c1b50373ad16f37af9464ff489432e8..703a6a3c641740120555f22ebe90fafcd30b9d6c 100644 (file)
@@ -37,6 +37,7 @@ sv_jumpspeedcap_min ""
 sv_jumpspeedcap_max ""
 sv_jumpspeedcap_max_disable_on_ramps 0
 g_teleport_maxspeed 0
+g_teleport_minspeed 0
 sv_track_canjump 0
 sv_gameplayfix_stepdown_maxspeed 0
 g_movement_highspeed_q3_compat 0
index 26f746a7c0d9ae8e961a1afcebcd11f10d23f516..d5d377b0cd3f4b995c1279a5af2e05d28b83715a 100644 (file)
@@ -37,6 +37,7 @@ sv_jumpspeedcap_min ""
 sv_jumpspeedcap_max ""
 sv_jumpspeedcap_max_disable_on_ramps 0
 g_teleport_maxspeed 0
+g_teleport_minspeed 0
 sv_track_canjump 0
 sv_gameplayfix_stepdown_maxspeed 0
 g_movement_highspeed_q3_compat 0
index 40e7d1f3fca423b90d6c9dd9a0323032975a4f6a..32a4aaac534fee48a15a4bdb89a03c9134f899fd 100644 (file)
@@ -37,6 +37,7 @@ sv_jumpspeedcap_min ""
 sv_jumpspeedcap_max ""
 sv_jumpspeedcap_max_disable_on_ramps 0
 g_teleport_maxspeed 0
+g_teleport_minspeed 0
 sv_track_canjump 0
 sv_gameplayfix_stepdown_maxspeed 0
 g_movement_highspeed_q3_compat 0
index 24e27b01dd2fb07177d893c61fe69d5d07d24116..d0c5e196a86736a266ed0143dd3854c73d4361d1 100644 (file)
@@ -37,6 +37,7 @@ sv_jumpspeedcap_min ""
 sv_jumpspeedcap_max ""
 sv_jumpspeedcap_max_disable_on_ramps 0
 g_teleport_maxspeed 0
+g_teleport_minspeed 0
 sv_track_canjump 0
 sv_gameplayfix_stepdown_maxspeed 0
 g_movement_highspeed_q3_compat 0
index 167d2f4d453efb5a0b155c597915d2d3f3dffac0..a563f39b03af2677395bca10b92df57fb7f7a7cd 100644 (file)
@@ -37,6 +37,7 @@ sv_jumpspeedcap_min ""
 sv_jumpspeedcap_max ""
 sv_jumpspeedcap_max_disable_on_ramps 0
 g_teleport_maxspeed 0
+g_teleport_minspeed 0
 sv_track_canjump 0
 sv_gameplayfix_stepdown_maxspeed 0
 g_movement_highspeed_q3_compat 0
index 6c41d6bbc061e9106bcca2e96b7a9bf22990571a..7bd2891f95048206993f4d82a83fa17659e40fa6 100644 (file)
@@ -37,6 +37,7 @@ sv_jumpspeedcap_min ""
 sv_jumpspeedcap_max ""
 sv_jumpspeedcap_max_disable_on_ramps 0
 g_teleport_maxspeed 0
+g_teleport_minspeed 0
 sv_track_canjump 0
 sv_gameplayfix_stepdown_maxspeed 0
 g_movement_highspeed_q3_compat 0
index c1447c0f091aa748b084ce148ae01af65fc91e98..cf077e6aec2d9207c90d4f095a52c6c8b441a486 100644 (file)
@@ -46,6 +46,7 @@ sv_jumpspeedcap_min ""
 sv_jumpspeedcap_max ""
 sv_jumpspeedcap_max_disable_on_ramps 1
 g_teleport_maxspeed 0
+g_teleport_minspeed 0
 sv_track_canjump 0
 sv_gameplayfix_stepdown_maxspeed 0
 g_movement_highspeed_q3_compat 0
index aa97fb15b4882198f22757aea2be809eca3e5a08..794d1cc4428f7b532c719d18c7a83869a8bfe1ec 100644 (file)
@@ -52,6 +52,7 @@ sv_jumpspeedcap_min ""
 sv_jumpspeedcap_max ""
 sv_jumpspeedcap_max_disable_on_ramps 1
 g_teleport_maxspeed 0
+g_teleport_minspeed 0
 sv_track_canjump 0
 sv_gameplayfix_stepdown_maxspeed 400
 g_movement_highspeed_q3_compat 0
index b84883d88bc4ab4acc2b8ba9244212339068392d..9a5becaa3cb1c30a8024670a46a7296374b4e0c0 100644 (file)
@@ -38,6 +38,7 @@ sv_jumpspeedcap_min ""
 sv_jumpspeedcap_max ""
 sv_jumpspeedcap_max_disable_on_ramps 0
 g_teleport_maxspeed 0
+g_teleport_minspeed 0
 sv_track_canjump 0
 sv_gameplayfix_stepdown_maxspeed 0
 g_movement_highspeed_q3_compat 0
index 5e18a2f0491a46da8c336e884ba00d9d70427c18..3d3c14aeae77888bef6b4710d30eb0542af5e72a 100644 (file)
@@ -38,6 +38,7 @@ sv_jumpspeedcap_min ""
 sv_jumpspeedcap_max ""
 sv_jumpspeedcap_max_disable_on_ramps 0
 g_teleport_maxspeed 0
+g_teleport_minspeed 0
 sv_track_canjump 0
 sv_gameplayfix_stepdown_maxspeed 0
 g_movement_highspeed_q3_compat 0
index c614e817d350d64d1725b9f17da243ffd216379e..7fe21756f74015e5efe5f890c84aaf6cad44d6f7 100644 (file)
@@ -39,6 +39,7 @@ sv_jumpspeedcap_min ""
 sv_jumpspeedcap_max ""
 sv_jumpspeedcap_max_disable_on_ramps 0
 g_teleport_maxspeed 0
+g_teleport_minspeed 0
 sv_track_canjump 0
 sv_gameplayfix_stepdown_maxspeed 0
 g_movement_highspeed_q3_compat 0
index 08fdde547eda7a7f2f9b193f52f2ef3851992875..1e26efb33602e8e74c919ace39f2ed881a266f8b 100644 (file)
@@ -41,8 +41,8 @@ sv_jumpspeedcap_min ""
 // VQ3 has no ramp jumping
 sv_jumpspeedcap_max 270
 sv_jumpspeedcap_max_disable_on_ramps 0
-// FIXME: Q3 teleporters _set_ speed to 400, not cap it
 g_teleport_maxspeed 400
+g_teleport_minspeed 400
 sv_track_canjump 1
 sv_gameplayfix_stepdown_maxspeed 0
 g_movement_highspeed_q3_compat 1
index 4de2fbd88517603b606b3ca9136bffa5a891cac2..c12f3c3ba3998270da07fc7affd61b7538411a29 100644 (file)
@@ -37,6 +37,7 @@ sv_jumpspeedcap_min ""
 sv_jumpspeedcap_max ""
 sv_jumpspeedcap_max_disable_on_ramps 0
 g_teleport_maxspeed 0
+g_teleport_minspeed 0
 sv_track_canjump 0
 sv_gameplayfix_stepdown_maxspeed 0
 g_movement_highspeed_q3_compat 0
index 880504782b2d999ca253d8c1b9dce55d7c8cbbfe..dc2f3a186a3b4e67f6aa0646b0a95a09f6f014b2 100644 (file)
@@ -37,6 +37,7 @@ sv_jumpspeedcap_min ""
 sv_jumpspeedcap_max ""
 sv_jumpspeedcap_max_disable_on_ramps 0
 g_teleport_maxspeed 0
+g_teleport_minspeed 0
 sv_track_canjump 0
 sv_gameplayfix_stepdown_maxspeed 0
 g_movement_highspeed_q3_compat 0
index 88165e03df64da0c0afc56cf714f2898423d53c8..b960eb01b6fb87d9c4dcb12a17c3664379d16958 100644 (file)
@@ -37,6 +37,7 @@ sv_jumpspeedcap_min ""
 sv_jumpspeedcap_max ""
 sv_jumpspeedcap_max_disable_on_ramps 0
 g_teleport_maxspeed 0
+g_teleport_minspeed 0
 sv_track_canjump 0
 sv_gameplayfix_stepdown_maxspeed 0
 g_movement_highspeed_q3_compat 0
index f89927d5d3b18d259ff134cc7a47c637889362b3..189b3307834d090573414ced5d53e09b30a95ccd 100644 (file)
@@ -38,6 +38,7 @@ sv_jumpspeedcap_min ""
 sv_jumpspeedcap_max ""
 sv_jumpspeedcap_max_disable_on_ramps 0
 g_teleport_maxspeed 0
+g_teleport_minspeed 0
 sv_track_canjump 0
 sv_gameplayfix_stepdown_maxspeed 0
 g_movement_highspeed_q3_compat 0
index ac1a96b52a1f9b8306dd2c6d2fdeab1733890295..c891a2b74928704a36d7935794186c611c895771 100644 (file)
@@ -38,6 +38,7 @@ sv_jumpspeedcap_min ""
 sv_jumpspeedcap_max ""
 sv_jumpspeedcap_max_disable_on_ramps 0
 g_teleport_maxspeed 0
+g_teleport_minspeed 0
 sv_track_canjump 0
 sv_gameplayfix_stepdown_maxspeed 0
 g_movement_highspeed_q3_compat 0
index 7f7bcc8d6fbb1ec494ef141a0739b68783bea611..7c9db0fbaeb243566dded3c480ca250853d68944 100644 (file)
@@ -38,6 +38,7 @@ sv_jumpspeedcap_min ""
 sv_jumpspeedcap_max ""
 sv_jumpspeedcap_max_disable_on_ramps 0
 g_teleport_maxspeed 0
+g_teleport_minspeed 0
 sv_track_canjump 0
 sv_gameplayfix_stepdown_maxspeed 0
 g_movement_highspeed_q3_compat 0
index 21ded2a8c859376b438e9b49d7db39e7393bd3b3..f0f984bfa5f397a4a481c0139a145e1dd3883353 100644 (file)
@@ -53,6 +53,7 @@ sv_jumpspeedcap_min ""
 sv_jumpspeedcap_max ""
 sv_jumpspeedcap_max_disable_on_ramps 1
 g_teleport_maxspeed 0
+g_teleport_minspeed 0
 sv_track_canjump 0
 sv_gameplayfix_stepdown_maxspeed 400
 g_movement_highspeed_q3_compat 0
index e350037e60e2da0591270e83014e2c1fcfc6595e..4a6d8bb86051822d8a7a4d8bd0fb27efa667e2b2 100644 (file)
@@ -46,6 +46,7 @@ sv_jumpspeedcap_min ""
 sv_jumpspeedcap_max ""
 sv_jumpspeedcap_max_disable_on_ramps 1
 g_teleport_maxspeed 0
+g_teleport_minspeed 0
 sv_track_canjump 0
 sv_gameplayfix_stepdown_maxspeed 400
 g_movement_highspeed_q3_compat 0
index c7c2250e7c91a74f47cc64a8f6600f2a2f39464c..b3936901c42eb87da825eaed8ca1cb3de676e162 100644 (file)
@@ -52,6 +52,7 @@ sv_jumpspeedcap_min ""
 sv_jumpspeedcap_max ""
 sv_jumpspeedcap_max_disable_on_ramps 1
 g_teleport_maxspeed 0
+g_teleport_minspeed 0
 sv_track_canjump 0
 sv_gameplayfix_stepdown_maxspeed 400
 g_movement_highspeed_q3_compat 0
index 1436bbdcb85bd00952a04855674d21957a779820..8baf5be7ec41282d89a97cc33d1f1e82a6a0dff4 100644 (file)
@@ -44,6 +44,7 @@ sv_jumpspeedcap_min 0
 sv_jumpspeedcap_max 0.5
 sv_jumpspeedcap_max_disable_on_ramps 1
 g_teleport_maxspeed 600
+g_teleport_minspeed 0
 sv_track_canjump 0
 sv_gameplayfix_stepdown_maxspeed 400
 // needed for correct q3 haste simulation
index 1c86e786d1051d79643a7d0199ff4669421f7674..bab680d68605ac8465b8ae6478e2d326c11e6767 100644 (file)
@@ -44,6 +44,7 @@ sv_jumpspeedcap_min ""
 sv_jumpspeedcap_max ""
 sv_jumpspeedcap_max_disable_on_ramps 1
 g_teleport_maxspeed 0
+g_teleport_minspeed 0
 sv_track_canjump 0
 sv_gameplayfix_stepdown_maxspeed 400
 g_movement_highspeed_q3_compat 0
index 58d497aab77b176a9ef60b951762e60d7eecac95..9e214551097dd0dc60e5d3431cbfd4df32b43ecc 100644 (file)
@@ -1060,13 +1060,25 @@ bool CSQC_Parse_TempEntity()
        return false;
 }
 
+bool autocvar_r_drawfog;
+bool autocvar_r_fog_exp2;
 string forcefog;
 void Fog_Force()
 {
        if (autocvar_cl_orthoview && autocvar_cl_orthoview_nofog)
-               localcmd("\nr_drawfog 0\n");
+       {
+               if (autocvar_r_drawfog)
+                       cvar_set("r_drawfog", "0");
+       }
        else if (forcefog != "")
-               localcmd(sprintf("\nfog %s\nr_fog_exp2 0\nr_drawfog 1\n", forcefog));
+       {
+               // using cvar_set as it's faster and safer than a command
+               if (!autocvar_r_drawfog)
+                       cvar_set("r_drawfog", "1");
+               if (autocvar_r_fog_exp2)
+                       cvar_set("r_fog_exp2", "0");
+               localcmd(sprintf("\nfog %s\n", forcefog));
+       }
 }
 
 bool net_handle_ServerWelcome();
index a9496ea15310ba50332e9480692c4e30bacc2502..689f4b4cecbdd80ad0c119f2c42fce5be85977bc 100644 (file)
@@ -481,7 +481,7 @@ vector GetCurrentFov(float fov)
                }
        }
 
-       if(almost_equals(current_viewzoom, 1))
+       if(zoomfactor == 1 || current_viewzoom > 0.999) // zoomfactor check prevents a division by 0
                current_zoomfraction = 0;
        else if(almost_equals(current_viewzoom, 1/zoomfactor))
                current_zoomfraction = 1;
@@ -1200,6 +1200,7 @@ void View_PostProcessing()
 {
        float e1 = (autocvar_hud_postprocessing_maxbluralpha != 0);
        float e2 = (autocvar_hud_powerup != 0);
+       bool want_postprocessing = false;
        if(autocvar_hud_postprocessing && (e1 || e2)) // TODO: Remove this code and re-do the postprocess handling in the engine, where it properly belongs.
        {
                // enable or disable rendering types if they are used or not
@@ -1217,6 +1218,7 @@ void View_PostProcessing()
                                old_blurradius = blurradius;
                                old_bluralpha = bluralpha;
                        }
+                       want_postprocessing = true;
                }
                else if(cvar_string("r_glsl_postprocess_uservec1") != "0 0 0 0") // reduce cvar_set spam as much as possible
                {
@@ -1243,18 +1245,24 @@ void View_PostProcessing()
                                cvar_set("r_glsl_postprocess_uservec2", strcat(ftos((sharpen_intensity / 5) * autocvar_hud_powerup), " ", ftos(-sharpen_intensity * autocvar_hud_powerup), " 0 0"));
                                old_sharpen_intensity = sharpen_intensity;
                        }
+                       want_postprocessing = true;
                }
                else if(cvar_string("r_glsl_postprocess_uservec2") != "0 0 0 0") // reduce cvar_set spam as much as possible
                {
                        cvar_set("r_glsl_postprocess_uservec2", "0 0 0 0");
                        old_sharpen_intensity = 0;
                }
-
+       }
+       if (want_postprocessing)
+       {
                if(cvar("r_glsl_postprocess") == 0)
                        cvar_set("r_glsl_postprocess", "2");
        }
-       else if(cvar("r_glsl_postprocess") == 2)
-               cvar_set("r_glsl_postprocess", "0");
+       else
+       {
+               if(cvar("r_glsl_postprocess") == 2)
+                       cvar_set("r_glsl_postprocess", "0");
+       }
 }
 
 void View_Lock()
index f0a793afd50f4d39aa2d28fe1e3bfc313e438e43..8ee0a676569b8364f931e52b7a976c87d2f858ef 100644 (file)
@@ -1,7 +1,7 @@
 #include "sv_clanarena.qh"
 
 float autocvar_g_ca_damage2score = 100;
-bool autocvar_g_ca_prevent_stalemate;
+int autocvar_g_ca_prevent_stalemate;
 
 float autocvar_g_ca_start_health = 200;
 float autocvar_g_ca_start_armor = 200;
@@ -46,80 +46,95 @@ void nades_Clear(entity player);
 
 int CA_PreventStalemate()
 {
-       //LOG_INFO("PreventStalemate running");
-       int winnerTeam = 0;
-       int secondTeam = 0;
+       //bprint("PreventStalemate running\n");
 
-       for(int i = 1; i <= AVAILABLE_TEAMS; i++)
+       // g_ca_prevent_stalemate:
+       // Run survivor count check with 1 aka bit 0b0001
+       // Run total health check with 2 aka bit 0b0010
+       // With a value like 3 which has both bits both are ran
+
+       bool prevent_stalemate_by_survivors = (autocvar_g_ca_prevent_stalemate & BIT(0));
+       bool prevent_stalemate_by_health    = (autocvar_g_ca_prevent_stalemate & BIT(1));
+
+       // Check which team has more alive players
+       if (prevent_stalemate_by_survivors)
        {
-               if(!winnerTeam || Team_GetNumberOfAlivePlayers(Team_GetTeamFromIndex(i)) > Team_GetNumberOfAlivePlayers(Team_GetTeam(winnerTeam)))
+               int winnerTeam = 0;
+               int secondTeam = 0;
+
+               for(int i = 1; i <= AVAILABLE_TEAMS; ++i)
                {
-                       secondTeam = winnerTeam;
-                       winnerTeam = Team_IndexToTeam(i);
+                       if(!winnerTeam || Team_GetNumberOfAlivePlayers(Team_GetTeamFromIndex(i)) > Team_GetNumberOfAlivePlayers(Team_GetTeam(winnerTeam)))
+                       {
+                               secondTeam = winnerTeam;
+                               winnerTeam = Team_IndexToTeam(i);
+                       }
+                       else
+                       {
+                               if(!secondTeam || Team_GetNumberOfAlivePlayers(Team_GetTeamFromIndex(i)) > Team_GetNumberOfAlivePlayers(Team_GetTeam(secondTeam)))
+                                       secondTeam = Team_IndexToTeam(i);
+                       }
                }
-               else
+
+               if(Team_GetNumberOfAlivePlayers(Team_GetTeam(winnerTeam)) != Team_GetNumberOfAlivePlayers(Team_GetTeam(secondTeam)))
                {
-                       if(!secondTeam || Team_GetNumberOfAlivePlayers(Team_GetTeamFromIndex(i)) > Team_GetNumberOfAlivePlayers(Team_GetTeam(secondTeam)))
-                               secondTeam = Team_IndexToTeam(i);
+                       bprint(sprintf("Stalemate broken by alive players. Best team: %s%s (%d)^7 - Trailing team: %s%s (%d)\n",
+                               Team_ColorCode(winnerTeam), Team_ColorName(winnerTeam), Team_GetNumberOfAlivePlayers(Team_GetTeam(winnerTeam)),
+                               Team_ColorCode(secondTeam), Team_ColorName(secondTeam), Team_GetNumberOfAlivePlayers(Team_GetTeam(secondTeam))));
+                       return winnerTeam;
                }
        }
 
-       if(Team_GetNumberOfAlivePlayers(Team_GetTeam(winnerTeam)) != Team_GetNumberOfAlivePlayers(Team_GetTeam(secondTeam)))
+       // Check which team has more health
+       if (prevent_stalemate_by_health)
        {
-               LOG_INFOF("Stalemate broken by alive players. Best team: %s%s (%d)^7 - Trailing team: %s%s (%d)",
-                       Team_ColorCode(winnerTeam), Team_ColorName(winnerTeam), Team_GetNumberOfAlivePlayers(Team_GetTeam(winnerTeam)),
-                       Team_ColorCode(secondTeam), Team_ColorName(secondTeam), Team_GetNumberOfAlivePlayers(Team_GetTeam(secondTeam)));
-               return winnerTeam;
-       }
-
-       // Equality. Let's check which team has more health now
-       //LOG_INFO("Equality. Checking health now.");
-       winnerTeam = 0;
-       secondTeam = 0;
-       int winnerTeamHealth = 0;
-       int secondTeamHealth = 0;
-       int teamIndex, teamHealth;
+               int winnerTeam = 0;
+               int secondTeam = 0;
+               int winnerTeamHealth = 0;
+               int secondTeamHealth = 0;
+               int teamIndex, teamHealth;
 
-       for(int i = 1; i <= AVAILABLE_TEAMS; i++)
-       {
-               teamIndex = i;
-               teamHealth = 0;
-
-               // Add up health for the players in this team
-               FOREACH_CLIENT(IS_PLAYER(it) && Entity_HasValidTeam(it) && it.team == Team_IndexToTeam(teamIndex),
+               for(int i = 1; i <= AVAILABLE_TEAMS; ++i)
                {
-                       if (IS_DEAD(it))
-                               continue;
-                       teamHealth += GetResource(it, RES_HEALTH) + GetResource(it, RES_ARMOR);
-               });
+                       teamIndex = i;
+                       teamHealth = 0;
 
-               // Set the winner teams
-               if(!winnerTeam || teamHealth > winnerTeamHealth)
-               {
-                       secondTeam = winnerTeam;
-                       secondTeamHealth = winnerTeamHealth;
-                       winnerTeam = Team_IndexToTeam(i);
-                       winnerTeamHealth = teamHealth;
-               }
-               else
-               {
-                       if(!secondTeam || teamHealth > secondTeamHealth)
+                       // Add up health for the players in this team
+                       FOREACH_CLIENT(IS_PLAYER(it) && Entity_HasValidTeam(it) && it.team == Team_IndexToTeam(teamIndex),
+                       {
+                               if (IS_DEAD(it))
+                                       continue;
+                               teamHealth += GetResource(it, RES_HEALTH) + GetResource(it, RES_ARMOR);
+                       });
+
+                       // Set the winner teams
+                       if(!winnerTeam || teamHealth > winnerTeamHealth)
+                       {
+                               secondTeam = winnerTeam;
+                               secondTeamHealth = winnerTeamHealth;
+                               winnerTeam = Team_IndexToTeam(i);
+                               winnerTeamHealth = teamHealth;
+                       }
+                       else
                        {
-                               secondTeam = Team_IndexToTeam(i);
-                               secondTeamHealth = teamHealth;
+                               if(!secondTeam || teamHealth > secondTeamHealth)
+                               {
+                                       secondTeam = Team_IndexToTeam(i);
+                                       secondTeamHealth = teamHealth;
+                               }
                        }
                }
-       }
 
-       if(winnerTeamHealth != secondTeamHealth)
-       {
-               LOG_INFOF("Stalemate broken by team health. Best team: %s%s (%d)^7 - Trailing team: %s%s (%d)",
-                       Team_ColorCode(winnerTeam), Team_ColorName(winnerTeam), winnerTeamHealth,
-                       Team_ColorCode(secondTeam), Team_ColorName(secondTeam), secondTeamHealth);
-               return winnerTeam;
+               if(winnerTeamHealth != secondTeamHealth)
+               {
+                       bprint(sprintf("Stalemate broken by team health. Best team: %s%s (%d)^7 - Trailing team: %s%s (%d)\n",
+                               Team_ColorCode(winnerTeam), Team_ColorName(winnerTeam), winnerTeamHealth,
+                               Team_ColorCode(secondTeam), Team_ColorName(secondTeam), secondTeamHealth));
+                       return winnerTeam;
+               }
        }
-       else
-               return -2; // Equality. Can't avoid the stalemate.
+
+       return -2; // Equality. Can't avoid the stalemate.
 }
 
 float CA_CheckWinner()
@@ -128,7 +143,11 @@ float CA_CheckWinner()
 
        if(round_handler_GetEndTime() > 0 && round_handler_GetEndTime() - time <= 0)
        {
-               if(autocvar_g_ca_prevent_stalemate)
+               // attempt to prevent stalemate by survivor count AND/OR total team health?
+               bool prevent_stalemate_by_survivors = (autocvar_g_ca_prevent_stalemate & BIT(0));
+               bool prevent_stalemate_by_health    = (autocvar_g_ca_prevent_stalemate & BIT(1));
+
+               if(prevent_stalemate_by_survivors || prevent_stalemate_by_health)
                        winner_team = CA_PreventStalemate();
                else
                        winner_team = -2;
index 77fbfc231633cda534ad78aeca6e3484cb2cfdbf..3f7fff9ebe3ad5bfc01b4f1ae582c26b4b273ddb 100644 (file)
@@ -167,8 +167,11 @@ void freezetag_Add_Score(entity targ, entity attacker)
        {
                // got frozen by an enemy
                // counted as "kill" and "death" already
+               if(SAME_TEAM(attacker, targ))
+                       GameRules_scoring_add(attacker, SCORE, -1);
+               else
+                       GameRules_scoring_add(attacker, SCORE, +1);
                GameRules_scoring_add(targ, SCORE, -1);
-               GameRules_scoring_add(attacker, SCORE, +1);
        }
        // else nothing - got frozen by the game type rules themselves
 }
@@ -365,6 +368,11 @@ MUTATOR_HOOKFUNCTION(ft, PlayerDies)
 
        if(ITEM_DAMAGE_NEEDKILL(frag_deathtype))
        {
+               // can't use freezetag_Add_Score here since it doesn't assign any points
+               // if the attacker is not a player (e.g. triggerhurt) by design
+               if ((STAT(FROZEN, frag_target) != FROZEN_NORMAL) && !IS_PLAYER(frag_attacker))
+                       GameRules_scoring_add(frag_target, SCORE, -1);
+
                // by restoring some health right after player death (soft-kill)
                // weapons and ammo won't be reset
                SetResourceExplicit(frag_target, RES_HEALTH, 1);
index 82a7e758413de31ffd73eae094b93717c67fb678..e66ebb7671d4b85e9dc832d690d9e11e67392b44 100644 (file)
@@ -1167,14 +1167,14 @@ float MapInfo_Get_ByName_NoFallbacks(string pFilename, int pAllowGenerate, Gamet
                {
                        MapInfo_Map_flags |= MAPINFO_FLAG_FRUSTRATING;
                }
-               else if(t == "noautomaplist")
+               else if(t == "donotwant" || t == "noautomaplist")
                {
-                       MapInfo_Map_flags |= MAPINFO_FLAG_NOAUTOMAPLIST;
+                       MapInfo_Map_flags |= MAPINFO_FLAG_DONOTWANT;
                }
                else if(t == "gameversion_min")
                {
                        if (cvar("gameversion") < stof(s))
-                               MapInfo_Map_flags |= MAPINFO_FLAG_NOAUTOMAPLIST;
+                               MapInfo_Map_flags |= MAPINFO_FLAG_DONOTWANT;
                }
                else if(t == "type")
                {
index 952274a73aaf0fe584a47cf2f2583478345abe8c..4d65695ae41a9391d19b1f145440c1942bfc5e70 100644 (file)
@@ -123,7 +123,7 @@ ENDCLASS(Gametype)
 
 REGISTRY(Gametypes, 32)
 REGISTER_REGISTRY(Gametypes)
-REGISTRY_SORT(Gametypes);
+REGISTRY_SORT(Gametypes)
 REGISTRY_CHECK(Gametypes)
 
 REGISTRY_DEFINE_GET(Gametypes, NULL)
@@ -143,7 +143,7 @@ const int MAPINFO_FEATURE_MONSTERS      = 8;
 const int MAPINFO_FLAG_HIDDEN           = 1; // not in lsmaps/menu/vcall/etc., can just be changed to manually
 const int MAPINFO_FLAG_FORBIDDEN        = 2; // don't even allow the map by a cvar setting that allows hidden maps
 const int MAPINFO_FLAG_FRUSTRATING      = 4; // this map is near impossible to play, enable at your own risk
-const int MAPINFO_FLAG_NOAUTOMAPLIST    = 8; // do not include when automatically building maplist (counts as hidden for maplist building purposes)
+const int MAPINFO_FLAG_DONOTWANT        = 8; // do not include in GUI voting screen or select in GotoNextMap()/GetNextMap(), unless added with `suggestmap` or required as a fallback
 
 float MapInfo_count;
 
index 1316c3283003e6ce5b5a573e47960eebdb9c2020..ba2e53d27d027c2a01bbcd38736fec993665b60b 100644 (file)
@@ -29,6 +29,7 @@ void door_blocked(entity this, entity blocker)
 {
        bool reverse = false;
        if((this.spawnflags & DOOR_CRUSH)
+               && !Q3COMPAT_COMMON
 #ifdef SVQC
                && (blocker.takedamage != DAMAGE_NO)
 #elif defined(CSQC)
@@ -43,46 +44,46 @@ void door_blocked(entity this, entity blocker)
        else
        {
 #ifdef SVQC
-               if((this.dmg) && (blocker.takedamage == DAMAGE_YES))    // Shall we bite?
+               if (this.dmg && blocker.takedamage != DAMAGE_NO)    // Shall we bite?
                        Damage (blocker, this, this, this.dmg, DEATH_HURTTRIGGER.m_id, DMG_NOWEP, blocker.origin, '0 0 0');
 #endif
 
-                // don't change direction for dead or dying stuff
-               if(IS_DEAD(blocker)
+               // don't change direction for dead or dying stuff
+               if (!IS_DEAD(blocker)
 #ifdef SVQC
-                       && (blocker.takedamage == DAMAGE_NO)
+                       && blocker.takedamage != DAMAGE_NO
 #endif
+                       && this.wait >= 0
+                       && !(Q3COMPAT_COMMON && (this.spawnflags & Q3_DOOR_CRUSHER))
                )
                {
-                       if (this.wait >= 0)
+                       if (this.state == STATE_DOWN)
                        {
-                               if (this.state == STATE_DOWN)
-                               {
-                                       if (this.classname == "door")
-                                               door_go_up(this, NULL, NULL);
-                                       else
-                                               door_rotating_go_up(this, blocker);
-                               }
+                               if (this.classname == "door")
+                                       door_go_up(this, NULL, NULL);
                                else
-                               {
-                                       if (this.classname == "door")
-                                               door_go_down(this);
-                                       else
-                                               door_rotating_go_down(this);
-                               }
-                               reverse = true;
+                                       door_rotating_go_up(this, blocker);
                        }
+                       else
+                       {
+                               if (this.classname == "door")
+                                       door_go_down(this);
+                               else
+                                       door_rotating_go_down(this);
+                       }
+                       reverse = true;
                }
 #ifdef SVQC
                else
                {
                        //gib dying stuff just to make sure
-                       if((this.dmg) && (blocker.takedamage != DAMAGE_NO))    // Shall we bite?
+                       if (this.dmg && blocker.takedamage != DAMAGE_NO && IS_DEAD(blocker))    // Shall we bite?
                                Damage (blocker, this, this, 10000, DEATH_HURTTRIGGER.m_id, DMG_NOWEP, blocker.origin, '0 0 0');
                }
 #endif
        }
-       if (!reverse && this.classname == "door")
+       // if we didn't change direction and are using a non-linear movement controller, we must pause it
+       if (!reverse && this.classname == "door" && this.move_controller)
                SUB_CalcMovePause(this);
 }
 
@@ -212,10 +213,13 @@ bool door_check_keys(entity door, entity player)
        return false;
 }
 
-void door_fire(entity this, entity actor, entity trigger)
+void door_use(entity this, entity actor, entity trigger)
 {
-       if (this.owner != this)
-               objerror (this, "door_fire: this.owner != this");
+       //dprint("door_use (model: ");dprint(this.model);dprint(")\n");
+
+       if (!this.owner)
+               return;
+       this = this.owner;
 
        if (this.spawnflags & DOOR_TOGGLE)
        {
@@ -256,14 +260,6 @@ void door_fire(entity this, entity actor, entity trigger)
        } while ((e != this) && (e != NULL));
 }
 
-void door_use(entity this, entity actor, entity trigger)
-{
-       //dprint("door_use (model: ");dprint(this.model);dprint(")\n");
-
-       if (this.owner)
-               door_fire(this.owner, actor, trigger);
-}
-
 void door_damage(entity this, entity inflictor, entity attacker, float damage, int deathtype, .entity weaponentity, vector hitloc, vector force)
 {
        if(this.spawnflags & NOSPLASH)
@@ -369,14 +365,25 @@ void door_trigger_touch(entity this, entity toucher)
 #endif
                        return;
 
-       if (time < this.door_finished)
+       if (this.owner.state == STATE_UP)
                return;
 
        // check if door is locked
        if (!door_check_keys(this, toucher))
                return;
 
-       this.door_finished = time + 1;
+       if (this.owner.state == STATE_TOP)
+       {
+               if (this.owner.nextthink < this.owner.ltime + this.owner.wait)
+               {
+                       entity e = this.owner;
+                       do {
+                               e.nextthink = e.ltime + e.wait;
+                               e = e.enemy;
+                       } while (e != this.owner);
+               }
+               return;
+       }
 
        door_use(this.owner, toucher, NULL);
 }
@@ -408,7 +415,8 @@ LinkDoors
 
 entity LinkDoors_nextent(entity cur, entity near, entity pass)
 {
-       while((cur = find(cur, classname, pass.classname)) && ((cur.spawnflags & DOOR_DONT_LINK) || cur.enemy))
+       while ((cur = find(cur, classname, pass.classname))
+       && ((!Q3COMPAT_COMMON && (cur.spawnflags & DOOR_DONT_LINK)) || cur.enemy))
        {
        }
        return cur;
@@ -416,6 +424,9 @@ entity LinkDoors_nextent(entity cur, entity near, entity pass)
 
 bool LinkDoors_isconnected(entity e1, entity e2, entity pass)
 {
+       if(Q3COMPAT_COMMON)
+               return e1.team == e2.team;
+
        float DELTA = 4;
        if((e1.absmin_x > e2.absmax_x + DELTA)
        || (e1.absmin_y > e2.absmax_y + DELTA)
@@ -441,7 +452,9 @@ void LinkDoors(entity this)
 
        if (this.enemy)
                return;         // already linked by another door
-       if (this.spawnflags & DOOR_DONT_LINK)
+
+       // Q3 door linking is done for teamed doors only and is not affected by spawnflags or bmodel proximity
+       if ((!Q3COMPAT_COMMON && (this.spawnflags & DOOR_DONT_LINK)) || (Q3COMPAT_COMMON && !this.team))
        {
                this.owner = this.enemy = this;
 
@@ -544,7 +557,7 @@ SILVER_KEY causes the door to open only if the activator holds a silver key.
 "speed"                movement speed (100 default)
 "wait"         wait before returning (3 default, -1 = never return)
 "lip"          lip remaining at end of move (8 default)
-"dmg"          damage to inflict when blocked (2 default)
+"dmg"          damage to inflict when blocked (0 default)
 "sounds"
 0)     no sound
 1)     stone
@@ -666,14 +679,28 @@ void door_init_shared(entity this)
 
        if (q3compat)
        {
-               // CPMA adds these fields for overriding the engine sounds
+               // CPMA adds these fields for overriding the Q3 default sounds
                string s = GetField_fullspawndata(this, "sound_start", true);
                string e = GetField_fullspawndata(this, "sound_end", true);
 
                if (s)
                        this.noise2 = strzone(s);
+               else
+               {
+                       // PK3s supporting Q3A sometimes include custom sounds at Q3 default paths
+                       s = "sound/movers/doors/dr1_strt.wav";
+                       if (FindFileInMapPack(s))
+                               this.noise2 = s;
+               }
+
                if (e)
                        this.noise1 = strzone(e);
+               else
+               {
+                       e = "sound/movers/doors/dr1_end.wav";
+                       if (FindFileInMapPack(e))
+                               this.noise1 = e;
+               }
        }
 
        // sound when door stops moving
@@ -693,7 +720,7 @@ void door_init_shared(entity this)
        }
        else if (!this.wait)
        {
-               this.wait = 3;
+               this.wait = q3compat ? 2 : 3;
        }
 
        if (!this.lip)
@@ -738,15 +765,20 @@ spawnfunc(func_door)
        if(this.spawnflags & DOOR_NONSOLID)
                this.solid = SOLID_NOT;
 
-// DOOR_START_OPEN is to allow an entity to be lighted in the closed position
-// but spawn in the open position
+       // DOOR_START_OPEN is to allow an entity to be lighted in the closed position
+       // but spawn in the open position
+       // the tuba door on xoylent requires the delayed init
        if (this.spawnflags & DOOR_START_OPEN)
                InitializeEntity(this, door_init_startopen, INITPRIO_SETLOCATION);
 
        door_init_shared(this);
 
        this.pos1 = this.origin;
-       this.pos2 = this.pos1 + this.movedir*(fabs(this.movedir*this.size) - this.lip);
+       vector absmovedir;
+       absmovedir.x = fabs(this.movedir.x);
+       absmovedir.y = fabs(this.movedir.y);
+       absmovedir.z = fabs(this.movedir.z);
+       this.pos2 = this.pos1 + this.movedir * (absmovedir * this.size - this.lip);
 
        if(autocvar_sv_doors_always_open)
        {
@@ -760,10 +792,23 @@ spawnfunc(func_door)
                        this.speed = 100;
        }
 
+       if (q3compat)
+       {
+               if (!this.dmg)
+                       this.dmg = 2;
+
+               if (!this.team)
+               {
+                       string t = GetField_fullspawndata(this, "team");
+                       // bones_was_here: same hack as used to support teamed items on Q3 maps
+                       if (t) this.team = crc16(false, t);
+               }
+       }
+
        settouch(this, door_touch);
 
-// LinkDoors can't be done until all of the doors have been spawned, so
-// the sizes can be detected properly.
+       // LinkDoors can't be done until all of the doors have been spawned, so
+       // the sizes can be detected properly.
        InitializeEntity(this, LinkDoors, INITPRIO_LINKDOORS);
 
        this.reset = door_reset;
index f185f4be8fc96e307ae05ee89078b3174396fb44..ce7025dd5488854e741bb166c9c3e2db8b1a8f2a 100644 (file)
@@ -4,7 +4,7 @@
 bool autocvar_sv_doors_always_open;
 #endif
 
-const int DOOR_START_OPEN = BIT(0);
+const int DOOR_START_OPEN = BIT(0); // has same meaning in Q3: reverse position 1 and 2
 const int DOOR_DONT_LINK = BIT(2);
 const int SPAWNFLAGS_GOLD_KEY = BIT(3); // Quake 1 compat, can only be used with func_door!
 const int SPAWNFLAGS_SILVER_KEY = BIT(4); // Quake 1 compat, can only be used with func_door!
@@ -13,6 +13,7 @@ const int DOOR_TOGGLE = BIT(5);
 const int DOOR_NONSOLID = BIT(10);
 const int DOOR_CRUSH = BIT(11); // can't use CRUSH cause that is the same as DOOR_DONT_LINK
 
+#define Q3_DOOR_CRUSHER BIT(2) // in Q3 this disables the auto reverse so the blocking player takes damage every frame
 
 #ifdef CSQC
 // stuff for preload
index 2376c5956de1adbdc227654e30b819c8d5137b0f..23b9eb5b1725eee170cfd1ab7ab5c020bca102b3 100644 (file)
@@ -7,7 +7,9 @@ void plat_link(entity this);
 void plat_delayedinit(entity this)
 {
        plat_link(this);
-       plat_spawn_inside_trigger(this); // the "start moving" trigger
+       // Q3 uses only a truth check of .targetname to decide whether to spawn a trigger
+       if (!Q3COMPAT_COMMON || this.targetname == "")
+               plat_spawn_inside_trigger(this); // the "start moving" trigger
 }
 
 float plat_send(entity this, entity to, float sf)
@@ -56,7 +58,12 @@ void plat_link(entity this)
 
 spawnfunc(func_plat)
 {
-       if (this.spawnflags & CRUSH)
+       if (q3compat)
+       {
+               this.spawnflags = 0; // Q3 plats have no spawnflags
+               if (!this.dmg) this.dmg = 2;
+       }
+       else if (this.spawnflags & CRUSH)
        {
                this.dmg = 10000;
        }
@@ -91,14 +98,28 @@ spawnfunc(func_plat)
 
        if (q3compat)
        {
-               // CPMA adds these fields for overriding the engine sounds
+               // CPMA adds these fields for overriding the Q3 default sounds
                string s = GetField_fullspawndata(this, "sound_start", true);
                string e = GetField_fullspawndata(this, "sound_end", true);
 
                if (s)
                        this.noise = strzone(s);
+               else
+               {
+                       // PK3s supporting Q3A sometimes include custom sounds at Q3 default paths
+                       s = "sound/movers/plats/pt1_strt.wav";
+                       if (FindFileInMapPack(s))
+                               this.noise = s;
+               }
+
                if (e)
                        this.noise1 = strzone(e);
+               else
+               {
+                       e = "sound/movers/plats/pt1_end.wav";
+                       if (FindFileInMapPack(e))
+                               this.noise1 = e;
+               }
        }
 
        if(this.noise && this.noise != "")
@@ -122,8 +143,8 @@ spawnfunc(func_plat)
 
        setblocked(this, plat_crush);
 
-       if (!this.speed) this.speed = 150;
-       if (!this.lip) this.lip = 16;
+       if (!this.speed) this.speed = q3compat ? 200 : 150;
+       if (!this.lip) this.lip = q3compat ? 8 : 16;
        if (!this.height) this.height = this.size.z - this.lip;
 
        this.pos1 = this.origin;
@@ -186,7 +207,8 @@ NET_HANDLE(ENT_CLIENT_PLAT, bool isnew)
                set_movetype(this, MOVETYPE_PUSH);
                this.move_time = time;
 
-               plat_spawn_inside_trigger(this);
+               if (!Q3COMPAT_COMMON || this.targetname == "")
+                       plat_spawn_inside_trigger(this);
        }
 
        if(sf & SF_TRIGGER_RESET)
index 28b420b20ab4f2ed6c49bde68e5383d365de1b6b..08458a630b3aa1187e330039111104a4ae7406c4 100644 (file)
@@ -173,13 +173,21 @@ void plat_use(entity this, entity actor, entity trigger)
        plat_go_down(this);
 }
 
+void plat_target_use(entity this, entity actor, entity trigger)
+{
+       if (this.state == STATE_TOP)
+               this.nextthink = this.ltime + 1;
+       else if (this.state != STATE_UP)
+               plat_go_up(this);
+}
+
 // WARNING: backwards compatibility because people don't use already existing fields :(
 // TODO: Check if any maps use these fields and remove these fields if it doesn't break maps
 .string sound1, sound2;
 
 void plat_reset(entity this)
 {
-       if(this.targetname && this.targetname != "")
+       if (this.targetname && this.targetname != "" && !Q3COMPAT_COMMON)
        {
                setorigin(this, this.pos1);
                this.state = STATE_UP;
@@ -189,7 +197,7 @@ void plat_reset(entity this)
        {
                setorigin(this, this.pos2);
                this.state = STATE_BOTTOM;
-               this.use = plat_trigger_use;
+               this.use = (this.targetname != "" && Q3COMPAT_COMMON) ? plat_target_use : plat_trigger_use;
        }
 
 #ifdef SVQC
index f89ab21e2f79ab1903dabc12c10da0cbcefac9ef..09ceba21f0bb4caee58bc093bfb1ea6a11b5e8a6 100644 (file)
@@ -298,6 +298,11 @@ void SUB_CalcMove (entity this, vector tdest, float tspeedtype, float tspeed, vo
                        break;
        }
 
+       // Q3 implements this fallback for all movers at the end of its InitMover()
+       // If .speed is negative this applies, instead of the mover-specific default speed.
+       if (traveltime <= 0)
+               traveltime = 0.001;
+
        // Very short animations don't really show off the effect
        // of controlled animation, so let's just use linear movement.
        // Alternatively entities can choose to specify non-controlled movement.
index 651566c71b6fbec9ff4fd7ef5052a14dea7919ce..98864129cf20daa9e12d8d562a31995b8bc2e7f3 100644 (file)
@@ -225,9 +225,16 @@ entity Simple_TeleportPlayer(entity teleporter, entity player)
 
        if(!(teleporter.classname == "trigger_teleport" && (teleporter.spawnflags & TELEPORT_KEEP_SPEED)) &&
           !(teleporter.classname == "target_teleporter" && (teleporter.spawnflags & TARGET_TELEPORTER_KEEP_SPEED)))
+       {
+               // test if player is slower than min
+               if(STAT(TELEPORT_MINSPEED, player))
+                       if(vdist(player.velocity, <, STAT(TELEPORT_MINSPEED, player)))
+                               player.velocity = normalize(player.velocity) * max(0, STAT(TELEPORT_MINSPEED, player));
+               // test if player is faster than max (or if min is above max)
                if(STAT(TELEPORT_MAXSPEED, player))
                        if(vdist(player.velocity, >, STAT(TELEPORT_MAXSPEED, player)))
                                player.velocity = normalize(player.velocity) * max(0, STAT(TELEPORT_MAXSPEED, player));
+       }
 
        locout = e.origin + '0 0 1' * (1 - player.mins.z - 24);
 
index 9a23879aeeb64add4a9c478394fb87e5199554a9..8383626fc718733f0cfc76f0e5daa69b1166df76 100644 (file)
 #include "cl_damagetext.qh"
 
 CLASS(DamageText, Object)
-    ATTRIB(DamageText, m_color, vector, autocvar_cl_damagetext_color);
-    ATTRIB(DamageText, m_color_friendlyfire, vector, autocvar_cl_damagetext_friendlyfire_color);
-    ATTRIB(DamageText, m_size, float, autocvar_cl_damagetext_size_min);
-    ATTRIB(DamageText, alpha, float, autocvar_cl_damagetext_alpha_start);
-    ATTRIB(DamageText, fade_rate, float, 0);
-    ATTRIB(DamageText, m_shrink_rate, float, 0);
-    ATTRIB(DamageText, m_group, int, 0);
-    ATTRIB(DamageText, m_friendlyfire, bool, false);
-    ATTRIB(DamageText, m_healthdamage, int, 0);
-    ATTRIB(DamageText, m_armordamage, int, 0);
-    ATTRIB(DamageText, m_potential_damage, int, 0);
-    ATTRIB(DamageText, m_deathtype, int, 0);
-    ATTRIB(DamageText, hit_time, float, 0);
-    ATTRIB(DamageText, text, string, string_null);
-    ATTRIB(DamageText, m_screen_coords, bool, false);
-
-    STATIC_ATTRIB(DamageText, screen_count, int, 0);
-
-    void DamageText_draw2d(DamageText this) {
-        float since_hit = time - this.hit_time;
-        // can't use `dt = hit_time - prev_update_time` because shrinking wouldn't be linear
-        float size = this.m_size - since_hit * this.m_shrink_rate * this.m_size;
-        float alpha_ = this.alpha - since_hit * this.fade_rate;
-        if (alpha_ <= 0 || size <= 0) {
-            IL_REMOVE(g_damagetext, this);
-            delete(this);
-            return;
-        }
-
-        vector screen_pos;
-        if (this.m_screen_coords) {
-            screen_pos = this.origin + since_hit * autocvar_cl_damagetext_2d_velocity;
-        } else {
-            vector forward, right, up;
-            MAKE_VECTORS(view_angles, forward, right, up);
-            vector world_offset = since_hit * autocvar_cl_damagetext_velocity_world + autocvar_cl_damagetext_offset_world;
-            vector world_pos = this.origin + world_offset.x * forward + world_offset.y * right + world_offset.z * up;
-            screen_pos = project_3d_to_2d(world_pos) + since_hit * autocvar_cl_damagetext_velocity_screen + autocvar_cl_damagetext_offset_screen;
-        }
-        screen_pos.y += size / 2;
-
-        // strip trailing spaces
-        string dtext = this.text;
-        int j = strlen(dtext) - 1;
-        while (substring(dtext, j, 1) == " " && j >= 0)
-            --j;
-        if (j < strlen(dtext) - 1)
-            dtext = substring(dtext, 0, j + 1);
-
-        // strip leading spaces
-        j = 0;
-        while (substring(dtext, j, 1) == " " && j < strlen(dtext))
-            ++j;
-        if (j > 0)
-            dtext = substring(dtext, j, strlen(dtext) - j);
-
-        // Center damage text
-        screen_pos.x -= stringwidth(dtext, true, hud_fontsize * 2) * 0.5;
-
-        if (screen_pos.z >= 0) {
-            screen_pos.z = 0;
-            vector rgb;
-            if (this.m_friendlyfire) {
-                rgb = this.m_color_friendlyfire;
-            } else {
-                rgb = this.m_color;
-            }
-            if (autocvar_cl_damagetext_color_per_weapon) {
-                Weapon w = DEATH_WEAPONOF(this.m_deathtype);
-                if (w != WEP_Null) rgb = w.wpcolor;
-            }
-
-            vector drawfontscale_save = drawfontscale;
-            drawfontscale = (size / autocvar_cl_damagetext_size_max) * '1 1 0';
-            screen_pos.y -= drawfontscale.x * size / 2;
-            drawcolorcodedstring2_builtin(screen_pos, this.text, autocvar_cl_damagetext_size_max * '1 1 0', rgb, alpha_, DRAWFLAG_NORMAL);
-            drawfontscale = drawfontscale_save;
-        }
-    }
-    ATTRIB(DamageText, draw2d, void(DamageText), DamageText_draw2d);
-
-    void DamageText_update(DamageText this, vector _origin, bool screen_coords, int _health, int _armor, int _potential_damage, int _deathtype) {
-        this.m_healthdamage = _health;
-        this.m_armordamage = _armor;
-        this.m_potential_damage = _potential_damage;
-        this.m_deathtype = _deathtype;
-        this.hit_time = time;
-        setorigin(this, _origin);
-        this.m_screen_coords = screen_coords;
-        if (this.m_screen_coords) {
-            this.alpha = autocvar_cl_damagetext_2d_alpha_start;
-        } else {
-            this.alpha = autocvar_cl_damagetext_alpha_start;
-        }
-
-        int health = rint(this.m_healthdamage / DAMAGETEXT_PRECISION_MULTIPLIER);
-        int armor = rint(this.m_armordamage / DAMAGETEXT_PRECISION_MULTIPLIER);
-        int total = rint((this.m_healthdamage + this.m_armordamage) / DAMAGETEXT_PRECISION_MULTIPLIER);
-        int potential = rint(this.m_potential_damage / DAMAGETEXT_PRECISION_MULTIPLIER);
-        int potential_health = rint((this.m_potential_damage - this.m_armordamage) / DAMAGETEXT_PRECISION_MULTIPLIER);
-
-        bool redundant = almost_equals_eps(this.m_healthdamage + this.m_armordamage, this.m_potential_damage, 5);
-
-        string s = autocvar_cl_damagetext_format;
-        s = strreplace("{armor}", (
-            (this.m_armordamage == 0 && autocvar_cl_damagetext_format_hide_redundant)
-                ? ""
-                : sprintf("%d", armor)
-            ), s);
-        s = strreplace("{potential}", (
-            (redundant && autocvar_cl_damagetext_format_hide_redundant)
-                ? ""
-                : sprintf("%d", potential)
-            ), s);
-        s = strreplace("{potential_health}", (
-            (redundant && autocvar_cl_damagetext_format_hide_redundant)
-                ? ""
-                : sprintf("%d", potential_health)
-            ), s);
-
-        s = strreplace("{health}", (
-            (health == potential_health || !autocvar_cl_damagetext_format_verbose)
-                ? sprintf("%d",      health)
-                : sprintf("%d (%d)", health, potential_health)
-            ), s);
-        s = strreplace("{total}", (
-            (total == potential || !autocvar_cl_damagetext_format_verbose)
-                ? sprintf("%d",      total)
-                : sprintf("%d (%d)", total, potential)
-            ), s);
-
-        // futureproofing: remove any remaining (unknown) format strings in case we add new ones in the future
-        // so players can use them on new servers and still have working damagetext on old ones
-        while (true) {
-            int opening_pos = strstrofs(s, "{", 0);
-            if (opening_pos == -1) break;
-            int closing_pos = strstrofs(s, "}", opening_pos);
-            if (closing_pos == -1 || closing_pos <= opening_pos) break;
-            s = strcat(
-                substring(s, 0, opening_pos),
-                substring_range(s, closing_pos + 1, strlen(s))
-            );
-        }
-
-        strcpy(this.text, s);
-
-        this.m_size = map_bound_ranges(potential,
-            autocvar_cl_damagetext_size_min_damage, autocvar_cl_damagetext_size_max_damage,
-            autocvar_cl_damagetext_size_min, autocvar_cl_damagetext_size_max);
-    }
-
-    CONSTRUCTOR(DamageText, int _group, vector _origin, bool _screen_coords, int _health, int _armor, int _potential_damage, int _deathtype, bool _friendlyfire) {
-        CONSTRUCT(DamageText);
-        this.m_group = _group;
-        this.m_friendlyfire = _friendlyfire;
-        this.m_screen_coords = _screen_coords;
-        if (_screen_coords) {
-            if (autocvar_cl_damagetext_2d_alpha_lifetime)
-                this.fade_rate = 1 / autocvar_cl_damagetext_2d_alpha_lifetime;
-            if (autocvar_cl_damagetext_2d_size_lifetime)
-                this.m_shrink_rate = 1 / autocvar_cl_damagetext_2d_size_lifetime;
-        } else {
-            if (autocvar_cl_damagetext_alpha_lifetime)
-                this.fade_rate = 1 / autocvar_cl_damagetext_alpha_lifetime;
-            this.m_shrink_rate = 0;
-        }
-        DamageText_update(this, _origin, _screen_coords, _health, _armor, _potential_damage, _deathtype);
-        IL_PUSH(g_damagetext, this);
-    }
-
-    DESTRUCTOR(DamageText) {
-        strfree(this.text);
-        --DamageText_screen_count;
-    }
+       ATTRIB(DamageText, m_color, vector, autocvar_cl_damagetext_color);
+       ATTRIB(DamageText, m_color_friendlyfire, vector, autocvar_cl_damagetext_friendlyfire_color);
+       ATTRIB(DamageText, m_size, float, autocvar_cl_damagetext_size_min);
+       ATTRIB(DamageText, alpha, float, autocvar_cl_damagetext_alpha_start);
+       ATTRIB(DamageText, fade_rate, float, 0);
+       ATTRIB(DamageText, m_shrink_rate, float, 0);
+       ATTRIB(DamageText, m_group, int, 0);
+       ATTRIB(DamageText, m_friendlyfire, bool, false);
+       ATTRIB(DamageText, m_healthdamage, int, 0);
+       ATTRIB(DamageText, m_armordamage, int, 0);
+       ATTRIB(DamageText, m_potential_damage, int, 0);
+       ATTRIB(DamageText, m_deathtype, int, 0);
+       ATTRIB(DamageText, hit_time, float, 0);
+       ATTRIB(DamageText, text, string, string_null);
+       ATTRIB(DamageText, m_screen_coords, bool, false);
+
+       STATIC_ATTRIB(DamageText, screen_count, int, 0);
+
+       void DamageText_draw2d(DamageText this)
+       {
+               float since_hit = time - this.hit_time;
+               // can't use `dt = hit_time - prev_update_time` because shrinking wouldn't be linear
+               float size = this.m_size - since_hit * this.m_shrink_rate * this.m_size;
+               float alpha_ = this.alpha - since_hit * this.fade_rate;
+               bool haslifetime = (autocvar_cl_damagetext_lifetime < 0 // negative ignores lifetime
+                               || (since_hit < autocvar_cl_damagetext_lifetime));
+               if (alpha_ <= 0 || size <= 0 || !haslifetime)
+               {
+                       IL_REMOVE(g_damagetext, this);
+                       delete(this);
+                       return;
+               }
+
+               vector screen_pos;
+               if (this.m_screen_coords)
+                       screen_pos = this.origin + since_hit * autocvar_cl_damagetext_2d_velocity;
+               else
+               {
+                       vector forward, right, up;
+                       MAKE_VECTORS(view_angles, forward, right, up);
+
+                       vector world_offset = since_hit * autocvar_cl_damagetext_velocity_world
+                                       + autocvar_cl_damagetext_offset_world;
+                       vector world_pos = this.origin
+                                        + world_offset.x * forward
+                                        + world_offset.y * right
+                                        + world_offset.z * up;
+
+                       screen_pos = project_3d_to_2d(world_pos)
+                               + (since_hit * autocvar_cl_damagetext_velocity_screen)
+                               + autocvar_cl_damagetext_offset_screen;
+               }
+               screen_pos.y += size / 2;
+
+               // strip trailing spaces
+               string dtext = this.text;
+               int j = strlen(dtext) - 1;
+               while (substring(dtext, j, 1) == " " && j >= 0)
+                       --j;
+               if (j < strlen(dtext) - 1)
+                       dtext = substring(dtext, 0, j + 1);
+
+               // strip leading spaces
+               j = 0;
+               while (substring(dtext, j, 1) == " " && j < strlen(dtext))
+                       ++j;
+               if (j > 0)
+                       dtext = substring(dtext, j, strlen(dtext) - j);
+
+               // Center damage text
+               screen_pos.x -= stringwidth(dtext, true, hud_fontsize * 2) * 0.5;
+
+               if (screen_pos.z >= 0)
+               {
+                       screen_pos.z = 0;
+                       vector rgb;
+                       if (this.m_friendlyfire)
+                               rgb = this.m_color_friendlyfire;
+                       else
+                               rgb = this.m_color;
+
+                       if (autocvar_cl_damagetext_color_per_weapon)
+                       {
+                               Weapon w = DEATH_WEAPONOF(this.m_deathtype);
+                               if (w != WEP_Null) rgb = w.wpcolor;
+                       }
+
+                       vector drawfontscale_save = drawfontscale;
+                       drawfontscale = (size / autocvar_cl_damagetext_size_max) * '1 1 0';
+                       screen_pos.y -= drawfontscale.x * size / 2;
+                       drawcolorcodedstring2_builtin(screen_pos, this.text,
+                                       autocvar_cl_damagetext_size_max * '1 1 0',
+                                       rgb, alpha_, DRAWFLAG_NORMAL);
+                       drawfontscale = drawfontscale_save;
+               }
+       }
+       ATTRIB(DamageText, draw2d, void(DamageText), DamageText_draw2d);
+
+       void DamageText_update(DamageText this, vector _origin, bool screen_coords,
+                       int _health, int _armor, int _potential_damage, int _deathtype)
+       {
+               this.m_healthdamage = _health;
+               this.m_armordamage = _armor;
+               this.m_potential_damage = _potential_damage;
+               this.m_deathtype = _deathtype;
+               this.hit_time = time;
+               setorigin(this, _origin);
+               this.m_screen_coords = screen_coords;
+               if (this.m_screen_coords)
+                       this.alpha = autocvar_cl_damagetext_2d_alpha_start;
+               else
+                       this.alpha = autocvar_cl_damagetext_alpha_start;
+
+               int health           = rint(this.m_healthdamage
+                                    / DAMAGETEXT_PRECISION_MULTIPLIER);
+               int armor            = rint(this.m_armordamage
+                                    / DAMAGETEXT_PRECISION_MULTIPLIER);
+               int total            = rint((this.m_healthdamage + this.m_armordamage)
+                                    / DAMAGETEXT_PRECISION_MULTIPLIER);
+               int potential        = rint(this.m_potential_damage
+                                    / DAMAGETEXT_PRECISION_MULTIPLIER);
+               int potential_health = rint((this.m_potential_damage - this.m_armordamage)
+                                    / DAMAGETEXT_PRECISION_MULTIPLIER);
+
+               bool redundant = almost_equals_eps(this.m_healthdamage + this.m_armordamage,
+                               this.m_potential_damage, 5);
+
+               string s = autocvar_cl_damagetext_format;
+               s = strreplace("{armor}", (
+                       (this.m_armordamage == 0 && autocvar_cl_damagetext_format_hide_redundant)
+                               ? ""
+                               : sprintf("%d", armor)
+                       ), s);
+               s = strreplace("{potential}", (
+                       (redundant && autocvar_cl_damagetext_format_hide_redundant)
+                               ? ""
+                               : sprintf("%d", potential)
+                       ), s);
+               s = strreplace("{potential_health}", (
+                       (redundant && autocvar_cl_damagetext_format_hide_redundant)
+                               ? ""
+                               : sprintf("%d", potential_health)
+                       ), s);
+
+               s = strreplace("{health}", (
+                       (health == potential_health || !autocvar_cl_damagetext_format_verbose)
+                               ? sprintf("%d",      health)
+                               : sprintf("%d (%d)", health, potential_health)
+                       ), s);
+               s = strreplace("{total}", (
+                       (total == potential || !autocvar_cl_damagetext_format_verbose)
+                               ? sprintf("%d",      total)
+                               : sprintf("%d (%d)", total, potential)
+                       ), s);
+
+               // futureproofing: remove any remaining (unknown) format strings
+               // in case we add new ones in the future so players can use them
+               // on new servers and still have working damagetext on old ones
+               while (true)
+               {
+                       int opening_pos = strstrofs(s, "{", 0);
+                       if (opening_pos == -1) break;
+                       int closing_pos = strstrofs(s, "}", opening_pos);
+                       if (closing_pos == -1 || closing_pos <= opening_pos) break;
+                       s = strcat(
+                               substring(s, 0, opening_pos),
+                               substring_range(s, closing_pos + 1, strlen(s))
+                       );
+               }
+
+               strcpy(this.text, s);
+
+               this.m_size = map_bound_ranges(potential,
+                       autocvar_cl_damagetext_size_min_damage, autocvar_cl_damagetext_size_max_damage,
+                       autocvar_cl_damagetext_size_min,        autocvar_cl_damagetext_size_max);
+       }
+
+       CONSTRUCTOR(DamageText, int _group, vector _origin, bool _screen_coords,
+               int _health, int _armor, int _potential_damage, int _deathtype, bool _friendlyfire)
+       {
+               CONSTRUCT(DamageText);
+               this.m_group = _group;
+               this.m_friendlyfire = _friendlyfire;
+               this.m_screen_coords = _screen_coords;
+               if (_screen_coords)
+               {
+                       if (autocvar_cl_damagetext_2d_alpha_lifetime)
+                               this.fade_rate = 1 / autocvar_cl_damagetext_2d_alpha_lifetime;
+                       if (autocvar_cl_damagetext_2d_size_lifetime)
+                               this.m_shrink_rate = 1 / autocvar_cl_damagetext_2d_size_lifetime;
+               }
+               else
+               {
+                       if (autocvar_cl_damagetext_alpha_lifetime)
+                               this.fade_rate = 1 / autocvar_cl_damagetext_alpha_lifetime;
+                       this.m_shrink_rate = 0;
+               }
+               DamageText_update(this, _origin, _screen_coords,
+                       _health, _armor, _potential_damage, _deathtype);
+               IL_PUSH(g_damagetext, this);
+       }
+
+       DESTRUCTOR(DamageText)
+       {
+               strfree(this.text);
+               --DamageText_screen_count;
+       }
 ENDCLASS(DamageText)
 
-float current_alpha(entity damage_text) {
-    // alpha doesn't change - actual alpha is always calculated from the initial value
-    return damage_text.alpha - (time - damage_text.hit_time) * damage_text.fade_rate;
+float current_alpha(entity damage_text)
+{
+       // alpha doesn't change - actual alpha is always calculated from the initial value
+       return damage_text.alpha - (time - damage_text.hit_time) * damage_text.fade_rate;
 }
 
 NET_HANDLE(damagetext, bool isNew)
 {
-    make_pure(this);
-    int server_entity_index = ReadByte();
-    int deathtype = ReadInt24_t();
-    int flags = ReadByte();
-    bool friendlyfire = flags & DTFLAG_SAMETEAM;
-
-    int health, armor, potential_damage;
-    if (flags & DTFLAG_BIG_HEALTH) health = ReadInt24_t();
-    else health = ReadShort();
-    if (flags & DTFLAG_NO_ARMOR) armor = 0;
-    else if (flags & DTFLAG_BIG_ARMOR) armor = ReadInt24_t();
-    else armor = ReadShort();
-    if (flags & DTFLAG_NO_POTENTIAL) potential_damage = health + armor;
-    else if (flags & DTFLAG_BIG_POTENTIAL) potential_damage = ReadInt24_t();
-    else potential_damage = ReadShort();
-
-    return = true;
-    if (!isNew) return;
-    if (autocvar_cl_damagetext == 0) return;
-    if (friendlyfire) {
-        if (autocvar_cl_damagetext_friendlyfire == 0) return;
-        if (autocvar_cl_damagetext_friendlyfire == 1 && health == 0 && armor == 0) return;
-    }
-
-    int client_entity_index = server_entity_index - 1;
-    entity entcs = entcs_receiver(client_entity_index);
-
-    bool can_use_3d = entcs && entcs.has_origin;
-    bool too_close = vdist(entcs.origin - view_origin, <, autocvar_cl_damagetext_2d_close_range);
-    bool prefer_in_view = autocvar_cl_damagetext_2d_out_of_view && !projected_on_screen(project_3d_to_2d(entcs.origin));
-    bool prefer_2d = spectatee_status != -1 && autocvar_cl_damagetext_2d && (too_close || prefer_in_view);
-
-    if (can_use_3d && !prefer_2d) {
-        // world coords
-        IL_EACH(g_damagetext, it.m_group == server_entity_index, {
-            if (current_alpha(it) > autocvar_cl_damagetext_accumulate_alpha_rel * autocvar_cl_damagetext_alpha_start) {
-                DamageText_update(it, entcs.origin, false, it.m_healthdamage + health, it.m_armordamage + armor, it.m_potential_damage + potential_damage, deathtype);
-                return;
-            }
-        });
-       ++DamageText_screen_count; //3D DamageTexts can later be changed into 2D, increment this just in case
-        NEW(DamageText, server_entity_index, entcs.origin, false, health, armor, potential_damage, deathtype, friendlyfire);
-    } else if (autocvar_cl_damagetext_2d && spectatee_status != -1) {
-        // screen coords only
-        vector screen_pos = vec2(vid_conwidth * autocvar_cl_damagetext_2d_pos.x, vid_conheight * autocvar_cl_damagetext_2d_pos.y);
-        IL_EACH(g_damagetext, it.m_group == server_entity_index, {
-            DamageText_update(it, screen_pos, true, it.m_healthdamage + health, it.m_armordamage + armor, it.m_potential_damage + potential_damage, deathtype);
-            return;
-        });
-
-        // offset when hitting multiple enemies, dmgtext would overlap
-        screen_pos += autocvar_cl_damagetext_2d_overlap_offset * DamageText_screen_count++;
-        NEW(DamageText, server_entity_index, screen_pos, true, health, armor, potential_damage, deathtype, friendlyfire);
-    }
+       make_pure(this);
+       int server_entity_index = ReadByte();
+       int deathtype = ReadInt24_t();
+       int flags = ReadByte();
+       bool friendlyfire = flags & DTFLAG_SAMETEAM;
+
+       int health, armor, potential_damage;
+       if (flags & DTFLAG_BIG_HEALTH) health = ReadInt24_t();
+       else health = ReadShort();
+       if (flags & DTFLAG_NO_ARMOR) armor = 0;
+       else if (flags & DTFLAG_BIG_ARMOR) armor = ReadInt24_t();
+       else armor = ReadShort();
+       if (flags & DTFLAG_NO_POTENTIAL) potential_damage = health + armor;
+       else if (flags & DTFLAG_BIG_POTENTIAL) potential_damage = ReadInt24_t();
+       else potential_damage = ReadShort();
+
+       return = true;
+       if (!isNew) return;
+       if (autocvar_cl_damagetext == 0) return;
+       if (friendlyfire)
+       {
+               if (autocvar_cl_damagetext_friendlyfire == 0)
+                       return;
+
+               if (autocvar_cl_damagetext_friendlyfire == 1
+               && health == 0 && armor == 0)
+                       return;
+       }
+
+       int client_entity_index = server_entity_index - 1;
+       entity entcs = entcs_receiver(client_entity_index);
+
+       bool can_use_3d = entcs && entcs.has_origin;
+       bool too_close = vdist(entcs.origin - view_origin, <, autocvar_cl_damagetext_2d_close_range);
+       bool prefer_in_view = autocvar_cl_damagetext_2d_out_of_view && !projected_on_screen(project_3d_to_2d(entcs.origin));
+       bool prefer_2d = spectatee_status != -1 && autocvar_cl_damagetext_2d && (too_close || prefer_in_view);
+
+       vector position;
+       bool is2d;
+       entity entDT = NULL; // which DT to update
+
+       float alphathreshold = autocvar_cl_damagetext_accumulate_alpha_rel
+                       * autocvar_cl_damagetext_alpha_start;
+
+       // check if this entity already has a DamageText for it
+       IL_EACH(g_damagetext, it.m_group == server_entity_index, {
+               // if the time window where damage accumulates closes,
+               // disown the parent entity from this DamageText
+               // and (likely) give the entity a new DT afterwards
+               // this should only cancel damage accumulation for this DT
+               if ((autocvar_cl_damagetext_accumulate_lifetime >= 0) // negative never disowns
+               && (time - it.hit_time > autocvar_cl_damagetext_accumulate_lifetime)
+               && (current_alpha(it) > alphathreshold))
+               {
+                       it.m_group = 0;
+               }
+               else
+               {
+                       health += it.m_healthdamage;
+                       armor += it.m_armordamage;
+                       potential_damage += it.m_potential_damage;
+
+                       entDT = it;
+               }
+               break;
+       });
+
+       if (can_use_3d && !prefer_2d)
+       {
+               // world coords
+               is2d = false;
+               position = entcs.origin;
+
+               if (entDT)
+                       goto updateDT;
+
+               // 3D DamageTexts can later be changed into 2D,
+               // increment this here just in case
+               ++DamageText_screen_count;
+               goto spawnnewDT;
+       }
+       else if (autocvar_cl_damagetext_2d && spectatee_status != -1)
+       {
+               // screen coords only
+               is2d = true;
+               position = vec2(vid_conwidth  * autocvar_cl_damagetext_2d_pos.x,
+                               vid_conheight * autocvar_cl_damagetext_2d_pos.y);
+
+               if (entDT)
+                       goto updateDT;
+
+               // offset when hitting multiple enemies, dmgtext would overlap
+               position += autocvar_cl_damagetext_2d_overlap_offset * DamageText_screen_count++;
+               goto spawnnewDT;
+       }
+       return;
+
+LABEL(updateDT)
+       DamageText_update(entDT, position, is2d, health, armor, potential_damage, deathtype);
+       return;
+
+LABEL(spawnnewDT)
+       NEW(DamageText, server_entity_index, position, is2d,
+               health, armor, potential_damage, deathtype, friendlyfire);
+       return;
 }
index e76b4119a73944005b78cb666d47f3189500b2b3..f845a97cd225fd3d2fd3a9f1f62fd650db117617 100644 (file)
@@ -29,3 +29,14 @@ float autocvar_cl_damagetext_2d_close_range;
 bool autocvar_cl_damagetext_2d_out_of_view;
 vector autocvar_cl_damagetext_velocity_screen;
 vector autocvar_cl_damagetext_offset_screen;
+
+// TODO: remove the value init and sort them above properly after next (0.9) release
+// or the release after it to support the old-stable release
+// this can't be done now as players would lack these from their configs then
+#if 0
+float autocvar_cl_damagetext_lifetime = -1;
+float autocvar_cl_damagetext_accumulate_lifetime = -1;
+#else
+AUTOCVAR_SAVE(cl_damagetext_lifetime,             float,  -1,  "Damage text lifetime, edit this if you wish for damage text to disappear before it fades out");
+AUTOCVAR_SAVE(cl_damagetext_accumulate_lifetime,  float,  -1,  "Only update existing damage text when it is younger than this many seconds, negative always updates");
+#endif
index 8bf9516809e474e62cddb99cf72cacf83807d28f..c244d170d259709ea485cc874e0a707e0c1294dc 100644 (file)
@@ -17,72 +17,72 @@ REGISTER_MUTATOR(damagetext, true);
 
 bool write_damagetext(entity this, entity client, int sf)
 {
-    entity attacker = this.realowner;
-    entity hit = this.enemy;
-    int flags = this.dent_net_flags;
-    int deathtype = this.dent_net_deathtype;
-    float health = this.dent_net_health;
-    float armor = this.dent_net_armor;
-    float potential_damage = this.dent_net_potential;
-    if (!(
-        (SV_DAMAGETEXT_ALL()) ||
-        (SV_DAMAGETEXT_PLAYERS() && client == attacker) ||
-        (SV_DAMAGETEXT_SPECTATORS_ONLY() && IS_SPEC(client) && client.enemy == attacker) ||
-        (SV_DAMAGETEXT_SPECTATORS_ONLY() && IS_OBSERVER(client))
-    )) return false;
+       entity attacker = this.realowner;
+       entity hit = this.enemy;
+       int flags = this.dent_net_flags;
+       int deathtype = this.dent_net_deathtype;
+       float health = this.dent_net_health;
+       float armor = this.dent_net_armor;
+       float potential_damage = this.dent_net_potential;
+       if (!(
+               (SV_DAMAGETEXT_ALL()) ||
+               (SV_DAMAGETEXT_PLAYERS() && client == attacker) ||
+               (SV_DAMAGETEXT_SPECTATORS_ONLY() && IS_SPEC(client) && client.enemy == attacker) ||
+               (SV_DAMAGETEXT_SPECTATORS_ONLY() && IS_OBSERVER(client))
+       )) return false;
 
-    WriteHeader(MSG_ENTITY, damagetext);
-    WriteByte(MSG_ENTITY, etof(hit));
-    WriteInt24_t(MSG_ENTITY, deathtype);
-    WriteByte(MSG_ENTITY, flags);
+       WriteHeader(MSG_ENTITY, damagetext);
+       WriteByte(MSG_ENTITY, etof(hit));
+       WriteInt24_t(MSG_ENTITY, deathtype);
+       WriteByte(MSG_ENTITY, flags);
 
-    // we need to send a few decimal places to minimize errors when accumulating damage
-    // sending them multiplied saves bandwidth compared to using WriteCoord,
-    // however if the multiplied damage would be too much for (signed) short, we send an int24
-    if (flags & DTFLAG_BIG_HEALTH) WriteInt24_t(MSG_ENTITY, health * DAMAGETEXT_PRECISION_MULTIPLIER);
-    else WriteShort(MSG_ENTITY, health * DAMAGETEXT_PRECISION_MULTIPLIER);
-    if (!(flags & DTFLAG_NO_ARMOR))
-    {
-        if (flags & DTFLAG_BIG_ARMOR) WriteInt24_t(MSG_ENTITY, armor * DAMAGETEXT_PRECISION_MULTIPLIER);
-        else WriteShort(MSG_ENTITY, armor * DAMAGETEXT_PRECISION_MULTIPLIER);
-    }
-    if (!(flags & DTFLAG_NO_POTENTIAL))
-    {
-        if (flags & DTFLAG_BIG_POTENTIAL) WriteInt24_t(MSG_ENTITY, potential_damage * DAMAGETEXT_PRECISION_MULTIPLIER);
-        else WriteShort(MSG_ENTITY, potential_damage * DAMAGETEXT_PRECISION_MULTIPLIER);
-    }
-    return true;
+       // we need to send a few decimal places to minimize errors when accumulating damage
+       // sending them multiplied saves bandwidth compared to using WriteCoord,
+       // however if the multiplied damage would be too much for (signed) short, we send an int24
+       if (flags & DTFLAG_BIG_HEALTH) WriteInt24_t(MSG_ENTITY, health * DAMAGETEXT_PRECISION_MULTIPLIER);
+       else WriteShort(MSG_ENTITY, health * DAMAGETEXT_PRECISION_MULTIPLIER);
+       if (!(flags & DTFLAG_NO_ARMOR))
+       {
+               if (flags & DTFLAG_BIG_ARMOR) WriteInt24_t(MSG_ENTITY, armor * DAMAGETEXT_PRECISION_MULTIPLIER);
+               else WriteShort(MSG_ENTITY, armor * DAMAGETEXT_PRECISION_MULTIPLIER);
+       }
+       if (!(flags & DTFLAG_NO_POTENTIAL))
+       {
+               if (flags & DTFLAG_BIG_POTENTIAL) WriteInt24_t(MSG_ENTITY, potential_damage * DAMAGETEXT_PRECISION_MULTIPLIER);
+               else WriteShort(MSG_ENTITY, potential_damage * DAMAGETEXT_PRECISION_MULTIPLIER);
+       }
+       return true;
 }
 
 MUTATOR_HOOKFUNCTION(damagetext, PlayerDamaged) {
-    if (SV_DAMAGETEXT_DISABLED()) return;
-    entity attacker = M_ARGV(0, entity);
-    entity hit = M_ARGV(1, entity); if (hit == attacker) return;
-    float health = M_ARGV(2, float);
-    float armor = M_ARGV(3, float);
-    int deathtype = M_ARGV(5, int);
-    float potential_damage = M_ARGV(6, float);
-    if(DEATH_WEAPONOF(deathtype) == WEP_VAPORIZER) return;
+       if (SV_DAMAGETEXT_DISABLED()) return;
+       entity attacker = M_ARGV(0, entity);
+       entity hit = M_ARGV(1, entity); if (hit == attacker) return;
+       float health = M_ARGV(2, float);
+       float armor = M_ARGV(3, float);
+       int deathtype = M_ARGV(5, int);
+       float potential_damage = M_ARGV(6, float);
+       if(DEATH_WEAPONOF(deathtype) == WEP_VAPORIZER) return;
 
-    int flags = 0;
-    if (SAME_TEAM(hit, attacker)) flags |= DTFLAG_SAMETEAM;
-    if (health >= DAMAGETEXT_SHORT_LIMIT) flags |= DTFLAG_BIG_HEALTH;
-    if (armor >= DAMAGETEXT_SHORT_LIMIT) flags |= DTFLAG_BIG_ARMOR;
-    if (potential_damage >= DAMAGETEXT_SHORT_LIMIT) flags |= DTFLAG_BIG_POTENTIAL;
-    if (!armor) flags |= DTFLAG_NO_ARMOR;
-    if (almost_equals_eps(armor + health, potential_damage, 5)) flags |= DTFLAG_NO_POTENTIAL;
+       int flags = 0;
+       if (SAME_TEAM(hit, attacker)) flags |= DTFLAG_SAMETEAM;
+       if (health >= DAMAGETEXT_SHORT_LIMIT) flags |= DTFLAG_BIG_HEALTH;
+       if (armor >= DAMAGETEXT_SHORT_LIMIT) flags |= DTFLAG_BIG_ARMOR;
+       if (potential_damage >= DAMAGETEXT_SHORT_LIMIT) flags |= DTFLAG_BIG_POTENTIAL;
+       if (!armor) flags |= DTFLAG_NO_ARMOR;
+       if (almost_equals_eps(armor + health, potential_damage, 5)) flags |= DTFLAG_NO_POTENTIAL;
 
-    entity net_text = new_pure(net_damagetext);
-    net_text.realowner = attacker;
-    net_text.enemy = hit;
-    net_text.dent_net_flags = flags;
-    net_text.dent_net_deathtype = deathtype;
-    net_text.dent_net_health = health;
-    net_text.dent_net_armor = armor;
-    net_text.dent_net_potential = potential_damage;
+       entity net_text = new_pure(net_damagetext);
+       net_text.realowner = attacker;
+       net_text.enemy = hit;
+       net_text.dent_net_flags = flags;
+       net_text.dent_net_deathtype = deathtype;
+       net_text.dent_net_health = health;
+       net_text.dent_net_armor = armor;
+       net_text.dent_net_potential = potential_damage;
 
-    setthink(net_text, SUB_Remove);
-    net_text.nextthink = (time > 10) ? (time + 0.5) : 10; // allow a buffer from start time for clients to load in
+       setthink(net_text, SUB_Remove);
+       net_text.nextthink = (time > 10) ? (time + 0.5) : 10; // allow a buffer from start time for clients to load in
 
-    Net_LinkEntity(net_text, false, 0, write_damagetext);
+       Net_LinkEntity(net_text, false, 0, write_damagetext);
 }
index cf83e41c03fe17fa4a5f6ec8db40b3de2aa93a70..391d9acbbab15defbdef1828f81c7685b6dee780 100644 (file)
@@ -80,10 +80,10 @@ METHOD(OverkillHeavyMachineGun, wr_think, void(entity thiswep, entity actor, .en
                        animdecide_setaction(actor, ANIMACTION_SHOOT, true);
                }
        }
-    if (WEP_CVAR(okhmg, reload_ammo) && actor.(weaponentity).clip_load < WEP_CVAR_PRI(okhmg, ammo))
+       if (WEP_CVAR(okhmg, reload_ammo) && actor.(weaponentity).clip_load < WEP_CVAR_PRI(okhmg, ammo))
        {
                // Forced reload.
-        thiswep.wr_reload(thiswep, actor, weaponentity);
+               thiswep.wr_reload(thiswep, actor, weaponentity);
                return;
        }
        if (fire & 1) // Primary attack
@@ -130,20 +130,20 @@ METHOD(OverkillHeavyMachineGun, wr_checkammo2, bool(entity thiswep, entity actor
 
 METHOD(OverkillHeavyMachineGun, wr_reload, void(entity thiswep, entity actor, .entity weaponentity))
 {
-    W_Reload(actor, weaponentity, WEP_CVAR_PRI(okhmg, ammo), SND_RELOAD);
+       W_Reload(actor, weaponentity, WEP_CVAR_PRI(okhmg, ammo), SND_RELOAD);
 }
 
 METHOD(OverkillHeavyMachineGun, wr_suicidemessage, Notification(entity thiswep))
 {
-    return WEAPON_THINKING_WITH_PORTALS;
+       return WEAPON_THINKING_WITH_PORTALS;
 }
 
 METHOD(OverkillHeavyMachineGun, wr_killmessage, Notification(entity thiswep))
 {
-    if(w_deathtype & HITTYPE_SECONDARY)
-        return WEAPON_OVERKILL_HMG_MURDER_SNIPE;
-    else
-        return WEAPON_OVERKILL_HMG_MURDER_SPRAY;
+       if(w_deathtype & HITTYPE_SECONDARY)
+               return WEAPON_OVERKILL_HMG_MURDER_SNIPE;
+       else
+               return WEAPON_OVERKILL_HMG_MURDER_SPRAY;
 }
 
 #endif
@@ -151,10 +151,10 @@ METHOD(OverkillHeavyMachineGun, wr_killmessage, Notification(entity thiswep))
 
 METHOD(OverkillHeavyMachineGun, wr_impacteffect, void(entity thiswep, entity actor))
 {
-    vector org2 = w_org + w_backoff * 2;
-    pointparticles(EFFECT_MACHINEGUN_IMPACT, org2, w_backoff * 1000, 1);
-    if(!w_issilent)
-        sound(actor, CH_SHOTS, SND_RIC_RANDOM(), VOL_BASE, ATTEN_NORM);
+       vector org2 = w_org + w_backoff * 2;
+       pointparticles(EFFECT_MACHINEGUN_IMPACT, org2, w_backoff * 1000, 1);
+       if(!w_issilent)
+               sound(actor, CH_SHOTS, SND_RIC_RANDOM(), VOL_BASE, ATTEN_NORM);
 }
 
 #endif
index 55fea8ca754e4570ab99293d8d86476296e07fb6..c4e140234c482fc31e09012069b69d8608206570 100644 (file)
@@ -54,8 +54,8 @@ CLASS(OverkillHeavyMachineGun, Weapon)
                P(class, prefix, weaponstartoverride, float, NONE) \
                P(class, prefix, weaponstart, float, NONE) \
                P(class, prefix, weaponthrowable, float, NONE) \
-    END()
-    W_PROPS(X, OverkillHeavyMachineGun, okhmg)
+       END()
+       W_PROPS(X, OverkillHeavyMachineGun, okhmg)
 #undef X
 
 ENDCLASS(OverkillHeavyMachineGun)
index 7cf072b33a5c5bf41e92baa3f3b41c2e982580b5..5ec40b7f73b14f79803dc61dc8258813a2655b6d 100644 (file)
@@ -4,18 +4,18 @@ CLASS(OverkillMachineGun, Weapon)
 /* spawnfunc */ ATTRIB(OverkillMachineGun, m_canonical_spawnfunc, string, "weapon_okmachinegun");
 /* ammotype  */ ATTRIB(OverkillMachineGun, ammo_type, Resource, RES_BULLETS);
 /* impulse   */ ATTRIB(OverkillMachineGun, impulse, int, 3);
-/* flags        */ ATTRIB(OverkillMachineGun, spawnflags, int, WEP_FLAG_HIDDEN | WEP_FLAG_RELOADABLE | WEP_TYPE_HITSCAN | WEP_FLAG_PENETRATEWALLS | WEP_FLAG_MUTATORBLOCKED);
-/* rating      */ ATTRIB(OverkillMachineGun, bot_pickupbasevalue, float, 7000);
-/* color        */ ATTRIB(OverkillMachineGun, wpcolor, vector, '1 1 0');
+/* flags     */ ATTRIB(OverkillMachineGun, spawnflags, int, WEP_FLAG_HIDDEN | WEP_FLAG_RELOADABLE | WEP_TYPE_HITSCAN | WEP_FLAG_PENETRATEWALLS | WEP_FLAG_MUTATORBLOCKED);
+/* rating    */ ATTRIB(OverkillMachineGun, bot_pickupbasevalue, float, 7000);
+/* color     */ ATTRIB(OverkillMachineGun, wpcolor, vector, '1 1 0');
 /* modelname */ ATTRIB(OverkillMachineGun, mdl, string, "ok_mg");
 #ifdef GAMEQC
-/* model        */ ATTRIB(OverkillMachineGun, m_model, Model, MDL_OK_MG_ITEM);
+/* model     */ ATTRIB(OverkillMachineGun, m_model, Model, MDL_OK_MG_ITEM);
 /* flash mdl */ ATTRIB(OverkillMachineGun, m_muzzlemodel, Model, MDL_MACHINEGUN_MUZZLEFLASH);
 /* flash eff */ ATTRIB(OverkillMachineGun, m_muzzleeffect, entity, EFFECT_MACHINEGUN_MUZZLEFLASH);
 #endif
 /* crosshair */ ATTRIB(OverkillMachineGun, w_crosshair, string, "gfx/crosshairuzi");
 /* crosshair */ ATTRIB(OverkillMachineGun, w_crosshair_size, float, 0.6);
-/* wepimg      */ ATTRIB(OverkillMachineGun, model2, string, "ok_weapon_smg");
+/* wepimg    */ ATTRIB(OverkillMachineGun, model2, string, "ok_weapon_smg");
 /* refname   */ ATTRIB(OverkillMachineGun, netname, string, "okmachinegun");
 /* wepname   */ ATTRIB(OverkillMachineGun, m_name, string, _("Overkill MachineGun"));
 
index d84a6766a3bbafe5fe27fab2ecafbbdf4e433818..a1f9d5db63b38d68a0b239a13612f8738042f9aa 100644 (file)
@@ -130,7 +130,7 @@ void W_OverkillRocketPropelledChainsaw_Attack(Weapon thiswep, entity actor, .ent
 
 METHOD(OverkillRocketPropelledChainsaw, wr_aim, void(entity thiswep, entity actor, .entity weaponentity))
 {
-    PHYS_INPUT_BUTTON_ATCK(actor) = bot_aim(actor, weaponentity, WEP_CVAR_PRI(okrpc, speed), 0, WEP_CVAR_PRI(okrpc, lifetime), false, true);
+       PHYS_INPUT_BUTTON_ATCK(actor) = bot_aim(actor, weaponentity, WEP_CVAR_PRI(okrpc, speed), 0, WEP_CVAR_PRI(okrpc, lifetime), false, true);
 }
 
 METHOD(OverkillRocketPropelledChainsaw, wr_think, void(entity thiswep, entity actor, .entity weaponentity, int fire))
@@ -199,25 +199,25 @@ METHOD(OverkillRocketPropelledChainsaw, wr_checkammo2, bool(entity thiswep, enti
 
 METHOD(OverkillRocketPropelledChainsaw, wr_reload, void(entity thiswep, entity actor, .entity weaponentity))
 {
-    W_Reload(actor, weaponentity, WEP_CVAR_PRI(okrpc, ammo), SND_RELOAD);
+       W_Reload(actor, weaponentity, WEP_CVAR_PRI(okrpc, ammo), SND_RELOAD);
 }
 
 METHOD(OverkillRocketPropelledChainsaw, wr_suicidemessage, Notification(entity thiswep))
 {
-    if((w_deathtype & HITTYPE_BOUNCE) || (w_deathtype & HITTYPE_SPLASH))
-        return WEAPON_OVERKILL_RPC_SUICIDE_SPLASH;
-    else
-        return WEAPON_OVERKILL_RPC_SUICIDE_DIRECT;
+       if((w_deathtype & HITTYPE_BOUNCE) || (w_deathtype & HITTYPE_SPLASH))
+               return WEAPON_OVERKILL_RPC_SUICIDE_SPLASH;
+       else
+               return WEAPON_OVERKILL_RPC_SUICIDE_DIRECT;
 }
 
 METHOD(OverkillRocketPropelledChainsaw, wr_killmessage, Notification(entity thiswep))
 {
-    if(w_deathtype & HITTYPE_SECONDARY)
-        return WEAPON_BLASTER_MURDER;
-    else if((w_deathtype & HITTYPE_BOUNCE) || (w_deathtype & HITTYPE_SPLASH))
-        return WEAPON_OVERKILL_RPC_MURDER_SPLASH;
-    else
-        return WEAPON_OVERKILL_RPC_MURDER_DIRECT;
+       if(w_deathtype & HITTYPE_SECONDARY)
+               return WEAPON_BLASTER_MURDER;
+       else if((w_deathtype & HITTYPE_BOUNCE) || (w_deathtype & HITTYPE_SPLASH))
+               return WEAPON_OVERKILL_RPC_MURDER_SPLASH;
+       else
+               return WEAPON_OVERKILL_RPC_MURDER_DIRECT;
 }
 
 #endif
@@ -226,10 +226,10 @@ METHOD(OverkillRocketPropelledChainsaw, wr_killmessage, Notification(entity this
 
 METHOD(OverkillRocketPropelledChainsaw, wr_impacteffect, void(entity thiswep, entity actor))
 {
-    vector org2 = w_org + w_backoff * 2;
-    pointparticles(EFFECT_ROCKET_EXPLODE, org2, '0 0 0', 1);
-    if(!w_issilent)
-        sound(actor, CH_SHOTS, SND_ROCKET_IMPACT, VOL_BASE, ATTEN_NORM);
+       vector org2 = w_org + w_backoff * 2;
+       pointparticles(EFFECT_ROCKET_EXPLODE, org2, '0 0 0', 1);
+       if(!w_issilent)
+               sound(actor, CH_SHOTS, SND_ROCKET_IMPACT, VOL_BASE, ATTEN_NORM);
 }
 
 #endif
index 23421d2f542dfd4f467994ec04d34ab605c2b89e..28b76348840e84512f75083eb341a5e328ad3b0c 100644 (file)
@@ -52,15 +52,15 @@ CLASS(OverkillRocketPropelledChainsaw, Weapon)
                P(class, prefix, speed, float, SEC) \
                P(class, prefix, spread, float, SEC) \
                P(class, prefix, reload_ammo, float, NONE) \
-        P(class, prefix, reload_time, float, NONE) \
-        P(class, prefix, switchdelay_drop, float, NONE) \
-        P(class, prefix, switchdelay_raise, float, NONE) \
-        P(class, prefix, weaponreplace, string, NONE) \
-        P(class, prefix, weaponstartoverride, float, NONE) \
-        P(class, prefix, weaponstart, float, NONE) \
-        P(class, prefix, weaponthrowable, float, NONE) \
-    END()
-    W_PROPS(X, OverkillRocketPropelledChainsaw, okrpc)
+               P(class, prefix, reload_time, float, NONE) \
+               P(class, prefix, switchdelay_drop, float, NONE) \
+               P(class, prefix, switchdelay_raise, float, NONE) \
+               P(class, prefix, weaponreplace, string, NONE) \
+               P(class, prefix, weaponstartoverride, float, NONE) \
+               P(class, prefix, weaponstart, float, NONE) \
+               P(class, prefix, weaponthrowable, float, NONE) \
+       END()
+       W_PROPS(X, OverkillRocketPropelledChainsaw, okrpc)
 #undef X
 
 ENDCLASS(OverkillRocketPropelledChainsaw)
index bf8d8fb10a903820e9ad9e546c444c05b9274c19..690abb5ca2fe207b7fb41bd7c6ac7af82bcc7786 100644 (file)
@@ -51,6 +51,7 @@ REGISTER_ITEM(Invisibility, Powerup) {
 }
 
 SPAWNFUNC_ITEM(item_invisibility, ITEM_Invisibility)
+SPAWNFUNC_ITEM(item_buff_invisibility, ITEM_Invisibility)
 
 CLASS(Invisibility, Powerups)
     ATTRIB(Invisibility, netname, string, "invisibility");
index c816fec53a7ffc8f3fc6d48c2dad5bbe853c1f11..38010e480b1c723b5d0449ef0616ad0629cd3c4b 100644 (file)
@@ -52,6 +52,7 @@ REGISTER_ITEM(Speed, Powerup) {
 }
 
 SPAWNFUNC_ITEM(item_speed, ITEM_Speed)
+SPAWNFUNC_ITEM(item_buff_speed, ITEM_Speed)
 
 CLASS(Speed, Powerups)
     ATTRIB(Speed, netname, string, "speed");
index 00bd94bb740066bc03810210ece3d6238d895da8..f4c25968cc2bf3154b7bd2643c4403ad946b0055 100644 (file)
@@ -714,7 +714,7 @@ string notif_arg_item_wepammo(float f1, float f2)
 
 REGISTRY(Notifications, BITS(11))
 REGISTER_REGISTRY(Notifications)
-REGISTRY_SORT(Notifications);
+REGISTRY_SORT(Notifications)
 
 REGISTRY_DEFINE_GET(Notifications, NULL)
 STATIC_INIT(Notifications) { FOREACH(Notifications, true, it.m_id = i); }
index 17c76461fd3516a72b5355a39f906846cfe9f205..548246f5fc45a75b82af918a1f9bd9aa70f2b145 100644 (file)
@@ -258,22 +258,21 @@ void PlayerStats_GameReport(bool finished)
                PlayerStats_GameReport_FinalizePlayer(it);
        });
 
-       if(autocvar_g_playerstats_gamereport_uri != "")
-       {
-               PlayerStats_GameReport_DelayMapVote = true;
-               url_multi_fopen(
-                       autocvar_g_playerstats_gamereport_uri,
-                       FILE_APPEND,
-                       PlayerStats_GameReport_Handler,
-                       NULL
-               );
-       }
-       else
+       if(autocvar_g_playerstats_gamereport_uri == "" || warmup_stage)
        {
                PlayerStats_GameReport_DelayMapVote = false;
                db_close(PS_GR_OUT_DB);
                PS_GR_OUT_DB = -1;
+               return;
        }
+
+       PlayerStats_GameReport_DelayMapVote = true;
+       url_multi_fopen(
+               autocvar_g_playerstats_gamereport_uri,
+               FILE_APPEND,
+               PlayerStats_GameReport_Handler,
+               NULL
+       );
 }
 
 void PlayerStats_GameReport_Init() // initiated before InitGameplayMode so that scores are added properly
@@ -369,6 +368,7 @@ void PlayerStats_GameReport_Handler(entity fh, entity pass, float status)
                 * C: number of "unpure" cvar changes
                 * U: UDP port number of the server
                 * D: duration of the match
+                * RP: number of rounds played
                 * L: "ladder" in which the server is participating in
                 * P: player ID of an existing player; this also sets the owner for all following "n", "e" and "t" lines (lower case!)
                 * Q: team number of an existing team (format: team#NN); this also sets the owner for all following "e" lines (lower case!)
@@ -409,7 +409,10 @@ void PlayerStats_GameReport_Handler(entity fh, entity pass, float status)
                        url_fputs(fh, sprintf("C %d\n", cvar_purechanges_count));
                        url_fputs(fh, sprintf("U %d\n", cvar("port")));
                        url_fputs(fh, sprintf("D %f\n", max(0, time - game_starttime)));
-                       url_fputs(fh, sprintf("L %s\n", autocvar_g_playerstats_gamereport_ladder));
+                       if (rounds_played > 0)
+                               url_fputs(fh, sprintf("RP %d\n", rounds_played));
+                       if (autocvar_g_playerstats_gamereport_ladder != "")
+                               url_fputs(fh, sprintf("L %s\n", autocvar_g_playerstats_gamereport_ladder));
 
                        // TEAMS
                        if(teamplay)
index fa7ce8b73bf448e928a254fb1f62e687d581e0fc..28ad1f82adb628e128887661a1ddf191f346a034 100644 (file)
@@ -49,8 +49,8 @@ STATIC_INIT(default_order_resources)
 }
 #endif
 
-REGISTRY_SORT(Resources);
-REGISTRY_CHECK(Resources);
+REGISTRY_SORT(Resources)
+REGISTRY_CHECK(Resources)
 
 REGISTRY_DEFINE_GET(Resources, NULL)
 STATIC_INIT(Resources_renumber) { FOREACH(Resources, true, it.m_id = i); }
index 8a01893f1019c423927029d57b004baa8f66b88c..8f22b5c7525bcea5c80f01d594c9fc38a11660a7 100644 (file)
@@ -3,11 +3,11 @@
 #define MAX_SCORE 64
 
 #define REGISTER_SP(id) REGISTER(Scores, SP, id, m_id, new_pure(PlayerScoreField))
-REGISTRY(Scores, MAX_SCORE);
+REGISTRY(Scores, MAX_SCORE)
 REGISTER_REGISTRY(Scores)
 // do not sort alphabetically, player sort priority is based on score registration order
-//REGISTRY_SORT(Scores);
-REGISTRY_CHECK(Scores);
+//REGISTRY_SORT(Scores)
+REGISTRY_CHECK(Scores)
 
 REGISTRY_DEFINE_GET(Scores, NULL)
 STATIC_INIT(Scores_renumber) { FOREACH(Scores, true, it.m_id = i); }
index b7be1425c02c535c3354e91a9edc9af2613c8177..9b4394e45a62f1d0a2851555945521740c7c8e71 100644 (file)
@@ -343,8 +343,10 @@ REGISTER_STAT(NB_METERSTART, float)
 
 #ifdef SVQC
 float autocvar_g_teleport_maxspeed;
+float autocvar_g_teleport_minspeed;
 #endif
 REGISTER_STAT(TELEPORT_MAXSPEED, float, autocvar_g_teleport_maxspeed)
+REGISTER_STAT(TELEPORT_MINSPEED, float, autocvar_g_teleport_minspeed)
 REGISTER_STAT(TELEPORT_TELEFRAG_AVOID, int, autocvar_g_telefrags_avoid)
 
 REGISTER_STAT(CAMERA_SPECTATOR, int)
index fdcc730a068527b73b4a1e2291fc910616e9b53f..a610df2044d6745b7ffde1dc6412ce7516cd18b5 100644 (file)
@@ -177,13 +177,30 @@ void Registry_send(string id, string hash);
        STATIC_INIT(Registry_check_##id) \
        { \
                /* Note: SHA256 isn't always available, use MD4 instead */ \
-               string s = ""; \
-               FOREACH(id, true, s = strcat(s, ":", it.registered_id)); \
+               string s = "", group = ""; \
+               int str_len = 0, digests_len = 0, group_idx = 0; \
+               FOREACH(id, true, { \
+                       group = strcat(group, ":", it.registered_id); \
+                       if (++group_idx < 50) /* this is to reduce strlen calls */ \
+                               continue; \
+                       int group_len = strlen(group); \
+                       if (str_len + 1 + group_len >= VM_TEMPSTRING_MAXSIZE) \
+                       { \
+                               /* keep previous digests and replace current string with its digest */ \
+                               s = strcat(substring(s, 0, digests_len), ":", digest_hex("MD4", s)); \
+                               digests_len = str_len = strlen(s); \
+                       } \
+                       s = strcat(s, group); \
+                       str_len += group_len; \
+                       group = ""; \
+                       group_idx = 0; \
+               }); \
+               s = strcat(s, group); \
                s = substring(s, 1, -1); /* remove initial ":" */ \
                string h = REGISTRY_HASH(id) = strzone(digest_hex("MD4", s)); \
                LOG_DEBUGF(#id ": %s\n[%s]", h, s); \
        } \
-       void Registry_check(string r, string sv) \
+       void Registry_check(string r, string sv) /* called by CSQC */ \
        { \
                if (r == #id) \
                { \
@@ -194,7 +211,7 @@ void Registry_send(string id, string hash);
                        } \
                } \
        } \
-       void Registry_send_all() { Registry_send(#id, REGISTRY_HASH(id)); } \
+       void Registry_send_all() { Registry_send(#id, REGISTRY_HASH(id)); } /* called by SVQC */ \
 
 #define _REGISTER_REGISTRY(id, str) \
        ACCUMULATE_FUNCTION(__static_init_1, Register##id) \
index 3c39b7c0bb8e93a0f94ec95cbd081a41e44ba3e2..72673b2354517e28c5abd96c1cc1eb8f160b5b70 100644 (file)
@@ -4,6 +4,9 @@
 #include "sort.qh"
 #include "oo.qh"
 
+// this is not exactly 16KiB (16384 bytes) because one byte is reserved for the \0 terminator
+#define VM_TEMPSTRING_MAXSIZE 16383
+
 // string logic
 //
 // true: is truthy
index 1edc5b8400c8cc6347f5916125ebc34c850e5e0d..65373f1b10e277b5ba8b5307886c064117cf37be 100644 (file)
@@ -18,34 +18,31 @@ entity makeXonoticPlayerList()
 
 void XonoticPlayerList_setPlayerList(entity me, string plist)
 {
-       int buf,i,n;
-       string s;
+       int i;
+       int buf = buf_create();
 
-       buf = buf_create();
        me.nItems = tokenizebyseparator(plist, "\n");
        for(i = 0; i < me.nItems; ++i)
        {
-               bufstr_set(buf, i * PLAYERPARM_COUNT + PLAYERPARM_NAME, argv(i)); // -666 100 "^4Nex ^2Player"
+               bufstr_set(buf, i * PLAYERPARM_COUNT + PLAYERPARM_NAME, argv(i)); // -666 100 "^4Xon ^2Player"
        }
 
        for(i = 0; i < me.nItems; ++i)
        {
-               s = bufstr_get(buf, i * PLAYERPARM_COUNT + PLAYERPARM_NAME);
-               n = tokenize_console(s);
+               string name = bufstr_get(buf, i * PLAYERPARM_COUNT + PLAYERPARM_NAME);
+               int n = tokenize_console(name);
 
+               bufstr_set(buf, i * PLAYERPARM_COUNT + PLAYERPARM_SCORE, argv(0)); // -666
+               bufstr_set(buf, i * PLAYERPARM_COUNT + PLAYERPARM_PING,  argv(1)); // 100
                if(n == PLAYERPARM_COUNT)
                {
-                       bufstr_set(buf, i * PLAYERPARM_COUNT + PLAYERPARM_SCORE, argv(0)); // -666
-                       bufstr_set(buf, i * PLAYERPARM_COUNT + PLAYERPARM_PING,  argv(1)); // 100
                        bufstr_set(buf, i * PLAYERPARM_COUNT + PLAYERPARM_TEAM,  argv(2)); // 0 for spec, else 1, 2, 3, 4
-                       bufstr_set(buf, i * PLAYERPARM_COUNT + PLAYERPARM_NAME,  argv(3)); // ^4Nex ^2Player
+                       bufstr_set(buf, i * PLAYERPARM_COUNT + PLAYERPARM_NAME,  argv(3)); // ^4Xon ^2Player
                }
                else
                {
-                       bufstr_set(buf, i * PLAYERPARM_COUNT + PLAYERPARM_SCORE, argv(0)); // -666
-                       bufstr_set(buf, i * PLAYERPARM_COUNT + PLAYERPARM_PING,  argv(1)); // 100
                        bufstr_set(buf, i * PLAYERPARM_COUNT + PLAYERPARM_TEAM,  "-1");
-                       bufstr_set(buf, i * PLAYERPARM_COUNT + PLAYERPARM_NAME,  argv(2)); // ^4Nex ^2Player
+                       bufstr_set(buf, i * PLAYERPARM_COUNT + PLAYERPARM_NAME,  argv(2)); // ^4Xon ^2Player
                }
        }
        me.playerList = buf;
@@ -77,12 +74,9 @@ void XonoticPlayerList_resizeNotify(entity me, vector relOrigin, vector relSize,
 
 void XonoticPlayerList_drawListBoxItem(entity me, int i, vector absSize, bool isSelected, bool isFocused)
 {
-       string s;
-       string score;
-       float t;
-       vector rgb;
+       float t = stof(me.getPlayerList(me, i, PLAYERPARM_TEAM));
 
-       t = stof(me.getPlayerList(me, i, PLAYERPARM_TEAM));
+       vector rgb = SKINCOLOR_TEXT;
        if(t == 1)
                rgb = colormapPaletteColor(4, 0);
        else if(t == 2)
@@ -91,11 +85,9 @@ void XonoticPlayerList_drawListBoxItem(entity me, int i, vector absSize, bool is
                rgb = colormapPaletteColor(12, 0);
        else if(t == 4)
                rgb = colormapPaletteColor(9, 0);
-       else
-               rgb = SKINCOLOR_TEXT;
 
-       s = me.getPlayerList(me, i, PLAYERPARM_NAME);
-       score = me.getPlayerList(me, i, PLAYERPARM_SCORE);
+       string name = me.getPlayerList(me, i, PLAYERPARM_NAME);
+       string score = me.getPlayerList(me, i, PLAYERPARM_SCORE);
 
        if(substring(score, strlen(score) - 10, 10) == ":spectator")
        {
@@ -112,9 +104,10 @@ void XonoticPlayerList_drawListBoxItem(entity me, int i, vector absSize, bool is
                        score = _("spectator");
        }
 
-       s = draw_TextShortenToWidth(s, me.columnNameSize, 1, me.realFontSize);
-       draw_Text(me.realUpperMargin2 * eY + (me.columnNameOrigin + 0.00 * (me.columnNameSize - draw_TextWidth(s, 1, me.realFontSize))) * eX, s, me.realFontSize, '1 1 1', 1, 1);
+       name = draw_TextShortenToWidth(name, me.columnNameSize, 1, me.realFontSize);
+       draw_Text(me.realUpperMargin2 * eY + me.columnNameOrigin * eX, name, me.realFontSize, '1 1 1', 1, 1);
 
        score = draw_TextShortenToWidth(score, me.columnScoreSize, 0, me.realFontSize);
-       draw_Text(me.realUpperMargin2 * eY + (me.columnScoreOrigin + 1.00 * (me.columnScoreSize - draw_TextWidth(score, 1, me.realFontSize))) * eX, score, me.realFontSize, rgb, 1, 0);
+       float score_ofs = me.columnScoreSize - draw_TextWidth(score, 1, me.realFontSize);
+       draw_Text(me.realUpperMargin2 * eY + (me.columnScoreOrigin + score_ofs) * eX, score, me.realFontSize, rgb, 1, 0);
 }
index f05edfcb5a670225986eb18ae6f679645d540c9b..3fdb1f968c5b75b96363643c1286837850d67ab4 100644 (file)
@@ -21,6 +21,7 @@
 #include <server/command/radarmap.qh>
 #include <server/intermission.qh>
 #include <server/ipban.qh>
+#include <server/mapvoting.qh>
 #include <server/mutators/_mod.qh>
 #include <server/player.qh>
 #include <server/scores_rules.qh>
@@ -774,30 +775,12 @@ void GameCommand_gametype(int request, int argc)
                        if (argv(1) != "")
                        {
                                string s = argv(1);
-                               Gametype t = MapInfo_Type_FromString(s, false, false), tsave = MapInfo_CurrentGametype();
+                               Gametype t = MapInfo_Type_FromString(s, false, false);
 
                                if (t)
-                               {
-                                       MapInfo_SwitchGameType(t);
-                                       MapInfo_FilterGametype(MapInfo_CurrentGametype(), MapInfo_CurrentFeatures(), MapInfo_RequiredFlags(), MapInfo_ForbiddenFlags(), 0);
-                                       if (MapInfo_count > 0)
-                                       {
-                                               // update lsmaps in case the gametype changed, this way people can easily list maps for it
-                                               if (lsmaps_reply != "")   strunzone(lsmaps_reply);
-                                               lsmaps_reply = strzone(getlsmaps());
-                                               bprint("Game type successfully switched to ", s, "\n");
-                                       }
-                                       else
-                                       {
-                                               bprint("Cannot use this game type: no map for it found\n");
-                                               MapInfo_SwitchGameType(tsave);
-                                               MapInfo_FilterGametype(MapInfo_CurrentGametype(), MapInfo_CurrentFeatures(), MapInfo_RequiredFlags(), MapInfo_ForbiddenFlags(), 0);
-                                       }
-                               }
+                                       GameTypeVote_SetGametype(t);
                                else
-                               {
                                        bprint("Failed to switch to ", s, ": this game type does not exist!\n");
-                               }
 
                                return;
                        }
index 9392c2399f3942aac3a2598568b4e7111be6971e..917eb8ce44b18901b3704e7226cf3bfaf99ea1dd 100644 (file)
@@ -20,8 +20,7 @@ string GetMapname()
        return mapname;
 }
 
-float Map_Count, Map_Current;
-string Map_Current_Name;
+int Map_Count, Map_Current;
 
 // NOTE: this now expects the map list to be already tokenized and the count in Map_Count
 int GetMaplistPosition()
@@ -130,6 +129,9 @@ bool Map_Check(int position, float pass)
        {
                if(pass == 2)
                        return true;
+               // MapInfo_Map_flags was set by MapInfo_CheckMap()
+               if (MapInfo_Map_flags & MAPINFO_FLAG_DONOTWANT)
+                       return false;
                if(MapHasRightSize(map_next))
                        return true;
                return false;
@@ -150,8 +152,9 @@ void Map_Goto_SetStr(string nextmapname)
                getmapname_stored = strzone(nextmapname);
 }
 
-void Map_Goto_SetFloat(float position)
+void Map_Goto_SetIndex(int position)
 {
+       Map_Current = position;
        cvar_set("g_maplist_index", ftos(position));
        Map_Goto_SetStr(argv(position));
 }
@@ -164,9 +167,9 @@ void Map_Goto(float reinit)
 // return codes of map selectors:
 //   -1 = temporary failure (that is, try some method that is guaranteed to succeed)
 //   -2 = permanent failure
-float MaplistMethod_Iterate() // usual method
+int MaplistMethod_Iterate(void) // usual method
 {
-       float pass, i;
+       int pass, i;
 
        LOG_TRACE("Trying MaplistMethod_Iterate");
 
@@ -174,7 +177,7 @@ float MaplistMethod_Iterate() // usual method
        {
                for(i = 1; i < Map_Count; ++i)
                {
-                       float mapindex;
+                       int mapindex;
                        mapindex = (i + Map_Current) % Map_Count;
                        if(Map_Check(mapindex, pass))
                                return mapindex;
@@ -183,7 +186,7 @@ float MaplistMethod_Iterate() // usual method
        return -1;
 }
 
-float MaplistMethod_Repeat() // fallback method
+int MaplistMethod_Repeat(void) // fallback method
 {
        LOG_TRACE("Trying MaplistMethod_Repeat");
 
@@ -192,9 +195,9 @@ float MaplistMethod_Repeat() // fallback method
        return -2;
 }
 
-float MaplistMethod_Random() // random map selection
+int MaplistMethod_Random(void) // random map selection
 {
-       float i, imax;
+       int i, imax;
 
        LOG_TRACE("Trying MaplistMethod_Random");
 
@@ -202,7 +205,7 @@ float MaplistMethod_Random() // random map selection
 
        for(i = 0; i <= imax; ++i)
        {
-               float mapindex;
+               int mapindex;
                mapindex = (Map_Current + floor(random() * (Map_Count - 1) + 1)) % Map_Count; // any OTHER map
                if(Map_Check(mapindex, 1))
                        return mapindex;
@@ -212,7 +215,7 @@ float MaplistMethod_Random() // random map selection
 
 // the exponent sets a bias on the map selection:
 // the higher the exponent, the less likely "shortly repeated" same maps are
-float MaplistMethod_Shuffle(float exponent) // more clever shuffling
+int MaplistMethod_Shuffle(float exponent) // more clever shuffling
 {
        float i, j, imax, insertpos;
 
@@ -252,57 +255,57 @@ float MaplistMethod_Shuffle(float exponent) // more clever shuffling
                Map_Count = tokenizebyseparator(autocvar_g_maplist, " ");
 
                // NOTE: the selected map has just been inserted at (insertpos-1)th position
-               Map_Current = insertpos - 1; // this is not really valid, but this way the fallback has a chance of working
-               if(Map_Check(Map_Current, 1))
-                       return Map_Current;
+               if (Map_Check(insertpos - 1, 1))
+                       return insertpos - 1;
        }
        return -1;
 }
 
-void Maplist_Init()
+int Maplist_Init(void)
 {
-       float i = Map_Count = 0;
+       int i, available_maps = 0;
+       Map_Count = 0;
        if(autocvar_g_maplist != "")
        {
                Map_Count = tokenizebyseparator(autocvar_g_maplist, " ");
                for (i = 0; i < Map_Count; ++i)
-               {
                        if (Map_Check(i, 2))
-                               break;
-               }
+                               ++available_maps;
        }
 
-       if (i == Map_Count)
+       if (!available_maps)
        {
                bprint( "Maplist contains no usable maps!  Resetting it to default map list.\n" );
-               cvar_set("g_maplist", MapInfo_ListAllAllowedMaps(MapInfo_RequiredFlags(), MapInfo_ForbiddenFlags() | MAPINFO_FLAG_NOAUTOMAPLIST));
-               if(autocvar_g_maplist_shuffle)
-                       ShuffleMaplist();
+               cvar_set("g_maplist", MapInfo_ListAllowedMaps(MapInfo_CurrentGametype(), MapInfo_RequiredFlags(), MapInfo_ForbiddenFlags()));
                if(!server_is_dedicated)
                        localcmd("\nmenu_cmd sync\n");
                Map_Count = tokenizebyseparator(autocvar_g_maplist, " ");
+               for (i = 0; i < Map_Count; ++i)
+                       if (Map_Check(i, 2))
+                               ++available_maps;
        }
+
        if(Map_Count == 0)
                error("empty maplist, cannot select a new map");
+
        Map_Current = bound(0, GetMaplistPosition(), Map_Count - 1);
 
-       strcpy(Map_Current_Name, argv(Map_Current)); // will be automatically freed on exit thanks to DP
-       // this may or may not be correct, but who cares, in the worst case a map
-       // isn't chosen in the first pass that should have been
+       if(autocvar_g_maplist_shuffle)
+               cvar_set("g_maplist", shufflewords(autocvar_g_maplist));
+
+       return available_maps;
 }
 
-string GetNextMap()
+// NOTE: call Maplist_Init() before making GetNextMap() call(s)
+string GetNextMap(void)
 {
-       Maplist_Init();
-       float nextMap = -1;
+       int nextMap = -1;
 
-       if(nextMap == -1)
-               if(autocvar_g_maplist_shuffle > 0)
-                       nextMap = MaplistMethod_Shuffle(autocvar_g_maplist_shuffle + 1);
+       if(nextMap == -1 && autocvar_g_maplist_shuffle > 0)
+               nextMap = MaplistMethod_Shuffle(autocvar_g_maplist_shuffle + 1);
 
-       if(nextMap == -1)
-               if(autocvar_g_maplist_selectrandom)
-                       nextMap = MaplistMethod_Random();
+       if(nextMap == -1 && autocvar_g_maplist_selectrandom)
+               nextMap = MaplistMethod_Random();
 
        if(nextMap == -1)
                nextMap = MaplistMethod_Iterate();
@@ -312,7 +315,7 @@ string GetNextMap()
 
        if(nextMap >= 0)
        {
-               Map_Goto_SetFloat(nextMap);
+               Map_Goto_SetIndex(nextMap);
                return getmapname_stored;
        }
 
@@ -389,17 +392,13 @@ void GotoNextMap(float reinit)
                return;
        alreadychangedlevel = true;
 
+       Maplist_Init();
        string nextMap = GetNextMap();
        if(nextMap == "")
                error("Everything is broken - cannot find a next map. Please report this to the developers.");
        Map_Goto(reinit);
 }
 
-void ShuffleMaplist()
-{
-       cvar_set("g_maplist", shufflewords(autocvar_g_maplist));
-}
-
 string GotoMap(string m)
 {
        m = GameTypeVote_MapInfo_FixName(m);
index e3504829b57cdb27b11049c590432b336a240dbe..67413147c18bc3e231e57619dced90864cc1521e 100644 (file)
@@ -24,9 +24,8 @@ bool Map_IsRecent(string m);
 
 bool Map_Check(int position, float pass);
 
-string GetNextMap();
-
-void ShuffleMaplist();
+int Maplist_Init(void);
+string GetNextMap(void);
 
 void Map_Goto_SetStr(string nextmapname);
 
index f22347e8411632de37f40794976e87ad8b66ffbb..b5832d8939ae91b28b44f671007e9a619d5ec44f 100644 (file)
@@ -477,6 +477,32 @@ string GetField_fullspawndata(entity e, string f, ...)
        return v;
 }
 
+/*
+=============
+FindFileInMapPack
+
+Returns the first matching VFS file path that exists in the current map's pack.
+Returns string_null if no files match or the map isn't packaged.
+=============
+*/
+string FindFileInMapPack(string pattern)
+{
+       if (!checkextension("DP_QC_FS_SEARCH_PACKFILE"))
+               return string_null;
+
+       string base_pack = whichpack(strcat("maps/", mapname, ".bsp"));
+       if (base_pack == "" || !base_pack) // this map isn't packaged or there was an error
+               return string_null;
+
+       int glob = search_packfile_begin(pattern, true, true, base_pack);
+       if (glob < 0)
+               return string_null;
+
+       string file = search_getfilename(glob, 0);
+       search_end(glob);
+       return file;
+}
+
 void WarpZone_PostInitialize_Callback()
 {
        // create waypoint links for warpzones
index 3e9e1aaec578ac9ec3862bd20f1d697e4f77f238..d8ba13dcc2633ae0e0925143b9c145eea2d8530e 100644 (file)
@@ -12,7 +12,6 @@
 #include <server/command/cmd.qh>
 #include <server/command/getreplies.qh>
 #include <server/gamelog.qh>
-#include <server/intermission.qh>
 #include <server/world.qh>
 
 // definitions
@@ -203,16 +202,7 @@ void MapVote_AddVotable(string nextMap, bool isSuggestion)
 
 void MapVote_AddVotableMaps(int nmax, int smax)
 {
-       int available_maps = 0;
-       if (autocvar_g_maplist != "")
-       {
-               int c = tokenizebyseparator(autocvar_g_maplist, " ");
-               for (int i = 0; i < c; ++i)
-               {
-                       if (Map_Check(i, 1) || Map_Check(i, 2))
-                               ++available_maps;
-               }
-       }
+       int available_maps = Maplist_Init();
        int max_attempts = available_maps;
        if (available_maps >= 2)
                max_attempts = min(available_maps * 5, 100);
@@ -264,16 +254,6 @@ void MapVote_Init()
 
        MapVote_AddVotableMaps(nmax, smax);
 
-       if(mapvote_count == 0)
-       {
-               bprint( "Maplist contains no single playable map!  Resetting it to default map list.\n" );
-               cvar_set("g_maplist", MapInfo_ListAllowedMaps(MapInfo_CurrentGametype(), MapInfo_RequiredFlags(), MapInfo_ForbiddenFlags()));
-               if(autocvar_g_maplist_shuffle)
-                       ShuffleMaplist();
-               localcmd("\nmenu_cmd sync\n");
-               MapVote_AddVotableMaps(nmax, 0);
-       }
-
        mapvote_count_real = mapvote_count;
        if(mapvote_abstain)
                MapVote_AddVotable("don't care", false);
@@ -801,11 +781,7 @@ bool GameTypeVote_SetGametype(Gametype type)
                return false;
        }
 
-       //localcmd("gametype ", MapInfo_Type_ToString(type), "\n");
-
        cvar_set("g_maplist", MapInfo_ListAllowedMaps(type, MapInfo_RequiredFlags(), MapInfo_ForbiddenFlags()) );
-       if(autocvar_g_maplist_shuffle)
-               ShuffleMaplist();
 
        return true;
 }
index 8c6a2a7690cc7c6e0efb075411839f929c6f6fef..36578740c07fff735e11041ce9811d1284727484 100644 (file)
@@ -30,6 +30,7 @@ void MapVote_Start();
 void MapVote_Spawn();
 void MapVote_Think();
 void MapVote_SendPicture(entity to, int id);
+bool GameTypeVote_SetGametype(entity type);
 float GameTypeVote_Start();
 float GameTypeVote_Finished(int pos);
 string GameTypeVote_MapInfo_FixName(string m);
index 6e79c73ef1c014d1de388729a8de6f15fdbffd1f..7bbbfa0dd7d9152f8e096f3a778ee0639059bfde 100644 (file)
@@ -118,12 +118,7 @@ void GotoFirstMap(entity this)
        {
                // cvar_set("_sv_init", "0");
                // we do NOT set this to 0 any more, so someone "accidentally" changing
-               // to this "init" map on a dedicated server will cause no permanent
-               // harm
-               if(autocvar_g_maplist_shuffle)
-                       ShuffleMaplist();
-               n = tokenizebyseparator(autocvar_g_maplist, " ");
-               cvar_set("g_maplist_index", ftos(n - 1)); // jump to map 0 in GotoNextMap
+               // to this "init" map on a dedicated server will cause no permanent harm
 
                MapInfo_Enumerate();
                MapInfo_FilterGametype(MapInfo_CurrentGametype(), MapInfo_CurrentFeatures(), MapInfo_RequiredFlags(), MapInfo_ForbiddenFlags(), 0);
@@ -337,8 +332,11 @@ void cvar_changes_init()
 
                if(adding)
                {
+                       if (cvar_changes == "")
+                               cvar_changes = "// this server runs at modified server settings:\n";
+
                        cvar_changes = strcat(cvar_changes, k, " \"", v, "\" // \"", d, "\"\n");
-                       if(strlen(cvar_changes) > 16384)
+                       if(strlen(cvar_changes) >= VM_TEMPSTRING_MAXSIZE)
                        {
                                cvar_changes = "// too many settings have been changed to show them here\n";
                                adding = 0;
@@ -551,8 +549,11 @@ void cvar_changes_init()
 
                if(pureadding)
                {
+                       if (cvar_purechanges == "")
+                               cvar_purechanges = "// this server runs at modified gameplay settings:\n";
+
                        cvar_purechanges = strcat(cvar_purechanges, k, " \"", v, "\" // \"", d, "\"\n");
-                       if(strlen(cvar_purechanges) > 16384)
+                       if(strlen(cvar_purechanges) >= VM_TEMPSTRING_MAXSIZE)
                        {
                                cvar_purechanges = "// too many settings have been changed to show them here\n";
                                pureadding = 0;
@@ -567,15 +568,13 @@ void cvar_changes_init()
                // though.
        }
        buf_del(h);
+
        if(cvar_changes == "")
                cvar_changes = "// this server runs at default server settings\n";
-       else
-               cvar_changes = strcat("// this server runs at modified server settings:\n", cvar_changes);
        cvar_changes = strzone(cvar_changes);
+
        if(cvar_purechanges == "")
                cvar_purechanges = "// this server runs at default gameplay settings\n";
-       else
-               cvar_purechanges = strcat("// this server runs at modified gameplay settings:\n", cvar_purechanges);
        cvar_purechanges = strzone(cvar_purechanges);
 }
 
diff --git a/qcsrc/tools/sv_game-hashtest.sh b/qcsrc/tools/sv_game-hashtest.sh
new file mode 100755 (executable)
index 0000000..f3f0eb2
--- /dev/null
@@ -0,0 +1,235 @@
+#!/bin/bash
+
+# abort on error(non-0 return code) and abort on unset variable
+set -eu
+
+# refuse to run on Windows' MINGW due to symlinking issues
+# `ln -s "$PWD" data/xonotic-data.pk3dir` seems to not work in any form
+# even with fully relative paths or `ln -s ../ xonotic-data.pk3dir`
+# FIXME?
+case "$(uname)" in
+       MINGW*) printf "%s\n%s\n" "This file is not suitable for Windows' MINGW" \
+               "without modifications due to the lack of proper symlink support"; exit 1 ;;
+esac
+
+printf "Testing for dependencies\n"
+# command -q / --quiet one day? :(
+command -V awk       > /dev/null
+command -V chmod     > /dev/null
+command -V git       > /dev/null
+command -V grep      > /dev/null
+command -V make      > /dev/null
+command -V md5sum    > /dev/null
+command -V mkdir     > /dev/null
+command -V mktemp    > /dev/null
+command -V rm        > /dev/null
+command -V rmdir     > /dev/null
+command -V sed       > /dev/null
+command -V tee       > /dev/null
+command -V test      > /dev/null
+command -V true      > /dev/null
+command -V printf    > /dev/null
+command -V wget      > /dev/null
+printf "All dependencies found\n"
+
+createdtoday() {
+       # check if a file's creation date is today
+       if [ "$(stat -c '%y' "$1" | cut -d ' ' -f 1)" = "$(date -I)" ]
+       then
+               #echo "$1 was created today"
+               return 0
+       else
+               #echo "$1 was not created today"
+               return 1
+       fi
+}
+
+hashtestcleanup() {
+       # allow for error return codes in this function as this may be ran on interrupt
+       # right after starting where all files to clean up don't exist yet
+       set +e
+
+       # unset trap
+       trap - EXIT INT QUIT TERM
+
+       # Few files' removal has been disabled for file reuse
+       # It's possible to get rate limited with enough testing
+
+       rm lock
+       rm data/darkplaces_history.txt
+       rm data/xonotic-data.pk3dir
+       #rm data/stormkeep.pk3
+       rm data/data/defaultSVQC.cfg
+       rm data/data/hits---1.plot
+       rm data/data/hits---2.plot
+       rm data/data/hits---3.plot
+       rm data/data/notifications_dump.cfg
+       rm data/data/server.db
+       rmdir data/data/
+       #rm data/maps/_init.bsp
+       #rm data/maps/stormkeep.mapinfo
+       #rm data/maps/stormkeep.waypoints
+       #rm data/maps/stormkeep.waypoints.cache
+       #rmdir data/maps/
+
+       set -e
+}
+trap "hashtestcleanup" EXIT INT QUIT TERM
+
+# cd xonotic-data.pk3dir
+cd "$(dirname "$0")/../../"
+
+WORKINGDIR="$PWD"
+
+TMPDIR="$PWD/.tmp"
+
+# if xonotic-data.pk3dir/data/xonotic-data.pk3dir isn't a symlink then link it
+if [ -e data/xonotic-data.pk3dir ]
+then # file exists
+       if ! [ -L data/xonotic-data.pk3dir ]
+       then # file exists but it's not a symlink, replace it
+               if [ -d data/xonotic-data.pk3dir ]
+               then # it's a dir
+                       rmdir data/xonotic-data.pk3dir
+                       ln -s "$PWD" data/xonotic-data.pk3dir
+               else # it's not a dir
+                       rm data/xonotic-data.pk3dir
+                       ln -s "$PWD" data/xonotic-data.pk3dir
+               fi
+       else # it is a symlink, verify where it points
+               if [ "$(realpath data/xonotic-data.pk3dir)" != "$PWD" ]
+               then # wrong place, recreate it
+                       rm data/xonotic-data.pk3dir
+                       ln -s "$PWD" data/xonotic-data.pk3dir
+               fi
+       fi
+else # no file exists there
+       ln -s "$PWD" data/xonotic-data.pk3dir
+fi
+
+MAKEFLAGS=-j$(nproc)
+export MAKEFLAGS
+printf "%s\n" "MAKEFLAGS=$MAKEFLAGS"
+export CC="gcc -pipe"
+
+# precompiled binary is executable and its creation date is today
+if [ -x "$TMPDIR/gmqcc-bin" ] && createdtoday "$TMPDIR/gmqcc-bin"
+then
+       export QCC="$TMPDIR/gmqcc-bin"
+else # previously compiled is executable and its creation date is today
+       if [ -x "$TMPDIR/gmqcc/gmqcc" ] && createdtoday "$TMPDIR/gmqcc/gmqcc"
+       then
+               export QCC="$TMPDIR/gmqcc/gmqcc"
+       else # nothing reusable exists
+               # prefer a precompiled binary
+               if wget -nv https://beta.xonotic.org/pipeline-bin/gmqcc -O "$TMPDIR/gmqcc-bin"
+               then
+                       export QCC="$TMPDIR/gmqcc-bin"
+                       chmod +x "$QCC"
+               else
+                       if [ -d "$TMPDIR/gmqcc" ]
+                       then
+                               cd "$TMPDIR/gmqcc"
+                               git checkout main
+                               git pull
+                               cd "$WORKINGDIR"
+                       else
+                               git clone --depth=1 --branch=main https://gitlab.com/xonotic/gmqcc.git "$TMPDIR/gmqcc"
+                       fi
+                       make -C "$TMPDIR/gmqcc" || exit 1
+                       export QCC="$TMPDIR/gmqcc/gmqcc"
+               fi
+       fi
+fi
+
+# Makefile: don't complain about lack of tags (fetching them is slow)
+export QCCFLAGS_WATERMARK=gitlab_pipeline
+# Makefile: don't compress anything or complain about lack of zip program
+export ZIP=true
+
+
+if [ "$(uname):$(uname -m)" = "Linux:x86_64" ] && [ -x "$TMPDIR/xonotic-linux64-dedicated" ] && createdtoday "$TMPDIR/xonotic-linux64-dedicated"
+then # precompiled binary is executable and its creation date is today
+       export ENGINE="$TMPDIR/xonotic-linux64-dedicated"
+else
+       if [ -x "$TMPDIR/darkplaces/darkplaces-dedicated" ] && createdtoday "$TMPDIR/darkplaces/darkplaces-dedicated"
+       then # previously compiled is executable and its creation date is today
+               export ENGINE="$TMPDIR/darkplaces/darkplaces-dedicated -xonotic"
+       else # nothing reusable exists
+               # prefer a precompiled binary
+               if [ "$(uname):$(uname -m)" = "Linux:x86_64" ] && wget -nv https://beta.xonotic.org/pipeline-bin/xonotic-linux64-dedicated -O "$TMPDIR/xonotic-linux64-dedicated"
+               then
+                       export ENGINE="$TMPDIR/xonotic-linux64-dedicated"
+                       chmod +x "$ENGINE"
+               else
+                       if [ -d "$TMPDIR/darkplaces" ]
+                       then
+                               cd "$TMPDIR/darkplaces"
+                               #git checkout master
+                               git pull --autostash
+                               cd "$WORKINGDIR"
+                       else
+                               git clone --depth=1 https://gitlab.com/xonotic/darkplaces.git "$TMPDIR/darkplaces"
+                       fi
+                       make -C "$TMPDIR/darkplaces" sv-release || exit 1
+                       export ENGINE="$TMPDIR/darkplaces/darkplaces-dedicated -xonotic"
+               fi
+       fi
+fi
+export ENGINE="$ENGINE -noconfig -nohome"
+
+make qc || exit 1
+
+mkdir -p data/maps
+
+createdtoday "data/maps/_init.bsp" \
+       || wget -nv -O data/maps/_init.bsp https://gitlab.com/xonotic/xonotic-maps.pk3dir/raw/master/maps/_init/_init.bsp
+
+while read -r LINE
+do
+       printf "%s\n" "$LINE"
+       [ "$LINE" = "All tests OK" ] && PASS=1
+done < <(${ENGINE} +developer 1 +map _init +sv_cmd runtest +wait +quit)
+test "$PASS" = "1" || { printf 'sv_cmd runtest failed!'; exit 1; }
+
+${ENGINE} +map _init +sv_cmd dumpnotifs +wait +quit
+diff notifications.cfg data/data/notifications_dump.cfg ||
+       { printf "Please update notifications.cfg using \`dumpnotifs\`!"; exit 1; }
+
+createdtoday "data/stormkeep.pk3" \
+       || wget -nv -O data/stormkeep.pk3 https://beta.xonotic.org/pipeline-bin/stormkeep.pk3
+createdtoday "data/maps/stormkeep.mapinfo" \
+       || wget -nv -O data/maps/stormkeep.mapinfo https://gitlab.com/xonotic/xonotic-maps.pk3dir/raw/master/maps/stormkeep.mapinfo
+createdtoday "data/maps/stormkeep.waypoints" \
+       || wget -nv -O data/maps/stormkeep.waypoints https://gitlab.com/xonotic/xonotic-maps.pk3dir/raw/master/maps/stormkeep.waypoints
+createdtoday "data/maps/stormkeep.waypoints.cache" \
+       || wget -nv -O data/maps/stormkeep.waypoints.cache https://gitlab.com/xonotic/xonotic-maps.pk3dir/raw/master/maps/stormkeep.waypoints.cache
+
+set +u
+if [ -z "$EXPECT" ]
+then
+       # find the line with expected hash from .gitlab-ci.yml, extract the hash and remove carriage return
+       EXPECT="$(grep 'EXPECT=' './.gitlab-ci.yml' | cut -d '=' -f 2 | tr -d $'\r')"
+fi
+set -u
+HASH=$(${ENGINE} +exec serverbench.cfg \
+      | tee /dev/stderr \
+      | grep '^:' \
+      | grep -v '^:gamestart:' \
+      | grep -v '^:anticheat:' \
+      | md5sum | awk '{ print $1 }')
+
+hashtestcleanup
+
+if [ "$HASH" = "$EXPECT" ]
+then # green ok print
+       printf "\033[32m%s\033[0m\n" "expected: $EXPECT"
+       printf "\033[32m%s\033[0m\n" "  actual: $HASH"
+       printf "\033[32m%s\033[0m\n" "hashes match"
+       exit 0
+else # red error print
+       printf "\033[32m%s\033[0m\n" "expected: $EXPECT"
+       printf "\033[32m%s\033[0m\n" "  actual: $HASH"
+       printf "\033[31m%s\033[0m\n" "!!! ERROR: HASHES DO NOT MATCH !!!"
+       exit 1
+fi
index 9e9c48f5faeb108b83a24e0ca0c84d497d6e8f72..d1b449f475d8ac5608a069854660ec72626e739e 100644 (file)
@@ -456,11 +456,13 @@ seta cl_damagetext_size_max 16 "Damage text font size for large damage"
 seta cl_damagetext_size_max_damage 140 "How much damage is considered large"
 seta cl_damagetext_alpha_start "1" "Damage text initial alpha"
 seta cl_damagetext_alpha_lifetime "3" "Damage text lifetime in seconds"
+seta cl_damagetext_lifetime "-1" "Damage text lifetime, edit this if you wish for damage text to disappear before it fades out"
 seta cl_damagetext_velocity_screen "0 0 0" "Damage text move direction (screen coordinates)"
 seta cl_damagetext_velocity_world "0 0 20" "Damage text move direction (world coordinates relative to player's view)"
 seta cl_damagetext_offset_screen "0 -45 0" "Damage text offset (screen coordinates)"
 seta cl_damagetext_offset_world "0 25 0" "Damage text offset (world coordinates relative to player's view)"
 seta cl_damagetext_accumulate_alpha_rel "0.65" "Only update existing damage text when it's above this much percentage (0 to 1) of the starting alpha"
+seta cl_damagetext_accumulate_lifetime "-1" "Only update existing damage text when it is younger than this many seconds, negative always updates"
 seta cl_damagetext_friendlyfire "1" "0: never show for friendly fire, 1: when more than 0 damage, 2: always"
 seta cl_damagetext_friendlyfire_color "1 0 0" "Damage text color for friendlyfire"
 
index a72143db3849a387a10fad28f8440f6816600081..3ec45a9fdb973bd567484e45c715ed53c9dbb8a2 100644 (file)
@@ -57,6 +57,7 @@ set g_telefrags 1 "telefragging, i.e. killing someone who stands in the way of s
 set g_telefrags_teamplay 1 "never telefrag team mates"
 set g_telefrags_avoid 1 "when teleporters have a random destination, avoid teleporting to locations where a telefrag would happen"
 set g_teleport_maxspeed 0 "maximum speed that a player can keep when going through a teleporter (if a misc_teleporter_dest also has a cap the smallest one of these will be used), 0 = don't limit, -1 = keep no speed"
+set g_teleport_minspeed 0 "minimum speed that a player can keep when going through a teleporter which affects speed"
 
 set g_respawn_ghosts 1 "if 1 dead bodies become ghosts and float away when the player respawns"
 set g_respawn_ghosts_speed 5 "the speed with which respawn ghosts float and rotate"
@@ -226,7 +227,7 @@ set g_maplist_mostrecent "" "contains the name of the maps that were most recent
 set g_maplist_mostrecent_count 3 "number of most recent maps that are blocked from being played again"
 set g_maplist_index 0 "this is used internally for saving position in maplist cycle"
 set g_maplist_selectrandom 0 "if 1, a random map will be chosen as next map - DEPRECATED in favor of g_maplist_shuffle"
-set g_maplist_shuffle 1 "new randomization method: like selectrandom, but avoid playing the same maps in short succession. This works by taking out the first element and inserting it into g_maplist with a bias to the end of the list"
+set g_maplist_shuffle 1 "1: shuffling method which avoids playing the same maps in short succession by taking out the first element and inserting it into g_maplist with a bias to the end of the list. -1: a simpler shuffling method which should be adequate if g_maplist_mostrecent_count is large enough."
 set g_maplist_check_waypoints 0 "when 1, maps are skipped if there currently are bots, but the map has no waypoints"
 set g_maplist_ignore_sizes 0 "when 1, all maps are shown in the map list regardless of player count"
 set g_maplist_sizes_count_maxplayers 1 "check the player limit when getting the player count so forced spectators don't affect the size restrictions"
@@ -243,7 +244,7 @@ set g_player_brightness 0 "set to 2 for brighter players"
 
 set g_player_damageforcescale 2 "push multiplier of attacks against players"
 
-set g_player_damageplayercenter 0 "0: always calculate knockback force direction from player's eyes instead of bbox center. 1: use bbox center point for others, shot origin for attacker's self-damage"
+set g_player_damageplayercenter 1 "0: always calculate knockback force direction from player's eyes instead of bbox center. 1: use bbox center point for others, shot origin for attacker's self-damage"
 
 set g_playerclip_collisions 1 "0 = disable collision testing against playerclips, might be useful on some defrag maps"
 set g_botclip_collisions 1 "0 = disable collision testing against botclips, might be useful on some defrag maps"