From 952c5c128f9efaea89d41d882c4ea3ade7df4591 Mon Sep 17 00:00:00 2001 From: zakk Date: Fri, 26 Aug 2005 04:48:05 +0000 Subject: Itsa me, quake3io! git-svn-id: svn://svn.icculus.org/quake3/trunk@2 edf5b092-35ff-0310-97b2-ce42778d08ea --- code/q3_ui/Conscript | 93 ++ code/q3_ui/compile.bat | 2 + code/q3_ui/keycodes.h | 163 ++++ code/q3_ui/q3_ui.bat | 100 ++ code/q3_ui/q3_ui.q3asm | 43 + code/q3_ui/q3_ui.sh | 55 ++ code/q3_ui/q3_ui.vcproj | 2008 ++++++++++++++++++++++++++++++++++++++++ code/q3_ui/ui.def | 3 + code/q3_ui/ui.q3asm | 45 + code/q3_ui/ui_addbots.c | 412 +++++++++ code/q3_ui/ui_atoms.c | 1267 +++++++++++++++++++++++++ code/q3_ui/ui_cdkey.c | 291 ++++++ code/q3_ui/ui_cinematics.c | 350 +++++++ code/q3_ui/ui_confirm.c | 293 ++++++ code/q3_ui/ui_connect.c | 282 ++++++ code/q3_ui/ui_controls2.c | 1667 +++++++++++++++++++++++++++++++++ code/q3_ui/ui_credits.c | 129 +++ code/q3_ui/ui_demo2.c | 291 ++++++ code/q3_ui/ui_display.c | 265 ++++++ code/q3_ui/ui_gameinfo.c | 820 ++++++++++++++++ code/q3_ui/ui_ingame.c | 349 +++++++ code/q3_ui/ui_loadconfig.c | 274 ++++++ code/q3_ui/ui_local.h | 800 ++++++++++++++++ code/q3_ui/ui_login.c | 208 +++++ code/q3_ui/ui_main.c | 249 +++++ code/q3_ui/ui_menu.c | 419 +++++++++ code/q3_ui/ui_mfield.c | 439 +++++++++ code/q3_ui/ui_mods.c | 283 ++++++ code/q3_ui/ui_network.c | 281 ++++++ code/q3_ui/ui_options.c | 229 +++++ code/q3_ui/ui_playermodel.c | 731 +++++++++++++++ code/q3_ui/ui_players.c | 1248 +++++++++++++++++++++++++ code/q3_ui/ui_playersettings.c | 513 ++++++++++ code/q3_ui/ui_preferences.c | 419 +++++++++ code/q3_ui/ui_qmenu.c | 1746 ++++++++++++++++++++++++++++++++++ code/q3_ui/ui_rankings.c | 420 +++++++++ code/q3_ui/ui_rankstatus.c | 209 +++++ code/q3_ui/ui_removebots.c | 342 +++++++ code/q3_ui/ui_saveconfig.c | 212 +++++ code/q3_ui/ui_serverinfo.c | 272 ++++++ code/q3_ui/ui_servers2.c | 1640 ++++++++++++++++++++++++++++++++ code/q3_ui/ui_setup.c | 327 +++++++ code/q3_ui/ui_signup.c | 286 ++++++ code/q3_ui/ui_sound.c | 316 +++++++ code/q3_ui/ui_sparena.c | 50 + code/q3_ui/ui_specifyleague.c | 333 +++++++ code/q3_ui/ui_specifyserver.c | 213 +++++ code/q3_ui/ui_splevel.c | 1008 ++++++++++++++++++++ code/q3_ui/ui_sppostgame.c | 644 +++++++++++++ code/q3_ui/ui_spreset.c | 194 ++++ code/q3_ui/ui_spskill.c | 329 +++++++ code/q3_ui/ui_startserver.c | 1968 +++++++++++++++++++++++++++++++++++++++ code/q3_ui/ui_team.c | 210 +++++ code/q3_ui/ui_teamorders.c | 449 +++++++++ code/q3_ui/ui_video.c | 1070 +++++++++++++++++++++ 55 files changed, 27259 insertions(+) create mode 100755 code/q3_ui/Conscript create mode 100755 code/q3_ui/compile.bat create mode 100755 code/q3_ui/keycodes.h create mode 100755 code/q3_ui/q3_ui.bat create mode 100755 code/q3_ui/q3_ui.q3asm create mode 100755 code/q3_ui/q3_ui.sh create mode 100755 code/q3_ui/q3_ui.vcproj create mode 100755 code/q3_ui/ui.def create mode 100755 code/q3_ui/ui.q3asm create mode 100755 code/q3_ui/ui_addbots.c create mode 100755 code/q3_ui/ui_atoms.c create mode 100755 code/q3_ui/ui_cdkey.c create mode 100755 code/q3_ui/ui_cinematics.c create mode 100755 code/q3_ui/ui_confirm.c create mode 100755 code/q3_ui/ui_connect.c create mode 100755 code/q3_ui/ui_controls2.c create mode 100755 code/q3_ui/ui_credits.c create mode 100755 code/q3_ui/ui_demo2.c create mode 100755 code/q3_ui/ui_display.c create mode 100755 code/q3_ui/ui_gameinfo.c create mode 100755 code/q3_ui/ui_ingame.c create mode 100755 code/q3_ui/ui_loadconfig.c create mode 100755 code/q3_ui/ui_local.h create mode 100755 code/q3_ui/ui_login.c create mode 100755 code/q3_ui/ui_main.c create mode 100755 code/q3_ui/ui_menu.c create mode 100755 code/q3_ui/ui_mfield.c create mode 100755 code/q3_ui/ui_mods.c create mode 100755 code/q3_ui/ui_network.c create mode 100755 code/q3_ui/ui_options.c create mode 100755 code/q3_ui/ui_playermodel.c create mode 100755 code/q3_ui/ui_players.c create mode 100755 code/q3_ui/ui_playersettings.c create mode 100755 code/q3_ui/ui_preferences.c create mode 100755 code/q3_ui/ui_qmenu.c create mode 100755 code/q3_ui/ui_rankings.c create mode 100755 code/q3_ui/ui_rankstatus.c create mode 100755 code/q3_ui/ui_removebots.c create mode 100755 code/q3_ui/ui_saveconfig.c create mode 100755 code/q3_ui/ui_serverinfo.c create mode 100755 code/q3_ui/ui_servers2.c create mode 100755 code/q3_ui/ui_setup.c create mode 100755 code/q3_ui/ui_signup.c create mode 100755 code/q3_ui/ui_sound.c create mode 100755 code/q3_ui/ui_sparena.c create mode 100755 code/q3_ui/ui_specifyleague.c create mode 100755 code/q3_ui/ui_specifyserver.c create mode 100755 code/q3_ui/ui_splevel.c create mode 100755 code/q3_ui/ui_sppostgame.c create mode 100755 code/q3_ui/ui_spreset.c create mode 100755 code/q3_ui/ui_spskill.c create mode 100755 code/q3_ui/ui_startserver.c create mode 100755 code/q3_ui/ui_team.c create mode 100755 code/q3_ui/ui_teamorders.c create mode 100755 code/q3_ui/ui_video.c (limited to 'code/q3_ui') diff --git a/code/q3_ui/Conscript b/code/q3_ui/Conscript new file mode 100755 index 0000000..2387e25 --- /dev/null +++ b/code/q3_ui/Conscript @@ -0,0 +1,93 @@ +# Q3 ui building + +# qvm building against native: +# only native has ui_syscalls.c +# qvm uses a ui_syscalls.asm with equ stubs +# qvm has additional bg_lib.c + +Import qw( BASE_CFLAGS TARGET_DIR INSTALL_DIR NO_VM NO_SO CC CXX LINK ); + +$env = new cons( + # the code has the very bad habit of doing things like #include "../ui/ui_shared.h" + # this seems to confuse the dependency analysis, explicit toplevel includes seem to fix + CPPPATH => '#cgame:#game:#q3_ui', + CC => $CC, + CXX => $CXX, + LINK => $LINK, + ENV => { PATH => $ENV{PATH}, HOME => $ENV{HOME} }, + CFLAGS => $BASE_CFLAGS . '-fPIC', + LDFLAGS => '-shared -ldl -lm' +); + +# qvm building +# we heavily customize the cons environment +$vm_env = new cons( + # the code has the very bad habit of doing things like #include "../ui/ui_shared.h" + # this seems to confuse the dependency analysis, explicit toplevel includes seem to fix + CPPPATH => '#cgame:#game:#q3_ui', + CC => 'q3lcc', + CCCOM => '%CC %CFLAGS %_IFLAGS -c %< -o %>', + SUFOBJ => '.asm', + LINK => 'q3asm', + CFLAGS => '-DQ3_VM -S -Wf-target=bytecode -Wf-g', + # need to know where to find the compiler tools + ENV => { PATH => $ENV{PATH} . ":./qvmtools", }, +); + +# the file with vmMain function MUST be the first one of the list +@FILES = qw( + ui_main.c + ../game/bg_misc.c + ../game/q_math.c + ../game/q_shared.c + ui_addbots.c + ui_atoms.c + ui_cdkey.c + ui_cinematics.c + ui_confirm.c + ui_connect.c + ui_controls2.c + ui_credits.c + ui_demo2.c + ui_display.c + ui_gameinfo.c + ui_ingame.c + ui_menu.c + ui_mfield.c + ui_mods.c + ui_network.c + ui_options.c + ui_playermodel.c + ui_players.c + ui_playersettings.c + ui_preferences.c + ui_qmenu.c + ui_removebots.c + ui_serverinfo.c + ui_servers2.c + ui_setup.c + ui_sound.c + ui_sparena.c + ui_specifyserver.c + ui_splevel.c + ui_sppostgame.c + ui_spskill.c + ui_startserver.c + ui_team.c + ui_teamorders.c + ui_video.c + ); +$FILESREF = \@FILES; + +if ($NO_SO eq 0) +{ + Program $env 'uii386.so', @$FILESREF, '../ui/ui_syscalls.c'; + Install $env $INSTALL_DIR, 'uii386.so'; +} +if ($NO_VM eq 0) +{ + Depends $vm_env 'ui.qvm', '#qvmtools/q3lcc'; + Depends $vm_env 'ui.qvm', '#qvmtools/q3asm'; + Program $vm_env 'ui.qvm', @$FILESREF, '../game/bg_lib.c', '../ui/ui_syscalls.asm'; + Install $vm_env $INSTALL_DIR . '/vm', 'ui.qvm'; +} diff --git a/code/q3_ui/compile.bat b/code/q3_ui/compile.bat new file mode 100755 index 0000000..8299251 --- /dev/null +++ b/code/q3_ui/compile.bat @@ -0,0 +1,2 @@ +lcc -S -Wf-target=bytecode -Wf-g -I..\..\cgame -I..\..\game -I..\..\ui %1 + diff --git a/code/q3_ui/keycodes.h b/code/q3_ui/keycodes.h new file mode 100755 index 0000000..a1a0f1f --- /dev/null +++ b/code/q3_ui/keycodes.h @@ -0,0 +1,163 @@ +/* +=========================================================================== +Copyright (C) 1999-2005 Id Software, Inc. + +This file is part of Quake III Arena source code. + +Quake III Arena source code is free software; you can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 2 of the License, +or (at your option) any later version. + +Quake III Arena source code is distributed in the hope that it will be +useful, but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Foobar; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ +// +#ifndef __KEYCODES_H__ +#define __KEYCODES_H__ + +// +// these are the key numbers that should be passed to KeyEvent +// + +// normal keys should be passed as lowercased ascii + +typedef enum { + K_TAB = 9, + K_ENTER = 13, + K_ESCAPE = 27, + K_SPACE = 32, + + K_BACKSPACE = 127, + + K_COMMAND = 128, + K_CAPSLOCK, + K_POWER, + K_PAUSE, + + K_UPARROW, + K_DOWNARROW, + K_LEFTARROW, + K_RIGHTARROW, + + K_ALT, + K_CTRL, + K_SHIFT, + K_INS, + K_DEL, + K_PGDN, + K_PGUP, + K_HOME, + K_END, + + K_F1, + K_F2, + K_F3, + K_F4, + K_F5, + K_F6, + K_F7, + K_F8, + K_F9, + K_F10, + K_F11, + K_F12, + K_F13, + K_F14, + K_F15, + + K_KP_HOME, + K_KP_UPARROW, + K_KP_PGUP, + K_KP_LEFTARROW, + K_KP_5, + K_KP_RIGHTARROW, + K_KP_END, + K_KP_DOWNARROW, + K_KP_PGDN, + K_KP_ENTER, + K_KP_INS, + K_KP_DEL, + K_KP_SLASH, + K_KP_MINUS, + K_KP_PLUS, + K_KP_NUMLOCK, + K_KP_STAR, + K_KP_EQUALS, + + K_MOUSE1, + K_MOUSE2, + K_MOUSE3, + K_MOUSE4, + K_MOUSE5, + + K_MWHEELDOWN, + K_MWHEELUP, + + K_JOY1, + K_JOY2, + K_JOY3, + K_JOY4, + K_JOY5, + K_JOY6, + K_JOY7, + K_JOY8, + K_JOY9, + K_JOY10, + K_JOY11, + K_JOY12, + K_JOY13, + K_JOY14, + K_JOY15, + K_JOY16, + K_JOY17, + K_JOY18, + K_JOY19, + K_JOY20, + K_JOY21, + K_JOY22, + K_JOY23, + K_JOY24, + K_JOY25, + K_JOY26, + K_JOY27, + K_JOY28, + K_JOY29, + K_JOY30, + K_JOY31, + K_JOY32, + + K_AUX1, + K_AUX2, + K_AUX3, + K_AUX4, + K_AUX5, + K_AUX6, + K_AUX7, + K_AUX8, + K_AUX9, + K_AUX10, + K_AUX11, + K_AUX12, + K_AUX13, + K_AUX14, + K_AUX15, + K_AUX16, + + K_LAST_KEY // this had better be <256! +} keyNum_t; + + +// The menu code needs to get both key and char events, but +// to avoid duplicating the paths, the char events are just +// distinguished by or'ing in K_CHAR_FLAG (ugly) +#define K_CHAR_FLAG 1024 + +#endif diff --git a/code/q3_ui/q3_ui.bat b/code/q3_ui/q3_ui.bat new file mode 100755 index 0000000..b86f4f6 --- /dev/null +++ b/code/q3_ui/q3_ui.bat @@ -0,0 +1,100 @@ +rem make sure we have a safe environement +set LIBRARY= +set INCLUDE= + +mkdir vm +cd vm + +set cc=lcc -DQ3_VM -S -Wf-target=bytecode -Wf-g -I..\..\cgame -I..\..\game -I..\..\q3_ui %1 + +lcc -DQ3_VM -S -Wf-target=bytecode -Wf-g -I..\..\cgame -I..\..\game -I..\..\q3_ui ../ui_main.c +@if errorlevel 1 goto quit +lcc -DQ3_VM -S -Wf-target=bytecode -Wf-g -I..\..\cgame -I..\..\game -I..\..\q3_ui ../ui_cdkey.c +@if errorlevel 1 goto quit +lcc -DQ3_VM -S -Wf-target=bytecode -Wf-g -I..\..\cgame -I..\..\game -I..\..\q3_ui ../ui_ingame.c +@if errorlevel 1 goto quit +lcc -DQ3_VM -S -Wf-target=bytecode -Wf-g -I..\..\cgame -I..\..\game -I..\..\q3_ui ../ui_serverinfo.c +@if errorlevel 1 goto quit +lcc -DQ3_VM -S -Wf-target=bytecode -Wf-g -I..\..\cgame -I..\..\game -I..\..\q3_ui ../ui_confirm.c +@if errorlevel 1 goto quit +lcc -DQ3_VM -S -Wf-target=bytecode -Wf-g -I..\..\cgame -I..\..\game -I..\..\q3_ui ../ui_setup.c +@if errorlevel 1 goto quit +lcc -DQ3_VM -S -Wf-target=bytecode -Wf-g -I..\..\cgame -I..\..\game -I..\..\q3_ui ../../game/bg_misc.c +@if errorlevel 1 goto quit +lcc -DQ3_VM -S -Wf-target=bytecode -Wf-g -I..\..\cgame -I..\..\game -I..\..\q3_ui ../../game/bg_lib.c +@if errorlevel 1 goto quit +lcc -DQ3_VM -S -Wf-target=bytecode -Wf-g -I..\..\cgame -I..\..\game -I..\..\q3_ui ../../game/q_math.c +@if errorlevel 1 goto quit +lcc -DQ3_VM -S -Wf-target=bytecode -Wf-g -I..\..\cgame -I..\..\game -I..\..\q3_ui ../../game/q_shared.c +@if errorlevel 1 goto quit +lcc -DQ3_VM -S -Wf-target=bytecode -Wf-g -I..\..\cgame -I..\..\game -I..\..\q3_ui ../ui_gameinfo.c +@if errorlevel 1 goto quit +lcc -DQ3_VM -S -Wf-target=bytecode -Wf-g -I..\..\cgame -I..\..\game -I..\..\q3_ui ../ui_atoms.c +@if errorlevel 1 goto quit +lcc -DQ3_VM -S -Wf-target=bytecode -Wf-g -I..\..\cgame -I..\..\game -I..\..\q3_ui ../ui_connect.c +@if errorlevel 1 goto quit +lcc -DQ3_VM -S -Wf-target=bytecode -Wf-g -I..\..\cgame -I..\..\game -I..\..\q3_ui ../ui_controls2.c +@if errorlevel 1 goto quit +lcc -DQ3_VM -S -Wf-target=bytecode -Wf-g -I..\..\cgame -I..\..\game -I..\..\q3_ui ../ui_demo2.c +@if errorlevel 1 goto quit +lcc -DQ3_VM -S -Wf-target=bytecode -Wf-g -I..\..\cgame -I..\..\game -I..\..\q3_ui ../ui_mfield.c +@if errorlevel 1 goto quit +lcc -DQ3_VM -S -Wf-target=bytecode -Wf-g -I..\..\cgame -I..\..\game -I..\..\q3_ui ../ui_credits.c +@if errorlevel 1 goto quit +lcc -DQ3_VM -S -Wf-target=bytecode -Wf-g -I..\..\cgame -I..\..\game -I..\..\q3_ui ../ui_menu.c +@if errorlevel 1 goto quit +lcc -DQ3_VM -S -Wf-target=bytecode -Wf-g -I..\..\cgame -I..\..\game -I..\..\q3_ui ../ui_options.c +@if errorlevel 1 goto quit +lcc -DQ3_VM -S -Wf-target=bytecode -Wf-g -I..\..\cgame -I..\..\game -I..\..\q3_ui ../ui_display.c +@if errorlevel 1 goto quit +lcc -DQ3_VM -S -Wf-target=bytecode -Wf-g -I..\..\cgame -I..\..\game -I..\..\q3_ui ../ui_sound.c +@if errorlevel 1 goto quit +lcc -DQ3_VM -S -Wf-target=bytecode -Wf-g -I..\..\cgame -I..\..\game -I..\..\q3_ui ../ui_network.c +@if errorlevel 1 goto quit +lcc -DQ3_VM -S -Wf-target=bytecode -Wf-g -I..\..\cgame -I..\..\game -I..\..\q3_ui ../ui_playermodel.c +@if errorlevel 1 goto quit +lcc -DQ3_VM -S -Wf-target=bytecode -Wf-g -I..\..\cgame -I..\..\game -I..\..\q3_ui ../ui_players.c +@if errorlevel 1 goto quit +lcc -DQ3_VM -S -Wf-target=bytecode -Wf-g -I..\..\cgame -I..\..\game -I..\..\q3_ui ../ui_playersettings.c +@if errorlevel 1 goto quit +lcc -DQ3_VM -S -Wf-target=bytecode -Wf-g -I..\..\cgame -I..\..\game -I..\..\q3_ui ../ui_preferences.c +@if errorlevel 1 goto quit +lcc -DQ3_VM -S -Wf-target=bytecode -Wf-g -I..\..\cgame -I..\..\game -I..\..\q3_ui ../ui_qmenu.c +@if errorlevel 1 goto quit +lcc -DQ3_VM -S -Wf-target=bytecode -Wf-g -I..\..\cgame -I..\..\game -I..\..\q3_ui ../ui_servers2.c +@if errorlevel 1 goto quit +lcc -DQ3_VM -S -Wf-target=bytecode -Wf-g -I..\..\cgame -I..\..\game -I..\..\q3_ui ../ui_sparena.c +@if errorlevel 1 goto quit +lcc -DQ3_VM -S -Wf-target=bytecode -Wf-g -I..\..\cgame -I..\..\game -I..\..\q3_ui ../ui_specifyserver.c +@if errorlevel 1 goto quit +lcc -DQ3_VM -S -Wf-target=bytecode -Wf-g -I..\..\cgame -I..\..\game -I..\..\q3_ui ../ui_splevel.c +@if errorlevel 1 goto quit +lcc -DQ3_VM -S -Wf-target=bytecode -Wf-g -I..\..\cgame -I..\..\game -I..\..\q3_ui ../ui_sppostgame.c +@if errorlevel 1 goto quit +lcc -DQ3_VM -S -Wf-target=bytecode -Wf-g -I..\..\cgame -I..\..\game -I..\..\q3_ui ../ui_startserver.c +@if errorlevel 1 goto quit +lcc -DQ3_VM -S -Wf-target=bytecode -Wf-g -I..\..\cgame -I..\..\game -I..\..\q3_ui ../ui_team.c +@if errorlevel 1 goto quit +lcc -DQ3_VM -S -Wf-target=bytecode -Wf-g -I..\..\cgame -I..\..\game -I..\..\q3_ui ../ui_video.c +@if errorlevel 1 goto quit +lcc -DQ3_VM -S -Wf-target=bytecode -Wf-g -I..\..\cgame -I..\..\game -I..\..\q3_ui ../ui_cinematics.c +@if errorlevel 1 goto quit +lcc -DQ3_VM -S -Wf-target=bytecode -Wf-g -I..\..\cgame -I..\..\game -I..\..\q3_ui ../ui_spskill.c +@if errorlevel 1 goto quit +lcc -DQ3_VM -S -Wf-target=bytecode -Wf-g -I..\..\cgame -I..\..\game -I..\..\q3_ui ../ui_addbots.c +@if errorlevel 1 goto quit +lcc -DQ3_VM -S -Wf-target=bytecode -Wf-g -I..\..\cgame -I..\..\game -I..\..\q3_ui ../ui_removebots.c +@if errorlevel 1 goto quit +rem lcc -DQ3_VM -S -Wf-target=bytecode -Wf-g -I..\..\cgame -I..\..\game -I..\..\q3_ui ../ui_loadconfig.c +rem @if errorlevel 1 goto quit +rem lcc -DQ3_VM -S -Wf-target=bytecode -Wf-g -I..\..\cgame -I..\..\game -I..\..\q3_ui ../ui_saveconfig.c +rem @if errorlevel 1 goto quit +lcc -DQ3_VM -S -Wf-target=bytecode -Wf-g -I..\..\cgame -I..\..\game -I..\..\q3_ui ../ui_teamorders.c +@if errorlevel 1 goto quit +lcc -DQ3_VM -S -Wf-target=bytecode -Wf-g -I..\..\cgame -I..\..\game -I..\..\q3_ui ../ui_mods.c +@if errorlevel 1 goto quit + + +q3asm -f ../q3_ui +:quit +cd .. diff --git a/code/q3_ui/q3_ui.q3asm b/code/q3_ui/q3_ui.q3asm new file mode 100755 index 0000000..09ec962 --- /dev/null +++ b/code/q3_ui/q3_ui.q3asm @@ -0,0 +1,43 @@ +-o "\quake3\baseq3\vm\ui" +ui_main +..\..\ui\ui_syscalls +ui_gameinfo +ui_atoms +ui_cinematics +ui_connect +ui_controls2 +ui_demo2 +ui_mfield +ui_credits +ui_menu +ui_ingame +ui_confirm +ui_setup +ui_options +ui_display +ui_sound +ui_network +ui_playermodel +ui_players +ui_playersettings +ui_preferences +ui_qmenu +ui_serverinfo +ui_servers2 +ui_sparena +ui_specifyserver +ui_sppostgame +ui_splevel +ui_spskill +ui_startserver +ui_team +ui_video +ui_addbots +ui_removebots +ui_teamorders +ui_cdkey +ui_mods +bg_misc +bg_lib +q_math +q_shared diff --git a/code/q3_ui/q3_ui.sh b/code/q3_ui/q3_ui.sh new file mode 100755 index 0000000..377d16e --- /dev/null +++ b/code/q3_ui/q3_ui.sh @@ -0,0 +1,55 @@ +#!/bin/sh + +mkdir -p vm +cd vm + +CC="q3lcc -DQ3_VM -S -Wf-target=bytecode -Wf-g -I../../cgame -I../../game -I../../q3_ui " + +$CC ../ui_main.c +$CC ../ui_cdkey.c +$CC ../ui_ingame.c +$CC ../ui_confirm.c +$CC ../ui_setup.c +$CC ../../game/bg_misc.c +$CC ../../game/bg_lib.c +$CC ../../game/q_math.c +$CC ../../game/q_shared.c +$CC ../ui_gameinfo.c +$CC ../ui_atoms.c +$CC ../ui_connect.c +$CC ../ui_controls2.c +$CC ../ui_demo2.c +$CC ../ui_mfield.c +$CC ../ui_credits.c +$CC ../ui_menu.c +$CC ../ui_options.c +$CC ../ui_display.c +$CC ../ui_sound.c +$CC ../ui_network.c +$CC ../ui_playermodel.c +$CC ../ui_players.c +$CC ../ui_playersettings.c +$CC ../ui_preferences.c +$CC ../ui_qmenu.c +$CC ../ui_serverinfo.c +$CC ../ui_servers2.c +$CC ../ui_sparena.c +$CC ../ui_specifyserver.c +$CC ../ui_splevel.c +$CC ../ui_sppostgame.c +$CC ../ui_startserver.c +$CC ../ui_syscalls.c +$CC ../ui_team.c +$CC ../ui_video.c +$CC ../ui_cinematics.c +$CC ../ui_spskill.c +$CC ../ui_addbots.c +$CC ../ui_removebots.c +$CC ../ui_loadconfig.c +$CC ../ui_saveconfig.c +$CC ../ui_teamorders.c +$CC ../ui_mods.c + +q3asm -f ../q3_ui + +cd .. diff --git a/code/q3_ui/q3_ui.vcproj b/code/q3_ui/q3_ui.vcproj new file mode 100755 index 0000000..8c1d78d --- /dev/null +++ b/code/q3_ui/q3_ui.vcproj @@ -0,0 +1,2008 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/code/q3_ui/ui.def b/code/q3_ui/ui.def new file mode 100755 index 0000000..01861ba --- /dev/null +++ b/code/q3_ui/ui.def @@ -0,0 +1,3 @@ +EXPORTS + vmMain + dllEntry diff --git a/code/q3_ui/ui.q3asm b/code/q3_ui/ui.q3asm new file mode 100755 index 0000000..80936bd --- /dev/null +++ b/code/q3_ui/ui.q3asm @@ -0,0 +1,45 @@ +-o "\quake3\baseq3\vm\ui" +ui_main +..\ui_syscalls +ui_gameinfo +ui_atoms +ui_cinematics +ui_connect +ui_controls2 +ui_demo2 +ui_mfield +ui_credits +ui_menu +ui_ingame +ui_confirm +ui_setup +ui_options +ui_display +ui_sound +ui_network +ui_playermodel +ui_players +ui_playersettings +ui_preferences +ui_qmenu +ui_serverinfo +ui_servers2 +ui_sparena +ui_specifyserver +ui_sppostgame +ui_splevel +ui_spskill +ui_startserver +ui_team +ui_video +ui_addbots +ui_removebots +ui_teamorders +ui_loadconfig +ui_saveconfig +ui_cdkey +ui_mods +bg_misc +bg_lib +q_math +q_shared diff --git a/code/q3_ui/ui_addbots.c b/code/q3_ui/ui_addbots.c new file mode 100755 index 0000000..ba906f3 --- /dev/null +++ b/code/q3_ui/ui_addbots.c @@ -0,0 +1,412 @@ +/* +=========================================================================== +Copyright (C) 1999-2005 Id Software, Inc. + +This file is part of Quake III Arena source code. + +Quake III Arena source code is free software; you can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 2 of the License, +or (at your option) any later version. + +Quake III Arena source code is distributed in the hope that it will be +useful, but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Foobar; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ +// +/* +======================================================================= + +ADD BOTS MENU + +======================================================================= +*/ + + +#include "ui_local.h" + + +#define ART_BACK0 "menu/art/back_0" +#define ART_BACK1 "menu/art/back_1" +#define ART_FIGHT0 "menu/art/accept_0" +#define ART_FIGHT1 "menu/art/accept_1" +#define ART_BACKGROUND "menu/art/addbotframe" +#define ART_ARROWS "menu/art/arrows_vert_0" +#define ART_ARROWUP "menu/art/arrows_vert_top" +#define ART_ARROWDOWN "menu/art/arrows_vert_bot" + +#define ID_BACK 10 +#define ID_GO 11 +#define ID_LIST 12 +#define ID_UP 13 +#define ID_DOWN 14 +#define ID_SKILL 15 +#define ID_TEAM 16 +#define ID_BOTNAME0 20 +#define ID_BOTNAME1 21 +#define ID_BOTNAME2 22 +#define ID_BOTNAME3 23 +#define ID_BOTNAME4 24 +#define ID_BOTNAME5 25 +#define ID_BOTNAME6 26 + + +typedef struct { + menuframework_s menu; + menubitmap_s arrows; + menubitmap_s up; + menubitmap_s down; + menutext_s bots[7]; + menulist_s skill; + menulist_s team; + menubitmap_s go; + menubitmap_s back; + + int numBots; + int delay; + int baseBotNum; + int selectedBotNum; + int sortedBotNums[MAX_BOTS]; + char botnames[7][32]; +} addBotsMenuInfo_t; + +static addBotsMenuInfo_t addBotsMenuInfo; + + +/* +================= +UI_AddBotsMenu_FightEvent +================= +*/ +static void UI_AddBotsMenu_FightEvent( void* ptr, int event ) { + const char *team; + int skill; + + if (event != QM_ACTIVATED) { + return; + } + + team = addBotsMenuInfo.team.itemnames[addBotsMenuInfo.team.curvalue]; + skill = addBotsMenuInfo.skill.curvalue + 1; + + trap_Cmd_ExecuteText( EXEC_APPEND, va("addbot %s %i %s %i\n", + addBotsMenuInfo.botnames[addBotsMenuInfo.selectedBotNum], skill, team, addBotsMenuInfo.delay) ); + + addBotsMenuInfo.delay += 1500; +} + + +/* +================= +UI_AddBotsMenu_BotEvent +================= +*/ +static void UI_AddBotsMenu_BotEvent( void* ptr, int event ) { + if (event != QM_ACTIVATED) { + return; + } + + addBotsMenuInfo.bots[addBotsMenuInfo.selectedBotNum].color = color_orange; + addBotsMenuInfo.selectedBotNum = ((menucommon_s*)ptr)->id - ID_BOTNAME0; + addBotsMenuInfo.bots[addBotsMenuInfo.selectedBotNum].color = color_white; +} + + +/* +================= +UI_AddBotsMenu_BackEvent +================= +*/ +static void UI_AddBotsMenu_BackEvent( void* ptr, int event ) { + if (event != QM_ACTIVATED) { + return; + } + UI_PopMenu(); +} + + +/* +================= +UI_AddBotsMenu_SetBotNames +================= +*/ +static void UI_AddBotsMenu_SetBotNames( void ) { + int n; + const char *info; + + for ( n = 0; n < 7; n++ ) { + info = UI_GetBotInfoByNumber( addBotsMenuInfo.sortedBotNums[addBotsMenuInfo.baseBotNum + n] ); + Q_strncpyz( addBotsMenuInfo.botnames[n], Info_ValueForKey( info, "name" ), sizeof(addBotsMenuInfo.botnames[n]) ); + } + +} + + +/* +================= +UI_AddBotsMenu_UpEvent +================= +*/ +static void UI_AddBotsMenu_UpEvent( void* ptr, int event ) { + if (event != QM_ACTIVATED) { + return; + } + + if( addBotsMenuInfo.baseBotNum > 0 ) { + addBotsMenuInfo.baseBotNum--; + UI_AddBotsMenu_SetBotNames(); + } +} + + +/* +================= +UI_AddBotsMenu_DownEvent +================= +*/ +static void UI_AddBotsMenu_DownEvent( void* ptr, int event ) { + if (event != QM_ACTIVATED) { + return; + } + + if( addBotsMenuInfo.baseBotNum + 7 < addBotsMenuInfo.numBots ) { + addBotsMenuInfo.baseBotNum++; + UI_AddBotsMenu_SetBotNames(); + } +} + + +/* +================= +UI_AddBotsMenu_GetSortedBotNums +================= +*/ +static int QDECL UI_AddBotsMenu_SortCompare( const void *arg1, const void *arg2 ) { + int num1, num2; + const char *info1, *info2; + const char *name1, *name2; + + num1 = *(int *)arg1; + num2 = *(int *)arg2; + + info1 = UI_GetBotInfoByNumber( num1 ); + info2 = UI_GetBotInfoByNumber( num2 ); + + name1 = Info_ValueForKey( info1, "name" ); + name2 = Info_ValueForKey( info2, "name" ); + + return Q_stricmp( name1, name2 ); +} + +static void UI_AddBotsMenu_GetSortedBotNums( void ) { + int n; + + // initialize the array + for( n = 0; n < addBotsMenuInfo.numBots; n++ ) { + addBotsMenuInfo.sortedBotNums[n] = n; + } + + qsort( addBotsMenuInfo.sortedBotNums, addBotsMenuInfo.numBots, sizeof(addBotsMenuInfo.sortedBotNums[0]), UI_AddBotsMenu_SortCompare ); +} + + +/* +================= +UI_AddBotsMenu_Draw +================= +*/ +static void UI_AddBotsMenu_Draw( void ) { + UI_DrawBannerString( 320, 16, "ADD BOTS", UI_CENTER, color_white ); + UI_DrawNamedPic( 320-233, 240-166, 466, 332, ART_BACKGROUND ); + + // standard menu drawing + Menu_Draw( &addBotsMenuInfo.menu ); +} + + +/* +================= +UI_AddBotsMenu_Init +================= +*/ +static const char *skillNames[] = { + "I Can Win", + "Bring It On", + "Hurt Me Plenty", + "Hardcore", + "Nightmare!", + 0 +}; + +static const char *teamNames1[] = { + "Free", + 0 +}; + +static const char *teamNames2[] = { + "Red", + "Blue", + 0 +}; + +static void UI_AddBotsMenu_Init( void ) { + int n; + int y; + int gametype; + int count; + char info[MAX_INFO_STRING]; + + trap_GetConfigString(CS_SERVERINFO, info, MAX_INFO_STRING); + gametype = atoi( Info_ValueForKey( info,"g_gametype" ) ); + + memset( &addBotsMenuInfo, 0 ,sizeof(addBotsMenuInfo) ); + addBotsMenuInfo.menu.draw = UI_AddBotsMenu_Draw; + addBotsMenuInfo.menu.fullscreen = qfalse; + addBotsMenuInfo.menu.wrapAround = qtrue; + addBotsMenuInfo.delay = 1000; + + UI_AddBots_Cache(); + + addBotsMenuInfo.numBots = UI_GetNumBots(); + count = addBotsMenuInfo.numBots < 7 ? addBotsMenuInfo.numBots : 7; + + addBotsMenuInfo.arrows.generic.type = MTYPE_BITMAP; + addBotsMenuInfo.arrows.generic.name = ART_ARROWS; + addBotsMenuInfo.arrows.generic.flags = QMF_INACTIVE; + addBotsMenuInfo.arrows.generic.x = 200; + addBotsMenuInfo.arrows.generic.y = 128; + addBotsMenuInfo.arrows.width = 64; + addBotsMenuInfo.arrows.height = 128; + + addBotsMenuInfo.up.generic.type = MTYPE_BITMAP; + addBotsMenuInfo.up.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS; + addBotsMenuInfo.up.generic.x = 200; + addBotsMenuInfo.up.generic.y = 128; + addBotsMenuInfo.up.generic.id = ID_UP; + addBotsMenuInfo.up.generic.callback = UI_AddBotsMenu_UpEvent; + addBotsMenuInfo.up.width = 64; + addBotsMenuInfo.up.height = 64; + addBotsMenuInfo.up.focuspic = ART_ARROWUP; + + addBotsMenuInfo.down.generic.type = MTYPE_BITMAP; + addBotsMenuInfo.down.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS; + addBotsMenuInfo.down.generic.x = 200; + addBotsMenuInfo.down.generic.y = 128+64; + addBotsMenuInfo.down.generic.id = ID_DOWN; + addBotsMenuInfo.down.generic.callback = UI_AddBotsMenu_DownEvent; + addBotsMenuInfo.down.width = 64; + addBotsMenuInfo.down.height = 64; + addBotsMenuInfo.down.focuspic = ART_ARROWDOWN; + + for( n = 0, y = 120; n < count; n++, y += 20 ) { + addBotsMenuInfo.bots[n].generic.type = MTYPE_PTEXT; + addBotsMenuInfo.bots[n].generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS; + addBotsMenuInfo.bots[n].generic.id = ID_BOTNAME0 + n; + addBotsMenuInfo.bots[n].generic.x = 320 - 56; + addBotsMenuInfo.bots[n].generic.y = y; + addBotsMenuInfo.bots[n].generic.callback = UI_AddBotsMenu_BotEvent; + addBotsMenuInfo.bots[n].string = addBotsMenuInfo.botnames[n]; + addBotsMenuInfo.bots[n].color = color_orange; + addBotsMenuInfo.bots[n].style = UI_LEFT|UI_SMALLFONT; + } + + y += 12; + addBotsMenuInfo.skill.generic.type = MTYPE_SPINCONTROL; + addBotsMenuInfo.skill.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT; + addBotsMenuInfo.skill.generic.x = 320; + addBotsMenuInfo.skill.generic.y = y; + addBotsMenuInfo.skill.generic.name = "Skill:"; + addBotsMenuInfo.skill.generic.id = ID_SKILL; + addBotsMenuInfo.skill.itemnames = skillNames; + addBotsMenuInfo.skill.curvalue = Com_Clamp( 0, 4, (int)trap_Cvar_VariableValue( "g_spSkill" ) - 1 ); + + y += SMALLCHAR_HEIGHT; + addBotsMenuInfo.team.generic.type = MTYPE_SPINCONTROL; + addBotsMenuInfo.team.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT; + addBotsMenuInfo.team.generic.x = 320; + addBotsMenuInfo.team.generic.y = y; + addBotsMenuInfo.team.generic.name = "Team: "; + addBotsMenuInfo.team.generic.id = ID_TEAM; + if( gametype >= GT_TEAM ) { + addBotsMenuInfo.team.itemnames = teamNames2; + } + else { + addBotsMenuInfo.team.itemnames = teamNames1; + addBotsMenuInfo.team.generic.flags = QMF_GRAYED; + } + + addBotsMenuInfo.go.generic.type = MTYPE_BITMAP; + addBotsMenuInfo.go.generic.name = ART_FIGHT0; + addBotsMenuInfo.go.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS; + addBotsMenuInfo.go.generic.id = ID_GO; + addBotsMenuInfo.go.generic.callback = UI_AddBotsMenu_FightEvent; + addBotsMenuInfo.go.generic.x = 320+128-128; + addBotsMenuInfo.go.generic.y = 256+128-64; + addBotsMenuInfo.go.width = 128; + addBotsMenuInfo.go.height = 64; + addBotsMenuInfo.go.focuspic = ART_FIGHT1; + + addBotsMenuInfo.back.generic.type = MTYPE_BITMAP; + addBotsMenuInfo.back.generic.name = ART_BACK0; + addBotsMenuInfo.back.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS; + addBotsMenuInfo.back.generic.id = ID_BACK; + addBotsMenuInfo.back.generic.callback = UI_AddBotsMenu_BackEvent; + addBotsMenuInfo.back.generic.x = 320-128; + addBotsMenuInfo.back.generic.y = 256+128-64; + addBotsMenuInfo.back.width = 128; + addBotsMenuInfo.back.height = 64; + addBotsMenuInfo.back.focuspic = ART_BACK1; + + addBotsMenuInfo.baseBotNum = 0; + addBotsMenuInfo.selectedBotNum = 0; + addBotsMenuInfo.bots[0].color = color_white; + + UI_AddBotsMenu_GetSortedBotNums(); + UI_AddBotsMenu_SetBotNames(); + + Menu_AddItem( &addBotsMenuInfo.menu, &addBotsMenuInfo.arrows ); + + Menu_AddItem( &addBotsMenuInfo.menu, &addBotsMenuInfo.up ); + Menu_AddItem( &addBotsMenuInfo.menu, &addBotsMenuInfo.down ); + for( n = 0; n < count; n++ ) { + Menu_AddItem( &addBotsMenuInfo.menu, &addBotsMenuInfo.bots[n] ); + } + Menu_AddItem( &addBotsMenuInfo.menu, &addBotsMenuInfo.skill ); + Menu_AddItem( &addBotsMenuInfo.menu, &addBotsMenuInfo.team ); + Menu_AddItem( &addBotsMenuInfo.menu, &addBotsMenuInfo.go ); + Menu_AddItem( &addBotsMenuInfo.menu, &addBotsMenuInfo.back ); +} + + +/* +================= +UI_AddBots_Cache +================= +*/ +void UI_AddBots_Cache( void ) { + trap_R_RegisterShaderNoMip( ART_BACK0 ); + trap_R_RegisterShaderNoMip( ART_BACK1 ); + trap_R_RegisterShaderNoMip( ART_FIGHT0 ); + trap_R_RegisterShaderNoMip( ART_FIGHT1 ); + trap_R_RegisterShaderNoMip( ART_BACKGROUND ); + trap_R_RegisterShaderNoMip( ART_ARROWS ); + trap_R_RegisterShaderNoMip( ART_ARROWUP ); + trap_R_RegisterShaderNoMip( ART_ARROWDOWN ); +} + + +/* +================= +UI_AddBotsMenu +================= +*/ +void UI_AddBotsMenu( void ) { + UI_AddBotsMenu_Init(); + UI_PushMenu( &addBotsMenuInfo.menu ); +} diff --git a/code/q3_ui/ui_atoms.c b/code/q3_ui/ui_atoms.c new file mode 100755 index 0000000..4a2177d --- /dev/null +++ b/code/q3_ui/ui_atoms.c @@ -0,0 +1,1267 @@ +/* +=========================================================================== +Copyright (C) 1999-2005 Id Software, Inc. + +This file is part of Quake III Arena source code. + +Quake III Arena source code is free software; you can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 2 of the License, +or (at your option) any later version. + +Quake III Arena source code is distributed in the hope that it will be +useful, but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Foobar; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ +// +/********************************************************************** + UI_ATOMS.C + + User interface building blocks and support functions. +**********************************************************************/ +#include "ui_local.h" + +uiStatic_t uis; +qboolean m_entersound; // after a frame, so caching won't disrupt the sound + +// these are here so the functions in q_shared.c can link +#ifndef UI_HARD_LINKED + +void QDECL Com_Error( int level, const char *error, ... ) { + va_list argptr; + char text[1024]; + + va_start (argptr, error); + vsprintf (text, error, argptr); + va_end (argptr); + + trap_Error( va("%s", text) ); +} + +void QDECL Com_Printf( const char *msg, ... ) { + va_list argptr; + char text[1024]; + + va_start (argptr, msg); + vsprintf (text, msg, argptr); + va_end (argptr); + + trap_Print( va("%s", text) ); +} + +#endif + +/* +================= +UI_ClampCvar +================= +*/ +float UI_ClampCvar( float min, float max, float value ) +{ + if ( value < min ) return min; + if ( value > max ) return max; + return value; +} + +/* +================= +UI_StartDemoLoop +================= +*/ +void UI_StartDemoLoop( void ) { + trap_Cmd_ExecuteText( EXEC_APPEND, "d1\n" ); +} + +/* +================= +UI_PushMenu +================= +*/ +void UI_PushMenu( menuframework_s *menu ) +{ + int i; + menucommon_s* item; + + // avoid stacking menus invoked by hotkeys + for (i=0 ; i= MAX_MENUDEPTH) + trap_Error("UI_PushMenu: menu stack overflow"); + + uis.stack[uis.menusp++] = menu; + } + + uis.activemenu = menu; + + // default cursor position + menu->cursor = 0; + menu->cursor_prev = 0; + + m_entersound = qtrue; + + trap_Key_SetCatcher( KEYCATCH_UI ); + + // force first available item to have focus + for (i=0; initems; i++) + { + item = (menucommon_s *)menu->items[i]; + if (!(item->flags & (QMF_GRAYED|QMF_MOUSEONLY|QMF_INACTIVE))) + { + menu->cursor_prev = -1; + Menu_SetCursor( menu, i ); + break; + } + } + + uis.firstdraw = qtrue; +} + +/* +================= +UI_PopMenu +================= +*/ +void UI_PopMenu (void) +{ + trap_S_StartLocalSound( menu_out_sound, CHAN_LOCAL_SOUND ); + + uis.menusp--; + + if (uis.menusp < 0) + trap_Error ("UI_PopMenu: menu stack underflow"); + + if (uis.menusp) { + uis.activemenu = uis.stack[uis.menusp-1]; + uis.firstdraw = qtrue; + } + else { + UI_ForceMenuOff (); + } +} + +void UI_ForceMenuOff (void) +{ + uis.menusp = 0; + uis.activemenu = NULL; + + trap_Key_SetCatcher( trap_Key_GetCatcher() & ~KEYCATCH_UI ); + trap_Key_ClearStates(); + trap_Cvar_Set( "cl_paused", "0" ); +} + +/* +================= +UI_LerpColor +================= +*/ +void UI_LerpColor(vec4_t a, vec4_t b, vec4_t c, float t) +{ + int i; + + // lerp and clamp each component + for (i=0; i<4; i++) + { + c[i] = a[i] + t*(b[i]-a[i]); + if (c[i] < 0) + c[i] = 0; + else if (c[i] > 1.0) + c[i] = 1.0; + } +} + +/* +================= +UI_DrawProportionalString2 +================= +*/ +static int propMap[128][3] = { +{0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, +{0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, + +{0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, +{0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, + +{0, 0, PROP_SPACE_WIDTH}, // SPACE +{11, 122, 7}, // ! +{154, 181, 14}, // " +{55, 122, 17}, // # +{79, 122, 18}, // $ +{101, 122, 23}, // % +{153, 122, 18}, // & +{9, 93, 7}, // ' +{207, 122, 8}, // ( +{230, 122, 9}, // ) +{177, 122, 18}, // * +{30, 152, 18}, // + +{85, 181, 7}, // , +{34, 93, 11}, // - +{110, 181, 6}, // . +{130, 152, 14}, // / + +{22, 64, 17}, // 0 +{41, 64, 12}, // 1 +{58, 64, 17}, // 2 +{78, 64, 18}, // 3 +{98, 64, 19}, // 4 +{120, 64, 18}, // 5 +{141, 64, 18}, // 6 +{204, 64, 16}, // 7 +{162, 64, 17}, // 8 +{182, 64, 18}, // 9 +{59, 181, 7}, // : +{35,181, 7}, // ; +{203, 152, 14}, // < +{56, 93, 14}, // = +{228, 152, 14}, // > +{177, 181, 18}, // ? + +{28, 122, 22}, // @ +{5, 4, 18}, // A +{27, 4, 18}, // B +{48, 4, 18}, // C +{69, 4, 17}, // D +{90, 4, 13}, // E +{106, 4, 13}, // F +{121, 4, 18}, // G +{143, 4, 17}, // H +{164, 4, 8}, // I +{175, 4, 16}, // J +{195, 4, 18}, // K +{216, 4, 12}, // L +{230, 4, 23}, // M +{6, 34, 18}, // N +{27, 34, 18}, // O + +{48, 34, 18}, // P +{68, 34, 18}, // Q +{90, 34, 17}, // R +{110, 34, 18}, // S +{130, 34, 14}, // T +{146, 34, 18}, // U +{166, 34, 19}, // V +{185, 34, 29}, // W +{215, 34, 18}, // X +{234, 34, 18}, // Y +{5, 64, 14}, // Z +{60, 152, 7}, // [ +{106, 151, 13}, // '\' +{83, 152, 7}, // ] +{128, 122, 17}, // ^ +{4, 152, 21}, // _ + +{134, 181, 5}, // ' +{5, 4, 18}, // A +{27, 4, 18}, // B +{48, 4, 18}, // C +{69, 4, 17}, // D +{90, 4, 13}, // E +{106, 4, 13}, // F +{121, 4, 18}, // G +{143, 4, 17}, // H +{164, 4, 8}, // I +{175, 4, 16}, // J +{195, 4, 18}, // K +{216, 4, 12}, // L +{230, 4, 23}, // M +{6, 34, 18}, // N +{27, 34, 18}, // O + +{48, 34, 18}, // P +{68, 34, 18}, // Q +{90, 34, 17}, // R +{110, 34, 18}, // S +{130, 34, 14}, // T +{146, 34, 18}, // U +{166, 34, 19}, // V +{185, 34, 29}, // W +{215, 34, 18}, // X +{234, 34, 18}, // Y +{5, 64, 14}, // Z +{153, 152, 13}, // { +{11, 181, 5}, // | +{180, 152, 13}, // } +{79, 93, 17}, // ~ +{0, 0, -1} // DEL +}; + +static int propMapB[26][3] = { +{11, 12, 33}, +{49, 12, 31}, +{85, 12, 31}, +{120, 12, 30}, +{156, 12, 21}, +{183, 12, 21}, +{207, 12, 32}, + +{13, 55, 30}, +{49, 55, 13}, +{66, 55, 29}, +{101, 55, 31}, +{135, 55, 21}, +{158, 55, 40}, +{204, 55, 32}, + +{12, 97, 31}, +{48, 97, 31}, +{82, 97, 30}, +{118, 97, 30}, +{153, 97, 30}, +{185, 97, 25}, +{213, 97, 30}, + +{11, 139, 32}, +{42, 139, 51}, +{93, 139, 32}, +{126, 139, 31}, +{158, 139, 25}, +}; + +#define PROPB_GAP_WIDTH 4 +#define PROPB_SPACE_WIDTH 12 +#define PROPB_HEIGHT 36 + +// bk001205 - code below duplicated in cgame/cg_drawtools.c +// bk001205 - FIXME: does this belong in ui_shared.c? +/* +================= +UI_DrawBannerString +================= +*/ +static void UI_DrawBannerString2( int x, int y, const char* str, vec4_t color ) +{ + const char* s; + unsigned char ch; // bk001204 - unsigned + float ax; + float ay; + float aw; + float ah; + float frow; + float fcol; + float fwidth; + float fheight; + + // draw the colored text + trap_R_SetColor( color ); + + ax = x * uis.scale + uis.bias; + ay = y * uis.scale; + + s = str; + while ( *s ) + { + ch = *s & 127; + if ( ch == ' ' ) { + ax += ((float)PROPB_SPACE_WIDTH + (float)PROPB_GAP_WIDTH)* uis.scale; + } + else if ( ch >= 'A' && ch <= 'Z' ) { + ch -= 'A'; + fcol = (float)propMapB[ch][0] / 256.0f; + frow = (float)propMapB[ch][1] / 256.0f; + fwidth = (float)propMapB[ch][2] / 256.0f; + fheight = (float)PROPB_HEIGHT / 256.0f; + aw = (float)propMapB[ch][2] * uis.scale; + ah = (float)PROPB_HEIGHT * uis.scale; + trap_R_DrawStretchPic( ax, ay, aw, ah, fcol, frow, fcol+fwidth, frow+fheight, uis.charsetPropB ); + ax += (aw + (float)PROPB_GAP_WIDTH * uis.scale); + } + s++; + } + + trap_R_SetColor( NULL ); +} + +void UI_DrawBannerString( int x, int y, const char* str, int style, vec4_t color ) { + const char * s; + int ch; + int width; + vec4_t drawcolor; + + // find the width of the drawn text + s = str; + width = 0; + while ( *s ) { + ch = *s; + if ( ch == ' ' ) { + width += PROPB_SPACE_WIDTH; + } + else if ( ch >= 'A' && ch <= 'Z' ) { + width += propMapB[ch - 'A'][2] + PROPB_GAP_WIDTH; + } + s++; + } + width -= PROPB_GAP_WIDTH; + + switch( style & UI_FORMATMASK ) { + case UI_CENTER: + x -= width / 2; + break; + + case UI_RIGHT: + x -= width; + break; + + case UI_LEFT: + default: + break; + } + + if ( style & UI_DROPSHADOW ) { + drawcolor[0] = drawcolor[1] = drawcolor[2] = 0; + drawcolor[3] = color[3]; + UI_DrawBannerString2( x+2, y+2, str, drawcolor ); + } + + UI_DrawBannerString2( x, y, str, color ); +} + + +int UI_ProportionalStringWidth( const char* str ) { + const char * s; + int ch; + int charWidth; + int width; + + s = str; + width = 0; + while ( *s ) { + ch = *s & 127; + charWidth = propMap[ch][2]; + if ( charWidth != -1 ) { + width += charWidth; + width += PROP_GAP_WIDTH; + } + s++; + } + + width -= PROP_GAP_WIDTH; + return width; +} + +static void UI_DrawProportionalString2( int x, int y, const char* str, vec4_t color, float sizeScale, qhandle_t charset ) +{ + const char* s; + unsigned char ch; // bk001204 - unsigned + float ax; + float ay; + float aw = 0; // bk001204 - init + float ah; + float frow; + float fcol; + float fwidth; + float fheight; + + // draw the colored text + trap_R_SetColor( color ); + + ax = x * uis.scale + uis.bias; + ay = y * uis.scale; + + s = str; + while ( *s ) + { + ch = *s & 127; + if ( ch == ' ' ) { + aw = (float)PROP_SPACE_WIDTH * uis.scale * sizeScale; + } + else if ( propMap[ch][2] != -1 ) { + fcol = (float)propMap[ch][0] / 256.0f; + frow = (float)propMap[ch][1] / 256.0f; + fwidth = (float)propMap[ch][2] / 256.0f; + fheight = (float)PROP_HEIGHT / 256.0f; + aw = (float)propMap[ch][2] * uis.scale * sizeScale; + ah = (float)PROP_HEIGHT * uis.scale * sizeScale; + trap_R_DrawStretchPic( ax, ay, aw, ah, fcol, frow, fcol+fwidth, frow+fheight, charset ); + } + + ax += (aw + (float)PROP_GAP_WIDTH * uis.scale * sizeScale); + s++; + } + + trap_R_SetColor( NULL ); +} + +/* +================= +UI_ProportionalSizeScale +================= +*/ +float UI_ProportionalSizeScale( int style ) { + if( style & UI_SMALLFONT ) { + return PROP_SMALL_SIZE_SCALE; + } + + return 1.00; +} + + +/* +================= +UI_DrawProportionalString +================= +*/ +void UI_DrawProportionalString( int x, int y, const char* str, int style, vec4_t color ) { + vec4_t drawcolor; + int width; + float sizeScale; + + sizeScale = UI_ProportionalSizeScale( style ); + + switch( style & UI_FORMATMASK ) { + case UI_CENTER: + width = UI_ProportionalStringWidth( str ) * sizeScale; + x -= width / 2; + break; + + case UI_RIGHT: + width = UI_ProportionalStringWidth( str ) * sizeScale; + x -= width; + break; + + case UI_LEFT: + default: + break; + } + + if ( style & UI_DROPSHADOW ) { + drawcolor[0] = drawcolor[1] = drawcolor[2] = 0; + drawcolor[3] = color[3]; + UI_DrawProportionalString2( x+2, y+2, str, drawcolor, sizeScale, uis.charsetProp ); + } + + if ( style & UI_INVERSE ) { + drawcolor[0] = color[0] * 0.7; + drawcolor[1] = color[1] * 0.7; + drawcolor[2] = color[2] * 0.7; + drawcolor[3] = color[3]; + UI_DrawProportionalString2( x, y, str, drawcolor, sizeScale, uis.charsetProp ); + return; + } + + if ( style & UI_PULSE ) { + drawcolor[0] = color[0] * 0.7; + drawcolor[1] = color[1] * 0.7; + drawcolor[2] = color[2] * 0.7; + drawcolor[3] = color[3]; + UI_DrawProportionalString2( x, y, str, color, sizeScale, uis.charsetProp ); + + drawcolor[0] = color[0]; + drawcolor[1] = color[1]; + drawcolor[2] = color[2]; + drawcolor[3] = 0.5 + 0.5 * sin( uis.realtime / PULSE_DIVISOR ); + UI_DrawProportionalString2( x, y, str, drawcolor, sizeScale, uis.charsetPropGlow ); + return; + } + + UI_DrawProportionalString2( x, y, str, color, sizeScale, uis.charsetProp ); +} + +/* +================= +UI_DrawProportionalString_Wrapped +================= +*/ +void UI_DrawProportionalString_AutoWrapped( int x, int y, int xmax, int ystep, const char* str, int style, vec4_t color ) { + int width; + char *s1,*s2,*s3; + char c_bcp; + char buf[1024]; + float sizeScale; + + if (!str || str[0]=='\0') + return; + + sizeScale = UI_ProportionalSizeScale( style ); + + Q_strncpyz(buf, str, sizeof(buf)); + s1 = s2 = s3 = buf; + + while (1) { + do { + s3++; + } while (*s3!=' ' && *s3!='\0'); + c_bcp = *s3; + *s3 = '\0'; + width = UI_ProportionalStringWidth(s1) * sizeScale; + *s3 = c_bcp; + if (width > xmax) { + if (s1==s2) + { + // fuck, don't have a clean cut, we'll overflow + s2 = s3; + } + *s2 = '\0'; + UI_DrawProportionalString(x, y, s1, style, color); + y += ystep; + if (c_bcp == '\0') + { + // that was the last word + // we could start a new loop, but that wouldn't be much use + // even if the word is too long, we would overflow it (see above) + // so just print it now if needed + s2++; + if (*s2 != '\0') // if we are printing an overflowing line we have s2 == s3 + UI_DrawProportionalString(x, y, s2, style, color); + break; + } + s2++; + s1 = s2; + s3 = s2; + } + else + { + s2 = s3; + if (c_bcp == '\0') // we reached the end + { + UI_DrawProportionalString(x, y, s1, style, color); + break; + } + } + } +} + +/* +================= +UI_DrawString2 +================= +*/ +static void UI_DrawString2( int x, int y, const char* str, vec4_t color, int charw, int charh ) +{ + const char* s; + char ch; + int forceColor = qfalse; //APSFIXME; + vec4_t tempcolor; + float ax; + float ay; + float aw; + float ah; + float frow; + float fcol; + + if (y < -charh) + // offscreen + return; + + // draw the colored text + trap_R_SetColor( color ); + + ax = x * uis.scale + uis.bias; + ay = y * uis.scale; + aw = charw * uis.scale; + ah = charh * uis.scale; + + s = str; + while ( *s ) + { + if ( Q_IsColorString( s ) ) + { + if ( !forceColor ) + { + memcpy( tempcolor, g_color_table[ColorIndex(s[1])], sizeof( tempcolor ) ); + tempcolor[3] = color[3]; + trap_R_SetColor( tempcolor ); + } + s += 2; + continue; + } + + ch = *s & 255; + if (ch != ' ') + { + frow = (ch>>4)*0.0625; + fcol = (ch&15)*0.0625; + trap_R_DrawStretchPic( ax, ay, aw, ah, fcol, frow, fcol + 0.0625, frow + 0.0625, uis.charset ); + } + + ax += aw; + s++; + } + + trap_R_SetColor( NULL ); +} + +/* +================= +UI_DrawString +================= +*/ +void UI_DrawString( int x, int y, const char* str, int style, vec4_t color ) +{ + int len; + int charw; + int charh; + vec4_t newcolor; + vec4_t lowlight; + float *drawcolor; + vec4_t dropcolor; + + if( !str ) { + return; + } + + if ((style & UI_BLINK) && ((uis.realtime/BLINK_DIVISOR) & 1)) + return; + + if (style & UI_SMALLFONT) + { + charw = SMALLCHAR_WIDTH; + charh = SMALLCHAR_HEIGHT; + } + else if (style & UI_GIANTFONT) + { + charw = GIANTCHAR_WIDTH; + charh = GIANTCHAR_HEIGHT; + } + else + { + charw = BIGCHAR_WIDTH; + charh = BIGCHAR_HEIGHT; + } + + if (style & UI_PULSE) + { + lowlight[0] = 0.8*color[0]; + lowlight[1] = 0.8*color[1]; + lowlight[2] = 0.8*color[2]; + lowlight[3] = 0.8*color[3]; + UI_LerpColor(color,lowlight,newcolor,0.5+0.5*sin(uis.realtime/PULSE_DIVISOR)); + drawcolor = newcolor; + } + else + drawcolor = color; + + switch (style & UI_FORMATMASK) + { + case UI_CENTER: + // center justify at x + len = strlen(str); + x = x - len*charw/2; + break; + + case UI_RIGHT: + // right justify at x + len = strlen(str); + x = x - len*charw; + break; + + default: + // left justify at x + break; + } + + if ( style & UI_DROPSHADOW ) + { + dropcolor[0] = dropcolor[1] = dropcolor[2] = 0; + dropcolor[3] = drawcolor[3]; + UI_DrawString2(x+2,y+2,str,dropcolor,charw,charh); + } + + UI_DrawString2(x,y,str,drawcolor,charw,charh); +} + +/* +================= +UI_DrawChar +================= +*/ +void UI_DrawChar( int x, int y, int ch, int style, vec4_t color ) +{ + char buff[2]; + + buff[0] = ch; + buff[1] = '\0'; + + UI_DrawString( x, y, buff, style, color ); +} + +qboolean UI_IsFullscreen( void ) { + if ( uis.activemenu && ( trap_Key_GetCatcher() & KEYCATCH_UI ) ) { + return uis.activemenu->fullscreen; + } + + return qfalse; +} + +static void NeedCDAction( qboolean result ) { + if ( !result ) { + trap_Cmd_ExecuteText( EXEC_APPEND, "quit\n" ); + } +} + +static void NeedCDKeyAction( qboolean result ) { + if ( !result ) { + trap_Cmd_ExecuteText( EXEC_APPEND, "quit\n" ); + } +} + +void UI_SetActiveMenu( uiMenuCommand_t menu ) { + // this should be the ONLY way the menu system is brought up + // enusure minumum menu data is cached + Menu_Cache(); + + switch ( menu ) { + case UIMENU_NONE: + UI_ForceMenuOff(); + return; + case UIMENU_MAIN: + UI_MainMenu(); + return; + case UIMENU_NEED_CD: + UI_ConfirmMenu( "Insert the CD", (voidfunc_f)NULL, NeedCDAction ); + return; + case UIMENU_BAD_CD_KEY: + UI_ConfirmMenu( "Bad CD Key", (voidfunc_f)NULL, NeedCDKeyAction ); + return; + case UIMENU_INGAME: + /* + //GRank + UI_RankingsMenu(); + return; + */ + trap_Cvar_Set( "cl_paused", "1" ); + UI_InGameMenu(); + return; + + // bk001204 + case UIMENU_TEAM: + case UIMENU_POSTGAME: + default: +#ifndef NDEBUG + Com_Printf("UI_SetActiveMenu: bad enum %d\n", menu ); +#endif + break; + } +} + +/* +================= +UI_KeyEvent +================= +*/ +void UI_KeyEvent( int key, int down ) { + sfxHandle_t s; + + if (!uis.activemenu) { + return; + } + + if (!down) { + return; + } + + if (uis.activemenu->key) + s = uis.activemenu->key( key ); + else + s = Menu_DefaultKey( uis.activemenu, key ); + + if ((s > 0) && (s != menu_null_sound)) + trap_S_StartLocalSound( s, CHAN_LOCAL_SOUND ); +} + +/* +================= +UI_MouseEvent +================= +*/ +void UI_MouseEvent( int dx, int dy ) +{ + int i; + menucommon_s* m; + + if (!uis.activemenu) + return; + + // update mouse screen position + uis.cursorx += dx; + if (uis.cursorx < 0) + uis.cursorx = 0; + else if (uis.cursorx > SCREEN_WIDTH) + uis.cursorx = SCREEN_WIDTH; + + uis.cursory += dy; + if (uis.cursory < 0) + uis.cursory = 0; + else if (uis.cursory > SCREEN_HEIGHT) + uis.cursory = SCREEN_HEIGHT; + + // region test the active menu items + for (i=0; initems; i++) + { + m = (menucommon_s*)uis.activemenu->items[i]; + + if (m->flags & (QMF_GRAYED|QMF_INACTIVE)) + continue; + + if ((uis.cursorx < m->left) || + (uis.cursorx > m->right) || + (uis.cursory < m->top) || + (uis.cursory > m->bottom)) + { + // cursor out of item bounds + continue; + } + + // set focus to item at cursor + if (uis.activemenu->cursor != i) + { + Menu_SetCursor( uis.activemenu, i ); + ((menucommon_s*)(uis.activemenu->items[uis.activemenu->cursor_prev]))->flags &= ~QMF_HASMOUSEFOCUS; + + if ( !(((menucommon_s*)(uis.activemenu->items[uis.activemenu->cursor]))->flags & QMF_SILENT ) ) { + trap_S_StartLocalSound( menu_move_sound, CHAN_LOCAL_SOUND ); + } + } + + ((menucommon_s*)(uis.activemenu->items[uis.activemenu->cursor]))->flags |= QMF_HASMOUSEFOCUS; + return; + } + + if (uis.activemenu->nitems > 0) { + // out of any region + ((menucommon_s*)(uis.activemenu->items[uis.activemenu->cursor]))->flags &= ~QMF_HASMOUSEFOCUS; + } +} + +char *UI_Argv( int arg ) { + static char buffer[MAX_STRING_CHARS]; + + trap_Argv( arg, buffer, sizeof( buffer ) ); + + return buffer; +} + + +char *UI_Cvar_VariableString( const char *var_name ) { + static char buffer[MAX_STRING_CHARS]; + + trap_Cvar_VariableStringBuffer( var_name, buffer, sizeof( buffer ) ); + + return buffer; +} + + +/* +================= +UI_Cache +================= +*/ +void UI_Cache_f( void ) { + MainMenu_Cache(); + InGame_Cache(); + ConfirmMenu_Cache(); + PlayerModel_Cache(); + PlayerSettings_Cache(); + Controls_Cache(); + Demos_Cache(); + UI_CinematicsMenu_Cache(); + Preferences_Cache(); + ServerInfo_Cache(); + SpecifyServer_Cache(); + ArenaServers_Cache(); + StartServer_Cache(); + ServerOptions_Cache(); + DriverInfo_Cache(); + GraphicsOptions_Cache(); + UI_DisplayOptionsMenu_Cache(); + UI_SoundOptionsMenu_Cache(); + UI_NetworkOptionsMenu_Cache(); + UI_SPLevelMenu_Cache(); + UI_SPSkillMenu_Cache(); + UI_SPPostgameMenu_Cache(); + TeamMain_Cache(); + UI_AddBots_Cache(); + UI_RemoveBots_Cache(); + UI_SetupMenu_Cache(); +// UI_LoadConfig_Cache(); +// UI_SaveConfigMenu_Cache(); + UI_BotSelectMenu_Cache(); + UI_CDKeyMenu_Cache(); + UI_ModsMenu_Cache(); + +} + + +/* +================= +UI_ConsoleCommand +================= +*/ +qboolean UI_ConsoleCommand( int realTime ) { + char *cmd; + + cmd = UI_Argv( 0 ); + + // ensure minimum menu data is available + Menu_Cache(); + + if ( Q_stricmp (cmd, "levelselect") == 0 ) { + UI_SPLevelMenu_f(); + return qtrue; + } + + if ( Q_stricmp (cmd, "postgame") == 0 ) { + UI_SPPostgameMenu_f(); + return qtrue; + } + + if ( Q_stricmp (cmd, "ui_cache") == 0 ) { + UI_Cache_f(); + return qtrue; + } + + if ( Q_stricmp (cmd, "ui_cinematics") == 0 ) { + UI_CinematicsMenu_f(); + return qtrue; + } + + if ( Q_stricmp (cmd, "ui_teamOrders") == 0 ) { + UI_TeamOrdersMenu_f(); + return qtrue; + } + + if ( Q_stricmp (cmd, "iamacheater") == 0 ) { + UI_SPUnlock_f(); + return qtrue; + } + + if ( Q_stricmp (cmd, "iamamonkey") == 0 ) { + UI_SPUnlockMedals_f(); + return qtrue; + } + + if ( Q_stricmp (cmd, "ui_cdkey") == 0 ) { + UI_CDKeyMenu_f(); + return qtrue; + } + + return qfalse; +} + +/* +================= +UI_Shutdown +================= +*/ +void UI_Shutdown( void ) { +} + +/* +================= +UI_Init +================= +*/ +void UI_Init( void ) { + UI_RegisterCvars(); + + UI_InitGameinfo(); + + // cache redundant calulations + trap_GetGlconfig( &uis.glconfig ); + + // for 640x480 virtualized screen + uis.scale = uis.glconfig.vidHeight * (1.0/480.0); + if ( uis.glconfig.vidWidth * 480 > uis.glconfig.vidHeight * 640 ) { + // wide screen + uis.bias = 0.5 * ( uis.glconfig.vidWidth - ( uis.glconfig.vidHeight * (640.0/480.0) ) ); + } + else { + // no wide screen + uis.bias = 0; + } + + // initialize the menu system + Menu_Cache(); + + uis.activemenu = NULL; + uis.menusp = 0; +} + +/* +================ +UI_AdjustFrom640 + +Adjusted for resolution and screen aspect ratio +================ +*/ +void UI_AdjustFrom640( float *x, float *y, float *w, float *h ) { + // expect valid pointers + *x = *x * uis.scale + uis.bias; + *y *= uis.scale; + *w *= uis.scale; + *h *= uis.scale; +} + +void UI_DrawNamedPic( float x, float y, float width, float height, const char *picname ) { + qhandle_t hShader; + + hShader = trap_R_RegisterShaderNoMip( picname ); + UI_AdjustFrom640( &x, &y, &width, &height ); + trap_R_DrawStretchPic( x, y, width, height, 0, 0, 1, 1, hShader ); +} + +void UI_DrawHandlePic( float x, float y, float w, float h, qhandle_t hShader ) { + float s0; + float s1; + float t0; + float t1; + + if( w < 0 ) { // flip about vertical + w = -w; + s0 = 1; + s1 = 0; + } + else { + s0 = 0; + s1 = 1; + } + + if( h < 0 ) { // flip about horizontal + h = -h; + t0 = 1; + t1 = 0; + } + else { + t0 = 0; + t1 = 1; + } + + UI_AdjustFrom640( &x, &y, &w, &h ); + trap_R_DrawStretchPic( x, y, w, h, s0, t0, s1, t1, hShader ); +} + +/* +================ +UI_FillRect + +Coordinates are 640*480 virtual values +================= +*/ +void UI_FillRect( float x, float y, float width, float height, const float *color ) { + trap_R_SetColor( color ); + + UI_AdjustFrom640( &x, &y, &width, &height ); + trap_R_DrawStretchPic( x, y, width, height, 0, 0, 0, 0, uis.whiteShader ); + + trap_R_SetColor( NULL ); +} + +/* +================ +UI_DrawRect + +Coordinates are 640*480 virtual values +================= +*/ +void UI_DrawRect( float x, float y, float width, float height, const float *color ) { + trap_R_SetColor( color ); + + UI_AdjustFrom640( &x, &y, &width, &height ); + + trap_R_DrawStretchPic( x, y, width, 1, 0, 0, 0, 0, uis.whiteShader ); + trap_R_DrawStretchPic( x, y, 1, height, 0, 0, 0, 0, uis.whiteShader ); + trap_R_DrawStretchPic( x, y + height - 1, width, 1, 0, 0, 0, 0, uis.whiteShader ); + trap_R_DrawStretchPic( x + width - 1, y, 1, height, 0, 0, 0, 0, uis.whiteShader ); + + trap_R_SetColor( NULL ); +} + +void UI_SetColor( const float *rgba ) { + trap_R_SetColor( rgba ); +} + +void UI_UpdateScreen( void ) { + trap_UpdateScreen(); +} + +/* +================= +UI_Refresh +================= +*/ +void UI_Refresh( int realtime ) +{ + uis.frametime = realtime - uis.realtime; + uis.realtime = realtime; + + if ( !( trap_Key_GetCatcher() & KEYCATCH_UI ) ) { + return; + } + + UI_UpdateCvars(); + + if ( uis.activemenu ) + { + if (uis.activemenu->fullscreen) + { + // draw the background + if( uis.activemenu->showlogo ) { + UI_DrawHandlePic( 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, uis.menuBackShader ); + } + else { + UI_DrawHandlePic( 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, uis.menuBackNoLogoShader ); + } + } + + if (uis.activemenu->draw) + uis.activemenu->draw(); + else + Menu_Draw( uis.activemenu ); + + if( uis.firstdraw ) { + UI_MouseEvent( 0, 0 ); + uis.firstdraw = qfalse; + } + } + + // draw cursor + UI_SetColor( NULL ); + UI_DrawHandlePic( uis.cursorx-16, uis.cursory-16, 32, 32, uis.cursor); + +#ifndef NDEBUG + if (uis.debug) + { + // cursor coordinates + UI_DrawString( 0, 0, va("(%d,%d)",uis.cursorx,uis.cursory), UI_LEFT|UI_SMALLFONT, colorRed ); + } +#endif + + // delay playing the enter sound until after the + // menu has been drawn, to avoid delay while + // caching images + if (m_entersound) + { + trap_S_StartLocalSound( menu_in_sound, CHAN_LOCAL_SOUND ); + m_entersound = qfalse; + } +} + +void UI_DrawTextBox (int x, int y, int width, int lines) +{ + UI_FillRect( x + BIGCHAR_WIDTH/2, y + BIGCHAR_HEIGHT/2, ( width + 1 ) * BIGCHAR_WIDTH, ( lines + 1 ) * BIGCHAR_HEIGHT, colorBlack ); + UI_DrawRect( x + BIGCHAR_WIDTH/2, y + BIGCHAR_HEIGHT/2, ( width + 1 ) * BIGCHAR_WIDTH, ( lines + 1 ) * BIGCHAR_HEIGHT, colorWhite ); +} + +qboolean UI_CursorInRect (int x, int y, int width, int height) +{ + if (uis.cursorx < x || + uis.cursory < y || + uis.cursorx > x+width || + uis.cursory > y+height) + return qfalse; + + return qtrue; +} diff --git a/code/q3_ui/ui_cdkey.c b/code/q3_ui/ui_cdkey.c new file mode 100755 index 0000000..0b1f718 --- /dev/null +++ b/code/q3_ui/ui_cdkey.c @@ -0,0 +1,291 @@ +/* +=========================================================================== +Copyright (C) 1999-2005 Id Software, Inc. + +This file is part of Quake III Arena source code. + +Quake III Arena source code is free software; you can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 2 of the License, +or (at your option) any later version. + +Quake III Arena source code is distributed in the hope that it will be +useful, but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Foobar; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ +// +/* +======================================================================= + +CD KEY MENU + +======================================================================= +*/ + + +#include "ui_local.h" + + +#define ART_FRAME "menu/art/cut_frame" +#define ART_ACCEPT0 "menu/art/accept_0" +#define ART_ACCEPT1 "menu/art/accept_1" +#define ART_BACK0 "menu/art/back_0" +#define ART_BACK1 "menu/art/back_1" + +#define ID_CDKEY 10 +#define ID_ACCEPT 11 +#define ID_BACK 12 + + +typedef struct { + menuframework_s menu; + + menutext_s banner; + menubitmap_s frame; + + menufield_s cdkey; + + menubitmap_s accept; + menubitmap_s back; +} cdkeyMenuInfo_t; + +static cdkeyMenuInfo_t cdkeyMenuInfo; + + +/* +=============== +UI_CDKeyMenu_Event +=============== +*/ +static void UI_CDKeyMenu_Event( void *ptr, int event ) { + if( event != QM_ACTIVATED ) { + return; + } + + switch( ((menucommon_s*)ptr)->id ) { + case ID_ACCEPT: + if( cdkeyMenuInfo.cdkey.field.buffer[0] ) { + trap_SetCDKey( cdkeyMenuInfo.cdkey.field.buffer ); + } + UI_PopMenu(); + break; + + case ID_BACK: + UI_PopMenu(); + break; + } +} + + +/* +================= +UI_CDKeyMenu_PreValidateKey +================= +*/ +static int UI_CDKeyMenu_PreValidateKey( const char *key ) { + char ch; + + if( strlen( key ) != 16 ) { + return 1; + } + + while( ( ch = *key++ ) ) { + switch( ch ) { + case '2': + case '3': + case '7': + case 'a': + case 'b': + case 'c': + case 'd': + case 'g': + case 'h': + case 'j': + case 'l': + case 'p': + case 'r': + case 's': + case 't': + case 'w': + continue; + default: + return -1; + } + } + + return 0; +} + + +/* +================= +UI_CDKeyMenu_DrawKey +================= +*/ +static void UI_CDKeyMenu_DrawKey( void *self ) { + menufield_s *f; + qboolean focus; + int style; + char c; + float *color; + int x, y; + int val; + + f = (menufield_s *)self; + + focus = (f->generic.parent->cursor == f->generic.menuPosition); + + style = UI_LEFT; + if( focus ) { + color = color_yellow; + } + else { + color = color_orange; + } + + x = 320 - 8 * BIGCHAR_WIDTH; + y = 240 - BIGCHAR_HEIGHT / 2; + UI_FillRect( x, y, 16 * BIGCHAR_WIDTH, BIGCHAR_HEIGHT, listbar_color ); + UI_DrawString( x, y, f->field.buffer, style, color ); + + // draw cursor if we have focus + if( focus ) { + if ( trap_Key_GetOverstrikeMode() ) { + c = 11; + } else { + c = 10; + } + + style &= ~UI_PULSE; + style |= UI_BLINK; + + UI_DrawChar( x + f->field.cursor * BIGCHAR_WIDTH, y, c, style, color_white ); + } + + val = UI_CDKeyMenu_PreValidateKey( f->field.buffer ); + if( val == 1 ) { + UI_DrawProportionalString( 320, 376, "Please enter your CD Key", UI_CENTER|UI_SMALLFONT, color_yellow ); + } + else if ( val == 0 ) { + UI_DrawProportionalString( 320, 376, "The CD Key appears to be valid, thank you", UI_CENTER|UI_SMALLFONT, color_white ); + } + else { + UI_DrawProportionalString( 320, 376, "The CD Key is not valid", UI_CENTER|UI_SMALLFONT, color_red ); + } +} + + +/* +=============== +UI_CDKeyMenu_Init +=============== +*/ +static void UI_CDKeyMenu_Init( void ) { + trap_Cvar_Set( "ui_cdkeychecked", "1" ); + + UI_CDKeyMenu_Cache(); + + memset( &cdkeyMenuInfo, 0, sizeof(cdkeyMenuInfo) ); + cdkeyMenuInfo.menu.wrapAround = qtrue; + cdkeyMenuInfo.menu.fullscreen = qtrue; + + cdkeyMenuInfo.banner.generic.type = MTYPE_BTEXT; + cdkeyMenuInfo.banner.generic.x = 320; + cdkeyMenuInfo.banner.generic.y = 16; + cdkeyMenuInfo.banner.string = "CD KEY"; + cdkeyMenuInfo.banner.color = color_white; + cdkeyMenuInfo.banner.style = UI_CENTER; + + cdkeyMenuInfo.frame.generic.type = MTYPE_BITMAP; + cdkeyMenuInfo.frame.generic.name = ART_FRAME; + cdkeyMenuInfo.frame.generic.flags = QMF_INACTIVE; + cdkeyMenuInfo.frame.generic.x = 142; + cdkeyMenuInfo.frame.generic.y = 118; + cdkeyMenuInfo.frame.width = 359; + cdkeyMenuInfo.frame.height = 256; + + cdkeyMenuInfo.cdkey.generic.type = MTYPE_FIELD; + cdkeyMenuInfo.cdkey.generic.name = "CD Key:"; + cdkeyMenuInfo.cdkey.generic.flags = QMF_LOWERCASE; + cdkeyMenuInfo.cdkey.generic.x = 320 - BIGCHAR_WIDTH * 2.5; + cdkeyMenuInfo.cdkey.generic.y = 240 - BIGCHAR_HEIGHT / 2; + cdkeyMenuInfo.cdkey.field.widthInChars = 16; + cdkeyMenuInfo.cdkey.field.maxchars = 16; + cdkeyMenuInfo.cdkey.generic.ownerdraw = UI_CDKeyMenu_DrawKey; + + cdkeyMenuInfo.accept.generic.type = MTYPE_BITMAP; + cdkeyMenuInfo.accept.generic.name = ART_ACCEPT0; + cdkeyMenuInfo.accept.generic.flags = QMF_RIGHT_JUSTIFY|QMF_PULSEIFFOCUS; + cdkeyMenuInfo.accept.generic.id = ID_ACCEPT; + cdkeyMenuInfo.accept.generic.callback = UI_CDKeyMenu_Event; + cdkeyMenuInfo.accept.generic.x = 640; + cdkeyMenuInfo.accept.generic.y = 480-64; + cdkeyMenuInfo.accept.width = 128; + cdkeyMenuInfo.accept.height = 64; + cdkeyMenuInfo.accept.focuspic = ART_ACCEPT1; + + cdkeyMenuInfo.back.generic.type = MTYPE_BITMAP; + cdkeyMenuInfo.back.generic.name = ART_BACK0; + cdkeyMenuInfo.back.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS; + cdkeyMenuInfo.back.generic.id = ID_BACK; + cdkeyMenuInfo.back.generic.callback = UI_CDKeyMenu_Event; + cdkeyMenuInfo.back.generic.x = 0; + cdkeyMenuInfo.back.generic.y = 480-64; + cdkeyMenuInfo.back.width = 128; + cdkeyMenuInfo.back.height = 64; + cdkeyMenuInfo.back.focuspic = ART_BACK1; + + Menu_AddItem( &cdkeyMenuInfo.menu, &cdkeyMenuInfo.banner ); + Menu_AddItem( &cdkeyMenuInfo.menu, &cdkeyMenuInfo.frame ); + Menu_AddItem( &cdkeyMenuInfo.menu, &cdkeyMenuInfo.cdkey ); + Menu_AddItem( &cdkeyMenuInfo.menu, &cdkeyMenuInfo.accept ); + if( uis.menusp ) { + Menu_AddItem( &cdkeyMenuInfo.menu, &cdkeyMenuInfo.back ); + } + + trap_GetCDKey( cdkeyMenuInfo.cdkey.field.buffer, cdkeyMenuInfo.cdkey.field.maxchars + 1 ); + if( trap_VerifyCDKey( cdkeyMenuInfo.cdkey.field.buffer, NULL ) == qfalse ) { + cdkeyMenuInfo.cdkey.field.buffer[0] = 0; + } +} + + +/* +================= +UI_CDKeyMenu_Cache +================= +*/ +void UI_CDKeyMenu_Cache( void ) { + trap_R_RegisterShaderNoMip( ART_ACCEPT0 ); + trap_R_RegisterShaderNoMip( ART_ACCEPT1 ); + trap_R_RegisterShaderNoMip( ART_BACK0 ); + trap_R_RegisterShaderNoMip( ART_BACK1 ); + trap_R_RegisterShaderNoMip( ART_FRAME ); +} + + +/* +=============== +UI_CDKeyMenu +=============== +*/ +void UI_CDKeyMenu( void ) { + UI_CDKeyMenu_Init(); + UI_PushMenu( &cdkeyMenuInfo.menu ); +} + + +/* +=============== +UI_CDKeyMenu_f +=============== +*/ +void UI_CDKeyMenu_f( void ) { + UI_CDKeyMenu(); +} diff --git a/code/q3_ui/ui_cinematics.c b/code/q3_ui/ui_cinematics.c new file mode 100755 index 0000000..6092b4a --- /dev/null +++ b/code/q3_ui/ui_cinematics.c @@ -0,0 +1,350 @@ +/* +=========================================================================== +Copyright (C) 1999-2005 Id Software, Inc. + +This file is part of Quake III Arena source code. + +Quake III Arena source code is free software; you can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 2 of the License, +or (at your option) any later version. + +Quake III Arena source code is distributed in the hope that it will be +useful, but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Foobar; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ +// +#include "ui_local.h" + + +#define ART_BACK0 "menu/art/back_0" +#define ART_BACK1 "menu/art/back_1" +#define ART_FRAMEL "menu/art/frame2_l" +#define ART_FRAMER "menu/art/frame1_r" + +#define VERTICAL_SPACING 30 + +#define ID_BACK 10 +#define ID_CIN_IDLOGO 11 +#define ID_CIN_INTRO 12 +#define ID_CIN_TIER1 13 +#define ID_CIN_TIER2 14 +#define ID_CIN_TIER3 15 +#define ID_CIN_TIER4 16 +#define ID_CIN_TIER5 17 +#define ID_CIN_TIER6 18 +#define ID_CIN_TIER7 19 +#define ID_CIN_END 20 + + +typedef struct { + menuframework_s menu; + menutext_s banner; + menubitmap_s framel; + menubitmap_s framer; + menutext_s cin_idlogo; + menutext_s cin_intro; + menutext_s cin_tier1; + menutext_s cin_tier2; + menutext_s cin_tier3; + menutext_s cin_tier4; + menutext_s cin_tier5; + menutext_s cin_tier6; + menutext_s cin_tier7; + menutext_s cin_end; + menubitmap_s back; +} cinematicsMenuInfo_t; + +static cinematicsMenuInfo_t cinematicsMenuInfo; + +static char *cinematics[] = { + "idlogo", + "intro", + "tier1", + "tier2", + "tier3", + "tier4", + "tier5", + "tier6", + "tier7", + "end" +}; + +/* +=============== +UI_CinematicsMenu_BackEvent +=============== +*/ +static void UI_CinematicsMenu_BackEvent( void *ptr, int event ) { + if( event != QM_ACTIVATED ) { + return; + } + UI_PopMenu(); +} + + +/* +=============== +UI_CinematicsMenu_Event +=============== +*/ +static void UI_CinematicsMenu_Event( void *ptr, int event ) { + int n; + + if (event != QM_ACTIVATED) + return; + + n = ((menucommon_s*)ptr)->id - ID_CIN_IDLOGO; + trap_Cvar_Set( "nextmap", va( "ui_cinematics %i", n ) ); + if( uis.demoversion && ((menucommon_s*)ptr)->id == ID_CIN_END ) { + trap_Cmd_ExecuteText( EXEC_APPEND, "disconnect; cinematic demoEnd.RoQ 1\n" ); + } + else { + trap_Cmd_ExecuteText( EXEC_APPEND, va( "disconnect; cinematic %s.RoQ\n", cinematics[n] ) ); + } +} + + +/* +=============== +UI_CinematicsMenu_Init +=============== +*/ +static void UI_CinematicsMenu_Init( void ) { + int y; + + UI_CinematicsMenu_Cache(); + + memset( &cinematicsMenuInfo, 0, sizeof(cinematicsMenuInfo) ); + cinematicsMenuInfo.menu.fullscreen = qtrue; + + cinematicsMenuInfo.banner.generic.type = MTYPE_BTEXT; + cinematicsMenuInfo.banner.generic.x = 320; + cinematicsMenuInfo.banner.generic.y = 16; + cinematicsMenuInfo.banner.string = "CINEMATICS"; + cinematicsMenuInfo.banner.color = color_white; + cinematicsMenuInfo.banner.style = UI_CENTER; + + cinematicsMenuInfo.framel.generic.type = MTYPE_BITMAP; + cinematicsMenuInfo.framel.generic.name = ART_FRAMEL; + cinematicsMenuInfo.framel.generic.flags = QMF_INACTIVE; + cinematicsMenuInfo.framel.generic.x = 0; + cinematicsMenuInfo.framel.generic.y = 78; + cinematicsMenuInfo.framel.width = 256; + cinematicsMenuInfo.framel.height = 329; + + cinematicsMenuInfo.framer.generic.type = MTYPE_BITMAP; + cinematicsMenuInfo.framer.generic.name = ART_FRAMER; + cinematicsMenuInfo.framer.generic.flags = QMF_INACTIVE; + cinematicsMenuInfo.framer.generic.x = 376; + cinematicsMenuInfo.framer.generic.y = 76; + cinematicsMenuInfo.framer.width = 256; + cinematicsMenuInfo.framer.height = 334; + + y = 100; + cinematicsMenuInfo.cin_idlogo.generic.type = MTYPE_PTEXT; + cinematicsMenuInfo.cin_idlogo.generic.flags = QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS; + cinematicsMenuInfo.cin_idlogo.generic.x = 320; + cinematicsMenuInfo.cin_idlogo.generic.y = y; + cinematicsMenuInfo.cin_idlogo.generic.id = ID_CIN_IDLOGO; + cinematicsMenuInfo.cin_idlogo.generic.callback = UI_CinematicsMenu_Event; + cinematicsMenuInfo.cin_idlogo.string = "ID LOGO"; + cinematicsMenuInfo.cin_idlogo.color = color_red; + cinematicsMenuInfo.cin_idlogo.style = UI_CENTER; + + y += VERTICAL_SPACING; + cinematicsMenuInfo.cin_intro.generic.type = MTYPE_PTEXT; + cinematicsMenuInfo.cin_intro.generic.flags = QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS; + cinematicsMenuInfo.cin_intro.generic.x = 320; + cinematicsMenuInfo.cin_intro.generic.y = y; + cinematicsMenuInfo.cin_intro.generic.id = ID_CIN_INTRO; + cinematicsMenuInfo.cin_intro.generic.callback = UI_CinematicsMenu_Event; + cinematicsMenuInfo.cin_intro.string = "INTRO"; + cinematicsMenuInfo.cin_intro.color = color_red; + cinematicsMenuInfo.cin_intro.style = UI_CENTER; + if( uis.demoversion ) { + cinematicsMenuInfo.cin_intro.generic.flags |= QMF_GRAYED; + } + + y += VERTICAL_SPACING; + cinematicsMenuInfo.cin_tier1.generic.type = MTYPE_PTEXT; + cinematicsMenuInfo.cin_tier1.generic.flags = QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS; + cinematicsMenuInfo.cin_tier1.generic.x = 320; + cinematicsMenuInfo.cin_tier1.generic.y = y; + cinematicsMenuInfo.cin_tier1.generic.id = ID_CIN_TIER1; + cinematicsMenuInfo.cin_tier1.generic.callback = UI_CinematicsMenu_Event; + cinematicsMenuInfo.cin_tier1.string = "Tier 1"; + cinematicsMenuInfo.cin_tier1.color = color_red; + cinematicsMenuInfo.cin_tier1.style = UI_CENTER; + if( !UI_CanShowTierVideo( 1 ) ) { + cinematicsMenuInfo.cin_tier1.generic.flags |= QMF_GRAYED; + } + + y += VERTICAL_SPACING; + cinematicsMenuInfo.cin_tier2.generic.type = MTYPE_PTEXT; + cinematicsMenuInfo.cin_tier2.generic.flags = QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS; + cinematicsMenuInfo.cin_tier2.generic.x = 320; + cinematicsMenuInfo.cin_tier2.generic.y = y; + cinematicsMenuInfo.cin_tier2.generic.id = ID_CIN_TIER2; + cinematicsMenuInfo.cin_tier2.generic.callback = UI_CinematicsMenu_Event; + cinematicsMenuInfo.cin_tier2.string = "Tier 2"; + cinematicsMenuInfo.cin_tier2.color = color_red; + cinematicsMenuInfo.cin_tier2.style = UI_CENTER; + if( !UI_CanShowTierVideo( 2 ) ) { + cinematicsMenuInfo.cin_tier2.generic.flags |= QMF_GRAYED; + } + + y += VERTICAL_SPACING; + cinematicsMenuInfo.cin_tier3.generic.type = MTYPE_PTEXT; + cinematicsMenuInfo.cin_tier3.generic.flags = QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS; + cinematicsMenuInfo.cin_tier3.generic.x = 320; + cinematicsMenuInfo.cin_tier3.generic.y = y; + cinematicsMenuInfo.cin_tier3.generic.id = ID_CIN_TIER3; + cinematicsMenuInfo.cin_tier3.generic.callback = UI_CinematicsMenu_Event; + cinematicsMenuInfo.cin_tier3.string = "Tier 3"; + cinematicsMenuInfo.cin_tier3.color = color_red; + cinematicsMenuInfo.cin_tier3.style = UI_CENTER; + if( !UI_CanShowTierVideo( 3 ) ) { + cinematicsMenuInfo.cin_tier3.generic.flags |= QMF_GRAYED; + } + + y += VERTICAL_SPACING; + cinematicsMenuInfo.cin_tier4.generic.type = MTYPE_PTEXT; + cinematicsMenuInfo.cin_tier4.generic.flags = QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS; + cinematicsMenuInfo.cin_tier4.generic.x = 320; + cinematicsMenuInfo.cin_tier4.generic.y = y; + cinematicsMenuInfo.cin_tier4.generic.id = ID_CIN_TIER4; + cinematicsMenuInfo.cin_tier4.generic.callback = UI_CinematicsMenu_Event; + cinematicsMenuInfo.cin_tier4.string = "Tier 4"; + cinematicsMenuInfo.cin_tier4.color = color_red; + cinematicsMenuInfo.cin_tier4.style = UI_CENTER; + if( !UI_CanShowTierVideo( 4 ) ) { + cinematicsMenuInfo.cin_tier4.generic.flags |= QMF_GRAYED; + } + + y += VERTICAL_SPACING; + cinematicsMenuInfo.cin_tier5.generic.type = MTYPE_PTEXT; + cinematicsMenuInfo.cin_tier5.generic.flags = QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS; + cinematicsMenuInfo.cin_tier5.generic.x = 320; + cinematicsMenuInfo.cin_tier5.generic.y = y; + cinematicsMenuInfo.cin_tier5.generic.id = ID_CIN_TIER5; + cinematicsMenuInfo.cin_tier5.generic.callback = UI_CinematicsMenu_Event; + cinematicsMenuInfo.cin_tier5.string = "Tier 5"; + cinematicsMenuInfo.cin_tier5.color = color_red; + cinematicsMenuInfo.cin_tier5.style = UI_CENTER; + if( !UI_CanShowTierVideo( 5 ) ) { + cinematicsMenuInfo.cin_tier5.generic.flags |= QMF_GRAYED; + } + + y += VERTICAL_SPACING; + cinematicsMenuInfo.cin_tier6.generic.type = MTYPE_PTEXT; + cinematicsMenuInfo.cin_tier6.generic.flags = QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS; + cinematicsMenuInfo.cin_tier6.generic.x = 320; + cinematicsMenuInfo.cin_tier6.generic.y = y; + cinematicsMenuInfo.cin_tier6.generic.id = ID_CIN_TIER6; + cinematicsMenuInfo.cin_tier6.generic.callback = UI_CinematicsMenu_Event; + cinematicsMenuInfo.cin_tier6.string = "Tier 6"; + cinematicsMenuInfo.cin_tier6.color = color_red; + cinematicsMenuInfo.cin_tier6.style = UI_CENTER; + if( !UI_CanShowTierVideo( 6 ) ) { + cinematicsMenuInfo.cin_tier6.generic.flags |= QMF_GRAYED; + } + + y += VERTICAL_SPACING; + cinematicsMenuInfo.cin_tier7.generic.type = MTYPE_PTEXT; + cinematicsMenuInfo.cin_tier7.generic.flags = QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS; + cinematicsMenuInfo.cin_tier7.generic.x = 320; + cinematicsMenuInfo.cin_tier7.generic.y = y; + cinematicsMenuInfo.cin_tier7.generic.id = ID_CIN_TIER7; + cinematicsMenuInfo.cin_tier7.generic.callback = UI_CinematicsMenu_Event; + cinematicsMenuInfo.cin_tier7.string = "Tier 7"; + cinematicsMenuInfo.cin_tier7.color = color_red; + cinematicsMenuInfo.cin_tier7.style = UI_CENTER; + if( !UI_CanShowTierVideo( 7 ) ) { + cinematicsMenuInfo.cin_tier7.generic.flags |= QMF_GRAYED; + } + + y += VERTICAL_SPACING; + cinematicsMenuInfo.cin_end.generic.type = MTYPE_PTEXT; + cinematicsMenuInfo.cin_end.generic.flags = QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS; + cinematicsMenuInfo.cin_end.generic.x = 320; + cinematicsMenuInfo.cin_end.generic.y = y; + cinematicsMenuInfo.cin_end.generic.id = ID_CIN_END; + cinematicsMenuInfo.cin_end.generic.callback = UI_CinematicsMenu_Event; + cinematicsMenuInfo.cin_end.string = "END"; + cinematicsMenuInfo.cin_end.color = color_red; + cinematicsMenuInfo.cin_end.style = UI_CENTER; + if( !UI_CanShowTierVideo( 8 ) ) { + cinematicsMenuInfo.cin_end.generic.flags |= QMF_GRAYED; + } + + cinematicsMenuInfo.back.generic.type = MTYPE_BITMAP; + cinematicsMenuInfo.back.generic.name = ART_BACK0; + cinematicsMenuInfo.back.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS; + cinematicsMenuInfo.back.generic.id = ID_BACK; + cinematicsMenuInfo.back.generic.callback = UI_CinematicsMenu_BackEvent; + cinematicsMenuInfo.back.generic.x = 0; + cinematicsMenuInfo.back.generic.y = 480-64; + cinematicsMenuInfo.back.width = 128; + cinematicsMenuInfo.back.height = 64; + cinematicsMenuInfo.back.focuspic = ART_BACK1; + + Menu_AddItem( &cinematicsMenuInfo.menu, &cinematicsMenuInfo.banner ); + Menu_AddItem( &cinematicsMenuInfo.menu, &cinematicsMenuInfo.framel ); + Menu_AddItem( &cinematicsMenuInfo.menu, &cinematicsMenuInfo.framer ); + Menu_AddItem( &cinematicsMenuInfo.menu, &cinematicsMenuInfo.cin_idlogo ); + Menu_AddItem( &cinematicsMenuInfo.menu, &cinematicsMenuInfo.cin_intro ); + Menu_AddItem( &cinematicsMenuInfo.menu, &cinematicsMenuInfo.cin_tier1 ); + Menu_AddItem( &cinematicsMenuInfo.menu, &cinematicsMenuInfo.cin_tier2 ); + Menu_AddItem( &cinematicsMenuInfo.menu, &cinematicsMenuInfo.cin_tier3 ); + Menu_AddItem( &cinematicsMenuInfo.menu, &cinematicsMenuInfo.cin_tier4 ); + Menu_AddItem( &cinematicsMenuInfo.menu, &cinematicsMenuInfo.cin_tier5 ); + Menu_AddItem( &cinematicsMenuInfo.menu, &cinematicsMenuInfo.cin_tier6 ); + Menu_AddItem( &cinematicsMenuInfo.menu, &cinematicsMenuInfo.cin_tier7 ); + Menu_AddItem( &cinematicsMenuInfo.menu, &cinematicsMenuInfo.cin_end ); + Menu_AddItem( &cinematicsMenuInfo.menu, &cinematicsMenuInfo.back ); +} + + +/* +================= +UI_CinematicsMenu_Cache +================= +*/ +void UI_CinematicsMenu_Cache( void ) { + trap_R_RegisterShaderNoMip( ART_BACK0 ); + trap_R_RegisterShaderNoMip( ART_BACK1 ); + trap_R_RegisterShaderNoMip( ART_FRAMEL ); + trap_R_RegisterShaderNoMip( ART_FRAMER ); +} + + +/* +=============== +UI_CinematicsMenu +=============== +*/ +void UI_CinematicsMenu( void ) { + UI_CinematicsMenu_Init(); + UI_PushMenu( &cinematicsMenuInfo.menu ); +} + + +/* +=============== +UI_CinematicsMenu_f +=============== +*/ +void UI_CinematicsMenu_f( void ) { + int n; + + n = atoi( UI_Argv( 1 ) ); + UI_CinematicsMenu(); + Menu_SetCursorToItem( &cinematicsMenuInfo.menu, cinematicsMenuInfo.menu.items[n + 3] ); +} diff --git a/code/q3_ui/ui_confirm.c b/code/q3_ui/ui_confirm.c new file mode 100755 index 0000000..c58071b --- /dev/null +++ b/code/q3_ui/ui_confirm.c @@ -0,0 +1,293 @@ +/* +=========================================================================== +Copyright (C) 1999-2005 Id Software, Inc. + +This file is part of Quake III Arena source code. + +Quake III Arena source code is free software; you can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 2 of the License, +or (at your option) any later version. + +Quake III Arena source code is distributed in the hope that it will be +useful, but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Foobar; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ +// +/* +======================================================================= + +CONFIRMATION MENU + +======================================================================= +*/ + + +#include "ui_local.h" + + +#define ART_CONFIRM_FRAME "menu/art/cut_frame" + +#define ID_CONFIRM_NO 10 +#define ID_CONFIRM_YES 11 + + +typedef struct { + menuframework_s menu; + + menutext_s no; + menutext_s yes; + + int slashX; + const char * question; + void (*draw)( void ); + void (*action)( qboolean result ); + + int style; + const char **lines; +} confirmMenu_t; + + +static confirmMenu_t s_confirm; + + +/* +================= +ConfirmMenu_Event +================= +*/ +static void ConfirmMenu_Event( void* ptr, int event ) { + qboolean result; + + if( event != QM_ACTIVATED ) { + return; + } + + UI_PopMenu(); + + if( ((menucommon_s*)ptr)->id == ID_CONFIRM_NO ) { + result = qfalse; + } + else { + result = qtrue; + } + + if( s_confirm.action ) { + s_confirm.action( result ); + } +} + + +/* +================= +ConfirmMenu_Key +================= +*/ +static sfxHandle_t ConfirmMenu_Key( int key ) { + switch ( key ) { + case K_KP_LEFTARROW: + case K_LEFTARROW: + case K_KP_RIGHTARROW: + case K_RIGHTARROW: + key = K_TAB; + break; + + case 'n': + case 'N': + ConfirmMenu_Event( &s_confirm.no, QM_ACTIVATED ); + break; + + case 'y': + case 'Y': + ConfirmMenu_Event( &s_confirm.yes, QM_ACTIVATED ); + break; + } + + return Menu_DefaultKey( &s_confirm.menu, key ); +} + + +/* +================= +MessaheMenu_Draw +================= +*/ +static void MessageMenu_Draw( void ) { + int i,y; + + UI_DrawNamedPic( 142, 118, 359, 256, ART_CONFIRM_FRAME ); + + y = 188; + for(i=0; s_confirm.lines[i]; i++) + { + UI_DrawProportionalString( 320, y, s_confirm.lines[i], s_confirm.style, color_red ); + y += 18; + } + + Menu_Draw( &s_confirm.menu ); + + if( s_confirm.draw ) { + s_confirm.draw(); + } +} + +/* +================= +ConfirmMenu_Draw +================= +*/ +static void ConfirmMenu_Draw( void ) { + UI_DrawNamedPic( 142, 118, 359, 256, ART_CONFIRM_FRAME ); + UI_DrawProportionalString( 320, 204, s_confirm.question, s_confirm.style, color_red ); + UI_DrawProportionalString( s_confirm.slashX, 265, "/", UI_LEFT|UI_INVERSE, color_red ); + + Menu_Draw( &s_confirm.menu ); + + if( s_confirm.draw ) { + s_confirm.draw(); + } +} + + +/* +================= +ConfirmMenu_Cache +================= +*/ +void ConfirmMenu_Cache( void ) { + trap_R_RegisterShaderNoMip( ART_CONFIRM_FRAME ); +} + + +/* +================= +UI_ConfirmMenu_Stlye +================= +*/ +void UI_ConfirmMenu_Style( const char *question, int style, void (*draw)( void ), void (*action)( qboolean result ) ) { + uiClientState_t cstate; + int n1, n2, n3; + int l1, l2, l3; + + // zero set all our globals + memset( &s_confirm, 0, sizeof(s_confirm) ); + + ConfirmMenu_Cache(); + + n1 = UI_ProportionalStringWidth( "YES/NO" ); + n2 = UI_ProportionalStringWidth( "YES" ) + PROP_GAP_WIDTH; + n3 = UI_ProportionalStringWidth( "/" ) + PROP_GAP_WIDTH; + l1 = 320 - ( n1 / 2 ); + l2 = l1 + n2; + l3 = l2 + n3; + s_confirm.slashX = l2; + + s_confirm.question = question; + s_confirm.draw = draw; + s_confirm.action = action; + s_confirm.style = style; + + s_confirm.menu.draw = ConfirmMenu_Draw; + s_confirm.menu.key = ConfirmMenu_Key; + s_confirm.menu.wrapAround = qtrue; + + trap_GetClientState( &cstate ); + if ( cstate.connState >= CA_CONNECTED ) { + s_confirm.menu.fullscreen = qfalse; + } + else { + s_confirm.menu.fullscreen = qtrue; + } + + s_confirm.yes.generic.type = MTYPE_PTEXT; + s_confirm.yes.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS; + s_confirm.yes.generic.callback = ConfirmMenu_Event; + s_confirm.yes.generic.id = ID_CONFIRM_YES; + s_confirm.yes.generic.x = l1; + s_confirm.yes.generic.y = 264; + s_confirm.yes.string = "YES"; + s_confirm.yes.color = color_red; + s_confirm.yes.style = UI_LEFT; + + s_confirm.no.generic.type = MTYPE_PTEXT; + s_confirm.no.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS; + s_confirm.no.generic.callback = ConfirmMenu_Event; + s_confirm.no.generic.id = ID_CONFIRM_NO; + s_confirm.no.generic.x = l3; + s_confirm.no.generic.y = 264; + s_confirm.no.string = "NO"; + s_confirm.no.color = color_red; + s_confirm.no.style = UI_LEFT; + + Menu_AddItem( &s_confirm.menu, &s_confirm.yes ); + Menu_AddItem( &s_confirm.menu, &s_confirm.no ); + + UI_PushMenu( &s_confirm.menu ); + + Menu_SetCursorToItem( &s_confirm.menu, &s_confirm.no ); +} + +/* +================= +UI_ConfirmMenu +================= +*/ +void UI_ConfirmMenu( const char *question, void (*draw)( void ), void (*action)( qboolean result ) ) { + UI_ConfirmMenu_Style(question, UI_CENTER|UI_INVERSE, draw, action); +} + +/* +================= +UI_Message +hacked over from Confirm stuff +================= +*/ +void UI_Message( const char **lines ) { + uiClientState_t cstate; + int n1, l1; + + // zero set all our globals + memset( &s_confirm, 0, sizeof(s_confirm) ); + + ConfirmMenu_Cache(); + + n1 = UI_ProportionalStringWidth( "OK" ); + l1 = 320 - ( n1 / 2 ); + + s_confirm.lines = lines; + s_confirm.style = UI_CENTER|UI_INVERSE|UI_SMALLFONT; + + s_confirm.menu.draw = MessageMenu_Draw; + s_confirm.menu.key = ConfirmMenu_Key; + s_confirm.menu.wrapAround = qtrue; + + trap_GetClientState( &cstate ); + if ( cstate.connState >= CA_CONNECTED ) { + s_confirm.menu.fullscreen = qfalse; + } + else { + s_confirm.menu.fullscreen = qtrue; + } + + s_confirm.yes.generic.type = MTYPE_PTEXT; + s_confirm.yes.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS; + s_confirm.yes.generic.callback = ConfirmMenu_Event; + s_confirm.yes.generic.id = ID_CONFIRM_YES; + s_confirm.yes.generic.x = l1; + s_confirm.yes.generic.y = 280; + s_confirm.yes.string = "OK"; + s_confirm.yes.color = color_red; + s_confirm.yes.style = UI_LEFT; + + Menu_AddItem( &s_confirm.menu, &s_confirm.yes ); + + UI_PushMenu( &s_confirm.menu ); + + Menu_SetCursorToItem( &s_confirm.menu, &s_confirm.yes ); +} diff --git a/code/q3_ui/ui_connect.c b/code/q3_ui/ui_connect.c new file mode 100755 index 0000000..a348db2 --- /dev/null +++ b/code/q3_ui/ui_connect.c @@ -0,0 +1,282 @@ +/* +=========================================================================== +Copyright (C) 1999-2005 Id Software, Inc. + +This file is part of Quake III Arena source code. + +Quake III Arena source code is free software; you can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 2 of the License, +or (at your option) any later version. + +Quake III Arena source code is distributed in the hope that it will be +useful, but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Foobar; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ +// +#include "ui_local.h" + +/* +=============================================================================== + +CONNECTION SCREEN + +=============================================================================== +*/ + +qboolean passwordNeeded = qtrue; +menufield_s passwordField; + +static connstate_t lastConnState; +static char lastLoadingText[MAX_INFO_VALUE]; + +static void UI_ReadableSize ( char *buf, int bufsize, int value ) +{ + if (value > 1024*1024*1024 ) { // gigs + Com_sprintf( buf, bufsize, "%d", value / (1024*1024*1024) ); + Com_sprintf( buf+strlen(buf), bufsize-strlen(buf), ".%02d GB", + (value % (1024*1024*1024))*100 / (1024*1024*1024) ); + } else if (value > 1024*1024 ) { // megs + Com_sprintf( buf, bufsize, "%d", value / (1024*1024) ); + Com_sprintf( buf+strlen(buf), bufsize-strlen(buf), ".%02d MB", + (value % (1024*1024))*100 / (1024*1024) ); + } else if (value > 1024 ) { // kilos + Com_sprintf( buf, bufsize, "%d KB", value / 1024 ); + } else { // bytes + Com_sprintf( buf, bufsize, "%d bytes", value ); + } +} + +// Assumes time is in msec +static void UI_PrintTime ( char *buf, int bufsize, int time ) { + time /= 1000; // change to seconds + + if (time > 3600) { // in the hours range + Com_sprintf( buf, bufsize, "%d hr %d min", time / 3600, (time % 3600) / 60 ); + } else if (time > 60) { // mins + Com_sprintf( buf, bufsize, "%d min %d sec", time / 60, time % 60 ); + } else { // secs + Com_sprintf( buf, bufsize, "%d sec", time ); + } +} + +static void UI_DisplayDownloadInfo( const char *downloadName ) { + static char dlText[] = "Downloading:"; + static char etaText[] = "Estimated time left:"; + static char xferText[] = "Transfer rate:"; + + int downloadSize, downloadCount, downloadTime; + char dlSizeBuf[64], totalSizeBuf[64], xferRateBuf[64], dlTimeBuf[64]; + int xferRate; + int width, leftWidth; + int style = UI_LEFT|UI_SMALLFONT|UI_DROPSHADOW; + const char *s; + + downloadSize = trap_Cvar_VariableValue( "cl_downloadSize" ); + downloadCount = trap_Cvar_VariableValue( "cl_downloadCount" ); + downloadTime = trap_Cvar_VariableValue( "cl_downloadTime" ); + +#if 0 // bk010104 + fprintf( stderr, "\n\n-----------------------------------------------\n"); + fprintf( stderr, "DB: downloadSize: %16d\n", downloadSize ); + fprintf( stderr, "DB: downloadCount: %16d\n", downloadCount ); + fprintf( stderr, "DB: downloadTime: %16d\n", downloadTime ); + fprintf( stderr, "DB: UI realtime: %16d\n", uis.realtime ); // bk + fprintf( stderr, "DB: UI frametime: %16d\n", uis.frametime ); // bk +#endif + + leftWidth = width = UI_ProportionalStringWidth( dlText ) * UI_ProportionalSizeScale( style ); + width = UI_ProportionalStringWidth( etaText ) * UI_ProportionalSizeScale( style ); + if (width > leftWidth) leftWidth = width; + width = UI_ProportionalStringWidth( xferText ) * UI_ProportionalSizeScale( style ); + if (width > leftWidth) leftWidth = width; + leftWidth += 16; + + UI_DrawProportionalString( 8, 128, dlText, style, color_white ); + UI_DrawProportionalString( 8, 160, etaText, style, color_white ); + UI_DrawProportionalString( 8, 224, xferText, style, color_white ); + + if (downloadSize > 0) { + s = va( "%s (%d%%)", downloadName, downloadCount * 100 / downloadSize ); + } else { + s = downloadName; + } + + UI_DrawProportionalString( leftWidth, 128, s, style, color_white ); + + UI_ReadableSize( dlSizeBuf, sizeof dlSizeBuf, downloadCount ); + UI_ReadableSize( totalSizeBuf, sizeof totalSizeBuf, downloadSize ); + + if (downloadCount < 4096 || !downloadTime) { + UI_DrawProportionalString( leftWidth, 160, "estimating", style, color_white ); + UI_DrawProportionalString( leftWidth, 192, + va("(%s of %s copied)", dlSizeBuf, totalSizeBuf), style, color_white ); + } else { + // bk010108 + //float elapsedTime = (float)(uis.realtime - downloadTime); // current - start (msecs) + //elapsedTime = elapsedTime * 0.001f; // in seconds + //if ( elapsedTime <= 0.0f ) elapsedTime == 0.0f; + if ( (uis.realtime - downloadTime) / 1000) { + xferRate = downloadCount / ((uis.realtime - downloadTime) / 1000); + //xferRate = (int)( ((float)downloadCount) / elapsedTime); + } else { + xferRate = 0; + } + + //fprintf( stderr, "DB: elapsedTime: %16.8f\n", elapsedTime ); // bk + //fprintf( stderr, "DB: xferRate: %16d\n", xferRate ); // bk + + UI_ReadableSize( xferRateBuf, sizeof xferRateBuf, xferRate ); + + // Extrapolate estimated completion time + if (downloadSize && xferRate) { + int n = downloadSize / xferRate; // estimated time for entire d/l in secs + + // We do it in K (/1024) because we'd overflow around 4MB + n = (n - (((downloadCount/1024) * n) / (downloadSize/1024))) * 1000; + + UI_PrintTime ( dlTimeBuf, sizeof dlTimeBuf, n ); // bk010104 + //(n - (((downloadCount/1024) * n) / (downloadSize/1024))) * 1000); + + UI_DrawProportionalString( leftWidth, 160, + dlTimeBuf, style, color_white ); + UI_DrawProportionalString( leftWidth, 192, + va("(%s of %s copied)", dlSizeBuf, totalSizeBuf), style, color_white ); + } else { + UI_DrawProportionalString( leftWidth, 160, + "estimating", style, color_white ); + if (downloadSize) { + UI_DrawProportionalString( leftWidth, 192, + va("(%s of %s copied)", dlSizeBuf, totalSizeBuf), style, color_white ); + } else { + UI_DrawProportionalString( leftWidth, 192, + va("(%s copied)", dlSizeBuf), style, color_white ); + } + } + + if (xferRate) { + UI_DrawProportionalString( leftWidth, 224, + va("%s/Sec", xferRateBuf), style, color_white ); + } + } +} + +/* +======================== +UI_DrawConnectScreen + +This will also be overlaid on the cgame info screen during loading +to prevent it from blinking away too rapidly on local or lan games. +======================== +*/ +void UI_DrawConnectScreen( qboolean overlay ) { + char *s; + uiClientState_t cstate; + char info[MAX_INFO_VALUE]; + + Menu_Cache(); + + if ( !overlay ) { + // draw the dialog background + UI_SetColor( color_white ); + UI_DrawHandlePic( 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, uis.menuBackShader ); + } + + // see what information we should display + trap_GetClientState( &cstate ); + + info[0] = '\0'; + if( trap_GetConfigString( CS_SERVERINFO, info, sizeof(info) ) ) { + UI_DrawProportionalString( 320, 16, va( "Loading %s", Info_ValueForKey( info, "mapname" ) ), UI_BIGFONT|UI_CENTER|UI_DROPSHADOW, color_white ); + } + + UI_DrawProportionalString( 320, 64, va("Connecting to %s", cstate.servername), UI_CENTER|UI_SMALLFONT|UI_DROPSHADOW, menu_text_color ); + //UI_DrawProportionalString( 320, 96, "Press Esc to abort", UI_CENTER|UI_SMALLFONT|UI_DROPSHADOW, menu_text_color ); + + // display global MOTD at bottom + UI_DrawProportionalString( SCREEN_WIDTH/2, SCREEN_HEIGHT-32, + Info_ValueForKey( cstate.updateInfoString, "motd" ), UI_CENTER|UI_SMALLFONT|UI_DROPSHADOW, menu_text_color ); + + // print any server info (server full, bad version, etc) + if ( cstate.connState < CA_CONNECTED ) { + UI_DrawProportionalString_AutoWrapped( 320, 192, 630, 20, cstate.messageString, UI_CENTER|UI_SMALLFONT|UI_DROPSHADOW, menu_text_color ); + } + +#if 0 + // display password field + if ( passwordNeeded ) { + s_ingame_menu.x = SCREEN_WIDTH * 0.50 - 128; + s_ingame_menu.nitems = 0; + s_ingame_menu.wrapAround = qtrue; + + passwordField.generic.type = MTYPE_FIELD; + passwordField.generic.name = "Password:"; + passwordField.generic.callback = 0; + passwordField.generic.x = 10; + passwordField.generic.y = 180; + Field_Clear( &passwordField.field ); + passwordField.width = 256; + passwordField.field.widthInChars = 16; + Q_strncpyz( passwordField.field.buffer, Cvar_VariableString("password"), + sizeof(passwordField.field.buffer) ); + + Menu_AddItem( &s_ingame_menu, ( void * ) &s_customize_player_action ); + + MField_Draw( &passwordField ); + } +#endif + + if ( lastConnState > cstate.connState ) { + lastLoadingText[0] = '\0'; + } + lastConnState = cstate.connState; + + switch ( cstate.connState ) { + case CA_CONNECTING: + s = va("Awaiting challenge...%i", cstate.connectPacketCount); + break; + case CA_CHALLENGING: + s = va("Awaiting connection...%i", cstate.connectPacketCount); + break; + case CA_CONNECTED: { + char downloadName[MAX_INFO_VALUE]; + + trap_Cvar_VariableStringBuffer( "cl_downloadName", downloadName, sizeof(downloadName) ); + if (*downloadName) { + UI_DisplayDownloadInfo( downloadName ); + return; + } + } + s = "Awaiting gamestate..."; + break; + case CA_LOADING: + return; + case CA_PRIMED: + return; + default: + return; + } + + UI_DrawProportionalString( 320, 128, s, UI_CENTER|UI_SMALLFONT|UI_DROPSHADOW, color_white ); + + // password required / connection rejected information goes here +} + + +/* +=================== +UI_KeyConnect +=================== +*/ +void UI_KeyConnect( int key ) { + if ( key == K_ESCAPE ) { + trap_Cmd_ExecuteText( EXEC_APPEND, "disconnect\n" ); + return; + } +} diff --git a/code/q3_ui/ui_controls2.c b/code/q3_ui/ui_controls2.c new file mode 100755 index 0000000..f6dc59f --- /dev/null +++ b/code/q3_ui/ui_controls2.c @@ -0,0 +1,1667 @@ +/* +=========================================================================== +Copyright (C) 1999-2005 Id Software, Inc. + +This file is part of Quake III Arena source code. + +Quake III Arena source code is free software; you can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 2 of the License, +or (at your option) any later version. + +Quake III Arena source code is distributed in the hope that it will be +useful, but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Foobar; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ +// +/* +======================================================================= + +CONTROLS MENU + +======================================================================= +*/ + + +#include "ui_local.h" + +#define ART_BACK0 "menu/art/back_0" +#define ART_BACK1 "menu/art/back_1" +#define ART_FRAMEL "menu/art/frame2_l" +#define ART_FRAMER "menu/art/frame1_r" + + +typedef struct { + char *command; + char *label; + int id; + int anim; + int defaultbind1; + int defaultbind2; + int bind1; + int bind2; +} bind_t; + +typedef struct +{ + char* name; + float defaultvalue; + float value; +} configcvar_t; + +#define SAVE_NOOP 0 +#define SAVE_YES 1 +#define SAVE_NO 2 +#define SAVE_CANCEL 3 + +// control sections +#define C_MOVEMENT 0 +#define C_LOOKING 1 +#define C_WEAPONS 2 +#define C_MISC 3 +#define C_MAX 4 + +#define ID_MOVEMENT 100 +#define ID_LOOKING 101 +#define ID_WEAPONS 102 +#define ID_MISC 103 +#define ID_DEFAULTS 104 +#define ID_BACK 105 +#define ID_SAVEANDEXIT 106 +#define ID_EXIT 107 + +// bindable actions +#define ID_SHOWSCORES 0 +#define ID_USEITEM 1 +#define ID_SPEED 2 +#define ID_FORWARD 3 +#define ID_BACKPEDAL 4 +#define ID_MOVELEFT 5 +#define ID_MOVERIGHT 6 +#define ID_MOVEUP 7 +#define ID_MOVEDOWN 8 +#define ID_LEFT 9 +#define ID_RIGHT 10 +#define ID_STRAFE 11 +#define ID_LOOKUP 12 +#define ID_LOOKDOWN 13 +#define ID_MOUSELOOK 14 +#define ID_CENTERVIEW 15 +#define ID_ZOOMVIEW 16 +#define ID_WEAPON1 17 +#define ID_WEAPON2 18 +#define ID_WEAPON3 19 +#define ID_WEAPON4 20 +#define ID_WEAPON5 21 +#define ID_WEAPON6 22 +#define ID_WEAPON7 23 +#define ID_WEAPON8 24 +#define ID_WEAPON9 25 +#define ID_ATTACK 26 +#define ID_WEAPPREV 27 +#define ID_WEAPNEXT 28 +#define ID_GESTURE 29 +#define ID_CHAT 30 +#define ID_CHAT2 31 +#define ID_CHAT3 32 +#define ID_CHAT4 33 + +// all others +#define ID_FREELOOK 34 +#define ID_INVERTMOUSE 35 +#define ID_ALWAYSRUN 36 +#define ID_AUTOSWITCH 37 +#define ID_MOUSESPEED 38 +#define ID_JOYENABLE 39 +#define ID_JOYTHRESHOLD 40 +#define ID_SMOOTHMOUSE 41 + +#define ANIM_IDLE 0 +#define ANIM_RUN 1 +#define ANIM_WALK 2 +#define ANIM_BACK 3 +#define ANIM_JUMP 4 +#define ANIM_CROUCH 5 +#define ANIM_STEPLEFT 6 +#define ANIM_STEPRIGHT 7 +#define ANIM_TURNLEFT 8 +#define ANIM_TURNRIGHT 9 +#define ANIM_LOOKUP 10 +#define ANIM_LOOKDOWN 11 +#define ANIM_WEAPON1 12 +#define ANIM_WEAPON2 13 +#define ANIM_WEAPON3 14 +#define ANIM_WEAPON4 15 +#define ANIM_WEAPON5 16 +#define ANIM_WEAPON6 17 +#define ANIM_WEAPON7 18 +#define ANIM_WEAPON8 19 +#define ANIM_WEAPON9 20 +#define ANIM_WEAPON10 21 +#define ANIM_ATTACK 22 +#define ANIM_GESTURE 23 +#define ANIM_DIE 24 +#define ANIM_CHAT 25 + +typedef struct +{ + menuframework_s menu; + + menutext_s banner; + menubitmap_s framel; + menubitmap_s framer; + menubitmap_s player; + + menutext_s movement; + menutext_s looking; + menutext_s weapons; + menutext_s misc; + + menuaction_s walkforward; + menuaction_s backpedal; + menuaction_s stepleft; + menuaction_s stepright; + menuaction_s moveup; + menuaction_s movedown; + menuaction_s turnleft; + menuaction_s turnright; + menuaction_s sidestep; + menuaction_s run; + menuaction_s machinegun; + menuaction_s chainsaw; + menuaction_s shotgun; + menuaction_s grenadelauncher; + menuaction_s rocketlauncher; + menuaction_s lightning; + menuaction_s railgun; + menuaction_s plasma; + menuaction_s bfg; + menuaction_s attack; + menuaction_s prevweapon; + menuaction_s nextweapon; + menuaction_s lookup; + menuaction_s lookdown; + menuaction_s mouselook; + menuradiobutton_s freelook; + menuaction_s centerview; + menuaction_s zoomview; + menuaction_s gesture; + menuradiobutton_s invertmouse; + menuslider_s sensitivity; + menuradiobutton_s smoothmouse; + menuradiobutton_s alwaysrun; + menuaction_s showscores; + menuradiobutton_s autoswitch; + menuaction_s useitem; + playerInfo_t playerinfo; + qboolean changesmade; + menuaction_s chat; + menuaction_s chat2; + menuaction_s chat3; + menuaction_s chat4; + menuradiobutton_s joyenable; + menuslider_s joythreshold; + int section; + qboolean waitingforkey; + char playerModel[64]; + vec3_t playerViewangles; + vec3_t playerMoveangles; + int playerLegs; + int playerTorso; + int playerWeapon; + qboolean playerChat; + + menubitmap_s back; + menutext_s name; +} controls_t; + +static controls_t s_controls; + +static vec4_t controls_binding_color = {1.00f, 0.43f, 0.00f, 1.00f}; // bk: Win32 C4305 + +static bind_t g_bindings[] = +{ + {"+scores", "show scores", ID_SHOWSCORES, ANIM_IDLE, K_TAB, -1, -1, -1}, + {"+button2", "use item", ID_USEITEM, ANIM_IDLE, K_ENTER, -1, -1, -1}, + {"+speed", "run / walk", ID_SPEED, ANIM_RUN, K_SHIFT, -1, -1, -1}, + {"+forward", "walk forward", ID_FORWARD, ANIM_WALK, K_UPARROW, -1, -1, -1}, + {"+back", "backpedal", ID_BACKPEDAL, ANIM_BACK, K_DOWNARROW, -1, -1, -1}, + {"+moveleft", "step left", ID_MOVELEFT, ANIM_STEPLEFT, ',', -1, -1, -1}, + {"+moveright", "step right", ID_MOVERIGHT, ANIM_STEPRIGHT, '.', -1, -1, -1}, + {"+moveup", "up / jump", ID_MOVEUP, ANIM_JUMP, K_SPACE, -1, -1, -1}, + {"+movedown", "down / crouch", ID_MOVEDOWN, ANIM_CROUCH, 'c', -1, -1, -1}, + {"+left", "turn left", ID_LEFT, ANIM_TURNLEFT, K_LEFTARROW, -1, -1, -1}, + {"+right", "turn right", ID_RIGHT, ANIM_TURNRIGHT, K_RIGHTARROW, -1, -1, -1}, + {"+strafe", "sidestep / turn", ID_STRAFE, ANIM_IDLE, K_ALT, -1, -1, -1}, + {"+lookup", "look up", ID_LOOKUP, ANIM_LOOKUP, K_PGDN, -1, -1, -1}, + {"+lookdown", "look down", ID_LOOKDOWN, ANIM_LOOKDOWN, K_DEL, -1, -1, -1}, + {"+mlook", "mouse look", ID_MOUSELOOK, ANIM_IDLE, '/', -1, -1, -1}, + {"centerview", "center view", ID_CENTERVIEW, ANIM_IDLE, K_END, -1, -1, -1}, + {"+zoom", "zoom view", ID_ZOOMVIEW, ANIM_IDLE, -1, -1, -1, -1}, + {"weapon 1", "gauntlet", ID_WEAPON1, ANIM_WEAPON1, '1', -1, -1, -1}, + {"weapon 2", "machinegun", ID_WEAPON2, ANIM_WEAPON2, '2', -1, -1, -1}, + {"weapon 3", "shotgun", ID_WEAPON3, ANIM_WEAPON3, '3', -1, -1, -1}, + {"weapon 4", "grenade launcher", ID_WEAPON4, ANIM_WEAPON4, '4', -1, -1, -1}, + {"weapon 5", "rocket launcher", ID_WEAPON5, ANIM_WEAPON5, '5', -1, -1, -1}, + {"weapon 6", "lightning", ID_WEAPON6, ANIM_WEAPON6, '6', -1, -1, -1}, + {"weapon 7", "railgun", ID_WEAPON7, ANIM_WEAPON7, '7', -1, -1, -1}, + {"weapon 8", "plasma gun", ID_WEAPON8, ANIM_WEAPON8, '8', -1, -1, -1}, + {"weapon 9", "BFG", ID_WEAPON9, ANIM_WEAPON9, '9', -1, -1, -1}, + {"+attack", "attack", ID_ATTACK, ANIM_ATTACK, K_CTRL, -1, -1, -1}, + {"weapprev", "prev weapon", ID_WEAPPREV, ANIM_IDLE, '[', -1, -1, -1}, + {"weapnext", "next weapon", ID_WEAPNEXT, ANIM_IDLE, ']', -1, -1, -1}, + {"+button3", "gesture", ID_GESTURE, ANIM_GESTURE, K_MOUSE3, -1, -1, -1}, + {"messagemode", "chat", ID_CHAT, ANIM_CHAT, 't', -1, -1, -1}, + {"messagemode2", "chat - team", ID_CHAT2, ANIM_CHAT, -1, -1, -1, -1}, + {"messagemode3", "chat - target", ID_CHAT3, ANIM_CHAT, -1, -1, -1, -1}, + {"messagemode4", "chat - attacker", ID_CHAT4, ANIM_CHAT, -1, -1, -1, -1}, + {(char*)NULL, (char*)NULL, 0, 0, -1, -1, -1, -1}, +}; + +static configcvar_t g_configcvars[] = +{ + {"cl_run", 0, 0}, + {"m_pitch", 0, 0}, + {"cg_autoswitch", 0, 0}, + {"sensitivity", 0, 0}, + {"in_joystick", 0, 0}, + {"joy_threshold", 0, 0}, + {"m_filter", 0, 0}, + {"cl_freelook", 0, 0}, + {NULL, 0, 0} +}; + +static menucommon_s *g_movement_controls[] = +{ + (menucommon_s *)&s_controls.alwaysrun, + (menucommon_s *)&s_controls.run, + (menucommon_s *)&s_controls.walkforward, + (menucommon_s *)&s_controls.backpedal, + (menucommon_s *)&s_controls.stepleft, + (menucommon_s *)&s_controls.stepright, + (menucommon_s *)&s_controls.moveup, + (menucommon_s *)&s_controls.movedown, + (menucommon_s *)&s_controls.turnleft, + (menucommon_s *)&s_controls.turnright, + (menucommon_s *)&s_controls.sidestep, + NULL +}; + +static menucommon_s *g_weapons_controls[] = { + (menucommon_s *)&s_controls.attack, + (menucommon_s *)&s_controls.nextweapon, + (menucommon_s *)&s_controls.prevweapon, + (menucommon_s *)&s_controls.autoswitch, + (menucommon_s *)&s_controls.chainsaw, + (menucommon_s *)&s_controls.machinegun, + (menucommon_s *)&s_controls.shotgun, + (menucommon_s *)&s_controls.grenadelauncher, + (menucommon_s *)&s_controls.rocketlauncher, + (menucommon_s *)&s_controls.lightning, + (menucommon_s *)&s_controls.railgun, + (menucommon_s *)&s_controls.plasma, + (menucommon_s *)&s_controls.bfg, + NULL, +}; + +static menucommon_s *g_looking_controls[] = { + (menucommon_s *)&s_controls.sensitivity, + (menucommon_s *)&s_controls.smoothmouse, + (menucommon_s *)&s_controls.invertmouse, + (menucommon_s *)&s_controls.lookup, + (menucommon_s *)&s_controls.lookdown, + (menucommon_s *)&s_controls.mouselook, + (menucommon_s *)&s_controls.freelook, + (menucommon_s *)&s_controls.centerview, + (menucommon_s *)&s_controls.zoomview, + (menucommon_s *)&s_controls.joyenable, + (menucommon_s *)&s_controls.joythreshold, + NULL, +}; + +static menucommon_s *g_misc_controls[] = { + (menucommon_s *)&s_controls.showscores, + (menucommon_s *)&s_controls.useitem, + (menucommon_s *)&s_controls.gesture, + (menucommon_s *)&s_controls.chat, + (menucommon_s *)&s_controls.chat2, + (menucommon_s *)&s_controls.chat3, + (menucommon_s *)&s_controls.chat4, + NULL, +}; + +static menucommon_s **g_controls[] = { + g_movement_controls, + g_looking_controls, + g_weapons_controls, + g_misc_controls, +}; + +/* +================= +Controls_InitCvars +================= +*/ +static void Controls_InitCvars( void ) +{ + int i; + configcvar_t* cvarptr; + + cvarptr = g_configcvars; + for (i=0; ;i++,cvarptr++) + { + if (!cvarptr->name) + break; + + // get current value + cvarptr->value = trap_Cvar_VariableValue( cvarptr->name ); + + // get default value + trap_Cvar_Reset( cvarptr->name ); + cvarptr->defaultvalue = trap_Cvar_VariableValue( cvarptr->name ); + + // restore current value + trap_Cvar_SetValue( cvarptr->name, cvarptr->value ); + } +} + +/* +================= +Controls_GetCvarDefault +================= +*/ +static float Controls_GetCvarDefault( char* name ) +{ + configcvar_t* cvarptr; + int i; + + cvarptr = g_configcvars; + for (i=0; ;i++,cvarptr++) + { + if (!cvarptr->name) + return (0); + + if (!strcmp(cvarptr->name,name)) + break; + } + + return (cvarptr->defaultvalue); +} + +/* +================= +Controls_GetCvarValue +================= +*/ +static float Controls_GetCvarValue( char* name ) +{ + configcvar_t* cvarptr; + int i; + + cvarptr = g_configcvars; + for (i=0; ;i++,cvarptr++) + { + if (!cvarptr->name) + return (0); + + if (!strcmp(cvarptr->name,name)) + break; + } + + return (cvarptr->value); +} + + +/* +================= +Controls_UpdateModel +================= +*/ +static void Controls_UpdateModel( int anim ) { + VectorClear( s_controls.playerViewangles ); + VectorClear( s_controls.playerMoveangles ); + s_controls.playerViewangles[YAW] = 180 - 30; + s_controls.playerMoveangles[YAW] = s_controls.playerViewangles[YAW]; + s_controls.playerLegs = LEGS_IDLE; + s_controls.playerTorso = TORSO_STAND; + s_controls.playerWeapon = -1; + s_controls.playerChat = qfalse; + + switch( anim ) { + case ANIM_RUN: + s_controls.playerLegs = LEGS_RUN; + break; + + case ANIM_WALK: + s_controls.playerLegs = LEGS_WALK; + break; + + case ANIM_BACK: + s_controls.playerLegs = LEGS_BACK; + break; + + case ANIM_JUMP: + s_controls.playerLegs = LEGS_JUMP; + break; + + case ANIM_CROUCH: + s_controls.playerLegs = LEGS_IDLECR; + break; + + case ANIM_TURNLEFT: + s_controls.playerViewangles[YAW] += 90; + break; + + case ANIM_TURNRIGHT: + s_controls.playerViewangles[YAW] -= 90; + break; + + case ANIM_STEPLEFT: + s_controls.playerLegs = LEGS_WALK; + s_controls.playerMoveangles[YAW] = s_controls.playerViewangles[YAW] + 90; + break; + + case ANIM_STEPRIGHT: + s_controls.playerLegs = LEGS_WALK; + s_controls.playerMoveangles[YAW] = s_controls.playerViewangles[YAW] - 90; + break; + + case ANIM_LOOKUP: + s_controls.playerViewangles[PITCH] = -45; + break; + + case ANIM_LOOKDOWN: + s_controls.playerViewangles[PITCH] = 45; + break; + + case ANIM_WEAPON1: + s_controls.playerWeapon = WP_GAUNTLET; + break; + + case ANIM_WEAPON2: + s_controls.playerWeapon = WP_MACHINEGUN; + break; + + case ANIM_WEAPON3: + s_controls.playerWeapon = WP_SHOTGUN; + break; + + case ANIM_WEAPON4: + s_controls.playerWeapon = WP_GRENADE_LAUNCHER; + break; + + case ANIM_WEAPON5: + s_controls.playerWeapon = WP_ROCKET_LAUNCHER; + break; + + case ANIM_WEAPON6: + s_controls.playerWeapon = WP_LIGHTNING; + break; + + case ANIM_WEAPON7: + s_controls.playerWeapon = WP_RAILGUN; + break; + + case ANIM_WEAPON8: + s_controls.playerWeapon = WP_PLASMAGUN; + break; + + case ANIM_WEAPON9: + s_controls.playerWeapon = WP_BFG; + break; + + case ANIM_WEAPON10: + s_controls.playerWeapon = WP_GRAPPLING_HOOK; + break; + + case ANIM_ATTACK: + s_controls.playerTorso = TORSO_ATTACK; + break; + + case ANIM_GESTURE: + s_controls.playerTorso = TORSO_GESTURE; + break; + + case ANIM_DIE: + s_controls.playerLegs = BOTH_DEATH1; + s_controls.playerTorso = BOTH_DEATH1; + s_controls.playerWeapon = WP_NONE; + break; + + case ANIM_CHAT: + s_controls.playerChat = qtrue; + break; + + default: + break; + } + + UI_PlayerInfo_SetInfo( &s_controls.playerinfo, s_controls.playerLegs, s_controls.playerTorso, s_controls.playerViewangles, s_controls.playerMoveangles, s_controls.playerWeapon, s_controls.playerChat ); +} + + +/* +================= +Controls_Update +================= +*/ +static void Controls_Update( void ) { + int i; + int j; + int y; + menucommon_s **controls; + menucommon_s *control; + + // disable all controls in all groups + for( i = 0; i < C_MAX; i++ ) { + controls = g_controls[i]; + // bk001204 - parentheses + for( j = 0; (control = controls[j]) ; j++ ) { + control->flags |= (QMF_HIDDEN|QMF_INACTIVE); + } + } + + controls = g_controls[s_controls.section]; + + // enable controls in active group (and count number of items for vertical centering) + // bk001204 - parentheses + for( j = 0; (control = controls[j]) ; j++ ) { + control->flags &= ~(QMF_GRAYED|QMF_HIDDEN|QMF_INACTIVE); + } + + // position controls + y = ( SCREEN_HEIGHT - j * SMALLCHAR_HEIGHT ) / 2; + // bk001204 - parentheses + for( j = 0; (control = controls[j]) ; j++, y += SMALLCHAR_HEIGHT ) { + control->x = 320; + control->y = y; + control->left = 320 - 19*SMALLCHAR_WIDTH; + control->right = 320 + 21*SMALLCHAR_WIDTH; + control->top = y; + control->bottom = y + SMALLCHAR_HEIGHT; + } + + if( s_controls.waitingforkey ) { + // disable everybody + for( i = 0; i < s_controls.menu.nitems; i++ ) { + ((menucommon_s*)(s_controls.menu.items[i]))->flags |= QMF_GRAYED; + } + + // enable action item + ((menucommon_s*)(s_controls.menu.items[s_controls.menu.cursor]))->flags &= ~QMF_GRAYED; + + // don't gray out player's name + s_controls.name.generic.flags &= ~QMF_GRAYED; + + return; + } + + // enable everybody + for( i = 0; i < s_controls.menu.nitems; i++ ) { + ((menucommon_s*)(s_controls.menu.items[i]))->flags &= ~QMF_GRAYED; + } + + // makes sure flags are right on the group selection controls + s_controls.looking.generic.flags &= ~(QMF_GRAYED|QMF_HIGHLIGHT|QMF_HIGHLIGHT_IF_FOCUS); + s_controls.movement.generic.flags &= ~(QMF_GRAYED|QMF_HIGHLIGHT|QMF_HIGHLIGHT_IF_FOCUS); + s_controls.weapons.generic.flags &= ~(QMF_GRAYED|QMF_HIGHLIGHT|QMF_HIGHLIGHT_IF_FOCUS); + s_controls.misc.generic.flags &= ~(QMF_GRAYED|QMF_HIGHLIGHT|QMF_HIGHLIGHT_IF_FOCUS); + + s_controls.looking.generic.flags |= QMF_PULSEIFFOCUS; + s_controls.movement.generic.flags |= QMF_PULSEIFFOCUS; + s_controls.weapons.generic.flags |= QMF_PULSEIFFOCUS; + s_controls.misc.generic.flags |= QMF_PULSEIFFOCUS; + + // set buttons + switch( s_controls.section ) { + case C_MOVEMENT: + s_controls.movement.generic.flags &= ~QMF_PULSEIFFOCUS; + s_controls.movement.generic.flags |= (QMF_HIGHLIGHT|QMF_HIGHLIGHT_IF_FOCUS); + break; + + case C_LOOKING: + s_controls.looking.generic.flags &= ~QMF_PULSEIFFOCUS; + s_controls.looking.generic.flags |= (QMF_HIGHLIGHT|QMF_HIGHLIGHT_IF_FOCUS); + break; + + case C_WEAPONS: + s_controls.weapons.generic.flags &= ~QMF_PULSEIFFOCUS; + s_controls.weapons.generic.flags |= (QMF_HIGHLIGHT|QMF_HIGHLIGHT_IF_FOCUS); + break; + + case C_MISC: + s_controls.misc.generic.flags &= ~QMF_PULSEIFFOCUS; + s_controls.misc.generic.flags |= (QMF_HIGHLIGHT|QMF_HIGHLIGHT_IF_FOCUS); + break; + } +} + + +/* +================= +Controls_DrawKeyBinding +================= +*/ +static void Controls_DrawKeyBinding( void *self ) +{ + menuaction_s* a; + int x; + int y; + int b1; + int b2; + qboolean c; + char name[32]; + char name2[32]; + + a = (menuaction_s*) self; + + x = a->generic.x; + y = a->generic.y; + + c = (Menu_ItemAtCursor( a->generic.parent ) == a); + + b1 = g_bindings[a->generic.id].bind1; + if (b1 == -1) + strcpy(name,"???"); + else + { + trap_Key_KeynumToStringBuf( b1, name, 32 ); + Q_strupr(name); + + b2 = g_bindings[a->generic.id].bind2; + if (b2 != -1) + { + trap_Key_KeynumToStringBuf( b2, name2, 32 ); + Q_strupr(name2); + + strcat( name, " or " ); + strcat( name, name2 ); + } + } + + if (c) + { + UI_FillRect( a->generic.left, a->generic.top, a->generic.right-a->generic.left+1, a->generic.bottom-a->generic.top+1, listbar_color ); + + UI_DrawString( x - SMALLCHAR_WIDTH, y, g_bindings[a->generic.id].label, UI_RIGHT|UI_SMALLFONT, text_color_highlight ); + UI_DrawString( x + SMALLCHAR_WIDTH, y, name, UI_LEFT|UI_SMALLFONT|UI_PULSE, text_color_highlight ); + + if (s_controls.waitingforkey) + { + UI_DrawChar( x, y, '=', UI_CENTER|UI_BLINK|UI_SMALLFONT, text_color_highlight); + UI_DrawString(SCREEN_WIDTH * 0.50, SCREEN_HEIGHT * 0.80, "Waiting for new key ... ESCAPE to cancel", UI_SMALLFONT|UI_CENTER|UI_PULSE, colorWhite ); + } + else + { + UI_DrawChar( x, y, 13, UI_CENTER|UI_BLINK|UI_SMALLFONT, text_color_highlight); + UI_DrawString(SCREEN_WIDTH * 0.50, SCREEN_HEIGHT * 0.78, "Press ENTER or CLICK to change", UI_SMALLFONT|UI_CENTER, colorWhite ); + UI_DrawString(SCREEN_WIDTH * 0.50, SCREEN_HEIGHT * 0.82, "Press BACKSPACE to clear", UI_SMALLFONT|UI_CENTER, colorWhite ); + } + } + else + { + if (a->generic.flags & QMF_GRAYED) + { + UI_DrawString( x - SMALLCHAR_WIDTH, y, g_bindings[a->generic.id].label, UI_RIGHT|UI_SMALLFONT, text_color_disabled ); + UI_DrawString( x + SMALLCHAR_WIDTH, y, name, UI_LEFT|UI_SMALLFONT, text_color_disabled ); + } + else + { + UI_DrawString( x - SMALLCHAR_WIDTH, y, g_bindings[a->generic.id].label, UI_RIGHT|UI_SMALLFONT, controls_binding_color ); + UI_DrawString( x + SMALLCHAR_WIDTH, y, name, UI_LEFT|UI_SMALLFONT, controls_binding_color ); + } + } +} + +/* +================= +Controls_StatusBar +================= +*/ +static void Controls_StatusBar( void *self ) +{ + UI_DrawString(SCREEN_WIDTH * 0.50, SCREEN_HEIGHT * 0.80, "Use Arrow Keys or CLICK to change", UI_SMALLFONT|UI_CENTER, colorWhite ); +} + + +/* +================= +Controls_DrawPlayer +================= +*/ +static void Controls_DrawPlayer( void *self ) { + menubitmap_s *b; + char buf[MAX_QPATH]; + + trap_Cvar_VariableStringBuffer( "model", buf, sizeof( buf ) ); + if ( strcmp( buf, s_controls.playerModel ) != 0 ) { + UI_PlayerInfo_SetModel( &s_controls.playerinfo, buf ); + strcpy( s_controls.playerModel, buf ); + Controls_UpdateModel( ANIM_IDLE ); + } + + b = (menubitmap_s*) self; + UI_DrawPlayer( b->generic.x, b->generic.y, b->width, b->height, &s_controls.playerinfo, uis.realtime/2 ); +} + + +/* +================= +Controls_GetKeyAssignment +================= +*/ +static void Controls_GetKeyAssignment (char *command, int *twokeys) +{ + int count; + int j; + char b[256]; + + twokeys[0] = twokeys[1] = -1; + count = 0; + + for ( j = 0; j < 256; j++ ) + { + trap_Key_GetBindingBuf( j, b, 256 ); + if ( *b == 0 ) { + continue; + } + if ( !Q_stricmp( b, command ) ) { + twokeys[count] = j; + count++; + if (count == 2) + break; + } + } +} + +/* +================= +Controls_GetConfig +================= +*/ +static void Controls_GetConfig( void ) +{ + int i; + int twokeys[2]; + bind_t* bindptr; + + // put the bindings into a local store + bindptr = g_bindings; + + // iterate each command, get its numeric binding + for (i=0; ;i++,bindptr++) + { + if (!bindptr->label) + break; + + Controls_GetKeyAssignment(bindptr->command, twokeys); + + bindptr->bind1 = twokeys[0]; + bindptr->bind2 = twokeys[1]; + } + + s_controls.invertmouse.curvalue = Controls_GetCvarValue( "m_pitch" ) < 0; + s_controls.smoothmouse.curvalue = UI_ClampCvar( 0, 1, Controls_GetCvarValue( "m_filter" ) ); + s_controls.alwaysrun.curvalue = UI_ClampCvar( 0, 1, Controls_GetCvarValue( "cl_run" ) ); + s_controls.autoswitch.curvalue = UI_ClampCvar( 0, 1, Controls_GetCvarValue( "cg_autoswitch" ) ); + s_controls.sensitivity.curvalue = UI_ClampCvar( 2, 30, Controls_GetCvarValue( "sensitivity" ) ); + s_controls.joyenable.curvalue = UI_ClampCvar( 0, 1, Controls_GetCvarValue( "in_joystick" ) ); + s_controls.joythreshold.curvalue = UI_ClampCvar( 0.05f, 0.75f, Controls_GetCvarValue( "joy_threshold" ) ); + s_controls.freelook.curvalue = UI_ClampCvar( 0, 1, Controls_GetCvarValue( "cl_freelook" ) ); +} + +/* +================= +Controls_SetConfig +================= +*/ +static void Controls_SetConfig( void ) +{ + int i; + bind_t* bindptr; + + // set the bindings from the local store + bindptr = g_bindings; + + // iterate each command, get its numeric binding + for (i=0; ;i++,bindptr++) + { + if (!bindptr->label) + break; + + if (bindptr->bind1 != -1) + { + trap_Key_SetBinding( bindptr->bind1, bindptr->command ); + + if (bindptr->bind2 != -1) + trap_Key_SetBinding( bindptr->bind2, bindptr->command ); + } + } + + if ( s_controls.invertmouse.curvalue ) + trap_Cvar_SetValue( "m_pitch", -fabs( trap_Cvar_VariableValue( "m_pitch" ) ) ); + else + trap_Cvar_SetValue( "m_pitch", fabs( trap_Cvar_VariableValue( "m_pitch" ) ) ); + + trap_Cvar_SetValue( "m_filter", s_controls.smoothmouse.curvalue ); + trap_Cvar_SetValue( "cl_run", s_controls.alwaysrun.curvalue ); + trap_Cvar_SetValue( "cg_autoswitch", s_controls.autoswitch.curvalue ); + trap_Cvar_SetValue( "sensitivity", s_controls.sensitivity.curvalue ); + trap_Cvar_SetValue( "in_joystick", s_controls.joyenable.curvalue ); + trap_Cvar_SetValue( "joy_threshold", s_controls.joythreshold.curvalue ); + trap_Cvar_SetValue( "cl_freelook", s_controls.freelook.curvalue ); + trap_Cmd_ExecuteText( EXEC_APPEND, "in_restart\n" ); +} + +/* +================= +Controls_SetDefaults +================= +*/ +static void Controls_SetDefaults( void ) +{ + int i; + bind_t* bindptr; + + // set the bindings from the local store + bindptr = g_bindings; + + // iterate each command, set its default binding + for (i=0; ;i++,bindptr++) + { + if (!bindptr->label) + break; + + bindptr->bind1 = bindptr->defaultbind1; + bindptr->bind2 = bindptr->defaultbind2; + } + + s_controls.invertmouse.curvalue = Controls_GetCvarDefault( "m_pitch" ) < 0; + s_controls.smoothmouse.curvalue = Controls_GetCvarDefault( "m_filter" ); + s_controls.alwaysrun.curvalue = Controls_GetCvarDefault( "cl_run" ); + s_controls.autoswitch.curvalue = Controls_GetCvarDefault( "cg_autoswitch" ); + s_controls.sensitivity.curvalue = Controls_GetCvarDefault( "sensitivity" ); + s_controls.joyenable.curvalue = Controls_GetCvarDefault( "in_joystick" ); + s_controls.joythreshold.curvalue = Controls_GetCvarDefault( "joy_threshold" ); + s_controls.freelook.curvalue = Controls_GetCvarDefault( "cl_freelook" ); +} + +/* +================= +Controls_MenuKey +================= +*/ +static sfxHandle_t Controls_MenuKey( int key ) +{ + int id; + int i; + qboolean found; + bind_t* bindptr; + found = qfalse; + + if (!s_controls.waitingforkey) + { + switch (key) + { + case K_BACKSPACE: + case K_DEL: + case K_KP_DEL: + key = -1; + break; + + case K_MOUSE2: + case K_ESCAPE: + if (s_controls.changesmade) + Controls_SetConfig(); + goto ignorekey; + + default: + goto ignorekey; + } + } + else + { + if (key & K_CHAR_FLAG) + goto ignorekey; + + switch (key) + { + case K_ESCAPE: + s_controls.waitingforkey = qfalse; + Controls_Update(); + return (menu_out_sound); + + case '`': + goto ignorekey; + } + } + + s_controls.changesmade = qtrue; + + if (key != -1) + { + // remove from any other bind + bindptr = g_bindings; + for (i=0; ;i++,bindptr++) + { + if (!bindptr->label) + break; + + if (bindptr->bind2 == key) + bindptr->bind2 = -1; + + if (bindptr->bind1 == key) + { + bindptr->bind1 = bindptr->bind2; + bindptr->bind2 = -1; + } + } + } + + // assign key to local store + id = ((menucommon_s*)(s_controls.menu.items[s_controls.menu.cursor]))->id; + bindptr = g_bindings; + for (i=0; ;i++,bindptr++) + { + if (!bindptr->label) + break; + + if (bindptr->id == id) + { + found = qtrue; + if (key == -1) + { + if( bindptr->bind1 != -1 ) { + trap_Key_SetBinding( bindptr->bind1, "" ); + bindptr->bind1 = -1; + } + if( bindptr->bind2 != -1 ) { + trap_Key_SetBinding( bindptr->bind2, "" ); + bindptr->bind2 = -1; + } + } + else if (bindptr->bind1 == -1) { + bindptr->bind1 = key; + } + else if (bindptr->bind1 != key && bindptr->bind2 == -1) { + bindptr->bind2 = key; + } + else + { + trap_Key_SetBinding( bindptr->bind1, "" ); + trap_Key_SetBinding( bindptr->bind2, "" ); + bindptr->bind1 = key; + bindptr->bind2 = -1; + } + break; + } + } + + s_controls.waitingforkey = qfalse; + + if (found) + { + Controls_Update(); + return (menu_out_sound); + } + +ignorekey: + return Menu_DefaultKey( &s_controls.menu, key ); +} + +/* +================= +Controls_ResetDefaults_Action +================= +*/ +static void Controls_ResetDefaults_Action( qboolean result ) { + if( !result ) { + return; + } + + s_controls.changesmade = qtrue; + Controls_SetDefaults(); + Controls_Update(); +} + +/* +================= +Controls_ResetDefaults_Draw +================= +*/ +static void Controls_ResetDefaults_Draw( void ) { + UI_DrawProportionalString( SCREEN_WIDTH/2, 356 + PROP_HEIGHT * 0, "WARNING: This will reset all", UI_CENTER|UI_SMALLFONT, color_yellow ); + UI_DrawProportionalString( SCREEN_WIDTH/2, 356 + PROP_HEIGHT * 1, "controls to their default values.", UI_CENTER|UI_SMALLFONT, color_yellow ); +} + +/* +================= +Controls_MenuEvent +================= +*/ +static void Controls_MenuEvent( void* ptr, int event ) +{ + switch (((menucommon_s*)ptr)->id) + { + case ID_MOVEMENT: + if (event == QM_ACTIVATED) + { + s_controls.section = C_MOVEMENT; + Controls_Update(); + } + break; + + case ID_LOOKING: + if (event == QM_ACTIVATED) + { + s_controls.section = C_LOOKING; + Controls_Update(); + } + break; + + case ID_WEAPONS: + if (event == QM_ACTIVATED) + { + s_controls.section = C_WEAPONS; + Controls_Update(); + } + break; + + case ID_MISC: + if (event == QM_ACTIVATED) + { + s_controls.section = C_MISC; + Controls_Update(); + } + break; + + case ID_DEFAULTS: + if (event == QM_ACTIVATED) + { + UI_ConfirmMenu( "SET TO DEFAULTS?", Controls_ResetDefaults_Draw, Controls_ResetDefaults_Action ); + } + break; + + case ID_BACK: + if (event == QM_ACTIVATED) + { + if (s_controls.changesmade) + Controls_SetConfig(); + UI_PopMenu(); + } + break; + + case ID_SAVEANDEXIT: + if (event == QM_ACTIVATED) + { + Controls_SetConfig(); + UI_PopMenu(); + } + break; + + case ID_EXIT: + if (event == QM_ACTIVATED) + { + UI_PopMenu(); + } + break; + + case ID_FREELOOK: + case ID_MOUSESPEED: + case ID_INVERTMOUSE: + case ID_SMOOTHMOUSE: + case ID_ALWAYSRUN: + case ID_AUTOSWITCH: + case ID_JOYENABLE: + case ID_JOYTHRESHOLD: + if (event == QM_ACTIVATED) + { + s_controls.changesmade = qtrue; + } + break; + } +} + +/* +================= +Controls_ActionEvent +================= +*/ +static void Controls_ActionEvent( void* ptr, int event ) +{ + if (event == QM_LOSTFOCUS) + { + Controls_UpdateModel( ANIM_IDLE ); + } + else if (event == QM_GOTFOCUS) + { + Controls_UpdateModel( g_bindings[((menucommon_s*)ptr)->id].anim ); + } + else if ((event == QM_ACTIVATED) && !s_controls.waitingforkey) + { + s_controls.waitingforkey = 1; + Controls_Update(); + } +} + +/* +================= +Controls_InitModel +================= +*/ +static void Controls_InitModel( void ) +{ + memset( &s_controls.playerinfo, 0, sizeof(playerInfo_t) ); + + UI_PlayerInfo_SetModel( &s_controls.playerinfo, UI_Cvar_VariableString( "model" ) ); + + Controls_UpdateModel( ANIM_IDLE ); +} + +/* +================= +Controls_InitWeapons +================= +*/ +static void Controls_InitWeapons( void ) { + gitem_t * item; + + for ( item = bg_itemlist + 1 ; item->classname ; item++ ) { + if ( item->giType != IT_WEAPON ) { + continue; + } + trap_R_RegisterModel( item->world_model[0] ); + } +} + +/* +================= +Controls_MenuInit +================= +*/ +static void Controls_MenuInit( void ) +{ + static char playername[32]; + + // zero set all our globals + memset( &s_controls, 0 ,sizeof(controls_t) ); + + Controls_Cache(); + + s_controls.menu.key = Controls_MenuKey; + s_controls.menu.wrapAround = qtrue; + s_controls.menu.fullscreen = qtrue; + + s_controls.banner.generic.type = MTYPE_BTEXT; + s_controls.banner.generic.flags = QMF_CENTER_JUSTIFY; + s_controls.banner.generic.x = 320; + s_controls.banner.generic.y = 16; + s_controls.banner.string = "CONTROLS"; + s_controls.banner.color = color_white; + s_controls.banner.style = UI_CENTER; + + s_controls.framel.generic.type = MTYPE_BITMAP; + s_controls.framel.generic.name = ART_FRAMEL; + s_controls.framel.generic.flags = QMF_LEFT_JUSTIFY|QMF_INACTIVE; + s_controls.framel.generic.x = 0; + s_controls.framel.generic.y = 78; + s_controls.framel.width = 256; + s_controls.framel.height = 329; + + s_controls.framer.generic.type = MTYPE_BITMAP; + s_controls.framer.generic.name = ART_FRAMER; + s_controls.framer.generic.flags = QMF_LEFT_JUSTIFY|QMF_INACTIVE; + s_controls.framer.generic.x = 376; + s_controls.framer.generic.y = 76; + s_controls.framer.width = 256; + s_controls.framer.height = 334; + + s_controls.looking.generic.type = MTYPE_PTEXT; + s_controls.looking.generic.flags = QMF_RIGHT_JUSTIFY|QMF_PULSEIFFOCUS; + s_controls.looking.generic.id = ID_LOOKING; + s_controls.looking.generic.callback = Controls_MenuEvent; + s_controls.looking.generic.x = 152; + s_controls.looking.generic.y = 240 - 2 * PROP_HEIGHT; + s_controls.looking.string = "LOOK"; + s_controls.looking.style = UI_RIGHT; + s_controls.looking.color = color_red; + + s_controls.movement.generic.type = MTYPE_PTEXT; + s_controls.movement.generic.flags = QMF_RIGHT_JUSTIFY|QMF_PULSEIFFOCUS; + s_controls.movement.generic.id = ID_MOVEMENT; + s_controls.movement.generic.callback = Controls_MenuEvent; + s_controls.movement.generic.x = 152; + s_controls.movement.generic.y = 240 - PROP_HEIGHT; + s_controls.movement.string = "MOVE"; + s_controls.movement.style = UI_RIGHT; + s_controls.movement.color = color_red; + + s_controls.weapons.generic.type = MTYPE_PTEXT; + s_controls.weapons.generic.flags = QMF_RIGHT_JUSTIFY|QMF_PULSEIFFOCUS; + s_controls.weapons.generic.id = ID_WEAPONS; + s_controls.weapons.generic.callback = Controls_MenuEvent; + s_controls.weapons.generic.x = 152; + s_controls.weapons.generic.y = 240; + s_controls.weapons.string = "SHOOT"; + s_controls.weapons.style = UI_RIGHT; + s_controls.weapons.color = color_red; + + s_controls.misc.generic.type = MTYPE_PTEXT; + s_controls.misc.generic.flags = QMF_RIGHT_JUSTIFY|QMF_PULSEIFFOCUS; + s_controls.misc.generic.id = ID_MISC; + s_controls.misc.generic.callback = Controls_MenuEvent; + s_controls.misc.generic.x = 152; + s_controls.misc.generic.y = 240 + PROP_HEIGHT; + s_controls.misc.string = "MISC"; + s_controls.misc.style = UI_RIGHT; + s_controls.misc.color = color_red; + + s_controls.back.generic.type = MTYPE_BITMAP; + s_controls.back.generic.name = ART_BACK0; + s_controls.back.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS; + s_controls.back.generic.x = 0; + s_controls.back.generic.y = 480-64; + s_controls.back.generic.id = ID_BACK; + s_controls.back.generic.callback = Controls_MenuEvent; + s_controls.back.width = 128; + s_controls.back.height = 64; + s_controls.back.focuspic = ART_BACK1; + + s_controls.player.generic.type = MTYPE_BITMAP; + s_controls.player.generic.flags = QMF_INACTIVE; + s_controls.player.generic.ownerdraw = Controls_DrawPlayer; + s_controls.player.generic.x = 400; + s_controls.player.generic.y = -40; + s_controls.player.width = 32*10; + s_controls.player.height = 56*10; + + s_controls.walkforward.generic.type = MTYPE_ACTION; + s_controls.walkforward.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_GRAYED|QMF_HIDDEN; + s_controls.walkforward.generic.callback = Controls_ActionEvent; + s_controls.walkforward.generic.ownerdraw = Controls_DrawKeyBinding; + s_controls.walkforward.generic.id = ID_FORWARD; + + s_controls.backpedal.generic.type = MTYPE_ACTION; + s_controls.backpedal.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_GRAYED|QMF_HIDDEN; + s_controls.backpedal.generic.callback = Controls_ActionEvent; + s_controls.backpedal.generic.ownerdraw = Controls_DrawKeyBinding; + s_controls.backpedal.generic.id = ID_BACKPEDAL; + + s_controls.stepleft.generic.type = MTYPE_ACTION; + s_controls.stepleft.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_GRAYED|QMF_HIDDEN; + s_controls.stepleft.generic.callback = Controls_ActionEvent; + s_controls.stepleft.generic.ownerdraw = Controls_DrawKeyBinding; + s_controls.stepleft.generic.id = ID_MOVELEFT; + + s_controls.stepright.generic.type = MTYPE_ACTION; + s_controls.stepright.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_GRAYED|QMF_HIDDEN; + s_controls.stepright.generic.callback = Controls_ActionEvent; + s_controls.stepright.generic.ownerdraw = Controls_DrawKeyBinding; + s_controls.stepright.generic.id = ID_MOVERIGHT; + + s_controls.moveup.generic.type = MTYPE_ACTION; + s_controls.moveup.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_GRAYED|QMF_HIDDEN; + s_controls.moveup.generic.callback = Controls_ActionEvent; + s_controls.moveup.generic.ownerdraw = Controls_DrawKeyBinding; + s_controls.moveup.generic.id = ID_MOVEUP; + + s_controls.movedown.generic.type = MTYPE_ACTION; + s_controls.movedown.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_GRAYED|QMF_HIDDEN; + s_controls.movedown.generic.callback = Controls_ActionEvent; + s_controls.movedown.generic.ownerdraw = Controls_DrawKeyBinding; + s_controls.movedown.generic.id = ID_MOVEDOWN; + + s_controls.turnleft.generic.type = MTYPE_ACTION; + s_controls.turnleft.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_GRAYED|QMF_HIDDEN; + s_controls.turnleft.generic.callback = Controls_ActionEvent; + s_controls.turnleft.generic.ownerdraw = Controls_DrawKeyBinding; + s_controls.turnleft.generic.id = ID_LEFT; + + s_controls.turnright.generic.type = MTYPE_ACTION; + s_controls.turnright.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_GRAYED|QMF_HIDDEN; + s_controls.turnright.generic.callback = Controls_ActionEvent; + s_controls.turnright.generic.ownerdraw = Controls_DrawKeyBinding; + s_controls.turnright.generic.id = ID_RIGHT; + + s_controls.sidestep.generic.type = MTYPE_ACTION; + s_controls.sidestep.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_GRAYED|QMF_HIDDEN; + s_controls.sidestep.generic.callback = Controls_ActionEvent; + s_controls.sidestep.generic.ownerdraw = Controls_DrawKeyBinding; + s_controls.sidestep.generic.id = ID_STRAFE; + + s_controls.run.generic.type = MTYPE_ACTION; + s_controls.run.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_GRAYED|QMF_HIDDEN; + s_controls.run.generic.callback = Controls_ActionEvent; + s_controls.run.generic.ownerdraw = Controls_DrawKeyBinding; + s_controls.run.generic.id = ID_SPEED; + + s_controls.chainsaw.generic.type = MTYPE_ACTION; + s_controls.chainsaw.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_GRAYED|QMF_HIDDEN; + s_controls.chainsaw.generic.callback = Controls_ActionEvent; + s_controls.chainsaw.generic.ownerdraw = Controls_DrawKeyBinding; + s_controls.chainsaw.generic.id = ID_WEAPON1; + + s_controls.machinegun.generic.type = MTYPE_ACTION; + s_controls.machinegun.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_GRAYED|QMF_HIDDEN; + s_controls.machinegun.generic.callback = Controls_ActionEvent; + s_controls.machinegun.generic.ownerdraw = Controls_DrawKeyBinding; + s_controls.machinegun.generic.id = ID_WEAPON2; + + s_controls.shotgun.generic.type = MTYPE_ACTION; + s_controls.shotgun.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_GRAYED|QMF_HIDDEN; + s_controls.shotgun.generic.callback = Controls_ActionEvent; + s_controls.shotgun.generic.ownerdraw = Controls_DrawKeyBinding; + s_controls.shotgun.generic.id = ID_WEAPON3; + + s_controls.grenadelauncher.generic.type = MTYPE_ACTION; + s_controls.grenadelauncher.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_GRAYED|QMF_HIDDEN; + s_controls.grenadelauncher.generic.callback = Controls_ActionEvent; + s_controls.grenadelauncher.generic.ownerdraw = Controls_DrawKeyBinding; + s_controls.grenadelauncher.generic.id = ID_WEAPON4; + + s_controls.rocketlauncher.generic.type = MTYPE_ACTION; + s_controls.rocketlauncher.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_GRAYED|QMF_HIDDEN; + s_controls.rocketlauncher.generic.callback = Controls_ActionEvent; + s_controls.rocketlauncher.generic.ownerdraw = Controls_DrawKeyBinding; + s_controls.rocketlauncher.generic.id = ID_WEAPON5; + + s_controls.lightning.generic.type = MTYPE_ACTION; + s_controls.lightning.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_GRAYED|QMF_HIDDEN; + s_controls.lightning.generic.callback = Controls_ActionEvent; + s_controls.lightning.generic.ownerdraw = Controls_DrawKeyBinding; + s_controls.lightning.generic.id = ID_WEAPON6; + + s_controls.railgun.generic.type = MTYPE_ACTION; + s_controls.railgun.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_GRAYED|QMF_HIDDEN; + s_controls.railgun.generic.callback = Controls_ActionEvent; + s_controls.railgun.generic.ownerdraw = Controls_DrawKeyBinding; + s_controls.railgun.generic.id = ID_WEAPON7; + + s_controls.plasma.generic.type = MTYPE_ACTION; + s_controls.plasma.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_GRAYED|QMF_HIDDEN; + s_controls.plasma.generic.callback = Controls_ActionEvent; + s_controls.plasma.generic.ownerdraw = Controls_DrawKeyBinding; + s_controls.plasma.generic.id = ID_WEAPON8; + + s_controls.bfg.generic.type = MTYPE_ACTION; + s_controls.bfg.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_GRAYED|QMF_HIDDEN; + s_controls.bfg.generic.callback = Controls_ActionEvent; + s_controls.bfg.generic.ownerdraw = Controls_DrawKeyBinding; + s_controls.bfg.generic.id = ID_WEAPON9; + + s_controls.attack.generic.type = MTYPE_ACTION; + s_controls.attack.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_GRAYED|QMF_HIDDEN; + s_controls.attack.generic.callback = Controls_ActionEvent; + s_controls.attack.generic.ownerdraw = Controls_DrawKeyBinding; + s_controls.attack.generic.id = ID_ATTACK; + + s_controls.prevweapon.generic.type = MTYPE_ACTION; + s_controls.prevweapon.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_GRAYED|QMF_HIDDEN; + s_controls.prevweapon.generic.callback = Controls_ActionEvent; + s_controls.prevweapon.generic.ownerdraw = Controls_DrawKeyBinding; + s_controls.prevweapon.generic.id = ID_WEAPPREV; + + s_controls.nextweapon.generic.type = MTYPE_ACTION; + s_controls.nextweapon.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_GRAYED|QMF_HIDDEN; + s_controls.nextweapon.generic.callback = Controls_ActionEvent; + s_controls.nextweapon.generic.ownerdraw = Controls_DrawKeyBinding; + s_controls.nextweapon.generic.id = ID_WEAPNEXT; + + s_controls.lookup.generic.type = MTYPE_ACTION; + s_controls.lookup.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_GRAYED|QMF_HIDDEN; + s_controls.lookup.generic.callback = Controls_ActionEvent; + s_controls.lookup.generic.ownerdraw = Controls_DrawKeyBinding; + s_controls.lookup.generic.id = ID_LOOKUP; + + s_controls.lookdown.generic.type = MTYPE_ACTION; + s_controls.lookdown.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_GRAYED|QMF_HIDDEN; + s_controls.lookdown.generic.callback = Controls_ActionEvent; + s_controls.lookdown.generic.ownerdraw = Controls_DrawKeyBinding; + s_controls.lookdown.generic.id = ID_LOOKDOWN; + + s_controls.mouselook.generic.type = MTYPE_ACTION; + s_controls.mouselook.generic.flags = QMF_LEFT_JUSTIFY|QMF_HIGHLIGHT_IF_FOCUS|QMF_GRAYED|QMF_HIDDEN; + s_controls.mouselook.generic.callback = Controls_ActionEvent; + s_controls.mouselook.generic.ownerdraw = Controls_DrawKeyBinding; + s_controls.mouselook.generic.id = ID_MOUSELOOK; + + s_controls.freelook.generic.type = MTYPE_RADIOBUTTON; + s_controls.freelook.generic.flags = QMF_SMALLFONT; + s_controls.freelook.generic.x = SCREEN_WIDTH/2; + s_controls.freelook.generic.name = "free look"; + s_controls.freelook.generic.id = ID_FREELOOK; + s_controls.freelook.generic.callback = Controls_MenuEvent; + s_controls.freelook.generic.statusbar = Controls_StatusBar; + + s_controls.centerview.generic.type = MTYPE_ACTION; + s_controls.centerview.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_GRAYED|QMF_HIDDEN; + s_controls.centerview.generic.callback = Controls_ActionEvent; + s_controls.centerview.generic.ownerdraw = Controls_DrawKeyBinding; + s_controls.centerview.generic.id = ID_CENTERVIEW; + + s_controls.zoomview.generic.type = MTYPE_ACTION; + s_controls.zoomview.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_GRAYED|QMF_HIDDEN; + s_controls.zoomview.generic.callback = Controls_ActionEvent; + s_controls.zoomview.generic.ownerdraw = Controls_DrawKeyBinding; + s_controls.zoomview.generic.id = ID_ZOOMVIEW; + + s_controls.useitem.generic.type = MTYPE_ACTION; + s_controls.useitem.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_GRAYED|QMF_HIDDEN; + s_controls.useitem.generic.callback = Controls_ActionEvent; + s_controls.useitem.generic.ownerdraw = Controls_DrawKeyBinding; + s_controls.useitem.generic.id = ID_USEITEM; + + s_controls.showscores.generic.type = MTYPE_ACTION; + s_controls.showscores.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_GRAYED|QMF_HIDDEN; + s_controls.showscores.generic.callback = Controls_ActionEvent; + s_controls.showscores.generic.ownerdraw = Controls_DrawKeyBinding; + s_controls.showscores.generic.id = ID_SHOWSCORES; + + s_controls.invertmouse.generic.type = MTYPE_RADIOBUTTON; + s_controls.invertmouse.generic.flags = QMF_SMALLFONT; + s_controls.invertmouse.generic.x = SCREEN_WIDTH/2; + s_controls.invertmouse.generic.name = "invert mouse"; + s_controls.invertmouse.generic.id = ID_INVERTMOUSE; + s_controls.invertmouse.generic.callback = Controls_MenuEvent; + s_controls.invertmouse.generic.statusbar = Controls_StatusBar; + + s_controls.smoothmouse.generic.type = MTYPE_RADIOBUTTON; + s_controls.smoothmouse.generic.flags = QMF_SMALLFONT; + s_controls.smoothmouse.generic.x = SCREEN_WIDTH/2; + s_controls.smoothmouse.generic.name = "smooth mouse"; + s_controls.smoothmouse.generic.id = ID_SMOOTHMOUSE; + s_controls.smoothmouse.generic.callback = Controls_MenuEvent; + s_controls.smoothmouse.generic.statusbar = Controls_StatusBar; + + s_controls.alwaysrun.generic.type = MTYPE_RADIOBUTTON; + s_controls.alwaysrun.generic.flags = QMF_SMALLFONT; + s_controls.alwaysrun.generic.x = SCREEN_WIDTH/2; + s_controls.alwaysrun.generic.name = "always run"; + s_controls.alwaysrun.generic.id = ID_ALWAYSRUN; + s_controls.alwaysrun.generic.callback = Controls_MenuEvent; + s_controls.alwaysrun.generic.statusbar = Controls_StatusBar; + + s_controls.autoswitch.generic.type = MTYPE_RADIOBUTTON; + s_controls.autoswitch.generic.flags = QMF_SMALLFONT; + s_controls.autoswitch.generic.x = SCREEN_WIDTH/2; + s_controls.autoswitch.generic.name = "autoswitch weapons"; + s_controls.autoswitch.generic.id = ID_AUTOSWITCH; + s_controls.autoswitch.generic.callback = Controls_MenuEvent; + s_controls.autoswitch.generic.statusbar = Controls_StatusBar; + + s_controls.sensitivity.generic.type = MTYPE_SLIDER; + s_controls.sensitivity.generic.x = SCREEN_WIDTH/2; + s_controls.sensitivity.generic.flags = QMF_SMALLFONT; + s_controls.sensitivity.generic.name = "mouse speed"; + s_controls.sensitivity.generic.id = ID_MOUSESPEED; + s_controls.sensitivity.generic.callback = Controls_MenuEvent; + s_controls.sensitivity.minvalue = 2; + s_controls.sensitivity.maxvalue = 30; + s_controls.sensitivity.generic.statusbar = Controls_StatusBar; + + s_controls.gesture.generic.type = MTYPE_ACTION; + s_controls.gesture.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_GRAYED|QMF_HIDDEN; + s_controls.gesture.generic.callback = Controls_ActionEvent; + s_controls.gesture.generic.ownerdraw = Controls_DrawKeyBinding; + s_controls.gesture.generic.id = ID_GESTURE; + + s_controls.chat.generic.type = MTYPE_ACTION; + s_controls.chat.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_GRAYED|QMF_HIDDEN; + s_controls.chat.generic.callback = Controls_ActionEvent; + s_controls.chat.generic.ownerdraw = Controls_DrawKeyBinding; + s_controls.chat.generic.id = ID_CHAT; + + s_controls.chat2.generic.type = MTYPE_ACTION; + s_controls.chat2.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_GRAYED|QMF_HIDDEN; + s_controls.chat2.generic.callback = Controls_ActionEvent; + s_controls.chat2.generic.ownerdraw = Controls_DrawKeyBinding; + s_controls.chat2.generic.id = ID_CHAT2; + + s_controls.chat3.generic.type = MTYPE_ACTION; + s_controls.chat3.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_GRAYED|QMF_HIDDEN; + s_controls.chat3.generic.callback = Controls_ActionEvent; + s_controls.chat3.generic.ownerdraw = Controls_DrawKeyBinding; + s_controls.chat3.generic.id = ID_CHAT3; + + s_controls.chat4.generic.type = MTYPE_ACTION; + s_controls.chat4.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_GRAYED|QMF_HIDDEN; + s_controls.chat4.generic.callback = Controls_ActionEvent; + s_controls.chat4.generic.ownerdraw = Controls_DrawKeyBinding; + s_controls.chat4.generic.id = ID_CHAT4; + + s_controls.joyenable.generic.type = MTYPE_RADIOBUTTON; + s_controls.joyenable.generic.flags = QMF_SMALLFONT; + s_controls.joyenable.generic.x = SCREEN_WIDTH/2; + s_controls.joyenable.generic.name = "joystick"; + s_controls.joyenable.generic.id = ID_JOYENABLE; + s_controls.joyenable.generic.callback = Controls_MenuEvent; + s_controls.joyenable.generic.statusbar = Controls_StatusBar; + + s_controls.joythreshold.generic.type = MTYPE_SLIDER; + s_controls.joythreshold.generic.x = SCREEN_WIDTH/2; + s_controls.joythreshold.generic.flags = QMF_SMALLFONT; + s_controls.joythreshold.generic.name = "joystick threshold"; + s_controls.joythreshold.generic.id = ID_JOYTHRESHOLD; + s_controls.joythreshold.generic.callback = Controls_MenuEvent; + s_controls.joythreshold.minvalue = 0.05f; + s_controls.joythreshold.maxvalue = 0.75f; + s_controls.joythreshold.generic.statusbar = Controls_StatusBar; + + s_controls.name.generic.type = MTYPE_PTEXT; + s_controls.name.generic.flags = QMF_CENTER_JUSTIFY|QMF_INACTIVE; + s_controls.name.generic.x = 320; + s_controls.name.generic.y = 440; + s_controls.name.string = playername; + s_controls.name.style = UI_CENTER; + s_controls.name.color = text_color_normal; + + Menu_AddItem( &s_controls.menu, &s_controls.banner ); + Menu_AddItem( &s_controls.menu, &s_controls.framel ); + Menu_AddItem( &s_controls.menu, &s_controls.framer ); + Menu_AddItem( &s_controls.menu, &s_controls.player ); + Menu_AddItem( &s_controls.menu, &s_controls.name ); + + Menu_AddItem( &s_controls.menu, &s_controls.looking ); + Menu_AddItem( &s_controls.menu, &s_controls.movement ); + Menu_AddItem( &s_controls.menu, &s_controls.weapons ); + Menu_AddItem( &s_controls.menu, &s_controls.misc ); + + Menu_AddItem( &s_controls.menu, &s_controls.sensitivity ); + Menu_AddItem( &s_controls.menu, &s_controls.smoothmouse ); + Menu_AddItem( &s_controls.menu, &s_controls.invertmouse ); + Menu_AddItem( &s_controls.menu, &s_controls.lookup ); + Menu_AddItem( &s_controls.menu, &s_controls.lookdown ); + Menu_AddItem( &s_controls.menu, &s_controls.mouselook ); + Menu_AddItem( &s_controls.menu, &s_controls.freelook ); + Menu_AddItem( &s_controls.menu, &s_controls.centerview ); + Menu_AddItem( &s_controls.menu, &s_controls.zoomview ); + Menu_AddItem( &s_controls.menu, &s_controls.joyenable ); + Menu_AddItem( &s_controls.menu, &s_controls.joythreshold ); + + Menu_AddItem( &s_controls.menu, &s_controls.alwaysrun ); + Menu_AddItem( &s_controls.menu, &s_controls.run ); + Menu_AddItem( &s_controls.menu, &s_controls.walkforward ); + Menu_AddItem( &s_controls.menu, &s_controls.backpedal ); + Menu_AddItem( &s_controls.menu, &s_controls.stepleft ); + Menu_AddItem( &s_controls.menu, &s_controls.stepright ); + Menu_AddItem( &s_controls.menu, &s_controls.moveup ); + Menu_AddItem( &s_controls.menu, &s_controls.movedown ); + Menu_AddItem( &s_controls.menu, &s_controls.turnleft ); + Menu_AddItem( &s_controls.menu, &s_controls.turnright ); + Menu_AddItem( &s_controls.menu, &s_controls.sidestep ); + + Menu_AddItem( &s_controls.menu, &s_controls.attack ); + Menu_AddItem( &s_controls.menu, &s_controls.nextweapon ); + Menu_AddItem( &s_controls.menu, &s_controls.prevweapon ); + Menu_AddItem( &s_controls.menu, &s_controls.autoswitch ); + Menu_AddItem( &s_controls.menu, &s_controls.chainsaw ); + Menu_AddItem( &s_controls.menu, &s_controls.machinegun ); + Menu_AddItem( &s_controls.menu, &s_controls.shotgun ); + Menu_AddItem( &s_controls.menu, &s_controls.grenadelauncher ); + Menu_AddItem( &s_controls.menu, &s_controls.rocketlauncher ); + Menu_AddItem( &s_controls.menu, &s_controls.lightning ); + Menu_AddItem( &s_controls.menu, &s_controls.railgun ); + Menu_AddItem( &s_controls.menu, &s_controls.plasma ); + Menu_AddItem( &s_controls.menu, &s_controls.bfg ); + + Menu_AddItem( &s_controls.menu, &s_controls.showscores ); + Menu_AddItem( &s_controls.menu, &s_controls.useitem ); + Menu_AddItem( &s_controls.menu, &s_controls.gesture ); + Menu_AddItem( &s_controls.menu, &s_controls.chat ); + Menu_AddItem( &s_controls.menu, &s_controls.chat2 ); + Menu_AddItem( &s_controls.menu, &s_controls.chat3 ); + Menu_AddItem( &s_controls.menu, &s_controls.chat4 ); + + Menu_AddItem( &s_controls.menu, &s_controls.back ); + + trap_Cvar_VariableStringBuffer( "name", s_controls.name.string, 16 ); + Q_CleanStr( s_controls.name.string ); + + // initialize the configurable cvars + Controls_InitCvars(); + + // initialize the current config + Controls_GetConfig(); + + // intialize the model + Controls_InitModel(); + + // intialize the weapons + Controls_InitWeapons (); + + // initial default section + s_controls.section = C_LOOKING; + + // update the ui + Controls_Update(); +} + + +/* +================= +Controls_Cache +================= +*/ +void Controls_Cache( void ) { + trap_R_RegisterShaderNoMip( ART_BACK0 ); + trap_R_RegisterShaderNoMip( ART_BACK1 ); + trap_R_RegisterShaderNoMip( ART_FRAMEL ); + trap_R_RegisterShaderNoMip( ART_FRAMER ); +} + + +/* +================= +UI_ControlsMenu +================= +*/ +void UI_ControlsMenu( void ) { + Controls_MenuInit(); + UI_PushMenu( &s_controls.menu ); +} diff --git a/code/q3_ui/ui_credits.c b/code/q3_ui/ui_credits.c new file mode 100755 index 0000000..266e00b --- /dev/null +++ b/code/q3_ui/ui_credits.c @@ -0,0 +1,129 @@ +/* +=========================================================================== +Copyright (C) 1999-2005 Id Software, Inc. + +This file is part of Quake III Arena source code. + +Quake III Arena source code is free software; you can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 2 of the License, +or (at your option) any later version. + +Quake III Arena source code is distributed in the hope that it will be +useful, but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Foobar; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ +// +/* +======================================================================= + +CREDITS + +======================================================================= +*/ + + +#include "ui_local.h" + + +typedef struct { + menuframework_s menu; +} creditsmenu_t; + +static creditsmenu_t s_credits; + + +/* +================= +UI_CreditMenu_Key +================= +*/ +static sfxHandle_t UI_CreditMenu_Key( int key ) { + if( key & K_CHAR_FLAG ) { + return 0; + } + + trap_Cmd_ExecuteText( EXEC_APPEND, "quit\n" ); + return 0; +} + + +/* +=============== +UI_CreditMenu_Draw +=============== +*/ +static void UI_CreditMenu_Draw( void ) { + int y; + + y = 12; + UI_DrawProportionalString( 320, y, "id Software is:", UI_CENTER|UI_SMALLFONT, color_white ); + + y += 1.42 * PROP_HEIGHT * PROP_SMALL_SIZE_SCALE; + UI_DrawProportionalString( 320, y, "Programming", UI_CENTER|UI_SMALLFONT, color_white ); + y += PROP_HEIGHT * PROP_SMALL_SIZE_SCALE; + UI_DrawProportionalString( 320, y, "John Carmack, Robert A. Duffy, Jim Dose'", UI_CENTER|UI_SMALLFONT, color_white ); + + y += 1.42 * PROP_HEIGHT * PROP_SMALL_SIZE_SCALE; + UI_DrawProportionalString( 320, y, "Art", UI_CENTER|UI_SMALLFONT, color_white ); + y += PROP_HEIGHT * PROP_SMALL_SIZE_SCALE; + UI_DrawProportionalString( 320, y, "Adrian Carmack, Kevin Cloud,", UI_CENTER|UI_SMALLFONT, color_white ); + y += PROP_HEIGHT * PROP_SMALL_SIZE_SCALE; + UI_DrawProportionalString( 320, y, "Kenneth Scott, Seneca Menard, Fred Nilsson", UI_CENTER|UI_SMALLFONT, color_white ); + + y += 1.42 * PROP_HEIGHT * PROP_SMALL_SIZE_SCALE; + UI_DrawProportionalString( 320, y, "Game Designer", UI_CENTER|UI_SMALLFONT, color_white ); + y += PROP_HEIGHT * PROP_SMALL_SIZE_SCALE; + UI_DrawProportionalString( 320, y, "Graeme Devine", UI_CENTER|UI_SMALLFONT, color_white ); + + y += 1.42 * PROP_HEIGHT * PROP_SMALL_SIZE_SCALE; + UI_DrawProportionalString( 320, y, "Level Design", UI_CENTER|UI_SMALLFONT, color_white ); + y += PROP_HEIGHT * PROP_SMALL_SIZE_SCALE; + UI_DrawProportionalString( 320, y, "Tim Willits, Christian Antkow, Paul Jaquays", UI_CENTER|UI_SMALLFONT, color_white ); + + y += 1.42 * PROP_HEIGHT * PROP_SMALL_SIZE_SCALE; + UI_DrawProportionalString( 320, y, "CEO", UI_CENTER|UI_SMALLFONT, color_white ); + y += PROP_HEIGHT * PROP_SMALL_SIZE_SCALE; + UI_DrawProportionalString( 320, y, "Todd Hollenshead", UI_CENTER|UI_SMALLFONT, color_white ); + + y += 1.42 * PROP_HEIGHT * PROP_SMALL_SIZE_SCALE; + UI_DrawProportionalString( 320, y, "Director of Business Development", UI_CENTER|UI_SMALLFONT, color_white ); + y += PROP_HEIGHT * PROP_SMALL_SIZE_SCALE; + UI_DrawProportionalString( 320, y, "Marty Stratton", UI_CENTER|UI_SMALLFONT, color_white ); + + y += 1.42 * PROP_HEIGHT * PROP_SMALL_SIZE_SCALE; + UI_DrawProportionalString( 320, y, "Biz Assist and id Mom", UI_CENTER|UI_SMALLFONT, color_white ); + y += PROP_HEIGHT * PROP_SMALL_SIZE_SCALE; + UI_DrawProportionalString( 320, y, "Donna Jackson", UI_CENTER|UI_SMALLFONT, color_white ); + + y += 1.42 * PROP_HEIGHT * PROP_SMALL_SIZE_SCALE; + UI_DrawProportionalString( 320, y, "Development Assistance", UI_CENTER|UI_SMALLFONT, color_white ); + y += PROP_HEIGHT * PROP_SMALL_SIZE_SCALE; + UI_DrawProportionalString( 320, y, "Eric Webb", UI_CENTER|UI_SMALLFONT, color_white ); + + y += 1.35 * PROP_HEIGHT * PROP_SMALL_SIZE_SCALE; + UI_DrawString( 320, y, "To order: 1-800-idgames www.quake3arena.com www.idsoftware.com", UI_CENTER|UI_SMALLFONT, color_red ); + y += SMALLCHAR_HEIGHT; + UI_DrawString( 320, y, "Quake III Arena(c) 1999-2000, Id Software, Inc. All Rights Reserved", UI_CENTER|UI_SMALLFONT, color_red ); +} + + +/* +=============== +UI_CreditMenu +=============== +*/ +void UI_CreditMenu( void ) { + memset( &s_credits, 0 ,sizeof(s_credits) ); + + s_credits.menu.draw = UI_CreditMenu_Draw; + s_credits.menu.key = UI_CreditMenu_Key; + s_credits.menu.fullscreen = qtrue; + UI_PushMenu ( &s_credits.menu ); +} diff --git a/code/q3_ui/ui_demo2.c b/code/q3_ui/ui_demo2.c new file mode 100755 index 0000000..57b5955 --- /dev/null +++ b/code/q3_ui/ui_demo2.c @@ -0,0 +1,291 @@ +/* +=========================================================================== +Copyright (C) 1999-2005 Id Software, Inc. + +This file is part of Quake III Arena source code. + +Quake III Arena source code is free software; you can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 2 of the License, +or (at your option) any later version. + +Quake III Arena source code is distributed in the hope that it will be +useful, but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Foobar; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ +// +/* +======================================================================= + +DEMOS MENU + +======================================================================= +*/ + + +#include "ui_local.h" + + +#define ART_BACK0 "menu/art/back_0" +#define ART_BACK1 "menu/art/back_1" +#define ART_GO0 "menu/art/play_0" +#define ART_GO1 "menu/art/play_1" +#define ART_FRAMEL "menu/art/frame2_l" +#define ART_FRAMER "menu/art/frame1_r" +#define ART_ARROWS "menu/art/arrows_horz_0" +#define ART_ARROWLEFT "menu/art/arrows_horz_left" +#define ART_ARROWRIGHT "menu/art/arrows_horz_right" + +#define MAX_DEMOS 128 +#define NAMEBUFSIZE ( MAX_DEMOS * 16 ) + +#define ID_BACK 10 +#define ID_GO 11 +#define ID_LIST 12 +#define ID_RIGHT 13 +#define ID_LEFT 14 + +#define ARROWS_WIDTH 128 +#define ARROWS_HEIGHT 48 + + +typedef struct { + menuframework_s menu; + + menutext_s banner; + menubitmap_s framel; + menubitmap_s framer; + + menulist_s list; + + menubitmap_s arrows; + menubitmap_s left; + menubitmap_s right; + menubitmap_s back; + menubitmap_s go; + + int numDemos; + char names[NAMEBUFSIZE]; + char *demolist[MAX_DEMOS]; +} demos_t; + +static demos_t s_demos; + + +/* +=============== +Demos_MenuEvent +=============== +*/ +static void Demos_MenuEvent( void *ptr, int event ) { + if( event != QM_ACTIVATED ) { + return; + } + + switch( ((menucommon_s*)ptr)->id ) { + case ID_GO: + UI_ForceMenuOff (); + trap_Cmd_ExecuteText( EXEC_APPEND, va( "demo %s\n", + s_demos.list.itemnames[s_demos.list.curvalue]) ); + break; + + case ID_BACK: + UI_PopMenu(); + break; + + case ID_LEFT: + ScrollList_Key( &s_demos.list, K_LEFTARROW ); + break; + + case ID_RIGHT: + ScrollList_Key( &s_demos.list, K_RIGHTARROW ); + break; + } +} + + +/* +================= +UI_DemosMenu_Key +================= +*/ +static sfxHandle_t UI_DemosMenu_Key( int key ) { + menucommon_s *item; + + item = Menu_ItemAtCursor( &s_demos.menu ); + + return Menu_DefaultKey( &s_demos.menu, key ); +} + + +/* +=============== +Demos_MenuInit +=============== +*/ +static void Demos_MenuInit( void ) { + int i; + int len; + char *demoname, extension[32]; + + memset( &s_demos, 0 ,sizeof(demos_t) ); + s_demos.menu.key = UI_DemosMenu_Key; + + Demos_Cache(); + + s_demos.menu.fullscreen = qtrue; + s_demos.menu.wrapAround = qtrue; + + s_demos.banner.generic.type = MTYPE_BTEXT; + s_demos.banner.generic.x = 320; + s_demos.banner.generic.y = 16; + s_demos.banner.string = "DEMOS"; + s_demos.banner.color = color_white; + s_demos.banner.style = UI_CENTER; + + s_demos.framel.generic.type = MTYPE_BITMAP; + s_demos.framel.generic.name = ART_FRAMEL; + s_demos.framel.generic.flags = QMF_INACTIVE; + s_demos.framel.generic.x = 0; + s_demos.framel.generic.y = 78; + s_demos.framel.width = 256; + s_demos.framel.height = 329; + + s_demos.framer.generic.type = MTYPE_BITMAP; + s_demos.framer.generic.name = ART_FRAMER; + s_demos.framer.generic.flags = QMF_INACTIVE; + s_demos.framer.generic.x = 376; + s_demos.framer.generic.y = 76; + s_demos.framer.width = 256; + s_demos.framer.height = 334; + + s_demos.arrows.generic.type = MTYPE_BITMAP; + s_demos.arrows.generic.name = ART_ARROWS; + s_demos.arrows.generic.flags = QMF_INACTIVE; + s_demos.arrows.generic.x = 320-ARROWS_WIDTH/2; + s_demos.arrows.generic.y = 400; + s_demos.arrows.width = ARROWS_WIDTH; + s_demos.arrows.height = ARROWS_HEIGHT; + + s_demos.left.generic.type = MTYPE_BITMAP; + s_demos.left.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_MOUSEONLY; + s_demos.left.generic.x = 320-ARROWS_WIDTH/2; + s_demos.left.generic.y = 400; + s_demos.left.generic.id = ID_LEFT; + s_demos.left.generic.callback = Demos_MenuEvent; + s_demos.left.width = ARROWS_WIDTH/2; + s_demos.left.height = ARROWS_HEIGHT; + s_demos.left.focuspic = ART_ARROWLEFT; + + s_demos.right.generic.type = MTYPE_BITMAP; + s_demos.right.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_MOUSEONLY; + s_demos.right.generic.x = 320; + s_demos.right.generic.y = 400; + s_demos.right.generic.id = ID_RIGHT; + s_demos.right.generic.callback = Demos_MenuEvent; + s_demos.right.width = ARROWS_WIDTH/2; + s_demos.right.height = ARROWS_HEIGHT; + s_demos.right.focuspic = ART_ARROWRIGHT; + + s_demos.back.generic.type = MTYPE_BITMAP; + s_demos.back.generic.name = ART_BACK0; + s_demos.back.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS; + s_demos.back.generic.id = ID_BACK; + s_demos.back.generic.callback = Demos_MenuEvent; + s_demos.back.generic.x = 0; + s_demos.back.generic.y = 480-64; + s_demos.back.width = 128; + s_demos.back.height = 64; + s_demos.back.focuspic = ART_BACK1; + + s_demos.go.generic.type = MTYPE_BITMAP; + s_demos.go.generic.name = ART_GO0; + s_demos.go.generic.flags = QMF_RIGHT_JUSTIFY|QMF_PULSEIFFOCUS; + s_demos.go.generic.id = ID_GO; + s_demos.go.generic.callback = Demos_MenuEvent; + s_demos.go.generic.x = 640; + s_demos.go.generic.y = 480-64; + s_demos.go.width = 128; + s_demos.go.height = 64; + s_demos.go.focuspic = ART_GO1; + + s_demos.list.generic.type = MTYPE_SCROLLLIST; + s_demos.list.generic.flags = QMF_PULSEIFFOCUS; + s_demos.list.generic.callback = Demos_MenuEvent; + s_demos.list.generic.id = ID_LIST; + s_demos.list.generic.x = 118; + s_demos.list.generic.y = 130; + s_demos.list.width = 16; + s_demos.list.height = 14; + Com_sprintf(extension, sizeof(extension), "dm_%d", (int)trap_Cvar_VariableValue( "protocol" ) ); + s_demos.list.numitems = trap_FS_GetFileList( "demos", extension, s_demos.names, NAMEBUFSIZE ); + s_demos.list.itemnames = (const char **)s_demos.demolist; + s_demos.list.columns = 3; + + if (!s_demos.list.numitems) { + strcpy( s_demos.names, "No Demos Found." ); + s_demos.list.numitems = 1; + + //degenerate case, not selectable + s_demos.go.generic.flags |= (QMF_INACTIVE|QMF_HIDDEN); + } + else if (s_demos.list.numitems > MAX_DEMOS) + s_demos.list.numitems = MAX_DEMOS; + + demoname = s_demos.names; + for ( i = 0; i < s_demos.list.numitems; i++ ) { + s_demos.list.itemnames[i] = demoname; + + // strip extension + len = strlen( demoname ); + if (!Q_stricmp(demoname + len - 4,".dm3")) + demoname[len-4] = '\0'; + + Q_strupr(demoname); + + demoname += len + 1; + } + + Menu_AddItem( &s_demos.menu, &s_demos.banner ); + Menu_AddItem( &s_demos.menu, &s_demos.framel ); + Menu_AddItem( &s_demos.menu, &s_demos.framer ); + Menu_AddItem( &s_demos.menu, &s_demos.list ); + Menu_AddItem( &s_demos.menu, &s_demos.arrows ); + Menu_AddItem( &s_demos.menu, &s_demos.left ); + Menu_AddItem( &s_demos.menu, &s_demos.right ); + Menu_AddItem( &s_demos.menu, &s_demos.back ); + Menu_AddItem( &s_demos.menu, &s_demos.go ); +} + +/* +================= +Demos_Cache +================= +*/ +void Demos_Cache( void ) { + trap_R_RegisterShaderNoMip( ART_BACK0 ); + trap_R_RegisterShaderNoMip( ART_BACK1 ); + trap_R_RegisterShaderNoMip( ART_GO0 ); + trap_R_RegisterShaderNoMip( ART_GO1 ); + trap_R_RegisterShaderNoMip( ART_FRAMEL ); + trap_R_RegisterShaderNoMip( ART_FRAMER ); + trap_R_RegisterShaderNoMip( ART_ARROWS ); + trap_R_RegisterShaderNoMip( ART_ARROWLEFT ); + trap_R_RegisterShaderNoMip( ART_ARROWRIGHT ); +} + +/* +=============== +UI_DemosMenu +=============== +*/ +void UI_DemosMenu( void ) { + Demos_MenuInit(); + UI_PushMenu( &s_demos.menu ); +} diff --git a/code/q3_ui/ui_display.c b/code/q3_ui/ui_display.c new file mode 100755 index 0000000..9a8a49f --- /dev/null +++ b/code/q3_ui/ui_display.c @@ -0,0 +1,265 @@ +/* +=========================================================================== +Copyright (C) 1999-2005 Id Software, Inc. + +This file is part of Quake III Arena source code. + +Quake III Arena source code is free software; you can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 2 of the License, +or (at your option) any later version. + +Quake III Arena source code is distributed in the hope that it will be +useful, but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Foobar; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ +// +/* +======================================================================= + +DISPLAY OPTIONS MENU + +======================================================================= +*/ + +#include "ui_local.h" + + +#define ART_FRAMEL "menu/art/frame2_l" +#define ART_FRAMER "menu/art/frame1_r" +#define ART_BACK0 "menu/art/back_0" +#define ART_BACK1 "menu/art/back_1" + +#define ID_GRAPHICS 10 +#define ID_DISPLAY 11 +#define ID_SOUND 12 +#define ID_NETWORK 13 +#define ID_BRIGHTNESS 14 +#define ID_SCREENSIZE 15 +#define ID_BACK 16 + + +typedef struct { + menuframework_s menu; + + menutext_s banner; + menubitmap_s framel; + menubitmap_s framer; + + menutext_s graphics; + menutext_s display; + menutext_s sound; + menutext_s network; + + menuslider_s brightness; + menuslider_s screensize; + + menubitmap_s back; +} displayOptionsInfo_t; + +static displayOptionsInfo_t displayOptionsInfo; + + +/* +================= +UI_DisplayOptionsMenu_Event +================= +*/ +static void UI_DisplayOptionsMenu_Event( void* ptr, int event ) { + if( event != QM_ACTIVATED ) { + return; + } + + switch( ((menucommon_s*)ptr)->id ) { + case ID_GRAPHICS: + UI_PopMenu(); + UI_GraphicsOptionsMenu(); + break; + + case ID_DISPLAY: + break; + + case ID_SOUND: + UI_PopMenu(); + UI_SoundOptionsMenu(); + break; + + case ID_NETWORK: + UI_PopMenu(); + UI_NetworkOptionsMenu(); + break; + + case ID_BRIGHTNESS: + trap_Cvar_SetValue( "r_gamma", displayOptionsInfo.brightness.curvalue / 10.0f ); + break; + + case ID_SCREENSIZE: + trap_Cvar_SetValue( "cg_viewsize", displayOptionsInfo.screensize.curvalue * 10 ); + break; + + case ID_BACK: + UI_PopMenu(); + break; + } +} + + +/* +=============== +UI_DisplayOptionsMenu_Init +=============== +*/ +static void UI_DisplayOptionsMenu_Init( void ) { + int y; + + memset( &displayOptionsInfo, 0, sizeof(displayOptionsInfo) ); + + UI_DisplayOptionsMenu_Cache(); + displayOptionsInfo.menu.wrapAround = qtrue; + displayOptionsInfo.menu.fullscreen = qtrue; + + displayOptionsInfo.banner.generic.type = MTYPE_BTEXT; + displayOptionsInfo.banner.generic.flags = QMF_CENTER_JUSTIFY; + displayOptionsInfo.banner.generic.x = 320; + displayOptionsInfo.banner.generic.y = 16; + displayOptionsInfo.banner.string = "SYSTEM SETUP"; + displayOptionsInfo.banner.color = color_white; + displayOptionsInfo.banner.style = UI_CENTER; + + displayOptionsInfo.framel.generic.type = MTYPE_BITMAP; + displayOptionsInfo.framel.generic.name = ART_FRAMEL; + displayOptionsInfo.framel.generic.flags = QMF_INACTIVE; + displayOptionsInfo.framel.generic.x = 0; + displayOptionsInfo.framel.generic.y = 78; + displayOptionsInfo.framel.width = 256; + displayOptionsInfo.framel.height = 329; + + displayOptionsInfo.framer.generic.type = MTYPE_BITMAP; + displayOptionsInfo.framer.generic.name = ART_FRAMER; + displayOptionsInfo.framer.generic.flags = QMF_INACTIVE; + displayOptionsInfo.framer.generic.x = 376; + displayOptionsInfo.framer.generic.y = 76; + displayOptionsInfo.framer.width = 256; + displayOptionsInfo.framer.height = 334; + + displayOptionsInfo.graphics.generic.type = MTYPE_PTEXT; + displayOptionsInfo.graphics.generic.flags = QMF_RIGHT_JUSTIFY|QMF_PULSEIFFOCUS; + displayOptionsInfo.graphics.generic.id = ID_GRAPHICS; + displayOptionsInfo.graphics.generic.callback = UI_DisplayOptionsMenu_Event; + displayOptionsInfo.graphics.generic.x = 216; + displayOptionsInfo.graphics.generic.y = 240 - 2 * PROP_HEIGHT; + displayOptionsInfo.graphics.string = "GRAPHICS"; + displayOptionsInfo.graphics.style = UI_RIGHT; + displayOptionsInfo.graphics.color = color_red; + + displayOptionsInfo.display.generic.type = MTYPE_PTEXT; + displayOptionsInfo.display.generic.flags = QMF_RIGHT_JUSTIFY; + displayOptionsInfo.display.generic.id = ID_DISPLAY; + displayOptionsInfo.display.generic.callback = UI_DisplayOptionsMenu_Event; + displayOptionsInfo.display.generic.x = 216; + displayOptionsInfo.display.generic.y = 240 - PROP_HEIGHT; + displayOptionsInfo.display.string = "DISPLAY"; + displayOptionsInfo.display.style = UI_RIGHT; + displayOptionsInfo.display.color = color_red; + + displayOptionsInfo.sound.generic.type = MTYPE_PTEXT; + displayOptionsInfo.sound.generic.flags = QMF_RIGHT_JUSTIFY|QMF_PULSEIFFOCUS; + displayOptionsInfo.sound.generic.id = ID_SOUND; + displayOptionsInfo.sound.generic.callback = UI_DisplayOptionsMenu_Event; + displayOptionsInfo.sound.generic.x = 216; + displayOptionsInfo.sound.generic.y = 240; + displayOptionsInfo.sound.string = "SOUND"; + displayOptionsInfo.sound.style = UI_RIGHT; + displayOptionsInfo.sound.color = color_red; + + displayOptionsInfo.network.generic.type = MTYPE_PTEXT; + displayOptionsInfo.network.generic.flags = QMF_RIGHT_JUSTIFY|QMF_PULSEIFFOCUS; + displayOptionsInfo.network.generic.id = ID_NETWORK; + displayOptionsInfo.network.generic.callback = UI_DisplayOptionsMenu_Event; + displayOptionsInfo.network.generic.x = 216; + displayOptionsInfo.network.generic.y = 240 + PROP_HEIGHT; + displayOptionsInfo.network.string = "NETWORK"; + displayOptionsInfo.network.style = UI_RIGHT; + displayOptionsInfo.network.color = color_red; + + y = 240 - 1 * (BIGCHAR_HEIGHT+2); + displayOptionsInfo.brightness.generic.type = MTYPE_SLIDER; + displayOptionsInfo.brightness.generic.name = "Brightness:"; + displayOptionsInfo.brightness.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT; + displayOptionsInfo.brightness.generic.callback = UI_DisplayOptionsMenu_Event; + displayOptionsInfo.brightness.generic.id = ID_BRIGHTNESS; + displayOptionsInfo.brightness.generic.x = 400; + displayOptionsInfo.brightness.generic.y = y; + displayOptionsInfo.brightness.minvalue = 5; + displayOptionsInfo.brightness.maxvalue = 20; + if( !uis.glconfig.deviceSupportsGamma ) { + displayOptionsInfo.brightness.generic.flags |= QMF_GRAYED; + } + + y += BIGCHAR_HEIGHT+2; + displayOptionsInfo.screensize.generic.type = MTYPE_SLIDER; + displayOptionsInfo.screensize.generic.name = "Screen Size:"; + displayOptionsInfo.screensize.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT; + displayOptionsInfo.screensize.generic.callback = UI_DisplayOptionsMenu_Event; + displayOptionsInfo.screensize.generic.id = ID_SCREENSIZE; + displayOptionsInfo.screensize.generic.x = 400; + displayOptionsInfo.screensize.generic.y = y; + displayOptionsInfo.screensize.minvalue = 3; + displayOptionsInfo.screensize.maxvalue = 10; + + displayOptionsInfo.back.generic.type = MTYPE_BITMAP; + displayOptionsInfo.back.generic.name = ART_BACK0; + displayOptionsInfo.back.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS; + displayOptionsInfo.back.generic.callback = UI_DisplayOptionsMenu_Event; + displayOptionsInfo.back.generic.id = ID_BACK; + displayOptionsInfo.back.generic.x = 0; + displayOptionsInfo.back.generic.y = 480-64; + displayOptionsInfo.back.width = 128; + displayOptionsInfo.back.height = 64; + displayOptionsInfo.back.focuspic = ART_BACK1; + + Menu_AddItem( &displayOptionsInfo.menu, ( void * ) &displayOptionsInfo.banner ); + Menu_AddItem( &displayOptionsInfo.menu, ( void * ) &displayOptionsInfo.framel ); + Menu_AddItem( &displayOptionsInfo.menu, ( void * ) &displayOptionsInfo.framer ); + Menu_AddItem( &displayOptionsInfo.menu, ( void * ) &displayOptionsInfo.graphics ); + Menu_AddItem( &displayOptionsInfo.menu, ( void * ) &displayOptionsInfo.display ); + Menu_AddItem( &displayOptionsInfo.menu, ( void * ) &displayOptionsInfo.sound ); + Menu_AddItem( &displayOptionsInfo.menu, ( void * ) &displayOptionsInfo.network ); + Menu_AddItem( &displayOptionsInfo.menu, ( void * ) &displayOptionsInfo.brightness ); + Menu_AddItem( &displayOptionsInfo.menu, ( void * ) &displayOptionsInfo.screensize ); + Menu_AddItem( &displayOptionsInfo.menu, ( void * ) &displayOptionsInfo.back ); + + displayOptionsInfo.brightness.curvalue = trap_Cvar_VariableValue("r_gamma") * 10; + displayOptionsInfo.screensize.curvalue = trap_Cvar_VariableValue( "cg_viewsize")/10; +} + + +/* +=============== +UI_DisplayOptionsMenu_Cache +=============== +*/ +void UI_DisplayOptionsMenu_Cache( void ) { + trap_R_RegisterShaderNoMip( ART_FRAMEL ); + trap_R_RegisterShaderNoMip( ART_FRAMER ); + trap_R_RegisterShaderNoMip( ART_BACK0 ); + trap_R_RegisterShaderNoMip( ART_BACK1 ); +} + + +/* +=============== +UI_DisplayOptionsMenu +=============== +*/ +void UI_DisplayOptionsMenu( void ) { + UI_DisplayOptionsMenu_Init(); + UI_PushMenu( &displayOptionsInfo.menu ); + Menu_SetCursorToItem( &displayOptionsInfo.menu, &displayOptionsInfo.display ); +} diff --git a/code/q3_ui/ui_gameinfo.c b/code/q3_ui/ui_gameinfo.c new file mode 100755 index 0000000..29beddd --- /dev/null +++ b/code/q3_ui/ui_gameinfo.c @@ -0,0 +1,820 @@ +/* +=========================================================================== +Copyright (C) 1999-2005 Id Software, Inc. + +This file is part of Quake III Arena source code. + +Quake III Arena source code is free software; you can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 2 of the License, +or (at your option) any later version. + +Quake III Arena source code is distributed in the hope that it will be +useful, but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Foobar; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ +// +// +// gameinfo.c +// + +#include "ui_local.h" + + +// +// arena and bot info +// + +#define POOLSIZE 128 * 1024 + +int ui_numBots; +static char *ui_botInfos[MAX_BOTS]; + +static int ui_numArenas; +static char *ui_arenaInfos[MAX_ARENAS]; + +static int ui_numSinglePlayerArenas; +static int ui_numSpecialSinglePlayerArenas; + +static char memoryPool[POOLSIZE]; +static int allocPoint, outOfMemory; + + +/* +=============== +UI_Alloc +=============== +*/ +void *UI_Alloc( int size ) { + char *p; + + if ( allocPoint + size > POOLSIZE ) { + outOfMemory = qtrue; + return NULL; + } + + p = &memoryPool[allocPoint]; + + allocPoint += ( size + 31 ) & ~31; + + return p; +} + +/* +=============== +UI_InitMemory +=============== +*/ +void UI_InitMemory( void ) { + allocPoint = 0; + outOfMemory = qfalse; +} + +/* +=============== +UI_ParseInfos +=============== +*/ +int UI_ParseInfos( char *buf, int max, char *infos[] ) { + char *token; + int count; + char key[MAX_TOKEN_CHARS]; + char info[MAX_INFO_STRING]; + + count = 0; + + while ( 1 ) { + token = COM_Parse( &buf ); + if ( !token[0] ) { + break; + } + if ( strcmp( token, "{" ) ) { + Com_Printf( "Missing { in info file\n" ); + break; + } + + if ( count == max ) { + Com_Printf( "Max infos exceeded\n" ); + break; + } + + info[0] = '\0'; + while ( 1 ) { + token = COM_ParseExt( &buf, qtrue ); + if ( !token[0] ) { + Com_Printf( "Unexpected end of info file\n" ); + break; + } + if ( !strcmp( token, "}" ) ) { + break; + } + Q_strncpyz( key, token, sizeof( key ) ); + + token = COM_ParseExt( &buf, qfalse ); + if ( !token[0] ) { + strcpy( token, "" ); + } + Info_SetValueForKey( info, key, token ); + } + //NOTE: extra space for arena number + infos[count] = UI_Alloc(strlen(info) + strlen("\\num\\") + strlen(va("%d", MAX_ARENAS)) + 1); + if (infos[count]) { + strcpy(infos[count], info); + count++; + } + } + return count; +} + +/* +=============== +UI_LoadArenasFromFile +=============== +*/ +static void UI_LoadArenasFromFile( char *filename ) { + int len; + fileHandle_t f; + char buf[MAX_ARENAS_TEXT]; + + len = trap_FS_FOpenFile( filename, &f, FS_READ ); + if ( !f ) { + trap_Print( va( S_COLOR_RED "file not found: %s\n", filename ) ); + return; + } + if ( len >= MAX_ARENAS_TEXT ) { + trap_Print( va( S_COLOR_RED "file too large: %s is %i, max allowed is %i", filename, len, MAX_ARENAS_TEXT ) ); + trap_FS_FCloseFile( f ); + return; + } + + trap_FS_Read( buf, len, f ); + buf[len] = 0; + trap_FS_FCloseFile( f ); + + ui_numArenas += UI_ParseInfos( buf, MAX_ARENAS - ui_numArenas, &ui_arenaInfos[ui_numArenas] ); +} + +/* +=============== +UI_LoadArenas +=============== +*/ +static void UI_LoadArenas( void ) { + int numdirs; + vmCvar_t arenasFile; + char filename[128]; + char dirlist[1024]; + char* dirptr; + int i, n; + int dirlen; + char *type; + char *tag; + int singlePlayerNum, specialNum, otherNum; + + ui_numArenas = 0; + + trap_Cvar_Register( &arenasFile, "g_arenasFile", "", CVAR_INIT|CVAR_ROM ); + if( *arenasFile.string ) { + UI_LoadArenasFromFile(arenasFile.string); + } + else { + UI_LoadArenasFromFile("scripts/arenas.txt"); + } + + // get all arenas from .arena files + numdirs = trap_FS_GetFileList("scripts", ".arena", dirlist, 1024 ); + dirptr = dirlist; + for (i = 0; i < numdirs; i++, dirptr += dirlen+1) { + dirlen = strlen(dirptr); + strcpy(filename, "scripts/"); + strcat(filename, dirptr); + UI_LoadArenasFromFile(filename); + } + trap_Print( va( "%i arenas parsed\n", ui_numArenas ) ); + if (outOfMemory) trap_Print(S_COLOR_YELLOW"WARNING: not anough memory in pool to load all arenas\n"); + + // set initial numbers + for( n = 0; n < ui_numArenas; n++ ) { + Info_SetValueForKey( ui_arenaInfos[n], "num", va( "%i", n ) ); + } + + // go through and count single players levels + ui_numSinglePlayerArenas = 0; + ui_numSpecialSinglePlayerArenas = 0; + for( n = 0; n < ui_numArenas; n++ ) { + // determine type + type = Info_ValueForKey( ui_arenaInfos[n], "type" ); + + // if no type specified, it will be treated as "ffa" + if( !*type ) { + continue; + } + + if( strstr( type, "single" ) ) { + // check for special single player arenas (training, final) + tag = Info_ValueForKey( ui_arenaInfos[n], "special" ); + if( *tag ) { + ui_numSpecialSinglePlayerArenas++; + continue; + } + + ui_numSinglePlayerArenas++; + } + } + + n = ui_numSinglePlayerArenas % ARENAS_PER_TIER; + if( n != 0 ) { + ui_numSinglePlayerArenas -= n; + trap_Print( va( "%i arenas ignored to make count divisible by %i\n", n, ARENAS_PER_TIER ) ); + } + + // go through once more and assign number to the levels + singlePlayerNum = 0; + specialNum = singlePlayerNum + ui_numSinglePlayerArenas; + otherNum = specialNum + ui_numSpecialSinglePlayerArenas; + for( n = 0; n < ui_numArenas; n++ ) { + // determine type + type = Info_ValueForKey( ui_arenaInfos[n], "type" ); + + // if no type specified, it will be treated as "ffa" + if( *type ) { + if( strstr( type, "single" ) ) { + // check for special single player arenas (training, final) + tag = Info_ValueForKey( ui_arenaInfos[n], "special" ); + if( *tag ) { + Info_SetValueForKey( ui_arenaInfos[n], "num", va( "%i", specialNum++ ) ); + continue; + } + + Info_SetValueForKey( ui_arenaInfos[n], "num", va( "%i", singlePlayerNum++ ) ); + continue; + } + } + + Info_SetValueForKey( ui_arenaInfos[n], "num", va( "%i", otherNum++ ) ); + } +} + +/* +=============== +UI_GetArenaInfoByNumber +=============== +*/ +const char *UI_GetArenaInfoByNumber( int num ) { + int n; + char *value; + + if( num < 0 || num >= ui_numArenas ) { + trap_Print( va( S_COLOR_RED "Invalid arena number: %i\n", num ) ); + return NULL; + } + + for( n = 0; n < ui_numArenas; n++ ) { + value = Info_ValueForKey( ui_arenaInfos[n], "num" ); + if( *value && atoi(value) == num ) { + return ui_arenaInfos[n]; + } + } + + return NULL; +} + + +/* +=============== +UI_GetArenaInfoByNumber +=============== +*/ +const char *UI_GetArenaInfoByMap( const char *map ) { + int n; + + for( n = 0; n < ui_numArenas; n++ ) { + if( Q_stricmp( Info_ValueForKey( ui_arenaInfos[n], "map" ), map ) == 0 ) { + return ui_arenaInfos[n]; + } + } + + return NULL; +} + + +/* +=============== +UI_GetSpecialArenaInfo +=============== +*/ +const char *UI_GetSpecialArenaInfo( const char *tag ) { + int n; + + for( n = 0; n < ui_numArenas; n++ ) { + if( Q_stricmp( Info_ValueForKey( ui_arenaInfos[n], "special" ), tag ) == 0 ) { + return ui_arenaInfos[n]; + } + } + + return NULL; +} + +/* +=============== +UI_LoadBotsFromFile +=============== +*/ +static void UI_LoadBotsFromFile( char *filename ) { + int len; + fileHandle_t f; + char buf[MAX_BOTS_TEXT]; + + len = trap_FS_FOpenFile( filename, &f, FS_READ ); + if ( !f ) { + trap_Print( va( S_COLOR_RED "file not found: %s\n", filename ) ); + return; + } + if ( len >= MAX_BOTS_TEXT ) { + trap_Print( va( S_COLOR_RED "file too large: %s is %i, max allowed is %i", filename, len, MAX_BOTS_TEXT ) ); + trap_FS_FCloseFile( f ); + return; + } + + trap_FS_Read( buf, len, f ); + buf[len] = 0; + trap_FS_FCloseFile( f ); + + ui_numBots += UI_ParseInfos( buf, MAX_BOTS - ui_numBots, &ui_botInfos[ui_numBots] ); + if (outOfMemory) trap_Print(S_COLOR_YELLOW"WARNING: not anough memory in pool to load all bots\n"); +} + +/* +=============== +UI_LoadBots +=============== +*/ +static void UI_LoadBots( void ) { + vmCvar_t botsFile; + int numdirs; + char filename[128]; + char dirlist[1024]; + char* dirptr; + int i; + int dirlen; + + ui_numBots = 0; + + trap_Cvar_Register( &botsFile, "g_botsFile", "", CVAR_INIT|CVAR_ROM ); + if( *botsFile.string ) { + UI_LoadBotsFromFile(botsFile.string); + } + else { + UI_LoadBotsFromFile("scripts/bots.txt"); + } + + // get all bots from .bot files + numdirs = trap_FS_GetFileList("scripts", ".bot", dirlist, 1024 ); + dirptr = dirlist; + for (i = 0; i < numdirs; i++, dirptr += dirlen+1) { + dirlen = strlen(dirptr); + strcpy(filename, "scripts/"); + strcat(filename, dirptr); + UI_LoadBotsFromFile(filename); + } + trap_Print( va( "%i bots parsed\n", ui_numBots ) ); +} + + +/* +=============== +UI_GetBotInfoByNumber +=============== +*/ +char *UI_GetBotInfoByNumber( int num ) { + if( num < 0 || num >= ui_numBots ) { + trap_Print( va( S_COLOR_RED "Invalid bot number: %i\n", num ) ); + return NULL; + } + return ui_botInfos[num]; +} + + +/* +=============== +UI_GetBotInfoByName +=============== +*/ +char *UI_GetBotInfoByName( const char *name ) { + int n; + char *value; + + for ( n = 0; n < ui_numBots ; n++ ) { + value = Info_ValueForKey( ui_botInfos[n], "name" ); + if ( !Q_stricmp( value, name ) ) { + return ui_botInfos[n]; + } + } + + return NULL; +} + + +// +// single player game info +// + +/* +=============== +UI_GetBestScore + +Returns the player's best finish on a given level, 0 if the have not played the level +=============== +*/ +void UI_GetBestScore( int level, int *score, int *skill ) { + int n; + int skillScore; + int bestScore; + int bestScoreSkill; + char arenaKey[16]; + char scores[MAX_INFO_VALUE]; + + if( !score || !skill ) { + return; + } + + if( level < 0 || level > ui_numArenas ) { + return; + } + + bestScore = 0; + bestScoreSkill = 0; + + for( n = 1; n <= 5; n++ ) { + trap_Cvar_VariableStringBuffer( va( "g_spScores%i", n ), scores, MAX_INFO_VALUE ); + + Com_sprintf( arenaKey, sizeof( arenaKey ), "l%i", level ); + skillScore = atoi( Info_ValueForKey( scores, arenaKey ) ); + + if( skillScore < 1 || skillScore > 8 ) { + continue; + } + + if( !bestScore || skillScore <= bestScore ) { + bestScore = skillScore; + bestScoreSkill = n; + } + } + + *score = bestScore; + *skill = bestScoreSkill; +} + + +/* +=============== +UI_SetBestScore + +Set the player's best finish for a level +=============== +*/ +void UI_SetBestScore( int level, int score ) { + int skill; + int oldScore; + char arenaKey[16]; + char scores[MAX_INFO_VALUE]; + + // validate score + if( score < 1 || score > 8 ) { + return; + } + + // validate skill + skill = (int)trap_Cvar_VariableValue( "g_spSkill" ); + if( skill < 1 || skill > 5 ) { + return; + } + + // get scores + trap_Cvar_VariableStringBuffer( va( "g_spScores%i", skill ), scores, MAX_INFO_VALUE ); + + // see if this is better + Com_sprintf( arenaKey, sizeof( arenaKey ), "l%i", level ); + oldScore = atoi( Info_ValueForKey( scores, arenaKey ) ); + if( oldScore && oldScore <= score ) { + return; + } + + // update scores + Info_SetValueForKey( scores, arenaKey, va( "%i", score ) ); + trap_Cvar_Set( va( "g_spScores%i", skill ), scores ); +} + + +/* +=============== +UI_LogAwardData +=============== +*/ +void UI_LogAwardData( int award, int data ) { + char key[16]; + char awardData[MAX_INFO_VALUE]; + int oldValue; + + if( data == 0 ) { + return; + } + + if( award > AWARD_PERFECT ) { + trap_Print( va( S_COLOR_RED "Bad award %i in UI_LogAwardData\n", award ) ); + return; + } + + trap_Cvar_VariableStringBuffer( "g_spAwards", awardData, sizeof(awardData) ); + + Com_sprintf( key, sizeof(key), "a%i", award ); + oldValue = atoi( Info_ValueForKey( awardData, key ) ); + + Info_SetValueForKey( awardData, key, va( "%i", oldValue + data ) ); + trap_Cvar_Set( "g_spAwards", awardData ); +} + + +/* +=============== +UI_GetAwardLevel +=============== +*/ +int UI_GetAwardLevel( int award ) { + char key[16]; + char awardData[MAX_INFO_VALUE]; + + trap_Cvar_VariableStringBuffer( "g_spAwards", awardData, sizeof(awardData) ); + + Com_sprintf( key, sizeof(key), "a%i", award ); + return atoi( Info_ValueForKey( awardData, key ) ); +} + + +/* +=============== +UI_TierCompleted +=============== +*/ +int UI_TierCompleted( int levelWon ) { + int level; + int n; + int tier; + int score; + int skill; + const char *info; + + tier = levelWon / ARENAS_PER_TIER; + level = tier * ARENAS_PER_TIER; + + if( tier == UI_GetNumSPTiers() ) { + info = UI_GetSpecialArenaInfo( "training" ); + if( levelWon == atoi( Info_ValueForKey( info, "num" ) ) ) { + return 0; + } + info = UI_GetSpecialArenaInfo( "final" ); + if( !info || levelWon == atoi( Info_ValueForKey( info, "num" ) ) ) { + return tier + 1; + } + return -1; + } + + for( n = 0; n < ARENAS_PER_TIER; n++, level++ ) { + UI_GetBestScore( level, &score, &skill ); + if ( score != 1 ) { + return -1; + } + } + return tier + 1; +} + + +/* +=============== +UI_ShowTierVideo +=============== +*/ +qboolean UI_ShowTierVideo( int tier ) { + char key[16]; + char videos[MAX_INFO_VALUE]; + + if( tier <= 0 ) { + return qfalse; + } + + trap_Cvar_VariableStringBuffer( "g_spVideos", videos, sizeof(videos) ); + + Com_sprintf( key, sizeof(key), "tier%i", tier ); + if( atoi( Info_ValueForKey( videos, key ) ) ) { + return qfalse; + } + + Info_SetValueForKey( videos, key, va( "%i", 1 ) ); + trap_Cvar_Set( "g_spVideos", videos ); + + return qtrue; +} + + +/* +=============== +UI_CanShowTierVideo +=============== +*/ +qboolean UI_CanShowTierVideo( int tier ) { + char key[16]; + char videos[MAX_INFO_VALUE]; + + if( !tier ) { + return qfalse; + } + + if( uis.demoversion && tier != 8 ) { + return qfalse; + } + + trap_Cvar_VariableStringBuffer( "g_spVideos", videos, sizeof(videos) ); + + Com_sprintf( key, sizeof(key), "tier%i", tier ); + if( atoi( Info_ValueForKey( videos, key ) ) ) { + return qtrue; + } + + return qfalse; +} + + +/* +=============== +UI_GetCurrentGame + +Returns the next level the player has not won +=============== +*/ +int UI_GetCurrentGame( void ) { + int level; + int rank; + int skill; + const char *info; + + info = UI_GetSpecialArenaInfo( "training" ); + if( info ) { + level = atoi( Info_ValueForKey( info, "num" ) ); + UI_GetBestScore( level, &rank, &skill ); + if ( !rank || rank > 1 ) { + return level; + } + } + + for( level = 0; level < ui_numSinglePlayerArenas; level++ ) { + UI_GetBestScore( level, &rank, &skill ); + if ( !rank || rank > 1 ) { + return level; + } + } + + info = UI_GetSpecialArenaInfo( "final" ); + if( !info ) { + return -1; + } + return atoi( Info_ValueForKey( info, "num" ) ); +} + + +/* +=============== +UI_NewGame + +Clears the scores and sets the difficutly level +=============== +*/ +void UI_NewGame( void ) { + trap_Cvar_Set( "g_spScores1", "" ); + trap_Cvar_Set( "g_spScores2", "" ); + trap_Cvar_Set( "g_spScores3", "" ); + trap_Cvar_Set( "g_spScores4", "" ); + trap_Cvar_Set( "g_spScores5", "" ); + trap_Cvar_Set( "g_spAwards", "" ); + trap_Cvar_Set( "g_spVideos", "" ); +} + + +/* +=============== +UI_GetNumArenas +=============== +*/ +int UI_GetNumArenas( void ) { + return ui_numArenas; +} + + +/* +=============== +UI_GetNumSPArenas +=============== +*/ +int UI_GetNumSPArenas( void ) { + return ui_numSinglePlayerArenas; +} + + +/* +=============== +UI_GetNumSPTiers +=============== +*/ +int UI_GetNumSPTiers( void ) { + return ui_numSinglePlayerArenas / ARENAS_PER_TIER; +} + + +/* +=============== +UI_GetNumBots +=============== +*/ +int UI_GetNumBots( void ) { + return ui_numBots; +} + + +/* +=============== +UI_SPUnlock_f +=============== +*/ +void UI_SPUnlock_f( void ) { + char arenaKey[16]; + char scores[MAX_INFO_VALUE]; + int level; + int tier; + + // get scores for skill 1 + trap_Cvar_VariableStringBuffer( "g_spScores1", scores, MAX_INFO_VALUE ); + + // update scores + for( level = 0; level < ui_numSinglePlayerArenas + ui_numSpecialSinglePlayerArenas; level++ ) { + Com_sprintf( arenaKey, sizeof( arenaKey ), "l%i", level ); + Info_SetValueForKey( scores, arenaKey, "1" ); + } + trap_Cvar_Set( "g_spScores1", scores ); + + // unlock cinematics + for( tier = 1; tier <= 8; tier++ ) { + UI_ShowTierVideo( tier ); + } + + trap_Print( "All levels unlocked at skill level 1\n" ); + + UI_SPLevelMenu_ReInit(); +} + + +/* +=============== +UI_SPUnlockMedals_f +=============== +*/ +void UI_SPUnlockMedals_f( void ) { + int n; + char key[16]; + char awardData[MAX_INFO_VALUE]; + + trap_Cvar_VariableStringBuffer( "g_spAwards", awardData, MAX_INFO_VALUE ); + + for( n = 0; n < 6; n++ ) { + Com_sprintf( key, sizeof(key), "a%i", n ); + Info_SetValueForKey( awardData, key, "100" ); + } + + trap_Cvar_Set( "g_spAwards", awardData ); + + trap_Print( "All levels unlocked at 100\n" ); +} + + +/* +=============== +UI_InitGameinfo +=============== +*/ +void UI_InitGameinfo( void ) { + + UI_InitMemory(); + UI_LoadArenas(); + UI_LoadBots(); + + if( (trap_Cvar_VariableValue( "fs_restrict" )) || (ui_numSpecialSinglePlayerArenas == 0 && ui_numSinglePlayerArenas == 4) ) { + uis.demoversion = qtrue; + } + else { + uis.demoversion = qfalse; + } +} diff --git a/code/q3_ui/ui_ingame.c b/code/q3_ui/ui_ingame.c new file mode 100755 index 0000000..c5c6b06 --- /dev/null +++ b/code/q3_ui/ui_ingame.c @@ -0,0 +1,349 @@ +/* +=========================================================================== +Copyright (C) 1999-2005 Id Software, Inc. + +This file is part of Quake III Arena source code. + +Quake III Arena source code is free software; you can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 2 of the License, +or (at your option) any later version. + +Quake III Arena source code is distributed in the hope that it will be +useful, but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Foobar; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ +// +/* +======================================================================= + +INGAME MENU + +======================================================================= +*/ + + +#include "ui_local.h" + + +#define INGAME_FRAME "menu/art/addbotframe" +//#define INGAME_FRAME "menu/art/cut_frame" +#define INGAME_MENU_VERTICAL_SPACING 28 + +#define ID_TEAM 10 +#define ID_ADDBOTS 11 +#define ID_REMOVEBOTS 12 +#define ID_SETUP 13 +#define ID_SERVERINFO 14 +#define ID_LEAVEARENA 15 +#define ID_RESTART 16 +#define ID_QUIT 17 +#define ID_RESUME 18 +#define ID_TEAMORDERS 19 + + +typedef struct { + menuframework_s menu; + + menubitmap_s frame; + menutext_s team; + menutext_s setup; + menutext_s server; + menutext_s leave; + menutext_s restart; + menutext_s addbots; + menutext_s removebots; + menutext_s teamorders; + menutext_s quit; + menutext_s resume; +} ingamemenu_t; + +static ingamemenu_t s_ingame; + + +/* +================= +InGame_RestartAction +================= +*/ +static void InGame_RestartAction( qboolean result ) { + if( !result ) { + return; + } + + UI_PopMenu(); + trap_Cmd_ExecuteText( EXEC_APPEND, "map_restart 0\n" ); +} + + +/* +================= +InGame_QuitAction +================= +*/ +static void InGame_QuitAction( qboolean result ) { + if( !result ) { + return; + } + UI_PopMenu(); + UI_CreditMenu(); +} + + +/* +================= +InGame_Event +================= +*/ +void InGame_Event( void *ptr, int notification ) { + if( notification != QM_ACTIVATED ) { + return; + } + + switch( ((menucommon_s*)ptr)->id ) { + case ID_TEAM: + UI_TeamMainMenu(); + break; + + case ID_SETUP: + UI_SetupMenu(); + break; + + case ID_LEAVEARENA: + trap_Cmd_ExecuteText( EXEC_APPEND, "disconnect\n" ); + break; + + case ID_RESTART: + UI_ConfirmMenu( "RESTART ARENA?", (voidfunc_f)NULL, InGame_RestartAction ); + break; + + case ID_QUIT: + UI_ConfirmMenu( "EXIT GAME?", (voidfunc_f)NULL, InGame_QuitAction ); + break; + + case ID_SERVERINFO: + UI_ServerInfoMenu(); + break; + + case ID_ADDBOTS: + UI_AddBotsMenu(); + break; + + case ID_REMOVEBOTS: + UI_RemoveBotsMenu(); + break; + + case ID_TEAMORDERS: + UI_TeamOrdersMenu(); + break; + + case ID_RESUME: + UI_PopMenu(); + break; + } +} + + +/* +================= +InGame_MenuInit +================= +*/ +void InGame_MenuInit( void ) { + int y; + uiClientState_t cs; + char info[MAX_INFO_STRING]; + int team; + + memset( &s_ingame, 0 ,sizeof(ingamemenu_t) ); + + InGame_Cache(); + + s_ingame.menu.wrapAround = qtrue; + s_ingame.menu.fullscreen = qfalse; + + s_ingame.frame.generic.type = MTYPE_BITMAP; + s_ingame.frame.generic.flags = QMF_INACTIVE; + s_ingame.frame.generic.name = INGAME_FRAME; + s_ingame.frame.generic.x = 320-233;//142; + s_ingame.frame.generic.y = 240-166;//118; + s_ingame.frame.width = 466;//359; + s_ingame.frame.height = 332;//256; + + //y = 96; + y = 88; + s_ingame.team.generic.type = MTYPE_PTEXT; + s_ingame.team.generic.flags = QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS; + s_ingame.team.generic.x = 320; + s_ingame.team.generic.y = y; + s_ingame.team.generic.id = ID_TEAM; + s_ingame.team.generic.callback = InGame_Event; + s_ingame.team.string = "START"; + s_ingame.team.color = color_red; + s_ingame.team.style = UI_CENTER|UI_SMALLFONT; + + y += INGAME_MENU_VERTICAL_SPACING; + s_ingame.addbots.generic.type = MTYPE_PTEXT; + s_ingame.addbots.generic.flags = QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS; + s_ingame.addbots.generic.x = 320; + s_ingame.addbots.generic.y = y; + s_ingame.addbots.generic.id = ID_ADDBOTS; + s_ingame.addbots.generic.callback = InGame_Event; + s_ingame.addbots.string = "ADD BOTS"; + s_ingame.addbots.color = color_red; + s_ingame.addbots.style = UI_CENTER|UI_SMALLFONT; + if( !trap_Cvar_VariableValue( "sv_running" ) || !trap_Cvar_VariableValue( "bot_enable" ) || (trap_Cvar_VariableValue( "g_gametype" ) == GT_SINGLE_PLAYER)) { + s_ingame.addbots.generic.flags |= QMF_GRAYED; + } + + y += INGAME_MENU_VERTICAL_SPACING; + s_ingame.removebots.generic.type = MTYPE_PTEXT; + s_ingame.removebots.generic.flags = QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS; + s_ingame.removebots.generic.x = 320; + s_ingame.removebots.generic.y = y; + s_ingame.removebots.generic.id = ID_REMOVEBOTS; + s_ingame.removebots.generic.callback = InGame_Event; + s_ingame.removebots.string = "REMOVE BOTS"; + s_ingame.removebots.color = color_red; + s_ingame.removebots.style = UI_CENTER|UI_SMALLFONT; + if( !trap_Cvar_VariableValue( "sv_running" ) || !trap_Cvar_VariableValue( "bot_enable" ) || (trap_Cvar_VariableValue( "g_gametype" ) == GT_SINGLE_PLAYER)) { + s_ingame.removebots.generic.flags |= QMF_GRAYED; + } + + y += INGAME_MENU_VERTICAL_SPACING; + s_ingame.teamorders.generic.type = MTYPE_PTEXT; + s_ingame.teamorders.generic.flags = QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS; + s_ingame.teamorders.generic.x = 320; + s_ingame.teamorders.generic.y = y; + s_ingame.teamorders.generic.id = ID_TEAMORDERS; + s_ingame.teamorders.generic.callback = InGame_Event; + s_ingame.teamorders.string = "TEAM ORDERS"; + s_ingame.teamorders.color = color_red; + s_ingame.teamorders.style = UI_CENTER|UI_SMALLFONT; + if( !(trap_Cvar_VariableValue( "g_gametype" ) >= GT_TEAM) ) { + s_ingame.teamorders.generic.flags |= QMF_GRAYED; + } + else { + trap_GetClientState( &cs ); + trap_GetConfigString( CS_PLAYERS + cs.clientNum, info, MAX_INFO_STRING ); + team = atoi( Info_ValueForKey( info, "t" ) ); + if( team == TEAM_SPECTATOR ) { + s_ingame.teamorders.generic.flags |= QMF_GRAYED; + } + } + + y += INGAME_MENU_VERTICAL_SPACING; + s_ingame.setup.generic.type = MTYPE_PTEXT; + s_ingame.setup.generic.flags = QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS; + s_ingame.setup.generic.x = 320; + s_ingame.setup.generic.y = y; + s_ingame.setup.generic.id = ID_SETUP; + s_ingame.setup.generic.callback = InGame_Event; + s_ingame.setup.string = "SETUP"; + s_ingame.setup.color = color_red; + s_ingame.setup.style = UI_CENTER|UI_SMALLFONT; + + y += INGAME_MENU_VERTICAL_SPACING; + s_ingame.server.generic.type = MTYPE_PTEXT; + s_ingame.server.generic.flags = QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS; + s_ingame.server.generic.x = 320; + s_ingame.server.generic.y = y; + s_ingame.server.generic.id = ID_SERVERINFO; + s_ingame.server.generic.callback = InGame_Event; + s_ingame.server.string = "SERVER INFO"; + s_ingame.server.color = color_red; + s_ingame.server.style = UI_CENTER|UI_SMALLFONT; + + y += INGAME_MENU_VERTICAL_SPACING; + s_ingame.restart.generic.type = MTYPE_PTEXT; + s_ingame.restart.generic.flags = QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS; + s_ingame.restart.generic.x = 320; + s_ingame.restart.generic.y = y; + s_ingame.restart.generic.id = ID_RESTART; + s_ingame.restart.generic.callback = InGame_Event; + s_ingame.restart.string = "RESTART ARENA"; + s_ingame.restart.color = color_red; + s_ingame.restart.style = UI_CENTER|UI_SMALLFONT; + if( !trap_Cvar_VariableValue( "sv_running" ) ) { + s_ingame.restart.generic.flags |= QMF_GRAYED; + } + + y += INGAME_MENU_VERTICAL_SPACING; + s_ingame.resume.generic.type = MTYPE_PTEXT; + s_ingame.resume.generic.flags = QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS; + s_ingame.resume.generic.x = 320; + s_ingame.resume.generic.y = y; + s_ingame.resume.generic.id = ID_RESUME; + s_ingame.resume.generic.callback = InGame_Event; + s_ingame.resume.string = "RESUME GAME"; + s_ingame.resume.color = color_red; + s_ingame.resume.style = UI_CENTER|UI_SMALLFONT; + + y += INGAME_MENU_VERTICAL_SPACING; + s_ingame.leave.generic.type = MTYPE_PTEXT; + s_ingame.leave.generic.flags = QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS; + s_ingame.leave.generic.x = 320; + s_ingame.leave.generic.y = y; + s_ingame.leave.generic.id = ID_LEAVEARENA; + s_ingame.leave.generic.callback = InGame_Event; + s_ingame.leave.string = "LEAVE ARENA"; + s_ingame.leave.color = color_red; + s_ingame.leave.style = UI_CENTER|UI_SMALLFONT; + + y += INGAME_MENU_VERTICAL_SPACING; + s_ingame.quit.generic.type = MTYPE_PTEXT; + s_ingame.quit.generic.flags = QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS; + s_ingame.quit.generic.x = 320; + s_ingame.quit.generic.y = y; + s_ingame.quit.generic.id = ID_QUIT; + s_ingame.quit.generic.callback = InGame_Event; + s_ingame.quit.string = "EXIT GAME"; + s_ingame.quit.color = color_red; + s_ingame.quit.style = UI_CENTER|UI_SMALLFONT; + + Menu_AddItem( &s_ingame.menu, &s_ingame.frame ); + Menu_AddItem( &s_ingame.menu, &s_ingame.team ); + Menu_AddItem( &s_ingame.menu, &s_ingame.addbots ); + Menu_AddItem( &s_ingame.menu, &s_ingame.removebots ); + Menu_AddItem( &s_ingame.menu, &s_ingame.teamorders ); + Menu_AddItem( &s_ingame.menu, &s_ingame.setup ); + Menu_AddItem( &s_ingame.menu, &s_ingame.server ); + Menu_AddItem( &s_ingame.menu, &s_ingame.restart ); + Menu_AddItem( &s_ingame.menu, &s_ingame.resume ); + Menu_AddItem( &s_ingame.menu, &s_ingame.leave ); + Menu_AddItem( &s_ingame.menu, &s_ingame.quit ); +} + + +/* +================= +InGame_Cache +================= +*/ +void InGame_Cache( void ) { + trap_R_RegisterShaderNoMip( INGAME_FRAME ); +} + + +/* +================= +UI_InGameMenu +================= +*/ +void UI_InGameMenu( void ) { + // force as top level menu + uis.menusp = 0; + + // set menu cursor to a nice location + uis.cursorx = 319; + uis.cursory = 80; + + InGame_MenuInit(); + UI_PushMenu( &s_ingame.menu ); +} diff --git a/code/q3_ui/ui_loadconfig.c b/code/q3_ui/ui_loadconfig.c new file mode 100755 index 0000000..24aff9f --- /dev/null +++ b/code/q3_ui/ui_loadconfig.c @@ -0,0 +1,274 @@ +/* +=========================================================================== +Copyright (C) 1999-2005 Id Software, Inc. + +This file is part of Quake III Arena source code. + +Quake III Arena source code is free software; you can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 2 of the License, +or (at your option) any later version. + +Quake III Arena source code is distributed in the hope that it will be +useful, but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Foobar; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ +// +/* +============================================================================= + +LOAD CONFIG MENU + +============================================================================= +*/ + +#include "ui_local.h" + + +#define ART_BACK0 "menu/art/back_0" +#define ART_BACK1 "menu/art/back_1" +#define ART_FIGHT0 "menu/art/load_0" +#define ART_FIGHT1 "menu/art/load_1" +#define ART_FRAMEL "menu/art/frame2_l" +#define ART_FRAMER "menu/art/frame1_r" +#define ART_ARROWS "menu/art/arrows_horz_0" +#define ART_ARROWLEFT "menu/art/arrows_horz_left" +#define ART_ARROWRIGHT "menu/art/arrows_horz_right" + +#define MAX_CONFIGS 128 +#define NAMEBUFSIZE ( MAX_CONFIGS * 16 ) + +#define ID_BACK 10 +#define ID_GO 11 +#define ID_LIST 12 +#define ID_LEFT 13 +#define ID_RIGHT 14 + +#define ARROWS_WIDTH 128 +#define ARROWS_HEIGHT 48 + + +typedef struct { + menuframework_s menu; + + menutext_s banner; + menubitmap_s framel; + menubitmap_s framer; + + menulist_s list; + + menubitmap_s arrows; + menubitmap_s left; + menubitmap_s right; + menubitmap_s back; + menubitmap_s go; + + char names[NAMEBUFSIZE]; + char* configlist[MAX_CONFIGS]; +} configs_t; + +static configs_t s_configs; + + +/* +=============== +LoadConfig_MenuEvent +=============== +*/ +static void LoadConfig_MenuEvent( void *ptr, int event ) { + if( event != QM_ACTIVATED ) { + return; + } + + switch ( ((menucommon_s*)ptr)->id ) { + case ID_GO: + trap_Cmd_ExecuteText( EXEC_APPEND, va( "exec %s\n", s_configs.list.itemnames[s_configs.list.curvalue] ) ); + UI_PopMenu(); + break; + + case ID_BACK: + UI_PopMenu(); + break; + + case ID_LEFT: + ScrollList_Key( &s_configs.list, K_LEFTARROW ); + break; + + case ID_RIGHT: + ScrollList_Key( &s_configs.list, K_RIGHTARROW ); + break; + } +} + + +/* +=============== +LoadConfig_MenuInit +=============== +*/ +static void LoadConfig_MenuInit( void ) { + int i; + int len; + char *configname; + + UI_LoadConfig_Cache(); + + memset( &s_configs, 0 ,sizeof(configs_t) ); + s_configs.menu.wrapAround = qtrue; + s_configs.menu.fullscreen = qtrue; + + s_configs.banner.generic.type = MTYPE_BTEXT; + s_configs.banner.generic.x = 320; + s_configs.banner.generic.y = 16; + s_configs.banner.string = "LOAD CONFIG"; + s_configs.banner.color = color_white; + s_configs.banner.style = UI_CENTER; + + s_configs.framel.generic.type = MTYPE_BITMAP; + s_configs.framel.generic.name = ART_FRAMEL; + s_configs.framel.generic.flags = QMF_INACTIVE; + s_configs.framel.generic.x = 0; + s_configs.framel.generic.y = 78; + s_configs.framel.width = 256; + s_configs.framel.height = 329; + + s_configs.framer.generic.type = MTYPE_BITMAP; + s_configs.framer.generic.name = ART_FRAMER; + s_configs.framer.generic.flags = QMF_INACTIVE; + s_configs.framer.generic.x = 376; + s_configs.framer.generic.y = 76; + s_configs.framer.width = 256; + s_configs.framer.height = 334; + + s_configs.arrows.generic.type = MTYPE_BITMAP; + s_configs.arrows.generic.name = ART_ARROWS; + s_configs.arrows.generic.flags = QMF_INACTIVE; + s_configs.arrows.generic.x = 320-ARROWS_WIDTH/2; + s_configs.arrows.generic.y = 400; + s_configs.arrows.width = ARROWS_WIDTH; + s_configs.arrows.height = ARROWS_HEIGHT; + + s_configs.left.generic.type = MTYPE_BITMAP; + s_configs.left.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_MOUSEONLY; + s_configs.left.generic.x = 320-ARROWS_WIDTH/2; + s_configs.left.generic.y = 400; + s_configs.left.generic.id = ID_LEFT; + s_configs.left.generic.callback = LoadConfig_MenuEvent; + s_configs.left.width = ARROWS_WIDTH/2; + s_configs.left.height = ARROWS_HEIGHT; + s_configs.left.focuspic = ART_ARROWLEFT; + + s_configs.right.generic.type = MTYPE_BITMAP; + s_configs.right.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_MOUSEONLY; + s_configs.right.generic.x = 320; + s_configs.right.generic.y = 400; + s_configs.right.generic.id = ID_RIGHT; + s_configs.right.generic.callback = LoadConfig_MenuEvent; + s_configs.right.width = ARROWS_WIDTH/2; + s_configs.right.height = ARROWS_HEIGHT; + s_configs.right.focuspic = ART_ARROWRIGHT; + + s_configs.back.generic.type = MTYPE_BITMAP; + s_configs.back.generic.name = ART_BACK0; + s_configs.back.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS; + s_configs.back.generic.id = ID_BACK; + s_configs.back.generic.callback = LoadConfig_MenuEvent; + s_configs.back.generic.x = 0; + s_configs.back.generic.y = 480-64; + s_configs.back.width = 128; + s_configs.back.height = 64; + s_configs.back.focuspic = ART_BACK1; + + s_configs.go.generic.type = MTYPE_BITMAP; + s_configs.go.generic.name = ART_FIGHT0; + s_configs.go.generic.flags = QMF_RIGHT_JUSTIFY|QMF_PULSEIFFOCUS; + s_configs.go.generic.id = ID_GO; + s_configs.go.generic.callback = LoadConfig_MenuEvent; + s_configs.go.generic.x = 640; + s_configs.go.generic.y = 480-64; + s_configs.go.width = 128; + s_configs.go.height = 64; + s_configs.go.focuspic = ART_FIGHT1; + + // scan for configs + s_configs.list.generic.type = MTYPE_SCROLLLIST; + s_configs.list.generic.flags = QMF_PULSEIFFOCUS; + s_configs.list.generic.callback = LoadConfig_MenuEvent; + s_configs.list.generic.id = ID_LIST; + s_configs.list.generic.x = 118; + s_configs.list.generic.y = 130; + s_configs.list.width = 16; + s_configs.list.height = 14; + s_configs.list.numitems = trap_FS_GetFileList( "", "cfg", s_configs.names, NAMEBUFSIZE ); + s_configs.list.itemnames = (const char **)s_configs.configlist; + s_configs.list.columns = 3; + + if (!s_configs.list.numitems) { + strcpy(s_configs.names,"No Files Found."); + s_configs.list.numitems = 1; + + //degenerate case, not selectable + s_configs.go.generic.flags |= (QMF_INACTIVE|QMF_HIDDEN); + } + else if (s_configs.list.numitems > MAX_CONFIGS) + s_configs.list.numitems = MAX_CONFIGS; + + configname = s_configs.names; + for ( i = 0; i < s_configs.list.numitems; i++ ) { + s_configs.list.itemnames[i] = configname; + + // strip extension + len = strlen( configname ); + if (!Q_stricmp(configname + len - 4,".cfg")) + configname[len-4] = '\0'; + + Q_strupr(configname); + + configname += len + 1; + } + + Menu_AddItem( &s_configs.menu, &s_configs.banner ); + Menu_AddItem( &s_configs.menu, &s_configs.framel ); + Menu_AddItem( &s_configs.menu, &s_configs.framer ); + Menu_AddItem( &s_configs.menu, &s_configs.list ); + Menu_AddItem( &s_configs.menu, &s_configs.arrows ); + Menu_AddItem( &s_configs.menu, &s_configs.left ); + Menu_AddItem( &s_configs.menu, &s_configs.right ); + Menu_AddItem( &s_configs.menu, &s_configs.back ); + Menu_AddItem( &s_configs.menu, &s_configs.go ); +} + +/* +================= +UI_LoadConfig_Cache +================= +*/ +void UI_LoadConfig_Cache( void ) { + trap_R_RegisterShaderNoMip( ART_BACK0 ); + trap_R_RegisterShaderNoMip( ART_BACK1 ); + trap_R_RegisterShaderNoMip( ART_FIGHT0 ); + trap_R_RegisterShaderNoMip( ART_FIGHT1 ); + trap_R_RegisterShaderNoMip( ART_FRAMEL ); + trap_R_RegisterShaderNoMip( ART_FRAMER ); + trap_R_RegisterShaderNoMip( ART_ARROWS ); + trap_R_RegisterShaderNoMip( ART_ARROWLEFT ); + trap_R_RegisterShaderNoMip( ART_ARROWRIGHT ); +} + + +/* +=============== +UI_LoadConfigMenu +=============== +*/ +void UI_LoadConfigMenu( void ) { + LoadConfig_MenuInit(); + UI_PushMenu( &s_configs.menu ); +} + diff --git a/code/q3_ui/ui_local.h b/code/q3_ui/ui_local.h new file mode 100755 index 0000000..71ea0de --- /dev/null +++ b/code/q3_ui/ui_local.h @@ -0,0 +1,800 @@ +/* +=========================================================================== +Copyright (C) 1999-2005 Id Software, Inc. + +This file is part of Quake III Arena source code. + +Quake III Arena source code is free software; you can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 2 of the License, +or (at your option) any later version. + +Quake III Arena source code is distributed in the hope that it will be +useful, but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Foobar; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ +// +#ifndef __UI_LOCAL_H__ +#define __UI_LOCAL_H__ + +#include "../game/q_shared.h" +#include "../cgame/tr_types.h" +//NOTE: include the ui_public.h from the new UI +#include "../ui/ui_public.h" // bk001205 - yes, do have to use this +//redefine to old API version +#undef UI_API_VERSION +#define UI_API_VERSION 4 +#include "keycodes.h" +#include "../game/bg_public.h" + +typedef void (*voidfunc_f)(void); + +extern vmCvar_t ui_ffa_fraglimit; +extern vmCvar_t ui_ffa_timelimit; + +extern vmCvar_t ui_tourney_fraglimit; +extern vmCvar_t ui_tourney_timelimit; + +extern vmCvar_t ui_team_fraglimit; +extern vmCvar_t ui_team_timelimit; +extern vmCvar_t ui_team_friendly; + +extern vmCvar_t ui_ctf_capturelimit; +extern vmCvar_t ui_ctf_timelimit; +extern vmCvar_t ui_ctf_friendly; + +extern vmCvar_t ui_arenasFile; +extern vmCvar_t ui_botsFile; +extern vmCvar_t ui_spScores1; +extern vmCvar_t ui_spScores2; +extern vmCvar_t ui_spScores3; +extern vmCvar_t ui_spScores4; +extern vmCvar_t ui_spScores5; +extern vmCvar_t ui_spAwards; +extern vmCvar_t ui_spVideos; +extern vmCvar_t ui_spSkill; + +extern vmCvar_t ui_spSelection; + +extern vmCvar_t ui_browserMaster; +extern vmCvar_t ui_browserGameType; +extern vmCvar_t ui_browserSortKey; +extern vmCvar_t ui_browserShowFull; +extern vmCvar_t ui_browserShowEmpty; + +extern vmCvar_t ui_brassTime; +extern vmCvar_t ui_drawCrosshair; +extern vmCvar_t ui_drawCrosshairNames; +extern vmCvar_t ui_marks; + +extern vmCvar_t ui_server1; +extern vmCvar_t ui_server2; +extern vmCvar_t ui_server3; +extern vmCvar_t ui_server4; +extern vmCvar_t ui_server5; +extern vmCvar_t ui_server6; +extern vmCvar_t ui_server7; +extern vmCvar_t ui_server8; +extern vmCvar_t ui_server9; +extern vmCvar_t ui_server10; +extern vmCvar_t ui_server11; +extern vmCvar_t ui_server12; +extern vmCvar_t ui_server13; +extern vmCvar_t ui_server14; +extern vmCvar_t ui_server15; +extern vmCvar_t ui_server16; + +extern vmCvar_t ui_cdkey; +extern vmCvar_t ui_cdkeychecked; + + +// +// ui_qmenu.c +// + +#define RCOLUMN_OFFSET ( BIGCHAR_WIDTH ) +#define LCOLUMN_OFFSET (-BIGCHAR_WIDTH ) + +#define SLIDER_RANGE 10 +#define MAX_EDIT_LINE 256 + +#define MAX_MENUDEPTH 8 +#define MAX_MENUITEMS 64 + +#define MTYPE_NULL 0 +#define MTYPE_SLIDER 1 +#define MTYPE_ACTION 2 +#define MTYPE_SPINCONTROL 3 +#define MTYPE_FIELD 4 +#define MTYPE_RADIOBUTTON 5 +#define MTYPE_BITMAP 6 +#define MTYPE_TEXT 7 +#define MTYPE_SCROLLLIST 8 +#define MTYPE_PTEXT 9 +#define MTYPE_BTEXT 10 + +#define QMF_BLINK 0x00000001 +#define QMF_SMALLFONT 0x00000002 +#define QMF_LEFT_JUSTIFY 0x00000004 +#define QMF_CENTER_JUSTIFY 0x00000008 +#define QMF_RIGHT_JUSTIFY 0x00000010 +#define QMF_NUMBERSONLY 0x00000020 // edit field is only numbers +#define QMF_HIGHLIGHT 0x00000040 +#define QMF_HIGHLIGHT_IF_FOCUS 0x00000080 // steady focus +#define QMF_PULSEIFFOCUS 0x00000100 // pulse if focus +#define QMF_HASMOUSEFOCUS 0x00000200 +#define QMF_NOONOFFTEXT 0x00000400 +#define QMF_MOUSEONLY 0x00000800 // only mouse input allowed +#define QMF_HIDDEN 0x00001000 // skips drawing +#define QMF_GRAYED 0x00002000 // grays and disables +#define QMF_INACTIVE 0x00004000 // disables any input +#define QMF_NODEFAULTINIT 0x00008000 // skip default initialization +#define QMF_OWNERDRAW 0x00010000 +#define QMF_PULSE 0x00020000 +#define QMF_LOWERCASE 0x00040000 // edit field is all lower case +#define QMF_UPPERCASE 0x00080000 // edit field is all upper case +#define QMF_SILENT 0x00100000 + +// callback notifications +#define QM_GOTFOCUS 1 +#define QM_LOSTFOCUS 2 +#define QM_ACTIVATED 3 + +typedef struct _tag_menuframework +{ + int cursor; + int cursor_prev; + + int nitems; + void *items[MAX_MENUITEMS]; + + void (*draw) (void); + sfxHandle_t (*key) (int key); + + qboolean wrapAround; + qboolean fullscreen; + qboolean showlogo; +} menuframework_s; + +typedef struct +{ + int type; + const char *name; + int id; + int x, y; + int left; + int top; + int right; + int bottom; + menuframework_s *parent; + int menuPosition; + unsigned flags; + + void (*callback)( void *self, int event ); + void (*statusbar)( void *self ); + void (*ownerdraw)( void *self ); +} menucommon_s; + +typedef struct { + int cursor; + int scroll; + int widthInChars; + char buffer[MAX_EDIT_LINE]; + int maxchars; +} mfield_t; + +typedef struct +{ + menucommon_s generic; + mfield_t field; +} menufield_s; + +typedef struct +{ + menucommon_s generic; + + float minvalue; + float maxvalue; + float curvalue; + + float range; +} menuslider_s; + +typedef struct +{ + menucommon_s generic; + + int oldvalue; + int curvalue; + int numitems; + int top; + + const char **itemnames; + + int width; + int height; + int columns; + int seperation; +} menulist_s; + +typedef struct +{ + menucommon_s generic; +} menuaction_s; + +typedef struct +{ + menucommon_s generic; + int curvalue; +} menuradiobutton_s; + +typedef struct +{ + menucommon_s generic; + char* focuspic; + char* errorpic; + qhandle_t shader; + qhandle_t focusshader; + int width; + int height; + float* focuscolor; +} menubitmap_s; + +typedef struct +{ + menucommon_s generic; + char* string; + int style; + float* color; +} menutext_s; + +extern void Menu_Cache( void ); +extern void Menu_Focus( menucommon_s *m ); +extern void Menu_AddItem( menuframework_s *menu, void *item ); +extern void Menu_AdjustCursor( menuframework_s *menu, int dir ); +extern void Menu_Draw( menuframework_s *menu ); +extern void *Menu_ItemAtCursor( menuframework_s *m ); +extern sfxHandle_t Menu_ActivateItem( menuframework_s *s, menucommon_s* item ); +extern void Menu_SetCursor( menuframework_s *s, int cursor ); +extern void Menu_SetCursorToItem( menuframework_s *m, void* ptr ); +extern sfxHandle_t Menu_DefaultKey( menuframework_s *s, int key ); +extern void Bitmap_Init( menubitmap_s *b ); +extern void Bitmap_Draw( menubitmap_s *b ); +extern void ScrollList_Draw( menulist_s *l ); +extern sfxHandle_t ScrollList_Key( menulist_s *l, int key ); +extern sfxHandle_t menu_in_sound; +extern sfxHandle_t menu_move_sound; +extern sfxHandle_t menu_out_sound; +extern sfxHandle_t menu_buzz_sound; +extern sfxHandle_t menu_null_sound; +extern sfxHandle_t weaponChangeSound; +extern vec4_t menu_text_color; +extern vec4_t menu_grayed_color; +extern vec4_t menu_dark_color; +extern vec4_t menu_highlight_color; +extern vec4_t menu_red_color; +extern vec4_t menu_black_color; +extern vec4_t menu_dim_color; +extern vec4_t color_black; +extern vec4_t color_white; +extern vec4_t color_yellow; +extern vec4_t color_blue; +extern vec4_t color_orange; +extern vec4_t color_red; +extern vec4_t color_dim; +extern vec4_t name_color; +extern vec4_t list_color; +extern vec4_t listbar_color; +extern vec4_t text_color_disabled; +extern vec4_t text_color_normal; +extern vec4_t text_color_highlight; + +extern char *ui_medalNames[]; +extern char *ui_medalPicNames[]; +extern char *ui_medalSounds[]; + +// +// ui_mfield.c +// +extern void MField_Clear( mfield_t *edit ); +extern void MField_KeyDownEvent( mfield_t *edit, int key ); +extern void MField_CharEvent( mfield_t *edit, int ch ); +extern void MField_Draw( mfield_t *edit, int x, int y, int style, vec4_t color ); +extern void MenuField_Init( menufield_s* m ); +extern void MenuField_Draw( menufield_s *f ); +extern sfxHandle_t MenuField_Key( menufield_s* m, int* key ); + +// +// ui_menu.c +// +extern void MainMenu_Cache( void ); +extern void UI_MainMenu(void); +extern void UI_RegisterCvars( void ); +extern void UI_UpdateCvars( void ); + +// +// ui_credits.c +// +extern void UI_CreditMenu( void ); + +// +// ui_ingame.c +// +extern void InGame_Cache( void ); +extern void UI_InGameMenu(void); + +// +// ui_confirm.c +// +extern void ConfirmMenu_Cache( void ); +extern void UI_ConfirmMenu( const char *question, void (*draw)( void ), void (*action)( qboolean result ) ); +extern void UI_ConfirmMenu_Style( const char *question, int style, void (*draw)( void ), void (*action)( qboolean result ) ); +extern void UI_Message( const char **lines ); + +// +// ui_setup.c +// +extern void UI_SetupMenu_Cache( void ); +extern void UI_SetupMenu(void); + +// +// ui_team.c +// +extern void UI_TeamMainMenu( void ); +extern void TeamMain_Cache( void ); + +// +// ui_connect.c +// +extern void UI_DrawConnectScreen( qboolean overlay ); + +// +// ui_controls2.c +// +extern void UI_ControlsMenu( void ); +extern void Controls_Cache( void ); + +// +// ui_demo2.c +// +extern void UI_DemosMenu( void ); +extern void Demos_Cache( void ); + +// +// ui_cinematics.c +// +extern void UI_CinematicsMenu( void ); +extern void UI_CinematicsMenu_f( void ); +extern void UI_CinematicsMenu_Cache( void ); + +// +// ui_mods.c +// +extern void UI_ModsMenu( void ); +extern void UI_ModsMenu_Cache( void ); + +// +// ui_cdkey.c +// +extern void UI_CDKeyMenu( void ); +extern void UI_CDKeyMenu_Cache( void ); +extern void UI_CDKeyMenu_f( void ); + +// +// ui_playermodel.c +// +extern void UI_PlayerModelMenu( void ); +extern void PlayerModel_Cache( void ); + +// +// ui_playersettings.c +// +extern void UI_PlayerSettingsMenu( void ); +extern void PlayerSettings_Cache( void ); + +// +// ui_preferences.c +// +extern void UI_PreferencesMenu( void ); +extern void Preferences_Cache( void ); + +// +// ui_specifyleague.c +// +extern void UI_SpecifyLeagueMenu( void ); +extern void SpecifyLeague_Cache( void ); + +// +// ui_specifyserver.c +// +extern void UI_SpecifyServerMenu( void ); +extern void SpecifyServer_Cache( void ); + +// +// ui_servers2.c +// +#define MAX_FAVORITESERVERS 16 + +extern void UI_ArenaServersMenu( void ); +extern void ArenaServers_Cache( void ); + +// +// ui_startserver.c +// +extern void UI_StartServerMenu( qboolean multiplayer ); +extern void StartServer_Cache( void ); +extern void ServerOptions_Cache( void ); +extern void UI_BotSelectMenu( char *bot ); +extern void UI_BotSelectMenu_Cache( void ); + +// +// ui_serverinfo.c +// +extern void UI_ServerInfoMenu( void ); +extern void ServerInfo_Cache( void ); + +// +// ui_video.c +// +extern void UI_GraphicsOptionsMenu( void ); +extern void GraphicsOptions_Cache( void ); +extern void DriverInfo_Cache( void ); + +// +// ui_players.c +// + +//FIXME ripped from cg_local.h +typedef struct { + int oldFrame; + int oldFrameTime; // time when ->oldFrame was exactly on + + int frame; + int frameTime; // time when ->frame will be exactly on + + float backlerp; + + float yawAngle; + qboolean yawing; + float pitchAngle; + qboolean pitching; + + int animationNumber; // may include ANIM_TOGGLEBIT + animation_t *animation; + int animationTime; // time when the first frame of the animation will be exact +} lerpFrame_t; + +typedef struct { + // model info + qhandle_t legsModel; + qhandle_t legsSkin; + lerpFrame_t legs; + + qhandle_t torsoModel; + qhandle_t torsoSkin; + lerpFrame_t torso; + + qhandle_t headModel; + qhandle_t headSkin; + + animation_t animations[MAX_ANIMATIONS]; + + qhandle_t weaponModel; + qhandle_t barrelModel; + qhandle_t flashModel; + vec3_t flashDlightColor; + int muzzleFlashTime; + + // currently in use drawing parms + vec3_t viewAngles; + vec3_t moveAngles; + weapon_t currentWeapon; + int legsAnim; + int torsoAnim; + + // animation vars + weapon_t weapon; + weapon_t lastWeapon; + weapon_t pendingWeapon; + int weaponTimer; + int pendingLegsAnim; + int torsoAnimationTimer; + + int pendingTorsoAnim; + int legsAnimationTimer; + + qboolean chat; + qboolean newModel; + + qboolean barrelSpinning; + float barrelAngle; + int barrelTime; + + int realWeapon; +} playerInfo_t; + +void UI_DrawPlayer( float x, float y, float w, float h, playerInfo_t *pi, int time ); +void UI_PlayerInfo_SetModel( playerInfo_t *pi, const char *model ); +void UI_PlayerInfo_SetInfo( playerInfo_t *pi, int legsAnim, int torsoAnim, vec3_t viewAngles, vec3_t moveAngles, weapon_t weaponNum, qboolean chat ); +qboolean UI_RegisterClientModelname( playerInfo_t *pi, const char *modelSkinName ); + +// +// ui_atoms.c +// +typedef struct { + int frametime; + int realtime; + int cursorx; + int cursory; + int menusp; + menuframework_s* activemenu; + menuframework_s* stack[MAX_MENUDEPTH]; + glconfig_t glconfig; + qboolean debug; + qhandle_t whiteShader; + qhandle_t menuBackShader; + qhandle_t menuBackNoLogoShader; + qhandle_t charset; + qhandle_t charsetProp; + qhandle_t charsetPropGlow; + qhandle_t charsetPropB; + qhandle_t cursor; + qhandle_t rb_on; + qhandle_t rb_off; + float scale; + float bias; + qboolean demoversion; + qboolean firstdraw; +} uiStatic_t; + +extern void UI_Init( void ); +extern void UI_Shutdown( void ); +extern void UI_KeyEvent( int key, int down ); +extern void UI_MouseEvent( int dx, int dy ); +extern void UI_Refresh( int realtime ); +extern qboolean UI_ConsoleCommand( int realTime ); +extern float UI_ClampCvar( float min, float max, float value ); +extern void UI_DrawNamedPic( float x, float y, float width, float height, const char *picname ); +extern void UI_DrawHandlePic( float x, float y, float w, float h, qhandle_t hShader ); +extern void UI_FillRect( float x, float y, float width, float height, const float *color ); +extern void UI_DrawRect( float x, float y, float width, float height, const float *color ); +extern void UI_UpdateScreen( void ); +extern void UI_SetColor( const float *rgba ); +extern void UI_LerpColor(vec4_t a, vec4_t b, vec4_t c, float t); +extern void UI_DrawBannerString( int x, int y, const char* str, int style, vec4_t color ); +extern float UI_ProportionalSizeScale( int style ); +extern void UI_DrawProportionalString( int x, int y, const char* str, int style, vec4_t color ); +extern void UI_DrawProportionalString_AutoWrapped( int x, int ystart, int xmax, int ystep, const char* str, int style, vec4_t color ); +extern int UI_ProportionalStringWidth( const char* str ); +extern void UI_DrawString( int x, int y, const char* str, int style, vec4_t color ); +extern void UI_DrawChar( int x, int y, int ch, int style, vec4_t color ); +extern qboolean UI_CursorInRect (int x, int y, int width, int height); +extern void UI_AdjustFrom640( float *x, float *y, float *w, float *h ); +extern void UI_DrawTextBox (int x, int y, int width, int lines); +extern qboolean UI_IsFullscreen( void ); +extern void UI_SetActiveMenu( uiMenuCommand_t menu ); +extern void UI_PushMenu ( menuframework_s *menu ); +extern void UI_PopMenu (void); +extern void UI_ForceMenuOff (void); +extern char *UI_Argv( int arg ); +extern char *UI_Cvar_VariableString( const char *var_name ); +extern void UI_Refresh( int time ); +extern void UI_StartDemoLoop( void ); +extern qboolean m_entersound; +extern uiStatic_t uis; + +// +// ui_spLevel.c +// +void UI_SPLevelMenu_Cache( void ); +void UI_SPLevelMenu( void ); +void UI_SPLevelMenu_f( void ); +void UI_SPLevelMenu_ReInit( void ); + +// +// ui_spArena.c +// +void UI_SPArena_Start( const char *arenaInfo ); + +// +// ui_spPostgame.c +// +void UI_SPPostgameMenu_Cache( void ); +void UI_SPPostgameMenu_f( void ); + +// +// ui_spSkill.c +// +void UI_SPSkillMenu( const char *arenaInfo ); +void UI_SPSkillMenu_Cache( void ); + +// +// ui_syscalls.c +// +void trap_Print( const char *string ); +void trap_Error( const char *string ); +int trap_Milliseconds( void ); +void trap_Cvar_Register( vmCvar_t *vmCvar, const char *varName, const char *defaultValue, int flags ); +void trap_Cvar_Update( vmCvar_t *vmCvar ); +void trap_Cvar_Set( const char *var_name, const char *value ); +float trap_Cvar_VariableValue( const char *var_name ); +void trap_Cvar_VariableStringBuffer( const char *var_name, char *buffer, int bufsize ); +void trap_Cvar_SetValue( const char *var_name, float value ); +void trap_Cvar_Reset( const char *name ); +void trap_Cvar_Create( const char *var_name, const char *var_value, int flags ); +void trap_Cvar_InfoStringBuffer( int bit, char *buffer, int bufsize ); +int trap_Argc( void ); +void trap_Argv( int n, char *buffer, int bufferLength ); +void trap_Cmd_ExecuteText( int exec_when, const char *text ); // don't use EXEC_NOW! +int trap_FS_FOpenFile( const char *qpath, fileHandle_t *f, fsMode_t mode ); +void trap_FS_Read( void *buffer, int len, fileHandle_t f ); +void trap_FS_Write( const void *buffer, int len, fileHandle_t f ); +void trap_FS_FCloseFile( fileHandle_t f ); +int trap_FS_GetFileList( const char *path, const char *extension, char *listbuf, int bufsize ); +int trap_FS_Seek( fileHandle_t f, long offset, int origin ); // fsOrigin_t +qhandle_t trap_R_RegisterModel( const char *name ); +qhandle_t trap_R_RegisterSkin( const char *name ); +qhandle_t trap_R_RegisterShaderNoMip( const char *name ); +void trap_R_ClearScene( void ); +void trap_R_AddRefEntityToScene( const refEntity_t *re ); +void trap_R_AddPolyToScene( qhandle_t hShader , int numVerts, const polyVert_t *verts ); +void trap_R_AddLightToScene( const vec3_t org, float intensity, float r, float g, float b ); +void trap_R_RenderScene( const refdef_t *fd ); +void trap_R_SetColor( const float *rgba ); +void trap_R_DrawStretchPic( float x, float y, float w, float h, float s1, float t1, float s2, float t2, qhandle_t hShader ); +void trap_UpdateScreen( void ); +int trap_CM_LerpTag( orientation_t *tag, clipHandle_t mod, int startFrame, int endFrame, float frac, const char *tagName ); +void trap_S_StartLocalSound( sfxHandle_t sfx, int channelNum ); +sfxHandle_t trap_S_RegisterSound( const char *sample, qboolean compressed ); +void trap_Key_KeynumToStringBuf( int keynum, char *buf, int buflen ); +void trap_Key_GetBindingBuf( int keynum, char *buf, int buflen ); +void trap_Key_SetBinding( int keynum, const char *binding ); +qboolean trap_Key_IsDown( int keynum ); +qboolean trap_Key_GetOverstrikeMode( void ); +void trap_Key_SetOverstrikeMode( qboolean state ); +void trap_Key_ClearStates( void ); +int trap_Key_GetCatcher( void ); +void trap_Key_SetCatcher( int catcher ); +void trap_GetClipboardData( char *buf, int bufsize ); +void trap_GetClientState( uiClientState_t *state ); +void trap_GetGlconfig( glconfig_t *glconfig ); +int trap_GetConfigString( int index, char* buff, int buffsize ); +int trap_LAN_GetServerCount( int source ); +void trap_LAN_GetServerAddressString( int source, int n, char *buf, int buflen ); +void trap_LAN_GetServerInfo( int source, int n, char *buf, int buflen ); +int trap_LAN_GetPingQueueCount( void ); +int trap_LAN_ServerStatus( const char *serverAddress, char *serverStatus, int maxLen ); +void trap_LAN_ClearPing( int n ); +void trap_LAN_GetPing( int n, char *buf, int buflen, int *pingtime ); +void trap_LAN_GetPingInfo( int n, char *buf, int buflen ); +int trap_MemoryRemaining( void ); +void trap_GetCDKey( char *buf, int buflen ); +void trap_SetCDKey( char *buf ); + +qboolean trap_VerifyCDKey( const char *key, const char *chksum); // bk001208 - RC4 + +void trap_SetPbClStatus( int status ); + +// +// ui_addbots.c +// +void UI_AddBots_Cache( void ); +void UI_AddBotsMenu( void ); + +// +// ui_removebots.c +// +void UI_RemoveBots_Cache( void ); +void UI_RemoveBotsMenu( void ); + +// +// ui_teamorders.c +// +extern void UI_TeamOrdersMenu( void ); +extern void UI_TeamOrdersMenu_f( void ); +extern void UI_TeamOrdersMenu_Cache( void ); + +// +// ui_loadconfig.c +// +void UI_LoadConfig_Cache( void ); +void UI_LoadConfigMenu( void ); + +// +// ui_saveconfig.c +// +void UI_SaveConfigMenu_Cache( void ); +void UI_SaveConfigMenu( void ); + +// +// ui_display.c +// +void UI_DisplayOptionsMenu_Cache( void ); +void UI_DisplayOptionsMenu( void ); + +// +// ui_sound.c +// +void UI_SoundOptionsMenu_Cache( void ); +void UI_SoundOptionsMenu( void ); + +// +// ui_network.c +// +void UI_NetworkOptionsMenu_Cache( void ); +void UI_NetworkOptionsMenu( void ); + +// +// ui_gameinfo.c +// +typedef enum { + AWARD_ACCURACY, + AWARD_IMPRESSIVE, + AWARD_EXCELLENT, + AWARD_GAUNTLET, + AWARD_FRAGS, + AWARD_PERFECT +} awardType_t; + +const char *UI_GetArenaInfoByNumber( int num ); +const char *UI_GetArenaInfoByMap( const char *map ); +const char *UI_GetSpecialArenaInfo( const char *tag ); +int UI_GetNumArenas( void ); +int UI_GetNumSPArenas( void ); +int UI_GetNumSPTiers( void ); + +char *UI_GetBotInfoByNumber( int num ); +char *UI_GetBotInfoByName( const char *name ); +int UI_GetNumBots( void ); + +void UI_GetBestScore( int level, int *score, int *skill ); +void UI_SetBestScore( int level, int score ); +int UI_TierCompleted( int levelWon ); +qboolean UI_ShowTierVideo( int tier ); +qboolean UI_CanShowTierVideo( int tier ); +int UI_GetCurrentGame( void ); +void UI_NewGame( void ); +void UI_LogAwardData( int award, int data ); +int UI_GetAwardLevel( int award ); + +void UI_SPUnlock_f( void ); +void UI_SPUnlockMedals_f( void ); + +void UI_InitGameinfo( void ); + +//GRank + +// +// ui_rankings.c +// +void Rankings_DrawText( void* self ); +void Rankings_DrawName( void* self ); +void Rankings_DrawPassword( void* self ); +void Rankings_Cache( void ); +void UI_RankingsMenu( void ); + +// +// ui_login.c +// +void Login_Cache( void ); +void UI_LoginMenu( void ); + +// +// ui_signup.c +// +void Signup_Cache( void ); +void UI_SignupMenu( void ); + +// +// ui_rankstatus.c +// +void RankStatus_Cache( void ); +void UI_RankStatusMenu( void ); + +#endif diff --git a/code/q3_ui/ui_login.c b/code/q3_ui/ui_login.c new file mode 100755 index 0000000..86b7584 --- /dev/null +++ b/code/q3_ui/ui_login.c @@ -0,0 +1,208 @@ +/* +=========================================================================== +Copyright (C) 1999-2005 Id Software, Inc. + +This file is part of Quake III Arena source code. + +Quake III Arena source code is free software; you can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 2 of the License, +or (at your option) any later version. + +Quake III Arena source code is distributed in the hope that it will be +useful, but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Foobar; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ +// +// +// ui_login.c +// + +#include "ui_local.h" + + +#define LOGIN_FRAME "menu/art/cut_frame" + +#define ID_NAME 100 +#define ID_NAME_BOX 101 +#define ID_PASSWORD 102 +#define ID_PASSWORD_BOX 103 +#define ID_LOGIN 104 +#define ID_CANCEL 105 + + +typedef struct +{ + menuframework_s menu; + menubitmap_s frame; + menutext_s name; + menufield_s name_box; + menutext_s password; + menufield_s password_box; + menutext_s login; + menutext_s cancel; +} login_t; + +static login_t s_login; + +static menuframework_s s_login_menu; +static menuaction_s s_login_login; +static menuaction_s s_login_cancel; + +static vec4_t s_login_color_prompt = {1.00, 0.43, 0.00, 1.00}; + +/* +=============== +Login_MenuEvent +=============== +*/ +static void Login_MenuEvent( void* ptr, int event ) { + if( event != QM_ACTIVATED ) { + return; + } + + switch( ((menucommon_s*)ptr)->id ) { + case ID_LOGIN: + // set name `` + //trap_Cvar_Set( "name", s_login.name_box.field.buffer ); + /* + trap_Cvar_Set( "rank_name", s_login.name_box.field.buffer ); + trap_Cvar_Set( "rank_pwd", s_login.password_box.field.buffer ); + */ + + // login + trap_CL_UI_RankUserLogin( + s_login.name_box.field.buffer, + s_login.password_box.field.buffer ); + + UI_ForceMenuOff(); + break; + + case ID_CANCEL: + UI_PopMenu(); + break; + } +} + + +/* +=============== +Login_MenuInit +=============== +*/ +void Login_MenuInit( void ) { + int y; + + memset( &s_login, 0, sizeof(s_login) ); + + Login_Cache(); + + s_login.menu.wrapAround = qtrue; + s_login.menu.fullscreen = qfalse; + + s_login.frame.generic.type = MTYPE_BITMAP; + s_login.frame.generic.flags = QMF_INACTIVE; + s_login.frame.generic.name = LOGIN_FRAME; + s_login.frame.generic.x = 142; //320-233; + s_login.frame.generic.y = 118; //240-166; + s_login.frame.width = 359; //466; + s_login.frame.height = 256; //332; + + y = 214; + + s_login.name.generic.type = MTYPE_PTEXT; + s_login.name.generic.flags = QMF_RIGHT_JUSTIFY|QMF_INACTIVE; + s_login.name.generic.id = ID_NAME; + s_login.name.generic.x = 310; + s_login.name.generic.y = y; + s_login.name.string = "NAME"; + s_login.name.style = UI_RIGHT|UI_SMALLFONT; + s_login.name.color = s_login_color_prompt; + + s_login.name_box.generic.type = MTYPE_FIELD; + s_login.name_box.generic.ownerdraw = Rankings_DrawName; + s_login.name_box.generic.name = ""; + s_login.name_box.generic.flags = 0; + s_login.name_box.generic.x = 330; + s_login.name_box.generic.y = y; + s_login.name_box.field.widthInChars = 16; + s_login.name_box.field.maxchars = 16; + y += 20; + + s_login.password.generic.type = MTYPE_PTEXT; + s_login.password.generic.flags = QMF_RIGHT_JUSTIFY|QMF_INACTIVE; + s_login.password.generic.id = ID_PASSWORD; + s_login.password.generic.x = 310; + s_login.password.generic.y = y; + s_login.password.string = "PASSWORD"; + s_login.password.style = UI_RIGHT|UI_SMALLFONT; + s_login.password.color = s_login_color_prompt; + + s_login.password_box.generic.type = MTYPE_FIELD; + s_login.password_box.generic.ownerdraw = Rankings_DrawPassword; + s_login.password_box.generic.name = ""; + s_login.password_box.generic.flags = 0; + s_login.password_box.generic.x = 330; + s_login.password_box.generic.y = y; + s_login.password_box.field.widthInChars = 16; + s_login.password_box.field.maxchars = 16; + y += 40; + + s_login.login.generic.type = MTYPE_PTEXT; + s_login.login.generic.flags = QMF_RIGHT_JUSTIFY|QMF_PULSEIFFOCUS; + s_login.login.generic.id = ID_LOGIN; + s_login.login.generic.callback = Login_MenuEvent; + s_login.login.generic.x = 310; + s_login.login.generic.y = y; + s_login.login.string = "LOGIN"; + s_login.login.style = UI_RIGHT|UI_SMALLFONT; + s_login.login.color = colorRed; + + s_login.cancel.generic.type = MTYPE_PTEXT; + s_login.cancel.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS; + s_login.cancel.generic.id = ID_CANCEL; + s_login.cancel.generic.callback = Login_MenuEvent; + s_login.cancel.generic.x = 330; + s_login.cancel.generic.y = y; + s_login.cancel.string = "CANCEL"; + s_login.cancel.style = UI_LEFT|UI_SMALLFONT; + s_login.cancel.color = colorRed; + y += 20; + + Menu_AddItem( &s_login.menu, (void*) &s_login.frame ); + Menu_AddItem( &s_login.menu, (void*) &s_login.name ); + Menu_AddItem( &s_login.menu, (void*) &s_login.name_box ); + Menu_AddItem( &s_login.menu, (void*) &s_login.password ); + Menu_AddItem( &s_login.menu, (void*) &s_login.password_box ); + Menu_AddItem( &s_login.menu, (void*) &s_login.login ); + Menu_AddItem( &s_login.menu, (void*) &s_login.cancel ); +} + + +/* +=============== +Login_Cache +=============== +*/ +void Login_Cache( void ) { + trap_R_RegisterShaderNoMip( LOGIN_FRAME ); +} + + +/* +=============== +UI_LoginMenu +=============== +*/ +void UI_LoginMenu( void ) { + Login_MenuInit(); + UI_PushMenu ( &s_login.menu ); +} + + diff --git a/code/q3_ui/ui_main.c b/code/q3_ui/ui_main.c new file mode 100755 index 0000000..465e6ec --- /dev/null +++ b/code/q3_ui/ui_main.c @@ -0,0 +1,249 @@ +/* +=========================================================================== +Copyright (C) 1999-2005 Id Software, Inc. + +This file is part of Quake III Arena source code. + +Quake III Arena source code is free software; you can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 2 of the License, +or (at your option) any later version. + +Quake III Arena source code is distributed in the hope that it will be +useful, but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Foobar; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ +// +/* +======================================================================= + +USER INTERFACE MAIN + +======================================================================= +*/ + + +#include "ui_local.h" + + +/* +================ +vmMain + +This is the only way control passes into the module. +This must be the very first function compiled into the .qvm file +================ +*/ +int vmMain( int command, int arg0, int arg1, int arg2, int arg3, int arg4, int arg5, int arg6, int arg7, int arg8, int arg9, int arg10, int arg11 ) { + switch ( command ) { + case UI_GETAPIVERSION: + return UI_API_VERSION; + + case UI_INIT: + UI_Init(); + return 0; + + case UI_SHUTDOWN: + UI_Shutdown(); + return 0; + + case UI_KEY_EVENT: + UI_KeyEvent( arg0, arg1 ); + return 0; + + case UI_MOUSE_EVENT: + UI_MouseEvent( arg0, arg1 ); + return 0; + + case UI_REFRESH: + UI_Refresh( arg0 ); + return 0; + + case UI_IS_FULLSCREEN: + return UI_IsFullscreen(); + + case UI_SET_ACTIVE_MENU: + UI_SetActiveMenu( arg0 ); + return 0; + + case UI_CONSOLE_COMMAND: + return UI_ConsoleCommand(arg0); + + case UI_DRAW_CONNECT_SCREEN: + UI_DrawConnectScreen( arg0 ); + return 0; + case UI_HASUNIQUECDKEY: // mod authors need to observe this + return qtrue; // bk010117 - change this to qfalse for mods! + } + + return -1; +} + + +/* +================ +cvars +================ +*/ + +typedef struct { + vmCvar_t *vmCvar; + char *cvarName; + char *defaultString; + int cvarFlags; +} cvarTable_t; + +vmCvar_t ui_ffa_fraglimit; +vmCvar_t ui_ffa_timelimit; + +vmCvar_t ui_tourney_fraglimit; +vmCvar_t ui_tourney_timelimit; + +vmCvar_t ui_team_fraglimit; +vmCvar_t ui_team_timelimit; +vmCvar_t ui_team_friendly; + +vmCvar_t ui_ctf_capturelimit; +vmCvar_t ui_ctf_timelimit; +vmCvar_t ui_ctf_friendly; + +vmCvar_t ui_arenasFile; +vmCvar_t ui_botsFile; +vmCvar_t ui_spScores1; +vmCvar_t ui_spScores2; +vmCvar_t ui_spScores3; +vmCvar_t ui_spScores4; +vmCvar_t ui_spScores5; +vmCvar_t ui_spAwards; +vmCvar_t ui_spVideos; +vmCvar_t ui_spSkill; + +vmCvar_t ui_spSelection; + +vmCvar_t ui_browserMaster; +vmCvar_t ui_browserGameType; +vmCvar_t ui_browserSortKey; +vmCvar_t ui_browserShowFull; +vmCvar_t ui_browserShowEmpty; + +vmCvar_t ui_brassTime; +vmCvar_t ui_drawCrosshair; +vmCvar_t ui_drawCrosshairNames; +vmCvar_t ui_marks; + +vmCvar_t ui_server1; +vmCvar_t ui_server2; +vmCvar_t ui_server3; +vmCvar_t ui_server4; +vmCvar_t ui_server5; +vmCvar_t ui_server6; +vmCvar_t ui_server7; +vmCvar_t ui_server8; +vmCvar_t ui_server9; +vmCvar_t ui_server10; +vmCvar_t ui_server11; +vmCvar_t ui_server12; +vmCvar_t ui_server13; +vmCvar_t ui_server14; +vmCvar_t ui_server15; +vmCvar_t ui_server16; + +vmCvar_t ui_cdkeychecked; + +// bk001129 - made static to avoid aliasing. +static cvarTable_t cvarTable[] = { + { &ui_ffa_fraglimit, "ui_ffa_fraglimit", "20", CVAR_ARCHIVE }, + { &ui_ffa_timelimit, "ui_ffa_timelimit", "0", CVAR_ARCHIVE }, + + { &ui_tourney_fraglimit, "ui_tourney_fraglimit", "0", CVAR_ARCHIVE }, + { &ui_tourney_timelimit, "ui_tourney_timelimit", "15", CVAR_ARCHIVE }, + + { &ui_team_fraglimit, "ui_team_fraglimit", "0", CVAR_ARCHIVE }, + { &ui_team_timelimit, "ui_team_timelimit", "20", CVAR_ARCHIVE }, + { &ui_team_friendly, "ui_team_friendly", "1", CVAR_ARCHIVE }, + + { &ui_ctf_capturelimit, "ui_ctf_capturelimit", "8", CVAR_ARCHIVE }, + { &ui_ctf_timelimit, "ui_ctf_timelimit", "30", CVAR_ARCHIVE }, + { &ui_ctf_friendly, "ui_ctf_friendly", "0", CVAR_ARCHIVE }, + + { &ui_arenasFile, "g_arenasFile", "", CVAR_INIT|CVAR_ROM }, + { &ui_botsFile, "g_botsFile", "", CVAR_INIT|CVAR_ROM }, + { &ui_spScores1, "g_spScores1", "", CVAR_ARCHIVE | CVAR_ROM }, + { &ui_spScores2, "g_spScores2", "", CVAR_ARCHIVE | CVAR_ROM }, + { &ui_spScores3, "g_spScores3", "", CVAR_ARCHIVE | CVAR_ROM }, + { &ui_spScores4, "g_spScores4", "", CVAR_ARCHIVE | CVAR_ROM }, + { &ui_spScores5, "g_spScores5", "", CVAR_ARCHIVE | CVAR_ROM }, + { &ui_spAwards, "g_spAwards", "", CVAR_ARCHIVE | CVAR_ROM }, + { &ui_spVideos, "g_spVideos", "", CVAR_ARCHIVE | CVAR_ROM }, + { &ui_spSkill, "g_spSkill", "2", CVAR_ARCHIVE | CVAR_LATCH }, + + { &ui_spSelection, "ui_spSelection", "", CVAR_ROM }, + + { &ui_browserMaster, "ui_browserMaster", "0", CVAR_ARCHIVE }, + { &ui_browserGameType, "ui_browserGameType", "0", CVAR_ARCHIVE }, + { &ui_browserSortKey, "ui_browserSortKey", "4", CVAR_ARCHIVE }, + { &ui_browserShowFull, "ui_browserShowFull", "1", CVAR_ARCHIVE }, + { &ui_browserShowEmpty, "ui_browserShowEmpty", "1", CVAR_ARCHIVE }, + + { &ui_brassTime, "cg_brassTime", "2500", CVAR_ARCHIVE }, + { &ui_drawCrosshair, "cg_drawCrosshair", "4", CVAR_ARCHIVE }, + { &ui_drawCrosshairNames, "cg_drawCrosshairNames", "1", CVAR_ARCHIVE }, + { &ui_marks, "cg_marks", "1", CVAR_ARCHIVE }, + + { &ui_server1, "server1", "", CVAR_ARCHIVE }, + { &ui_server2, "server2", "", CVAR_ARCHIVE }, + { &ui_server3, "server3", "", CVAR_ARCHIVE }, + { &ui_server4, "server4", "", CVAR_ARCHIVE }, + { &ui_server5, "server5", "", CVAR_ARCHIVE }, + { &ui_server6, "server6", "", CVAR_ARCHIVE }, + { &ui_server7, "server7", "", CVAR_ARCHIVE }, + { &ui_server8, "server8", "", CVAR_ARCHIVE }, + { &ui_server9, "server9", "", CVAR_ARCHIVE }, + { &ui_server10, "server10", "", CVAR_ARCHIVE }, + { &ui_server11, "server11", "", CVAR_ARCHIVE }, + { &ui_server12, "server12", "", CVAR_ARCHIVE }, + { &ui_server13, "server13", "", CVAR_ARCHIVE }, + { &ui_server14, "server14", "", CVAR_ARCHIVE }, + { &ui_server15, "server15", "", CVAR_ARCHIVE }, + { &ui_server16, "server16", "", CVAR_ARCHIVE }, + + { &ui_cdkeychecked, "ui_cdkeychecked", "0", CVAR_ROM } +}; + +// bk001129 - made static to avoid aliasing +static int cvarTableSize = sizeof(cvarTable) / sizeof(cvarTable[0]); + + +/* +================= +UI_RegisterCvars +================= +*/ +void UI_RegisterCvars( void ) { + int i; + cvarTable_t *cv; + + for ( i = 0, cv = cvarTable ; i < cvarTableSize ; i++, cv++ ) { + trap_Cvar_Register( cv->vmCvar, cv->cvarName, cv->defaultString, cv->cvarFlags ); + } +} + +/* +================= +UI_UpdateCvars +================= +*/ +void UI_UpdateCvars( void ) { + int i; + cvarTable_t *cv; + + for ( i = 0, cv = cvarTable ; i < cvarTableSize ; i++, cv++ ) { + trap_Cvar_Update( cv->vmCvar ); + } +} diff --git a/code/q3_ui/ui_menu.c b/code/q3_ui/ui_menu.c new file mode 100755 index 0000000..682c5a8 --- /dev/null +++ b/code/q3_ui/ui_menu.c @@ -0,0 +1,419 @@ +/* +=========================================================================== +Copyright (C) 1999-2005 Id Software, Inc. + +This file is part of Quake III Arena source code. + +Quake III Arena source code is free software; you can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 2 of the License, +or (at your option) any later version. + +Quake III Arena source code is distributed in the hope that it will be +useful, but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Foobar; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ +// +/* +======================================================================= + +MAIN MENU + +======================================================================= +*/ + + +#include "ui_local.h" + + +#define ID_SINGLEPLAYER 10 +#define ID_MULTIPLAYER 11 +#define ID_SETUP 12 +#define ID_DEMOS 13 +#define ID_CINEMATICS 14 +#define ID_TEAMARENA 15 +#define ID_MODS 16 +#define ID_EXIT 17 + +#define MAIN_BANNER_MODEL "models/mapobjects/banner/banner5.md3" +#define MAIN_MENU_VERTICAL_SPACING 34 + + +typedef struct { + menuframework_s menu; + + menutext_s singleplayer; + menutext_s multiplayer; + menutext_s setup; + menutext_s demos; + menutext_s cinematics; + menutext_s teamArena; + menutext_s mods; + menutext_s exit; + + qhandle_t bannerModel; +} mainmenu_t; + + +static mainmenu_t s_main; + +typedef struct { + menuframework_s menu; + char errorMessage[4096]; +} errorMessage_t; + +static errorMessage_t s_errorMessage; + +/* +================= +MainMenu_ExitAction +================= +*/ +static void MainMenu_ExitAction( qboolean result ) { + if( !result ) { + return; + } + UI_PopMenu(); + UI_CreditMenu(); +} + + + +/* +================= +Main_MenuEvent +================= +*/ +void Main_MenuEvent (void* ptr, int event) { + if( event != QM_ACTIVATED ) { + return; + } + + switch( ((menucommon_s*)ptr)->id ) { + case ID_SINGLEPLAYER: + UI_SPLevelMenu(); + break; + + case ID_MULTIPLAYER: + UI_ArenaServersMenu(); + break; + + case ID_SETUP: + UI_SetupMenu(); + break; + + case ID_DEMOS: + UI_DemosMenu(); + break; + + case ID_CINEMATICS: + UI_CinematicsMenu(); + break; + + case ID_MODS: + UI_ModsMenu(); + break; + + case ID_TEAMARENA: + trap_Cvar_Set( "fs_game", "missionpack"); + trap_Cmd_ExecuteText( EXEC_APPEND, "vid_restart;" ); + break; + + case ID_EXIT: + UI_ConfirmMenu( "EXIT GAME?", NULL, MainMenu_ExitAction ); + break; + } +} + + +/* +=============== +MainMenu_Cache +=============== +*/ +void MainMenu_Cache( void ) { + s_main.bannerModel = trap_R_RegisterModel( MAIN_BANNER_MODEL ); +} + +sfxHandle_t ErrorMessage_Key(int key) +{ + trap_Cvar_Set( "com_errorMessage", "" ); + UI_MainMenu(); + return (menu_null_sound); +} + +/* +=============== +Main_MenuDraw +TTimo: this function is common to the main menu and errorMessage menu +=============== +*/ + +static void Main_MenuDraw( void ) { + refdef_t refdef; + refEntity_t ent; + vec3_t origin; + vec3_t angles; + float adjust; + float x, y, w, h; + vec4_t color = {0.5, 0, 0, 1}; + + // setup the refdef + + memset( &refdef, 0, sizeof( refdef ) ); + + refdef.rdflags = RDF_NOWORLDMODEL; + + AxisClear( refdef.viewaxis ); + + x = 0; + y = 0; + w = 640; + h = 120; + UI_AdjustFrom640( &x, &y, &w, &h ); + refdef.x = x; + refdef.y = y; + refdef.width = w; + refdef.height = h; + + adjust = 0; // JDC: Kenneth asked me to stop this 1.0 * sin( (float)uis.realtime / 1000 ); + refdef.fov_x = 60 + adjust; + refdef.fov_y = 19.6875 + adjust; + + refdef.time = uis.realtime; + + origin[0] = 300; + origin[1] = 0; + origin[2] = -32; + + trap_R_ClearScene(); + + // add the model + + memset( &ent, 0, sizeof(ent) ); + + adjust = 5.0 * sin( (float)uis.realtime / 5000 ); + VectorSet( angles, 0, 180 + adjust, 0 ); + AnglesToAxis( angles, ent.axis ); + ent.hModel = s_main.bannerModel; + VectorCopy( origin, ent.origin ); + VectorCopy( origin, ent.lightingOrigin ); + ent.renderfx = RF_LIGHTING_ORIGIN | RF_NOSHADOW; + VectorCopy( ent.origin, ent.oldorigin ); + + trap_R_AddRefEntityToScene( &ent ); + + trap_R_RenderScene( &refdef ); + + if (strlen(s_errorMessage.errorMessage)) + { + UI_DrawProportionalString_AutoWrapped( 320, 192, 600, 20, s_errorMessage.errorMessage, UI_CENTER|UI_SMALLFONT|UI_DROPSHADOW, menu_text_color ); + } + else + { + // standard menu drawing + Menu_Draw( &s_main.menu ); + } + + if (uis.demoversion) { + UI_DrawProportionalString( 320, 372, "DEMO FOR MATURE AUDIENCES DEMO", UI_CENTER|UI_SMALLFONT, color ); + UI_DrawString( 320, 400, "Quake III Arena(c) 1999-2000, Id Software, Inc. All Rights Reserved", UI_CENTER|UI_SMALLFONT, color ); + } else { + UI_DrawString( 320, 450, "Quake III Arena(c) 1999-2000, Id Software, Inc. All Rights Reserved", UI_CENTER|UI_SMALLFONT, color ); + } +} + + +/* +=============== +UI_TeamArenaExists +=============== +*/ +static qboolean UI_TeamArenaExists( void ) { + int numdirs; + char dirlist[2048]; + char *dirptr; + char *descptr; + int i; + int dirlen; + + numdirs = trap_FS_GetFileList( "$modlist", "", dirlist, sizeof(dirlist) ); + dirptr = dirlist; + for( i = 0; i < numdirs; i++ ) { + dirlen = strlen( dirptr ) + 1; + descptr = dirptr + dirlen; + if (Q_stricmp(dirptr, "missionpack") == 0) { + return qtrue; + } + dirptr += dirlen + strlen(descptr) + 1; + } + return qfalse; +} + + +/* +=============== +UI_MainMenu + +The main menu only comes up when not in a game, +so make sure that the attract loop server is down +and that local cinematics are killed +=============== +*/ +void UI_MainMenu( void ) { + int y; + qboolean teamArena = qfalse; + int style = UI_CENTER | UI_DROPSHADOW; + + trap_Cvar_Set( "sv_killserver", "1" ); + + if( !uis.demoversion && !ui_cdkeychecked.integer ) { + char key[17]; + + trap_GetCDKey( key, sizeof(key) ); + if( trap_VerifyCDKey( key, NULL ) == qfalse ) { + UI_CDKeyMenu(); + return; + } + } + + memset( &s_main, 0 ,sizeof(mainmenu_t) ); + memset( &s_errorMessage, 0 ,sizeof(errorMessage_t) ); + + // com_errorMessage would need that too + MainMenu_Cache(); + + trap_Cvar_VariableStringBuffer( "com_errorMessage", s_errorMessage.errorMessage, sizeof(s_errorMessage.errorMessage) ); + if (strlen(s_errorMessage.errorMessage)) + { + s_errorMessage.menu.draw = Main_MenuDraw; + s_errorMessage.menu.key = ErrorMessage_Key; + s_errorMessage.menu.fullscreen = qtrue; + s_errorMessage.menu.wrapAround = qtrue; + s_errorMessage.menu.showlogo = qtrue; + + trap_Key_SetCatcher( KEYCATCH_UI ); + uis.menusp = 0; + UI_PushMenu ( &s_errorMessage.menu ); + + return; + } + + s_main.menu.draw = Main_MenuDraw; + s_main.menu.fullscreen = qtrue; + s_main.menu.wrapAround = qtrue; + s_main.menu.showlogo = qtrue; + + y = 134; + s_main.singleplayer.generic.type = MTYPE_PTEXT; + s_main.singleplayer.generic.flags = QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS; + s_main.singleplayer.generic.x = 320; + s_main.singleplayer.generic.y = y; + s_main.singleplayer.generic.id = ID_SINGLEPLAYER; + s_main.singleplayer.generic.callback = Main_MenuEvent; + s_main.singleplayer.string = "SINGLE PLAYER"; + s_main.singleplayer.color = color_red; + s_main.singleplayer.style = style; + + y += MAIN_MENU_VERTICAL_SPACING; + s_main.multiplayer.generic.type = MTYPE_PTEXT; + s_main.multiplayer.generic.flags = QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS; + s_main.multiplayer.generic.x = 320; + s_main.multiplayer.generic.y = y; + s_main.multiplayer.generic.id = ID_MULTIPLAYER; + s_main.multiplayer.generic.callback = Main_MenuEvent; + s_main.multiplayer.string = "MULTIPLAYER"; + s_main.multiplayer.color = color_red; + s_main.multiplayer.style = style; + + y += MAIN_MENU_VERTICAL_SPACING; + s_main.setup.generic.type = MTYPE_PTEXT; + s_main.setup.generic.flags = QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS; + s_main.setup.generic.x = 320; + s_main.setup.generic.y = y; + s_main.setup.generic.id = ID_SETUP; + s_main.setup.generic.callback = Main_MenuEvent; + s_main.setup.string = "SETUP"; + s_main.setup.color = color_red; + s_main.setup.style = style; + + y += MAIN_MENU_VERTICAL_SPACING; + s_main.demos.generic.type = MTYPE_PTEXT; + s_main.demos.generic.flags = QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS; + s_main.demos.generic.x = 320; + s_main.demos.generic.y = y; + s_main.demos.generic.id = ID_DEMOS; + s_main.demos.generic.callback = Main_MenuEvent; + s_main.demos.string = "DEMOS"; + s_main.demos.color = color_red; + s_main.demos.style = style; + + y += MAIN_MENU_VERTICAL_SPACING; + s_main.cinematics.generic.type = MTYPE_PTEXT; + s_main.cinematics.generic.flags = QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS; + s_main.cinematics.generic.x = 320; + s_main.cinematics.generic.y = y; + s_main.cinematics.generic.id = ID_CINEMATICS; + s_main.cinematics.generic.callback = Main_MenuEvent; + s_main.cinematics.string = "CINEMATICS"; + s_main.cinematics.color = color_red; + s_main.cinematics.style = style; + + if (UI_TeamArenaExists()) { + teamArena = qtrue; + y += MAIN_MENU_VERTICAL_SPACING; + s_main.teamArena.generic.type = MTYPE_PTEXT; + s_main.teamArena.generic.flags = QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS; + s_main.teamArena.generic.x = 320; + s_main.teamArena.generic.y = y; + s_main.teamArena.generic.id = ID_TEAMARENA; + s_main.teamArena.generic.callback = Main_MenuEvent; + s_main.teamArena.string = "TEAM ARENA"; + s_main.teamArena.color = color_red; + s_main.teamArena.style = style; + } + + y += MAIN_MENU_VERTICAL_SPACING; + s_main.mods.generic.type = MTYPE_PTEXT; + s_main.mods.generic.flags = QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS; + s_main.mods.generic.x = 320; + s_main.mods.generic.y = y; + s_main.mods.generic.id = ID_MODS; + s_main.mods.generic.callback = Main_MenuEvent; + s_main.mods.string = "MODS"; + s_main.mods.color = color_red; + s_main.mods.style = style; + + y += MAIN_MENU_VERTICAL_SPACING; + s_main.exit.generic.type = MTYPE_PTEXT; + s_main.exit.generic.flags = QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS; + s_main.exit.generic.x = 320; + s_main.exit.generic.y = y; + s_main.exit.generic.id = ID_EXIT; + s_main.exit.generic.callback = Main_MenuEvent; + s_main.exit.string = "EXIT"; + s_main.exit.color = color_red; + s_main.exit.style = style; + + Menu_AddItem( &s_main.menu, &s_main.singleplayer ); + Menu_AddItem( &s_main.menu, &s_main.multiplayer ); + Menu_AddItem( &s_main.menu, &s_main.setup ); + Menu_AddItem( &s_main.menu, &s_main.demos ); + Menu_AddItem( &s_main.menu, &s_main.cinematics ); + if (teamArena) { + Menu_AddItem( &s_main.menu, &s_main.teamArena ); + } + Menu_AddItem( &s_main.menu, &s_main.mods ); + Menu_AddItem( &s_main.menu, &s_main.exit ); + + trap_Key_SetCatcher( KEYCATCH_UI ); + uis.menusp = 0; + UI_PushMenu ( &s_main.menu ); + +} diff --git a/code/q3_ui/ui_mfield.c b/code/q3_ui/ui_mfield.c new file mode 100755 index 0000000..927e6c2 --- /dev/null +++ b/code/q3_ui/ui_mfield.c @@ -0,0 +1,439 @@ +/* +=========================================================================== +Copyright (C) 1999-2005 Id Software, Inc. + +This file is part of Quake III Arena source code. + +Quake III Arena source code is free software; you can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 2 of the License, +or (at your option) any later version. + +Quake III Arena source code is distributed in the hope that it will be +useful, but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Foobar; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ +// +#include "ui_local.h" + +/* +=================== +MField_Draw + +Handles horizontal scrolling and cursor blinking +x, y, are in pixels +=================== +*/ +void MField_Draw( mfield_t *edit, int x, int y, int style, vec4_t color ) { + int len; + int charw; + int drawLen; + int prestep; + int cursorChar; + char str[MAX_STRING_CHARS]; + + drawLen = edit->widthInChars; + len = strlen( edit->buffer ) + 1; + + // guarantee that cursor will be visible + if ( len <= drawLen ) { + prestep = 0; + } else { + if ( edit->scroll + drawLen > len ) { + edit->scroll = len - drawLen; + if ( edit->scroll < 0 ) { + edit->scroll = 0; + } + } + prestep = edit->scroll; + } + + if ( prestep + drawLen > len ) { + drawLen = len - prestep; + } + + // extract characters from the field at + if ( drawLen >= MAX_STRING_CHARS ) { + trap_Error( "drawLen >= MAX_STRING_CHARS" ); + } + memcpy( str, edit->buffer + prestep, drawLen ); + str[ drawLen ] = 0; + + UI_DrawString( x, y, str, style, color ); + + // draw the cursor + if (!(style & UI_PULSE)) { + return; + } + + if ( trap_Key_GetOverstrikeMode() ) { + cursorChar = 11; + } else { + cursorChar = 10; + } + + style &= ~UI_PULSE; + style |= UI_BLINK; + + if (style & UI_SMALLFONT) + { + charw = SMALLCHAR_WIDTH; + } + else if (style & UI_GIANTFONT) + { + charw = GIANTCHAR_WIDTH; + } + else + { + charw = BIGCHAR_WIDTH; + } + + if (style & UI_CENTER) + { + len = strlen(str); + x = x - len*charw/2; + } + else if (style & UI_RIGHT) + { + len = strlen(str); + x = x - len*charw; + } + + UI_DrawChar( x + ( edit->cursor - prestep ) * charw, y, cursorChar, style & ~(UI_CENTER|UI_RIGHT), color ); +} + +/* +================ +MField_Paste +================ +*/ +void MField_Paste( mfield_t *edit ) { + char pasteBuffer[64]; + int pasteLen, i; + + trap_GetClipboardData( pasteBuffer, 64 ); + + // send as if typed, so insert / overstrike works properly + pasteLen = strlen( pasteBuffer ); + for ( i = 0 ; i < pasteLen ; i++ ) { + MField_CharEvent( edit, pasteBuffer[i] ); + } +} + +/* +================= +MField_KeyDownEvent + +Performs the basic line editing functions for the console, +in-game talk, and menu fields + +Key events are used for non-printable characters, others are gotten from char events. +================= +*/ +void MField_KeyDownEvent( mfield_t *edit, int key ) { + int len; + + // shift-insert is paste + if ( ( ( key == K_INS ) || ( key == K_KP_INS ) ) && trap_Key_IsDown( K_SHIFT ) ) { + MField_Paste( edit ); + return; + } + + len = strlen( edit->buffer ); + + if ( key == K_DEL || key == K_KP_DEL ) { + if ( edit->cursor < len ) { + memmove( edit->buffer + edit->cursor, + edit->buffer + edit->cursor + 1, len - edit->cursor ); + } + return; + } + + if ( key == K_RIGHTARROW || key == K_KP_RIGHTARROW ) + { + if ( edit->cursor < len ) { + edit->cursor++; + } + if ( edit->cursor >= edit->scroll + edit->widthInChars && edit->cursor <= len ) + { + edit->scroll++; + } + return; + } + + if ( key == K_LEFTARROW || key == K_KP_LEFTARROW ) + { + if ( edit->cursor > 0 ) { + edit->cursor--; + } + if ( edit->cursor < edit->scroll ) + { + edit->scroll--; + } + return; + } + + if ( key == K_HOME || key == K_KP_HOME || ( tolower(key) == 'a' && trap_Key_IsDown( K_CTRL ) ) ) { + edit->cursor = 0; + edit->scroll = 0; + return; + } + + if ( key == K_END || key == K_KP_END || ( tolower(key) == 'e' && trap_Key_IsDown( K_CTRL ) ) ) { + edit->cursor = len; + edit->scroll = len - edit->widthInChars + 1; + if (edit->scroll < 0) + edit->scroll = 0; + return; + } + + if ( key == K_INS || key == K_KP_INS ) { + trap_Key_SetOverstrikeMode( !trap_Key_GetOverstrikeMode() ); + return; + } +} + +/* +================== +MField_CharEvent +================== +*/ +void MField_CharEvent( mfield_t *edit, int ch ) { + int len; + + if ( ch == 'v' - 'a' + 1 ) { // ctrl-v is paste + MField_Paste( edit ); + return; + } + + if ( ch == 'c' - 'a' + 1 ) { // ctrl-c clears the field + MField_Clear( edit ); + return; + } + + len = strlen( edit->buffer ); + + if ( ch == 'h' - 'a' + 1 ) { // ctrl-h is backspace + if ( edit->cursor > 0 ) { + memmove( edit->buffer + edit->cursor - 1, + edit->buffer + edit->cursor, len + 1 - edit->cursor ); + edit->cursor--; + if ( edit->cursor < edit->scroll ) + { + edit->scroll--; + } + } + return; + } + + if ( ch == 'a' - 'a' + 1 ) { // ctrl-a is home + edit->cursor = 0; + edit->scroll = 0; + return; + } + + if ( ch == 'e' - 'a' + 1 ) { // ctrl-e is end + edit->cursor = len; + edit->scroll = edit->cursor - edit->widthInChars + 1; + if (edit->scroll < 0) + edit->scroll = 0; + return; + } + + // + // ignore any other non printable chars + // + if ( ch < 32 ) { + return; + } + + if ( !trap_Key_GetOverstrikeMode() ) { + if ((edit->cursor == MAX_EDIT_LINE - 1) || (edit->maxchars && edit->cursor >= edit->maxchars)) + return; + } else { + // insert mode + if (( len == MAX_EDIT_LINE - 1 ) || (edit->maxchars && len >= edit->maxchars)) + return; + memmove( edit->buffer + edit->cursor + 1, edit->buffer + edit->cursor, len + 1 - edit->cursor ); + } + + edit->buffer[edit->cursor] = ch; + if (!edit->maxchars || edit->cursor < edit->maxchars-1) + edit->cursor++; + + if ( edit->cursor >= edit->widthInChars ) + { + edit->scroll++; + } + + if ( edit->cursor == len + 1) { + edit->buffer[edit->cursor] = 0; + } +} + +/* +================== +MField_Clear +================== +*/ +void MField_Clear( mfield_t *edit ) { + edit->buffer[0] = 0; + edit->cursor = 0; + edit->scroll = 0; +} + +/* +================== +MenuField_Init +================== +*/ +void MenuField_Init( menufield_s* m ) { + int l; + int w; + int h; + + MField_Clear( &m->field ); + + if (m->generic.flags & QMF_SMALLFONT) + { + w = SMALLCHAR_WIDTH; + h = SMALLCHAR_HEIGHT; + } + else + { + w = BIGCHAR_WIDTH; + h = BIGCHAR_HEIGHT; + } + + if (m->generic.name) { + l = (strlen( m->generic.name )+1) * w; + } + else { + l = 0; + } + + m->generic.left = m->generic.x - l; + m->generic.top = m->generic.y; + m->generic.right = m->generic.x + w + m->field.widthInChars*w; + m->generic.bottom = m->generic.y + h; +} + +/* +================== +MenuField_Draw +================== +*/ +void MenuField_Draw( menufield_s *f ) +{ + int x; + int y; + int w; + int h; + int style; + qboolean focus; + float *color; + + x = f->generic.x; + y = f->generic.y; + + if (f->generic.flags & QMF_SMALLFONT) + { + w = SMALLCHAR_WIDTH; + h = SMALLCHAR_HEIGHT; + style = UI_SMALLFONT; + } + else + { + w = BIGCHAR_WIDTH; + h = BIGCHAR_HEIGHT; + style = UI_BIGFONT; + } + + if (Menu_ItemAtCursor( f->generic.parent ) == f) { + focus = qtrue; + style |= UI_PULSE; + } + else { + focus = qfalse; + } + + if (f->generic.flags & QMF_GRAYED) + color = text_color_disabled; + else if (focus) + color = text_color_highlight; + else + color = text_color_normal; + + if ( focus ) + { + // draw cursor + UI_FillRect( f->generic.left, f->generic.top, f->generic.right-f->generic.left+1, f->generic.bottom-f->generic.top+1, listbar_color ); + UI_DrawChar( x, y, 13, UI_CENTER|UI_BLINK|style, color); + } + + if ( f->generic.name ) { + UI_DrawString( x - w, y, f->generic.name, style|UI_RIGHT, color ); + } + + MField_Draw( &f->field, x + w, y, style, color ); +} + +/* +================== +MenuField_Key +================== +*/ +sfxHandle_t MenuField_Key( menufield_s* m, int* key ) +{ + int keycode; + + keycode = *key; + + switch ( keycode ) + { + case K_KP_ENTER: + case K_ENTER: + case K_JOY1: + case K_JOY2: + case K_JOY3: + case K_JOY4: + // have enter go to next cursor point + *key = K_TAB; + break; + + case K_TAB: + case K_KP_DOWNARROW: + case K_DOWNARROW: + case K_KP_UPARROW: + case K_UPARROW: + break; + + default: + if ( keycode & K_CHAR_FLAG ) + { + keycode &= ~K_CHAR_FLAG; + + if ((m->generic.flags & QMF_UPPERCASE) && Q_islower( keycode )) + keycode -= 'a' - 'A'; + else if ((m->generic.flags & QMF_LOWERCASE) && Q_isupper( keycode )) + keycode -= 'A' - 'a'; + else if ((m->generic.flags & QMF_NUMBERSONLY) && Q_isalpha( keycode )) + return (menu_buzz_sound); + + MField_CharEvent( &m->field, keycode); + } + else + MField_KeyDownEvent( &m->field, keycode ); + break; + } + + return (0); +} + + diff --git a/code/q3_ui/ui_mods.c b/code/q3_ui/ui_mods.c new file mode 100755 index 0000000..2c6b82d --- /dev/null +++ b/code/q3_ui/ui_mods.c @@ -0,0 +1,283 @@ +/* +=========================================================================== +Copyright (C) 1999-2005 Id Software, Inc. + +This file is part of Quake III Arena source code. + +Quake III Arena source code is free software; you can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 2 of the License, +or (at your option) any later version. + +Quake III Arena source code is distributed in the hope that it will be +useful, but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Foobar; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ +// +#include "ui_local.h" + +#define ART_BACK0 "menu/art/back_0" +#define ART_BACK1 "menu/art/back_1" +#define ART_FIGHT0 "menu/art/load_0" +#define ART_FIGHT1 "menu/art/load_1" +#define ART_FRAMEL "menu/art/frame2_l" +#define ART_FRAMER "menu/art/frame1_r" + +#define MAX_MODS 64 +#define NAMEBUFSIZE ( MAX_MODS * 48 ) +#define GAMEBUFSIZE ( MAX_MODS * 16 ) + +#define ID_BACK 10 +#define ID_GO 11 +#define ID_LIST 12 + + +typedef struct { + menuframework_s menu; + + menutext_s banner; + menubitmap_s framel; + menubitmap_s framer; + + menulist_s list; + + menubitmap_s back; + menubitmap_s go; + + char description[NAMEBUFSIZE]; + char fs_game[GAMEBUFSIZE]; + + char *descriptionPtr; + char *fs_gamePtr; + + char *descriptionList[MAX_MODS]; + char *fs_gameList[MAX_MODS]; +} mods_t; + +static mods_t s_mods; + + +/* +=============== +UI_Mods_MenuEvent +=============== +*/ +static void UI_Mods_MenuEvent( void *ptr, int event ) { + if( event != QM_ACTIVATED ) { + return; + } + + switch ( ((menucommon_s*)ptr)->id ) { + case ID_GO: + trap_Cvar_Set( "fs_game", s_mods.fs_gameList[s_mods.list.curvalue] ); + trap_Cmd_ExecuteText( EXEC_APPEND, "vid_restart;" ); + UI_PopMenu(); + break; + + case ID_BACK: + UI_PopMenu(); + break; + } +} + + +/* +=============== +UI_Mods_ParseInfos +=============== +*/ +static void UI_Mods_ParseInfos( char *modDir, char *modDesc ) { + s_mods.fs_gameList[s_mods.list.numitems] = s_mods.fs_gamePtr; + Q_strncpyz( s_mods.fs_gamePtr, modDir, 16 ); + + s_mods.descriptionList[s_mods.list.numitems] = s_mods.descriptionPtr; + Q_strncpyz( s_mods.descriptionPtr, modDesc, 48 ); + + s_mods.list.itemnames[s_mods.list.numitems] = s_mods.descriptionPtr; + s_mods.descriptionPtr += strlen( s_mods.descriptionPtr ) + 1; + s_mods.fs_gamePtr += strlen( s_mods.fs_gamePtr ) + 1; + s_mods.list.numitems++; +} + + +#if 0 // bk001204 - unused +/* +=============== +UI_Mods_LoadModsFromFile +=============== +*/ +static void UI_Mods_LoadModsFromFile( char *filename ) { + int len; + fileHandle_t f; + char buf[1024]; + + len = trap_FS_FOpenFile( filename, &f, FS_READ ); + if ( !f ) { + trap_Print( va( S_COLOR_RED "file not found: %s\n", filename ) ); + return; + } + if ( len >= sizeof(buf) ) { + trap_Print( va( S_COLOR_RED "file too large: %s is %i, max allowed is %i", filename, len, sizeof(buf) ) ); + trap_FS_FCloseFile( f ); + return; + } + + trap_FS_Read( buf, len, f ); + buf[len] = 0; + trap_FS_FCloseFile( f ); + + len = strlen( filename ); + if( !Q_stricmp(filename + len - 4,".mod") ) { + filename[len-4] = '\0'; + } + + UI_Mods_ParseInfos( filename, buf ); +} +#endif + + +/* +=============== +UI_Mods_LoadMods +=============== +*/ +static void UI_Mods_LoadMods( void ) { + int numdirs; + char dirlist[2048]; + char *dirptr; + char *descptr; + int i; + int dirlen; + + s_mods.list.itemnames = (const char **)s_mods.descriptionList; + s_mods.descriptionPtr = s_mods.description; + s_mods.fs_gamePtr = s_mods.fs_game; + + // always start off with baseq3 + s_mods.list.numitems = 1; + s_mods.list.itemnames[0] = s_mods.descriptionList[0] = "Quake III Arena"; + s_mods.fs_gameList[0] = ""; + + numdirs = trap_FS_GetFileList( "$modlist", "", dirlist, sizeof(dirlist) ); + dirptr = dirlist; + for( i = 0; i < numdirs; i++ ) { + dirlen = strlen( dirptr ) + 1; + descptr = dirptr + dirlen; + UI_Mods_ParseInfos( dirptr, descptr); + dirptr += dirlen + strlen(descptr) + 1; + } + + trap_Print( va( "%i mods parsed\n", s_mods.list.numitems ) ); + if (s_mods.list.numitems > MAX_MODS) { + s_mods.list.numitems = MAX_MODS; + } +} + + +/* +=============== +UI_Mods_MenuInit +=============== +*/ +static void UI_Mods_MenuInit( void ) { + UI_ModsMenu_Cache(); + + memset( &s_mods, 0 ,sizeof(mods_t) ); + s_mods.menu.wrapAround = qtrue; + s_mods.menu.fullscreen = qtrue; + + s_mods.banner.generic.type = MTYPE_BTEXT; + s_mods.banner.generic.x = 320; + s_mods.banner.generic.y = 16; + s_mods.banner.string = "MODS"; + s_mods.banner.color = color_white; + s_mods.banner.style = UI_CENTER; + + s_mods.framel.generic.type = MTYPE_BITMAP; + s_mods.framel.generic.name = ART_FRAMEL; + s_mods.framel.generic.flags = QMF_INACTIVE; + s_mods.framel.generic.x = 0; + s_mods.framel.generic.y = 78; + s_mods.framel.width = 256; + s_mods.framel.height = 329; + + s_mods.framer.generic.type = MTYPE_BITMAP; + s_mods.framer.generic.name = ART_FRAMER; + s_mods.framer.generic.flags = QMF_INACTIVE; + s_mods.framer.generic.x = 376; + s_mods.framer.generic.y = 76; + s_mods.framer.width = 256; + s_mods.framer.height = 334; + + s_mods.back.generic.type = MTYPE_BITMAP; + s_mods.back.generic.name = ART_BACK0; + s_mods.back.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS; + s_mods.back.generic.id = ID_BACK; + s_mods.back.generic.callback = UI_Mods_MenuEvent; + s_mods.back.generic.x = 0; + s_mods.back.generic.y = 480-64; + s_mods.back.width = 128; + s_mods.back.height = 64; + s_mods.back.focuspic = ART_BACK1; + + s_mods.go.generic.type = MTYPE_BITMAP; + s_mods.go.generic.name = ART_FIGHT0; + s_mods.go.generic.flags = QMF_RIGHT_JUSTIFY|QMF_PULSEIFFOCUS; + s_mods.go.generic.id = ID_GO; + s_mods.go.generic.callback = UI_Mods_MenuEvent; + s_mods.go.generic.x = 640; + s_mods.go.generic.y = 480-64; + s_mods.go.width = 128; + s_mods.go.height = 64; + s_mods.go.focuspic = ART_FIGHT1; + + // scan for mods + s_mods.list.generic.type = MTYPE_SCROLLLIST; + s_mods.list.generic.flags = QMF_PULSEIFFOCUS|QMF_CENTER_JUSTIFY; + s_mods.list.generic.callback = UI_Mods_MenuEvent; + s_mods.list.generic.id = ID_LIST; + s_mods.list.generic.x = 320; + s_mods.list.generic.y = 130; + s_mods.list.width = 48; + s_mods.list.height = 14; + + UI_Mods_LoadMods(); + + Menu_AddItem( &s_mods.menu, &s_mods.banner ); + Menu_AddItem( &s_mods.menu, &s_mods.framel ); + Menu_AddItem( &s_mods.menu, &s_mods.framer ); + Menu_AddItem( &s_mods.menu, &s_mods.list ); + Menu_AddItem( &s_mods.menu, &s_mods.back ); + Menu_AddItem( &s_mods.menu, &s_mods.go ); +} + +/* +================= +UI_Mods_Cache +================= +*/ +void UI_ModsMenu_Cache( void ) { + trap_R_RegisterShaderNoMip( ART_BACK0 ); + trap_R_RegisterShaderNoMip( ART_BACK1 ); + trap_R_RegisterShaderNoMip( ART_FIGHT0 ); + trap_R_RegisterShaderNoMip( ART_FIGHT1 ); + trap_R_RegisterShaderNoMip( ART_FRAMEL ); + trap_R_RegisterShaderNoMip( ART_FRAMER ); +} + + +/* +=============== +UI_ModsMenu +=============== +*/ +void UI_ModsMenu( void ) { + UI_Mods_MenuInit(); + UI_PushMenu( &s_mods.menu ); +} diff --git a/code/q3_ui/ui_network.c b/code/q3_ui/ui_network.c new file mode 100755 index 0000000..30019e8 --- /dev/null +++ b/code/q3_ui/ui_network.c @@ -0,0 +1,281 @@ +/* +=========================================================================== +Copyright (C) 1999-2005 Id Software, Inc. + +This file is part of Quake III Arena source code. + +Quake III Arena source code is free software; you can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 2 of the License, +or (at your option) any later version. + +Quake III Arena source code is distributed in the hope that it will be +useful, but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Foobar; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ +// +/* +======================================================================= + +NETWORK OPTIONS MENU + +======================================================================= +*/ + +#include "ui_local.h" + + +#define ART_FRAMEL "menu/art/frame2_l" +#define ART_FRAMER "menu/art/frame1_r" +#define ART_BACK0 "menu/art/back_0" +#define ART_BACK1 "menu/art/back_1" + +#define ID_GRAPHICS 10 +#define ID_DISPLAY 11 +#define ID_SOUND 12 +#define ID_NETWORK 13 +#define ID_RATE 14 +#define ID_BACK 15 + + +static const char *rate_items[] = { + "<= 28.8K", + "33.6K", + "56K", + "ISDN", + "LAN/Cable/xDSL", + 0 +}; + +typedef struct { + menuframework_s menu; + + menutext_s banner; + menubitmap_s framel; + menubitmap_s framer; + + menutext_s graphics; + menutext_s display; + menutext_s sound; + menutext_s network; + + menulist_s rate; + + menubitmap_s back; +} networkOptionsInfo_t; + +static networkOptionsInfo_t networkOptionsInfo; + + +/* +================= +UI_NetworkOptionsMenu_Event +================= +*/ +static void UI_NetworkOptionsMenu_Event( void* ptr, int event ) { + if( event != QM_ACTIVATED ) { + return; + } + + switch( ((menucommon_s*)ptr)->id ) { + case ID_GRAPHICS: + UI_PopMenu(); + UI_GraphicsOptionsMenu(); + break; + + case ID_DISPLAY: + UI_PopMenu(); + UI_DisplayOptionsMenu(); + break; + + case ID_SOUND: + UI_PopMenu(); + UI_SoundOptionsMenu(); + break; + + case ID_NETWORK: + break; + + case ID_RATE: + if( networkOptionsInfo.rate.curvalue == 0 ) { + trap_Cvar_SetValue( "rate", 2500 ); + } + else if( networkOptionsInfo.rate.curvalue == 1 ) { + trap_Cvar_SetValue( "rate", 3000 ); + } + else if( networkOptionsInfo.rate.curvalue == 2 ) { + trap_Cvar_SetValue( "rate", 4000 ); + } + else if( networkOptionsInfo.rate.curvalue == 3 ) { + trap_Cvar_SetValue( "rate", 5000 ); + } + else if( networkOptionsInfo.rate.curvalue == 4 ) { + trap_Cvar_SetValue( "rate", 25000 ); + } + break; + + case ID_BACK: + UI_PopMenu(); + break; + } +} + + +/* +=============== +UI_NetworkOptionsMenu_Init +=============== +*/ +static void UI_NetworkOptionsMenu_Init( void ) { + int y; + int rate; + + memset( &networkOptionsInfo, 0, sizeof(networkOptionsInfo) ); + + UI_NetworkOptionsMenu_Cache(); + networkOptionsInfo.menu.wrapAround = qtrue; + networkOptionsInfo.menu.fullscreen = qtrue; + + networkOptionsInfo.banner.generic.type = MTYPE_BTEXT; + networkOptionsInfo.banner.generic.flags = QMF_CENTER_JUSTIFY; + networkOptionsInfo.banner.generic.x = 320; + networkOptionsInfo.banner.generic.y = 16; + networkOptionsInfo.banner.string = "SYSTEM SETUP"; + networkOptionsInfo.banner.color = color_white; + networkOptionsInfo.banner.style = UI_CENTER; + + networkOptionsInfo.framel.generic.type = MTYPE_BITMAP; + networkOptionsInfo.framel.generic.name = ART_FRAMEL; + networkOptionsInfo.framel.generic.flags = QMF_INACTIVE; + networkOptionsInfo.framel.generic.x = 0; + networkOptionsInfo.framel.generic.y = 78; + networkOptionsInfo.framel.width = 256; + networkOptionsInfo.framel.height = 329; + + networkOptionsInfo.framer.generic.type = MTYPE_BITMAP; + networkOptionsInfo.framer.generic.name = ART_FRAMER; + networkOptionsInfo.framer.generic.flags = QMF_INACTIVE; + networkOptionsInfo.framer.generic.x = 376; + networkOptionsInfo.framer.generic.y = 76; + networkOptionsInfo.framer.width = 256; + networkOptionsInfo.framer.height = 334; + + networkOptionsInfo.graphics.generic.type = MTYPE_PTEXT; + networkOptionsInfo.graphics.generic.flags = QMF_RIGHT_JUSTIFY|QMF_PULSEIFFOCUS; + networkOptionsInfo.graphics.generic.id = ID_GRAPHICS; + networkOptionsInfo.graphics.generic.callback = UI_NetworkOptionsMenu_Event; + networkOptionsInfo.graphics.generic.x = 216; + networkOptionsInfo.graphics.generic.y = 240 - 2 * PROP_HEIGHT; + networkOptionsInfo.graphics.string = "GRAPHICS"; + networkOptionsInfo.graphics.style = UI_RIGHT; + networkOptionsInfo.graphics.color = color_red; + + networkOptionsInfo.display.generic.type = MTYPE_PTEXT; + networkOptionsInfo.display.generic.flags = QMF_RIGHT_JUSTIFY|QMF_PULSEIFFOCUS; + networkOptionsInfo.display.generic.id = ID_DISPLAY; + networkOptionsInfo.display.generic.callback = UI_NetworkOptionsMenu_Event; + networkOptionsInfo.display.generic.x = 216; + networkOptionsInfo.display.generic.y = 240 - PROP_HEIGHT; + networkOptionsInfo.display.string = "DISPLAY"; + networkOptionsInfo.display.style = UI_RIGHT; + networkOptionsInfo.display.color = color_red; + + networkOptionsInfo.sound.generic.type = MTYPE_PTEXT; + networkOptionsInfo.sound.generic.flags = QMF_RIGHT_JUSTIFY|QMF_PULSEIFFOCUS; + networkOptionsInfo.sound.generic.id = ID_SOUND; + networkOptionsInfo.sound.generic.callback = UI_NetworkOptionsMenu_Event; + networkOptionsInfo.sound.generic.x = 216; + networkOptionsInfo.sound.generic.y = 240; + networkOptionsInfo.sound.string = "SOUND"; + networkOptionsInfo.sound.style = UI_RIGHT; + networkOptionsInfo.sound.color = color_red; + + networkOptionsInfo.network.generic.type = MTYPE_PTEXT; + networkOptionsInfo.network.generic.flags = QMF_RIGHT_JUSTIFY; + networkOptionsInfo.network.generic.id = ID_NETWORK; + networkOptionsInfo.network.generic.callback = UI_NetworkOptionsMenu_Event; + networkOptionsInfo.network.generic.x = 216; + networkOptionsInfo.network.generic.y = 240 + PROP_HEIGHT; + networkOptionsInfo.network.string = "NETWORK"; + networkOptionsInfo.network.style = UI_RIGHT; + networkOptionsInfo.network.color = color_red; + + y = 240 - 1 * (BIGCHAR_HEIGHT+2); + networkOptionsInfo.rate.generic.type = MTYPE_SPINCONTROL; + networkOptionsInfo.rate.generic.name = "Data Rate:"; + networkOptionsInfo.rate.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT; + networkOptionsInfo.rate.generic.callback = UI_NetworkOptionsMenu_Event; + networkOptionsInfo.rate.generic.id = ID_RATE; + networkOptionsInfo.rate.generic.x = 400; + networkOptionsInfo.rate.generic.y = y; + networkOptionsInfo.rate.itemnames = rate_items; + + networkOptionsInfo.back.generic.type = MTYPE_BITMAP; + networkOptionsInfo.back.generic.name = ART_BACK0; + networkOptionsInfo.back.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS; + networkOptionsInfo.back.generic.callback = UI_NetworkOptionsMenu_Event; + networkOptionsInfo.back.generic.id = ID_BACK; + networkOptionsInfo.back.generic.x = 0; + networkOptionsInfo.back.generic.y = 480-64; + networkOptionsInfo.back.width = 128; + networkOptionsInfo.back.height = 64; + networkOptionsInfo.back.focuspic = ART_BACK1; + + Menu_AddItem( &networkOptionsInfo.menu, ( void * ) &networkOptionsInfo.banner ); + Menu_AddItem( &networkOptionsInfo.menu, ( void * ) &networkOptionsInfo.framel ); + Menu_AddItem( &networkOptionsInfo.menu, ( void * ) &networkOptionsInfo.framer ); + Menu_AddItem( &networkOptionsInfo.menu, ( void * ) &networkOptionsInfo.graphics ); + Menu_AddItem( &networkOptionsInfo.menu, ( void * ) &networkOptionsInfo.display ); + Menu_AddItem( &networkOptionsInfo.menu, ( void * ) &networkOptionsInfo.sound ); + Menu_AddItem( &networkOptionsInfo.menu, ( void * ) &networkOptionsInfo.network ); + Menu_AddItem( &networkOptionsInfo.menu, ( void * ) &networkOptionsInfo.rate ); + Menu_AddItem( &networkOptionsInfo.menu, ( void * ) &networkOptionsInfo.back ); + + rate = trap_Cvar_VariableValue( "rate" ); + if( rate <= 2500 ) { + networkOptionsInfo.rate.curvalue = 0; + } + else if( rate <= 3000 ) { + networkOptionsInfo.rate.curvalue = 1; + } + else if( rate <= 4000 ) { + networkOptionsInfo.rate.curvalue = 2; + } + else if( rate <= 5000 ) { + networkOptionsInfo.rate.curvalue = 3; + } + else { + networkOptionsInfo.rate.curvalue = 4; + } +} + + +/* +=============== +UI_NetworkOptionsMenu_Cache +=============== +*/ +void UI_NetworkOptionsMenu_Cache( void ) { + trap_R_RegisterShaderNoMip( ART_FRAMEL ); + trap_R_RegisterShaderNoMip( ART_FRAMER ); + trap_R_RegisterShaderNoMip( ART_BACK0 ); + trap_R_RegisterShaderNoMip( ART_BACK1 ); +} + + +/* +=============== +UI_NetworkOptionsMenu +=============== +*/ +void UI_NetworkOptionsMenu( void ) { + UI_NetworkOptionsMenu_Init(); + UI_PushMenu( &networkOptionsInfo.menu ); + Menu_SetCursorToItem( &networkOptionsInfo.menu, &networkOptionsInfo.network ); +} diff --git a/code/q3_ui/ui_options.c b/code/q3_ui/ui_options.c new file mode 100755 index 0000000..d65afb0 --- /dev/null +++ b/code/q3_ui/ui_options.c @@ -0,0 +1,229 @@ +/* +=========================================================================== +Copyright (C) 1999-2005 Id Software, Inc. + +This file is part of Quake III Arena source code. + +Quake III Arena source code is free software; you can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 2 of the License, +or (at your option) any later version. + +Quake III Arena source code is distributed in the hope that it will be +useful, but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Foobar; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ +/* +======================================================================= + +SYSTEM CONFIGURATION MENU + +======================================================================= +*/ + +#include "ui_local.h" + + +#define ART_FRAMEL "menu/art/frame2_l" +#define ART_FRAMER "menu/art/frame1_r" +#define ART_BACK0 "menu/art/back_0" +#define ART_BACK1 "menu/art/back_1" + +#define ID_GRAPHICS 10 +#define ID_DISPLAY 11 +#define ID_SOUND 12 +#define ID_NETWORK 13 +#define ID_BACK 14 + +#define VERTICAL_SPACING 34 + +typedef struct { + menuframework_s menu; + + menutext_s banner; + menubitmap_s framel; + menubitmap_s framer; + + menutext_s graphics; + menutext_s display; + menutext_s sound; + menutext_s network; + menubitmap_s back; +} optionsmenu_t; + +static optionsmenu_t s_options; + + +/* +================= +Options_Event +================= +*/ +static void Options_Event( void* ptr, int event ) { + if( event != QM_ACTIVATED ) { + return; + } + + switch( ((menucommon_s*)ptr)->id ) { + case ID_GRAPHICS: + UI_GraphicsOptionsMenu(); + break; + + case ID_DISPLAY: + UI_DisplayOptionsMenu(); + break; + + case ID_SOUND: + UI_SoundOptionsMenu(); + break; + + case ID_NETWORK: + UI_NetworkOptionsMenu(); + break; + + case ID_BACK: + UI_PopMenu(); + break; + } +} + + +/* +=============== +SystemConfig_Cache +=============== +*/ +void SystemConfig_Cache( void ) { + trap_R_RegisterShaderNoMip( ART_FRAMEL ); + trap_R_RegisterShaderNoMip( ART_FRAMER ); + trap_R_RegisterShaderNoMip( ART_BACK0 ); + trap_R_RegisterShaderNoMip( ART_BACK1 ); +} + +/* +=============== +Options_MenuInit +=============== +*/ +void Options_MenuInit( void ) { + int y; + uiClientState_t cstate; + + memset( &s_options, 0, sizeof(optionsmenu_t) ); + + SystemConfig_Cache(); + s_options.menu.wrapAround = qtrue; + + trap_GetClientState( &cstate ); + if ( cstate.connState >= CA_CONNECTED ) { + s_options.menu.fullscreen = qfalse; + } + else { + s_options.menu.fullscreen = qtrue; + } + + s_options.banner.generic.type = MTYPE_BTEXT; + s_options.banner.generic.flags = QMF_CENTER_JUSTIFY; + s_options.banner.generic.x = 320; + s_options.banner.generic.y = 16; + s_options.banner.string = "SYSTEM SETUP"; + s_options.banner.color = color_white; + s_options.banner.style = UI_CENTER; + + s_options.framel.generic.type = MTYPE_BITMAP; + s_options.framel.generic.name = ART_FRAMEL; + s_options.framel.generic.flags = QMF_INACTIVE; + s_options.framel.generic.x = 8; + s_options.framel.generic.y = 76; + s_options.framel.width = 256; + s_options.framel.height = 334; + + s_options.framer.generic.type = MTYPE_BITMAP; + s_options.framer.generic.name = ART_FRAMER; + s_options.framer.generic.flags = QMF_INACTIVE; + s_options.framer.generic.x = 376; + s_options.framer.generic.y = 76; + s_options.framer.width = 256; + s_options.framer.height = 334; + + y = 168; + s_options.graphics.generic.type = MTYPE_PTEXT; + s_options.graphics.generic.flags = QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS; + s_options.graphics.generic.callback = Options_Event; + s_options.graphics.generic.id = ID_GRAPHICS; + s_options.graphics.generic.x = 320; + s_options.graphics.generic.y = y; + s_options.graphics.string = "GRAPHICS"; + s_options.graphics.color = color_red; + s_options.graphics.style = UI_CENTER; + + y += VERTICAL_SPACING; + s_options.display.generic.type = MTYPE_PTEXT; + s_options.display.generic.flags = QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS; + s_options.display.generic.callback = Options_Event; + s_options.display.generic.id = ID_DISPLAY; + s_options.display.generic.x = 320; + s_options.display.generic.y = y; + s_options.display.string = "DISPLAY"; + s_options.display.color = color_red; + s_options.display.style = UI_CENTER; + + y += VERTICAL_SPACING; + s_options.sound.generic.type = MTYPE_PTEXT; + s_options.sound.generic.flags = QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS; + s_options.sound.generic.callback = Options_Event; + s_options.sound.generic.id = ID_SOUND; + s_options.sound.generic.x = 320; + s_options.sound.generic.y = y; + s_options.sound.string = "SOUND"; + s_options.sound.color = color_red; + s_options.sound.style = UI_CENTER; + + y += VERTICAL_SPACING; + s_options.network.generic.type = MTYPE_PTEXT; + s_options.network.generic.flags = QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS; + s_options.network.generic.callback = Options_Event; + s_options.network.generic.id = ID_NETWORK; + s_options.network.generic.x = 320; + s_options.network.generic.y = y; + s_options.network.string = "NETWORK"; + s_options.network.color = color_red; + s_options.network.style = UI_CENTER; + + s_options.back.generic.type = MTYPE_BITMAP; + s_options.back.generic.name = ART_BACK0; + s_options.back.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS; + s_options.back.generic.callback = Options_Event; + s_options.back.generic.id = ID_BACK; + s_options.back.generic.x = 0; + s_options.back.generic.y = 480-64; + s_options.back.width = 128; + s_options.back.height = 64; + s_options.back.focuspic = ART_BACK1; + + Menu_AddItem( &s_options.menu, ( void * ) &s_options.banner ); + Menu_AddItem( &s_options.menu, ( void * ) &s_options.framel ); + Menu_AddItem( &s_options.menu, ( void * ) &s_options.framer ); + Menu_AddItem( &s_options.menu, ( void * ) &s_options.graphics ); + Menu_AddItem( &s_options.menu, ( void * ) &s_options.display ); + Menu_AddItem( &s_options.menu, ( void * ) &s_options.sound ); + Menu_AddItem( &s_options.menu, ( void * ) &s_options.network ); + Menu_AddItem( &s_options.menu, ( void * ) &s_options.back ); +} + + +/* +=============== +UI_SystemConfigMenu +=============== +*/ +void UI_SystemConfigMenu( void ) { + Options_MenuInit(); + UI_PushMenu ( &s_options.menu ); +} diff --git a/code/q3_ui/ui_playermodel.c b/code/q3_ui/ui_playermodel.c new file mode 100755 index 0000000..316d5ec --- /dev/null +++ b/code/q3_ui/ui_playermodel.c @@ -0,0 +1,731 @@ +/* +=========================================================================== +Copyright (C) 1999-2005 Id Software, Inc. + +This file is part of Quake III Arena source code. + +Quake III Arena source code is free software; you can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 2 of the License, +or (at your option) any later version. + +Quake III Arena source code is distributed in the hope that it will be +useful, but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Foobar; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ +// +#include "ui_local.h" + +#define MODEL_BACK0 "menu/art/back_0" +#define MODEL_BACK1 "menu/art/back_1" +#define MODEL_SELECT "menu/art/opponents_select" +#define MODEL_SELECTED "menu/art/opponents_selected" +#define MODEL_FRAMEL "menu/art/frame1_l" +#define MODEL_FRAMER "menu/art/frame1_r" +#define MODEL_PORTS "menu/art/player_models_ports" +#define MODEL_ARROWS "menu/art/gs_arrows_0" +#define MODEL_ARROWSL "menu/art/gs_arrows_l" +#define MODEL_ARROWSR "menu/art/gs_arrows_r" + +#define LOW_MEMORY (5 * 1024 * 1024) + +static char* playermodel_artlist[] = +{ + MODEL_BACK0, + MODEL_BACK1, + MODEL_SELECT, + MODEL_SELECTED, + MODEL_FRAMEL, + MODEL_FRAMER, + MODEL_PORTS, + MODEL_ARROWS, + MODEL_ARROWSL, + MODEL_ARROWSR, + NULL +}; + +#define PLAYERGRID_COLS 4 +#define PLAYERGRID_ROWS 4 +#define MAX_MODELSPERPAGE (PLAYERGRID_ROWS*PLAYERGRID_COLS) + +#define MAX_PLAYERMODELS 256 + +#define ID_PLAYERPIC0 0 +#define ID_PLAYERPIC1 1 +#define ID_PLAYERPIC2 2 +#define ID_PLAYERPIC3 3 +#define ID_PLAYERPIC4 4 +#define ID_PLAYERPIC5 5 +#define ID_PLAYERPIC6 6 +#define ID_PLAYERPIC7 7 +#define ID_PLAYERPIC8 8 +#define ID_PLAYERPIC9 9 +#define ID_PLAYERPIC10 10 +#define ID_PLAYERPIC11 11 +#define ID_PLAYERPIC12 12 +#define ID_PLAYERPIC13 13 +#define ID_PLAYERPIC14 14 +#define ID_PLAYERPIC15 15 +#define ID_PREVPAGE 100 +#define ID_NEXTPAGE 101 +#define ID_BACK 102 + +typedef struct +{ + menuframework_s menu; + menubitmap_s pics[MAX_MODELSPERPAGE]; + menubitmap_s picbuttons[MAX_MODELSPERPAGE]; + menubitmap_s framel; + menubitmap_s framer; + menubitmap_s ports; + menutext_s banner; + menubitmap_s back; + menubitmap_s player; + menubitmap_s arrows; + menubitmap_s left; + menubitmap_s right; + menutext_s modelname; + menutext_s skinname; + menutext_s playername; + playerInfo_t playerinfo; + int nummodels; + char modelnames[MAX_PLAYERMODELS][128]; + int modelpage; + int numpages; + char modelskin[64]; + int selectedmodel; +} playermodel_t; + +static playermodel_t s_playermodel; + +/* +================= +PlayerModel_UpdateGrid +================= +*/ +static void PlayerModel_UpdateGrid( void ) +{ + int i; + int j; + + j = s_playermodel.modelpage * MAX_MODELSPERPAGE; + for (i=0; i 1) + { + if (s_playermodel.modelpage > 0) + s_playermodel.left.generic.flags &= ~QMF_INACTIVE; + else + s_playermodel.left.generic.flags |= QMF_INACTIVE; + + if (s_playermodel.modelpage < s_playermodel.numpages-1) + s_playermodel.right.generic.flags &= ~QMF_INACTIVE; + else + s_playermodel.right.generic.flags |= QMF_INACTIVE; + } + else + { + // hide left/right markers + s_playermodel.left.generic.flags |= QMF_INACTIVE; + s_playermodel.right.generic.flags |= QMF_INACTIVE; + } +} + +/* +================= +PlayerModel_UpdateModel +================= +*/ +static void PlayerModel_UpdateModel( void ) +{ + vec3_t viewangles; + vec3_t moveangles; + + memset( &s_playermodel.playerinfo, 0, sizeof(playerInfo_t) ); + + viewangles[YAW] = 180 - 30; + viewangles[PITCH] = 0; + viewangles[ROLL] = 0; + VectorClear( moveangles ); + + UI_PlayerInfo_SetModel( &s_playermodel.playerinfo, s_playermodel.modelskin ); + UI_PlayerInfo_SetInfo( &s_playermodel.playerinfo, LEGS_IDLE, TORSO_STAND, viewangles, moveangles, WP_MACHINEGUN, qfalse ); +} + +/* +================= +PlayerModel_SaveChanges +================= +*/ +static void PlayerModel_SaveChanges( void ) +{ + trap_Cvar_Set( "model", s_playermodel.modelskin ); + trap_Cvar_Set( "headmodel", s_playermodel.modelskin ); + trap_Cvar_Set( "team_model", s_playermodel.modelskin ); + trap_Cvar_Set( "team_headmodel", s_playermodel.modelskin ); +} + +/* +================= +PlayerModel_MenuEvent +================= +*/ +static void PlayerModel_MenuEvent( void* ptr, int event ) +{ + if (event != QM_ACTIVATED) + return; + + switch (((menucommon_s*)ptr)->id) + { + case ID_PREVPAGE: + if (s_playermodel.modelpage > 0) + { + s_playermodel.modelpage--; + PlayerModel_UpdateGrid(); + } + break; + + case ID_NEXTPAGE: + if (s_playermodel.modelpage < s_playermodel.numpages-1) + { + s_playermodel.modelpage++; + PlayerModel_UpdateGrid(); + } + break; + + case ID_BACK: + PlayerModel_SaveChanges(); + UI_PopMenu(); + break; + } +} + +/* +================= +PlayerModel_MenuKey +================= +*/ +static sfxHandle_t PlayerModel_MenuKey( int key ) +{ + menucommon_s* m; + int picnum; + + switch (key) + { + case K_KP_LEFTARROW: + case K_LEFTARROW: + m = Menu_ItemAtCursor(&s_playermodel.menu); + picnum = m->id - ID_PLAYERPIC0; + if (picnum >= 0 && picnum <= 15) + { + if (picnum > 0) + { + Menu_SetCursor(&s_playermodel.menu,s_playermodel.menu.cursor-1); + return (menu_move_sound); + + } + else if (s_playermodel.modelpage > 0) + { + s_playermodel.modelpage--; + Menu_SetCursor(&s_playermodel.menu,s_playermodel.menu.cursor+15); + PlayerModel_UpdateGrid(); + return (menu_move_sound); + } + else + return (menu_buzz_sound); + } + break; + + case K_KP_RIGHTARROW: + case K_RIGHTARROW: + m = Menu_ItemAtCursor(&s_playermodel.menu); + picnum = m->id - ID_PLAYERPIC0; + if (picnum >= 0 && picnum <= 15) + { + if ((picnum < 15) && (s_playermodel.modelpage*MAX_MODELSPERPAGE + picnum+1 < s_playermodel.nummodels)) + { + Menu_SetCursor(&s_playermodel.menu,s_playermodel.menu.cursor+1); + return (menu_move_sound); + } + else if ((picnum == 15) && (s_playermodel.modelpage < s_playermodel.numpages-1)) + { + s_playermodel.modelpage++; + Menu_SetCursor(&s_playermodel.menu,s_playermodel.menu.cursor-15); + PlayerModel_UpdateGrid(); + return (menu_move_sound); + } + else + return (menu_buzz_sound); + } + break; + + case K_MOUSE2: + case K_ESCAPE: + PlayerModel_SaveChanges(); + break; + } + + return ( Menu_DefaultKey( &s_playermodel.menu, key ) ); +} + +/* +================= +PlayerModel_PicEvent +================= +*/ +static void PlayerModel_PicEvent( void* ptr, int event ) +{ + int modelnum; + int maxlen; + char* buffptr; + char* pdest; + int i; + + if (event != QM_ACTIVATED) + return; + + for (i=0; iid - ID_PLAYERPIC0; + s_playermodel.pics[i].generic.flags |= QMF_HIGHLIGHT; + s_playermodel.picbuttons[i].generic.flags &= ~QMF_PULSEIFFOCUS; + + // get model and strip icon_ + modelnum = s_playermodel.modelpage*MAX_MODELSPERPAGE + i; + buffptr = s_playermodel.modelnames[modelnum] + strlen("models/players/"); + pdest = strstr(buffptr,"icon_"); + if (pdest) + { + // track the whole model/skin name + Q_strncpyz(s_playermodel.modelskin,buffptr,pdest-buffptr+1); + strcat(s_playermodel.modelskin,pdest + 5); + + // seperate the model name + maxlen = pdest-buffptr; + if (maxlen > 16) + maxlen = 16; + Q_strncpyz( s_playermodel.modelname.string, buffptr, maxlen ); + Q_strupr( s_playermodel.modelname.string ); + + // seperate the skin name + maxlen = strlen(pdest+5)+1; + if (maxlen > 16) + maxlen = 16; + Q_strncpyz( s_playermodel.skinname.string, pdest+5, maxlen ); + Q_strupr( s_playermodel.skinname.string ); + + s_playermodel.selectedmodel = modelnum; + + if( trap_MemoryRemaining() > LOW_MEMORY ) { + PlayerModel_UpdateModel(); + } + } +} + +/* +================= +PlayerModel_DrawPlayer +================= +*/ +static void PlayerModel_DrawPlayer( void *self ) +{ + menubitmap_s* b; + + b = (menubitmap_s*) self; + + if( trap_MemoryRemaining() <= LOW_MEMORY ) { + UI_DrawProportionalString( b->generic.x, b->generic.y + b->height / 2, "LOW MEMORY", UI_LEFT, color_red ); + return; + } + + UI_DrawPlayer( b->generic.x, b->generic.y, b->width, b->height, &s_playermodel.playerinfo, uis.realtime/2 ); +} + +/* +================= +PlayerModel_BuildList +================= +*/ +static void PlayerModel_BuildList( void ) +{ + int numdirs; + int numfiles; + char dirlist[2048]; + char filelist[2048]; + char skinname[64]; + char* dirptr; + char* fileptr; + int i; + int j; + int dirlen; + int filelen; + qboolean precache; + + precache = trap_Cvar_VariableValue("com_buildscript"); + + s_playermodel.modelpage = 0; + s_playermodel.nummodels = 0; + + // iterate directory of all player models + numdirs = trap_FS_GetFileList("models/players", "/", dirlist, 2048 ); + dirptr = dirlist; + for (i=0; i= MAX_PLAYERMODELS) + // return; + } + + if( precache ) { + trap_S_RegisterSound( va( "sound/player/announce/%s_wins.wav", skinname), qfalse ); + } + } + } + + //APSFIXME - Degenerate no models case + + s_playermodel.numpages = s_playermodel.nummodels/MAX_MODELSPERPAGE; + if (s_playermodel.nummodels % MAX_MODELSPERPAGE) + s_playermodel.numpages++; +} + +/* +================= +PlayerModel_SetMenuItems +================= +*/ +static void PlayerModel_SetMenuItems( void ) +{ + int i; + int maxlen; + char modelskin[64]; + char* buffptr; + char* pdest; + + // name + trap_Cvar_VariableStringBuffer( "name", s_playermodel.playername.string, 16 ); + Q_CleanStr( s_playermodel.playername.string ); + + // model + trap_Cvar_VariableStringBuffer( "model", s_playermodel.modelskin, 64 ); + + // find model in our list + for (i=0; i 16) + maxlen = 16; + Q_strncpyz( s_playermodel.modelname.string, buffptr, maxlen ); + Q_strupr( s_playermodel.modelname.string ); + + // seperate the skin name + maxlen = strlen(pdest+5)+1; + if (maxlen > 16) + maxlen = 16; + Q_strncpyz( s_playermodel.skinname.string, pdest+5, maxlen ); + Q_strupr( s_playermodel.skinname.string ); + break; + } + } +} + +/* +================= +PlayerModel_MenuInit +================= +*/ +static void PlayerModel_MenuInit( void ) +{ + int i; + int j; + int k; + int x; + int y; + static char playername[32]; + static char modelname[32]; + static char skinname[32]; + + // zero set all our globals + memset( &s_playermodel, 0 ,sizeof(playermodel_t) ); + + PlayerModel_Cache(); + + s_playermodel.menu.key = PlayerModel_MenuKey; + s_playermodel.menu.wrapAround = qtrue; + s_playermodel.menu.fullscreen = qtrue; + + s_playermodel.banner.generic.type = MTYPE_BTEXT; + s_playermodel.banner.generic.x = 320; + s_playermodel.banner.generic.y = 16; + s_playermodel.banner.string = "PLAYER MODEL"; + s_playermodel.banner.color = color_white; + s_playermodel.banner.style = UI_CENTER; + + s_playermodel.framel.generic.type = MTYPE_BITMAP; + s_playermodel.framel.generic.name = MODEL_FRAMEL; + s_playermodel.framel.generic.flags = QMF_LEFT_JUSTIFY|QMF_INACTIVE; + s_playermodel.framel.generic.x = 0; + s_playermodel.framel.generic.y = 78; + s_playermodel.framel.width = 256; + s_playermodel.framel.height = 329; + + s_playermodel.framer.generic.type = MTYPE_BITMAP; + s_playermodel.framer.generic.name = MODEL_FRAMER; + s_playermodel.framer.generic.flags = QMF_LEFT_JUSTIFY|QMF_INACTIVE; + s_playermodel.framer.generic.x = 376; + s_playermodel.framer.generic.y = 76; + s_playermodel.framer.width = 256; + s_playermodel.framer.height = 334; + + s_playermodel.ports.generic.type = MTYPE_BITMAP; + s_playermodel.ports.generic.name = MODEL_PORTS; + s_playermodel.ports.generic.flags = QMF_LEFT_JUSTIFY|QMF_INACTIVE; + s_playermodel.ports.generic.x = 50; + s_playermodel.ports.generic.y = 59; + s_playermodel.ports.width = 274; + s_playermodel.ports.height = 274; + + y = 59; + for (i=0,k=0; icurrentWeapon = weaponNum; +tryagain: + pi->realWeapon = weaponNum; + pi->weaponModel = 0; + pi->barrelModel = 0; + pi->flashModel = 0; + + if ( weaponNum == WP_NONE ) { + return; + } + + for ( item = bg_itemlist + 1; item->classname ; item++ ) { + if ( item->giType != IT_WEAPON ) { + continue; + } + if ( item->giTag == weaponNum ) { + break; + } + } + + if ( item->classname ) { + pi->weaponModel = trap_R_RegisterModel( item->world_model[0] ); + } + + if( pi->weaponModel == 0 ) { + if( weaponNum == WP_MACHINEGUN ) { + weaponNum = WP_NONE; + goto tryagain; + } + weaponNum = WP_MACHINEGUN; + goto tryagain; + } + + if ( weaponNum == WP_MACHINEGUN || weaponNum == WP_GAUNTLET || weaponNum == WP_BFG ) { + strcpy( path, item->world_model[0] ); + COM_StripExtension( path, path ); + strcat( path, "_barrel.md3" ); + pi->barrelModel = trap_R_RegisterModel( path ); + } + + strcpy( path, item->world_model[0] ); + COM_StripExtension( path, path ); + strcat( path, "_flash.md3" ); + pi->flashModel = trap_R_RegisterModel( path ); + + switch( weaponNum ) { + case WP_GAUNTLET: + MAKERGB( pi->flashDlightColor, 0.6f, 0.6f, 1 ); + break; + + case WP_MACHINEGUN: + MAKERGB( pi->flashDlightColor, 1, 1, 0 ); + break; + + case WP_SHOTGUN: + MAKERGB( pi->flashDlightColor, 1, 1, 0 ); + break; + + case WP_GRENADE_LAUNCHER: + MAKERGB( pi->flashDlightColor, 1, 0.7f, 0.5f ); + break; + + case WP_ROCKET_LAUNCHER: + MAKERGB( pi->flashDlightColor, 1, 0.75f, 0 ); + break; + + case WP_LIGHTNING: + MAKERGB( pi->flashDlightColor, 0.6f, 0.6f, 1 ); + break; + + case WP_RAILGUN: + MAKERGB( pi->flashDlightColor, 1, 0.5f, 0 ); + break; + + case WP_PLASMAGUN: + MAKERGB( pi->flashDlightColor, 0.6f, 0.6f, 1 ); + break; + + case WP_BFG: + MAKERGB( pi->flashDlightColor, 1, 0.7f, 1 ); + break; + + case WP_GRAPPLING_HOOK: + MAKERGB( pi->flashDlightColor, 0.6f, 0.6f, 1 ); + break; + + default: + MAKERGB( pi->flashDlightColor, 1, 1, 1 ); + break; + } +} + + +/* +=============== +UI_ForceLegsAnim +=============== +*/ +static void UI_ForceLegsAnim( playerInfo_t *pi, int anim ) { + pi->legsAnim = ( ( pi->legsAnim & ANIM_TOGGLEBIT ) ^ ANIM_TOGGLEBIT ) | anim; + + if ( anim == LEGS_JUMP ) { + pi->legsAnimationTimer = UI_TIMER_JUMP; + } +} + + +/* +=============== +UI_SetLegsAnim +=============== +*/ +static void UI_SetLegsAnim( playerInfo_t *pi, int anim ) { + if ( pi->pendingLegsAnim ) { + anim = pi->pendingLegsAnim; + pi->pendingLegsAnim = 0; + } + UI_ForceLegsAnim( pi, anim ); +} + + +/* +=============== +UI_ForceTorsoAnim +=============== +*/ +static void UI_ForceTorsoAnim( playerInfo_t *pi, int anim ) { + pi->torsoAnim = ( ( pi->torsoAnim & ANIM_TOGGLEBIT ) ^ ANIM_TOGGLEBIT ) | anim; + + if ( anim == TORSO_GESTURE ) { + pi->torsoAnimationTimer = UI_TIMER_GESTURE; + } + + if ( anim == TORSO_ATTACK || anim == TORSO_ATTACK2 ) { + pi->torsoAnimationTimer = UI_TIMER_ATTACK; + } +} + + +/* +=============== +UI_SetTorsoAnim +=============== +*/ +static void UI_SetTorsoAnim( playerInfo_t *pi, int anim ) { + if ( pi->pendingTorsoAnim ) { + anim = pi->pendingTorsoAnim; + pi->pendingTorsoAnim = 0; + } + + UI_ForceTorsoAnim( pi, anim ); +} + + +/* +=============== +UI_TorsoSequencing +=============== +*/ +static void UI_TorsoSequencing( playerInfo_t *pi ) { + int currentAnim; + + currentAnim = pi->torsoAnim & ~ANIM_TOGGLEBIT; + + if ( pi->weapon != pi->currentWeapon ) { + if ( currentAnim != TORSO_DROP ) { + pi->torsoAnimationTimer = UI_TIMER_WEAPON_SWITCH; + UI_ForceTorsoAnim( pi, TORSO_DROP ); + } + } + + if ( pi->torsoAnimationTimer > 0 ) { + return; + } + + if( currentAnim == TORSO_GESTURE ) { + UI_SetTorsoAnim( pi, TORSO_STAND ); + return; + } + + if( currentAnim == TORSO_ATTACK || currentAnim == TORSO_ATTACK2 ) { + UI_SetTorsoAnim( pi, TORSO_STAND ); + return; + } + + if ( currentAnim == TORSO_DROP ) { + UI_PlayerInfo_SetWeapon( pi, pi->weapon ); + pi->torsoAnimationTimer = UI_TIMER_WEAPON_SWITCH; + UI_ForceTorsoAnim( pi, TORSO_RAISE ); + return; + } + + if ( currentAnim == TORSO_RAISE ) { + UI_SetTorsoAnim( pi, TORSO_STAND ); + return; + } +} + + +/* +=============== +UI_LegsSequencing +=============== +*/ +static void UI_LegsSequencing( playerInfo_t *pi ) { + int currentAnim; + + currentAnim = pi->legsAnim & ~ANIM_TOGGLEBIT; + + if ( pi->legsAnimationTimer > 0 ) { + if ( currentAnim == LEGS_JUMP ) { + jumpHeight = JUMP_HEIGHT * sin( M_PI * ( UI_TIMER_JUMP - pi->legsAnimationTimer ) / UI_TIMER_JUMP ); + } + return; + } + + if ( currentAnim == LEGS_JUMP ) { + UI_ForceLegsAnim( pi, LEGS_LAND ); + pi->legsAnimationTimer = UI_TIMER_LAND; + jumpHeight = 0; + return; + } + + if ( currentAnim == LEGS_LAND ) { + UI_SetLegsAnim( pi, LEGS_IDLE ); + return; + } +} + + +/* +====================== +UI_PositionEntityOnTag +====================== +*/ +static void UI_PositionEntityOnTag( refEntity_t *entity, const refEntity_t *parent, + clipHandle_t parentModel, char *tagName ) { + int i; + orientation_t lerped; + + // lerp the tag + trap_CM_LerpTag( &lerped, parentModel, parent->oldframe, parent->frame, + 1.0 - parent->backlerp, tagName ); + + // FIXME: allow origin offsets along tag? + VectorCopy( parent->origin, entity->origin ); + for ( i = 0 ; i < 3 ; i++ ) { + VectorMA( entity->origin, lerped.origin[i], parent->axis[i], entity->origin ); + } + + // cast away const because of compiler problems + MatrixMultiply( lerped.axis, ((refEntity_t*)parent)->axis, entity->axis ); + entity->backlerp = parent->backlerp; +} + + +/* +====================== +UI_PositionRotatedEntityOnTag +====================== +*/ +static void UI_PositionRotatedEntityOnTag( refEntity_t *entity, const refEntity_t *parent, + clipHandle_t parentModel, char *tagName ) { + int i; + orientation_t lerped; + vec3_t tempAxis[3]; + + // lerp the tag + trap_CM_LerpTag( &lerped, parentModel, parent->oldframe, parent->frame, + 1.0 - parent->backlerp, tagName ); + + // FIXME: allow origin offsets along tag? + VectorCopy( parent->origin, entity->origin ); + for ( i = 0 ; i < 3 ; i++ ) { + VectorMA( entity->origin, lerped.origin[i], parent->axis[i], entity->origin ); + } + + // cast away const because of compiler problems + MatrixMultiply( entity->axis, ((refEntity_t *)parent)->axis, tempAxis ); + MatrixMultiply( lerped.axis, tempAxis, entity->axis ); +} + + +/* +=============== +UI_SetLerpFrameAnimation +=============== +*/ +static void UI_SetLerpFrameAnimation( playerInfo_t *ci, lerpFrame_t *lf, int newAnimation ) { + animation_t *anim; + + lf->animationNumber = newAnimation; + newAnimation &= ~ANIM_TOGGLEBIT; + + if ( newAnimation < 0 || newAnimation >= MAX_ANIMATIONS ) { + trap_Error( va("Bad animation number: %i", newAnimation) ); + } + + anim = &ci->animations[ newAnimation ]; + + lf->animation = anim; + lf->animationTime = lf->frameTime + anim->initialLerp; +} + + +/* +=============== +UI_RunLerpFrame +=============== +*/ +static void UI_RunLerpFrame( playerInfo_t *ci, lerpFrame_t *lf, int newAnimation ) { + int f; + animation_t *anim; + + // see if the animation sequence is switching + if ( newAnimation != lf->animationNumber || !lf->animation ) { + UI_SetLerpFrameAnimation( ci, lf, newAnimation ); + } + + // if we have passed the current frame, move it to + // oldFrame and calculate a new frame + if ( dp_realtime >= lf->frameTime ) { + lf->oldFrame = lf->frame; + lf->oldFrameTime = lf->frameTime; + + // get the next frame based on the animation + anim = lf->animation; + if ( dp_realtime < lf->animationTime ) { + lf->frameTime = lf->animationTime; // initial lerp + } else { + lf->frameTime = lf->oldFrameTime + anim->frameLerp; + } + f = ( lf->frameTime - lf->animationTime ) / anim->frameLerp; + if ( f >= anim->numFrames ) { + f -= anim->numFrames; + if ( anim->loopFrames ) { + f %= anim->loopFrames; + f += anim->numFrames - anim->loopFrames; + } else { + f = anim->numFrames - 1; + // the animation is stuck at the end, so it + // can immediately transition to another sequence + lf->frameTime = dp_realtime; + } + } + lf->frame = anim->firstFrame + f; + if ( dp_realtime > lf->frameTime ) { + lf->frameTime = dp_realtime; + } + } + + if ( lf->frameTime > dp_realtime + 200 ) { + lf->frameTime = dp_realtime; + } + + if ( lf->oldFrameTime > dp_realtime ) { + lf->oldFrameTime = dp_realtime; + } + // calculate current lerp value + if ( lf->frameTime == lf->oldFrameTime ) { + lf->backlerp = 0; + } else { + lf->backlerp = 1.0 - (float)( dp_realtime - lf->oldFrameTime ) / ( lf->frameTime - lf->oldFrameTime ); + } +} + + +/* +=============== +UI_PlayerAnimation +=============== +*/ +static void UI_PlayerAnimation( playerInfo_t *pi, int *legsOld, int *legs, float *legsBackLerp, + int *torsoOld, int *torso, float *torsoBackLerp ) { + + // legs animation + pi->legsAnimationTimer -= uis.frametime; + if ( pi->legsAnimationTimer < 0 ) { + pi->legsAnimationTimer = 0; + } + + UI_LegsSequencing( pi ); + + if ( pi->legs.yawing && ( pi->legsAnim & ~ANIM_TOGGLEBIT ) == LEGS_IDLE ) { + UI_RunLerpFrame( pi, &pi->legs, LEGS_TURN ); + } else { + UI_RunLerpFrame( pi, &pi->legs, pi->legsAnim ); + } + *legsOld = pi->legs.oldFrame; + *legs = pi->legs.frame; + *legsBackLerp = pi->legs.backlerp; + + // torso animation + pi->torsoAnimationTimer -= uis.frametime; + if ( pi->torsoAnimationTimer < 0 ) { + pi->torsoAnimationTimer = 0; + } + + UI_TorsoSequencing( pi ); + + UI_RunLerpFrame( pi, &pi->torso, pi->torsoAnim ); + *torsoOld = pi->torso.oldFrame; + *torso = pi->torso.frame; + *torsoBackLerp = pi->torso.backlerp; +} + + +/* +================== +UI_SwingAngles +================== +*/ +static void UI_SwingAngles( float destination, float swingTolerance, float clampTolerance, + float speed, float *angle, qboolean *swinging ) { + float swing; + float move; + float scale; + + if ( !*swinging ) { + // see if a swing should be started + swing = AngleSubtract( *angle, destination ); + if ( swing > swingTolerance || swing < -swingTolerance ) { + *swinging = qtrue; + } + } + + if ( !*swinging ) { + return; + } + + // modify the speed depending on the delta + // so it doesn't seem so linear + swing = AngleSubtract( destination, *angle ); + scale = fabs( swing ); + if ( scale < swingTolerance * 0.5 ) { + scale = 0.5; + } else if ( scale < swingTolerance ) { + scale = 1.0; + } else { + scale = 2.0; + } + + // swing towards the destination angle + if ( swing >= 0 ) { + move = uis.frametime * scale * speed; + if ( move >= swing ) { + move = swing; + *swinging = qfalse; + } + *angle = AngleMod( *angle + move ); + } else if ( swing < 0 ) { + move = uis.frametime * scale * -speed; + if ( move <= swing ) { + move = swing; + *swinging = qfalse; + } + *angle = AngleMod( *angle + move ); + } + + // clamp to no more than tolerance + swing = AngleSubtract( destination, *angle ); + if ( swing > clampTolerance ) { + *angle = AngleMod( destination - (clampTolerance - 1) ); + } else if ( swing < -clampTolerance ) { + *angle = AngleMod( destination + (clampTolerance - 1) ); + } +} + + +/* +====================== +UI_MovedirAdjustment +====================== +*/ +static float UI_MovedirAdjustment( playerInfo_t *pi ) { + vec3_t relativeAngles; + vec3_t moveVector; + + VectorSubtract( pi->viewAngles, pi->moveAngles, relativeAngles ); + AngleVectors( relativeAngles, moveVector, NULL, NULL ); + if ( Q_fabs( moveVector[0] ) < 0.01 ) { + moveVector[0] = 0.0; + } + if ( Q_fabs( moveVector[1] ) < 0.01 ) { + moveVector[1] = 0.0; + } + + if ( moveVector[1] == 0 && moveVector[0] > 0 ) { + return 0; + } + if ( moveVector[1] < 0 && moveVector[0] > 0 ) { + return 22; + } + if ( moveVector[1] < 0 && moveVector[0] == 0 ) { + return 45; + } + if ( moveVector[1] < 0 && moveVector[0] < 0 ) { + return -22; + } + if ( moveVector[1] == 0 && moveVector[0] < 0 ) { + return 0; + } + if ( moveVector[1] > 0 && moveVector[0] < 0 ) { + return 22; + } + if ( moveVector[1] > 0 && moveVector[0] == 0 ) { + return -45; + } + + return -22; +} + + +/* +=============== +UI_PlayerAngles +=============== +*/ +static void UI_PlayerAngles( playerInfo_t *pi, vec3_t legs[3], vec3_t torso[3], vec3_t head[3] ) { + vec3_t legsAngles, torsoAngles, headAngles; + float dest; + float adjust; + + VectorCopy( pi->viewAngles, headAngles ); + headAngles[YAW] = AngleMod( headAngles[YAW] ); + VectorClear( legsAngles ); + VectorClear( torsoAngles ); + + // --------- yaw ------------- + + // allow yaw to drift a bit + if ( ( pi->legsAnim & ~ANIM_TOGGLEBIT ) != LEGS_IDLE + || ( pi->torsoAnim & ~ANIM_TOGGLEBIT ) != TORSO_STAND ) { + // if not standing still, always point all in the same direction + pi->torso.yawing = qtrue; // always center + pi->torso.pitching = qtrue; // always center + pi->legs.yawing = qtrue; // always center + } + + // adjust legs for movement dir + adjust = UI_MovedirAdjustment( pi ); + legsAngles[YAW] = headAngles[YAW] + adjust; + torsoAngles[YAW] = headAngles[YAW] + 0.25 * adjust; + + + // torso + UI_SwingAngles( torsoAngles[YAW], 25, 90, SWINGSPEED, &pi->torso.yawAngle, &pi->torso.yawing ); + UI_SwingAngles( legsAngles[YAW], 40, 90, SWINGSPEED, &pi->legs.yawAngle, &pi->legs.yawing ); + + torsoAngles[YAW] = pi->torso.yawAngle; + legsAngles[YAW] = pi->legs.yawAngle; + + // --------- pitch ------------- + + // only show a fraction of the pitch angle in the torso + if ( headAngles[PITCH] > 180 ) { + dest = (-360 + headAngles[PITCH]) * 0.75; + } else { + dest = headAngles[PITCH] * 0.75; + } + UI_SwingAngles( dest, 15, 30, 0.1f, &pi->torso.pitchAngle, &pi->torso.pitching ); + torsoAngles[PITCH] = pi->torso.pitchAngle; + + // pull the angles back out of the hierarchial chain + AnglesSubtract( headAngles, torsoAngles, headAngles ); + AnglesSubtract( torsoAngles, legsAngles, torsoAngles ); + AnglesToAxis( legsAngles, legs ); + AnglesToAxis( torsoAngles, torso ); + AnglesToAxis( headAngles, head ); +} + + +/* +=============== +UI_PlayerFloatSprite +=============== +*/ +static void UI_PlayerFloatSprite( playerInfo_t *pi, vec3_t origin, qhandle_t shader ) { + refEntity_t ent; + + memset( &ent, 0, sizeof( ent ) ); + VectorCopy( origin, ent.origin ); + ent.origin[2] += 48; + ent.reType = RT_SPRITE; + ent.customShader = shader; + ent.radius = 10; + ent.renderfx = 0; + trap_R_AddRefEntityToScene( &ent ); +} + + +/* +====================== +UI_MachinegunSpinAngle +====================== +*/ +float UI_MachinegunSpinAngle( playerInfo_t *pi ) { + int delta; + float angle; + float speed; + int torsoAnim; + + delta = dp_realtime - pi->barrelTime; + if ( pi->barrelSpinning ) { + angle = pi->barrelAngle + delta * SPIN_SPEED; + } else { + if ( delta > COAST_TIME ) { + delta = COAST_TIME; + } + + speed = 0.5 * ( SPIN_SPEED + (float)( COAST_TIME - delta ) / COAST_TIME ); + angle = pi->barrelAngle + delta * speed; + } + + torsoAnim = pi->torsoAnim & ~ANIM_TOGGLEBIT; + if( torsoAnim == TORSO_ATTACK2 ) { + torsoAnim = TORSO_ATTACK; + } + if ( pi->barrelSpinning == !(torsoAnim == TORSO_ATTACK) ) { + pi->barrelTime = dp_realtime; + pi->barrelAngle = AngleMod( angle ); + pi->barrelSpinning = !!(torsoAnim == TORSO_ATTACK); + } + + return angle; +} + + +/* +=============== +UI_DrawPlayer +=============== +*/ +void UI_DrawPlayer( float x, float y, float w, float h, playerInfo_t *pi, int time ) { + refdef_t refdef; + refEntity_t legs; + refEntity_t torso; + refEntity_t head; + refEntity_t gun; + refEntity_t barrel; + refEntity_t flash; + vec3_t origin; + int renderfx; + vec3_t mins = {-16, -16, -24}; + vec3_t maxs = {16, 16, 32}; + float len; + float xx; + + if ( !pi->legsModel || !pi->torsoModel || !pi->headModel || !pi->animations[0].numFrames ) { + return; + } + + dp_realtime = time; + + if ( pi->pendingWeapon != -1 && dp_realtime > pi->weaponTimer ) { + pi->weapon = pi->pendingWeapon; + pi->lastWeapon = pi->pendingWeapon; + pi->pendingWeapon = -1; + pi->weaponTimer = 0; + if( pi->currentWeapon != pi->weapon ) { + trap_S_StartLocalSound( weaponChangeSound, CHAN_LOCAL ); + } + } + + UI_AdjustFrom640( &x, &y, &w, &h ); + + y -= jumpHeight; + + memset( &refdef, 0, sizeof( refdef ) ); + memset( &legs, 0, sizeof(legs) ); + memset( &torso, 0, sizeof(torso) ); + memset( &head, 0, sizeof(head) ); + + refdef.rdflags = RDF_NOWORLDMODEL; + + AxisClear( refdef.viewaxis ); + + refdef.x = x; + refdef.y = y; + refdef.width = w; + refdef.height = h; + + refdef.fov_x = (int)((float)refdef.width / 640.0f * 90.0f); + xx = refdef.width / tan( refdef.fov_x / 360 * M_PI ); + refdef.fov_y = atan2( refdef.height, xx ); + refdef.fov_y *= ( 360 / M_PI ); + + // calculate distance so the player nearly fills the box + len = 0.7 * ( maxs[2] - mins[2] ); + origin[0] = len / tan( DEG2RAD(refdef.fov_x) * 0.5 ); + origin[1] = 0.5 * ( mins[1] + maxs[1] ); + origin[2] = -0.5 * ( mins[2] + maxs[2] ); + + refdef.time = dp_realtime; + + trap_R_ClearScene(); + + // get the rotation information + UI_PlayerAngles( pi, legs.axis, torso.axis, head.axis ); + + // get the animation state (after rotation, to allow feet shuffle) + UI_PlayerAnimation( pi, &legs.oldframe, &legs.frame, &legs.backlerp, + &torso.oldframe, &torso.frame, &torso.backlerp ); + + renderfx = RF_LIGHTING_ORIGIN | RF_NOSHADOW; + + // + // add the legs + // + legs.hModel = pi->legsModel; + legs.customSkin = pi->legsSkin; + + VectorCopy( origin, legs.origin ); + + VectorCopy( origin, legs.lightingOrigin ); + legs.renderfx = renderfx; + VectorCopy (legs.origin, legs.oldorigin); + + trap_R_AddRefEntityToScene( &legs ); + + if (!legs.hModel) { + return; + } + + // + // add the torso + // + torso.hModel = pi->torsoModel; + if (!torso.hModel) { + return; + } + + torso.customSkin = pi->torsoSkin; + + VectorCopy( origin, torso.lightingOrigin ); + + UI_PositionRotatedEntityOnTag( &torso, &legs, pi->legsModel, "tag_torso"); + + torso.renderfx = renderfx; + + trap_R_AddRefEntityToScene( &torso ); + + // + // add the head + // + head.hModel = pi->headModel; + if (!head.hModel) { + return; + } + head.customSkin = pi->headSkin; + + VectorCopy( origin, head.lightingOrigin ); + + UI_PositionRotatedEntityOnTag( &head, &torso, pi->torsoModel, "tag_head"); + + head.renderfx = renderfx; + + trap_R_AddRefEntityToScene( &head ); + + // + // add the gun + // + if ( pi->currentWeapon != WP_NONE ) { + memset( &gun, 0, sizeof(gun) ); + gun.hModel = pi->weaponModel; + VectorCopy( origin, gun.lightingOrigin ); + UI_PositionEntityOnTag( &gun, &torso, pi->torsoModel, "tag_weapon"); + gun.renderfx = renderfx; + trap_R_AddRefEntityToScene( &gun ); + } + + // + // add the spinning barrel + // + if ( pi->realWeapon == WP_MACHINEGUN || pi->realWeapon == WP_GAUNTLET || pi->realWeapon == WP_BFG ) { + vec3_t angles; + + memset( &barrel, 0, sizeof(barrel) ); + VectorCopy( origin, barrel.lightingOrigin ); + barrel.renderfx = renderfx; + + barrel.hModel = pi->barrelModel; + angles[YAW] = 0; + angles[PITCH] = 0; + angles[ROLL] = UI_MachinegunSpinAngle( pi ); + if( pi->realWeapon == WP_GAUNTLET || pi->realWeapon == WP_BFG ) { + angles[PITCH] = angles[ROLL]; + angles[ROLL] = 0; + } + AnglesToAxis( angles, barrel.axis ); + + UI_PositionRotatedEntityOnTag( &barrel, &gun, pi->weaponModel, "tag_barrel"); + + trap_R_AddRefEntityToScene( &barrel ); + } + + // + // add muzzle flash + // + if ( dp_realtime <= pi->muzzleFlashTime ) { + if ( pi->flashModel ) { + memset( &flash, 0, sizeof(flash) ); + flash.hModel = pi->flashModel; + VectorCopy( origin, flash.lightingOrigin ); + UI_PositionEntityOnTag( &flash, &gun, pi->weaponModel, "tag_flash"); + flash.renderfx = renderfx; + trap_R_AddRefEntityToScene( &flash ); + } + + // make a dlight for the flash + if ( pi->flashDlightColor[0] || pi->flashDlightColor[1] || pi->flashDlightColor[2] ) { + trap_R_AddLightToScene( flash.origin, 200 + (rand()&31), pi->flashDlightColor[0], + pi->flashDlightColor[1], pi->flashDlightColor[2] ); + } + } + + // + // add the chat icon + // + if ( pi->chat ) { + UI_PlayerFloatSprite( pi, origin, trap_R_RegisterShaderNoMip( "sprites/balloon3" ) ); + } + + // + // add an accent light + // + origin[0] -= 100; // + = behind, - = in front + origin[1] += 100; // + = left, - = right + origin[2] += 100; // + = above, - = below + trap_R_AddLightToScene( origin, 500, 1.0, 1.0, 1.0 ); + + origin[0] -= 100; + origin[1] -= 100; + origin[2] -= 100; + trap_R_AddLightToScene( origin, 500, 1.0, 0.0, 0.0 ); + + trap_R_RenderScene( &refdef ); +} + + +/* +========================== +UI_RegisterClientSkin +========================== +*/ +static qboolean UI_RegisterClientSkin( playerInfo_t *pi, const char *modelName, const char *skinName ) { + char filename[MAX_QPATH]; + + Com_sprintf( filename, sizeof( filename ), "models/players/%s/lower_%s.skin", modelName, skinName ); + pi->legsSkin = trap_R_RegisterSkin( filename ); + + Com_sprintf( filename, sizeof( filename ), "models/players/%s/upper_%s.skin", modelName, skinName ); + pi->torsoSkin = trap_R_RegisterSkin( filename ); + + Com_sprintf( filename, sizeof( filename ), "models/players/%s/head_%s.skin", modelName, skinName ); + pi->headSkin = trap_R_RegisterSkin( filename ); + + if ( !pi->legsSkin || !pi->torsoSkin || !pi->headSkin ) { + return qfalse; + } + + return qtrue; +} + + +/* +====================== +UI_ParseAnimationFile +====================== +*/ +static qboolean UI_ParseAnimationFile( const char *filename, animation_t *animations ) { + char *text_p, *prev; + int len; + int i; + char *token; + float fps; + int skip; + char text[20000]; + fileHandle_t f; + + memset( animations, 0, sizeof( animation_t ) * MAX_ANIMATIONS ); + + // load the file + len = trap_FS_FOpenFile( filename, &f, FS_READ ); + if ( len <= 0 ) { + return qfalse; + } + if ( len >= ( sizeof( text ) - 1 ) ) { + Com_Printf( "File %s too long\n", filename ); + return qfalse; + } + trap_FS_Read( text, len, f ); + text[len] = 0; + trap_FS_FCloseFile( f ); + + // parse the text + text_p = text; + skip = 0; // quite the compiler warning + + // read optional parameters + while ( 1 ) { + prev = text_p; // so we can unget + token = COM_Parse( &text_p ); + if ( !token ) { + break; + } + if ( !Q_stricmp( token, "footsteps" ) ) { + token = COM_Parse( &text_p ); + if ( !token ) { + break; + } + continue; + } else if ( !Q_stricmp( token, "headoffset" ) ) { + for ( i = 0 ; i < 3 ; i++ ) { + token = COM_Parse( &text_p ); + if ( !token ) { + break; + } + } + continue; + } else if ( !Q_stricmp( token, "sex" ) ) { + token = COM_Parse( &text_p ); + if ( !token ) { + break; + } + continue; + } + + // if it is a number, start parsing animations + if ( token[0] >= '0' && token[0] <= '9' ) { + text_p = prev; // unget the token + break; + } + + Com_Printf( "unknown token '%s' is %s\n", token, filename ); + } + + // read information for each frame + for ( i = 0 ; i < MAX_ANIMATIONS ; i++ ) { + + token = COM_Parse( &text_p ); + if ( !token ) { + break; + } + animations[i].firstFrame = atoi( token ); + // leg only frames are adjusted to not count the upper body only frames + if ( i == LEGS_WALKCR ) { + skip = animations[LEGS_WALKCR].firstFrame - animations[TORSO_GESTURE].firstFrame; + } + if ( i >= LEGS_WALKCR ) { + animations[i].firstFrame -= skip; + } + + token = COM_Parse( &text_p ); + if ( !token ) { + break; + } + animations[i].numFrames = atoi( token ); + + token = COM_Parse( &text_p ); + if ( !token ) { + break; + } + animations[i].loopFrames = atoi( token ); + + token = COM_Parse( &text_p ); + if ( !token ) { + break; + } + fps = atof( token ); + if ( fps == 0 ) { + fps = 1; + } + animations[i].frameLerp = 1000 / fps; + animations[i].initialLerp = 1000 / fps; + } + + if ( i != MAX_ANIMATIONS ) { + Com_Printf( "Error parsing animation file: %s", filename ); + return qfalse; + } + + return qtrue; +} + + +/* +========================== +UI_RegisterClientModelname +========================== +*/ +qboolean UI_RegisterClientModelname( playerInfo_t *pi, const char *modelSkinName ) { + char modelName[MAX_QPATH]; + char skinName[MAX_QPATH]; + char filename[MAX_QPATH]; + char *slash; + + pi->torsoModel = 0; + pi->headModel = 0; + + if ( !modelSkinName[0] ) { + return qfalse; + } + + Q_strncpyz( modelName, modelSkinName, sizeof( modelName ) ); + + slash = strchr( modelName, '/' ); + if ( !slash ) { + // modelName did not include a skin name + Q_strncpyz( skinName, "default", sizeof( skinName ) ); + } else { + Q_strncpyz( skinName, slash + 1, sizeof( skinName ) ); + // truncate modelName + *slash = 0; + } + + // load cmodels before models so filecache works + + Com_sprintf( filename, sizeof( filename ), "models/players/%s/lower.md3", modelName ); + pi->legsModel = trap_R_RegisterModel( filename ); + if ( !pi->legsModel ) { + Com_Printf( "Failed to load model file %s\n", filename ); + return qfalse; + } + + Com_sprintf( filename, sizeof( filename ), "models/players/%s/upper.md3", modelName ); + pi->torsoModel = trap_R_RegisterModel( filename ); + if ( !pi->torsoModel ) { + Com_Printf( "Failed to load model file %s\n", filename ); + return qfalse; + } + + Com_sprintf( filename, sizeof( filename ), "models/players/%s/head.md3", modelName ); + pi->headModel = trap_R_RegisterModel( filename ); + if ( !pi->headModel ) { + Com_Printf( "Failed to load model file %s\n", filename ); + return qfalse; + } + + // if any skins failed to load, fall back to default + if ( !UI_RegisterClientSkin( pi, modelName, skinName ) ) { + if ( !UI_RegisterClientSkin( pi, modelName, "default" ) ) { + Com_Printf( "Failed to load skin file: %s : %s\n", modelName, skinName ); + return qfalse; + } + } + + // load the animations + Com_sprintf( filename, sizeof( filename ), "models/players/%s/animation.cfg", modelName ); + if ( !UI_ParseAnimationFile( filename, pi->animations ) ) { + Com_Printf( "Failed to load animation file %s\n", filename ); + return qfalse; + } + + return qtrue; +} + + +/* +=============== +UI_PlayerInfo_SetModel +=============== +*/ +void UI_PlayerInfo_SetModel( playerInfo_t *pi, const char *model ) { + memset( pi, 0, sizeof(*pi) ); + UI_RegisterClientModelname( pi, model ); + pi->weapon = WP_MACHINEGUN; + pi->currentWeapon = pi->weapon; + pi->lastWeapon = pi->weapon; + pi->pendingWeapon = -1; + pi->weaponTimer = 0; + pi->chat = qfalse; + pi->newModel = qtrue; + UI_PlayerInfo_SetWeapon( pi, pi->weapon ); +} + + +/* +=============== +UI_PlayerInfo_SetInfo +=============== +*/ +void UI_PlayerInfo_SetInfo( playerInfo_t *pi, int legsAnim, int torsoAnim, vec3_t viewAngles, vec3_t moveAngles, weapon_t weaponNumber, qboolean chat ) { + int currentAnim; + weapon_t weaponNum; + + pi->chat = chat; + + // view angles + VectorCopy( viewAngles, pi->viewAngles ); + + // move angles + VectorCopy( moveAngles, pi->moveAngles ); + + if ( pi->newModel ) { + pi->newModel = qfalse; + + jumpHeight = 0; + pi->pendingLegsAnim = 0; + UI_ForceLegsAnim( pi, legsAnim ); + pi->legs.yawAngle = viewAngles[YAW]; + pi->legs.yawing = qfalse; + + pi->pendingTorsoAnim = 0; + UI_ForceTorsoAnim( pi, torsoAnim ); + pi->torso.yawAngle = viewAngles[YAW]; + pi->torso.yawing = qfalse; + + if ( weaponNumber != -1 ) { + pi->weapon = weaponNumber; + pi->currentWeapon = weaponNumber; + pi->lastWeapon = weaponNumber; + pi->pendingWeapon = -1; + pi->weaponTimer = 0; + UI_PlayerInfo_SetWeapon( pi, pi->weapon ); + } + + return; + } + + // weapon + if ( weaponNumber == -1 ) { + pi->pendingWeapon = -1; + pi->weaponTimer = 0; + } + else if ( weaponNumber != WP_NONE ) { + pi->pendingWeapon = weaponNumber; + pi->weaponTimer = dp_realtime + UI_TIMER_WEAPON_DELAY; + } + weaponNum = pi->lastWeapon; + pi->weapon = weaponNum; + + if ( torsoAnim == BOTH_DEATH1 || legsAnim == BOTH_DEATH1 ) { + torsoAnim = legsAnim = BOTH_DEATH1; + pi->weapon = pi->currentWeapon = WP_NONE; + UI_PlayerInfo_SetWeapon( pi, pi->weapon ); + + jumpHeight = 0; + pi->pendingLegsAnim = 0; + UI_ForceLegsAnim( pi, legsAnim ); + + pi->pendingTorsoAnim = 0; + UI_ForceTorsoAnim( pi, torsoAnim ); + + return; + } + + // leg animation + currentAnim = pi->legsAnim & ~ANIM_TOGGLEBIT; + if ( legsAnim != LEGS_JUMP && ( currentAnim == LEGS_JUMP || currentAnim == LEGS_LAND ) ) { + pi->pendingLegsAnim = legsAnim; + } + else if ( legsAnim != currentAnim ) { + jumpHeight = 0; + pi->pendingLegsAnim = 0; + UI_ForceLegsAnim( pi, legsAnim ); + } + + // torso animation + if ( torsoAnim == TORSO_STAND || torsoAnim == TORSO_STAND2 ) { + if ( weaponNum == WP_NONE || weaponNum == WP_GAUNTLET ) { + torsoAnim = TORSO_STAND2; + } + else { + torsoAnim = TORSO_STAND; + } + } + + if ( torsoAnim == TORSO_ATTACK || torsoAnim == TORSO_ATTACK2 ) { + if ( weaponNum == WP_NONE || weaponNum == WP_GAUNTLET ) { + torsoAnim = TORSO_ATTACK2; + } + else { + torsoAnim = TORSO_ATTACK; + } + pi->muzzleFlashTime = dp_realtime + UI_TIMER_MUZZLE_FLASH; + //FIXME play firing sound here + } + + currentAnim = pi->torsoAnim & ~ANIM_TOGGLEBIT; + + if ( weaponNum != pi->currentWeapon || currentAnim == TORSO_RAISE || currentAnim == TORSO_DROP ) { + pi->pendingTorsoAnim = torsoAnim; + } + else if ( ( currentAnim == TORSO_GESTURE || currentAnim == TORSO_ATTACK ) && ( torsoAnim != currentAnim ) ) { + pi->pendingTorsoAnim = torsoAnim; + } + else if ( torsoAnim != currentAnim ) { + pi->pendingTorsoAnim = 0; + UI_ForceTorsoAnim( pi, torsoAnim ); + } +} diff --git a/code/q3_ui/ui_playersettings.c b/code/q3_ui/ui_playersettings.c new file mode 100755 index 0000000..c299f75 --- /dev/null +++ b/code/q3_ui/ui_playersettings.c @@ -0,0 +1,513 @@ +/* +=========================================================================== +Copyright (C) 1999-2005 Id Software, Inc. + +This file is part of Quake III Arena source code. + +Quake III Arena source code is free software; you can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 2 of the License, +or (at your option) any later version. + +Quake III Arena source code is distributed in the hope that it will be +useful, but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Foobar; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ +// +#include "ui_local.h" + +#define ART_FRAMEL "menu/art/frame2_l" +#define ART_FRAMER "menu/art/frame1_r" +#define ART_MODEL0 "menu/art/model_0" +#define ART_MODEL1 "menu/art/model_1" +#define ART_BACK0 "menu/art/back_0" +#define ART_BACK1 "menu/art/back_1" +#define ART_FX_BASE "menu/art/fx_base" +#define ART_FX_BLUE "menu/art/fx_blue" +#define ART_FX_CYAN "menu/art/fx_cyan" +#define ART_FX_GREEN "menu/art/fx_grn" +#define ART_FX_RED "menu/art/fx_red" +#define ART_FX_TEAL "menu/art/fx_teal" +#define ART_FX_WHITE "menu/art/fx_white" +#define ART_FX_YELLOW "menu/art/fx_yel" + +#define ID_NAME 10 +#define ID_HANDICAP 11 +#define ID_EFFECTS 12 +#define ID_BACK 13 +#define ID_MODEL 14 + +#define MAX_NAMELENGTH 20 + + +typedef struct { + menuframework_s menu; + + menutext_s banner; + menubitmap_s framel; + menubitmap_s framer; + menubitmap_s player; + + menufield_s name; + menulist_s handicap; + menulist_s effects; + + menubitmap_s back; + menubitmap_s model; + menubitmap_s item_null; + + qhandle_t fxBasePic; + qhandle_t fxPic[7]; + playerInfo_t playerinfo; + int current_fx; + char playerModel[MAX_QPATH]; +} playersettings_t; + +static playersettings_t s_playersettings; + +static int gamecodetoui[] = {4,2,3,0,5,1,6}; +static int uitogamecode[] = {4,6,2,3,1,5,7}; + +static const char *handicap_items[] = { + "None", + "95", + "90", + "85", + "80", + "75", + "70", + "65", + "60", + "55", + "50", + "45", + "40", + "35", + "30", + "25", + "20", + "15", + "10", + "5", + 0 +}; + + +/* +================= +PlayerSettings_DrawName +================= +*/ +static void PlayerSettings_DrawName( void *self ) { + menufield_s *f; + qboolean focus; + int style; + char *txt; + char c; + float *color; + int n; + int basex, x, y; + char name[32]; + + f = (menufield_s*)self; + basex = f->generic.x; + y = f->generic.y; + focus = (f->generic.parent->cursor == f->generic.menuPosition); + + style = UI_LEFT|UI_SMALLFONT; + color = text_color_normal; + if( focus ) { + style |= UI_PULSE; + color = text_color_highlight; + } + + UI_DrawProportionalString( basex, y, "Name", style, color ); + + // draw the actual name + basex += 64; + y += PROP_HEIGHT; + txt = f->field.buffer; + color = g_color_table[ColorIndex(COLOR_WHITE)]; + x = basex; + while ( (c = *txt) != 0 ) { + if ( !focus && Q_IsColorString( txt ) ) { + n = ColorIndex( *(txt+1) ); + if( n == 0 ) { + n = 7; + } + color = g_color_table[n]; + txt += 2; + continue; + } + UI_DrawChar( x, y, c, style, color ); + txt++; + x += SMALLCHAR_WIDTH; + } + + // draw cursor if we have focus + if( focus ) { + if ( trap_Key_GetOverstrikeMode() ) { + c = 11; + } else { + c = 10; + } + + style &= ~UI_PULSE; + style |= UI_BLINK; + + UI_DrawChar( basex + f->field.cursor * SMALLCHAR_WIDTH, y, c, style, color_white ); + } + + // draw at bottom also using proportional font + Q_strncpyz( name, f->field.buffer, sizeof(name) ); + Q_CleanStr( name ); + UI_DrawProportionalString( 320, 440, name, UI_CENTER|UI_BIGFONT, text_color_normal ); +} + + +/* +================= +PlayerSettings_DrawHandicap +================= +*/ +static void PlayerSettings_DrawHandicap( void *self ) { + menulist_s *item; + qboolean focus; + int style; + float *color; + + item = (menulist_s *)self; + focus = (item->generic.parent->cursor == item->generic.menuPosition); + + style = UI_LEFT|UI_SMALLFONT; + color = text_color_normal; + if( focus ) { + style |= UI_PULSE; + color = text_color_highlight; + } + + UI_DrawProportionalString( item->generic.x, item->generic.y, "Handicap", style, color ); + UI_DrawProportionalString( item->generic.x + 64, item->generic.y + PROP_HEIGHT, handicap_items[item->curvalue], style, color ); +} + + +/* +================= +PlayerSettings_DrawEffects +================= +*/ +static void PlayerSettings_DrawEffects( void *self ) { + menulist_s *item; + qboolean focus; + int style; + float *color; + + item = (menulist_s *)self; + focus = (item->generic.parent->cursor == item->generic.menuPosition); + + style = UI_LEFT|UI_SMALLFONT; + color = text_color_normal; + if( focus ) { + style |= UI_PULSE; + color = text_color_highlight; + } + + UI_DrawProportionalString( item->generic.x, item->generic.y, "Effects", style, color ); + + UI_DrawHandlePic( item->generic.x + 64, item->generic.y + PROP_HEIGHT + 8, 128, 8, s_playersettings.fxBasePic ); + UI_DrawHandlePic( item->generic.x + 64 + item->curvalue * 16 + 8, item->generic.y + PROP_HEIGHT + 6, 16, 12, s_playersettings.fxPic[item->curvalue] ); +} + + +/* +================= +PlayerSettings_DrawPlayer +================= +*/ +static void PlayerSettings_DrawPlayer( void *self ) { + menubitmap_s *b; + vec3_t viewangles; + char buf[MAX_QPATH]; + + trap_Cvar_VariableStringBuffer( "model", buf, sizeof( buf ) ); + if ( strcmp( buf, s_playersettings.playerModel ) != 0 ) { + UI_PlayerInfo_SetModel( &s_playersettings.playerinfo, buf ); + strcpy( s_playersettings.playerModel, buf ); + + viewangles[YAW] = 180 - 30; + viewangles[PITCH] = 0; + viewangles[ROLL] = 0; + UI_PlayerInfo_SetInfo( &s_playersettings.playerinfo, LEGS_IDLE, TORSO_STAND, viewangles, vec3_origin, WP_MACHINEGUN, qfalse ); + } + + b = (menubitmap_s*) self; + UI_DrawPlayer( b->generic.x, b->generic.y, b->width, b->height, &s_playersettings.playerinfo, uis.realtime/2 ); +} + + +/* +================= +PlayerSettings_SaveChanges +================= +*/ +static void PlayerSettings_SaveChanges( void ) { + // name + trap_Cvar_Set( "name", s_playersettings.name.field.buffer ); + + // handicap + trap_Cvar_SetValue( "handicap", 100 - s_playersettings.handicap.curvalue * 5 ); + + // effects color + trap_Cvar_SetValue( "color1", uitogamecode[s_playersettings.effects.curvalue] ); +} + + +/* +================= +PlayerSettings_MenuKey +================= +*/ +static sfxHandle_t PlayerSettings_MenuKey( int key ) { + if( key == K_MOUSE2 || key == K_ESCAPE ) { + PlayerSettings_SaveChanges(); + } + return Menu_DefaultKey( &s_playersettings.menu, key ); +} + + +/* +================= +PlayerSettings_SetMenuItems +================= +*/ +static void PlayerSettings_SetMenuItems( void ) { + vec3_t viewangles; + int c; + int h; + + // name + Q_strncpyz( s_playersettings.name.field.buffer, UI_Cvar_VariableString("name"), sizeof(s_playersettings.name.field.buffer) ); + + // effects color + c = trap_Cvar_VariableValue( "color1" ) - 1; + if( c < 0 || c > 6 ) { + c = 6; + } + s_playersettings.effects.curvalue = gamecodetoui[c]; + + // model/skin + memset( &s_playersettings.playerinfo, 0, sizeof(playerInfo_t) ); + + viewangles[YAW] = 180 - 30; + viewangles[PITCH] = 0; + viewangles[ROLL] = 0; + + UI_PlayerInfo_SetModel( &s_playersettings.playerinfo, UI_Cvar_VariableString( "model" ) ); + UI_PlayerInfo_SetInfo( &s_playersettings.playerinfo, LEGS_IDLE, TORSO_STAND, viewangles, vec3_origin, WP_MACHINEGUN, qfalse ); + + // handicap + h = Com_Clamp( 5, 100, trap_Cvar_VariableValue("handicap") ); + s_playersettings.handicap.curvalue = 20 - h / 5; +} + + +/* +================= +PlayerSettings_MenuEvent +================= +*/ +static void PlayerSettings_MenuEvent( void* ptr, int event ) { + if( event != QM_ACTIVATED ) { + return; + } + + switch( ((menucommon_s*)ptr)->id ) { + case ID_HANDICAP: + trap_Cvar_Set( "handicap", va( "%i", 100 - 25 * s_playersettings.handicap.curvalue ) ); + break; + + case ID_MODEL: + PlayerSettings_SaveChanges(); + UI_PlayerModelMenu(); + break; + + case ID_BACK: + PlayerSettings_SaveChanges(); + UI_PopMenu(); + break; + } +} + + +/* +================= +PlayerSettings_MenuInit +================= +*/ +static void PlayerSettings_MenuInit( void ) { + int y; + + memset(&s_playersettings,0,sizeof(playersettings_t)); + + PlayerSettings_Cache(); + + s_playersettings.menu.key = PlayerSettings_MenuKey; + s_playersettings.menu.wrapAround = qtrue; + s_playersettings.menu.fullscreen = qtrue; + + s_playersettings.banner.generic.type = MTYPE_BTEXT; + s_playersettings.banner.generic.x = 320; + s_playersettings.banner.generic.y = 16; + s_playersettings.banner.string = "PLAYER SETTINGS"; + s_playersettings.banner.color = color_white; + s_playersettings.banner.style = UI_CENTER; + + s_playersettings.framel.generic.type = MTYPE_BITMAP; + s_playersettings.framel.generic.name = ART_FRAMEL; + s_playersettings.framel.generic.flags = QMF_LEFT_JUSTIFY|QMF_INACTIVE; + s_playersettings.framel.generic.x = 0; + s_playersettings.framel.generic.y = 78; + s_playersettings.framel.width = 256; + s_playersettings.framel.height = 329; + + s_playersettings.framer.generic.type = MTYPE_BITMAP; + s_playersettings.framer.generic.name = ART_FRAMER; + s_playersettings.framer.generic.flags = QMF_LEFT_JUSTIFY|QMF_INACTIVE; + s_playersettings.framer.generic.x = 376; + s_playersettings.framer.generic.y = 76; + s_playersettings.framer.width = 256; + s_playersettings.framer.height = 334; + + y = 144; + s_playersettings.name.generic.type = MTYPE_FIELD; + s_playersettings.name.generic.flags = QMF_NODEFAULTINIT; + s_playersettings.name.generic.ownerdraw = PlayerSettings_DrawName; + s_playersettings.name.field.widthInChars = MAX_NAMELENGTH; + s_playersettings.name.field.maxchars = MAX_NAMELENGTH; + s_playersettings.name.generic.x = 192; + s_playersettings.name.generic.y = y; + s_playersettings.name.generic.left = 192 - 8; + s_playersettings.name.generic.top = y - 8; + s_playersettings.name.generic.right = 192 + 200; + s_playersettings.name.generic.bottom = y + 2 * PROP_HEIGHT; + + y += 3 * PROP_HEIGHT; + s_playersettings.handicap.generic.type = MTYPE_SPINCONTROL; + s_playersettings.handicap.generic.flags = QMF_NODEFAULTINIT; + s_playersettings.handicap.generic.id = ID_HANDICAP; + s_playersettings.handicap.generic.ownerdraw = PlayerSettings_DrawHandicap; + s_playersettings.handicap.generic.x = 192; + s_playersettings.handicap.generic.y = y; + s_playersettings.handicap.generic.left = 192 - 8; + s_playersettings.handicap.generic.top = y - 8; + s_playersettings.handicap.generic.right = 192 + 200; + s_playersettings.handicap.generic.bottom = y + 2 * PROP_HEIGHT; + s_playersettings.handicap.numitems = 20; + + y += 3 * PROP_HEIGHT; + s_playersettings.effects.generic.type = MTYPE_SPINCONTROL; + s_playersettings.effects.generic.flags = QMF_NODEFAULTINIT; + s_playersettings.effects.generic.id = ID_EFFECTS; + s_playersettings.effects.generic.ownerdraw = PlayerSettings_DrawEffects; + s_playersettings.effects.generic.x = 192; + s_playersettings.effects.generic.y = y; + s_playersettings.effects.generic.left = 192 - 8; + s_playersettings.effects.generic.top = y - 8; + s_playersettings.effects.generic.right = 192 + 200; + s_playersettings.effects.generic.bottom = y + 2* PROP_HEIGHT; + s_playersettings.effects.numitems = 7; + + s_playersettings.model.generic.type = MTYPE_BITMAP; + s_playersettings.model.generic.name = ART_MODEL0; + s_playersettings.model.generic.flags = QMF_RIGHT_JUSTIFY|QMF_PULSEIFFOCUS; + s_playersettings.model.generic.id = ID_MODEL; + s_playersettings.model.generic.callback = PlayerSettings_MenuEvent; + s_playersettings.model.generic.x = 640; + s_playersettings.model.generic.y = 480-64; + s_playersettings.model.width = 128; + s_playersettings.model.height = 64; + s_playersettings.model.focuspic = ART_MODEL1; + + s_playersettings.player.generic.type = MTYPE_BITMAP; + s_playersettings.player.generic.flags = QMF_INACTIVE; + s_playersettings.player.generic.ownerdraw = PlayerSettings_DrawPlayer; + s_playersettings.player.generic.x = 400; + s_playersettings.player.generic.y = -40; + s_playersettings.player.width = 32*10; + s_playersettings.player.height = 56*10; + + s_playersettings.back.generic.type = MTYPE_BITMAP; + s_playersettings.back.generic.name = ART_BACK0; + s_playersettings.back.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS; + s_playersettings.back.generic.id = ID_BACK; + s_playersettings.back.generic.callback = PlayerSettings_MenuEvent; + s_playersettings.back.generic.x = 0; + s_playersettings.back.generic.y = 480-64; + s_playersettings.back.width = 128; + s_playersettings.back.height = 64; + s_playersettings.back.focuspic = ART_BACK1; + + s_playersettings.item_null.generic.type = MTYPE_BITMAP; + s_playersettings.item_null.generic.flags = QMF_LEFT_JUSTIFY|QMF_MOUSEONLY|QMF_SILENT; + s_playersettings.item_null.generic.x = 0; + s_playersettings.item_null.generic.y = 0; + s_playersettings.item_null.width = 640; + s_playersettings.item_null.height = 480; + + Menu_AddItem( &s_playersettings.menu, &s_playersettings.banner ); + Menu_AddItem( &s_playersettings.menu, &s_playersettings.framel ); + Menu_AddItem( &s_playersettings.menu, &s_playersettings.framer ); + + Menu_AddItem( &s_playersettings.menu, &s_playersettings.name ); + Menu_AddItem( &s_playersettings.menu, &s_playersettings.handicap ); + Menu_AddItem( &s_playersettings.menu, &s_playersettings.effects ); + Menu_AddItem( &s_playersettings.menu, &s_playersettings.model ); + Menu_AddItem( &s_playersettings.menu, &s_playersettings.back ); + + Menu_AddItem( &s_playersettings.menu, &s_playersettings.player ); + + Menu_AddItem( &s_playersettings.menu, &s_playersettings.item_null ); + + PlayerSettings_SetMenuItems(); +} + + +/* +================= +PlayerSettings_Cache +================= +*/ +void PlayerSettings_Cache( void ) { + trap_R_RegisterShaderNoMip( ART_FRAMEL ); + trap_R_RegisterShaderNoMip( ART_FRAMER ); + trap_R_RegisterShaderNoMip( ART_MODEL0 ); + trap_R_RegisterShaderNoMip( ART_MODEL1 ); + trap_R_RegisterShaderNoMip( ART_BACK0 ); + trap_R_RegisterShaderNoMip( ART_BACK1 ); + + s_playersettings.fxBasePic = trap_R_RegisterShaderNoMip( ART_FX_BASE ); + s_playersettings.fxPic[0] = trap_R_RegisterShaderNoMip( ART_FX_RED ); + s_playersettings.fxPic[1] = trap_R_RegisterShaderNoMip( ART_FX_YELLOW ); + s_playersettings.fxPic[2] = trap_R_RegisterShaderNoMip( ART_FX_GREEN ); + s_playersettings.fxPic[3] = trap_R_RegisterShaderNoMip( ART_FX_TEAL ); + s_playersettings.fxPic[4] = trap_R_RegisterShaderNoMip( ART_FX_BLUE ); + s_playersettings.fxPic[5] = trap_R_RegisterShaderNoMip( ART_FX_CYAN ); + s_playersettings.fxPic[6] = trap_R_RegisterShaderNoMip( ART_FX_WHITE ); +} + + +/* +================= +UI_PlayerSettingsMenu +================= +*/ +void UI_PlayerSettingsMenu( void ) { + PlayerSettings_MenuInit(); + UI_PushMenu( &s_playersettings.menu ); +} diff --git a/code/q3_ui/ui_preferences.c b/code/q3_ui/ui_preferences.c new file mode 100755 index 0000000..c83ba6a --- /dev/null +++ b/code/q3_ui/ui_preferences.c @@ -0,0 +1,419 @@ +/* +=========================================================================== +Copyright (C) 1999-2005 Id Software, Inc. + +This file is part of Quake III Arena source code. + +Quake III Arena source code is free software; you can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 2 of the License, +or (at your option) any later version. + +Quake III Arena source code is distributed in the hope that it will be +useful, but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Foobar; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ +// +/* +======================================================================= + +GAME OPTIONS MENU + +======================================================================= +*/ + + +#include "ui_local.h" + + +#define ART_FRAMEL "menu/art/frame2_l" +#define ART_FRAMER "menu/art/frame1_r" +#define ART_BACK0 "menu/art/back_0" +#define ART_BACK1 "menu/art/back_1" + +#define PREFERENCES_X_POS 360 + +#define ID_CROSSHAIR 127 +#define ID_SIMPLEITEMS 128 +#define ID_HIGHQUALITYSKY 129 +#define ID_EJECTINGBRASS 130 +#define ID_WALLMARKS 131 +#define ID_DYNAMICLIGHTS 132 +#define ID_IDENTIFYTARGET 133 +#define ID_SYNCEVERYFRAME 134 +#define ID_FORCEMODEL 135 +#define ID_DRAWTEAMOVERLAY 136 +#define ID_ALLOWDOWNLOAD 137 +#define ID_BACK 138 + +#define NUM_CROSSHAIRS 10 + + +typedef struct { + menuframework_s menu; + + menutext_s banner; + menubitmap_s framel; + menubitmap_s framer; + + menulist_s crosshair; + menuradiobutton_s simpleitems; + menuradiobutton_s brass; + menuradiobutton_s wallmarks; + menuradiobutton_s dynamiclights; + menuradiobutton_s identifytarget; + menuradiobutton_s highqualitysky; + menuradiobutton_s synceveryframe; + menuradiobutton_s forcemodel; + menulist_s drawteamoverlay; + menuradiobutton_s allowdownload; + menubitmap_s back; + + qhandle_t crosshairShader[NUM_CROSSHAIRS]; +} preferences_t; + +static preferences_t s_preferences; + +static const char *teamoverlay_names[] = +{ + "off", + "upper right", + "lower right", + "lower left", + 0 +}; + +static void Preferences_SetMenuItems( void ) { + s_preferences.crosshair.curvalue = (int)trap_Cvar_VariableValue( "cg_drawCrosshair" ) % NUM_CROSSHAIRS; + s_preferences.simpleitems.curvalue = trap_Cvar_VariableValue( "cg_simpleItems" ) != 0; + s_preferences.brass.curvalue = trap_Cvar_VariableValue( "cg_brassTime" ) != 0; + s_preferences.wallmarks.curvalue = trap_Cvar_VariableValue( "cg_marks" ) != 0; + s_preferences.identifytarget.curvalue = trap_Cvar_VariableValue( "cg_drawCrosshairNames" ) != 0; + s_preferences.dynamiclights.curvalue = trap_Cvar_VariableValue( "r_dynamiclight" ) != 0; + s_preferences.highqualitysky.curvalue = trap_Cvar_VariableValue ( "r_fastsky" ) == 0; + s_preferences.synceveryframe.curvalue = trap_Cvar_VariableValue( "r_finish" ) != 0; + s_preferences.forcemodel.curvalue = trap_Cvar_VariableValue( "cg_forcemodel" ) != 0; + s_preferences.drawteamoverlay.curvalue = Com_Clamp( 0, 3, trap_Cvar_VariableValue( "cg_drawTeamOverlay" ) ); + s_preferences.allowdownload.curvalue = trap_Cvar_VariableValue( "cl_allowDownload" ) != 0; +} + + +static void Preferences_Event( void* ptr, int notification ) { + if( notification != QM_ACTIVATED ) { + return; + } + + switch( ((menucommon_s*)ptr)->id ) { + case ID_CROSSHAIR: + s_preferences.crosshair.curvalue++; + if( s_preferences.crosshair.curvalue == NUM_CROSSHAIRS ) { + s_preferences.crosshair.curvalue = 0; + } + trap_Cvar_SetValue( "cg_drawCrosshair", s_preferences.crosshair.curvalue ); + break; + + case ID_SIMPLEITEMS: + trap_Cvar_SetValue( "cg_simpleItems", s_preferences.simpleitems.curvalue ); + break; + + case ID_HIGHQUALITYSKY: + trap_Cvar_SetValue( "r_fastsky", !s_preferences.highqualitysky.curvalue ); + break; + + case ID_EJECTINGBRASS: + if ( s_preferences.brass.curvalue ) + trap_Cvar_Reset( "cg_brassTime" ); + else + trap_Cvar_SetValue( "cg_brassTime", 0 ); + break; + + case ID_WALLMARKS: + trap_Cvar_SetValue( "cg_marks", s_preferences.wallmarks.curvalue ); + break; + + case ID_DYNAMICLIGHTS: + trap_Cvar_SetValue( "r_dynamiclight", s_preferences.dynamiclights.curvalue ); + break; + + case ID_IDENTIFYTARGET: + trap_Cvar_SetValue( "cg_drawCrosshairNames", s_preferences.identifytarget.curvalue ); + break; + + case ID_SYNCEVERYFRAME: + trap_Cvar_SetValue( "r_finish", s_preferences.synceveryframe.curvalue ); + break; + + case ID_FORCEMODEL: + trap_Cvar_SetValue( "cg_forcemodel", s_preferences.forcemodel.curvalue ); + break; + + case ID_DRAWTEAMOVERLAY: + trap_Cvar_SetValue( "cg_drawTeamOverlay", s_preferences.drawteamoverlay.curvalue ); + break; + + case ID_ALLOWDOWNLOAD: + trap_Cvar_SetValue( "cl_allowDownload", s_preferences.allowdownload.curvalue ); + trap_Cvar_SetValue( "sv_allowDownload", s_preferences.allowdownload.curvalue ); + break; + + case ID_BACK: + UI_PopMenu(); + break; + } +} + + +/* +================= +Crosshair_Draw +================= +*/ +static void Crosshair_Draw( void *self ) { + menulist_s *s; + float *color; + int x, y; + int style; + qboolean focus; + + s = (menulist_s *)self; + x = s->generic.x; + y = s->generic.y; + + style = UI_SMALLFONT; + focus = (s->generic.parent->cursor == s->generic.menuPosition); + + if ( s->generic.flags & QMF_GRAYED ) + color = text_color_disabled; + else if ( focus ) + { + color = text_color_highlight; + style |= UI_PULSE; + } + else if ( s->generic.flags & QMF_BLINK ) + { + color = text_color_highlight; + style |= UI_BLINK; + } + else + color = text_color_normal; + + if ( focus ) + { + // draw cursor + UI_FillRect( s->generic.left, s->generic.top, s->generic.right-s->generic.left+1, s->generic.bottom-s->generic.top+1, listbar_color ); + UI_DrawChar( x, y, 13, UI_CENTER|UI_BLINK|UI_SMALLFONT, color); + } + + UI_DrawString( x - SMALLCHAR_WIDTH, y, s->generic.name, style|UI_RIGHT, color ); + if( !s->curvalue ) { + return; + } + UI_DrawHandlePic( x + SMALLCHAR_WIDTH, y - 4, 24, 24, s_preferences.crosshairShader[s->curvalue] ); +} + + +static void Preferences_MenuInit( void ) { + int y; + + memset( &s_preferences, 0 ,sizeof(preferences_t) ); + + Preferences_Cache(); + + s_preferences.menu.wrapAround = qtrue; + s_preferences.menu.fullscreen = qtrue; + + s_preferences.banner.generic.type = MTYPE_BTEXT; + s_preferences.banner.generic.x = 320; + s_preferences.banner.generic.y = 16; + s_preferences.banner.string = "GAME OPTIONS"; + s_preferences.banner.color = color_white; + s_preferences.banner.style = UI_CENTER; + + s_preferences.framel.generic.type = MTYPE_BITMAP; + s_preferences.framel.generic.name = ART_FRAMEL; + s_preferences.framel.generic.flags = QMF_INACTIVE; + s_preferences.framel.generic.x = 0; + s_preferences.framel.generic.y = 78; + s_preferences.framel.width = 256; + s_preferences.framel.height = 329; + + s_preferences.framer.generic.type = MTYPE_BITMAP; + s_preferences.framer.generic.name = ART_FRAMER; + s_preferences.framer.generic.flags = QMF_INACTIVE; + s_preferences.framer.generic.x = 376; + s_preferences.framer.generic.y = 76; + s_preferences.framer.width = 256; + s_preferences.framer.height = 334; + + y = 144; + s_preferences.crosshair.generic.type = MTYPE_TEXT; + s_preferences.crosshair.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT|QMF_NODEFAULTINIT|QMF_OWNERDRAW; + s_preferences.crosshair.generic.x = PREFERENCES_X_POS; + s_preferences.crosshair.generic.y = y; + s_preferences.crosshair.generic.name = "Crosshair:"; + s_preferences.crosshair.generic.callback = Preferences_Event; + s_preferences.crosshair.generic.ownerdraw = Crosshair_Draw; + s_preferences.crosshair.generic.id = ID_CROSSHAIR; + s_preferences.crosshair.generic.top = y - 4; + s_preferences.crosshair.generic.bottom = y + 20; + s_preferences.crosshair.generic.left = PREFERENCES_X_POS - ( ( strlen(s_preferences.crosshair.generic.name) + 1 ) * SMALLCHAR_WIDTH ); + s_preferences.crosshair.generic.right = PREFERENCES_X_POS + 48; + + y += BIGCHAR_HEIGHT+2+4; + s_preferences.simpleitems.generic.type = MTYPE_RADIOBUTTON; + s_preferences.simpleitems.generic.name = "Simple Items:"; + s_preferences.simpleitems.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT; + s_preferences.simpleitems.generic.callback = Preferences_Event; + s_preferences.simpleitems.generic.id = ID_SIMPLEITEMS; + s_preferences.simpleitems.generic.x = PREFERENCES_X_POS; + s_preferences.simpleitems.generic.y = y; + + y += BIGCHAR_HEIGHT; + s_preferences.wallmarks.generic.type = MTYPE_RADIOBUTTON; + s_preferences.wallmarks.generic.name = "Marks on Walls:"; + s_preferences.wallmarks.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT; + s_preferences.wallmarks.generic.callback = Preferences_Event; + s_preferences.wallmarks.generic.id = ID_WALLMARKS; + s_preferences.wallmarks.generic.x = PREFERENCES_X_POS; + s_preferences.wallmarks.generic.y = y; + + y += BIGCHAR_HEIGHT+2; + s_preferences.brass.generic.type = MTYPE_RADIOBUTTON; + s_preferences.brass.generic.name = "Ejecting Brass:"; + s_preferences.brass.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT; + s_preferences.brass.generic.callback = Preferences_Event; + s_preferences.brass.generic.id = ID_EJECTINGBRASS; + s_preferences.brass.generic.x = PREFERENCES_X_POS; + s_preferences.brass.generic.y = y; + + y += BIGCHAR_HEIGHT+2; + s_preferences.dynamiclights.generic.type = MTYPE_RADIOBUTTON; + s_preferences.dynamiclights.generic.name = "Dynamic Lights:"; + s_preferences.dynamiclights.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT; + s_preferences.dynamiclights.generic.callback = Preferences_Event; + s_preferences.dynamiclights.generic.id = ID_DYNAMICLIGHTS; + s_preferences.dynamiclights.generic.x = PREFERENCES_X_POS; + s_preferences.dynamiclights.generic.y = y; + + y += BIGCHAR_HEIGHT+2; + s_preferences.identifytarget.generic.type = MTYPE_RADIOBUTTON; + s_preferences.identifytarget.generic.name = "Identify Target:"; + s_preferences.identifytarget.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT; + s_preferences.identifytarget.generic.callback = Preferences_Event; + s_preferences.identifytarget.generic.id = ID_IDENTIFYTARGET; + s_preferences.identifytarget.generic.x = PREFERENCES_X_POS; + s_preferences.identifytarget.generic.y = y; + + y += BIGCHAR_HEIGHT+2; + s_preferences.highqualitysky.generic.type = MTYPE_RADIOBUTTON; + s_preferences.highqualitysky.generic.name = "High Quality Sky:"; + s_preferences.highqualitysky.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT; + s_preferences.highqualitysky.generic.callback = Preferences_Event; + s_preferences.highqualitysky.generic.id = ID_HIGHQUALITYSKY; + s_preferences.highqualitysky.generic.x = PREFERENCES_X_POS; + s_preferences.highqualitysky.generic.y = y; + + y += BIGCHAR_HEIGHT+2; + s_preferences.synceveryframe.generic.type = MTYPE_RADIOBUTTON; + s_preferences.synceveryframe.generic.name = "Sync Every Frame:"; + s_preferences.synceveryframe.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT; + s_preferences.synceveryframe.generic.callback = Preferences_Event; + s_preferences.synceveryframe.generic.id = ID_SYNCEVERYFRAME; + s_preferences.synceveryframe.generic.x = PREFERENCES_X_POS; + s_preferences.synceveryframe.generic.y = y; + + y += BIGCHAR_HEIGHT+2; + s_preferences.forcemodel.generic.type = MTYPE_RADIOBUTTON; + s_preferences.forcemodel.generic.name = "Force Player Models:"; + s_preferences.forcemodel.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT; + s_preferences.forcemodel.generic.callback = Preferences_Event; + s_preferences.forcemodel.generic.id = ID_FORCEMODEL; + s_preferences.forcemodel.generic.x = PREFERENCES_X_POS; + s_preferences.forcemodel.generic.y = y; + + y += BIGCHAR_HEIGHT+2; + s_preferences.drawteamoverlay.generic.type = MTYPE_SPINCONTROL; + s_preferences.drawteamoverlay.generic.name = "Draw Team Overlay:"; + s_preferences.drawteamoverlay.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT; + s_preferences.drawteamoverlay.generic.callback = Preferences_Event; + s_preferences.drawteamoverlay.generic.id = ID_DRAWTEAMOVERLAY; + s_preferences.drawteamoverlay.generic.x = PREFERENCES_X_POS; + s_preferences.drawteamoverlay.generic.y = y; + s_preferences.drawteamoverlay.itemnames = teamoverlay_names; + + y += BIGCHAR_HEIGHT+2; + s_preferences.allowdownload.generic.type = MTYPE_RADIOBUTTON; + s_preferences.allowdownload.generic.name = "Automatic Downloading:"; + s_preferences.allowdownload.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT; + s_preferences.allowdownload.generic.callback = Preferences_Event; + s_preferences.allowdownload.generic.id = ID_ALLOWDOWNLOAD; + s_preferences.allowdownload.generic.x = PREFERENCES_X_POS; + s_preferences.allowdownload.generic.y = y; + + y += BIGCHAR_HEIGHT+2; + s_preferences.back.generic.type = MTYPE_BITMAP; + s_preferences.back.generic.name = ART_BACK0; + s_preferences.back.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS; + s_preferences.back.generic.callback = Preferences_Event; + s_preferences.back.generic.id = ID_BACK; + s_preferences.back.generic.x = 0; + s_preferences.back.generic.y = 480-64; + s_preferences.back.width = 128; + s_preferences.back.height = 64; + s_preferences.back.focuspic = ART_BACK1; + + Menu_AddItem( &s_preferences.menu, &s_preferences.banner ); + Menu_AddItem( &s_preferences.menu, &s_preferences.framel ); + Menu_AddItem( &s_preferences.menu, &s_preferences.framer ); + + Menu_AddItem( &s_preferences.menu, &s_preferences.crosshair ); + Menu_AddItem( &s_preferences.menu, &s_preferences.simpleitems ); + Menu_AddItem( &s_preferences.menu, &s_preferences.wallmarks ); + Menu_AddItem( &s_preferences.menu, &s_preferences.brass ); + Menu_AddItem( &s_preferences.menu, &s_preferences.dynamiclights ); + Menu_AddItem( &s_preferences.menu, &s_preferences.identifytarget ); + Menu_AddItem( &s_preferences.menu, &s_preferences.highqualitysky ); + Menu_AddItem( &s_preferences.menu, &s_preferences.synceveryframe ); + Menu_AddItem( &s_preferences.menu, &s_preferences.forcemodel ); + Menu_AddItem( &s_preferences.menu, &s_preferences.drawteamoverlay ); + Menu_AddItem( &s_preferences.menu, &s_preferences.allowdownload ); + + Menu_AddItem( &s_preferences.menu, &s_preferences.back ); + + Preferences_SetMenuItems(); +} + + +/* +=============== +Preferences_Cache +=============== +*/ +void Preferences_Cache( void ) { + int n; + + trap_R_RegisterShaderNoMip( ART_FRAMEL ); + trap_R_RegisterShaderNoMip( ART_FRAMER ); + trap_R_RegisterShaderNoMip( ART_BACK0 ); + trap_R_RegisterShaderNoMip( ART_BACK1 ); + for( n = 0; n < NUM_CROSSHAIRS; n++ ) { + s_preferences.crosshairShader[n] = trap_R_RegisterShaderNoMip( va("gfx/2d/crosshair%c", 'a' + n ) ); + } +} + + +/* +=============== +UI_PreferencesMenu +=============== +*/ +void UI_PreferencesMenu( void ) { + Preferences_MenuInit(); + UI_PushMenu( &s_preferences.menu ); +} diff --git a/code/q3_ui/ui_qmenu.c b/code/q3_ui/ui_qmenu.c new file mode 100755 index 0000000..400448a --- /dev/null +++ b/code/q3_ui/ui_qmenu.c @@ -0,0 +1,1746 @@ +/* +=========================================================================== +Copyright (C) 1999-2005 Id Software, Inc. + +This file is part of Quake III Arena source code. + +Quake III Arena source code is free software; you can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 2 of the License, +or (at your option) any later version. + +Quake III Arena source code is distributed in the hope that it will be +useful, but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Foobar; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ +// +/********************************************************************** + UI_QMENU.C + + Quake's menu framework system. +**********************************************************************/ +#include "ui_local.h" + +sfxHandle_t menu_in_sound; +sfxHandle_t menu_move_sound; +sfxHandle_t menu_out_sound; +sfxHandle_t menu_buzz_sound; +sfxHandle_t menu_null_sound; +sfxHandle_t weaponChangeSound; + +static qhandle_t sliderBar; +static qhandle_t sliderButton_0; +static qhandle_t sliderButton_1; + +vec4_t menu_text_color = {1.0f, 1.0f, 1.0f, 1.0f}; +vec4_t menu_dim_color = {0.0f, 0.0f, 0.0f, 0.75f}; +vec4_t color_black = {0.00f, 0.00f, 0.00f, 1.00f}; +vec4_t color_white = {1.00f, 1.00f, 1.00f, 1.00f}; +vec4_t color_yellow = {1.00f, 1.00f, 0.00f, 1.00f}; +vec4_t color_blue = {0.00f, 0.00f, 1.00f, 1.00f}; +vec4_t color_lightOrange = {1.00f, 0.68f, 0.00f, 1.00f }; +vec4_t color_orange = {1.00f, 0.43f, 0.00f, 1.00f}; +vec4_t color_red = {1.00f, 0.00f, 0.00f, 1.00f}; +vec4_t color_dim = {0.00f, 0.00f, 0.00f, 0.25f}; + +// current color scheme +vec4_t pulse_color = {1.00f, 1.00f, 1.00f, 1.00f}; +vec4_t text_color_disabled = {0.50f, 0.50f, 0.50f, 1.00f}; // light gray +vec4_t text_color_normal = {1.00f, 0.43f, 0.00f, 1.00f}; // light orange +vec4_t text_color_highlight = {1.00f, 1.00f, 0.00f, 1.00f}; // bright yellow +vec4_t listbar_color = {1.00f, 0.43f, 0.00f, 0.30f}; // transluscent orange +vec4_t text_color_status = {1.00f, 1.00f, 1.00f, 1.00f}; // bright white + +// action widget +static void Action_Init( menuaction_s *a ); +static void Action_Draw( menuaction_s *a ); + +// radio button widget +static void RadioButton_Init( menuradiobutton_s *rb ); +static void RadioButton_Draw( menuradiobutton_s *rb ); +static sfxHandle_t RadioButton_Key( menuradiobutton_s *rb, int key ); + +// slider widget +static void Slider_Init( menuslider_s *s ); +static sfxHandle_t Slider_Key( menuslider_s *s, int key ); +static void Slider_Draw( menuslider_s *s ); + +// spin control widget +static void SpinControl_Init( menulist_s *s ); +static void SpinControl_Draw( menulist_s *s ); +static sfxHandle_t SpinControl_Key( menulist_s *l, int key ); + +// text widget +static void Text_Init( menutext_s *b ); +static void Text_Draw( menutext_s *b ); + +// scrolllist widget +static void ScrollList_Init( menulist_s *l ); +sfxHandle_t ScrollList_Key( menulist_s *l, int key ); + +// proportional text widget +static void PText_Init( menutext_s *b ); +static void PText_Draw( menutext_s *b ); + +// proportional banner text widget +static void BText_Init( menutext_s *b ); +static void BText_Draw( menutext_s *b ); + +/* +================= +Text_Init +================= +*/ +static void Text_Init( menutext_s *t ) +{ + t->generic.flags |= QMF_INACTIVE; +} + +/* +================= +Text_Draw +================= +*/ +static void Text_Draw( menutext_s *t ) +{ + int x; + int y; + char buff[512]; + float* color; + + x = t->generic.x; + y = t->generic.y; + + buff[0] = '\0'; + + // possible label + if (t->generic.name) + strcpy(buff,t->generic.name); + + // possible value + if (t->string) + strcat(buff,t->string); + + if (t->generic.flags & QMF_GRAYED) + color = text_color_disabled; + else + color = t->color; + + UI_DrawString( x, y, buff, t->style, color ); +} + +/* +================= +BText_Init +================= +*/ +static void BText_Init( menutext_s *t ) +{ + t->generic.flags |= QMF_INACTIVE; +} + +/* +================= +BText_Draw +================= +*/ +static void BText_Draw( menutext_s *t ) +{ + int x; + int y; + float* color; + + x = t->generic.x; + y = t->generic.y; + + if (t->generic.flags & QMF_GRAYED) + color = text_color_disabled; + else + color = t->color; + + UI_DrawBannerString( x, y, t->string, t->style, color ); +} + +/* +================= +PText_Init +================= +*/ +static void PText_Init( menutext_s *t ) +{ + int x; + int y; + int w; + int h; + float sizeScale; + + sizeScale = UI_ProportionalSizeScale( t->style ); + + x = t->generic.x; + y = t->generic.y; + w = UI_ProportionalStringWidth( t->string ) * sizeScale; + h = PROP_HEIGHT * sizeScale; + + if( t->generic.flags & QMF_RIGHT_JUSTIFY ) { + x -= w; + } + else if( t->generic.flags & QMF_CENTER_JUSTIFY ) { + x -= w / 2; + } + + t->generic.left = x - PROP_GAP_WIDTH * sizeScale; + t->generic.right = x + w + PROP_GAP_WIDTH * sizeScale; + t->generic.top = y; + t->generic.bottom = y + h; +} + +/* +================= +PText_Draw +================= +*/ +static void PText_Draw( menutext_s *t ) +{ + int x; + int y; + float * color; + int style; + + x = t->generic.x; + y = t->generic.y; + + if (t->generic.flags & QMF_GRAYED) + color = text_color_disabled; + else + color = t->color; + + style = t->style; + if( t->generic.flags & QMF_PULSEIFFOCUS ) { + if( Menu_ItemAtCursor( t->generic.parent ) == t ) { + style |= UI_PULSE; + } + else { + style |= UI_INVERSE; + } + } + + UI_DrawProportionalString( x, y, t->string, style, color ); +} + +/* +================= +Bitmap_Init +================= +*/ +void Bitmap_Init( menubitmap_s *b ) +{ + int x; + int y; + int w; + int h; + + x = b->generic.x; + y = b->generic.y; + w = b->width; + h = b->height; + if( w < 0 ) { + w = -w; + } + if( h < 0 ) { + h = -h; + } + + if (b->generic.flags & QMF_RIGHT_JUSTIFY) + { + x = x - w; + } + else if (b->generic.flags & QMF_CENTER_JUSTIFY) + { + x = x - w/2; + } + + b->generic.left = x; + b->generic.right = x + w; + b->generic.top = y; + b->generic.bottom = y + h; + + b->shader = 0; + b->focusshader = 0; +} + +/* +================= +Bitmap_Draw +================= +*/ +void Bitmap_Draw( menubitmap_s *b ) +{ + float x; + float y; + float w; + float h; + vec4_t tempcolor; + float* color; + + x = b->generic.x; + y = b->generic.y; + w = b->width; + h = b->height; + + if (b->generic.flags & QMF_RIGHT_JUSTIFY) + { + x = x - w; + } + else if (b->generic.flags & QMF_CENTER_JUSTIFY) + { + x = x - w/2; + } + + // used to refresh shader + if (b->generic.name && !b->shader) + { + b->shader = trap_R_RegisterShaderNoMip( b->generic.name ); + if (!b->shader && b->errorpic) + b->shader = trap_R_RegisterShaderNoMip( b->errorpic ); + } + + if (b->focuspic && !b->focusshader) + b->focusshader = trap_R_RegisterShaderNoMip( b->focuspic ); + + if (b->generic.flags & QMF_GRAYED) + { + if (b->shader) + { + trap_R_SetColor( colorMdGrey ); + UI_DrawHandlePic( x, y, w, h, b->shader ); + trap_R_SetColor( NULL ); + } + } + else + { + if (b->shader) + UI_DrawHandlePic( x, y, w, h, b->shader ); + + // bk001204 - parentheses + if ( ( (b->generic.flags & QMF_PULSE) + || (b->generic.flags & QMF_PULSEIFFOCUS) ) + && (Menu_ItemAtCursor( b->generic.parent ) == b)) + { + if (b->focuscolor) + { + tempcolor[0] = b->focuscolor[0]; + tempcolor[1] = b->focuscolor[1]; + tempcolor[2] = b->focuscolor[2]; + color = tempcolor; + } + else + color = pulse_color; + color[3] = 0.5+0.5*sin(uis.realtime/PULSE_DIVISOR); + + trap_R_SetColor( color ); + UI_DrawHandlePic( x, y, w, h, b->focusshader ); + trap_R_SetColor( NULL ); + } + else if ((b->generic.flags & QMF_HIGHLIGHT) || ((b->generic.flags & QMF_HIGHLIGHT_IF_FOCUS) && (Menu_ItemAtCursor( b->generic.parent ) == b))) + { + if (b->focuscolor) + { + trap_R_SetColor( b->focuscolor ); + UI_DrawHandlePic( x, y, w, h, b->focusshader ); + trap_R_SetColor( NULL ); + } + else + UI_DrawHandlePic( x, y, w, h, b->focusshader ); + } + } +} + +/* +================= +Action_Init +================= +*/ +static void Action_Init( menuaction_s *a ) +{ + int len; + + // calculate bounds + if (a->generic.name) + len = strlen(a->generic.name); + else + len = 0; + + // left justify text + a->generic.left = a->generic.x; + a->generic.right = a->generic.x + len*BIGCHAR_WIDTH; + a->generic.top = a->generic.y; + a->generic.bottom = a->generic.y + BIGCHAR_HEIGHT; +} + +/* +================= +Action_Draw +================= +*/ +static void Action_Draw( menuaction_s *a ) +{ + int x, y; + int style; + float* color; + + style = 0; + color = menu_text_color; + if ( a->generic.flags & QMF_GRAYED ) + { + color = text_color_disabled; + } + else if (( a->generic.flags & QMF_PULSEIFFOCUS ) && ( a->generic.parent->cursor == a->generic.menuPosition )) + { + color = text_color_highlight; + style = UI_PULSE; + } + else if (( a->generic.flags & QMF_HIGHLIGHT_IF_FOCUS ) && ( a->generic.parent->cursor == a->generic.menuPosition )) + { + color = text_color_highlight; + } + else if ( a->generic.flags & QMF_BLINK ) + { + style = UI_BLINK; + color = text_color_highlight; + } + + x = a->generic.x; + y = a->generic.y; + + UI_DrawString( x, y, a->generic.name, UI_LEFT|style, color ); + + if ( a->generic.parent->cursor == a->generic.menuPosition ) + { + // draw cursor + UI_DrawChar( x - BIGCHAR_WIDTH, y, 13, UI_LEFT|UI_BLINK, color); + } +} + +/* +================= +RadioButton_Init +================= +*/ +static void RadioButton_Init( menuradiobutton_s *rb ) +{ + int len; + + // calculate bounds + if (rb->generic.name) + len = strlen(rb->generic.name); + else + len = 0; + + rb->generic.left = rb->generic.x - (len+1)*SMALLCHAR_WIDTH; + rb->generic.right = rb->generic.x + 6*SMALLCHAR_WIDTH; + rb->generic.top = rb->generic.y; + rb->generic.bottom = rb->generic.y + SMALLCHAR_HEIGHT; +} + +/* +================= +RadioButton_Key +================= +*/ +static sfxHandle_t RadioButton_Key( menuradiobutton_s *rb, int key ) +{ + switch (key) + { + case K_MOUSE1: + if (!(rb->generic.flags & QMF_HASMOUSEFOCUS)) + break; + + case K_JOY1: + case K_JOY2: + case K_JOY3: + case K_JOY4: + case K_ENTER: + case K_KP_ENTER: + case K_KP_LEFTARROW: + case K_LEFTARROW: + case K_KP_RIGHTARROW: + case K_RIGHTARROW: + rb->curvalue = !rb->curvalue; + if ( rb->generic.callback ) + rb->generic.callback( rb, QM_ACTIVATED ); + + return (menu_move_sound); + } + + // key not handled + return 0; +} + +/* +================= +RadioButton_Draw +================= +*/ +static void RadioButton_Draw( menuradiobutton_s *rb ) +{ + int x; + int y; + float *color; + int style; + qboolean focus; + + x = rb->generic.x; + y = rb->generic.y; + + focus = (rb->generic.parent->cursor == rb->generic.menuPosition); + + if ( rb->generic.flags & QMF_GRAYED ) + { + color = text_color_disabled; + style = UI_LEFT|UI_SMALLFONT; + } + else if ( focus ) + { + color = text_color_highlight; + style = UI_LEFT|UI_PULSE|UI_SMALLFONT; + } + else + { + color = text_color_normal; + style = UI_LEFT|UI_SMALLFONT; + } + + if ( focus ) + { + // draw cursor + UI_FillRect( rb->generic.left, rb->generic.top, rb->generic.right-rb->generic.left+1, rb->generic.bottom-rb->generic.top+1, listbar_color ); + UI_DrawChar( x, y, 13, UI_CENTER|UI_BLINK|UI_SMALLFONT, color); + } + + if ( rb->generic.name ) + UI_DrawString( x - SMALLCHAR_WIDTH, y, rb->generic.name, UI_RIGHT|UI_SMALLFONT, color ); + + if ( !rb->curvalue ) + { + UI_DrawHandlePic( x + SMALLCHAR_WIDTH, y + 2, 16, 16, uis.rb_off); + UI_DrawString( x + SMALLCHAR_WIDTH + 16, y, "off", style, color ); + } + else + { + UI_DrawHandlePic( x + SMALLCHAR_WIDTH, y + 2, 16, 16, uis.rb_on ); + UI_DrawString( x + SMALLCHAR_WIDTH + 16, y, "on", style, color ); + } +} + +/* +================= +Slider_Init +================= +*/ +static void Slider_Init( menuslider_s *s ) +{ + int len; + + // calculate bounds + if (s->generic.name) + len = strlen(s->generic.name); + else + len = 0; + + s->generic.left = s->generic.x - (len+1)*SMALLCHAR_WIDTH; + s->generic.right = s->generic.x + (SLIDER_RANGE+2+1)*SMALLCHAR_WIDTH; + s->generic.top = s->generic.y; + s->generic.bottom = s->generic.y + SMALLCHAR_HEIGHT; +} + +/* +================= +Slider_Key +================= +*/ +static sfxHandle_t Slider_Key( menuslider_s *s, int key ) +{ + sfxHandle_t sound; + int x; + int oldvalue; + + switch (key) + { + case K_MOUSE1: + x = uis.cursorx - s->generic.x - 2*SMALLCHAR_WIDTH; + oldvalue = s->curvalue; + s->curvalue = (x/(float)(SLIDER_RANGE*SMALLCHAR_WIDTH)) * (s->maxvalue-s->minvalue) + s->minvalue; + + if (s->curvalue < s->minvalue) + s->curvalue = s->minvalue; + else if (s->curvalue > s->maxvalue) + s->curvalue = s->maxvalue; + if (s->curvalue != oldvalue) + sound = menu_move_sound; + else + sound = 0; + break; + + case K_KP_LEFTARROW: + case K_LEFTARROW: + if (s->curvalue > s->minvalue) + { + s->curvalue--; + sound = menu_move_sound; + } + else + sound = menu_buzz_sound; + break; + + case K_KP_RIGHTARROW: + case K_RIGHTARROW: + if (s->curvalue < s->maxvalue) + { + s->curvalue++; + sound = menu_move_sound; + } + else + sound = menu_buzz_sound; + break; + + default: + // key not handled + sound = 0; + break; + } + + if ( sound && s->generic.callback ) + s->generic.callback( s, QM_ACTIVATED ); + + return (sound); +} + +#if 1 +/* +================= +Slider_Draw +================= +*/ +static void Slider_Draw( menuslider_s *s ) { + int x; + int y; + int style; + float *color; + int button; + qboolean focus; + + x = s->generic.x; + y = s->generic.y; + focus = (s->generic.parent->cursor == s->generic.menuPosition); + + if( s->generic.flags & QMF_GRAYED ) { + color = text_color_disabled; + style = UI_SMALLFONT; + } + else if( focus ) { + color = text_color_highlight; + style = UI_SMALLFONT | UI_PULSE; + } + else { + color = text_color_normal; + style = UI_SMALLFONT; + } + + // draw label + UI_DrawString( x - SMALLCHAR_WIDTH, y, s->generic.name, UI_RIGHT|style, color ); + + // draw slider + UI_SetColor( color ); + UI_DrawHandlePic( x + SMALLCHAR_WIDTH, y, 96, 16, sliderBar ); + UI_SetColor( NULL ); + + // clamp thumb + if( s->maxvalue > s->minvalue ) { + s->range = ( s->curvalue - s->minvalue ) / ( float ) ( s->maxvalue - s->minvalue ); + if( s->range < 0 ) { + s->range = 0; + } + else if( s->range > 1) { + s->range = 1; + } + } + else { + s->range = 0; + } + + // draw thumb + if( style & UI_PULSE) { + button = sliderButton_1; + } + else { + button = sliderButton_0; + } + + UI_DrawHandlePic( (int)( x + 2*SMALLCHAR_WIDTH + (SLIDER_RANGE-1)*SMALLCHAR_WIDTH* s->range ) - 2, y - 2, 12, 20, button ); +} +#else +/* +================= +Slider_Draw +================= +*/ +static void Slider_Draw( menuslider_s *s ) +{ + float *color; + int style; + int i; + int x; + int y; + qboolean focus; + + x = s->generic.x; + y = s->generic.y; + focus = (s->generic.parent->cursor == s->generic.menuPosition); + + style = UI_SMALLFONT; + if ( s->generic.flags & QMF_GRAYED ) + { + color = text_color_disabled; + } + else if (focus) + { + color = text_color_highlight; + style |= UI_PULSE; + } + else + { + color = text_color_normal; + } + + if ( focus ) + { + // draw cursor + UI_FillRect( s->generic.left, s->generic.top, s->generic.right-s->generic.left+1, s->generic.bottom-s->generic.top+1, listbar_color ); + UI_DrawChar( x, y, 13, UI_CENTER|UI_BLINK|UI_SMALLFONT, color); + } + + // draw label + UI_DrawString( x - SMALLCHAR_WIDTH, y, s->generic.name, UI_RIGHT|style, color ); + + // draw slider + UI_DrawChar( x + SMALLCHAR_WIDTH, y, 128, UI_LEFT|style, color); + for ( i = 0; i < SLIDER_RANGE; i++ ) + UI_DrawChar( x + (i+2)*SMALLCHAR_WIDTH, y, 129, UI_LEFT|style, color); + UI_DrawChar( x + (i+2)*SMALLCHAR_WIDTH, y, 130, UI_LEFT|style, color); + + // clamp thumb + if (s->maxvalue > s->minvalue) + { + s->range = ( s->curvalue - s->minvalue ) / ( float ) ( s->maxvalue - s->minvalue ); + if ( s->range < 0) + s->range = 0; + else if ( s->range > 1) + s->range = 1; + } + else + s->range = 0; + + // draw thumb + if (style & UI_PULSE) { + style &= ~UI_PULSE; + style |= UI_BLINK; + } + UI_DrawChar( (int)( x + 2*SMALLCHAR_WIDTH + (SLIDER_RANGE-1)*SMALLCHAR_WIDTH* s->range ), y, 131, UI_LEFT|style, color); +} +#endif + +/* +================= +SpinControl_Init +================= +*/ +static void SpinControl_Init( menulist_s *s ) { + int len; + int l; + const char* str; + + if (s->generic.name) + len = strlen(s->generic.name) * SMALLCHAR_WIDTH; + else + len = 0; + + s->generic.left = s->generic.x - SMALLCHAR_WIDTH - len; + + len = s->numitems = 0; + while ( (str = s->itemnames[s->numitems]) != 0 ) + { + l = strlen(str); + if (l > len) + len = l; + + s->numitems++; + } + + s->generic.top = s->generic.y; + s->generic.right = s->generic.x + (len+1)*SMALLCHAR_WIDTH; + s->generic.bottom = s->generic.y + SMALLCHAR_HEIGHT; +} + +/* +================= +SpinControl_Key +================= +*/ +static sfxHandle_t SpinControl_Key( menulist_s *s, int key ) +{ + sfxHandle_t sound; + + sound = 0; + switch (key) + { + case K_MOUSE1: + s->curvalue++; + if (s->curvalue >= s->numitems) + s->curvalue = 0; + sound = menu_move_sound; + break; + + case K_KP_LEFTARROW: + case K_LEFTARROW: + if (s->curvalue > 0) + { + s->curvalue--; + sound = menu_move_sound; + } + else + sound = menu_buzz_sound; + break; + + case K_KP_RIGHTARROW: + case K_RIGHTARROW: + if (s->curvalue < s->numitems-1) + { + s->curvalue++; + sound = menu_move_sound; + } + else + sound = menu_buzz_sound; + break; + } + + if ( sound && s->generic.callback ) + s->generic.callback( s, QM_ACTIVATED ); + + return (sound); +} + +/* +================= +SpinControl_Draw +================= +*/ +static void SpinControl_Draw( menulist_s *s ) +{ + float *color; + int x,y; + int style; + qboolean focus; + + x = s->generic.x; + y = s->generic.y; + + style = UI_SMALLFONT; + focus = (s->generic.parent->cursor == s->generic.menuPosition); + + if ( s->generic.flags & QMF_GRAYED ) + color = text_color_disabled; + else if ( focus ) + { + color = text_color_highlight; + style |= UI_PULSE; + } + else if ( s->generic.flags & QMF_BLINK ) + { + color = text_color_highlight; + style |= UI_BLINK; + } + else + color = text_color_normal; + + if ( focus ) + { + // draw cursor + UI_FillRect( s->generic.left, s->generic.top, s->generic.right-s->generic.left+1, s->generic.bottom-s->generic.top+1, listbar_color ); + UI_DrawChar( x, y, 13, UI_CENTER|UI_BLINK|UI_SMALLFONT, color); + } + + UI_DrawString( x - SMALLCHAR_WIDTH, y, s->generic.name, style|UI_RIGHT, color ); + UI_DrawString( x + SMALLCHAR_WIDTH, y, s->itemnames[s->curvalue], style|UI_LEFT, color ); +} + +/* +================= +ScrollList_Init +================= +*/ +static void ScrollList_Init( menulist_s *l ) +{ + int w; + + l->oldvalue = 0; + l->curvalue = 0; + l->top = 0; + + if( !l->columns ) { + l->columns = 1; + l->seperation = 0; + } + else if( !l->seperation ) { + l->seperation = 3; + } + + w = ( (l->width + l->seperation) * l->columns - l->seperation) * SMALLCHAR_WIDTH; + + l->generic.left = l->generic.x; + l->generic.top = l->generic.y; + l->generic.right = l->generic.x + w; + l->generic.bottom = l->generic.y + l->height * SMALLCHAR_HEIGHT; + + if( l->generic.flags & QMF_CENTER_JUSTIFY ) { + l->generic.left -= w / 2; + l->generic.right -= w / 2; + } +} + +/* +================= +ScrollList_Key +================= +*/ +sfxHandle_t ScrollList_Key( menulist_s *l, int key ) +{ + int x; + int y; + int w; + int i; + int j; + int c; + int cursorx; + int cursory; + int column; + int index; + + switch (key) + { + case K_MOUSE1: + if (l->generic.flags & QMF_HASMOUSEFOCUS) + { + // check scroll region + x = l->generic.x; + y = l->generic.y; + w = ( (l->width + l->seperation) * l->columns - l->seperation) * SMALLCHAR_WIDTH; + if( l->generic.flags & QMF_CENTER_JUSTIFY ) { + x -= w / 2; + } + if (UI_CursorInRect( x, y, w, l->height*SMALLCHAR_HEIGHT )) + { + cursorx = (uis.cursorx - x)/SMALLCHAR_WIDTH; + column = cursorx / (l->width + l->seperation); + cursory = (uis.cursory - y)/SMALLCHAR_HEIGHT; + index = column * l->height + cursory; + if (l->top + index < l->numitems) + { + l->oldvalue = l->curvalue; + l->curvalue = l->top + index; + + if (l->oldvalue != l->curvalue && l->generic.callback) + { + l->generic.callback( l, QM_GOTFOCUS ); + return (menu_move_sound); + } + } + } + + // absorbed, silent sound effect + return (menu_null_sound); + } + break; + + case K_KP_HOME: + case K_HOME: + l->oldvalue = l->curvalue; + l->curvalue = 0; + l->top = 0; + + if (l->oldvalue != l->curvalue && l->generic.callback) + { + l->generic.callback( l, QM_GOTFOCUS ); + return (menu_move_sound); + } + return (menu_buzz_sound); + + case K_KP_END: + case K_END: + l->oldvalue = l->curvalue; + l->curvalue = l->numitems-1; + if( l->columns > 1 ) { + c = (l->curvalue / l->height + 1) * l->height; + l->top = c - (l->columns * l->height); + } + else { + l->top = l->curvalue - (l->height - 1); + } + if (l->top < 0) + l->top = 0; + + if (l->oldvalue != l->curvalue && l->generic.callback) + { + l->generic.callback( l, QM_GOTFOCUS ); + return (menu_move_sound); + } + return (menu_buzz_sound); + + case K_PGUP: + case K_KP_PGUP: + if( l->columns > 1 ) { + return menu_null_sound; + } + + if (l->curvalue > 0) + { + l->oldvalue = l->curvalue; + l->curvalue -= l->height-1; + if (l->curvalue < 0) + l->curvalue = 0; + l->top = l->curvalue; + if (l->top < 0) + l->top = 0; + + if (l->generic.callback) + l->generic.callback( l, QM_GOTFOCUS ); + + return (menu_move_sound); + } + return (menu_buzz_sound); + + case K_PGDN: + case K_KP_PGDN: + if( l->columns > 1 ) { + return menu_null_sound; + } + + if (l->curvalue < l->numitems-1) + { + l->oldvalue = l->curvalue; + l->curvalue += l->height-1; + if (l->curvalue > l->numitems-1) + l->curvalue = l->numitems-1; + l->top = l->curvalue - (l->height-1); + if (l->top < 0) + l->top = 0; + + if (l->generic.callback) + l->generic.callback( l, QM_GOTFOCUS ); + + return (menu_move_sound); + } + return (menu_buzz_sound); + + case K_KP_UPARROW: + case K_UPARROW: + if( l->curvalue == 0 ) { + return menu_buzz_sound; + } + + l->oldvalue = l->curvalue; + l->curvalue--; + + if( l->curvalue < l->top ) { + if( l->columns == 1 ) { + l->top--; + } + else { + l->top -= l->height; + } + } + + if( l->generic.callback ) { + l->generic.callback( l, QM_GOTFOCUS ); + } + + return (menu_move_sound); + + case K_KP_DOWNARROW: + case K_DOWNARROW: + if( l->curvalue == l->numitems - 1 ) { + return menu_buzz_sound; + } + + l->oldvalue = l->curvalue; + l->curvalue++; + + if( l->curvalue >= l->top + l->columns * l->height ) { + if( l->columns == 1 ) { + l->top++; + } + else { + l->top += l->height; + } + } + + if( l->generic.callback ) { + l->generic.callback( l, QM_GOTFOCUS ); + } + + return menu_move_sound; + + case K_KP_LEFTARROW: + case K_LEFTARROW: + if( l->columns == 1 ) { + return menu_null_sound; + } + + if( l->curvalue < l->height ) { + return menu_buzz_sound; + } + + l->oldvalue = l->curvalue; + l->curvalue -= l->height; + + if( l->curvalue < l->top ) { + l->top -= l->height; + } + + if( l->generic.callback ) { + l->generic.callback( l, QM_GOTFOCUS ); + } + + return menu_move_sound; + + case K_KP_RIGHTARROW: + case K_RIGHTARROW: + if( l->columns == 1 ) { + return menu_null_sound; + } + + c = l->curvalue + l->height; + + if( c >= l->numitems ) { + return menu_buzz_sound; + } + + l->oldvalue = l->curvalue; + l->curvalue = c; + + if( l->curvalue > l->top + l->columns * l->height - 1 ) { + l->top += l->height; + } + + if( l->generic.callback ) { + l->generic.callback( l, QM_GOTFOCUS ); + } + + return menu_move_sound; + } + + // cycle look for ascii key inside list items + if ( !Q_isprint( key ) ) + return (0); + + // force to lower for case insensitive compare + if ( Q_isupper( key ) ) + { + key -= 'A' - 'a'; + } + + // iterate list items + for (i=1; i<=l->numitems; i++) + { + j = (l->curvalue + i) % l->numitems; + c = l->itemnames[j][0]; + if ( Q_isupper( c ) ) + { + c -= 'A' - 'a'; + } + + if (c == key) + { + // set current item, mimic windows listbox scroll behavior + if (j < l->top) + { + // behind top most item, set this as new top + l->top = j; + } + else if (j > l->top+l->height-1) + { + // past end of list box, do page down + l->top = (j+1) - l->height; + } + + if (l->curvalue != j) + { + l->oldvalue = l->curvalue; + l->curvalue = j; + if (l->generic.callback) + l->generic.callback( l, QM_GOTFOCUS ); + return ( menu_move_sound ); + } + + return (menu_buzz_sound); + } + } + + return (menu_buzz_sound); +} + +/* +================= +ScrollList_Draw +================= +*/ +void ScrollList_Draw( menulist_s *l ) +{ + int x; + int u; + int y; + int i; + int base; + int column; + float* color; + qboolean hasfocus; + int style; + + hasfocus = (l->generic.parent->cursor == l->generic.menuPosition); + + x = l->generic.x; + for( column = 0; column < l->columns; column++ ) { + y = l->generic.y; + base = l->top + column * l->height; + for( i = base; i < base + l->height; i++) { + if (i >= l->numitems) + break; + + if (i == l->curvalue) + { + u = x - 2; + if( l->generic.flags & QMF_CENTER_JUSTIFY ) { + u -= (l->width * SMALLCHAR_WIDTH) / 2 + 1; + } + + UI_FillRect(u,y,l->width*SMALLCHAR_WIDTH,SMALLCHAR_HEIGHT+2,listbar_color); + color = text_color_highlight; + + if (hasfocus) + style = UI_PULSE|UI_LEFT|UI_SMALLFONT; + else + style = UI_LEFT|UI_SMALLFONT; + } + else + { + color = text_color_normal; + style = UI_LEFT|UI_SMALLFONT; + } + if( l->generic.flags & QMF_CENTER_JUSTIFY ) { + style |= UI_CENTER; + } + + UI_DrawString( + x, + y, + l->itemnames[i], + style, + color); + + y += SMALLCHAR_HEIGHT; + } + x += (l->width + l->seperation) * SMALLCHAR_WIDTH; + } +} + +/* +================= +Menu_AddItem +================= +*/ +void Menu_AddItem( menuframework_s *menu, void *item ) +{ + menucommon_s *itemptr; + + if (menu->nitems >= MAX_MENUITEMS) + trap_Error ("Menu_AddItem: excessive items"); + + menu->items[menu->nitems] = item; + ((menucommon_s*)menu->items[menu->nitems])->parent = menu; + ((menucommon_s*)menu->items[menu->nitems])->menuPosition = menu->nitems; + ((menucommon_s*)menu->items[menu->nitems])->flags &= ~QMF_HASMOUSEFOCUS; + + // perform any item specific initializations + itemptr = (menucommon_s*)item; + if (!(itemptr->flags & QMF_NODEFAULTINIT)) + { + switch (itemptr->type) + { + case MTYPE_ACTION: + Action_Init((menuaction_s*)item); + break; + + case MTYPE_FIELD: + MenuField_Init((menufield_s*)item); + break; + + case MTYPE_SPINCONTROL: + SpinControl_Init((menulist_s*)item); + break; + + case MTYPE_RADIOBUTTON: + RadioButton_Init((menuradiobutton_s*)item); + break; + + case MTYPE_SLIDER: + Slider_Init((menuslider_s*)item); + break; + + case MTYPE_BITMAP: + Bitmap_Init((menubitmap_s*)item); + break; + + case MTYPE_TEXT: + Text_Init((menutext_s*)item); + break; + + case MTYPE_SCROLLLIST: + ScrollList_Init((menulist_s*)item); + break; + + case MTYPE_PTEXT: + PText_Init((menutext_s*)item); + break; + + case MTYPE_BTEXT: + BText_Init((menutext_s*)item); + break; + + default: + trap_Error( va("Menu_Init: unknown type %d", itemptr->type) ); + } + } + + menu->nitems++; +} + +/* +================= +Menu_CursorMoved +================= +*/ +void Menu_CursorMoved( menuframework_s *m ) +{ + void (*callback)( void *self, int notification ); + + if (m->cursor_prev == m->cursor) + return; + + if (m->cursor_prev >= 0 && m->cursor_prev < m->nitems) + { + callback = ((menucommon_s*)(m->items[m->cursor_prev]))->callback; + if (callback) + callback(m->items[m->cursor_prev],QM_LOSTFOCUS); + } + + if (m->cursor >= 0 && m->cursor < m->nitems) + { + callback = ((menucommon_s*)(m->items[m->cursor]))->callback; + if (callback) + callback(m->items[m->cursor],QM_GOTFOCUS); + } +} + +/* +================= +Menu_SetCursor +================= +*/ +void Menu_SetCursor( menuframework_s *m, int cursor ) +{ + if (((menucommon_s*)(m->items[cursor]))->flags & (QMF_GRAYED|QMF_INACTIVE)) + { + // cursor can't go there + return; + } + + m->cursor_prev = m->cursor; + m->cursor = cursor; + + Menu_CursorMoved( m ); +} + +/* +================= +Menu_SetCursorToItem +================= +*/ +void Menu_SetCursorToItem( menuframework_s *m, void* ptr ) +{ + int i; + + for (i=0; initems; i++) + { + if (m->items[i] == ptr) + { + Menu_SetCursor( m, i ); + return; + } + } +} + +/* +** Menu_AdjustCursor +** +** This function takes the given menu, the direction, and attempts +** to adjust the menu's cursor so that it's at the next available +** slot. +*/ +void Menu_AdjustCursor( menuframework_s *m, int dir ) { + menucommon_s *item = NULL; + qboolean wrapped = qfalse; + +wrap: + while ( m->cursor >= 0 && m->cursor < m->nitems ) { + item = ( menucommon_s * ) m->items[m->cursor]; + if (( item->flags & (QMF_GRAYED|QMF_MOUSEONLY|QMF_INACTIVE) ) ) { + m->cursor += dir; + } + else { + break; + } + } + + if ( dir == 1 ) { + if ( m->cursor >= m->nitems ) { + if ( m->wrapAround ) { + if ( wrapped ) { + m->cursor = m->cursor_prev; + return; + } + m->cursor = 0; + wrapped = qtrue; + goto wrap; + } + m->cursor = m->cursor_prev; + } + } + else { + if ( m->cursor < 0 ) { + if ( m->wrapAround ) { + if ( wrapped ) { + m->cursor = m->cursor_prev; + return; + } + m->cursor = m->nitems - 1; + wrapped = qtrue; + goto wrap; + } + m->cursor = m->cursor_prev; + } + } +} + +/* +================= +Menu_Draw +================= +*/ +void Menu_Draw( menuframework_s *menu ) +{ + int i; + menucommon_s *itemptr; + + // draw menu + for (i=0; initems; i++) + { + itemptr = (menucommon_s*)menu->items[i]; + + if (itemptr->flags & QMF_HIDDEN) + continue; + + if (itemptr->ownerdraw) + { + // total subclassing, owner draws everything + itemptr->ownerdraw( itemptr ); + } + else + { + switch (itemptr->type) + { + case MTYPE_RADIOBUTTON: + RadioButton_Draw( (menuradiobutton_s*)itemptr ); + break; + + case MTYPE_FIELD: + MenuField_Draw( (menufield_s*)itemptr ); + break; + + case MTYPE_SLIDER: + Slider_Draw( (menuslider_s*)itemptr ); + break; + + case MTYPE_SPINCONTROL: + SpinControl_Draw( (menulist_s*)itemptr ); + break; + + case MTYPE_ACTION: + Action_Draw( (menuaction_s*)itemptr ); + break; + + case MTYPE_BITMAP: + Bitmap_Draw( (menubitmap_s*)itemptr ); + break; + + case MTYPE_TEXT: + Text_Draw( (menutext_s*)itemptr ); + break; + + case MTYPE_SCROLLLIST: + ScrollList_Draw( (menulist_s*)itemptr ); + break; + + case MTYPE_PTEXT: + PText_Draw( (menutext_s*)itemptr ); + break; + + case MTYPE_BTEXT: + BText_Draw( (menutext_s*)itemptr ); + break; + + default: + trap_Error( va("Menu_Draw: unknown type %d", itemptr->type) ); + } + } +#ifndef NDEBUG + if( uis.debug ) { + int x; + int y; + int w; + int h; + + if( !( itemptr->flags & QMF_INACTIVE ) ) { + x = itemptr->left; + y = itemptr->top; + w = itemptr->right - itemptr->left + 1; + h = itemptr->bottom - itemptr->top + 1; + + if (itemptr->flags & QMF_HASMOUSEFOCUS) { + UI_DrawRect(x, y, w, h, colorYellow ); + } + else { + UI_DrawRect(x, y, w, h, colorWhite ); + } + } + } +#endif + } + + itemptr = Menu_ItemAtCursor( menu ); + if ( itemptr && itemptr->statusbar) + itemptr->statusbar( ( void * ) itemptr ); +} + +/* +================= +Menu_ItemAtCursor +================= +*/ +void *Menu_ItemAtCursor( menuframework_s *m ) +{ + if ( m->cursor < 0 || m->cursor >= m->nitems ) + return 0; + + return m->items[m->cursor]; +} + +/* +================= +Menu_ActivateItem +================= +*/ +sfxHandle_t Menu_ActivateItem( menuframework_s *s, menucommon_s* item ) { + if ( item->callback ) { + item->callback( item, QM_ACTIVATED ); + if( !( item->flags & QMF_SILENT ) ) { + return menu_move_sound; + } + } + + return 0; +} + +/* +================= +Menu_DefaultKey +================= +*/ +sfxHandle_t Menu_DefaultKey( menuframework_s *m, int key ) +{ + sfxHandle_t sound = 0; + menucommon_s *item; + int cursor_prev; + + // menu system keys + switch ( key ) + { + case K_MOUSE2: + case K_ESCAPE: + UI_PopMenu(); + return menu_out_sound; + } + + if (!m || !m->nitems) + return 0; + + // route key stimulus to widget + item = Menu_ItemAtCursor( m ); + if (item && !(item->flags & (QMF_GRAYED|QMF_INACTIVE))) + { + switch (item->type) + { + case MTYPE_SPINCONTROL: + sound = SpinControl_Key( (menulist_s*)item, key ); + break; + + case MTYPE_RADIOBUTTON: + sound = RadioButton_Key( (menuradiobutton_s*)item, key ); + break; + + case MTYPE_SLIDER: + sound = Slider_Key( (menuslider_s*)item, key ); + break; + + case MTYPE_SCROLLLIST: + sound = ScrollList_Key( (menulist_s*)item, key ); + break; + + case MTYPE_FIELD: + sound = MenuField_Key( (menufield_s*)item, &key ); + break; + } + + if (sound) { + // key was handled + return sound; + } + } + + // default handling + switch ( key ) + { +#ifndef NDEBUG + case K_F11: + uis.debug ^= 1; + break; + + case K_F12: + trap_Cmd_ExecuteText(EXEC_APPEND, "screenshot\n"); + break; +#endif + case K_KP_UPARROW: + case K_UPARROW: + cursor_prev = m->cursor; + m->cursor_prev = m->cursor; + m->cursor--; + Menu_AdjustCursor( m, -1 ); + if ( cursor_prev != m->cursor ) { + Menu_CursorMoved( m ); + sound = menu_move_sound; + } + break; + + case K_TAB: + case K_KP_DOWNARROW: + case K_DOWNARROW: + cursor_prev = m->cursor; + m->cursor_prev = m->cursor; + m->cursor++; + Menu_AdjustCursor( m, 1 ); + if ( cursor_prev != m->cursor ) { + Menu_CursorMoved( m ); + sound = menu_move_sound; + } + break; + + case K_MOUSE1: + case K_MOUSE3: + if (item) + if ((item->flags & QMF_HASMOUSEFOCUS) && !(item->flags & (QMF_GRAYED|QMF_INACTIVE))) + return (Menu_ActivateItem( m, item )); + break; + + case K_JOY1: + case K_JOY2: + case K_JOY3: + case K_JOY4: + case K_AUX1: + case K_AUX2: + case K_AUX3: + case K_AUX4: + case K_AUX5: + case K_AUX6: + case K_AUX7: + case K_AUX8: + case K_AUX9: + case K_AUX10: + case K_AUX11: + case K_AUX12: + case K_AUX13: + case K_AUX14: + case K_AUX15: + case K_AUX16: + case K_KP_ENTER: + case K_ENTER: + if (item) + if (!(item->flags & (QMF_MOUSEONLY|QMF_GRAYED|QMF_INACTIVE))) + return (Menu_ActivateItem( m, item )); + break; + } + + return sound; +} + +/* +================= +Menu_Cache +================= +*/ +void Menu_Cache( void ) +{ + uis.charset = trap_R_RegisterShaderNoMip( "gfx/2d/bigchars" ); + uis.charsetProp = trap_R_RegisterShaderNoMip( "menu/art/font1_prop.tga" ); + uis.charsetPropGlow = trap_R_RegisterShaderNoMip( "menu/art/font1_prop_glo.tga" ); + uis.charsetPropB = trap_R_RegisterShaderNoMip( "menu/art/font2_prop.tga" ); + uis.cursor = trap_R_RegisterShaderNoMip( "menu/art/3_cursor2" ); + uis.rb_on = trap_R_RegisterShaderNoMip( "menu/art/switch_on" ); + uis.rb_off = trap_R_RegisterShaderNoMip( "menu/art/switch_off" ); + + uis.whiteShader = trap_R_RegisterShaderNoMip( "white" ); + if ( uis.glconfig.hardwareType == GLHW_RAGEPRO ) { + // the blend effect turns to shit with the normal + uis.menuBackShader = trap_R_RegisterShaderNoMip( "menubackRagePro" ); + } else { + uis.menuBackShader = trap_R_RegisterShaderNoMip( "menuback" ); + } + uis.menuBackNoLogoShader = trap_R_RegisterShaderNoMip( "menubacknologo" ); + + menu_in_sound = trap_S_RegisterSound( "sound/misc/menu1.wav", qfalse ); + menu_move_sound = trap_S_RegisterSound( "sound/misc/menu2.wav", qfalse ); + menu_out_sound = trap_S_RegisterSound( "sound/misc/menu3.wav", qfalse ); + menu_buzz_sound = trap_S_RegisterSound( "sound/misc/menu4.wav", qfalse ); + weaponChangeSound = trap_S_RegisterSound( "sound/weapons/change.wav", qfalse ); + + // need a nonzero sound, make an empty sound for this + menu_null_sound = -1; + + sliderBar = trap_R_RegisterShaderNoMip( "menu/art/slider2" ); + sliderButton_0 = trap_R_RegisterShaderNoMip( "menu/art/sliderbutt_0" ); + sliderButton_1 = trap_R_RegisterShaderNoMip( "menu/art/sliderbutt_1" ); +} + diff --git a/code/q3_ui/ui_rankings.c b/code/q3_ui/ui_rankings.c new file mode 100755 index 0000000..762e964 --- /dev/null +++ b/code/q3_ui/ui_rankings.c @@ -0,0 +1,420 @@ +/* +=========================================================================== +Copyright (C) 1999-2005 Id Software, Inc. + +This file is part of Quake III Arena source code. + +Quake III Arena source code is free software; you can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 2 of the License, +or (at your option) any later version. + +Quake III Arena source code is distributed in the hope that it will be +useful, but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Foobar; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ +// +// +// ui_rankings.c +// + +#include "ui_local.h" + + +#define RANKINGS_FRAME "menu/art/cut_frame" + +#define ID_LOGIN 100 +#define ID_LOGOUT 101 +#define ID_CREATE 102 +#define ID_SPECTATE 103 +#define ID_SETUP 104 +#define ID_LEAVE 105 + + +typedef struct +{ + menuframework_s menu; + menubitmap_s frame; + menutext_s login; + menutext_s logout; + menutext_s create; + menutext_s spectate; + menutext_s setup; + menutext_s leave; +} rankings_t; + +static rankings_t s_rankings; + +static menuframework_s s_rankings_menu; +static menuaction_s s_rankings_login; +static menuaction_s s_rankings_logout; +static menuaction_s s_rankings_create; +static menuaction_s s_rankings_spectate; +static menuaction_s s_rankings_setup; +static menuaction_s s_rankings_leave; + + +/* +=============== +Rankings_DrawText +=============== +*/ +void Rankings_DrawText( void* self ) +{ + menufield_s *f; + qboolean focus; + int style; + char *txt; + char c; + float *color; + int basex, x, y; + + f = (menufield_s*)self; + basex = f->generic.x; + y = f->generic.y + 4; + focus = (f->generic.parent->cursor == f->generic.menuPosition); + + style = UI_LEFT|UI_SMALLFONT; + color = text_color_normal; + if( focus ) { + style |= UI_PULSE; + color = text_color_highlight; + } + + // draw the actual text + txt = f->field.buffer; + color = g_color_table[ColorIndex(COLOR_WHITE)]; + x = basex; + while ( (c = *txt) != 0 ) { + UI_DrawChar( x, y, c, style, color ); + txt++; + x += SMALLCHAR_WIDTH; + } + + // draw cursor if we have focus + if( focus ) { + if ( trap_Key_GetOverstrikeMode() ) { + c = 11; + } else { + c = 10; + } + + style &= ~UI_PULSE; + style |= UI_BLINK; + + UI_DrawChar( basex + f->field.cursor * SMALLCHAR_WIDTH, y, c, style, color_white ); + } +} + +/* +=============== +Rankings_DrawName +=============== +*/ +void Rankings_DrawName( void* self ) +{ + menufield_s *f; + int length; + char* p; + + f = (menufield_s*)self; + + // GRANK_FIXME - enforce valid characters + for( p = f->field.buffer; *p != '\0'; p++ ) + { + //if( ispunct(*p) || isspace(*p) ) + if( !( ( (*p) >= '0' && (*p) <= '9') || Q_isalpha(*p)) ) + { + *p = '\0'; + } + } + + // strip color codes + Q_CleanStr( f->field.buffer ); + length = strlen( f->field.buffer ); + if( f->field.cursor > length ) + { + f->field.cursor = length; + } + + Rankings_DrawText( f ); +} + +#if 0 // old version +/* +=============== +Rankings_DrawName +=============== +*/ +void Rankings_DrawName( void* self ) +{ + menufield_s* f; + int length; + + f = (menufield_s*)self; + + // strip color codes + Q_CleanStr( f->field.buffer ); + length = strlen( f->field.buffer ); + if( f->field.cursor > length ) + { + f->field.cursor = length; + } + + // show beginning of long names + /* + if( Menu_ItemAtCursor( f->generic.parent ) != f ) + { + if( f->field.scroll > 0 ) + { + f->field.cursor = 0; + f->field.scroll = 0; + } + } + */ + + MenuField_Draw( f ); +} +#endif + +/* +=============== +Rankings_DrawPassword +=============== +*/ +void Rankings_DrawPassword( void* self ) +{ + menufield_s* f; + char password[MAX_EDIT_LINE]; + int length; + int i; + char* p; + + f = (menufield_s*)self; + + // GRANK_FIXME - enforce valid characters + for( p = f->field.buffer; *p != '\0'; p++ ) + { + //if( ispunct(*p) || isspace(*p) ) + if( !( ( (*p) >= '0' && (*p) <= '9') || Q_isalpha(*p)) ) + { + *p = '\0'; + } + } + + length = strlen( f->field.buffer ); + if( f->field.cursor > length ) + { + f->field.cursor = length; + } + + // save password + Q_strncpyz( password, f->field.buffer, sizeof(password) ); + + // mask password with * + for( i = 0; i < length; i++ ) + { + f->field.buffer[i] = '*'; + } + + // draw masked password + Rankings_DrawText( f ); + //MenuField_Draw( f ); + + // restore password + Q_strncpyz( f->field.buffer, password, sizeof(f->field.buffer) ); +} + +/* +=============== +Rankings_MenuEvent +=============== +*/ +static void Rankings_MenuEvent( void* ptr, int event ) { + if( event != QM_ACTIVATED ) { + return; + } + + switch( ((menucommon_s*)ptr)->id ) { + case ID_LOGIN: + UI_LoginMenu(); + break; + + case ID_LOGOUT: + // server side masqueraded player logout first + trap_CL_UI_RankUserRequestLogout(); + UI_ForceMenuOff(); + break; + + case ID_CREATE: + UI_SignupMenu(); + break; + + case ID_SPECTATE: + trap_Cmd_ExecuteText( EXEC_APPEND, "cmd rank_spectate\n" ); + UI_ForceMenuOff(); + break; + + case ID_SETUP: + UI_SetupMenu(); + break; + + case ID_LEAVE: + trap_Cmd_ExecuteText( EXEC_APPEND, "disconnect\n" ); + UI_ForceMenuOff(); + break; + + } +} + + +/* +=============== +Rankings_MenuInit +=============== +*/ +void Rankings_MenuInit( void ) { + grank_status_t status; + int y; + + memset( &s_rankings, 0, sizeof(s_rankings) ); + + Rankings_Cache(); + + s_rankings.menu.wrapAround = qtrue; + s_rankings.menu.fullscreen = qfalse; + + s_rankings.frame.generic.type = MTYPE_BITMAP; + s_rankings.frame.generic.flags = QMF_INACTIVE; + s_rankings.frame.generic.name = RANKINGS_FRAME; + s_rankings.frame.generic.x = 142; + s_rankings.frame.generic.y = 118; + s_rankings.frame.width = 359; + s_rankings.frame.height = 256; + + y = 194; + + s_rankings.login.generic.type = MTYPE_PTEXT; + s_rankings.login.generic.flags = QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS; + s_rankings.login.generic.id = ID_LOGIN; + s_rankings.login.generic.callback = Rankings_MenuEvent; + s_rankings.login.generic.x = 320; + s_rankings.login.generic.y = y; + s_rankings.login.string = "LOGIN"; + s_rankings.login.style = UI_CENTER|UI_SMALLFONT; + s_rankings.login.color = colorRed; + y += 20; + + s_rankings.logout.generic.type = MTYPE_PTEXT; + s_rankings.logout.generic.flags = QMF_HIDDEN|QMF_INACTIVE|QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS; + s_rankings.logout.generic.id = ID_LOGOUT; + s_rankings.logout.generic.callback = Rankings_MenuEvent; + s_rankings.logout.generic.x = 320; + s_rankings.logout.generic.y = y; + s_rankings.logout.string = "LOGOUT"; + s_rankings.logout.style = UI_CENTER|UI_SMALLFONT; + s_rankings.logout.color = colorRed; + + s_rankings.create.generic.type = MTYPE_PTEXT; + s_rankings.create.generic.flags = QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS; + s_rankings.create.generic.id = ID_CREATE; + s_rankings.create.generic.callback = Rankings_MenuEvent; + s_rankings.create.generic.x = 320; + s_rankings.create.generic.y = y; + s_rankings.create.string = "SIGN UP"; + s_rankings.create.style = UI_CENTER|UI_SMALLFONT; + s_rankings.create.color = colorRed; + y += 20; + + s_rankings.spectate.generic.type = MTYPE_PTEXT; + s_rankings.spectate.generic.flags = QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS; + s_rankings.spectate.generic.id = ID_SPECTATE; + s_rankings.spectate.generic.callback = Rankings_MenuEvent; + s_rankings.spectate.generic.x = 320; + s_rankings.spectate.generic.y = y; + s_rankings.spectate.string = "SPECTATE"; + s_rankings.spectate.style = UI_CENTER|UI_SMALLFONT; + s_rankings.spectate.color = colorRed; + y += 20; + + s_rankings.setup.generic.type = MTYPE_PTEXT; + s_rankings.setup.generic.flags = QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS; + s_rankings.setup.generic.id = ID_SETUP; + s_rankings.setup.generic.callback = Rankings_MenuEvent; + s_rankings.setup.generic.x = 320; + s_rankings.setup.generic.y = y; + s_rankings.setup.string = "SETUP"; + s_rankings.setup.style = UI_CENTER|UI_SMALLFONT; + s_rankings.setup.color = colorRed; + y += 20; + + s_rankings.leave.generic.type = MTYPE_PTEXT; + s_rankings.leave.generic.flags = QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS; + s_rankings.leave.generic.id = ID_LEAVE; + s_rankings.leave.generic.callback = Rankings_MenuEvent; + s_rankings.leave.generic.x = 320; + s_rankings.leave.generic.y = y; + s_rankings.leave.string = "LEAVE ARENA"; + s_rankings.leave.style = UI_CENTER|UI_SMALLFONT; + s_rankings.leave.color = colorRed; + y += 20; + + status = (grank_status_t)trap_Cvar_VariableValue("client_status"); + if( (status != QGR_STATUS_NEW) && (status != QGR_STATUS_SPECTATOR) ) + { + s_rankings.login.generic.flags |= QMF_HIDDEN | QMF_INACTIVE; + s_rankings.create.generic.flags |= QMF_HIDDEN | QMF_INACTIVE; + s_rankings.spectate.generic.flags |= QMF_HIDDEN | QMF_INACTIVE; + + s_rankings.logout.generic.flags &= ~(QMF_HIDDEN | QMF_INACTIVE); + } + + if ( (status == QGR_STATUS_VALIDATING) || + (status == QGR_STATUS_PENDING) || + (status == QGR_STATUS_LEAVING) ) + { + s_rankings.login.generic.flags |= QMF_GRAYED; + s_rankings.create.generic.flags |= QMF_GRAYED; + s_rankings.logout.generic.flags |= QMF_GRAYED; + } + + //GRank FIXME -- don't need setup option any more + s_rankings.setup.generic.flags |= QMF_HIDDEN | QMF_INACTIVE; + + Menu_AddItem( &s_rankings.menu, (void*) &s_rankings.frame ); + Menu_AddItem( &s_rankings.menu, (void*) &s_rankings.login ); + Menu_AddItem( &s_rankings.menu, (void*) &s_rankings.logout ); + Menu_AddItem( &s_rankings.menu, (void*) &s_rankings.create ); + Menu_AddItem( &s_rankings.menu, (void*) &s_rankings.spectate ); + Menu_AddItem( &s_rankings.menu, (void*) &s_rankings.setup ); + Menu_AddItem( &s_rankings.menu, (void*) &s_rankings.leave ); +} + + +/* +=============== +Rankings_Cache +=============== +*/ +void Rankings_Cache( void ) { + trap_R_RegisterShaderNoMip( RANKINGS_FRAME ); +} + + +/* +=============== +UI_RankingsMenu +=============== +*/ +void UI_RankingsMenu( void ) { + Rankings_MenuInit(); + UI_PushMenu ( &s_rankings.menu ); +} + + diff --git a/code/q3_ui/ui_rankstatus.c b/code/q3_ui/ui_rankstatus.c new file mode 100755 index 0000000..3563364 --- /dev/null +++ b/code/q3_ui/ui_rankstatus.c @@ -0,0 +1,209 @@ +/* +=========================================================================== +Copyright (C) 1999-2005 Id Software, Inc. + +This file is part of Quake III Arena source code. + +Quake III Arena source code is free software; you can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 2 of the License, +or (at your option) any later version. + +Quake III Arena source code is distributed in the hope that it will be +useful, but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Foobar; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ +// +// +// ui_rankstatus.c +// + +#include "ui_local.h" + + +#define RANKSTATUS_FRAME "menu/art/cut_frame" + +#define ID_MESSAGE 100 +#define ID_OK 101 + + +typedef struct +{ + menuframework_s menu; + menubitmap_s frame; + menutext_s message; + menutext_s ok; +} rankstatus_t; + +static rankstatus_t s_rankstatus; + +static menuframework_s s_rankstatus_menu; +static menuaction_s s_rankstatus_ok; + +static grank_status_t s_status = 0; +static char* s_rankstatus_message = NULL; + +static vec4_t s_rankingstatus_color_prompt = {1.00, 0.43, 0.00, 1.00}; + +/* +=============== +RankStatus_MenuEvent +=============== +*/ +static void RankStatus_MenuEvent( void* ptr, int event ) { + if( event != QM_ACTIVATED ) { + return; + } + + switch( ((menucommon_s*)ptr)->id ) { + case ID_OK: + UI_PopMenu(); + + switch( s_status ) + { + case QGR_STATUS_NO_USER: + UI_RankingsMenu(); + break; + case QGR_STATUS_BAD_PASSWORD: + UI_RankingsMenu(); + UI_LoginMenu(); + break; + case QGR_STATUS_USER_EXISTS: + UI_RankingsMenu(); + UI_SignupMenu(); + break; + case QGR_STATUS_NO_MEMBERSHIP: + UI_RankingsMenu(); + break; + case QGR_STATUS_TIMEOUT: + UI_RankingsMenu(); + break; + case QGR_STATUS_INVALIDUSER: + UI_RankingsMenu(); + break; + case QGR_STATUS_ERROR: + UI_RankingsMenu(); + break; + default: + break; + } + + break; + } +} + + +/* +=============== +RankStatus_MenuInit +=============== +*/ +void RankStatus_MenuInit( void ) { + int y; + + memset( &s_rankstatus, 0, sizeof(s_rankstatus) ); + + RankStatus_Cache(); + + s_rankstatus.menu.wrapAround = qtrue; + s_rankstatus.menu.fullscreen = qfalse; + + s_rankstatus.frame.generic.type = MTYPE_BITMAP; + s_rankstatus.frame.generic.flags = QMF_INACTIVE; + s_rankstatus.frame.generic.name = RANKSTATUS_FRAME; + s_rankstatus.frame.generic.x = 142; //320-233; + s_rankstatus.frame.generic.y = 118; //240-166; + s_rankstatus.frame.width = 359; //466; + s_rankstatus.frame.height = 256; //332; + + y = 214; + + s_rankstatus.message.generic.type = MTYPE_PTEXT; + s_rankstatus.message.generic.flags = QMF_CENTER_JUSTIFY|QMF_INACTIVE; + s_rankstatus.message.generic.id = ID_MESSAGE; + s_rankstatus.message.generic.x = 320; + s_rankstatus.message.generic.y = y; + s_rankstatus.message.string = s_rankstatus_message; + s_rankstatus.message.style = UI_CENTER|UI_SMALLFONT; + s_rankstatus.message.color = s_rankingstatus_color_prompt; + y += 40; + + s_rankstatus.ok.generic.type = MTYPE_PTEXT; + s_rankstatus.ok.generic.flags = QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS; + s_rankstatus.ok.generic.id = ID_OK; + s_rankstatus.ok.generic.callback = RankStatus_MenuEvent; + s_rankstatus.ok.generic.x = 320; + s_rankstatus.ok.generic.y = y; + s_rankstatus.ok.string = "OK"; + s_rankstatus.ok.style = UI_CENTER|UI_SMALLFONT; + s_rankstatus.ok.color = colorRed; + + Menu_AddItem( &s_rankstatus.menu, (void*) &s_rankstatus.frame ); + Menu_AddItem( &s_rankstatus.menu, (void*) &s_rankstatus.message ); + Menu_AddItem( &s_rankstatus.menu, (void*) &s_rankstatus.ok ); +} + + +/* +=============== +RankStatus_Cache +=============== +*/ +void RankStatus_Cache( void ) { + trap_R_RegisterShaderNoMip( RANKSTATUS_FRAME ); +} + + +/* +=============== +UI_RankStatusMenu +=============== +*/ +void UI_RankStatusMenu( void ) { + + s_status = (grank_status_t)trap_Cvar_VariableValue("client_status"); + + switch( s_status ) + { + case QGR_STATUS_NEW: + return; + case QGR_STATUS_PENDING: + // GRANK_FIXME + return; + case QGR_STATUS_NO_USER: + // GRANK_FIXME - get this when user exists + s_rankstatus_message = "Username unavailable"; + break; + case QGR_STATUS_BAD_PASSWORD: + s_rankstatus_message = "Invalid password"; + break; + case QGR_STATUS_TIMEOUT: + s_rankstatus_message = "Timed out"; + break; + case QGR_STATUS_NO_MEMBERSHIP: + s_rankstatus_message = "No membership"; + break; + case QGR_STATUS_INVALIDUSER: + s_rankstatus_message = "Validation failed"; + break; + case QGR_STATUS_ERROR: + s_rankstatus_message = "Error"; + break; + case QGR_STATUS_SPECTATOR: + case QGR_STATUS_ACTIVE: + UI_ForceMenuOff(); + return; + default: + return; + } + RankStatus_MenuInit(); + trap_CL_UI_RankUserReset(); + UI_PushMenu ( &s_rankstatus.menu ); +} + diff --git a/code/q3_ui/ui_removebots.c b/code/q3_ui/ui_removebots.c new file mode 100755 index 0000000..8d13fdc --- /dev/null +++ b/code/q3_ui/ui_removebots.c @@ -0,0 +1,342 @@ +/* +=========================================================================== +Copyright (C) 1999-2005 Id Software, Inc. + +This file is part of Quake III Arena source code. + +Quake III Arena source code is free software; you can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 2 of the License, +or (at your option) any later version. + +Quake III Arena source code is distributed in the hope that it will be +useful, but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Foobar; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ +// +/* +======================================================================= + +REMOVE BOTS MENU + +======================================================================= +*/ + + +#include "ui_local.h" + + +#define ART_BACKGROUND "menu/art/addbotframe" +#define ART_BACK0 "menu/art/back_0" +#define ART_BACK1 "menu/art/back_1" +#define ART_DELETE0 "menu/art/delete_0" +#define ART_DELETE1 "menu/art/delete_1" +#define ART_ARROWS "menu/art/arrows_vert_0" +#define ART_ARROWUP "menu/art/arrows_vert_top" +#define ART_ARROWDOWN "menu/art/arrows_vert_bot" + +#define ID_UP 10 +#define ID_DOWN 11 +#define ID_DELETE 12 +#define ID_BACK 13 +#define ID_BOTNAME0 20 +#define ID_BOTNAME1 21 +#define ID_BOTNAME2 22 +#define ID_BOTNAME3 23 +#define ID_BOTNAME4 24 +#define ID_BOTNAME5 25 +#define ID_BOTNAME6 26 + + +typedef struct { + menuframework_s menu; + + menutext_s banner; + menubitmap_s background; + + menubitmap_s arrows; + menubitmap_s up; + menubitmap_s down; + + menutext_s bots[7]; + + menubitmap_s delete; + menubitmap_s back; + + int numBots; + int baseBotNum; + int selectedBotNum; + char botnames[7][32]; + int botClientNums[MAX_BOTS]; +} removeBotsMenuInfo_t; + +static removeBotsMenuInfo_t removeBotsMenuInfo; + + +/* +================= +UI_RemoveBotsMenu_SetBotNames +================= +*/ +static void UI_RemoveBotsMenu_SetBotNames( void ) { + int n; + char info[MAX_INFO_STRING]; + + for ( n = 0; (n < 7) && (removeBotsMenuInfo.baseBotNum + n < removeBotsMenuInfo.numBots); n++ ) { + trap_GetConfigString( CS_PLAYERS + removeBotsMenuInfo.botClientNums[removeBotsMenuInfo.baseBotNum + n], info, MAX_INFO_STRING ); + Q_strncpyz( removeBotsMenuInfo.botnames[n], Info_ValueForKey( info, "n" ), sizeof(removeBotsMenuInfo.botnames[n]) ); + Q_CleanStr( removeBotsMenuInfo.botnames[n] ); + } + +} + + +/* +================= +UI_RemoveBotsMenu_DeleteEvent +================= +*/ +static void UI_RemoveBotsMenu_DeleteEvent( void* ptr, int event ) { + if (event != QM_ACTIVATED) { + return; + } + + trap_Cmd_ExecuteText( EXEC_APPEND, va("clientkick %i\n", removeBotsMenuInfo.botClientNums[removeBotsMenuInfo.baseBotNum + removeBotsMenuInfo.selectedBotNum]) ); +} + + +/* +================= +UI_RemoveBotsMenu_BotEvent +================= +*/ +static void UI_RemoveBotsMenu_BotEvent( void* ptr, int event ) { + if (event != QM_ACTIVATED) { + return; + } + + removeBotsMenuInfo.bots[removeBotsMenuInfo.selectedBotNum].color = color_orange; + removeBotsMenuInfo.selectedBotNum = ((menucommon_s*)ptr)->id - ID_BOTNAME0; + removeBotsMenuInfo.bots[removeBotsMenuInfo.selectedBotNum].color = color_white; +} + + +/* +================= +UI_RemoveAddBotsMenu_BackEvent +================= +*/ +static void UI_RemoveBotsMenu_BackEvent( void* ptr, int event ) { + if (event != QM_ACTIVATED) { + return; + } + UI_PopMenu(); +} + + +/* +================= +UI_RemoveBotsMenu_UpEvent +================= +*/ +static void UI_RemoveBotsMenu_UpEvent( void* ptr, int event ) { + if (event != QM_ACTIVATED) { + return; + } + + if( removeBotsMenuInfo.baseBotNum > 0 ) { + removeBotsMenuInfo.baseBotNum--; + UI_RemoveBotsMenu_SetBotNames(); + } +} + + +/* +================= +UI_RemoveBotsMenu_DownEvent +================= +*/ +static void UI_RemoveBotsMenu_DownEvent( void* ptr, int event ) { + if (event != QM_ACTIVATED) { + return; + } + + if( removeBotsMenuInfo.baseBotNum + 7 < removeBotsMenuInfo.numBots ) { + removeBotsMenuInfo.baseBotNum++; + UI_RemoveBotsMenu_SetBotNames(); + } +} + + +/* +================= +UI_RemoveBotsMenu_GetBots +================= +*/ +static void UI_RemoveBotsMenu_GetBots( void ) { + int numPlayers; + int isBot; + int n; + char info[MAX_INFO_STRING]; + + trap_GetConfigString( CS_SERVERINFO, info, sizeof(info) ); + numPlayers = atoi( Info_ValueForKey( info, "sv_maxclients" ) ); + removeBotsMenuInfo.numBots = 0; + + for( n = 0; n < numPlayers; n++ ) { + trap_GetConfigString( CS_PLAYERS + n, info, MAX_INFO_STRING ); + + isBot = atoi( Info_ValueForKey( info, "skill" ) ); + if( !isBot ) { + continue; + } + + removeBotsMenuInfo.botClientNums[removeBotsMenuInfo.numBots] = n; + removeBotsMenuInfo.numBots++; + } +} + + +/* +================= +UI_RemoveBots_Cache +================= +*/ +void UI_RemoveBots_Cache( void ) { + trap_R_RegisterShaderNoMip( ART_BACKGROUND ); + trap_R_RegisterShaderNoMip( ART_BACK0 ); + trap_R_RegisterShaderNoMip( ART_BACK1 ); + trap_R_RegisterShaderNoMip( ART_DELETE0 ); + trap_R_RegisterShaderNoMip( ART_DELETE1 ); +} + + +/* +================= +UI_RemoveBotsMenu_Init +================= +*/ +static void UI_RemoveBotsMenu_Init( void ) { + int n; + int count; + int y; + + memset( &removeBotsMenuInfo, 0 ,sizeof(removeBotsMenuInfo) ); + removeBotsMenuInfo.menu.fullscreen = qfalse; + removeBotsMenuInfo.menu.wrapAround = qtrue; + + UI_RemoveBots_Cache(); + + UI_RemoveBotsMenu_GetBots(); + UI_RemoveBotsMenu_SetBotNames(); + count = removeBotsMenuInfo.numBots < 7 ? removeBotsMenuInfo.numBots : 7; + + removeBotsMenuInfo.banner.generic.type = MTYPE_BTEXT; + removeBotsMenuInfo.banner.generic.x = 320; + removeBotsMenuInfo.banner.generic.y = 16; + removeBotsMenuInfo.banner.string = "REMOVE BOTS"; + removeBotsMenuInfo.banner.color = color_white; + removeBotsMenuInfo.banner.style = UI_CENTER; + + removeBotsMenuInfo.background.generic.type = MTYPE_BITMAP; + removeBotsMenuInfo.background.generic.name = ART_BACKGROUND; + removeBotsMenuInfo.background.generic.flags = QMF_INACTIVE; + removeBotsMenuInfo.background.generic.x = 320-233; + removeBotsMenuInfo.background.generic.y = 240-166; + removeBotsMenuInfo.background.width = 466; + removeBotsMenuInfo.background.height = 332; + + removeBotsMenuInfo.arrows.generic.type = MTYPE_BITMAP; + removeBotsMenuInfo.arrows.generic.name = ART_ARROWS; + removeBotsMenuInfo.arrows.generic.flags = QMF_INACTIVE; + removeBotsMenuInfo.arrows.generic.x = 200; + removeBotsMenuInfo.arrows.generic.y = 128; + removeBotsMenuInfo.arrows.width = 64; + removeBotsMenuInfo.arrows.height = 128; + + removeBotsMenuInfo.up.generic.type = MTYPE_BITMAP; + removeBotsMenuInfo.up.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS; + removeBotsMenuInfo.up.generic.x = 200; + removeBotsMenuInfo.up.generic.y = 128; + removeBotsMenuInfo.up.generic.id = ID_UP; + removeBotsMenuInfo.up.generic.callback = UI_RemoveBotsMenu_UpEvent; + removeBotsMenuInfo.up.width = 64; + removeBotsMenuInfo.up.height = 64; + removeBotsMenuInfo.up.focuspic = ART_ARROWUP; + + removeBotsMenuInfo.down.generic.type = MTYPE_BITMAP; + removeBotsMenuInfo.down.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS; + removeBotsMenuInfo.down.generic.x = 200; + removeBotsMenuInfo.down.generic.y = 128+64; + removeBotsMenuInfo.down.generic.id = ID_DOWN; + removeBotsMenuInfo.down.generic.callback = UI_RemoveBotsMenu_DownEvent; + removeBotsMenuInfo.down.width = 64; + removeBotsMenuInfo.down.height = 64; + removeBotsMenuInfo.down.focuspic = ART_ARROWDOWN; + + for( n = 0, y = 120; n < count; n++, y += 20 ) { + removeBotsMenuInfo.bots[n].generic.type = MTYPE_PTEXT; + removeBotsMenuInfo.bots[n].generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS; + removeBotsMenuInfo.bots[n].generic.id = ID_BOTNAME0 + n; + removeBotsMenuInfo.bots[n].generic.x = 320 - 56; + removeBotsMenuInfo.bots[n].generic.y = y; + removeBotsMenuInfo.bots[n].generic.callback = UI_RemoveBotsMenu_BotEvent; + removeBotsMenuInfo.bots[n].string = removeBotsMenuInfo.botnames[n]; + removeBotsMenuInfo.bots[n].color = color_orange; + removeBotsMenuInfo.bots[n].style = UI_LEFT|UI_SMALLFONT; + } + + removeBotsMenuInfo.delete.generic.type = MTYPE_BITMAP; + removeBotsMenuInfo.delete.generic.name = ART_DELETE0; + removeBotsMenuInfo.delete.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS; + removeBotsMenuInfo.delete.generic.id = ID_DELETE; + removeBotsMenuInfo.delete.generic.callback = UI_RemoveBotsMenu_DeleteEvent; + removeBotsMenuInfo.delete.generic.x = 320+128-128; + removeBotsMenuInfo.delete.generic.y = 256+128-64; + removeBotsMenuInfo.delete.width = 128; + removeBotsMenuInfo.delete.height = 64; + removeBotsMenuInfo.delete.focuspic = ART_DELETE1; + + removeBotsMenuInfo.back.generic.type = MTYPE_BITMAP; + removeBotsMenuInfo.back.generic.name = ART_BACK0; + removeBotsMenuInfo.back.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS; + removeBotsMenuInfo.back.generic.id = ID_BACK; + removeBotsMenuInfo.back.generic.callback = UI_RemoveBotsMenu_BackEvent; + removeBotsMenuInfo.back.generic.x = 320-128; + removeBotsMenuInfo.back.generic.y = 256+128-64; + removeBotsMenuInfo.back.width = 128; + removeBotsMenuInfo.back.height = 64; + removeBotsMenuInfo.back.focuspic = ART_BACK1; + + Menu_AddItem( &removeBotsMenuInfo.menu, &removeBotsMenuInfo.background ); + Menu_AddItem( &removeBotsMenuInfo.menu, &removeBotsMenuInfo.banner ); + Menu_AddItem( &removeBotsMenuInfo.menu, &removeBotsMenuInfo.arrows ); + Menu_AddItem( &removeBotsMenuInfo.menu, &removeBotsMenuInfo.up ); + Menu_AddItem( &removeBotsMenuInfo.menu, &removeBotsMenuInfo.down ); + for( n = 0; n < count; n++ ) { + Menu_AddItem( &removeBotsMenuInfo.menu, &removeBotsMenuInfo.bots[n] ); + } + Menu_AddItem( &removeBotsMenuInfo.menu, &removeBotsMenuInfo.delete ); + Menu_AddItem( &removeBotsMenuInfo.menu, &removeBotsMenuInfo.back ); + + removeBotsMenuInfo.baseBotNum = 0; + removeBotsMenuInfo.selectedBotNum = 0; + removeBotsMenuInfo.bots[0].color = color_white; +} + + +/* +================= +UI_RemoveBotsMenu +================= +*/ +void UI_RemoveBotsMenu( void ) { + UI_RemoveBotsMenu_Init(); + UI_PushMenu( &removeBotsMenuInfo.menu ); +} diff --git a/code/q3_ui/ui_saveconfig.c b/code/q3_ui/ui_saveconfig.c new file mode 100755 index 0000000..d13b676 --- /dev/null +++ b/code/q3_ui/ui_saveconfig.c @@ -0,0 +1,212 @@ +/* +=========================================================================== +Copyright (C) 1999-2005 Id Software, Inc. + +This file is part of Quake III Arena source code. + +Quake III Arena source code is free software; you can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 2 of the License, +or (at your option) any later version. + +Quake III Arena source code is distributed in the hope that it will be +useful, but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Foobar; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ +// +/* +============================================================================= + +SAVE CONFIG MENU + +============================================================================= +*/ + +#include "ui_local.h" + + +#define ART_BACK0 "menu/art/back_0" +#define ART_BACK1 "menu/art/back_1" +#define ART_SAVE0 "menu/art/save_0" +#define ART_SAVE1 "menu/art/save_1" +#define ART_BACKGROUND "menu/art/cut_frame" + +#define ID_NAME 10 +#define ID_BACK 11 +#define ID_SAVE 12 + + +typedef struct { + menuframework_s menu; + + menutext_s banner; + menubitmap_s background; + menufield_s savename; + menubitmap_s back; + menubitmap_s save; +} saveConfig_t; + +static saveConfig_t saveConfig; + + +/* +=============== +UI_SaveConfigMenu_BackEvent +=============== +*/ +static void UI_SaveConfigMenu_BackEvent( void *ptr, int event ) { + if( event != QM_ACTIVATED ) { + return; + } + + UI_PopMenu(); +} + + +/* +=============== +UI_SaveConfigMenu_SaveEvent +=============== +*/ +static void UI_SaveConfigMenu_SaveEvent( void *ptr, int event ) { + char configname[MAX_QPATH]; + + if( event != QM_ACTIVATED ) { + return; + } + + if( !saveConfig.savename.field.buffer[0] ) { + return; + } + + COM_StripExtension(saveConfig.savename.field.buffer, configname ); + trap_Cmd_ExecuteText( EXEC_APPEND, va( "writeconfig %s.cfg\n", configname ) ); + UI_PopMenu(); +} + + +/* +=============== +UI_SaveConfigMenu_SavenameDraw +=============== +*/ +static void UI_SaveConfigMenu_SavenameDraw( void *self ) { + menufield_s *f; + int style; + float *color; + + f = (menufield_s *)self; + + if( f == Menu_ItemAtCursor( &saveConfig.menu ) ) { + style = UI_LEFT|UI_PULSE|UI_SMALLFONT; + color = text_color_highlight; + } + else { + style = UI_LEFT|UI_SMALLFONT; + color = colorRed; + } + + UI_DrawProportionalString( 320, 192, "Enter filename:", UI_CENTER|UI_SMALLFONT, color_orange ); + UI_FillRect( f->generic.x, f->generic.y, f->field.widthInChars*SMALLCHAR_WIDTH, SMALLCHAR_HEIGHT, colorBlack ); + MField_Draw( &f->field, f->generic.x, f->generic.y, style, color ); +} + + +/* +================= +UI_SaveConfigMenu_Init +================= +*/ +static void UI_SaveConfigMenu_Init( void ) { + memset( &saveConfig, 0, sizeof(saveConfig) ); + + UI_SaveConfigMenu_Cache(); + saveConfig.menu.wrapAround = qtrue; + saveConfig.menu.fullscreen = qtrue; + + saveConfig.banner.generic.type = MTYPE_BTEXT; + saveConfig.banner.generic.x = 320; + saveConfig.banner.generic.y = 16; + saveConfig.banner.string = "SAVE CONFIG"; + saveConfig.banner.color = color_white; + saveConfig.banner.style = UI_CENTER; + + saveConfig.background.generic.type = MTYPE_BITMAP; + saveConfig.background.generic.name = ART_BACKGROUND; + saveConfig.background.generic.flags = QMF_INACTIVE; + saveConfig.background.generic.x = 142; + saveConfig.background.generic.y = 118; + saveConfig.background.width = 359; + saveConfig.background.height = 256; + + saveConfig.savename.generic.type = MTYPE_FIELD; + saveConfig.savename.generic.flags = QMF_NODEFAULTINIT|QMF_UPPERCASE; + saveConfig.savename.generic.ownerdraw = UI_SaveConfigMenu_SavenameDraw; + saveConfig.savename.field.widthInChars = 20; + saveConfig.savename.field.maxchars = 20; + saveConfig.savename.generic.x = 240; + saveConfig.savename.generic.y = 155+72; + saveConfig.savename.generic.left = 240; + saveConfig.savename.generic.top = 155+72; + saveConfig.savename.generic.right = 233 + 20*SMALLCHAR_WIDTH; + saveConfig.savename.generic.bottom = 155+72 + SMALLCHAR_HEIGHT+2; + + saveConfig.back.generic.type = MTYPE_BITMAP; + saveConfig.back.generic.name = ART_BACK0; + saveConfig.back.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS; + saveConfig.back.generic.id = ID_BACK; + saveConfig.back.generic.callback = UI_SaveConfigMenu_BackEvent; + saveConfig.back.generic.x = 0; + saveConfig.back.generic.y = 480-64; + saveConfig.back.width = 128; + saveConfig.back.height = 64; + saveConfig.back.focuspic = ART_BACK1; + + saveConfig.save.generic.type = MTYPE_BITMAP; + saveConfig.save.generic.name = ART_SAVE0; + saveConfig.save.generic.flags = QMF_RIGHT_JUSTIFY|QMF_PULSEIFFOCUS; + saveConfig.save.generic.id = ID_SAVE; + saveConfig.save.generic.callback = UI_SaveConfigMenu_SaveEvent; + saveConfig.save.generic.x = 640; + saveConfig.save.generic.y = 480-64; + saveConfig.save.width = 128; + saveConfig.save.height = 64; + saveConfig.save.focuspic = ART_SAVE1; + + Menu_AddItem( &saveConfig.menu, &saveConfig.banner ); + Menu_AddItem( &saveConfig.menu, &saveConfig.background ); + Menu_AddItem( &saveConfig.menu, &saveConfig.savename ); + Menu_AddItem( &saveConfig.menu, &saveConfig.back ); + Menu_AddItem( &saveConfig.menu, &saveConfig.save ); +} + + +/* +================= +UI_SaveConfigMenu_Cache +================= +*/ +void UI_SaveConfigMenu_Cache( void ) { + trap_R_RegisterShaderNoMip( ART_BACK0 ); + trap_R_RegisterShaderNoMip( ART_BACK1 ); + trap_R_RegisterShaderNoMip( ART_SAVE0 ); + trap_R_RegisterShaderNoMip( ART_SAVE1 ); + trap_R_RegisterShaderNoMip( ART_BACKGROUND ); +} + + +/* +=============== +UI_SaveConfigMenu +=============== +*/ +void UI_SaveConfigMenu( void ) { + UI_SaveConfigMenu_Init(); + UI_PushMenu( &saveConfig.menu ); +} diff --git a/code/q3_ui/ui_serverinfo.c b/code/q3_ui/ui_serverinfo.c new file mode 100755 index 0000000..61f4ad8 --- /dev/null +++ b/code/q3_ui/ui_serverinfo.c @@ -0,0 +1,272 @@ +/* +=========================================================================== +Copyright (C) 1999-2005 Id Software, Inc. + +This file is part of Quake III Arena source code. + +Quake III Arena source code is free software; you can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 2 of the License, +or (at your option) any later version. + +Quake III Arena source code is distributed in the hope that it will be +useful, but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Foobar; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ +// +#include "ui_local.h" + +#define SERVERINFO_FRAMEL "menu/art/frame2_l" +#define SERVERINFO_FRAMER "menu/art/frame1_r" +#define SERVERINFO_BACK0 "menu/art/back_0" +#define SERVERINFO_BACK1 "menu/art/back_1" + +static char* serverinfo_artlist[] = +{ + SERVERINFO_FRAMEL, + SERVERINFO_FRAMER, + SERVERINFO_BACK0, + SERVERINFO_BACK1, + NULL +}; + +#define ID_ADD 100 +#define ID_BACK 101 + +typedef struct +{ + menuframework_s menu; + menutext_s banner; + menubitmap_s framel; + menubitmap_s framer; + menubitmap_s back; + menutext_s add; + char info[MAX_INFO_STRING]; + int numlines; +} serverinfo_t; + +static serverinfo_t s_serverinfo; + + +/* +================= +Favorites_Add + +Add current server to favorites +================= +*/ +void Favorites_Add( void ) +{ + char adrstr[128]; + char serverbuff[128]; + int i; + int best; + + trap_Cvar_VariableStringBuffer( "cl_currentServerAddress", serverbuff, sizeof(serverbuff) ); + if (!serverbuff[0]) + return; + + best = 0; + for (i=0; i '9' ) && !best) + best = i+1; + } + + if (best) + trap_Cvar_Set( va("server%d",best), serverbuff); +} + + +/* +================= +ServerInfo_Event +================= +*/ +static void ServerInfo_Event( void* ptr, int event ) +{ + switch (((menucommon_s*)ptr)->id) + { + case ID_ADD: + if (event != QM_ACTIVATED) + break; + + Favorites_Add(); + UI_PopMenu(); + break; + + case ID_BACK: + if (event != QM_ACTIVATED) + break; + + UI_PopMenu(); + break; + } +} + +/* +================= +ServerInfo_MenuDraw +================= +*/ +static void ServerInfo_MenuDraw( void ) +{ + const char *s; + char key[MAX_INFO_KEY]; + char value[MAX_INFO_VALUE]; + int y; + + y = SCREEN_HEIGHT/2 - s_serverinfo.numlines*(SMALLCHAR_HEIGHT)/2 - 20; + s = s_serverinfo.info; + while ( s ) { + Info_NextPair( &s, key, value ); + if ( !key[0] ) { + break; + } + + Q_strcat( key, MAX_INFO_KEY, ":" ); + + UI_DrawString(SCREEN_WIDTH*0.50 - 8,y,key,UI_RIGHT|UI_SMALLFONT,color_red); + UI_DrawString(SCREEN_WIDTH*0.50 + 8,y,value,UI_LEFT|UI_SMALLFONT,text_color_normal); + + y += SMALLCHAR_HEIGHT; + } + + Menu_Draw( &s_serverinfo.menu ); +} + +/* +================= +ServerInfo_MenuKey +================= +*/ +static sfxHandle_t ServerInfo_MenuKey( int key ) +{ + return ( Menu_DefaultKey( &s_serverinfo.menu, key ) ); +} + +/* +================= +ServerInfo_Cache +================= +*/ +void ServerInfo_Cache( void ) +{ + int i; + + // touch all our pics + for (i=0; ;i++) + { + if (!serverinfo_artlist[i]) + break; + trap_R_RegisterShaderNoMip(serverinfo_artlist[i]); + } +} + +/* +================= +UI_ServerInfoMenu +================= +*/ +void UI_ServerInfoMenu( void ) +{ + const char *s; + char key[MAX_INFO_KEY]; + char value[MAX_INFO_VALUE]; + + // zero set all our globals + memset( &s_serverinfo, 0 ,sizeof(serverinfo_t) ); + + ServerInfo_Cache(); + + s_serverinfo.menu.draw = ServerInfo_MenuDraw; + s_serverinfo.menu.key = ServerInfo_MenuKey; + s_serverinfo.menu.wrapAround = qtrue; + s_serverinfo.menu.fullscreen = qtrue; + + s_serverinfo.banner.generic.type = MTYPE_BTEXT; + s_serverinfo.banner.generic.x = 320; + s_serverinfo.banner.generic.y = 16; + s_serverinfo.banner.string = "SERVER INFO"; + s_serverinfo.banner.color = color_white; + s_serverinfo.banner.style = UI_CENTER; + + s_serverinfo.framel.generic.type = MTYPE_BITMAP; + s_serverinfo.framel.generic.name = SERVERINFO_FRAMEL; + s_serverinfo.framel.generic.flags = QMF_INACTIVE; + s_serverinfo.framel.generic.x = 0; + s_serverinfo.framel.generic.y = 78; + s_serverinfo.framel.width = 256; + s_serverinfo.framel.height = 329; + + s_serverinfo.framer.generic.type = MTYPE_BITMAP; + s_serverinfo.framer.generic.name = SERVERINFO_FRAMER; + s_serverinfo.framer.generic.flags = QMF_INACTIVE; + s_serverinfo.framer.generic.x = 376; + s_serverinfo.framer.generic.y = 76; + s_serverinfo.framer.width = 256; + s_serverinfo.framer.height = 334; + + s_serverinfo.add.generic.type = MTYPE_PTEXT; + s_serverinfo.add.generic.flags = QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS; + s_serverinfo.add.generic.callback = ServerInfo_Event; + s_serverinfo.add.generic.id = ID_ADD; + s_serverinfo.add.generic.x = 320; + s_serverinfo.add.generic.y = 371; + s_serverinfo.add.string = "ADD TO FAVORITES"; + s_serverinfo.add.style = UI_CENTER|UI_SMALLFONT; + s_serverinfo.add.color = color_red; + if( trap_Cvar_VariableValue( "sv_running" ) ) { + s_serverinfo.add.generic.flags |= QMF_GRAYED; + } + + s_serverinfo.back.generic.type = MTYPE_BITMAP; + s_serverinfo.back.generic.name = SERVERINFO_BACK0; + s_serverinfo.back.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS; + s_serverinfo.back.generic.callback = ServerInfo_Event; + s_serverinfo.back.generic.id = ID_BACK; + s_serverinfo.back.generic.x = 0; + s_serverinfo.back.generic.y = 480-64; + s_serverinfo.back.width = 128; + s_serverinfo.back.height = 64; + s_serverinfo.back.focuspic = SERVERINFO_BACK1; + + trap_GetConfigString( CS_SERVERINFO, s_serverinfo.info, MAX_INFO_STRING ); + + s_serverinfo.numlines = 0; + s = s_serverinfo.info; + while ( s ) { + Info_NextPair( &s, key, value ); + if ( !key[0] ) { + break; + } + s_serverinfo.numlines++; + } + + if (s_serverinfo.numlines > 16) + s_serverinfo.numlines = 16; + + Menu_AddItem( &s_serverinfo.menu, (void*) &s_serverinfo.banner ); + Menu_AddItem( &s_serverinfo.menu, (void*) &s_serverinfo.framel ); + Menu_AddItem( &s_serverinfo.menu, (void*) &s_serverinfo.framer ); + Menu_AddItem( &s_serverinfo.menu, (void*) &s_serverinfo.add ); + Menu_AddItem( &s_serverinfo.menu, (void*) &s_serverinfo.back ); + + UI_PushMenu( &s_serverinfo.menu ); +} + + diff --git a/code/q3_ui/ui_servers2.c b/code/q3_ui/ui_servers2.c new file mode 100755 index 0000000..d20fb6f --- /dev/null +++ b/code/q3_ui/ui_servers2.c @@ -0,0 +1,1640 @@ +/* +=========================================================================== +Copyright (C) 1999-2005 Id Software, Inc. + +This file is part of Quake III Arena source code. + +Quake III Arena source code is free software; you can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 2 of the License, +or (at your option) any later version. + +Quake III Arena source code is distributed in the hope that it will be +useful, but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Foobar; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ +// +/* +======================================================================= + +MULTIPLAYER MENU (SERVER BROWSER) + +======================================================================= +*/ + + +#include "ui_local.h" + + +#define MAX_GLOBALSERVERS 128 +#define MAX_PINGREQUESTS 32 +#define MAX_ADDRESSLENGTH 64 +#define MAX_HOSTNAMELENGTH 22 +#define MAX_MAPNAMELENGTH 16 +#define MAX_LISTBOXITEMS 128 +#define MAX_LOCALSERVERS 128 +#define MAX_STATUSLENGTH 64 +#define MAX_LEAGUELENGTH 28 +#define MAX_LISTBOXWIDTH 68 + +#define ART_BACK0 "menu/art/back_0" +#define ART_BACK1 "menu/art/back_1" +#define ART_CREATE0 "menu/art/create_0" +#define ART_CREATE1 "menu/art/create_1" +#define ART_SPECIFY0 "menu/art/specify_0" +#define ART_SPECIFY1 "menu/art/specify_1" +#define ART_REFRESH0 "menu/art/refresh_0" +#define ART_REFRESH1 "menu/art/refresh_1" +#define ART_CONNECT0 "menu/art/fight_0" +#define ART_CONNECT1 "menu/art/fight_1" +#define ART_ARROWS0 "menu/art/arrows_vert_0" +#define ART_ARROWS_UP "menu/art/arrows_vert_top" +#define ART_ARROWS_DOWN "menu/art/arrows_vert_bot" +#define ART_UNKNOWNMAP "menu/art/unknownmap" +#define ART_REMOVE0 "menu/art/delete_0" +#define ART_REMOVE1 "menu/art/delete_1" +#define ART_PUNKBUSTER "menu/art/pblogo" + +#define ID_MASTER 10 +#define ID_GAMETYPE 11 +#define ID_SORTKEY 12 +#define ID_SHOW_FULL 13 +#define ID_SHOW_EMPTY 14 +#define ID_LIST 15 +#define ID_SCROLL_UP 16 +#define ID_SCROLL_DOWN 17 +#define ID_BACK 18 +#define ID_REFRESH 19 +#define ID_SPECIFY 20 +#define ID_CREATE 21 +#define ID_CONNECT 22 +#define ID_REMOVE 23 +#define ID_PUNKBUSTER 24 + +#define GR_LOGO 30 +#define GR_LETTERS 31 + +#define AS_LOCAL 0 +#define AS_MPLAYER 1 +#define AS_GLOBAL 2 +#define AS_FAVORITES 3 + +#define SORT_HOST 0 +#define SORT_MAP 1 +#define SORT_CLIENTS 2 +#define SORT_GAME 3 +#define SORT_PING 4 + +#define GAMES_ALL 0 +#define GAMES_FFA 1 +#define GAMES_TEAMPLAY 2 +#define GAMES_TOURNEY 3 +#define GAMES_CTF 4 + +static const char *master_items[] = { + "Local", + "Internet", + "Favorites", + 0 +}; + +static const char *servertype_items[] = { + "All", + "Free For All", + "Team Deathmatch", + "Tournament", + "Capture the Flag", + 0 +}; + +static const char *sortkey_items[] = { + "Server Name", + "Map Name", + "Open Player Spots", + "Game Type", + "Ping Time", + 0 +}; + +static char* gamenames[] = { + "DM ", // deathmatch + "1v1", // tournament + "SP ", // single player + "Team DM", // team deathmatch + "CTF", // capture the flag + "One Flag CTF", // one flag ctf + "OverLoad", // Overload + "Harvester", // Harvester + "Rocket Arena 3", // Rocket Arena 3 + "Q3F", // Q3F + "Urban Terror", // Urban Terror + "OSP", // Orange Smoothie Productions + "???", // unknown + 0 +}; + +static char* netnames[] = { + "???", + "UDP", + "IPX", + NULL +}; + +static char quake3worldMessage[] = "Visit www.quake3world.com - News, Community, Events, Files"; + +const char* punkbuster_items[] = { + "Disabled", + "Enabled", + NULL +}; + +const char* punkbuster_msg[] = { + "PunkBuster will be", + "disabled the next time", + "Quake III Arena", + "is started.", + NULL +}; + +typedef struct { + char adrstr[MAX_ADDRESSLENGTH]; + int start; +} pinglist_t; + +typedef struct servernode_s { + char adrstr[MAX_ADDRESSLENGTH]; + char hostname[MAX_HOSTNAMELENGTH+3]; + char mapname[MAX_MAPNAMELENGTH]; + int numclients; + int maxclients; + int pingtime; + int gametype; + char gamename[12]; + int nettype; + int minPing; + int maxPing; + qboolean bPB; + +} servernode_t; + +typedef struct { + char buff[MAX_LISTBOXWIDTH]; + servernode_t* servernode; +} table_t; + +typedef struct { + menuframework_s menu; + + menutext_s banner; + + menulist_s master; + menulist_s gametype; + menulist_s sortkey; + menuradiobutton_s showfull; + menuradiobutton_s showempty; + + menulist_s list; + menubitmap_s mappic; + menubitmap_s arrows; + menubitmap_s up; + menubitmap_s down; + menutext_s status; + menutext_s statusbar; + + menubitmap_s remove; + menubitmap_s back; + menubitmap_s refresh; + menubitmap_s specify; + menubitmap_s create; + menubitmap_s go; + + pinglist_t pinglist[MAX_PINGREQUESTS]; + table_t table[MAX_LISTBOXITEMS]; + char* items[MAX_LISTBOXITEMS]; + int numqueriedservers; + int *numservers; + servernode_t *serverlist; + int currentping; + qboolean refreshservers; + int nextpingtime; + int maxservers; + int refreshtime; + char favoriteaddresses[MAX_FAVORITESERVERS][MAX_ADDRESSLENGTH]; + int numfavoriteaddresses; + + menulist_s punkbuster; + menubitmap_s pblogo; +} arenaservers_t; + +static arenaservers_t g_arenaservers; + + +static servernode_t g_globalserverlist[MAX_GLOBALSERVERS]; +static int g_numglobalservers; +static servernode_t g_localserverlist[MAX_LOCALSERVERS]; +static int g_numlocalservers; +static servernode_t g_favoriteserverlist[MAX_FAVORITESERVERS]; +static int g_numfavoriteservers; +static servernode_t g_mplayerserverlist[MAX_GLOBALSERVERS]; +static int g_nummplayerservers; +static int g_servertype; +static int g_gametype; +static int g_sortkey; +static int g_emptyservers; +static int g_fullservers; + + +/* +================= +ArenaServers_MaxPing +================= +*/ +static int ArenaServers_MaxPing( void ) { + int maxPing; + + maxPing = (int)trap_Cvar_VariableValue( "cl_maxPing" ); + if( maxPing < 100 ) { + maxPing = 100; + } + return maxPing; +} + + +/* +================= +ArenaServers_Compare +================= +*/ +static int QDECL ArenaServers_Compare( const void *arg1, const void *arg2 ) { + float f1; + float f2; + servernode_t* t1; + servernode_t* t2; + + t1 = (servernode_t *)arg1; + t2 = (servernode_t *)arg2; + + switch( g_sortkey ) { + case SORT_HOST: + return Q_stricmp( t1->hostname, t2->hostname ); + + case SORT_MAP: + return Q_stricmp( t1->mapname, t2->mapname ); + + case SORT_CLIENTS: + f1 = t1->maxclients - t1->numclients; + if( f1 < 0 ) { + f1 = 0; + } + + f2 = t2->maxclients - t2->numclients; + if( f2 < 0 ) { + f2 = 0; + } + + if( f1 < f2 ) { + return 1; + } + if( f1 == f2 ) { + return 0; + } + return -1; + + case SORT_GAME: + if( t1->gametype < t2->gametype ) { + return -1; + } + if( t1->gametype == t2->gametype ) { + return 0; + } + return 1; + + case SORT_PING: + if( t1->pingtime < t2->pingtime ) { + return -1; + } + if( t1->pingtime > t2->pingtime ) { + return 1; + } + return Q_stricmp( t1->hostname, t2->hostname ); + } + + return 0; +} + + +/* +================= +ArenaServers_Go +================= +*/ +static void ArenaServers_Go( void ) { + servernode_t* servernode; + + servernode = g_arenaservers.table[g_arenaservers.list.curvalue].servernode; + if( servernode ) { + trap_Cmd_ExecuteText( EXEC_APPEND, va( "connect %s\n", servernode->adrstr ) ); + } +} + + +/* +================= +ArenaServers_UpdatePicture +================= +*/ +static void ArenaServers_UpdatePicture( void ) { + static char picname[64]; + servernode_t* servernodeptr; + + if( !g_arenaservers.list.numitems ) { + g_arenaservers.mappic.generic.name = NULL; + } + else { + servernodeptr = g_arenaservers.table[g_arenaservers.list.curvalue].servernode; + Com_sprintf( picname, sizeof(picname), "levelshots/%s.tga", servernodeptr->mapname ); + g_arenaservers.mappic.generic.name = picname; + + } + + // force shader update during draw + g_arenaservers.mappic.shader = 0; +} + + +/* +================= +ArenaServers_UpdateMenu +================= +*/ +static void ArenaServers_UpdateMenu( void ) { + int i; + int j; + int count; + char* buff; + servernode_t* servernodeptr; + table_t* tableptr; + char *pingColor; + + if( g_arenaservers.numqueriedservers > 0 ) { + // servers found + if( g_arenaservers.refreshservers && ( g_arenaservers.currentping <= g_arenaservers.numqueriedservers ) ) { + // show progress + Com_sprintf( g_arenaservers.status.string, MAX_STATUSLENGTH, "%d of %d Arena Servers.", g_arenaservers.currentping, g_arenaservers.numqueriedservers); + g_arenaservers.statusbar.string = "Press SPACE to stop"; + qsort( g_arenaservers.serverlist, *g_arenaservers.numservers, sizeof( servernode_t ), ArenaServers_Compare); + } + else { + // all servers pinged - enable controls + g_arenaservers.master.generic.flags &= ~QMF_GRAYED; + g_arenaservers.gametype.generic.flags &= ~QMF_GRAYED; + g_arenaservers.sortkey.generic.flags &= ~QMF_GRAYED; + g_arenaservers.showempty.generic.flags &= ~QMF_GRAYED; + g_arenaservers.showfull.generic.flags &= ~QMF_GRAYED; + g_arenaservers.list.generic.flags &= ~QMF_GRAYED; + g_arenaservers.refresh.generic.flags &= ~QMF_GRAYED; + g_arenaservers.go.generic.flags &= ~QMF_GRAYED; + g_arenaservers.punkbuster.generic.flags &= ~QMF_GRAYED; + + // update status bar + if( g_servertype == AS_GLOBAL || g_servertype == AS_MPLAYER ) { + g_arenaservers.statusbar.string = quake3worldMessage; + } + else { + g_arenaservers.statusbar.string = ""; + } + + } + } + else { + // no servers found + if( g_arenaservers.refreshservers ) { + strcpy( g_arenaservers.status.string,"Scanning For Servers." ); + g_arenaservers.statusbar.string = "Press SPACE to stop"; + + // disable controls during refresh + g_arenaservers.master.generic.flags |= QMF_GRAYED; + g_arenaservers.gametype.generic.flags |= QMF_GRAYED; + g_arenaservers.sortkey.generic.flags |= QMF_GRAYED; + g_arenaservers.showempty.generic.flags |= QMF_GRAYED; + g_arenaservers.showfull.generic.flags |= QMF_GRAYED; + g_arenaservers.list.generic.flags |= QMF_GRAYED; + g_arenaservers.refresh.generic.flags |= QMF_GRAYED; + g_arenaservers.go.generic.flags |= QMF_GRAYED; + g_arenaservers.punkbuster.generic.flags |= QMF_GRAYED; + } + else { + if( g_arenaservers.numqueriedservers < 0 ) { + strcpy(g_arenaservers.status.string,"No Response From Master Server." ); + } + else { + strcpy(g_arenaservers.status.string,"No Servers Found." ); + } + + // update status bar + if( g_servertype == AS_GLOBAL || g_servertype == AS_MPLAYER ) { + g_arenaservers.statusbar.string = quake3worldMessage; + } + else { + g_arenaservers.statusbar.string = ""; + } + + // end of refresh - set control state + g_arenaservers.master.generic.flags &= ~QMF_GRAYED; + g_arenaservers.gametype.generic.flags &= ~QMF_GRAYED; + g_arenaservers.sortkey.generic.flags &= ~QMF_GRAYED; + g_arenaservers.showempty.generic.flags &= ~QMF_GRAYED; + g_arenaservers.showfull.generic.flags &= ~QMF_GRAYED; + g_arenaservers.list.generic.flags |= QMF_GRAYED; + g_arenaservers.refresh.generic.flags &= ~QMF_GRAYED; + g_arenaservers.go.generic.flags |= QMF_GRAYED; + g_arenaservers.punkbuster.generic.flags &= ~QMF_GRAYED; + } + + // zero out list box + g_arenaservers.list.numitems = 0; + g_arenaservers.list.curvalue = 0; + g_arenaservers.list.top = 0; + + // update picture + ArenaServers_UpdatePicture(); + return; + } + + // build list box strings - apply culling filters + servernodeptr = g_arenaservers.serverlist; + count = *g_arenaservers.numservers; + for( i = 0, j = 0; i < count; i++, servernodeptr++ ) { + tableptr = &g_arenaservers.table[j]; + tableptr->servernode = servernodeptr; + buff = tableptr->buff; + + // can only cull valid results + if( !g_emptyservers && !servernodeptr->numclients ) { + continue; + } + + if( !g_fullservers && ( servernodeptr->numclients == servernodeptr->maxclients ) ) { + continue; + } + + switch( g_gametype ) { + case GAMES_ALL: + break; + + case GAMES_FFA: + if( servernodeptr->gametype != GT_FFA ) { + continue; + } + break; + + case GAMES_TEAMPLAY: + if( servernodeptr->gametype != GT_TEAM ) { + continue; + } + break; + + case GAMES_TOURNEY: + if( servernodeptr->gametype != GT_TOURNAMENT ) { + continue; + } + break; + + case GAMES_CTF: + if( servernodeptr->gametype != GT_CTF ) { + continue; + } + break; + } + + if( servernodeptr->pingtime < servernodeptr->minPing ) { + pingColor = S_COLOR_BLUE; + } + else if( servernodeptr->maxPing && servernodeptr->pingtime > servernodeptr->maxPing ) { + pingColor = S_COLOR_BLUE; + } + else if( servernodeptr->pingtime < 200 ) { + pingColor = S_COLOR_GREEN; + } + else if( servernodeptr->pingtime < 400 ) { + pingColor = S_COLOR_YELLOW; + } + else { + pingColor = S_COLOR_RED; + } + + Com_sprintf( buff, MAX_LISTBOXWIDTH, "%-20.20s %-12.12s %2d/%2d %-8.8s %3s %s%3d " S_COLOR_YELLOW "%s", + servernodeptr->hostname, servernodeptr->mapname, servernodeptr->numclients, + servernodeptr->maxclients, servernodeptr->gamename, + netnames[servernodeptr->nettype], pingColor, servernodeptr->pingtime, servernodeptr->bPB ? "Yes" : "No" ); + j++; + } + + g_arenaservers.list.numitems = j; + g_arenaservers.list.curvalue = 0; + g_arenaservers.list.top = 0; + + // update picture + ArenaServers_UpdatePicture(); +} + + +/* +================= +ArenaServers_Remove +================= +*/ +static void ArenaServers_Remove( void ) +{ + int i; + servernode_t* servernodeptr; + table_t* tableptr; + + if (!g_arenaservers.list.numitems) + return; + + // remove selected item from display list + // items are in scattered order due to sort and cull + // perform delete on list box contents, resync all lists + + tableptr = &g_arenaservers.table[g_arenaservers.list.curvalue]; + servernodeptr = tableptr->servernode; + + // find address in master list + for (i=0; iadrstr)) + break; + + // delete address from master list + if (i <= g_arenaservers.numfavoriteaddresses-1) + { + if (i < g_arenaservers.numfavoriteaddresses-1) + { + // shift items up + memcpy( &g_arenaservers.favoriteaddresses[i], &g_arenaservers.favoriteaddresses[i+1], (g_arenaservers.numfavoriteaddresses - i - 1)*sizeof(MAX_ADDRESSLENGTH)); + } + g_arenaservers.numfavoriteaddresses--; + } + + // find address in server list + for (i=0; i= ArenaServers_MaxPing()) && (g_servertype != AS_FAVORITES)) + { + // slow global or local servers do not get entered + return; + } + + if (*g_arenaservers.numservers >= g_arenaservers.maxservers) { + // list full; + servernodeptr = g_arenaservers.serverlist+(*g_arenaservers.numservers)-1; + } else { + // next slot + servernodeptr = g_arenaservers.serverlist+(*g_arenaservers.numservers); + (*g_arenaservers.numservers)++; + } + + Q_strncpyz( servernodeptr->adrstr, adrstr, MAX_ADDRESSLENGTH ); + + Q_strncpyz( servernodeptr->hostname, Info_ValueForKey( info, "hostname"), MAX_HOSTNAMELENGTH ); + Q_CleanStr( servernodeptr->hostname ); + Q_strupr( servernodeptr->hostname ); + + Q_strncpyz( servernodeptr->mapname, Info_ValueForKey( info, "mapname"), MAX_MAPNAMELENGTH ); + Q_CleanStr( servernodeptr->mapname ); + Q_strupr( servernodeptr->mapname ); + + servernodeptr->numclients = atoi( Info_ValueForKey( info, "clients") ); + servernodeptr->maxclients = atoi( Info_ValueForKey( info, "sv_maxclients") ); + servernodeptr->pingtime = pingtime; + servernodeptr->minPing = atoi( Info_ValueForKey( info, "minPing") ); + servernodeptr->maxPing = atoi( Info_ValueForKey( info, "maxPing") ); + servernodeptr->bPB = atoi( Info_ValueForKey( info, "punkbuster") ); + + /* + s = Info_ValueForKey( info, "nettype" ); + for (i=0; ;i++) + { + if (!netnames[i]) + { + servernodeptr->nettype = 0; + break; + } + else if (!Q_stricmp( netnames[i], s )) + { + servernodeptr->nettype = i; + break; + } + } + */ + servernodeptr->nettype = atoi(Info_ValueForKey(info, "nettype")); + + s = Info_ValueForKey( info, "game"); + i = atoi( Info_ValueForKey( info, "gametype") ); + if( i < 0 ) { + i = 0; + } + else if( i > 11 ) { + i = 12; + } + if( *s ) { + servernodeptr->gametype = i;//-1; + Q_strncpyz( servernodeptr->gamename, s, sizeof(servernodeptr->gamename) ); + } + else { + servernodeptr->gametype = i; + Q_strncpyz( servernodeptr->gamename, gamenames[i], sizeof(servernodeptr->gamename) ); + } +} + + +/* +================= +ArenaServers_InsertFavorites + +Insert nonresponsive address book entries into display lists. +================= +*/ +void ArenaServers_InsertFavorites( void ) +{ + int i; + int j; + char info[MAX_INFO_STRING]; + + // resync existing results with new or deleted cvars + info[0] = '\0'; + Info_SetValueForKey( info, "hostname", "No Response" ); + for (i=0; i= g_numfavoriteservers) + { + // not in list, add it + ArenaServers_Insert( g_arenaservers.favoriteaddresses[i], info, ArenaServers_MaxPing() ); + } + } +} + + +/* +================= +ArenaServers_LoadFavorites + +Load cvar address book entries into local lists. +================= +*/ +void ArenaServers_LoadFavorites( void ) +{ + int i; + int j; + int numtempitems; + char emptyinfo[MAX_INFO_STRING]; + char adrstr[MAX_ADDRESSLENGTH]; + servernode_t templist[MAX_FAVORITESERVERS]; + qboolean found; + + found = qfalse; + emptyinfo[0] = '\0'; + + // copy the old + memcpy( templist, g_favoriteserverlist, sizeof(servernode_t)*MAX_FAVORITESERVERS ); + numtempitems = g_numfavoriteservers; + + // clear the current for sync + memset( g_favoriteserverlist, 0, sizeof(servernode_t)*MAX_FAVORITESERVERS ); + g_numfavoriteservers = 0; + + // resync existing results with new or deleted cvars + for (i=0; i '9') + continue; + + // favorite server addresses must be maintained outside refresh list + // this mimics local and global netadr's stored in client + // these can be fetched to fill ping list + strcpy( g_arenaservers.favoriteaddresses[g_numfavoriteservers], adrstr ); + + // find this server in the old list + for (j=0; j= 0) + { + g_arenaservers.currentping = *g_arenaservers.numservers; + g_arenaservers.numqueriedservers = *g_arenaservers.numservers; + } + + // sort + qsort( g_arenaservers.serverlist, *g_arenaservers.numservers, sizeof( servernode_t ), ArenaServers_Compare); + + ArenaServers_UpdateMenu(); +} + + +/* +================= +ArenaServers_DoRefresh +================= +*/ +static void ArenaServers_DoRefresh( void ) +{ + int i; + int j; + int time; + int maxPing; + char adrstr[MAX_ADDRESSLENGTH]; + char info[MAX_INFO_STRING]; + + if (uis.realtime < g_arenaservers.refreshtime) + { + if (g_servertype != AS_FAVORITES) { + if (g_servertype == AS_LOCAL) { + if (!trap_LAN_GetServerCount(g_servertype)) { + return; + } + } + if (trap_LAN_GetServerCount(g_servertype) < 0) { + // still waiting for response + return; + } + } + } + + if (uis.realtime < g_arenaservers.nextpingtime) + { + // wait for time trigger + return; + } + + // trigger at 10Hz intervals + g_arenaservers.nextpingtime = uis.realtime + 10; + + // process ping results + maxPing = ArenaServers_MaxPing(); + for (i=0; i maxPing) + { + // stale it out + info[0] = '\0'; + time = maxPing; + } + else + { + trap_LAN_GetPingInfo( i, info, MAX_INFO_STRING ); + } + + // insert ping results + ArenaServers_Insert( adrstr, info, time ); + + // clear this query from internal list + g_arenaservers.pinglist[j].adrstr[0] = '\0'; + } + + // clear this query from external list + trap_LAN_ClearPing( i ); + } + + // get results of servers query + // counts can increase as servers respond + if (g_servertype == AS_FAVORITES) { + g_arenaservers.numqueriedservers = g_arenaservers.numfavoriteaddresses; + } else { + g_arenaservers.numqueriedservers = trap_LAN_GetServerCount(g_servertype); + } + +// if (g_arenaservers.numqueriedservers > g_arenaservers.maxservers) +// g_arenaservers.numqueriedservers = g_arenaservers.maxservers; + + // send ping requests in reasonable bursts + // iterate ping through all found servers + for (i=0; i= MAX_PINGREQUESTS) + { + // ping queue is full + break; + } + + // find empty slot + for (j=0; j= MAX_PINGREQUESTS) + // no empty slots available yet - wait for timeout + break; + + // get an address to ping + + if (g_servertype == AS_FAVORITES) { + strcpy( adrstr, g_arenaservers.favoriteaddresses[g_arenaservers.currentping] ); + } else { + trap_LAN_GetServerAddressString(g_servertype, g_arenaservers.currentping, adrstr, MAX_ADDRESSLENGTH ); + } + + strcpy( g_arenaservers.pinglist[j].adrstr, adrstr ); + g_arenaservers.pinglist[j].start = uis.realtime; + + trap_Cmd_ExecuteText( EXEC_NOW, va( "ping %s\n", adrstr ) ); + + // advance to next server + g_arenaservers.currentping++; + } + + if (!trap_LAN_GetPingQueueCount()) + { + // all pings completed + ArenaServers_StopRefresh(); + return; + } + + // update the user interface with ping status + ArenaServers_UpdateMenu(); +} + + +/* +================= +ArenaServers_StartRefresh +================= +*/ +static void ArenaServers_StartRefresh( void ) +{ + int i; + char myargs[32], protocol[32]; + + memset( g_arenaservers.serverlist, 0, g_arenaservers.maxservers*sizeof(table_t) ); + + for (i=0; iid; + + if( event != QM_ACTIVATED && id != ID_LIST ) { + return; + } + + switch( id ) { + case ID_MASTER: + value = g_arenaservers.master.curvalue; + if (value >= 1) + { + value++; + } + trap_Cvar_SetValue( "ui_browserMaster", value ); + ArenaServers_SetType( value ); + break; + + case ID_GAMETYPE: + trap_Cvar_SetValue( "ui_browserGameType", g_arenaservers.gametype.curvalue ); + g_gametype = g_arenaservers.gametype.curvalue; + ArenaServers_UpdateMenu(); + break; + + case ID_SORTKEY: + trap_Cvar_SetValue( "ui_browserSortKey", g_arenaservers.sortkey.curvalue ); + ArenaServers_Sort( g_arenaservers.sortkey.curvalue ); + ArenaServers_UpdateMenu(); + break; + + case ID_SHOW_FULL: + trap_Cvar_SetValue( "ui_browserShowFull", g_arenaservers.showfull.curvalue ); + g_fullservers = g_arenaservers.showfull.curvalue; + ArenaServers_UpdateMenu(); + break; + + case ID_SHOW_EMPTY: + trap_Cvar_SetValue( "ui_browserShowEmpty", g_arenaservers.showempty.curvalue ); + g_emptyservers = g_arenaservers.showempty.curvalue; + ArenaServers_UpdateMenu(); + break; + + case ID_LIST: + if( event == QM_GOTFOCUS ) { + ArenaServers_UpdatePicture(); + } + break; + + case ID_SCROLL_UP: + ScrollList_Key( &g_arenaservers.list, K_UPARROW ); + break; + + case ID_SCROLL_DOWN: + ScrollList_Key( &g_arenaservers.list, K_DOWNARROW ); + break; + + case ID_BACK: + ArenaServers_StopRefresh(); + ArenaServers_SaveChanges(); + UI_PopMenu(); + break; + + case ID_REFRESH: + ArenaServers_StartRefresh(); + break; + + case ID_SPECIFY: + UI_SpecifyServerMenu(); + break; + + case ID_CREATE: + UI_StartServerMenu( qtrue ); + break; + + case ID_CONNECT: + ArenaServers_Go(); + break; + + case ID_REMOVE: + ArenaServers_Remove(); + ArenaServers_UpdateMenu(); + break; + + case ID_PUNKBUSTER: + if (g_arenaservers.punkbuster.curvalue) + { + UI_ConfirmMenu_Style( "Enable Punkbuster?", UI_CENTER|UI_INVERSE|UI_SMALLFONT, (voidfunc_f)NULL, Punkbuster_ConfirmEnable ); + } + else + { + UI_ConfirmMenu_Style( "Disable Punkbuster?", UI_CENTER|UI_INVERSE|UI_SMALLFONT, (voidfunc_f)NULL, Punkbuster_ConfirmDisable ); + } + break; + } +} + + +/* +================= +ArenaServers_MenuDraw +================= +*/ +static void ArenaServers_MenuDraw( void ) +{ + if (g_arenaservers.refreshservers) + ArenaServers_DoRefresh(); + + Menu_Draw( &g_arenaservers.menu ); +} + + +/* +================= +ArenaServers_MenuKey +================= +*/ +static sfxHandle_t ArenaServers_MenuKey( int key ) { + if( key == K_SPACE && g_arenaservers.refreshservers ) { + ArenaServers_StopRefresh(); + return menu_move_sound; + } + + if( ( key == K_DEL || key == K_KP_DEL ) && ( g_servertype == AS_FAVORITES ) && + ( Menu_ItemAtCursor( &g_arenaservers.menu) == &g_arenaservers.list ) ) { + ArenaServers_Remove(); + ArenaServers_UpdateMenu(); + return menu_move_sound; + } + + if( key == K_MOUSE2 || key == K_ESCAPE ) { + ArenaServers_StopRefresh(); + ArenaServers_SaveChanges(); + } + + + return Menu_DefaultKey( &g_arenaservers.menu, key ); +} + + +/* +================= +ArenaServers_MenuInit +================= +*/ +static void ArenaServers_MenuInit( void ) { + int i; + int type; + int y; + int value; + static char statusbuffer[MAX_STATUSLENGTH]; + + // zero set all our globals + memset( &g_arenaservers, 0 ,sizeof(arenaservers_t) ); + + ArenaServers_Cache(); + + g_arenaservers.menu.fullscreen = qtrue; + g_arenaservers.menu.wrapAround = qtrue; + g_arenaservers.menu.draw = ArenaServers_MenuDraw; + g_arenaservers.menu.key = ArenaServers_MenuKey; + + g_arenaservers.banner.generic.type = MTYPE_BTEXT; + g_arenaservers.banner.generic.flags = QMF_CENTER_JUSTIFY; + g_arenaservers.banner.generic.x = 320; + g_arenaservers.banner.generic.y = 16; + g_arenaservers.banner.string = "ARENA SERVERS"; + g_arenaservers.banner.style = UI_CENTER; + g_arenaservers.banner.color = color_white; + + y = 80; + g_arenaservers.master.generic.type = MTYPE_SPINCONTROL; + g_arenaservers.master.generic.name = "Servers:"; + g_arenaservers.master.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT; + g_arenaservers.master.generic.callback = ArenaServers_Event; + g_arenaservers.master.generic.id = ID_MASTER; + g_arenaservers.master.generic.x = 320; + g_arenaservers.master.generic.y = y; + g_arenaservers.master.itemnames = master_items; + + y += SMALLCHAR_HEIGHT; + g_arenaservers.gametype.generic.type = MTYPE_SPINCONTROL; + g_arenaservers.gametype.generic.name = "Game Type:"; + g_arenaservers.gametype.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT; + g_arenaservers.gametype.generic.callback = ArenaServers_Event; + g_arenaservers.gametype.generic.id = ID_GAMETYPE; + g_arenaservers.gametype.generic.x = 320; + g_arenaservers.gametype.generic.y = y; + g_arenaservers.gametype.itemnames = servertype_items; + + y += SMALLCHAR_HEIGHT; + g_arenaservers.sortkey.generic.type = MTYPE_SPINCONTROL; + g_arenaservers.sortkey.generic.name = "Sort By:"; + g_arenaservers.sortkey.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT; + g_arenaservers.sortkey.generic.callback = ArenaServers_Event; + g_arenaservers.sortkey.generic.id = ID_SORTKEY; + g_arenaservers.sortkey.generic.x = 320; + g_arenaservers.sortkey.generic.y = y; + g_arenaservers.sortkey.itemnames = sortkey_items; + + y += SMALLCHAR_HEIGHT; + g_arenaservers.showfull.generic.type = MTYPE_RADIOBUTTON; + g_arenaservers.showfull.generic.name = "Show Full:"; + g_arenaservers.showfull.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT; + g_arenaservers.showfull.generic.callback = ArenaServers_Event; + g_arenaservers.showfull.generic.id = ID_SHOW_FULL; + g_arenaservers.showfull.generic.x = 320; + g_arenaservers.showfull.generic.y = y; + + y += SMALLCHAR_HEIGHT; + g_arenaservers.showempty.generic.type = MTYPE_RADIOBUTTON; + g_arenaservers.showempty.generic.name = "Show Empty:"; + g_arenaservers.showempty.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT; + g_arenaservers.showempty.generic.callback = ArenaServers_Event; + g_arenaservers.showempty.generic.id = ID_SHOW_EMPTY; + g_arenaservers.showempty.generic.x = 320; + g_arenaservers.showempty.generic.y = y; + + y += 3 * SMALLCHAR_HEIGHT; + g_arenaservers.list.generic.type = MTYPE_SCROLLLIST; + g_arenaservers.list.generic.flags = QMF_HIGHLIGHT_IF_FOCUS; + g_arenaservers.list.generic.id = ID_LIST; + g_arenaservers.list.generic.callback = ArenaServers_Event; + g_arenaservers.list.generic.x = 72; + g_arenaservers.list.generic.y = y; + g_arenaservers.list.width = MAX_LISTBOXWIDTH; + g_arenaservers.list.height = 11; + g_arenaservers.list.itemnames = (const char **)g_arenaservers.items; + for( i = 0; i < MAX_LISTBOXITEMS; i++ ) { + g_arenaservers.items[i] = g_arenaservers.table[i].buff; + } + + g_arenaservers.mappic.generic.type = MTYPE_BITMAP; + g_arenaservers.mappic.generic.flags = QMF_LEFT_JUSTIFY|QMF_INACTIVE; + g_arenaservers.mappic.generic.x = 72; + g_arenaservers.mappic.generic.y = 80; + g_arenaservers.mappic.width = 128; + g_arenaservers.mappic.height = 96; + g_arenaservers.mappic.errorpic = ART_UNKNOWNMAP; + + g_arenaservers.arrows.generic.type = MTYPE_BITMAP; + g_arenaservers.arrows.generic.name = ART_ARROWS0; + g_arenaservers.arrows.generic.flags = QMF_LEFT_JUSTIFY|QMF_INACTIVE; + g_arenaservers.arrows.generic.callback = ArenaServers_Event; + g_arenaservers.arrows.generic.x = 512+48; + g_arenaservers.arrows.generic.y = 240-64+16; + g_arenaservers.arrows.width = 64; + g_arenaservers.arrows.height = 128; + + g_arenaservers.up.generic.type = MTYPE_BITMAP; + g_arenaservers.up.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_MOUSEONLY; + g_arenaservers.up.generic.callback = ArenaServers_Event; + g_arenaservers.up.generic.id = ID_SCROLL_UP; + g_arenaservers.up.generic.x = 512+48; + g_arenaservers.up.generic.y = 240-64+16; + g_arenaservers.up.width = 64; + g_arenaservers.up.height = 64; + g_arenaservers.up.focuspic = ART_ARROWS_UP; + + g_arenaservers.down.generic.type = MTYPE_BITMAP; + g_arenaservers.down.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_MOUSEONLY; + g_arenaservers.down.generic.callback = ArenaServers_Event; + g_arenaservers.down.generic.id = ID_SCROLL_DOWN; + g_arenaservers.down.generic.x = 512+48; + g_arenaservers.down.generic.y = 240+16; + g_arenaservers.down.width = 64; + g_arenaservers.down.height = 64; + g_arenaservers.down.focuspic = ART_ARROWS_DOWN; + + y = 376; + g_arenaservers.status.generic.type = MTYPE_TEXT; + g_arenaservers.status.generic.x = 320; + g_arenaservers.status.generic.y = y; + g_arenaservers.status.string = statusbuffer; + g_arenaservers.status.style = UI_CENTER|UI_SMALLFONT; + g_arenaservers.status.color = menu_text_color; + + y += SMALLCHAR_HEIGHT; + g_arenaservers.statusbar.generic.type = MTYPE_TEXT; + g_arenaservers.statusbar.generic.x = 320; + g_arenaservers.statusbar.generic.y = y; + g_arenaservers.statusbar.string = ""; + g_arenaservers.statusbar.style = UI_CENTER|UI_SMALLFONT; + g_arenaservers.statusbar.color = text_color_normal; + + g_arenaservers.remove.generic.type = MTYPE_BITMAP; + g_arenaservers.remove.generic.name = ART_REMOVE0; + g_arenaservers.remove.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS; + g_arenaservers.remove.generic.callback = ArenaServers_Event; + g_arenaservers.remove.generic.id = ID_REMOVE; + g_arenaservers.remove.generic.x = 450; + g_arenaservers.remove.generic.y = 86; + g_arenaservers.remove.width = 96; + g_arenaservers.remove.height = 48; + g_arenaservers.remove.focuspic = ART_REMOVE1; + + g_arenaservers.back.generic.type = MTYPE_BITMAP; + g_arenaservers.back.generic.name = ART_BACK0; + g_arenaservers.back.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS; + g_arenaservers.back.generic.callback = ArenaServers_Event; + g_arenaservers.back.generic.id = ID_BACK; + g_arenaservers.back.generic.x = 0; + g_arenaservers.back.generic.y = 480-64; + g_arenaservers.back.width = 128; + g_arenaservers.back.height = 64; + g_arenaservers.back.focuspic = ART_BACK1; + + g_arenaservers.specify.generic.type = MTYPE_BITMAP; + g_arenaservers.specify.generic.name = ART_SPECIFY0; + g_arenaservers.specify.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS; + g_arenaservers.specify.generic.callback = ArenaServers_Event; + g_arenaservers.specify.generic.id = ID_SPECIFY; + g_arenaservers.specify.generic.x = 128; + g_arenaservers.specify.generic.y = 480-64; + g_arenaservers.specify.width = 128; + g_arenaservers.specify.height = 64; + g_arenaservers.specify.focuspic = ART_SPECIFY1; + + g_arenaservers.refresh.generic.type = MTYPE_BITMAP; + g_arenaservers.refresh.generic.name = ART_REFRESH0; + g_arenaservers.refresh.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS; + g_arenaservers.refresh.generic.callback = ArenaServers_Event; + g_arenaservers.refresh.generic.id = ID_REFRESH; + g_arenaservers.refresh.generic.x = 256; + g_arenaservers.refresh.generic.y = 480-64; + g_arenaservers.refresh.width = 128; + g_arenaservers.refresh.height = 64; + g_arenaservers.refresh.focuspic = ART_REFRESH1; + + g_arenaservers.create.generic.type = MTYPE_BITMAP; + g_arenaservers.create.generic.name = ART_CREATE0; + g_arenaservers.create.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS; + g_arenaservers.create.generic.callback = ArenaServers_Event; + g_arenaservers.create.generic.id = ID_CREATE; + g_arenaservers.create.generic.x = 384; + g_arenaservers.create.generic.y = 480-64; + g_arenaservers.create.width = 128; + g_arenaservers.create.height = 64; + g_arenaservers.create.focuspic = ART_CREATE1; + + g_arenaservers.go.generic.type = MTYPE_BITMAP; + g_arenaservers.go.generic.name = ART_CONNECT0; + g_arenaservers.go.generic.flags = QMF_RIGHT_JUSTIFY|QMF_PULSEIFFOCUS; + g_arenaservers.go.generic.callback = ArenaServers_Event; + g_arenaservers.go.generic.id = ID_CONNECT; + g_arenaservers.go.generic.x = 640; + g_arenaservers.go.generic.y = 480-64; + g_arenaservers.go.width = 128; + g_arenaservers.go.height = 64; + g_arenaservers.go.focuspic = ART_CONNECT1; + + g_arenaservers.punkbuster.generic.type = MTYPE_SPINCONTROL; + g_arenaservers.punkbuster.generic.name = "Punkbuster:"; + g_arenaservers.punkbuster.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT; + g_arenaservers.punkbuster.generic.callback = ArenaServers_Event; + g_arenaservers.punkbuster.generic.id = ID_PUNKBUSTER; + g_arenaservers.punkbuster.generic.x = 480+32; + g_arenaservers.punkbuster.generic.y = 144; + g_arenaservers.punkbuster.itemnames = punkbuster_items; + + g_arenaservers.pblogo.generic.type = MTYPE_BITMAP; + g_arenaservers.pblogo.generic.name = ART_PUNKBUSTER; + g_arenaservers.pblogo.generic.flags = QMF_LEFT_JUSTIFY|QMF_INACTIVE; + g_arenaservers.pblogo.generic.x = 526; + g_arenaservers.pblogo.generic.y = 176; + g_arenaservers.pblogo.width = 32; + g_arenaservers.pblogo.height = 16; + g_arenaservers.pblogo.errorpic = ART_UNKNOWNMAP; + + Menu_AddItem( &g_arenaservers.menu, (void*) &g_arenaservers.banner ); + + Menu_AddItem( &g_arenaservers.menu, (void*) &g_arenaservers.master ); + Menu_AddItem( &g_arenaservers.menu, (void*) &g_arenaservers.gametype ); + Menu_AddItem( &g_arenaservers.menu, (void*) &g_arenaservers.sortkey ); + Menu_AddItem( &g_arenaservers.menu, (void*) &g_arenaservers.showfull); + Menu_AddItem( &g_arenaservers.menu, (void*) &g_arenaservers.showempty ); + + Menu_AddItem( &g_arenaservers.menu, (void*) &g_arenaservers.mappic ); + Menu_AddItem( &g_arenaservers.menu, (void*) &g_arenaservers.list ); + Menu_AddItem( &g_arenaservers.menu, (void*) &g_arenaservers.status ); + Menu_AddItem( &g_arenaservers.menu, (void*) &g_arenaservers.statusbar ); + Menu_AddItem( &g_arenaservers.menu, (void*) &g_arenaservers.arrows ); + Menu_AddItem( &g_arenaservers.menu, (void*) &g_arenaservers.up ); + Menu_AddItem( &g_arenaservers.menu, (void*) &g_arenaservers.down ); + + Menu_AddItem( &g_arenaservers.menu, (void*) &g_arenaservers.remove ); + Menu_AddItem( &g_arenaservers.menu, (void*) &g_arenaservers.back ); + Menu_AddItem( &g_arenaservers.menu, (void*) &g_arenaservers.specify ); + Menu_AddItem( &g_arenaservers.menu, (void*) &g_arenaservers.refresh ); + Menu_AddItem( &g_arenaservers.menu, (void*) &g_arenaservers.create ); + Menu_AddItem( &g_arenaservers.menu, (void*) &g_arenaservers.go ); + + Menu_AddItem( &g_arenaservers.menu, (void*) &g_arenaservers.punkbuster ); + Menu_AddItem( &g_arenaservers.menu, (void*) &g_arenaservers.pblogo ); + + ArenaServers_LoadFavorites(); + + g_servertype = Com_Clamp( 0, 3, ui_browserMaster.integer ); + // hack to get rid of MPlayer stuff + value = g_servertype; + if (value >= 1) + value--; + g_arenaservers.master.curvalue = value; + + g_gametype = Com_Clamp( 0, 4, ui_browserGameType.integer ); + g_arenaservers.gametype.curvalue = g_gametype; + + g_sortkey = Com_Clamp( 0, 4, ui_browserSortKey.integer ); + g_arenaservers.sortkey.curvalue = g_sortkey; + + g_fullservers = Com_Clamp( 0, 1, ui_browserShowFull.integer ); + g_arenaservers.showfull.curvalue = g_fullservers; + + g_emptyservers = Com_Clamp( 0, 1, ui_browserShowEmpty.integer ); + g_arenaservers.showempty.curvalue = g_emptyservers; + + g_arenaservers.punkbuster.curvalue = Com_Clamp( 0, 1, trap_Cvar_VariableValue( "cl_punkbuster" ) ); + + // force to initial state and refresh + type = g_servertype; + g_servertype = -1; + ArenaServers_SetType( type ); + + trap_Cvar_Register(NULL, "debug_protocol", "", 0 ); +} + + +/* +================= +ArenaServers_Cache +================= +*/ +void ArenaServers_Cache( void ) { + trap_R_RegisterShaderNoMip( ART_BACK0 ); + trap_R_RegisterShaderNoMip( ART_BACK1 ); + trap_R_RegisterShaderNoMip( ART_CREATE0 ); + trap_R_RegisterShaderNoMip( ART_CREATE1 ); + trap_R_RegisterShaderNoMip( ART_SPECIFY0 ); + trap_R_RegisterShaderNoMip( ART_SPECIFY1 ); + trap_R_RegisterShaderNoMip( ART_REFRESH0 ); + trap_R_RegisterShaderNoMip( ART_REFRESH1 ); + trap_R_RegisterShaderNoMip( ART_CONNECT0 ); + trap_R_RegisterShaderNoMip( ART_CONNECT1 ); + trap_R_RegisterShaderNoMip( ART_ARROWS0 ); + trap_R_RegisterShaderNoMip( ART_ARROWS_UP ); + trap_R_RegisterShaderNoMip( ART_ARROWS_DOWN ); + trap_R_RegisterShaderNoMip( ART_UNKNOWNMAP ); + trap_R_RegisterShaderNoMip( ART_PUNKBUSTER ); +} + + +/* +================= +UI_ArenaServersMenu +================= +*/ +void UI_ArenaServersMenu( void ) { + ArenaServers_MenuInit(); + UI_PushMenu( &g_arenaservers.menu ); +} diff --git a/code/q3_ui/ui_setup.c b/code/q3_ui/ui_setup.c new file mode 100755 index 0000000..25e01d5 --- /dev/null +++ b/code/q3_ui/ui_setup.c @@ -0,0 +1,327 @@ +/* +=========================================================================== +Copyright (C) 1999-2005 Id Software, Inc. + +This file is part of Quake III Arena source code. + +Quake III Arena source code is free software; you can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 2 of the License, +or (at your option) any later version. + +Quake III Arena source code is distributed in the hope that it will be +useful, but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Foobar; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ +// +/* +======================================================================= + +SETUP MENU + +======================================================================= +*/ + + +#include "ui_local.h" + + +#define SETUP_MENU_VERTICAL_SPACING 34 + +#define ART_BACK0 "menu/art/back_0" +#define ART_BACK1 "menu/art/back_1" +#define ART_FRAMEL "menu/art/frame2_l" +#define ART_FRAMER "menu/art/frame1_r" + +#define ID_CUSTOMIZEPLAYER 10 +#define ID_CUSTOMIZECONTROLS 11 +#define ID_SYSTEMCONFIG 12 +#define ID_GAME 13 +#define ID_CDKEY 14 +#define ID_LOAD 15 +#define ID_SAVE 16 +#define ID_DEFAULTS 17 +#define ID_BACK 18 + + +typedef struct { + menuframework_s menu; + + menutext_s banner; + menubitmap_s framel; + menubitmap_s framer; + menutext_s setupplayer; + menutext_s setupcontrols; + menutext_s setupsystem; + menutext_s game; + menutext_s cdkey; +// menutext_s load; +// menutext_s save; + menutext_s defaults; + menubitmap_s back; +} setupMenuInfo_t; + +static setupMenuInfo_t setupMenuInfo; + + +/* +================= +Setup_ResetDefaults_Action +================= +*/ +static void Setup_ResetDefaults_Action( qboolean result ) { + if( !result ) { + return; + } + trap_Cmd_ExecuteText( EXEC_APPEND, "exec default.cfg\n"); + trap_Cmd_ExecuteText( EXEC_APPEND, "cvar_restart\n"); + trap_Cmd_ExecuteText( EXEC_APPEND, "vid_restart\n" ); +} + + +/* +================= +Setup_ResetDefaults_Draw +================= +*/ +static void Setup_ResetDefaults_Draw( void ) { + UI_DrawProportionalString( SCREEN_WIDTH/2, 356 + PROP_HEIGHT * 0, "WARNING: This will reset *ALL*", UI_CENTER|UI_SMALLFONT, color_yellow ); + UI_DrawProportionalString( SCREEN_WIDTH/2, 356 + PROP_HEIGHT * 1, "options to their default values.", UI_CENTER|UI_SMALLFONT, color_yellow ); +} + + +/* +=============== +UI_SetupMenu_Event +=============== +*/ +static void UI_SetupMenu_Event( void *ptr, int event ) { + if( event != QM_ACTIVATED ) { + return; + } + + switch( ((menucommon_s*)ptr)->id ) { + case ID_CUSTOMIZEPLAYER: + UI_PlayerSettingsMenu(); + break; + + case ID_CUSTOMIZECONTROLS: + UI_ControlsMenu(); + break; + + case ID_SYSTEMCONFIG: + UI_GraphicsOptionsMenu(); + break; + + case ID_GAME: + UI_PreferencesMenu(); + break; + + case ID_CDKEY: + UI_CDKeyMenu(); + break; + +// case ID_LOAD: +// UI_LoadConfigMenu(); +// break; + +// case ID_SAVE: +// UI_SaveConfigMenu(); +// break; + + case ID_DEFAULTS: + UI_ConfirmMenu( "SET TO DEFAULTS?", Setup_ResetDefaults_Draw, Setup_ResetDefaults_Action ); + break; + + case ID_BACK: + UI_PopMenu(); + break; + } +} + + +/* +=============== +UI_SetupMenu_Init +=============== +*/ +static void UI_SetupMenu_Init( void ) { + int y; + + UI_SetupMenu_Cache(); + + memset( &setupMenuInfo, 0, sizeof(setupMenuInfo) ); + setupMenuInfo.menu.wrapAround = qtrue; + setupMenuInfo.menu.fullscreen = qtrue; + + setupMenuInfo.banner.generic.type = MTYPE_BTEXT; + setupMenuInfo.banner.generic.x = 320; + setupMenuInfo.banner.generic.y = 16; + setupMenuInfo.banner.string = "SETUP"; + setupMenuInfo.banner.color = color_white; + setupMenuInfo.banner.style = UI_CENTER; + + setupMenuInfo.framel.generic.type = MTYPE_BITMAP; + setupMenuInfo.framel.generic.name = ART_FRAMEL; + setupMenuInfo.framel.generic.flags = QMF_INACTIVE; + setupMenuInfo.framel.generic.x = 0; + setupMenuInfo.framel.generic.y = 78; + setupMenuInfo.framel.width = 256; + setupMenuInfo.framel.height = 329; + + setupMenuInfo.framer.generic.type = MTYPE_BITMAP; + setupMenuInfo.framer.generic.name = ART_FRAMER; + setupMenuInfo.framer.generic.flags = QMF_INACTIVE; + setupMenuInfo.framer.generic.x = 376; + setupMenuInfo.framer.generic.y = 76; + setupMenuInfo.framer.width = 256; + setupMenuInfo.framer.height = 334; + + y = 134; + setupMenuInfo.setupplayer.generic.type = MTYPE_PTEXT; + setupMenuInfo.setupplayer.generic.flags = QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS; + setupMenuInfo.setupplayer.generic.x = 320; + setupMenuInfo.setupplayer.generic.y = y; + setupMenuInfo.setupplayer.generic.id = ID_CUSTOMIZEPLAYER; + setupMenuInfo.setupplayer.generic.callback = UI_SetupMenu_Event; + setupMenuInfo.setupplayer.string = "PLAYER"; + setupMenuInfo.setupplayer.color = color_red; + setupMenuInfo.setupplayer.style = UI_CENTER; + + y += SETUP_MENU_VERTICAL_SPACING; + setupMenuInfo.setupcontrols.generic.type = MTYPE_PTEXT; + setupMenuInfo.setupcontrols.generic.flags = QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS; + setupMenuInfo.setupcontrols.generic.x = 320; + setupMenuInfo.setupcontrols.generic.y = y; + setupMenuInfo.setupcontrols.generic.id = ID_CUSTOMIZECONTROLS; + setupMenuInfo.setupcontrols.generic.callback = UI_SetupMenu_Event; + setupMenuInfo.setupcontrols.string = "CONTROLS"; + setupMenuInfo.setupcontrols.color = color_red; + setupMenuInfo.setupcontrols.style = UI_CENTER; + + y += SETUP_MENU_VERTICAL_SPACING; + setupMenuInfo.setupsystem.generic.type = MTYPE_PTEXT; + setupMenuInfo.setupsystem.generic.flags = QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS; + setupMenuInfo.setupsystem.generic.x = 320; + setupMenuInfo.setupsystem.generic.y = y; + setupMenuInfo.setupsystem.generic.id = ID_SYSTEMCONFIG; + setupMenuInfo.setupsystem.generic.callback = UI_SetupMenu_Event; + setupMenuInfo.setupsystem.string = "SYSTEM"; + setupMenuInfo.setupsystem.color = color_red; + setupMenuInfo.setupsystem.style = UI_CENTER; + + y += SETUP_MENU_VERTICAL_SPACING; + setupMenuInfo.game.generic.type = MTYPE_PTEXT; + setupMenuInfo.game.generic.flags = QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS; + setupMenuInfo.game.generic.x = 320; + setupMenuInfo.game.generic.y = y; + setupMenuInfo.game.generic.id = ID_GAME; + setupMenuInfo.game.generic.callback = UI_SetupMenu_Event; + setupMenuInfo.game.string = "GAME OPTIONS"; + setupMenuInfo.game.color = color_red; + setupMenuInfo.game.style = UI_CENTER; + + y += SETUP_MENU_VERTICAL_SPACING; + setupMenuInfo.cdkey.generic.type = MTYPE_PTEXT; + setupMenuInfo.cdkey.generic.flags = QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS; + setupMenuInfo.cdkey.generic.x = 320; + setupMenuInfo.cdkey.generic.y = y; + setupMenuInfo.cdkey.generic.id = ID_CDKEY; + setupMenuInfo.cdkey.generic.callback = UI_SetupMenu_Event; + setupMenuInfo.cdkey.string = "CD Key"; + setupMenuInfo.cdkey.color = color_red; + setupMenuInfo.cdkey.style = UI_CENTER; + + if( !trap_Cvar_VariableValue( "cl_paused" ) ) { +#if 0 + y += SETUP_MENU_VERTICAL_SPACING; + setupMenuInfo.load.generic.type = MTYPE_PTEXT; + setupMenuInfo.load.generic.flags = QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS; + setupMenuInfo.load.generic.x = 320; + setupMenuInfo.load.generic.y = y; + setupMenuInfo.load.generic.id = ID_LOAD; + setupMenuInfo.load.generic.callback = UI_SetupMenu_Event; + setupMenuInfo.load.string = "LOAD"; + setupMenuInfo.load.color = color_red; + setupMenuInfo.load.style = UI_CENTER; + + y += SETUP_MENU_VERTICAL_SPACING; + setupMenuInfo.save.generic.type = MTYPE_PTEXT; + setupMenuInfo.save.generic.flags = QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS; + setupMenuInfo.save.generic.x = 320; + setupMenuInfo.save.generic.y = y; + setupMenuInfo.save.generic.id = ID_SAVE; + setupMenuInfo.save.generic.callback = UI_SetupMenu_Event; + setupMenuInfo.save.string = "SAVE"; + setupMenuInfo.save.color = color_red; + setupMenuInfo.save.style = UI_CENTER; +#endif + + y += SETUP_MENU_VERTICAL_SPACING; + setupMenuInfo.defaults.generic.type = MTYPE_PTEXT; + setupMenuInfo.defaults.generic.flags = QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS; + setupMenuInfo.defaults.generic.x = 320; + setupMenuInfo.defaults.generic.y = y; + setupMenuInfo.defaults.generic.id = ID_DEFAULTS; + setupMenuInfo.defaults.generic.callback = UI_SetupMenu_Event; + setupMenuInfo.defaults.string = "DEFAULTS"; + setupMenuInfo.defaults.color = color_red; + setupMenuInfo.defaults.style = UI_CENTER; + } + + setupMenuInfo.back.generic.type = MTYPE_BITMAP; + setupMenuInfo.back.generic.name = ART_BACK0; + setupMenuInfo.back.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS; + setupMenuInfo.back.generic.id = ID_BACK; + setupMenuInfo.back.generic.callback = UI_SetupMenu_Event; + setupMenuInfo.back.generic.x = 0; + setupMenuInfo.back.generic.y = 480-64; + setupMenuInfo.back.width = 128; + setupMenuInfo.back.height = 64; + setupMenuInfo.back.focuspic = ART_BACK1; + + Menu_AddItem( &setupMenuInfo.menu, &setupMenuInfo.banner ); + Menu_AddItem( &setupMenuInfo.menu, &setupMenuInfo.framel ); + Menu_AddItem( &setupMenuInfo.menu, &setupMenuInfo.framer ); + Menu_AddItem( &setupMenuInfo.menu, &setupMenuInfo.setupplayer ); + Menu_AddItem( &setupMenuInfo.menu, &setupMenuInfo.setupcontrols ); + Menu_AddItem( &setupMenuInfo.menu, &setupMenuInfo.setupsystem ); + Menu_AddItem( &setupMenuInfo.menu, &setupMenuInfo.game ); + Menu_AddItem( &setupMenuInfo.menu, &setupMenuInfo.cdkey ); +// Menu_AddItem( &setupMenuInfo.menu, &setupMenuInfo.load ); +// Menu_AddItem( &setupMenuInfo.menu, &setupMenuInfo.save ); + if( !trap_Cvar_VariableValue( "cl_paused" ) ) { + Menu_AddItem( &setupMenuInfo.menu, &setupMenuInfo.defaults ); + } + Menu_AddItem( &setupMenuInfo.menu, &setupMenuInfo.back ); +} + + +/* +================= +UI_SetupMenu_Cache +================= +*/ +void UI_SetupMenu_Cache( void ) { + trap_R_RegisterShaderNoMip( ART_BACK0 ); + trap_R_RegisterShaderNoMip( ART_BACK1 ); + trap_R_RegisterShaderNoMip( ART_FRAMEL ); + trap_R_RegisterShaderNoMip( ART_FRAMER ); +} + + +/* +=============== +UI_SetupMenu +=============== +*/ +void UI_SetupMenu( void ) { + UI_SetupMenu_Init(); + UI_PushMenu( &setupMenuInfo.menu ); +} diff --git a/code/q3_ui/ui_signup.c b/code/q3_ui/ui_signup.c new file mode 100755 index 0000000..efe9529 --- /dev/null +++ b/code/q3_ui/ui_signup.c @@ -0,0 +1,286 @@ +/* +=========================================================================== +Copyright (C) 1999-2005 Id Software, Inc. + +This file is part of Quake III Arena source code. + +Quake III Arena source code is free software; you can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 2 of the License, +or (at your option) any later version. + +Quake III Arena source code is distributed in the hope that it will be +useful, but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Foobar; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ +// +// +// ui_signup.c +// + +#include "ui_local.h" + + +#define SIGNUP_FRAME "menu/art/cut_frame" + +#define ID_NAME 100 +#define ID_NAME_BOX 101 +#define ID_PASSWORD 102 +#define ID_PASSWORD_BOX 103 +#define ID_AGAIN 104 +#define ID_AGAIN_BOX 105 +#define ID_EMAIL 106 +#define ID_EMAIL_BOX 107 +#define ID_SIGNUP 108 +#define ID_CANCEL 109 + + +typedef struct +{ + menuframework_s menu; + menubitmap_s frame; + menutext_s name; + menufield_s name_box; + menutext_s password; + menufield_s password_box; + menutext_s again; + menufield_s again_box; + menutext_s email; + menufield_s email_box; + menutext_s signup; + menutext_s cancel; +} signup_t; + +static signup_t s_signup; + +static menuframework_s s_signup_menu; +static menuaction_s s_signup_signup; +static menuaction_s s_signup_cancel; + +static vec4_t s_signup_color_prompt = {1.00, 0.43, 0.00, 1.00}; + +/* +=============== +Signup_MenuEvent +=============== +*/ +static void Signup_MenuEvent( void* ptr, int event ) { + //char cmd[1024]; + + if( event != QM_ACTIVATED ) { + return; + } + + switch( ((menucommon_s*)ptr)->id ) { + case ID_SIGNUP: + if( strcmp(s_signup.password_box.field.buffer, + s_signup.again_box.field.buffer) != 0 ) + { + // GRANK_FIXME - password mismatch + break; + } + // set name + //trap_Cvar_Set( "name", s_signup.name_box.field.buffer ); + /* + trap_Cvar_Set( "rank_name", s_signup.name_box.field.buffer ); + trap_Cvar_Set( "rank_pwd", s_signup.password_box.field.buffer ); + */ + + // create account + /* + sprintf( cmd, "cmd rank_create \"%s\" \"%s\" \"%s\"\n", + s_signup.name_box.field.buffer, + s_signup.password_box.field.buffer, + s_signup.email_box.field.buffer ); + trap_Cmd_ExecuteText( EXEC_APPEND, cmd ); + */ + trap_CL_UI_RankUserCreate( + s_signup.name_box.field.buffer, + s_signup.password_box.field.buffer, + s_signup.email_box.field.buffer ); + + UI_ForceMenuOff(); + break; + + case ID_CANCEL: + UI_PopMenu(); + break; + } +} + +/* +=============== +Signup_MenuInit +=============== +*/ +void Signup_MenuInit( void ) { + grank_status_t status; + int y; + + memset( &s_signup, 0, sizeof(s_signup) ); + + Signup_Cache(); + + s_signup.menu.wrapAround = qtrue; + s_signup.menu.fullscreen = qfalse; + + s_signup.frame.generic.type = MTYPE_BITMAP; + s_signup.frame.generic.flags = QMF_INACTIVE; + s_signup.frame.generic.name = SIGNUP_FRAME; + s_signup.frame.generic.x = 142; //320-233; + s_signup.frame.generic.y = 118; //240-166; + s_signup.frame.width = 359; //466; + s_signup.frame.height = 256; //332; + + y = 194; + + s_signup.name.generic.type = MTYPE_PTEXT; + s_signup.name.generic.flags = QMF_RIGHT_JUSTIFY|QMF_INACTIVE; + s_signup.name.generic.id = ID_NAME; + s_signup.name.generic.x = 310; + s_signup.name.generic.y = y; + s_signup.name.string = "NAME"; + s_signup.name.style = UI_RIGHT|UI_SMALLFONT; + s_signup.name.color = s_signup_color_prompt; + + s_signup.name_box.generic.type = MTYPE_FIELD; + s_signup.name_box.generic.ownerdraw = Rankings_DrawName; + s_signup.name_box.generic.name = ""; + s_signup.name_box.generic.flags = 0; + s_signup.name_box.generic.x = 330; + s_signup.name_box.generic.y = y; + s_signup.name_box.field.widthInChars = 16; + s_signup.name_box.field.maxchars = 16; + y += 20; + + s_signup.password.generic.type = MTYPE_PTEXT; + s_signup.password.generic.flags = QMF_RIGHT_JUSTIFY|QMF_INACTIVE; + s_signup.password.generic.id = ID_PASSWORD; + s_signup.password.generic.x = 310; + s_signup.password.generic.y = y; + s_signup.password.string = "PASSWORD"; + s_signup.password.style = UI_RIGHT|UI_SMALLFONT; + s_signup.password.color = s_signup_color_prompt; + + s_signup.password_box.generic.type = MTYPE_FIELD; + s_signup.password_box.generic.ownerdraw = Rankings_DrawPassword; + s_signup.password_box.generic.name = ""; + s_signup.password_box.generic.flags = 0; + s_signup.password_box.generic.x = 330; + s_signup.password_box.generic.y = y; + s_signup.password_box.field.widthInChars = 16; + s_signup.password_box.field.maxchars = 16; + y += 20; + + s_signup.again.generic.type = MTYPE_PTEXT; + s_signup.again.generic.flags = QMF_RIGHT_JUSTIFY|QMF_INACTIVE; + s_signup.again.generic.id = ID_AGAIN; + s_signup.again.generic.x = 310; + s_signup.again.generic.y = y; + s_signup.again.string = "(AGAIN)"; + s_signup.again.style = UI_RIGHT|UI_SMALLFONT; + s_signup.again.color = s_signup_color_prompt; + + s_signup.again_box.generic.type = MTYPE_FIELD; + s_signup.again_box.generic.ownerdraw = Rankings_DrawPassword; + s_signup.again_box.generic.name = ""; + s_signup.again_box.generic.flags = 0; + s_signup.again_box.generic.x = 330; + s_signup.again_box.generic.y = y; + s_signup.again_box.field.widthInChars = 16; + s_signup.again_box.field.maxchars = 16; + y += 20; + + s_signup.email.generic.type = MTYPE_PTEXT; + s_signup.email.generic.flags = QMF_RIGHT_JUSTIFY|QMF_INACTIVE; + s_signup.email.generic.id = ID_EMAIL; + s_signup.email.generic.x = 310; + s_signup.email.generic.y = y; + s_signup.email.string = "EMAIL"; + s_signup.email.style = UI_RIGHT|UI_SMALLFONT; + s_signup.email.color = s_signup_color_prompt; + + s_signup.email_box.generic.type = MTYPE_FIELD; + s_signup.email_box.generic.ownerdraw = Rankings_DrawText; + s_signup.email_box.generic.name = ""; + s_signup.email_box.generic.flags = 0; + s_signup.email_box.generic.x = 330; + s_signup.email_box.generic.y = y; + s_signup.email_box.field.widthInChars = 16; + s_signup.email_box.field.maxchars = MAX_EDIT_LINE; + y += 40; + + s_signup.signup.generic.type = MTYPE_PTEXT; + s_signup.signup.generic.flags = QMF_RIGHT_JUSTIFY|QMF_PULSEIFFOCUS; + s_signup.signup.generic.id = ID_SIGNUP; + s_signup.signup.generic.callback = Signup_MenuEvent; + s_signup.signup.generic.x = 310; + s_signup.signup.generic.y = y; + s_signup.signup.string = "SIGN UP"; + s_signup.signup.style = UI_RIGHT|UI_SMALLFONT; + s_signup.signup.color = colorRed; + + s_signup.cancel.generic.type = MTYPE_PTEXT; + s_signup.cancel.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS; + s_signup.cancel.generic.id = ID_CANCEL; + s_signup.cancel.generic.callback = Signup_MenuEvent; + s_signup.cancel.generic.x = 330; + s_signup.cancel.generic.y = y; + s_signup.cancel.string = "CANCEL"; + s_signup.cancel.style = UI_LEFT|UI_SMALLFONT; + s_signup.cancel.color = colorRed; + y += 20; + + status = (grank_status_t)trap_Cvar_VariableValue("client_status"); + if( (status != QGR_STATUS_NEW) && (status != QGR_STATUS_SPECTATOR) ) + { + s_signup.name_box.generic.flags |= QMF_INACTIVE; + s_signup.password_box.generic.flags |= QMF_INACTIVE; + s_signup.again_box.generic.flags |= QMF_INACTIVE; + s_signup.email_box.generic.flags |= QMF_INACTIVE; + s_signup.signup.generic.flags |= QMF_INACTIVE; + + s_signup.signup.color = colorMdGrey; + } + + Menu_AddItem( &s_signup.menu, (void*) &s_signup.frame ); + Menu_AddItem( &s_signup.menu, (void*) &s_signup.name ); + Menu_AddItem( &s_signup.menu, (void*) &s_signup.name_box ); + Menu_AddItem( &s_signup.menu, (void*) &s_signup.password ); + Menu_AddItem( &s_signup.menu, (void*) &s_signup.password_box ); + Menu_AddItem( &s_signup.menu, (void*) &s_signup.again ); + Menu_AddItem( &s_signup.menu, (void*) &s_signup.again_box ); + Menu_AddItem( &s_signup.menu, (void*) &s_signup.email ); + Menu_AddItem( &s_signup.menu, (void*) &s_signup.email_box ); + Menu_AddItem( &s_signup.menu, (void*) &s_signup.signup ); + Menu_AddItem( &s_signup.menu, (void*) &s_signup.cancel ); +} + + +/* +=============== +Signup_Cache +=============== +*/ +void Signup_Cache( void ) { + trap_R_RegisterShaderNoMip( SIGNUP_FRAME ); +} + + +/* +=============== +UI_SignupMenu +=============== +*/ +void UI_SignupMenu( void ) { + Signup_MenuInit(); + UI_PushMenu ( &s_signup.menu ); +} + + diff --git a/code/q3_ui/ui_sound.c b/code/q3_ui/ui_sound.c new file mode 100755 index 0000000..60040f0 --- /dev/null +++ b/code/q3_ui/ui_sound.c @@ -0,0 +1,316 @@ +/* +=========================================================================== +Copyright (C) 1999-2005 Id Software, Inc. + +This file is part of Quake III Arena source code. + +Quake III Arena source code is free software; you can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 2 of the License, +or (at your option) any later version. + +Quake III Arena source code is distributed in the hope that it will be +useful, but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Foobar; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ +// +/* +======================================================================= + +SOUND OPTIONS MENU + +======================================================================= +*/ + +#include "ui_local.h" + + +#define ART_FRAMEL "menu/art/frame2_l" +#define ART_FRAMER "menu/art/frame1_r" +#define ART_BACK0 "menu/art/back_0" +#define ART_BACK1 "menu/art/back_1" + +#define ID_GRAPHICS 10 +#define ID_DISPLAY 11 +#define ID_SOUND 12 +#define ID_NETWORK 13 +#define ID_EFFECTSVOLUME 14 +#define ID_MUSICVOLUME 15 +#define ID_QUALITY 16 +//#define ID_A3D 17 +#define ID_BACK 18 + + +static const char *quality_items[] = { + "Low", "High", 0 +}; + +typedef struct { + menuframework_s menu; + + menutext_s banner; + menubitmap_s framel; + menubitmap_s framer; + + menutext_s graphics; + menutext_s display; + menutext_s sound; + menutext_s network; + + menuslider_s sfxvolume; + menuslider_s musicvolume; + menulist_s quality; +// menuradiobutton_s a3d; + + menubitmap_s back; +} soundOptionsInfo_t; + +static soundOptionsInfo_t soundOptionsInfo; + + +/* +================= +UI_SoundOptionsMenu_Event +================= +*/ +static void UI_SoundOptionsMenu_Event( void* ptr, int event ) { + if( event != QM_ACTIVATED ) { + return; + } + + switch( ((menucommon_s*)ptr)->id ) { + case ID_GRAPHICS: + UI_PopMenu(); + UI_GraphicsOptionsMenu(); + break; + + case ID_DISPLAY: + UI_PopMenu(); + UI_DisplayOptionsMenu(); + break; + + case ID_SOUND: + break; + + case ID_NETWORK: + UI_PopMenu(); + UI_NetworkOptionsMenu(); + break; + + case ID_EFFECTSVOLUME: + trap_Cvar_SetValue( "s_volume", soundOptionsInfo.sfxvolume.curvalue / 10 ); + break; + + case ID_MUSICVOLUME: + trap_Cvar_SetValue( "s_musicvolume", soundOptionsInfo.musicvolume.curvalue / 10 ); + break; + + case ID_QUALITY: + if( soundOptionsInfo.quality.curvalue ) { + trap_Cvar_SetValue( "s_khz", 22 ); + trap_Cvar_SetValue( "s_compression", 0 ); + } + else { + trap_Cvar_SetValue( "s_khz", 11 ); + trap_Cvar_SetValue( "s_compression", 1 ); + } + UI_ForceMenuOff(); + trap_Cmd_ExecuteText( EXEC_APPEND, "snd_restart\n" ); + break; +/* + case ID_A3D: + if( soundOptionsInfo.a3d.curvalue ) { + trap_Cmd_ExecuteText( EXEC_NOW, "s_enable_a3d\n" ); + } + else { + trap_Cmd_ExecuteText( EXEC_NOW, "s_disable_a3d\n" ); + } + soundOptionsInfo.a3d.curvalue = (int)trap_Cvar_VariableValue( "s_usingA3D" ); + break; +*/ + case ID_BACK: + UI_PopMenu(); + break; + } +} + + +/* +=============== +UI_SoundOptionsMenu_Init +=============== +*/ +static void UI_SoundOptionsMenu_Init( void ) { + int y; + + memset( &soundOptionsInfo, 0, sizeof(soundOptionsInfo) ); + + UI_SoundOptionsMenu_Cache(); + soundOptionsInfo.menu.wrapAround = qtrue; + soundOptionsInfo.menu.fullscreen = qtrue; + + soundOptionsInfo.banner.generic.type = MTYPE_BTEXT; + soundOptionsInfo.banner.generic.flags = QMF_CENTER_JUSTIFY; + soundOptionsInfo.banner.generic.x = 320; + soundOptionsInfo.banner.generic.y = 16; + soundOptionsInfo.banner.string = "SYSTEM SETUP"; + soundOptionsInfo.banner.color = color_white; + soundOptionsInfo.banner.style = UI_CENTER; + + soundOptionsInfo.framel.generic.type = MTYPE_BITMAP; + soundOptionsInfo.framel.generic.name = ART_FRAMEL; + soundOptionsInfo.framel.generic.flags = QMF_INACTIVE; + soundOptionsInfo.framel.generic.x = 0; + soundOptionsInfo.framel.generic.y = 78; + soundOptionsInfo.framel.width = 256; + soundOptionsInfo.framel.height = 329; + + soundOptionsInfo.framer.generic.type = MTYPE_BITMAP; + soundOptionsInfo.framer.generic.name = ART_FRAMER; + soundOptionsInfo.framer.generic.flags = QMF_INACTIVE; + soundOptionsInfo.framer.generic.x = 376; + soundOptionsInfo.framer.generic.y = 76; + soundOptionsInfo.framer.width = 256; + soundOptionsInfo.framer.height = 334; + + soundOptionsInfo.graphics.generic.type = MTYPE_PTEXT; + soundOptionsInfo.graphics.generic.flags = QMF_RIGHT_JUSTIFY|QMF_PULSEIFFOCUS; + soundOptionsInfo.graphics.generic.id = ID_GRAPHICS; + soundOptionsInfo.graphics.generic.callback = UI_SoundOptionsMenu_Event; + soundOptionsInfo.graphics.generic.x = 216; + soundOptionsInfo.graphics.generic.y = 240 - 2 * PROP_HEIGHT; + soundOptionsInfo.graphics.string = "GRAPHICS"; + soundOptionsInfo.graphics.style = UI_RIGHT; + soundOptionsInfo.graphics.color = color_red; + + soundOptionsInfo.display.generic.type = MTYPE_PTEXT; + soundOptionsInfo.display.generic.flags = QMF_RIGHT_JUSTIFY|QMF_PULSEIFFOCUS; + soundOptionsInfo.display.generic.id = ID_DISPLAY; + soundOptionsInfo.display.generic.callback = UI_SoundOptionsMenu_Event; + soundOptionsInfo.display.generic.x = 216; + soundOptionsInfo.display.generic.y = 240 - PROP_HEIGHT; + soundOptionsInfo.display.string = "DISPLAY"; + soundOptionsInfo.display.style = UI_RIGHT; + soundOptionsInfo.display.color = color_red; + + soundOptionsInfo.sound.generic.type = MTYPE_PTEXT; + soundOptionsInfo.sound.generic.flags = QMF_RIGHT_JUSTIFY; + soundOptionsInfo.sound.generic.id = ID_SOUND; + soundOptionsInfo.sound.generic.callback = UI_SoundOptionsMenu_Event; + soundOptionsInfo.sound.generic.x = 216; + soundOptionsInfo.sound.generic.y = 240; + soundOptionsInfo.sound.string = "SOUND"; + soundOptionsInfo.sound.style = UI_RIGHT; + soundOptionsInfo.sound.color = color_red; + + soundOptionsInfo.network.generic.type = MTYPE_PTEXT; + soundOptionsInfo.network.generic.flags = QMF_RIGHT_JUSTIFY|QMF_PULSEIFFOCUS; + soundOptionsInfo.network.generic.id = ID_NETWORK; + soundOptionsInfo.network.generic.callback = UI_SoundOptionsMenu_Event; + soundOptionsInfo.network.generic.x = 216; + soundOptionsInfo.network.generic.y = 240 + PROP_HEIGHT; + soundOptionsInfo.network.string = "NETWORK"; + soundOptionsInfo.network.style = UI_RIGHT; + soundOptionsInfo.network.color = color_red; + + y = 240 - 1.5 * (BIGCHAR_HEIGHT + 2); + soundOptionsInfo.sfxvolume.generic.type = MTYPE_SLIDER; + soundOptionsInfo.sfxvolume.generic.name = "Effects Volume:"; + soundOptionsInfo.sfxvolume.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT; + soundOptionsInfo.sfxvolume.generic.callback = UI_SoundOptionsMenu_Event; + soundOptionsInfo.sfxvolume.generic.id = ID_EFFECTSVOLUME; + soundOptionsInfo.sfxvolume.generic.x = 400; + soundOptionsInfo.sfxvolume.generic.y = y; + soundOptionsInfo.sfxvolume.minvalue = 0; + soundOptionsInfo.sfxvolume.maxvalue = 10; + + y += BIGCHAR_HEIGHT+2; + soundOptionsInfo.musicvolume.generic.type = MTYPE_SLIDER; + soundOptionsInfo.musicvolume.generic.name = "Music Volume:"; + soundOptionsInfo.musicvolume.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT; + soundOptionsInfo.musicvolume.generic.callback = UI_SoundOptionsMenu_Event; + soundOptionsInfo.musicvolume.generic.id = ID_MUSICVOLUME; + soundOptionsInfo.musicvolume.generic.x = 400; + soundOptionsInfo.musicvolume.generic.y = y; + soundOptionsInfo.musicvolume.minvalue = 0; + soundOptionsInfo.musicvolume.maxvalue = 10; + + y += BIGCHAR_HEIGHT+2; + soundOptionsInfo.quality.generic.type = MTYPE_SPINCONTROL; + soundOptionsInfo.quality.generic.name = "Sound Quality:"; + soundOptionsInfo.quality.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT; + soundOptionsInfo.quality.generic.callback = UI_SoundOptionsMenu_Event; + soundOptionsInfo.quality.generic.id = ID_QUALITY; + soundOptionsInfo.quality.generic.x = 400; + soundOptionsInfo.quality.generic.y = y; + soundOptionsInfo.quality.itemnames = quality_items; +/* + y += BIGCHAR_HEIGHT+2; + soundOptionsInfo.a3d.generic.type = MTYPE_RADIOBUTTON; + soundOptionsInfo.a3d.generic.name = "A3D:"; + soundOptionsInfo.a3d.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT; + soundOptionsInfo.a3d.generic.callback = UI_SoundOptionsMenu_Event; + soundOptionsInfo.a3d.generic.id = ID_A3D; + soundOptionsInfo.a3d.generic.x = 400; + soundOptionsInfo.a3d.generic.y = y; +*/ + soundOptionsInfo.back.generic.type = MTYPE_BITMAP; + soundOptionsInfo.back.generic.name = ART_BACK0; + soundOptionsInfo.back.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS; + soundOptionsInfo.back.generic.callback = UI_SoundOptionsMenu_Event; + soundOptionsInfo.back.generic.id = ID_BACK; + soundOptionsInfo.back.generic.x = 0; + soundOptionsInfo.back.generic.y = 480-64; + soundOptionsInfo.back.width = 128; + soundOptionsInfo.back.height = 64; + soundOptionsInfo.back.focuspic = ART_BACK1; + + Menu_AddItem( &soundOptionsInfo.menu, ( void * ) &soundOptionsInfo.banner ); + Menu_AddItem( &soundOptionsInfo.menu, ( void * ) &soundOptionsInfo.framel ); + Menu_AddItem( &soundOptionsInfo.menu, ( void * ) &soundOptionsInfo.framer ); + Menu_AddItem( &soundOptionsInfo.menu, ( void * ) &soundOptionsInfo.graphics ); + Menu_AddItem( &soundOptionsInfo.menu, ( void * ) &soundOptionsInfo.display ); + Menu_AddItem( &soundOptionsInfo.menu, ( void * ) &soundOptionsInfo.sound ); + Menu_AddItem( &soundOptionsInfo.menu, ( void * ) &soundOptionsInfo.network ); + Menu_AddItem( &soundOptionsInfo.menu, ( void * ) &soundOptionsInfo.sfxvolume ); + Menu_AddItem( &soundOptionsInfo.menu, ( void * ) &soundOptionsInfo.musicvolume ); + Menu_AddItem( &soundOptionsInfo.menu, ( void * ) &soundOptionsInfo.quality ); +// Menu_AddItem( &soundOptionsInfo.menu, ( void * ) &soundOptionsInfo.a3d ); + Menu_AddItem( &soundOptionsInfo.menu, ( void * ) &soundOptionsInfo.back ); + + soundOptionsInfo.sfxvolume.curvalue = trap_Cvar_VariableValue( "s_volume" ) * 10; + soundOptionsInfo.musicvolume.curvalue = trap_Cvar_VariableValue( "s_musicvolume" ) * 10; + soundOptionsInfo.quality.curvalue = !trap_Cvar_VariableValue( "s_compression" ); +// soundOptionsInfo.a3d.curvalue = (int)trap_Cvar_VariableValue( "s_usingA3D" ); +} + + +/* +=============== +UI_SoundOptionsMenu_Cache +=============== +*/ +void UI_SoundOptionsMenu_Cache( void ) { + trap_R_RegisterShaderNoMip( ART_FRAMEL ); + trap_R_RegisterShaderNoMip( ART_FRAMER ); + trap_R_RegisterShaderNoMip( ART_BACK0 ); + trap_R_RegisterShaderNoMip( ART_BACK1 ); +} + + +/* +=============== +UI_SoundOptionsMenu +=============== +*/ +void UI_SoundOptionsMenu( void ) { + UI_SoundOptionsMenu_Init(); + UI_PushMenu( &soundOptionsInfo.menu ); + Menu_SetCursorToItem( &soundOptionsInfo.menu, &soundOptionsInfo.sound ); +} diff --git a/code/q3_ui/ui_sparena.c b/code/q3_ui/ui_sparena.c new file mode 100755 index 0000000..44970f6 --- /dev/null +++ b/code/q3_ui/ui_sparena.c @@ -0,0 +1,50 @@ +/* +=========================================================================== +Copyright (C) 1999-2005 Id Software, Inc. + +This file is part of Quake III Arena source code. + +Quake III Arena source code is free software; you can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 2 of the License, +or (at your option) any later version. + +Quake III Arena source code is distributed in the hope that it will be +useful, but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Foobar; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ +// +#include "ui_local.h" + +void UI_SPArena_Start( const char *arenaInfo ) { + char *map; + int level; + int n; + char *txt; + + n = (int)trap_Cvar_VariableValue( "sv_maxclients" ); + if ( n < 8 ) { + trap_Cvar_SetValue( "sv_maxclients", 8 ); + } + + level = atoi( Info_ValueForKey( arenaInfo, "num" ) ); + txt = Info_ValueForKey( arenaInfo, "special" ); + if( txt[0] ) { + if( Q_stricmp( txt, "training" ) == 0 ) { + level = -4; + } + else if( Q_stricmp( txt, "final" ) == 0 ) { + level = UI_GetNumSPTiers() * ARENAS_PER_TIER; + } + } + trap_Cvar_SetValue( "ui_spSelection", level ); + + map = Info_ValueForKey( arenaInfo, "map" ); + trap_Cmd_ExecuteText( EXEC_APPEND, va( "spmap %s\n", map ) ); +} diff --git a/code/q3_ui/ui_specifyleague.c b/code/q3_ui/ui_specifyleague.c new file mode 100755 index 0000000..4e0a8b0 --- /dev/null +++ b/code/q3_ui/ui_specifyleague.c @@ -0,0 +1,333 @@ +/* +=========================================================================== +Copyright (C) 1999-2005 Id Software, Inc. + +This file is part of Quake III Arena source code. + +Quake III Arena source code is free software; you can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 2 of the License, +or (at your option) any later version. + +Quake III Arena source code is distributed in the hope that it will be +useful, but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Foobar; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ +// +#include "ui_local.h" + +/********************************************************************************* + SPECIFY SERVER +*********************************************************************************/ + +#define MAX_LISTBOXITEMS 128 +#define MAX_LISTBOXWIDTH 40 +#define MAX_LEAGUENAME 80 + +#define SPECIFYLEAGUE_FRAMEL "menu/art/frame2_l" +#define SPECIFYLEAGUE_FRAMER "menu/art/frame1_r" +#define SPECIFYLEAGUE_BACK0 "menu/art/back_0" +#define SPECIFYLEAGUE_BACK1 "menu/art/back_1" +#define SPECIFYLEAGUE_ARROWS0 "menu/art/arrows_vert_0" +#define SPECIFYLEAGUE_UP "menu/art/arrows_vert_top" +#define SPECIFYLEAGUE_DOWN "menu/art/arrows_vert_bot" +#define GLOBALRANKINGS_LOGO "menu/art/gr/grlogo" +#define GLOBALRANKINGS_LETTERS "menu/art/gr/grletters" + +#define ID_SPECIFYLEAGUENAME 100 +#define ID_SPECIFYLEAGUELIST 101 +#define ID_SPECIFYLEAGUEUP 102 +#define ID_SPECIFYLEAGUEDOWN 103 +#define ID_SPECIFYLEAGUEBACK 104 + +static char* specifyleague_artlist[] = +{ + SPECIFYLEAGUE_FRAMEL, + SPECIFYLEAGUE_FRAMER, + SPECIFYLEAGUE_ARROWS0, + SPECIFYLEAGUE_UP, + SPECIFYLEAGUE_DOWN, + SPECIFYLEAGUE_BACK0, + SPECIFYLEAGUE_BACK1, + GLOBALRANKINGS_LOGO, + GLOBALRANKINGS_LETTERS, + NULL +}; + +static char playername[80]; + +typedef struct +{ + menuframework_s menu; + menutext_s banner; + menubitmap_s framel; + menubitmap_s framer; + menufield_s rankname; + menulist_s list; + menubitmap_s arrows; + menubitmap_s up; + menubitmap_s down; + menubitmap_s back; + menubitmap_s grlogo; + menubitmap_s grletters; +} specifyleague_t; + +static specifyleague_t s_specifyleague; + + +typedef struct { + char buff[MAX_LISTBOXWIDTH]; + char leaguename[MAX_LEAGUENAME]; +} table_t; + +table_t league_table[MAX_LISTBOXITEMS]; +char *leaguename_items[MAX_LISTBOXITEMS]; + + +static void SpecifyLeague_GetList() +{ + int count = 0; + int i; + /* The Player Name has changed. We need to perform another search */ + Q_strncpyz( playername, + s_specifyleague.rankname.field.buffer, + sizeof(playername) ); + + count = trap_CL_UI_RankGetLeauges( playername ); + + for(i = 0; i < count; i++) + { + char s[MAX_LEAGUENAME]; + const char *var; + var = va( "leaguename%i", i+1 ); + trap_Cvar_VariableStringBuffer( var, s, sizeof(s) ); + Q_strncpyz(league_table[i].leaguename, s, sizeof(league_table[i].leaguename) ); + Q_strncpyz(league_table[i].buff, league_table[i].leaguename, sizeof(league_table[i].buff) ); + } + + s_specifyleague.list.numitems = count; +} + +/* +================= +SpecifyLeague_Event +================= +*/ +static void SpecifyLeague_Event( void* ptr, int event ) +{ + int id; + id = ((menucommon_s*)ptr)->id; + //if( event != QM_ACTIVATED && id != ID_SPECIFYLEAGUELIST ) { + // return; + //} + + switch (id) + { + case ID_SPECIFYLEAGUELIST: + if( event == QM_GOTFOCUS ) { + //ArenaServers_UpdatePicture(); + } + break; + + case ID_SPECIFYLEAGUEUP: + if( event == QM_ACTIVATED ) + ScrollList_Key( &s_specifyleague.list, K_UPARROW ); + break; + + case ID_SPECIFYLEAGUEDOWN: + if( event == QM_ACTIVATED ) + ScrollList_Key( &s_specifyleague.list, K_DOWNARROW ); + break; + + case ID_SPECIFYLEAGUENAME: + if( (event == QM_LOSTFOCUS) && + (Q_strncmp(playername, + s_specifyleague.rankname.field.buffer, + strlen(s_specifyleague.rankname.field.buffer)) != 0)) + { + SpecifyLeague_GetList(); + } + break; + + case ID_SPECIFYLEAGUEBACK: + if( event == QM_ACTIVATED ) + { + trap_Cvar_Set( "sv_leagueName", league_table[s_specifyleague.list.curvalue].leaguename); + UI_PopMenu(); + } + break; + } +} + +/* +================= +SpecifyLeague_MenuInit +================= +*/ +void SpecifyLeague_MenuInit( void ) +{ + int i; + // zero set all our globals + memset( &s_specifyleague, 0 ,sizeof(specifyleague_t) ); + + SpecifyLeague_Cache(); + + s_specifyleague.menu.wrapAround = qtrue; + s_specifyleague.menu.fullscreen = qtrue; + + s_specifyleague.banner.generic.type = MTYPE_BTEXT; + s_specifyleague.banner.generic.x = 320; + s_specifyleague.banner.generic.y = 16; + s_specifyleague.banner.string = "CHOOSE LEAGUE"; + s_specifyleague.banner.color = color_white; + s_specifyleague.banner.style = UI_CENTER; + + s_specifyleague.framel.generic.type = MTYPE_BITMAP; + s_specifyleague.framel.generic.name = SPECIFYLEAGUE_FRAMEL; + s_specifyleague.framel.generic.flags = QMF_INACTIVE; + s_specifyleague.framel.generic.x = 0; + s_specifyleague.framel.generic.y = 78; + s_specifyleague.framel.width = 256; + s_specifyleague.framel.height = 334; + + s_specifyleague.framer.generic.type = MTYPE_BITMAP; + s_specifyleague.framer.generic.name = SPECIFYLEAGUE_FRAMER; + s_specifyleague.framer.generic.flags = QMF_INACTIVE; + s_specifyleague.framer.generic.x = 376; + s_specifyleague.framer.generic.y = 76; + s_specifyleague.framer.width = 256; + s_specifyleague.framer.height = 334; + + s_specifyleague.grlogo.generic.type = MTYPE_BITMAP; + s_specifyleague.grlogo.generic.name = GLOBALRANKINGS_LOGO; + s_specifyleague.grlogo.generic.flags = QMF_INACTIVE; + s_specifyleague.grlogo.generic.x = 0; + s_specifyleague.grlogo.generic.y = 0; + s_specifyleague.grlogo.width = 64; + s_specifyleague.grlogo.height = 128; + + s_specifyleague.rankname.generic.type = MTYPE_FIELD; + s_specifyleague.rankname.generic.name = "Player Name:"; + s_specifyleague.rankname.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT; + s_specifyleague.rankname.generic.callback = SpecifyLeague_Event; + s_specifyleague.rankname.generic.id = ID_SPECIFYLEAGUENAME; + s_specifyleague.rankname.generic.x = 226; + s_specifyleague.rankname.generic.y = 128; + s_specifyleague.rankname.field.widthInChars = 32; + s_specifyleague.rankname.field.maxchars = 80; + + s_specifyleague.list.generic.type = MTYPE_SCROLLLIST; + s_specifyleague.list.generic.flags = QMF_HIGHLIGHT_IF_FOCUS; + s_specifyleague.list.generic.id = ID_SPECIFYLEAGUELIST; + s_specifyleague.list.generic.callback = SpecifyLeague_Event; + s_specifyleague.list.generic.x = 160; + s_specifyleague.list.generic.y = 200; + s_specifyleague.list.width = MAX_LISTBOXWIDTH; + s_specifyleague.list.height = 8; + s_specifyleague.list.itemnames = (const char **)leaguename_items; + s_specifyleague.list.numitems = 0; + for( i = 0; i < MAX_LISTBOXITEMS; i++ ) { + league_table[i].buff[0] = 0; + league_table[i].leaguename[0] = 0; + leaguename_items[i] = league_table[i].buff; + } + + s_specifyleague.arrows.generic.type = MTYPE_BITMAP; + s_specifyleague.arrows.generic.name = SPECIFYLEAGUE_ARROWS0; + s_specifyleague.arrows.generic.flags = QMF_LEFT_JUSTIFY|QMF_INACTIVE; + s_specifyleague.arrows.generic.callback = SpecifyLeague_Event; + s_specifyleague.arrows.generic.x = 512; + s_specifyleague.arrows.generic.y = 240-64+16; + s_specifyleague.arrows.width = 64; + s_specifyleague.arrows.height = 128; + + s_specifyleague.up.generic.type = MTYPE_BITMAP; + s_specifyleague.up.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_MOUSEONLY; + s_specifyleague.up.generic.callback = SpecifyLeague_Event; + s_specifyleague.up.generic.id = ID_SPECIFYLEAGUEUP; + s_specifyleague.up.generic.x = 512; + s_specifyleague.up.generic.y = 240-64+16; + s_specifyleague.up.width = 64; + s_specifyleague.up.height = 64; + s_specifyleague.up.focuspic = SPECIFYLEAGUE_UP; + + s_specifyleague.down.generic.type = MTYPE_BITMAP; + s_specifyleague.down.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_MOUSEONLY; + s_specifyleague.down.generic.callback = SpecifyLeague_Event; + s_specifyleague.down.generic.id = ID_SPECIFYLEAGUEDOWN; + s_specifyleague.down.generic.x = 512; + s_specifyleague.down.generic.y = 240+16; + s_specifyleague.down.width = 64; + s_specifyleague.down.height = 64; + s_specifyleague.down.focuspic = SPECIFYLEAGUE_DOWN; + + s_specifyleague.back.generic.type = MTYPE_BITMAP; + s_specifyleague.back.generic.name = SPECIFYLEAGUE_BACK0; + s_specifyleague.back.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS; + s_specifyleague.back.generic.callback = SpecifyLeague_Event; + s_specifyleague.back.generic.id = ID_SPECIFYLEAGUEBACK; + s_specifyleague.back.generic.x = 0; + s_specifyleague.back.generic.y = 480-64; + s_specifyleague.back.width = 128; + s_specifyleague.back.height = 64; + s_specifyleague.back.focuspic = SPECIFYLEAGUE_BACK1; + + Menu_AddItem( &s_specifyleague.menu, &s_specifyleague.banner ); + Menu_AddItem( &s_specifyleague.menu, &s_specifyleague.framel ); + Menu_AddItem( &s_specifyleague.menu, &s_specifyleague.framer ); + Menu_AddItem( &s_specifyleague.menu, &s_specifyleague.grlogo ); + Menu_AddItem( &s_specifyleague.menu, &s_specifyleague.rankname ); + Menu_AddItem( &s_specifyleague.menu, &s_specifyleague.list ); + Menu_AddItem( &s_specifyleague.menu, &s_specifyleague.arrows ); + Menu_AddItem( &s_specifyleague.menu, &s_specifyleague.up ); + Menu_AddItem( &s_specifyleague.menu, &s_specifyleague.down ); + Menu_AddItem( &s_specifyleague.menu, &s_specifyleague.back ); + + + // initialize any menu variables + Q_strncpyz( s_specifyleague.rankname.field.buffer, + UI_Cvar_VariableString("name"), + sizeof(s_specifyleague.rankname.field.buffer) ); + + Q_strncpyz( playername, + UI_Cvar_VariableString("name"), + sizeof(playername) ); + + SpecifyLeague_GetList(); +} + +/* +================= +SpecifyLeague_Cache +================= +*/ +void SpecifyLeague_Cache( void ) +{ + int i; + + // touch all our pics + for (i=0; ;i++) + { + if (!specifyleague_artlist[i]) + break; + trap_R_RegisterShaderNoMip(specifyleague_artlist[i]); + } +} + +/* +================= +UI_SpecifyLeagueMenu +================= +*/ +void UI_SpecifyLeagueMenu( void ) +{ + SpecifyLeague_MenuInit(); + UI_PushMenu( &s_specifyleague.menu ); +} + diff --git a/code/q3_ui/ui_specifyserver.c b/code/q3_ui/ui_specifyserver.c new file mode 100755 index 0000000..2df4418 --- /dev/null +++ b/code/q3_ui/ui_specifyserver.c @@ -0,0 +1,213 @@ +/* +=========================================================================== +Copyright (C) 1999-2005 Id Software, Inc. + +This file is part of Quake III Arena source code. + +Quake III Arena source code is free software; you can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 2 of the License, +or (at your option) any later version. + +Quake III Arena source code is distributed in the hope that it will be +useful, but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Foobar; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ +// +#include "ui_local.h" + +/********************************************************************************* + SPECIFY SERVER +*********************************************************************************/ + +#define SPECIFYSERVER_FRAMEL "menu/art/frame2_l" +#define SPECIFYSERVER_FRAMER "menu/art/frame1_r" +#define SPECIFYSERVER_BACK0 "menu/art/back_0" +#define SPECIFYSERVER_BACK1 "menu/art/back_1" +#define SPECIFYSERVER_FIGHT0 "menu/art/fight_0" +#define SPECIFYSERVER_FIGHT1 "menu/art/fight_1" + +#define ID_SPECIFYSERVERBACK 102 +#define ID_SPECIFYSERVERGO 103 + +static char* specifyserver_artlist[] = +{ + SPECIFYSERVER_FRAMEL, + SPECIFYSERVER_FRAMER, + SPECIFYSERVER_BACK0, + SPECIFYSERVER_BACK1, + SPECIFYSERVER_FIGHT0, + SPECIFYSERVER_FIGHT1, + NULL +}; + +typedef struct +{ + menuframework_s menu; + menutext_s banner; + menubitmap_s framel; + menubitmap_s framer; + menufield_s domain; + menufield_s port; + menubitmap_s go; + menubitmap_s back; +} specifyserver_t; + +static specifyserver_t s_specifyserver; + +/* +================= +SpecifyServer_Event +================= +*/ +static void SpecifyServer_Event( void* ptr, int event ) +{ + char buff[256]; + + switch (((menucommon_s*)ptr)->id) + { + case ID_SPECIFYSERVERGO: + if (event != QM_ACTIVATED) + break; + + if (s_specifyserver.domain.field.buffer[0]) + { + strcpy(buff,s_specifyserver.domain.field.buffer); + if (s_specifyserver.port.field.buffer[0]) + Com_sprintf( buff+strlen(buff), 128, ":%s", s_specifyserver.port.field.buffer ); + + trap_Cmd_ExecuteText( EXEC_APPEND, va( "connect %s\n", buff ) ); + } + break; + + case ID_SPECIFYSERVERBACK: + if (event != QM_ACTIVATED) + break; + + UI_PopMenu(); + break; + } +} + +/* +================= +SpecifyServer_MenuInit +================= +*/ +void SpecifyServer_MenuInit( void ) +{ + // zero set all our globals + memset( &s_specifyserver, 0 ,sizeof(specifyserver_t) ); + + SpecifyServer_Cache(); + + s_specifyserver.menu.wrapAround = qtrue; + s_specifyserver.menu.fullscreen = qtrue; + + s_specifyserver.banner.generic.type = MTYPE_BTEXT; + s_specifyserver.banner.generic.x = 320; + s_specifyserver.banner.generic.y = 16; + s_specifyserver.banner.string = "SPECIFY SERVER"; + s_specifyserver.banner.color = color_white; + s_specifyserver.banner.style = UI_CENTER; + + s_specifyserver.framel.generic.type = MTYPE_BITMAP; + s_specifyserver.framel.generic.name = SPECIFYSERVER_FRAMEL; + s_specifyserver.framel.generic.flags = QMF_INACTIVE; + s_specifyserver.framel.generic.x = 0; + s_specifyserver.framel.generic.y = 78; + s_specifyserver.framel.width = 256; + s_specifyserver.framel.height = 329; + + s_specifyserver.framer.generic.type = MTYPE_BITMAP; + s_specifyserver.framer.generic.name = SPECIFYSERVER_FRAMER; + s_specifyserver.framer.generic.flags = QMF_INACTIVE; + s_specifyserver.framer.generic.x = 376; + s_specifyserver.framer.generic.y = 76; + s_specifyserver.framer.width = 256; + s_specifyserver.framer.height = 334; + + s_specifyserver.domain.generic.type = MTYPE_FIELD; + s_specifyserver.domain.generic.name = "Address:"; + s_specifyserver.domain.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT; + s_specifyserver.domain.generic.x = 206; + s_specifyserver.domain.generic.y = 220; + s_specifyserver.domain.field.widthInChars = 38; + s_specifyserver.domain.field.maxchars = 80; + + s_specifyserver.port.generic.type = MTYPE_FIELD; + s_specifyserver.port.generic.name = "Port:"; + s_specifyserver.port.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT|QMF_NUMBERSONLY; + s_specifyserver.port.generic.x = 206; + s_specifyserver.port.generic.y = 250; + s_specifyserver.port.field.widthInChars = 6; + s_specifyserver.port.field.maxchars = 5; + + s_specifyserver.go.generic.type = MTYPE_BITMAP; + s_specifyserver.go.generic.name = SPECIFYSERVER_FIGHT0; + s_specifyserver.go.generic.flags = QMF_RIGHT_JUSTIFY|QMF_PULSEIFFOCUS; + s_specifyserver.go.generic.callback = SpecifyServer_Event; + s_specifyserver.go.generic.id = ID_SPECIFYSERVERGO; + s_specifyserver.go.generic.x = 640; + s_specifyserver.go.generic.y = 480-64; + s_specifyserver.go.width = 128; + s_specifyserver.go.height = 64; + s_specifyserver.go.focuspic = SPECIFYSERVER_FIGHT1; + + s_specifyserver.back.generic.type = MTYPE_BITMAP; + s_specifyserver.back.generic.name = SPECIFYSERVER_BACK0; + s_specifyserver.back.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS; + s_specifyserver.back.generic.callback = SpecifyServer_Event; + s_specifyserver.back.generic.id = ID_SPECIFYSERVERBACK; + s_specifyserver.back.generic.x = 0; + s_specifyserver.back.generic.y = 480-64; + s_specifyserver.back.width = 128; + s_specifyserver.back.height = 64; + s_specifyserver.back.focuspic = SPECIFYSERVER_BACK1; + + Menu_AddItem( &s_specifyserver.menu, &s_specifyserver.banner ); + Menu_AddItem( &s_specifyserver.menu, &s_specifyserver.framel ); + Menu_AddItem( &s_specifyserver.menu, &s_specifyserver.framer ); + Menu_AddItem( &s_specifyserver.menu, &s_specifyserver.domain ); + Menu_AddItem( &s_specifyserver.menu, &s_specifyserver.port ); + Menu_AddItem( &s_specifyserver.menu, &s_specifyserver.go ); + Menu_AddItem( &s_specifyserver.menu, &s_specifyserver.back ); + + Com_sprintf( s_specifyserver.port.field.buffer, 6, "%i", 27960 ); +} + +/* +================= +SpecifyServer_Cache +================= +*/ +void SpecifyServer_Cache( void ) +{ + int i; + + // touch all our pics + for (i=0; ;i++) + { + if (!specifyserver_artlist[i]) + break; + trap_R_RegisterShaderNoMip(specifyserver_artlist[i]); + } +} + +/* +================= +UI_SpecifyServerMenu +================= +*/ +void UI_SpecifyServerMenu( void ) +{ + SpecifyServer_MenuInit(); + UI_PushMenu( &s_specifyserver.menu ); +} + diff --git a/code/q3_ui/ui_splevel.c b/code/q3_ui/ui_splevel.c new file mode 100755 index 0000000..0c57500 --- /dev/null +++ b/code/q3_ui/ui_splevel.c @@ -0,0 +1,1008 @@ +/* +=========================================================================== +Copyright (C) 1999-2005 Id Software, Inc. + +This file is part of Quake III Arena source code. + +Quake III Arena source code is free software; you can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 2 of the License, +or (at your option) any later version. + +Quake III Arena source code is distributed in the hope that it will be +useful, but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Foobar; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ +// +/* +============================================================================= + +SINGLE PLAYER LEVEL SELECT MENU + +============================================================================= +*/ + +#include "ui_local.h" + + +#define ART_LEVELFRAME_FOCUS "menu/art/maps_select" +#define ART_LEVELFRAME_SELECTED "menu/art/maps_selected" +#define ART_ARROW "menu/art/narrow_0" +#define ART_ARROW_FOCUS "menu/art/narrow_1" +#define ART_MAP_UNKNOWN "menu/art/unknownmap" +#define ART_MAP_COMPLETE1 "menu/art/level_complete1" +#define ART_MAP_COMPLETE2 "menu/art/level_complete2" +#define ART_MAP_COMPLETE3 "menu/art/level_complete3" +#define ART_MAP_COMPLETE4 "menu/art/level_complete4" +#define ART_MAP_COMPLETE5 "menu/art/level_complete5" +#define ART_BACK0 "menu/art/back_0" +#define ART_BACK1 "menu/art/back_1" +#define ART_FIGHT0 "menu/art/fight_0" +#define ART_FIGHT1 "menu/art/fight_1" +#define ART_RESET0 "menu/art/reset_0" +#define ART_RESET1 "menu/art/reset_1" +#define ART_CUSTOM0 "menu/art/skirmish_0" +#define ART_CUSTOM1 "menu/art/skirmish_1" + +#define ID_LEFTARROW 10 +#define ID_PICTURE0 11 +#define ID_PICTURE1 12 +#define ID_PICTURE2 13 +#define ID_PICTURE3 14 +#define ID_RIGHTARROW 15 +#define ID_PLAYERPIC 16 +#define ID_AWARD1 17 +#define ID_AWARD2 18 +#define ID_AWARD3 19 +#define ID_AWARD4 20 +#define ID_AWARD5 21 +#define ID_AWARD6 22 +#define ID_BACK 23 +#define ID_RESET 24 +#define ID_CUSTOM 25 +#define ID_NEXT 26 + +#define PLAYER_Y 314 +#define AWARDS_Y (PLAYER_Y + 26) + + +typedef struct { + menuframework_s menu; + menutext_s item_banner; + menubitmap_s item_leftarrow; + menubitmap_s item_maps[4]; + menubitmap_s item_rightarrow; + menubitmap_s item_player; + menubitmap_s item_awards[6]; + menubitmap_s item_back; + menubitmap_s item_reset; + menubitmap_s item_custom; + menubitmap_s item_next; + menubitmap_s item_null; + + qboolean reinit; + + const char * selectedArenaInfo; + int numMaps; + char levelPicNames[4][MAX_QPATH]; + char levelNames[4][16]; + int levelScores[4]; + int levelScoresSkill[4]; + qhandle_t levelSelectedPic; + qhandle_t levelFocusPic; + qhandle_t levelCompletePic[5]; + + char playerModel[MAX_QPATH]; + char playerPicName[MAX_QPATH]; + int awardLevels[6]; + sfxHandle_t awardSounds[6]; + + int numBots; + qhandle_t botPics[7]; + char botNames[7][10]; +} levelMenuInfo_t; + +static levelMenuInfo_t levelMenuInfo; + +static int selectedArenaSet; +static int selectedArena; +static int currentSet; +static int currentGame; +static int trainingTier; +static int finalTier; +static int minTier; +static int maxTier; + + +/* +================= +PlayerIcon +================= +*/ +static void PlayerIcon( const char *modelAndSkin, char *iconName, int iconNameMaxSize ) { + char *skin; + char model[MAX_QPATH]; + + Q_strncpyz( model, modelAndSkin, sizeof(model)); + skin = Q_strrchr( model, '/' ); + if ( skin ) { + *skin++ = '\0'; + } + else { + skin = "default"; + } + + Com_sprintf(iconName, iconNameMaxSize, "models/players/%s/icon_%s.tga", model, skin ); + + if( !trap_R_RegisterShaderNoMip( iconName ) && Q_stricmp( skin, "default" ) != 0 ) { + Com_sprintf(iconName, iconNameMaxSize, "models/players/%s/icon_default.tga", model ); + } +} + + +/* +================= +PlayerIconhandle +================= +*/ +static qhandle_t PlayerIconHandle( const char *modelAndSkin ) { + char iconName[MAX_QPATH]; + + PlayerIcon( modelAndSkin, iconName, sizeof(iconName) ); + return trap_R_RegisterShaderNoMip( iconName ); +} + + +/* +================= +UI_SPLevelMenu_SetBots +================= +*/ +static void UI_SPLevelMenu_SetBots( void ) { + char *p; + char *bot; + char *botInfo; + char bots[MAX_INFO_STRING]; + + levelMenuInfo.numBots = 0; + if ( selectedArenaSet > currentSet ) { + return; + } + + Q_strncpyz( bots, Info_ValueForKey( levelMenuInfo.selectedArenaInfo, "bots" ), sizeof(bots) ); + + p = &bots[0]; + while( *p && levelMenuInfo.numBots < 7 ) { + //skip spaces + while( *p && *p == ' ' ) { + p++; + } + if( !p ) { + break; + } + + // mark start of bot name + bot = p; + + // skip until space of null + while( *p && *p != ' ' ) { + p++; + } + if( *p ) { + *p++ = 0; + } + + botInfo = UI_GetBotInfoByName( bot ); + if( botInfo ) { + levelMenuInfo.botPics[levelMenuInfo.numBots] = PlayerIconHandle( Info_ValueForKey( botInfo, "model" ) ); + Q_strncpyz( levelMenuInfo.botNames[levelMenuInfo.numBots], Info_ValueForKey( botInfo, "name" ), 10 ); + } + else { + levelMenuInfo.botPics[levelMenuInfo.numBots] = 0; + Q_strncpyz( levelMenuInfo.botNames[levelMenuInfo.numBots], bot, 10 ); + } + Q_CleanStr( levelMenuInfo.botNames[levelMenuInfo.numBots] ); + levelMenuInfo.numBots++; + } +} + + +/* +================= +UI_SPLevelMenu_SetMenuItems +================= +*/ +static void UI_SPLevelMenu_SetMenuArena( int n, int level, const char *arenaInfo ) { + char map[MAX_QPATH]; + + Q_strncpyz( map, Info_ValueForKey( arenaInfo, "map" ), sizeof(map) ); + + Q_strncpyz( levelMenuInfo.levelNames[n], map, sizeof(levelMenuInfo.levelNames[n]) ); + Q_strupr( levelMenuInfo.levelNames[n] ); + + UI_GetBestScore( level, &levelMenuInfo.levelScores[n], &levelMenuInfo.levelScoresSkill[n] ); + if( levelMenuInfo.levelScores[n] > 8 ) { + levelMenuInfo.levelScores[n] = 8; + } + + strcpy( levelMenuInfo.levelPicNames[n], va( "levelshots/%s.tga", map ) ); + if( !trap_R_RegisterShaderNoMip( levelMenuInfo.levelPicNames[n] ) ) { + strcpy( levelMenuInfo.levelPicNames[n], ART_MAP_UNKNOWN ); + } + levelMenuInfo.item_maps[n].shader = 0; + if ( selectedArenaSet > currentSet ) { + levelMenuInfo.item_maps[n].generic.flags |= QMF_GRAYED; + } + else { + levelMenuInfo.item_maps[n].generic.flags &= ~QMF_GRAYED; + } + + levelMenuInfo.item_maps[n].generic.flags &= ~QMF_INACTIVE; +} + +static void UI_SPLevelMenu_SetMenuItems( void ) { + int n; + int level; + const char *arenaInfo; + + if ( selectedArenaSet > currentSet ) { + selectedArena = -1; + } + else if ( selectedArena == -1 ) { + selectedArena = 0; + } + + if( selectedArenaSet == trainingTier || selectedArenaSet == finalTier ) { + selectedArena = 0; + } + + if( selectedArena != -1 ) { + trap_Cvar_SetValue( "ui_spSelection", selectedArenaSet * ARENAS_PER_TIER + selectedArena ); + } + + if( selectedArenaSet == trainingTier ) { + arenaInfo = UI_GetSpecialArenaInfo( "training" ); + level = atoi( Info_ValueForKey( arenaInfo, "num" ) ); + UI_SPLevelMenu_SetMenuArena( 0, level, arenaInfo ); + levelMenuInfo.selectedArenaInfo = arenaInfo; + + levelMenuInfo.item_maps[0].generic.x = 256; + Bitmap_Init( &levelMenuInfo.item_maps[0] ); + levelMenuInfo.item_maps[0].generic.bottom += 32; + levelMenuInfo.numMaps = 1; + + levelMenuInfo.item_maps[1].generic.flags |= QMF_INACTIVE; + levelMenuInfo.item_maps[2].generic.flags |= QMF_INACTIVE; + levelMenuInfo.item_maps[3].generic.flags |= QMF_INACTIVE; + levelMenuInfo.levelPicNames[1][0] = 0; + levelMenuInfo.levelPicNames[2][0] = 0; + levelMenuInfo.levelPicNames[3][0] = 0; + levelMenuInfo.item_maps[1].shader = 0; + levelMenuInfo.item_maps[2].shader = 0; + levelMenuInfo.item_maps[3].shader = 0; + } + else if( selectedArenaSet == finalTier ) { + arenaInfo = UI_GetSpecialArenaInfo( "final" ); + level = atoi( Info_ValueForKey( arenaInfo, "num" ) ); + UI_SPLevelMenu_SetMenuArena( 0, level, arenaInfo ); + levelMenuInfo.selectedArenaInfo = arenaInfo; + + levelMenuInfo.item_maps[0].generic.x = 256; + Bitmap_Init( &levelMenuInfo.item_maps[0] ); + levelMenuInfo.item_maps[0].generic.bottom += 32; + levelMenuInfo.numMaps = 1; + + levelMenuInfo.item_maps[1].generic.flags |= QMF_INACTIVE; + levelMenuInfo.item_maps[2].generic.flags |= QMF_INACTIVE; + levelMenuInfo.item_maps[3].generic.flags |= QMF_INACTIVE; + levelMenuInfo.levelPicNames[1][0] = 0; + levelMenuInfo.levelPicNames[2][0] = 0; + levelMenuInfo.levelPicNames[3][0] = 0; + levelMenuInfo.item_maps[1].shader = 0; + levelMenuInfo.item_maps[2].shader = 0; + levelMenuInfo.item_maps[3].shader = 0; + } + else { + levelMenuInfo.item_maps[0].generic.x = 46; + Bitmap_Init( &levelMenuInfo.item_maps[0] ); + levelMenuInfo.item_maps[0].generic.bottom += 18; + levelMenuInfo.numMaps = 4; + + for ( n = 0; n < 4; n++ ) { + level = selectedArenaSet * ARENAS_PER_TIER + n; + arenaInfo = UI_GetArenaInfoByNumber( level ); + UI_SPLevelMenu_SetMenuArena( n, level, arenaInfo ); + } + + if( selectedArena != -1 ) { + levelMenuInfo.selectedArenaInfo = UI_GetArenaInfoByNumber( selectedArenaSet * ARENAS_PER_TIER + selectedArena ); + } + } + + // enable/disable arrows when they are valid/invalid + if ( selectedArenaSet == minTier ) { + levelMenuInfo.item_leftarrow.generic.flags |= ( QMF_INACTIVE | QMF_HIDDEN ); + } + else { + levelMenuInfo.item_leftarrow.generic.flags &= ~( QMF_INACTIVE | QMF_HIDDEN ); + } + + if ( selectedArenaSet == maxTier ) { + levelMenuInfo.item_rightarrow.generic.flags |= ( QMF_INACTIVE | QMF_HIDDEN ); + } + else { + levelMenuInfo.item_rightarrow.generic.flags &= ~( QMF_INACTIVE | QMF_HIDDEN ); + } + + UI_SPLevelMenu_SetBots(); +} + + +/* +================= +UI_SPLevelMenu_ResetEvent +================= +*/ +static void UI_SPLevelMenu_ResetDraw( void ) { + UI_DrawProportionalString( SCREEN_WIDTH/2, 356 + PROP_HEIGHT * 0, "WARNING: This resets all of the", UI_CENTER|UI_SMALLFONT, color_yellow ); + UI_DrawProportionalString( SCREEN_WIDTH/2, 356 + PROP_HEIGHT * 1, "single player game variables.", UI_CENTER|UI_SMALLFONT, color_yellow ); + UI_DrawProportionalString( SCREEN_WIDTH/2, 356 + PROP_HEIGHT * 2, "Do this only if you want to", UI_CENTER|UI_SMALLFONT, color_yellow ); + UI_DrawProportionalString( SCREEN_WIDTH/2, 356 + PROP_HEIGHT * 3, "start over from the beginning.", UI_CENTER|UI_SMALLFONT, color_yellow ); +} + +static void UI_SPLevelMenu_ResetAction( qboolean result ) { + if( !result ) { + return; + } + + // clear game variables + UI_NewGame(); + trap_Cvar_SetValue( "ui_spSelection", -4 ); + + // make the level select menu re-initialize + UI_PopMenu(); + UI_SPLevelMenu(); +} + +static void UI_SPLevelMenu_ResetEvent( void* ptr, int event ) +{ + if (event != QM_ACTIVATED) { + return; + } + + UI_ConfirmMenu( "RESET GAME?", UI_SPLevelMenu_ResetDraw, UI_SPLevelMenu_ResetAction ); +} + + +/* +================= +UI_SPLevelMenu_LevelEvent +================= +*/ +static void UI_SPLevelMenu_LevelEvent( void* ptr, int notification ) { + if (notification != QM_ACTIVATED) { + return; + } + + if ( selectedArenaSet == trainingTier || selectedArenaSet == finalTier ) { + return; + } + + selectedArena = ((menucommon_s*)ptr)->id - ID_PICTURE0; + levelMenuInfo.selectedArenaInfo = UI_GetArenaInfoByNumber( selectedArenaSet * ARENAS_PER_TIER + selectedArena ); + UI_SPLevelMenu_SetBots(); + + trap_Cvar_SetValue( "ui_spSelection", selectedArenaSet * ARENAS_PER_TIER + selectedArena ); +} + + +/* +================= +UI_SPLevelMenu_LeftArrowEvent +================= +*/ +static void UI_SPLevelMenu_LeftArrowEvent( void* ptr, int notification ) { + if (notification != QM_ACTIVATED) { + return; + } + + if ( selectedArenaSet == minTier ) { + return; + } + + selectedArenaSet--; + UI_SPLevelMenu_SetMenuItems(); +} + + +/* +================= +UI_SPLevelMenu_RightArrowEvent +================= +*/ +static void UI_SPLevelMenu_RightArrowEvent( void* ptr, int notification ) { + if (notification != QM_ACTIVATED) { + return; + } + + if ( selectedArenaSet == maxTier ) { + return; + } + + selectedArenaSet++; + UI_SPLevelMenu_SetMenuItems(); +} + + +/* +================= +UI_SPLevelMenu_PlayerEvent +================= +*/ +static void UI_SPLevelMenu_PlayerEvent( void* ptr, int notification ) { + if (notification != QM_ACTIVATED) { + return; + } + + UI_PlayerSettingsMenu(); +} + + +/* +================= +UI_SPLevelMenu_AwardEvent +================= +*/ +static void UI_SPLevelMenu_AwardEvent( void* ptr, int notification ) { + int n; + + if (notification != QM_ACTIVATED) { + return; + } + + n = ((menucommon_s*)ptr)->id - ID_AWARD1; + trap_S_StartLocalSound( levelMenuInfo.awardSounds[n], CHAN_ANNOUNCER ); +} + + +/* +================= +UI_SPLevelMenu_NextEvent +================= +*/ +static void UI_SPLevelMenu_NextEvent( void* ptr, int notification ) { + if (notification != QM_ACTIVATED) { + return; + } + + if ( selectedArenaSet > currentSet ) { + return; + } + + if ( selectedArena == -1 ) { + selectedArena = 0; + } + + UI_SPSkillMenu( levelMenuInfo.selectedArenaInfo ); +} + + +/* +================= +UI_SPLevelMenu_BackEvent +================= +*/ +static void UI_SPLevelMenu_BackEvent( void* ptr, int notification ) { + if (notification != QM_ACTIVATED) { + return; + } + + if ( selectedArena == -1 ) { + selectedArena = 0; + } + + UI_PopMenu(); +} + + +/* +================= +UI_SPLevelMenu_CustomEvent +================= +*/ +static void UI_SPLevelMenu_CustomEvent( void* ptr, int notification ) { + if (notification != QM_ACTIVATED) { + return; + } + + UI_StartServerMenu( qfalse ); +} + + +/* +================= +UI_SPLevelMenu_MenuDraw +================= +*/ +#define LEVEL_DESC_LEFT_MARGIN 332 + +static void UI_SPLevelMenu_MenuDraw( void ) { + int n, i; + int x, y; + vec4_t color; + int level; +// int fraglimit; + int pad; + char buf[MAX_INFO_VALUE]; + char string[64]; + + if( levelMenuInfo.reinit ) { + UI_PopMenu(); + UI_SPLevelMenu(); + return; + } + + // draw player name + trap_Cvar_VariableStringBuffer( "name", string, 32 ); + Q_CleanStr( string ); + UI_DrawProportionalString( 320, PLAYER_Y, string, UI_CENTER|UI_SMALLFONT, color_orange ); + + // check for model changes + trap_Cvar_VariableStringBuffer( "model", buf, sizeof(buf) ); + if( Q_stricmp( buf, levelMenuInfo.playerModel ) != 0 ) { + Q_strncpyz( levelMenuInfo.playerModel, buf, sizeof(levelMenuInfo.playerModel) ); + PlayerIcon( levelMenuInfo.playerModel, levelMenuInfo.playerPicName, sizeof(levelMenuInfo.playerPicName) ); + levelMenuInfo.item_player.shader = 0; + } + + // standard menu drawing + Menu_Draw( &levelMenuInfo.menu ); + + // draw player award levels + y = AWARDS_Y; + i = 0; + for( n = 0; n < 6; n++ ) { + level = levelMenuInfo.awardLevels[n]; + if( level > 0 ) { + if( i & 1 ) { + x = 224 - (i - 1 ) / 2 * (48 + 16); + } + else { + x = 368 + i / 2 * (48 + 16); + } + i++; + + if( level == 1 ) { + continue; + } + + if( level >= 1000000 ) { + Com_sprintf( string, sizeof(string), "%im", level / 1000000 ); + } + else if( level >= 1000 ) { + Com_sprintf( string, sizeof(string), "%ik", level / 1000 ); + } + else { + Com_sprintf( string, sizeof(string), "%i", level ); + } + + UI_DrawString( x + 24, y + 48, string, UI_CENTER, color_yellow ); + } + } + + UI_DrawProportionalString( 18, 38, va( "Tier %i", selectedArenaSet + 1 ), UI_LEFT|UI_SMALLFONT, color_orange ); + + for ( n = 0; n < levelMenuInfo.numMaps; n++ ) { + x = levelMenuInfo.item_maps[n].generic.x; + y = levelMenuInfo.item_maps[n].generic.y; + UI_FillRect( x, y + 96, 128, 18, color_black ); + } + + if ( selectedArenaSet > currentSet ) { + UI_DrawProportionalString( 320, 216, "ACCESS DENIED", UI_CENTER|UI_BIGFONT, color_red ); + return; + } + + // show levelshots for levels of current tier + Vector4Copy( color_white, color ); + color[3] = 0.5+0.5*sin(uis.realtime/PULSE_DIVISOR); + for ( n = 0; n < levelMenuInfo.numMaps; n++ ) { + x = levelMenuInfo.item_maps[n].generic.x; + y = levelMenuInfo.item_maps[n].generic.y; + + UI_DrawString( x + 64, y + 96, levelMenuInfo.levelNames[n], UI_CENTER|UI_SMALLFONT, color_orange ); + + if( levelMenuInfo.levelScores[n] == 1 ) { + UI_DrawHandlePic( x, y, 128, 96, levelMenuInfo.levelCompletePic[levelMenuInfo.levelScoresSkill[n] - 1] ); + } + + if ( n == selectedArena ) { + if( Menu_ItemAtCursor( &levelMenuInfo.menu ) == &levelMenuInfo.item_maps[n] ) { + trap_R_SetColor( color ); + } + UI_DrawHandlePic( x-1, y-1, 130, 130 - 14, levelMenuInfo.levelSelectedPic ); + trap_R_SetColor( NULL ); + } + else if( Menu_ItemAtCursor( &levelMenuInfo.menu ) == &levelMenuInfo.item_maps[n] ) { + trap_R_SetColor( color ); + UI_DrawHandlePic( x-31, y-30, 256, 256-27, levelMenuInfo.levelFocusPic); + trap_R_SetColor( NULL ); + } + } + + // show map name and long name of selected level + y = 192; + Q_strncpyz( buf, Info_ValueForKey( levelMenuInfo.selectedArenaInfo, "map" ), 20 ); + Q_strupr( buf ); + Com_sprintf( string, sizeof(string), "%s: %s", buf, Info_ValueForKey( levelMenuInfo.selectedArenaInfo, "longname" ) ); + UI_DrawProportionalString( 320, y, string, UI_CENTER|UI_SMALLFONT, color_orange ); + +// fraglimit = atoi( Info_ValueForKey( levelMenuInfo.selectedArenaInfo, "fraglimit" ) ); +// UI_DrawString( 18, 212, va("Frags %i", fraglimit) , UI_LEFT|UI_SMALLFONT, color_orange ); + + // draw bot opponents + y += 24; + pad = (7 - levelMenuInfo.numBots) * (64 + 26) / 2; + for( n = 0; n < levelMenuInfo.numBots; n++ ) { + x = 18 + pad + (64 + 26) * n; + if( levelMenuInfo.botPics[n] ) { + UI_DrawHandlePic( x, y, 64, 64, levelMenuInfo.botPics[n]); + } + else { + UI_FillRect( x, y, 64, 64, color_black ); + UI_DrawProportionalString( x+22, y+18, "?", UI_BIGFONT, color_orange ); + } + UI_DrawString( x, y + 64, levelMenuInfo.botNames[n], UI_SMALLFONT|UI_LEFT, color_orange ); + } +} + + +/* +================= +UI_SPLevelMenu_Cache +================= +*/ +void UI_SPLevelMenu_Cache( void ) { + int n; + + trap_R_RegisterShaderNoMip( ART_LEVELFRAME_FOCUS ); + trap_R_RegisterShaderNoMip( ART_LEVELFRAME_SELECTED ); + trap_R_RegisterShaderNoMip( ART_ARROW ); + trap_R_RegisterShaderNoMip( ART_ARROW_FOCUS ); + trap_R_RegisterShaderNoMip( ART_MAP_UNKNOWN ); + trap_R_RegisterShaderNoMip( ART_MAP_COMPLETE1 ); + trap_R_RegisterShaderNoMip( ART_MAP_COMPLETE2 ); + trap_R_RegisterShaderNoMip( ART_MAP_COMPLETE3 ); + trap_R_RegisterShaderNoMip( ART_MAP_COMPLETE4 ); + trap_R_RegisterShaderNoMip( ART_MAP_COMPLETE5 ); + trap_R_RegisterShaderNoMip( ART_BACK0 ); + trap_R_RegisterShaderNoMip( ART_BACK1 ); + trap_R_RegisterShaderNoMip( ART_FIGHT0 ); + trap_R_RegisterShaderNoMip( ART_FIGHT1 ); + trap_R_RegisterShaderNoMip( ART_RESET0 ); + trap_R_RegisterShaderNoMip( ART_RESET1 ); + trap_R_RegisterShaderNoMip( ART_CUSTOM0 ); + trap_R_RegisterShaderNoMip( ART_CUSTOM1 ); + + for( n = 0; n < 6; n++ ) { + trap_R_RegisterShaderNoMip( ui_medalPicNames[n] ); + levelMenuInfo.awardSounds[n] = trap_S_RegisterSound( ui_medalSounds[n], qfalse ); + } + + levelMenuInfo.levelSelectedPic = trap_R_RegisterShaderNoMip( ART_LEVELFRAME_SELECTED ); + levelMenuInfo.levelFocusPic = trap_R_RegisterShaderNoMip( ART_LEVELFRAME_FOCUS ); + levelMenuInfo.levelCompletePic[0] = trap_R_RegisterShaderNoMip( ART_MAP_COMPLETE1 ); + levelMenuInfo.levelCompletePic[1] = trap_R_RegisterShaderNoMip( ART_MAP_COMPLETE2 ); + levelMenuInfo.levelCompletePic[2] = trap_R_RegisterShaderNoMip( ART_MAP_COMPLETE3 ); + levelMenuInfo.levelCompletePic[3] = trap_R_RegisterShaderNoMip( ART_MAP_COMPLETE4 ); + levelMenuInfo.levelCompletePic[4] = trap_R_RegisterShaderNoMip( ART_MAP_COMPLETE5 ); +} + + +/* +================= +UI_SPLevelMenu_Init +================= +*/ +static void UI_SPLevelMenu_Init( void ) { + int skill; + int n; + int x, y; + int count; + char buf[MAX_QPATH]; + + skill = (int)trap_Cvar_VariableValue( "g_spSkill" ); + if( skill < 1 || skill > 5 ) { + trap_Cvar_Set( "g_spSkill", "2" ); + skill = 2; + } + + memset( &levelMenuInfo, 0, sizeof(levelMenuInfo) ); + levelMenuInfo.menu.fullscreen = qtrue; + levelMenuInfo.menu.wrapAround = qtrue; + levelMenuInfo.menu.draw = UI_SPLevelMenu_MenuDraw; + + UI_SPLevelMenu_Cache(); + + levelMenuInfo.item_banner.generic.type = MTYPE_BTEXT; + levelMenuInfo.item_banner.generic.x = 320; + levelMenuInfo.item_banner.generic.y = 16; + levelMenuInfo.item_banner.string = "CHOOSE LEVEL"; + levelMenuInfo.item_banner.color = color_red; + levelMenuInfo.item_banner.style = UI_CENTER; + + levelMenuInfo.item_leftarrow.generic.type = MTYPE_BITMAP; + levelMenuInfo.item_leftarrow.generic.name = ART_ARROW; + levelMenuInfo.item_leftarrow.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS; + levelMenuInfo.item_leftarrow.generic.x = 18; + levelMenuInfo.item_leftarrow.generic.y = 64; + levelMenuInfo.item_leftarrow.generic.callback = UI_SPLevelMenu_LeftArrowEvent; + levelMenuInfo.item_leftarrow.generic.id = ID_LEFTARROW; + levelMenuInfo.item_leftarrow.width = 16; + levelMenuInfo.item_leftarrow.height = 114; + levelMenuInfo.item_leftarrow.focuspic = ART_ARROW_FOCUS; + + levelMenuInfo.item_maps[0].generic.type = MTYPE_BITMAP; + levelMenuInfo.item_maps[0].generic.name = levelMenuInfo.levelPicNames[0]; + levelMenuInfo.item_maps[0].generic.flags = QMF_LEFT_JUSTIFY; + levelMenuInfo.item_maps[0].generic.x = 46; + levelMenuInfo.item_maps[0].generic.y = 64; + levelMenuInfo.item_maps[0].generic.id = ID_PICTURE0; + levelMenuInfo.item_maps[0].generic.callback = UI_SPLevelMenu_LevelEvent; + levelMenuInfo.item_maps[0].width = 128; + levelMenuInfo.item_maps[0].height = 96; + + levelMenuInfo.item_maps[1].generic.type = MTYPE_BITMAP; + levelMenuInfo.item_maps[1].generic.name = levelMenuInfo.levelPicNames[1]; + levelMenuInfo.item_maps[1].generic.flags = QMF_LEFT_JUSTIFY; + levelMenuInfo.item_maps[1].generic.x = 186; + levelMenuInfo.item_maps[1].generic.y = 64; + levelMenuInfo.item_maps[1].generic.id = ID_PICTURE1; + levelMenuInfo.item_maps[1].generic.callback = UI_SPLevelMenu_LevelEvent; + levelMenuInfo.item_maps[1].width = 128; + levelMenuInfo.item_maps[1].height = 96; + + levelMenuInfo.item_maps[2].generic.type = MTYPE_BITMAP; + levelMenuInfo.item_maps[2].generic.name = levelMenuInfo.levelPicNames[2]; + levelMenuInfo.item_maps[2].generic.flags = QMF_LEFT_JUSTIFY; + levelMenuInfo.item_maps[2].generic.x = 326; + levelMenuInfo.item_maps[2].generic.y = 64; + levelMenuInfo.item_maps[2].generic.id = ID_PICTURE2; + levelMenuInfo.item_maps[2].generic.callback = UI_SPLevelMenu_LevelEvent; + levelMenuInfo.item_maps[2].width = 128; + levelMenuInfo.item_maps[2].height = 96; + + levelMenuInfo.item_maps[3].generic.type = MTYPE_BITMAP; + levelMenuInfo.item_maps[3].generic.name = levelMenuInfo.levelPicNames[3]; + levelMenuInfo.item_maps[3].generic.flags = QMF_LEFT_JUSTIFY; + levelMenuInfo.item_maps[3].generic.x = 466; + levelMenuInfo.item_maps[3].generic.y = 64; + levelMenuInfo.item_maps[3].generic.id = ID_PICTURE3; + levelMenuInfo.item_maps[3].generic.callback = UI_SPLevelMenu_LevelEvent; + levelMenuInfo.item_maps[3].width = 128; + levelMenuInfo.item_maps[3].height = 96; + + levelMenuInfo.item_rightarrow.generic.type = MTYPE_BITMAP; + levelMenuInfo.item_rightarrow.generic.name = ART_ARROW; + levelMenuInfo.item_rightarrow.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS; + levelMenuInfo.item_rightarrow.generic.x = 606; + levelMenuInfo.item_rightarrow.generic.y = 64; + levelMenuInfo.item_rightarrow.generic.callback = UI_SPLevelMenu_RightArrowEvent; + levelMenuInfo.item_rightarrow.generic.id = ID_RIGHTARROW; + levelMenuInfo.item_rightarrow.width = -16; + levelMenuInfo.item_rightarrow.height = 114; + levelMenuInfo.item_rightarrow.focuspic = ART_ARROW_FOCUS; + + trap_Cvar_VariableStringBuffer( "model", levelMenuInfo.playerModel, sizeof(levelMenuInfo.playerModel) ); + PlayerIcon( levelMenuInfo.playerModel, levelMenuInfo.playerPicName, sizeof(levelMenuInfo.playerPicName) ); + levelMenuInfo.item_player.generic.type = MTYPE_BITMAP; + levelMenuInfo.item_player.generic.name = levelMenuInfo.playerPicName; + levelMenuInfo.item_player.generic.flags = QMF_LEFT_JUSTIFY|QMF_MOUSEONLY; + levelMenuInfo.item_player.generic.x = 288; + levelMenuInfo.item_player.generic.y = AWARDS_Y; + levelMenuInfo.item_player.generic.id = ID_PLAYERPIC; + levelMenuInfo.item_player.generic.callback = UI_SPLevelMenu_PlayerEvent; + levelMenuInfo.item_player.width = 64; + levelMenuInfo.item_player.height = 64; + + for( n = 0; n < 6; n++ ) { + levelMenuInfo.awardLevels[n] = UI_GetAwardLevel( n ); + } + levelMenuInfo.awardLevels[AWARD_FRAGS] = 100 * (levelMenuInfo.awardLevels[AWARD_FRAGS] / 100); + + y = AWARDS_Y; + count = 0; + for( n = 0; n < 6; n++ ) { + if( levelMenuInfo.awardLevels[n] ) { + if( count & 1 ) { + x = 224 - (count - 1 ) / 2 * (48 + 16); + } + else { + x = 368 + count / 2 * (48 + 16); + } + + levelMenuInfo.item_awards[count].generic.type = MTYPE_BITMAP; + levelMenuInfo.item_awards[count].generic.name = ui_medalPicNames[n]; + levelMenuInfo.item_awards[count].generic.flags = QMF_LEFT_JUSTIFY|QMF_SILENT|QMF_MOUSEONLY; + levelMenuInfo.item_awards[count].generic.x = x; + levelMenuInfo.item_awards[count].generic.y = y; + levelMenuInfo.item_awards[count].generic.id = ID_AWARD1 + n; + levelMenuInfo.item_awards[count].generic.callback = UI_SPLevelMenu_AwardEvent; + levelMenuInfo.item_awards[count].width = 48; + levelMenuInfo.item_awards[count].height = 48; + count++; + } + } + + levelMenuInfo.item_back.generic.type = MTYPE_BITMAP; + levelMenuInfo.item_back.generic.name = ART_BACK0; + levelMenuInfo.item_back.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS; + levelMenuInfo.item_back.generic.x = 0; + levelMenuInfo.item_back.generic.y = 480-64; + levelMenuInfo.item_back.generic.callback = UI_SPLevelMenu_BackEvent; + levelMenuInfo.item_back.generic.id = ID_BACK; + levelMenuInfo.item_back.width = 128; + levelMenuInfo.item_back.height = 64; + levelMenuInfo.item_back.focuspic = ART_BACK1; + + levelMenuInfo.item_reset.generic.type = MTYPE_BITMAP; + levelMenuInfo.item_reset.generic.name = ART_RESET0; + levelMenuInfo.item_reset.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS; + levelMenuInfo.item_reset.generic.x = 170; + levelMenuInfo.item_reset.generic.y = 480-64; + levelMenuInfo.item_reset.generic.callback = UI_SPLevelMenu_ResetEvent; + levelMenuInfo.item_reset.generic.id = ID_RESET; + levelMenuInfo.item_reset.width = 128; + levelMenuInfo.item_reset.height = 64; + levelMenuInfo.item_reset.focuspic = ART_RESET1; + + levelMenuInfo.item_custom.generic.type = MTYPE_BITMAP; + levelMenuInfo.item_custom.generic.name = ART_CUSTOM0; + levelMenuInfo.item_custom.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS; + levelMenuInfo.item_custom.generic.x = 342; + levelMenuInfo.item_custom.generic.y = 480-64; + levelMenuInfo.item_custom.generic.callback = UI_SPLevelMenu_CustomEvent; + levelMenuInfo.item_custom.generic.id = ID_CUSTOM; + levelMenuInfo.item_custom.width = 128; + levelMenuInfo.item_custom.height = 64; + levelMenuInfo.item_custom.focuspic = ART_CUSTOM1; + + levelMenuInfo.item_next.generic.type = MTYPE_BITMAP; + levelMenuInfo.item_next.generic.name = ART_FIGHT0; + levelMenuInfo.item_next.generic.flags = QMF_RIGHT_JUSTIFY|QMF_PULSEIFFOCUS; + levelMenuInfo.item_next.generic.x = 640; + levelMenuInfo.item_next.generic.y = 480-64; + levelMenuInfo.item_next.generic.callback = UI_SPLevelMenu_NextEvent; + levelMenuInfo.item_next.generic.id = ID_NEXT; + levelMenuInfo.item_next.width = 128; + levelMenuInfo.item_next.height = 64; + levelMenuInfo.item_next.focuspic = ART_FIGHT1; + + levelMenuInfo.item_null.generic.type = MTYPE_BITMAP; + levelMenuInfo.item_null.generic.flags = QMF_LEFT_JUSTIFY|QMF_MOUSEONLY|QMF_SILENT; + levelMenuInfo.item_null.generic.x = 0; + levelMenuInfo.item_null.generic.y = 0; + levelMenuInfo.item_null.width = 640; + levelMenuInfo.item_null.height = 480; + + Menu_AddItem( &levelMenuInfo.menu, &levelMenuInfo.item_banner ); + + Menu_AddItem( &levelMenuInfo.menu, &levelMenuInfo.item_leftarrow ); + Menu_AddItem( &levelMenuInfo.menu, &levelMenuInfo.item_maps[0] ); + Menu_AddItem( &levelMenuInfo.menu, &levelMenuInfo.item_maps[1] ); + Menu_AddItem( &levelMenuInfo.menu, &levelMenuInfo.item_maps[2] ); + Menu_AddItem( &levelMenuInfo.menu, &levelMenuInfo.item_maps[3] ); + levelMenuInfo.item_maps[0].generic.bottom += 18; + levelMenuInfo.item_maps[1].generic.bottom += 18; + levelMenuInfo.item_maps[2].generic.bottom += 18; + levelMenuInfo.item_maps[3].generic.bottom += 18; + Menu_AddItem( &levelMenuInfo.menu, &levelMenuInfo.item_rightarrow ); + + Menu_AddItem( &levelMenuInfo.menu, &levelMenuInfo.item_player ); + + for( n = 0; n < count; n++ ) { + Menu_AddItem( &levelMenuInfo.menu, &levelMenuInfo.item_awards[n] ); + } + Menu_AddItem( &levelMenuInfo.menu, &levelMenuInfo.item_back ); + Menu_AddItem( &levelMenuInfo.menu, &levelMenuInfo.item_reset ); + Menu_AddItem( &levelMenuInfo.menu, &levelMenuInfo.item_custom ); + Menu_AddItem( &levelMenuInfo.menu, &levelMenuInfo.item_next ); + Menu_AddItem( &levelMenuInfo.menu, &levelMenuInfo.item_null ); + + trap_Cvar_VariableStringBuffer( "ui_spSelection", buf, sizeof(buf) ); + if( *buf ) { + n = atoi( buf ); + selectedArenaSet = n / ARENAS_PER_TIER; + selectedArena = n % ARENAS_PER_TIER; + } + else { + selectedArenaSet = currentSet; + selectedArena = currentGame; + } + + UI_SPLevelMenu_SetMenuItems(); +} + + +/* +================= +UI_SPLevelMenu +================= +*/ +void UI_SPLevelMenu( void ) { + int level; + int trainingLevel; + const char *arenaInfo; + + trainingTier = -1; + arenaInfo = UI_GetSpecialArenaInfo( "training" ); + if( arenaInfo ) { + minTier = trainingTier; + trainingLevel = atoi( Info_ValueForKey( arenaInfo, "num" ) ); + } + else { + minTier = 0; + trainingLevel = -2; + } + + finalTier = UI_GetNumSPTiers(); + arenaInfo = UI_GetSpecialArenaInfo( "final" ); + if( arenaInfo ) { + maxTier = finalTier; + } + else { + maxTier = finalTier - 1; + if( maxTier < minTier ) { + maxTier = minTier; + } + } + + level = UI_GetCurrentGame(); + if ( level == -1 ) { + level = UI_GetNumSPArenas() - 1; + if( maxTier == finalTier ) { + level++; + } + } + + if( level == trainingLevel ) { + currentSet = -1; + currentGame = 0; + } + else { + currentSet = level / ARENAS_PER_TIER; + currentGame = level % ARENAS_PER_TIER; + } + + UI_SPLevelMenu_Init(); + UI_PushMenu( &levelMenuInfo.menu ); + Menu_SetCursorToItem( &levelMenuInfo.menu, &levelMenuInfo.item_next ); +} + + +/* +================= +UI_SPLevelMenu_f +================= +*/ +void UI_SPLevelMenu_f( void ) { + trap_Key_SetCatcher( KEYCATCH_UI ); + uis.menusp = 0; + UI_SPLevelMenu(); +} + + +/* +================= +UI_SPLevelMenu_ReInit +================= +*/ +void UI_SPLevelMenu_ReInit( void ) { + levelMenuInfo.reinit = qtrue; +} diff --git a/code/q3_ui/ui_sppostgame.c b/code/q3_ui/ui_sppostgame.c new file mode 100755 index 0000000..0f65af8 --- /dev/null +++ b/code/q3_ui/ui_sppostgame.c @@ -0,0 +1,644 @@ +/* +=========================================================================== +Copyright (C) 1999-2005 Id Software, Inc. + +This file is part of Quake III Arena source code. + +Quake III Arena source code is free software; you can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 2 of the License, +or (at your option) any later version. + +Quake III Arena source code is distributed in the hope that it will be +useful, but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Foobar; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ +// +/* +============================================================================= + +SINGLE PLAYER POSTGAME MENU + +============================================================================= +*/ + +#include "ui_local.h" + +#define MAX_SCOREBOARD_CLIENTS 8 + +#define AWARD_PRESENTATION_TIME 2000 + +#define ART_MENU0 "menu/art/menu_0" +#define ART_MENU1 "menu/art/menu_1" +#define ART_REPLAY0 "menu/art/replay_0" +#define ART_REPLAY1 "menu/art/replay_1" +#define ART_NEXT0 "menu/art/next_0" +#define ART_NEXT1 "menu/art/next_1" + +#define ID_AGAIN 10 +#define ID_NEXT 11 +#define ID_MENU 12 + +typedef struct { + menuframework_s menu; + menubitmap_s item_again; + menubitmap_s item_next; + menubitmap_s item_menu; + + int phase; + int ignoreKeysTime; + int starttime; + int scoreboardtime; + int serverId; + + int clientNums[MAX_SCOREBOARD_CLIENTS]; + int ranks[MAX_SCOREBOARD_CLIENTS]; + int scores[MAX_SCOREBOARD_CLIENTS]; + + char placeNames[3][64]; + + int level; + int numClients; + int won; + int numAwards; + int awardsEarned[6]; + int awardsLevels[6]; + qboolean playedSound[6]; + int lastTier; + sfxHandle_t winnerSound; +} postgameMenuInfo_t; + +static postgameMenuInfo_t postgameMenuInfo; +static char arenainfo[MAX_INFO_VALUE]; + +char *ui_medalNames[] = {"Accuracy", "Impressive", "Excellent", "Gauntlet", "Frags", "Perfect"}; +char *ui_medalPicNames[] = { + "menu/medals/medal_accuracy", + "menu/medals/medal_impressive", + "menu/medals/medal_excellent", + "menu/medals/medal_gauntlet", + "menu/medals/medal_frags", + "menu/medals/medal_victory" +}; +char *ui_medalSounds[] = { + "sound/feedback/accuracy.wav", + "sound/feedback/impressive_a.wav", + "sound/feedback/excellent_a.wav", + "sound/feedback/gauntlet.wav", + "sound/feedback/frags.wav", + "sound/feedback/perfect.wav" +}; + + +/* +================= +UI_SPPostgameMenu_AgainEvent +================= +*/ +static void UI_SPPostgameMenu_AgainEvent( void* ptr, int event ) +{ + if (event != QM_ACTIVATED) { + return; + } + UI_PopMenu(); + trap_Cmd_ExecuteText( EXEC_APPEND, "map_restart 0\n" ); +} + + +/* +================= +UI_SPPostgameMenu_NextEvent +================= +*/ +static void UI_SPPostgameMenu_NextEvent( void* ptr, int event ) { + int currentSet; + int levelSet; + int level; + int currentLevel; + const char *arenaInfo; + + if (event != QM_ACTIVATED) { + return; + } + UI_PopMenu(); + + // handle specially if we just won the training map + if( postgameMenuInfo.won == 0 ) { + level = 0; + } + else { + level = postgameMenuInfo.level + 1; + } + levelSet = level / ARENAS_PER_TIER; + + currentLevel = UI_GetCurrentGame(); + if( currentLevel == -1 ) { + currentLevel = postgameMenuInfo.level; + } + currentSet = currentLevel / ARENAS_PER_TIER; + + if( levelSet > currentSet || levelSet == UI_GetNumSPTiers() ) { + level = currentLevel; + } + + arenaInfo = UI_GetArenaInfoByNumber( level ); + if ( !arenaInfo ) { + return; + } + + UI_SPArena_Start( arenaInfo ); +} + + +/* +================= +UI_SPPostgameMenu_MenuEvent +================= +*/ +static void UI_SPPostgameMenu_MenuEvent( void* ptr, int event ) +{ + if (event != QM_ACTIVATED) { + return; + } + UI_PopMenu(); + trap_Cmd_ExecuteText( EXEC_APPEND, "disconnect; levelselect\n" ); +} + + +/* +================= +UI_SPPostgameMenu_MenuKey +================= +*/ +static sfxHandle_t UI_SPPostgameMenu_MenuKey( int key ) { + if ( uis.realtime < postgameMenuInfo.ignoreKeysTime ) { + return 0; + } + + if( postgameMenuInfo.phase == 1 ) { + trap_Cmd_ExecuteText( EXEC_APPEND, "abort_podium\n" ); + postgameMenuInfo.phase = 2; + postgameMenuInfo.starttime = uis.realtime; + postgameMenuInfo.ignoreKeysTime = uis.realtime + 250; + return 0; + } + + if( postgameMenuInfo.phase == 2 ) { + postgameMenuInfo.phase = 3; + postgameMenuInfo.starttime = uis.realtime; + postgameMenuInfo.ignoreKeysTime = uis.realtime + 250; + return 0; + } + + if( key == K_ESCAPE || key == K_MOUSE2 ) { + return 0; + } + + return Menu_DefaultKey( &postgameMenuInfo.menu, key ); +} + + +static int medalLocations[6] = {144, 448, 88, 504, 32, 560}; + +static void UI_SPPostgameMenu_DrawAwardsMedals( int max ) { + int n; + int medal; + int amount; + int x, y; + char buf[16]; + + for( n = 0; n < max; n++ ) { + x = medalLocations[n]; + y = 64; + medal = postgameMenuInfo.awardsEarned[n]; + amount = postgameMenuInfo.awardsLevels[n]; + + UI_DrawNamedPic( x, y, 48, 48, ui_medalPicNames[medal] ); + + if( medal == AWARD_ACCURACY ) { + Com_sprintf( buf, sizeof(buf), "%i%%", amount ); + } + else { + if( amount == 1 ) { + continue; + } + Com_sprintf( buf, sizeof(buf), "%i", amount ); + } + + UI_DrawString( x + 24, y + 52, buf, UI_CENTER, color_yellow ); + } +} + + +static void UI_SPPostgameMenu_DrawAwardsPresentation( int timer ) { + int awardNum; + int atimer; + vec4_t color; + + awardNum = timer / AWARD_PRESENTATION_TIME; + atimer = timer % AWARD_PRESENTATION_TIME; + + color[0] = color[1] = color[2] = 1.0f; + color[3] = (float)( AWARD_PRESENTATION_TIME - atimer ) / (float)AWARD_PRESENTATION_TIME; + UI_DrawProportionalString( 320, 64, ui_medalNames[postgameMenuInfo.awardsEarned[awardNum]], UI_CENTER, color ); + + UI_SPPostgameMenu_DrawAwardsMedals( awardNum + 1 ); + + if( !postgameMenuInfo.playedSound[awardNum] ) { + postgameMenuInfo.playedSound[awardNum] = qtrue; + trap_S_StartLocalSound( trap_S_RegisterSound( ui_medalSounds[postgameMenuInfo.awardsEarned[awardNum]], qfalse ), CHAN_ANNOUNCER ); + } +} + + +/* +================= +UI_SPPostgameMenu_MenuDrawScoreLine +================= +*/ +static void UI_SPPostgameMenu_MenuDrawScoreLine( int n, int y ) { + int rank; + char name[64]; + char info[MAX_INFO_STRING]; + + if( n > (postgameMenuInfo.numClients + 1) ) { + n -= (postgameMenuInfo.numClients + 2); + } + + if( n >= postgameMenuInfo.numClients ) { + return; + } + + rank = postgameMenuInfo.ranks[n]; + if( rank & RANK_TIED_FLAG ) { + UI_DrawString( 640 - 31 * SMALLCHAR_WIDTH, y, "(tie)", UI_LEFT|UI_SMALLFONT, color_white ); + rank &= ~RANK_TIED_FLAG; + } + trap_GetConfigString( CS_PLAYERS + postgameMenuInfo.clientNums[n], info, MAX_INFO_STRING ); + Q_strncpyz( name, Info_ValueForKey( info, "n" ), sizeof(name) ); + Q_CleanStr( name ); + + UI_DrawString( 640 - 25 * SMALLCHAR_WIDTH, y, va( "#%i: %-16s %2i", rank + 1, name, postgameMenuInfo.scores[n] ), UI_LEFT|UI_SMALLFONT, color_white ); +} + + +/* +================= +UI_SPPostgameMenu_MenuDraw +================= +*/ +static void UI_SPPostgameMenu_MenuDraw( void ) { + int timer; + int serverId; + int n; + char info[MAX_INFO_STRING]; + + trap_GetConfigString( CS_SYSTEMINFO, info, sizeof(info) ); + serverId = atoi( Info_ValueForKey( info, "sv_serverid" ) ); + if( serverId != postgameMenuInfo.serverId ) { + UI_PopMenu(); + return; + } + + // phase 1 + if ( postgameMenuInfo.numClients > 2 ) { + UI_DrawProportionalString( 510, 480 - 64 - PROP_HEIGHT, postgameMenuInfo.placeNames[2], UI_CENTER, color_white ); + } + UI_DrawProportionalString( 130, 480 - 64 - PROP_HEIGHT, postgameMenuInfo.placeNames[1], UI_CENTER, color_white ); + UI_DrawProportionalString( 320, 480 - 64 - 2 * PROP_HEIGHT, postgameMenuInfo.placeNames[0], UI_CENTER, color_white ); + + if( postgameMenuInfo.phase == 1 ) { + timer = uis.realtime - postgameMenuInfo.starttime; + + if( timer >= 1000 && postgameMenuInfo.winnerSound ) { + trap_S_StartLocalSound( postgameMenuInfo.winnerSound, CHAN_ANNOUNCER ); + postgameMenuInfo.winnerSound = 0; + } + + if( timer < 5000 ) { + return; + } + postgameMenuInfo.phase = 2; + postgameMenuInfo.starttime = uis.realtime; + } + + // phase 2 + if( postgameMenuInfo.phase == 2 ) { + timer = uis.realtime - postgameMenuInfo.starttime; + if( timer >= ( postgameMenuInfo.numAwards * AWARD_PRESENTATION_TIME ) ) { + + if( timer < 5000 ) { + return; + } + + postgameMenuInfo.phase = 3; + postgameMenuInfo.starttime = uis.realtime; + } + else { + UI_SPPostgameMenu_DrawAwardsPresentation( timer ); + } + } + + // phase 3 + if( postgameMenuInfo.phase == 3 ) { + if( uis.demoversion ) { + if( postgameMenuInfo.won == 1 && UI_ShowTierVideo( 8 )) { + trap_Cvar_Set( "nextmap", "" ); + trap_Cmd_ExecuteText( EXEC_APPEND, "disconnect; cinematic demoEnd.RoQ\n" ); + return; + } + } + else if( postgameMenuInfo.won > -1 && UI_ShowTierVideo( postgameMenuInfo.won + 1 )) { + if( postgameMenuInfo.won == postgameMenuInfo.lastTier ) { + trap_Cvar_Set( "nextmap", "" ); + trap_Cmd_ExecuteText( EXEC_APPEND, "disconnect; cinematic end.RoQ\n" ); + return; + } + + trap_Cvar_SetValue( "ui_spSelection", postgameMenuInfo.won * ARENAS_PER_TIER ); + trap_Cvar_Set( "nextmap", "levelselect" ); + trap_Cmd_ExecuteText( EXEC_APPEND, va( "disconnect; cinematic tier%i.RoQ\n", postgameMenuInfo.won + 1 ) ); + return; + } + + postgameMenuInfo.item_again.generic.flags &= ~QMF_INACTIVE; + postgameMenuInfo.item_next.generic.flags &= ~QMF_INACTIVE; + postgameMenuInfo.item_menu.generic.flags &= ~QMF_INACTIVE; + + UI_SPPostgameMenu_DrawAwardsMedals( postgameMenuInfo.numAwards ); + + Menu_Draw( &postgameMenuInfo.menu ); + } + + // draw the scoreboard + if( !trap_Cvar_VariableValue( "ui_spScoreboard" ) ) { + return; + } + + timer = uis.realtime - postgameMenuInfo.scoreboardtime; + if( postgameMenuInfo.numClients <= 3 ) { + n = 0; + } + else { + n = timer / 1500 % (postgameMenuInfo.numClients + 2); + } + UI_SPPostgameMenu_MenuDrawScoreLine( n, 0 ); + UI_SPPostgameMenu_MenuDrawScoreLine( n + 1, 0 + SMALLCHAR_HEIGHT ); + UI_SPPostgameMenu_MenuDrawScoreLine( n + 2, 0 + 2 * SMALLCHAR_HEIGHT ); +} + + +/* +================= +UI_SPPostgameMenu_Cache +================= +*/ +void UI_SPPostgameMenu_Cache( void ) { + int n; + qboolean buildscript; + + buildscript = trap_Cvar_VariableValue("com_buildscript"); + + trap_R_RegisterShaderNoMip( ART_MENU0 ); + trap_R_RegisterShaderNoMip( ART_MENU1 ); + trap_R_RegisterShaderNoMip( ART_REPLAY0 ); + trap_R_RegisterShaderNoMip( ART_REPLAY1 ); + trap_R_RegisterShaderNoMip( ART_NEXT0 ); + trap_R_RegisterShaderNoMip( ART_NEXT1 ); + for( n = 0; n < 6; n++ ) { + trap_R_RegisterShaderNoMip( ui_medalPicNames[n] ); + trap_S_RegisterSound( ui_medalSounds[n], qfalse ); + } + + if( buildscript ) { + trap_S_RegisterSound( "music/loss.wav", qfalse ); + trap_S_RegisterSound( "music/win.wav", qfalse ); + trap_S_RegisterSound( "sound/player/announce/youwin.wav", qfalse ); + } +} + + +/* +================= +UI_SPPostgameMenu_Init +================= +*/ +static void UI_SPPostgameMenu_Init( void ) { + postgameMenuInfo.menu.wrapAround = qtrue; + postgameMenuInfo.menu.key = UI_SPPostgameMenu_MenuKey; + postgameMenuInfo.menu.draw = UI_SPPostgameMenu_MenuDraw; + postgameMenuInfo.ignoreKeysTime = uis.realtime + 1500; + + UI_SPPostgameMenu_Cache(); + + postgameMenuInfo.item_menu.generic.type = MTYPE_BITMAP; + postgameMenuInfo.item_menu.generic.name = ART_MENU0; + postgameMenuInfo.item_menu.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_INACTIVE; + postgameMenuInfo.item_menu.generic.x = 0; + postgameMenuInfo.item_menu.generic.y = 480-64; + postgameMenuInfo.item_menu.generic.callback = UI_SPPostgameMenu_MenuEvent; + postgameMenuInfo.item_menu.generic.id = ID_MENU; + postgameMenuInfo.item_menu.width = 128; + postgameMenuInfo.item_menu.height = 64; + postgameMenuInfo.item_menu.focuspic = ART_MENU1; + + postgameMenuInfo.item_again.generic.type = MTYPE_BITMAP; + postgameMenuInfo.item_again.generic.name = ART_REPLAY0; + postgameMenuInfo.item_again.generic.flags = QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS|QMF_INACTIVE; + postgameMenuInfo.item_again.generic.x = 320; + postgameMenuInfo.item_again.generic.y = 480-64; + postgameMenuInfo.item_again.generic.callback = UI_SPPostgameMenu_AgainEvent; + postgameMenuInfo.item_again.generic.id = ID_AGAIN; + postgameMenuInfo.item_again.width = 128; + postgameMenuInfo.item_again.height = 64; + postgameMenuInfo.item_again.focuspic = ART_REPLAY1; + + postgameMenuInfo.item_next.generic.type = MTYPE_BITMAP; + postgameMenuInfo.item_next.generic.name = ART_NEXT0; + postgameMenuInfo.item_next.generic.flags = QMF_RIGHT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_INACTIVE; + postgameMenuInfo.item_next.generic.x = 640; + postgameMenuInfo.item_next.generic.y = 480-64; + postgameMenuInfo.item_next.generic.callback = UI_SPPostgameMenu_NextEvent; + postgameMenuInfo.item_next.generic.id = ID_NEXT; + postgameMenuInfo.item_next.width = 128; + postgameMenuInfo.item_next.height = 64; + postgameMenuInfo.item_next.focuspic = ART_NEXT1; + + Menu_AddItem( &postgameMenuInfo.menu, ( void * )&postgameMenuInfo.item_menu ); + Menu_AddItem( &postgameMenuInfo.menu, ( void * )&postgameMenuInfo.item_again ); + Menu_AddItem( &postgameMenuInfo.menu, ( void * )&postgameMenuInfo.item_next ); +} + + +static void Prepname( int index ) { + int len; + char name[64]; + char info[MAX_INFO_STRING]; + + trap_GetConfigString( CS_PLAYERS + postgameMenuInfo.clientNums[index], info, MAX_INFO_STRING ); + Q_strncpyz( name, Info_ValueForKey( info, "n" ), sizeof(name) ); + Q_CleanStr( name ); + len = strlen( name ); + + while( len && UI_ProportionalStringWidth( name ) > 256 ) { + len--; + name[len] = 0; + } + + Q_strncpyz( postgameMenuInfo.placeNames[index], name, sizeof(postgameMenuInfo.placeNames[index]) ); +} + + +/* +================= +UI_SPPostgameMenu_f +================= +*/ +void UI_SPPostgameMenu_f( void ) { + int playerGameRank; + int playerClientNum; + int n; + int oldFrags, newFrags; + const char *arena; + int awardValues[6]; + char map[MAX_QPATH]; + char info[MAX_INFO_STRING]; + + memset( &postgameMenuInfo, 0, sizeof(postgameMenuInfo) ); + + trap_GetConfigString( CS_SYSTEMINFO, info, sizeof(info) ); + postgameMenuInfo.serverId = atoi( Info_ValueForKey( info, "sv_serverid" ) ); + + trap_GetConfigString( CS_SERVERINFO, info, sizeof(info) ); + Q_strncpyz( map, Info_ValueForKey( info, "mapname" ), sizeof(map) ); + arena = UI_GetArenaInfoByMap( map ); + if ( !arena ) { + return; + } + Q_strncpyz( arenainfo, arena, sizeof(arenainfo) ); + + postgameMenuInfo.level = atoi( Info_ValueForKey( arenainfo, "num" ) ); + + postgameMenuInfo.numClients = atoi( UI_Argv( 1 ) ); + playerClientNum = atoi( UI_Argv( 2 ) ); + playerGameRank = 8; // in case they ended game as a spectator + + if( postgameMenuInfo.numClients > MAX_SCOREBOARD_CLIENTS ) { + postgameMenuInfo.numClients = MAX_SCOREBOARD_CLIENTS; + } + + for( n = 0; n < postgameMenuInfo.numClients; n++ ) { + postgameMenuInfo.clientNums[n] = atoi( UI_Argv( 8 + n * 3 + 1 ) ); + postgameMenuInfo.ranks[n] = atoi( UI_Argv( 8 + n * 3 + 2 ) ); + postgameMenuInfo.scores[n] = atoi( UI_Argv( 8 + n * 3 + 3 ) ); + + if( postgameMenuInfo.clientNums[n] == playerClientNum ) { + playerGameRank = (postgameMenuInfo.ranks[n] & ~RANK_TIED_FLAG) + 1; + } + } + + UI_SetBestScore( postgameMenuInfo.level, playerGameRank ); + + // process award stats and prepare presentation data + awardValues[AWARD_ACCURACY] = atoi( UI_Argv( 3 ) ); + awardValues[AWARD_IMPRESSIVE] = atoi( UI_Argv( 4 ) ); + awardValues[AWARD_EXCELLENT] = atoi( UI_Argv( 5 ) ); + awardValues[AWARD_GAUNTLET] = atoi( UI_Argv( 6 ) ); + awardValues[AWARD_FRAGS] = atoi( UI_Argv( 7 ) ); + awardValues[AWARD_PERFECT] = atoi( UI_Argv( 8 ) ); + + postgameMenuInfo.numAwards = 0; + + if( awardValues[AWARD_ACCURACY] >= 50 ) { + UI_LogAwardData( AWARD_ACCURACY, 1 ); + postgameMenuInfo.awardsEarned[postgameMenuInfo.numAwards] = AWARD_ACCURACY; + postgameMenuInfo.awardsLevels[postgameMenuInfo.numAwards] = awardValues[AWARD_ACCURACY]; + postgameMenuInfo.numAwards++; + } + + if( awardValues[AWARD_IMPRESSIVE] ) { + UI_LogAwardData( AWARD_IMPRESSIVE, awardValues[AWARD_IMPRESSIVE] ); + postgameMenuInfo.awardsEarned[postgameMenuInfo.numAwards] = AWARD_IMPRESSIVE; + postgameMenuInfo.awardsLevels[postgameMenuInfo.numAwards] = awardValues[AWARD_IMPRESSIVE]; + postgameMenuInfo.numAwards++; + } + + if( awardValues[AWARD_EXCELLENT] ) { + UI_LogAwardData( AWARD_EXCELLENT, awardValues[AWARD_EXCELLENT] ); + postgameMenuInfo.awardsEarned[postgameMenuInfo.numAwards] = AWARD_EXCELLENT; + postgameMenuInfo.awardsLevels[postgameMenuInfo.numAwards] = awardValues[AWARD_EXCELLENT]; + postgameMenuInfo.numAwards++; + } + + if( awardValues[AWARD_GAUNTLET] ) { + UI_LogAwardData( AWARD_GAUNTLET, awardValues[AWARD_GAUNTLET] ); + postgameMenuInfo.awardsEarned[postgameMenuInfo.numAwards] = AWARD_GAUNTLET; + postgameMenuInfo.awardsLevels[postgameMenuInfo.numAwards] = awardValues[AWARD_GAUNTLET]; + postgameMenuInfo.numAwards++; + } + + oldFrags = UI_GetAwardLevel( AWARD_FRAGS ) / 100; + UI_LogAwardData( AWARD_FRAGS, awardValues[AWARD_FRAGS] ); + newFrags = UI_GetAwardLevel( AWARD_FRAGS ) / 100; + if( newFrags > oldFrags ) { + postgameMenuInfo.awardsEarned[postgameMenuInfo.numAwards] = AWARD_FRAGS; + postgameMenuInfo.awardsLevels[postgameMenuInfo.numAwards] = newFrags * 100; + postgameMenuInfo.numAwards++; + } + + if( awardValues[AWARD_PERFECT] ) { + UI_LogAwardData( AWARD_PERFECT, 1 ); + postgameMenuInfo.awardsEarned[postgameMenuInfo.numAwards] = AWARD_PERFECT; + postgameMenuInfo.awardsLevels[postgameMenuInfo.numAwards] = 1; + postgameMenuInfo.numAwards++; + } + + if ( playerGameRank == 1 ) { + postgameMenuInfo.won = UI_TierCompleted( postgameMenuInfo.level ); + } + else { + postgameMenuInfo.won = -1; + } + + postgameMenuInfo.starttime = uis.realtime; + postgameMenuInfo.scoreboardtime = uis.realtime; + + trap_Key_SetCatcher( KEYCATCH_UI ); + uis.menusp = 0; + + UI_SPPostgameMenu_Init(); + UI_PushMenu( &postgameMenuInfo.menu ); + + if ( playerGameRank == 1 ) { + Menu_SetCursorToItem( &postgameMenuInfo.menu, &postgameMenuInfo.item_next ); + } + else { + Menu_SetCursorToItem( &postgameMenuInfo.menu, &postgameMenuInfo.item_again ); + } + + Prepname( 0 ); + Prepname( 1 ); + Prepname( 2 ); + + if ( playerGameRank != 1 ) { + postgameMenuInfo.winnerSound = trap_S_RegisterSound( va( "sound/player/announce/%s_wins.wav", postgameMenuInfo.placeNames[0] ), qfalse ); + trap_Cmd_ExecuteText( EXEC_APPEND, "music music/loss\n" ); + } + else { + postgameMenuInfo.winnerSound = trap_S_RegisterSound( "sound/player/announce/youwin.wav", qfalse ); + trap_Cmd_ExecuteText( EXEC_APPEND, "music music/win\n" ); + } + + postgameMenuInfo.phase = 1; + + postgameMenuInfo.lastTier = UI_GetNumSPTiers(); + if ( UI_GetSpecialArenaInfo( "final" ) ) { + postgameMenuInfo.lastTier++; + } +} diff --git a/code/q3_ui/ui_spreset.c b/code/q3_ui/ui_spreset.c new file mode 100755 index 0000000..0dc3634 --- /dev/null +++ b/code/q3_ui/ui_spreset.c @@ -0,0 +1,194 @@ +/* +=========================================================================== +Copyright (C) 1999-2005 Id Software, Inc. + +This file is part of Quake III Arena source code. + +Quake III Arena source code is free software; you can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 2 of the License, +or (at your option) any later version. + +Quake III Arena source code is distributed in the hope that it will be +useful, but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Foobar; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ +/* +======================================================================= + +RESET MENU + +======================================================================= +*/ + +#include "ui_local.h" + + +#define ART_FRAME "menu/art/cut_frame" + +#define ID_NO 100 +#define ID_YES 101 + +typedef struct +{ + menuframework_s menu; + menutext_s no; + menutext_s yes; + int slashX; +} resetMenu_t; + +static resetMenu_t s_reset; + + +/* +================= +Reset_MenuEvent +================= +*/ +void Reset_MenuEvent(void* ptr, int event) { + if( event != QM_ACTIVATED ) { + return; + } + + UI_PopMenu(); + + if( ((menucommon_s*)ptr)->id == ID_NO ) { + return; + } + + // reset the game, pop the level menu and restart it so it updates + UI_NewGame(); + trap_Cvar_SetValue( "ui_spSelection", 0 ); + UI_PopMenu(); + UI_SPLevelMenu(); +} + + +/* +================= +Reset_MenuKey +================= +*/ +static sfxHandle_t Reset_MenuKey( int key ) { + switch ( key ) { + case K_KP_LEFTARROW: + case K_LEFTARROW: + case K_KP_RIGHTARROW: + case K_RIGHTARROW: + key = K_TAB; + break; + + case 'n': + case 'N': + Reset_MenuEvent( &s_reset.no, QM_ACTIVATED ); + break; + + case 'y': + case 'Y': + Reset_MenuEvent( &s_reset.yes, QM_ACTIVATED ); + break; + } + + return Menu_DefaultKey( &s_reset.menu, key ); +} + + +/* +================= +Reset_MenuDraw +================= +*/ +static void Reset_MenuDraw( void ) { + UI_DrawNamedPic( 142, 118, 359, 256, ART_FRAME ); + UI_DrawProportionalString( 320, 194 + 10, "RESET GAME?", UI_CENTER|UI_INVERSE, color_red ); + UI_DrawProportionalString( s_reset.slashX, 265, "/", UI_LEFT|UI_INVERSE, color_red ); + Menu_Draw( &s_reset.menu ); + + UI_DrawProportionalString( SCREEN_WIDTH/2, 356 + PROP_HEIGHT * 0, "WARNING: This resets all of the", UI_CENTER|UI_SMALLFONT, color_yellow ); + UI_DrawProportionalString( SCREEN_WIDTH/2, 356 + PROP_HEIGHT * 1, "single player game variables.", UI_CENTER|UI_SMALLFONT, color_yellow ); + UI_DrawProportionalString( SCREEN_WIDTH/2, 356 + PROP_HEIGHT * 2, "Do this only if you want to", UI_CENTER|UI_SMALLFONT, color_yellow ); + UI_DrawProportionalString( SCREEN_WIDTH/2, 356 + PROP_HEIGHT * 3, "start over from the beginning.", UI_CENTER|UI_SMALLFONT, color_yellow ); +} + + +/* +================= +Reset_Cache +================= +*/ +void Reset_Cache( void ) { + trap_R_RegisterShaderNoMip( ART_FRAME ); +} + + +/* +================= +UI_ResetMenu +================= +*/ +void UI_ResetMenu(void) { + uiClientState_t cstate; + int n1, n2, n3; + int l1, l2, l3; + + // zero set all our globals + memset( &s_reset, 0, sizeof(s_reset) ); + + Reset_Cache(); + + n1 = UI_ProportionalStringWidth( "YES/NO" ); + n2 = UI_ProportionalStringWidth( "YES" ) + PROP_GAP_WIDTH; + n3 = UI_ProportionalStringWidth( "/" ) + PROP_GAP_WIDTH; + l1 = 320 - ( n1 / 2 ); + l2 = l1 + n2; + l3 = l2 + n3; + s_reset.slashX = l2; + + s_reset.menu.draw = Reset_MenuDraw; + s_reset.menu.key = Reset_MenuKey; + s_reset.menu.wrapAround = qtrue; + + trap_GetClientState( &cstate ); + + if ( cstate.connState >= CA_CONNECTED ) { + // float on top of running game + s_reset.menu.fullscreen = qfalse; + } + else { + // game not running + s_reset.menu.fullscreen = qtrue; + } + + s_reset.yes.generic.type = MTYPE_PTEXT; + s_reset.yes.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS; + s_reset.yes.generic.callback = Reset_MenuEvent; + s_reset.yes.generic.id = ID_YES; + s_reset.yes.generic.x = l1; + s_reset.yes.generic.y = 264; + s_reset.yes.string = "YES"; + s_reset.yes.color = color_red; + s_reset.yes.style = UI_LEFT; + + s_reset.no.generic.type = MTYPE_PTEXT; + s_reset.no.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS; + s_reset.no.generic.callback = Reset_MenuEvent; + s_reset.no.generic.id = ID_NO; + s_reset.no.generic.x = l3; + s_reset.no.generic.y = 264; + s_reset.no.string = "NO"; + s_reset.no.color = color_red; + s_reset.no.style = UI_LEFT; + + Menu_AddItem( &s_reset.menu, &s_reset.yes ); + Menu_AddItem( &s_reset.menu, &s_reset.no ); + + UI_PushMenu( &s_reset.menu ); + + Menu_SetCursorToItem( &s_reset.menu, &s_reset.no ); +} diff --git a/code/q3_ui/ui_spskill.c b/code/q3_ui/ui_spskill.c new file mode 100755 index 0000000..934d832 --- /dev/null +++ b/code/q3_ui/ui_spskill.c @@ -0,0 +1,329 @@ +/* +=========================================================================== +Copyright (C) 1999-2005 Id Software, Inc. + +This file is part of Quake III Arena source code. + +Quake III Arena source code is free software; you can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 2 of the License, +or (at your option) any later version. + +Quake III Arena source code is distributed in the hope that it will be +useful, but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Foobar; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ +// +/* +============================================================================= + +SINGLE PLAYER SKILL MENU + +============================================================================= +*/ + +#include "ui_local.h" + + +#define ART_FRAME "menu/art/cut_frame" +#define ART_BACK "menu/art/back_0.tga" +#define ART_BACK_FOCUS "menu/art/back_1.tga" +#define ART_FIGHT "menu/art/fight_0" +#define ART_FIGHT_FOCUS "menu/art/fight_1" +#define ART_MAP_COMPLETE1 "menu/art/level_complete1" +#define ART_MAP_COMPLETE2 "menu/art/level_complete2" +#define ART_MAP_COMPLETE3 "menu/art/level_complete3" +#define ART_MAP_COMPLETE4 "menu/art/level_complete4" +#define ART_MAP_COMPLETE5 "menu/art/level_complete5" + +#define ID_BABY 10 +#define ID_EASY 11 +#define ID_MEDIUM 12 +#define ID_HARD 13 +#define ID_NIGHTMARE 14 +#define ID_BACK 15 +#define ID_FIGHT 16 + + +typedef struct { + menuframework_s menu; + + menubitmap_s art_frame; + menutext_s art_banner; + + menutext_s item_baby; + menutext_s item_easy; + menutext_s item_medium; + menutext_s item_hard; + menutext_s item_nightmare; + + menubitmap_s art_skillPic; + menubitmap_s item_back; + menubitmap_s item_fight; + + const char *arenaInfo; + qhandle_t skillpics[5]; + sfxHandle_t nightmareSound; + sfxHandle_t silenceSound; +} skillMenuInfo_t; + +static skillMenuInfo_t skillMenuInfo; + + +static void SetSkillColor( int skill, vec4_t color ) { + switch( skill ) { + case 1: + skillMenuInfo.item_baby.color = color; + break; + case 2: + skillMenuInfo.item_easy.color = color; + break; + case 3: + skillMenuInfo.item_medium.color = color; + break; + case 4: + skillMenuInfo.item_hard.color = color; + break; + case 5: + skillMenuInfo.item_nightmare.color = color; + break; + default: + break; + } +} + + +/* +================= +UI_SPSkillMenu_SkillEvent +================= +*/ +static void UI_SPSkillMenu_SkillEvent( void *ptr, int notification ) { + int id; + int skill; + + if (notification != QM_ACTIVATED) + return; + + SetSkillColor( (int)trap_Cvar_VariableValue( "g_spSkill" ), color_red ); + + id = ((menucommon_s*)ptr)->id; + skill = id - ID_BABY + 1; + trap_Cvar_SetValue( "g_spSkill", skill ); + + SetSkillColor( skill, color_white ); + skillMenuInfo.art_skillPic.shader = skillMenuInfo.skillpics[skill - 1]; + + if( id == ID_NIGHTMARE ) { + trap_S_StartLocalSound( skillMenuInfo.nightmareSound, CHAN_ANNOUNCER ); + } + else { + trap_S_StartLocalSound( skillMenuInfo.silenceSound, CHAN_ANNOUNCER ); + } +} + + +/* +================= +UI_SPSkillMenu_FightEvent +================= +*/ +static void UI_SPSkillMenu_FightEvent( void *ptr, int notification ) { + if (notification != QM_ACTIVATED) + return; + + UI_SPArena_Start( skillMenuInfo.arenaInfo ); +} + + +/* +================= +UI_SPSkillMenu_BackEvent +================= +*/ +static void UI_SPSkillMenu_BackEvent( void* ptr, int notification ) { + if (notification != QM_ACTIVATED) { + return; + } + + trap_S_StartLocalSound( skillMenuInfo.silenceSound, CHAN_ANNOUNCER ); + UI_PopMenu(); +} + + +/* +================= +UI_SPSkillMenu_Key +================= +*/ +static sfxHandle_t UI_SPSkillMenu_Key( int key ) { + if( key == K_MOUSE2 || key == K_ESCAPE ) { + trap_S_StartLocalSound( skillMenuInfo.silenceSound, CHAN_ANNOUNCER ); + } + return Menu_DefaultKey( &skillMenuInfo.menu, key ); +} + + +/* +================= +UI_SPSkillMenu_Cache +================= +*/ +void UI_SPSkillMenu_Cache( void ) { + trap_R_RegisterShaderNoMip( ART_FRAME ); + trap_R_RegisterShaderNoMip( ART_BACK ); + trap_R_RegisterShaderNoMip( ART_BACK_FOCUS ); + trap_R_RegisterShaderNoMip( ART_FIGHT ); + trap_R_RegisterShaderNoMip( ART_FIGHT_FOCUS ); + skillMenuInfo.skillpics[0] = trap_R_RegisterShaderNoMip( ART_MAP_COMPLETE1 ); + skillMenuInfo.skillpics[1] = trap_R_RegisterShaderNoMip( ART_MAP_COMPLETE2 ); + skillMenuInfo.skillpics[2] = trap_R_RegisterShaderNoMip( ART_MAP_COMPLETE3 ); + skillMenuInfo.skillpics[3] = trap_R_RegisterShaderNoMip( ART_MAP_COMPLETE4 ); + skillMenuInfo.skillpics[4] = trap_R_RegisterShaderNoMip( ART_MAP_COMPLETE5 ); + + skillMenuInfo.nightmareSound = trap_S_RegisterSound( "sound/misc/nightmare.wav", qfalse ); + skillMenuInfo.silenceSound = trap_S_RegisterSound( "sound/misc/silence.wav", qfalse ); +} + + +/* +================= +UI_SPSkillMenu_Init +================= +*/ +static void UI_SPSkillMenu_Init( void ) { + int skill; + + memset( &skillMenuInfo, 0, sizeof(skillMenuInfo) ); + skillMenuInfo.menu.fullscreen = qtrue; + skillMenuInfo.menu.key = UI_SPSkillMenu_Key; + + UI_SPSkillMenu_Cache(); + + skillMenuInfo.art_frame.generic.type = MTYPE_BITMAP; + skillMenuInfo.art_frame.generic.name = ART_FRAME; + skillMenuInfo.art_frame.generic.flags = QMF_LEFT_JUSTIFY|QMF_INACTIVE; + skillMenuInfo.art_frame.generic.x = 142; + skillMenuInfo.art_frame.generic.y = 118; + skillMenuInfo.art_frame.width = 359; + skillMenuInfo.art_frame.height = 256; + + skillMenuInfo.art_banner.generic.type = MTYPE_BTEXT; + skillMenuInfo.art_banner.generic.flags = QMF_CENTER_JUSTIFY; + skillMenuInfo.art_banner.generic.x = 320; + skillMenuInfo.art_banner.generic.y = 16; + skillMenuInfo.art_banner.string = "DIFFICULTY"; + skillMenuInfo.art_banner.color = color_white; + skillMenuInfo.art_banner.style = UI_CENTER; + + skillMenuInfo.item_baby.generic.type = MTYPE_PTEXT; + skillMenuInfo.item_baby.generic.flags = QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS; + skillMenuInfo.item_baby.generic.x = 320; + skillMenuInfo.item_baby.generic.y = 170; + skillMenuInfo.item_baby.generic.callback = UI_SPSkillMenu_SkillEvent; + skillMenuInfo.item_baby.generic.id = ID_BABY; + skillMenuInfo.item_baby.string = "I Can Win"; + skillMenuInfo.item_baby.color = color_red; + skillMenuInfo.item_baby.style = UI_CENTER; + + skillMenuInfo.item_easy.generic.type = MTYPE_PTEXT; + skillMenuInfo.item_easy.generic.flags = QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS; + skillMenuInfo.item_easy.generic.x = 320; + skillMenuInfo.item_easy.generic.y = 198; + skillMenuInfo.item_easy.generic.callback = UI_SPSkillMenu_SkillEvent; + skillMenuInfo.item_easy.generic.id = ID_EASY; + skillMenuInfo.item_easy.string = "Bring It On"; + skillMenuInfo.item_easy.color = color_red; + skillMenuInfo.item_easy.style = UI_CENTER; + + skillMenuInfo.item_medium.generic.type = MTYPE_PTEXT; + skillMenuInfo.item_medium.generic.flags = QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS; + skillMenuInfo.item_medium.generic.x = 320; + skillMenuInfo.item_medium.generic.y = 227; + skillMenuInfo.item_medium.generic.callback = UI_SPSkillMenu_SkillEvent; + skillMenuInfo.item_medium.generic.id = ID_MEDIUM; + skillMenuInfo.item_medium.string = "Hurt Me Plenty"; + skillMenuInfo.item_medium.color = color_red; + skillMenuInfo.item_medium.style = UI_CENTER; + + skillMenuInfo.item_hard.generic.type = MTYPE_PTEXT; + skillMenuInfo.item_hard.generic.flags = QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS; + skillMenuInfo.item_hard.generic.x = 320; + skillMenuInfo.item_hard.generic.y = 255; + skillMenuInfo.item_hard.generic.callback = UI_SPSkillMenu_SkillEvent; + skillMenuInfo.item_hard.generic.id = ID_HARD; + skillMenuInfo.item_hard.string = "Hardcore"; + skillMenuInfo.item_hard.color = color_red; + skillMenuInfo.item_hard.style = UI_CENTER; + + skillMenuInfo.item_nightmare.generic.type = MTYPE_PTEXT; + skillMenuInfo.item_nightmare.generic.flags = QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS; + skillMenuInfo.item_nightmare.generic.x = 320; + skillMenuInfo.item_nightmare.generic.y = 283; + skillMenuInfo.item_nightmare.generic.callback = UI_SPSkillMenu_SkillEvent; + skillMenuInfo.item_nightmare.generic.id = ID_NIGHTMARE; + skillMenuInfo.item_nightmare.string = "NIGHTMARE!"; + skillMenuInfo.item_nightmare.color = color_red; + skillMenuInfo.item_nightmare.style = UI_CENTER; + + skillMenuInfo.item_back.generic.type = MTYPE_BITMAP; + skillMenuInfo.item_back.generic.name = ART_BACK; + skillMenuInfo.item_back.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS; + skillMenuInfo.item_back.generic.x = 0; + skillMenuInfo.item_back.generic.y = 480-64; + skillMenuInfo.item_back.generic.callback = UI_SPSkillMenu_BackEvent; + skillMenuInfo.item_back.generic.id = ID_BACK; + skillMenuInfo.item_back.width = 128; + skillMenuInfo.item_back.height = 64; + skillMenuInfo.item_back.focuspic = ART_BACK_FOCUS; + + skillMenuInfo.art_skillPic.generic.type = MTYPE_BITMAP; + skillMenuInfo.art_skillPic.generic.flags = QMF_LEFT_JUSTIFY|QMF_INACTIVE; + skillMenuInfo.art_skillPic.generic.x = 320-64; + skillMenuInfo.art_skillPic.generic.y = 368; + skillMenuInfo.art_skillPic.width = 128; + skillMenuInfo.art_skillPic.height = 96; + + skillMenuInfo.item_fight.generic.type = MTYPE_BITMAP; + skillMenuInfo.item_fight.generic.name = ART_FIGHT; + skillMenuInfo.item_fight.generic.flags = QMF_RIGHT_JUSTIFY|QMF_PULSEIFFOCUS; + skillMenuInfo.item_fight.generic.callback = UI_SPSkillMenu_FightEvent; + skillMenuInfo.item_fight.generic.id = ID_FIGHT; + skillMenuInfo.item_fight.generic.x = 640; + skillMenuInfo.item_fight.generic.y = 480-64; + skillMenuInfo.item_fight.width = 128; + skillMenuInfo.item_fight.height = 64; + skillMenuInfo.item_fight.focuspic = ART_FIGHT_FOCUS; + + Menu_AddItem( &skillMenuInfo.menu, ( void * )&skillMenuInfo.art_frame ); + Menu_AddItem( &skillMenuInfo.menu, ( void * )&skillMenuInfo.art_banner ); + Menu_AddItem( &skillMenuInfo.menu, ( void * )&skillMenuInfo.item_baby ); + Menu_AddItem( &skillMenuInfo.menu, ( void * )&skillMenuInfo.item_easy ); + Menu_AddItem( &skillMenuInfo.menu, ( void * )&skillMenuInfo.item_medium ); + Menu_AddItem( &skillMenuInfo.menu, ( void * )&skillMenuInfo.item_hard ); + Menu_AddItem( &skillMenuInfo.menu, ( void * )&skillMenuInfo.item_nightmare ); + Menu_AddItem( &skillMenuInfo.menu, ( void * )&skillMenuInfo.art_skillPic ); + Menu_AddItem( &skillMenuInfo.menu, ( void * )&skillMenuInfo.item_back ); + Menu_AddItem( &skillMenuInfo.menu, ( void * )&skillMenuInfo.item_fight ); + + skill = (int)Com_Clamp( 1, 5, trap_Cvar_VariableValue( "g_spSkill" ) ); + SetSkillColor( skill, color_white ); + skillMenuInfo.art_skillPic.shader = skillMenuInfo.skillpics[skill - 1]; + if( skill == 5 ) { + trap_S_StartLocalSound( skillMenuInfo.nightmareSound, CHAN_ANNOUNCER ); + } +} + + +void UI_SPSkillMenu( const char *arenaInfo ) { + UI_SPSkillMenu_Init(); + skillMenuInfo.arenaInfo = arenaInfo; + UI_PushMenu( &skillMenuInfo.menu ); + Menu_SetCursorToItem( &skillMenuInfo.menu, &skillMenuInfo.item_fight ); +} diff --git a/code/q3_ui/ui_startserver.c b/code/q3_ui/ui_startserver.c new file mode 100755 index 0000000..5bc3680 --- /dev/null +++ b/code/q3_ui/ui_startserver.c @@ -0,0 +1,1968 @@ +/* +=========================================================================== +Copyright (C) 1999-2005 Id Software, Inc. + +This file is part of Quake III Arena source code. + +Quake III Arena source code is free software; you can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 2 of the License, +or (at your option) any later version. + +Quake III Arena source code is distributed in the hope that it will be +useful, but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Foobar; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ +// +/* +============================================================================= + +START SERVER MENU ***** + +============================================================================= +*/ + + +#include "ui_local.h" + + +#define GAMESERVER_BACK0 "menu/art/back_0" +#define GAMESERVER_BACK1 "menu/art/back_1" +#define GAMESERVER_NEXT0 "menu/art/next_0" +#define GAMESERVER_NEXT1 "menu/art/next_1" +#define GAMESERVER_FRAMEL "menu/art/frame2_l" +#define GAMESERVER_FRAMER "menu/art/frame1_r" +#define GAMESERVER_SELECT "menu/art/maps_select" +#define GAMESERVER_SELECTED "menu/art/maps_selected" +#define GAMESERVER_FIGHT0 "menu/art/fight_0" +#define GAMESERVER_FIGHT1 "menu/art/fight_1" +#define GAMESERVER_UNKNOWNMAP "menu/art/unknownmap" +#define GAMESERVER_ARROWS "menu/art/gs_arrows_0" +#define GAMESERVER_ARROWSL "menu/art/gs_arrows_l" +#define GAMESERVER_ARROWSR "menu/art/gs_arrows_r" + +#define MAX_MAPROWS 2 +#define MAX_MAPCOLS 2 +#define MAX_MAPSPERPAGE 4 + +#define MAX_SERVERSTEXT 8192 + +#define MAX_SERVERMAPS 64 +#define MAX_NAMELENGTH 16 + +#define ID_GAMETYPE 10 +#define ID_PICTURES 11 // 12, 13, 14 +#define ID_PREVPAGE 15 +#define ID_NEXTPAGE 16 +#define ID_STARTSERVERBACK 17 +#define ID_STARTSERVERNEXT 18 + +typedef struct { + menuframework_s menu; + + menutext_s banner; + menubitmap_s framel; + menubitmap_s framer; + + menulist_s gametype; + menubitmap_s mappics[MAX_MAPSPERPAGE]; + menubitmap_s mapbuttons[MAX_MAPSPERPAGE]; + menubitmap_s arrows; + menubitmap_s prevpage; + menubitmap_s nextpage; + menubitmap_s back; + menubitmap_s next; + + menutext_s mapname; + menubitmap_s item_null; + + qboolean multiplayer; + int currentmap; + int nummaps; + int page; + int maxpages; + char maplist[MAX_SERVERMAPS][MAX_NAMELENGTH]; + int mapGamebits[MAX_SERVERMAPS]; +} startserver_t; + +static startserver_t s_startserver; + +static const char *gametype_items[] = { + "Free For All", + "Team Deathmatch", + "Tournament", + "Capture the Flag", + 0 +}; + +static int gametype_remap[] = {GT_FFA, GT_TEAM, GT_TOURNAMENT, GT_CTF}; +static int gametype_remap2[] = {0, 2, 0, 1, 3}; + +// use ui_servers2.c definition +extern const char* punkbuster_items[]; + +static void UI_ServerOptionsMenu( qboolean multiplayer ); + + +/* +================= +GametypeBits +================= +*/ +static int GametypeBits( char *string ) { + int bits; + char *p; + char *token; + + bits = 0; + p = string; + while( 1 ) { + token = COM_ParseExt( &p, qfalse ); + if( token[0] == 0 ) { + break; + } + + if( Q_stricmp( token, "ffa" ) == 0 ) { + bits |= 1 << GT_FFA; + continue; + } + + if( Q_stricmp( token, "tourney" ) == 0 ) { + bits |= 1 << GT_TOURNAMENT; + continue; + } + + if( Q_stricmp( token, "single" ) == 0 ) { + bits |= 1 << GT_SINGLE_PLAYER; + continue; + } + + if( Q_stricmp( token, "team" ) == 0 ) { + bits |= 1 << GT_TEAM; + continue; + } + + if( Q_stricmp( token, "ctf" ) == 0 ) { + bits |= 1 << GT_CTF; + continue; + } + } + + return bits; +} + + +/* +================= +StartServer_Update +================= +*/ +static void StartServer_Update( void ) { + int i; + int top; + static char picname[MAX_MAPSPERPAGE][64]; + + top = s_startserver.page*MAX_MAPSPERPAGE; + + for (i=0; i= s_startserver.nummaps) + break; + + Com_sprintf( picname[i], sizeof(picname[i]), "levelshots/%s", s_startserver.maplist[top+i] ); + + s_startserver.mappics[i].generic.flags &= ~QMF_HIGHLIGHT; + s_startserver.mappics[i].generic.name = picname[i]; + s_startserver.mappics[i].shader = 0; + + // reset + s_startserver.mapbuttons[i].generic.flags |= QMF_PULSEIFFOCUS; + s_startserver.mapbuttons[i].generic.flags &= ~QMF_INACTIVE; + } + + for (; i=0 && i < MAX_MAPSPERPAGE ) + { + s_startserver.mappics[i].generic.flags |= QMF_HIGHLIGHT; + s_startserver.mapbuttons[i].generic.flags &= ~QMF_PULSEIFFOCUS; + } + + // set the map name + strcpy( s_startserver.mapname.string, s_startserver.maplist[s_startserver.currentmap] ); + } + + Q_strupr( s_startserver.mapname.string ); +} + + +/* +================= +StartServer_MapEvent +================= +*/ +static void StartServer_MapEvent( void* ptr, int event ) { + if( event != QM_ACTIVATED) { + return; + } + + s_startserver.currentmap = (s_startserver.page*MAX_MAPSPERPAGE) + (((menucommon_s*)ptr)->id - ID_PICTURES); + StartServer_Update(); +} + + +/* +================= +StartServer_GametypeEvent +================= +*/ +static void StartServer_GametypeEvent( void* ptr, int event ) { + int i; + int count; + int gamebits; + int matchbits; + const char *info; + + if( event != QM_ACTIVATED) { + return; + } + + count = UI_GetNumArenas(); + s_startserver.nummaps = 0; + matchbits = 1 << gametype_remap[s_startserver.gametype.curvalue]; + if( gametype_remap[s_startserver.gametype.curvalue] == GT_FFA ) { + matchbits |= ( 1 << GT_SINGLE_PLAYER ); + } + for( i = 0; i < count; i++ ) { + info = UI_GetArenaInfoByNumber( i ); + + gamebits = GametypeBits( Info_ValueForKey( info, "type") ); + if( !( gamebits & matchbits ) ) { + continue; + } + + Q_strncpyz( s_startserver.maplist[s_startserver.nummaps], Info_ValueForKey( info, "map"), MAX_NAMELENGTH ); + Q_strupr( s_startserver.maplist[s_startserver.nummaps] ); + s_startserver.mapGamebits[s_startserver.nummaps] = gamebits; + s_startserver.nummaps++; + } + s_startserver.maxpages = (s_startserver.nummaps + MAX_MAPSPERPAGE-1)/MAX_MAPSPERPAGE; + s_startserver.page = 0; + s_startserver.currentmap = 0; + + StartServer_Update(); +} + + +/* +================= +StartServer_MenuEvent +================= +*/ +static void StartServer_MenuEvent( void* ptr, int event ) { + if( event != QM_ACTIVATED ) { + return; + } + + switch( ((menucommon_s*)ptr)->id ) { + case ID_PREVPAGE: + if( s_startserver.page > 0 ) { + s_startserver.page--; + StartServer_Update(); + } + break; + + case ID_NEXTPAGE: + if( s_startserver.page < s_startserver.maxpages - 1 ) { + s_startserver.page++; + StartServer_Update(); + } + break; + + case ID_STARTSERVERNEXT: + trap_Cvar_SetValue( "g_gameType", gametype_remap[s_startserver.gametype.curvalue] ); + UI_ServerOptionsMenu( s_startserver.multiplayer ); + break; + + case ID_STARTSERVERBACK: + UI_PopMenu(); + break; + } +} + + +/* +=============== +StartServer_LevelshotDraw +=============== +*/ +static void StartServer_LevelshotDraw( void *self ) { + menubitmap_s *b; + int x; + int y; + int w; + int h; + int n; + + b = (menubitmap_s *)self; + + if( !b->generic.name ) { + return; + } + + if( b->generic.name && !b->shader ) { + b->shader = trap_R_RegisterShaderNoMip( b->generic.name ); + if( !b->shader && b->errorpic ) { + b->shader = trap_R_RegisterShaderNoMip( b->errorpic ); + } + } + + if( b->focuspic && !b->focusshader ) { + b->focusshader = trap_R_RegisterShaderNoMip( b->focuspic ); + } + + x = b->generic.x; + y = b->generic.y; + w = b->width; + h = b->height; + if( b->shader ) { + UI_DrawHandlePic( x, y, w, h, b->shader ); + } + + x = b->generic.x; + y = b->generic.y + b->height; + UI_FillRect( x, y, b->width, 28, colorBlack ); + + x += b->width / 2; + y += 4; + n = s_startserver.page * MAX_MAPSPERPAGE + b->generic.id - ID_PICTURES; + UI_DrawString( x, y, s_startserver.maplist[n], UI_CENTER|UI_SMALLFONT, color_orange ); + + x = b->generic.x; + y = b->generic.y; + w = b->width; + h = b->height + 28; + if( b->generic.flags & QMF_HIGHLIGHT ) { + UI_DrawHandlePic( x, y, w, h, b->focusshader ); + } +} + + +/* +================= +StartServer_MenuInit +================= +*/ +static void StartServer_MenuInit( void ) { + int i; + int x; + int y; + static char mapnamebuffer[64]; + + // zero set all our globals + memset( &s_startserver, 0 ,sizeof(startserver_t) ); + + StartServer_Cache(); + + s_startserver.menu.wrapAround = qtrue; + s_startserver.menu.fullscreen = qtrue; + + s_startserver.banner.generic.type = MTYPE_BTEXT; + s_startserver.banner.generic.x = 320; + s_startserver.banner.generic.y = 16; + s_startserver.banner.string = "GAME SERVER"; + s_startserver.banner.color = color_white; + s_startserver.banner.style = UI_CENTER; + + s_startserver.framel.generic.type = MTYPE_BITMAP; + s_startserver.framel.generic.name = GAMESERVER_FRAMEL; + s_startserver.framel.generic.flags = QMF_INACTIVE; + s_startserver.framel.generic.x = 0; + s_startserver.framel.generic.y = 78; + s_startserver.framel.width = 256; + s_startserver.framel.height = 329; + + s_startserver.framer.generic.type = MTYPE_BITMAP; + s_startserver.framer.generic.name = GAMESERVER_FRAMER; + s_startserver.framer.generic.flags = QMF_INACTIVE; + s_startserver.framer.generic.x = 376; + s_startserver.framer.generic.y = 76; + s_startserver.framer.width = 256; + s_startserver.framer.height = 334; + + s_startserver.gametype.generic.type = MTYPE_SPINCONTROL; + s_startserver.gametype.generic.name = "Game Type:"; + s_startserver.gametype.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT; + s_startserver.gametype.generic.callback = StartServer_GametypeEvent; + s_startserver.gametype.generic.id = ID_GAMETYPE; + s_startserver.gametype.generic.x = 320 - 24; + s_startserver.gametype.generic.y = 368; + s_startserver.gametype.itemnames = gametype_items; + + for (i=0; i= GT_TEAM) && + (s_serveroptions.playerTeam[n].curvalue != s_serveroptions.playerTeam[s_serveroptions.newBotIndex].curvalue ) ) { + continue; + } + if( Q_stricmp( checkName, s_serveroptions.playerNameBuffers[n] ) == 0 ) { + return qtrue; + } + } + + return qfalse; +} + + +/* +================= +ServerOptions_Start +================= +*/ +static void ServerOptions_Start( void ) { + int timelimit; + int fraglimit; + int maxclients; + int dedicated; + int friendlyfire; + int flaglimit; + int pure; + int skill; + int n; + char buf[64]; + + + timelimit = atoi( s_serveroptions.timelimit.field.buffer ); + fraglimit = atoi( s_serveroptions.fraglimit.field.buffer ); + flaglimit = atoi( s_serveroptions.flaglimit.field.buffer ); + dedicated = s_serveroptions.dedicated.curvalue; + friendlyfire = s_serveroptions.friendlyfire.curvalue; + pure = s_serveroptions.pure.curvalue; + skill = s_serveroptions.botSkill.curvalue + 1; + + //set maxclients + for( n = 0, maxclients = 0; n < PLAYER_SLOTS; n++ ) { + if( s_serveroptions.playerType[n].curvalue == 2 ) { + continue; + } + if( (s_serveroptions.playerType[n].curvalue == 1) && (s_serveroptions.playerNameBuffers[n][0] == 0) ) { + continue; + } + maxclients++; + } + + switch( s_serveroptions.gametype ) { + case GT_FFA: + default: + trap_Cvar_SetValue( "ui_ffa_fraglimit", fraglimit ); + trap_Cvar_SetValue( "ui_ffa_timelimit", timelimit ); + break; + + case GT_TOURNAMENT: + trap_Cvar_SetValue( "ui_tourney_fraglimit", fraglimit ); + trap_Cvar_SetValue( "ui_tourney_timelimit", timelimit ); + break; + + case GT_TEAM: + trap_Cvar_SetValue( "ui_team_fraglimit", fraglimit ); + trap_Cvar_SetValue( "ui_team_timelimit", timelimit ); + trap_Cvar_SetValue( "ui_team_friendlt", friendlyfire ); + break; + + case GT_CTF: + trap_Cvar_SetValue( "ui_ctf_fraglimit", fraglimit ); + trap_Cvar_SetValue( "ui_ctf_timelimit", timelimit ); + trap_Cvar_SetValue( "ui_ctf_friendlt", friendlyfire ); + break; + } + + trap_Cvar_SetValue( "sv_maxclients", Com_Clamp( 0, 12, maxclients ) ); + trap_Cvar_SetValue( "dedicated", Com_Clamp( 0, 2, dedicated ) ); + trap_Cvar_SetValue ("timelimit", Com_Clamp( 0, timelimit, timelimit ) ); + trap_Cvar_SetValue ("fraglimit", Com_Clamp( 0, fraglimit, fraglimit ) ); + trap_Cvar_SetValue ("capturelimit", Com_Clamp( 0, flaglimit, flaglimit ) ); + trap_Cvar_SetValue( "g_friendlyfire", friendlyfire ); + trap_Cvar_SetValue( "sv_pure", pure ); + trap_Cvar_Set("sv_hostname", s_serveroptions.hostname.field.buffer ); + + trap_Cvar_SetValue( "sv_punkbuster", s_serveroptions.punkbuster.curvalue ); + + // the wait commands will allow the dedicated to take effect + trap_Cmd_ExecuteText( EXEC_APPEND, va( "wait ; wait ; map %s\n", s_startserver.maplist[s_startserver.currentmap] ) ); + + // add bots + trap_Cmd_ExecuteText( EXEC_APPEND, "wait 3\n" ); + for( n = 1; n < PLAYER_SLOTS; n++ ) { + if( s_serveroptions.playerType[n].curvalue != 1 ) { + continue; + } + if( s_serveroptions.playerNameBuffers[n][0] == 0 ) { + continue; + } + if( s_serveroptions.playerNameBuffers[n][0] == '-' ) { + continue; + } + if( s_serveroptions.gametype >= GT_TEAM ) { + Com_sprintf( buf, sizeof(buf), "addbot %s %i %s\n", s_serveroptions.playerNameBuffers[n], skill, + playerTeam_list[s_serveroptions.playerTeam[n].curvalue] ); + } + else { + Com_sprintf( buf, sizeof(buf), "addbot %s %i\n", s_serveroptions.playerNameBuffers[n], skill ); + } + trap_Cmd_ExecuteText( EXEC_APPEND, buf ); + } + + // set player's team + if( dedicated == 0 && s_serveroptions.gametype >= GT_TEAM ) { + trap_Cmd_ExecuteText( EXEC_APPEND, va( "wait 5; team %s\n", playerTeam_list[s_serveroptions.playerTeam[0].curvalue] ) ); + } +} + + +/* +================= +ServerOptions_InitPlayerItems +================= +*/ +static void ServerOptions_InitPlayerItems( void ) { + int n; + int v; + + // init types + if( s_serveroptions.multiplayer ) { + v = 0; // open + } + else { + v = 1; // bot + } + + for( n = 0; n < PLAYER_SLOTS; n++ ) { + s_serveroptions.playerType[n].curvalue = v; + } + + if( s_serveroptions.multiplayer && (s_serveroptions.gametype < GT_TEAM) ) { + for( n = 8; n < PLAYER_SLOTS; n++ ) { + s_serveroptions.playerType[n].curvalue = 2; + } + } + + // if not a dedicated server, first slot is reserved for the human on the server + if( s_serveroptions.dedicated.curvalue == 0 ) { + // human + s_serveroptions.playerType[0].generic.flags |= QMF_INACTIVE; + s_serveroptions.playerType[0].curvalue = 0; + trap_Cvar_VariableStringBuffer( "name", s_serveroptions.playerNameBuffers[0], sizeof(s_serveroptions.playerNameBuffers[0]) ); + Q_CleanStr( s_serveroptions.playerNameBuffers[0] ); + } + + // init teams + if( s_serveroptions.gametype >= GT_TEAM ) { + for( n = 0; n < (PLAYER_SLOTS / 2); n++ ) { + s_serveroptions.playerTeam[n].curvalue = 0; + } + for( ; n < PLAYER_SLOTS; n++ ) { + s_serveroptions.playerTeam[n].curvalue = 1; + } + } + else { + for( n = 0; n < PLAYER_SLOTS; n++ ) { + s_serveroptions.playerTeam[n].generic.flags |= (QMF_INACTIVE|QMF_HIDDEN); + } + } +} + + +/* +================= +ServerOptions_SetPlayerItems +================= +*/ +static void ServerOptions_SetPlayerItems( void ) { + int start; + int n; + + // types +// for( n = 0; n < PLAYER_SLOTS; n++ ) { +// if( (!s_serveroptions.multiplayer) && (n > 0) && (s_serveroptions.playerType[n].curvalue == 0) ) { +// s_serveroptions.playerType[n].curvalue = 1; +// } +// } + + // names + if( s_serveroptions.dedicated.curvalue == 0 ) { + s_serveroptions.player0.string = "Human"; + s_serveroptions.playerName[0].generic.flags &= ~QMF_HIDDEN; + + start = 1; + } + else { + s_serveroptions.player0.string = "Open"; + start = 0; + } + for( n = start; n < PLAYER_SLOTS; n++ ) { + if( s_serveroptions.playerType[n].curvalue == 1 ) { + s_serveroptions.playerName[n].generic.flags &= ~(QMF_INACTIVE|QMF_HIDDEN); + } + else { + s_serveroptions.playerName[n].generic.flags |= (QMF_INACTIVE|QMF_HIDDEN); + } + } + + // teams + if( s_serveroptions.gametype < GT_TEAM ) { + return; + } + for( n = start; n < PLAYER_SLOTS; n++ ) { + if( s_serveroptions.playerType[n].curvalue == 2 ) { + s_serveroptions.playerTeam[n].generic.flags |= (QMF_INACTIVE|QMF_HIDDEN); + } + else { + s_serveroptions.playerTeam[n].generic.flags &= ~(QMF_INACTIVE|QMF_HIDDEN); + } + } +} + + +/* +================= +ServerOptions_Event +================= +*/ +static void ServerOptions_Event( void* ptr, int event ) { + switch( ((menucommon_s*)ptr)->id ) { + + //if( event != QM_ACTIVATED && event != QM_LOSTFOCUS) { + // return; + //} + case ID_PLAYER_TYPE: + if( event != QM_ACTIVATED ) { + break; + } + ServerOptions_SetPlayerItems(); + break; + + case ID_MAXCLIENTS: + case ID_DEDICATED: + ServerOptions_SetPlayerItems(); + break; + case ID_GO: + if( event != QM_ACTIVATED ) { + break; + } + ServerOptions_Start(); + break; + + case ID_STARTSERVERNEXT: + if( event != QM_ACTIVATED ) { + break; + } + break; + case ID_BACK: + if( event != QM_ACTIVATED ) { + break; + } + UI_PopMenu(); + break; + } +} + + +static void ServerOptions_PlayerNameEvent( void* ptr, int event ) { + int n; + + if( event != QM_ACTIVATED ) { + return; + } + n = ((menutext_s*)ptr)->generic.id; + s_serveroptions.newBotIndex = n; + UI_BotSelectMenu( s_serveroptions.playerNameBuffers[n] ); +} + + +/* +================= +ServerOptions_StatusBar +================= +*/ +static void ServerOptions_StatusBar( void* ptr ) { + switch( ((menucommon_s*)ptr)->id ) { + default: + UI_DrawString( 320, 440, "0 = NO LIMIT", UI_CENTER|UI_SMALLFONT, colorWhite ); + break; + } +} + + +/* +=============== +ServerOptions_LevelshotDraw +=============== +*/ +static void ServerOptions_LevelshotDraw( void *self ) { + menubitmap_s *b; + int x; + int y; + + // strange place for this, but it works + if( s_serveroptions.newBot ) { + Q_strncpyz( s_serveroptions.playerNameBuffers[s_serveroptions.newBotIndex], s_serveroptions.newBotName, 16 ); + s_serveroptions.newBot = qfalse; + } + + b = (menubitmap_s *)self; + + Bitmap_Draw( b ); + + x = b->generic.x; + y = b->generic.y + b->height; + UI_FillRect( x, y, b->width, 40, colorBlack ); + + x += b->width / 2; + y += 4; + UI_DrawString( x, y, s_serveroptions.mapnamebuffer, UI_CENTER|UI_SMALLFONT, color_orange ); + + y += SMALLCHAR_HEIGHT; + UI_DrawString( x, y, gametype_items[gametype_remap2[s_serveroptions.gametype]], UI_CENTER|UI_SMALLFONT, color_orange ); +} + + +static void ServerOptions_InitBotNames( void ) { + int count; + int n; + const char *arenaInfo; + const char *botInfo; + char *p; + char *bot; + char bots[MAX_INFO_STRING]; + + if( s_serveroptions.gametype >= GT_TEAM ) { + Q_strncpyz( s_serveroptions.playerNameBuffers[1], "grunt", 16 ); + Q_strncpyz( s_serveroptions.playerNameBuffers[2], "major", 16 ); + if( s_serveroptions.gametype == GT_TEAM ) { + Q_strncpyz( s_serveroptions.playerNameBuffers[3], "visor", 16 ); + } + else { + s_serveroptions.playerType[3].curvalue = 2; + } + s_serveroptions.playerType[4].curvalue = 2; + s_serveroptions.playerType[5].curvalue = 2; + + Q_strncpyz( s_serveroptions.playerNameBuffers[6], "sarge", 16 ); + Q_strncpyz( s_serveroptions.playerNameBuffers[7], "grunt", 16 ); + Q_strncpyz( s_serveroptions.playerNameBuffers[8], "major", 16 ); + if( s_serveroptions.gametype == GT_TEAM ) { + Q_strncpyz( s_serveroptions.playerNameBuffers[9], "visor", 16 ); + } + else { + s_serveroptions.playerType[9].curvalue = 2; + } + s_serveroptions.playerType[10].curvalue = 2; + s_serveroptions.playerType[11].curvalue = 2; + + return; + } + + count = 1; // skip the first slot, reserved for a human + + // get info for this map + arenaInfo = UI_GetArenaInfoByMap( s_serveroptions.mapnamebuffer ); + + // get the bot info - we'll seed with them if any are listed + Q_strncpyz( bots, Info_ValueForKey( arenaInfo, "bots" ), sizeof(bots) ); + p = &bots[0]; + while( *p && count < PLAYER_SLOTS ) { + //skip spaces + while( *p && *p == ' ' ) { + p++; + } + if( !p ) { + break; + } + + // mark start of bot name + bot = p; + + // skip until space of null + while( *p && *p != ' ' ) { + p++; + } + if( *p ) { + *p++ = 0; + } + + botInfo = UI_GetBotInfoByName( bot ); + bot = Info_ValueForKey( botInfo, "name" ); + + Q_strncpyz( s_serveroptions.playerNameBuffers[count], bot, sizeof(s_serveroptions.playerNameBuffers[count]) ); + count++; + } + + // set the rest of the bot slots to "---" + for( n = count; n < PLAYER_SLOTS; n++ ) { + strcpy( s_serveroptions.playerNameBuffers[n], "--------" ); + } + + // pad up to #8 as open slots + for( ;count < 8; count++ ) { + s_serveroptions.playerType[count].curvalue = 0; + } + + // close off the rest by default + for( ;count < PLAYER_SLOTS; count++ ) { + if( s_serveroptions.playerType[count].curvalue == 1 ) { + s_serveroptions.playerType[count].curvalue = 2; + } + } +} + + +/* +================= +ServerOptions_SetMenuItems +================= +*/ +static void ServerOptions_SetMenuItems( void ) { + static char picname[64]; + + switch( s_serveroptions.gametype ) { + case GT_FFA: + default: + Com_sprintf( s_serveroptions.fraglimit.field.buffer, 4, "%i", (int)Com_Clamp( 0, 999, trap_Cvar_VariableValue( "ui_ffa_fraglimit" ) ) ); + Com_sprintf( s_serveroptions.timelimit.field.buffer, 4, "%i", (int)Com_Clamp( 0, 999, trap_Cvar_VariableValue( "ui_ffa_timelimit" ) ) ); + break; + + case GT_TOURNAMENT: + Com_sprintf( s_serveroptions.fraglimit.field.buffer, 4, "%i", (int)Com_Clamp( 0, 999, trap_Cvar_VariableValue( "ui_tourney_fraglimit" ) ) ); + Com_sprintf( s_serveroptions.timelimit.field.buffer, 4, "%i", (int)Com_Clamp( 0, 999, trap_Cvar_VariableValue( "ui_tourney_timelimit" ) ) ); + break; + + case GT_TEAM: + Com_sprintf( s_serveroptions.fraglimit.field.buffer, 4, "%i", (int)Com_Clamp( 0, 999, trap_Cvar_VariableValue( "ui_team_fraglimit" ) ) ); + Com_sprintf( s_serveroptions.timelimit.field.buffer, 4, "%i", (int)Com_Clamp( 0, 999, trap_Cvar_VariableValue( "ui_team_timelimit" ) ) ); + s_serveroptions.friendlyfire.curvalue = (int)Com_Clamp( 0, 1, trap_Cvar_VariableValue( "ui_team_friendly" ) ); + break; + + case GT_CTF: + Com_sprintf( s_serveroptions.flaglimit.field.buffer, 4, "%i", (int)Com_Clamp( 0, 100, trap_Cvar_VariableValue( "ui_ctf_capturelimit" ) ) ); + Com_sprintf( s_serveroptions.timelimit.field.buffer, 4, "%i", (int)Com_Clamp( 0, 999, trap_Cvar_VariableValue( "ui_ctf_timelimit" ) ) ); + s_serveroptions.friendlyfire.curvalue = (int)Com_Clamp( 0, 1, trap_Cvar_VariableValue( "ui_ctf_friendly" ) ); + break; + } + + Q_strncpyz( s_serveroptions.hostname.field.buffer, UI_Cvar_VariableString( "sv_hostname" ), sizeof( s_serveroptions.hostname.field.buffer ) ); + s_serveroptions.pure.curvalue = Com_Clamp( 0, 1, trap_Cvar_VariableValue( "sv_pure" ) ); + + // set the map pic + Com_sprintf( picname, 64, "levelshots/%s", s_startserver.maplist[s_startserver.currentmap] ); + s_serveroptions.mappic.generic.name = picname; + + // set the map name + strcpy( s_serveroptions.mapnamebuffer, s_startserver.mapname.string ); + Q_strupr( s_serveroptions.mapnamebuffer ); + + // get the player selections initialized + ServerOptions_InitPlayerItems(); + ServerOptions_SetPlayerItems(); + + // seed bot names + ServerOptions_InitBotNames(); + ServerOptions_SetPlayerItems(); +} + +/* +================= +PlayerName_Draw +================= +*/ +static void PlayerName_Draw( void *item ) { + menutext_s *s; + float *color; + int x, y; + int style; + qboolean focus; + + s = (menutext_s *)item; + + x = s->generic.x; + y = s->generic.y; + + style = UI_SMALLFONT; + focus = (s->generic.parent->cursor == s->generic.menuPosition); + + if ( s->generic.flags & QMF_GRAYED ) + color = text_color_disabled; + else if ( focus ) + { + color = text_color_highlight; + style |= UI_PULSE; + } + else if ( s->generic.flags & QMF_BLINK ) + { + color = text_color_highlight; + style |= UI_BLINK; + } + else + color = text_color_normal; + + if ( focus ) + { + // draw cursor + UI_FillRect( s->generic.left, s->generic.top, s->generic.right-s->generic.left+1, s->generic.bottom-s->generic.top+1, listbar_color ); + UI_DrawChar( x, y, 13, UI_CENTER|UI_BLINK|UI_SMALLFONT, color); + } + + UI_DrawString( x - SMALLCHAR_WIDTH, y, s->generic.name, style|UI_RIGHT, color ); + UI_DrawString( x + SMALLCHAR_WIDTH, y, s->string, style|UI_LEFT, color ); +} + + +/* +================= +ServerOptions_MenuInit +================= +*/ +#define OPTIONS_X 456 + +static void ServerOptions_MenuInit( qboolean multiplayer ) { + int y; + int n; + + memset( &s_serveroptions, 0 ,sizeof(serveroptions_t) ); + s_serveroptions.multiplayer = multiplayer; + s_serveroptions.gametype = (int)Com_Clamp( 0, 5, trap_Cvar_VariableValue( "g_gameType" ) ); + s_serveroptions.punkbuster.curvalue = Com_Clamp( 0, 1, trap_Cvar_VariableValue( "sv_punkbuster" ) ); + + ServerOptions_Cache(); + + s_serveroptions.menu.wrapAround = qtrue; + s_serveroptions.menu.fullscreen = qtrue; + + s_serveroptions.banner.generic.type = MTYPE_BTEXT; + s_serveroptions.banner.generic.x = 320; + s_serveroptions.banner.generic.y = 16; + s_serveroptions.banner.string = "GAME SERVER"; + s_serveroptions.banner.color = color_white; + s_serveroptions.banner.style = UI_CENTER; + + s_serveroptions.mappic.generic.type = MTYPE_BITMAP; + s_serveroptions.mappic.generic.flags = QMF_LEFT_JUSTIFY|QMF_INACTIVE; + s_serveroptions.mappic.generic.x = 352; + s_serveroptions.mappic.generic.y = 80; + s_serveroptions.mappic.width = 160; + s_serveroptions.mappic.height = 120; + s_serveroptions.mappic.errorpic = GAMESERVER_UNKNOWNMAP; + s_serveroptions.mappic.generic.ownerdraw = ServerOptions_LevelshotDraw; + + s_serveroptions.picframe.generic.type = MTYPE_BITMAP; + s_serveroptions.picframe.generic.flags = QMF_LEFT_JUSTIFY|QMF_INACTIVE|QMF_HIGHLIGHT; + s_serveroptions.picframe.generic.x = 352 - 38; + s_serveroptions.picframe.generic.y = 80 - 40; + s_serveroptions.picframe.width = 320; + s_serveroptions.picframe.height = 320; + s_serveroptions.picframe.focuspic = GAMESERVER_SELECT; + + y = 272; + if( s_serveroptions.gametype != GT_CTF ) { + s_serveroptions.fraglimit.generic.type = MTYPE_FIELD; + s_serveroptions.fraglimit.generic.name = "Frag Limit:"; + s_serveroptions.fraglimit.generic.flags = QMF_NUMBERSONLY|QMF_PULSEIFFOCUS|QMF_SMALLFONT; + s_serveroptions.fraglimit.generic.x = OPTIONS_X; + s_serveroptions.fraglimit.generic.y = y; + s_serveroptions.fraglimit.generic.statusbar = ServerOptions_StatusBar; + s_serveroptions.fraglimit.field.widthInChars = 3; + s_serveroptions.fraglimit.field.maxchars = 3; + } + else { + s_serveroptions.flaglimit.generic.type = MTYPE_FIELD; + s_serveroptions.flaglimit.generic.name = "Capture Limit:"; + s_serveroptions.flaglimit.generic.flags = QMF_NUMBERSONLY|QMF_PULSEIFFOCUS|QMF_SMALLFONT; + s_serveroptions.flaglimit.generic.x = OPTIONS_X; + s_serveroptions.flaglimit.generic.y = y; + s_serveroptions.flaglimit.generic.statusbar = ServerOptions_StatusBar; + s_serveroptions.flaglimit.field.widthInChars = 3; + s_serveroptions.flaglimit.field.maxchars = 3; + } + + y += BIGCHAR_HEIGHT+2; + s_serveroptions.timelimit.generic.type = MTYPE_FIELD; + s_serveroptions.timelimit.generic.name = "Time Limit:"; + s_serveroptions.timelimit.generic.flags = QMF_NUMBERSONLY|QMF_PULSEIFFOCUS|QMF_SMALLFONT; + s_serveroptions.timelimit.generic.x = OPTIONS_X; + s_serveroptions.timelimit.generic.y = y; + s_serveroptions.timelimit.generic.statusbar = ServerOptions_StatusBar; + s_serveroptions.timelimit.field.widthInChars = 3; + s_serveroptions.timelimit.field.maxchars = 3; + + if( s_serveroptions.gametype >= GT_TEAM ) { + y += BIGCHAR_HEIGHT+2; + s_serveroptions.friendlyfire.generic.type = MTYPE_RADIOBUTTON; + s_serveroptions.friendlyfire.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT; + s_serveroptions.friendlyfire.generic.x = OPTIONS_X; + s_serveroptions.friendlyfire.generic.y = y; + s_serveroptions.friendlyfire.generic.name = "Friendly Fire:"; + } + + y += BIGCHAR_HEIGHT+2; + s_serveroptions.pure.generic.type = MTYPE_RADIOBUTTON; + s_serveroptions.pure.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT; + s_serveroptions.pure.generic.x = OPTIONS_X; + s_serveroptions.pure.generic.y = y; + s_serveroptions.pure.generic.name = "Pure Server:"; + + if( s_serveroptions.multiplayer ) { + y += BIGCHAR_HEIGHT+2; + s_serveroptions.dedicated.generic.type = MTYPE_SPINCONTROL; + s_serveroptions.dedicated.generic.id = ID_DEDICATED; + s_serveroptions.dedicated.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT; + s_serveroptions.dedicated.generic.callback = ServerOptions_Event; + s_serveroptions.dedicated.generic.x = OPTIONS_X; + s_serveroptions.dedicated.generic.y = y; + s_serveroptions.dedicated.generic.name = "Dedicated:"; + s_serveroptions.dedicated.itemnames = dedicated_list; + } + + if( s_serveroptions.multiplayer ) { + y += BIGCHAR_HEIGHT+2; + s_serveroptions.hostname.generic.type = MTYPE_FIELD; + s_serveroptions.hostname.generic.name = "Hostname:"; + s_serveroptions.hostname.generic.flags = QMF_SMALLFONT; + s_serveroptions.hostname.generic.x = OPTIONS_X; + s_serveroptions.hostname.generic.y = y; + s_serveroptions.hostname.field.widthInChars = 18; + s_serveroptions.hostname.field.maxchars = 64; + } + + y += BIGCHAR_HEIGHT+2; + s_serveroptions.punkbuster.generic.type = MTYPE_SPINCONTROL; + s_serveroptions.punkbuster.generic.name = "Punkbuster:"; + s_serveroptions.punkbuster.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT; + s_serveroptions.punkbuster.generic.id = 0; + s_serveroptions.punkbuster.generic.x = OPTIONS_X; + s_serveroptions.punkbuster.generic.y = y; + s_serveroptions.punkbuster.itemnames = punkbuster_items; + + y = 80; + s_serveroptions.botSkill.generic.type = MTYPE_SPINCONTROL; + s_serveroptions.botSkill.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT; + s_serveroptions.botSkill.generic.name = "Bot Skill: "; + s_serveroptions.botSkill.generic.x = 32 + (strlen(s_serveroptions.botSkill.generic.name) + 2 ) * SMALLCHAR_WIDTH; + s_serveroptions.botSkill.generic.y = y; + s_serveroptions.botSkill.itemnames = botSkill_list; + s_serveroptions.botSkill.curvalue = 1; + + y += ( 2 * SMALLCHAR_HEIGHT ); + s_serveroptions.player0.generic.type = MTYPE_TEXT; + s_serveroptions.player0.generic.flags = QMF_SMALLFONT; + s_serveroptions.player0.generic.x = 32 + SMALLCHAR_WIDTH; + s_serveroptions.player0.generic.y = y; + s_serveroptions.player0.color = color_orange; + s_serveroptions.player0.style = UI_LEFT|UI_SMALLFONT; + + for( n = 0; n < PLAYER_SLOTS; n++ ) { + s_serveroptions.playerType[n].generic.type = MTYPE_SPINCONTROL; + s_serveroptions.playerType[n].generic.flags = QMF_SMALLFONT; + s_serveroptions.playerType[n].generic.id = ID_PLAYER_TYPE; + s_serveroptions.playerType[n].generic.callback = ServerOptions_Event; + s_serveroptions.playerType[n].generic.x = 32; + s_serveroptions.playerType[n].generic.y = y; + s_serveroptions.playerType[n].itemnames = playerType_list; + + s_serveroptions.playerName[n].generic.type = MTYPE_TEXT; + s_serveroptions.playerName[n].generic.flags = QMF_SMALLFONT; + s_serveroptions.playerName[n].generic.x = 96; + s_serveroptions.playerName[n].generic.y = y; + s_serveroptions.playerName[n].generic.callback = ServerOptions_PlayerNameEvent; + s_serveroptions.playerName[n].generic.id = n; + s_serveroptions.playerName[n].generic.ownerdraw = PlayerName_Draw; + s_serveroptions.playerName[n].color = color_orange; + s_serveroptions.playerName[n].style = UI_SMALLFONT; + s_serveroptions.playerName[n].string = s_serveroptions.playerNameBuffers[n]; + s_serveroptions.playerName[n].generic.top = s_serveroptions.playerName[n].generic.y; + s_serveroptions.playerName[n].generic.bottom = s_serveroptions.playerName[n].generic.y + SMALLCHAR_HEIGHT; + s_serveroptions.playerName[n].generic.left = s_serveroptions.playerName[n].generic.x - SMALLCHAR_HEIGHT/ 2; + s_serveroptions.playerName[n].generic.right = s_serveroptions.playerName[n].generic.x + 16 * SMALLCHAR_WIDTH; + + s_serveroptions.playerTeam[n].generic.type = MTYPE_SPINCONTROL; + s_serveroptions.playerTeam[n].generic.flags = QMF_SMALLFONT; + s_serveroptions.playerTeam[n].generic.x = 240; + s_serveroptions.playerTeam[n].generic.y = y; + s_serveroptions.playerTeam[n].itemnames = playerTeam_list; + + y += ( SMALLCHAR_HEIGHT + 4 ); + } + + s_serveroptions.back.generic.type = MTYPE_BITMAP; + s_serveroptions.back.generic.name = GAMESERVER_BACK0; + s_serveroptions.back.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS; + s_serveroptions.back.generic.callback = ServerOptions_Event; + s_serveroptions.back.generic.id = ID_BACK; + s_serveroptions.back.generic.x = 0; + s_serveroptions.back.generic.y = 480-64; + s_serveroptions.back.width = 128; + s_serveroptions.back.height = 64; + s_serveroptions.back.focuspic = GAMESERVER_BACK1; + + s_serveroptions.next.generic.type = MTYPE_BITMAP; + s_serveroptions.next.generic.name = GAMESERVER_NEXT0; + s_serveroptions.next.generic.flags = QMF_RIGHT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_INACTIVE|QMF_GRAYED|QMF_HIDDEN; + s_serveroptions.next.generic.callback = ServerOptions_Event; + s_serveroptions.next.generic.id = ID_STARTSERVERNEXT; + s_serveroptions.next.generic.x = 640; + s_serveroptions.next.generic.y = 480-64-72; + s_serveroptions.next.generic.statusbar = ServerOptions_StatusBar; + s_serveroptions.next.width = 128; + s_serveroptions.next.height = 64; + s_serveroptions.next.focuspic = GAMESERVER_NEXT1; + + s_serveroptions.go.generic.type = MTYPE_BITMAP; + s_serveroptions.go.generic.name = GAMESERVER_FIGHT0; + s_serveroptions.go.generic.flags = QMF_RIGHT_JUSTIFY|QMF_PULSEIFFOCUS; + s_serveroptions.go.generic.callback = ServerOptions_Event; + s_serveroptions.go.generic.id = ID_GO; + s_serveroptions.go.generic.x = 640; + s_serveroptions.go.generic.y = 480-64; + s_serveroptions.go.width = 128; + s_serveroptions.go.height = 64; + s_serveroptions.go.focuspic = GAMESERVER_FIGHT1; + + Menu_AddItem( &s_serveroptions.menu, &s_serveroptions.banner ); + + Menu_AddItem( &s_serveroptions.menu, &s_serveroptions.mappic ); + Menu_AddItem( &s_serveroptions.menu, &s_serveroptions.picframe ); + + Menu_AddItem( &s_serveroptions.menu, &s_serveroptions.botSkill ); + Menu_AddItem( &s_serveroptions.menu, &s_serveroptions.player0 ); + for( n = 0; n < PLAYER_SLOTS; n++ ) { + if( n != 0 ) { + Menu_AddItem( &s_serveroptions.menu, &s_serveroptions.playerType[n] ); + } + Menu_AddItem( &s_serveroptions.menu, &s_serveroptions.playerName[n] ); + if( s_serveroptions.gametype >= GT_TEAM ) { + Menu_AddItem( &s_serveroptions.menu, &s_serveroptions.playerTeam[n] ); + } + } + + if( s_serveroptions.gametype != GT_CTF ) { + Menu_AddItem( &s_serveroptions.menu, &s_serveroptions.fraglimit ); + } + else { + Menu_AddItem( &s_serveroptions.menu, &s_serveroptions.flaglimit ); + } + Menu_AddItem( &s_serveroptions.menu, &s_serveroptions.timelimit ); + if( s_serveroptions.gametype >= GT_TEAM ) { + Menu_AddItem( &s_serveroptions.menu, &s_serveroptions.friendlyfire ); + } + Menu_AddItem( &s_serveroptions.menu, &s_serveroptions.pure ); + if( s_serveroptions.multiplayer ) { + Menu_AddItem( &s_serveroptions.menu, &s_serveroptions.dedicated ); + } + if( s_serveroptions.multiplayer ) { + Menu_AddItem( &s_serveroptions.menu, &s_serveroptions.hostname ); + } + + Menu_AddItem( &s_serveroptions.menu, &s_serveroptions.back ); + Menu_AddItem( &s_serveroptions.menu, &s_serveroptions.next ); + Menu_AddItem( &s_serveroptions.menu, &s_serveroptions.go ); + + Menu_AddItem( &s_serveroptions.menu, (void*) &s_serveroptions.punkbuster ); + + ServerOptions_SetMenuItems(); +} + +/* +================= +ServerOptions_Cache +================= +*/ +void ServerOptions_Cache( void ) { + trap_R_RegisterShaderNoMip( GAMESERVER_BACK0 ); + trap_R_RegisterShaderNoMip( GAMESERVER_BACK1 ); + trap_R_RegisterShaderNoMip( GAMESERVER_FIGHT0 ); + trap_R_RegisterShaderNoMip( GAMESERVER_FIGHT1 ); + trap_R_RegisterShaderNoMip( GAMESERVER_SELECT ); + trap_R_RegisterShaderNoMip( GAMESERVER_UNKNOWNMAP ); +} + + +/* +================= +UI_ServerOptionsMenu +================= +*/ +static void UI_ServerOptionsMenu( qboolean multiplayer ) { + ServerOptions_MenuInit( multiplayer ); + UI_PushMenu( &s_serveroptions.menu ); +} + + + +/* +============================================================================= + +BOT SELECT MENU ***** + +============================================================================= +*/ + + +#define BOTSELECT_BACK0 "menu/art/back_0" +#define BOTSELECT_BACK1 "menu/art/back_1" +#define BOTSELECT_ACCEPT0 "menu/art/accept_0" +#define BOTSELECT_ACCEPT1 "menu/art/accept_1" +#define BOTSELECT_SELECT "menu/art/opponents_select" +#define BOTSELECT_SELECTED "menu/art/opponents_selected" +#define BOTSELECT_ARROWS "menu/art/gs_arrows_0" +#define BOTSELECT_ARROWSL "menu/art/gs_arrows_l" +#define BOTSELECT_ARROWSR "menu/art/gs_arrows_r" + +#define PLAYERGRID_COLS 4 +#define PLAYERGRID_ROWS 4 +#define MAX_MODELSPERPAGE (PLAYERGRID_ROWS * PLAYERGRID_COLS) + + +typedef struct { + menuframework_s menu; + + menutext_s banner; + + menubitmap_s pics[MAX_MODELSPERPAGE]; + menubitmap_s picbuttons[MAX_MODELSPERPAGE]; + menutext_s picnames[MAX_MODELSPERPAGE]; + + menubitmap_s arrows; + menubitmap_s left; + menubitmap_s right; + + menubitmap_s go; + menubitmap_s back; + + int numBots; + int modelpage; + int numpages; + int selectedmodel; + int sortedBotNums[MAX_BOTS]; + char boticons[MAX_MODELSPERPAGE][MAX_QPATH]; + char botnames[MAX_MODELSPERPAGE][16]; +} botSelectInfo_t; + +static botSelectInfo_t botSelectInfo; + + +/* +================= +UI_BotSelectMenu_SortCompare +================= +*/ +static int QDECL UI_BotSelectMenu_SortCompare( const void *arg1, const void *arg2 ) { + int num1, num2; + const char *info1, *info2; + const char *name1, *name2; + + num1 = *(int *)arg1; + num2 = *(int *)arg2; + + info1 = UI_GetBotInfoByNumber( num1 ); + info2 = UI_GetBotInfoByNumber( num2 ); + + name1 = Info_ValueForKey( info1, "name" ); + name2 = Info_ValueForKey( info2, "name" ); + + return Q_stricmp( name1, name2 ); +} + + +/* +================= +UI_BotSelectMenu_BuildList +================= +*/ +static void UI_BotSelectMenu_BuildList( void ) { + int n; + + botSelectInfo.modelpage = 0; + botSelectInfo.numBots = UI_GetNumBots(); + botSelectInfo.numpages = botSelectInfo.numBots / MAX_MODELSPERPAGE; + if( botSelectInfo.numBots % MAX_MODELSPERPAGE ) { + botSelectInfo.numpages++; + } + + // initialize the array + for( n = 0; n < botSelectInfo.numBots; n++ ) { + botSelectInfo.sortedBotNums[n] = n; + } + + // now sort it + qsort( botSelectInfo.sortedBotNums, botSelectInfo.numBots, sizeof(botSelectInfo.sortedBotNums[0]), UI_BotSelectMenu_SortCompare ); +} + + +/* +================= +ServerPlayerIcon +================= +*/ +static void ServerPlayerIcon( const char *modelAndSkin, char *iconName, int iconNameMaxSize ) { + char *skin; + char model[MAX_QPATH]; + + Q_strncpyz( model, modelAndSkin, sizeof(model)); + skin = Q_strrchr( model, '/' ); + if ( skin ) { + *skin++ = '\0'; + } + else { + skin = "default"; + } + + Com_sprintf(iconName, iconNameMaxSize, "models/players/%s/icon_%s.tga", model, skin ); + + if( !trap_R_RegisterShaderNoMip( iconName ) && Q_stricmp( skin, "default" ) != 0 ) { + Com_sprintf(iconName, iconNameMaxSize, "models/players/%s/icon_default.tga", model ); + } +} + + +/* +================= +UI_BotSelectMenu_UpdateGrid +================= +*/ +static void UI_BotSelectMenu_UpdateGrid( void ) { + const char *info; + int i; + int j; + + j = botSelectInfo.modelpage * MAX_MODELSPERPAGE; + for( i = 0; i < (PLAYERGRID_ROWS * PLAYERGRID_COLS); i++, j++) { + if( j < botSelectInfo.numBots ) { + info = UI_GetBotInfoByNumber( botSelectInfo.sortedBotNums[j] ); + ServerPlayerIcon( Info_ValueForKey( info, "model" ), botSelectInfo.boticons[i], MAX_QPATH ); + Q_strncpyz( botSelectInfo.botnames[i], Info_ValueForKey( info, "name" ), 16 ); + Q_CleanStr( botSelectInfo.botnames[i] ); + botSelectInfo.pics[i].generic.name = botSelectInfo.boticons[i]; + if( BotAlreadySelected( botSelectInfo.botnames[i] ) ) { + botSelectInfo.picnames[i].color = color_red; + } + else { + botSelectInfo.picnames[i].color = color_orange; + } + botSelectInfo.picbuttons[i].generic.flags &= ~QMF_INACTIVE; + } + else { + // dead slot + botSelectInfo.pics[i].generic.name = NULL; + botSelectInfo.picbuttons[i].generic.flags |= QMF_INACTIVE; + botSelectInfo.botnames[i][0] = 0; + } + + botSelectInfo.pics[i].generic.flags &= ~QMF_HIGHLIGHT; + botSelectInfo.pics[i].shader = 0; + botSelectInfo.picbuttons[i].generic.flags |= QMF_PULSEIFFOCUS; + } + + // set selected model + i = botSelectInfo.selectedmodel % MAX_MODELSPERPAGE; + botSelectInfo.pics[i].generic.flags |= QMF_HIGHLIGHT; + botSelectInfo.picbuttons[i].generic.flags &= ~QMF_PULSEIFFOCUS; + + if( botSelectInfo.numpages > 1 ) { + if( botSelectInfo.modelpage > 0 ) { + botSelectInfo.left.generic.flags &= ~QMF_INACTIVE; + } + else { + botSelectInfo.left.generic.flags |= QMF_INACTIVE; + } + + if( botSelectInfo.modelpage < (botSelectInfo.numpages - 1) ) { + botSelectInfo.right.generic.flags &= ~QMF_INACTIVE; + } + else { + botSelectInfo.right.generic.flags |= QMF_INACTIVE; + } + } + else { + // hide left/right markers + botSelectInfo.left.generic.flags |= QMF_INACTIVE; + botSelectInfo.right.generic.flags |= QMF_INACTIVE; + } +} + + +/* +================= +UI_BotSelectMenu_Default +================= +*/ +static void UI_BotSelectMenu_Default( char *bot ) { + const char *botInfo; + const char *test; + int n; + int i; + + for( n = 0; n < botSelectInfo.numBots; n++ ) { + botInfo = UI_GetBotInfoByNumber( n ); + test = Info_ValueForKey( botInfo, "name" ); + if( Q_stricmp( bot, test ) == 0 ) { + break; + } + } + if( n == botSelectInfo.numBots ) { + botSelectInfo.selectedmodel = 0; + return; + } + + for( i = 0; i < botSelectInfo.numBots; i++ ) { + if( botSelectInfo.sortedBotNums[i] == n ) { + break; + } + } + if( i == botSelectInfo.numBots ) { + botSelectInfo.selectedmodel = 0; + return; + } + + botSelectInfo.selectedmodel = i; +} + + +/* +================= +UI_BotSelectMenu_LeftEvent +================= +*/ +static void UI_BotSelectMenu_LeftEvent( void* ptr, int event ) { + if( event != QM_ACTIVATED ) { + return; + } + if( botSelectInfo.modelpage > 0 ) { + botSelectInfo.modelpage--; + botSelectInfo.selectedmodel = botSelectInfo.modelpage * MAX_MODELSPERPAGE; + UI_BotSelectMenu_UpdateGrid(); + } +} + + +/* +================= +UI_BotSelectMenu_RightEvent +================= +*/ +static void UI_BotSelectMenu_RightEvent( void* ptr, int event ) { + if( event != QM_ACTIVATED ) { + return; + } + if( botSelectInfo.modelpage < botSelectInfo.numpages - 1 ) { + botSelectInfo.modelpage++; + botSelectInfo.selectedmodel = botSelectInfo.modelpage * MAX_MODELSPERPAGE; + UI_BotSelectMenu_UpdateGrid(); + } +} + + +/* +================= +UI_BotSelectMenu_BotEvent +================= +*/ +static void UI_BotSelectMenu_BotEvent( void* ptr, int event ) { + int i; + + if( event != QM_ACTIVATED ) { + return; + } + + for( i = 0; i < (PLAYERGRID_ROWS * PLAYERGRID_COLS); i++ ) { + botSelectInfo.pics[i].generic.flags &= ~QMF_HIGHLIGHT; + botSelectInfo.picbuttons[i].generic.flags |= QMF_PULSEIFFOCUS; + } + + // set selected + i = ((menucommon_s*)ptr)->id; + botSelectInfo.pics[i].generic.flags |= QMF_HIGHLIGHT; + botSelectInfo.picbuttons[i].generic.flags &= ~QMF_PULSEIFFOCUS; + botSelectInfo.selectedmodel = botSelectInfo.modelpage * MAX_MODELSPERPAGE + i; +} + + +/* +================= +UI_BotSelectMenu_BackEvent +================= +*/ +static void UI_BotSelectMenu_BackEvent( void* ptr, int event ) { + if( event != QM_ACTIVATED ) { + return; + } + UI_PopMenu(); +} + + +/* +================= +UI_BotSelectMenu_SelectEvent +================= +*/ +static void UI_BotSelectMenu_SelectEvent( void* ptr, int event ) { + if( event != QM_ACTIVATED ) { + return; + } + UI_PopMenu(); + + s_serveroptions.newBot = qtrue; + Q_strncpyz( s_serveroptions.newBotName, botSelectInfo.botnames[botSelectInfo.selectedmodel % MAX_MODELSPERPAGE], 16 ); +} + + +/* +================= +UI_BotSelectMenu_Cache +================= +*/ +void UI_BotSelectMenu_Cache( void ) { + trap_R_RegisterShaderNoMip( BOTSELECT_BACK0 ); + trap_R_RegisterShaderNoMip( BOTSELECT_BACK1 ); + trap_R_RegisterShaderNoMip( BOTSELECT_ACCEPT0 ); + trap_R_RegisterShaderNoMip( BOTSELECT_ACCEPT1 ); + trap_R_RegisterShaderNoMip( BOTSELECT_SELECT ); + trap_R_RegisterShaderNoMip( BOTSELECT_SELECTED ); + trap_R_RegisterShaderNoMip( BOTSELECT_ARROWS ); + trap_R_RegisterShaderNoMip( BOTSELECT_ARROWSL ); + trap_R_RegisterShaderNoMip( BOTSELECT_ARROWSR ); +} + + +static void UI_BotSelectMenu_Init( char *bot ) { + int i, j, k; + int x, y; + + memset( &botSelectInfo, 0 ,sizeof(botSelectInfo) ); + botSelectInfo.menu.wrapAround = qtrue; + botSelectInfo.menu.fullscreen = qtrue; + + UI_BotSelectMenu_Cache(); + + botSelectInfo.banner.generic.type = MTYPE_BTEXT; + botSelectInfo.banner.generic.x = 320; + botSelectInfo.banner.generic.y = 16; + botSelectInfo.banner.string = "SELECT BOT"; + botSelectInfo.banner.color = color_white; + botSelectInfo.banner.style = UI_CENTER; + + y = 80; + for( i = 0, k = 0; i < PLAYERGRID_ROWS; i++) { + x = 180; + for( j = 0; j < PLAYERGRID_COLS; j++, k++ ) { + botSelectInfo.pics[k].generic.type = MTYPE_BITMAP; + botSelectInfo.pics[k].generic.flags = QMF_LEFT_JUSTIFY|QMF_INACTIVE; + botSelectInfo.pics[k].generic.x = x; + botSelectInfo.pics[k].generic.y = y; + botSelectInfo.pics[k].generic.name = botSelectInfo.boticons[k]; + botSelectInfo.pics[k].width = 64; + botSelectInfo.pics[k].height = 64; + botSelectInfo.pics[k].focuspic = BOTSELECT_SELECTED; + botSelectInfo.pics[k].focuscolor = colorRed; + + botSelectInfo.picbuttons[k].generic.type = MTYPE_BITMAP; + botSelectInfo.picbuttons[k].generic.flags = QMF_LEFT_JUSTIFY|QMF_NODEFAULTINIT|QMF_PULSEIFFOCUS; + botSelectInfo.picbuttons[k].generic.callback = UI_BotSelectMenu_BotEvent; + botSelectInfo.picbuttons[k].generic.id = k; + botSelectInfo.picbuttons[k].generic.x = x - 16; + botSelectInfo.picbuttons[k].generic.y = y - 16; + botSelectInfo.picbuttons[k].generic.left = x; + botSelectInfo.picbuttons[k].generic.top = y; + botSelectInfo.picbuttons[k].generic.right = x + 64; + botSelectInfo.picbuttons[k].generic.bottom = y + 64; + botSelectInfo.picbuttons[k].width = 128; + botSelectInfo.picbuttons[k].height = 128; + botSelectInfo.picbuttons[k].focuspic = BOTSELECT_SELECT; + botSelectInfo.picbuttons[k].focuscolor = colorRed; + + botSelectInfo.picnames[k].generic.type = MTYPE_TEXT; + botSelectInfo.picnames[k].generic.flags = QMF_SMALLFONT; + botSelectInfo.picnames[k].generic.x = x + 32; + botSelectInfo.picnames[k].generic.y = y + 64; + botSelectInfo.picnames[k].string = botSelectInfo.botnames[k]; + botSelectInfo.picnames[k].color = color_orange; + botSelectInfo.picnames[k].style = UI_CENTER|UI_SMALLFONT; + + x += (64 + 6); + } + y += (64 + SMALLCHAR_HEIGHT + 6); + } + + botSelectInfo.arrows.generic.type = MTYPE_BITMAP; + botSelectInfo.arrows.generic.name = BOTSELECT_ARROWS; + botSelectInfo.arrows.generic.flags = QMF_INACTIVE; + botSelectInfo.arrows.generic.x = 260; + botSelectInfo.arrows.generic.y = 440; + botSelectInfo.arrows.width = 128; + botSelectInfo.arrows.height = 32; + + botSelectInfo.left.generic.type = MTYPE_BITMAP; + botSelectInfo.left.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS; + botSelectInfo.left.generic.callback = UI_BotSelectMenu_LeftEvent; + botSelectInfo.left.generic.x = 260; + botSelectInfo.left.generic.y = 440; + botSelectInfo.left.width = 64; + botSelectInfo.left.height = 32; + botSelectInfo.left.focuspic = BOTSELECT_ARROWSL; + + botSelectInfo.right.generic.type = MTYPE_BITMAP; + botSelectInfo.right.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS; + botSelectInfo.right.generic.callback = UI_BotSelectMenu_RightEvent; + botSelectInfo.right.generic.x = 321; + botSelectInfo.right.generic.y = 440; + botSelectInfo.right.width = 64; + botSelectInfo.right.height = 32; + botSelectInfo.right.focuspic = BOTSELECT_ARROWSR; + + botSelectInfo.back.generic.type = MTYPE_BITMAP; + botSelectInfo.back.generic.name = BOTSELECT_BACK0; + botSelectInfo.back.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS; + botSelectInfo.back.generic.callback = UI_BotSelectMenu_BackEvent; + botSelectInfo.back.generic.x = 0; + botSelectInfo.back.generic.y = 480-64; + botSelectInfo.back.width = 128; + botSelectInfo.back.height = 64; + botSelectInfo.back.focuspic = BOTSELECT_BACK1; + + botSelectInfo.go.generic.type = MTYPE_BITMAP; + botSelectInfo.go.generic.name = BOTSELECT_ACCEPT0; + botSelectInfo.go.generic.flags = QMF_RIGHT_JUSTIFY|QMF_PULSEIFFOCUS; + botSelectInfo.go.generic.callback = UI_BotSelectMenu_SelectEvent; + botSelectInfo.go.generic.x = 640; + botSelectInfo.go.generic.y = 480-64; + botSelectInfo.go.width = 128; + botSelectInfo.go.height = 64; + botSelectInfo.go.focuspic = BOTSELECT_ACCEPT1; + + Menu_AddItem( &botSelectInfo.menu, &botSelectInfo.banner ); + for( i = 0; i < MAX_MODELSPERPAGE; i++ ) { + Menu_AddItem( &botSelectInfo.menu, &botSelectInfo.pics[i] ); + Menu_AddItem( &botSelectInfo.menu, &botSelectInfo.picbuttons[i] ); + Menu_AddItem( &botSelectInfo.menu, &botSelectInfo.picnames[i] ); + } + Menu_AddItem( &botSelectInfo.menu, &botSelectInfo.arrows ); + Menu_AddItem( &botSelectInfo.menu, &botSelectInfo.left ); + Menu_AddItem( &botSelectInfo.menu, &botSelectInfo.right ); + Menu_AddItem( &botSelectInfo.menu, &botSelectInfo.back ); + Menu_AddItem( &botSelectInfo.menu, &botSelectInfo.go ); + + UI_BotSelectMenu_BuildList(); + UI_BotSelectMenu_Default( bot ); + botSelectInfo.modelpage = botSelectInfo.selectedmodel / MAX_MODELSPERPAGE; + UI_BotSelectMenu_UpdateGrid(); +} + + +/* +================= +UI_BotSelectMenu +================= +*/ +void UI_BotSelectMenu( char *bot ) { + UI_BotSelectMenu_Init( bot ); + UI_PushMenu( &botSelectInfo.menu ); +} diff --git a/code/q3_ui/ui_team.c b/code/q3_ui/ui_team.c new file mode 100755 index 0000000..1ea1bd1 --- /dev/null +++ b/code/q3_ui/ui_team.c @@ -0,0 +1,210 @@ +/* +=========================================================================== +Copyright (C) 1999-2005 Id Software, Inc. + +This file is part of Quake III Arena source code. + +Quake III Arena source code is free software; you can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 2 of the License, +or (at your option) any later version. + +Quake III Arena source code is distributed in the hope that it will be +useful, but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Foobar; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ +// +// +// ui_team.c +// + +#include "ui_local.h" + + +#define TEAMMAIN_FRAME "menu/art/cut_frame" + +#define ID_JOINRED 100 +#define ID_JOINBLUE 101 +#define ID_JOINGAME 102 +#define ID_SPECTATE 103 + + +typedef struct +{ + menuframework_s menu; + menubitmap_s frame; + menutext_s joinred; + menutext_s joinblue; + menutext_s joingame; + menutext_s spectate; +} teammain_t; + +static teammain_t s_teammain; + +// bk001204 - unused +//static menuframework_s s_teammain_menu; +//static menuaction_s s_teammain_orders; +//static menuaction_s s_teammain_voice; +//static menuaction_s s_teammain_joinred; +//static menuaction_s s_teammain_joinblue; +//static menuaction_s s_teammain_joingame; +//static menuaction_s s_teammain_spectate; + + +/* +=============== +TeamMain_MenuEvent +=============== +*/ +static void TeamMain_MenuEvent( void* ptr, int event ) { + if( event != QM_ACTIVATED ) { + return; + } + + switch( ((menucommon_s*)ptr)->id ) { + case ID_JOINRED: + trap_Cmd_ExecuteText( EXEC_APPEND, "cmd team red\n" ); + UI_ForceMenuOff(); + break; + + case ID_JOINBLUE: + trap_Cmd_ExecuteText( EXEC_APPEND, "cmd team blue\n" ); + UI_ForceMenuOff(); + break; + + case ID_JOINGAME: + trap_Cmd_ExecuteText( EXEC_APPEND, "cmd team free\n" ); + UI_ForceMenuOff(); + break; + + case ID_SPECTATE: + trap_Cmd_ExecuteText( EXEC_APPEND, "cmd team spectator\n" ); + UI_ForceMenuOff(); + break; + } +} + + +/* +=============== +TeamMain_MenuInit +=============== +*/ +void TeamMain_MenuInit( void ) { + int y; + int gametype; + char info[MAX_INFO_STRING]; + + memset( &s_teammain, 0, sizeof(s_teammain) ); + + TeamMain_Cache(); + + s_teammain.menu.wrapAround = qtrue; + s_teammain.menu.fullscreen = qfalse; + + s_teammain.frame.generic.type = MTYPE_BITMAP; + s_teammain.frame.generic.flags = QMF_INACTIVE; + s_teammain.frame.generic.name = TEAMMAIN_FRAME; + s_teammain.frame.generic.x = 142; + s_teammain.frame.generic.y = 118; + s_teammain.frame.width = 359; + s_teammain.frame.height = 256; + + y = 194; + + s_teammain.joinred.generic.type = MTYPE_PTEXT; + s_teammain.joinred.generic.flags = QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS; + s_teammain.joinred.generic.id = ID_JOINRED; + s_teammain.joinred.generic.callback = TeamMain_MenuEvent; + s_teammain.joinred.generic.x = 320; + s_teammain.joinred.generic.y = y; + s_teammain.joinred.string = "JOIN RED"; + s_teammain.joinred.style = UI_CENTER|UI_SMALLFONT; + s_teammain.joinred.color = colorRed; + y += 20; + + s_teammain.joinblue.generic.type = MTYPE_PTEXT; + s_teammain.joinblue.generic.flags = QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS; + s_teammain.joinblue.generic.id = ID_JOINBLUE; + s_teammain.joinblue.generic.callback = TeamMain_MenuEvent; + s_teammain.joinblue.generic.x = 320; + s_teammain.joinblue.generic.y = y; + s_teammain.joinblue.string = "JOIN BLUE"; + s_teammain.joinblue.style = UI_CENTER|UI_SMALLFONT; + s_teammain.joinblue.color = colorRed; + y += 20; + + s_teammain.joingame.generic.type = MTYPE_PTEXT; + s_teammain.joingame.generic.flags = QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS; + s_teammain.joingame.generic.id = ID_JOINGAME; + s_teammain.joingame.generic.callback = TeamMain_MenuEvent; + s_teammain.joingame.generic.x = 320; + s_teammain.joingame.generic.y = y; + s_teammain.joingame.string = "JOIN GAME"; + s_teammain.joingame.style = UI_CENTER|UI_SMALLFONT; + s_teammain.joingame.color = colorRed; + y += 20; + + s_teammain.spectate.generic.type = MTYPE_PTEXT; + s_teammain.spectate.generic.flags = QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS; + s_teammain.spectate.generic.id = ID_SPECTATE; + s_teammain.spectate.generic.callback = TeamMain_MenuEvent; + s_teammain.spectate.generic.x = 320; + s_teammain.spectate.generic.y = y; + s_teammain.spectate.string = "SPECTATE"; + s_teammain.spectate.style = UI_CENTER|UI_SMALLFONT; + s_teammain.spectate.color = colorRed; + y += 20; + + trap_GetConfigString(CS_SERVERINFO, info, MAX_INFO_STRING); + gametype = atoi( Info_ValueForKey( info,"g_gametype" ) ); + + // set initial states + switch( gametype ) { + case GT_SINGLE_PLAYER: + case GT_FFA: + case GT_TOURNAMENT: + s_teammain.joinred.generic.flags |= QMF_GRAYED; + s_teammain.joinblue.generic.flags |= QMF_GRAYED; + break; + + default: + case GT_TEAM: + case GT_CTF: + s_teammain.joingame.generic.flags |= QMF_GRAYED; + break; + } + + Menu_AddItem( &s_teammain.menu, (void*) &s_teammain.frame ); + Menu_AddItem( &s_teammain.menu, (void*) &s_teammain.joinred ); + Menu_AddItem( &s_teammain.menu, (void*) &s_teammain.joinblue ); + Menu_AddItem( &s_teammain.menu, (void*) &s_teammain.joingame ); + Menu_AddItem( &s_teammain.menu, (void*) &s_teammain.spectate ); +} + + +/* +=============== +TeamMain_Cache +=============== +*/ +void TeamMain_Cache( void ) { + trap_R_RegisterShaderNoMip( TEAMMAIN_FRAME ); +} + + +/* +=============== +UI_TeamMainMenu +=============== +*/ +void UI_TeamMainMenu( void ) { + TeamMain_MenuInit(); + UI_PushMenu ( &s_teammain.menu ); +} diff --git a/code/q3_ui/ui_teamorders.c b/code/q3_ui/ui_teamorders.c new file mode 100755 index 0000000..3187402 --- /dev/null +++ b/code/q3_ui/ui_teamorders.c @@ -0,0 +1,449 @@ +/* +=========================================================================== +Copyright (C) 1999-2005 Id Software, Inc. + +This file is part of Quake III Arena source code. + +Quake III Arena source code is free software; you can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 2 of the License, +or (at your option) any later version. + +Quake III Arena source code is distributed in the hope that it will be +useful, but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Foobar; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ +// +/* +======================================================================= + +TEAM ORDERS MENU + +======================================================================= +*/ + + +#include "ui_local.h" + + +#define ART_FRAME "menu/art/addbotframe" +#define ART_BACK0 "menu/art/back_0" +#define ART_BACK1 "menu/art/back_1" + +#define ID_LIST_BOTS 10 +#define ID_LIST_CTF_ORDERS 11 +#define ID_LIST_TEAM_ORDERS 12 + + +typedef struct { + menuframework_s menu; + + menutext_s banner; + menubitmap_s frame; + + menulist_s list; + + menubitmap_s back; + + int gametype; + int numBots; + int selectedBot; + char *bots[9]; + char botNames[9][16]; +} teamOrdersMenuInfo_t; + +static teamOrdersMenuInfo_t teamOrdersMenuInfo; + +#define NUM_CTF_ORDERS 7 +static const char *ctfOrders[] = { + "I Am the Leader", + "Defend the Base", + "Follow Me", + "Get Enemy Flag", + "Camp Here", + "Report", + "I Relinquish Command", + NULL +}; +static const char *ctfMessages[] = { + "i am the leader", + "%s defend the base", + "%s follow me", + "%s get enemy flag", + "%s camp here", + "%s report", + "i stop being the leader", + NULL +}; + +#define NUM_TEAM_ORDERS 6 +static const char *teamOrders[] = { + "I Am the Leader", + "Follow Me", + "Roam", + "Camp Here", + "Report", + "I Relinquish Command", + NULL +}; +static const char *teamMessages[] = { + "i am the leader", + "%s follow me", + "%s roam", + "%s camp here", + "%s report", + "i stop being the leader", + NULL +}; + + +/* +=============== +UI_TeamOrdersMenu_BackEvent +=============== +*/ +static void UI_TeamOrdersMenu_BackEvent( void *ptr, int event ) { + if( event != QM_ACTIVATED ) { + return; + } + UI_PopMenu(); +} + + +/* +=============== +UI_TeamOrdersMenu_SetList +=============== +*/ +static void UI_TeamOrdersMenu_SetList( int id ) { + switch( id ) { + default: + case ID_LIST_BOTS: + teamOrdersMenuInfo.list.generic.id = id; + teamOrdersMenuInfo.list.numitems = teamOrdersMenuInfo.numBots; + teamOrdersMenuInfo.list.itemnames = (const char **)teamOrdersMenuInfo.bots; + break; + + case ID_LIST_CTF_ORDERS: + teamOrdersMenuInfo.list.generic.id = id; + teamOrdersMenuInfo.list.numitems = NUM_CTF_ORDERS; + teamOrdersMenuInfo.list.itemnames = ctfOrders; + break; + + case ID_LIST_TEAM_ORDERS: + teamOrdersMenuInfo.list.generic.id = id; + teamOrdersMenuInfo.list.numitems = NUM_TEAM_ORDERS; + teamOrdersMenuInfo.list.itemnames = teamOrders; + break; + } + + teamOrdersMenuInfo.list.generic.bottom = teamOrdersMenuInfo.list.generic.top + teamOrdersMenuInfo.list.numitems * PROP_HEIGHT; +} + + +/* +================= +UI_TeamOrdersMenu_Key +================= +*/ +sfxHandle_t UI_TeamOrdersMenu_Key( int key ) { + menulist_s *l; + int x; + int y; + int index; + + l = (menulist_s *)Menu_ItemAtCursor( &teamOrdersMenuInfo.menu ); + if( l != &teamOrdersMenuInfo.list ) { + return Menu_DefaultKey( &teamOrdersMenuInfo.menu, key ); + } + + switch( key ) { + case K_MOUSE1: + x = l->generic.left; + y = l->generic.top; + if( UI_CursorInRect( x, y, l->generic.right - x, l->generic.bottom - y ) ) { + index = (uis.cursory - y) / PROP_HEIGHT; + l->oldvalue = l->curvalue; + l->curvalue = index; + + if( l->generic.callback ) { + l->generic.callback( l, QM_ACTIVATED ); + return menu_move_sound; + } + } + return menu_null_sound; + + case K_KP_UPARROW: + case K_UPARROW: + l->oldvalue = l->curvalue; + + if( l->curvalue == 0 ) { + l->curvalue = l->numitems - 1; + } + else { + l->curvalue--; + } + return menu_move_sound; + + case K_KP_DOWNARROW: + case K_DOWNARROW: + l->oldvalue = l->curvalue; + + if( l->curvalue == l->numitems - 1 ) { + l->curvalue = 0;; + } + else { + l->curvalue++; + } + return menu_move_sound; + } + + return Menu_DefaultKey( &teamOrdersMenuInfo.menu, key ); +} + + +/* +================= +UI_TeamOrdersMenu_ListDraw +================= +*/ +static void UI_TeamOrdersMenu_ListDraw( void *self ) { + menulist_s *l; + int x; + int y; + int i; + float *color; + qboolean hasfocus; + int style; + + l = (menulist_s *)self; + + hasfocus = (l->generic.parent->cursor == l->generic.menuPosition); + + x = 320;//l->generic.x; + y = l->generic.y; + for( i = 0; i < l->numitems; i++ ) { + style = UI_LEFT|UI_SMALLFONT|UI_CENTER; + if( i == l->curvalue ) { + color = color_yellow; + if( hasfocus ) { + style |= UI_PULSE; + } + } + else { + color = color_orange; + } + + UI_DrawProportionalString( x, y, l->itemnames[i], style, color ); + y += PROP_HEIGHT; + } +} + + +/* +=============== +UI_TeamOrdersMenu_ListEvent +=============== +*/ +static void UI_TeamOrdersMenu_ListEvent( void *ptr, int event ) { + int id; + int selection; + char message[256]; + + if (event != QM_ACTIVATED) + return; + + id = ((menulist_s *)ptr)->generic.id; + selection = ((menulist_s *)ptr)->curvalue; + + if( id == ID_LIST_BOTS ) { + teamOrdersMenuInfo.selectedBot = selection; + if( teamOrdersMenuInfo.gametype == GT_CTF ) { + UI_TeamOrdersMenu_SetList( ID_LIST_CTF_ORDERS ); + } + else { + UI_TeamOrdersMenu_SetList( ID_LIST_TEAM_ORDERS ); + } + return; + } + + if( id == ID_LIST_CTF_ORDERS ) { + Com_sprintf( message, sizeof(message), ctfMessages[selection], teamOrdersMenuInfo.botNames[teamOrdersMenuInfo.selectedBot] ); + } + else { + Com_sprintf( message, sizeof(message), teamMessages[selection], teamOrdersMenuInfo.botNames[teamOrdersMenuInfo.selectedBot] ); + } + + trap_Cmd_ExecuteText( EXEC_APPEND, va( "say_team \"%s\"\n", message ) ); + UI_PopMenu(); +} + + +/* +=============== +UI_TeamOrdersMenu_BuildBotList +=============== +*/ +static void UI_TeamOrdersMenu_BuildBotList( void ) { + uiClientState_t cs; + int numPlayers; + int isBot; + int n; + char playerTeam; + char botTeam; + char info[MAX_INFO_STRING]; + + for( n = 0; n < 9; n++ ) { + teamOrdersMenuInfo.bots[n] = teamOrdersMenuInfo.botNames[n]; + } + + trap_GetClientState( &cs ); + + Q_strncpyz( teamOrdersMenuInfo.botNames[0], "Everyone", 16 ); + teamOrdersMenuInfo.numBots = 1; + + trap_GetConfigString( CS_SERVERINFO, info, sizeof(info) ); + numPlayers = atoi( Info_ValueForKey( info, "sv_maxclients" ) ); + teamOrdersMenuInfo.gametype = atoi( Info_ValueForKey( info, "g_gametype" ) ); + + for( n = 0; n < numPlayers && teamOrdersMenuInfo.numBots < 9; n++ ) { + trap_GetConfigString( CS_PLAYERS + n, info, MAX_INFO_STRING ); + + playerTeam = TEAM_SPECTATOR; // bk001204 = possible uninit use + + if( n == cs.clientNum ) { + playerTeam = *Info_ValueForKey( info, "t" ); + continue; + } + + isBot = atoi( Info_ValueForKey( info, "skill" ) ); + if( !isBot ) { + continue; + } + + botTeam = *Info_ValueForKey( info, "t" ); + if( botTeam != playerTeam ) { + continue; + } + + Q_strncpyz( teamOrdersMenuInfo.botNames[teamOrdersMenuInfo.numBots], Info_ValueForKey( info, "n" ), 16 ); + Q_CleanStr( teamOrdersMenuInfo.botNames[teamOrdersMenuInfo.numBots] ); + teamOrdersMenuInfo.numBots++; + } +} + + +/* +=============== +UI_TeamOrdersMenu_Init +=============== +*/ +static void UI_TeamOrdersMenu_Init( void ) { + UI_TeamOrdersMenu_Cache(); + + memset( &teamOrdersMenuInfo, 0, sizeof(teamOrdersMenuInfo) ); + teamOrdersMenuInfo.menu.fullscreen = qfalse; + teamOrdersMenuInfo.menu.key = UI_TeamOrdersMenu_Key; + + UI_TeamOrdersMenu_BuildBotList(); + + teamOrdersMenuInfo.banner.generic.type = MTYPE_BTEXT; + teamOrdersMenuInfo.banner.generic.x = 320; + teamOrdersMenuInfo.banner.generic.y = 16; + teamOrdersMenuInfo.banner.string = "TEAM ORDERS"; + teamOrdersMenuInfo.banner.color = color_white; + teamOrdersMenuInfo.banner.style = UI_CENTER; + + teamOrdersMenuInfo.frame.generic.type = MTYPE_BITMAP; + teamOrdersMenuInfo.frame.generic.flags = QMF_INACTIVE; + teamOrdersMenuInfo.frame.generic.name = ART_FRAME; + teamOrdersMenuInfo.frame.generic.x = 320-233; + teamOrdersMenuInfo.frame.generic.y = 240-166; + teamOrdersMenuInfo.frame.width = 466; + teamOrdersMenuInfo.frame.height = 332; + + teamOrdersMenuInfo.list.generic.type = MTYPE_SCROLLLIST; + teamOrdersMenuInfo.list.generic.flags = QMF_PULSEIFFOCUS; + teamOrdersMenuInfo.list.generic.ownerdraw = UI_TeamOrdersMenu_ListDraw; + teamOrdersMenuInfo.list.generic.callback = UI_TeamOrdersMenu_ListEvent; + teamOrdersMenuInfo.list.generic.x = 320-64; + teamOrdersMenuInfo.list.generic.y = 120; + + teamOrdersMenuInfo.back.generic.type = MTYPE_BITMAP; + teamOrdersMenuInfo.back.generic.name = ART_BACK0; + teamOrdersMenuInfo.back.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS; + teamOrdersMenuInfo.back.generic.callback = UI_TeamOrdersMenu_BackEvent; + teamOrdersMenuInfo.back.generic.x = 0; + teamOrdersMenuInfo.back.generic.y = 480-64; + teamOrdersMenuInfo.back.width = 128; + teamOrdersMenuInfo.back.height = 64; + teamOrdersMenuInfo.back.focuspic = ART_BACK1; + + Menu_AddItem( &teamOrdersMenuInfo.menu, &teamOrdersMenuInfo.banner ); + Menu_AddItem( &teamOrdersMenuInfo.menu, &teamOrdersMenuInfo.frame ); + Menu_AddItem( &teamOrdersMenuInfo.menu, &teamOrdersMenuInfo.list ); + Menu_AddItem( &teamOrdersMenuInfo.menu, &teamOrdersMenuInfo.back ); + + teamOrdersMenuInfo.list.generic.left = 220; + teamOrdersMenuInfo.list.generic.top = teamOrdersMenuInfo.list.generic.y; + teamOrdersMenuInfo.list.generic.right = 420; + UI_TeamOrdersMenu_SetList( ID_LIST_BOTS ); +} + + +/* +================= +UI_TeamOrdersMenu_Cache +================= +*/ +void UI_TeamOrdersMenu_Cache( void ) { + trap_R_RegisterShaderNoMip( ART_FRAME ); + trap_R_RegisterShaderNoMip( ART_BACK0 ); + trap_R_RegisterShaderNoMip( ART_BACK1 ); +} + + +/* +=============== +UI_TeamOrdersMenu +=============== +*/ +void UI_TeamOrdersMenu( void ) { + UI_TeamOrdersMenu_Init(); + UI_PushMenu( &teamOrdersMenuInfo.menu ); +} + + +/* +=============== +UI_TeamOrdersMenu_f +=============== +*/ +void UI_TeamOrdersMenu_f( void ) { + uiClientState_t cs; + char info[MAX_INFO_STRING]; + int team; + + // make sure it's a team game + trap_GetConfigString( CS_SERVERINFO, info, sizeof(info) ); + teamOrdersMenuInfo.gametype = atoi( Info_ValueForKey( info, "g_gametype" ) ); + if( teamOrdersMenuInfo.gametype < GT_TEAM ) { + return; + } + + // not available to spectators + trap_GetClientState( &cs ); + trap_GetConfigString( CS_PLAYERS + cs.clientNum, info, MAX_INFO_STRING ); + team = atoi( Info_ValueForKey( info, "t" ) ); + if( team == TEAM_SPECTATOR ) { + return; + } + + UI_TeamOrdersMenu(); +} diff --git a/code/q3_ui/ui_video.c b/code/q3_ui/ui_video.c new file mode 100755 index 0000000..8784245 --- /dev/null +++ b/code/q3_ui/ui_video.c @@ -0,0 +1,1070 @@ +/* +=========================================================================== +Copyright (C) 1999-2005 Id Software, Inc. + +This file is part of Quake III Arena source code. + +Quake III Arena source code is free software; you can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 2 of the License, +or (at your option) any later version. + +Quake III Arena source code is distributed in the hope that it will be +useful, but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Foobar; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ +// +#include "ui_local.h" + +void GraphicsOptions_MenuInit( void ); + +/* +======================================================================= + +DRIVER INFORMATION MENU + +======================================================================= +*/ + + +#define DRIVERINFO_FRAMEL "menu/art/frame2_l" +#define DRIVERINFO_FRAMER "menu/art/frame1_r" +#define DRIVERINFO_BACK0 "menu/art/back_0" +#define DRIVERINFO_BACK1 "menu/art/back_1" + +static char* driverinfo_artlist[] = +{ + DRIVERINFO_FRAMEL, + DRIVERINFO_FRAMER, + DRIVERINFO_BACK0, + DRIVERINFO_BACK1, + NULL, +}; + +#define ID_DRIVERINFOBACK 100 + +typedef struct +{ + menuframework_s menu; + menutext_s banner; + menubitmap_s back; + menubitmap_s framel; + menubitmap_s framer; + char stringbuff[1024]; + char* strings[64]; + int numstrings; +} driverinfo_t; + +static driverinfo_t s_driverinfo; + +/* +================= +DriverInfo_Event +================= +*/ +static void DriverInfo_Event( void* ptr, int event ) +{ + if (event != QM_ACTIVATED) + return; + + switch (((menucommon_s*)ptr)->id) + { + case ID_DRIVERINFOBACK: + UI_PopMenu(); + break; + } +} + +/* +================= +DriverInfo_MenuDraw +================= +*/ +static void DriverInfo_MenuDraw( void ) +{ + int i; + int y; + + Menu_Draw( &s_driverinfo.menu ); + + UI_DrawString( 320, 80, "VENDOR", UI_CENTER|UI_SMALLFONT, color_red ); + UI_DrawString( 320, 152, "PIXELFORMAT", UI_CENTER|UI_SMALLFONT, color_red ); + UI_DrawString( 320, 192, "EXTENSIONS", UI_CENTER|UI_SMALLFONT, color_red ); + + UI_DrawString( 320, 80+16, uis.glconfig.vendor_string, UI_CENTER|UI_SMALLFONT, text_color_normal ); + UI_DrawString( 320, 96+16, uis.glconfig.version_string, UI_CENTER|UI_SMALLFONT, text_color_normal ); + UI_DrawString( 320, 112+16, uis.glconfig.renderer_string, UI_CENTER|UI_SMALLFONT, text_color_normal ); + UI_DrawString( 320, 152+16, va ("color(%d-bits) Z(%d-bits) stencil(%d-bits)", uis.glconfig.colorBits, uis.glconfig.depthBits, uis.glconfig.stencilBits), UI_CENTER|UI_SMALLFONT, text_color_normal ); + + // double column + y = 192+16; + for (i=0; i 32) { + s_driverinfo.strings[i][len-1] = '>'; + s_driverinfo.strings[i][len] = '\0'; + } + } + + Menu_AddItem( &s_driverinfo.menu, &s_driverinfo.banner ); + Menu_AddItem( &s_driverinfo.menu, &s_driverinfo.framel ); + Menu_AddItem( &s_driverinfo.menu, &s_driverinfo.framer ); + Menu_AddItem( &s_driverinfo.menu, &s_driverinfo.back ); + + UI_PushMenu( &s_driverinfo.menu ); +} + +/* +======================================================================= + +GRAPHICS OPTIONS MENU + +======================================================================= +*/ + +#define GRAPHICSOPTIONS_FRAMEL "menu/art/frame2_l" +#define GRAPHICSOPTIONS_FRAMER "menu/art/frame1_r" +#define GRAPHICSOPTIONS_BACK0 "menu/art/back_0" +#define GRAPHICSOPTIONS_BACK1 "menu/art/back_1" +#define GRAPHICSOPTIONS_ACCEPT0 "menu/art/accept_0" +#define GRAPHICSOPTIONS_ACCEPT1 "menu/art/accept_1" + +static const char *s_drivers[] = +{ + OPENGL_DRIVER_NAME, + _3DFX_DRIVER_NAME, + 0 +}; + +#define ID_BACK2 101 +#define ID_FULLSCREEN 102 +#define ID_LIST 103 +#define ID_MODE 104 +#define ID_DRIVERINFO 105 +#define ID_GRAPHICS 106 +#define ID_DISPLAY 107 +#define ID_SOUND 108 +#define ID_NETWORK 109 + +typedef struct { + menuframework_s menu; + + menutext_s banner; + menubitmap_s framel; + menubitmap_s framer; + + menutext_s graphics; + menutext_s display; + menutext_s sound; + menutext_s network; + + menulist_s list; + menulist_s mode; + menulist_s driver; + menuslider_s tq; + menulist_s fs; + menulist_s lighting; + menulist_s allow_extensions; + menulist_s texturebits; + menulist_s colordepth; + menulist_s geometry; + menulist_s filter; + menutext_s driverinfo; + + menubitmap_s apply; + menubitmap_s back; +} graphicsoptions_t; + +typedef struct +{ + int mode; + qboolean fullscreen; + int tq; + int lighting; + int colordepth; + int texturebits; + int geometry; + int filter; + int driver; + qboolean extensions; +} InitialVideoOptions_s; + +static InitialVideoOptions_s s_ivo; +static graphicsoptions_t s_graphicsoptions; + +static InitialVideoOptions_s s_ivo_templates[] = +{ + { + 4, qtrue, 2, 0, 2, 2, 1, 1, 0, qtrue // JDC: this was tq 3 + }, + { + 3, qtrue, 2, 0, 0, 0, 1, 0, 0, qtrue + }, + { + 2, qtrue, 1, 0, 1, 0, 0, 0, 0, qtrue + }, + { + 2, qtrue, 1, 1, 1, 0, 0, 0, 0, qtrue + }, + { + 3, qtrue, 1, 0, 0, 0, 1, 0, 0, qtrue + } +}; + +#define NUM_IVO_TEMPLATES ( sizeof( s_ivo_templates ) / sizeof( s_ivo_templates[0] ) ) + +/* +================= +GraphicsOptions_GetInitialVideo +================= +*/ +static void GraphicsOptions_GetInitialVideo( void ) +{ + s_ivo.colordepth = s_graphicsoptions.colordepth.curvalue; + s_ivo.driver = s_graphicsoptions.driver.curvalue; + s_ivo.mode = s_graphicsoptions.mode.curvalue; + s_ivo.fullscreen = s_graphicsoptions.fs.curvalue; + s_ivo.extensions = s_graphicsoptions.allow_extensions.curvalue; + s_ivo.tq = s_graphicsoptions.tq.curvalue; + s_ivo.lighting = s_graphicsoptions.lighting.curvalue; + s_ivo.geometry = s_graphicsoptions.geometry.curvalue; + s_ivo.filter = s_graphicsoptions.filter.curvalue; + s_ivo.texturebits = s_graphicsoptions.texturebits.curvalue; +} + +/* +================= +GraphicsOptions_CheckConfig +================= +*/ +static void GraphicsOptions_CheckConfig( void ) +{ + int i; + + for ( i = 0; i < NUM_IVO_TEMPLATES; i++ ) + { + if ( s_ivo_templates[i].colordepth != s_graphicsoptions.colordepth.curvalue ) + continue; + if ( s_ivo_templates[i].driver != s_graphicsoptions.driver.curvalue ) + continue; + if ( s_ivo_templates[i].mode != s_graphicsoptions.mode.curvalue ) + continue; + if ( s_ivo_templates[i].fullscreen != s_graphicsoptions.fs.curvalue ) + continue; + if ( s_ivo_templates[i].tq != s_graphicsoptions.tq.curvalue ) + continue; + if ( s_ivo_templates[i].lighting != s_graphicsoptions.lighting.curvalue ) + continue; + if ( s_ivo_templates[i].geometry != s_graphicsoptions.geometry.curvalue ) + continue; + if ( s_ivo_templates[i].filter != s_graphicsoptions.filter.curvalue ) + continue; +// if ( s_ivo_templates[i].texturebits != s_graphicsoptions.texturebits.curvalue ) +// continue; + s_graphicsoptions.list.curvalue = i; + return; + } + s_graphicsoptions.list.curvalue = 4; +} + +/* +================= +GraphicsOptions_UpdateMenuItems +================= +*/ +static void GraphicsOptions_UpdateMenuItems( void ) +{ + if ( s_graphicsoptions.driver.curvalue == 1 ) + { + s_graphicsoptions.fs.curvalue = 1; + s_graphicsoptions.fs.generic.flags |= QMF_GRAYED; + s_graphicsoptions.colordepth.curvalue = 1; + } + else + { + s_graphicsoptions.fs.generic.flags &= ~QMF_GRAYED; + } + + if ( s_graphicsoptions.fs.curvalue == 0 || s_graphicsoptions.driver.curvalue == 1 ) + { + s_graphicsoptions.colordepth.curvalue = 0; + s_graphicsoptions.colordepth.generic.flags |= QMF_GRAYED; + } + else + { + s_graphicsoptions.colordepth.generic.flags &= ~QMF_GRAYED; + } + + if ( s_graphicsoptions.allow_extensions.curvalue == 0 ) + { + if ( s_graphicsoptions.texturebits.curvalue == 0 ) + { + s_graphicsoptions.texturebits.curvalue = 1; + } + } + + s_graphicsoptions.apply.generic.flags |= QMF_HIDDEN|QMF_INACTIVE; + + if ( s_ivo.mode != s_graphicsoptions.mode.curvalue ) + { + s_graphicsoptions.apply.generic.flags &= ~(QMF_HIDDEN|QMF_INACTIVE); + } + if ( s_ivo.fullscreen != s_graphicsoptions.fs.curvalue ) + { + s_graphicsoptions.apply.generic.flags &= ~(QMF_HIDDEN|QMF_INACTIVE); + } + if ( s_ivo.extensions != s_graphicsoptions.allow_extensions.curvalue ) + { + s_graphicsoptions.apply.generic.flags &= ~(QMF_HIDDEN|QMF_INACTIVE); + } + if ( s_ivo.tq != s_graphicsoptions.tq.curvalue ) + { + s_graphicsoptions.apply.generic.flags &= ~(QMF_HIDDEN|QMF_INACTIVE); + } + if ( s_ivo.lighting != s_graphicsoptions.lighting.curvalue ) + { + s_graphicsoptions.apply.generic.flags &= ~(QMF_HIDDEN|QMF_INACTIVE); + } + if ( s_ivo.colordepth != s_graphicsoptions.colordepth.curvalue ) + { + s_graphicsoptions.apply.generic.flags &= ~(QMF_HIDDEN|QMF_INACTIVE); + } + if ( s_ivo.driver != s_graphicsoptions.driver.curvalue ) + { + s_graphicsoptions.apply.generic.flags &= ~(QMF_HIDDEN|QMF_INACTIVE); + } + if ( s_ivo.texturebits != s_graphicsoptions.texturebits.curvalue ) + { + s_graphicsoptions.apply.generic.flags &= ~(QMF_HIDDEN|QMF_INACTIVE); + } + if ( s_ivo.geometry != s_graphicsoptions.geometry.curvalue ) + { + s_graphicsoptions.apply.generic.flags &= ~(QMF_HIDDEN|QMF_INACTIVE); + } + if ( s_ivo.filter != s_graphicsoptions.filter.curvalue ) + { + s_graphicsoptions.apply.generic.flags &= ~(QMF_HIDDEN|QMF_INACTIVE); + } + + GraphicsOptions_CheckConfig(); +} + +/* +================= +GraphicsOptions_ApplyChanges +================= +*/ +static void GraphicsOptions_ApplyChanges( void *unused, int notification ) +{ + if (notification != QM_ACTIVATED) + return; + + switch ( s_graphicsoptions.texturebits.curvalue ) + { + case 0: + trap_Cvar_SetValue( "r_texturebits", 0 ); + break; + case 1: + trap_Cvar_SetValue( "r_texturebits", 16 ); + break; + case 2: + trap_Cvar_SetValue( "r_texturebits", 32 ); + break; + } + trap_Cvar_SetValue( "r_picmip", 3 - s_graphicsoptions.tq.curvalue ); + trap_Cvar_SetValue( "r_allowExtensions", s_graphicsoptions.allow_extensions.curvalue ); + trap_Cvar_SetValue( "r_mode", s_graphicsoptions.mode.curvalue ); + trap_Cvar_SetValue( "r_fullscreen", s_graphicsoptions.fs.curvalue ); + trap_Cvar_Set( "r_glDriver", ( char * ) s_drivers[s_graphicsoptions.driver.curvalue] ); + switch ( s_graphicsoptions.colordepth.curvalue ) + { + case 0: + trap_Cvar_SetValue( "r_colorbits", 0 ); + trap_Cvar_SetValue( "r_depthbits", 0 ); + trap_Cvar_SetValue( "r_stencilbits", 0 ); + break; + case 1: + trap_Cvar_SetValue( "r_colorbits", 16 ); + trap_Cvar_SetValue( "r_depthbits", 16 ); + trap_Cvar_SetValue( "r_stencilbits", 0 ); + break; + case 2: + trap_Cvar_SetValue( "r_colorbits", 32 ); + trap_Cvar_SetValue( "r_depthbits", 24 ); + break; + } + trap_Cvar_SetValue( "r_vertexLight", s_graphicsoptions.lighting.curvalue ); + + if ( s_graphicsoptions.geometry.curvalue == 2 ) + { + trap_Cvar_SetValue( "r_lodBias", 0 ); + trap_Cvar_SetValue( "r_subdivisions", 4 ); + } + else if ( s_graphicsoptions.geometry.curvalue == 1 ) + { + trap_Cvar_SetValue( "r_lodBias", 1 ); + trap_Cvar_SetValue( "r_subdivisions", 12 ); + } + else + { + trap_Cvar_SetValue( "r_lodBias", 1 ); + trap_Cvar_SetValue( "r_subdivisions", 20 ); + } + + if ( s_graphicsoptions.filter.curvalue ) + { + trap_Cvar_Set( "r_textureMode", "GL_LINEAR_MIPMAP_LINEAR" ); + } + else + { + trap_Cvar_Set( "r_textureMode", "GL_LINEAR_MIPMAP_NEAREST" ); + } + + trap_Cmd_ExecuteText( EXEC_APPEND, "vid_restart\n" ); +} + +/* +================= +GraphicsOptions_Event +================= +*/ +static void GraphicsOptions_Event( void* ptr, int event ) { + InitialVideoOptions_s *ivo; + + if( event != QM_ACTIVATED ) { + return; + } + + switch( ((menucommon_s*)ptr)->id ) { + case ID_MODE: + // clamp 3dfx video modes + if ( s_graphicsoptions.driver.curvalue == 1 ) + { + if ( s_graphicsoptions.mode.curvalue < 2 ) + s_graphicsoptions.mode.curvalue = 2; + else if ( s_graphicsoptions.mode.curvalue > 6 ) + s_graphicsoptions.mode.curvalue = 6; + } + break; + + case ID_LIST: + ivo = &s_ivo_templates[s_graphicsoptions.list.curvalue]; + + s_graphicsoptions.mode.curvalue = ivo->mode; + s_graphicsoptions.tq.curvalue = ivo->tq; + s_graphicsoptions.lighting.curvalue = ivo->lighting; + s_graphicsoptions.colordepth.curvalue = ivo->colordepth; + s_graphicsoptions.texturebits.curvalue = ivo->texturebits; + s_graphicsoptions.geometry.curvalue = ivo->geometry; + s_graphicsoptions.filter.curvalue = ivo->filter; + s_graphicsoptions.fs.curvalue = ivo->fullscreen; + break; + + case ID_DRIVERINFO: + UI_DriverInfo_Menu(); + break; + + case ID_BACK2: + UI_PopMenu(); + break; + + case ID_GRAPHICS: + break; + + case ID_DISPLAY: + UI_PopMenu(); + UI_DisplayOptionsMenu(); + break; + + case ID_SOUND: + UI_PopMenu(); + UI_SoundOptionsMenu(); + break; + + case ID_NETWORK: + UI_PopMenu(); + UI_NetworkOptionsMenu(); + break; + } +} + + +/* +================ +GraphicsOptions_TQEvent +================ +*/ +static void GraphicsOptions_TQEvent( void *ptr, int event ) { + if( event != QM_ACTIVATED ) { + return; + } + s_graphicsoptions.tq.curvalue = (int)(s_graphicsoptions.tq.curvalue + 0.5); +} + + +/* +================ +GraphicsOptions_MenuDraw +================ +*/ +void GraphicsOptions_MenuDraw (void) +{ +//APSFIX - rework this + GraphicsOptions_UpdateMenuItems(); + + Menu_Draw( &s_graphicsoptions.menu ); +} + +/* +================= +GraphicsOptions_SetMenuItems +================= +*/ +static void GraphicsOptions_SetMenuItems( void ) +{ + s_graphicsoptions.mode.curvalue = trap_Cvar_VariableValue( "r_mode" ); + if ( s_graphicsoptions.mode.curvalue < 0 ) + { + s_graphicsoptions.mode.curvalue = 3; + } + s_graphicsoptions.fs.curvalue = trap_Cvar_VariableValue("r_fullscreen"); + s_graphicsoptions.allow_extensions.curvalue = trap_Cvar_VariableValue("r_allowExtensions"); + s_graphicsoptions.tq.curvalue = 3-trap_Cvar_VariableValue( "r_picmip"); + if ( s_graphicsoptions.tq.curvalue < 0 ) + { + s_graphicsoptions.tq.curvalue = 0; + } + else if ( s_graphicsoptions.tq.curvalue > 3 ) + { + s_graphicsoptions.tq.curvalue = 3; + } + + s_graphicsoptions.lighting.curvalue = trap_Cvar_VariableValue( "r_vertexLight" ) != 0; + switch ( ( int ) trap_Cvar_VariableValue( "r_texturebits" ) ) + { + default: + case 0: + s_graphicsoptions.texturebits.curvalue = 0; + break; + case 16: + s_graphicsoptions.texturebits.curvalue = 1; + break; + case 32: + s_graphicsoptions.texturebits.curvalue = 2; + break; + } + + if ( !Q_stricmp( UI_Cvar_VariableString( "r_textureMode" ), "GL_LINEAR_MIPMAP_NEAREST" ) ) + { + s_graphicsoptions.filter.curvalue = 0; + } + else + { + s_graphicsoptions.filter.curvalue = 1; + } + + if ( trap_Cvar_VariableValue( "r_lodBias" ) > 0 ) + { + if ( trap_Cvar_VariableValue( "r_subdivisions" ) >= 20 ) + { + s_graphicsoptions.geometry.curvalue = 0; + } + else + { + s_graphicsoptions.geometry.curvalue = 1; + } + } + else + { + s_graphicsoptions.geometry.curvalue = 2; + } + + switch ( ( int ) trap_Cvar_VariableValue( "r_colorbits" ) ) + { + default: + case 0: + s_graphicsoptions.colordepth.curvalue = 0; + break; + case 16: + s_graphicsoptions.colordepth.curvalue = 1; + break; + case 32: + s_graphicsoptions.colordepth.curvalue = 2; + break; + } + + if ( s_graphicsoptions.fs.curvalue == 0 ) + { + s_graphicsoptions.colordepth.curvalue = 0; + } + if ( s_graphicsoptions.driver.curvalue == 1 ) + { + s_graphicsoptions.colordepth.curvalue = 1; + } +} + +/* +================ +GraphicsOptions_MenuInit +================ +*/ +void GraphicsOptions_MenuInit( void ) +{ + static const char *s_driver_names[] = + { + "Default", + "Voodoo", + 0 + }; + + static const char *tq_names[] = + { + "Default", + "16 bit", + "32 bit", + 0 + }; + + static const char *s_graphics_options_names[] = + { + "High Quality", + "Normal", + "Fast", + "Fastest", + "Custom", + 0 + }; + + static const char *lighting_names[] = + { + "Lightmap", + "Vertex", + 0 + }; + + static const char *colordepth_names[] = + { + "Default", + "16 bit", + "32 bit", + 0 + }; + + static const char *resolutions[] = + { + "320x240", + "400x300", + "512x384", + "640x480", + "800x600", + "960x720", + "1024x768", + "1152x864", + "1280x1024", + "1600x1200", + "2048x1536", + "856x480 wide screen", + 0 + }; + static const char *filter_names[] = + { + "Bilinear", + "Trilinear", + 0 + }; + static const char *quality_names[] = + { + "Low", + "Medium", + "High", + 0 + }; + static const char *enabled_names[] = + { + "Off", + "On", + 0 + }; + + int y; + + // zero set all our globals + memset( &s_graphicsoptions, 0 ,sizeof(graphicsoptions_t) ); + + GraphicsOptions_Cache(); + + s_graphicsoptions.menu.wrapAround = qtrue; + s_graphicsoptions.menu.fullscreen = qtrue; + s_graphicsoptions.menu.draw = GraphicsOptions_MenuDraw; + + s_graphicsoptions.banner.generic.type = MTYPE_BTEXT; + s_graphicsoptions.banner.generic.x = 320; + s_graphicsoptions.banner.generic.y = 16; + s_graphicsoptions.banner.string = "SYSTEM SETUP"; + s_graphicsoptions.banner.color = color_white; + s_graphicsoptions.banner.style = UI_CENTER; + + s_graphicsoptions.framel.generic.type = MTYPE_BITMAP; + s_graphicsoptions.framel.generic.name = GRAPHICSOPTIONS_FRAMEL; + s_graphicsoptions.framel.generic.flags = QMF_INACTIVE; + s_graphicsoptions.framel.generic.x = 0; + s_graphicsoptions.framel.generic.y = 78; + s_graphicsoptions.framel.width = 256; + s_graphicsoptions.framel.height = 329; + + s_graphicsoptions.framer.generic.type = MTYPE_BITMAP; + s_graphicsoptions.framer.generic.name = GRAPHICSOPTIONS_FRAMER; + s_graphicsoptions.framer.generic.flags = QMF_INACTIVE; + s_graphicsoptions.framer.generic.x = 376; + s_graphicsoptions.framer.generic.y = 76; + s_graphicsoptions.framer.width = 256; + s_graphicsoptions.framer.height = 334; + + s_graphicsoptions.graphics.generic.type = MTYPE_PTEXT; + s_graphicsoptions.graphics.generic.flags = QMF_RIGHT_JUSTIFY; + s_graphicsoptions.graphics.generic.id = ID_GRAPHICS; + s_graphicsoptions.graphics.generic.callback = GraphicsOptions_Event; + s_graphicsoptions.graphics.generic.x = 216; + s_graphicsoptions.graphics.generic.y = 240 - 2 * PROP_HEIGHT; + s_graphicsoptions.graphics.string = "GRAPHICS"; + s_graphicsoptions.graphics.style = UI_RIGHT; + s_graphicsoptions.graphics.color = color_red; + + s_graphicsoptions.display.generic.type = MTYPE_PTEXT; + s_graphicsoptions.display.generic.flags = QMF_RIGHT_JUSTIFY|QMF_PULSEIFFOCUS; + s_graphicsoptions.display.generic.id = ID_DISPLAY; + s_graphicsoptions.display.generic.callback = GraphicsOptions_Event; + s_graphicsoptions.display.generic.x = 216; + s_graphicsoptions.display.generic.y = 240 - PROP_HEIGHT; + s_graphicsoptions.display.string = "DISPLAY"; + s_graphicsoptions.display.style = UI_RIGHT; + s_graphicsoptions.display.color = color_red; + + s_graphicsoptions.sound.generic.type = MTYPE_PTEXT; + s_graphicsoptions.sound.generic.flags = QMF_RIGHT_JUSTIFY|QMF_PULSEIFFOCUS; + s_graphicsoptions.sound.generic.id = ID_SOUND; + s_graphicsoptions.sound.generic.callback = GraphicsOptions_Event; + s_graphicsoptions.sound.generic.x = 216; + s_graphicsoptions.sound.generic.y = 240; + s_graphicsoptions.sound.string = "SOUND"; + s_graphicsoptions.sound.style = UI_RIGHT; + s_graphicsoptions.sound.color = color_red; + + s_graphicsoptions.network.generic.type = MTYPE_PTEXT; + s_graphicsoptions.network.generic.flags = QMF_RIGHT_JUSTIFY|QMF_PULSEIFFOCUS; + s_graphicsoptions.network.generic.id = ID_NETWORK; + s_graphicsoptions.network.generic.callback = GraphicsOptions_Event; + s_graphicsoptions.network.generic.x = 216; + s_graphicsoptions.network.generic.y = 240 + PROP_HEIGHT; + s_graphicsoptions.network.string = "NETWORK"; + s_graphicsoptions.network.style = UI_RIGHT; + s_graphicsoptions.network.color = color_red; + + y = 240 - 6 * (BIGCHAR_HEIGHT + 2); + s_graphicsoptions.list.generic.type = MTYPE_SPINCONTROL; + s_graphicsoptions.list.generic.name = "Graphics Settings:"; + s_graphicsoptions.list.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT; + s_graphicsoptions.list.generic.x = 400; + s_graphicsoptions.list.generic.y = y; + s_graphicsoptions.list.generic.callback = GraphicsOptions_Event; + s_graphicsoptions.list.generic.id = ID_LIST; + s_graphicsoptions.list.itemnames = s_graphics_options_names; + y += 2 * ( BIGCHAR_HEIGHT + 2 ); + + s_graphicsoptions.driver.generic.type = MTYPE_SPINCONTROL; + s_graphicsoptions.driver.generic.name = "GL Driver:"; + s_graphicsoptions.driver.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT; + s_graphicsoptions.driver.generic.x = 400; + s_graphicsoptions.driver.generic.y = y; + s_graphicsoptions.driver.itemnames = s_driver_names; + s_graphicsoptions.driver.curvalue = (uis.glconfig.driverType == GLDRV_VOODOO); + y += BIGCHAR_HEIGHT+2; + + // references/modifies "r_allowExtensions" + s_graphicsoptions.allow_extensions.generic.type = MTYPE_SPINCONTROL; + s_graphicsoptions.allow_extensions.generic.name = "GL Extensions:"; + s_graphicsoptions.allow_extensions.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT; + s_graphicsoptions.allow_extensions.generic.x = 400; + s_graphicsoptions.allow_extensions.generic.y = y; + s_graphicsoptions.allow_extensions.itemnames = enabled_names; + y += BIGCHAR_HEIGHT+2; + + // references/modifies "r_mode" + s_graphicsoptions.mode.generic.type = MTYPE_SPINCONTROL; + s_graphicsoptions.mode.generic.name = "Video Mode:"; + s_graphicsoptions.mode.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT; + s_graphicsoptions.mode.generic.x = 400; + s_graphicsoptions.mode.generic.y = y; + s_graphicsoptions.mode.itemnames = resolutions; + s_graphicsoptions.mode.generic.callback = GraphicsOptions_Event; + s_graphicsoptions.mode.generic.id = ID_MODE; + y += BIGCHAR_HEIGHT+2; + + // references "r_colorbits" + s_graphicsoptions.colordepth.generic.type = MTYPE_SPINCONTROL; + s_graphicsoptions.colordepth.generic.name = "Color Depth:"; + s_graphicsoptions.colordepth.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT; + s_graphicsoptions.colordepth.generic.x = 400; + s_graphicsoptions.colordepth.generic.y = y; + s_graphicsoptions.colordepth.itemnames = colordepth_names; + y += BIGCHAR_HEIGHT+2; + + // references/modifies "r_fullscreen" + s_graphicsoptions.fs.generic.type = MTYPE_SPINCONTROL; + s_graphicsoptions.fs.generic.name = "Fullscreen:"; + s_graphicsoptions.fs.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT; + s_graphicsoptions.fs.generic.x = 400; + s_graphicsoptions.fs.generic.y = y; + s_graphicsoptions.fs.itemnames = enabled_names; + y += BIGCHAR_HEIGHT+2; + + // references/modifies "r_vertexLight" + s_graphicsoptions.lighting.generic.type = MTYPE_SPINCONTROL; + s_graphicsoptions.lighting.generic.name = "Lighting:"; + s_graphicsoptions.lighting.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT; + s_graphicsoptions.lighting.generic.x = 400; + s_graphicsoptions.lighting.generic.y = y; + s_graphicsoptions.lighting.itemnames = lighting_names; + y += BIGCHAR_HEIGHT+2; + + // references/modifies "r_lodBias" & "subdivisions" + s_graphicsoptions.geometry.generic.type = MTYPE_SPINCONTROL; + s_graphicsoptions.geometry.generic.name = "Geometric Detail:"; + s_graphicsoptions.geometry.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT; + s_graphicsoptions.geometry.generic.x = 400; + s_graphicsoptions.geometry.generic.y = y; + s_graphicsoptions.geometry.itemnames = quality_names; + y += BIGCHAR_HEIGHT+2; + + // references/modifies "r_picmip" + s_graphicsoptions.tq.generic.type = MTYPE_SLIDER; + s_graphicsoptions.tq.generic.name = "Texture Detail:"; + s_graphicsoptions.tq.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT; + s_graphicsoptions.tq.generic.x = 400; + s_graphicsoptions.tq.generic.y = y; + s_graphicsoptions.tq.minvalue = 0; + s_graphicsoptions.tq.maxvalue = 3; + s_graphicsoptions.tq.generic.callback = GraphicsOptions_TQEvent; + y += BIGCHAR_HEIGHT+2; + + // references/modifies "r_textureBits" + s_graphicsoptions.texturebits.generic.type = MTYPE_SPINCONTROL; + s_graphicsoptions.texturebits.generic.name = "Texture Quality:"; + s_graphicsoptions.texturebits.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT; + s_graphicsoptions.texturebits.generic.x = 400; + s_graphicsoptions.texturebits.generic.y = y; + s_graphicsoptions.texturebits.itemnames = tq_names; + y += BIGCHAR_HEIGHT+2; + + // references/modifies "r_textureMode" + s_graphicsoptions.filter.generic.type = MTYPE_SPINCONTROL; + s_graphicsoptions.filter.generic.name = "Texture Filter:"; + s_graphicsoptions.filter.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT; + s_graphicsoptions.filter.generic.x = 400; + s_graphicsoptions.filter.generic.y = y; + s_graphicsoptions.filter.itemnames = filter_names; + y += 2*BIGCHAR_HEIGHT; + + s_graphicsoptions.driverinfo.generic.type = MTYPE_PTEXT; + s_graphicsoptions.driverinfo.generic.flags = QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS; + s_graphicsoptions.driverinfo.generic.callback = GraphicsOptions_Event; + s_graphicsoptions.driverinfo.generic.id = ID_DRIVERINFO; + s_graphicsoptions.driverinfo.generic.x = 320; + s_graphicsoptions.driverinfo.generic.y = y; + s_graphicsoptions.driverinfo.string = "Driver Info"; + s_graphicsoptions.driverinfo.style = UI_CENTER|UI_SMALLFONT; + s_graphicsoptions.driverinfo.color = color_red; + y += BIGCHAR_HEIGHT+2; + + s_graphicsoptions.back.generic.type = MTYPE_BITMAP; + s_graphicsoptions.back.generic.name = GRAPHICSOPTIONS_BACK0; + s_graphicsoptions.back.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS; + s_graphicsoptions.back.generic.callback = GraphicsOptions_Event; + s_graphicsoptions.back.generic.id = ID_BACK2; + s_graphicsoptions.back.generic.x = 0; + s_graphicsoptions.back.generic.y = 480-64; + s_graphicsoptions.back.width = 128; + s_graphicsoptions.back.height = 64; + s_graphicsoptions.back.focuspic = GRAPHICSOPTIONS_BACK1; + + s_graphicsoptions.apply.generic.type = MTYPE_BITMAP; + s_graphicsoptions.apply.generic.name = GRAPHICSOPTIONS_ACCEPT0; + s_graphicsoptions.apply.generic.flags = QMF_RIGHT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_HIDDEN|QMF_INACTIVE; + s_graphicsoptions.apply.generic.callback = GraphicsOptions_ApplyChanges; + s_graphicsoptions.apply.generic.x = 640; + s_graphicsoptions.apply.generic.y = 480-64; + s_graphicsoptions.apply.width = 128; + s_graphicsoptions.apply.height = 64; + s_graphicsoptions.apply.focuspic = GRAPHICSOPTIONS_ACCEPT1; + + Menu_AddItem( &s_graphicsoptions.menu, ( void * ) &s_graphicsoptions.banner ); + Menu_AddItem( &s_graphicsoptions.menu, ( void * ) &s_graphicsoptions.framel ); + Menu_AddItem( &s_graphicsoptions.menu, ( void * ) &s_graphicsoptions.framer ); + + Menu_AddItem( &s_graphicsoptions.menu, ( void * ) &s_graphicsoptions.graphics ); + Menu_AddItem( &s_graphicsoptions.menu, ( void * ) &s_graphicsoptions.display ); + Menu_AddItem( &s_graphicsoptions.menu, ( void * ) &s_graphicsoptions.sound ); + Menu_AddItem( &s_graphicsoptions.menu, ( void * ) &s_graphicsoptions.network ); + + Menu_AddItem( &s_graphicsoptions.menu, ( void * ) &s_graphicsoptions.list ); + Menu_AddItem( &s_graphicsoptions.menu, ( void * ) &s_graphicsoptions.driver ); + Menu_AddItem( &s_graphicsoptions.menu, ( void * ) &s_graphicsoptions.allow_extensions ); + Menu_AddItem( &s_graphicsoptions.menu, ( void * ) &s_graphicsoptions.mode ); + Menu_AddItem( &s_graphicsoptions.menu, ( void * ) &s_graphicsoptions.colordepth ); + Menu_AddItem( &s_graphicsoptions.menu, ( void * ) &s_graphicsoptions.fs ); + Menu_AddItem( &s_graphicsoptions.menu, ( void * ) &s_graphicsoptions.lighting ); + Menu_AddItem( &s_graphicsoptions.menu, ( void * ) &s_graphicsoptions.geometry ); + Menu_AddItem( &s_graphicsoptions.menu, ( void * ) &s_graphicsoptions.tq ); + Menu_AddItem( &s_graphicsoptions.menu, ( void * ) &s_graphicsoptions.texturebits ); + Menu_AddItem( &s_graphicsoptions.menu, ( void * ) &s_graphicsoptions.filter ); + Menu_AddItem( &s_graphicsoptions.menu, ( void * ) &s_graphicsoptions.driverinfo ); + + Menu_AddItem( &s_graphicsoptions.menu, ( void * ) &s_graphicsoptions.back ); + Menu_AddItem( &s_graphicsoptions.menu, ( void * ) &s_graphicsoptions.apply ); + + GraphicsOptions_SetMenuItems(); + GraphicsOptions_GetInitialVideo(); + + if ( uis.glconfig.driverType == GLDRV_ICD && + uis.glconfig.hardwareType == GLHW_3DFX_2D3D ) + { + s_graphicsoptions.driver.generic.flags |= QMF_HIDDEN|QMF_INACTIVE; + } +} + + +/* +================= +GraphicsOptions_Cache +================= +*/ +void GraphicsOptions_Cache( void ) { + trap_R_RegisterShaderNoMip( GRAPHICSOPTIONS_FRAMEL ); + trap_R_RegisterShaderNoMip( GRAPHICSOPTIONS_FRAMER ); + trap_R_RegisterShaderNoMip( GRAPHICSOPTIONS_BACK0 ); + trap_R_RegisterShaderNoMip( GRAPHICSOPTIONS_BACK1 ); + trap_R_RegisterShaderNoMip( GRAPHICSOPTIONS_ACCEPT0 ); + trap_R_RegisterShaderNoMip( GRAPHICSOPTIONS_ACCEPT1 ); +} + + +/* +================= +UI_GraphicsOptionsMenu +================= +*/ +void UI_GraphicsOptionsMenu( void ) { + GraphicsOptions_MenuInit(); + UI_PushMenu( &s_graphicsoptions.menu ); + Menu_SetCursorToItem( &s_graphicsoptions.menu, &s_graphicsoptions.graphics ); +} + -- cgit v1.2.3