From: Rudolf Polzer Date: Fri, 22 Oct 2010 07:02:59 +0000 (+0200) Subject: Merge remote branch 'refs/remotes/origin/ThePWTULN/campaigntimer' X-Git-Tag: xonotic-v0.1.0preview~266 X-Git-Url: https://git.xonotic.org/?a=commitdiff_plain;h=cb78214cf1252fa80df3490c0cd3d41bae72bbb8;hp=669c8376ed12ed0039a6ea7eb2ed9615c03411f3;p=xonotic%2Fxonotic-data.pk3dir.git Merge remote branch 'refs/remotes/origin/ThePWTULN/campaigntimer' --- diff --git a/.gitattributes b/.gitattributes index a2b2bfc3a..ec3bfe3d1 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,31 +1,41 @@ * -crlf -*.7z -crlf -diff +*.0 -diff -crlf +*.1 crlf=input +*.3 crlf=input +*.7z -diff -crlf *.ac crlf=input +*.a -diff -crlf *.afm crlf=input *.aft crlf=input +*.ai -diff -crlf *.aliases crlf=input all crlf=input *.am crlf=input *.animinfo crlf=input -*.aps -crlf -diff +*.aps -diff -crlf +*.asc -diff -crlf *.ase -crlf *.bat -crlf *.bgs crlf=input -*.blend -crlf -diff -*.bmp -crlf -diff +*.blend1 -diff -crlf +*.blend -diff -crlf +blind_id -diff -crlf +*.bmp -diff -crlf branch-manager crlf=input +*.brand crlf=input BSDmakefile crlf=input bsp2ent crlf=input -*.bsp -crlf -diff -*.cache -crlf -diff +*.bsp -diff -crlf +*.cache -diff -crlf *.cbp -crlf -*.cbp -crlf -diff +*.cbp -diff -crlf *.c crlf=input *.cfg crlf=input *.cg crlf=input ChangeLog crlf=input CHANGES crlf=input +cjpeg -diff -crlf COMPILING crlf=input compress-texture crlf=input *.conf crlf=input @@ -33,42 +43,49 @@ CONTRIBUTORS crlf=input COPYING crlf=input *.cpp crlf=input create crlf=input +*.cron crlf=input *.css crlf=input -Current -crlf -diff -*.cvsignore crlf=input *.cvswrappers crlf=input -*.dat -crlf -diff -*.db -crlf -diff +*.d0pk -diff -crlf +*.db -diff -crlf *.default crlf=input *.def crlf=input -*.dem -crlf -diff +*.dem -diff -crlf *.dev -crlf -*.dll -crlf -diff -DOCS -crlf -diff +dir -diff -crlf +djpeg -diff -crlf +*.dll -diff -crlf +DOCS -diff -crlf *.dot crlf=input DoxyConfig crlf=input +doxyfile crlf=input Doxyfile crlf=input *.doxygen crlf=input -*.dpm -crlf -diff +*.dpm -diff -crlf *.dsp -crlf *.dsw -crlf *.dtd crlf=input -*.dylib -crlf -diff +*.dylib -diff -crlf +empty -diff -crlf *.EncoderPlugin crlf=input -*.ent -crlf +*.flac -diff -crlf *.form crlf=input *.framegroups crlf=input *.game crlf=input +*.gdb crlf=input gendox crlf=input gendoxfunctions crlf=input genDoxyfile crlf=input -*.gif -crlf -diff +*.gif -diff -crlf *.gitattributes crlf=input git-branch-manager crlf=input git-filter-index crlf=input git-filter-repository crlf=input *.gitignore crlf=input +git-pk3-import crlf=input +git-pk3-merge crlf=input git-pullall crlf=input +git-recurse crlf=input git-split-repository crlf=input git-svn-checkout crlf=input git-svn-update crlf=input @@ -81,64 +98,70 @@ GPL crlf=input *.hs crlf=input *.html crlf=input *.html-part crlf=input -*.icns -crlf -diff -*.ico -crlf -diff +*.icns -diff -crlf +*.ico -diff -crlf +*.idl crlf=input *.idsoftware crlf=input *.inc crlf=input *.in crlf=input +*.info-1 -diff -crlf +*.info-2 -diff -crlf +*.info -diff -crlf +*.inl crlf=input *.instantaction crlf=input -*.iqm -crlf -diff +*.iqm -diff -crlf *.java crlf=input *.jhm crlf=input *.jnlp crlf=input -*.jpg -crlf -diff +jpegtran -diff -crlf +*.jpg -diff -crlf *.jsmooth crlf=input +*.la crlf=input LGPL crlf=input LICENSE crlf=input -*.lmp -crlf -diff +*.lmp -diff -crlf *.loaders crlf=input -*.lso -crlf -diff +*.lso -diff -crlf +*.m4 crlf=input makefile crlf=input Makefile crlf=input -*.makespr32 crlf=input makespr32 crlf=input -*.map -crlf +*.map -crlf filter=mapclean *.mapinfo crlf=input *.m crlf=input -*.md3 -crlf -diff +*.md3 -diff -crlf *.md5anim -crlf *.md5mesh -crlf -*.mdl -crlf -diff +*.mdl -diff -crlf *.med crlf=input *.mf crlf=input -*.mid -crlf -diff +*.mid -diff -crlf *.mk crlf=input -*.mkdir -crlf -diff -*.mmpz -crlf -diff -*.modinfo crlf=input +*.mkdir -diff -crlf +*.mmpz -diff -crlf *.modules crlf=input -nexuiz-map-compiler crlf=input *.nib -crlf *.obj -crlf -OFFSETS -crlf -diff -*.ogg -crlf -diff +OFFSETS -diff -crlf +*.ogg -diff -crlf *.options crlf=input pangorc crlf=input *.patch crlf=input *.patchsets crlf=input -*.pcx -crlf -diff -*.pfb -crlf -diff -*.pfm -crlf -diff -*.pk3 -crlf -diff +*.pc crlf=input +*.pcx -diff -crlf +*.pfb -diff -crlf +*.pfm -diff -crlf +*.pk3 -diff -crlf PkgInfo crlf=input *.pl crlf=input *.plist crlf=input *.pm crlf=input -*.png -crlf -diff -POSITIONS -crlf -diff +*.png -diff -crlf +POSITIONS -diff -crlf *.proj -crlf *.properties crlf=input -*.psd -crlf -diff +*.psd -diff -crlf *.py crlf=input *.q3map1 crlf=input *.qc crlf=input @@ -147,48 +170,53 @@ POSITIONS -crlf -diff *.rb crlf=input *.rc2 crlf=input *.rc -crlf +rdjpgcom -diff -crlf *.readme crlf=input README crlf=input -*.rtlights -crlf -diff +*.rtlights -diff -crlf SCHEMA crlf=input *.scm crlf=input -SDL -crlf -diff -SDLMain.m crlf=input +sdl-config crlf=input +SDL -diff -crlf *.shader crlf=input *.sh crlf=input *.skin crlf=input *.sln -crlf *.sounds crlf=input -*.sp2 -crlf -diff -*.spr32 -crlf -diff -*.spr -crlf -diff +*.sp2 -diff -crlf +*.spr32 -diff -crlf +*.spr -diff -crlf *.src crlf=input *.strings crlf=input -*.strip crlf=input strip crlf=input -*.svg -crlf -diff -*.TAB -crlf -diff -*.tga -crlf -diff -TMAP -crlf -diff +*.svg -diff -crlf +*.TAB -diff -crlf +*.tga -diff -crlf +TMAP -diff -crlf todo crlf=input TODO crlf=input -*.ttf -crlf -diff -*.TTF -crlf -diff +*.ttf -diff -crlf +*.TTF -diff -crlf *.txt crlf=input -*.TXT crlf=input update-shaderlists crlf=input +*.vbs -crlf *.vcproj -crlf -*.wav -crlf -diff -*.waypoints -crlf -diff +versionbuilder crlf=input +*.wav -diff -crlf +*.waypoints -diff -crlf w crlf=input *.width crlf=input *.workspace -crlf -*.xcf -crlf -diff +wrjpgcom -diff -crlf +*.xcf -diff -crlf *.xlink crlf=input *.xml crlf=input xonotic-map-compiler-autobuild crlf=input xonotic-map-compiler crlf=input +xonotic-map-screenshot crlf=input +xonotic-osx-agl crlf=input +xonotic-osx-sdl crlf=input *.xpm crlf=input -*.zip -crlf -diff +*.zip -diff -crlf zipdiff crlf=input -*.zym -crlf -diff +*.zym -diff -crlf diff --git a/Makefile b/Makefile index 99478f084..50a9f0b02 100644 --- a/Makefile +++ b/Makefile @@ -1,15 +1,14 @@ SCM := $(shell if [ -d .svn ]; then echo svn; elif [ -d ../.git ]; then echo git; fi) FTEQCC ?= fteqcc PERL ?= perl -PK3NAME ?= `date +../data%Y%m%d.pk3` ZIP ?= 7za a -tzip -mx=9 ZIPEXCLUDE ?= -x\!*.pk3 -xr\!\.svn -x\!qcsrc DIFF ?= diff FTEQCCFLAGS_WATERMARK ?= -DWATERMARK='"^1$(shell git describe) TEST BUILD"' FTEQCCFLAGS ?= -Werror -Wall -Wno-mundane -O3 -Ono-c -Ono-cs -flo $(FTEQCCFLAGS_EXTRA) $(FTEQCCFLAGS_WATERMARK) -FTEQCCFLAGS_PROGS ?= -FTEQCCFLAGS_MENU ?= +FTEQCCFLAGS_PROGS ?= +FTEQCCFLAGS_MENU ?= # NOTE: use -DUSE_FTE instead of -TFTE here! # It will automagically add an engine check with -TID and then change back to -TFTE @@ -35,122 +34,28 @@ qc-recursive: menu.dat progs.dat csprogs.dat .PHONY: skin skin: gfx/menu/default/skinvalues.txt -.PHONY: pk3 -pk3: $(PK3NAME) - -.PHONY: pk3here -pk3here: qc - $(RM) $(PK3NAME); \ - set -ex; \ - ABSPK3NAME=$(PK3NAME); \ - case $$ABSPK3NAME in \ - /*) \ - ;; \ - *) \ - ABSPK3NAME=$$PWD/$$ABSPK3NAME; \ - ;; \ - esac; \ - $(ZIP) $(ZIPEXCLUDE) $$ABSPK3NAME . - .PHONY: clean clean: rm -f progs.dat menu.dat csprogs.dat -csprogs.dat: qcsrc/client/*.* qcsrc/common/*.* qcsrc/warpzonelib/*.* +FILES_CSPROGS = qcsrc/client/progs.src $(shell sed '/\.dat/d; s,//.*,,; s,[^ ],qcsrc/client/&,' < qcsrc/client/progs.src) +csprogs.dat: $(FILES_CSPROGS) @echo make[1]: Entering directory \`$(PWD)/qcsrc/client\' cd qcsrc/client && $(FTEQCC) $(FTEQCCFLAGS) $(FTEQCCFLAGS_CSPROGS) -progs.dat: qcsrc/server/*.* qcsrc/common/*.* qcsrc/server/*/*.* qcsrc/server/*/*/*.* qcsrc/warpzonelib/*.* +FILES_PROGS = qcsrc/server/progs.src $(shell sed '/\.dat/d; s,//.*,,; s,[^ ],qcsrc/server/&,' < qcsrc/server/progs.src) +progs.dat: $(FILES_PROGS) @echo make[1]: Entering directory \`$(PWD)/qcsrc/server\' cd qcsrc/server && $(FTEQCC) $(FTEQCCFLAGS) $(FTEQCCFLAGS_PROGS) -menu.dat: qcsrc/menu/*.* qcsrc/menu/*/*.* qcsrc/common/*.* +FILES_MENU = qcsrc/menu/progs.src $(shell sed '/\.dat/d; s,//.*,,; s,[^ ],qcsrc/menu/&,' < qcsrc/menu/progs.src) +menu.dat: $(FILES_MENU) @echo make[1]: Entering directory \`$(PWD)/qcsrc/menu\' cd qcsrc/menu && $(FTEQCC) $(FTEQCCFLAGS) $(FTEQCCFLAGS_MENU) gfx/menu/default/skinvalues.txt: qcsrc/menu/skin-customizables.inc $(PERL) qcsrc/menu/skin-customizables.inc > gfx/menu/default/skinvalues.txt -$(PK3NAME): qc - $(RM) $(PK3NAME) - set -ex; \ - ABSPK3NAME=$(PK3NAME); \ - case $$ABSPK3NAME in \ - /*) \ - ;; \ - *) \ - ABSPK3NAME=$$PWD/$$ABSPK3NAME; \ - ;; \ - esac; \ - TDIR=`mktemp -d -t xonoticpk3.XXXXXX`; \ - cp -v progs.dat csprogs.dat menu.dat $$TDIR/; \ - svn export --force . $$TDIR; \ - cd $$TDIR; \ - $(ZIP) $$ABSPK3NAME . - .PHONY: testcase testcase: cd qcsrc/testcase && $(FTEQCC) $(FTEQCCFLAGS) $(FTEQCCFLAGS_CSPROGS) -DTESTCASE="$$TESTCASE" - -.PHONY: update commit diff log logv logupdate logvupdate revert -update: $(SCM)-update -commit: $(SCM)-commit -diff: $(SCM)-diff -log: $(SCM)-log -logv: $(SCM)-logv -revert: $(SCM)-revert -logupdate: log update -logvupdate: logv update - -.PHONY: svn-update -svn-update: - cd .. && svn update - -.PHONY: svn-commit -svn-commit: - cd .. && svn commit - -.PHONY: svn-diff -svn-diff: - cd .. && svn diff - -.PHONY: svn-log -svn-log: - cd .. && svn log -r HEAD:BASE - -.PHONY: svn-logv -svn-logv: - cd .. && svn log -r HEAD:BASE -v - -.PHONY: svn-revert -svn-revert: - svn revert -- $(FILE) - -.PHONY: git-update -git-update: - git pull origin - -.PHONY: git-commit -git-commit: - git commit -a || true - if echo -n 'Also send to server? Hit Enter for yes, ^C for no. '; read -r L; then \ - git config svn-remote.svn.url svn://svn.icculus.org/xonotic; \ - git config svn-remote.svn.fetch trunk:refs/remotes/origin/master; \ - git svn dcommit; \ - fi - -.PHONY: git-diff -git-diff: - git diff; git diff origin/master..HEAD; true - -.PHONY: git-log -git-log: - git fetch && git log HEAD..origin/master - -.PHONY: git-logv -git-logv: - git fetch && git log -v HEAD..origin/master - -.PHONY: git-revert -git-revert: - git checkout -- $(FILE) diff --git a/_hud_descriptions.cfg b/_hud_descriptions.cfg index 09860bbfa..ddcd45a36 100644 --- a/_hud_descriptions.cfg +++ b/_hud_descriptions.cfg @@ -28,6 +28,8 @@ seta hud_configure_grid "" "snap to grid when moving/resizing panels" seta hud_configure_grid_xsize "" "snap to X * vid_conwidth" seta hud_configure_grid_ysize "" "snap to Y * vid_conheight" +seta scr_centerpos "" "Y position of the centerprint" + seta hud_panel_weapons "" "enable/disable this panel" seta hud_panel_weapons_pos "" "position of this panel" seta hud_panel_weapons_size "" "size of this panel" diff --git a/balance25.cfg b/balance25.cfg index 0250978c3..8fb2e008a 100644 --- a/balance25.cfg +++ b/balance25.cfg @@ -3,6 +3,7 @@ set g_start_weapon_laser -1 "0 = never provide the weapon, 1 = always provide th set g_start_weapon_shotgun -1 "0 = never provide the weapon, 1 = always provide the weapon, -1 = game mode default, -2 = provide the weapon in ca and lms" set g_start_weapon_uzi -1 "0 = never provide the weapon, 1 = always provide the weapon, -1 = game mode default, -2 = provide the weapon in ca and lms" set g_start_weapon_grenadelauncher -1 "0 = never provide the weapon, 1 = always provide the weapon, -1 = game mode default, -2 = provide the weapon in ca and lms" +set g_start_weapon_minelayer -1 "0 = never provide the weapon, 1 = always provide the weapon, -1 = game mode default, -2 = provide the weapon in ca and lms" set g_start_weapon_electro -1 "0 = never provide the weapon, 1 = always provide the weapon, -1 = game mode default, -2 = provide the weapon in ca and lms" set g_start_weapon_crylink -1 "0 = never provide the weapon, 1 = always provide the weapon, -1 = game mode default, -2 = provide the weapon in ca and lms" set g_start_weapon_nex -1 "0 = never provide the weapon, 1 = always provide the weapon, -1 = game mode default, -2 = provide the weapon in ca and lms" @@ -55,14 +56,19 @@ set g_balance_nix_ammoincr_fuel 2 set g_pickup_ammo_anyway 0 set g_pickup_weapons_anyway 0 set g_pickup_shells 15 +set g_pickup_shells_weapon 15 set g_pickup_shells_max 999 set g_pickup_nails 80 +set g_pickup_nails_weapon 80 set g_pickup_nails_max 999 set g_pickup_rockets 15 +set g_pickup_rockets_weapon 15 set g_pickup_rockets_max 999 set g_pickup_cells 25 +set g_pickup_cells_weapon 25 set g_pickup_cells_max 999 set g_pickup_fuel 25 +set g_pickup_fuel_weapon 25 set g_pickup_fuel_jetpack 50 set g_pickup_fuel_max 999 set g_pickup_armorsmall 5 @@ -268,8 +274,7 @@ set g_balance_uzi_speed 18000 set g_balance_uzi_bulletconstant 115 // 13.1qu // }}} // {{{ mortar -set g_balance_grenadelauncher_primary2secondary 0 -set g_balance_grenadelauncher_primary_sticky 0 +set g_balance_grenadelauncher_primary_type 0 set g_balance_grenadelauncher_primary_damage 70 set g_balance_grenadelauncher_primary_edgedamage 38 set g_balance_grenadelauncher_primary_force 400 @@ -284,7 +289,12 @@ set g_balance_grenadelauncher_primary_refire 0.8 set g_balance_grenadelauncher_primary_animtime 0.3 set g_balance_grenadelauncher_primary_ammo 2 set g_balance_grenadelauncher_primary_health 25 -set g_balance_grenadelauncher_secondary_sticky 0 +set g_balance_grenadelauncher_primary_damageforcescale 4 +set g_balance_grenadelauncher_primary_bouncefactor 0.5 +set g_balance_grenadelauncher_primary_bouncestop 0.075 +set g_balance_grenadelauncher_primary_remote_minbouncecnt 0 + +set g_balance_grenadelauncher_secondary_type 1 set g_balance_grenadelauncher_secondary_damage 70 set g_balance_grenadelauncher_secondary_edgedamage 38 set g_balance_grenadelauncher_secondary_force 400 @@ -302,6 +312,29 @@ set g_balance_grenadelauncher_secondary_health 10 set g_balance_grenadelauncher_secondary_damageforcescale 4 set g_balance_grenadelauncher_secondary_bouncefactor 0.5 set g_balance_grenadelauncher_secondary_bouncestop 0.075 +set g_balance_grenadelauncher_secondary_remote_detonateprimary 0 +// }}} +// {{{ minelayer // TODO +set g_balance_minelayer_damage 35 +set g_balance_minelayer_edgedamage 30 +set g_balance_minelayer_force 250 +set g_balance_minelayer_radius 175 +set g_balance_minelayer_proximityradius 150 +set g_balance_minelayer_speed 750 +set g_balance_minelayer_lifetime 60 +set g_balance_minelayer_refire 1.5 +set g_balance_minelayer_animtime 0.4 +set g_balance_minelayer_ammo 5 +set g_balance_minelayer_health 15 +set g_balance_minelayer_limit 4 // 0 disables the limit +set g_balance_minelayer_protection 1 // don't explode if the mine would hurt the owner or a team mate +set g_balance_minelayer_damageforcescale 0 +set g_balance_minelayer_detonatedelay -1 // positive: timer till detonation is allowed, negative: "security device" that prevents ANY remote detonation if it could hurt its owner, zero: detonatable at any time +set g_balance_minelayer_time 0.5 +set g_balance_minelayer_remote_damage 45 +set g_balance_minelayer_remote_edgedamage 40 +set g_balance_minelayer_remote_radius 200 +set g_balance_minelayer_remote_force 300 // }}} // {{{ electro set g_balance_electro_lightning 0 @@ -318,8 +351,10 @@ set g_balance_electro_primary_refire 0.6 set g_balance_electro_primary_animtime 0.3 set g_balance_electro_primary_ammo 2 set g_balance_electro_primary_range 0 +set g_balance_electro_primary_falloff_mindist 255 // 0.3 * radius +set g_balance_electro_primary_falloff_maxdist 850 +set g_balance_electro_primary_falloff_halflifedist 425 set g_balance_electro_secondary_damage 50 -set g_balance_electro_secondary_spread 0.05 set g_balance_electro_secondary_edgedamage 0 set g_balance_electro_secondary_force 200 set g_balance_electro_secondary_radius 150 @@ -394,6 +429,8 @@ set g_balance_nex_primary_damagefalloff_halflife 0 set g_balance_nex_primary_damagefalloff_forcehalflife 0 set g_balance_nex_secondary 0 +set g_balance_nex_secondary_charge 0 +set g_balance_nex_secondary_charge_rate 0.1 set g_balance_nex_secondary_damage 100 set g_balance_nex_secondary_force 600 set g_balance_nex_secondary_refire 1.5 @@ -403,6 +440,15 @@ set g_balance_nex_secondary_damagefalloff_mindist 0 set g_balance_nex_secondary_damagefalloff_maxdist 0 set g_balance_nex_secondary_damagefalloff_halflife 0 set g_balance_nex_secondary_damagefalloff_forcehalflife 0 + +set g_balance_nex_charge 0 +set g_balance_nex_charge_start 0 +set g_balance_nex_charge_rate 0.1 +set g_balance_nex_charge_limit 0.5 +set g_balance_nex_charge_shot_multiplier 0.5 +set g_balance_nex_charge_velocity_rate 0.2 +set g_balance_nex_charge_minspeed 400 +set g_balance_nex_charge_maxspeed 1000 // }}} // {{{ minstanex set g_balance_minstanex_refire 1 @@ -527,7 +573,7 @@ set g_balance_campingrifle_magazinecapacity 8 set g_balance_campingrifle_reloadtime 2 // matches reload anim set g_balance_campingrifle_auto_reload_after_changing_weapons 0 set g_balance_campingrifle_bursttime 0 -set g_balance_campingrifle_tracer 0 +set g_balance_campingrifle_primary_tracer 0 set g_balance_campingrifle_primary_damage 60 set g_balance_campingrifle_primary_headshotaddeddamage 100 set g_balance_campingrifle_primary_spread 0 @@ -541,6 +587,7 @@ set g_balance_campingrifle_primary_bulletconstant 130 // 56.3qu set g_balance_campingrifle_primary_burstcost 0 set g_balance_campingrifle_primary_bullethail 0 // empty magazine on shot set g_balance_campingrifle_secondary 1 +set g_balance_campingrifle_secondary_tracer 0 set g_balance_campingrifle_secondary_damage 35 set g_balance_campingrifle_secondary_headshotaddeddamage 15 // 50 damage only on head set g_balance_campingrifle_secondary_spread 0.008 diff --git a/balanceLeeStricklin.cfg b/balanceLeeStricklin.cfg new file mode 100644 index 000000000..eaff81828 --- /dev/null +++ b/balanceLeeStricklin.cfg @@ -0,0 +1,714 @@ +////2.4.2 weapons (with some tweaks) VS balanceLeeStricklin + +// {{{ weapon replacement +// NOTE: this only replaces weapons on the map +// use g_start_weapon_* to also replace the on-startup weapons! +// example: g_weaponreplace_nex "nex minstanex", then Nexes become MinstaNexes 50% of the times +// set the cvars to "0" to totally disable a weapon +set sv_q3acompat_machineshotgunswap 0 "shorthand for swapping uzi and shotgun" +// }}} + +// {{{ starting gear +set g_start_weapon_laser -1 "0 = never provide the weapon, 1 = always provide the weapon, -1 = game mode default, -2 = provide the weapon in ca and lms" +set g_start_weapon_shotgun -1 "0 = never provide the weapon, 1 = always provide the weapon, -1 = game mode default, -2 = provide the weapon in ca and lms" +set g_start_weapon_uzi -1 "0 = never provide the weapon, 1 = always provide the weapon, -1 = game mode default, -2 = provide the weapon in ca and lms" +set g_start_weapon_grenadelauncher -1 "0 = never provide the weapon, 1 = always provide the weapon, -1 = game mode default, -2 = provide the weapon in ca and lms" +set g_start_weapon_minelayer -1 "0 = never provide the weapon, 1 = always provide the weapon, -1 = game mode default, -2 = provide the weapon in ca and lms" +set g_start_weapon_electro -1 "0 = never provide the weapon, 1 = always provide the weapon, -1 = game mode default, -2 = provide the weapon in ca and lms" +set g_start_weapon_crylink -1 "0 = never provide the weapon, 1 = always provide the weapon, -1 = game mode default, -2 = provide the weapon in ca and lms" +set g_start_weapon_nex -1 "0 = never provide the weapon, 1 = always provide the weapon, -1 = game mode default, -2 = provide the weapon in ca and lms" +set g_start_weapon_hagar -1 "0 = never provide the weapon, 1 = always provide the weapon, -1 = game mode default, -2 = provide the weapon in ca and lms" +set g_start_weapon_rocketlauncher -1 "0 = never provide the weapon, 1 = always provide the weapon, -1 = game mode default, -2 = provide the weapon in ca and lms" +set g_start_weapon_minstanex -1 "0 = never provide the weapon, 1 = always provide the weapon, -1 = game mode default, -2 = provide the weapon in ca and lms" +set g_start_weapon_porto -1 "0 = never provide the weapon, 1 = always provide the weapon, -1 = game mode default, -2 = provide the weapon in ca and lms" +set g_start_weapon_hook -1 "0 = never provide the weapon, 1 = always provide the weapon, -1 = game mode default, -2 = provide the weapon in ca and lms" +set g_start_weapon_hlac 0 "0 = never provide the weapon, 1 = always provide the weapon, -1 = game mode default, -2 = provide the weapon in ca and lms" +set g_start_weapon_campingrifle -1 "0 = never provide the weapon, 1 = always provide the weapon, -1 = game mode default, -2 = provide the weapon in ca and lms" +set g_start_weapon_tuba -1 "0 = never provide the weapon, 1 = always provide the weapon, -1 = game mode default, -2 = provide the weapon in ca and lms" +set g_start_weapon_fireball 0 "0 = never provide the weapon, 1 = always provide the weapon, -1 = game mode default, -2 = provide the weapon in ca and lms" +set g_start_weapon_seeker -1 "0 = never provide the weapon, 1 = always provide the weapon, -1 = game mode default, -2 = provide the weapon in ca and lms" +set g_balance_health_start 200 +set g_balance_armor_start 115 +set g_start_ammo_shells 45 +set g_start_ammo_nails 0 +set g_start_ammo_rockets 0 +set g_start_ammo_cells 0 +set g_start_ammo_fuel 0 +set g_warmup_start_health 200 "starting values when being in warmup-stage" +set g_warmup_start_armor 100 "starting values when being in warmup-stage" +set g_warmup_start_ammo_shells 50 "starting values when being in warmup-stage" +set g_warmup_start_ammo_nails 150 "starting values when being in warmup-stage" +set g_warmup_start_ammo_rockets 50 "starting values when being in warmup-stage" +set g_warmup_start_ammo_cells 50 "starting values when being in warmup-stage" +set g_warmup_start_ammo_fuel 0 "starting values when being in warmup-stage" +set g_lms_start_health 200 +set g_lms_start_armor 100 +set g_lms_start_ammo_shells 50 +set g_lms_start_ammo_nails 150 +set g_lms_start_ammo_rockets 50 +set g_lms_start_ammo_cells 50 +set g_lms_start_ammo_fuel 0 +set g_balance_nix_roundtime 25 +set g_balance_nix_incrtime 1.6 +set g_balance_nix_ammo_shells 15 +set g_balance_nix_ammo_nails 45 +set g_balance_nix_ammo_rockets 15 +set g_balance_nix_ammo_cells 15 +set g_balance_nix_ammo_fuel 0 +set g_balance_nix_ammoincr_shells 2 +set g_balance_nix_ammoincr_nails 6 +set g_balance_nix_ammoincr_rockets 2 +set g_balance_nix_ammoincr_cells 2 +set g_balance_nix_ammoincr_fuel 2 +// }}} + +// {{{ pickup items +// Ammo caps copied from balanceFruit +set g_pickup_ammo_anyway 0 +set g_pickup_weapons_anyway 1 +set g_pickup_shells 20 +set g_pickup_shells_weapon 20 +set g_pickup_shells_max 45 +set g_pickup_nails 120 +set g_pickup_nails_weapon 120 +set g_pickup_nails_max 300 +set g_pickup_rockets 25 +set g_pickup_rockets_weapon 25 +set g_pickup_rockets_max 150 +set g_pickup_cells 25 +set g_pickup_cells_weapon 25 +set g_pickup_cells_max 200 +set g_pickup_fuel 25 +set g_pickup_fuel_weapon 25 +set g_pickup_fuel_jetpack 50 +set g_pickup_fuel_max 999 +set g_pickup_armorsmall 10 +set g_pickup_armorsmall_max 250 +set g_pickup_armorsmall_anyway 1 +set g_pickup_armormedium 25 +set g_pickup_armormedium_max 250 +set g_pickup_armormedium_anyway 0 +set g_pickup_armorbig 50 +set g_pickup_armorbig_max 250 +set g_pickup_armorbig_anyway 0 +set g_pickup_armorlarge 100 +set g_pickup_armorlarge_max 250 +set g_pickup_armorlarge_anyway 0 +set g_pickup_healthsmall 10 +set g_pickup_healthsmall_max 300 +set g_pickup_healthsmall_anyway 1 +set g_pickup_healthmedium 25 +set g_pickup_healthmedium_max 300 +set g_pickup_healthmedium_anyway 0 +set g_pickup_healthlarge 50 +set g_pickup_healthlarge_max 300 +set g_pickup_healthlarge_anyway 0 +set g_pickup_healthmega 100 +set g_pickup_healthmega_max 300 +set g_pickup_healthmega_anyway 1 +set g_pickup_respawntime_short 15 +set g_pickup_respawntime_medium 20 +set g_pickup_respawntime_long 30 +set g_pickup_respawntime_powerup 120 +set g_pickup_respawntime_weapon 15 +set g_pickup_respawntime_ammo 15 +set g_pickup_respawntimejitter_short 0 +set g_pickup_respawntimejitter_medium 0 +set g_pickup_respawntimejitter_long 0 +set g_pickup_respawntimejitter_powerup 10 +set g_pickup_respawntimejitter_weapon 0 +set g_pickup_respawntimejitter_ammo 0 +// }}} + +// {{{ regen/rot +set g_balance_health_regen 0 +set g_balance_health_regenlinear 5 +set g_balance_pause_health_regen 5 +set g_balance_pause_health_regen_spawn 0 +set g_balance_health_rot 0 +set g_balance_health_rotlinear 5 +set g_balance_pause_health_rot 3 +set g_balance_pause_health_rot_spawn 1 +set g_balance_health_regenstable 100 +set g_balance_health_rotstable 100 +set g_balance_health_limit 300 +set g_balance_armor_regen 0 +set g_balance_armor_regenlinear 0 +set g_balance_armor_rot 0 +set g_balance_armor_rotlinear 4.86 +set g_balance_pause_armor_rot 1 +set g_balance_pause_armor_rot_spawn 1 +set g_balance_armor_regenstable 100 +set g_balance_armor_rotstable 200 +set g_balance_armor_limit 250 +set g_balance_armor_blockpercent 0.6 +set g_balance_fuel_regen 0.1 "fuel regeneration (only applies if the player owns IT_FUEL_REGEN)" +set g_balance_fuel_regenlinear 0 +set g_balance_pause_fuel_regen 2 // other than this, fuel uses the health regen counter +set g_balance_fuel_rot 0.05 +set g_balance_fuel_rotlinear 0 +set g_balance_pause_fuel_rot 5 +set g_balance_pause_fuel_rot_spawn 10 +set g_balance_fuel_regenstable 100 +set g_balance_fuel_rotstable 999 +set g_balance_fuel_limit 999 +// }}} + +// {{{ misc +set g_balance_selfdamagepercent 0.6 +set g_balance_weaponswitchdelay 0.15 +set g_weaponspeedfactor 1 "weapon projectile speed multiplier" +set g_weaponratefactor 1 "weapon fire rate multiplier" +set g_weapondamagefactor 1 "weapon damage multiplier" +set g_weaponforcefactor 1 "weapon force multiplier" +set g_weaponspreadfactor 1 "weapon spread multiplier" +set g_balance_firetransfer_time 0.9 +set g_balance_firetransfer_damage 0.8 +set g_throughfloor_damage 0.4 +set g_throughfloor_force 0.7 +set g_projectiles_newton_style 2 +// possible values: +// 0: absolute velocity projectiles (like Quake) +// 1: relative velocity projectiles, "Newtonian" (like Tribes 2) +// 2: relative velocity projectiles, but aim is precorrected so projectiles hit the crosshair (note: strafe rockets then are SLOWER than ones shot while standing, happens in 1 too when aiming correctly which is hard) +// 3: absolute velocity + player velocity component in shot direction (note: does NOT yield the right relative velocity, but may be good enough, but it is somewhat prone to sniper rockets) +// 4: just add the player velocity length to the absolute velocity (tZork's sniper rockets) +set g_projectiles_newton_style_2_minfactor 0.8 +set g_projectiles_newton_style_2_maxfactor 1.5 +set g_projectiles_spread_style 0 +// possible values: +// 0: forward + solid sphere (like Quake) - varies velocity +// 1: forward + flattened solid sphere +// 2: forward + solid circle +// 3: forward + normal distribution 3D - varies velocity +// 4: forward + normal distribution on a plane +// 5: forward + circle with 1-r falloff +// 6: forward + circle with 1-r^2 falloff +// 7: forward + circle with (1-r)(2-r) falloff +set g_balance_falldamage_deadminspeed 150 +set g_balance_falldamage_minspeed 1400 +set g_balance_falldamage_factor 0.15 +set g_balance_falldamage_maxdamage 25 +// }}} + +// {{{ powerups +set g_balance_powerup_invincible_takedamage 0.2 +set g_balance_powerup_invincible_time 30 +set g_balance_powerup_strength_damage 3 +set g_balance_powerup_strength_force 3 +set g_balance_powerup_strength_time 30 +set g_balance_powerup_strength_selfdamage 1.5 +set g_balance_powerup_strength_selfforce 1.5 +// }}} + +// {{{ jetpack/hook +set g_jetpack_antigravity 0.8 "factor of gravity compensation of the jetpack" +set g_jetpack_acceleration_side 1200 "acceleration of the jetpack in xy direction" +set g_jetpack_acceleration_up 600 "acceleration of the jetpack in z direction (note: you have to factor in gravity here, if antigravity is not 1)" +set g_jetpack_maxspeed_side 1200 "max speed of the jetpack in xy direction" +set g_jetpack_maxspeed_up 600 "max speed of the jetpack in z direction" +set g_jetpack_fuel 8 "fuel per second for jetpack" +set g_jetpack_attenuation 2 "jetpack sound attenuation" + +set g_grappling_hook_tarzan 2 // 2: can also pull players +set g_balance_grapplehook_speed_fly 1800 +set g_balance_grapplehook_speed_pull 2000 +set g_balance_grapplehook_force_rubber 2000 +set g_balance_grapplehook_force_rubber_overstretch 1000 +set g_balance_grapplehook_length_min 50 +set g_balance_grapplehook_stretch 50 +set g_balance_grapplehook_airfriction 0.2 +set g_balance_grapplehook_health 130 +// }}} + +// {{{ weapon properties +// {{{ laser +set g_balance_laser_primary_damage 25 +set g_balance_laser_primary_edgedamage 10 +set g_balance_laser_primary_force 258 +set g_balance_laser_primary_radius 70 +set g_balance_laser_primary_speed 12000 +set g_balance_laser_primary_spread 0 +set g_balance_laser_primary_refire 0.7 +set g_balance_laser_primary_animtime 0.3 +set g_balance_laser_primary_lifetime 30 +set g_balance_laser_primary_shotangle 0 +set g_balance_laser_primary_delay 0.03 +set g_balance_laser_primary_gauntlet 0 +set g_balance_laser_secondary 0 // when 1, a secondary laser mode exists +set g_balance_laser_secondary_damage 25 +set g_balance_laser_secondary_edgedamage 10 +set g_balance_laser_secondary_force 375 +set g_balance_laser_secondary_radius 70 +set g_balance_laser_secondary_speed 12000 +set g_balance_laser_secondary_spread 0 +set g_balance_laser_secondary_refire 0.7 +set g_balance_laser_secondary_animtime 0.3 +set g_balance_laser_secondary_lifetime 30 +set g_balance_laser_secondary_shotangle -90 +set g_balance_laser_secondary_delay 0 +set g_balance_laser_secondary_gauntlet 0 +// }}} +// {{{ shotgun +set g_balance_shotgun_primary_bullets 5 +set g_balance_shotgun_primary_damage 12 +set g_balance_shotgun_primary_force 40 +set g_balance_shotgun_primary_spread 0.08 +set g_balance_shotgun_primary_refire 0.5 +set g_balance_shotgun_primary_animtime 0.2 +set g_balance_shotgun_primary_ammo 1 +set g_balance_shotgun_primary_speed 12000 +set g_balance_shotgun_primary_bulletconstant 75 // 3.8qu +set g_balance_shotgun_secondary 1 +set g_balance_shotgun_secondary_melee_delay 0.35 // match the anim +set g_balance_shotgun_secondary_melee_range 85 +set g_balance_shotgun_secondary_melee_swing 50 +set g_balance_shotgun_secondary_melee_time 0.1 +set g_balance_shotgun_secondary_damage 84 +set g_balance_shotgun_secondary_force 147 +set g_balance_shotgun_secondary_refire 1.1 +set g_balance_shotgun_secondary_animtime 1 +// }}} +// {{{ uzi +set g_balance_uzi_first 1 +set g_balance_uzi_first_damage 26 +set g_balance_uzi_first_force -30 +set g_balance_uzi_first_spread 0.01 +set g_balance_uzi_first_refire 0.2 +set g_balance_uzi_first_ammo 1 +set g_balance_uzi_sustained_damage 17 +set g_balance_uzi_sustained_force 27 +set g_balance_uzi_sustained_spread 0.05 +set g_balance_uzi_sustained_refire 0.1 +set g_balance_uzi_sustained_ammo 1 +set g_balance_uzi_speed 18000 +set g_balance_uzi_bulletconstant 300 // 13.1qu +// }}} +// {{{ mortar +set g_balance_grenadelauncher_primary_type 0 +set g_balance_grenadelauncher_primary_damage 65 +set g_balance_grenadelauncher_primary_edgedamage 35 +set g_balance_grenadelauncher_primary_force 310 +set g_balance_grenadelauncher_primary_radius 140 +set g_balance_grenadelauncher_primary_speed 2000 +set g_balance_grenadelauncher_primary_speed_up 200 +set g_balance_grenadelauncher_primary_speed_z 0 +set g_balance_grenadelauncher_primary_spread 0 +set g_balance_grenadelauncher_primary_lifetime 30 +set g_balance_grenadelauncher_primary_lifetime2 0.65 +set g_balance_grenadelauncher_primary_refire 0.7 +set g_balance_grenadelauncher_primary_animtime 0.3 +set g_balance_grenadelauncher_primary_ammo 2 +set g_balance_grenadelauncher_primary_health 72 +set g_balance_grenadelauncher_primary_damageforcescale 0 +set g_balance_grenadelauncher_primary_bouncefactor 0.7 +set g_balance_grenadelauncher_primary_bouncestop 0.12 +set g_balance_grenadelauncher_primary_remote_minbouncecnt 0 + +set g_balance_grenadelauncher_secondary_type 1 +set g_balance_grenadelauncher_secondary_damage 65 +set g_balance_grenadelauncher_secondary_edgedamage 35 +set g_balance_grenadelauncher_secondary_force 320 +set g_balance_grenadelauncher_secondary_radius 140 +set g_balance_grenadelauncher_secondary_speed 1400 +set g_balance_grenadelauncher_secondary_speed_up 200 +set g_balance_grenadelauncher_secondary_speed_z 0 +set g_balance_grenadelauncher_secondary_spread 0 +set g_balance_grenadelauncher_secondary_lifetime 2.5 +set g_balance_grenadelauncher_secondary_lifetime2 1 +set g_balance_grenadelauncher_secondary_refire 0.6 +set g_balance_grenadelauncher_secondary_animtime 0.3 +set g_balance_grenadelauncher_secondary_ammo 2 +set g_balance_grenadelauncher_secondary_health 40 +set g_balance_grenadelauncher_secondary_damageforcescale 0 +set g_balance_grenadelauncher_secondary_bouncefactor 0.7 +set g_balance_grenadelauncher_secondary_bouncestop 0.12 +set g_balance_grenadelauncher_secondary_remote_detonateprimary 0 +// }}} +// {{{ minelayer // TODO +set g_balance_minelayer_damage 35 +set g_balance_minelayer_edgedamage 30 +set g_balance_minelayer_force 250 +set g_balance_minelayer_radius 175 +set g_balance_minelayer_proximityradius 150 +set g_balance_minelayer_speed 750 +set g_balance_minelayer_lifetime 60 +set g_balance_minelayer_refire 1.5 +set g_balance_minelayer_animtime 0.4 +set g_balance_minelayer_ammo 5 +set g_balance_minelayer_health 15 +set g_balance_minelayer_limit 4 // 0 disables the limit +set g_balance_minelayer_protection 1 // don't explode if the mine would hurt the owner or a team mate +set g_balance_minelayer_damageforcescale 0 +set g_balance_minelayer_detonatedelay -1 // positive: timer till detonation is allowed, negative: "security device" that prevents ANY remote detonation if it could hurt its owner, zero: detonatable at any time +set g_balance_minelayer_time 0.5 +set g_balance_minelayer_remote_damage 45 +set g_balance_minelayer_remote_edgedamage 40 +set g_balance_minelayer_remote_radius 200 +set g_balance_minelayer_remote_force 300 +// }}} +// {{{ electro +set g_balance_electro_lightning 0 +set g_balance_electro_primary_damage 55 +set g_balance_electro_primary_edgedamage 5 +set g_balance_electro_primary_force 267 +set g_balance_electro_primary_force_up 125 +set g_balance_electro_primary_radius 150 +set g_balance_electro_primary_comboradius 75 +set g_balance_electro_primary_speed 2000 +set g_balance_electro_primary_spread 0 +set g_balance_electro_primary_lifetime 30 +set g_balance_electro_primary_refire 0.78 +set g_balance_electro_primary_animtime 0.4 +set g_balance_electro_primary_ammo 2 +set g_balance_electro_primary_range 800 +set g_balance_electro_primary_falloff_mindist 255 +set g_balance_electro_primary_falloff_maxdist 850 +set g_balance_electro_primary_falloff_halflifedist 0 +set g_balance_electro_secondary_damage 60 +set g_balance_electro_secondary_edgedamage 0 +set g_balance_electro_secondary_force 200 +set g_balance_electro_secondary_radius 150 +set g_balance_electro_secondary_speed 900 +set g_balance_electro_secondary_speed_up 200 +set g_balance_electro_secondary_speed_z 0 +set g_balance_electro_secondary_lifetime 3 +set g_balance_electro_secondary_spread 0.05 +set g_balance_electro_secondary_refire 0.2 +set g_balance_electro_secondary_refire2 1 +set g_balance_electro_secondary_animtime 0.3 +set g_balance_electro_secondary_ammo 2 +set g_balance_electro_secondary_health 10 +set g_balance_electro_secondary_damageforcescale 4 +set g_balance_electro_secondary_count 3 +set g_balance_electro_combo_damage 70 +set g_balance_electro_combo_edgedamage 0 +set g_balance_electro_combo_force 200 +set g_balance_electro_combo_radius 250 +set g_balance_electro_combo_comboradius 70 +set g_balance_electro_combo_speed 400 +// }}} +// {{{ crylink +set g_balance_crylink_primary_damage 23 +set g_balance_crylink_primary_edgedamage 0 +set g_balance_crylink_primary_force -55 +set g_balance_crylink_primary_radius 80 +set g_balance_crylink_primary_speed 6950 +set g_balance_crylink_primary_spread 0.03 +set g_balance_crylink_primary_shots 4 +set g_balance_crylink_primary_bounces 2 +set g_balance_crylink_primary_refire 0.4 +set g_balance_crylink_primary_animtime 0.30008 +set g_balance_crylink_primary_ammo 3 +set g_balance_crylink_primary_bouncedamagefactor 0.2 + +set g_balance_crylink_primary_middle_lifetime 5 // range: 10000 full, fades to 20000 +set g_balance_crylink_primary_middle_fadetime 5 +set g_balance_crylink_primary_star_lifetime 2 // range: 800 full, fades to 1300 +set g_balance_crylink_primary_star_fadetime 0.25 +set g_balance_crylink_primary_other_lifetime 2 // range: 800 full, fades to 1300 +set g_balance_crylink_primary_other_fadetime 0.25 + +set g_balance_crylink_secondary 1 +set g_balance_crylink_secondary_damage 19 +set g_balance_crylink_secondary_edgedamage 0 +set g_balance_crylink_secondary_force -55 +set g_balance_crylink_secondary_radius 3 +set g_balance_crylink_secondary_speed 6950 +set g_balance_crylink_secondary_spread 0.08 +set g_balance_crylink_secondary_shots 7 +set g_balance_crylink_secondary_bounces 0 +set g_balance_crylink_secondary_refire 0.5 +set g_balance_crylink_secondary_animtime 0.3 +set g_balance_crylink_secondary_ammo 3 +set g_balance_crylink_secondary_bouncedamagefactor 0.5 + +set g_balance_crylink_secondary_middle_lifetime 5 // range: 10000 full, fades to 10000 +set g_balance_crylink_secondary_middle_fadetime 5 +set g_balance_crylink_secondary_line_lifetime 2 // range: 4000 full, fades to 8000 +set g_balance_crylink_secondary_line_fadetime 2 +// }}} +// {{{ nex +set g_balance_nex_primary_ammo 13 +set g_balance_nex_primary_animtime 0.3 +set g_balance_nex_primary_damage 78 +set g_balance_nex_primary_force 600 +set g_balance_nex_primary_refire 1.505 +set g_balance_nex_primary_damagefalloff_mindist 9999999 +set g_balance_nex_primary_damagefalloff_maxdist 9999999 +set g_balance_nex_primary_damagefalloff_halflife 9999999 +set g_balance_nex_primary_damagefalloff_forcehalflife 9999999 + +set g_balance_nex_secondary 0 +set g_balance_nex_secondary_charge 0 +set g_balance_nex_secondary_charge_rate 0.1 +set g_balance_nex_secondary_damage 80 +set g_balance_nex_secondary_force -500 +set g_balance_nex_secondary_refire 1.25 +set g_balance_nex_secondary_animtime 0.75 +set g_balance_nex_secondary_ammo 5 +set g_balance_nex_secondary_damagefalloff_mindist 9999999 +set g_balance_nex_secondary_damagefalloff_maxdist 9999999 +set g_balance_nex_secondary_damagefalloff_halflife 9999999 +set g_balance_nex_secondary_damagefalloff_forcehalflife 9999999 + +set g_balance_nex_charge 0 +set g_balance_nex_charge_start 0 +set g_balance_nex_charge_rate 0.1 +set g_balance_nex_charge_limit 0.5 +set g_balance_nex_charge_shot_multiplier 0.5 +set g_balance_nex_charge_velocity_rate 0.2 +set g_balance_nex_charge_minspeed 400 +set g_balance_nex_charge_maxspeed 1000 +// }}} +// {{{ minstanex +set g_balance_minstanex_refire 1 +set g_balance_minstanex_animtime 0.278 +set g_balance_minstanex_ammo 10 +// }}} +// {{{ hagar +set g_balance_hagar_primary_damage 43 +set g_balance_hagar_primary_edgedamage 15 +set g_balance_hagar_primary_force 94 +set g_balance_hagar_primary_radius 70 +set g_balance_hagar_primary_spread 0.010 +set g_balance_hagar_primary_speed 3000 +set g_balance_hagar_primary_lifetime 30 +set g_balance_hagar_primary_refire 0.15 +set g_balance_hagar_primary_ammo 2 +set g_balance_hagar_secondary 1 +set g_balance_hagar_secondary_damage 43 +set g_balance_hagar_secondary_edgedamage 15 +set g_balance_hagar_secondary_force 100 +set g_balance_hagar_secondary_radius 70 +set g_balance_hagar_secondary_spread 0.015 +set g_balance_hagar_secondary_speed 1400 +set g_balance_hagar_secondary_lifetime_min 5 +set g_balance_hagar_secondary_lifetime_rand 0 +set g_balance_hagar_secondary_refire 0.15 +set g_balance_hagar_secondary_ammo 2 +// }}} +// {{{ rocketlauncher +set g_balance_rocketlauncher_damage 65 +set g_balance_rocketlauncher_edgedamage 25 +set g_balance_rocketlauncher_force 360 +set g_balance_rocketlauncher_radius 185 +set g_balance_rocketlauncher_speed 900 +set g_balance_rocketlauncher_speedaccel 0 +set g_balance_rocketlauncher_speedstart 850 +set g_balance_rocketlauncher_lifetime 30 +set g_balance_rocketlauncher_refire 1 +set g_balance_rocketlauncher_animtime 0.3 +set g_balance_rocketlauncher_ammo 7 +set g_balance_rocketlauncher_health 40 +set g_balance_rocketlauncher_damageforcescale 4 +set g_balance_rocketlauncher_detonatedelay -1 // positive: timer till detonation is allowed, negative: "security device" that prevents ANY remote detonation if it could hurt its owner, zero: detonatable at any time +set g_balance_rocketlauncher_guiderate 65 // max degrees per second +set g_balance_rocketlauncher_guideratedelay 0.01 // immediate +set g_balance_rocketlauncher_guidegoal 512 // goal distance for (non-laser) guiding (higher = less control, lower = erratic) +set g_balance_rocketlauncher_guidedelay 0.15 // delay before guiding kicks in +set g_balance_rocketlauncher_guidestop 0 // stop guiding when firing again +set g_balance_rocketlauncher_laserguided_speed 1000 //650 +set g_balance_rocketlauncher_laserguided_speedaccel 0 +set g_balance_rocketlauncher_laserguided_speedstart 1000 +set g_balance_rocketlauncher_laserguided_turnrate 0.60 //0.5 +set g_balance_rocketlauncher_laserguided_allow_steal 1 +set g_balance_rocketlauncher_remote_damage 120 +set g_balance_rocketlauncher_remote_edgedamage 46 +set g_balance_rocketlauncher_remote_radius 185 +set g_balance_rocketlauncher_remote_force 590 +// }}} +// {{{ porto +set g_balance_porto_primary_refire 1.5 +set g_balance_porto_primary_animtime 0.3 +set g_balance_porto_primary_speed 5000 +set g_balance_porto_primary_lifetime 30 +set g_balance_portal_health 200 // these get recharged whenever the portal is used +set g_balance_portal_lifetime 15 // these get recharged whenever the portal is used +// }}} +// {{{ hook +set g_balance_hook_primary_fuel 2 // hook monkeys set 0 +set g_balance_hook_primary_refire 0 // hook monkeys set 0 +set g_balance_hook_primary_animtime 0.3 // good shoot anim +set g_balance_hook_primary_hooked_time_max 0 // infinite +set g_balance_hook_primary_hooked_time_free 2 // 2s being hooked are free +set g_balance_hook_primary_hooked_fuel 3 // fuel per second hooked +set g_balance_hook_secondary_damage 25 // not much +set g_balance_hook_secondary_edgedamage 5 // not much +set g_balance_hook_secondary_radius 500 // LOTS +set g_balance_hook_secondary_force -2000 // LOTS +set g_balance_hook_secondary_ammo 50 // a whole pack +set g_balance_hook_secondary_lifetime 30 // infinite +set g_balance_hook_secondary_speed 0 // not much throwing +set g_balance_hook_secondary_gravity 5 // fast falling +set g_balance_hook_secondary_refire 3 // don't drop too many bombs... +set g_balance_hook_secondary_animtime 0.3 // good shoot anim +set g_balance_hook_secondary_power 3 // effect behaves like a square function +set g_balance_hook_secondary_duration 1.5 // effect runs for three seconds +// }}} +// {{{ hlac +set g_balance_hlac_primary_spread_min 0.01 +set g_balance_hlac_primary_spread_max 0.25 +set g_balance_hlac_primary_spread_add 0.0045 +set g_balance_hlac_primary_spread_crouchmod 0.25 + +set g_balance_hlac_primary_damage 17 +set g_balance_hlac_primary_edgedamage 10 +set g_balance_hlac_primary_force 45 +set g_balance_hlac_primary_radius 70 +set g_balance_hlac_primary_speed 9000 +set g_balance_hlac_primary_lifetime 5 + +set g_balance_hlac_primary_refire 0.1 +set g_balance_hlac_primary_animtime 0.3 +set g_balance_hlac_primary_ammo 3 + +set g_balance_hlac_secondary 1 +set g_balance_hlac_secondary_spread 0.15 +set g_balance_hlac_secondary_spread_crouchmod 0.5 + +set g_balance_hlac_secondary_damage 18 +set g_balance_hlac_secondary_edgedamage 10 +set g_balance_hlac_secondary_force 100 +set g_balance_hlac_secondary_radius 70 +set g_balance_hlac_secondary_speed 9000 +set g_balance_hlac_secondary_lifetime 5 + +set g_balance_hlac_secondary_refire 1 +set g_balance_hlac_secondary_animtime 0.3 +set g_balance_hlac_secondary_ammo 11 +set g_balance_hlac_secondary_shots 6 +// }}} +// {{{ campingrifle +set g_balance_campingrifle_magazinecapacity 8 +set g_balance_campingrifle_reloadtime 2 // matches reload anim +set g_balance_campingrifle_auto_reload_after_changing_weapons 0 +set g_balance_campingrifle_bursttime 0.85 // 0.35 - 0.1 + 0.35 - 0.1 + 0.35 = three secondaries +set g_balance_campingrifle_primary_tracer 0 +set g_balance_campingrifle_primary_damage 75 +set g_balance_campingrifle_primary_headshotaddeddamage 90 +set g_balance_campingrifle_primary_spread 0 +set g_balance_campingrifle_primary_force 2 +set g_balance_campingrifle_primary_speed 35000 +set g_balance_campingrifle_primary_lifetime 5 +set g_balance_campingrifle_primary_refire 0.7 +set g_balance_campingrifle_primary_animtime 0.3 +set g_balance_campingrifle_primary_ammo 10 +set g_balance_campingrifle_primary_bulletconstant 130 // 56.3qu +set g_balance_campingrifle_primary_burstcost 0 // require same cooldown as secondary, note it's smaller than primary refire time +set g_balance_campingrifle_primary_bullethail 0 // empty magazine on shot +set g_balance_campingrifle_secondary 1 +set g_balance_campingrifle_secondary_tracer 0 +set g_balance_campingrifle_secondary_damage 40 +set g_balance_campingrifle_secondary_headshotaddeddamage 20 +set g_balance_campingrifle_secondary_spread 0.008 +set g_balance_campingrifle_secondary_force 1 +set g_balance_campingrifle_secondary_speed 20000 +set g_balance_campingrifle_secondary_lifetime 5 +set g_balance_campingrifle_secondary_refire 0.0006 +set g_balance_campingrifle_secondary_animtime 0.1 +set g_balance_campingrifle_secondary_ammo 10 +set g_balance_campingrifle_secondary_bulletconstant 130 // 18.3qu +set g_balance_campingrifle_secondary_burstcost 0 +set g_balance_campingrifle_secondary_bullethail 0 +// }}} +// {{{ tuba +set g_balance_tuba_refire 0.05 +set g_balance_tuba_animtime 0.05 +set g_balance_tuba_attenuation 0.5 +set g_balance_tuba_volume 1 +set g_balance_tuba_fadetime 0.25 +set g_balance_tuba_damage 5 +set g_balance_tuba_edgedamage 0 +set g_balance_tuba_radius 200 +set g_balance_tuba_force 40 +// }}} +// {{{ fireball +set g_balance_fireball_primary_ammo 5 +set g_balance_fireball_primary_animtime 0.3 +set g_balance_fireball_primary_bfgdamage 0 +set g_balance_fireball_primary_bfgforce 0 +set g_balance_fireball_primary_bfgradius 0 +set g_balance_fireball_primary_damage 40 +set g_balance_fireball_primary_damageforcescale 4 +set g_balance_fireball_primary_edgedamage 0 +set g_balance_fireball_primary_force 100 +set g_balance_fireball_primary_health 9999 +set g_balance_fireball_primary_laserburntime 0.5 +set g_balance_fireball_primary_laserdamage 30 +set g_balance_fireball_primary_laseredgedamage 20 +set g_balance_fireball_primary_laserradius 110 +set g_balance_fireball_primary_lifetime 7 +set g_balance_fireball_primary_radius 20 +set g_balance_fireball_primary_refire 2 +set g_balance_fireball_primary_refire2 1.5 +set g_balance_fireball_primary_speed 900 +set g_balance_fireball_primary_spread 0 +set g_balance_fireball_secondary_ammo 25 +set g_balance_fireball_secondary_animtime 0.15 +set g_balance_fireball_secondary_damage 150 +set g_balance_fireball_secondary_damageforcescale 4 +set g_balance_fireball_secondary_damagetime 3 +set g_balance_fireball_secondary_force 700 +set g_balance_fireball_secondary_laserburntime 0.5 +set g_balance_fireball_secondary_laserdamage 30 +set g_balance_fireball_secondary_laseredgedamage 20 +set g_balance_fireball_secondary_laserradius 256 +set g_balance_fireball_secondary_lifetime 15 +set g_balance_fireball_secondary_refire 0 +set g_balance_fireball_secondary_speed 650 +set g_balance_fireball_secondary_speed_up 0 +set g_balance_fireball_secondary_speed_z 0 +set g_balance_fireball_secondary_spread 0 +// }}} +// {{{ seeker +set g_balance_seeker_flac_ammo 0.5 +set g_balance_seeker_flac_animtime 0.1 +set g_balance_seeker_flac_damage 15 +set g_balance_seeker_flac_edgedamage 10 +set g_balance_seeker_flac_force 50 +set g_balance_seeker_flac_lifetime 0.1 +set g_balance_seeker_flac_lifetime_rand 0.05 +set g_balance_seeker_flac_radius 100 +set g_balance_seeker_flac_refire 0.1 +set g_balance_seeker_flac_speed 3000 +set g_balance_seeker_flac_speed_up 1000 +set g_balance_seeker_flac_speed_z 0 +set g_balance_seeker_flac_spread 0.4 +set g_balance_seeker_missile_accel 1.05 +set g_balance_seeker_missile_ammo 2 +set g_balance_seeker_missile_animtime 0.3 +set g_balance_seeker_missile_count 8 +set g_balance_seeker_missile_damage 15 +set g_balance_seeker_missile_damageforcescale 4 +set g_balance_seeker_missile_decel 0.9 +set g_balance_seeker_missile_delay 0.25 +set g_balance_seeker_missile_edgedamage 10 +set g_balance_seeker_missile_force 250 +set g_balance_seeker_missile_health 5 +set g_balance_seeker_missile_lifetime 15 +set g_balance_seeker_missile_proxy 0 +set g_balance_seeker_missile_proxy_delay 0.2 +set g_balance_seeker_missile_proxy_maxrange 45 +set g_balance_seeker_missile_radius 80 +set g_balance_seeker_missile_refire 0.5 +set g_balance_seeker_missile_smart 1 +set g_balance_seeker_missile_smart_mindist 800 +set g_balance_seeker_missile_smart_trace_max 2500 +set g_balance_seeker_missile_smart_trace_min 1000 +set g_balance_seeker_missile_speed 700 +set g_balance_seeker_missile_speed_accel 0 +set g_balance_seeker_missile_speed_up 300 +set g_balance_seeker_missile_speed_z 0 +set g_balance_seeker_missile_speed_max 1250 +set g_balance_seeker_missile_spread 0 +set g_balance_seeker_missile_turnrate 0.65 +set g_balance_seeker_tag_ammo 1 +set g_balance_seeker_tag_animtime 0.3 +set g_balance_seeker_tag_damageforcescale 4 +set g_balance_seeker_tag_health 5 +set g_balance_seeker_tag_lifetime 15 +set g_balance_seeker_tag_refire 0.7 +set g_balance_seeker_tag_speed 9000 +set g_balance_seeker_tag_spread 0 +// End new seeker diff --git a/balanceNexSVN.cfg b/balanceNexSVN.cfg index 0f8a8dc35..445e8b156 100644 --- a/balanceNexSVN.cfg +++ b/balanceNexSVN.cfg @@ -3,6 +3,7 @@ set g_start_weapon_laser -1 "0 = never provide the weapon, 1 = always provide th set g_start_weapon_shotgun -1 "0 = never provide the weapon, 1 = always provide the weapon, -1 = game mode default, -2 = provide the weapon in ca and lms" set g_start_weapon_uzi -1 "0 = never provide the weapon, 1 = always provide the weapon, -1 = game mode default, -2 = provide the weapon in ca and lms" set g_start_weapon_grenadelauncher -1 "0 = never provide the weapon, 1 = always provide the weapon, -1 = game mode default, -2 = provide the weapon in ca and lms" +set g_start_weapon_minelayer -1 "0 = never provide the weapon, 1 = always provide the weapon, -1 = game mode default, -2 = provide the weapon in ca and lms" set g_start_weapon_electro -1 "0 = never provide the weapon, 1 = always provide the weapon, -1 = game mode default, -2 = provide the weapon in ca and lms" set g_start_weapon_crylink -1 "0 = never provide the weapon, 1 = always provide the weapon, -1 = game mode default, -2 = provide the weapon in ca and lms" set g_start_weapon_nex -1 "0 = never provide the weapon, 1 = always provide the weapon, -1 = game mode default, -2 = provide the weapon in ca and lms" @@ -55,14 +56,19 @@ set g_balance_nix_ammoincr_fuel 2 set g_pickup_ammo_anyway 0 set g_pickup_weapons_anyway 0 set g_pickup_shells 15 +set g_pickup_shells_weapon 15 set g_pickup_shells_max 999 set g_pickup_nails 80 +set g_pickup_nails_weapon 80 set g_pickup_nails_max 999 set g_pickup_rockets 15 +set g_pickup_rockets_weapon 15 set g_pickup_rockets_max 999 set g_pickup_cells 25 +set g_pickup_cells_weapon 25 set g_pickup_cells_max 999 set g_pickup_fuel 25 +set g_pickup_fuel_weapon 25 set g_pickup_fuel_jetpack 50 set g_pickup_fuel_max 999 set g_pickup_armorsmall 5 @@ -268,8 +274,7 @@ set g_balance_uzi_speed 18000 set g_balance_uzi_bulletconstant 115 // 13.1qu // }}} // {{{ mortar -set g_balance_grenadelauncher_primary2secondary 0 -set g_balance_grenadelauncher_primary_sticky 0 +set g_balance_grenadelauncher_primary_type 0 set g_balance_grenadelauncher_primary_damage 70 set g_balance_grenadelauncher_primary_edgedamage 38 set g_balance_grenadelauncher_primary_force 400 @@ -284,7 +289,11 @@ set g_balance_grenadelauncher_primary_refire 0.8 set g_balance_grenadelauncher_primary_animtime 0.3 set g_balance_grenadelauncher_primary_ammo 2 set g_balance_grenadelauncher_primary_health 25 -set g_balance_grenadelauncher_secondary_sticky 0 +set g_balance_grenadelauncher_primary_damageforcescale 4 +set g_balance_grenadelauncher_primary_bouncefactor 0.5 +set g_balance_grenadelauncher_primary_bouncestop 0.075 +set g_balance_grenadelauncher_primary_remote_minbouncecnt 0 +set g_balance_grenadelauncher_secondary_type 1 set g_balance_grenadelauncher_secondary_damage 70 set g_balance_grenadelauncher_secondary_edgedamage 38 set g_balance_grenadelauncher_secondary_force 400 @@ -302,6 +311,29 @@ set g_balance_grenadelauncher_secondary_health 10 set g_balance_grenadelauncher_secondary_damageforcescale 4 set g_balance_grenadelauncher_secondary_bouncefactor 0.5 set g_balance_grenadelauncher_secondary_bouncestop 0.075 +set g_balance_grenadelauncher_secondary_remote_detonateprimary 0 +// }}} +// {{{ minelayer // TODO +set g_balance_minelayer_damage 35 +set g_balance_minelayer_edgedamage 30 +set g_balance_minelayer_force 250 +set g_balance_minelayer_radius 175 +set g_balance_minelayer_proximityradius 150 +set g_balance_minelayer_speed 750 +set g_balance_minelayer_lifetime 60 +set g_balance_minelayer_refire 1.5 +set g_balance_minelayer_animtime 0.4 +set g_balance_minelayer_ammo 5 +set g_balance_minelayer_health 15 +set g_balance_minelayer_limit 4 // 0 disables the limit +set g_balance_minelayer_protection 1 // don't explode if the mine would hurt the owner or a team mate +set g_balance_minelayer_damageforcescale 0 +set g_balance_minelayer_detonatedelay -1 // positive: timer till detonation is allowed, negative: "security device" that prevents ANY remote detonation if it could hurt its owner, zero: detonatable at any time +set g_balance_minelayer_time 0.5 +set g_balance_minelayer_remote_damage 45 +set g_balance_minelayer_remote_edgedamage 40 +set g_balance_minelayer_remote_radius 200 +set g_balance_minelayer_remote_force 300 // }}} // {{{ electro set g_balance_electro_lightning 0 @@ -318,8 +350,10 @@ set g_balance_electro_primary_refire 0.6 set g_balance_electro_primary_animtime 0.3 set g_balance_electro_primary_ammo 2 set g_balance_electro_primary_range 0 +set g_balance_electro_primary_falloff_mindist 255 // 0.3 * radius +set g_balance_electro_primary_falloff_maxdist 850 +set g_balance_electro_primary_falloff_halflifedist 425 set g_balance_electro_secondary_damage 50 -set g_balance_electro_secondary_spread 0.05 set g_balance_electro_secondary_edgedamage 0 set g_balance_electro_secondary_force 200 set g_balance_electro_secondary_radius 150 @@ -394,6 +428,8 @@ set g_balance_nex_primary_damagefalloff_halflife 1500 set g_balance_nex_primary_damagefalloff_forcehalflife 1500 set g_balance_nex_secondary 0 +set g_balance_nex_secondary_charge 0 +set g_balance_nex_secondary_charge_rate 0.1 set g_balance_nex_secondary_damage 90 set g_balance_nex_secondary_force 200 set g_balance_nex_secondary_refire 1.5 @@ -403,6 +439,15 @@ set g_balance_nex_secondary_damagefalloff_mindist 1000 set g_balance_nex_secondary_damagefalloff_maxdist 3000 set g_balance_nex_secondary_damagefalloff_halflife 1500 set g_balance_nex_secondary_damagefalloff_forcehalflife 1500 + +set g_balance_nex_charge 0 +set g_balance_nex_charge_start 0 +set g_balance_nex_charge_rate 0.1 +set g_balance_nex_charge_limit 0.5 +set g_balance_nex_charge_shot_multiplier 0.5 +set g_balance_nex_charge_velocity_rate 0.2 +set g_balance_nex_charge_minspeed 400 +set g_balance_nex_charge_maxspeed 1000 // }}} // {{{ minstanex set g_balance_minstanex_refire 1 @@ -527,7 +572,7 @@ set g_balance_campingrifle_magazinecapacity 0 set g_balance_campingrifle_reloadtime 2 // matches reload anim set g_balance_campingrifle_auto_reload_after_changing_weapons 0 set g_balance_campingrifle_bursttime 0.85 // 0.35 - 0.1 + 0.35 - 0.1 + 0.35 = three secondaries -set g_balance_campingrifle_tracer 1 +set g_balance_campingrifle_primary_tracer 0 set g_balance_campingrifle_primary_damage 50 set g_balance_campingrifle_primary_headshotaddeddamage 50 set g_balance_campingrifle_primary_spread 0 @@ -541,6 +586,7 @@ set g_balance_campingrifle_primary_bulletconstant 130 // 56.3qu set g_balance_campingrifle_primary_burstcost 0.35 // require same cooldown as secondary, note it's smaller than primary refire time set g_balance_campingrifle_primary_bullethail 0 set g_balance_campingrifle_secondary 1 +set g_balance_campingrifle_secondary_tracer 0 set g_balance_campingrifle_secondary_damage 15 set g_balance_campingrifle_secondary_headshotaddeddamage 25 set g_balance_campingrifle_secondary_spread 0.02 diff --git a/balanceSamual.cfg b/balanceSamual.cfg index e70157872..517f5c9cf 100644 --- a/balanceSamual.cfg +++ b/balanceSamual.cfg @@ -3,6 +3,7 @@ set g_start_weapon_laser -1 "0 = never provide the weapon, 1 = always provide th set g_start_weapon_shotgun -1 "0 = never provide the weapon, 1 = always provide the weapon, -1 = game mode default, -2 = provide the weapon in ca and lms" set g_start_weapon_uzi -1 "0 = never provide the weapon, 1 = always provide the weapon, -1 = game mode default, -2 = provide the weapon in ca and lms" set g_start_weapon_grenadelauncher -1 "0 = never provide the weapon, 1 = always provide the weapon, -1 = game mode default, -2 = provide the weapon in ca and lms" +set g_start_weapon_minelayer -1 "0 = never provide the weapon, 1 = always provide the weapon, -1 = game mode default, -2 = provide the weapon in ca and lms" set g_start_weapon_electro -1 "0 = never provide the weapon, 1 = always provide the weapon, -1 = game mode default, -2 = provide the weapon in ca and lms" set g_start_weapon_crylink -1 "0 = never provide the weapon, 1 = always provide the weapon, -1 = game mode default, -2 = provide the weapon in ca and lms" set g_start_weapon_nex -1 "0 = never provide the weapon, 1 = always provide the weapon, -1 = game mode default, -2 = provide the weapon in ca and lms" @@ -55,14 +56,19 @@ set g_balance_nix_ammoincr_fuel 2 set g_pickup_ammo_anyway 1 set g_pickup_weapons_anyway 1 set g_pickup_shells 30 +set g_pickup_shells_weapon 30 set g_pickup_shells_max 120 set g_pickup_nails 80 +set g_pickup_nails_weapon 80 set g_pickup_nails_max 400 set g_pickup_rockets 30 +set g_pickup_rockets_weapon 30 set g_pickup_rockets_max 120 set g_pickup_cells 50 +set g_pickup_cells_weapon 50 set g_pickup_cells_max 200 set g_pickup_fuel 25 +set g_pickup_fuel_weapon 25 set g_pickup_fuel_jetpack 50 set g_pickup_fuel_max 999 set g_pickup_armorsmall 10 @@ -268,8 +274,7 @@ set g_balance_uzi_speed 18000 set g_balance_uzi_bulletconstant 115 // 13.1qu // }}} // {{{ mortar -set g_balance_grenadelauncher_primary2secondary 0 -set g_balance_grenadelauncher_primary_sticky 0 +set g_balance_grenadelauncher_primary_type 0 set g_balance_grenadelauncher_primary_damage 50 set g_balance_grenadelauncher_primary_edgedamage 38 set g_balance_grenadelauncher_primary_force 400 @@ -284,7 +289,12 @@ set g_balance_grenadelauncher_primary_refire 0.8 set g_balance_grenadelauncher_primary_animtime 0.3 set g_balance_grenadelauncher_primary_ammo 2 set g_balance_grenadelauncher_primary_health 25 -set g_balance_grenadelauncher_secondary_sticky 0 +set g_balance_grenadelauncher_primary_damageforcescale 4 +set g_balance_grenadelauncher_primary_bouncefactor 0.5 +set g_balance_grenadelauncher_primary_bouncestop 0.075 +set g_balance_grenadelauncher_primary_remote_minbouncecnt 0 + +set g_balance_grenadelauncher_secondary_type 1 set g_balance_grenadelauncher_secondary_damage 60 set g_balance_grenadelauncher_secondary_edgedamage 38 set g_balance_grenadelauncher_secondary_force 400 @@ -302,6 +312,29 @@ set g_balance_grenadelauncher_secondary_health 70 set g_balance_grenadelauncher_secondary_damageforcescale 4 set g_balance_grenadelauncher_secondary_bouncefactor 0.5 set g_balance_grenadelauncher_secondary_bouncestop 0.075 +set g_balance_grenadelauncher_secondary_remote_detonateprimary 1 +// }}} +// {{{ minelayer // TODO +set g_balance_minelayer_damage 35 +set g_balance_minelayer_edgedamage 30 +set g_balance_minelayer_force 250 +set g_balance_minelayer_radius 175 +set g_balance_minelayer_proximityradius 150 +set g_balance_minelayer_speed 750 +set g_balance_minelayer_lifetime 60 +set g_balance_minelayer_refire 1.5 +set g_balance_minelayer_animtime 0.4 +set g_balance_minelayer_ammo 5 +set g_balance_minelayer_health 15 +set g_balance_minelayer_limit 4 // 0 disables the limit +set g_balance_minelayer_protection 1 // don't explode if the mine would hurt the owner or a team mate +set g_balance_minelayer_damageforcescale 0 +set g_balance_minelayer_detonatedelay -1 // positive: timer till detonation is allowed, negative: "security device" that prevents ANY remote detonation if it could hurt its owner, zero: detonatable at any time +set g_balance_minelayer_time 0.5 +set g_balance_minelayer_remote_damage 45 +set g_balance_minelayer_remote_edgedamage 40 +set g_balance_minelayer_remote_radius 200 +set g_balance_minelayer_remote_force 300 // }}} // {{{ electro set g_balance_electro_lightning 0 @@ -318,8 +351,10 @@ set g_balance_electro_primary_refire 0.6 set g_balance_electro_primary_animtime 0.3 set g_balance_electro_primary_ammo 2 set g_balance_electro_primary_range 0 +set g_balance_electro_primary_falloff_mindist 255 // 0.3 * radius +set g_balance_electro_primary_falloff_maxdist 850 +set g_balance_electro_primary_falloff_halflifedist 425 set g_balance_electro_secondary_damage 50 -set g_balance_electro_secondary_spread 0.05 set g_balance_electro_secondary_edgedamage 0 set g_balance_electro_secondary_force 200 set g_balance_electro_secondary_radius 150 @@ -394,6 +429,8 @@ set g_balance_nex_primary_damagefalloff_halflife 1500 set g_balance_nex_primary_damagefalloff_forcehalflife 1500 set g_balance_nex_secondary 0 +set g_balance_nex_secondary_charge 0 +set g_balance_nex_secondary_charge_rate 0.1 set g_balance_nex_secondary_damage 90 set g_balance_nex_secondary_force 300 set g_balance_nex_secondary_refire 1.5 @@ -403,6 +440,15 @@ set g_balance_nex_secondary_damagefalloff_mindist 1000 set g_balance_nex_secondary_damagefalloff_maxdist 3000 set g_balance_nex_secondary_damagefalloff_halflife 1500 set g_balance_nex_secondary_damagefalloff_forcehalflife 1500 + +set g_balance_nex_charge 0 +set g_balance_nex_charge_start 0 +set g_balance_nex_charge_rate 0.1 +set g_balance_nex_charge_limit 0.5 +set g_balance_nex_charge_shot_multiplier 0.5 +set g_balance_nex_charge_velocity_rate 0.2 +set g_balance_nex_charge_minspeed 400 +set g_balance_nex_charge_maxspeed 1000 // }}} // {{{ minstanex set g_balance_minstanex_refire 1 @@ -527,7 +573,7 @@ set g_balance_campingrifle_magazinecapacity 0 set g_balance_campingrifle_reloadtime 2 // matches reload anim set g_balance_campingrifle_auto_reload_after_changing_weapons 0 set g_balance_campingrifle_bursttime 0.85 // 0.35 - 0.1 + 0.35 - 0.1 + 0.35 = three secondaries -set g_balance_campingrifle_tracer 1 +set g_balance_campingrifle_primary_tracer 0 set g_balance_campingrifle_primary_damage 50 set g_balance_campingrifle_primary_headshotaddeddamage 50 set g_balance_campingrifle_primary_spread 0 @@ -541,6 +587,7 @@ set g_balance_campingrifle_primary_bulletconstant 130 // 56.3qu set g_balance_campingrifle_primary_burstcost 0.35 // require same cooldown as secondary, note it's smaller than primary refire time set g_balance_campingrifle_primary_bullethail 0 set g_balance_campingrifle_secondary 1 +set g_balance_campingrifle_secondary_tracer 0 set g_balance_campingrifle_secondary_damage 15 set g_balance_campingrifle_secondary_headshotaddeddamage 25 set g_balance_campingrifle_secondary_spread 0.02 diff --git a/balanceXonotic.cfg b/balanceXonotic.cfg index 39b9b26cc..084810b55 100644 --- a/balanceXonotic.cfg +++ b/balanceXonotic.cfg @@ -3,6 +3,7 @@ set g_start_weapon_laser -1 "0 = never provide the weapon, 1 = always provide th set g_start_weapon_shotgun -1 "0 = never provide the weapon, 1 = always provide the weapon, -1 = game mode default, -2 = provide the weapon in ca and lms" set g_start_weapon_uzi -1 "0 = never provide the weapon, 1 = always provide the weapon, -1 = game mode default, -2 = provide the weapon in ca and lms" set g_start_weapon_grenadelauncher -1 "0 = never provide the weapon, 1 = always provide the weapon, -1 = game mode default, -2 = provide the weapon in ca and lms" +set g_start_weapon_minelayer -1 "0 = never provide the weapon, 1 = always provide the weapon, -1 = game mode default, -2 = provide the weapon in ca and lms" set g_start_weapon_electro -1 "0 = never provide the weapon, 1 = always provide the weapon, -1 = game mode default, -2 = provide the weapon in ca and lms" set g_start_weapon_crylink -1 "0 = never provide the weapon, 1 = always provide the weapon, -1 = game mode default, -2 = provide the weapon in ca and lms" set g_start_weapon_nex -1 "0 = never provide the weapon, 1 = always provide the weapon, -1 = game mode default, -2 = provide the weapon in ca and lms" @@ -55,14 +56,19 @@ set g_balance_nix_ammoincr_fuel 2 set g_pickup_ammo_anyway 1 set g_pickup_weapons_anyway 1 set g_pickup_shells 20 +set g_pickup_shells_weapon 10 set g_pickup_shells_max 45 set g_pickup_nails 120 +set g_pickup_nails_weapon 60 set g_pickup_nails_max 300 set g_pickup_rockets 25 +set g_pickup_rockets_weapon 15 set g_pickup_rockets_max 150 set g_pickup_cells 25 +set g_pickup_cells_weapon 15 set g_pickup_cells_max 200 set g_pickup_fuel 25 +set g_pickup_fuel_weapon 15 set g_pickup_fuel_jetpack 50 set g_pickup_fuel_max 100 set g_pickup_armorsmall 5 @@ -114,7 +120,7 @@ set g_balance_pause_health_rot 1 set g_balance_pause_health_rot_spawn 0 set g_balance_health_regenstable 100 set g_balance_health_rotstable 100 -set g_balance_health_limit 200 +set g_balance_health_limit 999 set g_balance_armor_regen 0 set g_balance_armor_regenlinear 0 set g_balance_armor_rot 0 @@ -123,7 +129,7 @@ set g_balance_pause_armor_rot 1 set g_balance_pause_armor_rot_spawn 0 set g_balance_armor_regenstable 100 set g_balance_armor_rotstable 100 -set g_balance_armor_limit 200 +set g_balance_armor_limit 999 set g_balance_armor_blockpercent 0.7 set g_balance_fuel_regen 0.1 "fuel regeneration (only applies if the player owns IT_FUEL_REGEN)" set g_balance_fuel_regenlinear 0 @@ -244,82 +250,111 @@ set g_balance_shotgun_primary_speed 12000 set g_balance_shotgun_primary_bulletconstant 75 // 3.8qu set g_balance_shotgun_secondary 1 set g_balance_shotgun_secondary_melee_delay 0.35 // match the anim -set g_balance_shotgun_secondary_melee_range 60 +set g_balance_shotgun_secondary_melee_range 85 set g_balance_shotgun_secondary_melee_swing 50 set g_balance_shotgun_secondary_melee_time 0.1 -set g_balance_shotgun_secondary_damage 115 +set g_balance_shotgun_secondary_damage 110 set g_balance_shotgun_secondary_force 150 set g_balance_shotgun_secondary_refire 1.1 set g_balance_shotgun_secondary_animtime 1 // }}} // {{{ uzi set g_balance_uzi_first 1 -set g_balance_uzi_first_damage 17 +set g_balance_uzi_first_damage 16 set g_balance_uzi_first_force 35 set g_balance_uzi_first_spread 0.03 set g_balance_uzi_first_refire 0.2 set g_balance_uzi_first_ammo 2 -set g_balance_uzi_sustained_damage 7 +set g_balance_uzi_sustained_damage 9 set g_balance_uzi_sustained_force 7.5 set g_balance_uzi_sustained_spread 0.1 -set g_balance_uzi_sustained_refire 0.075 +set g_balance_uzi_sustained_refire 0.1 set g_balance_uzi_sustained_ammo 1 set g_balance_uzi_speed 18000 set g_balance_uzi_bulletconstant 115 // 13.1qu // }}} // {{{ mortar // TODO -set g_balance_grenadelauncher_primary2secondary 0 -set g_balance_grenadelauncher_primary_sticky 0 -set g_balance_grenadelauncher_primary_damage 60 +set g_balance_grenadelauncher_primary_type 0 +set g_balance_grenadelauncher_primary_damage 50 set g_balance_grenadelauncher_primary_edgedamage 25 set g_balance_grenadelauncher_primary_force 300 set g_balance_grenadelauncher_primary_radius 100 -set g_balance_grenadelauncher_primary_speed 1400 +set g_balance_grenadelauncher_primary_speed 1200 set g_balance_grenadelauncher_primary_speed_up 225 set g_balance_grenadelauncher_primary_speed_z 0 set g_balance_grenadelauncher_primary_spread 0 set g_balance_grenadelauncher_primary_lifetime 5 set g_balance_grenadelauncher_primary_lifetime2 0.65 set g_balance_grenadelauncher_primary_refire 0.8 -set g_balance_grenadelauncher_primary_animtime 0.2 +set g_balance_grenadelauncher_primary_animtime 0.4 set g_balance_grenadelauncher_primary_ammo 2 -set g_balance_grenadelauncher_primary_health 72 -set g_balance_grenadelauncher_secondary_sticky 1 -set g_balance_grenadelauncher_secondary_damage 90 +set g_balance_grenadelauncher_primary_health 80 +set g_balance_grenadelauncher_primary_damageforcescale 0 +set g_balance_grenadelauncher_primary_bouncefactor 0.5 +set g_balance_grenadelauncher_primary_bouncestop 0.12 +set g_balance_grenadelauncher_primary_remote_minbouncecnt 0 + +set g_balance_grenadelauncher_secondary_type 1 +set g_balance_grenadelauncher_secondary_damage 70 set g_balance_grenadelauncher_secondary_edgedamage 32 set g_balance_grenadelauncher_secondary_force 300 set g_balance_grenadelauncher_secondary_radius 150 -set g_balance_grenadelauncher_secondary_speed 1400 +set g_balance_grenadelauncher_secondary_speed 1200 set g_balance_grenadelauncher_secondary_speed_up 225 set g_balance_grenadelauncher_secondary_speed_z 0 set g_balance_grenadelauncher_secondary_spread 0 -set g_balance_grenadelauncher_secondary_lifetime 5 -set g_balance_grenadelauncher_secondary_lifetime2 1 +set g_balance_grenadelauncher_secondary_lifetime 3 +set g_balance_grenadelauncher_secondary_lifetime2 0.65 set g_balance_grenadelauncher_secondary_refire 0.8 -set g_balance_grenadelauncher_secondary_animtime 0.2 +set g_balance_grenadelauncher_secondary_animtime 0.4 set g_balance_grenadelauncher_secondary_ammo 2 set g_balance_grenadelauncher_secondary_health 40 set g_balance_grenadelauncher_secondary_damageforcescale 0 -set g_balance_grenadelauncher_secondary_bouncefactor 0.7 +set g_balance_grenadelauncher_secondary_bouncefactor 0.5 set g_balance_grenadelauncher_secondary_bouncestop 0.12 +set g_balance_grenadelauncher_secondary_remote_detonateprimary 0 +// }}} +// {{{ minelayer // TODO +set g_balance_minelayer_damage 35 +set g_balance_minelayer_edgedamage 30 +set g_balance_minelayer_force 250 +set g_balance_minelayer_radius 175 +set g_balance_minelayer_proximityradius 150 +set g_balance_minelayer_speed 750 +set g_balance_minelayer_lifetime 60 +set g_balance_minelayer_refire 1.5 +set g_balance_minelayer_animtime 0.4 +set g_balance_minelayer_ammo 5 +set g_balance_minelayer_health 15 +set g_balance_minelayer_limit 4 // 0 disables the limit +set g_balance_minelayer_protection 1 // don't explode if the mine would hurt the owner or a team mate +set g_balance_minelayer_damageforcescale 0 +set g_balance_minelayer_detonatedelay -1 // positive: timer till detonation is allowed, negative: "security device" that prevents ANY remote detonation if it could hurt its owner, zero: detonatable at any time +set g_balance_minelayer_time 0.5 +set g_balance_minelayer_remote_damage 45 +set g_balance_minelayer_remote_edgedamage 40 +set g_balance_minelayer_remote_radius 200 +set g_balance_minelayer_remote_force 300 // }}} // {{{ electro // TODO set g_balance_electro_lightning 1 -set g_balance_electro_primary_damage 90 +set g_balance_electro_primary_damage 85 set g_balance_electro_primary_edgedamage 0 -set g_balance_electro_primary_force 550 +set g_balance_electro_primary_force 425 set g_balance_electro_primary_force_up 125 set g_balance_electro_primary_radius 850 set g_balance_electro_primary_comboradius 75 set g_balance_electro_primary_speed 0 set g_balance_electro_primary_spread 0 set g_balance_electro_primary_lifetime 0 -set g_balance_electro_primary_refire 0.03333333 +set g_balance_electro_primary_refire 0.4 set g_balance_electro_primary_animtime 0.03333333 -set g_balance_electro_primary_ammo 10 +set g_balance_electro_primary_ammo 7 set g_balance_electro_primary_range 800 +set g_balance_electro_primary_falloff_mindist 255 // 0.3 * radius +set g_balance_electro_primary_falloff_maxdist 850 +set g_balance_electro_primary_falloff_halflifedist 425 set g_balance_electro_secondary_damage 25 -set g_balance_electro_secondary_spread 0 set g_balance_electro_secondary_edgedamage 0 set g_balance_electro_secondary_force 100 set g_balance_electro_secondary_radius 100 @@ -343,10 +378,10 @@ set g_balance_electro_combo_comboradius 0 set g_balance_electro_combo_speed 400 // }}} // {{{ crylink -set g_balance_crylink_primary_damage 10 -set g_balance_crylink_primary_edgedamage 8 -set g_balance_crylink_primary_force -60 -set g_balance_crylink_primary_radius 100 +set g_balance_crylink_primary_damage 8 +set g_balance_crylink_primary_edgedamage 6 +set g_balance_crylink_primary_force 40 +set g_balance_crylink_primary_radius 80 set g_balance_crylink_primary_speed 1100 set g_balance_crylink_primary_spread 0.1 set g_balance_crylink_primary_shots 7 @@ -364,16 +399,16 @@ set g_balance_crylink_primary_other_lifetime 2 // range: 800 full, fades to 1300 set g_balance_crylink_primary_other_fadetime 0.25 set g_balance_crylink_secondary 1 -set g_balance_crylink_secondary_damage 4 +set g_balance_crylink_secondary_damage 2 set g_balance_crylink_secondary_edgedamage 0 set g_balance_crylink_secondary_force -20 -set g_balance_crylink_secondary_radius 15 +set g_balance_crylink_secondary_radius 5 set g_balance_crylink_secondary_speed 1600 set g_balance_crylink_secondary_spread 0.03 set g_balance_crylink_secondary_shots 3 set g_balance_crylink_secondary_bounces 0 -set g_balance_crylink_secondary_refire 0.1 -set g_balance_crylink_secondary_animtime 0.1 +set g_balance_crylink_secondary_refire 0.15 +set g_balance_crylink_secondary_animtime 0.15 set g_balance_crylink_secondary_ammo 1 set g_balance_crylink_secondary_bouncedamagefactor 0.5 @@ -383,26 +418,37 @@ set g_balance_crylink_secondary_line_lifetime 2 // range: 4000 full, fades to 80 set g_balance_crylink_secondary_line_fadetime 2 // }}} // {{{ nex -set g_balance_nex_primary_damage 80 -set g_balance_nex_primary_force 200 -set g_balance_nex_primary_refire 1.25 +set g_balance_nex_primary_damage 120 +set g_balance_nex_primary_force 500 +set g_balance_nex_primary_refire 1 set g_balance_nex_primary_animtime 0.75 set g_balance_nex_primary_ammo 5 set g_balance_nex_primary_damagefalloff_mindist 1000 set g_balance_nex_primary_damagefalloff_maxdist 3000 -set g_balance_nex_primary_damagefalloff_halflife 4000 -set g_balance_nex_primary_damagefalloff_forcehalflife 4000 +set g_balance_nex_primary_damagefalloff_halflife 1000 +set g_balance_nex_primary_damagefalloff_forcehalflife 2000 set g_balance_nex_secondary 1 -set g_balance_nex_secondary_damage 80 -set g_balance_nex_secondary_force -200 -set g_balance_nex_secondary_refire 1.25 -set g_balance_nex_secondary_animtime 0.75 -set g_balance_nex_secondary_ammo 5 -set g_balance_nex_secondary_damagefalloff_mindist 1000 -set g_balance_nex_secondary_damagefalloff_maxdist 3000 -set g_balance_nex_secondary_damagefalloff_halflife 4000 -set g_balance_nex_secondary_damagefalloff_forcehalflife 4000 +set g_balance_nex_secondary_charge 1 +set g_balance_nex_secondary_charge_rate 0.15 +set g_balance_nex_secondary_damage 0 +set g_balance_nex_secondary_force 0 +set g_balance_nex_secondary_refire 0 +set g_balance_nex_secondary_animtime 0 +set g_balance_nex_secondary_ammo 4 +set g_balance_nex_secondary_damagefalloff_mindist 0 +set g_balance_nex_secondary_damagefalloff_maxdist 0 +set g_balance_nex_secondary_damagefalloff_halflife 0 +set g_balance_nex_secondary_damagefalloff_forcehalflife 0 + +set g_balance_nex_charge 1 +set g_balance_nex_charge_start 0.2 +set g_balance_nex_charge_rate 0.05 +set g_balance_nex_charge_limit 0.5 +set g_balance_nex_charge_shot_multiplier 0.675 +set g_balance_nex_charge_velocity_rate 0.15 +set g_balance_nex_charge_minspeed 400 +set g_balance_nex_charge_maxspeed 1000 // }}} // {{{ minstanex set g_balance_minstanex_refire 1.25 @@ -411,9 +457,9 @@ set g_balance_minstanex_ammo 10 // }}} // {{{ hagar set g_balance_hagar_primary_damage 12 -set g_balance_hagar_primary_edgedamage 12 +set g_balance_hagar_primary_edgedamage 6 set g_balance_hagar_primary_force 70 -set g_balance_hagar_primary_radius 70 +set g_balance_hagar_primary_radius 100 set g_balance_hagar_primary_spread 0.1 set g_balance_hagar_primary_speed 1800 set g_balance_hagar_primary_lifetime 5 @@ -421,9 +467,9 @@ set g_balance_hagar_primary_refire 0.12 set g_balance_hagar_primary_ammo 1 set g_balance_hagar_secondary 1 set g_balance_hagar_secondary_damage 12 -set g_balance_hagar_secondary_edgedamage 12 +set g_balance_hagar_secondary_edgedamage 6 set g_balance_hagar_secondary_force 70 -set g_balance_hagar_secondary_radius 50 +set g_balance_hagar_secondary_radius 100 set g_balance_hagar_secondary_spread 0.15 set g_balance_hagar_secondary_speed 1800 set g_balance_hagar_secondary_lifetime_min 5 @@ -441,7 +487,7 @@ set g_balance_rocketlauncher_speedaccel 0 set g_balance_rocketlauncher_speedstart 1000 set g_balance_rocketlauncher_lifetime 5 set g_balance_rocketlauncher_refire 1 -set g_balance_rocketlauncher_animtime 0.2 +set g_balance_rocketlauncher_animtime 0.4 set g_balance_rocketlauncher_ammo 3 set g_balance_rocketlauncher_health 0 set g_balance_rocketlauncher_damageforcescale 0 @@ -523,34 +569,35 @@ set g_balance_hlac_secondary_ammo 10 set g_balance_hlac_secondary_shots 6 // }}} // {{{ campingrifle -set g_balance_campingrifle_magazinecapacity 4 // make it pretty much useless in close combat +set g_balance_campingrifle_magazinecapacity 8 // make it pretty much useless in close combat set g_balance_campingrifle_reloadtime 2 // matches reload anim set g_balance_campingrifle_auto_reload_after_changing_weapons 0 set g_balance_campingrifle_bursttime 0 -set g_balance_campingrifle_tracer 1 -set g_balance_campingrifle_primary_damage 60 -set g_balance_campingrifle_primary_headshotaddeddamage 50 +set g_balance_campingrifle_primary_tracer 1 +set g_balance_campingrifle_primary_damage 75 +set g_balance_campingrifle_primary_headshotaddeddamage 75 set g_balance_campingrifle_primary_spread 0 set g_balance_campingrifle_primary_force 2 set g_balance_campingrifle_primary_speed 35000 set g_balance_campingrifle_primary_lifetime 5 -set g_balance_campingrifle_primary_refire 0.8 -set g_balance_campingrifle_primary_animtime 0.8 +set g_balance_campingrifle_primary_refire 1.5 +set g_balance_campingrifle_primary_animtime 1.4 set g_balance_campingrifle_primary_ammo 10 set g_balance_campingrifle_primary_bulletconstant 130 // 56.3qu set g_balance_campingrifle_primary_burstcost 0 set g_balance_campingrifle_primary_bullethail 0 // empty magazine on shot set g_balance_campingrifle_secondary 1 -set g_balance_campingrifle_secondary_damage 25 -set g_balance_campingrifle_secondary_headshotaddeddamage 20 // 45 damage only on head -set g_balance_campingrifle_secondary_spread 0.008 -set g_balance_campingrifle_secondary_force 1 -set g_balance_campingrifle_secondary_speed 20000 +set g_balance_campingrifle_secondary_tracer 0 +set g_balance_campingrifle_secondary_damage 50 +set g_balance_campingrifle_secondary_headshotaddeddamage 50 // 50 damage only on head +set g_balance_campingrifle_secondary_spread 0 +set g_balance_campingrifle_secondary_force 2 +set g_balance_campingrifle_secondary_speed 15000 set g_balance_campingrifle_secondary_lifetime 5 -set g_balance_campingrifle_secondary_refire 0.15 -set g_balance_campingrifle_secondary_animtime 0.1 +set g_balance_campingrifle_secondary_refire 1.5 +set g_balance_campingrifle_secondary_animtime 1.4 set g_balance_campingrifle_secondary_ammo 10 -set g_balance_campingrifle_secondary_bulletconstant 130 // 18.3qu +set g_balance_campingrifle_secondary_bulletconstant 130 // 10.3qu set g_balance_campingrifle_secondary_burstcost 0 set g_balance_campingrifle_secondary_bullethail 0 // empty magazine on shot // }}} diff --git a/darkplaces-icon.tga b/darkplaces-icon.tga new file mode 100644 index 000000000..d7a0dd09e Binary files /dev/null and b/darkplaces-icon.tga differ diff --git a/darkplaces-icon.xpm b/darkplaces-icon.xpm new file mode 100644 index 000000000..cdd7f4414 --- /dev/null +++ b/darkplaces-icon.xpm @@ -0,0 +1,127 @@ +/* XPM */ +static char * xonotic_32_xpm[] = { +"32 32 92 1", +" c None", +". c #000509", +"+ c #0F0303", +"@ c #150400", +"# c #1B0400", +"$ c #010C14", +"% c #220700", +"& c #010F1A", +"* c #250700", +"= c #2B0900", +"- c #011321", +"; c #310A03", +"> c #001628", +", c #330B00", +"' c #390B03", +") c #400A01", +"! c #3C0E00", +"~ c #051A31", +"{ c #331103", +"] c #430D00", +"^ c #4D1002", +"/ c #0A1F36", +"( c #141E29", +"_ c #451A07", +": c #082743", +"< c #0A273F", +"[ c #4F1D08", +"} c #5B1B07", +"| c #182C3F", +"1 c #0C2F51", +"2 c #5D2409", +"3 c #65240A", +"4 c #562812", +"5 c #4D2C1B", +"6 c #0D3A65", +"7 c #662A06", +"8 c #722D0F", +"9 c #743101", +"0 c #2C3F53", +"a c #77310A", +"b c #1A4673", +"c c #7C3908", +"d c #683D29", +"e c #733B1E", +"f c #823A03", +"g c #214C76", +"h c #8B3E18", +"i c #8F410D", +"j c #963F11", +"k c #604D4A", +"l c #255A88", +"m c #255A9B", +"n c #295B8F", +"o c #9F4610", +"p c #984A17", +"q c #255EA5", +"r c #1761B1", +"s c #9A4A21", +"t c #A54C15", +"u c #475E79", +"v c #346399", +"w c #A2511E", +"x c #3E6792", +"y c #5C6272", +"z c #266BBB", +"A c #2271BD", +"B c #4D6C8F", +"C c #3C6FA5", +"D c #B15A26", +"E c #3472BA", +"F c #3373B4", +"G c #3479C1", +"H c #4178AE", +"I c #287ED1", +"J c #347CCA", +"K c #387FC7", +"L c #4380C1", +"M c #3A84D2", +"N c #5489C0", +"O c #488CD4", +"P c #648AB7", +"Q c #628DB2", +"R c #678DBA", +"S c #5691CC", +"T c #748CA8", +"U c #5F9AD7", +"V c #6D99CC", +"W c #74A4DA", +"X c #81A4C9", +"Y c #7AACDC", +"Z c #8DBCE9", +"` c #98C2EA", +" ", +" ", +" E E ", +" AUG EUA ", +" SW WS ", +" SY YS ", +" LZr rZL ", +" E`E cwcppc E`E ", +" YW pwh}h3}sp WY ", +" GXL w8hD8^3swD LXG ", +" VR is^]8h^ai9 RV ", +" zxS p8]]]]]]Dpptf Sxz ", +" JlO t}))))))))}io OlJ ", +" MgJ fo]!!!!!!!!8o JgM ", +" MbI ih}t!''''''8i IbM ", +" K6M ijht3,,,,,,!i M6K ", +" K6K otffa3;;;;;;a9 K6K ", +" K6Fq f ftia======a rF6K ", +" M1nz f!======a An1M ", +" Ib1K a*******29 K1bI ", +" rv1bJ c[%%%%%%%%a9 Jb1vr ", +" K::Fq c7%%%%%%%%%*2a9 mF::K ", +" Ag:1Le_############%_2eH1:gA ", +" K//:Hd{############{dH://K ", +" zv~~/Ck[%@@@@@@@@%[kC/~~vz ", +" Jg>>>gCy4!@++@!4yCg>>>gJ ", +" Jg---- 0.5) { PolyDrawModel(self); + self.drawmask = 0; } else { self.renderflags = 0; - R_AddEntity(self); + self.drawmask = MASK_NORMAL; } } @@ -1278,6 +1264,7 @@ void Net_WeaponComplain() { complain_weapon_type = ReadByte(); complain_weapon_time = time; + weapontime = time; // ping the weapon panel } // CSQC_Parse_TempEntity : Handles all temporary entity network data in the CSQC layer. @@ -1350,6 +1337,10 @@ float CSQC_Parse_TempEntity() Net_WeaponComplain(); bHandled = true; break; + case TE_CSQC_CR_MAXBULLETS: + cr_maxbullets = ReadByte(); + bHandled = true; + break; default: // No special logic for this temporary entity; return 0 so the engine can handle it bHandled = false; diff --git a/qcsrc/client/View.qc b/qcsrc/client/View.qc index d3a5ea6a2..215aa524e 100644 --- a/qcsrc/client/View.qc +++ b/qcsrc/client/View.qc @@ -79,11 +79,11 @@ void Porto_Draw() p = p - view_up * 16; if(idx-1 >= portal1_idx) { - Draw_CylindricLine(p, q, 4, "", 1, 0, '0 0 1', 0.5, DRAWFLAG_NORMAL); + Draw_CylindricLine(p, q, 4, "", 1, 0, '0 0 1', 0.5, DRAWFLAG_NORMAL, view_origin); } else { - Draw_CylindricLine(p, q, 4, "", 1, 0, '1 0 0', 0.5, DRAWFLAG_NORMAL); + Draw_CylindricLine(p, q, 4, "", 1, 0, '1 0 0', 0.5, DRAWFLAG_NORMAL, view_origin); } --idx; } @@ -102,7 +102,7 @@ void CheckForGamestartChange() { if (previous_game_starttime != startTime) { if ((time + 5.0) < startTime) { //if connecting to server while restart was active don't always play prepareforbattle - sound(self, CHAN_VOICE, strcat("announcer/", cvar_string("cl_announcer"), "/prepareforbattle.wav"), VOL_BASEVOICE, ATTN_NONE); + sound(world, CHAN_AUTO, strcat("announcer/", cvar_string("cl_announcer"), "/prepareforbattle.wav"), VOL_BASEVOICE, ATTN_NONE); } if (time < startTime) { restartAnnouncer = spawn(); @@ -338,7 +338,7 @@ void CSQC_common_hud(void); void PostInit(void); void CSQC_Demo_Camera(); -float HUD_WouldDrawScoreboard (); +float HUD_WouldDrawScoreboard(); float view_set; float camera_mode; float reticle_type; @@ -347,6 +347,7 @@ void CSQC_SPIDER_HUD(); void CSQC_RAPTOR_HUD(); vector freeze_pmove_org, freeze_input_angles; +entity nightvision_noise, nightvision_noise2; void CSQC_UpdateView(float w, float h) { @@ -354,6 +355,12 @@ void CSQC_UpdateView(float w, float h) float fov; float f, i, j; vector v, vo; + vector vf_size, vf_min; + + vf_size = R_SetView3fv(VF_SIZE); + vf_min = R_SetView3fv(VF_MIN); + vid_width = vf_size_x; + vid_height = vf_size_y; vector reticle_pos, reticle_size; @@ -375,7 +382,7 @@ void CSQC_UpdateView(float w, float h) input_angles = warpzone_fixview_cl_viewangles; view_angles = warpzone_fixview_angles; - if(cvar("cl_lockview") || autocvar__hud_configure) + if(cvar("cl_lockview") || (autocvar__hud_configure && spectatee_status <= 0)) { pmove_org = freeze_pmove_org; input_angles = view_angles = freeze_input_angles; @@ -398,9 +405,6 @@ void CSQC_UpdateView(float w, float h) view_set = 1; } - vid_width = w; - vid_height = h; - #ifdef BLURTEST if(time > blurtest_time0 && time < blurtest_time1) { @@ -464,7 +468,6 @@ void CSQC_UpdateView(float w, float h) } } - hud_accuracy_hud = cvar_or("hud_accuracy_hud", 1); ColorTranslateMode = cvar("cl_stripcolorcodes"); activeweapon = getstati(STAT_SWITCHWEAPON); f = cvar("teamplay"); @@ -488,6 +491,10 @@ void CSQC_UpdateView(float w, float h) // ALWAYS Clear Current Scene First R_ClearScene(); + // FIXME engine bug? VF_SIZE and VF_MIN are not restored to sensible values by this + R_SetView(VF_SIZE, vf_size); + R_SetView(VF_MIN, vf_min); + // Assign Standard Viewflags // Draw the World (and sky) R_SetView(VF_DRAWWORLD, 1); @@ -526,8 +533,6 @@ void CSQC_UpdateView(float w, float h) } // Draw the Crosshair - float scoreboard_active; - scoreboard_active = HUD_WouldDrawScoreboard(); R_SetView(VF_DRAWCROSSHAIR, 0); //Make sure engine crosshairs are always hidden // Draw the Engine Status Bar (the default Quake HUD) @@ -558,12 +563,64 @@ void CSQC_UpdateView(float w, float h) // next R_RenderScene call drawstring('0 0 0', "", '1 1 0', '1 1 1', 0, 0); + if(cvar("r_fakelight") >= 2 || cvar("r_fullbright")) + { + // apply night vision effect + vector rgb, tc_00, tc_01, tc_10, tc_11; + float a; + + if(!nightvision_noise) + { + nightvision_noise = spawn(); + nightvision_noise.classname = "nightvision_noise"; + } + if(!nightvision_noise2) + { + nightvision_noise2 = spawn(); + nightvision_noise2.classname = "nightvision_noise2"; + } + + // color tint in yellow + drawfill('0 0 0', cvar("vid_conwidth") * '1 0 0' + cvar("vid_conheight") * '0 1 0', '0.5 1 0.3', 1, DRAWFLAG_MODULATE); + + // draw BG + a = Noise_Pink(nightvision_noise, frametime * 1.5) * 0.05 + 0.15; + rgb = '1 1 1'; + tc_00 = '0 0 0' + '0.2 0 0' * sin(time * 0.3) + '0 0.3 0' * cos(time * 0.7); + tc_01 = '0 2.25 0' + '0.6 0 0' * cos(time * 1.2) - '0 0.3 0' * sin(time * 2.2); + tc_10 = '1.5 0 0' - '0.2 0 0' * sin(time * 0.5) + '0 0.5 0' * cos(time * 1.7); + //tc_11 = '1 1 0' + '0.6 0 0' * sin(time * 0.6) + '0 0.3 0' * cos(time * 0.1); + tc_11 = tc_01 + tc_10 - tc_00; + R_BeginPolygon("gfx/nightvision-bg.tga", DRAWFLAG_ADDITIVE); + R_PolygonVertex('0 0 0', tc_00, rgb, a); + R_PolygonVertex(cvar("vid_conwidth") * '1 0 0', tc_10, rgb, a); + R_PolygonVertex(cvar("vid_conwidth") * '1 0 0' + cvar("vid_conheight") * '0 1 0', tc_11, rgb, a); + R_PolygonVertex(cvar("vid_conheight") * '0 1 0', tc_01, rgb, a); + R_EndPolygon(); + + // draw FG + a = Noise_Pink(nightvision_noise2, frametime * 0.1) * 0.05 + 0.12; + rgb = '0.3 0.6 0.4' + '0.1 0.4 0.2' * Noise_White(nightvision_noise2, frametime); + tc_00 = '0 0 0' + '1 0 0' * Noise_White(nightvision_noise2, frametime) + '0 1 0' * Noise_White(nightvision_noise2, frametime); + tc_01 = tc_00 + '0 3 0' * (1 + Noise_White(nightvision_noise2, frametime) * 0.2); + tc_10 = tc_00 + '2 0 0' * (1 + Noise_White(nightvision_noise2, frametime) * 0.3); + tc_11 = tc_01 + tc_10 - tc_00; + R_BeginPolygon("gfx/nightvision-fg.tga", DRAWFLAG_ADDITIVE); + R_PolygonVertex('0 0 0', tc_00, rgb, a); + R_PolygonVertex(cvar("vid_conwidth") * '1 0 0', tc_10, rgb, a); + R_PolygonVertex(cvar("vid_conwidth") * '1 0 0' + cvar("vid_conheight") * '0 1 0', tc_11, rgb, a); + R_PolygonVertex(cvar("vid_conheight") * '0 1 0', tc_01, rgb, a); + R_EndPolygon(); + } + // Draw the aiming reticle for weapons that use it // reticle_type is changed to the item we are zooming / aiming with, to decide which reticle to use // It must be a persisted float for fading out to work properly (you let go of the zoom button for // the view to go back to normal, so reticle_type would become 0 as we fade out) if(spectatee_status || getstati(STAT_HEALTH) <= 0) reticle_type = 0; // prevent reticle from showing during the respawn zoom effect or for spectators + else if(activeweapon == WEP_NEX && (button_zoom || zoomscript_caught) || activeweapon == WEP_CAMPINGRIFLE && (button_zoom || zoomscript_caught) || activeweapon == WEP_MINSTANEX && (button_zoom || zoomscript_caught)) + reticle_type = 2; // nex zoom else if(button_zoom || zoomscript_caught) reticle_type = 1; // normal zoom else if(activeweapon == WEP_NEX && button_attack2 || activeweapon == WEP_CAMPINGRIFLE && button_attack2) @@ -623,17 +680,12 @@ void CSQC_UpdateView(float w, float h) self.draw2d(); self = e; - // draw hud - if(cvar("r_letterbox") == 0) { - HUD_DrawCenterPrint(); // draw centerprint messages even if viewsize >= 120 - } + scoreboard_active = HUD_WouldDrawScoreboard(); float hud; hud = getstati(STAT_HUD); if(hud == HUD_SPIDERBOT) - { CSQC_SPIDER_HUD(); - } else if(hud == HUD_WAKIZASHI) CSQC_WAKIZASHI_HUD(); else if(hud == HUD_RAPTOR) @@ -645,7 +697,7 @@ void CSQC_UpdateView(float w, float h) CSQC_common_hud(); // crosshair goes VERY LAST - if(!scoreboard_active && !camera_active) { + if(!scoreboard_active && !camera_active && intermission != 2) { // TrueAim check float shottype; float bullets, ring_scale; @@ -771,17 +823,28 @@ void CSQC_UpdateView(float w, float h) wcross_scale *= 1 - cvar("_menu_alpha"); wcross_alpha *= 1 - cvar("_menu_alpha"); + ring_scale = cvar("crosshair_ring_size"); + + float f, a; + wcross_size = drawgetimagesize(wcross_name) * wcross_scale; + + float nex_charge; + nex_charge = getstatf(STAT_NEX_CHARGE); + // ring around crosshair representing bullets left in camping rifle clip - if (activeweapon == WEP_CAMPINGRIFLE) + if (activeweapon == WEP_CAMPINGRIFLE && cr_maxbullets) { - ring_scale = cvar("crosshair_campingrifle_ring_size"); - bullets = bound(0, getstati(STAT_BULLETS_LOADED), 4); - } - else - bullets = 0; + bullets = getstati(STAT_BULLETS_LOADED); + f = bound(0, bullets / cr_maxbullets, 1); -#define CROSSHAIR_DRAW_RING(i,j,sz,wcross_name,wcross_alpha) \ - drawpic(wcross_origin - ('0.5 0 0' * (sz * wcross_size_x * ring_scale + i * wcross_blur) + '0 0.5 0' * (sz * wcross_size_y * ring_scale + j * wcross_blur)), strcat("gfx/rifle_ring_", ftos(bullets)), sz * wcross_size * ring_scale, wcross_color, wcross_alpha, DRAWFLAG_NORMAL) + a = cvar("crosshair_campingrifle_bulletcounter_alpha"); + DrawCircleClippedPic(wcross_origin, wcross_size_x * ring_scale, "gfx/crosshair_ring.tga", f, wcross_color, wcross_alpha * a, DRAWFLAG_ADDITIVE); + } + else if (activeweapon == WEP_NEX && nex_charge) // ring around crosshair representing velocity-dependent damage for the nex + { + a = cvar("crosshair_nexvelocity_alpha"); + DrawCircleClippedPic(wcross_origin, wcross_size_x * ring_scale, "gfx/crosshair_ring.tga", nex_charge, wcross_color, wcross_alpha * a, DRAWFLAG_ADDITIVE); + } #define CROSSHAIR_DO_BLUR(M,sz,wcross_name,wcross_alpha) \ do \ @@ -818,11 +881,11 @@ void CSQC_UpdateView(float w, float h) } wcross_size = drawgetimagesize(wcross_name) * wcross_scale; - if(bullets) - { - CROSSHAIR_DO_BLUR(CROSSHAIR_DRAW_RING, wcross_resolution, wcross_name, wcross_alpha); - } CROSSHAIR_DRAW(wcross_resolution, wcross_name, wcross_alpha * f); + + if(cvar("crosshair_dot")) + CROSSHAIR_DRAW(wcross_resolution * cvar("crosshair_dot_size"), "gfx/crosshairdot.tga", wcross_alpha * f * cvar("crosshair_dot_alpha")); + wcross_name_alpha_goal_prev = f; } } @@ -883,6 +946,11 @@ void CSQC_UpdateView(float w, float h) if(autocvar__hud_configure) HUD_Panel_Mouse(); + + // let's reset the view back to normal for the end + R_SetView(VF_MIN, '0 0 0'); + R_SetView(VF_SIZE, '1 0 0' * w + '0 1 0' * h); + // be safe against triggerbots until everyone has the fixed engine // this call is meant to overwrite the trace globals by something // unsuspicious @@ -1194,9 +1262,13 @@ void CSQC_common_hud(void) case HUD_NORMAL: // do some accuracy var caching float i; + if(cvar_string("hud_panel_weapons_accuracy_color_levels") != acc_color_levels) if(!(gametype == GAME_RACE || gametype == GAME_CTS)) { - acc_levels = tokenize(cvar_string("hud_panel_weapons_accuracy_color_levels")); + if(acc_color_levels) + strunzone(acc_color_levels); + acc_color_levels = strzone(cvar_string("hud_panel_weapons_accuracy_color_levels")); + acc_levels = tokenize(acc_color_levels); if (acc_levels > MAX_ACCURACY_LEVELS) acc_levels = MAX_ACCURACY_LEVELS; @@ -1204,23 +1276,29 @@ void CSQC_common_hud(void) acc_lev[i] = stof(argv(i)); } - // hud first - HUD_Main(); + HUD_Main(); // always run these functions for alpha checks + HUD_DrawScoreboard(); - // scoreboard/accuracy - if (intermission == 2 && !scoreboard_showaccuracy && !scoreboard_showscores) // map voting screen + if (scoreboard_active) // scoreboard/accuracy + { + HUD_Reset(); + // HUD_DrawScoreboard takes care of centerprint_start + } + else if (intermission == 2) // map voting screen { HUD_FinaleOverlay(); HUD_Reset(); - } - else if(scoreboard_showaccuracy && spectatee_status != -1) - HUD_DrawAccuracyStats(); - else - HUD_DrawScoreboard(); - if (scoreboard_showscores || scoreboard_showaccuracy || scoreboard_showscores_force || getstati(STAT_HEALTH) <= 0 || intermission == 1) - HUD_Reset(); + centerprint_start_x = 0; + centerprint_start_y = cvar("scr_centerpos") * vid_conheight; + } + else // hud + { + centerprint_start_x = 0; + centerprint_start_y = cvar("scr_centerpos") * vid_conheight; + } + HUD_DrawCenterPrint(); break; case HUD_SPIDERBOT: diff --git a/qcsrc/client/autocvars.qh b/qcsrc/client/autocvars.qh index 0c2df0e63..a98b70683 100644 --- a/qcsrc/client/autocvars.qh +++ b/qcsrc/client/autocvars.qh @@ -10,7 +10,7 @@ var float autocvar_cl_gentle; var float autocvar_cl_gentle_gibs; var float autocvar_cl_gentle_messages; -var float autocvar_hud_color_bg_team; +var float autocvar_scoreboard_color_bg_team; var float autocvar__menu_alpha; @@ -234,3 +234,5 @@ var string autocvar_hud_panel_infomessages_bg_alpha; var string autocvar_hud_panel_infomessages_bg_border; var string autocvar_hud_panel_infomessages_bg_padding; var float autocvar_hud_panel_infomessages_flip; + +var float autocvar_scoreboard_border_thickness; diff --git a/qcsrc/client/bgmscript.qc b/qcsrc/client/bgmscript.qc index 587a2e96c..c23b425ae 100644 --- a/qcsrc/client/bgmscript.qc +++ b/qcsrc/client/bgmscript.qc @@ -167,7 +167,6 @@ float GetTimeForAmplitude(entity e, float amp) float BGMScript(entity e) { - float t; float amp, vel; if(e.bgmscript == "") @@ -178,34 +177,33 @@ float BGMScript(entity e) e.just_toggled = FALSE; - t = gettime(GETTIME_CDTRACK); - if(t < 0) + if(bgmtime < 0) return -1; - if(t < e.bgmscripttime) + if(bgmtime < e.bgmscripttime) { //print("reset ", e.bgmscript, "\n"); amp = GetCurrentAmplitude(e, e.bgmscripttime - e.bgmscriptstatetime + drawframetime); e.bgmscriptline = e.bgmscriptline0; - e.bgmscripttime = t; + e.bgmscripttime = bgmtime; // treat this as a stop event for all notes, to prevent sticking keys e.bgmscriptstate = FALSE; e.bgmscriptvolume = 1; - e.bgmscriptstatetime = t - GetTimeForAmplitude(e, amp); + e.bgmscriptstatetime = bgmtime - GetTimeForAmplitude(e, amp); } // find the CURRENT line for(;;) { tokenize_console(bufstr_get(bgmscriptbuf, e.bgmscriptline)); - if(stof(argv(1)) >= t || argv(0) != e.bgmscript) + if(stof(argv(1)) >= bgmtime || argv(0) != e.bgmscript) { - e.bgmscripttime = t; - return GetCurrentAmplitude(e, t - e.bgmscriptstatetime); + e.bgmscripttime = bgmtime; + return GetCurrentAmplitude(e, bgmtime - e.bgmscriptstatetime); } - else if(t >= stof(argv(1))) + else if(bgmtime >= stof(argv(1))) { e.bgmscriptline += 1; e.bgmscripttime = stof(argv(1)); diff --git a/qcsrc/client/casings.qc b/qcsrc/client/casings.qc index e8e3073b8..348e4a1a6 100644 --- a/qcsrc/client/casings.qc +++ b/qcsrc/client/casings.qc @@ -20,9 +20,10 @@ void Casing_Draw() self.alpha = bound(0, self.cnt - time, 1); if(self.alpha < ALPHA_MIN_VISIBLE) + { Casing_Delete(); - else - R_AddEntity(self); + self.drawmask = 0; + } } void Casing_Touch() @@ -85,6 +86,7 @@ void Ent_Casing(float isNew) casing.angles_x = ReadByte() * 360 / 256; casing.angles_y = ReadByte() * 360 / 256; casing.angles_z = ReadByte() * 360 / 256; + casing.drawmask = MASK_NORMAL; if(cvar("cl_casings") && isNew) { casing.draw = Casing_Draw; diff --git a/qcsrc/client/csqc_builtins.qc b/qcsrc/client/csqc_builtins.qc index ec2ab9a31..760197a27 100644 --- a/qcsrc/client/csqc_builtins.qc +++ b/qcsrc/client/csqc_builtins.qc @@ -79,6 +79,7 @@ void () R_ClearScene = #300; void (float mask) R_AddEntities = #301; void (entity e) R_AddEntity = #302; float (float property, ...) R_SetView = #303; +vector (float property, ...) R_SetView3fv = #303; void () R_RenderScene = #304; void (vector org, float radius, vector rgb) R_AddDynamicLight = #305; void () R_CalcRefDef = #306; @@ -292,6 +293,7 @@ entity(vector org, float rad) findradius = #22; string(float uselocaltime, string format, ...) strftime = #478; float(float timer) gettime = #519; +#define GETTIME_REALTIME 1 #define GETTIME_CDTRACK 4 float(string s) tokenize_console = #514; diff --git a/qcsrc/client/effects.qc b/qcsrc/client/effects.qc index bbee65800..2e946fc83 100644 --- a/qcsrc/client/effects.qc +++ b/qcsrc/client/effects.qc @@ -10,8 +10,8 @@ void SUB_Remove() void b_draw() { - //Draw_CylindricLine(self.fx_start, self.fx_end, self.fx_with, self.fx_texture, 0, time * 3, '1 1 1', 0.7, DRAWFLAG_ADDITIVE); - Draw_CylindricLine(self.fx_start, self.fx_end, self.fx_with, self.fx_texture, (self.fx_with/256), 0, '1 1 1', 1, DRAWFLAG_ADDITIVE); + //Draw_CylindricLine(self.fx_start, self.fx_end, self.fx_with, self.fx_texture, 0, time * 3, '1 1 1', 0.7, DRAWFLAG_ADDITIVE, view_origin); + Draw_CylindricLine(self.fx_start, self.fx_end, self.fx_with, self.fx_texture, (self.fx_with/256), 0, '1 1 1', 1, DRAWFLAG_ADDITIVE, view_origin); } void b_make(vector s,vector e, string t,float l,float z) diff --git a/qcsrc/client/gibs.qc b/qcsrc/client/gibs.qc index f395fb6a7..78826f8f3 100644 --- a/qcsrc/client/gibs.qc +++ b/qcsrc/client/gibs.qc @@ -97,9 +97,10 @@ void Gib_Draw() self.alpha = bound(0, self.nextthink - time, 1); if(self.alpha < ALPHA_MIN_VISIBLE) + { + self.drawmask = 0; Gib_Delete(); - else - R_AddEntity(self); + } } void TossGib (string mdlname, vector org, vector vconst, vector vrand, float specnum, float destroyontouch, float issilent) @@ -130,6 +131,7 @@ void TossGib (string mdlname, vector org, vector vconst, vector vrand, float spe gib.damageforcescale = cvar_or("cl_gibs_damageforcescale", 3.5); gib.nextthink = time + cvar_or("cl_gibs_lifetime", 14) * (1 + prandom() * 0.15); + gib.drawmask = MASK_NORMAL; RubbleLimit("gib", cvar_or("cl_gibs_maxcount",100), Gib_Delete); } diff --git a/qcsrc/client/hook.qc b/qcsrc/client/hook.qc index b769947ee..c1e8383aa 100644 --- a/qcsrc/client/hook.qc +++ b/qcsrc/client/hook.qc @@ -5,7 +5,7 @@ .float HookSilent; .float HookRange; -void Draw_CylindricLine(vector from, vector to, float thickness, string texture, float aspect, float shift, vector rgb, float alpha, float drawflag) +void Draw_CylindricLine(vector from, vector to, float thickness, string texture, float aspect, float shift, vector rgb, float alpha, float drawflag, vector vieworg) { // I want to draw a quad... // from and to are MIDPOINTS. @@ -17,7 +17,7 @@ void Draw_CylindricLine(vector from, vector to, float thickness, string texture, length_tex = aspect * vlen(to - from) / thickness; // direction is perpendicular to the view normal, and perpendicular to the axis - thickdir = normalize(cross(axis, view_origin - from)); + thickdir = normalize(cross(axis, vieworg - from)); /* print("from ", vtos(from), "\n"); @@ -46,11 +46,14 @@ float Draw_GrapplingHook_trace_callback_a; void Draw_GrapplingHook_trace_callback(vector start, vector hit, vector end) { float i; + vector vorg; + vorg = WarpZone_TransformOrigin(WarpZone_trace_transform, view_origin); for(i = 0; i < Draw_GrapplingHook_trace_callback_a; ++i) - Draw_CylindricLine(hit, start, 8, Draw_GrapplingHook_trace_callback_tex, 0.25, Draw_GrapplingHook_trace_callback_rnd, Draw_GrapplingHook_trace_callback_rgb, min(1, Draw_GrapplingHook_trace_callback_a - i), DRAWFLAG_NORMAL); + Draw_CylindricLine(hit, start, 8, Draw_GrapplingHook_trace_callback_tex, 0.25, Draw_GrapplingHook_trace_callback_rnd, Draw_GrapplingHook_trace_callback_rgb, min(1, Draw_GrapplingHook_trace_callback_a - i), DRAWFLAG_NORMAL, vorg); Draw_GrapplingHook_trace_callback_rnd += 0.25 * vlen(hit - start) / 8; } +.float teleport_time; void Draw_GrapplingHook() { vector a, b, atrans; @@ -61,6 +64,13 @@ void Draw_GrapplingHook() vector vs; float intensity, offset; + if(self.teleport_time) + if(time > self.teleport_time) + { + sound (self, CHAN_PROJECTILE, "misc/null.wav", VOL_BASE, ATTN_NORM); // safeguard + self.teleport_time = 0; + } + InterpolateOrigin_Do(); s = cvar("cl_gunalign"); @@ -251,7 +261,7 @@ void Ent_ReadHook(float bIsNew, float type) InterpolateOrigin_Note(); - if(bIsNew) + if(bIsNew || !self.teleport_time) { self.draw = Draw_GrapplingHook; self.entremove = Remove_GrapplingHook; @@ -272,6 +282,8 @@ void Ent_ReadHook(float bIsNew, float type) break; } } + + self.teleport_time = time + 10; } void Hook_Precache() diff --git a/qcsrc/client/hud.qc b/qcsrc/client/hud.qc index f2b900fa9..357f8a0e3 100644 --- a/qcsrc/client/hud.qc +++ b/qcsrc/client/hud.qc @@ -131,7 +131,7 @@ float stringwidth_nocolors(string s, vector theSize) #define CENTERPRINT_MAX_LINES 30 string centerprint_messages[CENTERPRINT_MAX_LINES]; float centerprint_width[CENTERPRINT_MAX_LINES]; -vector centerprint_start; +float centerprint_time; float centerprint_expire; float centerprint_num; float centerprint_offset_hint; @@ -182,6 +182,8 @@ void centerprint(string strMessage) while(getWrappedLine_remaining) { s = getWrappedLine(vid_conwidth * 0.75, centerprint_fontsize, stringwidth_colors); + if(centerprint_messages[i] != s) // don't fade the same message in, looks stupid + centerprint_time = time; if(centerprint_messages[i]) strunzone(centerprint_messages[i]); centerprint_messages[i] = strzone(s); @@ -208,8 +210,6 @@ void centerprint(string strMessage) if(havail > vid_conheight - 70) havail = vid_conheight - 70; // avoid overlapping HUD - centerprint_start_x = 0; - #if 0 float forbiddenmin, forbiddenmax, allowedmin, allowedmax, preferred; @@ -260,17 +260,10 @@ void centerprint(string strMessage) centerprint_start_y = bound(forbiddenmax, preferred, allowedmax); } #else - centerprint_start_y = - min( - max( - max(scoreboard_bottom, vid_conheight * 0.5 + 16), - (havail - h)/2 - ), - havail - h - ); #endif centerprint_num = i; + centerprint_expire = time + cvar("scr_centertime"); } @@ -279,32 +272,38 @@ void HUD_DrawCenterPrint (void) float i; vector pos; string ts; - float a; - - //if(time > centerprint_expire) - // return; + float a, sz; - //a = bound(0, 1 - 2 * (time - centerprint_expire), 1); - a = bound(0, 1 - 4 * (time - centerprint_expire), 1); - //sz = 1.2 / (a + 0.2); + if(time - centerprint_time < 0.25) + a = (time - centerprint_time) / 0.25; + else + a = bound(0, 1 - 4 * (time - centerprint_expire), 1); if(a <= 0) return; + sz = 0.8 + (a / 5); + + if(centerprint_num * cvar("scr_centersize") > 24 && scoreboard_active) // 24 = height of Scoreboard text + centerprint_start_y = scoreboard_bottom + centerprint_fontsize_y; + pos = centerprint_start; for (i=0; i vid_conwidth) + tmp_size_x = vid_conwidth - panel_pos_x; + if (panel_pos_y + panel_size_copied_y > vid_conheight) + tmp_size_y = vid_conheight - panel_pos_y; + + if (panel_size == tmp_size) + return true; + + // backup first! + panel_pos_backup = panel_pos; + panel_size_backup = panel_size; + highlightedPanel_backup = highlightedPanel_prev; + + string s; + s = strcat(ftos(tmp_size_x/vid_conwidth), " ", ftos(tmp_size_y/vid_conheight)); + cvar_set(strcat("hud_panel_", panel_name, "_size"), s); + } + else if(nPrimary == 'z') // undo last action + { + if (bInputType == 1) + return true; + //restore previous values + if (highlightedPanel_backup != -1) + { + HUD_Panel_GetName(highlightedPanel_backup) + string s; + s = strcat(ftos(panel_pos_backup_x/vid_conwidth), " ", ftos(panel_pos_backup_y/vid_conheight)); + cvar_set(strcat("hud_panel_", panel_name, "_pos"), s); + s = strcat(ftos(panel_size_backup_x/vid_conwidth), " ", ftos(panel_size_backup_y/vid_conheight)); + cvar_set(strcat("hud_panel_", panel_name, "_size"), s); + highlightedPanel_backup = -1; + } + } + } else if(nPrimary == K_UPARROW || nPrimary == K_DOWNARROW || nPrimary == K_LEFTARROW || nPrimary == K_RIGHTARROW) { if (bInputType == 1) @@ -1226,21 +1314,26 @@ void HUD_Panel_Highlight() } float highlightcheck; +vector prev_pos, prev_size; void HUD_Panel_Mouse() { // TODO: needs better check... is there any float that contains the current state of the menu? _menu_alpha isn't apparently updated the frame the menu gets enabled - if (menu_enabled == 0) // menu dialog closed, enable normal alpha stuff again - disable_menu_alphacheck = 0; if (autocvar__menu_alpha == 0 && time - menu_enabled_time > 0.5) menu_enabled = 0; /* - print("Disable menu_alphacheck: ", ftos(disable_menu_alphacheck), "\n"); + print("menu_enabled: ", ftos(menu_enabled), "\n"); print("Highlighted: ", ftos(highlightedPanel), "\n"); print("Menu alpha: ", cvar_string("_menu_alpha"), "\n"); */ - if(mouseClicked == 0 && disable_menu_alphacheck != 2 && highlightedPanel >= 0) { // don't reset these variables in disable_menu_alphacheck mode 2! + // instantly hide the editor cursor if we open the HUDExit dialog + // as hud_fade_alpha doesn't decrease to 0 in this case + // TODO: find a way to fade the cursor out even in this case + if(menu_enabled == 1 || (menu_enabled == 2 && !hud_fade_alpha)) + return; + + if(mouseClicked == 0 && menu_enabled != 2 && highlightedPanel >= 0) { // don't reset these variables in menu_enabled mode 2! highlightedPanel = -1; highlightedAction = 0; } @@ -1255,9 +1348,28 @@ void HUD_Panel_Mouse() if(mouseClicked) { if(prevMouseClicked == 0) + { HUD_Panel_Highlight(); // sets highlightedPanel, highlightedAction, panel_click_distance, panel_click_resizeorigin + // and calls HUD_Panel_UpdatePosSizeForId() for the highlighted panel + prev_pos = panel_pos; + prev_size = panel_size; + } + else + HUD_Panel_UpdatePosSizeForId(highlightedPanel) - hud_configure_checkcollisions = (!(hudShiftState & S_CTRL) && autocvar_hud_configure_checkcollisions); + if (prev_pos != panel_pos || prev_size != panel_size) + { + hud_configure_checkcollisions = (!(hudShiftState & S_CTRL) && autocvar_hud_configure_checkcollisions); + // backup! + panel_pos_backup = prev_pos; + panel_size_backup = prev_size; + highlightedPanel_backup = highlightedPanel; + } + else + // in case the clicked panel is inside another panel and we aren't + // moving it, avoid the immediate "fix" of its position/size + // (often unwanted and hateful) by disabling collisions check + hud_configure_checkcollisions = false; if(highlightedAction == 1) HUD_Panel_SetPos(mousepos - panel_click_distance); @@ -1284,8 +1396,7 @@ void HUD_Panel_Mouse() if(time - prevMouseClickedTime < 0.4 && prevMouseClicked == 0 && prevMouseClickedPos == mousepos && highlightedPanel >= 0) { mouseClicked = 0; // to prevent spam, I guess. - disable_menu_alphacheck = 2; - menu_enabled = 1; + menu_enabled = 2; menu_enabled_time = time; HUD_Panel_GetName(highlightedPanel) localcmd("menu_showhudoptions ", panel_name, "\n"); @@ -1307,13 +1418,13 @@ void HUD_Panel_Mouse() cursorsize = '32 32 0'; if(highlightcheck == 0) - drawpic(mousepos, strcat("gfx/menu/", cvar_string("menu_skin"), "/cursor.tga"), '32 32 0', '1 1 1', 1, DRAWFLAG_NORMAL); + drawpic(mousepos, strcat("gfx/menu/", cvar_string("menu_skin"), "/cursor.tga"), '32 32 0', '1 1 1', hud_fade_alpha, DRAWFLAG_NORMAL); else if(highlightcheck == 1) - drawpic(mousepos - cursorsize * 0.5, strcat("gfx/menu/", cvar_string("menu_skin"), "/cursor_move.tga"), '32 32 0', '1 1 1', 1, DRAWFLAG_NORMAL); + drawpic(mousepos - cursorsize * 0.5, strcat("gfx/menu/", cvar_string("menu_skin"), "/cursor_move.tga"), '32 32 0', '1 1 1', hud_fade_alpha, DRAWFLAG_NORMAL); else if(highlightcheck == 2) - drawpic(mousepos - cursorsize * 0.5, strcat("gfx/menu/", cvar_string("menu_skin"), "/cursor_resize.tga"), '32 32 0', '1 1 1', 1, DRAWFLAG_NORMAL); + drawpic(mousepos - cursorsize * 0.5, strcat("gfx/menu/", cvar_string("menu_skin"), "/cursor_resize.tga"), '32 32 0', '1 1 1', hud_fade_alpha, DRAWFLAG_NORMAL); else - drawpic(mousepos - cursorsize * 0.5, strcat("gfx/menu/", cvar_string("menu_skin"), "/cursor_resize2.tga"), '32 32 0', '1 1 1', 1, DRAWFLAG_NORMAL); + drawpic(mousepos - cursorsize * 0.5, strcat("gfx/menu/", cvar_string("menu_skin"), "/cursor_resize2.tga"), '32 32 0', '1 1 1', hud_fade_alpha, DRAWFLAG_NORMAL); prevMouseClicked = mouseClicked; } @@ -1366,6 +1477,7 @@ float GetAmmoTypeForWep(float i) case WEP_UZI: return 1; case WEP_CAMPINGRIFLE: return 1; case WEP_GRENADE_LAUNCHER: return 2; + case WEP_MINE_LAYER: return 2; case WEP_ELECTRO: return 3; case WEP_CRYLINK: return 3; case WEP_HLAC: return 3; @@ -1385,14 +1497,94 @@ void HUD_Weapons(void) if(!autocvar_hud_panel_weapons && !autocvar__hud_configure) return; + float timeout = cvar("hud_panel_weapons_timeout"); + float timeout_effect_length, timein_effect_length; + if (cvar("hud_panel_weapons_timeout_effect") == 0) + { + timeout_effect_length = 0; + timein_effect_length = 0; + } + else + { + timeout_effect_length = 0.75; + timein_effect_length = 0.375; + } + + if (timeout && time >= weapontime + timeout + timeout_effect_length && !autocvar__hud_configure) + { + weaponprevtime = time; + return; + } + active_panel = HUD_PANEL_WEAPONS; HUD_Panel_UpdateCvars(weapons); - vector pos, mySize; - float i, weapid, fade, weapon_stats, weapon_number, weapon_cnt; - pos = panel_pos; - mySize = panel_size; + if (timeout && time >= weapontime + timeout && !autocvar__hud_configure) + { + float f = (time - (weapontime + timeout)) / timeout_effect_length; + if (cvar("hud_panel_weapons_timeout_effect")) + { + panel_bg_alpha *= (1 - f); + panel_fg_alpha *= (1 - f); + } + if (cvar("hud_panel_weapons_timeout_effect") == 1) + { + f *= f; // for a cooler movement + vector center; + center_x = panel_pos_x + panel_size_x/2; + center_y = panel_pos_y + panel_size_y/2; + float screen_ar = vid_conwidth/vid_conheight; + if (center_x/center_y < screen_ar) //bottom left + { + if ((vid_conwidth - center_x)/center_y < screen_ar) //bottom + panel_pos_y += f * (vid_conheight - panel_pos_y); + else //left + panel_pos_x -= f * (panel_pos_x + panel_size_x); + } + else //top right + { + if ((vid_conwidth - center_x)/center_y < screen_ar) //right + panel_pos_x += f * (vid_conwidth - panel_pos_x); + else //top + panel_pos_y -= f * (panel_pos_y + panel_size_y); + } + } + weaponprevtime = time - (1 - f) * timein_effect_length; + } + else if (timeout && time < weaponprevtime + timein_effect_length && !autocvar__hud_configure) + { + float f = (time - weaponprevtime) / timein_effect_length; + if (cvar("hud_panel_weapons_timeout_effect")) + { + panel_bg_alpha *= (f); + panel_fg_alpha *= (f); + } + if (cvar("hud_panel_weapons_timeout_effect") == 1) + { + f *= f; // for a cooler movement + f = 1 - f; + vector center; + center_x = panel_pos_x + panel_size_x/2; + center_y = panel_pos_y + panel_size_y/2; + float screen_ar = vid_conwidth/vid_conheight; + if (center_x/center_y < screen_ar) //bottom left + { + if ((vid_conwidth - center_x)/center_y < screen_ar) //bottom + panel_pos_y += f * (vid_conheight - panel_pos_y); + else //left + panel_pos_x -= f * (panel_pos_x + panel_size_x); + } + else //top right + { + if ((vid_conwidth - center_x)/center_y < screen_ar) //right + panel_pos_x += f * (vid_conwidth - panel_pos_x); + else //top + panel_pos_y -= f * (panel_pos_y + panel_size_y); + } + } + } + float i, weapid, fade, weapon_stats, weapon_number, weapon_cnt; weapon_cnt = 0; for(i = WEP_FIRST; i <= WEP_LAST; ++i) { @@ -1425,8 +1617,8 @@ void HUD_Weapons(void) HUD_Panel_DrawBg(1); if(panel_bg_padding) { - pos += '1 1 0' * panel_bg_padding; - mySize -= '2 2 0' * panel_bg_padding; + panel_pos += '1 1 0' * panel_bg_padding; + panel_size -= '2 2 0' * panel_bg_padding; } // hits @@ -1449,7 +1641,7 @@ void HUD_Weapons(void) HUD_Weapons_Clear(); float rows, columns; - rows = mySize_y/mySize_x; + rows = panel_size_y/panel_size_x; rows = bound(1, floor((sqrt(4 * autocvar_hud_panel_weapons_aspect * rows * WEP_COUNT + rows * rows) + rows + 0.5) / 2), WEP_COUNT); columns = ceil(WEP_COUNT/rows); @@ -1465,10 +1657,14 @@ void HUD_Weapons(void) vector wpnpos; vector wpnsize; + float show_accuracy; + if(autocvar_hud_panel_weapons_accuracy && acc_levels) + show_accuracy = true; + for(i = 0; i < weapon_cnt; ++i) { - wpnpos = pos + eX * column * mySize_x*(1/columns) + eY * row * mySize_y*(1/rows); - wpnsize = eX * mySize_x*(1/columns) + eY * mySize_y*(1/rows); + wpnpos = panel_pos + eX * column * panel_size_x*(1/columns) + eY * row * panel_size_y*(1/rows); + wpnsize = eX * panel_size_x*(1/columns) + eY * panel_size_y*(1/rows); self = weaponorder[i]; weapid = self.impulse; @@ -1478,7 +1674,7 @@ void HUD_Weapons(void) drawpic_aspect_skin(wpnpos, "weapon_current_bg", wpnsize, '1 1 1', fade * panel_fg_alpha, DRAWFLAG_NORMAL); // draw the weapon accuracy - if(acc_levels) + if(show_accuracy) { float weapon_hit, weapon_damage; weapon_damage = weapon_fired[self.weapon-WEP_FIRST]; @@ -1510,9 +1706,9 @@ void HUD_Weapons(void) drawpic_aspect_skin(wpnpos, strcat("weapon", self.netname), wpnsize, '1 1 1', fade * panel_fg_alpha, DRAWFLAG_NORMAL); if(autocvar_hud_panel_weapons_label == 1) // weapon number - drawstring(wpnpos, ftos(weapid), '1 1 0' * 0.5 * mySize_y*(1/rows), '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL); + drawstring(wpnpos, ftos(weapid), '1 1 0' * 0.5 * panel_size_y*(1/rows), '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL); else if(autocvar_hud_panel_weapons_label == 2) // bind - drawstring(wpnpos, getcommandkey(ftos(weapid), strcat("impulse ", ftos(weapid))), '1 1 0' * 0.5 * mySize_y*(1/rows), '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL); + drawstring(wpnpos, getcommandkey(ftos(weapid), strcat("impulse ", ftos(weapid))), '1 1 0' * 0.5 * panel_size_y*(1/rows), '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL); // draw ammo status bar if(autocvar_hud_panel_weapons_ammo && weapid != WEP_TUBA && weapid != WEP_LASER && weapid != WEP_PORTO) @@ -1845,10 +2041,17 @@ void HUD_Powerups(void) { pos = panel_pos; mySize = panel_size; - float strength_time, shield_time; - - strength_time = bound(0, getstatf(STAT_STRENGTH_FINISHED) - time, 99); - shield_time = bound(0, getstatf(STAT_INVINCIBLE_FINISHED) - time, 99); + float strength_time, shield_time; + if(autocvar__hud_configure) + { + strength_time = 15; + shield_time = 27; + } + else + { + strength_time = bound(0, getstatf(STAT_STRENGTH_FINISHED) - time, 99); + shield_time = bound(0, getstatf(STAT_INVINCIBLE_FINISHED) - time, 99); + } HUD_Panel_DrawBg(bound(0, max(strength_time, shield_time), 1)); if(panel_bg_padding) @@ -1857,12 +2060,6 @@ void HUD_Powerups(void) { mySize -= '2 2 0' * panel_bg_padding; } - if(autocvar__hud_configure) - { - strength_time = 15; - shield_time = 27; - } - vector barpos, barsize; vector picpos; vector numpos; @@ -2062,12 +2259,10 @@ void HUD_HealthArmor(void) mySize -= '2 2 0' * panel_bg_padding; } - float armor, health; + float armor, health, fuel; armor = getstati(STAT_ARMOR); health = getstati(STAT_HEALTH); - - float fuel; - fuel = getstati(GetAmmoStat(4)); // how much fuel do we have? + fuel = getstati(STAT_FUEL); if(autocvar__hud_configure) { @@ -2391,7 +2586,7 @@ void HUD_KillNotify_Push(string attacker, string victim, float actiontype, float killnotify_victims[0] = strzone(victim); } -void HUD_KillNotify(string s1, string s2, string s3, float type, float msg) +void HUD_KillNotify(string s1, string s2, string s3, float type, float msg) // s1 = attacker, s2 = victim { float w; float alsoprint, gentle; @@ -2472,96 +2667,104 @@ void HUD_KillNotify(string s1, string s2, string s3, float type, float msg) } else if(type == KILL_FIRST_BLOOD) print("^1",s1, "^1 drew first blood", "\n"); - // TODO: icon! - else if (type == DEATH_TELEFRAG) - print ("^1",s1, "^1 was telefragged by ", s2, "\n"); + else if (type == DEATH_TELEFRAG) { + HUD_KillNotify_Push(s1, s2, 1, DEATH_TELEFRAG); + if(gentle) + print ("^1",s2, "^1 tried to occupy ", s1, "^1's teleport destination space\n"); + else + print ("^1",s2, "^1 was telefragged by ", s1, "\n"); + } else if (type == DEATH_DROWN) { - HUD_KillNotify_Push(s2, s1, 1, DEATH_DROWN); + HUD_KillNotify_Push(s1, s2, 1, DEATH_DROWN); if(alsoprint) - print ("^1",s1, "^1 was drowned by ", s2, "\n"); + print ("^1",s2, "^1 was drowned by ", s1, "\n"); } else if (type == DEATH_SLIME) { - HUD_KillNotify_Push(s2, s1, 1, DEATH_SLIME); + HUD_KillNotify_Push(s1, s2, 1, DEATH_SLIME); if(alsoprint) - print ("^1",s1, "^1 was slimed by ", s2, "\n"); + print ("^1",s2, "^1 was slimed by ", s1, "\n"); } else if (type == DEATH_LAVA) { - HUD_KillNotify_Push(s2, s1, 1, DEATH_LAVA); + HUD_KillNotify_Push(s1, s2, 1, DEATH_LAVA); if(alsoprint) - print ("^1",s1, "^1 was cooked by ", s2, "\n"); + print ("^1",s2, "^1 was cooked by ", s1, "\n"); } else if (type == DEATH_FALL) { - HUD_KillNotify_Push(s2, s1, 1, DEATH_FALL); + HUD_KillNotify_Push(s1, s2, 1, DEATH_FALL); if(alsoprint) - print ("^1",s1, "^1 was grounded by ", s2, "\n"); + print ("^1",s2, "^1 was grounded by ", s1, "\n"); } else if (type == DEATH_SHOOTING_STAR) { - HUD_KillNotify_Push(s2, s1, 1, DEATH_SHOOTING_STAR); + HUD_KillNotify_Push(s1, s2, 1, DEATH_SHOOTING_STAR); if(alsoprint) - print ("^1",s1, "^1 was shot into space by ", s2, "\n"); + print ("^1",s2, "^1 was shot into space by ", s1, "\n"); } else if (type == DEATH_SWAMP) { - HUD_KillNotify_Push(s2, s1, 1, DEATH_GENERIC); + HUD_KillNotify_Push(s1, s2, 1, DEATH_GENERIC); if(alsoprint) - print ("^1",s1, "^1 was conserved by ", s2, "\n"); + print ("^1",s2, "^1 was conserved by ", s1, "\n"); } else if (type == DEATH_HURTTRIGGER) { - HUD_KillNotify_Push(s2, s1, 1, DEATH_HURTTRIGGER); + HUD_KillNotify_Push(s1, s2, 1, DEATH_HURTTRIGGER); if(alsoprint) - print("^1",s1, "^1 was thrown into a world of hurt by ", s2, "\n"); + print("^1",s2, "^1 was thrown into a world of hurt by ", s1, "\n"); } else if(type == DEATH_SBCRUSH) { - HUD_KillNotify_Push(s2, s1, 1, DEATH_GENERIC); + HUD_KillNotify_Push(s1, s2, 1, DEATH_GENERIC); if(alsoprint) - print ("^1",s1, "^1 was crushed by ^1", s2, "\n"); + print ("^1",s2, "^1 was crushed by ^1", s1, "\n"); } else if(type == DEATH_SBMINIGUN) { - HUD_KillNotify_Push(s2, s1, 1, DEATH_GENERIC); + HUD_KillNotify_Push(s1, s2, 1, DEATH_GENERIC); if(alsoprint) - print ("^1",s1, "^1 got shredded by ^1", s2, "\n"); + print ("^1",s2, "^1 got shredded by ^1", s1, "\n"); } else if(type == DEATH_SBROCKET) { - HUD_KillNotify_Push(s2, s1, 1, DEATH_GENERIC); + HUD_KillNotify_Push(s1, s2, 1, DEATH_GENERIC); if(alsoprint) - print ("^1",s1, "^1 was blased to bits by ^1", s2, "\n"); + print ("^1",s2, "^1 was blased to bits by ^1", s1, "\n"); } else if(type == DEATH_SBBLOWUP) { - HUD_KillNotify_Push(s2, s1, 1, DEATH_GENERIC); + HUD_KillNotify_Push(s1, s2, 1, DEATH_GENERIC); if(alsoprint) - print ("^1",s1, "^1 got caught in the destruction of ^1", s2, "'s vehicle\n"); + print ("^1",s2, "^1 got caught in the destruction of ^1", s1, "'s vehicle\n"); } else if(type == DEATH_WAKIGUN) { - HUD_KillNotify_Push(s2, s1, 1, DEATH_GENERIC); + HUD_KillNotify_Push(s1, s2, 1, DEATH_GENERIC); if(alsoprint) - print ("^1",s1, "^1 was bolted down by ^1", s2, "\n"); + print ("^1",s2, "^1 was bolted down by ^1", s1, "\n"); } else if(type == DEATH_WAKIROCKET) { - HUD_KillNotify_Push(s2, s1, 1, DEATH_GENERIC); + HUD_KillNotify_Push(s1, s2, 1, DEATH_GENERIC); if(alsoprint) - print ("^1",s1, "^1 could find no shelter from ^1", s2, "'s rockets\n"); + print ("^1",s2, "^1 could find no shelter from ^1", s1, "'s rockets\n"); } else if(type == DEATH_WAKIBLOWUP) { - HUD_KillNotify_Push(s2, s1, 1, DEATH_GENERIC); + HUD_KillNotify_Push(s1, s2, 1, DEATH_GENERIC); if(alsoprint) - print ("^1",s1, "^1 dies when ^1", s2, "'s wakizashi dies.\n"); + print ("^1",s2, "^1 dies when ^1", s1, "'s wakizashi dies.\n"); } else if(type == DEATH_TURRET) { - HUD_KillNotify_Push(s2, s1, 1, DEATH_GENERIC); + HUD_KillNotify_Push(s1, s2, 1, DEATH_GENERIC); if(alsoprint) - print ("^1",s1, "^1 was pushed into the line of fire by ^1", s2, "\n"); + print ("^1",s2, "^1 was pushed into the line of fire by ^1", s1, "\n"); } else if(type == DEATH_TOUCHEXPLODE) { - HUD_KillNotify_Push(s2, s1, 1, DEATH_GENERIC); + HUD_KillNotify_Push(s1, s2, 1, DEATH_GENERIC); if(alsoprint) - print ("^1",s1, "^1 was pushed into an accident by ^1", s2, "\n"); + print ("^1",s2, "^1 was pushed into an accident by ^1", s1, "\n"); } else if(type == DEATH_CHEAT) { - HUD_KillNotify_Push(s2, s1, 1, DEATH_GENERIC); + HUD_KillNotify_Push(s1, s2, 1, DEATH_GENERIC); if(alsoprint) - print ("^1",s1, "^1 was unfairly eliminated by ^1", s2, "\n"); + print ("^1",s2, "^1 was unfairly eliminated by ^1", s1, "\n"); } else if (type == DEATH_FIRE) { - HUD_KillNotify_Push(s2, s1, 1, DEATH_GENERIC); + HUD_KillNotify_Push(s1, s2, 1, DEATH_GENERIC); if(alsoprint) - print ("^1",s1, "^1 was burnt to death by ^1", s2, "\n"); + print ("^1",s2, "^1 was burnt to death by ^1", s1, "\n"); } else if (type == DEATH_CUSTOM) { - HUD_KillNotify_Push(s2, s1, 1, DEATH_CUSTOM); + HUD_KillNotify_Push(s1, s2, 1, DEATH_CUSTOM); if(alsoprint) - print ("^1",s1, "^1 ", s2, "\n"); + print("^1", sprintf(s3, strcat(s2, "^1"), strcat(s1, "^1")), "\n"); + } else if (type == DEATH_HURTTRIGGER) { + HUD_KillNotify_Push(s1, s2, 1, DEATH_HURTTRIGGER); + if(alsoprint) + print("^1", sprintf(s3, strcat(s2, "^1"), strcat(s1, "^1")), "\n"); } else { - HUD_KillNotify_Push(s2, s1, 1, DEATH_GENERIC); + HUD_KillNotify_Push(s1, s2, 1, DEATH_GENERIC); if(alsoprint) - print ("^1",s1, "^1 was fragged by ", s2, "\n"); + print ("^1",s2, "^1 was fragged by ", s1, "\n"); } } else if(msg == MSG_SPREE) { if(type == KILL_END_SPREE) { @@ -2662,11 +2865,11 @@ void HUD_KillNotify(string s1, string s2, string s3, float type, float msg) } else if (type == DEATH_CUSTOM) { HUD_KillNotify_Push(s1, "", 0, DEATH_CUSTOM); if(alsoprint) - print ("^1",s1, "^1 ", s2, "\n"); + print("^1", sprintf(s2, strcat(s1, "^1")), "\n"); } else if (type == DEATH_HURTTRIGGER) { HUD_KillNotify_Push(s1, "", 0, DEATH_HURTTRIGGER); if(alsoprint) - print ("^1",s1, "^1 was in the wrong place\n"); + print("^1", sprintf(s2, strcat(s1, "^1")), "\n"); } else if(type == DEATH_TOUCHEXPLODE) { HUD_KillNotify_Push(s1, "", 0, DEATH_GENERIC); if(alsoprint) @@ -2752,7 +2955,7 @@ void HUD_Centerprint(string s1, string s2, float type, float msg) centerprint(strcat(DAMAGE_CENTERPRINT_SPACER, "^1Don't shoot your team mates!")); } else if (type == DEATH_QUIET) { // do nothing - } else if (type == DEATH_KILL) { + } else { // generic message if(gentle) centerprint(strcat(DAMAGE_CENTERPRINT_SPACER, "^1You need to be more careful!")); else @@ -2795,7 +2998,7 @@ void HUD_Centerprint(string s1, string s2, float type, float msg) } else { centerprint(strcat(DAMAGE_CENTERPRINT_SPACER, "^4You fragged ^7", s1, s2)); } - } else if (type == KILL_FRAGGED) { + } else { // generic message if(gentle) { centerprint(strcat(DAMAGE_CENTERPRINT_SPACER, "^1You were scored against by ^7", s1, s2)); } else { @@ -2846,7 +3049,7 @@ void HUD_Notify (void) float width_attacker; string attacker, victim; - float i, j; + float i, j, w; for(j = 0; j < entries; ++j) { s = ""; @@ -2870,7 +3073,7 @@ void HUD_Notify (void) a = 0; } - float w; + w = -1; w = DEATH_WEAPONOF(killnotify_deathtype[j]); // TODO: maybe print in team colors? @@ -3024,6 +3227,10 @@ void HUD_Notify (void) { s = "notify_teamkill_red"; } + else if(killnotify_deathtype[j] == DEATH_TELEFRAG) + { + s = "notify_telefrag"; + } else if(killnotify_deathtype[j] == DEATH_DROWN) { s = "notify_water"; @@ -3547,6 +3754,17 @@ void HUD_VoteWindow(void) pos = panel_pos; mySize = panel_size; + if(!autocvar__hud_configure) + { + panel_fg_alpha = autocvar_hud_panel_fg_alpha; + panel_bg_alpha_str = autocvar_hud_panel_vote_bg_alpha; + + if(panel_bg_alpha_str == "") { + panel_bg_alpha_str = ftos(autocvar_hud_panel_bg_alpha); + } + panel_bg_alpha = stof(panel_bg_alpha_str); + } + string s; float a; if(vote_active != vote_prev) { @@ -3569,9 +3787,9 @@ void HUD_VoteWindow(void) if(!vote_alpha) return; - a = vote_alpha * bound(autocvar_hud_panel_vote_alreadyvoted_alpha, 1 - vote_highlighted, 1); - + a = panel_bg_alpha * vote_alpha * bound(autocvar_hud_panel_vote_alreadyvoted_alpha, 1 - vote_highlighted, 1); HUD_Panel_DrawBg(a); + a = panel_fg_alpha * vote_alpha * bound(autocvar_hud_panel_vote_alreadyvoted_alpha, 1 - vote_highlighted, 1); if(panel_bg_padding) { pos += '1 1 0' * panel_bg_padding; @@ -3597,37 +3815,37 @@ void HUD_VoteWindow(void) mySize = newSize; s = "A vote has been called for:"; - drawstring_aspect(pos, s, eX * mySize_x + eY * (2/8) * mySize_y, '1 1 1', a * panel_fg_alpha, DRAWFLAG_NORMAL); + drawstring_aspect(pos, s, eX * mySize_x + eY * (2/8) * mySize_y, '1 1 1', a, DRAWFLAG_NORMAL); s = textShortenToWidth(vote_called_vote, mySize_x, '1 1 0' * mySize_y * (1.75/8), stringwidth_colors); if(autocvar__hud_configure) s = "^1Configure the HUD"; - drawcolorcodedstring_aspect(pos + eY * (2/8) * mySize_y, s, eX * mySize_x + eY * (1.75/8) * mySize_y, a * panel_fg_alpha, DRAWFLAG_NORMAL); + drawcolorcodedstring_aspect(pos + eY * (2/8) * mySize_y, s, eX * mySize_x + eY * (1.75/8) * mySize_y, a, DRAWFLAG_NORMAL); // print the yes/no counts - s = strcat("Yes (", getcommandkey("not bound", "vyes"), "): ", ftos(vote_yescount)); - drawstring_aspect(pos + eY * (4/8) * mySize_y, s, eX * 0.5 * mySize_x + eY * (1.5/8) * mySize_y, '0 1 0', a * panel_fg_alpha, DRAWFLAG_NORMAL); - s = strcat("No (", getcommandkey("not bound", "vno"), "): ", ftos(vote_nocount)); - drawstring_aspect(pos + eX * 0.5 * mySize_x + eY * (4/8) * mySize_y, s, eX * 0.5 * mySize_x + eY * (1.5/8) * mySize_y, '1 0 0', a * panel_fg_alpha, DRAWFLAG_NORMAL); + s = strcat("Yes (", getcommandkey("vyes", "vyes"), "): ", ftos(vote_yescount)); + drawstring_aspect(pos + eY * (4/8) * mySize_y, s, eX * 0.5 * mySize_x + eY * (1.5/8) * mySize_y, '0 1 0', a, DRAWFLAG_NORMAL); + s = strcat("No (", getcommandkey("vno", "vno"), "): ", ftos(vote_nocount)); + drawstring_aspect(pos + eX * 0.5 * mySize_x + eY * (4/8) * mySize_y, s, eX * 0.5 * mySize_x + eY * (1.5/8) * mySize_y, '1 0 0', a, DRAWFLAG_NORMAL); // draw the progress bar backgrounds - drawpic_skin(pos + eY * (5/8) * mySize_y, "voteprogress_back", eX * mySize_x + eY * (3/8) * mySize_y, '1 1 1', a * panel_fg_alpha, DRAWFLAG_NORMAL); + drawpic_skin(pos + eY * (5/8) * mySize_y, "voteprogress_back", eX * mySize_x + eY * (3/8) * mySize_y, '1 1 1', a, DRAWFLAG_NORMAL); // draw the highlights if(vote_highlighted == 1) { drawsetcliparea(pos_x, pos_y, mySize_x * 0.5, mySize_y); - drawpic_skin(pos + eY * (5/8) * mySize_y, "voteprogress_voted", eX * mySize_x + eY * (3/8) * mySize_y, '0 1 0', a * panel_fg_alpha, DRAWFLAG_NORMAL); + drawpic_skin(pos + eY * (5/8) * mySize_y, "voteprogress_voted", eX * mySize_x + eY * (3/8) * mySize_y, '1 1 1', a, DRAWFLAG_NORMAL); } else if(vote_highlighted == 2) { drawsetcliparea(pos_x + 0.5 * mySize_x, pos_y, mySize_x * 0.5, mySize_y); - drawpic_skin(pos + eY * (5/8) * mySize_y, "voteprogress_voted", eX * mySize_x + eY * (3/8) * mySize_y, '0 1 0', a * panel_fg_alpha, DRAWFLAG_NORMAL); + drawpic_skin(pos + eY * (5/8) * mySize_y, "voteprogress_voted", eX * mySize_x + eY * (3/8) * mySize_y, '1 1 1', a, DRAWFLAG_NORMAL); } // draw the progress bars drawsetcliparea(pos_x, pos_y, mySize_x * 0.5 * (vote_yescount/vote_needed), mySize_y); - drawpic_skin(pos + eY * (5/8) * mySize_y, "voteprogress_prog", eX * mySize_x + eY * (3/8) * mySize_y, '0 1 0', a * panel_fg_alpha, DRAWFLAG_NORMAL); + drawpic_skin(pos + eY * (5/8) * mySize_y, "voteprogress_prog", eX * mySize_x + eY * (3/8) * mySize_y, '1 1 1', a, DRAWFLAG_NORMAL); drawsetcliparea(pos_x + mySize_x - mySize_x * 0.5 * (vote_nocount/vote_needed), pos_y, mySize_x * 0.5, mySize_y); - drawpic_skin(pos + eY * (5/8) * mySize_y, "voteprogress_prog", eX * mySize_x + eY * (3/8) * mySize_y, '1 0 0', a * panel_fg_alpha, DRAWFLAG_NORMAL); + drawpic_skin(pos + eY * (5/8) * mySize_y, "voteprogress_prog", eX * mySize_x + eY * (3/8) * mySize_y, '1 1 1', a, DRAWFLAG_NORMAL); drawresetcliparea(); @@ -4025,16 +4243,31 @@ void HUD_Mod_Race(vector pos, vector mySize) crecordtime_prev = t; crecordtime_change_time = time; } + + vector textPos, medalPos; + float squareSize; + if(mySize_x > mySize_y) { + // text on left side + squareSize = min(mySize_y, mySize_x/2); + textPos = pos + eX * 0.5 * max(0, mySize_x/2 - squareSize) + eY * 0.5 * (mySize_y - squareSize); + medalPos = pos + eX * 0.5 * max(0, mySize_x/2 - squareSize) + eX * 0.5 * mySize_x + eY * 0.5 * (mySize_y - squareSize); + } else { + // text on top + squareSize = min(mySize_x, mySize_y/2); + textPos = pos + eY * 0.5 * max(0, mySize_y/2 - squareSize) + eX * 0.5 * (mySize_x - squareSize);; + medalPos = pos + eY * 0.5 * max(0, mySize_y/2 - squareSize) + eY * 0.5 * mySize_y + eX * 0.5 * (mySize_x - squareSize); + } + f = time - crecordtime_change_time; if (f > 1) { - drawstring_aspect(pos, "Personal best", eX * 0.5 * mySize_x + eY * 0.25 * mySize_y, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL); - drawstring_aspect(pos + eY * 0.25 * mySize_y, TIME_ENCODED_TOSTRING(t), eX * 0.5 * mySize_x + eY * 0.25 * mySize_y, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL); + drawstring_aspect(textPos, "Personal best", eX * squareSize + eY * 0.25 * squareSize, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL); + drawstring_aspect(textPos + eY * 0.25 * squareSize, TIME_ENCODED_TOSTRING(t), eX * squareSize + eY * 0.25 * squareSize, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL); } else { - drawstring_aspect(pos, "Personal best", eX * 0.5 * mySize_x + eY * 0.25 * mySize_y, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL); - drawstring_aspect(pos + eY * 0.25 * mySize_y, TIME_ENCODED_TOSTRING(t), eX * 0.5 * mySize_x + eY * 0.25 * mySize_y, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL); - drawstring_aspect_expanding(pos, "Personal best", eX * 0.5 * mySize_x + eY * 0.25 * mySize_y, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL, f); - drawstring_aspect_expanding(pos + eY * 0.25 * mySize_y, TIME_ENCODED_TOSTRING(t), eX * 0.5 * mySize_x + eY * 0.25 * mySize_y, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL, f); + drawstring_aspect(textPos, "Personal best", eX * squareSize + eY * 0.25 * squareSize, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL); + drawstring_aspect(textPos + eY * 0.25 * squareSize, TIME_ENCODED_TOSTRING(t), eX * squareSize + eY * 0.25 * squareSize, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL); + drawstring_aspect_expanding(pos, "Personal best", eX * squareSize + eY * 0.25 * squareSize, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL, f); + drawstring_aspect_expanding(pos + eY * 0.25 * squareSize, TIME_ENCODED_TOSTRING(t), eX * squareSize + eY * 0.25 * squareSize, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL, f); } // server record @@ -4046,13 +4279,13 @@ void HUD_Mod_Race(vector pos, vector mySize) f = time - srecordtime_change_time; if (f > 1) { - drawstring_aspect(pos + eY * 0.5 * mySize_y, "Server best", eX * 0.5 * mySize_x + eY * 0.25 * mySize_y, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL); - drawstring_aspect(pos + eY * 0.75 * mySize_y, TIME_ENCODED_TOSTRING(t), eX * 0.5 * mySize_x + eY * 0.25 * mySize_y, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL); + drawstring_aspect(textPos + eY * 0.5 * squareSize, "Server best", eX * squareSize + eY * 0.25 * squareSize, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL); + drawstring_aspect(textPos + eY * 0.75 * squareSize, TIME_ENCODED_TOSTRING(t), eX * squareSize + eY * 0.25 * squareSize, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL); } else { - drawstring_aspect(pos + eY * 0.5 * mySize_y, "Server best", eX * 0.5 * mySize_x + eY * 0.25 * mySize_y, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL); - drawstring_aspect(pos + eY * 0.75 * mySize_y, TIME_ENCODED_TOSTRING(t), eX * 0.5 * mySize_x + eY * 0.25 * mySize_y, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL); - drawstring_aspect_expanding(pos + eY * 0.5 * mySize_y, "Server best", eX * 0.5 * mySize_x + eY * 0.25 * mySize_y, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL, f); - drawstring_aspect_expanding(pos + eY * 0.75 * mySize_y, TIME_ENCODED_TOSTRING(t), eX * 0.5 * mySize_x + eY * 0.25 * mySize_y, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL, f); + drawstring_aspect(textPos + eY * 0.5 * squareSize, "Server best", eX * squareSize + eY * 0.25 * squareSize, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL); + drawstring_aspect(textPos + eY * 0.75 * squareSize, TIME_ENCODED_TOSTRING(t), eX * squareSize + eY * 0.25 * squareSize, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL); + drawstring_aspect_expanding(textPos + eY * 0.5 * squareSize, "Server best", eX * squareSize + eY * 0.25 * squareSize, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL, f); + drawstring_aspect_expanding(textPos + eY * 0.75 * squareSize, TIME_ENCODED_TOSTRING(t), eX * squareSize + eY * 0.25 * squareSize, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL, f); } if (race_status != race_status_prev || race_status_name != race_status_name_prev) { @@ -4063,13 +4296,12 @@ void HUD_Mod_Race(vector pos, vector mySize) race_status_name_prev = strzone(race_status_name); } - pos_x += mySize_x/2; // race "awards" float a; a = bound(0, race_status_time - time, 1); string s; - s = textShortenToWidth(race_status_name, mySize_y, '1 1 0' * 0.1 * mySize_y, stringwidth_colors); + s = textShortenToWidth(race_status_name, squareSize, '1 1 0' * 0.1 * squareSize, stringwidth_colors); float rank; if(race_status > 0) @@ -4078,27 +4310,27 @@ void HUD_Mod_Race(vector pos, vector mySize) rankname = race_PlaceName(rank); vector namepos; - namepos = pos + '0.5 0.9 0' * mySize_y - eX * stringwidth(s, TRUE, '1 1 0' * 0.1 * mySize_y); + namepos = medalPos + '0 0.8 0' * squareSize; vector rankpos; - rankpos = pos + '0.5 0.25 0' * mySize_y - eX * stringwidth(rankname, TRUE, '1 1 0' * 0.15 * mySize_y); + rankpos = medalPos + '0 0.15 0' * squareSize; if(race_status == 0) - drawpic_aspect_skin(pos, "race_newfail", '1 1 0' * mySize_y, '1 1 1', panel_fg_alpha * a, DRAWFLAG_NORMAL); + drawpic_aspect_skin(medalPos, "race_newfail", '1 1 0' * squareSize, '1 1 1', panel_fg_alpha * a, DRAWFLAG_NORMAL); else if(race_status == 1) { - drawpic_aspect_skin(pos, "race_newtime", '1 1 0' * 0.9 * mySize_y, '1 1 1', panel_fg_alpha * a, DRAWFLAG_NORMAL); - drawcolorcodedstring(namepos, s, '1 1 0' * 0.1 * mySize_y, panel_fg_alpha * a, DRAWFLAG_NORMAL); - drawstring(rankpos, rankname, '1 1 0' * 0.15 * mySize_y, '1 1 1', panel_fg_alpha * a, DRAWFLAG_NORMAL); + drawpic_aspect_skin(medalPos + '0.1 0 0' * squareSize, "race_newtime", '1 1 0' * 0.8 * squareSize, '1 1 1', panel_fg_alpha * a, DRAWFLAG_NORMAL); + drawcolorcodedstring_aspect(namepos, s, '1 0.2 0' * squareSize, panel_fg_alpha * a, DRAWFLAG_NORMAL); + drawstring_aspect(rankpos, rankname, '1 0.15 0' * squareSize, '1 1 1', panel_fg_alpha * a, DRAWFLAG_NORMAL); } else if(race_status == 2) { if(race_status_name == GetPlayerName(player_localentnum -1) || !race_myrank || race_myrank < rank) - drawpic_aspect_skin(pos, "race_newrankgreen", '1 1 0' * 0.9 * mySize_y, '1 1 1', panel_fg_alpha * a, DRAWFLAG_NORMAL); + drawpic_aspect_skin(medalPos + '0.1 0 0' * squareSize, "race_newrankgreen", '1 1 0' * 0.8 * squareSize, '1 1 1', panel_fg_alpha * a, DRAWFLAG_NORMAL); else - drawpic_aspect_skin(pos, "race_newrankyellow", '1 1 0' * 0.9 * mySize_y, '1 1 1', panel_fg_alpha * a, DRAWFLAG_NORMAL); - drawcolorcodedstring(namepos, s, '1 1 0' * 0.1 * mySize_y, panel_fg_alpha * a, DRAWFLAG_NORMAL); - drawstring(rankpos, rankname, '1 1 0' * 0.15 * mySize_y, '1 1 1', panel_fg_alpha * a, DRAWFLAG_NORMAL); + drawpic_aspect_skin(medalPos + '0.1 0 0' * squareSize, "race_newrankyellow", '1 1 0' * 0.8 * squareSize, '1 1 1', panel_fg_alpha * a, DRAWFLAG_NORMAL); + drawcolorcodedstring_aspect(namepos, s, '1 0.2 0' * squareSize, panel_fg_alpha * a, DRAWFLAG_NORMAL); + drawstring_aspect(rankpos, rankname, '1 0.15 0' * squareSize, '1 1 1', panel_fg_alpha * a, DRAWFLAG_NORMAL); } else if(race_status == 3) { - drawpic_aspect_skin(pos, "race_newrecordserver", '1 1 0' * 0.9 * mySize_y, '1 1 1', panel_fg_alpha * a, DRAWFLAG_NORMAL); - drawcolorcodedstring(namepos, s, '1 1 0' * 0.1 * mySize_y, panel_fg_alpha * a, DRAWFLAG_NORMAL); - drawstring(rankpos, rankname, '1 1 0' * 0.15 * mySize_y, '1 1 1', panel_fg_alpha * a, DRAWFLAG_NORMAL); + drawpic_aspect_skin(medalPos + '0.1 0 0' * squareSize, "race_newrecordserver", '1 1 0' * 0.8 * squareSize, '1 1 1', panel_fg_alpha * a, DRAWFLAG_NORMAL); + drawcolorcodedstring_aspect(namepos, s, '1 0.2 0' * squareSize, panel_fg_alpha * a, DRAWFLAG_NORMAL); + drawstring_aspect(rankpos, rankname, '1 0.15 0' * squareSize, '1 1 1', panel_fg_alpha * a, DRAWFLAG_NORMAL); } if (race_status_time - time <= 0) { @@ -4236,8 +4468,15 @@ void HUD_Chat(void) { panel_pos_y = panel_bg_border; panel_size_y = vid_conheight - panel_bg_border * 2; - if(panel_bg == "0") - panel_bg = "border"; // force a border when maximized + if(panel_bg == "0") // force a border when maximized + { + if(precache_pic(panel_bg) == "") { + panel_bg = strcat(hud_skin_path, "/border_default"); + if(precache_pic(panel_bg) == "") { + panel_bg = "gfx/hud/default/border_default"; + } + } + } panel_bg_alpha = max(0.75, panel_bg_alpha); // force an alpha of at least 0.75 } @@ -4305,29 +4544,32 @@ void HUD_EngineInfo(void) mySize -= '2 2 0' * panel_bg_padding; } + float currentTime = gettime(GETTIME_REALTIME); if(cvar("hud_panel_engineinfo_framecounter_exponentialmovingaverage")) { - frametimeavg = (frametimeavg + frametimeavg1 + frametimeavg2 + frametime)/4; // average three frametimes into framecounter for slightly more stable fps readings :P + float currentframetime = currentTime - prevfps_time; + frametimeavg = (frametimeavg + frametimeavg1 + frametimeavg2 + currentframetime)/4; // average three frametimes into framecounter for slightly more stable fps readings :P frametimeavg2 = frametimeavg1; frametimeavg1 = frametimeavg; float weight; weight = cvar("hud_panel_engineinfo_framecounter_exponentialmovingaverage_new_weight"); - if(frametime > 0.0001) // filter out insane values which sometimes seem to occur and throw off the average? If you are getting 10,000 fps or more, then you don't need a framerate counter. + if(currentframetime > 0.0001) // filter out insane values which sometimes seem to occur and throw off the average? If you are getting 10,000 fps or more, then you don't need a framerate counter. { - if(fabs(prevfps - (1/frametimeavg)) > prevfps * cvar("hud_panel_engineinfo_framecounter_exponentialmovingaverage_instantupdate_change_threshold")) // if there was a big jump in fps, just force prevfps at current (1/frametime) to make big updates instant - prevfps = (1/frametime); + if(fabs(prevfps - (1/frametimeavg)) > prevfps * cvar("hud_panel_engineinfo_framecounter_exponentialmovingaverage_instantupdate_change_threshold")) // if there was a big jump in fps, just force prevfps at current (1/currentframetime) to make big updates instant + prevfps = (1/currentframetime); prevfps = (1 - weight) * prevfps + weight * (1/frametimeavg); // framecounter just used so there's no need for a new variable, think of it as "frametime average" } + prevfps_time = currentTime; } else { framecounter += 1; - if(time - prevfps_time > cvar("hud_panel_engineinfo_framecounter_time")) + if(currentTime - prevfps_time > cvar("hud_panel_engineinfo_framecounter_time")) { - prevfps = framecounter/cvar("hud_panel_engineinfo_framecounter_time"); + prevfps = framecounter/(currentTime - prevfps_time); framecounter = 0; - prevfps_time = time; + prevfps_time = currentTime; } } @@ -4340,6 +4582,11 @@ void HUD_EngineInfo(void) // Info messages panel (#14) // +#define drawInfoMessage(s)\ + if(autocvar_hud_panel_infomessages_flip)\ + o_x = pos_x + mySize_x - stringwidth(s, TRUE, fontsize);\ + drawcolorcodedstring(o, s, fontsize, a, DRAWFLAG_NORMAL);\ + o_y += fontsize_y; void HUD_InfoMessages(void) { if(!autocvar_hud_panel_infomessages && !autocvar__hud_configure) @@ -4383,6 +4630,12 @@ void HUD_InfoMessages(void) vector fontsize; fontsize = '0.20 0.20 0' * mySize_y; + float a; + if(spectatee_status != 0) + a = 1; + else + a = panel_fg_alpha; + string s; if(!autocvar__hud_configure) { @@ -4392,35 +4645,22 @@ void HUD_InfoMessages(void) s = "^1Observing"; else s = strcat("^1Spectating: ^7", GetPlayerName(spectatee_status - 1)); - - if(autocvar_hud_panel_infomessages_flip) - o_x = pos_x + mySize_x - stringwidth(s, TRUE, fontsize); - drawcolorcodedstring(o, s, fontsize, panel_fg_alpha, DRAWFLAG_NORMAL); - o += eY * fontsize_y; + drawInfoMessage(s) if(spectatee_status == -1) - s = strcat("^1Press ^3", getcommandkey("primary fire", "+attack"), "^1 to spectate"); + s = strcat("^1Press ^3", getcommandkey("primary fire", "+fire"), "^1 to spectate"); else - s = strcat("^1Press ^3", getcommandkey("primary fire", "+attack"), "^1 for another player"); - if(autocvar_hud_panel_infomessages_flip) - o_x = pos_x + mySize_x - stringwidth(s, TRUE, fontsize); - drawcolorcodedstring(o, s, fontsize, panel_fg_alpha, DRAWFLAG_NORMAL); - o += eY * fontsize_y; + s = strcat("^1Press ^3", getcommandkey("primary fire", "+fire"), "^1 for another player"); + drawInfoMessage(s) if(spectatee_status == -1) s = strcat("^1Use ^3", getcommandkey("next weapon", "weapnext"), "^1 or ^3", getcommandkey("previous weapon", "weapprev"), "^1 to change the speed"); else - s = strcat("^1Press ^3", getcommandkey("secondary fire", "+attack2"), "^1 to observe"); - if(autocvar_hud_panel_infomessages_flip) - o_x = pos_x + mySize_x - stringwidth(s, TRUE, fontsize); - drawcolorcodedstring(o, s, fontsize, panel_fg_alpha, DRAWFLAG_NORMAL); - o += eY * fontsize_y; + s = strcat("^1Press ^3", getcommandkey("secondary fire", "+fire2"), "^1 to observe"); + drawInfoMessage(s) s = strcat("^1Press ^3", getcommandkey("server info", "+show_info"), "^1 for gamemode info"); - if(autocvar_hud_panel_infomessages_flip) - o_x = pos_x + mySize_x - stringwidth(s, TRUE, fontsize); - drawcolorcodedstring(o, s, fontsize, panel_fg_alpha, DRAWFLAG_NORMAL); - o += eY * fontsize_y; + drawInfoMessage(s) if(gametype == GAME_ARENA) s = "^1Wait for your turn to join"; @@ -4437,10 +4677,7 @@ void HUD_InfoMessages(void) } else s = strcat("^1Press ^3", getcommandkey("jump", "+jump"), "^1 to join"); - if(autocvar_hud_panel_infomessages_flip) - o_x = pos_x + mySize_x - stringwidth(s, TRUE, fontsize); - drawcolorcodedstring(o, s, fontsize, panel_fg_alpha, DRAWFLAG_NORMAL); - o += eY * fontsize_y; + drawInfoMessage(s) //show restart countdown: if (time < getstatf(STAT_GAMESTARTTIME)) { @@ -4448,17 +4685,14 @@ void HUD_InfoMessages(void) //we need to ceil, otherwise the countdown would be off by .5 when using round() countdown = ceil(getstatf(STAT_GAMESTARTTIME) - time); s = strcat("^1Game starts in ^3", ftos(countdown), "^1 seconds"); - drawcolorcodedstring(o, s, fontsize, panel_fg_alpha, DRAWFLAG_NORMAL); - o += eY * fontsize_y; + drawcolorcodedstring(o, s, fontsize, a, DRAWFLAG_NORMAL); + o_y += fontsize_y; } } if(warmup_stage && !intermission) { s = "^2Currently in ^1warmup^2 stage!"; - if(autocvar_hud_panel_infomessages_flip) - o_x = pos_x + mySize_x - stringwidth(s, TRUE, fontsize); - drawcolorcodedstring(o, s, fontsize, panel_fg_alpha, DRAWFLAG_NORMAL); - o += eY * fontsize_y; + drawInfoMessage(s) } string blinkcolor; @@ -4483,18 +4717,12 @@ void HUD_InfoMessages(void) else s = strcat("^2Waiting for others to ready up..."); } - if(autocvar_hud_panel_infomessages_flip) - o_x = pos_x + mySize_x - stringwidth(s, TRUE, fontsize); - drawcolorcodedstring(o, s, fontsize, panel_fg_alpha, DRAWFLAG_NORMAL); - o += eY * fontsize_y; + drawInfoMessage(s) } else if(warmup_stage && !intermission && !spectatee_status) { s = strcat("^2Press ^3", getcommandkey("ready", "ready"), "^2 to end warmup"); - if(autocvar_hud_panel_infomessages_flip) - o_x = pos_x + mySize_x - stringwidth(s, TRUE, fontsize); - drawcolorcodedstring(o, s, fontsize, panel_fg_alpha, DRAWFLAG_NORMAL); - o += eY * fontsize_y; + drawInfoMessage(s) } if(teamplay && !intermission && !spectatee_status && gametype != GAME_CA && teamnagger) @@ -4520,11 +4748,7 @@ void HUD_InfoMessages(void) if (tm.team != COLOR_SPECTATOR) if (tm.team_size == ts_max) s = strcat(s, " Press ^3", getcommandkey("team menu", "menu_showteamselect"), blinkcolor, " to adjust"); - - if(autocvar_hud_panel_infomessages_flip) - o_x = pos_x + mySize_x - stringwidth(s, TRUE, fontsize); - drawcolorcodedstring(o, s, fontsize, panel_fg_alpha, DRAWFLAG_NORMAL); - o += eY * fontsize_y; + drawInfoMessage(s) } } } @@ -4532,25 +4756,13 @@ void HUD_InfoMessages(void) else { s = "^7Press ^3ESC ^7to show HUD options."; - if(autocvar_hud_panel_infomessages_flip) - o_x = pos_x + mySize_x - stringwidth(s, TRUE, fontsize); - drawcolorcodedstring(o, s, fontsize, panel_fg_alpha, DRAWFLAG_NORMAL); - o += eY * fontsize_y; + drawInfoMessage(s) s = "^3Doubleclick ^7a panel for panel-specific options."; - if(autocvar_hud_panel_infomessages_flip) - o_x = pos_x + mySize_x - stringwidth(s, TRUE, fontsize); - drawcolorcodedstring(o, s, fontsize, panel_fg_alpha, DRAWFLAG_NORMAL); - o += eY * fontsize_y; + drawInfoMessage(s) s = "^3CTRL ^7to disable collision testing, ^3SHIFT ^7and"; - if(autocvar_hud_panel_infomessages_flip) - o_x = pos_x + mySize_x - stringwidth(s, TRUE, fontsize); - drawcolorcodedstring(o, s, fontsize, panel_fg_alpha, DRAWFLAG_NORMAL); - o += eY * fontsize_y; + drawInfoMessage(s) s = "^3ALT ^7+ ^3ARROW KEYS ^7for fine adjustments."; - if(autocvar_hud_panel_infomessages_flip) - o_x = pos_x + mySize_x - stringwidth(s, TRUE, fontsize); - drawcolorcodedstring(o, s, fontsize, panel_fg_alpha, DRAWFLAG_NORMAL); - o += eY * fontsize_y; + drawInfoMessage(s) } } @@ -4601,11 +4813,11 @@ void HUD_ShowSpeed(void) pos = (vid_conheight - numsize_y) * cvar("cl_showspeed_position"); drawfont = hud_bigfont; - drawstringcenter(eX + pos * eY, speed, numsize, '1 1 1', autocvar_hud_panel_fg_alpha, DRAWFLAG_NORMAL); + drawstringcenter(eX + pos * eY, speed, numsize, '1 1 1', autocvar_hud_panel_fg_alpha * hud_fade_alpha, DRAWFLAG_NORMAL); if (cvar("cl_showspeed_z") == 1) { zspeed = strcat(ftos(fabs(floor( pmove_vel_z * conversion_factor + 0.5 ))), unit); - drawstringcenter(eX + pos * eY + numsize_y * eY, zspeed, numsize * 0.5, '1 1 1', autocvar_hud_panel_fg_alpha, DRAWFLAG_NORMAL); + drawstringcenter(eX + pos * eY + numsize_y * eY, zspeed, numsize * 0.5, '1 1 1', autocvar_hud_panel_fg_alpha * hud_fade_alpha, DRAWFLAG_NORMAL); } drawfont = hud_font; @@ -4633,6 +4845,8 @@ void HUD_ShowAcceleration(void) f = bound(0, f * 10, 1); acc_avg = acc_avg * (1 - f) + acceleration * f; acceleration = acc_avg / getstatf(STAT_MOVEVARS_MAXSPEED); + if (acceleration == 0) + return; pos = top - sz/2 * eY + (cvar("cl_showacceleration_position") * vid_conheight) * eY; @@ -4642,18 +4856,16 @@ void HUD_ShowAcceleration(void) if (cvar("cl_showacceleration_color_custom")) rgb = stov(cvar_string("cl_showacceleration_color")); else { - rgb = '1 1 1'; - if (acceleration < 0) { + if (acceleration < 0) rgb = '1 .5 .5' - '0 .5 .5' * bound(0, -acceleration * 0.2, 1); - } else if (acceleration > 0) { + else rgb = '.5 1 .5' - '.5 0 .5' * bound(0, +acceleration * 0.2, 1); - } } if (acceleration > 0) - HUD_Panel_DrawProgressBar(pos, 0, acceleration * scale * '40 0 0' + sz * eY, rgb, alpha * autocvar_hud_panel_fg_alpha, DRAWFLAG_NORMAL); - else if (acceleration < 0) - HUD_Panel_DrawProgressBar(pos + acceleration * scale * '40 0 0', 0, -acceleration * scale * '40 0 0' + sz * eY, rgb, alpha * autocvar_hud_panel_fg_alpha, DRAWFLAG_NORMAL); + HUD_Panel_DrawProgressBar(pos, 0, acceleration * scale * '40 0 0' + sz * eY, rgb, alpha * autocvar_hud_panel_fg_alpha * hud_fade_alpha, DRAWFLAG_NORMAL); + else + HUD_Panel_DrawProgressBar(pos + acceleration * scale * '40 0 0', 0, -acceleration * scale * '40 0 0' + sz * eY, rgb, alpha * autocvar_hud_panel_fg_alpha * hud_fade_alpha, DRAWFLAG_NORMAL); } void HUD_Reset (void) @@ -4703,16 +4915,24 @@ void HUD_Main (void) { hud_skin_path = strcat("gfx/hud/", autocvar_hud_skin); - if(disable_menu_alphacheck == 1) - menu_fade_alpha = 1; + // global hud alpha fade + if(menu_enabled == 1) + hud_fade_alpha = 1; else - menu_fade_alpha = (1 - autocvar__menu_alpha); + hud_fade_alpha = (1 - autocvar__menu_alpha); + + if(scoreboard_fade_alpha) + hud_fade_alpha = (1 - scoreboard_fade_alpha); - hud_border_thickness = bound(0, cvar("hud_border_thickness"), 5); - hud_accuracy_border_thickness = bound(0, cvar_or("hud_accuracy_border_thickness", 1), 5); + if(intermission == 2) // no hud during mapvote + hud_fade_alpha = 0; + else if(autocvar__menu_alpha == 0 && scoreboard_fade_alpha == 0) + hud_fade_alpha = 1; hud_fontsize = HUD_GetFontsize("hud_fontsize"); - hud_fontsize_spec = HUD_GetFontsize("hud_fontsize_spec"); + + if(!autocvar__hud_configure && !hud_fade_alpha) + return; // Drawing stuff @@ -4732,35 +4952,38 @@ void HUD_Main (void) } } - float f; - vector color; - if((teamplay) && autocvar_hud_dock_color_team) { - f = stof(getplayerkey(player_localentnum - 1, "colors")); - color = colormapPaletteColor(mod(f, 16), 1) * autocvar_hud_dock_color_team; - } - else if(autocvar_hud_configure_teamcolorforced && autocvar__hud_configure && autocvar_hud_dock_color_team) { - color = '1 0 0' * autocvar_hud_dock_color_team; - } - else if(autocvar_hud_dock_color == "shirt") { - f = stof(getplayerkey(player_localentnum - 1, "colors")); - color = colormapPaletteColor(floor(f / 16), 0); - } - else if(autocvar_hud_dock_color == "pants") { - f = stof(getplayerkey(player_localentnum - 1, "colors")); - color = colormapPaletteColor(mod(f, 16), 1); - } - else - color = stov(autocvar_hud_dock_color); - // draw the dock if(autocvar_hud_dock != "" && autocvar_hud_dock != "0") { + float f; + vector color; + if((teamplay) && autocvar_hud_dock_color_team) { + f = stof(getplayerkey(player_localentnum - 1, "colors")); + color = colormapPaletteColor(mod(f, 16), 1) * autocvar_hud_dock_color_team; + } + else if(autocvar_hud_configure_teamcolorforced && autocvar__hud_configure && autocvar_hud_dock_color_team) { + color = '1 0 0' * autocvar_hud_dock_color_team; + } + else if(autocvar_hud_dock_color == "shirt") { + f = stof(getplayerkey(player_localentnum - 1, "colors")); + color = colormapPaletteColor(floor(f / 16), 0); + } + else if(autocvar_hud_dock_color == "pants") { + f = stof(getplayerkey(player_localentnum - 1, "colors")); + color = colormapPaletteColor(mod(f, 16), 1); + } + else + color = stov(autocvar_hud_dock_color); + string pic; pic = strcat(hud_skin_path, "/", autocvar_hud_dock); if(precache_pic(pic) == "") { - pic = "gfx/hud/default/dock"; + pic = strcat(hud_skin_path, "/dock_medium"); + if(precache_pic(pic) == "") { + pic = "gfx/hud/default/dock_medium"; + } } - drawpic('0 0 0', pic, eX * vid_conwidth + eY * vid_conheight, color, autocvar_hud_dock_alpha * menu_fade_alpha, DRAWFLAG_NORMAL); // no aspect ratio forcing on dock... + drawpic('0 0 0', pic, eX * vid_conwidth + eY * vid_conheight, color, autocvar_hud_dock_alpha * hud_fade_alpha, DRAWFLAG_NORMAL); // no aspect ratio forcing on dock... } // cache the panel order into the panel_order array @@ -4795,5 +5018,6 @@ void HUD_Main (void) hud_configure_prev = autocvar__hud_configure; if (!autocvar__hud_configure) // hud config mode disabled, enable normal alpha stuff again - disable_menu_alphacheck = 0; + if (menu_enabled) + menu_enabled = 0; } diff --git a/qcsrc/client/hud.qh b/qcsrc/client/hud.qh index bdc533edb..5e9d59b6e 100644 --- a/qcsrc/client/hud.qh +++ b/qcsrc/client/hud.qh @@ -1,5 +1,7 @@ float log(float f); +vector centerprint_start; + float panel_order[HUD_PANEL_NUM]; string hud_panelorder_prev; @@ -20,6 +22,7 @@ float weapon_fired[WEP_MAXCOUNT]; #define MAX_ACCURACY_LEVELS 10 float acc_lev[MAX_ACCURACY_LEVELS]; float acc_levels; +string acc_color_levels; float complain_weapon; string complain_weapon_name; @@ -31,11 +34,9 @@ float ts_primary, ts_secondary; float last_weapon; float weapontime; +float weaponprevtime; float teamnagger; -float hud_accuracy_hud; -float hud_border_thickness; -float hud_accuracy_border_thickness; float hud_configure_checkcollisions; float hud_configure_prev; @@ -45,13 +46,22 @@ const float S_SHIFT = 1; const float S_CTRL = 2; const float S_ALT = 4; -float disable_menu_alphacheck; // 0 = enable alpha check, 1 = disable for entire hud, 2 = disable for one panel -float menu_fade_alpha; +float menu_enabled; // 1 showing the entire HUD, 2 showing only the clicked panel +float menu_enabled_time; + +float hud_fade_alpha; string hud_skin_path; var vector progressbar_color; +var float highlightedPanel_backup = -1; +var vector panel_pos_backup; +var vector panel_size_backup; + +var float highlightedPanel_copied = -1; //this is good only to know if there is something copied +var vector panel_size_copied; + var float active_panel; // this panel has recently referred the UpdateCvars macro var string panel_name; var float panel_enabled; @@ -85,7 +95,7 @@ var string picpath; // ---------------------- // MACRO HELL STARTS HERE // ---------------------- -// Little help for the poor people who have to make sense of this: Start from the bottom +// Little help for the poor people who have to make sense of this: Start from the bottom ;) #define HUD_Panel_GetProgressBarColor(item) \ switch(item) {\ @@ -104,18 +114,19 @@ if(!autocvar__hud_configure && panel_bg_str == "0") {\ panel_bg = "0";\ } else {\ if(panel_bg_str == "") {\ - panel_bg = autocvar_hud_panel_bg;\ - } else if(panel_bg_str == "0" && autocvar__hud_configure) {\ - panel_bg = autocvar_hud_panel_bg;\ - panel_bg_alpha_str = "0";\ - } else {\ - panel_bg = panel_bg_str;\ + panel_bg_str = autocvar_hud_panel_bg;\ }\ - panel_bg = strcat(hud_skin_path, "/", panel_bg);\ - if(precache_pic(panel_bg) == "") {\ - panel_bg = strcat(hud_skin_path, "/", "border");\ + if(panel_bg_str == "0" && !autocvar__hud_configure) {\ + panel_bg = "0";\ + } else {\ + if (panel_bg_str == "0" && autocvar__hud_configure)\ + panel_bg_alpha_str = "0";\ + panel_bg = strcat(hud_skin_path, "/", panel_bg_str);\ if(precache_pic(panel_bg) == "") {\ - panel_bg = strcat("gfx/hud/default/", "border");\ + panel_bg = strcat(hud_skin_path, "/", "border_default");\ + if(precache_pic(panel_bg) == "") {\ + panel_bg = strcat("gfx/hud/default/", "border_default");\ + }\ }\ }\ } @@ -155,14 +166,14 @@ if(panel_bg_alpha_str == "") {\ panel_bg_alpha_str = ftos(autocvar_hud_panel_bg_alpha);\ }\ panel_bg_alpha = stof(panel_bg_alpha_str);\ -if(autocvar__hud_configure && disable_menu_alphacheck == 2 && highlightedPanel == active_panel) {\ +if(autocvar__hud_configure && menu_enabled == 2 && highlightedPanel == active_panel) {\ panel_bg_alpha = (1 - autocvar__menu_alpha) * max(autocvar_hud_configure_bg_minalpha, panel_bg_alpha) + autocvar__menu_alpha * panel_bg_alpha;\ } else if(autocvar__hud_configure) {\ panel_bg_alpha = max(autocvar_hud_configure_bg_minalpha, panel_bg_alpha);\ } if(autocvar__hud_configure && !panel_enabled) {\ panel_bg_alpha = 0.25;\ -} if(!(disable_menu_alphacheck == 2 && highlightedPanel == active_panel)) {\ - panel_bg_alpha *= menu_fade_alpha;\ +} if(!(menu_enabled == 2 && highlightedPanel == active_panel)) {\ + panel_bg_alpha *= hud_fade_alpha;\ } // Get value for panel_fg_alpha. Also do various minalpha checks @@ -172,8 +183,8 @@ if(autocvar__hud_configure && disable_menu_alphacheck == 2 && highlightedPanel = panel_fg_alpha = autocvar_hud_panel_fg_alpha;\ if(autocvar__hud_configure && !panel_enabled)\ panel_fg_alpha = 0.25;\ -if(!(disable_menu_alphacheck == 2 && highlightedPanel == active_panel))\ - panel_fg_alpha *= menu_fade_alpha; +if(!(menu_enabled == 2 && highlightedPanel == active_panel))\ + panel_fg_alpha *= hud_fade_alpha; // Get border. See comments above, it's similar. #define HUD_Panel_GetBorder()\ @@ -257,7 +268,7 @@ panel_bg_alpha_str = autocvar_hud_panel_##name##_bg_alpha; \ panel_bg_border_str = autocvar_hud_panel_##name##_bg_border; \ panel_bg_padding_str = autocvar_hud_panel_##name##_bg_padding; \ HUD_Panel_StringVars()\ -if(disable_menu_alphacheck == 2 && active_panel == highlightedPanel) {\ +if(menu_enabled == 2 && active_panel == highlightedPanel) {\ HUD_Panel_GetMenuSize()\ HUD_Panel_GetMenuPos()\ } @@ -286,7 +297,7 @@ switch(id) { \ panel_pos = autocvar_hud_panel_##name##_pos; \ panel_size = autocvar_hud_panel_##name##_size; \ HUD_Panel_GetScaledVectors()\ -if(disable_menu_alphacheck == 2 && active_panel == highlightedPanel) {\ +if(menu_enabled == 2 && active_panel == highlightedPanel) {\ HUD_Panel_GetMenuSize()\ HUD_Panel_GetMenuPos()\ }\ diff --git a/qcsrc/client/interpolate.qc b/qcsrc/client/interpolate.qc index 559357050..f96d3d7f9 100644 --- a/qcsrc/client/interpolate.qc +++ b/qcsrc/client/interpolate.qc @@ -6,15 +6,17 @@ .float itime1, itime2; void InterpolateOrigin_Reset() { - self.iflags &~= (IFLAG_PREVALID | IFLAG_VALID); + self.iflags &~= IFLAG_INTERNALMASK; self.itime1 = self.itime2 = 0; } void InterpolateOrigin_Note() { float dt; + float f0; dt = time - self.itime2; + f0 = self.iflags; if(self.iflags & IFLAG_PREVALID) self.iflags |= IFLAG_VALID; else @@ -24,13 +26,22 @@ void InterpolateOrigin_Note() self.iorigin2 = self.origin; if(self.iflags & IFLAG_AUTOANGLES) - self.angles = vectoangles(self.iorigin2 - self.iorigin1); + if(self.iorigin2 != self.iorigin1) + self.angles = vectoangles(self.iorigin2 - self.iorigin1); if(self.iflags & IFLAG_ANGLES) { fixedmakevectors(self.angles); - self.iforward1 = self.iforward2; - self.iup1 = self.iup2; + if(f0 & IFLAG_VALID) + { + self.iforward1 = self.iforward2; + self.iup1 = self.iup2; + } + else + { + self.iforward1 = v_forward; + self.iup1 = v_up; + } self.iforward2 = v_forward; self.iup2 = v_up; } diff --git a/qcsrc/client/laser.qc b/qcsrc/client/laser.qc index 23ced4b64..0880ddc4b 100644 --- a/qcsrc/client/laser.qc +++ b/qcsrc/client/laser.qc @@ -22,24 +22,39 @@ void Draw_Laser() InterpolateOrigin_Do(); if(self.count & 0x80) { - traceline(self.origin, self.velocity, 0, self); + if(self.count & 0x10) + { + trace_endpos = self.velocity, + trace_dphitq3surfaceflags = 0; + } + else + traceline(self.origin, self.velocity, 0, self); } else { - makevectors(self.angles); - traceline(self.origin, self.origin + v_forward * 32768, 0, self); - if(trace_dphitq3surfaceflags & Q3SURFACEFLAG_SKY) + if(self.count & 0x10) + { + makevectors(self.angles); trace_endpos = self.origin + v_forward * 1048576; + trace_dphitq3surfaceflags = Q3SURFACEFLAG_SKY; + } + else + { + makevectors(self.angles); + traceline(self.origin, self.origin + v_forward * 32768, 0, self); + if(trace_dphitq3surfaceflags & Q3SURFACEFLAG_SKY) + trace_endpos = self.origin + v_forward * 1048576; + } } if(self.scale != 0) { if(self.alpha) { - Draw_CylindricLine(self.origin, trace_endpos, self.scale, "particles/laserbeam", 0, time * 3, self.colormod, self.alpha, DRAWFLAG_NORMAL); // TODO make a texture to make the laser look smoother + Draw_CylindricLine(self.origin, trace_endpos, self.scale, "particles/laserbeam", 0, time * 3, self.colormod, self.alpha, DRAWFLAG_NORMAL, view_origin); } else { - Draw_CylindricLine(self.origin, trace_endpos, self.scale, "particles/laserbeam", 0, time * 3, self.colormod, 0.5, DRAWFLAG_ADDITIVE); // TODO make a texture to make the laser look smoother + Draw_CylindricLine(self.origin, trace_endpos, self.scale, "particles/laserbeam", 0, time * 3, self.colormod, 0.5, DRAWFLAG_ADDITIVE, view_origin); } } if not(trace_dphitq3surfaceflags & (Q3SURFACEFLAG_SKY | Q3SURFACEFLAG_NOIMPACT)) @@ -58,7 +73,7 @@ void Ent_Laser() // 30 bytes, or 13 bytes for just moving f = ReadByte(); - self.count = (f & 0xE0); + self.count = (f & 0xF0); if(self.count & 0x80) self.iflags = IFLAG_VELOCITY; @@ -87,7 +102,10 @@ void Ent_Laser() self.scale *= ReadByte() / 16.0; // beam radius self.modelscale *= ReadByte() / 16.0; // dlight radius } - self.cnt = ReadShort() - 1; // effect number + if((f & 0x80) || !(f & 0x10)) + self.cnt = ReadShort() - 1; // effect number + else + self.cnt = 0; } if(f & 2) { diff --git a/qcsrc/client/main.qh b/qcsrc/client/main.qh index f00e49c53..2294ffd15 100644 --- a/qcsrc/client/main.qh +++ b/qcsrc/client/main.qh @@ -95,7 +95,6 @@ float teamscores_flags[MAX_SCORE]; vector hud_fontsize; -vector hud_fontsize_spec; float RANKINGS_RECEIVED_CNT; string grecordholder[RANKINGS_CNT]; diff --git a/qcsrc/client/mapvoting.qc b/qcsrc/client/mapvoting.qc index 7c3bcecc5..40fcfda11 100644 --- a/qcsrc/client/mapvoting.qc +++ b/qcsrc/client/mapvoting.qc @@ -71,8 +71,8 @@ void MapVote_DrawMapItem(vector pos, float isize, float tsize, string map, strin pos_x = pos_x + text_size*0.5 - img_size_x*0.5; pos_y = pos_y - img_size_y; - pos += hud_border_thickness * '1 1 0'; - img_size -= (hud_border_thickness * 2) * '1 1 0'; + pos += autocvar_scoreboard_border_thickness * '1 1 0'; + img_size -= (autocvar_scoreboard_border_thickness * 2) * '1 1 0'; if(pic == "") { drawfill(pos, img_size, '.5 .5 .5', .7, DRAWFLAG_NORMAL); @@ -81,19 +81,14 @@ void MapVote_DrawMapItem(vector pos, float isize, float tsize, string map, strin { drawpic(pos, pic, img_size, '1 1 1', 1, DRAWFLAG_NORMAL); } - - drawpic(pos + '1 0 0', strcat("gfx/hud/num_", ftos(id+1)), (img_size_y / 5) * '1 1 0', '1 1 1', 0.6, DRAWFLAG_NORMAL); - if(id == mv_ownvote || pic == "") - { - drawborderlines(hud_border_thickness, pos, img_size, rgb, 1, DRAWFLAG_NORMAL); - drawpic(pos + '1 0 0', strcat("gfx/hud/num_", ftos(id+1)), (img_size_y / 5) * '1 1 0', rgb, 0.6, DRAWFLAG_NORMAL); - } + if(id == mv_ownvote) + drawborderlines(autocvar_scoreboard_border_thickness, pos, img_size, rgb, 1, DRAWFLAG_NORMAL); else - { - drawborderlines(hud_border_thickness, pos, img_size, '0 0 0', 1, DRAWFLAG_NORMAL); - drawpic(pos + '1 0 0', strcat("gfx/hud/num_", ftos(id+1)), (img_size_y / 5) * '1 1 0', '1 1 1', 0.6, DRAWFLAG_NORMAL); - } + drawborderlines(autocvar_scoreboard_border_thickness, pos, img_size, '0 0 0', 1, DRAWFLAG_NORMAL); + + if(id == mv_selection) + drawfill(pos, img_size, '1 1 1', 0.1, DRAWFLAG_NORMAL); } void MapVote_DrawAbstain(vector pos, float isize, float tsize, float count, float id) diff --git a/qcsrc/client/miscfunctions.qc b/qcsrc/client/miscfunctions.qc index 026987450..5c377bffa 100644 --- a/qcsrc/client/miscfunctions.qc +++ b/qcsrc/client/miscfunctions.qc @@ -8,7 +8,7 @@ void serverAnnouncer() // check for pending announcement, play it and remove it if(announce_snd != "") { - sound(self, CHAN_VOICE, strcat("announcer/", cvar_string("cl_announcer"), "/", announce_snd, ".wav"), VOL_BASEVOICE, ATTN_NONE); + sound(world, CHAN_AUTO, strcat("announcer/", cvar_string("cl_announcer"), "/", announce_snd, ".wav"), VOL_BASEVOICE, ATTN_NONE); strunzone(announce_snd); announce_snd = ""; } @@ -22,7 +22,7 @@ void restartAnnouncer_Think() { if (!spectatee_status) //do cprint only for players centerprint("^1Begin!"); - sound(self, CHAN_VOICE, strcat("announcer/", cvar_string("cl_announcer"), "/begin.wav"), VOL_BASEVOICE, ATTN_NONE); + sound(world, CHAN_AUTO, strcat("announcer/", cvar_string("cl_announcer"), "/begin.wav"), VOL_BASEVOICE, ATTN_NONE); //reset maptime announcers now as well announcer_5min = announcer_1min = FALSE; @@ -34,7 +34,7 @@ void restartAnnouncer_Think() { centerprint(strcat("^1Game starts in ", ftos(countdown_rounded), " seconds")); if(countdown_rounded <= 3 && countdown_rounded >= 1) { - sound(self, CHAN_VOICE, strcat("announcer/", cvar_string("cl_announcer"), "/", ftos(countdown_rounded), ".wav"), VOL_BASEVOICE, ATTN_NONE); + sound(world, CHAN_AUTO, strcat("announcer/", cvar_string("cl_announcer"), "/", ftos(countdown_rounded), ".wav"), VOL_BASEVOICE, ATTN_NONE); } self.nextthink = getstatf(STAT_GAMESTARTTIME) - (countdown - 1); @@ -72,7 +72,7 @@ void maptimeAnnouncer() { if not (warmuplimit == -1 && warmup_stage) { announcer_5min = TRUE; //dprint("i will play the sound, I promise!\n"); - sound(self, CHAN_VOICE, strcat("announcer/", cvar_string("cl_announcer"), "/5minutesremain.wav"), VOL_BASEVOICE, ATTN_NONE); + sound(world, CHAN_AUTO, strcat("announcer/", cvar_string("cl_announcer"), "/5minutesremain.wav"), VOL_BASEVOICE, ATTN_NONE); } } @@ -87,7 +87,7 @@ void maptimeAnnouncer() { //if we're in warmup mode, check whether there's a warmup timelimit if not (warmuplimit == -1 && warmup_stage) { announcer_1min = TRUE; - sound(self, CHAN_VOICE, strcat("announcer/", cvar_string("cl_announcer"), "/1minuteremains.wav"), VOL_BASEVOICE, ATTN_NONE); + sound(world, CHAN_AUTO, strcat("announcer/", cvar_string("cl_announcer"), "/1minuteremains.wav"), VOL_BASEVOICE, ATTN_NONE); } } } @@ -324,19 +324,6 @@ vector HUD_GetFontsize(string cvarname) return v; } -float HUD_GetWidth(float teamcolumnwidth) -{ - float f; - f = cvar("hud_width"); - if(f == 0) - f = 640; - if(f < 320) - f = 320; - if(f > vid_conwidth - 2 * teamcolumnwidth) - f = vid_conwidth - 2 * teamcolumnwidth; - return f; -} - float PreviewExists(string name) { float f; @@ -663,3 +650,153 @@ void PolyDrawModel(entity e) } } } + +void DrawCircleClippedPic(vector centre, float radius, string pic, float f, vector rgb, float a, float drawflag) +{ + float x, y, q, d; + vector ringsize, v, t; + ringsize = radius * '1 1 0'; + + x = cos(f * 2 * M_PI); + y = sin(f * 2 * M_PI); + q = fabs(x) + fabs(y); + x /= q; + y /= q; + + if(f >= 1) + { + // draw full rectangle + R_BeginPolygon(pic, drawflag); + v = centre; t = '0.5 0.5 0'; + v_x += 0.5 * ringsize_x; t += '0.5 0.5 0'; + R_PolygonVertex(v, t, rgb, a); + + v = centre; t = '0.5 0.5 0'; + v_y += 0.5 * ringsize_y; t += '0.5 -0.5 0'; + R_PolygonVertex(v, t, rgb, a); + + v = centre; t = '0.5 0.5 0'; + v_x -= 0.5 * ringsize_x; t -= '0.5 0.5 0'; + R_PolygonVertex(v, t, rgb, a); + + v = centre; t = '0.5 0.5 0'; + v_y -= 0.5 * ringsize_y; t -= '0.5 -0.5 0'; + R_PolygonVertex(v, t, rgb, a); + R_EndPolygon(); + + d = q - 1; + if(d > 0) + { + R_BeginPolygon(pic, drawflag); + v = centre; t = '0.5 0.5 0'; + R_PolygonVertex(v, t, rgb, a); + + v = centre; t = '0.5 0.5 0'; + v_x += 0.5 * ringsize_x; t += '0.5 0.5 0'; + R_PolygonVertex(v, t, rgb, a); + } + } + else if(f > 0.75) + { + // draw upper and first triangle + R_BeginPolygon(pic, drawflag); + v = centre; t = '0.5 0.5 0'; + v_x += 0.5 * ringsize_x; t += '0.5 0.5 0'; + R_PolygonVertex(v, t, rgb, a); + + v = centre; t = '0.5 0.5 0'; + v_y += 0.5 * ringsize_y; t += '0.5 -0.5 0'; + R_PolygonVertex(v, t, rgb, a); + + v = centre; t = '0.5 0.5 0'; + v_x -= 0.5 * ringsize_x; t -= '0.5 0.5 0'; + R_PolygonVertex(v, t, rgb, a); + R_EndPolygon(); + R_BeginPolygon(pic, drawflag); + v = centre; t = '0.5 0.5 0'; + R_PolygonVertex(v, t, rgb, a); + + v = centre; t = '0.5 0.5 0'; + v_x -= 0.5 * ringsize_x; t -= '0.5 0.5 0'; + R_PolygonVertex(v, t, rgb, a); + + v = centre; t = '0.5 0.5 0'; + v_y -= 0.5 * ringsize_y; t -= '0.5 -0.5 0'; + R_PolygonVertex(v, t, rgb, a); + + d = q - 0.75; + if(d <= 0) + R_EndPolygon(); + } + else if(f > 0.5) + { + // draw upper triangle + R_BeginPolygon(pic, drawflag); + v = centre; t = '0.5 0.5 0'; + v_x += 0.5 * ringsize_x; t += '0.5 0.5 0'; + R_PolygonVertex(v, t, rgb, a); + + v = centre; t = '0.5 0.5 0'; + v_y += 0.5 * ringsize_y; t += '0.5 -0.5 0'; + R_PolygonVertex(v, t, rgb, a); + + v = centre; t = '0.5 0.5 0'; + v_x -= 0.5 * ringsize_x; t -= '0.5 0.5 0'; + R_PolygonVertex(v, t, rgb, a); + R_EndPolygon(); + + d = q - 0.5; + if(d > 0) + { + R_BeginPolygon(pic, drawflag); + v = centre; t = '0.5 0.5 0'; + R_PolygonVertex(v, t, rgb, a); + + v = centre; t = '0.5 0.5 0'; + v_x -= 0.5 * ringsize_x; t -= '0.5 0.5 0'; + R_PolygonVertex(v, t, rgb, a); + } + } + else if(f > 0.25) + { + // draw first triangle + R_BeginPolygon(pic, drawflag); + v = centre; t = '0.5 0.5 0'; + R_PolygonVertex(v, t, rgb, a); + + v = centre; t = '0.5 0.5 0'; + v_x += 0.5 * ringsize_x; t += '0.5 0.5 0'; + R_PolygonVertex(v, t, rgb, a); + + v = centre; t = '0.5 0.5 0'; + v_y += 0.5 * ringsize_y; t += '0.5 -0.5 0'; + R_PolygonVertex(v, t, rgb, a); + + d = q - 0.25; + if(d <= 0) + R_EndPolygon(); + } + else + { + d = q; + if(d > 0) + { + R_BeginPolygon(pic, drawflag); + v = centre; t = '0.5 0.5 0'; + R_PolygonVertex(v, t, rgb, a); + + v = centre; t = '0.5 0.5 0'; + v_x += 0.5 * ringsize_x; t += '0.5 0.5 0'; + R_PolygonVertex(v, t, rgb, a); + } + } + + if(d > 0) + { + v = centre; t = '0.5 0.5 0'; + v_x += x * 0.5 * ringsize_x; t += x * '0.5 0.5 0'; + v_y += y * 0.5 * ringsize_y; t += y * '0.5 -0.5 0'; + R_PolygonVertex(v, t, rgb, a); + R_EndPolygon(); + } +} diff --git a/qcsrc/client/modeleffects.qc b/qcsrc/client/modeleffects.qc index 765257732..1b5465349 100644 --- a/qcsrc/client/modeleffects.qc +++ b/qcsrc/client/modeleffects.qc @@ -14,9 +14,12 @@ void ModelEffect_Draw() remove(self); return; } + self.drawmask = MASK_NORMAL; if(self.scale <= 0) + { + self.drawmask = 0; return; - R_AddEntity(self); + } } void Ent_ModelEffect(float isNew) diff --git a/qcsrc/client/particles.qc b/qcsrc/client/particles.qc index e0bbeb81b..e9a02631f 100644 --- a/qcsrc/client/particles.qc +++ b/qcsrc/client/particles.qc @@ -58,7 +58,7 @@ void Draw_PointParticles() if(self.noise != "") { self.origin = p; - sound(self, CHAN_AUTO, self.noise, VOL_BASE * self.volume, self.atten); + sound(self, CHAN_TRIGGER, self.noise, VOL_BASE * self.volume, self.atten); } self.just_toggled = 0; } @@ -286,14 +286,18 @@ void Net_ReadZCurveParticles() void Net_ReadNexgunBeamParticle() { vector shotorg, endpos; + float charge; shotorg_x = ReadCoord(); shotorg_y = ReadCoord(); shotorg_z = ReadCoord(); endpos_x = ReadCoord(); endpos_y = ReadCoord(); endpos_z = ReadCoord(); + charge = ReadByte() / 255.0; pointparticles(particleeffectnum("nex_muzzleflash"), shotorg, normalize(endpos - shotorg) * 1000, 1); //draw either the old v2.3 beam or the new beam + charge = sqrt(charge); // divide evenly among trail spacing and alpha + particles_alphamin = particles_alphamax = charge; if (cvar("cl_particles_oldnexbeam") && (getstati(STAT_ALLOW_OLDNEXBEAM) || isdemo())) - WarpZone_TrailParticles(world, particleeffectnum("TE_TEI_G3"), shotorg, endpos); + WarpZone_TrailParticles_WithMultiplier(world, particleeffectnum("TE_TEI_G3"), shotorg, endpos, charge, 1); else - WarpZone_TrailParticles(world, particleeffectnum("nex_beam"), shotorg, endpos); + WarpZone_TrailParticles_WithMultiplier(world, particleeffectnum("nex_beam"), shotorg, endpos, charge, 1); } diff --git a/qcsrc/client/progs.src b/qcsrc/client/progs.src index 4569e497c..1334d7d3c 100644 --- a/qcsrc/client/progs.src +++ b/qcsrc/client/progs.src @@ -22,6 +22,7 @@ autocvars.qh interpolate.qh teamradar.qh hud.qh +scoreboard.qh waypointsprites.qh movetypes.qh prandom.qh diff --git a/qcsrc/client/projectile.qc b/qcsrc/client/projectile.qc index 407b86c74..fb07b21b8 100644 --- a/qcsrc/client/projectile.qc +++ b/qcsrc/client/projectile.qc @@ -72,7 +72,8 @@ void Projectile_Draw() else Movetype_Physics_MatchServer(autocvar_cl_projectiles_sloppy); if(!(self.move_flags & FL_ONGROUND)) - self.angles = vectoangles(self.velocity); + if(self.velocity != '0 0 0') + self.angles = vectoangles(self.velocity); } else { @@ -138,6 +139,8 @@ void Projectile_Draw() else Projectile_ResetTrail(trailorigin); + self.drawmask = 0; + if(!drawn) return; @@ -151,7 +154,7 @@ void Projectile_Draw() break; } - R_AddEntity(self); + self.drawmask = MASK_NORMAL; } void loopsound(entity e, float ch, string samp, float vol, float attn) @@ -278,6 +281,7 @@ void Ent_Projectile() case PROJECTILE_ELECTRO_BEAM: setmodel(self, "models/elaser.mdl");self.traileffect = particleeffectnum("TR_NEXUIZPLASMA"); break; case PROJECTILE_GRENADE: setmodel(self, "models/grenademodel.md3");self.traileffect = particleeffectnum("TR_GRENADE"); break; case PROJECTILE_GRENADE_BOUNCING: setmodel(self, "models/grenademodel.md3");self.traileffect = particleeffectnum("TR_GRENADE"); break; + case PROJECTILE_MINE: setmodel(self, "models/mine.md3");self.traileffect = particleeffectnum(""); break; case PROJECTILE_LASER: setmodel(self, "models/laser.mdl");self.traileffect = particleeffectnum(""); break; case PROJECTILE_HLAC: setmodel(self, "models/hlac_bullet.md3");self.traileffect = particleeffectnum(""); break; case PROJECTILE_PORTO_RED: setmodel(self, "models/grenademodel.md3");self.traileffect = particleeffectnum("TR_WIZSPIKE"); self.scale = 4; break; @@ -318,17 +322,21 @@ void Ent_Projectile() self.maxs = '3 3 3'; break; case PROJECTILE_GRENADE: - self.mins = '0 0 -3'; - self.maxs = '0 0 -3'; + self.mins = '-3 -3 -3'; + self.maxs = '3 3 3'; break; case PROJECTILE_GRENADE_BOUNCING: - self.mins = '0 0 -3'; - self.maxs = '0 0 -3'; + self.mins = '-3 -3 -3'; + self.maxs = '3 3 3'; self.move_movetype = MOVETYPE_BOUNCE; self.move_touch = SUB_Null; self.move_bounce_factor = g_balance_grenadelauncher_secondary_bouncefactor; self.move_bounce_stopspeed = g_balance_grenadelauncher_secondary_bouncestop; break; + case PROJECTILE_MINE: + self.mins = '-4 -4 -4'; + self.maxs = '4 4 4'; + break; case PROJECTILE_PORTO_RED: self.colormod = '2 1 1'; self.alphamod = 0.5; @@ -406,6 +414,7 @@ void Projectile_Precache() precache_model("models/ebomb.mdl"); precache_model("models/elaser.mdl"); precache_model("models/grenademodel.md3"); + precache_model("models/mine.md3"); precache_model("models/hagarmissile.mdl"); precache_model("models/hlac_bullet.md3"); precache_model("models/laser.mdl"); diff --git a/qcsrc/client/scoreboard.qc b/qcsrc/client/scoreboard.qc index 29fb20642..4000f30a7 100644 --- a/qcsrc/client/scoreboard.qc +++ b/qcsrc/client/scoreboard.qc @@ -595,8 +595,8 @@ string HUD_FixScoreboardColumnWidth(float i, string str) for(j = 0; j < hud_num_fields; ++j) if(j != i) if (hud_field[i] != SP_SEPARATOR) - namesize -= hud_size[j] + 1; - namesize += 1; + namesize -= hud_size[j] + hud_fontsize_x; + namesize += hud_fontsize_x; hud_size[i] = namesize; if (hud_fixscoreboardcolumnwidth_iconlen != 0) @@ -760,37 +760,43 @@ vector HUD_Scoreboard_MakeTable(vector pos, entity tm, vector rgb, vector bg_siz tmp_y = 1.25 * hud_fontsize_y; // rounded header - drawpic(pos, "gfx/scoreboard/scoreboard_tableheader", tmp, (rgb * autocvar_hud_color_bg_team) + '0.5 0.5 0.5', scoreboard_alpha_bg, DRAWFLAG_NORMAL); + if (teamplay) + drawpic(pos, "gfx/scoreboard/scoreboard_tableheader", tmp, (rgb * autocvar_scoreboard_color_bg_team) + '0.5 0.5 0.5', scoreboard_alpha_bg, DRAWFLAG_NORMAL); + else + drawpic(pos, "gfx/scoreboard/scoreboard_tableheader", tmp, rgb + '0.5 0.5 0.5', scoreboard_alpha_bg, DRAWFLAG_NORMAL); // table border - tmp_y += hud_border_thickness; + tmp_y += autocvar_scoreboard_border_thickness; tmp_y += body_table_height; - drawborderlines(hud_border_thickness, pos, tmp, '0 0 0', scoreboard_alpha_bg, DRAWFLAG_NORMAL); // more transparency for the scoreboard + drawborderlines(autocvar_scoreboard_border_thickness, pos, tmp, '0 0 0', scoreboard_alpha_bg, DRAWFLAG_NORMAL); // more transparency for the scoreboard // separator header/table pos_y += 1.25 * hud_fontsize_y; - tmp_y = hud_border_thickness; + tmp_y = autocvar_scoreboard_border_thickness; drawfill(pos, tmp, '0 0 0', scoreboard_alpha_bg, DRAWFLAG_NORMAL); - pos_y += hud_border_thickness; + pos_y += autocvar_scoreboard_border_thickness; // table background tmp_y = body_table_height; - drawpic_tiled(pos, "gfx/scoreboard/scoreboard_bg", bg_size, tmp, rgb * autocvar_hud_color_bg_team, scoreboard_alpha_bg, DRAWFLAG_NORMAL); + if (teamplay) + drawpic_tiled(pos, "gfx/scoreboard/scoreboard_bg", bg_size, tmp, rgb * autocvar_scoreboard_color_bg_team, scoreboard_alpha_bg, DRAWFLAG_NORMAL); + else + drawpic_tiled(pos, "gfx/scoreboard/scoreboard_bg", bg_size, tmp, rgb, scoreboard_alpha_bg, DRAWFLAG_NORMAL); // anyway, apply some color //drawfill(pos, tmp + '2 0 0', rgb, 0.1, DRAWFLAG_NORMAL); // go back to the top to make alternated columns highlighting and to print the strings pos_y -= 1.25 * hud_fontsize_y; - pos_y -= hud_border_thickness; + pos_y -= autocvar_scoreboard_border_thickness; pos += '1 1 0'; if (scoreboard_highlight) { column_dim_y = 1.25 * hud_fontsize_y; // header - column_dim_y += hud_border_thickness; + column_dim_y += autocvar_scoreboard_border_thickness; column_dim_y += body_table_height; } @@ -840,7 +846,7 @@ vector HUD_Scoreboard_MakeTable(vector pos, entity tm, vector rgb, vector bg_siz pos_x = xmin; pos_y += 1.25 * hud_fontsize_y; // skip the header - pos_y += hud_border_thickness; + pos_y += autocvar_scoreboard_border_thickness; // fill the table and draw the rows i = 0; @@ -877,11 +883,9 @@ float HUD_WouldDrawScoreboard() { return 1; else if (intermission == 1) return 1; - else if (intermission == 2) - return 1; else if (getstati(STAT_HEALTH) <= 0 && cvar("cl_deathscoreboard")) return 1; - else if(scoreboard_showscores_force) + else if (scoreboard_showscores_force) return 1; return 0; } @@ -892,7 +896,6 @@ vector HUD_DrawScoreboardAccuracyStats(vector pos, vector rgb, vector bg_size) { float i; float weapon_hit, weapon_damage, weapon_stats; - float fontsize = 40 * 1/3; float weapon_cnt = WEP_COUNT - 3; // either minstanex/nex are hidden, no port-o-launch, no tuba float rows; if(cvar("scoreboard_accuracy_doublerows")) @@ -900,32 +903,33 @@ vector HUD_DrawScoreboardAccuracyStats(vector pos, vector rgb, vector bg_size) else rows = 1; float height = 40; - - if(warmup_stage) - { - return pos; - } + float fontsize = height * 1/3; + float weapon_height = height * 2/3; + float weapon_width = sbwidth / weapon_cnt; drawstring(pos, strcat("Accuracy stats (average ", ftos(average_accuracy), "%)"), hud_fontsize, '1 1 1', scoreboard_alpha_fg, DRAWFLAG_NORMAL); - pos_y += 18; + pos_y += 1.25 * hud_fontsize_y; vector tmp; tmp_x = sbwidth; tmp_y = height * rows; - drawpic_tiled(pos, "gfx/scoreboard/scoreboard_bg", bg_size, tmp, rgb * autocvar_hud_color_bg_team, scoreboard_alpha_bg, DRAWFLAG_NORMAL); - drawborderlines(hud_accuracy_border_thickness, pos, tmp, '0 0 0', scoreboard_alpha_bg * 0.75, DRAWFLAG_NORMAL); + if (teamplay) + drawpic_tiled(pos, "gfx/scoreboard/scoreboard_bg", bg_size, tmp, rgb * autocvar_scoreboard_color_bg_team, scoreboard_alpha_bg, DRAWFLAG_NORMAL); + else + drawpic_tiled(pos, "gfx/scoreboard/scoreboard_bg", bg_size, tmp, rgb, scoreboard_alpha_bg, DRAWFLAG_NORMAL); + drawborderlines(autocvar_scoreboard_border_thickness, pos, tmp, '0 0 0', scoreboard_alpha_bg * 0.75, DRAWFLAG_NORMAL); // column highlighting for(i = 0; i < weapon_cnt/rows; ++i) { if(!mod(i, 2)) - drawfill(pos + '1 0 0' * (sbwidth/weapon_cnt) * rows * i, '0 1 0' * height * rows + '1 0 0' * (sbwidth/weapon_cnt) * rows, '0 0 0', scoreboard_alpha_bg * 0.2, DRAWFLAG_NORMAL); + drawfill(pos + '1 0 0' * weapon_width * rows * i, '0 1 0' * height * rows + '1 0 0' * weapon_width * rows, '0 0 0', scoreboard_alpha_bg * 0.2, DRAWFLAG_NORMAL); } // row highlighting for(i = 0; i < rows; ++i) { - drawfill(pos + '0 1 0' * height * (2/3) + '0 1 0' * height * i, '1 0 0' * sbwidth + '0 1 0' * fontsize, '1 1 1', scoreboard_highlight_alpha, DRAWFLAG_NORMAL); + drawfill(pos + '0 1 0' * weapon_height + '0 1 0' * height * i, '1 0 0' * sbwidth + '0 1 0' * fontsize, '1 1 1', scoreboard_highlight_alpha, DRAWFLAG_NORMAL); } drawfont = hud_bigfont; @@ -933,11 +937,14 @@ vector HUD_DrawScoreboardAccuracyStats(vector pos, vector rgb, vector bg_size) float weapons_with_stats; weapons_with_stats = 0; if(rows == 2) - pos_x += sbwidth/weapon_cnt / 2; + pos_x += weapon_width / 2; if(getstati(STAT_SWITCHWEAPON) == WEP_MINSTANEX) g_minstagib = 1; // TODO: real detection for minstagib? + if (!acc_levels) + rgb = '1 1 1'; + for(i = WEP_FIRST; i <= WEP_LAST; ++i) { self = get_weaponinfo(i); @@ -957,7 +964,7 @@ vector HUD_DrawScoreboardAccuracyStats(vector pos, vector rgb, vector bg_size) weapon_alpha = 0.2 * scoreboard_alpha_fg; // weapon icon - drawpic_aspect_skin(pos, strcat("weapon", self.netname), '1 0 0' * sbwidth * (1/weapon_cnt) + '0 1 0' * height * (2/3), '1 1 1', weapon_alpha, DRAWFLAG_NORMAL); + drawpic_aspect_skin(pos, strcat("weapon", self.netname), '1 0 0' * weapon_width + '0 1 0' * weapon_height, '1 1 1', weapon_alpha, DRAWFLAG_NORMAL); // the accuracy if(weapon_damage) { weapons_with_stats += 1; @@ -967,7 +974,7 @@ vector HUD_DrawScoreboardAccuracyStats(vector pos, vector rgb, vector bg_size) s = strcat(ftos(weapon_stats),"%"); float padding; - padding = ((sbwidth/weapon_cnt) - stringwidth(s, FALSE, '1 0 0' * fontsize)) / 2; // center the accuracy value + padding = (weapon_width - stringwidth(s, FALSE, '1 0 0' * fontsize)) / 2; // center the accuracy value float weapon_hit, weapon_damage; weapon_damage = weapon_fired[self.weapon-WEP_FIRST]; @@ -977,21 +984,24 @@ vector HUD_DrawScoreboardAccuracyStats(vector pos, vector rgb, vector bg_size) weapon_stats = floor(100 * weapon_hit / weapon_damage); } - // find the max level lower than weapon_stats - float j; - j = acc_levels-1; - while ( j && weapon_stats < acc_lev[j] ) - --j; - - // inject color j+1 in color j, how much depending on how much weapon_stats is higher than level j - float factor; - factor = (weapon_stats - acc_lev[j]) / (acc_lev[j+1] - acc_lev[j]); - rgb = acc_color(j); - rgb = rgb + factor * (acc_color(j+1) - rgb); + if (acc_levels) + { + // find the max level lower than weapon_stats + float j; + j = acc_levels-1; + while ( j && weapon_stats < acc_lev[j] ) + --j; + + // inject color j+1 in color j, how much depending on how much weapon_stats is higher than level j + float factor; + factor = (weapon_stats - acc_lev[j]) / (acc_lev[j+1] - acc_lev[j]); + rgb = acc_color(j); + rgb = rgb + factor * (acc_color(j+1) - rgb); + } - drawstring(pos + '1 0 0' * padding + '0 1 0' * height * (2/3), s, '1 1 0' * fontsize, rgb, scoreboard_alpha_fg, DRAWFLAG_NORMAL); + drawstring(pos + '1 0 0' * padding + '0 1 0' * weapon_height, s, '1 1 0' * fontsize, rgb, scoreboard_alpha_fg, DRAWFLAG_NORMAL); } - pos_x += sbwidth/weapon_cnt * rows; + pos_x += weapon_width * rows; if(rows == 2 && i == 6) { pos_x -= sbwidth; pos_y += height; @@ -1003,9 +1013,11 @@ vector HUD_DrawScoreboardAccuracyStats(vector pos, vector rgb, vector bg_size) average_accuracy = floor(average_accuracy / weapons_with_stats); if(rows == 2) - pos_x -= sbwidth/weapon_cnt / 2; + pos_x -= weapon_width / 2; pos_x -= sbwidth; pos_y += height; + + pos_y += 1.25 * hud_fontsize_y; return pos; } @@ -1013,9 +1025,9 @@ vector HUD_DrawScoreboardRankings(vector pos, entity pl, vector rgb, vector bg_ { float i; RANKINGS_RECEIVED_CNT = 0; - for (i=RANKINGS_CNT-1; i>=0; --i) - if (grecordtime[i]) - RANKINGS_RECEIVED_CNT = RANKINGS_RECEIVED_CNT + 1; + for (i=RANKINGS_CNT-1; i>=0; --i) + if (grecordtime[i]) + ++RANKINGS_RECEIVED_CNT; if (RANKINGS_RECEIVED_CNT == 0) return pos; @@ -1023,9 +1035,9 @@ vector HUD_DrawScoreboardRankings(vector pos, entity pl, vector rgb, vector bg_ float is_spec; is_spec = (GetPlayerColor(pl.sv_entnum) == COLOR_SPECTATOR); vector hl_rgb; - hl_rgb_x = cvar("scoreboard_color_bg_r") + 0.5; - hl_rgb_y = cvar("scoreboard_color_bg_g") + 0.5; - hl_rgb_z = cvar("scoreboard_color_bg_b") + 0.5; + hl_rgb_x = cvar("scoreboard_color_bg_r") + 0.5; + hl_rgb_y = cvar("scoreboard_color_bg_g") + 0.5; + hl_rgb_z = cvar("scoreboard_color_bg_b") + 0.5; pos_y += hud_fontsize_y; drawstring(pos, strcat("Rankings"), hud_fontsize, '1 1 1', scoreboard_alpha_fg, DRAWFLAG_NORMAL); @@ -1034,8 +1046,11 @@ vector HUD_DrawScoreboardRankings(vector pos, entity pl, vector rgb, vector bg_ tmp_x = sbwidth; tmp_y = hud_fontsize_y * RANKINGS_RECEIVED_CNT; - drawpic_tiled(pos, "gfx/scoreboard/scoreboard_bg", bg_size, tmp, rgb * autocvar_hud_color_bg_team, scoreboard_alpha_bg, DRAWFLAG_NORMAL); - drawborderlines(hud_border_thickness, pos, tmp, '0 0 0', scoreboard_alpha_bg * 0.75, DRAWFLAG_NORMAL); + if (teamplay) + drawpic_tiled(pos, "gfx/scoreboard/scoreboard_bg", bg_size, tmp, rgb * autocvar_scoreboard_color_bg_team, scoreboard_alpha_bg, DRAWFLAG_NORMAL); + else + drawpic_tiled(pos, "gfx/scoreboard/scoreboard_bg", bg_size, tmp, rgb, scoreboard_alpha_bg, DRAWFLAG_NORMAL); + drawborderlines(autocvar_scoreboard_border_thickness, pos, tmp, '0 0 0', scoreboard_alpha_bg * 0.75, DRAWFLAG_NORMAL); // row highlighting for(i = 0; i 0) + { + if(d == 1) + self.modelindex = self.lodmodelindex0; + else if(d == 2 || !self.lodmodelindex2) + self.modelindex = self.lodmodelindex1; + else // if(d == 3) + self.modelindex = self.lodmodelindex2; + } + else + { + d = vlen(NearestPointOnBox(self, view_origin) - view_origin); + if(d < self.loddistance1) + self.modelindex = self.lodmodelindex0; + else if(!self.lodmodelindex2 || d < self.loddistance2) + self.modelindex = self.lodmodelindex1; + else + self.modelindex = self.lodmodelindex2; + } + } + InterpolateOrigin_Do(); if(self.bgmscriptangular) - fld = angles; + self.saved = self.angles; else - fld = origin; - - save = self.fld; + self.saved = self.origin; + f = BGMScript(self); if(f >= 0) { @@ -28,9 +60,9 @@ void Ent_Wall_Draw() self.alpha = 1; if(self.alpha >= ALPHA_MIN_VISIBLE) - R_AddEntity(self); - - self.fld = save; + self.drawmask = MASK_NORMAL; + else + self.drawmask = 0; } void Ent_Wall_Remove() @@ -46,6 +78,11 @@ void Ent_Wall() InterpolateOrigin_Undo(); self.iflags = IFLAG_ANGLES; + if(self.bgmscriptangular) + self.angles = self.saved; + else + self.origin = self.saved; + f = ReadByte(); if(f & 1) @@ -77,9 +114,22 @@ void Ent_Wall() if(f & 8) { - self.modelindex = ReadShort(); + if(f & 0x80) + { + self.lodmodelindex0 = ReadShort(); + self.loddistance1 = ReadShort(); + self.lodmodelindex1 = ReadShort(); + self.loddistance2 = ReadShort(); + self.lodmodelindex2 = ReadShort(); + } + else + { + self.modelindex = ReadShort(); + self.loddistance1 = 0; + self.loddistance2 = 0; + } self.solid = ReadByte(); - self.scale = ReadByte() / 16.0; + self.scale = ReadShort() / 256.0; if(f & 0x20) { self.mins_x = ReadCoord(); @@ -121,6 +171,11 @@ void Ent_Wall() InterpolateOrigin_Note(); + if(self.bgmscriptangular) + self.saved = self.angles; + else + self.saved = self.origin; + self.entremove = Ent_Wall_Remove; self.draw = Ent_Wall_Draw; } diff --git a/qcsrc/client/waypointsprites.qc b/qcsrc/client/waypointsprites.qc index d7b9ee9d0..07e912782 100644 --- a/qcsrc/client/waypointsprites.qc +++ b/qcsrc/client/waypointsprites.qc @@ -431,16 +431,28 @@ void WaypointSprite_Load() { float dh, n, i, o, f; string s, sname, sframes; + dh = search_begin("models/sprites/*_frame*.tga", FALSE, FALSE); n = search_getsize(dh); for(i = 0; i < n; ++i) { s = search_getfilename(dh, i); - if(substring(s, 0, 15) != "models/sprites/") - continue; - if(substring(s, strlen(s) - 4, 4) != ".tga") - continue; - s = substring(s, 15, strlen(s) - 19); + s = substring(s, 15, strlen(s) - 15 - 4); // strip models/sprites/ and .tga + + o = strstrofs(s, "_frame", 0); + sname = strcat("/spriteframes/", substring(s, 0, o)); + sframes = substring(s, o + 6, strlen(s) - o - 6); + f = stof(sframes) + 1; + db_put(tempdb, sname, ftos(max(f, stof(db_get(tempdb, sname))))); + } + search_end(dh); + + dh = search_begin("models/sprites/*_frame*.jpg", FALSE, FALSE); + n = search_getsize(dh); + for(i = 0; i < n; ++i) + { + s = search_getfilename(dh, i); + s = substring(s, 15, strlen(s) - 15 - 4); // strip models/sprites/ and .jpg o = strstrofs(s, "_frame", 0); sname = strcat("/spriteframes/", substring(s, 0, o)); diff --git a/qcsrc/common/constants.qh b/qcsrc/common/constants.qh index 53f37bcdd..6f0eccfaf 100644 --- a/qcsrc/common/constants.qh +++ b/qcsrc/common/constants.qh @@ -61,6 +61,7 @@ const float TE_CSQC_NOTIFY = 112; const float TE_CSQC_WEAPONCOMPLAIN = 113; const float TE_CSQC_CAMPINGRIFLE_SCOPE = 115; const float TE_CSQC_NEX_SCOPE = 116; +const float TE_CSQC_CR_MAXBULLETS = 117; const float RACE_NET_CHECKPOINT_HIT_QUALIFYING = 0; // byte checkpoint, short time, short recordtime, string recordholder const float RACE_NET_CHECKPOINT_CLEAR = 1; @@ -308,6 +309,7 @@ const float STAT_NB_METERSTART = 45; const float STAT_SHOTORG = 46; // compressShotOrigin const float STAT_LEADLIMIT = 47; const float STAT_BULLETS_LOADED = 48; +const float STAT_NEX_CHARGE = 49; // see DP source, quakedef.h const float STAT_MOVEVARS_AIRSPEEDLIMIT_NONQW = 222; @@ -398,7 +400,7 @@ float CHAN_AUTO = 0; // on world: announcers, ... INFO // on players: item pickup ITEMS // on entities: UNUSED - // on csqc: UNUSED + // on csqc: announcers INFO float CHAN_WEAPON = 1; // Weapon fire // on world: UNUSED // on players: weapon firing WEAPONS @@ -413,7 +415,7 @@ float CHAN_TRIGGER = 3; // Triggers/Items // on world: UNUSED // on players: item pickup ITEMS // on entities: platforms moving etc. ITEMS - // on csqc: UNUSED + // on csqc: platforms moving etc. ITEMS float CHAN_PROJECTILE = 4; // Projectiles // on world: UNUSED // on players: projectiles hitting player SHOTS @@ -454,20 +456,21 @@ float PROJECTILE_CRYLINK = 5; float PROJECTILE_ELECTRO_BEAM = 6; float PROJECTILE_GRENADE = 7; float PROJECTILE_GRENADE_BOUNCING = 8; -float PROJECTILE_LASER = 9; -float PROJECTILE_HLAC = 10; -float PROJECTILE_SEEKER = 11; -float PROJECTILE_FLAC = 12; -float PROJECTILE_PORTO_RED = 13; -float PROJECTILE_PORTO_BLUE = 14; -float PROJECTILE_HOOKBOMB = 15; -float PROJECTILE_HAGAR = 16; -float PROJECTILE_HAGAR_BOUNCING = 17; -float PROJECTILE_BULLET_GLOWING = 18; -float PROJECTILE_CRYLINK_BOUNCING = 19; -float PROJECTILE_FIREBALL = 20; -float PROJECTILE_FIREMINE = 21; -float PROJECTILE_BULLET_GLOWING_TRACER = 22; +float PROJECTILE_MINE = 9; +float PROJECTILE_LASER = 10; +float PROJECTILE_HLAC = 11; +float PROJECTILE_SEEKER = 12; +float PROJECTILE_FLAC = 13; +float PROJECTILE_PORTO_RED = 14; +float PROJECTILE_PORTO_BLUE = 15; +float PROJECTILE_HOOKBOMB = 16; +float PROJECTILE_HAGAR = 17; +float PROJECTILE_HAGAR_BOUNCING = 18; +float PROJECTILE_BULLET_GLOWING = 19; +float PROJECTILE_CRYLINK_BOUNCING = 20; +float PROJECTILE_FIREBALL = 21; +float PROJECTILE_FIREMINE = 22; +float PROJECTILE_BULLET_GLOWING_TRACER = 23; float SPECIES_HUMAN = 0; float SPECIES_ROBOT_SOLID = 1; diff --git a/qcsrc/common/mapinfo.qc b/qcsrc/common/mapinfo.qc index 1fd2cf809..835c58f64 100644 --- a/qcsrc/common/mapinfo.qc +++ b/qcsrc/common/mapinfo.qc @@ -699,7 +699,7 @@ float MapInfo_Get_ByName(string pFilename, float pAllowGenerate, float pGametype else fputs(fh, strcat("cdtrack ", _MapInfo_Map_worldspawn_music, "\n")); } - else if(_MapInfo_Map_worldspawn_music) + else { n = tokenize_console(cvar_string("g_cdtracks_remaplist")); s = strcat(" ", cvar_string("g_cdtracks_dontusebydefault"), " "); @@ -720,7 +720,7 @@ float MapInfo_Get_ByName(string pFilename, float pAllowGenerate, float pGametype for(i = 1; i <= MapInfo_Map_supportedGametypes; i *= 2) if(MapInfo_Map_supportedGametypes & i) - fputs(fh, sprintf("type %s %s\n", i, MapInfo_GetDefault(i))); + fputs(fh, sprintf("type %s %s\n", MapInfo_Type_ToString(i), MapInfo_GetDefault(i))); fh2 = fopen(strcat("scripts/", pFilename, ".arena"), FILE_READ); if(fh2 >= 0) diff --git a/qcsrc/common/util.qc b/qcsrc/common/util.qc index 72af70111..1efc0e373 100644 --- a/qcsrc/common/util.qc +++ b/qcsrc/common/util.qc @@ -1913,3 +1913,25 @@ float get_model_parameters(string m, float sk) return 1; } + +vector vec2(vector v) +{ + v_z = 0; + return v; +} + +#ifndef MENUQC +vector NearestPointOnBox(entity box, vector org) +{ + vector m1, m2, nearest; + + m1 = box.mins + box.origin; + m2 = box.maxs + box.origin; + + nearest_x = bound(m1_x, org_x, m2_x); + nearest_y = bound(m1_y, org_y, m2_y); + nearest_z = bound(m1_z, org_z, m2_z); + + return nearest; +} +#endif diff --git a/qcsrc/common/util.qh b/qcsrc/common/util.qh index f2c2e6702..77b3e0320 100644 --- a/qcsrc/common/util.qh +++ b/qcsrc/common/util.qh @@ -236,3 +236,9 @@ switch(id) { \ case HUD_PANEL_CHAT: panel_name = HUD_PANELNAME_CHAT; break; \ }\ HUD_Panel_GetName_Part2(id) + +vector vec2(vector v); + +#ifndef MENUQC +vector NearestPointOnBox(entity box, vector org); +#endif diff --git a/qcsrc/menu/classes.c b/qcsrc/menu/classes.c index c0568b1e5..9ebcbb8f5 100644 --- a/qcsrc/menu/classes.c +++ b/qcsrc/menu/classes.c @@ -101,3 +101,4 @@ #include "xonotic/dialog_hudpanel_engineinfo.c" #include "xonotic/dialog_hudpanel_infomessages.c" #include "xonotic/dialog_hudpanel_weapons.c" +#include "xonotic/slider_picmip.c" diff --git a/qcsrc/menu/draw.qc b/qcsrc/menu/draw.qc index cec73d6c0..a33cac916 100644 --- a/qcsrc/menu/draw.qc +++ b/qcsrc/menu/draw.qc @@ -69,6 +69,8 @@ void draw_PreloadPicture(string pic) void draw_Picture(vector theOrigin, string pic, vector theSize, vector theColor, float theAlpha) { + if(theSize_x == 0 || theSize_y <= 0) // no default sizing please + return; pic = draw_UseSkinFor(pic); drawpic(boxToGlobal(theOrigin, draw_shift, draw_scale), pic, boxToGlobalSize(theSize, draw_scale), theColor, theAlpha * draw_alpha, 0); } @@ -174,11 +176,40 @@ void draw_BorderPicture(vector theOrigin, string pic, vector theSize, vector the theAlpha *= draw_alpha; width = eX * theSize_x; height = eY * theSize_y; - if(theSize_x <= theBorderSize_x * 2) + // zero size? bail out, we cannot handle this + if(theSize_x <= 0 || theSize_y <= 0) + return; + if(theBorderSize_x <= 0) // no x border + { + if(theBorderSize_y <= 0) + { + drawsubpic(theOrigin, width + height, pic, '0.25 0.25 0', '0.5 0.5 0', theColor, theAlpha, 0); + } + else if(theSize_y <= theBorderSize_y * 2) + { + // not high enough... draw just top and bottom then + bH = eY * (0.25 * theSize_y / (theBorderSize_y * 2)); + drawsubpic(theOrigin, width + height * 0.5, pic, '0.25 0 0', '0.5 0 0' + bH, theColor, theAlpha, 0); + drawsubpic(theOrigin + height * 0.5, width + height * 0.5, pic, '0.25 0 0' + eY - bH, '0.5 0 0' + bH, theColor, theAlpha, 0); + } + else + { + dY = theBorderSize_y * eY; + drawsubpic(theOrigin, width + dY, pic, '0.25 0 0', '0.5 0.25 0', theColor, theAlpha, 0); + drawsubpic(theOrigin + dY, width + height - 2 * dY, pic, '0.25 0.25 0', '0.5 0.5 0', theColor, theAlpha, 0); + drawsubpic(theOrigin + height - dY, width + dY, pic, '0.25 0.75 0', '0.5 0.25 0', theColor, theAlpha, 0); + } + } + else if(theSize_x <= theBorderSize_x * 2) { // not wide enough... draw just left and right then bW = eX * (0.25 * theSize_x / (theBorderSize_x * 2)); - if(theSize_y <= theBorderSize_y * 2) + if(theBorderSize_y <= 0) + { + drawsubpic(theOrigin, width * 0.5 + height, pic, '0 0.25 0', '0 0.5 0' + bW, theColor, theAlpha, 0); + drawsubpic(theOrigin + width * 0.5, width * 0.5 + height, pic, '0 0.25 0' + eX - bW, '0 0.5 0' + bW, theColor, theAlpha, 0); + } + else if(theSize_y <= theBorderSize_y * 2) { // not high enough... draw just corners bH = eY * (0.25 * theSize_y / (theBorderSize_y * 2)); @@ -189,7 +220,7 @@ void draw_BorderPicture(vector theOrigin, string pic, vector theSize, vector the } else { - dY = theBorderSize_x * eY; + dY = theBorderSize_y * eY; drawsubpic(theOrigin, width * 0.5 + dY, pic, '0 0 0', '0 0.25 0' + bW, theColor, theAlpha, 0); drawsubpic(theOrigin + width * 0.5, width * 0.5 + dY, pic, '0 0 0' + eX - bW, '0 0.25 0' + bW, theColor, theAlpha, 0); drawsubpic(theOrigin + dY, width * 0.5 + height - 2 * dY, pic, '0 0.25 0', '0 0.5 0' + bW, theColor, theAlpha, 0); @@ -200,7 +231,14 @@ void draw_BorderPicture(vector theOrigin, string pic, vector theSize, vector the } else { - if(theSize_y <= theBorderSize_y * 2) + if(theBorderSize_y <= 0) + { + dX = theBorderSize_x * eX; + drawsubpic(theOrigin, dX + height, pic, '0 0.25 0', '0.25 0.5 0', theColor, theAlpha, 0); + drawsubpic(theOrigin + dX, width - 2 * dX + height, pic, '0.25 0.25 0', '0.5 0.5 0', theColor, theAlpha, 0); + drawsubpic(theOrigin + width - dX, dX + height, pic, '0.75 0.25 0', '0.25 0.5 0', theColor, theAlpha, 0); + } + else if(theSize_y <= theBorderSize_y * 2) { // not high enough... draw just top and bottom then bH = eY * (0.25 * theSize_y / (theBorderSize_y * 2)); @@ -215,7 +253,7 @@ void draw_BorderPicture(vector theOrigin, string pic, vector theSize, vector the else { dX = theBorderSize_x * eX; - dY = theBorderSize_x * eY; + dY = theBorderSize_y * eY; drawsubpic(theOrigin, dX + dY, pic, '0 0 0', '0.25 0.25 0', theColor, theAlpha, 0); drawsubpic(theOrigin + dX, width - 2 * dX + dY, pic, '0.25 0 0', '0.5 0.25 0', theColor, theAlpha, 0); drawsubpic(theOrigin + width - dX, dX + dY, pic, '0.75 0 0', '0.25 0.25 0', theColor, theAlpha, 0); diff --git a/qcsrc/menu/item/slider.c b/qcsrc/menu/item/slider.c index 1f01cb4e2..c8bab9bf8 100644 --- a/qcsrc/menu/item/slider.c +++ b/qcsrc/menu/item/slider.c @@ -104,7 +104,7 @@ float Slider_keyDown(entity me, float key, float ascii, float shift) if(me.disabled) return 0; inRange = (almost_in_bounds(me.valueMin, me.value, me.valueMax)); - if(key == K_LEFTARROW || key == K_KP_LEFTARROW) + if(key == K_LEFTARROW || key == K_KP_LEFTARROW || key == K_MWHEELUP) { if(inRange) me.setValue(me, median(me.valueMin, me.value - me.valueKeyStep, me.valueMax)); @@ -112,7 +112,7 @@ float Slider_keyDown(entity me, float key, float ascii, float shift) me.setValue(me, me.valueMax); return 1; } - if(key == K_RIGHTARROW || key == K_KP_RIGHTARROW) + if(key == K_RIGHTARROW || key == K_KP_RIGHTARROW || key == K_MWHEELDOWN) { if(inRange) me.setValue(me, median(me.valueMin, me.value + me.valueKeyStep, me.valueMax)); diff --git a/qcsrc/menu/mbuiltin.qh b/qcsrc/menu/mbuiltin.qh index 6d9d3345c..e325915c9 100644 --- a/qcsrc/menu/mbuiltin.qh +++ b/qcsrc/menu/mbuiltin.qh @@ -350,3 +350,12 @@ string(float, float) getgamedirinfo = #626; float log(float f) = #532; string(string format, ...) sprintf = #627; + +//DP_CRYPTO +//idea: divVerent +//darkplaces implementation: divVerent +//field definitions: (MENUQC) +string crypto_getkeyfp(string serveraddress) = #633; // retrieves the cached host key's CA fingerprint of a server given by IP address +string crypto_getidfp(string serveraddress) = #634; // retrieves the cached host key fingerprint of a server given by IP address +string crypto_getencryptlevel(string serveraddress) = #635; // 0 if never encrypting, 1 supported, 2 requested, 3 required, appended by list of allowed methods in order of preference ("AES128"), preceded by a space each +//description: diff --git a/qcsrc/menu/skin-customizables.inc b/qcsrc/menu/skin-customizables.inc index c3320e503..b93ecaa7c 100644 --- a/qcsrc/menu/skin-customizables.inc +++ b/qcsrc/menu/skin-customizables.inc @@ -220,6 +220,8 @@ SKINBEGIN SKINFLOAT(ALPHA_SERVERLIST_HIGHPING, 0.4); SKINFLOAT(ALPHA_SERVERLIST_FAVORITE, 0.8); SKINVECTOR(COLOR_SERVERLIST_FAVORITE, '1 1 1'); + SKINFLOAT(ALPHA_SERVERLIST_IMPOSSIBLE, 0.7); + SKINVECTOR(COLOR_SERVERLIST_IMPOSSIBLE, '0.3 0.3 0.3'); // item: server info SKINVECTOR(COLOR_SERVERINFO_NAME, '1 1 1'); diff --git a/qcsrc/menu/xonotic/crosshairbutton.c b/qcsrc/menu/xonotic/crosshairbutton.c index b290f3d21..058bfd7eb 100644 --- a/qcsrc/menu/xonotic/crosshairbutton.c +++ b/qcsrc/menu/xonotic/crosshairbutton.c @@ -8,6 +8,7 @@ CLASS(XonoticCrosshairButton) EXTENDS(RadioButton) ATTRIB(XonoticCrosshairButton, useDownAsChecked, float, 1) ATTRIB(XonoticCrosshairButton, src3, string, string_null) + ATTRIB(XonoticCrosshairButton, src4, string, string_null) ATTRIB(XonoticCrosshairButton, cvarName, string, string_null) ATTRIB(XonoticCrosshairButton, cvarValueFloat, float, 0) @@ -33,6 +34,7 @@ void XonoticCrosshairButton_configureXonoticCrosshairButton(entity me, float the me.configureRadioButton(me, string_null, me.fontSize, me.image, theGroup, 0); me.srcMulti = 1; me.src3 = strzone(strcat("/gfx/crosshair", ftos(me.cvarValueFloat))); + me.src4 = "/gfx/crosshairdot"; } void XonoticCrosshairButton_setChecked(entity me, float val) { @@ -76,12 +78,14 @@ void XonoticCrosshairButton_draw(entity me) sz = draw_PictureSize(me.src3); sz = globalToBoxSize(sz, draw_scale); - sz = sz * cvar("crosshair_size"); + sz = (10 * '1 1 0' + sz * cvar("crosshair_size")) * 0.05; // (10 * '1 1 0' + ...) * 0.05 here to make visible size changes happen also at bigger sizes if(sz_x > 0.95) sz = sz * (0.95 / sz_x); if(sz_y > 0.95) sz = sz * (0.95 / sz_y); draw_Picture('0.5 0.5 0' - 0.5 * sz, me.src3, sz, rgb, a); + if(cvar("crosshair_dot")) + draw_Picture('0.5 0.5 0' - 0.5 * sz * cvar("crosshair_dot_size"), me.src4, sz * cvar("crosshair_dot_size"), rgb, a * cvar("crosshair_dot_alpha")); } #endif diff --git a/qcsrc/menu/xonotic/dialog_hudpanel_weapons.c b/qcsrc/menu/xonotic/dialog_hudpanel_weapons.c index a32099d9d..538723bce 100644 --- a/qcsrc/menu/xonotic/dialog_hudpanel_weapons.c +++ b/qcsrc/menu/xonotic/dialog_hudpanel_weapons.c @@ -4,7 +4,7 @@ CLASS(XonoticHUDWeaponsDialog) EXTENDS(XonoticRootDialog) ATTRIB(XonoticHUDWeaponsDialog, title, string, "Weapons Panel") ATTRIB(XonoticHUDWeaponsDialog, color, vector, SKINCOLOR_DIALOG_TEAMSELECT) ATTRIB(XonoticHUDWeaponsDialog, intendedWidth, float, 0.4) - ATTRIB(XonoticHUDWeaponsDialog, rows, float, 15) + ATTRIB(XonoticHUDWeaponsDialog, rows, float, 17) ATTRIB(XonoticHUDWeaponsDialog, columns, float, 4) ATTRIB(XonoticHUDWeaponsDialog, name, string, "HUDweapons") ENDCLASS(XonoticHUDWeaponsDialog) @@ -71,6 +71,23 @@ void XonoticHUDWeaponsDialog_fill(entity me) for(i = 0; i <= 10; ++i) e.addValue(e, strzone(ftos_decimals(i - 5, 0)), strzone(ftos(i - 5))); e.configureXonoticTextSliderValues(e); + me.TR(me); + me.TDempty(me, 0.2); + me.TD(me, 1, 1.2, e = makeXonoticTextLabel(0, "Fade out after:")); + me.TD(me, 1, 2.6, e = makeXonoticTextSlider(strzone(strcat("hud_panel_", panelname, "_timeout")))); + e.addValue(e, "Never", "0"); + for(i = 1; i <= 10; ++i) + e.addValue(e, strzone(strcat(ftos_decimals(i, 0), "s")), strzone(ftos(i))); + e.configureXonoticTextSliderValues(e); + me.TR(me); + me.TDempty(me, 0.2); + me.TD(me, 1, 1.4, e = makeXonoticTextLabel(0, "Fade effect:")); + me.TD(me, 1, 0.8, e = makeXonoticRadioButton(3, "hud_panel_weapons_timeout_effect", "0", "None")); + setDependentStringNotEqual(e, strzone(strcat("hud_panel_", panelname, "_timeout")), "0"); + me.TD(me, 1, 0.8, e = makeXonoticRadioButton(3, "hud_panel_weapons_timeout_effect", "1", "Slide")); + setDependentStringNotEqual(e, strzone(strcat("hud_panel_", panelname, "_timeout")), "0"); + me.TD(me, 1, 0.8, e = makeXonoticRadioButton(3, "hud_panel_weapons_timeout_effect", "2", "Alpha")); + setDependentStringNotEqual(e, strzone(strcat("hud_panel_", panelname, "_timeout")), "0"); me.TR(me); me.TD(me, 1, 2, e = makeXonoticTextLabel(0, "Weapon icons:")); me.TR(me); diff --git a/qcsrc/menu/xonotic/dialog_hudsetup_exit.c b/qcsrc/menu/xonotic/dialog_hudsetup_exit.c index d3a21c6bf..3f8bcebd7 100644 --- a/qcsrc/menu/xonotic/dialog_hudsetup_exit.c +++ b/qcsrc/menu/xonotic/dialog_hudsetup_exit.c @@ -69,7 +69,7 @@ void XonoticHUDExitDialog_fill(entity me) me.TD(me, 1, 2.6, e = makeXonoticTextSlider("hud_dock")); e.addValue(e, "Disable", "0"); e.addValue(e, "Small", "dock_small"); - e.addValue(e, "Medium", "dock"); + e.addValue(e, "Medium", "dock_medium"); e.addValue(e, "Large", "dock_large"); e.configureXonoticTextSliderValues(e); me.TR(me); diff --git a/qcsrc/menu/xonotic/dialog_multiplayer_create_mapinfo.c b/qcsrc/menu/xonotic/dialog_multiplayer_create_mapinfo.c index 05ed89887..bd54aa219 100644 --- a/qcsrc/menu/xonotic/dialog_multiplayer_create_mapinfo.c +++ b/qcsrc/menu/xonotic/dialog_multiplayer_create_mapinfo.c @@ -163,6 +163,5 @@ void XonoticMapInfoDialog_fill(entity me) me.TD(me, 1, me.columns - 5.5, me.startButton = e = makeXonoticButton("Play", '0 0 0')); me.startButton.onClick = MapList_LoadMap; me.startButton.onClickEntity = NULL; // filled later - me.TDempty(me, 0.5); } #endif diff --git a/qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.c b/qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.c index 517f68bd3..c0d16a959 100644 --- a/qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.c +++ b/qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.c @@ -268,7 +268,7 @@ void XonoticMutatorsDialog_fill(entity me) me.TDempty(me, 0.2); me.TD(me, 1, 2, e = makeXonoticRadioButton(1, "g_start_weapon_laser", "0", "No start weapons")); e.cvarOffValue = "-1"; - makeMulti(e, "g_start_weapon_shotgun g_start_weapon_uzi g_start_weapon_grenadelauncher g_start_weapon_electro g_start_weapon_crylink g_start_weapon_nex g_start_weapon_hagar g_start_weapon_rocketlauncher g_start_weapon_campingrifle g_start_weapon_hlac g_start_weapon_seeker g_start_weapon_minstanex g_start_weapon_hook g_start_weapon_porto g_start_weapon_tuba"); + makeMulti(e, "g_start_weapon_shotgun g_start_weapon_uzi g_start_weapon_grenadelauncher g_start_weapon_minelayer g_start_weapon_electro g_start_weapon_crylink g_start_weapon_nex g_start_weapon_hagar g_start_weapon_rocketlauncher g_start_weapon_campingrifle g_start_weapon_hlac g_start_weapon_seeker g_start_weapon_minstanex g_start_weapon_hook g_start_weapon_porto g_start_weapon_tuba"); me.gotoRC(me, me.rows - 1, 0); me.TD(me, 1, me.columns, e = makeXonoticButton("OK", '0 0 0')); diff --git a/qcsrc/menu/xonotic/dialog_multiplayer_join_serverinfo.c b/qcsrc/menu/xonotic/dialog_multiplayer_join_serverinfo.c index 7770230d3..21eefeae6 100644 --- a/qcsrc/menu/xonotic/dialog_multiplayer_join_serverinfo.c +++ b/qcsrc/menu/xonotic/dialog_multiplayer_join_serverinfo.c @@ -5,7 +5,7 @@ CLASS(XonoticServerInfoDialog) EXTENDS(XonoticDialog) ATTRIB(XonoticServerInfoDialog, title, string, "Server Information") ATTRIB(XonoticServerInfoDialog, color, vector, SKINCOLOR_DIALOG_SERVERINFO) ATTRIB(XonoticServerInfoDialog, intendedWidth, float, 0.68) - ATTRIB(XonoticServerInfoDialog, rows, float, 11) + ATTRIB(XonoticServerInfoDialog, rows, float, 14) ATTRIB(XonoticServerInfoDialog, columns, float, 12) ATTRIB(XonoticServerInfoDialog, currentServerName, string, string_null) @@ -18,6 +18,10 @@ CLASS(XonoticServerInfoDialog) EXTENDS(XonoticDialog) ATTRIB(XonoticServerInfoDialog, currentServerMod, string, string_null) ATTRIB(XonoticServerInfoDialog, currentServerVersion, string, string_null) ATTRIB(XonoticServerInfoDialog, currentServerPing, string, string_null) + ATTRIB(XonoticServerInfoDialog, currentServerKey, string, string_null) + ATTRIB(XonoticServerInfoDialog, currentServerID, string, string_null) + ATTRIB(XonoticServerInfoDialog, currentServerEncrypt, string, string_null) + ATTRIB(XonoticServerInfoDialog, currentServerCanConnect, string, string_null) ATTRIB(XonoticServerInfoDialog, nameLabel, entity, NULL) ATTRIB(XonoticServerInfoDialog, cnameLabel, entity, NULL) @@ -29,6 +33,10 @@ CLASS(XonoticServerInfoDialog) EXTENDS(XonoticDialog) ATTRIB(XonoticServerInfoDialog, modLabel, entity, NULL) ATTRIB(XonoticServerInfoDialog, versionLabel, entity, NULL) ATTRIB(XonoticServerInfoDialog, pingLabel, entity, NULL) + ATTRIB(XonoticServerInfoDialog, keyLabel, entity, NULL) + ATTRIB(XonoticServerInfoDialog, idLabel, entity, NULL) + ATTRIB(XonoticServerInfoDialog, encryptLabel, entity, NULL) + ATTRIB(XonoticServerInfoDialog, canConnectLabel, entity, NULL) ENDCLASS(XonoticServerInfoDialog) float SLIST_FIELD_NAME; @@ -74,7 +82,6 @@ void XonoticServerInfoDialog_loadServerInfo(entity me, float i) me.currentServerType = strzone(typestr); me.typeLabel.setText(me.typeLabel, me.currentServerType); - SLIST_FIELD_MAP = gethostcacheindexforkey("map"); me.currentServerMap = strzone(gethostcachestring(SLIST_FIELD_MAP, i)); me.mapLabel.setText(me.mapLabel, me.currentServerMap); @@ -106,6 +113,51 @@ void XonoticServerInfoDialog_loadServerInfo(entity me, float i) s = ftos(gethostcachenumber(SLIST_FIELD_PING, i)); me.currentServerPing = strzone(s); me.pingLabel.setText(me.pingLabel, me.currentServerPing); + + print(me.currentServerCName, "\n"); + + s = crypto_getidfp(me.currentServerCName); + if not(s) + s = "N/A"; + me.currentServerID = strzone(s); + me.idLabel.setText(me.idLabel, me.currentServerID); + + s = crypto_getkeyfp(me.currentServerCName); + if not(s) + s = "N/A"; + me.currentServerKey = strzone(s); + me.keyLabel.setText(me.keyLabel, me.currentServerKey); + + s = crypto_getencryptlevel(me.currentServerCName); + if(s == "") + { + if(cvar("crypto_aeslevel") >= 3) + me.currentServerEncrypt = "N/A (can't connect)"; + else + me.currentServerEncrypt = "N/A"; + } + else switch(stof(substring(s, 0, 1))) + { + case 0: + if(cvar("crypto_aeslevel") >= 3) + me.currentServerEncrypt = "not supported (can't connect)"; + else + me.currentServerEncrypt = "not supported"; + break; + case 1: + me.currentServerEncrypt = "supported"; + break; + case 2: + me.currentServerEncrypt = "requested"; + break; + case 3: + if(cvar("crypto_aeslevel") <= 0) + me.currentServerEncrypt = "required (can't connect)"; + else + me.currentServerEncrypt = "required"; + break; + } + me.encryptLabel.setText(me.encryptLabel, me.currentServerEncrypt); } void XonoticServerInfoDialog_fill(entity me) @@ -166,6 +218,24 @@ void XonoticServerInfoDialog_fill(entity me) e.allowCut = 1; me.pingLabel = e; + me.TR(me); + me.TD(me, 1, 1.75, e = makeXonoticTextLabel(0, "CA:")); + me.TD(me, 1, 4.0, e = makeXonoticTextLabel(0, "")); + e.allowCut = 1; + me.keyLabel = e; + + me.TR(me); + me.TD(me, 1, 1.75, e = makeXonoticTextLabel(0, "Key:")); + me.TD(me, 1, 4.0, e = makeXonoticTextLabel(0, "")); + e.allowCut = 1; + me.idLabel = e; + + me.TR(me); + me.TD(me, 1, 1.75, e = makeXonoticTextLabel(0, "Encryption:")); + me.TD(me, 1, 4.0, e = makeXonoticTextLabel(0, "")); + e.allowCut = 1; + me.encryptLabel = e; + me.gotoRC(me, me.rows - 1, 0); me.TD(me, 1, me.columns - 6, e = makeXonoticButton("Close", '0 0 0')); diff --git a/qcsrc/menu/xonotic/dialog_multiplayer_playersetup.c b/qcsrc/menu/xonotic/dialog_multiplayer_playersetup.c index 8c75c1f46..751c55591 100644 --- a/qcsrc/menu/xonotic/dialog_multiplayer_playersetup.c +++ b/qcsrc/menu/xonotic/dialog_multiplayer_playersetup.c @@ -84,7 +84,7 @@ void XonoticPlayerSettingsTab_fill(entity me) } me.gotoRC(me, 0, 3.5); me.setFirstColumn(me, me.currentColumn); - me.TD(me, 1, 1, e = makeXonoticTextLabel(0, "Field of View:")); + me.TD(me, 1, 1, e = makeXonoticTextLabel(0, "Field of view:")); me.TD(me, 1, 2, e = makeXonoticSlider(60, 130, 1, "fov")); me.TR(me); me.TD(me, 1, 1, e = makeXonoticTextLabel(0, "Damage kick:")); @@ -92,11 +92,9 @@ void XonoticPlayerSettingsTab_fill(entity me) me.TR(me); sl = makeXonoticSlider(0.45, 0.75, 0.01, "cl_bobcycle"); me.TD(me, 1, 1, e = makeXonoticSliderCheckBox(0, 1, sl, "View bobbing:")); - me.TD(me, 1, 2, sl); - - me.TR(me); + me.TD(me, 1, 2, sl); me.TR(me); - me.TD(me, 1, 1, e = makeXonoticTextLabel(0, "Zoom Factor:")); + me.TD(me, 1, 1, e = makeXonoticTextLabel(0, "Zoom factor:")); me.TD(me, 1, 2, e = makeXonoticSlider(2, 16, 0.5, "cl_zoomfactor")); me.TR(me); sl = makeXonoticSlider(1, 8, 0.5, "cl_zoomspeed"); @@ -110,40 +108,55 @@ void XonoticPlayerSettingsTab_fill(entity me) e0.textEntity = main.weaponsDialog; e0.allowCut = 1; me.TR(me); - me.TR(me); - me.TD(me, 1, 2, e = makeXonoticCheckBox(0, "crosshair_per_weapon", "Per weapon crosshairs")); - me.TD(me, 1, 1.3, e = makeXonoticCheckBox(1, "crosshair_color_override", "& crosshair colors")); + me.TD(me, 1, 0.75, e = makeXonoticTextLabel(0, "Crosshair:")); + me.TD(me, 1, 1.00, e = makeXonoticCheckBox(0, "crosshair_per_weapon", "Per weapon")); + me.TD(me, 1, 1.25, e = makeXonoticCheckBox(1, "crosshair_color_override", "& Per weapon colors")); setDependent(e, "crosshair_per_weapon", 1, 1); me.TR(me); - me.TD(me, 1, 1, e = makeXonoticTextLabel(0, "Crosshair:")); + me.TDempty(me, 0.5); for(i = 1; i <= 10; ++i) { me.TDNoMargin(me, 1, 2 / 10, e = makeXonoticCrosshairButton(3, i), '1 1 0'); setDependent(e, "crosshair_per_weapon", 0, 0); } me.TR(me); - me.TDempty(me, 1); + me.TDempty(me, 0.5); for(i = 11; i <= 20; ++i) { me.TDNoMargin(me, 1, 2 / 10, e = makeXonoticCrosshairButton(3, i), '1 1 0'); setDependent(e, "crosshair_per_weapon", 0, 0); } me.TR(me); - me.TD(me, 1, 1, e = makeXonoticTextLabel(0, "Crosshair Size:")); - me.TD(me, 1, 2, e = makeXonoticSlider(0.40, 2, 0.05, "crosshair_size")); + me.TDempty(me, 0.2); + me.TD(me, 1, 1, e = makeXonoticTextLabel(0, "Crosshair size:")); + me.TD(me, 1, 1.8, e = makeXonoticSlider(0.10, 1.5, 0.05, "crosshair_size")); me.TR(me); - me.TD(me, 1, 1, e = makeXonoticTextLabel(0, "Crosshair Alpha:")); - me.TD(me, 1, 2, e = makeXonoticSlider(0, 1, 0.01, "crosshair_color_alpha")); + me.TDempty(me, 0.2); + me.TD(me, 1, 1, e = makeXonoticTextLabel(0, "Crosshair alpha:")); + me.TD(me, 1, 1.8, e = makeXonoticSlider(0, 1, 0.1, "crosshair_color_alpha")); me.TR(me); - me.TD(me, 1, 1, e = makeXonoticTextLabel(0, "Crosshair Red:")); - me.TD(me, 1, 2, e = makeXonoticSlider(0, 1, 0.01, "crosshair_color_red")); + me.TDempty(me, 0.2); + me.TD(me, 1, 1, e = makeXonoticTextLabel(0, "Crosshair red:")); + me.TD(me, 1, 1.8, e = makeXonoticSlider(0, 1, 0.01, "crosshair_color_red")); setDependentOR(e, "crosshair_per_weapon", 0, 0, "crosshair_color_override", 1, 1); me.TR(me); - me.TD(me, 1, 1, e = makeXonoticTextLabel(0, "Crosshair Green:")); - me.TD(me, 1, 2, e = makeXonoticSlider(0, 1, 0.01, "crosshair_color_green")); + me.TDempty(me, 0.2); + me.TD(me, 1, 1, e = makeXonoticTextLabel(0, "Crosshair green:")); + me.TD(me, 1, 1.8, e = makeXonoticSlider(0, 1, 0.01, "crosshair_color_green")); setDependentOR(e, "crosshair_per_weapon", 0, 0, "crosshair_color_override", 1, 1); me.TR(me); - me.TD(me, 1, 1, e = makeXonoticTextLabel(0, "Crosshair Blue:")); - me.TD(me, 1, 2, e = makeXonoticSlider(0, 1, 0.01, "crosshair_color_blue")); + me.TDempty(me, 0.2); + me.TD(me, 1, 1, e = makeXonoticTextLabel(0, "Crosshair blue:")); + me.TD(me, 1, 1.8, e = makeXonoticSlider(0, 1, 0.01, "crosshair_color_blue")); setDependentOR(e, "crosshair_per_weapon", 0, 0, "crosshair_color_override", 1, 1); + me.TR(me); + me.TD(me, 1, 3, e = makeXonoticCheckBox(0, "crosshair_dot", "Enable centered dot")); + me.TR(me); + me.TDempty(me, 0.2); + me.TD(me, 1, 0.5, e = makeXonoticTextLabel(0, "Size:")); + me.TD(me, 1, 0.9, e = makeXonoticSlider(0.2, 2, 0.1, "crosshair_dot_size")); + setDependent(e, "crosshair_dot", 1, 1); + me.TD(me, 1, 0.5, e = makeXonoticTextLabel(0, "Alpha:")); + me.TD(me, 1, 0.9, e = makeXonoticSlider(0.10, 1, 0.1, "crosshair_dot_alpha")); + setDependent(e, "crosshair_dot", 1, 1); me.TR(me); me.TD(me, 1, 1, e = makeXonoticTextLabel(0, "Hit test:")); me.TD(me, 1, 2/3, e = makeXonoticRadioButton(1, "crosshair_hittest", "0", "None")); @@ -151,19 +164,19 @@ void XonoticPlayerSettingsTab_fill(entity me) me.TD(me, 1, 2/3, e = makeXonoticRadioButton(1, "crosshair_hittest", "1.25", "Enemies")); me.TR(me); me.TDempty(me, 0.4); - me.TD(me, 1, 2.2, e = makeXonoticButton("Waypoints Setup", '0 0 0')); + me.TD(me, 1, 2.2, e = makeXonoticButton("Waypoints setup...", '0 0 0')); e.onClick = DialogOpenButton_Click; e.onClickEntity = main.waypointDialog; me.TDempty(me, 0.5); me.TR(me); me.TDempty(me, 0.4); - me.TD(me, 1, 2.2, e = makeXonoticButton("HUD Setup", '0 0 0')); + me.TD(me, 1, 2.2, e = makeXonoticButton("Enter HUD editor", '0 0 0')); e.onClick = HUDSetup_Join_Click; e.onClickEntity = me; me.TDempty(me, 0.5); me.TR(me); #ifdef ALLOW_FORCEMODELS - me.TD(me, 1, 1, e = makeXonoticTextLabel(0, "Force Models:")); + me.TD(me, 1, 1, e = makeXonoticTextLabel(0, "Force models:")); me.TD(me, 1, 2/3, e = makeXonoticRadioButton(2, string_null, string_null, "None")); me.TD(me, 1, 2/3, e = makeXonoticRadioButton(2, "cl_forceplayermodelsfromxonotic", string_null, "Custom")); me.TD(me, 1, 2/3, e = makeXonoticRadioButton(2, "cl_forceplayermodels", string_null, "All")); @@ -178,7 +191,6 @@ void XonoticPlayerSettingsTab_fill(entity me) e.addValue(e, "Lots", "0"); e.configureXonoticTextSliderValues(e); setDependent(e, "cl_gentle", 0, 0); - me.TR(me); me.gotoRC(me, me.rows - 1, 0); me.TD(me, 1, me.columns, makeXonoticCommandButton("Apply immediately", '0 0 0', "color -1 -1;name \"$_cl_name\";cl_cmd sendcvar cl_weaponpriority;sendcvar cl_zoomfactor;sendcvar cl_zoomspeed;sendcvar cl_autoswitch;sendcvar cl_shownames;sendcvar cl_forceplayermodelsfromxonotic;sendcvar cl_forceplayermodels;playermodel $_cl_playermodel;playerskin $_cl_playerskin", COMMANDBUTTON_APPLY)); diff --git a/qcsrc/menu/xonotic/dialog_settings_audio.c b/qcsrc/menu/xonotic/dialog_settings_audio.c index 7d1f17f0f..ddde45d2b 100644 --- a/qcsrc/menu/xonotic/dialog_settings_audio.c +++ b/qcsrc/menu/xonotic/dialog_settings_audio.c @@ -51,7 +51,7 @@ void XonoticAudioSettingsTab_fill(entity me) me.TR(me); me.TDempty(me, 0.2); s = makeXonoticDecibelsSlider(-20, 0, 0.5, "snd_entchannel3volume"); - makeMulti(s, "snd_playerchannel0volume snd_playerchannel3volume"); + makeMulti(s, "snd_playerchannel0volume snd_playerchannel3volume snd_csqcchannel3volume"); me.TD(me, 1, 0.8, e = makeXonoticSliderCheckBox(-1000000, 1, s, "Items:")); me.TD(me, 1, 2, s); setDependentStringNotEqual(e, "volume", "0"); @@ -155,7 +155,8 @@ void XonoticAudioSettingsTab_fill(entity me) if(sl.value != e.savedValue) e.savedValue = 0.65; // default me.TR(me); - me.TD(me, 1, 3, e = makeXonoticTextLabel(0.1, "Frequency:")); + me.TDempty(me, 0.2); + me.TD(me, 1, 0.8, e = makeXonoticTextLabel(0, "Frequency:")); me.TD(me, 1, 2, sl); me.TR(me); me.TR(me); diff --git a/qcsrc/menu/xonotic/dialog_settings_effects.c b/qcsrc/menu/xonotic/dialog_settings_effects.c index 6cb071536..d5fbd82fd 100644 --- a/qcsrc/menu/xonotic/dialog_settings_effects.c +++ b/qcsrc/menu/xonotic/dialog_settings_effects.c @@ -36,9 +36,9 @@ float updateCompression() float have_dds, have_jpg, have_tga; if((have_dds = (fh = fopen("dds/particles/particlefont.dds", FILE_READ) >= 0))) fclose(fh); - if((have_jpg = (fh = fopen("jpg/particles/particlefont.jpg", FILE_READ) >= 0))) + if((have_jpg = (fh = fopen("particles/particlefont.jpg", FILE_READ) >= 0))) fclose(fh); - if((have_tga = (fh = fopen("tga/particles/particlefont.tga", FILE_READ) >= 0))) + if((have_tga = (fh = fopen("particles/particlefont.tga", FILE_READ) >= 0))) fclose(fh); if(have_dds && (have_jpg || have_tga)) { @@ -96,7 +96,7 @@ void XonoticEffectsSettingsTab_fill(entity me) me.TR(me); me.TR(me); me.TD(me, 1, 1, e = makeXonoticTextLabel(0, "Texture resolution:")); - me.TD(me, 1, 2, e = makeXonoticTextSlider("gl_picmip")); + me.TD(me, 1, 2, e = makeXonoticPicmipSlider()); if(cvar("developer")) e.addValue(e, "Leet", "1337"); e.addValue(e, "Lowest", "2"); diff --git a/qcsrc/menu/xonotic/dialog_settings_misc.c b/qcsrc/menu/xonotic/dialog_settings_misc.c index 2dcf83f1f..89c8471ca 100644 --- a/qcsrc/menu/xonotic/dialog_settings_misc.c +++ b/qcsrc/menu/xonotic/dialog_settings_misc.c @@ -66,13 +66,12 @@ void XonoticMiscSettingsTab_fill(entity me) me.TR(me); me.TR(me); me.TDempty(me, 0.2); - me.TD(me, 1, 2.8, e = makeXonoticCheckBox(0, "host_sleep", "Minimize input latency")); + me.TD(me, 1, 2.8, e = makeXonoticCheckBox(0, "cl_maxfps_alwayssleep", "Minimize input latency")); me.TR(me); me.TR(me); me.TDempty(me, 0.5); me.TD(me, 1, 2, e = makeXonoticButton("Advanced settings...", '0 0 0')); e.onClick = DialogOpenButton_Click; e.onClickEntity = main.cvarsDialog; - me.TDempty(me, 0.5); } #endif diff --git a/qcsrc/menu/xonotic/serverlist.c b/qcsrc/menu/xonotic/serverlist.c index d721c2555..95e1f80b8 100644 --- a/qcsrc/menu/xonotic/serverlist.c +++ b/qcsrc/menu/xonotic/serverlist.c @@ -95,41 +95,76 @@ void ServerList_UpdateFieldIDs() float IsFavorite(string srv) { + string p; float i, n; + if(srv == "") + return FALSE; srv = netaddress_resolve(srv, 26000); + p = crypto_getidfp(srv); n = tokenize_console(cvar_string("net_slist_favorites")); for(i = 0; i < n; ++i) - if(srv == netaddress_resolve(argv(i), 26000)) - return TRUE; + { + if(substring(argv(i), 0, 1) != "[" && strlen(argv(i)) == 44 && strstrofs(argv(i), ".", 0) < 0) + { + if(p) + if(argv(i) == p) + return TRUE; + } + else + { + if(srv == netaddress_resolve(argv(i), 26000)) + return TRUE; + } + } return FALSE; } void ToggleFavorite(string srv) { - string s, s0, s1, s2, srv_resolved; - float i, n; + string s, s0, s1, s2, srv_resolved, p; + float i, n, f; srv_resolved = netaddress_resolve(srv, 26000); + p = crypto_getidfp(srv_resolved); s = cvar_string("net_slist_favorites"); n = tokenize_console(s); + f = 0; for(i = 0; i < n; ++i) - if(srv_resolved == netaddress_resolve(argv(i), 26000)) + { + if(substring(argv(i), 0, 1) != "[" && strlen(argv(i)) == 44 && strstrofs(argv(i), ".", 0) < 0) { - s0 = s1 = s2 = ""; - if(i > 0) - s0 = substring(s, 0, argv_end_index(i - 1)); - if(i < n-1) - s2 = substring(s, argv_start_index(i + 1), -1); - if(s0 != "" && s2 != "") - s1 = " "; - print("s0 = >>", s0, "<<\ns1 = >>", s1, "<<\ns2 = >>", s2, "<<\n"); - cvar_set("net_slist_favorites", strcat(s0, s1, s2)); - return; + if(p) + if(argv(i) != p) + continue; } + else + { + if(srv_resolved != netaddress_resolve(argv(i), 26000)) + continue; + } + s0 = s1 = s2 = ""; + if(i > 0) + s0 = substring(s, 0, argv_end_index(i - 1)); + if(i < n-1) + s2 = substring(s, argv_start_index(i + 1), -1); + if(s0 != "" && s2 != "") + s1 = " "; + cvar_set("net_slist_favorites", strcat(s0, s1, s2)); + s = cvar_string("net_slist_favorites"); + n = tokenize_console(s); + f = 1; + --i; + } - s1 = ""; - if(s != "") - s1 = " "; - cvar_set("net_slist_favorites", strcat(s, " ", srv)); + if(!f) + { + s1 = ""; + if(s != "") + s1 = " "; + if(p) + cvar_set("net_slist_favorites", strcat(s, s1, p)); + else + cvar_set("net_slist_favorites", strcat(s, s1, srv)); + } resorthostcache(); } @@ -517,7 +552,7 @@ void XonoticServerList_drawListBoxItem(entity me, float i, vector absSize, float { // layout: Ping, Server name, Map name, NP, TP, MP string s; - float p; + float p, q; vector theColor; float theAlpha; @@ -556,6 +591,15 @@ void XonoticServerList_drawListBoxItem(entity me, float i, vector absSize, float theAlpha = theAlpha * (1 - SKINALPHA_SERVERLIST_FAVORITE) + SKINALPHA_SERVERLIST_FAVORITE; } + s = gethostcachestring(SLIST_FIELD_CNAME, i); + q = stof(substring(crypto_getencryptlevel(s), 0, 1)); + if((q <= 0 && cvar("crypto_aeslevel") >= 3) || (q >= 3 && cvar("crypto_aeslevel") <= 0)) + { + theColor = SKINCOLOR_SERVERLIST_IMPOSSIBLE; + theAlpha = SKINALPHA_SERVERLIST_IMPOSSIBLE; + } + // TODO show an icon for encryption status + s = ftos(p); draw_Text(me.realUpperMargin * eY + (me.columnPingSize - draw_TextWidth(s, 0, me.realFontSize)) * eX, s, me.realFontSize, theColor, theAlpha, 0); s = draw_TextShortenToWidth(gethostcachestring(SLIST_FIELD_NAME, i), me.columnNameSize, 0, me.realFontSize); diff --git a/qcsrc/menu/xonotic/slider_picmip.c b/qcsrc/menu/xonotic/slider_picmip.c new file mode 100644 index 000000000..e906242fe --- /dev/null +++ b/qcsrc/menu/xonotic/slider_picmip.c @@ -0,0 +1,49 @@ +#ifdef INTERFACE +CLASS(XonoticPicmipSlider) EXTENDS(XonoticTextSlider) + METHOD(XonoticPicmipSlider, configureXonoticPicmipSlider, void(entity)) + METHOD(XonoticPicmipSlider, draw, void(entity)) + METHOD(XonoticPicmipSlider, autofix, void(entity)) +ENDCLASS(XonoticPicmipSlider) +entity makeXonoticPicmipSlider(); // note: you still need to call addValue and configureXonoticTextSliderValues! +#endif + +#ifdef IMPLEMENTATION +entity makeXonoticPicmipSlider() +{ + entity me; + me = spawnXonoticPicmipSlider(); + me.configureXonoticPicmipSlider(me); + return me; +} +void XonoticPicmipSlider_configureXonoticPicmipSlider(entity me) +{ + me.configureXonoticTextSlider(me, "gl_picmip"); + me.autofix(me); +} +float texmemsize() +{ + return + ( + 2500 * pow(0.5, max(0, cvar("gl_picmip") + cvar("gl_picmip_other"))) + + 1500 * pow(0.5, max(0, cvar("gl_picmip") + cvar("gl_picmip_world"))) + ) * ((cvar("r_texture_dds_load") || cvar("gl_texturecompression")) ? 0.4 : 1.0); // TC: normalmaps 50%, other 25%, few incompressible, guessing 40% as conservative average +} +void XonoticPicmipSlider_autofix(entity me) +{ + float max_hard, max_soft; + max_hard = cvar("sys_memsize_virtual"); + max_soft = cvar("sys_memsize_physical"); + if(max_hard > 0) + { + while(me.value > 0 && texmemsize() > max_hard) + me.setValue(me, me.value - 1); + } + // TODO also check the soft limit! + // TODO better handling than clamping the slider! +} +void XonoticPicmipSlider_draw(entity me) +{ + me.autofix(me); + SUPER(XonoticPicmipSlider).draw(me); +} +#endif diff --git a/qcsrc/menu/xonotic/textslider.c b/qcsrc/menu/xonotic/textslider.c index 69270a67a..3fee2bf55 100644 --- a/qcsrc/menu/xonotic/textslider.c +++ b/qcsrc/menu/xonotic/textslider.c @@ -6,13 +6,13 @@ CLASS(XonoticTextSlider) EXTENDS(TextSlider) ATTRIB(XonoticTextSlider, fontSize, float, SKINFONTSIZE_NORMAL) ATTRIB(XonoticTextSlider, valueSpace, float, SKINWIDTH_SLIDERTEXT) ATTRIB(XonoticTextSlider, image, string, SKINGFX_SLIDER) - ATTRIB(XonoticSlider, tolerance, vector, SKINTOLERANCE_SLIDER) + ATTRIB(XonoticTextSlider, tolerance, vector, SKINTOLERANCE_SLIDER) ATTRIB(XonoticTextSlider, align, float, 0.5) - ATTRIB(XonoticSlider, color, vector, SKINCOLOR_SLIDER_N) - ATTRIB(XonoticSlider, colorC, vector, SKINCOLOR_SLIDER_C) - ATTRIB(XonoticSlider, colorF, vector, SKINCOLOR_SLIDER_F) - ATTRIB(XonoticSlider, colorD, vector, SKINCOLOR_SLIDER_D) - ATTRIB(XonoticSlider, color2, vector, SKINCOLOR_SLIDER_S) + ATTRIB(XonoticTextSlider, color, vector, SKINCOLOR_SLIDER_N) + ATTRIB(XonoticTextSlider, colorC, vector, SKINCOLOR_SLIDER_C) + ATTRIB(XonoticTextSlider, colorF, vector, SKINCOLOR_SLIDER_F) + ATTRIB(XonoticTextSlider, colorD, vector, SKINCOLOR_SLIDER_D) + ATTRIB(XonoticTextSlider, color2, vector, SKINCOLOR_SLIDER_S) ATTRIB(XonoticTextSlider, cvarName, string, string_null) METHOD(XonoticTextSlider, loadCvars, void(entity)) @@ -61,6 +61,16 @@ void XonoticTextSlider_loadCvars(entity me) for(i = 1; i < n; ++i) s = strcat(s, " ", cvar_string(argv(i))); me.setValueFromIdentifier(me, s); + if(me.value < 0 && n > 1) + { + // if it failed: check if all cvars have the same value + // if yes, try its value as 1-word identifier + for(i = 1; i < n; ++i) + if(cvar_string(argv(i)) != cvar_string(argv(i-1))) + break; + if(i >= n) + me.setValueFromIdentifier(me, cvar_string(argv(0))); + } } void XonoticTextSlider_saveCvars(entity me) { diff --git a/qcsrc/qc-server.cbp b/qcsrc/qc-server.cbp index 00912bea3..eaa30d2d4 100644 --- a/qcsrc/qc-server.cbp +++ b/qcsrc/qc-server.cbp @@ -192,6 +192,7 @@ + diff --git a/qcsrc/server/anticheat.qc b/qcsrc/server/anticheat.qc index 3b729ca48..5e7eb7075 100644 --- a/qcsrc/server/anticheat.qc +++ b/qcsrc/server/anticheat.qc @@ -70,11 +70,11 @@ void anticheat_physics() MEAN_ACCUMULATE(anticheat_div0_evade, 1 - (self.anticheat_div0_evade_forward_initial * v_forward), 1); } - MEAN_ACCUMULATE(anticheat_div0_strafebot_old, movement_oddity(self.movement, self.anticheat_div0_strafebot_movement_prev), max(0, 0.05 - frametime)); + MEAN_ACCUMULATE(anticheat_div0_strafebot_old, movement_oddity(self.movement, self.anticheat_div0_strafebot_movement_prev), max(0, sys_frametime - frametime)); self.anticheat_div0_strafebot_movement_prev = self.movement; if(vlen(self.anticheat_div0_strafebot_forward_prev)) - MEAN_ACCUMULATE(anticheat_div0_strafebot_new, 1 - (self.anticheat_div0_strafebot_forward_prev * v_forward), max(0, 0.05 - frametime)); + MEAN_ACCUMULATE(anticheat_div0_strafebot_new, 1 - (self.anticheat_div0_strafebot_forward_prev * v_forward), max(0, sys_frametime - frametime)); self.anticheat_div0_strafebot_forward_prev = v_forward; // generic speedhack detection: correlate anticheat_speedhack_movetime (UPDATED BEFORE THIS) and server time diff --git a/qcsrc/server/antilag.qc b/qcsrc/server/antilag.qc index 8b1dc6de1..8a628a1be 100644 --- a/qcsrc/server/antilag.qc +++ b/qcsrc/server/antilag.qc @@ -49,7 +49,7 @@ float antilag_find(entity e, float t) return -1; } -vector lerp(float t0, vector v0, float t1, vector v1, float t) +vector lerpv(float t0, vector v0, float t1, vector v1, float t) { return v0 + (v1 - v0) * ((t - t0) / (t1 - t0)); } @@ -69,7 +69,17 @@ vector antilag_takebackorigin(entity e, float t) if(i1 >= ANTILAG_MAX_ORIGINS) i1 = 0; - return lerp(e.(antilag_times[i0]), e.(antilag_origins[i0]), e.(antilag_times[i1]), e.(antilag_origins[i1]), t); + return lerpv(e.(antilag_times[i0]), e.(antilag_origins[i0]), e.(antilag_times[i1]), e.(antilag_origins[i1]), t); +} + +vector antilag_takebackavgvelocity(entity e, float t0, float t1) +{ + vector o0, o1; + if(t0 >= t1) + return '0 0 0'; + o0 = antilag_takebackorigin(e, t0); + o1 = antilag_takebackorigin(e, t1); + return (o1 - o0) * (1 / (t1 - t0)); } void antilag_takeback(entity e, float t) diff --git a/qcsrc/server/antilag.qh b/qcsrc/server/antilag.qh index d4ed9118e..2a7343243 100644 --- a/qcsrc/server/antilag.qh +++ b/qcsrc/server/antilag.qh @@ -1,6 +1,7 @@ void antilag_record(entity e, float t); float antilag_find(entity e, float t); vector antilag_takebackorigin(entity e, float t); +vector antilag_takebackavgvelocity(entity e, float t0, float t1); void antilag_takeback(entity e, float t); void antilag_restore(entity e); diff --git a/qcsrc/server/bot/bot.qc b/qcsrc/server/bot/bot.qc index 3ef50481d..945600a88 100644 --- a/qcsrc/server/bot/bot.qc +++ b/qcsrc/server/bot/bot.qc @@ -43,7 +43,7 @@ void bot_think() //self.bot_painintensity = self.bot_painintensity + self.bot_oldhealth - self.health; //self.bot_painintensity = bound(0, self.bot_painintensity, 100); - if(time < game_starttime || ((cvar("g_campaign") && !campaign_bots_may_start))) + if (cvar("g_campaign") && !campaign_bots_may_start) { self.nextthink = time + 0.5; return; @@ -81,6 +81,14 @@ void bot_think() self.BUTTON_CHAT = 0; self.BUTTON_USE = 0; + if (time < game_starttime) + { + // block the bot during the countdown to game start + self.movement = '0 0 0'; + self.nextthink = game_starttime; + return; + } + // if dead, just wait until we can respawn if (self.deadflag) { @@ -555,17 +563,16 @@ void bot_serverframe() // But don't remove bots immediately on level change, as the real players // usually haven't rejoined yet bots_would_leave = FALSE; - if ((realplayers || cvar("bot_join_empty") || (currentbots > 0 && time < 5))) + if (teamplay && cvar("bot_vs_human") && (c3==-1 && c4==-1)) + bots = min(ceil(fabs(cvar("bot_vs_human")) * activerealplayers), maxclients - realplayers); + else if ((realplayers || cvar("bot_join_empty") || (currentbots > 0 && time < 5))) { float realminplayers, minplayers; realminplayers = cvar("minplayers"); minplayers = max(0, floor(realminplayers)); float realminbots, minbots; - if(teamplay && cvar("bot_vs_human")) - realminbots = ceil(fabs(cvar("bot_vs_human")) * activerealplayers); - else - realminbots = cvar("bot_number"); + realminbots = cvar("bot_number"); minbots = max(0, floor(realminbots)); bots = min(max(minbots, minplayers - activerealplayers), maxclients - realplayers); diff --git a/qcsrc/server/bot/havocbot/havocbot.qc b/qcsrc/server/bot/havocbot/havocbot.qc index 2b86c27ad..934aba87d 100644 --- a/qcsrc/server/bot/havocbot/havocbot.qc +++ b/qcsrc/server/bot/havocbot/havocbot.qc @@ -950,6 +950,7 @@ void havocbot_chooseweapon() local float nex ; nex =-1000; local float hagar ; hagar =-1000; local float grenade ; grenade =-1000; + local float mine ; mine =-1000; local float electro ; electro =-1000; local float crylink ; crylink =-1000; local float uzi ; uzi =-1000; @@ -1077,6 +1078,15 @@ void havocbot_chooseweapon() grenade = (cvar("g_balance_grenadelauncher_primary_damage")/cvar("g_balance_grenadelauncher_primary_refire")*1.0) * bound(0,(cvar("g_balance_grenadelauncher_primary_speed")/distance*maxdelaytime),1)*1.1; + if (client_hasweapon(self, WEP_MINE_LAYER, TRUE, FALSE) && + !( + cvar("bot_ai_weapon_combo") && self.weapon == WEP_MINE_LAYER && + af > combo_time + ) + ) + mine = (cvar("g_balance_minelayer_damage")/cvar("g_balance_minelayer_refire")*1.0) + * bound(0,(cvar("g_balance_minelayer_speed")/distance*maxdelaytime),1)*1.1; + if (client_hasweapon(self, WEP_ELECTRO, TRUE, FALSE) && !( cvar("bot_ai_weapon_combo") && self.weapon == WEP_ELECTRO && af > combo_time @@ -1123,6 +1133,7 @@ void havocbot_chooseweapon() dprint("Nex: " , ftos(nex ), "\n"); dprint("Hagar: " , ftos(hagar ), "\n"); dprint("Grenade: ", ftos(grenade ), "\n"); + dprint("Mine: " , ftos(mine ), "\n"); dprint("Electro: ", ftos(electro ), "\n"); dprint("Crylink: ", ftos(crylink ), "\n"); dprint("Uzi: " , ftos(uzi ), "\n"); @@ -1135,6 +1146,7 @@ void havocbot_chooseweapon() w = WEP_NEX ;s = nex ;if (s > bestscore){bestscore = s;bestweapon = w;} if (self.switchweapon == w) currentscore = s; w = WEP_HAGAR ;s = hagar ;if (s > bestscore){bestscore = s;bestweapon = w;} if (self.switchweapon == w) currentscore = s; w = WEP_GRENADE_LAUNCHER ;s = grenade ;if (s > bestscore){bestscore = s;bestweapon = w;} if (self.switchweapon == w) currentscore = s; + w = WEP_MINE_LAYER ;s = mine ;if (s > bestscore){bestscore = s;bestweapon = w;} if (self.switchweapon == w) currentscore = s; w = WEP_ELECTRO ;s = electro ;if (s > bestscore){bestscore = s;bestweapon = w;} if (self.switchweapon == w) currentscore = s; w = WEP_CRYLINK ;s = crylink ;if (s > bestscore){bestscore = s;bestweapon = w;} if (self.switchweapon == w) currentscore = s; w = WEP_UZI ;s = uzi ;if (s > bestscore){bestscore = s;bestweapon = w;} if (self.switchweapon == w) currentscore = s; diff --git a/qcsrc/server/bot/waypoints.qc b/qcsrc/server/bot/waypoints.qc index 3cbec8761..4f3640e26 100644 --- a/qcsrc/server/bot/waypoints.qc +++ b/qcsrc/server/bot/waypoints.qc @@ -16,7 +16,7 @@ entity waypoint_spawn(vector m1, vector m2, float f) } w = spawn(); - w.dphitcontentsmask = DPCONTENTS_SOLID | DPCONTENTS_BODY | DPCONTENTS_PLAYERCLIP; + w.dphitcontentsmask = DPCONTENTS_SOLID | DPCONTENTS_BODY | DPCONTENTS_PLAYERCLIP | DPCONTENTS_BOTCLIP; w.classname = "waypoint"; w.wpflags = f; setorigin(w, (m1 + m2) * 0.5); diff --git a/qcsrc/server/cheats.qc b/qcsrc/server/cheats.qc index a75537907..8d837b801 100644 --- a/qcsrc/server/cheats.qc +++ b/qcsrc/server/cheats.qc @@ -672,6 +672,7 @@ float CheatCommand(float argc) END_CHEAT_FUNCTION(); } +void crosshair_trace_plusvisibletriggers(entity pl); void Drag_Begin(entity dragger, entity draggee, vector touchpoint); void Drag_Finish(entity dragger); float Drag_IsDraggable(entity draggee); @@ -725,7 +726,7 @@ float CheatFrame() if(Drag_CanDrag(self)) if(self.BUTTON_DRAG) { - crosshair_trace(self); + crosshair_trace_plusvisibletriggers(self); if(trace_ent) if(Drag_IsDraggable(trace_ent)) switch(0) @@ -752,6 +753,22 @@ float CheatFrame() // ENTITY DRAGGING +void crosshair_trace_plusvisibletriggers(entity pl) +{ + entity first; + entity e; + first = findchainfloat(solid, SOLID_TRIGGER); + + for (e = first; e; e = e.chain) + if (e.model != "") + e.solid = SOLID_BSP; + + crosshair_trace(pl); + + for (e = first; e; e = e.chain) + e.solid = SOLID_TRIGGER; +} + // on dragger: .float draggravity; .float dragspeed; // speed of mouse wheel action @@ -828,14 +845,16 @@ float Drag_IsDraggable(entity draggee) return FALSE; if(draggee.classname == "func_button") return FALSE; - if(draggee.model == "") - return FALSE; +// if(draggee.model == "") +// return FALSE; if(draggee.classname == "spectator") return FALSE; if(draggee.classname == "observer") return FALSE; if(draggee.classname == "exteriorweaponentity") return FALSE; + if(draggee.classname == "weaponentity") + return FALSE; return TRUE; } diff --git a/qcsrc/server/cl_client.qc b/qcsrc/server/cl_client.qc index f08ef5f53..df6c8d4b2 100644 --- a/qcsrc/server/cl_client.qc +++ b/qcsrc/server/cl_client.qc @@ -6,6 +6,13 @@ void send_CSQC_teamnagger() { WriteByte(0, TE_CSQC_TEAMNAGGER); } +void send_CSQC_cr_maxbullets(entity e) { + msg_entity = e; + WriteByte(MSG_ONE, SVC_TEMPENTITY); + WriteByte(MSG_ONE, TE_CSQC_CR_MAXBULLETS); + WriteByte(MSG_ONE, cvar("g_balance_campingrifle_magazinecapacity")); +} + void Announce(string snd) { WriteByte(MSG_ALL, SVC_TEMPENTITY); WriteByte(MSG_ALL, TE_CSQC_ANNOUNCE); @@ -866,10 +873,11 @@ void PutClientInServer (void) self.iscreature = TRUE; self.movetype = MOVETYPE_WALK; self.solid = SOLID_SLIDEBOX; + self.dphitcontentsmask = DPCONTENTS_BODY | DPCONTENTS_SOLID; if(cvar("g_playerclip_collisions")) - self.dphitcontentsmask = DPCONTENTS_SOLID | DPCONTENTS_BODY | DPCONTENTS_PLAYERCLIP; - else - self.dphitcontentsmask = DPCONTENTS_SOLID | DPCONTENTS_BODY; + self.dphitcontentsmask |= DPCONTENTS_PLAYERCLIP; + if(clienttype(self) == CLIENTTYPE_BOT && cvar("g_botclip_collisions")) + self.dphitcontentsmask |= DPCONTENTS_BOTCLIP; self.frags = FRAGS_PLAYER; if(independent_players) MAKE_INDEPENDENT_PLAYER(self); @@ -881,6 +889,8 @@ void PutClientInServer (void) self.effects = 0; self.air_finished = time + 12; self.dmg = 2; + if(cvar("g_balance_nex_charge")) + self.nex_charge = cvar("g_balance_nex_charge_start"); if(inWarmupStage) { @@ -1354,8 +1364,9 @@ void FixClientCvars(entity e) if(g_race || g_cts) stuffcmd(e, "cl_cmd settemp cl_movecliptokeyboard 2\n"); if(cvar("g_antilag") == 3) // client side hitscan - //stuffcmd(e, "cl_cmd settemp cl_prydoncursor -1\ncl_cmd settemp cl_prydoncursor_notrace 0\n"); stuffcmd(e, "cl_cmd settemp cl_prydoncursor_notrace 0\n"); + if(sv_gentle) + stuffcmd(e, "cl_cmd settemp cl_gentle 1\n"); /* * we no longer need to stuff this. Remove this comment block if you feel * 2.3 and higher (or was it 2.2.3?) don't need these any more @@ -1386,10 +1397,6 @@ Called when a client connects to the server string ColoredTeamName(float t); void DecodeLevelParms (void); //void dom_player_join_team(entity pl); -#ifdef UID -.float uid_kicktime; -.string uid; -#endif void ClientConnect (void) { float t; @@ -1567,12 +1574,6 @@ void ClientConnect (void) else self.hitplotfh = -1; -#ifdef UID - if(clienttype(self) == CLIENTTYPE_REAL) - if not(self.uid) - self.uid_kicktime = time + 60; -#endif - if(g_race || g_cts) { string rr; if(g_cts) @@ -1593,9 +1594,11 @@ void ClientConnect (void) race_SendRankings(i, 0, 0, MSG_ONE); } } - else if(cvar("sv_teamnagger") && !g_ca) // teamnagger is currently bad for ca + else if(cvar("sv_teamnagger") && !(cvar("bot_vs_human") && (c3==-1 && c4==-1)) && !g_ca) // teamnagger is currently bad for ca send_CSQC_teamnagger(); + send_CSQC_cr_maxbullets(self); + CheatInitClient(); } @@ -2856,9 +2859,16 @@ float isInvisibleString(string s) switch(c) { case 0: - case 32: - case 160: + case 32: // space break; + case 192: // charmap space + if (!cvar("utf8_enable")) + break; + return FALSE; + case 160: // space in unicode fonts + case 0xE000 + 192: // utf8 charmap space + if (cvar("utf8_enable")) + break; default: return FALSE; } @@ -2903,16 +2913,6 @@ void PlayerPostThink (void) self.stat_count -= 1; } -#ifdef UID - if(self.uid_kicktime) - if(time > self.uid_kicktime) - { - bprint("^3", self.netname, "^3 was kicked for missing UID.\n"); - dropclient(self); - return; - } -#endif - if(sv_maxidle && frametime) { // WORKAROUND: only use dropclient in server frames (frametime set). Never use it in cl_movement frames (frametime zero). diff --git a/qcsrc/server/cl_physics.qc b/qcsrc/server/cl_physics.qc index 70e702505..b005dd5f3 100644 --- a/qcsrc/server/cl_physics.qc +++ b/qcsrc/server/cl_physics.qc @@ -33,6 +33,12 @@ float sv_airspeedlimit_nonqw; .float wasFlying; .float spectatorspeed; +.float multijump_count; +.float multijump_ready; +.float prevjumpbutton; + +.float nexspeed; + /* ============= PlayerJump @@ -66,9 +72,58 @@ void PlayerJump (void) return; } + if (cvar("g_multijump")) + { + if (self.prevjumpbutton == FALSE && !(self.flags & FL_ONGROUND)) // jump button pressed this frame and we are in midair + self.multijump_ready = TRUE; // this is necessary to check that we released the jump button and pressed it again + else + self.multijump_ready = FALSE; + } + + if(!doublejump && self.multijump_ready && self.multijump_count < cvar("g_multijump") && self.velocity_z > cvar("g_multijump_speed")) + { + // doublejump = FALSE; // checked above in the if + if (cvar("g_multijump") > 0) + { + if (cvar("g_multijump_add") == 0) // in this case we make the z velocity == jumpvelocity + { + if (self.velocity_z < mjumpheight) + { + doublejump = TRUE; + self.velocity_z = 0; + } + } + else + doublejump = TRUE; + + if(doublejump) + { + if(self.movement_x != 0 || self.movement_y != 0) // don't remove all speed if player isnt pressing any movement keys + { + float curspeed; + vector wishvel, wishdir; + + curspeed = max( + vlen(vec2(self.velocity)), // current xy speed + vlen(vec2(antilag_takebackavgvelocity(self, max(self.lastteleporttime + sys_frametime, time - 0.25), time))) // average xy topspeed over the last 0.25 secs + ); + makevectors(self.v_angle_y * '0 1 0'); + wishvel = v_forward * self.movement_x + v_right * self.movement_y; + wishdir = normalize(wishvel); + + self.velocity_x = wishdir_x * curspeed; // allow "dodging" at a multijump + self.velocity_y = wishdir_y * curspeed; + // keep velocity_z unchanged! + } + self.multijump_count += 1; + } + } + self.multijump_ready = FALSE; // require releasing and pressing the jump button again for the next jump + } + if (!doublejump) - if (!(self.flags & FL_ONGROUND)) - return; + if (!(self.flags & FL_ONGROUND)) + return; if(!sv_pogostick) if (!(self.flags & FL_JUMPRELEASED)) @@ -319,8 +374,7 @@ void RaceCarPhysics() float mt; rigvel_z -= frametime * sv_gravity; // 4x gravity plays better - rigvel_xy = rigvel; - rigvel_xy_z = 0; + rigvel_xy = vec2(rigvel); if(g_bugrigs_planar_movement_car_jumping && !g_touchexplode) // touchexplode is a better way to handle collisions mt = MOVE_NORMAL; @@ -512,7 +566,7 @@ void PM_Accelerate(vector wishdir, float wishspeed, float wishspeed0, float acce vel_straight = self.velocity * wishdir; vel_z = self.velocity_z; - vel_xy = self.velocity - vel_z * '0 0 1'; + vel_xy = vec2(self.velocity); vel_perpend = vel_xy - vel_straight * wishdir; step = accel * frametime * wishspeed0; @@ -652,7 +706,7 @@ void SV_PlayerPhysics() float buttons_prev; float not_allowed_to_move; string c; - + // fix physics stats for g_movement_highspeed self.stat_sv_airaccel_qw = AdjustAirAccelQW(sv_airaccel_qw, autocvar_g_movement_highspeed); if(sv_airstrafeaccel_qw) @@ -897,6 +951,14 @@ void SV_PlayerPhysics() if(self.classname == "player") { + if(self.flags & FL_ONGROUND) + { + if (cvar("g_multijump") > 0) + self.multijump_count = 0; + else + self.multijump_count = -2; // the cvar value for infinite jumps is -1, so this needs to be smaller + } + if (self.BUTTON_JUMP) PlayerJump (); else @@ -904,6 +966,7 @@ void SV_PlayerPhysics() if (self.waterlevel == WATERLEVEL_SWIMMING) CheckWaterJump (); + self.prevjumpbutton = self.BUTTON_JUMP; } if (self.flags & FL_WATERJUMP ) @@ -1262,6 +1325,17 @@ void SV_PlayerPhysics() } } } + + float xyspeed; + xyspeed = vlen('1 0 0' * self.velocity_x + '0 1 0' * self.velocity_y); + if(self.weapon == WEP_NEX && cvar("g_balance_nex_charge") && cvar("g_balance_nex_charge_velocity_rate") && xyspeed > cvar("g_balance_nex_charge_minspeed")) + { + // add a maximum of charge_velocity_rate when going fast (f = 1), gradually increasing from minspeed (f = 0) to maxspeed + xyspeed = min(xyspeed, cvar("g_balance_nex_charge_maxspeed")); + f = (xyspeed - cvar("g_balance_nex_charge_minspeed")) / (cvar("g_balance_nex_charge_maxspeed") - cvar("g_balance_nex_charge_minspeed")); + // add the extra charge + self.nex_charge = min(1, self.nex_charge + cvar("g_balance_nex_charge_velocity_rate") * f * frametime); + } :end if(self.flags & FL_ONGROUND) self.lastground = time; diff --git a/qcsrc/server/cl_player.qc b/qcsrc/server/cl_player.qc index 494a80b36..db8bc4bfc 100644 --- a/qcsrc/server/cl_player.qc +++ b/qcsrc/server/cl_player.qc @@ -660,7 +660,7 @@ void PlayerDamage (entity inflictor, entity attacker, float damage, float deatht // call the corpse damage function just in case it wants to gib self.event_damage(inflictor, attacker, 0, deathtype, hitloc, force); // set up to fade out later - SUB_SetFade (self, time + 12 + random () * 4, 1); + SUB_SetFade (self, time + 6 + random (), 1); // remove laserdot if(self.weaponentity) diff --git a/qcsrc/server/cl_weapons.qc b/qcsrc/server/cl_weapons.qc index 4ab7abde4..540e3f84a 100644 --- a/qcsrc/server/cl_weapons.qc +++ b/qcsrc/server/cl_weapons.qc @@ -293,7 +293,7 @@ void W_ThrowWeapon(vector velo, vector delta, float doreduce) return; if(!W_IsWeaponThrowable(w)) return; - if(self.weaponentity.state != WS_READY) + if(self.deadflag == DEAD_NO && self.weaponentity.state != WS_READY) return; wb = W_WeaponBit(w); @@ -385,7 +385,7 @@ void W_WeaponFrame() // server framerate is very low and the weapon fire rate very high local float c; c = 0; - while (c < 5) + while (c < W_TICSPERFRAME) { c = c + 1; if(wb && ((self.weapons & wb) == 0)) diff --git a/qcsrc/server/cl_weaponsystem.qc b/qcsrc/server/cl_weaponsystem.qc index 925d53fa7..4537573c5 100644 --- a/qcsrc/server/cl_weaponsystem.qc +++ b/qcsrc/server/cl_weaponsystem.qc @@ -130,6 +130,8 @@ vector w_shotend; // this function calculates w_shotorg and w_shotdir based on the weapon model // offset, trueaim and antilag, and won't put w_shotorg inside a wall. // make sure you call makevectors first (FIXME?) +.float prevstrengthsound; +.float prevstrengthsoundattempt; void W_SetupShot_Dir_ProjectileSize_Range(entity ent, vector s_forward, vector mi, vector ma, float antilag, float recoil, string snd, float maxdamage, float range) { float nudge = 1; // added to traceline target and subtracted from result @@ -245,9 +247,18 @@ void W_SetupShot_Dir_ProjectileSize_Range(entity ent, vector s_forward, vector m sound (ent, CHAN_WEAPON, snd, VOL_BASE, ATTN_NORM); } - if (ent.items & IT_STRENGTH) - if (!g_minstagib) - sound (ent, CHAN_AUTO, "weapons/strength_fire.wav", VOL_BASE, ATTN_NORM); + if(ent.items & IT_STRENGTH) + if(!g_minstagib) + if( + (time > ent.prevstrengthsound + cvar("sv_strengthsound_antispam_time")) + || + (time > ent.prevstrengthsoundattempt + cvar("sv_strengthsound_antispam_refire_threshold")) + ) // prevent insane sound spam + { + sound(ent, CHAN_AUTO, "weapons/strength_fire.wav", VOL_BASE, ATTN_NORM); + ent.prevstrengthsound = time; + } + ent.prevstrengthsoundattempt = time; // nudge w_shotend so a trace to w_shotend hits w_shotend = w_shotend + normalize(w_shotend - w_shotorg) * nudge; @@ -981,6 +992,13 @@ float client_hasweapon(entity cl, float wpn, float andammo, float complain) self = cl; f = weapon_action(wpn, WR_CHECKAMMO1); f = f + weapon_action(wpn, WR_CHECKAMMO2); + + // always allow selecting the Mine Layer if we placed mines, so that we can detonate them + local entity mine; + if(wpn == WEP_MINE_LAYER) + for(mine = world; (mine = find(mine, classname, "mine")); ) if(mine.owner == self) + f = 1; + self = oldself; } if (!f) @@ -1093,6 +1111,15 @@ float weapon_prepareattack_checkammo(float secondary) if not(self.items & IT_UNLIMITED_WEAPON_AMMO) if (!weapon_action(self.weapon, WR_CHECKAMMO1 + secondary)) { + // always keep the Mine Layer if we placed mines, so that we can detonate them + local entity mine; + if(self.weapon == WEP_MINE_LAYER) + for(mine = world; (mine = find(mine, classname, "mine")); ) if(mine.owner == self) + return FALSE; + + if(self.weapon == self.switchweapon) // only play once BEFORE starting to switch weapons + sound (self, CHAN_AUTO, "weapons/dryfire.wav", VOL_BASE, ATTN_NORM); + W_SwitchToOtherWeapon(self); return FALSE; } diff --git a/qcsrc/server/clientcommands.qc b/qcsrc/server/clientcommands.qc index 171906428..a9fd886bf 100644 --- a/qcsrc/server/clientcommands.qc +++ b/qcsrc/server/clientcommands.qc @@ -182,16 +182,6 @@ void SV_ParseClientCommand(string s) { tokens = tokenize_console(s); } GetCvars(1); -#ifdef UID - } else if(cmd == "uid") { - if not(self.uid) - { - self.uid = strzone(argv(1)); - self.uid_kicktime = 0; - print("Client ", etos(self), " has UID ", self.uid, "\n"); - Ban_MaybeEnforceBan(self); - } -#endif } else if(cmd == "sentcvar") { // new system if(tokens == 2) // undefined cvar: use the default value on the server then { diff --git a/qcsrc/server/ctf.qc b/qcsrc/server/ctf.qc index 6e314c88e..8c0844b22 100644 --- a/qcsrc/server/ctf.qc +++ b/qcsrc/server/ctf.qc @@ -188,7 +188,7 @@ void place_flag() self.nextthink = time + 0.1; self.cnt = FLAG_BASE; self.mangle = self.angles; - self.dphitcontentsmask = DPCONTENTS_SOLID | DPCONTENTS_BODY | DPCONTENTS_PLAYERCLIP; + self.dphitcontentsmask = DPCONTENTS_SOLID | DPCONTENTS_BODY | DPCONTENTS_PLAYERCLIP | DPCONTENTS_BOTCLIP; //self.effects = self.effects | EF_DIMLIGHT; if(self.noalign) { diff --git a/qcsrc/server/defs.qh b/qcsrc/server/defs.qh index 74b4ecea8..d1d86ed79 100644 --- a/qcsrc/server/defs.qh +++ b/qcsrc/server/defs.qh @@ -221,6 +221,9 @@ float WS_DROP = 2; // deselecting frame float WS_INUSE = 3; // fire state float WS_READY = 4; // idle frame +// there is 2 weapon tics that can run in one server frame +#define W_TICSPERFRAME 2 + void weapon_defaultspawnfunc(float wpn); string w_deathtypestring; @@ -294,6 +297,7 @@ string getTimeoutText(float addOneSecond); .entity flagcarried; .entity lastrocket; +.entity lastmine; .float playerid; float playerid_last; @@ -436,6 +440,7 @@ float next_pingtime; // TODO implemented fall and falling #define ALLPLAYERSOUNDS \ _VOICEMSG(death) \ + _VOICEMSG(fall) \ _VOICEMSG(drown) \ _VOICEMSG(gasp) \ _VOICEMSG(jump) \ @@ -635,3 +640,14 @@ string deathmessage; .float selectweapon; // last selected weapon of the player .float ballistics_density; // wall piercing factor, larger = bullet can pass through more + +#define ACTIVE_NOT 0 +#define ACTIVE_ACTIVE 1 +#define ACTIVE_IDLE 2 +#define ACTIVE_BUSY 2 +#define ACTIVE_TOGGLE 3 +.float active; +.float (float act_state) setactive; +.entity realowner; + +.float nex_charge; diff --git a/qcsrc/server/domination.qc b/qcsrc/server/domination.qc index 5bf2b9ad8..3e5bed8b2 100644 --- a/qcsrc/server/domination.qc +++ b/qcsrc/server/domination.qc @@ -77,7 +77,10 @@ void dompoint_captured () wait_time = self.wait; bprint("^3", head.netname, "^3", self.message); - bprint(" ^7(", ftos(points), " points every ", ftos(wait_time), " seconds)\n"); + if (points != 1) + bprint(" ^7(", ftos(points), " points every ", ftos(wait_time), " seconds)\n"); + else + bprint(" ^7(", ftos(points), " point every ", ftos(wait_time), " seconds)\n"); if(self.enemy.playerid == self.enemy_playerid) PlayerScore_Add(self.enemy, SP_DOM_TAKES, 1); diff --git a/qcsrc/server/extensions.qh b/qcsrc/server/extensions.qh index 18119546c..b72a05000 100644 --- a/qcsrc/server/extensions.qh +++ b/qcsrc/server/extensions.qh @@ -2309,3 +2309,15 @@ float JOINTTYPE_HINGE2 = 5; // hinge2; uses origin (anchor), angles (axis1), vel //description: //various physics properties can be defined in an entity and are executed via //ODE + +//DP_CRYPTO +//idea: divVerent +//darkplaces implementation: divVerent +//field definitions: (SVQC) +.string crypto_keyfp; // fingerprint of CA key the player used to authenticate, or string_null if not verified +.string crypto_mykeyfp; // fingerprint of CA key the server used to authenticate to the player, or string_null if not verified +.string crypto_idfp; // fingerprint of ID used by the player entity, or string_null if not identified +.string crypto_encryptmethod; // the string "AES128" if encrypting, and string_null if plaintext +.string crypto_signmethod; // the string "HMAC-SHA256" if signing, and string_null if plaintext +// there is no field crypto_myidfp, as that info contains no additional information the QC may have a use for +//description: diff --git a/qcsrc/server/func_breakable.qc b/qcsrc/server/func_breakable.qc index eb4c8b4de..44605ddee 100644 --- a/qcsrc/server/func_breakable.qc +++ b/qcsrc/server/func_breakable.qc @@ -31,8 +31,6 @@ // Otherwise mdl_dead will be displayed at the map origin, and nobody would // want that! -.vector mins_save, maxs_save; - void func_breakable_damage(entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector force); // @@ -87,15 +85,18 @@ void func_breakable_look_destroyed() { local float floor_z; + if(self.solid == SOLID_BSP) // in case a misc_follow moved me, save the current origin first + self.dropped_origin = self.origin; + if(self.mdl_dead == "") self.model = ""; else { - setmodel(self, self.mdl_dead); if (self.origin == '0 0 0') { // probably no origin brush, so don't spawn in the middle of the map.. floor_z = self.absmin_z; setorigin(self,((self.absmax+self.absmin)*.5)); self.origin_z = floor_z; } + setmodel(self, self.mdl_dead); } self.solid = SOLID_NOT; @@ -104,6 +105,8 @@ void func_breakable_look_destroyed() void func_breakable_look_restore() { setmodel(self, self.mdl); + if(self.mdl_dead != "") // only do this if we use mdl_dead, to behave better with misc_follow + setorigin(self, self.dropped_origin); self.solid = SOLID_BSP; } @@ -113,7 +116,6 @@ void func_breakable_behave_destroyed() self.takedamage = DAMAGE_NO; self.event_damage = SUB_Null; self.state = 1; - setsize(self, '0 0 0', '0 0 0'); func_breakable_colormod(); } @@ -123,7 +125,6 @@ void func_breakable_behave_restore() self.takedamage = DAMAGE_AIM; self.event_damage = func_breakable_damage; self.state = 0; - setsize(self, self.mins_save, self.maxs_save); func_breakable_colormod(); } @@ -145,6 +146,7 @@ void func_breakable_destroy() { string oldmsg; activator = self.owner; + self.owner = world; // set by W_PrepareExplosionByDamage // now throw around the debris n = tokenize_console(self.debris); @@ -232,8 +234,6 @@ void spawnfunc_func_breakable() { self.mdl = self.model; SetBrushEntityModel(); - self.mins_save = self.mins; - self.maxs_save = self.maxs; self.use = func_breakable_restore; @@ -247,6 +247,7 @@ void spawnfunc_func_breakable() { precache_sound(self.noise); self.team_saved = self.team; + self.dropped_origin = self.origin; self.reset = func_breakable_reset; func_breakable_reset(); diff --git a/qcsrc/server/g_damage.qc b/qcsrc/server/g_damage.qc index 45962bee7..c7336356c 100644 --- a/qcsrc/server/g_damage.qc +++ b/qcsrc/server/g_damage.qc @@ -364,11 +364,12 @@ void Obituary (entity attacker, entity inflictor, entity targ, float deathtype) // TODO: fix this? if (deathtype == DEATH_CUSTOM) - msg = strcat(deathmessage, " by ^1", msg); - else if (deathtype == DEATH_HURTTRIGGER && inflictor.message2 != "") - { - msg = ftos(strstrofs(inflictor.message2, "#", 0)); - } + msg = deathmessage; + else + msg = inflictor.message2; + + if(strstrofs(msg, "%", 0) < 0) + msg = strcat("%s ", msg, " by %s"); Send_KillNotification(a, s, msg, deathtype, MSG_KILL); @@ -435,6 +436,8 @@ void Obituary (entity attacker, entity inflictor, entity targ, float deathtype) msg = inflictor.message; else if (deathtype == DEATH_CUSTOM) msg = deathmessage; + if(strstrofs(msg, "%", 0) < 0) + msg = strcat("%s ", msg); GiveFrags(targ, targ, -1); if(PlayerScore_Add(targ, SP_SCORE, 0) == -5) { @@ -847,20 +850,6 @@ void Damage (entity targ, entity inflictor, entity attacker, float damage, float } } -vector NearestPointOnBox(entity box, vector org) -{ - vector m1, m2, nearest; - - m1 = box.mins + box.origin; - m2 = box.maxs + box.origin; - - nearest_x = bound(m1_x, org_x, m2_x); - nearest_y = bound(m1_y, org_y, m2_y); - nearest_z = bound(m1_z, org_z, m2_z); - - return nearest; -} - void Damage_RecordDamage(entity attacker, float deathtype, float damage) { float weaponid; @@ -1165,9 +1154,7 @@ void Fire_ApplyDamage(entity e) if not(Fire_IsBurning(e)) return; - o = e.owner; - while(o.owner) - o = o.owner; + for(t = 0, o = e.owner; o.owner && t < 16; o = o.owner, ++t); if(clienttype(o) == CLIENTTYPE_NOTACLIENT) o = e.fire_owner; diff --git a/qcsrc/server/g_models.qc b/qcsrc/server/g_models.qc index 8a380484a..bc996fd32 100644 --- a/qcsrc/server/g_models.qc +++ b/qcsrc/server/g_models.qc @@ -57,6 +57,8 @@ float g_clientmodel_genericsendentity (entity to, float sf) sf |= 0x20; if(self.colormap != 0) sf |= 0x40; + if(self.lodmodelindex1) + sf |= 0x80; WriteByte(MSG_ENTITY, ENT_CLIENT_WALL); WriteByte(MSG_ENTITY, sf); @@ -86,9 +88,18 @@ float g_clientmodel_genericsendentity (entity to, float sf) if(sf & 8) { - WriteShort(MSG_ENTITY, self.modelindex); + if(sf & 0x80) + { + WriteShort(MSG_ENTITY, self.lodmodelindex0); + WriteShort(MSG_ENTITY, bound(0, self.loddistance1, 65535)); + WriteShort(MSG_ENTITY, self.lodmodelindex1); + WriteShort(MSG_ENTITY, bound(0, self.loddistance2, 65535)); + WriteShort(MSG_ENTITY, self.lodmodelindex2); + } + else + WriteShort(MSG_ENTITY, self.modelindex); WriteByte(MSG_ENTITY, self.solid); - WriteByte(MSG_ENTITY, floor(self.scale * 16)); + WriteShort(MSG_ENTITY, floor(self.scale * 256)); if(sf & 0x20) { WriteCoord(MSG_ENTITY, self.mins_x); @@ -124,7 +135,7 @@ float g_clientmodel_genericsendentity (entity to, float sf) if(!self.solid) self.solid = (sol); else if(self.solid < 0) self.solid = SOLID_NOT; #define G_CLIENTMODEL_INIT(sol) \ - SetBrushEntityModelNoLOD(); \ + SetBrushEntityModel(); \ if(!self.scale) self.scale = self.modelscale; \ self.use = g_clientmodel_setcolormaptoactivator; \ InitializeEntity(self, g_clientmodel_dropbyspawnflags, INITPRIO_DROPTOFLOOR); \ diff --git a/qcsrc/server/g_subs.qc b/qcsrc/server/g_subs.qc index 1d1f0bb9b..5d8401df9 100644 --- a/qcsrc/server/g_subs.qc +++ b/qcsrc/server/g_subs.qc @@ -605,7 +605,6 @@ float angc (float a1, float a2) .float loddistance1; .float loddistance2; -vector NearestPointOnBox(entity box, vector org); float LOD_customize() { float d; @@ -615,7 +614,7 @@ float LOD_customize() d = cvar("loddebug"); if(d == 1) self.modelindex = self.lodmodelindex0; - else if(d == 2) + else if(d == 2 || !self.lodmodelindex2) self.modelindex = self.lodmodelindex1; else // if(d == 3) self.modelindex = self.lodmodelindex2; @@ -695,7 +694,8 @@ void LODmodel_attach() } if(self.lodmodelindex1) - SetCustomizer(self, LOD_customize, LOD_uncustomize); + if not(self.SendEntity) + SetCustomizer(self, LOD_customize, LOD_uncustomize); } void SetBrushEntityModel() diff --git a/qcsrc/server/g_triggers.qc b/qcsrc/server/g_triggers.qc index c31352ed5..8ded34fea 100644 --- a/qcsrc/server/g_triggers.qc +++ b/qcsrc/server/g_triggers.qc @@ -413,6 +413,9 @@ void spawnfunc_trigger_counter() .float triggerhurttime; void trigger_hurt_touch() { + if (self.active != ACTIVE_ACTIVE) + return; + // only do the EXACTTRIGGER_TOUCH checks when really needed (saves some cpu) if (other.iscreature) { @@ -455,6 +458,7 @@ entity trigger_hurt_first; void spawnfunc_trigger_hurt() { EXACTTRIGGER_INIT; + self.active = ACTIVE_ACTIVE; self.touch = trigger_hurt_touch; if (!self.dmg) self.dmg = 1000; @@ -462,6 +466,7 @@ void spawnfunc_trigger_hurt() self.message = "was in the wrong place"; if (!self.message2) self.message2 = "was thrown into a world of hurt by"; + // self.message = "someone like %s always gets wrongplaced"; if(!trigger_hurt_first) trigger_hurt_first = self; @@ -492,6 +497,9 @@ float tracebox_hits_trigger_hurt(vector start, vector mi, vector ma, vector end) .float triggerhealtime; void trigger_heal_touch() { + if (self.active != ACTIVE_ACTIVE) + return; + // only do the EXACTTRIGGER_TOUCH checks when really needed (saves some cpu) if (other.iscreature) { @@ -513,6 +521,8 @@ void trigger_heal_touch() void spawnfunc_trigger_heal() { + self.active = ACTIVE_ACTIVE; + EXACTTRIGGER_INIT; self.touch = trigger_heal_touch; if (!self.health) @@ -818,7 +828,7 @@ void spawnfunc_func_pointparticles() if(!self.cnt) self.cnt = particleeffectnum(self.mdl); - Net_LinkEntity(self, FALSE, 0, pointparticles_SendEntity); + Net_LinkEntity(self, (self.spawnflags & 4), 0, pointparticles_SendEntity); IFTARGETED { @@ -1066,13 +1076,15 @@ void misc_laser_think() float laser_SendEntity(entity to, float fl) { WriteByte(MSG_ENTITY, ENT_CLIENT_LASER); - fl = fl - (fl & 0xE0); // use that bit to indicate finite length laser + fl = fl - (fl & 0xF0); // use that bit to indicate finite length laser if(self.spawnflags & 2) fl |= 0x80; if(self.alpha) fl |= 0x40; if(self.scale != 1 || self.modelscale != 1) fl |= 0x20; + if(self.spawnflags & 4) + fl |= 0x10; WriteByte(MSG_ENTITY, fl); if(fl & 1) { @@ -1092,7 +1104,8 @@ float laser_SendEntity(entity to, float fl) WriteByte(MSG_ENTITY, bound(0, self.scale * 16.0, 255)); WriteByte(MSG_ENTITY, bound(0, self.modelscale * 16.0, 255)); } - WriteShort(MSG_ENTITY, self.cnt + 1); + if((fl & 0x80) || !(fl & 0x10)) // effect doesn't need sending if the laser is infinite and has collision testing turned off + WriteShort(MSG_ENTITY, self.cnt + 1); } if(fl & 2) { @@ -1175,6 +1188,8 @@ void spawnfunc_misc_laser() self.scale = 1; if(!self.modelscale) self.modelscale = 1; + else if(self.modelscale < 0) + self.modelscale = 0; self.think = misc_laser_think; self.nextthink = time; InitializeEntity(self, misc_laser_init, INITPRIO_FINDTARGET); @@ -1206,6 +1221,9 @@ void trigger_impulse_touch1() float pushdeltatime; float str; + if (self.active != ACTIVE_ACTIVE) + return; + // FIXME: Better checking for what to push and not. if not(other.iscreature) if (other.classname != "corpse") @@ -1249,7 +1267,8 @@ void trigger_impulse_touch1() if(!pushdeltatime) return; other.velocity = other.velocity + normalize(targ.origin - self.origin) * str * pushdeltatime; - other.flags &~= FL_ONGROUND; + other.flags &~= FL_ONGROUND; + UpdateCSQCProjectile(other); } // Directionless (accelerator/decelerator) mode @@ -1257,6 +1276,9 @@ void trigger_impulse_touch2() { float pushdeltatime; + if (self.active != ACTIVE_ACTIVE) + return; + // FIXME: Better checking for what to push and not. if not(other.iscreature) if (other.classname != "corpse") @@ -1286,6 +1308,7 @@ void trigger_impulse_touch2() // div0: ticrate independent, 1 = identity (not 20) other.velocity = other.velocity * pow(self.strength, pushdeltatime); + UpdateCSQCProjectile(other); } // Spherical (gravity/repulsor) mode @@ -1294,6 +1317,9 @@ void trigger_impulse_touch3() float pushdeltatime; float str; + if (self.active != ACTIVE_ACTIVE) + return; + // FIXME: Better checking for what to push and not. if not(other.iscreature) if (other.classname != "corpse") @@ -1333,6 +1359,7 @@ void trigger_impulse_touch3() str = self.strength; other.velocity = other.velocity + normalize(other.origin - self.origin) * str * pushdeltatime; + UpdateCSQCProjectile(other); } /*QUAKED spawnfunc_trigger_impulse (.5 .5 .5) ? @@ -1355,6 +1382,8 @@ in directional and sperical mode. For damper/accelerator mode this is not nesses void spawnfunc_trigger_impulse() { + self.active = ACTIVE_ACTIVE; + EXACTTRIGGER_INIT; if(self.radius) { @@ -1931,3 +1960,64 @@ void spawnfunc_trigger_magicear() // target: // what to trigger } + +void relay_activators_use() +{ + entity trg, os; + + os = self; + + for(trg = world; (trg = find(trg, targetname, os.target)); ) + { + self = trg; + if (trg.setactive) + trg.setactive(os.cnt); + else + { + //bprint("Not using setactive\n"); + if(os.cnt == ACTIVE_TOGGLE) + if(trg.active == ACTIVE_ACTIVE) + trg.active = ACTIVE_NOT; + else + trg.active = ACTIVE_ACTIVE; + else + trg.active = os.cnt; + } + } + self = os; +} + +void spawnfunc_relay_activate() +{ + self.cnt = ACTIVE_ACTIVE; + self.use = relay_activators_use; +} + +void spawnfunc_relay_deactivate() +{ + self.cnt = ACTIVE_NOT; + self.use = relay_activators_use; +} + +void spawnfunc_relay_activatetoggle() +{ + self.cnt = ACTIVE_TOGGLE; + self.use = relay_activators_use; +} + +.string chmap, gametype; +void spawnfunc_target_changelevel_use() +{ + if(self.gametype != "") + MapInfo_SwitchGameType(MapInfo_Type_FromString(self.gametype)); + + if (self.chmap == "") + localcmd("endmatch\n"); + else + localcmd(strcat("changelevel ", self.chmap, "\n")); +}; + +void spawnfunc_target_changelevel() +{ + self.use = spawnfunc_target_changelevel_use; +}; diff --git a/qcsrc/server/g_violence.qc b/qcsrc/server/g_violence.qc index 8cecaeae6..a6e73ba25 100644 --- a/qcsrc/server/g_violence.qc +++ b/qcsrc/server/g_violence.qc @@ -19,8 +19,6 @@ void Violence_GibSplash_At(vector org, vector dir, float type, float amount, ent e.classname = "gibsplash"; e.cnt = amount; e.state = type; // should stay smaller than 15 - if(sv_gentle) - e.state |= 0x80; // "force gentle" bit if(!sound_allowed(MSG_BROADCAST, gibowner) || !sound_allowed(MSG_BROADCAST, attacker)) e.state |= 0x40; // "silence" bit e.state |= 8 * self.species; // gib type, ranges from 0 to 15 diff --git a/qcsrc/server/g_world.qc b/qcsrc/server/g_world.qc index 55d61a73a..262fe14b3 100644 --- a/qcsrc/server/g_world.qc +++ b/qcsrc/server/g_world.qc @@ -637,6 +637,8 @@ void spawnfunc_worldspawn (void) addstat(STAT_LEADLIMIT, AS_FLOAT, stat_leadlimit); addstat(STAT_BULLETS_LOADED, AS_INT, campingrifle_bulletcounter); + addstat(STAT_NEX_CHARGE, AS_FLOAT, nex_charge); + // g_movementspeed hack addstat(STAT_MOVEVARS_AIRSPEEDLIMIT_NONQW, AS_FLOAT, stat_sv_airspeedlimit_nonqw); addstat(STAT_MOVEVARS_AIRACCEL_QW, AS_FLOAT, stat_sv_airaccel_qw); @@ -703,6 +705,21 @@ void spawnfunc_worldspawn (void) localcmd("\n_sv_hook_gamestart ", GetGametype(), "\n"); + // fill sv_curl_serverpackages from .serverpackage files + if(cvar("sv_curl_serverpackages_auto")) + { + fd = search_begin("*.serverpackage", TRUE, FALSE); + s = ""; + if(fd >= 0) + { + j = search_getsize(fd); + for(i = 0; i < j; ++i) + s = strcat(s, " ", search_getfilename(fd, i)); + search_end(fd); + } + cvar_set("sv_curl_serverpackages", substring(s, 1, -1)); + } + world_initialized = 1; } @@ -1644,7 +1661,7 @@ float WinningCondition_Assault() TeamScore_AddToTeam(assault_attacker_team, ST_ASSAULT_OBJECTIVES, 666 - TeamScore_AddToTeam(assault_attacker_team, ST_ASSAULT_OBJECTIVES, 0)); - if(ent.cnt == 1) // this was the second round + if(ent.cnt == 1 || cvar("g_campaign")) // this was the second round { status = WINNING_YES; } diff --git a/qcsrc/server/ipban.qc b/qcsrc/server/ipban.qc index ebc58cea7..293a9b4e4 100644 --- a/qcsrc/server/ipban.qc +++ b/qcsrc/server/ipban.qc @@ -160,12 +160,15 @@ void OnlineBanList_URI_Get_Callback(float id, float status, string data) continue; l = strlen(ip); - for(j = 0; j < l; ++j) - if(strstrofs("0123456789.", substring(ip, j, 1), 0) == -1) - { - print("Invalid character ", substring(ip, j, 1), " in IP address ", ip, ". Skipping this ban.\n"); - goto skip; - } + if(l != 44) // length 44 is a cryptographic ID + { + for(j = 0; j < l; ++j) + if(strstrofs("0123456789.", substring(ip, j, 1), 0) == -1) + { + print("Invalid character ", substring(ip, j, 1), " in IP address ", ip, ". Skipping this ban.\n"); + goto skip; + } + } if(cvar("g_ban_sync_trusted_servers_verify")) if((strstrofs(strcat(";", OnlineBanList_Servers, ";"), strcat(";", serverip, ";"), 0) == -1)) @@ -243,9 +246,7 @@ string ban_ip1; string ban_ip2; string ban_ip3; string ban_ip4; -#ifdef UID -string ban_uid; -#endif +string ban_idfp; void Ban_SaveBans() { @@ -335,11 +336,16 @@ float Ban_GetClientIP(entity client) float i1, i2, i3, i4; string s; + if(client.crypto_keyfp) + ban_idfp = client.crypto_idfp; + else + ban_idfp = string_null; + s = client.netaddress; - + i1 = strstrofs(s, ".", 0); if(i1 < 0) - return FALSE; + goto ipv6; i2 = strstrofs(s, ".", i1 + 1); if(i2 < 0) return FALSE; @@ -348,22 +354,43 @@ float Ban_GetClientIP(entity client) return FALSE; i4 = strstrofs(s, ".", i3 + 1); if(i4 >= 0) - return FALSE; + s = substring(s, 0, i4); - ban_ip1 = substring(s, 0, i1); - ban_ip2 = substring(s, 0, i2); - ban_ip3 = substring(s, 0, i3); - ban_ip4 = strcat1(s); -#ifdef UID - ban_uid = client.uid; -#endif + ban_ip1 = substring(s, 0, i1); // 8 + ban_ip2 = substring(s, 0, i2); // 16 + ban_ip3 = substring(s, 0, i3); // 24 + ban_ip4 = strcat1(s); // 32 + return TRUE; + +:ipv6 + i1 = strstrofs(s, ":", 0); + if(i1 < 0) + return FALSE; + i1 = strstrofs(s, ":", i1 + 1); + if(i1 < 0) + return FALSE; + i2 = strstrofs(s, ":", i1 + 1); + if(i2 < 0) + return FALSE; + i3 = strstrofs(s, ":", i2 + 1); + if(i3 < 0) + return FALSE; + + ban_ip1 = strcat(substring(s, 0, i1), "::/32"); // 32 + ban_ip2 = strcat(substring(s, 0, i2), "::/48"); // 48 + ban_ip4 = strcat(substring(s, 0, i3), "::/64"); // 64 + + if(i3 - i2 > 3) // means there is more than 2 digits and a : in the range + ban_ip3 = strcat(substring(s, 0, i2), ":", substring(s, i2 + 1, i3 - i2 - 3), "00::/56"); + else + ban_ip3 = strcat(substring(s, 0, i2), ":0::/56"); return TRUE; } float Ban_IsClientBanned(entity client, float idx) { - float i, b, e; + float i, b, e, ipbanned; if(!ban_loaded) Ban_LoadBans(); if(!Ban_GetClientIP(client)) @@ -378,20 +405,22 @@ float Ban_IsClientBanned(entity client, float idx) b = idx; e = idx + 1; } + ipbanned = FALSE; for(i = b; i < e; ++i) { string s; if(time > ban_expire[i]) continue; s = ban_ip[i]; - if(ban_ip1 == s) return TRUE; - if(ban_ip2 == s) return TRUE; - if(ban_ip3 == s) return TRUE; - if(ban_ip4 == s) return TRUE; -#ifdef UID - if(ban_uid == s) return TRUE; -#endif + if(ban_ip1 == s) ipbanned = TRUE; + if(ban_ip2 == s) ipbanned = TRUE; + if(ban_ip3 == s) ipbanned = TRUE; + if(ban_ip4 == s) ipbanned = TRUE; + if(ban_idfp == s) return TRUE; } + if(ipbanned) + if(!cvar("g_banned_list_idmode") || !ban_idfp) + return TRUE; return FALSE; } @@ -535,12 +564,9 @@ void Ban_KickBanClient(entity client, float bantime, float masksize, string reas default: Ban_Insert(ban_ip4, bantime, reason, 1); break; -#ifdef UID - case 0: - Ban_Insert(ban_uid, bantime, reason, 1); - break; -#endif } + if(ban_idfp) + Ban_Insert(ban_idfp, bantime, reason, 1); /* * not needed, as we enforce the ban in Ban_Insert anyway // and kick him diff --git a/qcsrc/server/miscfunctions.qc b/qcsrc/server/miscfunctions.qc index 5b0fa2b8c..59428f65d 100644 --- a/qcsrc/server/miscfunctions.qc +++ b/qcsrc/server/miscfunctions.qc @@ -100,9 +100,9 @@ string GetAdvancedDeathReports(entity enPlayer) // Extra fragmessage information if(cvar("sv_fragmessage_information_ping")) { if(clienttype(enPlayer) == CLIENTTYPE_BOT) // Bots have no ping - strMessage = strcat(strMessage, "\n^7(^2Bot"); + strMessage = strcat(strMessage, " ^7(^2Bot"); else - strMessage = strcat(strMessage, "\n^7(Ping ", strPlayerPingColor, ftos(nPlayerPing), "ms"); + strMessage = strcat(strMessage, " ^7(Ping ", strPlayerPingColor, ftos(nPlayerPing), "ms"); if(cvar("sv_fragmessage_information_handicap")) if(cvar("sv_fragmessage_information_handicap") == 2) if(nPlayerHandicap <= 1) @@ -989,7 +989,7 @@ void readplayerstartcvars() if (g_weaponarena) { start_weapons = g_weaponarena; - if (g_weaponarena & (WEPBIT_GRENADE_LAUNCHER | WEPBIT_HAGAR | WEPBIT_ROCKET_LAUNCHER)) + if (g_weaponarena & (WEPBIT_GRENADE_LAUNCHER | WEPBIT_MINE_LAYER | WEPBIT_HAGAR | WEPBIT_ROCKET_LAUNCHER)) start_ammo_rockets = 999; if (g_weaponarena & WEPBIT_SHOTGUN) start_ammo_shells = 999; @@ -1668,6 +1668,7 @@ void precache() precache_sound ("weapons/weapon_switch.wav"); precache_sound ("weapons/weaponpickup.wav"); precache_sound ("weapons/unavailable.wav"); + precache_sound ("weapons/dryfire.wav"); if (g_grappling_hook) { precache_sound ("weapons/hook_fire.wav"); // hook diff --git a/qcsrc/server/monsters/mode_management.qc b/qcsrc/server/monsters/mode_management.qc index b9ebf9183..9f3770ff2 100644 --- a/qcsrc/server/monsters/mode_management.qc +++ b/qcsrc/server/monsters/mode_management.qc @@ -491,11 +491,11 @@ void() deathmatch7update = if (time >= 2) { spawnedexitmonsters = TRUE; - e = find(world, classname, "trigger_changelevel"); + e = find(world, classname, "target_changelevel"); while (e) { spawnmonster(e.origin + (e.mins + e.maxs) * 0.5, 8, 8, "monster_hellfish", monster_hellfish, '-16 -16 -24', '16 16 32'); - e = find(e, classname, "trigger_changelevel"); + e = find(e, classname, "target_changelevel"); } } return; diff --git a/qcsrc/server/mutators/gamemode_keyhunt.qc b/qcsrc/server/mutators/gamemode_keyhunt.qc index cdc4a076f..2b6f54780 100644 --- a/qcsrc/server/mutators/gamemode_keyhunt.qc +++ b/qcsrc/server/mutators/gamemode_keyhunt.qc @@ -750,7 +750,7 @@ void kh_Key_Spawn(entity initial_owner, float angle, float i) // runs every tim key.modelindex = kh_key_dropped; key.model = "key"; key.kh_dropperteam = 0; - key.dphitcontentsmask = DPCONTENTS_SOLID | DPCONTENTS_BODY | DPCONTENTS_PLAYERCLIP; + key.dphitcontentsmask = DPCONTENTS_SOLID | DPCONTENTS_BODY | DPCONTENTS_PLAYERCLIP | DPCONTENTS_BOTCLIP; setsize(key, KH_KEY_MIN, KH_KEY_MAX); key.colormod = TeamColor(initial_owner.team) * KH_KEY_BRIGHTNESS; key.reset = key_reset; diff --git a/qcsrc/server/pathlib/debug.qc b/qcsrc/server/pathlib/debug.qc index bad8516de..64ce9da02 100644 --- a/qcsrc/server/pathlib/debug.qc +++ b/qcsrc/server/pathlib/debug.qc @@ -1,8 +1,9 @@ +#ifdef TURRET_DEBUG void mark_error(vector where,float lifetime); void mark_info(vector where,float lifetime); entity mark_misc(vector where,float lifetime); - +#endif void pathlib_showpath(entity start) { @@ -23,7 +24,9 @@ void path_dbg_think() void __showpath2_think() { - mark_info(self.origin,1); + #ifdef TURRET_DEBUG + mark_info(self.origin,1); + #endif if(self.path_next) { self.path_next.think = __showpath2_think; diff --git a/qcsrc/server/pathlib/main.qc b/qcsrc/server/pathlib/main.qc index fbff82e9e..9658747ee 100644 --- a/qcsrc/server/pathlib/main.qc +++ b/qcsrc/server/pathlib/main.qc @@ -28,7 +28,9 @@ entity pathlib_mknode(vector where,entity parent) node = pathlib_nodeatpoint(where); if(node) { + #ifdef TURRET_DEBUG mark_error(where, 60); + #endif return node; } diff --git a/qcsrc/server/race.qc b/qcsrc/server/race.qc index 4dff570d3..2f1588981 100644 --- a/qcsrc/server/race.qc +++ b/qcsrc/server/race.qc @@ -101,9 +101,7 @@ void race_InitSpectator() string rr; float grecordtime[RANKINGS_CNT]; string grecordholder[RANKINGS_CNT]; -#ifdef UID string grecorduid[RANKINGS_CNT]; -#endif float worst_time; // last ranked time float have_recs; // have we already read the records from the database before? float race_GetTime(float pos) { @@ -117,15 +115,11 @@ float race_GetTime(float pos) { for(i=0;i=0;--i) + if(grecorduid[i] == myuid) + return i+1; + } for (i=RANKINGS_CNT-1;i>=0;--i) - if(grecorduid[i] == myuid) - return i+1; - for (i=RANKINGS_CNT-1;i>=0;--i) - if(grecordholder[i] == net_name) - return i+1; - return 0; -} -#endif - -float race_CheckName(string net_name) { // Does the name already exist in rankings? In that case, where? (otherwise 0) - float i; - for (i=RANKINGS_CNT-1;i>=0;--i) - if(grecordholder[i] == net_name) - return i+1; + if(!grecorduid[i]) + if(grecordholder[i] == net_name) + return i+1; return 0; } @@ -224,11 +212,7 @@ string race_PlaceName(float pos) { void race_SetTime(entity e, float t, float match_rec) { float pos, prevpos; pos = race_GetPos(t); -#ifdef UID - prevpos = race_CheckUID(e.uid, e.netname); -#else - prevpos = race_CheckName(e.netname); -#endif + prevpos = race_CheckUID(e.crypto_idfp, e.netname); float oldrec; string recorddifference; @@ -254,37 +238,29 @@ void race_SetTime(entity e, float t, float match_rec) { for (i=prevpos-1;i>pos-1;--i) { db_put(ServerProgsDB, strcat(GetMapname(), rr, "time", ftos(i)), ftos(grecordtime[i-1])); db_put(ServerProgsDB, strcat(GetMapname(), rr, "netname", ftos(i)), grecordholder[i-1]); -#ifdef UID - db_put(ServerProgsDB, strcat(GetMapname(), rr, "uid", ftos(i)), grecorduid[i-1]); -#endif + db_put(ServerProgsDB, strcat(GetMapname(), rr, "crypto_idfp", ftos(i)), grecorduid[i-1]); grecordtime[i] = grecordtime[i-1]; if (grecordholder[i]) strunzone(grecordholder[i]); grecordholder[i] = strzone(grecordholder[i-1]); -#ifdef UID if (grecorduid[i]) strunzone(grecorduid[i]); grecorduid[i] = strzone(grecorduid[i-1]); -#endif } } else { // player has no ranked record yet for (i=RANKINGS_CNT-1;i>pos-1;--i) { db_put(ServerProgsDB, strcat(GetMapname(), rr, "time", ftos(i)), ftos(grecordtime[i-1])); db_put(ServerProgsDB, strcat(GetMapname(), rr, "netname", ftos(i)), grecordholder[i-1]); -#ifdef UID - db_put(ServerProgsDB, strcat(GetMapname(), rr, "uid", ftos(i)), grecorduid[i-1]); -#endif + db_put(ServerProgsDB, strcat(GetMapname(), rr, "crypto_idfp", ftos(i)), grecorduid[i-1]); grecordtime[i] = grecordtime[i-1]; if (grecordholder[i]) strunzone(grecordholder[i]); grecordholder[i] = strzone(grecordholder[i-1]); -#ifdef UID if (grecorduid[i]) strunzone(grecorduid[i]); grecorduid[i] = strzone(grecorduid[i-1]); -#endif } } @@ -292,39 +268,31 @@ void race_SetTime(entity e, float t, float match_rec) { if (pos == 1) { db_put(ServerProgsDB, strcat(GetMapname(), rr, "time"), ftos(t)); db_put(ServerProgsDB, strcat(GetMapname(), rr, "netname"), e.netname); -#ifdef UID - db_put(ServerProgsDB, strcat(GetMapname(), rr, "uid"), e.uid); -#endif + db_put(ServerProgsDB, strcat(GetMapname(), rr, "crypto_idfp"), e.crypto_idfp); grecordtime[0] = t; if (grecordholder[0]) strunzone(grecordholder[0]); grecordholder[0] = strzone(e.netname); -#ifdef UID if (grecorduid[0]) strunzone(grecorduid[0]); - grecorduid[0] = strzone(e.uid); -#endif + grecorduid[0] = strzone(e.crypto_idfp); write_recordmarker(e, time - TIME_DECODE(t), TIME_DECODE(t)); race_send_recordtime(MSG_ALL); } else { db_put(ServerProgsDB, strcat(GetMapname(), rr, "time", ftos(pos-1)), ftos(t)); db_put(ServerProgsDB, strcat(GetMapname(), rr, "netname", ftos(pos-1)), e.netname); -#ifdef UID - db_put(ServerProgsDB, strcat(GetMapname(), rr, "uid", ftos(pos-1)), e.uid); -#endif + db_put(ServerProgsDB, strcat(GetMapname(), rr, "crypto_idfp", ftos(pos-1)), e.crypto_idfp); grecordtime[pos-1] = t; if (grecordholder[pos-1]) strunzone(grecordholder[pos-1]); grecordholder[pos-1] = strzone(e.netname); -#ifdef UID if (grecorduid[pos-1]) strunzone(grecorduid[pos-1]); - grecorduid[pos-1] = strzone(e.uid); -#endif + grecorduid[pos-1] = strzone(e.crypto_idfp); } if (pos == RANKINGS_CNT) @@ -368,53 +336,41 @@ void race_DeleteTime(float pos) { if (i == 0) { db_put(ServerProgsDB, strcat(GetMapname(), rr, "time"), ftos(grecordtime[1])); db_put(ServerProgsDB, strcat(GetMapname(), rr, "netname"), grecordholder[1]); -#ifdef UID - db_put(ServerProgsDB, strcat(GetMapname(), rr, "uid"), grecorduid[1]); -#endif + db_put(ServerProgsDB, strcat(GetMapname(), rr, "crypto_idfp"), grecorduid[1]); grecordtime[0] = grecordtime[1]; if (grecordholder[i]) strunzone(grecordholder[0]); grecordholder[0] = strzone(grecordholder[1]); -#ifdef UID if (grecorduid[i]) strunzone(grecorduid[0]); grecorduid[0] = strzone(grecorduid[1]); -#endif } else if (i == RANKINGS_CNT-1) { db_put(ServerProgsDB, strcat(GetMapname(), rr, "time", ftos(i)), string_null); db_put(ServerProgsDB, strcat(GetMapname(), rr, "netname", ftos(i)), string_null); -#ifdef UID - db_put(ServerProgsDB, strcat(GetMapname(), rr, "uid", ftos(i)), string_null); -#endif + db_put(ServerProgsDB, strcat(GetMapname(), rr, "crypto_idfp", ftos(i)), string_null); grecordtime[i] = 0; if (grecordholder[i]) strunzone(grecordholder[i]); grecordholder[i] = string_null; -#ifdef UID if (grecorduid[i]) strunzone(grecorduid[i]); grecorduid[i] = string_null; -#endif } else { db_put(ServerProgsDB, strcat(GetMapname(), rr, "time", ftos(i)), ftos(grecordtime[i+1])); db_put(ServerProgsDB, strcat(GetMapname(), rr, "netname", ftos(i)), grecordholder[i+1]); -#ifdef UID - db_put(ServerProgsDB, strcat(GetMapname(), rr, "uid", ftos(i)), grecorduid[i+1]); -#endif + db_put(ServerProgsDB, strcat(GetMapname(), rr, "crypto_idfp", ftos(i)), grecorduid[i+1]); grecordtime[i] = grecordtime[i+1]; if (grecordholder[i]) strunzone(grecordholder[i]); grecordholder[i] = strzone(grecordholder[i+1]); -#ifdef UID if (grecorduid[i]) strunzone(grecorduid[i]); grecorduid[i] = strzone(grecorduid[i+1]); -#endif } } diff --git a/qcsrc/server/sv_main.qc b/qcsrc/server/sv_main.qc index 44a47c95d..3b7d77d58 100644 --- a/qcsrc/server/sv_main.qc +++ b/qcsrc/server/sv_main.qc @@ -77,6 +77,10 @@ void CreatureFrame (void) if (dm > 0) { Damage (self, world, world, dm, DEATH_FALL, self.origin, '0 0 0'); + // this must be allowed to cut the normal pain sounds (played after them and on the same channel) + // there's no way to detect falling damage and prevent the pain sounds for this to be played instead + if(self.health > 0) + PlayerSound(playersound_fall, CHAN_PAIN, VOICETYPE_PLAYERSOUND); } } diff --git a/qcsrc/server/t_items.qc b/qcsrc/server/t_items.qc index c291e79a0..ba0cb8bb3 100644 --- a/qcsrc/server/t_items.qc +++ b/qcsrc/server/t_items.qc @@ -233,8 +233,13 @@ void Item_ScheduleRespawnIn(entity e, float t) void Item_ScheduleRespawn(entity e) { - Item_Show(e, 0); - Item_ScheduleRespawnIn(e, ITEM_RESPAWNTIME(e)); + if(e.respawntime > 0) + { + Item_Show(e, 0); + Item_ScheduleRespawnIn(e, ITEM_RESPAWNTIME(e)); + } + else // if respawntime is -1, this item does not respawn + Item_Show(e, -1); } void Item_ScheduleInitialRespawn(entity e) @@ -1047,7 +1052,7 @@ void weapon_defaultspawnfunc(float wpn) { ammofield = Item_CounterField(j); if(!self.ammofield) - self.ammofield = cvar(strcat("g_pickup_", Item_CounterFieldName(j))); + self.ammofield = cvar(strcat("g_pickup_", Item_CounterFieldName(j), "_weapon")); } } } @@ -1192,7 +1197,7 @@ void spawnfunc_item_armor_small (void) { self.max_armorvalue = g_pickup_armorsmall_max; if(!self.pickup_anyway) self.pickup_anyway = g_pickup_armorsmall_anyway; - StartItem ("models/items/g_a1.md3", "misc/armor1.wav", g_pickup_respawntime_short, g_pickup_respawntimejitter_short, "5 Armor", IT_ARMOR_SHARD, 0, 0, commodity_pickupevalfunc, BOT_PICKUP_RATING_LOW); + StartItem ("models/items/item_armor_small.md3", "misc/armor1.wav", g_pickup_respawntime_short, g_pickup_respawntimejitter_short, "5 Armor", IT_ARMOR_SHARD, 0, 0, commodity_pickupevalfunc, BOT_PICKUP_RATING_LOW); } void spawnfunc_item_armor_medium (void) { @@ -1202,7 +1207,7 @@ void spawnfunc_item_armor_medium (void) { self.max_armorvalue = g_pickup_armormedium_max; if(!self.pickup_anyway) self.pickup_anyway = g_pickup_armormedium_anyway; - StartItem ("models/items/g_armormedium.md3", "misc/armor10.wav", g_pickup_respawntime_medium, g_pickup_respawntimejitter_medium, "25 Armor", IT_ARMOR, 0, 0, commodity_pickupevalfunc, BOT_PICKUP_RATING_MID); + StartItem ("models/items/item_armor_medium.md3", "misc/armor10.wav", g_pickup_respawntime_medium, g_pickup_respawntimejitter_medium, "25 Armor", IT_ARMOR, 0, 0, commodity_pickupevalfunc, BOT_PICKUP_RATING_MID); } void spawnfunc_item_armor_big (void) { @@ -1212,7 +1217,7 @@ void spawnfunc_item_armor_big (void) { self.max_armorvalue = g_pickup_armorbig_max; if(!self.pickup_anyway) self.pickup_anyway = g_pickup_armorbig_anyway; - StartItem ("models/items/g_a50.md3", "misc/armor17_5.wav", g_pickup_respawntime_long, g_pickup_respawntimejitter_long, "50 Armor", IT_ARMOR, 0, 0, commodity_pickupevalfunc, 20000); + StartItem ("models/items/item_armor_big.md3", "misc/armor17_5.wav", g_pickup_respawntime_long, g_pickup_respawntimejitter_long, "50 Armor", IT_ARMOR, 0, 0, commodity_pickupevalfunc, 20000); } void spawnfunc_item_armor_large (void) { @@ -1222,7 +1227,7 @@ void spawnfunc_item_armor_large (void) { self.max_armorvalue = g_pickup_armorlarge_max; if(!self.pickup_anyway) self.pickup_anyway = g_pickup_armorlarge_anyway; - StartItem ("models/items/g_a25.md3", "misc/armor25.wav", g_pickup_respawntime_long, g_pickup_respawntimejitter_long, "100 Armor", IT_ARMOR, 0, 0, commodity_pickupevalfunc, BOT_PICKUP_RATING_HIGH); + StartItem ("models/items/item_armor_large.md3", "misc/armor25.wav", g_pickup_respawntime_long, g_pickup_respawntimejitter_long, "100 Armor", IT_ARMOR, 0, 0, commodity_pickupevalfunc, BOT_PICKUP_RATING_HIGH); } void spawnfunc_item_health_small (void) { diff --git a/qcsrc/server/t_jumppads.qc b/qcsrc/server/t_jumppads.qc index 9bb8f7c92..df5788f4c 100644 --- a/qcsrc/server/t_jumppads.qc +++ b/qcsrc/server/t_jumppads.qc @@ -127,6 +127,9 @@ vector trigger_push_calculatevelocity(vector org, entity tgt, float ht) void trigger_push_touch() { + if (self.active == ACTIVE_NOT) + return; + // FIXME: add a .float for whether an entity should be tossed by jumppads if (!other.iscreature) if (other.classname != "corpse") @@ -229,7 +232,6 @@ void trigger_push_touch() }; .vector dest; - void trigger_push_findtarget() { local entity e; @@ -287,7 +289,8 @@ void spawnfunc_trigger_push() SetMovedir (); EXACTTRIGGER_INIT; - + + self.active = ACTIVE_ACTIVE; self.use = trigger_push_use; self.touch = trigger_push_touch; diff --git a/qcsrc/server/t_plats.qc b/qcsrc/server/t_plats.qc index ad80e7f99..d338cf637 100644 --- a/qcsrc/server/t_plats.qc +++ b/qcsrc/server/t_plats.qc @@ -327,6 +327,25 @@ void spawnfunc_func_train() // TODO make a reset function for this one }; +void func_rotating_setactive(float astate) +{ + + if (astate == ACTIVE_TOGGLE) + { + if(self.active == ACTIVE_ACTIVE) + self.active = ACTIVE_NOT; + else + self.active = ACTIVE_ACTIVE; + } + else + self.active = astate; + + if(self.active == ACTIVE_NOT) + self.avelocity = '0 0 0'; + else + self.avelocity = self.pos1; +} + /*QUAKED spawnfunc_func_rotating (0 .5 .8) ? - - X_AXIS Y_AXIS Brush model that spins in place on one axis (default Z). speed : speed to rotate (in degrees per second) @@ -342,6 +361,10 @@ void spawnfunc_func_rotating() precache_sound(self.noise); ambientsound(self.origin, self.noise, VOL_BASE, ATTN_IDLE); } + + self.active = ACTIVE_ACTIVE; + self.setactive = func_rotating_setactive; + if (!self.speed) self.speed = 100; // FIXME: test if this turns the right way, then remove this comment (negate as needed) @@ -353,7 +376,9 @@ void spawnfunc_func_rotating() // FIXME: test if this turns the right way, then remove this comment (negate as needed) else // Z self.avelocity = '0 1 0' * self.speed; - + + self.pos1 = self.avelocity; + if(self.dmg & (!self.message)) self.message = " was squished"; if(self.dmg && (!self.message2)) @@ -383,11 +408,19 @@ void func_bobbing_controller_think() { local vector v; self.nextthink = time + 0.1; + + if not (self.owner.active == ACTIVE_ACTIVE) + { + self.owner.velocity = '0 0 0'; + return; + } + // calculate sinewave using makevectors makevectors((self.nextthink * self.owner.cnt + self.owner.phase * 360) * '0 1 0'); v = self.owner.destvec + self.owner.movedir * v_forward_y; - // * 10 so it will arrive in 0.1 sec - self.owner.velocity = (v - self.owner.origin) * 10; + if(self.owner.classname == "func_bobbing") // don't brake stuff if the func_bobbing was killtarget'ed + // * 10 so it will arrive in 0.1 sec + self.owner.velocity = (v - self.owner.origin) * 10; }; void bobbing_blocked() @@ -422,6 +455,8 @@ void spawnfunc_func_bobbing() // time scale to get degrees self.cnt = 360 / self.speed; + self.active = ACTIVE_ACTIVE; + // damage when blocked self.blocked = bobbing_blocked; if(self.dmg & (!self.message)) @@ -526,6 +561,10 @@ void button_use() // dprint(activator.classname); // dprint(" triggered a button\n"); // } + + if not (self.active == ACTIVE_ACTIVE) + return; + self.enemy = activator; button_fire (); }; @@ -615,6 +654,8 @@ void spawnfunc_func_button() if(self.noise != "") precache_sound(self.noise); + self.active = ACTIVE_ACTIVE; + self.pos1 = self.origin; self.pos2 = self.pos1 + self.movedir*(fabs(self.movedir*self.size) - self.lip); self.flags |= FL_NOTARGET; @@ -1636,6 +1677,12 @@ void func_fourier_controller_think() float n, i, t; self.nextthink = time + 0.1; + if not (self.owner.active == ACTIVE_ACTIVE) + { + self.owner.velocity = '0 0 0'; + return; + } + n = floor((tokenize_console(self.owner.netname)) / 5); t = self.nextthink * self.owner.cnt + self.owner.phase * 360; @@ -1648,8 +1695,9 @@ void func_fourier_controller_think() v = v + ('1 0 0' * stof(argv(i*5+2)) + '0 1 0' * stof(argv(i*5+3)) + '0 0 1' * stof(argv(i*5+4))) * self.owner.height * v_forward_y; } - // * 10 so it will arrive in 0.1 sec - self.owner.velocity = (v - self.owner.origin) * 10; + if(self.owner.classname == "func_fourier") // don't brake stuff if the func_fourier was killtarget'ed + // * 10 so it will arrive in 0.1 sec + self.owner.velocity = (v - self.owner.origin) * 10; }; void spawnfunc_func_fourier() @@ -1683,6 +1731,8 @@ void spawnfunc_func_fourier() if not(InitMovingBrushTrigger()) return; + self.active = ACTIVE_ACTIVE; + // wait for targets to spawn controller = spawn(); controller.classname = "func_fourier_controller"; @@ -1759,7 +1809,15 @@ vector func_vectormamamam_origin(entity o, float t) void func_vectormamamam_controller_think() { self.nextthink = time + 0.1; - self.owner.velocity = (self.owner.destvec + func_vectormamamam_origin(self.owner, 0.1) - self.owner.origin) * 10; + + if not (self.owner.active == ACTIVE_ACTIVE) + { + self.owner.velocity = '0 0 0'; + return; + } + + if(self.owner.classname == "func_vectormamamam") // don't brake stuff if the func_vectormamamam was killtarget'ed + self.owner.velocity = (self.owner.destvec + func_vectormamamam_origin(self.owner, 0.1) - self.owner.origin) * 10; } void func_vectormamamam_findtarget() @@ -1843,5 +1901,7 @@ void spawnfunc_func_vectormamamam() // Savage: Reduce bandwith, critical on e.g. nexdm02 self.effects |= EF_LOWPRECISION; + self.active = ACTIVE_ACTIVE; + InitializeEntity(self, func_vectormamamam_findtarget, INITPRIO_FINDTARGET); } diff --git a/qcsrc/server/t_quake3.qc b/qcsrc/server/t_quake3.qc index 52214c2a6..cffe88bd7 100644 --- a/qcsrc/server/t_quake3.qc +++ b/qcsrc/server/t_quake3.qc @@ -5,42 +5,42 @@ // NOTE: for best experience, you need to swap MGs with SGs in the map or it won't have a MG // SG -> SG -void spawnfunc_ammo_shells() { spawnfunc_item_shells(); } - -// MG -> MG -void spawnfunc_weapon_machinegun() { spawnfunc_weapon_uzi(); } -void spawnfunc_ammo_bullets() { spawnfunc_item_bullets(); } - -// GL -> Mortar -void spawnfunc_ammo_grenades() { spawnfunc_item_rockets(); } - -// LG -> Electro -void spawnfunc_weapon_lightning() { spawnfunc_weapon_electro(); } -void spawnfunc_ammo_lightning() { spawnfunc_item_cells(); } - -// Plasma -> Hagar -void spawnfunc_weapon_plasmagun() { spawnfunc_weapon_hagar(); } -void spawnfunc_ammo_cells() { spawnfunc_item_rockets(); } - -// Rail -> Nex -void spawnfunc_weapon_railgun() { spawnfunc_weapon_nex(); } -void spawnfunc_ammo_slugs() { spawnfunc_item_cells(); } - -// BFG -> Crylink -void spawnfunc_weapon_bfg() { spawnfunc_weapon_crylink(); } -void spawnfunc_ammo_bfg() { spawnfunc_item_cells(); } +void spawnfunc_ammo_shells() { spawnfunc_item_shells(); } + +// MG -> MG +void spawnfunc_weapon_machinegun() { spawnfunc_weapon_uzi(); } +void spawnfunc_ammo_bullets() { spawnfunc_item_bullets(); } + +// GL -> Mortar +void spawnfunc_ammo_grenades() { spawnfunc_item_rockets(); } + +// LG -> Electro +void spawnfunc_weapon_lightning() { spawnfunc_weapon_electro(); } +void spawnfunc_ammo_lightning() { spawnfunc_item_cells(); } + +// Plasma -> Hagar +void spawnfunc_weapon_plasmagun() { spawnfunc_weapon_hagar(); } +void spawnfunc_ammo_cells() { spawnfunc_item_rockets(); } + +// Rail -> Rifle +void spawnfunc_weapon_railgun() { spawnfunc_weapon_campingrifle(); } +void spawnfunc_ammo_slugs() { spawnfunc_item_bullets(); } + +// BFG -> Crylink +void spawnfunc_weapon_bfg() { spawnfunc_weapon_crylink(); } +void spawnfunc_ammo_bfg() { spawnfunc_item_cells(); } // RL -> RL -void spawnfunc_ammo_rockets() { spawnfunc_item_rockets(); } - -// Armor -void spawnfunc_item_armor_body() { spawnfunc_item_armor_large(); } -void spawnfunc_item_armor_combat() { spawnfunc_item_armor_big(); } -void spawnfunc_item_armor_shard() { spawnfunc_item_armor_small(); } -void spawnfunc_item_enviro() { spawnfunc_item_invincible(); } +void spawnfunc_ammo_rockets() { spawnfunc_item_rockets(); } + +// Armor +void spawnfunc_item_armor_body() { spawnfunc_item_armor_large(); } +void spawnfunc_item_armor_combat() { spawnfunc_item_armor_big(); } +void spawnfunc_item_armor_shard() { spawnfunc_item_armor_small(); } +void spawnfunc_item_enviro() { spawnfunc_item_invincible(); } // weapon remove ent from defrag -void spawnfunc_target_init() +void spawnfunc_target_init() { self.spawnflags = 0; // remove all weapons except the ones listed below self.netname = "laser uzi"; // keep these weapons through the remove trigger diff --git a/qcsrc/server/t_teleporters.qc b/qcsrc/server/t_teleporters.qc index 795697dcd..eba0ea068 100644 --- a/qcsrc/server/t_teleporters.qc +++ b/qcsrc/server/t_teleporters.qc @@ -29,13 +29,14 @@ void trigger_teleport_use() float check_tdeath(entity player, vector org, vector telefragmin, vector telefragmax) { - TDEATHLOOP(org) + if (player.classname == "player" && player.health >= 1) { - if ((player.classname == "player") && (player.health >= 1)) + TDEATHLOOP(org) { - if(head.classname == "player") - if(head.health >= 1) - return 1; + if not(teamplay && cvar("g_telefrags_teamplay") && head.team == player.team) + if(head.classname == "player") + if(head.health >= 1) + return 1; } } return 0; @@ -45,15 +46,16 @@ void tdeath(entity player, entity teleporter, entity telefragger, vector telefra { TDEATHLOOP(player.origin) { - if ((player.classname == "player") && (player.health >= 1)) + if (player.classname == "player" && player.health >= 1) { - if(head.classname == "player") - if(head.health >= 1) - ++tdeath_hit; - Damage (head, teleporter, telefragger, 10000, DEATH_TELEFRAG, head.origin, '0 0 0'); + if not(teamplay && cvar("g_telefrags_teamplay") && head.team == player.team) + { + if(head.classname == "player") + if(head.health >= 1) + ++tdeath_hit; + Damage (head, teleporter, telefragger, 10000, DEATH_TELEFRAG, head.origin, '0 0 0'); + } } - else if (telefragger.health < 1) // corpses gib - Damage (head, teleporter, telefragger, 10000, DEATH_TELEFRAG, head.origin, '0 0 0'); else // dead bodies and monsters gib themselves instead of telefragging Damage (telefragger, teleporter, telefragger, 10000, DEATH_TELEFRAG, telefragger.origin, '0 0 0'); } @@ -68,9 +70,10 @@ void spawn_tdeath(vector v0, entity e, vector v) #define TELEPORT_FLAG_SOUND 1 #define TELEPORT_FLAG_PARTICLES 2 #define TELEPORT_FLAG_TDEATH 4 +#define TELEPORT_FLAG_FORCE_TDEATH 8 #define TELEPORT_FLAGS_WARPZONE 0 -#define TELEPORT_FLAGS_PORTAL (TELEPORT_FLAG_SOUND | TELEPORT_FLAG_PARTICLES) +#define TELEPORT_FLAGS_PORTAL (TELEPORT_FLAG_SOUND | TELEPORT_FLAG_PARTICLES | TELEPORT_FLAG_TDEATH | TELEPORT_FLAG_FORCE_TDEATH) #define TELEPORT_FLAGS_TELEPORTER (TELEPORT_FLAG_SOUND | TELEPORT_FLAG_PARTICLES | TELEPORT_FLAG_TDEATH) void TeleportPlayer(entity teleporter, entity player, vector to, vector to_angles, vector to_velocity, vector telefragmin, vector telefragmax, float tflags) { @@ -112,7 +115,7 @@ void TeleportPlayer(entity teleporter, entity player, vector to, vector to_angle if(player.classname == "player") { if(tflags & TELEPORT_FLAG_TDEATH) - if(player.takedamage && player.deadflag == DEAD_NO && !g_race && !g_cts && cvar("g_telefrags")) + if(player.takedamage && player.deadflag == DEAD_NO && !g_race && !g_cts && (cvar("g_telefrags") || (tflags & TELEPORT_FLAG_FORCE_TDEATH))) tdeath(player, teleporter, telefragger, telefragmin, telefragmax); // player no longer is on ground @@ -132,8 +135,7 @@ void TeleportPlayer(entity teleporter, entity player, vector to, vector to_angle player.pushltime = 0; } - if(player.isbot) - player.lastteleporttime = time; + player.lastteleporttime = time; // stop player name display { @@ -150,7 +152,11 @@ void Teleport_Touch (void) entity oldself, e; vector o; float p; + string s; + if (self.active != ACTIVE_ACTIVE) + return; + if (other.health < 1) return; if not(other.flags & FL_CLIENT) // FIXME: Make missiles firable through the teleport too @@ -206,14 +212,15 @@ void Teleport_Touch (void) o = e.origin + '0 0 1' * (1 - other.mins_z - 24); TeleportPlayer(self, other, o, e.mangle, v_forward * vlen(other.velocity), '0 0 0', '0 0 0', TELEPORT_FLAGS_TELEPORTER); - if(e.target) - { - oldself = self; - activator = other; - self = e; - SUB_UseTargets(); - self = oldself; - } + activator = other; + s = self.target; self.target = string_null; + SUB_UseTargets(); + if not(self.target) self.target = s; + + oldself = self; + self = e; + SUB_UseTargets(); + self = oldself; } void spawnfunc_info_teleport_destination (void) @@ -288,7 +295,9 @@ void spawnfunc_trigger_teleport (void) self.angles = '0 0 0'; EXACTTRIGGER_INIT; - + + self.active = ACTIVE_ACTIVE; + self.use = trigger_teleport_use; // this must be called to spawn the teleport waypoints for bots @@ -308,5 +317,7 @@ void WarpZone_PostTeleportPlayer_Callback(entity pl) { // reset tracking of oldvelocity for impact damage (sudden velocity changes) pl.oldvelocity = pl.velocity; + // reset teleport time tracking too (or multijump can cause insane speeds) + pl.lastteleporttime = time; } } diff --git a/qcsrc/server/teamplay.qc b/qcsrc/server/teamplay.qc index 0798b29b2..912e22c24 100644 --- a/qcsrc/server/teamplay.qc +++ b/qcsrc/server/teamplay.qc @@ -16,6 +16,8 @@ float IsTeamBalanceForced() return 0; if(cvar("g_campaign")) return 0; + if(cvar("bot_vs_human") && (c3==-1 && c4==-1)) + return 0; if(!cvar("g_balance_teams_force")) return -1; return 1; @@ -511,8 +513,6 @@ void PrintWelcomeMessage(entity pl) modifications = strcat(modifications, ", Low gravity"); if(g_cloaked) modifications = strcat(modifications, ", Cloaked"); - if(g_footsteps) - modifications = strcat(modifications, ", Steps"); if(g_grappling_hook) modifications = strcat(modifications, ", Hook"); if(g_laserguided_missile) @@ -694,7 +694,7 @@ void CheckAllowedTeams (entity for_whom) } // TODO: Balance quantity of bots across > 2 teams when bot_vs_human is set (and remove next line) - if(c3==-1&&c4==-1) + if(c3==-1 && c4==-1) if(cvar("bot_vs_human") && for_whom) { if(cvar("bot_vs_human") > 0) @@ -721,6 +721,7 @@ float PlayerValue(entity p) if(IsTeamBalanceForced() == 1) return 1; return 1; + // FIXME: it always returns 1... } // c1...c4 should be set to -1 (not allowed) or 0 (allowed). @@ -799,7 +800,7 @@ float FindSmallestTeam(entity pl, float ignore_pl) if(c4 >= 0) totalteams = totalteams + 1; - if(cvar("bot_vs_human")) + if(cvar("bot_vs_human") && totalteams == 1) totalteams += 1; if(totalteams <= 1) @@ -879,6 +880,33 @@ float JoinBestTeam(entity pl, float only_return_best, float forcebestteam) // find out what teams are available CheckAllowedTeams(pl); + // if we want the player in a certain team for campaign, force him there + if(cvar("g_campaign")) + if(clienttype(pl) == CLIENTTYPE_REAL) // only players, not bots + { + switch(cvar("g_campaign_forceteam")) + { + case 1: + SetPlayerColors(pl, COLOR_TEAM1 - 1); + LogTeamchange(pl.playerid, pl.team, 2); + return COLOR_TEAM1; + case 2: + SetPlayerColors(pl, COLOR_TEAM2 - 1); + LogTeamchange(pl.playerid, pl.team, 2); + return COLOR_TEAM2; + case 3: + SetPlayerColors(pl, COLOR_TEAM3 - 1); + LogTeamchange(pl.playerid, pl.team, 2); + return COLOR_TEAM3; + case 4: + SetPlayerColors(pl, COLOR_TEAM4 - 1); + LogTeamchange(pl.playerid, pl.team, 2); + return COLOR_TEAM4; + default: + break; + } + } + // if we don't care what team he ends up on, put him on whatever team he entered as. // if he's not on a valid team, then let other code put him on the smallest team if(!forcebestteam) @@ -911,7 +939,7 @@ float JoinBestTeam(entity pl, float only_return_best, float forcebestteam) smallest = FindSmallestTeam(pl, TRUE); - if(!only_return_best) + if(!only_return_best && !pl.bot_forced_team) { TeamchangeFrags(self); if(smallest == 1) diff --git a/qcsrc/server/tturrets/include/turrets_early.qh b/qcsrc/server/tturrets/include/turrets_early.qh index fa07f867f..8cdd0f509 100644 --- a/qcsrc/server/tturrets/include/turrets_early.qh +++ b/qcsrc/server/tturrets/include/turrets_early.qh @@ -74,7 +74,7 @@ vector real_origin(entity ent); /// Dont aim. #define TFL_AIM_NO 1 /// Go for ground, not direct hit -#define TFL_AIM_GROUND 2 +//#define TFL_AIM_GROUND 2 /// Go for ground, not direct hit, but only if target is on ground. #define TFL_AIM_GROUND2 4 /// Use balistic aim. FIXME: not implemented @@ -87,8 +87,8 @@ vector real_origin(entity ent); #define TFL_AIM_INFRONT 64 /// Aim slightly behind target #define TFL_AIM_BEHIND 128 -/// blend real and predicted z positions. (fake bounce prediction) -#define TFL_AIM_ZEASE 256 +/// blend real and predicted z positions. (fake bounce prediction) +// #define TFL_AIM_ZEASE 256 /// Try to do real prediction of targets z pos at impact. #define TFL_AIM_ZPREDICT 512 /// Simply aim at target's current location @@ -266,9 +266,6 @@ vector real_origin(entity ent); /// on/off toggle. .float tur_active; -// Aim from this point, -//.vector tur_aimorg; - /// and shoot from here. (can be non constant, think MLRS) .vector tur_shotorg; @@ -323,8 +320,6 @@ vector real_origin(entity ent); .float target_range; /// Dont consider targets closer then .float target_range_min; -// Engage fire routine on targets within -//.float target_range_fire; // no practical use aymore, work with target_range insted. /// Targets closer to this are prefered .float target_range_optimal; @@ -353,8 +348,6 @@ vector real_origin(entity ent); */ /// Maximum offset between impact and aim spot to fire .float aim_firetolerance_dist; -// Maximum angular offset between head and aimspot to fire -//.float aim_firetolerance_angle; /// How fast can i rotate/pitch (per second in stepmotor mode, base force in smooth modes) .float aim_speed; /// cant aim higher/lower then this @@ -397,16 +390,12 @@ void turret_fire(); .void() turret_firefunc; /// prefire checks go here. return 1 to go bang, 0 not to. .float() turret_firecheckfunc; -// Execure BEFORE main ai loop. return 0 to cancel any following proccessing. -//.float() turret_prethink; /// Execure AFTER main AI loop .void() turret_postthink; /// Add a target .float(entity e_target,entity e_sender) turret_addtarget; -//.float call_diehook; -//.float call_respwnhook; .void() turret_diehook; .void() turret_respawnhook; @@ -421,27 +410,6 @@ void turret_fire(); .float(float event_id) turret_eventhook; */ -/* -* Some turrets need other aimsystems then other. -* This should return the place to aim at, not acctualy turn or -* pitch anyting. -* -* use turret_stdproc_aim* or Make your own. -* Make sure you update tur_enemy_dist and tur_enemy_adist -* with the apropriate info, if you do. - -removed. -*/ -// function used to aim, usualy turret_stdproc_aim_generic -//.vector() turret_aim; - -/* -* This is where the acctual turret turning should take place -* Use turret_stdproc_track or make your own. -wkacked to save mem. -*/ -// Function used to turn and pitch the .tur_head usualy turret_stdproc_track -//.void() turret_track; /* * Target selection, preferably but not nessesarely @@ -450,41 +418,11 @@ wkacked to save mem. /// Function to use for target evaluation. usualy turret_stdproc_targetscore_generic .float(entity e_turret, entity e_target) turret_score_target; -/* -* Damage, death and respawn. -*/ -//void turret_gibs_precash(); -// generalized so save mem (on fields) -// Function to handle incomming damage. usualy turret_stdproc_damage -//.void(entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector vforce) turret_damagefunc; -// Function to handle the event of death. usualy turret_stdproc_die -//.void() turret_diefunc; -// Function that handles rebirth. usualy turret_stdproc_respawn -//.void() turret_spawnfunc; - -/* -* Stuff to plug into requierd but unused callbacks. -*/ -/// Always return 1 -//float turret_stdproc_true(); -/// Always return 0 -//float turret_stdproc_false(); -/// Always return nothing at all -//void turret_stdproc_nothing(); /* * Target selection */ -// noting uses the following atm. -// "closeer is beter" selection -//float turret_stdproc_targetscore_close(entity e_turret, entity e_target); -// "further is beter" selection -//float turret_stdproc_targetscore_far(entity e_turret, entity e_target); -// only target_range_optimal -//float turret_stdproc_targetscore_optimal(entity e_turret, entity e_target); -// defendpos -//float turret_stdproc_targetscore_defend(entity e_turret, entity e_target); -/// Generic fairly smart bias-aware target selection. +/// Generic, fairly smart, bias-aware target selection. float turret_stdproc_targetscore_generic(entity e_turret, entity e_target); /// Experimental supportunits targetselector float turret_stdproc_targetscore_support(entity e_turret,entity e_target); @@ -493,9 +431,7 @@ float turret_stdproc_targetscore_support(entity e_turret,entity e_target); * Aim functions */ /// Generic aimer guided by self.aim_flags -vector turret_stdproc_aim_generic() -// Straight line, current location -//vector turret_stdproc_aim_simple() +vector turret_stdproc_aim_generic(); /* * Turret turning & pitch @@ -525,8 +461,6 @@ float tvt_dist; /// updates aim org, shot org, shot dir and enemy org for selected turret void turret_do_updates(entity e_turret); -//.vector tur_aimorg_updated; // creates to much aim issues. using tur_shotorg_updated insted. -//.vector tur_shotorg_updated; // DP8815 fixes gettaginfo, no longer needed. .vector tur_shotdir_updated; void turrets_precash(); diff --git a/qcsrc/server/tturrets/system/system_aimprocs.qc b/qcsrc/server/tturrets/system/system_aimprocs.qc index a6b6b30c1..99f18c20b 100644 --- a/qcsrc/server/tturrets/system/system_aimprocs.qc +++ b/qcsrc/server/tturrets/system/system_aimprocs.qc @@ -3,15 +3,18 @@ supports: TFL_AIM_NO -TFL_AIM_GROUND +TFL_AIM_GROUND2 TFL_AIM_LEAD TFL_AIM_SHOTTIMECOMPENSATE TFL_AIM_INFRONT TFL_AIM_BEHIND -TFL_AIM_ZEASE not supported: TFL_AIM_BALISTIC + +removed +TFL_AIM_ZEASE +TFL_AIM_GROUND */ vector turret_stdproc_aim_generic() { @@ -24,15 +27,7 @@ vector turret_stdproc_aim_generic() if(self.aim_flags & TFL_AIM_SIMPLE) return real_origin(self.enemy); - // Keep track of when we can shoot the next time and - // try to predict where the target will be then, so we can put our aimpoint there. - // + sys_frametime, becouse spawned REMOVE THIS IF sv_gameplayfix_delayprojectiles are 0! - // projectiles dont move during the first tic of their life. - //if (self.turrcaps_flags & TFL_TURRCAPS_HITSCAN) - // mintime = max(self.attack_finished_single - time,0) + sys_frametime; - //else - - mintime = max(self.attack_finished_single - time,0) + sys_frametime; + mintime = max(self.attack_finished_single - time,0) + sys_frametime ; // Baseline pre_pos = real_origin(self.enemy); @@ -45,60 +40,39 @@ vector turret_stdproc_aim_generic() // Lead? if (self.aim_flags & TFL_AIM_LEAD) - if (self.aim_flags & TFL_AIM_SHOTTIMECOMPENSATE) // Need to conpensate for shot traveltime - { - // FIXME: this cant be the best way to do this.. - prep = pre_pos; - for(i = 0; i < 4; ++i) - { - distance = vlen(prep - self.tur_shotorg); - impact_time = distance / self.shot_speed; - prep = pre_pos + self.enemy.velocity * impact_time; - } - - - // tnx to Rudolf "div0" Polzer for this solution. - // hmm tobad it dont work. - /* - vector q; - q = solve_quadratic(self.enemy.velocity*self.enemy.velocity - self.shot_speed*self.shot_speed, 2*(pre_pos*self.enemy.velocity), pre_pos * pre_pos); - if(q_x > 0) - impact_time = q_x; - else - impact_time = q_y; - */ - - prep = pre_pos + (self.enemy.velocity * (impact_time + mintime)); - - if(self.aim_flags & TFL_AIM_ZPREDICT) - if not(self.enemy.flags & FL_ONGROUND) - if(self.enemy.movetype == MOVETYPE_WALK || self.enemy.movetype == MOVETYPE_TOSS || self.enemy.movetype == MOVETYPE_BOUNCE) - { - float vz; - prep_z = pre_pos_z; - vz = self.enemy.velocity_z; - for(i = 0; i < impact_time; i += sys_frametime) - { - vz = vz - (sv_gravity * sys_frametime); - prep_z = prep_z + vz * sys_frametime; - } - } - pre_pos = prep; - } - else - pre_pos = pre_pos + self.enemy.velocity * mintime; - - // Smooth out predict-Z? - /* - if (self.aim_flags & TFL_AIM_ZEASE) - if (self.enemy.flags & FL_CLIENT) - { - vector v; - v = real_origin(self.enemy); - pre_pos_z = (pre_pos_z + v_z) * 0.5; + { + if (self.aim_flags & TFL_AIM_SHOTTIMECOMPENSATE) // Need to conpensate for shot traveltime + { + // FIXME: this cant be the best way to do this.. + prep = pre_pos; + for(i = 0; i < 4; ++i) + { + distance = vlen(prep - self.tur_shotorg); + impact_time = distance / self.shot_speed; + prep = pre_pos + self.enemy.velocity * impact_time; + } + + prep = pre_pos + (self.enemy.velocity * (impact_time + mintime)); + + if(self.aim_flags & TFL_AIM_ZPREDICT) + if not(self.enemy.flags & FL_ONGROUND) + if(self.enemy.movetype == MOVETYPE_WALK || self.enemy.movetype == MOVETYPE_TOSS || self.enemy.movetype == MOVETYPE_BOUNCE) + { + float vz; + prep_z = pre_pos_z; + vz = self.enemy.velocity_z; + for(i = 0; i < impact_time; i += sys_frametime) + { + vz = vz - (sv_gravity * sys_frametime); + prep_z = prep_z + vz * sys_frametime; + } + } + pre_pos = prep; + } + else + pre_pos = pre_pos + self.enemy.velocity * mintime; } - */ - + if(self.aim_flags & TFL_AIM_GROUND2) { //tracebox(pre_pos + '0 0 32',self.enemy.mins,self.enemy.maxs,pre_pos -'0 0 64',MOVE_WORLDONLY,self.enemy); @@ -107,14 +81,5 @@ vector turret_stdproc_aim_generic() pre_pos = trace_endpos; } - /* - // This turret should hit the ground neer a target rather the do a direct hit - if (self.aim_flags & TFL_AIM_GROUND) - { - traceline(pre_pos + '0 0 8',pre_pos - '0 0 10000',MOVE_WORLDONLY,self.enemy); - pre_pos = trace_endpos; - } - */ - return pre_pos; } diff --git a/qcsrc/server/tturrets/system/system_damage.qc b/qcsrc/server/tturrets/system/system_damage.qc index 9600c583c..d3e0553db 100644 --- a/qcsrc/server/tturrets/system/system_damage.qc +++ b/qcsrc/server/tturrets/system/system_damage.qc @@ -17,12 +17,11 @@ void turret_trowgib( gib = spawn(); gib.classname = "turret_gib"; - setmodel(gib,smodel); - setorigin(gib,v_from); - SUB_SetFade(gib,time + f_lifetime,2); + setmodel(gib, smodel); + setorigin(gib, v_from); + SUB_SetFade(gib,time + f_lifetime, 2); gib.solid = SOLID_BBOX; - gib.movetype = MOVETYPE_BOUNCE; gib.takedamage = DAMAGE_YES; gib.event_damage = turret_gib_damage; @@ -38,7 +37,7 @@ void turret_trowgib( burn.effects = EF_LOWPRECISION;//|EF_FLAME; setattachment(burn,gib,""); setorigin(burn,(gib.mins + gib.maxs) * 0.5); - SUB_SetFade(burn,time + (f_lifetime * 0.5) ,2); + SUB_SetFade(burn,time + (f_lifetime * 0.5), 2); } } @@ -55,15 +54,13 @@ void turret_gib_boom() s = strcat("models/turrets/head-gib",ftos(i)); s = strcat(s,".md3"); - // bprint("s:",s,"\n"); - setmodel(gib,s); + setmodel(gib, s); setorigin(gib,self.origin); SUB_SetFade(gib,time + 5,2); gib.solid = SOLID_BBOX; - gib.movetype = MOVETYPE_BOUNCE; gib.gravity = 0.5; gib.damageforcescale = 2; @@ -161,22 +158,21 @@ void turret_stdproc_die() makevectors(self.angles); if (random() > 0.5) { - turret_trowgib(self.origin, '0 0 0','1 1 1',"models/turrets/base-gib2.md3",min(self.respawntime,20),1,1); + turret_trowgib(self.origin, '0 0 0', '1 1 1', "models/turrets/base-gib2.md3", min(self.respawntime, 20), 1, 1); + + t_dir = (v_up * 700) + (randomvec() * 300); + turret_trowgib(self.origin, t_dir, '1 1 1', "models/turrets/base-gib3.md3", min(self.respawntime, 10), 1, 1); + t_dir = (v_up * 700) + (randomvec() * 300); - turret_trowgib(self.origin, t_dir,'1 1 1',"models/turrets/base-gib3.md3",min(self.respawntime,10),1,1); - t_dir = (v_up * 700) + (randomvec() * 300); - turret_trowgib(self.origin, t_dir,'1 1 1',"models/turrets/base-gib4.md3",min(self.respawntime,10),1,1); + turret_trowgib(self.origin, t_dir, '1 1 1', "models/turrets/base-gib4.md3", min(self.respawntime, 10), 1, 1); } else { - turret_trowgib(self.origin, '0 0 0','1 1 1',"models/turrets/base-gib1.md3",min(self.respawntime,20),1,1); + turret_trowgib(self.origin, '0 0 0', '1 1 1', "models/turrets/base-gib1.md3", min(self.respawntime, 20), 1, 1); } // Blow the top part up into the air - turret_trowgib2( self.origin + (v_up * 50), - v_up * 150 + randomvec() * 50, - '0.2 0.2 0.2', - self.tur_head,time + 0.5 + (random() * 0.5)); + turret_trowgib2( self.origin + (v_up * 50), v_up * 150 + randomvec() * 50, '0.2 0.2 0.2', self.tur_head,time + 0.5 + (random() * 0.5)); } // Go boom @@ -192,31 +188,23 @@ void turret_stdproc_die() } else { - // Setup respawn + // Setup respawn self.nextthink = time + self.respawntime; - //self.think = self.turret_spawnfunc; self.think = turret_stdproc_respawn; + if (self.turret_diehook) self.turret_diehook(); } - } +var const float SUB_NullFloat(); void turret_stdproc_respawn() { // Make sure all parts belong to the same team since // this function doubles as "teamchange" function. - self.tur_head.team = self.team; - - /* - COLOR_TEAM1 = 4; // red - COLOR_TEAM2 = 13; // blue - COLOR_TEAM3 = 12; // yellow - COLOR_TEAM4 = 9; // pink - */ - - self.colormod = '0 0 0'; + self.tur_head.team = self.team; + self.colormod = '0 0 0'; switch(self.team) { @@ -238,17 +226,16 @@ void turret_stdproc_respawn() } self.deadflag = DEAD_NO; - self.effects = 0; + self.effects = EF_LOWPRECISION; self.tur_head.effects = self.effects; - self.solid = SOLID_BBOX; - - self.alpha = 1; + self.alpha = 1; self.tur_head.alpha = self.alpha; - self.customizeentityforclient = SUB_True; - self.tur_head.customizeentityforclient = SUB_True; + + self.customizeentityforclient = SUB_NullFloat; + self.tur_head.customizeentityforclient = SUB_NullFloat; - self.takedamage = DAMAGE_AIM; + self.takedamage = DAMAGE_AIM; self.event_damage = turret_stdproc_damage; self.avelocity = '0 0 0'; diff --git a/qcsrc/server/tturrets/system/system_main.qc b/qcsrc/server/tturrets/system/system_main.qc index afddaef0d..af53db7c6 100644 --- a/qcsrc/server/tturrets/system/system_main.qc +++ b/qcsrc/server/tturrets/system/system_main.qc @@ -19,12 +19,10 @@ float Turret_SendEntity(entity to, float sf) } */ -void load_unit_settings(entity ent,string unitname,float is_reload) +void load_unit_settings(entity ent, string unitname, float is_reload) { string sbase; - // dprint("Reloading turret ",e_turret.netname,"\n"); - if (ent == world) return; @@ -59,8 +57,8 @@ void load_unit_settings(entity ent,string unitname,float is_reload) ent.target_range = cvar(strcat(sbase,"_target_range")) * ent.turret_scale_range; ent.target_range_min = cvar(strcat(sbase,"_target_range_min")) * ent.turret_scale_range; - //ent.target_range_fire = cvar(strcat(sbase,"_target_range_fire")) * ent.turret_scale_range; ent.target_range_optimal = cvar(strcat(sbase,"_target_range_optimal")) * ent.turret_scale_range; + //ent.target_range_fire = cvar(strcat(sbase,"_target_range_fire")) * ent.turret_scale_range; ent.target_select_rangebias = cvar(strcat(sbase,"_target_select_rangebias")); ent.target_select_samebias = cvar(strcat(sbase,"_target_select_samebias")); @@ -84,26 +82,8 @@ void load_unit_settings(entity ent,string unitname,float is_reload) if(is_reload) if(ent.turret_respawnhook) ent.turret_respawnhook(); - -} - -/* -float turret_stdproc_true() -{ - return 1; } -float turret_stdproc_false() -{ - return 0; -} - - -void turret_stdproc_nothing() -{ - return; -} -*/ /** ** updates enemy distances, predicted impact point/time @@ -111,7 +91,7 @@ void turret_stdproc_nothing() **/ void turret_do_updates(entity t_turret) { - vector enemy_pos,oldpos; + vector enemy_pos, oldpos; entity oldself; oldself = self; @@ -121,8 +101,7 @@ void turret_do_updates(entity t_turret) turret_tag_fire_update(); - self.tur_shotdir_updated = normalize(v_forward); - + self.tur_shotdir_updated = v_forward; self.tur_dist_enemy = vlen(self.tur_shotorg - enemy_pos); self.tur_dist_aimpos = vlen(self.tur_shotorg - self.tur_aimpos); @@ -136,20 +115,16 @@ void turret_do_updates(entity t_turret) if(trace_ent == self.enemy) self.tur_dist_impact_to_aimpos = 0; else - self.tur_dist_impact_to_aimpos = vlen(trace_endpos - self.tur_aimpos);// - (vlen(self.enemy.maxs - self.enemy.mins)*0.5); + self.tur_dist_impact_to_aimpos = vlen(trace_endpos - self.tur_aimpos); - self.tur_impactent = trace_ent; - self.tur_impacttime = vlen(self.tur_shotorg - trace_endpos) / self.shot_speed; } else - tracebox(self.tur_shotorg, '-1 -1 -1','1 1 1',self.tur_shotorg + (self.tur_shotdir_updated * self.tur_dist_aimpos),MOVE_NORMAL,self); - //traceline(self.tur_shotorg, self.tur_shotorg + (self.tur_shotdir_updated * self.tur_dist_aimpos),MOVE_NORMAL,self); - - self.tur_dist_impact_to_aimpos = vlen(trace_endpos - self.tur_aimpos) - (vlen(self.enemy.maxs - self.enemy.mins)*0.5); - self.tur_impactent = trace_ent; - self.tur_impacttime = vlen(self.tur_shotorg - trace_endpos) / self.shot_speed; - + tracebox(self.tur_shotorg, '-1 -1 -1','1 1 1', self.tur_shotorg + (self.tur_shotdir_updated * self.tur_dist_aimpos),MOVE_NORMAL,self); + + self.tur_dist_impact_to_aimpos = vlen(trace_endpos - self.tur_aimpos) - (vlen(self.enemy.maxs - self.enemy.mins) * 0.5); + self.tur_impactent = trace_ent; + self.tur_impacttime = vlen(self.tur_shotorg - trace_endpos) / self.shot_speed; self = oldself; } @@ -224,7 +199,6 @@ vector turret_fovsearch_random() ** Handles head rotation according to ** the units .track_type and .track_flags **/ -//.entity aim_mark; void turret_stdproc_track() { vector target_angle; // This is where we want to aim @@ -245,21 +219,16 @@ void turret_stdproc_track() } else { - // Find the direction - target_angle = normalize(self.tur_aimpos - self.tur_shotorg); - target_angle = vectoangles(target_angle); // And make a angle + target_angle = vectoangles(normalize(self.tur_aimpos - self.tur_shotorg)); } - - self.tur_head.angles_x = safeangle(self.tur_head.angles_x); - self.tur_head.angles_y = safeangle(self.tur_head.angles_y); + + self.tur_head.angles_x = anglemods(self.tur_head.angles_x); + self.tur_head.angles_y = anglemods(self.tur_head.angles_y); // Find the diffrence between where we currently aim and where we want to aim move_angle = target_angle - (self.angles + self.tur_head.angles); move_angle = shortangle_vxy(move_angle,(self.angles + self.tur_head.angles)); - - - switch(self.track_type) { case TFL_TRACKTYPE_STEPMOTOR: @@ -288,8 +257,8 @@ void turret_stdproc_track() case TFL_TRACKTYPE_FLUIDINERTIA: f_tmp = self.aim_speed * self.ticrate; // dgr/sec -> dgr/tic - move_angle_x = bound(-self.aim_speed, move_angle_x * self.track_accel_pitch * f_tmp,self.aim_speed); - move_angle_y = bound(-self.aim_speed, move_angle_y * self.track_accel_rot * f_tmp,self.aim_speed); + move_angle_x = bound(-self.aim_speed, move_angle_x * self.track_accel_pitch * f_tmp, self.aim_speed); + move_angle_y = bound(-self.aim_speed, move_angle_y * self.track_accel_rot * f_tmp, self.aim_speed); move_angle = (self.tur_head.avelocity * self.track_blendrate) + (move_angle * (1 - self.track_blendrate)); break; @@ -310,12 +279,12 @@ void turret_stdproc_track() self.tur_head.avelocity_x = 0; self.tur_head.angles_x = self.aim_maxpitch; } + if((self.tur_head.angles_x + self.tur_head.avelocity_x * self.ticrate) < -self.aim_maxpitch) { self.tur_head.avelocity_x = 0; - self.tur_head.angles_x = self.aim_maxpitch; + self.tur_head.angles_x = -self.aim_maxpitch; } - } // rot @@ -332,11 +301,9 @@ void turret_stdproc_track() if((self.tur_head.angles_y + self.tur_head.avelocity_y * self.ticrate) < -self.aim_maxrot) { self.tur_head.avelocity_y = 0; - self.tur_head.angles_y = self.aim_maxrot; + self.tur_head.angles_y = -self.aim_maxrot; } - } - } @@ -369,12 +336,13 @@ float turret_stdproc_firecheck() // Ready? if (self.firecheck_flags & TFL_FIRECHECK_REFIRE) - if (self.attack_finished_single >= time) return 0; + if (self.attack_finished_single > time) return 0; // Special case: volly fire turret that has to fire a full volly if a shot was fired. if (self.shoot_flags & TFL_SHOOT_VOLLYALWAYS) - if not (self.volly_counter == self.shot_volly) - return 1; + if (self.volly_counter != self.shot_volly) + if(self.ammo >= self.shot_dmg) + return 1; // Lack of zombies makes shooting dead things unnecessary :P if (self.firecheck_flags & TFL_FIRECHECK_DEAD) @@ -395,15 +363,22 @@ float turret_stdproc_firecheck() if (self.firecheck_flags & TFL_FIRECHECK_OTHER_AMMO) if (self.enemy.ammo >= self.enemy.ammo_max) return 0; + + // Target of opertunity? + if(turret_validate_target(self, self.tur_impactent, self.target_validate_flags) > 0) + { + self.enemy = self.tur_impactent; + return 1; + } if (self.firecheck_flags & TFL_FIRECHECK_DISTANCES) { - // Not close enougth? - //if (self.tur_dist_aimpos > self.target_range_fire) return 0; - // To close? if (self.tur_dist_aimpos < self.target_range_min) - return 0; + if(turret_validate_target(self, self.tur_impactent, self.target_validate_flags) > 0) + return 1; // Target of opertunity? + else + return 0; } // Try to avoid FF? @@ -416,8 +391,6 @@ float turret_stdproc_firecheck() if (self.tur_dist_impact_to_aimpos > self.aim_firetolerance_dist) return 0; - //if (self.tur_impactent != self.enemy) - // Volly status if (self.shot_volly > 1) if (self.volly_counter == self.shot_volly) @@ -448,7 +421,7 @@ float turret_stdproc_firecheck() ** Evaluate a entity for target valitity based on validate_flags ** NOTE: the caller must check takedamage before calling this, to inline this check. **/ -float turret_validate_target(entity e_turret,entity e_target,float validate_flags) +float turret_validate_target(entity e_turret, entity e_target, float validate_flags) { vector v_tmp; @@ -537,12 +510,8 @@ float turret_validate_target(entity e_turret,entity e_target,float validate_flag } // Can we even aim this thing? - tvt_thadv = angleofs3(e_turret.tur_head.origin,e_turret.angles + e_turret.tur_head.angles ,e_target); - //tvt_thadv = angleofs(e_turret.angles,e_target); - - - - tvt_tadv = shortangle_vxy(angleofs(e_turret,e_target),e_turret.angles); + tvt_thadv = angleofs3(e_turret.tur_head.origin, e_turret.angles + e_turret.tur_head.angles, e_target); + tvt_tadv = shortangle_vxy(angleofs(e_turret, e_target), e_turret.angles); tvt_thadf = vlen(tvt_thadv); tvt_tadf = vlen(tvt_tadv); @@ -595,7 +564,6 @@ entity turret_select_target() float score; // target looper entity score entity e_enemy; // currently best scoreing target float m_score; // currently best scoreing target's score - float f; m_score = 0; if(self.enemy) @@ -608,17 +576,17 @@ entity turret_select_target() else self.enemy = world; - e = findradius(self.origin,self.target_range); + e = findradius(self.origin, self.target_range); // Nothing to aim at? - if (!e) return world; + if (!e) + return world; while (e) { if(e.takedamage) { - f = turret_validate_target(self,e,self.target_select_flags); - if (f > 0) + if (turret_validate_target(self, e, self.target_select_flags) > 0) { score = self.turret_score_target(self,e); if ((score > m_score) && (score > 0)) @@ -646,7 +614,7 @@ void turret_think() if not (g_onslaught) if (self.target) { - e = find(world,targetname,self.target); + e = find(world, targetname,self.target); if (e != world) self.team = e.team; } @@ -667,8 +635,7 @@ void turret_think() // Handle ammo if not (self.spawnflags & TSF_NO_AMMO_REGEN) if (self.ammo < self.ammo_max) - self.ammo = min(self.ammo + self.ammo_recharge,self.ammo_max); - + self.ammo = min(self.ammo + self.ammo_recharge, self.ammo_max); // Inactive turrets needs to run the think loop, // So they can handle animation and wake up if need be. @@ -678,15 +645,6 @@ void turret_think() return; } - //This is just wrong :| and unlikely to ever happen. - /* - if(self.deadflag != DEAD_NO) - { - dprint("WARNING: dead turret running the think function!\n"); - return; - } - */ - // This is typicaly used for zaping every target in range // turret_fusionreactor uses this to recharge friendlys. if (self.shoot_flags & TFL_SHOOT_HITALLVALID) @@ -758,14 +716,17 @@ void turret_think() // Check if we have a vailid enemy, and try to find one if we dont. - // g_turrets_targetscan_maxdelay forces a target re-scan this often + // g_turrets_targetscan_maxdelay forces a target re-scan at least this often float do_target_scan; if((self.target_select_time + cvar("g_turrets_targetscan_maxdelay")) < time) do_target_scan = 1; // Old target (if any) invalid? - if (turret_validate_target(self,self.enemy,self.target_validate_flags) <= 0) - do_target_scan = 1; + if (turret_validate_target(self, self.enemy, self.target_validate_flags) <= 0) + { + self.enemy = world; + do_target_scan = 1; + } // But never more often then g_turrets_targetscan_mindelay! if (self.target_select_time + cvar("g_turrets_targetscan_mindelay") > time) @@ -809,7 +770,7 @@ void turret_think() turret_fire(); } - // do any per-turret stuff + // do any custom per-turret stuff if(self.turret_postthink) self.turret_postthink(); } @@ -819,15 +780,6 @@ void turret_fire() if (cvar("g_turrets_nofire") != 0) return; - /* - // unlikely to ever happen. - if (self.deadflag != DEAD_NO) - return; - - if not (self.tur_active) - return; - */ - self.turret_firefunc(); self.attack_finished_single = time + self.shot_refire; @@ -857,11 +809,11 @@ void turret_stdproc_fire() /* When .used a turret switch team to activator.team. - If activator is world, the turrets goes inactive. + If activator is world, the turret go inactive. */ void turret_stdproc_use() { - dprint("Turret ",self.netname, " used by ",activator.classname,"\n"); + dprint("Turret ",self.netname, " used by ", activator.classname, "\n"); self.team = activator.team; @@ -911,7 +863,7 @@ float turret_stdproc_init (string cvar_base_name, float csqc_shared, string base { entity e, ee; - // Are turrets allowed atm? + // Are turrets allowed? if (cvar("g_turrets") == 0) return 0; @@ -967,7 +919,7 @@ float turret_stdproc_init (string cvar_base_name, float csqc_shared, string base self.team = 14; // Assume turrets are on the defending side if not explicitly set otehrwize } else if not (teamplay) - self.team = MAX_SHOT_DISTANCE; // Group all turrets into the same team iso they dont kill eachother. + self.team = MAX_SHOT_DISTANCE; // Group all turrets into the same team, so they dont kill eachother. else if(g_onslaught && self.targetname) { e = find(world,target,self.targetname); @@ -978,7 +930,7 @@ float turret_stdproc_init (string cvar_base_name, float csqc_shared, string base } } else if(!self.team) - self.team = MAX_SHOT_DISTANCE; // Group all turrets into the same team iso they dont kill eachother. + self.team = MAX_SHOT_DISTANCE; // Group all turrets into the same team, so they dont kill eachother. /* * Try to guess some reasonaly defaults @@ -988,11 +940,11 @@ float turret_stdproc_init (string cvar_base_name, float csqc_shared, string base * as possible beforehand. */ if (self.turrcaps_flags & TFL_TURRCAPS_SUPPORT) - if not (self.ticrate) self.ticrate = 0.2; // Support units generaly dont need to have a high speed ai-loop + self.ticrate = 0.2; // Support units generaly dont need to have a high speed ai-loop else - if not (self.ticrate) self.ticrate = 0.1; // 10 fps for normal turrets + self.ticrate = 0.1; // 10 fps for normal turrets - self.ticrate = bound(sys_frametime,self.ticrate,60); // keep it sane + self.ticrate = bound(sys_frametime, self.ticrate, 60); // keep it sane // General stuff if (self.netname == "") @@ -1000,50 +952,50 @@ float turret_stdproc_init (string cvar_base_name, float csqc_shared, string base if not (self.respawntime) self.respawntime = 60; - self.respawntime = max(-1,self.respawntime); + self.respawntime = max(-1, self.respawntime); if not (self.health) self.health = 1000; - self.tur_health = max(1,self.health); + self.tur_health = max(1, self.health); if not (self.turrcaps_flags) self.turrcaps_flags = TFL_TURRCAPS_RADIUSDMG | TFL_TURRCAPS_MEDPROJ | TFL_TURRCAPS_PLAYERKILL; - if (!self.damage_flags) + if not (self.damage_flags) self.damage_flags = TFL_DMG_YES | TFL_DMG_RETALIATE | TFL_DMG_AIMSHAKE; // Shot stuff. if not (self.shot_refire) self.shot_refire = 1; - self.shot_refire = bound(0.01,self.shot_refire,9999); + self.shot_refire = bound(0.01, self.shot_refire, 9999); if not (self.shot_dmg) self.shot_dmg = self.shot_refire * 50; - self.shot_dmg = max(1,self.shot_dmg); + self.shot_dmg = max(1, self.shot_dmg); if not (self.shot_radius) self.shot_radius = self.shot_dmg * 0.5; - self.shot_radius = max(1,self.shot_radius); + self.shot_radius = max(1, self.shot_radius); if not (self.shot_speed) self.shot_speed = 2500; - self.shot_speed = max(1,self.shot_speed); + self.shot_speed = max(1, self.shot_speed); if not (self.shot_spread) self.shot_spread = 0.0125; - self.shot_spread = bound(0.0001,self.shot_spread,500); + self.shot_spread = bound(0.0001, self.shot_spread, 500); if not (self.shot_force) self.shot_force = self.shot_dmg * 0.5 + self.shot_radius * 0.5; - self.shot_force = bound(0.001,self.shot_force,MAX_SHOT_DISTANCE * 0.5); + self.shot_force = bound(0.001, self.shot_force, 5000); if not (self.shot_volly) self.shot_volly = 1; - self.shot_volly = bound(1,self.shot_volly,floor(self.ammo_max / self.shot_dmg)); + self.shot_volly = bound(1, self.shot_volly, floor(self.ammo_max / self.shot_dmg)); if not (self.shot_volly_refire) self.shot_volly_refire = self.shot_refire * self.shot_volly; - self.shot_volly_refire = bound(self.shot_refire,self.shot_volly_refire,60); + self.shot_volly_refire = bound(self.shot_refire, self.shot_volly_refire, 60); if not (self.firecheck_flags) self.firecheck_flags = TFL_FIRECHECK_WORLD | TFL_FIRECHECK_DEAD | TFL_FIRECHECK_DISTANCES | @@ -1053,37 +1005,33 @@ float turret_stdproc_init (string cvar_base_name, float csqc_shared, string base // Range stuff. if not (self.target_range) self.target_range = self.shot_speed * 0.5; - self.target_range = bound(0,self.target_range,MAX_SHOT_DISTANCE); + self.target_range = bound(0, self.target_range, MAX_SHOT_DISTANCE); if not (self.target_range_min) self.target_range_min = self.shot_radius * 2; - self.target_range_min = bound(0,self.target_range_min,MAX_SHOT_DISTANCE); - - //if (!self.target_range_fire) - // self.target_range_fire = self.target_range * 0.8; - //self.target_range_fire = bound(0,self.target_range_fire,MAX_SHOT_DISTANCE); + self.target_range_min = bound(0, self.target_range_min, MAX_SHOT_DISTANCE); if not (self.target_range_optimal) self.target_range_optimal = self.target_range * 0.5; - self.target_range_optimal = bound(0,self.target_range_optimal,MAX_SHOT_DISTANCE); + self.target_range_optimal = bound(0, self.target_range_optimal, MAX_SHOT_DISTANCE); // Aim stuff. if not (self.aim_maxrot) self.aim_maxrot = 90; - self.aim_maxrot = bound(0,self.aim_maxrot,360); + self.aim_maxrot = bound(0, self.aim_maxrot, 360); if not (self.aim_maxpitch) self.aim_maxpitch = 20; - self.aim_maxpitch = bound(0,self.aim_maxpitch,90); + self.aim_maxpitch = bound(0, self.aim_maxpitch, 90); if not (self.aim_speed) self.aim_speed = 36; - self.aim_speed = bound(0.1,self.aim_speed, 1000); + self.aim_speed = bound(0.1, self.aim_speed, 1000); if not (self.aim_firetolerance_dist) self.aim_firetolerance_dist = 5 + (self.shot_radius * 2); - self.aim_firetolerance_dist = bound(0.1,self.aim_firetolerance_dist,MAX_SHOT_DISTANCE); + self.aim_firetolerance_dist = bound(0.1, self.aim_firetolerance_dist, MAX_SHOT_DISTANCE); if not (self.aim_flags) { @@ -1092,19 +1040,17 @@ float turret_stdproc_init (string cvar_base_name, float csqc_shared, string base self.aim_flags |= TFL_AIM_GROUND2; } - // Sill the most tested (and aim-effective) if not (self.track_type) self.track_type = TFL_TRACKTYPE_STEPMOTOR; if (self.track_type != TFL_TRACKTYPE_STEPMOTOR) { - // Fluid / Ineria mode. Looks mutch nicer, bit experimental & - // Can inmapt aim preformance alot. - // needs a bit diffrent aimspeed + // Fluid / Ineria mode. Looks mutch nicer. + // Can reduce aim preformance alot, needs a bit diffrent aimspeed if not (self.aim_speed) self.aim_speed = 180; - self.aim_speed = bound(0.1,self.aim_speed, 1000); + self.aim_speed = bound(0.1, self.aim_speed, 1000); if not (self.track_accel_pitch) self.track_accel_pitch = 0.5; @@ -1123,21 +1069,21 @@ float turret_stdproc_init (string cvar_base_name, float csqc_shared, string base // Target selection stuff. if not (self.target_select_rangebias) self.target_select_rangebias = 1; - self.target_select_rangebias = bound(-10,self.target_select_rangebias,10); + self.target_select_rangebias = bound(-10, self.target_select_rangebias, 10); if not (self.target_select_samebias) self.target_select_samebias = 1; - self.target_select_samebias = bound(-10,self.target_select_samebias,10); + self.target_select_samebias = bound(-10, self.target_select_samebias, 10); if not (self.target_select_anglebias) self.target_select_anglebias = 1; - self.target_select_anglebias = bound(-10,self.target_select_anglebias,10); + self.target_select_anglebias = bound(-10, self.target_select_anglebias, 10); if not (self.target_select_missilebias) self.target_select_missilebias = -10; - self.target_select_missilebias = bound(-10,self.target_select_missilebias,10); - self.target_select_playerbias = bound(-10,self.target_select_playerbias,10); + self.target_select_missilebias = bound(-10, self.target_select_missilebias, 10); + self.target_select_playerbias = bound(-10, self.target_select_playerbias, 10); if not (self.target_select_flags) { @@ -1159,15 +1105,15 @@ float turret_stdproc_init (string cvar_base_name, float csqc_shared, string base // Ammo stuff if not (self.ammo_max) self.ammo_max = self.shot_dmg * 10; - self.ammo_max = max(self.shot_dmg,self.ammo_max); + self.ammo_max = max(self.shot_dmg, self.ammo_max); if not (self.ammo) self.ammo = self.shot_dmg * 5; - self.ammo = bound(0,self.ammo,self.ammo_max); + self.ammo = bound(0,self.ammo, self.ammo_max); if not (self.ammo_recharge) self.ammo_recharge = self.shot_dmg * 0.5; - self.ammo_recharge = max(0,self.ammo_recharge); + self.ammo_recharge = max(0 ,self.ammo_recharge); // Convert the recharge from X per sec to X per ticrate self.ammo_recharge = self.ammo_recharge * self.ticrate; @@ -1191,13 +1137,13 @@ float turret_stdproc_init (string cvar_base_name, float csqc_shared, string base self.tur_head.team = self.team; self.tur_head.owner = self; - setmodel(self,base); - setmodel(self.tur_head,head); + setmodel(self, base); + setmodel(self.tur_head, head); - setsize(self,'-32 -32 0','32 32 64'); - setsize(self.tur_head,'0 0 0','0 0 0'); + setsize(self, '-32 -32 0', '32 32 64'); + setsize(self.tur_head, '0 0 0', '0 0 0'); - setorigin(self.tur_head,'0 0 0'); + setorigin(self.tur_head, '0 0 0'); setattachment(self.tur_head, self, "tag_head"); if (!self.health) @@ -1225,7 +1171,7 @@ float turret_stdproc_init (string cvar_base_name, float csqc_shared, string base // In target defend mode, aim on the spot to defend when idle. if (self.tur_defend) - self.idle_aim = self.tur_head.angles + angleofs(self.tur_head,self.tur_defend); + self.idle_aim = self.tur_head.angles + angleofs(self.tur_head, self.tur_defend); else self.idle_aim = '0 0 0'; @@ -1289,6 +1235,7 @@ float turret_stdproc_init (string cvar_base_name, float csqc_shared, string base self.use(); } + turret_stdproc_respawn(); return 1; } diff --git a/qcsrc/server/tturrets/system/system_misc.qc b/qcsrc/server/tturrets/system/system_misc.qc index 161bdcbcc..7b2875d7d 100644 --- a/qcsrc/server/tturrets/system/system_misc.qc +++ b/qcsrc/server/tturrets/system/system_misc.qc @@ -1,25 +1,22 @@ -//--// Some support routines //--// - -#define anglemodss(a) (a - floor(a / 360) * 360) - -float(float v) anglemods = +/* +* Return a angle within +/- 360. +*/ +float anglemods(float v) { v = v - 360 * floor(v / 360); - return v; -} - -float safeangle(float a) -{ - if((a >= -360) && (a <= 360)) - return a; - - - a -= (360 * floor(a / 360)); - - return a; + + if(v >= 180) + return v - 360; + else if(v <= -180) + return v + 360; + else + return v; } -float shortangle_f(float ang1,float ang2) +/* +* Return the short angle +*/ +float shortangle_f(float ang1, float ang2) { if(ang1 > ang2) { @@ -35,7 +32,7 @@ float shortangle_f(float ang1,float ang2) return ang1; } -vector shortangle_v(vector ang1,vector ang2) +vector shortangle_v(vector ang1, vector ang2) { vector vtmp; @@ -46,7 +43,7 @@ vector shortangle_v(vector ang1,vector ang2) return vtmp; } -vector shortangle_vxy(vector ang1,vector ang2) +vector shortangle_vxy(vector ang1, vector ang2) { vector vtmp; @@ -56,7 +53,10 @@ vector shortangle_vxy(vector ang1,vector ang2) return vtmp; } -// Get real origin + +/* +* Get "real" origin, in worldspace, even if ent is attached to something else. +*/ vector real_origin(entity ent) { entity e; @@ -65,241 +65,74 @@ vector real_origin(entity ent) e = ent.tag_entity; while(e) { - // v = v + e.origin; v = v + ((e.absmin + e.absmax) * 0.5); e = e.tag_entity; } - //v = v + ent.origin; v = v + ((ent.absmin + ent.absmax) * 0.5); return v; } -// Plug this into wherever precache is done. -void g_turrets_common_precash() -{ - precache_model ("models/turrets/c512.md3"); - precache_model ("models/marker.md3"); -} - -void SUB_Remove(); -void marker_think() -{ - if(self.cnt) - if(self.cnt < time) - { - self.think = SUB_Remove; - self.nextthink = time; - return; - } - - self.frame += 1; - if(self.frame > 29) - self.frame = 0; - - self.nextthink = time; -} - -void mark_error(vector where,float lifetime) -{ - entity err; - - err = spawn(); - err.classname = "error_marker"; - setmodel(err,"models/marker.md3"); - setorigin(err,where); - err.movetype = MOVETYPE_NONE; - err.think = marker_think; - err.nextthink = time; - err.skin = 0; - if(lifetime) - err.cnt = lifetime + time; -} - -void mark_info(vector where,float lifetime) -{ - entity err; - - err = spawn(); - err.classname = "info_marker"; - setmodel(err,"models/marker.md3"); - setorigin(err,where); - err.movetype = MOVETYPE_NONE; - err.think = marker_think; - err.nextthink = time; - err.skin = 1; - if(lifetime) - err.cnt = lifetime + time; -} - -entity mark_misc(vector where,float lifetime) -{ - entity err; - - err = spawn(); - err.classname = "mark_misc"; - setmodel(err,"models/marker.md3"); - setorigin(err,where); - err.movetype = MOVETYPE_NONE; - err.think = marker_think; - err.nextthink = time; - err.skin = 3; - if(lifetime) - err.cnt = lifetime + time; - return err; -} - -/* -* Paint a v_color colord circle on target onwho -* that fades away over f_time -*/ -void paint_target(entity onwho, float f_size, vector v_color, float f_time) -{ - entity e; - - e = spawn(); - setmodel(e, "models/turrets/c512.md3"); // precision set above - e.scale = (f_size/512); - //setsize(e, '0 0 0', '0 0 0'); - //setattachment(e,onwho,""); - setorigin(e,onwho.origin + '0 0 1'); - e.alpha = 0.15; - e.movetype = MOVETYPE_FLY; - - e.velocity = (v_color * 32); // + '0 0 1' * 64; - - e.colormod = v_color; - SUB_SetFade(e,time,f_time); -} - -void paint_target2(entity onwho, float f_size, vector v_color, float f_time) -{ - entity e; - - e = spawn(); - setmodel(e, "models/turrets/c512.md3"); // precision set above - e.scale = (f_size/512); - setsize(e, '0 0 0', '0 0 0'); - - setorigin(e,onwho.origin + '0 0 1'); - e.alpha = 0.15; - e.movetype = MOVETYPE_FLY; - - e.velocity = (v_color * 32); // + '0 0 1' * 64; - e.avelocity_x = -128; - - e.colormod = v_color; - SUB_SetFade(e,time,f_time); -} - -void paint_target3(vector where, float f_size, vector v_color, float f_time) -{ - entity e; - e = spawn(); - setmodel(e, "models/turrets/c512.md3"); // precision set above - e.scale = (f_size/512); - setsize(e, '0 0 0', '0 0 0'); - setorigin(e,where+ '0 0 1'); - e.movetype = MOVETYPE_NONE; - e.velocity = '0 0 0'; - e.colormod = v_color; - SUB_SetFade(e,time,f_time); -} - /* * Return the angle between two enteties */ vector angleofs(entity from, entity to) { vector v_res; - - // makevectors(from.angles); + v_res = normalize(to.origin - from.origin); v_res = vectoangles(v_res); v_res = v_res - from.angles; - if (v_res_x < 0) v_res_x += 360; - if (v_res_x > 180) v_res_x -= 360; - - if (v_res_y < 0) v_res_y += 360; - if (v_res_y > 180) v_res_y -= 360; - - return v_res; -} - -vector angleofs2(entity from, vector to) -{ - vector v_res; - - // makevectors(from.angles); - v_res = normalize(to - from.origin); - v_res = vectoangles(v_res); - v_res = v_res - from.angles; - - if (v_res_x < 0) v_res_x += 360; - if (v_res_x > 180) v_res_x -= 360; + if (v_res_x < 0) v_res_x += 360; + if (v_res_x > 180) v_res_x -= 360; - if (v_res_y < 0) v_res_y += 360; - if (v_res_y > 180) v_res_y -= 360; + if (v_res_y < 0) v_res_y += 360; + if (v_res_y > 180) v_res_y -= 360; return v_res; } -vector angleofs3(vector from,vector from_a, entity to) +vector angleofs3(vector from, vector from_a, entity to) { vector v_res; - - // makevectors(from.angles); + v_res = normalize(to.origin - from); v_res = vectoangles(v_res); v_res = v_res - from_a; - if (v_res_x < 0) v_res_x += 360; - if (v_res_x > 180) v_res_x -= 360; + if (v_res_x < 0) v_res_x += 360; + if (v_res_x > 180) v_res_x -= 360; - if (v_res_y < 0) v_res_y += 360; - if (v_res_y > 180) v_res_y -= 360; + if (v_res_y < 0) v_res_y += 360; + if (v_res_y > 180) v_res_y -= 360; return v_res; } -float turret_tag_setup() -{ - if(!self.tur_head) - { - dprint("Call to turret_tag_setup with self.tur_head missing!\n"); - self.tur_shotorg = '0 0 0'; - return 0; - } - - //if not(self.turrcaps_flags & TFL_TURRCAPS_HEADATTACHED) - // setorigin(self.tur_head,gettaginfo(self,gettagindex(self,"tag_head"))); - - self.tur_shotorg = gettaginfo(self.tur_head,gettagindex(self.tur_head,"tag_fire")); - - v_forward = normalize(v_forward); - - return 1; -} - +/* +* Update self.tur_shotorg by getting up2date bone info +* NOTICE this func overwrites the global v_forward, v_right and v_up vectors. +*/ float turret_tag_fire_update() { if(!self.tur_head) { - dprint("Call to turret_tag_fire_update with self.tur_head missing!\n"); + error("Call to turret_tag_fire_update with self.tur_head missing!\n"); self.tur_shotorg = '0 0 0'; - return 0; + return FALSE; } - self.tur_shotorg = gettaginfo(self.tur_head,gettagindex(self.tur_head,"tag_fire")); + self.tur_shotorg = gettaginfo(self.tur_head, gettagindex(self.tur_head, "tag_fire")); v_forward = normalize(v_forward); - //dprint("update: tur_shotorg: ",vtos(self.tur_shotorg)," origin:", vtos(self.tur_head.origin), " angels: ", vtos(self.tur_head.angles),"\n"); - - return 1; + return TRUE; } -void FireImoBeam (vector start,vector end,vector smin,vector smax, - float bforce,float f_dmg,float f_velfactor, float deathtype) +/* +* Railgun-like beam, but has thickness and suppots slowing of target +*/ +void FireImoBeam (vector start, vector end, vector smin, vector smax, + float bforce, float f_dmg, float f_velfactor, float deathtype) { local vector hitloc, force, endpoint, dir; @@ -370,6 +203,13 @@ void FireImoBeam (vector start,vector end,vector smin,vector smax, trace_endpos = endpoint; } +// Plug this into wherever precache is done. +void g_turrets_common_precash() +{ + precache_model ("models/turrets/c512.md3"); + precache_model ("models/marker.md3"); +} + void turrets_precache_debug_models() { precache_model ("models/turrets/c512.md3"); @@ -409,5 +249,134 @@ void turrets_precash() //precache_model ("models/turrets/plasma.md3"); //precache_model ("models/turrets/tesla_head.md3"); //precache_model ("models/turrets/tesla_base.md3"); - //turrets_precache_debug_models(); + #ifdef TURRET_DEBUG + turrets_precache_debug_models(); + #endif +} + + +#ifdef TURRET_DEBUG +void SUB_Remove(); +void marker_think() +{ + if(self.cnt) + if(self.cnt < time) + { + self.think = SUB_Remove; + self.nextthink = time; + return; + } + + self.frame += 1; + if(self.frame > 29) + self.frame = 0; + + self.nextthink = time; +} + +void mark_error(vector where,float lifetime) +{ + entity err; + + err = spawn(); + err.classname = "error_marker"; + setmodel(err,"models/marker.md3"); + setorigin(err,where); + err.movetype = MOVETYPE_NONE; + err.think = marker_think; + err.nextthink = time; + err.skin = 0; + if(lifetime) + err.cnt = lifetime + time; +} + +void mark_info(vector where,float lifetime) +{ + entity err; + + err = spawn(); + err.classname = "info_marker"; + setmodel(err,"models/marker.md3"); + setorigin(err,where); + err.movetype = MOVETYPE_NONE; + err.think = marker_think; + err.nextthink = time; + err.skin = 1; + if(lifetime) + err.cnt = lifetime + time; +} + +entity mark_misc(vector where,float lifetime) +{ + entity err; + + err = spawn(); + err.classname = "mark_misc"; + setmodel(err,"models/marker.md3"); + setorigin(err,where); + err.movetype = MOVETYPE_NONE; + err.think = marker_think; + err.nextthink = time; + err.skin = 3; + if(lifetime) + err.cnt = lifetime + time; + return err; +} + +/* +* Paint a v_color colord circle on target onwho +* that fades away over f_time +*/ +void paint_target(entity onwho, float f_size, vector v_color, float f_time) +{ + entity e; + + e = spawn(); + setmodel(e, "models/turrets/c512.md3"); // precision set above + e.scale = (f_size/512); + //setsize(e, '0 0 0', '0 0 0'); + //setattachment(e,onwho,""); + setorigin(e,onwho.origin + '0 0 1'); + e.alpha = 0.15; + e.movetype = MOVETYPE_FLY; + + e.velocity = (v_color * 32); // + '0 0 1' * 64; + + e.colormod = v_color; + SUB_SetFade(e,time,f_time); +} + +void paint_target2(entity onwho, float f_size, vector v_color, float f_time) +{ + entity e; + + e = spawn(); + setmodel(e, "models/turrets/c512.md3"); // precision set above + e.scale = (f_size/512); + setsize(e, '0 0 0', '0 0 0'); + + setorigin(e,onwho.origin + '0 0 1'); + e.alpha = 0.15; + e.movetype = MOVETYPE_FLY; + + e.velocity = (v_color * 32); // + '0 0 1' * 64; + e.avelocity_x = -128; + + e.colormod = v_color; + SUB_SetFade(e,time,f_time); +} + +void paint_target3(vector where, float f_size, vector v_color, float f_time) +{ + entity e; + e = spawn(); + setmodel(e, "models/turrets/c512.md3"); // precision set above + e.scale = (f_size/512); + setsize(e, '0 0 0', '0 0 0'); + setorigin(e,where+ '0 0 1'); + e.movetype = MOVETYPE_NONE; + e.velocity = '0 0 0'; + e.colormod = v_color; + SUB_SetFade(e,time,f_time); } +#endif diff --git a/qcsrc/server/tturrets/system/system_scoreprocs.qc b/qcsrc/server/tturrets/system/system_scoreprocs.qc index c78a3e018..32c7856a3 100644 --- a/qcsrc/server/tturrets/system/system_scoreprocs.qc +++ b/qcsrc/server/tturrets/system/system_scoreprocs.qc @@ -30,7 +30,7 @@ float turret_stdproc_targetscore_support(entity e_turret,entity e_target) /* * Generic bias aware score system. */ -float turret_stdproc_targetscore_generic(entity e_turret,entity e_target) +float turret_stdproc_targetscore_generic(entity e_turret, entity e_target) { //vector v_tmp; float d_dist; // Defendmode Distance @@ -45,9 +45,10 @@ float turret_stdproc_targetscore_generic(entity e_turret,entity e_target) float ikr; // ideal kill range - if(!e_target) return 0; - - //if (e_target == e_turret.enemy) s_score = 1; + /* + if(!e_target) + return 0; + */ if (e_turret.tur_defend) { @@ -83,10 +84,10 @@ float turret_stdproc_targetscore_generic(entity e_turret,entity e_target) if ((e_turret.target_select_playerbias > 0) && (e_target.flags & FL_CLIENT)) p_score = 1; - d_score = max(d_score,0); - a_score = max(a_score,0); - m_score = max(m_score,0); - p_score = max(p_score,0); + d_score = max(d_score, 0); + a_score = max(a_score, 0); + m_score = max(m_score, 0); + p_score = max(p_score, 0); score = (d_score * e_turret.target_select_rangebias) + (a_score * e_turret.target_select_anglebias) + diff --git a/qcsrc/server/tturrets/units/unit_ewheel.qc b/qcsrc/server/tturrets/units/unit_ewheel.qc index 3d84386a4..aff4c0aec 100644 --- a/qcsrc/server/tturrets/units/unit_ewheel.qc +++ b/qcsrc/server/tturrets/units/unit_ewheel.qc @@ -59,12 +59,13 @@ void ewheel_attack() proj.bot_dodgerating = self.shot_dmg; proj.think = turret_ewheel_projectile_explode; proj.nextthink = time + 9; - proj.solid = SOLID_BBOX; + //proj.solid = SOLID_TRIGGER; proj.movetype = MOVETYPE_FLYMISSILE; proj.velocity = normalize(self.tur_shotdir_updated + randomvec() * self.shot_spread) * self.shot_speed; proj.touch = turret_ewheel_projectile_explode; proj.enemy = self.enemy; proj.flags = FL_PROJECTILE | FL_NOTARGET; + PROJECTILE_MAKETRIGGER(proj); CSQCProjectile(proj, TRUE, PROJECTILE_LASER, TRUE); @@ -285,7 +286,9 @@ void turret_ewheel_dinit() } self.target_select_flags = TFL_TARGETSELECT_PLAYERS | TFL_TARGETSELECT_RANGELIMTS | TFL_TARGETSELECT_TEAMCHECK | TFL_TARGETSELECT_LOS; + self.target_select_flags = TFL_TARGETSELECT_RANGELIMTS | TFL_TARGETSELECT_TEAMCHECK | TFL_TARGETSELECT_LOS; self.target_validate_flags = TFL_TARGETSELECT_PLAYERS | TFL_TARGETSELECT_RANGELIMTS | TFL_TARGETSELECT_TEAMCHECK;// | TFL_TARGETSELECT_LOS; + self.target_validate_flags = TFL_TARGETSELECT_RANGELIMTS | TFL_TARGETSELECT_TEAMCHECK;// | TFL_TARGETSELECT_LOS; self.damage_flags |= TFL_DMG_DEATH_NOGIBS; self.iscreature = TRUE; @@ -307,7 +310,7 @@ void turret_ewheel_dinit() self.tur_head.aim_speed = cvar("g_turrets_unit_ewheel_turnrate"); self.tur_head.aim_speed = self.tur_head.aim_speed / (1 / self.ticrate); - if (!turret_tag_setup()) + if (!turret_tag_fire_update()) dprint("Warning: Turret ",self.classname, " faild to initialize md3 tags\n"); //setorigin(self,self.origin + '0 0 128'); diff --git a/qcsrc/server/tturrets/units/unit_flac.qc b/qcsrc/server/tturrets/units/unit_flac.qc index 3d2c51fe9..0c874fb50 100644 --- a/qcsrc/server/tturrets/units/unit_flac.qc +++ b/qcsrc/server/tturrets/units/unit_flac.qc @@ -99,7 +99,7 @@ void turret_flac_dinit() self.damage_flags |= TFL_DMG_HEADSHAKE; self.target_select_flags |= TFL_TARGETSELECT_NOTURRETS | TFL_TARGETSELECT_MISSILESONLY; - if (!turret_tag_setup()) + if (!turret_tag_fire_update()) dprint("Warning: Turret ",self.classname, " faild to initialize md3 tags\n"); // Our fire routine diff --git a/qcsrc/server/tturrets/units/unit_hellion.qc b/qcsrc/server/tturrets/units/unit_hellion.qc index 0225c1653..b6408ed4f 100644 --- a/qcsrc/server/tturrets/units/unit_hellion.qc +++ b/qcsrc/server/tturrets/units/unit_hellion.qc @@ -17,21 +17,23 @@ void turret_hellion_postthink() } if (self.tur_head.frame != 0) - self.tur_head.frame = self.tur_head.frame + 1; + self.tur_head.frame += 1; - if (self.tur_head.frame > 7) + if (self.tur_head.frame >= 7) self.tur_head.frame = 0; } void turret_hellion_attack() { - local entity missile; - + entity missile; + + if(self.tur_head.frame != 0) + self.tur_shotorg = gettaginfo(self.tur_head, gettagindex(self.tur_head, "tag_fire")); + else + self.tur_shotorg = gettaginfo(self.tur_head, gettagindex(self.tur_head, "tag_fire2")); + sound (self, CHAN_WEAPON, "weapons/hagar_fire.wav", VOL_BASE, ATTN_NORM); - // switch tubes - //self.tur_shotorg_y = self.tur_shotorg_y * -1; - missile = spawn (); setorigin(missile, self.tur_shotorg); setsize (missile, '-3 -3 -3', '3 3 3'); // give it some size so it can be shot @@ -57,12 +59,9 @@ void turret_hellion_attack() missile.tur_health = time + 9; missile.tur_aimpos = randomvec() * 128; te_explosion (missile.origin); - CSQCProjectile(missile, FALSE, PROJECTILE_ROCKET, FALSE); // no culling, has fly sound - if (self.tur_head.frame == 0) - self.tur_head.frame = self.tur_head.frame + 1; - + self.tur_head.frame += 1; } void turret_hellion_missile_damage (entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector vforce) @@ -195,7 +194,7 @@ void turret_hellion_dinit() return; } - if (!turret_tag_setup()) + if (!turret_tag_fire_update()) dprint("Warning: Turret ",self.classname, " faild to initialize md3 tags\n"); self.turret_firefunc = turret_hellion_attack; diff --git a/qcsrc/server/tturrets/units/unit_hk.qc b/qcsrc/server/tturrets/units/unit_hk.qc index ac1e51ecd..cea4c13bd 100644 --- a/qcsrc/server/tturrets/units/unit_hk.qc +++ b/qcsrc/server/tturrets/units/unit_hk.qc @@ -417,7 +417,7 @@ void turret_hk_dinit() self.target_validate_flags = TFL_TARGETSELECT_PLAYERS | TFL_TARGETSELECT_TEAMCHECK; - if (!turret_tag_setup()) + if (!turret_tag_fire_update()) dprint("Warning: Turret ",self.classname, " faild to initialize md3 tags\n"); // Our fire routine diff --git a/qcsrc/server/tturrets/units/unit_machinegun.qc b/qcsrc/server/tturrets/units/unit_machinegun.qc index 777ad90a8..4777722da 100644 --- a/qcsrc/server/tturrets/units/unit_machinegun.qc +++ b/qcsrc/server/tturrets/units/unit_machinegun.qc @@ -34,12 +34,10 @@ void turret_machinegun_std_init() self.ammo_flags = TFL_AMMO_BULLETS | TFL_AMMO_RECHARGE | TFL_AMMO_RECIVE; self.turrcaps_flags = TFL_TURRCAPS_PLAYERKILL; - self.aim_flags = TFL_AIM_LEAD; - - if(cvar("g_antilag_bullets")) - self.turrcaps_flags |= TFL_TURRCAPS_HITSCAN; - else - self.aim_flags |= TFL_AIM_SHOTTIMECOMPENSATE; + self.aim_flags = TFL_AIM_LEAD | TFL_AIM_SHOTTIMECOMPENSATE; + + if not (cvar("g_antilag_bullets")) + self.turrcaps_flags |= TFL_TURRCAPS_HITSCAN; if (turret_stdproc_init("machinegun_std",0,"models/turrets/base.md3","models/turrets/machinegun.md3") == 0) { @@ -49,7 +47,7 @@ void turret_machinegun_std_init() self.damage_flags |= TFL_DMG_HEADSHAKE; - if (!turret_tag_setup()) + if (!turret_tag_fire_update()) dprint("Warning: Turret ",self.classname, " faild to initialize md3 tags\n"); // Our fire routine diff --git a/qcsrc/server/tturrets/units/unit_mlrs.qc b/qcsrc/server/tturrets/units/unit_mlrs.qc index e28b9b4aa..499d6de23 100644 --- a/qcsrc/server/tturrets/units/unit_mlrs.qc +++ b/qcsrc/server/tturrets/units/unit_mlrs.qc @@ -6,9 +6,14 @@ void turret_mlrs_rocket_touch(); void turret_mlrs_postthink() { - // 0 = full, 6 = empty - self.tur_head.frame = rint(6 - (self.ammo / self.shot_dmg)); + self.tur_head.frame = bound(0, 6 - floor(0.1 + self.ammo / self.shot_dmg), 6); + if(self.tur_head.frame < 0) + { + dprint("ammo:",ftos(self.ammo),"\n"); + dprint("shot_dmg:",ftos(self.shot_dmg),"\n"); + } + } void turret_mlrs_attack() @@ -106,7 +111,7 @@ void turret_mlrs_dinit() self.shoot_flags |= TFL_SHOOT_VOLLYALWAYS; self.volly_counter = self.shot_volly; - if (!turret_tag_setup()) + if (!turret_tag_fire_update()) dprint("Warning: Turret ",self.classname, " faild to initialize md3 tags\n"); // Our fire routine diff --git a/qcsrc/server/tturrets/units/unit_phaser.qc b/qcsrc/server/tturrets/units/unit_phaser.qc index e4c07b667..e454dadfb 100644 --- a/qcsrc/server/tturrets/units/unit_phaser.qc +++ b/qcsrc/server/tturrets/units/unit_phaser.qc @@ -114,7 +114,7 @@ void turret_phaser_dinit() self.turrcaps_flags = TFL_TURRCAPS_SNIPER|TFL_TURRCAPS_HITSCAN|TFL_TURRCAPS_PLAYERKILL; self.ammo_flags = TFL_AMMO_ENERGY | TFL_AMMO_RECHARGE | TFL_AMMO_RECIVE; - self.aim_flags = TFL_AIM_ZEASE | TFL_AIM_LEAD; + self.aim_flags = TFL_AIM_LEAD; if (turret_stdproc_init("phaser_std",0,"models/turrets/base.md3","models/turrets/phaser.md3") == 0) { @@ -122,7 +122,7 @@ void turret_phaser_dinit() return; } - if (!turret_tag_setup()) + if (!turret_tag_fire_update()) dprint("Warning: Turret ",self.classname, " faild to initialize md3 tags\n"); self.turret_firecheckfunc = turret_phaser_firecheck; diff --git a/qcsrc/server/tturrets/units/unit_plasma.qc b/qcsrc/server/tturrets/units/unit_plasma.qc index f79103b77..63466084a 100644 --- a/qcsrc/server/tturrets/units/unit_plasma.qc +++ b/qcsrc/server/tturrets/units/unit_plasma.qc @@ -133,7 +133,7 @@ void turret_plasma_std_init() self.damage_flags |= TFL_DMG_HEADSHAKE; self.firecheck_flags |= TFL_FIRECHECK_AFF; - if (!turret_tag_setup()) + if (!turret_tag_fire_update()) dprint("Warning: Turret ",self.classname, " faild to initialize md3 tags\n"); // Our fireing routine @@ -165,7 +165,7 @@ void turret_plasma_dual_init() self.damage_flags |= TFL_DMG_HEADSHAKE; self.firecheck_flags |= TFL_FIRECHECK_AFF; - if (!turret_tag_setup()) + if (!turret_tag_fire_update()) dprint("Warning: Turret ",self.classname, " faild to initialize md3 tags\n"); // Our fireing routine diff --git a/qcsrc/server/tturrets/units/unit_tessla.qc b/qcsrc/server/tturrets/units/unit_tessla.qc index 1d77c99eb..443cd8b56 100644 --- a/qcsrc/server/tturrets/units/unit_tessla.qc +++ b/qcsrc/server/tturrets/units/unit_tessla.qc @@ -155,7 +155,7 @@ void turret_tesla_dinit() self.target_validate_flags = TFL_TARGETSELECT_PLAYERS | TFL_TARGETSELECT_MISSILES | TFL_TARGETSELECT_RANGELIMTS | TFL_TARGETSELECT_TEAMCHECK; - if (!turret_tag_setup()) + if (!turret_tag_fire_update()) dprint("Warning: Turret ",self.classname, " faild to initialize md3 tags\n"); self.turret_firefunc = turret_tesla_fire; diff --git a/qcsrc/server/tturrets/units/unit_walker.qc b/qcsrc/server/tturrets/units/unit_walker.qc index e1341b460..e12bbb830 100644 --- a/qcsrc/server/tturrets/units/unit_walker.qc +++ b/qcsrc/server/tturrets/units/unit_walker.qc @@ -718,7 +718,7 @@ void turret_walker_dinit() return; } - if (!turret_tag_setup()) + if (!turret_tag_fire_update()) dprint("Warning: Turret ",self.classname, " faild to initialize md3 tags\n"); self.damage_flags |= TFL_DMG_DEATH_NOGIBS; diff --git a/qcsrc/server/vehicles/racer.qc b/qcsrc/server/vehicles/racer.qc index b929c425f..6f40e0b4d 100644 --- a/qcsrc/server/vehicles/racer.qc +++ b/qcsrc/server/vehicles/racer.qc @@ -398,11 +398,11 @@ float racer_pplug() ftmp2 = ftmp * -1; ftmp = bound(ftmp2, shortangle_f(player.v_angle_y - racer.angles_y, racer.angles_y), ftmp); - ftmp2 = safeangle(racer.angles_y + ftmp); + ftmp2 = anglemods(racer.angles_y + ftmp); // Roll ftmp = bound(-45, shortangle_f(player.v_angle_z + ((racer.angles_y - ftmp2) * racer_turnroll), racer.angles_z), 45); - ftmp = safeangle(racer.angles_z + ftmp); + ftmp = anglemods(racer.angles_z + ftmp); racer.angles_z = bound(-85, ftmp, 85); // Turn @@ -413,7 +413,7 @@ float racer_pplug() ftmp2 = ftmp * -1; ftmp = bound(ftmp2,shortangle_f(player.v_angle_x - racer.angles_x,racer.angles_x),ftmp); - racer.angles_x = safeangle(racer.angles_x + ftmp); + racer.angles_x = anglemods(racer.angles_x + ftmp); racer.angles_x *= -1; df = racer.velocity * -0.5; diff --git a/qcsrc/server/vehicles/raptor.qc b/qcsrc/server/vehicles/raptor.qc index 06392ec0d..ee6d3976f 100644 --- a/qcsrc/server/vehicles/raptor.qc +++ b/qcsrc/server/vehicles/raptor.qc @@ -458,14 +458,14 @@ float raptor_pplug() //vhic.angles_z = ftmp; // Turn - vhic.angles_y = safeangle(vhic.angles_y + ftmp); + vhic.angles_y = anglemods(vhic.angles_y + ftmp); // Pitch Body ftmp = raptor_pitchspeed * sys_frametime; ftmp = bound(-ftmp, shortangle_f(player.v_angle_x - vhic.angles_x,vhic.angles_x), ftmp); - vhic.angles_x = bound(-60,safeangle(vhic.angles_x + ftmp),60); + vhic.angles_x = bound(-60,anglemods(vhic.angles_x + ftmp),60); vhic.angles_x *= -1; if(raptor_movestyle == 1) diff --git a/qcsrc/server/vehicles/spiderbot.qc b/qcsrc/server/vehicles/spiderbot.qc index 32049c862..ba4360550 100644 --- a/qcsrc/server/vehicles/spiderbot.qc +++ b/qcsrc/server/vehicles/spiderbot.qc @@ -367,7 +367,7 @@ float spiderbot_pplug() } else { - spider.angles_y = safeangle(spider.angles_y + ftmp); + spider.angles_y = anglemods(spider.angles_y + ftmp); spider.tur_head.angles_y -= ftmp; if(player.movement_x != 0) diff --git a/qcsrc/server/w_all.qc b/qcsrc/server/w_all.qc index 9a9b38302..83fc8acb5 100644 --- a/qcsrc/server/w_all.qc +++ b/qcsrc/server/w_all.qc @@ -2,6 +2,7 @@ #include "w_shotgun.qc" #include "w_uzi.qc" #include "w_grenadelauncher.qc" +#include "w_minelayer.qc" #include "w_electro.qc" #include "w_crylink.qc" #include "w_nex.qc" diff --git a/qcsrc/server/w_campingrifle.qc b/qcsrc/server/w_campingrifle.qc index 1cd280e00..d0b6f4ed8 100644 --- a/qcsrc/server/w_campingrifle.qc +++ b/qcsrc/server/w_campingrifle.qc @@ -96,7 +96,10 @@ void W_CampingRifle_FireBullet(float pSpread, float pDamage, float pHeadshotAdde w_shotorg = self.origin + self.view_ofs + ((w_shotorg - self.origin - self.view_ofs) * v_forward) * v_forward; } - fireBallisticBullet(w_shotorg, w_shotdir, pSpread, pSpeed, pLifetime, pDamage, pHeadshotAddedDamage / pDamage, pForce, deathtype, (cvar("g_balance_campingrifle_tracer") ? EF_RED : EF_BLUE), 1, pBulletConstant); + if(deathtype & HITTYPE_SECONDARY) + fireBallisticBullet(w_shotorg, w_shotdir, pSpread, pSpeed, pLifetime, pDamage, pHeadshotAddedDamage / pDamage, pForce, deathtype, (cvar("g_balance_campingrifle_secondary_tracer") ? EF_RED : EF_BLUE), 1, pBulletConstant); + else + fireBallisticBullet(w_shotorg, w_shotdir, pSpread, pSpeed, pLifetime, pDamage, pHeadshotAddedDamage / pDamage, pForce, deathtype, (cvar("g_balance_campingrifle_primary_tracer") ? EF_RED : EF_BLUE), 1, pBulletConstant); endFireBallisticBullet(); if (cvar("g_casings") >= 2) diff --git a/qcsrc/server/w_common.qc b/qcsrc/server/w_common.qc index 442732058..99df7041b 100644 --- a/qcsrc/server/w_common.qc +++ b/qcsrc/server/w_common.qc @@ -511,6 +511,7 @@ void W_PrepareExplosionByDamage(entity attacker, void() explode) self.takedamage = DAMAGE_NO; self.event_damage = SUB_Null; self.owner = attacker; + self.realowner = attacker; // do not explode NOW but in the NEXT FRAME! // because recursive calls to RadiusDamage are not allowed diff --git a/qcsrc/server/w_crylink.qc b/qcsrc/server/w_crylink.qc index e9015f580..5d1721f78 100644 --- a/qcsrc/server/w_crylink.qc +++ b/qcsrc/server/w_crylink.qc @@ -4,8 +4,6 @@ REGISTER_WEAPON(CRYLINK, w_crylink, IT_CELLS, 6, WEP_FLAG_NORMAL | WEP_TYPE_SPLA #ifdef SVQC .float gravity; -.entity realowner; - .entity queuenext; .entity queueprev; diff --git a/qcsrc/server/w_electro.qc b/qcsrc/server/w_electro.qc index a98c5a915..2268ca7cb 100644 --- a/qcsrc/server/w_electro.qc +++ b/qcsrc/server/w_electro.qc @@ -216,23 +216,32 @@ float lgbeam_send(entity to, float sf) void lgbeam_think() { self.owner.prevlgfire = time; - if (self.owner.weaponentity.state != WS_INUSE || (self.owner.ammo_cells <= 0 && !(self.owner.items & IT_UNLIMITED_WEAPON_AMMO)) || self != self.owner.lgbeam || self.owner.deadflag != DEAD_NO || !self.owner.BUTTON_ATCK) + if (self != self.owner.lgbeam) { remove(self); return; } + if (self.owner.weaponentity.state != WS_INUSE || (self.owner.ammo_cells <= 0 && !(self.owner.items & IT_UNLIMITED_WEAPON_AMMO)) || self.owner.deadflag != DEAD_NO || !self.owner.BUTTON_ATCK) + { + if(self == self.owner.lgbeam) + self.owner.lgbeam = world; + remove(self); + return; + } self.nextthink = time; makevectors(self.owner.v_angle); - float dt; + float dt, f; dt = frametime; if not(self.owner.items & IT_UNLIMITED_WEAPON_AMMO) { if(cvar("g_balance_electro_primary_ammo")) - dt = min(frametime, self.owner.ammo_cells / cvar("g_balance_electro_primary_ammo")); - self.owner.ammo_cells = max(0, self.owner.ammo_cells - cvar("g_balance_electro_primary_ammo") * frametime); + { + dt = min(dt, self.owner.ammo_cells / cvar("g_balance_electro_primary_ammo")); + self.owner.ammo_cells = max(0, self.owner.ammo_cells - cvar("g_balance_electro_primary_ammo") * frametime); + } } W_SetupShot_Range(self.owner, TRUE, 0, "", cvar("g_balance_electro_primary_damage") * dt, cvar("g_balance_electro_primary_range")); @@ -243,8 +252,11 @@ void lgbeam_think() { vector force; force = w_shotdir * cvar("g_balance_electro_primary_force") + '0 0 1' * cvar("g_balance_electro_primary_force_up"); - Damage (trace_ent, self.owner, self.owner, cvar("g_balance_electro_primary_damage") * dt, WEP_ELECTRO, trace_endpos, force * dt); - Damage_RecordDamage(self.owner, WEP_ELECTRO, cvar("g_balance_electro_primary_damage") * dt); + + f = ExponentialFalloff(cvar("g_balance_electro_primary_falloff_mindist"), cvar("g_balance_electro_primary_falloff_maxdist"), cvar("g_balance_electro_primary_falloff_halflifedist"), vlen(WarpZone_UnTransformOrigin(WarpZone_trace_transform, trace_endpos) - w_shotorg)); + + Damage (trace_ent, self.owner, self.owner, cvar("g_balance_electro_primary_damage") * dt * f, WEP_ELECTRO, trace_endpos, force * dt); + Damage_RecordDamage(self.owner, WEP_ELECTRO, cvar("g_balance_electro_primary_damage") * dt * f); } W_Plasma_TriggerCombo(trace_endpos, cvar("g_balance_electro_primary_comboradius"), self.owner); @@ -352,7 +364,7 @@ float w_electro(float req) { if(cvar("g_balance_electro_lightning")) { - if (self.BUTTON_ATCK_prev == 0) + if ((!self.lgbeam) || wasfreed(self.lgbeam)) { W_Electro_Attack3(); } @@ -365,7 +377,14 @@ float w_electro(float req) weapon_thinkf(WFRAME_FIRE1, cvar("g_balance_electro_primary_animtime"), w_ready); } } else { - self.BUTTON_ATCK_prev = 0; + if(cvar("g_balance_electro_lightning")) + { + if (self.BUTTON_ATCK_prev != 0) + { + ATTACK_FINISHED(self) = time + cvar("g_balance_electro_primary_refire") * W_WeaponRateFactor(); + } + self.BUTTON_ATCK_prev = 0; + } } if (self.BUTTON_ATCK2) @@ -398,7 +417,7 @@ float w_electro(float req) else if (req == WR_CHECKAMMO1) { if(cvar("g_balance_electro_lightning")) - return self.ammo_cells >= cvar("g_balance_electro_primary_ammo") * cvar("g_balance_electro_primary_refire"); + return !cvar("g_balance_electro_primary_ammo") || (self.ammo_cells > 0); else return self.ammo_cells >= cvar("g_balance_electro_primary_ammo"); } diff --git a/qcsrc/server/w_fireball.qc b/qcsrc/server/w_fireball.qc index 368faecbf..6b98d37cd 100644 --- a/qcsrc/server/w_fireball.qc +++ b/qcsrc/server/w_fireball.qc @@ -323,13 +323,13 @@ float w_fireball(float req) { if (self.BUTTON_ATCK) if (time >= self.fireball_primarytime) - if (weapon_prepareattack(1, cvar("g_balance_fireball_primary_refire"))) + if (weapon_prepareattack(0, cvar("g_balance_fireball_primary_refire"))) { W_Fireball_Attack1_Frame0(); self.fireball_primarytime = time + cvar("g_balance_fireball_primary_refire2"); } if (self.BUTTON_ATCK2) - if (weapon_prepareattack(0, cvar("g_balance_fireball_secondary_refire"))) + if (weapon_prepareattack(1, cvar("g_balance_fireball_secondary_refire"))) { W_Fireball_Attack2(); weapon_thinkf(WFRAME_FIRE2, cvar("g_balance_fireball_secondary_animtime"), w_ready); @@ -378,7 +378,6 @@ float w_fireball(float req) } else if(req == WR_PRECACHE) { - precache_sound("weapons/fireball_impact.wav"); precache_sound("weapons/fireball_impact2.wav"); } else if (req == WR_SUICIDEMESSAGE) diff --git a/qcsrc/server/w_grenadelauncher.qc b/qcsrc/server/w_grenadelauncher.qc index 6848b2a5a..0bc08b8de 100644 --- a/qcsrc/server/w_grenadelauncher.qc +++ b/qcsrc/server/w_grenadelauncher.qc @@ -2,6 +2,9 @@ REGISTER_WEAPON(GRENADE_LAUNCHER, w_glauncher, IT_ROCKETS, 4, WEP_FLAG_NORMAL | WEP_FLAG_CANCLIMB | WEP_TYPE_SPLASH, BOT_PICKUP_RATING_MID, "gl", "grenadelauncher", "Mortar"); #else #ifdef SVQC +.float gl_detonate_later; +.float gl_bouncecnt; + void W_Grenade_Explode (void) { if(other.takedamage == DAMAGE_AIM) @@ -32,6 +35,10 @@ void W_Grenade_Explode2 (void) self.event_damage = SUB_Null; self.takedamage = DAMAGE_NO; + + if(self.movetype == MOVETYPE_NONE) + self.velocity = self.oldvelocity; + RadiusDamage (self, self.owner, cvar("g_balance_grenadelauncher_secondary_damage"), cvar("g_balance_grenadelauncher_secondary_edgedamage"), cvar("g_balance_grenadelauncher_secondary_radius"), world, cvar("g_balance_grenadelauncher_secondary_force"), self.projectiledeathtype, other); remove (self); @@ -48,10 +55,47 @@ void W_Grenade_Damage (entity inflictor, entity attacker, float damage, float de } } +void W_Grenade_Think1 (void) +{ + self.nextthink = time; + if (time > self.cnt) + { + other = world; + self.projectiledeathtype |= HITTYPE_BOUNCE; + W_Grenade_Explode (); + return; + } + if(self.gl_detonate_later && self.gl_bouncecnt >= cvar("g_balance_grenadelauncher_primary_remote_minbouncecnt")) + W_Grenade_Explode(); +} + void W_Grenade_Touch1 (void) { PROJECTILE_TOUCH; - if(cvar("g_balance_grenadelauncher_primary_sticky") && other.takedamage != DAMAGE_AIM) + if (other.takedamage == DAMAGE_AIM || cvar("g_balance_grenadelauncher_primary_type") == 0) // always explode when hitting a player, or if normal mortar projectile + { + self.use (); + } + else if (cvar("g_balance_grenadelauncher_primary_type") == 1) // bounce + { + float r; + r = random() * 6; + if(r < 1) + spamsound (self, CHAN_PROJECTILE, "weapons/grenade_bounce1.wav", VOL_BASE, ATTN_NORM); + else if(r < 2) + spamsound (self, CHAN_PROJECTILE, "weapons/grenade_bounce2.wav", VOL_BASE, ATTN_NORM); + else if(r < 3) + spamsound (self, CHAN_PROJECTILE, "weapons/grenade_bounce3.wav", VOL_BASE, ATTN_NORM); + else if(r < 4) + spamsound (self, CHAN_PROJECTILE, "weapons/grenade_bounce4.wav", VOL_BASE, ATTN_NORM); + else if(r < 5) + spamsound (self, CHAN_PROJECTILE, "weapons/grenade_bounce5.wav", VOL_BASE, ATTN_NORM); + else + spamsound (self, CHAN_PROJECTILE, "weapons/grenade_bounce6.wav", VOL_BASE, ATTN_NORM); + self.projectiledeathtype |= HITTYPE_BOUNCE; + self.gl_bouncecnt += 1; + } + else if(cvar("g_balance_grenadelauncher_primary_type") == 2 && (!other || (other.takedamage != DAMAGE_AIM && other.movetype == MOVETYPE_NONE))) // stick { spamsound (self, CHAN_PROJECTILE, "weapons/grenade_stick.wav", VOL_BASE, ATTN_NORM); @@ -67,14 +111,35 @@ void W_Grenade_Touch1 (void) self.nextthink = min(self.nextthink, time + cvar("g_balance_grenadelauncher_primary_lifetime2")); } - else - W_Grenade_Explode (); } void W_Grenade_Touch2 (void) { PROJECTILE_TOUCH; - if(cvar("g_balance_grenadelauncher_secondary_sticky") && other.takedamage != DAMAGE_AIM) + if (other.takedamage == DAMAGE_AIM || cvar("g_balance_grenadelauncher_secondary_type") == 0) // always explode when hitting a player, or if normal mortar projectile + { + self.use (); + } + else if (cvar("g_balance_grenadelauncher_secondary_type") == 1) // bounce + { + float r; + r = random() * 6; + if(r < 1) + spamsound (self, CHAN_PROJECTILE, "weapons/grenade_bounce1.wav", VOL_BASE, ATTN_NORM); + else if(r < 2) + spamsound (self, CHAN_PROJECTILE, "weapons/grenade_bounce2.wav", VOL_BASE, ATTN_NORM); + else if(r < 3) + spamsound (self, CHAN_PROJECTILE, "weapons/grenade_bounce3.wav", VOL_BASE, ATTN_NORM); + else if(r < 4) + spamsound (self, CHAN_PROJECTILE, "weapons/grenade_bounce4.wav", VOL_BASE, ATTN_NORM); + else if(r < 5) + spamsound (self, CHAN_PROJECTILE, "weapons/grenade_bounce5.wav", VOL_BASE, ATTN_NORM); + else + spamsound (self, CHAN_PROJECTILE, "weapons/grenade_bounce6.wav", VOL_BASE, ATTN_NORM); + self.projectiledeathtype |= HITTYPE_BOUNCE; + self.gl_bouncecnt += 1; + } + else if(cvar("g_balance_grenadelauncher_secondary_type") == 2 && (!other || (other.takedamage != DAMAGE_AIM && other.movetype == MOVETYPE_NONE))) // stick { spamsound (self, CHAN_PROJECTILE, "weapons/grenade_stick.wav", VOL_BASE, ATTN_NORM); @@ -90,31 +155,6 @@ void W_Grenade_Touch2 (void) self.nextthink = min(self.nextthink, time + cvar("g_balance_grenadelauncher_secondary_lifetime2")); } - else - { - if (other.takedamage == DAMAGE_AIM) - { - self.use (); - } - else - { - float r; - r = random() * 6; - if(r < 1) - spamsound (self, CHAN_PROJECTILE, "weapons/grenade_bounce1.wav", VOL_BASE, ATTN_NORM); - else if(r < 2) - spamsound (self, CHAN_PROJECTILE, "weapons/grenade_bounce2.wav", VOL_BASE, ATTN_NORM); - else if(r < 3) - spamsound (self, CHAN_PROJECTILE, "weapons/grenade_bounce3.wav", VOL_BASE, ATTN_NORM); - else if(r < 4) - spamsound (self, CHAN_PROJECTILE, "weapons/grenade_bounce4.wav", VOL_BASE, ATTN_NORM); - else if(r < 5) - spamsound (self, CHAN_PROJECTILE, "weapons/grenade_bounce5.wav", VOL_BASE, ATTN_NORM); - else - spamsound (self, CHAN_PROJECTILE, "weapons/grenade_bounce6.wav", VOL_BASE, ATTN_NORM); - self.projectiledeathtype |= HITTYPE_BOUNCE; - } - } } void W_Grenade_Attack (void) @@ -123,7 +163,7 @@ void W_Grenade_Attack (void) if not(self.items & IT_UNLIMITED_WEAPON_AMMO) self.ammo_rockets = self.ammo_rockets - cvar("g_balance_grenadelauncher_primary_ammo"); - W_SetupShot_ProjectileSize (self, '0 0 -3', '0 0 -3', FALSE, 4, "weapons/grenade_fire.wav", cvar("g_balance_grenadelauncher_primary_damage")); + W_SetupShot_ProjectileSize (self, '-3 -3 -3', '3 3 3', FALSE, 4, "weapons/grenade_fire.wav", cvar("g_balance_grenadelauncher_primary_damage")); w_shotdir = v_forward; // no TrueAim for grenades please pointparticles(particleeffectnum("grenadelauncher_muzzleflash"), w_shotorg, w_shotdir * 1000, 1); @@ -134,25 +174,32 @@ void W_Grenade_Attack (void) gren.bot_dodge = TRUE; gren.bot_dodgerating = cvar("g_balance_grenadelauncher_primary_damage"); gren.movetype = MOVETYPE_BOUNCE; + gren.bouncefactor = cvar("g_balance_grenadelauncher_primary_bouncefactor"); + gren.bouncestop = cvar("g_balance_grenadelauncher_primary_bouncestop"); PROJECTILE_MAKETRIGGER(gren); gren.projectiledeathtype = WEP_GRENADE_LAUNCHER; setorigin(gren, w_shotorg); - setsize(gren, '0 0 -3', '0 0 -3'); + setsize(gren, '-3 -3 -3', '3 3 3'); - gren.nextthink = time + cvar("g_balance_grenadelauncher_primary_lifetime"); - gren.think = adaptor_think2use_hittype_splash; + gren.cnt = time + cvar("g_balance_grenadelauncher_primary_lifetime"); + gren.nextthink = time; + gren.think = W_Grenade_Think1; gren.use = W_Grenade_Explode; gren.touch = W_Grenade_Touch1; gren.takedamage = DAMAGE_YES; gren.health = cvar("g_balance_grenadelauncher_primary_health"); + gren.damageforcescale = cvar("g_balance_grenadelauncher_primary_damageforcescale"); gren.event_damage = W_Grenade_Damage; W_SETUPPROJECTILEVELOCITY_UP(gren, g_balance_grenadelauncher_primary); gren.angles = vectoangles (gren.velocity); gren.flags = FL_PROJECTILE; - CSQCProjectile(gren, TRUE, PROJECTILE_GRENADE, TRUE); + if(cvar("g_balance_grenadelauncher_primary_type") == 0 || cvar("g_balance_grenadelauncher_primary_type") == 2) + CSQCProjectile(gren, TRUE, PROJECTILE_GRENADE, TRUE); + else + CSQCProjectile(gren, TRUE, PROJECTILE_GRENADE_BOUNCING, TRUE); } void W_Grenade_Attack2 (void) @@ -161,7 +208,7 @@ void W_Grenade_Attack2 (void) if not(self.items & IT_UNLIMITED_WEAPON_AMMO) self.ammo_rockets = self.ammo_rockets - cvar("g_balance_grenadelauncher_secondary_ammo"); - W_SetupShot_ProjectileSize (self, '0 0 -3', '0 0 -3', FALSE, 4, "weapons/grenade_fire.wav", cvar("g_balance_grenadelauncher_secondary_damage")); + W_SetupShot_ProjectileSize (self, '-3 -3 -3', '3 3 3', FALSE, 4, "weapons/grenade_fire.wav", cvar("g_balance_grenadelauncher_secondary_damage")); w_shotdir = v_forward; // no TrueAim for grenades please pointparticles(particleeffectnum("grenadelauncher_muzzleflash"), w_shotorg, w_shotdir * 1000, 1); @@ -177,7 +224,7 @@ void W_Grenade_Attack2 (void) PROJECTILE_MAKETRIGGER(gren); gren.projectiledeathtype = WEP_GRENADE_LAUNCHER | HITTYPE_SECONDARY; setorigin(gren, w_shotorg); - setsize(gren, '0 0 -3', '0 0 -3'); + setsize(gren, '-3 -3 -3', '3 3 3'); gren.nextthink = time + cvar("g_balance_grenadelauncher_secondary_lifetime"); gren.think = adaptor_think2use_hittype_splash; @@ -193,7 +240,7 @@ void W_Grenade_Attack2 (void) gren.angles = vectoangles (gren.velocity); gren.flags = FL_PROJECTILE; - if(cvar("g_balance_grenadelauncher_secondary_sticky")) + if(cvar("g_balance_grenadelauncher_secondary_type") == 0 || cvar("g_balance_grenadelauncher_secondary_type") == 2) CSQCProjectile(gren, TRUE, PROJECTILE_GRENADE, TRUE); else CSQCProjectile(gren, TRUE, PROJECTILE_GRENADE_BOUNCING, TRUE); @@ -207,6 +254,9 @@ void spawnfunc_weapon_grenadelauncher (void) .float bot_secondary_grenademooth; float w_glauncher(float req) { + entity nade; + float nadefound; + if (req == WR_AIM) { self.BUTTON_ATCK = FALSE; @@ -233,17 +283,30 @@ float w_glauncher(float req) if (self.BUTTON_ATCK) if (weapon_prepareattack(0, cvar("g_balance_grenadelauncher_primary_refire"))) { - if(cvar("g_balance_grenadelauncher_primary2secondary")) - W_Grenade_Attack2(); - else - W_Grenade_Attack(); + W_Grenade_Attack(); weapon_thinkf(WFRAME_FIRE1, cvar("g_balance_grenadelauncher_primary_animtime"), w_ready); } - if (self.BUTTON_ATCK2 && !cvar("g_balance_grenadelauncher_primary2secondary")) - if (weapon_prepareattack(1, cvar("g_balance_grenadelauncher_secondary_refire"))) + if (self.BUTTON_ATCK2) { - W_Grenade_Attack2(); - weapon_thinkf(WFRAME_FIRE2, cvar("g_balance_grenadelauncher_secondary_animtime"), w_ready); + if (cvar("g_balance_grenadelauncher_secondary_remote_detonateprimary")) + { + nadefound = 0; + for(nade = world; (nade = find(nade, classname, "grenade")); ) if(nade.owner == self) + { + if(!nade.gl_detonate_later) + { + nade.gl_detonate_later = TRUE; + nadefound = 1; + } + } + if(nadefound) + sound (self, CHAN_WEAPON2, "weapons/rocket_det.wav", VOL_BASE, ATTN_NORM); + } + else if (weapon_prepareattack(1, cvar("g_balance_grenadelauncher_secondary_refire"))) + { + W_Grenade_Attack2(); + weapon_thinkf(WFRAME_FIRE2, cvar("g_balance_grenadelauncher_secondary_animtime"), w_ready); + } } } else if (req == WR_PRECACHE) diff --git a/qcsrc/server/w_minelayer.qc b/qcsrc/server/w_minelayer.qc new file mode 100644 index 000000000..8c81d89f7 --- /dev/null +++ b/qcsrc/server/w_minelayer.qc @@ -0,0 +1,451 @@ +#ifdef REGISTER_WEAPON +REGISTER_WEAPON(MINE_LAYER, w_minelayer, IT_ROCKETS, 4, WEP_FLAG_NORMAL | WEP_TYPE_SPLASH, BOT_PICKUP_RATING_HIGH, "minelayer", "minelayer", "Mine Layer"); +#else +#ifdef SVQC +void W_Mine_Think (void); +.float minelayer_detonate, minelayer_mines; +.float mine_time; + +void spawnfunc_weapon_minelayer (void) +{ + weapon_defaultspawnfunc(WEP_MINE_LAYER); +} + +void W_Mine_Stick () +{ + spamsound (self, CHAN_PROJECTILE, "weapons/mine_stick.wav", VOL_BASE, ATTN_NORM); + + // in order for mines to face properly when sticking to the ground, they must be a server side entity rather than a csqc projectile + + entity newmine; + newmine = spawn(); + newmine.classname = self.classname; + + newmine.bot_dodge = self.bot_dodge; + newmine.bot_dodgerating = self.bot_dodgerating; + + newmine.owner = self.owner; + setsize(newmine, '-4 -4 -4', '4 4 4'); + setorigin(newmine, self.origin); + setmodel(newmine, "models/mine.md3"); + newmine.angles = vectoangles(-trace_plane_normal); // face against the surface + + newmine.takedamage = self.takedamage; + newmine.damageforcescale = self.damageforcescale; + newmine.health = self.health; + newmine.event_damage = self.event_damage; + + newmine.movetype = MOVETYPE_NONE; // lock the mine in place + newmine.projectiledeathtype = self.projectiledeathtype; + + newmine.mine_time = self.mine_time; + + newmine.touch = SUB_Null; + newmine.think = W_Mine_Think; + newmine.nextthink = time; + newmine.cnt = self.cnt; + newmine.flags = self.flags; + + remove(self); + self = newmine; +} + +void W_Mine_Explode () +{ + if(other.takedamage == DAMAGE_AIM) + if(other.classname == "player") + if(IsDifferentTeam(self.owner, other)) + if(IsFlying(other)) + AnnounceTo(self.owner, "airshot"); + + self.event_damage = SUB_Null; + self.takedamage = DAMAGE_NO; + + RadiusDamage (self, self.owner, cvar("g_balance_minelayer_damage"), cvar("g_balance_minelayer_edgedamage"), cvar("g_balance_minelayer_radius"), world, cvar("g_balance_minelayer_force"), self.projectiledeathtype, other); + + if (self.owner.weapon == WEP_MINE_LAYER) + { + if(self.owner.ammo_rockets < cvar("g_balance_minelayer_ammo")) + { + self.owner.cnt = WEP_MINE_LAYER; + ATTACK_FINISHED(self.owner) = time; + self.owner.switchweapon = w_getbestweapon(self.owner); + } + } + remove (self); +} + +void W_Mine_DoRemoteExplode () +{ + self.event_damage = SUB_Null; + self.takedamage = DAMAGE_NO; + + RadiusDamage (self, self.owner, cvar("g_balance_minelayer_remote_damage"), cvar("g_balance_minelayer_remote_edgedamage"), cvar("g_balance_minelayer_remote_radius"), world, cvar("g_balance_minelayer_remote_force"), self.projectiledeathtype | HITTYPE_BOUNCE, world); + + if (self.owner.weapon == WEP_MINE_LAYER) + { + if(self.owner.ammo_rockets < cvar("g_balance_minelayer_ammo")) + { + self.owner.cnt = WEP_MINE_LAYER; + ATTACK_FINISHED(self.owner) = time; + self.owner.switchweapon = w_getbestweapon(self.owner); + } + } + remove (self); +} + +void W_Mine_RemoteExplode () +{ + if(self.owner.deadflag == DEAD_NO) + if((self.spawnshieldtime >= 0) + ? (time >= self.spawnshieldtime) // timer + : (vlen(NearestPointOnBox(self.owner, self.origin) - self.origin) > cvar("g_balance_minelayer_radius")) // safety device + ) + { + W_Mine_DoRemoteExplode(); + } +} + +void W_Mine_ProximityExplode () +{ + // make sure no friend is in the mine's radius. If there is any, explosion is delayed until he's at a safe distance + if(cvar("g_balance_minelayer_protection")) + { + entity head; + head = findradius(self.origin, cvar("g_balance_minelayer_radius")); + while(head) + { + if(head == self.owner || !IsDifferentTeam(head, self.owner)) + return; + head = head.chain; + } + } + + self.mine_time = 0; + W_Mine_Explode(); +} + +void W_Mine_Think (void) +{ + entity head; + + self.nextthink = time; + if (time > self.cnt) + { + other = world; + self.projectiledeathtype |= HITTYPE_BOUNCE; + W_Mine_Explode(); + return; + } + + // a player's mines shall explode if he disconnects or dies + // TODO: Do this on team change too + if(self.owner.classname != "player" || self.owner.deadflag != DEAD_NO) + { + other = world; + self.projectiledeathtype |= HITTYPE_BOUNCE; + W_Mine_Explode(); + return; + } + + // set the mine for detonation when a foe gets close enough + head = findradius(self.origin, cvar("g_balance_minelayer_proximityradius")); + while(head) + { + if(head.classname == "player" && head.deadflag == DEAD_NO) + if(head != self.owner && IsDifferentTeam(head, self.owner)) // don't trigger for team mates + if(!self.mine_time) + { + spamsound (self, CHAN_PROJECTILE, "weapons/mine_trigger.wav", VOL_BASE, ATTN_NORM); + self.mine_time = time + cvar("g_balance_minelayer_time"); + } + head = head.chain; + } + + // explode if it's time to + if(self.mine_time && time >= self.mine_time) + W_Mine_ProximityExplode(); + + // remote detonation + if (self.owner.weapon == WEP_MINE_LAYER) + if (self.owner.deadflag == DEAD_NO) + if (self.minelayer_detonate) + W_Mine_RemoteExplode(); + + if(self.csqcprojectile_clientanimate == 0) + UpdateCSQCProjectile(self); +} + +void W_Mine_Touch (void) +{ + PROJECTILE_TOUCH; + if(!other || (other.takedamage != DAMAGE_AIM && other.movetype == MOVETYPE_NONE)) + W_Mine_Stick(); + else if(self.movetype != MOVETYPE_NONE) // don't unstick a locked mine when someone touches it + self.velocity = '0 0 0'; +} + +void W_Mine_Damage (entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector force) +{ + if (self.health <= 0) + return; + self.health = self.health - damage; + self.angles = vectoangles(self.velocity); + if (self.health <= 0) + W_PrepareExplosionByDamage(attacker, W_Mine_Explode); +} + +void W_Mine_Attack (void) +{ + entity mine; + entity flash; + + // scan how many mines we placed, and return if we reached our limit + if(cvar("g_balance_minelayer_limit")) + { + self.minelayer_mines = 0; + for(mine = world; (mine = find(mine, classname, "mine")); ) if(mine.owner == self) + self.minelayer_mines += 1; + + if(self.minelayer_mines >= cvar("g_balance_minelayer_limit")) + { + // the refire delay keeps this message from being spammed + sprint(self, strcat("You cannot place more than ^2", cvar_string("g_balance_minelayer_limit"), " ^7mines at a time\n") ); + play2(self, "weapons/unavailable.wav"); + return; + } + } + + if not(self.items & IT_UNLIMITED_WEAPON_AMMO) + self.ammo_rockets = self.ammo_rockets - cvar("g_balance_minelayer_ammo"); + + W_SetupShot_ProjectileSize (self, '-4 -4 -4', '4 4 4', FALSE, 5, "weapons/mine_fire.wav", cvar("g_balance_minelayer_damage")); + pointparticles(particleeffectnum("rocketlauncher_muzzleflash"), w_shotorg, w_shotdir * 1000, 1); + + mine = WarpZone_RefSys_SpawnSameRefSys(self); + mine.owner = self; + if(cvar("g_balance_minelayer_detonatedelay") >= 0) + mine.spawnshieldtime = time + cvar("g_balance_minelayer_detonatedelay"); + else + mine.spawnshieldtime = -1; + mine.classname = "mine"; + mine.bot_dodge = TRUE; + mine.bot_dodgerating = cvar("g_balance_minelayer_damage") * 2; // * 2 because it can detonate inflight which makes it even more dangerous + + mine.takedamage = DAMAGE_YES; + mine.damageforcescale = cvar("g_balance_minelayer_damageforcescale"); + mine.health = cvar("g_balance_minelayer_health"); + mine.event_damage = W_Mine_Damage; + + mine.movetype = MOVETYPE_TOSS; + PROJECTILE_MAKETRIGGER(mine); + mine.projectiledeathtype = WEP_MINE_LAYER; + setsize (mine, '-4 -4 -4', '4 4 4'); // give it some size so it can be shot + + setorigin (mine, w_shotorg - v_forward * 4); // move it back so it hits the wall at the right point + W_SetupProjectileVelocity(mine, cvar("g_balance_minelayer_speed"), 0); + mine.angles = vectoangles (mine.velocity); + + mine.touch = W_Mine_Touch; + mine.think = W_Mine_Think; + mine.nextthink = time; + mine.cnt = time + cvar("g_balance_minelayer_lifetime"); + mine.flags = FL_PROJECTILE; + + CSQCProjectile(mine, FALSE, PROJECTILE_MINE, TRUE); + + // muzzle flash for 1st person view + flash = spawn (); + setmodel (flash, "models/flash.md3"); // precision set below + SUB_SetFade (flash, time, 0.1); + flash.effects = EF_ADDITIVE | EF_FULLBRIGHT | EF_LOWPRECISION; + W_AttachToShotorg(flash, '5 0 0'); + + // common properties +} + +void spawnfunc_weapon_minelayer (void); // defined in t_items.qc + +float w_minelayer(float req) +{ + entity mine; + float minfound; + if (req == WR_AIM) + { + // aim and decide to fire if appropriate + self.BUTTON_ATCK = bot_aim(cvar("g_balance_minelayer_speed"), 0, cvar("g_balance_minelayer_lifetime"), FALSE); + if(skill >= 2) // skill 0 and 1 bots won't detonate mines! + { + // decide whether to detonate mines + entity targetlist, targ; + float edgedamage, coredamage, edgeradius, recipricoledgeradius, d; + float selfdamage, teamdamage, enemydamage; + edgedamage = cvar("g_balance_minelayer_edgedamage"); + coredamage = cvar("g_balance_minelayer_damage"); + edgeradius = cvar("g_balance_minelayer_radius"); + recipricoledgeradius = 1 / edgeradius; + selfdamage = 0; + teamdamage = 0; + enemydamage = 0; + targetlist = findchainfloat(bot_attack, TRUE); + mine = find(world, classname, "mine"); + while (mine) + { + if (mine.owner != self) + { + mine = find(mine, classname, "mine"); + continue; + } + targ = targetlist; + while (targ) + { + d = vlen(targ.origin + (targ.mins + targ.maxs) * 0.5 - mine.origin); + d = bound(0, edgedamage + (coredamage - edgedamage) * sqrt(1 - d * recipricoledgeradius), 10000); + // count potential damage according to type of target + if (targ == self) + selfdamage = selfdamage + d; + else if (targ.team == self.team && teams_matter) + teamdamage = teamdamage + d; + else if (bot_shouldattack(targ)) + enemydamage = enemydamage + d; + targ = targ.chain; + } + mine = find(mine, classname, "mine"); + } + float desirabledamage; + desirabledamage = enemydamage; + if (teamplay != 1 && time > self.invincible_finished && time > self.spawnshieldtime) + desirabledamage = desirabledamage - selfdamage * cvar("g_balance_selfdamagepercent"); + if (self.team && teamplay != 1) + desirabledamage = desirabledamage - teamdamage; + + mine = find(world, classname, "mine"); + while (mine) + { + if (mine.owner != self) + { + mine = find(mine, classname, "mine"); + continue; + } + makevectors(mine.v_angle); + targ = targetlist; + if (skill > 9) // normal players only do this for the target they are tracking + { + targ = targetlist; + while (targ) + { + if ( + (v_forward * normalize(mine.origin - targ.origin)< 0.1) + && desirabledamage > 0.1*coredamage + )self.BUTTON_ATCK2 = TRUE; + targ = targ.chain; + } + }else{ + float distance; distance= bound(300,vlen(self.origin-self.enemy.origin),30000); + //As the distance gets larger, a correct detonation gets near imposible + //Bots are assumed to use the mine spawnfunc_light to see if the mine gets near a player + if(v_forward * normalize(mine.origin - self.enemy.origin)< 0.1) + if(self.enemy.classname == "player") + if(desirabledamage >= 0.1*coredamage) + if(random()/distance*300 > frametime*bound(0,(10-skill)*0.2,1)) + self.BUTTON_ATCK2 = TRUE; + // dprint(ftos(random()/distance*300),">");dprint(ftos(frametime*bound(0,(10-skill)*0.2,1)),"\n"); + } + + mine = find(mine, classname, "mine"); + } + // if we would be doing at X percent of the core damage, detonate it + // but don't fire a new shot at the same time! + if (desirabledamage >= 0.75 * coredamage) //this should do group damage in rare fortunate events + self.BUTTON_ATCK2 = TRUE; + if ((skill > 6.5) && (selfdamage > self.health)) + self.BUTTON_ATCK2 = FALSE; + //if(self.BUTTON_ATCK2 == TRUE) + // dprint(ftos(desirabledamage),"\n"); + if (self.BUTTON_ATCK2 == TRUE) self.BUTTON_ATCK = FALSE; + } + } + else if (req == WR_THINK) + { + if (self.BUTTON_ATCK) + { + if(weapon_prepareattack(0, cvar("g_balance_minelayer_refire"))) + { + W_Mine_Attack(); + weapon_thinkf(WFRAME_FIRE1, cvar("g_balance_minelayer_animtime"), w_ready); + } + } + + if (self.BUTTON_ATCK2) + { + minfound = 0; + for(mine = world; (mine = find(mine, classname, "mine")); ) if(mine.owner == self) + { + if(!mine.minelayer_detonate) + { + mine.minelayer_detonate = TRUE; + minfound = 1; + } + } + if(minfound) + sound (self, CHAN_WEAPON2, "weapons/mine_det.wav", VOL_BASE, ATTN_NORM); + } + } + else if (req == WR_PRECACHE) + { + precache_model ("models/flash.md3"); + precache_model ("models/mine.md3"); + precache_model ("models/weapons/g_minelayer.md3"); + precache_model ("models/weapons/v_minelayer.md3"); + precache_model ("models/weapons/h_minelayer.iqm"); + precache_sound ("weapons/mine_det.wav"); + precache_sound ("weapons/mine_fire.wav"); + precache_sound ("weapons/mine_stick.wav"); + precache_sound ("weapons/mine_trigger.wav"); + } + else if (req == WR_SETUP) + { + weapon_setup(WEP_MINE_LAYER); + } + else if (req == WR_CHECKAMMO1) + { + // don't switch while placing a mine + if ((ATTACK_FINISHED(self) <= time || self.weapon != WEP_MINE_LAYER) + && self.ammo_rockets < cvar("g_balance_minelayer_ammo")) + return FALSE; + } + else if (req == WR_CHECKAMMO2) + return FALSE; + return TRUE; +}; +#endif +#ifdef CSQC +float w_minelayer(float req) +{ + if(req == WR_IMPACTEFFECT) + { + vector org2; + org2 = w_org + w_backoff * 12; + pointparticles(particleeffectnum("rocket_explode"), org2, '0 0 0', 1); + if(!w_issilent) + sound(self, CHAN_PROJECTILE, "weapons/mine_exp.wav", VOL_BASE, ATTN_NORM); + } + else if(req == WR_PRECACHE) + { + precache_sound("weapons/mine_exp.wav"); + } + else if (req == WR_SUICIDEMESSAGE) + w_deathtypestring = "%s exploded"; + else if (req == WR_KILLMESSAGE) + { + if(w_deathtype & HITTYPE_BOUNCE) // (remote detonation) + w_deathtypestring = "%s got too close to %s's mine"; + else if(w_deathtype & HITTYPE_SPLASH) + w_deathtypestring = "%s almost dodged %s's mine"; + else + w_deathtypestring = "%s stepped on %s's mine"; + } + return TRUE; +} +#endif +#endif diff --git a/qcsrc/server/w_nex.qc b/qcsrc/server/w_nex.qc index a6ec07d6a..61af784e0 100644 --- a/qcsrc/server/w_nex.qc +++ b/qcsrc/server/w_nex.qc @@ -2,23 +2,23 @@ REGISTER_WEAPON(NEX, w_nex, IT_CELLS, 7, WEP_FLAG_NORMAL | WEP_TYPE_HITSCAN, BOT_PICKUP_RATING_HIGH, "nex", "nex", "Nex"); #else #ifdef SVQC -void SendCSQCNexBeamParticle() { +void SendCSQCNexBeamParticle(float charge) { vector v; v = WarpZone_UnTransformOrigin(WarpZone_trace_transform, trace_endpos); WriteByte(MSG_BROADCAST, SVC_TEMPENTITY); WriteByte(MSG_BROADCAST, TE_CSQC_NEXGUNBEAMPARTICLE); - WriteCoord(MSG_BROADCAST, w_shotorg_x); WriteCoord(MSG_BROADCAST, w_shotorg_y); WriteCoord(MSG_BROADCAST, w_shotorg_z); WriteCoord(MSG_BROADCAST, v_x); WriteCoord(MSG_BROADCAST, v_y); WriteCoord(MSG_BROADCAST, v_z); + WriteByte(MSG_BROADCAST, bound(0, 255 * charge, 255)); } void W_Nex_Attack (float issecondary) { - float mydmg, myforce, mymindist, mymaxdist, myhalflife, myforcehalflife, myammo; + float mydmg, myforce, mymindist, mymaxdist, myhalflife, myforcehalflife, myammo, charge; if(issecondary) { mydmg = cvar("g_balance_nex_secondary_damage"); @@ -43,6 +43,16 @@ void W_Nex_Attack (float issecondary) float flying; flying = IsFlying(self); // do this BEFORE to make the trace values from FireRailgunBullet last + if(cvar("g_balance_nex_charge")) + { + charge = self.nex_charge; + self.nex_charge *= cvar("g_balance_nex_charge_shot_multiplier"); // do this AFTER setting mydmg/myforce + } + else + charge = 1; + mydmg *= charge; + myforce *= charge; + W_SetupShot (self, TRUE, 5, "weapons/nexfire.wav", mydmg); yoda = 0; @@ -52,7 +62,7 @@ void W_Nex_Attack (float issecondary) AnnounceTo(self, "yoda"); //beam and muzzle flash done on client - SendCSQCNexBeamParticle(); + SendCSQCNexBeamParticle(charge); // flash and burn the wall if (trace_ent.solid == SOLID_BSP && !(trace_dphitq3surfaceflags & Q3SURFACEFLAG_NOIMPACT)) @@ -66,6 +76,7 @@ void spawnfunc_weapon_nex (void); // defined in t_items.qc float w_nex(float req) { + float dt; if (req == WR_AIM) { self.BUTTON_ATCK = bot_aim(1000000, 0, 1, FALSE); @@ -73,6 +84,8 @@ float w_nex(float req) } else if (req == WR_THINK) { + if(cvar("g_balance_nex_charge") && self.nex_charge < cvar("g_balance_nex_charge_limit")) + self.nex_charge = min(1, self.nex_charge + cvar("g_balance_nex_charge_rate") * frametime / W_TICSPERFRAME); if (self.BUTTON_ATCK) { if (weapon_prepareattack(0, cvar("g_balance_nex_primary_refire"))) @@ -83,7 +96,28 @@ float w_nex(float req) } if (self.BUTTON_ATCK2) { - if(cvar("g_balance_nex_secondary")) + if(cvar("g_balance_nex_secondary_charge")) + { + dt = frametime / W_TICSPERFRAME; + if(self.nex_charge < 1) + { + dt = min(dt, (1 - self.nex_charge) / cvar("g_balance_nex_secondary_charge_rate")); + if not(self.items & IT_UNLIMITED_WEAPON_AMMO) + { + if(cvar("g_balance_nex_secondary_ammo")) + { + dt = min(dt, (self.ammo_cells - cvar("g_balance_nex_primary_ammo")) / cvar("g_balance_nex_secondary_ammo")); + dt = max(0, dt); + if(dt > 0) + { + self.ammo_cells = max(cvar("g_balance_nex_secondary_ammo"), self.ammo_cells - cvar("g_balance_nex_secondary_ammo") * dt); + } + } + } + self.nex_charge += dt * cvar("g_balance_nex_secondary_charge_rate"); + } + } + else if(cvar("g_balance_nex_secondary")) { if (weapon_prepareattack(0, cvar("g_balance_nex_secondary_refire"))) { @@ -109,7 +143,11 @@ float w_nex(float req) else if (req == WR_CHECKAMMO1) return self.ammo_cells >= cvar("g_balance_nex_primary_ammo"); else if (req == WR_CHECKAMMO2) + { + if(cvar("g_balance_nex_secondary_charge")) + return self.ammo_cells >= cvar("g_balance_nex_primary_ammo"); return self.ammo_cells >= cvar("g_balance_nex_secondary_ammo"); + } return TRUE; }; #endif diff --git a/qcsrc/server/w_rocketlauncher.qc b/qcsrc/server/w_rocketlauncher.qc index d4056763a..12f7647e5 100644 --- a/qcsrc/server/w_rocketlauncher.qc +++ b/qcsrc/server/w_rocketlauncher.qc @@ -291,9 +291,13 @@ void W_Rocket_Think (void) void W_Rocket_Touch (void) { + if(WarpZone_Projectile_Touch()) + { + if(wasfreed(self)) + W_Rocket_Unregister(); + return; + } W_Rocket_Unregister(); - - PROJECTILE_TOUCH; W_Rocket_Explode (); } diff --git a/qcsrc/server/w_shotgun.qc b/qcsrc/server/w_shotgun.qc index b186230ec..f47077a25 100644 --- a/qcsrc/server/w_shotgun.qc +++ b/qcsrc/server/w_shotgun.qc @@ -65,12 +65,12 @@ void shotgun_meleethink (void) WarpZone_traceline_antilag(self.owner, self.owner.origin + self.owner.view_ofs, targpos, FALSE, self.owner, ANTILAG_LATENCY(self.owner)); // apply the damage, also remove self - if(trace_fraction < 1 && trace_ent.takedamage == DAMAGE_AIM && trace_ent.classname == "player") + if(trace_fraction < 1 && trace_ent.takedamage == DAMAGE_AIM && (trace_ent.classname == "player" || trace_ent.classname == "body")) { vector force; force = angle * cvar("g_balance_shotgun_secondary_force"); - Damage (trace_ent, self.owner, self.owner, cvar("g_balance_shotgun_secondary_damage") * ((f + 1) / 2), WEP_SHOTGUN | HITTYPE_SECONDARY , self.owner.origin + self.owner.view_ofs, force); - Damage_RecordDamage(self.owner, WEP_SHOTGUN | HITTYPE_SECONDARY, cvar("g_balance_shotgun_secondary_damage") * ((f + 1) / 2)); + Damage (trace_ent, self.owner, self.owner, cvar("g_balance_shotgun_secondary_damage") * min(1, f + 1), WEP_SHOTGUN | HITTYPE_SECONDARY , self.owner.origin + self.owner.view_ofs, force); + Damage_RecordDamage(self.owner, WEP_SHOTGUN | HITTYPE_SECONDARY, cvar("g_balance_shotgun_secondary_damage") * min(1, f + 1)); remove(self); } else if(time >= self.cnt + cvar("g_balance_shotgun_secondary_melee_time")) // missed, remove ent @@ -94,6 +94,8 @@ void W_Shotgun_Attack2 (void) void spawnfunc_weapon_shotgun(); // defined in t_items.qc +.float shotgun_primarytime; + float w_shotgun(float req) { if (req == WR_AIM) @@ -104,10 +106,16 @@ float w_shotgun(float req) else if (req == WR_THINK) { if (self.BUTTON_ATCK) - if (weapon_prepareattack(0, cvar("g_balance_shotgun_primary_refire"))) { - W_Shotgun_Attack(); - weapon_thinkf(WFRAME_FIRE1, cvar("g_balance_shotgun_primary_animtime"), w_ready); + if (time >= self.shotgun_primarytime) // handle refire separately so the secondary can be fired straight after a primary + { + if(weapon_prepareattack(0, cvar("g_balance_shotgun_primary_animtime"))) + { + W_Shotgun_Attack(); + self.shotgun_primarytime = time + cvar("g_balance_shotgun_primary_refire"); + weapon_thinkf(WFRAME_FIRE1, cvar("g_balance_shotgun_primary_animtime"), w_ready); + } + } } if (self.BUTTON_ATCK2 && cvar("g_balance_shotgun_secondary")) if (weapon_prepareattack(1, cvar("g_balance_shotgun_secondary_refire"))) diff --git a/qcsrc/warpzonelib/client.qc b/qcsrc/warpzonelib/client.qc index d084e0808..725f84ffb 100644 --- a/qcsrc/warpzonelib/client.qc +++ b/qcsrc/warpzonelib/client.qc @@ -1,5 +1,20 @@ +void WarpZone_Fade_PreDraw() +{ + if(self.warpzone_fadestart) + self.alpha = bound(0, (self.warpzone_fadeend - vlen(view_origin - self.origin - 0.5 * (self.mins + self.maxs))) / (self.warpzone_fadeend - self.warpzone_fadestart), 1); + else + self.alpha = 1; + //print(sprintf("%v <-> %v\n", view_origin, self.origin + 0.5 * (self.mins + self.maxs))); + if(self.alpha <= 0) + self.drawmask = 0; + else + self.drawmask = MASK_NORMAL; +} + void WarpZone_Read(float isnew) { + float f; + ++warpzone_warpzones_exist; if not(self.enemy) { @@ -8,10 +23,16 @@ void WarpZone_Read(float isnew) } self.classname = "trigger_warpzone"; - self.warpzone_isboxy = ReadByte(); - self.origin_x = ReadCoord(); - self.origin_y = ReadCoord(); - self.origin_z = ReadCoord(); + f = ReadByte(); + self.warpzone_isboxy = (f & 1); + if(f & 4) + { + self.origin_x = ReadCoord(); + self.origin_y = ReadCoord(); + self.origin_z = ReadCoord(); + } + else + self.origin = '0 0 0'; self.modelindex = ReadShort(); self.mins_x = ReadCoord(); self.mins_y = ReadCoord(); @@ -33,25 +54,48 @@ void WarpZone_Read(float isnew) self.avelocity_y = ReadCoord(); self.avelocity_z = ReadCoord(); + if(f & 2) + { + self.warpzone_fadestart = ReadShort(); + self.warpzone_fadeend = max(self.warpzone_fadestart + 1, ReadShort()); + } + else + { + self.warpzone_fadestart = 0; + self.warpzone_fadeend = 0; + } + // common stuff WarpZone_SetUp(self, self.enemy.oldorigin, self.enemy.avelocity, self.oldorigin, self.avelocity); - // engine currently wants this - self.drawmask = MASK_NORMAL; - // link me //setmodel(self, self.model); setorigin(self, self.origin); setsize(self, self.mins, self.maxs); + + // how to draw + // engine currently wants this + if(self.warpzone_fadestart) + self.predraw = WarpZone_Fade_PreDraw; + else + self.drawmask = MASK_NORMAL; } void WarpZone_Camera_Read(float isnew) { + float f; ++warpzone_cameras_exist; self.classname = "func_warpzone_camera"; - self.origin_x = ReadCoord(); - self.origin_y = ReadCoord(); - self.origin_z = ReadCoord(); + + f = ReadByte(); + if(f & 4) + { + self.origin_x = ReadCoord(); + self.origin_y = ReadCoord(); + self.origin_z = ReadCoord(); + } + else + self.origin = '0 0 0'; self.modelindex = ReadShort(); self.mins_x = ReadCoord(); self.mins_y = ReadCoord(); @@ -67,6 +111,17 @@ void WarpZone_Camera_Read(float isnew) self.avelocity_y = ReadCoord(); self.avelocity_z = ReadCoord(); + if(f & 2) + { + self.warpzone_fadestart = ReadShort(); + self.warpzone_fadeend = max(self.warpzone_fadestart + 1, ReadShort()); + } + else + { + self.warpzone_fadestart = 0; + self.warpzone_fadeend = 0; + } + // common stuff WarpZone_Camera_SetUp(self, self.oldorigin, self.avelocity); @@ -77,6 +132,13 @@ void WarpZone_Camera_Read(float isnew) //setmodel(self, self.model); setorigin(self, self.origin); setsize(self, self.mins, self.maxs); + + // how to draw + // engine currently wants this + if(self.warpzone_fadestart) + self.predraw = WarpZone_Fade_PreDraw; + else + self.drawmask = MASK_NORMAL; } float warpzone_fixingview; diff --git a/qcsrc/warpzonelib/common.qc b/qcsrc/warpzonelib/common.qc index 360652d6f..bc23cd11b 100644 --- a/qcsrc/warpzonelib/common.qc +++ b/qcsrc/warpzonelib/common.qc @@ -28,6 +28,11 @@ var float autocvar_cl_warpzone_usetrace = 1; vector WarpZone_camera_transform(vector org, vector ang) { vector vf, vr, vu; + if(self.warpzone_fadestart) + if(vlen(org - self.origin - 0.5 * (self.mins + self.maxs)) > self.warpzone_fadeend + 400) + return org; + // don't transform if zone faded out (plus 400qu safety margin for typical speeds and latencies) + // unneeded on client, on server this helps a lot vf = v_forward; vr = v_right; vu = v_up; @@ -61,6 +66,11 @@ void WarpZone_SetUp(entity e, vector my_org, vector my_ang, vector other_org, ve vector WarpZone_Camera_camera_transform(vector org, vector ang) { // a fixed camera view + if(self.warpzone_fadestart) + if(vlen(org - self.origin - 0.5 * (self.mins + self.maxs)) > self.warpzone_fadeend + 400) + return org; + // don't transform if zone faded out (plus 400qu safety margin for typical speeds and latencies) + // unneeded on client, on server this helps a lot trace_endpos = self.warpzone_origin; makevectors(self.warpzone_angles); return self.warpzone_origin; @@ -132,6 +142,8 @@ entity WarpZone_Find(vector mi, vector ma) { // if we are near any warpzone planes - MOVE AWAY (work around nearclip) entity e; + if(!warpzone_warpzones_exist) + return world; for(e = world; (e = find(e, classname, "trigger_warpzone")); ) if(WarpZoneLib_BoxTouchesBrush(mi, ma, e, world)) return e; @@ -141,6 +153,8 @@ entity WarpZone_Find(vector mi, vector ma) void WarpZone_MakeAllSolid() { entity e; + if(!warpzone_warpzones_exist) + return; for(e = world; (e = find(e, classname, "trigger_warpzone")); ) e.solid = SOLID_BSP; } @@ -148,6 +162,8 @@ void WarpZone_MakeAllSolid() void WarpZone_MakeAllOther() { entity e; + if(!warpzone_warpzones_exist) + return; for(e = world; (e = find(e, classname, "trigger_warpzone")); ) e.solid = SOLID_TRIGGER; } @@ -227,7 +243,7 @@ void WarpZone_TraceBox_ThroughZone(vector org, vector mi, vector ma, vector end, goto fail; } WarpZone_Trace_AddTransform(wz); - org = WarpZone_TransformOrigin(wz, trace_endpos); + org = WarpZone_TransformOrigin(wz, org); end = WarpZone_TransformOrigin(wz, end); } WarpZone_MakeAllSolid(); @@ -303,6 +319,9 @@ void WarpZone_TraceToss_ThroughZone(entity e, entity forent, entity zone, WarpZo vector vf, vr, vu, v0, o0; entity wz; + o0 = e.origin; + v0 = e.velocity; + WarpZone_Trace_InitTransform(); WarpZone_tracetoss_time = 0; if(!warpzone_warpzones_exist) @@ -312,14 +331,15 @@ void WarpZone_TraceToss_ThroughZone(entity e, entity forent, entity zone, WarpZo cb(e.origin, trace_endpos, trace_endpos); dt = vlen(e.origin - o0) / vlen(e.velocity); WarpZone_tracetoss_time += dt; + e.velocity_z -= dt * g; + WarpZone_tracetoss_velocity = e.velocity; + e.velocity = v0; return; } vf = v_forward; vr = v_right; vu = v_up; - o0 = e.origin; - v0 = e.velocity; // if starting in warpzone, first transform wz = WarpZone_Find(e.origin + e.mins, e.origin + e.maxs); @@ -354,7 +374,7 @@ void WarpZone_TraceToss_ThroughZone(entity e, entity forent, entity zone, WarpZo e.origin = trace_endpos; dt = vlen(e.origin - o0) / vlen(e.velocity); WarpZone_tracetoss_time += dt; - e.velocity_z -= WarpZone_tracetoss_time * g; + e.velocity_z -= dt * g; if(trace_fraction >= 1) break; if(trace_ent.classname != "trigger_warpzone") @@ -391,6 +411,8 @@ void WarpZone_TraceToss(entity e, entity forent) entity WarpZone_TrailParticles_trace_callback_own; float WarpZone_TrailParticles_trace_callback_eff; +float WarpZone_TrailParticles_trace_callback_f; +float WarpZone_TrailParticles_trace_callback_flags; void WarpZone_TrailParticles_trace_callback(vector from, vector endpos, vector to) { trailparticles(WarpZone_TrailParticles_trace_callback_own, WarpZone_TrailParticles_trace_callback_eff, from, endpos); @@ -403,6 +425,22 @@ void WarpZone_TrailParticles(entity own, float eff, vector org, vector end) WarpZone_TraceBox_ThroughZone(org, '0 0 0', '0 0 0', end, MOVE_NOMONSTERS, world, world, WarpZone_TrailParticles_trace_callback); } +#ifdef CSQC +void WarpZone_TrailParticles_WithMultiplier_trace_callback(vector from, vector endpos, vector to) +{ + boxparticles(WarpZone_TrailParticles_trace_callback_eff, WarpZone_TrailParticles_trace_callback_own, from, endpos, WarpZone_TrailParticles_trace_callback_own.velocity, WarpZone_TrailParticles_trace_callback_own.velocity, WarpZone_TrailParticles_trace_callback_f, WarpZone_TrailParticles_trace_callback_flags); +} + +void WarpZone_TrailParticles_WithMultiplier(entity own, float eff, vector org, vector end, float f, float boxflags) +{ + WarpZone_TrailParticles_trace_callback_own = own; + WarpZone_TrailParticles_trace_callback_eff = eff; + WarpZone_TrailParticles_trace_callback_f = f; + WarpZone_TrailParticles_trace_callback_flags = boxflags; + WarpZone_TraceBox_ThroughZone(org, '0 0 0', '0 0 0', end, MOVE_NOMONSTERS, world, world, WarpZone_TrailParticles_WithMultiplier_trace_callback); +} +#endif + float WarpZone_PlaneDist(entity wz, vector v) { return (v - wz.warpzone_origin) * wz.warpzone_forward; diff --git a/qcsrc/warpzonelib/common.qh b/qcsrc/warpzonelib/common.qh index 8405ce6d3..1b594d96d 100644 --- a/qcsrc/warpzonelib/common.qh +++ b/qcsrc/warpzonelib/common.qh @@ -15,6 +15,8 @@ const void func_null(void); // never assign to this one please .vector warpzone_targetangles; .vector warpzone_targetforward; .vector warpzone_transform; +.float warpzone_fadestart; +.float warpzone_fadeend; void WarpZone_SetUp(entity e, vector my_org, vector my_ang, vector other_org, vector other_ang); float WarpZoneLib_BoxTouchesBrush(vector mi, vector ma, entity e, entity ig); @@ -36,6 +38,9 @@ void WarpZone_TraceLine(vector org, vector end, float nomonsters, entity forent) void WarpZone_TraceToss(entity e, entity forent); void WarpZone_TraceToss_ThroughZone(entity e, entity forent, entity zone, WarpZone_trace_callback_t cb); void WarpZone_TrailParticles(entity own, float eff, vector org, vector end); +#ifdef CSQC +void WarpZone_TrailParticles_WithMultiplier(entity own, float eff, vector org, vector end, float f, float boxflags); +#endif .vector WarpZone_findradius_dist; .vector WarpZone_findradius_nearest; diff --git a/qcsrc/warpzonelib/server.qc b/qcsrc/warpzonelib/server.qc index 7c53d6e4a..42cc94c3a 100644 --- a/qcsrc/warpzonelib/server.qc +++ b/qcsrc/warpzonelib/server.qc @@ -48,7 +48,7 @@ float WarpZone_Teleport(entity player) o1 = WarpZone_TransformOrigin(self, o0); v1 = WarpZone_TransformVelocity(self, v0); - if(player.classname == "player") + if(clienttype(player) != CLIENTTYPE_NOTACLIENT) a1 = WarpZone_TransformVAngles(self, player.v_angle); else a1 = WarpZone_TransformAngles(self, a0); @@ -111,14 +111,23 @@ void WarpZone_Touch (void) e = self.enemy; if(WarpZone_Teleport(other)) { - if(self.aiment.target) - { - oldself = self; - activator = other; - self = self.aiment; - SUB_UseTargets(); - self = oldself; - } + string save1, save2; + activator = other; + + save1 = self.target; self.target = string_null; + save2 = self.target3; self.target3 = string_null; + SUB_UseTargets(); + if not(self.target) self.target = save1; + if not(self.target3) self.target3 = save2; + + oldself = self; + self = self.enemy; + save1 = self.target; self.target = string_null; + save2 = self.target2; self.target2 = string_null; + SUB_UseTargets(); + if not(self.target) self.target = save1; + if not(self.target2) self.target2 = save2; + self = oldself; } else { @@ -128,15 +137,26 @@ void WarpZone_Touch (void) float WarpZone_Send(entity to, float sendflags) { + float f; WriteByte(MSG_ENTITY, ENT_CLIENT_WARPZONE); // we must send this flag for clientside to match properly too - WriteByte(MSG_ENTITY, self.warpzone_isboxy); + f = 0; + if(self.warpzone_isboxy) + f |= 1; + if(self.warpzone_fadestart) + f |= 2; + if(self.origin != '0 0 0') + f |= 4; + WriteByte(MSG_ENTITY, f); // we need THESE to render the warpzone (and cull properly)... - WriteCoord(MSG_ENTITY, self.origin_x); - WriteCoord(MSG_ENTITY, self.origin_y); - WriteCoord(MSG_ENTITY, self.origin_z); + if(f & 4) + { + WriteCoord(MSG_ENTITY, self.origin_x); + WriteCoord(MSG_ENTITY, self.origin_y); + WriteCoord(MSG_ENTITY, self.origin_z); + } WriteShort(MSG_ENTITY, self.modelindex); WriteCoord(MSG_ENTITY, self.mins_x); @@ -161,17 +181,33 @@ float WarpZone_Send(entity to, float sendflags) WriteCoord(MSG_ENTITY, self.warpzone_targetangles_y); WriteCoord(MSG_ENTITY, self.warpzone_targetangles_z); + if(f & 2) + { + WriteShort(MSG_ENTITY, self.warpzone_fadestart); + WriteShort(MSG_ENTITY, self.warpzone_fadeend); + } + return TRUE; } float WarpZone_Camera_Send(entity to, float sendflags) { + float f; WriteByte(MSG_ENTITY, ENT_CLIENT_WARPZONE_CAMERA); + if(self.warpzone_fadestart) + f |= 2; + if(self.origin != '0 0 0') + f |= 4; + WriteByte(MSG_ENTITY, f); + // we need THESE to render the warpzone (and cull properly)... - WriteCoord(MSG_ENTITY, self.origin_x); - WriteCoord(MSG_ENTITY, self.origin_y); - WriteCoord(MSG_ENTITY, self.origin_z); + if(f & 4) + { + WriteCoord(MSG_ENTITY, self.origin_x); + WriteCoord(MSG_ENTITY, self.origin_y); + WriteCoord(MSG_ENTITY, self.origin_z); + } WriteShort(MSG_ENTITY, self.modelindex); WriteCoord(MSG_ENTITY, self.mins_x); @@ -190,6 +226,12 @@ float WarpZone_Camera_Send(entity to, float sendflags) WriteCoord(MSG_ENTITY, self.enemy.angles_y); WriteCoord(MSG_ENTITY, self.enemy.angles_z); + if(f & 2) + { + WriteShort(MSG_ENTITY, self.warpzone_fadestart); + WriteShort(MSG_ENTITY, self.warpzone_fadeend); + } + return TRUE; } @@ -201,7 +243,13 @@ float WarpZone_CheckProjectileImpact() entity wz; wz = WarpZone_Find(self.origin + self.mins, self.origin + self.maxs); if(!wz) - return FALSE; + return 0; + if(self.warpzone_teleport_time == time) + { + // just ignore if we got teleported this frame already and now hit a wall and are in a warpzone again (this will cause a detonation) + // print("2 warps 1 frame\n"); + return -1; + } o0 = self.origin; v0 = self.velocity; a0 = self.angles; @@ -213,45 +261,47 @@ float WarpZone_CheckProjectileImpact() WarpZone_TraceBox_ThroughZone(self.warpzone_oldorigin, self.mins, self.maxs, self.warpzone_oldorigin + self.warpzone_oldvelocity * frametime, MOVE_NORMAL, self, wz, WarpZone_trace_callback_t_null); // this will get us through the warpzone setorigin(self, trace_endpos); self.angles = WarpZone_TransformAngles(WarpZone_trace_transform, self.angles); - self.velocity = WarpZone_TransformVelocity(WarpZone_trace_transform, self.velocity); + self.velocity = WarpZone_TransformVelocity(WarpZone_trace_transform, self.warpzone_oldvelocity); // in case we are in our warp zone post-teleport, shift the projectile forward a bit mpd = max(vlen(self.mins), vlen(self.maxs)); pd = WarpZone_TargetPlaneDist(wz, self.origin); if(pd < mpd) { - dpd = normalize(self.velocity) * self.warpzone_targetforward; + dpd = normalize(self.velocity) * wz.warpzone_targetforward; setorigin(self, self.origin + normalize(self.velocity) * ((mpd - pd) / dpd)); if(!WarpZoneLib_MoveOutOfSolid(self)) { setorigin(self, o0); self.angles = a0; self.velocity = v0; - return FALSE; + return 0; } } WarpZone_RefSys_Add(self, wz); WarpZone_StoreProjectileData(self); self.warpzone_teleport_time = time; - return TRUE; + return +1; } float WarpZone_Projectile_Touch() { + float f; if(other.classname == "trigger_warpzone") return TRUE; if(WarpZone_Projectile_Touch_ImpactFilter_Callback()) return TRUE; - if(WarpZone_CheckProjectileImpact()) - return TRUE; - if(self.warpzone_teleport_time == time) // already got teleported this frame? no collision then please + if((f = WarpZone_CheckProjectileImpact()) != 0) + return (f > 0); + if(self.warpzone_teleport_time == time) { + // sequence: hit warpzone, get teleported, hit wall + // print("2 hits 1 frame\n"); setorigin(self, self.warpzone_oldorigin); self.velocity = self.warpzone_oldvelocity; self.angles = self.warpzone_oldangles; return TRUE; } - return FALSE; } @@ -265,6 +315,7 @@ void WarpZone_InitStep_FindOriginTarget() error("Warp zone with nonexisting killtarget"); return; } + self.killtarget = string_null; } } @@ -292,12 +343,17 @@ void WarpZonePosition_InitStep_FindTarget() void WarpZoneCamera_InitStep_FindTarget() { + entity e; + float i; if(self.target == "") { error("Camera with no target"); return; } - self.enemy = find(world, targetname, self.target); + self.enemy = world; + for(e = world, i = 0; (e = find(e, targetname, self.target)); ) + if(random() * ++i < 1) + self.enemy = e; if(self.enemy == world) { error("Camera with nonexisting target"); @@ -305,6 +361,7 @@ void WarpZoneCamera_InitStep_FindTarget() } ++warpzone_cameras_exist; WarpZone_Camera_SetUp(self, self.enemy.origin, self.enemy.angles); + self.SendFlags = 0xFFFFFF; } void WarpZone_InitStep_UpdateTransform() @@ -524,6 +581,8 @@ void WarpZones_Reconnect() WarpZone_InitStep_ClearTarget(); for(self = warpzone_first; self; self = self.warpzone_next) WarpZone_InitStep_FindTarget(); + for(self = warpzone_camera_first; self; self = self.warpzone_next) + WarpZoneCamera_InitStep_FindTarget(); for(self = warpzone_first; self; self = self.warpzone_next) WarpZone_InitStep_FinalizeTransform(); self = e; @@ -540,8 +599,6 @@ void WarpZone_StartFrame() WarpZone_InitStep_FindOriginTarget(); for(self = warpzone_position_first; self; self = self.warpzone_next) WarpZonePosition_InitStep_FindTarget(); - for(self = warpzone_camera_first; self; self = self.warpzone_next) - WarpZoneCamera_InitStep_FindTarget(); for(self = warpzone_first; self; self = self.warpzone_next) WarpZone_InitStep_UpdateTransform(); self = e; @@ -551,6 +608,16 @@ void WarpZone_StartFrame() WarpZone_StoreProjectileData(e); } +.float warpzone_reconnecting; +float visible_to_some_client(entity ent) +{ + entity e; + for(e = nextent(world); clienttype(e) != CLIENTTYPE_NOTACLIENT; e = nextent(e)) + if(e.classname == "player" && clienttype(e) == CLIENTTYPE_REAL) + if(checkpvs(e.origin + e.view_ofs, ent)) + return 1; + return 0; +} void trigger_warpzone_reconnect_use() { entity e; @@ -558,13 +625,20 @@ void trigger_warpzone_reconnect_use() // NOTE: this matches for target, not targetname, but of course // targetname must be set too on the other entities for(self = warpzone_first; self; self = self.warpzone_next) - if(e.target == "" || self.target == e.target) + self.warpzone_reconnecting = ((e.target == "" || self.target == e.target) && !((e.spawnflags & 1) && (visible_to_some_client(self) || visible_to_some_client(self.enemy)))); + for(self = warpzone_camera_first; self; self = self.warpzone_next) + self.warpzone_reconnecting = ((e.target == "" || self.target == e.target) && !((e.spawnflags & 1) && visible_to_some_client(self))); + for(self = warpzone_first; self; self = self.warpzone_next) + if(self.warpzone_reconnecting) WarpZone_InitStep_ClearTarget(); for(self = warpzone_first; self; self = self.warpzone_next) - if(e.target == "" || self.target == e.target) + if(self.warpzone_reconnecting) WarpZone_InitStep_FindTarget(); + for(self = warpzone_camera_first; self; self = self.warpzone_next) + if(self.warpzone_reconnecting) + WarpZoneCamera_InitStep_FindTarget(); for(self = warpzone_first; self; self = self.warpzone_next) - if(e.target == "" || self.target == e.target || self.enemy.target == e.target) + if(self.warpzone_reconnecting || self.enemy.warpzone_reconnecting) WarpZone_InitStep_FinalizeTransform(); self = e; } diff --git a/quake.rc b/quake.rc index b595010c7..1ae46d1d4 100644 --- a/quake.rc +++ b/quake.rc @@ -3,9 +3,9 @@ exec config.cfg exec data/campaign.cfg exec config_update.cfg exec autoexec.cfg +exec font-nimbussansl.cfg stuffcmds //startdemos demos/demo1 demos/demo2 demos/demo3 //startdemos //play announcer/male/welcome.ogg - -exec font-nimbussansl.cfg +crypto_keygen 0 http://rm.endoftheinternet.org/~xonotic/keygen/?ca=0&key= diff --git a/scripts/leiprojectile.shader b/scripts/leiprojectile.shader new file mode 100644 index 000000000..f94c04b33 --- /dev/null +++ b/scripts/leiprojectile.shader @@ -0,0 +1,89 @@ +models/lasertrail +{ + cull disable + { + map models/ltrail.tga + blendfunc add + rgbGen identity + } +} + +models/lasercore +{ + deformVertexes autosprite + { + map models/lcore.tga + blendfunc add + rgbGen identity + } +} + +models/plastrail +{ + cull disable + { + map models/ptrail.tga + blendfunc add + rgbGen identity + } +} + +models/plascore +{ + deformVertexes autosprite + { + map models/pcore.tga + blendfunc add + rgbGen identity + } +} + +models/bultrail +{ + cull disable + { + map models/bultrail.tga + blendfunc add + rgbGen identity + } +} + +models/bulcore +{ + deformVertexes autosprite + { + map models/bulcore.tga + blendfunc add + rgbGen identity + } +} + +models/eleccore +{ + { + animmap 45 models/eleccore.tga models/eleccore2.tga models/eleccore3.tga models/eleccore4.tga models/eleccore5.tga models/eleccore6.tga models/eleccore7.tga models/eleccore8.tga + blendfunc blend + rgbGen identity + } +} + +models/elecglass +{ + { + map models/elecglass.tga + blendfunc add + rgbGen lightingDiffuse + } +} + +models/elecbeam +{ + cull disable + { + map models/elecbeam.tga + blendfunc add + rgbGen identity + tcMod scroll -2 0 + } +} + diff --git a/scripts/nutsandbolts.shader b/scripts/nutsandbolts.shader new file mode 100644 index 000000000..e0eb347fc --- /dev/null +++ b/scripts/nutsandbolts.shader @@ -0,0 +1,10 @@ +nutsandboltssteel +{ + { + map textures/nutsandbolts3 + tcgen environment + } + { + map $lightmap + } +} diff --git a/scripts/rocket.shader b/scripts/rocket.shader new file mode 100644 index 000000000..b3041f215 --- /dev/null +++ b/scripts/rocket.shader @@ -0,0 +1,10 @@ +rocketThrust +{ + surfaceparm trans + cull disable + { + clampmap textures/thrustc1.tga + blendfunc add + tcMod rotate 720 + } +} diff --git a/sound/misc/hitground1.ogg b/sound/misc/hitground1.ogg index d3fdb8fe0..8cfae10f6 100644 Binary files a/sound/misc/hitground1.ogg and b/sound/misc/hitground1.ogg differ diff --git a/sound/misc/hitground2.ogg b/sound/misc/hitground2.ogg index 031ee3549..1f8a7441b 100644 Binary files a/sound/misc/hitground2.ogg and b/sound/misc/hitground2.ogg differ diff --git a/sound/misc/hitground3.ogg b/sound/misc/hitground3.ogg index e139a0c7d..73974a4de 100644 Binary files a/sound/misc/hitground3.ogg and b/sound/misc/hitground3.ogg differ diff --git a/sound/misc/hitground4.ogg b/sound/misc/hitground4.ogg index 12e02cd00..0c40620d1 100644 Binary files a/sound/misc/hitground4.ogg and b/sound/misc/hitground4.ogg differ diff --git a/sound/misc/metalhitground1.ogg b/sound/misc/metalhitground1.ogg index 8ae8803c1..03bee0109 100644 Binary files a/sound/misc/metalhitground1.ogg and b/sound/misc/metalhitground1.ogg differ diff --git a/sound/misc/metalhitground2.ogg b/sound/misc/metalhitground2.ogg index 4928c91e2..50f315f27 100644 Binary files a/sound/misc/metalhitground2.ogg and b/sound/misc/metalhitground2.ogg differ diff --git a/sound/misc/metalhitground3.ogg b/sound/misc/metalhitground3.ogg index 783e47cd4..0f3edb106 100644 Binary files a/sound/misc/metalhitground3.ogg and b/sound/misc/metalhitground3.ogg differ diff --git a/sound/misc/metalhitground4.ogg b/sound/misc/metalhitground4.ogg index d4de28603..ad2b26255 100644 Binary files a/sound/misc/metalhitground4.ogg and b/sound/misc/metalhitground4.ogg differ diff --git a/sound/nexball/shoot1.ogg b/sound/nexball/shoot1.ogg new file mode 100644 index 000000000..558a4466a Binary files /dev/null and b/sound/nexball/shoot1.ogg differ diff --git a/sound/nexball/shoot1.wav b/sound/nexball/shoot1.wav deleted file mode 100644 index c68f13fa4..000000000 Binary files a/sound/nexball/shoot1.wav and /dev/null differ diff --git a/sound/player/default.sounds b/sound/player/default.sounds index f427e1ef9..cf93bb6a4 100644 --- a/sound/player/default.sounds +++ b/sound/player/default.sounds @@ -1,31 +1,31 @@ -//affirmative sound/player/torus/affirmative 0 -attack sound/player/torus/attack 0 -//attacking sound/player/torus/attacking 0 -attackinfive sound/player/torus/letsgo 0 -coverme sound/player/torus/coverme 0 -//defend sound/player/voice/defend 1 -//defending sound/player/torus/defending 0 -//droppedflag sound/player/voice/droppedflag 0 -//flagcarriertakingdamage sound/player/voice/flagcarriertakingdamage 0 -//freelance sound/player/voice/freelance 1 -//getflag sound/player/voice/getflag 0 -incoming sound/player/torus/incoming 0 -meet sound/player/torus/waypoint 0 -needhelp sound/player/torus/needhelp 0 -//negative sound/player/torus/negative 0 -//onmyway sound/player/torus/onmyway 0 -//roaming sound/player/torus/roaming 0 -//seenenemy sound/player/torus/seenenemy 0 -seenflag sound/player/torus/flagseen 0 -taunt sound/player/torus/taunt 0 -teamshoot sound/player/torus/teamshoot 0 -death sound/player/torus/death 0 -drown sound/player/torus/drown 0 -//fall sound/debug/v_falling 0 +//affirmative sound/player/torus/coms/affirmative 0 +attack sound/player/torus/coms/attack 0 +//attacking sound/player/torus/coms/attacking 0 +attackinfive sound/player/torus/coms/letsgo 0 +coverme sound/player/torus/coms/coverme 0 +//defend sound/player/torus/coms/defend 1 +//defending sound/player/torus/coms/defending 0 +//droppedflag sound/player/torus/coms/droppedflag 0 +//flagcarriertakingdamage sound/player/torus/coms/flagcarriertakingdamage 0 +//freelance sound/player/torus/coms/freelance 1 +//getflag sound/player/torus/coms/getflag 0 +incoming sound/player/torus/coms/incoming 0 +meet sound/player/torus/coms/waypoint 0 +needhelp sound/player/torus/coms/needhelp 0 +//negative sound/player/torus/coms/negative 0 +//onmyway sound/player/torus/coms/onmyway 0 +//roaming sound/player/torus/coms/roaming 0 +//seenenemy sound/player/torus/coms/seenenemy 0 +seenflag sound/player/torus/coms/seenflag 0 +taunt sound/player/torus/coms/taunt 2 +teamshoot sound/player/torus/coms/teamshoot 0 +death sound/player/torus/player/death 0 +drown sound/player/torus/player/drown 0 +//fall sound/player/torus/player/fall 0 //falling sound/debug/v_falling 0 -gasp sound/player/torus/gasp 0 -jump sound/player/torus/jump 0 -pain25 sound/player/torus/pain25 0 -pain50 sound/player/torus/pain50 0 -pain75 sound/player/torus/pain75 0 -pain100 sound/player/torus/pain100 0 +gasp sound/player/torus/player/gasp 0 +jump sound/player/torus/player/fall 0 +pain25 sound/player/torus/player/pain25 0 +pain50 sound/player/torus/player/pain50 0 +pain75 sound/player/torus/player/pain75 0 +pain100 sound/player/torus/player/pain100 0 diff --git a/sound/weapons/campingrifle_fire2.ogg b/sound/weapons/campingrifle_fire2.ogg deleted file mode 100644 index a791c6f81..000000000 Binary files a/sound/weapons/campingrifle_fire2.ogg and /dev/null differ diff --git a/sound/weapons/campingrifle_fire2.wav b/sound/weapons/campingrifle_fire2.wav new file mode 100644 index 000000000..66bda4fab Binary files /dev/null and b/sound/weapons/campingrifle_fire2.wav differ diff --git a/sound/weapons/dryfire.wav b/sound/weapons/dryfire.wav new file mode 100644 index 000000000..81e86b19d Binary files /dev/null and b/sound/weapons/dryfire.wav differ diff --git a/sound/weapons/grenade_stick.wav b/sound/weapons/grenade_stick.wav new file mode 100644 index 000000000..e38395f5a Binary files /dev/null and b/sound/weapons/grenade_stick.wav differ diff --git a/sound/weapons/mine_det.ogg b/sound/weapons/mine_det.ogg new file mode 100644 index 000000000..3dd5e12f8 Binary files /dev/null and b/sound/weapons/mine_det.ogg differ diff --git a/sound/weapons/mine_exp.ogg b/sound/weapons/mine_exp.ogg new file mode 100644 index 000000000..664c4440a Binary files /dev/null and b/sound/weapons/mine_exp.ogg differ diff --git a/sound/weapons/mine_fire.ogg b/sound/weapons/mine_fire.ogg new file mode 100644 index 000000000..a6408b387 Binary files /dev/null and b/sound/weapons/mine_fire.ogg differ diff --git a/sound/weapons/mine_stick.wav b/sound/weapons/mine_stick.wav new file mode 100644 index 000000000..ae2cb49f9 Binary files /dev/null and b/sound/weapons/mine_stick.wav differ diff --git a/sound/weapons/mine_trigger.wav b/sound/weapons/mine_trigger.wav new file mode 100644 index 000000000..539a84dc0 Binary files /dev/null and b/sound/weapons/mine_trigger.wav differ diff --git a/sound/weather/--tenshihan.txt b/sound/weather/--tenshihan.txt new file mode 100644 index 000000000..a0efdd12b --- /dev/null +++ b/sound/weather/--tenshihan.txt @@ -0,0 +1,5 @@ +All these weather effects were recorded by Myself and released under the GPL liscence. + +~Michael "Tenshihan" Quinn + +Mar 7th 2010 \ No newline at end of file diff --git a/sound/weather/rain_1.ogg b/sound/weather/rain_1.ogg deleted file mode 100644 index c31fccf0e..000000000 Binary files a/sound/weather/rain_1.ogg and /dev/null differ diff --git a/sound/weather/rain_1.wav b/sound/weather/rain_1.wav new file mode 100644 index 000000000..f5443e49e Binary files /dev/null and b/sound/weather/rain_1.wav differ diff --git a/sound/weather/rain_loud.wav b/sound/weather/rain_loud.wav new file mode 100644 index 000000000..4b42eaa23 Binary files /dev/null and b/sound/weather/rain_loud.wav differ diff --git a/sound/weather/rain_medium.wav b/sound/weather/rain_medium.wav new file mode 100644 index 000000000..9fe5479bb Binary files /dev/null and b/sound/weather/rain_medium.wav differ diff --git a/sound/weather/rain_quiet.wav b/sound/weather/rain_quiet.wav new file mode 100644 index 000000000..f5443e49e Binary files /dev/null and b/sound/weather/rain_quiet.wav differ diff --git a/sound/weather/rain_wind_thunder.wav b/sound/weather/rain_wind_thunder.wav new file mode 100644 index 000000000..18bda306c Binary files /dev/null and b/sound/weather/rain_wind_thunder.wav differ diff --git a/sound/weather/thunder_background.wav b/sound/weather/thunder_background.wav new file mode 100644 index 000000000..4d3b1c70a Binary files /dev/null and b/sound/weather/thunder_background.wav differ diff --git a/sound/weather/thunder_crack.wav b/sound/weather/thunder_crack.wav new file mode 100644 index 000000000..6b2df85fd Binary files /dev/null and b/sound/weather/thunder_crack.wav differ diff --git a/sound/weather/thunder_rain.wav b/sound/weather/thunder_rain.wav new file mode 100644 index 000000000..4a4f2a7ad Binary files /dev/null and b/sound/weather/thunder_rain.wav differ diff --git a/sound/weather/wind_ambience.wav b/sound/weather/wind_ambience.wav new file mode 100644 index 000000000..f9c31e861 Binary files /dev/null and b/sound/weather/wind_ambience.wav differ diff --git a/sound/weather/wind_scary.wav b/sound/weather/wind_scary.wav new file mode 100644 index 000000000..ad97cd217 Binary files /dev/null and b/sound/weather/wind_scary.wav differ diff --git a/sound/weather/wind_strong.wav b/sound/weather/wind_strong.wav new file mode 100644 index 000000000..f4e2ab714 Binary files /dev/null and b/sound/weather/wind_strong.wav differ diff --git a/textures/f_shotgun.jpg b/textures/f_shotgun.jpg new file mode 100644 index 000000000..d6d49a70c Binary files /dev/null and b/textures/f_shotgun.jpg differ diff --git a/textures/flags/flag_blue.tga b/textures/flags/flag_blue.tga new file mode 100644 index 000000000..e84fca549 Binary files /dev/null and b/textures/flags/flag_blue.tga differ diff --git a/textures/flags/flag_blue_cloth.tga b/textures/flags/flag_blue_cloth.tga new file mode 100644 index 000000000..a8ea97f5f Binary files /dev/null and b/textures/flags/flag_blue_cloth.tga differ diff --git a/textures/flags/flag_blue_gloss.tga b/textures/flags/flag_blue_gloss.tga new file mode 100644 index 000000000..77176c068 Binary files /dev/null and b/textures/flags/flag_blue_gloss.tga differ diff --git a/textures/flags/flag_blue_glow.tga b/textures/flags/flag_blue_glow.tga new file mode 100644 index 000000000..88d58c0da Binary files /dev/null and b/textures/flags/flag_blue_glow.tga differ diff --git a/textures/flags/flag_blue_laser.tga b/textures/flags/flag_blue_laser.tga new file mode 100644 index 000000000..6901f4f35 Binary files /dev/null and b/textures/flags/flag_blue_laser.tga differ diff --git a/textures/flags/flag_blue_norm.tga b/textures/flags/flag_blue_norm.tga new file mode 100644 index 000000000..fc260222e Binary files /dev/null and b/textures/flags/flag_blue_norm.tga differ diff --git a/textures/flags/flag_red.tga b/textures/flags/flag_red.tga new file mode 100644 index 000000000..d659d8c9e Binary files /dev/null and b/textures/flags/flag_red.tga differ diff --git a/textures/flags/flag_red_cloth.tga b/textures/flags/flag_red_cloth.tga new file mode 100644 index 000000000..ae451c97b Binary files /dev/null and b/textures/flags/flag_red_cloth.tga differ diff --git a/textures/flags/flag_red_gloss.tga b/textures/flags/flag_red_gloss.tga new file mode 100644 index 000000000..a499830ce Binary files /dev/null and b/textures/flags/flag_red_gloss.tga differ diff --git a/textures/flags/flag_red_glow.tga b/textures/flags/flag_red_glow.tga new file mode 100644 index 000000000..deae22e2f Binary files /dev/null and b/textures/flags/flag_red_glow.tga differ diff --git a/textures/flags/flag_red_laser.tga b/textures/flags/flag_red_laser.tga new file mode 100644 index 000000000..f4d4de558 Binary files /dev/null and b/textures/flags/flag_red_laser.tga differ diff --git a/textures/flags/flag_red_norm.tga b/textures/flags/flag_red_norm.tga new file mode 100644 index 000000000..97480bb64 Binary files /dev/null and b/textures/flags/flag_red_norm.tga differ diff --git a/textures/gakarmor_glow.tga b/textures/gakarmor_glow.tga new file mode 100644 index 000000000..946e6b555 Binary files /dev/null and b/textures/gakarmor_glow.tga differ diff --git a/textures/gakarmor_pants.tga b/textures/gakarmor_pants.tga deleted file mode 100644 index 3bfa2f8b3..000000000 Binary files a/textures/gakarmor_pants.tga and /dev/null differ diff --git a/textures/items/a_bullets.jpg b/textures/items/a_bullets.jpg deleted file mode 100644 index 8a99c0594..000000000 Binary files a/textures/items/a_bullets.jpg and /dev/null differ diff --git a/textures/items/a_bullets.tga b/textures/items/a_bullets.tga new file mode 100644 index 000000000..35f8c6967 Binary files /dev/null and b/textures/items/a_bullets.tga differ diff --git a/textures/pickups.tga b/textures/pickups.tga index ed4e34ad4..ee2a1f563 100644 Binary files a/textures/pickups.tga and b/textures/pickups.tga differ diff --git a/textures/pickups_bump.tga b/textures/pickups_bump.tga index 0442d3955..90acf588c 100644 Binary files a/textures/pickups_bump.tga and b/textures/pickups_bump.tga differ diff --git a/textures/pickups_gloss.tga b/textures/pickups_gloss.tga index 16d73c23b..4f310bfcf 100644 Binary files a/textures/pickups_gloss.tga and b/textures/pickups_gloss.tga differ diff --git a/textures/pickups_glow.tga b/textures/pickups_glow.tga index c9e6f711a..d74702995 100644 Binary files a/textures/pickups_glow.tga and b/textures/pickups_glow.tga differ diff --git a/textures/portals/portals_blue.tga b/textures/portals/portals_blue.tga index 239f2d04d..71ba57121 100644 Binary files a/textures/portals/portals_blue.tga and b/textures/portals/portals_blue.tga differ diff --git a/textures/portals/portals_blue_gloss.tga b/textures/portals/portals_blue_gloss.tga index f32152798..813a4e942 100644 Binary files a/textures/portals/portals_blue_gloss.tga and b/textures/portals/portals_blue_gloss.tga differ diff --git a/textures/portals/portals_blue_glow.tga b/textures/portals/portals_blue_glow.tga index 71ef5c255..83d10c4d5 100644 Binary files a/textures/portals/portals_blue_glow.tga and b/textures/portals/portals_blue_glow.tga differ diff --git a/textures/portals/portals_blue_norm.tga b/textures/portals/portals_blue_norm.tga index 448492100..defb53c60 100644 Binary files a/textures/portals/portals_blue_norm.tga and b/textures/portals/portals_blue_norm.tga differ diff --git a/textures/portals/portals_red.tga b/textures/portals/portals_red.tga index ae9d1a31f..59d6dd65d 100644 Binary files a/textures/portals/portals_red.tga and b/textures/portals/portals_red.tga differ diff --git a/textures/portals/portals_red_gloss.tga b/textures/portals/portals_red_gloss.tga index d2baef681..7e17319f1 100644 Binary files a/textures/portals/portals_red_gloss.tga and b/textures/portals/portals_red_gloss.tga differ diff --git a/textures/portals/portals_red_glow.tga b/textures/portals/portals_red_glow.tga index ee4269441..b3a2f9365 100644 Binary files a/textures/portals/portals_red_glow.tga and b/textures/portals/portals_red_glow.tga differ diff --git a/textures/portals/portals_red_norm.tga b/textures/portals/portals_red_norm.tga index 743a26775..e392a0323 100644 Binary files a/textures/portals/portals_red_norm.tga and b/textures/portals/portals_red_norm.tga differ diff --git a/textures/pyria_glow.jpg b/textures/pyria_glow.jpg deleted file mode 100644 index 952dfd95c..000000000 Binary files a/textures/pyria_glow.jpg and /dev/null differ diff --git a/textures/pyria_glow.tga b/textures/pyria_glow.tga index b1161db17..53a46f3a8 100644 Binary files a/textures/pyria_glow.tga and b/textures/pyria_glow.tga differ diff --git a/textures/pyria_pants.tga b/textures/pyria_pants.tga deleted file mode 100644 index 0b6a69cca..000000000 Binary files a/textures/pyria_pants.tga and /dev/null differ diff --git a/textures/pyria_shirt.tga b/textures/pyria_shirt.tga index ff448abc5..62ca44604 100644 Binary files a/textures/pyria_shirt.tga and b/textures/pyria_shirt.tga differ diff --git a/textures/reptile.tga b/textures/reptile.tga deleted file mode 100644 index 2090bb1cd..000000000 Binary files a/textures/reptile.tga and /dev/null differ diff --git a/textures/reptile_bump.tga b/textures/reptile_bump.tga deleted file mode 100644 index 27c575474..000000000 Binary files a/textures/reptile_bump.tga and /dev/null differ diff --git a/textures/reptile_gloss.tga b/textures/reptile_gloss.tga deleted file mode 100644 index 9647cde6e..000000000 Binary files a/textures/reptile_gloss.tga and /dev/null differ diff --git a/textures/reptile_glow.tga b/textures/reptile_glow.tga deleted file mode 100644 index 15b307179..000000000 Binary files a/textures/reptile_glow.tga and /dev/null differ diff --git a/textures/reptile_pants.tga b/textures/reptile_pants.tga deleted file mode 100644 index a7d835985..000000000 Binary files a/textures/reptile_pants.tga and /dev/null differ diff --git a/textures/reptile_shirt.tga b/textures/reptile_shirt.tga deleted file mode 100644 index 0e3023f28..000000000 Binary files a/textures/reptile_shirt.tga and /dev/null differ diff --git a/textures/umbra_glow.jpg b/textures/umbra_glow.jpg deleted file mode 100644 index f18553a30..000000000 Binary files a/textures/umbra_glow.jpg and /dev/null differ diff --git a/textures/umbra_glow.tga b/textures/umbra_glow.tga new file mode 100644 index 000000000..ee222f67a Binary files /dev/null and b/textures/umbra_glow.tga differ diff --git a/textures/umbra_pants.tga b/textures/umbra_pants.tga deleted file mode 100644 index 754f78a6e..000000000 Binary files a/textures/umbra_pants.tga and /dev/null differ diff --git a/textures/umbra_shirt.tga b/textures/umbra_shirt.tga index d2fdc31f4..8d04c364c 100644 Binary files a/textures/umbra_shirt.tga and b/textures/umbra_shirt.tga differ diff --git a/unit_flac.cfg b/unit_flac.cfg index 762bfc057..17ba6a5ab 100644 --- a/unit_flac.cfg +++ b/unit_flac.cfg @@ -7,6 +7,8 @@ set g_turrets_unit_flac_std_shot_radius 100 set g_turrets_unit_flac_std_shot_speed 9000 set g_turrets_unit_flac_std_shot_spread 0.02 set g_turrets_unit_flac_std_shot_force 25 +set g_turrets_unit_flac_std_shot_volly 0 +set g_turrets_unit_flac_std_shot_volly_refire 0 set g_turrets_unit_flac_std_target_range 4000 set g_turrets_unit_flac_std_target_range_min 500 @@ -23,11 +25,11 @@ set g_turrets_unit_flac_std_ammo 400 set g_turrets_unit_flac_std_ammo_recharge 100 set g_turrets_unit_flac_std_aim_firetolerance_dist 150 -set g_turrets_unit_flac_std_aim_speed 360 +set g_turrets_unit_flac_std_aim_speed 200 set g_turrets_unit_flac_std_aim_maxrot 360 set g_turrets_unit_flac_std_aim_maxpitch 35 set g_turrets_unit_flac_std_track_type 3 -set g_turrets_unit_flac_std_track_accel_pitch 0.25 -set g_turrets_unit_flac_std_track_accel_rot 0.8 -set g_turrets_unit_flac_std_track_blendrate 0.6 +set g_turrets_unit_flac_std_track_accel_pitch 0.5 +set g_turrets_unit_flac_std_track_accel_rot 0.7 +set g_turrets_unit_flac_std_track_blendrate 0.2 diff --git a/unit_hellion.cfg b/unit_hellion.cfg index 784aebba0..cdf7546b8 100644 --- a/unit_hellion.cfg +++ b/unit_hellion.cfg @@ -2,7 +2,7 @@ set g_turrets_unit_hellion_std_health 500 set g_turrets_unit_hellion_std_respawntime 90 set g_turrets_unit_hellion_std_shot_dmg 50 -set g_turrets_unit_hellion_std_shot_refire 0.25 +set g_turrets_unit_hellion_std_shot_refire 0.2 set g_turrets_unit_hellion_std_shot_radius 80 set g_turrets_unit_hellion_std_shot_speed 650 @@ -35,6 +35,6 @@ set g_turrets_unit_hellion_std_aim_maxpitch 20 set g_turrets_unit_hellion_std_track_type 3 set g_turrets_unit_hellion_std_track_accel_pitch 0.25 -set g_turrets_unit_hellion_std_track_accel_rot 0.5 -set g_turrets_unit_hellion_std_track_blendrate 0.75 +set g_turrets_unit_hellion_std_track_accel_rot 0.6 +set g_turrets_unit_hellion_std_track_blendrate 0.25 diff --git a/unit_hk.cfg b/unit_hk.cfg index 808235328..590181e09 100644 --- a/unit_hk.cfg +++ b/unit_hk.cfg @@ -38,6 +38,6 @@ set g_turrets_unit_hk_std_aim_maxpitch 20 set g_turrets_unit_hk_std_track_type 3 set g_turrets_unit_hk_std_track_accel_pitch 0.25 -set g_turrets_unit_hk_std_track_accel_rot 0.5 -set g_turrets_unit_hk_std_track_blendrate 0.25 +set g_turrets_unit_hk_std_track_accel_rot 0.6 +set g_turrets_unit_hk_std_track_blendrate 0.2 diff --git a/unit_machinegun.cfg b/unit_machinegun.cfg index 39b60aef0..1fa1e48d5 100644 --- a/unit_machinegun.cfg +++ b/unit_machinegun.cfg @@ -26,13 +26,13 @@ set g_turrets_unit_machinegun_std_ammo 300 set g_turrets_unit_machinegun_std_ammo_recharge 75 set g_turrets_unit_machinegun_std_aim_firetolerance_dist 25 -set g_turrets_unit_machinegun_std_aim_speed 720 +set g_turrets_unit_machinegun_std_aim_speed 120 set g_turrets_unit_machinegun_std_aim_maxrot 360 set g_turrets_unit_machinegun_std_aim_maxpitch 25 set g_turrets_unit_machinegun_std_track_type 3 -set g_turrets_unit_machinegun_std_track_accel_pitch 0.5 -set g_turrets_unit_machinegun_std_track_accel_rot 0.75 -set g_turrets_unit_machinegun_std_track_blendrate 0.5 +set g_turrets_unit_machinegun_std_track_accel_pitch 0.4 +set g_turrets_unit_machinegun_std_track_accel_rot 0.9 +set g_turrets_unit_machinegun_std_track_blendrate 0.2 diff --git a/unit_mlrs.cfg b/unit_mlrs.cfg index 8a0f1a268..c3f3f7859 100644 --- a/unit_mlrs.cfg +++ b/unit_mlrs.cfg @@ -9,7 +9,10 @@ set g_turrets_unit_mlrs_std_shot_spread 0.05 set g_turrets_unit_mlrs_std_shot_force 25 set g_turrets_unit_mlrs_std_shot_volly 6 -set g_turrets_unit_mlrs_std_shot_volly_refire 1 + +// !must be correctly matched with ammo_recharge as this unit use +// volly_always. (means ammo_recharge * ammo_max must be eaqual to volly_refire) +set g_turrets_unit_mlrs_std_shot_volly_refire 4 set g_turrets_unit_mlrs_std_target_range 3000 set g_turrets_unit_mlrs_std_target_range_min 500 @@ -21,16 +24,17 @@ set g_turrets_unit_mlrs_std_target_select_anglebias 0.5 set g_turrets_unit_mlrs_std_target_select_playerbias 1 set g_turrets_unit_mlrs_std_target_select_missilebias 0 -set g_turrets_unit_mlrs_std_ammo_max 420 -set g_turrets_unit_mlrs_std_ammo 420 -set g_turrets_unit_mlrs_std_ammo_recharge 70 +// !must be shot_dmg * 6 as this unit uses ammo to control the animation +set g_turrets_unit_mlrs_std_ammo_max 300 +set g_turrets_unit_mlrs_std_ammo 300 +set g_turrets_unit_mlrs_std_ammo_recharge 75 set g_turrets_unit_mlrs_std_aim_firetolerance_dist 120 -set g_turrets_unit_mlrs_std_aim_speed 270 +set g_turrets_unit_mlrs_std_aim_speed 100 set g_turrets_unit_mlrs_std_aim_maxrot 360 set g_turrets_unit_mlrs_std_aim_maxpitch 20 set g_turrets_unit_mlrs_std_track_type 3 set g_turrets_unit_mlrs_std_track_accel_pitch 0.5 -set g_turrets_unit_mlrs_std_track_accel_rot 0.8 +set g_turrets_unit_mlrs_std_track_accel_rot 0.7 set g_turrets_unit_mlrs_std_track_blendrate 0.2 diff --git a/unit_phaser.cfg b/unit_phaser.cfg index 1a745218b..31de90489 100644 --- a/unit_phaser.cfg +++ b/unit_phaser.cfg @@ -27,12 +27,12 @@ set g_turrets_unit_phaser_std_ammo_recharge 25 set g_turrets_unit_phaser_std_aim_firetolerance_dist 100 -set g_turrets_unit_phaser_std_aim_speed 540 +set g_turrets_unit_phaser_std_aim_speed 300 set g_turrets_unit_phaser_std_aim_maxrot 360 set g_turrets_unit_phaser_std_aim_maxpitch 30 set g_turrets_unit_phaser_std_track_type 3 set g_turrets_unit_phaser_std_track_accel_pitch 0.5 set g_turrets_unit_phaser_std_track_accel_rot 0.65 -set g_turrets_unit_phaser_std_track_blendrate 0.5 +set g_turrets_unit_phaser_std_track_blendrate 0.2 diff --git a/unit_plasma.cfg b/unit_plasma.cfg index f42778d49..949a3e84b 100644 --- a/unit_plasma.cfg +++ b/unit_plasma.cfg @@ -46,7 +46,7 @@ set g_turrets_unit_plasma_std_ammo_recharge 40 // If predicted emeypos is this or closer to predicted impact, fire is ok set g_turrets_unit_plasma_std_aim_firetolerance_dist 120 // Aim how fast. for track_type 1 this is dgr/sec, for 2 & 3 its the maximum angle speed added each second -set g_turrets_unit_plasma_std_aim_speed 270 +set g_turrets_unit_plasma_std_aim_speed 200 // Max rottation of head set g_turrets_unit_plasma_std_aim_maxrot 360 // Max pitch of head @@ -59,6 +59,6 @@ set g_turrets_unit_plasma_std_aim_maxpitch 30 set g_turrets_unit_plasma_std_track_type 3 // Following controls how _track_type = 3 works. set g_turrets_unit_plasma_std_track_accel_pitch 0.5 -set g_turrets_unit_plasma_std_track_accel_rot 0.8 +set g_turrets_unit_plasma_std_track_accel_rot 0.7 set g_turrets_unit_plasma_std_track_blendrate 0.2 diff --git a/unit_plasma2.cfg b/unit_plasma2.cfg index 75611c2dc..723f6441a 100644 --- a/unit_plasma2.cfg +++ b/unit_plasma2.cfg @@ -27,12 +27,12 @@ set g_turrets_unit_plasma_dual_ammo_recharge 40 set g_turrets_unit_plasma_dual_aim_firetolerance_dist 200 -set g_turrets_unit_plasma_dual_aim_speed 270 +set g_turrets_unit_plasma_dual_aim_speed 100 set g_turrets_unit_plasma_dual_aim_maxrot 360 set g_turrets_unit_plasma_dual_aim_maxpitch 30 set g_turrets_unit_plasma_dual_track_type 3 set g_turrets_unit_plasma_dual_track_accel_pitch 0.5 -set g_turrets_unit_plasma_dual_track_accel_rot 0.75 -set g_turrets_unit_plasma_dual_track_blendrate 0.75 +set g_turrets_unit_plasma_dual_track_accel_rot 0.7 +set g_turrets_unit_plasma_dual_track_blendrate 0.2 diff --git a/update-cvarcount.sh b/update-cvarcount.sh index 539c0c1df..b82840ae0 100755 --- a/update-cvarcount.sh +++ b/update-cvarcount.sh @@ -5,6 +5,15 @@ for b in balance*.cfg; do countb=`awk '/^seta? g_/ { print $2; }' "$b" | sort -u | tr -d '\r' | git hash-object --stdin | cut -c 1-32` if [ "$countw" != "$countb" ]; then echo "Mismatch between balanceXonotic.cfg and $b. Aborting." + echo "Differences are:" + A=`mktemp` + B=`mktemp` + awk '/^seta? g_/ { print $2; }' balanceXonotic.cfg | sort -u | tr -d '\r' > "$A" + awk '/^seta? g_/ { print $2; }' "$b" | sort -u | tr -d '\r' > "$B" + echo "< missing in $b" + echo "> must get removed from $b" + diff "$A" "$B" | grep '^[<>]' | sort + rm -f "$A" "$B" exit 1 fi done diff --git a/xonotic-credits.txt b/xonotic-credits.txt index 20e6048f9..368b64b42 100644 --- a/xonotic-credits.txt +++ b/xonotic-credits.txt @@ -26,6 +26,7 @@ FruitieX *Music / Sound FX mand1nga Merlijn Hofstra +remaxim *Engine Code Additions & QA Rudolf "divVerent" Polzer @@ -48,8 +49,11 @@ DarkPlaces by Forest "LordHavoc" Hale **Active Contributors +Antonio "terencehill" Piu Ben "MooKow" Banker +Calinou Kristian "morfar" Johansson +kojn Maik "SavageX" Merten MrBougo Stephan "esteel" Stahl