.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
-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
-Mon Dec 11 07:23:08 AM CET 2023
+Fri Jan 26 07:22:59 AM CET 2024
# 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 ""
#: 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."
#: 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
#: 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
#: 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
#: 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!"
#: 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
#: 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..."
#: 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:"
#: 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
#: 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"
#: qcsrc/client/hud/panel/quickmenu.qc:824
msgid "QMCMD^Send in English"
-msgstr "QMCMD^Send i Engelsk"
+msgstr "QMCMD^Send på Engelsk"
#: qcsrc/client/hud/panel/quickmenu.qc:829
#: qcsrc/client/hud/panel/quickmenu.qc:845
#: 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"
"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"
#: 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
#: 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!"
#: 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
#: 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"
# 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
"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"
#: 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"
#
# 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"
#: 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
#: 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
#: 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:"
#: 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"
#: 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"
#: 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"
#: 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:"
#: 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
#: 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:"
#: 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:"
#: 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:"
#: 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"
#: 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"
#: 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"
#: 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:"
#: 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"
#: 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"
#: 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:"
#: 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:"
#: 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"
#: 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
#: 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"
#: 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"
#: 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"
#: 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"
#: 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"
#: 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"
#: 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"
#: 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
#: 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"
#: 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
#: 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"
#: 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:"
#: 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"
#: 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:"
# Lucifer Morningstar, 2022
# Lucifer Morningstar, 2022
# Mehmet Ali Kaplan, 2023
+# Mehmet Ali Kaplan, 2023
# Tan Siret Akıncı <tanakinci2002@gmail.com>, 2021
msgid ""
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"
"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
#: 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"
#: qcsrc/client/mapvoting.qc:395
msgid "Decide the gametype"
-msgstr "选择游戏种类"
+msgstr "选择游戏模式"
#: qcsrc/client/mapvoting.qc:395
msgid "Vote for a map"
#: 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"
#: 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
#: 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
#: qcsrc/menu/xonotic/serverlist.qh:160
msgid "SLCAT^Defrag Mode"
-msgstr "Defrag(无杀戮模式)"
+msgstr "Defrag(休闲)"
#: qcsrc/menu/xonotic/skinlist.qc:70
msgid "<TITLE>"
"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
#: 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"
#: qcsrc/client/mapvoting.qc:395
msgid "Decide the gametype"
-msgstr "選擇遊戲種類"
+msgstr "選擇遊戲模式"
#: qcsrc/client/mapvoting.qc:395
msgid "Vote for a map"
#: 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"
#: 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
#: 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
#: qcsrc/menu/xonotic/serverlist.qh:160
msgid "SLCAT^Defrag Mode"
-msgstr "Defrag(無殺戮模式)"
+msgstr "Defrag(休閒)"
#: qcsrc/menu/xonotic/skinlist.qc:70
msgid "<TITLE>"
#: 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."
"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
#: 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"
#: qcsrc/client/mapvoting.qc:395
msgid "Decide the gametype"
-msgstr "選擇遊戲種類"
+msgstr "選擇遊戲類型"
#: qcsrc/client/mapvoting.qc:395
msgid "Vote for a map"
#: 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"
#: 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
#: 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"
#: 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
#: 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"
#: 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
#: qcsrc/common/notifications/all.inc:807
msgid "^F2Intruder detected, disabling shields!"
-msgstr "^F2檢測到入侵者,正在禁用護盾!"
+msgstr "^F2檢測到入侵者,正在停用護盾!"
#: qcsrc/common/notifications/all.inc:809
msgid ""
#: 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
#: qcsrc/menu/xonotic/dialog_hudsetup_exit.qc:95
msgid "DOCK^Disabled"
-msgstr "禁用"
+msgstr "停用"
#: qcsrc/menu/xonotic/dialog_hudsetup_exit.qc:96
msgid "DOCK^Small"
#: 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
#: qcsrc/menu/xonotic/dialog_settings_audio.qc:170
msgid "WRN^Disabled"
-msgstr "已禁用"
+msgstr "已停用"
#: qcsrc/menu/xonotic/dialog_settings_audio.qc:172
msgid "5 minutes"
#: 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"
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"
#: qcsrc/menu/xonotic/dialog_settings_effects.qc:186
msgid "DMGFX^Disabled"
-msgstr "禁用"
+msgstr "停用"
#: qcsrc/menu/xonotic/dialog_settings_effects.qc:187
msgid "Skeletal"
#: 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"
#: 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"
#: 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"
#: qcsrc/menu/xonotic/dialog_settings_input.qc:102
msgid "JPJUMP^Disabled"
-msgstr "禁用"
+msgstr "停用"
#: qcsrc/menu/xonotic/dialog_settings_input.qc:103
msgid "Air only"
#: qcsrc/menu/xonotic/dialog_settings_misc.qc:101
msgid "TRGT^Disabled"
-msgstr "已禁用"
+msgstr "已停用"
#: qcsrc/menu/xonotic/dialog_settings_misc.qc:112
msgid "Idle limit:"
"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"
#: 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"
#: 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
#: qcsrc/menu/xonotic/dialog_settings_video.qc:93
msgid "ANISO^Disabled"
-msgstr "已禁用"
+msgstr "已停用"
#: qcsrc/menu/xonotic/dialog_settings_video.qc:96
msgid "8x"
#: qcsrc/menu/xonotic/dialog_settings_video.qc:105
msgid "DF^Disabled"
-msgstr "已禁用"
+msgstr "已停用"
#: qcsrc/menu/xonotic/dialog_settings_video.qc:106
msgid "DF^World"
#: qcsrc/menu/xonotic/serverlist.qh:160
msgid "SLCAT^Defrag Mode"
-msgstr "Defrag(無殺戮模式)"
+msgstr "Defrag(休閒)"
#: qcsrc/menu/xonotic/skinlist.qc:70
msgid "<TITLE>"
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"
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%
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
// 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
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
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
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
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
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
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
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
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
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
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
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
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();
}
}
- 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;
{
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
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
{
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()
#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;
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()
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;
{
// 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
}
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);
{
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")
{
REGISTRY(Gametypes, 32)
REGISTER_REGISTRY(Gametypes)
-REGISTRY_SORT(Gametypes);
+REGISTRY_SORT(Gametypes)
REGISTRY_CHECK(Gametypes)
REGISTRY_DEFINE_GET(Gametypes, NULL)
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;
{
bool reverse = false;
if((this.spawnflags & DOOR_CRUSH)
+ && !Q3COMPAT_COMMON
#ifdef SVQC
&& (blocker.takedamage != DAMAGE_NO)
#elif defined(CSQC)
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);
}
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)
{
} 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)
#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);
}
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;
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)
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;
"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
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
}
else if (!this.wait)
{
- this.wait = 3;
+ this.wait = q3compat ? 2 : 3;
}
if (!this.lip)
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)
{
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;
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!
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
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)
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;
}
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 != "")
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;
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)
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;
{
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
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.
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);
#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;
}
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
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);
}
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
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
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
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)
/* 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"));
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))
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
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
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)
}
SPAWNFUNC_ITEM(item_invisibility, ITEM_Invisibility)
+SPAWNFUNC_ITEM(item_buff_invisibility, ITEM_Invisibility)
CLASS(Invisibility, Powerups)
ATTRIB(Invisibility, netname, string, "invisibility");
}
SPAWNFUNC_ITEM(item_speed, ITEM_Speed)
+SPAWNFUNC_ITEM(item_buff_speed, ITEM_Speed)
CLASS(Speed, Powerups)
ATTRIB(Speed, netname, string, "speed");
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); }
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
* 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!)
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)
}
#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); }
#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); }
#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)
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) \
{ \
} \
} \
} \
- 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) \
#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
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;
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)
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")
{
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);
}
#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>
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;
}
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()
{
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;
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));
}
// 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");
{
for(i = 1; i < Map_Count; ++i)
{
- float mapindex;
+ int mapindex;
mapindex = (i + Map_Current) % Map_Count;
if(Map_Check(mapindex, pass))
return mapindex;
return -1;
}
-float MaplistMethod_Repeat() // fallback method
+int MaplistMethod_Repeat(void) // fallback method
{
LOG_TRACE("Trying MaplistMethod_Repeat");
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");
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;
// 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;
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();
if(nextMap >= 0)
{
- Map_Goto_SetFloat(nextMap);
+ Map_Goto_SetIndex(nextMap);
return getmapname_stored;
}
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);
bool Map_Check(int position, float pass);
-string GetNextMap();
-
-void ShuffleMaplist();
+int Maplist_Init(void);
+string GetNextMap(void);
void Map_Goto_SetStr(string nextmapname);
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
#include <server/command/cmd.qh>
#include <server/command/getreplies.qh>
#include <server/gamelog.qh>
-#include <server/intermission.qh>
#include <server/world.qh>
// definitions
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);
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);
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;
}
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);
{
// 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);
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;
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;
// 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);
}
--- /dev/null
+#!/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
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"
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"
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"
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"