diff --git a/.gitignore b/.gitignore index 8fb7001634..cc78ea48b9 100644 --- a/.gitignore +++ b/.gitignore @@ -1,9 +1,13 @@ .travis.yml *.o *.lo +*.vs shadows.dat bin_unix/native_client bin_unix/native_server +bin_win32/ac_* +bin_win32/private/* +bin_win/logs/* config/authpreprivate.cfg config/authprivate.cfg config/history @@ -35,6 +39,12 @@ source/src/ac_client source/src/ac_server source/src/cube.h.gch source/src/Makefile_local +source/vcpp/.vs +source/vcpp/Debug +source/vcpp/Profile +source/vcpp/Release +source/vcpp/Standalone +source/vcpp/Standalone Debug clientlog*.txt dumpmapconfig.txt packetlog.txt diff --git a/bin_win32/ac_client.exe b/bin_win32/ac_client.exe deleted file mode 100644 index f23cfc4a38..0000000000 Binary files a/bin_win32/ac_client.exe and /dev/null differ diff --git a/config/docs.cfg b/config/docs.cfg index dd5a1a378c..8644199eb9 100644 --- a/config/docs.cfg +++ b/config/docs.cfg @@ -3721,12 +3721,12 @@ docref [cleardemo]; docident [deleteservermap] [Deletes a map from the current server.]; docargument [A] [map name] [] [0]; docident [forceme] [Calls a vote to forceteam yourself to the specified team.]; -docargument [T] [the team to force yourself to] [0-4] [0]; +docargument [T] [the team to force yourself to] [0 (CLA), 1 (RVSF), 2 (CLA-SPECT), 3 (RVSF-SPECT), 4 (SPECTATOR)] [0]; docremark [By default, if you are on team CLA or RVSF, this command will force you to the enemy team, no arguments necessary.]; docref [forceteam]; docident [forceteam] [Calls a vote to force the specified player to switch to the specified team.]; docargument [C] [client number of player] [integer] [0]; -docargument [T] [the team to force to] [0-4] [0]; +docargument [T] [the team to force to] [0 (CLA), 1 (RVSF), 2 (CLA-SPECT), 3 (RVSF-SPECT), 4 (SPECTATOR)] [0]; docref [forceme]; docref [setadmin]; docident [getvita] [Get vita for a client.]; diff --git a/config/menus_multiplayer.cfg b/config/menus_multiplayer.cfg index 59a18150fa..0ad578afb3 100644 --- a/config/menus_multiplayer.cfg +++ b/config/menus_multiplayer.cfg @@ -202,12 +202,27 @@ menuinitselection 2 newmenu [Team adjustment] menuitem [Initiate shuffleteams] shuffleteams menuitem [Force a team change] [ showmenu [force team] ] +menuitem [Force to spectate] [ showmenu [force spectate] ] menuitem [Force yourself to enemy team] forceme menuitem [Initiate autoteam] [ showmenu Auto-team ] //// In-Game > Team adjustment > force team //// // hardcoded +//// In-Game > Team adjustment > force spectate //// +// hardcoded + +//// In-Game > Team adjustment > force spectate > select team //// + +newmenu [Force to spectator team] +tempalias _forcespectcn 0 +menuinit [ + resetcurmenu + menuitem "Force to team \f3CLA-SPECT" [ forceteam $_forcespectcn 2 ] + menuitem "Force to team \f1RVSF-SPECT" [ forceteam $_forcespectcn 3 ] + menuitem "Force to SPECTATOR" [ forceteam $_forcespectcn 4 ] +] + //// In-Game > Team adjustment > Auto-team //// newmenu Auto-team diff --git a/config/menus_settings.cfg b/config/menus_settings.cfg index 6fddb03a34..be168c468a 100644 --- a/config/menus_settings.cfg +++ b/config/menus_settings.cfg @@ -89,26 +89,35 @@ const __fsaa_valuemap [-1 0 2 4 8 16] const __aniso_valuemap [0 2 4 8 16] const __minlod_valuemap [60 100 200 250] const __watersubdiv_valuemap [16 8 4 2 1] -menuitemslider "Graphics detail: " 1 6 "$gfxqualityalias" [Horrible Low Medium Good High "INSANE! (May perform slowly on older gfx)"] [ new_gfx_quality $arg1; refreshcurmenu ] -menuitemslider [Scope FOV: ] 5 60 "$scopefov" 5 [ scopefov $arg1 ] 1 -menuitemslider [Antialiasing (FSAA): ] 0 5 "(findlist $__fsaa_valuemap $fsaa)" [Default Off 2 4 8 16] [ fsaa (at $__fsaa_valuemap $arg1) ] -menuitemslider [Anisotropic filtering: ] 0 4 "(findlist $__aniso_valuemap $aniso)" [Off 2 4 8 16] [ aniso (at $__aniso_valuemap $arg1) ] -menuitemslider [Minimal level of detail: ] 0 3 "(findlist $__minlod_valuemap $minlod)" [Low Decent Good Best] [ minlod (at $__minlod_valuemap $arg1) ] -menuitemslider [Light error: ] 1 100 "$lighterror" 5 [ lighterror $arg1 ] -menuitemslider [Water subdivision: ] 0 4 "(findlist $__watersubdiv_valuemap $watersubdiv)" ["Lowest quality" "Low quality" "Medium quality" "High quality" "Highest quality"] [ watersubdiv (at $__watersubdiv_valuemap $arg1) ] -menuitemslider [Dynamic shadows: ] 0 2 __getshadowq [Off Blob Stencil] [ (concatword __setshadowq_ $arg1) ] 1 -menuitemslider [Tex-reduce: ] -1 3 "$texreduce" 1 [ texreduce $arg1 ] -menuitemcheckbox [Water reflection: ] "$waterreflect" [ waterreflect $arg1 ] -menuitemcheckbox [Dynamic lights: ] "$dynlight" [ dynlight $arg1 ] -menuitemcheckbox [Bulletholes: ] "$bullethole" [ bullethole $arg1 ] -menuitemcheckbox [Scorch: ] "$scorch" [ scorch $arg1 ] -menuitemcheckbox "Ignore map override: Disable water reflection" "$ignoreoverride_nowaterreflect" [ ignoreoverride_nowaterreflect $arg1 ] -menuitemcheckbox "Ignore map override: Limit water waveheight" "$ignoreoverride_limitwaveheight" [ ignoreoverride_limitwaveheight $arg1 ] -menuitemcheckbox "Ignore map override: Disable stencil shadows" "$ignoreoverride_nostencilshadows" [ ignoreoverride_nostencilshadows $arg1 ] -menuitem "" -1 -menuitem "FPS Range\i\3" [ showmenu [FPS Range] ] -menuitem "" -1 -menuitem "\f2\t\t [ Apply now! ]" [ resetgl ] +menuinit [ + resetcurmenu + menuitemslider "Graphics detail: " 1 6 "$gfxqualityalias" [Horrible Low Medium Good High "INSANE! (May perform slowly on older gfx)"] [ new_gfx_quality $arg1; refreshcurmenu ] + menuitemslider [Scope FOV: ] 5 60 "$scopefov" 5 [ scopefov $arg1 ] 1 + menuitemslider [Antialiasing (FSAA): ] 0 5 "(findlist $__fsaa_valuemap $fsaa)" [Default Off 2 4 8 16] [ fsaa (at $__fsaa_valuemap $arg1) ] + menuitemslider [Anisotropic filtering: ] 0 4 "(findlist $__aniso_valuemap $aniso)" [Off 2 4 8 16] [ aniso (at $__aniso_valuemap $arg1) ] + menuitemslider [Minimal level of detail: ] 0 3 "(findlist $__minlod_valuemap $minlod)" [Low Decent Good Best] [ minlod (at $__minlod_valuemap $arg1) ] + menuitemslider [Light error: ] 1 100 "$lighterror" 5 [ lighterror $arg1 ] + menuitemslider [Water subdivision: ] 0 4 "(findlist $__watersubdiv_valuemap $watersubdiv)" ["Lowest quality" "Low quality" "Medium quality" "High quality" "Highest quality"] [ watersubdiv (at $__watersubdiv_valuemap $arg1) ] + menuitemslider [Dynamic shadows: ] 0 2 __getshadowq [Off Blob Stencil] [ (concatword __setshadowq_ $arg1) ] 1 + menuitemslider [Explosion effects: ] 0 1 "$mtexplosion" [Simple Detailed] [ mtexplosion $arg1 ] 1 + menuitemslider [Tex-reduce: ] -1 3 "$texreduce" 1 [ texreduce $arg1 ] + menuitemcheckbox [Water reflection: ] "$waterreflect" [ waterreflect $arg1 ; refreshcurmenu ] + menuitemgreyedout (! $waterreflect) + menuitemslider [Water reflection quality: ] 6 10 "$reflectsize" [64px 128px 256px 512px 1024px] [ reflectsize $arg1 ] 1 + menuitemcheckbox [Water refraction: ] "$waterrefract" [ waterrefract $arg1 ] + menuitemgreyedout 0 + menuitemslider [Wave height: ] 0 10 "(* $waveheight 10)" ["0.0" "0.1" "0.2" "0.3" "0.4" "0.5" "0.6" "0.7" "0.8" "0.9" "1.0"] [ waveheight (divf $arg1 10.0) ] 1 + menuitemcheckbox [Dynamic lights: ] "$dynlight" [ dynlight $arg1 ] + menuitemcheckbox [Bulletholes: ] "$bullethole" [ bullethole $arg1 ] + menuitemcheckbox [Scorch: ] "$scorch" [ scorch $arg1 ] + menuitemcheckbox "Ignore map override: Disable water reflection" "$ignoreoverride_nowaterreflect" [ ignoreoverride_nowaterreflect $arg1 ] + menuitemcheckbox "Ignore map override: Limit water waveheight" "$ignoreoverride_limitwaveheight" [ ignoreoverride_limitwaveheight $arg1 ] + menuitemcheckbox "Ignore map override: Disable stencil shadows" "$ignoreoverride_nostencilshadows" [ ignoreoverride_nostencilshadows $arg1 ] + menuitem "" -1 + menuitem "FPS Range\i\3" [ showmenu [FPS Range] ] + menuitem "" -1 + menuitem "\f2\t\t [ Apply now! ]" [ resetgl ] +] //// Main > Settings > Video > Advanced video settings > FPS Range //// @@ -128,28 +137,62 @@ menuitem [I don't understand LOD (250+ FPS)] [ closecurmenu; maxfps 0; fpsra newmenu HUD alias wallclockformat "" // strftime formatting alias wallclockformatlist ["" %H:%M %H:%M:%S %I:%M%p %I:%M:%S%p U%H:%M U%H:%M:%S] //"U" at beginning means UTC/GMT time -menuitem [Show:] -1 -menuitemcheckbox [ Gun ] "$hudgun" [ hudgun $arg1 ] -menuitemcheckbox [ Team icon ] "(= $hideteam 0)" [ hideteam (= $arg1 0) ] -menuitemcheckbox [ Icons ] "(= $hidehudequipment 0)" [ hidehudequipment (= $arg1 0) ] -menuitemcheckbox [ Console ] "(= $hideconsole 0)" [ hideconsole (= $arg1 0) ] -menuitemcheckbox [ Player names ] "$showtargetname" [ showtargetname $arg1 ] -menuitemcheckbox [ Spectator info ] "(= $hidespecthud 0)" [ hidespecthud (= $arg1 0) ] -menuitemcheckbox [ Quick messages ] "(= $hidehudmsgs 0)" [ hidehudmsgs (= $arg1 0) ] -menuitemcheckbox [ Damage direction indicator ] "(= $hidedamageindicator 0)" [ hidedamageindicator (= $arg1 0) ] -menuitemcheckbox [ Damage screen flash ] "$damagescreen" [ damagescreen $arg1 ] -menuitemslider [ Damage maxroll: ] 0 (getvarrange max maxrolleffect) "$maxrolleffect" 1 [ maxrolleffect $arg1 ] -menuitemcheckbox [ Team score counters ] "(= $hideteamscorehud 0)" [ hideteamscorehud (= $arg1 0) ] -menuitemcheckbox [ KTF flag direction indicator ] "(! $hidektfindicator)" [ hidektfindicator (! $arg1) ] -menuitemcheckbox [ Radar ] "(= $hideradar 0)" [ hideradar (= $arg1 0) ] -menuitemslider [ Radar zoom: ] 5 500 [ $radarheight ] 5 [ radarheight $arg1 ] 1 -menuitemslider [ Votes: ] 0 2 "$hidevote" ["Always show" "Show until you vote" "Never show"] [ hidevote $arg1 ] 1 -menuitemradio [ Graphics statistics: ] 0 2 "$showstats" [None "FPS Only" All] [ showstats $arg1 ] 1 -menuitemslider [ Game time: ] 0 2 "$gametimedisplay" [None "Count backward" "Count forward"] [ gametimedisplay $arg1 ] 1 -menuitemslider [ Wall clock: ] 0 6 [findlist $wallclockformatlist $wallclockformat] [None "HH:MM (local, 24h)" "HH:MM:SS (local, 24h)" "HH:MM (local, 12h)" "HH:MM:SS (local, 12h)" "HH:MM (UTC/GMT)" "HH:MM:SS (UTC/GMT)"] [ alias wallclockformat (at $wallclockformatlist $arg1)] 1 -menuitemradio [ Hand alignment: ] 0 1 "$righthanded" [Left-handed Right-handed] [ righthanded $arg1 ] 1 -menuitemslider [ Max-roll: ] 0 (getvarrange max maxroll) "$maxroll" 1 [ maxroll $arg1 ] -menuitemslider [ Spectator max-roll: ] 0 (getvarrange max maxrollremote) "$maxrollremote" 2 [ maxrollremote $arg1 ] +menuinit [ + resetcurmenu + menuitem [Show:] -1 + menuitemcheckbox [ Gun ] "$hudgun" [ hudgun $arg1 ; refreshcurmenu ] + menuitemgreyedout (! $hudgun) + menuitemcheckbox [ Gun when spectating: ] "$specthudgun" [ specthudgun $arg1 ] + menuitemcheckbox [ Disable weapon sway: ] "$nosway" [ nosway $arg1 ] + menuitemradio [ Hand alignment: ] 0 1 "$righthanded" [Left-handed Right-handed] [ righthanded $arg1 ] 1 + menuitemgreyedout 0 + menuitem "" -1 + menuitemcheckbox [ Team icon ] "(= $hideteam 0)" [ hideteam (= $arg1 0) ] + menuitemcheckbox [ Team score counters ] "(= $hideteamscorehud 0)" [ hideteamscorehud (= $arg1 0) ; refreshcurmenu ] + menuitemgreyedout $hideteamscorehud + menuitemslider [ Flag score HUD style: ] 0 2 "$flagscorehudtransparency" [ "Icon set 'flag gone'" "Transparency, icon set 'flag gone'" "Transparency, classic icon set" ] [ flagscorehudtransparency $arg1 ] 1 + menuitemgreyedout 0 + menuitemcheckbox [ KTF flag direction indicator ] "(! $hidektfindicator)" [ hidektfindicator (! $arg1) ; refreshcurmenu ] + menuitemgreyedout $hidektfindicator + menuitemslider [ KTF indicator transparency: ] 1 100 "$ktfindicatoralpha" 5 [ ktfindicatoralpha $arg1 ] + menuitemgreyedout 0 + menuitemcheckbox [ Icons ] "(= $hidehudequipment 0)" [ hidehudequipment (= $arg1 0) ] + menuitemcheckbox [ Console ] "(= $hideconsole 0)" [ hideconsole (= $arg1 0) ] + menuitemcheckbox [ Player names ] "$showtargetname" [ showtargetname $arg1 ] + menuitemcheckbox [ Spectator info ] "(= $hidespecthud 0)" [ hidespecthud (= $arg1 0) ] + menuitemcheckbox [ Quick messages ] "(= $hidehudmsgs 0)" [ hidehudmsgs (= $arg1 0) ] + menuitem "" -1 + menuitemcheckbox [ Damage direction indicator ] "(= $hidedamageindicator 0)" [ hidedamageindicator (= $arg1 0) ; refreshcurmenu ] + menuitemgreyedout $hidedamageindicator + menuitemslider [ Damage indicator size: ] 20 500 "$damageindicatorsize" 10 [ damageindicatorsize $arg1 ] 1 + menuitemslider [ Damage indicator distance: ] 40 900 "$damageindicatordist" 20 [ damageindicatordist $arg1 ] 1 + menuitemslider [ Damage indicator fade time: ] 800 1600 "$damageindicatortime" 50 [ damageindicatortime $arg1 ] 1 + menuitemslider [ Damage indicator transparency: ] 20 100 "$damageindicatoralpha" 10 [ damageindicatoralpha $arg1 ] 1 + menuitemgreyedout 0 + menuitem "" -1 + menuitemcheckbox [ Damage screen flash ] "$damagescreen" [ damagescreen $arg1 ; refreshcurmenu ] + menuitemgreyedout (! $damagescreen) + menuitemslider [ Damage screen intensity: ] 7 98 "$damagescreenfactor" 3 [ damagescreenfactor $arg1 ] 1 + menuitemslider [ Damage screen transparency: ] 25 100 "$damagescreenalpha" 5 [ damagescreenalpha $arg1 ] 1 + menuitemslider [ Damage screen fade time: ] 25 355 "$damagescreenfade" 5 [ damagescreenfade $arg1 ] 1 + menuitemgreyedout 0 + menuitem "" -1 + menuitemslider [ Radar: ] 0 2 "$hideradar" ["Always show" "Always hide" "Hide in non-team modes"] [ hideradar $arg1 ; refreshcurmenu ] 1 + menuitemgreyedout (= $hideradar 1) + menuitemslider [ Radar zoom: ] 5 500 [ $radarheight ] 5 [ radarheight $arg1 ] 1 + menuitemslider [ Minimap resolution: ] 7 10 "$minimapres" 1 [ minimapres $arg1 ] 1 + menuitemslider [ Radar icon size: ] 4 64 "$radarentsize" 2 [ radarentsize $arg1 ] 1 + menuitemcheckbox [ Radar Compass: ] "$hidecompass" [ hidecompass $arg1 ] + menuitemgreyedout 0 + menuitem "" -1 + menuitemslider [ Votes: ] 0 2 "$hidevote" ["Always show" "Show until you vote" "Never show"] [ hidevote $arg1 ; refreshcurmenu ] 1 + menuitemgreyedout (= $hidevote 2) + menuitemslider [ Vote display transparency: ] 15 255 "$votealpha" 15 [ votealpha $arg1 ] 1 + menuitemgreyedout 0 + menuitemradio [ Graphics statistics: ] 0 2 "$showstats" [None "FPS Only" All] [ showstats $arg1 ] 1 + menuitemslider [ Game time: ] 0 2 "$gametimedisplay" [None "Count backward" "Count forward"] [ gametimedisplay $arg1 ] 1 + menuitemslider [ Wall clock: ] 0 6 [findlist $wallclockformatlist $wallclockformat] [None "HH:MM (local, 24h)" "HH:MM:SS (local, 24h)" "HH:MM (local, 12h)" "HH:MM:SS (local, 12h)" "HH:MM (UTC/GMT)" "HH:MM:SS (UTC/GMT)"] [ alias wallclockformat (at $wallclockformatlist $arg1)] 1 +] //// Main > Settings > Console //// @@ -180,22 +223,35 @@ menuitemcheckbox "Disable igraphs: " "$hideigraphs" [ hideigraphs $arg1 ] newmenu "\fsGameplay" alias nickhighlight 0 alias __gibsgore 1 -menuitemtextinput "Nickname: " "result $curname" [ name $arg1 ] -menuitemslider "Player skins: " 0 2 "$teamdisplaymode" [Normal "Colored vests" "Full color"] [ teamdisplaymode $arg1 ] 1 -menuitemslider "Custom player skins: " 0 2 "$hidecustomskins" ["Always show" "Show in non-team modes" "Never show"] [ hidecustomskins $arg1 ] 1 -menuitem "" -1 -menuitemcheckbox "Reduced violence mode: " "$poniesmodeon" [ reducedviolencemode $arg1 ] -menuitemslider "Gib gore: " 0 4 "$__gibsgore" [Off Normal Good Messy Unrealistic] [ gibsgore $arg1 ] -menuitemslider "Name highlight color: " 0 9 "$nickhighlight" [ "\f0green \f5(default)" "\f1blue" "\f2yellow" "\f3red" "\f4gray" "white" "\f6dark brown" "\f7dark red" "\f8purple" "\f9orange" ] [ nickhighlight = $arg1; HIGHLIGHT = (concatword "\f" $nickhighlight) ] -menuitemcheckbox "Show scores on death: " "$showscoresondeath" [ showscoresondeath $arg1 ] -menuitem "Change to the enemy team" changeteam -menuitem "Change weapon\i\3" [ showmenu Weapons ] -menuitem "Change player skin\i\3" [ showmenu @(at [CLA RVSF CLA RVSF ANY ANY ANY] (player1 team)) ] -menuitem "Weapon settings\i\3" [ showmenu [Weapon Settings] ] -menuitem "Edit kill messages\i\3" [ showmenu [Kill Messages] ] -menuitem "Bot settings\i\3" [ showmenu [Bot settings] ] -menuitem "" -1 -menuitemcheckbox "Use high-res player skins" "(>= (findlist (zipmodlist active) protox_hq_reskin) 0)" [ if $arg1 [addzipmod protox_hq_reskin; resetgl] [zipmodremove protox_hq_reskin; resetgl] ] +menuinit [ + resetcurmenu + menuitemtextinput "Nickname: " "result $curname" [ name $arg1 ] + menuitemslider "Player skins: " 0 2 "$teamdisplaymode" [Normal "Colored vests" "Full color"] [ teamdisplaymode $arg1 ] 1 + menuitemslider "Custom player skins: " 0 2 "$hidecustomskins" ["Always show" "Show in non-team modes" "Never show"] [ hidecustomskins $arg1 ] 1 + menuitem "" -1 + menuitemcheckbox "Reduced violence mode: " "$poniesmodeon" [ reducedviolencemode $arg1 ] + menuitemslider "Gib gore: " 0 4 "$__gibsgore" [Off Normal Good Messy Unrealistic] [ gibsgore $arg1 ] 1 + menuitemcheckbox "Hide dead player bodies: " "$popdeadplayers" [ popdeadplayers $arg1 ] + menuitemslider "Name highlight color: " 0 9 "$nickhighlight" [ "\f0green \f5(default)" "\f1blue" "\f2yellow" "\f3red" "\f4gray" "white" "\f6dark brown" "\f7dark red" "\f8purple" "\f9orange" ] [ nickhighlight = $arg1; HIGHLIGHT = (concatword "\f" $nickhighlight) ] 1 + menuitemcheckbox "Show scores on death: " "$showscoresondeath" [ showscoresondeath $arg1 ] + menuitemcheckbox "Show shotlines: " "$shotline" [ shotline $arg1 ; refreshcurmenu ] + menuitemgreyedout (! $shotline) + menuitemslider "Shotline duration: " 50 300 "$shotlinettl" 5 [ shotlinettl $arg1 ] 1 + menuitemgreyedout 0 + menuitem "" -1 + menuitemslider "Camera max-roll (movement): " 0 (getvarrange max maxroll) "$maxroll" 1 [ maxroll $arg1 ] 1 + menuitemslider "Camera max-roll (damage): " 0 (getvarrange max maxrolleffect) "$maxrolleffect" 1 [ maxrolleffect $arg1 ] 1 + menuitemslider "Spectator max-roll: " 0 (getvarrange max maxrollremote) "$maxrollremote" 2 [ maxrollremote $arg1 ] 1 + menuitem "" -1 + menuitem "Change to the enemy team" changeteam + menuitem "Change weapon\i\3" [ showmenu Weapons ] + menuitem "Change player skin\i\3" [ showmenu @(at [CLA RVSF CLA RVSF ANY ANY ANY] (player1 team)) ] + menuitem "Weapon settings\i\3" [ showmenu [Weapon Settings] ] + menuitem "Edit kill messages\i\3" [ showmenu [Kill Messages] ] + menuitem "Bot settings\i\3" [ showmenu [Bot settings] ] + menuitem "" -1 + menuitemcheckbox "Use high-res player skins" "(>= (findlist (zipmodlist active) protox_hq_reskin) 0)" [ if $arg1 [addzipmod protox_hq_reskin; resetgl] [zipmodremove protox_hq_reskin; resetgl] ] +] //// Main > Settings > Gameplay > Weapons //// @@ -282,6 +338,7 @@ const __DEFAULT_SCOREBOARD [ sc_frags Frags sc_deaths Deaths sc_ratio Ratio + sc_score Score sc_lag Lag sc_clientnum "Client number" sc_name Name @@ -466,6 +523,7 @@ alias __soundquality 3 menuitemslider "Sound volume: " 0 255 "$soundvol" 16 [ soundvol $arg1 ] menuitemslider "Music volume: " 0 255 "$musicvol" 16 [ musicvol $arg1 ] menuitemslider "Sound detail: " 1 3 "($__soundquality)" [Low Medium High] [ __set_sound_quality $arg1; refreshcurmenu ] +menuitemcheckbox "Keep game audio playing when window is minimized: " "$soundfocus" [ soundfocus $arg1 ] menuitem "" -1 menuitem "Mute/Un-mute specific sounds\i\3" [ showmenu [Mute specific sounds] ] menuitem "" -1 @@ -532,6 +590,9 @@ menuitemslider "Milliseconds between pinging servers: " 1000 60000 "$servpingrat menuitemslider "Screenshot type: " 0 5 __getscreenshottype $__screenshottypes [ screenshottype (at "1 1 1 1 2 0" $arg1) ; if (< $arg1 4) [ jpegquality (at [50 70 85 100] $arg1) ] ] menuitemslider "Font type: " 0 2 [findlist $__fontlist (curfont)] [Default Serif Monospace] [ setfont (at $__fontlist $arg1) ] menuitemslider "Mini-map background style: " 0 2 "$showmapbackdrop" ["Fully Transparent" Black White/Transparent] [ showmapbackdrop $arg1 ] +menuitemslider "Mini-map backdrop transparency: " 10 100 "$showmapbackdroptransparency" 5 [ showmapbackdroptransparency $arg1 ] +menuitemslider "Overview flags rendering: " 0 2 "$overviewflags" [Regular "Model-askew" "Radar icons"] [ overviewflags $arg1 ] 1 +menuitemcheckbox "Show speed: " "$showspeed" [ showspeed $arg1 ] menuitemslider "Menu map file sort order: " 0 -1 "$menufilesort_cgz" (listoptions menufilesortorders) [menufilesort_cgz = $arg1] menuitemslider "Menu demo file sort order: " 0 -1 "$menufilesort_dmo" (listoptions menufilesortorders) [menufilesort_dmo = $arg1] menuitem "Edit hook script \i\1" [ showmenu "Edit cubescript hook" ] @@ -763,6 +824,9 @@ const new_gfx_quality [ waterrefract 1 texreduce 0 hidebigmenuimages 0 + minimapres 10 + reflectsize 10 + mtexplosion 1 ] [ if (= $arg1 5) [ // High gfx quality fsaa 4 @@ -786,6 +850,9 @@ const new_gfx_quality [ waterrefract 0 texreduce 0 hidebigmenuimages 0 + minimapres 10 + reflectsize 10 + mtexplosion 1 ] [ if (= $arg1 4) [ // Good gfx quality (DEFAULT) fsaa 0 @@ -809,6 +876,9 @@ const new_gfx_quality [ waterrefract 0 texreduce 0 hidebigmenuimages 0 + minimapres 9 + reflectsize 9 + mtexplosion 1 ] [ if (= $arg1 3) [ // Medium gfx quality fsaa 0 @@ -837,6 +907,9 @@ const new_gfx_quality [ waterrefract 0 texreduce 0 hidebigmenuimages 0 + minimapres 9 + reflectsize 9 + mtexplosion 1 ] [ if (= $arg1 2) [ // Low gfx quality fsaa 0 @@ -860,6 +933,9 @@ const new_gfx_quality [ waterrefract 0 texreduce 1 hidebigmenuimages 1 + minimapres 8 + reflectsize 8 + mtexplosion 0 ] [ // Horrible gfx quality fsaa 0 aniso 0 @@ -883,6 +959,9 @@ const new_gfx_quality [ waterrefract 0 texreduce -1 hidebigmenuimages 1 + minimapres 7 + reflectsize 7 + mtexplosion 0 ] ] ] diff --git a/config/opt/compatibility.cfg b/config/opt/compatibility.cfg index eaf88ea8e1..46d08fc168 100644 --- a/config/opt/compatibility.cfg +++ b/config/opt/compatibility.cfg @@ -22,16 +22,18 @@ const orderscorecolumns [ sc_flags 2; sc_frags 3; sc_deaths 4; - sc_lag 5; + sc_score 5; + sc_lag 6; sc_ratio -1; ] [ sc_flags 0; sc_frags 1; sc_deaths 2; sc_ratio -1; - sc_lag 4; - sc_clientnum 5; - sc_name 6; + sc_score 4; + sc_lag 5; + sc_clientnum 6; + sc_name 7; ] ] diff --git a/source/src/audiomanager.cpp b/source/src/audiomanager.cpp index 722a76b121..bc8e032cf2 100644 --- a/source/src/audiomanager.cpp +++ b/source/src/audiomanager.cpp @@ -507,6 +507,18 @@ void audiomanager::detachsounds(playerent *owner) locations.replaceworldobjreference(physentreference(owner), staticreference(owner->o)); } +void audiomanager::stopplayersounds(playerent *owner) +{ + if(nosound) return; + // stop and drop all sounds from this player + physentreference ref(owner); + loopv(locations) + { + location *l = locations[i]; + if(!l || !l->ref || l->stale) continue; + if(*l->ref == ref) l->drop(); + } +} VARP(maxsoundsatonce, 0, 32, 100); diff --git a/source/src/bot/bot_waypoint.cpp b/source/src/bot/bot_waypoint.cpp index 8dbeec50e8..15b36513c6 100644 --- a/source/src/bot/bot_waypoint.cpp +++ b/source/src/bot/bot_waypoint.cpp @@ -1418,6 +1418,11 @@ bool CWaypointClass::CanPlaceNodeHere(const vec &from) return false; } + if (s->tag & TAGANYCLIP) + { + return false; + } + if (fabs((float)(s->ceil - s->floor)) < player1->radius) { return false; @@ -1696,12 +1701,20 @@ void wpvisible(int *on) COMMAND(wpvisible, "i"); -void wpsave(void) +void wpsave(char *name) { - WaypointClass.SaveWaypoints(); + if(name && name[0]) + { + WaypointClass.SetMapName(name); + } + else + { + WaypointClass.SetMapName(getclientmap()); + } + WaypointClass.SaveWaypoints(); } -COMMAND(wpsave, ""); +COMMAND(wpsave, "s"); void wpload(void) { diff --git a/source/src/client.cpp b/source/src/client.cpp index 2687f5a12d..c5f45be535 100644 --- a/source/src/client.cpp +++ b/source/src/client.cpp @@ -194,6 +194,7 @@ void disconnect(int onlyclean, int async) loopv(players) zapplayer(players[i]); clearvote(); audiomgr.clearworldsounds(false); + discscores.shrink(0); localdisconnect(); } if(!onlyclean) localconnect(); @@ -284,7 +285,7 @@ COMMAND(hudecho, "c"); void whereami() { - conoutf("you are at (%.2f,%.2f)", player1->o.x, player1->o.y); + conoutf("you are at (%.2f, %.2f)", player1->o.x, player1->o.y); } COMMAND(whereami, ""); diff --git a/source/src/clientgame.cpp b/source/src/clientgame.cpp index 9608e3ca28..68def56dc0 100644 --- a/source/src/clientgame.cpp +++ b/source/src/clientgame.cpp @@ -464,6 +464,8 @@ void deathstate(playerent *pl) pl->attacking = false; pl->weaponsel->onownerdies(); + audiomgr.stopplayersounds(pl); // stop all sounds from this player when they die + if(pl==player1) { if(showscoresondeath) showscores(true); @@ -1673,14 +1675,9 @@ COMMAND(gonext, "i"); COMMANDN(callvote, scallvote, "iss"); //fixme,ah COMMANDF(vote, "i", (int *v) { vote(*v); }); -void cmd_pause(int* arg1) +void cmd_pause(int *arg1) { if(*arg1 != 0 && *arg1 != 1) return; - if(servstate.mastermode != MM_MATCH && servstate.mastermode != MM_PRIVATE) - { - conoutf("You may only pause the game in mastermode private or match."); - return; - } defformatstring(m)("%d", *arg1); callvote(SA_PAUSE, m, "-1", "0"); } @@ -1740,7 +1737,7 @@ COMMAND(setadmin, "is"); static vector mlines; -void *kickmenu = NULL, *banmenu = NULL, *forceteammenu = NULL, *giveadminmenu = NULL; +void *kickmenu = NULL, *banmenu = NULL, *forceteammenu = NULL, *giveadminmenu = NULL, *forcespectatemenu = NULL; void refreshsopmenu(void *menu, bool init) { @@ -1753,7 +1750,28 @@ void refreshsopmenu(void *menu, bool init) copystring(m.name, colorname(players[i])); string kbr; if(getalias("_kickbanreason")!=NULL) formatstring(kbr)(" [ %s ]", getalias("_kickbanreason")); // leading space! - formatstring(m.cmd)("%s %d%s", menu==kickmenu ? "kick" : (menu==banmenu ? "ban" : (menu==forceteammenu ? "forceteam" : "giveadmin")), i, (menu==kickmenu||menu==banmenu)?(strlen(kbr)>8?kbr:" NONE"):""); // 8==3 + "format-extra-chars" + if(menu == forcespectatemenu) + { + if(servstate.mastermode == MM_MATCH || servstate.mastermode == MM_PRIVATE) + { + if(m_teammode) + { + formatstring(m.cmd)("tempalias _forcespectcn %d; showmenu [Force to spectator team]", i); + } + else + { + formatstring(m.cmd)("forceteam %d 4", i); + } + } + else + { + formatstring(m.cmd)("forceteam %d 4", i); + } + } + else + { + formatstring(m.cmd)("%s %d%s", menu==kickmenu ? "kick" : (menu==banmenu ? "ban" : ((menu==forceteammenu) ? "forceteam" : "giveadmin")), i, (menu==kickmenu||menu==banmenu)?(strlen(kbr)>8?kbr:" NONE"): ""); // 8==3 + "format-extra-chars" + } menuitemmanual(menu, m.name, m.cmd); } } diff --git a/source/src/console.cpp b/source/src/console.cpp index 96636e6835..483c521f3a 100644 --- a/source/src/console.cpp +++ b/source/src/console.cpp @@ -502,6 +502,10 @@ void consolekey(int code, bool isdown, SDL_Keymod mod) scrolldoc(4); break; + case SDLK_F12: + screenshot(NULL); + break; + case SDL_AC_BUTTON_WHEELUP: case SDLK_UP: if(histpos > history.length()) histpos = history.length(); diff --git a/source/src/editing.cpp b/source/src/editing.cpp index 2ae53bc839..ade702711e 100644 --- a/source/src/editing.cpp +++ b/source/src/editing.cpp @@ -42,6 +42,7 @@ VARFP(showeditingsettings, 0, 0, 3, { if(showeditingsettings){ toucheditingsetti void toggleedit(bool force) { + if(watchingdemo) return; // do not allow editing while watching a demo. * add message that editing is not allowed while watching demo?? * if(player1->state==CS_DEAD) return; // do not allow dead players to edit to avoid state confusion if(!force && !editmode && !allowedittoggle()) return; // not in most multiplayer modes if(player1->state == CS_SPECTATE) @@ -79,6 +80,8 @@ void toggleedit(bool force) if(editing && player1->onladder) player1->onladder = false; if(editing && (player1->weaponsel->type == GUN_SNIPER && ((sniperrifle *)player1->weaponsel)->scoped)) ((sniperrifle *)player1->weaponsel)->onownerdies(); // or ondeselecting() if(editing && (player1->weaponsel->type == GUN_GRENADE) && ((grenades *)player1->weaponsel)->state < GST_THROWING) ((grenades *)player1->weaponsel)->onownerdies(); + /*prevents flag from being dropped when entering edit mode, allowing flag movement to another position when testing with the flag is needed + if(editing && m_flags_) tryflagdrop(false);*/ if(!force) addmsg(SV_EDITMODE, "ri", editing); } diff --git a/source/src/entities.cpp b/source/src/entities.cpp index 05666589bf..33e6de20c2 100644 --- a/source/src/entities.cpp +++ b/source/src/entities.cpp @@ -176,7 +176,13 @@ void rendermapmodels() { mapmodelinfo *mmi = getmminfo(e.attr2); if(!mmi) continue; - rendermodel(mmi->name, ANIM_MAPMODEL|ANIM_LOOP, e.attr4, 0, vec(e.x, e.y, S(e.x, e.y)->floor + mmi->zoff + float(e.attr3) / ENTSCALE5), e.attr6, float(e.attr1) / ENTSCALE10, float(e.attr5) / ENTSCALE10, 10.0f, 0, NULL, NULL, mmi->scale); + float model_z = S(e.x, e.y)->floor + mmi->zoff + float(e.attr3) / ENTSCALE5; + if(player1->spectatemode == SM_OVERVIEW) + { + float model_top_z = model_z + mmi->h; + if(model_top_z > clmapdims.maxceil - 10) continue; + } + rendermodel(mmi->name, ANIM_MAPMODEL|ANIM_LOOP, e.attr4, 0, vec(e.x, e.y, model_z), e.attr6, float(e.attr1) / ENTSCALE10, float(e.attr5) / ENTSCALE10, 10.0f, 0, NULL, NULL, mmi->scale); } } } @@ -652,13 +658,13 @@ void checkitems(playerent *d) if(OUTBORD(f.pos.x, f.pos.y)) continue; if(f.state==CTFF_DROPPED) // 3d collision for dropped ctf flags { - if(objcollide(d, f.pos, 2.5f, 8.0f)) trypickupflag(i, d); + if(objcollide(d, f.pos, 2.5f, 6.5f)) trypickupflag(i, d); } - else // simple 2d collision + else // 3d collision for flag in base { - vec v = f.pos; - v.z = S(int(v.x), int(v.y))->floor + eyeheight; - if(d->o.dist(v)<2.5f) trypickupflag(i, d); + vec flagpos = f.pos; + flagpos.z = S(int(f.pos.x), int(f.pos.y))->floor; + if(objcollide(d, flagpos, 2.5f, 6.5f)) trypickupflag(i, d); } } if(d==player1) diff --git a/source/src/entity.h b/source/src/entity.h index f88869c5f2..e497417b43 100644 --- a/source/src/entity.h +++ b/source/src/entity.h @@ -129,7 +129,7 @@ enum { ENT_PLAYER = 0, ENT_BOT, ENT_CAMERA, ENT_BOUNCE }; enum { CS_ALIVE = 0, CS_DEAD, CS_SPAWNING, CS_LAGGED, CS_EDITING, CS_SPECTATE }; enum { CR_DEFAULT = 0, CR_MASTER, CR_ADMIN, CR_OWNER, CR_NUM }; enum { SM_NONE = 0, SM_DEATHCAM, SM_FOLLOW1ST, SM_FOLLOW3RD, SM_FOLLOW3RD_TRANSPARENT, SM_FLY, SM_OVERVIEW, SM_NUM }; -enum { FPCN_VOID = -4, FPCN_DEATHCAM = -2, FPCN_FLY = -2, FPCN_OVERVIEW = -1 }; +enum { FPCN_VOID = -4, FPCN_DEATHCAM, FPCN_FLY, FPCN_OVERVIEW }; class physent { diff --git a/source/src/main.cpp b/source/src/main.cpp index 7e24a1e44a..ebe1865c69 100644 --- a/source/src/main.cpp +++ b/source/src/main.cpp @@ -31,8 +31,13 @@ void cleanup(char *msg) // single program exit point; VAR(resetcfg, 0, 0, 1); +VARP(soundfocus, 0, 0, 1); + +int lastsoundvol = 0; + void quit() // normal exit { + if(lastsoundvol > 0) soundvol = lastsoundvol; if(clientlogfile) clientlogfile->fflush(); const char *onquit = getalias("onQuit"); setcontext("hook", "onQuit"); @@ -1086,12 +1091,23 @@ void checkinput() case SDL_WINDOWEVENT_FOCUS_GAINED: // window has gained keyboard focus EVENTDEBUG(concatstring(eb, " SDL_WINDOWEVENT_FOCUS_GAINED")); shouldgrab = true; + if(!soundfocus && lastsoundvol > 0) + { + soundvol = lastsoundvol; + audiomgr.setlistenervol(soundvol); + } break; case SDL_WINDOWEVENT_FOCUS_LOST: // window has lost keyboard focus EVENTDEBUG(concatstring(eb, " SDL_WINDOWEVENT_FOCUS_LOST")); shouldgrab = false; focused = -1; + if(!soundfocus) + { + lastsoundvol = soundvol; + soundvol = 0; + audiomgr.setlistenervol(soundvol); + } break; } break; @@ -1559,7 +1575,7 @@ int main(int argc, char **argv) audiomgr.initsound(); initlog("cfg"); - extern void *scoremenu, *servmenu, *searchmenu, *serverinfomenu, *kickmenu, *banmenu, *forceteammenu, *giveadminmenu, *docmenu, *applymenu, *downloaddemomenu; + extern void *scoremenu, *servmenu, *searchmenu, *serverinfomenu, *kickmenu, *banmenu, *forceteammenu, *forcespectatemenu, *giveadminmenu, *docmenu, *applymenu, *downloaddemomenu; scoremenu = addmenu("score", "columns", false, renderscores, NULL, false, true); servmenu = addmenu("server", NULL, true, refreshservers, serverskey); searchmenu = addmenu("search", NULL, true, refreshservers, serverskey); @@ -1567,6 +1583,7 @@ int main(int argc, char **argv) kickmenu = addmenu("kick player", NULL, true, refreshsopmenu); banmenu = addmenu("ban player", NULL, true, refreshsopmenu); forceteammenu = addmenu("force team", NULL, true, refreshsopmenu); + forcespectatemenu = addmenu("force spectate", NULL, true, refreshsopmenu); giveadminmenu = addmenu("give admin", NULL, true, refreshsopmenu); docmenu = addmenu("reference", NULL, true, renderdocmenu); applymenu = addmenu("apply", "apply changes now?", true, refreshapplymenu); diff --git a/source/src/menus.cpp b/source/src/menus.cpp index 868ff27fa4..dc0e4107ff 100644 --- a/source/src/menus.cpp +++ b/source/src/menus.cpp @@ -466,7 +466,7 @@ struct mitemtextinput : mitemtext virtual void key(int code, bool isdown) { if(input.key(code)) modified = true; - if(action && code == SDLK_RETURN && modified && parent->items.find(this) != parent->items.length() - 1) + if(action && (code == SDLK_RETURN || code == SDLK_KP_ENTER) && modified && parent->items.find(this) != parent->items.length() - 1) { modified = false; execaction(input.buf); @@ -577,6 +577,8 @@ struct mitemslider : mitem else if(code == SDLK_RIGHT) slide(true); } + virtual int select() { return -1; } + virtual void init() { const char *p = valueexp; @@ -1270,14 +1272,13 @@ bool menukey(int code, bool isdown, SDL_Keymod mod) case SDLK_F12: if(curmenu->allowinput) { - extern void screenshot(const char *filename); screenshot(NULL); } break; } if(!curmenu->allowinput || !curmenu->items.inrange(menusel)) return false; mitem &m = *curmenu->items[menusel]; - if(code==SDLK_RETURN || code==SDLK_KP_ENTER || code==SDLK_SPACE || code==SDL_AC_BUTTON_LEFT || code==SDL_AC_BUTTON_MIDDLE) + if(code==SDLK_RETURN || code==SDLK_KP_ENTER || (code==SDLK_SPACE && m.mitemtype != mitem::TYPE_TEXTINPUT) || code==SDL_AC_BUTTON_LEFT || code==SDL_AC_BUTTON_MIDDLE) { if(!m.greyedout && m.select() != -1) audiomgr.playsound(S_MENUENTER, SP_HIGHEST); return true; diff --git a/source/src/physics.cpp b/source/src/physics.cpp index 1c65061b8a..5f8ddc1100 100644 --- a/source/src/physics.cpp +++ b/source/src/physics.cpp @@ -139,7 +139,8 @@ bool mmcollide(physent *d, float &hi, float &lo) // collide with a map for(int i = clentstats.firstclip; i < ents.length(); i++) { entity &e = ents[i]; - if (e.type==CLIP || (e.type == PLCLIP && (d->type == ENT_BOT || d->type == ENT_PLAYER || (d->type == ENT_BOUNCE && ((bounceent *)d)->plclipped)))) + const bool specfly = d->type == ENT_PLAYER && ((playerent *)d)->spectatemode == SM_FLY; + if (e.type==CLIP || (e.type == PLCLIP && !specfly && (d->type == ENT_BOT || d->type == ENT_PLAYER || (d->type == ENT_BOUNCE && ((bounceent *)d)->plclipped)))) { bool hitarea = false; switch(e.attr7 & 3) @@ -226,7 +227,8 @@ bool collide(physent *d, bool spawn, float drop, float rise) const float playerheight = eyeheight + d->aboveeye; float z1 = d->o.z-eyeheight, z2 = z1 + playerheight; if(d->type != ENT_BOUNCE) z1 += 1.26; - const int applyclip = d->type == ENT_BOT || d->type == ENT_PLAYER || (d->type == ENT_BOUNCE && ((bounceent *)d)->plclipped) ? TAGANYCLIP : TAGCLIP; + const bool specfly = d->type == ENT_PLAYER && ((playerent *)d)->spectatemode == SM_FLY; + const int applyclip = (d->type == ENT_BOT || (d->type == ENT_PLAYER && !specfly) || (d->type == ENT_BOUNCE && ((bounceent *)d)->plclipped)) ? TAGANYCLIP : TAGCLIP; for(int y = y1; y<=y2; y++) for(int x = x1; x<=x2; x++) // collide with map { @@ -291,7 +293,7 @@ bool collide(physent *d, bool spawn, float drop, float rise) ceil += (s->vdelta+S(x+1,y)->vdelta+S(x,y+1)->vdelta+S(x+1,y+1)->vdelta)/16.0f; } - if(tagclipped) return true; // tagged clips feel like solids + if(tagclipped && !specfly) return true; // tagged clips feel like solids if(ceillo) lo = floor; } @@ -302,13 +304,16 @@ bool collide(physent *d, bool spawn, float drop, float rise) if(d->type!=ENT_CAMERA) { - loopv(players) // collide with other players + if(!specfly) { - playerent *o = players[i]; - if(!o || o==d) continue; - if(plcollide(d, o, headspace, hi, lo)) return true; + loopv(players) // collide with other players + { + playerent *o = players[i]; + if(!o || o==d) continue; + if(plcollide(d, o, headspace, hi, lo)) return true; + } + if(d!=player1) if(plcollide(d, player1, headspace, hi, lo)) return true; } - if(d!=player1) if(plcollide(d, player1, headspace, hi, lo)) return true; } headspace -= 0.01f; @@ -865,7 +870,7 @@ void attack(bool on) void jumpn(bool on) { static bool wason = false; - player1->jumpnext = on && !wason && !player1->crouching && !intermission && !player1->isspectating() && !ispaused; + player1->jumpnext = on && (player1->state == CS_EDITING || (!wason && !player1->crouching)) && !intermission && !player1->isspectating() && !ispaused; wason = on; if(player1->isspectating()) { @@ -967,6 +972,6 @@ void entinmap(physent *d) // brute force but effective way to find a free spa } // leave ent at original pos, possibly stuck d->resetinterp(); - conoutf("can't find entity spawn spot! (%d, %d)", int(d->o.x), int(d->o.y)); + conoutf("can't find entity spawn spot! (%.2f, %.2f, %.2f)", d->o.x, d->o.y, d->o.z); } diff --git a/source/src/protocol.cpp b/source/src/protocol.cpp index 6b7f890d3b..a215ff9d16 100644 --- a/source/src/protocol.cpp +++ b/source/src/protocol.cpp @@ -474,13 +474,13 @@ void filterlang(char *d, const char *s) void filtercountrycode(char *d, const char *s) // tries to return two uppercase chars or "--" { - if(strlen(s) == 2 && isalpha(s[0]) && isalpha(s[1])) + if(isalpha(s[0]) && isalpha(s[1]) && !s[2]) { d[0] = toupper(s[0]); d[1] = toupper(s[1]); } else d[0] = d[1] = '-'; - d[max(0,min((int)strlen(s),2))] = '\0'; + d[2] = '\0'; } void trimtrailingwhitespace(char *s) @@ -509,7 +509,13 @@ const char *modeacronymnames[] = "PARKOUR", "GEMA" }; -const char *voteerrors[] = { "voting is currently disabled", "there is already a vote pending", "already voted", "can't vote that often", "this vote is not allowed in the current environment (singleplayer/multiplayer)", "no permission", "invalid vote", "server denied your call", "the next map/mode is already set" }; +const char *voteerrors[] = +{ + "voting is currently disabled", "there is already a vote pending", "already voted", "can't vote that often", + "this vote is not allowed in the current environment (singleplayer/multiplayer)","no permission", "invalid vote", + "server denied your call", "the next map/mode is already set", "shuffle teams requires teammode", + "pause is only allowed in mastermode private or match" +}; const char *mmfullnames[] = { "open", "private", "match" }; const char *fullmodestr(int n) { return (n>=-1 && size_t(n+1) < sizeof(modefullnames)/sizeof(modefullnames[0])) ? modefullnames[n+1] : "unknown"; } diff --git a/source/src/protocol.h b/source/src/protocol.h index 11ae1c02c1..995140eaf5 100644 --- a/source/src/protocol.h +++ b/source/src/protocol.h @@ -65,7 +65,7 @@ extern const char *messagenames[SV_NUM]; enum { SA_KICK = 0, SA_BAN, SA_REMBANS, SA_MASTERMODE, SA_AUTOTEAM, SA_FORCETEAM, SA_GIVEADMIN, SA_MAP, SA_RECORDDEMO, SA_STOPDEMO, SA_CLEARDEMOS, SA_SERVERDESC, SA_SHUFFLETEAMS, SA_PAUSE, SA_NUM}; enum { VOTE_NEUTRAL = 0, VOTE_YES, VOTE_NO, VOTE_NUM }; -enum { VOTEE_DISABLED = 0, VOTEE_CUR, VOTEE_MUL, VOTEE_MAX, VOTEE_AREA, VOTEE_PERMISSION, VOTEE_INVALID, VOTEE_WEAK, VOTEE_NEXT, VOTEE_NUM }; +enum { VOTEE_DISABLED = 0, VOTEE_CUR, VOTEE_MUL, VOTEE_MAX, VOTEE_AREA, VOTEE_PERMISSION, VOTEE_INVALID, VOTEE_WEAK, VOTEE_NEXT, VOTEE_SHUFFLETEAMS, VOTEE_PAUSE, VOTEE_NUM }; enum { MM_OPEN = 0, MM_PRIVATE, MM_MATCH, MM_NUM }; enum { MM_MASK = 0x03 }; enum { DC_DEMO = 0, DC_NUM }; enum { DT_INIT = 0, DT_PROGRESS, DT_FINISH, DT_QUIRK, DT_ERROR, DT_NUM }; diff --git a/source/src/protos.h b/source/src/protos.h index 16a6cd8994..1663c7ead5 100644 --- a/source/src/protos.h +++ b/source/src/protos.h @@ -698,6 +698,7 @@ extern char *lang; extern SDL_Window *screen; extern int screenw, screenh; extern int stencilbits; +extern void screenshot(const char *filename); enum { KR_CONSOLE = 1<<0, KR_MENU = 1<<1, KR_EDITMODE = 1<<2 }; extern void keyrepeat(bool on, int mask = ~0); diff --git a/source/src/rendergl.cpp b/source/src/rendergl.cpp index 53ea5f0b7a..491a68b91d 100644 --- a/source/src/rendergl.cpp +++ b/source/src/rendergl.cpp @@ -1146,7 +1146,74 @@ void gl_drawframe(int w, int h, float changelod, float curfps, int elapsed) if(editmode) { - if(cursordepth==1.0f) worldpos = camera1->o; + // in editmode, always use raycube for precise selection + vec start = camera1->o; + int x = int(start.x), y = int(start.y); + + // if we are inside the world and inside the wall, move forward until we exit + if(!OUTBORD(x, y)) + { + sqr *s = S(x, y); + float floor = s->floor, ceil = s->ceil; + if(s->type==FHF) floor -= s->vdelta/4.0f; + if(s->type==CHF) ceil += s->vdelta/4.0f; + + if(SOLID(s) || start.z < floor || start.z > ceil) + { + // we are within a solid geometry, moving forward + vec step = camdir; + step.mul(0.5f); + for(int i = 0; i < 20; i++) + { + start.add(step); + x = int(start.x); y = int(start.y); + if(OUTBORD(x, y)) break; + s = S(x, y); + floor = s->floor; ceil = s->ceil; + if(s->type==FHF) floor -= s->vdelta/4.0f; + if(s->type==CHF) ceil += s->vdelta/4.0f; + if(!SOLID(s) && start.z >= floor && start.z <= ceil) break; + } + } + } + else + { + // we are out of the world, move towards the camera until we enter + vec step = camdir; + step.mul(1.0f); + for(int i = 0; i < 100; i++) + { + start.add(step); + x = int(start.x); y = int(start.y); + if(!OUTBORD(x, y)) + { + // we're entering the world! Check if the position is valid + sqr *s = S(x, y); + float floor = s->floor, ceil = s->ceil; + if(s->type==FHF) floor -= s->vdelta/4.0f; + if(s->type==CHF) ceil += s->vdelta/4.0f; + if(!SOLID(s) && start.z >= floor && start.z <= ceil) break; + } + } + } + + vec surface; + float dist = raycube(start, camdir, surface); + if(dist >= 0) + { + worldpos = start; + vec dir = camdir; + dir.mul(dist); + worldpos.add(dir); + } + else + { + // if raycube fails, use a simple projection + worldpos = camera1->o; + vec dir = camdir; + dir.mul(50); + worldpos.add(dir); + } enablepolygonoffset(GL_POLYGON_OFFSET_LINE); glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); glDepthMask(GL_FALSE); diff --git a/source/src/renderhud.cpp b/source/src/renderhud.cpp index 9e300ed237..e9da848e57 100644 --- a/source/src/renderhud.cpp +++ b/source/src/renderhud.cpp @@ -206,7 +206,7 @@ VARP(crosshairsize, 0, 15, 50); VARP(showstats, 0, 1, 2); VARP(crosshairfx, 0, 1, 3); VARP(crosshairteamsign, 0, 1, 1); -VARP(hideradar, 0, 0, 1); +VARP(hideradar, 0, 0, 2); VARP(hidecompass, 0, 0, 1); VARP(hideteam, 0, 0, 1); VARP(hideteamscorehud, 0, 0, 1); @@ -947,11 +947,15 @@ void gl_drawhud(int w, int h, int curfps, int nquads, int curvert, bool underwat if(!editmode) { - if((!hideradar || showmap) && player1->spectatemode <= SM_FLY) drawradar(p, w, h); // EDITMINIMAP: radar/showmap in editmode will be out-of-date + if((hideradar == 0 || (hideradar == 2 && m_teammode) || showmap) && player1->spectatemode <= SM_FLY) drawradar(p, w, h); // EDITMINIMAP: radar/showmap in editmode will be out-of-date glMatrixMode(GL_MODELVIEW); if(!hideteam && m_teammode) drawteamicons(w, h, is_spect); glMatrixMode(GL_PROJECTION); } + else if(showmap) + { + drawradar(p, w, h); + } char *infostr = editinfo(); int commandh = HUDPOS_Y_BOTTOMLEFT + FONTH; diff --git a/source/src/scoreboard.cpp b/source/src/scoreboard.cpp index 416771e87a..99df5e90df 100644 --- a/source/src/scoreboard.cpp +++ b/source/src/scoreboard.cpp @@ -289,7 +289,7 @@ void reorderscorecolumns() sscore.addcol(sc_frags, "frags"); sscore.addcol(sc_deaths, "deaths"); sscore.addcol(sc_ratio, "ratio"); - sscore.addcol(sc_score, "score"); + if(multiplayer(NULL) || watchingdemo) sscore.addcol(sc_score, "score"); if(multiplayer(NULL) || watchingdemo) sscore.addcol(sc_lag, "pj/ping"); sscore.addcol(sc_clientnum, "cn"); sscore.addcol(sc_name, "name"); diff --git a/source/src/server.cpp b/source/src/server.cpp index facd008f97..127ea8c1b5 100644 --- a/source/src/server.cpp +++ b/source/src/server.cpp @@ -26,11 +26,11 @@ struct servergame ENetAddress servdesc_caller; bool custom_servdesc; int serverstyle; - int sispaused = 0; + int sispaused; // current game string smapname, nextmapname; - int smode, nextgamemode, srvgamesalt; + int smode, nextgamemode, nextgametime, srvgamesalt; int interm; int minremain, gamemillis, gamelimit, nextsendscore; int arenaround, arenaroundstartmillis; @@ -55,6 +55,7 @@ struct servergame forceintermission = false; custom_servdesc = false; serverstyle = SS_GAME; + sispaused = 0; smode = GMODE_TEAMDEATHMATCH; interm = 0; minremain = 0; @@ -221,9 +222,8 @@ void poll_serverthreads() // called once per mainloop-timeslice else if(!startnewservermapsepoch) { // readmapsthread is done - if(servmillis<2000)mlog(ACLOG_INFO,"added %d servermaps",servermaps.length()); - while(!readmapsthread_sem->trywait()) - ; + if(servmillis<2000)mlog(ACLOG_INFO,"added %d servermaps", servermaps.length()); + while(!readmapsthread_sem->trywait()); stage++; } break; @@ -251,6 +251,16 @@ void poll_serverthreads() // called once per mainloop-timeslice { mlog(ACLOG_INFO, "read/updated %d vitas from %s", parsevitas(vitaupdatebuf, vitaupdatebuflen), vitafilename_update_backup);; DELETEA(vitaupdatebuf); + loopvrev(clients) + { + client &c = *clients[i]; + if(c.type != ST_TCPIP) continue; + if(c.checkvitadate(VS_BAN)) + { + mlog(ACLOG_INFO, "[%s] %s disconnected (vita ban update)", c.hostname, c.name); + disconnect_client(c.clientnum, DISC_BANNED); + } + } } stage++; } @@ -312,8 +322,6 @@ void poll_serverthreads() // called once per mainloop-timeslice // update thread-safe data structures (vectors and hashtables can be read concurrently - but to be updated, they need to be locked) poll_logbuffers(); - - } SERVPAR(gamepenalty_cutoff, 30, 60, 120, "gNumber of minutes to remember that a map+mode combination has been played"); @@ -632,13 +640,14 @@ void changemastermode(int newmode) } } else if(sg->matchteamsize) changematchteamsize(sg->matchteamsize); - sendservermode(); + sendservermode(); } } void setpausemode(int newmode) { - if (sg->sispaused != newmode) { + if(sg->sispaused != newmode) + { sg->sispaused = newmode; } @@ -757,7 +766,7 @@ void sendf(int cn, int chan, const char *format, ...) void sendpoints() // only at3_points { - if( sg->gamemillis < sg->nextsendscore ) return; + if(sg->gamemillis < sg->nextsendscore) return; int doers = 0, achievers[MAXCLIENTS]; loopv(clients) @@ -2047,7 +2056,7 @@ void checkitemspawns(int diff) void serverdamage(client *target, client *actor, int damage, int gun, bool gib, const vec &hitpush = vec(0, 0, 0)) { - if ( m_arena && gun == GUN_GRENADE && sg->arenaroundstartmillis + 2000 > sg->gamemillis && target != actor ) return; + if(m_arena && gun == GUN_GRENADE && sg->arenaroundstartmillis + 2000 > sg->gamemillis && target != actor) return; clientstate &ts = target->state; ts.dodamage(damage, gun); if(damage < INT_MAX) @@ -2150,7 +2159,8 @@ void serverdamage(client *target, client *actor, int damage, int gun, bool gib, actor->state.teamkills * 60 * 1000 > sg->gamemillis && actor->state.frags < 4 * actor->state.teamkills ) ) disconnect_client(actor->clientnum, DISC_AUTOKICK); } - } else if ( target!=actor && isteam(target->team, actor->team) ) check_ffire (target, actor, damage); // friendly fire counter + } + else if ( target!=actor && isteam(target->team, actor->team) ) check_ffire (target, actor, damage); // friendly fire counter } #include "serverevents.h" @@ -2783,7 +2793,6 @@ void resetserver(const char *newname, int newmode, int newtime) else savedscores.shrink(0); ctfreset(); - sg->sispaused = false; sg->nextmapname[0] = '\0'; sg->forceintermission = false; } @@ -2889,7 +2898,7 @@ void startgame(const char *newname, int newmode, int newtime, bool notify) packetbuf q(MAXTRANS, ENET_PACKET_FLAG_RELIABLE); send_item_list(q); // always send the item list when a game starts sendpacket(-1, 1, q.finalize()); - defformatstring(gsmsg)("Game start: %s on %s, %d players, %d minutes, mastermode %d, ", modestr(sg->smode), sg->smapname, numclients(), sg->minremain, sg->mastermode); + defformatstring(gsmsg)("Game start: %s on %s, %d minutes, mastermode %s, %d players ", modestr(sg->smode), sg->smapname, sg->minremain, mmfullname(sg->mastermode), numclients()); if(sg->mastermode == MM_MATCH) concatformatstring(gsmsg, "teamsize %d, ", sg->matchteamsize); if(sm) concatformatstring(gsmsg, "(map rev %d/%d, %s, 'getmap' %sprepared)", sm->maprevision, sm->cgzlen, sm->getpathdesc(), sm->isdistributable() ? "" : "not "); else concatformatstring(gsmsg, "error: failed to preload map"); @@ -3095,7 +3104,6 @@ void scallvoteerr(voteinfo *v, int error) { if(!valid_client(v->owner)) return; sendf(v->owner, 1, "ri2", SV_CALLVOTEERR, error); - if(v->type == SA_SHUFFLETEAMS && !m_teammode) sendservmsg("\f3shuffle teams requires teammode", v->owner); // 20220119: w/o changing protocol easiest feedback about why the "invalid vote" error was raised. mlog(ACLOG_INFO, "[%s] client %s failed to call a vote: %s (%s)", clients[v->owner]->hostname, clients[v->owner]->name, v->action && *v->action->desc ? v->action->desc : "[unknown]", voteerrorstr(error)); } @@ -3116,7 +3124,10 @@ bool scallvote(voteinfo *v, ENetPacket *msg) // true if a regular vote was calle c->nvotes++; - if( !v || !v->isvalid() || (v->boot && (!b || cn2boot == v->owner) ) ) error = VOTEE_INVALID; + if( !v || (v->boot && (!b || cn2boot == v->owner) ) ) error = VOTEE_INVALID; + else if( v->type == SA_SHUFFLETEAMS && !m_teammode ) error = VOTEE_SHUFFLETEAMS; + else if( v->type == SA_PAUSE && !v->isvalid() ) error = VOTEE_PAUSE; + else if( !v->isvalid() ) error = VOTEE_INVALID; else if( v->action->role > c->role ) error = VOTEE_PERMISSION; else if( !(area & v->action->area) ) error = VOTEE_AREA; else if( curvote && curvote->result==VOTE_NEUTRAL ) error = VOTEE_CUR; @@ -3514,7 +3525,7 @@ int checktype(int type, client *cl) SV_SENDDEMOLIST, SV_SENDDEMO, SV_DEMOPLAYBACK, SV_CLIENT, SV_DEMOCHECKSUM, SV_PAUSEMODE }; // only allow edit messages in coop-edit mode - static int edittypes[] = { SV_EDITENT, SV_EDITXY, SV_EDITARCH, SV_EDITBLOCK, SV_EDITD, SV_EDITE, SV_NEWMAP }; + static int edittypes[] = { SV_EDITENT, SV_EDITXY, SV_EDITARCH, SV_EDITBLOCK, SV_EDITD, SV_EDITE, SV_NEWMAP, SV_EDITMODE }; if(cl) { loopi(sizeof(servtypes)/sizeof(int)) if(type == servtypes[i]) return -1; @@ -4503,6 +4514,35 @@ void process(ENetPacket *packet, int sender, int chan) break; } + case SV_NEWMAP: + { + int size = getint(p); + if(sg->smode != GMODE_COOPEDIT) break; + if(size >= 0) + { + size = clamp(size, 7, 10); // FIXME, there is a lot of misinformation about the maximum map size in multiplayer. Should support mapenlarge/mapshrink? + sg->curmap->sfactor = size; + } + QUEUE_MSG; + break; + } + + case SV_EDITMODE: + { + int val = getint(p); + if(sg->smode != GMODE_COOPEDIT) break; + clientstate &cs = cl->state; + if(val ? (cs.state != CS_ALIVE && cs.state != CS_DEAD) : (cs.state != CS_EDITING)) break; + if(val) + { + cs.editstate = cs.state; + cs.state = CS_EDITING; + } + else cs.state = cs.editstate; + QUEUE_MSG; + break; + } + case SV_FLAGACTION: { int action = getint(p); @@ -4889,6 +4929,7 @@ void resetserverifempty() resetserver("", 0, 10); sg->matchteamsize = 0; sg->autoteam = true; + sg->sispaused = 0; changemastermode(MM_OPEN); sg->nextmapname[0] = '\0'; } @@ -4916,7 +4957,7 @@ void loggamestatus(const char *reason) string text; formatstring(text)("%d minutes remaining", sg->minremain); mlog(ACLOG_INFO, ""); - mlog(ACLOG_INFO, "Game status: %s on %s, %s, %s, %d clients%c %s", + mlog(ACLOG_INFO, "Game status: %s on %s, %s, mastermode %s, %d clients%c %s", modestr(gamemode), sg->smapname, reason ? reason : text, mmfullname(sg->mastermode), totalclients, sg->custom_servdesc ? ',' : '\0', sg->servdesc_current); if(!scl.loggamestatus) return; mlog(ACLOG_INFO, "cn name %s%s%s%s points frag death %sping role host", m_teammode ? "team " : "", m_park ? "P@ " : "", m_park ? "#PP# " : "", m_flags_ ? "flag " : "", m_teammode ? "tk " : ""); @@ -5102,9 +5143,16 @@ void serverslice(uint timeout) // main server update, called from cube main lo sg->interm = sg->nextsendscore = 0; //start next game - if(sg->nextmapname[0]) startgame(sg->nextmapname, sg->nextgamemode); - else maprot.next(); - sg->nextmapname[0] = '\0'; + if(sg->nextmapname[0]) + { + startgame(sg->nextmapname, sg->nextgamemode, sg->nextgametime, true); + sg->nextmapname[0] = '\0'; + } + else + { + maprot.next(); + sg->nextmapname[0] = '\0'; + } map_queued = false; } @@ -5468,7 +5516,7 @@ void initserver(bool dedicated) formatstring(vitafilename_update_backup_base)("%s_update_", scl.vitabasename); path(vitafilename); path(vitafilename_backup); path(vitafilename_update); path(vitafilename_update_backup_base); char *vn; - int gotvitas = readvitas((vn = vitafilename)); // FIXME: broken characters (from countrycodes) can lead to crashes + int gotvitas = readvitas((vn = vitafilename)); if(gotvitas < 0) gotvitas = readvitas((vn = vitafilename_backup)); if(gotvitas >= 0) mlog(ACLOG_INFO, "read %d player vitas from %s", gotvitas, vn); maprot.init(scl.maprotfile); diff --git a/source/src/server.h b/source/src/server.h index 3330b2b1b6..3d4e6d96af 100644 --- a/source/src/server.h +++ b/source/src/server.h @@ -110,7 +110,7 @@ static const int DEATHMILLIS = 300; struct clientstate : playerstate { vec o; - int state; + int state, editstate; int lastdeath, lastspawn, spawn, lifesequence, lastclaction; bool forced; int lastshot; @@ -121,7 +121,7 @@ struct clientstate : playerstate int suicides, friendlyfire, enemyfire, goodflags, antiflags; // match only vita replacement vector parkents; - clientstate() : state(CS_DEAD) {} + clientstate() : state(CS_DEAD), editstate(CS_DEAD) {} bool isalive(int gamemillis) { @@ -137,7 +137,7 @@ struct clientstate : playerstate void reset() { - state = CS_DEAD; + if(state != CS_SPECTATE) state = editstate = CS_DEAD; lifesequence = -1; grenades.reset(); akimbomillis = 0; diff --git a/source/src/serveractions.h b/source/src/serveractions.h index 8415b06ac6..a69a329326 100644 --- a/source/src/serveractions.h +++ b/source/src/serveractions.h @@ -43,12 +43,14 @@ struct mapaction : serveraction if(queue) { sg->nextgamemode = mode; + sg->nextgametime = time; copystring(sg->nextmapname, map); } else if(isdedicated && numclients() > 2 && sg->smode >= GMODE_TEAMDEATHMATCH && sg->smode != GMODE_COOPEDIT && ( sg->gamemillis > sg->gamelimit/4 || scl.demo_interm )) { sg->forceintermission = true; sg->nextgamemode = mode; + sg->nextgametime = time; copystring(sg->nextmapname, map); } else diff --git a/source/src/serverfiles.h b/source/src/serverfiles.h index 9efd927df5..7b3545a654 100644 --- a/source/src/serverfiles.h +++ b/source/src/serverfiles.h @@ -2040,7 +2040,7 @@ void vita_s::addcc(const char *cc) { int rem = 0; for(; rem < VITACCHISTLEN - 1; rem++) if(cchist[rem * 2] == cc[0] && cchist[rem * 2 + 1] == cc[1]) break; - if(rem) memmove(cchist + 2, iphist, rem * 2); + if(rem) memmove(cchist + 2, cchist, rem * 2); loopi(2) cchist[i] = cc[i]; } diff --git a/source/src/sound.h b/source/src/sound.h index 4de1be97a7..e9012a3f0d 100644 --- a/source/src/sound.h +++ b/source/src/sound.h @@ -445,6 +445,7 @@ class audiomanager void sound(int n); int findsound(const char *name, int vol, vector &sounds); void detachsounds(class playerent *owner); + void stopplayersounds(class playerent *owner); // update void updateplayerfootsteps(class playerent *p); diff --git a/source/src/worldrender.cpp b/source/src/worldrender.cpp index 237cbd3561..cb9605bf17 100644 --- a/source/src/worldrender.cpp +++ b/source/src/worldrender.cpp @@ -297,7 +297,7 @@ void distlod(int &low, int &high, int angle, float widef) void render_world(float vx, float vy, float vh, float changelod, int yaw, int pitch, float fov, float fovy, int w, int h) { loopi(LARGEST_FACTOR) stats[i] = 0; - min_lod = minimap || (player1->isspectating() && player1->spectatemode == SM_OVERVIEW) ? MAX_LOD : MIN_LOD+iabs(pitch)/12; + min_lod = minimap || (player1->isspectating() && player1->spectatemode == SM_OVERVIEW) ? MAX_LOD : MIN_LOD+90.0f/12; // ignore pitch for lod yaw = 360-yaw; float widef = fov/75.0f; int cdist = iabs(yaw%90-45);