diff --git a/CODE-mp/ALut.lib b/CODE-mp/ALut.lib new file mode 100644 index 0000000..67cde9f Binary files /dev/null and b/CODE-mp/ALut.lib differ diff --git a/CODE-mp/EaxMan.dll b/CODE-mp/EaxMan.dll new file mode 100644 index 0000000..0a41c53 Binary files /dev/null and b/CODE-mp/EaxMan.dll differ diff --git a/CODE-mp/OpenAL32.dll b/CODE-mp/OpenAL32.dll new file mode 100644 index 0000000..78195c4 Binary files /dev/null and b/CODE-mp/OpenAL32.dll differ diff --git a/CODE-mp/OpenAL32.lib b/CODE-mp/OpenAL32.lib new file mode 100644 index 0000000..86de420 Binary files /dev/null and b/CODE-mp/OpenAL32.lib differ diff --git a/CODE-mp/WinDed.dsp b/CODE-mp/WinDed.dsp index 9d25ba2..41228a9 100644 --- a/CODE-mp/WinDed.dsp +++ b/CODE-mp/WinDed.dsp @@ -38,11 +38,11 @@ RSC=rc.exe # PROP Use_MFC 0 # PROP Use_Debug_Libraries 0 # PROP Output_Dir "Release" -# PROP Intermediate_Dir "Release" +# PROP Intermediate_Dir "Release/Dedicated" # PROP Ignore_Export_Lib 0 # PROP Target_Dir "" # ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c -# ADD CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /D "DEDICATED" /D "BOTLIB" /YX /FD /c +# ADD CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /D "DEDICATED" /D "BOTLIB" /FR /YX /FD /c # ADD BASE RSC /l 0x409 /d "NDEBUG" # ADD RSC /l 0x409 /d "NDEBUG" BSC32=bscmake.exe @@ -50,7 +50,7 @@ BSC32=bscmake.exe # ADD BSC32 /nologo LINK32=link.exe # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 -# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib wsock32.lib Winmm.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib wsock32.lib Winmm.lib /nologo /subsystem:console /machine:I386 /out:"Release/jk2Ded.exe" !ELSEIF "$(CFG)" == "WinDed - Win32 Debug" @@ -62,11 +62,11 @@ LINK32=link.exe # PROP Use_MFC 0 # PROP Use_Debug_Libraries 1 # PROP Output_Dir "Debug" -# PROP Intermediate_Dir "Debug" +# PROP Intermediate_Dir "Debug/dedicated" # PROP Ignore_Export_Lib 0 # PROP Target_Dir "" # ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c -# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /D "DEDICATED" /D "_JK2" /D "BOTLIB" /FD /GZ /c +# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /D "DEDICATED" /D "_JK2" /D "BOTLIB" /FR /FD /GZ /c # SUBTRACT CPP /YX # ADD BASE RSC /l 0x409 /d "_DEBUG" # ADD RSC /l 0x409 /d "_DEBUG" @@ -75,7 +75,7 @@ BSC32=bscmake.exe # ADD BSC32 /nologo LINK32=link.exe # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept -# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib wsock32.lib Winmm.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib wsock32.lib Winmm.lib /nologo /subsystem:console /debug /machine:I386 /out:"Debug/jk2Ded.exe" /pdbtype:sept !ENDIF @@ -136,10 +136,6 @@ SOURCE=.\qcommon\cmd.cpp # End Source File # Begin Source File -SOURCE=.\qcommon\CNetProfile.cpp -# End Source File -# Begin Source File - SOURCE=.\qcommon\common.cpp # End Source File # Begin Source File @@ -160,30 +156,10 @@ SOURCE=.\qcommon\game_version.h # End Source File # Begin Source File -SOURCE=.\qcommon\GenericParser2.cpp -# End Source File -# Begin Source File - -SOURCE=.\qcommon\GenericParser2.h -# End Source File -# Begin Source File - -SOURCE=.\qcommon\hstring.cpp -# End Source File -# Begin Source File - -SOURCE=.\qcommon\hstring.h -# End Source File -# Begin Source File - SOURCE=.\qcommon\huffman.cpp # End Source File # Begin Source File -SOURCE=.\qcommon\INetProfile.h -# End Source File -# Begin Source File - SOURCE=.\qcommon\md4.cpp # End Source File # Begin Source File @@ -756,14 +732,6 @@ SOURCE=.\png\png.h # End Source File # Begin Source File -SOURCE=.\game\q_math.c -# End Source File -# Begin Source File - -SOURCE=.\game\q_shared.c -# End Source File -# Begin Source File - SOURCE=.\game\q_shared.h # End Source File # Begin Source File diff --git a/CODE-mp/WinDed.plg b/CODE-mp/WinDed.plg index c4fac35..2a7958c 100644 --- a/CODE-mp/WinDed.plg +++ b/CODE-mp/WinDed.plg @@ -6,114 +6,353 @@ --------------------Configuration: WinDed - Win32 Debug--------------------

Command Lines

-Creating temporary file "C:\DOCUME~1\jmonroe\LOCALS~1\Temp\RSPB2B.tmp" with contents +Creating temporary file "C:\DOCUME~1\jmonroe\LOCALS~1\Temp\RSP12B4.tmp" with contents [ -/nologo /MLd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /D "DEDICATED" /D "_JK2" /D "BOTLIB" /Fo"Debug/" /Fd"Debug/" /FD /GZ /c +/nologo /MLd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /D "DEDICATED" /D "_JK2" /D "BOTLIB" /FR"Debug/dedicated/" /Fo"Debug/dedicated/" /Fd"Debug/dedicated/" /FD /GZ /c +"C:\projects\jk2\CODE-mp\qcommon\cm_load.cpp" +"C:\projects\jk2\CODE-mp\qcommon\cm_patch.cpp" +"C:\projects\jk2\CODE-mp\qcommon\cm_polylib.cpp" +"C:\projects\jk2\CODE-mp\qcommon\cm_test.cpp" +"C:\projects\jk2\CODE-mp\qcommon\cm_trace.cpp" +"C:\projects\jk2\CODE-mp\qcommon\cmd.cpp" +"C:\projects\jk2\CODE-mp\qcommon\common.cpp" +"C:\projects\jk2\CODE-mp\qcommon\cvar.cpp" +"C:\projects\jk2\CODE-mp\qcommon\files.cpp" +"C:\projects\jk2\CODE-mp\qcommon\huffman.cpp" +"C:\projects\jk2\CODE-mp\qcommon\msg.cpp" +"C:\projects\jk2\CODE-mp\qcommon\net_chan.cpp" +"C:\projects\jk2\CODE-mp\qcommon\q_math.cpp" +"C:\projects\jk2\CODE-mp\qcommon\q_shared.cpp" +"C:\projects\jk2\CODE-mp\qcommon\RoffSystem.cpp" +"C:\projects\jk2\CODE-mp\qcommon\strip.cpp" +"C:\projects\jk2\CODE-mp\qcommon\unzip.cpp" +"C:\projects\jk2\CODE-mp\qcommon\vm.cpp" +"C:\projects\jk2\CODE-mp\qcommon\vm_interpreted.cpp" +"C:\projects\jk2\CODE-mp\qcommon\vm_x86.cpp" +"C:\projects\jk2\CODE-mp\ghoul2\G2_API.cpp" +"C:\projects\jk2\CODE-mp\ghoul2\G2_bolts.cpp" +"C:\projects\jk2\CODE-mp\ghoul2\G2_bones.cpp" +"C:\projects\jk2\CODE-mp\ghoul2\G2_misc.cpp" +"C:\projects\jk2\CODE-mp\ghoul2\G2_surfaces.cpp" +"C:\projects\jk2\CODE-mp\server\sv_bot.cpp" +"C:\projects\jk2\CODE-mp\server\sv_ccmds.cpp" +"C:\projects\jk2\CODE-mp\server\sv_client.cpp" +"C:\projects\jk2\CODE-mp\server\sv_game.cpp" +"C:\projects\jk2\CODE-mp\server\sv_init.cpp" +"C:\projects\jk2\CODE-mp\server\sv_main.cpp" +"C:\projects\jk2\CODE-mp\server\sv_net_chan.cpp" +"C:\projects\jk2\CODE-mp\server\sv_snapshot.cpp" +"C:\projects\jk2\CODE-mp\server\sv_world.cpp" +"C:\projects\jk2\CODE-mp\null\null_client.cpp" "C:\projects\jk2\CODE-mp\null\null_glimp.cpp" -"C:\projects\jk2\CODE-mp\null\null_renderer.cpp" +"C:\projects\jk2\CODE-mp\null\null_input.cpp" "C:\projects\jk2\CODE-mp\null\null_snddma.cpp" +"C:\projects\jk2\CODE-mp\null\win_main.cpp" +"C:\projects\jk2\CODE-mp\renderer\tr_backend.cpp" +"C:\projects\jk2\CODE-mp\renderer\tr_ghoul2.cpp" +"C:\projects\jk2\CODE-mp\renderer\tr_image.cpp" +"C:\projects\jk2\CODE-mp\renderer\tr_init.cpp" +"C:\projects\jk2\CODE-mp\renderer\tr_main.cpp" +"C:\projects\jk2\CODE-mp\renderer\tr_mesh.cpp" +"C:\projects\jk2\CODE-mp\renderer\tr_model.cpp" +"C:\projects\jk2\CODE-mp\renderer\tr_shader.cpp" +"C:\projects\jk2\CODE-mp\win32\win_net.cpp" +"C:\projects\jk2\CODE-mp\win32\win_shared.cpp" +"C:\projects\jk2\CODE-mp\botlib\be_aas_bspq3.cpp" +"C:\projects\jk2\CODE-mp\botlib\be_aas_cluster.cpp" +"C:\projects\jk2\CODE-mp\botlib\be_aas_debug.cpp" +"C:\projects\jk2\CODE-mp\botlib\be_aas_entity.cpp" +"C:\projects\jk2\CODE-mp\botlib\be_aas_file.cpp" +"C:\projects\jk2\CODE-mp\botlib\be_aas_main.cpp" +"C:\projects\jk2\CODE-mp\botlib\be_aas_move.cpp" +"C:\projects\jk2\CODE-mp\botlib\be_aas_optimize.cpp" +"C:\projects\jk2\CODE-mp\botlib\be_aas_reach.cpp" +"C:\projects\jk2\CODE-mp\botlib\be_aas_route.cpp" +"C:\projects\jk2\CODE-mp\botlib\be_aas_routealt.cpp" +"C:\projects\jk2\CODE-mp\botlib\be_aas_sample.cpp" +"C:\projects\jk2\CODE-mp\botlib\be_ai_char.cpp" +"C:\projects\jk2\CODE-mp\botlib\be_ai_chat.cpp" +"C:\projects\jk2\CODE-mp\botlib\be_ai_gen.cpp" +"C:\projects\jk2\CODE-mp\botlib\be_ai_goal.cpp" +"C:\projects\jk2\CODE-mp\botlib\be_ai_move.cpp" +"C:\projects\jk2\CODE-mp\botlib\be_ai_weap.cpp" +"C:\projects\jk2\CODE-mp\botlib\be_ai_weight.cpp" +"C:\projects\jk2\CODE-mp\botlib\be_ea.cpp" +"C:\projects\jk2\CODE-mp\botlib\be_interface.cpp" +"C:\projects\jk2\CODE-mp\botlib\l_crc.cpp" +"C:\projects\jk2\CODE-mp\botlib\l_libvar.cpp" +"C:\projects\jk2\CODE-mp\botlib\l_log.cpp" +"C:\projects\jk2\CODE-mp\botlib\l_memory.cpp" +"C:\projects\jk2\CODE-mp\botlib\l_precomp.cpp" +"C:\projects\jk2\CODE-mp\botlib\l_script.cpp" +"C:\projects\jk2\CODE-mp\botlib\l_struct.cpp" ] -Creating command line "cl.exe @C:\DOCUME~1\jmonroe\LOCALS~1\Temp\RSPB2B.tmp" -Creating temporary file "C:\DOCUME~1\jmonroe\LOCALS~1\Temp\RSPB2C.tmp" with contents +Creating command line "cl.exe @C:\DOCUME~1\jmonroe\LOCALS~1\Temp\RSP12B4.tmp" +Creating temporary file "C:\DOCUME~1\jmonroe\LOCALS~1\Temp\RSP12B5.tmp" with contents [ -kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib wsock32.lib Winmm.lib /nologo /subsystem:console /incremental:yes /pdb:"Debug/WinDed.pdb" /debug /machine:I386 /out:"Debug/WinDed.exe" /pdbtype:sept -".\Debug\cm_load.obj" -".\Debug\cm_patch.obj" -".\Debug\cm_polylib.obj" -".\Debug\cm_test.obj" -".\Debug\cm_trace.obj" -".\Debug\cmd.obj" -".\Debug\CNetProfile.obj" -".\Debug\common.obj" -".\Debug\cvar.obj" -".\Debug\files.obj" -".\Debug\GenericParser2.obj" -".\Debug\hstring.obj" -".\Debug\huffman.obj" -".\Debug\md4.obj" -".\Debug\msg.obj" -".\Debug\net_chan.obj" -".\Debug\q_math.obj" -".\Debug\q_shared.obj" -".\Debug\RoffSystem.obj" -".\Debug\strip.obj" -".\Debug\unzip.obj" -".\Debug\vm.obj" -".\Debug\vm_interpreted.obj" -".\Debug\vm_x86.obj" -".\Debug\G2_API.obj" -".\Debug\G2_bolts.obj" -".\Debug\G2_bones.obj" -".\Debug\G2_misc.obj" -".\Debug\G2_surfaces.obj" -".\Debug\sv_bot.obj" -".\Debug\sv_ccmds.obj" -".\Debug\sv_client.obj" -".\Debug\sv_game.obj" -".\Debug\sv_init.obj" -".\Debug\sv_main.obj" -".\Debug\sv_net_chan.obj" -".\Debug\sv_snapshot.obj" -".\Debug\sv_world.obj" -".\Debug\null_client.obj" -".\Debug\null_glimp.obj" -".\Debug\null_input.obj" -".\Debug\null_renderer.obj" -".\Debug\null_snddma.obj" -".\Debug\win_main.obj" -".\Debug\matcomp.obj" -".\Debug\tr_backend.obj" -".\Debug\tr_ghoul2.obj" -".\Debug\tr_image.obj" -".\Debug\tr_init.obj" -".\Debug\tr_main.obj" -".\Debug\tr_mesh.obj" -".\Debug\tr_model.obj" -".\Debug\tr_shader.obj" -".\Debug\win_net.obj" -".\Debug\win_shared.obj" -".\Debug\be_aas_bspq3.obj" -".\Debug\be_aas_cluster.obj" -".\Debug\be_aas_debug.obj" -".\Debug\be_aas_entity.obj" -".\Debug\be_aas_file.obj" -".\Debug\be_aas_main.obj" -".\Debug\be_aas_move.obj" -".\Debug\be_aas_optimize.obj" -".\Debug\be_aas_reach.obj" -".\Debug\be_aas_route.obj" -".\Debug\be_aas_routealt.obj" -".\Debug\be_aas_sample.obj" -".\Debug\be_ai_char.obj" -".\Debug\be_ai_chat.obj" -".\Debug\be_ai_gen.obj" -".\Debug\be_ai_goal.obj" -".\Debug\be_ai_move.obj" -".\Debug\be_ai_weap.obj" -".\Debug\be_ai_weight.obj" -".\Debug\be_ea.obj" -".\Debug\be_interface.obj" -".\Debug\l_crc.obj" -".\Debug\l_libvar.obj" -".\Debug\l_log.obj" -".\Debug\l_memory.obj" -".\Debug\l_precomp.obj" -".\Debug\l_script.obj" -".\Debug\l_struct.obj" +kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib wsock32.lib Winmm.lib /nologo /subsystem:console /incremental:yes /pdb:"Debug/jk2Ded.pdb" /debug /machine:I386 /out:"Debug/jk2Ded.exe" /pdbtype:sept +".\Debug\dedicated\cm_load.obj" +".\Debug\dedicated\cm_patch.obj" +".\Debug\dedicated\cm_polylib.obj" +".\Debug\dedicated\cm_test.obj" +".\Debug\dedicated\cm_trace.obj" +".\Debug\dedicated\cmd.obj" +".\Debug\dedicated\common.obj" +".\Debug\dedicated\cvar.obj" +".\Debug\dedicated\files.obj" +".\Debug\dedicated\huffman.obj" +".\Debug\dedicated\md4.obj" +".\Debug\dedicated\msg.obj" +".\Debug\dedicated\net_chan.obj" +".\Debug\dedicated\q_math.obj" +".\Debug\dedicated\q_shared.obj" +".\Debug\dedicated\RoffSystem.obj" +".\Debug\dedicated\strip.obj" +".\Debug\dedicated\unzip.obj" +".\Debug\dedicated\vm.obj" +".\Debug\dedicated\vm_interpreted.obj" +".\Debug\dedicated\vm_x86.obj" +".\Debug\dedicated\G2_API.obj" +".\Debug\dedicated\G2_bolts.obj" +".\Debug\dedicated\G2_bones.obj" +".\Debug\dedicated\G2_misc.obj" +".\Debug\dedicated\G2_surfaces.obj" +".\Debug\dedicated\sv_bot.obj" +".\Debug\dedicated\sv_ccmds.obj" +".\Debug\dedicated\sv_client.obj" +".\Debug\dedicated\sv_game.obj" +".\Debug\dedicated\sv_init.obj" +".\Debug\dedicated\sv_main.obj" +".\Debug\dedicated\sv_net_chan.obj" +".\Debug\dedicated\sv_snapshot.obj" +".\Debug\dedicated\sv_world.obj" +".\Debug\dedicated\null_client.obj" +".\Debug\dedicated\null_glimp.obj" +".\Debug\dedicated\null_input.obj" +".\Debug\dedicated\null_renderer.obj" +".\Debug\dedicated\null_snddma.obj" +".\Debug\dedicated\win_main.obj" +".\Debug\dedicated\matcomp.obj" +".\Debug\dedicated\tr_backend.obj" +".\Debug\dedicated\tr_ghoul2.obj" +".\Debug\dedicated\tr_image.obj" +".\Debug\dedicated\tr_init.obj" +".\Debug\dedicated\tr_main.obj" +".\Debug\dedicated\tr_mesh.obj" +".\Debug\dedicated\tr_model.obj" +".\Debug\dedicated\tr_shader.obj" +".\Debug\dedicated\win_net.obj" +".\Debug\dedicated\win_shared.obj" +".\Debug\dedicated\be_aas_bspq3.obj" +".\Debug\dedicated\be_aas_cluster.obj" +".\Debug\dedicated\be_aas_debug.obj" +".\Debug\dedicated\be_aas_entity.obj" +".\Debug\dedicated\be_aas_file.obj" +".\Debug\dedicated\be_aas_main.obj" +".\Debug\dedicated\be_aas_move.obj" +".\Debug\dedicated\be_aas_optimize.obj" +".\Debug\dedicated\be_aas_reach.obj" +".\Debug\dedicated\be_aas_route.obj" +".\Debug\dedicated\be_aas_routealt.obj" +".\Debug\dedicated\be_aas_sample.obj" +".\Debug\dedicated\be_ai_char.obj" +".\Debug\dedicated\be_ai_chat.obj" +".\Debug\dedicated\be_ai_gen.obj" +".\Debug\dedicated\be_ai_goal.obj" +".\Debug\dedicated\be_ai_move.obj" +".\Debug\dedicated\be_ai_weap.obj" +".\Debug\dedicated\be_ai_weight.obj" +".\Debug\dedicated\be_ea.obj" +".\Debug\dedicated\be_interface.obj" +".\Debug\dedicated\l_crc.obj" +".\Debug\dedicated\l_libvar.obj" +".\Debug\dedicated\l_log.obj" +".\Debug\dedicated\l_memory.obj" +".\Debug\dedicated\l_precomp.obj" +".\Debug\dedicated\l_script.obj" +".\Debug\dedicated\l_struct.obj" ] -Creating command line "link.exe @C:\DOCUME~1\jmonroe\LOCALS~1\Temp\RSPB2C.tmp" +Creating command line "link.exe @C:\DOCUME~1\jmonroe\LOCALS~1\Temp\RSP12B5.tmp"

Output Window

Compiling... +G2_API.cpp +Generating Code... +Compiling... +cm_load.cpp +cm_patch.cpp +cm_polylib.cpp +cm_test.cpp +cm_trace.cpp +cmd.cpp +common.cpp +cvar.cpp +files.cpp +huffman.cpp +msg.cpp +net_chan.cpp +q_math.cpp +q_shared.cpp +RoffSystem.cpp +strip.cpp +unzip.cpp +vm.cpp +vm_interpreted.cpp +vm_x86.cpp +Generating Code... +Compiling... +G2_bolts.cpp +G2_bones.cpp +G2_misc.cpp +G2_surfaces.cpp +sv_bot.cpp +sv_ccmds.cpp +sv_client.cpp +sv_game.cpp +sv_init.cpp +sv_main.cpp +sv_net_chan.cpp +sv_snapshot.cpp +sv_world.cpp +null_client.cpp null_glimp.cpp -null_renderer.cpp +null_input.cpp null_snddma.cpp +win_main.cpp +tr_backend.cpp +tr_ghoul2.cpp +Generating Code... +Compiling... +tr_image.cpp +tr_init.cpp +tr_main.cpp +tr_mesh.cpp +tr_model.cpp +tr_shader.cpp +win_net.cpp +win_shared.cpp +be_aas_bspq3.cpp +be_aas_cluster.cpp +be_aas_debug.cpp +be_aas_entity.cpp +be_aas_file.cpp +be_aas_main.cpp +be_aas_move.cpp +be_aas_optimize.cpp +be_aas_reach.cpp +be_aas_route.cpp +be_aas_routealt.cpp +be_aas_sample.cpp +Generating Code... +Compiling... +be_ai_char.cpp +be_ai_chat.cpp +be_ai_gen.cpp +be_ai_goal.cpp +be_ai_move.cpp +be_ai_weap.cpp +be_ai_weight.cpp +be_ea.cpp +be_interface.cpp +l_crc.cpp +l_libvar.cpp +l_log.cpp +l_memory.cpp +l_precomp.cpp +l_script.cpp +l_struct.cpp Generating Code... Linking... +Creating temporary file "C:\DOCUME~1\jmonroe\LOCALS~1\Temp\RSP12B8.tmp" with contents +[ +/nologo /o"Debug/WinDed.bsc" +".\Debug\dedicated\cm_load.sbr" +".\Debug\dedicated\cm_patch.sbr" +".\Debug\dedicated\cm_polylib.sbr" +".\Debug\dedicated\cm_test.sbr" +".\Debug\dedicated\cm_trace.sbr" +".\Debug\dedicated\cmd.sbr" +".\Debug\dedicated\common.sbr" +".\Debug\dedicated\cvar.sbr" +".\Debug\dedicated\files.sbr" +".\Debug\dedicated\huffman.sbr" +".\Debug\dedicated\md4.sbr" +".\Debug\dedicated\msg.sbr" +".\Debug\dedicated\net_chan.sbr" +".\Debug\dedicated\q_math.sbr" +".\Debug\dedicated\q_shared.sbr" +".\Debug\dedicated\RoffSystem.sbr" +".\Debug\dedicated\strip.sbr" +".\Debug\dedicated\unzip.sbr" +".\Debug\dedicated\vm.sbr" +".\Debug\dedicated\vm_interpreted.sbr" +".\Debug\dedicated\vm_x86.sbr" +".\Debug\dedicated\G2_API.sbr" +".\Debug\dedicated\G2_bolts.sbr" +".\Debug\dedicated\G2_bones.sbr" +".\Debug\dedicated\G2_misc.sbr" +".\Debug\dedicated\G2_surfaces.sbr" +".\Debug\dedicated\sv_bot.sbr" +".\Debug\dedicated\sv_ccmds.sbr" +".\Debug\dedicated\sv_client.sbr" +".\Debug\dedicated\sv_game.sbr" +".\Debug\dedicated\sv_init.sbr" +".\Debug\dedicated\sv_main.sbr" +".\Debug\dedicated\sv_net_chan.sbr" +".\Debug\dedicated\sv_snapshot.sbr" +".\Debug\dedicated\sv_world.sbr" +".\Debug\dedicated\null_client.sbr" +".\Debug\dedicated\null_glimp.sbr" +".\Debug\dedicated\null_input.sbr" +".\Debug\dedicated\null_renderer.sbr" +".\Debug\dedicated\null_snddma.sbr" +".\Debug\dedicated\win_main.sbr" +".\Debug\dedicated\matcomp.sbr" +".\Debug\dedicated\tr_backend.sbr" +".\Debug\dedicated\tr_ghoul2.sbr" +".\Debug\dedicated\tr_image.sbr" +".\Debug\dedicated\tr_init.sbr" +".\Debug\dedicated\tr_main.sbr" +".\Debug\dedicated\tr_mesh.sbr" +".\Debug\dedicated\tr_model.sbr" +".\Debug\dedicated\tr_shader.sbr" +".\Debug\dedicated\win_net.sbr" +".\Debug\dedicated\win_shared.sbr" +".\Debug\dedicated\be_aas_bspq3.sbr" +".\Debug\dedicated\be_aas_cluster.sbr" +".\Debug\dedicated\be_aas_debug.sbr" +".\Debug\dedicated\be_aas_entity.sbr" +".\Debug\dedicated\be_aas_file.sbr" +".\Debug\dedicated\be_aas_main.sbr" +".\Debug\dedicated\be_aas_move.sbr" +".\Debug\dedicated\be_aas_optimize.sbr" +".\Debug\dedicated\be_aas_reach.sbr" +".\Debug\dedicated\be_aas_route.sbr" +".\Debug\dedicated\be_aas_routealt.sbr" +".\Debug\dedicated\be_aas_sample.sbr" +".\Debug\dedicated\be_ai_char.sbr" +".\Debug\dedicated\be_ai_chat.sbr" +".\Debug\dedicated\be_ai_gen.sbr" +".\Debug\dedicated\be_ai_goal.sbr" +".\Debug\dedicated\be_ai_move.sbr" +".\Debug\dedicated\be_ai_weap.sbr" +".\Debug\dedicated\be_ai_weight.sbr" +".\Debug\dedicated\be_ea.sbr" +".\Debug\dedicated\be_interface.sbr" +".\Debug\dedicated\l_crc.sbr" +".\Debug\dedicated\l_libvar.sbr" +".\Debug\dedicated\l_log.sbr" +".\Debug\dedicated\l_memory.sbr" +".\Debug\dedicated\l_precomp.sbr" +".\Debug\dedicated\l_script.sbr" +".\Debug\dedicated\l_struct.sbr"] +Creating command line "bscmake.exe @C:\DOCUME~1\jmonroe\LOCALS~1\Temp\RSP12B8.tmp" +Creating browse info file... +

Output Window

Results

-WinDed.exe - 0 error(s), 0 warning(s) +jk2Ded.exe - 0 error(s), 0 warning(s) diff --git a/CODE-mp/botlib/botlib.plg b/CODE-mp/botlib/botlib.plg new file mode 100644 index 0000000..d2443fd --- /dev/null +++ b/CODE-mp/botlib/botlib.plg @@ -0,0 +1,16 @@ + + +
+

Build Log

+

+--------------------Configuration: botlib - Win32 Final JK2-------------------- +

+

Command Lines

+ + + +

Results

+botlib.lib - 0 error(s), 0 warning(s) +
+ + diff --git a/CODE-mp/botlib/vssver.scc b/CODE-mp/botlib/vssver.scc index 6f32c47..e7e3df8 100644 Binary files a/CODE-mp/botlib/vssver.scc and b/CODE-mp/botlib/vssver.scc differ diff --git a/CODE-mp/cgame/animtable.h b/CODE-mp/cgame/animtable.h index 8810019..d091b1b 100644 --- a/CODE-mp/cgame/animtable.h +++ b/CODE-mp/cgame/animtable.h @@ -8,6 +8,7 @@ stringID_table_t animTable [MAX_ANIMATIONS+1] = //================================================= //ANIMS IN WHICH UPPER AND LOWER OBJECTS ARE IN MD3 //================================================= + ENUM2STRING(BOTH_1CRUFTFORGIL), //# G2 cannot have a reverse anim at beginning of file //# #sep ENUM2STRING(BOTH_ DEATHS ENUM2STRING(BOTH_DEATH1), //# First Death anim ENUM2STRING(BOTH_DEATH2), //# Second Death anim @@ -23,13 +24,17 @@ stringID_table_t animTable [MAX_ANIMATIONS+1] = ENUM2STRING(BOTH_DEATH12), //# ENUM2STRING(BOTH_DEATH13), //# ENUM2STRING(BOTH_DEATH14), //# - ENUM2STRING(BOTH_DEATH14_UNGRIP), //# Desann's end death (cin #35) - ENUM2STRING(BOTH_DEATH14_SITUP), //# Tavion sitting up after having been thrown (cin #23) ENUM2STRING(BOTH_DEATH15), //# ENUM2STRING(BOTH_DEATH16), //# ENUM2STRING(BOTH_DEATH17), //# ENUM2STRING(BOTH_DEATH18), //# ENUM2STRING(BOTH_DEATH19), //# + ENUM2STRING(BOTH_DEATH20), //# + ENUM2STRING(BOTH_DEATH21), //# + ENUM2STRING(BOTH_DEATH22), //# + ENUM2STRING(BOTH_DEATH23), //# + ENUM2STRING(BOTH_DEATH24), //# + ENUM2STRING(BOTH_DEATH25), //# ENUM2STRING(BOTH_DEATHFORWARD1), //# First Death in which they get thrown forward ENUM2STRING(BOTH_DEATHFORWARD2), //# Second Death in which they get thrown forward @@ -73,6 +78,12 @@ stringID_table_t animTable [MAX_ANIMATIONS+1] = ENUM2STRING(BOTH_DEAD17), //# ENUM2STRING(BOTH_DEAD18), //# ENUM2STRING(BOTH_DEAD19), //# + ENUM2STRING(BOTH_DEAD20), //# + ENUM2STRING(BOTH_DEAD21), //# + ENUM2STRING(BOTH_DEAD22), //# + ENUM2STRING(BOTH_DEAD23), //# + ENUM2STRING(BOTH_DEAD24), //# + ENUM2STRING(BOTH_DEAD25), //# ENUM2STRING(BOTH_DEADFORWARD1), //# First thrown forward death finished pose ENUM2STRING(BOTH_DEADFORWARD2), //# Second thrown forward death finished pose ENUM2STRING(BOTH_DEADBACKWARD1), //# First thrown backward death finished pose @@ -124,6 +135,7 @@ stringID_table_t animTable [MAX_ANIMATIONS+1] = //# #sep ENUM2STRING(BOTH_ ATTACKS ENUM2STRING(BOTH_ATTACK1), //# Attack with stun baton ENUM2STRING(BOTH_ATTACK2), //# Attack with one-handed pistol + ENUM2STRING(BOTH_ATTACK2IDLE1), //# Idle with one-handed pistol ENUM2STRING(BOTH_ATTACK3), //# Attack with blaster rifle ENUM2STRING(BOTH_ATTACK4), //# Attack with disruptor ENUM2STRING(BOTH_ATTACK5), //# Attack with bow caster @@ -607,19 +619,29 @@ stringID_table_t animTable [MAX_ANIMATIONS+1] = ENUM2STRING(BOTH_CCWCIRCLEBREAK), //# ENUM2STRING(BOTH_CWCIRCLELOCK), //# ENUM2STRING(BOTH_CCWCIRCLELOCK), //# + //other saber anims/attacks + ENUM2STRING(BOTH_SABERFAST_STANCE), + ENUM2STRING(BOTH_SABERSLOW_STANCE), + ENUM2STRING(BOTH_A2_STABBACK1), //# Stab saber backward + ENUM2STRING(BOTH_ATTACK_BACK), //# Swing around backwards and attack + ENUM2STRING(BOTH_JUMPFLIPSLASHDOWN1),//# + ENUM2STRING(BOTH_JUMPFLIPSTABDOWN),//# + ENUM2STRING(BOTH_FORCELEAP2_T__B_),//# + ENUM2STRING(BOTH_LUNGE2_B__T_),//# + ENUM2STRING(BOTH_CROUCHATTACKBACK1),//# //# #sep ENUM2STRING(BOTH_ STANDING - ENUM2STRING(BOTH_STAND1), //# Standing idle), no weapon), hands down - ENUM2STRING(BOTH_STAND1_RANDOM1), //# Random standing idle - ENUM2STRING(BOTH_STAND1_RANDOM2), //# Random standing idle - ENUM2STRING(BOTH_STAND2), //# Standing idle with a weapon - ENUM2STRING(BOTH_STAND2_RANDOM1), //# Random standing idle - ENUM2STRING(BOTH_STAND2_RANDOM2), //# Random standing idle - ENUM2STRING(BOTH_STAND2_RANDOM3), //# Random standing idle - ENUM2STRING(BOTH_STAND2_RANDOM4), //# Random standing idle - ENUM2STRING(BOTH_STAND3), //# Standing hands behind back), at ease), etc. + ENUM2STRING(BOTH_STAND1), //# Standing idle, no weapon, hands down + ENUM2STRING(BOTH_STAND1IDLE1), //# Random standing idle + ENUM2STRING(BOTH_STAND2), //# Standing idle with a saber + ENUM2STRING(BOTH_STAND2IDLE1), //# Random standing idle + ENUM2STRING(BOTH_STAND2IDLE2), + ENUM2STRING(BOTH_STAND3), //# Standing idle with 2-handed weapon + ENUM2STRING(BOTH_STAND3IDLE1), //# Random standing idle ENUM2STRING(BOTH_STAND4), //# hands clasp behind back - ENUM2STRING(BOTH_STAND5), //# standing idle), no weapon), hand down), back straight + ENUM2STRING(BOTH_STAND4IDLE1), //# Random standing idle + ENUM2STRING(BOTH_STAND5), //# standing idle, no weapon, hand down, back straight + ENUM2STRING(BOTH_STAND5IDLE1), //# Random standing idle ENUM2STRING(BOTH_STAND6), //# one handed), gun at side), relaxed stand ENUM2STRING(BOTH_STAND7), //# both hands on hips (female) ENUM2STRING(BOTH_STAND8), //# both hands on hips (male) @@ -638,8 +660,21 @@ stringID_table_t animTable [MAX_ANIMATIONS+1] = ENUM2STRING(BOTH_STAND5_REELO), //# Reelo in his stand5 position (cin #18) ENUM2STRING(BOTH_STAND1TOSTAND5), //# Transition from stand1 to stand5 ENUM2STRING(BOTH_STAND5TOSTAND1), //# Transition from stand5 to stand1 + ENUM2STRING(BOTH_STAND5TOAIM), //# Transition of Kye aiming his gun at Desann (cin #9) + ENUM2STRING(BOTH_STAND5STARTLEDLOOKLEFT), //# Kyle turning to watch the bridge drop (cin #9) + ENUM2STRING(BOTH_STARTLEDLOOKLEFTTOSTAND5), //# Kyle returning to stand 5 from watching the bridge drop (cin #9) ENUM2STRING(BOTH_STAND5TOSTAND8), //# Transition from stand5 to stand8 + ENUM2STRING(BOTH_STAND7TOSTAND8), //# Tavion putting hands on back of chair (cin #11) ENUM2STRING(BOTH_STAND8TOSTAND5), //# Transition from stand8 to stand5 + ENUM2STRING(BOTH_STAND5SHIFTWEIGHT), //# Weightshift from stand5 to side and back to stand5 + ENUM2STRING(BOTH_STAND5SHIFTWEIGHTSTART), //# From stand5 to side + ENUM2STRING(BOTH_STAND5SHIFTWEIGHTSTOP), //# From side to stand5 + ENUM2STRING(BOTH_STAND5TURNLEFTSTART), //# Start turning left from stand5 + ENUM2STRING(BOTH_STAND5TURNLEFTSTOP), //# Stop turning left from stand5 + ENUM2STRING(BOTH_STAND5TURNRIGHTSTART), //# Start turning right from stand5 + ENUM2STRING(BOTH_STAND5TURNRIGHTSTOP), //# Stop turning right from stand5 + ENUM2STRING(BOTH_STAND5LOOK180LEFTSTART), //# Start looking over left shoulder (cin #17) + ENUM2STRING(BOTH_STAND5LOOK180LEFTSTOP), //# Stop looking over left shoulder (cin #17) ENUM2STRING(BOTH_CONSOLE1START), //# typing at a console ENUM2STRING(BOTH_CONSOLE1), //# typing at a console @@ -647,6 +682,8 @@ stringID_table_t animTable [MAX_ANIMATIONS+1] = ENUM2STRING(BOTH_CONSOLE2START), //# typing at a console with comm link in hand (cin #5) ENUM2STRING(BOTH_CONSOLE2), //# typing at a console with comm link in hand (cin #5) ENUM2STRING(BOTH_CONSOLE2STOP), //# typing at a console with comm link in hand (cin #5) + ENUM2STRING(BOTH_CONSOLE2HOLDCOMSTART), //# lean in to type at console while holding comm link in hand (cin #5) + ENUM2STRING(BOTH_CONSOLE2HOLDCOMSTOP), //# lean away after typing at console while holding comm link in hand (cin #5) ENUM2STRING(BOTH_GUARD_LOOKAROUND1), //# Cradling weapon and looking around ENUM2STRING(BOTH_GUARD_IDLE1), //# Cradling weapon and standing @@ -654,6 +691,53 @@ stringID_table_t animTable [MAX_ANIMATIONS+1] = ENUM2STRING(BOTH_GESTURE1), //# Generic gesture), non-specific ENUM2STRING(BOTH_GESTURE2), //# Generic gesture), non-specific ENUM2STRING(BOTH_GESTURE3), //# Generic gesture), non-specific + ENUM2STRING(BOTH_WALK1TALKCOMM1), //# Talking into coom link while walking + ENUM2STRING(BOTH_TALK1), //# Generic talk anim + ENUM2STRING(BOTH_TALK2), //# Generic talk anim + ENUM2STRING(BOTH_TALKCOMM1START), //# Start talking into a comm link + ENUM2STRING(BOTH_TALKCOMM1), //# Talking into a comm link + ENUM2STRING(BOTH_TALKCOMM1STOP), //# Stop talking into a comm link + ENUM2STRING(BOTH_TALKGESTURE1), //# Generic talk anim + ENUM2STRING(BOTH_TALKGESTURE2), //# Generic talk anim + ENUM2STRING(BOTH_TALKGESTURE3), //# Generic talk anim + + ENUM2STRING(BOTH_TALKGESTURE4START), //# Beginning talk anim 4 + ENUM2STRING(BOTH_TALKGESTURE4), //# Talk gesture 4 + ENUM2STRING(BOTH_TALKGESTURE4STOP), //# Ending talk anim 4 + ENUM2STRING(BOTH_TALKGESTURE5START), //# Start hand on chin + ENUM2STRING(BOTH_TALKGESTURE5), //# Hand on chin + ENUM2STRING(BOTH_TALKGESTURE5STOP), //# Stop hand on chin + ENUM2STRING(BOTH_TALKGESTURE6START), //# Starting Motions to self + ENUM2STRING(BOTH_TALKGESTURE6), //# Pointing at self + ENUM2STRING(BOTH_TALKGESTURE6STOP), //# Ending Motions to self + ENUM2STRING(BOTH_TALKGESTURE7START), //# Start touches Kyle on shoulder + ENUM2STRING(BOTH_TALKGESTURE7), //# Hold touches Kyle on shoulder + ENUM2STRING(BOTH_TALKGESTURE7STOP), //# Ending touches Kyle on shoulder + ENUM2STRING(BOTH_TALKGESTURE8START), //# Lando's chin hold + ENUM2STRING(BOTH_TALKGESTURE8), //# Lando's chin hold + ENUM2STRING(BOTH_TALKGESTURE8STOP), //# Lando's chin hold + ENUM2STRING(BOTH_TALKGESTURE9), //# Same as gesture 2 but with the right hand + ENUM2STRING(BOTH_TALKGESTURE10), //# Shoulder shrug + ENUM2STRING(BOTH_TALKGESTURE11START), //# Arms folded across chest + ENUM2STRING(BOTH_TALKGESTURE11STOP), //# Arms folded across chest + ENUM2STRING(BOTH_TALKGESTURE12), //# Tavion taunting Kyle + ENUM2STRING(BOTH_TALKGESTURE13START), //# Luke warning Kyle + ENUM2STRING(BOTH_TALKGESTURE13), //# Luke warning Kyle + ENUM2STRING(BOTH_TALKGESTURE13STOP), //# Luke warning Kyle + ENUM2STRING(BOTH_TALKGESTURE14), //# Luke gesturing to Kyle + + ENUM2STRING(BOTH_TALKGESTURE15START), //# Desann taunting Kyle + ENUM2STRING(BOTH_TALKGESTURE15), //# Desann taunting Kyle + ENUM2STRING(BOTH_TALKGESTURE15STOP), //# Desann taunting Kyle + ENUM2STRING(BOTH_TALKGESTURE16), //# Bartender gesture cin #15 + ENUM2STRING(BOTH_TALKGESTURE17), //# Bartender gesture cin #15 + ENUM2STRING(BOTH_TALKGESTURE18), //# Bartender gesture cin #15 + ENUM2STRING(BOTH_TALKGESTURE19START), //# Desann lifting his arm "Join me" (cin #34) + ENUM2STRING(BOTH_TALKGESTURE19STOP), //# Desann lifting his arm "Join me" (cin #34) + ENUM2STRING(BOTH_TALKGESTURE20START), //# Kyle lifting his arm "Join us" (cin #34) + ENUM2STRING(BOTH_TALKGESTURE21), //# generic talk gesture from stand3 + ENUM2STRING(BOTH_TALKGESTURE22), //# generic talk gesture from stand3 + ENUM2STRING(BOTH_TALKGESTURE23), //# generic talk gesture from stand3 ENUM2STRING(BOTH_PAUSE1START), //# Luke pauses to warn Kyle (cin #24) start ENUM2STRING(BOTH_PAUSE1STOP), //# Luke pauses to warn Kyle (cin #24) stop @@ -670,6 +754,8 @@ stringID_table_t animTable [MAX_ANIMATIONS+1] = ENUM2STRING(BOTH_SITHEADTILTRSTOP), //# Head tilt to right from seated position ENUM2STRING(BOTH_SITHEADNOD), //# Head shake YES from seated position ENUM2STRING(BOTH_SITHEADSHAKE), //# Head shake NO from seated position + ENUM2STRING(BOTH_SIT2HEADTILTLSTART), //# Head tilt to left from seated position 2 + ENUM2STRING(BOTH_SIT2HEADTILTLSTOP), //# Head tilt to left from seated position 2 ENUM2STRING(BOTH_REACH1START), //# Monmothma reaching for crystal ENUM2STRING(BOTH_REACH1STOP), //# Monmothma reaching for crystal @@ -684,13 +770,6 @@ stringID_table_t animTable [MAX_ANIMATIONS+1] = ENUM2STRING(BOTH_EXAMINE3), //# Hold Lando looking around corner ENUM2STRING(BOTH_EXAMINE3STOP), //# End Lando looking around corner - ENUM2STRING(BOTH_THROW1START), //# Kyle thrown to the right - ENUM2STRING(BOTH_THROW1), //# Kyle thrown to the right - ENUM2STRING(BOTH_THROW1STOP), //# Kyle thrown to the right - ENUM2STRING(BOTH_THROW2START), //# Kyle thrown to the left - ENUM2STRING(BOTH_THROW2), //# Kyle thrown to the left - ENUM2STRING(BOTH_THROW3), //# Kyle thrown backwards in cin #9 - ENUM2STRING(BOTH_LEANLEFT2START), //# Start leaning left in chair ENUM2STRING(BOTH_LEANLEFT2STOP), //# Stop leaning left in chair ENUM2STRING(BOTH_LEANRIGHT3START), //# Start Lando leaning on wall @@ -726,6 +805,26 @@ stringID_table_t animTable [MAX_ANIMATIONS+1] = ENUM2STRING(BOTH_LAUGH1STOP), //# Reelo laughing (cin #18) ENUM2STRING(BOTH_ESCAPEPOD_LEAVE1), //# Kyle leaving escape pod (cin #33) ENUM2STRING(BOTH_ESCAPEPOD_LEAVE2), //# Jan leaving escape pod (cin #33) + ENUM2STRING(BOTH_HUGGER1), //# Kyle hugging Jan (cin #29) + ENUM2STRING(BOTH_HUGGERSTOP1), //# Kyle stop hugging Jan but don't let her go (cin #29) + ENUM2STRING(BOTH_HUGGERSTOP2), //# Kyle let go of Jan and step back (cin #29) + ENUM2STRING(BOTH_HUGGEE1), //# Jan being hugged (cin #29) + ENUM2STRING(BOTH_HUGGEESTOP1), //# Jan stop being hugged but don't let go (cin #29) + ENUM2STRING(BOTH_HUGGEESTOP2), //# Jan released from hug (cin #29) + ENUM2STRING(BOTH_KISSER1), //# Temp until the Kiss anim gets split up + ENUM2STRING(BOTH_KISSER1START1), //# Kyle start kissing Jan + ENUM2STRING(BOTH_KISSER1START2), //# Kyle start kissing Jan + ENUM2STRING(BOTH_KISSER1LOOP), //# Kyle loop kissing Jan + ENUM2STRING(BOTH_KISSER1STOP), //# Temp until the Kiss anim gets split up + ENUM2STRING(BOTH_KISSER1STOP1), //# Kyle stop kissing but don't let go + ENUM2STRING(BOTH_KISSER1STOP2), //# Kyle step back from Jan + ENUM2STRING(BOTH_KISSEE1), //# Temp until the Kiss anim gets split up + ENUM2STRING(BOTH_KISSEE1START1), //# Jan start being kissed + ENUM2STRING(BOTH_KISSEE1START2), //# Jan start2 being kissed + ENUM2STRING(BOTH_KISSEE1LOOP), //# Jan loop being kissed + ENUM2STRING(BOTH_KISSEE1STOP), //# Temp until the Kiss anim gets split up + ENUM2STRING(BOTH_KISSEE1STOP1), //# Jan stop being kissed but don't let go + ENUM2STRING(BOTH_KISSEE1STOP2), //# Jan wait for Kyle to step back ENUM2STRING(BOTH_BARTENDER_IDLE1), //# Bartender idle in cin #15 ENUM2STRING(BOTH_BARTENDER_THROW1), //# Bartender throws glass in cin #15 ENUM2STRING(BOTH_BARTENDER_COWERSTART), //# Start of Bartender raising both hands up in surrender (cin #16) @@ -735,6 +834,7 @@ stringID_table_t animTable [MAX_ANIMATIONS+1] = ENUM2STRING(BOTH_THREATEN1), //# Kyle threatening Bartender with lightsaber (cin #16) ENUM2STRING(BOTH_RADIO_ONOFF), //# Mech Galak turning on his suit radio (cin #32) ENUM2STRING(BOTH_TRIUMPHANT1START), //# Mech Galak raising his arms in victory (cin #32) + ENUM2STRING(BOTH_TRIUMPHANT1STARTGESTURE), //# Mech Galak raising his arms in victory (cin #32) ENUM2STRING(BOTH_TRIUMPHANT1STOP), //# Mech Galak lowering his arms in victory (cin #32) ENUM2STRING(BOTH_SABERTHROW1START), //# Desann throwing his light saber (cin #26) @@ -758,6 +858,8 @@ stringID_table_t animTable [MAX_ANIMATIONS+1] = ENUM2STRING(BOTH_SIT2TO3), //# Trans from sit2 to sit3? ENUM2STRING(BOTH_SIT2TOSTAND5), //# Transition from sit 2 to stand 5 + ENUM2STRING(BOTH_STAND5TOSIT2), //# Transition from stand 5 to sit 2 + ENUM2STRING(BOTH_SIT2TOSIT4), //# Trans from sit2 to sit4 (cin #12) Luke leaning back from lotus position. ENUM2STRING(BOTH_SIT3TO1), //# Trans from sit3 to sit1? ENUM2STRING(BOTH_SIT3TO2), //# Trans from sit3 to sit2? ENUM2STRING(BOTH_SIT3TOSTAND5), //# transition from sit 3 to stand 5 @@ -778,23 +880,22 @@ stringID_table_t animTable [MAX_ANIMATIONS+1] = ENUM2STRING(BOTH_UNCROUCH1), //# Transition from crouch to standing ENUM2STRING(BOTH_CROUCH2IDLE), //# crouch and resting on back righ heel), no weapon ENUM2STRING(BOTH_CROUCH2TOSTAND1), //# going from crouch2 to stand1 - ENUM2STRING(BOTH_UNCROUCH3), //# Desann uncrouching down to Kyle (cin 9) ENUM2STRING(BOTH_CROUCH3), //# Desann crouching down to Kyle (cin 9) + ENUM2STRING(BOTH_UNCROUCH3), //# Desann uncrouching down to Kyle (cin 9) + ENUM2STRING(BOTH_CROUCH4), //# Slower version of crouch1 for cinematics + ENUM2STRING(BOTH_UNCROUCH4), //# Slower version of uncrouch1 for cinematics ENUM2STRING(BOTH_GET_UP1), //# Get up from the ground), face down ENUM2STRING(BOTH_GET_UP2), //# Get up from the ground), face up - ENUM2STRING(BOTH_COCKPIT_CONSOLE1), //# work console1 while sitting in a cockpit. - ENUM2STRING(BOTH_COCKPIT_CONSOLE2), //# work console2 while sitting in a cockpit. ENUM2STRING(BOTH_COCKPIT_SIT), //# sit in a cockpit. ENUM2STRING(BOTH_GUNSIT1), //# sitting on an emplaced gun. + ENUM2STRING(BOTH_DEATH14_UNGRIP), //# Desann's end death (cin #35) + ENUM2STRING(BOTH_DEATH14_SITUP), //# Tavion sitting up after having been thrown (cin #23) ENUM2STRING(BOTH_KNEES1), //# Tavion on her knees ENUM2STRING(BOTH_KNEES2), //# Tavion on her knees looking down ENUM2STRING(BOTH_KNEES2TO1), //# Transition of KNEES2 to KNEES1 - ENUM2STRING(BOTH_STRUGGLE1START), //# Kyle struggling under crate - ENUM2STRING(BOTH_STRUGGLE1), //# Kyle struggling under crate - ENUM2STRING(BOTH_STRUGGLE1STOP), //# Kyle struggling under crate ENUM2STRING(BOTH_RUMMAGE1START), //# Kyle rummaging for crystal (cin 2) ENUM2STRING(BOTH_RUMMAGE1), //# Kyle rummaging for crystal (cin 2) @@ -812,6 +913,9 @@ stringID_table_t animTable [MAX_ANIMATIONS+1] = ENUM2STRING(BOTH_WALK5), //# Tavion taunting Kyle (cin 22) ENUM2STRING(BOTH_WALK6), //# Slow walk for Luke (cin 12) ENUM2STRING(BOTH_WALK7), //# Fast walk + ENUM2STRING(BOTH_WALK8), //# Normal walk with hands behind back (Luke in cin#12) + ENUM2STRING(BOTH_WALK9), //# Lando walk (cin #17) + ENUM2STRING(BOTH_WALK10), //# Lando walk (cin #17) ENUM2STRING(BOTH_WALKTORUN1), //# transition from walk to run ENUM2STRING(BOTH_RUN1), //# Full run ENUM2STRING(BOTH_RUN1START), //# Start into full run1 @@ -824,10 +928,12 @@ stringID_table_t animTable [MAX_ANIMATIONS+1] = ENUM2STRING(BOTH_RUNSTRAFE_RIGHT1), //# Sidestep right), should loop ENUM2STRING(BOTH_TURN_LEFT1), //# Turn left), should loop ENUM2STRING(BOTH_TURN_RIGHT1), //# Turn right), should loop + ENUM2STRING(BOTH_TURNSTAND1), //# Turn from STAND1 position ENUM2STRING(BOTH_TURNSTAND2), //# Turn from STAND2 position ENUM2STRING(BOTH_TURNSTAND3), //# Turn from STAND3 position ENUM2STRING(BOTH_TURNSTAND4), //# Turn from STAND4 position ENUM2STRING(BOTH_TURNSTAND5), //# Turn from STAND5 position + ENUM2STRING(BOTH_TURNCROUCH1), //# Turn from CROUCH1 position ENUM2STRING(BOTH_RUNAWAY1), //# Running scared ENUM2STRING(BOTH_SWIM1), //# Swimming @@ -898,16 +1004,7 @@ stringID_table_t animTable [MAX_ANIMATIONS+1] = ENUM2STRING(BOTH_DIVE1), //# Dive! - ENUM2STRING(BOTH_SABERFAST_STANCE), - ENUM2STRING(BOTH_SABERSLOW_STANCE), ENUM2STRING(BOTH_ENGAGETAUNT), - ENUM2STRING(BOTH_A2_STABBACK1), //# Stab saber backward - ENUM2STRING(BOTH_ATTACK_BACK), //# Swing around backwards and attack - ENUM2STRING(BOTH_JUMPFLIPSLASHDOWN1),//# - ENUM2STRING(BOTH_JUMPFLIPSTABDOWN),//# - ENUM2STRING(BOTH_FORCELEAP2_T__B_),//# - ENUM2STRING(BOTH_LUNGE2_B__T_),//# - ENUM2STRING(BOTH_CROUCHATTACKBACK1),//# ENUM2STRING(BOTH_ARIAL_LEFT), //# ENUM2STRING(BOTH_ARIAL_RIGHT), //# ENUM2STRING(BOTH_CARTWHEEL_LEFT), //# @@ -963,10 +1060,6 @@ stringID_table_t animTable [MAX_ANIMATIONS+1] = ENUM2STRING(BOTH_ARIAL_F1),//# ENUM2STRING(BOTH_BUTTERFLY_FR1),//# ENUM2STRING(BOTH_BUTTERFLY_FL1),//# - ENUM2STRING(BOTH_POSE1),//# - ENUM2STRING(BOTH_POSE2),//# - ENUM2STRING(BOTH_POSE3),//# - ENUM2STRING(BOTH_POSE4),//# //# #sep BOTH_ MISC MOVEMENT ENUM2STRING(BOTH_HIT1), //# Kyle hit by crate in cin #9 @@ -999,12 +1092,7 @@ stringID_table_t animTable [MAX_ANIMATIONS+1] = //# #sep BOTH_ SWIMMING ENUM2STRING(BOTH_SWIM_IDLE1), //# Swimming Idle 1 - ENUM2STRING(BOTH_SWIMFORWARDSTART), //# Swim forward start ENUM2STRING(BOTH_SWIMFORWARD), //# Swim forward loop - ENUM2STRING(BOTH_SWIMFORWARDSTOP), //# Swim forward end - ENUM2STRING(BOTH_SWIMBACKWARDSTART),//# Swim backward start - ENUM2STRING(BOTH_SWIMBACKWARD), //# Swim backward loop - ENUM2STRING(BOTH_SWIMBACKWARDSTOP), //# Swim backward end //# #sep ENUM2STRING(BOTH_ LYING ENUM2STRING(BOTH_LIE_DOWN1), //# From a stand position), get down on ground), face down @@ -1030,6 +1118,26 @@ stringID_table_t animTable [MAX_ANIMATIONS+1] = ENUM2STRING(BOTH_PROPUP1), //# Kyle getting up from having been knocked down (cin #9 end) ENUM2STRING(BOTH_CRAWLBACK1), //# Lying on back), crawling backwards with elbows ENUM2STRING(BOTH_SITWALL1), //# Sitting against a wall + ENUM2STRING(BOTH_SLEEP1), //# laying on back-rknee up-rhand on torso + ENUM2STRING(BOTH_SLEEP2), //# on floor-back against wall-arms crossed + ENUM2STRING(BOTH_SLEEP3), //# Sleeping in a chair + ENUM2STRING(BOTH_SLEEP4), //# Sleeping slumped over table + ENUM2STRING(BOTH_SLEEP5), //# Laying on side sleeping on flat sufrace + ENUM2STRING(BOTH_SLEEP6START), //# Kyle leaning back to sleep (cin 20) + ENUM2STRING(BOTH_SLEEP6STOP), //# Kyle waking up and shaking his head (cin 21) + ENUM2STRING(BOTH_SLEEP1GETUP), //# alarmed and getting up out of sleep1 pose to stand + ENUM2STRING(BOTH_SLEEP1GETUP2), //# + ENUM2STRING(BOTH_SLEEP2GETUP), //# alarmed and getting up out of sleep2 pose to stand + ENUM2STRING(BOTH_SLEEP3GETUP), //# alarmed and getting up out of sleep3 pose to stand + ENUM2STRING(BOTH_SLEEP3DEATH), //# death in chair), from sleep3 idle + ENUM2STRING(BOTH_SLEEP3DEAD), //# death in chair), from sleep3 idle + + ENUM2STRING(BOTH_SLEEP_IDLE1), //# rub face and nose while asleep from sleep pose 1 + ENUM2STRING(BOTH_SLEEP_IDLE2), //# shift position while asleep - stays in sleep2 + ENUM2STRING(BOTH_SLEEP_IDLE3), //# Idle anim from sleep pose 3 + ENUM2STRING(BOTH_SLEEP_IDLE4), //# Idle anim from sleep pose 4 + ENUM2STRING(BOTH_SLEEP1_NOSE), //# Scratch nose from SLEEP1 pose + ENUM2STRING(BOTH_SLEEP2_SHIFT), //# Shift in sleep from SLEEP2 pose ENUM2STRING(BOTH_RESTRAINED1), //# Telsia tied to medical table ENUM2STRING(BOTH_RESTRAINED1POINT), //# Telsia tied to medical table pointing at Munro ENUM2STRING(BOTH_LIFTED1), //# Fits with ENUM2STRING(BOTH_LIFT1), lifted on shoulder @@ -1060,6 +1168,7 @@ stringID_table_t animTable [MAX_ANIMATIONS+1] = ENUM2STRING(BOTH_MINDTRICK1), //# Use off-hand to do mind trick ENUM2STRING(BOTH_MINDTRICK2), //# Use off-hand to do distraction ENUM2STRING(BOTH_FORCELIGHTNING), //# Use off-hand to do lightning + ENUM2STRING(BOTH_FORCELIGHTNING_START), //# Use off-hand to do lightning - start ENUM2STRING(BOTH_FORCELIGHTNING_HOLD), //# Use off-hand to do lightning - hold ENUM2STRING(BOTH_FORCELIGHTNING_RELEASE),//# Use off-hand to do lightning - release ENUM2STRING(BOTH_FORCEHEAL_START), //# Healing meditation pose start @@ -1067,13 +1176,51 @@ stringID_table_t animTable [MAX_ANIMATIONS+1] = ENUM2STRING(BOTH_FORCEHEAL_QUICK), //# Healing meditation gesture ENUM2STRING(BOTH_SABERPULL), //# Use off-hand to do force power. ENUM2STRING(BOTH_FORCEGRIP1), //# force-gripping (no anim?) - ENUM2STRING(BOTH_FORCEGRIP2), //# force-gripping (?) ENUM2STRING(BOTH_FORCEGRIP3), //# force-gripping (right-hand) + ENUM2STRING(BOTH_FORCEGRIP3THROW), //# throwing while force-gripping (right hand) ENUM2STRING(BOTH_FORCEGRIP_HOLD), //# Use off-hand to do grip - hold ENUM2STRING(BOTH_FORCEGRIP_RELEASE),//# Use off-hand to do grip - release ENUM2STRING(BOTH_TOSS1), //# throwing to left after force gripping ENUM2STRING(BOTH_TOSS2), //# throwing to right after force gripping + ENUM2STRING(BOTH_COCKPIT_TALKR1START), //# turn head from straight forward to looking full right + ENUM2STRING(BOTH_COCKPIT_TALKR1STARTTOMID), //# from TALKR1START to looking at hologram (cin #1) + ENUM2STRING(BOTH_COCKPIT_TALKR1MIDTOSTART), //# from looking at hologram to TALKR1START (cin #1) + ENUM2STRING(BOTH_COCKPIT_TALKR1STOP), //# return head to straight forward from BOTH_COCKPIT_TALKR1 + ENUM2STRING(BOTH_COCKPIT_TALKR1STOPTOMID), //# from TALKR1STOP to TALKR1MID + ENUM2STRING(BOTH_COCKPIT_TALKR1MIDTOSTOP), //# from looking at hologram to TALKR1STOP (cin #1) + ENUM2STRING(BOTH_COCKPIT_TALKR1), //# talk to right side + + ENUM2STRING(BOTH_COCKPIT_TALKL1START), //# turn head from straight forward to looking full left + ENUM2STRING(BOTH_COCKPIT_TALKL1STARTTOMID), //# from TALKL1START to looking at hologram (cin #1) + ENUM2STRING(BOTH_COCKPIT_TALKL1MIDTOSTART), //# from looking at hologram to TALKL1START (cin #1) + ENUM2STRING(BOTH_COCKPIT_TALKL1STOP), //# return head to straight forward from BOTH_COCKPIT_TALKL1 + ENUM2STRING(BOTH_COCKPIT_TALKL1STOPTOMID), //# from TALKL1STOP to TALKL1MID + ENUM2STRING(BOTH_COCKPIT_TALKL1MIDTOSTOP), //# from looking at hologram to TALKL1STOP (cin #1) + ENUM2STRING(BOTH_COCKPIT_TALKL1), //# talk to left side + + ENUM2STRING(BOTH_COCKPIT_CONSOLE1), //# type at controls + ENUM2STRING(BOTH_COCKPIT_CONSOLE2), //# type at controls + ENUM2STRING(BOTH_COCKPIT_CONSOLE2_PARTIAL), //# last part of console2 anim (cin #1) used by Jan + + ENUM2STRING(BOTH_COCKPIT_HEADNOD), //# nod head yes while sitting + ENUM2STRING(BOTH_COCKPIT_HEADSHAKE), //# shake head no while sitting + + ENUM2STRING(BOTH_COCKPIT_HEADTILTLSTART), //# start tilt head left while sitting + ENUM2STRING(BOTH_COCKPIT_HEADTILTLSTOP), //# stop tilt head left while sitting + ENUM2STRING(BOTH_COCKPIT_HEADTILTRSTART), //# start tilt head right while sitting + ENUM2STRING(BOTH_COCKPIT_HEADTILTRSTOP), //# stop tilt head right while sitting + + ENUM2STRING(BOTH_COCKPIT_TALKGESTURE7START), //# Lando's supporting hand to Kyle (cin #21) + ENUM2STRING(BOTH_COCKPIT_TALKGESTURE7STOP), //# Lando's supporting hand away from Kyle (cin #21) + ENUM2STRING(BOTH_COCKPIT_TALKGESTURE8START), //# Hand to Lando's chin (cin #21) + ENUM2STRING(BOTH_COCKPIT_TALKGESTURE8STOP), //# hand away from Lando's chin *cin #21) + ENUM2STRING(BOTH_COCKPIT_TALKGESTURE11START), //# + ENUM2STRING(BOTH_COCKPIT_TALKGESTURE11STOP), //# + + ENUM2STRING(BOTH_COCKPIT_SLEEP6START), //# + ENUM2STRING(BOTH_COCKPIT_SLEEP6STOP), //# + //================================================= //ANIMS IN WHICH ONLY THE UPPER OBJECTS ARE IN MD3 //================================================= @@ -1114,22 +1261,6 @@ stringID_table_t animTable [MAX_ANIMATIONS+1] = //# #sep ENUM2STRING(TORSO_ USING NON-WEAPON OBJECTS //# #sep ENUM2STRING(TORSO_ MISC - ENUM2STRING(TORSO_TALKR1START), //# begin turning head for ENUM2STRING(BOTH_ENUM2STRING(TORSO_TALKR - ENUM2STRING(TORSO_TALKR1HOLD), //# non-looping version of talk to right side - ENUM2STRING(TORSO_TALKR1STOP), //# return head to straight forward from ENUM2STRING(BOTH_ENUM2STRING(TORSO_TALKL - ENUM2STRING(TORSO_TALKR1), //# talk to right side - ENUM2STRING(TORSO_TALKL1START), //# begin turning head for ENUM2STRING(BOTH_ENUM2STRING(TORSO_TALKL - ENUM2STRING(TORSO_TALKL1HOLD), //# non-looping version of talk to left side - ENUM2STRING(TORSO_TALKL1STOP), //# return head to straight forward from ENUM2STRING(BOTH_ENUM2STRING(TORSO_TALKL - ENUM2STRING(TORSO_TALKL1), //# talk to left side - ENUM2STRING(TORSO_LOOKL1), //# looking left - ENUM2STRING(TORSO_LOOKR1), //# looking right - ENUM2STRING(TORSO_LOOKR2START), //# turn not so far as TALKR1 - ENUM2STRING(TORSO_LOOKR2STOP), //# turn not so far as TALKR1 - ENUM2STRING(TORSO_LOOKR2), //# looking right - not so far as LOOKR1 - ENUM2STRING(TORSO_LOOKL2START), //# turn not so far as TALKL1 - ENUM2STRING(TORSO_LOOKL2STOP), //# turn not so far as TALKL1 - ENUM2STRING(TORSO_LOOKL2), //# looking right - not so far as LOOKL1 ENUM2STRING(TORSO_HANDGESTURE1), //# gestures to left one hand ENUM2STRING(TORSO_HANDGESTURE2), //# gestures to right one hand ENUM2STRING(TORSO_HANDGESTURE3), //# gestures to the left both hands diff --git a/CODE-mp/cgame/cg_draw.c b/CODE-mp/cgame/cg_draw.c index 4718634..5d677f3 100644 --- a/CODE-mp/cgame/cg_draw.c +++ b/CODE-mp/cgame/cg_draw.c @@ -30,24 +30,24 @@ char teamChat2[256]; char *showPowersName[] = { - "Heal",//FP_HEAL - "Jump",//FP_LEVITATION - "Speed",//FP_SPEED - "Push",//FP_PUSH - "Pull",//FP_PULL - "Mind Trick",//FP_TELEPTAHY - "Grip",//FP_GRIP - "Lightning",//FP_LIGHTNING - "Dark Rage",//FP_RAGE - "Protect",//FP_PROTECT - "Absorb",//FP_ABSORB - "Team Heal",//FP_TEAM_HEAL - "Team Replenish",//FP_TEAM_FORCE - "Drain",//FP_DRAIN - "Seeing",//FP_SEE - "Saber Attack",//FP_SABERATTACK - "Saber Defend",//FP_SABERDEFEND - "Saber Throw",//FP_SABERTHROW + "HEAL2",//FP_HEAL + "JUMP2",//FP_LEVITATION + "SPEED2",//FP_SPEED + "PUSH2",//FP_PUSH + "PULL2",//FP_PULL + "MINDTRICK2",//FP_TELEPTAHY + "GRIP2",//FP_GRIP + "LIGHTNING2",//FP_LIGHTNING + "DARK_RAGE2",//FP_RAGE + "PROTECT2",//FP_PROTECT + "ABSORB2",//FP_ABSORB + "TEAM_HEAL2",//FP_TEAM_HEAL + "TEAM_REPLENISH2",//FP_TEAM_FORCE + "DRAIN2",//FP_DRAIN + "SEEING2",//FP_SEE + "SABER_OFFENSE2",//FP_SABERATTACK + "SABER_DEFENSE2",//FP_SABERDEFEND + "SABER_THROW2",//FP_SABERTHROW NULL }; @@ -1134,7 +1134,12 @@ void CG_DrawHUD(centity_t *cent) } //scoreStr = va("Score: %i", cgs.clientinfo[cg.snap->ps.clientNum].score); - if (0 && cgs.gametype < GT_TEAM ) + if ( cgs.gametype == GT_TOURNAMENT ) + {//A duel that requires more than one kill to knock the current enemy back to the queue + //show current kills out of how many needed + scoreStr = va("Score: %i/%i", cg.snap->ps.persistant[PERS_SCORE], cgs.fraglimit); + } + else if (0 && cgs.gametype < GT_TEAM ) { // This is a teamless mode, draw the score bias. scoreBias = cg.snap->ps.persistant[PERS_SCORE] - cgs.scores1; if (scoreBias == 0) @@ -1358,7 +1363,7 @@ void CG_DrawForceSelect( void ) if ( showPowersName[cg.forceSelect] ) { - UI_DrawProportionalString(320, y + 30, showPowersName[cg.forceSelect], UI_CENTER | UI_SMALLFONT, colorTable[CT_ICON_BLUE]); + UI_DrawProportionalString(320, y + 30, CG_GetStripEdString("INGAME", showPowersName[cg.forceSelect]), UI_CENTER | UI_SMALLFONT, colorTable[CT_ICON_BLUE]); } } @@ -1664,7 +1669,7 @@ static float CG_DrawMiniScoreboard ( float y ) Q_strcat ( temp, MAX_QPATH, " 2nd: " ); Q_strcat ( temp, MAX_QPATH, cgs.scores2==SCORE_NOT_PRESENT?"-":(va("%i",cgs.scores2)) ); - CG_Text_Paint( 630 - CG_Text_Width ( temp, 0.75f, FONT_SMALL ), y, 0.75f, colorWhite, temp, 0, 0, ITEM_TEXTSTYLE_SHADOWEDMORE, FONT_MEDIUM ); + CG_Text_Paint( 630 - CG_Text_Width ( temp, 0.7f, FONT_SMALL ), y, 0.7f, colorWhite, temp, 0, 0, ITEM_TEXTSTYLE_SHADOWEDMORE, FONT_MEDIUM ); y += 15; */ //rww - no longer doing this. Since the attacker now shows who is first, we print the score there. @@ -1698,13 +1703,16 @@ static float CG_DrawEnemyInfo ( float y ) if ( cgs.gametype == GT_JEDIMASTER ) { - title = "Jedi Master"; + //title = "Jedi Master"; + title = CG_GetStripEdString("INGAMETEXT", "MASTERY7"); clientNum = cgs.jediMaster; if ( clientNum < 0 ) { //return y; - title = "Get Saber!"; +// title = "Get Saber!"; + title = CG_GetStripEdString("INGAMETEXT", "GET_SABER"); + size = ICON_SIZE * 1.25; y += 5; @@ -1714,23 +1722,25 @@ static float CG_DrawEnemyInfo ( float y ) y += size; /* - CG_Text_Paint( 630 - CG_Text_Width ( ci->name, 0.75f, FONT_MEDIUM ), y, 0.75f, colorWhite, ci->name, 0, 0, 0, FONT_MEDIUM ); + CG_Text_Paint( 630 - CG_Text_Width ( ci->name, 0.7f, FONT_MEDIUM ), y, 0.7f, colorWhite, ci->name, 0, 0, 0, FONT_MEDIUM ); y += 15; */ - CG_Text_Paint( 630 - CG_Text_Width ( title, 0.75f, FONT_MEDIUM ), y, 0.75f, colorWhite, title, 0, 0, 0, FONT_MEDIUM ); + CG_Text_Paint( 630 - CG_Text_Width ( title, 0.7f, FONT_MEDIUM ), y, 0.7f, colorWhite, title, 0, 0, 0, FONT_MEDIUM ); return y + BIGCHAR_HEIGHT + 2; } } else if ( cg.snap->ps.duelInProgress ) { - title = "Dueling"; +// title = "Dueling"; + title = CG_GetStripEdString("INGAMETEXT", "DUELING"); clientNum = cg.snap->ps.duelIndex; } else if ( cgs.gametype == GT_TOURNAMENT && cgs.clientinfo[cg.snap->ps.clientNum].team != TEAM_SPECTATOR) { - title = "Dueling"; +// title = "Dueling"; + title = CG_GetStripEdString("INGAMETEXT", "DUELING"); if (cg.snap->ps.clientNum == cgs.duelist1) { clientNum = cgs.duelist2; @@ -1785,7 +1795,7 @@ static float CG_DrawEnemyInfo ( float y ) ci = &cgs.clientinfo[ clientNum ]; - if (!ci || !ci->modelIcon) + if ( !ci ) { return y; } @@ -1793,14 +1803,25 @@ static float CG_DrawEnemyInfo ( float y ) size = ICON_SIZE * 1.25; y += 5; - CG_DrawPic( 640 - size - 5, y, size, size, ci->modelIcon ); + if ( ci->modelIcon ) + { + CG_DrawPic( 640 - size - 5, y, size, size, ci->modelIcon ); + } y += size; - CG_Text_Paint( 630 - CG_Text_Width ( ci->name, 0.75f, FONT_MEDIUM ), y, 0.75f, colorWhite, ci->name, 0, 0, 0, FONT_MEDIUM ); + CG_Text_Paint( 630 - CG_Text_Width ( ci->name, 0.7f, FONT_MEDIUM ), y, 0.7f, colorWhite, ci->name, 0, 0, 0, FONT_MEDIUM ); y += 15; - CG_Text_Paint( 630 - CG_Text_Width ( title, 0.75f, FONT_MEDIUM ), y, 0.75f, colorWhite, title, 0, 0, 0, FONT_MEDIUM ); + CG_Text_Paint( 630 - CG_Text_Width ( title, 0.7f, FONT_MEDIUM ), y, 0.7f, colorWhite, title, 0, 0, 0, FONT_MEDIUM ); + + if ( cgs.gametype == GT_TOURNAMENT && cgs.clientinfo[cg.snap->ps.clientNum].team != TEAM_SPECTATOR) + {//also print their score + char text[1024]; + y += 15; + Com_sprintf(text, sizeof(text), "%i/%i", cgs.clientinfo[clientNum].score, cgs.fraglimit ); + CG_Text_Paint( 630 - CG_Text_Width ( text, 0.7f, FONT_MEDIUM ), y, 0.7f, colorWhite, text, 0, 0, 0, FONT_MEDIUM ); + } return y + BIGCHAR_HEIGHT + 2; } @@ -2664,6 +2685,12 @@ static void CG_DrawCrosshair( vec3_t worldPoint, int chEntValid ) { ecolor[1] = 0.0;//G ecolor[2] = 0.0;//B } + else if (crossEnt->currentState.eType == ET_GRAPPLE) + { + ecolor[0] = 1.0;//R + ecolor[1] = 0.0;//G + ecolor[2] = 0.0;//B + } } ecolor[3] = 1.0; @@ -3266,7 +3293,7 @@ CG_DrawSpectator static void CG_DrawSpectator(void) { const char* s; - s = "SPECTATOR"; + s = CG_GetStripEdString("INGAMETEXT", "SPECTATOR"); if (cgs.gametype == GT_TOURNAMENT && cgs.duelist1 != -1 && cgs.duelist2 != -1) @@ -3278,13 +3305,20 @@ static void CG_DrawSpectator(void) CG_Text_Paint ( 320 - CG_Text_Width ( text, 1.0f, 3 ) / 2, 420, 1.0f, colorWhite, text, 0, 0, 0, 3 ); - if (cgs.clientinfo[cgs.duelist1].modelIcon && - cgs.clientinfo[cgs.duelist2].modelIcon) + trap_R_SetColor( colorTable[CT_WHITE] ); + if ( cgs.clientinfo[cgs.duelist1].modelIcon ) { - trap_R_SetColor( colorTable[CT_WHITE] ); CG_DrawPic( 10, SCREEN_HEIGHT-(size*1.5), size, size, cgs.clientinfo[cgs.duelist1].modelIcon ); + } + if ( cgs.clientinfo[cgs.duelist2].modelIcon ) + { CG_DrawPic( SCREEN_WIDTH-size-10, SCREEN_HEIGHT-(size*1.5), size, size, cgs.clientinfo[cgs.duelist2].modelIcon ); } + Com_sprintf(text, sizeof(text), "%i/%i", cgs.clientinfo[cgs.duelist1].score, cgs.fraglimit ); + CG_Text_Paint( 42 - CG_Text_Width( text, 1.0f, 2 ) / 2, SCREEN_HEIGHT-(size*1.5) + 64, 1.0f, colorWhite, text, 0, 0, 0, 2 ); + + Com_sprintf(text, sizeof(text), "%i/%i", cgs.clientinfo[cgs.duelist2].score, cgs.fraglimit ); + CG_Text_Paint( SCREEN_WIDTH-size+22 - CG_Text_Width( text, 1.0f, 2 ) / 2, SCREEN_HEIGHT-(size*1.5) + 64, 1.0f, colorWhite, text, 0, 0, 0, 2 ); } else { @@ -3293,7 +3327,7 @@ static void CG_DrawSpectator(void) if ( cgs.gametype == GT_TOURNAMENT ) { - s = "waiting to play"; + s = CG_GetStripEdString("INGAMETEXT", "WAITING_TO_PLAY"); // "waiting to play"; CG_Text_Paint ( 320 - CG_Text_Width ( s, 1.0f, 3 ) / 2, 440, 1.0f, colorWhite, s, 0, 0, 0, 3 ); } else //if ( cgs.gametype >= GT_TEAM ) @@ -3509,7 +3543,8 @@ static qboolean CG_DrawFollow( void ) return qfalse; } - s = "following"; +// s = "following"; + s = CG_GetStripEdString("INGAMETEXT", "FOLLOWING"); CG_Text_Paint ( 320 - CG_Text_Width ( s, 1.0f, FONT_MEDIUM ) / 2, 60, 1.0f, colorWhite, s, 0, 0, 0, FONT_MEDIUM ); s = cgs.clientinfo[ cg.snap->ps.clientNum ].name; @@ -3601,7 +3636,8 @@ static void CG_DrawWarmup( void ) { } if ( sec < 0 ) { - s = "Waiting for players"; +// s = "Waiting for players"; + s = CG_GetStripEdString("INGAMETEXT", "WAITING_FOR_PLAYERS"); w = CG_DrawStrlen( s ) * BIGCHAR_WIDTH; CG_DrawBigString(320 - w / 2, 24, s, 1.0F); cg.warmupCount = 0; @@ -3654,7 +3690,8 @@ static void CG_DrawWarmup( void ) { cg.warmup = 0; sec = 0; } - s = va( "Starts in: %i", sec + 1 ); +// s = va( "Starts in: %i", sec + 1 ); + s = va( "%s: %i",CG_GetStripEdString("INGAMETEXT", "STARTS_IN"), sec + 1 ); if ( sec != cg.warmupCount ) { cg.warmupCount = sec; switch ( sec ) { @@ -4254,6 +4291,7 @@ static void CG_Draw2D( void ) { CG_DrawSpectator(); CG_DrawCrosshair(NULL, 0); CG_DrawCrosshairNames(); + CG_SaberClashFlare(); } else { // don't draw any status if dead or the scoreboard is being explicitly shown if ( !cg.showScores && cg.snap->ps.stats[STAT_HEALTH] > 0 ) { diff --git a/CODE-mp/cgame/cg_effects.c b/CODE-mp/cgame/cg_effects.c index 6931bb4..895c4ce 100644 --- a/CODE-mp/cgame/cg_effects.c +++ b/CODE-mp/cgame/cg_effects.c @@ -726,15 +726,69 @@ Throws specified debris from within a given bounding box in the world #define DEBRIS_SPECIALCASE_CHUNKS -2 #define DEBRIS_SPECIALCASE_WOOD -3 #define DEBRIS_SPECIALCASE_GLASS -4 + +#define NUM_DEBRIS_MODELS_GLASS 8 +#define NUM_DEBRIS_MODELS_WOOD 8 +#define NUM_DEBRIS_MODELS_CHUNKS 3 +#define NUM_DEBRIS_MODELS_ROCKS 4 //12 + +int dbModels_Glass[NUM_DEBRIS_MODELS_GLASS]; +int dbModels_Wood[NUM_DEBRIS_MODELS_WOOD]; +int dbModels_Chunks[NUM_DEBRIS_MODELS_CHUNKS]; +int dbModels_Rocks[NUM_DEBRIS_MODELS_ROCKS]; + void CG_CreateDebris(int entnum, vec3_t org, vec3_t mins, vec3_t maxs, int debrissound, int debrismodel) { vec3_t velocity, a, shardorg, dif, difx; float windowmass; float shardsthrow = 0; - char chunkname[256]; - int rfact = 0; int omodel = debrismodel; + if (omodel == DEBRIS_SPECIALCASE_GLASS && !dbModels_Glass[0]) + { //glass no longer exists, using it for metal. + dbModels_Glass[0] = trap_R_RegisterModel("models/chunks/metal/metal1_1.md3"); + dbModels_Glass[1] = trap_R_RegisterModel("models/chunks/metal/metal1_2.md3"); + dbModels_Glass[2] = trap_R_RegisterModel("models/chunks/metal/metal1_3.md3"); + dbModels_Glass[3] = trap_R_RegisterModel("models/chunks/metal/metal1_4.md3"); + dbModels_Glass[4] = trap_R_RegisterModel("models/chunks/metal/metal2_1.md3"); + dbModels_Glass[5] = trap_R_RegisterModel("models/chunks/metal/metal2_2.md3"); + dbModels_Glass[6] = trap_R_RegisterModel("models/chunks/metal/metal2_3.md3"); + dbModels_Glass[7] = trap_R_RegisterModel("models/chunks/metal/metal2_4.md3"); + } + if (omodel == DEBRIS_SPECIALCASE_WOOD && !dbModels_Wood[0]) + { + dbModels_Wood[0] = trap_R_RegisterModel("models/chunks/crate/crate1_1.md3"); + dbModels_Wood[1] = trap_R_RegisterModel("models/chunks/crate/crate1_2.md3"); + dbModels_Wood[2] = trap_R_RegisterModel("models/chunks/crate/crate1_3.md3"); + dbModels_Wood[3] = trap_R_RegisterModel("models/chunks/crate/crate1_4.md3"); + dbModels_Wood[4] = trap_R_RegisterModel("models/chunks/crate/crate2_1.md3"); + dbModels_Wood[5] = trap_R_RegisterModel("models/chunks/crate/crate2_2.md3"); + dbModels_Wood[6] = trap_R_RegisterModel("models/chunks/crate/crate2_3.md3"); + dbModels_Wood[7] = trap_R_RegisterModel("models/chunks/crate/crate2_4.md3"); + } + if (omodel == DEBRIS_SPECIALCASE_CHUNKS && !dbModels_Chunks[0]) + { + dbModels_Chunks[0] = trap_R_RegisterModel("models/chunks/generic/chunks_1.md3"); + dbModels_Chunks[1] = trap_R_RegisterModel("models/chunks/generic/chunks_2.md3"); + } + if (omodel == DEBRIS_SPECIALCASE_ROCK && !dbModels_Rocks[0]) + { + dbModels_Rocks[0] = trap_R_RegisterModel("models/chunks/rock/rock1_1.md3"); + dbModels_Rocks[1] = trap_R_RegisterModel("models/chunks/rock/rock1_2.md3"); + dbModels_Rocks[2] = trap_R_RegisterModel("models/chunks/rock/rock1_3.md3"); + dbModels_Rocks[3] = trap_R_RegisterModel("models/chunks/rock/rock1_4.md3"); + /* + dbModels_Rocks[4] = trap_R_RegisterModel("models/chunks/rock/rock2_1.md3"); + dbModels_Rocks[5] = trap_R_RegisterModel("models/chunks/rock/rock2_2.md3"); + dbModels_Rocks[6] = trap_R_RegisterModel("models/chunks/rock/rock2_3.md3"); + dbModels_Rocks[7] = trap_R_RegisterModel("models/chunks/rock/rock2_4.md3"); + dbModels_Rocks[8] = trap_R_RegisterModel("models/chunks/rock/rock3_1.md3"); + dbModels_Rocks[9] = trap_R_RegisterModel("models/chunks/rock/rock3_2.md3"); + dbModels_Rocks[10] = trap_R_RegisterModel("models/chunks/rock/rock3_3.md3"); + dbModels_Rocks[11] = trap_R_RegisterModel("models/chunks/rock/rock3_4.md3"); + */ + } + VectorSubtract(maxs, mins, a); windowmass = VectorLength(a); //should give us some idea of how big the chunk of glass is @@ -747,35 +801,19 @@ void CG_CreateDebris(int entnum, vec3_t org, vec3_t mins, vec3_t maxs, int debri if (omodel == DEBRIS_SPECIALCASE_GLASS) { - Com_sprintf(chunkname, sizeof(chunkname), "models/chunks/glass/glchunks_%i.md3", Q_irand(1, 6)); - debrismodel = trap_R_RegisterModel(chunkname); + debrismodel = dbModels_Glass[Q_irand(0, NUM_DEBRIS_MODELS_GLASS-1)]; } else if (omodel == DEBRIS_SPECIALCASE_WOOD) { - Com_sprintf(chunkname, sizeof(chunkname), "models/chunks/generic/wood_%i.md3", Q_irand(1, 3)); - debrismodel = trap_R_RegisterModel(chunkname); + debrismodel = dbModels_Wood[Q_irand(0, NUM_DEBRIS_MODELS_WOOD-1)]; } else if (omodel == DEBRIS_SPECIALCASE_CHUNKS) { - Com_sprintf(chunkname, sizeof(chunkname), "models/chunks/generic/chunks_%i.md3", Q_irand(1, 6)); - debrismodel = trap_R_RegisterModel(chunkname); + debrismodel = dbModels_Chunks[Q_irand(0, NUM_DEBRIS_MODELS_CHUNKS-1)]; } else if (omodel == DEBRIS_SPECIALCASE_ROCK) { - rfact = Q_irand(1, 3); - if (rfact == 1) - { - Com_sprintf(chunkname, sizeof(chunkname), "models/chunks/rock/rock_small.md3"); - } - else if (rfact == 2) - { - Com_sprintf(chunkname, sizeof(chunkname), "models/chunks/rock/rock_med.md3"); - } - else - { - Com_sprintf(chunkname, sizeof(chunkname), "models/chunks/rock/rock_big.md3"); - } - debrismodel = trap_R_RegisterModel(chunkname); + debrismodel = dbModels_Rocks[Q_irand(0, NUM_DEBRIS_MODELS_ROCKS-1)]; } VectorCopy(org, shardorg); @@ -1158,168 +1196,3 @@ void CG_LaunchGib( vec3_t origin, vec3_t velocity, qhandle_t hModel ) { le->leBounceSoundType = LEBS_BLOOD; le->leMarkType = LEMT_BLOOD; } - -/* -=================== -CG_GibPlayer - -Generated a bunch of gibs launching out from the bodies location -=================== -*/ -#define GIB_VELOCITY 250 -#define GIB_JUMP 250 -void CG_GibPlayer( vec3_t playerOrigin ) { - vec3_t origin, velocity; - - if ( !cg_blood.integer ) { - return; - } - - VectorCopy( playerOrigin, origin ); - velocity[0] = crandom()*GIB_VELOCITY; - velocity[1] = crandom()*GIB_VELOCITY; - velocity[2] = GIB_JUMP + crandom()*GIB_VELOCITY; - if ( rand() & 1 ) { -// CG_LaunchGib( origin, velocity, cgs.media.gibSkull ); - } else { -// CG_LaunchGib( origin, velocity, cgs.media.gibBrain ); - } - - // allow gibs to be turned off for speed - if ( !cg_gibs.integer ) { - return; - } - - VectorCopy( playerOrigin, origin ); - velocity[0] = crandom()*GIB_VELOCITY; - velocity[1] = crandom()*GIB_VELOCITY; - velocity[2] = GIB_JUMP + crandom()*GIB_VELOCITY; -// CG_LaunchGib( origin, velocity, cgs.media.gibAbdomen ); - - VectorCopy( playerOrigin, origin ); - velocity[0] = crandom()*GIB_VELOCITY; - velocity[1] = crandom()*GIB_VELOCITY; - velocity[2] = GIB_JUMP + crandom()*GIB_VELOCITY; -// CG_LaunchGib( origin, velocity, cgs.media.gibArm ); - - VectorCopy( playerOrigin, origin ); - velocity[0] = crandom()*GIB_VELOCITY; - velocity[1] = crandom()*GIB_VELOCITY; - velocity[2] = GIB_JUMP + crandom()*GIB_VELOCITY; -// CG_LaunchGib( origin, velocity, cgs.media.gibChest ); - - VectorCopy( playerOrigin, origin ); - velocity[0] = crandom()*GIB_VELOCITY; - velocity[1] = crandom()*GIB_VELOCITY; - velocity[2] = GIB_JUMP + crandom()*GIB_VELOCITY; -// CG_LaunchGib( origin, velocity, cgs.media.gibFist ); - - VectorCopy( playerOrigin, origin ); - velocity[0] = crandom()*GIB_VELOCITY; - velocity[1] = crandom()*GIB_VELOCITY; - velocity[2] = GIB_JUMP + crandom()*GIB_VELOCITY; -// CG_LaunchGib( origin, velocity, cgs.media.gibFoot ); - - VectorCopy( playerOrigin, origin ); - velocity[0] = crandom()*GIB_VELOCITY; - velocity[1] = crandom()*GIB_VELOCITY; - velocity[2] = GIB_JUMP + crandom()*GIB_VELOCITY; -// CG_LaunchGib( origin, velocity, cgs.media.gibForearm ); - - VectorCopy( playerOrigin, origin ); - velocity[0] = crandom()*GIB_VELOCITY; - velocity[1] = crandom()*GIB_VELOCITY; - velocity[2] = GIB_JUMP + crandom()*GIB_VELOCITY; -// CG_LaunchGib( origin, velocity, cgs.media.gibIntestine ); - - VectorCopy( playerOrigin, origin ); - velocity[0] = crandom()*GIB_VELOCITY; - velocity[1] = crandom()*GIB_VELOCITY; - velocity[2] = GIB_JUMP + crandom()*GIB_VELOCITY; -// CG_LaunchGib( origin, velocity, cgs.media.gibLeg ); - - VectorCopy( playerOrigin, origin ); - velocity[0] = crandom()*GIB_VELOCITY; - velocity[1] = crandom()*GIB_VELOCITY; - velocity[2] = GIB_JUMP + crandom()*GIB_VELOCITY; -// CG_LaunchGib( origin, velocity, cgs.media.gibLeg ); -} - -/* -================== -CG_LaunchGib -================== -*/ -void CG_LaunchExplode( vec3_t origin, vec3_t velocity, qhandle_t hModel ) { - localEntity_t *le; - refEntity_t *re; - - le = CG_AllocLocalEntity(); - re = &le->refEntity; - - le->leType = LE_FRAGMENT; - le->startTime = cg.time; - le->endTime = le->startTime + 10000 + random() * 6000; - - VectorCopy( origin, re->origin ); - AxisCopy( axisDefault, re->axis ); - re->hModel = hModel; - - le->pos.trType = TR_GRAVITY; - VectorCopy( origin, le->pos.trBase ); - VectorCopy( velocity, le->pos.trDelta ); - le->pos.trTime = cg.time; - - le->bounceFactor = 0.1f; - - le->leBounceSoundType = LEBS_BRASS; - le->leMarkType = LEMT_NONE; -} - -#define EXP_VELOCITY 100 -#define EXP_JUMP 150 -/* -=================== -CG_GibPlayer - -Generated a bunch of gibs launching out from the bodies location -=================== -*/ -void CG_BigExplode( vec3_t playerOrigin ) { - vec3_t origin, velocity; - - if ( !cg_blood.integer ) { - return; - } - - VectorCopy( playerOrigin, origin ); - velocity[0] = crandom()*EXP_VELOCITY; - velocity[1] = crandom()*EXP_VELOCITY; - velocity[2] = EXP_JUMP + crandom()*EXP_VELOCITY; -// CG_LaunchExplode( origin, velocity, cgs.media.smoke2 ); - - VectorCopy( playerOrigin, origin ); - velocity[0] = crandom()*EXP_VELOCITY; - velocity[1] = crandom()*EXP_VELOCITY; - velocity[2] = EXP_JUMP + crandom()*EXP_VELOCITY; -// CG_LaunchExplode( origin, velocity, cgs.media.smoke2 ); - - VectorCopy( playerOrigin, origin ); - velocity[0] = crandom()*EXP_VELOCITY*1.5; - velocity[1] = crandom()*EXP_VELOCITY*1.5; - velocity[2] = EXP_JUMP + crandom()*EXP_VELOCITY; -// CG_LaunchExplode( origin, velocity, cgs.media.smoke2 ); - - VectorCopy( playerOrigin, origin ); - velocity[0] = crandom()*EXP_VELOCITY*2.0; - velocity[1] = crandom()*EXP_VELOCITY*2.0; - velocity[2] = EXP_JUMP + crandom()*EXP_VELOCITY; -// CG_LaunchExplode( origin, velocity, cgs.media.smoke2 ); - - VectorCopy( playerOrigin, origin ); - velocity[0] = crandom()*EXP_VELOCITY*2.5; - velocity[1] = crandom()*EXP_VELOCITY*2.5; - velocity[2] = EXP_JUMP + crandom()*EXP_VELOCITY; -// CG_LaunchExplode( origin, velocity, cgs.media.smoke2 ); -} - diff --git a/CODE-mp/cgame/cg_ents.c b/CODE-mp/cgame/cg_ents.c index fb23235..d5616fa 100644 --- a/CODE-mp/cgame/cg_ents.c +++ b/CODE-mp/cgame/cg_ents.c @@ -492,6 +492,7 @@ static void CG_General( centity_t *cent ) { int beamID; vec3_t beamOrg; mdxaBone_t matrix; + qboolean doNotSetModel = qfalse; if (cent->currentState.modelGhoul2 == 127) { //not ready to be drawn or initialized.. @@ -512,8 +513,19 @@ static void CG_General( centity_t *cent ) { cent->currentState.modelindex < MAX_CLIENTS && cent->currentState.weapon == G2_MODEL_PART) { //special case for client limbs - centity_t *clEnt = &cg_entities[cent->currentState.modelindex]; + centity_t *clEnt; int dismember_settings = cg_dismember.integer; + + doNotSetModel = qtrue; + + if (cent->currentState.modelindex >= 0) + { + clEnt = &cg_entities[cent->currentState.modelindex]; + } + else + { + clEnt = &cg_entities[cent->currentState.modelindex2]; + } if (!dismember_settings) { //This client does not wish to see dismemberment. @@ -551,9 +563,8 @@ static void CG_General( centity_t *cent ) { cent->bolt4 = -1; cent->trailTime = 0; - switch (cent->currentState.modelGhoul2) + if (cent->currentState.modelGhoul2 == G2_MODELPART_HEAD) { - case G2_MODELPART_HEAD: limbBone = "cervical"; rotateBone = "cranium"; limbName = "head"; @@ -562,8 +573,9 @@ static void CG_General( centity_t *cent ) { limbTagName = "*head_cap_torso"; stubTagName = "*torso_cap_head"; limb_anim = BOTH_DISMEMBER_HEAD1; - break; - case G2_MODELPART_WAIST: + } + else if (cent->currentState.modelGhoul2 == G2_MODELPART_WAIST) + { limbBone = "pelvis"; rotateBone = "thoracic"; limbName = "torso"; @@ -572,8 +584,9 @@ static void CG_General( centity_t *cent ) { limbTagName = "*torso_cap_hips"; stubTagName = "*hips_cap_torso"; limb_anim = BOTH_DISMEMBER_TORSO1; - break; - case G2_MODELPART_LARM: + } + else if (cent->currentState.modelGhoul2 == G2_MODELPART_LARM) + { limbBone = "lhumerus"; rotateBone = "lradius"; limbName = "l_arm"; @@ -582,8 +595,9 @@ static void CG_General( centity_t *cent ) { limbTagName = "*l_arm_cap_torso"; stubTagName = "*torso_cap_l_arm"; limb_anim = BOTH_DISMEMBER_LARM; - break; - case G2_MODELPART_RARM: + } + else if (cent->currentState.modelGhoul2 == G2_MODELPART_RARM) + { limbBone = "rhumerus"; rotateBone = "rradius"; limbName = "r_arm"; @@ -592,8 +606,20 @@ static void CG_General( centity_t *cent ) { limbTagName = "*r_arm_cap_torso"; stubTagName = "*torso_cap_r_arm"; limb_anim = BOTH_DISMEMBER_RARM; - break; - case G2_MODELPART_LLEG: + } + else if (cent->currentState.modelGhoul2 == G2_MODELPART_RHAND) + { + limbBone = "rradiusX"; + rotateBone = "rhand"; + limbName = "r_hand"; + limbCapName = "r_hand_cap_r_arm_off"; + stubCapName = "r_arm_cap_r_hand_off"; + limbTagName = "*r_hand_cap_r_arm"; + stubTagName = "*r_arm_cap_r_hand"; + limb_anim = BOTH_DISMEMBER_RARM; + } + else if (cent->currentState.modelGhoul2 == G2_MODELPART_LLEG) + { limbBone = "lfemurYZ"; rotateBone = "ltibia"; limbName = "l_leg"; @@ -602,8 +628,9 @@ static void CG_General( centity_t *cent ) { limbTagName = "*l_leg_cap_hips"; stubTagName = "*hips_cap_l_leg"; limb_anim = BOTH_DISMEMBER_LLEG; - break; - case G2_MODELPART_RLEG: + } + else if (cent->currentState.modelGhoul2 == G2_MODELPART_RLEG) + { limbBone = "rfemurYZ"; rotateBone = "rtibia"; limbName = "r_leg"; @@ -612,8 +639,9 @@ static void CG_General( centity_t *cent ) { limbTagName = "*r_leg_cap_hips"; stubTagName = "*hips_cap_r_leg"; limb_anim = BOTH_DISMEMBER_RLEG; - break; - default: + } + else + { limbBone = "rfemurYZ"; rotateBone = "rtibia"; limbName = "r_leg"; @@ -622,7 +650,6 @@ static void CG_General( centity_t *cent ) { limbTagName = "*r_leg_cap_hips"; stubTagName = "*hips_cap_r_leg"; limb_anim = BOTH_DISMEMBER_RLEG; - break; } if (clEnt && clEnt->ghoul2) @@ -632,28 +659,35 @@ static void CG_General( centity_t *cent ) { int flags=BONE_ANIM_OVERRIDE_FREEZE; clientInfo_t *ci; - ci = &cgs.clientinfo[ clEnt->currentState.number ]; + if (clEnt->currentState.number < MAX_CLIENTS) + { + ci = &cgs.clientinfo[ clEnt->currentState.number ]; + } + else + { + ci = NULL; + } if (ci) { - /* - if (cent->currentState.modelGhoul2 == G2_MODELPART_WAIST) - { - anim = &ci->animations[ cent->currentState.modelindex2 ]; - } - else - */ - { - anim = &bgGlobalAnimations[ limb_anim ]; - } + //anim = &bgGlobalAnimations[ limb_anim ]; + //I guess it looks better to continue the body anim on the severed limb. If not a bit strange. It's what + //SP seems to do anyway. + anim = &bgGlobalAnimations[ (clEnt->currentState.torsoAnim&~ANIM_TOGGLEBIT) ]; + } + else + { //a g2anim ent, maybe? For those, we can settle for generic limb anims. + anim = &bgGlobalAnimations[ limb_anim ]; } trap_G2API_DuplicateGhoul2Instance(clEnt->ghoul2, ¢->ghoul2); if (anim) { + int aNum; animSpeed = 50.0f / anim->frameLerp; + /* if (cent->currentState.modelGhoul2 == G2_MODELPART_WAIST) { trap_G2API_SetBoneAnim(cent->ghoul2, 0, "upper_lumbar", anim->firstFrame, anim->firstFrame + anim->numFrames, flags, animSpeed, cg.time, -1, 0); @@ -664,6 +698,31 @@ static void CG_General( centity_t *cent ) { trap_G2API_SetBoneAnim(cent->ghoul2, 0, "upper_lumbar", anim->firstFrame + anim->numFrames-1, anim->firstFrame + anim->numFrames, flags, animSpeed, cg.time, -1, 0); trap_G2API_SetBoneAnim(cent->ghoul2, 0, "model_root", anim->firstFrame + anim->numFrames-1, anim->firstFrame + anim->numFrames, flags, animSpeed, cg.time, -1, 0); } + */ + //I guess it looks better to continue the body anim on the severed limb. If not a bit strange. It's what + //SP seems to do anyway. + if (ci) + { + aNum = ci->frame+1; + + while (aNum >= anim->firstFrame+anim->numFrames) + { + aNum--; + } + + if (aNum < anim->firstFrame-1) + { //wrong animation...? + aNum = (anim->firstFrame+anim->numFrames)-1; + } + } + else + { + aNum = anim->firstFrame; + } + + trap_G2API_SetBoneAnim(cent->ghoul2, 0, "upper_lumbar", aNum, anim->firstFrame + anim->numFrames, flags, animSpeed, cg.time, -1, 150); + trap_G2API_SetBoneAnim(cent->ghoul2, 0, "model_root", aNum, anim->firstFrame + anim->numFrames, flags, animSpeed, cg.time, -1, 150); + trap_G2API_SetBoneAnim(cent->ghoul2, 0, "Motion", aNum, anim->firstFrame + anim->numFrames, flags, animSpeed, cg.time, -1, 150); } } @@ -709,7 +768,7 @@ static void CG_General( centity_t *cent ) { trap_FX_PlayEffectID(trap_FX_RegisterEffect("blaster/smoke_bolton"), boltOrg, boltAng); } - if (cent->currentState.modelGhoul2 == G2_MODELPART_RARM || cent->currentState.modelGhoul2 == G2_MODELPART_WAIST) + if (cent->currentState.modelGhoul2 == G2_MODELPART_RARM || cent->currentState.modelGhoul2 == G2_MODELPART_RHAND || cent->currentState.modelGhoul2 == G2_MODELPART_WAIST) { //Cut his weapon holding arm off, so remove the weapon if (trap_G2API_HasGhoul2ModelOnIndex(&(clEnt->ghoul2), 1)) { @@ -989,7 +1048,7 @@ Ghoul2 Insert End VectorCopy( cg.autoAngles, cent->lerpAngles ); AxisCopy( cg.autoAxis, ent.axis ); } - else + else if (!doNotSetModel) { ent.hModel = cgs.gameModels[s1->modelindex]; } @@ -1076,6 +1135,13 @@ Ghoul2 Insert End cent->dustTrailTime = 0; } + if (cent->currentState.modelGhoul2 && + !ent.ghoul2 && + !ent.hModel) + { + return; + } + // add to refresh list trap_R_AddRefEntityToScene (&ent); @@ -2294,10 +2360,16 @@ static void CG_TeamBase( centity_t *cent ) { else { model.hModel = cgs.media.neutralFlagBaseModel; } - trap_R_AddRefEntityToScene( &model ); + + if (cent->currentState.eType != ET_GRAPPLE) + { //do not do this for g2animents + trap_R_AddRefEntityToScene( &model ); + } } } +void CG_G2Animated( centity_t *cent ); + /* =============== CG_AddCEntity @@ -2366,6 +2438,8 @@ Ghoul2 Insert End case ET_SPEAKER: CG_Speaker( cent ); break; + case ET_GRAPPLE: //An entity that wants to be able to use ghoul2 humanoid anims. Like a player, but not. + CG_G2Animated( cent ); case ET_TEAM: CG_TeamBase( cent ); break; diff --git a/CODE-mp/cgame/cg_event.c b/CODE-mp/cgame/cg_event.c index e37406f..052c7fe 100644 --- a/CODE-mp/cgame/cg_event.c +++ b/CODE-mp/cgame/cg_event.c @@ -640,6 +640,10 @@ void CG_ReattachLimb(centity_t *source) limbName = "r_arm"; stubCapName = "torso_cap_r_arm_off"; break; + case G2_MODELPART_RHAND: + limbName = "r_hand"; + stubCapName = "r_arm_cap_r_hand_off"; + break; case G2_MODELPART_LLEG: limbName = "l_leg"; stubCapName = "hips_cap_l_leg_off"; @@ -649,9 +653,9 @@ void CG_ReattachLimb(centity_t *source) stubCapName = "hips_cap_r_leg_off"; break; default: - limbName = "r_leg"; - stubCapName = "hips_cap_r_leg_off"; - break; + source->torsoBolt = 0; + source->ghoul2weapon = NULL; + return; } trap_G2API_SetSurfaceOnOff(source->ghoul2, limbName, 0); @@ -1014,7 +1018,7 @@ void CG_EntityEvent( centity_t *cent, vec3_t position ) { cl_ent->isATST = 0; cl_ent->atstFootClang = 0; cl_ent->atstSwinging = 0; - cl_ent->torsoBolt = 0; +// cl_ent->torsoBolt = 0; cl_ent->bolt1 = 0; cl_ent->bolt2 = 0; cl_ent->bolt3 = 0; @@ -1231,7 +1235,7 @@ void CG_EntityEvent( centity_t *cent, vec3_t position ) { const char *strText = CG_GetStripEdString("INGAMETEXT", "PICKUPLINE"); //Com_Printf("%s %s\n", strText, showPowersName[index]); - CG_CenterPrint( va("%s %s\n", strText, showPowersName[index]), SCREEN_HEIGHT * 0.30, BIGCHAR_WIDTH ); + CG_CenterPrint( va("%s %s\n", strText, CG_GetStripEdString("INGAME",showPowersName[index])), SCREEN_HEIGHT * 0.30, BIGCHAR_WIDTH ); } //Show the player their force selection bar in case picking the holocron up changed the current selection @@ -1340,7 +1344,7 @@ void CG_EntityEvent( centity_t *cent, vec3_t position ) { break; case EV_FIRE_WEAPON: DEBUGNAME("EV_FIRE_WEAPON"); - if (cent->currentState.number >= MAX_CLIENTS) + if (cent->currentState.number >= MAX_CLIENTS && cent->currentState.eType != ET_GRAPPLE) { //special case for turret firing vec3_t gunpoint, gunangle; mdxaBone_t matrix; @@ -1431,7 +1435,23 @@ void CG_EntityEvent( centity_t *cent, vec3_t position ) { case EV_SABER_HIT: DEBUGNAME("EV_SABER_HIT"); - if (es->eventParm) + if (es->eventParm == 16) + { //Make lots of sparks, something special happened + vec3_t fxDir; + VectorCopy(es->angles, fxDir); + if (!fxDir[0] && !fxDir[1] && !fxDir[2]) + { + fxDir[1] = 1; + } + trap_S_StartSound(es->origin, es->number, CHAN_AUTO, trap_S_RegisterSound("sound/weapons/saber/saberhit.wav")); + trap_FX_PlayEffectID( trap_FX_RegisterEffect("saber/blood_sparks.efx"), es->origin, fxDir ); + trap_FX_PlayEffectID( trap_FX_RegisterEffect("saber/blood_sparks.efx"), es->origin, fxDir ); + trap_FX_PlayEffectID( trap_FX_RegisterEffect("saber/blood_sparks.efx"), es->origin, fxDir ); + trap_FX_PlayEffectID( trap_FX_RegisterEffect("saber/blood_sparks.efx"), es->origin, fxDir ); + trap_FX_PlayEffectID( trap_FX_RegisterEffect("saber/blood_sparks.efx"), es->origin, fxDir ); + trap_FX_PlayEffectID( trap_FX_RegisterEffect("saber/blood_sparks.efx"), es->origin, fxDir ); + } + else if (es->eventParm) { //hit a person vec3_t fxDir; VectorCopy(es->angles, fxDir); @@ -1611,6 +1631,13 @@ void CG_EntityEvent( centity_t *cent, vec3_t position ) { break; case PDSOUND_ABSORBHIT: sID = trap_S_RegisterSound("sound/weapons/force/absorbhit.mp3"); + if (es->trickedentindex >= 0 && es->trickedentindex < MAX_CLIENTS) + { + int clnum = es->trickedentindex; + + cg_entities[clnum].teamPowerEffectTime = cg.time + 1000; + cg_entities[clnum].teamPowerType = 3; + } break; case PDSOUND_ABSORB: sID = trap_S_RegisterSound("sound/weapons/force/absorb.mp3"); @@ -2265,7 +2292,7 @@ void CG_EntityEvent( centity_t *cent, vec3_t position ) { case EV_GIB_PLAYER: DEBUGNAME("EV_GIB_PLAYER"); //trap_S_StartSound( NULL, es->number, CHAN_BODY, cgs.media.gibSound ); - CG_GibPlayer( cent->lerpOrigin ); + //CG_GibPlayer( cent->lerpOrigin ); break; case EV_STARTLOOPINGSOUND: diff --git a/CODE-mp/cgame/cg_info.c b/CODE-mp/cgame/cg_info.c index 81ec063..227c51b 100644 --- a/CODE-mp/cgame/cg_info.c +++ b/CODE-mp/cgame/cg_info.c @@ -106,6 +106,7 @@ void CG_DrawInformation( void ) { int value, valueNOFP; qhandle_t levelshot; char buf[1024]; + int iPropHeight = 18; // I know, this is total crap, but as a post release asian-hack.... -Ste info = CG_ConfigString( CS_SERVERINFO ); sysInfo = CG_ConfigString( CS_SYSTEMINFO ); @@ -147,14 +148,15 @@ void CG_DrawInformation( void ) { Q_CleanStr(buf); UI_DrawProportionalString( 320, y, buf, UI_CENTER|UI_INFOFONT|UI_DROPSHADOW, colorWhite ); - y += PROP_HEIGHT; + y += iPropHeight; // pure server s = Info_ValueForKey( sysInfo, "sv_pure" ); if ( s[0] == '1' ) { - UI_DrawProportionalString( 320, y, "Pure Server", + const char *psPure = CG_GetStripEdString("INGAMETEXT", "PURE_SERVER"); + UI_DrawProportionalString( 320, y, psPure, UI_CENTER|UI_INFOFONT|UI_DROPSHADOW, colorWhite ); - y += PROP_HEIGHT; + y += iPropHeight; } // server-specific message of the day @@ -162,7 +164,7 @@ void CG_DrawInformation( void ) { if ( s[0] ) { UI_DrawProportionalString( 320, y, s, UI_CENTER|UI_INFOFONT|UI_DROPSHADOW, colorWhite ); - y += PROP_HEIGHT; + y += iPropHeight; } // some extra space after hostname and motd @@ -174,7 +176,7 @@ void CG_DrawInformation( void ) { if ( s[0] ) { UI_DrawProportionalString( 320, y, s, UI_CENTER|UI_INFOFONT|UI_DROPSHADOW, colorWhite ); - y += PROP_HEIGHT; + y += iPropHeight; } // cheats warning @@ -182,7 +184,7 @@ void CG_DrawInformation( void ) { if ( s[0] == '1' ) { UI_DrawProportionalString( 320, y, CG_GetStripEdString("INGAMETEXT", "CHEATSAREENABLED"), UI_CENTER|UI_INFOFONT|UI_DROPSHADOW, colorWhite ); - y += PROP_HEIGHT; + y += iPropHeight; } // game type @@ -220,13 +222,13 @@ void CG_DrawInformation( void ) { } UI_DrawProportionalString( 320, y, s, UI_CENTER|UI_INFOFONT|UI_DROPSHADOW, colorWhite ); - y += PROP_HEIGHT; + y += iPropHeight; value = atoi( Info_ValueForKey( info, "timelimit" ) ); if ( value ) { UI_DrawProportionalString( 320, y, va( "%s %i", CG_GetStripEdString("INGAMETEXT", "TIMELIMIT"), value ), UI_CENTER|UI_INFOFONT|UI_DROPSHADOW, colorWhite ); - y += PROP_HEIGHT; + y += iPropHeight; } if (cgs.gametype < GT_CTF ) { @@ -234,7 +236,7 @@ void CG_DrawInformation( void ) { if ( value ) { UI_DrawProportionalString( 320, y, va( "%s %i", CG_GetStripEdString("INGAMETEXT", "FRAGLIMIT"), value ), UI_CENTER|UI_INFOFONT|UI_DROPSHADOW, colorWhite ); - y += PROP_HEIGHT; + y += iPropHeight; } if (cgs.gametype == GT_TOURNAMENT) @@ -243,7 +245,7 @@ void CG_DrawInformation( void ) { if ( value ) { UI_DrawProportionalString( 320, y, va( "%s %i", CG_GetStripEdString("INGAMETEXT", "WINLIMIT"), value ), UI_CENTER|UI_INFOFONT|UI_DROPSHADOW, colorWhite ); - y += PROP_HEIGHT; + y += iPropHeight; } } } @@ -253,7 +255,7 @@ void CG_DrawInformation( void ) { if ( value ) { UI_DrawProportionalString( 320, y, va( "%s %i", CG_GetStripEdString("INGAMETEXT", "CAPTURELIMIT"), value ), UI_CENTER|UI_INFOFONT|UI_DROPSHADOW, colorWhite ); - y += PROP_HEIGHT; + y += iPropHeight; } } @@ -263,7 +265,7 @@ void CG_DrawInformation( void ) { if ( value ) { UI_DrawProportionalString( 320, y, CG_GetStripEdString("INGAMETEXT", "FORCEBASEDTEAMS"), UI_CENTER|UI_INFOFONT|UI_DROPSHADOW, colorWhite ); - y += PROP_HEIGHT; + y += iPropHeight; } } @@ -277,7 +279,7 @@ void CG_DrawInformation( void ) { UI_DrawProportionalString( 320, y, va( "%s %s", fmStr, CG_GetStripEdString("INGAMETEXT", forceMasteryLevels[value]) ), UI_CENTER|UI_INFOFONT|UI_DROPSHADOW, colorWhite ); - y += PROP_HEIGHT; + y += iPropHeight; } else if (!valueNOFP) { @@ -286,7 +288,7 @@ void CG_DrawInformation( void ) { UI_DrawProportionalString( 320, y, va( "%s %s", fmStr, (char *)CG_GetStripEdString("INGAMETEXT", forceMasteryLevels[7]) ), UI_CENTER|UI_INFOFONT|UI_DROPSHADOW, colorWhite ); - y += PROP_HEIGHT; + y += iPropHeight; } if (cgs.gametype == GT_TOURNAMENT) @@ -300,75 +302,75 @@ void CG_DrawInformation( void ) { if ( cgs.gametype != GT_JEDIMASTER && value ) { UI_DrawProportionalString( 320, y, va( "%s", (char *)CG_GetStripEdString("INGAMETEXT", "SABERONLYSET") ), UI_CENTER|UI_INFOFONT|UI_DROPSHADOW, colorWhite ); - y += PROP_HEIGHT; + y += iPropHeight; } if ( valueNOFP ) { UI_DrawProportionalString( 320, y, va( "%s", (char *)CG_GetStripEdString("INGAMETEXT", "NOFPSET") ), UI_CENTER|UI_INFOFONT|UI_DROPSHADOW, colorWhite ); - y += PROP_HEIGHT; + y += iPropHeight; } // Display the rules based on type - y += PROP_HEIGHT; + y += iPropHeight; switch ( cgs.gametype ) { case GT_FFA: UI_DrawProportionalString( 320, y, va( "%s", (char *)CG_GetStripEdString("INGAMETEXT", "RULES_FFA_1")), UI_CENTER|UI_INFOFONT|UI_DROPSHADOW, colorWhite ); - y += PROP_HEIGHT; + y += iPropHeight; break; case GT_HOLOCRON: UI_DrawProportionalString( 320, y, va( "%s", (char *)CG_GetStripEdString("INGAMETEXT", "RULES_HOLO_1")), UI_CENTER|UI_INFOFONT|UI_DROPSHADOW, colorWhite ); - y += PROP_HEIGHT; + y += iPropHeight; UI_DrawProportionalString( 320, y, va( "%s", (char *)CG_GetStripEdString("INGAMETEXT", "RULES_HOLO_2")), UI_CENTER|UI_INFOFONT|UI_DROPSHADOW, colorWhite ); - y += PROP_HEIGHT; + y += iPropHeight; break; case GT_JEDIMASTER: UI_DrawProportionalString( 320, y, va( "%s", (char *)CG_GetStripEdString("INGAMETEXT", "RULES_JEDI_1")), UI_CENTER|UI_INFOFONT|UI_DROPSHADOW, colorWhite ); - y += PROP_HEIGHT; + y += iPropHeight; UI_DrawProportionalString( 320, y, va( "%s", (char *)CG_GetStripEdString("INGAMETEXT", "RULES_JEDI_2")), UI_CENTER|UI_INFOFONT|UI_DROPSHADOW, colorWhite ); - y += PROP_HEIGHT; + y += iPropHeight; break; case GT_SINGLE_PLAYER: break; case GT_TOURNAMENT: UI_DrawProportionalString( 320, y, va( "%s", (char *)CG_GetStripEdString("INGAMETEXT", "RULES_DUEL_1")), UI_CENTER|UI_INFOFONT|UI_DROPSHADOW, colorWhite ); - y += PROP_HEIGHT; + y += iPropHeight; UI_DrawProportionalString( 320, y, va( "%s", (char *)CG_GetStripEdString("INGAMETEXT", "RULES_DUEL_2")), UI_CENTER|UI_INFOFONT|UI_DROPSHADOW, colorWhite ); - y += PROP_HEIGHT; + y += iPropHeight; break; case GT_TEAM: UI_DrawProportionalString( 320, y, va( "%s", (char *)CG_GetStripEdString("INGAMETEXT", "RULES_TEAM_1")), UI_CENTER|UI_INFOFONT|UI_DROPSHADOW, colorWhite ); - y += PROP_HEIGHT; + y += iPropHeight; UI_DrawProportionalString( 320, y, va( "%s", (char *)CG_GetStripEdString("INGAMETEXT", "RULES_TEAM_2")), UI_CENTER|UI_INFOFONT|UI_DROPSHADOW, colorWhite ); - y += PROP_HEIGHT; + y += iPropHeight; break; case GT_SAGA: break; case GT_CTF: UI_DrawProportionalString( 320, y, va( "%s", (char *)CG_GetStripEdString("INGAMETEXT", "RULES_CTF_1")), UI_CENTER|UI_INFOFONT|UI_DROPSHADOW, colorWhite ); - y += PROP_HEIGHT; + y += iPropHeight; UI_DrawProportionalString( 320, y, va( "%s", (char *)CG_GetStripEdString("INGAMETEXT", "RULES_CTF_2")), UI_CENTER|UI_INFOFONT|UI_DROPSHADOW, colorWhite ); - y += PROP_HEIGHT; + y += iPropHeight; break; case GT_CTY: UI_DrawProportionalString( 320, y, va( "%s", (char *)CG_GetStripEdString("INGAMETEXT", "RULES_CTY_1")), UI_CENTER|UI_INFOFONT|UI_DROPSHADOW, colorWhite ); - y += PROP_HEIGHT; + y += iPropHeight; UI_DrawProportionalString( 320, y, va( "%s", (char *)CG_GetStripEdString("INGAMETEXT", "RULES_CTY_2")), UI_CENTER|UI_INFOFONT|UI_DROPSHADOW, colorWhite ); - y += PROP_HEIGHT; + y += iPropHeight; break; default: break; diff --git a/CODE-mp/cgame/cg_local.h b/CODE-mp/cgame/cg_local.h index c06e173..8b9b4f1 100644 --- a/CODE-mp/cgame/cg_local.h +++ b/CODE-mp/cgame/cg_local.h @@ -76,9 +76,8 @@ #define TEAM_OVERLAY_MAXNAME_WIDTH 12 #define TEAM_OVERLAY_MAXLOCATION_WIDTH 16 -#define DEFAULT_MODEL "kyle/default" -#define DEFAULT_TEAM_MODEL "kyle/default" -#define DEFAULT_TEAM_HEAD "kyle/default" +#define DEFAULT_MODEL "kyle" +#define DEFAULT_TEAM_MODEL "kyle" #define DEFAULT_FORCEPOWERS "5-1-000000000000000000" //"rank-side-heal.lev.speed.push.pull.tele.grip.lightning.rage.protect.absorb.teamheal.teamforce.drain.see" @@ -236,7 +235,7 @@ typedef struct centity_s { int trickAlphaTime; int teamPowerEffectTime; - qboolean teamPowerType; //0 regen, 1 heal, 2 drain + qboolean teamPowerType; //0 regen, 1 heal, 2 drain, 3 absorb } centity_t; @@ -957,9 +956,9 @@ typedef struct { qhandle_t teamRedShader; qhandle_t teamBlueShader; + qhandle_t balloonShader; qhandle_t connectionShader; - qhandle_t selectShader; qhandle_t viewBloodShader; qhandle_t tracerShader; qhandle_t crosshairShader[NUM_CROSSHAIRS]; @@ -968,9 +967,6 @@ typedef struct { qhandle_t noammoShader; qhandle_t smokePuffShader; - qhandle_t smokePuffRageProShader; - qhandle_t shotgunSmokePuffShader; - qhandle_t plasmaBallShader; qhandle_t waterBubbleShader; qhandle_t bloodTrailShader; @@ -1414,7 +1410,6 @@ extern vmCvar_t cg_bobpitch; extern vmCvar_t cg_bobroll; //extern vmCvar_t cg_swingSpeed; extern vmCvar_t cg_shadows; -extern vmCvar_t cg_gibs; extern vmCvar_t cg_drawTimer; extern vmCvar_t cg_drawFPS; extern vmCvar_t cg_drawSnapshot; @@ -1461,9 +1456,15 @@ extern vmCvar_t cg_zoomFov; extern vmCvar_t cg_swingAngles; +#ifdef G2_COLLISION_ENABLED +extern vmCvar_t cg_saberModelTraceEffect; +#endif + extern vmCvar_t cg_saberContact; extern vmCvar_t cg_saberTrail; +extern vmCvar_t cg_duelHeadAngles; + extern vmCvar_t cg_speedTrail; extern vmCvar_t cg_auraShell; @@ -1789,9 +1790,6 @@ void CG_GlassShatter(int entnum, vec3_t dmgPt, vec3_t dmgDir, float dmgRadius, i void CG_CreateDebris(int entnum, vec3_t org, vec3_t mins, vec3_t maxs, int debrissound, int debrismodel); void CG_ScorePlum( int client, vec3_t org, int score ); -void CG_GibPlayer( vec3_t playerOrigin ); -void CG_BigExplode( vec3_t playerOrigin ); - void CG_Bleed( vec3_t origin, int entityNum ); localEntity_t *CG_MakeExplosion( vec3_t origin, vec3_t dir, @@ -1964,7 +1962,9 @@ int trap_R_Font_StrLenPixels(const char *text, const int iFontIndex, const flo int trap_R_Font_StrLenChars(const char *text); int trap_R_Font_HeightPixels(const int iFontIndex, const float scale); void trap_R_Font_DrawString(int ox, int oy, const char *text, const float *rgba, const int setIndex, int iCharLimit, const float scale); -unsigned trap_AnyLanguage_ReadCharFromString( const char **ppText ); +qboolean trap_Language_IsAsian(void); +qboolean trap_Language_UsesSpaces(void); +unsigned trap_AnyLanguage_ReadCharFromString( const char *psText, int *piAdvanceCount, qboolean *pbIsTrailingPunctuation/* = NULL*/ ); // a scene is built up by calls to R_ClearScene and the various R_Add functions. @@ -2171,6 +2171,8 @@ void FX_BlasterWeaponHitWall( vec3_t origin, vec3_t normal ); void FX_BlasterWeaponHitPlayer( vec3_t origin, vec3_t normal, qboolean humanoid ); +void trap_G2API_CollisionDetect ( CollisionRecord_t *collRecMap, void* ghoul2, const vec3_t angles, const vec3_t position,int frameNumber, int entNum, const vec3_t rayStart, const vec3_t rayEnd, const vec3_t scale, int traceFlags, int useLod, float fRadius ); + /* Ghoul2 Insert Start @@ -2184,6 +2186,8 @@ qboolean trap_G2API_GetBoltMatrix(void *ghoul2, const int modelIndex, const int const vec3_t angles, const vec3_t position, const int frameNum, qhandle_t *modelList, vec3_t scale); qboolean trap_G2API_GetBoltMatrix_NoReconstruct(void *ghoul2, const int modelIndex, const int boltIndex, mdxaBone_t *matrix, const vec3_t angles, const vec3_t position, const int frameNum, qhandle_t *modelList, vec3_t scale); +qboolean trap_G2API_GetBoltMatrix_NoRecNoRot(void *ghoul2, const int modelIndex, const int boltIndex, mdxaBone_t *matrix, + const vec3_t angles, const vec3_t position, const int frameNum, qhandle_t *modelList, vec3_t scale); int trap_G2API_InitGhoul2Model(void **ghoul2Ptr, const char *fileName, int modelIndex, qhandle_t customSkin, qhandle_t customShader, int modelFlags, int lodBias); diff --git a/CODE-mp/cgame/cg_main.c b/CODE-mp/cgame/cg_main.c index 56c70fe..2de895b 100644 --- a/CODE-mp/cgame/cg_main.c +++ b/CODE-mp/cgame/cg_main.c @@ -365,7 +365,6 @@ vmCvar_t cg_bobpitch; vmCvar_t cg_bobroll; //vmCvar_t cg_swingSpeed; vmCvar_t cg_shadows; -vmCvar_t cg_gibs; vmCvar_t cg_drawTimer; vmCvar_t cg_drawFPS; vmCvar_t cg_drawSnapshot; @@ -411,9 +410,15 @@ vmCvar_t cg_zoomFov; vmCvar_t cg_swingAngles; +#ifdef G2_COLLISION_ENABLED +vmCvar_t cg_saberModelTraceEffect; +#endif + vmCvar_t cg_saberContact; vmCvar_t cg_saberTrail; +vmCvar_t cg_duelHeadAngles; + vmCvar_t cg_speedTrail; vmCvar_t cg_auraShell; @@ -505,7 +510,6 @@ static cvarTable_t cvarTable[] = { // bk001129 { &cg_viewsize, "cg_viewsize", "100", CVAR_ARCHIVE }, { &cg_stereoSeparation, "cg_stereoSeparation", "0.4", CVAR_ARCHIVE }, { &cg_shadows, "cg_shadows", "1", CVAR_ARCHIVE }, - { &cg_gibs, "cg_gibs", "1", CVAR_ARCHIVE }, { &cg_draw2D, "cg_draw2D", "1", CVAR_ARCHIVE }, { &cg_drawStatus, "cg_drawStatus", "1", CVAR_ARCHIVE }, { &cg_drawTimer, "cg_drawTimer", "0", CVAR_ARCHIVE }, @@ -553,15 +557,21 @@ static cvarTable_t cvarTable[] = { // bk001129 { &cg_swingAngles, "cg_swingAngles", "1", 0 }, +#ifdef G2_COLLISION_ENABLED + { &cg_saberModelTraceEffect, "cg_saberModelTraceEffect", "0", 0 }, +#endif + { &cg_saberContact, "cg_saberContact", "1", 0 }, { &cg_saberTrail, "cg_saberTrail", "1", 0 }, + { &cg_duelHeadAngles, "cg_duelHeadAngles", "0", 0 }, + { &cg_speedTrail, "cg_speedTrail", "1", 0 }, { &cg_auraShell, "cg_auraShell", "1", 0 }, { &cg_animBlend, "cg_animBlend", "1", 0 }, - { &cg_dismember, "cg_dismember", "0", 0 }, + { &cg_dismember, "cg_dismember", "0", CVAR_ARCHIVE }, { &cg_thirdPerson, "cg_thirdPerson", "0", 0 }, { &cg_thirdPersonRange, "cg_thirdPersonRange", "80", CVAR_CHEAT }, @@ -1267,22 +1277,20 @@ static void CG_RegisterGraphics( void ) { cgs.media.chunkyNumberShaders[i] = trap_R_RegisterShaderNoMip( sb_c_nums[i] ); } + cgs.media.balloonShader = trap_R_RegisterShader( "gfx/mp/chat_icon" ); + cgs.media.viewBloodShader = trap_R_RegisterShader( "viewBloodBlend" ); cgs.media.deferShader = trap_R_RegisterShaderNoMip( "gfx/2d/defer.tga" ); cgs.media.smokePuffShader = trap_R_RegisterShader( "smokePuff" ); - cgs.media.smokePuffRageProShader = trap_R_RegisterShader( "smokePuffRagePro" ); - cgs.media.shotgunSmokePuffShader = trap_R_RegisterShader( "shotgunSmokePuff" ); - cgs.media.plasmaBallShader = trap_R_RegisterShader( "sprites/plasma1" ); cgs.media.bloodTrailShader = trap_R_RegisterShader( "bloodTrail" ); - cgs.media.lagometerShader = trap_R_RegisterShader("gfx/2d/lag" ); - cgs.media.connectionShader = trap_R_RegisterShader( "disconnected" ); + cgs.media.lagometerShader = trap_R_RegisterShaderNoMip("gfx/2d/lag" ); + cgs.media.connectionShader = trap_R_RegisterShaderNoMip( "gfx/2d/net" ); cgs.media.waterBubbleShader = trap_R_RegisterShader( "waterBubble" ); cgs.media.tracerShader = trap_R_RegisterShader( "gfx/misc/tracer" ); - cgs.media.selectShader = trap_R_RegisterShader( "gfx/2d/select" ); Com_Printf( S_COLOR_CYAN "---------- Fx System Initialization ---------\n" ); trap_FX_InitSystem(); @@ -2005,14 +2013,15 @@ static clientInfo_t * CG_InfoFromScoreIndex(int index, int team, int *scoreIndex return &cgs.clientinfo[ cg.scores[index].client ]; } -static const char *CG_FeederItemText(float feederID, int index, int column, qhandle_t *handle) { +static const char *CG_FeederItemText(float feederID, int index, int column, + qhandle_t *handle1, qhandle_t *handle2, qhandle_t *handle3) { gitem_t *item; int scoreIndex = 0; clientInfo_t *info = NULL; int team = -1; score_t *sp = NULL; - *handle = -1; + *handle1 = *handle2 = *handle3 = -1; if (feederID == FEEDER_REDTEAM_LIST) { team = TEAM_RED; @@ -2028,17 +2037,17 @@ static const char *CG_FeederItemText(float feederID, int index, int column, qhan case 0: if ( info->powerups & ( 1 << PW_NEUTRALFLAG ) ) { item = BG_FindItemForPowerup( PW_NEUTRALFLAG ); - *handle = cg_items[ ITEM_INDEX(item) ].icon; + *handle1 = cg_items[ ITEM_INDEX(item) ].icon; } else if ( info->powerups & ( 1 << PW_REDFLAG ) ) { item = BG_FindItemForPowerup( PW_REDFLAG ); - *handle = cg_items[ ITEM_INDEX(item) ].icon; + *handle1 = cg_items[ ITEM_INDEX(item) ].icon; } else if ( info->powerups & ( 1 << PW_BLUEFLAG ) ) { item = BG_FindItemForPowerup( PW_BLUEFLAG ); - *handle = cg_items[ ITEM_INDEX(item) ].icon; + *handle1 = cg_items[ ITEM_INDEX(item) ].icon; } else { /* if ( info->botSkill > 0 && info->botSkill <= 5 ) { - *handle = cgs.media.botSkillShaders[ info->botSkill - 1 ]; + *handle1 = cgs.media.botSkillShaders[ info->botSkill - 1 ]; } else if ( info->handicap < 100 ) { return va("%i", info->handicap ); } @@ -2049,7 +2058,7 @@ static const char *CG_FeederItemText(float feederID, int index, int column, qhan if (team == -1) { return ""; } else { - *handle = CG_StatusHandle(info->teamTask); + *handle1 = CG_StatusHandle(info->teamTask); } break; case 2: @@ -2194,6 +2203,8 @@ void CG_LoadHudMenu() cgDC.Font_StrLenChars = &trap_R_Font_StrLenChars; cgDC.Font_HeightPixels = &trap_R_Font_HeightPixels; cgDC.Font_DrawString = &trap_R_Font_DrawString; + cgDC.Language_IsAsian = &trap_Language_IsAsian; + cgDC.Language_UsesSpaces = &trap_Language_UsesSpaces; cgDC.AnyLanguage_ReadCharFromString = &trap_AnyLanguage_ReadCharFromString; cgDC.ownerDrawItem = &CG_OwnerDraw; cgDC.getValue = &CG_GetValue; diff --git a/CODE-mp/cgame/cg_newDraw.c b/CODE-mp/cgame/cg_newDraw.c index baaf620..16ea811 100644 --- a/CODE-mp/cgame/cg_newDraw.c +++ b/CODE-mp/cgame/cg_newDraw.c @@ -379,6 +379,8 @@ extern int MenuFontToHandle(int iMenuFont); // static void CG_Text_Paint_Limit(float *maxX, float x, float y, float scale, vec4_t color, const char* text, float adjust, int limit, int iMenuFont) { + qboolean bIsTrailingPunctuation; + // this is kinda dirty, but... // int iFontIndex = MenuFontToHandle(iMenuFont); @@ -400,9 +402,12 @@ static void CG_Text_Paint_Limit(float *maxX, float x, float y, float scale, vec4 && psOut < &sTemp[sizeof(sTemp)-1] // sanity ) { - psOutLastGood = psOut; - - uiLetter = trap_AnyLanguage_ReadCharFromString(&psText); + int iAdvanceCount; + psOutLastGood = psOut; + + uiLetter = trap_AnyLanguage_ReadCharFromString(psText, &iAdvanceCount, &bIsTrailingPunctuation); + psText += iAdvanceCount; + if (uiLetter > 255) { *psOut++ = uiLetter>>8; @@ -967,7 +972,7 @@ void CG_KeyEvent(int key, qboolean down) { if (cgs.capturedItem) { cgs.capturedItem = NULL; } else { - if (key == K_MOUSE2 && down) { + if (key == A_MOUSE2 && down) { cgs.capturedItem = Display_CaptureItem(cgs.cursorX, cgs.cursorY); } } diff --git a/CODE-mp/cgame/cg_players.c b/CODE-mp/cgame/cg_players.c index 43b259a..e8b6660 100644 --- a/CODE-mp/cgame/cg_players.c +++ b/CODE-mp/cgame/cg_players.c @@ -98,6 +98,128 @@ qboolean CG_NeedAnimSequence(int anim) return qfalse; } +//To see if the client is trying to use one of the included skins not meant for MP. +//I don't much care for hardcoded strings, but this seems the best way to go. +static qboolean CG_IsValidCharacterModel(const char *modelName, const char *skinName) +{ + if (!Q_stricmp(modelName, "kyle")) + { + if (!Q_stricmp(skinName, "fpls")) + { + return qfalse; + } + else if (!Q_stricmp(skinName, "fpls2")) + { + return qfalse; + } + else if (!Q_stricmp(skinName, "fpls3")) + { + return qfalse; + } + } + else if (!Q_stricmp(modelName, "morgan")) + { + //For morgan, we want to deny if the skin is anything but one of the valid ones + //Since his default skin is actually the bad one, you could just type + //"model morgan/blah" and get it. This rules out custom morgan skins without + //programming assistance unfortunately. + if (Q_stricmp(skinName, "default_mp") && + Q_stricmp(skinName, "red") && + Q_stricmp(skinName, "blue")) + { + return qfalse; + } + } + + return qtrue; +} + +#define MAX_SURF_LIST_SIZE 1024 +qboolean CG_ParseSurfsFile( const char *modelName, const char *skinName, char *surfOff, char *surfOn ) +{ + const char *text_p; + int len; + const char *token; + const char *value; + char text[20000]; + char sfilename[MAX_QPATH]; + fileHandle_t f; + + // Load and parse .surf file + Com_sprintf( sfilename, sizeof( sfilename ), "models/players/%s/model_%s.surf", modelName, skinName ); + + // load the file + len = trap_FS_FOpenFile( sfilename, &f, FS_READ ); + if ( len <= 0 ) + {//no file + return qfalse; + } + if ( len >= sizeof( text ) - 1 ) + { + Com_Printf( "File %s too long\n", sfilename ); + return qfalse; + } + + trap_FS_Read( text, len, f ); + text[len] = 0; + trap_FS_FCloseFile( f ); + + // parse the text + text_p = text; + + memset( (char *)surfOff, 0, sizeof(surfOff) ); + memset( (char *)surfOn, 0, sizeof(surfOn) ); + + // read information for surfOff and surfOn + while ( 1 ) + { + token = COM_ParseExt( &text_p, qtrue ); + if ( !token || !token[0] ) + { + break; + } + + // surfOff + if ( !Q_stricmp( token, "surfOff" ) ) + { + if ( COM_ParseString( &text_p, &value ) ) + { + continue; + } + if ( surfOff && surfOff[0] ) + { + Q_strcat( surfOff, MAX_SURF_LIST_SIZE, "," ); + Q_strcat( surfOff, MAX_SURF_LIST_SIZE, value ); + } + else + { + Q_strncpyz( surfOff, value, MAX_SURF_LIST_SIZE ); + } + continue; + } + + // surfOn + if ( !Q_stricmp( token, "surfOn" ) ) + { + if ( COM_ParseString( &text_p, &value ) ) + { + continue; + } + if ( surfOn && surfOn[0] ) + { + Q_strcat( surfOn, MAX_SURF_LIST_SIZE, ","); + Q_strcat( surfOn, MAX_SURF_LIST_SIZE, value ); + } + else + { + Q_strncpyz( surfOn, value, MAX_SURF_LIST_SIZE ); + } + continue; + } + } + return qtrue; +} + /* ========================== CG_RegisterClientModelname @@ -111,6 +233,9 @@ static qboolean CG_RegisterClientModelname( clientInfo_t *ci, const char *modelN vec3_t tempVec = {0,0,0}; qboolean badModel = qfalse; qboolean retriedAlready = qfalse; + char surfOff[MAX_SURF_LIST_SIZE]; + char surfOn[MAX_SURF_LIST_SIZE]; + retryModel: if (ci->ATST && clientNum == -1) { @@ -128,6 +253,12 @@ retryModel: retriedAlready = qtrue; } + if (!CG_IsValidCharacterModel(modelName, skinName)) + { + modelName = "kyle"; + skinName = "default"; + } + // First things first. If this is a ghoul2 model, then let's make sure we demolish this first. if (ci->ghoul2Model && trap_G2_HaveWeGhoul2Models(ci->ghoul2Model)) { @@ -138,48 +269,50 @@ retryModel: { if (ci->team == TEAM_RED) { - Com_sprintf(ci->skinName, sizeof(ci->skinName), "red"); + Q_strncpyz(ci->skinName, "red", sizeof(ci->skinName)); skinName = "red"; } else if (ci->team == TEAM_BLUE) { - Com_sprintf(ci->skinName, sizeof(ci->skinName), "blue"); + Q_strncpyz(ci->skinName, "blue", sizeof(ci->skinName)); skinName = "blue"; } } if (clientNum != -1 && cg_entities[clientNum].currentState.teamowner && !cg_entities[clientNum].isATST) { + ci->torsoSkin = 0; + ci->ATST = qtrue; handle = trap_G2API_InitGhoul2Model(&ci->ghoul2Model, "models/players/atst/model.glm", 0, 0, 0, 0, 0); } else { + ci->torsoSkin = trap_R_RegisterSkin(va("models/players/%s/model_%s.skin", modelName, skinName)); + ci->ATST = qfalse; Com_sprintf( afilename, sizeof( afilename ), "models/players/%s/model.glm", modelName ); - handle = trap_G2API_InitGhoul2Model(&ci->ghoul2Model, afilename, 0, trap_R_RegisterSkin(va("models/players/%s/model_%s.skin", modelName, skinName)), 0, 0, 0); + handle = trap_G2API_InitGhoul2Model(&ci->ghoul2Model, afilename, 0, ci->torsoSkin, 0, 0, 0); } if (handle<0) { return qfalse; } - if (clientNum != -1 && cg_entities[clientNum].currentState.teamowner && !cg_entities[clientNum].isATST) - { - ci->torsoSkin = 0; - ci->ATST = qtrue; - } - else - { - ci->torsoSkin = trap_R_RegisterSkin(va("models/players/%s/model_%s.skin", modelName, skinName)); - ci->ATST = qfalse; - } - // The model is now loaded. GLAName[0] = 0; + trap_G2API_GetGLAName( ci->ghoul2Model, 0, GLAName); + if (GLAName[0] != 0) + { + if (!strstr(GLAName, "players/_humanoid/")) + { //Bad! + badModel = qtrue; + goto retryModel; + } + } + if (!BGPAFtextLoaded) { - trap_G2API_GetGLAName( ci->ghoul2Model, 0, GLAName); if (GLAName[0] == 0/*GLAName == NULL*/) { if (!BG_ParseAnimationFile("models/players/_humanoid/animation.cfg")) @@ -239,6 +372,42 @@ retryModel: } } + if ( CG_ParseSurfsFile( modelName, skinName, surfOff, surfOn ) ) + {//turn on/off any surfs + const char *token; + const char *p; + + //Now turn on/off any surfaces + if ( surfOff && surfOff[0] ) + { + p = surfOff; + while ( 1 ) + { + token = COM_ParseExt( &p, qtrue ); + if ( !token[0] ) + {//reached end of list + break; + } + //turn off this surf + trap_G2API_SetSurfaceOnOff( ci->ghoul2Model, token, 0x00000002/*G2SURFACEFLAG_OFF*/ ); + } + } + if ( surfOn && surfOn[0] ) + { + p = surfOn; + while ( 1 ) + { + token = COM_ParseExt( &p, qtrue ); + if ( !token[0] ) + {//reached end of list + break; + } + //turn on this surf + trap_G2API_SetSurfaceOnOff( ci->ghoul2Model, token, 0 ); + } + } + } + if (clientNum != -1 && cg_entities[clientNum].currentState.teamowner && !cg_entities[clientNum].isATST) { ci->torsoSkin = 0; @@ -329,7 +498,7 @@ retryModel: } //rww - Set the animation again because it just got reset due to the model change - trap_G2API_SetBoneAnim(ci->ghoul2Model, 0, "upper_lumbar", anim->firstFrame + anim->numFrames-1, anim->firstFrame + anim->numFrames, flags, 1.0f, cg.time, -1, 150); + trap_G2API_SetBoneAnim(ci->ghoul2Model, 0, "lower_lumbar", anim->firstFrame + anim->numFrames-1, anim->firstFrame + anim->numFrames, flags, 1.0f, cg.time, -1, 150); cg_entities[clientNum].currentState.torsoAnim = 0; } @@ -346,7 +515,7 @@ retryModel: cg_entities[clientNum].ghoul2weapon = NULL; } - Com_sprintf(ci->teamName, sizeof(ci->teamName), teamName); + Q_strncpyz (ci->teamName, teamName, sizeof(ci->teamName)); // Model icon for drawing the portrait on screen ci->modelIcon = trap_R_RegisterShaderNoMip ( va ( "models/players/%s/icon_%s", modelName, skinName ) ); @@ -634,7 +803,7 @@ static void CG_CopyClientInfoModel( clientInfo_t *from, clientInfo_t *to ) { CG_ScanForExistingClientInfo ====================== */ -static qboolean CG_ScanForExistingClientInfo( clientInfo_t *ci ) { +static qboolean CG_ScanForExistingClientInfo( clientInfo_t *ci, int clientNum ) { int i; clientInfo_t *match; @@ -660,7 +829,49 @@ static qboolean CG_ScanForExistingClientInfo( clientInfo_t *ci ) { ci->deferred = qfalse; - CG_CopyClientInfoModel( match, ci ); + //rww - Filthy hack. If this is actually the info already belonging to us, just reassign the pointer. + //Switching instances when not necessary produces small animation glitches. + //Actually, before, were we even freeing the instance attached to the old clientinfo before copying + //this new clientinfo over it? Could be a nasty leak possibility. (though this should remedy it in theory) + if (clientNum == i) + { + if (match->ghoul2Model && trap_G2_HaveWeGhoul2Models(match->ghoul2Model)) + { //The match has a valid instance (if it didn't, we'd probably already be fudged (^_^) at this state) + if (ci->ghoul2Model && trap_G2_HaveWeGhoul2Models(ci->ghoul2Model)) + { //First kill the copy we have if we have one. (but it should be null) + trap_G2API_CleanGhoul2Models(&ci->ghoul2Model); + } + + VectorCopy( match->headOffset, ci->headOffset ); + ci->footsteps = match->footsteps; + ci->gender = match->gender; + + ci->legsModel = match->legsModel; + ci->legsSkin = match->legsSkin; + ci->torsoModel = match->torsoModel; + ci->torsoSkin = match->torsoSkin; + ci->modelIcon = match->modelIcon; + + ci->newAnims = match->newAnims; + + ci->bolt_head = match->bolt_head; + ci->bolt_lhand = match->bolt_lhand; + ci->bolt_rhand = match->bolt_rhand; + ci->bolt_motion = match->bolt_motion; + ci->bolt_llumbar = match->bolt_llumbar; + + memcpy( ci->sounds, match->sounds, sizeof( ci->sounds ) ); + + //We can share this pointer, because it already belongs to this client. + //The pointer itself and the ghoul2 instance is never actually changed, just passed between + //clientinfo structures. + ci->ghoul2Model = match->ghoul2Model; + } + } + else + { + CG_CopyClientInfoModel( match, ci ); + } return qtrue; } @@ -934,7 +1145,7 @@ void CG_NewClientInfo( int clientNum, qboolean entitiesInitialized ) { // scan for an existing clientinfo that matches this modelname // so we can avoid loading checks if possible - if ( !CG_ScanForExistingClientInfo( &newInfo ) ) { + if ( !CG_ScanForExistingClientInfo( &newInfo, clientNum ) ) { qboolean forceDefer; forceDefer = trap_MemoryRemaining() < 4000000; @@ -959,6 +1170,13 @@ void CG_NewClientInfo( int clientNum, qboolean entitiesInitialized ) { // replace whatever was there with the new one newInfo.infoValid = qtrue; + if (ci->ghoul2Model && + ci->ghoul2Model != newInfo.ghoul2Model && + trap_G2_HaveWeGhoul2Models(ci->ghoul2Model)) + { //We must kill this instance before we remove our only pointer to it from the cgame. + //Otherwise we will end up with extra instances all over the place, I think. + trap_G2API_CleanGhoul2Models(&ci->ghoul2Model); + } *ci = newInfo; //force a weapon change anyway, for all clients being rendered to the current client @@ -1007,7 +1225,7 @@ void CG_NewClientInfo( int clientNum, qboolean entitiesInitialized ) { } //rww - Set the animation again because it just got reset due to the model change - trap_G2API_SetBoneAnim(ci->ghoul2Model, 0, "upper_lumbar", anim->firstFrame + anim->numFrames-1, anim->firstFrame + anim->numFrames, flags, 1.0f, cg.time, -1, 150); + trap_G2API_SetBoneAnim(ci->ghoul2Model, 0, "lower_lumbar", anim->firstFrame + anim->numFrames-1, anim->firstFrame + anim->numFrames, flags, 1.0f, cg.time, -1, 150); cg_entities[clientNum].currentState.torsoAnim = 0; } @@ -1089,7 +1307,7 @@ PLAYER ANIMATION ============================================================================= */ -static qboolean CG_FirstAnimFrame(clientInfo_t *ci, lerpFrame_t *lf, qboolean torsoOnly, float speedScale); +static qboolean CG_FirstAnimFrame(lerpFrame_t *lf, qboolean torsoOnly, float speedScale); qboolean CG_InRoll( centity_t *cent ) { @@ -1269,18 +1487,6 @@ static void CG_SetLerpFrameAnimation( centity_t *cent, clientInfo_t *ci, lerpFra { return; } - -// if (lf->animationNumber != BOTH_STAND1 && -// ((lf->frame-lf->animation->firstFrame) < (lf->animation->numFrames/2)-8 || -// (lf->frame-lf->animation->firstFrame) > (lf->animation->numFrames/2)+8)) -// { -// return; -// } - // if (lf->animationNumber != BOTH_STAND1 && - // !CG_FirstAnimFrame(ci, lf, torsoOnly, animSpeedMult)) - // { - // return; - // } } oldAnim = lf->animationNumber; @@ -1297,8 +1503,8 @@ static void CG_SetLerpFrameAnimation( centity_t *cent, clientInfo_t *ci, lerpFra lf->animation = anim; lf->animationTime = lf->frameTime + anim->initialLerp; - if ( cg_debugAnim.integer ) { - CG_Printf( "Anim: %i, '%s'\n", newAnimation, GetStringForID(animTable, newAnimation)); + if ( cg_debugAnim.integer && (cg_debugAnim.integer < 0 || cg_debugAnim.integer == cent->currentState.clientNum) ) { + CG_Printf( "%d: %d Anim: %i, '%s'\n", cg.time, cent->currentState.clientNum, newAnimation, GetStringForID(animTable, newAnimation)); } if (cent->ghoul2) @@ -1360,6 +1566,8 @@ static void CG_SetLerpFrameAnimation( centity_t *cent, clientInfo_t *ci, lerpFra animSpeed *= animSpeedMult; + BG_SaberStartTransAnim(cent->currentState.fireflag, newAnimation, &animSpeed); + if (torsoOnly) { lf->animationTorsoSpeed = animSpeedMult; @@ -1384,42 +1592,35 @@ static void CG_SetLerpFrameAnimation( centity_t *cent, clientInfo_t *ci, lerpFra } else { + int beginFrame = anim->firstFrame; + if (torsoOnly) { - trap_G2API_SetBoneAnim(cent->ghoul2, 0, "upper_lumbar", anim->firstFrame, anim->firstFrame + anim->numFrames, flags, animSpeed,cg.time, -1, blendTime); + if ((cent->currentState.torsoAnim&~ANIM_TOGGLEBIT) == (cent->currentState.legsAnim&~ANIM_TOGGLEBIT) && cent->pe.legs.frame >= anim->firstFrame && cent->pe.legs.frame <= (anim->firstFrame + anim->numFrames)) + { + trap_G2API_SetBoneAnim(cent->ghoul2, 0, "lower_lumbar", anim->firstFrame, anim->firstFrame + anim->numFrames, flags, animSpeed,cg.time, cent->pe.legs.frame, blendTime); + beginFrame = cent->pe.legs.frame; + } + else + { + trap_G2API_SetBoneAnim(cent->ghoul2, 0, "lower_lumbar", anim->firstFrame, anim->firstFrame + anim->numFrames, flags, animSpeed,cg.time, -1, blendTime); + } cgs.clientinfo[cent->currentState.number].torsoAnim = newAnimation; } else { trap_G2API_SetBoneAnim(cent->ghoul2, 0, "model_root", anim->firstFrame, anim->firstFrame + anim->numFrames, flags, animSpeed, cg.time, -1, blendTime); - cgs.clientinfo[cent->currentState.number].torsoAnim = newAnimation; + //cgs.clientinfo[cent->currentState.number].torsoAnim = newAnimation; cgs.clientinfo[cent->currentState.number].legsAnim = newAnimation; } - /* - if ((cent->currentState.torsoAnim&~ANIM_TOGGLEBIT) == newAnimation && - !BG_FlippingAnim( cent->currentState.legsAnim ) && - !BG_SpinningSaberAnim( cent->currentState.legsAnim ) && - !BG_SpinningSaberAnim( cent->currentState.torsoAnim ) && - !BG_InSpecialJump( cent->currentState.legsAnim ) && - !BG_InSpecialJump( cent->currentState.torsoAnim ) && - !BG_InDeathAnim(cent->currentState.legsAnim) && - !BG_InDeathAnim(cent->currentState.torsoAnim) && - !CG_InRoll(cent) && - !BG_SaberInSpecial(cent->currentState.saberMove) && - !BG_SaberInSpecialAttack(cent->currentState.torsoAnim) && - !BG_SaberInSpecialAttack(cent->currentState.legsAnim) ) - */ - if (cg.snap && cg.snap->ps.clientNum == cent->currentState.number) - { //go ahead and use the predicted state if you can. - if ((cg.predictedPlayerState.torsoAnim&~ANIM_TOGGLEBIT) == newAnimation) - { - trap_G2API_SetBoneAnim(cent->ghoul2, 0, "Motion", anim->firstFrame, anim->firstFrame + anim->numFrames, flags, animSpeed, cg.time, -1, blendTime); - } - } - else + if ((cent->currentState.torsoAnim&~ANIM_TOGGLEBIT) == newAnimation) { - if ((cent->currentState.torsoAnim&~ANIM_TOGGLEBIT) == newAnimation) + if (beginFrame != anim->firstFrame) + { + trap_G2API_SetBoneAnim(cent->ghoul2, 0, "Motion", anim->firstFrame, anim->firstFrame + anim->numFrames, flags, animSpeed, cg.time, beginFrame, blendTime); + } + else { trap_G2API_SetBoneAnim(cent->ghoul2, 0, "Motion", anim->firstFrame, anim->firstFrame + anim->numFrames, flags, animSpeed, cg.time, -1, blendTime); } @@ -1441,7 +1642,7 @@ the animation before it completes at normal speed, in the case of a looping animation (such as the leg running anim). =============== */ -static qboolean CG_FirstAnimFrame(clientInfo_t *ci, lerpFrame_t *lf, qboolean torsoOnly, float speedScale) +static qboolean CG_FirstAnimFrame(lerpFrame_t *lf, qboolean torsoOnly, float speedScale) { if (torsoOnly) { @@ -1649,13 +1850,13 @@ static void CG_RunLerpFrame( centity_t *cent, clientInfo_t *ci, lerpFrame_t *lf, { int flags = BONE_ANIM_OVERRIDE_FREEZE; //|BONE_ANIM_BLEND; float animSpeed = 1.0f; - trap_G2API_SetBoneAnim(cent->ghoul2, 0, "upper_lumbar", cent->currentState.forceFrame, cent->currentState.forceFrame+1, flags, animSpeed, cg.time, -1, 150); + trap_G2API_SetBoneAnim(cent->ghoul2, 0, "lower_lumbar", cent->currentState.forceFrame, cent->currentState.forceFrame+1, flags, animSpeed, cg.time, -1, 150); trap_G2API_SetBoneAnim(cent->ghoul2, 0, "model_root", cent->currentState.forceFrame, cent->currentState.forceFrame+1, flags, animSpeed, cg.time, -1, 150); trap_G2API_SetBoneAnim(cent->ghoul2, 0, "Motion", cent->currentState.forceFrame, cent->currentState.forceFrame+1, flags, animSpeed, cg.time, -1, 150); lf->animationNumber = 0; } - else if ( (newAnimation != lf->animationNumber || !lf->animation) || (CG_FirstAnimFrame(ci, lf, torsoOnly, speedScale)) ) + else if ( (newAnimation != lf->animationNumber || !lf->animation) || (CG_FirstAnimFrame(lf, torsoOnly, speedScale)) ) { CG_SetLerpFrameAnimation( cent, ci, lf, newAnimation, speedScale, torsoOnly); } @@ -1778,7 +1979,7 @@ static void CG_RunLerpFrame( centity_t *cent, clientInfo_t *ci, lerpFrame_t *lf, } if ( cg.time > lf->frameTime ) { lf->frameTime = cg.time; - if ( cg_debugAnim.integer ) { + if ( cg_debugAnim.integer && (cg_debugAnim.integer < 0 || cg_debugAnim.integer == cent->currentState.clientNum) ) { CG_Printf( "Clamp lf->frameTime\n"); } } @@ -2096,125 +2297,101 @@ void CG_G2SetBoneAngles(void *ghoul2, int modelIndex, const char *boneName, cons void CG_G2ClientSpineAngles( centity_t *cent, vec3_t viewAngles, const vec3_t angles, vec3_t thoracicAngles, vec3_t ulAngles, vec3_t llAngles ) { - int ang = 0; - - if (cent->isATST || cent->currentState.teamowner) - { - return; - } - - VectorClear(ulAngles); - VectorClear(llAngles); - - //cent->pe.torso.pitchAngle = viewAngles[PITCH]; + float legDif = 0; +// cent->pe.torso.pitchAngle = viewAngles[PITCH]; viewAngles[YAW] = AngleDelta( cent->lerpAngles[YAW], angles[YAW] ); - //cent->pe.torso.yawAngle = viewAngles[YAW]; + legDif = viewAngles[YAW]; +// cent->pe.torso.yawAngle = viewAngles[YAW]; - if ( !BG_FlippingAnim( cent->currentState.legsAnim ) && - !BG_SpinningSaberAnim( cent->currentState.legsAnim ) && - !BG_SpinningSaberAnim( cent->currentState.torsoAnim ) && - !BG_InSpecialJump( cent->currentState.legsAnim ) && - !BG_InSpecialJump( cent->currentState.torsoAnim ) && - !BG_InDeathAnim(cent->currentState.legsAnim) && - !BG_InDeathAnim(cent->currentState.torsoAnim) && + /* + if ( !BG_FlippingAnim( cent->currentState.legsAnim ) + && !BG_SpinningSaberAnim( cent->currentState.legsAnim ) + && !BG_SpinningSaberAnim( cent->currentState.torsoAnim ) + && !BG_SaberInSpecial(cent->currentState.saberMove) + && cent->currentState.legsAnim != cent->currentState.torsoAnim )//NOTE: presumes your legs & torso are on the same frame, though they *should* be because PM_SetAnimFinal tries to keep them in synch + */ + if ( !BG_FlippingAnim( cent->currentState.legsAnim&~ANIM_TOGGLEBIT ) && + !BG_SpinningSaberAnim( cent->currentState.legsAnim&~ANIM_TOGGLEBIT ) && + !BG_SpinningSaberAnim( cent->currentState.torsoAnim&~ANIM_TOGGLEBIT ) && + !BG_InSpecialJump( cent->currentState.legsAnim&~ANIM_TOGGLEBIT ) && + !BG_InSpecialJump( cent->currentState.torsoAnim&~ANIM_TOGGLEBIT ) && + !BG_InDeathAnim(cent->currentState.legsAnim&~ANIM_TOGGLEBIT) && + !BG_InDeathAnim(cent->currentState.torsoAnim&~ANIM_TOGGLEBIT) && !CG_InRoll(cent) && !CG_InRollAnim(cent) && !BG_SaberInSpecial(cent->currentState.saberMove) && - !BG_SaberInSpecialAttack(cent->currentState.torsoAnim) && - !BG_SaberInSpecialAttack(cent->currentState.legsAnim) && + !BG_SaberInSpecialAttack(cent->currentState.torsoAnim&~ANIM_TOGGLEBIT) && + !BG_SaberInSpecialAttack(cent->currentState.legsAnim&~ANIM_TOGGLEBIT) && - !BG_FlippingAnim( cgs.clientinfo[cent->currentState.number].legsAnim ) && - !BG_SpinningSaberAnim( cgs.clientinfo[cent->currentState.number].legsAnim ) && - !BG_SpinningSaberAnim( cgs.clientinfo[cent->currentState.number].torsoAnim ) && - !BG_InSpecialJump( cgs.clientinfo[cent->currentState.number].legsAnim ) && - !BG_InSpecialJump( cgs.clientinfo[cent->currentState.number].torsoAnim ) && - !BG_InDeathAnim(cgs.clientinfo[cent->currentState.number].legsAnim) && - !BG_InDeathAnim(cgs.clientinfo[cent->currentState.number].torsoAnim) && - !BG_SaberInSpecialAttack(cgs.clientinfo[cent->currentState.number].torsoAnim) && - !BG_SaberInSpecialAttack(cgs.clientinfo[cent->currentState.number].legsAnim) && + !BG_FlippingAnim( cgs.clientinfo[cent->currentState.number].legsAnim&~ANIM_TOGGLEBIT ) && + !BG_SpinningSaberAnim( cgs.clientinfo[cent->currentState.number].legsAnim&~ANIM_TOGGLEBIT ) && + !BG_SpinningSaberAnim( cgs.clientinfo[cent->currentState.number].torsoAnim&~ANIM_TOGGLEBIT ) && + !BG_InSpecialJump( cgs.clientinfo[cent->currentState.number].legsAnim&~ANIM_TOGGLEBIT ) && + !BG_InSpecialJump( cgs.clientinfo[cent->currentState.number].torsoAnim&~ANIM_TOGGLEBIT ) && + !BG_InDeathAnim(cgs.clientinfo[cent->currentState.number].legsAnim&~ANIM_TOGGLEBIT) && + !BG_InDeathAnim(cgs.clientinfo[cent->currentState.number].torsoAnim&~ANIM_TOGGLEBIT) && + !BG_SaberInSpecialAttack(cgs.clientinfo[cent->currentState.number].torsoAnim&~ANIM_TOGGLEBIT) && + !BG_SaberInSpecialAttack(cgs.clientinfo[cent->currentState.number].legsAnim&~ANIM_TOGGLEBIT) && - /* - !BG_FlippingAnim( cent->rootBone ) && - !BG_SpinningSaberAnim( cent->rootBone ) && - !BG_InSpecialJump( cent->rootBone ) && - !BG_InDeathAnim(cent->rootBone) && - !BG_SaberInSpecialAttack(cent->rootBone) && - */ - - !(cent->currentState.eFlags & EF_DEAD) ) - { + !(cent->currentState.eFlags & EF_DEAD) && + (cent->currentState.legsAnim&~ANIM_TOGGLEBIT) != (cent->currentState.torsoAnim&~ANIM_TOGGLEBIT) && + (cgs.clientinfo[cent->currentState.number].legsAnim&~ANIM_TOGGLEBIT) != (cgs.clientinfo[cent->currentState.number].torsoAnim&~ANIM_TOGGLEBIT)) + {//FIXME: no need to do this if legs and torso on are same frame //adjust for motion offset mdxaBone_t boltMatrix; vec3_t motionFwd, motionAngles; + vec3_t motionRt, tempAng; + int ang; - //trap_G2API_GetBoltMatrix( cent->ghoul2, 0, cgs.clientinfo[cent->currentState.number].bolt_motion, &boltMatrix, vec3_origin, cent->lerpOrigin, cg.time, /*cgs.gameModels*/0, cent->modelScale); - trap_G2API_GetBoltMatrix_NoReconstruct( cent->ghoul2, 0, cgs.clientinfo[cent->currentState.number].bolt_motion, &boltMatrix, vec3_origin, cent->lerpOrigin, cg.time, /*cgs.gameModels*/0, cent->modelScale); - // trap_G2API_GiveMeVectorFromMatrix( &boltMatrix, POSITIVE_X, motionFwd ); - //trap_G2API_GiveMeVectorFromMatrix( &boltMatrix, POSITIVE_Y, motionFwd ); + trap_G2API_GetBoltMatrix_NoRecNoRot( cent->ghoul2, 0, cgs.clientinfo[cent->currentState.number].bolt_motion, &boltMatrix, vec3_origin, cent->lerpOrigin, cg.time, /*cgs.gameModels*/0, cent->modelScale); trap_G2API_GiveMeVectorFromMatrix( &boltMatrix, NEGATIVE_Y, motionFwd ); vectoangles( motionFwd, motionAngles ); + + trap_G2API_GiveMeVectorFromMatrix( &boltMatrix, NEGATIVE_X, motionRt ); + vectoangles( motionRt, tempAng ); + motionAngles[ROLL] = -tempAng[PITCH]; + for ( ang = 0; ang < 3; ang++ ) { viewAngles[ang] = AngleNormalize180( viewAngles[ang] - AngleNormalize180( motionAngles[ang] ) ); } - - //Using NEGATIVE_Y and subtractinging 90 seems to magically fix our horrible contortion issues. - //SP actually just uses NEGATIVE_Y without this. Unfortunately we have some sort of worthless - //chunk of code in our GBM function that rotates the entire matrix 90 degrees before returning - //a "proper" direction. SP does not have this. And I am not even going to consider changing it at - //this point to match. - //Com_Printf("Comp: %f %f %f\n", viewAngles[0], viewAngles[1], viewAngles[2]); - - if (viewAngles[YAW] < -90) - { - viewAngles[YAW] += 360; - } - - viewAngles[YAW] -= 90; } + + //Keep it within 80 degrees of the leg angles, on either side. Will hopefully prevent spine twisting. + /* + if (legDif > 0) + { + legDif += 80; + } + else + { + legDif -= 80; + } + + if (legDif < 0 && viewAngles[YAW] < legDif) + { + viewAngles[YAW] = legDif; + } + if (legDif > 0 && viewAngles[YAW] > legDif) + { + viewAngles[YAW] = legDif; + } + */ + //distribute the angles differently up the spine //NOTE: each of these distributions must add up to 1.0f - thoracicAngles[PITCH] = 0;//viewAngles[PITCH]*0.20f; - llAngles[PITCH] = 0;//viewAngles[PITCH]*0.40f; - ulAngles[PITCH] = 0;//viewAngles[PITCH]*0.40f; + thoracicAngles[PITCH] = viewAngles[PITCH]*0.20f; + llAngles[PITCH] = viewAngles[PITCH]*0.40f; + ulAngles[PITCH] = viewAngles[PITCH]*0.40f; - thoracicAngles[YAW] = viewAngles[YAW]*0.20f - (viewAngles[PITCH]*(viewAngles[YAW]*.020f)); - ulAngles[YAW] = viewAngles[YAW]*0.25f - (viewAngles[PITCH]*(viewAngles[YAW]*.0005f)); - llAngles[YAW] = viewAngles[YAW]*0.25f - (viewAngles[PITCH]*(viewAngles[YAW]*.0005f)); - - if (thoracicAngles[YAW] > 20) - { - thoracicAngles[YAW] = 20; - } - if (ulAngles[YAW] > 20) - { - ulAngles[YAW] = 20; - } - if (llAngles[YAW] > 20) - { - llAngles[YAW] = 20; - } + thoracicAngles[YAW] = viewAngles[YAW]*0.20f; + ulAngles[YAW] = viewAngles[YAW]*0.35f; + llAngles[YAW] = viewAngles[YAW]*0.45f; thoracicAngles[ROLL] = viewAngles[ROLL]*0.20f; ulAngles[ROLL] = viewAngles[ROLL]*0.35f; llAngles[ROLL] = viewAngles[ROLL]*0.45f; - - for ( ang = 0; ang < 3; ang++ ) - { - if (ulAngles[ang] < 0) - { - ulAngles[ang] += 360; - } - } - - //thoracic is added modified again by neckAngle calculations, so don't set it until then -// BG_G2SetBoneAngles( cent, cent->gent, cent->gent->upperLumbarBone, ulAngles, BONE_ANGLES_POSTMULT, POSITIVE_X, NEGATIVE_Y, NEGATIVE_Z, cgs.model_draw); -// BG_G2SetBoneAngles( cent, cent->gent, cent->gent->lowerLumbarBone, llAngles, BONE_ANGLES_POSTMULT, POSITIVE_X, NEGATIVE_Y, NEGATIVE_Z, cgs.model_draw); - -// trap_G2API_SetBoneAngles(cent->ghoul2, 0, "upper_lumbar", ulAngles, BONE_ANGLES_POSTMULT, POSITIVE_X, NEGATIVE_Y, NEGATIVE_Z, cgs.gameModels, 0, cg.time); -// trap_G2API_SetBoneAngles(cent->ghoul2, 0, "lower_lumbar", llAngles, BONE_ANGLES_POSTMULT, POSITIVE_X, NEGATIVE_Y, NEGATIVE_Z, cgs.gameModels, 0, cg.time); -// trap_G2API_SetBoneAngles(cent->ghoul2, 0, "thoracic", thoracicAngles, BONE_ANGLES_POSTMULT, POSITIVE_X, NEGATIVE_Y, NEGATIVE_Z, cgs.gameModels, 0, cg.time); } static void CG_G2PlayerAngles( centity_t *cent, vec3_t legs[3], vec3_t legsAngles){ @@ -2444,6 +2621,9 @@ static void CG_G2PlayerAngles( centity_t *cent, vec3_t legs[3], vec3_t legsAngle // pull the angles back out of the hierarchial chain AnglesSubtract( headAngles, torsoAngles, headAngles ); AnglesSubtract( torsoAngles, legsAngles, torsoAngles ); + + legsAngles[PITCH] = 0; + AnglesToAxis( legsAngles, legs ); // we assume that model 0 is the player model. @@ -2467,23 +2647,22 @@ static void CG_G2PlayerAngles( centity_t *cent, vec3_t legs[3], vec3_t legsAngle viewAngles[YAW] = viewAngles[ROLL] = 0; viewAngles[PITCH] *= 0.5; - VectorCopy( cent->lerpAngles, angles ); - angles[PITCH] = 0; + VectorSet( angles, 0, legsAngles[1], 0 ); + + angles[0] = legsAngles[0]; + if ( angles[0] > 30 ) + { + angles[0] = 30; + } + else if ( angles[0] < -30 ) + { + angles[0] = -30; + } + +// VectorCopy(legsAngles, angles); CG_G2ClientSpineAngles(cent, viewAngles, angles, thoracicAngles, ulAngles, llAngles); - ulAngles[YAW] += torsoAngles[YAW]*0.3; - llAngles[YAW] += torsoAngles[YAW]*0.3; - thoracicAngles[YAW] += torsoAngles[YAW]*0.4; - - ulAngles[PITCH] = torsoAngles[PITCH]*0.3; - llAngles[PITCH] = torsoAngles[PITCH]*0.3; - thoracicAngles[PITCH] = torsoAngles[PITCH]*0.4; - - ulAngles[ROLL] += torsoAngles[ROLL]*0.3; - llAngles[ROLL] += torsoAngles[ROLL]*0.3; - thoracicAngles[ROLL] += torsoAngles[ROLL]*0.4; - if ( cent->currentState.otherEntityNum2 && !(cent->currentState.eFlags & EF_DEAD) ) { //using an emplaced gun centity_t *empEnt = &cg_entities[cent->currentState.otherEntityNum2]; @@ -2532,7 +2711,126 @@ static void CG_G2PlayerAngles( centity_t *cent, vec3_t legs[3], vec3_t legsAngle CG_G2SetBoneAngles(cent->ghoul2, 0, "upper_lumbar", ulAngles, BONE_ANGLES_POSTMULT, POSITIVE_X, NEGATIVE_Y, NEGATIVE_Z, cgs.gameModels, 0, cg.time); CG_G2SetBoneAngles(cent->ghoul2, 0, "lower_lumbar", llAngles, BONE_ANGLES_POSTMULT, POSITIVE_X, NEGATIVE_Y, NEGATIVE_Z, cgs.gameModels, 0, cg.time); CG_G2SetBoneAngles(cent->ghoul2, 0, "thoracic", thoracicAngles, BONE_ANGLES_POSTMULT, POSITIVE_X, NEGATIVE_Y, NEGATIVE_Z, cgs.gameModels, 0, cg.time); - CG_G2SetBoneAngles(cent->ghoul2, 0, "cervical", vec3_origin, BONE_ANGLES_POSTMULT, POSITIVE_X, NEGATIVE_Y, NEGATIVE_Z, cgs.gameModels, 0, cg.time); + + if (cg_duelHeadAngles.integer && !(cent->currentState.eFlags & EF_DEAD)) + { + if ( !BG_FlippingAnim( cent->currentState.legsAnim&~ANIM_TOGGLEBIT ) && + !BG_SpinningSaberAnim( cent->currentState.legsAnim&~ANIM_TOGGLEBIT ) && + !BG_SpinningSaberAnim( cent->currentState.torsoAnim&~ANIM_TOGGLEBIT ) && + !BG_InSpecialJump( cent->currentState.legsAnim&~ANIM_TOGGLEBIT ) && + !BG_InSpecialJump( cent->currentState.torsoAnim&~ANIM_TOGGLEBIT ) && + !BG_InDeathAnim(cent->currentState.legsAnim&~ANIM_TOGGLEBIT) && + !BG_InDeathAnim(cent->currentState.torsoAnim&~ANIM_TOGGLEBIT) && + !CG_InRoll(cent) && + !CG_InRollAnim(cent) && + !BG_SaberInSpecial(cent->currentState.saberMove) && + !BG_SaberInSpecialAttack(cent->currentState.torsoAnim&~ANIM_TOGGLEBIT) && + !BG_SaberInSpecialAttack(cent->currentState.legsAnim&~ANIM_TOGGLEBIT) && + + !BG_FlippingAnim( cgs.clientinfo[cent->currentState.number].legsAnim&~ANIM_TOGGLEBIT ) && + !BG_SpinningSaberAnim( cgs.clientinfo[cent->currentState.number].legsAnim&~ANIM_TOGGLEBIT ) && + !BG_SpinningSaberAnim( cgs.clientinfo[cent->currentState.number].torsoAnim&~ANIM_TOGGLEBIT ) && + !BG_InSpecialJump( cgs.clientinfo[cent->currentState.number].legsAnim&~ANIM_TOGGLEBIT ) && + !BG_InSpecialJump( cgs.clientinfo[cent->currentState.number].torsoAnim&~ANIM_TOGGLEBIT ) && + !BG_InDeathAnim(cgs.clientinfo[cent->currentState.number].legsAnim&~ANIM_TOGGLEBIT) && + !BG_InDeathAnim(cgs.clientinfo[cent->currentState.number].torsoAnim&~ANIM_TOGGLEBIT) && + !BG_SaberInSpecialAttack(cgs.clientinfo[cent->currentState.number].torsoAnim&~ANIM_TOGGLEBIT) && + !BG_SaberInSpecialAttack(cgs.clientinfo[cent->currentState.number].legsAnim&~ANIM_TOGGLEBIT) ) + { //use similar check to spine correction, these are the "safe" anims to be in for twisting around + vec3_t headAngles; + int duelClient = -1; + + if (cgs.gametype == GT_TOURNAMENT && (cent->currentState.number == cgs.duelist1 || cent->currentState.number == cgs.duelist2)) + { + if (cgs.duelist1 >= 0 && cgs.duelist1 < MAX_CLIENTS && + cgs.duelist2 >= 0 && cgs.duelist2 < MAX_CLIENTS) + { + if (cent->currentState.number == cgs.duelist1) + { + duelClient = cgs.duelist2; + } + else + { + duelClient = cgs.duelist1; + } + } + } + else if (cg.snap && cg.snap->ps.duelInProgress) + { + if (cent->currentState.number == cg.snap->ps.duelIndex) + { + duelClient = cg.snap->ps.clientNum; + } + else if (cent->currentState.number == cg.snap->ps.clientNum) + { + duelClient = cg.snap->ps.duelIndex; + } + } + + if (duelClient != -1) + { + trace_t tr; + + CG_Trace( &tr, cent->lerpOrigin, NULL, NULL, cg_entities[duelClient].lerpOrigin, cent->currentState.number, MASK_PLAYERSOLID ); + + if (tr.fraction == 1.0 || + tr.entityNum == duelClient) + { + centity_t *duelCEnt = &cg_entities[duelClient]; + vec3_t headSub; + + VectorSubtract(duelCEnt->lerpOrigin, cent->lerpOrigin, headSub); + vectoangles(headSub, headSub); + + headAngles[ROLL] = AngleSubtract(headSub[ROLL], cent->lerpAngles[ROLL]); + headAngles[YAW] = AngleSubtract(headSub[YAW], cent->lerpAngles[YAW]); + + if (headAngles[YAW] > 55) + { + headAngles[YAW] = 55; + } + if (headAngles[YAW] < -55) + { + headAngles[YAW] = -55; + } + + VectorCopy( cent->lerpAngles, viewAngles ); + viewAngles[YAW] = viewAngles[ROLL] = 0; + viewAngles[PITCH] *= 0.5; + + headAngles[PITCH] = AngleSubtract(headSub[PITCH], viewAngles[PITCH]); + if (headAngles[PITCH] > 16) + { + headAngles[PITCH] = 16; + } + if (headAngles[PITCH] < -16) + { + headAngles[PITCH] = -16; + } + headAngles[PITCH] += 6; + } + else + { + VectorClear(headAngles); + } + } + else + { + VectorClear(headAngles); + } + + CG_G2SetBoneAngles(cent->ghoul2, 0, "cervical", headAngles, BONE_ANGLES_POSTMULT, POSITIVE_X, NEGATIVE_Y, NEGATIVE_Z, cgs.gameModels, 0, cg.time); + } + else + { + VectorClear(headAngles); + CG_G2SetBoneAngles(cent->ghoul2, 0, "cervical", headAngles, BONE_ANGLES_POSTMULT, POSITIVE_X, NEGATIVE_Y, NEGATIVE_Z, cgs.gameModels, 0, cg.time); + } + } + else + { + CG_G2SetBoneAngles(cent->ghoul2, 0, "cervical", vec3_origin, BONE_ANGLES_POSTMULT, POSITIVE_X, NEGATIVE_Y, NEGATIVE_Z, cgs.gameModels, 0, cg.time); + } } //trap_G2API_SetBoneAngles(cent->ghoul2, 0, "cranium", headAngles, BONE_ANGLES_POSTMULT, POSITIVE_Z, NEGATIVE_Y, POSITIVE_X, cgs.gameModels, 0, cg.time); @@ -2839,6 +3137,78 @@ static void CG_PlayerFloatSpriteRGBA( centity_t *cent, qhandle_t shader, vec4_t #endif +/* +=============== +CG_PlayerSprites + +Float sprites over the player's head +=============== +*/ +static void CG_PlayerSprites( centity_t *cent ) { +// int team; + + if (cg.snap && + CG_IsMindTricked(cent->currentState.trickedentindex, + cent->currentState.trickedentindex2, + cent->currentState.trickedentindex3, + cent->currentState.trickedentindex4, + cg.snap->ps.clientNum)) + { + return; //this entity is mind-tricking the current client, so don't render it + } + + if ( cent->currentState.eFlags & EF_CONNECTION ) { + CG_PlayerFloatSprite( cent, cgs.media.connectionShader ); + return; + } + + if ( cent->currentState.eFlags & EF_TALK ) { + CG_PlayerFloatSprite( cent, cgs.media.balloonShader ); + return; + } +/* + if ( cent->currentState.eFlags & EF_AWARD_IMPRESSIVE ) { + CG_PlayerFloatSprite( cent, cgs.media.medalImpressive ); + return; + } + + if ( cent->currentState.eFlags & EF_AWARD_EXCELLENT ) { + CG_PlayerFloatSprite( cent, cgs.media.medalExcellent ); + return; + } + + if ( cent->currentState.eFlags & EF_AWARD_GAUNTLET ) { + CG_PlayerFloatSprite( cent, cgs.media.medalGauntlet ); + return; + } + + if ( cent->currentState.eFlags & EF_AWARD_DEFEND ) { + CG_PlayerFloatSprite( cent, cgs.media.medalDefend ); + return; + } + + if ( cent->currentState.eFlags & EF_AWARD_ASSIST ) { + CG_PlayerFloatSprite( cent, cgs.media.medalAssist ); + return; + } + + if ( cent->currentState.eFlags & EF_AWARD_CAP ) { + CG_PlayerFloatSprite( cent, cgs.media.medalCapture ); + return; + } + + team = cgs.clientinfo[ cent->currentState.clientNum ].team; + if ( !(cent->currentState.eFlags & EF_DEAD) && + cg.snap->ps.persistant[PERS_TEAM] == team && + cgs.gametype >= GT_TEAM) { + if (cg_drawFriend.integer) { + CG_PlayerFloatSprite( cent, cgs.media.friendShader ); + } + return; + } +*/ +} + /* =============== CG_PlayerShadow @@ -3477,6 +3847,99 @@ void CG_CreateSaberMarks( vec3_t start, vec3_t end, vec3_t normal ) } } +#ifdef G2_COLLISION_ENABLED +qboolean CG_G2TraceCollide(trace_t *tr, vec3_t lastValidStart, vec3_t lastValidEnd) +{ + if (tr->entityNum < MAX_CLIENTS) + { //Hit a client with the normal trace, try the collision trace. + G2Trace_t G2Trace; + centity_t *g2Hit; + vec3_t vIdentity = {1.0f, 1.0f, 1.0f}; + vec3_t angles; + int tN = 0; + float fRadius = 0; + + memset (&G2Trace, 0, sizeof(G2Trace)); + + while (tN < MAX_G2_COLLISIONS) + { + G2Trace[tN].mEntityNum = -1; + tN++; + } + g2Hit = &cg_entities[tr->entityNum]; + + if (g2Hit && g2Hit->ghoul2) + { + angles[ROLL] = angles[PITCH] = 0; + angles[YAW] = g2Hit->lerpAngles[YAW]; + + trap_G2API_CollisionDetect ( G2Trace, g2Hit->ghoul2, angles, g2Hit->lerpOrigin, cg.time, g2Hit->currentState.number, lastValidStart, lastValidEnd, vIdentity, 0, 2, fRadius ); + + if (G2Trace[0].mEntityNum != g2Hit->currentState.number) + { + tr->fraction = 1.0f; + tr->entityNum = ENTITYNUM_NONE; + tr->startsolid = 0; + tr->allsolid = 0; + return qfalse; + } + else + { //Yay! + VectorCopy(G2Trace[0].mCollisionPosition, tr->endpos); + VectorCopy(G2Trace[0].mCollisionNormal, tr->plane.normal); + return qtrue; + } + } + } + + return qfalse; +} + +void CG_G2SaberEffects(vec3_t start, vec3_t end, centity_t *owner) +{ + trace_t trace; + vec3_t startTr; + vec3_t endTr; + qboolean backWards = qfalse; + qboolean doneWithTraces = qfalse; + + while (!doneWithTraces) + { + if (!backWards) + { + VectorCopy(start, startTr); + VectorCopy(end, endTr); + } + else + { + VectorCopy(end, startTr); + VectorCopy(start, endTr); + } + + CG_Trace( &trace, startTr, NULL, NULL, endTr, owner->currentState.number, MASK_PLAYERSOLID ); + + if (trace.entityNum < MAX_CLIENTS) + { //hit a client.. + CG_G2TraceCollide(&trace, startTr, endTr); + + if (trace.entityNum != ENTITYNUM_NONE) + { //it succeeded with the ghoul2 trace + trap_FX_PlayEffectID( trap_FX_RegisterEffect("saber/blood_sparks.efx"), trace.endpos, trace.plane.normal ); + } + } + + if (!backWards) + { + backWards = qtrue; + } + else + { + doneWithTraces = qtrue; + } + } +} +#endif + #define SABER_TRAIL_TIME 40.0f #define FX_USE_ALPHA 0x08000000 @@ -3614,6 +4077,13 @@ Ghoul2 Insert Start goto CheckTrail; } +#ifdef G2_COLLISION_ENABLED + if (cg_saberModelTraceEffect.integer) + { + CG_G2SaberEffects(org_, end, cent); + } +#endif + for ( i = 0; i < 1; i++ )//was 2 because it would go through architecture and leave saber trails on either side of the brush - but still looks bad if we hit a corner, blade is still 8 longer than hit { if ( i ) @@ -4125,6 +4595,933 @@ qboolean CG_ThereIsAMaster(void) return qfalse; } +//rww - here begins the majority of my g2animent stuff. +void CG_FootStepGeneric(centity_t *cent, int anim) +{ + int groundType; + + if ((anim & ~ANIM_TOGGLEBIT) == BOTH_WALL_RUN_RIGHT || + (anim & ~ANIM_TOGGLEBIT) == BOTH_WALL_RUN_LEFT) + { + groundType = FOOTSTEP_GENERIC; + goto skipCheck; + } + + if (cent->currentState.groundEntityNum == ENTITYNUM_NONE) + { + return; + } + +skipCheck: + groundType = FOOTSTEP_GENERIC;//CG_FootstepForSurface(cent, cent->currentState.number); + +//skipCheck: + + if (!groundType) + { + return; + } + + switch (groundType) + { + case FOOTSTEP_GENERIC: + trap_S_StartSound (NULL, cent->currentState.number, CHAN_BODY, + cgs.media.footsteps[ FOOTSTEP_NORMAL ][rand()&3] ); + break; + case FOOTSTEP_METAL: + trap_S_StartSound (NULL, cent->currentState.number, CHAN_BODY, + cgs.media.footsteps[ FOOTSTEP_METAL ][rand()&3] ); + break; + default: + break; + } +} + +static void CG_G2EntSetLerpFrameAnimation( centity_t *cent, lerpFrame_t *lf, int newAnimation, float animSpeedMult, qboolean torsoOnly) { + animation_t *anim; + float animSpeed; + int flags=BONE_ANIM_OVERRIDE_FREEZE; + int oldAnim = -1; + int blendTime = 150; + + if (cent->currentState.number < MAX_CLIENTS && + cent->currentState.teamowner && + !cent->isATST) + { + return; + } + + oldAnim = lf->animationNumber; + + lf->animationNumber = newAnimation; + newAnimation &= ~ANIM_TOGGLEBIT; + + if ( newAnimation < 0 || newAnimation >= MAX_TOTALANIMATIONS ) { +// CG_Error( "Bad animation number: %i", newAnimation ); + return; + } + + anim = &bgGlobalAnimations[ newAnimation ]; + + lf->animation = anim; + lf->animationTime = lf->frameTime + anim->initialLerp; + + if ( cg_debugAnim.integer && (cg_debugAnim.integer < 0 || cg_debugAnim.integer == cent->currentState.clientNum) ) { + CG_Printf( "%d: %d Anim: %i, '%s'\n", cg.time, cent->currentState.clientNum, newAnimation, GetStringForID(animTable, newAnimation)); + } + + if (cent->ghoul2) + { + animSpeed = 50.0f / anim->frameLerp; + if (lf->animation->loopFrames != -1) + { + flags = BONE_ANIM_OVERRIDE_LOOP; + } + + if (cent->isATST) + { + if (animSpeed < 0.3) + { + animSpeed = 0.3; + } + + if (newAnimation == BOTH_WALKBACK1) + { + animSpeed = 0.8; + } + + if (newAnimation != BOTH_DEATH1) + { + flags = BONE_ANIM_OVERRIDE_LOOP; + } + } + + if (cg_animBlend.integer) + { + flags |= BONE_ANIM_BLEND; + } + + if (!cent->isATST) + { + if (/*BG_FlippingAnim(newAnimation) ||*/ BG_InDeathAnim(newAnimation)) + { + flags &= ~BONE_ANIM_BLEND; + } + else if ( oldAnim != -1 && + (/*BG_FlippingAnim(oldAnim) ||*/ BG_InDeathAnim(oldAnim)) ) + { + flags &= ~BONE_ANIM_BLEND; + } + + if (flags & BONE_ANIM_BLEND) + { + if (BG_FlippingAnim(newAnimation)) + { + blendTime = 200; + } + else if ( oldAnim != -1 && + (BG_FlippingAnim(oldAnim)) ) + { + blendTime = 200; + } + } + } + + animSpeed *= animSpeedMult; + + if (torsoOnly) + { + lf->animationTorsoSpeed = animSpeedMult; + } + else + { + lf->animationSpeed = animSpeedMult; + } + + if (cent->isATST) + { + int atstBlend = 400; + + if (torsoOnly) + { + trap_G2API_SetBoneAnim(cent->ghoul2, 0, "pelvis", anim->firstFrame, anim->firstFrame + anim->numFrames, flags, animSpeed, cg.time, -1, atstBlend); + } + else + { + trap_G2API_SetBoneAnim(cent->ghoul2, 0, "model_root", anim->firstFrame, anim->firstFrame + anim->numFrames, flags, animSpeed, cg.time, -1, atstBlend); + } + } + else + { + if (torsoOnly) + { + trap_G2API_SetBoneAnim(cent->ghoul2, 0, "upper_lumbar", anim->firstFrame, anim->firstFrame + anim->numFrames, flags, animSpeed,cg.time, -1, blendTime); + } + else + { + trap_G2API_SetBoneAnim(cent->ghoul2, 0, "model_root", anim->firstFrame, anim->firstFrame + anim->numFrames, flags, animSpeed, cg.time, -1, blendTime); + } + + /* + if ((cent->currentState.torsoAnim&~ANIM_TOGGLEBIT) == newAnimation && + !BG_FlippingAnim( cent->currentState.legsAnim ) && + !BG_SpinningSaberAnim( cent->currentState.legsAnim ) && + !BG_SpinningSaberAnim( cent->currentState.torsoAnim ) && + !BG_InSpecialJump( cent->currentState.legsAnim ) && + !BG_InSpecialJump( cent->currentState.torsoAnim ) && + !BG_InDeathAnim(cent->currentState.legsAnim) && + !BG_InDeathAnim(cent->currentState.torsoAnim) && + !CG_InRoll(cent) && + !BG_SaberInSpecial(cent->currentState.saberMove) && + !BG_SaberInSpecialAttack(cent->currentState.torsoAnim) && + !BG_SaberInSpecialAttack(cent->currentState.legsAnim) ) + */ + if (cg.snap && cg.snap->ps.clientNum == cent->currentState.number) + { //go ahead and use the predicted state if you can. + if ((cg.predictedPlayerState.torsoAnim&~ANIM_TOGGLEBIT) == newAnimation) + { + trap_G2API_SetBoneAnim(cent->ghoul2, 0, "Motion", anim->firstFrame, anim->firstFrame + anim->numFrames, flags, animSpeed, cg.time, -1, blendTime); + } + } + else + { + if ((cent->currentState.torsoAnim&~ANIM_TOGGLEBIT) == newAnimation) + { + trap_G2API_SetBoneAnim(cent->ghoul2, 0, "Motion", anim->firstFrame, anim->firstFrame + anim->numFrames, flags, animSpeed, cg.time, -1, blendTime); + } + } + } + } +} + +static void CG_G2EntRunLerpFrame( centity_t *cent, lerpFrame_t *lf, int newAnimation, float speedScale, qboolean torsoOnly) +{ + int f, numFrames; + animation_t *anim; + + // debugging tool to get no animations + if ( cg_animSpeed.integer == 0 ) { + lf->oldFrame = lf->frame = lf->backlerp = 0; + return; + } + + // see if the animation sequence is switching + if (cent->currentState.forceFrame) + { + int flags = BONE_ANIM_OVERRIDE_FREEZE; //|BONE_ANIM_BLEND; + float animSpeed = 1.0f; + trap_G2API_SetBoneAnim(cent->ghoul2, 0, "upper_lumbar", cent->currentState.forceFrame, cent->currentState.forceFrame+1, flags, animSpeed, cg.time, -1, 150); + trap_G2API_SetBoneAnim(cent->ghoul2, 0, "model_root", cent->currentState.forceFrame, cent->currentState.forceFrame+1, flags, animSpeed, cg.time, -1, 150); + trap_G2API_SetBoneAnim(cent->ghoul2, 0, "Motion", cent->currentState.forceFrame, cent->currentState.forceFrame+1, flags, animSpeed, cg.time, -1, 150); + + lf->animationNumber = 0; + } + else if ( (newAnimation != lf->animationNumber || !lf->animation) || (CG_FirstAnimFrame(lf, torsoOnly, speedScale)) ) + { + CG_G2EntSetLerpFrameAnimation( cent, lf, newAnimation, speedScale, torsoOnly); + } + else if (cent->isATST) + { + if (cent->pe.legs.yawing != !lf->torsoYawing) + { + CG_G2EntSetLerpFrameAnimation( cent, lf, newAnimation, speedScale, torsoOnly); + lf->torsoYawing = cent->pe.legs.yawing; + } + } + + // if we have passed the current frame, move it to + // oldFrame and calculate a new frame + if ( cg.time >= lf->frameTime ) { + if (lf->oldFrame != lf->frame && + lf == &(cent->pe.legs)) + { + int addFinalFrame = CG_InWalkingAnim(lf->animationNumber); //9; + + if (!cent->isATST && + ((lf->animationNumber&~ANIM_TOGGLEBIT) == BOTH_WALL_RUN_RIGHT || (lf->animationNumber&~ANIM_TOGGLEBIT) == BOTH_WALL_RUN_LEFT) && + addFinalFrame) + { + if ( lf->frame >= (lf->animation->firstFrame+2) && + lf->oldFrame < (lf->animation->firstFrame+2)) + { + CG_FootStepGeneric(cent, lf->animationNumber); + } + else if ( lf->frame >= (lf->animation->firstFrame+addFinalFrame) && + lf->oldFrame < (lf->animation->firstFrame+addFinalFrame)) + { + CG_FootStepGeneric(cent, lf->animationNumber); + } + else if ( lf->frame >= (lf->animation->firstFrame+12) && + lf->oldFrame < (lf->animation->firstFrame+12)) + { + CG_FootStepGeneric(cent, lf->animationNumber); + } + else if ( lf->frame >= (lf->animation->firstFrame+16) && + lf->oldFrame < (lf->animation->firstFrame+16)) + { + CG_FootStepGeneric(cent, lf->animationNumber); + } + else if (lf->oldFrame > lf->frame && lf->frame > (lf->animation->firstFrame+1)) + { //missed one + CG_FootStepGeneric(cent, lf->animationNumber); + } + } + else if (addFinalFrame && !cent->isATST) + { + if ( lf->frame >= (lf->animation->firstFrame+3) && + lf->oldFrame < (lf->animation->firstFrame+3)) + { + CG_FootStepGeneric(cent, lf->animationNumber); + } + else if ( lf->frame >= (lf->animation->firstFrame+addFinalFrame) && + lf->oldFrame < (lf->animation->firstFrame+addFinalFrame)) + { + CG_FootStepGeneric(cent, lf->animationNumber); + } + else if (lf->oldFrame > lf->frame && lf->frame > (lf->animation->firstFrame+1)) + { //missed one + CG_FootStepGeneric(cent, lf->animationNumber); + } + } + } + + lf->oldFrame = lf->frame; + lf->oldFrameTime = lf->frameTime; + + // get the next frame based on the animation + anim = lf->animation; + if ( !anim->frameLerp ) { + return; // shouldn't happen + } + + if ( cg.time < lf->animationTime ) { + lf->frameTime = lf->animationTime; // initial lerp + } else { + lf->frameTime = lf->oldFrameTime + anim->frameLerp; + } + f = ( lf->frameTime - lf->animationTime ) / anim->frameLerp; + f *= speedScale; // adjust for haste, etc + + numFrames = anim->numFrames; + if (anim->flipflop) { + numFrames *= 2; + } + if ( f >= numFrames ) { + f -= numFrames; + if ( anim->loopFrames != -1 ) //Before 0 meant no loop + { + if(anim->numFrames - anim->loopFrames == 0) + { + f %= anim->numFrames; + } + else + { + f %= (anim->numFrames - anim->loopFrames); + } + f += anim->loopFrames; + } + else + { + f = numFrames - 1; + // the animation is stuck at the end, so it + // can immediately transition to another sequence + lf->frameTime = cg.time; + } + } + if ( anim->reversed ) { + lf->frame = anim->firstFrame + anim->numFrames - 1 - f; + } + else if (anim->flipflop && f>=anim->numFrames) { + lf->frame = anim->firstFrame + anim->numFrames - 1 - (f%anim->numFrames); + } + else { + lf->frame = anim->firstFrame + f; + } + if ( cg.time > lf->frameTime ) { + lf->frameTime = cg.time; + if ( cg_debugAnim.integer && (cg_debugAnim.integer < 0 || cg_debugAnim.integer == cent->currentState.clientNum) ) { + CG_Printf( "Clamp lf->frameTime\n"); + } + } + } + + if ( lf->frameTime > cg.time + 200 ) { + lf->frameTime = cg.time; + } + + if ( lf->oldFrameTime > cg.time ) { + lf->oldFrameTime = cg.time; + } + // calculate current lerp value + if ( lf->frameTime == lf->oldFrameTime ) { + lf->backlerp = 0; + } else { + lf->backlerp = 1.0 - (float)( cg.time - lf->oldFrameTime ) / ( lf->frameTime - lf->oldFrameTime ); + } +} + +static void CG_G2EntAnimation( centity_t *cent, int *legsOld, int *legs, float *legsBackLerp, + int *torsoOld, int *torso, float *torsoBackLerp ) { + float speedScale; + + if ( cg_noPlayerAnims.integer ) { + *legsOld = *legs = *torsoOld = *torso = 0; + return; + } + + if (cent->currentState.forcePowersActive & (1 << FP_RAGE)) + { + speedScale = 1.3; + } + else if (cent->currentState.forcePowersActive & (1 << FP_SPEED)) + { + speedScale = 1.7; + } + else + { + speedScale = 1; + } + + CG_G2EntRunLerpFrame( cent, ¢->pe.legs, cent->currentState.legsAnim, speedScale, qfalse); + + if (!(cent->currentState.forcePowersActive & (1 << FP_RAGE))) + { //don't affect torso anim speed unless raged + speedScale = 1; + } + else + { + speedScale = 1.7; + } + + *legsOld = cent->pe.legs.oldFrame; + *legs = cent->pe.legs.frame; + *legsBackLerp = cent->pe.legs.backlerp; + + CG_G2EntRunLerpFrame( cent, ¢->pe.torso, cent->currentState.torsoAnim, speedScale, qtrue ); + + *torsoOld = cent->pe.torso.oldFrame; + *torso = cent->pe.torso.frame; + *torsoBackLerp = cent->pe.torso.backlerp; +} + +void CG_G2AnimEntSpineAngles( centity_t *cent, vec3_t viewAngles, const vec3_t angles, vec3_t thoracicAngles, vec3_t ulAngles, vec3_t llAngles ) +{ + int ang = 0; + + if (cent->isATST || cent->currentState.teamowner) + { + return; + } + + VectorClear(ulAngles); + VectorClear(llAngles); + + //cent->pe.torso.pitchAngle = viewAngles[PITCH]; + viewAngles[YAW] = AngleDelta( cent->lerpAngles[YAW], angles[YAW] ); + //cent->pe.torso.yawAngle = viewAngles[YAW]; + + //distribute the angles differently up the spine + //NOTE: each of these distributions must add up to 1.0f + thoracicAngles[PITCH] = 0;//viewAngles[PITCH]*0.20f; + llAngles[PITCH] = 0;//viewAngles[PITCH]*0.40f; + ulAngles[PITCH] = 0;//viewAngles[PITCH]*0.40f; + + thoracicAngles[YAW] = viewAngles[YAW]*0.20f - (viewAngles[PITCH]*(viewAngles[YAW]*.020f)); + ulAngles[YAW] = viewAngles[YAW]*0.25f - (viewAngles[PITCH]*(viewAngles[YAW]*.0005f)); + llAngles[YAW] = viewAngles[YAW]*0.25f - (viewAngles[PITCH]*(viewAngles[YAW]*.0005f)); + + if (thoracicAngles[YAW] > 20) + { + thoracicAngles[YAW] = 20; + } + if (ulAngles[YAW] > 20) + { + ulAngles[YAW] = 20; + } + if (llAngles[YAW] > 20) + { + llAngles[YAW] = 20; + } + + thoracicAngles[ROLL] = viewAngles[ROLL]*0.20f; + ulAngles[ROLL] = viewAngles[ROLL]*0.35f; + llAngles[ROLL] = viewAngles[ROLL]*0.45f; + + for ( ang = 0; ang < 3; ang++ ) + { + if (ulAngles[ang] < 0) + { + ulAngles[ang] += 360; + } + } +} + +static void CG_G2AnimEntAngles( centity_t *cent, vec3_t legs[3], vec3_t legsAngles) +{ + vec3_t torsoAngles, headAngles; + float dest; + static int movementOffsets[8] = { 0, 22, 45, -22, 0, 22, -45, -22 }; + vec3_t velocity; + float speed; //, speed_dif, speed_desired; + int dir; + vec3_t velPos, velAng; + int adddir = 0; + float dif; + float degrees_negative = 0; + float degrees_positive = 0; + vec3_t ulAngles, llAngles, viewAngles, angles, thoracicAngles = {0,0,0}; + + VectorCopy( cent->lerpAngles, headAngles ); + headAngles[YAW] = AngleMod( headAngles[YAW] ); + VectorClear( legsAngles ); + VectorClear( torsoAngles ); + + // --------- yaw ------------- + + // allow yaw to drift a bit + if ((( cent->currentState.legsAnim & ~ANIM_TOGGLEBIT ) != BOTH_STAND1) || + ( cent->currentState.torsoAnim & ~ANIM_TOGGLEBIT ) != WeaponReadyAnim[cent->currentState.weapon] ) + { + // if not standing still, always point all in the same direction + cent->pe.torso.yawing = qtrue; // always center + cent->pe.torso.pitching = qtrue; // always center + cent->pe.legs.yawing = qtrue; // always center + } + + dir = 0; + if (!cent->isATST) + { + torsoAngles[YAW] = headAngles[YAW] + 0.25 * movementOffsets[ dir ]; + } + else + { + torsoAngles[YAW] = headAngles[YAW]; + } + + //for now, turn torso instantly and let the legs swing to follow + cent->pe.torso.yawAngle = torsoAngles[YAW]; + + // --------- pitch ------------- + + VectorCopy( cent->currentState.pos.trDelta, velocity ); + speed = VectorNormalize( velocity ); + + if (!speed) + { + torsoAngles[YAW] = headAngles[YAW]; + } + + // 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; + } + CG_SwingAngles( dest, 15, 30, 0.1, ¢->pe.torso.pitchAngle, ¢->pe.torso.pitching ); + torsoAngles[PITCH] = cent->pe.torso.pitchAngle; + + if ( speed ) { + vec3_t axis[3]; + float side; + + speed *= 0.05; + + AnglesToAxis( legsAngles, axis ); + side = speed * DotProduct( velocity, axis[1] ); + legsAngles[ROLL] -= side; + + side = speed * DotProduct( velocity, axis[0] ); + legsAngles[PITCH] += side; + } + + //rww - crazy velocity-based leg angle calculation + legsAngles[YAW] = headAngles[YAW]; + velPos[0] = cent->lerpOrigin[0] + velocity[0]; + velPos[1] = cent->lerpOrigin[1] + velocity[1]; + velPos[2] = cent->lerpOrigin[2];// + velocity[2]; + + if (cent->currentState.groundEntityNum == ENTITYNUM_NONE) + { //off the ground, no direction-based leg angles + VectorCopy(cent->lerpOrigin, velPos); + } + + VectorSubtract(cent->lerpOrigin, velPos, velAng); + + if (!VectorCompare(velAng, vec3_origin)) + { + vectoangles(velAng, velAng); + + if (velAng[YAW] <= legsAngles[YAW]) + { + degrees_negative = (legsAngles[YAW] - velAng[YAW]); + degrees_positive = (360 - legsAngles[YAW]) + velAng[YAW]; + } + else + { + degrees_negative = legsAngles[YAW] + (360 - velAng[YAW]); + degrees_positive = (velAng[YAW] - legsAngles[YAW]); + } + + if (degrees_negative < degrees_positive) + { + dif = degrees_negative; + adddir = 0; + } + else + { + dif = degrees_positive; + adddir = 1; + } + + if (dif > 90) + { + dif = (180 - dif); + } + + if (cent->isATST) + { + if (dif > 360) + { + dif = 360; + } + } + else + { + if (dif > 60) + { + dif = 60; + } + } + + //Slight hack for when playing is running backward + if (dir == 3 || dir == 5) + { + dif = -dif; + } + + if (adddir) + { + legsAngles[YAW] -= dif; + } + else + { + legsAngles[YAW] += dif; + } + } + + cent->pe.legs.yawAngle = legsAngles[YAW]; + legsAngles[YAW] = cent->pe.legs.yawAngle; + + // pain twitch + CG_AddPainTwitch( cent, torsoAngles ); + + legsAngles[ROLL] = 0; + torsoAngles[ROLL] = 0; + + //VectorCopy(legsAngles, cent->turAngles); + //turAngles is used as a smoothing storage vector for g2animents. + + if (cent->isATST) + { + legsAngles[ROLL] = 0; + legsAngles[PITCH] = 0; + } + + // pull the angles back out of the hierarchial chain + AnglesSubtract( headAngles, torsoAngles, headAngles ); + AnglesSubtract( torsoAngles, legsAngles, torsoAngles ); + AnglesToAxis( legsAngles, legs ); + // we assume that model 0 is the player model. + + if (cent->isATST) + { + vec3_t flatYaw; + + flatYaw[YAW] = 0;//cent->lerpAngles[YAW]; + flatYaw[ROLL] = 0; + flatYaw[PITCH] = 0; + CG_G2SetBoneAngles(cent->ghoul2, 0, "pelvis", flatYaw, BONE_ANGLES_POSTMULT, POSITIVE_X, NEGATIVE_Y, NEGATIVE_Z, cgs.gameModels, 0, cg.time); + + CG_G2SetBoneAngles(cent->ghoul2, 0, "thoracic", torsoAngles, BONE_ANGLES_POSTMULT, POSITIVE_X, NEGATIVE_Y, NEGATIVE_Z, cgs.gameModels, 0, cg.time); + + return; + } + + VectorCopy( cent->lerpAngles, viewAngles ); + viewAngles[YAW] = viewAngles[ROLL] = 0; + viewAngles[PITCH] *= 0.5; + + VectorCopy( cent->lerpAngles, angles ); + angles[PITCH] = 0; + + CG_G2AnimEntSpineAngles(cent, viewAngles, angles, thoracicAngles, ulAngles, llAngles); + + ulAngles[YAW] += torsoAngles[YAW]*0.3; + llAngles[YAW] += torsoAngles[YAW]*0.3; + thoracicAngles[YAW] += torsoAngles[YAW]*0.4; + + ulAngles[PITCH] = torsoAngles[PITCH]*0.3; + llAngles[PITCH] = torsoAngles[PITCH]*0.3; + thoracicAngles[PITCH] = torsoAngles[PITCH]*0.4; + + ulAngles[ROLL] += torsoAngles[ROLL]*0.3; + llAngles[ROLL] += torsoAngles[ROLL]*0.3; + thoracicAngles[ROLL] += torsoAngles[ROLL]*0.4; + + CG_G2SetBoneAngles(cent->ghoul2, 0, "upper_lumbar", ulAngles, BONE_ANGLES_POSTMULT, POSITIVE_X, NEGATIVE_Y, NEGATIVE_Z, cgs.gameModels, 0, cg.time); + CG_G2SetBoneAngles(cent->ghoul2, 0, "lower_lumbar", llAngles, BONE_ANGLES_POSTMULT, POSITIVE_X, NEGATIVE_Y, NEGATIVE_Z, cgs.gameModels, 0, cg.time); + CG_G2SetBoneAngles(cent->ghoul2, 0, "thoracic", thoracicAngles, BONE_ANGLES_POSTMULT, POSITIVE_X, NEGATIVE_Y, NEGATIVE_Z, cgs.gameModels, 0, cg.time); + CG_G2SetBoneAngles(cent->ghoul2, 0, "cervical", vec3_origin, BONE_ANGLES_POSTMULT, POSITIVE_X, NEGATIVE_Y, NEGATIVE_Z, cgs.gameModels, 0, cg.time); +} + +#define SMOOTH_G2ANIM_LERPORIGIN + +void CG_DrawNoForceSphere(centity_t *cent, vec3_t origin, float scale, int shader) +{ + refEntity_t ent; + + // Don't draw the shield when the player is dead. + if (cent->currentState.eFlags & EF_DEAD) + { + return; + } + + memset( &ent, 0, sizeof( ent ) ); + + VectorCopy( origin, ent.origin ); + ent.origin[2] += 9.0; + + VectorSubtract(cg.refdef.vieworg, ent.origin, ent.axis[0]); + if (VectorNormalize(ent.axis[0]) <= 0.1f) + { // Entity is right on vieworg. quit. + return; + } + + VectorCopy(cg.refdef.viewaxis[2], ent.axis[2]); + CrossProduct(ent.axis[0], ent.axis[2], ent.axis[1]); + + VectorScale(ent.axis[0], scale, ent.axis[0]); + VectorScale(ent.axis[1], scale, ent.axis[1]); + VectorScale(ent.axis[2], -scale, ent.axis[2]); + + ent.shaderRGBA[3] = (cent->currentState.genericenemyindex - cg.time)/8; + ent.renderfx |= RF_RGB_TINT; + if (ent.shaderRGBA[3] > 200) + { + ent.shaderRGBA[3] = 200; + } + if (ent.shaderRGBA[3] < 1) + { + ent.shaderRGBA[3] = 1; + } + + ent.shaderRGBA[2] = 0; + ent.shaderRGBA[0] = ent.shaderRGBA[1] = ent.shaderRGBA[3]; + + ent.hModel = cgs.media.halfShieldModel; + ent.customShader = shader; + + trap_R_AddRefEntityToScene( &ent ); +} + +void CG_G2Animated( centity_t *cent ) +{ + refEntity_t legs; + refEntity_t torso; + int renderfx = 0; + qboolean shadow = qfalse; + float shadowPlane = 0; + qboolean dead = qfalse; + vec3_t rootAngles; +#ifdef SMOOTH_G2ANIM_LERPORIGIN + vec3_t posDif; + float smoothFactor = 0.4f; + int k = 0; +#endif + + cent->ghoul2 = cg_entities[cent->currentState.number].ghoul2; + + if (!cent->ghoul2) + { //Initialize this g2 anim ent, then return (will start rendering next frame) + const char *modelName = CG_ConfigString( CS_MODELS+cent->currentState.modelindex ); + + if (modelName && modelName[0]) + { + trap_G2API_InitGhoul2Model(¢->ghoul2, modelName, 0, 0, 0, 0, 0); + if (cent->ghoul2) + { + trap_G2API_AddBolt(cent->ghoul2, 0, "*r_hand"); + trap_G2API_AddBolt(cent->ghoul2, 0, "*l_hand"); + trap_G2API_AddBolt(cent->ghoul2, 0, "*head_top"); + trap_G2API_AddBolt(cent->ghoul2, 0, "Motion"); + } + } + return; + } + + if (cent->currentState.weapon && + !trap_G2API_HasGhoul2ModelOnIndex(&(cent->ghoul2), 1) && + !(cent->currentState.eFlags & EF_DEAD)) + { //if the server says we have a weapon and we haven't copied one onto ourselves yet, then do so. + trap_G2API_CopySpecificGhoul2Model(g2WeaponInstances[cent->currentState.weapon], 0, cent->ghoul2, 1); + } + + if (cent->torsoBolt && !(cent->currentState.eFlags & EF_DEAD)) + { //he's alive and has a limb missing still, reattach it and reset the weapon + CG_ReattachLimb(cent); + } + +#ifdef SMOOTH_G2ANIM_LERPORIGIN + if (DistanceSquared(cent->turAngles,cent->lerpOrigin)>12000.0f) + { + VectorCopy(cent->lerpOrigin, cent->turAngles); + } + + VectorSubtract(cent->lerpOrigin, cent->turAngles, posDif); + + for (k=0;k<3;k++) + { + cent->turAngles[k]=(cent->turAngles[k]+posDif[k]*smoothFactor); + cent->lerpOrigin[k]=cent->turAngles[k]; + } +#endif + + if (cent->currentState.weapon) + { + weaponInfo_t *weapon = NULL; + + CG_RegisterWeapon(cent->currentState.weapon); + + weapon = &cg_weapons[cent->currentState.weapon]; + if (weapon) + { + if ( cg.time - cent->muzzleFlashTime <= MUZZLE_FLASH_TIME + 10 ) + { // Handle muzzle flashes + vec3_t flashorigin, flashdir; + mdxaBone_t boltMatrix; + + if (trap_G2API_HasGhoul2ModelOnIndex(&(cent->ghoul2), 1)) + { + vec3_t boltAngle; + VectorClear(boltAngle); + boltAngle[YAW] = cent->lerpAngles[YAW]; + trap_G2API_GetBoltMatrix(cent->ghoul2, 1, 0, &boltMatrix, boltAngle, cent->lerpOrigin, cg.time, cgs.gameModels, cent->modelScale); + + trap_G2API_GiveMeVectorFromMatrix(&boltMatrix, ORIGIN, flashorigin); + trap_G2API_GiveMeVectorFromMatrix(&boltMatrix, POSITIVE_X, flashdir); + + if ( cent->currentState.eFlags & EF_ALT_FIRING ) + { // Check the alt firing first. + if (weapon->altMuzzleEffect) + { + trap_FX_PlayEffectID(weapon->altMuzzleEffect, flashorigin, flashdir); + } + } + else + { // Regular firing + if (weapon->muzzleEffect) + { + trap_FX_PlayEffectID(weapon->muzzleEffect, flashorigin, flashdir); + } + } + } + } + } + } + + memset (&legs, 0, sizeof(legs)); + + CG_SetGhoul2Info(&legs, cent); + + VectorSet(legs.modelScale, 1,1,1); + legs.radius = cent->currentState.g2radius; + VectorClear(legs.angles); + + // add the shadow + shadow = CG_PlayerShadow( cent, &shadowPlane ); + + if ( cg_shadows.integer == 3 && shadow ) { + renderfx |= RF_SHADOW_PLANE; + } + renderfx |= RF_LIGHTING_ORIGIN; // use the same origin for all + + VectorCopy( cent->lerpOrigin, legs.origin ); + VectorCopy( cent->lerpOrigin, legs.lightingOrigin ); + legs.shadowPlane = shadowPlane; + legs.renderfx = renderfx; + VectorCopy (legs.origin, legs.oldorigin); // don't positionally lerp at all + + CG_G2AnimEntAngles( cent, legs.axis, rootAngles ); + + if (cent->currentState.eFlags & EF_DEAD) + { + dead = qtrue; + //rww - since our angles are fixed when we're dead this shouldn't be an issue anyway + //we need to render the dying/dead player because we are now spawning the body on respawn instead of death + //return; + } + + ScaleModelAxis(&legs); + + memset( &torso, 0, sizeof(torso) ); + + VectorCopy(cent->turAngles, cg_entities[cent->currentState.number].turAngles); + VectorCopy(legs.origin, cg_entities[cent->currentState.number].lerpOrigin); + + // get the animation state (after rotation, to allow feet shuffle) + CG_G2EntAnimation( cent, &legs.oldframe, &legs.frame, &legs.backlerp, + &torso.oldframe, &torso.frame, &torso.backlerp ); + + trap_R_AddRefEntityToScene(&legs); + + + // Electricity + //------------------------------------------------ + if ( cent->currentState.emplacedOwner > cg.time ) + { + int dif = cent->currentState.emplacedOwner - cg.time; + + if ( dif > 0 && random() > 0.4f ) + { + // fade out over the last 500 ms + int brightness = 255; + + if ( dif < 500 ) + { + brightness = floor((dif - 500.0f) / 500.0f * 255.0f ); + } + + legs.renderfx &= ~RF_FORCE_ENT_ALPHA; + legs.renderfx &= ~RF_MINLIGHT; + + legs.renderfx |= RF_RGB_TINT; + legs.shaderRGBA[0] = legs.shaderRGBA[1] = legs.shaderRGBA[2] = brightness; + legs.shaderRGBA[3] = 255; + + if ( rand() & 1 ) + { + legs.customShader = cgs.media.electricBodyShader; + } + else + { + legs.customShader = cgs.media.electricBody2Shader; + } + + trap_R_AddRefEntityToScene( &legs ); + + if ( random() > 0.9f ) + trap_S_StartSound ( NULL, cent->currentState.number, CHAN_AUTO, cgs.media.crackleSound ); + } + } + + if (cent->currentState.genericenemyindex > cg.time) + { + CG_DrawNoForceSphere(cent, cent->lerpOrigin, 1.4, cgs.media.ysalimariShader ); + } +} +//rww - here ends the majority of my g2animent stuff. + + /* =============== CG_Player @@ -4207,6 +5604,18 @@ void CG_Player( centity_t *cent ) { { //he's alive and has a limb missing still, reattach it and reset the weapon CG_ReattachLimb(cent); } + else if (cg_entities[cent->currentState.number].torsoBolt && !(cent->currentState.eFlags & EF_DEAD)) + { //It happens. (usually between odd level change events) + cent->torsoBolt = cg_entities[cent->currentState.number].torsoBolt; + cg_entities[cent->currentState.number].torsoBolt = 0; + CG_ReattachLimb(cent); + } + + if (cent->ghoul2 && cent->torsoBolt && (cent->torsoBolt == G2_MODELPART_RARM || cent->torsoBolt == G2_MODELPART_RHAND || cent->torsoBolt == G2_MODELPART_WAIST) && g2HasWeapon) + { //kill the weapon if the limb holding it is no longer on the model + trap_G2API_RemoveGhoul2Model(&(cent->ghoul2), 1); + g2HasWeapon = qfalse; + } if (cent->currentState.teamowner && !cent->isATST) { @@ -4593,6 +6002,9 @@ doEssentialTwo: CG_PlayerAnimation( cent, &legs.oldframe, &legs.frame, &legs.backlerp, &torso.oldframe, &torso.frame, &torso.backlerp ); + // add the talk baloon or disconnect icon + CG_PlayerSprites( cent ); + if (cent->currentState.eFlags & EF_DEAD) { //keep track of death anim frame for when we copy off the bodyqueue cgs.clientinfo[cent->currentState.number].frame = cent->pe.torso.frame; @@ -4786,13 +6198,17 @@ doEssentialTwo: efOrg[1] -= boltDir[1]*4; efOrg[2] -= boltDir[2]*4; - efOrg[2] += 8; + //efOrg[2] += 8; + efOrg[2] -= 4; VectorCopy(efOrg, cent->grip_arm.origin); VectorCopy(cent->grip_arm.origin, cent->grip_arm.lightingOrigin); - VectorCopy(cent->lerpAngles, armAng); - armAng[ROLL] = -90; + //VectorCopy(cent->lerpAngles, armAng); + VectorAdd(vec3_origin, rootAngles, armAng); + //armAng[ROLL] = -90; + armAng[ROLL] = 0; + armAng[PITCH] = 0; AnglesToAxis(armAng, cent->grip_arm.axis); trap_G2API_DuplicateGhoul2Instance(cent->ghoul2, ¢->grip_arm.ghoul2); @@ -4855,51 +6271,58 @@ doEssentialTwo: } } - if (cent->teamPowerEffectTime > cg.time) + if (cg_entities[cent->currentState.number].teamPowerEffectTime > cg.time) { - vec4_t preCol; - int preRFX; - - preRFX = legs.renderfx; - - legs.renderfx |= RF_RGB_TINT; - legs.renderfx |= RF_FORCE_ENT_ALPHA; - - preCol[0] = legs.shaderRGBA[0]; - preCol[1] = legs.shaderRGBA[1]; - preCol[2] = legs.shaderRGBA[2]; - preCol[3] = legs.shaderRGBA[3]; - - if (cent->teamPowerType == 1) - { //heal - legs.shaderRGBA[0] = 0; - legs.shaderRGBA[1] = 255; - legs.shaderRGBA[2] = 0; - } - else if (cent->teamPowerType == 0) - { //regen - legs.shaderRGBA[0] = 0; - legs.shaderRGBA[1] = 0; - legs.shaderRGBA[2] = 255; + if (cg_entities[cent->currentState.number].teamPowerType == 3) + { //absorb is a somewhat different effect entirely + //Guess I'll take care of it where it's always been, just checking these values instead. } else - { //drain - legs.shaderRGBA[0] = 255; - legs.shaderRGBA[1] = 0; - legs.shaderRGBA[2] = 0; + { + vec4_t preCol; + int preRFX; + + preRFX = legs.renderfx; + + legs.renderfx |= RF_RGB_TINT; + legs.renderfx |= RF_FORCE_ENT_ALPHA; + + preCol[0] = legs.shaderRGBA[0]; + preCol[1] = legs.shaderRGBA[1]; + preCol[2] = legs.shaderRGBA[2]; + preCol[3] = legs.shaderRGBA[3]; + + if (cg_entities[cent->currentState.number].teamPowerType == 1) + { //heal + legs.shaderRGBA[0] = 0; + legs.shaderRGBA[1] = 255; + legs.shaderRGBA[2] = 0; + } + else if (cg_entities[cent->currentState.number].teamPowerType == 0) + { //regen + legs.shaderRGBA[0] = 0; + legs.shaderRGBA[1] = 0; + legs.shaderRGBA[2] = 255; + } + else + { //drain + legs.shaderRGBA[0] = 255; + legs.shaderRGBA[1] = 0; + legs.shaderRGBA[2] = 0; + } + + legs.shaderRGBA[3] = ((cg_entities[cent->currentState.number].teamPowerEffectTime - cg.time)/8); + + legs.customShader = trap_R_RegisterShader( "powerups/ysalimarishell" ); + trap_R_AddRefEntityToScene(&legs); + + legs.customShader = 0; + legs.renderfx = preRFX; + legs.shaderRGBA[0] = preCol[0]; + legs.shaderRGBA[1] = preCol[1]; + legs.shaderRGBA[2] = preCol[2]; + legs.shaderRGBA[3] = preCol[3]; } - - legs.shaderRGBA[3] = ((cent->teamPowerEffectTime - cg.time)/8); - - legs.customShader = trap_R_RegisterShader( "powerups/ysalimarishell" ); - trap_R_AddRefEntityToScene(&legs); - - legs.customShader = 0; - legs.renderfx = preRFX; - legs.shaderRGBA[0] = preCol[0]; - legs.shaderRGBA[1] = preCol[1]; - legs.shaderRGBA[2] = preCol[2]; - legs.shaderRGBA[3] = preCol[3]; } //If you've tricked this client. @@ -5477,7 +6900,7 @@ doEssentialThree: } trap_G2API_SetBoneAnim(legs.ghoul2, 0, "model_root", cent->miscTime, cent->miscTime, BONE_ANIM_OVERRIDE_FREEZE, 1.0f, cg.time, cent->miscTime, -1); - trap_G2API_SetBoneAnim(legs.ghoul2, 0, "upper_lumbar", cent->miscTime, cent->miscTime, BONE_ANIM_OVERRIDE_FREEZE, 1.0f, cg.time, cent->miscTime, -1); + trap_G2API_SetBoneAnim(legs.ghoul2, 0, "lower_lumbar", cent->miscTime, cent->miscTime, BONE_ANIM_OVERRIDE_FREEZE, 1.0f, cg.time, cent->miscTime, -1); trap_G2API_SetBoneAnim(legs.ghoul2, 0, "Motion", cent->miscTime, cent->miscTime, BONE_ANIM_OVERRIDE_FREEZE, 1.0f, cg.time, cent->miscTime, -1); VectorCopy(cent->currentState.origin2, hitLoc); @@ -5633,7 +7056,9 @@ doEssentialThree: trap_R_AddRefEntityToScene( &legs ); } - if (cent->currentState.forcePowersActive & (1 << FP_ABSORB)) + //if (cent->currentState.forcePowersActive & (1 << FP_ABSORB)) + //Showing only when the power has been active (absorbed something) recently now, instead of always. + if (cg_entities[cent->currentState.number].teamPowerEffectTime > cg.time && cg_entities[cent->currentState.number].teamPowerType == 3) { //aborb is represented by blue.. legs.shaderRGBA[0] = 0; legs.shaderRGBA[1] = 0; diff --git a/CODE-mp/cgame/cg_public.h b/CODE-mp/cgame/cg_public.h index d533b83..75cd29a 100644 --- a/CODE-mp/cgame/cg_public.h +++ b/CODE-mp/cgame/cg_public.h @@ -49,7 +49,7 @@ functions imported from the main executable ================================================================== */ -#define CGAME_IMPORT_API_VERSION 4 +#define CGAME_IMPORT_API_VERSION 5 typedef enum { CG_PRINT = 0, @@ -104,6 +104,8 @@ typedef enum { CG_R_FONT_STRLENCHARS, CG_R_FONT_STRHEIGHTPIXELS, CG_R_FONT_DRAWSTRING, + CG_LANGUAGE_ISASIAN, + CG_LANGUAGE_USESSPACES, CG_ANYLANGUAGE_READCHARFROMSTRING, CGAME_MEMSET = 100, @@ -216,7 +218,9 @@ Ghoul2 Insert Start CG_G2_GIVEMEVECTORFROMMATRIX, CG_G2_GETBOLT, CG_G2_GETBOLT_NOREC, + CG_G2_GETBOLT_NOREC_NOROT, CG_G2_INITGHOUL2MODEL, + CG_G2_COLLISIONDETECT, CG_G2_CLEANMODELS, CG_G2_ANGLEOVERRIDE, CG_G2_PLAYANIM, diff --git a/CODE-mp/cgame/cg_scoreboard.c b/CODE-mp/cgame/cg_scoreboard.c index aa4f940..5224d11 100644 --- a/CODE-mp/cgame/cg_scoreboard.c +++ b/CODE-mp/cgame/cg_scoreboard.c @@ -173,7 +173,7 @@ static void CG_DrawClientScore( int y, score_t *score, float *color, float fade, // add the "ready" marker for intermission exiting if ( cg.snap->ps.stats[ STAT_CLIENTS_READY ] & ( 1 << score->client ) ) { - CG_Text_Paint (SB_NAME_X - 64, y + 2, 0.7f * scale, colorWhite, "READY" ,0, 0, ITEM_TEXTSTYLE_OUTLINED, FONT_MEDIUM ); + CG_Text_Paint (SB_NAME_X - 64, y + 2, 0.7f * scale, colorWhite, CG_GetStripEdString("INGAMETEXT", "READY"),0, 0, ITEM_TEXTSTYLE_OUTLINED, FONT_MEDIUM ); } } @@ -257,11 +257,6 @@ qboolean CG_DrawOldScoreboard( void ) { return qfalse; } - if ( cgs.gametype == GT_SINGLE_PLAYER && cg.predictedPlayerState.pm_type == PM_INTERMISSION ) { - cg.deferredPlayerLoading = 0; - return qfalse; - } - // don't draw scoreboard during death while warmup up if ( cg.warmup && !cg.showScores ) { return qfalse; @@ -371,7 +366,10 @@ qboolean CG_DrawOldScoreboard( void ) { CG_Text_Paint ( SB_NAME_X, y, 1.0f, colorWhite, "Name", 0, 0, ITEM_TEXTSTYLE_OUTLINED, FONT_MEDIUM ); if (cgs.gametype == GT_TOURNAMENT) { - CG_Text_Paint ( SB_SCORE_X, y, 1.0f, colorWhite, "W/L", 0, 0, ITEM_TEXTSTYLE_OUTLINED, FONT_MEDIUM ); + char sWL[100]; + trap_SP_GetStringTextString("INGAMETEXT_W_L", sWL, sizeof(sWL)); + + CG_Text_Paint ( SB_SCORE_X, y, 1.0f, colorWhite, sWL, 0, 0, ITEM_TEXTSTYLE_OUTLINED, FONT_MEDIUM ); } else { diff --git a/CODE-mp/cgame/cg_servercmds.c b/CODE-mp/cgame/cg_servercmds.c index 85ef985..87b7c7e 100644 --- a/CODE-mp/cgame/cg_servercmds.c +++ b/CODE-mp/cgame/cg_servercmds.c @@ -61,6 +61,8 @@ static void CG_ParseScores( void ) { cg.numScores = MAX_CLIENTS; } + cg.numScores = readScores; + cg.teamScores[0] = atoi( CG_Argv( 2 ) ); cg.teamScores[1] = atoi( CG_Argv( 3 ) ); @@ -525,7 +527,7 @@ void CG_KillCEntityInstances() cg_entities[i].frame_minus2_refreshed = 0; cg_entities[i].dustTrailTime = 0; cg_entities[i].ghoul2weapon = NULL; - cg_entities[i].torsoBolt = 0; +// cg_entities[i].torsoBolt = 0; cg_entities[i].trailTime = 0; cg_entities[i].frame_hold_time = 0; cg_entities[i].frame_hold_refreshed = 0; diff --git a/CODE-mp/cgame/cg_syscalls.asm b/CODE-mp/cgame/cg_syscalls.asm index e01be71..a3b2fc0 100644 --- a/CODE-mp/cgame/cg_syscalls.asm +++ b/CODE-mp/cgame/cg_syscalls.asm @@ -52,7 +52,9 @@ equ trap_R_Font_StrLenPixels -49 ; CG_R_FONT_STRLENPIXELS equ trap_R_Font_StrLenChars -50 ; CG_R_FONT_STRLENCHARS equ trap_R_Font_HeightPixels -51 ; CG_R_FONT_STRHEIGHTPIXELS equ trap_R_Font_DrawString -52 ; CG_R_FONT_DRAWSTRING -equ trap_AnyLanguage_ReadCharFromString -53 ; CG_ANYLANGUAGE_READCHARFROMSTRING +equ trap_Language_IsAsian -53 ; CG_LANGUAGE_ISASIAN +equ trap_Language_UsesSpaces -54 ; CG_LANGUAGE_USESSPACES +equ trap_AnyLanguage_ReadCharFromString -55 ; CG_ANYLANGUAGE_READCHARFROMSTRING equ trap_R_ClearScene -201 ; CG_R_CLEARSCENE equ trap_R_AddRefEntityToScene -202 ; CG_R_ADDREFENTITYTOSCENE equ trap_R_AddPolyToScene -203 ; CG_R_ADDPOLYTOSCENE @@ -136,22 +138,24 @@ equ trap_G2_HaveWeGhoul2Models -282 ; CG_G2_HAVEWEGHOULMODELS equ trap_G2API_GiveMeVectorFromMatrix -283 ; CG_G2_GIVEMEVECTORFROMMATRIX equ trap_G2API_GetBoltMatrix -284 ; CG_G2_GETBOLT equ trap_G2API_GetBoltMatrix_NoReconstruct -285 ; CG_G2_GETBOLT_NOREC -equ trap_G2API_InitGhoul2Model -286 ; CG_G2_INITGHOUL2MODEL -equ trap_G2API_CleanGhoul2Models -287 ; CG_G2_CLEANMODELS -equ trap_G2API_SetBoneAngles -288 ; CG_G2_ANGLEOVERRIDE -equ trap_G2API_SetBoneAnim -289 ; CG_G2_PLAYANIM -equ trap_G2API_GetGLAName -290 ; CG_G2_GETGLANAME -equ trap_G2API_CopyGhoul2Instance -291 ; CG_G2_COPYGHOUL2INSTANCE -equ trap_G2API_CopySpecificGhoul2Model -292 ; CG_G2_COPYSPECIFICGHOUL2MODEL -equ trap_G2API_DuplicateGhoul2Instance -293 ; CG_G2_DUPLICATEGHOUL2INSTANCE -equ trap_G2API_HasGhoul2ModelOnIndex -294 ; CG_G2_HASGHOUL2MODELONINDEX -equ trap_G2API_RemoveGhoul2Model -295 ; CG_G2_REMOVEGHOUL2MODEL -equ trap_G2API_AddBolt -296 ; CG_G2_ADDBOLT -equ trap_G2API_SetBoltInfo -297 ; CG_G2_SETBOLTON -equ trap_G2API_SetRootSurface -298 ; CG_G2_SETROOTSURFACE -equ trap_G2API_SetSurfaceOnOff -299 ; CG_G2_SETSURFACEONOFF -equ trap_G2API_SetNewOrigin -300 ; CG_G2_SETNEWORIGIN -equ trap_CG_RegisterSharedMemory -301 ; CG_SET_SHARED_BUFFER +equ trap_G2API_GetBoltMatrix_NoRecNoRot -286 ; CG_G2_GETBOLT_NOREC_NOROT +equ trap_G2API_InitGhoul2Model -287 ; CG_G2_INITGHOUL2MODEL +equ trap_G2API_CollisionDetect -288 ; CG_G2_COLLISIONDETECT +equ trap_G2API_CleanGhoul2Models -289 ; CG_G2_CLEANMODELS +equ trap_G2API_SetBoneAngles -290 ; CG_G2_ANGLEOVERRIDE +equ trap_G2API_SetBoneAnim -291 ; CG_G2_PLAYANIM +equ trap_G2API_GetGLAName -292 ; CG_G2_GETGLANAME +equ trap_G2API_CopyGhoul2Instance -293 ; CG_G2_COPYGHOUL2INSTANCE +equ trap_G2API_CopySpecificGhoul2Model -294 ; CG_G2_COPYSPECIFICGHOUL2MODEL +equ trap_G2API_DuplicateGhoul2Instance -295 ; CG_G2_DUPLICATEGHOUL2INSTANCE +equ trap_G2API_HasGhoul2ModelOnIndex -296 ; CG_G2_HASGHOUL2MODELONINDEX +equ trap_G2API_RemoveGhoul2Model -297 ; CG_G2_REMOVEGHOUL2MODEL +equ trap_G2API_AddBolt -298 ; CG_G2_ADDBOLT +equ trap_G2API_SetBoltInfo -299 ; CG_G2_SETBOLTON +equ trap_G2API_SetRootSurface -300 ; CG_G2_SETROOTSURFACE +equ trap_G2API_SetSurfaceOnOff -301 ; CG_G2_SETSURFACEONOFF +equ trap_G2API_SetNewOrigin -302 ; CG_G2_SETNEWORIGIN +equ trap_CG_RegisterSharedMemory -303 ; CG_SET_SHARED_BUFFER ; hardcoded functions diff --git a/CODE-mp/cgame/cg_syscalls.c b/CODE-mp/cgame/cg_syscalls.c index 4ffd644..8c0752c 100644 --- a/CODE-mp/cgame/cg_syscalls.c +++ b/CODE-mp/cgame/cg_syscalls.c @@ -244,9 +244,19 @@ void trap_R_Font_DrawString(int ox, int oy, const char *text, const float *rgba, syscall( CG_R_FONT_DRAWSTRING, ox, oy, text, rgba, setIndex, iCharLimit, PASSFLOAT(scale)); } -unsigned int trap_AnyLanguage_ReadCharFromString( const char **ppText ) +qboolean trap_Language_IsAsian(void) { - return syscall( CG_ANYLANGUAGE_READCHARFROMSTRING, ppText); + return syscall( CG_LANGUAGE_ISASIAN ); +} + +qboolean trap_Language_UsesSpaces(void) +{ + return syscall( CG_LANGUAGE_USESSPACES ); +} + +unsigned int trap_AnyLanguage_ReadCharFromString( const char *psText, int *piAdvanceCount, qboolean *pbIsTrailingPunctuation/* = NULL*/ ) +{ + return syscall( CG_ANYLANGUAGE_READCHARFROMSTRING, psText, piAdvanceCount, pbIsTrailingPunctuation); } void trap_R_ClearScene( void ) { @@ -659,12 +669,36 @@ qboolean trap_G2API_GetBoltMatrix_NoReconstruct(void *ghoul2, const int modelInd return (qboolean)(syscall(CG_G2_GETBOLT_NOREC, ghoul2, modelIndex, boltIndex, matrix, angles, position, frameNum, modelList, scale)); } +qboolean trap_G2API_GetBoltMatrix_NoRecNoRot(void *ghoul2, const int modelIndex, const int boltIndex, mdxaBone_t *matrix, + const vec3_t angles, const vec3_t position, const int frameNum, qhandle_t *modelList, vec3_t scale) +{ //Same as above but force it to not reconstruct the skeleton before getting the bolt position + return (qboolean)(syscall(CG_G2_GETBOLT_NOREC_NOROT, ghoul2, modelIndex, boltIndex, matrix, angles, position, frameNum, modelList, scale)); +} + int trap_G2API_InitGhoul2Model(void **ghoul2Ptr, const char *fileName, int modelIndex, qhandle_t customSkin, qhandle_t customShader, int modelFlags, int lodBias) { return syscall(CG_G2_INITGHOUL2MODEL, ghoul2Ptr, fileName, modelIndex, customSkin, customShader, modelFlags, lodBias); } +void trap_G2API_CollisionDetect ( + CollisionRecord_t *collRecMap, + void* ghoul2, + const vec3_t angles, + const vec3_t position, + int frameNumber, + int entNum, + const vec3_t rayStart, + const vec3_t rayEnd, + const vec3_t scale, + int traceFlags, + int useLod, + float fRadius + ) +{ + syscall ( CG_G2_COLLISIONDETECT, collRecMap, ghoul2, angles, position, frameNumber, entNum, rayStart, rayEnd, scale, traceFlags, useLod, PASSFLOAT(fRadius) ); +} + void trap_G2API_CleanGhoul2Models(void **ghoul2Ptr) { syscall(CG_G2_CLEANMODELS, ghoul2Ptr); diff --git a/CODE-mp/cgame/cg_weapons.c b/CODE-mp/cgame/cg_weapons.c index 4249514..7466b34 100644 --- a/CODE-mp/cgame/cg_weapons.c +++ b/CODE-mp/cgame/cg_weapons.c @@ -1417,50 +1417,36 @@ void CG_Weapon_f( void ) { if (num >= WP_THERMAL) { - int prenum = 0; - int loopback = 0; + int weap, i = 0; if (cg.snap->ps.weapon >= WP_THERMAL && cg.snap->ps.weapon <= WP_DET_PACK) { - num = cg.snap->ps.weapon; - prenum = num; - num++; + // already in cycle range so start with next cycle item + weap = cg.snap->ps.weapon + 1; } else { - prenum = num; + // not in cycle range, so start with thermal detonator + weap = WP_THERMAL; } - if (num > WP_DET_PACK) + // prevent an endless loop + while ( i <= 4 ) { - num = WP_THERMAL; - } - - while (prenum != num || !loopback) - { - if (num > WP_DET_PACK) + if (weap > WP_DET_PACK) { - num = WP_THERMAL; - loopback = 1; + weap = WP_THERMAL; } - if (CG_WeaponSelectable(num)) + if (CG_WeaponSelectable(weap)) { + num = weap; break; } - if (num == prenum) - { - break; - } - - num++; - } - - if (num > WP_DET_PACK) - { - num = WP_THERMAL; + weap++; + i++; } } diff --git a/CODE-mp/cgame/vssver.scc b/CODE-mp/cgame/vssver.scc index 41f72b7..7c98f9c 100644 Binary files a/CODE-mp/cgame/vssver.scc and b/CODE-mp/cgame/vssver.scc differ diff --git a/CODE-mp/client/OpenAL/al.h b/CODE-mp/client/OpenAL/al.h new file mode 100644 index 0000000..e4f5a27 --- /dev/null +++ b/CODE-mp/client/OpenAL/al.h @@ -0,0 +1,490 @@ +#ifndef _AL_H_ +#define _AL_H_ + +/** + * OpenAL cross platform audio library + * Copyright (C) 1999-2000 by authors. + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * Or go to http://www.gnu.org/copyleft/lgpl.html + */ +#include "altypes.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef _WIN32 + #ifdef _OPENAL32LIB + #define ALAPI __declspec(dllexport) + #else + #define ALAPI __declspec(dllimport) + #endif + #define ALAPIENTRY __cdecl + #define AL_CALLBACK +#else + #ifdef TARGET_OS_MAC + #if TARGET_OS_MAC + #pragma export on + #endif + #endif + #define ALAPI + #define ALAPIENTRY __cdecl + #define AL_CALLBACK +#endif + +#define OPENAL + +#ifndef AL_NO_PROTOTYPES + +/** + * OpenAL Maintenance Functions + * Initialization and exiting. + * State Management and Query. + * Error Handling. + * Extension Support. + */ + +/** State management. */ +ALAPI ALvoid ALAPIENTRY alEnable( ALenum capability ); +ALAPI ALvoid ALAPIENTRY alDisable( ALenum capability ); +ALAPI ALboolean ALAPIENTRY alIsEnabled( ALenum capability ); + +/** Application preferences for driver performance choices. */ +ALAPI ALvoid ALAPIENTRY alHint( ALenum target, ALenum mode ); + +/** State retrieval. */ +ALAPI ALboolean ALAPIENTRY alGetBoolean( ALenum param ); +ALAPI ALint ALAPIENTRY alGetInteger( ALenum param ); +ALAPI ALfloat ALAPIENTRY alGetFloat( ALenum param ); +ALAPI ALdouble ALAPIENTRY alGetDouble( ALenum param ); +ALAPI ALvoid ALAPIENTRY alGetBooleanv( ALenum param, ALboolean* data ); +ALAPI ALvoid ALAPIENTRY alGetIntegerv( ALenum param, ALint* data ); +ALAPI ALvoid ALAPIENTRY alGetFloatv( ALenum param, ALfloat* data ); +ALAPI ALvoid ALAPIENTRY alGetDoublev( ALenum param, ALdouble* data ); +ALAPI ALubyte* ALAPIENTRY alGetString( ALenum param ); + +/** + * Error support. + * Obtain the most recent error generated in the AL state machine. + */ +ALAPI ALenum ALAPIENTRY alGetError( ALvoid ); + + +/** + * Extension support. + * Obtain the address of a function (usually an extension) + * with the name fname. All addresses are context-independent. + */ +ALAPI ALboolean ALAPIENTRY alIsExtensionPresent( ALubyte* fname ); + + +/** + * Extension support. + * Obtain the address of a function (usually an extension) + * with the name fname. All addresses are context-independent. + */ +ALAPI ALvoid* ALAPIENTRY alGetProcAddress( ALubyte* fname ); + + +/** + * Extension support. + * Obtain the integer value of an enumeration (usually an extension) with the name ename. + */ +ALAPI ALenum ALAPIENTRY alGetEnumValue( ALubyte* ename ); + + + + +/** + * LISTENER + * Listener is the sample position for a given context. + * The multi-channel (usually stereo) output stream generated + * by the mixer is parametrized by this Listener object: + * its position and velocity relative to Sources, within + * occluder and reflector geometry. + */ + + + +/** + * + * Listener Environment: default 0. + */ +ALAPI ALvoid ALAPIENTRY alListeneri( ALenum param, ALint value ); + + +/** + * + * Listener Gain: default 1.0f. + */ +ALAPI ALvoid ALAPIENTRY alListenerf( ALenum param, ALfloat value ); + + +/** + * + * Listener Position. + * Listener Velocity. + */ +ALAPI ALvoid ALAPIENTRY alListener3f( ALenum param, ALfloat v1, ALfloat v2, ALfloat v3 ); + + +/** + * + * Listener Position: ALfloat[3] + * Listener Velocity: ALfloat[3] + * Listener Orientation: ALfloat[6] (forward and up vector). + */ +ALAPI ALvoid ALAPIENTRY alListenerfv( ALenum param, ALfloat* values ); + +ALAPI ALvoid ALAPIENTRY alGetListeneri( ALenum param, ALint* value ); +ALAPI ALvoid ALAPIENTRY alGetListenerf( ALenum param, ALfloat* value ); +ALAPI ALvoid ALAPIENTRY alGetListener3f( ALenum param, ALfloat* v1, ALfloat* v2, ALfloat* v3 ); +ALAPI ALvoid ALAPIENTRY alGetListenerfv( ALenum param, ALfloat* values ); + + +/** + * SOURCE + * Source objects are by default localized. Sources + * take the PCM data provided in the specified Buffer, + * apply Source-specific modifications, and then + * submit them to be mixed according to spatial + * arrangement etc. + */ + + + +/** Create Source objects. */ +ALAPI ALvoid ALAPIENTRY alGenSources( ALsizei n, ALuint* sources ); + +/** Delete Source objects. */ +ALAPI ALvoid ALAPIENTRY alDeleteSources( ALsizei n, ALuint* sources ); + +/** Verify a handle is a valid Source. */ +ALAPI ALboolean ALAPIENTRY alIsSource( ALuint id ); + +/** Set an integer parameter for a Source object. */ +ALAPI ALvoid ALAPIENTRY alSourcei( ALuint source, ALenum param, ALint value ); +ALAPI ALvoid ALAPIENTRY alSourcef( ALuint source, ALenum param, ALfloat value ); +ALAPI ALvoid ALAPIENTRY alSource3f( ALuint source, ALenum param, ALfloat v1, ALfloat v2, ALfloat v3 ); +ALAPI ALvoid ALAPIENTRY alSourcefv( ALuint source, ALenum param, ALfloat* values ); + +/** Get an integer parameter for a Source object. */ +ALAPI ALvoid ALAPIENTRY alGetSourcei( ALuint source, ALenum param, ALint* value ); +ALAPI ALvoid ALAPIENTRY alGetSourcef( ALuint source, ALenum param, ALfloat* value ); +ALAPI ALvoid ALAPIENTRY alGetSource3f( ALuint source, ALenum param, ALfloat* v1, ALfloat* v2, ALfloat* v3 ); +ALAPI ALvoid ALAPIENTRY alGetSourcefv( ALuint source, ALenum param, ALfloat* values ); + +ALAPI ALvoid ALAPIENTRY alSourcePlayv( ALsizei n, ALuint *sources ); +ALAPI ALvoid ALAPIENTRY alSourcePausev( ALsizei n, ALuint *sources ); +ALAPI ALvoid ALAPIENTRY alSourceStopv( ALsizei n, ALuint *sources ); +ALAPI ALvoid ALAPIENTRY alSourceRewindv(ALsizei n,ALuint *sources); + +/** Activate a source, start replay. */ +ALAPI ALvoid ALAPIENTRY alSourcePlay( ALuint source ); + +/** + * Pause a source, + * temporarily remove it from the mixer list. + */ +ALAPI ALvoid ALAPIENTRY alSourcePause( ALuint source ); + +/** + * Stop a source, + * temporarily remove it from the mixer list, + * and reset its internal state to pre-Play. + * To remove a Source completely, it has to be + * deleted following Stop, or before Play. + */ +ALAPI ALvoid ALAPIENTRY alSourceStop( ALuint source ); + +/** + * Rewinds a source, + * temporarily remove it from the mixer list, + * and reset its internal state to pre-Play. + */ +ALAPI ALvoid ALAPIENTRY alSourceRewind( ALuint source ); + + + +/** + * BUFFER + * Buffer objects are storage space for sample data. + * Buffers are referred to by Sources. There can be more than + * one Source using the same Buffer data. If Buffers have + * to be duplicated on a per-Source basis, the driver has to + * take care of allocation, copying, and deallocation as well + * as propagating buffer data changes. + */ + + + + +/** Buffer object generation. */ +ALAPI ALvoid ALAPIENTRY alGenBuffers( ALsizei n, ALuint* buffers ); +ALAPI ALvoid ALAPIENTRY alDeleteBuffers( ALsizei n, ALuint* buffers ); +ALAPI ALboolean ALAPIENTRY alIsBuffer( ALuint buffer ); + +/** + * Specify the data to be filled into a buffer. + */ +ALAPI ALvoid ALAPIENTRY alBufferData( ALuint buffer, + ALenum format, + ALvoid* data, + ALsizei size, + ALsizei freq ); + + +ALAPI ALvoid ALAPIENTRY alGetBufferi( ALuint buffer, ALenum param, ALint* value ); +ALAPI ALvoid ALAPIENTRY alGetBufferf( ALuint buffer, ALenum param, ALfloat* value ); + + + + +/** + * Queue stuff + */ + +ALAPI ALvoid ALAPIENTRY alSourceQueueBuffers( ALuint source, ALsizei n, ALuint* buffers ); +ALAPI ALvoid ALAPIENTRY alSourceUnqueueBuffers( ALuint source, ALsizei n, ALuint* buffers ); + +/** + * Knobs and dials + */ +ALAPI ALvoid ALAPIENTRY alDistanceModel( ALenum value ); +ALAPI ALvoid ALAPIENTRY alDopplerFactor( ALfloat value ); +ALAPI ALvoid ALAPIENTRY alDopplerVelocity( ALfloat value ); + +#else /* AL_NO_PROTOTYPES */ + +/** + * OpenAL Maintenance Functions + * Initialization and exiting. + * State Management and Query. + * Error Handling. + * Extension Support. + */ + +/** State management. */ +ALAPI ALvoid ALAPIENTRY (*alEnable)( ALenum capability ); +ALAPI ALvoid ALAPIENTRY (*alDisable)( ALenum capability ); +ALAPI ALboolean ALAPIENTRY (*alIsEnabled)( ALenum capability ); + +/** Application preferences for driver performance choices. */ +ALAPI ALvoid ALAPIENTRY (*alHint)( ALenum target, ALenum mode ); + +/** State retrieval. */ +ALAPI ALboolean ALAPIENTRY (*alGetBoolean)( ALenum param ); +ALAPI ALint ALAPIENTRY (*alGetInteger)( ALenum param ); +ALAPI ALfloat ALAPIENTRY (*alGetFloat)( ALenum param ); +ALAPI ALdouble ALAPIENTRY (*alGetDouble)( ALenum param ); +ALAPI ALvoid ALAPIENTRY (*alGetBooleanv)( ALenum param, ALboolean* data ); +ALAPI ALvoid ALAPIENTRY (*alGetIntegerv)( ALenum param, ALint* data ); +ALAPI ALvoid ALAPIENTRY (*alGetFloatv)( ALenum param, ALfloat* data ); +ALAPI ALvoid ALAPIENTRY (*alGetDoublev)( ALenum param, ALdouble* data ); +ALAPI ALubyte* ALAPIENTRY (*alGetString)( ALenum param ); + +/** + * Error support. + * Obtain the most recent error generated in the AL state machine. + */ +ALAPI ALenum ALAPIENTRY (*alGetError)( ALvoid ); + + +/** + * Extension support. + * Obtain the address of a function (usually an extension) + * with the name fname. All addresses are context-independent. + */ +ALAPI ALboolean ALAPIENTRY (*alIsExtensionPresent)( ALubyte* fname ); + + +/** + * Extension support. + * Obtain the address of a function (usually an extension) + * with the name fname. All addresses are context-independent. + */ +ALAPI ALvoid* ALAPIENTRY (*alGetProcAddress)( ALubyte* fname ); + + +/** + * Extension support. + * Obtain the integer value of an enumeration (usually an extension) with the name ename. + */ +ALAPI ALenum ALAPIENTRY (*alGetEnumValue)( ALubyte* ename ); + + + + +/** + * LISTENER + * Listener is the sample position for a given context. + * The multi-channel (usually stereo) output stream generated + * by the mixer is parametrized by this Listener object: + * its position and velocity relative to Sources, within + * occluder and reflector geometry. + */ + + + +/** + * + * Listener Environment: default 0. + */ +ALAPI ALvoid ALAPIENTRY (*alListeneri)( ALenum param, ALint value ); + + +/** + * + * Listener Gain: default 1.0f. + */ +ALAPI ALvoid ALAPIENTRY (*alListenerf)( ALenum param, ALfloat value ); + + +/** + * + * Listener Position. + * Listener Velocity. + */ +ALAPI ALvoid ALAPIENTRY (*alListener3f)( ALenum param, ALfloat v1, ALfloat v2, ALfloat v3 ); + + +/** + * + * Listener Position: ALfloat[3] + * Listener Velocity: ALfloat[3] + * Listener Orientation: ALfloat[6] (forward and up vector). + */ +ALAPI ALvoid ALAPIENTRY (*alListenerfv)( ALenum param, ALfloat* values ); + +ALAPI ALvoid ALAPIENTRY (*alGetListeneri)( ALenum param, ALint* value ); +ALAPI ALvoid ALAPIENTRY (*alGetListenerf)( ALenum param, ALfloat* value ); +ALAPI ALvoid ALAPIENTRY (*alGetListener3f)( ALenum param, ALfloat* v1, ALfloat* v2, ALfloat* v3 ); +ALAPI ALvoid ALAPIENTRY (*alGetListenerfv)( ALenum param, ALfloat* values ); + + +/** + * SOURCE + * Source objects are by default localized. Sources + * take the PCM data provided in the specified Buffer, + * apply Source-specific modifications, and then + * submit them to be mixed according to spatial + * arrangement etc. + */ + + + +/** Create Source objects. */ +ALAPI ALvoid ALAPIENTRY (*alGenSources)( ALsizei n, ALuint* sources ); + +/** Delete Source objects. */ +ALAPI ALvoid ALAPIENTRY (*alDeleteSources)( ALsizei n, ALuint* sources ); + +/** Verify a handle is a valid Source. */ +ALAPI ALboolean ALAPIENTRY (*alIsSource)( ALuint id ); + +/** Set an integer parameter for a Source object. */ +ALAPI ALvoid ALAPIENTRY (*alSourcei)( ALuint source, ALenum param, ALint value ); +ALAPI ALvoid ALAPIENTRY (*alSourcef)( ALuint source, ALenum param, ALfloat value ); +ALAPI ALvoid ALAPIENTRY (*alSource3f)( ALuint source, ALenum param, ALfloat v1, ALfloat v2, ALfloat v3 ); +ALAPI ALvoid ALAPIENTRY (*alSourcefv)( ALuint source, ALenum param, ALfloat* values ); + +/** Get an integer parameter for a Source object. */ +ALAPI ALvoid ALAPIENTRY (*alGetSourcei)( ALuint source, ALenum param, ALint* value ); +ALAPI ALvoid ALAPIENTRY (*alGetSourcef)( ALuint source, ALenum param, ALfloat* value ); +ALAPI ALvoid ALAPIENTRY (*alGetSourcefv)( ALuint source, ALenum param, ALfloat* values ); + +ALAPI ALvoid ALAPIENTRY (*alSourcePlayv)( ALsizei n, ALuint *sources ); +ALAPI ALvoid ALAPIENTRY (*alSourceStopv)( ALsizei n, ALuint *sources ); + +/** Activate a source, start replay. */ +ALAPI ALvoid ALAPIENTRY (*alSourcePlay)( ALuint source ); + +/** + * Pause a source, + * temporarily remove it from the mixer list. + */ +ALAPI ALvoid ALAPIENTRY (*alSourcePause)( ALuint source ); + +/** + * Stop a source, + * temporarily remove it from the mixer list, + * and reset its internal state to pre-Play. + * To remove a Source completely, it has to be + * deleted following Stop, or before Play. + */ +ALAPI ALvoid ALAPIENTRY (*alSourceStop)( ALuint source ); + + + +/** + * BUFFER + * Buffer objects are storage space for sample data. + * Buffers are referred to by Sources. There can be more than + * one Source using the same Buffer data. If Buffers have + * to be duplicated on a per-Source basis, the driver has to + * take care of allocation, copying, and deallocation as well + * as propagating buffer data changes. + */ + + + + +/** Buffer object generation. */ +ALAPI ALvoid ALAPIENTRY (*alGenBuffers)( ALsizei n, ALuint* buffers ); +ALAPI ALvoid ALAPIENTRY (*alDeleteBuffers)( ALsizei n, ALuint* buffers ); +ALAPI ALboolean ALAPIENTRY (*alIsBuffer)( ALuint buffer ); + +/** + * Specify the data to be filled into a buffer. + */ +ALAPI ALvoid ALAPIENTRY (*alBufferData)( ALuint buffer, + ALenum format, + ALvoid* data, + ALsizei size, + ALsizei freq ); + +ALAPI ALvoid ALAPIENTRY (*alGetBufferi)( ALuint buffer, ALenum param, ALint* value ); +ALAPI ALvoid ALAPIENTRY (*alGetBufferf)( ALuint buffer, ALenum param, ALfloat* value ); + + + + +/** + * Queue stuff + */ +ALAPI ALvoid ALAPIENTRY (*alSourceQueueBuffers)( ALuint source, ALsizei n, ALuint* buffers ); +ALAPI ALvoid ALAPIENTRY (*alSourceUnqueueBuffers)( ALuint source, ALsizei n, ALuint* buffers ); + +/** + * Knobs and dials + */ +ALAPI ALvoid ALAPIENTRY (*alDistanceModel)( ALenum value ); +ALAPI ALvoid ALAPIENTRY (*alDopplerFactor)( ALfloat value ); +ALAPI ALvoid ALAPIENTRY (*alDopplerVelocity)( ALfloat value ); + +#endif /* AL_NO_PROTOTYPES */ + +#ifdef TARGET_OS_MAC + #if TARGET_OS_MAC + #pragma export off + #endif +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/CODE-mp/client/OpenAL/alc.h b/CODE-mp/client/OpenAL/alc.h new file mode 100644 index 0000000..32c664c --- /dev/null +++ b/CODE-mp/client/OpenAL/alc.h @@ -0,0 +1,90 @@ +#ifndef _ALC_H_ +#define _ALC_H_ + +#include "altypes.h" +#include "alctypes.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef _WIN32 + #ifdef _OPENAL32LIB + #define ALCAPI __declspec(dllexport) + #else + #define ALCAPI __declspec(dllimport) + #endif + + typedef struct ALCdevice_struct ALCdevice; + typedef struct ALCcontext_struct ALCcontext; + + #define ALCAPIENTRY __cdecl +#else + #ifdef TARGET_OS_MAC + #if TARGET_OS_MAC + #pragma export on + #endif + #endif + #define ALCAPI + #define ALCAPIENTRY __cdecl +#endif + + + +#ifndef ALC_NO_PROTOTYPES + +ALCAPI ALCubyte* ALCAPIENTRY alcGetString(ALCdevice *device,ALCenum param); +ALCAPI ALCvoid ALCAPIENTRY alcGetIntegerv(ALCdevice *device,ALCenum param,ALCsizei size,ALCint *data); + +ALCAPI ALCdevice* ALCAPIENTRY alcOpenDevice(ALCubyte *deviceName); +ALCAPI ALCvoid ALCAPIENTRY alcCloseDevice(ALCdevice *device); + +ALCAPI ALCcontext*ALCAPIENTRY alcCreateContext(ALCdevice *device,ALCint *attrList); +ALCAPI ALCboolean ALCAPIENTRY alcMakeContextCurrent(ALCcontext *context); +ALCAPI ALCvoid ALCAPIENTRY alcProcessContext(ALCcontext *context); +ALCAPI ALCcontext*ALCAPIENTRY alcGetCurrentContext(ALCvoid); +ALCAPI ALCdevice* ALCAPIENTRY alcGetContextsDevice(ALCcontext *context); +ALCAPI ALCvoid ALCAPIENTRY alcSuspendContext(ALCcontext *context); +ALCAPI ALCvoid ALCAPIENTRY alcDestroyContext(ALCcontext *context); + +ALCAPI ALCenum ALCAPIENTRY alcGetError(ALCdevice *device); + +ALCAPI ALCboolean ALCAPIENTRY alcIsExtensionPresent(ALCdevice *device,ALCubyte *extName); +ALCAPI ALCvoid * ALCAPIENTRY alcGetProcAddress(ALCdevice *device,ALCubyte *funcName); +ALCAPI ALCenum ALCAPIENTRY alcGetEnumValue(ALCdevice *device,ALCubyte *enumName); + +#else /* AL_NO_PROTOTYPES */ + +ALCAPI ALCubyte* ALCAPIENTRY (*alcGetString)(ALCdevice *device,ALCenum param); +ALCAPI ALCvoid ALCAPIENTRY (*alcGetIntegerv)(ALCdevice * device,ALCenum param,ALCsizei size,ALCint *data); + +ALCAPI ALCdevice* ALCAPIENTRY (*alcOpenDevice)(ALubyte *deviceName); +ALCAPI ALCvoid ALCAPIENTRY (*alcCloseDevice)(ALCdevice *device); + +ALCAPI ALCcontext*ALCAPIENTRY (*alcCreateContext)(ALCdevice *device,ALCint *attrList); +ALCAPI ALCboolean ALCAPIENTRY (*alcMakeContextCurrent)(ALCcontext *context); +ALCAPI ALCvoid ALCAPIENTRY (*alcProcessContext)(ALCcontext *context); +ALCAPI ALCcontext*ALCAPIENTRY (*alcGetCurrentContext)(ALCvoid); +ALCAPI ALCdevice* ALCAPIENTRY (*alcGetContextsDevice)(ALCcontext *context); +ALCAPI ALCvoid ALCAPIENTRY (*alcSuspendContext)(ALCcontext *context); +ALCAPI ALCvoid ALCAPIENTRY (*alcDestroyContext)(ALCcontext *context); + +ALCAPI ALCenum ALCAPIENTRY (*alcGetError)(ALCdevice *device); + +ALCAPI ALCboolean ALCAPIENTRY (*alcIsExtensionPresent)(ALCdevice *device,ALCubyte *extName); +ALCAPI ALCvoid * ALCAPIENTRY (*alcGetProcAddress)(ALCdevice *device,ALCubyte *funcName); +ALCAPI ALCenum ALCAPIENTRY (*alcGetEnumValue)(ALCdevice *device,ALCubyte *enumName); + +#endif /* AL_NO_PROTOTYPES */ + +#ifdef TARGET_OS_MAC + #if TARGET_OS_MAC + #pragma export off + #endif +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/CODE-mp/client/OpenAL/alctypes.h b/CODE-mp/client/OpenAL/alctypes.h new file mode 100644 index 0000000..c04eb44 --- /dev/null +++ b/CODE-mp/client/OpenAL/alctypes.h @@ -0,0 +1,125 @@ +#ifndef _ALCTYPES_H_ +#define _ALCTYPES_H_ + +/** + * OpenAL cross platform audio library + * Copyright (C) 1999-2000 by authors. + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * Or go to http://www.gnu.org/copyleft/lgpl.html + */ + + +#ifdef __cplusplus +extern "C" { +#endif + +/** ALC boolean type. */ +typedef char ALCboolean; + +/** ALC 8bit signed byte. */ +typedef char ALCbyte; + +/** ALC 8bit unsigned byte. */ +typedef unsigned char ALCubyte; + +/** ALC 16bit signed short integer type. */ +typedef short ALCshort; + +/** ALC 16bit unsigned short integer type. */ +typedef unsigned short ALCushort; + +/** ALC 32bit unsigned integer type. */ +typedef unsigned ALCuint; + +/** ALC 32bit signed integer type. */ +typedef int ALCint; + +/** ALC 32bit floating point type. */ +typedef float ALCfloat; + +/** ALC 64bit double point type. */ +typedef double ALCdouble; + +/** ALC 32bit type. */ +typedef unsigned int ALCsizei; + +/** ALC void type */ +typedef void ALCvoid; + +/** ALC enumerations. */ +typedef int ALCenum; + +/* Bad value. */ +#define ALC_INVALID (-1) + +/* Boolean False. */ +#define ALC_FALSE 0 + +/* Boolean True. */ +#define ALC_TRUE 1 + +/** Errors: No Error. */ +#define ALC_NO_ERROR ALC_FALSE + +#define ALC_MAJOR_VERSION 0x1000 +#define ALC_MINOR_VERSION 0x1001 +#define ALC_ATTRIBUTES_SIZE 0x1002 +#define ALC_ALL_ATTRIBUTES 0x1003 + +#define ALC_DEFAULT_DEVICE_SPECIFIER 0x1004 +#define ALC_DEVICE_SPECIFIER 0x1005 +#define ALC_EXTENSIONS 0x1006 + +#define ALC_FREQUENCY 0x1007 +#define ALC_REFRESH 0x1008 +#define ALC_SYNC 0x1009 + +/** + * The device argument does not name a valid dvice. + */ +#define ALC_INVALID_DEVICE 0xA001 + +/** + * The context argument does not name a valid context. + */ +#define ALC_INVALID_CONTEXT 0xA002 + +/** + * A function was called at inappropriate time, + * or in an inappropriate way, causing an illegal state. + * This can be an incompatible ALenum, object ID, + * and/or function. + */ +#define ALC_INVALID_ENUM 0xA003 + +/** + * Illegal value passed as an argument to an AL call. + * Applies to parameter values, but not to enumerations. + */ +#define ALC_INVALID_VALUE 0xA004 + +/** + * A function could not be completed, + * because there is not enough memory available. + */ +#define ALC_OUT_OF_MEMORY 0xA005 + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/CODE-mp/client/OpenAL/altypes.h b/CODE-mp/client/OpenAL/altypes.h new file mode 100644 index 0000000..9cb02e2 --- /dev/null +++ b/CODE-mp/client/OpenAL/altypes.h @@ -0,0 +1,332 @@ +#ifndef _ALTYPES_H_ +#define _ALTYPES_H_ + +/** + * OpenAL cross platform audio library + * Copyright (C) 1999-2000 by authors. + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * Or go to http://www.gnu.org/copyleft/lgpl.html + */ + + +#ifdef __cplusplus +extern "C" { +#endif + +/** OpenAL boolean type. */ +typedef char ALboolean; + +/** OpenAL 8bit signed byte. */ +typedef char ALbyte; + +/** OpenAL 8bit unsigned byte. */ +typedef unsigned char ALubyte; + +/** OpenAL 16bit signed short integer type. */ +typedef short ALshort; + +/** OpenAL 16bit unsigned short integer type. */ +typedef unsigned short ALushort; + +/** OpenAL 32bit unsigned integer type. */ +typedef unsigned ALuint; + +/** OpenAL 32bit signed integer type. */ +typedef int ALint; + +/** OpenAL 32bit floating point type. */ +typedef float ALfloat; + +/** OpenAL 64bit double point type. */ +typedef double ALdouble; + +/** OpenAL 32bit type. */ +typedef unsigned int ALsizei; + +/** OpenAL void type */ +typedef void ALvoid; + +/** OpenAL enumerations. */ +typedef int ALenum; + +/* Bad value. */ +#define AL_INVALID (-1) + +/* Disable value. */ +#define AL_NONE 0 + +/* Boolean False. */ +#define AL_FALSE 0 + +/* Boolean True. */ +#define AL_TRUE 1 + +/** + * Indicate the type of AL_SOURCE. + * Sources can be spatialized + */ +#define AL_SOURCE_TYPE 0x200 + +/** Indicate source has absolute coordinates. */ +#define AL_SOURCE_ABSOLUTE 0x201 + +/** Indicate Source has listener relative coordinates. */ +#define AL_SOURCE_RELATIVE 0x202 + +/** + * Directional source, inner cone angle, in degrees. + * Range: [0-360] + * Default: 360 + */ +#define AL_CONE_INNER_ANGLE 0x1001 + +/** + * Directional source, outer cone angle, in degrees. + * Range: [0-360] + * Default: 360 + */ +#define AL_CONE_OUTER_ANGLE 0x1002 + +/** + * Specify the pitch to be applied, either at source, + * or on mixer results, at listener. + * Range: [0.5-2.0] + * Default: 1.0 + */ +#define AL_PITCH 0x1003 + +/** + * Specify the current location in three dimensional space. + * OpenAL, like OpenGL, uses a right handed coordinate system, + * where in a frontal default view X (thumb) points right, + * Y points up (index finger), and Z points towards the + * viewer/camera (middle finger). + * To switch from a left handed coordinate system, flip the + * sign on the Z coordinate. + * Listener position is always in the world coordinate system. + */ +#define AL_POSITION 0x1004 + +/** Specify the current direction as forward vector. */ +#define AL_DIRECTION 0x1005 + +/** Specify the current velocity in three dimensional space. */ +#define AL_VELOCITY 0x1006 + +/** + * Indicate whether source has to loop infinite. + * Type: ALboolean + * Range: [AL_TRUE, AL_FALSE] + * Default: AL_FALSE + */ +#define AL_LOOPING 0x1007 + +/** + * Indicate the buffer to provide sound samples. + * Type: ALuint. + * Range: any valid Buffer id. + */ +#define AL_BUFFER 0x1009 + +/** + * Indicate the gain (volume amplification) applied. + * Type: ALfloat. + * Range: ]0.0- ] + * A value of 1.0 means un-attenuated/unchanged. + * Each division by 2 equals an attenuation of -6dB. + * Each multiplicaton with 2 equals an amplification of +6dB. + * A value of 0.0 is meaningless with respect to a logarithmic + * scale; it is interpreted as zero volume - the channel + * is effectively disabled. + */ +#define AL_GAIN 0x100A + +/** + * Indicate minimum source attenuation. + * Type: ALfloat + * Range: [0.0 - 1.0] + */ +#define AL_MIN_GAIN 0x100D + +/** + * Indicate maximum source attenuation. + * Type: ALfloat + * Range: [0.0 - 1.0] + */ +#define AL_MAX_GAIN 0x100E + +/** + * Specify the current orientation. + * Type: ALfv6 (at/up) + * Range: N/A + */ +#define AL_ORIENTATION 0x100F + +/* byte offset into source (in canon format). -1 if source + * is not playing. Don't set this, get this. + * + * Type: ALfloat + * Range: [0.0 - ] + * Default: 1.0 + */ +#define AL_REFERENCE_DISTANCE 0x1020 + + /** + * Indicate the rolloff factor for the source. + * Type: ALfloat + * Range: [0.0 - ] + * Default: 1.0 + */ +#define AL_ROLLOFF_FACTOR 0x1021 + +/** + * Indicate the gain (volume amplification) applied. + * Type: ALfloat. + * Range: ]0.0- ] + * A value of 1.0 means un-attenuated/unchanged. + * Each division by 2 equals an attenuation of -6dB. + * Each multiplicaton with 2 equals an amplification of +6dB. + * A value of 0.0 is meaningless with respect to a logarithmic + * scale; it is interpreted as zero volume - the channel + * is effectively disabled. + */ +#define AL_CONE_OUTER_GAIN 0x1022 + +/** + * Specify the maximum distance. + * Type: ALfloat + * Range: [0.0 - ] + */ +#define AL_MAX_DISTANCE 0x1023 + +/** + * Specify the channel mask. (Creative) + * Type: ALuint + * Range: [0 - 255] + */ +#define AL_CHANNEL_MASK 0x3000 + +/** + * Source state information + */ +#define AL_SOURCE_STATE 0x1010 +#define AL_INITIAL 0x1011 +#define AL_PLAYING 0x1012 +#define AL_PAUSED 0x1013 +#define AL_STOPPED 0x1014 + +/** + * Buffer Queue params + */ +#define AL_BUFFERS_QUEUED 0x1015 +#define AL_BUFFERS_PROCESSED 0x1016 + +/** Sound buffers: format specifier. */ +#define AL_FORMAT_MONO8 0x1100 +#define AL_FORMAT_MONO16 0x1101 +#define AL_FORMAT_STEREO8 0x1102 +#define AL_FORMAT_STEREO16 0x1103 + +/** + * Sound buffers: frequency, in units of Hertz [Hz]. + * This is the number of samples per second. Half of the + * sample frequency marks the maximum significant + * frequency component. + */ +#define AL_FREQUENCY 0x2001 +#define AL_BITS 0x2002 +#define AL_CHANNELS 0x2003 +#define AL_SIZE 0x2004 +#define AL_DATA 0x2005 + +/** + * Buffer state. + * + * Not supported for public use (yet). + */ +#define AL_UNUSED 0x2010 +#define AL_PENDING 0x2011 +#define AL_PROCESSED 0x2012 + +/** Errors: No Error. */ +#define AL_NO_ERROR AL_FALSE + +/** + * Illegal name passed as an argument to an AL call. + */ +#define AL_INVALID_NAME 0xA001 + +/** + * Illegal enum passed as an argument to an AL call. + */ +#define AL_INVALID_ENUM 0xA002 +/** + * Illegal value passed as an argument to an AL call. + * Applies to parameter values, but not to enumerations. + */ +#define AL_INVALID_VALUE 0xA003 + +/** + * A function was called at inappropriate time, + * or in an inappropriate way, causing an illegal state. + * This can be an incompatible ALenum, object ID, + * and/or function. + */ +#define AL_INVALID_OPERATION 0xA004 + +/** + * A function could not be completed, + * because there is not enough memory available. + */ +#define AL_OUT_OF_MEMORY 0xA005 + +/** Context strings: Vendor Name. */ +#define AL_VENDOR 0xB001 +#define AL_VERSION 0xB002 +#define AL_RENDERER 0xB003 +#define AL_EXTENSIONS 0xB004 + +/** Global tweakage. */ + +/** + * Doppler scale. Default 1.0 + */ +#define AL_DOPPLER_FACTOR 0xC000 + +/** + * Doppler velocity. Default 1.0 + */ +#define AL_DOPPLER_VELOCITY 0xC001 + +/** + * Distance model. Default AL_INVERSE_DISTANCE_CLAMPED + */ +#define AL_DISTANCE_MODEL 0xD000 + +/** Distance models. */ + +#define AL_INVERSE_DISTANCE 0xD001 +#define AL_INVERSE_DISTANCE_CLAMPED 0xD002 + + /** + * enables + */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/CODE-mp/client/OpenAL/alu.h b/CODE-mp/client/OpenAL/alu.h new file mode 100644 index 0000000..8a4004b --- /dev/null +++ b/CODE-mp/client/OpenAL/alu.h @@ -0,0 +1,34 @@ +#ifndef _ALU_H_ +#define _ALU_H_ + +#define ALUAPI +#define ALUAPIENTRY __cdecl + +#define BUFFERSIZE 48000 +#define FRACTIONBITS 14 +#define FRACTIONMASK ((1L<>8)&7 ) != currentColor ) { - currentColor = (text[x]>>8)&7; - re.SetColor( g_color_table[currentColor] ); - } - if (!cl_conXOffset) - { - cl_conXOffset = Cvar_Get ("cl_conXOffset", "0", 0); - } - SCR_DrawSmallChar( (int)(cl_conXOffset->integer + con.xadjust + (x+1)*SMALLCHAR_WIDTH), v, text[x] & 0xff ); + + if (!cl_conXOffset) + { + cl_conXOffset = Cvar_Get ("cl_conXOffset", "0", 0); } - v += SMALLCHAR_HEIGHT; + // asian language needs to use the new font system to print glyphs... + // + // (ignore colours since we're going to print the whole thing as one string) + // + if (re.Language_IsAsian()) + { + static int iFontIndex = re.RegisterFont("ocr_a"); // this seems naughty + const float fFontScale = 0.75f*con.yadjust; + const int iPixelHeightToAdvance = 2+(1.3/con.yadjust) * re.Font_HeightPixels(iFontIndex, fFontScale); // for asian spacing, since we don't want glyphs to touch. + + // concat the text to be printed... + // + char sTemp[4096]={0}; // ott + for (x = 0 ; x < con.linewidth ; x++) + { + if ( ( (text[x]>>8)&7 ) != currentColor ) { + currentColor = (text[x]>>8)&7; + strcat(sTemp,va("^%i", (text[x]>>8)&7) ); + } + strcat(sTemp,va("%c",text[x] & 0xFF)); + } + // + // and print... + // + re.Font_DrawString(cl_conXOffset->integer + con.xadjust*(con.xadjust + (1*SMALLCHAR_WIDTH/*aesthetics*/)), con.yadjust*(v), sTemp, g_color_table[currentColor], iFontIndex, -1, fFontScale); + + v += iPixelHeightToAdvance; + } + else + { + for (x = 0 ; x < con.linewidth ; x++) { + if ( ( text[x] & 0xff ) == ' ' ) { + continue; + } + if ( ( (text[x]>>8)&7 ) != currentColor ) { + currentColor = (text[x]>>8)&7; + re.SetColor( g_color_table[currentColor] ); + } + if (!cl_conXOffset) + { + cl_conXOffset = Cvar_Get ("cl_conXOffset", "0", 0); + } + SCR_DrawSmallChar( (int)(cl_conXOffset->integer + con.xadjust + (x+1)*SMALLCHAR_WIDTH), v, text[x] & 0xff ); + } + + v += SMALLCHAR_HEIGHT; + } } re.SetColor( NULL ); @@ -589,7 +628,19 @@ void Con_DrawSolidConsole( float frac ) { currentColor = 7; re.SetColor( g_color_table[currentColor] ); - for (i=0 ; i>8)&7 ) != currentColor ) { + currentColor = (text[x]>>8)&7; + strcat(sTemp,va("^%i", (text[x]>>8)&7) ); + } + strcat(sTemp,va("%c",text[x] & 0xFF)); } + // + // and print... + // + re.Font_DrawString(con.xadjust*(con.xadjust + (1*SMALLCHAR_WIDTH/*(aesthetics)*/)), con.yadjust*(y), sTemp, g_color_table[currentColor], iFontIndexForAsian, -1, fFontScaleForAsian); + } + else + { + for (x=0 ; x>8)&7 ) != currentColor ) { - currentColor = (text[x]>>8)&7; - re.SetColor( g_color_table[currentColor] ); + if ( ( (text[x]>>8)&7 ) != currentColor ) { + currentColor = (text[x]>>8)&7; + re.SetColor( g_color_table[currentColor] ); + } + SCR_DrawSmallChar( (int) (con.xadjust + (x+1)*SMALLCHAR_WIDTH), y, text[x] & 0xff ); } - SCR_DrawSmallChar( (int) (con.xadjust + (x+1)*SMALLCHAR_WIDTH), y, text[x] & 0xff ); } } @@ -712,7 +788,7 @@ void Con_Close( void ) { if ( !com_cl_running->integer ) { return; } - Field_Clear( &g_consoleField ); + Field_Clear( &kg.g_consoleField ); Con_ClearNotify (); cls.keyCatchers &= ~KEYCATCH_CONSOLE; con.finalFrac = 0; // none visible diff --git a/CODE-mp/client/cl_input.cpp b/CODE-mp/client/cl_input.cpp index 6a02598..302f3f8 100644 --- a/CODE-mp/client/cl_input.cpp +++ b/CODE-mp/client/cl_input.cpp @@ -586,12 +586,12 @@ void CL_CmdButtons( usercmd_t *cmd ) { } if ( cls.keyCatchers ) { -// cmd->buttons |= BUTTON_TALK; + cmd->buttons |= BUTTON_TALK; } // allow the game to know if any key at all is // currently pressed, even if it isn't bound to anything - if ( anykeydown && !cls.keyCatchers ) { + if ( kg.anykeydown && !cls.keyCatchers ) { cmd->buttons |= BUTTON_ANY; } } diff --git a/CODE-mp/client/cl_keys.cpp b/CODE-mp/client/cl_keys.cpp index 1e69b06..b588c98 100644 --- a/CODE-mp/client/cl_keys.cpp +++ b/CODE-mp/client/cl_keys.cpp @@ -6,532 +6,350 @@ key up events are sent even if in console mode */ -field_t historyEditLines[COMMAND_HISTORY]; - -int nextHistoryLine; // the last line in the history buffer, not masked -int historyLine; // the line being displayed from history buffer - // will be <= nextHistoryLine - -field_t g_consoleField; field_t chatField; qboolean chat_team; int chat_playerNum; +keyGlobals_t kg; -qboolean key_overstrikeMode; - -qboolean anykeydown; -qkey_t keys[MAX_KEYS]; - - -typedef struct { - char *name; - int keynum; -} keyname_t; - - -// names not in this list can either be lowercase ascii, or '0xnn' hex sequences -keyname_t keynames[] = -{ - {"TAB", K_TAB}, - {"ENTER", K_ENTER}, - {"ESCAPE", K_ESCAPE}, - {"SPACE", K_SPACE}, - {"BACKSPACE", K_BACKSPACE}, - {"UPARROW", K_UPARROW}, - {"DOWNARROW", K_DOWNARROW}, - {"LEFTARROW", K_LEFTARROW}, - {"RIGHTARROW", K_RIGHTARROW}, - - {"ALT", K_ALT}, - {"CTRL", K_CTRL}, - {"SHIFT", K_SHIFT}, - - {"COMMAND", K_COMMAND}, - - {"CAPSLOCK", K_CAPSLOCK}, - - - {"F1", K_F1}, - {"F2", K_F2}, - {"F3", K_F3}, - {"F4", K_F4}, - {"F5", K_F5}, - {"F6", K_F6}, - {"F7", K_F7}, - {"F8", K_F8}, - {"F9", K_F9}, - {"F10", K_F10}, - {"F11", K_F11}, - {"F12", K_F12}, - - {"INS", K_INS}, - {"DEL", K_DEL}, - {"PGDN", K_PGDN}, - {"PGUP", K_PGUP}, - {"HOME", K_HOME}, - {"END", K_END}, - - {"MOUSE1", K_MOUSE1}, - {"MOUSE2", K_MOUSE2}, - {"MOUSE3", K_MOUSE3}, - {"MOUSE4", K_MOUSE4}, - {"MOUSE5", K_MOUSE5}, - - {"MWHEELUP", K_MWHEELUP }, - {"MWHEELDOWN", K_MWHEELDOWN }, - - {"JOY1", K_JOY1}, - {"JOY2", K_JOY2}, - {"JOY3", K_JOY3}, - {"JOY4", K_JOY4}, - {"JOY5", K_JOY5}, - {"JOY6", K_JOY6}, - {"JOY7", K_JOY7}, - {"JOY8", K_JOY8}, - {"JOY9", K_JOY9}, - {"JOY10", K_JOY10}, - {"JOY11", K_JOY11}, - {"JOY12", K_JOY12}, - {"JOY13", K_JOY13}, - {"JOY14", K_JOY14}, - {"JOY15", K_JOY15}, - {"JOY16", K_JOY16}, - {"JOY17", K_JOY17}, - {"JOY18", K_JOY18}, - {"JOY19", K_JOY19}, - {"JOY20", K_JOY20}, - {"JOY21", K_JOY21}, - {"JOY22", K_JOY22}, - {"JOY23", K_JOY23}, - {"JOY24", K_JOY24}, - {"JOY25", K_JOY25}, - {"JOY26", K_JOY26}, - {"JOY27", K_JOY27}, - {"JOY28", K_JOY28}, - {"JOY29", K_JOY29}, - {"JOY30", K_JOY30}, - {"JOY31", K_JOY31}, - {"JOY32", K_JOY32}, - - {"AUX1", K_AUX1}, - {"AUX2", K_AUX2}, - {"AUX3", K_AUX3}, - {"AUX4", K_AUX4}, - {"AUX5", K_AUX5}, - {"AUX6", K_AUX6}, - {"AUX7", K_AUX7}, - {"AUX8", K_AUX8}, - {"AUX9", K_AUX9}, - {"AUX10", K_AUX10}, - {"AUX11", K_AUX11}, - {"AUX12", K_AUX12}, - {"AUX13", K_AUX13}, - {"AUX14", K_AUX14}, - {"AUX15", K_AUX15}, - {"AUX16", K_AUX16}, - - {"KP_HOME", K_KP_HOME }, - {"KP_UPARROW", K_KP_UPARROW }, - {"KP_PGUP", K_KP_PGUP }, - {"KP_LEFTARROW", K_KP_LEFTARROW }, - {"KP_5", K_KP_5 }, - {"KP_RIGHTARROW", K_KP_RIGHTARROW }, - {"KP_END", K_KP_END }, - {"KP_DOWNARROW", K_KP_DOWNARROW }, - {"KP_PGDN", K_KP_PGDN }, - {"KP_ENTER", K_KP_ENTER }, - {"KP_INS", K_KP_INS }, - {"KP_DEL", K_KP_DEL }, - {"KP_SLASH", K_KP_SLASH }, - {"KP_MINUS", K_KP_MINUS }, - {"KP_PLUS", K_KP_PLUS }, - {"KP_NUMLOCK", K_KP_NUMLOCK }, - {"KP_STAR", K_KP_STAR }, - {"KP_EQUALS", K_KP_EQUALS }, - - {"PAUSE", K_PAUSE}, - - {"SEMICOLON", ';'}, // because a raw semicolon seperates commands - - {NULL,0} +// do NOT blithely change any of the key names (3rd field) here, since they have to match the key binds +// in the CFG files, they're also prepended with "KEYNAME_" when looking up StripEd references +// +keyname_t keynames[MAX_KEYS] = +{ + { 0x00, 0x00, NULL, A_NULL, false }, + { 0x01, 0x01, "SHIFT", A_SHIFT, false }, + { 0x02, 0x02, "CTRL", A_CTRL, false }, + { 0x03, 0x03, "ALT", A_ALT, false }, + { 0x04, 0x04, "CAPSLOCK", A_CAPSLOCK, false }, + { 0x05, 0x05, "KP_NUMLOCK", A_NUMLOCK, false }, + { 0x06, 0x06, "SCROLLLOCK", A_SCROLLLOCK, false }, + { 0x07, 0x07, "PAUSE", A_PAUSE, false }, + { 0x08, 0x08, "BACKSPACE", A_BACKSPACE, false }, + { 0x09, 0x09, "TAB", A_TAB, false }, + { 0x0a, 0x0a, "ENTER", A_ENTER, false }, + { 0x0b, 0x0b, "KP_PLUS", A_KP_PLUS, false }, + { 0x0c, 0x0c, "KP_MINUS", A_KP_MINUS, false }, + { 0x0d, 0x0d, "KP_ENTER", A_KP_ENTER, false }, + { 0x0e, 0x0e, "KP_DEL", A_KP_PERIOD, false }, + { 0x0f, 0x0f, NULL, A_PRINTSCREEN, false }, + { 0x10, 0x10, "KP_INS", A_KP_0, false }, + { 0x11, 0x11, "KP_END", A_KP_1, false }, + { 0x12, 0x12, "KP_DOWNARROW", A_KP_2, false }, + { 0x13, 0x13, "KP_PGDN", A_KP_3, false }, + { 0x14, 0x14, "KP_LEFTARROW", A_KP_4, false }, + { 0x15, 0x15, "KP_5", A_KP_5, false }, + { 0x16, 0x16, "KP_RIGHTARROW", A_KP_6, false }, + { 0x17, 0x17, "KP_HOME", A_KP_7, false }, + { 0x18, 0x18, "KP_UPARROW", A_KP_8, false }, + { 0x19, 0x19, "KP_PGUP", A_KP_9, false }, + { 0x1a, 0x1a, "CONSOLE", A_CONSOLE, false }, + { 0x1b, 0x1b, "ESCAPE", A_ESCAPE, false }, + { 0x1c, 0x1c, "F1", A_F1, true }, + { 0x1d, 0x1d, "F2", A_F2, true }, + { 0x1e, 0x1e, "F3", A_F3, true }, + { 0x1f, 0x1f, "F4", A_F4, true }, + + { 0x20, 0x20, "SPACE", A_SPACE, false }, + { (word)'!', (word)'!', NULL, A_PLING, false }, + { (word)'"', (word)'"', NULL, A_DOUBLE_QUOTE, false }, + { (word)'#', (word)'#', NULL, A_HASH, false }, + { (word)'$', (word)'$', NULL, A_STRING, false }, + { (word)'%', (word)'%', NULL, A_PERCENT, false }, + { (word)'&', (word)'&', NULL, A_AND, false }, + { 0x27, 0x27, NULL, A_SINGLE_QUOTE, false }, + { (word)'(', (word)'(', NULL, A_OPEN_BRACKET, false }, + { (word)')', (word)')', NULL, A_CLOSE_BRACKET, false }, + { (word)'*', (word)'*', NULL, A_STAR, false }, + { (word)'+', (word)'+', NULL, A_PLUS, false }, + { (word)',', (word)',', NULL, A_COMMA, false }, + { (word)'-', (word)'-', NULL, A_MINUS, false }, + { (word)'.', (word)'.', NULL, A_PERIOD, false }, + { (word)'/', (word)'/', NULL, A_FORWARD_SLASH, false }, + { (word)'0', (word)'0', NULL, A_0, false }, + { (word)'1', (word)'1', NULL, A_1, false }, + { (word)'2', (word)'2', NULL, A_2, false }, + { (word)'3', (word)'3', NULL, A_3, false }, + { (word)'4', (word)'4', NULL, A_4, false }, + { (word)'5', (word)'5', NULL, A_5, false }, + { (word)'6', (word)'6', NULL, A_6, false }, + { (word)'7', (word)'7', NULL, A_7, false }, + { (word)'8', (word)'8', NULL, A_8, false }, + { (word)'9', (word)'9', NULL, A_9, false }, + { (word)':', (word)':', NULL, A_COLON, false }, + { (word)';', (word)';', "SEMICOLON", A_SEMICOLON, false }, + { (word)'<', (word)'<', NULL, A_LESSTHAN, false }, + { (word)'=', (word)'=', NULL, A_EQUALS, false }, + { (word)'>', (word)'>', NULL, A_GREATERTHAN, false }, + { (word)'?', (word)'?', NULL, A_QUESTION, false }, + + { (word)'@', (word)'@', NULL, A_AT, false }, + { (word)'A', (word)'a', NULL, A_CAP_A, false }, + { (word)'B', (word)'b', NULL, A_CAP_B, false }, + { (word)'C', (word)'c', NULL, A_CAP_C, false }, + { (word)'D', (word)'d', NULL, A_CAP_D, false }, + { (word)'E', (word)'e', NULL, A_CAP_E, false }, + { (word)'F', (word)'f', NULL, A_CAP_F, false }, + { (word)'G', (word)'g', NULL, A_CAP_G, false }, + { (word)'H', (word)'h', NULL, A_CAP_H, false }, + { (word)'I', (word)'i', NULL, A_CAP_I, false }, + { (word)'J', (word)'j', NULL, A_CAP_J, false }, + { (word)'K', (word)'k', NULL, A_CAP_K, false }, + { (word)'L', (word)'l', NULL, A_CAP_L, false }, + { (word)'M', (word)'m', NULL, A_CAP_M, false }, + { (word)'N', (word)'n', NULL, A_CAP_N, false }, + { (word)'O', (word)'o', NULL, A_CAP_O, false }, + { (word)'P', (word)'p', NULL, A_CAP_P, false }, + { (word)'Q', (word)'q', NULL, A_CAP_Q, false }, + { (word)'R', (word)'r', NULL, A_CAP_R, false }, + { (word)'S', (word)'s', NULL, A_CAP_S, false }, + { (word)'T', (word)'t', NULL, A_CAP_T, false }, + { (word)'U', (word)'u', NULL, A_CAP_U, false }, + { (word)'V', (word)'v', NULL, A_CAP_V, false }, + { (word)'W', (word)'w', NULL, A_CAP_W, false }, + { (word)'X', (word)'x', NULL, A_CAP_X, false }, + { (word)'Y', (word)'y', NULL, A_CAP_Y, false }, + { (word)'Z', (word)'z', NULL, A_CAP_Z, false }, + { (word)'[', (word)'[', NULL, A_OPEN_SQUARE, false }, + { 0x5c, 0x5c, NULL, A_BACKSLASH, false }, + { (word)']', (word)']', NULL, A_CLOSE_SQUARE, false }, + { (word)'^', (word)'^', NULL, A_CARET, false }, + { (word)'_', (word)'_', NULL, A_UNDERSCORE, false }, + + { 0x60, 0x60, NULL, A_LEFT_SINGLE_QUOTE, false }, + { (word)'A', (word)'a', NULL, A_LOW_A, false }, + { (word)'B', (word)'b', NULL, A_LOW_B, false }, + { (word)'C', (word)'c', NULL, A_LOW_C, false }, + { (word)'D', (word)'d', NULL, A_LOW_D, false }, + { (word)'E', (word)'e', NULL, A_LOW_E, false }, + { (word)'F', (word)'f', NULL, A_LOW_F, false }, + { (word)'G', (word)'g', NULL, A_LOW_G, false }, + { (word)'H', (word)'h', NULL, A_LOW_H, false }, + { (word)'I', (word)'i', NULL, A_LOW_I, false }, + { (word)'J', (word)'j', NULL, A_LOW_J, false }, + { (word)'K', (word)'k', NULL, A_LOW_K, false }, + { (word)'L', (word)'l', NULL, A_LOW_L, false }, + { (word)'M', (word)'m', NULL, A_LOW_M, false }, + { (word)'N', (word)'n', NULL, A_LOW_N, false }, + { (word)'O', (word)'o', NULL, A_LOW_O, false }, + { (word)'P', (word)'p', NULL, A_LOW_P, false }, + { (word)'Q', (word)'q', NULL, A_LOW_Q, false }, + { (word)'R', (word)'r', NULL, A_LOW_R, false }, + { (word)'S', (word)'s', NULL, A_LOW_S, false }, + { (word)'T', (word)'t', NULL, A_LOW_T, false }, + { (word)'U', (word)'u', NULL, A_LOW_U, false }, + { (word)'V', (word)'v', NULL, A_LOW_V, false }, + { (word)'W', (word)'w', NULL, A_LOW_W, false }, + { (word)'X', (word)'x', NULL, A_LOW_X, false }, + { (word)'Y', (word)'y', NULL, A_LOW_Y, false }, + { (word)'Z', (word)'z', NULL, A_LOW_Z, false }, + { (word)'{', (word)'{', NULL, A_OPEN_BRACE, false }, + { (word)'|', (word)'|', NULL, A_BAR, false }, + { (word)'}', (word)'}', NULL, A_CLOSE_BRACE, false }, + { (word)'~', (word)'~', NULL, A_TILDE, false }, + { 0x7f, 0x7f, "DEL", A_DELETE, false }, + + { 0x80, 0x80, "EURO", A_EURO, false }, + { 0x81, 0x81, "SHIFT", A_SHIFT2, false }, + { 0x82, 0x82, "CTRL", A_CTRL2, false }, + { 0x83, 0x83, "ALT", A_ALT2, false }, + { 0x84, 0x84, "F5", A_F5, true }, + { 0x85, 0x85, "F6", A_F6, true }, + { 0x86, 0x86, "F7", A_F7, true }, + { 0x87, 0x87, "F8", A_F8, true }, + { 0x88, 0x88, "CIRCUMFLEX", A_CIRCUMFLEX, false }, + { 0x89, 0x89, "MWHEELUP", A_MWHEELUP, false }, + { 0x8a, 0x9a, NULL, A_CAP_SCARON, false }, // ****** + { 0x8b, 0x8b, "MWHEELDOWN", A_MWHEELDOWN, false }, + { 0x8c, 0x9c, NULL, A_CAP_OE, false }, // ****** + { 0x8d, 0x8d, "MOUSE1", A_MOUSE1, false }, + { 0x8e, 0x8e, "MOUSE2", A_MOUSE2, false }, + { 0x8f, 0x8f, "INS", A_INSERT, false }, + { 0x90, 0x90, "HOME", A_HOME, false }, + { 0x91, 0x91, "PGUP", A_PAGE_UP, false }, + { 0x92, 0x92, NULL, A_RIGHT_SINGLE_QUOTE, false }, + { 0x93, 0x93, NULL, A_LEFT_DOUBLE_QUOTE, false }, + { 0x94, 0x94, NULL, A_RIGHT_DOUBLE_QUOTE, false }, + { 0x95, 0x95, "F9", A_F9, true }, + { 0x96, 0x96, "F10", A_F10, true }, + { 0x97, 0x97, "F11", A_F11, true }, + { 0x98, 0x98, "F12", A_F12, true }, + { 0x99, 0x99, NULL, A_TRADEMARK, false }, + { 0x8a, 0x9a, NULL, A_LOW_SCARON, false }, // ****** + { 0x9b, 0x9b, "SHIFT_ENTER", A_ENTER, false }, + { 0x8c, 0x9c, NULL, A_LOW_OE, false }, // ****** + { 0x9d, 0x9d, "END", A_END, false }, + { 0x9e, 0x9e, "PGDN", A_PAGE_DOWN, false }, + { 0x9f, 0xff, NULL, A_CAP_YDIERESIS, false }, // ****** + + { 0xa0, 0, "SHIFT_SPACE", A_SPACE, false }, + { 0xa1, 0xa1, NULL, A_EXCLAMDOWN, false }, // upside down '!' - undisplayable + { (word)(byte)'¢', (word)(byte)'¢', NULL, A_CENT, false }, + { (word)(byte)'£', (word)(byte)'£', NULL, A_POUND, false }, + { 0xa4, 0, "SHIFT_KP_ENTER", A_KP_ENTER, false }, + { (word)(byte)'¥', (word)(byte)'¥', NULL, A_YEN, false }, + { 0xa6, 0xa6, "MOUSE3", A_MOUSE3, false }, + { 0xa7, 0xa7, "MOUSE4", A_MOUSE4, false }, + { 0xa8, 0xa8, "MOUSE5", A_MOUSE5, false }, + { (word)(byte)'©', (word)(byte)'©', NULL, A_COPYRIGHT, false }, + { 0xaa, 0xaa, "UPARROW", A_CURSOR_UP, false }, + { 0xab, 0xab, "DOWNARROW", A_CURSOR_DOWN, false }, + { 0xac, 0xac, "LEFTARROW", A_CURSOR_LEFT, false }, + { 0xad, 0xad, "RIGHTARROW", A_CURSOR_RIGHT, false }, + { (word)(byte)'®', (word)(byte)'®', NULL, A_REGISTERED, false }, + { 0xaf, 0, NULL, A_UNDEFINED_7, false }, + { 0xb0, 0, NULL, A_UNDEFINED_8, false }, + { 0xb1, 0, NULL, A_UNDEFINED_9, false }, + { 0xb2, 0, NULL, A_UNDEFINED_10, false }, + { 0xb3, 0, NULL, A_UNDEFINED_11, false }, + { 0xb4, 0, NULL, A_UNDEFINED_12, false }, + { 0xb5, 0, NULL, A_UNDEFINED_13, false }, + { 0xb6, 0, NULL, A_UNDEFINED_14, false }, + { 0xb7, 0, NULL, A_UNDEFINED_15, false }, + { 0xb8, 0, NULL, A_UNDEFINED_16, false }, + { 0xb9, 0, NULL, A_UNDEFINED_17, false }, + { 0xba, 0, NULL, A_UNDEFINED_18, false }, + { 0xbb, 0, NULL, A_UNDEFINED_19, false }, + { 0xbc, 0, NULL, A_UNDEFINED_20, false }, + { 0xbd, 0, NULL, A_UNDEFINED_21, false }, + { 0xbe, 0, NULL, A_UNDEFINED_22, false }, + { (word)(byte)'¿', (word)(byte)'¿', NULL, A_QUESTION_DOWN, false }, + + { (word)(byte)'À', (word)(byte)'à', NULL, A_CAP_AGRAVE, false }, + { (word)(byte)'Á', (word)(byte)'á', NULL, A_CAP_AACUTE, false }, + { (word)(byte)'Â', (word)(byte)'â', NULL, A_CAP_ACIRCUMFLEX, false }, + { (word)(byte)'Ã', (word)(byte)'ã', NULL, A_CAP_ATILDE, false }, + { (word)(byte)'Ä', (word)(byte)'ä', NULL, A_CAP_ADIERESIS, false }, + { (word)(byte)'Å', (word)(byte)'å', NULL, A_CAP_ARING, false }, + { (word)(byte)'Æ', (word)(byte)'æ', NULL, A_CAP_AE, false }, + { (word)(byte)'Ç', (word)(byte)'ç', NULL, A_CAP_CCEDILLA, false }, + { (word)(byte)'È', (word)(byte)'è', NULL, A_CAP_EGRAVE, false }, + { (word)(byte)'É', (word)(byte)'é', NULL, A_CAP_EACUTE, false }, + { (word)(byte)'Ê', (word)(byte)'ê', NULL, A_CAP_ECIRCUMFLEX, false }, + { (word)(byte)'Ë', (word)(byte)'ë', NULL, A_CAP_EDIERESIS, false }, + { (word)(byte)'Ì', (word)(byte)'ì', NULL, A_CAP_IGRAVE, false }, + { (word)(byte)'Í', (word)(byte)'í', NULL, A_CAP_IACUTE, false }, + { (word)(byte)'Î', (word)(byte)'î', NULL, A_CAP_ICIRCUMFLEX, false }, + { (word)(byte)'Ï', (word)(byte)'ï', NULL, A_CAP_IDIERESIS, false }, + { (word)(byte)'Ð', (word)(byte)'ð', NULL, A_CAP_ETH, false }, + { (word)(byte)'Ñ', (word)(byte)'ñ', NULL, A_CAP_NTILDE, false }, + { (word)(byte)'Ò', (word)(byte)'ò', NULL, A_CAP_OGRAVE, false }, + { (word)(byte)'Ó', (word)(byte)'ó', NULL, A_CAP_OACUTE, false }, + { (word)(byte)'Ô', (word)(byte)'ô', NULL, A_CAP_OCIRCUMFLEX, false }, + { (word)(byte)'Õ', (word)(byte)'õ', NULL, A_CAP_OTILDE, false }, + { (word)(byte)'Ö', (word)(byte)'ö', NULL, A_CAP_ODIERESIS, false }, + { (word)(byte)'×', (word)(byte)'×', "KP_STAR", A_MULTIPLY, false }, + { (word)(byte)'Ø', (word)(byte)'ø', NULL, A_CAP_OSLASH, false }, + { (word)(byte)'Ù', (word)(byte)'ù', NULL, A_CAP_UGRAVE, false }, + { (word)(byte)'Ú', (word)(byte)'ú', NULL, A_CAP_UACUTE, false }, + { (word)(byte)'Û', (word)(byte)'û', NULL, A_CAP_UCIRCUMFLEX, false }, + { (word)(byte)'Ü', (word)(byte)'ü', NULL, A_CAP_UDIERESIS, false }, + { (word)(byte)'Ý', (word)(byte)'ý', NULL, A_CAP_YACUTE, false }, + { (word)(byte)'Þ', (word)(byte)'þ', NULL, A_CAP_THORN, false }, + { (word)(byte)'ß', (word)(byte)'ß', NULL, A_GERMANDBLS, false }, + + { (word)(byte)'À', (word)(byte)'à', NULL, A_LOW_AGRAVE, false }, + { (word)(byte)'Á', (word)(byte)'á', NULL, A_LOW_AACUTE, false }, + { (word)(byte)'Â', (word)(byte)'â', NULL, A_LOW_ACIRCUMFLEX, false }, + { (word)(byte)'Ã', (word)(byte)'ã', NULL, A_LOW_ATILDE, false }, + { (word)(byte)'Ä', (word)(byte)'ä', NULL, A_LOW_ADIERESIS, false }, + { (word)(byte)'Å', (word)(byte)'å', NULL, A_LOW_ARING, false }, + { (word)(byte)'Æ', (word)(byte)'æ', NULL, A_LOW_AE, false }, + { (word)(byte)'Ç', (word)(byte)'ç', NULL, A_LOW_CCEDILLA, false }, + { (word)(byte)'È', (word)(byte)'è', NULL, A_LOW_EGRAVE, false }, + { (word)(byte)'É', (word)(byte)'é', NULL, A_LOW_EACUTE, false }, + { (word)(byte)'Ê', (word)(byte)'ê', NULL, A_LOW_ECIRCUMFLEX, false }, + { (word)(byte)'Ë', (word)(byte)'ë', NULL, A_LOW_EDIERESIS, false }, + { (word)(byte)'Ì', (word)(byte)'ì', NULL, A_LOW_IGRAVE, false }, + { (word)(byte)'Í', (word)(byte)'í', NULL, A_LOW_IACUTE, false }, + { (word)(byte)'Î', (word)(byte)'î', NULL, A_LOW_ICIRCUMFLEX, false }, + { (word)(byte)'Ï', (word)(byte)'ï', NULL, A_LOW_IDIERESIS, false }, + { (word)(byte)'Ð', (word)(byte)'ð', NULL, A_LOW_ETH, false }, + { (word)(byte)'Ñ', (word)(byte)'ñ', NULL, A_LOW_NTILDE, false }, + { (word)(byte)'Ò', (word)(byte)'ò', NULL, A_LOW_OGRAVE, false }, + { (word)(byte)'Ó', (word)(byte)'ó', NULL, A_LOW_OACUTE, false }, + { (word)(byte)'Ô', (word)(byte)'ô', NULL, A_LOW_OCIRCUMFLEX, false }, + { (word)(byte)'Õ', (word)(byte)'õ', NULL, A_LOW_OTILDE, false }, + { (word)(byte)'Ö', (word)(byte)'ö', NULL, A_LOW_ODIERESIS, false }, + { (word)(byte)'÷', (word)(byte)'÷', "KP_SLASH", A_DIVIDE, false }, + { (word)(byte)'Ø', (word)(byte)'ø', NULL, A_LOW_OSLASH, false }, + { (word)(byte)'Ù', (word)(byte)'ù', NULL, A_LOW_UGRAVE, false }, + { (word)(byte)'Ú', (word)(byte)'ú', NULL, A_LOW_UACUTE, false }, + { (word)(byte)'Û', (word)(byte)'û', NULL, A_LOW_UCIRCUMFLEX, false }, + { (word)(byte)'Ü', (word)(byte)'ü', NULL, A_LOW_UDIERESIS, false }, + { (word)(byte)'Ý', (word)(byte)'ý', NULL, A_LOW_YACUTE, false }, + { (word)(byte)'Þ', (word)(byte)'þ', NULL, A_LOW_THORN, false }, + { 0x9f, 0xff, NULL, A_LOW_YDIERESIS, false }, // ******* + + { 0x100, 0x100, "JOY0", A_JOY0, false }, + { 0x101, 0x101, "JOY1", A_JOY1, false }, + { 0x102, 0x102, "JOY2", A_JOY2, false }, + { 0x103, 0x103, "JOY3", A_JOY3, false }, + { 0x104, 0x104, "JOY4", A_JOY4, false }, + { 0x105, 0x105, "JOY5", A_JOY5, false }, + { 0x106, 0x106, "JOY6", A_JOY6, false }, + { 0x107, 0x107, "JOY7", A_JOY7, false }, + { 0x108, 0x108, "JOY8", A_JOY8, false }, + { 0x109, 0x109, "JOY9", A_JOY9, false }, + { 0x10a, 0x10a, "JOY10", A_JOY10, false }, + { 0x10b, 0x10b, "JOY11", A_JOY11, false }, + { 0x10c, 0x10c, "JOY12", A_JOY12, false }, + { 0x10d, 0x10d, "JOY13", A_JOY13, false }, + { 0x10e, 0x10e, "JOY14", A_JOY14, false }, + { 0x10f, 0x10f, "JOY15", A_JOY15, false }, + { 0x110, 0x110, "JOY16", A_JOY16, false }, + { 0x111, 0x111, "JOY17", A_JOY17, false }, + { 0x112, 0x112, "JOY18", A_JOY18, false }, + { 0x113, 0x113, "JOY19", A_JOY19, false }, + { 0x114, 0x114, "JOY20", A_JOY20, false }, + { 0x115, 0x115, "JOY21", A_JOY21, false }, + { 0x116, 0x116, "JOY22", A_JOY22, false }, + { 0x117, 0x117, "JOY23", A_JOY23, false }, + { 0x118, 0x118, "JOY24", A_JOY24, false }, + { 0x119, 0x119, "JOY25", A_JOY25, false }, + { 0x11a, 0x11a, "JOY26", A_JOY26, false }, + { 0x11b, 0x11b, "JOY27", A_JOY27, false }, + { 0x11c, 0x11c, "JOY28", A_JOY28, false }, + { 0x11d, 0x11d, "JOY29", A_JOY29, false }, + { 0x11e, 0x11e, "JOY30", A_JOY30, false }, + { 0x11f, 0x11f, "JOY31", A_JOY31, false }, + + { 0x120, 0x120, "AUX0", A_AUX0, false }, + { 0x121, 0x121, "AUX1", A_AUX1, false }, + { 0x122, 0x122, "AUX2", A_AUX2, false }, + { 0x123, 0x123, "AUX3", A_AUX3, false }, + { 0x124, 0x124, "AUX4", A_AUX4, false }, + { 0x125, 0x125, "AUX5", A_AUX5, false }, + { 0x126, 0x126, "AUX6", A_AUX6, false }, + { 0x127, 0x127, "AUX7", A_AUX7, false }, + { 0x128, 0x128, "AUX8", A_AUX8, false }, + { 0x129, 0x129, "AUX9", A_AUX9, false }, + { 0x12a, 0x12a, "AUX10", A_AUX10, false }, + { 0x12b, 0x12b, "AUX11", A_AUX11, false }, + { 0x12c, 0x12c, "AUX12", A_AUX12, false }, + { 0x12d, 0x12d, "AUX13", A_AUX13, false }, + { 0x12e, 0x12e, "AUX14", A_AUX14, false }, + { 0x12f, 0x12f, "AUX15", A_AUX15, false }, + { 0x130, 0x130, "AUX16", A_AUX16, false }, + { 0x131, 0x131, "AUX17", A_AUX17, false }, + { 0x132, 0x132, "AUX18", A_AUX18, false }, + { 0x133, 0x133, "AUX19", A_AUX19, false }, + { 0x134, 0x134, "AUX20", A_AUX20, false }, + { 0x135, 0x135, "AUX21", A_AUX21, false }, + { 0x136, 0x136, "AUX22", A_AUX22, false }, + { 0x137, 0x137, "AUX23", A_AUX23, false }, + { 0x138, 0x138, "AUX24", A_AUX24, false }, + { 0x139, 0x139, "AUX25", A_AUX25, false }, + { 0x13a, 0x13a, "AUX26", A_AUX26, false }, + { 0x13b, 0x13b, "AUX27", A_AUX27, false }, + { 0x13c, 0x13c, "AUX28", A_AUX28, false }, + { 0x13d, 0x13d, "AUX29", A_AUX29, false }, + { 0x13e, 0x13e, "AUX30", A_AUX30, false }, + { 0x13f, 0x13f, "AUX31", A_AUX31, false } }; -//english printed keynames, for when we want what's printed to be different -//from the "technical" bind label -keyname_t keynames_e[] = -{ - {"TAB", K_TAB}, - {"ENTER", K_ENTER}, - {"ESCAPE", K_ESCAPE}, - {"SPACE", K_SPACE}, - {"BACKSPACE", K_BACKSPACE}, - {"UP", K_UPARROW}, - {"DOWN", K_DOWNARROW}, - {"LEFT", K_LEFTARROW}, - {"RIGHT", K_RIGHTARROW}, - {"ALT", K_ALT}, - {"CTRL", K_CTRL}, - {"SHIFT", K_SHIFT}, - - {"COMMAND", K_COMMAND}, - - {"CAPSLOCK", K_CAPSLOCK}, - - - {"F1", K_F1}, - {"F2", K_F2}, - {"F3", K_F3}, - {"F4", K_F4}, - {"F5", K_F5}, - {"F6", K_F6}, - {"F7", K_F7}, - {"F8", K_F8}, - {"F9", K_F9}, - {"F10", K_F10}, - {"F11", K_F11}, - {"F12", K_F12}, - - {"INS", K_INS}, - {"DEL", K_DEL}, - {"PGDN", K_PGDN}, - {"PGUP", K_PGUP}, - {"HOME", K_HOME}, - {"END", K_END}, - - {"MOUSE1", K_MOUSE1}, - {"MOUSE2", K_MOUSE2}, - {"MOUSE3", K_MOUSE3}, - {"MOUSE4", K_MOUSE4}, - {"MOUSE5", K_MOUSE5}, - - {"MWHEELUP", K_MWHEELUP }, - {"MWHEELDOWN", K_MWHEELDOWN }, - - {"JOY1", K_JOY1}, - {"JOY2", K_JOY2}, - {"JOY3", K_JOY3}, - {"JOY4", K_JOY4}, - {"JOY5", K_JOY5}, - {"JOY6", K_JOY6}, - {"JOY7", K_JOY7}, - {"JOY8", K_JOY8}, - {"JOY9", K_JOY9}, - {"JOY10", K_JOY10}, - {"JOY11", K_JOY11}, - {"JOY12", K_JOY12}, - {"JOY13", K_JOY13}, - {"JOY14", K_JOY14}, - {"JOY15", K_JOY15}, - {"JOY16", K_JOY16}, - {"JOY17", K_JOY17}, - {"JOY18", K_JOY18}, - {"JOY19", K_JOY19}, - {"JOY20", K_JOY20}, - {"JOY21", K_JOY21}, - {"JOY22", K_JOY22}, - {"JOY23", K_JOY23}, - {"JOY24", K_JOY24}, - {"JOY25", K_JOY25}, - {"JOY26", K_JOY26}, - {"JOY27", K_JOY27}, - {"JOY28", K_JOY28}, - {"JOY29", K_JOY29}, - {"JOY30", K_JOY30}, - {"JOY31", K_JOY31}, - {"JOY32", K_JOY32}, - - {"AUX1", K_AUX1}, - {"AUX2", K_AUX2}, - {"AUX3", K_AUX3}, - {"AUX4", K_AUX4}, - {"AUX5", K_AUX5}, - {"AUX6", K_AUX6}, - {"AUX7", K_AUX7}, - {"AUX8", K_AUX8}, - {"AUX9", K_AUX9}, - {"AUX10", K_AUX10}, - {"AUX11", K_AUX11}, - {"AUX12", K_AUX12}, - {"AUX13", K_AUX13}, - {"AUX14", K_AUX14}, - {"AUX15", K_AUX15}, - {"AUX16", K_AUX16}, - - {"KP_HOME", K_KP_HOME }, - {"KP_UP", K_KP_UPARROW }, - {"KP_PGUP", K_KP_PGUP }, - {"KP_LEFT", K_KP_LEFTARROW }, - {"KP_5", K_KP_5 }, - {"KP_RIGHT", K_KP_RIGHTARROW }, - {"KP_END", K_KP_END }, - {"KP_DOWN", K_KP_DOWNARROW }, - {"KP_PGDN", K_KP_PGDN }, - {"KP_ENTER", K_KP_ENTER }, - {"KP_INS", K_KP_INS }, - {"KP_DEL", K_KP_DEL }, - {"KP_SLASH", K_KP_SLASH }, - {"KP_MINUS", K_KP_MINUS }, - {"KP_PLUS", K_KP_PLUS }, - {"KP_NUMLOCK", K_KP_NUMLOCK }, - {"KP_STAR", K_KP_STAR }, - {"KP_EQUALS", K_KP_EQUALS }, - - {"PAUSE", K_PAUSE}, - - {"SEMICOLON", ';'}, // because a raw semicolon seperates commands - - {NULL,0} -}; - -keyname_t keynames_d[] = //deutsch -{ - {"TAB", K_TAB}, - {"EINGABETASTE", K_ENTER}, - {"ESC", K_ESCAPE}, - {"LEERTASTE", K_SPACE}, - {"RÜCKTASTE", K_BACKSPACE}, - {"PFEILT.AUF", K_UPARROW}, - {"PFEILT.UNTEN", K_DOWNARROW}, - {"PFEILT.LINKS", K_LEFTARROW}, - {"PFEILT.RECHTS", K_RIGHTARROW}, - - {"ALT", K_ALT}, - {"STRG", K_CTRL}, - {"UMSCHALT", K_SHIFT}, - - {"FESTSTELLT", K_CAPSLOCK}, - - {"F1", K_F1}, - {"F2", K_F2}, - {"F3", K_F3}, - {"F4", K_F4}, - {"F5", K_F5}, - {"F6", K_F6}, - {"F7", K_F7}, - {"F8", K_F8}, - {"F9", K_F9}, - {"F10", K_F10}, - {"F11", K_F11}, - {"F12", K_F12}, - - {"EINFG", K_INS}, - {"ENTF", K_DEL}, - {"BILD-AB", K_PGDN}, - {"BILD-AUF", K_PGUP}, - {"POS1", K_HOME}, - {"ENDE", K_END}, - - {"MAUS1", K_MOUSE1}, - {"MAUS2", K_MOUSE2}, - {"MAUS3", K_MOUSE3}, - {"MAUS4", K_MOUSE4}, - {"MAUS5", K_MOUSE5}, - - {"MRADOBEN", K_MWHEELUP }, - {"MRADUNTEN", K_MWHEELDOWN }, - - {"JOY1", K_JOY1}, - {"JOY2", K_JOY2}, - {"JOY3", K_JOY3}, - {"JOY4", K_JOY4}, - {"JOY5", K_JOY5}, - {"JOY6", K_JOY6}, - {"JOY7", K_JOY7}, - {"JOY8", K_JOY8}, - {"JOY9", K_JOY9}, - {"JOY10", K_JOY10}, - {"JOY11", K_JOY11}, - {"JOY12", K_JOY12}, - {"JOY13", K_JOY13}, - {"JOY14", K_JOY14}, - {"JOY15", K_JOY15}, - {"JOY16", K_JOY16}, - {"JOY17", K_JOY17}, - {"JOY18", K_JOY18}, - {"JOY19", K_JOY19}, - {"JOY20", K_JOY20}, - {"JOY21", K_JOY21}, - {"JOY22", K_JOY22}, - {"JOY23", K_JOY23}, - {"JOY24", K_JOY24}, - {"JOY25", K_JOY25}, - {"JOY26", K_JOY26}, - {"JOY27", K_JOY27}, - {"JOY28", K_JOY28}, - {"JOY29", K_JOY29}, - {"JOY30", K_JOY30}, - {"JOY31", K_JOY31}, - {"JOY32", K_JOY32}, - - {"AUX1", K_AUX1}, - {"AUX2", K_AUX2}, - {"AUX3", K_AUX3}, - {"AUX4", K_AUX4}, - {"AUX5", K_AUX5}, - {"AUX6", K_AUX6}, - {"AUX7", K_AUX7}, - {"AUX8", K_AUX8}, - {"AUX9", K_AUX9}, - {"AUX10", K_AUX10}, - {"AUX11", K_AUX11}, - {"AUX12", K_AUX12}, - {"AUX13", K_AUX13}, - {"AUX14", K_AUX14}, - {"AUX15", K_AUX15}, - {"AUX16", K_AUX16}, - - {"ZB_POS1", K_KP_HOME }, - {"ZB_PFEILT.AUF", K_KP_UPARROW }, - {"ZB_BILD-AUF", K_KP_PGUP }, - {"ZB_PFEILT.LINKS", K_KP_LEFTARROW }, - {"ZB_5", K_KP_5 }, - {"ZB_PFEILT.RECHTS",K_KP_RIGHTARROW }, - {"ZB_ENDE", K_KP_END }, - {"ZB_PFEILT.UNTEN", K_KP_DOWNARROW }, - {"ZB_BILD-AB", K_KP_PGDN }, - {"ZB_ENTER", K_KP_ENTER }, - {"ZB_EINFG", K_KP_INS }, - {"ZB_ENTF", K_KP_DEL }, - {"ZB_SLASH", K_KP_SLASH }, - {"ZB_MINUS", K_KP_MINUS }, - {"ZB_PLUS", K_KP_PLUS }, - {"ZB_NUM", K_KP_NUMLOCK }, - {"ZB_*", K_KP_STAR }, - {"ZB_EQUALS", K_KP_EQUALS }, - - {"PAUSE", K_PAUSE}, - - {"COMMAND", K_COMMAND}, //mac - {NULL,0} -}; //end german - -keyname_t keynames_f[] = //french -{ - {"TAB", K_TAB}, - {"ENTREE", K_ENTER}, - {"ECHAP", K_ESCAPE}, - {"ESPACE", K_SPACE}, - {"RETOUR", K_BACKSPACE}, - {"HAUT", K_UPARROW}, - {"BAS", K_DOWNARROW}, - {"GAUCHE", K_LEFTARROW}, - {"DROITE", K_RIGHTARROW}, - - {"ALT", K_ALT}, - {"CTRL", K_CTRL}, - {"MAJ", K_SHIFT}, - - {"VERRMAJ", K_CAPSLOCK}, - - {"F1", K_F1}, - {"F2", K_F2}, - {"F3", K_F3}, - {"F4", K_F4}, - {"F5", K_F5}, - {"F6", K_F6}, - {"F7", K_F7}, - {"F8", K_F8}, - {"F9", K_F9}, - {"F10", K_F10}, - {"F11", K_F11}, - {"F12", K_F12}, - - {"INSER", K_INS}, - {"SUPPR", K_DEL}, - {"PGBAS", K_PGDN}, - {"PGHAUT", K_PGUP}, - {"ORIGINE", K_HOME}, - {"FIN", K_END}, - - {"SOURIS1", K_MOUSE1}, - {"SOURIS2", K_MOUSE2}, - {"SOURIS3", K_MOUSE3}, - {"SOURIS4", K_MOUSE4}, - {"SOURIS5", K_MOUSE5}, - - {"MOLETTEHT.", K_MWHEELUP }, - {"MOLETTEBAS", K_MWHEELDOWN }, - - {"JOY1", K_JOY1}, - {"JOY2", K_JOY2}, - {"JOY3", K_JOY3}, - {"JOY4", K_JOY4}, - {"JOY5", K_JOY5}, - {"JOY6", K_JOY6}, - {"JOY7", K_JOY7}, - {"JOY8", K_JOY8}, - {"JOY9", K_JOY9}, - {"JOY10", K_JOY10}, - {"JOY11", K_JOY11}, - {"JOY12", K_JOY12}, - {"JOY13", K_JOY13}, - {"JOY14", K_JOY14}, - {"JOY15", K_JOY15}, - {"JOY16", K_JOY16}, - {"JOY17", K_JOY17}, - {"JOY18", K_JOY18}, - {"JOY19", K_JOY19}, - {"JOY20", K_JOY20}, - {"JOY21", K_JOY21}, - {"JOY22", K_JOY22}, - {"JOY23", K_JOY23}, - {"JOY24", K_JOY24}, - {"JOY25", K_JOY25}, - {"JOY26", K_JOY26}, - {"JOY27", K_JOY27}, - {"JOY28", K_JOY28}, - {"JOY29", K_JOY29}, - {"JOY30", K_JOY30}, - {"JOY31", K_JOY31}, - {"JOY32", K_JOY32}, - - {"AUX1", K_AUX1}, - {"AUX2", K_AUX2}, - {"AUX3", K_AUX3}, - {"AUX4", K_AUX4}, - {"AUX5", K_AUX5}, - {"AUX6", K_AUX6}, - {"AUX7", K_AUX7}, - {"AUX8", K_AUX8}, - {"AUX9", K_AUX9}, - {"AUX10", K_AUX10}, - {"AUX11", K_AUX11}, - {"AUX12", K_AUX12}, - {"AUX13", K_AUX13}, - {"AUX14", K_AUX14}, - {"AUX15", K_AUX15}, - {"AUX16", K_AUX16}, - - {"PN_ORIGINE", K_KP_HOME }, - {"PN_HAUT", K_KP_UPARROW }, - {"PN_PGBAS", K_KP_PGUP }, - {"PN_GAUCHE", K_KP_LEFTARROW }, - {"PN_5", K_KP_5 }, - {"PN_DROITE", K_KP_RIGHTARROW }, - {"PN_FIN", K_KP_END }, - {"PN_BAS", K_KP_DOWNARROW }, - {"PN_PGBAS", K_KP_PGDN }, - {"PN_ENTR", K_KP_ENTER }, - {"PN_INSER", K_KP_INS }, - {"PN_SUPPR", K_KP_DEL }, - {"PN_SLASH", K_KP_SLASH }, - {"PN_MOINS", K_KP_MINUS }, - {"PN_PLUS", K_KP_PLUS }, - {"PN_VERRNUM", K_KP_NUMLOCK }, - {"PN_*", K_KP_STAR }, - {"PN_EQUALS", K_KP_EQUALS }, - - {"PAUSE", K_PAUSE}, - - {"COMMAND", K_COMMAND}, //mac - - {"POINT-VIRGULE", ';' }, // because a raw semicolon seperates commands - - {NULL,0} -}; //end french /* ============================================================================= @@ -614,7 +432,7 @@ void Field_VariableSizeDraw( field_t *edit, int x, int y, int width, int size, q return; // off blink } - if ( key_overstrikeMode ) { + if ( kg.key_overstrikeMode ) { cursorChar = 11; } else { cursorChar = 10; @@ -680,14 +498,14 @@ void Field_KeyDownEvent( field_t *edit, int key ) { int len; // shift-insert is paste - if ( ( ( key == K_INS ) || ( key == K_KP_INS ) ) && keys[K_SHIFT].down ) { + if ( ( ( key == A_INSERT ) || ( key == A_KP_0 ) ) && kg.keys[A_SHIFT].down ) { Field_Paste( edit ); return; } len = strlen( edit->buffer ); - if ( key == K_DEL ) { + if ( key == A_DELETE ) { if ( edit->cursor < len ) { memmove( edit->buffer + edit->cursor, edit->buffer + edit->cursor + 1, len - edit->cursor ); @@ -695,7 +513,7 @@ void Field_KeyDownEvent( field_t *edit, int key ) { return; } - if ( key == K_RIGHTARROW ) + if ( key == A_CURSOR_RIGHT ) { if ( edit->cursor < len ) { edit->cursor++; @@ -708,7 +526,7 @@ void Field_KeyDownEvent( field_t *edit, int key ) { return; } - if ( key == K_LEFTARROW ) + if ( key == A_CURSOR_LEFT ) { if ( edit->cursor > 0 ) { edit->cursor--; @@ -720,18 +538,20 @@ void Field_KeyDownEvent( field_t *edit, int key ) { return; } - if ( key == K_HOME || ( tolower(key) == 'a' && keys[K_CTRL].down ) ) { + if ( key == A_HOME || ( keynames[key].lower == 'a' && kg.keys[A_CTRL].down ) ) + { edit->cursor = 0; return; } - if ( key == K_END || ( tolower(key) == 'e' && keys[K_CTRL].down ) ) { + if ( key == A_END || ( keynames[key].lower == 'e' && kg.keys[A_CTRL].down ) ) + { edit->cursor = len; return; } - if ( key == K_INS ) { - key_overstrikeMode = (qboolean)!key_overstrikeMode; + if ( key == A_INSERT ) { + kg.key_overstrikeMode = (qboolean)!kg.key_overstrikeMode; return; } } @@ -788,7 +608,7 @@ void Field_CharEvent( field_t *edit, int ch ) { return; } - if ( key_overstrikeMode ) { + if ( kg.key_overstrikeMode ) { if ( edit->cursor == MAX_EDIT_LINE - 1 ) return; edit->buffer[edit->cursor] = ch; @@ -884,18 +704,18 @@ static void keyConcatArgs( void ) { char *arg; for ( i = 1 ; i < Cmd_Argc() ; i++ ) { - Q_strcat( g_consoleField.buffer, sizeof( g_consoleField.buffer ), " " ); + Q_strcat( kg.g_consoleField.buffer, sizeof( kg.g_consoleField.buffer ), " " ); arg = Cmd_Argv( i ); while (*arg) { if (*arg == ' ') { - Q_strcat( g_consoleField.buffer, sizeof( g_consoleField.buffer ), "\""); + Q_strcat( kg.g_consoleField.buffer, sizeof( kg.g_consoleField.buffer ), "\""); break; } arg++; } - Q_strcat( g_consoleField.buffer, sizeof( g_consoleField.buffer ), Cmd_Argv( i ) ); + Q_strcat( kg.g_consoleField.buffer, sizeof( kg.g_consoleField.buffer ), Cmd_Argv( i ) ); if (*arg == ' ') { - Q_strcat( g_consoleField.buffer, sizeof( g_consoleField.buffer ), "\""); + Q_strcat( kg.g_consoleField.buffer, sizeof( kg.g_consoleField.buffer ), "\""); } } } @@ -910,7 +730,7 @@ static void ConcatRemaining( const char *src, const char *start ) { } str += strlen(start); - Q_strcat( g_consoleField.buffer, sizeof( g_consoleField.buffer ), str); + Q_strcat( kg.g_consoleField.buffer, sizeof( kg.g_consoleField.buffer ), str); } @@ -926,7 +746,7 @@ void CompleteCommand( void ) field_t *edit; field_t temp; - edit = &g_consoleField; + edit = &kg.g_consoleField; // only look at the first token for completion purposes Cmd_TokenizeString( edit->buffer ); @@ -954,7 +774,7 @@ void CompleteCommand( void ) if ( matchCount == 1 ) { Com_sprintf( edit->buffer, sizeof( edit->buffer ), "\\%s", shortestMatch ); if ( Cmd_Argc() == 1 ) { - Q_strcat( g_consoleField.buffer, sizeof( g_consoleField.buffer ), " " ); + Q_strcat( kg.g_consoleField.buffer, sizeof( kg.g_consoleField.buffer ), " " ); } else { ConcatRemaining( temp.buffer, completionString ); } @@ -984,52 +804,52 @@ Handles history and console scrollback */ void Console_Key (int key) { // ctrl-L clears screen - if ( key == 'l' && keys[K_CTRL].down ) { + if ( keynames[ key ].lower == 'l' && kg.keys[A_CTRL].down ) { Cbuf_AddText ("clear\n"); return; } // enter finishes the line - if ( key == K_ENTER || key == K_KP_ENTER ) { + if ( key == A_ENTER || key == A_KP_ENTER ) { // if not in the game explicitly prepent a slash if needed - if ( cls.state != CA_ACTIVE && g_consoleField.buffer[0] != '\\' - && g_consoleField.buffer[0] != '/' ) { + if ( cls.state != CA_ACTIVE && kg.g_consoleField.buffer[0] != '\\' + && kg.g_consoleField.buffer[0] != '/' ) { char temp[MAX_STRING_CHARS]; - Q_strncpyz( temp, g_consoleField.buffer, sizeof( temp ) ); - Com_sprintf( g_consoleField.buffer, sizeof( g_consoleField.buffer ), "\\%s", temp ); - g_consoleField.cursor++; + Q_strncpyz( temp, kg.g_consoleField.buffer, sizeof( temp ) ); + Com_sprintf( kg.g_consoleField.buffer, sizeof( kg.g_consoleField.buffer ), "\\%s", temp ); + kg.g_consoleField.cursor++; } else { // Added this to automatically make explicit commands not need slashes. CompleteCommand(); } - Com_Printf ( "]%s\n", g_consoleField.buffer ); + Com_Printf ( "]%s\n", kg.g_consoleField.buffer ); // leading slash is an explicit command - if ( g_consoleField.buffer[0] == '\\' || g_consoleField.buffer[0] == '/' ) { - Cbuf_AddText( g_consoleField.buffer+1 ); // valid command + if ( kg.g_consoleField.buffer[0] == '\\' || kg.g_consoleField.buffer[0] == '/' ) { + Cbuf_AddText( kg.g_consoleField.buffer+1 ); // valid command Cbuf_AddText ("\n"); } else { // other text will be chat messages - if ( !g_consoleField.buffer[0] ) { + if ( !kg.g_consoleField.buffer[0] ) { return; // empty lines just scroll the console without adding to history } else { Cbuf_AddText ("cmd say "); - Cbuf_AddText( g_consoleField.buffer ); + Cbuf_AddText( kg.g_consoleField.buffer ); Cbuf_AddText ("\n"); } } // copy line to history buffer - historyEditLines[nextHistoryLine % COMMAND_HISTORY] = g_consoleField; - nextHistoryLine++; - historyLine = nextHistoryLine; + kg.historyEditLines[kg.nextHistoryLine % COMMAND_HISTORY] = kg.g_consoleField; + kg.nextHistoryLine++; + kg.historyLine = kg.nextHistoryLine; - Field_Clear( &g_consoleField ); + Field_Clear( &kg.g_consoleField ); - g_consoleField.widthInChars = g_console_field_width; + kg.g_consoleField.widthInChars = g_console_field_width; if ( cls.state == CA_DISCONNECTED ) { SCR_UpdateScreen (); // force an update, because the command @@ -1039,57 +859,57 @@ void Console_Key (int key) { // command completion - if (key == K_TAB) { + if (key == A_TAB) { CompleteCommand(); return; } // command history (ctrl-p ctrl-n for unix style) - if ( ( key == K_UPARROW ) || ( key == K_KP_UPARROW ) || - ( ( tolower(key) == 'p' ) && keys[K_CTRL].down ) ) { - if ( nextHistoryLine - historyLine < COMMAND_HISTORY - && historyLine > 0 ) { - historyLine--; + if ( ( key == A_CURSOR_UP ) || ( ( keynames[ key ].lower == 'p' ) && kg.keys[A_CTRL].down ) ) + { + if ( kg.nextHistoryLine - kg.historyLine < COMMAND_HISTORY && kg.historyLine > 0 ) + { + kg.historyLine--; } - g_consoleField = historyEditLines[ historyLine % COMMAND_HISTORY ]; + kg.g_consoleField = kg.historyEditLines[ kg.historyLine % COMMAND_HISTORY ]; return; } - if ( ( key == K_DOWNARROW ) || ( key == K_KP_DOWNARROW ) || - ( ( tolower(key) == 'n' ) && keys[K_CTRL].down ) ) { - if (historyLine == nextHistoryLine) + if ( ( key == A_CURSOR_DOWN ) || ( ( keynames[ key ].lower == 'n' ) && kg.keys[A_CTRL].down ) ) + { + if (kg.historyLine == kg.nextHistoryLine) return; - historyLine++; - g_consoleField = historyEditLines[ historyLine % COMMAND_HISTORY ]; + kg.historyLine++; + kg.g_consoleField = kg.historyEditLines[ kg.historyLine % COMMAND_HISTORY ]; return; } // console scrolling - if ( key == K_PGUP ) { + if ( key == A_PAGE_UP ) { Con_PageUp(); return; } - if ( key == K_PGDN ) { + if ( key == A_PAGE_DOWN ) { Con_PageDown(); return; } // ctrl-home = top of console - if ( key == K_HOME && keys[K_CTRL].down ) { + if ( key == A_HOME && kg.keys[A_CTRL].down ) { Con_Top(); return; } // ctrl-end = bottom of console - if ( key == K_END && keys[K_CTRL].down ) { + if ( key == A_END && kg.keys[A_CTRL].down ) { Con_Bottom(); return; } // pass to the normal editline routine - Field_KeyDownEvent( &g_consoleField, key ); + Field_KeyDownEvent( &kg.g_consoleField, key ); } //============================================================================ @@ -1107,13 +927,13 @@ void Message_Key( int key ) { char buffer[MAX_STRING_CHARS]; - if (key == K_ESCAPE) { + if (key == A_ESCAPE) { cls.keyCatchers &= ~KEYCATCH_MESSAGE; Field_Clear( &chatField ); return; } - if ( key == K_ENTER || key == K_KP_ENTER ) + if ( key == A_ENTER || key == A_KP_ENTER ) { if ( chatField.buffer[0] && cls.state == CA_ACTIVE ) { if (chat_playerNum != -1 ) @@ -1142,12 +962,12 @@ void Message_Key( int key ) { qboolean Key_GetOverstrikeMode( void ) { - return key_overstrikeMode; + return kg.key_overstrikeMode; } void Key_SetOverstrikeMode( qboolean state ) { - key_overstrikeMode = state; + kg.key_overstrikeMode = state; } @@ -1161,7 +981,7 @@ qboolean Key_IsDown( int keynum ) { return qfalse; } - return keys[keynum].down; + return kg.keys[ keynames[keynum].upper ].down; } @@ -1174,54 +994,158 @@ the given string. Single ascii characters return themselves, while the K_* names are matched up. 0x11 will be interpreted as raw hex, which will allow new controlers - to be configured even if they don't have defined names. =================== */ int Key_StringToKeynum( char *str ) { - keyname_t *kn; + int i; - if ( !str || !str[0] ) { + if ( !str || !str[0] ) + { return -1; } - if ( !str[1] ) { - return str[0]; + // If single char bind, presume ascii char bind + if ( !str[1] ) + { + return keynames[ (unsigned char)str[0] ].upper; + } + + // scan for a text match + for ( i = 0 ; i < MAX_KEYS ; i++ ) + { + if ( keynames[i].name && !stricmp( str, keynames[i].name ) ) + { + return keynames[i].keynum; + } } // check for hex code - if ( str[0] == '0' && str[1] == 'x' && strlen( str ) == 4) { + if ( str[0] == '0' && str[1] == 'x' && strlen( str ) == 4) + { int n1, n2; n1 = str[2]; - if ( n1 >= '0' && n1 <= '9' ) { + if ( n1 >= '0' && n1 <= '9' ) + { n1 -= '0'; - } else if ( n1 >= 'a' && n1 <= 'f' ) { - n1 = n1 - 'a' + 10; - } else { + } + else if ( n1 >= 'A' && n1 <= 'F' ) + { + n1 = n1 - 'A' + 10; + } + else + { n1 = 0; } n2 = str[3]; - if ( n2 >= '0' && n2 <= '9' ) { + if ( n2 >= '0' && n2 <= '9' ) + { n2 -= '0'; - } else if ( n2 >= 'a' && n2 <= 'f' ) { - n2 = n2 - 'a' + 10; - } else { + } + else if ( n2 >= 'A' && n2 <= 'F' ) + { + n2 = n2 - 'A' + 10; + } + else + { n2 = 0; } - return n1 * 16 + n2; } - // scan for a text match - for ( kn=keynames ; kn->name ; kn++ ) { - if ( !Q_stricmp( str,kn->name ) ) - return kn->keynum; - } - return -1; } + +static char tinyString[16]; +static const char *Key_KeynumValid( int keynum ) +{ + if ( keynum == -1 ) + { + return ""; + } + if ( keynum < 0 || keynum >= MAX_KEYS ) + { + return ""; + } + return NULL; +} + +static const char *Key_KeyToName( int keynum ) +{ + return keynames[keynum].name; +} + + +static const char *Key_KeyToAscii( int keynum ) +{ + if(!keynames[keynum].lower) + { + return(NULL); + } + if(keynum == A_SPACE) + { + tinyString[0] = (char)A_SHIFT_SPACE; + } + else if(keynum == A_ENTER) + { + tinyString[0] = (char)A_SHIFT_ENTER; + } + else if(keynum == A_KP_ENTER) + { + tinyString[0] = (char)A_SHIFT_KP_ENTER; + } + else + { + tinyString[0] = keynames[keynum].upper; + } + tinyString[1] = 0; + return tinyString; +} + +static const char *Key_KeyToHex( int keynum ) +{ + int i, j; + + i = keynum >> 4; + j = keynum & 15; + + tinyString[0] = '0'; + tinyString[1] = 'x'; + tinyString[2] = i > 9 ? i - 10 + 'A' : i + '0'; + tinyString[3] = j > 9 ? j - 10 + 'A' : j + '0'; + tinyString[4] = 0; + + return tinyString; +} + +// Returns the ascii code of the keynum +const char *Key_KeynumToAscii( int keynum ) +{ + const char *name; + + name = Key_KeynumValid(keynum); + + // check for printable ascii + if ( !name && keynum > 0 && keynum < 256 ) + { + name = Key_KeyToAscii(keynum); + } + // Check for name (for JOYx and AUXx buttons) + if ( !name ) + { + name = Key_KeyToName(keynum); + } + // Fallback to hex number + if ( !name ) + { + name = Key_KeyToHex(keynum); + } + return name; +} + + /* =================== Key_KeynumToString @@ -1230,62 +1154,33 @@ Returns a string (either a single ascii char, a K_* name, or a 0x11 hex string) given keynum. =================== */ -extern cvar_t *sp_language; -char *Key_KeynumToString( int keynum, qboolean bTranslate ) //note: translate is only called for menu display not configs +// Returns a console/config file friendly name for the key +const char *Key_KeynumToString( int keynum ) { - keyname_t *kn; - static char tinystr[5]; - int i, j; + const char *name; - if ( keynum == -1 ) { - return ""; + name = Key_KeynumValid(keynum); + + // Check for friendly name + if ( !name ) + { + name = Key_KeyToName(keynum); } - - if ( keynum < 0 || keynum > 255 ) { - return ""; + // check for printable ascii + if ( !name && keynum > 0 && keynum < 256) + { + name = Key_KeyToAscii(keynum); } - - // check for printable ascii (don't use quote) - if ( keynum > 32 && keynum < 127 && keynum != '"' && keynum != ';' ) { - tinystr[0] = keynum; - tinystr[1] = 0; - return tinystr; + // Fallback to hex number + if ( !name ) + { + name = Key_KeyToHex(keynum); } - - kn=keynames; //init to english - if (bTranslate) { - if ( sp_language->integer == SP_LANGUAGE_GERMAN ) { - kn=keynames_d; //use german - } else if ( sp_language->integer == SP_LANGUAGE_FRENCH ) { - kn=keynames_f; //use french - } - else //rww - this is actually English and doesn't need to be "translated". - { //however, certain key names are too long to display right, this does the trick. - kn=keynames_e; - } - } - - // check for a key string - for ( ; kn->name ; kn++ ) { - if (keynum == kn->keynum) { - return kn->name; - } - } - - // make a hex string - i = keynum >> 4; - j = keynum & 15; - - tinystr[0] = '0'; - tinystr[1] = 'x'; - tinystr[2] = i > 9 ? i - 10 + 'a' : i + '0'; - tinystr[3] = j > 9 ? j - 10 + 'a' : j + '0'; - tinystr[4] = 0; - - return tinystr; + return name; } + /* =================== Key_SetBinding @@ -1297,12 +1192,16 @@ void Key_SetBinding( int keynum, const char *binding ) { } // free old bindings - if ( keys[ keynum ].binding ) { - Z_Free( keys[ keynum ].binding ); + if ( kg.keys[ keynames[keynum].upper ].binding ) { + Z_Free( kg.keys[ keynames[keynum].upper ].binding ); + kg.keys[ keynames[keynum].upper ].binding = NULL; } - + // allocate memory for new binding - keys[keynum].binding = CopyString( binding ); + if (binding) + { + kg.keys[ keynames[keynum].upper ].binding = CopyString( binding ); + } // consider this like modifying an archived cvar, so the // file write will be triggered at the next oportunity @@ -1320,7 +1219,7 @@ char *Key_GetBinding( int keynum ) { return ""; } - return keys[ keynum ].binding; + return kg.keys[ keynum ].binding; } /* @@ -1334,7 +1233,7 @@ int Key_GetKey(const char *binding) { if (binding) { for (i=0 ; i<256 ; i++) { - if (keys[i].binding && Q_stricmp(binding, keys[i].binding) == 0) { + if (kg.keys[i].binding && Q_stricmp(binding, kg.keys[i].binding) == 0) { return i; } } @@ -1376,12 +1275,17 @@ void Key_Unbindall_f (void) { int i; - for (i=0 ; i<256 ; i++) - if (keys[i].binding) + for (i = 0; i < MAX_KEYS ; i++) + { + if (kg.keys[i].binding) + { Key_SetBinding (i, ""); + } + } } + /* =================== Key_Bind_f @@ -1408,8 +1312,8 @@ void Key_Bind_f (void) if (c == 2) { - if (keys[b].binding) - Com_Printf ("\"%s\" = \"%s\"\n", Cmd_Argv(1), keys[b].binding ); + if (kg.keys[b].binding) + Com_Printf ("\"%s\" = \"%s\"\n", Cmd_Argv(1), kg.keys[b].binding ); else Com_Printf ("\"%s\" is not bound\n", Cmd_Argv(1) ); return; @@ -1438,17 +1342,16 @@ void Key_WriteBindings( fileHandle_t f ) { int i; FS_Printf (f, "unbindall\n" ); - - for (i=0 ; i<256 ; i++) { - if (keys[i].binding && keys[i].binding[0] ) { - FS_Printf (f, "bind %s \"%s\"\n", Key_KeynumToString(i, qfalse), keys[i].binding); - + for (i=0 ; i= 200) { - Com_Printf ("%s is unbound, use controls menu to set.\n" - , Key_KeynumToString( key, qfalse ) ); - } - } else if (kb[0] == '+') { - int i; - char button[1024], *buttonPtr; - buttonPtr = button; - for ( i = 0; ; i++ ) { - if ( kb[i] == ';' || !kb[i] ) { - *buttonPtr = '\0'; - if ( button[0] == '+') { - // button commands add keynum and time as parms so that multiple - // sources can be discriminated and subframe corrected - Com_sprintf (cmd, sizeof(cmd), "%s %i %i\n", button, key, time); - Cbuf_AddText (cmd); - } else { - // down-only command - Cbuf_AddText (button); - Cbuf_AddText ("\n"); + kb = kg.keys[ keynames[key].upper ].binding; + if (kb) + { + if (kb[0] == '+') { + int i; + char button[1024], *buttonPtr; + buttonPtr = button; + for ( i = 0; ; i++ ) { + if ( kb[i] == ';' || !kb[i] ) { + *buttonPtr = '\0'; + if ( button[0] == '+') { + // button commands add keynum and time as parms so that multiple + // sources can be discriminated and subframe corrected + Com_sprintf (cmd, sizeof(cmd), "%s %i %i\n", button, key, time); + Cbuf_AddText (cmd); + } else { + // down-only command + Cbuf_AddText (button); + Cbuf_AddText ("\n"); + } + buttonPtr = button; + while ( (kb[i] <= ' ' || kb[i] == ';') && kb[i] != 0 ) { + i++; + } } - buttonPtr = button; - while ( (kb[i] <= ' ' || kb[i] == ';') && kb[i] != 0 ) { - i++; + *buttonPtr++ = kb[i]; + if ( !kb[i] ) { + break; } } - *buttonPtr++ = kb[i]; - if ( !kb[i] ) { - break; - } + } else { + // down-only command + Cbuf_AddText (kb); + Cbuf_AddText ("\n"); } - } else { - // down-only command - Cbuf_AddText (kb); - Cbuf_AddText ("\n"); } } } @@ -1703,7 +1611,7 @@ void CL_CharEvent( int key ) { // distribute the key down event to the apropriate handler if ( cls.keyCatchers & KEYCATCH_CONSOLE ) { - Field_CharEvent( &g_consoleField, key ); + Field_CharEvent( &kg.g_consoleField, key ); } else if ( cls.keyCatchers & KEYCATCH_UI ) { @@ -1715,7 +1623,7 @@ void CL_CharEvent( int key ) { } else if ( cls.state == CA_DISCONNECTED ) { - Field_CharEvent( &g_consoleField, key ); + Field_CharEvent( &kg.g_consoleField, key ); } } @@ -1729,15 +1637,15 @@ void Key_ClearStates (void) { int i; - anykeydown = qfalse; + kg.anykeydown = qfalse; for ( i=0 ; i < MAX_KEYS ; i++ ) { - if ( keys[i].down ) { + if ( kg.keys[i].down ) { CL_KeyEvent( i, qfalse, 0 ); } - keys[i].down = (qboolean)0; - keys[i].repeats = 0; + kg.keys[i].down = (qboolean)0; + kg.keys[i].repeats = 0; } } diff --git a/CODE-mp/client/cl_main.cpp b/CODE-mp/client/cl_main.cpp index f539be8..cd6798b 100644 --- a/CODE-mp/client/cl_main.cpp +++ b/CODE-mp/client/cl_main.cpp @@ -9,6 +9,12 @@ #include "..\ghoul2\G2_local.h" #endif +#ifdef G2_COLLISION_ENABLED +#if !defined (MINIHEAP_H_INC) +#include "../qcommon/miniheap.h" +#endif +#endif + #ifdef _DONETPROFILE_ #include "../qcommon/INetProfile.h" #endif @@ -93,6 +99,10 @@ typedef struct serverStatus_s serverStatus_t cl_serverStatusList[MAX_SERVERSTATUSREQUESTS]; int serverStatusCount; +#ifdef G2_COLLISION_ENABLED +CMiniHeap *G2VertSpaceClient = 0; +#endif + #if defined __USEA3D && defined __A3D_GEOM void hA3Dg_ExportRenderGeom (refexport_t *incoming_re); #endif @@ -514,13 +524,7 @@ void CL_PlayDemo_f( void ) { if (!clc.demofile) { if (!Q_stricmp(arg, "(null)")) { - extern cvar_t *sp_language; - switch (sp_language->integer) - { - case SP_LANGUAGE_GERMAN: Com_Error( ERR_DROP, "Kein demo ausgewählt." ); break; - case SP_LANGUAGE_FRENCH: Com_Error( ERR_DROP, "Aucun demo choisi." ); break; - default: Com_Error( ERR_DROP, "No demo selected." ); break; - } + Com_Error( ERR_DROP, SP_GetStringTextString("CON_TEXT_NO_DEMO_SELECTED") ); } else { @@ -758,9 +762,6 @@ void CL_Disconnect( qboolean showMainMenu ) { cls.state = CA_DISCONNECTED; - // allow cheats locally - Cvar_Set( "sv_cheats", "1" ); - // not connected to a pure server anymore cl_connectedToPureServer = qfalse; } @@ -1033,23 +1034,7 @@ void CL_Connect_f( void ) { if ( !Cvar_VariableValue("fs_restrict") && !Sys_CheckCD() ) { - int iLanguage = Cvar_VariableValue("sp_language"); - //rww - we don't have an actual cvar object for sp_language to use here. - - if (iLanguage) // dunno if SP files are loaded at this point if no CD... - { - switch (iLanguage) - { - case SP_LANGUAGE_GERMAN: - Com_Error( ERR_NEED_CD, "Spiel CD nicht im Laufwerk" ); - break; // keep compiler happy - case SP_LANGUAGE_FRENCH: - Com_Error( ERR_NEED_CD, "CD de jeu pas dans le lecteur" ); - break; // keep compiler happy - } - } - - Com_Error( ERR_NEED_CD, "Game CD not in drive" ); + Com_Error( ERR_NEED_CD, SP_GetStringTextString("CON_TEXT_NEED_CD") ); //"Game CD not in drive" ); } if ( Cmd_Argc() != 2 ) { @@ -1238,6 +1223,7 @@ void CL_Vid_Restart_f( void ) { // if not running a server clear the whole hunk if ( !com_sv_running->integer ) { + CM_ClearMap(); // clear the whole hunk Hunk_Clear(); } @@ -1665,7 +1651,11 @@ void CL_InitServerInfo( serverInfo_t *server, serverAddress_t *address ) { server->game[0] = '\0'; server->gameType = 0; server->netType = 0; - server->allowAnonymous = 0; + server->needPassword = qfalse; + server->trueJedi = 0; + server->weaponDisable = 0; + server->forceDisable = 0; + //server->pure = qfalse; } #define MAX_SERVERSPERPACKET 256 @@ -2096,6 +2086,10 @@ void CL_CheckUserinfo( void ) { } +#ifdef G2_COLLISION_ENABLED +extern CMiniHeap *G2VertSpaceServer; +#endif + /* ================== CL_Frame @@ -2125,10 +2119,14 @@ void CL_Frame ( int msec ) { if ( cl_avidemo->integer && msec) { // save the current screen if ( cls.state == CA_ACTIVE || cl_forceavidemo->integer) { - Cbuf_ExecuteText( EXEC_NOW, "screenshot silent\n" ); + if (cl_avidemo->integer > 0) { + Cbuf_ExecuteText( EXEC_NOW, "screenshot silent\n" ); + } else { + Cbuf_ExecuteText( EXEC_NOW, "screenshot_tga silent\n" ); + } } // fixed time for next frame' - msec = (1000 / cl_avidemo->integer) * com_timescale->value; + msec = (1000 / abs(cl_avidemo->integer)) * com_timescale->value; if (msec == 0) { msec = 1; } @@ -2194,7 +2192,13 @@ void CL_Frame ( int msec ) { SCR_RunCinematic(); Con_RunConsole(); - +#ifdef G2_COLLISION_ENABLED + // reset the heap for Ghoul2 vert transform space gameside + if (G2VertSpaceServer) + { + G2VertSpaceServer->ResetHeap(); + } +#endif cls.framecount++; } @@ -2260,7 +2264,7 @@ void CL_InitRenderer( void ) { cls.whiteShader = re.RegisterShader( "white" ); cls.consoleShader = re.RegisterShader( "console" ); g_console_field_width = cls.glconfig.vidWidth / SMALLCHAR_WIDTH - 2; - g_consoleField.widthInChars = g_console_field_width; + kg.g_consoleField.widthInChars = g_console_field_width; } /* @@ -2401,19 +2405,9 @@ void CL_SetForcePowers_f( void ) { return; } -/* -======================= -Register_StringPackets -======================= -*/ -void Register_StringPackets (void) -{ - SP_Register("con_text", SP_REGISTER_REQUIRED); //reference is CON_TEXT - SP_Register("mp_ingame",SP_REGISTER_REQUIRED); //reference is INGAMETEXT - SP_Register("mp_svgame",SP_REGISTER_REQUIRED); //reference is SVINGAME - SP_Register("sp_ingame",SP_REGISTER_REQUIRED); //reference is INGAME , needed for item pickups -} - +#ifdef G2_COLLISION_ENABLED +#define G2_VERT_SPACE_CLIENT_SIZE 256 +#endif /* ==================== @@ -2423,8 +2417,6 @@ CL_Init void CL_Init( void ) { Com_Printf( "----- Client Initialization -----\n" ); - Register_StringPackets(); - Con_Init (); CL_ClearState (); @@ -2565,6 +2557,10 @@ void CL_Init( void ) { Cvar_Set( "cl_running", "1" ); +#ifdef G2_COLLISION_ENABLED + G2VertSpaceClient = new CMiniHeap(G2_VERT_SPACE_CLIENT_SIZE * 1024); +#endif + Com_Printf( "----- Client Initialization Complete -----\n" ); } @@ -2586,6 +2582,14 @@ void CL_Shutdown( void ) { } recursive = qtrue; +#ifdef G2_COLLISION_ENABLED + if (G2VertSpaceClient) + { + delete G2VertSpaceClient; + G2VertSpaceClient = 0; + } +#endif + CL_Disconnect( qtrue ); CL_ShutdownRef(); //must be before shutdown all so the images get dumped in RE_Shutdown @@ -2639,7 +2643,12 @@ static void CL_SetServerInfo(serverInfo_t *server, const char *info, int ping) { server->netType = atoi(Info_ValueForKey(info, "nettype")); server->minPing = atoi(Info_ValueForKey(info, "minping")); server->maxPing = atoi(Info_ValueForKey(info, "maxping")); - server->allowAnonymous = atoi(Info_ValueForKey(info, "sv_allowAnonymous")); +// server->allowAnonymous = atoi(Info_ValueForKey(info, "sv_allowAnonymous")); + server->needPassword = (qboolean)atoi(Info_ValueForKey(info, "needpass" )); + server->trueJedi = atoi(Info_ValueForKey(info, "truejedi" )); + server->weaponDisable = atoi(Info_ValueForKey(info, "wdisable" )); + server->forceDisable = atoi(Info_ValueForKey(info, "fdisable" )); +// server->pure = (qboolean)atoi(Info_ValueForKey(info, "pure" )); } server->ping = ping; } @@ -2770,7 +2779,12 @@ void CL_ServerInfoPacket( netadr_t from, msg_t *msg ) { cls.localServers[i].game[0] = '\0'; cls.localServers[i].gameType = 0; cls.localServers[i].netType = from.type; - cls.localServers[i].allowAnonymous = 0; +// cls.localServers[i].allowAnonymous = 0; + cls.localServers[i].needPassword = qfalse; + cls.localServers[i].trueJedi = 0; + cls.localServers[i].weaponDisable = 0; + cls.localServers[i].forceDisable = 0; +// cls.localServers[i].pure = qfalse; Q_strncpyz( info, MSG_ReadString( msg ), MAX_INFO_STRING ); if (strlen(info)) { diff --git a/CODE-mp/client/cl_ui.cpp b/CODE-mp/client/cl_ui.cpp index d5530b5..026369d 100644 --- a/CODE-mp/client/cl_ui.cpp +++ b/CODE-mp/client/cl_ui.cpp @@ -152,10 +152,19 @@ static int LAN_AddServer(int source, const char *name, const char *address) { case AS_FAVORITES : count = &cls.numfavoriteservers; servers = &cls.favoriteServers[0]; +/* if (!name || !*name) + { + name = "?"; + } +*/ break; } if (servers && *count < max) { NET_StringToAdr( address, &adr ); + if (adr.type == NA_BAD) + { + return -1; + } for ( i = 0; i < *count; i++ ) { if (NET_CompareAdr(servers[i].adr, adr)) { break; @@ -204,7 +213,7 @@ static void LAN_RemoveServer(int source, const char *addr) { netadr_t comp; NET_StringToAdr( addr, &comp ); for (i = 0; i < *count; i++) { - if (NET_CompareAdr( comp, servers[i].adr)) { + if (servers[i].adr.type==NA_BAD || NET_CompareAdr( comp, servers[i].adr)) { int j = i; while (j < *count - 1) { Com_Memcpy(&servers[j], &servers[j+1], sizeof(servers[j])); @@ -320,7 +329,12 @@ static void LAN_GetServerInfo( int source, int n, char *buf, int buflen ) { Info_SetValueForKey( info, "gametype", va("%i",server->gameType)); Info_SetValueForKey( info, "nettype", va("%i",server->netType)); Info_SetValueForKey( info, "addr", NET_AdrToString(server->adr)); - Info_SetValueForKey( info, "sv_allowAnonymous", va("%i", server->allowAnonymous)); +// Info_SetValueForKey( info, "sv_allowAnonymous", va("%i", server->allowAnonymous)); + Info_SetValueForKey( info, "needpass", va("%i", server->needPassword ) ); + Info_SetValueForKey( info, "truejedi", va("%i", server->trueJedi ) ); + Info_SetValueForKey( info, "wdisable", va("%i", server->weaponDisable ) ); + Info_SetValueForKey( info, "fdisable", va("%i", server->forceDisable ) ); +// Info_SetValueForKey( info, "pure", va("%i", server->pure ) ); Q_strncpyz(buf, info, buflen); } else { if (buf) { @@ -640,10 +654,21 @@ static void GetClipboardData( char *buf, int buflen ) { Key_KeynumToStringBuf ==================== */ -static void Key_KeynumToStringBuf( int keynum, char *buf, int buflen ) { - Q_strncpyz( buf, Key_KeynumToString( keynum, qtrue ), buflen ); +// only ever called by binding-display code, therefore returns non-technical "friendly" names +// in any language that don't necessarily match those in the config file... +// +void Key_KeynumToStringBuf( int keynum, char *buf, int buflen ) +{ + const char *psKeyName = Key_KeynumToString( keynum/*, qtrue */); + + // see if there's a more friendly (or localised) name... + // + const char *psKeyNameFriendly = SP_GetStringTextString( va("KEYNAMES_KEYNAME_%s",psKeyName) ); + + Q_strncpyz( buf, (psKeyNameFriendly && psKeyNameFriendly[0]) ? psKeyNameFriendly : psKeyName, buflen ); } + /* ==================== Key_GetBindingBuf @@ -1045,8 +1070,14 @@ int CL_UISystemCalls( int *args ) { re.Font_DrawString( args[1], args[2], (const char *)VMA(3), (const float *) VMA(4), args[5], args[6], VMF(7) ); return 0; + case UI_LANGUAGE_ISASIAN: + return re.Language_IsAsian(); + + case UI_LANGUAGE_USESSPACES: + return re.Language_UsesSpaces(); + case UI_ANYLANGUAGE_READCHARFROMSTRING: - return re.AnyLanguage_ReadCharFromString( (const char **)VMA(1) ); + return re.AnyLanguage_ReadCharFromString( (const char *)VMA(1), (int *) VMA(2), (qboolean *) VMA(3) ); case UI_MEMSET: Com_Memset( VMA(1), args[2], args[3] ); @@ -1181,7 +1212,6 @@ void CL_ShutdownUI( void ) { CL_InitUI ==================== */ -#define UI_OLD_API_VERSION 4 void CL_InitUI( void ) { int v; @@ -1202,12 +1232,7 @@ void CL_InitUI( void ) { // sanity check v = VM_Call( uivm, UI_GETAPIVERSION ); - if (v == UI_OLD_API_VERSION) { -// Com_Printf(S_COLOR_YELLOW "WARNING: loading old Quake III Arena User Interface version %d\n", v ); - // init for this gamestate - VM_Call( uivm, UI_INIT, (cls.state >= CA_AUTHORIZING && cls.state < CA_ACTIVE)); - } - else if (v != UI_API_VERSION) { + if (v != UI_API_VERSION) { Com_Error( ERR_DROP, "User Interface is version %d, expected %d", v, UI_API_VERSION ); cls.uiStarted = qfalse; } diff --git a/CODE-mp/client/client.h b/CODE-mp/client/client.h index 9956a70..bfcd434 100644 --- a/CODE-mp/client/client.h +++ b/CODE-mp/client/client.h @@ -234,7 +234,12 @@ typedef struct { int maxPing; int ping; qboolean visible; - int allowAnonymous; +// int allowAnonymous; + qboolean needPassword; + int trueJedi; + int weaponDisable; + int forceDisable; +// qboolean pure; } serverInfo_t; typedef struct { @@ -437,7 +442,7 @@ void IN_CenterView (void); void CL_VerifyCode( void ); float CL_KeyState (kbutton_t *key); -char *Key_KeynumToString( int keynum, qboolean bTranslate ); //note: translate is only called for menu display not configs +const char *Key_KeynumToString( int keynum/*, qboolean bTranslate */ ); //note: translate is only called for menu display not configs // // cl_parse.c diff --git a/CODE-mp/client/eax/EaxMan.h b/CODE-mp/client/eax/EaxMan.h new file mode 100644 index 0000000..c885b6d --- /dev/null +++ b/CODE-mp/client/eax/EaxMan.h @@ -0,0 +1,165 @@ +/* +*/ +#ifndef __EAXMANH +#define __EAXMANH + +#define COM_NO_WINDOWS_H +#include +#include "eax.h" + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +#define CLSID_EAXMANAGER CLSID_EAX20_Manager +#define IID_IEaxManager IID_EAX20_Manager +#define EM_MAX_NAME 32 + +#define EMFLAG_IDDEFAULT (-1) +#define EMFLAG_IDNONE (-2) +#define EMFLAG_LOCKPOSITION 1 +#define EMFLAG_LOADFROMMEMORY 2 +#define EMFLAG_NODIFFRACTION 4 + +typedef struct _EMPOINT { + float fX; + float fY; + float fZ; +} EMPOINT; +typedef EMPOINT FAR *LPEMPOINT; + +typedef struct _LISTENERATTRIBUTES { + float fDistanceFactor; + float fRolloffFactor; + float fDopplerFactor; +} LISTENERATTRIBUTES; +typedef LISTENERATTRIBUTES FAR *LPLISTENERATTRIBUTES; + +typedef struct _SOURCEATTRIBUTES { + EAXBUFFERPROPERTIES eaxAttributes; + unsigned long ulInsideConeAngle; + unsigned long ulOutsideConeAngle; + long lConeOutsideVolume; + float fConeXdir; + float fConeYdir; + float fConeZdir; + float fMinDistance; + float fMaxDistance; + long lDupCount; + long lPriority; +} SOURCEATTRIBUTES; +typedef SOURCEATTRIBUTES FAR *LPSOURCEATTRIBUTES; + +typedef struct _MATERIALATTRIBUTES { + long lLevel; + float fLFRatio; + float fRoomRatio; + DWORD dwFlags; +} MATERIALATTRIBUTES; +typedef MATERIALATTRIBUTES FAR *LPMATERIALATTRIBUTES; + +#define EMMATERIAL_OBSTRUCTS 1 +#define EMMATERIAL_OCCLUDES 3 + +typedef struct _DIFFRACTIONBOX { + long lSubspaceID; + EMPOINT empMin; + EMPOINT empMax; +} DIFFRACTIONBOX; +typedef DIFFRACTIONBOX FAR *LPDIFFRACTIONBOX; + +// {7CE4D6E6-562F-11d3-8812-005004062F83} +DEFINE_GUID(CLSID_EAXMANAGER, 0x60b721a1, 0xf7c8, 0x11d2, 0xa0, 0x2e, 0x0, 0x50, 0x4, 0x6, 0x18, 0xb8); + +#ifdef __cplusplus +struct IEaxManager; +#endif // __cplusplus + +typedef struct IEaxManager *LPEAXMANAGER; + +// {7CE4D6E8-562F-11d3-8812-005004062F83} +DEFINE_GUID(IID_IEaxManager, 0x60b721a2, 0xf7c8, 0x11d2, 0xa0, 0x2e, 0x0, 0x50, 0x4, 0x6, 0x18, 0xb8); + +#undef INTERFACE +#define INTERFACE IEaxManager + +extern HRESULT __stdcall EaxManagerCreate(LPEAXMANAGER*); +typedef HRESULT (__stdcall *LPEAXMANAGERCREATE)(LPEAXMANAGER*); + +DECLARE_INTERFACE_(IEaxManager, IUnknown) +{ + // IUnknown methods + STDMETHOD(QueryInterface) (THIS_ REFIID, LPVOID *) PURE; + STDMETHOD_(ULONG,AddRef) (THIS) PURE; + STDMETHOD_(ULONG,Release) (THIS) PURE; + + STDMETHOD(GetDataSetSize) (THIS_ unsigned long*, DWORD) PURE; + STDMETHOD(LoadDataSet) (THIS_ char*, DWORD) PURE; + STDMETHOD(FreeDataSet) (THIS_ DWORD) PURE; + STDMETHOD(GetListenerAttributes) (THIS_ LPLISTENERATTRIBUTES) PURE; + STDMETHOD(GetSourceID) (THIS_ char*, long*) PURE; + STDMETHOD(GetSourceAttributes) (THIS_ long, LPSOURCEATTRIBUTES) PURE; + STDMETHOD(GetSourceNumInstances) (THIS_ long, long*) PURE; + STDMETHOD(GetSourceInstancePos) (THIS_ long, long, LPEMPOINT) PURE; + STDMETHOD(GetEnvironmentID) (THIS_ char*, long*) PURE; + STDMETHOD(GetEnvironmentAttributes) (THIS_ long, LPEAXLISTENERPROPERTIES) PURE; + STDMETHOD(GetMaterialID) (THIS_ char*, long*) PURE; + STDMETHOD(GetMaterialAttributes) (THIS_ long, LPMATERIALATTRIBUTES) PURE; + STDMETHOD(GetGeometrySetID) (THIS_ char*, long*) PURE; + STDMETHOD(GetListenerDynamicAttributes) (THIS_ long, LPEMPOINT, long*, DWORD) PURE; + STDMETHOD(GetSourceDynamicAttributes) (THIS_ long, LPEMPOINT, long*, float*, long*, float*, float*, LPEMPOINT, DWORD) PURE; +}; + +#if !defined(__cplusplus) || defined(CINTERFACE) +#define IEaxManager_QueryInterface(p,a,b) (p)->lpVtbl->QueryInterface(p,a,b) +#define IEaxManager_AddRef(p) (p)->lpVtbl->AddRef(p) +#define IEaxManager_Release(p) (p)->lpVtbl->Release(p) +#define IEaxManager_GetDataSetSize(p,a,b) (p)->lpVtbl->GetDataSetSize(p,a,b) +#define IEaxManager_LoadDataSet(p,a,b) (p)->lpVtbl->LoadDataSet(p,a,b) +#define IEaxManager_FreeDataSet(p,a) (p)->lpVtbl->FreeDataSet(p,a) +#define IEaxManager_GetListenerAttributes(p,a) (p)->lpVtbl->GetListenerAttributes(p,a) +#define IEaxManager_GetSourceID(p,a,b) (p)->lpVtbl->GetSourceID(p,a,b) +#define IEaxManager_GetSourceAttributes(p,a,b) (p)->lpVtbl->GetSourceAttributes(p,a,b) +#define IEaxManager_GetSourceNumInstances(p,a,b) (p)->lpVtbl->GetSourceNumInstances(p,a,b) +#define IEaxManager_GetSourceInstancePos(p,a,b,c) (p)->lpVtbl->GetSourceInstancePos(p,a,b,c) +#define IEaxManager_GetEnvironmentID(p,a,b) (p)->lpVtbl->GetEnvironmentID(p,a,b) +#define IEaxManager_GetEnvironmentAttributes(p,a,b) (p)->lpVtbl->GetEnvironmentAttributes(p,a,b) +#define IEaxManager_GetMaterialID(p,a,b) (p)->lpVtbl->GetMaterialID(p,a,b) +#define IEaxManager_GetMaterialAttributes(p,a,b) (p)->lpVtbl->GetMaterialAttributes(p,a,b) +#define IEaxManager_GetGeometrySetID(p,a,b) (p)->lpVtbl->GetGeometrySetID(p,a,b) +#define IEaxManager_GetListenerDynamicAttributes(p,a,b,c,d) (p)->lpVtbl->GetListenerDynamicAttributes(p,a,b,c,d) +#define IEaxManager_GetSourceDynamicAttributes(p,a,b,c,d,e,f,g,h,i) (p)->lpVtbl->GetSourceDynamicAttributes(p,a,b,c,d,e,f,g,h,i) +#else +#define IEaxManager_QueryInterface(p,a,b) (p)->QueryInterface(a,b) +#define IEaxManager_AddRef(p) (p)->AddRef() +#define IEaxManager_Release(p) (p)->Release() +#define IEaxManager_GetDataSetSize(p,a,b) (p)->GetDataSetSize(a,b) +#define IEaxManager_LoadDataSet(p,a,b) (p)->LoadDataSet(a,b) +#define IEaxManager_FreeDataSet(p,a) (p)->FreeDataSet(a) +#define IEaxManager_GetListenerAttributes(p,a) (p)->GetListenerAttributes(a) +#define IEaxManager_GetSourceID(p,a,b) (p)->GetSourceID(a,b) +#define IEaxManager_GetSourceAttributes(p,a,b) (p)->GetSourceAttributes(a,b) +#define IEaxManager_GetSourceNumInstances(p,a,b) (p)->GetSourceNumInstances(a,b) +#define IEaxManager_GetSourceInstancePos(p,a,b,c) (p)->GetSourceInstancePos(a,b,c) +#define IEaxManager_GetEnvironmentID(p,a,b) (p)->GetEnvironmentID(a,b) +#define IEaxManager_GetEnvironmentAttributes(p,a,b) (p)->GetEnvironmentAttributes(a,b) +#define IEaxManager_GetMaterialID(p,a,b) (p)->GetMaterialID(a,b) +#define IEaxManager_GetMaterialAttributes(p,a,b) (p)->GetMaterialAttributes(a,b) +#define IEaxManager_GetGeometrySetID(p,a,b) (p)->GetGeometrySetID(a,b) +#define IEaxManager_GetListenerDynamicAttributes(p,a,b,c,d) (p)->GetListenerDynamicAttributes(a,b,c,d) +#define IEaxManager_GetSourceDynamicAttributes(p,a,b,c,d,e,f,g,h,i) (p)->GetSourceDynamicAttributes(a,b,c,d,e,f,g,h,i) +#endif + +#define EM_OK 0 +#define EM_INVALIDID MAKE_HRESULT(1, FACILITY_ITF, 1) +#define EM_IDNOTFOUND MAKE_HRESULT(1, FACILITY_ITF, 2) +#define EM_FILENOTFOUND MAKE_HRESULT(1, FACILITY_ITF, 3) +#define EM_FILEINVALID MAKE_HRESULT(1, FACILITY_ITF, 4) +#define EM_VERSIONINVALID MAKE_HRESULT(1, FACILITY_ITF, 5) +#define EM_INSTANCENOTFOUND MAKE_HRESULT(1, FACILITY_ITF, 6) + +#ifdef __cplusplus +}; +#endif // __cplusplus + +#endif diff --git a/CODE-mp/client/eax/eax.h b/CODE-mp/client/eax/eax.h new file mode 100644 index 0000000..2393c97 --- /dev/null +++ b/CODE-mp/client/eax/eax.h @@ -0,0 +1,531 @@ +/*******************************************************************\ +* * +* EAX.H - Environmental Audio Extensions version 3.0 * +* for OpenAL and DirectSound3D * +* * +********************************************************************/ + +#ifndef EAX_H_INCLUDED +#define EAX_H_INCLUDED + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +#ifndef OPENAL + #include + + /* + * EAX Wrapper Interface (using Direct X 7) {4FF53B81-1CE0-11d3-AAB8-00A0C95949D5} + */ + DEFINE_GUID(CLSID_EAXDirectSound, + 0x4ff53b81, + 0x1ce0, + 0x11d3, + 0xaa, 0xb8, 0x0, 0xa0, 0xc9, 0x59, 0x49, 0xd5); + + /* + * EAX Wrapper Interface (using Direct X 8) {CA503B60-B176-11d4-A094-D0C0BF3A560C} + */ + DEFINE_GUID(CLSID_EAXDirectSound8, + 0xca503b60, + 0xb176, + 0x11d4, + 0xa0, 0x94, 0xd0, 0xc0, 0xbf, 0x3a, 0x56, 0xc); + + + +#ifdef DIRECTSOUND_VERSION +#if DIRECTSOUND_VERSION == 0x0800 + __declspec(dllimport) HRESULT WINAPI EAXDirectSoundCreate8(GUID*, LPDIRECTSOUND8*, IUnknown FAR *); + typedef HRESULT (FAR PASCAL *LPEAXDIRECTSOUNDCREATE8)(GUID*, LPDIRECTSOUND8*, IUnknown FAR*); +#endif +#endif + + __declspec(dllimport) HRESULT WINAPI EAXDirectSoundCreate(GUID*, LPDIRECTSOUND*, IUnknown FAR *); + typedef HRESULT (FAR PASCAL *LPEAXDIRECTSOUNDCREATE)(GUID*, LPDIRECTSOUND*, IUnknown FAR*); + +#else // OPENAL + #include "../OpenAl/al.h" + + #ifndef GUID_DEFINED + #define GUID_DEFINED + typedef struct _GUID + { + unsigned long Data1; + unsigned short Data2; + unsigned short Data3; + unsigned char Data4[8]; + } GUID; + #endif // !GUID_DEFINED + + #ifndef DEFINE_GUID + #ifndef INITGUID + #define DEFINE_GUID(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \ + extern const GUID /*FAR*/ name + #else + #define DEFINE_GUID(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \ + extern const GUID name = { l, w1, w2, { b1, b2, b3, b4, b5, b6, b7, b8 } } + #endif // INITGUID + #endif // DEFINE_GUID + + + /* + * EAX OpenAL Extension + */ + typedef ALenum (*EAXSet)(const GUID*, ALuint, ALuint, ALvoid*, ALuint); + typedef ALenum (*EAXGet)(const GUID*, ALuint, ALuint, ALvoid*, ALuint); +#endif + +#pragma pack(push, 4) + +/* + * EAX 3.0 listener property set {A8FA6880-B476-11d3-BDB9-00C0F02DDF87} + */ +DEFINE_GUID(DSPROPSETID_EAX30_ListenerProperties, + 0xa8fa6882, + 0xb476, + 0x11d3, + 0xbd, 0xb9, 0x00, 0xc0, 0xf0, 0x2d, 0xdf, 0x87); + +// For compatibility with future EAX versions: +#define DSPROPSETID_EAX_ListenerProperties DSPROPSETID_EAX30_ListenerProperties + +typedef enum +{ + DSPROPERTY_EAXLISTENER_NONE, + DSPROPERTY_EAXLISTENER_ALLPARAMETERS, + DSPROPERTY_EAXLISTENER_ENVIRONMENT, + DSPROPERTY_EAXLISTENER_ENVIRONMENTSIZE, + DSPROPERTY_EAXLISTENER_ENVIRONMENTDIFFUSION, + DSPROPERTY_EAXLISTENER_ROOM, + DSPROPERTY_EAXLISTENER_ROOMHF, + DSPROPERTY_EAXLISTENER_ROOMLF, + DSPROPERTY_EAXLISTENER_DECAYTIME, + DSPROPERTY_EAXLISTENER_DECAYHFRATIO, + DSPROPERTY_EAXLISTENER_DECAYLFRATIO, + DSPROPERTY_EAXLISTENER_REFLECTIONS, + DSPROPERTY_EAXLISTENER_REFLECTIONSDELAY, + DSPROPERTY_EAXLISTENER_REFLECTIONSPAN, + DSPROPERTY_EAXLISTENER_REVERB, + DSPROPERTY_EAXLISTENER_REVERBDELAY, + DSPROPERTY_EAXLISTENER_REVERBPAN, + DSPROPERTY_EAXLISTENER_ECHOTIME, + DSPROPERTY_EAXLISTENER_ECHODEPTH, + DSPROPERTY_EAXLISTENER_MODULATIONTIME, + DSPROPERTY_EAXLISTENER_MODULATIONDEPTH, + DSPROPERTY_EAXLISTENER_AIRABSORPTIONHF, + DSPROPERTY_EAXLISTENER_HFREFERENCE, + DSPROPERTY_EAXLISTENER_LFREFERENCE, + DSPROPERTY_EAXLISTENER_ROOMROLLOFFFACTOR, + DSPROPERTY_EAXLISTENER_FLAGS +} DSPROPERTY_EAX_LISTENERPROPERTY; + +// OR these flags with property id +#define DSPROPERTY_EAXLISTENER_IMMEDIATE 0x00000000 // changes take effect immediately +#define DSPROPERTY_EAXLISTENER_DEFERRED 0x80000000 // changes take effect later +#define DSPROPERTY_EAXLISTENER_COMMITDEFERREDSETTINGS (DSPROPERTY_EAXLISTENER_NONE | \ + DSPROPERTY_EAXLISTENER_IMMEDIATE) + +typedef struct _EAXVECTOR { + float x; + float y; + float z; +} EAXVECTOR; + +// Use this structure for DSPROPERTY_EAXLISTENER_ALLPARAMETERS +// - all levels are hundredths of decibels +// - all times and delays are in seconds +// +// NOTE: This structure may change in future EAX versions. +// It is recommended to initialize fields by name: +// myListener.lRoom = -1000; +// myListener.lRoomHF = -100; +// ... +// myListener.dwFlags = myFlags /* see EAXLISTENERFLAGS below */ ; +// instead of: +// myListener = { -1000, -100, ... , 0x00000009 }; +// If you want to save and load presets in binary form, you +// should define your own structure to insure future compatibility. +// +typedef struct _EAXLISTENERPROPERTIES +{ + unsigned long ulEnvironment; // sets all listener properties + float flEnvironmentSize; // environment size in meters + float flEnvironmentDiffusion; // environment diffusion + long lRoom; // room effect level (at mid frequencies) + long lRoomHF; // relative room effect level at high frequencies + long lRoomLF; // relative room effect level at low frequencies + float flDecayTime; // reverberation decay time at mid frequencies + float flDecayHFRatio; // high-frequency to mid-frequency decay time ratio + float flDecayLFRatio; // low-frequency to mid-frequency decay time ratio + long lReflections; // early reflections level relative to room effect + float flReflectionsDelay; // initial reflection delay time + EAXVECTOR vReflectionsPan; // early reflections panning vector + long lReverb; // late reverberation level relative to room effect + float flReverbDelay; // late reverberation delay time relative to initial reflection + EAXVECTOR vReverbPan; // late reverberation panning vector + float flEchoTime; // echo time + float flEchoDepth; // echo depth + float flModulationTime; // modulation time + float flModulationDepth; // modulation depth + float flAirAbsorptionHF; // change in level per meter at high frequencies + float flHFReference; // reference high frequency + float flLFReference; // reference low frequency + float flRoomRolloffFactor; // like DS3D flRolloffFactor but for room effect + unsigned long ulFlags; // modifies the behavior of properties +} EAXLISTENERPROPERTIES, *LPEAXLISTENERPROPERTIES; + +// used by DSPROPERTY_EAXLISTENER_ENVIRONMENT +enum +{ + EAX_ENVIRONMENT_GENERIC, + EAX_ENVIRONMENT_PADDEDCELL, + EAX_ENVIRONMENT_ROOM, + EAX_ENVIRONMENT_BATHROOM, + EAX_ENVIRONMENT_LIVINGROOM, + EAX_ENVIRONMENT_STONEROOM, + EAX_ENVIRONMENT_AUDITORIUM, + EAX_ENVIRONMENT_CONCERTHALL, + EAX_ENVIRONMENT_CAVE, + EAX_ENVIRONMENT_ARENA, + EAX_ENVIRONMENT_HANGAR, + EAX_ENVIRONMENT_CARPETEDHALLWAY, + EAX_ENVIRONMENT_HALLWAY, + EAX_ENVIRONMENT_STONECORRIDOR, + EAX_ENVIRONMENT_ALLEY, + EAX_ENVIRONMENT_FOREST, + EAX_ENVIRONMENT_CITY, + EAX_ENVIRONMENT_MOUNTAINS, + EAX_ENVIRONMENT_QUARRY, + EAX_ENVIRONMENT_PLAIN, + EAX_ENVIRONMENT_PARKINGLOT, + EAX_ENVIRONMENT_SEWERPIPE, + EAX_ENVIRONMENT_UNDERWATER, + EAX_ENVIRONMENT_DRUGGED, + EAX_ENVIRONMENT_DIZZY, + EAX_ENVIRONMENT_PSYCHOTIC, + + EAX_ENVIRONMENT_UNDEFINED, + + EAX_ENVIRONMENT_COUNT +}; + +// Used by DSPROPERTY_EAXLISTENER_FLAGS +// +// Note: The number and order of flags may change in future EAX versions. +// It is recommended to use the flag defines as follows: +// myFlags = EAXLISTENERFLAGS_DECAYTIMESCALE | EAXLISTENERFLAGS_REVERBSCALE; +// instead of: +// myFlags = 0x00000009; +// +// These flags determine what properties are affected by environment size. +#define EAXLISTENERFLAGS_DECAYTIMESCALE 0x00000001 // reverberation decay time +#define EAXLISTENERFLAGS_REFLECTIONSSCALE 0x00000002 // reflection level +#define EAXLISTENERFLAGS_REFLECTIONSDELAYSCALE 0x00000004 // initial reflection delay time +#define EAXLISTENERFLAGS_REVERBSCALE 0x00000008 // reflections level +#define EAXLISTENERFLAGS_REVERBDELAYSCALE 0x00000010 // late reverberation delay time +#define EAXLISTENERFLAGS_ECHOTIMESCALE 0x00000040 // echo time +#define EAXLISTENERFLAGS_MODULATIONTIMESCALE 0x00000080 // modulation time + +// This flag limits high-frequency decay time according to air absorption. +#define EAXLISTENERFLAGS_DECAYHFLIMIT 0x00000020 + +#define EAXLISTENERFLAGS_RESERVED 0xFFFFFF00 // reserved future use + +// Property ranges and defaults: + +#define EAXLISTENER_MINENVIRONMENT 0 +#define EAXLISTENER_MAXENVIRONMENT (EAX_ENVIRONMENT_COUNT-1) +#define EAXLISTENER_DEFAULTENVIRONMENT EAX_ENVIRONMENT_GENERIC + +#define EAXLISTENER_MINENVIRONMENTSIZE 1.0f +#define EAXLISTENER_MAXENVIRONMENTSIZE 100.0f +#define EAXLISTENER_DEFAULTENVIRONMENTSIZE 7.5f + +#define EAXLISTENER_MINENVIRONMENTDIFFUSION 0.0f +#define EAXLISTENER_MAXENVIRONMENTDIFFUSION 1.0f +#define EAXLISTENER_DEFAULTENVIRONMENTDIFFUSION 1.0f + +#define EAXLISTENER_MINROOM (-10000) +#define EAXLISTENER_MAXROOM 0 +#define EAXLISTENER_DEFAULTROOM (-1000) + +#define EAXLISTENER_MINROOMHF (-10000) +#define EAXLISTENER_MAXROOMHF 0 +#define EAXLISTENER_DEFAULTROOMHF (-100) + +#define EAXLISTENER_MINROOMLF (-10000) +#define EAXLISTENER_MAXROOMLF 0 +#define EAXLISTENER_DEFAULTROOMLF 0 + +#define EAXLISTENER_MINDECAYTIME 0.1f +#define EAXLISTENER_MAXDECAYTIME 20.0f +#define EAXLISTENER_DEFAULTDECAYTIME 1.49f + +#define EAXLISTENER_MINDECAYHFRATIO 0.1f +#define EAXLISTENER_MAXDECAYHFRATIO 2.0f +#define EAXLISTENER_DEFAULTDECAYHFRATIO 0.83f + +#define EAXLISTENER_MINDECAYLFRATIO 0.1f +#define EAXLISTENER_MAXDECAYLFRATIO 2.0f +#define EAXLISTENER_DEFAULTDECAYLFRATIO 1.00f + +#define EAXLISTENER_MINREFLECTIONS (-10000) +#define EAXLISTENER_MAXREFLECTIONS 1000 +#define EAXLISTENER_DEFAULTREFLECTIONS (-2602) + +#define EAXLISTENER_MINREFLECTIONSDELAY 0.0f +#define EAXLISTENER_MAXREFLECTIONSDELAY 0.3f +#define EAXLISTENER_DEFAULTREFLECTIONSDELAY 0.007f + +#define EAXLISTENER_MINREVERB (-10000) +#define EAXLISTENER_MAXREVERB 2000 +#define EAXLISTENER_DEFAULTREVERB 200 + +#define EAXLISTENER_MINREVERBDELAY 0.0f +#define EAXLISTENER_MAXREVERBDELAY 0.1f +#define EAXLISTENER_DEFAULTREVERBDELAY 0.011f + +#define EAXLISTENER_MINECHOTIME 0.075f +#define EAXLISTENER_MAXECHOTIME 0.25f +#define EAXLISTENER_DEFAULTECHOTIME 0.25f + +#define EAXLISTENER_MINECHODEPTH 0.0f +#define EAXLISTENER_MAXECHODEPTH 1.0f +#define EAXLISTENER_DEFAULTECHODEPTH 0.0f + +#define EAXLISTENER_MINMODULATIONTIME 0.04f +#define EAXLISTENER_MAXMODULATIONTIME 4.0f +#define EAXLISTENER_DEFAULTMODULATIONTIME 0.25f + +#define EAXLISTENER_MINMODULATIONDEPTH 0.0f +#define EAXLISTENER_MAXMODULATIONDEPTH 1.0f +#define EAXLISTENER_DEFAULTMODULATIONDEPTH 0.0f + +#define EAXLISTENER_MINAIRABSORPTIONHF (-100.0f) +#define EAXLISTENER_MAXAIRABSORPTIONHF 0.0f +#define EAXLISTENER_DEFAULTAIRABSORPTIONHF (-5.0f) + +#define EAXLISTENER_MINHFREFERENCE 1000.0f +#define EAXLISTENER_MAXHFREFERENCE 20000.0f +#define EAXLISTENER_DEFAULTHFREFERENCE 5000.0f + +#define EAXLISTENER_MINLFREFERENCE 20.0f +#define EAXLISTENER_MAXLFREFERENCE 1000.0f +#define EAXLISTENER_DEFAULTLFREFERENCE 250.0f + +#define EAXLISTENER_MINROOMROLLOFFFACTOR 0.0f +#define EAXLISTENER_MAXROOMROLLOFFFACTOR 10.0f +#define EAXLISTENER_DEFAULTROOMROLLOFFFACTOR 0.0f + +#define EAXLISTENER_DEFAULTFLAGS (EAXLISTENERFLAGS_DECAYTIMESCALE | \ + EAXLISTENERFLAGS_REFLECTIONSSCALE | \ + EAXLISTENERFLAGS_REFLECTIONSDELAYSCALE | \ + EAXLISTENERFLAGS_REVERBSCALE | \ + EAXLISTENERFLAGS_REVERBDELAYSCALE | \ + EAXLISTENERFLAGS_DECAYHFLIMIT) + + + +/* +* EAX 3.0 buffer property set {A8FA6881-B476-11d3-BDB9-00C0F02DDF87} +*/ +DEFINE_GUID(DSPROPSETID_EAX30_BufferProperties, + 0xa8fa6881, + 0xb476, + 0x11d3, + 0xbd, 0xb9, 0x0, 0xc0, 0xf0, 0x2d, 0xdf, 0x87); + +// For compatibility with future EAX versions: +#define DSPROPSETID_EAX_BufferProperties DSPROPSETID_EAX30_BufferProperties +#define DSPROPSETID_EAX_SourceProperties DSPROPSETID_EAX30_BufferProperties + +typedef enum +{ + DSPROPERTY_EAXBUFFER_NONE, + DSPROPERTY_EAXBUFFER_ALLPARAMETERS, + DSPROPERTY_EAXBUFFER_OBSTRUCTIONPARAMETERS, + DSPROPERTY_EAXBUFFER_OCCLUSIONPARAMETERS, + DSPROPERTY_EAXBUFFER_EXCLUSIONPARAMETERS, + DSPROPERTY_EAXBUFFER_DIRECT, + DSPROPERTY_EAXBUFFER_DIRECTHF, + DSPROPERTY_EAXBUFFER_ROOM, + DSPROPERTY_EAXBUFFER_ROOMHF, + DSPROPERTY_EAXBUFFER_OBSTRUCTION, + DSPROPERTY_EAXBUFFER_OBSTRUCTIONLFRATIO, + DSPROPERTY_EAXBUFFER_OCCLUSION, + DSPROPERTY_EAXBUFFER_OCCLUSIONLFRATIO, + DSPROPERTY_EAXBUFFER_OCCLUSIONROOMRATIO, + DSPROPERTY_EAXBUFFER_OCCLUSIONDIRECTRATIO, + DSPROPERTY_EAXBUFFER_EXCLUSION, + DSPROPERTY_EAXBUFFER_EXCLUSIONLFRATIO, + DSPROPERTY_EAXBUFFER_OUTSIDEVOLUMEHF, + DSPROPERTY_EAXBUFFER_DOPPLERFACTOR, + DSPROPERTY_EAXBUFFER_ROLLOFFFACTOR, + DSPROPERTY_EAXBUFFER_ROOMROLLOFFFACTOR, + DSPROPERTY_EAXBUFFER_AIRABSORPTIONFACTOR, + DSPROPERTY_EAXBUFFER_FLAGS +} DSPROPERTY_EAX_BUFFERPROPERTY; + +// OR these flags with property id +#define DSPROPERTY_EAXBUFFER_IMMEDIATE 0x00000000 // changes take effect immediately +#define DSPROPERTY_EAXBUFFER_DEFERRED 0x80000000 // changes take effect later +#define DSPROPERTY_EAXBUFFER_COMMITDEFERREDSETTINGS (DSPROPERTY_EAXBUFFER_NONE | \ + DSPROPERTY_EAXBUFFER_IMMEDIATE) + +// Use this structure for DSPROPERTY_EAXBUFFER_ALLPARAMETERS +// - all levels are hundredths of decibels +// - all delays are in seconds +// +// NOTE: This structure may change in future EAX versions. +// It is recommended to initialize fields by name: +// myBuffer.lDirect = 0; +// myBuffer.lDirectHF = -200; +// ... +// myBuffer.dwFlags = myFlags /* see EAXBUFFERFLAGS below */ ; +// instead of: +// myBuffer = { 0, -200, ... , 0x00000003 }; +// +typedef struct _EAXBUFFERPROPERTIES +{ + long lDirect; // direct path level (at low and mid frequencies) + long lDirectHF; // relative direct path level at high frequencies + long lRoom; // room effect level (at low and mid frequencies) + long lRoomHF; // relative room effect level at high frequencies + long lObstruction; // main obstruction control (attenuation at high frequencies) + float flObstructionLFRatio; // obstruction low-frequency level re. main control + long lOcclusion; // main occlusion control (attenuation at high frequencies) + float flOcclusionLFRatio; // occlusion low-frequency level re. main control + float flOcclusionRoomRatio; // relative occlusion control for room effect + float flOcclusionDirectRatio; // relative occlusion control for direct path + long lExclusion; // main exlusion control (attenuation at high frequencies) + float flExclusionLFRatio; // exclusion low-frequency level re. main control + long lOutsideVolumeHF; // outside sound cone level at high frequencies + float flDopplerFactor; // like DS3D flDopplerFactor but per source + float flRolloffFactor; // like DS3D flRolloffFactor but per source + float flRoomRolloffFactor; // like DS3D flRolloffFactor but for room effect + float flAirAbsorptionFactor; // multiplies DSPROPERTY_EAXLISTENER_AIRABSORPTIONHF + unsigned long ulFlags; // modifies the behavior of properties +} EAXBUFFERPROPERTIES, *LPEAXBUFFERPROPERTIES; + +// Use this structure for DSPROPERTY_EAXBUFFER_OBSTRUCTION, +typedef struct _EAXOBSTRUCTIONPROPERTIES +{ + long lObstruction; + float flObstructionLFRatio; +} EAXOBSTRUCTIONPROPERTIES, *LPEAXOBSTRUCTIONPROPERTIES; + +// Use this structure for DSPROPERTY_EAXBUFFER_OCCLUSION +typedef struct _EAXOCCLUSIONPROPERTIES +{ + long lOcclusion; + float flOcclusionLFRatio; + float flOcclusionRoomRatio; + float flOcclusionDirectRatio; +} EAXOCCLUSIONPROPERTIES, *LPEAXOCCLUSIONPROPERTIES; + +// Use this structure for DSPROPERTY_EAXBUFFER_EXCLUSION +typedef struct _EAXEXCLUSIONPROPERTIES +{ + long lExclusion; + float flExclusionLFRatio; +} EAXEXCLUSIONPROPERTIES, *LPEAXEXCLUSIONPROPERTIES; + +// Used by DSPROPERTY_EAXBUFFER_FLAGS +// TRUE: value is computed automatically - property is an offset +// FALSE: value is used directly +// +// Note: The number and order of flags may change in future EAX versions. +// To insure future compatibility, use flag defines as follows: +// myFlags = EAXBUFFERFLAGS_DIRECTHFAUTO | EAXBUFFERFLAGS_ROOMAUTO; +// instead of: +// myFlags = 0x00000003; +// +#define EAXBUFFERFLAGS_DIRECTHFAUTO 0x00000001 // affects DSPROPERTY_EAXBUFFER_DIRECTHF +#define EAXBUFFERFLAGS_ROOMAUTO 0x00000002 // affects DSPROPERTY_EAXBUFFER_ROOM +#define EAXBUFFERFLAGS_ROOMHFAUTO 0x00000004 // affects DSPROPERTY_EAXBUFFER_ROOMHF + +#define EAXBUFFERFLAGS_RESERVED 0xFFFFFFF8 // reserved future use + +// Property ranges and defaults: + +#define EAXBUFFER_MINDIRECT (-10000) +#define EAXBUFFER_MAXDIRECT 1000 +#define EAXBUFFER_DEFAULTDIRECT 0 + +#define EAXBUFFER_MINDIRECTHF (-10000) +#define EAXBUFFER_MAXDIRECTHF 0 +#define EAXBUFFER_DEFAULTDIRECTHF 0 + +#define EAXBUFFER_MINROOM (-10000) +#define EAXBUFFER_MAXROOM 1000 +#define EAXBUFFER_DEFAULTROOM 0 + +#define EAXBUFFER_MINROOMHF (-10000) +#define EAXBUFFER_MAXROOMHF 0 +#define EAXBUFFER_DEFAULTROOMHF 0 + +#define EAXBUFFER_MINOBSTRUCTION (-10000) +#define EAXBUFFER_MAXOBSTRUCTION 0 +#define EAXBUFFER_DEFAULTOBSTRUCTION 0 + +#define EAXBUFFER_MINOBSTRUCTIONLFRATIO 0.0f +#define EAXBUFFER_MAXOBSTRUCTIONLFRATIO 1.0f +#define EAXBUFFER_DEFAULTOBSTRUCTIONLFRATIO 0.0f + +#define EAXBUFFER_MINOCCLUSION (-10000) +#define EAXBUFFER_MAXOCCLUSION 0 +#define EAXBUFFER_DEFAULTOCCLUSION 0 + +#define EAXBUFFER_MINOCCLUSIONLFRATIO 0.0f +#define EAXBUFFER_MAXOCCLUSIONLFRATIO 1.0f +#define EAXBUFFER_DEFAULTOCCLUSIONLFRATIO 0.25f + +#define EAXBUFFER_MINOCCLUSIONROOMRATIO 0.0f +#define EAXBUFFER_MAXOCCLUSIONROOMRATIO 10.0f +#define EAXBUFFER_DEFAULTOCCLUSIONROOMRATIO 1.5f + +#define EAXBUFFER_MINOCCLUSIONDIRECTRATIO 0.0f +#define EAXBUFFER_MAXOCCLUSIONDIRECTRATIO 10.0f +#define EAXBUFFER_DEFAULTOCCLUSIONDIRECTRATIO 1.0f + +#define EAXBUFFER_MINEXCLUSION (-10000) +#define EAXBUFFER_MAXEXCLUSION 0 +#define EAXBUFFER_DEFAULTEXCLUSION 0 + +#define EAXBUFFER_MINEXCLUSIONLFRATIO 0.0f +#define EAXBUFFER_MAXEXCLUSIONLFRATIO 1.0f +#define EAXBUFFER_DEFAULTEXCLUSIONLFRATIO 1.0f + +#define EAXBUFFER_MINOUTSIDEVOLUMEHF (-10000) +#define EAXBUFFER_MAXOUTSIDEVOLUMEHF 0 +#define EAXBUFFER_DEFAULTOUTSIDEVOLUMEHF 0 + +#define EAXBUFFER_MINDOPPLERFACTOR 0.0f +#define EAXBUFFER_MAXDOPPLERFACTOR 10.f +#define EAXBUFFER_DEFAULTDOPPLERFACTOR 0.0f + +#define EAXBUFFER_MINROLLOFFFACTOR 0.0f +#define EAXBUFFER_MAXROLLOFFFACTOR 10.f +#define EAXBUFFER_DEFAULTROLLOFFFACTOR 0.0f + +#define EAXBUFFER_MINROOMROLLOFFFACTOR 0.0f +#define EAXBUFFER_MAXROOMROLLOFFFACTOR 10.f +#define EAXBUFFER_DEFAULTROOMROLLOFFFACTOR 0.0f + +#define EAXBUFFER_MINAIRABSORPTIONFACTOR 0.0f +#define EAXBUFFER_MAXAIRABSORPTIONFACTOR 10.0f +#define EAXBUFFER_DEFAULTAIRABSORPTIONFACTOR 1.0f + +#define EAXBUFFER_DEFAULTFLAGS (EAXBUFFERFLAGS_DIRECTHFAUTO | \ + EAXBUFFERFLAGS_ROOMAUTO | \ + EAXBUFFERFLAGS_ROOMHFAUTO ) + +#pragma pack(pop) + +#ifdef __cplusplus +} +#endif // __cplusplus + +#endif diff --git a/CODE-mp/client/eax/vssver.scc b/CODE-mp/client/eax/vssver.scc new file mode 100644 index 0000000..e45637b Binary files /dev/null and b/CODE-mp/client/eax/vssver.scc differ diff --git a/CODE-mp/client/keys.h b/CODE-mp/client/keys.h index 646d6fc..de965c4 100644 --- a/CODE-mp/client/keys.h +++ b/CODE-mp/client/keys.h @@ -1,17 +1,14 @@ #include "../ui/keycodes.h" -#define MAX_KEYS 256 - typedef struct { qboolean down; int repeats; // if > 1, it is autorepeating char *binding; } qkey_t; -extern qboolean key_overstrikeMode; -extern qkey_t keys[MAX_KEYS]; +#define MAX_EDIT_LINE 256 +#define COMMAND_HISTORY 32 -#define MAX_EDIT_LINE 256 typedef struct { int cursor; int scroll; @@ -19,18 +16,43 @@ typedef struct { char buffer[MAX_EDIT_LINE]; } field_t; +typedef struct keyGlobals_s +{ + field_t historyEditLines[COMMAND_HISTORY]; + + int nextHistoryLine; // the last line in the history buffer, not masked + int historyLine; // the line being displayed from history buffer + // will be <= nextHistoryLine + field_t g_consoleField; + + qboolean anykeydown; + qboolean key_overstrikeMode; + int keyDownCount; + + qkey_t keys[MAX_KEYS]; +} keyGlobals_t; + + +typedef struct +{ + word upper; + word lower; + char *name; + int keynum; + bool menukey; +} keyname_t; + +extern keyGlobals_t kg; +extern keyname_t keynames[MAX_KEYS]; + + void Field_Clear( field_t *edit ); void Field_KeyDownEvent( field_t *edit, int key ); void Field_CharEvent( field_t *edit, int ch ); void Field_Draw( field_t *edit, int x, int y, int width, qboolean showCursor ); void Field_BigDraw( field_t *edit, int x, int y, int width, qboolean showCursor ); -#define COMMAND_HISTORY 32 -extern field_t historyEditLines[COMMAND_HISTORY]; - -extern field_t g_consoleField; extern field_t chatField; -extern qboolean anykeydown; extern qboolean chat_team; extern int chat_playerNum; diff --git a/CODE-mp/client/snd_dma.cpp b/CODE-mp/client/snd_dma.cpp index 89aad1a..a79c12b 100644 --- a/CODE-mp/client/snd_dma.cpp +++ b/CODE-mp/client/snd_dma.cpp @@ -149,6 +149,68 @@ int s_rawend; portable_samplepair_t s_rawsamples[MAX_RAW_SAMPLES]; +/**************************************************************************************************\ +* +* Open AL Specific +* +\**************************************************************************************************/ + +int s_UseOpenAL = false; // Determines if using Open AL or the default software mixer +ALfloat listener_pos[3]; // Listener Position +ALfloat listener_ori[6]; // Listener Orientation +int s_numChannels; // Number of AL Sources == Num of Channels +short s_rawdata[MAX_RAW_SAMPLES*4]; // Used for Raw Samples (Music etc...) + +channel_t *S_OpenALPickChannel(int entnum, int entchannel); +void UpdateSingleShotSounds(); +void UpdateLoopingSounds(); +void UpdateRawSamples(); + +// EAX Related +ALboolean s_bEAX; // Is EAX 3.0 support is available +bool s_bEALFileLoaded; // Has an .eal file been loaded for the current level +bool s_bInWater; // Underwater effect currently active +int s_EnvironmentID; // EAGLE ID of current environment +LPEAXMANAGER s_lpEAXManager; // Pointer to EAXManager object +HINSTANCE s_hEAXManInst; // Handle of EAXManager DLL +EAXSet s_eaxSet; // EAXSet() function +EAXGet s_eaxGet; // EAXGet() function +bool s_eaxMorphing; // Is EAX Morphing in progress +int s_eaxMorphStartTime;// EAX Morph start time +int s_eaxMorphCount; // EAX Morph count (1 ... 10) +EAXLISTENERPROPERTIES s_eaxLPSource; // Source EAX Parameters +EAXLISTENERPROPERTIES s_eaxLPCur; // Current EAX Parameters +EAXLISTENERPROPERTIES s_eaxLPDest; // Destination EAX Parameters +char s_LevelName[MAX_QPATH]; // Name of current level + +void InitEAXManager(); +void ReleaseEAXManager(); +bool LoadEALFile(char *szEALFilename); +void UnloadEALFile(); +void UpdateEAXListener(bool bUseDefault, bool bUseMorphing); +void UpdateEAXBuffer(channel_t *ch); +void EALFileInit(char *level); +void EAXMorph(); +bool EAX3ListenerInterpolate(EAXLISTENERPROPERTIES *lpStartEAX3LP, EAXLISTENERPROPERTIES *lpFinishEAX3LP, + float flRatio, EAXLISTENERPROPERTIES *lpResultEAX3LP, bool bCheckValues = false); +void Clamp(EAXVECTOR *eaxVector); +bool CheckEAX3LP(LPEAXLISTENERPROPERTIES lpEAX3LP); + +// EAX 3.0 GUIDS ... confidential information ... + +const GUID DSPROPSETID_EAX30_ListenerProperties + = { 0xa8fa6882, 0xb476, 0x11d3, { 0xbd, 0xb9, 0x00, 0xc0, 0xf0, 0x2d, 0xdf, 0x87} }; + +const GUID DSPROPSETID_EAX30_BufferProperties + = { 0xa8fa6881, 0xb476, 0x11d3, { 0xbd, 0xb9, 0x0, 0xc0, 0xf0, 0x2d, 0xdf, 0x87} }; + +/**************************************************************************************************\ +* +* End of Open AL Specific +* +\**************************************************************************************************/ + + // instead of clearing a whole channel_t struct, we're going to skip the MP3SlidingDecodeBuffer[] buffer in the middle... // @@ -205,9 +267,17 @@ void S_SoundInfo_f(void) { S_Init ================ */ -void S_Init( void ) { +void S_Init( void ) +{ + ALCcontext *ALCContext = NULL; + ALCdevice *ALCDevice = NULL; + ALfloat listenerPos[]={0.0,0.0,0.0}; + ALfloat listenerVel[]={0.0,0.0,0.0}; + ALfloat listenerOri[]={0.0,0.0,-1.0, 0.0,1.0,0.0}; cvar_t *cv; qboolean r; + int i,j; + channel_t *ch; Com_Printf("\n------- sound initialization -------\n"); @@ -256,10 +326,108 @@ void S_Init( void ) { Cmd_AddCommand("soundinfo", S_SoundInfo_f); Cmd_AddCommand("soundstop", S_StopAllSounds); - r = SNDDMA_Init(); - Com_Printf("------------------------------------\n"); - if ( r ) { + cv = Cvar_Get("s_UseOpenAL" , "0",CVAR_ARCHIVE|CVAR_LATCH); + s_UseOpenAL = !!(cv->integer); + + if (s_UseOpenAL) + { + ALCDevice = alcOpenDevice((ALubyte*)"DirectSound3D"); + if (!ALCDevice) + return; + + //Create context(s) + ALCContext = alcCreateContext(ALCDevice, NULL); + if (!ALCContext) + return; + + //Set active context + alcMakeContextCurrent(ALCContext); + if (alcGetError(ALCDevice) != ALC_NO_ERROR) + return; + + s_soundStarted = 1; + s_soundMuted = qtrue; + s_soundtime = 0; + s_paintedtime = 0; + s_rawend = 0; + + S_StopAllSounds(); + + S_SoundInfo_f(); + + // Set default level name + memset(s_LevelName, 0, sizeof(s_LevelName)); + + // Set Listener attributes + alListenerfv(AL_POSITION,listenerPos); + alListenerfv(AL_VELOCITY,listenerVel); + alListenerfv(AL_ORIENTATION,listenerOri); + + InitEAXManager(); + + memset(s_channels, 0, sizeof(s_channels)); + + s_numChannels = 0; + + // Create as many AL Sources (up to 32) as possible + for (i = 0; i < 32; i++) + { + alGenSources(1, &s_channels[i].alSource); + if (alGetError() != AL_NO_ERROR) + { + // Reached limit of sources + break; + } + alSourcef(s_channels[i].alSource, AL_REFERENCE_DISTANCE, 400.0f); + if (alGetError() != AL_NO_ERROR) + { + break; + } + s_numChannels++; + } + + // Generate AL Buffers for streaming audio playback (used for MP3s) + ch = s_channels + 1; + for (i = 1; i < s_numChannels; i++, ch++) + { + for (j = 0; j < NUM_STREAMING_BUFFERS; j++) + { + alGenBuffers(1, &(ch->buffers[j].BufferID)); + ch->buffers[j].Status = UNQUEUED; + ch->buffers[j].Data = (char *)Z_Malloc(STREAMING_BUFFER_SIZE, TAG_SND_RAWDATA, qfalse); + } + } + + // Open AL will always use 22K + dma.speed = 22050; + + // These aren't really relevant for Open AL, but for completeness ... + dma.channels = 2; + dma.samplebits = 16; + dma.samples = 0; + dma.submission_chunk = 0; + dma.buffer = NULL; + + // Clamp sound volumes between 0.0f and 1.0f + if (s_volume->value < 0.f) + s_volume->value = 0.f; + if (s_volume->value > 1.f) + s_volume->value = 1.f; + + if (s_musicVolume->value < 0.f) + s_musicVolume->value = 0.f; + if (s_musicVolume->value > 1.f) + s_musicVolume->value = 1.f; + + return; + } + else + { + r = SNDDMA_Init(); + Com_Printf("------------------------------------\n"); + + if ( r ) { s_soundStarted = 1; s_soundMuted = (qboolean)1; // s_numSfx = 0; @@ -270,19 +438,48 @@ void S_Init( void ) { S_StopAllSounds (); S_SoundInfo_f(); + } } +} + +/* + Mutes / Unmutes all sound +*/ +void S_MuteAllSounds(bool bMute) +{ + if (!s_soundStarted) + return; + if (!s_UseOpenAL) + return; + + if (bMute) + { + alListenerf(AL_GAIN, 0.0f); + } + else + { + alListenerf(AL_GAIN, 1.0f); + } } +void S_ChannelFree(channel_t *v) +{ + if (s_UseOpenAL) + return; -void S_ChannelFree(channel_t *v) { v->thesfx = NULL; *(channel_t **)v = freelist; freelist = (channel_t*)v; } -channel_t* S_ChannelMalloc() { +channel_t* S_ChannelMalloc() +{ channel_t *v; + + if (s_UseOpenAL) + return NULL; + if (freelist == NULL) { return NULL; } @@ -292,9 +489,13 @@ channel_t* S_ChannelMalloc() { return v; } -void S_ChannelSetup() { +void S_ChannelSetup() +{ channel_t *p, *q; + if (s_UseOpenAL) + return; + // clear all the sounds so they don't Com_Memset( s_channels, 0, sizeof( s_channels ) ); @@ -313,12 +514,62 @@ void S_ChannelSetup() { // Shutdown sound engine // ======================================================================= -void S_Shutdown( void ) { +void S_Shutdown( void ) +{ + ALCcontext *ALCContext; + ALCdevice *ALCDevice; + channel_t *ch; + int i,j; + if ( !s_soundStarted ) { return; } - SNDDMA_Shutdown(); + if (s_UseOpenAL) + { + // Release all the AL Sources (including Music channel (Source 0)) + for (i = 0; i < s_numChannels; i++) + { + alDeleteSources(1, &(s_channels[i].alSource)); + } + + // Release all the AL Buffers here or not ? + S_FreeAllSFXMem(); + + // Release Streaming AL Buffers + ch = s_channels + 1; + for (i = 1; i < s_numChannels; i++, ch++) + { + for (j = 0; j < NUM_STREAMING_BUFFERS; j++) + { + alDeleteBuffers(1, &(ch->buffers[j].BufferID)); + ch->buffers[j].BufferID = 0; + ch->buffers[j].Status = UNQUEUED; + if (ch->buffers[j].Data) + { + Z_Free(ch->buffers[j].Data); + ch->buffers[j].Data = NULL; + } + } + } + + // Get active context + ALCContext = alcGetCurrentContext(); + // Get device for active context + ALCDevice = alcGetContextsDevice(ALCContext); + // Release context(s) + alcDestroyContext(ALCContext); + // Close device + alcCloseDevice(ALCDevice); + + ReleaseEAXManager(); + + s_numChannels = 0; + } + else + { + SNDDMA_Shutdown(); + } s_soundStarted = 0; @@ -500,6 +751,52 @@ void S_BeginRegistration( void ) } } +void EALFileInit(char *level) +{ + long lRoom; + char name[MAX_QPATH]; + char szEALFilename[MAX_QPATH]; + char *szMapName; + + // If an EAL File is already unloaded, remove it + if (s_bEALFileLoaded) + { + UnloadEALFile(); + } + + // Reset variables + s_bInWater = false; + + // Try and load an EAL file for the new level + COM_StripExtension(level, name); + + // Find the last occurence of the '/' character + szMapName = Q_strrchr(name, '/'); + if (szMapName) + { + Com_sprintf(szEALFilename, MAX_QPATH, "eagle/%s.eal", ++szMapName); + } + else + { + Com_sprintf(szEALFilename, MAX_QPATH, "eagle/%s.eal", name); + } + + s_bEALFileLoaded = LoadEALFile(szEALFilename); + + if (s_bEALFileLoaded) + { + UpdateEAXListener(true, false); + } + else + { + if ((s_bEAX)&&(s_eaxSet)) + { + lRoom = -10000; + s_eaxSet(&DSPROPSETID_EAX_ListenerProperties, DSPROPERTY_EAXLISTENER_ROOM, + NULL, &lRoom, sizeof(long)); + } + } +} /* ================== @@ -537,8 +834,17 @@ sfxHandle_t S_RegisterSound( const char *name) if ( sfx->bDefaultSound ) return 0; - if ( sfx->pSoundData ) { - return sfx - s_knownSfx; + if (s_UseOpenAL) + { + if ((sfx->pSoundData) || (sfx->Buffer)) + return sfx - s_knownSfx; + } + else + { + if ( sfx->pSoundData ) + { + return sfx - s_knownSfx; + } } sfx->bInMemory = qfalse; @@ -657,6 +963,9 @@ channel_t *S_PickChannel(int entnum, int entchannel) channel_t *ch, *ch_firstToDie; qboolean foundChan = qfalse; + if (s_UseOpenAL) + return S_OpenALPickChannel(entnum, entchannel); + if ( entchannel<0 ) { Com_Error (ERR_DROP, "S_PickChannel: entchannel<0"); } @@ -722,6 +1031,148 @@ channel_t *S_PickChannel(int entnum, int entchannel) } +/* + For use with Open AL + + Allows more than one sound of the same type to emanate from the same entity - sounds much better + on hardware this way esp. rapid fire modes of weapons! +*/ +channel_t *S_OpenALPickChannel(int entnum, int entchannel) +{ + int ch_idx; + channel_t *ch, *ch_firstToDie; + bool foundChan = false; + float source_pos[3]; + + if ( entchannel < 0 ) + { + Com_Error (ERR_DROP, "S_PickChannel: entchannel<0"); + } + + // Check for replacement sound, or find the best one to replace + + ch_firstToDie = s_channels + 1; // channel 0 is reserved for Music + + for (ch_idx = 1, ch = s_channels + ch_idx; ch_idx < s_numChannels; ch_idx++, ch++) + { + // See if the channel is free + if (!ch->thesfx) + { + ch_firstToDie = ch; + foundChan = true; + break; + } + } + + if (!foundChan) + { + for (ch_idx = 1, ch = s_channels + ch_idx; ch_idx < s_numChannels; ch_idx++, ch++) + { + if ( (ch->entnum == entnum) && (ch->entchannel == entchannel) && (ch->entnum != listener_number) ) + { + // Same entity and same type of sound effect (entchannel) + ch_firstToDie = ch; + foundChan = true; + break; + } + } + } + + int longestDist; + int dist; + + if (!foundChan) + { + // Find sound effect furthest from listener + ch = s_channels + 1; + + if (ch->fixed_origin) + { + // Convert to Open AL co-ordinates + source_pos[0] = ch->origin[0]; + source_pos[1] = ch->origin[2]; + source_pos[2] = -ch->origin[1]; + + longestDist = ((listener_pos[0] - source_pos[0]) * (listener_pos[0] - source_pos[0])) + + ((listener_pos[1] - source_pos[1]) * (listener_pos[1] - source_pos[1])) + + ((listener_pos[2] - source_pos[2]) * (listener_pos[2] - source_pos[2])); + } + else + { + if (ch->entnum == listener_number) + longestDist = 0; + else + { + // Convert to Open AL co-ordinates + source_pos[0] = loopSounds[ch->entnum].origin[0]; + source_pos[1] = loopSounds[ch->entnum].origin[2]; + source_pos[2] = -loopSounds[ch->entnum].origin[1]; + + longestDist = ((listener_pos[0] - source_pos[0]) * (listener_pos[0] - source_pos[0])) + + ((listener_pos[1] - source_pos[1]) * (listener_pos[1] - source_pos[1])) + + ((listener_pos[2] - source_pos[2]) * (listener_pos[2] - source_pos[2])); + } + } + + for (ch_idx = 2, ch = s_channels + ch_idx; ch_idx < s_numChannels; ch_idx++, ch++) + { + if (ch->fixed_origin) + { + // Convert to Open AL co-ordinates + source_pos[0] = ch->origin[0]; + source_pos[1] = ch->origin[2]; + source_pos[2] = -ch->origin[1]; + + dist = ((listener_pos[0] - source_pos[0]) * (listener_pos[0] - source_pos[0])) + + ((listener_pos[1] - source_pos[1]) * (listener_pos[1] - source_pos[1])) + + ((listener_pos[2] - source_pos[2]) * (listener_pos[2] - source_pos[2])); + } + else + { + if (ch->entnum == listener_number) + dist = 0; + else + { + // Convert to Open AL co-ordinates + source_pos[0] = loopSounds[ch->entnum].origin[0]; + source_pos[1] = loopSounds[ch->entnum].origin[2]; + source_pos[2] = -loopSounds[ch->entnum].origin[1]; + + dist = ((listener_pos[0] - source_pos[0]) * (listener_pos[0] - source_pos[0])) + + ((listener_pos[1] - source_pos[1]) * (listener_pos[1] - source_pos[1])) + + ((listener_pos[2] - source_pos[2]) * (listener_pos[2] - source_pos[2])); + } + } + + if (dist > longestDist) + { + longestDist = dist; + ch_firstToDie = ch; + } + } + } + + if (ch_firstToDie->bPlaying) + { + if (s_show->integer == 1) + { + Com_Printf(S_COLOR_RED"***kicking %s\n", ch_firstToDie->thesfx->sSoundName ); + } + + // Stop sound + alSourceStop(ch_firstToDie->alSource); + ch_firstToDie->bPlaying = false; + } + + // Reset channel variables + memset(&ch_firstToDie->MP3StreamHeader, 0, sizeof(MP3STREAM)); + ch_firstToDie->bLooping = false; + ch_firstToDie->bProcessed = false; + ch_firstToDie->bStreaming = false; + + return ch_firstToDie; +} + /* ==================== S_MuteSound @@ -732,22 +1183,38 @@ Gets the specified ent/channel and mutes any sound currently playing on it void S_MuteSound(int entityNum, int entchannel) { channel_t *ch; + int i; if (entchannel < 1) { return; } - ch = S_PickChannel( entityNum, entchannel ); - - if (!ch) + if (s_UseOpenAL) { - return; + ch = s_channels + 1; + for(i = 1; i < s_numChannels; i++,ch++) + { + if ((ch->entnum == entityNum) && (ch->entchannel == entchannel)) + { + alSourcef(ch->alSource, AL_GAIN, 0.0f); + break; + } + } } + else + { + ch = S_PickChannel( entityNum, entchannel ); + + if (!ch) + { + return; + } - ch->master_vol = 0; //just kill the volume and leave the rest alone, as to not actually interrupt anything expecting the sound to go through - ch->leftvol = 0; - ch->rightvol = 0; + ch->master_vol = 0; //just kill the volume and leave the rest alone, as to not actually interrupt anything expecting the sound to go through + ch->leftvol = 0; + ch->rightvol = 0; + } } @@ -767,7 +1234,8 @@ Entchannel 0 will never override a playing sound void S_StartSound(vec3_t origin, int entityNum, int entchannel, sfxHandle_t sfxHandle ) { channel_t *ch; sfx_t *sfx; -// int i, oldest, chosen; + int i; + int curTime; if ( !s_soundStarted || s_soundMuted ) { return; @@ -785,13 +1253,64 @@ void S_StartSound(vec3_t origin, int entityNum, int entchannel, sfxHandle_t sfxH if (sfx->bInMemory == qfalse) { S_memoryLoad(sfx); } - SND_TouchSFX(sfx); + if ( s_show->integer == 1 ) { Com_Printf( "%i : %s\n", s_paintedtime, sfx->sSoundName ); } -// Com_Printf("playing %s\n", sfx->soundName); + if (s_UseOpenAL) + { + // To avoid playing the same sound multiple times ... + if ((entityNum == ENTITYNUM_NONE) && (origin)) + { + // Check if we have already started playing this sound within 50 milliseconds ago + ch = s_channels + 1; + curTime = Com_Milliseconds(); + for (i = 1; i < s_numChannels; i++, ch++) + { + if ((ch->thesfx == sfx) && (curTime < (ch->thesfx->iLastTimeUsed + 50))) + { + return; + } + } + } + else if (entchannel == CHAN_WEAPON) + { + // Check if we are playing a 'charging' sound, if so, stop it now .. + ch = s_channels + 1; + for (i = 1; i < s_numChannels; i++, ch++) + { + if ((ch->entnum == entityNum) && (ch->entchannel == CHAN_WEAPON) && (ch->thesfx) && (strstr(strlwr(ch->thesfx->sSoundName), "altcharge") != NULL)) + { + // Stop this sound + alSourceStop(ch->alSource); + alSourcei(ch->alSource, AL_BUFFER, NULL); + ch->bPlaying = false; + ch->thesfx = NULL; + break; + } + } + } + else + { + ch = s_channels + 1; + for (i = 1; i < s_numChannels; i++, ch++) + { + if ((ch->entnum == entityNum) && (ch->thesfx) && (strstr(strlwr(ch->thesfx->sSoundName), "falling") != NULL)) + { + // Stop this sound + alSourceStop(ch->alSource); + alSourcei(ch->alSource, AL_BUFFER, NULL); + ch->bPlaying = false; + ch->thesfx = NULL; + break; + } + } + } + } + + SND_TouchSFX(sfx); // pick a channel to play on //--------------------------------- @@ -835,7 +1354,11 @@ void S_StartSound(vec3_t origin, int entityNum, int entchannel, sfxHandle_t sfxH ch->fixed_origin = qfalse; } - ch->master_vol = 240; + if (s_UseOpenAL) + ch->master_vol = 255; + else + ch->master_vol = 240; + ch->entnum = entityNum; ch->thesfx = sfx; ch->startSample = START_SAMPLE_IMMEDIATE; @@ -933,15 +1456,18 @@ void S_ClearSoundBuffer( void ) { s_rawend = 0; - if (dma.samplebits == 8) - clear = 0x80; - else - clear = 0; + if (!s_UseOpenAL) + { + if (dma.samplebits == 8) + clear = 0x80; + else + clear = 0; - SNDDMA_BeginPainting (); - if (dma.buffer) - Com_Memset(dma.buffer, clear, dma.samples * dma.samplebits/8); - SNDDMA_Submit (); + SNDDMA_BeginPainting (); + if (dma.buffer) + Com_Memset(dma.buffer, clear, dma.samples * dma.samplebits/8); + SNDDMA_Submit (); + } } @@ -950,7 +1476,11 @@ void S_ClearSoundBuffer( void ) { S_StopAllSounds ================== */ -void S_StopAllSounds(void) { +void S_StopAllSounds(void) +{ + channel_t *ch; + int i; + if ( !s_soundStarted ) { return; } @@ -958,6 +1488,21 @@ void S_StopAllSounds(void) { // stop the background music S_StopBackgroundTrack(); + if (s_UseOpenAL) + { + ch = s_channels; + for (i = 0; i < s_numChannels; i++, ch++) + { + alSourceStop(s_channels[i].alSource); + ch->thesfx = NULL; + memset(&ch->MP3StreamHeader, 0, sizeof(MP3STREAM)); + ch->bLooping = false; + ch->bProcessed = false; + ch->bPlaying = false; + ch->bStreaming = false; + } + } + S_ClearSoundBuffer (); } @@ -1028,6 +1573,31 @@ void S_AddLoopingSound( int entityNum, const vec3_t origin, const vec3_t velocit loopSounds[entityNum].doppler = qfalse; loopSounds[entityNum].oldDopplerScale = 1.0; loopSounds[entityNum].dopplerScale = 1.0; + + if (s_UseOpenAL) + { + if ((loopSounds[entityNum].bPlaying) && (loopSounds[entityNum].sfx != sfx)) + { + // Find the channel that is playing this sound, and stop it + channel_t *ch; + ch = s_channels + 1; + for (int i = 1; i < s_numChannels; i++, ch++) + { + if ((ch->bLooping) && (ch->entnum == entityNum)) + { + alSourceStop(ch->alSource); + + ch->bPlaying = false; + ch->thesfx = NULL; + + loopSounds[entityNum].bPlaying = false; + + break; + } + } + } + } + loopSounds[entityNum].sfx = sfx; /* if (VectorLengthSquared(velocity)>0.0) { @@ -1127,8 +1697,17 @@ static qboolean LoopSound_ChannelInit(loopSound_t *pLoopSound, int iLeftVol, int } numLoopChannels++; - if (numLoopChannels == MAX_CHANNELS) { - return qfalse; + + if (s_UseOpenAL) + { + if (numLoopChannels == s_numChannels) + return qfalse; + } + else + { + if (numLoopChannels == MAX_CHANNELS) { + return qfalse; + } } return qtrue; @@ -1342,10 +1921,39 @@ S_UpdateEntityPosition let the sound system know where an entity currently is ====================== */ -void S_UpdateEntityPosition( int entityNum, const vec3_t origin ) { +void S_UpdateEntityPosition( int entityNum, const vec3_t origin ) +{ + ALfloat pos[3]; + channel_t *ch; + int i; + if ( entityNum < 0 || entityNum > MAX_GENTITIES ) { Com_Error( ERR_DROP, "S_UpdateEntityPosition: bad entitynum %i", entityNum ); } + + if (s_UseOpenAL) + { + if (entityNum == listener_number) + return; + + ch = s_channels; + for (i = 0; i < s_numChannels; i++, ch++) + { + if ((s_channels[i].bPlaying) & (s_channels[i].entnum == entityNum)) + { + pos[0] = origin[0]; + pos[1] = origin[2]; + pos[2] = -origin[1]; + alSourcefv(s_channels[i].alSource, AL_POSITION, pos); + + if (s_bEALFileLoaded) + { + UpdateEAXBuffer(ch); + } + } + } + } + VectorCopy( origin, loopSounds[entityNum].origin ); } @@ -1357,44 +1965,129 @@ S_Respatialize Change the volumes of all the playing sounds for changes in their positions ============ */ -void S_Respatialize( int entityNum, const vec3_t head, vec3_t axis[3], int inwater ) { +void S_Respatialize( int entityNum, const vec3_t head, vec3_t axis[3], int inwater ) +{ + EAXOCCLUSIONPROPERTIES eaxOCProp; + unsigned int ulEnvironment; int i; channel_t *ch; vec3_t origin; + char *mapname; if ( !s_soundStarted || s_soundMuted ) { return; } - listener_number = entityNum; - VectorCopy(head, listener_origin); - VectorCopy(axis[0], listener_axis[0]); - VectorCopy(axis[1], listener_axis[1]); - VectorCopy(axis[2], listener_axis[2]); - - // update spatialization for dynamic sounds - ch = s_channels; - for ( i = 0 ; i < MAX_CHANNELS ; i++, ch++ ) { - if ( !ch->thesfx ) { - continue; + if (s_UseOpenAL) + { + // Check if a new level has been loaded - if so, try and load the appropriate EAL file + mapname = cl.mapname; + if ((mapname) && (strcmp(mapname, s_LevelName) != 0)) + { + EALFileInit(mapname); + strcpy(s_LevelName, mapname); } - // anything coming from the view entity will always be full volume - if (ch->entnum == listener_number) { - ch->leftvol = ch->master_vol; - ch->rightvol = ch->master_vol; - } else { - if (ch->fixed_origin) { - VectorCopy( ch->origin, origin ); - } else { - VectorCopy( loopSounds[ ch->entnum ].origin, origin ); - } - S_SpatializeOrigin (origin, ch->master_vol, &ch->leftvol, &ch->rightvol); + listener_number = entityNum; + + listener_pos[0] = head[0]; + listener_pos[1] = head[2]; + listener_pos[2] = -head[1]; + alListenerfv(AL_POSITION, listener_pos); + + listener_ori[0] = axis[0][0]; + listener_ori[1] = axis[0][2]; + listener_ori[2] = -axis[0][1]; + listener_ori[3] = axis[2][0]; + listener_ori[4] = axis[2][2]; + listener_ori[5] = -axis[2][1]; + alListenerfv(AL_ORIENTATION, listener_ori); + + // Update EAX effects here + if (s_bEALFileLoaded) + { + // Check if the Listener is underwater + if (inwater) + { + // Check if we have already applied Underwater effect + if (!s_bInWater) + { + // Apply Underwater Reverb effect, and occlude *all* Sources + ulEnvironment = EAX_ENVIRONMENT_UNDERWATER; + s_eaxSet(&DSPROPSETID_EAX_ListenerProperties, DSPROPERTY_EAXLISTENER_ENVIRONMENT, + NULL, &ulEnvironment, sizeof(unsigned int)); + s_EnvironmentID = 999; + + eaxOCProp.lOcclusion = -3000; + eaxOCProp.flOcclusionLFRatio = 0.0f; + eaxOCProp.flOcclusionRoomRatio = 1.37f; + eaxOCProp.flOcclusionDirectRatio = 1.0f; + + ch = s_channels + 1; + for (i = 1; i < s_numChannels; i++, ch++) + { + s_eaxSet(&DSPROPSETID_EAX_BufferProperties, DSPROPERTY_EAXBUFFER_OCCLUSIONPARAMETERS, + ch->alSource, &eaxOCProp, sizeof(EAXOCCLUSIONPROPERTIES)); + } + + s_bInWater = true; + } + } + else + { + // Not underwater ... check if the underwater effect is still present + if (s_bInWater) + { + // Remove underwater Reverb effect, and reset Occlusion / Obstruction amount on all Sources + UpdateEAXListener(false, false); + + ch = s_channels + 1; + for (i = 1; i < s_numChannels; i++, ch++) + { + UpdateEAXBuffer(ch); + } + + s_bInWater = false; + } + else + { + UpdateEAXListener(false, true); + } + } } } + else + { + listener_number = entityNum; + VectorCopy(head, listener_origin); + VectorCopy(axis[0], listener_axis[0]); + VectorCopy(axis[1], listener_axis[1]); + VectorCopy(axis[2], listener_axis[2]); - // add loopsounds - S_AddLoopSounds (); + // update spatialization for dynamic sounds + ch = s_channels; + for ( i = 0 ; i < MAX_CHANNELS ; i++, ch++ ) { + if ( !ch->thesfx ) { + continue; + } + // anything coming from the view entity will always be full volume + if (ch->entnum == listener_number) { + ch->leftvol = ch->master_vol; + ch->rightvol = ch->master_vol; + } else { + if (ch->fixed_origin) { + VectorCopy( ch->origin, origin ); + } else { + VectorCopy( loopSounds[ ch->entnum ].origin, origin ); + } + + S_SpatializeOrigin (origin, ch->master_vol, &ch->leftvol, &ch->rightvol); + } + } + + // add loopsounds + S_AddLoopSounds (); + } } @@ -1452,24 +2145,48 @@ void S_Update( void ) { return; } - // - // debugging output - // - if ( s_show->integer == 2 ) { - total = 0; - ch = s_channels; - for (i=0 ; ithesfx && (ch->leftvol || ch->rightvol) ) { - Com_Printf ("%f %f %s\n", ch->leftvol, ch->rightvol, ch->thesfx->sSoundName); - total++; + if (s_UseOpenAL) + { + // + // debugging output + // + if ( s_show->integer == 2 ) + { + total = 0; + ch = s_channels + 1; + for (i=1 ; ithesfx && (ch->leftvol || ch->rightvol) ) { + Com_Printf ("%s\n", ch->thesfx->sSoundName); + total++; + } } } + } + else + { + // + // debugging output + // + if ( s_show->integer == 2 ) { + total = 0; + ch = s_channels; + for (i=0 ; ithesfx && (ch->leftvol || ch->rightvol) ) { + Com_Printf ("%f %f %s\n", ch->leftvol, ch->rightvol, ch->thesfx->sSoundName); + total++; + } + } - Com_Printf ("----(%i)---- painted: %i\n", total, s_paintedtime); + Com_Printf ("----(%i)---- painted: %i\n", total, s_paintedtime); + } } - // add raw data from streamed samples - S_UpdateBackgroundTrack(); + // The Open AL code, handles background music in the S_UpdateRawSamples function + if (!s_UseOpenAL) + { + // add raw data from streamed samples + S_UpdateBackgroundTrack(); + } // mix some sound S_Update_(); @@ -1526,58 +2243,571 @@ void S_Update_(void) { float ma, op; float thisTime, sane; static int ot = -1; + channel_t *ch; + int i, j; + int source; + float pos[3]; if ( !s_soundStarted || s_soundMuted ) { return; } - thisTime = Com_Milliseconds(); + if (s_UseOpenAL) + { + UpdateSingleShotSounds(); - // Updates s_soundtime - S_GetSoundtime(); + ch = s_channels + 1; + for ( i = 1; i < s_numChannels; i++, ch++ ) + { + if ( !ch->thesfx || (ch->bPlaying)) + continue; + + source = ch - s_channels; - if (s_soundtime == ot) { - return; + // Get position of source + if (ch->fixed_origin) + { + pos[0] = ch->origin[0]; + pos[1] = ch->origin[2]; + pos[2] = -ch->origin[1]; + alSourcei(s_channels[source].alSource, AL_SOURCE_RELATIVE, AL_FALSE); + } + else + { + if (ch->entnum == listener_number) + { + pos[0] = 0.0f; + pos[1] = 0.0f; + pos[2] = 0.0f; + alSourcei(s_channels[source].alSource, AL_SOURCE_RELATIVE, AL_TRUE); + } + else + { + // Get position of Entity + pos[0] = loopSounds[ ch->entnum ].origin[0]; + pos[1] = loopSounds[ ch->entnum ].origin[2]; + pos[2] = -loopSounds[ ch->entnum ].origin[1]; + alSourcei(s_channels[source].alSource, AL_SOURCE_RELATIVE, AL_FALSE); + } + } + + alSourcefv(s_channels[source].alSource, AL_POSITION, pos); + + alSourcei(s_channels[source].alSource, AL_LOOPING, AL_FALSE); + alSourcef(s_channels[source].alSource, AL_GAIN, ((float)(ch->master_vol) * s_volume->value) / 255.0f); + + if (s_bEALFileLoaded) + UpdateEAXBuffer(ch); + + int nBytesDecoded = 0; + int nTotalBytesDecoded = 0; + int nBuffersToAdd = 0; + + if (ch->thesfx->pMP3StreamHeader) + { + memcpy(&ch->MP3StreamHeader, ch->thesfx->pMP3StreamHeader, sizeof(ch->MP3StreamHeader)); + ch->iMP3SlidingDecodeWritePos = 0; + ch->iMP3SlidingDecodeWindowPos= 0; + + // Reset streaming buffers status's + for (i = 0; i < NUM_STREAMING_BUFFERS; i++) + ch->buffers[i].Status = UNQUEUED; + + // Decode (STREAMING_BUFFER_SIZE / 1152) MP3 frames for each of the NUM_STREAMING_BUFFERS AL Buffers + for (i = 0; i < NUM_STREAMING_BUFFERS; i++) + { + nTotalBytesDecoded = 0; + + for (j = 0; j < (STREAMING_BUFFER_SIZE / 1152); j++) + { + nBytesDecoded = C_MP3Stream_Decode(&ch->MP3StreamHeader); + + memcpy(ch->buffers[i].Data + nTotalBytesDecoded, ch->MP3StreamHeader.bDecodeBuffer, nBytesDecoded); + + nTotalBytesDecoded += nBytesDecoded; + } + + if (nTotalBytesDecoded != STREAMING_BUFFER_SIZE) + { + memset(ch->buffers[i].Data + nTotalBytesDecoded, 0, (STREAMING_BUFFER_SIZE - nTotalBytesDecoded)); + break; + } + } + + if (i >= NUM_STREAMING_BUFFERS) + nBuffersToAdd = NUM_STREAMING_BUFFERS; + else + nBuffersToAdd = i + 1; + + // Make sure queue is empty first + alSourcei(s_channels[source].alSource, AL_BUFFER, NULL); + + for (i = 0; i < nBuffersToAdd; i++) + { + // Copy decoded data to AL Buffer + alBufferData(ch->buffers[i].BufferID, AL_FORMAT_MONO16, ch->buffers[i].Data, STREAMING_BUFFER_SIZE, 22050); + + // Queue AL Buffer on Source + alSourceQueueBuffers(s_channels[source].alSource, 1, &(ch->buffers[i].BufferID)); + if (alGetError() == AL_NO_ERROR) + { + ch->buffers[i].Status = QUEUED; + } + } + + // Clear error state, and check for successful Play call + alGetError(); + alSourcePlay(s_channels[source].alSource); + if (alGetError() == AL_NO_ERROR) + s_channels[source].bPlaying = true; + + // Record start time for Lip-syncing + s_channels[source].iStartTime = Com_Milliseconds(); + + ch->bStreaming = true; + + return; + } + else + { + // Attach buffer to source + alSourcei(s_channels[source].alSource, AL_BUFFER, ch->thesfx->Buffer); + + ch->bStreaming = false; + + // Clear error state, and check for successful Play call + alGetError(); + alSourcePlay(s_channels[source].alSource); + if (alGetError() == AL_NO_ERROR) + s_channels[source].bPlaying = true; + } + } + + UpdateLoopingSounds(); + + UpdateRawSamples(); + + EAXMorph(); } - ot = s_soundtime; + else + { + thisTime = Com_Milliseconds(); - // clear any sound effects that end before the current time, - // and start any new sounds - S_ScanChannelStarts(); + // Updates s_soundtime + S_GetSoundtime(); - sane = thisTime - lastTime; - if (sane<11) { - sane = 11; // 85hz + if (s_soundtime == ot) { + return; + } + ot = s_soundtime; + + // clear any sound effects that end before the current time, + // and start any new sounds + S_ScanChannelStarts(); + + sane = thisTime - lastTime; + if (sane<11) { + sane = 11; // 85hz + } + + ma = s_mixahead->value * dma.speed; + op = s_mixPreStep->value + sane*dma.speed*0.01; + + if (op < ma) { + ma = op; + } + + // mix ahead of current position + endtime = s_soundtime + ma; + + // mix to an even submission block size + endtime = (endtime + dma.submission_chunk-1) + & ~(dma.submission_chunk-1); + + // never mix more than the complete buffer + samps = dma.samples >> (dma.channels-1); + if (endtime - s_soundtime > samps) + endtime = s_soundtime + samps; + + + + SNDDMA_BeginPainting (); + + S_PaintChannels (endtime); + + SNDDMA_Submit (); + + lastTime = thisTime; + } +} + +void UpdateSingleShotSounds() +{ + int i, j, k; + ALint state; + ALint processed; + channel_t *ch; + + // Firstly, check if any single-shot sounds have completed, or if they need more data (for streaming Sources), + // and/or if any of the currently playing (non-Ambient) looping sounds need to be stopped + ch = s_channels ; + for (i = 0; i < s_numChannels; i++, ch++) + { + ch->bProcessed = false; + + if (s_channels[i].bPlaying) + { + if (ch->bLooping) + { + // Looping Sound + if (loopSounds[ch->entnum].active == false) + { + alSourceStop(s_channels[i].alSource); + + s_channels[i].bPlaying = false; + s_channels[i].thesfx = NULL; + loopSounds[ch->entnum].bPlaying = false; + } + } + else + { + // Single-shot + if (s_channels[i].bStreaming == false) + { + alGetSourcei(s_channels[i].alSource, AL_SOURCE_STATE, &state); + if (state == AL_STOPPED) + { + s_channels[i].thesfx = NULL; + s_channels[i].bPlaying = false; + } + } + else + { + // Process streaming sample + + // Procedure :- + // if more data to play + // if any UNQUEUED Buffers + // fill them with data + // (else ?) + // get number of buffers processed + // fill them with data + // restart playback if it has stopped (buffer underrun) + // else + // free channel + + int nBytesDecoded; + + if (ch->thesfx->pMP3StreamHeader) + { + if (ch->MP3StreamHeader.iSourceBytesRemaining == 0) + { + // Finished decoding data - if the source has finished playing then we're done + alGetSourcei(ch->alSource, AL_SOURCE_STATE, &state); + if (state == AL_STOPPED) + { + // Attach NULL buffer to Source to remove any buffers left in the queue + alSourcei(ch->alSource, AL_BUFFER, NULL); + ch->thesfx = NULL; + ch->bPlaying = false; + } + // Move on to next channel ... + continue; + } + + // Check to see if any Buffers have been processed + alGetSourcei(ch->alSource, AL_BUFFERS_PROCESSED, &processed); + + ALuint buffer; + while (processed) + { + alSourceUnqueueBuffers(ch->alSource, 1, &buffer); + for (j = 0; j < NUM_STREAMING_BUFFERS; j++) + { + if (ch->buffers[j].BufferID == buffer) + { + ch->buffers[j].Status = UNQUEUED; + break; + } + } + processed--; + } + + int nTotalBytesDecoded = 0; + + for (j = 0; j < NUM_STREAMING_BUFFERS; j++) + { + if ((ch->buffers[j].Status == UNQUEUED) & (ch->MP3StreamHeader.iSourceBytesRemaining > 0)) + { + nTotalBytesDecoded = 0; + + for (k = 0; k < (STREAMING_BUFFER_SIZE / 1152); k++) + { + nBytesDecoded = C_MP3Stream_Decode(&ch->MP3StreamHeader); + if (nBytesDecoded > 0) + { + memcpy(ch->buffers[j].Data + nTotalBytesDecoded, ch->MP3StreamHeader.bDecodeBuffer, nBytesDecoded); + nTotalBytesDecoded += nBytesDecoded; + } + else + { + // Make sure that iSourceBytesRemaining is 0 + if (ch->MP3StreamHeader.iSourceBytesRemaining != 0) + { + ch->MP3StreamHeader.iSourceBytesRemaining = 0; + break; + } + } + } + + if (nTotalBytesDecoded != STREAMING_BUFFER_SIZE) + { + memset(ch->buffers[j].Data + nTotalBytesDecoded, 0, (STREAMING_BUFFER_SIZE - nTotalBytesDecoded)); + + // Move data to buffer + alBufferData(ch->buffers[j].BufferID, AL_FORMAT_MONO16, ch->buffers[j].Data, STREAMING_BUFFER_SIZE, 22050); + + // Queue Buffer on Source + alSourceQueueBuffers(ch->alSource, 1, &(ch->buffers[j].BufferID)); + + // Update status of Buffer + ch->buffers[j].Status = QUEUED; + + break; + } + else + { + // Move data to buffer + alBufferData(ch->buffers[j].BufferID, AL_FORMAT_MONO16, ch->buffers[j].Data, STREAMING_BUFFER_SIZE, 22050); + + // Queue Buffer on Source + alSourceQueueBuffers(ch->alSource, 1, &(ch->buffers[j].BufferID)); + + // Update status of Buffer + ch->buffers[j].Status = QUEUED; + } + } + } + + // Get state of Buffer + alGetSourcei(ch->alSource, AL_SOURCE_STATE, &state); + if (state != AL_PLAYING) + { + alSourcePlay(ch->alSource); +#ifdef _DEBUG + char szString[256]; + sprintf(szString,"[%d] Restarting playback of single-shot streaming MP3 sample - still have %d bytes to decode\n", i, ch->MP3StreamHeader.iSourceBytesRemaining); + OutputDebugString(szString); +#endif + } + } + } + } + } + } +} + + + + +void UpdateLoopingSounds() +{ + int i; + ALuint source; + channel_t *ch; + loopSound_t *loop; + float pos[3]; + float fVolume = 0.003922; // 1.f / 255.f + +#ifdef _DEBUG + // Clear AL Error State + alGetError(); +#endif + + for ( i = 0 ; i < MAX_GENTITIES ; i++) + { + loop = &loopSounds[i]; + + if ((loop->bPlaying)|(!loop->active)) + continue; + + ch = S_PickChannel(i, CHAN_AUTO); + + // Play sound on channel + ch->master_vol = 255; + ch->entnum = i; + ch->thesfx = loop->sfx; + ch->entchannel = CHAN_AUTO; + + ch->fixed_origin = qfalse; + ch->origin[0] = 0.f; + ch->origin[1] = 0.f; + ch->origin[2] = 0.f; + + ch->bLooping = true; + + source = ch - s_channels; + alSourcei(s_channels[source].alSource, AL_BUFFER, ch->thesfx->Buffer); + + if (ch->entnum == listener_number) + { + // Make Source Head Relative and set position to 0,0,0 (on top of the listener) + alSourcei(s_channels[source].alSource, AL_SOURCE_RELATIVE, AL_TRUE); + alSourcefv(s_channels[source].alSource, AL_POSITION, ch->origin); + } + else + { + pos[0] = loop->origin[0]; + pos[1] = loop->origin[2]; + pos[2] = -loop->origin[1]; + alSourcefv(s_channels[source].alSource, AL_POSITION, pos); + alSourcei(s_channels[source].alSource, AL_SOURCE_RELATIVE, AL_FALSE); + } + + alSourcei(s_channels[source].alSource, AL_LOOPING, AL_TRUE); + alSourcef(s_channels[source].alSource, AL_GAIN, (float)(ch->master_vol) * s_volume->value * fVolume); + + if (s_bEALFileLoaded) + UpdateEAXBuffer(ch); + + alGetError(); + alSourcePlay(s_channels[source].alSource); + if (alGetError() == AL_NO_ERROR) + { + ch->bPlaying = true; + loop->bPlaying = true; + } + } +} + +void UpdateRawSamples() +{ + ALuint buffer; + ALint size; + ALint processed; + ALint state; + int i,j,src; + + +#ifdef _DEBUG + char szString[256]; + // Clear Open AL Error + alGetError(); +#endif + + S_UpdateBackgroundTrack(); + + // Find out how many buffers have been processed (played) by the Source + alGetSourcei(s_channels[0].alSource, AL_BUFFERS_PROCESSED, &processed); + + while (processed) + { + // Unqueue each buffer, determine the length of the buffer, and then delete it + alSourceUnqueueBuffers(s_channels[0].alSource, 1, &buffer); + alGetBufferi(buffer, AL_SIZE, &size); + alDeleteBuffers(1, &buffer); + + // Update sg.soundtime (+= number of samples played (number of bytes / 4)) + s_soundtime += (size >> 2); + + processed--; } - ma = s_mixahead->value * dma.speed; - op = s_mixPreStep->value + sane*dma.speed*0.01; +// S_UpdateBackgroundTrack(); - if (op < ma) { - ma = op; + // Add new data to a new Buffer and queue it on the Source + if (s_rawend > s_paintedtime) + { + size = (s_rawend - s_paintedtime)<<2; + if (size > (MAX_RAW_SAMPLES<<2)) + { + OutputDebugString("UpdateRawSamples :- Raw Sample buffer has overflowed !!!\n"); +// s_rawend = s_paintedtime + MAX_RAW_SAMPLES; +// size = MAX_RAW_SAMPLES<<2; + size = MAX_RAW_SAMPLES<<2; + s_paintedtime = s_rawend - MAX_RAW_SAMPLES; + } + + // Copy samples from RawSamples to audio buffer (sg.rawdata) + for (i = s_paintedtime, j = 0; i < s_rawend; i++, j+=2) + { + src = i & (MAX_RAW_SAMPLES - 1); + s_rawdata[j] = (short)(s_rawsamples[src].left>>8); + s_rawdata[j+1] = (short)(s_rawsamples[src].right>>8); + } + + // Need to generate more than 1 buffer for music playback + // iterations = 0; + // largestBufferSize = (MAX_RAW_SAMPLES / 4) * 4 + // while (size) + // generate a buffer + // if size > largestBufferSize + // copy sg.rawdata + ((iterations * largestBufferSize)>>1) to buffer + // size -= largestBufferSize + // else + // copy remainder + // size = 0 + // queue the buffer + // iterations++; + + int iterations = 0; + int largestBufferSize = MAX_RAW_SAMPLES; // in bytes (== quarter of Raw Samples data) + while (size) + { + alGenBuffers(1, &buffer); + + if (size > largestBufferSize) + { + alBufferData(buffer, AL_FORMAT_STEREO16, (char*)(s_rawdata + ((iterations * largestBufferSize)>>1)), largestBufferSize, 22050); + size -= largestBufferSize; + } + else + { + alBufferData(buffer, AL_FORMAT_STEREO16, (char*)(s_rawdata + ((iterations * largestBufferSize)>>1)), size, 22050); + size = 0; + } + + alSourceQueueBuffers(s_channels[0].alSource, 1, &buffer); + iterations++; + } + + // Update paintedtime + s_paintedtime = s_rawend; + + // Check that the Source is actually playing + alGetSourcei(s_channels[0].alSource, AL_SOURCE_STATE, &state); + if (state != AL_PLAYING) + { + // Stopped playing ... due to buffer underrun + // Unqueue any buffers still on the Source (they will be PROCESSED), and restart playback + alGetSourcei(s_channels[0].alSource, AL_BUFFERS_PROCESSED, &processed); +#ifdef _DEBUG + sprintf(szString, "RawSamples Source stopped with %d buffer processed\n", processed); + OutputDebugString(szString); +#endif + while (processed) + { + alSourceUnqueueBuffers(s_channels[0].alSource, 1, &buffer); + processed--; + alGetBufferi(buffer, AL_SIZE, &size); + alDeleteBuffers(1, &buffer); + + // Update sg.soundtime (+= number of samples played (number of bytes / 4)) + s_soundtime += (size >> 2); + } + +#ifdef _DEBUG + OutputDebugString("Restarting / Starting playback of Raw Samples\n"); +#endif + + alSourcePlay(s_channels[0].alSource); + } } - // mix ahead of current position - endtime = s_soundtime + ma; - - // mix to an even submission block size - endtime = (endtime + dma.submission_chunk-1) - & ~(dma.submission_chunk-1); - - // never mix more than the complete buffer - samps = dma.samples >> (dma.channels-1); - if (endtime - s_soundtime > samps) - endtime = s_soundtime + samps; - - - - SNDDMA_BeginPainting (); - - S_PaintChannels (endtime); - - SNDDMA_Submit (); - - lastTime = thisTime; +#ifdef _DEBUG + if (alGetError() != AL_NO_ERROR) + OutputDebugString("OAL Error : UpdateRawSamples\n"); +#endif } /* @@ -2419,3 +3649,639 @@ qboolean SND_RegisterAudio_LevelLoadEnd(qboolean bDeleteEverythingNotUsedThisLev return bAtLeastOneSoundDropped; } +/****************************************************************************************************\ +* +* EAX Related +* +\****************************************************************************************************/ + +/* + Initialize the EAX Manager +*/ +void InitEAXManager() +{ + LPEAXMANAGERCREATE lpEAXManagerCreateFn; + HRESULT hr; + + // Check for EAX 3.0 support + s_bEAX = alIsExtensionPresent((ALubyte*)"EAX3.0"); + if (s_bEAX) + { + s_eaxSet = (EAXSet)alGetProcAddress((ALubyte*)"EAXSet"); + if (s_eaxSet == NULL) + s_bEAX = false; + s_eaxGet = (EAXGet)alGetProcAddress((ALubyte*)"EAXGet"); + if (s_eaxGet == NULL) + s_bEAX = false; + } + + // If we have detected EAX support, then try and load the EAX Manager DLL + if (s_bEAX) + { + s_hEAXManInst = LoadLibrary("EAXMan.dll"); + if (s_hEAXManInst) + { + lpEAXManagerCreateFn = (LPEAXMANAGERCREATE)GetProcAddress(s_hEAXManInst, "EaxManagerCreate"); + if (lpEAXManagerCreateFn) + { + hr = lpEAXManagerCreateFn(&s_lpEAXManager); + if (hr == EM_OK) + return; + } + } + } + + // If the EAXManager library was loaded (and there was a problem), then unload it + if (s_hEAXManInst) + { + FreeLibrary(s_hEAXManInst); + s_hEAXManInst = NULL; + } + + s_lpEAXManager = NULL; + s_bEAX = false; + + return; +} + +/* + Release the EAX Manager +*/ +void ReleaseEAXManager() +{ + s_bEAX = false; + if (s_lpEAXManager) + { + s_lpEAXManager->Release(); + s_lpEAXManager = NULL; + } + if (s_hEAXManInst) + { + FreeLibrary(s_hEAXManInst); + s_hEAXManInst = NULL; + } +} + + +/* + Try to load the given .eal file +*/ +bool LoadEALFile(char *szEALFilename) +{ + char *ealData = NULL; + int result; + HRESULT hr; + char szFullEALFilename[MAX_QPATH]; + + if ((!s_lpEAXManager) || (!s_bEAX)) + { + return false; + } + + s_EnvironmentID = 0xFFFFFFFF; + + // Load EAL file from PAK file + result = FS_ReadFile(szEALFilename, (void **)&ealData); + if ((ealData) && (result != -1)) + { + hr = s_lpEAXManager->LoadDataSet(ealData, EMFLAG_LOADFROMMEMORY); + + // Unload EAL file + FS_FreeFile (ealData); + + if (hr == EM_OK) + return true; + } + else + { + // Failed to load via Quake loader, try manually + Com_sprintf(szFullEALFilename, MAX_QPATH, "base/%s", szEALFilename); + hr = s_lpEAXManager->LoadDataSet(szFullEALFilename, 0); + if (hr == EM_OK) + return true; + } + + return false; +} + +/* + Unload current .eal file +*/ +void UnloadEALFile() +{ + HRESULT hr; + + if ((!s_lpEAXManager) || (!s_bEAX)) + return; + + hr = s_lpEAXManager->FreeDataSet(0); + + return; +} + +/* + Updates the current EAX Reverb setting, based on the location of the listener +*/ +void UpdateEAXListener(bool bUseDefault, bool bUseMorphing) +{ + HRESULT hr; + EMPOINT EMPoint; + long lID; + + if ((!s_lpEAXManager) || (!s_bEAX)) + return; + + if (bUseDefault) + { + // Get Default EAX Listener attributes + hr = s_lpEAXManager->GetEnvironmentAttributes(EMFLAG_IDDEFAULT, &s_eaxLPSource); + if (hr == EM_OK) + { + s_eaxLPSource.flAirAbsorptionHF = 0.0f; + s_eaxSet(&DSPROPSETID_EAX_ListenerProperties, DSPROPERTY_EAXLISTENER_ALLPARAMETERS, + NULL, &s_eaxLPSource, sizeof(EAXLISTENERPROPERTIES)); + + s_eaxLPCur = s_eaxLPSource; + s_eaxLPDest = s_eaxLPSource; + + s_EnvironmentID = EMFLAG_IDDEFAULT; + + s_eaxMorphStartTime = 0; + s_eaxMorphCount = 0; + + return; + } + return; + } + + // Convert Listener co-ordinate to left-handed system + EMPoint.fX = listener_pos[0]; + EMPoint.fY = listener_pos[1]; + EMPoint.fZ = -listener_pos[2]; + + hr = s_lpEAXManager->GetListenerDynamicAttributes(0, &EMPoint, &lID, EMFLAG_LOCKPOSITION); + if (hr == EM_OK) + { + if (lID != s_EnvironmentID) + { + // Get EAX Preset info. + hr = s_lpEAXManager->GetEnvironmentAttributes(lID, &s_eaxLPDest); + s_eaxLPDest.flAirAbsorptionHF = 0.0f; + if (hr == EM_OK) + { + if (bUseMorphing) + { + // Morph to the new Destination from the Current Settings + s_eaxLPSource = s_eaxLPCur; + s_eaxMorphCount = 0; + s_eaxMorphStartTime = Com_Milliseconds(); + s_eaxMorphing = true; + } + else + { + // Set Environment + s_eaxSet(&DSPROPSETID_EAX_ListenerProperties, DSPROPERTY_EAXLISTENER_ALLPARAMETERS, + NULL, &s_eaxLPDest, sizeof(EAXLISTENERPROPERTIES)); + + s_eaxLPSource = s_eaxLPCur = s_eaxLPDest; + s_eaxMorphing = false; + } + + s_EnvironmentID = lID; + } + } + } + + return; +} + + +/* + Updates the EAX Buffer related effects on the given Source +*/ +void UpdateEAXBuffer(channel_t *ch) +{ + HRESULT hr; + EMPOINT EMSourcePoint; + EMPOINT EMVirtualSourcePoint; + EAXOBSTRUCTIONPROPERTIES eaxOBProp; + EAXOCCLUSIONPROPERTIES eaxOCProp; + + // If EAX Manager is not initialized, or there is no EAX support, or the listener + // is underwater, return + if ((!s_lpEAXManager) || (!s_bEAX) || (s_bInWater)) + return; + + // Set Occlusion Direct Ratio to the default value (it won't get set by the current version of + // EAX Manager) + eaxOCProp.flOcclusionDirectRatio = EAXBUFFER_DEFAULTOCCLUSIONDIRECTRATIO; + + // Convert Source co-ordinate to left-handed system + if (ch->fixed_origin) + { + // Converting from Quake -> DS3D (for EAGLE) ... swap Y and Z + EMSourcePoint.fX = ch->origin[0]; + EMSourcePoint.fY = ch->origin[2]; + EMSourcePoint.fZ = ch->origin[1]; + } + else + { + if (ch->entnum == listener_number) + { + // Source at same position as listener + // Probably won't be any Occlusion / Obstruction effect -- unless the listener is underwater + // Converting from Open AL -> DS3D (for EAGLE) ... invert Z + EMSourcePoint.fX = listener_pos[0]; + EMSourcePoint.fY = listener_pos[1]; + EMSourcePoint.fZ = -listener_pos[2]; + } + else + { + // Get position of Entity + // Converting from Quake -> DS3D (for EAGLE) ... swap Y and Z + EMSourcePoint.fX = loopSounds[ ch->entnum ].origin[0]; + EMSourcePoint.fY = loopSounds[ ch->entnum ].origin[2]; + EMSourcePoint.fZ = loopSounds[ ch->entnum ].origin[1]; + } + } + + hr = s_lpEAXManager->GetSourceDynamicAttributes(0, &EMSourcePoint, &eaxOBProp.lObstruction, &eaxOBProp.flObstructionLFRatio, + &eaxOCProp.lOcclusion, &eaxOCProp.flOcclusionLFRatio, &eaxOCProp.flOcclusionRoomRatio, &EMVirtualSourcePoint, 0); + if (hr == EM_OK) + { + // Set EAX effect ! + s_eaxSet(&DSPROPSETID_EAX_BufferProperties, DSPROPERTY_EAXBUFFER_OBSTRUCTIONPARAMETERS, + ch->alSource, &eaxOBProp, sizeof(EAXOBSTRUCTIONPROPERTIES)); + + s_eaxSet(&DSPROPSETID_EAX_BufferProperties, DSPROPERTY_EAXBUFFER_OCCLUSIONPARAMETERS, + ch->alSource, &eaxOCProp, sizeof(EAXOCCLUSIONPROPERTIES)); + } + + return; +} + + +void EAXMorph() +{ + int curPos; + int curTime; + float flRatio; + + if ((!s_bEAX) || (!s_eaxMorphing)) + return; + + // Get current time + curTime = Com_Milliseconds(); + + curPos = ((curTime - s_eaxMorphStartTime) / 100); + + if (curPos >= 10) + { + // Finished morphing + s_eaxMorphing = false; + s_eaxLPSource = s_eaxLPDest; + s_eaxLPCur = s_eaxLPDest; + + s_eaxSet(&DSPROPSETID_EAX_ListenerProperties, DSPROPERTY_EAXLISTENER_ALLPARAMETERS, + NULL, &s_eaxLPSource, sizeof(EAXLISTENERPROPERTIES)); + } + else + { + if (curPos > s_eaxMorphCount) + { + // Next morph step + flRatio = (float)curPos / 10.f; + + EAX3ListenerInterpolate(&s_eaxLPSource, &s_eaxLPDest, flRatio, &s_eaxLPCur); + + s_eaxSet(&DSPROPSETID_EAX_ListenerProperties, DSPROPERTY_EAXLISTENER_ALLPARAMETERS, + NULL, &s_eaxLPCur, sizeof(EAXLISTENERPROPERTIES)); + + s_eaxMorphCount = curPos; + } + } +} + +/***********************************************************************************************\ +* +* Definition of the EAXMorph function - EAX3ListenerInterpolate +* +\***********************************************************************************************/ + +/* + EAX3ListenerInterpolate + lpStart - Initial EAX 3 Listener parameters + lpFinish - Final EAX 3 Listener parameters + flRatio - Ratio Destination : Source (0.0 == Source, 1.0 == Destination) + lpResult - Interpolated EAX 3 Listener parameters + bCheckValues - Check EAX 3.0 parameters are in range, default = false (no checking) +*/ +bool EAX3ListenerInterpolate(LPEAXLISTENERPROPERTIES lpStart, LPEAXLISTENERPROPERTIES lpFinish, + float flRatio, LPEAXLISTENERPROPERTIES lpResult, bool bCheckValues) +{ + EAXVECTOR StartVector, FinalVector; + + float flInvRatio; + + if (bCheckValues) + { + if (!CheckEAX3LP(lpStart)) + return false; + + if (!CheckEAX3LP(lpFinish)) + return false; + } + + if (flRatio >= 1.0f) + { + memcpy(lpResult, lpFinish, sizeof(EAXLISTENERPROPERTIES)); + return true; + } + else if (flRatio <= 0.0f) + { + memcpy(lpResult, lpStart, sizeof(EAXLISTENERPROPERTIES)); + return true; + } + + flInvRatio = (1.0f - flRatio); + + // Environment + lpResult->ulEnvironment = 26; // (UNDEFINED environment) + + // Environment Size + if (lpStart->flEnvironmentSize == lpFinish->flEnvironmentSize) + lpResult->flEnvironmentSize = lpStart->flEnvironmentSize; + else + lpResult->flEnvironmentSize = (float)exp( (log(lpStart->flEnvironmentSize) * flInvRatio) + (log(lpFinish->flEnvironmentSize) * flRatio) ); + + // Environment Diffusion + if (lpStart->flEnvironmentDiffusion == lpFinish->flEnvironmentDiffusion) + lpResult->flEnvironmentDiffusion = lpStart->flEnvironmentDiffusion; + else + lpResult->flEnvironmentDiffusion = (lpStart->flEnvironmentDiffusion * flInvRatio) + (lpFinish->flEnvironmentDiffusion * flRatio); + + // Room + if (lpStart->lRoom == lpFinish->lRoom) + lpResult->lRoom = lpStart->lRoom; + else + lpResult->lRoom = (int)( ((float)lpStart->lRoom * flInvRatio) + ((float)lpFinish->lRoom * flRatio) ); + + // Room HF + if (lpStart->lRoomHF == lpFinish->lRoomHF) + lpResult->lRoomHF = lpStart->lRoomHF; + else + lpResult->lRoomHF = (int)( ((float)lpStart->lRoomHF * flInvRatio) + ((float)lpFinish->lRoomHF * flRatio) ); + + // Room LF + if (lpStart->lRoomLF == lpFinish->lRoomLF) + lpResult->lRoomLF = lpStart->lRoomLF; + else + lpResult->lRoomLF = (int)( ((float)lpStart->lRoomLF * flInvRatio) + ((float)lpFinish->lRoomLF * flRatio) ); + + // Decay Time + if (lpStart->flDecayTime == lpFinish->flDecayTime) + lpResult->flDecayTime = lpStart->flDecayTime; + else + lpResult->flDecayTime = (float)exp( (log(lpStart->flDecayTime) * flInvRatio) + (log(lpFinish->flDecayTime) * flRatio) ); + + // Decay HF Ratio + if (lpStart->flDecayHFRatio == lpFinish->flDecayHFRatio) + lpResult->flDecayHFRatio = lpStart->flDecayHFRatio; + else + lpResult->flDecayHFRatio = (float)exp( (log(lpStart->flDecayHFRatio) * flInvRatio) + (log(lpFinish->flDecayHFRatio) * flRatio) ); + + // Decay LF Ratio + if (lpStart->flDecayLFRatio == lpFinish->flDecayLFRatio) + lpResult->flDecayLFRatio = lpStart->flDecayLFRatio; + else + lpResult->flDecayLFRatio = (float)exp( (log(lpStart->flDecayLFRatio) * flInvRatio) + (log(lpFinish->flDecayLFRatio) * flRatio) ); + + // Reflections + if (lpStart->lReflections == lpFinish->lReflections) + lpResult->lReflections = lpStart->lReflections; + else + lpResult->lReflections = (int)( ((float)lpStart->lReflections * flInvRatio) + ((float)lpFinish->lReflections * flRatio) ); + + // Reflections Delay + if (lpStart->flReflectionsDelay == lpFinish->flReflectionsDelay) + lpResult->flReflectionsDelay = lpStart->flReflectionsDelay; + else + lpResult->flReflectionsDelay = (float)exp( (log(lpStart->flReflectionsDelay+0.0001) * flInvRatio) + (log(lpFinish->flReflectionsDelay+0.0001) * flRatio) ); + + // Reflections Pan + + // To interpolate the vector correctly we need to ensure that both the initial and final vectors vectors are clamped to a length of 1.0f + StartVector = lpStart->vReflectionsPan; + FinalVector = lpFinish->vReflectionsPan; + + Clamp(&StartVector); + Clamp(&FinalVector); + + if (lpStart->vReflectionsPan.x == lpFinish->vReflectionsPan.x) + lpResult->vReflectionsPan.x = lpStart->vReflectionsPan.x; + else + lpResult->vReflectionsPan.x = FinalVector.x + (flInvRatio * (StartVector.x - FinalVector.x)); + + if (lpStart->vReflectionsPan.y == lpFinish->vReflectionsPan.y) + lpResult->vReflectionsPan.y = lpStart->vReflectionsPan.y; + else + lpResult->vReflectionsPan.y = FinalVector.y + (flInvRatio * (StartVector.y - FinalVector.y)); + + if (lpStart->vReflectionsPan.z == lpFinish->vReflectionsPan.z) + lpResult->vReflectionsPan.z = lpStart->vReflectionsPan.z; + else + lpResult->vReflectionsPan.z = FinalVector.z + (flInvRatio * (StartVector.z - FinalVector.z)); + + // Reverb + if (lpStart->lReverb == lpFinish->lReverb) + lpResult->lReverb = lpStart->lReverb; + else + lpResult->lReverb = (int)( ((float)lpStart->lReverb * flInvRatio) + ((float)lpFinish->lReverb * flRatio) ); + + // Reverb Delay + if (lpStart->flReverbDelay == lpFinish->flReverbDelay) + lpResult->flReverbDelay = lpStart->flReverbDelay; + else + lpResult->flReverbDelay = (float)exp( (log(lpStart->flReverbDelay+0.0001) * flInvRatio) + (log(lpFinish->flReverbDelay+0.0001) * flRatio) ); + + // Reverb Pan + + // To interpolate the vector correctly we need to ensure that both the initial and final vectors are clamped to a length of 1.0f + StartVector = lpStart->vReverbPan; + FinalVector = lpFinish->vReverbPan; + + Clamp(&StartVector); + Clamp(&FinalVector); + + if (lpStart->vReverbPan.x == lpFinish->vReverbPan.x) + lpResult->vReverbPan.x = lpStart->vReverbPan.x; + else + lpResult->vReverbPan.x = FinalVector.x + (flInvRatio * (StartVector.x - FinalVector.x)); + + if (lpStart->vReverbPan.y == lpFinish->vReverbPan.y) + lpResult->vReverbPan.y = lpStart->vReverbPan.y; + else + lpResult->vReverbPan.y = FinalVector.y + (flInvRatio * (StartVector.y - FinalVector.y)); + + if (lpStart->vReverbPan.z == lpFinish->vReverbPan.z) + lpResult->vReverbPan.z = lpStart->vReverbPan.z; + else + lpResult->vReverbPan.z = FinalVector.z + (flInvRatio * (StartVector.z - FinalVector.z)); + + // Echo Time + if (lpStart->flEchoTime == lpFinish->flEchoTime) + lpResult->flEchoTime = lpStart->flEchoTime; + else + lpResult->flEchoTime = (float)exp( (log(lpStart->flEchoTime) * flInvRatio) + (log(lpFinish->flEchoTime) * flRatio) ); + + // Echo Depth + if (lpStart->flEchoDepth == lpFinish->flEchoDepth) + lpResult->flEchoDepth = lpStart->flEchoDepth; + else + lpResult->flEchoDepth = (lpStart->flEchoDepth * flInvRatio) + (lpFinish->flEchoDepth * flRatio); + + // Modulation Time + if (lpStart->flModulationTime == lpFinish->flModulationTime) + lpResult->flModulationTime = lpStart->flModulationTime; + else + lpResult->flModulationTime = (float)exp( (log(lpStart->flModulationTime) * flInvRatio) + (log(lpFinish->flModulationTime) * flRatio) ); + + // Modulation Depth + if (lpStart->flModulationDepth == lpFinish->flModulationDepth) + lpResult->flModulationDepth = lpStart->flModulationDepth; + else + lpResult->flModulationDepth = (lpStart->flModulationDepth * flInvRatio) + (lpFinish->flModulationDepth * flRatio); + + // Air Absorption HF + if (lpStart->flAirAbsorptionHF == lpFinish->flAirAbsorptionHF) + lpResult->flAirAbsorptionHF = lpStart->flAirAbsorptionHF; + else + lpResult->flAirAbsorptionHF = (lpStart->flAirAbsorptionHF * flInvRatio) + (lpFinish->flAirAbsorptionHF * flRatio); + + // HF Reference + if (lpStart->flHFReference == lpFinish->flHFReference) + lpResult->flHFReference = lpStart->flHFReference; + else + lpResult->flHFReference = (float)exp( (log(lpStart->flHFReference) * flInvRatio) + (log(lpFinish->flHFReference) * flRatio) ); + + // LF Reference + if (lpStart->flLFReference == lpFinish->flLFReference) + lpResult->flLFReference = lpStart->flLFReference; + else + lpResult->flLFReference = (float)exp( (log(lpStart->flLFReference) * flInvRatio) + (log(lpFinish->flLFReference) * flRatio) ); + + // Room Rolloff Factor + if (lpStart->flRoomRolloffFactor == lpFinish->flRoomRolloffFactor) + lpResult->flRoomRolloffFactor = lpStart->flRoomRolloffFactor; + else + lpResult->flRoomRolloffFactor = (lpStart->flRoomRolloffFactor * flInvRatio) + (lpFinish->flRoomRolloffFactor * flRatio); + + // Flags + lpResult->ulFlags = (lpStart->ulFlags & lpFinish->ulFlags); + + // Clamp Delays + if (lpResult->flReflectionsDelay > EAXLISTENER_MAXREFLECTIONSDELAY) + lpResult->flReflectionsDelay = EAXLISTENER_MAXREFLECTIONSDELAY; + + if (lpResult->flReverbDelay > EAXLISTENER_MAXREVERBDELAY) + lpResult->flReverbDelay = EAXLISTENER_MAXREVERBDELAY; + + return true; +} + + +/* + CheckEAX3LP + Checks that the parameters in the EAX 3 Listener Properties structure are in-range +*/ +bool CheckEAX3LP(LPEAXLISTENERPROPERTIES lpEAX3LP) +{ + if ( (lpEAX3LP->lRoom < EAXLISTENER_MINROOM) || (lpEAX3LP->lRoom > EAXLISTENER_MAXROOM) ) + return false; + + if ( (lpEAX3LP->lRoomHF < EAXLISTENER_MINROOMHF) || (lpEAX3LP->lRoomHF > EAXLISTENER_MAXROOMHF) ) + return false; + + if ( (lpEAX3LP->lRoomLF < EAXLISTENER_MINROOMLF) || (lpEAX3LP->lRoomLF > EAXLISTENER_MAXROOMLF) ) + return false; + + if ( (lpEAX3LP->ulEnvironment < EAXLISTENER_MINENVIRONMENT) || (lpEAX3LP->ulEnvironment > EAXLISTENER_MAXENVIRONMENT) ) + return false; + + if ( (lpEAX3LP->flEnvironmentSize < EAXLISTENER_MINENVIRONMENTSIZE) || (lpEAX3LP->flEnvironmentSize > EAXLISTENER_MAXENVIRONMENTSIZE) ) + return false; + + if ( (lpEAX3LP->flEnvironmentDiffusion < EAXLISTENER_MINENVIRONMENTDIFFUSION) || (lpEAX3LP->flEnvironmentDiffusion > EAXLISTENER_MAXENVIRONMENTDIFFUSION) ) + return false; + + if ( (lpEAX3LP->flDecayTime < EAXLISTENER_MINDECAYTIME) || (lpEAX3LP->flDecayTime > EAXLISTENER_MAXDECAYTIME) ) + return false; + + if ( (lpEAX3LP->flDecayHFRatio < EAXLISTENER_MINDECAYHFRATIO) || (lpEAX3LP->flDecayHFRatio > EAXLISTENER_MAXDECAYHFRATIO) ) + return false; + + if ( (lpEAX3LP->flDecayLFRatio < EAXLISTENER_MINDECAYLFRATIO) || (lpEAX3LP->flDecayLFRatio > EAXLISTENER_MAXDECAYLFRATIO) ) + return false; + + if ( (lpEAX3LP->lReflections < EAXLISTENER_MINREFLECTIONS) || (lpEAX3LP->lReflections > EAXLISTENER_MAXREFLECTIONS) ) + return false; + + if ( (lpEAX3LP->flReflectionsDelay < EAXLISTENER_MINREFLECTIONSDELAY) || (lpEAX3LP->flReflectionsDelay > EAXLISTENER_MAXREFLECTIONSDELAY) ) + return false; + + if ( (lpEAX3LP->lReverb < EAXLISTENER_MINREVERB) || (lpEAX3LP->lReverb > EAXLISTENER_MAXREVERB) ) + return false; + + if ( (lpEAX3LP->flReverbDelay < EAXLISTENER_MINREVERBDELAY) || (lpEAX3LP->flReverbDelay > EAXLISTENER_MAXREVERBDELAY) ) + return false; + + if ( (lpEAX3LP->flEchoTime < EAXLISTENER_MINECHOTIME) || (lpEAX3LP->flEchoTime > EAXLISTENER_MAXECHOTIME) ) + return false; + + if ( (lpEAX3LP->flEchoDepth < EAXLISTENER_MINECHODEPTH) || (lpEAX3LP->flEchoDepth > EAXLISTENER_MAXECHODEPTH) ) + return false; + + if ( (lpEAX3LP->flModulationTime < EAXLISTENER_MINMODULATIONTIME) || (lpEAX3LP->flModulationTime > EAXLISTENER_MAXMODULATIONTIME) ) + return false; + + if ( (lpEAX3LP->flModulationDepth < EAXLISTENER_MINMODULATIONDEPTH) || (lpEAX3LP->flModulationDepth > EAXLISTENER_MAXMODULATIONDEPTH) ) + return false; + + if ( (lpEAX3LP->flAirAbsorptionHF < EAXLISTENER_MINAIRABSORPTIONHF) || (lpEAX3LP->flAirAbsorptionHF > EAXLISTENER_MAXAIRABSORPTIONHF) ) + return false; + + if ( (lpEAX3LP->flHFReference < EAXLISTENER_MINHFREFERENCE) || (lpEAX3LP->flHFReference > EAXLISTENER_MAXHFREFERENCE) ) + return false; + + if ( (lpEAX3LP->flLFReference < EAXLISTENER_MINLFREFERENCE) || (lpEAX3LP->flLFReference > EAXLISTENER_MAXLFREFERENCE) ) + return false; + + if ( (lpEAX3LP->flRoomRolloffFactor < EAXLISTENER_MINROOMROLLOFFFACTOR) || (lpEAX3LP->flRoomRolloffFactor > EAXLISTENER_MAXROOMROLLOFFFACTOR) ) + return false; + + if (lpEAX3LP->ulFlags & EAXLISTENERFLAGS_RESERVED) + return false; + + return true; +} + +/* + Clamp + Clamps the length of the vector to 1.0f +*/ +void Clamp(EAXVECTOR *eaxVector) +{ + float flMagnitude; + float flInvMagnitude; + + flMagnitude = (float)sqrt((eaxVector->x*eaxVector->x) + (eaxVector->y*eaxVector->y) + (eaxVector->z*eaxVector->z)); + + if (flMagnitude <= 1.0f) + return; + + flInvMagnitude = 1.0f / flMagnitude; + + eaxVector->x *= flInvMagnitude; + eaxVector->y *= flInvMagnitude; + eaxVector->z *= flInvMagnitude; +} \ No newline at end of file diff --git a/CODE-mp/client/snd_local.h b/CODE-mp/client/snd_local.h index 3285df7..85c3ab8 100644 --- a/CODE-mp/client/snd_local.h +++ b/CODE-mp/client/snd_local.h @@ -8,6 +8,16 @@ #include "snd_public.h" #include "../mp3code/mp3struct.h" +// Open AL Specific +#include "openal\al.h" +#include "openal\alc.h" +#include +#include "eax\eax.h" +#include "eax\eaxman.h" + +// Added for Open AL to know when to mute all sounds (e.g when app. loses focus) +void S_MuteAllSounds(bool bMute); + #define PAINTBUFFER_SIZE 4096 // this is in samples #define SND_CHUNK_SIZE 1024 // samples @@ -54,9 +64,27 @@ typedef struct sfx_s { float fVolRange; // used to set the highest volume this sample has at load time - used for lipsynching int iLastLevelUsedOn; // used for cacheing purposes struct sfx_s *next; // only used because of hash table when registering + + // Open AL + ALuint Buffer; } sfx_t; +// Open AL specific +typedef struct +{ + ALuint BufferID; + ALuint Status; + char *Data; +} STREAMINGBUFFER; + +#define NUM_STREAMING_BUFFERS 4 +#define STREAMING_BUFFER_SIZE 4608 // 4 decoded MP3 frames + +#define QUEUED 1 +#define UNQUEUED 2 + + typedef struct { int channels; int samples; // mono samples in buffer @@ -80,6 +108,10 @@ typedef struct loopSound_s { float oldDopplerScale; int framenum; + // Open AL + bool bProcessed; + bool bPlaying; + bool bRelative; } loopSound_t; typedef struct @@ -104,6 +136,15 @@ typedef struct byte MP3SlidingDecodeBuffer[50000/*12000*/]; // typical back-request = -3072, so roughly double is 6000 (safety), then doubled again so the 6K pos is in the middle of the buffer) int iMP3SlidingDecodeWritePos; int iMP3SlidingDecodeWindowPos; + + // Open AL specific + bool bLooping; // Signifies if this channel / source is playing a looping sound + bool bProcessed; // Signifies if this channel / source has been processed + bool bStreaming; // Set to true if the data needs to be streamed (MP3 or dialogue) + STREAMINGBUFFER buffers[NUM_STREAMING_BUFFERS]; // AL Buffers for streaming + ALuint alSource; // Open AL Source + bool bPlaying; // Set to true when a sound is playing on this channel / source + int iStartTime; // Time playback of Source begins } channel_t; diff --git a/CODE-mp/client/snd_mem.cpp b/CODE-mp/client/snd_mem.cpp index cd62307..58ae3ab 100644 --- a/CODE-mp/client/snd_mem.cpp +++ b/CODE-mp/client/snd_mem.cpp @@ -15,6 +15,9 @@ #include "snd_mp3.h" +// Open AL +extern int s_UseOpenAL; + /* =============================================================================== @@ -230,30 +233,48 @@ static qboolean S_LoadSound_FileLoadAndNameAdjuster(char *psFilename, byte **pDa if (com_buildScript->integer) { fileHandle_t hFile; + //German strncpy(psVoice,"chr_d",5); // same number of letters as "chars" - FS_FOpenFileRead(psFilename, &hFile, qfalse); //cache this file + FS_FOpenFileRead(psFilename, &hFile, qfalse); //cache the wav if (!hFile) { strcpy(&psFilename[iNameStrlen-3],"mp3"); //not there try mp3 - FS_FOpenFileRead(psFilename, &hFile, qfalse); //cache this file + FS_FOpenFileRead(psFilename, &hFile, qfalse); //cache the mp3 } if (hFile) { FS_FCloseFile(hFile); } - strcpy(&psFilename[iNameStrlen-3],"wav"); + strcpy(&psFilename[iNameStrlen-3],"wav"); //put it back to wav + //French strncpy(psVoice,"chr_f",5); // same number of letters as "chars" - FS_FOpenFileRead(psFilename, &hFile, qfalse); //cahce this file + FS_FOpenFileRead(psFilename, &hFile, qfalse); //cache the wav if (!hFile) { strcpy(&psFilename[iNameStrlen-3],"mp3"); //not there try mp3 - FS_FOpenFileRead(psFilename, &hFile, qfalse); //cache this file + FS_FOpenFileRead(psFilename, &hFile, qfalse); //cache the mp3 } if (hFile) { FS_FCloseFile(hFile); } + strcpy(&psFilename[iNameStrlen-3],"wav"); //put it back to wav + + //Spanish + strncpy(psVoice,"chr_e",5); // same number of letters as "chars" + FS_FOpenFileRead(psFilename, &hFile, qfalse); //cache the wav + if (!hFile) + { + strcpy(&psFilename[iNameStrlen-3],"mp3"); //not there try mp3 + FS_FOpenFileRead(psFilename, &hFile, qfalse); //cache the mp3 + } + if (hFile) + { + FS_FCloseFile(hFile); + } + strcpy(&psFilename[iNameStrlen-3],"wav"); //put it back to wav + strncpy(psVoice,"chars",5); //put it back to chars } @@ -264,11 +285,14 @@ static qboolean S_LoadSound_FileLoadAndNameAdjuster(char *psFilename, byte **pDa { strncpy(psVoice,"chr_d",5); // same number of letters as "chars" } - else - if (s_language && stricmp("FRANCAIS",s_language->string)==0) + else if (s_language && stricmp("FRANCAIS",s_language->string)==0) { strncpy(psVoice,"chr_f",5); // same number of letters as "chars" } + else if (s_language && stricmp("ESPANOL",s_language->string)==0) + { + strncpy(psVoice,"chr_e",5); // same number of letters as "chars" + } else { psVoice = NULL; // use this ptr as a flag as to whether or not we substituted with a foreign version @@ -340,6 +364,7 @@ static qboolean S_LoadSound_Actual( sfx_t *sfx ) short *samples; wavinfo_t info; int size; + ALuint Buffer; // player specific sounds are never directly loaded... // @@ -406,6 +431,27 @@ static qboolean S_LoadSound_Actual( sfx_t *sfx ) S_LoadSound_Finalize(&info,sfx,pbUnpackBuffer); + // Open AL + if (s_UseOpenAL) + { + // Clear Open AL Error state + alGetError(); + + // Generate AL Buffer + alGenBuffers(1, &Buffer); + if (alGetError() == AL_NO_ERROR) + { + // Copy audio data to AL Buffer + alBufferData(Buffer, AL_FORMAT_MONO16, sfx->pSoundData, sfx->iSoundLengthInSamples*2, 22050); + if (alGetError() == AL_NO_ERROR) + { + sfx->Buffer = Buffer; + Z_Free(sfx->pSoundData); + sfx->pSoundData = NULL; + } + } + } + Z_Free(pbUnpackBuffer); } } @@ -452,6 +498,28 @@ static qboolean S_LoadSound_Actual( sfx_t *sfx ) sfx->pSoundData = NULL; ResampleSfx( sfx, info.rate, info.width, data + info.dataofs ); + // Open AL + if (s_UseOpenAL) + { + // Clear Open AL Error State + alGetError(); + + // Generate AL Buffer + alGenBuffers(1, &Buffer); + if (alGetError() == AL_NO_ERROR) + { + // Copy audio data to AL Buffer + alBufferData(Buffer, AL_FORMAT_MONO16, sfx->pSoundData, sfx->iSoundLengthInSamples*2, 22050); + if (alGetError() == AL_NO_ERROR) + { + // Store AL Buffer in sfx struct, and release sample data + sfx->Buffer = Buffer; + Z_Free(sfx->pSoundData); + sfx->pSoundData = NULL; + } + } + } + Z_Free(samples); } diff --git a/CODE-mp/client/snd_mp3.cpp b/CODE-mp/client/snd_mp3.cpp index a348adc..635a79a 100644 --- a/CODE-mp/client/snd_mp3.cpp +++ b/CODE-mp/client/snd_mp3.cpp @@ -523,10 +523,18 @@ qboolean MP3_ReadSpecialTagInfo(byte *pbLoadedFile, int iLoadedFileLen, // (in) #define FUZZY_AMOUNT (5*1024) // so it has to be significantly over, not just break even, because of // the xtra CPU time versus memory saving +#define OPENAL_FUZZY_AMOUNT (100*1024) // Speed up CPU time even more, at the cost of a bit more memory of course :) + cvar_t* cv_MP3overhead = NULL; void MP3_InitCvars(void) { cv_MP3overhead = Cvar_Get("s_mp3overhead", va("%d", sizeof(MP3STREAM) + FUZZY_AMOUNT), CVAR_ARCHIVE ); + + extern int s_UseOpenAL; + if (s_UseOpenAL) + { + cv_MP3overhead->value += OPENAL_FUZZY_AMOUNT; + } } diff --git a/CODE-mp/client/snd_public.h b/CODE-mp/client/snd_public.h index 67b685b..237af45 100644 --- a/CODE-mp/client/snd_public.h +++ b/CODE-mp/client/snd_public.h @@ -47,5 +47,5 @@ void S_DisplayFreeMemory(void); void S_ClearSoundBuffer( void ); -void SNDDMA_Activate( void ); +void SNDDMA_Activate( qboolean bAppActive ); diff --git a/CODE-mp/client/vssver.scc b/CODE-mp/client/vssver.scc index bb36b37..bbb0877 100644 Binary files a/CODE-mp/client/vssver.scc and b/CODE-mp/client/vssver.scc differ diff --git a/CODE-mp/game/ai_main.c b/CODE-mp/game/ai_main.c index 3631713..3af71fc 100644 --- a/CODE-mp/game/ai_main.c +++ b/CODE-mp/game/ai_main.c @@ -61,6 +61,7 @@ boteventtracker_t gBotEventTracker[MAX_CLIENTS]; //rww - new bot cvars.. vmCvar_t bot_forcepowers; vmCvar_t bot_forgimmick; +vmCvar_t bot_honorableduelacceptance; #ifdef _DEBUG vmCvar_t bot_nogoals; vmCvar_t bot_debugmessages; @@ -5686,6 +5687,7 @@ void StandardBotAI(bot_state_t *bs, float thinktime) } trap_Cvar_Update(&bot_forgimmick); + trap_Cvar_Update(&bot_honorableduelacceptance); if (bot_forgimmick.integer) { @@ -5693,6 +5695,11 @@ void StandardBotAI(bot_state_t *bs, float thinktime) bs->currentEnemy = NULL; bs->wpDestination = NULL; bs->wpDirection = 0; + + if (bot_forgimmick.integer == 2) + { //for debugging saber stuff, this is handy + trap_EA_Attack(bs->client); + } return; } @@ -6044,42 +6051,43 @@ void StandardBotAI(bot_state_t *bs, float thinktime) } } - /* - if (bs->currentEnemy && bs->currentEnemy->client && - bs->cur_ps.weapon == WP_SABER && - g_privateDuel.integer && - bs->frame_Enemy_Vis && - bs->frame_Enemy_Len < 400 && - bs->currentEnemy->client->ps.weapon == WP_SABER && - bs->currentEnemy->client->ps.saberHolstered) + if (bot_honorableduelacceptance.integer) { - vec3_t e_ang_vec; + if (bs->currentEnemy && bs->currentEnemy->client && + bs->cur_ps.weapon == WP_SABER && + g_privateDuel.integer && + bs->frame_Enemy_Vis && + bs->frame_Enemy_Len < 400 && + bs->currentEnemy->client->ps.weapon == WP_SABER && + bs->currentEnemy->client->ps.saberHolstered) + { + vec3_t e_ang_vec; - VectorSubtract(bs->currentEnemy->client->ps.origin, bs->eye, e_ang_vec); + VectorSubtract(bs->currentEnemy->client->ps.origin, bs->eye, e_ang_vec); - if (InFieldOfVision(bs->viewangles, 100, e_ang_vec)) - { //Our enemy has his saber holstered and has challenged us to a duel, so challenge him back - if (!bs->cur_ps.saberHolstered) - { - Cmd_ToggleSaber_f(&g_entities[bs->client]); - } - else - { - if (bs->currentEnemy->client->ps.duelIndex == bs->client && - bs->currentEnemy->client->ps.duelTime > level.time && - !bs->cur_ps.duelInProgress) + if (InFieldOfVision(bs->viewangles, 100, e_ang_vec)) + { //Our enemy has his saber holstered and has challenged us to a duel, so challenge him back + if (!bs->cur_ps.saberHolstered) { - Cmd_EngageDuel_f(&g_entities[bs->client]); + Cmd_ToggleSaber_f(&g_entities[bs->client]); + } + else + { + if (bs->currentEnemy->client->ps.duelIndex == bs->client && + bs->currentEnemy->client->ps.duelTime > level.time && + !bs->cur_ps.duelInProgress) + { + Cmd_EngageDuel_f(&g_entities[bs->client]); + } } - } - bs->doAttack = 0; - bs->doAltAttack = 0; - bs->botChallengingTime = level.time + 100; - bs->beStill = level.time + 100; + bs->doAttack = 0; + bs->doAltAttack = 0; + bs->botChallengingTime = level.time + 100; + bs->beStill = level.time + 100; + } } } - */ //Apparently this "allows you to cheese" when fighting against bots. I'm not sure why you'd want to con bots //into an easy kill, since they're bots and all. But whatever. @@ -6914,7 +6922,7 @@ void StandardBotAI(bot_state_t *bs, float thinktime) else { #endif - if (bot_forcepowers.integer) + if (bot_forcepowers.integer && !g_forcePowerDisable.integer) { trap_EA_ForcePower(bs->client); } @@ -7006,6 +7014,7 @@ int BotAISetup( int restart ) { //rww - new bot cvars.. trap_Cvar_Register(&bot_forcepowers, "bot_forcepowers", "1", CVAR_CHEAT); trap_Cvar_Register(&bot_forgimmick, "bot_forgimmick", "0", CVAR_CHEAT); + trap_Cvar_Register(&bot_honorableduelacceptance, "bot_honorableduelacceptance", "0", CVAR_CHEAT); #ifdef _DEBUG trap_Cvar_Register(&bot_nogoals, "bot_nogoals", "0", CVAR_CHEAT); trap_Cvar_Register(&bot_debugmessages, "bot_debugmessages", "0", CVAR_CHEAT); diff --git a/CODE-mp/game/ai_main.h b/CODE-mp/game/ai_main.h index d504062..1effde6 100644 --- a/CODE-mp/game/ai_main.h +++ b/CODE-mp/game/ai_main.h @@ -374,6 +374,7 @@ char *ConcatArgs( int start ); extern vmCvar_t bot_forcepowers; extern vmCvar_t bot_forgimmick; +extern vmCvar_t bot_honorableduelacceptance; #ifdef _DEBUG extern vmCvar_t bot_nogoals; extern vmCvar_t bot_debugmessages; diff --git a/CODE-mp/game/anims.h b/CODE-mp/game/anims.h index 45cc978..28eabc6 100644 --- a/CODE-mp/game/anims.h +++ b/CODE-mp/game/anims.h @@ -8,8 +8,9 @@ typedef enum //# animNumber_e //================================================= //ANIMS IN WHICH UPPER AND LOWER OBJECTS ARE IN MD3 //================================================= + BOTH_1CRUFTFORGIL = 0, //# G2 cannot have a reverse anim at beginning of file //# #sep BOTH_ DEATHS - BOTH_DEATH1 = 0, //# First Death anim + BOTH_DEATH1, //# First Death anim BOTH_DEATH2, //# Second Death anim BOTH_DEATH3, //# Third Death anim BOTH_DEATH4, //# Fourth Death anim @@ -23,13 +24,17 @@ typedef enum //# animNumber_e BOTH_DEATH12, //# BOTH_DEATH13, //# BOTH_DEATH14, //# - BOTH_DEATH14_UNGRIP, //# Desann's end death (cin #35) - BOTH_DEATH14_SITUP, //# Tavion sitting up after having been thrown (cin #23) BOTH_DEATH15, //# BOTH_DEATH16, //# BOTH_DEATH17, //# BOTH_DEATH18, //# BOTH_DEATH19, //# + BOTH_DEATH20, //# + BOTH_DEATH21, //# + BOTH_DEATH22, //# + BOTH_DEATH23, //# + BOTH_DEATH24, //# + BOTH_DEATH25, //# BOTH_DEATHFORWARD1, //# First Death in which they get thrown forward BOTH_DEATHFORWARD2, //# Second Death in which they get thrown forward @@ -73,6 +78,12 @@ typedef enum //# animNumber_e BOTH_DEAD17, //# BOTH_DEAD18, //# BOTH_DEAD19, //# + BOTH_DEAD20, //# + BOTH_DEAD21, //# + BOTH_DEAD22, //# + BOTH_DEAD23, //# + BOTH_DEAD24, //# + BOTH_DEAD25, //# BOTH_DEADFORWARD1, //# First thrown forward death finished pose BOTH_DEADFORWARD2, //# Second thrown forward death finished pose BOTH_DEADBACKWARD1, //# First thrown backward death finished pose @@ -124,6 +135,7 @@ typedef enum //# animNumber_e //# #sep BOTH_ ATTACKS BOTH_ATTACK1, //# Attack with stun baton BOTH_ATTACK2, //# Attack with one-handed pistol + BOTH_ATTACK2IDLE1, //# Idle with one-handed pistol BOTH_ATTACK3, //# Attack with blaster rifle BOTH_ATTACK4, //# Attack with disruptor BOTH_ATTACK5, //# Attack with bow caster @@ -608,19 +620,28 @@ typedef enum //# animNumber_e BOTH_CWCIRCLELOCK, //# BOTH_CCWCIRCLELOCK, //# + BOTH_SABERFAST_STANCE, + BOTH_SABERSLOW_STANCE, + BOTH_A2_STABBACK1, //# Stab saber backward + BOTH_ATTACK_BACK, //# Swing around backwards and attack + BOTH_JUMPFLIPSLASHDOWN1,//# + BOTH_JUMPFLIPSTABDOWN,//# + BOTH_FORCELEAP2_T__B_,//# + BOTH_LUNGE2_B__T_,//# + BOTH_CROUCHATTACKBACK1,//# //# #sep BOTH_ STANDING BOTH_STAND1, //# Standing idle, no weapon, hands down - BOTH_STAND1_RANDOM1, //# Random standing idle - BOTH_STAND1_RANDOM2, //# Random standing idle - BOTH_STAND2, //# Standing idle with a weapon - BOTH_STAND2_RANDOM1, //# Random standing idle - BOTH_STAND2_RANDOM2, //# Random standing idle - BOTH_STAND2_RANDOM3, //# Random standing idle - BOTH_STAND2_RANDOM4, //# Random standing idle - BOTH_STAND3, //# Standing hands behind back, at ease, etc. + BOTH_STAND1IDLE1, //# Random standing idle + BOTH_STAND2, //# Standing idle with a saber + BOTH_STAND2IDLE1, //# Random standing idle + BOTH_STAND2IDLE2, //# Random standing idle + BOTH_STAND3, //# Standing idle with 2-handed weapon + BOTH_STAND3IDLE1, //# Random standing idle BOTH_STAND4, //# hands clasp behind back + BOTH_STAND4IDLE1, //# Random standing idle BOTH_STAND5, //# standing idle, no weapon, hand down, back straight + BOTH_STAND5IDLE1, //# Random standing idle BOTH_STAND6, //# one handed, gun at side, relaxed stand BOTH_STAND7, //# both hands on hips (female) BOTH_STAND8, //# both hands on hips (male) @@ -639,8 +660,21 @@ typedef enum //# animNumber_e BOTH_STAND5_REELO, //# Reelo in his stand5 position (cin #18) BOTH_STAND1TOSTAND5, //# Transition from stand1 to stand5 BOTH_STAND5TOSTAND1, //# Transition from stand5 to stand1 + BOTH_STAND5TOAIM, //# Transition of Kye aiming his gun at Desann (cin #9) + BOTH_STAND5STARTLEDLOOKLEFT, //# Kyle turning to watch the bridge drop (cin #9) + BOTH_STARTLEDLOOKLEFTTOSTAND5, //# Kyle returning to stand 5 from watching the bridge drop (cin #9) BOTH_STAND5TOSTAND8, //# Transition from stand5 to stand8 + BOTH_STAND7TOSTAND8, //# Tavion putting hands on back of chair (cin #11) BOTH_STAND8TOSTAND5, //# Transition from stand8 to stand5 + BOTH_STAND5SHIFTWEIGHT, //# Weightshift from stand5 to side and back to stand5 + BOTH_STAND5SHIFTWEIGHTSTART, //# From stand5 to side + BOTH_STAND5SHIFTWEIGHTSTOP, //# From side to stand5 + BOTH_STAND5TURNLEFTSTART, //# Start turning left from stand5 + BOTH_STAND5TURNLEFTSTOP, //# Stop turning left from stand5 + BOTH_STAND5TURNRIGHTSTART, //# Start turning right from stand5 + BOTH_STAND5TURNRIGHTSTOP, //# Stop turning right from stand5 + BOTH_STAND5LOOK180LEFTSTART, //# Start looking over left shoulder (cin #17) + BOTH_STAND5LOOK180LEFTSTOP, //# Stop looking over left shoulder (cin #17) BOTH_CONSOLE1START, //# typing at a console BOTH_CONSOLE1, //# typing at a console @@ -648,6 +682,8 @@ typedef enum //# animNumber_e BOTH_CONSOLE2START, //# typing at a console with comm link in hand (cin #5) BOTH_CONSOLE2, //# typing at a console with comm link in hand (cin #5) BOTH_CONSOLE2STOP, //# typing at a console with comm link in hand (cin #5) + BOTH_CONSOLE2HOLDCOMSTART, //# lean in to type at console while holding comm link in hand (cin #5) + BOTH_CONSOLE2HOLDCOMSTOP, //# lean away after typing at console while holding comm link in hand (cin #5) BOTH_GUARD_LOOKAROUND1, //# Cradling weapon and looking around BOTH_GUARD_IDLE1, //# Cradling weapon and standing @@ -655,6 +691,51 @@ typedef enum //# animNumber_e BOTH_GESTURE1, //# Generic gesture, non-specific BOTH_GESTURE2, //# Generic gesture, non-specific BOTH_GESTURE3, //# Generic gesture, non-specific + BOTH_WALK1TALKCOMM1, //# Talking into coom link while walking + BOTH_TALK1, //# Generic talk anim + BOTH_TALK2, //# Generic talk anim + BOTH_TALKCOMM1START, //# Start talking into a comm link + BOTH_TALKCOMM1, //# Talking into a comm link + BOTH_TALKCOMM1STOP, //# Stop talking into a comm link + BOTH_TALKGESTURE1, //# Generic talk anim + BOTH_TALKGESTURE2, //# Generic talk anim + BOTH_TALKGESTURE3, //# Generic talk anim + BOTH_TALKGESTURE4START, //# Beginning talk anim 4 + BOTH_TALKGESTURE4, //# Talk gesture 4 + BOTH_TALKGESTURE4STOP, //# Ending talk anim 4 + BOTH_TALKGESTURE5START, //# Start hand on chin + BOTH_TALKGESTURE5, //# Hand on chin + BOTH_TALKGESTURE5STOP, //# Stop hand on chin + BOTH_TALKGESTURE6START, //# Starting Motions to self + BOTH_TALKGESTURE6, //# Pointing at self + BOTH_TALKGESTURE6STOP, //# Ending Motions to self + BOTH_TALKGESTURE7START, //# Start touches Kyle on shoulder + BOTH_TALKGESTURE7, //# Hold touches Kyle on shoulder + BOTH_TALKGESTURE7STOP, //# Ending touches Kyle on shoulder + BOTH_TALKGESTURE8START, //# Lando's chin hold + BOTH_TALKGESTURE8, //# Lando's chin hold + BOTH_TALKGESTURE8STOP, //# Lando's chin hold + BOTH_TALKGESTURE9, //# Same as gesture 2 but with the right hand + BOTH_TALKGESTURE10, //# Shoulder shrug + BOTH_TALKGESTURE11START, //# Arms folded across chest + BOTH_TALKGESTURE11STOP, //# Arms folded across chest + BOTH_TALKGESTURE12, //# Tavion taunting Kyle + BOTH_TALKGESTURE13START, //# Luke warning Kyle + BOTH_TALKGESTURE13, //# Luke warning Kyle + BOTH_TALKGESTURE13STOP, //# Luke warning Kyle + BOTH_TALKGESTURE14, //# Luke gesturing to Kyle + BOTH_TALKGESTURE15START, //# Desann taunting Kyle + BOTH_TALKGESTURE15, //# Desann taunting Kyle + BOTH_TALKGESTURE15STOP, //# Desann taunting Kyle + BOTH_TALKGESTURE16, //# Bartender gesture cin #15 + BOTH_TALKGESTURE17, //# Bartender gesture cin #15 + BOTH_TALKGESTURE18, //# Bartender gesture cin #15 + BOTH_TALKGESTURE19START, //# Desann lifting his arm "Join me" (cin #34) + BOTH_TALKGESTURE19STOP, //# Desann lifting his arm "Join me" (cin #34) + BOTH_TALKGESTURE20START, //# Kyle lifting his arm "Join us" (cin #34) + BOTH_TALKGESTURE21, //# generic talk gesture from stand3 + BOTH_TALKGESTURE22, //# generic talk gesture from stand3 + BOTH_TALKGESTURE23, //# generic talk gesture from stand3 BOTH_PAUSE1START, //# Luke pauses to warn Kyle (cin #24) start BOTH_PAUSE1STOP, //# Luke pauses to warn Kyle (cin #24) stop @@ -671,6 +752,8 @@ typedef enum //# animNumber_e BOTH_SITHEADTILTRSTOP, //# Head tilt to right from seated position BOTH_SITHEADNOD, //# Head shake YES from seated position BOTH_SITHEADSHAKE, //# Head shake NO from seated position + BOTH_SIT2HEADTILTLSTART, //# Head tilt to left from seated position 2 + BOTH_SIT2HEADTILTLSTOP, //# Head tilt to left from seated position 2 BOTH_REACH1START, //# Monmothma reaching for crystal BOTH_REACH1STOP, //# Monmothma reaching for crystal @@ -685,13 +768,6 @@ typedef enum //# animNumber_e BOTH_EXAMINE3, //# Hold Lando looking around corner BOTH_EXAMINE3STOP, //# End Lando looking around corner - BOTH_THROW1START, //# Kyle thrown to the right - BOTH_THROW1, //# Kyle thrown to the right - BOTH_THROW1STOP, //# Kyle thrown to the right - BOTH_THROW2START, //# Kyle thrown to the left - BOTH_THROW2, //# Kyle thrown to the left - BOTH_THROW3, //# Kyle thrown backwards in cin #9 - BOTH_LEANLEFT2START, //# Start leaning left in chair BOTH_LEANLEFT2STOP, //# Stop leaning left in chair BOTH_LEANRIGHT3START, //# Start Lando leaning on wall @@ -727,6 +803,26 @@ typedef enum //# animNumber_e BOTH_LAUGH1STOP, //# Reelo laughing (cin #18) BOTH_ESCAPEPOD_LEAVE1, //# Kyle leaving escape pod (cin #33) BOTH_ESCAPEPOD_LEAVE2, //# Jan leaving escape pod (cin #33) + BOTH_HUGGER1, //# Kyle hugging Jan (cin #29) + BOTH_HUGGERSTOP1, //# Kyle stop hugging Jan but don't let her go (cin #29) + BOTH_HUGGERSTOP2, //# Kyle let go of Jan and step back (cin #29) + BOTH_HUGGEE1, //# Jan being hugged (cin #29) + BOTH_HUGGEESTOP1, //# Jan stop being hugged but don't let go (cin #29) + BOTH_HUGGEESTOP2, //# Jan released from hug (cin #29) + BOTH_KISSER1, //# Temp until the Kiss anim gets split up + BOTH_KISSER1START1, //# Kyle start kissing Jan + BOTH_KISSER1START2, //# Kyle start kissing Jan + BOTH_KISSER1LOOP, //# Kyle loop kissing Jan + BOTH_KISSER1STOP, //# Temp until the Kiss anim gets split up + BOTH_KISSER1STOP1, //# Kyle stop kissing but don't let go + BOTH_KISSER1STOP2, //# Kyle step back from Jan + BOTH_KISSEE1, //# Temp until the Kiss anim gets split up + BOTH_KISSEE1START1, //# Jan start being kissed + BOTH_KISSEE1START2, //# Jan start being kissed + BOTH_KISSEE1LOOP, //# Jan loop being kissed + BOTH_KISSEE1STOP, //# Temp until the Kiss anim gets split up + BOTH_KISSEE1STOP1, //# Jan stop being kissed but don't let go + BOTH_KISSEE1STOP2, //# Jan wait for Kyle to step back BOTH_BARTENDER_IDLE1, //# Bartender idle in cin #15 BOTH_BARTENDER_THROW1, //# Bartender throws glass in cin #15 BOTH_BARTENDER_COWERSTART, //# Start of Bartender raising both hands up in surrender (cin #16) @@ -736,6 +832,7 @@ typedef enum //# animNumber_e BOTH_THREATEN1, //# Kyle threatening Bartender with lightsaber (cin #16) BOTH_RADIO_ONOFF, //# Mech Galak turning on his suit radio (cin #32) BOTH_TRIUMPHANT1START, //# Mech Galak raising his arms in victory (cin #32) + BOTH_TRIUMPHANT1STARTGESTURE, //# Mech Galak raising his arms in victory (cin #32) BOTH_TRIUMPHANT1STOP, //# Mech Galak lowering his arms in victory (cin #32) BOTH_SABERTHROW1START, //# Desann throwing his light saber (cin #26) @@ -759,6 +856,8 @@ typedef enum //# animNumber_e BOTH_SIT2TO3, //# Trans from sit2 to sit3? BOTH_SIT2TOSTAND5, //# Transition from sit 2 to stand 5 + BOTH_STAND5TOSIT2, //# Transition from stand 5 to sit 2 + BOTH_SIT2TOSIT4, //# Trans from sit2 to sit4 (cin #12) Luke leaning back from lotus position. BOTH_SIT3TO1, //# Trans from sit3 to sit1? BOTH_SIT3TO2, //# Trans from sit3 to sit2? BOTH_SIT3TOSTAND5, //# transition from sit 3 to stand 5 @@ -781,21 +880,20 @@ typedef enum //# animNumber_e BOTH_CROUCH2TOSTAND1, //# going from crouch2 to stand1 BOTH_CROUCH3, //# Desann crouching down to Kyle (cin 9) BOTH_UNCROUCH3, //# Desann uncrouching down to Kyle (cin 9) + BOTH_CROUCH4, //# Slower version of crouch1 for cinematics + BOTH_UNCROUCH4, //# Slower version of uncrouch1 for cinematics BOTH_GET_UP1, //# Get up from the ground, face down BOTH_GET_UP2, //# Get up from the ground, face up - BOTH_COCKPIT_CONSOLE1, //# work console1 while sitting in a cockpit. - BOTH_COCKPIT_CONSOLE2, //# work console2 while sitting in a cockpit. BOTH_COCKPIT_SIT, //# sit in a cockpit. BOTH_GUNSIT1, //# sitting on an emplaced gun. + BOTH_DEATH14_UNGRIP, //# Desann's end death (cin #35) + BOTH_DEATH14_SITUP, //# Tavion sitting up after having been thrown (cin #23) BOTH_KNEES1, //# Tavion on her knees BOTH_KNEES2, //# Tavion on her knees looking down BOTH_KNEES2TO1, //# Transition of KNEES2 to KNEES1 - BOTH_STRUGGLE1START, //# Kyle struggling under crate - BOTH_STRUGGLE1, //# Kyle struggling under crate - BOTH_STRUGGLE1STOP, //# Kyle struggling under crate BOTH_RUMMAGE1START, //# Kyle rummaging for crystal (cin 2) BOTH_RUMMAGE1, //# Kyle rummaging for crystal (cin 2) BOTH_RUMMAGE1STOP, //# Kyle rummaging for crystal (cin 2) @@ -811,6 +909,9 @@ typedef enum //# animNumber_e BOTH_WALK5, //# Tavion taunting Kyle (cin 22) BOTH_WALK6, //# Slow walk for Luke (cin 12) BOTH_WALK7, //# Fast walk + BOTH_WALK8, //# Normal walk with hands behind back (Luke in cin#12) + BOTH_WALK9, //# Lando walk (cin #17) + BOTH_WALK10, //# Lando walk (cin #17) BOTH_WALKTORUN1, //# transition from walk to run BOTH_RUN1, //# Full run BOTH_RUN1START, //# Start into full run1 @@ -823,10 +924,12 @@ typedef enum //# animNumber_e BOTH_RUNSTRAFE_RIGHT1, //# Sidestep right, should loop BOTH_TURN_LEFT1, //# Turn left, should loop BOTH_TURN_RIGHT1, //# Turn right, should loop + BOTH_TURNSTAND1, //# Turn from STAND1 position BOTH_TURNSTAND2, //# Turn from STAND2 position BOTH_TURNSTAND3, //# Turn from STAND3 position BOTH_TURNSTAND4, //# Turn from STAND4 position BOTH_TURNSTAND5, //# Turn from STAND5 position + BOTH_TURNCROUCH1, //# Turn from CROUCH1 position BOTH_RUNAWAY1, //# Running scared BOTH_SWIM1, //# Swimming @@ -897,16 +1000,7 @@ typedef enum //# animNumber_e BOTH_DIVE1, //# Dive! - BOTH_SABERFAST_STANCE, - BOTH_SABERSLOW_STANCE, BOTH_ENGAGETAUNT, - BOTH_A2_STABBACK1, //# Stab saber backward - BOTH_ATTACK_BACK, //# Swing around backwards and attack - BOTH_JUMPFLIPSLASHDOWN1,//# - BOTH_JUMPFLIPSTABDOWN,//# - BOTH_FORCELEAP2_T__B_,//# - BOTH_LUNGE2_B__T_,//# - BOTH_CROUCHATTACKBACK1,//# BOTH_ARIAL_LEFT, //# BOTH_ARIAL_RIGHT, //# BOTH_CARTWHEEL_LEFT, //# @@ -962,10 +1056,6 @@ typedef enum //# animNumber_e BOTH_ARIAL_F1,//# BOTH_BUTTERFLY_FR1,//# BOTH_BUTTERFLY_FL1,//# - BOTH_POSE1,//# - BOTH_POSE2,//# - BOTH_POSE3,//# - BOTH_POSE4,//# //# #sep BOTH_ MISC MOVEMENT BOTH_HIT1, //# Kyle hit by crate in cin #9 @@ -998,12 +1088,7 @@ typedef enum //# animNumber_e //# #sep BOTH_ SWIMMING BOTH_SWIM_IDLE1, //# Swimming Idle 1 - BOTH_SWIMFORWARDSTART, //# Swim forward start BOTH_SWIMFORWARD, //# Swim forward loop - BOTH_SWIMFORWARDSTOP, //# Swim forward end - BOTH_SWIMBACKWARDSTART, //# Swim backward start - BOTH_SWIMBACKWARD, //# Swim backward loop - BOTH_SWIMBACKWARDSTOP, //# Swim backward end //# #sep BOTH_ LYING BOTH_LIE_DOWN1, //# From a stand position, get down on ground, face down @@ -1029,6 +1114,26 @@ typedef enum //# animNumber_e BOTH_PROPUP1, //# Kyle getting up from having been knocked down (cin #9 end) BOTH_CRAWLBACK1, //# Lying on back, crawling backwards with elbows BOTH_SITWALL1, //# Sitting against a wall + BOTH_SLEEP1, //# laying on back-rknee up-rhand on torso + BOTH_SLEEP2, //# on floor-back against wall-arms crossed + BOTH_SLEEP3, //# Sleeping in a chair + BOTH_SLEEP4, //# Sleeping slumped over table + BOTH_SLEEP5, //# Laying on side sleeping on flat sufrace + BOTH_SLEEP6START, //# Kyle leaning back to sleep (cin 20) + BOTH_SLEEP6STOP, //# Kyle waking up and shaking his head (cin 21) + BOTH_SLEEP1GETUP, //# alarmed and getting up out of sleep1 pose to stand + BOTH_SLEEP1GETUP2, //# + BOTH_SLEEP2GETUP, //# alarmed and getting up out of sleep2 pose to stand + BOTH_SLEEP3GETUP, //# alarmed and getting up out of sleep3 pose to stand + BOTH_SLEEP3DEATH, //# death in chair, from sleep3 idle + BOTH_SLEEP3DEAD, //# death in chair, from sleep3 idle + + BOTH_SLEEP_IDLE1, //# rub face and nose while asleep from sleep pose 1 + BOTH_SLEEP_IDLE2, //# shift position while asleep - stays in sleep2 + BOTH_SLEEP_IDLE3, //# Idle anim from sleep pose 3 + BOTH_SLEEP_IDLE4, //# Idle anim from sleep pose 4 + BOTH_SLEEP1_NOSE, //# Scratch nose from SLEEP1 pose + BOTH_SLEEP2_SHIFT, //# Shift in sleep from SLEEP2 pose BOTH_RESTRAINED1, //# Telsia tied to medical table BOTH_RESTRAINED1POINT, //# Telsia tied to medical table pointing at Munro BOTH_LIFTED1, //# Fits with BOTH_LIFT1, lifted on shoulder @@ -1060,6 +1165,7 @@ typedef enum //# animNumber_e BOTH_MINDTRICK1, //# Use off-hand to do mind trick BOTH_MINDTRICK2, //# Use off-hand to do distraction BOTH_FORCELIGHTNING, //# Use off-hand to do lightning + BOTH_FORCELIGHTNING_START, //# Use off-hand to do lightning - start BOTH_FORCELIGHTNING_HOLD, //# Use off-hand to do lightning - hold BOTH_FORCELIGHTNING_RELEASE,//# Use off-hand to do lightning - release BOTH_FORCEHEAL_START, //# Healing meditation pose start @@ -1067,13 +1173,51 @@ typedef enum //# animNumber_e BOTH_FORCEHEAL_QUICK, //# Healing meditation gesture BOTH_SABERPULL, //# Use off-hand to do force power. BOTH_FORCEGRIP1, //# force-gripping (no anim?) - BOTH_FORCEGRIP2, //# force-gripping (?) BOTH_FORCEGRIP3, //# force-gripping (right hand) + BOTH_FORCEGRIP3THROW, //# throwing while force-gripping (right hand) BOTH_FORCEGRIP_HOLD, //# Use off-hand to do grip - hold BOTH_FORCEGRIP_RELEASE,//# Use off-hand to do grip - release BOTH_TOSS1, //# throwing to left after force gripping BOTH_TOSS2, //# throwing to right after force gripping + BOTH_COCKPIT_TALKR1START, //# turn head from straight forward to looking full right + BOTH_COCKPIT_TALKR1STARTTOMID, //# from TALKR1START to looking at hologram (cin #1) + BOTH_COCKPIT_TALKR1MIDTOSTART, //# from looking at hologram to TALKR1START (cin #1) + BOTH_COCKPIT_TALKR1STOP, //# return head to straight forward from BOTH_COCKPIT_TALKR1 + BOTH_COCKPIT_TALKR1STOPTOMID, //# from TALKR1STOP to TALKR1MID + BOTH_COCKPIT_TALKR1MIDTOSTOP, //# from looking at hologram to TALKR1STOP (cin #1) + BOTH_COCKPIT_TALKR1, //# talk to right side + + BOTH_COCKPIT_TALKL1START, //# turn head from straight forward to looking full left + BOTH_COCKPIT_TALKL1STARTTOMID, //# from TALKL1START to looking at hologram (cin #1) + BOTH_COCKPIT_TALKL1MIDTOSTART, //# from looking at hologram to TALKL1START (cin #1) + BOTH_COCKPIT_TALKL1STOP, //# return head to straight forward from BOTH_COCKPIT_TALKL1 + BOTH_COCKPIT_TALKL1STOPTOMID, //# from TALKL1STOP to TALKL1MID + BOTH_COCKPIT_TALKL1MIDTOSTOP, //# from looking at hologram to TALKL1STOP (cin #1) + BOTH_COCKPIT_TALKL1, //# talk to left side + + BOTH_COCKPIT_CONSOLE1, //# type at controls + BOTH_COCKPIT_CONSOLE2, //# type at controls + BOTH_COCKPIT_CONSOLE2_PARTIAL, //# last part of console2 anim (cin #1) used by Jan + + BOTH_COCKPIT_HEADNOD, //# nod head yes while sitting + BOTH_COCKPIT_HEADSHAKE, //# shake head no while sitting + + BOTH_COCKPIT_HEADTILTLSTART, //# start tilt head left while sitting + BOTH_COCKPIT_HEADTILTLSTOP, //# stop tilt head left while sitting + BOTH_COCKPIT_HEADTILTRSTART, //# start tilt head right while sitting + BOTH_COCKPIT_HEADTILTRSTOP, //# stop tilt head right while sitting + + BOTH_COCKPIT_TALKGESTURE7START, //# Lando's supporting hand to Kyle (cin #21) + BOTH_COCKPIT_TALKGESTURE7STOP, //# Lando's supporting hand away from Kyle (cin #21) + BOTH_COCKPIT_TALKGESTURE8START, //# Hand to Lando's chin (cin #21) + BOTH_COCKPIT_TALKGESTURE8STOP, //# hand away from Lando's chin *cin #21) + BOTH_COCKPIT_TALKGESTURE11START, //# + BOTH_COCKPIT_TALKGESTURE11STOP, //# + + BOTH_COCKPIT_SLEEP6START, //# + BOTH_COCKPIT_SLEEP6STOP, //# + //================================================= //ANIMS IN WHICH ONLY THE UPPER OBJECTS ARE IN MD3 //================================================= @@ -1111,25 +1255,7 @@ typedef enum //# animNumber_e TORSO_WEAPONIDLE11, //# Holding laser trap TORSO_WEAPONIDLE12, //# Holding detpack - //# #sep TORSO_ USING NON-WEAPON OBJECTS - //# #sep TORSO_ MISC - TORSO_TALKR1START, //# begin turning head for BOTH_TORSO_TALKR - TORSO_TALKR1HOLD, //# non-looping version of talk to right side - TORSO_TALKR1STOP, //# return head to straight forward from BOTH_TORSO_TALKL - TORSO_TALKR1, //# talk to right side - TORSO_TALKL1START, //# begin turning head for BOTH_TORSO_TALKL - TORSO_TALKL1HOLD, //# non-looping version of talk to left side - TORSO_TALKL1STOP, //# return head to straight forward from BOTH_TORSO_TALKL - TORSO_TALKL1, //# talk to left side - TORSO_LOOKL1, //# looking left - TORSO_LOOKR1, //# looking right - TORSO_LOOKR2START, //# turn not so far as TALKR1 - TORSO_LOOKR2STOP, //# turn not so far as TALKR1 - TORSO_LOOKR2, //# looking right - not so far as LOOKR1 - TORSO_LOOKL2START, //# turn not so far as TALKL1 - TORSO_LOOKL2STOP, //# turn not so far as TALKL1 - TORSO_LOOKL2, //# looking right - not so far as LOOKL1 TORSO_HANDGESTURE1, //# gestures to left one hand TORSO_HANDGESTURE2, //# gestures to right one hand TORSO_HANDGESTURE3, //# gestures to the left both hands diff --git a/CODE-mp/game/bg_local.h b/CODE-mp/game/bg_local.h index 54cf071..804c255 100644 --- a/CODE-mp/game/bg_local.h +++ b/CODE-mp/game/bg_local.h @@ -61,6 +61,7 @@ void trap_FS_FCloseFile( fileHandle_t f ); //PM anim utility functions: qboolean PM_SaberInParry( int move ); +qboolean PM_SaberInKnockaway( int move ); qboolean PM_SaberInReflect( int move ); qboolean PM_SaberInStart( int move ); qboolean PM_InSaberAnim( int anim ); diff --git a/CODE-mp/game/bg_misc.c b/CODE-mp/game/bg_misc.c index 303069b..6dd2d36 100644 --- a/CODE-mp/game/bg_misc.c +++ b/CODE-mp/game/bg_misc.c @@ -394,12 +394,6 @@ qboolean BG_LegalizedForcePowers(char *powerOut, int maxRank, qboolean freeSaber } } - if (final_Powers[FP_SABERATTACK] < 1) - { - final_Powers[FP_SABERDEFEND] = 0; - final_Powers[FP_SABERTHROW] = 0; - } - if (freeSaber) { if (final_Powers[FP_SABERATTACK] < 1) @@ -416,6 +410,7 @@ qboolean BG_LegalizedForcePowers(char *powerOut, int maxRank, qboolean freeSaber final_Powers[FP_LEVITATION] = 1; } + /* if (fpDisabled) { final_Powers[FP_LEVITATION] = 1; @@ -423,6 +418,31 @@ qboolean BG_LegalizedForcePowers(char *powerOut, int maxRank, qboolean freeSaber final_Powers[FP_SABERDEFEND] = 3; final_Powers[FP_SABERTHROW] = 0; } + */ + //Ahh. I have no idea why I did this, but I would say that it makes me a very bad man. + if (fpDisabled) + { //If we specifically have attack or def disabled, force them up to level 3. It's the way + //things work for the case of all powers disabled. + //If jump is disabled, down-cap it to level 1. Otherwise don't do a thing. + if (fpDisabled & (1 << FP_LEVITATION)) + { + final_Powers[FP_LEVITATION] = 1; + } + if (fpDisabled & (1 << FP_SABERATTACK)) + { + final_Powers[FP_SABERATTACK] = 3; + } + if (fpDisabled & (1 << FP_SABERDEFEND)) + { + final_Powers[FP_SABERDEFEND] = 3; + } + } + + if (final_Powers[FP_SABERATTACK] < 1) + { + final_Powers[FP_SABERDEFEND] = 0; + final_Powers[FP_SABERTHROW] = 0; + } //We finally have all the force powers legalized and stored locally. //Put them all into the string and return the result. We already have @@ -1276,6 +1296,11 @@ qboolean BG_CanUseFPNow(int gametype, playerState_t *ps, int time, forcePowers_t return qfalse; } + if ( ps->forceRestricted || ps->trueNonJedi ) + { + return qfalse; + } + if (ps->duelInProgress) { if (power != FP_SABERATTACK && power != FP_SABERDEFEND && power != FP_SABERTHROW && @@ -1581,13 +1606,39 @@ qboolean BG_CanItemBeGrabbed( int gametype, const entityState_t *ent, const play item = &bg_itemlist[ent->modelindex]; - if (ps && ps->isJediMaster && item && (item->giType == IT_WEAPON || item->giType == IT_AMMO)) + if ( ps ) { - return qfalse; + if ( ps->trueJedi ) + {//force powers and saber only + if ( item->giType != IT_TEAM //not a flag + && item->giType != IT_ARMOR//not shields + && (item->giType != IT_WEAPON || item->giTag != WP_SABER)//not a saber + && (item->giType != IT_HOLDABLE || item->giTag != HI_SEEKER)//not a seeker + && (item->giType != IT_POWERUP || item->giTag == PW_YSALAMIRI) )//not a force pick-up + { + return qfalse; + } + } + else if ( ps->trueNonJedi ) + {//can't pick up force powerups + if ( (item->giType == IT_POWERUP && item->giTag != PW_YSALAMIRI) //if a powerup, can only can pick up ysalamiri + || (item->giType == IT_HOLDABLE && item->giTag == HI_SEEKER)//if holdable, cannot pick up seeker + || (item->giType == IT_WEAPON && item->giTag == WP_SABER ) )//or if it's a saber + { + return qfalse; + } + } + if ( ps->isJediMaster && item && (item->giType == IT_WEAPON || item->giType == IT_AMMO)) + {//jedi master cannot pick up weapons + return qfalse; + } + if ( ps->duelInProgress ) + { //no picking stuff up while in a duel, no matter what the type is + return qfalse; + } } - - if (ps && ps->duelInProgress) - { //no picking stuff up while in a duel, no matter what the type is + else + {//safety return since below code assumes a non-null ps return qfalse; } @@ -2131,6 +2182,8 @@ void BG_PlayerStateToEntityState( playerState_t *ps, entityState_t *s, qboolean s->isJediMaster = ps->isJediMaster; s->time2 = ps->holocronBits; + + s->fireflag = ps->fd.saberAnimLevel; } /* @@ -2269,6 +2322,8 @@ void BG_PlayerStateToEntityStateExtraPolate( playerState_t *ps, entityState_t *s s->isJediMaster = ps->isJediMaster; s->time2 = ps->holocronBits; + + s->fireflag = ps->fd.saberAnimLevel; } /* diff --git a/CODE-mp/game/bg_panimate.c b/CODE-mp/game/bg_panimate.c index 047d269..4f2e4a8 100644 --- a/CODE-mp/game/bg_panimate.c +++ b/CODE-mp/game/bg_panimate.c @@ -114,7 +114,7 @@ qboolean BG_SaberInIdle( int move ) qboolean BG_FlippingAnim( int anim ) { - switch ( anim ) + switch ( anim&~ANIM_TOGGLEBIT ) { case BOTH_FLIP_F: //# Flip forward case BOTH_FLIP_B: //# Flip backwards @@ -151,7 +151,7 @@ qboolean BG_FlippingAnim( int anim ) qboolean BG_SpinningSaberAnim( int anim ) { - switch ( anim ) + switch ( anim&~ANIM_TOGGLEBIT ) { //level 1 - FIXME: level 1 will have *no* spins case BOTH_T1_BR_BL: @@ -236,6 +236,103 @@ qboolean BG_SaberInSpecialAttack( int anim ) return qfalse; } +int BG_BrokenParryForAttack( int move ) +{ + //Our attack was knocked away by a knockaway parry + //FIXME: need actual anims for this + //FIXME: need to know which side of the saber was hit! For now, we presume the saber gets knocked away from the center + switch ( saberMoveData[move].startQuad ) + { + case Q_B: + return LS_V1_B_; + break; + case Q_BR: + return LS_V1_BR; + break; + case Q_R: + return LS_V1__R; + break; + case Q_TR: + return LS_V1_TR; + break; + case Q_T: + return LS_V1_T_; + break; + case Q_TL: + return LS_V1_TL; + break; + case Q_L: + return LS_V1__L; + break; + case Q_BL: + return LS_V1_BL; + break; + } + return LS_NONE; +} + +int BG_BrokenParryForParry( int move ) +{ + //FIXME: need actual anims for this + //FIXME: need to know which side of the saber was hit! For now, we presume the saber gets knocked away from the center + switch ( move ) + { + case LS_PARRY_UP: + //Hmm... since we don't know what dir the hit came from, randomly pick knock down or knock back + if ( Q_irand( 0, 1 ) ) + { + return LS_H1_B_; + } + else + { + return LS_H1_T_; + } + break; + case LS_PARRY_UR: + return LS_H1_TR; + break; + case LS_PARRY_UL: + return LS_H1_TL; + break; + case LS_PARRY_LR: + return LS_H1_BR; + break; + case LS_PARRY_LL: + return LS_H1_BL; + break; + case LS_READY: + return LS_H1_B_;//??? + break; + } + return LS_NONE; +} + +int BG_KnockawayForParry( int move ) +{ + //FIXME: need actual anims for this + //FIXME: need to know which side of the saber was hit! For now, we presume the saber gets knocked away from the center + switch ( move ) + { + case BLOCKED_TOP://LS_PARRY_UP: + return LS_K1_T_;//push up + break; + case BLOCKED_UPPER_RIGHT://LS_PARRY_UR: + default://case LS_READY: + return LS_K1_TR;//push up, slightly to right + break; + case BLOCKED_UPPER_LEFT://LS_PARRY_UL: + return LS_K1_TL;//push up and to left + break; + case BLOCKED_LOWER_RIGHT://LS_PARRY_LR: + return LS_K1_BR;//push down and to left + break; + case BLOCKED_LOWER_LEFT://LS_PARRY_LL: + return LS_K1_BL;//push down and to right + break; + } + //return LS_NONE; +} + qboolean BG_InRoll( playerState_t *ps, int anim ) { switch ( (anim&~ANIM_TOGGLEBIT) ) @@ -285,6 +382,77 @@ qboolean BG_InDeathAnim( int anim ) } //Called only where pm is valid (not all require pm, but some do): +int PM_SaberBounceForAttack( int move ) +{ + switch ( saberMoveData[move].startQuad ) + { + case Q_B: + case Q_BR: + return LS_B1_BR; + break; + case Q_R: + return LS_B1__R; + break; + case Q_TR: + return LS_B1_TR; + break; + case Q_T: + return LS_B1_T_; + break; + case Q_TL: + return LS_B1_TL; + break; + case Q_L: + return LS_B1__L; + break; + case Q_BL: + return LS_B1_BL; + break; + } + return LS_NONE; +} + +int PM_SaberDeflectionForQuad( int quad ) +{ + switch ( quad ) + { + case Q_B: + return LS_D1_B_; + break; + case Q_BR: + return LS_D1_BR; + break; + case Q_R: + return LS_D1__R; + break; + case Q_TR: + return LS_D1_TR; + break; + case Q_T: + return LS_D1_T_; + break; + case Q_TL: + return LS_D1_TL; + break; + case Q_L: + return LS_D1__L; + break; + case Q_BL: + return LS_D1_BL; + break; + } + return LS_NONE; +} + +qboolean PM_SaberInDeflect( int move ) +{ + if ( move >= LS_D1_BR && move <= LS_D1_B_ ) + { + return qtrue; + } + return qfalse; +} + qboolean PM_SaberInParry( int move ) { if ( move >= LS_PARRY_UP && move <= LS_PARRY_LL ) @@ -294,6 +462,15 @@ qboolean PM_SaberInParry( int move ) return qfalse; } +qboolean PM_SaberInKnockaway( int move ) +{ + if ( move >= LS_K1_T_ && move <= LS_K1_BL ) + { + return qtrue; + } + return qfalse; +} + qboolean PM_SaberInReflect( int move ) { if ( move >= LS_REFLECT_UP && move <= LS_REFLECT_LL ) @@ -312,6 +489,15 @@ qboolean PM_SaberInStart( int move ) return qfalse; } +qboolean PM_SaberInReturn( int move ) +{ + if ( move >= LS_R_TL2BR && move <= LS_R_TL2BR ) + { + return qtrue; + } + return qfalse; +} + qboolean PM_InSaberAnim( int anim ) { if ( (anim&~ANIM_TOGGLEBIT) >= BOTH_A1_T__B_ && (anim&~ANIM_TOGGLEBIT) <= BOTH_H1_S1_BR ) @@ -544,6 +730,34 @@ char BGPAFtext[40000]; qboolean BGPAFtextLoaded = qfalse; animation_t bgGlobalAnimations[MAX_TOTALANIMATIONS]; +//#define CONVENIENT_ANIMATION_FILE_DEBUG_THING + +#ifdef CONVENIENT_ANIMATION_FILE_DEBUG_THING +void SpewDebugStuffToFile() +{ + fileHandle_t f; + int i = 0; + + trap_FS_FOpenFile("file_of_debug_stuff_MP.txt", &f, FS_WRITE); + + if (!f) + { + return; + } + + BGPAFtext[0] = 0; + + while (i < MAX_ANIMATIONS) + { + strcat(BGPAFtext, va("%i %i\n", i, bgGlobalAnimations[i].frameLerp)); + i++; + } + + trap_FS_Write(BGPAFtext, strlen(BGPAFtext), f); + trap_FS_FCloseFile(f); +} +#endif + qboolean BG_ParseAnimationFile(const char *filename) { char *text_p; @@ -673,6 +887,9 @@ qboolean BG_ParseAnimationFile(const char *filename) } #endif // _DEBUG +#ifdef CONVENIENT_ANIMATION_FILE_DEBUG_THING + SpewDebugStuffToFile(); +#endif BGPAFtextLoaded = qtrue; return qtrue; } @@ -831,7 +1048,7 @@ void PM_SetAnimFinal(int setAnimParts,int anim,int setAnimFlags, { animation_t *animations = pm->animations; - float editAnimSpeed = 0; + float editAnimSpeed = 1; if (!animations) { @@ -864,10 +1081,13 @@ void PM_SetAnimFinal(int setAnimParts,int anim,int setAnimFlags, if (setAnimFlags & SETANIM_FLAG_HOLDLESS) { // Make sure to only wait in full 1/20 sec server frame intervals. int dur; + int speedDif; - dur = (animations[anim].numFrames ) * fabs(animations[anim].frameLerp); + dur = (animations[anim].numFrames-1) * fabs(animations[anim].frameLerp); //dur = ((int)(dur/50.0)) * 50 / timeScaleMod; - dur -= blendTime+fabs(animations[anim].frameLerp)*2; + //dur -= blendTime+fabs(animations[anim].frameLerp)*2; + speedDif = dur - (dur * editAnimSpeed); + dur += speedDif; if (dur > 1) { pm->ps->torsoTimer = dur-1; @@ -886,11 +1106,6 @@ void PM_SetAnimFinal(int setAnimParts,int anim,int setAnimFlags, { pm->ps->torsoTimer /= 1.7; } - - if (editAnimSpeed) - { - pm->ps->torsoTimer /= editAnimSpeed; - } } } @@ -916,10 +1131,13 @@ setAnimLegs: if (setAnimFlags & SETANIM_FLAG_HOLDLESS) { // Make sure to only wait in full 1/20 sec server frame intervals. int dur; + int speedDif; - dur = (animations[anim].numFrames -1) * fabs(animations[anim].frameLerp); + dur = (animations[anim].numFrames-1) * fabs(animations[anim].frameLerp); //dur = ((int)(dur/50.0)) * 50 / timeScaleMod; - dur -= blendTime+fabs(animations[anim].frameLerp)*2; + //dur -= blendTime+fabs(animations[anim].frameLerp)*2; + speedDif = dur - (dur * editAnimSpeed); + dur += speedDif; if (dur > 1) { pm->ps->legsTimer = dur-1; diff --git a/CODE-mp/game/bg_pmove.c b/CODE-mp/game/bg_pmove.c index 6c91279..0cf7ecc 100644 --- a/CODE-mp/game/bg_pmove.c +++ b/CODE-mp/game/bg_pmove.c @@ -64,7 +64,7 @@ int forcePowerNeeded[NUM_FORCE_POWER_LEVELS][NUM_FORCE_POWERS] = //NUM_FORCE_POWERS }, { - 25,//FP_HEAL,//instant + 65,//FP_HEAL,//instant //was 25, but that was way too little 10,//FP_LEVITATION,//hold/duration 50,//FP_SPEED,//duration 20,//FP_PUSH,//hold/duration @@ -77,7 +77,7 @@ int forcePowerNeeded[NUM_FORCE_POWER_LEVELS][NUM_FORCE_POWERS] = 50,//FP_ABSORB,//duration 50,//FP_TEAM_HEAL,//instant 50,//FP_TEAM_FORCE,//instant - 10,//FP_DRAIN,//hold/duration + 20,//FP_DRAIN,//hold/duration 20,//FP_SEE,//duration 0,//FP_SABERATTACK, 2,//FP_SABERDEFEND, @@ -85,7 +85,7 @@ int forcePowerNeeded[NUM_FORCE_POWER_LEVELS][NUM_FORCE_POWERS] = //NUM_FORCE_POWERS }, { - 25,//FP_HEAL,//instant + 60,//FP_HEAL,//instant 10,//FP_LEVITATION,//hold/duration 50,//FP_SPEED,//duration 20,//FP_PUSH,//hold/duration @@ -98,7 +98,7 @@ int forcePowerNeeded[NUM_FORCE_POWER_LEVELS][NUM_FORCE_POWERS] = 25,//FP_ABSORB,//duration 33,//FP_TEAM_HEAL,//instant 33,//FP_TEAM_FORCE,//instant - 10,//FP_DRAIN,//hold/duration + 20,//FP_DRAIN,//hold/duration 20,//FP_SEE,//duration 0,//FP_SABERATTACK, 1,//FP_SABERDEFEND, @@ -106,7 +106,7 @@ int forcePowerNeeded[NUM_FORCE_POWER_LEVELS][NUM_FORCE_POWERS] = //NUM_FORCE_POWERS }, { - 25,//FP_HEAL,//instant + 50,//FP_HEAL,//instant //You get 5 points of health.. for 50 force points! 10,//FP_LEVITATION,//hold/duration 50,//FP_SPEED,//duration 20,//FP_PUSH,//hold/duration @@ -119,7 +119,7 @@ int forcePowerNeeded[NUM_FORCE_POWER_LEVELS][NUM_FORCE_POWERS] = 10,//FP_ABSORB,//duration 25,//FP_TEAM_HEAL,//instant 25,//FP_TEAM_FORCE,//instant - 10,//FP_DRAIN,//hold/duration + 20,//FP_DRAIN,//hold/duration 20,//FP_SEE,//duration 0,//FP_SABERATTACK, 0,//FP_SABERDEFEND, @@ -871,6 +871,7 @@ static qboolean PM_CheckJump( void ) pm->cmd.upmove = 0; return qfalse; } + /* else if ( pm->ps->groundEntityNum == ENTITYNUM_NONE ) { int legsAnim = (pm->ps->legsAnim&~ANIM_TOGGLEBIT); @@ -879,13 +880,14 @@ static qboolean PM_CheckJump( void ) return qfalse; } } + */ } } #endif //Not jumping - if ( pm->cmd.upmove < 10 ) { + if ( pm->cmd.upmove < 10 && pm->ps->groundEntityNum != ENTITYNUM_NONE) { return qfalse; } @@ -954,11 +956,13 @@ static qboolean PM_CheckJump( void ) anim = BOTH_WALL_FLIP_LEFT; } } + /* else if ( pm->cmd.forwardmove > 0 && pm->ps->fd.forcePowerLevel[FP_LEVITATION] > FORCE_LEVEL_1 ) {//run up wall, flip backwards vertPush = forceJumpStrength[FORCE_LEVEL_2]/2.25f; anim = BOTH_WALL_FLIP_BACK1; } + */ else if ( pm->cmd.forwardmove < 0 && !(pm->cmd.buttons&BUTTON_ATTACK) ) {//backflip vertPush = JUMP_VELOCITY; @@ -1186,6 +1190,58 @@ static qboolean PM_CheckJump( void ) return qfalse; } } + else if ( pm->cmd.forwardmove > 0 //pushing forward + && pm->ps->fd.forcePowerLevel[FP_LEVITATION] > FORCE_LEVEL_1 + && pm->ps->velocity[2] > 200 + && /*(level.time - pm->ps->lastOnGround) <= 500*/ PM_GroundDistance() <= 80 //unfortunately we do not have a happy ground timer. + && !BG_InSpecialJump(pm->ps->legsAnim)) + {//run up wall, flip backwards + //FIXME: have to be moving... make sure it's opposite the wall... or at least forward? + vec3_t fwd, traceto, mins, maxs, fwdAngles; + trace_t trace; + vec3_t idealNormal; + + VectorSet(mins, pm->mins[0],pm->mins[1],pm->mins[2]); + VectorSet(maxs, pm->maxs[0],pm->maxs[1],pm->maxs[2]); + VectorSet(fwdAngles, 0, pm->ps->viewangles[YAW], 0); + + AngleVectors( fwdAngles, fwd, NULL, NULL ); + VectorMA( pm->ps->origin, 32, fwd, traceto ); + + pm->trace( &trace, pm->ps->origin, mins, maxs, traceto, pm->ps->clientNum, MASK_PLAYERSOLID );//FIXME: clip brushes too? + VectorSubtract( pm->ps->origin, traceto, idealNormal ); + VectorNormalize( idealNormal ); + + if ( trace.fraction < 1.0f ) + {//there is a wall there + int parts = SETANIM_LEGS; + + pm->ps->velocity[0] = pm->ps->velocity[1] = 0; + VectorMA( pm->ps->velocity, -150, fwd, pm->ps->velocity ); + pm->ps->velocity[2] += 128; + + if ( !pm->ps->weaponTime ) + { + parts = SETANIM_BOTH; + } + PM_SetAnim( parts, BOTH_WALL_FLIP_BACK1, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD, 0 ); + + pm->ps->legsTimer -= 600; //I force this anim to play to the end to prevent landing on your head and suddenly flipping over. + //It is a bit too long at the end though, so I'll just shorten it. + + pm->ps->fd.forceJumpZStart = pm->ps->origin[2];//so we don't take damage if we land at same height + //pm->ps->pm_flags |= PMF_JUMPING|PMF_SLOW_MO_FALL; + pm->cmd.upmove = 0; + //G_SoundOnEnt( pm->gent, CHAN_BODY, "sound/weapons/force/jump.wav" ); + pm->ps->fd.forceJumpSound = 1; + BG_ForcePowerDrain( pm->ps, FP_LEVITATION, 5 ); + + if (trace.entityNum < MAX_CLIENTS) + { + pm->ps->forceKickFlip = trace.entityNum+1; //let the server know that this person gets kicked by this client + } + } + } else { //FIXME: if in a butterfly, kick people away? @@ -1235,6 +1291,7 @@ static qboolean PM_CheckJump( void ) else if ( pm->ps->fd.saberAnimLevel == FORCE_LEVEL_3 ) {//using strong attacks if ( pm->cmd.forwardmove > 0 && //going forward + (pm->cmd.buttons & BUTTON_ATTACK) && //must be holding attack still PM_GroundDistance() < 32 && !BG_InSpecialJump(pm->ps->legsAnim)) {//strong attack: jump-hack @@ -1447,13 +1504,19 @@ static void PM_FlyMove( void ) { PM_Friction (); scale = PM_CmdScale( &pm->cmd ); + + if ( pm->ps->pm_type == PM_SPECTATOR && pm->cmd.buttons & BUTTON_ALT_ATTACK) { + //turbo boost + scale *= 10; + } + // // user intentions // if ( !scale ) { wishvel[0] = 0; wishvel[1] = 0; - wishvel[2] = 0; + wishvel[2] = pm->ps->speed * (pm->cmd.upmove/127.0f); } else { for (i=0 ; i<3 ; i++) { wishvel[i] = scale * pml.forward[i]*pm->cmd.forwardmove + scale * pml.right[i]*pm->cmd.rightmove; @@ -1825,7 +1888,7 @@ static int PM_TryRoll( void ) if ( BG_SaberInAttack( pm->ps->saberMove ) || BG_SaberInSpecialAttack( pm->ps->torsoAnim ) || BG_SpinningSaberAnim( pm->ps->legsAnim ) - || (!pm->ps->clientNum&&PM_SaberInStart( pm->ps->saberMove )) ) + || PM_SaberInStart( pm->ps->saberMove ) ) {//attacking or spinning (or, if player, starting an attack) return 0; } @@ -2169,7 +2232,25 @@ static void PM_GroundTraceMissed( void ) { trace_t trace; vec3_t point; - if ( pm->ps->groundEntityNum != ENTITYNUM_NONE ) { + //rww - don't want to do this when handextend_choke, because you can be standing on the ground + //while still holding your throat. + if ( pm->ps->pm_type == PM_FLOAT ) { + //we're assuming this is because you're being choked + int parts = SETANIM_LEGS; + /* + if ( !pm->ps->weaponTime && pm->ps->forceHandExtend >= HANDEXTEND_CHOKE ) + {//still on ground, only set anim on torso + parts = SETANIM_BOTH; + } + */ + //rww - also don't use SETANIM_FLAG_HOLD, it will cause the legs to float around a bit before going into + //a proper anim even when on the ground. + PM_SetAnim(parts, BOTH_CHOKE3, SETANIM_FLAG_OVERRIDE, 100); + //pm->ps->torsoTimer = 1; + //pm->ps->legsTimer = 1; + } + //If the anim is choke3, act like we just went into the air because we aren't in a float + else if ( pm->ps->groundEntityNum != ENTITYNUM_NONE || (pm->ps->legsAnim&~ANIM_TOGGLEBIT) == BOTH_CHOKE3 ) { // we just transitioned into freefall if ( pm->debugLevel ) { Com_Printf("%i:lift\n", c_pmove); @@ -2531,6 +2612,22 @@ static void PM_Footsteps( void ) { float bobmove; int old; qboolean footstep; + int setAnimFlags = 0; + + if ( (PM_InSaberAnim( (pm->ps->legsAnim&~ANIM_TOGGLEBIT) ) && !BG_SpinningSaberAnim( (pm->ps->legsAnim&~ANIM_TOGGLEBIT) )) + || (pm->ps->legsAnim&~ANIM_TOGGLEBIT) == BOTH_STAND1 + || (pm->ps->legsAnim&~ANIM_TOGGLEBIT) == BOTH_STAND1TO2 + || (pm->ps->legsAnim&~ANIM_TOGGLEBIT) == BOTH_STAND2TO1 + || (pm->ps->legsAnim&~ANIM_TOGGLEBIT) == BOTH_STAND2 + || (pm->ps->legsAnim&~ANIM_TOGGLEBIT) == BOTH_SABERFAST_STANCE + || (pm->ps->legsAnim&~ANIM_TOGGLEBIT) == BOTH_SABERSLOW_STANCE + || (pm->ps->legsAnim&~ANIM_TOGGLEBIT) == BOTH_BUTTON_HOLD + || (pm->ps->legsAnim&~ANIM_TOGGLEBIT) == BOTH_BUTTON_RELEASE + || PM_LandingAnim( (pm->ps->legsAnim&~ANIM_TOGGLEBIT) ) + || PM_PainAnim( (pm->ps->legsAnim&~ANIM_TOGGLEBIT) )) + {//legs are in a saber anim, and not spinning, be sure to override it + setAnimFlags |= SETANIM_FLAG_OVERRIDE; + } // // calculate speed and cycle to be used for @@ -2542,8 +2639,16 @@ static void PM_Footsteps( void ) { if ( pm->ps->groundEntityNum == ENTITYNUM_NONE ) { // airborne leaves position in cycle intact, but doesn't advance - if ( pm->waterlevel > 1 ) { - PM_ContinueLegsAnim( BOTH_SWIM1 ); + if ( pm->waterlevel > 1 ) + { + if (pm->xyspeed > 60) + { + PM_ContinueLegsAnim( BOTH_SWIMFORWARD ); + } + else + { + PM_ContinueLegsAnim( BOTH_SWIM_IDLE1 ); + } } return; } @@ -2553,7 +2658,14 @@ static void PM_Footsteps( void ) { if ( pm->xyspeed < 5 ) { pm->ps->bobCycle = 0; // start at beginning of cycle again if ( (pm->ps->pm_flags & PMF_DUCKED) || (pm->ps->pm_flags & PMF_ROLLING) ) { - PM_ContinueLegsAnim( BOTH_CROUCH1IDLE ); + if ((pm->ps->legsAnim&~ANIM_TOGGLEBIT) != BOTH_CROUCH1IDLE) + { + PM_SetAnim(SETANIM_LEGS, BOTH_CROUCH1IDLE, setAnimFlags, 100); + } + else + { + PM_ContinueLegsAnim( BOTH_CROUCH1IDLE ); + } } else { if (pm->ps->weapon == WP_DISRUPTOR && pm->ps->zoomMode == 1) { @@ -2590,10 +2702,24 @@ static void PM_Footsteps( void ) { if ( !rolled ) { if ( pm->ps->pm_flags & PMF_BACKWARDS_RUN ) { - PM_ContinueLegsAnim( BOTH_CROUCH1WALKBACK ); + if ((pm->ps->legsAnim&~ANIM_TOGGLEBIT) != BOTH_CROUCH1WALKBACK) + { + PM_SetAnim(SETANIM_LEGS, BOTH_CROUCH1WALKBACK, setAnimFlags, 100); + } + else + { + PM_ContinueLegsAnim( BOTH_CROUCH1WALKBACK ); + } } else { - PM_ContinueLegsAnim( BOTH_CROUCH1WALK ); + if ((pm->ps->legsAnim&~ANIM_TOGGLEBIT) != BOTH_CROUCH1WALK) + { + PM_SetAnim(SETANIM_LEGS, BOTH_CROUCH1WALK, setAnimFlags, 100); + } + else + { + PM_ContinueLegsAnim( BOTH_CROUCH1WALK ); + } } } else @@ -2626,11 +2752,25 @@ static void PM_Footsteps( void ) { if ( pm->ps->pm_flags & PMF_BACKWARDS_RUN ) { - PM_ContinueLegsAnim( BOTH_CROUCH1WALKBACK ); + if ((pm->ps->legsAnim&~ANIM_TOGGLEBIT) != BOTH_CROUCH1WALKBACK) + { + PM_SetAnim(SETANIM_LEGS, BOTH_CROUCH1WALKBACK, setAnimFlags, 100); + } + else + { + PM_ContinueLegsAnim( BOTH_CROUCH1WALKBACK ); + } } else { - PM_ContinueLegsAnim( BOTH_CROUCH1WALK ); + if ((pm->ps->legsAnim&~ANIM_TOGGLEBIT) != BOTH_CROUCH1WALK) + { + PM_SetAnim(SETANIM_LEGS, BOTH_CROUCH1WALK, setAnimFlags, 100); + } + else + { + PM_ContinueLegsAnim( BOTH_CROUCH1WALK ); + } } } else @@ -2638,19 +2778,47 @@ static void PM_Footsteps( void ) { if ( !( pm->cmd.buttons & BUTTON_WALKING ) ) { bobmove = 0.4f; // faster speeds bob faster if ( pm->ps->pm_flags & PMF_BACKWARDS_RUN ) { - PM_ContinueLegsAnim( BOTH_RUNBACK1 ); + if ((pm->ps->legsAnim&~ANIM_TOGGLEBIT) != BOTH_RUNBACK1) + { + PM_SetAnim(SETANIM_LEGS, BOTH_RUNBACK1, setAnimFlags, 100); + } + else + { + PM_ContinueLegsAnim( BOTH_RUNBACK1 ); + } } else { - PM_ContinueLegsAnim( BOTH_RUN1 ); + if ((pm->ps->legsAnim&~ANIM_TOGGLEBIT) != BOTH_RUN1) + { + PM_SetAnim(SETANIM_LEGS, BOTH_RUN1, setAnimFlags, 100); + } + else + { + PM_ContinueLegsAnim( BOTH_RUN1 ); + } } footstep = qtrue; } else { bobmove = 0.2f; // walking bobs slow if ( pm->ps->pm_flags & PMF_BACKWARDS_RUN ) { - PM_ContinueLegsAnim( BOTH_WALKBACK1 ); + if ((pm->ps->legsAnim&~ANIM_TOGGLEBIT) != BOTH_WALKBACK1) + { + PM_SetAnim(SETANIM_LEGS, BOTH_WALKBACK1, setAnimFlags, 100); + } + else + { + PM_ContinueLegsAnim( BOTH_WALKBACK1 ); + } } else { - PM_ContinueLegsAnim( BOTH_WALK1 ); + if ((pm->ps->legsAnim&~ANIM_TOGGLEBIT) != BOTH_WALK1) + { + PM_SetAnim(SETANIM_LEGS, BOTH_WALK1, setAnimFlags, 100); + } + else + { + PM_ContinueLegsAnim( BOTH_WALK1 ); + } } } } @@ -3249,7 +3417,13 @@ static void PM_Weapon( void ) { desiredAnim = BOTH_SABERPULL; break; case HANDEXTEND_CHOKE: - desiredAnim = BOTH_CHOKE3;//TORSO_CHOKING1; + desiredAnim = BOTH_CHOKE3; //left-handed choke + /* + if ( pm->ps->weapon == WP_NONE || pm->ps->weapon == WP_MELEE ) + { + desiredAnim = BOTH_CHOKE1; //two-handed choke + } + */ break; case HANDEXTEND_DODGE: desiredAnim = pm->ps->forceDodgeAnim; @@ -3281,6 +3455,17 @@ static void PM_Weapon( void ) { case HANDEXTEND_TAUNT: desiredAnim = pm->ps->forceDodgeAnim; break; + //Hmm... maybe use these, too? + //BOTH_FORCEHEAL_QUICK //quick heal (SP level 2 & 3) + //BOTH_MINDTRICK1 // wave (maybe for mind trick 2 & 3 - whole area, and for force seeing) + //BOTH_MINDTRICK2 // tap (maybe for mind trick 1 - one person) + //BOTH_FORCEGRIP_START //start grip + //BOTH_FORCEGRIP_HOLD //hold grip + //BOTH_FORCEGRIP_RELEASE //release grip + //BOTH_FORCELIGHTNING //quick lightning burst (level 1) + //BOTH_FORCELIGHTNING_START //start lightning + //BOTH_FORCELIGHTNING_HOLD //hold lightning + //BOTH_FORCELIGHTNING_RELEASE //release lightning default: desiredAnim = BOTH_FORCEPUSH; break; @@ -3289,9 +3474,9 @@ static void PM_Weapon( void ) { PM_SetAnim(SETANIM_TORSO, desiredAnim, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD, 100); pm->ps->torsoTimer = 1; - if (pm->ps->forceHandExtend == HANDEXTEND_DODGE || pm->ps->forceHandExtend == HANDEXTEND_KNOCKDOWN /*|| - pm->ps->forceHandExtend == HANDEXTEND_CHOKE*/) - { //special case, play dodge anim on whole body + if (pm->ps->forceHandExtend == HANDEXTEND_DODGE || pm->ps->forceHandExtend == HANDEXTEND_KNOCKDOWN || + (pm->ps->forceHandExtend == HANDEXTEND_CHOKE && pm->ps->groundEntityNum == ENTITYNUM_NONE) ) + { //special case, play dodge anim on whole body, choke anim too if off ground PM_SetAnim(SETANIM_LEGS, desiredAnim, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD, 100); pm->ps->legsTimer = 1; } @@ -3451,12 +3636,12 @@ static void PM_Weapon( void ) { PM_StartTorsoAnim( BOTH_GUNSIT1 ); } - if (pm->ps->isJediMaster || pm->ps->duelInProgress) + if (pm->ps->isJediMaster || pm->ps->duelInProgress || pm->ps->trueJedi) { pm->cmd.weapon = WP_SABER; pm->ps->weapon = WP_SABER; - if (pm->ps->isJediMaster) + if (pm->ps->isJediMaster || pm->ps->trueJedi) { pm->ps->stats[STAT_WEAPONS] = (1 << WP_SABER); } @@ -3690,7 +3875,7 @@ PM_Animate static void PM_Animate( void ) { if ( pm->cmd.buttons & BUTTON_GESTURE ) { if ( pm->ps->torsoTimer < 1 && pm->ps->forceHandExtend == HANDEXTEND_NONE && - pm->ps->legsTimer < 1 && pm->ps->weaponTime < 1 ) { + pm->ps->legsTimer < 1 && pm->ps->weaponTime < 1 && pm->ps->saberLockTime < pm->cmd.serverTime) { /* PM_StartTorsoAnim( BOTH_TALKGESTURE3 ); pm->ps->torsoTimer = TIMER_GESTURE; @@ -4022,6 +4207,8 @@ void BG_CmdForRoll( int anim, usercmd_t *pCmd ) pCmd->upmove = 0; } +qboolean PM_SaberInTransition( int move ); + void BG_AdjustClientSpeed(playerState_t *ps, usercmd_t *cmd, int svTime) { //For prediction, always reset speed back to the last known server base speed @@ -4102,6 +4289,11 @@ void BG_AdjustClientSpeed(playerState_t *ps, usercmd_t *cmd, int svTime) } } + if (ps->fd.forcePowersActive & (1 << FP_GRIP)) + { + ps->speed *= 0.4; + } + if (ps->fd.forcePowersActive & (1 << FP_SPEED)) { if (ps->fd.forceSpeedSmash < 1.2) @@ -4160,7 +4352,14 @@ void BG_AdjustClientSpeed(playerState_t *ps, usercmd_t *cmd, int svTime) } else if ( BG_SpinningSaberAnim( ps->legsAnim ) ) { - ps->speed *= 0.5f; + if (ps->fd.saberAnimLevel == FORCE_LEVEL_3) + { + ps->speed *= 0.3f; + } + else + { + ps->speed *= 0.5f; + } } else if ( ps->weapon == WP_SABER && BG_SaberInAttack( ps->saberMove ) ) {//if attacking with saber while running, drop your speed @@ -4170,12 +4369,25 @@ void BG_AdjustClientSpeed(playerState_t *ps, usercmd_t *cmd, int svTime) ps->speed *= 0.85f; break; case FORCE_LEVEL_3: - ps->speed *= 0.70f; + //ps->speed *= 0.70f; + ps->speed *= 0.55f; break; default: break; } } + else if (ps->weapon == WP_SABER && ps->fd.saberAnimLevel == FORCE_LEVEL_3 && + PM_SaberInTransition(ps->saberMove)) + { //Now, we want to even slow down in transitions for level 3 (since it has chains and stuff now) + if (cmd->forwardmove < 0) + { + ps->speed *= 0.4f; + } + else + { + ps->speed *= 0.6f; + } + } if ( BG_InRoll( ps, ps->legsAnim ) && ps->speed > 200 ) @@ -4313,6 +4525,13 @@ void PmoveSingle (pmove_t *pmove) { pm->cmd.buttons &= ~BUTTON_WALKING; } + // set the talk balloon flag + if ( pm->cmd.buttons & BUTTON_TALK ) { + pm->ps->eFlags |= EF_TALK; + } else { + pm->ps->eFlags &= ~EF_TALK; + } + // In certain situations, we may want to control which attack buttons are pressed and what kind of functionality // is attached to them PM_AdjustAttackStates( pm ); @@ -4323,6 +4542,18 @@ void PmoveSingle (pmove_t *pmove) { pm->ps->pm_flags &= ~PMF_RESPAWNED; } + // if talk button is down, dissallow all other input + // this is to prevent any possible intercept proxy from + // adding fake talk balloons + if ( pmove->cmd.buttons & BUTTON_TALK ) { + // keep the talk button set tho for when the cmd.serverTime > 66 msec + // and the same cmd is used multiple times in Pmove + pmove->cmd.buttons = BUTTON_TALK; + pmove->cmd.forwardmove = 0; + pmove->cmd.rightmove = 0; + pmove->cmd.upmove = 0; + } + // clear all pmove local vars memset (&pml, 0, sizeof(pml)); @@ -4345,6 +4576,28 @@ void PmoveSingle (pmove_t *pmove) { PM_AdjustAngleForWallRun(pm->ps, &pm->cmd, qtrue); + if (pm->ps->saberMove == LS_A_JUMP_T__B_ || pm->ps->saberMove == LS_A_LUNGE) + { + /* + if (pm->ps->velocity[0] || + pm->ps->velocity[1] || + pm->ps->velocity[2]) + { //if we're doing a lunge and we have a velocity, force us to look in the direction we are + //flying with the lunge + vec3_t velAngles; + + vectoangles(pm->ps->velocity, velAngles); + PM_SetPMViewAngle(pm->ps, velAngles, &pm->cmd); + } + else + { //otherwise, if there is no valid velocity, just don't let us readjust the angles. + PM_SetPMViewAngle(pm->ps, pm->ps->viewangles, &pm->cmd); + } + */ + //FIXME: Use the above method, and don't let the angles mess up when you hit something. + PM_SetPMViewAngle(pm->ps, pm->ps->viewangles, &pm->cmd); + } + // update the viewangles PM_UpdateViewAngles( pm->ps, &pm->cmd ); diff --git a/CODE-mp/game/bg_public.h b/CODE-mp/game/bg_public.h index eac0a4b..2669d91 100644 --- a/CODE-mp/game/bg_public.h +++ b/CODE-mp/game/bg_public.h @@ -105,6 +105,7 @@ typedef enum { G2_MODELPART_WAIST, G2_MODELPART_LARM, G2_MODELPART_RARM, + G2_MODELPART_RHAND, G2_MODELPART_LLEG, G2_MODELPART_RLEG } g2ModelParts_t; @@ -273,6 +274,7 @@ typedef struct { int (*pointcontents)( const vec3_t point, int passEntityNum ); playerState_t *bgClients[MAX_CLIENTS]; + int checkDuelLoss; } pmove_t; extern pmove_t *pm; @@ -338,25 +340,36 @@ typedef enum { #define EF_DEAD 0x00000001 // don't draw a foe marker over players with EF_DEAD #define EF_BOUNCE_SHRAPNEL 0x00000002 // special shrapnel flag #define EF_TELEPORT_BIT 0x00000004 // toggled every time the origin abruptly changes + +//doesn't do anything #define EF_AWARD_EXCELLENT 0x00000008 // draw an excellent sprite #define EF_PLAYER_EVENT 0x00000010 #define EF_BOUNCE 0x00000010 // for missiles #define EF_BOUNCE_HALF 0x00000020 // for missiles + +//doesn't do anything #define EF_AWARD_GAUNTLET 0x00000040 // draw a gauntlet sprite + #define EF_NODRAW 0x00000080 // may have an event, but no model (unspawned items) #define EF_FIRING 0x00000100 // for lightning gun #define EF_ALT_FIRING 0x00000200 // for alt-fires, mostly for lightning guns though #define EF_MOVER_STOP 0x00000400 // will push otherwise + +//doesn't do anything #define EF_AWARD_CAP 0x00000800 // draw the capture sprite + #define EF_TALK 0x00001000 // draw a talk balloon #define EF_CONNECTION 0x00002000 // draw a connection trouble sprite #define EF_VOTED 0x00004000 // already cast a vote + +//next 4 don't actually do anything #define EF_AWARD_IMPRESSIVE 0x00008000 // draw an impressive sprite #define EF_AWARD_DEFEND 0x00010000 // draw a defend sprite #define EF_AWARD_ASSIST 0x00020000 // draw a assist sprite #define EF_AWARD_DENIED 0x00040000 // denied + #define EF_TEAMVOTED 0x00080000 // already cast a team vote #define EF_SEEKERDRONE 0x00100000 // show seeker drone floating around head #define EF_MISSILE_STICK 0x00200000 // missiles that stick to the wall. @@ -1000,6 +1013,9 @@ qboolean BG_SaberInIdle( int move ); qboolean BG_FlippingAnim( int anim ); qboolean BG_SpinningSaberAnim( int anim ); qboolean BG_SaberInSpecialAttack( int anim ); +int BG_BrokenParryForAttack( int move ); +int BG_BrokenParryForParry( int move ); +int BG_KnockawayForParry( int move ); qboolean BG_InRoll( playerState_t *ps, int anim ); qboolean BG_InDeathAnim( int anim ); diff --git a/CODE-mp/game/bg_saber.c b/CODE-mp/game/bg_saber.c index e6ad967..989ba5c 100644 --- a/CODE-mp/game/bg_saber.c +++ b/CODE-mp/game/bg_saber.c @@ -250,6 +250,7 @@ saberMoveData_t saberMoveData[LS_MOVE_MAX] = {// NB:randomized {"Reflect LL", BOTH_P1_S1_BL, Q_R, Q_BR, AFLAG_ACTIVE, 50, BLK_WIDE, LS_R_TL2BR, LS_A_BR2TL, 300 }, // LS_PARRY_LL, }; + int transitionMove[Q_NUM_QUADS][Q_NUM_QUADS] = { LS_NONE, //Can't transition to same pos! @@ -348,9 +349,11 @@ saberMoveName_t PM_AttackMoveForQuad( int quad ) return LS_NONE; } +qboolean PM_SaberKataDone(int curmove, int newmove); + int PM_SaberAnimTransitionAnim( int curmove, int newmove ) { - //FIXME: take FP_SABERATTACK into account here somehow? + //FIXME: take FP_SABER_OFFENSE into account here somehow? int retmove = newmove; if ( curmove == LS_READY ) {//just standing there @@ -397,11 +400,21 @@ int PM_SaberAnimTransitionAnim( int curmove, int newmove ) case LS_A_R2L: case LS_A_TR2BL: case LS_A_T2B: - /*if ( newmove == curmove ) + if ( newmove == curmove ) {//FIXME: need a spin or something or go to next level, but for now, just play the return - retmove = LS_R_TL2BR + (newmove-LS_A_TL2BR); + //going into another attack... + //allow endless chaining in level 1 attacks, several in level 2 and only one or a few in level 3 + //FIXME: don't let strong attacks chain to an attack in the opposite direction ( > 45 degrees?) + if ( PM_SaberKataDone( curmove, newmove ) ) + {//done with this kata, must return to ready before attack again + retmove = LS_R_TL2BR + (newmove-LS_A_TL2BR); + } + else + {//okay to chain to another attack + retmove = transitionMove[saberMoveData[curmove].endQuad][saberMoveData[newmove].startQuad]; + } } - else */if ( saberMoveData[curmove].endQuad == saberMoveData[newmove].startQuad ) + else if ( saberMoveData[curmove].endQuad == saberMoveData[newmove].startQuad ) {//new move starts from same quadrant retmove = newmove; } @@ -417,6 +430,14 @@ int PM_SaberAnimTransitionAnim( int curmove, int newmove ) case LS_A_R2L: case LS_A_TR2BL: case LS_A_T2B: + case LS_D1_BR: + case LS_D1__R: + case LS_D1_TR: + case LS_D1_T_: + case LS_D1_TL: + case LS_D1__L: + case LS_D1_BL: + case LS_D1_B_: retmove = transitionMove[saberMoveData[curmove].endQuad][saberMoveData[newmove].startQuad]; break; //transitioning from a return @@ -445,17 +466,35 @@ int PM_SaberAnimTransitionAnim( int curmove, int newmove ) case LS_BOUNCE_LR: case LS_BOUNCE_LL: */ - //transitioning from a parry/deflection + //transitioning from a parry/reflection/knockaway/broken parry case LS_PARRY_UP: - case LS_REFLECT_UP: case LS_PARRY_UR: - case LS_REFLECT_UR: case LS_PARRY_UL: - case LS_REFLECT_UL: case LS_PARRY_LR: - case LS_REFLECT_LR: case LS_PARRY_LL: + case LS_REFLECT_UP: + case LS_REFLECT_UR: + case LS_REFLECT_UL: + case LS_REFLECT_LR: case LS_REFLECT_LL: + case LS_K1_T_: + case LS_K1_TR: + case LS_K1_TL: + case LS_K1_BR: + case LS_K1_BL: + case LS_V1_BR: + case LS_V1__R: + case LS_V1_TR: + case LS_V1_T_: + case LS_V1_TL: + case LS_V1__L: + case LS_V1_BL: + case LS_V1_B_: + case LS_H1_T_: + case LS_H1_TR: + case LS_H1_TL: + case LS_H1_BR: + case LS_H1_BL: retmove = transitionMove[saberMoveData[curmove].endQuad][saberMoveData[newmove].startQuad]; break; //NB: transitioning from transitions is fine @@ -474,7 +513,6 @@ int PM_SaberAnimTransitionAnim( int curmove, int newmove ) return retmove; } - int PM_SaberMoveQuadrantForMovement( usercmd_t *ucmd ) { if ( ucmd->rightmove > 0 ) @@ -548,12 +586,150 @@ qboolean PM_SaberInTransition( int move ) return qfalse; } -qboolean PM_SaberKataDone( void ) +int saberMoveTransitionAngle[Q_NUM_QUADS][Q_NUM_QUADS] = { - if ( (pm->ps->fd.saberAnimLevel >= FORCE_LEVEL_3 && pm->ps->saberAttackChainCount > PM_irand_timesync( 0, 1 )) || - ( pm->ps->fd.saberAnimLevel == FORCE_LEVEL_2 && pm->ps->saberAttackChainCount > PM_irand_timesync( 2, 5 ) ) ) + 0,//Q_BR,Q_BR, + 45,//Q_BR,Q_R, + 90,//Q_BR,Q_TR, + 135,//Q_BR,Q_T, + 180,//Q_BR,Q_TL, + 215,//Q_BR,Q_L, + 270,//Q_BR,Q_BL, + 45,//Q_BR,Q_B, + 45,//Q_R,Q_BR, + 0,//Q_R,Q_R, + 45,//Q_R,Q_TR, + 90,//Q_R,Q_T, + 135,//Q_R,Q_TL, + 180,//Q_R,Q_L, + 215,//Q_R,Q_BL, + 90,//Q_R,Q_B, + 90,//Q_TR,Q_BR, + 45,//Q_TR,Q_R, + 0,//Q_TR,Q_TR, + 45,//Q_TR,Q_T, + 90,//Q_TR,Q_TL, + 135,//Q_TR,Q_L, + 180,//Q_TR,Q_BL, + 135,//Q_TR,Q_B, + 135,//Q_T,Q_BR, + 90,//Q_T,Q_R, + 45,//Q_T,Q_TR, + 0,//Q_T,Q_T, + 45,//Q_T,Q_TL, + 90,//Q_T,Q_L, + 135,//Q_T,Q_BL, + 180,//Q_T,Q_B, + 180,//Q_TL,Q_BR, + 135,//Q_TL,Q_R, + 90,//Q_TL,Q_TR, + 45,//Q_TL,Q_T, + 0,//Q_TL,Q_TL, + 45,//Q_TL,Q_L, + 90,//Q_TL,Q_BL, + 135,//Q_TL,Q_B, + 215,//Q_L,Q_BR, + 180,//Q_L,Q_R, + 135,//Q_L,Q_TR, + 90,//Q_L,Q_T, + 45,//Q_L,Q_TL, + 0,//Q_L,Q_L, + 45,//Q_L,Q_BL, + 90,//Q_L,Q_B, + 270,//Q_BL,Q_BR, + 215,//Q_BL,Q_R, + 180,//Q_BL,Q_TR, + 135,//Q_BL,Q_T, + 90,//Q_BL,Q_TL, + 45,//Q_BL,Q_L, + 0,//Q_BL,Q_BL, + 45,//Q_BL,Q_B, + 45,//Q_B,Q_BR, + 90,//Q_B,Q_R, + 135,//Q_B,Q_TR, + 180,//Q_B,Q_T, + 135,//Q_B,Q_TL, + 90,//Q_B,Q_L, + 45,//Q_B,Q_BL, + 0//Q_B,Q_B, +}; + +int PM_SaberAttackChainAngle( int move1, int move2 ) +{ + if ( move1 == -1 || move2 == -1 ) { - return qtrue; + return -1; + } + return saberMoveTransitionAngle[saberMoveData[move1].endQuad][saberMoveData[move2].startQuad]; +} + +qboolean PM_SaberKataDone(int curmove, int newmove) +{ + if ( pm->ps->fd.saberAnimLevel == FORCE_LEVEL_3 ) + { + if ( curmove == LS_NONE || newmove == LS_NONE ) + { + if ( pm->ps->fd.saberAnimLevel >= FORCE_LEVEL_3 && pm->ps->saberAttackChainCount > PM_irand_timesync( 0, 1 ) ) + { + return qtrue; + } + } + else if ( pm->ps->saberAttackChainCount > PM_irand_timesync( 2, 3 ) ) + { + return qtrue; + } + else if ( pm->ps->saberAttackChainCount > 0 ) + { + int chainAngle = PM_SaberAttackChainAngle( curmove, newmove ); + if ( chainAngle < 135 || chainAngle > 215 ) + {//if trying to chain to a move that doesn't continue the momentum + return qtrue; + } + else if ( chainAngle == 180 ) + {//continues the momentum perfectly, allow it to chain 66% of the time + if ( pm->ps->saberAttackChainCount > 1 ) + { + return qtrue; + } + } + else + {//would continue the movement somewhat, 50% chance of continuing + if ( pm->ps->saberAttackChainCount > 2 ) + { + return qtrue; + } + } + } + } + else + {//FIXME: have chainAngle influence fast and medium chains as well? + if (newmove == LS_A_TL2BR || + newmove == LS_A_L2R || + newmove == LS_A_BL2TR || + newmove == LS_A_BR2TL || + newmove == LS_A_R2L || + newmove == LS_A_TR2BL ) + { //lower chaining tolerance for spinning saber anims + int chainTolerance; + + if (pm->ps->fd.saberAnimLevel == FORCE_LEVEL_1) + { + chainTolerance = 5; + } + else + { + chainTolerance = 3; + } + + if (pm->ps->saberAttackChainCount >= chainTolerance && PM_irand_timesync(1, pm->ps->saberAttackChainCount) > chainTolerance) + { + return qtrue; + } + } + if ( pm->ps->fd.saberAnimLevel == FORCE_LEVEL_2 && pm->ps->saberAttackChainCount > PM_irand_timesync( 2, 5 ) ) + { + return qtrue; + } } return qfalse; } @@ -649,6 +825,8 @@ void PM_SaberLockBreak( playerState_t *genemy, qboolean victory ) genemy->velocity[0] = oppDir[0]*(strength*40); genemy->velocity[1] = oppDir[1]*(strength*40); genemy->velocity[2] = 100; + + pm->checkDuelLoss = genemy->clientNum+1; } else { @@ -688,7 +866,7 @@ void PM_SaberLockBreak( playerState_t *genemy, qboolean victory ) } else { - if ( Q_irand( 0, 1 ) ) + if ( PM_irand_timesync( 0, 1 ) ) { BG_AddPredictableEventToPlayerstate(EV_JUMP, PM_irand_timesync( 0, 75 ), genemy); } @@ -781,7 +959,7 @@ void PM_SaberLocked( void ) remaining = anim->firstFrame+anim->numFrames-curFrame; } } - if ( !Q_irand( 0, 2 ) ) + if ( !PM_irand_timesync( 0, 2 ) ) { PM_AddEvent( EV_JUMP ); } @@ -798,7 +976,7 @@ void PM_SaberLocked( void ) if ( (genemy->torsoAnim&~ANIM_TOGGLEBIT) == BOTH_CWCIRCLELOCK || (genemy->torsoAnim&~ANIM_TOGGLEBIT) == BOTH_BF1LOCK ) { - if ( !Q_irand( 0, 2 ) ) + if ( !PM_irand_timesync( 0, 2 ) ) { BG_AddPredictableEventToPlayerstate(EV_PAIN, floor((float)80/100*100.0f), genemy); } @@ -819,6 +997,10 @@ void PM_SaberLocked( void ) qboolean PM_SaberInBrokenParry( int move ) { + if ( move >= LS_V1_BR && move <= LS_V1_B_ ) + { + return qtrue; + } if ( move >= LS_H1_T_ && move <= LS_H1_BL ) { return qtrue; @@ -932,7 +1114,7 @@ saberMoveName_t PM_SaberFlipOverAttackMove(trace_t *tr) pm->ps->fd.forceJumpSound = 1; pm->cmd.upmove = 0; - if ( Q_irand( 0, 1 ) ) + if ( PM_irand_timesync( 0, 1 ) ) { return LS_A_FLIP_STAB; } @@ -1108,7 +1290,9 @@ saberMoveName_t PM_SaberAttackForMovement(saberMoveName_t curmove) } else if ( PM_SaberInBounce( curmove ) ) {//bounces should go to their default attack if you don't specify a direction but are attacking - if ( PM_SaberKataDone() ) + newmove = saberMoveData[curmove].chain_attack; + + if ( PM_SaberKataDone(curmove, newmove) ) { newmove = saberMoveData[curmove].chain_idle; } @@ -1124,7 +1308,9 @@ saberMoveName_t PM_SaberAttackForMovement(saberMoveName_t curmove) //rww - If we don't seed with a "common" value, the client and server will get mismatched //prediction values. Under laggy conditions this will cause the appearance of rapid swing //sequence changes. - newmove = PM_irand_timesync(LS_A_TL2BR, LS_A_T2B); + + //newmove = PM_irand_timesync(LS_A_TL2BR, LS_A_T2B); + newmove = LS_A_T2B; //decided we don't like random attacks when idle, use an overhead instead. } } @@ -1252,9 +1438,12 @@ void PM_WeaponLightsaber(void) } // don't allow attack until all buttons are up + //This is bad. It freezes the attack state and the animations if you hold the button after respawning, and it looks strange. + /* if ( pm->ps->pm_flags & PMF_RESPAWNED ) { return; } + */ // check for dead player if ( pm->ps->stats[STAT_HEALTH] <= 0 ) { @@ -1306,6 +1495,13 @@ void PM_WeaponLightsaber(void) switch ( pm->ps->saberBlocked ) { + case BLOCKED_BOUNCE_MOVE: + { //act as a bounceMove and reset the saberMove instead of using a seperate value for it + PM_SetSaberMove( pm->ps->saberMove ); + pm->ps->weaponTime = pm->ps->torsoTimer; + pm->ps->saberBlocked = 0; + } + break; case BLOCKED_PARRY_BROKEN: //whatever parry we were is in now broken, play the appropriate knocked-away anim { @@ -1326,6 +1522,10 @@ void PM_WeaponLightsaber(void) } else {//Maybe in a knockaway? + if (pm->ps->weaponTime <= 0) + { + pm->ps->saberBlocked = 0; + } } } break; @@ -1584,7 +1784,7 @@ weapChecks: if ( anim == -1 ) { //FIXME: take FP_SABER_OFFENSE into account here somehow? - if ( curmove >= LS_T1_BR__R && curmove <= LS_T1_BL__L ) + if ( PM_SaberInTransition( curmove ) ) {//in a transition, must play sequential attack newmove = saberMoveData[curmove].chain_attack; } @@ -1592,13 +1792,35 @@ weapChecks: {//started a swing, must continue from here newmove = LS_A_TL2BR + (curmove-LS_S_TL2BR); } - else - { + else if ( PM_SaberInBrokenParry( curmove ) ) + {//broken parries must always return to ready + newmove = LS_READY; + } + else//if ( pm->cmd.buttons&BUTTON_ATTACK && !(pm->ps->pm_flags&PMF_ATTACK_HELD) )//only do this if just pressed attack button? + {//get attack move from movement command + /* if ( PM_SaberKataDone() ) {//we came from a bounce and cannot chain to another attack because our kata is done newmove = saberMoveData[curmove].chain_idle; } - else + else */ + saberMoveName_t checkMove = PM_SaberAttackForMovement(curmove); + if (checkMove != -1) + { + newmove = checkMove; + } + + if ( (PM_SaberInBounce( curmove )||PM_SaberInBrokenParry( curmove )) + && saberMoveData[newmove].startQuad == saberMoveData[curmove].endQuad ) + {//this attack would be a repeat of the last (which was blocked), so don't actually use it, use the default chain attack for this bounce + newmove = saberMoveData[curmove].chain_attack; + } + + if ( PM_SaberKataDone(curmove, newmove) ) + {//we came from a bounce and cannot chain to another attack because our kata is done + newmove = saberMoveData[curmove].chain_idle; + } + /*else { saberMoveName_t checkMove = PM_SaberAttackForMovement(curmove); if (checkMove != -1) @@ -1606,6 +1828,7 @@ weapChecks: newmove = checkMove; } } + */ } /* if ( newmove == LS_NONE ) @@ -1665,6 +1888,11 @@ weapChecks: { anim = PM_GetSaberStance(); } + + if (anim == BOTH_RUN2 && !pm->cmd.forwardmove && !pm->cmd.rightmove) + { //semi-hacky + anim = PM_GetSaberStance(); + } newmove = LS_READY; } @@ -1709,8 +1937,8 @@ void PM_SetSaberMove(short newMove) int anim = saberMoveData[newMove].animToUse; int parts = SETANIM_TORSO; - if ( newMove == LS_READY ) - {//finished with a kata, reset attack counter + if ( newMove == LS_READY || newMove == LS_A_FLIP_STAB || newMove == LS_A_FLIP_SLASH ) + {//finished with a kata (or in a special move) reset attack counter pm->ps->saberAttackChainCount = 0; } else if ( BG_SaberInAttack( newMove ) ) @@ -1724,13 +1952,10 @@ void PM_SetSaberMove(short newMove) } if ( pm->ps->fd.saberAnimLevel > FORCE_LEVEL_1 && - !BG_SaberInIdle( newMove ) && !PM_SaberInParry( newMove ) && !PM_SaberInReflect( newMove ) && !BG_SaberInSpecial(newMove)) + !BG_SaberInIdle( newMove ) && !PM_SaberInParry( newMove ) && !PM_SaberInKnockaway( newMove ) && !PM_SaberInBrokenParry( newMove ) && !PM_SaberInReflect( newMove ) && !BG_SaberInSpecial(newMove)) {//readies, parries and reflections have only 1 level //increment the anim to the next level of saber anims - if ( !PM_SaberInTransition( newMove ) ) - {//FIXME: only have level 1 transitions for now - anim += (pm->ps->fd.saberAnimLevel-FORCE_LEVEL_1) * SABER_ANIM_GROUP_SIZE; - } + anim += (pm->ps->fd.saberAnimLevel-FORCE_LEVEL_1) * SABER_ANIM_GROUP_SIZE; } // If the move does the same animation as the last one, we need to force a restart... @@ -1739,8 +1964,17 @@ void PM_SetSaberMove(short newMove) setflags |= SETANIM_FLAG_RESTART; } - //saber torso anims should always be highest priority - setflags |= SETANIM_FLAG_OVERRIDE; + //saber torso anims should always be highest priority (4/12/02 - for special anims only) + if ( newMove == LS_A_LUNGE + || newMove == LS_A_JUMP_T__B_ + || newMove == LS_A_BACKSTAB + || newMove == LS_A_BACK + || newMove == LS_A_BACK_CR + || newMove == LS_A_FLIP_STAB + || newMove == LS_A_FLIP_SLASH ) + { + setflags |= SETANIM_FLAG_OVERRIDE; + } if ( BG_InSaberStandAnim(anim) || anim == BOTH_STAND1 ) { @@ -1779,7 +2013,24 @@ void PM_SetSaberMove(short newMove) {//spins must be played on entire body parts = SETANIM_BOTH; } - PM_SetAnim(parts, anim, setflags|SETANIM_FLAG_HOLD, saberMoveData[newMove].blendTime); + else if ( (!pm->cmd.forwardmove&&!pm->cmd.rightmove&&!pm->cmd.upmove)) + {//not trying to run, duck or jump + if ( !BG_FlippingAnim( pm->ps->legsAnim ) && + !BG_InRoll( pm->ps, pm->ps->legsAnim ) && + !PM_InKnockDown( pm->ps ) && + !PM_JumpingAnim( pm->ps->legsAnim ) && + !BG_InSpecialJump( pm->ps->legsAnim ) && + anim != PM_GetSaberStance() && + //!PM_CrouchAnim( pm->ps->legsAnim ) && + //pm->cmd.upmove >= 0 && + pm->ps->groundEntityNum != ENTITYNUM_NONE && + !(pm->ps->pm_flags & PMF_DUCKED)) + { + parts = SETANIM_BOTH; + } + } + + PM_SetAnim(parts, anim, setflags, saberMoveData[newMove].blendTime); if ( (pm->ps->torsoAnim&~ANIM_TOGGLEBIT) == anim ) {//successfully changed anims diff --git a/CODE-mp/game/bg_weapons.c b/CODE-mp/game/bg_weapons.c index eeafe2b..a85ed6d 100644 --- a/CODE-mp/game/bg_weapons.c +++ b/CODE-mp/game/bg_weapons.c @@ -153,7 +153,7 @@ weaponData_t weaponData[WP_NUM_WEAPONS] = 1, // int energyPerShot; // Amount of energy used per shot 100, // int fireTime; // Amount of time between firings 8192, // int range; // Range of weapon - 8, // int altEnergyPerShot; // Amount of energy used for alt-fire + 25, // int altEnergyPerShot; // Amount of energy used for alt-fire 800, // int altFireTime; // Amount of time between alt-firings 8192, // int altRange; // Range of alt-fire 0, // int chargeSubTime; // ms interval for subtracting ammo during charge @@ -187,7 +187,7 @@ weaponData_t weaponData[WP_NUM_WEAPONS] = 10, // int energyPerShot; // Amount of energy used per shot 700, // int fireTime; // Amount of time between firings 8192, // int range; // Range of weapon - 15, // int altEnergyPerShot; // Amount of energy used for alt-fire + 25, // int altEnergyPerShot; // Amount of energy used for alt-fire 800, // int altFireTime; // Amount of time between alt-firings 8192, // int altRange; // Range of alt-fire 0, // int chargeSubTime; // ms interval for subtracting ammo during charge diff --git a/CODE-mp/game/g_active.c b/CODE-mp/game/g_active.c index 7a50337..ace3bf4 100644 --- a/CODE-mp/game/g_active.c +++ b/CODE-mp/game/g_active.c @@ -3,6 +3,10 @@ #include "g_local.h" +qboolean PM_SaberInTransition( int move ); +qboolean PM_SaberInStart( int move ); +qboolean PM_SaberInReturn( int move ); + void P_SetTwitchInfo(gclient_t *client) { client->ps.painTime = level.time; @@ -1362,10 +1366,47 @@ void ClientThink_real( gentity_t *ent ) { else { ent->client->ps.saberLockFrame = 0; + //check for taunt + if ( (pm.cmd.generic_cmd == GENCMD_ENGAGE_DUEL) && (g_gametype.integer == GT_TOURNAMENT) ) + {//already in a duel, make it a taunt command + pm.cmd.buttons |= BUTTON_GESTURE; + } } Pmove (&pm); + if (pm.checkDuelLoss) + { + if (pm.checkDuelLoss > 0 && pm.checkDuelLoss <= MAX_CLIENTS) + { + gentity_t *clientLost = &g_entities[pm.checkDuelLoss-1]; + + if (clientLost && clientLost->inuse && clientLost->client && Q_irand(0, 40) > clientLost->health) + { + vec3_t attDir; + VectorSubtract(ent->client->ps.origin, clientLost->client->ps.origin, attDir); + VectorNormalize(attDir); + + VectorClear(clientLost->client->ps.velocity); + clientLost->client->ps.forceHandExtend = HANDEXTEND_NONE; + clientLost->client->ps.forceHandExtendTime = 0; + + gGAvoidDismember = 1; + G_Damage(clientLost, ent, ent, attDir, clientLost->client->ps.origin, 9999, DAMAGE_NO_PROTECTION, MOD_SABER); + + if (clientLost->health < 1) + { + gGAvoidDismember = 2; + G_CheckForDismemberment(clientLost, clientLost->client->ps.origin, 999, (clientLost->client->ps.legsAnim&~ANIM_TOGGLEBIT)); + } + + gGAvoidDismember = 0; + } + } + + pm.checkDuelLoss = 0; + } + switch(pm.cmd.generic_cmd) { case 0: @@ -1374,7 +1415,13 @@ void ClientThink_real( gentity_t *ent ) { Cmd_ToggleSaber_f(ent); break; case GENCMD_ENGAGE_DUEL: - Cmd_EngageDuel_f(ent); + if ( g_gametype.integer == GT_TOURNAMENT ) + {//already in a duel, made it a taunt command + } + else + { + Cmd_EngageDuel_f(ent); + } break; case GENCMD_FORCE_HEAL: ForceHeal(ent); @@ -1561,24 +1608,29 @@ void ClientThink_real( gentity_t *ent ) { G_Damage( faceKicked, ent, ent, oppDir, client->ps.origin, strength, DAMAGE_NO_ARMOR, MOD_MELEE ); - if (faceKicked->health > 0 && - faceKicked->client->ps.stats[STAT_HEALTH] > 0 && - faceKicked->client->ps.forceHandExtend != HANDEXTEND_KNOCKDOWN) + if ( faceKicked->client->ps.weapon != WP_SABER || + faceKicked->client->ps.fd.saberAnimLevel < FORCE_LEVEL_3 || + (!BG_SaberInAttack(faceKicked->client->ps.saberMove) && !PM_SaberInStart(faceKicked->client->ps.saberMove) && !PM_SaberInReturn(faceKicked->client->ps.saberMove) && !PM_SaberInTransition(faceKicked->client->ps.saberMove)) ) { - if (Q_irand(1, 10) <= 3) - { //only actually knock over sometimes, but always do velocity hit - faceKicked->client->ps.forceHandExtend = HANDEXTEND_KNOCKDOWN; - faceKicked->client->ps.forceHandExtendTime = level.time + 1100; - faceKicked->client->ps.forceDodgeAnim = 0; //this toggles between 1 and 0, when it's 1 we should play the get up anim + if (faceKicked->health > 0 && + faceKicked->client->ps.stats[STAT_HEALTH] > 0 && + faceKicked->client->ps.forceHandExtend != HANDEXTEND_KNOCKDOWN) + { + if (Q_irand(1, 10) <= 3) + { //only actually knock over sometimes, but always do velocity hit + faceKicked->client->ps.forceHandExtend = HANDEXTEND_KNOCKDOWN; + faceKicked->client->ps.forceHandExtendTime = level.time + 1100; + faceKicked->client->ps.forceDodgeAnim = 0; //this toggles between 1 and 0, when it's 1 we should play the get up anim + } + + faceKicked->client->ps.otherKiller = ent->s.number; + faceKicked->client->ps.otherKillerTime = level.time + 5000; + faceKicked->client->ps.otherKillerDebounceTime = level.time + 100; + + faceKicked->client->ps.velocity[0] = oppDir[0]*(strength*40); + faceKicked->client->ps.velocity[1] = oppDir[1]*(strength*40); + faceKicked->client->ps.velocity[2] = 200; } - - faceKicked->client->ps.otherKiller = ent->s.number; - faceKicked->client->ps.otherKillerTime = level.time + 5000; - faceKicked->client->ps.otherKillerDebounceTime = level.time + 100; - - faceKicked->client->ps.velocity[0] = oppDir[0]*(strength*40); - faceKicked->client->ps.velocity[1] = oppDir[1]*(strength*40); - faceKicked->client->ps.velocity[2] = 200; } G_Sound( faceKicked, CHAN_AUTO, G_SoundIndex( va("sound/weapons/melee/punch%d", Q_irand(1, 4)) ) ); diff --git a/CODE-mp/game/g_bot.c b/CODE-mp/game/g_bot.c index a42679d..8a6f8ef 100644 --- a/CODE-mp/game/g_bot.c +++ b/CODE-mp/game/g_bot.c @@ -338,7 +338,7 @@ const char *G_GetArenaInfoByMap( const char *map ) { return NULL; } - +#if 0 /* ================= PlayerIntroSound @@ -363,6 +363,7 @@ static void PlayerIntroSound( const char *modelAndSkin ) { trap_SendConsoleCommand( EXEC_APPEND, va( "play sound/player/announce/%s.wav\n", skin ) ); } +#endif /* =============== @@ -619,7 +620,6 @@ G_CheckBotSpawn */ void G_CheckBotSpawn( void ) { int n; - char userinfo[MAX_INFO_VALUE]; G_CheckMinimumPlayers(); @@ -633,10 +633,12 @@ void G_CheckBotSpawn( void ) { ClientBegin( botSpawnQueue[n].clientNum, qfalse ); botSpawnQueue[n].spawnTime = 0; + /* if( g_gametype.integer == GT_SINGLE_PLAYER ) { trap_GetUserinfo( botSpawnQueue[n].clientNum, userinfo, sizeof(userinfo) ); PlayerIntroSound( Info_ValueForKey (userinfo, "model") ); } + */ } } @@ -992,7 +994,7 @@ void Svcmd_BotList_f( void ) { } } - +#if 0 /* =============== G_SpawnBots @@ -1049,6 +1051,7 @@ static void G_SpawnBots( char *botList, int baseDelay ) { delay += BOT_BEGIN_DELAY_INCREMENT; } } +#endif /* @@ -1165,14 +1168,6 @@ G_InitBots =============== */ void G_InitBots( qboolean restart ) { - int fragLimit; - int timeLimit; - const char *arenainfo; - char *strValue; - int basedelay; - char map[MAX_QPATH]; - char serverinfo[MAX_INFO_STRING]; - G_LoadBots(); G_LoadArenas(); @@ -1181,46 +1176,4 @@ void G_InitBots( qboolean restart ) { //rww - new bot route stuff LoadPath_ThisLevel(); //end rww - - if( g_gametype.integer == GT_SINGLE_PLAYER ) { - trap_GetServerinfo( serverinfo, sizeof(serverinfo) ); - Q_strncpyz( map, Info_ValueForKey( serverinfo, "mapname" ), sizeof(map) ); - arenainfo = G_GetArenaInfoByMap( map ); - if ( !arenainfo ) { - return; - } - - strValue = Info_ValueForKey( arenainfo, "fraglimit" ); - fragLimit = atoi( strValue ); - if ( fragLimit ) { - trap_Cvar_Set( "fraglimit", strValue ); - } - else { - trap_Cvar_Set( "fraglimit", "0" ); - } - - strValue = Info_ValueForKey( arenainfo, "timelimit" ); - timeLimit = atoi( strValue ); - if ( timeLimit ) { - trap_Cvar_Set( "timelimit", strValue ); - } - else { - trap_Cvar_Set( "timelimit", "0" ); - } - - if ( !fragLimit && !timeLimit ) { - trap_Cvar_Set( "fraglimit", "10" ); - trap_Cvar_Set( "timelimit", "0" ); - } - - basedelay = BOT_BEGIN_DELAY_BASE; - strValue = Info_ValueForKey( arenainfo, "special" ); - if( Q_stricmp( strValue, "training" ) == 0 ) { - basedelay += 10000; - } - - if( !restart ) { - G_SpawnBots( Info_ValueForKey( arenainfo, "bots" ), basedelay ); - } - } } diff --git a/CODE-mp/game/g_client.c b/CODE-mp/game/g_client.c index 837badd..b5b250e 100644 --- a/CODE-mp/game/g_client.c +++ b/CODE-mp/game/g_client.c @@ -769,6 +769,15 @@ void respawn( gentity_t *ent ) { CopyToBodyQue (ent); + if (gEscaping) + { + ent->client->sess.sessionTeam = TEAM_SPECTATOR; + ent->client->sess.spectatorState = SPECTATOR_FREE; + ent->client->sess.spectatorClient = 0; + + ent->client->pers.teamState.state = TEAM_BEGIN; + } + trap_UnlinkEntity (ent); ClientSpawn(ent); @@ -1268,7 +1277,7 @@ void ClientUserinfoChanged( int clientNum ) { trap_SetConfigstring( CS_PLAYERS+clientNum, s ); - G_LogPrintf( "ClientUserinfoChanged: %i %s\n", clientNum, s ); + //G_LogPrintf( "ClientUserinfoChanged: %i %s\n", clientNum, s ); } @@ -1315,7 +1324,9 @@ char *ClientConnect( int clientNum, qboolean firstTime, qboolean isBot ) { value = Info_ValueForKey (userinfo, "password"); if ( g_password.string[0] && Q_stricmp( g_password.string, "none" ) && strcmp( g_password.string, value) != 0) { - return "Invalid password"; + static char sTemp[1024]; + Q_strncpyz(sTemp, G_GetStripEdString("SVINGAME","INVALID_PASSWORD"), sizeof (sTemp) ); + return sTemp;// return "Invalid password"; } } @@ -1524,6 +1535,26 @@ void ClientBegin( int clientNum, qboolean allowTeamReset ) { G_ClearClientLog(clientNum); } +static qboolean AllForceDisabled(int force) +{ + int i; + + if (force) + { + for (i=0;ips.stats[STAT_WEAPONS] = ( 1 << WP_NONE ); - if (g_gametype.integer == GT_HOLOCRON) - { - //always get free saber level 1 in holocron - client->ps.stats[STAT_WEAPONS] |= ( 1 << WP_SABER ); //these are precached in g_items, ClearRegisteredItems() - } - else - { - if (client->ps.fd.forcePowerLevel[FP_SABERATTACK]) - { - client->ps.stats[STAT_WEAPONS] |= ( 1 << WP_SABER ); //these are precached in g_items, ClearRegisteredItems() - } - else - { //if you don't have saber attack rank then you don't get a saber - client->ps.stats[STAT_WEAPONS] |= (1 << WP_STUN_BATON); - } - } - if (g_gametype.integer == GT_TOURNAMENT) { wDisable = g_duelWeaponDisable.integer; @@ -1719,32 +1734,81 @@ void ClientSpawn(gentity_t *ent) { wDisable = g_weaponDisable.integer; } - if (!wDisable || !(wDisable & (1 << WP_BRYAR_PISTOL))) - { - client->ps.stats[STAT_WEAPONS] |= ( 1 << WP_BRYAR_PISTOL ); - } - else if (g_gametype.integer == GT_JEDIMASTER) - { - client->ps.stats[STAT_WEAPONS] |= ( 1 << WP_BRYAR_PISTOL ); - } - if (g_gametype.integer == GT_JEDIMASTER) - { - client->ps.stats[STAT_WEAPONS] &= ~(1 << WP_SABER); - client->ps.stats[STAT_WEAPONS] |= (1 << WP_STUN_BATON); - } - if (client->ps.stats[STAT_WEAPONS] & (1 << WP_BRYAR_PISTOL)) + if ( g_gametype.integer != GT_HOLOCRON + && g_gametype.integer != GT_JEDIMASTER + && !HasSetSaberOnly() + && !AllForceDisabled( g_forcePowerDisable.integer ) + && g_trueJedi.integer ) { - client->ps.weapon = WP_BRYAR_PISTOL; - } - else if (client->ps.stats[STAT_WEAPONS] & (1 << WP_SABER)) - { - client->ps.weapon = WP_SABER; + if ( WP_HasForcePowers( &client->ps ) ) + { + client->ps.trueNonJedi = qfalse; + client->ps.trueJedi = qtrue; + //make sure they only use the saber + client->ps.weapon = WP_SABER; + client->ps.stats[STAT_WEAPONS] = (1 << WP_SABER); + } + else + {//no force powers set + client->ps.trueNonJedi = qtrue; + client->ps.trueJedi = qfalse; + if (!wDisable || !(wDisable & (1 << WP_BRYAR_PISTOL))) + { + client->ps.stats[STAT_WEAPONS] |= ( 1 << WP_BRYAR_PISTOL ); + } + client->ps.stats[STAT_WEAPONS] &= ~(1 << WP_SABER); + client->ps.stats[STAT_WEAPONS] |= (1 << WP_STUN_BATON); + client->ps.weapon = WP_BRYAR_PISTOL; + } } else { - client->ps.weapon = WP_STUN_BATON; + if (g_gametype.integer == GT_HOLOCRON) + { + //always get free saber level 1 in holocron + client->ps.stats[STAT_WEAPONS] |= ( 1 << WP_SABER ); //these are precached in g_items, ClearRegisteredItems() + } + else + { + if (client->ps.fd.forcePowerLevel[FP_SABERATTACK]) + { + client->ps.stats[STAT_WEAPONS] |= ( 1 << WP_SABER ); //these are precached in g_items, ClearRegisteredItems() + } + else + { //if you don't have saber attack rank then you don't get a saber + client->ps.stats[STAT_WEAPONS] |= (1 << WP_STUN_BATON); + } + } + + if (!wDisable || !(wDisable & (1 << WP_BRYAR_PISTOL))) + { + client->ps.stats[STAT_WEAPONS] |= ( 1 << WP_BRYAR_PISTOL ); + } + else if (g_gametype.integer == GT_JEDIMASTER) + { + client->ps.stats[STAT_WEAPONS] |= ( 1 << WP_BRYAR_PISTOL ); + } + + if (g_gametype.integer == GT_JEDIMASTER) + { + client->ps.stats[STAT_WEAPONS] &= ~(1 << WP_SABER); + client->ps.stats[STAT_WEAPONS] |= (1 << WP_STUN_BATON); + } + + if (client->ps.stats[STAT_WEAPONS] & (1 << WP_BRYAR_PISTOL)) + { + client->ps.weapon = WP_BRYAR_PISTOL; + } + else if (client->ps.stats[STAT_WEAPONS] & (1 << WP_SABER)) + { + client->ps.weapon = WP_SABER; + } + else + { + client->ps.weapon = WP_STUN_BATON; + } } /* @@ -1950,12 +2014,20 @@ void ClientDisconnect( int clientNum ) { G_LogPrintf( "ClientDisconnect: %i\n", clientNum ); - // if we are playing in tourney mode and losing, give a win to the other player + // if we are playing in tourney mode, give a win to the other player and clear his frags for this round if ( (g_gametype.integer == GT_TOURNAMENT ) && !level.intermissiontime - && !level.warmupTime && level.sortedClients[1] == clientNum ) { - level.clients[ level.sortedClients[0] ].sess.wins++; - ClientUserinfoChanged( level.sortedClients[0] ); + && !level.warmupTime ) { + if ( level.sortedClients[1] == clientNum ) { + level.clients[ level.sortedClients[0] ].ps.persistant[PERS_SCORE] = 0; + level.clients[ level.sortedClients[0] ].sess.wins++; + ClientUserinfoChanged( level.sortedClients[0] ); + } + else if ( level.sortedClients[0] == clientNum ) { + level.clients[ level.sortedClients[1] ].ps.persistant[PERS_SCORE] = 0; + level.clients[ level.sortedClients[1] ].sess.wins++; + ClientUserinfoChanged( level.sortedClients[1] ); + } } trap_UnlinkEntity (ent); diff --git a/CODE-mp/game/g_cmds.c b/CODE-mp/game/g_cmds.c index f746abf..b2c6c9d 100644 --- a/CODE-mp/game/g_cmds.c +++ b/CODE-mp/game/g_cmds.c @@ -748,7 +748,9 @@ void SetTeam( gentity_t *ent, char *s ) { } // they go to the end of the line for tournements if ( team == TEAM_SPECTATOR ) { - client->sess.spectatorTime = level.time; + if ( (g_gametype.integer != GT_TOURNAMENT) || (oldTeam != TEAM_SPECTATOR) ) {//so you don't get dropped to the bottom of the queue for changing skins, etc. + client->sess.spectatorTime = level.time; + } } client->sess.sessionTeam = team; @@ -827,10 +829,19 @@ void Cmd_Team_f( gentity_t *ent ) { return; } + if (gEscaping) + { + return; + } + // if they are playing a tournement game, count as a loss if ( (g_gametype.integer == GT_TOURNAMENT ) - && ent->client->sess.sessionTeam == TEAM_FREE ) { - ent->client->sess.losses++; + && ent->client->sess.sessionTeam == TEAM_FREE ) {//in a tournament game + //disallow changing teams + trap_SendServerCommand( ent-g_entities, "print \"Cannot switch teams in Duel\n\"" ); + return; + //FIXME: why should this be a loss??? + //ent->client->sess.losses++; } trap_Argv( 1, s, sizeof( s ) ); @@ -862,10 +873,15 @@ void Cmd_ForceChanged_f( gentity_t *ent ) strcpy(fpChStr, buf); - trap_SendServerCommand( ent-g_entities, va("print \"%s%s\n\"", S_COLOR_GREEN, fpChStr) ); + trap_SendServerCommand( ent-g_entities, va("print \"%s%s\n\n\"", S_COLOR_GREEN, fpChStr) ); ent->client->ps.fd.forceDoInit = 1; argCheck: + if (g_gametype.integer == GT_TOURNAMENT) + { //If this is duel, don't even bother changing team in relation to this. + return; + } + if (trap_Argc() > 1) { char arg[MAX_TOKEN_CHARS]; @@ -914,6 +930,7 @@ void Cmd_Follow_f( gentity_t *ent ) { // if they are playing a tournement game, count as a loss if ( (g_gametype.integer == GT_TOURNAMENT ) && ent->client->sess.sessionTeam == TEAM_FREE ) { + //WTF??? ent->client->sess.losses++; } @@ -937,7 +954,8 @@ void Cmd_FollowCycle_f( gentity_t *ent, int dir ) { // if they are playing a tournement game, count as a loss if ( (g_gametype.integer == GT_TOURNAMENT ) - && ent->client->sess.sessionTeam == TEAM_FREE ) { + && ent->client->sess.sessionTeam == TEAM_FREE ) {\ + //WTF??? ent->client->sess.losses++; } // first set them to spectator @@ -1006,6 +1024,7 @@ static void G_SayTo( gentity_t *ent, gentity_t *other, int mode, int color, cons if ( (g_gametype.integer == GT_TOURNAMENT ) && other->client->sess.sessionTeam == TEAM_FREE && ent->client->sess.sessionTeam != TEAM_FREE ) { + //Hmm, maybe some option to do so if allowed? Or at least in developer mode... return; } @@ -1925,6 +1944,11 @@ void Cmd_ToggleSaber_f(gentity_t *ent) return; } + if (ent->client->ps.saberLockTime >= level.time) + { + return; + } + if (ent->client && ent->client->ps.weaponTime < 1) { if (ent->client->ps.saberHolstered) @@ -2150,6 +2174,93 @@ void Cmd_EngageDuel_f(gentity_t *ent) } } +#ifdef _DEBUG +extern stringID_table_t animTable[MAX_ANIMATIONS+1]; +void PM_SetAnim(int setAnimParts,int anim,int setAnimFlags, int blendTime); + +void Cmd_DebugSetSaberMove_f(gentity_t *self) +{ + int argNum = trap_Argc(); + char arg[MAX_STRING_CHARS]; + + if (argNum < 2) + { + return; + } + + trap_Argv( 1, arg, sizeof( arg ) ); + + if (!arg[0]) + { + return; + } + + self->client->ps.saberMove = atoi(arg); + self->client->ps.saberBlocked = BLOCKED_BOUNCE_MOVE; + + if (self->client->ps.saberMove >= LS_MOVE_MAX) + { + self->client->ps.saberMove = LS_MOVE_MAX-1; + } + + Com_Printf("Anim for move: %s\n", animTable[saberMoveData[self->client->ps.saberMove].animToUse].name); +} + +void Cmd_DebugSetBodyAnim_f(gentity_t *self) +{ + int argNum = trap_Argc(); + char arg[MAX_STRING_CHARS]; + int i = 0; + pmove_t pmv; + + if (argNum < 2) + { + return; + } + + trap_Argv( 1, arg, sizeof( arg ) ); + + if (!arg[0]) + { + return; + } + + while (i < MAX_ANIMATIONS) + { + if (!Q_stricmp(arg, animTable[i].name)) + { + break; + } + i++; + } + + if (i == MAX_ANIMATIONS) + { + Com_Printf("Animation '%s' does not exist\n", arg); + return; + } + + memset (&pmv, 0, sizeof(pmv)); + pmv.ps = &self->client->ps; + pmv.animations = bgGlobalAnimations; + pmv.cmd = self->client->pers.cmd; + pmv.trace = trap_Trace; + pmv.pointcontents = trap_PointContents; + pmv.gametype = g_gametype.integer; + + pm = &pmv; + PM_SetAnim(SETANIM_BOTH, i, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD, 0); + + Com_Printf("Set body anim to %s\n", arg); +} +#endif + +void DismembermentTest(gentity_t *self); + +#ifdef _DEBUG +void DismembermentByNum(gentity_t *self, int num); +#endif + /* ================= ClientCommand @@ -2359,10 +2470,29 @@ void ClientCommand( int clientNum ) { Cmd_SetViewpos_f( ent ); else if (Q_stricmp (cmd, "stats") == 0) Cmd_Stats_f( ent ); + /* else if (Q_stricmp(cmd, "#mm") == 0 && CheatsOk( ent )) { G_PlayerBecomeATST(ent); } + */ + //I broke the ATST when I restructured it to use a single global anim set for all client animation. + //You can fix it, but you'll have to implement unique animations (per character) again. + else if (Q_stricmp(cmd, "headexplodey") == 0 && CheatsOk( ent )) + { + Cmd_Kill_f (ent); + if (ent->health < 1) + { + float presaveVel = ent->client->ps.velocity[2]; + ent->client->ps.velocity[2] = 500; + DismembermentTest(ent); + ent->client->ps.velocity[2] = presaveVel; + } + } + else if (Q_stricmp(cmd, "g2animent") == 0 && CheatsOk( ent )) + { + G_CreateExampleAnimEnt(ent); + } else if (Q_stricmp(cmd, "thedestroyer") == 0 && CheatsOk( ent ) && ent && ent->client && ent->client->ps.saberHolstered && ent->client->ps.weapon == WP_SABER) { Cmd_ToggleSaber_f(ent); @@ -2385,39 +2515,43 @@ void ClientCommand( int clientNum ) { } } #ifdef _DEBUG - else if (Q_stricmp(cmd, "gotocoord") == 0 && CheatsOk( ent )) + else if (Q_stricmp(cmd, "debugSetSaberMove") == 0) { - char x[64], y[64], z[64]; - vec3_t xyz; - - if (trap_Argc() < 3) + Cmd_DebugSetSaberMove_f(ent); + } + else if (Q_stricmp(cmd, "debugSetBodyAnim") == 0) + { + Cmd_DebugSetBodyAnim_f(ent); + } + else if (Q_stricmp(cmd, "debugDismemberment") == 0) + { + Cmd_Kill_f (ent); + if (ent->health < 1) { - return; + char arg[MAX_STRING_CHARS]; + int iArg = 0; + + if (trap_Argc() > 1) + { + trap_Argv( 1, arg, sizeof( arg ) ); + + if (arg[0]) + { + iArg = atoi(arg); + } + } + + DismembermentByNum(ent, iArg); } - - trap_Argv( 1, x, sizeof( x ) ); - trap_Argv( 2, y, sizeof( y ) ); - trap_Argv( 3, z, sizeof( z ) ); - - xyz[0] = atof(x); - xyz[1] = atof(y); - xyz[2] = atof(z); - - VectorCopy(xyz, ent->client->ps.origin); } #endif - /* - else if (Q_stricmp (cmd, "offwithmyhead") == 0) - { - DismembermentTest(ent); - } - */ else { if (Q_stricmp(cmd, "addbot") == 0) { //because addbot isn't a recognized command unless you're the server, but it is in the menus regardless - trap_SendServerCommand( clientNum, va("print \"You can only add bots as the server.\n\"" ) ); +// trap_SendServerCommand( clientNum, va("print \"You can only add bots as the server.\n\"" ) ); + trap_SendServerCommand( clientNum, va("print \"%s.\n\"", G_GetStripEdString("SVINGAME", "ONLY_ADD_BOTS_AS_SERVER"))); } else { diff --git a/CODE-mp/game/g_combat.c b/CODE-mp/game/g_combat.c index ebd03f2..3c55228 100644 --- a/CODE-mp/game/g_combat.c +++ b/CODE-mp/game/g_combat.c @@ -890,24 +890,60 @@ void CheckAlmostCapture( gentity_t *self, gentity_t *attacker ) { #endif } -static int G_PickDeathAnim( gentity_t *self, vec3_t point, int damage, int mod, int hitLoc ) +int G_PickDeathAnim( gentity_t *self, vec3_t point, int damage, int mod, int hitLoc ) {//FIXME: play dead flop anims on body if in an appropriate _DEAD anim when this func is called int deathAnim = -1; int max_health; + int legAnim = 0; + vec3_t objVelocity; if (!self || !self->client) { - return 0; + if (!self || self->s.eType != ET_GRAPPLE) + { //g2animent + return 0; + } } - max_health = self->client->ps.stats[STAT_MAX_HEALTH]; + if (self->client) + { + max_health = self->client->ps.stats[STAT_MAX_HEALTH]; + } + else + { + max_health = 60; + } + + if (self->client) + { + VectorCopy(self->client->ps.velocity, objVelocity); + } + else + { + VectorCopy(self->s.pos.trDelta, objVelocity); + } if ( hitLoc == HL_NONE ) { hitLoc = G_GetHitLocation( self, point );//self->hitLoc } + + if (self->client) + { + legAnim = self->client->ps.legsAnim; + } + else + { + legAnim = self->s.legsAnim; + } + + if (gGAvoidDismember) + { + return BOTH_RIGHTHANDCHOPPEDOFF; + } + //dead flops - switch( self->client->ps.legsAnim&~ANIM_TOGGLEBIT ) + switch( legAnim&~ANIM_TOGGLEBIT ) { case BOTH_DEATH1: //# First Death anim case BOTH_DEAD1: @@ -1051,7 +1087,7 @@ static int G_PickDeathAnim( gentity_t *self, vec3_t point, int damage, int mod, } break; case HL_BACK: - if ( !VectorLengthSquared( self->client->ps.velocity ) ) + if ( !VectorLengthSquared( objVelocity ) ) { deathAnim = BOTH_DEATH17;//head/back: croak } @@ -1155,7 +1191,7 @@ static int G_PickDeathAnim( gentity_t *self, vec3_t point, int damage, int mod, break; case HL_CHEST: case HL_WAIST: - if ( damage <= max_health*0.25 || !VectorLengthSquared( self->client->ps.velocity ) ) + if ( damage <= max_health*0.25 || !VectorLengthSquared( objVelocity ) ) { if ( !Q_irand( 0, 1 ) ) { @@ -1203,8 +1239,6 @@ static int G_PickDeathAnim( gentity_t *self, vec3_t point, int damage, int mod, return deathAnim; } -void G_CheckForDismemberment(gentity_t *ent, vec3_t point, int damage, int deathAnim); - gentity_t *G_GetJediMaster(void) { int i = 0; @@ -1230,6 +1264,7 @@ gentity_t *G_GetJediMaster(void) player_die ================== */ +extern stringID_table_t animTable[MAX_ANIMATIONS+1]; void player_die( gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int damage, int meansOfDeath ) { gentity_t *ent; int anim; @@ -1305,6 +1340,25 @@ void player_die( gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int killer, self->s.number, meansOfDeath, killerName, self->client->pers.netname, obit ); + if ( g_austrian.integer + && g_gametype.integer == GT_TOURNAMENT + && level.numPlayingClients >= 2 ) + { + int spawnTime = (level.clients[level.sortedClients[0]].respawnTime > level.clients[level.sortedClients[1]].respawnTime) ? level.clients[level.sortedClients[0]].respawnTime : level.clients[level.sortedClients[1]].respawnTime; + G_LogPrintf("Duel Kill Details:\n"); + G_LogPrintf("Kill Time: %d\n", level.time-spawnTime ); + G_LogPrintf("victim: %s, hits on enemy %d\n", self->client->pers.netname, self->client->ps.persistant[PERS_HITS] ); + if ( attacker && attacker->client ) + { + G_LogPrintf("killer: %s, hits on enemy %d, health: %d\n", attacker->client->pers.netname, attacker->client->ps.persistant[PERS_HITS], attacker->health ); + //also - if MOD_SABER, list the animation and saber style + if ( meansOfDeath == MOD_SABER ) + { + G_LogPrintf("killer saber style: %d, killer saber anim %s\n", attacker->client->ps.fd.saberAnimLevel, animTable[(attacker->client->ps.torsoAnim&~ANIM_TOGGLEBIT)].name ); + } + } + } + G_LogWeaponKill(killer, meansOfDeath); G_LogWeaponDeath(self->s.number, self->s.weapon); if (attacker && attacker->client && attacker->inuse) @@ -1807,8 +1861,108 @@ void LimbThink( gentity_t *ent ) G_RunObject(ent); } + +char *hitLocName[HL_MAX] = +{ + "none", //HL_NONE = 0, + "right foot", //HL_FOOT_RT, + "left foot", //HL_FOOT_LT, + "right leg", //HL_LEG_RT, + "left leg", //HL_LEG_LT, + "waist", //HL_WAIST, + "back right shoulder", //HL_BACK_RT, + "back left shoulder", //HL_BACK_LT, + "back", //HL_BACK, + "front right shouler", //HL_CHEST_RT, + "front left shoulder", //HL_CHEST_LT, + "chest", //HL_CHEST, + "right arm", //HL_ARM_RT, + "left arm", //HL_ARM_LT, + "right hand", //HL_HAND_RT, + "left hand", //HL_HAND_LT, + "head", //HL_HEAD + "generic1", //HL_GENERIC1, + "generic2", //HL_GENERIC2, + "generic3", //HL_GENERIC3, + "generic4", //HL_GENERIC4, + "generic5", //HL_GENERIC5, + "generic6" //HL_GENERIC6 +}; + void G_G2PlayerAngles( gentity_t *ent, vec3_t legs[3], vec3_t legsAngles); +void G_GetDismemberLoc(gentity_t *self, vec3_t boltPoint, int limbType) +{ //Just get the general area without using server-side ghoul2 + vec3_t fwd, right, up; + + AngleVectors(self->r.currentAngles, fwd, right, up); + + VectorCopy(self->r.currentOrigin, boltPoint); + + switch (limbType) + { + case G2_MODELPART_HEAD: + boltPoint[0] += up[0]*24; + boltPoint[1] += up[1]*24; + boltPoint[2] += up[2]*24; + break; + case G2_MODELPART_WAIST: + boltPoint[0] += up[0]*4; + boltPoint[1] += up[1]*4; + boltPoint[2] += up[2]*4; + break; + case G2_MODELPART_LARM: + boltPoint[0] += up[0]*18; + boltPoint[1] += up[1]*18; + boltPoint[2] += up[2]*18; + + boltPoint[0] -= right[0]*10; + boltPoint[1] -= right[1]*10; + boltPoint[2] -= right[2]*10; + break; + case G2_MODELPART_RARM: + boltPoint[0] += up[0]*18; + boltPoint[1] += up[1]*18; + boltPoint[2] += up[2]*18; + + boltPoint[0] += right[0]*10; + boltPoint[1] += right[1]*10; + boltPoint[2] += right[2]*10; + break; + case G2_MODELPART_RHAND: + boltPoint[0] += up[0]*8; + boltPoint[1] += up[1]*8; + boltPoint[2] += up[2]*8; + + boltPoint[0] += right[0]*10; + boltPoint[1] += right[1]*10; + boltPoint[2] += right[2]*10; + break; + case G2_MODELPART_LLEG: + boltPoint[0] -= up[0]*4; + boltPoint[1] -= up[1]*4; + boltPoint[2] -= up[2]*4; + + boltPoint[0] -= right[0]*10; + boltPoint[1] -= right[1]*10; + boltPoint[2] -= right[2]*10; + break; + case G2_MODELPART_RLEG: + boltPoint[0] -= up[0]*4; + boltPoint[1] -= up[1]*4; + boltPoint[2] -= up[2]*4; + + boltPoint[0] += right[0]*10; + boltPoint[1] += right[1]*10; + boltPoint[2] += right[2]*10; + break; + default: + break; + } + + return; +} + void G_GetDismemberBolt(gentity_t *self, vec3_t boltPoint, int limbType) { int useBolt = self->bolt_Head; @@ -1831,6 +1985,9 @@ void G_GetDismemberBolt(gentity_t *self, vec3_t boltPoint, int limbType) case G2_MODELPART_RARM: useBolt = self->bolt_RArm; break; + case G2_MODELPART_RHAND: + useBolt = trap_G2API_AddBolt(self->client->ghoul2, 0, "rhand"); + break; case G2_MODELPART_LLEG: useBolt = self->bolt_LLeg; break; @@ -1892,6 +2049,30 @@ void G_GetDismemberBolt(gentity_t *self, vec3_t boltPoint, int limbType) boltPoint[0] = boltMatrix.matrix[0][3]; boltPoint[1] = boltMatrix.matrix[1][3]; boltPoint[2] = boltMatrix.matrix[2][3]; + + trap_G2API_GetBoltMatrix(self->client->ghoul2, 1, 0, &boltMatrix, properAngles, properOrigin, level.time, NULL, vec3_origin); + + if (self->client && limbType == G2_MODELPART_RHAND) + { //Make some saber hit sparks over the severed wrist area + vec3_t boltAngles; + gentity_t *te; + + boltAngles[0] = -boltMatrix.matrix[0][1]; + boltAngles[1] = -boltMatrix.matrix[1][1]; + boltAngles[2] = -boltMatrix.matrix[2][1]; + + te = G_TempEntity( boltPoint, EV_SABER_HIT ); + + VectorCopy(boltPoint, te->s.origin); + VectorCopy(boltAngles, te->s.angles); + + if (!te->s.angles[0] && !te->s.angles[1] && !te->s.angles[2]) + { //don't let it play with no direction + te->s.angles[1] = 1; + } + + te->s.eventParm = 16; //lots of sparks + } } void G_Dismember( gentity_t *ent, vec3_t point, int limbType, float limbRollBase, float limbPitchBase, int deathAnim ) @@ -1913,8 +2094,8 @@ void G_Dismember( gentity_t *ent, vec3_t point, int limbType, float limbRollBase limb->r.svFlags = SVF_USE_CURRENT_ORIGIN; limb->clipmask = MASK_SOLID; limb->r.contents = CONTENTS_TRIGGER; - VectorSet( limb->r.mins, -3.0f, -3.0f, -3.0f ); - VectorSet( limb->r.maxs, 3.0f, 3.0f, 3.0f ); + VectorSet( limb->r.mins, -6.0f, -6.0f, -9.0f ); + VectorSet( limb->r.maxs, 6.0f, 6.0f, 6.0f ); // VectorClear(limb->r.mins); // VectorClear(limb->r.maxs); @@ -1934,20 +2115,45 @@ void G_Dismember( gentity_t *ent, vec3_t point, int limbType, float limbRollBase limb->s.pos.trTime = level.time; // move a bit on the very first frame VectorSubtract( point, ent->r.currentOrigin, dir ); VectorNormalize( dir ); - VectorCopy(ent->client->ps.velocity, vel); + if (ent->client) + { + VectorCopy(ent->client->ps.velocity, vel); + } + else + { + VectorCopy(ent->s.pos.trDelta, vel); + } VectorMA( vel, 100, dir, limb->s.pos.trDelta ); + //add some vertical velocity + if (limbType == G2_MODELPART_HEAD || + limbType == G2_MODELPART_WAIST) + { + limb->s.pos.trDelta[2] += 100; + } + //make it bounce some limb->s.eFlags |= EF_BOUNCE_HALF; //no trDuration? //spin it VectorClear( limb->s.apos.trBase ); + /* limb->s.apos.trBase[0] = limbPitchBase; limb->s.apos.trBase[1] = ent->client->ps.viewangles[1]; limb->s.apos.trBase[2] = limbRollBase; + */ + if (ent->client) + { + limb->s.apos.trBase[1] = ent->client->ps.viewangles[1]; + } + else + { + limb->s.apos.trBase[1] = ent->r.currentAngles[1]; + } VectorClear( limb->s.apos.trDelta ); + /* limb->s.apos.trDelta[0] = Q_irand( -300, 300 ); limb->s.apos.trDelta[2] = Q_irand( -300, 300 ); limb->s.apos.trDelta[1] = Q_irand( -300, 300 ); @@ -1958,34 +2164,71 @@ void G_Dismember( gentity_t *ent, vec3_t point, int limbType, float limbRollBase limb->s.apos.trDelta[2] = Q_irand( -60, 60 ); limb->s.apos.trDelta[1] = Q_irand( -60, 60 ); } + */ + VectorClear(limb->s.apos.trDelta); limb->s.apos.trTime = level.time; limb->s.apos.trType = TR_LINEAR; limb->s.modelGhoul2 = limbType; limb->s.g2radius = 200; - limb->s.modelindex = ent->s.number; - limb->s.modelindex2 = deathAnim; + if (ent->client) + { + limb->s.modelindex = ent->s.number; + limb->s.modelindex2 = deathAnim; + } + else + { + limb->s.modelindex = -1; + limb->s.modelindex2 = ent->s.number; + } trap_LinkEntity( limb ); } -/* void DismembermentTest(gentity_t *self) { int sect = G2_MODELPART_HEAD; vec3_t boltPoint; - char *sectc = ConcatArgs( 1 ); - - if (sectc && sectc[0]) + G_GetDismemberBolt(self, boltPoint, sect); + G_Dismember( self, boltPoint, sect, 90, 0, BOTH_DEATH1 ); +} + +void DismembermentByNum(gentity_t *self, int num) +{ + int sect = G2_MODELPART_HEAD; + vec3_t boltPoint; + + switch (num) { - sect = atoi(sectc)+G2_MODELPART_HEAD; + case 0: + sect = G2_MODELPART_HEAD; + break; + case 1: + sect = G2_MODELPART_WAIST; + break; + case 2: + sect = G2_MODELPART_LARM; + break; + case 3: + sect = G2_MODELPART_RARM; + break; + case 4: + sect = G2_MODELPART_RHAND; + break; + case 5: + sect = G2_MODELPART_LLEG; + break; + case 6: + sect = G2_MODELPART_RLEG; + break; + default: + break; } G_GetDismemberBolt(self, boltPoint, sect); - G_Dismember( self, boltPoint, sect, 90, 0 ); + G_Dismember( self, boltPoint, sect, 90, 0, BOTH_DEATH1 ); } -*/ int G_GetHitQuad( gentity_t *self, vec3_t hitloc ) { @@ -1995,14 +2238,29 @@ int G_GetHitQuad( gentity_t *self, vec3_t hitloc ) float zdiff; int hitLoc = -1; - VectorCopy(self->client->ps.origin, clEye); - clEye[2] += self->client->ps.viewheight; + if (self->client) + { + VectorCopy(self->client->ps.origin, clEye); + clEye[2] += self->client->ps.viewheight; + } + else + { + VectorCopy(self->s.pos.trBase, clEye); + clEye[2] += 16; + } VectorSubtract( hitloc, clEye, diff ); diff[2] = 0; VectorNormalize( diff ); - fwdangles[1] = self->client->ps.viewangles[1]; + if (self->client) + { + fwdangles[1] = self->client->ps.viewangles[1]; + } + else + { + fwdangles[1] = self->s.apos.trBase[1]; + } // Ultimately we might care if the shot was ahead or behind, but for now, just quadrant is fine. AngleVectors( fwdangles, NULL, right, NULL ); @@ -2054,6 +2312,8 @@ int G_GetHitQuad( gentity_t *self, vec3_t hitloc ) return hitLoc; } +int gGAvoidDismember = 0; + void G_CheckForDismemberment(gentity_t *ent, vec3_t point, int damage, int deathAnim) { int hitLoc, hitLocUse = -1; @@ -2065,17 +2325,32 @@ void G_CheckForDismemberment(gentity_t *ent, vec3_t point, int damage, int death return; } - if (Q_irand(0, 100) > dismember) + if (gGAvoidDismember == 1) { return; } - if (damage < 20) - { - return; + if (!gGAvoidDismember != 2) + { //this means do the dismemberment regardless of randomness and damage + if (Q_irand(0, 100) > dismember) + { + return; + } + + if (damage < 20) + { + return; + } } - hitLoc = G_GetHitLocation( ent, point ); + if (gGAvoidDismember == 2) + { + hitLoc = HL_HAND_RT; + } + else + { + hitLoc = G_GetHitLocation( ent, point ); + } switch(hitLoc) { @@ -2086,6 +2361,7 @@ void G_CheckForDismemberment(gentity_t *ent, vec3_t point, int damage, int death case HL_FOOT_LT: case HL_LEG_LT: hitLocUse = G2_MODELPART_LLEG; + break; case HL_WAIST: hitLocUse = G2_MODELPART_WAIST; @@ -2100,15 +2376,18 @@ void G_CheckForDismemberment(gentity_t *ent, vec3_t point, int damage, int death break; */ case HL_ARM_RT: - case HL_HAND_RT: hitLocUse = G2_MODELPART_RARM; break; + case HL_HAND_RT: + hitLocUse = G2_MODELPART_RHAND; + break; case HL_ARM_LT: case HL_HAND_LT: hitLocUse = G2_MODELPART_LARM; break; case HL_HEAD: hitLocUse = G2_MODELPART_HEAD; + break; default: hitLocUse = G_GetHitQuad(ent, point); break; @@ -2119,7 +2398,19 @@ void G_CheckForDismemberment(gentity_t *ent, vec3_t point, int damage, int death return; } - G_GetDismemberBolt(ent, boltPoint, hitLocUse); + if (ent->client) + { + G_GetDismemberBolt(ent, boltPoint, hitLocUse); + if ( g_austrian.integer + && g_gametype.integer == GT_TOURNAMENT ) + { + G_LogPrintf( "Duel Dismemberment: %s dismembered at %s\n", ent->client->pers.netname, hitLocName[hitLoc] ); + } + } + else + { + G_GetDismemberLoc(ent, boltPoint, hitLocUse); + } G_Dismember(ent, boltPoint, hitLocUse, 90, 0, deathAnim); } @@ -2285,7 +2576,14 @@ void G_Damage( gentity_t *targ, gentity_t *inflictor, gentity_t *attacker, mass = 200; - VectorScale (dir, g_knockback.value * (float)knockback / mass, kvel); + if (mod == MOD_SABER) + { + VectorScale (dir, (g_knockback.value * (float)knockback / mass)*g_saberDmgVelocityScale.integer, kvel); + } + else + { + VectorScale (dir, g_knockback.value * (float)knockback / mass, kvel); + } VectorAdd (targ->client->ps.velocity, kvel, targ->client->ps.velocity); if (attacker && attacker->client && attacker != targ) @@ -2296,7 +2594,7 @@ void G_Damage( gentity_t *targ, gentity_t *inflictor, gentity_t *attacker, } // set the timer so that the other client can't cancel // out the movement immediately - if ( !targ->client->ps.pm_time ) { + if ( !targ->client->ps.pm_time && (g_saberDmgVelocityScale.integer || mod != MOD_SABER) ) { int t; t = knockback * 2; @@ -2311,6 +2609,43 @@ void G_Damage( gentity_t *targ, gentity_t *inflictor, gentity_t *attacker, } } + + if ( g_trueJedi.integer ) + {//less explosive damage for jedi, more saber damage for non-jedi + if ( client->ps.trueJedi ) + {//if the target is a trueJedi, reduce splash and explosive damage to 1/2 + switch ( mod ) + { + case MOD_REPEATER_ALT: + case MOD_REPEATER_ALT_SPLASH: + case MOD_DEMP2_ALT: + case MOD_FLECHETTE_ALT_SPLASH: + case MOD_ROCKET: + case MOD_ROCKET_SPLASH: + case MOD_ROCKET_HOMING: + case MOD_ROCKET_HOMING_SPLASH: + case MOD_THERMAL: + case MOD_THERMAL_SPLASH: + case MOD_TRIP_MINE_SPLASH: + case MOD_TIMED_MINE_SPLASH: + case MOD_DET_PACK_SPLASH: + damage *= 0.5; + break; + } + } + else if ( client->ps.trueNonJedi && mod == MOD_SABER ) + {//if the target is a trueNonJedi, take more saber damage... combined with the 1.5 in the w_saber stuff, this is 6 times damage! + if ( damage < 100 ) + { + damage *= 4; + if ( damage > 100 ) + { + damage = 100; + } + } + } + } + // check for completely getting out of the damage if ( !(dflags & DAMAGE_NO_PROTECTION) ) { @@ -2483,7 +2818,11 @@ void G_Damage( gentity_t *targ, gentity_t *inflictor, gentity_t *attacker, int maxtake = take; //G_Sound(targ, CHAN_AUTO, protectHitSound); - G_PreDefSound(targ->client->ps.origin, PDSOUND_PROTECTHIT); + if (targ->client->forcePowerSoundDebounce < level.time) + { + G_PreDefSound(targ->client->ps.origin, PDSOUND_PROTECTHIT); + targ->client->forcePowerSoundDebounce = level.time + 400; + } if (targ->client->ps.fd.forcePowerLevel[FP_PROTECT] == FORCE_LEVEL_1) { @@ -2611,6 +2950,10 @@ void G_Damage( gentity_t *targ, gentity_t *inflictor, gentity_t *attacker, VectorCopy(targ->client->ps.origin, targ->pos1); } } + else if (targ->s.eType == ET_GRAPPLE) + { //g2animent + VectorCopy(point, targ->pos1); + } if (targ->health < -999) targ->health = -999; diff --git a/CODE-mp/game/g_items.c b/CODE-mp/game/g_items.c index bec9d22..a882e03 100644 --- a/CODE-mp/game/g_items.c +++ b/CODE-mp/game/g_items.c @@ -1723,32 +1723,11 @@ free fall from their spawn points void FinishSpawningItem( gentity_t *ent ) { trace_t tr; vec3_t dest; - int wDisable = 0; // gitem_t *item; // VectorSet( ent->r.mins, -ITEM_RADIUS, -ITEM_RADIUS, -ITEM_RADIUS ); // VectorSet( ent->r.maxs, ITEM_RADIUS, ITEM_RADIUS, ITEM_RADIUS ); - if (g_gametype.integer == GT_TOURNAMENT) - { - wDisable = g_duelWeaponDisable.integer; - } - else - { - wDisable = g_weaponDisable.integer; - } - - if (ent->item->giType == IT_WEAPON && - wDisable && - (wDisable & (1 << ent->item->giTag))) - { - if (g_gametype.integer != GT_JEDIMASTER) - { - G_FreeEntity( ent ); - return; - } - } - if (g_gametype.integer != GT_JEDIMASTER) { if (HasSetSaberOnly()) @@ -2027,9 +2006,31 @@ be on an entity that hasn't spawned yet. ============ */ void G_SpawnItem (gentity_t *ent, gitem_t *item) { + int wDisable = 0; + G_SpawnFloat( "random", "0", &ent->random ); G_SpawnFloat( "wait", "0", &ent->wait ); + if (g_gametype.integer == GT_TOURNAMENT) + { + wDisable = g_duelWeaponDisable.integer; + } + else + { + wDisable = g_weaponDisable.integer; + } + + if (item->giType == IT_WEAPON && + wDisable && + (wDisable & (1 << item->giTag))) + { + if (g_gametype.integer != GT_JEDIMASTER) + { + G_FreeEntity( ent ); + return; + } + } + RegisterItem( item ); if ( G_ItemDisabled(item) ) return; diff --git a/CODE-mp/game/g_local.h b/CODE-mp/game/g_local.h index e50a665..87fd55a 100644 --- a/CODE-mp/game/g_local.h +++ b/CODE-mp/game/g_local.h @@ -33,6 +33,8 @@ #define FL_NO_HUMANS 0x00004000 // spawn point just for bots #define FL_FORCE_GESTURE 0x00008000 // force gesture on client +#define ANIMENT_SPAWNER //allow animent spawners + // movers are things like doors, plats, buttons, etc typedef enum { MOVER_POS1, @@ -88,6 +90,9 @@ typedef enum extern void *precachedKyle; extern void *g2SaberInstance; +extern qboolean gEscaping; +extern int gEscapeTime; + typedef struct gentity_s gentity_t; typedef struct gclient_s gclient_t; @@ -405,10 +410,17 @@ struct gclient_s { vec3_t lastSaberTip; //position of saber tip last update vec3_t lastSaberBase; //position of saber base last update + + vec3_t lastSaberDir_Always; //every getboltmatrix, set to saber dir + vec3_t lastSaberBase_Always; //every getboltmatrix, set to saber base + int lastSaberStorageTime; //server time that the above two values were updated (for making sure they aren't out of date) + qboolean hasCurrentPosition; //are lastSaberTip and lastSaberBase valid? int dangerTime; // level.time when last attack occured + int forcePowerSoundDebounce; //if > level.time, don't do certain sound events again (drain sound, absorb sound, etc) + qboolean fjDidJump; }; @@ -621,6 +633,8 @@ qboolean trap_G2API_GetBoltMatrix(void *ghoul2, const int modelIndex, const int const vec3_t angles, const vec3_t position, const int frameNum, qhandle_t *modelList, vec3_t scale); qboolean trap_G2API_GetBoltMatrix_NoReconstruct(void *ghoul2, const int modelIndex, const int boltIndex, mdxaBone_t *matrix, const vec3_t angles, const vec3_t position, const int frameNum, qhandle_t *modelList, vec3_t scale); +qboolean trap_G2API_GetBoltMatrix_NoRecNoRot(void *ghoul2, const int modelIndex, const int boltIndex, mdxaBone_t *matrix, + const vec3_t angles, const vec3_t position, const int frameNum, qhandle_t *modelList, vec3_t scale); int trap_G2API_InitGhoul2Model(void **ghoul2Ptr, const char *fileName, int modelIndex, qhandle_t customSkin, qhandle_t customShader, int modelFlags, int lodBias); int trap_G2API_AddBolt(void *ghoul2, int modelIndex, const char *boneName); @@ -632,6 +646,8 @@ void trap_G2API_DuplicateGhoul2Instance(void *g2From, void **g2To); qboolean trap_G2API_HasGhoul2ModelOnIndex(void *ghlInfo, int modelIndex); qboolean trap_G2API_RemoveGhoul2Model(void *ghlInfo, int modelIndex); void trap_G2API_CleanGhoul2Models(void **ghoul2Ptr); +void trap_G2API_CollisionDetect ( CollisionRecord_t *collRecMap, void* ghoul2, const vec3_t angles, const vec3_t position, + int frameNumber, int entNum, vec3_t rayStart, vec3_t rayEnd, vec3_t scale, int traceFlags, int useLod, float fRadius ); qboolean trap_G2API_SetBoneAngles(void *ghoul2, int modelIndex, const char *boneName, const vec3_t angles, const int flags, const int up, const int right, const int forward, qhandle_t *modelList, @@ -654,6 +670,9 @@ void TossClientWeapon(gentity_t *self, vec3_t direction, float speed); void TossClientItems( gentity_t *self ); void TossClientCubes( gentity_t *self ); void ExplodeDeath( gentity_t *self ); +void G_CheckForDismemberment(gentity_t *ent, vec3_t point, int damage, int deathAnim); +extern int gGAvoidDismember; + // damage flags #define DAMAGE_NORMAL 0x00000000 // No flags set. @@ -688,6 +707,9 @@ void WP_FireBlasterMissile( gentity_t *ent, vec3_t start, vec3_t dir, qboolean a // // g_mover.c // +#define SPF_BUTTON_USABLE 1 +#define SPF_BUTTON_FPUSHABLE 2 + void G_RunMover( gentity_t *ent ); void Touch_DoorTrigger( gentity_t *ent, gentity_t *other, trace_t *trace ); @@ -703,6 +725,7 @@ void trigger_teleporter_touch (gentity_t *self, gentity_t *other, trace_t *trace void TeleportPlayer( gentity_t *player, vec3_t origin, vec3_t angles ); void ATST_ManageDamageBoxes(gentity_t *ent); int G_PlayerBecomeATST(gentity_t *ent); +void G_CreateExampleAnimEnt(gentity_t *ent); // @@ -842,7 +865,7 @@ qboolean G_DoesMapSupportGametype(const char *mapname, int gametype); const char *G_RefreshNextMap(int gametype, qboolean forced); // w_force.c / w_saber.c -void G_PreDefSound(vec3_t org, int pdSound); +gentity_t *G_PreDefSound(vec3_t org, int pdSound); qboolean HasSetSaberOnly(void); void WP_ForcePowerStop( gentity_t *self, forcePowers_t forcePower ); void WP_SaberPositionUpdate( gentity_t *self, usercmd_t *ucmd ); @@ -924,12 +947,23 @@ extern vmCvar_t g_maxclients; // allow this many total, including spectators extern vmCvar_t g_maxGameClients; // allow this many active extern vmCvar_t g_restarted; +extern vmCvar_t g_trueJedi; + extern vmCvar_t g_autoMapCycle; extern vmCvar_t g_dmflags; extern vmCvar_t g_maxForceRank; extern vmCvar_t g_forceBasedTeams; extern vmCvar_t g_privateDuel; extern vmCvar_t g_saberLocking; +extern vmCvar_t g_saberLockFactor; +extern vmCvar_t g_saberTraceSaberFirst; + +#ifdef G2_COLLISION_ENABLED +extern vmCvar_t g_saberGhoul2Collision; +#endif +extern vmCvar_t g_saberAlwaysBoxTrace; +extern vmCvar_t g_saberBoxTraceSize; + extern vmCvar_t g_forceRegenTime; extern vmCvar_t g_spawnInvulnerability; extern vmCvar_t g_forcePowerDisable; @@ -982,6 +1016,14 @@ extern vmCvar_t g_dismember; extern vmCvar_t g_forceDodge; extern vmCvar_t g_timeouttospec; +extern vmCvar_t g_saberDmgVelocityScale; +extern vmCvar_t g_saberDmgDelay_Idle; +extern vmCvar_t g_saberDmgDelay_Wound; + +extern vmCvar_t g_saberDebugPrint; + +extern vmCvar_t g_austrian; + void trap_Printf( const char *fmt ); void trap_Error( const char *fmt ); int trap_Milliseconds( void ); diff --git a/CODE-mp/game/g_main.c b/CODE-mp/game/g_main.c index fffc221..7b073dd 100644 --- a/CODE-mp/game/g_main.c +++ b/CODE-mp/game/g_main.c @@ -20,6 +20,8 @@ gclient_t g_clients[MAX_CLIENTS]; qboolean gDuelExit = qfalse; +vmCvar_t g_trueJedi; + vmCvar_t g_gametype; vmCvar_t g_MaxHolocronCarry; vmCvar_t g_ff_objectives; @@ -29,6 +31,15 @@ vmCvar_t g_maxForceRank; vmCvar_t g_forceBasedTeams; vmCvar_t g_privateDuel; vmCvar_t g_saberLocking; +vmCvar_t g_saberLockFactor; +vmCvar_t g_saberTraceSaberFirst; + +#ifdef G2_COLLISION_ENABLED +vmCvar_t g_saberGhoul2Collision; +#endif +vmCvar_t g_saberAlwaysBoxTrace; +vmCvar_t g_saberBoxTraceSize; + vmCvar_t g_forceRegenTime; vmCvar_t g_spawnInvulnerability; vmCvar_t g_forcePowerDisable; @@ -93,6 +104,14 @@ vmCvar_t g_dismember; vmCvar_t g_forceDodge; vmCvar_t g_timeouttospec; +vmCvar_t g_saberDmgVelocityScale; +vmCvar_t g_saberDmgDelay_Idle; +vmCvar_t g_saberDmgDelay_Wound; + +vmCvar_t g_saberDebugPrint; + +vmCvar_t g_austrian; + int gDuelist1 = -1; int gDuelist2 = -1; @@ -117,6 +136,8 @@ static cvarTable_t gameCvarTable[] = { // change anytime vars { &g_ff_objectives, "g_ff_objectives", "0", /*CVAR_SERVERINFO |*/ CVAR_NORESTART, 0, qtrue }, + { &g_trueJedi, "g_jediVmerc", "0", CVAR_INTERNAL |CVAR_SERVERINFO | CVAR_LATCH, 0, qtrue }, + { &g_autoMapCycle, "g_autoMapCycle", "0", CVAR_ARCHIVE | CVAR_NORESTART, 0, qtrue }, { &g_dmflags, "dmflags", "0", CVAR_SERVERINFO | CVAR_ARCHIVE, 0, qtrue }, @@ -124,6 +145,15 @@ static cvarTable_t gameCvarTable[] = { { &g_forceBasedTeams, "g_forceBasedTeams", "0", CVAR_SERVERINFO | CVAR_ARCHIVE | CVAR_USERINFO | CVAR_LATCH, 0, qfalse }, { &g_privateDuel, "g_privateDuel", "1", CVAR_SERVERINFO | CVAR_ARCHIVE, 0, qtrue }, { &g_saberLocking, "g_saberLocking", "1", CVAR_SERVERINFO | CVAR_ARCHIVE, 0, qtrue }, + { &g_saberLockFactor, "g_saberLockFactor", "6", CVAR_ARCHIVE, 0, qtrue }, + { &g_saberTraceSaberFirst, "g_saberTraceSaberFirst", "1", CVAR_ARCHIVE, 0, qtrue }, + +#ifdef G2_COLLISION_ENABLED + { &g_saberGhoul2Collision, "g_saberGhoul2Collision", "0", 0, 0, qtrue }, +#endif + { &g_saberAlwaysBoxTrace, "g_saberAlwaysBoxTrace", "0", 0, 0, qtrue }, + { &g_saberBoxTraceSize, "g_saberBoxTraceSize", "2", 0, 0, qtrue }, + { &g_forceRegenTime, "g_forceRegenTime", "200", CVAR_SERVERINFO | CVAR_ARCHIVE, 0, qtrue }, { &g_spawnInvulnerability, "g_spawnInvulnerability", "3000", CVAR_ARCHIVE, 0, qtrue }, @@ -203,10 +233,18 @@ static cvarTable_t gameCvarTable[] = { { &g_rankings, "g_rankings", "0", 0, 0, qfalse}, - { &g_dismember, "g_dismember", "0", 0, 0, qtrue }, + { &g_dismember, "g_dismember", "0", CVAR_ARCHIVE, 0, qtrue }, { &g_forceDodge, "g_forceDodge", "1", 0, 0, qtrue }, { &g_timeouttospec, "g_timeouttospec", "70", CVAR_ARCHIVE, 0, qfalse }, + + { &g_saberDmgVelocityScale, "g_saberDmgVelocityScale", "0", CVAR_ARCHIVE, 0, qtrue }, + { &g_saberDmgDelay_Idle, "g_saberDmgDelay_Idle", "350", CVAR_ARCHIVE, 0, qtrue }, + { &g_saberDmgDelay_Wound, "g_saberDmgDelay_Wound", "0", CVAR_ARCHIVE, 0, qtrue }, + + { &g_saberDebugPrint, "g_saberDebugPrint", "0", CVAR_CHEAT, 0, qfalse }, + + { &g_austrian, "g_austrian", "0", CVAR_ARCHIVE, 0, qfalse }, }; // bk001129 - made static to avoid aliasing @@ -461,7 +499,7 @@ void G_InitGame( int levelTime, int randomSeed, int restart ) { //trap_SP_RegisterServer("mp_svgame"); - if ( g_gametype.integer != GT_SINGLE_PLAYER && g_log.string[0] ) { + if ( g_log.string[0] ) { if ( g_logSync.integer ) { trap_FS_FOpenFile( g_log.string, &level.logFile, FS_APPEND_SYNC ); } else { @@ -554,6 +592,11 @@ void G_InitGame( int levelTime, int randomSeed, int restart ) { } G_RemapTeamShaders(); + + if ( g_gametype.integer == GT_TOURNAMENT ) + { + G_LogPrintf("Duel Tournament Begun: kill limit %d, win limit: %d\n", g_fraglimit.integer, g_duel_fraglimit.integer ); + } } @@ -702,6 +745,47 @@ void RemoveTournamentLoser( void ) { SetTeam( &g_entities[ clientNum ], "s" ); } +void RemoveDuelDrawLoser(void) +{ + int clFirst = 0; + int clSec = 0; + int clFailure = 0; + + if ( level.clients[ level.sortedClients[0] ].pers.connected != CON_CONNECTED ) + { + return; + } + if ( level.clients[ level.sortedClients[1] ].pers.connected != CON_CONNECTED ) + { + return; + } + + clFirst = level.clients[ level.sortedClients[0] ].ps.stats[STAT_HEALTH] + level.clients[ level.sortedClients[0] ].ps.stats[STAT_ARMOR]; + clSec = level.clients[ level.sortedClients[1] ].ps.stats[STAT_HEALTH] + level.clients[ level.sortedClients[1] ].ps.stats[STAT_ARMOR]; + + if (clFirst > clSec) + { + clFailure = 1; + } + else if (clSec > clFirst) + { + clFailure = 0; + } + else + { + clFailure = 2; + } + + if (clFailure != 2) + { + SetTeam( &g_entities[ level.sortedClients[clFailure] ], "s" ); + } + else + { //we could be more elegant about this, but oh well. + SetTeam( &g_entities[ level.sortedClients[1] ], "s" ); + } +} + /* ======================= RemoveTournamentWinner @@ -732,20 +816,78 @@ AdjustTournamentScores void AdjustTournamentScores( void ) { int clientNum; - clientNum = level.sortedClients[0]; - if ( level.clients[ clientNum ].pers.connected == CON_CONNECTED ) { - level.clients[ clientNum ].sess.wins++; - ClientUserinfoChanged( clientNum ); + if (level.clients[level.sortedClients[0]].ps.persistant[PERS_SCORE] == + level.clients[level.sortedClients[1]].ps.persistant[PERS_SCORE] && + level.clients[level.sortedClients[0]].pers.connected == CON_CONNECTED && + level.clients[level.sortedClients[1]].pers.connected == CON_CONNECTED) + { + int clFirst = level.clients[ level.sortedClients[0] ].ps.stats[STAT_HEALTH] + level.clients[ level.sortedClients[0] ].ps.stats[STAT_ARMOR]; + int clSec = level.clients[ level.sortedClients[1] ].ps.stats[STAT_HEALTH] + level.clients[ level.sortedClients[1] ].ps.stats[STAT_ARMOR]; + int clFailure = 0; + int clSuccess = 0; - trap_SetConfigstring ( CS_CLIENT_DUELWINNER, va("%i", clientNum ) ); + if (clFirst > clSec) + { + clFailure = 1; + clSuccess = 0; + } + else if (clSec > clFirst) + { + clFailure = 0; + clSuccess = 1; + } + else + { + clFailure = 2; + clSuccess = 2; + } + + if (clFailure != 2) + { + clientNum = level.sortedClients[clSuccess]; + + level.clients[ clientNum ].sess.wins++; + ClientUserinfoChanged( clientNum ); + trap_SetConfigstring ( CS_CLIENT_DUELWINNER, va("%i", clientNum ) ); + + clientNum = level.sortedClients[clFailure]; + + level.clients[ clientNum ].sess.losses++; + ClientUserinfoChanged( clientNum ); + } + else + { + clSuccess = 0; + clFailure = 1; + + clientNum = level.sortedClients[clSuccess]; + + level.clients[ clientNum ].sess.wins++; + ClientUserinfoChanged( clientNum ); + trap_SetConfigstring ( CS_CLIENT_DUELWINNER, va("%i", clientNum ) ); + + clientNum = level.sortedClients[clFailure]; + + level.clients[ clientNum ].sess.losses++; + ClientUserinfoChanged( clientNum ); + } } + else + { + clientNum = level.sortedClients[0]; + if ( level.clients[ clientNum ].pers.connected == CON_CONNECTED ) { + level.clients[ clientNum ].sess.wins++; + ClientUserinfoChanged( clientNum ); - clientNum = level.sortedClients[1]; - if ( level.clients[ clientNum ].pers.connected == CON_CONNECTED ) { - level.clients[ clientNum ].sess.losses++; - ClientUserinfoChanged( clientNum ); + trap_SetConfigstring ( CS_CLIENT_DUELWINNER, va("%i", clientNum ) ); + } + + clientNum = level.sortedClients[1]; + if ( level.clients[ clientNum ].pers.connected == CON_CONNECTED ) { + level.clients[ clientNum ].sess.losses++; + ClientUserinfoChanged( clientNum ); + } } - } /* @@ -806,6 +948,9 @@ int QDECL SortRanks( const void *a, const void *b ) { return 0; } +qboolean gQueueScoreMessage = qfalse; +int gQueueScoreMessageTime = 0; + /* ============ CalculateRanks @@ -953,9 +1098,12 @@ void CalculateRanks( void ) { // see if it is time to end the level CheckExitRules(); - // if we are at the intermission, send the new info to everyone - if ( level.intermissiontime ) { - SendScoreboardMessageToAllClients(); + // if we are at the intermission or in multi-frag Duel game mode, send the new info to everyone + if ( level.intermissiontime || g_gametype.integer == GT_TOURNAMENT ) { + gQueueScoreMessage = qtrue; + gQueueScoreMessageTime = level.time + 500; + //SendScoreboardMessageToAllClients(); + //rww - Made this operate on a "queue" system because it was causing large overflows } } @@ -1313,10 +1461,6 @@ void CheckIntermissionExit( void ) { gclient_t *cl; int readyMask; - if ( g_gametype.integer == GT_SINGLE_PLAYER ) { - return; - } - // see which players are ready ready = 0; notReady = 0; @@ -1345,14 +1489,51 @@ void CheckIntermissionExit( void ) { { gDidDuelStuff = qtrue; + if ( g_austrian.integer ) + { + G_LogPrintf("Duel Results:\n"); + //G_LogPrintf("Duel Time: %d\n", level.time ); + G_LogPrintf("winner: %s, score: %d, wins/losses: %d/%d\n", + level.clients[level.sortedClients[0]].pers.netname, + level.clients[level.sortedClients[0]].ps.persistant[PERS_SCORE], + level.clients[level.sortedClients[0]].sess.wins, + level.clients[level.sortedClients[0]].sess.losses ); + G_LogPrintf("loser: %s, score: %d, wins/losses: %d/%d\n", + level.clients[level.sortedClients[1]].pers.netname, + level.clients[level.sortedClients[1]].ps.persistant[PERS_SCORE], + level.clients[level.sortedClients[1]].sess.wins, + level.clients[level.sortedClients[1]].sess.losses ); + } // if we are running a tournement map, kick the loser to spectator status, // which will automatically grab the next spectator and restart if (!DuelLimitHit()) { - RemoveTournamentLoser(); + if (level.clients[level.sortedClients[0]].ps.persistant[PERS_SCORE] == + level.clients[level.sortedClients[1]].ps.persistant[PERS_SCORE] && + level.clients[level.sortedClients[0]].pers.connected == CON_CONNECTED && + level.clients[level.sortedClients[1]].pers.connected == CON_CONNECTED) + { + RemoveDuelDrawLoser(); + } + else + { + RemoveTournamentLoser(); + } AddTournamentPlayer(); + if ( g_austrian.integer ) + { + G_LogPrintf("Duel Initiated: %s %d/%d vs %s %d/%d, kill limit: %d\n", + level.clients[level.sortedClients[0]].pers.netname, + level.clients[level.sortedClients[0]].sess.wins, + level.clients[level.sortedClients[0]].sess.losses, + level.clients[level.sortedClients[1]].pers.netname, + level.clients[level.sortedClients[1]].sess.wins, + level.clients[level.sortedClients[1]].sess.losses, + g_fraglimit.integer ); + } + if (level.numPlayingClients >= 2) { trap_SetConfigstring ( CS_CLIENT_DUELISTS, va("%i|%i", level.sortedClients[0], level.sortedClients[1] ) ); @@ -1365,11 +1546,30 @@ void CheckIntermissionExit( void ) { return; } + if ( g_austrian.integer ) + { + G_LogPrintf("Duel Tournament Winner: %s wins/losses: %d/%d\n", + level.clients[level.sortedClients[0]].pers.netname, + level.clients[level.sortedClients[0]].sess.wins, + level.clients[level.sortedClients[0]].sess.losses ); + } //this means we hit the duel limit so reset the wins/losses //but still push the loser to the back of the line, and retain the order for //the map change - RemoveTournamentLoser(); + if (level.clients[level.sortedClients[0]].ps.persistant[PERS_SCORE] == + level.clients[level.sortedClients[1]].ps.persistant[PERS_SCORE] && + level.clients[level.sortedClients[0]].pers.connected == CON_CONNECTED && + level.clients[level.sortedClients[1]].pers.connected == CON_CONNECTED) + { + RemoveDuelDrawLoser(); + } + else + { + RemoveTournamentLoser(); + } + AddTournamentPlayer(); + if (level.numPlayingClients >= 2) { trap_SetConfigstring ( CS_CLIENT_DUELISTS, va("%i|%i", level.sortedClients[0], level.sortedClients[1] ) ); @@ -1485,6 +1685,38 @@ void CheckExitRules( void ) { return; } + if (gEscaping) + { + int i = 0; + int numLiveClients = 0; + + while (i < MAX_CLIENTS) + { + if (g_entities[i].inuse && g_entities[i].client && g_entities[i].health > 0) + { + if (g_entities[i].client->sess.sessionTeam != TEAM_SPECTATOR && + !(g_entities[i].client->ps.pm_flags & PMF_FOLLOW)) + { + numLiveClients++; + } + } + + i++; + } + if (gEscapeTime < level.time) + { + gEscaping = qfalse; + LogExit( "Escape time ended." ); + return; + } + if (!numLiveClients) + { + gEscaping = qfalse; + LogExit( "Everyone failed to escape." ); + return; + } + } + if ( level.intermissionQueued ) { int time = (g_singlePlayer.integer) ? SP_INTERMISSION_DELAY_TIME : INTERMISSION_DELAY_TIME; if ( level.time - level.intermissionQueued >= time ) { @@ -1497,12 +1729,16 @@ void CheckExitRules( void ) { // check for sudden death if ( ScoreIsTied() ) { // always wait for sudden death - return; + if (g_gametype.integer != GT_TOURNAMENT || !g_timelimit.integer) + { + return; + } } if ( g_timelimit.integer && !level.warmupTime ) { if ( level.time - level.startTime >= g_timelimit.integer*60000 ) { - trap_SendServerCommand( -1, "print \"Timelimit hit.\n\""); +// trap_SendServerCommand( -1, "print \"Timelimit hit.\n\""); + trap_SendServerCommand( -1, va("print \"%s.\n\"",G_GetStripEdString("SVINGAME", "TIMELIMIT_HIT"))); LogExit( "Timelimit hit." ); return; } @@ -1618,6 +1854,19 @@ void CheckTournament( void ) { trap_SetConfigstring ( CS_CLIENT_DUELISTS, va("%i|%i", level.sortedClients[0], level.sortedClients[1] ) ); gDuelist1 = level.sortedClients[0]; gDuelist2 = level.sortedClients[1]; + if ( g_austrian.integer ) + { + G_LogPrintf("Duel Initiated: %s %d/%d vs %s %d/%d, kill limit: %d\n", + level.clients[level.sortedClients[0]].pers.netname, + level.clients[level.sortedClients[0]].sess.wins, + level.clients[level.sortedClients[0]].sess.losses, + level.clients[level.sortedClients[1]].pers.netname, + level.clients[level.sortedClients[1]].sess.wins, + level.clients[level.sortedClients[1]].sess.losses, + g_fraglimit.integer ); + } + //trap_SendConsoleCommand( EXEC_APPEND, "map_restart 0\n" ); + //FIXME: This seems to cause problems. But we'd like to reset things whenever a new opponent is set. } } @@ -1672,7 +1921,7 @@ void CheckTournament( void ) { return; } #endif - } else if ( g_gametype.integer != GT_SINGLE_PLAYER && level.warmupTime != 0 ) { + } else if ( level.warmupTime != 0 ) { int counts[TEAM_NUM_TEAMS]; qboolean notEnough = qfalse; @@ -2100,6 +2349,18 @@ end = trap_Milliseconds(); //At the end of the frame, send out the ghoul2 kill queue, if there is one G_SendG2KillQueue(); + + if (gQueueScoreMessage) + { + if (gQueueScoreMessageTime < level.time) + { + SendScoreboardMessageToAllClients(); + + gQueueScoreMessageTime = 0; + gQueueScoreMessage = 0; + } + } + g_LastFrameTime = level.time; } diff --git a/CODE-mp/game/g_misc.c b/CODE-mp/game/g_misc.c index 9e44cb2..2d9d096 100644 --- a/CODE-mp/game/g_misc.c +++ b/CODE-mp/game/g_misc.c @@ -4,6 +4,8 @@ #include "g_local.h" +#include "ai_main.h" //for the g2animents + #define HOLOCRON_RESPAWN_TIME 30000 #define MAX_AMMO_GIVE 2 #define STATION_RECHARGE_TIME 3000//800 @@ -1546,3 +1548,1155 @@ void SP_fx_runner( gentity_t *ent ) trap_LinkEntity( ent ); } + +//rww - here starts the main example g2animent stuff +#define ANIMENT_TYPE_STORMTROOPER 0 +#define ANIMENT_TYPE_RODIAN 1 + +#define TROOPER_PAIN_SOUNDS 4 +#define TROOPER_DEATH_SOUNDS 3 +#define TROOPER_ALERT_SOUNDS 5 +int gTrooperSound_Pain[TROOPER_PAIN_SOUNDS]; +int gTrooperSound_Death[TROOPER_DEATH_SOUNDS]; +int gTrooperSound_Alert[TROOPER_ALERT_SOUNDS]; + +#define RODIAN_PAIN_SOUNDS 4 +#define RODIAN_DEATH_SOUNDS 3 +#define RODIAN_ALERT_SOUNDS 5 +int gRodianSound_Pain[RODIAN_PAIN_SOUNDS]; +int gRodianSound_Death[RODIAN_DEATH_SOUNDS]; +int gRodianSound_Alert[RODIAN_ALERT_SOUNDS]; + +int G_PickDeathAnim( gentity_t *self, vec3_t point, int damage, int mod, int hitLoc ); +void AnimEntFireWeapon( gentity_t *ent, qboolean altFire ); +int GetNearestVisibleWP(vec3_t org, int ignore); +int InFieldOfVision(vec3_t viewangles, float fov, vec3_t angles); +extern float gBotEdit; + +void ExampleAnimEntAlertOthers(gentity_t *self) +{ + //alert all the other animents in the area + int i = 0; + + while (i < MAX_GENTITIES) + { + if (g_entities[i].inuse && + g_entities[i].s.eType == ET_GRAPPLE && + g_entities[i].health > 0) + { + if (g_entities[i].bolt_Motion == ENTITYNUM_NONE && trap_InPVS(self->r.currentOrigin, g_entities[i].r.currentOrigin)) + { + g_entities[i].bolt_Motion = self->bolt_Motion; + g_entities[i].speed = level.time + 4000; //4 seconds til we forget about the enemy + g_entities[i].bolt_RArm = level.time + Q_irand(500, 1000); + } + } + + i++; + } +} + +void ExampleAnimEnt_Die( gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int damage, int mod ) +{ + self->s.torsoAnim = G_PickDeathAnim(self, self->pos1, damage, mod, HL_NONE); + + if (self->s.torsoAnim < 0 || self->s.torsoAnim >= MAX_TOTALANIMATIONS) + { //?! (bad) + self->s.torsoAnim = BOTH_DEATH1; + } + + self->s.legsAnim = self->s.torsoAnim; + self->health = 1; + self->s.eFlags |= EF_DEAD; + self->takedamage = qfalse; + self->r.contents = 0; + + if (self->watertype == ANIMENT_TYPE_STORMTROOPER) + { + G_Sound(self, CHAN_AUTO, gTrooperSound_Death[Q_irand(0, TROOPER_DEATH_SOUNDS-1)]); + } + else if (self->watertype == ANIMENT_TYPE_RODIAN) + { + G_Sound(self, CHAN_AUTO, gRodianSound_Death[Q_irand(0, RODIAN_DEATH_SOUNDS-1)]); + } + + if (mod == MOD_SABER) + { //Set the velocity up a bit to make the limb fly up more than it otherwise would. + vec3_t preDelta; + VectorCopy(self->s.pos.trDelta, preDelta); + + if (Q_irand(1, 10) < 5) + { + self->s.pos.trDelta[0] += Q_irand(10, 40); + } + else + { + self->s.pos.trDelta[0] -= Q_irand(10, 40); + } + if (Q_irand(1, 10) < 5) + { + self->s.pos.trDelta[1] += Q_irand(10, 40); + } + else + { + self->s.pos.trDelta[1] -= Q_irand(10, 40); + } + self->s.pos.trDelta[2] += 100; + G_CheckForDismemberment(self, self->pos1, damage, self->s.torsoAnim); + + VectorCopy(preDelta, self->s.pos.trDelta); + } + + if (self->bolt_Motion != ENTITYNUM_NONE) + { + ExampleAnimEntAlertOthers(self); + } + + trap_LinkEntity(self); + + self->bolt_Head = level.time + 5000; +} + +void ExampleAnimEnt_Pain(gentity_t *self, gentity_t *attacker, int damage) +{ + int painAnim = (BOTH_PAIN1 + Q_irand(0, 3)); + int animLen = (bgGlobalAnimations[painAnim].numFrames * fabs(bgGlobalAnimations[painAnim].frameLerp))-50; + + while (painAnim == self->s.torsoAnim) + { + painAnim = (BOTH_PAIN1 + Q_irand(0, 3)); + } + + self->s.torsoAnim = painAnim; + self->s.legsAnim = painAnim; + self->bolt_LArm = level.time + animLen; + + if (self->watertype == ANIMENT_TYPE_STORMTROOPER) + { + G_Sound(self, CHAN_AUTO, gTrooperSound_Pain[Q_irand(0, TROOPER_PAIN_SOUNDS-1)]); + } + else if (self->watertype == ANIMENT_TYPE_RODIAN) + { + G_Sound(self, CHAN_AUTO, gRodianSound_Pain[Q_irand(0, RODIAN_PAIN_SOUNDS-1)]); + } + + if (attacker && attacker->client && self->bolt_Motion == ENTITYNUM_NONE) + { + self->bolt_Motion = attacker->s.number; + self->speed = level.time + 4000; //4 seconds til we forget about the enemy + ExampleAnimEntAlertOthers(self); + self->bolt_RArm = level.time + Q_irand(500, 1000); + } +} + +void ExampleAnimEntTouch(gentity_t *self, gentity_t *other, trace_t *trace) +{ + +} + +//We can use this method of movement without horrible choppiness, because +//we are smoothing out the lerpOrigin on the client when rendering this eType. +int ExampleAnimEntMove(gentity_t *self, vec3_t moveTo, float stepSize) +{ + trace_t tr; + vec3_t stepTo; + vec3_t stepSub; + vec3_t stepGoal; + int didMove = 0; + + if (self->s.groundEntityNum == ENTITYNUM_NONE) + { + return 2; + } + + VectorCopy(moveTo, stepTo); + stepTo[2] = self->r.currentOrigin[2]; + + VectorSubtract(stepTo, self->r.currentOrigin, stepSub); + + if (VectorLength(stepSub) < 32) + { + return 2; + } + + VectorNormalize(stepSub); + + stepGoal[0] = self->r.currentOrigin[0] + stepSub[0]*stepSize; + stepGoal[1] = self->r.currentOrigin[1] + stepSub[1]*stepSize; + stepGoal[2] = self->r.currentOrigin[2] + stepSub[2]*stepSize; + + trap_Trace(&tr, self->r.currentOrigin, self->r.mins, self->r.maxs, stepGoal, self->s.number, self->clipmask); + + if (!tr.startsolid && !tr.allsolid && tr.fraction) + { + vec3_t vecSub; + VectorSubtract(self->r.currentOrigin, tr.endpos, vecSub); + + if (VectorLength(vecSub) > (stepSize/2)) + { + self->r.currentOrigin[0] = tr.endpos[0]; + self->r.currentOrigin[1] = tr.endpos[1]; + self->s.pos.trBase[0] = tr.endpos[0]; + self->s.pos.trBase[1] = tr.endpos[1]; + self->s.origin[0] = tr.endpos[0]; + self->s.origin[1] = tr.endpos[1]; + trap_LinkEntity(self); + didMove = 1; + } + } + + if (didMove != 1) + { //stair check + vec3_t trFrom; + vec3_t trTo; + vec3_t trDir; + vec3_t vecMeasure; + + VectorCopy(tr.endpos, trFrom); + trFrom[2] += 16; + + VectorSubtract(/*tr.endpos*/stepGoal, self->r.currentOrigin, trDir); + VectorNormalize(trDir); + trTo[0] = tr.endpos[0] + trDir[0]*2; + trTo[1] = tr.endpos[1] + trDir[1]*2; + trTo[2] = tr.endpos[2] + trDir[2]*2; + trTo[2] += 16; + + VectorSubtract(trFrom, trTo, vecMeasure); + + if (VectorLength(vecMeasure) > 1) + { + trap_Trace(&tr, trFrom, self->r.mins, self->r.maxs, trTo, self->s.number, self->clipmask); + + if (!tr.startsolid && !tr.allsolid && tr.fraction == 1) + { //clear trace here, probably up a step + vec3_t trDown; + vec3_t trUp; + VectorCopy(tr.endpos, trUp); + VectorCopy(tr.endpos, trDown); + trDown[2] -= 16; + + trap_Trace(&tr, trFrom, self->r.mins, self->r.maxs, trTo, self->s.number, self->clipmask); + + if (!tr.startsolid && !tr.allsolid) + { //plop us down on the step after moving up + VectorCopy(tr.endpos, self->r.currentOrigin); + VectorCopy(tr.endpos, self->s.pos.trBase); + VectorCopy(tr.endpos, self->s.origin); + trap_LinkEntity(self); + didMove = 1; + } + } + } + } + + return didMove; +} + +float ExampleAnimEntYaw(gentity_t *self, float idealYaw, float yawSpeed) +{ + float curYaw = 0; + float diffYaw = 0; + + curYaw = AngleNormalize360(self->s.apos.trBase[YAW]); + + diffYaw = AngleSubtract( curYaw, idealYaw ); + + if ( fabs(diffYaw) > 0.25f ) + { + if ( fabs(diffYaw) > yawSpeed ) + { + // cap max speed + curYaw += (diffYaw > 0.0f) ? -yawSpeed : yawSpeed; + } + else + { + // small enough + curYaw -= diffYaw; + } + } + + return curYaw; +} + +void ExampleAnimEntLook(gentity_t *self, vec3_t lookTo) +{ + vec3_t lookSub; + + VectorSubtract(lookTo, self->r.currentOrigin, lookSub); + VectorNormalize(lookSub); + vectoangles(lookSub, lookSub); + + if (lookSub[PITCH] < -180) + { + lookSub[PITCH] -= 90; + } + + //VectorCopy(lookSub, self->s.apos.trBase); + self->s.apos.trBase[PITCH] = lookSub[PITCH]; + self->s.apos.trBase[ROLL] = 0; + self->s.apos.trBase[YAW] = ExampleAnimEntYaw(self, lookSub[YAW], 20); +} + +qboolean ExampleAnimEntClearLOS(gentity_t *self, vec3_t point) +{ + trace_t tr; + + trap_Trace(&tr, self->r.currentOrigin, 0, 0, point, self->s.number, self->clipmask); + + if (tr.fraction == 1 || + tr.entityNum < MAX_CLIENTS) + { //clear LOS, or would be hitting a client (they're all bad!), so fire. + return qtrue; + } + + return qfalse; +} + +void ExampleAnimEntWeaponHandling(gentity_t *self) +{ + if (self->bolt_RArm > level.time) + { + return; + } + + if (self->boltpoint4) + { + if (self->s.weapon == WP_DISRUPTOR) + { + AnimEntFireWeapon(self, qtrue); + G_AddEvent(self, EV_FIRE_WEAPON, 1); + self->bolt_RArm = level.time + Q_irand(1500, 2500); + } + else + { + AnimEntFireWeapon(self, qfalse); + G_AddEvent(self, EV_FIRE_WEAPON, 0); + self->bolt_RArm = level.time + Q_irand(700, 1000); + } + } +} + +qboolean ExampleAnimEntWayValidCheck(gentity_t *self) +{ + wpobject_t *currentWP; + trace_t tr; + + if (self->bolt_Waist < 0 || + self->bolt_Waist >= gWPNum) + { + return qfalse; + } + + if (self->boltpoint1 < level.time) + { + return qfalse; + } + + if (self->boltpoint2 < level.time) + { + return qfalse; + } + + currentWP = gWPArray[self->bolt_Waist]; + + if (!currentWP) + { + return qfalse; + } + + trap_Trace(&tr, self->r.currentOrigin, 0, 0, currentWP->origin, self->s.number, self->clipmask); + + if (tr.fraction == 1) + { //allow one second for time you cannot see the point. If we go beyond that, kill the connection. + self->boltpoint2 = level.time + 1000; + } + + return qtrue; +} + +//Simple nav routine utilizing bot path data +//bolt_Waist represents our current indexed waypoint +void ExampleAnimEntNavigation(gentity_t *self, vec3_t goalPos) +{ + if (self->bolt_Waist == -1 || + !ExampleAnimEntWayValidCheck(self)) + { + int wpIndex = GetNearestVisibleWP(self->r.currentOrigin, self->s.number); + + if (wpIndex >= 0 && wpIndex < gWPNum) + { + self->bolt_Waist = wpIndex; + self->boltpoint1 = level.time + 10000; //10 seconds to get to the point + self->boltpoint2 = level.time + 1000; //initialize the 1 second allowed visibility + } + else + { + self->bolt_Waist = -1; + } + } + + if (self->bolt_Waist != -1) + { //we have a point to go to + wpobject_t *currentWP = gWPArray[self->bolt_Waist]; + + if (currentWP) + { + vec3_t subLen; + float vecLen = 0; + + VectorCopy(currentWP->origin, goalPos); + VectorSubtract(self->r.currentOrigin, currentWP->origin, subLen); + vecLen = VectorLength(subLen); + + if (vecLen <= 40) + { + int desiredIndex = -20; + + if (!self->boltpoint3) + { + desiredIndex = currentWP->index+1; + } + else + { + desiredIndex = currentWP->index-1; + } + + if (desiredIndex != -20) + { + if (desiredIndex < 0) + { + self->boltpoint3 = 0; + desiredIndex = currentWP->index+1; + } + if (desiredIndex >= gWPNum) + { + self->boltpoint3 = 1; + desiredIndex = currentWP->index-1; + } + } + + if (desiredIndex != -1 && desiredIndex >= 0 && desiredIndex < gWPNum) + { + currentWP = gWPArray[desiredIndex]; + + if (currentWP) + { + self->bolt_Waist = desiredIndex; + self->boltpoint1 = level.time + 10000; //every time we grab a new point, set the allowed travel-to time again + VectorCopy(currentWP->origin, goalPos); + } + } + } + } + } + else + { //We have no place to go. Run toward the origin mindlessly. + VectorClear(goalPos); + } +} + +void ExampleAnimEntEnemyHandling(gentity_t *self, float enDist) +{ + int i = 0; + int bestIndex = -1; + float minDist = enDist; + + while (i < MAX_CLIENTS) + { + if (g_entities[i].inuse && g_entities[i].client && g_entities[i].health > 0 && g_entities[i].client->sess.sessionTeam != TEAM_SPECTATOR) + { + vec3_t checkLen; + float fCheckLen; + + VectorSubtract(self->r.currentOrigin, g_entities[i].client->ps.origin, checkLen); + + fCheckLen = VectorLength(checkLen); + + if (fCheckLen < (minDist - 128)) + { + vec3_t enAngles; + VectorSubtract(g_entities[i].client->ps.origin, self->r.currentOrigin, enAngles); + vectoangles(enAngles, enAngles); + if ((InFieldOfVision(self->s.apos.trBase, 120, enAngles) || self->s.genericenemyindex > level.time) && ExampleAnimEntClearLOS(self, g_entities[i].client->ps.origin)) + { + minDist = fCheckLen; + bestIndex = i; + } + } + } + i++; + } + + if (bestIndex != -1) + { + self->bolt_Motion = bestIndex; + enDist = minDist; + self->speed = level.time + 4000; //4 seconds til we forget about the enemy + ExampleAnimEntAlertOthers(self); + self->bolt_RArm = level.time + Q_irand(500, 1000); + + if (self->watertype == ANIMENT_TYPE_STORMTROOPER) + { + G_Sound(self, CHAN_AUTO, gTrooperSound_Alert[Q_irand(0, TROOPER_ALERT_SOUNDS-1)]); + } + else if (self->watertype == ANIMENT_TYPE_RODIAN) + { + G_Sound(self, CHAN_AUTO, gRodianSound_Alert[Q_irand(0, RODIAN_ALERT_SOUNDS-1)]); + } + } +} + +void ExampleAnimEntUpdateSelf(gentity_t *self) +{ + vec3_t preserveAngles; + + if (gBotEdit || !gWPNum) + { + if (!(self->s.eFlags & EF_DEAD)) + { + if (self->bolt_LArm < level.time) + { + self->s.torsoAnim = BOTH_ATTACK3; + self->s.legsAnim = BOTH_STAND3; + } + } + else + { + if (self->bolt_Head < level.time) + { + self->think = G_FreeEntity; + self->nextthink = level.time; + return; + } + } + + VectorCopy(self->s.apos.trBase, preserveAngles); + G_RunObject(self); + VectorCopy(preserveAngles, self->s.apos.trBase); + return; + } + + if (!(self->s.eFlags & EF_DEAD)) + { + if (self->bolt_LArm < level.time) + { + vec3_t goalPos; + int didMove = 0; + float enDist = 999999999; + float runSpeed = 18; + vec3_t enemyOrigin; + qboolean hasEnemyLOS = qfalse; + int originalEnemyIndex = self->bolt_Motion; + + if (self->bolt_Motion != ENTITYNUM_NONE && + g_entities[self->bolt_Motion].inuse && + g_entities[self->bolt_Motion].client) + { + if (g_entities[self->bolt_Motion].client->sess.sessionTeam == TEAM_SPECTATOR) + { + self->bolt_Motion = ENTITYNUM_NONE; + } + } + + if (gWPNum > 0) + { + if (self->bolt_Motion != ENTITYNUM_NONE && + g_entities[self->bolt_Motion].inuse && + g_entities[self->bolt_Motion].client) + { + vec3_t enSubVec; + VectorSubtract(self->r.currentOrigin, g_entities[self->bolt_Motion].client->ps.origin, enSubVec); + + enDist = VectorLength(enSubVec); + + VectorCopy(g_entities[self->bolt_Motion].client->ps.origin, enemyOrigin); + + if (g_entities[self->bolt_Motion].client->pers.cmd.upmove < 0) + { + enemyOrigin[2] -= 8; + } + else + { + enemyOrigin[2] += 8; + } + + hasEnemyLOS = ExampleAnimEntClearLOS(self, enemyOrigin); + } + + if (hasEnemyLOS && enDist < 512 && self->splashRadius < level.time) + { + if (rand()%10 <= 8) + { + if (self->splashMethodOfDeath) + { + self->splashMethodOfDeath = 0; + } + else + { + self->splashMethodOfDeath = 1; + } + } + + if (self->watertype == ANIMENT_TYPE_RODIAN) + { //these guys stand still more often because they are "snipers" + if (rand()%10 <= 7) + { + self->splashMethodOfDeath = 1; + } + } + + self->splashRadius = level.time + Q_irand(2000, 5000); + } + + if (hasEnemyLOS && (enDist < 512 || self->watertype == ANIMENT_TYPE_RODIAN) && self->splashMethodOfDeath) + { + VectorCopy(self->r.currentOrigin, goalPos); + } + else + { + ExampleAnimEntNavigation(self, goalPos); + } + } + else + { //No path data? Eh. Just run toward the origin mindlessly. + VectorClear(goalPos); + } + + if (self->bolt_Motion == ENTITYNUM_NONE) + { + runSpeed = 6; + } + + didMove = ExampleAnimEntMove(self, goalPos, runSpeed); + + if (self->bolt_Motion != ENTITYNUM_NONE && + g_entities[self->bolt_Motion].inuse && + g_entities[self->bolt_Motion].client) + { + if (self->speed < level.time || g_entities[self->bolt_Motion].health < 1) + { + self->bolt_Motion = ENTITYNUM_NONE; + } + else + { + if (self->bolt_Motion != originalEnemyIndex) + { + vec3_t enSubVec; + VectorSubtract(self->r.currentOrigin, g_entities[self->bolt_Motion].client->ps.origin, enSubVec); + + enDist = VectorLength(enSubVec); + } + } + } + + ExampleAnimEntEnemyHandling(self, enDist); + + if (self->bolt_Motion != ENTITYNUM_NONE && + g_entities[self->bolt_Motion].inuse && + g_entities[self->bolt_Motion].client) + { + if (originalEnemyIndex != self->bolt_Motion) + { + VectorCopy(g_entities[self->bolt_Motion].client->ps.origin, enemyOrigin); + + if (g_entities[self->bolt_Motion].client->pers.cmd.upmove < 0) + { + enemyOrigin[2] -= 8; + } + else + { + enemyOrigin[2] += 8; + } + + hasEnemyLOS = ExampleAnimEntClearLOS(self, enemyOrigin); + } + + if (hasEnemyLOS) + { + vec3_t enAngles; + vec3_t enAimOrg; + vec3_t selfAimOrg; + vec3_t myZeroPitchAngles; + + VectorCopy(g_entities[self->bolt_Motion].client->ps.origin, enAimOrg); + VectorCopy(self->r.currentOrigin, selfAimOrg); + enAimOrg[2] = selfAimOrg[2]; + + VectorSubtract(enAimOrg, selfAimOrg, enAngles); + vectoangles(enAngles, enAngles); + + VectorCopy(self->s.apos.trBase, myZeroPitchAngles); + myZeroPitchAngles[PITCH] = 0; + if (InFieldOfVision(myZeroPitchAngles, 50, enAngles)) + { + self->boltpoint4 = 1; + } + self->speed = level.time + 4000; //4 seconds til we forget about the enemy + } + else + { + self->boltpoint4 = 0; + } + ExampleAnimEntLook(self, enemyOrigin); + } + else + { + self->boltpoint4 = 0; + ExampleAnimEntLook(self, goalPos); + } + + if (!didMove) + { //not just didMove 2, this means we're actually probably stuck + vec3_t aFwd, aRight; + vec3_t newGoalPos; + + AngleVectors(self->s.apos.trBase, aFwd, aRight, 0); + newGoalPos[0] = self->r.currentOrigin[0] + aRight[0]*64 - aFwd[0]*64; + newGoalPos[1] = self->r.currentOrigin[1] + aRight[1]*64 - aFwd[1]*64; + newGoalPos[2] = self->r.currentOrigin[2] + aRight[2]*64 - aFwd[2]*64; + + //Try moving to the right of the direction we're looking, to get around stuff + didMove = ExampleAnimEntMove(self, newGoalPos, 18); + + if (!didMove) + { //still? Try to the left. + newGoalPos[0] = self->r.currentOrigin[0] - aRight[0]*64 - aFwd[0]*64; + newGoalPos[1] = self->r.currentOrigin[1] - aRight[1]*64 - aFwd[1]*64; + newGoalPos[2] = self->r.currentOrigin[2] - aRight[2]*64 - aFwd[2]*64; + + didMove = ExampleAnimEntMove(self, newGoalPos, 18); + } + } + + if (didMove == 1) + { + if (self->bolt_Motion == ENTITYNUM_NONE) + { + self->s.torsoAnim = BOTH_WALK1; + self->s.legsAnim = BOTH_WALK1; + } + else + { + self->s.torsoAnim = BOTH_ATTACK3; + self->s.legsAnim = BOTH_RUN2; + } + } + else + { + self->s.torsoAnim = BOTH_ATTACK3; + self->s.legsAnim = BOTH_STAND3; + } + + ExampleAnimEntWeaponHandling(self); + } + } + else + { + if (self->bolt_Head < level.time) + { + self->think = G_FreeEntity; + self->nextthink = level.time; + return; + } + } + + VectorCopy(self->s.apos.trBase, preserveAngles); + G_RunObject(self); + VectorCopy(preserveAngles, self->s.apos.trBase); +} + +void G_SpawnExampleAnimEnt(vec3_t pos, int aeType) +{ + gentity_t *animEnt; + vec3_t playerMins; + vec3_t playerMaxs; + + VectorSet(playerMins, -15, -15, DEFAULT_MINS_2); + VectorSet(playerMaxs, 15, 15, DEFAULT_MAXS_2); + + if (aeType == ANIMENT_TYPE_STORMTROOPER) + { + if (!gTrooperSound_Pain[0]) + { + gTrooperSound_Pain[0] = G_SoundIndex("sound/chars/st1/misc/pain25"); + gTrooperSound_Pain[1] = G_SoundIndex("sound/chars/st1/misc/pain50"); + gTrooperSound_Pain[2] = G_SoundIndex("sound/chars/st1/misc/pain75"); + gTrooperSound_Pain[3] = G_SoundIndex("sound/chars/st1/misc/pain100"); + + gTrooperSound_Death[0] = G_SoundIndex("sound/chars/st1/misc/death1"); + gTrooperSound_Death[1] = G_SoundIndex("sound/chars/st1/misc/death2"); + gTrooperSound_Death[2] = G_SoundIndex("sound/chars/st1/misc/death3"); + + gTrooperSound_Alert[0] = G_SoundIndex("sound/chars/st1/misc/detected1"); + gTrooperSound_Alert[1] = G_SoundIndex("sound/chars/st1/misc/detected2"); + gTrooperSound_Alert[2] = G_SoundIndex("sound/chars/st1/misc/detected3"); + gTrooperSound_Alert[3] = G_SoundIndex("sound/chars/st1/misc/detected4"); + gTrooperSound_Alert[4] = G_SoundIndex("sound/chars/st1/misc/detected5"); + } + } + else if (aeType == ANIMENT_TYPE_RODIAN) + { + if (!gRodianSound_Pain[0]) + { + gRodianSound_Pain[0] = G_SoundIndex("sound/chars/rodian1/misc/pain25"); + gRodianSound_Pain[1] = G_SoundIndex("sound/chars/rodian1/misc/pain50"); + gRodianSound_Pain[2] = G_SoundIndex("sound/chars/rodian1/misc/pain75"); + gRodianSound_Pain[3] = G_SoundIndex("sound/chars/rodian1/misc/pain100"); + + gRodianSound_Death[0] = G_SoundIndex("sound/chars/rodian1/misc/death1"); + gRodianSound_Death[1] = G_SoundIndex("sound/chars/rodian1/misc/death2"); + gRodianSound_Death[2] = G_SoundIndex("sound/chars/rodian1/misc/death3"); + + gRodianSound_Alert[0] = G_SoundIndex("sound/chars/rodian1/misc/detected1"); + gRodianSound_Alert[1] = G_SoundIndex("sound/chars/rodian1/misc/detected2"); + gRodianSound_Alert[2] = G_SoundIndex("sound/chars/rodian1/misc/detected3"); + gRodianSound_Alert[3] = G_SoundIndex("sound/chars/rodian1/misc/detected4"); + gRodianSound_Alert[4] = G_SoundIndex("sound/chars/rodian1/misc/detected5"); + } + } + + animEnt = G_Spawn(); + + animEnt->watertype = aeType; //set the animent type + + animEnt->s.eType = ET_GRAPPLE; //ET_GRAPPLE is the reserved special type for G2 anim ents. + + if (animEnt->watertype == ANIMENT_TYPE_STORMTROOPER) + { + animEnt->s.modelindex = G_ModelIndex( "models/players/stormtrooper/model.glm" ); + } + else if (animEnt->watertype == ANIMENT_TYPE_RODIAN) + { + animEnt->s.modelindex = G_ModelIndex( "models/players/rodian/model.glm" ); + } + else + { + G_Error("Unknown AnimEnt type!\n"); + } + + animEnt->s.g2radius = 100; + + if (animEnt->watertype == ANIMENT_TYPE_STORMTROOPER) + { + animEnt->s.weapon = WP_BLASTER; //This will tell the client to stick a blaster in the model's hands upon model init. + } + else if (animEnt->watertype == ANIMENT_TYPE_RODIAN) + { + animEnt->s.weapon = WP_DISRUPTOR; //These guys get disruptors instead of blasters. + } + + animEnt->s.modelGhoul2 = 1; //Deal with it like any other ghoul2 ent, as far as killing instances. + + G_SetOrigin(animEnt, pos); + + animEnt->classname = "g2animent"; + + VectorCopy (playerMins, animEnt->r.mins); + VectorCopy (playerMaxs, animEnt->r.maxs); + + animEnt->r.svFlags = SVF_USE_CURRENT_ORIGIN; + + animEnt->clipmask = MASK_PLAYERSOLID; + animEnt->r.contents = MASK_PLAYERSOLID; + + animEnt->takedamage = qtrue; + + animEnt->health = 60; + + animEnt->s.owner = MAX_CLIENTS+1; + animEnt->s.shouldtarget = qtrue; + animEnt->s.teamowner = 0; + + trap_LinkEntity(animEnt); + + animEnt->pain = ExampleAnimEnt_Pain; + animEnt->die = ExampleAnimEnt_Die; + + animEnt->touch = ExampleAnimEntTouch; + + animEnt->think = ExampleAnimEntUpdateSelf; + animEnt->nextthink = level.time + 50; + + animEnt->s.torsoAnim = BOTH_ATTACK3; + animEnt->s.legsAnim = BOTH_STAND3; + + //initialize the "AI" values + animEnt->bolt_Waist = -1; //the waypoint index + animEnt->bolt_Motion = ENTITYNUM_NONE; //the enemy index + animEnt->splashMethodOfDeath = 0; //don't stand still while you have an enemy + animEnt->splashRadius = 0; //timer for randomly deciding to stand still + animEnt->boltpoint3 = 0; //running forward on the trail +} + +qboolean gEscaping = qfalse; +int gEscapeTime = 0; + +#ifdef ANIMENT_SPAWNER +int AESpawner_CountAnimEnts(void) +{ + int i = 0; + int count = 0; + + while (i < MAX_GENTITIES) + { + if (g_entities[i].inuse && g_entities[i].s.eType == ET_GRAPPLE) + { + count++; + } + i++; + } + + return count; +} + +qboolean AESpawner_NoClientInPVS(gentity_t *ent) +{ + int i = 0; + + while (i < MAX_CLIENTS) + { + if (g_entities[i].inuse && + g_entities[i].client && + trap_InPVS(ent->s.origin, g_entities[i].client->ps.origin)) + { + return qfalse; + } + + i++; + } + + return qtrue; +} + +qboolean AESpawner_PassAnimEntPVSCheck(gentity_t *ent) +{ + int count = 0; + int i = 0; + + if (!ent->bolt_LArm) + { //unlimited + return qtrue; + } + + while (i < MAX_GENTITIES) + { + if (g_entities[i].inuse && g_entities[i].s.eType == ET_GRAPPLE && + trap_InPVS(ent->r.currentOrigin, g_entities[i].r.currentOrigin)) + { + count++; + } + + if (count >= ent->bolt_LArm) + { //too many in this pvs.. + return qfalse; + } + i++; + } + + return qtrue; +} + +void AESpawner_Think(gentity_t *ent) +{ + int animEntCount; + + if (gBotEdit) + { + ent->nextthink = level.time + 1000; + return; + } + + if (!ent->bolt_LLeg) + { + animEntCount = -1; + } + else + { + animEntCount = AESpawner_CountAnimEnts(); + } + + if (animEntCount < ent->bolt_LLeg) + { + trace_t tr; + vec3_t playerMins; + vec3_t playerMaxs; + + VectorSet(playerMins, -15, -15, DEFAULT_MINS_2); + VectorSet(playerMaxs, 15, 15, DEFAULT_MAXS_2); + + trap_Trace(&tr, ent->s.origin, playerMins, playerMaxs, ent->s.origin, ent->s.number, MASK_PLAYERSOLID); + + if (tr.fraction == 1) + { + if (ent->bolt_Head || AESpawner_NoClientInPVS(ent)) + { + if (AESpawner_PassAnimEntPVSCheck(ent)) + { + G_SpawnExampleAnimEnt(ent->s.origin, ent->watertype); + } + } + } + } + + ent->nextthink = level.time + 1000; +} + +void SP_misc_animent_spawner(gentity_t *ent) +{ + if (g_gametype.integer != GT_SINGLE_PLAYER) + { + G_FreeEntity(ent); + return; + } + + G_SpawnInt( "spawninpvs", "0", &ent->bolt_Head ); + //If this is non-0, the spawner will spawn even if a client is in the PVS + G_SpawnInt( "othersinpvs", "3", &ent->bolt_LArm); + //Don't spawn more than this many animents in the PVS of this spawner. + //If 0, the amount is unlimited. + G_SpawnInt( "totalspawn", "12", &ent->bolt_LLeg); + //Only spawn if less than or equal to this many ents active globally. + //0 is unlimited, but that could cause horrible disaster. + G_SpawnInt( "spawntype", "0", &ent->watertype); + //Spawn type. 0 is stormtrooper, 1 is rodian. + + //Just precache the assets now + if (ent->watertype == ANIMENT_TYPE_STORMTROOPER) + { + gTrooperSound_Pain[0] = G_SoundIndex("sound/chars/st1/misc/pain25"); + gTrooperSound_Pain[1] = G_SoundIndex("sound/chars/st1/misc/pain50"); + gTrooperSound_Pain[2] = G_SoundIndex("sound/chars/st1/misc/pain75"); + gTrooperSound_Pain[3] = G_SoundIndex("sound/chars/st1/misc/pain100"); + + gTrooperSound_Death[0] = G_SoundIndex("sound/chars/st1/misc/death1"); + gTrooperSound_Death[1] = G_SoundIndex("sound/chars/st1/misc/death2"); + gTrooperSound_Death[2] = G_SoundIndex("sound/chars/st1/misc/death3"); + + gTrooperSound_Alert[0] = G_SoundIndex("sound/chars/st1/misc/detected1"); + gTrooperSound_Alert[1] = G_SoundIndex("sound/chars/st1/misc/detected2"); + gTrooperSound_Alert[2] = G_SoundIndex("sound/chars/st1/misc/detected3"); + gTrooperSound_Alert[3] = G_SoundIndex("sound/chars/st1/misc/detected4"); + gTrooperSound_Alert[4] = G_SoundIndex("sound/chars/st1/misc/detected5"); + + G_ModelIndex( "models/players/stormtrooper/model.glm" ); + } + else if (ent->watertype == ANIMENT_TYPE_RODIAN) + { + gRodianSound_Pain[0] = G_SoundIndex("sound/chars/rodian1/misc/pain25"); + gRodianSound_Pain[1] = G_SoundIndex("sound/chars/rodian1/misc/pain50"); + gRodianSound_Pain[2] = G_SoundIndex("sound/chars/rodian1/misc/pain75"); + gRodianSound_Pain[3] = G_SoundIndex("sound/chars/rodian1/misc/pain100"); + + gRodianSound_Death[0] = G_SoundIndex("sound/chars/rodian1/misc/death1"); + gRodianSound_Death[1] = G_SoundIndex("sound/chars/rodian1/misc/death2"); + gRodianSound_Death[2] = G_SoundIndex("sound/chars/rodian1/misc/death3"); + + gRodianSound_Alert[0] = G_SoundIndex("sound/chars/rodian1/misc/detected1"); + gRodianSound_Alert[1] = G_SoundIndex("sound/chars/rodian1/misc/detected2"); + gRodianSound_Alert[2] = G_SoundIndex("sound/chars/rodian1/misc/detected3"); + gRodianSound_Alert[3] = G_SoundIndex("sound/chars/rodian1/misc/detected4"); + gRodianSound_Alert[4] = G_SoundIndex("sound/chars/rodian1/misc/detected5"); + + G_ModelIndex( "models/players/rodian/model.glm" ); + } + + ent->think = AESpawner_Think; + ent->nextthink = level.time + Q_irand(50, 500); + trap_LinkEntity(ent); +} + +void Use_Target_Screenshake( gentity_t *ent, gentity_t *other, gentity_t *activator ) +{ + qboolean bGlobal = qfalse; + + if (ent->bolt_LArm) + { + bGlobal = qtrue; + } + + G_ScreenShake(ent->s.origin, NULL, ent->speed, ent->bolt_Head, bGlobal); +} + +void SP_target_screenshake(gentity_t *ent) +{ + if (g_gametype.integer != GT_SINGLE_PLAYER) + { + G_FreeEntity(ent); + return; + } + + G_SpawnFloat( "intensity", "10", &ent->speed ); + //intensity of the shake + G_SpawnInt( "duration", "800", &ent->bolt_Head ); + //duration of the shake + G_SpawnInt( "globalshake", "1", &ent->bolt_LArm ); + //non-0 if shake should be global (all clients). Otherwise, only in the PVS. + + ent->use = Use_Target_Screenshake; +} + +void LogExit( const char *string ); + +void Use_Target_Escapetrig( gentity_t *ent, gentity_t *other, gentity_t *activator ) +{ + if (!ent->bolt_LArm) + { + gEscaping = qtrue; + gEscapeTime = level.time + ent->bolt_Head; + } + else if (gEscaping) + { + int i = 0; + gEscaping = qfalse; + while (i < MAX_CLIENTS) + { //all of the survivors get 100 points! + if (g_entities[i].inuse && g_entities[i].client && g_entities[i].health > 0 && + g_entities[i].client->sess.sessionTeam != TEAM_SPECTATOR && + !(g_entities[i].client->ps.pm_flags & PMF_FOLLOW)) + { + AddScore(&g_entities[i], g_entities[i].client->ps.origin, 100); + } + i++; + } + if (activator && activator->inuse && activator->client) + { //the one who escaped gets 500 + AddScore(activator, activator->client->ps.origin, 500); + } + + LogExit("Escaped!"); + } +} + +void SP_target_escapetrig(gentity_t *ent) +{ + if (g_gametype.integer != GT_SINGLE_PLAYER) + { + G_FreeEntity(ent); + return; + } + + G_SpawnInt( "escapetime", "60000", &ent->bolt_Head); + //time given (in ms) for the escape + G_SpawnInt( "escapegoal", "0", &ent->bolt_LArm); + //if non-0, when used, will end an ongoing escape instead of start it + + ent->use = Use_Target_Escapetrig; +} + +#endif + +void G_CreateExampleAnimEnt(gentity_t *ent) +{ + vec3_t fwd, fwdPos; + + AngleVectors(ent->client->ps.viewangles, fwd, 0, 0); + + fwdPos[0] = ent->client->ps.origin[0] + fwd[0]*128; + fwdPos[1] = ent->client->ps.origin[1] + fwd[1]*128; + fwdPos[2] = ent->client->ps.origin[2] + fwd[2]*128; + + G_SpawnExampleAnimEnt(fwdPos, 0); +} +//rww - here ends the main example g2animent stuff + diff --git a/CODE-mp/game/g_mover.c b/CODE-mp/game/g_mover.c index 08a6f2c..eda285b 100644 --- a/CODE-mp/game/g_mover.c +++ b/CODE-mp/game/g_mover.c @@ -1197,9 +1197,10 @@ void Touch_Button(gentity_t *ent, gentity_t *other, trace_t *trace ) { } } - -/*QUAKED func_button (0 .5 .8) ? +/*QUAKED func_button (0 .5 .8) ? USABLE FPUSHABLE When a button is touched, it moves some distance in the direction of it's angle, triggers all of it's targets, waits some time, then returns to it's original position where it can be triggered again. +USABLE - Can activate with use button +FPUSHABLE - Can force-push it "model2" .md3 model to also draw "angle" determines the opening direction @@ -1268,6 +1269,11 @@ void SP_func_button( gentity_t *ent ) { ent->touch = Touch_Button; } + if ( (ent->spawnflags&SPF_BUTTON_USABLE) ) + { + ent->r.svFlags |= SVF_PLAYER_USABLE; + } + InitMover( ent ); } @@ -1793,18 +1799,40 @@ void SP_func_breakable( gentity_t *ent ) { if (strcmp(model, "rock") == 0) { + G_ModelIndex("models/chunks/rock/rock1_1.md3"); + G_ModelIndex("models/chunks/rock/rock1_2.md3"); + G_ModelIndex("models/chunks/rock/rock1_3.md3"); + G_ModelIndex("models/chunks/rock/rock1_4.md3"); ent->boltpoint2 = DEBRIS_SPECIALCASE_ROCK; } else if (strcmp(model, "chunks") == 0) { + G_ModelIndex("models/chunks/generic/chunks_1.md3"); + G_ModelIndex("models/chunks/generic/chunks_2.md3"); ent->boltpoint2 = DEBRIS_SPECIALCASE_CHUNKS; } else if (strcmp(model, "wood") == 0) { + G_ModelIndex("models/chunks/crate/crate1_1.md3"); + G_ModelIndex("models/chunks/crate/crate1_2.md3"); + G_ModelIndex("models/chunks/crate/crate1_3.md3"); + G_ModelIndex("models/chunks/crate/crate1_4.md3"); + G_ModelIndex("models/chunks/crate/crate2_1.md3"); + G_ModelIndex("models/chunks/crate/crate2_2.md3"); + G_ModelIndex("models/chunks/crate/crate2_3.md3"); + G_ModelIndex("models/chunks/crate/crate2_4.md3"); ent->boltpoint2 = DEBRIS_SPECIALCASE_WOOD; } else if (strcmp(model, "glass") == 0) { + G_ModelIndex("models/chunks/metal/metal1_1.md3"); + G_ModelIndex("models/chunks/metal/metal1_2.md3"); + G_ModelIndex("models/chunks/metal/metal1_3.md3"); + G_ModelIndex("models/chunks/metal/metal1_4.md3"); + G_ModelIndex("models/chunks/metal/metal2_1.md3"); + G_ModelIndex("models/chunks/metal/metal2_2.md3"); + G_ModelIndex("models/chunks/metal/metal2_3.md3"); + G_ModelIndex("models/chunks/metal/metal2_4.md3"); ent->boltpoint2 = DEBRIS_SPECIALCASE_GLASS; } else if (strcmp(model, "none") == 0) diff --git a/CODE-mp/game/g_object.c b/CODE-mp/game/g_object.c index 8718424..b6eb9ec 100644 --- a/CODE-mp/game/g_object.c +++ b/CODE-mp/game/g_object.c @@ -265,7 +265,11 @@ void G_RunObject( gentity_t *ent ) } // G_Sound( ent, G_SoundIndex( "sound/movers/objects/objectHit.wav" ) ); } - DoImpact( ent, traceEnt, qtrue ); + + if (ent->s.weapon != WP_SABER) + { + DoImpact( ent, traceEnt, qtrue ); + } } if ( !ent || (ent->takedamage&&ent->health <= 0) ) diff --git a/CODE-mp/game/g_public.h b/CODE-mp/game/g_public.h index 1595f45..7651496 100644 --- a/CODE-mp/game/g_public.h +++ b/CODE-mp/game/g_public.h @@ -408,6 +408,7 @@ Ghoul2 Insert Start G_G2_SETMODELS, G_G2_GETBOLT, G_G2_GETBOLT_NOREC, + G_G2_GETBOLT_NOREC_NOROT, G_G2_INITGHOUL2MODEL, G_G2_ADDBOLT, G_G2_SETBOLTINFO, @@ -420,6 +421,7 @@ Ghoul2 Insert Start G_G2_HASGHOUL2MODELONINDEX, G_G2_REMOVEGHOUL2MODEL, G_G2_CLEANMODELS, + G_G2_COLLISIONDETECT, /* Ghoul2 Insert End diff --git a/CODE-mp/game/g_spawn.c b/CODE-mp/game/g_spawn.c index a21a752..f13135d 100644 --- a/CODE-mp/game/g_spawn.c +++ b/CODE-mp/game/g_spawn.c @@ -175,6 +175,12 @@ void SP_misc_model_health_power_converter( gentity_t *ent ); void SP_fx_runner( gentity_t *ent ); +#ifdef ANIMENT_SPAWNER +void SP_misc_animent_spawner(gentity_t *ent); +void SP_target_screenshake(gentity_t *ent); +void SP_target_escapetrig(gentity_t *ent); +#endif + void SP_misc_holocron(gentity_t *ent); void SP_shooter_blaster( gentity_t *ent ); @@ -262,6 +268,11 @@ spawn_t spawns[] = { {"misc_model_health_power_converter", SP_misc_model_health_power_converter}, {"fx_runner", SP_fx_runner}, +#ifdef ANIMENT_SPAWNER + {"misc_animent_spawner", SP_misc_animent_spawner}, + {"target_screenshake", SP_target_screenshake}, + {"target_escapetrig", SP_target_escapetrig}, +#endif {"misc_holocron", SP_misc_holocron}, @@ -733,6 +744,16 @@ Every map should have exactly one worldspawn. "music" music wav file "gravity" 800 is default gravity "message" Text to print during connection process + +BSP Options +"gridsize" size of lighting grid to "X Y Z". default="64 64 128" +"ambient" scale of global light (from _color) +"fog" shader name of the global fog texture - must include the full path, such as "textures/rj/fog1" +"distancecull" value for vis for the maximum viewing distance +"chopsize" value for bsp on the maximum polygon / portal size +"ls_Xr" override lightstyle X with this pattern for Red. +"ls_Xg" green (valid patterns are "a-z") +"ls_Xb" blue (a is OFF, z is ON) */ void SP_worldspawn( void ) { diff --git a/CODE-mp/game/g_syscalls.asm b/CODE-mp/game/g_syscalls.asm index 0a639b6..446e504 100644 --- a/CODE-mp/game/g_syscalls.asm +++ b/CODE-mp/game/g_syscalls.asm @@ -197,18 +197,20 @@ equ trap_G2_HaveWeGhoul2Models -585 ; G_G2_HAVEWEGHOULMODELS equ trap_G2_SetGhoul2ModelIndexes -586 ; G_G2_SETMODELS equ trap_G2API_GetBoltMatrix -587 ; G_G2_GETBOLT equ trap_G2API_GetBoltMatrix_NoReconstruct -588 ; G_G2_GETBOLT_NOREC -equ trap_G2API_InitGhoul2Model -589 ; G_G2_INITGHOUL2MODEL -equ trap_G2API_AddBolt -590 ; G_G2_ADDBOLT -equ trap_G2API_SetBoltInfo -591 ; G_G2_SETBOLTINFO -equ trap_G2API_SetBoneAngles -592 ; G_G2_ANGLEOVERRIDE -equ trap_G2API_SetBoneAnim -593 ; G_G2_PLAYANIM -equ trap_G2API_GetGLAName -594 ; G_G2_GETGLANAME -equ trap_G2API_CopyGhoul2Instance -595 ; G_G2_COPYGHOUL2INSTANCE -equ trap_G2API_CopySpecificGhoul2Model -596 ; G_G2_COPYSPECIFICGHOUL2MODEL -equ trap_G2API_DuplicateGhoul2Instance -597 ; G_G2_DUPLICATEGHOUL2INSTANCE -equ trap_G2API_HasGhoul2ModelOnIndex -598 ; G_G2_HASGHOUL2MODELONINDEX -equ trap_G2API_RemoveGhoul2Model -599 ; G_G2_REMOVEGHOUL2MODEL -equ trap_G2API_CleanGhoul2Models -600 ; G_G2_CLEANMODELS +equ trap_G2API_GetBoltMatrix_NoRecNoRot -589 ; G_G2_GETBOLT_NOREC_NOROT +equ trap_G2API_InitGhoul2Model -590 ; G_G2_INITGHOUL2MODEL +equ trap_G2API_AddBolt -591 ; G_G2_ADDBOLT +equ trap_G2API_SetBoltInfo -592 ; G_G2_SETBOLTINFO +equ trap_G2API_SetBoneAngles -593 ; G_G2_ANGLEOVERRIDE +equ trap_G2API_SetBoneAnim -594 ; G_G2_PLAYANIM +equ trap_G2API_GetGLAName -595 ; G_G2_GETGLANAME +equ trap_G2API_CopyGhoul2Instance -596 ; G_G2_COPYGHOUL2INSTANCE +equ trap_G2API_CopySpecificGhoul2Model -597 ; G_G2_COPYSPECIFICGHOUL2MODEL +equ trap_G2API_DuplicateGhoul2Instance -598 ; G_G2_DUPLICATEGHOUL2INSTANCE +equ trap_G2API_HasGhoul2ModelOnIndex -599 ; G_G2_HASGHOUL2MODELONINDEX +equ trap_G2API_RemoveGhoul2Model -600 ; G_G2_REMOVEGHOUL2MODEL +equ trap_G2API_CleanGhoul2Models -601 ; G_G2_CLEANMODELS +equ trap_G2API_CollisionDetect -602 ; G_G2_COLLISIONDETECT ; hardcoded functions diff --git a/CODE-mp/game/g_syscalls.c b/CODE-mp/game/g_syscalls.c index 4f94c6e..1cbac9b 100644 --- a/CODE-mp/game/g_syscalls.c +++ b/CODE-mp/game/g_syscalls.c @@ -841,6 +841,12 @@ qboolean trap_G2API_GetBoltMatrix_NoReconstruct(void *ghoul2, const int modelInd return (qboolean)(syscall(G_G2_GETBOLT_NOREC, ghoul2, modelIndex, boltIndex, matrix, angles, position, frameNum, modelList, scale)); } +qboolean trap_G2API_GetBoltMatrix_NoRecNoRot(void *ghoul2, const int modelIndex, const int boltIndex, mdxaBone_t *matrix, + const vec3_t angles, const vec3_t position, const int frameNum, qhandle_t *modelList, vec3_t scale) +{ //Same as above but force it to not reconstruct the skeleton before getting the bolt position + return (qboolean)(syscall(G_G2_GETBOLT_NOREC_NOROT, ghoul2, modelIndex, boltIndex, matrix, angles, position, frameNum, modelList, scale)); +} + int trap_G2API_InitGhoul2Model(void **ghoul2Ptr, const char *fileName, int modelIndex, qhandle_t customSkin, qhandle_t customShader, int modelFlags, int lodBias) { @@ -905,6 +911,24 @@ void trap_G2API_CleanGhoul2Models(void **ghoul2Ptr) syscall(G_G2_CLEANMODELS, ghoul2Ptr); } +void trap_G2API_CollisionDetect ( + CollisionRecord_t *collRecMap, + void* ghoul2, + const vec3_t angles, + const vec3_t position, + int frameNumber, + int entNum, + vec3_t rayStart, + vec3_t rayEnd, + vec3_t scale, + int traceFlags, + int useLod, + float fRadius + ) +{ + syscall ( G_G2_COLLISIONDETECT, collRecMap, ghoul2, angles, position, frameNumber, entNum, rayStart, rayEnd, scale, traceFlags, useLod, PASSFLOAT(fRadius) ); +} + /* Ghoul2 Insert End */ diff --git a/CODE-mp/game/g_team.c b/CODE-mp/game/g_team.c index 70eb8b3..2d7cd85 100644 --- a/CODE-mp/game/g_team.c +++ b/CODE-mp/game/g_team.c @@ -188,6 +188,11 @@ qboolean OnSameTeam( gentity_t *ent1, gentity_t *ent2 ) { return qfalse; } + if (g_gametype.integer == GT_SINGLE_PLAYER) + { + return qtrue; + } + if ( g_gametype.integer < GT_TEAM ) { return qfalse; } diff --git a/CODE-mp/game/g_trigger.c b/CODE-mp/game/g_trigger.c index 09c82d4..a19a7c4 100644 --- a/CODE-mp/game/g_trigger.c +++ b/CODE-mp/game/g_trigger.c @@ -293,14 +293,17 @@ void Use_target_push( gentity_t *self, gentity_t *other, gentity_t *activator ) // play fly sound every 1.5 seconds if ( activator->fly_sound_debounce_time < level.time ) { activator->fly_sound_debounce_time = level.time + 1500; - G_Sound( activator, CHAN_AUTO, self->noise_index ); + if (self->noise_index) + { + G_Sound( activator, CHAN_AUTO, self->noise_index ); + } } } /*QUAKED target_push (.5 .5 .5) (-8 -8 -8) (8 8 8) bouncepad Pushes the activator in the direction.of angle, or towards a target apex. "speed" defaults to 1000 -if "bouncepad", play bounce noise instead of windfly +if "bouncepad", play bounce noise instead of none */ void SP_target_push( gentity_t *self ) { if (!self->speed) { diff --git a/CODE-mp/game/g_utils.c b/CODE-mp/game/g_utils.c index e708e67..ca82336 100644 --- a/CODE-mp/game/g_utils.c +++ b/CODE-mp/game/g_utils.c @@ -951,6 +951,7 @@ Try and use an entity in the world, directly ahead of us #define USE_DISTANCE 64.0f +extern void Touch_Button(gentity_t *ent, gentity_t *other, trace_t *trace ); void TryUse( gentity_t *ent ) { gentity_t *target; @@ -986,8 +987,14 @@ void TryUse( gentity_t *ent ) NPC_SetAnim( ent, SETANIM_LEGS, BOTH_FORCEPUSH, SETANIM_FLAG_NORMAL|SETANIM_FLAG_HOLD ); } */ - - target->use(target, ent, ent); + if ( target->touch == Touch_Button ) + {//pretend we touched it + target->touch(target, ent, NULL); + } + else + { + target->use(target, ent, ent); + } return; } } diff --git a/CODE-mp/game/g_weapon.c b/CODE-mp/game/g_weapon.c index 295567c..a6453a9 100644 --- a/CODE-mp/game/g_weapon.c +++ b/CODE-mp/game/g_weapon.c @@ -298,6 +298,10 @@ void WP_FireBlasterMissile( gentity_t *ent, vec3_t start, vec3_t dir, qboolean a int damage = BLASTER_DAMAGE; gentity_t *missile; + if (ent->s.eType == ET_GRAPPLE) + { //animent + damage = 10; + } // NOTENOTE Vehicle models are not yet implemented /* if ( ent->client && ent->client->ps.vehicleModel != 0 ) { @@ -549,10 +553,20 @@ void WP_DisruptorAltFire( gentity_t *ent ) VectorCopy( muzzle, muzzle2 ); // making a backup copy - VectorCopy( ent->client->ps.origin, start ); - start[2] += ent->client->ps.viewheight;//By eyes + if (ent->client) + { + VectorCopy( ent->client->ps.origin, start ); + start[2] += ent->client->ps.viewheight;//By eyes - count = ( level.time - ent->client->ps.weaponChargeTime ) / DISRUPTOR_CHARGE_UNIT; + count = ( level.time - ent->client->ps.weaponChargeTime ) / DISRUPTOR_CHARGE_UNIT; + } + else + { + VectorCopy( ent->r.currentOrigin, start ); + start[2] += 24; + + count = ( 100 ) / DISRUPTOR_CHARGE_UNIT; + } count *= 2; @@ -652,7 +666,10 @@ void WP_DisruptorAltFire( gentity_t *ent ) if ( LogAccuracyHit( traceEnt, ent )) { - ent->client->accuracy_hits++; + if (ent->client) + { + ent->client->accuracy_hits++; + } } } else @@ -741,6 +758,12 @@ static void WP_FireDisruptor( gentity_t *ent, qboolean altFire ) altFire = qfalse; } + if (ent && ent->s.eType == ET_GRAPPLE && !ent->client) + { //special case for animents + WP_DisruptorAltFire( ent ); + return; + } + if ( altFire ) { WP_DisruptorAltFire( ent ); @@ -2831,6 +2854,107 @@ void FireWeapon( gentity_t *ent, qboolean altFire ) { G_LogWeaponFire(ent->s.number, ent->s.weapon); } +void AnimEntCalcMuzzlePoint ( gentity_t *ent, vec3_t forward, vec3_t right, vec3_t up, vec3_t muzzlePoint ) +{ + int weapontype; + vec3_t muzzleOffPoint; + + weapontype = ent->s.weapon; + VectorCopy( ent->s.pos.trBase, muzzlePoint ); + + VectorCopy(WP_MuzzlePoint[weapontype], muzzleOffPoint); + + if (weapontype > WP_NONE && weapontype < WP_NUM_WEAPONS) + { // Use the table to generate the muzzlepoint; + { // Crouching. Use the add-to-Z method to adjust vertically. + VectorMA(muzzlePoint, muzzleOffPoint[0], forward, muzzlePoint); + VectorMA(muzzlePoint, muzzleOffPoint[1], right, muzzlePoint); + muzzlePoint[2] += 24 + muzzleOffPoint[2]; + } + } + + // snap to integer coordinates for more efficient network bandwidth usage + SnapVector( muzzlePoint ); +} + +void AnimEntFireWeapon( gentity_t *ent, qboolean altFire ) +{ + vec3_t modifiedAngles; + VectorCopy(ent->s.apos.trBase, modifiedAngles); +// modifiedAngles[PITCH] = -modifiedAngles[PITCH]; + if (modifiedAngles[PITCH] < -180) + { + modifiedAngles[PITCH] += 90; + } + AngleVectors( modifiedAngles, forward, right, up ); + + AnimEntCalcMuzzlePoint ( ent, forward, right, up, muzzle ); + + //rww - NOTE: I have only tested the bryar, blaster, and disruptor for weapon firing. + //Other routines will likely have a client pointer reference in them and cause a crash. + + // fire the specific weapon + switch( ent->s.weapon ) + { + case WP_STUN_BATON: + WP_FireStunBaton( ent, altFire ); + break; + + case WP_SABER: + break; + + case WP_BRYAR_PISTOL: + WP_FireBryarPistol( ent, altFire ); + break; + + case WP_BLASTER: + WP_FireBlaster( ent, altFire ); + break; + + case WP_DISRUPTOR: + WP_FireDisruptor( ent, altFire ); + break; + + case WP_BOWCASTER: + WP_FireBowcaster( ent, altFire ); + break; + + case WP_REPEATER: + WP_FireRepeater( ent, altFire ); + break; + + case WP_DEMP2: + WP_FireDEMP2( ent, altFire ); + break; + + case WP_FLECHETTE: + WP_FireFlechette( ent, altFire ); + break; + + case WP_ROCKET_LAUNCHER: + WP_FireRocket( ent, altFire ); + break; + + case WP_THERMAL: + WP_FireThermalDetonator( ent, altFire ); + break; + + case WP_TRIP_MINE: + WP_PlaceLaserTrap( ent, altFire ); + break; + + case WP_DET_PACK: + WP_DropDetPack( ent, altFire ); + break; + + case WP_EMPLACED_GUN: + WP_FireEmplaced( ent, altFire ); + break; + default: + break; + } +} + //--------------------------------------------------------- static void WP_FireEmplaced( gentity_t *ent, qboolean altFire ) //--------------------------------------------------------- diff --git a/CODE-mp/game/q_shared.c b/CODE-mp/game/q_shared.c index e188a33..522b29e 100644 --- a/CODE-mp/game/q_shared.c +++ b/CODE-mp/game/q_shared.c @@ -568,6 +568,83 @@ int COM_ParseInfos( char *buf, int max, char infos[][MAX_INFO_STRING] ) { } #endif +/* +=============== +COM_ParseString +=============== +*/ +qboolean COM_ParseString( const char **data, const char **s ) +{ +// *s = COM_ParseExt( data, qtrue ); + *s = COM_ParseExt( data, qfalse ); + if ( s[0] == 0 ) + { + Com_Printf("unexpected EOF\n"); + return qtrue; + } + return qfalse; +} + +/* +=============== +COM_ParseInt +=============== +*/ +qboolean COM_ParseInt( const char **data, int *i ) +{ + const char *token; + + token = COM_ParseExt( data, qfalse ); + if ( token[0] == 0 ) + { + Com_Printf( "unexpected EOF\n" ); + return qtrue; + } + + *i = atoi( token ); + return qfalse; +} + +/* +=============== +COM_ParseFloat +=============== +*/ +qboolean COM_ParseFloat( const char **data, float *f ) +{ + const char *token; + + token = COM_ParseExt( data, qfalse ); + if ( token[0] == 0 ) + { + Com_Printf( "unexpected EOF\n" ); + return qtrue; + } + + *f = atof( token ); + return qfalse; +} + +/* +=============== +COM_ParseVec4 +=============== +*/ +qboolean COM_ParseVec4( const char **buffer, vec4_t *c) +{ + int i; + float f; + + for (i = 0; i < 4; i++) + { + if (COM_ParseFloat(buffer, &f)) + { + return qtrue; + } + (*c)[i] = f; + } + return qfalse; +} /* ================== diff --git a/CODE-mp/game/q_shared.h b/CODE-mp/game/q_shared.h index 2c02b64..893cc84 100644 --- a/CODE-mp/game/q_shared.h +++ b/CODE-mp/game/q_shared.h @@ -292,6 +292,7 @@ typedef int sfxHandle_t; typedef int fileHandle_t; typedef int clipHandle_t; +#define G2_COLLISION_ENABLED #ifndef NULL #define NULL ((void *)0) @@ -364,6 +365,7 @@ typedef enum { typedef enum { BLOCKED_NONE, + BLOCKED_BOUNCE_MOVE, BLOCKED_PARRY_BROKEN, BLOCKED_ATK_BOUNCE, BLOCKED_UPPER_RIGHT, @@ -669,7 +671,9 @@ extern vec4_t colorLtBlue; extern vec4_t colorDkBlue; #define Q_COLOR_ESCAPE '^' -#define Q_IsColorString(p) ( p && *(p) == Q_COLOR_ESCAPE && *((p)+1) && *((p)+1) != Q_COLOR_ESCAPE ) +// you MUST have the last bit on here about colour strings being less than 7 or taiwanese strings register as colour!!!! +#define Q_IsColorString(p) ( p && *(p) == Q_COLOR_ESCAPE && *((p)+1) && *((p)+1) != Q_COLOR_ESCAPE && *((p)+1) <= '7' ) + #define COLOR_BLACK '0' #define COLOR_RED '1' @@ -939,6 +943,10 @@ char *COM_ParseExt( const char **data_p, qboolean allowLineBreak ); int COM_Compress( char *data_p ); void COM_ParseError( char *format, ... ); void COM_ParseWarning( char *format, ... ); +qboolean COM_ParseString( const char **data, const char **s ); +qboolean COM_ParseInt( const char **data, int *i ); +qboolean COM_ParseFloat( const char **data, float *f ); +qboolean COM_ParseVec4( const char **buffer, vec4_t *c); //int COM_ParseInfos( char *buf, int max, char infos[][MAX_INFO_STRING] ); #define MAX_TOKENLENGTH 1024 @@ -1178,6 +1186,11 @@ typedef struct }CollisionRecord_t; #define MAX_G2_COLLISIONS 16 + +#ifdef G2_COLLISION_ENABLED +typedef CollisionRecord_t G2Trace_t[MAX_G2_COLLISIONS]; // map that describes all of the parts of ghoul2 models that got hit +#endif + /* Ghoul2 Insert End */ @@ -1526,6 +1539,9 @@ typedef struct playerState_s { float emplacedTime; qboolean isJediMaster; + qboolean forceRestricted; + qboolean trueJedi; + qboolean trueNonJedi; int saberIndex; int genericEnemyIndex; @@ -1619,8 +1635,7 @@ typedef struct playerState_s { // so they aren't game/cgame only definitions // #define BUTTON_ATTACK 1 -//#define BUTTON_TALK 2 // displays talk balloon and disables actions -//#define BUTTON_FORCEJUMP 2 //rww - might be better to just reassign this from button1 on the client.. +#define BUTTON_TALK 2 // displays talk balloon and disables actions #define BUTTON_USE_HOLDABLE 4 #define BUTTON_GESTURE 8 #define BUTTON_WALKING 16 // walking can't just be infered from MOVE_RUN diff --git a/CODE-mp/game/vssver.scc b/CODE-mp/game/vssver.scc index bea999a..701e106 100644 Binary files a/CODE-mp/game/vssver.scc and b/CODE-mp/game/vssver.scc differ diff --git a/CODE-mp/game/w_force.c b/CODE-mp/game/w_force.c index 73cbd3d..70ad534 100644 --- a/CODE-mp/game/w_force.c +++ b/CODE-mp/game/w_force.c @@ -21,13 +21,15 @@ int ysalamiriLoopSound = 0; #define FORCE_VELOCITY_DAMAGE 0 -void G_PreDefSound(vec3_t org, int pdSound) +gentity_t *G_PreDefSound(vec3_t org, int pdSound) { gentity_t *te; te = G_TempEntity( org, EV_PREDEFSOUND ); te->s.eventParm = pdSound; VectorCopy(org, te->s.origin); + + return te; } qboolean InFront( vec3_t spot, vec3_t from, vec3_t fromAngles, float threshHold ) @@ -422,6 +424,13 @@ void WP_InitForcePowers( gentity_t *ent ) ent->client->ps.fd.forcePowerSelected = 0; } } + + while (i < NUM_FORCE_POWERS) + { + ent->client->ps.fd.forcePowerBaseLevel[i] = ent->client->ps.fd.forcePowerLevel[i]; + i++; + } + ent->client->ps.fd.forceUsingAdded = 0; } void WP_SpawnInitForcePowers( gentity_t *ent ) @@ -492,7 +501,8 @@ void WP_SpawnInitForcePowers( gentity_t *ent ) while (i < NUM_FORCE_POWERS) { - ent->client->ps.fd.forcePowerBaseLevel[i] = ent->client->ps.fd.forcePowerLevel[i]; + //Don't know why I was doing this here either. + //ent->client->ps.fd.forcePowerBaseLevel[i] = ent->client->ps.fd.forcePowerLevel[i]; ent->client->ps.fd.forcePowerDebounce[i] = 0; ent->client->ps.fd.forcePowerDuration[i] = 0; @@ -501,7 +511,8 @@ void WP_SpawnInitForcePowers( gentity_t *ent ) } ent->client->ps.fd.forcePowerRegenDebounceTime = 0; - ent->client->ps.fd.forceUsingAdded = 0; + //I wonder why I was doing this. + //ent->client->ps.fd.forceUsingAdded = 0; ent->client->ps.fd.forceJumpZStart = 0; ent->client->ps.fd.forceJumpCharge = 0; ent->client->ps.fd.forceJumpSound = 0; @@ -655,6 +666,7 @@ int WP_AbsorbConversion(gentity_t *attacked, int atdAbsLevel, gentity_t *attacke { int getLevel = 0; int addTot = 0; + gentity_t *abSound; if (atPower != FP_LIGHTNING && atPower != FP_DRAIN && @@ -698,7 +710,13 @@ int WP_AbsorbConversion(gentity_t *attacked, int atdAbsLevel, gentity_t *attacke } //play sound indicating that attack was absorbed - G_PreDefSound(attacker->client->ps.origin, PDSOUND_ABSORBHIT); + if (attacked->client->forcePowerSoundDebounce < level.time) + { + abSound = G_PreDefSound(attacked->client->ps.origin, PDSOUND_ABSORBHIT); + abSound->s.trickedentindex = attacked->s.number; + + attacked->client->forcePowerSoundDebounce = level.time + 400; + } return getLevel; } @@ -958,7 +976,7 @@ void ForceHeal( gentity_t *self ) if (self->client->ps.fd.forcePowerLevel[FP_HEAL] == FORCE_LEVEL_3) { - self->health += 50; + self->health += 25; //This was 50, but that angered the Balance God. if (self->health > self->client->ps.stats[STAT_MAX_HEALTH]) { @@ -968,7 +986,7 @@ void ForceHeal( gentity_t *self ) } else if (self->client->ps.fd.forcePowerLevel[FP_HEAL] == FORCE_LEVEL_2) { - self->health += 25; + self->health += 10; if (self->health > self->client->ps.stats[STAT_MAX_HEALTH]) { @@ -978,7 +996,7 @@ void ForceHeal( gentity_t *self ) } else { - self->health += 10; + self->health += 5; if (self->health > self->client->ps.stats[STAT_MAX_HEALTH]) { @@ -1502,6 +1520,13 @@ void ForceLightningDamage( gentity_t *self, gentity_t *traceEnt, vec3_t dir, vec if ( traceEnt && traceEnt->takedamage ) { + if (!traceEnt->client && traceEnt->s.eType == ET_GRAPPLE) + { //g2animent + if (traceEnt->s.genericenemyindex < level.time) + { + traceEnt->s.genericenemyindex = level.time + 2000; + } + } if ( traceEnt->client ) {//an enemy or object if (ForcePowerUsableOn(self, traceEnt, FP_LIGHTNING)) @@ -1724,6 +1749,13 @@ void ForceDrainDamage( gentity_t *self, gentity_t *traceEnt, vec3_t dir, vec3_t { if ( traceEnt->client && (!OnSameTeam(self, traceEnt) || g_friendlyFire.integer) && self->client->ps.fd.forceDrainTime < level.time && traceEnt->client->ps.fd.forcePower ) {//an enemy or object + if (!traceEnt->client && traceEnt->s.eType == ET_GRAPPLE) + { //g2animent + if (traceEnt->s.genericenemyindex < level.time) + { + traceEnt->s.genericenemyindex = level.time + 2000; + } + } if (ForcePowerUsableOn(self, traceEnt, FP_DRAIN)) { int modPowerLevel = -1; @@ -1766,7 +1798,7 @@ void ForceDrainDamage( gentity_t *self, gentity_t *traceEnt, vec3_t dir, vec3_t if (dmg) { - traceEnt->client->ps.fd.forcePower -= dmg; + traceEnt->client->ps.fd.forcePower -= (dmg); } if (traceEnt->client->ps.fd.forcePower < 0) { @@ -1819,9 +1851,14 @@ void ForceDrainDamage( gentity_t *self, gentity_t *traceEnt, vec3_t dir, vec3_t // traceEnt->client->ps.powerups[PW_DISINT_1] = level.time + 500; } - tent = G_TempEntity( impactPoint, EV_FORCE_DRAINED); - tent->s.eventParm = DirToByte(dir); - tent->s.owner = traceEnt->s.number; + if (traceEnt->client->forcePowerSoundDebounce < level.time) + { + tent = G_TempEntity( impactPoint, EV_FORCE_DRAINED); + tent->s.eventParm = DirToByte(dir); + tent->s.owner = traceEnt->s.number; + + traceEnt->client->forcePowerSoundDebounce = level.time + 400; + } } } } @@ -1962,7 +1999,7 @@ int ForceShootDrain( gentity_t *self ) } else*/ { - BG_ForcePowerDrain( &self->client->ps, FP_DRAIN, 1 ); + BG_ForcePowerDrain( &self->client->ps, FP_DRAIN, 5 ); //used to be 1, but this did, too, anger the God of Balance. } self->client->ps.fd.forcePowerRegenDebounceTime = level.time + 500; @@ -2528,6 +2565,7 @@ qboolean CanCounterThrow(gentity_t *self, qboolean pull) return 1; } +extern void Touch_Button(gentity_t *ent, gentity_t *other, trace_t *trace ); void ForceThrow( gentity_t *self, qboolean pull ) { //shove things in front of you away @@ -2669,6 +2707,14 @@ void ForceThrow( gentity_t *self, qboolean pull ) if (tr.fraction != 1.0 && tr.entityNum != ENTITYNUM_NONE) { + if (!g_entities[tr.entityNum].client && g_entities[tr.entityNum].s.eType == ET_GRAPPLE) + { //g2animent + if (g_entities[tr.entityNum].s.genericenemyindex < level.time) + { + g_entities[tr.entityNum].s.genericenemyindex = level.time + 2000; + } + } + numListedEntities = 0; entityList[numListedEntities] = tr.entityNum; numListedEntities++; @@ -2689,6 +2735,14 @@ void ForceThrow( gentity_t *self, qboolean pull ) { ent = &g_entities[entityList[e]]; + if (!ent->client && ent->s.eType == ET_GRAPPLE) + { //g2animent + if (ent->s.genericenemyindex < level.time) + { + ent->s.genericenemyindex = level.time + 2000; + } + } + if (ent) { if (ent->client) @@ -2767,30 +2821,40 @@ void ForceThrow( gentity_t *self, qboolean pull ) if ( ent->s.eType != ET_ITEM /*&& ent->e_ThinkFunc != thinkF_G_RunObject*/ )//|| !(ent->flags&FL_DROPPED_ITEM) )//was only dropped items { //FIXME: need pushable objects - if ( ent->s.eFlags & EF_NODRAW ) - { - continue; + if ( Q_stricmp( "func_button", ent->classname ) == 0 ) + {//we might push it + if ( pull || !(ent->spawnflags&SPF_BUTTON_FPUSHABLE) ) + {//not force-pushable, never pullable + continue; + } } - if ( !ent->client ) + else { - if ( Q_stricmp( "lightsaber", ent->classname ) != 0 ) - {//not a lightsaber -// if ( !(ent->svFlags&SVF_GLASS_BRUSH) ) -// {//and not glass - if ( Q_stricmp( "func_door", ent->classname ) != 0 || !(ent->spawnflags & 2/*MOVER_FORCE_ACTIVATE*/) ) - {//not a force-usable door - if ( Q_stricmp( "limb", ent->classname ) ) - {//not a limb + if ( ent->s.eFlags & EF_NODRAW ) + { + continue; + } + if ( !ent->client ) + { + if ( Q_stricmp( "lightsaber", ent->classname ) != 0 ) + {//not a lightsaber + // if ( !(ent->svFlags&SVF_GLASS_BRUSH) ) + // {//and not glass + if ( Q_stricmp( "func_door", ent->classname ) != 0 || !(ent->spawnflags & 2/*MOVER_FORCE_ACTIVATE*/) ) + {//not a force-usable door + if ( Q_stricmp( "limb", ent->classname ) ) + {//not a limb + continue; + } + } + else if ( ent->moverState != MOVER_POS1 && ent->moverState != MOVER_POS2 ) + {//not at rest continue; } - } - else if ( ent->moverState != MOVER_POS1 && ent->moverState != MOVER_POS2 ) - {//not at rest - continue; - } -// } + // } + } + //continue; } - //continue; } } } @@ -3134,6 +3198,11 @@ void ForceThrow( gentity_t *self, qboolean pull ) } GEntity_UseFunc( push_list[x], self, self ); } + else if ( Q_stricmp( "func_button", push_list[x]->classname ) == 0 ) + {//pretend you pushed it + Touch_Button( push_list[x], self, NULL ); + continue; + } } } @@ -3658,6 +3727,19 @@ static void WP_ForcePowerRun( gentity_t *self, forcePowers_t forcePower, usercmd WP_ForcePowerStop(self, FP_GRIP); break; } + + if (self->client->ps.fd.forcePowerDebounce[FP_PULL] < level.time) + { //This is sort of not ideal. Using the debounce value reserved for pull for this because pull doesn't need it. + BG_ForcePowerDrain( &self->client->ps, forcePower, 1 ); + self->client->ps.fd.forcePowerDebounce[FP_PULL] = level.time + 100; + } + + if (self->client->ps.fd.forcePower < 1) + { + WP_ForcePowerStop(self, FP_GRIP); + break; + } + DoGripAction(self, forcePower); break; case FP_LEVITATION: @@ -3779,7 +3861,6 @@ static void WP_ForcePowerRun( gentity_t *self, forcePowers_t forcePower, usercmd case FP_SABERTHROW: break; case FP_PROTECT: - case FP_ABSORB: if (self->client->ps.fd.forcePowerDebounce[forcePower] < level.time) { BG_ForcePowerDrain( &self->client->ps, forcePower, 1 ); @@ -3791,6 +3872,18 @@ static void WP_ForcePowerRun( gentity_t *self, forcePowers_t forcePower, usercmd self->client->ps.fd.forcePowerDebounce[forcePower] = level.time + 300; } break; + case FP_ABSORB: + if (self->client->ps.fd.forcePowerDebounce[forcePower] < level.time) + { + BG_ForcePowerDrain( &self->client->ps, forcePower, 1 ); + if (self->client->ps.fd.forcePower < 1) + { + WP_ForcePowerStop(self, forcePower); + } + + self->client->ps.fd.forcePowerDebounce[forcePower] = level.time + 600; + } + break; default: break; } @@ -4307,6 +4400,29 @@ void JediMasterUpdate(gentity_t *self) } } +qboolean WP_HasForcePowers( const playerState_t *ps ) +{ + int i; + if ( ps ) + { + for ( i = 0; i < NUM_FORCE_POWERS; i++ ) + { + if ( i == FP_LEVITATION ) + { + if ( ps->fd.forcePowerLevel[i] > FORCE_LEVEL_1 ) + { + return qtrue; + } + } + else if ( ps->fd.forcePowerLevel[i] > FORCE_LEVEL_0 ) + { + return qtrue; + } + } + } + return qfalse; +} + void WP_ForcePowersUpdate( gentity_t *self, usercmd_t *ucmd ) { qboolean usingForce = qfalse; @@ -4333,6 +4449,19 @@ void WP_ForcePowersUpdate( gentity_t *self, usercmd_t *ucmd ) return; } +/* + if (g_trueJedi.integer) + { + if (self->client->ps.weapon != WP_SABER) + { + self->client->ps.forceRestricted = qtrue; + } + else + { + self->client->ps.forceRestricted = qfalse; + } + } +*/ if (self->client->ps.fd.saberAnimLevel > self->client->ps.fd.forcePowerLevel[FP_SABERATTACK]) { self->client->ps.fd.saberAnimLevel = self->client->ps.fd.forcePowerLevel[FP_SABERATTACK]; @@ -4768,18 +4897,28 @@ void WP_ForcePowersUpdate( gentity_t *self, usercmd_t *ucmd ) { if (g_gametype.integer != GT_HOLOCRON || g_MaxHolocronCarry.value) { - if (self->client->ps.powerups[PW_FORCE_BOON]) + //if (!g_trueJedi.integer || self->client->ps.weapon == WP_SABER) + //let non-jedi force regen since we're doing a more strict jedi/non-jedi thing... this gives dark jedi something to drain { - WP_ForcePowerRegenerate( self, 6 ); + if (self->client->ps.powerups[PW_FORCE_BOON]) + { + WP_ForcePowerRegenerate( self, 6 ); + } + else if (self->client->ps.isJediMaster && g_gametype.integer == GT_JEDIMASTER) + { + WP_ForcePowerRegenerate( self, 4 ); //jedi master regenerates 4 times as fast + } + else + { + WP_ForcePowerRegenerate( self, 0 ); + } } - else if (self->client->ps.isJediMaster && g_gametype.integer == GT_JEDIMASTER) + /* + else if (g_trueJedi.integer && self->client->ps.weapon != WP_SABER) { - WP_ForcePowerRegenerate( self, 4 ); //jedi master regenerates 4 times as fast - } - else - { - WP_ForcePowerRegenerate( self, 0 ); + self->client->ps.fd.forcePower = 0; } + */ } else { //regenerate based on the number of holocrons carried diff --git a/CODE-mp/game/w_saber.c b/CODE-mp/game/w_saber.c index 5e59060..6e9850b 100644 --- a/CODE-mp/game/w_saber.c +++ b/CODE-mp/game/w_saber.c @@ -4,6 +4,8 @@ #include "ai_main.h" #include "..\ghoul2\g2.h" +#define SABER_BOX_SIZE 16.0f + extern bot_state_t *botstates[MAX_CLIENTS]; extern qboolean InFront( vec3_t spot, vec3_t from, vec3_t fromAngles, float threshHold ); @@ -12,10 +14,50 @@ int saberOffSound = 0; int saberOnSound = 0; int saberHumSound = 0; +qboolean PM_SaberInTransition( int move ); + float RandFloat(float min, float max) { return ((rand() * (max - min)) / 32768.0F) + min; } +//#define DEBUG_SABER_BOX + +#ifdef DEBUG_SABER_BOX +void G_DebugBoxLines(vec3_t mins, vec3_t maxs, int duration) +{ + vec3_t start; + vec3_t end; + + float x = maxs[0] - mins[0]; + float y = maxs[1] - mins[1]; + + // top of box + VectorCopy(maxs, start); + VectorCopy(maxs, end); + start[0] -= x; + G_TestLine(start, end, 0x00000ff, duration); + end[0] = start[0]; + end[1] -= y; + G_TestLine(start, end, 0x00000ff, duration); + start[1] = end[1]; + start[0] += x; + G_TestLine(start, end, 0x00000ff, duration); + G_TestLine(start, maxs, 0x00000ff, duration); + // bottom of box + VectorCopy(mins, start); + VectorCopy(mins, end); + start[0] += x; + G_TestLine(start, end, 0x00000ff, duration); + end[0] = start[0]; + end[1] += y; + G_TestLine(start, end, 0x00000ff, duration); + start[1] = end[1]; + start[0] -= x; + G_TestLine(start, end, 0x00000ff, duration); + G_TestLine(start, mins, 0x00000ff, duration); +} +#endif + void SaberUpdateSelf(gentity_t *ent) { if (ent->r.ownerNum == ENTITYNUM_NONE) @@ -57,6 +99,19 @@ void SaberUpdateSelf(gentity_t *ent) } else { +#ifdef DEBUG_SABER_BOX + vec3_t dbgMins; + vec3_t dbgMaxs; + + if (ent->r.ownerNum == 0) + { + VectorAdd( ent->r.currentOrigin, ent->r.mins, dbgMins ); + VectorAdd( ent->r.currentOrigin, ent->r.maxs, dbgMaxs ); + + G_DebugBoxLines(dbgMins, dbgMaxs, 100); + } +#endif + ent->r.contents = CONTENTS_LIGHTSABER; ent->clipmask = MASK_PLAYERSOLID | CONTENTS_LIGHTSABER; } @@ -94,8 +149,8 @@ void WP_SaberInitBladeData( gentity_t *ent ) saberent->clipmask = MASK_PLAYERSOLID | CONTENTS_LIGHTSABER; saberent->r.contents = CONTENTS_LIGHTSABER; - VectorSet( saberent->r.mins, -8.0f, -8.0f, -8.0f ); - VectorSet( saberent->r.maxs, 8.0f, 8.0f, 8.0f ); + VectorSet( saberent->r.mins, -SABER_BOX_SIZE, -SABER_BOX_SIZE, -SABER_BOX_SIZE ); + VectorSet( saberent->r.maxs, SABER_BOX_SIZE, SABER_BOX_SIZE, SABER_BOX_SIZE ); saberent->mass = 10; @@ -174,97 +229,52 @@ static void G_SwingAngles( float destination, float swingTolerance, float clampT //NOTE: If C` is modified this function should be modified as well (and vice versa) void G_G2ClientSpineAngles( gentity_t *ent, vec3_t viewAngles, const vec3_t angles, vec3_t thoracicAngles, vec3_t ulAngles, vec3_t llAngles ) { - int ang = 0; - - VectorClear(ulAngles); - VectorClear(llAngles); - viewAngles[YAW] = AngleDelta( ent->client->ps.viewangles[YAW], angles[YAW] ); - if ( !BG_FlippingAnim( ent->client->ps.legsAnim ) && - !BG_SpinningSaberAnim( ent->client->ps.legsAnim ) && - !BG_SpinningSaberAnim( ent->client->ps.torsoAnim ) && - !BG_InSpecialJump( ent->client->ps.legsAnim ) && - !BG_InSpecialJump( ent->client->ps.torsoAnim ) && - !BG_InRoll(&ent->client->ps, ent->client->ps.legsAnim) && - !BG_SaberInSpecial(ent->client->ps.saberMove) && - !BG_SaberInSpecialAttack(ent->client->ps.torsoAnim) && - !BG_SaberInSpecialAttack(ent->client->ps.legsAnim) ) - { + if ( !BG_FlippingAnim( ent->client->ps.legsAnim ) + && !BG_SpinningSaberAnim( ent->client->ps.legsAnim ) + && !BG_SpinningSaberAnim( ent->client->ps.torsoAnim ) + && ent->client->ps.legsAnim != ent->client->ps.torsoAnim )//NOTE: presumes your legs & torso are on the same frame, though they *should* be because PM_SetAnimFinal tries to keep them in synch + {//FIXME: no need to do this if legs and torso on are same frame //adjust for motion offset mdxaBone_t boltMatrix; vec3_t motionFwd, motionAngles; + vec3_t motionRt, tempAng; + int ang; - trap_G2API_GetBoltMatrix_NoReconstruct( ent->client->ghoul2, 0, ent->bolt_Motion, &boltMatrix, vec3_origin, ent->client->ps.origin, level.time, /*cgs.gameModels*/0, vec3_origin); - //trap_G2API_GiveMeVectorFromMatrix( &boltMatrix, POSITIVE_X, motionFwd ); - //POSITIVE_X: - /* - motionFwd[0] = boltMatrix.matrix[0][0]; - motionFwd[1] = boltMatrix.matrix[1][0]; - motionFwd[2] = boltMatrix.matrix[2][0]; - */ - - - //NEGATIVE_Y: + trap_G2API_GetBoltMatrix_NoRecNoRot( ent->client->ghoul2, 0, ent->bolt_Motion, &boltMatrix, vec3_origin, ent->client->ps.origin, level.time, /*cgs.gameModels*/0, vec3_origin); + //trap_G2API_GiveMeVectorFromMatrix( &boltMatrix, NEGATIVE_Y, motionFwd ); motionFwd[0] = -boltMatrix.matrix[0][1]; motionFwd[1] = -boltMatrix.matrix[1][1]; motionFwd[2] = -boltMatrix.matrix[2][1]; vectoangles( motionFwd, motionAngles ); + + //trap_G2API_GiveMeVectorFromMatrix( &boltMatrix, NEGATIVE_X, motionRt ); + motionRt[0] = -boltMatrix.matrix[0][0]; + motionRt[1] = -boltMatrix.matrix[1][0]; + motionRt[2] = -boltMatrix.matrix[2][0]; + vectoangles( motionRt, tempAng ); + motionAngles[ROLL] = -tempAng[PITCH]; + for ( ang = 0; ang < 3; ang++ ) { viewAngles[ang] = AngleNormalize180( viewAngles[ang] - AngleNormalize180( motionAngles[ang] ) ); } - - if (viewAngles[YAW] < -90) - { - viewAngles[YAW] += 360; - } - - viewAngles[YAW] -= 90; } //distribute the angles differently up the spine //NOTE: each of these distributions must add up to 1.0f - thoracicAngles[PITCH] = 0;//viewAngles[PITCH]*0.20f; - llAngles[PITCH] = 0;//viewAngles[PITCH]*0.40f; - ulAngles[PITCH] = 0;//viewAngles[PITCH]*0.40f; + thoracicAngles[PITCH] = viewAngles[PITCH]*0.20f; + llAngles[PITCH] = viewAngles[PITCH]*0.40f; + ulAngles[PITCH] = viewAngles[PITCH]*0.40f; - thoracicAngles[YAW] = viewAngles[YAW]*0.20f - (viewAngles[PITCH]*(viewAngles[YAW]*.020f)); - ulAngles[YAW] = viewAngles[YAW]*0.25f - (viewAngles[PITCH]*(viewAngles[YAW]*.0005f)); - llAngles[YAW] = viewAngles[YAW]*0.25f - (viewAngles[PITCH]*(viewAngles[YAW]*.0005f)); - - if (thoracicAngles[YAW] > 20) - { - thoracicAngles[YAW] = 20; - } - if (ulAngles[YAW] > 20) - { - ulAngles[YAW] = 20; - } - if (llAngles[YAW] > 20) - { - llAngles[YAW] = 20; - } + thoracicAngles[YAW] = viewAngles[YAW]*0.20f; + ulAngles[YAW] = viewAngles[YAW]*0.35f; + llAngles[YAW] = viewAngles[YAW]*0.45f; thoracicAngles[ROLL] = viewAngles[ROLL]*0.20f; ulAngles[ROLL] = viewAngles[ROLL]*0.35f; llAngles[ROLL] = viewAngles[ROLL]*0.45f; - - for ( ang = 0; ang < 3; ang++ ) - { - if (ulAngles[ang] < 0) - { - ulAngles[ang] += 360; - } - } - - //thoracic is added modified again by neckAngle calculations, so don't set it until then -// BG_G2SetBoneAngles( cent, cent->gent, cent->gent->upperLumbarBone, ulAngles, BONE_ANGLES_POSTMULT, POSITIVE_X, NEGATIVE_Y, NEGATIVE_Z, cgs.model_draw); -// BG_G2SetBoneAngles( cent, cent->gent, cent->gent->lowerLumbarBone, llAngles, BONE_ANGLES_POSTMULT, POSITIVE_X, NEGATIVE_Y, NEGATIVE_Z, cgs.model_draw); - -// trap_G2API_SetBoneAngles(cent->ghoul2, 0, "upper_lumbar", ulAngles, BONE_ANGLES_POSTMULT, POSITIVE_X, NEGATIVE_Y, NEGATIVE_Z, cgs.gameModels, 0, cg.time); -// trap_G2API_SetBoneAngles(cent->ghoul2, 0, "lower_lumbar", llAngles, BONE_ANGLES_POSTMULT, POSITIVE_X, NEGATIVE_Y, NEGATIVE_Z, cgs.gameModels, 0, cg.time); -// trap_G2API_SetBoneAngles(cent->ghoul2, 0, "thoracic", thoracicAngles, BONE_ANGLES_POSTMULT, POSITIVE_X, NEGATIVE_Y, NEGATIVE_Z, cgs.gameModels, 0, cg.time); } void G_G2PlayerAngles( gentity_t *ent, vec3_t legs[3], vec3_t legsAngles){ @@ -461,23 +471,10 @@ void G_G2PlayerAngles( gentity_t *ent, vec3_t legs[3], vec3_t legsAngles){ viewAngles[YAW] = viewAngles[ROLL] = 0; viewAngles[PITCH] *= 0.5; - VectorCopy( ent->client->ps.viewangles, angles ); - angles[PITCH] = 0; + VectorCopy(legsAngles, angles); G_G2ClientSpineAngles(ent, viewAngles, angles, thoracicAngles, ulAngles, llAngles); - ulAngles[YAW] += torsoAngles[YAW]*0.3; - llAngles[YAW] += torsoAngles[YAW]*0.3; - thoracicAngles[YAW] += torsoAngles[YAW]*0.4; - - ulAngles[PITCH] = torsoAngles[PITCH]*0.3; - llAngles[PITCH] = torsoAngles[PITCH]*0.3; - thoracicAngles[PITCH] = torsoAngles[PITCH]*0.4; - - ulAngles[ROLL] += torsoAngles[ROLL]*0.3; - llAngles[ROLL] += torsoAngles[ROLL]*0.3; - thoracicAngles[ROLL] += torsoAngles[ROLL]*0.4; - trap_G2API_SetBoneAngles(ent->client->ghoul2, 0, "upper_lumbar", ulAngles, BONE_ANGLES_POSTMULT, POSITIVE_X, NEGATIVE_Y, NEGATIVE_Z, NULL, 0, level.time); trap_G2API_SetBoneAngles(ent->client->ghoul2, 0, "lower_lumbar", llAngles, BONE_ANGLES_POSTMULT, POSITIVE_X, NEGATIVE_Y, NEGATIVE_Z, NULL, 0, level.time); trap_G2API_SetBoneAngles(ent->client->ghoul2, 0, "thoracic", thoracicAngles, BONE_ANGLES_POSTMULT, POSITIVE_X, NEGATIVE_Y, NEGATIVE_Z, NULL, 0, level.time); @@ -485,17 +482,39 @@ void G_G2PlayerAngles( gentity_t *ent, vec3_t legs[3], vec3_t legsAngles){ //trap_G2API_SetBoneAngles(ent->client->ghoul2, 0, "cranium", headAngles, BONE_ANGLES_POSTMULT, POSITIVE_Z, NEGATIVE_Y, POSITIVE_X, NULL, 0, level.time); } +qboolean PM_SaberInDeflect( int move ); +qboolean PM_SaberInBrokenParry( int move ); +qboolean PM_SaberInBounce( int move ); + qboolean SaberAttacking(gentity_t *self) { - /* - if (self->client->ps.torsoAnim == self->client->ps.saberAttackSequence) + if (PM_SaberInParry(self->client->ps.saberMove)) { - return qtrue; + return qfalse; } - */ + if (PM_SaberInBrokenParry(self->client->ps.saberMove)) + { + return qfalse; + } + if (PM_SaberInDeflect(self->client->ps.saberMove)) + { + return qfalse; + } + if (PM_SaberInBounce(self->client->ps.saberMove)) + { + return qfalse; + } + if (PM_SaberInKnockaway(self->client->ps.saberMove)) + { + return qfalse; + } + if (BG_SaberInAttack(self->client->ps.saberMove)) { - return qtrue; + if (self->client->ps.weaponstate == WEAPON_FIRING && self->client->ps.saberBlocked == BLOCKED_NONE) + { + return qtrue; + } } return qfalse; @@ -1008,51 +1027,562 @@ qboolean WP_SabersCheckLock( gentity_t *ent1, gentity_t *ent2 ) return qfalse; } -qboolean CheckSaberDamage(gentity_t *self, vec3_t saberStart, vec3_t saberEnd, qboolean doInterpolate) +int G_GetParryForBlock(int block) +{ + switch (block) + { + case BLOCKED_UPPER_RIGHT: + return LS_PARRY_UR; + break; + case BLOCKED_UPPER_RIGHT_PROJ: + return LS_REFLECT_UR; + break; + case BLOCKED_UPPER_LEFT: + return LS_PARRY_UL; + break; + case BLOCKED_UPPER_LEFT_PROJ: + return LS_REFLECT_UL; + break; + case BLOCKED_LOWER_RIGHT: + return LS_PARRY_LR; + break; + case BLOCKED_LOWER_RIGHT_PROJ: + return LS_REFLECT_LR; + break; + case BLOCKED_LOWER_LEFT: + return LS_PARRY_LL; + break; + case BLOCKED_LOWER_LEFT_PROJ: + return LS_REFLECT_LL; + break; + case BLOCKED_TOP: + return LS_PARRY_UP; + break; + case BLOCKED_TOP_PROJ: + return LS_REFLECT_UP; + break; + default: + break; + } + + return LS_NONE; +} + +int PM_SaberBounceForAttack( int move ); +int PM_SaberDeflectionForQuad( int quad ); +extern stringID_table_t animTable[MAX_ANIMATIONS+1]; +qboolean WP_GetSaberDeflectionAngle( gentity_t *attacker, gentity_t *defender, float saberHitFraction ) +{ + qboolean animBasedDeflection = qtrue; + + if ( !attacker || !attacker->client || !attacker->client->ghoul2 ) + { + return qfalse; + } + if ( !defender || !defender->client || !defender->client->ghoul2 ) + { + return qfalse; + } + + if ((level.time - attacker->client->lastSaberStorageTime) > 500) + { //last update was too long ago, something is happening to this client to prevent his saber from updating + return qfalse; + } + if ((level.time - defender->client->lastSaberStorageTime) > 500) + { //ditto + return qfalse; + } + + if ( animBasedDeflection ) + { + //Hmm, let's try just basing it off the anim + int attQuadStart = saberMoveData[attacker->client->ps.saberMove].startQuad; + int attQuadEnd = saberMoveData[attacker->client->ps.saberMove].endQuad; + int defQuad = saberMoveData[defender->client->ps.saberMove].endQuad; + int quadDiff = fabs(defQuad-attQuadStart); + + if ( defender->client->ps.saberMove == LS_READY ) + { + //FIXME: we should probably do SOMETHING here... + //I have this return qfalse here in the hopes that + //the defender will pick a parry and the attacker + //will hit the defender's saber again. + //But maybe this func call should come *after* + //it's decided whether or not the defender is + //going to parry. + return qfalse; + } + + //reverse the left/right of the defQuad because of the mirrored nature of facing each other in combat + switch ( defQuad ) + { + case Q_BR: + defQuad = Q_BL; + break; + case Q_R: + defQuad = Q_L; + break; + case Q_TR: + defQuad = Q_TL; + break; + case Q_TL: + defQuad = Q_TR; + break; + case Q_L: + defQuad = Q_R; + break; + case Q_BL: + defQuad = Q_BR; + break; + } + + if ( quadDiff > 4 ) + {//wrap around so diff is never greater than 180 (4 * 45) + quadDiff = 4 - (quadDiff - 4); + } + //have the quads, find a good anim to use + if ( (!quadDiff || (quadDiff == 1 && Q_irand(0,1))) //defender pretty much stopped the attack at a 90 degree angle + && (defender->client->ps.fd.saberAnimLevel == attacker->client->ps.fd.saberAnimLevel || Q_irand( 0, defender->client->ps.fd.saberAnimLevel-attacker->client->ps.fd.saberAnimLevel ) >= 0) )//and the defender's style is stronger + { + //bounce straight back + int attMove = attacker->client->ps.saberMove; + attacker->client->ps.saberMove = PM_SaberBounceForAttack( attacker->client->ps.saberMove ); + if (g_saberDebugPrint.integer) + { + Com_Printf( "attack %s vs. parry %s bounced to %s\n", + animTable[saberMoveData[attMove].animToUse].name, + animTable[saberMoveData[defender->client->ps.saberMove].animToUse].name, + animTable[saberMoveData[attacker->client->ps.saberMove].animToUse].name ); + } + attacker->client->ps.saberBlocked = BLOCKED_ATK_BOUNCE; + return qfalse; + } + else + {//attack hit at an angle, figure out what angle it should bounce off att + int newQuad; + quadDiff = defQuad - attQuadEnd; + //add half the diff of between the defense and attack end to the attack end + if ( quadDiff > 4 ) + { + quadDiff = 4 - (quadDiff - 4); + } + else if ( quadDiff < -4 ) + { + quadDiff = -4 + (quadDiff + 4); + } + newQuad = attQuadEnd + ceil( ((float)quadDiff)/2.0f ); + if ( newQuad < Q_BR ) + {//less than zero wraps around + newQuad = Q_B + newQuad; + } + if ( newQuad == attQuadStart ) + {//never come off at the same angle that we would have if the attack was not interrupted + if ( Q_irand(0, 1) ) + { + newQuad--; + } + else + { + newQuad++; + } + if ( newQuad < Q_BR ) + { + newQuad = Q_B; + } + else if ( newQuad > Q_B ) + { + newQuad = Q_BR; + } + } + if ( newQuad == defQuad ) + {//bounce straight back + int attMove = attacker->client->ps.saberMove; + attacker->client->ps.saberMove = PM_SaberBounceForAttack( attacker->client->ps.saberMove ); + if (g_saberDebugPrint.integer) + { + Com_Printf( "attack %s vs. parry %s bounced to %s\n", + animTable[saberMoveData[attMove].animToUse].name, + animTable[saberMoveData[defender->client->ps.saberMove].animToUse].name, + animTable[saberMoveData[attacker->client->ps.saberMove].animToUse].name ); + } + attacker->client->ps.saberBlocked = BLOCKED_ATK_BOUNCE; + return qfalse; + } + //else, pick a deflection + else + { + int attMove = attacker->client->ps.saberMove; + attacker->client->ps.saberMove = PM_SaberDeflectionForQuad( newQuad ); + if (g_saberDebugPrint.integer) + { + Com_Printf( "attack %s vs. parry %s deflected to %s\n", + animTable[saberMoveData[attMove].animToUse].name, + animTable[saberMoveData[defender->client->ps.saberMove].animToUse].name, + animTable[saberMoveData[attacker->client->ps.saberMove].animToUse].name ); + } + attacker->client->ps.saberBlocked = BLOCKED_BOUNCE_MOVE; + return qtrue; + } + } + } + else + { + vec3_t att_HitDir, def_BladeDir, temp; + float hitDot; + + //VectorSubtract( attacker->client->renderInfo.muzzlePoint, attacker->client->renderInfo.muzzlePointOld, temp ); + VectorCopy(attacker->client->lastSaberBase_Always, temp); + + //VectorCopy(attacker->client->lastSaberDir_Always, att_HitDir); + AngleVectors(attacker->client->lastSaberDir_Always, att_HitDir, 0, 0); + + AngleVectors(defender->client->lastSaberDir_Always, def_BladeDir, 0, 0); + //VectorMA( def_BladeDir, saberHitFraction, temp, def_BladeDir ); + + // VectorScale( att_HitDir, -1.0f, att_HitDir ); + // VectorScale( def_BladeDir, -1.0f, def_BladeDir ); + + //now compare + hitDot = DotProduct( att_HitDir, def_BladeDir ); + if ( hitDot < 0.25f && hitDot > -0.25f ) + {//hit pretty much perpendicular, pop straight back + attacker->client->ps.saberMove = PM_SaberBounceForAttack( attacker->client->ps.saberMove ); + attacker->client->ps.saberBlocked = BLOCKED_ATK_BOUNCE; + return qfalse; + } + else + {//a deflection + vec3_t att_Right, att_Up, att_DeflectionDir; + float swingRDot, swingUDot; + + //get the direction of the deflection + VectorScale( def_BladeDir, hitDot, att_DeflectionDir ); + //get our bounce straight back direction + VectorScale( att_HitDir, -1.0f, temp ); + //add the bounce back and deflection + VectorAdd( att_DeflectionDir, temp, att_DeflectionDir ); + //normalize the result to determine what direction our saber should bounce back toward + VectorNormalize( att_DeflectionDir ); + + //need to know the direction of the deflectoin relative to the attacker's facing + VectorSet( temp, 0, attacker->client->ps.viewangles[YAW], 0 );//presumes no pitch! + AngleVectors( temp, NULL, att_Right, att_Up ); + swingRDot = DotProduct( att_Right, att_DeflectionDir ); + swingUDot = DotProduct( att_Up, att_DeflectionDir ); + + if ( swingRDot > 0.25f ) + {//deflect to right + if ( swingUDot > 0.25f ) + {//deflect to top + attacker->client->ps.saberMove = LS_D1_TR; + } + else if ( swingUDot < -0.25f ) + {//deflect to bottom + attacker->client->ps.saberMove = LS_D1_BR; + } + else + {//deflect horizontally + attacker->client->ps.saberMove = LS_D1__R; + } + } + else if ( swingRDot < -0.25f ) + {//deflect to left + if ( swingUDot > 0.25f ) + {//deflect to top + attacker->client->ps.saberMove = LS_D1_TL; + } + else if ( swingUDot < -0.25f ) + {//deflect to bottom + attacker->client->ps.saberMove = LS_D1_BL; + } + else + {//deflect horizontally + attacker->client->ps.saberMove = LS_D1__L; + } + } + else + {//deflect in middle + if ( swingUDot > 0.25f ) + {//deflect to top + attacker->client->ps.saberMove = LS_D1_T_; + } + else if ( swingUDot < -0.25f ) + {//deflect to bottom + attacker->client->ps.saberMove = LS_D1_B_; + } + else + {//deflect horizontally? Well, no such thing as straight back in my face, so use top + if ( swingRDot > 0 ) + { + attacker->client->ps.saberMove = LS_D1_TR; + } + else if ( swingRDot < 0 ) + { + attacker->client->ps.saberMove = LS_D1_TL; + } + else + { + attacker->client->ps.saberMove = LS_D1_T_; + } + } + } + + attacker->client->ps.saberBlocked = BLOCKED_BOUNCE_MOVE; + return qtrue; + } + } +} + +int G_KnockawayForParry( int move ) +{ + //FIXME: need actual anims for this + //FIXME: need to know which side of the saber was hit! For now, we presume the saber gets knocked away from the center + switch ( move ) + { + case LS_PARRY_UP: + return LS_K1_T_;//push up + break; + case LS_PARRY_UR: + default://case LS_READY: + return LS_K1_TR;//push up, slightly to right + break; + case LS_PARRY_UL: + return LS_K1_TL;//push up and to left + break; + case LS_PARRY_LR: + return LS_K1_BR;//push down and to left + break; + case LS_PARRY_LL: + return LS_K1_BL;//push down and to right + break; + } + //return LS_NONE; +} + +#define SABER_NONATTACK_DAMAGE 1 + +//For strong attacks, we ramp damage based on the point in the attack animation +int G_GetAttackDamage(gentity_t *self, int minDmg, int maxDmg, float multPoint) +{ + int peakDif = 0; + int speedDif = 0; + int totalDamage = maxDmg; + float peakPoint = 0; + float attackAnimLength = bgGlobalAnimations[self->client->ps.torsoAnim].numFrames * fabs(bgGlobalAnimations[self->client->ps.torsoAnim].frameLerp); + float currentPoint = 0; + float damageFactor = 0; + float animSpeedFactor = 1.0f; + + //Be sure to scale by the proper anim speed just as if we were going to play the animation + BG_SaberStartTransAnim(self->client->ps.fd.saberAnimLevel, self->client->ps.torsoAnim&~ANIM_TOGGLEBIT, &animSpeedFactor); + speedDif = attackAnimLength - (attackAnimLength * animSpeedFactor); + attackAnimLength += speedDif; + peakPoint = attackAnimLength; + peakPoint -= attackAnimLength*multPoint; + + //we treat torsoTimer as the point in the animation (closer it is to attackAnimLength, closer it is to beginning) + currentPoint = self->client->ps.torsoTimer; + + if (peakPoint > currentPoint) + { + peakDif = (peakPoint - currentPoint); + } + else + { + peakDif = (currentPoint - peakPoint); + } + + damageFactor = (float)((currentPoint/peakPoint)); + if (damageFactor > 1) + { + damageFactor = (2.0f - damageFactor); + } + + totalDamage *= damageFactor; + if (totalDamage < minDmg) + { + totalDamage = minDmg; + } + if (totalDamage > maxDmg) + { + totalDamage = maxDmg; + } + + //Com_Printf("%i\n", totalDamage); + + return totalDamage; +} + +//Get the point in the animation and return a percentage of the current point in the anim between 0 and the total anim length (0.0f - 1.0f) +float G_GetAnimPoint(gentity_t *self) +{ + int speedDif = 0; + float attackAnimLength = bgGlobalAnimations[self->client->ps.torsoAnim].numFrames * fabs(bgGlobalAnimations[self->client->ps.torsoAnim].frameLerp); + float currentPoint = 0; + float animSpeedFactor = 1.0f; + float animPercentage = 0; + + //Be sure to scale by the proper anim speed just as if we were going to play the animation + BG_SaberStartTransAnim(self->client->ps.fd.saberAnimLevel, self->client->ps.torsoAnim&~ANIM_TOGGLEBIT, &animSpeedFactor); + speedDif = attackAnimLength - (attackAnimLength * animSpeedFactor); + attackAnimLength += speedDif; + + currentPoint = self->client->ps.torsoTimer; + + animPercentage = currentPoint/attackAnimLength; + + //Com_Printf("%f\n", animPercentage); + + return animPercentage; +} + +qboolean G_ClientIdleInWorld(gentity_t *ent) +{ + if (!ent->client->pers.cmd.upmove && + !ent->client->pers.cmd.forwardmove && + !ent->client->pers.cmd.rightmove && + !(ent->client->pers.cmd.buttons & BUTTON_GESTURE) && + !(ent->client->pers.cmd.buttons & BUTTON_FORCEGRIP) && + !(ent->client->pers.cmd.buttons & BUTTON_ALT_ATTACK) && + !(ent->client->pers.cmd.buttons & BUTTON_FORCEPOWER) && + !(ent->client->pers.cmd.buttons & BUTTON_FORCE_LIGHTNING) && + !(ent->client->pers.cmd.buttons & BUTTON_FORCE_DRAIN) && + !(ent->client->pers.cmd.buttons & BUTTON_ATTACK)) + { + return qtrue; + } + + return qfalse; +} + +#ifdef G2_COLLISION_ENABLED +qboolean G_G2TraceCollide(trace_t *tr, vec3_t lastValidStart, vec3_t lastValidEnd, vec3_t traceMins, vec3_t traceMaxs) +{ + if (!g_saberGhoul2Collision.integer) + { + return qfalse; + } + + if (tr->entityNum < MAX_CLIENTS) + { //Hit a client with the normal trace, try the collision trace. + G2Trace_t G2Trace; + gentity_t *g2Hit; + vec3_t vIdentity = {1.0f, 1.0f, 1.0f}; + vec3_t angles; + int tN = 0; + float fRadius = 0; + + if (traceMins[0] || + traceMins[1] || + traceMins[2] || + traceMaxs[0] || + traceMaxs[1] || + traceMaxs[2]) + { + fRadius=(traceMaxs[0]-traceMins[0])/2.0f; + } + + memset (&G2Trace, 0, sizeof(G2Trace)); + + while (tN < MAX_G2_COLLISIONS) + { + G2Trace[tN].mEntityNum = -1; + tN++; + } + g2Hit = &g_entities[tr->entityNum]; + + if (g2Hit && g2Hit->inuse && g2Hit->client && g2Hit->client->ghoul2) + { + angles[ROLL] = angles[PITCH] = 0; + angles[YAW] = g2Hit->client->ps.viewangles[YAW]; + + trap_G2API_CollisionDetect ( G2Trace, g2Hit->client->ghoul2, angles, g2Hit->client->ps.origin, level.time, g2Hit->s.number, lastValidStart, lastValidEnd, vIdentity, 0, 2, fRadius ); + + if (G2Trace[0].mEntityNum != g2Hit->s.number) + { + tr->fraction = 1.0f; + tr->entityNum = ENTITYNUM_NONE; + tr->startsolid = 0; + tr->allsolid = 0; + return qfalse; + } + else + { //Yay! + VectorCopy(G2Trace[0].mCollisionPosition, tr->endpos); + return qtrue; + } + } + } + + return qfalse; +} +#endif + +//rww - MP version of the saber damage function. This is where all the things like blocking, triggering a parry, +//triggering a broken parry, doing actual damage, etc. are done for the saber. It doesn't resemble the SP +//version very much, but functionality is (hopefully) about the same. +qboolean CheckSaberDamage(gentity_t *self, vec3_t saberStart, vec3_t saberEnd, qboolean doInterpolate, int trMask) { trace_t tr; vec3_t dir; + vec3_t saberTrMins, saberTrMaxs; +#ifdef G2_COLLISION_ENABLED + vec3_t lastValidStart; + vec3_t lastValidEnd; +#endif int dmg = 0; int attackStr = 0; + float saberBoxSize = g_saberBoxTraceSize.value; qboolean idleDamage = qfalse; qboolean didHit = qfalse; + qboolean sabersClashed = qfalse; + qboolean unblockable = qfalse; + qboolean didDefense = qfalse; + qboolean didOffense = qfalse; + qboolean saberTraceDone = qfalse; + qboolean otherUnblockable = qfalse; + qboolean tryDeflectAgain = qfalse; + + gentity_t *otherOwner; if (self->client->ps.saberHolstered) { return qfalse; } - if (doInterpolate) - { //This didn't quite work out like I hoped. But it's better than nothing. Sort of. - vec3_t oldSaberStart, oldSaberEnd, saberDif, oldSaberDif; - int traceTests = 0; - float trDif = 8; + memset (&tr, 0, sizeof(tr)); //make the compiler happy +#ifdef G2_COLLISION_ENABLED + if (g_saberGhoul2Collision.integer) + { + VectorSet(saberTrMins, -saberBoxSize*3, -saberBoxSize*3, -saberBoxSize*3); + VectorSet(saberTrMaxs, saberBoxSize*3, saberBoxSize*3, saberBoxSize*3); + } + else +#endif + if (self->client->ps.fd.saberAnimLevel < FORCE_LEVEL_2) + { //box trace for fast, because it doesn't get updated so often + VectorSet(saberTrMins, -saberBoxSize, -saberBoxSize, -saberBoxSize); + VectorSet(saberTrMaxs, saberBoxSize, saberBoxSize, saberBoxSize); + } + else if (g_saberAlwaysBoxTrace.integer) + { + VectorSet(saberTrMins, -saberBoxSize, -saberBoxSize, -saberBoxSize); + VectorSet(saberTrMaxs, saberBoxSize, saberBoxSize, saberBoxSize); + } + else + { + VectorClear(saberTrMins); + VectorClear(saberTrMaxs); + } - VectorCopy(self->client->lastSaberBase, oldSaberStart); - VectorCopy(self->client->lastSaberTip, oldSaberEnd); + while (!saberTraceDone) + { + if (doInterpolate) + { //This didn't quite work out like I hoped. But it's better than nothing. Sort of. + vec3_t oldSaberStart, oldSaberEnd, saberDif, oldSaberDif; + int traceTests = 0; + float trDif = 8; - VectorSubtract(saberStart, saberEnd, saberDif); - VectorSubtract(oldSaberStart, oldSaberEnd, oldSaberDif); - - VectorNormalize(saberDif); - VectorNormalize(oldSaberDif); - - saberEnd[0] = saberStart[0] - (saberDif[0]*trDif); - saberEnd[1] = saberStart[1] - (saberDif[1]*trDif); - saberEnd[2] = saberStart[2] - (saberDif[2]*trDif); - - oldSaberEnd[0] = oldSaberStart[0] - (oldSaberDif[0]*trDif); - oldSaberEnd[1] = oldSaberStart[1] - (oldSaberDif[1]*trDif); - oldSaberEnd[2] = oldSaberStart[2] - (oldSaberDif[2]*trDif); - - //G_TestLine(oldSaberEnd, saberEnd, 0x0000ff, 50); - - trap_Trace(&tr, saberEnd, NULL, NULL, saberStart, self->s.number, (MASK_PLAYERSOLID|CONTENTS_LIGHTSABER)); - - trDif++; - - while (tr.fraction == 1.0 && traceTests < 4 && tr.entityNum >= ENTITYNUM_NONE) - { VectorCopy(self->client->lastSaberBase, oldSaberStart); VectorCopy(self->client->lastSaberTip, oldSaberEnd); @@ -1072,46 +1602,191 @@ qboolean CheckSaberDamage(gentity_t *self, vec3_t saberStart, vec3_t saberEnd, q //G_TestLine(oldSaberEnd, saberEnd, 0x0000ff, 50); - trap_Trace(&tr, saberEnd, NULL, NULL, saberStart, self->s.number, (MASK_PLAYERSOLID|CONTENTS_LIGHTSABER)); + trap_Trace(&tr, saberEnd, saberTrMins, saberTrMaxs, saberStart, self->s.number, trMask); +#ifdef G2_COLLISION_ENABLED + VectorCopy(saberEnd, lastValidStart); + VectorCopy(saberStart, lastValidEnd); + if (tr.entityNum < MAX_CLIENTS) + { + G_G2TraceCollide(&tr, lastValidStart, lastValidEnd, saberTrMins, saberTrMaxs); + } +#endif - traceTests++; - trDif += 8; + trDif++; + + while (tr.fraction == 1.0 && traceTests < 4 && tr.entityNum >= ENTITYNUM_NONE) + { + VectorCopy(self->client->lastSaberBase, oldSaberStart); + VectorCopy(self->client->lastSaberTip, oldSaberEnd); + + VectorSubtract(saberStart, saberEnd, saberDif); + VectorSubtract(oldSaberStart, oldSaberEnd, oldSaberDif); + + VectorNormalize(saberDif); + VectorNormalize(oldSaberDif); + + saberEnd[0] = saberStart[0] - (saberDif[0]*trDif); + saberEnd[1] = saberStart[1] - (saberDif[1]*trDif); + saberEnd[2] = saberStart[2] - (saberDif[2]*trDif); + + oldSaberEnd[0] = oldSaberStart[0] - (oldSaberDif[0]*trDif); + oldSaberEnd[1] = oldSaberStart[1] - (oldSaberDif[1]*trDif); + oldSaberEnd[2] = oldSaberStart[2] - (oldSaberDif[2]*trDif); + + //G_TestLine(oldSaberEnd, saberEnd, 0x0000ff, 50); + + trap_Trace(&tr, saberEnd, saberTrMins, saberTrMaxs, saberStart, self->s.number, trMask); +#ifdef G2_COLLISION_ENABLED + VectorCopy(saberEnd, lastValidStart); + VectorCopy(saberStart, lastValidEnd); + if (tr.entityNum < MAX_CLIENTS) + { + G_G2TraceCollide(&tr, lastValidStart, lastValidEnd, saberTrMins, saberTrMaxs); + } +#endif + traceTests++; + trDif += 8; + } } - } - else - { - trap_Trace(&tr, saberStart, NULL, NULL, saberEnd, self->s.number, (MASK_PLAYERSOLID|CONTENTS_LIGHTSABER)); + else + { + /* + if (self->s.number == 0) + { + G_TestLine(saberStart, saberEnd, 0x0000ff, 50); + } + */ + trap_Trace(&tr, saberStart, saberTrMins, saberTrMaxs, saberEnd, self->s.number, trMask); +#ifdef G2_COLLISION_ENABLED + VectorCopy(saberStart, lastValidStart); + VectorCopy(saberEnd, lastValidEnd); + if (tr.entityNum < MAX_CLIENTS) + { + G_G2TraceCollide(&tr, lastValidStart, lastValidEnd, saberTrMins, saberTrMaxs); + } +#endif + } + + /* + if (tr.entityNum == ENTITYNUM_NONE && trMask == CONTENTS_LIGHTSABER) + { //didn't hit anything while checking with just the saber contents mask, do a normal trace. + trMask = (MASK_PLAYERSOLID|CONTENTS_LIGHTSABER|MASK_SHOT); + } + else + { + saberTraceDone = qtrue; + } + */ + //Doing this differently now + saberTraceDone = qtrue; } if (SaberAttacking(self) && self->client->ps.saberAttackWound < level.time) { //this animation is that of the last attack movement, and so it should do full damage + qboolean saberInSpecial = BG_SaberInSpecial(self->client->ps.saberMove); + dmg = SABER_HITDAMAGE;//*self->client->ps.fd.saberAnimLevel; if (self->client->ps.fd.saberAnimLevel == 3) { - dmg = 100; + //dmg = 100; + //new damage-ramping system + if (!saberInSpecial) + { + dmg = G_GetAttackDamage(self, 2, 120, 0.5f); + } + else if (saberInSpecial && + (self->client->ps.saberMove == LS_A_JUMP_T__B_)) + { + dmg = G_GetAttackDamage(self, 2, 180, 0.65f); + } + else + { + dmg = 100; + } } else if (self->client->ps.fd.saberAnimLevel == 2) { - dmg = 60; + if (saberInSpecial && + (self->client->ps.saberMove == LS_A_FLIP_STAB || self->client->ps.saberMove == LS_A_FLIP_SLASH)) + { //a well-timed hit with this can do a full 105 + dmg = G_GetAttackDamage(self, 2, 100, 0.5f); + } + else + { + dmg = 60; + } + } + else if (self->client->ps.fd.saberAnimLevel == 1) + { + if (saberInSpecial && + (self->client->ps.saberMove == LS_A_LUNGE)) + { + dmg = G_GetAttackDamage(self, 2, SABER_HITDAMAGE-5, 0.3f); + } + else + { + dmg = SABER_HITDAMAGE; + } } attackStr = self->client->ps.fd.saberAnimLevel; } else if (self->client->ps.saberIdleWound < level.time) { //just touching, do minimal damage and only check for it every 200ms (mainly to cut down on network traffic for hit events) - dmg = 5; - self->client->ps.saberIdleWound = level.time + 200; + dmg = SABER_NONATTACK_DAMAGE; + //self->client->ps.saberIdleWound = level.time + g_saberDmgDelay_Idle.integer; idleDamage = qtrue; } + /* + if (self->client->ps.saberMove == LS_A_BACK || + self->client->ps.saberMove == LS_A_BACK_CR || + self->client->ps.saberMove == LS_A_BACKSTAB || + self->client->ps.saberMove == LS_A_JUMP_T__B_) + */ + if (BG_SaberInSpecial(self->client->ps.saberMove)) + { + unblockable = qtrue; + self->client->ps.saberBlocked = 0; + if (self->client->ps.saberMove == LS_A_JUMP_T__B_) + { //do extra damage for special unblockables + dmg += 5; //This is very tiny, because this move has a huge damage ramp + } + else if (self->client->ps.saberMove == LS_A_FLIP_STAB || self->client->ps.saberMove == LS_A_FLIP_SLASH) + { + dmg += 5; //ditto + if (dmg <= 40 || G_GetAnimPoint(self) <= 0.4f) + { //sort of a hack, don't want it doing big damage in the off points of the anim + dmg = 2; + } + } + else if (self->client->ps.saberMove == LS_A_LUNGE) + { + dmg += 2; //and ditto again + if (G_GetAnimPoint(self) <= 0.4f) + { //same as above + dmg = 2; + } + } + else + { + dmg += 20; + } + } + if (!dmg) { + if (tr.entityNum < MAX_CLIENTS || + (g_entities[tr.entityNum].inuse && (g_entities[tr.entityNum].r.contents & CONTENTS_LIGHTSABER))) + { + return qtrue; + } return qfalse; } - if (dmg > 5 && self->client->ps.isJediMaster) + if (dmg > SABER_NONATTACK_DAMAGE && self->client->ps.isJediMaster) { //give the Jedi Master more saber attack power dmg *= 2; } @@ -1130,7 +1805,6 @@ qboolean CheckSaberDamage(gentity_t *self, vec3_t saberStart, vec3_t saberEnd, q tr.entityNum != self->s.number) { gentity_t *te; - qboolean unblockable = qfalse; if (idleDamage && g_entities[tr.entityNum].client && @@ -1154,94 +1828,53 @@ qboolean CheckSaberDamage(gentity_t *self, vec3_t saberStart, vec3_t saberEnd, q return qfalse; } - didHit = qtrue; + self->client->ps.saberIdleWound = level.time + g_saberDmgDelay_Idle.integer; - if (self->client->ps.saberMove == LS_A_BACK || - self->client->ps.saberMove == LS_A_BACK_CR || - self->client->ps.saberMove == LS_A_BACKSTAB || - self->client->ps.saberMove == LS_A_JUMP_T__B_) - { - unblockable = qtrue; - if (self->client->ps.saberMove == LS_A_JUMP_T__B_) - { //do extra damage for special unblockables - dmg += 40; - } - else - { - dmg += 20; - } - } + didHit = qtrue; if (g_entities[tr.entityNum].client && !unblockable && WP_SaberCanBlock(&g_entities[tr.entityNum], tr.endpos, 0, MOD_SABER, qfalse, attackStr)) { te = G_TempEntity( tr.endpos, EV_SABER_BLOCK ); + if (dmg <= SABER_NONATTACK_DAMAGE) + { + self->client->ps.saberIdleWound = level.time + g_saberDmgDelay_Idle.integer; + } VectorCopy(tr.endpos, te->s.origin); VectorCopy(tr.plane.normal, te->s.angles); te->s.eventParm = 1; - if (dmg > 5) + if (dmg > SABER_NONATTACK_DAMAGE) { + int lockFactor = g_saberLockFactor.integer; + if ((g_entities[tr.entityNum].client->ps.fd.forcePowerLevel[FP_SABERATTACK] - self->client->ps.fd.forcePowerLevel[FP_SABERATTACK]) > 1 && - Q_irand(1, 10) < 9) //used to be < 7 + Q_irand(1, 10) < lockFactor*2) //used to be < 7 { //Just got blocked by someone with a decently higher attack level, so enter into a lock (where they have the advantage due to a higher attack lev) - if (WP_SabersCheckLock(self, &g_entities[tr.entityNum])) - { - self->client->ps.saberBlocked = BLOCKED_NONE; - g_entities[tr.entityNum].client->ps.saberBlocked = BLOCKED_NONE; - return didHit; + if (!G_ClientIdleInWorld(&g_entities[tr.entityNum])) + { + if (WP_SabersCheckLock(self, &g_entities[tr.entityNum])) + { + self->client->ps.saberBlocked = BLOCKED_NONE; + g_entities[tr.entityNum].client->ps.saberBlocked = BLOCKED_NONE; + return didHit; + } } } - else if (Q_irand(1, 10) < 3) - { //Just got blocked by someone with a decently higher attack level, so enter into a lock (where they have the advantage due to a higher attack lev) - if (WP_SabersCheckLock(self, &g_entities[tr.entityNum])) - { - self->client->ps.saberBlocked = BLOCKED_NONE; - g_entities[tr.entityNum].client->ps.saberBlocked = BLOCKED_NONE; - return didHit; - } - } - } - - //our attack was blocked, so bounce back? - if (dmg > 5) - { - self->client->ps.weaponTime = 0; - self->client->ps.weaponstate = WEAPON_READY; - self->client->ps.saberBlocked = BLOCKED_ATK_BOUNCE; - - self->client->ps.saberBlockTime = level.time + (350 - (self->client->ps.fd.forcePowerLevel[FP_SABERDEFEND]*100));//300; - } - self->client->ps.saberAttackWound = level.time + 300; - - if (self->client->ps.fd.saberAnimLevel >= FORCE_LEVEL_3 && dmg > 5 && g_entities[tr.entityNum].client->ps.saberMove != LS_READY && g_entities[tr.entityNum].client->ps.saberMove != LS_NONE) - { - g_entities[tr.entityNum].client->ps.weaponTime = 0; - g_entities[tr.entityNum].client->ps.weaponstate = WEAPON_READY; - g_entities[tr.entityNum].client->ps.saberBlocked = BLOCKED_ATK_BOUNCE; - - g_entities[tr.entityNum].client->ps.saberBlockTime = level.time + (350 - (g_entities[tr.entityNum].client->ps.fd.forcePowerLevel[FP_SABERDEFEND]*100));//300; - } - - //NOTE: Actual blocking is handled in WP_SaberCanBlock - /* - if (dmg > 5) - { //play block anim on other person - gentity_t *otherhit = &g_entities[tr.entityNum]; - - if (otherhit && otherhit->client) + else if (Q_irand(1, 20) < lockFactor) { - // WP_SaberBlockNonRandom(otherhit, tr.endpos, qfalse); - - otherhit->client->ps.weaponTime = 0; - otherhit->client->ps.weaponstate = WEAPON_READY; - otherhit->client->ps.saberBlocked = BLOCKED_ATK_BOUNCE; - - self->client->ps.saberBlockTime = level.time + 300; - - otherhit->client->ps.saberAttackWound = level.time + 300; + if (!G_ClientIdleInWorld(&g_entities[tr.entityNum])) + { + if (WP_SabersCheckLock(self, &g_entities[tr.entityNum])) + { + self->client->ps.saberBlocked = BLOCKED_NONE; + g_entities[tr.entityNum].client->ps.saberBlocked = BLOCKED_NONE; + return didHit; + } + } } } - */ + otherOwner = &g_entities[tr.entityNum]; + goto blockStuff; } else { @@ -1252,15 +1885,31 @@ qboolean CheckSaberDamage(gentity_t *self, vec3_t saberStart, vec3_t saberEnd, q if (g_entities[tr.entityNum].client && !g_entities[tr.entityNum].client->ps.fd.forcePowerLevel[FP_SABERATTACK]) { //not a "jedi", so make them suffer more - if (dmg > 5) + if (dmg > SABER_NONATTACK_DAMAGE) { //don't bother increasing just for idle touch damage dmg *= 1.5; } } + if (g_entities[tr.entityNum].client && g_entities[tr.entityNum].client->ps.weapon == WP_SABER) + { //for jedi using the saber, half the damage (this comes with the increased default dmg debounce time) + if (dmg > SABER_NONATTACK_DAMAGE && !unblockable) + { //don't reduce damage if it's only 1, or if this is an unblockable attack + if (dmg == SABER_HITDAMAGE) + { //level 1 attack + dmg *= 0.7; + } + else + { + dmg *= 0.5; + } + } + } + G_Damage(&g_entities[tr.entityNum], self, self, dir, tr.endpos, dmg, 0, MOD_SABER); te = G_TempEntity( tr.endpos, EV_SABER_HIT ); + VectorCopy(tr.endpos, te->s.origin); VectorCopy(tr.plane.normal, te->s.angles); @@ -1286,7 +1935,7 @@ qboolean CheckSaberDamage(gentity_t *self, vec3_t saberStart, vec3_t saberEnd, q g_entities[tr.entityNum].r.contents != -1) { //saber clash gentity_t *te; - gentity_t *otherOwner = &g_entities[g_entities[tr.entityNum].r.ownerNum]; + otherOwner = &g_entities[g_entities[tr.entityNum].r.ownerNum]; if (otherOwner && otherOwner->inuse && @@ -1312,79 +1961,372 @@ qboolean CheckSaberDamage(gentity_t *self, vec3_t saberStart, vec3_t saberEnd, q } didHit = qtrue; + self->client->ps.saberIdleWound = level.time + g_saberDmgDelay_Idle.integer; te = G_TempEntity( tr.endpos, EV_SABER_BLOCK ); + if (dmg <= SABER_NONATTACK_DAMAGE) + { + self->client->ps.saberIdleWound = level.time + g_saberDmgDelay_Idle.integer; + } VectorCopy(tr.endpos, te->s.origin); VectorCopy(tr.plane.normal, te->s.angles); te->s.eventParm = 1; + sabersClashed = qtrue; + //WP_SaberBlockNonRandom(self, tr.endpos, qfalse); +blockStuff: + otherUnblockable = qfalse; + if (otherOwner && otherOwner->client && otherOwner->client->ps.saberInFlight) { return qfalse; } - if (self->client->ps.fd.saberAnimLevel < FORCE_LEVEL_3) + if (dmg > SABER_NONATTACK_DAMAGE && !unblockable && !otherUnblockable) { - self->client->ps.weaponTime = 0; - self->client->ps.weaponstate = WEAPON_READY; - self->client->ps.saberBlocked = BLOCKED_ATK_BOUNCE; - self->client->ps.saberBlockTime = level.time + (350 - (self->client->ps.fd.forcePowerLevel[FP_SABERDEFEND]*100));//300; + int lockFactor = g_saberLockFactor.integer; - if (otherOwner && otherOwner->client) + if (sabersClashed && Q_irand(1, 20) <= lockFactor) { - if (otherOwner->client->ps.weaponTime < 1 || otherOwner->client->ps.fd.saberAnimLevel < FORCE_LEVEL_3) + if (!G_ClientIdleInWorld(otherOwner)) { - WP_SaberCanBlock(otherOwner, tr.endpos, 0, MOD_SABER, qfalse, 1); - } - } - } - else if (otherOwner && otherOwner->client && otherOwner->client->ps.fd.forcePowerLevel[FP_SABERDEFEND] <= self->client->ps.fd.saberAnimLevel) - { //block - if (otherOwner->client->ps.weaponTime < 1 || otherOwner->client->ps.fd.saberAnimLevel < FORCE_LEVEL_3) - { - if (WP_SaberCanBlock(otherOwner, tr.endpos, 0, MOD_SABER, qfalse, 1) && dmg > 5) - { - otherOwner->client->ps.weaponTime = 0; - otherOwner->client->ps.weaponstate = WEAPON_READY; - otherOwner->client->ps.saberBlocked = BLOCKED_ATK_BOUNCE; - otherOwner->client->ps.saberBlockTime = level.time + (350 - (otherOwner->client->ps.fd.forcePowerLevel[FP_SABERDEFEND]*100));//300; + if (WP_SabersCheckLock(self, otherOwner)) + { + self->client->ps.saberBlocked = BLOCKED_NONE; + otherOwner->client->ps.saberBlocked = BLOCKED_NONE; + return didHit; + } } } } - self->client->ps.saberAttackWound = level.time + 300; - - if (dmg > 5) + if (!otherOwner || !otherOwner->client) { - if (Q_irand(1, 10) < 9) //used to be < 7 + return didHit; + } + + /* + if (otherOwner->client->ps.saberMove == LS_A_BACK || + otherOwner->client->ps.saberMove == LS_A_BACK_CR || + otherOwner->client->ps.saberMove == LS_A_BACKSTAB || + otherOwner->client->ps.saberMove == LS_A_JUMP_T__B_) + */ + if (BG_SaberInSpecial(otherOwner->client->ps.saberMove)) + { + otherUnblockable = qtrue; + otherOwner->client->ps.saberBlocked = 0; + } + + if ( sabersClashed && + dmg > SABER_NONATTACK_DAMAGE && + self->client->ps.fd.saberAnimLevel < FORCE_LEVEL_3 && + /*PM_SaberInParry(otherOwner->client->ps.saberMove) &&*/ + !PM_SaberInBounce(otherOwner->client->ps.saberMove) && + !PM_SaberInParry(self->client->ps.saberMove) && + !PM_SaberInBrokenParry(self->client->ps.saberMove) && + !BG_SaberInSpecial(self->client->ps.saberMove) && + !PM_SaberInBounce(self->client->ps.saberMove) && + !PM_SaberInDeflect(self->client->ps.saberMove) && + !PM_SaberInReflect(self->client->ps.saberMove) && + !unblockable /*&& + Q_irand(1, 10) <= 7*/) + { + //if (Q_irand(1, 10) <= 6) + if (1) //for now, just always try a deflect. (deflect func can cause bounces too) { - if (WP_SabersCheckLock(self, otherOwner)) + if (!WP_GetSaberDeflectionAngle(self, otherOwner, tr.fraction)) { - self->client->ps.saberBlocked = BLOCKED_NONE; - otherOwner->client->ps.saberBlocked = BLOCKED_NONE; - return didHit; + tryDeflectAgain = qtrue; //Failed the deflect, try it again if we can if the guy we're smashing goes into a parry and we don't break it + } + else + { + self->client->ps.saberBlocked = BLOCKED_BOUNCE_MOVE; + didOffense = qtrue; + } + } + else + { + self->client->ps.saberBlocked = BLOCKED_ATK_BOUNCE; + didOffense = qtrue; + + if (g_saberDebugPrint.integer) + { + Com_Printf("Client %i clashed into client %i's saber, did BLOCKED_ATK_BOUNCE\n", self->s.number, otherOwner->s.number); } } } - if (dmg > 5) - { //we clashed into this person's saber while attacking, so make them feel it too - if (otherOwner && otherOwner->client && otherOwner->client->ps.fd.forcePowerLevel[FP_SABERDEFEND] <= self->client->ps.fd.saberAnimLevel) - { - // WP_SaberBlockNonRandom(otherOwner, tr.endpos, qfalse); + if ( ((self->client->ps.fd.saberAnimLevel < FORCE_LEVEL_3 && ((tryDeflectAgain && Q_irand(1, 10) <= 3) || (!tryDeflectAgain && Q_irand(1, 10) <= 7))) || (Q_irand(1, 10) <= 1 && otherOwner->client->ps.fd.saberAnimLevel >= FORCE_LEVEL_3)) + /*&& PM_SaberInParry(otherOwner->client->ps.saberMove)*/ + && !PM_SaberInBounce(self->client->ps.saberMove) - otherOwner->client->ps.weaponTime = 0; - otherOwner->client->ps.weaponstate = WEAPON_READY; + && !PM_SaberInBrokenParry(otherOwner->client->ps.saberMove) + && !BG_SaberInSpecial(otherOwner->client->ps.saberMove) + && !PM_SaberInBounce(otherOwner->client->ps.saberMove) + && !PM_SaberInDeflect(otherOwner->client->ps.saberMove) + && !PM_SaberInReflect(otherOwner->client->ps.saberMove) + + && (otherOwner->client->ps.fd.saberAnimLevel > FORCE_LEVEL_2 || ( otherOwner->client->ps.fd.forcePowerLevel[FP_SABERDEFEND] >= 3 && Q_irand(0, otherOwner->client->ps.fd.saberAnimLevel) )) + && !unblockable + && !otherUnblockable + && dmg > SABER_NONATTACK_DAMAGE + && !didOffense) //don't allow the person we're attacking to do this if we're making an unblockable attack + {//knockaways can make fast-attacker go into a broken parry anim if the ent is using fast or med. In MP, we also randomly decide this for level 3 attacks. + //Going to go ahead and let idle damage do simple knockaways. Looks sort of good that way. + //turn the parry into a knockaway + if (!PM_SaberInParry(otherOwner->client->ps.saberMove)) + { + WP_SaberBlockNonRandom(otherOwner, tr.endpos, qfalse); + otherOwner->client->ps.saberMove = BG_KnockawayForParry( otherOwner->client->ps.saberBlocked ); + otherOwner->client->ps.saberBlocked = BLOCKED_BOUNCE_MOVE; + } + else + { + otherOwner->client->ps.saberMove = G_KnockawayForParry(otherOwner->client->ps.saberMove); //BG_KnockawayForParry( otherOwner->client->ps.saberBlocked ); + otherOwner->client->ps.saberBlocked = BLOCKED_BOUNCE_MOVE; + } + + //make them (me) go into a broken parry + self->client->ps.saberMove = BG_BrokenParryForAttack( self->client->ps.saberMove ); + self->client->ps.saberBlocked = BLOCKED_BOUNCE_MOVE;//BLOCKED_PARRY_BROKEN; + + if (g_saberDebugPrint.integer) + { + Com_Printf("Client %i sent client %i into a reflected attack with a knockaway\n", otherOwner->s.number, self->s.number); + } + + didDefense = qtrue; + } + else if ((self->client->ps.fd.saberAnimLevel > FORCE_LEVEL_2 || unblockable) && //if we're doing a special attack, we can send them into a broken parry too (MP only) + ( otherOwner->client->ps.fd.forcePowerLevel[FP_SABERDEFEND] < self->client->ps.fd.saberAnimLevel || (otherOwner->client->ps.fd.forcePowerLevel[FP_SABERDEFEND] == self->client->ps.fd.saberAnimLevel && (Q_irand(1, 10) >= otherOwner->client->ps.fd.saberAnimLevel*3 || unblockable)) ) && + PM_SaberInParry(otherOwner->client->ps.saberMove) && + !PM_SaberInBrokenParry(otherOwner->client->ps.saberMove) && + !PM_SaberInParry(self->client->ps.saberMove) && + !PM_SaberInBrokenParry(self->client->ps.saberMove) && + !PM_SaberInBounce(self->client->ps.saberMove) && + dmg > SABER_NONATTACK_DAMAGE && + !didOffense && + !otherUnblockable) + { //they are in a parry, and we are slamming down on them with a move of equal or greater force than their defense, so send them into a broken parry.. unless they are already in one. + if (g_saberDebugPrint.integer) + { + Com_Printf("Client %i sent client %i into a broken parry\n", self->s.number, otherOwner->s.number); + } + + otherOwner->client->ps.saberMove = BG_BrokenParryForParry( otherOwner->client->ps.saberMove ); + otherOwner->client->ps.saberBlocked = BLOCKED_PARRY_BROKEN; + + didDefense = qtrue; + } + else if ((self->client->ps.fd.saberAnimLevel > FORCE_LEVEL_2) && //if we're doing a special attack, we can send them into a broken parry too (MP only) + //( otherOwner->client->ps.fd.forcePowerLevel[FP_SABERDEFEND] < self->client->ps.fd.saberAnimLevel || (otherOwner->client->ps.fd.forcePowerLevel[FP_SABERDEFEND] == self->client->ps.fd.saberAnimLevel && (Q_irand(1, 10) >= otherOwner->client->ps.fd.saberAnimLevel*3 || unblockable)) ) && + otherOwner->client->ps.fd.saberAnimLevel >= FORCE_LEVEL_3 && + PM_SaberInParry(otherOwner->client->ps.saberMove) && + !PM_SaberInBrokenParry(otherOwner->client->ps.saberMove) && + !PM_SaberInParry(self->client->ps.saberMove) && + !PM_SaberInBrokenParry(self->client->ps.saberMove) && + !PM_SaberInBounce(self->client->ps.saberMove) && + !PM_SaberInDeflect(self->client->ps.saberMove) && + !PM_SaberInReflect(self->client->ps.saberMove) && + dmg > SABER_NONATTACK_DAMAGE && + !didOffense && + !unblockable) + { //they are in a parry, and we are slamming down on them with a move of equal or greater force than their defense, so send them into a broken parry.. unless they are already in one. + if (g_saberDebugPrint.integer) + { + Com_Printf("Client %i bounced off of client %i's saber\n", self->s.number, otherOwner->s.number); + } + + if (!tryDeflectAgain) + { + if (!WP_GetSaberDeflectionAngle(self, otherOwner, tr.fraction)) + { + tryDeflectAgain = qtrue; + } + } + + didOffense = qtrue; + } + else if (SaberAttacking(otherOwner) && dmg > SABER_NONATTACK_DAMAGE && !BG_SaberInSpecial(otherOwner->client->ps.saberMove) && !didOffense && !otherUnblockable) + { //they were attacking and our saber hit their saber, make them bounce. But if they're in a special attack, leave them. + if (!PM_SaberInBounce(self->client->ps.saberMove) && + !PM_SaberInBounce(otherOwner->client->ps.saberMove) && + !PM_SaberInDeflect(self->client->ps.saberMove) && + !PM_SaberInDeflect(otherOwner->client->ps.saberMove) && + + !PM_SaberInReflect(self->client->ps.saberMove) && + !PM_SaberInReflect(otherOwner->client->ps.saberMove)) + { + // Com_Printf("BLING\n"); + /* + WP_GetSaberDeflectionAngle(self, otherOwner, tr.fraction); + + if (SaberAttacking(self) && !unblockable && !BG_SaberInSpecial(otherOwner->client->ps.saberMove)) + { //make them bounce/deflect + WP_GetSaberDeflectionAngle(otherOwner, self, tr.fraction); + didDefense = qtrue; + } + */ + + if (g_saberDebugPrint.integer) + { + Com_Printf("Client %i and client %i bounced off of each other's sabers\n", self->s.number, otherOwner->s.number); + } + + self->client->ps.saberBlocked = BLOCKED_ATK_BOUNCE; otherOwner->client->ps.saberBlocked = BLOCKED_ATK_BOUNCE; - self->client->ps.saberBlockTime = level.time + (350 - (self->client->ps.fd.forcePowerLevel[FP_SABERDEFEND]*100));//300; - - otherOwner->client->ps.saberAttackWound = level.time + 300; + didOffense = qtrue; + // didDefense = qtrue; } } + +#ifdef G2_COLLISION_ENABLED + if (g_saberGhoul2Collision.integer && !didDefense && dmg <= SABER_NONATTACK_DAMAGE && !otherUnblockable) //with perpoly, it looks pretty weird to have clash flares coming off the guy's face and whatnot + { + if (!PM_SaberInParry(otherOwner->client->ps.saberMove) && + !PM_SaberInBrokenParry(otherOwner->client->ps.saberMove) && + !BG_SaberInSpecial(otherOwner->client->ps.saberMove) && + !PM_SaberInBounce(otherOwner->client->ps.saberMove) && + !PM_SaberInDeflect(otherOwner->client->ps.saberMove) && + !PM_SaberInReflect(otherOwner->client->ps.saberMove)) + { + WP_SaberBlockNonRandom(otherOwner, tr.endpos, qfalse); + } + } + else if (!didDefense && dmg > SABER_NONATTACK_DAMAGE && !otherUnblockable) //if not more than idle damage, don't even bother blocking. +#else + if (!didDefense && dmg > SABER_NONATTACK_DAMAGE && !otherUnblockable) //if not more than idle damage, don't even bother blocking. +#endif + { //block + if (!PM_SaberInParry(otherOwner->client->ps.saberMove) && + !PM_SaberInBrokenParry(otherOwner->client->ps.saberMove) && + !BG_SaberInSpecial(otherOwner->client->ps.saberMove) && + !PM_SaberInBounce(otherOwner->client->ps.saberMove) && + !PM_SaberInDeflect(otherOwner->client->ps.saberMove) && + !PM_SaberInReflect(otherOwner->client->ps.saberMove)) + { + qboolean crushTheParry = qfalse; + + if (unblockable) + { //It's unblockable. So send us into a broken parry immediately. + crushTheParry = qtrue; + } + + if (!SaberAttacking(otherOwner)) + { + WP_SaberBlockNonRandom(otherOwner, tr.endpos, qfalse); + } + else if (self->client->ps.fd.saberAnimLevel > otherOwner->client->ps.fd.saberAnimLevel || + (self->client->ps.fd.saberAnimLevel == otherOwner->client->ps.fd.saberAnimLevel && Q_irand(1, 10) <= 2)) + { //they are attacking, and we managed to make them break + //Give them a parry, so we can later break it. + WP_SaberBlockNonRandom(otherOwner, tr.endpos, qfalse); + crushTheParry = qtrue; + + if (g_saberDebugPrint.integer) + { + Com_Printf("Client %i forced client %i into a broken parry with a stronger attack\n", self->s.number, otherOwner->s.number); + } + } + else + { //They are attacking, so are we, and obviously they have an attack level higher than or equal to ours + if (self->client->ps.fd.saberAnimLevel == otherOwner->client->ps.fd.saberAnimLevel) + { //equal level, try to bounce off each other's sabers + if (!didOffense && + !PM_SaberInParry(self->client->ps.saberMove) && + !PM_SaberInBrokenParry(self->client->ps.saberMove) && + !BG_SaberInSpecial(self->client->ps.saberMove) && + !PM_SaberInBounce(self->client->ps.saberMove) && + !PM_SaberInDeflect(self->client->ps.saberMove) && + !PM_SaberInReflect(self->client->ps.saberMove) && + !unblockable) + { + /* + if (WP_GetSaberDeflectionAngle(self, otherOwner, tr.fraction)) + { + didOffense = qtrue; + } + */ + self->client->ps.saberBlocked = BLOCKED_ATK_BOUNCE; + didOffense = qtrue; + } + if (!didDefense && + !PM_SaberInParry(otherOwner->client->ps.saberMove) && + !PM_SaberInBrokenParry(otherOwner->client->ps.saberMove) && + !BG_SaberInSpecial(otherOwner->client->ps.saberMove) && + !PM_SaberInBounce(otherOwner->client->ps.saberMove) && + !PM_SaberInDeflect(otherOwner->client->ps.saberMove) && + !PM_SaberInReflect(otherOwner->client->ps.saberMove) && + !unblockable) + { + //WP_GetSaberDeflectionAngle(otherOwner, self, tr.fraction); + otherOwner->client->ps.saberBlocked = BLOCKED_ATK_BOUNCE; + } + if (g_saberDebugPrint.integer) + { + Com_Printf("Equal attack level bounce/deflection for clients %i and %i\n", self->s.number, otherOwner->s.number); + } + } + else if ((level.time - otherOwner->client->lastSaberStorageTime) < 500 && !unblockable) //make sure the stored saber data is updated + { //They are higher, this means they can actually smash us into a broken parry + /* + vec3_t saberMidPoint; + + //Base the block point off of their saber's mid point + saberMidPoint[0] = otherOwner->client->lastSaberBase_Always[0] + otherOwner->client->lastSaberDir_Always[0]*20; + saberMidPoint[0] = otherOwner->client->lastSaberBase_Always[1] + otherOwner->client->lastSaberDir_Always[1]*20; + saberMidPoint[0] = otherOwner->client->lastSaberBase_Always[2] + otherOwner->client->lastSaberDir_Always[2]*20; + + //Send us into a parry + WP_SaberBlockNonRandom(self, saberMidPoint, qfalse); + + //And then break the parry + if (PM_SaberInParry(G_GetParryForBlock(self->client->ps.saberBlocked))) + { + self->client->ps.saberMove = BG_BrokenParryForParry( G_GetParryForBlock(self->client->ps.saberBlocked) ); + self->client->ps.saberBlocked = BLOCKED_PARRY_BROKEN; + } + */ + //Using reflected anims instead now + self->client->ps.saberMove = BG_BrokenParryForAttack(self->client->ps.saberMove); + self->client->ps.saberBlocked = BLOCKED_PARRY_BROKEN; + + if (g_saberDebugPrint.integer) + { + Com_Printf("Client %i hit client %i's stronger attack, was forced into a broken parry\n", self->s.number, otherOwner->s.number); + } + + didOffense = qtrue; + } + } + + if (crushTheParry && PM_SaberInParry(G_GetParryForBlock(otherOwner->client->ps.saberBlocked))) + { //This means that the attack actually hit our saber, and we went to block it. + //But, one of the above cases says we actually can't. So we will be smashed into a broken parry instead. + otherOwner->client->ps.saberMove = BG_BrokenParryForParry( G_GetParryForBlock(otherOwner->client->ps.saberBlocked) ); + otherOwner->client->ps.saberBlocked = BLOCKED_PARRY_BROKEN; + + if (g_saberDebugPrint.integer) + { + Com_Printf("Client %i broke through %i's parry with a special or stronger attack\n", self->s.number, otherOwner->s.number); + } + } + else if (PM_SaberInParry(G_GetParryForBlock(otherOwner->client->ps.saberBlocked)) && !didOffense && tryDeflectAgain) + { //We want to try deflecting again because the other is in the parry and we haven't made any new moves + int preMove = otherOwner->client->ps.saberMove; + + otherOwner->client->ps.saberMove = G_GetParryForBlock(otherOwner->client->ps.saberBlocked); + WP_GetSaberDeflectionAngle(self, otherOwner, tr.fraction); + otherOwner->client->ps.saberMove = preMove; + } + } + } + + self->client->ps.saberAttackWound = level.time + g_saberDmgDelay_Wound.integer; } return didHit; @@ -1455,6 +2397,8 @@ qboolean CheckThrownSaberDamaged(gentity_t *saberent, gentity_t *saberOwner, gen { //Slice them if (!saberOwner->client->ps.isJediMaster && WP_SaberCanBlock(ent, tr.endpos, 0, MOD_SABER, qfalse, 8)) { + WP_SaberBlockNonRandom(ent, tr.endpos, qfalse); + te = G_TempEntity( tr.endpos, EV_SABER_BLOCK ); VectorCopy(tr.endpos, te->s.origin); VectorCopy(tr.plane.normal, te->s.angles); @@ -1532,7 +2476,14 @@ qboolean CheckThrownSaberDamaged(gentity_t *saberent, gentity_t *saberOwner, gen VectorSubtract(tr.endpos, saberent->r.currentOrigin, dir); VectorNormalize(dir); - G_Damage(ent, saberOwner, saberOwner, dir, tr.endpos, 5, 0, MOD_SABER); + if (ent->s.eType == ET_GRAPPLE) + { + G_Damage(ent, saberOwner, saberOwner, dir, tr.endpos, 40, 0, MOD_SABER); + } + else + { + G_Damage(ent, saberOwner, saberOwner, dir, tr.endpos, 5, 0, MOD_SABER); + } te = G_TempEntity( tr.endpos, EV_SABER_HIT ); VectorCopy(tr.endpos, te->s.origin); @@ -1777,8 +2728,8 @@ void saberBackToOwner(gentity_t *saberent) saberent->r.svFlags |= (SVF_NOCLIENT); saberent->r.contents = CONTENTS_LIGHTSABER; - VectorSet( saberent->r.mins, -8.0f, -8.0f, -8.0f ); - VectorSet( saberent->r.maxs, 8.0f, 8.0f, 8.0f ); + VectorSet( saberent->r.mins, -SABER_BOX_SIZE, -SABER_BOX_SIZE, -SABER_BOX_SIZE ); + VectorSet( saberent->r.maxs, SABER_BOX_SIZE, SABER_BOX_SIZE, SABER_BOX_SIZE ); saberent->s.loopSound = 0; g_entities[saberent->r.ownerNum].client->ps.saberInFlight = qfalse; @@ -1937,8 +2888,8 @@ void saberFirstThrown(gentity_t *saberent) saberent->r.svFlags |= (SVF_NOCLIENT); saberent->r.contents = CONTENTS_LIGHTSABER; - VectorSet( saberent->r.mins, -8.0f, -8.0f, -8.0f ); - VectorSet( saberent->r.maxs, 8.0f, 8.0f, 8.0f ); + VectorSet( saberent->r.mins, -SABER_BOX_SIZE, -SABER_BOX_SIZE, -SABER_BOX_SIZE ); + VectorSet( saberent->r.maxs, SABER_BOX_SIZE, SABER_BOX_SIZE, SABER_BOX_SIZE ); saberent->s.loopSound = 0; saberOwn->client->ps.saberInFlight = qfalse; @@ -2039,6 +2990,19 @@ runMin: G_RunObject(saberent); } +/* +void G_DebugDirection(vec3_t base, vec3_t dir) +{ + vec3_t dirPoint; + + dirPoint[0] = base[0] + dir[0]*64; + dirPoint[1] = base[1] + dir[1]*64; + dirPoint[2] = base[2] + dir[2]*64; + + G_TestLine(base, dirPoint, 0x0000ff, 100); +} +*/ + void WP_SaberPositionUpdate( gentity_t *self, usercmd_t *ucmd ) { //rww - keep the saber position as updated as possible on the server so that we can try to do realistic-looking contact stuff mdxaBone_t boltMatrix; @@ -2173,6 +3137,11 @@ void WP_SaberPositionUpdate( gentity_t *self, usercmd_t *ucmd ) boltAngles[1] = -boltMatrix.matrix[1][1]; boltAngles[2] = -boltMatrix.matrix[2][1]; + //immediately store these values so we don't have to recalculate this again + VectorCopy(boltOrigin, self->client->lastSaberBase_Always); + VectorCopy(boltOrigin, self->client->lastSaberDir_Always); + self->client->lastSaberStorageTime = level.time; + VectorCopy(boltAngles, rawAngles); VectorMA( boltOrigin, 40, boltAngles, end ); @@ -2181,7 +3150,8 @@ void WP_SaberPositionUpdate( gentity_t *self, usercmd_t *ucmd ) { gentity_t *mySaber = &g_entities[self->client->ps.saberEntityNum]; - if (mySaber && (mySaber->r.contents & CONTENTS_LIGHTSABER) && !self->client->ps.saberInFlight) + //I guess it's good to keep the position updated even when contents are 0 + if (mySaber && ((mySaber->r.contents & CONTENTS_LIGHTSABER) || mySaber->r.contents == 0) && !self->client->ps.saberInFlight) { //place it roughly in the middle of the saber.. VectorMA( boltOrigin, 20, boltAngles, mySaber->r.currentOrigin ); @@ -2289,8 +3259,8 @@ void WP_SaberPositionUpdate( gentity_t *self, usercmd_t *ucmd ) { saberent->r.svFlags |= (SVF_NOCLIENT); saberent->r.contents = CONTENTS_LIGHTSABER; - VectorSet( saberent->r.mins, -8.0f, -8.0f, -8.0f ); - VectorSet( saberent->r.maxs, 8.0f, 8.0f, 8.0f ); + VectorSet( saberent->r.mins, -SABER_BOX_SIZE, -SABER_BOX_SIZE, -SABER_BOX_SIZE ); + VectorSet( saberent->r.maxs, SABER_BOX_SIZE, SABER_BOX_SIZE, SABER_BOX_SIZE ); saberent->s.loopSound = 0; } @@ -2326,14 +3296,163 @@ void WP_SaberPositionUpdate( gentity_t *self, usercmd_t *ucmd ) if (self->client->hasCurrentPosition && g_saberInterpolate.integer) { - if (!CheckSaberDamage(self, boltOrigin, end, qfalse)) + if (g_saberInterpolate.integer == 1) { - CheckSaberDamage(self, boltOrigin, end, qtrue); + int trMask = CONTENTS_LIGHTSABER|CONTENTS_BODY; + int sN = 0; + qboolean gotHit = qfalse; + qboolean clientUnlinked[MAX_CLIENTS]; + + if (!g_saberTraceSaberFirst.integer) + { //skip the saber-contents-only trace and get right to the full trace + trMask = (MASK_PLAYERSOLID|CONTENTS_LIGHTSABER|MASK_SHOT); + } + else + { + while (sN < MAX_CLIENTS) + { + if (g_entities[sN].inuse && g_entities[sN].client && g_entities[sN].r.linked && g_entities[sN].health > 0 && (g_entities[sN].r.contents & CONTENTS_BODY)) + { //This was linking and relinking entities. But apparently you don't even have to do that to change contents (which is a very good thing) + //trap_UnlinkEntity(&g_entities[sN]); + g_entities[sN].r.contents &= ~CONTENTS_BODY; + clientUnlinked[sN] = qtrue; + } + else + { + clientUnlinked[sN] = qfalse; + } + sN++; + } + } + + while (!gotHit) + { + if (!CheckSaberDamage(self, boltOrigin, end, qfalse, trMask)) + { + if (!CheckSaberDamage(self, boltOrigin, end, qtrue, trMask)) + { + vec3_t oldSaberStart; + vec3_t oldSaberEnd; + vec3_t saberAngleNow; + vec3_t saberAngleBefore; + vec3_t saberMidDir; + vec3_t saberMidAngle; + vec3_t saberMidPoint; + vec3_t saberMidEnd; + vec3_t saberSubBase; + float deltaX, deltaY, deltaZ; + + VectorCopy(self->client->lastSaberBase, oldSaberStart); + VectorCopy(self->client->lastSaberTip, oldSaberEnd); + + VectorSubtract(oldSaberEnd, oldSaberStart, saberAngleBefore); + vectoangles(saberAngleBefore, saberAngleBefore); + + VectorSubtract(end, boltOrigin, saberAngleNow); + vectoangles(saberAngleNow, saberAngleNow); + + deltaX = AngleDelta(saberAngleBefore[0], saberAngleNow[0]); + deltaY = AngleDelta(saberAngleBefore[1], saberAngleNow[1]); + deltaZ = AngleDelta(saberAngleBefore[2], saberAngleNow[2]); + + if ( (deltaX != 0 || deltaY != 0 || deltaZ != 0) && deltaX < 180 && deltaY < 180 && deltaZ < 180 && (BG_SaberInAttack(self->client->ps.saberMove) || PM_SaberInTransition(self->client->ps.saberMove)) ) + { //don't go beyond here if we aren't attacking/transitioning or the angle is too large. + //and don't bother if the angle is the same + saberMidAngle[0] = saberAngleBefore[0] + (deltaX/2); + saberMidAngle[1] = saberAngleBefore[1] + (deltaY/2); + saberMidAngle[2] = saberAngleBefore[2] + (deltaZ/2); + + //Now that I have the angle, I'll just say the base for it is the difference between the two start + //points (even though that's quite possibly completely false) + VectorSubtract(boltOrigin, oldSaberStart, saberSubBase); + saberMidPoint[0] = boltOrigin[0] + (saberSubBase[0]*0.5); + saberMidPoint[1] = boltOrigin[1] + (saberSubBase[1]*0.5); + saberMidPoint[2] = boltOrigin[2] + (saberSubBase[2]*0.5); + + AngleVectors(saberMidAngle, saberMidDir, 0, 0); + saberMidEnd[0] = saberMidPoint[0] + saberMidDir[0]*40; //40 == saber length + saberMidEnd[1] = saberMidPoint[1] + saberMidDir[1]*40; + saberMidEnd[2] = saberMidPoint[2] + saberMidDir[2]*40; + + //Now that we have the difference points, check from them to both the old position and the new + /* + if (!CheckSaberDamage(self, saberMidPoint, saberMidEnd, qtrue, trMask)) //this checks between mid and old + { //that didn't hit, so copy the mid over the old and check between the new and mid + VectorCopy(saberMidPoint, self->client->lastSaberBase); + VectorCopy(saberMidEnd, self->client->lastSaberTip); + + if (CheckSaberDamage(self, boltOrigin, end, qtrue, trMask)) + { + gotHit = qtrue; + } + + //Then copy the old oldpoints in back for good measure + VectorCopy(oldSaberStart, self->client->lastSaberBase); + VectorCopy(oldSaberEnd, self->client->lastSaberTip); + } + else + { + gotHit = qtrue; + } + */ + //The above was more aggressive in approach, but it did add way too many traces unfortunately. + //I'll just trace straight out and not even trace between positions instead. + if (CheckSaberDamage(self, saberMidPoint, saberMidEnd, qfalse, trMask)) + { + gotHit = qtrue; + } + } + } + else + { + gotHit = qtrue; + } + } + else + { + gotHit = qtrue; + } + + if (g_saberTraceSaberFirst.integer) + { + sN = 0; + while (sN < MAX_CLIENTS) + { + if (clientUnlinked[sN]) + { + if (g_entities[sN].inuse && g_entities[sN].health > 0) + { + g_entities[sN].r.contents |= CONTENTS_BODY; + } + } + sN++; + } + } + + if (!gotHit) + { + if (trMask != (MASK_PLAYERSOLID|CONTENTS_LIGHTSABER|MASK_SHOT)) + { + trMask = (MASK_PLAYERSOLID|CONTENTS_LIGHTSABER|MASK_SHOT); + } + else + { + gotHit = qtrue; //break out of the loop + } + } + } + } + else if (g_saberInterpolate.integer) //anything but 0 or 1, use the old plain method. + { + if (!CheckSaberDamage(self, boltOrigin, end, qfalse, (MASK_PLAYERSOLID|CONTENTS_LIGHTSABER|MASK_SHOT))) + { + CheckSaberDamage(self, boltOrigin, end, qtrue, (MASK_PLAYERSOLID|CONTENTS_LIGHTSABER|MASK_SHOT)); + } } } else { - CheckSaberDamage(self, boltOrigin, end, qfalse); + CheckSaberDamage(self, boltOrigin, end, qfalse, (MASK_PLAYERSOLID|CONTENTS_LIGHTSABER|MASK_SHOT)); } if (self->client->ps.dualBlade) @@ -2346,7 +3465,7 @@ void WP_SaberPositionUpdate( gentity_t *self, usercmd_t *ucmd ) self->client->ps.saberIdleWound = 0; self->client->ps.saberAttackWound = 0; - CheckSaberDamage(self, otherOrg, otherEnd, qfalse); + CheckSaberDamage(self, otherOrg, otherEnd, qfalse, (MASK_PLAYERSOLID|CONTENTS_LIGHTSABER|MASK_SHOT)); } VectorCopy(boltOrigin, self->client->lastSaberBase); @@ -2359,7 +3478,7 @@ finalUpdate: if (self->client->ps.saberLockFrame) { trap_G2API_SetBoneAnim(self->client->ghoul2, 0, "model_root", self->client->ps.saberLockFrame, self->client->ps.saberLockFrame+1, BONE_ANIM_OVERRIDE_FREEZE|BONE_ANIM_BLEND, animSpeedScale, level.time, -1, 150); - trap_G2API_SetBoneAnim(self->client->ghoul2, 0, "upper_lumbar", self->client->ps.saberLockFrame, self->client->ps.saberLockFrame+1, BONE_ANIM_OVERRIDE_FREEZE|BONE_ANIM_BLEND, animSpeedScale, level.time, -1, 150); + trap_G2API_SetBoneAnim(self->client->ghoul2, 0, "lower_lumbar", self->client->ps.saberLockFrame, self->client->ps.saberLockFrame+1, BONE_ANIM_OVERRIDE_FREEZE|BONE_ANIM_BLEND, animSpeedScale, level.time, -1, 150); trap_G2API_SetBoneAnim(self->client->ghoul2, 0, "Motion", self->client->ps.saberLockFrame, self->client->ps.saberLockFrame+1, BONE_ANIM_OVERRIDE_FREEZE|BONE_ANIM_BLEND, animSpeedScale, level.time, -1, 150); return; } @@ -2421,7 +3540,7 @@ finalUpdate: aFlags |= BONE_ANIM_BLEND; //since client defaults to blend. Not sure if this will make much difference if any on client position, but it's here just for the sake of matching them. - trap_G2API_SetBoneAnim(self->client->ghoul2, 0, "upper_lumbar", initialFrame, bgGlobalAnimations[f].firstFrame+bgGlobalAnimations[f].numFrames, aFlags, animSpeedScale, level.time, initialFrame, 150); + trap_G2API_SetBoneAnim(self->client->ghoul2, 0, "lower_lumbar", initialFrame, bgGlobalAnimations[f].firstFrame+bgGlobalAnimations[f].numFrames, aFlags, animSpeedScale, level.time, initialFrame, 150); self->client->ps.torsoAnimExecute = torsoAnim; @@ -2717,6 +3836,11 @@ int WP_SaberCanBlock(gentity_t *self, vec3_t point, int dflags, int mod, qboolea } } + if (PM_SaberInBrokenParry(self->client->ps.saberMove)) + { + return 0; + } + if (self->client->ps.saberHolstered) { return 0; @@ -2748,6 +3872,8 @@ int WP_SaberCanBlock(gentity_t *self, vec3_t point, int dflags, int mod, qboolea return 0; } + //Removed this for no, the new broken parry stuff should handle it. + /* if (attackStr == FORCE_LEVEL_3) { if (self->client->ps.fd.forcePowerLevel[FP_SABERDEFEND] >= FORCE_LEVEL_3) @@ -2787,6 +3913,7 @@ int WP_SaberCanBlock(gentity_t *self, vec3_t point, int dflags, int mod, qboolea { //if I have no defense level at all then I might be unable to block a level 1 attack (but very rarely) return 0; } + */ if (SaberAttacking(self)) { //attacking, can't block now @@ -2813,7 +3940,18 @@ int WP_SaberCanBlock(gentity_t *self, vec3_t point, int dflags, int mod, qboolea if (self->client->ps.fd.forcePowerLevel[FP_SABERDEFEND] == FORCE_LEVEL_3) { +#ifdef G2_COLLISION_ENABLED + if (g_saberGhoul2Collision.integer) + { + blockFactor = 0.3f; + } + else + { + blockFactor = 0.05f; + } +#else blockFactor = 0.05f; +#endif } else if (self->client->ps.fd.forcePowerLevel[FP_SABERDEFEND] == FORCE_LEVEL_2) { @@ -2833,12 +3971,20 @@ int WP_SaberCanBlock(gentity_t *self, vec3_t point, int dflags, int mod, qboolea blockFactor -= 0.25f; } + if (attackStr) + { //blocking a saber, not a projectile. + blockFactor -= 0.25f; + } + if (!InFront( point, self->client->ps.origin, self->client->ps.viewangles, blockFactor )) //orig 0.2f { return 0; } - WP_SaberBlockNonRandom(self, point, projectile); + if (projectile) + { + WP_SaberBlockNonRandom(self, point, projectile); + } return 1; } diff --git a/CODE-mp/ghoul2/G2_API.cpp b/CODE-mp/ghoul2/G2_API.cpp index 24d0657..6a9d823 100644 --- a/CODE-mp/ghoul2/G2_API.cpp +++ b/CODE-mp/ghoul2/G2_API.cpp @@ -15,6 +15,10 @@ #endif #include "G2_local.h" +#ifdef G2_COLLISION_ENABLED +#include "../qcommon/miniheap.h" +#endif + #include extern mdxaBone_t worldMatrix; @@ -172,6 +176,7 @@ int G2API_InitGhoul2Model(CGhoul2Info_v **ghoul2Ptr, const char *fileName, int m { if (ghoul2.size() == 0)//very first model created {//you can't have an empty vector, so let's not give it one + G2API_CleanGhoul2Models(ghoul2Ptr); delete *ghoul2Ptr; *ghoul2Ptr = 0; } @@ -777,11 +782,76 @@ void G2API_DetachEnt(int *boltInfo) } qboolean gG2_GBMNoReconstruct; +qboolean gG2_GBMUseSPMethod; + +qboolean G2API_GetBoltMatrix_SPMethod(CGhoul2Info_v &ghoul2, const int modelIndex, const int boltIndex, mdxaBone_t *matrix, const vec3_t angles, + const vec3_t position, const int frameNum, qhandle_t *modelList, const vec3_t scale ) +{ + assert(ghoul2.size() > modelIndex); + + if ((int)&ghoul2 && (ghoul2.size() > modelIndex)) + { + CGhoul2Info *ghlInfo = &ghoul2[modelIndex]; + + //assert(boltIndex < ghlInfo->mBltlist.size()); + + if (ghlInfo && (boltIndex < ghlInfo->mBltlist.size()) && boltIndex >= 0 ) + { + // make sure we have transformed the skeleton + if (!gG2_GBMNoReconstruct) + { + G2_ConstructGhoulSkeleton(ghoul2, frameNum, modelList, true, angles, position, scale, false); + } + + gG2_GBMNoReconstruct = qfalse; + + mdxaBone_t scaled; + mdxaBone_t *use; + use=&ghlInfo->mBltlist[boltIndex].position; + + if (scale[0]||scale[1]||scale[2]) + { + scaled=*use; + use=&scaled; + + // scale the bolt position by the scale factor for this model since at this point its still in model space + if (scale[0]) + { + scaled.matrix[0][3] *= scale[0]; + } + if (scale[1]) + { + scaled.matrix[1][3] *= scale[1]; + } + if (scale[2]) + { + scaled.matrix[2][3] *= scale[2]; + } + } + // pre generate the world matrix + G2_GenerateWorldMatrix(angles, position); + + VectorNormalize((float*)use->matrix[0]); + VectorNormalize((float*)use->matrix[1]); + VectorNormalize((float*)use->matrix[2]); + + Multiply_3x4Matrix(matrix, &worldMatrix, use); + return qtrue; + } + } + return qfalse; +} qboolean G2API_GetBoltMatrix(CGhoul2Info_v &ghoul2, const int modelIndex, const int boltIndex, mdxaBone_t *matrix, const vec3_t angles, const vec3_t position, const int frameNum, qhandle_t *modelList, vec3_t scale ) { assert(ghoul2.size() > modelIndex); + if (gG2_GBMUseSPMethod) + { + gG2_GBMUseSPMethod = qfalse; + return G2API_GetBoltMatrix_SPMethod(ghoul2, modelIndex, boltIndex, matrix, angles, position, frameNum, modelList, scale); + } + if ((int)&ghoul2 && (ghoul2.size() > modelIndex)) { CGhoul2Info *ghlInfo = &ghoul2[modelIndex]; @@ -950,7 +1020,7 @@ static int QDECL QsortDistance( const void *a, const void *b ) { void G2API_CollisionDetect(CollisionRecord_t *collRecMap, CGhoul2Info_v &ghoul2, const vec3_t angles, const vec3_t position, - int frameNumber, int entNum, vec3_t rayStart, vec3_t rayEnd, vec3_t scale, CMiniHeap *G2VertSpace, int traceFlags, int useLod) + int frameNumber, int entNum, vec3_t rayStart, vec3_t rayEnd, vec3_t scale, CMiniHeap *G2VertSpace, int traceFlags, int useLod, float fRadius) { if ((int)&ghoul2) @@ -963,6 +1033,10 @@ void G2API_CollisionDetect(CollisionRecord_t *collRecMap, CGhoul2Info_v &ghoul2, // pre generate the world matrix - used to transform the incoming ray G2_GenerateWorldMatrix(angles, position); +#ifdef G2_COLLISION_ENABLED + G2VertSpace->ResetHeap(); +#endif + // now having done that, time to build the model G2_TransformModel(ghoul2, frameNumber, scale, G2VertSpace, useLod); @@ -972,11 +1046,20 @@ void G2API_CollisionDetect(CollisionRecord_t *collRecMap, CGhoul2Info_v &ghoul2, TransformAndTranslatePoint(rayEnd, transRayEnd, &worldMatrixInv); // now walk each model and check the ray against each poly - sigh, this is SO expensive. I wish there was a better way to do this. - G2_TraceModels(ghoul2, transRayStart, transRayEnd, collRecMap, entNum, traceFlags, useLod); + G2_TraceModels(ghoul2, transRayStart, transRayEnd, collRecMap, entNum, traceFlags, useLod, fRadius); +#ifdef G2_COLLISION_ENABLED + int i; + for ( i = 0; i < MAX_G2_COLLISIONS && collRecMap[i].mEntityNum != -1; i ++ ); + // now sort the resulting array of collision records so they are distance ordered + qsort( collRecMap, i, + sizeof( CCollisionRecord ), QsortDistance ); + +#else // now sort the resulting array of collision records so they are distance ordered qsort( collRecMap, MAX_G2_COLLISIONS, sizeof( CCollisionRecord ), QsortDistance ); +#endif } } diff --git a/CODE-mp/ghoul2/G2_local.h b/CODE-mp/ghoul2/G2_local.h index dfd7014..36e4ad4 100644 --- a/CODE-mp/ghoul2/G2_local.h +++ b/CODE-mp/ghoul2/G2_local.h @@ -55,7 +55,7 @@ qboolean G2_Get_Bone_Anim_Index( boneInfo_v &blist, const int index, const int c void G2_List_Model_Surfaces(const char *fileName); void G2_List_Model_Bones(const char *fileName, int frame); qboolean G2_GetAnimFileName(const char *fileName, char **filename); -void G2_TraceModels(CGhoul2Info_v &ghoul2, vec3_t rayStart, vec3_t rayEnd, CollisionRecord_t *collRecMap, int entNum, int traceFlags, int useLod); +void G2_TraceModels(CGhoul2Info_v &ghoul2, vec3_t rayStart, vec3_t rayEnd, CollisionRecord_t *collRecMap, int entNum, int traceFlags, int useLod, float fRadius); void TransformAndTranslatePoint (vec3_t in, vec3_t out, mdxaBone_t *mat); void G2_TransformModel(CGhoul2Info_v &ghoul2, const int frameNum, vec3_t scale, CMiniHeap *G2VertSpace, int useLod); void G2_GenerateWorldMatrix(const vec3_t angles, const vec3_t origin); @@ -128,7 +128,7 @@ int G2API_GetGhoul2ModelFlags(CGhoul2Info *ghlInfo); qboolean G2API_GetAnimFileName(CGhoul2Info *ghlInfo, char **filename); void G2API_CollisionDetect(CollisionRecord_t *collRecMap, CGhoul2Info_v &ghoul2, const vec3_t angles, const vec3_t position, - int frameNumber, int entNum, vec3_t rayStart, vec3_t rayEnd, vec3_t scale, CMiniHeap *G2VertSpace, int traceFlags, int useLod); + int frameNumber, int entNum, vec3_t rayStart, vec3_t rayEnd, vec3_t scale, CMiniHeap *G2VertSpace, int traceFlags, int useLod, float fRadius); void G2API_GiveMeVectorFromMatrix(mdxaBone_t *boltMatrix, Eorientations flags, vec3_t vec); int G2API_CopyGhoul2Instance(CGhoul2Info_v &g2From, CGhoul2Info_v &g2To, int modelIndex); @@ -160,6 +160,7 @@ void G2API_DuplicateGhoul2Instance(CGhoul2Info_v &g2From, CGhoul2Info_v **g2To) void G2API_SetBoltInfo(CGhoul2Info_v &ghoul2, int modelIndex, int boltInfo); extern qboolean gG2_GBMNoReconstruct; +extern qboolean gG2_GBMUseSPMethod; // From tr_ghoul2.cpp void G2_ConstructGhoulSkeleton( CGhoul2Info_v &ghoul2, const int frameNum, qhandle_t *modelList, bool checkForNewOrigin, const vec3_t angles, const vec3_t position, const vec3_t scale, bool modelSet); diff --git a/CODE-mp/ghoul2/G2_misc.cpp b/CODE-mp/ghoul2/G2_misc.cpp index 2cff8f8..fba238b 100644 --- a/CODE-mp/ghoul2/G2_misc.cpp +++ b/CODE-mp/ghoul2/G2_misc.cpp @@ -151,6 +151,7 @@ public: int *TransformedVertsArray; int traceFlags; bool hitOne; + float m_fRadius; CTraceSurface( @@ -166,7 +167,8 @@ public: skin_t *initskin, shader_t *initcust_shader, int *initTransformedVertsArray, - int inittraceFlags): + int inittraceFlags, + float fRadius): surfaceNum(initsurfaceNum), rootSList(initrootSList), @@ -178,7 +180,8 @@ public: skin(initskin), cust_shader(initcust_shader), traceFlags(inittraceFlags), - TransformedVertsArray(initTransformedVertsArray) + TransformedVertsArray(initTransformedVertsArray), + m_fRadius(fRadius) { VectorCopy(initrayStart, rayStart); VectorCopy(initrayEnd, rayEnd); @@ -307,6 +310,99 @@ int G2_DecideTraceLod(CGhoul2Info &ghoul2, int useLod, model_t *mod) return returnLod; } +#ifdef G2_COLLISION_ENABLED +void R_TransformEachSurface( mdxmSurface_t *surface, vec3_t scale, CMiniHeap *G2VertSpace, int *TransformedVertsArray, mdxaBone_v &bonePtr) { + int j, k, pos; + int numVerts; + mdxmVertex_t *v; + float *TransformedVerts; + + // + // deform the vertexes by the lerped bones + // + + // alloc some space for the transformed verts to get put in + v = (mdxmVertex_t *) ((byte *)surface + surface->ofsVerts); + numVerts = surface->numVerts; + mdxmVertexTexCoord_t *pTexCoords = (mdxmVertexTexCoord_t *) &v[numVerts]; + + TransformedVerts = (float *)G2VertSpace->MiniHeapAlloc(numVerts * 5 * 4); + TransformedVertsArray[surface->thisSurfaceIndex] = (int)TransformedVerts; + if (!TransformedVerts) + { + Com_Error(ERR_DROP, "Ran out of transform space gameside for Ghoul2 Models.\n"); + } + + // whip through and actually transform each vertex + int *piBoneRefs = (int*) ((byte*)surface + surface->ofsBoneReferences); + + // optimisation issue + if ((scale[0] != 1.0) || (scale[1] != 1.0) || (scale[2] != 1.0)) + { + for ( j = pos = 0; j < numVerts; j++ ) + { + vec3_t tempVert; + + VectorClear( tempVert ); + + const int iNumWeights = G2_GetVertWeights( v ); + float fTotalWeight = 0.0f; + for ( k = 0 ; k < iNumWeights ; k++ ) + { + int iBoneIndex = G2_GetVertBoneIndex( v, k ); + float fBoneWeight = G2_GetVertBoneWeight( v, k, fTotalWeight, iNumWeights ); + + const mdxaBone_t &bone=bonePtr[piBoneRefs[iBoneIndex]].second; + + tempVert[0] += fBoneWeight * ( DotProduct( bone.matrix[0], v->vertCoords ) + bone.matrix[0][3] ); + tempVert[1] += fBoneWeight * ( DotProduct( bone.matrix[1], v->vertCoords ) + bone.matrix[1][3] ); + tempVert[2] += fBoneWeight * ( DotProduct( bone.matrix[2], v->vertCoords ) + bone.matrix[2][3] ); + } + // copy tranformed verts into temp space + TransformedVerts[pos++] = tempVert[0] * scale[0]; + TransformedVerts[pos++] = tempVert[1] * scale[1]; + TransformedVerts[pos++] = tempVert[2] * scale[2]; + // we will need the S & T coors too for hitlocation and hitmaterial stuff + TransformedVerts[pos++] = pTexCoords[j].texCoords[0]; + TransformedVerts[pos++] = pTexCoords[j].texCoords[1]; + + v++;// = (mdxmVertex_t *)&v->weights[/*v->numWeights*/surface->maxVertBoneWeights]; + } + } + else + { + for ( j = pos = 0; j < numVerts; j++ ) + { + vec3_t tempVert; + + VectorClear( tempVert ); + + const int iNumWeights = G2_GetVertWeights( v ); + float fTotalWeight = 0.0f; + for ( k = 0 ; k < iNumWeights ; k++ ) + { + int iBoneIndex = G2_GetVertBoneIndex( v, k ); + float fBoneWeight = G2_GetVertBoneWeight( v, k, fTotalWeight, iNumWeights ); + + const mdxaBone_t &bone=bonePtr[piBoneRefs[iBoneIndex]].second; + + tempVert[0] += fBoneWeight * ( DotProduct( bone.matrix[0], v->vertCoords ) + bone.matrix[0][3] ); + tempVert[1] += fBoneWeight * ( DotProduct( bone.matrix[1], v->vertCoords ) + bone.matrix[1][3] ); + tempVert[2] += fBoneWeight * ( DotProduct( bone.matrix[2], v->vertCoords ) + bone.matrix[2][3] ); + } + // copy tranformed verts into temp space + TransformedVerts[pos++] = tempVert[0]; + TransformedVerts[pos++] = tempVert[1]; + TransformedVerts[pos++] = tempVert[2]; + // we will need the S & T coors too for hitlocation and hitmaterial stuff + TransformedVerts[pos++] = pTexCoords[j].texCoords[0]; + TransformedVerts[pos++] = pTexCoords[j].texCoords[1]; + + v++;// = (mdxmVertex_t *)&v->weights[/*v->numWeights*/surface->maxVertBoneWeights]; + } + } +} +#else void R_TransformEachSurface( mdxmSurface_t *surface, vec3_t scale, CMiniHeap *G2VertSpace, int *TransformedVertsArray, mdxaBone_v &bonePtr) { int j, k; int numVerts; @@ -415,6 +511,7 @@ void R_TransformEachSurface( mdxmSurface_t *surface, vec3_t scale, CMiniHeap *G2 } } } +#endif void G2_TransformSurfaces(int surfaceNum, surfaceInfo_v &rootSList, mdxaBone_v &bonePtr, model_t *currentModel, int lod, vec3_t scale, CMiniHeap *G2VertSpace, int *TransformedVertArray, bool secondTimeAround) @@ -845,6 +942,222 @@ void G2_GorePolys( const mdxmSurface_t *surface, const vec3_t rayStart, const ve } #endif // _SOF2 +//Sorry for the sloppiness here, this stuff is just hacked together to work from SP +#ifdef G2_COLLISION_ENABLED + +#ifndef _SOF2 +struct SVertexTemp +{ + int flags; + int touch; + int newindex; + float tex[2]; + SVertexTemp() + { + touch=0; + } +}; +#define MAX_GORE_VERTS (3000) +static SVertexTemp GoreVerts[MAX_GORE_VERTS]; +#endif + +void TransformAndTranslatePoint_SP (const vec3_t in, vec3_t out, mdxaBone_t *mat) +{ + + for (int i=0;i<3;i++) + { + out[i]= in[0]*mat->matrix[i][0] + in[1]*mat->matrix[i][1] + in[2]*mat->matrix[i][2] + mat->matrix[i][3]; + } +} + +// now we're at poly level, check each model space transformed poly against the model world transfomed ray +static bool G2_RadiusTracePolys( const mdxmSurface_t *surface, const vec3_t rayStart, const vec3_t rayEnd, CollisionRecord_t *collRecMap, int entNum, int modelIndex, const skin_t *skin, const shader_t *cust_shader, const mdxmSurfHierarchy_t *surfInfo, int *TransformedVertsArray, int traceFlags, float fRadius) +{ + int j; + vec3_t basis1; + vec3_t basis2; + vec3_t taxis; + vec3_t saxis; + + basis2[0]=0.0f; + basis2[1]=0.0f; + basis2[2]=1.0f; + + vec3_t v3RayDir; + VectorSubtract(rayEnd, rayStart, v3RayDir); + + CrossProduct(v3RayDir,basis2,basis1); + + if (DotProduct(basis1,basis1)<.1f) + { + basis2[0]=0.0f; + basis2[1]=1.0f; + basis2[2]=0.0f; + CrossProduct(v3RayDir,basis2,basis1); + } + + CrossProduct(v3RayDir,basis1,basis2); + // Give me a shot direction not a bunch of zeros :) -Gil +// assert(DotProduct(basis1,basis1)>.0001f); +// assert(DotProduct(basis2,basis2)>.0001f); + + VectorNormalize(basis1); + VectorNormalize(basis2); + + const float c=cos(0);//theta + const float s=sin(0);//theta + + VectorScale(basis1, 0.5f * c / fRadius,taxis); + VectorMA(taxis, 0.5f * s / fRadius,basis2,taxis); + + VectorScale(basis1,-0.5f * s /fRadius,saxis); + VectorMA( saxis, 0.5f * c /fRadius,basis2,saxis); + + const float * const verts = (float *)TransformedVertsArray[surface->thisSurfaceIndex]; + const int numVerts = surface->numVerts; + + int flags=63; + //rayDir/=lengthSquared(raydir); + const float f = VectorLengthSquared(v3RayDir); + v3RayDir[0]/=f; + v3RayDir[1]/=f; + v3RayDir[2]/=f; + + for ( j = 0; j < numVerts; j++ ) + { + const int pos=j*5; + vec3_t delta; + delta[0]=verts[pos+0]-rayStart[0]; + delta[1]=verts[pos+1]-rayStart[1]; + delta[2]=verts[pos+2]-rayStart[2]; + const float s=DotProduct(delta,saxis)+0.5f; + const float t=DotProduct(delta,taxis)+0.5f; + const float u=DotProduct(delta,v3RayDir); + int vflags=0; + + if (s>0) + { + vflags|=1; + } + if (s<1) + { + vflags|=2; + } + if (t>0) + { + vflags|=4; + } + if (t<1) + { + vflags|=8; + } + if (u>0) + { + vflags|=16; + } + if (u<1) + { + vflags|=32; + } + + vflags=(~vflags); + flags&=vflags; + GoreVerts[j].flags=vflags; + } + + if (flags) + { + return false; // completely off the gore splotch (so presumably hit nothing? -Ste) + } + const int numTris = surface->numTriangles; + const mdxmTriangle_t * const tris = (mdxmTriangle_t *) ((byte *)surface + surface->ofsTriangles); + + for ( j = 0; j < numTris; j++ ) + { + assert(tris[j].indexes[0]>=0&&tris[j].indexes[0]=0&&tris[j].indexes[1]=0&&tris[j].indexes[2]thisSurfaceIndex; + newCol.mModelIndex = modelIndex; +// if (face>0) +// { + newCol.mFlags = G2_FRONTFACE; +// } +// else +// { +// newCol.mFlags = G2_BACKFACE; +// } + + //get normal from triangle + const float *A = &verts[(tris[j].indexes[0] * 5)]; + const float *B = &verts[(tris[j].indexes[1] * 5)]; + const float *C = &verts[(tris[j].indexes[2] * 5)]; + vec3_t normal; + vec3_t edgeAC, edgeBA; + + VectorSubtract(C, A, edgeAC); + VectorSubtract(B, A, edgeBA); + CrossProduct(edgeBA, edgeAC, normal); + + // transform normal (but don't translate) into world angles + TransformPoint(normal, newCol.mCollisionNormal, &worldMatrix); + VectorNormalize(newCol.mCollisionNormal); + + newCol.mMaterial = newCol.mLocation = 0; + // exit now if we should + if (traceFlags & G2_RETURNONHIT) + { + //hitOne = true; + return true; + } + + //i don't know the hitPoint, but let's just assume it's the first vert for now... + const float *hitPoint = A; + vec3_t distVect; + + VectorSubtract(hitPoint, rayStart, distVect); + newCol.mDistance = VectorLength(distVect); + + // put the hit point back into world space + TransformAndTranslatePoint_SP(hitPoint, newCol.mCollisionPosition, &worldMatrix); + newCol.mBarycentricI = newCol.mBarycentricJ = 0.0f; + + break; + } + } + if (i==MAX_G2_COLLISIONS) + { + //assert(i!=MAX_G2_COLLISIONS); // run out of collision record space - happens OFTEN + //hitOne = true; //force stop recursion + return true; // return true to avoid wasting further time, but no hit will result without a record + } + } + } + + return false; +} +#endif + // now we're at poly level, check each model space transformed poly against the model world transfomed ray bool G2_TracePolys( const mdxmSurface_t *surface, const vec3_t rayStart, const vec3_t rayEnd, CollisionRecord_t *collRecMap, int entNum, int modelIndex, const skin_t *skin, const shader_t *cust_shader, const mdxmSurfHierarchy_t *surfInfo, int *TransformedVertsArray, int traceFlags) { @@ -1002,13 +1315,30 @@ void G2_TraceSurfaces(CTraceSurface &TS) // if this surface is not off, add it to the shader render list if (!offFlags) { - // go away and trace the polys in this surface - if (G2_TracePolys(surface, TS.rayStart, TS.rayEnd, TS.collRecMap, TS.entNum, TS.modelIndex, TS.skin, TS.cust_shader, surfInfo, TS.TransformedVertsArray, TS.traceFlags) && (TS.traceFlags & G2_RETURNONHIT)) +#ifdef G2_COLLISION_ENABLED + if (!(fabs(TS.m_fRadius) < 0.1)) // if not a point-trace { - // ok, we hit one, *and* we want to return instantly because the returnOnHit is set - // so indicate we've hit one, so other surfaces don't get hit and return - TS.hitOne = true; - return; + // .. then use radius check + // + if (G2_RadiusTracePolys(surface, TS.rayStart, TS.rayEnd, TS.collRecMap, TS.entNum, TS.modelIndex, TS.skin, TS.cust_shader, surfInfo, TS.TransformedVertsArray, TS.traceFlags, TS.m_fRadius) && (TS.traceFlags & G2_RETURNONHIT)) + { + // ok, we hit one, *and* we want to return instantly because the returnOnHit is set + // so indicate we've hit one, so other surfaces don't get hit and return + TS.hitOne = true; + return; + } + } + else +#endif + { + // go away and trace the polys in this surface + if (G2_TracePolys(surface, TS.rayStart, TS.rayEnd, TS.collRecMap, TS.entNum, TS.modelIndex, TS.skin, TS.cust_shader, surfInfo, TS.TransformedVertsArray, TS.traceFlags) && (TS.traceFlags & G2_RETURNONHIT)) + { + // ok, we hit one, *and* we want to return instantly because the returnOnHit is set + // so indicate we've hit one, so other surfaces don't get hit and return + TS.hitOne = true; + return; + } } } @@ -1027,7 +1357,7 @@ void G2_TraceSurfaces(CTraceSurface &TS) } -void G2_TraceModels(CGhoul2Info_v &ghoul2, vec3_t rayStart, vec3_t rayEnd, CollisionRecord_t *collRecMap, int entNum, int traceFlags, int useLod) +void G2_TraceModels(CGhoul2Info_v &ghoul2, vec3_t rayStart, vec3_t rayEnd, CollisionRecord_t *collRecMap, int entNum, int traceFlags, int useLod, float fRadius) { int i, lod; model_t *currentModel; @@ -1075,10 +1405,24 @@ void G2_TraceModels(CGhoul2Info_v &ghoul2, vec3_t rayStart, vec3_t rayEnd, Colli { skin = NULL; } - +#ifdef G2_COLLISION_ENABLED + if (collRecMap) + { + lod = G2_DecideTraceLod(ghoul2[i],useLod, currentModel); + } + else + { + lod=useLod; + if (lod>=currentModel->numLods) + { + return; + } + } +#else lod = G2_DecideTraceLod(ghoul2[i],useLod, currentModel); +#endif - CTraceSurface TS(ghoul2[i].mSurfaceRoot, ghoul2[i].mSlist, currentModel, lod, rayStart, rayEnd, collRecMap, entNum, i, skin, cust_shader, ghoul2[i].mTransformedVertsArray, traceFlags); + CTraceSurface TS(ghoul2[i].mSurfaceRoot, ghoul2[i].mSlist, currentModel, lod, rayStart, rayEnd, collRecMap, entNum, i, skin, cust_shader, ghoul2[i].mTransformedVertsArray, traceFlags, fRadius); // start the surface recursion loop G2_TraceSurfaces(TS); diff --git a/CODE-mp/ghoul2/vssver.scc b/CODE-mp/ghoul2/vssver.scc index 6d99a3e..c64d314 100644 Binary files a/CODE-mp/ghoul2/vssver.scc and b/CODE-mp/ghoul2/vssver.scc differ diff --git a/CODE-mp/jk2mp.dsp b/CODE-mp/jk2mp.dsp index b67d927..6ebc9ab 100644 --- a/CODE-mp/jk2mp.dsp +++ b/CODE-mp/jk2mp.dsp @@ -57,7 +57,7 @@ BSC32=bscmake.exe LINK32=link.exe # ADD BASE LINK32 advapi32.lib winmm.lib wsock32.lib kernel32.lib user32.lib gdi32.lib ole32.lib /nologo /stack:0x800000 /subsystem:windows /map /debug /machine:I386 # SUBTRACT BASE LINK32 /incremental:yes /nodefaultlib -# ADD LINK32 advapi32.lib winmm.lib wsock32.lib kernel32.lib user32.lib gdi32.lib ole32.lib /nologo /stack:0x800000 /subsystem:windows /map:"Release/jk2mp.map" /debug /machine:I386 +# ADD LINK32 ALut.lib OpenAL32.lib advapi32.lib winmm.lib wsock32.lib kernel32.lib user32.lib gdi32.lib ole32.lib /nologo /stack:0x800000 /subsystem:windows /map:"Release/jk2mp.map" /debug /machine:I386 # SUBTRACT LINK32 /pdb:none !ELSEIF "$(CFG)" == "jk2mp - Win32 Debug JK2" @@ -86,7 +86,7 @@ BSC32=bscmake.exe LINK32=link.exe # ADD BASE LINK32 advapi32.lib winmm.lib wsock32.lib kernel32.lib user32.lib gdi32.lib ole32.lib /nologo /stack:0x800000 /subsystem:windows /profile /map /debug /machine:I386 # SUBTRACT BASE LINK32 /nodefaultlib -# ADD LINK32 ./debug/jk2/smrtheap.obj advapi32.lib winmm.lib wsock32.lib kernel32.lib user32.lib gdi32.lib ole32.lib /nologo /stack:0x800000 /subsystem:windows /map:"Debug/jk2mp.map" /debug /machine:I386 +# ADD LINK32 ./debug/jk2/smrtheap.obj ALut.lib OpenAL32.lib advapi32.lib winmm.lib wsock32.lib kernel32.lib user32.lib gdi32.lib ole32.lib /nologo /stack:0x800000 /subsystem:windows /map:"Debug/jk2mp.map" /debug /machine:I386 # SUBTRACT LINK32 /profile !ELSEIF "$(CFG)" == "jk2mp - Win32 Final JK2" @@ -116,7 +116,7 @@ BSC32=bscmake.exe LINK32=link.exe # ADD BASE LINK32 advapi32.lib winmm.lib wsock32.lib kernel32.lib user32.lib gdi32.lib ole32.lib /nologo /stack:0x800000 /subsystem:windows /map:"Release/jk2mp.map" /debug /machine:I386 /out:".\Release/jk2mp.exe" # SUBTRACT BASE LINK32 /pdb:none -# ADD LINK32 advapi32.lib winmm.lib wsock32.lib kernel32.lib user32.lib gdi32.lib ole32.lib /nologo /stack:0x800000 /subsystem:windows /map:"Final/jk2mp.map" /machine:I386 +# ADD LINK32 ALut.lib OpenAL32.lib advapi32.lib winmm.lib wsock32.lib kernel32.lib user32.lib gdi32.lib ole32.lib /nologo /stack:0x800000 /subsystem:windows /map:"Final/jk2mp.map" /machine:I386 # SUBTRACT LINK32 /pdb:none /debug !ENDIF @@ -159,6 +159,14 @@ SOURCE=.\ui\ui_public.h # PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;cnt;rtf;gif;jpg;jpeg;jpe" # Begin Source File +SOURCE=.\EaxMan.dll +# End Source File +# Begin Source File + +SOURCE=.\OpenAL32.dll +# End Source File +# Begin Source File + SOURCE=.\win32\qe3.ico # End Source File # Begin Source File @@ -176,6 +184,14 @@ SOURCE=.\win32\winquake.rc !ENDIF +# End Source File +# Begin Source File + +SOURCE=.\OpenAL32.lib +# End Source File +# Begin Source File + +SOURCE=.\ALut.lib # End Source File # End Group # Begin Group "Client" @@ -346,10 +362,6 @@ SOURCE=.\qcommon\cm_public.h # End Source File # Begin Source File -SOURCE=.\qcommon\cm_shader.cpp -# End Source File -# Begin Source File - SOURCE=.\qcommon\cm_test.cpp # End Source File # Begin Source File @@ -764,6 +776,46 @@ SOURCE=.\mp3code\upsf.c SOURCE=.\mp3code\wavep.c # End Source File # End Group +# Begin Group "EAX" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\client\eax\eax.h +# End Source File +# Begin Source File + +SOURCE=.\client\eax\EaxMan.h +# End Source File +# End Group +# Begin Group "OpenAL" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\client\OpenAL\al.h +# End Source File +# Begin Source File + +SOURCE=.\client\OpenAL\alc.h +# End Source File +# Begin Source File + +SOURCE=.\client\OpenAL\alctypes.h +# End Source File +# Begin Source File + +SOURCE=.\client\OpenAL\altypes.h +# End Source File +# Begin Source File + +SOURCE=.\client\OpenAL\alu.h +# End Source File +# Begin Source File + +SOURCE=.\client\OpenAL\alut.h +# End Source File +# End Group # Begin Source File SOURCE=.\client\snd_dma.cpp diff --git a/CODE-mp/jk2mp.dsw b/CODE-mp/jk2mp.dsw index 2b9f289..91b1b55 100644 --- a/CODE-mp/jk2mp.dsw +++ b/CODE-mp/jk2mp.dsw @@ -3,13 +3,13 @@ Microsoft Developer Studio Workspace File, Format Version 6.00 ############################################################################### -Project: "JK2cgame"=.\cgame\JK2_cgame.dsp - Package Owner=<4> +Project: "JK2cgame"=".\cgame\JK2_cgame.dsp" - Package Owner=<4> Package=<5> {{{ begin source code control - "$/General/code/cgame", UPCAAAAA - .\cgame + "$/General/code/cgame", UPCAAAAA + .\cgame end source code control }}} @@ -19,13 +19,13 @@ Package=<4> ############################################################################### -Project: "JK2game"=.\game\JK2_game.dsp - Package Owner=<4> +Project: "JK2game"=".\game\JK2_game.dsp" - Package Owner=<4> Package=<5> {{{ begin source code control - "$/General/code/game", VPCAAAAA - .\game + "$/General/code/game", VPCAAAAA + .\game end source code control }}} @@ -35,7 +35,23 @@ Package=<4> ############################################################################### -Project: "botlib"=.\botlib\botlib.dsp - Package Owner=<4> +Project: "WinDed"=".\WinDed.dsp" - Package Owner=<4> + +Package=<5> +{{{ + begin source code control + "$/General/code", EAAAAAAA + . + end source code control +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "botlib"=".\botlib\botlib.dsp" - Package Owner=<4> Package=<5> {{{ @@ -51,7 +67,7 @@ Package=<4> ############################################################################### -Project: "jk2mp"=.\jk2mp.dsp - Package Owner=<4> +Project: "jk2mp"=".\jk2mp.dsp" - Package Owner=<4> Package=<5> {{{ @@ -79,7 +95,7 @@ Package=<4> ############################################################################### -Project: "ui"=.\ui\ui.dsp - Package Owner=<4> +Project: "ui"=".\ui\ui.dsp" - Package Owner=<4> Package=<5> {{{ diff --git a/CODE-mp/jk2mp.opt b/CODE-mp/jk2mp.opt index d5cdbb3..fef5d21 100644 Binary files a/CODE-mp/jk2mp.opt and b/CODE-mp/jk2mp.opt differ diff --git a/CODE-mp/jk2mp.plg b/CODE-mp/jk2mp.plg index 40185c7..203aff2 100644 --- a/CODE-mp/jk2mp.plg +++ b/CODE-mp/jk2mp.plg @@ -3,696 +3,36 @@
 

Build Log

---------------------Configuration: ui - Win32 Release JK2-------------------- +--------------------Configuration: WinDed - Win32 Release--------------------

Command Lines

-Creating temporary file "C:\DOCUME~1\jmonroe\LOCALS~1\Temp\RSP67C.tmp" with contents -[ -/nologo /G6 /ML /W4 /GX /Zi /O2 /D "NDEBUG" /D "_USRDL" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "UI_EXPORTS" /D "MISSIONPACK" /D "_JK2" /Fp"../Release/ui/ui.pch" /YX /Fo"../Release/ui/" /Fd"../Release/ui/" /FD /c -"C:\projects\jk2\CODE-mp\ui\ui_main.c" -] -Creating command line "cl.exe @C:\DOCUME~1\jmonroe\LOCALS~1\Temp\RSP67C.tmp" -Creating temporary file "C:\DOCUME~1\jmonroe\LOCALS~1\Temp\RSP67D.tmp" with contents -[ -/nologo /base:"0x40000000" /dll /incremental:no /pdb:"../Release/uix86.pdb" /map:"../Release/ui/uix86.map" /debug /machine:I386 /def:".\ui.def" /out:"../Release/uix86.dll" /implib:"../Release/uix86.lib" -"\projects\jk2\CODE-mp\Release\ui\bg_misc.obj" -"\projects\jk2\CODE-mp\Release\ui\bg_weapons.obj" -"\projects\jk2\CODE-mp\Release\ui\q_math.obj" -"\projects\jk2\CODE-mp\Release\ui\q_shared.obj" -"\projects\jk2\CODE-mp\Release\ui\ui_atoms.obj" -"\projects\jk2\CODE-mp\Release\ui\ui_force.obj" -"\projects\jk2\CODE-mp\Release\ui\ui_gameinfo.obj" -"\projects\jk2\CODE-mp\Release\ui\ui_main.obj" -"\projects\jk2\CODE-mp\Release\ui\ui_shared.obj" -"\projects\jk2\CODE-mp\Release\ui\ui_syscalls.obj" -"\projects\jk2\CODE-mp\Release\ui\ui_util.obj" -] -Creating command line "link.exe @C:\DOCUME~1\jmonroe\LOCALS~1\Temp\RSP67D.tmp" -

Output Window

-Compiling... -ui_main.c -Linking... - Creating library ../Release/uix86.lib and object ../Release/uix86.exp + + + +

Results

+jk2Ded.exe - 0 error(s), 0 warning(s)

--------------------Configuration: jk2mp - Win32 Release JK2--------------------

Command Lines

-Creating temporary file "C:\DOCUME~1\jmonroe\LOCALS~1\Temp\RSP686.tmp" with contents -[ -/nologo /G6 /ML /W4 /GX /Zi /O2 /Ob0 /D "_WIN32" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "_JK2" /Fp".\Release\jk2/jk2mp.pch" /YX /Fo".\Release\jk2/" /Fd".\Release\jk2/" /FD /c -"C:\projects\jk2\CODE-mp\client\cl_console.cpp" -"C:\projects\jk2\CODE-mp\qcommon\common.cpp" -] -Creating command line "cl.exe @C:\DOCUME~1\jmonroe\LOCALS~1\Temp\RSP686.tmp" -Creating temporary file "C:\DOCUME~1\jmonroe\LOCALS~1\Temp\RSP687.tmp" with contents -[ -advapi32.lib winmm.lib wsock32.lib kernel32.lib user32.lib gdi32.lib ole32.lib /nologo /stack:0x800000 /subsystem:windows /incremental:no /pdb:".\Release/jk2mp.pdb" /map:"Release/jk2mp.map" /debug /machine:I386 /out:".\Release/jk2mp.exe" -".\Release\jk2\cl_cgame.obj" -".\Release\jk2\cl_cin.obj" -".\Release\jk2\cl_console.obj" -".\Release\jk2\cl_input.obj" -".\Release\jk2\cl_keys.obj" -".\Release\jk2\cl_main.obj" -".\Release\jk2\cl_net_chan.obj" -".\Release\jk2\cl_parse.obj" -".\Release\jk2\cl_scrn.obj" -".\Release\jk2\cl_ui.obj" -".\Release\jk2\FXExport.obj" -".\Release\jk2\FxPrimitives.obj" -".\Release\jk2\FxScheduler.obj" -".\Release\jk2\FxSystem.obj" -".\Release\jk2\FxTemplate.obj" -".\Release\jk2\FxUtil.obj" -".\Release\jk2\cm_load.obj" -".\Release\jk2\cm_patch.obj" -".\Release\jk2\cm_polylib.obj" -".\Release\jk2\cm_shader.obj" -".\Release\jk2\cm_test.obj" -".\Release\jk2\cm_trace.obj" -".\Release\jk2\cmd.obj" -".\Release\jk2\CNetProfile.obj" -".\Release\jk2\common.obj" -".\Release\jk2\cvar.obj" -".\Release\jk2\files.obj" -".\Release\jk2\GenericParser2.obj" -".\Release\jk2\hstring.obj" -".\Release\jk2\huffman.obj" -".\Release\jk2\md4.obj" -".\Release\jk2\msg.obj" -".\Release\jk2\net_chan.obj" -".\Release\jk2\q_math.obj" -".\Release\jk2\q_shared.obj" -".\Release\jk2\RoffSystem.obj" -".\Release\jk2\strip.obj" -".\Release\jk2\unzip.obj" -".\Release\jk2\vm.obj" -".\Release\jk2\vm_interpreted.obj" -".\Release\jk2\vm_x86.obj" -".\Release\jk2\win_input.obj" -".\Release\jk2\win_main.obj" -".\Release\jk2\win_net.obj" -".\Release\jk2\win_shared.obj" -".\Release\jk2\win_snd.obj" -".\Release\jk2\win_syscon.obj" -".\Release\jk2\win_wndproc.obj" -".\Release\jk2\sv_bot.obj" -".\Release\jk2\sv_ccmds.obj" -".\Release\jk2\sv_client.obj" -".\Release\jk2\sv_game.obj" -".\Release\jk2\sv_init.obj" -".\Release\jk2\sv_main.obj" -".\Release\jk2\sv_net_chan.obj" -".\Release\jk2\sv_snapshot.obj" -".\Release\jk2\sv_world.obj" -".\Release\jk2\cdct.obj" -".\Release\jk2\csbt.obj" -".\Release\jk2\csbtb.obj" -".\Release\jk2\csbtl3.obj" -".\Release\jk2\cup.obj" -".\Release\jk2\cupini.obj" -".\Release\jk2\cupl1.obj" -".\Release\jk2\cupl3.obj" -".\Release\jk2\cwin.obj" -".\Release\jk2\cwinb.obj" -".\Release\jk2\cwinm.obj" -".\Release\jk2\hwin.obj" -".\Release\jk2\l3dq.obj" -".\Release\jk2\l3init.obj" -".\Release\jk2\mdct.obj" -".\Release\jk2\mhead.obj" -".\Release\jk2\msis.obj" -".\Release\jk2\towave.obj" -".\Release\jk2\uph.obj" -".\Release\jk2\upsf.obj" -".\Release\jk2\wavep.obj" -".\Release\jk2\snd_dma.obj" -".\Release\jk2\snd_mem.obj" -".\Release\jk2\snd_mix.obj" -".\Release\jk2\snd_mp3.obj" -".\Release\jk2\jcapimin.obj" -".\Release\jk2\jccoefct.obj" -".\Release\jk2\jccolor.obj" -".\Release\jk2\jcdctmgr.obj" -".\Release\jk2\jchuff.obj" -".\Release\jk2\jcinit.obj" -".\Release\jk2\jcmainct.obj" -".\Release\jk2\jcmarker.obj" -".\Release\jk2\jcmaster.obj" -".\Release\jk2\jcomapi.obj" -".\Release\jk2\jcparam.obj" -".\Release\jk2\jcphuff.obj" -".\Release\jk2\jcprepct.obj" -".\Release\jk2\jcsample.obj" -".\Release\jk2\jctrans.obj" -".\Release\jk2\jdapimin.obj" -".\Release\jk2\jdapistd.obj" -".\Release\jk2\jdatadst.obj" -".\Release\jk2\jdatasrc.obj" -".\Release\jk2\jdcoefct.obj" -".\Release\jk2\jdcolor.obj" -".\Release\jk2\jddctmgr.obj" -".\Release\jk2\jdhuff.obj" -".\Release\jk2\jdinput.obj" -".\Release\jk2\jdmainct.obj" -".\Release\jk2\jdmarker.obj" -".\Release\jk2\jdmaster.obj" -".\Release\jk2\jdpostct.obj" -".\Release\jk2\jdsample.obj" -".\Release\jk2\jdtrans.obj" -".\Release\jk2\jerror.obj" -".\Release\jk2\jfdctflt.obj" -".\Release\jk2\jidctflt.obj" -".\Release\jk2\jmemmgr.obj" -".\Release\jk2\jmemnobs.obj" -".\Release\jk2\jutils.obj" -".\Release\jk2\png.obj" -".\Release\jk2\matcomp.obj" -".\Release\jk2\tr_animation.obj" -".\Release\jk2\tr_backend.obj" -".\Release\jk2\tr_bsp.obj" -".\Release\jk2\tr_cmds.obj" -".\Release\jk2\tr_curve.obj" -".\Release\jk2\tr_flares.obj" -".\Release\jk2\tr_font.obj" -".\Release\jk2\tr_ghoul2.obj" -".\Release\jk2\tr_image.obj" -".\Release\jk2\tr_init.obj" -".\Release\jk2\tr_light.obj" -".\Release\jk2\tr_main.obj" -".\Release\jk2\tr_marks.obj" -".\Release\jk2\tr_mesh.obj" -".\Release\jk2\tr_model.obj" -".\Release\jk2\tr_noise.obj" -".\Release\jk2\tr_quicksprite.obj" -".\Release\jk2\tr_scene.obj" -".\Release\jk2\tr_shade.obj" -".\Release\jk2\tr_shade_calc.obj" -".\Release\jk2\tr_shader.obj" -".\Release\jk2\tr_shadows.obj" -".\Release\jk2\tr_sky.obj" -".\Release\jk2\tr_surface.obj" -".\Release\jk2\tr_surfacesprites.obj" -".\Release\jk2\tr_world.obj" -".\Release\jk2\tr_WorldEffects.obj" -".\Release\jk2\win_gamma.obj" -".\Release\jk2\win_glimp.obj" -".\Release\jk2\win_qgl.obj" -".\Release\jk2\G2_API.obj" -".\Release\jk2\G2_bolts.obj" -".\Release\jk2\G2_bones.obj" -".\Release\jk2\G2_misc.obj" -".\Release\jk2\G2_surfaces.obj" -".\Release\jk2\adler32.obj" -".\Release\jk2\crc32.obj" -".\Release\jk2\deflate.obj" -".\Release\jk2\infblock.obj" -".\Release\jk2\infcodes.obj" -".\Release\jk2\inffast.obj" -".\Release\jk2\inflate.obj" -".\Release\jk2\inftrees.obj" -".\Release\jk2\infutil.obj" -".\Release\jk2\trees.obj" -".\Release\jk2\zutil.obj" -".\Release\jk2\buffer.obj" -".\Release\jk2\cpp_interface.obj" -".\Release\jk2\sockets.obj" -".\Release\jk2\winquake.res" -".\Release\botlib.lib" -".\Release\uix86.lib" -".\Release\cgamex86.lib" -".\Release\jk2mpgamex86.lib" -] -Creating command line "link.exe @C:\DOCUME~1\jmonroe\LOCALS~1\Temp\RSP687.tmp" -

Output Window

-Compiling... -cl_console.cpp -common.cpp -Linking...

Results

jk2mp.exe - 0 error(s), 0 warning(s)

---------------------Configuration: ui - Win32 Debug JK2-------------------- -

-

Command Lines

-Creating temporary file "C:\DOCUME~1\jmonroe\LOCALS~1\Temp\RSP68C.tmp" with contents -[ -/nologo /G6 /MTd /W3 /Gm /GX /ZI /Od /D "_DEBUG" /D "_USRDLL" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "UI_EXPORTS" /D "MISSIONPACK" /D "_JK2" /FR"../Debug/ui/" /Fp"../Debug/ui/ui.pch" /YX /Fo"../Debug/ui/" /Fd"../Debug/ui/" /FD /GZ /c -"C:\projects\jk2\CODE-mp\ui\ui_main.c" -] -Creating command line "cl.exe @C:\DOCUME~1\jmonroe\LOCALS~1\Temp\RSP68C.tmp" -Creating temporary file "C:\DOCUME~1\jmonroe\LOCALS~1\Temp\RSP68D.tmp" with contents -[ -/nologo /base:"0x40000000" /dll /incremental:yes /pdb:"../Debug/uix86.pdb" /map:"../Debug/ui/uix86.map" /debug /machine:I386 /def:".\ui.def" /out:"../Debug/uix86.dll" /implib:"../Debug/uix86.lib" /pdbtype:sept -"\projects\jk2\CODE-mp\Debug\ui\bg_misc.obj" -"\projects\jk2\CODE-mp\Debug\ui\bg_weapons.obj" -"\projects\jk2\CODE-mp\Debug\ui\q_math.obj" -"\projects\jk2\CODE-mp\Debug\ui\q_shared.obj" -"\projects\jk2\CODE-mp\Debug\ui\ui_atoms.obj" -"\projects\jk2\CODE-mp\Debug\ui\ui_force.obj" -"\projects\jk2\CODE-mp\Debug\ui\ui_gameinfo.obj" -"\projects\jk2\CODE-mp\Debug\ui\ui_main.obj" -"\projects\jk2\CODE-mp\Debug\ui\ui_shared.obj" -"\projects\jk2\CODE-mp\Debug\ui\ui_syscalls.obj" -"\projects\jk2\CODE-mp\Debug\ui\ui_util.obj" -] -Creating command line "link.exe @C:\DOCUME~1\jmonroe\LOCALS~1\Temp\RSP68D.tmp" -

Output Window

-Compiling... -ui_main.c -Linking... -

--------------------Configuration: jk2mp - Win32 Debug JK2--------------------

Command Lines

-Creating temporary file "C:\DOCUME~1\jmonroe\LOCALS~1\Temp\RSP68F.tmp" with contents -[ -/nologo /G6 /MLd /W3 /GX /ZI /Od /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "_JK2" /D "MEM_DEBUG" /Fr".\Debug\jk2/" /Fo".\Debug\jk2/" /Fd".\Debug\jk2/" /FD /GZ /c -"C:\projects\jk2\CODE-mp\client\cl_console.cpp" -"C:\projects\jk2\CODE-mp\qcommon\common.cpp" -] -Creating command line "cl.exe @C:\DOCUME~1\jmonroe\LOCALS~1\Temp\RSP68F.tmp" -Creating temporary file "C:\DOCUME~1\jmonroe\LOCALS~1\Temp\RSP690.tmp" with contents -[ -./debug/jk2/smrtheap.obj advapi32.lib winmm.lib wsock32.lib kernel32.lib user32.lib gdi32.lib ole32.lib /nologo /stack:0x800000 /subsystem:windows /incremental:yes /pdb:".\Debug/jk2mp.pdb" /map:"Debug/jk2mp.map" /debug /machine:I386 /out:".\Debug/jk2mp.exe" -".\Debug\jk2\0_SH_Leak.obj" -".\Debug\jk2\cl_cgame.obj" -".\Debug\jk2\cl_cin.obj" -".\Debug\jk2\cl_console.obj" -".\Debug\jk2\cl_input.obj" -".\Debug\jk2\cl_keys.obj" -".\Debug\jk2\cl_main.obj" -".\Debug\jk2\cl_net_chan.obj" -".\Debug\jk2\cl_parse.obj" -".\Debug\jk2\cl_scrn.obj" -".\Debug\jk2\cl_ui.obj" -".\Debug\jk2\FXExport.obj" -".\Debug\jk2\FxPrimitives.obj" -".\Debug\jk2\FxScheduler.obj" -".\Debug\jk2\FxSystem.obj" -".\Debug\jk2\FxTemplate.obj" -".\Debug\jk2\FxUtil.obj" -".\Debug\jk2\cm_load.obj" -".\Debug\jk2\cm_patch.obj" -".\Debug\jk2\cm_polylib.obj" -".\Debug\jk2\cm_shader.obj" -".\Debug\jk2\cm_test.obj" -".\Debug\jk2\cm_trace.obj" -".\Debug\jk2\cmd.obj" -".\Debug\jk2\CNetProfile.obj" -".\Debug\jk2\common.obj" -".\Debug\jk2\cvar.obj" -".\Debug\jk2\files.obj" -".\Debug\jk2\GenericParser2.obj" -".\Debug\jk2\hstring.obj" -".\Debug\jk2\huffman.obj" -".\Debug\jk2\md4.obj" -".\Debug\jk2\msg.obj" -".\Debug\jk2\net_chan.obj" -".\Debug\jk2\q_math.obj" -".\Debug\jk2\q_shared.obj" -".\Debug\jk2\RoffSystem.obj" -".\Debug\jk2\strip.obj" -".\Debug\jk2\unzip.obj" -".\Debug\jk2\vm.obj" -".\Debug\jk2\vm_interpreted.obj" -".\Debug\jk2\vm_x86.obj" -".\Debug\jk2\win_input.obj" -".\Debug\jk2\win_main.obj" -".\Debug\jk2\win_net.obj" -".\Debug\jk2\win_shared.obj" -".\Debug\jk2\win_snd.obj" -".\Debug\jk2\win_syscon.obj" -".\Debug\jk2\win_wndproc.obj" -".\Debug\jk2\sv_bot.obj" -".\Debug\jk2\sv_ccmds.obj" -".\Debug\jk2\sv_client.obj" -".\Debug\jk2\sv_game.obj" -".\Debug\jk2\sv_init.obj" -".\Debug\jk2\sv_main.obj" -".\Debug\jk2\sv_net_chan.obj" -".\Debug\jk2\sv_snapshot.obj" -".\Debug\jk2\sv_world.obj" -".\Debug\jk2\cdct.obj" -".\Debug\jk2\csbt.obj" -".\Debug\jk2\csbtb.obj" -".\Debug\jk2\csbtl3.obj" -".\Debug\jk2\cup.obj" -".\Debug\jk2\cupini.obj" -".\Debug\jk2\cupl1.obj" -".\Debug\jk2\cupl3.obj" -".\Debug\jk2\cwin.obj" -".\Debug\jk2\cwinb.obj" -".\Debug\jk2\cwinm.obj" -".\Debug\jk2\hwin.obj" -".\Debug\jk2\l3dq.obj" -".\Debug\jk2\l3init.obj" -".\Debug\jk2\mdct.obj" -".\Debug\jk2\mhead.obj" -".\Debug\jk2\msis.obj" -".\Debug\jk2\towave.obj" -".\Debug\jk2\uph.obj" -".\Debug\jk2\upsf.obj" -".\Debug\jk2\wavep.obj" -".\Debug\jk2\snd_dma.obj" -".\Debug\jk2\snd_mem.obj" -".\Debug\jk2\snd_mix.obj" -".\Debug\jk2\snd_mp3.obj" -".\Debug\jk2\jcapimin.obj" -".\Debug\jk2\jccoefct.obj" -".\Debug\jk2\jccolor.obj" -".\Debug\jk2\jcdctmgr.obj" -".\Debug\jk2\jchuff.obj" -".\Debug\jk2\jcinit.obj" -".\Debug\jk2\jcmainct.obj" -".\Debug\jk2\jcmarker.obj" -".\Debug\jk2\jcmaster.obj" -".\Debug\jk2\jcomapi.obj" -".\Debug\jk2\jcparam.obj" -".\Debug\jk2\jcphuff.obj" -".\Debug\jk2\jcprepct.obj" -".\Debug\jk2\jcsample.obj" -".\Debug\jk2\jctrans.obj" -".\Debug\jk2\jdapimin.obj" -".\Debug\jk2\jdapistd.obj" -".\Debug\jk2\jdatadst.obj" -".\Debug\jk2\jdatasrc.obj" -".\Debug\jk2\jdcoefct.obj" -".\Debug\jk2\jdcolor.obj" -".\Debug\jk2\jddctmgr.obj" -".\Debug\jk2\jdhuff.obj" -".\Debug\jk2\jdinput.obj" -".\Debug\jk2\jdmainct.obj" -".\Debug\jk2\jdmarker.obj" -".\Debug\jk2\jdmaster.obj" -".\Debug\jk2\jdpostct.obj" -".\Debug\jk2\jdsample.obj" -".\Debug\jk2\jdtrans.obj" -".\Debug\jk2\jerror.obj" -".\Debug\jk2\jfdctflt.obj" -".\Debug\jk2\jidctflt.obj" -".\Debug\jk2\jmemmgr.obj" -".\Debug\jk2\jmemnobs.obj" -".\Debug\jk2\jutils.obj" -".\Debug\jk2\png.obj" -".\Debug\jk2\matcomp.obj" -".\Debug\jk2\tr_animation.obj" -".\Debug\jk2\tr_backend.obj" -".\Debug\jk2\tr_bsp.obj" -".\Debug\jk2\tr_cmds.obj" -".\Debug\jk2\tr_curve.obj" -".\Debug\jk2\tr_flares.obj" -".\Debug\jk2\tr_font.obj" -".\Debug\jk2\tr_ghoul2.obj" -".\Debug\jk2\tr_image.obj" -".\Debug\jk2\tr_init.obj" -".\Debug\jk2\tr_light.obj" -".\Debug\jk2\tr_main.obj" -".\Debug\jk2\tr_marks.obj" -".\Debug\jk2\tr_mesh.obj" -".\Debug\jk2\tr_model.obj" -".\Debug\jk2\tr_noise.obj" -".\Debug\jk2\tr_quicksprite.obj" -".\Debug\jk2\tr_scene.obj" -".\Debug\jk2\tr_shade.obj" -".\Debug\jk2\tr_shade_calc.obj" -".\Debug\jk2\tr_shader.obj" -".\Debug\jk2\tr_shadows.obj" -".\Debug\jk2\tr_sky.obj" -".\Debug\jk2\tr_surface.obj" -".\Debug\jk2\tr_surfacesprites.obj" -".\Debug\jk2\tr_world.obj" -".\Debug\jk2\tr_WorldEffects.obj" -".\Debug\jk2\win_gamma.obj" -".\Debug\jk2\win_glimp.obj" -".\Debug\jk2\win_qgl.obj" -".\Debug\jk2\G2_API.obj" -".\Debug\jk2\G2_bolts.obj" -".\Debug\jk2\G2_bones.obj" -".\Debug\jk2\G2_misc.obj" -".\Debug\jk2\G2_surfaces.obj" -".\Debug\jk2\adler32.obj" -".\Debug\jk2\crc32.obj" -".\Debug\jk2\deflate.obj" -".\Debug\jk2\infblock.obj" -".\Debug\jk2\infcodes.obj" -".\Debug\jk2\inffast.obj" -".\Debug\jk2\inflate.obj" -".\Debug\jk2\inftrees.obj" -".\Debug\jk2\infutil.obj" -".\Debug\jk2\trees.obj" -".\Debug\jk2\zutil.obj" -".\Debug\jk2\buffer.obj" -".\Debug\jk2\cpp_interface.obj" -".\Debug\jk2\sockets.obj" -".\Debug\jk2\SMRTHEAP.OBJ" -".\win32\winquake.res" -".\smartheap\HAW32M.LIB" -".\Debug\botlib.lib" -".\Debug\uix86.lib" -".\Debug\cgamex86.lib" -".\Debug\jk2mpgamex86.lib" -] -Creating command line "link.exe @C:\DOCUME~1\jmonroe\LOCALS~1\Temp\RSP690.tmp" -

Output Window

-Compiling... -cl_console.cpp -common.cpp -Generating Code... -Linking...

Results

jk2mp.exe - 0 error(s), 0 warning(s)

---------------------Configuration: ui - Win32 Final JK2-------------------- -

-

Command Lines

-Creating temporary file "C:\DOCUME~1\jmonroe\LOCALS~1\Temp\RSP692.tmp" with contents -[ -/nologo /G6 /ML /W4 /GX /O2 /D "NDEBUG" /D "_USRDL" /D "_WINDOWS" /D "_MBCS" /D "UI_EXPORTS" /D "MISSIONPACK" /D "WIN32" /D "_JK2" /D "FINAL_BUILD" /Fp"../Final/ui/ui.pch" /YX /Fo"../Final/ui/" /Fd"../Final/ui/" /FD /c -"C:\projects\jk2\CODE-mp\ui\ui_main.c" -] -Creating command line "cl.exe @C:\DOCUME~1\jmonroe\LOCALS~1\Temp\RSP692.tmp" -Creating temporary file "C:\DOCUME~1\jmonroe\LOCALS~1\Temp\RSP693.tmp" with contents -[ -/nologo /base:"0x40000000" /dll /incremental:no /pdb:"../Final/uix86.pdb" /map:"../Final/ui/uix86.map" /debug /machine:I386 /def:".\ui.def" /out:"../Final/uix86.dll" /implib:"../Final/uix86.lib" -"\projects\jk2\CODE-mp\Final\ui\bg_misc.obj" -"\projects\jk2\CODE-mp\Final\ui\bg_weapons.obj" -"\projects\jk2\CODE-mp\Final\ui\q_math.obj" -"\projects\jk2\CODE-mp\Final\ui\q_shared.obj" -"\projects\jk2\CODE-mp\Final\ui\ui_atoms.obj" -"\projects\jk2\CODE-mp\Final\ui\ui_force.obj" -"\projects\jk2\CODE-mp\Final\ui\ui_gameinfo.obj" -"\projects\jk2\CODE-mp\Final\ui\ui_main.obj" -"\projects\jk2\CODE-mp\Final\ui\ui_shared.obj" -"\projects\jk2\CODE-mp\Final\ui\ui_syscalls.obj" -"\projects\jk2\CODE-mp\Final\ui\ui_util.obj" -] -Creating command line "link.exe @C:\DOCUME~1\jmonroe\LOCALS~1\Temp\RSP693.tmp" -

Output Window

-Compiling... -ui_main.c -Linking... - Creating library ../Final/uix86.lib and object ../Final/uix86.exp -

--------------------Configuration: jk2mp - Win32 Final JK2--------------------

Command Lines

-Creating temporary file "C:\DOCUME~1\jmonroe\LOCALS~1\Temp\RSP698.tmp" with contents -[ -/nologo /G6 /ML /W4 /GX /O2 /Ob0 /D "_WIN32" /D "NDEBUG" /D "_WINDOWS" /D "WIN32" /D "_JK2" /D "FINAL_BUILD" /Fp".\Final\jk2/jk2mp.pch" /YX /Fo".\Final\jk2/" /Fd".\Final\jk2/" /FD /c -"C:\projects\jk2\CODE-mp\client\cl_console.cpp" -"C:\projects\jk2\CODE-mp\qcommon\common.cpp" -] -Creating command line "cl.exe @C:\DOCUME~1\jmonroe\LOCALS~1\Temp\RSP698.tmp" -Creating temporary file "C:\DOCUME~1\jmonroe\LOCALS~1\Temp\RSP699.tmp" with contents -[ -advapi32.lib winmm.lib wsock32.lib kernel32.lib user32.lib gdi32.lib ole32.lib /nologo /stack:0x800000 /subsystem:windows /incremental:no /pdb:".\Final/jk2mp.pdb" /map:"Final/jk2mp.map" /machine:I386 /out:".\Final/jk2mp.exe" -".\Final\jk2\cl_cgame.obj" -".\Final\jk2\cl_cin.obj" -".\Final\jk2\cl_console.obj" -".\Final\jk2\cl_input.obj" -".\Final\jk2\cl_keys.obj" -".\Final\jk2\cl_main.obj" -".\Final\jk2\cl_net_chan.obj" -".\Final\jk2\cl_parse.obj" -".\Final\jk2\cl_scrn.obj" -".\Final\jk2\cl_ui.obj" -".\Final\jk2\FXExport.obj" -".\Final\jk2\FxPrimitives.obj" -".\Final\jk2\FxScheduler.obj" -".\Final\jk2\FxSystem.obj" -".\Final\jk2\FxTemplate.obj" -".\Final\jk2\FxUtil.obj" -".\Final\jk2\cm_load.obj" -".\Final\jk2\cm_patch.obj" -".\Final\jk2\cm_polylib.obj" -".\Final\jk2\cm_shader.obj" -".\Final\jk2\cm_test.obj" -".\Final\jk2\cm_trace.obj" -".\Final\jk2\cmd.obj" -".\Final\jk2\CNetProfile.obj" -".\Final\jk2\common.obj" -".\Final\jk2\cvar.obj" -".\Final\jk2\files.obj" -".\Final\jk2\GenericParser2.obj" -".\Final\jk2\hstring.obj" -".\Final\jk2\huffman.obj" -".\Final\jk2\md4.obj" -".\Final\jk2\msg.obj" -".\Final\jk2\net_chan.obj" -".\Final\jk2\q_math.obj" -".\Final\jk2\q_shared.obj" -".\Final\jk2\RoffSystem.obj" -".\Final\jk2\strip.obj" -".\Final\jk2\unzip.obj" -".\Final\jk2\vm.obj" -".\Final\jk2\vm_interpreted.obj" -".\Final\jk2\vm_x86.obj" -".\Final\jk2\win_input.obj" -".\Final\jk2\win_main.obj" -".\Final\jk2\win_net.obj" -".\Final\jk2\win_shared.obj" -".\Final\jk2\win_snd.obj" -".\Final\jk2\win_syscon.obj" -".\Final\jk2\win_wndproc.obj" -".\Final\jk2\sv_bot.obj" -".\Final\jk2\sv_ccmds.obj" -".\Final\jk2\sv_client.obj" -".\Final\jk2\sv_game.obj" -".\Final\jk2\sv_init.obj" -".\Final\jk2\sv_main.obj" -".\Final\jk2\sv_net_chan.obj" -".\Final\jk2\sv_snapshot.obj" -".\Final\jk2\sv_world.obj" -".\Final\jk2\cdct.obj" -".\Final\jk2\csbt.obj" -".\Final\jk2\csbtb.obj" -".\Final\jk2\csbtl3.obj" -".\Final\jk2\cup.obj" -".\Final\jk2\cupini.obj" -".\Final\jk2\cupl1.obj" -".\Final\jk2\cupl3.obj" -".\Final\jk2\cwin.obj" -".\Final\jk2\cwinb.obj" -".\Final\jk2\cwinm.obj" -".\Final\jk2\hwin.obj" -".\Final\jk2\l3dq.obj" -".\Final\jk2\l3init.obj" -".\Final\jk2\mdct.obj" -".\Final\jk2\mhead.obj" -".\Final\jk2\msis.obj" -".\Final\jk2\towave.obj" -".\Final\jk2\uph.obj" -".\Final\jk2\upsf.obj" -".\Final\jk2\wavep.obj" -".\Final\jk2\snd_dma.obj" -".\Final\jk2\snd_mem.obj" -".\Final\jk2\snd_mix.obj" -".\Final\jk2\snd_mp3.obj" -".\Final\jk2\jcapimin.obj" -".\Final\jk2\jccoefct.obj" -".\Final\jk2\jccolor.obj" -".\Final\jk2\jcdctmgr.obj" -".\Final\jk2\jchuff.obj" -".\Final\jk2\jcinit.obj" -".\Final\jk2\jcmainct.obj" -".\Final\jk2\jcmarker.obj" -".\Final\jk2\jcmaster.obj" -".\Final\jk2\jcomapi.obj" -".\Final\jk2\jcparam.obj" -".\Final\jk2\jcphuff.obj" -".\Final\jk2\jcprepct.obj" -".\Final\jk2\jcsample.obj" -".\Final\jk2\jctrans.obj" -".\Final\jk2\jdapimin.obj" -".\Final\jk2\jdapistd.obj" -".\Final\jk2\jdatadst.obj" -".\Final\jk2\jdatasrc.obj" -".\Final\jk2\jdcoefct.obj" -".\Final\jk2\jdcolor.obj" -".\Final\jk2\jddctmgr.obj" -".\Final\jk2\jdhuff.obj" -".\Final\jk2\jdinput.obj" -".\Final\jk2\jdmainct.obj" -".\Final\jk2\jdmarker.obj" -".\Final\jk2\jdmaster.obj" -".\Final\jk2\jdpostct.obj" -".\Final\jk2\jdsample.obj" -".\Final\jk2\jdtrans.obj" -".\Final\jk2\jerror.obj" -".\Final\jk2\jfdctflt.obj" -".\Final\jk2\jidctflt.obj" -".\Final\jk2\jmemmgr.obj" -".\Final\jk2\jmemnobs.obj" -".\Final\jk2\jutils.obj" -".\Final\jk2\png.obj" -".\Final\jk2\matcomp.obj" -".\Final\jk2\tr_animation.obj" -".\Final\jk2\tr_backend.obj" -".\Final\jk2\tr_bsp.obj" -".\Final\jk2\tr_cmds.obj" -".\Final\jk2\tr_curve.obj" -".\Final\jk2\tr_flares.obj" -".\Final\jk2\tr_font.obj" -".\Final\jk2\tr_ghoul2.obj" -".\Final\jk2\tr_image.obj" -".\Final\jk2\tr_init.obj" -".\Final\jk2\tr_light.obj" -".\Final\jk2\tr_main.obj" -".\Final\jk2\tr_marks.obj" -".\Final\jk2\tr_mesh.obj" -".\Final\jk2\tr_model.obj" -".\Final\jk2\tr_noise.obj" -".\Final\jk2\tr_quicksprite.obj" -".\Final\jk2\tr_scene.obj" -".\Final\jk2\tr_shade.obj" -".\Final\jk2\tr_shade_calc.obj" -".\Final\jk2\tr_shader.obj" -".\Final\jk2\tr_shadows.obj" -".\Final\jk2\tr_sky.obj" -".\Final\jk2\tr_surface.obj" -".\Final\jk2\tr_surfacesprites.obj" -".\Final\jk2\tr_world.obj" -".\Final\jk2\tr_WorldEffects.obj" -".\Final\jk2\win_gamma.obj" -".\Final\jk2\win_glimp.obj" -".\Final\jk2\win_qgl.obj" -".\Final\jk2\G2_API.obj" -".\Final\jk2\G2_bolts.obj" -".\Final\jk2\G2_bones.obj" -".\Final\jk2\G2_misc.obj" -".\Final\jk2\G2_surfaces.obj" -".\Final\jk2\adler32.obj" -".\Final\jk2\crc32.obj" -".\Final\jk2\deflate.obj" -".\Final\jk2\infblock.obj" -".\Final\jk2\infcodes.obj" -".\Final\jk2\inffast.obj" -".\Final\jk2\inflate.obj" -".\Final\jk2\inftrees.obj" -".\Final\jk2\infutil.obj" -".\Final\jk2\trees.obj" -".\Final\jk2\zutil.obj" -".\Final\jk2\buffer.obj" -".\Final\jk2\cpp_interface.obj" -".\Final\jk2\sockets.obj" -".\Final\jk2\winquake.res" -".\Final\botlib.lib" -".\Final\uix86.lib" -".\Final\cgamex86.lib" -".\Final\jk2mpgamex86.lib" -] -Creating command line "link.exe @C:\DOCUME~1\jmonroe\LOCALS~1\Temp\RSP699.tmp" -

Output Window

-Compiling... -cl_console.cpp -common.cpp -Linking... diff --git a/CODE-mp/mssccprj.scc b/CODE-mp/mssccprj.scc index 3ec70d1..d2668fc 100644 --- a/CODE-mp/mssccprj.scc +++ b/CODE-mp/mssccprj.scc @@ -1,5 +1,9 @@ SCC = This is a Source Code Control file +[WinDed.dsp] +SCC_Aux_Path = "\\ravend\vss_projects\jk2sof2MP" +SCC_Project_Name = "$/General/code", EAAAAAAA + [jk2mp.dsp] SCC_Aux_Path = "\\ravend\vss_projects\jk2sof2MP" SCC_Project_Name = "$/General/code", EAAAAAAA diff --git a/CODE-mp/null/vssver.scc b/CODE-mp/null/vssver.scc index 8be47c1..25acc4d 100644 Binary files a/CODE-mp/null/vssver.scc and b/CODE-mp/null/vssver.scc differ diff --git a/CODE-mp/null/win_main.cpp b/CODE-mp/null/win_main.cpp index 78e357a..2fd9321 100644 --- a/CODE-mp/null/win_main.cpp +++ b/CODE-mp/null/win_main.cpp @@ -22,85 +22,20 @@ static char sys_cmdline[MAX_STRING_CHARS]; clientStatic_t cls; -// enable this for executable checksumming -#ifdef FINAL_BUILD -#define SPANK_MONKEYS -#endif static int sys_monkeySpank; static int sys_checksum; -static unsigned busyCount = 0; -static bool otherTasksRunning = false; -unsigned otherTaskTime = 0; - -#pragma optimize("", off) - -void busyFunction(void) -{ - float a = MEM_THRESHOLD; - float b = 9343; - short c = 4; - - while((int)b > (float)(b-1)) - { - a = a + b / c; - busyCount++; - } -} - -void CheckProcessTime(void) -{ - HANDLE threadHandle; - int threadId; - FILETIME creationTime; // thread creation time - FILETIME exitTime; // thread exit time - FILETIME kernelTime; // thread kernel-mode time - FILETIME userTime; // thread user-mode time -// char temp[1024]; - - busyCount = 0; - threadHandle = CreateThread( - NULL, // LPSECURITY_ATTRIBUTES lpsa, - 0, // DWORD cbStack, - (LPTHREAD_START_ROUTINE)busyFunction, // LPTHREAD_START_ROUTINE lpStartAddr, - 0, // LPVOID lpvThreadParm, - CREATE_SUSPENDED, // DWORD fdwCreate, - (unsigned long *)&threadId ); - - SetThreadPriority(threadHandle, THREAD_PRIORITY_IDLE); - ResumeThread(threadHandle); - while(busyCount < 10) - { - Sleep(100); - } - Sleep(1000); - - TerminateThread(threadHandle, 0); - GetThreadTimes(threadHandle, &creationTime, &exitTime, &kernelTime, &userTime); - CloseHandle(threadHandle); - -// sprintf(temp, "Time = %u\n", userTime.dwLowDateTime); -// OutputDebugString(temp); - - otherTaskTime = userTime.dwLowDateTime; - if (userTime.dwLowDateTime < 7500000) - { - otherTasksRunning = true; -// OutputDebugString("WARNING: possibly running on a system with another task\n"); - } -} - -#pragma optimize("", on) - - void *Sys_GetBotAIAPI (void *parms ) { return NULL; } void Conbuf_AppendText( const char *pMsg ) { - printf(pMsg); + char msg[4096]; + strcpy(msg, pMsg); + printf(Q_CleanStr(msg)); + printf("\n"); } /* @@ -236,136 +171,6 @@ int Sys_MonkeyShouldBeSpanked( void ) { return sys_monkeySpank; } -/* -================== -Sys_CodeInMemoryChecksum -================== -*/ -#define MakePtr( cast, ptr, addValue ) (cast)( (DWORD)(ptr) + (addValue) ) - -int Sys_CodeInMemoryChecksum( void *codeBase ) { - PIMAGE_DOS_HEADER dosHeader; - PIMAGE_NT_HEADERS pNTHeader; - PIMAGE_SECTION_HEADER section; - - dosHeader = (PIMAGE_DOS_HEADER)codeBase; - pNTHeader = MakePtr( PIMAGE_NT_HEADERS, dosHeader, dosHeader->e_lfanew ); - - // First, verify that the e_lfanew field gave us a reasonable - // pointer, then verify the PE signature. - if ( IsBadReadPtr(pNTHeader, sizeof(IMAGE_NT_HEADERS)) || - pNTHeader->Signature != IMAGE_NT_SIGNATURE ) - { - //printf("Unhandled EXE type, or invalid .EXE\n"); - return 0; - } - // first section oughta be the code section - section = (PIMAGE_SECTION_HEADER)(pNTHeader+1); - /* - // the name of the code section should be .text - if ( Q_stricmp( section->Name, ".text" ) ) { - return 0; - } - */ - - return Com_BlockChecksum( ((byte *) codeBase) + section->VirtualAddress, section->SizeOfRawData ); -} - -/* -================== -Sys_ChecksumExe -================== -*/ - -// make sure this string is unique in the executable -// 01234567890123 -byte *exeChecksumId = (unsigned char *)"q3monkeyid\0\0\0\0"; - -void Sys_ChecksumExe( void *codeBase ) { - TCHAR szPathOrig[_MAX_PATH], szPathClone[_MAX_PATH]; - STARTUPINFO si; - TCHAR szCmdLine[512]; - HANDLE hfile, hProcessOrig; - PROCESS_INFORMATION pi; - int l, i, n; - FILE *f; - byte *buf, *ptr; - - // Is this the original EXE or the clone EXE? - if ( Q_stricmp(__argv[1], "monkey") ) { - // Original EXE: Spawn clone EXE to delete this EXE - - GetModuleFileName(NULL, szPathOrig, _MAX_PATH); - GetTempPath(_MAX_PATH, szPathClone); - GetTempFileName(szPathClone, __TEXT("Del"), 0, szPathClone); - CopyFile(szPathOrig, szPathClone, FALSE); - - // Open the clone EXE using FILE_FLAG_DELETE_ON_CLOSE - hfile = CreateFile(szPathClone, 0, FILE_SHARE_READ, NULL, - OPEN_EXISTING, FILE_FLAG_DELETE_ON_CLOSE, NULL); - // Spawn the clone EXE passing it our EXE's process handle - // and the full path name to the original EXE file. - hProcessOrig = OpenProcess(SYNCHRONIZE, TRUE, - GetCurrentProcessId()); - wsprintf(szCmdLine, __TEXT("%s monkey %d %d \"%s\""), szPathClone, - sys_checksum, hProcessOrig, szPathOrig); - ZeroMemory(&si, sizeof(si)); - si.cb = sizeof(si); - CreateProcess(NULL, szCmdLine, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi); - CloseHandle(hProcessOrig); - CloseHandle(hfile); - } else { - // Clone EXE: When original EXE terminates, overwrite it with a new one - sys_checksum = atoi( __argv[2] ); - hProcessOrig = (HANDLE) atoi( __argv[3] ); - WaitForSingleObject(hProcessOrig, INFINITE); - CloseHandle(hProcessOrig); - // open the original executable - f = fopen( __argv[4], "rb" ); - if ( !f ) { - return; - } - fseek (f, 0, SEEK_END); - l = ftell (f); - fseek (f, 0, SEEK_SET); - buf = (unsigned char *)malloc(l); - if ( fread(buf, l, 1, f) != 1 ) { - return; - } - fclose(f); - // search for the exe name string, nice brute force - n = strlen((const char *)exeChecksumId); - for ( i = 0; i < l; i++ ) { - if ( !Q_strncmp((const char *)(buf + i), (const char *)exeChecksumId, n) ) { - break; - } - } - if ( i >= l ) { - return; - } - ptr = buf + i; - // write checksum into exe memory image - ptr[0] = (sys_checksum >> 24) & 0xFF; - ptr[1] = (sys_checksum >> 16) & 0xFF; - ptr[2] = (sys_checksum >> 8) & 0xFF; - ptr[3] = (sys_checksum >> 0) & 0xFF; - ptr[4] = ptr[5] = ptr[6] = ptr[7] = ptr[8] = ptr[9] = 0; - // write out new exe with checksum - f = fopen( __argv[4], "wb" ); - if ( !f ) { - return; - } - if ( fwrite(buf, l, 1, f) != 1 ) { - return; - } - fclose(f); - free(buf); - // The system will delete the clone EXE automatically - // because it was opened with FILE_FLAG_DELETE_ON_CLOSE - } - // - exit(0); -} /* ================== @@ -373,89 +178,124 @@ Sys_VerifyCodeChecksum ================== */ void Sys_VerifyCodeChecksum( void *codeBase ) { - // NOTE: should not checksum code in debug mode because the memory image changes - // as soon as you set a break point! -#if defined(SPANK_MONKEYS) && !defined(_DEBUG) - int exeChecksum; +} - // if the checksum is not yet stored in the executable - if ( exeChecksumId[4] != 0 ) { - // spawn another process that will replace this executable with one that has a checksum - Sys_ChecksumExe( codeBase ); - return; - } +/* +=============== +PrintMatches - exeChecksum = (exeChecksumId[0] << 24) | (exeChecksumId[1] << 16) | (exeChecksumId[2] << 8) | exeChecksumId[3]; - if ( exeChecksum != sys_checksum ) { - sys_monkeySpank = qtrue; +=============== +*/ +static char g_consoleField1[256]; +static char g_consoleField2[256]; + +static void PrintMatches( const char *s ) { + if ( !Q_stricmpn( s, g_consoleField1, strlen( g_consoleField1 ) ) ) { + printf( " %s\n", s ); } -#endif } //qboolean stdin_active = qtrue; char *Sys_ConsoleInput(void) { - static char text[256]; - static int len=0; - fd_set fdset; - struct timeval timeout; + const char ClearLine[] = "\r \r"; -// if (!com_dedicated || !com_dedicated->value) -// return NULL; - -// if (!stdin_active) -// return NULL; - -// FD_ZERO(&fdset); -// FD_SET(0, &fdset); // stdin -// timeout.tv_sec = 0; -// timeout.tv_usec = 0; -// if (select (1, &fdset, NULL, NULL, &timeout) == -1 || !FD_ISSET(0, &fdset)) -// return NULL; - - if (!kbhit()) return NULL; - if (len == 0) memset(text,0,sizeof(text)); - - text[len] = getch(); + static int len=0; + static bool bPendingExtended = false; - switch (text[len]) + if (!kbhit()) return NULL; + + if (len == 0) memset(g_consoleField1,0,sizeof(g_consoleField1)); + + g_consoleField1[len] = getch(); + + if (bPendingExtended) { + switch (g_consoleField1[len]) + { + case 'H': //up + strcpy(g_consoleField1, g_consoleField2); + printf(ClearLine); + printf("%s",g_consoleField1); + len = strlen(g_consoleField1); + break; + + case 'K': //left + break; + + case 'M': //right + break; + + case 'P': //down + break; + } + g_consoleField1[len] = 0; //erase last key hit + bPendingExtended = false; + } + else + switch ((unsigned char) g_consoleField1[len]) + { + case 0x00: //fkey is next + case 0xe0: //extended = arrow keys + g_consoleField1[len] = 0; //erase last key hit + bPendingExtended = true; + break; case 8: // backspace - printf("%c %c",text[len],text[len]); - text[len] = 0; + printf("%c %c",g_consoleField1[len],g_consoleField1[len]); + g_consoleField1[len] = 0; if (len > 0) len--; - text[len] = 0; + g_consoleField1[len] = 0; + break; + case 9: //Tab + if (len) { + g_consoleField1[len] = 0; //erase last key hit + printf( "\n"); + // run through again, printing matches + Cmd_CommandCompletion( PrintMatches ); + Cvar_CommandCompletion( PrintMatches ); + printf( "\n%s", g_consoleField1); + } break; case 27: // esc // clear the line + printf(ClearLine); len = 0; - printf("\n"); break; - case '\r': + case '\r': //enter + g_consoleField1[len] = 0; //erase last key hit printf("\n"); - text[len] = 0; - len = 0; - return text; + if (len) { + len = 0; + strcpy(g_consoleField2, g_consoleField1); + return g_consoleField1; + } + break; + case 'v' - 'a' + 1: // ctrl-v is paste + g_consoleField1[len] = 0; //erase last key hit + char *cbd; + cbd = Sys_GetClipboardData(); + if (cbd) { + strncpy (&g_consoleField1[len], cbd, sizeof(g_consoleField1) ); + printf("%s",cbd); + len += strlen(cbd); + Z_Free( cbd ); + if (len == sizeof(g_consoleField1)) + { + len = 0; + return g_consoleField1; + } + } + break; default: - printf("%c",text[len]); + printf("%c",g_consoleField1[len]); len++; - if (len == sizeof(text)) + if (len == sizeof(g_consoleField1)) { len = 0; - return text; + return g_consoleField1; } break; } -// len = read (0, text, sizeof(text)); -// if (len == 0) { // eof! -// stdin_active = qfalse; -// return NULL; -// } - -// if (len < 1) -// return NULL; -// len = strlen(text); -// text[len-1] = 0; // rip off the /n and terminate return NULL; } @@ -509,7 +349,7 @@ void QDECL Sys_Error( const char *error, ... ) { // Sys_DestroyConsole(); Com_ShutdownZoneMemory(); -// Com_ShutdownHunkMemory(); + Com_ShutdownHunkMemory(); exit (1); } @@ -524,7 +364,7 @@ void Sys_Quit( void ) { IN_Shutdown(); // Sys_DestroyConsole(); Com_ShutdownZoneMemory(); -// Com_ShutdownHunkMemory(); + Com_ShutdownHunkMemory(); exit (0); } @@ -1247,7 +1087,8 @@ EVENT LOOP #define MASK_QUED_EVENTS ( MAX_QUED_EVENTS - 1 ) sysEvent_t eventQue[MAX_QUED_EVENTS]; -int eventHead, eventTail; +static int eventHead=0; +static int eventTail=0; byte sys_packetReceived[MAX_MSGLEN]; /* @@ -1531,50 +1372,6 @@ void Sys_Init( void ) { IN_Init(); // FIXME: not in dedicated? } -// do a quick mem test to check for any potential future mem problems... -// -void QuickMemTest(void) -{ -// if (!Sys_LowPhysicalMemory()) - { - const int iMemTestMegs = 64; // useful search label - // special test, - void *pvData = malloc(iMemTestMegs * 1024 * 1024); - if (pvData) - { - free(pvData); - } - else - { - // err... - // - LPCSTR psContinue = "Your machine failed to allocate %dMB in a memory test, which may mean you'll have problems running this game all the way through.\n\nContinue anyway?"; - LPCSTR psNoMem = "Insufficient memory to run this game!\n"; - - switch (Language_GetIntegerValue()) - { - case SP_LANGUAGE_GERMAN: - - psContinue = "Ihr Computer konnte bei einem Speichertest keine %dMB reservieren, daher werden Sie mit dem Starten des Spiels Probleme haben.\n\nDennoch fortsetzen?"; - psNoMem = "Unzureichender Speicher zum Starten!\n"; - break; - - case SP_LANGUAGE_FRENCH: - - psContinue = "Votre système n'a pu allouer %d Mo lors d'une vérification de la mémoire, ce qui signifie que vous aurez peut-être du mal à faire fonctionner ce jeu. \n\nSouhaitez-vous continuer malgré tout ?"; - psNoMem = "Mémoire insuffisante pour lancer ce jeu !\n"; - break; - } - - #define GetYesNo(psQuery) (!!(MessageBox(NULL,psQuery,"Query",MB_YESNO|MB_ICONWARNING|MB_TASKMODAL)==IDYES)) - if (!GetYesNo(va(psContinue,iMemTestMegs))) - { - Com_Error( ERR_FATAL, psNoMem ); - } - } - } -} - //======================================================================= //int totalMsec, countMsec; diff --git a/CODE-mp/qcommon/RoffSystem.cpp b/CODE-mp/qcommon/RoffSystem.cpp index 67819d9..fdf837c 100644 --- a/CODE-mp/qcommon/RoffSystem.cpp +++ b/CODE-mp/qcommon/RoffSystem.cpp @@ -801,7 +801,6 @@ qboolean CROFFSystem::ApplyROFF( SROFFEntity *roff_ent, CROFFSystem::CROFF *roff sharedEntity_t *ent = NULL; trajectory_t *originTrajectory, *angleTrajectory; vec_t *origin, *angle; - vec3_t originTemp, angleTemp; if ( svs.time < roff_ent->mNextROFFTime ) @@ -812,6 +811,7 @@ qboolean CROFFSystem::ApplyROFF( SROFFEntity *roff_ent, CROFFSystem::CROFF *roff if (roff_ent->mIsClient) { #ifndef DEDICATED + vec3_t originTemp, angleTemp; originTrajectory = (trajectory_t *)VM_Call( cgvm, CG_GET_ORIGIN_TRAJECTORY, roff_ent->mEntID ); angleTrajectory = (trajectory_t *)VM_Call( cgvm, CG_GET_ANGLE_TRAJECTORY, roff_ent->mEntID ); VM_Call( cgvm, CG_GET_ORIGIN, roff_ent->mEntID, originTemp ); @@ -949,11 +949,11 @@ qboolean CROFFSystem::ClearLerp( SROFFEntity *roff_ent ) sharedEntity_t *ent; trajectory_t *originTrajectory, *angleTrajectory; vec_t *origin, *angle; - vec3_t originTemp, angleTemp; if (roff_ent->mIsClient) { #ifndef DEDICATED + vec3_t originTemp, angleTemp; originTrajectory = (trajectory_t *)VM_Call( cgvm, CG_GET_ORIGIN_TRAJECTORY, roff_ent->mEntID ); angleTrajectory = (trajectory_t *)VM_Call( cgvm, CG_GET_ANGLE_TRAJECTORY, roff_ent->mEntID ); VM_Call( cgvm, CG_GET_ORIGIN, roff_ent->mEntID, originTemp ); diff --git a/CODE-mp/qcommon/cm_load.cpp b/CODE-mp/qcommon/cm_load.cpp index 38eeafa..5dcd38b 100644 --- a/CODE-mp/qcommon/cm_load.cpp +++ b/CODE-mp/qcommon/cm_load.cpp @@ -91,7 +91,6 @@ void CMod_LoadShaders( lump_t *l ) out->contentFlags = LittleLong( in->contentFlags ); out->surfaceFlags = LittleLong( in->surfaceFlags ); } - CM_SetupShaderProperties(); } @@ -674,9 +673,6 @@ static void CM_LoadMap_Actual( const char *name, qboolean clientload, int *check , name, header.version, BSP_VERSION ); } - // Load in the shader text - return instantly if already loaded - CM_LoadShaderText(qfalse); - cmod_base = (byte *)buf; // load into heap @@ -747,10 +743,6 @@ CM_ClearMap */ void CM_ClearMap( void ) { -#if !defined(BSPC) - CM_ShutdownShaderProperties(); -#endif - Com_Memset( &cm, 0, sizeof( cm ) ); CM_ClearLevelPatches(); } diff --git a/CODE-mp/qcommon/cm_local.h b/CODE-mp/qcommon/cm_local.h index 08f9256..47e388c 100644 --- a/CODE-mp/qcommon/cm_local.h +++ b/CODE-mp/qcommon/cm_local.h @@ -194,10 +194,3 @@ struct patchCollide_s *CM_GeneratePatchCollide( int width, int height, vec3_t *p void CM_TraceThroughPatchCollide( traceWork_t *tw, const struct patchCollide_s *pc ); qboolean CM_PositionTestInPatchCollide( traceWork_t *tw, const struct patchCollide_s *pc ); void CM_ClearLevelPatches( void ); - -// cm_shader.cpp -void CM_SetupShaderProperties( void ); -void CM_ShutdownShaderProperties(void); -CCMShader *CM_GetShaderInfo( const char *name ); -CCMShader *CM_GetShaderInfo( int shaderNum ); -int CM_HandleDamageShader(int sideNum, int damage); diff --git a/CODE-mp/qcommon/common.cpp b/CODE-mp/qcommon/common.cpp index 9aeb1f3..1211add 100644 --- a/CODE-mp/qcommon/common.cpp +++ b/CODE-mp/qcommon/common.cpp @@ -278,6 +278,7 @@ void QDECL Com_Error( int code, const char *fmt, ... ) { va_end (argptr); if ( code != ERR_DISCONNECT ) { + Cvar_Get("com_errorMessage", "", CVAR_ROM); //give com_errorMessage a default so it won't come back to life after a resetDefaults Cvar_Set("com_errorMessage", com_errorMessage); } @@ -857,7 +858,11 @@ void *Z_Malloc(int iSize, memtag_t eTag, qboolean bZeroit /* = qfalse */) zoneHeader_t *pMemory = NULL; while (pMemory == NULL) { - pMemory = (zoneHeader_t *) malloc ( iRealSize ); + if (bZeroit) { + pMemory = (zoneHeader_t *) calloc ( iRealSize, 1 ); + } else { + pMemory = (zoneHeader_t *) malloc ( iRealSize ); + } if (!pMemory) { // new bit, if we fail to malloc memory, try dumping some of the cached stuff that's non-vital and try again... @@ -980,9 +985,6 @@ void *Z_Malloc(int iSize, memtag_t eTag, qboolean bZeroit /* = qfalse */) Z_Validate(); // check for corruption void *pvReturnMem = &pMemory[1]; - if (bZeroit) { - memset(pvReturnMem, 0, iSize); - } return pvReturnMem; } @@ -1641,6 +1643,15 @@ void Com_InitHunkMemory( void ) { #endif } +void Com_ShutdownHunkMemory(void) +{ + if(s_hunkData) + { + free(s_hunkData); + s_hunkData = NULL; + } +} + /* ==================== Hunk_MemoryRemaining @@ -2494,7 +2505,11 @@ void Com_Init( char *commandLine ) { // skip the jk2mpconfig.cfg if "safe" is on the command line if ( !Com_SafeMode() ) { +#ifdef DEDICATED + Cbuf_AddText ("exec jk2mpserver.cfg\n"); +#else Cbuf_AddText ("exec jk2mpconfig.cfg\n"); +#endif } Cbuf_AddText ("exec autoexec.cfg\n"); @@ -2532,7 +2547,7 @@ void Com_Init( char *commandLine ) { com_dropsim = Cvar_Get ("com_dropsim", "0", CVAR_CHEAT); com_viewlog = Cvar_Get( "viewlog", "0", CVAR_CHEAT ); com_speeds = Cvar_Get ("com_speeds", "0", 0); - com_timedemo = Cvar_Get ("timedemo", "0", CVAR_CHEAT); + com_timedemo = Cvar_Get ("timedemo", "0", 0); com_cameraMode = Cvar_Get ("com_cameraMode", "0", CVAR_CHEAT); cl_paused = Cvar_Get ("cl_paused", "0", CVAR_ROM); @@ -2569,7 +2584,7 @@ void Com_Init( char *commandLine ) { com_version = Cvar_Get ("version", s, CVAR_ROM | CVAR_SERVERINFO ); SP_Init(); -#ifndef __linux__ +#ifndef DEDICATED extern void QuickMemTest(void); QuickMemTest(); #endif @@ -2669,7 +2684,11 @@ void Com_WriteConfiguration( void ) { } cvar_modifiedFlags &= ~CVAR_ARCHIVE; +#ifdef DEDICATED + Com_WriteConfigToFile( "jk2mpserver.cfg" ); +#else Com_WriteConfigToFile( "jk2mpconfig.cfg" ); +#endif // bk001119 - tentative "not needed for dedicated" #ifndef DEDICATED @@ -2938,7 +2957,6 @@ void MSG_shutdownHuffman(); void Com_Shutdown (void) { CM_ClearMap(); - CM_FreeShaderText(); if (logfile) { FS_FCloseFile (logfile); diff --git a/CODE-mp/qcommon/cvar.cpp b/CODE-mp/qcommon/cvar.cpp index a6449b5..d202181 100644 --- a/CODE-mp/qcommon/cvar.cpp +++ b/CODE-mp/qcommon/cvar.cpp @@ -150,6 +150,11 @@ void Cvar_CommandCompletion( void(*callback)(const char *s) ) { cvar_t *cvar; for ( cvar = cvar_vars ; cvar ; cvar = cvar->next ) { + // Dont show internal cvars + if ( cvar->flags & CVAR_INTERNAL ) + { + continue; + } callback( cvar->name ); } } @@ -463,11 +468,11 @@ qboolean Cvar_Command( void ) { // perform a variable print or set if ( Cmd_Argc() == 1 ) { - if (v->flags & CVAR_INTERNAL) // don't display +/* if (v->flags & CVAR_INTERNAL) // don't display { return qtrue; } - +*/ Com_Printf ("\"%s\" is:\"%s" S_COLOR_WHITE "\" default:\"%s" S_COLOR_WHITE "\"\n", v->name, v->string, v->resetString ); if ( v->latchedString ) { Com_Printf( "latched: \"%s\"\n", v->latchedString ); @@ -902,7 +907,7 @@ Reads in all archived cvars ============ */ void Cvar_Init (void) { - cvar_cheats = Cvar_Get("sv_cheats", "1", CVAR_ROM | CVAR_SYSTEMINFO ); + cvar_cheats = Cvar_Get("sv_cheats", "0", CVAR_ROM | CVAR_SYSTEMINFO ); Cmd_AddCommand ("toggle", Cvar_Toggle_f); Cmd_AddCommand ("set", Cvar_Set_f); diff --git a/CODE-mp/qcommon/files.cpp b/CODE-mp/qcommon/files.cpp index c3442d1..f9811a4 100644 --- a/CODE-mp/qcommon/files.cpp +++ b/CODE-mp/qcommon/files.cpp @@ -2531,7 +2531,7 @@ qboolean FS_idPak( char *pak, char *base ) { int i; for (i = 0; i < NUM_ID_PAKS; i++) { - if ( !FS_FilenameCompare(pak, va("%s/pak%d", base, i)) ) { + if ( !FS_FilenameCompare(pak, va("%s/assets%d", base, i)) ) { break; } } @@ -3266,7 +3266,11 @@ void FS_Restart( int checksumFeed ) { if ( Q_stricmp(fs_gamedirvar->string, lastValidGame) ) { // skip the jk2mpconfig.cfg if "safe" is on the command line if ( !Com_SafeMode() ) { +#ifdef DEDICATED + Cbuf_AddText ("exec jk2mpserver.cfg\n"); +#else Cbuf_AddText ("exec jk2mpconfig.cfg\n"); +#endif } } diff --git a/CODE-mp/qcommon/game_version.h b/CODE-mp/qcommon/game_version.h index ad6a048..ac19112 100644 --- a/CODE-mp/qcommon/game_version.h +++ b/CODE-mp/qcommon/game_version.h @@ -3,6 +3,6 @@ // Current version of the multi player game -#define Q3_VERSION "JK2MP: v1.02" +#define Q3_VERSION "JK2MP: v1.03" //end diff --git a/CODE-mp/qcommon/huffman.cpp b/CODE-mp/qcommon/huffman.cpp index 0ee677e..9994c7c 100644 --- a/CODE-mp/qcommon/huffman.cpp +++ b/CODE-mp/qcommon/huffman.cpp @@ -6,14 +6,8 @@ #include "../game/q_shared.h" #include "qcommon.h" -//#define _TESTCR_ static int bloc = 0; -#ifdef _TESTCR_ -static int byteCount=0; -static int bitCount=0; -#endif - void Huff_putBit( int bit, byte *fout, int *offset) { bloc = *offset; if ((bloc&7) == 0) { @@ -240,9 +234,6 @@ void Huff_addRef(huff_t* huff, byte ch) { /* Get a symbol */ int Huff_Receive (node_t *node, int *ch, byte *fin) { while (node && node->symbol == INTERNAL_NODE) { -#ifdef _TESTCR_ - bitCount++; -#endif if (get_bit(fin)) { node = node->right; } else { @@ -250,11 +241,9 @@ int Huff_Receive (node_t *node, int *ch, byte *fin) { } } if (!node) { - Com_Error(ERR_DROP, "Illegal tree!\n"); + return 0; +// Com_Error(ERR_DROP, "Illegal tree!\n"); } -#ifdef _TESTCR_ - byteCount++; -#endif return (*ch = node->symbol); } @@ -262,9 +251,6 @@ int Huff_Receive (node_t *node, int *ch, byte *fin) { void Huff_offsetReceive (node_t *node, int *ch, byte *fin, int *offset) { bloc = *offset; while (node && node->symbol == INTERNAL_NODE) { -#ifdef _TESTCR_ - bitCount++; -#endif if (get_bit(fin)) { node = node->right; } else { @@ -272,11 +258,10 @@ void Huff_offsetReceive (node_t *node, int *ch, byte *fin, int *offset) { } } if (!node) { - Com_Error(ERR_DROP, "Illegal tree!\n"); + *ch = 0; + return; +// Com_Error(ERR_DROP, "Illegal tree!\n"); } -#ifdef _TESTCR_ - byteCount++; -#endif *ch = node->symbol; *offset = bloc; } @@ -322,9 +307,9 @@ void Huff_Decompress(msg_t *mbuf, int offset) { huff_t huff; size = mbuf->cursize - offset; - buffer = mbuf->data+ + offset; + buffer = mbuf->data + offset; - if (size<=0) { + if ( size <= 0 ) { return; } @@ -337,13 +322,24 @@ void Huff_Decompress(msg_t *mbuf, int offset) { huff.tree->parent = huff.tree->left = huff.tree->right = NULL; cch = buffer[0]*256 + buffer[1]; + // don't overflow with bad messages + if ( cch > mbuf->maxsize - offset ) { + cch = mbuf->maxsize - offset; + } bloc = 16; - for (j=0; j> 3) > size ) { + seq[j] = 0; + break; + } Huff_Receive(huff.tree, &ch, buffer); /* Get a character */ - if (ch == NYT) { /* We got a NYT, get the symbol associated with it */ + if ( ch == NYT ) { /* We got a NYT, get the symbol associated with it */ ch = 0; - for (i = 0; i < 8; i++) { + for ( i = 0; i < 8; i++ ) { ch = (ch<<1) + get_bit(buffer); } } @@ -352,9 +348,8 @@ void Huff_Decompress(msg_t *mbuf, int offset) { Huff_addRef(&huff, (byte)ch); /* Increment node */ } - mbuf->cursize = cch + offset; - Com_Memcpy(mbuf->data+offset, seq, cch); + Com_Memcpy(mbuf->data + offset, seq, cch); } extern int oldsize; @@ -400,11 +395,6 @@ void Huff_Compress(msg_t *mbuf, int offset) { void Huff_Init(huffman_t *huff) { -#ifdef _TESTCR_ - byteCount=0; - bitCount=0; -#endif - Com_Memset(&huff->compressor, 0, sizeof(huff_t)); Com_Memset(&huff->decompressor, 0, sizeof(huff_t)); @@ -424,16 +414,3 @@ void Huff_Init(huffman_t *huff) { huff->compressor.loc[NYT] = huff->compressor.tree; } -float Huff_GetCR(void) -{ -#ifdef _TESTCR_ - if(!bitCount) - { - // No valid data. - return(-1.0f); - } - return(((float)byteCount*8.0f)/bitCount); -#else - return(-1.0f); -#endif -} diff --git a/CODE-mp/qcommon/msg.cpp b/CODE-mp/qcommon/msg.cpp index fe2fee5..3f69f08 100644 --- a/CODE-mp/qcommon/msg.cpp +++ b/CODE-mp/qcommon/msg.cpp @@ -854,7 +854,7 @@ netField_t entityStateFields[] = { NETF(teamowner), 8 }, { NETF(shouldtarget), 1 }, { NETF(powerups), 16 }, -{ NETF(modelGhoul2), 4 }, +{ NETF(modelGhoul2), 5 }, { NETF(g2radius), 8 }, { NETF(modelindex), -8 }, { NETF(otherEntityNum2), GENTITYNUM_BITS }, @@ -1235,6 +1235,9 @@ netField_t playerStateFields[] = { PSF(rocketTargetTime), 32 }, { PSF(holocronBits), 32 }, { PSF(isJediMaster), 1 }, +{ PSF(forceRestricted), 1 }, +{ PSF(trueJedi), 1 }, +{ PSF(trueNonJedi), 1 }, { PSF(fallingToDeath), 32 }, { PSF(electrifyTime), 32 }, diff --git a/CODE-mp/qcommon/net_chan.cpp b/CODE-mp/qcommon/net_chan.cpp index f2dd86a..f7cfcd8 100644 --- a/CODE-mp/qcommon/net_chan.cpp +++ b/CODE-mp/qcommon/net_chan.cpp @@ -508,6 +508,8 @@ const char *NET_AdrToString (netadr_t a) } else if (a.type == NA_IP) { Com_sprintf (s, sizeof(s), "%i.%i.%i.%i:%i", a.ip[0], a.ip[1], a.ip[2], a.ip[3], BigShort(a.port)); + } else if (a.type == NA_BAD) { + Com_sprintf (s, sizeof(s), "BAD"); } else { Com_sprintf (s, sizeof(s), "%02x%02x%02x%02x.%02x%02x%02x%02x%02x%02x:%i", a.ipx[0], a.ipx[1], a.ipx[2], a.ipx[3], a.ipx[4], a.ipx[5], a.ipx[6], a.ipx[7], a.ipx[8], a.ipx[9], diff --git a/CODE-mp/qcommon/qcommon.h b/CODE-mp/qcommon/qcommon.h index 0d15863..642b16f 100644 --- a/CODE-mp/qcommon/qcommon.h +++ b/CODE-mp/qcommon/qcommon.h @@ -753,7 +753,7 @@ void Z_TagFree ( memtag_t eTag ); void Z_Free ( void *ptr ); int Z_Size ( void *pvAddress); void Com_ShutdownZoneMemory(void); - +void Com_ShutdownHunkMemory(void); void Hunk_Clear( void ); void Hunk_ClearToMark( void ); diff --git a/CODE-mp/qcommon/strip.cpp b/CODE-mp/qcommon/strip.cpp index 6fc13db..e63dff1 100644 --- a/CODE-mp/qcommon/strip.cpp +++ b/CODE-mp/qcommon/strip.cpp @@ -822,7 +822,7 @@ void cStringsSingle::SetText(const char *newText) // fix problems caused by fucking morons entering clever "rich" chars in to new text files *after* the auto-stripper // removed them all in the first place... // -// ONLY DO THIS FOR ENGLISH, OR IT BREAKS ASIAN STRINGS!!!!!!!!!!!!!!!!!!!!! +// ONLY DO THIS FOR EUROPEAN LANGUAGES, OR IT BREAKS ASIAN STRINGS!!!!!!!!!!!!!!!!!!!!! // static void FixIllegalChars(char *psText) { @@ -898,7 +898,8 @@ bool cStringsSingle::UnderstandToken(int token, char *data) { // default to english in case there is no foreign if (LanguagePair->Name == TK_TEXT_LANGUAGE1 || LanguagePair->Name == TK_TEXT_LANGUAGE2 || - LanguagePair->Name == TK_TEXT_LANGUAGE3 + LanguagePair->Name == TK_TEXT_LANGUAGE3 || + LanguagePair->Name == TK_TEXT_LANGUAGE8 ) { FixIllegalChars(data); @@ -910,7 +911,8 @@ bool cStringsSingle::UnderstandToken(int token, char *data) { if (LanguagePair->Name == TK_TEXT_LANGUAGE1 || LanguagePair->Name == TK_TEXT_LANGUAGE2 || - LanguagePair->Name == TK_TEXT_LANGUAGE3 + LanguagePair->Name == TK_TEXT_LANGUAGE3 || + LanguagePair->Name == TK_TEXT_LANGUAGE8 ) { FixIllegalChars(data); @@ -1597,7 +1599,7 @@ int SP_GetStringID(const char *inReference) int ID; char Reference[MAX_QPATH]; Q_strncpyz(Reference, inReference, MAX_QPATH); - strupr(Reference); + Q_strupr(Reference); for(i = SP_ListByID.begin(); i != SP_ListByID.end(); i++) { @@ -1714,11 +1716,19 @@ static void SP_UpdateLanguage(void) void SP_Init(void) { - sp_language = Cvar_Get("sp_language", va("%d", SP_LANGUAGE_ENGLISH), CVAR_ARCHIVE); + sp_language = Cvar_Get("sp_language", va("%d", SP_LANGUAGE_ENGLISH), CVAR_ARCHIVE | CVAR_NORESTART); sp_show_strip = Cvar_Get ("sp_show_strip", "0", 0); SP_UpdateLanguage(); sp_language->modified = qfalse; + + // Register_StringPackets... + // + SP_Register("con_text", SP_REGISTER_REQUIRED); //reference is CON_TEXT + SP_Register("mp_ingame",SP_REGISTER_REQUIRED); //reference is INGAMETEXT + SP_Register("mp_svgame",SP_REGISTER_REQUIRED); //reference is SVINGAME + SP_Register("sp_ingame",SP_REGISTER_REQUIRED); //reference is INGAME , needed for item pickups + SP_Register("keynames", 0/*SP_REGISTER_REQUIRED*/); //reference is KEYNAMES } // called in Com_Frame, so don't take up any time! (can also be called during dedicated) @@ -1743,5 +1753,24 @@ int Language_GetIntegerValue(void) return 0; } + +// query function from font code +// +qboolean Language_IsKorean(void) +{ + return (sp_language && sp_language->integer == SP_LANGUAGE_KOREAN) ? qtrue : qfalse; +} + +qboolean Language_IsTaiwanese(void) +{ + return (sp_language && sp_language->integer == SP_LANGUAGE_TAIWANESE) ? qtrue : qfalse; +} + +qboolean Language_IsJapanese(void) +{ + return (sp_language && sp_language->integer == SP_LANGUAGE_JAPANESE) ? qtrue : qfalse; +} + + #endif diff --git a/CODE-mp/qcommon/vm_ppc.cpp b/CODE-mp/qcommon/vm_ppc.cpp index 266c34d..7fff987 100644 --- a/CODE-mp/qcommon/vm_ppc.cpp +++ b/CODE-mp/qcommon/vm_ppc.cpp @@ -426,8 +426,8 @@ void VM_Compile( vm_t *vm, vmHeader_t *header ) { // allocate a very large temp buffer, we will shrink it later maxLength = header->codeLength * 8; - buf = Z_Malloc( maxLength ); - jused = Z_Malloc(header->instructionCount + 2); + buf = Z_Malloc( maxLength,qfalse ); + jused = Z_Malloc(header->instructionCount + 2,qfalse); Com_Memset(jused, 0, header->instructionCount+2); // compile everything twice, so the second pass will have valid instruction diff --git a/CODE-mp/qcommon/vm_x86.cpp b/CODE-mp/qcommon/vm_x86.cpp index 67b6ff3..920f89f 100644 --- a/CODE-mp/qcommon/vm_x86.cpp +++ b/CODE-mp/qcommon/vm_x86.cpp @@ -55,8 +55,8 @@ int qftol027F( void ); // bk001215 - fixed FPU control variants int qftol037F( void ); int qftol0E7F( void ); // bk010102 - fixed bogus bits (duh) int qftol0F7F( void ); - } + static int ftolPtr = (int)qftol0F7F; #endif // FTOL_PTR @@ -66,16 +66,31 @@ static int asmCallPtr = (int)doAsmCall; static int callMask = 0; // bk001213 - init -/* + +static int instruction, pass, lastConst; +static int oc0, oc1, pop0, pop1; + +typedef enum +{ + LAST_COMMAND_NONE = 0, + LAST_COMMAND_MOV_EDI_EAX, + LAST_COMMAND_SUB_DI_4, + LAST_COMMAND_SUB_DI_8, +} ELastCommand; + +static ELastCommand LastCommand; + + /* ================= AsmCall ================= */ #ifdef _WIN32 __declspec( naked ) void AsmCall( void ) { -static int programStack; -static int *opStack; -static int syscallNum; +int programStack; +int *opStack; +int syscallNum; +vm_t* savedVM; __asm { mov eax, dword ptr [edi] @@ -96,6 +111,10 @@ systemCall: neg eax dec eax + push ebp + mov ebp, esp + sub esp, __LOCAL_SIZE + mov dword ptr syscallNum, eax // so C code can get at it mov dword ptr programStack, esi // so C code can get at it mov dword ptr opStack, edi @@ -105,18 +124,25 @@ systemCall: push edi // statics aren't guaranteed to be around } + savedVM = currentVM; + // save the stack to allow recursive VM entry currentVM->programStack = programStack - 4; *(int *)((byte *)currentVM->dataBase + programStack + 4) = syscallNum; //VM_LogSyscalls( (int *)((byte *)currentVM->dataBase + programStack + 4) ); *(opStack+1) = currentVM->systemCall( (int *)((byte *)currentVM->dataBase + programStack + 4) ); + currentVM = savedVM; + _asm { pop edi pop esi pop ecx add edi, 4 // we added the return value + mov esp, ebp + pop ebp + ret } @@ -171,7 +197,6 @@ void AsmCall( void ) { } #endif - static int Constant4( void ) { int v; @@ -188,16 +213,21 @@ static int Constant1( void ) { return v; } -static void Emit1( int v ) { +static void Emit1( int v ) +{ buf[ compiledOfs ] = v; compiledOfs++; + + LastCommand = LAST_COMMAND_NONE; } + #if 0 static void Emit2( int v ) { Emit1( v & 255 ); Emit1( ( v >> 8 ) & 255 ); } #endif + static void Emit4( int v ) { Emit1( v & 255 ); Emit1( ( v >> 8 ) & 255 ); @@ -238,16 +268,36 @@ static void EmitString( const char *string ) { } } -static int instruction, pass, lastConst; -static int oc0, oc1, pop0, pop1; + + +static void EmitCommand(ELastCommand command) +{ + switch(command) + { + case LAST_COMMAND_MOV_EDI_EAX: + EmitString( "89 07" ); // mov dword ptr [edi], eax + break; + + case LAST_COMMAND_SUB_DI_4: + EmitString( "83 EF 04" ); // sub edi, 4 + break; + + case LAST_COMMAND_SUB_DI_8: + EmitString( "83 EF 08" ); // sub edi, 8 + break; + } + LastCommand = command; +} static void EmitAddEDI4(vm_t *vm) { - if (buf[compiledOfs-3] == 0x83 && buf[compiledOfs-2] == 0xEF && buf[compiledOfs-1] == 0x04 && jused[instruction-1] == 0) { // sub di,4 + if (LastCommand == LAST_COMMAND_SUB_DI_4 && jused[instruction-1] == 0) + { // sub di,4 compiledOfs -= 3; vm->instructionPointers[ instruction-1 ] = compiledOfs; return; } - if (buf[compiledOfs-3] == 0x83 && buf[compiledOfs-2] == 0xEF && buf[compiledOfs-1] == 0x08 && jused[instruction-1] == 0) { // sub di,8 + if (LastCommand == LAST_COMMAND_SUB_DI_8 && jused[instruction-1] == 0) + { // sub di,8 compiledOfs -= 3; vm->instructionPointers[ instruction-1 ] = compiledOfs; EmitString( "83 EF 04" ); // sub edi,4 @@ -257,16 +307,19 @@ static void EmitAddEDI4(vm_t *vm) { } static void EmitMovEAXEDI(vm_t *vm) { - if (buf[compiledOfs-2] == 0x89 && buf[compiledOfs-1] == 0x07) { // mov [edi], eax + if (LastCommand == LAST_COMMAND_MOV_EDI_EAX) + { // mov [edi], eax compiledOfs -= 2; vm->instructionPointers[ instruction-1 ] = compiledOfs; return; } if (pop1 == OP_DIVI || pop1 == OP_DIVU || pop1 == OP_MULI || pop1 == OP_MULU || - pop1 == OP_STORE4 || pop1 == OP_STORE2 || pop1 == OP_STORE1 ) { + pop1 == OP_STORE4 || pop1 == OP_STORE2 || pop1 == OP_STORE1 ) + { return; } - if (pop1 == OP_CONST && buf[compiledOfs-6] == 0xC7 && buf[compiledOfs-5] == 0x07 ) { // mov edi, 0x123456 + if (pop1 == OP_CONST && buf[compiledOfs-6] == 0xC7 && buf[compiledOfs-5] == 0x07 ) + { // mov edi, 0x123456 compiledOfs -= 6; vm->instructionPointers[ instruction-1 ] = compiledOfs; EmitString( "B8" ); // mov eax, 0x12345678 @@ -277,18 +330,21 @@ static void EmitMovEAXEDI(vm_t *vm) { } qboolean EmitMovEBXEDI(vm_t *vm, int andit) { - if (buf[compiledOfs-2] == 0x89 && buf[compiledOfs-1] == 0x07) { // mov [edi], eax + if (LastCommand == LAST_COMMAND_MOV_EDI_EAX) + { // mov [edi], eax compiledOfs -= 2; vm->instructionPointers[ instruction-1 ] = compiledOfs; EmitString( "8B D8"); // mov bx, eax return qfalse; } if (pop1 == OP_DIVI || pop1 == OP_DIVU || pop1 == OP_MULI || pop1 == OP_MULU || - pop1 == OP_STORE4 || pop1 == OP_STORE2 || pop1 == OP_STORE1 ) { + pop1 == OP_STORE4 || pop1 == OP_STORE2 || pop1 == OP_STORE1 ) + { EmitString( "8B D8"); // mov bx, eax return qfalse; } - if (pop1 == OP_CONST && buf[compiledOfs-6] == 0xC7 && buf[compiledOfs-5] == 0x07 ) { // mov edi, 0x123456 + if (pop1 == OP_CONST && buf[compiledOfs-6] == 0xC7 && buf[compiledOfs-5] == 0x07 ) + { // mov edi, 0x123456 compiledOfs -= 6; vm->instructionPointers[ instruction-1 ] = compiledOfs; EmitString( "BB" ); // mov ebx, 0x12345678 @@ -335,6 +391,8 @@ void VM_Compile( vm_t *vm, vmHeader_t *header ) { code = (byte *)header + header->codeOffset; compiledOfs = 0; + LastCommand = LAST_COMMAND_NONE; + while ( instruction < header->instructionCount ) { if ( compiledOfs > maxLength - 16 ) { Com_Error( ERR_FATAL, "VM_CompileX86: maxLength exceeded" ); @@ -365,7 +423,7 @@ void VM_Compile( vm_t *vm, vmHeader_t *header ) { EmitString( "BB" ); // mov ebx, 0x12345678 Emit4( (Constant4()&vm->dataMask) + (int)vm->dataBase); EmitString( "8B 03" ); // mov eax, dword ptr [ebx] - EmitString( "89 07" ); // mov dword ptr [edi], eax + EmitCommand(LAST_COMMAND_MOV_EDI_EAX); // mov dword ptr [edi], eax pc++; // OP_LOAD4 instruction += 1; break; @@ -375,7 +433,7 @@ void VM_Compile( vm_t *vm, vmHeader_t *header ) { EmitString( "BB" ); // mov ebx, 0x12345678 Emit4( (Constant4()&vm->dataMask) + (int)vm->dataBase); EmitString( "0F B7 03" ); // movzx eax, word ptr [ebx] - EmitString( "89 07" ); // mov dword ptr [edi], eax + EmitCommand(LAST_COMMAND_MOV_EDI_EAX); // mov dword ptr [edi], eax pc++; // OP_LOAD4 instruction += 1; break; @@ -385,7 +443,7 @@ void VM_Compile( vm_t *vm, vmHeader_t *header ) { EmitString( "BB" ); // mov ebx, 0x12345678 Emit4( (Constant4()&vm->dataMask) + (int)vm->dataBase); EmitString( "0F B6 03" ); // movzx eax, byte ptr [ebx] - EmitString( "89 07" ); // mov dword ptr [edi], eax + EmitCommand(LAST_COMMAND_MOV_EDI_EAX); // mov dword ptr [edi], eax pc++; // OP_LOAD4 instruction += 1; break; @@ -400,7 +458,7 @@ void VM_Compile( vm_t *vm, vmHeader_t *header ) { // } EmitString( "89 83" ); // mov dword ptr [ebx+0x12345678], eax Emit4( (int)vm->dataBase ); - EmitString( "83 EF 04" ); // sub edi, 4 + EmitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4 pc++; // OP_STORE4 instruction += 1; break; @@ -415,7 +473,7 @@ void VM_Compile( vm_t *vm, vmHeader_t *header ) { // } EmitString( "66 89 83" ); // mov word ptr [ebx+0x12345678], eax Emit4( (int)vm->dataBase ); - EmitString( "83 EF 04" ); // sub edi, 4 + EmitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4 pc++; // OP_STORE4 instruction += 1; break; @@ -430,7 +488,7 @@ void VM_Compile( vm_t *vm, vmHeader_t *header ) { // } EmitString( "88 83" ); // mov byte ptr [ebx+0x12345678], eax Emit4( (int)vm->dataBase ); - EmitString( "83 EF 04" ); // sub edi, 4 + EmitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4 pc++; // OP_STORE4 instruction += 1; break; @@ -463,14 +521,14 @@ void VM_Compile( vm_t *vm, vmHeader_t *header ) { oc0 = oc1; oc1 = Constant4(); Emit4( oc1 ); - EmitString( "89 07" ); // mov dword ptr [edi], eax + EmitCommand(LAST_COMMAND_MOV_EDI_EAX); // mov dword ptr [edi], eax break; case OP_ARG: EmitMovEAXEDI(vm); // mov eax,dword ptr [edi] EmitString( "89 86" ); // mov dword ptr [esi+database],eax // FIXME: range check Emit4( Constant1() + (int)vm->dataBase ); - EmitString( "83 EF 04" ); // sub edi,4 + EmitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4 break; case OP_CALL: EmitString( "C7 86" ); // mov dword ptr [esi+database],0x12345678 @@ -483,7 +541,7 @@ void VM_Compile( vm_t *vm, vmHeader_t *header ) { EmitAddEDI4(vm); break; case OP_POP: - EmitString( "83 EF 04" ); // sub edi, 4 + EmitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4 break; case OP_LEAVE: v = Constant4(); @@ -512,13 +570,13 @@ void VM_Compile( vm_t *vm, vmHeader_t *header ) { EmitString( "89 83" ); // mov dword ptr [ebx+0x12345678], eax Emit4( (int)vm->dataBase ); } else { - EmitString( "83 EF 04" ); // sub edi, 4 + EmitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4 EmitString( "8B 1F" ); // mov ebx, dword ptr [edi] EmitString( "89 83" ); // mov dword ptr [ebx+0x12345678], eax Emit4( (int)vm->dataBase ); } } - EmitString( "83 EF 04" ); // sub edi, 4 + EmitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4 pc++; // OP_ADD pc++; // OP_STORE instruction += 3; @@ -545,13 +603,13 @@ void VM_Compile( vm_t *vm, vmHeader_t *header ) { EmitString( "89 83" ); // mov dword ptr [ebx+0x12345678], eax Emit4( (int)vm->dataBase ); } else { - EmitString( "83 EF 04" ); // sub edi, 4 + EmitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4 EmitString( "8B 1F" ); // mov ebx, dword ptr [edi] EmitString( "89 83" ); // mov dword ptr [ebx+0x12345678], eax Emit4( (int)vm->dataBase ); } } - EmitString( "83 EF 04" ); // sub edi, 4 + EmitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4 pc++; // OP_SUB pc++; // OP_STORE instruction += 3; @@ -563,25 +621,25 @@ void VM_Compile( vm_t *vm, vmHeader_t *header ) { vm->instructionPointers[ instruction-1 ] = compiledOfs; EmitString( "8B 80"); // mov eax, dword ptr [eax + 0x1234567] Emit4( (int)vm->dataBase ); - EmitString( "89 07" ); // mov dword ptr [edi], eax + EmitCommand(LAST_COMMAND_MOV_EDI_EAX); // mov dword ptr [edi], eax break; } EmitMovEBXEDI(vm, vm->dataMask); EmitString( "8B 83" ); // mov eax, dword ptr [ebx + 0x12345678] Emit4( (int)vm->dataBase ); - EmitString( "89 07" ); // mov dword ptr [edi], eax + EmitCommand(LAST_COMMAND_MOV_EDI_EAX); // mov dword ptr [edi], eax break; case OP_LOAD2: EmitMovEBXEDI(vm, vm->dataMask); EmitString( "0F B7 83" ); // movzx eax, word ptr [ebx + 0x12345678] Emit4( (int)vm->dataBase ); - EmitString( "89 07" ); // mov dword ptr [edi], eax + EmitCommand(LAST_COMMAND_MOV_EDI_EAX); // mov dword ptr [edi], eax break; case OP_LOAD1: EmitMovEBXEDI(vm, vm->dataMask); EmitString( "0F B6 83" ); // movzx eax, byte ptr [ebx + 0x12345678] Emit4( (int)vm->dataBase ); - EmitString( "89 07" ); // mov dword ptr [edi], eax + EmitCommand(LAST_COMMAND_MOV_EDI_EAX); // mov dword ptr [edi], eax break; case OP_STORE4: EmitMovEAXEDI(vm); @@ -592,7 +650,7 @@ void VM_Compile( vm_t *vm, vmHeader_t *header ) { // } EmitString( "89 83" ); // mov dword ptr [ebx+0x12345678], eax Emit4( (int)vm->dataBase ); - EmitString( "83 EF 08" ); // sub edi, 8 + EmitCommand(LAST_COMMAND_SUB_DI_8); // sub edi, 8 break; case OP_STORE2: EmitMovEAXEDI(vm); @@ -601,7 +659,7 @@ void VM_Compile( vm_t *vm, vmHeader_t *header ) { // Emit4( vm->dataMask & ~1 ); EmitString( "66 89 83" ); // mov word ptr [ebx+0x12345678], eax Emit4( (int)vm->dataBase ); - EmitString( "83 EF 08" ); // sub edi, 8 + EmitCommand(LAST_COMMAND_SUB_DI_8); // sub edi, 8 break; case OP_STORE1: EmitMovEAXEDI(vm); @@ -610,11 +668,11 @@ void VM_Compile( vm_t *vm, vmHeader_t *header ) { // Emit4( vm->dataMask ); EmitString( "88 83" ); // mov byte ptr [ebx+0x12345678], eax Emit4( (int)vm->dataBase ); - EmitString( "83 EF 08" ); // sub edi, 8 + EmitCommand(LAST_COMMAND_SUB_DI_8); // sub edi, 8 break; case OP_EQ: - EmitString( "83 EF 08" ); // sub edi,8 + EmitCommand(LAST_COMMAND_SUB_DI_8); // sub edi, 8 EmitString( "8B 47 04" ); // mov eax, dword ptr [edi+4] EmitString( "3B 47 08" ); // cmp eax, dword ptr [edi+8] EmitString( "75 06" ); // jne +6 @@ -624,7 +682,7 @@ void VM_Compile( vm_t *vm, vmHeader_t *header ) { Emit4( (int)vm->instructionPointers + v*4 ); break; case OP_NE: - EmitString( "83 EF 08" ); // sub edi,8 + EmitCommand(LAST_COMMAND_SUB_DI_8); // sub edi, 8 EmitString( "8B 47 04" ); // mov eax, dword ptr [edi+4] EmitString( "3B 47 08" ); // cmp eax, dword ptr [edi+8] EmitString( "74 06" ); // je +6 @@ -634,7 +692,7 @@ void VM_Compile( vm_t *vm, vmHeader_t *header ) { Emit4( (int)vm->instructionPointers + v*4 ); break; case OP_LTI: - EmitString( "83 EF 08" ); // sub edi,8 + EmitCommand(LAST_COMMAND_SUB_DI_8); // sub edi, 8 EmitString( "8B 47 04" ); // mov eax, dword ptr [edi+4] EmitString( "3B 47 08" ); // cmp eax, dword ptr [edi+8] EmitString( "7D 06" ); // jnl +6 @@ -644,7 +702,7 @@ void VM_Compile( vm_t *vm, vmHeader_t *header ) { Emit4( (int)vm->instructionPointers + v*4 ); break; case OP_LEI: - EmitString( "83 EF 08" ); // sub edi,8 + EmitCommand(LAST_COMMAND_SUB_DI_8); // sub edi, 8 EmitString( "8B 47 04" ); // mov eax, dword ptr [edi+4] EmitString( "3B 47 08" ); // cmp eax, dword ptr [edi+8] EmitString( "7F 06" ); // jnle +6 @@ -654,7 +712,7 @@ void VM_Compile( vm_t *vm, vmHeader_t *header ) { Emit4( (int)vm->instructionPointers + v*4 ); break; case OP_GTI: - EmitString( "83 EF 08" ); // sub edi,8 + EmitCommand(LAST_COMMAND_SUB_DI_8); // sub edi, 8 EmitString( "8B 47 04" ); // mov eax, dword ptr [edi+4] EmitString( "3B 47 08" ); // cmp eax, dword ptr [edi+8] EmitString( "7E 06" ); // jng +6 @@ -664,7 +722,7 @@ void VM_Compile( vm_t *vm, vmHeader_t *header ) { Emit4( (int)vm->instructionPointers + v*4 ); break; case OP_GEI: - EmitString( "83 EF 08" ); // sub edi,8 + EmitCommand(LAST_COMMAND_SUB_DI_8); // sub edi, 8 EmitString( "8B 47 04" ); // mov eax, dword ptr [edi+4] EmitString( "3B 47 08" ); // cmp eax, dword ptr [edi+8] EmitString( "7C 06" ); // jnge +6 @@ -674,7 +732,7 @@ void VM_Compile( vm_t *vm, vmHeader_t *header ) { Emit4( (int)vm->instructionPointers + v*4 ); break; case OP_LTU: - EmitString( "83 EF 08" ); // sub edi,8 + EmitCommand(LAST_COMMAND_SUB_DI_8); // sub edi, 8 EmitString( "8B 47 04" ); // mov eax, dword ptr [edi+4] EmitString( "3B 47 08" ); // cmp eax, dword ptr [edi+8] EmitString( "73 06" ); // jnb +6 @@ -684,7 +742,7 @@ void VM_Compile( vm_t *vm, vmHeader_t *header ) { Emit4( (int)vm->instructionPointers + v*4 ); break; case OP_LEU: - EmitString( "83 EF 08" ); // sub edi,8 + EmitCommand(LAST_COMMAND_SUB_DI_8); // sub edi, 8 EmitString( "8B 47 04" ); // mov eax, dword ptr [edi+4] EmitString( "3B 47 08" ); // cmp eax, dword ptr [edi+8] EmitString( "77 06" ); // jnbe +6 @@ -694,7 +752,7 @@ void VM_Compile( vm_t *vm, vmHeader_t *header ) { Emit4( (int)vm->instructionPointers + v*4 ); break; case OP_GTU: - EmitString( "83 EF 08" ); // sub edi,8 + EmitCommand(LAST_COMMAND_SUB_DI_8); // sub edi, 8 EmitString( "8B 47 04" ); // mov eax, dword ptr [edi+4] EmitString( "3B 47 08" ); // cmp eax, dword ptr [edi+8] EmitString( "76 06" ); // jna +6 @@ -704,7 +762,7 @@ void VM_Compile( vm_t *vm, vmHeader_t *header ) { Emit4( (int)vm->instructionPointers + v*4 ); break; case OP_GEU: - EmitString( "83 EF 08" ); // sub edi,8 + EmitCommand(LAST_COMMAND_SUB_DI_8); // sub edi, 8 EmitString( "8B 47 04" ); // mov eax, dword ptr [edi+4] EmitString( "3B 47 08" ); // cmp eax, dword ptr [edi+8] EmitString( "72 06" ); // jnae +6 @@ -714,7 +772,7 @@ void VM_Compile( vm_t *vm, vmHeader_t *header ) { Emit4( (int)vm->instructionPointers + v*4 ); break; case OP_EQF: - EmitString( "83 EF 08" ); // sub edi,8 + EmitCommand(LAST_COMMAND_SUB_DI_8); // sub edi, 8 EmitString( "D9 47 04" ); // fld dword ptr [edi+4] EmitString( "D8 5F 08" ); // fcomp dword ptr [edi+8] EmitString( "DF E0" ); // fnstsw ax @@ -726,7 +784,7 @@ void VM_Compile( vm_t *vm, vmHeader_t *header ) { Emit4( (int)vm->instructionPointers + v*4 ); break; case OP_NEF: - EmitString( "83 EF 08" ); // sub edi,8 + EmitCommand(LAST_COMMAND_SUB_DI_8); // sub edi, 8 EmitString( "D9 47 04" ); // fld dword ptr [edi+4] EmitString( "D8 5F 08" ); // fcomp dword ptr [edi+8] EmitString( "DF E0" ); // fnstsw ax @@ -738,7 +796,7 @@ void VM_Compile( vm_t *vm, vmHeader_t *header ) { Emit4( (int)vm->instructionPointers + v*4 ); break; case OP_LTF: - EmitString( "83 EF 08" ); // sub edi,8 + EmitCommand(LAST_COMMAND_SUB_DI_8); // sub edi, 8 EmitString( "D9 47 04" ); // fld dword ptr [edi+4] EmitString( "D8 5F 08" ); // fcomp dword ptr [edi+8] EmitString( "DF E0" ); // fnstsw ax @@ -750,7 +808,7 @@ void VM_Compile( vm_t *vm, vmHeader_t *header ) { Emit4( (int)vm->instructionPointers + v*4 ); break; case OP_LEF: - EmitString( "83 EF 08" ); // sub edi,8 + EmitCommand(LAST_COMMAND_SUB_DI_8); // sub edi, 8 EmitString( "D9 47 04" ); // fld dword ptr [edi+4] EmitString( "D8 5F 08" ); // fcomp dword ptr [edi+8] EmitString( "DF E0" ); // fnstsw ax @@ -762,7 +820,7 @@ void VM_Compile( vm_t *vm, vmHeader_t *header ) { Emit4( (int)vm->instructionPointers + v*4 ); break; case OP_GTF: - EmitString( "83 EF 08" ); // sub edi,8 + EmitCommand(LAST_COMMAND_SUB_DI_8); // sub edi, 8 EmitString( "D9 47 04" ); // fld dword ptr [edi+4] EmitString( "D8 5F 08" ); // fcomp dword ptr [edi+8] EmitString( "DF E0" ); // fnstsw ax @@ -774,7 +832,7 @@ void VM_Compile( vm_t *vm, vmHeader_t *header ) { Emit4( (int)vm->instructionPointers + v*4 ); break; case OP_GEF: - EmitString( "83 EF 08" ); // sub edi,8 + EmitCommand(LAST_COMMAND_SUB_DI_8); // sub edi, 8 EmitString( "D9 47 04" ); // fld dword ptr [edi+4] EmitString( "D8 5F 08" ); // fcomp dword ptr [edi+8] EmitString( "DF E0" ); // fnstsw ax @@ -791,67 +849,67 @@ void VM_Compile( vm_t *vm, vmHeader_t *header ) { case OP_ADD: EmitMovEAXEDI(vm); // mov eax, dword ptr [edi] EmitString( "01 47 FC" ); // add dword ptr [edi-4],eax - EmitString( "83 EF 04" ); // sub edi,4 + EmitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4 break; case OP_SUB: EmitMovEAXEDI(vm); // mov eax, dword ptr [edi] EmitString( "29 47 FC" ); // sub dword ptr [edi-4],eax - EmitString( "83 EF 04" ); // sub edi,4 + EmitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4 break; case OP_DIVI: EmitString( "8B 47 FC" ); // mov eax,dword ptr [edi-4] EmitString( "99" ); // cdq EmitString( "F7 3F" ); // idiv dword ptr [edi] EmitString( "89 47 FC" ); // mov dword ptr [edi-4],eax - EmitString( "83 EF 04" ); // sub edi,4 + EmitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4 break; case OP_DIVU: EmitString( "8B 47 FC" ); // mov eax,dword ptr [edi-4] EmitString( "33 D2" ); // xor edx, edx EmitString( "F7 37" ); // div dword ptr [edi] EmitString( "89 47 FC" ); // mov dword ptr [edi-4],eax - EmitString( "83 EF 04" ); // sub edi,4 + EmitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4 break; case OP_MODI: EmitString( "8B 47 FC" ); // mov eax,dword ptr [edi-4] EmitString( "99" ); // cdq EmitString( "F7 3F" ); // idiv dword ptr [edi] EmitString( "89 57 FC" ); // mov dword ptr [edi-4],edx - EmitString( "83 EF 04" ); // sub edi,4 + EmitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4 break; case OP_MODU: EmitString( "8B 47 FC" ); // mov eax,dword ptr [edi-4] EmitString( "33 D2" ); // xor edx, edx EmitString( "F7 37" ); // div dword ptr [edi] EmitString( "89 57 FC" ); // mov dword ptr [edi-4],edx - EmitString( "83 EF 04" ); // sub edi,4 + EmitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4 break; case OP_MULI: EmitString( "8B 47 FC" ); // mov eax,dword ptr [edi-4] EmitString( "F7 2F" ); // imul dword ptr [edi] EmitString( "89 47 FC" ); // mov dword ptr [edi-4],eax - EmitString( "83 EF 04" ); // sub edi,4 + EmitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4 break; case OP_MULU: EmitString( "8B 47 FC" ); // mov eax,dword ptr [edi-4] EmitString( "F7 27" ); // mul dword ptr [edi] EmitString( "89 47 FC" ); // mov dword ptr [edi-4],eax - EmitString( "83 EF 04" ); // sub edi,4 + EmitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4 break; case OP_BAND: EmitMovEAXEDI(vm); // mov eax, dword ptr [edi] EmitString( "21 47 FC" ); // and dword ptr [edi-4],eax - EmitString( "83 EF 04" ); // sub edi,4 + EmitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4 break; case OP_BOR: EmitMovEAXEDI(vm); // mov eax, dword ptr [edi] EmitString( "09 47 FC" ); // or dword ptr [edi-4],eax - EmitString( "83 EF 04" ); // sub edi,4 + EmitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4 break; case OP_BXOR: EmitMovEAXEDI(vm); // mov eax, dword ptr [edi] EmitString( "31 47 FC" ); // xor dword ptr [edi-4],eax - EmitString( "83 EF 04" ); // sub edi,4 + EmitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4 break; case OP_BCOM: EmitString( "F7 17" ); // not dword ptr [edi] @@ -859,17 +917,17 @@ void VM_Compile( vm_t *vm, vmHeader_t *header ) { case OP_LSH: EmitString( "8B 0F" ); // mov ecx, dword ptr [edi] EmitString( "D3 67 FC" ); // shl dword ptr [edi-4], cl - EmitString( "83 EF 04" ); // sub edi,4 + EmitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4 break; case OP_RSHI: EmitString( "8B 0F" ); // mov ecx, dword ptr [edi] EmitString( "D3 7F FC" ); // sar dword ptr [edi-4], cl - EmitString( "83 EF 04" ); // sub edi,4 + EmitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4 break; case OP_RSHU: EmitString( "8B 0F" ); // mov ecx, dword ptr [edi] EmitString( "D3 6F FC" ); // shr dword ptr [edi-4], cl - EmitString( "83 EF 04" ); // sub edi,4 + EmitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4 break; case OP_NEGF: EmitString( "D9 07" ); // fld dword ptr [edi] @@ -880,22 +938,22 @@ void VM_Compile( vm_t *vm, vmHeader_t *header ) { EmitString( "D9 47 FC" ); // fld dword ptr [edi-4] EmitString( "D8 07" ); // fadd dword ptr [edi] EmitString( "D9 5F FC" ); // fstp dword ptr [edi-4] - EmitString( "83 EF 04" ); // sub edi,4 + EmitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4 break; case OP_SUBF: - EmitString( "83 EF 04" ); // sub edi,4 + EmitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4 EmitString( "D9 07" ); // fld dword ptr [edi] EmitString( "D8 67 04" ); // fsub dword ptr [edi+4] EmitString( "D9 1F" ); // fstp dword ptr [edi] break; case OP_DIVF: - EmitString( "83 EF 04" ); // sub edi,4 + EmitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4 EmitString( "D9 07" ); // fld dword ptr [edi] EmitString( "D8 77 04" ); // fdiv dword ptr [edi+4] EmitString( "D9 1F" ); // fstp dword ptr [edi] break; case OP_MULF: - EmitString( "83 EF 04" ); // sub edi,4 + EmitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4 EmitString( "D9 07" ); // fld dword ptr [edi] EmitString( "D8 4f 04" ); // fmul dword ptr [edi+4] EmitString( "D9 1F" ); // fstp dword ptr [edi] @@ -914,16 +972,16 @@ void VM_Compile( vm_t *vm, vmHeader_t *header ) { EmitString( "D9 07" ); // fld dword ptr [edi] EmitString( "FF 15" ); // call ftolPtr Emit4( (int)&ftolPtr ); - EmitString( "89 07" ); // mov dword ptr [edi], eax + EmitCommand(LAST_COMMAND_MOV_EDI_EAX); // mov dword ptr [edi], eax #endif break; case OP_SEX8: EmitString( "0F BE 07" ); // movsx eax, byte ptr [edi] - EmitString( "89 07" ); // mov dword ptr [edi], eax + EmitCommand(LAST_COMMAND_MOV_EDI_EAX); // mov dword ptr [edi], eax break; case OP_SEX16: EmitString( "0F BF 07" ); // movsx eax, word ptr [edi] - EmitString( "89 07" ); // mov dword ptr [edi], eax + EmitCommand(LAST_COMMAND_MOV_EDI_EAX); // mov dword ptr [edi], eax break; case OP_BLOCK_COPY: @@ -945,11 +1003,11 @@ void VM_Compile( vm_t *vm, vmHeader_t *header ) { EmitString( "F3 A5" ); // rep movsd EmitString( "5F" ); // pop edi EmitString( "5E" ); // pop esi - EmitString( "83 EF 08" ); // sub edi,8 + EmitCommand(LAST_COMMAND_SUB_DI_8); // sub edi, 8 break; case OP_JUMP: - EmitString( "83 EF 04" ); // sub edi,4 + EmitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4 EmitString( "8B 47 04" ); // mov eax,dword ptr [edi+4] // FIXME: range check EmitString( "FF 24 85" ); // jmp dword ptr [instructionPointers + eax * 4] @@ -962,13 +1020,14 @@ void VM_Compile( vm_t *vm, vmHeader_t *header ) { pop1 = op; } } + // copy to an exact size buffer on the hunk vm->codeLength = compiledOfs; vm->codeBase = (unsigned char *)Hunk_Alloc( compiledOfs, h_low ); Com_Memcpy( vm->codeBase, buf, compiledOfs ); Z_Free( buf ); Z_Free( jused ); - Com_Printf( "VM file %s compiled to %i bytes of code\n", vm->name, compiledOfs ); + Com_Printf( "VM file %s compiled to %i bytes of code\n", vm->name, compiledOfs); // offset all the instruction pointers for the new location for ( i = 0 ; i < header->instructionCount ; i++ ) { diff --git a/CODE-mp/qcommon/vssver.scc b/CODE-mp/qcommon/vssver.scc index ae662b6..058b9aa 100644 Binary files a/CODE-mp/qcommon/vssver.scc and b/CODE-mp/qcommon/vssver.scc differ diff --git a/CODE-mp/renderer/tr_bsp.cpp b/CODE-mp/renderer/tr_bsp.cpp index 083ce3c..fcb6f17 100644 --- a/CODE-mp/renderer/tr_bsp.cpp +++ b/CODE-mp/renderer/tr_bsp.cpp @@ -1771,6 +1771,32 @@ void R_LoadLightGrid( lump_t *l ) { R_ColorShiftLightingBytes(w->lightGridData[i].directLight[j]); } } + + if (r_newDLights->integer) + { + // Precalc soe data to speed up R_SetupEntityLightingGrid + w->lightGridStep[0] = 1; + w->lightGridStep[1] = w->lightGridBounds[0]; + w->lightGridStep[2] = w->lightGridBounds[0] * w->lightGridBounds[1]; + + for(i = 0; i < 8; i++) + { + w->lightGridOffsets[i] = 0; + + if(i & 1) + { + w->lightGridOffsets[i] += w->lightGridStep[0]; + } + if(i & 2) + { + w->lightGridOffsets[i] += w->lightGridStep[1]; + } + if(i & 4) + { + w->lightGridOffsets[i] += w->lightGridStep[2]; + } + } + } } /* diff --git a/CODE-mp/renderer/tr_font.cpp b/CODE-mp/renderer/tr_font.cpp index 03e7633..89112ee 100644 --- a/CODE-mp/renderer/tr_font.cpp +++ b/CODE-mp/renderer/tr_font.cpp @@ -38,11 +38,7 @@ typedef map fontIndexMap_t; #define KSC5601_HANGUL_LOBYTE_HIBOUND 0xFF // ...bounding (ie only valid in between these points, but NULLs in charsets for these codes) #define KSC5601_HANGUL_CODES_PER_ROW 96 // 2 more than the number of glyphs -//extern qboolean Language_IsKorean( void ); -qboolean Language_IsKorean( void ) -{ - return qfalse; // multiplayer does not support asian languages -} +extern qboolean Language_IsKorean( void ); static inline bool Korean_ValidKSC5601Hangul( byte _iHi, byte _iLo ) { @@ -75,6 +71,13 @@ static int Korean_CollapseKSC5601HangulCode(unsigned int uiCode) return 0; } +static int Korean_InitFields(int &iGlyphTPs, LPCSTR &psLang) +{ + psLang = "kor"; + iGlyphTPs = GLYPH_MAX_KOREAN_SHADERS; + return 32; // m_iAsianGlyphsAcross +} + // ======================== some taiwanese stuff ============================== // (all ranges inclusive for Big5)... @@ -89,16 +92,13 @@ static int Korean_CollapseKSC5601HangulCode(unsigned int uiCode) #define BIG5_LOBYTE_HIBOUND1 0xFE // #define BIG5_CODES_PER_ROW 160 // 3 more than the number of glyphs -//extern qboolean Language_IsTaiwanese( void ); -qboolean Language_IsTaiwanese( void ) -{ - return qfalse; // multiplayer does not support asian languages -} +extern qboolean Language_IsTaiwanese( void ); static bool Taiwanese_ValidBig5Code( unsigned int uiCode ) { - if ( (uiCode >= ((BIG5_HIBYTE_START0<<8)|BIG5_LOBYTE_LOBOUND0) && uiCode <= ((BIG5_HIBYTE_STOP0<<8)|BIG5_LOBYTE_HIBOUND0)) - || (uiCode >= ((BIG5_HIBYTE_START1<<8)|BIG5_LOBYTE_LOBOUND0) && uiCode <= ((BIG5_HIBYTE_STOP1<<8)|0xD5)) // no meaningful equate for this, it's just end-of-glyphs for highest row + const byte _iHi = (uiCode >> 8)&0xFF; + if ( (_iHi >= BIG5_HIBYTE_START0 && _iHi <= BIG5_HIBYTE_STOP0) + || (_iHi >= BIG5_HIBYTE_START1 && _iHi <= BIG5_HIBYTE_STOP1) ) { const byte _iLo = uiCode & 0xFF; @@ -115,6 +115,23 @@ static bool Taiwanese_ValidBig5Code( unsigned int uiCode ) } +// only call this when Taiwanese_ValidBig5Code() has already returned true... +// +static bool Taiwanese_IsTrailingPunctuation( unsigned int uiCode ) +{ + // so far I'm just counting the first 21 chars, those seem to be all the basic punctuation... + // + if ( uiCode >= ((BIG5_HIBYTE_START0<<8)|BIG5_LOBYTE_LOBOUND0) && + uiCode < ((BIG5_HIBYTE_START0<<8)|BIG5_LOBYTE_LOBOUND0+20) + ) + { + return true; + } + + return false; +} + + // takes a BIG5 double-byte code (including level 2 hanzi) and collapses down to a 0..n glyph index... // Assumes rows are 160 wide (glyph slots), not 157 wide (actual glyphs), so I can ignore boundary markers // @@ -135,6 +152,106 @@ static int Taiwanese_CollapseBig5Code( unsigned int uiCode ) return 0; } +static int Taiwanese_InitFields(int &iGlyphTPs, LPCSTR &psLang) +{ + psLang = "tai"; + iGlyphTPs = GLYPH_MAX_TAIWANESE_SHADERS; + return 64; // m_iAsianGlyphsAcross +} + +// ======================== some Japanese stuff ============================== + + +// ( all ranges inclusive for Shift-JIS ) +// +#define SHIFTJIS_HIBYTE_START0 0x81 +#define SHIFTJIS_HIBYTE_STOP0 0x9F +#define SHIFTJIS_HIBYTE_START1 0xE0 +#define SHIFTJIS_HIBYTE_STOP1 0xEF +// +#define SHIFTJIS_LOBYTE_START0 0x40 +#define SHIFTJIS_LOBYTE_STOP0 0x7E +#define SHIFTJIS_LOBYTE_START1 0x80 +#define SHIFTJIS_LOBYTE_STOP1 0xFC +#define SHIFTJIS_CODES_PER_ROW (((SHIFTJIS_LOBYTE_STOP0-SHIFTJIS_LOBYTE_START0)+1)+((SHIFTJIS_LOBYTE_STOP1-SHIFTJIS_LOBYTE_START1)+1)) + + +extern qboolean Language_IsJapanese( void ); + +static bool Japanese_ValidShiftJISCode( byte _iHi, byte _iLo ) +{ + if ( (_iHi >= SHIFTJIS_HIBYTE_START0 && _iHi <= SHIFTJIS_HIBYTE_STOP0) + || (_iHi >= SHIFTJIS_HIBYTE_START1 && _iHi <= SHIFTJIS_HIBYTE_STOP1) + ) + { + if ( (_iLo >= SHIFTJIS_LOBYTE_START0 && _iLo <= SHIFTJIS_LOBYTE_STOP0) || + (_iLo >= SHIFTJIS_LOBYTE_START1 && _iLo <= SHIFTJIS_LOBYTE_STOP1) + ) + { + return true; + } + } + + return false; +} + +static inline bool Japanese_ValidShiftJISCode( unsigned int uiCode ) +{ + return Japanese_ValidShiftJISCode( uiCode >> 8, uiCode & 0xFF ); +} + + +// only call this when Japanese_ValidShiftJISCode() has already returned true... +// +static bool Japanese_IsTrailingPunctuation( unsigned int uiCode ) +{ + // so far I'm just counting the first 18 chars, those seem to be all the basic punctuation... + // + if ( uiCode >= ((SHIFTJIS_HIBYTE_START0<<8)|SHIFTJIS_LOBYTE_START0) && + uiCode < ((SHIFTJIS_HIBYTE_START0<<8)|SHIFTJIS_LOBYTE_START0+18) + ) + { + return true; + } + + return false; +} + + +// takes a ShiftJIS double-byte code and collapse down to a 0..n glyph index... +// +// (invalid codes will return 0) +// +static int Japanese_CollapseShiftJISCode( unsigned int uiCode ) +{ + if (Japanese_ValidShiftJISCode( uiCode )) + { + uiCode -= ((SHIFTJIS_HIBYTE_START0<<8)|SHIFTJIS_LOBYTE_START0); // sneaky maths on both bytes, reduce to 0x0000 onwards + + if ( (uiCode & 0xFF) >= (SHIFTJIS_LOBYTE_START1)-SHIFTJIS_LOBYTE_START0) + { + uiCode -= ((SHIFTJIS_LOBYTE_START1)-SHIFTJIS_LOBYTE_STOP0)-1; + } + + if ( ((uiCode>>8)&0xFF) >= (SHIFTJIS_HIBYTE_START1)-SHIFTJIS_HIBYTE_START0) + { + uiCode -= (((SHIFTJIS_HIBYTE_START1)-SHIFTJIS_HIBYTE_STOP0)-1) << 8; + } + + uiCode = ((uiCode >> 8) * SHIFTJIS_CODES_PER_ROW) + (uiCode & 0xFF); + + return uiCode; + } + return 0; +} + + +static int Japanese_InitFields(int &iGlyphTPs, LPCSTR &psLang) +{ + psLang = "jap"; + iGlyphTPs = GLYPH_MAX_JAPANESE_SHADERS; + return 64; // m_iAsianGlyphsAcross +} // ============================================================================ @@ -142,29 +259,101 @@ static int Taiwanese_CollapseBig5Code( unsigned int uiCode ) // takes char *, returns integer char at that point, and advances char * on by enough bytes to move // past the letter (either western 1 byte or Asian multi-byte)... // -unsigned int AnyLanguage_ReadCharFromString( const char **ppsText ) +// looks messy, but the actual execution route is quite short, so it's fast... +// +unsigned int AnyLanguage_ReadCharFromString( const char *psText, int *piAdvanceCount, qboolean *pbIsTrailingPunctuation /* = NULL */) { - const byte *psString = (const byte *) *ppsText; // avoid sign-promote bug + const byte *psString = (const byte *) psText; // avoid sign-promote bug unsigned int uiLetter; - // at some stage I can put other MBCS languages here I guess, but for now... - // - if ( (Language_IsKorean() && Korean_ValidKSC5601Hangul( psString[0], psString[1] )) || - (Language_IsTaiwanese()&& Taiwanese_ValidBig5Code ((psString[0] * 256) + psString[1])) - ) + if ( Language_IsKorean() ) { - uiLetter = (psString[0] * 256) + psString[1]; - *ppsText += 2; + if ( Korean_ValidKSC5601Hangul( psString[0], psString[1] )) + { + uiLetter = (psString[0] * 256) + psString[1]; + *piAdvanceCount = 2; + + // not going to bother testing for korean punctuation here, since korean already + // uses spaces, and I don't have the punctuation glyphs defined, only the basic 2350 hanguls + // + if ( pbIsTrailingPunctuation) + { + *pbIsTrailingPunctuation = qfalse; + } + + return uiLetter; + } } else + if ( Language_IsTaiwanese() ) { - uiLetter = psString[0]; - *ppsText += 1; // NOT ++ + if ( Taiwanese_ValidBig5Code( (psString[0] * 256) + psString[1] )) + { + uiLetter = (psString[0] * 256) + psString[1]; + *piAdvanceCount = 2; + + // need to ask if this is a trailing (ie like a comma or full-stop) punctuation?... + // + if ( pbIsTrailingPunctuation) + { + *pbIsTrailingPunctuation = Taiwanese_IsTrailingPunctuation( uiLetter ) ? qtrue : qfalse; + } + + return uiLetter; + } + } + else + if ( Language_IsJapanese() ) + { + if ( Japanese_ValidShiftJISCode( psString[0], psString[1] )) + { + uiLetter = (psString[0] * 256) + psString[1]; + *piAdvanceCount = 2; + + // need to ask if this is a trailing (ie like a comma or full-stop) punctuation?... + // + if ( pbIsTrailingPunctuation) + { + *pbIsTrailingPunctuation = Japanese_IsTrailingPunctuation( uiLetter ) ? qtrue : qfalse; + } + + return uiLetter; + } + } + + // ... must not have been an MBCS code... + // + uiLetter = psString[0]; + *piAdvanceCount = 1; + + if (pbIsTrailingPunctuation) + { + *pbIsTrailingPunctuation = (uiLetter == '!' || + uiLetter == '?' || + uiLetter == ',' || + uiLetter == '.' || + uiLetter == ';' || + uiLetter == ':' + ) ? qtrue : qfalse; } return uiLetter; } +// needed for subtitle printing since original code no longer worked once camera bar height was changed to 480/10 +// rather than refdef height / 10. I now need to bodge the coords to come out right. +// +qboolean Language_IsAsian(void) +{ + return (Language_IsKorean() || Language_IsTaiwanese() || Language_IsJapanese()) ? qtrue : qfalse; +} + +qboolean Language_UsesSpaces(void) +{ + return (!(Language_IsTaiwanese() || Language_IsJapanese())) ? qtrue : qfalse; +} + + // ====================================================================== CFontInfo::CFontInfo(const char *fontName) @@ -210,11 +399,7 @@ CFontInfo::CFontInfo(const char *fontName) fontArray[fontIndex++] = this; } -//extern int Language_GetIntegerValue(void); -static int Language_GetIntegerValue(void) -{ - return 0; // irrlevant in this codebase since multiplayer doesn't support asian chars -} +extern int Language_GetIntegerValue(void); void CFontInfo::UpdateAsianIfNeeded( bool bForceReEval /* = false */ ) { @@ -224,8 +409,9 @@ void CFontInfo::UpdateAsianIfNeeded( bool bForceReEval /* = false */ ) { qboolean bKorean = Language_IsKorean(); qboolean bTaiwanese = Language_IsTaiwanese(); + qboolean bJapanese = Language_IsJapanese(); - if (bKorean || bTaiwanese) + if (bKorean || bTaiwanese || bJapanese) { const int iThisLanguage = Language_GetIntegerValue(); @@ -240,16 +426,17 @@ void CFontInfo::UpdateAsianIfNeeded( bool bForceReEval /* = false */ ) if (bKorean) { - iGlyphTPs = GLYPH_MAX_KOREAN_SHADERS; - psLang = "kor"; - m_iAsianGlyphsAcross = 32; // hardwired for now (only one glyph set), may change later + m_iAsianGlyphsAcross = Korean_InitFields(iGlyphTPs, psLang); } else if (bTaiwanese) { - iGlyphTPs = GLYPH_MAX_TAIWANESE_SHADERS; - psLang = "tai"; - m_iAsianGlyphsAcross = 64; // hardwired for now (only one glyph set), may change later + m_iAsianGlyphsAcross = Taiwanese_InitFields(iGlyphTPs, psLang); + } + else + if (bJapanese) + { + m_iAsianGlyphsAcross = Japanese_InitFields(iGlyphTPs, psLang); } @@ -289,7 +476,7 @@ void CFontInfo::UpdateAsianIfNeeded( bool bForceReEval /* = false */ ) // m_AsianGlyph.width = iCappedHeight; // square Asian chars same size as height of western set m_AsianGlyph.height = iCappedHeight; // "" - m_AsianGlyph.horizAdvance = iCappedHeight + (bTaiwanese?3:-1); // Asian chars contain a small amount of space in the glyph + m_AsianGlyph.horizAdvance = iCappedHeight + ((bTaiwanese||bJapanese)?3:-1); // Asian chars contain a small amount of space in the glyph m_AsianGlyph.horizOffset = 0; // "" // .. or you can use the mKoreanHack value (which is the same number as the calc below) m_AsianGlyph.baseline = mAscender + ((iCappedHeight - mHeight) >> 1); @@ -311,7 +498,7 @@ void CFontInfo::UpdateAsianIfNeeded( bool bForceReEval /* = false */ ) } // needed to add *piShader param because of multiple TPs, -// if not passed in, then I also skip S,T calculations for re-usable static korean glyphinfo struct... +// if not passed in, then I also skip S,T calculations for re-usable static asian glyphinfo struct... // const glyphInfo_t *CFontInfo::GetLetter(const unsigned int uiLetter, int *piShader /* = NULL */) { @@ -319,7 +506,19 @@ const glyphInfo_t *CFontInfo::GetLetter(const unsigned int uiLetter, int *piShad { int iCollapsedAsianCode = 0; - qboolean bTaiHack = qfalse; + // small definition private to this module, I don't normally use language numbers in this module but switch-case is more useful. + // This is for a small set of hacks to do with onconsistant windows glyph placement...(sigh) + // + typedef enum + { + eDefault, + //eKorean, + eTaiwanese, // 15x15 glyphs tucked against BR of 16x16 space + eJapanese // 15x15 glyphs tucked against TL of 16x16 space + } Language_e; + + Language_e eLanguage = eDefault; + if ( Language_IsKorean() ) { iCollapsedAsianCode = Korean_CollapseKSC5601HangulCode( uiLetter ); @@ -328,7 +527,13 @@ const glyphInfo_t *CFontInfo::GetLetter(const unsigned int uiLetter, int *piShad if ( Language_IsTaiwanese() ) { iCollapsedAsianCode = Taiwanese_CollapseBig5Code( uiLetter ); - bTaiHack = qtrue; + eLanguage = eTaiwanese; + } + else + if ( Language_IsJapanese() ) + { + iCollapsedAsianCode = Japanese_CollapseShiftJISCode( uiLetter ); + eLanguage = eJapanese; } if (iCollapsedAsianCode) @@ -353,23 +558,37 @@ const glyphInfo_t *CFontInfo::GetLetter(const unsigned int uiLetter, int *piShad const bool bHalfT = (iTexturePageIndex == (m_iAsianPagesLoaded - 1) && m_bAsianLastPageHalfHeight); const int iAsianGlyphsDown = (bHalfT) ? m_iAsianGlyphsAcross / 2 : m_iAsianGlyphsAcross; - if (!bTaiHack) + switch (eLanguage) { - // standard... - // - m_AsianGlyph.s = (float)( iColumn ) / (float)m_iAsianGlyphsAcross; - m_AsianGlyph.t = (float)( iRow ) / (float) iAsianGlyphsDown; - } - else - { - // special hack for Taiwanese stuff to avoid GL-bleed... - // - m_AsianGlyph.s = (float)(((1024 / m_iAsianGlyphsAcross) * ( iColumn ))+1) / 1024.0f; - m_AsianGlyph.t = (float)(((1024 / iAsianGlyphsDown ) * ( iRow ))+1) / 1024.0f; - } - m_AsianGlyph.s2 = (float)( iColumn + 1) / (float)m_iAsianGlyphsAcross; - m_AsianGlyph.t2 = (float)( iRow + 1 ) / (float) iAsianGlyphsDown; + default: + { + // standard (also Korean)... + // + m_AsianGlyph.s = (float)( iColumn ) / (float)m_iAsianGlyphsAcross; + m_AsianGlyph.t = (float)( iRow ) / (float) iAsianGlyphsDown; + m_AsianGlyph.s2 = (float)( iColumn + 1) / (float)m_iAsianGlyphsAcross; + m_AsianGlyph.t2 = (float)( iRow + 1 ) / (float) iAsianGlyphsDown; + } + break; + case eTaiwanese: + { + m_AsianGlyph.s = (float)(((1024 / m_iAsianGlyphsAcross) * ( iColumn ))+1) / 1024.0f; + m_AsianGlyph.t = (float)(((1024 / iAsianGlyphsDown ) * ( iRow ))+1) / 1024.0f; + m_AsianGlyph.s2 = (float)(((1024 / m_iAsianGlyphsAcross) * ( iColumn+1 )) ) / 1024.0f; + m_AsianGlyph.t2 = (float)(((1024 / iAsianGlyphsDown ) * ( iRow+1 )) ) / 1024.0f; + } + break; + + case eJapanese: + { + m_AsianGlyph.s = (float)(((1024 / m_iAsianGlyphsAcross) * ( iColumn )) ) / 1024.0f; + m_AsianGlyph.t = (float)(((1024 / iAsianGlyphsDown ) * ( iRow )) ) / 1024.0f; + m_AsianGlyph.s2 = (float)(((1024 / m_iAsianGlyphsAcross) * ( iColumn+1 ))-1) / 1024.0f; + m_AsianGlyph.t2 = (float)(((1024 / iAsianGlyphsDown ) * ( iRow+1 ))-1) / 1024.0f; + } + break; + } *piShader = m_hAsianShaders[ iTexturePageIndex ]; } return &m_AsianGlyph; @@ -384,6 +603,7 @@ const glyphInfo_t *CFontInfo::GetLetter(const unsigned int uiLetter, int *piShad return(mGlyphs + (uiLetter & 0xff)); } + const int CFontInfo::GetAsianCode(ulong uiLetter) const { int iCollapsedAsianCode = 0; @@ -399,11 +619,17 @@ const int CFontInfo::GetAsianCode(ulong uiLetter) const { iCollapsedAsianCode = Taiwanese_CollapseBig5Code( uiLetter ); } + else + if ( Language_IsJapanese() ) + { + iCollapsedAsianCode = Japanese_CollapseShiftJISCode( uiLetter ); + } } return iCollapsedAsianCode; } + const int CFontInfo::GetLetterWidth(unsigned int uiLetter) const { if ( GetAsianCode(uiLetter) ) @@ -454,40 +680,36 @@ CFontInfo *GetFont(int index) int RE_Font_StrLenPixels(const char *psText, const int iFontHandle, const float fScale) { - int x = 0, i = 0, r = 0; - CFontInfo *curfont; - char parseText[2048]; + int x = 0; - //It gets confused about ^blah here too and reports an inaccurate length as a result - while (psText[i] && r < 2048) - { - if (psText[i] == '^') - { - if ( (i < 1 || psText[i-1] != '^') && - (!psText[i+1] || psText[i+1] != '^') ) - { //If char before or after ^ is ^ then it prints ^ instead of accepting a colorcode - i += 2; - } - } - - parseText[r] = psText[i]; - r++; - i++; - } - parseText[r] = 0; - - const char *constParseText = parseText; - - curfont = GetFont(iFontHandle); + CFontInfo *curfont = curfont = GetFont(iFontHandle); if(!curfont) { return(0); } - while(*constParseText) - { - int a = curfont->GetLetterHorizAdvance( AnyLanguage_ReadCharFromString( &constParseText )); - x += Round ( a * fScale ); + float fScaleA = fScale; + if (Language_IsAsian()) + { + fScaleA = fScale * 0.75f; + } + + while(*psText) + { + int iAdvanceCount; + unsigned int uiLetter = AnyLanguage_ReadCharFromString( psText, &iAdvanceCount, NULL ); + psText += iAdvanceCount; + + if (uiLetter == '^' && *psText >= '0' && *psText <= '7') + { + // then this is colour, so skip it from width considerations + } + else + { + int a = curfont->GetLetterHorizAdvance( uiLetter ); + + x += Round ( a * ((uiLetter > 255) ? fScaleA : fScale) ); + } } return(x); @@ -505,7 +727,11 @@ int RE_Font_StrLenChars(const char *psText) { // in other words, colour codes and CR/LF don't count as chars, all else does... // - switch (AnyLanguage_ReadCharFromString( &psText )) + int iAdvanceCount; + unsigned int uiChar = AnyLanguage_ReadCharFromString( psText, &iAdvanceCount, NULL ); + psText += iAdvanceCount; + + switch (uiChar) { case '^': psText++; break; // colour code (note next-char skip) case 10: break; // linefeed @@ -531,6 +757,7 @@ int RE_Font_HeightPixels(const int iFontHandle, const float fScale) // iCharLimit is -1 for "all of string", else MBCS char count... // +qboolean gbInShadow = qfalse; // MUST default to this void RE_Font_DrawString(int ox, int oy, const char *psText, const float *rgba, const int iFontHandle, int iCharLimit, const float fScale) { int x, y, colour, offset; @@ -561,35 +788,26 @@ void RE_Font_DrawString(int ox, int oy, const char *psText, const float *rgba, c { return; } + + float fScaleA = fScale; + int iAsianYAdjust = 0; + if (Language_IsAsian()) + { + fScaleA = fScale * 0.75f; + iAsianYAdjust = /*Round*/((((float)curfont->GetPointSize() * fScale) - ((float)curfont->GetPointSize() * fScaleA))/2); + } + // Draw a dropshadow if required if(iFontHandle & STYLE_DROPSHADOW) { - int i = 0, r = 0; - char dropShadowText[1024]; static const vec4_t v4DKGREY2 = {0.15f, 0.15f, 0.15f, 1}; offset = Round(curfont->GetPointSize() * fScale * 0.075f); - - //^blah stuff confuses shadows, so parse it out first - while (psText[i] && r < 1024) - { - if (psText[i] == '^') - { - if ( (i < 1 || psText[i-1] != '^') && - (!psText[i+1] || psText[i+1] != '^') ) - { //If char before or after ^ is ^ then it prints ^ instead of accepting a colorcode - i += 2; - } - } - - dropShadowText[r] = psText[i]; - r++; - i++; - } - dropShadowText[r] = 0; - RE_Font_DrawString(ox + offset, oy + offset, dropShadowText, v4DKGREY2, iFontHandle & SET_MASK, iCharLimit, fScale); + gbInShadow = qtrue; + RE_Font_DrawString(ox + offset, oy + offset, psText, v4DKGREY2, iFontHandle & SET_MASK, iCharLimit, fScale); + gbInShadow = qfalse; } RE_SetColor( rgba ); @@ -599,20 +817,30 @@ void RE_Font_DrawString(int ox, int oy, const char *psText, const float *rgba, c while(*psText) { + int iAdvanceCount; qbThisCharCountsAsLetter = qfalse; + + unsigned int uiLetter = AnyLanguage_ReadCharFromString(psText, &iAdvanceCount, NULL); // 'psText' ptr has been advanced now + psText += iAdvanceCount; - unsigned int uiLetter = AnyLanguage_ReadCharFromString(&psText); // 'psText' ptr has been advanced now switch( uiLetter ) { case '^': - { + { colour = ColorIndex(*psText++); - RE_SetColor( g_color_table[colour] ); + if (!gbInShadow) + { + RE_SetColor( g_color_table[colour] ); } - break; + } + break; case 10: //linefeed x = ox; oy += Round(curfont->GetPointSize() * fScale); +// if (Language_IsAsian()) +// { +// oy += 4; // this only comes into effect when playing in asian (for SP, though I'm going to keep it in MP probbly) "A long time ago in a galaxy" etc, all other text is line-broken in feeder functions +// } break; case 13: // Return break; @@ -634,12 +862,13 @@ void RE_Font_DrawString(int ox, int oy, const char *psText, const float *rgba, c // // this 'mbRoundCalcs' stuff is crap, but the only way to make the font code work. Sigh... // - y = oy - (curfont->mbRoundCalcs ? Round(pLetter->baseline * fScale) : pLetter->baseline * fScale); + float fThisScale = uiLetter > 255 ? fScaleA : fScale; + y = oy - (curfont->mbRoundCalcs ? Round(pLetter->baseline * fThisScale) : pLetter->baseline * fThisScale); - RE_StretchPic ( x + Round(pLetter->horizOffset * fScale), // float x - y, // float y - curfont->mbRoundCalcs ? Round(pLetter->width * fScale) : pLetter->width * fScale, // float w - curfont->mbRoundCalcs ? Round(pLetter->height * fScale) : pLetter->height * fScale, // float h + RE_StretchPic ( x + Round(pLetter->horizOffset * fThisScale), // float x + (uiLetter > 255) ? y - iAsianYAdjust : y, // float y + curfont->mbRoundCalcs ? Round(pLetter->width * fThisScale) : pLetter->width * fThisScale, // float w + curfont->mbRoundCalcs ? Round(pLetter->height * fThisScale) : pLetter->height * fThisScale, // float h pLetter->s, // float s1 pLetter->t, // float t1 pLetter->s2, // float s2 @@ -648,7 +877,7 @@ void RE_Font_DrawString(int ox, int oy, const char *psText, const float *rgba, c hShader // qhandle_t hShader ); - x += Round(pLetter->horizAdvance * fScale); + x += Round(pLetter->horizAdvance * fThisScale); break; } diff --git a/CODE-mp/renderer/tr_font.h b/CODE-mp/renderer/tr_font.h index 351da05..a504fa1 100644 --- a/CODE-mp/renderer/tr_font.h +++ b/CODE-mp/renderer/tr_font.h @@ -9,6 +9,7 @@ #define GLYPH_MAX_KOREAN_SHADERS 3 #define GLYPH_MAX_TAIWANESE_SHADERS 4 +#define GLYPH_MAX_JAPANESE_SHADERS 3 #define GLYPH_MAX_ASIAN_SHADERS 4 // this MUST equal the larger of the above defines class CFontInfo @@ -69,7 +70,9 @@ int RE_Font_StrLenPixels(const char *psText, const int iFontHandle, const float int RE_Font_StrLenChars(const char *psText); int RE_Font_HeightPixels(const int iFontHandle, const float fScale = 1.0f); void RE_Font_DrawString(int ox, int oy, const char *psText, const float *rgba, const int iFontHandle, int iCharLimit, const float fScale = 1.0f); -unsigned int AnyLanguage_ReadCharFromString( const char **ppsText ); +qboolean Language_IsAsian(void); +qboolean Language_UsesSpaces(void); +unsigned int AnyLanguage_ReadCharFromString( const char *psText, int *piAdvanceCount, qboolean *pbIsTrailingPunctuation/* = NULL*/ ); diff --git a/CODE-mp/renderer/tr_ghoul2.cpp b/CODE-mp/renderer/tr_ghoul2.cpp index f41305b..f503918 100644 --- a/CODE-mp/renderer/tr_ghoul2.cpp +++ b/CODE-mp/renderer/tr_ghoul2.cpp @@ -1610,6 +1610,7 @@ R_AddGHOULSurfaces */ void R_AddGhoulSurfaces( trRefEntity_t *ent ) { +#ifndef DEDICATED mdxaHeader_t *aHeader; shader_t *cust_shader = 0; int fogNum = 0; @@ -1625,8 +1626,8 @@ void R_AddGhoulSurfaces( trRefEntity_t *ent ) { bool setNewOrigin = false; CGhoul2Info_v &ghoul2 = *((CGhoul2Info_v *)ent->e.ghoul2); - // if we don't want server ghoul2 models and this is one, or we just don't want ghoul2 models at all, then return - if ((r_noServerGhoul2->integer && !(ghoul2[0].mCreationID & WF_CLIENTONLY)) || (r_noGhoul2->integer)) + // if we don't want server ghoul2 models and this is one, then return + if ((r_noServerGhoul2->integer && !(ghoul2[0].mCreationID & WF_CLIENTONLY)) ) { return; } @@ -1668,7 +1669,19 @@ void R_AddGhoulSurfaces( trRefEntity_t *ent ) { VectorNormalize((float*)&ghoul2[i].mBltlist[ghoul2[i].mNewOrigin].position.matrix[1]); VectorNormalize((float*)&ghoul2[i].mBltlist[ghoul2[i].mNewOrigin].position.matrix[2]); mdxaBone_t tempMatrix; - Inverse_Matrix(&ghoul2[i].mBltlist[ghoul2[i].mNewOrigin].position, &tempMatrix); + tempMatrix.matrix[0][0]=1.0f; + tempMatrix.matrix[0][1]=0.0f; + tempMatrix.matrix[0][2]=0.0f; + tempMatrix.matrix[0][3]=-ghoul2[i].mBltlist[ghoul2[i].mNewOrigin].position.matrix[0][3]; + tempMatrix.matrix[1][0]=0.0f; + tempMatrix.matrix[1][1]=1.0f; + tempMatrix.matrix[1][2]=0.0f; + tempMatrix.matrix[1][3]=-ghoul2[i].mBltlist[ghoul2[i].mNewOrigin].position.matrix[1][3]; + tempMatrix.matrix[2][0]=0.0f; + tempMatrix.matrix[2][1]=0.0f; + tempMatrix.matrix[2][2]=1.0f; + tempMatrix.matrix[2][3]=-ghoul2[i].mBltlist[ghoul2[i].mNewOrigin].position.matrix[2][3]; + //Inverse_Matrix(&ghoul2[i].mBltlist[ghoul2[i].mNewOrigin].position, &tempMatrix); Multiply_3x4Matrix(&rootMatrix, &tempMatrix, (mdxaBone_t*)&identityMatrix); setNewOrigin = true; @@ -1873,9 +1886,7 @@ void R_AddGhoulSurfaces( trRefEntity_t *ent ) { else { // start the walk of the surface hierarchy CRenderSurface RS(ghoul2[i].mSurfaceRoot, ghoul2[i].mSlist, cust_shader, fogNum, personalModel, ghoul2[i].mTempBoneList, ent->e.renderfx, skin, currentModel, whichLod, ghoul2[i].mBltlist); -#ifndef DEDICATED RenderSurfaces(RS); -#endif } // go through all the generated surfaces and create their bolt info if we need it. @@ -1884,6 +1895,7 @@ void R_AddGhoulSurfaces( trRefEntity_t *ent ) { } } Z_Free(modelList); +#endif } /* @@ -1902,8 +1914,8 @@ void G2_ConstructGhoulSkeleton( CGhoul2Info_v &ghoul2, const int frameNum, qhand bool setNewOrigin = false; mdxaBone_t rootMatrix; - // if we don't want server ghoul2 models and this is one, or we just don't want ghoul2 models at all, then return - if ((r_noServerGhoul2->integer && !(ghoul2[0].mCreationID & WF_CLIENTONLY)) || (r_noGhoul2->integer)) + // if we don't want server ghoul2 models and this is one, then return + if ((r_noServerGhoul2->integer && !(ghoul2[0].mCreationID & WF_CLIENTONLY)) ) { return; } @@ -2206,7 +2218,6 @@ qboolean R_LoadMDXM( model_t *mod, void *buffer, const char *mod_name, qboolean mdxmSurface_t *surf; int version; int size; - shader_t *sh; mdxmSurfHierarchy_t *surfInfo; #ifndef _M_IX86 @@ -2286,11 +2297,13 @@ qboolean R_LoadMDXM( model_t *mod, void *buffer, const char *mod_name, qboolean { LL(surfInfo->childIndexes[j]); } -#ifndef DEDICATED +#ifdef DEDICATED + surfInfo->shaderIndex = 0; +#else + shader_t *sh; // get the shader name sh = R_FindShader( surfInfo->shader, lightmapsNone, stylesDefault, qtrue ); // insert it in the surface list -#endif if ( sh->defaultShader ) { surfInfo->shaderIndex = 0; @@ -2299,6 +2312,7 @@ qboolean R_LoadMDXM( model_t *mod, void *buffer, const char *mod_name, qboolean { surfInfo->shaderIndex = sh->index; } +#endif RE_RegisterModels_StoreShaderRequest(mod_name, &surfInfo->shader[0], &surfInfo->shaderIndex); // find the next surface diff --git a/CODE-mp/renderer/tr_image.cpp b/CODE-mp/renderer/tr_image.cpp index f1331a1..2d4b317 100644 --- a/CODE-mp/renderer/tr_image.cpp +++ b/CODE-mp/renderer/tr_image.cpp @@ -2280,7 +2280,14 @@ void R_CreateBuiltinImages( void ) { tr.scratchImage[x] = R_CreateImage(va("*scratch%d",x), (byte *)data, DEFAULT_SIZE, DEFAULT_SIZE, qfalse, qtrue, qfalse, GL_CLAMP ); } - R_CreateDlightImage(); + if (r_newDLights->integer) + { + tr.dlightImage = R_FindImageFile("gfx/2d/dlight", qtrue, qfalse, qfalse, GL_CLAMP); + } + else + { + R_CreateDlightImage(); + } R_CreateFogImage(); } diff --git a/CODE-mp/renderer/tr_init.cpp b/CODE-mp/renderer/tr_init.cpp index 5692042..df180a3 100644 --- a/CODE-mp/renderer/tr_init.cpp +++ b/CODE-mp/renderer/tr_init.cpp @@ -10,12 +10,24 @@ #include "tr_font.h" +#ifdef G2_COLLISION_ENABLED +#if !defined (MINIHEAP_H_INC) + #include "../qcommon/miniheap.h" +#endif + +#include "../ghoul2/G2_local.h" +#endif + //#ifdef __USEA3D //// Defined in snd_a3dg_refcommon.c //void RE_A3D_RenderGeometry (void *pVoidA3D, void *pVoidGeom, void *pVoidMat, void *pVoidGeomStatus); //#endif +#ifdef G2_COLLISION_ENABLED +CMiniHeap *G2VertSpaceServer = NULL; +#endif + #ifndef DEDICATED glconfig_t glConfig; glstate_t glState; @@ -55,6 +67,8 @@ cvar_t *r_lodbias; cvar_t *r_lodscale; cvar_t *r_autolodscalevalue; +cvar_t *r_newDLights; + cvar_t *r_norefresh; cvar_t *r_drawentities; cvar_t *r_drawworld; @@ -160,7 +174,6 @@ Ghoul2 Insert Start */ cvar_t *r_noServerGhoul2; -cvar_t *r_noGhoul2; cvar_t *r_Ghoul2AnimSmooth=0; cvar_t *r_Ghoul2UnSqashAfterSmooth=0; //cvar_t *r_Ghoul2UnSqash; @@ -908,8 +921,8 @@ void R_Register( void ) r_debugSort = ri.Cvar_Get( "r_debugSort", "0", CVAR_CHEAT ); r_printShaders = ri.Cvar_Get( "r_printShaders", "0", 0 ); - r_surfaceSprites = ri.Cvar_Get ("r_surfaceSprites", "1", CVAR_CHEAT); - r_surfaceWeather = ri.Cvar_Get ("r_surfaceWeather", "0", 0); + r_surfaceSprites = ri.Cvar_Get ("r_surfaceSprites", "1", CVAR_TEMP); + r_surfaceWeather = ri.Cvar_Get ("r_surfaceWeather", "0", CVAR_TEMP); r_windSpeed = ri.Cvar_Get ("r_windSpeed", "0", 0); r_windAngle = ri.Cvar_Get ("r_windAngle", "0", 0); @@ -930,6 +943,8 @@ void R_Register( void ) r_showSmp = ri.Cvar_Get ("r_showSmp", "0", CVAR_CHEAT); r_skipBackEnd = ri.Cvar_Get ("r_skipBackEnd", "0", CVAR_CHEAT); + r_newDLights = ri.Cvar_Get ("r_newDLights", "0", 0); + r_measureOverdraw = ri.Cvar_Get( "r_measureOverdraw", "0", CVAR_CHEAT ); r_lodscale = ri.Cvar_Get( "r_lodscale", "5", 0 ); r_norefresh = ri.Cvar_Get ("r_norefresh", "0", CVAR_CHEAT); @@ -960,7 +975,6 @@ void R_Register( void ) Ghoul2 Insert Start */ r_noServerGhoul2 = ri.Cvar_Get( "r_noserverghoul2", "0", CVAR_CHEAT); - r_noGhoul2 = ri.Cvar_Get( "r_noghoul2", "0", CVAR_CHEAT); r_Ghoul2AnimSmooth = ri.Cvar_Get( "r_ghoul2animsmooth", ".3", 0 ); r_Ghoul2UnSqashAfterSmooth = ri.Cvar_Get( "r_ghoul2unsqashaftersmooth", "1", 0 ); @@ -992,13 +1006,16 @@ extern qboolean Sys_LowPhysicalMemory(); } +#ifdef G2_COLLISION_ENABLED +#define G2_VERT_SPACE_SERVER_SIZE 256 +#endif + /* =============== R_Init =============== */ void R_Init( void ) { - int err; int i; byte *ptr; @@ -1090,7 +1107,15 @@ void R_Init( void ) { #endif R_ModelInit(); #ifndef DEDICATED - err = qglGetError(); + +#ifdef G2_COLLISION_ENABLED + if (!G2VertSpaceServer) + { + G2VertSpaceServer = new CMiniHeap(G2_VERT_SPACE_SERVER_SIZE * 1024); + } +#endif + + int err = qglGetError(); if ( err != GL_NO_ERROR ) ri.Printf (PRINT_ALL, "glGetError() = 0x%x\n", err); #endif @@ -1136,6 +1161,14 @@ void RE_Shutdown( qboolean destroyWindow ) { #endif //!DEDICATED tr.registered = qfalse; + +#ifdef G2_COLLISION_ENABLED + if (G2VertSpaceServer) + { + delete G2VertSpaceServer; + G2VertSpaceServer = 0; + } +#endif } #ifndef DEDICATED @@ -1241,6 +1274,8 @@ refexport_t *GetRefAPI ( int apiVersion, refimport_t *rimp ) { re.Font_StrLenChars = RE_Font_StrLenChars; re.Font_HeightPixels = RE_Font_HeightPixels; re.Font_DrawString = RE_Font_DrawString; + re.Language_IsAsian = Language_IsAsian; + re.Language_UsesSpaces = Language_UsesSpaces; re.AnyLanguage_ReadCharFromString = AnyLanguage_ReadCharFromString; re.RemapShader = R_RemapShader; diff --git a/CODE-mp/renderer/tr_light.cpp b/CODE-mp/renderer/tr_light.cpp index ad5e729..8dc1c97 100644 --- a/CODE-mp/renderer/tr_light.cpp +++ b/CODE-mp/renderer/tr_light.cpp @@ -22,11 +22,40 @@ void R_TransformDlights( int count, dlight_t *dl, orientationr_t *ori) { int i; vec3_t temp; - for ( i = 0 ; i < count ; i++, dl++ ) { - VectorSubtract( dl->origin, ori->origin, temp ); - dl->transformed[0] = DotProduct( temp, ori->axis[0] ); - dl->transformed[1] = DotProduct( temp, ori->axis[1] ); - dl->transformed[2] = DotProduct( temp, ori->axis[2] ); + if (r_newDLights->integer) + { + for ( i = 0 ; i < count ; i++, dl++ ) + { + VectorSubtract( dl->origin, ori->origin, temp ); + dl->transformed[0] = DotProduct( temp, ori->axis[0] ); + dl->transformed[1] = DotProduct( temp, ori->axis[1] ); + dl->transformed[2] = DotProduct( temp, ori->axis[2] ); + VectorSubtract( dl->mProjOrigin, ori->origin, temp ); + dl->mProjTransformed[0] = DotProduct( temp, ori->axis[0] ); + dl->mProjTransformed[1] = DotProduct( temp, ori->axis[1] ); + dl->mProjTransformed[2] = DotProduct( temp, ori->axis[2] ); + if (dl->mType == DLIGHT_PROJECTED) + { + dl->mTransDirection[0] = DotProduct(dl->mDirection, ori->axis[0]); + dl->mTransDirection[1] = DotProduct(dl->mDirection, ori->axis[1]); + dl->mTransDirection[2] = DotProduct(dl->mDirection, ori->axis[2]); + dl->mTransBasis2[0] = DotProduct(dl->mBasis2, ori->axis[0]); + dl->mTransBasis2[1] = DotProduct(dl->mBasis2, ori->axis[1]); + dl->mTransBasis2[2] = DotProduct(dl->mBasis2, ori->axis[2]); + dl->mTransBasis3[0] = DotProduct(dl->mBasis3, ori->axis[0]); + dl->mTransBasis3[1] = DotProduct(dl->mBasis3, ori->axis[1]); + dl->mTransBasis3[2] = DotProduct(dl->mBasis3, ori->axis[2]); + } + } + } + else + { + for ( i = 0 ; i < count ; i++, dl++ ) { + VectorSubtract( dl->origin, ori->origin, temp ); + dl->transformed[0] = DotProduct( temp, ori->axis[0] ); + dl->transformed[1] = DotProduct( temp, ori->axis[1] ); + dl->transformed[2] = DotProduct( temp, ori->axis[2] ); + } } } @@ -96,6 +125,13 @@ extern cvar_t *r_ambientScale; extern cvar_t *r_directedScale; extern cvar_t *r_debugLight; +inline void VectorScaleVector(const vec3_t a, const vec3_t b, vec3_t out) +{ + out[0] = a[0] * b[0]; + out[1] = a[1] * b[1]; + out[2] = a[2] * b[2]; +} + /* ================= R_SetupEntityLightingGrid @@ -121,117 +157,246 @@ static void R_SetupEntityLightingGrid( trRefEntity_t *ent ) { return; } - if ( ent->e.renderfx & RF_LIGHTING_ORIGIN ) { - // seperate lightOrigins are needed so an object that is - // sinking into the ground can still be lit, and so - // multi-part models can be lit identically - VectorCopy( ent->e.lightingOrigin, lightOrigin ); - } else { - VectorCopy( ent->e.origin, lightOrigin ); - } - - VectorSubtract( lightOrigin, tr.world->lightGridOrigin, lightOrigin ); - for ( i = 0 ; i < 3 ; i++ ) { - float v; - - v = lightOrigin[i]*tr.world->lightGridInverseSize[i]; - pos[i] = floor( v ); - frac[i] = v - pos[i]; - if ( pos[i] < 0 ) { - pos[i] = 0; - } else if ( pos[i] >= tr.world->lightGridBounds[i] - 1 ) { - pos[i] = tr.world->lightGridBounds[i] - 1; - } - } - - VectorClear( ent->ambientLight ); - VectorClear( ent->directedLight ); - VectorClear( direction ); - - // trilerp the light value - gridStep[0] = 1; - gridStep[1] = tr.world->lightGridBounds[0]; - gridStep[2] = tr.world->lightGridBounds[0] * tr.world->lightGridBounds[1]; - startGridPos = tr.world->lightGridArray + (pos[0] * gridStep[0] + pos[1] * gridStep[1] + pos[2] * gridStep[2]); - - totalFactor = 0; - for ( i = 0 ; i < 8 ; i++ ) { - float factor; - mgrid_t *data; - unsigned short *gridPos; - int lat, lng; - vec3_t normal; - - factor = 1.0; - gridPos = startGridPos; - for ( j = 0 ; j < 3 ; j++ ) { - if ( i & (1<= tr.world->lightGridArray + tr.world->numGridArrayElements) - {//we've gone off the array somehow - continue; - } - data = tr.world->lightGridData + *gridPos; - if ( data->styles[0] == LS_LSNONE ) - { - continue; // ignore samples in walls - } - - totalFactor += factor; - - for(j=0;jstyles[j] != LS_LSNONE) - { - const byte style= data->styles[j]; - - ent->ambientLight[0] += factor * data->ambientLight[j][0] * styleColors[style][0] / 255.0f; - ent->ambientLight[1] += factor * data->ambientLight[j][1] * styleColors[style][1] / 255.0f; - ent->ambientLight[2] += factor * data->ambientLight[j][2] * styleColors[style][2] / 255.0f; - - ent->directedLight[0] += factor * data->directLight[j][0] * styleColors[style][0] / 255.0f; - ent->directedLight[1] += factor * data->directLight[j][1] * styleColors[style][1] / 255.0f; - ent->directedLight[2] += factor * data->directLight[j][2] * styleColors[style][2] / 255.0f; - } - else - { - break; - } - } - - lat = data->latLong[1]; - lng = data->latLong[0]; - lat *= (FUNCTABLE_SIZE/256); - lng *= (FUNCTABLE_SIZE/256); - - // decode X as cos( lat ) * sin( long ) - // decode Y as sin( lat ) * sin( long ) - // decode Z as cos( long ) - - normal[0] = tr.sinTable[(lat + (FUNCTABLE_SIZE / 4)) & FUNCTABLE_MASK] * tr.sinTable[lng]; - normal[1] = tr.sinTable[lat] * tr.sinTable[lng]; - normal[2] = tr.sinTable[(lng + (FUNCTABLE_SIZE / 4)) & FUNCTABLE_MASK]; - - VectorMA( direction, factor, normal, direction ); - } - - if ( totalFactor > 0 && totalFactor < 0.99 ) + if (r_newDLights->integer) { - totalFactor = 1.0 / totalFactor; - VectorScale( ent->ambientLight, totalFactor, ent->ambientLight ); - VectorScale( ent->directedLight, totalFactor, ent->directedLight ); + vec3_t v, invfrac; + float fraction[8]; + + if ( ent->e.renderfx & RF_LIGHTING_ORIGIN ) + { + // seperate lightOrigins are needed so an object that is + // sinking into the ground can still be lit, and so + // multi-part models can be lit identically + VectorCopy( ent->e.lightingOrigin, lightOrigin ); + } + else + { + VectorCopy( ent->e.origin, lightOrigin ); + } + + VectorSubtract( lightOrigin, tr.world->lightGridOrigin, lightOrigin ); + VectorScaleVector( lightOrigin, tr.world->lightGridInverseSize, v ); + + pos[0] = (int)floorf(v[0]); + pos[1] = (int)floorf(v[1]); + pos[2] = (int)floorf(v[2]); + + frac[0] = v[0] - (float)pos[0]; + frac[1] = v[1] - (float)pos[1]; + frac[2] = v[2] - (float)pos[2]; + + invfrac[0] = 1.0f - frac[0]; + invfrac[1] = 1.0f - frac[1]; + invfrac[2] = 1.0f - frac[2]; + + fraction[0] = invfrac[0] * invfrac[1] * invfrac[2]; + fraction[1] = frac[0] * invfrac[1] * invfrac[2]; + fraction[2] = invfrac[0] * frac[1] * invfrac[2]; + fraction[3] = frac[0] * frac[1] * invfrac[2]; + fraction[4] = invfrac[0] * invfrac[1] * frac[2]; + fraction[5] = frac[0] * invfrac[1] * frac[2]; + fraction[6] = invfrac[0] * frac[1] * frac[2]; + fraction[7] = frac[0] * frac[1] * frac[2]; + + pos[0] = Com_Clamp(0, tr.world->lightGridBounds[0] - 1, pos[0]); + pos[1] = Com_Clamp(0, tr.world->lightGridBounds[1] - 1, pos[1]); + pos[2] = Com_Clamp(0, tr.world->lightGridBounds[2] - 1, pos[2]); + + VectorClear( ent->ambientLight ); + VectorClear( ent->directedLight ); + VectorClear( direction ); + + // trilerp the light value + /* + startGridPos = tr.world->lightGridArray + (pos[0] * tr.world->lightGridStep[0]) + (pos[1] * tr.world->lightGridStep[1]) + (pos[2] * tr.world->lightGridStep[2]); + */ + startGridPos = tr.world->lightGridArray + (int)((pos[0] * tr.world->lightGridStep[0])) + (int)((pos[1] * tr.world->lightGridStep[1])) + (int)((pos[2] * tr.world->lightGridStep[2])); + + totalFactor = 0; + for ( i = 0 ; i < 8 ; i++ ) + { + float factor; + mgrid_t *data; + unsigned short *gridPos; + int lat, lng; + vec3_t normal; + + gridPos = startGridPos + tr.world->lightGridOffsets[i]; + + if (gridPos >= tr.world->lightGridArray + tr.world->numGridArrayElements) + { + //we've gone off the array somehow + continue; + } + + data = tr.world->lightGridData + *gridPos; + if ( data->styles[0] == LS_LSNONE ) + { + continue; // ignore samples in walls + } + + factor = fraction[i]; + totalFactor += factor; + + for(j = 0; j < MAXLIGHTMAPS; j++) + { + if (data->styles[j] != LS_LSNONE) + { + const byte style = data->styles[j]; + + ent->ambientLight[0] += factor * data->ambientLight[j][0] * styleColors[style][0] / 255.0f; + ent->ambientLight[1] += factor * data->ambientLight[j][1] * styleColors[style][1] / 255.0f; + ent->ambientLight[2] += factor * data->ambientLight[j][2] * styleColors[style][2] / 255.0f; + + ent->directedLight[0] += factor * data->directLight[j][0] * styleColors[style][0] / 255.0f; + ent->directedLight[1] += factor * data->directLight[j][1] * styleColors[style][1] / 255.0f; + ent->directedLight[2] += factor * data->directLight[j][2] * styleColors[style][2] / 255.0f; + } + else + { + break; + } + } + + lat = data->latLong[1] << 2; + lng = data->latLong[0] << 2; + + // decode X as cos( lat ) * sin( long ) + // decode Y as sin( lat ) * sin( long ) + // decode Z as cos( long ) + + normal[0] = tr.sinTable[(lat + (FUNCTABLE_SIZE / 4)) & FUNCTABLE_MASK] * tr.sinTable[lng]; + normal[1] = tr.sinTable[lat] * tr.sinTable[lng]; + normal[2] = tr.sinTable[(lng + (FUNCTABLE_SIZE / 4)) & FUNCTABLE_MASK]; + + VectorMA( direction, factor, normal, direction ); + } + + if ( totalFactor > 0 && totalFactor < 0.99 ) + { + totalFactor = 1.0 / totalFactor; + VectorScale( ent->ambientLight, totalFactor, ent->ambientLight ); + VectorScale( ent->directedLight, totalFactor, ent->directedLight ); + } + + VectorScale( ent->ambientLight, r_ambientScale->value, ent->ambientLight ); + VectorScale( ent->directedLight, r_directedScale->value, ent->directedLight ); + VectorNormalize2( direction, ent->lightDir ); } + else + { + if ( ent->e.renderfx & RF_LIGHTING_ORIGIN ) { + // seperate lightOrigins are needed so an object that is + // sinking into the ground can still be lit, and so + // multi-part models can be lit identically + VectorCopy( ent->e.lightingOrigin, lightOrigin ); + } else { + VectorCopy( ent->e.origin, lightOrigin ); + } - VectorScale( ent->ambientLight, r_ambientScale->value, ent->ambientLight ); - VectorScale( ent->directedLight, r_directedScale->value, ent->directedLight ); + VectorSubtract( lightOrigin, tr.world->lightGridOrigin, lightOrigin ); + for ( i = 0 ; i < 3 ; i++ ) { + float v; - VectorNormalize2( direction, ent->lightDir ); + v = lightOrigin[i]*tr.world->lightGridInverseSize[i]; + pos[i] = floor( v ); + frac[i] = v - pos[i]; + if ( pos[i] < 0 ) { + pos[i] = 0; + } else if ( pos[i] >= tr.world->lightGridBounds[i] - 1 ) { + pos[i] = tr.world->lightGridBounds[i] - 1; + } + } + + VectorClear( ent->ambientLight ); + VectorClear( ent->directedLight ); + VectorClear( direction ); + + // trilerp the light value + gridStep[0] = 1; + gridStep[1] = tr.world->lightGridBounds[0]; + gridStep[2] = tr.world->lightGridBounds[0] * tr.world->lightGridBounds[1]; + startGridPos = tr.world->lightGridArray + (pos[0] * gridStep[0] + pos[1] * gridStep[1] + pos[2] * gridStep[2]); + + totalFactor = 0; + for ( i = 0 ; i < 8 ; i++ ) { + float factor; + mgrid_t *data; + unsigned short *gridPos; + int lat, lng; + vec3_t normal; + + factor = 1.0; + gridPos = startGridPos; + for ( j = 0 ; j < 3 ; j++ ) { + if ( i & (1<= tr.world->lightGridArray + tr.world->numGridArrayElements) + {//we've gone off the array somehow + continue; + } + data = tr.world->lightGridData + *gridPos; + if ( data->styles[0] == LS_LSNONE ) + { + continue; // ignore samples in walls + } + + totalFactor += factor; + + for(j=0;jstyles[j] != LS_LSNONE) + { + const byte style= data->styles[j]; + + ent->ambientLight[0] += factor * data->ambientLight[j][0] * styleColors[style][0] / 255.0f; + ent->ambientLight[1] += factor * data->ambientLight[j][1] * styleColors[style][1] / 255.0f; + ent->ambientLight[2] += factor * data->ambientLight[j][2] * styleColors[style][2] / 255.0f; + + ent->directedLight[0] += factor * data->directLight[j][0] * styleColors[style][0] / 255.0f; + ent->directedLight[1] += factor * data->directLight[j][1] * styleColors[style][1] / 255.0f; + ent->directedLight[2] += factor * data->directLight[j][2] * styleColors[style][2] / 255.0f; + } + else + { + break; + } + } + + lat = data->latLong[1]; + lng = data->latLong[0]; + lat *= (FUNCTABLE_SIZE/256); + lng *= (FUNCTABLE_SIZE/256); + + // decode X as cos( lat ) * sin( long ) + // decode Y as sin( lat ) * sin( long ) + // decode Z as cos( long ) + + normal[0] = tr.sinTable[(lat + (FUNCTABLE_SIZE / 4)) & FUNCTABLE_MASK] * tr.sinTable[lng]; + normal[1] = tr.sinTable[lat] * tr.sinTable[lng]; + normal[2] = tr.sinTable[(lng + (FUNCTABLE_SIZE / 4)) & FUNCTABLE_MASK]; + + VectorMA( direction, factor, normal, direction ); + } + + if ( totalFactor > 0 && totalFactor < 0.99 ) + { + totalFactor = 1.0 / totalFactor; + VectorScale( ent->ambientLight, totalFactor, ent->ambientLight ); + VectorScale( ent->directedLight, totalFactor, ent->directedLight ); + } + + VectorScale( ent->ambientLight, r_ambientScale->value, ent->ambientLight ); + VectorScale( ent->directedLight, r_directedScale->value, ent->directedLight ); + + VectorNormalize2( direction, ent->lightDir ); + } } diff --git a/CODE-mp/renderer/tr_local.h b/CODE-mp/renderer/tr_local.h index 1fb9f51..6620db2 100644 --- a/CODE-mp/renderer/tr_local.h +++ b/CODE-mp/renderer/tr_local.h @@ -36,14 +36,35 @@ long myftol( float f ); #define MAX_STATE_NAME 32 // can't be increased without changing bit packing for drawsurfs +typedef enum +{ + DLIGHT_VERTICAL = 0, + DLIGHT_PROJECTED +} eDLightTypes; typedef struct dlight_s { - vec3_t origin; - vec3_t color; // range from 0.0 to 1.0, should be color normalized - float radius; + eDLightTypes mType; - vec3_t transformed; // origin in local coordinate system - int additive; // texture detail is lost tho when the lightmap is dark + vec3_t origin; + vec3_t mProjOrigin; // projected light's origin + + vec3_t color; // range from 0.0 to 1.0, should be color normalized + + float radius; + float mProjRadius; // desired radius of light + + int additive; // texture detail is lost tho when the lightmap is dark + + vec3_t transformed; // origin in local coordinate system + vec3_t mProjTransformed; // projected light's origin in local coordinate system + + vec3_t mDirection; + vec3_t mBasis2; + vec3_t mBasis3; + + vec3_t mTransDirection; + vec3_t mTransBasis2; + vec3_t mTransBasis3; } dlight_t; @@ -440,6 +461,7 @@ Ghoul2 Insert End deformStage_t deforms[MAX_SHADER_DEFORMS]; int numUnfoggedPasses; + int lastNonDetailStage; shaderStage_t *stages[MAX_SHADER_STAGES]; void (*optimalStageIteratorFunc)( void ); @@ -806,8 +828,13 @@ typedef struct { vec3_t lightGridSize; vec3_t lightGridInverseSize; int lightGridBounds[3]; + + int lightGridOffsets[8]; + + vec3_t lightGridStep; + mgrid_t *lightGridData; - unsigned short *lightGridArray; + word *lightGridArray; int numGridArrayElements; @@ -1118,6 +1145,8 @@ extern cvar_t *r_drawSun; // controls drawing of sun quad extern cvar_t *r_dynamiclight; // dynamic lights enabled/disabled extern cvar_t *r_dlightBacks; // dlight non-facing surfaces for continuity +extern cvar_t *r_newDLights; + extern cvar_t *r_norefresh; // bypasses the ref rendering extern cvar_t *r_drawentities; // disable/enable entity rendering extern cvar_t *r_drawworld; // disable/enable world rendering @@ -1209,7 +1238,6 @@ extern cvar_t *r_printShaders; Ghoul2 Insert Start */ extern cvar_t *r_noServerGhoul2; -extern cvar_t *r_noGhoul2; /* Ghoul2 Insert End */ diff --git a/CODE-mp/renderer/tr_model.cpp b/CODE-mp/renderer/tr_model.cpp index 075f7a7..d70ea51 100644 --- a/CODE-mp/renderer/tr_model.cpp +++ b/CODE-mp/renderer/tr_model.cpp @@ -995,10 +995,9 @@ Ghoul2 Insert Start Ghoul2 Insert End */ - if (!r_noServerGhoul2 || !r_noGhoul2) + if (!r_noServerGhoul2) { //keep it from choking when it gets to these checks in the g2 code. Registering all r_ cvars for the server would be a Bad Thing though. r_noServerGhoul2 = Cvar_Get( "r_noserverghoul2", "0", 0); - r_noGhoul2 = Cvar_Get( "r_noghoul2", "0", 0); } if ( !name || !name[0] ) { @@ -1377,7 +1376,6 @@ static qboolean R_LoadMD3 (model_t *mod, int lod, void *buffer, const char *mod_ int i, j; md3Header_t *pinmodel; md3Surface_t *surf; - md3Shader_t *shader; int version; int size; @@ -1508,6 +1506,7 @@ static qboolean R_LoadMD3 (model_t *mod, int lod, void *buffer, const char *mod_ } #ifndef DEDICATED // register the shaders + md3Shader_t *shader; shader = (md3Shader_t *) ( (byte *)surf + surf->ofsShaders ); for ( j = 0 ; j < surf->numShaders ; j++, shader++ ) { shader_t *sh; @@ -1584,7 +1583,6 @@ static qboolean R_LoadMD4( model_t *mod, void *buffer, const char *mod_name, qbo int version; int size; - shader_t *sh; pinmodel = (md4Header_t *)buffer; // @@ -1690,6 +1688,7 @@ static qboolean R_LoadMD4( model_t *mod, void *buffer, const char *mod_name, qbo // change to surface identifier surf->ident = SF_MD4; #ifndef DEDICATED + shader_t *sh; // register the shaders sh = R_FindShader( surf->shader, lightmapsNone, stylesDefault, qtrue ); if ( sh->defaultShader ) { diff --git a/CODE-mp/renderer/tr_public.h b/CODE-mp/renderer/tr_public.h index 1b0ec9e..e076bf7 100644 --- a/CODE-mp/renderer/tr_public.h +++ b/CODE-mp/renderer/tr_public.h @@ -83,7 +83,9 @@ typedef struct { int (*Font_StrLenChars) (const char *text); int (*Font_HeightPixels)(const int iFontIndex, const float scale); void (*Font_DrawString)(int ox, int oy, const char *text, const float *rgba, const int setIndex, int iCharLimit, const float scale); - unsigned int (*AnyLanguage_ReadCharFromString)( const char **ppText ); + qboolean (*Language_IsAsian)(void); + qboolean (*Language_UsesSpaces)(void); + unsigned int (*AnyLanguage_ReadCharFromString)( const char *psText, int *piAdvanceCount, qboolean *pbIsTrailingPunctuation/* = NULL*/ ); void (*RemapShader)(const char *oldShader, const char *newShader, const char *offsetTime); qboolean (*GetEntityToken)( char *buffer, int size ); diff --git a/CODE-mp/renderer/tr_scene.cpp b/CODE-mp/renderer/tr_scene.cpp index 9b910df..dee8329 100644 --- a/CODE-mp/renderer/tr_scene.cpp +++ b/CODE-mp/renderer/tr_scene.cpp @@ -318,7 +318,44 @@ RE_AddLightToScene ===================== */ void RE_AddLightToScene( const vec3_t org, float intensity, float r, float g, float b ) { - RE_AddDynamicLightToScene( org, intensity, r, g, b, qfalse ); + dlight_t *dl; + + if (r_newDLights->integer) + { + if ( !tr.registered ) { + return; + } + if ( r_numdlights >= MAX_DLIGHTS ) { + return; + } + //dl = &backEnd.refdef.dlights[r_numdlights++]; + dl = &backEndData[tr.smpFrame]->dlights[r_numdlights++]; + + dl->mType=DLIGHT_VERTICAL; + VectorCopy (org, dl->origin); + dl->color[0] = r; + dl->color[1] = g; + dl->color[2] = b; + if ( intensity <= 0 ) + { + // projected from viewer + VectorCopy (tr.viewParms.ori.axis[0], dl->mDirection); + VectorCopy (tr.viewParms.ori.axis[1], dl->mBasis2); + VectorCopy (tr.viewParms.ori.axis[2], dl->mBasis3); + dl->mType=DLIGHT_PROJECTED; + dl->radius = -intensity; + } + else + { + dl->radius = intensity; + } + + // dl->additive = qtrue; + } + else + { + RE_AddDynamicLightToScene( org, intensity, r, g, b, qfalse ); + } } /* diff --git a/CODE-mp/renderer/tr_shade.cpp b/CODE-mp/renderer/tr_shade.cpp index abb70db..c1357cc 100644 --- a/CODE-mp/renderer/tr_shade.cpp +++ b/CODE-mp/renderer/tr_shade.cpp @@ -394,7 +394,247 @@ static void DrawMultitextured( shaderCommands_t *input, int stage ) { GL_SelectTexture( 0 ); } +inline int VectorToInt(vec3_t vec) +{ + int tmp, retval; + _asm + { + push edx + mov edx, [vec] + fld dword ptr[edx + 0] + fld dword ptr[edx + 4] + fld dword ptr[edx + 8] + + mov eax, 0xff00 + + fistp tmp + mov al, byte ptr [tmp] + shl eax, 16 + + fistp tmp + mov ah, byte ptr [tmp] + + fistp tmp + mov al, byte ptr [tmp] + + mov [retval], eax + pop edx + } + return(retval); +} + +/* +=================== +NewProjectDlightTexture + +Perform dynamic lighting with another rendering pass +=================== +*/ +static void NewProjectDlightTexture( void ) +{ + int i, l; + vec3_t origin, projOrigin, projToVert; + float *texCoords; + byte *colors; + byte clipBits[SHADER_MAX_VERTEXES]; + MAC_STATIC float texCoordsArray[SHADER_MAX_VERTEXES][2]; + byte colorArray[SHADER_MAX_VERTEXES][4]; + unsigned hitIndexes[SHADER_MAX_INDEXES]; + int numIndexes; + float scale; + float radius; + vec3_t floatColor, coefBasis2, coefBasis3; + float texcoord0, texcoord1, coef = 0.0085f * 30.0f, invRadius = 1.0f; + + if ( !backEnd.refdef.num_dlights ) + { + return; + } + for ( l = 0 ; l < backEnd.refdef.num_dlights ; l++ ) + { + dlight_t *dl; + + if ( !( tess.dlightBits & ( 1 << l ) ) ) + { + continue; // this surface definately doesn't have any of this light + } + + { + colors = colorArray[0]; + texCoords = texCoordsArray[0]; + } + + dl = &backEnd.refdef.dlights[l]; + VectorCopy( dl->transformed, origin ); + VectorCopy( dl->mProjTransformed, projOrigin ); + invRadius = 1.0f / dl->mProjRadius; + VectorScale(dl->mBasis2, coef * invRadius, coefBasis2); + VectorScale(dl->mBasis3, coef * invRadius, coefBasis3); + radius = dl->radius; + scale = 1.0f / radius; + + int intcolor; + floatColor[0] = dl->color[0] * 255; + floatColor[1] = dl->color[1] * 255; + floatColor[2] = dl->color[2] * 255; + + intcolor = VectorToInt(floatColor); + +// RB_BypassXYZCollapse(); // do the copy into tess, because something wants to read it + + for ( i = 0 ; i < tess.numVertexes ; i++, texCoords += 2, colors += 4 ) + { + vec3_t dist, dest; + int clip; + float modulate; + + backEnd.pc.c_dlightVertexes++; + + VectorSubtract( origin, tess.xyz[i], dist ); + clip = 0; + + if (dl->mType == DLIGHT_PROJECTED) + { + // if this vertex is behind the projection origin of the light, give it texcoords of some unlit corner of the light texture + //so it appears unlit + VectorSubtract(tess.xyz[i], projOrigin, projToVert); + // use the actual radius of the light here + texCoords[0] = texcoord0 = 0.5f + DotProduct(dist,coefBasis2); + texCoords[1] = texcoord1 = 0.5f + DotProduct(dist,coefBasis3); + } + else + { + texCoords[0] = texcoord0 = 0.5f + dist[0] * scale; + texCoords[1] = texcoord1 = 0.5f + dist[1] * scale; + } + + if ( texcoord0 < 0.0f ) + { + clip |= 1; + } + else if ( texcoord0 > 1.0f ) + { + clip |= 2; + } + if ( texcoord1 < 0.0f ) + { + clip |= 4; + } + else if ( texcoord1 > 1.0f ) + { + clip |= 8; + } + clipBits[i] = clip; + if (dl->mType == DLIGHT_PROJECTED) + { + *(int *)colors = intcolor; + } + else + { + // modulate the strength based on the height and color + if ( dist[2] > radius ) + { + clip |= 16; + modulate = 0; + } + else if ( dist[2] < -radius ) + { + clip |= 32; + modulate = 0; + } + else + { + if ( dist[2] < 0.0f ) + { + dist[2] = -dist[2]; + } + if ( dist[2] < radius * 0.5f ) + { + modulate = 1.0f; + } + else + { + modulate = 2.0 * (radius - dist[2]) * scale; + } + } + VectorScale(floatColor, modulate, dest); + *(int *)colors = VectorToInt(dest); + } + } + +// RB_BypassIndeciesCollapse(); // need to get indecies sorted if they aren't already + + // build a list of triangles that need light + numIndexes = 0; + for ( i = 0 ; i < tess.numIndexes ; i += 3 ) + { + int a, b, c; + + a = tess.indexes[i]; + b = tess.indexes[i + 1]; + c = tess.indexes[i + 2]; + if ( clipBits[a] & clipBits[b] & clipBits[c] ) + { + continue; // not lighted + } + hitIndexes[numIndexes] = a; + hitIndexes[numIndexes + 1] = b; + hitIndexes[numIndexes + 2] = c; + numIndexes += 3; + } + if ( !numIndexes ) + { + continue; + } + + if ( qglActiveTextureARB ) + { + GL_State( GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE | GLS_DEPTHFUNC_EQUAL ); + + GL_SelectTexture( 0 ); + R_BindAnimatedImage( tess.shader->stages[tess.shader->lastNonDetailStage]->bundle ); + GL_SelectTexture( 1 ); + qglEnable( GL_TEXTURE_2D ); + GL_TexEnv( GL_MODULATE ); + + qglEnableClientState( GL_COLOR_ARRAY ); + qglEnableClientState( GL_TEXTURE_COORD_ARRAY ); + + { + qglColorPointer( 4, GL_UNSIGNED_BYTE, 0, colorArray ); + qglTexCoordPointer( 2, GL_FLOAT, 0, texCoordsArray[0] ); + } + + GL_Bind( tr.dlightImage ); + + R_DrawElements( numIndexes, hitIndexes ); + + // turn off the multitexture unit + qglDisable( GL_TEXTURE_2D ); + GL_SelectTexture( 0 ); + } + else + { + qglEnableClientState( GL_COLOR_ARRAY ); + qglEnableClientState( GL_TEXTURE_COORD_ARRAY ); + + { + qglColorPointer( 4, GL_UNSIGNED_BYTE, 0, colorArray ); + qglTexCoordPointer( 2, GL_FLOAT, 0, texCoordsArray[0] ); + } + + GL_Bind( tr.dlightImage ); + // include GLS_DEPTHFUNC_EQUAL so alpha tested surfaces don't add light + // where they aren't rendered + GL_State( GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE | GLS_DEPTHFUNC_EQUAL ); + + R_DrawElements( numIndexes, hitIndexes ); + } + backEnd.pc.c_totalIndexes += numIndexes; + backEnd.pc.c_dlightIndexes += numIndexes; + } +} /* =================== @@ -421,6 +661,12 @@ static void ProjectDlightTexture( void ) { return; } + if (r_newDLights->integer) + { + NewProjectDlightTexture(); + return; + } + for ( l = 0 ; l < backEnd.refdef.num_dlights ; l++ ) { dlight_t *dl; diff --git a/CODE-mp/renderer/tr_shader.cpp b/CODE-mp/renderer/tr_shader.cpp index 3f5c934..671fffe 100644 --- a/CODE-mp/renderer/tr_shader.cpp +++ b/CODE-mp/renderer/tr_shader.cpp @@ -3131,6 +3131,22 @@ static shader_t *FinishShader( void ) { // determine which stage iterator function is appropriate ComputeStageIteratorFunc(); + shader.lastNonDetailStage = 0; + for ( stage = 1; stage < shader.numUnfoggedPasses; stage++ ) + { + // Make sure stage is non detail and active + if(stages[stage].isDetail || !stages[stage].active) + { + break; + } + // MT lightmaps are always in bundle 1 + if(stages[stage].bundle[0].isLightmap) + { + continue; + } + shader.lastNonDetailStage = stage; + } + return GeneratePermanentShader(); } diff --git a/CODE-mp/renderer/tr_surface.cpp b/CODE-mp/renderer/tr_surface.cpp index b87ecd5..71aee03 100644 --- a/CODE-mp/renderer/tr_surface.cpp +++ b/CODE-mp/renderer/tr_surface.cpp @@ -616,9 +616,10 @@ static void DoLine_Oriented( const vec3_t start, const vec3_t end, const vec3_t VectorMA( start, spanWidth, up, tess.xyz[tess.numVertexes] ); tess.texCoords[tess.numVertexes][0][0] = 0; tess.texCoords[tess.numVertexes][0][1] = 0; - tess.vertexColors[tess.numVertexes][0] = backEnd.currentEntity->e.shaderRGBA[0] * 0.25; - tess.vertexColors[tess.numVertexes][1] = backEnd.currentEntity->e.shaderRGBA[1] * 0.25; - tess.vertexColors[tess.numVertexes][2] = backEnd.currentEntity->e.shaderRGBA[2] * 0.25; + tess.vertexColors[tess.numVertexes][0] = backEnd.currentEntity->e.shaderRGBA[0];// * 0.25; + tess.vertexColors[tess.numVertexes][1] = backEnd.currentEntity->e.shaderRGBA[1];// * 0.25; + tess.vertexColors[tess.numVertexes][2] = backEnd.currentEntity->e.shaderRGBA[2];// * 0.25; + tess.vertexColors[tess.numVertexes][3] = backEnd.currentEntity->e.shaderRGBA[3];// * 0.25; tess.numVertexes++; VectorMA( start, spanWidth2, up, tess.xyz[tess.numVertexes] ); @@ -627,6 +628,7 @@ static void DoLine_Oriented( const vec3_t start, const vec3_t end, const vec3_t tess.vertexColors[tess.numVertexes][0] = backEnd.currentEntity->e.shaderRGBA[0]; tess.vertexColors[tess.numVertexes][1] = backEnd.currentEntity->e.shaderRGBA[1]; tess.vertexColors[tess.numVertexes][2] = backEnd.currentEntity->e.shaderRGBA[2]; + tess.vertexColors[tess.numVertexes][3] = backEnd.currentEntity->e.shaderRGBA[3];// * 0.25; tess.numVertexes++; VectorMA( end, spanWidth, up, tess.xyz[tess.numVertexes] ); @@ -636,6 +638,7 @@ static void DoLine_Oriented( const vec3_t start, const vec3_t end, const vec3_t tess.vertexColors[tess.numVertexes][0] = backEnd.currentEntity->e.shaderRGBA[0]; tess.vertexColors[tess.numVertexes][1] = backEnd.currentEntity->e.shaderRGBA[1]; tess.vertexColors[tess.numVertexes][2] = backEnd.currentEntity->e.shaderRGBA[2]; + tess.vertexColors[tess.numVertexes][3] = backEnd.currentEntity->e.shaderRGBA[3];// * 0.25; tess.numVertexes++; VectorMA( end, spanWidth2, up, tess.xyz[tess.numVertexes] ); @@ -644,6 +647,7 @@ static void DoLine_Oriented( const vec3_t start, const vec3_t end, const vec3_t tess.vertexColors[tess.numVertexes][0] = backEnd.currentEntity->e.shaderRGBA[0]; tess.vertexColors[tess.numVertexes][1] = backEnd.currentEntity->e.shaderRGBA[1]; tess.vertexColors[tess.numVertexes][2] = backEnd.currentEntity->e.shaderRGBA[2]; + tess.vertexColors[tess.numVertexes][3] = backEnd.currentEntity->e.shaderRGBA[3];// * 0.25; tess.numVertexes++; tess.indexes[tess.numIndexes++] = vbase; @@ -722,6 +726,7 @@ static void DoCylinderPart(polyVert_t *verts) tess.vertexColors[tess.numVertexes][0] = verts->modulate[0]; tess.vertexColors[tess.numVertexes][1] = verts->modulate[1]; tess.vertexColors[tess.numVertexes][2] = verts->modulate[2]; + tess.vertexColors[tess.numVertexes][3] = verts->modulate[3]; tess.numVertexes++; verts++; } diff --git a/CODE-mp/renderer/vssver.scc b/CODE-mp/renderer/vssver.scc index 51e600e..5701849 100644 Binary files a/CODE-mp/renderer/vssver.scc and b/CODE-mp/renderer/vssver.scc differ diff --git a/CODE-mp/server/server.h b/CODE-mp/server/server.h index f5d1365..309ba31 100644 --- a/CODE-mp/server/server.h +++ b/CODE-mp/server/server.h @@ -211,8 +211,7 @@ extern cvar_t *sv_gametype; extern cvar_t *sv_pure; extern cvar_t *sv_floodProtect; extern cvar_t *sv_allowAnonymous; - -extern cvar_t *sv_debugserver; +extern cvar_t *sv_needpass; //=========================================================== diff --git a/CODE-mp/server/sv_ccmds.cpp b/CODE-mp/server/sv_ccmds.cpp index 7f999fb..5633efa 100644 --- a/CODE-mp/server/sv_ccmds.cpp +++ b/CODE-mp/server/sv_ccmds.cpp @@ -180,9 +180,11 @@ static void SV_Map_f( void ) { cheat = qfalse; killBots = qfalse; } + /* if( sv_gametype->integer == GT_SINGLE_PLAYER ) { Cvar_SetValue( "g_gametype", GT_FFA ); } + */ } // save the map name here cause on a map restart we reload the jk2mpconfig.cfg @@ -663,11 +665,12 @@ SV_Status_f */ static void SV_Status_f( void ) { - int i, j, l; + int i; client_t *cl; playerState_t *ps; const char *s; int ping; + char state[32]; // make sure server is running if ( !com_sv_running->integer ) @@ -683,39 +686,36 @@ static void SV_Status_f( void ) for (i=0,cl=svs.clients ; i < sv_maxclients->integer ; i++,cl++) { if (!cl->state) + { continue; - Com_Printf ("%3i ", i); - ps = SV_GameClientNum( i ); - Com_Printf ("%5i ", ps->persistant[PERS_SCORE]); + } if (cl->state == CS_CONNECTED) - Com_Printf ("CNCT "); + { + strcpy(state, "CNCT "); + } else if (cl->state == CS_ZOMBIE) - Com_Printf ("ZMBI "); + { + strcpy(state, "ZMBI "); + } else { ping = cl->ping < 9999 ? cl->ping : 9999; - Com_Printf ("%4i ", ping); + sprintf(state, "%4i", ping); } - Com_Printf ("%s", cl->name); - l = 16 - strlen(cl->name); - for (j=0 ; jlastPacketTime ); - + ps = SV_GameClientNum( i ); s = NET_AdrToString( cl->netchan.remoteAddress ); - Com_Printf ("%s", s); - l = 22 - strlen(s); - for (j=0 ; jnetchan.qport); - - Com_Printf (" %5i", cl->rate); - - Com_Printf ("\n"); + Com_Printf ("%3i %5i %s %-15.15s %7i %21s %5i %5i\n", + i, + ps->persistant[PERS_SCORE], + state, + cl->name, + svs.time - cl->lastPacketTime, + s, + cl->netchan.qport, + cl->rate + ); } Com_Printf ("\n"); } @@ -744,7 +744,7 @@ static void SV_ConSay_f(void) { return; } - strcpy (text, "console: "); + strcpy (text, "Server: "); p = Cmd_Args(); if ( *p == '"' ) { @@ -757,6 +757,85 @@ static void SV_ConSay_f(void) { SV_SendServerCommand(NULL, "chat \"%s\n\"", text); } +static const char *forceToggleNamePrints[] = +{ + "HEAL",//FP_HEAL + "JUMP",//FP_LEVITATION + "SPEED",//FP_SPEED + "PUSH",//FP_PUSH + "PULL",//FP_PULL + "MINDTRICK",//FP_TELEPTAHY + "GRIP",//FP_GRIP + "LIGHTNING",//FP_LIGHTNING + "DARK RAGE",//FP_RAGE + "PROTECT",//FP_PROTECT + "ABSORB",//FP_ABSORB + "TEAM HEAL",//FP_TEAM_HEAL + "TEAM REPLENISH",//FP_TEAM_FORCE + "DRAIN",//FP_DRAIN + "SEEING",//FP_SEE + "SABER OFFENSE",//FP_SABERATTACK + "SABER DEFENSE",//FP_SABERDEFEND + "SABER THROW",//FP_SABERTHROW + NULL +}; + +/* +================== +SV_ForceToggle_f +================== +*/ +void SV_ForceToggle_f(void) +{ + int i = 0; + int fpDisabled = Cvar_VariableValue("g_forcePowerDisable"); + int targetPower = 0; + const char *powerDisabled = "Enabled"; + + if ( Cmd_Argc () < 2 ) + { //no argument supplied, spit out a list of force powers and their numbers + while (i < NUM_FORCE_POWERS) + { + if (fpDisabled & (1 << i)) + { + powerDisabled = "Disabled"; + } + else + { + powerDisabled = "Enabled"; + } + + Com_Printf(va("%i - %s - Status: %s\n", i, forceToggleNamePrints[i], powerDisabled)); + i++; + } + + Com_Printf("Example usage: forcetoggle 3\n(toggles PUSH)\n"); + return; + } + + targetPower = atoi(Cmd_Argv(1)); + + if (targetPower < 0 || targetPower >= NUM_FORCE_POWERS) + { + Com_Printf("Specified a power that does not exist.\nExample usage: forcetoggle 3\n(toggles PUSH)\n"); + return; + } + + if (fpDisabled & (1 << targetPower)) + { + powerDisabled = "enabled"; + fpDisabled &= ~(1 << targetPower); + } + else + { + powerDisabled = "disabled"; + fpDisabled |= (1 << targetPower); + } + + Cvar_Set("g_forcePowerDisable", va("%i", fpDisabled)); + + Com_Printf("%s has been %s.\n", forceToggleNamePrints[targetPower], powerDisabled); +} /* ================== @@ -883,6 +962,8 @@ void SV_AddOperatorCommands( void ) { { Cmd_AddCommand ("svsay", SV_ConSay_f); } + + Cmd_AddCommand ("forcetoggle", SV_ForceToggle_f); } /* diff --git a/CODE-mp/server/sv_client.cpp b/CODE-mp/server/sv_client.cpp index b5669f7..8b39dcf 100644 --- a/CODE-mp/server/sv_client.cpp +++ b/CODE-mp/server/sv_client.cpp @@ -30,9 +30,11 @@ void SV_GetChallenge( netadr_t from ) { challenge_t *challenge; // ignore if we are in single player + /* if ( Cvar_VariableValue( "g_gametype" ) == GT_SINGLE_PLAYER || Cvar_VariableValue("ui_singlePlayerActive")) { return; } + */ oldest = 0; oldestTime = 0x7fffffff; @@ -932,8 +934,10 @@ SV_Disconnect_f The client is going to disconnect, so remove the connection immediately FIXME: move to game? ================= */ +const char *SV_GetStripEdString(char *refSection, char *refName); static void SV_Disconnect_f( client_t *cl ) { - SV_DropClient( cl, "disconnected" ); +// SV_DropClient( cl, "disconnected" ); + SV_DropClient( cl, SV_GetStripEdString("SVINGAME","DISCONNECTED") ); } /* diff --git a/CODE-mp/server/sv_game.cpp b/CODE-mp/server/sv_game.cpp index 779a128..a5117c3 100644 --- a/CODE-mp/server/sv_game.cpp +++ b/CODE-mp/server/sv_game.cpp @@ -15,6 +15,10 @@ botlib_export_t *botlib_export; +#ifdef G2_COLLISION_ENABLED +extern CMiniHeap *G2VertSpaceServer; +#endif + void SV_GameError( const char *string ) { Com_Error( ERR_DROP, "%s", string ); } @@ -931,6 +935,11 @@ int SV_GameSystemCalls( int *args ) { gG2_GBMNoReconstruct = qtrue; return G2API_GetBoltMatrix(*((CGhoul2Info_v *)args[1]), args[2], args[3], (mdxaBone_t *)VMA(4), (const float *)VMA(5),(const float *)VMA(6), args[7], (qhandle_t *)VMA(8), (float *)VMA(9)); + case G_G2_GETBOLT_NOREC_NOROT: + gG2_GBMNoReconstruct = qtrue; + gG2_GBMUseSPMethod = qtrue; + return G2API_GetBoltMatrix(*((CGhoul2Info_v *)args[1]), args[2], args[3], (mdxaBone_t *)VMA(4), (const float *)VMA(5),(const float *)VMA(6), args[7], (qhandle_t *)VMA(8), (float *)VMA(9)); + case G_G2_INITGHOUL2MODEL: RicksCrazyOnServer=true; return G2API_InitGhoul2Model((CGhoul2Info_v **)VMA(1), (const char *)VMA(2), args[3], (qhandle_t) args[4], @@ -988,6 +997,23 @@ int SV_GameSystemCalls( int *args ) { G2API_CleanGhoul2Models((CGhoul2Info_v **)VMA(1)); // G2API_CleanGhoul2Models((CGhoul2Info_v **)args[1]); return 0; + + case G_G2_COLLISIONDETECT: +#ifdef G2_COLLISION_ENABLED + G2API_CollisionDetect ( (CollisionRecord_t*)VMA(1), *((CGhoul2Info_v *)args[2]), + (const float*)VMA(3), + (const float*)VMA(4), + args[5], + args[6], + (float*)VMA(7), + (float*)VMA(8), + (float*)VMA(9), + G2VertSpaceServer, + args[10], + args[11], + VMF(12) ); +#endif + return 0; default: Com_Error( ERR_DROP, "Bad game system trap: %i", args[0] ); @@ -1082,23 +1108,7 @@ void SV_InitGameProgs( void ) { if ( !Cvar_VariableValue("fs_restrict") && !Sys_CheckCD() ) { - int iLanguage = Cvar_VariableValue("sp_language"); - //rww - we don't have an actual cvar object for sp_language to use here. - - if (iLanguage) // dunno if SP files are loaded at this point if no CD... - { - switch (iLanguage) - { - case SP_LANGUAGE_GERMAN: - Com_Error( ERR_NEED_CD, "Spiel CD nicht im Laufwerk" ); - break; // keep compiler happy - case SP_LANGUAGE_FRENCH: - Com_Error( ERR_NEED_CD, "CD de jeu pas dans le lecteur" ); - break; // keep compiler happy - } - } - - Com_Error( ERR_NEED_CD, "Game CD not in drive" ); + Com_Error( ERR_NEED_CD, SP_GetStringTextString("CON_TEXT_NEED_CD") ); //"Game CD not in drive" ); } // load the dll or bytecode diff --git a/CODE-mp/server/sv_init.cpp b/CODE-mp/server/sv_init.cpp index 4a37a52..f786f64 100644 --- a/CODE-mp/server/sv_init.cpp +++ b/CODE-mp/server/sv_init.cpp @@ -9,6 +9,12 @@ Ghoul2 Insert Start #include "../renderer/tr_local.h" #endif +#ifdef G2_COLLISION_ENABLED +#if !defined (MINIHEAP_H_INC) +#include "../qcommon/miniheap.h" +#endif +#endif + #include "../qcommon/strip.h" /* @@ -430,6 +436,11 @@ This is NOT called for map_restart */ extern void FixGhoul2InfoLeaks(bool,bool); +#ifdef G2_COLLISION_ENABLED +extern CMiniHeap *G2VertSpaceServer; +#define G2_VERT_SPACE_SERVER_SIZE 256 +#endif + extern void RE_RegisterMedia_LevelLoadBegin(const char *psMapName, ForceReload_e eForceReload); void SV_SpawnServer( char *server, qboolean killBots, ForceReload_e eForceReload ) { int i; @@ -498,6 +509,13 @@ Ghoul2 Insert Start else { R_SVModelInit(); + +#ifdef G2_COLLISION_ENABLED + if (!G2VertSpaceServer) + { + G2VertSpaceServer = new CMiniHeap(G2_VERT_SPACE_SERVER_SIZE * 1024); + } +#endif } SV_SendMapChange(); @@ -730,9 +748,9 @@ void SV_Init (void) { Cvar_Get ("duel_fraglimit", "10", CVAR_SERVERINFO); Cvar_Get ("g_forceBasedTeams", "0", CVAR_SERVERINFO); Cvar_Get ("g_duelWeaponDisable", "1", CVAR_SERVERINFO); - Cvar_Get ("g_needpass", "0", CVAR_SERVERINFO); sv_gametype = Cvar_Get ("g_gametype", "0", CVAR_SERVERINFO | CVAR_LATCH ); + sv_needpass = Cvar_Get ("g_needpass", "0", CVAR_SERVERINFO | CVAR_ROM ); Cvar_Get ("sv_keywords", "", CVAR_SERVERINFO); Cvar_Get ("protocol", va("%i", PROTOCOL_VERSION), CVAR_SERVERINFO | CVAR_ROM); sv_mapname = Cvar_Get ("mapname", "nomap", CVAR_SERVERINFO | CVAR_ROM); @@ -746,7 +764,7 @@ void SV_Init (void) { sv_allowAnonymous = Cvar_Get ("sv_allowAnonymous", "0", CVAR_SERVERINFO); // systeminfo - Cvar_Get ("sv_cheats", "1", CVAR_SYSTEMINFO | CVAR_ROM ); + Cvar_Get ("sv_cheats", "0", CVAR_SYSTEMINFO | CVAR_ROM ); sv_serverid = Cvar_Get ("sv_serverid", "0", CVAR_SYSTEMINFO | CVAR_ROM ); #ifndef DLL_ONLY // bk010216 - for DLL-only servers sv_pure = Cvar_Get ("sv_pure", "1", CVAR_SYSTEMINFO ); @@ -778,7 +796,7 @@ void SV_Init (void) { sv_killserver = Cvar_Get ("sv_killserver", "0", 0); sv_mapChecksum = Cvar_Get ("sv_mapChecksum", "", CVAR_ROM); - sv_debugserver = Cvar_Get ("sv_debugserver", "0", 0); +// sv_debugserver = Cvar_Get ("sv_debugserver", "0", 0); SP_Register("str_server",SP_REGISTER_REQUIRED); @@ -856,6 +874,14 @@ Ghoul2 Insert Start svs.snapshotEntities = NULL; } +#ifdef G2_COLLISION_ENABLED + if ( com_dedicated->integer && G2VertSpaceServer) + { + delete G2VertSpaceServer; + G2VertSpaceServer = 0; + } +#endif + // free current level SV_ClearServer(); diff --git a/CODE-mp/server/sv_main.cpp b/CODE-mp/server/sv_main.cpp index 9feaf0b..d38f15c 100644 --- a/CODE-mp/server/sv_main.cpp +++ b/CODE-mp/server/sv_main.cpp @@ -29,8 +29,7 @@ cvar_t *sv_gametype; cvar_t *sv_pure; cvar_t *sv_floodProtect; cvar_t *sv_allowAnonymous; - -cvar_t *sv_debugserver; +cvar_t *sv_needpass; /* ============================================================================= @@ -294,9 +293,11 @@ void SVC_Status( netadr_t from ) { char infostring[MAX_INFO_STRING]; // ignore if we are in single player + /* if ( Cvar_VariableValue( "g_gametype" ) == GT_SINGLE_PLAYER ) { return; } + */ strcpy( infostring, Cvar_InfoString( CVAR_SERVERINFO ) ); @@ -343,14 +344,16 @@ if a user is interested in a server to do a full status ================ */ void SVC_Info( netadr_t from ) { - int i, count; + int i, count, wDisable; char *gamedir; char infostring[MAX_INFO_STRING]; // ignore if we are in single player + /* if ( Cvar_VariableValue( "g_gametype" ) == GT_SINGLE_PLAYER || Cvar_VariableValue("ui_singlePlayerActive")) { return; } + */ // don't count privateclients count = 0; @@ -373,7 +376,19 @@ void SVC_Info( netadr_t from ) { Info_SetValueForKey( infostring, "sv_maxclients", va("%i", sv_maxclients->integer - sv_privateClients->integer ) ); Info_SetValueForKey( infostring, "gametype", va("%i", sv_gametype->integer ) ); - Info_SetValueForKey( infostring, "pure", va("%i", sv_pure->integer ) ); + Info_SetValueForKey( infostring, "needpass", va("%i", sv_needpass->integer ) ); + Info_SetValueForKey( infostring, "truejedi", va("%i", Cvar_VariableIntegerValue( "g_jediVmerc" ) ) ); + if ( sv_gametype->integer == GT_TOURNAMENT ) + { + wDisable = Cvar_VariableIntegerValue( "g_duelWeaponDisable" ); + } + else + { + wDisable = Cvar_VariableIntegerValue( "g_weaponDisable" ); + } + Info_SetValueForKey( infostring, "wdisable", va("%i", wDisable ) ); + Info_SetValueForKey( infostring, "fdisable", va("%i", Cvar_VariableIntegerValue( "g_forcePowerDisable" ) ) ); + //Info_SetValueForKey( infostring, "pure", va("%i", sv_pure->integer ) ); if( sv_minPing->integer ) { Info_SetValueForKey( infostring, "minPing", va("%i", sv_minPing->integer) ); @@ -411,11 +426,11 @@ Redirect all printfs */ void SVC_RemoteCommand( netadr_t from, msg_t *msg ) { qboolean valid; - int i, time; + unsigned int i, time; char remaining[1024]; #define SV_OUTPUTBUF_LENGTH (MAX_MSGLEN - 16) char sv_outputbuf[SV_OUTPUTBUF_LENGTH]; - static int lasttime = 0; + static unsigned int lasttime = 0; time = Com_Milliseconds(); if (time<(lasttime+500)) { diff --git a/CODE-mp/server/vssver.scc b/CODE-mp/server/vssver.scc index 6a45a42..ac8e6f5 100644 Binary files a/CODE-mp/server/vssver.scc and b/CODE-mp/server/vssver.scc differ diff --git a/CODE-mp/ui/keycodes.h b/CODE-mp/ui/keycodes.h index d4c5c87..e62f49f 100644 --- a/CODE-mp/ui/keycodes.h +++ b/CODE-mp/ui/keycodes.h @@ -3,136 +3,342 @@ #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 +{ + A_NULL = 0, + A_SHIFT, + A_CTRL, + A_ALT, + A_CAPSLOCK, + A_NUMLOCK, + A_SCROLLLOCK, + A_PAUSE, + A_BACKSPACE, + A_TAB, + A_ENTER, + A_KP_PLUS, + A_KP_MINUS, + A_KP_ENTER, + A_KP_PERIOD, + A_PRINTSCREEN, + A_KP_0, + A_KP_1, + A_KP_2, + A_KP_3, + A_KP_4, + A_KP_5, + A_KP_6, + A_KP_7, + A_KP_8, + A_KP_9, + A_CONSOLE, + A_ESCAPE, + A_F1, + A_F2, + A_F3, + A_F4, -typedef enum { - K_TAB = 9, - K_ENTER = 13, - K_ESCAPE = 27, - K_SPACE = 32, + A_SPACE, + A_PLING, + A_DOUBLE_QUOTE, + A_HASH, + A_STRING, + A_PERCENT, + A_AND, + A_SINGLE_QUOTE, + A_OPEN_BRACKET, + A_CLOSE_BRACKET, + A_STAR, + A_PLUS, + A_COMMA, + A_MINUS, + A_PERIOD, + A_FORWARD_SLASH, + A_0, + A_1, + A_2, + A_3, + A_4, + A_5, + A_6, + A_7, + A_8, + A_9, + A_COLON, + A_SEMICOLON, + A_LESSTHAN, + A_EQUALS, + A_GREATERTHAN, + A_QUESTION, - K_BACKSPACE = 127, + A_AT, + A_CAP_A, + A_CAP_B, + A_CAP_C, + A_CAP_D, + A_CAP_E, + A_CAP_F, + A_CAP_G, + A_CAP_H, + A_CAP_I, + A_CAP_J, + A_CAP_K, + A_CAP_L, + A_CAP_M, + A_CAP_N, + A_CAP_O, + A_CAP_P, + A_CAP_Q, + A_CAP_R, + A_CAP_S, + A_CAP_T, + A_CAP_U, + A_CAP_V, + A_CAP_W, + A_CAP_X, + A_CAP_Y, + A_CAP_Z, + A_OPEN_SQUARE, + A_BACKSLASH, + A_CLOSE_SQUARE, + A_CARET, + A_UNDERSCORE, - K_COMMAND = 128, - K_CAPSLOCK, - K_POWER, - K_PAUSE, + A_LEFT_SINGLE_QUOTE, + A_LOW_A, + A_LOW_B, + A_LOW_C, + A_LOW_D, + A_LOW_E, + A_LOW_F, + A_LOW_G, + A_LOW_H, + A_LOW_I, + A_LOW_J, + A_LOW_K, + A_LOW_L, + A_LOW_M, + A_LOW_N, + A_LOW_O, + A_LOW_P, + A_LOW_Q, + A_LOW_R, + A_LOW_S, + A_LOW_T, + A_LOW_U, + A_LOW_V, + A_LOW_W, + A_LOW_X, + A_LOW_Y, + A_LOW_Z, + A_OPEN_BRACE, + A_BAR, + A_CLOSE_BRACE, + A_TILDE, + A_DELETE, - K_UPARROW, - K_DOWNARROW, - K_LEFTARROW, - K_RIGHTARROW, + A_EURO, + A_SHIFT2, + A_CTRL2, + A_ALT2, + A_F5, + A_F6, + A_F7, + A_F8, + A_CIRCUMFLEX, + A_MWHEELUP, + A_CAP_SCARON, + A_MWHEELDOWN, + A_CAP_OE, + A_MOUSE1, + A_MOUSE2, + A_INSERT, + A_HOME, + A_PAGE_UP, + A_RIGHT_SINGLE_QUOTE, + A_LEFT_DOUBLE_QUOTE, + A_RIGHT_DOUBLE_QUOTE, + A_F9, + A_F10, + A_F11, + A_F12, + A_TRADEMARK, + A_LOW_SCARON, + A_SHIFT_ENTER, + A_LOW_OE, + A_END, + A_PAGE_DOWN, + A_CAP_YDIERESIS, - K_ALT, - K_CTRL, - K_SHIFT, - K_INS, - K_DEL, - K_PGDN, - K_PGUP, - K_HOME, - K_END, + A_SHIFT_SPACE, + A_EXCLAMDOWN, + A_CENT, + A_POUND, + A_SHIFT_KP_ENTER, + A_YEN, + A_MOUSE3, + A_MOUSE4, + A_MOUSE5, + A_COPYRIGHT, + A_CURSOR_UP, + A_CURSOR_DOWN, + A_CURSOR_LEFT, + A_CURSOR_RIGHT, + A_REGISTERED, + A_UNDEFINED_7, + A_UNDEFINED_8, + A_UNDEFINED_9, + A_UNDEFINED_10, + A_UNDEFINED_11, + A_UNDEFINED_12, + A_UNDEFINED_13, + A_UNDEFINED_14, + A_UNDEFINED_15, + A_UNDEFINED_16, + A_UNDEFINED_17, + A_UNDEFINED_18, + A_UNDEFINED_19, + A_UNDEFINED_20, + A_UNDEFINED_21, + A_UNDEFINED_22, + A_QUESTION_DOWN, - 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, + A_CAP_AGRAVE, + A_CAP_AACUTE, + A_CAP_ACIRCUMFLEX, + A_CAP_ATILDE, + A_CAP_ADIERESIS, + A_CAP_ARING, + A_CAP_AE, + A_CAP_CCEDILLA, + A_CAP_EGRAVE, + A_CAP_EACUTE, + A_CAP_ECIRCUMFLEX, + A_CAP_EDIERESIS, + A_CAP_IGRAVE, + A_CAP_IACUTE, + A_CAP_ICIRCUMFLEX, + A_CAP_IDIERESIS, + A_CAP_ETH, + A_CAP_NTILDE, + A_CAP_OGRAVE, + A_CAP_OACUTE, + A_CAP_OCIRCUMFLEX, + A_CAP_OTILDE, + A_CAP_ODIERESIS, + A_MULTIPLY, + A_CAP_OSLASH, + A_CAP_UGRAVE, + A_CAP_UACUTE, + A_CAP_UCIRCUMFLEX, + A_CAP_UDIERESIS, + A_CAP_YACUTE, + A_CAP_THORN, + A_GERMANDBLS, - 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, + A_LOW_AGRAVE, + A_LOW_AACUTE, + A_LOW_ACIRCUMFLEX, + A_LOW_ATILDE, + A_LOW_ADIERESIS, + A_LOW_ARING, + A_LOW_AE, + A_LOW_CCEDILLA, + A_LOW_EGRAVE, + A_LOW_EACUTE, + A_LOW_ECIRCUMFLEX, + A_LOW_EDIERESIS, + A_LOW_IGRAVE, + A_LOW_IACUTE, + A_LOW_ICIRCUMFLEX, + A_LOW_IDIERESIS, + A_LOW_ETH, + A_LOW_NTILDE, + A_LOW_OGRAVE, + A_LOW_OACUTE, + A_LOW_OCIRCUMFLEX, + A_LOW_OTILDE, + A_LOW_ODIERESIS, + A_DIVIDE, + A_LOW_OSLASH, + A_LOW_UGRAVE, + A_LOW_UACUTE, + A_LOW_UCIRCUMFLEX, + A_LOW_UDIERESIS, + A_LOW_YACUTE, + A_LOW_THORN, + A_LOW_YDIERESIS, + + A_JOY0, + A_JOY1, + A_JOY2, + A_JOY3, + A_JOY4, + A_JOY5, + A_JOY6, + A_JOY7, + A_JOY8, + A_JOY9, + A_JOY10, + A_JOY11, + A_JOY12, + A_JOY13, + A_JOY14, + A_JOY15, + A_JOY16, + A_JOY17, + A_JOY18, + A_JOY19, + A_JOY20, + A_JOY21, + A_JOY22, + A_JOY23, + A_JOY24, + A_JOY25, + A_JOY26, + A_JOY27, + A_JOY28, + A_JOY29, + A_JOY30, + A_JOY31, - K_MOUSE1, - K_MOUSE2, - K_MOUSE3, - K_MOUSE4, - K_MOUSE5, + A_AUX0, + A_AUX1, + A_AUX2, + A_AUX3, + A_AUX4, + A_AUX5, + A_AUX6, + A_AUX7, + A_AUX8, + A_AUX9, + A_AUX10, + A_AUX11, + A_AUX12, + A_AUX13, + A_AUX14, + A_AUX15, + A_AUX16, + A_AUX17, + A_AUX18, + A_AUX19, + A_AUX20, + A_AUX21, + A_AUX22, + A_AUX23, + A_AUX24, + A_AUX25, + A_AUX26, + A_AUX27, + A_AUX28, + A_AUX29, + A_AUX30, + A_AUX31, - 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; + MAX_KEYS +} fakeAscii_t; // The menu code needs to get both key and char events, but diff --git a/CODE-mp/ui/ui_force.c b/CODE-mp/ui/ui_force.c index 9363f6a..aafe854 100644 --- a/CODE-mp/ui/ui_force.c +++ b/CODE-mp/ui/ui_force.c @@ -13,16 +13,40 @@ FORCE INTERFACE #include "ui_force.h" int uiForceSide = FORCE_LIGHTSIDE; +int uiJediNonJedi = -1; int uiForceRank = FORCE_MASTERY_JEDI_KNIGHT; int uiMaxRank = MAX_FORCE_RANK; int uiMaxPoints = 20; int uiForceUsed = 0; int uiForceAvailable=0; +extern const char *UI_TeamName(int team); + qboolean gTouchedForce = qfalse; vmCvar_t ui_freeSaber, ui_forcePowerDisable; void Menu_ShowItemByName(menuDef_t *menu, const char *p, qboolean bShow); +qboolean uiForcePowersDisabled[NUM_FORCE_POWERS] = { + qfalse,//FP_HEAL,//instant + qfalse,//FP_LEVITATION,//hold/duration + qfalse,//FP_SPEED,//duration + qfalse,//FP_PUSH,//hold/duration + qfalse,//FP_PULL,//hold/duration + qfalse,//FP_TELEPATHY,//instant + qfalse,//FP_GRIP,//hold/duration + qfalse,//FP_LIGHTNING,//hold/duration + qfalse,//FP_RAGE,//duration + qfalse,//FP_PROTECT, + qfalse,//FP_ABSORB, + qfalse,//FP_TEAM_HEAL, + qfalse,//FP_TEAM_FORCE, + qfalse,//FP_DRAIN, + qfalse,//FP_SEE, + qfalse,//FP_SABERATTACK, + qfalse,//FP_SABERDEFEND, + qfalse//FP_SABERTHROW, +}; + int uiForcePowersRank[NUM_FORCE_POWERS] = { 0,//FP_HEAL = 0,//instant 1,//FP_LEVITATION,//hold/duration, this one defaults to 1 (gives a free point) @@ -118,6 +142,12 @@ void UI_DrawForceStars(rectDef_t *rect, float scale, vec4_t color, int textStyle { starcolor = bgForcePowerCost[forceindex][i]; + if (uiForcePowersDisabled[forceindex]) + { + vec4_t grColor = {0.2f, 0.2f, 0.2f, 1.0f}; + trap_R_SetColor(grColor); + } + if (val >= i) { // Draw a star. UI_DrawHandlePic( xPos, rect->y+6, width, width, uiForceStarShaders[starcolor][1] ); @@ -126,6 +156,12 @@ void UI_DrawForceStars(rectDef_t *rect, float scale, vec4_t color, int textStyle { // Draw a circle. UI_DrawHandlePic( xPos, rect->y+6, width, width, uiForceStarShaders[starcolor][0] ); } + + if (uiForcePowersDisabled[forceindex]) + { + trap_R_SetColor(NULL); + } + xPos += width + pad; } } @@ -245,8 +281,9 @@ void UI_SaveForceTemplate() } } -// +// +extern qboolean UI_TrueJediEnabled( void ); void UpdateForceUsed() { int curpower, currank; @@ -263,7 +300,69 @@ void UpdateForceUsed() { uiForcePowersRank[FP_LEVITATION]=1; } - + + if ( UI_TrueJediEnabled() ) + {//true jedi mode is set + if ( uiJediNonJedi == -1 ) + { + int x = 0; + qboolean clear = qfalse, update = qfalse; + uiJediNonJedi = FORCE_NONJEDI; + while ( x < NUM_FORCE_POWERS ) + {//if any force power is set, we must be a jedi + if ( x == FP_LEVITATION || x == FP_SABERATTACK ) + { + if ( uiForcePowersRank[x] > 1 ) + { + uiJediNonJedi = FORCE_JEDI; + break; + } + else if ( uiForcePowersRank[x] > 0 ) + { + clear = qtrue; + } + } + else if ( uiForcePowersRank[x] > 0 ) + { + uiJediNonJedi = FORCE_JEDI; + break; + } + x++; + } + if ( uiJediNonJedi == FORCE_JEDI ) + { + if ( uiForcePowersRank[FP_SABERATTACK] < 1 ) + { + uiForcePowersRank[FP_SABERATTACK]=1; + update = qtrue; + } + } + else if ( clear ) + { + x = 0; + while ( x < NUM_FORCE_POWERS ) + {//clear all force + uiForcePowersRank[x] = 0; + x++; + } + update = qtrue; + } + if ( update ) + { + int myTeam; + myTeam = (int)(trap_Cvar_VariableValue("ui_myteam")); + if ( myTeam != TEAM_SPECTATOR ) + { + UI_UpdateClientForcePowers(UI_TeamName(myTeam));//will cause him to respawn, if it's been 5 seconds since last one + } + else + { + UI_UpdateClientForcePowers(NULL);//just update powers + } + } + } + } + menu = Menus_FindByName("ingame_playerforce"); // Set the cost of the saberattack according to whether its free. if (ui_freeSaber.integer) @@ -658,11 +757,11 @@ extern int uiSkinColor; qboolean UI_SkinColor_HandleKey(int flags, float *special, int key, int num, int min, int max, int type) { - if (key == K_MOUSE1 || key == K_MOUSE2 || key == K_ENTER || key == K_KP_ENTER) + if (key == A_MOUSE1 || key == A_MOUSE2 || key == A_ENTER || key == A_KP_ENTER) { int i = num; - if (key == K_MOUSE2) + if (key == A_MOUSE2) { i--; } @@ -714,7 +813,7 @@ qboolean UI_ForceSide_HandleKey(int flags, float *special, int key, int num, int } } - if (key == K_MOUSE1 || key == K_MOUSE2 || key == K_ENTER || key == K_KP_ENTER) + if (key == A_MOUSE1 || key == A_MOUSE2 || key == A_ENTER || key == A_KP_ENTER) { int i = num; int x = 0; @@ -722,7 +821,7 @@ qboolean UI_ForceSide_HandleKey(int flags, float *special, int key, int num, int //update the feeder item selection, it might be different depending on side Menu_SetFeederSelection(NULL, FEEDER_FORCECFG, 0, NULL); - if (key == K_MOUSE2) + if (key == A_MOUSE2) { i--; } @@ -762,14 +861,90 @@ qboolean UI_ForceSide_HandleKey(int flags, float *special, int key, int num, int return qfalse; } +qboolean UI_JediNonJedi_HandleKey(int flags, float *special, int key, int num, int min, int max, int type) +{ + char info[MAX_INFO_VALUE]; + + info[0] = '\0'; + trap_GetConfigString(CS_SERVERINFO, info, sizeof(info)); + + if ( !UI_TrueJediEnabled() ) + {//true jedi mode is not set + return qfalse; + } + + if (key == A_MOUSE1 || key == A_MOUSE2 || key == A_ENTER || key == A_KP_ENTER) + { + int i = num; + int x = 0; + + if (key == A_MOUSE2) + { + i--; + } + else + { + i++; + } + + if (i < min) + { + i = max; + } + else if (i > max) + { + i = min; + } + + num = i; + + uiJediNonJedi = num; + + // Resetting power ranks based on if light or dark side is chosen + if ( !num ) + {//not a jedi? + int myTeam = (int)(trap_Cvar_VariableValue("ui_myteam")); + while ( x < NUM_FORCE_POWERS ) + {//clear all force powers + uiForcePowersRank[x] = 0; + x++; + } + if ( myTeam != TEAM_SPECTATOR ) + { + UI_UpdateClientForcePowers(UI_TeamName(myTeam));//will cause him to respawn, if it's been 5 seconds since last one + } + else + { + UI_UpdateClientForcePowers(NULL);//just update powers + } + } + else if ( num ) + {//a jedi, set the minimums, hopefuly they know to set the rest! + if ( uiForcePowersRank[FP_LEVITATION] < FORCE_LEVEL_1 ) + {//force jump 1 minimum + uiForcePowersRank[FP_LEVITATION] = FORCE_LEVEL_1; + } + if ( uiForcePowersRank[FP_SABERATTACK] < FORCE_LEVEL_1 ) + {//saber attack 1, minimum + uiForcePowersRank[FP_SABERATTACK] = FORCE_LEVEL_1; + } + } + + UpdateForceUsed(); + + gTouchedForce = qtrue; + return qtrue; + } + return qfalse; +} qboolean UI_ForceMaxRank_HandleKey(int flags, float *special, int key, int num, int min, int max, int type) { - if (key == K_MOUSE1 || key == K_MOUSE2 || key == K_ENTER || key == K_KP_ENTER) + if (key == A_MOUSE1 || key == A_MOUSE2 || key == A_ENTER || key == A_KP_ENTER) { int i = num; - if (key == K_MOUSE2) + if (key == A_MOUSE2) { i--; } @@ -809,13 +984,19 @@ qboolean UI_ForcePowerRank_HandleKey(int flags, float *special, int key, int num { qboolean raising; - if (key == K_MOUSE1 || key == K_MOUSE2 || key == K_ENTER || key == K_KP_ENTER) + if (key == A_MOUSE1 || key == A_MOUSE2 || key == A_ENTER || key == A_KP_ENTER) { int forcepower, rank; //this will give us the index as long as UI_FORCE_RANK is always one below the first force rank index forcepower = (type-UI_FORCE_RANK)-1; - + + //the power is disabled on the server + if (uiForcePowersDisabled[forcepower]) + { + return qtrue; + } + // If we are not on the same side as a power, or if we are not of any rank at all. if (uiForcePowerDarkLight[forcepower] && uiForceSide != uiForcePowerDarkLight[forcepower]) { @@ -842,7 +1023,7 @@ qboolean UI_ForcePowerRank_HandleKey(int flags, float *special, int key, int num min += 1; } - if (key == K_MOUSE2) + if (key == A_MOUSE2) { // Lower a point. if (uiForcePowersRank[forcepower]<=min) { diff --git a/CODE-mp/ui/ui_force.h b/CODE-mp/ui/ui_force.h index 87576ac..088721e 100644 --- a/CODE-mp/ui/ui_force.h +++ b/CODE-mp/ui/ui_force.h @@ -1,13 +1,17 @@ #include "../qcommon/qfiles.h" #define NUM_FORCE_STAR_IMAGES 9 +#define FORCE_NONJEDI 0 +#define FORCE_JEDI 1 extern int uiForceSide; +extern int uiJediNonJedi; extern int uiForceRank; extern int uiMaxRank; extern int uiForceUsed; extern int uiForceAvailable; extern qboolean gTouchedForce; +extern qboolean uiForcePowersDisabled[NUM_FORCE_POWERS]; extern int uiForcePowersRank[NUM_FORCE_POWERS]; extern int uiForcePowerDarkLight[NUM_FORCE_POWERS]; extern int uiSaberColorShaders[NUM_SABER_COLORS]; @@ -23,6 +27,7 @@ void UI_SaveForceTemplate(); void UI_UpdateForcePowers(); qboolean UI_SkinColor_HandleKey(int flags, float *special, int key, int num, int min, int max, int type); qboolean UI_ForceSide_HandleKey(int flags, float *special, int key, int num, int min, int max, int type); +qboolean UI_JediNonJedi_HandleKey(int flags, float *special, int key, int num, int min, int max, int type); qboolean UI_ForceMaxRank_HandleKey(int flags, float *special, int key, int num, int min, int max, int type); qboolean UI_ForcePowerRank_HandleKey(int flags, float *special, int key, int num, int min, int max, int type); extern void UI_ForceConfigHandle( int oldindex, int newindex ); diff --git a/CODE-mp/ui/ui_local.h b/CODE-mp/ui/ui_local.h index 3d21ecd..6c95192 100644 --- a/CODE-mp/ui/ui_local.h +++ b/CODE-mp/ui/ui_local.h @@ -991,7 +991,9 @@ int trap_R_Font_StrLenPixels(const char *text, const int iFontIndex, const fl int trap_R_Font_StrLenChars(const char *text); int trap_R_Font_HeightPixels(const int iFontIndex, const float scale); void trap_R_Font_DrawString(int ox, int oy, const char *text, const float *rgba, const int setIndex, int iCharLimit, const float scale); -unsigned trap_AnyLanguage_ReadCharFromString( const char **ppText ); +qboolean trap_Language_IsAsian(void); +qboolean trap_Language_UsesSpaces(void); +unsigned trap_AnyLanguage_ReadCharFromString( const char *psText, int *piAdvanceCount, qboolean *pbIsTrailingPunctuation/* = NULL*/ ); void trap_S_StopBackgroundTrack( void ); void trap_S_StartBackgroundTrack( const char *intro, const char *loop, qboolean bReturnWithoutStarting); int trap_CIN_PlayCinematic( const char *arg0, int xpos, int ypos, int width, int height, int bits); diff --git a/CODE-mp/ui/ui_main.c b/CODE-mp/ui/ui_main.c index d0b893e..905e8dc 100644 --- a/CODE-mp/ui/ui_main.c +++ b/CODE-mp/ui/ui_main.c @@ -16,100 +16,12 @@ USER INTERFACE MAIN #include "../qcommon/game_version.h" #include "ui_force.h" -menuDef_t *Menus_FindByName(const char *p); -void Menu_ShowItemByName(menuDef_t *menu, const char *p, qboolean bShow); -void UpdateForceUsed(); - -char holdSPString[1024]={0}; - -uiInfo_t uiInfo; - -static const char *MonthAbbrev[] = { - "Jan","Feb","Mar", - "Apr","May","Jun", - "Jul","Aug","Sep", - "Oct","Nov","Dec" -}; - - -static const char *skillLevels[] = { - "SKILL1",//"I Can Win", - "SKILL2",//"Bring It On", - "SKILL3",//"Hurt Me Plenty", - "SKILL4",//"Hardcore", - "SKILL5"//"Nightmare" -}; - -static const int numSkillLevels = sizeof(skillLevels) / sizeof(const char*); - - -static const char *netSources[] = { - "Local", - "Internet", - "Favorites" -// "Mplayer" -}; -static const int numNetSources = sizeof(netSources) / sizeof(const char*); - -static const serverFilter_t serverFilters[] = { - {"All", "" }, - {"Jedi Knight 2", "" }, -}; - -static const char *teamArenaGameTypes[] = { - "FFA", - "HOLOCRON", - "JEDIMASTER", - "DUEL", - "SP", - "TEAM FFA", - "N/A", - "CTF", - "CTY", - "TEAMTOURNAMENT" -}; - -static int const numTeamArenaGameTypes = sizeof(teamArenaGameTypes) / sizeof(const char*); - - -static const int numServerFilters = sizeof(serverFilters) / sizeof(serverFilter_t); - - -static char* netnames[] = { - "???", - "UDP", - "IPX", - NULL -}; - -static int gamecodetoui[] = {4,2,3,0,5,1,6}; -static int uitogamecode[] = {4,6,2,3,1,5,7}; - - -static void UI_StartServerRefresh(qboolean full); -static void UI_StopServerRefresh( void ); -static void UI_DoServerRefresh( void ); -static void UI_BuildServerDisplayList(qboolean force); -static void UI_BuildServerStatus(qboolean force); -static void UI_BuildFindPlayerList(qboolean force); -static int QDECL UI_ServersQsortCompare( const void *arg1, const void *arg2 ); -static int UI_MapCountByGameType(qboolean singlePlayer); -static int UI_HeadCountByTeam( void ); -static int UI_HeadCountByColor( void ); -static void UI_ParseGameInfo(const char *teamFile); -static const char *UI_SelectedMap(int index, int *actual); -static const char *UI_SelectedHead(int index, int *actual); -static int UI_GetIndexFromSelection(int actual); - -int ProcessNewUI( int command, int arg0, int arg1, int arg2, int arg3, int arg4, int arg5, int arg6 ); -int uiSkinColor=TEAM_FREE; - /* ================ vmMain This is the only way control passes into the module. -This must be the very first function compiled into the .qvm file +!!! This MUST BE THE VERY FIRST FUNCTION compiled into the .qvm file !!! ================ */ vmCvar_t ui_debug; @@ -167,6 +79,145 @@ int vmMain( int command, int arg0, int arg1, int arg2, int arg3, int arg4, int a return -1; } +menuDef_t *Menus_FindByName(const char *p); +void Menu_ShowItemByName(menuDef_t *menu, const char *p, qboolean bShow); +void UpdateForceUsed(); + +char holdSPString[1024]={0}; + +uiInfo_t uiInfo; + +static void UI_StartServerRefresh(qboolean full); +static void UI_StopServerRefresh( void ); +static void UI_DoServerRefresh( void ); +static void UI_BuildServerDisplayList(qboolean force); +static void UI_BuildServerStatus(qboolean force); +static void UI_BuildFindPlayerList(qboolean force); +static int QDECL UI_ServersQsortCompare( const void *arg1, const void *arg2 ); +static int UI_MapCountByGameType(qboolean singlePlayer); +static int UI_HeadCountByTeam( void ); +static int UI_HeadCountByColor( void ); +static void UI_ParseGameInfo(const char *teamFile); +static const char *UI_SelectedMap(int index, int *actual); +static const char *UI_SelectedHead(int index, int *actual); +static int UI_GetIndexFromSelection(int actual); + +int ProcessNewUI( int command, int arg0, int arg1, int arg2, int arg3, int arg4, int arg5, int arg6 ); +int uiSkinColor=TEAM_FREE; + +static const serverFilter_t serverFilters[] = { + {"All", "" }, + {"Jedi Knight 2", "" }, +}; +static const int numServerFilters = sizeof(serverFilters) / sizeof(serverFilter_t); + + + + +static const char *skillLevels[] = { + "SKILL1",//"I Can Win", + "SKILL2",//"Bring It On", + "SKILL3",//"Hurt Me Plenty", + "SKILL4",//"Hardcore", + "SKILL5"//"Nightmare" +}; +static const int numSkillLevels = sizeof(skillLevels) / sizeof(const char*); + + + +static const char *teamArenaGameTypes[] = { + "FFA", + "HOLOCRON", + "JEDIMASTER", + "DUEL", + "SP", + "TEAM FFA", + "N/A", + "CTF", + "CTY", + "TEAMTOURNAMENT" +}; +static int const numTeamArenaGameTypes = sizeof(teamArenaGameTypes) / sizeof(const char*); + + + +static char* netnames[] = { + "???", + "UDP", + "IPX", + NULL +}; + +static int gamecodetoui[] = {4,2,3,0,5,1,6}; +static int uitogamecode[] = {4,6,2,3,1,5,7}; + +const char *UI_GetStripEdString(const char *refSection, const char *refName); + +const char *UI_TeamName(int team) { + if (team==TEAM_RED) + return "RED"; + else if (team==TEAM_BLUE) + return "BLUE"; + else if (team==TEAM_SPECTATOR) + return "SPECTATOR"; + return "FREE"; +} + +// returns either string or NULL for OOR... +// +static const char *GetCRDelineatedString( const char *psStripFileRef, const char *psStripStringRef, int iIndex) +{ + static char sTemp[256]; + const char *psList = UI_GetStripEdString(psStripFileRef, psStripStringRef); + char *p; + + while (iIndex--) + { + psList = strchr(psList,'\n'); + if (!psList){ + return NULL; // OOR + } + psList++; + } + + strcpy(sTemp,psList); + p = strchr(sTemp,'\n'); + if (p) { + *p = '\0'; + } + + return sTemp; +} + + +static const char *GetMonthAbbrevString( int iMonth ) +{ + const char *p = GetCRDelineatedString("INGAMETEXT","MONTHS", iMonth); + + return p ? p : "Jan"; // sanity +} + + + + +/* +static const char *netSources[] = { + "Local", + "Internet", + "Favorites" +// "Mplayer" +}; +static const int numNetSources = sizeof(netSources) / sizeof(const char*); +*/ +static const int numNetSources = 3; // now hard-entered in StripEd file +static const char *GetNetSourceString(int iSource) +{ + const char *p = GetCRDelineatedString("INGAMETEXT","NET_SOURCES", iSource); + + return p ? p : "??"; +} + + void AssetCache() { @@ -335,9 +386,12 @@ static void Text_Paint_Limit(float *maxX, float x, float y, float scale, vec4_t && psOut < &sTemp[sizeof(sTemp)-1] // sanity ) { + int iAdvanceCount; psOutLastGood = psOut; - uiLetter = trap_AnyLanguage_ReadCharFromString(&psText); + uiLetter = trap_AnyLanguage_ReadCharFromString(psText, &iAdvanceCount, NULL); + psText += iAdvanceCount; + if (uiLetter > 255) { *psOut++ = uiLetter>>8; @@ -392,7 +446,7 @@ char parsedFPMessage[1024]; extern int FPMessageTime; void Text_PaintCenter(float x, float y, float scale, vec4_t color, const char *text, float adjust, int iMenuFont); -const char *UI_GetStripEdString(char *refSection, char *refName) +const char *UI_GetStripEdString(const char *refSection, const char *refName) { static char text[1024]={0}; @@ -926,8 +980,9 @@ void UI_Load() { UI_ParseGameInfo("demogameinfo.txt"); #else UI_ParseGameInfo("ui/jk2mp/gameinfo.txt"); - UI_LoadArenas(); #endif + UI_LoadArenas(); + UI_LoadBots(); UI_LoadMenus(menuSet, qtrue); Menus_CloseAll(); @@ -1195,7 +1250,7 @@ static void UI_DrawForceSide(rectDef_t *rect, float scale, vec4_t color, int tex if (val == FORCE_LIGHTSIDE) { - Com_sprintf(s, sizeof(s), "Light\0"); + trap_SP_GetStringTextString("MENUS3_FORCEDESC_LIGHT",s, sizeof(s)); menu = Menus_FindByName("forcealloc"); if (menu) { @@ -1218,8 +1273,7 @@ static void UI_DrawForceSide(rectDef_t *rect, float scale, vec4_t color, int tex } else { - Com_sprintf(s, sizeof(s), "Dark\0"); - + trap_SP_GetStringTextString("MENUS3_FORCEDESC_DARK",s, sizeof(s)); menu = Menus_FindByName("forcealloc"); if (menu) { @@ -1243,6 +1297,128 @@ static void UI_DrawForceSide(rectDef_t *rect, float scale, vec4_t color, int tex Text_Paint(rect->x, rect->y, scale, color, s,0, 0, textStyle, iMenuFont); } +qboolean UI_HasSetSaberOnly( void ) +{ + char info[MAX_INFO_STRING]; + int i = 0; + int wDisable = 0; + int gametype = 0; + + gametype = atoi(Info_ValueForKey(info, "g_gametype")); + + if ( gametype == GT_JEDIMASTER ) + { //set to 0 + return qfalse; + } + + trap_GetConfigString( CS_SERVERINFO, info, sizeof(info) ); + + if (gametype == GT_TOURNAMENT) + { + wDisable = atoi(Info_ValueForKey(info, "g_duelWeaponDisable")); + } + else + { + wDisable = atoi(Info_ValueForKey(info, "g_weaponDisable")); + } + + while (i < WP_NUM_WEAPONS) + { + if (!(wDisable & (1 << i)) && + i != WP_SABER && i != WP_NONE) + { + return qfalse; + } + + i++; + } + + return qtrue; +} + +static qboolean UI_AllForceDisabled(int force) +{ + int i; + + if (force) + { + for (i=0;i max) + { + i = min; + } + + info[0] = '\0'; + trap_GetConfigString(CS_SERVERINFO, info, sizeof(info)); + + if ( !UI_TrueJediEnabled() ) + {//true jedi mode is not on, do not draw this button type + return; + } + + if ( val == FORCE_NONJEDI ) + { + trap_SP_GetStringTextString("MENUS0_NO",s, sizeof(s)); + } + else + { + trap_SP_GetStringTextString("MENUS0_YES",s, sizeof(s)); + } + + Text_Paint(rect->x, rect->y, scale, color, s,0, 0, textStyle, iMenuFont); +} static void UI_DrawTeamName(rectDef_t *rect, float scale, vec4_t color, qboolean blue, int textStyle, int iMenuFont) { int i; @@ -1287,11 +1463,13 @@ static void UI_DrawTeamMember(rectDef_t *rect, float scale, vec4_t color, qboole if (value <= 1) { if (value == -1) { - text = "Closed"; + //text = "Closed"; + text = UI_GetStripEdString("MENUS3", "CLOSED"); } else { - text = "Human"; + //text = "Human"; + text = UI_GetStripEdString("MENUS3", "HUMAN"); } } else { value -= 2; @@ -1389,6 +1567,52 @@ static void UI_DrawMapCinematic(rectDef_t *rect, float scale, vec4_t color, qboo } } +static void UI_SetForceDisabled(int force) +{ + int i = 0; + + if (force) + { + while (i < NUM_FORCE_POWERS) + { + if (force & (1 << i)) + { + uiForcePowersDisabled[i] = qtrue; + + if (i != FP_LEVITATION && i != FP_SABERATTACK && i != FP_SABERDEFEND) + { + uiForcePowersRank[i] = 0; + } + else + { + if (i == FP_LEVITATION) + { + uiForcePowersRank[i] = 1; + } + else + { + uiForcePowersRank[i] = 3; + } + } + } + else + { + uiForcePowersDisabled[i] = qfalse; + } + i++; + } + } + else + { + i = 0; + + while (i < NUM_FORCE_POWERS) + { + uiForcePowersDisabled[i] = qfalse; + i++; + } + } +} void UpdateForceStatus() { @@ -1412,23 +1636,27 @@ void UpdateForceStatus() if (menu) { char info[MAX_INFO_STRING]; + int disabledForce = 0; + qboolean trueJedi = qfalse, allForceDisabled = qfalse; - if (uiForcePowersRank[FP_SABERATTACK] > 0) - { // Show lightsaber stuff. - Menu_ShowItemByName(menu, "nosaber", qfalse); - Menu_ShowItemByName(menu, "yessaber", qtrue); - } - else - { - Menu_ShowItemByName(menu, "nosaber", qtrue); - Menu_ShowItemByName(menu, "yessaber", qfalse); - } - trap_GetConfigString( CS_SERVERINFO, info, sizeof(info) ); //already have serverinfo at this point for stuff below. Don't bother trying to use ui_forcePowerDisable. //if (ui_forcePowerDisable.integer) - if (atoi(Info_ValueForKey(info, "g_forcePowerDisable"))) + //if (atoi(Info_ValueForKey(info, "g_forcePowerDisable"))) + disabledForce = atoi(Info_ValueForKey(info, "g_forcePowerDisable")); + allForceDisabled = UI_AllForceDisabled(disabledForce); + trueJedi = UI_TrueJediEnabled(); + + if ( !trueJedi || allForceDisabled ) + { + Menu_ShowItemByName(menu, "jedinonjedi", qfalse); + } + else + { + Menu_ShowItemByName(menu, "jedinonjedi", qtrue); + } + if ( allForceDisabled == qtrue || (trueJedi && uiJediNonJedi == FORCE_NONJEDI) ) { // No force stuff Menu_ShowItemByName(menu, "noforce", qtrue); Menu_ShowItemByName(menu, "yesforce", qfalse); @@ -1437,10 +1665,23 @@ void UpdateForceStatus() } else { + UI_SetForceDisabled(disabledForce); Menu_ShowItemByName(menu, "noforce", qfalse); Menu_ShowItemByName(menu, "yesforce", qtrue); } + //Moved this to happen after it's done with force power disabling stuff + if (uiForcePowersRank[FP_SABERATTACK] > 0 || ui_freeSaber.integer) + { // Show lightsaber stuff. + Menu_ShowItemByName(menu, "nosaber", qfalse); + Menu_ShowItemByName(menu, "yessaber", qtrue); + } + else + { + Menu_ShowItemByName(menu, "nosaber", qtrue); + Menu_ShowItemByName(menu, "yessaber", qfalse); + } + // The leftmost button should be "apply" unless you are in spectator, where you can join any team. if ((int)(trap_Cvar_VariableValue("ui_myteam")) != TEAM_SPECTATOR) { @@ -1569,7 +1810,7 @@ static void UI_DrawNetSource(rectDef_t *rect, float scale, vec4_t color, int tex trap_SP_GetStringTextString("MENUS3_SOURCE", holdSPString, sizeof(holdSPString) ); Text_Paint(rect->x, rect->y, scale, color, va("%s %s",holdSPString, - netSources[ui_netSource.integer]), 0, 0, textStyle, iMenuFont); + GetNetSourceString(ui_netSource.integer)), 0, 0, textStyle, iMenuFont); } static void UI_DrawNetMapPreview(rectDef_t *rect, float scale, vec4_t color) { @@ -1871,11 +2112,31 @@ static int UI_OwnerDrawWidth(int ownerDraw, float scale) { if (i == FORCE_LIGHTSIDE) { - s = "Light"; +// s = "Light"; + s = (char *)UI_GetStripEdString("MENUS3", "FORCEDESC_LIGHT"); } else { - s = "Dark"; +// s = "Dark"; + s = (char *)UI_GetStripEdString("MENUS3", "FORCEDESC_DARK"); + } + break; + case UI_JEDI_NONJEDI: + i = uiJediNonJedi; + if (i < 0 || i > 1) + { + i = 0; + } + + if (i == FORCE_NONJEDI) + { +// s = "Non-Jedi"; + s = (char *)UI_GetStripEdString("MENUS0", "NO"); + } + else + { +// s = "Jedi"; + s = (char *)UI_GetStripEdString("MENUS0", "YES"); } break; case UI_FORCE_RANK: @@ -2003,7 +2264,7 @@ static int UI_OwnerDrawWidth(int ownerDraw, float scale) { ui_netSource.integer = 0; } trap_SP_GetStringTextString("MENUS3_SOURCE", holdSPString, sizeof(holdSPString)); - s = va("%s %s", holdSPString, netSources[ui_netSource.integer]); + s = va("%s %s", holdSPString, GetNetSourceString(ui_netSource.integer)); break; case UI_NETFILTER: if (ui_serverFilterType.integer < 0 || ui_serverFilterType.integer > numServerFilters) { @@ -2345,6 +2606,9 @@ static void UI_OwnerDraw(float x, float y, float w, float h, float text_x, float break; case UI_FORCE_SIDE: UI_DrawForceSide(&rect, scale, color, textStyle, uiForceSide, 1, 2, iMenuFont); + break; + case UI_JEDI_NONJEDI: + UI_DrawJediNonJedi(&rect, scale, color, textStyle, uiJediNonJedi, 0, 1, iMenuFont); break; case UI_FORCE_POINTS: UI_DrawGenericNum(&rect, scale, color, textStyle, uiForceAvailable, 1, forceMasteryPoints[MAX_FORCE_RANK], ownerDraw,iMenuFont); @@ -2705,10 +2969,10 @@ static qboolean UI_OwnerDrawVisible(int flags) { } static qboolean UI_Handicap_HandleKey(int flags, float *special, int key) { - if (key == K_MOUSE1 || key == K_MOUSE2 || key == K_ENTER || key == K_KP_ENTER) { + if (key == A_MOUSE1 || key == A_MOUSE2 || key == A_ENTER || key == A_KP_ENTER) { int h; h = Com_Clamp( 5, 100, trap_Cvar_VariableValue("handicap") ); - if (key == K_MOUSE2) { + if (key == A_MOUSE2) { h -= 5; } else { h += 5; @@ -2725,7 +2989,7 @@ static qboolean UI_Handicap_HandleKey(int flags, float *special, int key) { } static qboolean UI_Effects_HandleKey(int flags, float *special, int key) { - if (key == K_MOUSE1 || key == K_MOUSE2 || key == K_ENTER || key == K_KP_ENTER) { + if (key == A_MOUSE1 || key == A_MOUSE2 || key == A_ENTER || key == A_KP_ENTER) { int team = (int)(trap_Cvar_VariableValue("ui_myteam")); @@ -2735,7 +2999,7 @@ static qboolean UI_Effects_HandleKey(int flags, float *special, int key) { } - if (key == K_MOUSE2) { + if (key == A_MOUSE2) { uiInfo.effectsColor--; } else { uiInfo.effectsColor++; @@ -2754,14 +3018,14 @@ static qboolean UI_Effects_HandleKey(int flags, float *special, int key) { } static qboolean UI_ClanName_HandleKey(int flags, float *special, int key) { - if (key == K_MOUSE1 || key == K_MOUSE2 || key == K_ENTER || key == K_KP_ENTER) { + if (key == A_MOUSE1 || key == A_MOUSE2 || key == A_ENTER || key == A_KP_ENTER) { int i; i = UI_TeamIndexFromName(UI_Cvar_VariableString("ui_teamName")); if (uiInfo.teamList[i].cinematic >= 0) { trap_CIN_StopCinematic(uiInfo.teamList[i].cinematic); uiInfo.teamList[i].cinematic = -1; } - if (key == K_MOUSE2) { + if (key == A_MOUSE2) { i--; } else { i++; @@ -2781,11 +3045,11 @@ static qboolean UI_ClanName_HandleKey(int flags, float *special, int key) { } static qboolean UI_GameType_HandleKey(int flags, float *special, int key, qboolean resetMap) { - if (key == K_MOUSE1 || key == K_MOUSE2 || key == K_ENTER || key == K_KP_ENTER) { + if (key == A_MOUSE1 || key == A_MOUSE2 || key == A_ENTER || key == A_KP_ENTER) { int oldCount = UI_MapCountByGameType(qtrue); // hard coded mess here - if (key == K_MOUSE2) { + if (key == A_MOUSE2) { ui_gameType.integer--; if (ui_gameType.integer == 2) { ui_gameType.integer = 1; @@ -2820,9 +3084,9 @@ static qboolean UI_GameType_HandleKey(int flags, float *special, int key, qboole } static qboolean UI_NetGameType_HandleKey(int flags, float *special, int key) { - if (key == K_MOUSE1 || key == K_MOUSE2 || key == K_ENTER || key == K_KP_ENTER) { + if (key == A_MOUSE1 || key == A_MOUSE2 || key == A_ENTER || key == A_KP_ENTER) { - if (key == K_MOUSE2) { + if (key == A_MOUSE2) { ui_netGameType.integer--; } else { ui_netGameType.integer++; @@ -2845,10 +3109,10 @@ static qboolean UI_NetGameType_HandleKey(int flags, float *special, int key) { } static qboolean UI_AutoSwitch_HandleKey(int flags, float *special, int key) { - if (key == K_MOUSE1 || key == K_MOUSE2 || key == K_ENTER || key == K_KP_ENTER) { + if (key == A_MOUSE1 || key == A_MOUSE2 || key == A_ENTER || key == A_KP_ENTER) { int switchVal = trap_Cvar_VariableValue("cg_autoswitch"); - if (key == K_MOUSE2) { + if (key == A_MOUSE2) { switchVal--; } else { switchVal++; @@ -2870,9 +3134,9 @@ static qboolean UI_AutoSwitch_HandleKey(int flags, float *special, int key) { } static qboolean UI_JoinGameType_HandleKey(int flags, float *special, int key) { - if (key == K_MOUSE1 || key == K_MOUSE2 || key == K_ENTER || key == K_KP_ENTER) { + if (key == A_MOUSE1 || key == A_MOUSE2 || key == A_ENTER || key == A_KP_ENTER) { - if (key == K_MOUSE2) { + if (key == A_MOUSE2) { ui_joinGameType.integer--; } else { ui_joinGameType.integer++; @@ -2894,10 +3158,10 @@ static qboolean UI_JoinGameType_HandleKey(int flags, float *special, int key) { static qboolean UI_Skill_HandleKey(int flags, float *special, int key) { - if (key == K_MOUSE1 || key == K_MOUSE2 || key == K_ENTER || key == K_KP_ENTER) { + if (key == A_MOUSE1 || key == A_MOUSE2 || key == A_ENTER || key == A_KP_ENTER) { int i = trap_Cvar_VariableValue( "g_spSkill" ); - if (key == K_MOUSE2) { + if (key == A_MOUSE2) { i--; } else { i++; @@ -2917,11 +3181,11 @@ static qboolean UI_Skill_HandleKey(int flags, float *special, int key) { static qboolean UI_TeamName_HandleKey(int flags, float *special, int key, qboolean blue) { - if (key == K_MOUSE1 || key == K_MOUSE2 || key == K_ENTER || key == K_KP_ENTER) { + if (key == A_MOUSE1 || key == A_MOUSE2 || key == A_ENTER || key == A_KP_ENTER) { int i; i = UI_TeamIndexFromName(UI_Cvar_VariableString((blue) ? "ui_blueTeam" : "ui_redTeam")); - if (key == K_MOUSE2) { + if (key == A_MOUSE2) { i--; } else { i++; @@ -2941,7 +3205,7 @@ static qboolean UI_TeamName_HandleKey(int flags, float *special, int key, qboole } static qboolean UI_TeamMember_HandleKey(int flags, float *special, int key, qboolean blue, int num) { - if (key == K_MOUSE1 || key == K_MOUSE2 || key == K_ENTER || key == K_KP_ENTER) { + if (key == A_MOUSE1 || key == A_MOUSE2 || key == A_ENTER || key == A_KP_ENTER) { // 0 - None // 1 - Human // 2..NumCharacters - Bot @@ -2967,7 +3231,7 @@ static qboolean UI_TeamMember_HandleKey(int flags, float *special, int key, qboo value = 1; } - if (key == K_MOUSE2) { + if (key == A_MOUSE2) { value--; } else { value++; @@ -2994,9 +3258,9 @@ static qboolean UI_TeamMember_HandleKey(int flags, float *special, int key, qboo } static qboolean UI_NetSource_HandleKey(int flags, float *special, int key) { - if (key == K_MOUSE1 || key == K_MOUSE2 || key == K_ENTER || key == K_KP_ENTER) { + if (key == A_MOUSE1 || key == A_MOUSE2 || key == A_ENTER || key == A_KP_ENTER) { - if (key == K_MOUSE2) { + if (key == A_MOUSE2) { ui_netSource.integer--; } else { ui_netSource.integer++; @@ -3019,9 +3283,9 @@ static qboolean UI_NetSource_HandleKey(int flags, float *special, int key) { } static qboolean UI_NetFilter_HandleKey(int flags, float *special, int key) { - if (key == K_MOUSE1 || key == K_MOUSE2 || key == K_ENTER || key == K_KP_ENTER) { + if (key == A_MOUSE1 || key == A_MOUSE2 || key == A_ENTER || key == A_KP_ENTER) { - if (key == K_MOUSE2) { + if (key == A_MOUSE2) { ui_serverFilterType.integer--; } else { ui_serverFilterType.integer++; @@ -3039,8 +3303,8 @@ static qboolean UI_NetFilter_HandleKey(int flags, float *special, int key) { } static qboolean UI_OpponentName_HandleKey(int flags, float *special, int key) { - if (key == K_MOUSE1 || key == K_MOUSE2 || key == K_ENTER || key == K_KP_ENTER) { - if (key == K_MOUSE2) { + if (key == A_MOUSE1 || key == A_MOUSE2 || key == A_ENTER || key == A_KP_ENTER) { + if (key == A_MOUSE2) { UI_PriorOpponent(); } else { UI_NextOpponent(); @@ -3051,11 +3315,11 @@ static qboolean UI_OpponentName_HandleKey(int flags, float *special, int key) { } static qboolean UI_BotName_HandleKey(int flags, float *special, int key) { - if (key == K_MOUSE1 || key == K_MOUSE2 || key == K_ENTER || key == K_KP_ENTER) { + if (key == A_MOUSE1 || key == A_MOUSE2 || key == A_ENTER || key == A_KP_ENTER) { // int game = trap_Cvar_VariableValue("g_gametype"); int value = uiInfo.botIndex; - if (key == K_MOUSE2) { + if (key == A_MOUSE2) { value--; } else { value++; @@ -3083,8 +3347,8 @@ static qboolean UI_BotName_HandleKey(int flags, float *special, int key) { } static qboolean UI_BotSkill_HandleKey(int flags, float *special, int key) { - if (key == K_MOUSE1 || key == K_MOUSE2 || key == K_ENTER || key == K_KP_ENTER) { - if (key == K_MOUSE2) { + if (key == A_MOUSE1 || key == A_MOUSE2 || key == A_ENTER || key == A_KP_ENTER) { + if (key == A_MOUSE2) { uiInfo.skillIndex--; } else { uiInfo.skillIndex++; @@ -3100,7 +3364,7 @@ static qboolean UI_BotSkill_HandleKey(int flags, float *special, int key) { } static qboolean UI_RedBlue_HandleKey(int flags, float *special, int key) { - if (key == K_MOUSE1 || key == K_MOUSE2 || key == K_ENTER || key == K_KP_ENTER) { + if (key == A_MOUSE1 || key == A_MOUSE2 || key == A_ENTER || key == A_KP_ENTER) { uiInfo.redBlue ^= 1; return qtrue; } @@ -3108,8 +3372,8 @@ static qboolean UI_RedBlue_HandleKey(int flags, float *special, int key) { } static qboolean UI_Crosshair_HandleKey(int flags, float *special, int key) { - if (key == K_MOUSE1 || key == K_MOUSE2 || key == K_ENTER || key == K_KP_ENTER) { - if (key == K_MOUSE2) { + if (key == A_MOUSE1 || key == A_MOUSE2 || key == A_ENTER || key == A_KP_ENTER) { + if (key == A_MOUSE2) { uiInfo.currentCrosshair--; } else { uiInfo.currentCrosshair++; @@ -3129,7 +3393,7 @@ static qboolean UI_Crosshair_HandleKey(int flags, float *special, int key) { static qboolean UI_SelectedPlayer_HandleKey(int flags, float *special, int key) { - if (key == K_MOUSE1 || key == K_MOUSE2 || key == K_ENTER || key == K_KP_ENTER) { + if (key == A_MOUSE1 || key == A_MOUSE2 || key == A_ENTER || key == A_KP_ENTER) { int selected; UI_BuildPlayerList(); @@ -3138,7 +3402,7 @@ static qboolean UI_SelectedPlayer_HandleKey(int flags, float *special, int key) } selected = trap_Cvar_VariableValue("cg_selectedPlayer"); - if (key == K_MOUSE2) { + if (key == A_MOUSE2) { selected--; } else { selected++; @@ -3173,6 +3437,9 @@ static qboolean UI_OwnerDrawHandleKey(int ownerDraw, int flags, float *special, break; case UI_FORCE_SIDE: return UI_ForceSide_HandleKey(flags, special, key, uiForceSide, 1, 2, ownerDraw); + break; + case UI_JEDI_NONJEDI: + return UI_JediNonJedi_HandleKey(flags, special, key, uiJediNonJedi, 0, 1, ownerDraw); break; case UI_FORCE_MASTERY_SET: return UI_ForceMaxRank_HandleKey(flags, special, key, uiForceRank, 1, MAX_FORCE_RANK, ownerDraw); @@ -3494,7 +3761,7 @@ static void UI_StartSkirmish(qboolean next) { UI_SelectedMap(index, &actual); if (UI_SetNextMap(actual, index)) { } else { - UI_GameType_HandleKey(0, 0, K_MOUSE1, qfalse); + UI_GameType_HandleKey(0, 0, A_MOUSE1, qfalse); UI_MapCountByGameType(qtrue); Menu_SetFeederSelection(NULL, FEEDER_MAPS, 0, "skirmish"); } @@ -3966,14 +4233,13 @@ static void UI_RunMenuScript(char **args) ui_mapIndex.integer = UI_GetIndexFromSelection(ui_currentMap.integer); trap_Cvar_Set("ui_mapIndex", va("%d", ui_mapIndex.integer)); Menu_SetFeederSelection(NULL, FEEDER_MAPS, ui_mapIndex.integer, "skirmish"); - UI_GameType_HandleKey(0, 0, K_MOUSE1, qfalse); - UI_GameType_HandleKey(0, 0, K_MOUSE2, qfalse); + UI_GameType_HandleKey(0, 0, A_MOUSE1, qfalse); + UI_GameType_HandleKey(0, 0, A_MOUSE2, qfalse); } else if (Q_stricmp(name, "resetDefaults") == 0) { - trap_Cmd_ExecuteText( EXEC_APPEND, "exec mpdefault.cfg\n"); trap_Cmd_ExecuteText( EXEC_APPEND, "cvar_restart\n"); - Controls_SetDefaults(); - trap_Cvar_Set("com_introPlayed", "1" ); + trap_Cmd_ExecuteText( EXEC_APPEND, "exec mpdefault.cfg\n"); trap_Cmd_ExecuteText( EXEC_APPEND, "vid_restart\n" ); + trap_Cvar_Set("com_introPlayed", "1" ); #ifdef USE_CD_KEY } else if (Q_stricmp(name, "getCDKey") == 0) { char out[17]; @@ -4316,7 +4582,26 @@ static void UI_RunMenuScript(char **args) if (String_Parse(args, &teamArg)) { - UI_UpdateClientForcePowers(teamArg); + if ( Q_stricmp( "none", teamArg ) == 0 ) + { + UI_UpdateClientForcePowers(NULL); + } + else if ( Q_stricmp( "same", teamArg ) == 0 ) + {//stay on current team + int myTeam = (int)(trap_Cvar_VariableValue("ui_myteam")); + if ( myTeam != TEAM_SPECTATOR ) + { + UI_UpdateClientForcePowers(UI_TeamName(myTeam));//will cause him to respawn, if it's been 5 seconds since last one + } + else + { + UI_UpdateClientForcePowers(NULL);//just update powers + } + } + else + { + UI_UpdateClientForcePowers(teamArg); + } } else { @@ -4344,10 +4629,6 @@ static void UI_RunMenuScript(char **args) forcePowerDisable |= (1<= 0 && game < numTeamArenaGameTypes) { - return teamArenaGameTypes[game]; + strcpy(needPass,teamArenaGameTypes[game]); } else { - return "Unknown"; + if (ping <= 0) + { + strcpy(needPass,"Inactive"); + } + strcpy(needPass,"Unknown"); } + + return needPass; case SORT_PING : if (ping <= 0) { return "..."; @@ -6107,6 +6451,8 @@ void _UI_Init( qboolean inGameLoad ) { uiInfo.uiDC.Font_StrLenChars = trap_R_Font_StrLenChars; uiInfo.uiDC.Font_HeightPixels = trap_R_Font_HeightPixels; uiInfo.uiDC.Font_DrawString = trap_R_Font_DrawString; + uiInfo.uiDC.Language_IsAsian = trap_Language_IsAsian; + uiInfo.uiDC.Language_UsesSpaces = trap_Language_UsesSpaces; uiInfo.uiDC.AnyLanguage_ReadCharFromString = trap_AnyLanguage_ReadCharFromString; uiInfo.uiDC.ownerDrawItem = &UI_OwnerDraw; uiInfo.uiDC.getValue = &UI_GetValue; @@ -6214,6 +6560,7 @@ void _UI_Init( qboolean inGameLoad ) { uiInfo.previewMovie = -1; trap_Cvar_Register(NULL, "debug_protocol", "", 0 ); + trap_Cvar_Register(NULL, "ui_hidelang", "0", CVAR_INTERNAL ); trap_Cvar_Set("ui_actualNetGameType", va("%d", ui_netGameType.integer)); } @@ -6229,7 +6576,7 @@ void _UI_KeyEvent( int key, qboolean down ) { if (Menu_Count() > 0) { menuDef_t *menu = Menu_GetFocused(); if (menu) { - if (key == K_ESCAPE && down && !Menus_AnyFullScreenVisible()) { + if (key == A_ESCAPE && down && !Menus_AnyFullScreenVisible()) { Menus_CloseAll(); } else { Menu_HandleKey(menu, key, down ); @@ -6414,11 +6761,11 @@ 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 ); + Com_sprintf( buf, bufsize, "%d hr %2d min", time / 3600, (time % 3600) / 60 ); } else if (time > 60) { // mins - Com_sprintf( buf, bufsize, "%d min %d sec", time / 60, time % 60 ); + Com_sprintf( buf, bufsize, "%2d min %2d sec", time / 60, time % 60 ); } else { // secs - Com_sprintf( buf, bufsize, "%d sec", time ); + Com_sprintf( buf, bufsize, "%2d sec", time ); } } @@ -6429,16 +6776,36 @@ void Text_PaintCenter(float x, float y, float scale, vec4_t color, const char *t static void UI_DisplayDownloadInfo( const char *downloadName, float centerPoint, float yStart, float scale, int iMenuFont) { - static char dlText[] = "Downloading:"; - static char etaText[] = "Estimated time left:"; - static char xferText[] = "Transfer rate:"; - + char sDownLoading[256]; + char sEstimatedTimeLeft[256]; + char sTransferRate[256]; + char sOf[20]; + char sCopied[256]; + char sSec[20]; + // int downloadSize, downloadCount, downloadTime; char dlSizeBuf[64], totalSizeBuf[64], xferRateBuf[64], dlTimeBuf[64]; int xferRate; int leftWidth; const char *s; + vec4_t colorLtGreyAlpha = {0, 0, 0, .5}; + + UI_FillRect( 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, colorLtGreyAlpha ); + + s = GetCRDelineatedString("MENUS3","DOWNLOAD_STUFF", 0); // "Downloading:" + strcpy(sDownLoading,s?s:""); + s = GetCRDelineatedString("MENUS3","DOWNLOAD_STUFF", 1); // "Estimated time left:" + strcpy(sEstimatedTimeLeft,s?s:""); + s = GetCRDelineatedString("MENUS3","DOWNLOAD_STUFF", 2); // "Transfer rate:" + strcpy(sTransferRate,s?s:""); + s = GetCRDelineatedString("MENUS3","DOWNLOAD_STUFF", 3); // "of" + strcpy(sOf,s?s:""); + s = GetCRDelineatedString("MENUS3","DOWNLOAD_STUFF", 4); // "copied" + strcpy(sCopied,s?s:""); + s = GetCRDelineatedString("MENUS3","DOWNLOAD_STUFF", 5); // "sec." + strcpy(sSec,s?s:""); + downloadSize = trap_Cvar_VariableValue( "cl_downloadSize" ); downloadCount = trap_Cvar_VariableValue( "cl_downloadCount" ); downloadTime = trap_Cvar_VariableValue( "cl_downloadTime" ); @@ -6446,9 +6813,10 @@ static void UI_DisplayDownloadInfo( const char *downloadName, float centerPoint, leftWidth = 320; UI_SetColor(colorWhite); - Text_PaintCenter(centerPoint, yStart + 112, scale, colorWhite, dlText, 0, iMenuFont); - Text_PaintCenter(centerPoint, yStart + 192, scale, colorWhite, etaText, 0, iMenuFont); - Text_PaintCenter(centerPoint, yStart + 248, scale, colorWhite, xferText, 0, iMenuFont); + + Text_PaintCenter(centerPoint, yStart + 112, scale, colorWhite, sDownLoading, 0, iMenuFont); + Text_PaintCenter(centerPoint, yStart + 192, scale, colorWhite, sEstimatedTimeLeft, 0, iMenuFont); + Text_PaintCenter(centerPoint, yStart + 248, scale, colorWhite, sTransferRate, 0, iMenuFont); if (downloadSize > 0) { s = va( "%s (%d%%)", downloadName, downloadCount * 100 / downloadSize ); @@ -6463,7 +6831,7 @@ static void UI_DisplayDownloadInfo( const char *downloadName, float centerPoint, if (downloadCount < 4096 || !downloadTime) { Text_PaintCenter(leftWidth, yStart+216, scale, colorWhite, "estimating", 0, iMenuFont); - Text_PaintCenter(leftWidth, yStart+160, scale, colorWhite, va("(%s of %s copied)", dlSizeBuf, totalSizeBuf), 0, iMenuFont); + Text_PaintCenter(leftWidth, yStart+160, scale, colorWhite, va("(%s %s %s %s)", dlSizeBuf, sOf, totalSizeBuf, sCopied), 0, iMenuFont); } else { if ((uiInfo.uiDC.realTime - downloadTime) / 1000) { xferRate = downloadCount / ((uiInfo.uiDC.realTime - downloadTime) / 1000); @@ -6481,18 +6849,18 @@ static void UI_DisplayDownloadInfo( const char *downloadName, float centerPoint, (n - (((downloadCount/1024) * n) / (downloadSize/1024))) * 1000); Text_PaintCenter(leftWidth, yStart+216, scale, colorWhite, dlTimeBuf, 0, iMenuFont); - Text_PaintCenter(leftWidth, yStart+160, scale, colorWhite, va("(%s of %s copied)", dlSizeBuf, totalSizeBuf), 0, iMenuFont); + Text_PaintCenter(leftWidth, yStart+160, scale, colorWhite, va("(%s %s %s %s)", dlSizeBuf, sOf, totalSizeBuf, sCopied), 0, iMenuFont); } else { Text_PaintCenter(leftWidth, yStart+216, scale, colorWhite, "estimating", 0, iMenuFont); if (downloadSize) { - Text_PaintCenter(leftWidth, yStart+160, scale, colorWhite, va("(%s of %s copied)", dlSizeBuf, totalSizeBuf), 0, iMenuFont); + Text_PaintCenter(leftWidth, yStart+160, scale, colorWhite, va("(%s %s %s %s)", dlSizeBuf, sOf, totalSizeBuf, sCopied), 0, iMenuFont); } else { - Text_PaintCenter(leftWidth, yStart+160, scale, colorWhite, va("(%s copied)", dlSizeBuf), 0, iMenuFont); + Text_PaintCenter(leftWidth, yStart+160, scale, colorWhite, va("(%s %s)", dlSizeBuf, sCopied), 0, iMenuFont); } } if (xferRate) { - Text_PaintCenter(leftWidth, yStart+272, scale, colorWhite, va("%s/Sec", xferRateBuf), 0, iMenuFont); + Text_PaintCenter(leftWidth, yStart+272, scale, colorWhite, va("%s/%s", xferRateBuf,sSec), 0, iMenuFont); } } } @@ -6744,7 +7112,6 @@ vmCvar_t ui_realCaptureLimit; vmCvar_t ui_realWarmUp; vmCvar_t ui_serverStatusTimeOut; vmCvar_t s_language; -vmCvar_t k_language; // bk001129 - made static to avoid aliasing static cvarTable_t cvarTable[] = { @@ -6874,7 +7241,6 @@ static cvarTable_t cvarTable[] = { { &ui_realCaptureLimit, "capturelimit", "8", CVAR_SERVERINFO | CVAR_ARCHIVE | CVAR_NORESTART}, { &ui_serverStatusTimeOut, "ui_serverStatusTimeOut", "7000", CVAR_ARCHIVE}, { &s_language, "s_language", "english", CVAR_ARCHIVE | CVAR_NORESTART}, - { &k_language, "k_language", "english", CVAR_ARCHIVE | CVAR_NORESTART}, // any default ("" or "american") is fine, only foreign strings ("deutsch" etc) make a different keyboard table get looked at }; // bk001129 - made static to avoid aliasing @@ -6992,7 +7358,7 @@ static void UI_StartServerRefresh(qboolean full) qtime_t q; trap_RealTime(&q); - trap_Cvar_Set( va("ui_lastServerRefresh_%i", ui_netSource.integer), va("%s-%i, %i at %i:%i", MonthAbbrev[q.tm_mon],q.tm_mday, 1900+q.tm_year,q.tm_hour,q.tm_min)); + trap_Cvar_Set( va("ui_lastServerRefresh_%i", ui_netSource.integer), va("%s-%i, %i @ %i:%2i", GetMonthAbbrevString(q.tm_mon),q.tm_mday, 1900+q.tm_year,q.tm_hour,q.tm_min)); if (!full) { UI_UpdatePendingPings(); diff --git a/CODE-mp/ui/ui_players.c b/CODE-mp/ui/ui_players.c new file mode 100644 index 0000000..5111460 --- /dev/null +++ b/CODE-mp/ui/ui_players.c @@ -0,0 +1,1338 @@ +// Copyright (C) 1999-2000 Id Software, Inc. +// +// ui_players.c + +#include "ui_local.h" + + +#define UI_TIMER_GESTURE 2300 +#define UI_TIMER_JUMP 1000 +#define UI_TIMER_LAND 130 +#define UI_TIMER_WEAPON_SWITCH 300 +#define UI_TIMER_ATTACK 500 +#define UI_TIMER_MUZZLE_FLASH 20 +#define UI_TIMER_WEAPON_DELAY 250 + +#define JUMP_HEIGHT 56 + +#define SWINGSPEED 0.3f + +#define SPIN_SPEED 0.9f +#define COAST_TIME 1000 + + +static int dp_realtime; +static float jumpHeight; +sfxHandle_t weaponChangeSound; + + +/* +=============== +UI_PlayerInfo_SetWeapon +=============== +*/ +static void UI_PlayerInfo_SetWeapon( playerInfo_t *pi, weapon_t weaponNum ) { + gitem_t * item; + char path[MAX_QPATH]; + + pi->currentWeapon = 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_BRYAR_PISTOL ) { + weaponNum = WP_NONE; + goto tryagain; + } + weaponNum = WP_BRYAR_PISTOL; + goto tryagain; + } +/* + if ( weaponNum == WP_MACHINEGUN || 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_STUN_BATON: + case WP_SABER: + MAKERGB( pi->flashDlightColor, 0.6f, 0.6f, 1 ); + break; + + case WP_BRYAR_PISTOL: + case WP_BLASTER: + case WP_DISRUPTOR: + case WP_BOWCASTER: + case WP_REPEATER: + case WP_DEMP2: + case WP_FLECHETTE: + case WP_ROCKET_LAUNCHER: + case WP_THERMAL: + case WP_TRIP_MINE: + case WP_DET_PACK: + MAKERGB( pi->flashDlightColor, 1, 1, 0 ); + 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 == BOTH_JUMP1 ) { + 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 == BOTH_GESTURE1 ) { + pi->torsoAnimationTimer = UI_TIMER_GESTURE; + } + + if ( anim == BOTH_ATTACK3 || anim == BOTH_A1_T__B_ ) { + 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_DROPWEAP1 ) { + pi->torsoAnimationTimer = UI_TIMER_WEAPON_SWITCH; + UI_ForceTorsoAnim( pi, TORSO_DROPWEAP1 ); + } + } + + if ( pi->torsoAnimationTimer > 0 ) { + return; + } + + if( currentAnim == BOTH_GESTURE1 ) { + UI_SetTorsoAnim( pi, TORSO_WEAPONREADY3 ); + return; + } + + if( currentAnim == BOTH_ATTACK3 || currentAnim == BOTH_A1_T__B_ ) { + UI_SetTorsoAnim( pi, TORSO_WEAPONREADY3 ); + return; + } + + if ( currentAnim == TORSO_DROPWEAP1 ) { + UI_PlayerInfo_SetWeapon( pi, pi->weapon ); + pi->torsoAnimationTimer = UI_TIMER_WEAPON_SWITCH; + UI_ForceTorsoAnim( pi, TORSO_RAISEWEAP1 ); + return; + } + + if ( currentAnim == TORSO_RAISEWEAP1 ) { + UI_SetTorsoAnim( pi, TORSO_WEAPONREADY3 ); + return; + } +} + + +/* +=============== +UI_LegsSequencing +=============== +*/ +static void UI_LegsSequencing( playerInfo_t *pi ) { + int currentAnim; + + currentAnim = pi->legsAnim & ~ANIM_TOGGLEBIT; + + if ( pi->legsAnimationTimer > 0 ) { + if ( currentAnim == BOTH_JUMP1 ) { + jumpHeight = JUMP_HEIGHT * sin( M_PI * ( UI_TIMER_JUMP - pi->legsAnimationTimer ) / UI_TIMER_JUMP ); + } + return; + } + + if ( currentAnim == BOTH_JUMP1 ) { + UI_ForceLegsAnim( pi, BOTH_LAND1 ); + pi->legsAnimationTimer = UI_TIMER_LAND; + jumpHeight = 0; + return; + } + + if ( currentAnim == BOTH_LAND1 ) { + UI_SetLegsAnim( pi, TORSO_WEAPONREADY3 ); + 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 -= uiInfo.uiDC.frameTime; + if ( pi->legsAnimationTimer < 0 ) { + pi->legsAnimationTimer = 0; + } + + UI_LegsSequencing( pi ); + + if ( pi->legs.yawing && ( pi->legsAnim & ~ANIM_TOGGLEBIT ) == TORSO_WEAPONREADY3 ) { + UI_RunLerpFrame( pi, &pi->legs, TORSO_WEAPONREADY3 ); + } else { + UI_RunLerpFrame( pi, &pi->legs, pi->legsAnim ); + } + *legsOld = pi->legs.oldFrame; + *legs = pi->legs.frame; + *legsBackLerp = pi->legs.backlerp; + + // torso animation + pi->torsoAnimationTimer -= uiInfo.uiDC.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 = uiInfo.uiDC.frameTime * scale * speed; + if ( move >= swing ) { + move = swing; + *swinging = qfalse; + } + *angle = AngleMod( *angle + move ); + } else if ( swing < 0 ) { + move = uiInfo.uiDC.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 ) != TORSO_WEAPONREADY3 + || ( pi->torsoAnim & ~ANIM_TOGGLEBIT ) != TORSO_WEAPONREADY3 ) { + // 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 == BOTH_A1_T__B_ ) { + torsoAnim = BOTH_ATTACK3; + } + if ( pi->barrelSpinning == !(torsoAnim == BOTH_ATTACK3) ) { + pi->barrelTime = dp_realtime; + pi->barrelAngle = AngleMod( angle ); + pi->barrelSpinning = !!(torsoAnim == BOTH_ATTACK3); + } + + 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; + } + + // this allows the ui to cache the player model on the main menu + if (w == 0 || h == 0) { + 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 ); + } + } + + 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 / (float)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_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_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_FileExists +========================== +*/ +static qboolean UI_FileExists(const char *filename) { + int len; + fileHandle_t f; + + len = trap_FS_FOpenFile( filename, &f, FS_READ ); + if (len>0) { + trap_FS_FCloseFile(f); + return qtrue; + } + return qfalse; +} + +/* +========================== +UI_FindClientHeadFile +========================== +*/ +static qboolean UI_FindClientHeadFile( char *filename, int length, const char *teamName, const char *headModelName, const char *headSkinName, const char *base, const char *ext ) { + char *team, *headsFolder; + int i; + + team = "default"; + + if ( headModelName[0] == '*' ) { + headsFolder = "heads/"; + headModelName++; + } + else { + headsFolder = ""; + } + while(1) { + for ( i = 0; i < 2; i++ ) { + if ( i == 0 && teamName && *teamName ) { + Com_sprintf( filename, length, "models/players/%s%s/%s/%s%s_%s.%s", headsFolder, headModelName, headSkinName, teamName, base, team, ext ); + } + else { + Com_sprintf( filename, length, "models/players/%s%s/%s/%s_%s.%s", headsFolder, headModelName, headSkinName, base, team, ext ); + } + if ( UI_FileExists( filename ) ) { + return qtrue; + } + if ( i == 0 && teamName && *teamName ) { + Com_sprintf( filename, length, "models/players/%s%s/%s%s_%s.%s", headsFolder, headModelName, teamName, base, headSkinName, ext ); + } + else { + Com_sprintf( filename, length, "models/players/%s%s/%s_%s.%s", headsFolder, headModelName, base, headSkinName, ext ); + } + if ( UI_FileExists( filename ) ) { + return qtrue; + } + if ( !teamName || !*teamName ) { + break; + } + } + // if tried the heads folder first + if ( headsFolder[0] ) { + break; + } + headsFolder = "heads/"; + } + + return qfalse; +} + +/* +========================== +UI_RegisterClientSkin +========================== +*/ +static qboolean UI_RegisterClientSkin( playerInfo_t *pi, const char *modelName, const char *skinName, const char *headModelName, const char *headSkinName , const char *teamName) { + char filename[MAX_QPATH*2]; + + if (teamName && *teamName) { + Com_sprintf( filename, sizeof( filename ), "models/players/%s/%s/lower_%s.skin", modelName, teamName, skinName ); + } else { + Com_sprintf( filename, sizeof( filename ), "models/players/%s/lower_%s.skin", modelName, skinName ); + } + pi->legsSkin = trap_R_RegisterSkin( filename ); + if (!pi->legsSkin) { + if (teamName && *teamName) { + Com_sprintf( filename, sizeof( filename ), "models/players/characters/%s/%s/lower_%s.skin", modelName, teamName, skinName ); + } else { + Com_sprintf( filename, sizeof( filename ), "models/players/characters/%s/lower_%s.skin", modelName, skinName ); + } + pi->legsSkin = trap_R_RegisterSkin( filename ); + } + + if (teamName && *teamName) { + Com_sprintf( filename, sizeof( filename ), "models/players/%s/%s/upper_%s.skin", modelName, teamName, skinName ); + } else { + Com_sprintf( filename, sizeof( filename ), "models/players/%s/upper_%s.skin", modelName, skinName ); + } + pi->torsoSkin = trap_R_RegisterSkin( filename ); + if (!pi->torsoSkin) { + if (teamName && *teamName) { + Com_sprintf( filename, sizeof( filename ), "models/players/characters/%s/%s/upper_%s.skin", modelName, teamName, skinName ); + } else { + Com_sprintf( filename, sizeof( filename ), "models/players/characters/%s/upper_%s.skin", modelName, skinName ); + } + pi->torsoSkin = trap_R_RegisterSkin( filename ); + } + + if ( UI_FindClientHeadFile( filename, sizeof(filename), teamName, headModelName, headSkinName, "head", "skin" ) ) { + 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 ); + + COM_Compress(text); + + // 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( (const char **)&text_p ); + if ( !token ) { + break; + } + if ( !Q_stricmp( token, "footsteps" ) ) { + token = COM_Parse( (const char **)&text_p ); + if ( !token ) { + break; + } + continue; + } else if ( !Q_stricmp( token, "headoffset" ) ) { + for ( i = 0 ; i < 3 ; i++ ) { + token = COM_Parse( (const char **)&text_p ); + if ( !token ) { + break; + } + } + continue; + } else if ( !Q_stricmp( token, "sex" ) ) { + token = COM_Parse( (const char **)&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( (const char **)&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 == BOTH_CROUCH1WALK ) { + skip = animations[BOTH_CROUCH1WALK].firstFrame - animations[BOTH_GESTURE1].firstFrame; + } + if ( i >= BOTH_CROUCH1WALK ) { + animations[i].firstFrame -= skip; + } + + token = COM_Parse( (const char **)&text_p ); + if ( !token ) { + break; + } + animations[i].numFrames = atoi( token ); + + token = COM_Parse( (const char **)&text_p ); + if ( !token ) { + break; + } + animations[i].loopFrames = atoi( token ); + + token = COM_Parse( (const char **)&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, const char *headModelSkinName, const char *teamName ) { + char modelName[MAX_QPATH]; + char skinName[MAX_QPATH]; + char headModelName[MAX_QPATH]; + char headSkinName[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 ) ); + *slash = '\0'; + } + + Q_strncpyz( headModelName, headModelSkinName, sizeof( headModelName ) ); + slash = strchr( headModelName, '/' ); + if ( !slash ) { + // modelName did not include a skin name + Q_strncpyz( headSkinName, "default", sizeof( skinName ) ); + } else { + Q_strncpyz( headSkinName, slash + 1, sizeof( skinName ) ); + *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_sprintf( filename, sizeof( filename ), "models/players/characters/%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_sprintf( filename, sizeof( filename ), "models/players/characters/%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; + } + } + + if (headModelName && headModelName[0] == '*' ) { + Com_sprintf( filename, sizeof( filename ), "models/players/heads/%s/%s.md3", &headModelName[1], &headModelName[1] ); + } + else { + Com_sprintf( filename, sizeof( filename ), "models/players/%s/head.md3", headModelName ); + } + pi->headModel = trap_R_RegisterModel( filename ); + if ( !pi->headModel && headModelName[0] != '*') { + Com_sprintf( filename, sizeof( filename ), "models/players/heads/%s/%s.md3", headModelName, headModelName ); + 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, headModelName, headSkinName, teamName) ) { + if ( !UI_RegisterClientSkin( pi, modelName, "default", headModelName, "default", teamName ) ) { + 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_sprintf( filename, sizeof( filename ), "models/players/characters/%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, const char *headmodel, char *teamName ) { + memset( pi, 0, sizeof(*pi) ); + UI_RegisterClientModelname( pi, model, headmodel, teamName ); + pi->weapon = WP_BRYAR_PISTOL; + 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 != BOTH_JUMP1 && ( currentAnim == BOTH_JUMP1 || currentAnim == BOTH_LAND1 ) ) { + pi->pendingLegsAnim = legsAnim; + } + else if ( legsAnim != currentAnim ) { + jumpHeight = 0; + pi->pendingLegsAnim = 0; + UI_ForceLegsAnim( pi, legsAnim ); + } + + // torso animation + if ( torsoAnim == TORSO_WEAPONREADY3 || torsoAnim == BOTH_STAND2 ) { + if ( weaponNum == WP_NONE || weaponNum == WP_SABER ) { + torsoAnim = BOTH_STAND2; + } + else { + torsoAnim = TORSO_WEAPONREADY3; + } + } + + if ( torsoAnim == BOTH_ATTACK3 || torsoAnim == BOTH_A1_T__B_ ) { + if ( weaponNum == WP_NONE || weaponNum == WP_SABER ) { + torsoAnim = BOTH_A1_T__B_; + } + else { + torsoAnim = BOTH_ATTACK3; + } + pi->muzzleFlashTime = dp_realtime + UI_TIMER_MUZZLE_FLASH; + //FIXME play firing sound here + } + + currentAnim = pi->torsoAnim & ~ANIM_TOGGLEBIT; + + if ( weaponNum != pi->currentWeapon || currentAnim == TORSO_RAISEWEAP1|| currentAnim == TORSO_DROPWEAP1 ) { + pi->pendingTorsoAnim = torsoAnim; + } + else if ( ( currentAnim == BOTH_GESTURE1 || currentAnim == BOTH_ATTACK3 ) && ( torsoAnim != currentAnim ) ) { + pi->pendingTorsoAnim = torsoAnim; + } + else if ( torsoAnim != currentAnim ) { + pi->pendingTorsoAnim = 0; + UI_ForceTorsoAnim( pi, torsoAnim ); + } +} diff --git a/CODE-mp/ui/ui_public.h b/CODE-mp/ui/ui_public.h index 6a73df3..8253068 100644 --- a/CODE-mp/ui/ui_public.h +++ b/CODE-mp/ui/ui_public.h @@ -3,7 +3,7 @@ #ifndef __UI_PUBLIC_H__ #define __UI_PUBLIC_H__ -#define UI_API_VERSION 6 +#define UI_API_VERSION 7 typedef struct { connstate_t connState; @@ -76,6 +76,8 @@ typedef enum { UI_R_FONT_STRLENCHARS, UI_R_FONT_STRHEIGHTPIXELS, UI_R_FONT_DRAWSTRING, + UI_LANGUAGE_ISASIAN, + UI_LANGUAGE_USESSPACES, UI_ANYLANGUAGE_READCHARFROMSTRING, UI_R_MODELBOUNDS, UI_PC_ADD_GLOBAL_DEFINE, diff --git a/CODE-mp/ui/ui_shared.c b/CODE-mp/ui/ui_shared.c index 4b32af3..6e1d15e 100644 --- a/CODE-mp/ui/ui_shared.c +++ b/CODE-mp/ui/ui_shared.c @@ -1572,12 +1572,12 @@ commandDef_t commandList[] = {"setitemcolor", &Script_SetItemColor}, // group/name {"setitemrect", &Script_SetItemRect}, // group/name {"setteamcolor", &Script_SetTeamColor}, // sets this background color to team color - {"setfocus", &Script_SetFocus}, // sets this background color to team color - {"setplayermodel", &Script_SetPlayerModel}, // sets this background color to team color - {"setplayerhead", &Script_SetPlayerHead}, // sets this background color to team color + {"setfocus", &Script_SetFocus}, // sets focus + {"setplayermodel", &Script_SetPlayerModel}, // sets model + {"setplayerhead", &Script_SetPlayerHead}, // sets head {"transition", &Script_Transition}, // group/name - {"setcvar", &Script_SetCvar}, // group/name - {"setcvartocvar", &Script_SetCvarToCvar}, // group/name + {"setcvar", &Script_SetCvar}, // name + {"setcvartocvar", &Script_SetCvarToCvar}, // name {"exec", &Script_Exec}, // group/name {"play", &Script_Play}, // group/name {"playlooped", &Script_playLooped}, // group/name @@ -1754,7 +1754,7 @@ int Item_TextScroll_MaxScroll ( itemDef_t *item ) { textScrollDef_t *scrollPtr = (textScrollDef_t*)item->typeData; - int count = scrollPtr->lineCount; + int count = scrollPtr->iLineCount; int max = count - (int)(item->window.rect.h / scrollPtr->lineHeight) + 1; if (max < 0) @@ -1815,7 +1815,7 @@ int Item_TextScroll_OverLB ( itemDef_t *item, float x, float y ) int count; scrollPtr = (textScrollDef_t*)item->typeData; - count = scrollPtr->lineCount; + count = scrollPtr->iLineCount; r.x = item->window.rect.x + item->window.rect.w - SCROLLBAR_SIZE; r.y = item->window.rect.y; @@ -1872,7 +1872,7 @@ qboolean Item_TextScroll_HandleKey ( itemDef_t *item, int key, qboolean down, qb max = Item_TextScroll_MaxScroll(item); viewmax = (item->window.rect.h / scrollPtr->lineHeight); - if ( key == K_UPARROW || key == K_KP_UPARROW ) + if ( key == A_CURSOR_UP || key == A_KP_8 ) { scrollPtr->startPos--; if (scrollPtr->startPos < 0) @@ -1882,7 +1882,7 @@ qboolean Item_TextScroll_HandleKey ( itemDef_t *item, int key, qboolean down, qb return qtrue; } - if ( key == K_DOWNARROW || key == K_KP_DOWNARROW ) + if ( key == A_CURSOR_DOWN || key == A_KP_2 ) { scrollPtr->startPos++; if (scrollPtr->startPos > max) @@ -1894,7 +1894,7 @@ qboolean Item_TextScroll_HandleKey ( itemDef_t *item, int key, qboolean down, qb } // mouse hit - if (key == K_MOUSE1 || key == K_MOUSE2) + if (key == A_MOUSE1 || key == A_MOUSE2) { if (item->window.flags & WINDOW_LB_LEFTARROW) { @@ -1939,19 +1939,19 @@ qboolean Item_TextScroll_HandleKey ( itemDef_t *item, int key, qboolean down, qb return qtrue; } - if ( key == K_HOME || key == K_KP_HOME) + if ( key == A_HOME || key == A_KP_7) { // home scrollPtr->startPos = 0; return qtrue; } - if ( key == K_END || key == K_KP_END) + if ( key == A_END || key == A_KP_1) { // end scrollPtr->startPos = max; return qtrue; } - if (key == K_PGUP || key == K_KP_PGUP ) + if (key == A_PAGE_UP || key == A_KP_9 ) { scrollPtr->startPos -= viewmax; if (scrollPtr->startPos < 0) @@ -1961,7 +1961,7 @@ qboolean Item_TextScroll_HandleKey ( itemDef_t *item, int key, qboolean down, qb return qtrue; } - if ( key == K_PGDN || key == K_KP_PGDN ) + if ( key == A_PAGE_DOWN || key == A_KP_3 ) { scrollPtr->startPos += viewmax; if (scrollPtr->startPos > max) @@ -2301,7 +2301,7 @@ qboolean Item_ListBox_HandleKey(itemDef_t *item, int key, qboolean down, qboolea max = Item_ListBox_MaxScroll(item); if (item->window.flags & WINDOW_HORIZONTAL) { viewmax = (item->window.rect.w / listPtr->elementWidth); - if ( key == K_LEFTARROW || key == K_KP_LEFTARROW ) + if ( key == A_CURSOR_LEFT || key == A_KP_4 ) { if (!listPtr->notselectable) { listPtr->cursorPos--; @@ -2324,7 +2324,7 @@ qboolean Item_ListBox_HandleKey(itemDef_t *item, int key, qboolean down, qboolea } return qtrue; } - if ( key == K_RIGHTARROW || key == K_KP_RIGHTARROW ) + if ( key == A_CURSOR_RIGHT || key == A_KP_6 ) { if (!listPtr->notselectable) { listPtr->cursorPos++; @@ -2350,7 +2350,7 @@ qboolean Item_ListBox_HandleKey(itemDef_t *item, int key, qboolean down, qboolea } else { viewmax = (item->window.rect.h / listPtr->elementHeight); - if ( key == K_UPARROW || key == K_KP_UPARROW ) + if ( key == A_CURSOR_UP || key == A_KP_8 ) { if (!listPtr->notselectable) { listPtr->cursorPos--; @@ -2373,7 +2373,7 @@ qboolean Item_ListBox_HandleKey(itemDef_t *item, int key, qboolean down, qboolea } return qtrue; } - if ( key == K_DOWNARROW || key == K_KP_DOWNARROW ) + if ( key == A_CURSOR_DOWN || key == A_KP_2 ) { if (!listPtr->notselectable) { listPtr->cursorPos++; @@ -2398,7 +2398,7 @@ qboolean Item_ListBox_HandleKey(itemDef_t *item, int key, qboolean down, qboolea } } // mouse hit - if (key == K_MOUSE1 || key == K_MOUSE2) { + if (key == A_MOUSE1 || key == A_MOUSE2) { if (item->window.flags & WINDOW_LB_LEFTARROW) { listPtr->startPos--; if (listPtr->startPos < 0) { @@ -2443,17 +2443,17 @@ qboolean Item_ListBox_HandleKey(itemDef_t *item, int key, qboolean down, qboolea } return qtrue; } - if ( key == K_HOME || key == K_KP_HOME) { + if ( key == A_HOME || key == A_KP_7) { // home listPtr->startPos = 0; return qtrue; } - if ( key == K_END || key == K_KP_END) { + if ( key == A_END || key == A_KP_1) { // end listPtr->startPos = max; return qtrue; } - if (key == K_PGUP || key == K_KP_PGUP ) { + if (key == A_PAGE_UP || key == A_KP_9 ) { // page up if (!listPtr->notselectable) { listPtr->cursorPos -= viewmax; @@ -2477,7 +2477,7 @@ qboolean Item_ListBox_HandleKey(itemDef_t *item, int key, qboolean down, qboolea } return qtrue; } - if ( key == K_PGDN || key == K_KP_PGDN ) { + if ( key == A_PAGE_DOWN || key == A_KP_3 ) { // page down if (!listPtr->notselectable) { listPtr->cursorPos += viewmax; @@ -2508,7 +2508,7 @@ qboolean Item_ListBox_HandleKey(itemDef_t *item, int key, qboolean down, qboolea qboolean Item_YesNo_HandleKey(itemDef_t *item, int key) { if (Rect_ContainsPoint(&item->window.rect, DC->cursorx, DC->cursory) && item->window.flags & WINDOW_HASFOCUS && item->cvar) { - if (key == K_MOUSE1 || key == K_ENTER || key == K_MOUSE2 || key == K_MOUSE3) { + if (key == A_MOUSE1 || key == A_ENTER || key == A_MOUSE2 || key == A_MOUSE3) { DC->setCVar(item->cvar, va("%i", !DC->getCVarValue(item->cvar))); return qtrue; } @@ -2582,7 +2582,7 @@ qboolean Item_Multi_HandleKey(itemDef_t *item, int key) { multiDef_t *multiPtr = (multiDef_t*)item->typeData; if (multiPtr) { if (Rect_ContainsPoint(&item->window.rect, DC->cursorx, DC->cursory) && item->window.flags & WINDOW_HASFOCUS && item->cvar) { - if (key == K_MOUSE1 || key == K_ENTER || key == K_MOUSE2 || key == K_MOUSE3) { + if (key == A_MOUSE1 || key == A_ENTER || key == A_MOUSE2 || key == A_MOUSE3) { int current = Item_Multi_FindCvarByValue(item) + 1; int max = Item_Multi_CountSettings(item); if ( current < 0 || current >= max ) { @@ -2684,7 +2684,7 @@ qboolean Item_TextField_HandleKey(itemDef_t *item, int key) { } else { - if ( key == K_DEL || key == K_KP_DEL ) { + if ( key == A_DELETE || key == A_KP_PERIOD ) { if ( item->cursorPos < len ) { memmove( buff + item->cursorPos, buff + item->cursorPos + 1, len - item->cursorPos); DC->setCVar(item->cvar, buff); @@ -2692,7 +2692,7 @@ qboolean Item_TextField_HandleKey(itemDef_t *item, int key) { return qtrue; } - if ( key == K_RIGHTARROW || key == K_KP_RIGHTARROW ) + if ( key == A_CURSOR_RIGHT || key == A_KP_6 ) { if (editPtr->maxPaintChars && item->cursorPos >= editPtr->maxPaintChars && item->cursorPos < len) { item->cursorPos++; @@ -2705,7 +2705,7 @@ qboolean Item_TextField_HandleKey(itemDef_t *item, int key) { return qtrue; } - if ( key == K_LEFTARROW || key == K_KP_LEFTARROW ) + if ( key == A_CURSOR_LEFT || key == A_KP_4 ) { if ( item->cursorPos > 0 ) { item->cursorPos--; @@ -2716,13 +2716,13 @@ qboolean Item_TextField_HandleKey(itemDef_t *item, int key) { return qtrue; } - if ( key == K_HOME || key == K_KP_HOME) {// || ( tolower(key) == 'a' && trap_Key_IsDown( K_CTRL ) ) ) { + if ( key == A_HOME || key == A_KP_7) {// || ( tolower(key) == 'a' && trap_Key_IsDown( K_CTRL ) ) ) { item->cursorPos = 0; editPtr->paintOffset = 0; return qtrue; } - if ( key == K_END || key == K_KP_END) {// ( tolower(key) == 'e' && trap_Key_IsDown( K_CTRL ) ) ) { + if ( key == A_END || key == A_KP_1) {// ( tolower(key) == 'e' && trap_Key_IsDown( K_CTRL ) ) ) { item->cursorPos = len; if(item->cursorPos > editPtr->maxPaintChars) { editPtr->paintOffset = len - editPtr->maxPaintChars; @@ -2730,27 +2730,27 @@ qboolean Item_TextField_HandleKey(itemDef_t *item, int key) { return qtrue; } - if ( key == K_INS || key == K_KP_INS ) { + if ( key == A_INSERT || key == A_KP_0 ) { DC->setOverstrikeMode(!DC->getOverstrikeMode()); return qtrue; } } - if (key == K_TAB || key == K_DOWNARROW || key == K_KP_DOWNARROW) { + if (key == A_TAB || key == A_CURSOR_DOWN || key == A_KP_2) { newItem = Menu_SetNextCursorItem(item->parent); if (newItem && (newItem->type == ITEM_TYPE_EDITFIELD || newItem->type == ITEM_TYPE_NUMERICFIELD)) { g_editItem = newItem; } } - if (key == K_UPARROW || key == K_KP_UPARROW) { + if (key == A_CURSOR_UP || key == A_KP_8) { newItem = Menu_SetPrevCursorItem(item->parent); if (newItem && (newItem->type == ITEM_TYPE_EDITFIELD || newItem->type == ITEM_TYPE_NUMERICFIELD)) { g_editItem = newItem; } } - if ( key == K_ENTER || key == K_KP_ENTER || key == K_ESCAPE) { + if ( key == A_ENTER || key == A_KP_ENTER || key == A_ESCAPE) { return qfalse; } @@ -3021,7 +3021,7 @@ qboolean Item_Slider_HandleKey(itemDef_t *item, int key, qboolean down) { //DC->Print("slider handle key\n"); if (item->window.flags & WINDOW_HASFOCUS && item->cvar && Rect_ContainsPoint(&item->window.rect, DC->cursorx, DC->cursory)) { - if (key == K_MOUSE1 || key == K_ENTER || key == K_MOUSE2 || key == K_MOUSE3) { + if (key == A_MOUSE1 || key == A_ENTER || key == A_MOUSE2 || key == A_MOUSE3) { editFieldDef_t *editDef = item->typeData; if (editDef) { rectDef_t testRect; @@ -3066,7 +3066,7 @@ qboolean Item_HandleKey(itemDef_t *item, int key, qboolean down) { captureData = NULL; } else { // bk001206 - parentheses - if ( down && ( key == K_MOUSE1 || key == K_MOUSE2 || key == K_MOUSE3 ) ) { + if ( down && ( key == A_MOUSE1 || key == A_MOUSE2 || key == A_MOUSE3 ) ) { Item_StartCapture(item, key); } } @@ -3087,7 +3087,7 @@ qboolean Item_HandleKey(itemDef_t *item, int key, qboolean down) { break; case ITEM_TYPE_EDITFIELD: case ITEM_TYPE_NUMERICFIELD: - if (key == K_MOUSE1 || key == K_MOUSE2 || key == K_ENTER) + if (key == A_MOUSE1 || key == A_MOUSE2 || key == A_ENTER) { editFieldDef_t *editPtr = (editFieldDef_t*)item->typeData; @@ -3317,11 +3317,11 @@ void Menu_HandleKey(menuDef_t *menu, int key, qboolean down) { g_editItem = NULL; inHandler = qfalse; return; - } else if (key == K_MOUSE1 || key == K_MOUSE2 || key == K_MOUSE3) { + } else if (key == A_MOUSE1 || key == A_MOUSE2 || key == A_MOUSE3) { g_editingField = qfalse; g_editItem = NULL; Display_MouseMove(NULL, DC->cursorx, DC->cursory); - } else if (key == K_TAB || key == K_UPARROW || key == K_DOWNARROW) { + } else if (key == A_TAB || key == A_CURSOR_UP || key == A_CURSOR_DOWN) { return; } } @@ -3335,7 +3335,7 @@ void Menu_HandleKey(menuDef_t *menu, int key, qboolean down) { if (down && !(menu->window.flags & WINDOW_POPUP) && !Rect_ContainsPoint(&menu->window.rect, DC->cursorx, DC->cursory)) { static qboolean inHandleKey = qfalse; // bk001206 - parentheses - if (!inHandleKey && ( key == K_MOUSE1 || key == K_MOUSE2 || key == K_MOUSE3 ) ) { + if (!inHandleKey && ( key == A_MOUSE1 || key == A_MOUSE2 || key == A_MOUSE3 ) ) { inHandleKey = qtrue; Menus_HandleOOBClick(menu, key, down); inHandleKey = qfalse; @@ -3367,23 +3367,23 @@ void Menu_HandleKey(menuDef_t *menu, int key, qboolean down) { // default handling switch ( key ) { - case K_F11: + case A_F11: if (DC->getCVarValue("developer")) { debugMode ^= 1; } break; - case K_F12: + case A_F12: if (DC->getCVarValue("developer")) { DC->executeText(EXEC_APPEND, "screenshot\n"); } break; - case K_KP_UPARROW: - case K_UPARROW: + case A_KP_8: + case A_CURSOR_UP: Menu_SetPrevCursorItem(menu); break; - case K_ESCAPE: + case A_ESCAPE: if (!g_waitingForKey && menu->onESC) { itemDef_t it; it.parent = menu; @@ -3391,14 +3391,14 @@ void Menu_HandleKey(menuDef_t *menu, int key, qboolean down) { } g_waitingForKey = qfalse; break; - case K_TAB: - case K_KP_DOWNARROW: - case K_DOWNARROW: + case A_TAB: + case A_KP_2: + case A_CURSOR_DOWN: Menu_SetNextCursorItem(menu); break; - case K_MOUSE1: - case K_MOUSE2: + case A_MOUSE1: + case A_MOUSE2: if (item) { if (item->type == ITEM_TYPE_TEXT) { if (Rect_ContainsPoint(Item_CorrectedTextRect(item), DC->cursorx, DC->cursory)) { @@ -3419,29 +3419,31 @@ void Menu_HandleKey(menuDef_t *menu, int key, qboolean down) { } 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 A_JOY0: + case A_JOY1: + case A_JOY2: + case A_JOY3: + case A_JOY4: + case A_AUX0: + case A_AUX1: + case A_AUX2: + case A_AUX3: + case A_AUX4: + case A_AUX5: + case A_AUX6: + case A_AUX7: + case A_AUX8: + case A_AUX9: + case A_AUX10: + case A_AUX11: + case A_AUX12: + case A_AUX13: + case A_AUX14: + case A_AUX15: + case A_AUX16: break; - case K_KP_ENTER: - case K_ENTER: + case A_KP_ENTER: + case A_ENTER: if (item) { if (item->type == ITEM_TYPE_EDITFIELD || item->type == ITEM_TYPE_NUMERICFIELD) { item->cursorPos = 0; @@ -3860,22 +3862,22 @@ typedef struct static bind_t g_bindings[] = { - {"+scores", K_TAB, -1, -1, -1}, - {"+button2", K_ENTER, -1, -1, -1}, - {"+speed", K_SHIFT, -1, -1, -1}, - {"+forward", K_UPARROW, -1, -1, -1}, - {"+back", K_DOWNARROW, -1, -1, -1}, + {"+scores", A_TAB, -1, -1, -1}, + {"+button2", A_ENTER, -1, -1, -1}, + {"+speed", A_SHIFT, -1, -1, -1}, + {"+forward", A_CURSOR_UP, -1, -1, -1}, + {"+back", A_CURSOR_DOWN, -1, -1, -1}, {"+moveleft", ',', -1, -1, -1}, {"+moveright", '.', -1, -1, -1}, - {"+moveup", K_SPACE, -1, -1, -1}, + {"+moveup", A_SPACE, -1, -1, -1}, {"+movedown", 'c', -1, -1, -1}, - {"+left", K_LEFTARROW, -1, -1, -1}, - {"+right", K_RIGHTARROW, -1, -1, -1}, - {"+strafe", K_ALT, -1, -1, -1}, - {"+lookup", K_PGDN, -1, -1, -1}, - {"+lookdown", K_DEL, -1, -1, -1}, + {"+left", A_CURSOR_LEFT, -1, -1, -1}, + {"+right", A_CURSOR_RIGHT, -1, -1, -1}, + {"+strafe", A_ALT, -1, -1, -1}, + {"+lookup", A_PAGE_DOWN, -1, -1, -1}, + {"+lookdown", A_DELETE, -1, -1, -1}, {"+mlook", '/', -1, -1, -1}, - {"centerview", K_END, -1, -1, -1}, + {"centerview", A_END, -1, -1, -1}, // {"+zoom", -1, -1, -1, -1}, {"weapon 1", '1', -1, -1, -1}, {"weapon 2", '2', -1, -1, -1}, @@ -3891,7 +3893,7 @@ static bind_t g_bindings[] = {"weapon 11", -1, -1, -1, -1}, {"weapon 12", -1, -1, -1, -1}, {"weapon 13", -1, -1, -1, -1}, - {"+attack", K_CTRL, -1, -1, -1}, + {"+attack", A_CTRL, -1, -1, -1}, {"+altattack", -1, -1, -1, -1}, {"+use", -1, -1, -1, -1}, {"engage_duel", 'h', -1, -1, -1}, @@ -3917,21 +3919,21 @@ static bind_t g_bindings[] = {"tauntTaunt", -1, -1, -1, -1}, {"tauntDeathInsult",-1, -1, -1, -1}, {"tauntGauntlet", -1, -1, -1, -1}, - {"scoresUp", K_INS, -1, -1, -1}, - {"scoresDown", K_DEL, -1, -1, -1}, + {"scoresUp", A_INSERT, -1, -1, -1}, + {"scoresDown", A_DELETE, -1, -1, -1}, {"messagemode", -1, -1, -1, -1}, {"messagemode2", -1, -1, -1, -1}, {"messagemode3", -1, -1, -1, -1}, {"messagemode4", -1, -1, -1, -1}, {"+use", -1, -1, -1, -1}, {"+force_jump", -1, -1, -1, -1}, - {"force_throw", K_F1, -1, -1, -1}, - {"force_pull", K_F2, -1, -1, -1}, - {"force_speed", K_F3, -1, -1, -1}, - {"force_distract", K_F4, -1, -1, -1}, - {"force_heal", K_F5, -1, -1, -1}, - {"+force_grip", K_F6, -1, -1, -1}, - {"+force_lightning",K_F7, -1, -1, -1}, + {"force_throw", A_F1, -1, -1, -1}, + {"force_pull", A_F2, -1, -1, -1}, + {"force_speed", A_F3, -1, -1, -1}, + {"force_distract", A_F4, -1, -1, -1}, + {"force_heal", A_F5, -1, -1, -1}, + {"+force_grip", A_F6, -1, -1, -1}, + {"+force_lightning",A_F7, -1, -1, -1}, //mp only {"+force_drain", -1, -1, -1, -1}, {"force_rage", -1, -1, -1, -1}, @@ -3972,7 +3974,7 @@ static void Controls_GetKeyAssignment (char *command, int *twokeys) twokeys[0] = twokeys[1] = -1; count = 0; - for ( j = 0; j < 256; j++ ) + for ( j = 0; j < MAX_KEYS; j++ ) { DC->getBindingBuf( j, b, 256 ); if ( *b == 0 ) { @@ -4056,31 +4058,6 @@ void Controls_SetConfig(qboolean restart) // ^--this is bad, it shows the cursor during map load, if you need to, add it as an exec cmd to use_joy or something. } -/* -================= -Controls_SetDefaults -================= -*/ -void Controls_SetDefaults( void ) -{ - int i; - - // iterate each command, set its default binding - for (i=0; i < g_bindCount; i++) - { - g_bindings[i].bind1 = g_bindings[i].defaultbind1; - g_bindings[i].bind2 = g_bindings[i].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" ); -} int BindingIDFromName(const char *name) { int i; @@ -4242,7 +4219,7 @@ qboolean Item_Bind_HandleKey(itemDef_t *item, int key, qboolean down) { int id; int i; - if (key == K_MOUSE1 && Rect_ContainsPoint(&item->window.rect, DC->cursorx, DC->cursory) && !g_waitingForKey) + if (key == A_MOUSE1 && Rect_ContainsPoint(&item->window.rect, DC->cursorx, DC->cursory) && !g_waitingForKey) { if (down) { g_waitingForKey = qtrue; @@ -4250,7 +4227,7 @@ qboolean Item_Bind_HandleKey(itemDef_t *item, int key, qboolean down) { } return qtrue; } - else if (key == K_ENTER && !g_waitingForKey) + else if (key == A_ENTER && !g_waitingForKey) { if (down) { @@ -4271,11 +4248,11 @@ qboolean Item_Bind_HandleKey(itemDef_t *item, int key, qboolean down) { switch (key) { - case K_ESCAPE: + case A_ESCAPE: g_waitingForKey = qfalse; return qtrue; - case K_BACKSPACE: + case A_BACKSPACE: id = BindingIDFromName(item->cvar); if (id != -1) { @@ -4461,7 +4438,7 @@ void Item_TextScroll_Paint(itemDef_t *item) int i; textScrollDef_t *scrollPtr = (textScrollDef_t*)item->typeData; - count = scrollPtr->lineCount; + count = scrollPtr->iLineCount; // draw scrollbar to right side of the window x = item->window.rect.x + item->window.rect.w - SCROLLBAR_SIZE - 1; @@ -4490,9 +4467,9 @@ void Item_TextScroll_Paint(itemDef_t *item) for (i = scrollPtr->startPos; i < count; i++) { - char *text; + const char *text; - text = scrollPtr->lines[i]; + text = scrollPtr->pLines[i]; if (!text) { continue; @@ -4515,7 +4492,7 @@ void Item_TextScroll_Paint(itemDef_t *item) void Item_ListBox_Paint(itemDef_t *item) { float x, y, size, count, i, thumb; qhandle_t image; - qhandle_t optionalImage; + qhandle_t optionalImage1, optionalImage2, optionalImage3; listBoxDef_t *listPtr = (listBoxDef_t*)item->typeData; // the listbox is horizontal or vertical and has a fixed size scroll bar going either direction @@ -4577,7 +4554,7 @@ void Item_ListBox_Paint(itemDef_t *item) { // } - text = DC->feederItemText(item->special, item->cursorPos, 0, &optionalImage); + text = DC->feederItemText(item->special, item->cursorPos, 0, &optionalImage1, &optionalImage2, &optionalImage3); if (text) { DC->drawText(item->window.rect.x, item->window.rect.y+item->window.rect.h, item->textscale, item->window.foreColor, text, 0, 0, item->textStyle, item->iMenuFont); @@ -4637,24 +4614,41 @@ void Item_ListBox_Paint(itemDef_t *item) { // which may overdraw the box if it is too small for the element if (listPtr->numColumns > 0) { - int j; + int j;//, subX = listPtr->elementHeight; - for (j = 0; j < listPtr->numColumns; j++) { - text = DC->feederItemText(item->special, i, j, &optionalImage); + for (j = 0; j < listPtr->numColumns; j++) + { + int imageStartX = listPtr->columnInfo[j].pos; + text = DC->feederItemText(item->special, i, j, &optionalImage1, &optionalImage2, &optionalImage3); + /* if (optionalImage >= 0) { DC->drawHandlePic(x + 4 + listPtr->columnInfo[j].pos, y - 1 + listPtr->elementHeight / 2, listPtr->columnInfo[j].width, listPtr->columnInfo[j].width, optionalImage); } - else if (text) + else + */if ( text ) { // DC->drawText(x + 4 + listPtr->columnInfo[j].pos, y + listPtr->elementHeight, item->textscale, item->window.foreColor, text, 0, listPtr->columnInfo[j].maxChars, item->textStyle); DC->drawText(x + 4 + listPtr->columnInfo[j].pos, y, item->textscale, item->window.foreColor, text, 0, listPtr->columnInfo[j].maxChars, item->textStyle, item->iMenuFont); } + if ( j < listPtr->numColumns - 1 ) + { + imageStartX = listPtr->columnInfo[j+1].pos; + } + if (optionalImage3 >= 0) { + DC->drawHandlePic(imageStartX - listPtr->elementHeight*3, y+2, listPtr->elementHeight, listPtr->elementHeight, optionalImage3); + } + if (optionalImage2 >= 0) { + DC->drawHandlePic(imageStartX - listPtr->elementHeight*2, y+2, listPtr->elementHeight, listPtr->elementHeight, optionalImage2); + } + if (optionalImage1 >= 0) { + DC->drawHandlePic(imageStartX - listPtr->elementHeight, y+2, listPtr->elementHeight, listPtr->elementHeight, optionalImage1); + } } } else { - text = DC->feederItemText(item->special, i, 0, &optionalImage); - if (optionalImage >= 0) + text = DC->feederItemText(item->special, i, 0, &optionalImage1, &optionalImage2, &optionalImage3 ); + if ( optionalImage1 >= 0 || optionalImage2 >= 0 || optionalImage3 >= 0) { //DC->drawHandlePic(x + 4 + listPtr->elementHeight, y, listPtr->columnInfo[j].width, listPtr->columnInfo[j].width, optionalImage); } @@ -5043,7 +5037,7 @@ void Menu_ScrollFeeder(menuDef_t *menu, int feeder, qboolean down) { int i; for (i = 0; i < menu->itemCount; i++) { if (menu->items[i]->special == feeder) { - Item_ListBox_HandleKey(menu->items[i], (down) ? K_DOWNARROW : K_UPARROW, qtrue, qtrue); + Item_ListBox_HandleKey(menu->items[i], (down) ? A_CURSOR_DOWN : A_CURSOR_UP, qtrue, qtrue); return; } } @@ -6431,28 +6425,156 @@ qboolean Item_Parse(int handle, itemDef_t *item) { static void Item_TextScroll_BuildLines ( itemDef_t* item ) { +#if 1 + // new asian-aware line breaker... (pasted from elsewhere late @ night, hence aliasing-vars ;-) + // textScrollDef_t* scrollPtr = (textScrollDef_t*) item->typeData; + const char *psText = item->text; // for copy/paste ease + int iBoxWidth = item->window.rect.w - SCROLLBAR_SIZE - 10; + + // this could probably be simplified now, but it was converted from something else I didn't originally write, + // and it works anyway so wtf... + // + const char *psCurrentTextReadPos = psText; + const char *psReadPosAtLineStart = psCurrentTextReadPos; + const char *psBestLineBreakSrcPos = psCurrentTextReadPos; + const char *psLastGood_s; // needed if we get a full screen of chars with no punctuation or space (see usage notes) + qboolean bIsTrailingPunctuation; + unsigned int uiLetter; + + scrollPtr->iLineCount = 0; + memset((char*)scrollPtr->pLines,0,sizeof(scrollPtr->pLines)); + + while (*psCurrentTextReadPos && (scrollPtr->iLineCount < MAX_TEXTSCROLL_LINES) ) + { + char sLineForDisplay[2048]; // ott + + // construct a line... + // + psCurrentTextReadPos = psReadPosAtLineStart; + sLineForDisplay[0] = '\0'; + while ( *psCurrentTextReadPos ) + { + int iAdvanceCount; + psLastGood_s = psCurrentTextReadPos; + + // read letter... + // + uiLetter = trap_AnyLanguage_ReadCharFromString(psCurrentTextReadPos, &iAdvanceCount, &bIsTrailingPunctuation); + psCurrentTextReadPos += iAdvanceCount; + + // concat onto string so far... + // + if (uiLetter == 32 && sLineForDisplay[0] == '\0') + { + psReadPosAtLineStart++; + continue; // unless it's a space at the start of a line, in which case ignore it. + } + + if (uiLetter > 255) + { + Q_strcat(sLineForDisplay, sizeof(sLineForDisplay),va("%c%c",uiLetter >> 8, uiLetter & 0xFF)); + } + else + { + Q_strcat(sLineForDisplay, sizeof(sLineForDisplay),va("%c",uiLetter & 0xFF)); + } + + if (uiLetter == '\n') + { + // explicit new line... + // + sLineForDisplay[ strlen(sLineForDisplay)-1 ] = '\0'; // kill the CR + psReadPosAtLineStart = psCurrentTextReadPos; + psBestLineBreakSrcPos = psCurrentTextReadPos; + + // hack it to fit in with this code... + // + scrollPtr->pLines[ scrollPtr->iLineCount ] = String_Alloc ( sLineForDisplay ); + break; // print this line + } + else + if ( DC->textWidth( sLineForDisplay, item->textscale, item->iMenuFont ) >= iBoxWidth ) + { + // reached screen edge, so cap off string at bytepos after last good position... + // + if (uiLetter > 255 && bIsTrailingPunctuation && !trap_Language_UsesSpaces()) + { + // Special case, don't consider line breaking if you're on an asian punctuation char of + // a language that doesn't use spaces... + // + uiLetter = uiLetter; // breakpoint line only + } + else + { + if (psBestLineBreakSrcPos == psReadPosAtLineStart) + { + // aarrrggh!!!!! we'll only get here is someone has fed in a (probably) garbage string, + // since it doesn't have a single space or punctuation mark right the way across one line + // of the screen. So far, this has only happened in testing when I hardwired a taiwanese + // string into this function while the game was running in english (which should NEVER happen + // normally). On the other hand I suppose it's entirely possible that some taiwanese string + // might have no punctuation at all, so... + // + psBestLineBreakSrcPos = psLastGood_s; // force a break after last good letter + } + + sLineForDisplay[ psBestLineBreakSrcPos - psReadPosAtLineStart ] = '\0'; + psReadPosAtLineStart = psCurrentTextReadPos = psBestLineBreakSrcPos; + + // hack it to fit in with this code... + // + scrollPtr->pLines[ scrollPtr->iLineCount ] = String_Alloc( sLineForDisplay ); + break; // print this line + } + } + + // record last-good linebreak pos... (ie if we've just concat'd a punctuation point (western or asian) or space) + // + if (bIsTrailingPunctuation || uiLetter == ' ' || (uiLetter > 255 && !trap_Language_UsesSpaces())) + { + psBestLineBreakSrcPos = psCurrentTextReadPos; + } + } + + /// arrgghh, this is gettng horrible now... + // + if (scrollPtr->pLines[ scrollPtr->iLineCount ] == NULL && strlen(sLineForDisplay)) + { + // then this is the last line and we've just run out of text, no CR, no overflow etc... + // + scrollPtr->pLines[ scrollPtr->iLineCount ] = String_Alloc( sLineForDisplay ); + } + + scrollPtr->iLineCount++; + } + +#else + // old version... + // int width; char* lineStart; char* lineEnd; float w; float cw; - scrollPtr->lineCount = 0; + textScrollDef_t* scrollPtr = (textScrollDef_t*) item->typeData; + + scrollPtr->iLineCount = 0; width = scrollPtr->maxLineChars; lineStart = (char*)item->text; lineEnd = lineStart; w = 0; // Keep going as long as there are more lines - while ( scrollPtr->lineCount < MAX_TEXTSCROLL_LINES ) + while ( scrollPtr->iLineCount < MAX_TEXTSCROLL_LINES ) { // End of the road if ( *lineEnd == '\0') { if ( lineStart < lineEnd ) { - scrollPtr->lines[ scrollPtr->lineCount++ ] = lineStart; + scrollPtr->pLines[ scrollPtr->iLineCount++ ] = lineStart; } break; @@ -6462,7 +6584,7 @@ static void Item_TextScroll_BuildLines ( itemDef_t* item ) else if ( *lineEnd == '\n' ) { *lineEnd = '\0'; - scrollPtr->lines[ scrollPtr->lineCount++ ] = lineStart; + scrollPtr->pLines[ scrollPtr->iLineCount++ ] = lineStart; lineStart = lineEnd + 1; lineEnd = lineStart; w = 0; @@ -6482,7 +6604,7 @@ static void Item_TextScroll_BuildLines ( itemDef_t* item ) } *lineEnd = '\0'; - scrollPtr->lines[ scrollPtr->lineCount++ ] = lineStart; + scrollPtr->pLines[ scrollPtr->iLineCount++ ] = lineStart; // Skip any whitespaces lineEnd++; @@ -6500,6 +6622,7 @@ static void Item_TextScroll_BuildLines ( itemDef_t* item ) lineEnd++; } } +#endif } // Item_InitControls diff --git a/CODE-mp/ui/ui_shared.h b/CODE-mp/ui/ui_shared.h index 6aef9dc..9afe91b 100644 --- a/CODE-mp/ui/ui_shared.h +++ b/CODE-mp/ui/ui_shared.h @@ -204,8 +204,10 @@ typedef struct textScrollDef_s int maxLineChars; int drawPadding; - int lineCount; - char* lines[MAX_TEXTSCROLL_LINES]; + // changed spelling to make them fall out during compile while I made them asian-aware -Ste + // + int iLineCount; + const char* pLines[MAX_TEXTSCROLL_LINES]; // can contain NULL ptrs that you should skip over during paint. } textScrollDef_t; @@ -353,8 +355,9 @@ typedef struct { int (*Font_StrLenChars) (const char *text); int (*Font_HeightPixels)(const int iFontIndex, const float scale); void (*Font_DrawString)(int ox, int oy, const char *text, const float *rgba, const int setIndex, int iCharLimit, const float scale); - unsigned int (*AnyLanguage_ReadCharFromString)( const char **ppText ); - + qboolean (*Language_IsAsian)(void); + qboolean (*Language_UsesSpaces)(void); + unsigned int (*AnyLanguage_ReadCharFromString)( const char *psText, int *piAdvanceCount, qboolean *pbIsTrailingPunctuation/* = NULL*/ ); void (*ownerDrawItem) (float x, float y, float w, float h, float text_x, float text_y, int ownerDraw, int ownerDrawFlags, int align, float special, float scale, vec4_t color, qhandle_t shader, int textStyle,int iMenuFont); float (*getValue) (int ownerDraw); qboolean (*ownerDrawVisible) (int flags); @@ -370,7 +373,7 @@ typedef struct { void (*startLocalSound)( sfxHandle_t sfx, int channelNum ); qboolean (*ownerDrawHandleKey)(int ownerDraw, int flags, float *special, int key); int (*feederCount)(float feederID); - const char *(*feederItemText)(float feederID, int index, int column, qhandle_t *handle); + const char *(*feederItemText)(float feederID, int index, int column, qhandle_t *handle1, qhandle_t *handle2, qhandle_t *handle3); qhandle_t (*feederItemImage)(float feederID, int index); qboolean (*feederSelection)(float feederID, int index); void (*keynumToStringBuf)( int keynum, char *buf, int buflen ); @@ -462,7 +465,6 @@ qboolean UI_OutOfMemory(); void Controls_GetConfig( void ); void Controls_SetConfig(qboolean restart); -void Controls_SetDefaults( void ); int trap_PC_AddGlobalDefine ( char *define ); int trap_PC_LoadSource ( const char *filename ); @@ -472,6 +474,14 @@ int trap_PC_SourceFileAndLine ( int handle, char *filename, int *line ); int trap_PC_LoadGlobalDefines ( const char* filename ); void trap_PC_RemoveAllGlobalDefines ( void ); +int trap_R_Font_StrLenPixels(const char *text, const int iFontIndex, const float scale); +int trap_R_Font_StrLenChars(const char *text); +int trap_R_Font_HeightPixels(const int iFontIndex, const float scale); +void trap_R_Font_DrawString(int ox, int oy, const char *text, const float *rgba, const int setIndex, int iCharLimit, const float scale); +qboolean trap_Language_IsAsian(void); +qboolean trap_Language_UsesSpaces(void); +unsigned int trap_AnyLanguage_ReadCharFromString( const char *psText, int *piAdvanceCount, qboolean *pbIsTrailingPunctuation ); + qboolean trap_SP_RegisterServer( const char *package ); qboolean trap_SP_Register(char *file ); int trap_SP_GetStringTextString(const char *text, char *buffer, int bufferLength); diff --git a/CODE-mp/ui/ui_syscalls.asm b/CODE-mp/ui/ui_syscalls.asm index 42131d4..2426284 100644 --- a/CODE-mp/ui/ui_syscalls.asm +++ b/CODE-mp/ui/ui_syscalls.asm @@ -27,7 +27,9 @@ equ trap_R_Font_StrLenPixels -58 ; UI_R_FONT_STRLENPIXELS equ trap_R_Font_StrLenChars -59 ; UI_R_FONT_STRLENCHARS equ trap_R_Font_HeightPixels -60 ; UI_R_FONT_STRHEIGHTPIXELS equ trap_R_Font_DrawString -61 ; UI_R_FONT_DRAWSTRING -equ trap_AnyLanguage_ReadCharFromString -62 ; UI_ANYLANGUAGE_READCHARFROMSTRING +equ trap_Language_IsAsian -62 ; UI_LANGUAGE_ISASIAN +equ trap_Language_UsesSpaces -63 ; UI_LANGUAGE_USESSPACES +equ trap_AnyLanguage_ReadCharFromString -64 ; UI_ANYLANGUAGE_READCHARFROMSTRING equ trap_R_RegisterShaderNoMip -21 ; UI_R_REGISTERSHADERNOMIP equ trap_R_ClearScene -22 ; UI_R_CLEARSCENE equ trap_R_AddRefEntityToScene -23 ; UI_R_ADDREFENTITYTOSCENE @@ -36,7 +38,7 @@ equ trap_R_AddLightToScene -25 ; UI_R_ADDLIGHTTOSCENE equ trap_R_RenderScene -26 ; UI_R_RENDERSCENE equ trap_R_SetColor -27 ; UI_R_SETCOLOR equ trap_R_DrawStretchPic -28 ; UI_R_DRAWSTRETCHPIC -equ trap_R_ModelBounds -63 ; UI_R_MODELBOUNDS +equ trap_R_ModelBounds -65 ; UI_R_MODELBOUNDS equ trap_UpdateScreen -29 ; UI_UPDATESCREEN equ trap_CM_LerpTag -30 ; UI_CM_LERPTAG equ trap_S_StartLocalSound -33 ; UI_S_STARTLOCALSOUND @@ -54,44 +56,44 @@ equ trap_GetClipboardData -43 ; UI_GETCLIPBOARDDATA equ trap_GetClientState -45 ; UI_GETCLIENTSTATE equ trap_GetGlconfig -44 ; UI_GETGLCONFIG equ trap_GetConfigString -46 ; UI_GETCONFIGSTRING -equ trap_LAN_GetServerCount -74 ; UI_LAN_GETSERVERCOUNT -equ trap_LAN_GetServerAddressString -75 ; UI_LAN_GETSERVERADDRESSSTRING -equ trap_LAN_GetServerInfo -76 ; UI_LAN_GETSERVERINFO -equ trap_LAN_GetServerPing -91 ; UI_LAN_GETSERVERPING +equ trap_LAN_GetServerCount -76 ; UI_LAN_GETSERVERCOUNT +equ trap_LAN_GetServerAddressString -77 ; UI_LAN_GETSERVERADDRESSSTRING +equ trap_LAN_GetServerInfo -78 ; UI_LAN_GETSERVERINFO +equ trap_LAN_GetServerPing -93 ; UI_LAN_GETSERVERPING equ trap_LAN_GetPingQueueCount -47 ; UI_LAN_GETPINGQUEUECOUNT -equ trap_LAN_ServerStatus -90 ; UI_LAN_SERVERSTATUS -equ trap_LAN_SaveCachedServers -81 ; UI_LAN_SAVECACHEDSERVERS -equ trap_LAN_LoadCachedServers -80 ; UI_LAN_LOADCACHEDSERVERS -equ trap_LAN_ResetPings -79 ; UI_LAN_RESETPINGS +equ trap_LAN_ServerStatus -92 ; UI_LAN_SERVERSTATUS +equ trap_LAN_SaveCachedServers -83 ; UI_LAN_SAVECACHEDSERVERS +equ trap_LAN_LoadCachedServers -82 ; UI_LAN_LOADCACHEDSERVERS +equ trap_LAN_ResetPings -81 ; UI_LAN_RESETPINGS equ trap_LAN_ClearPing -48 ; UI_LAN_CLEARPING equ trap_LAN_GetPing -49 ; UI_LAN_GETPING equ trap_LAN_GetPingInfo -50 ; UI_LAN_GETPINGINFO -equ trap_LAN_MarkServerVisible -77 ; UI_LAN_MARKSERVERVISIBLE -equ trap_LAN_ServerIsVisible -92 ; UI_LAN_SERVERISVISIBLE -equ trap_LAN_UpdateVisiblePings -78 ; UI_LAN_UPDATEVISIBLEPINGS -equ trap_LAN_AddServer -82 ; UI_LAN_ADDSERVER -equ trap_LAN_RemoveServer -83 ; UI_LAN_REMOVESERVER -equ trap_LAN_CompareServers -93 ; UI_LAN_COMPARESERVERS +equ trap_LAN_MarkServerVisible -79 ; UI_LAN_MARKSERVERVISIBLE +equ trap_LAN_ServerIsVisible -94 ; UI_LAN_SERVERISVISIBLE +equ trap_LAN_UpdateVisiblePings -80 ; UI_LAN_UPDATEVISIBLEPINGS +equ trap_LAN_AddServer -84 ; UI_LAN_ADDSERVER +equ trap_LAN_RemoveServer -85 ; UI_LAN_REMOVESERVER +equ trap_LAN_CompareServers -95 ; UI_LAN_COMPARESERVERS equ trap_MemoryRemaining -53 ; UI_MEMORY_REMAINING equ trap_GetCDKey -54 ; UI_GET_CDKEY equ trap_SetCDKey -55 ; UI_SET_CDKEY equ trap_VerifyCDKey -56 ; UI_VERIFY_CDKEY -equ trap_PC_AddGlobalDefine -64 ; UI_PC_ADD_GLOBAL_DEFINE -equ trap_PC_LoadSource -65 ; UI_PC_LOAD_SOURCE -equ trap_PC_FreeSource -66 ; UI_PC_FREE_SOURCE -equ trap_PC_ReadToken -67 ; UI_PC_READ_TOKEN -equ trap_PC_SourceFileAndLine -68 ; UI_PC_SOURCE_FILE_AND_LINE -equ trap_PC_LoadGlobalDefines -69 ; UI_PC_LOAD_GLOBAL_DEFINES -equ trap_PC_RemoveAllGlobalDefines -70 ; UI_PC_REMOVE_ALL_GLOBAL_DEFINES -equ trap_S_StopBackgroundTrack -71 ; UI_S_STOPBACKGROUNDTRACK -equ trap_S_StartBackgroundTrack -72 ; UI_S_STARTBACKGROUNDTRACK -equ trap_RealTime -73 ; UI_REAL_TIME -equ trap_CIN_PlayCinematic -84 ; UI_CIN_PLAYCINEMATIC -equ trap_CIN_StopCinematic -85 ; UI_CIN_STOPCINEMATIC -equ trap_CIN_RunCinematic -86 ; UI_CIN_RUNCINEMATIC -equ trap_CIN_DrawCinematic -87 ; UI_CIN_DRAWCINEMATIC -equ trap_CIN_SetExtents -88 ; UI_CIN_SETEXTENTS -equ trap_R_RemapShader -89 ; UI_R_REMAP_SHADER +equ trap_PC_AddGlobalDefine -66 ; UI_PC_ADD_GLOBAL_DEFINE +equ trap_PC_LoadSource -67 ; UI_PC_LOAD_SOURCE +equ trap_PC_FreeSource -68 ; UI_PC_FREE_SOURCE +equ trap_PC_ReadToken -69 ; UI_PC_READ_TOKEN +equ trap_PC_SourceFileAndLine -70 ; UI_PC_SOURCE_FILE_AND_LINE +equ trap_PC_LoadGlobalDefines -71 ; UI_PC_LOAD_GLOBAL_DEFINES +equ trap_PC_RemoveAllGlobalDefines -72 ; UI_PC_REMOVE_ALL_GLOBAL_DEFINES +equ trap_S_StopBackgroundTrack -73 ; UI_S_STOPBACKGROUNDTRACK +equ trap_S_StartBackgroundTrack -74 ; UI_S_STARTBACKGROUNDTRACK +equ trap_RealTime -75 ; UI_REAL_TIME +equ trap_CIN_PlayCinematic -86 ; UI_CIN_PLAYCINEMATIC +equ trap_CIN_StopCinematic -87 ; UI_CIN_STOPCINEMATIC +equ trap_CIN_RunCinematic -88 ; UI_CIN_RUNCINEMATIC +equ trap_CIN_DrawCinematic -89 ; UI_CIN_DRAWCINEMATIC +equ trap_CIN_SetExtents -90 ; UI_CIN_SETEXTENTS +equ trap_R_RemapShader -91 ; UI_R_REMAP_SHADER equ trap_SP_Register -201 ; UI_SP_REGISTER equ trap_SP_GetStringTextString -202 ; UI_SP_GETSTRINGTEXTSTRING equ trap_G2API_SetBoneAngles -203 ; UI_G2_ANGLEOVERRIDE diff --git a/CODE-mp/ui/ui_syscalls.c b/CODE-mp/ui/ui_syscalls.c index 0bd7e8e..ed3c338 100644 --- a/CODE-mp/ui/ui_syscalls.c +++ b/CODE-mp/ui/ui_syscalls.c @@ -132,9 +132,19 @@ void trap_R_Font_DrawString(int ox, int oy, const char *text, const float *rgba, syscall( UI_R_FONT_DRAWSTRING, ox, oy, text, rgba, setIndex, iCharLimit, PASSFLOAT(scale)); } -unsigned int trap_AnyLanguage_ReadCharFromString( const char **ppText ) +qboolean trap_Language_IsAsian(void) { - return syscall( UI_ANYLANGUAGE_READCHARFROMSTRING, ppText); + return syscall( UI_LANGUAGE_ISASIAN ); +} + +qboolean trap_Language_UsesSpaces(void) +{ + return syscall( UI_LANGUAGE_USESSPACES ); +} + +unsigned int trap_AnyLanguage_ReadCharFromString( const char *psText, int *piAdvanceCount, qboolean *pbIsTrailingPunctuation ) +{ + return syscall( UI_ANYLANGUAGE_READCHARFROMSTRING, psText, piAdvanceCount, pbIsTrailingPunctuation); } qhandle_t trap_R_RegisterShaderNoMip( const char *name ) { diff --git a/CODE-mp/ui/vssver.scc b/CODE-mp/ui/vssver.scc index ad20ece..d63277c 100644 Binary files a/CODE-mp/ui/vssver.scc and b/CODE-mp/ui/vssver.scc differ diff --git a/CODE-mp/unix/makefile b/CODE-mp/unix/makefile index b244f78..a9f86b0 100644 --- a/CODE-mp/unix/makefile +++ b/CODE-mp/unix/makefile @@ -76,7 +76,8 @@ DLL_ONLY=false # bk001205: no mo' -I/usr/include/glide, no FX # bk001205: no mo' -Dstricmp=strcasecmp, see q_shared.h - BASE_CFLAGS = -pipe -fsigned-char -x c++ -D_JK2 -D_M_IX86 + #BASE_CFLAGS = -pipe -fsigned-char -x c++ -D_JK2 -D_M_IX86 -I/home/drews/STLport-4.5.3/stlport -I/opt/intel/compiler50/ia32/include + BASE_CFLAGS = -pipe -fsigned-char -Kc++ -D_JK2 -D_M_IX86 -I/opt/intel/compiler50/ia32/include # rcg010216: DLL_ONLY for PPC ifeq ($(strip $(DLL_ONLY)),true) BASE_CFLAGS += -DDLL_ONLY @@ -104,7 +105,8 @@ DLL_ONLY=false #NEWPGCC=/usr/local/gcc-2.95.2/bin/gcc # bk001205 #NEWPGCC=/loki/global/x86/bin/gcc #NEWPGCC=/usr/bin/gcc - NEWPGCC=/usr/local/bin/gcc + #NEWPGCC=/usr/local/bin/gcc + NEWPGCC=/opt/intel/compiler50/ia32/bin/icc CC=$(shell if [ -f $(NEWPGCC) ]; then echo $(NEWPGCC); else echo pgcc; fi ) CXX=/usr/bin/g++ # TTimo: legacy RELEASE_CFLAGS @@ -126,7 +128,8 @@ DLL_ONLY=false RANLIB=ranlib THREAD_LDFLAGS=-lpthread - LDFLAGS=-ldl -lm -static -lstdc++ + #LDFLAGS=/opt/sxl/lib/sxlgcc3.a -lpthread -ldl -lm -lstdc++ -static -Wl --gc-sections + LDFLAGS=-ldl -lm -lstdc++ -static GLLDFLAGS=-L/usr/X11R6/lib -L$(MESADIR)/lib -lX11 -lXext -lXxf86dga -lXxf86vm TARGETS=\ @@ -169,7 +172,6 @@ fixnames: @if [ ! -d $(GHOUL2DIR)/G2.h ]; then mv $(GHOUL2DIR)/g2.h $(GHOUL2DIR)/G2.h;fi @if [ ! -d $(CMDIR)/ROFFSystem.h ]; then mv $(CMDIR)/roffsystem.h $(CMDIR)/ROFFSystem.h;fi @if [ ! -d $(RDIR)/MatComp.h ] ; then mv $(RDIR)/matcomp.h $(RDIR)/MatComp.h;fi - @if [ ! -d $(CMDIR)/stri.cpp ]; then mv $(CMDIR)/`strip.cpp` $(CMDIR)/stri.cpp;fi makedirs: @@ -211,6 +213,7 @@ Q3DOBJ = \ $(B)/ded/cm_polylib.o \ $(B)/ded/cm_test.o \ $(B)/ded/cm_trace.o \ + $(B)/ded/cm_shader.o \ $(B)/ded/cmd.o \ $(B)/ded/common.o \ $(B)/ded/cvar.o \ @@ -271,8 +274,10 @@ Q3DOBJ = \ $(B)/ded/null_input.o \ $(B)/ded/null_snddma.o \ $(B)/ded/null_glimp.o \ + $(B)/ded/null_renderer.o \ \ $(B)/ded/tr_model.o \ + $(B)/ded/tr_image.o \ $(B)/ded/roffsystem.o \ $(B)/ded/tr_ghoul2.o \ $(B)/ded/matcomp.o \ @@ -280,7 +285,8 @@ Q3DOBJ = \ $(B)/ded/tr_main.o \ $(B)/ded/tr_backend.o \ $(B)/ded/tr_mesh.o \ - $(B)/ded/stri.o \ + $(B)/ded/tr_shader.o \ + $(B)/ded/strip.o \ # \ # $(B)/ded/null_main.o \ # $(B)/ded/null_net.o \ @@ -332,6 +338,7 @@ $(B)/ded/sv_net_chan.o : $(SDIR)/sv_net_chan.cpp; $(DO_DED_CC) $(B)/ded/sv_snapshot.o : $(SDIR)/sv_snapshot.cpp; $(DO_DED_CC) $(B)/ded/sv_world.o : $(SDIR)/sv_world.cpp; $(DO_DED_CC) $(B)/ded/cm_load.o : $(CMDIR)/cm_load.cpp; $(DO_DED_CC) +$(B)/ded/cm_shader.o : $(CMDIR)/cm_shader.cpp; $(DO_DED_CC) $(B)/ded/cm_polylib.o : $(CMDIR)/cm_polylib.cpp; $(DO_DED_CC) $(B)/ded/cm_test.o : $(CMDIR)/cm_test.cpp; $(DO_DED_CC) $(B)/ded/cm_trace.o : $(CMDIR)/cm_trace.cpp; $(DO_DED_CC) @@ -346,7 +353,7 @@ $(B)/ded/net_chan.o : $(CMDIR)/net_chan.cpp; $(DO_DED_CC) $(B)/ded/huffman.o : $(CMDIR)/huffman.cpp; $(DO_DED_CC) $(B)/ded/q_shared.o : $(CMDIR)/q_shared.cpp; $(DO_DED_CC) $(B)/ded/q_math.o : $(GDIR)/q_math.c; $(DO_DED_CC) -$(B)/ded/stri.o : $(CMDIR)/stri.cpp; $(DO_DED_CC) +$(B)/ded/strip.o : $(CMDIR)/strip.cpp; $(DO_DED_CC) $(B)/ded/g2_api.o : $(GHOUL2DIR)/g2_api.cpp; $(DO_DED_CC) $(B)/ded/g2_bolts.o : $(GHOUL2DIR)/g2_bolts.cpp; $(DO_DED_CC) @@ -427,6 +434,7 @@ $(B)/ded/null_snddma.o : $(NDIR)/null_snddma.c; $(DO_DED_CC) $(B)/ded/null_glimp.o : $(NDIR)/null_glimp.c; $(DO_DED_CC) $(B)/ded/null_main.o : $(NDIR)/null_main.c; $(DO_DED_CC) $(B)/ded/null_net.o : $(NDIR)/null_net.c; $(DO_DED_CC) +$(B)/ded/null_renderer.o : $(NDIR)/null_renderer.c; $(DO_DED_CC) $(B)/ded/unzip.o : $(CMDIR)/unzip.cpp; $(DO_DED_CC) $(B)/ded/vm.o : $(CMDIR)/vm.cpp; $(DO_DED_CC) $(B)/ded/vm_interpreted.o : $(CMDIR)/vm_interpreted.cpp; $(DO_DED_CC) diff --git a/CODE-mp/unix/unix_shared.c b/CODE-mp/unix/unix_shared.c index 37d1380..7886ceb 100644 --- a/CODE-mp/unix/unix_shared.c +++ b/CODE-mp/unix/unix_shared.c @@ -303,7 +303,7 @@ char *Sys_DefaultHomePath(void) #ifdef MACOS_X Q_strcat(homePath, sizeof(homePath), "/Library/Application Support/Quake3"); #else - Q_strcat(homePath, sizeof(homePath), "/.q3a"); + Q_strcat(homePath, sizeof(homePath), "/.jkii"); #endif if (mkdir(homePath, 0777)) { if (errno != EEXIST) diff --git a/CODE-mp/unix/vssver.scc b/CODE-mp/unix/vssver.scc index 84dd5a7..c48f019 100644 Binary files a/CODE-mp/unix/vssver.scc and b/CODE-mp/unix/vssver.scc differ diff --git a/CODE-mp/vssver.scc b/CODE-mp/vssver.scc index 2c78430..1c10fb7 100644 Binary files a/CODE-mp/vssver.scc and b/CODE-mp/vssver.scc differ diff --git a/CODE-mp/win32/vssver.scc b/CODE-mp/win32/vssver.scc index c062c2a..f8d9610 100644 Binary files a/CODE-mp/win32/vssver.scc and b/CODE-mp/win32/vssver.scc differ diff --git a/CODE-mp/win32/win_glimp.cpp b/CODE-mp/win32/win_glimp.cpp index 646e2e7..8bca936 100644 --- a/CODE-mp/win32/win_glimp.cpp +++ b/CODE-mp/win32/win_glimp.cpp @@ -724,45 +724,27 @@ static rserr_t GLW_SetMode( int mode, { if ( colorbits == 0 || ( !cdsFullscreen && colorbits >= 15 ) ) { - const char *psErrorTitle_English = "Low Desktop Color Depth"; - const char *psErrorBody_English = "It is highly unlikely that a correct windowed\n" + // since I can't be bothered trying to mess around with asian codepages and MBCS stuff for a windows + // error box that'll only appear if something's seriously fucked then I'm going to fallback to + // english text when these would otherwise be used... + // + char sErrorHead[1024]; // ott + + extern qboolean Language_IsAsian(void); + Q_strncpyz(sErrorHead, Language_IsAsian() ? "Low Desktop Color Depth" : SP_GetStringTextString("CON_TEXT_LOW_DESKTOP_COLOUR_DEPTH"), sizeof(sErrorHead) ); + + const char *psErrorBody = Language_IsAsian() ? + "It is highly unlikely that a correct windowed\n" "display can be initialized with the current\n" "desktop display depth. Select 'OK' to try\n" "anyway. Select 'Cancel' to try a fullscreen\n" - "mode instead."; - - const char *psErrorTitle_German = "Falsche Desktop-Farbtiefe"; - const char *psErrorBody_German = "Es ist unwahrscheinlich, dass bei der momentanen\n" - "Desktop-Farbiefe ein Fenstermodus initialisiert\n" - "werden kann. Mit 'OK' versuchen Sie es dennoch,\n" - "mit 'Abbrechen' wechselt das Spiel in den\n" - "Vollbildmodus."; - - const char *psErrorTitle_French = "Basse Intensité De la Couleur DeskTop"; - const char *psErrorBody_French = "Il est fortement peu probable qu'un correct windowed\n" - "l'affichage peut être initialisé avec la profondeur\n" - "de bureau actuelle d'affichage. Choisissez 'OK'\n" - "pour essayer de toute façon. Choisissez 'ANNUL'\n" - "pour essayer a fullscreen le mode à la place."; - - const char *psHeadText = psErrorTitle_English; - const char *psBodyText = psErrorBody_English; - - if (Language_GetIntegerValue() == SP_LANGUAGE_GERMAN) - { - psHeadText = psErrorTitle_German; - psBodyText = psErrorBody_German; - } - else - if (Language_GetIntegerValue() == SP_LANGUAGE_FRENCH) - { - psHeadText = psErrorTitle_French; - psBodyText = psErrorBody_French; - } + "mode instead." + : + SP_GetStringTextString("CON_TEXT_TRY_ANYWAY"); if ( MessageBox( NULL, - psBodyText, - psHeadText, + psErrorBody, + sErrorHead, MB_OKCANCEL | MB_ICONEXCLAMATION ) != IDOK ) { return RSERR_INVALID_MODE; @@ -1463,6 +1445,12 @@ extern qboolean Sys_LowPhysicalMemory(); ri.Cvar_Set( "r_textureMode", "GL_LINEAR_MIPMAP_NEAREST" ); } + if ( strstr( buf, "kyro" ) ) + { + ri.Cvar_Set( "r_ext_texture_filter_anisotropic", "0"); //KYROs have it avail, but suck at it! + ri.Cvar_Set( "r_ext_preferred_tc_method", "1"); //(Use DXT1 instead of DXT5 - same quality but much better performance on KYRO) + } + //this must be a really sucky card! if ( (glConfig.textureCompression == TC_NONE) || (glConfig.maxActiveTextures < 2) || (glConfig.maxTextureSize <= 512) ) { diff --git a/CODE-mp/win32/win_input.cpp b/CODE-mp/win32/win_input.cpp index 1c35a00..0808211 100644 --- a/CODE-mp/win32/win_input.cpp +++ b/CODE-mp/win32/win_input.cpp @@ -52,8 +52,6 @@ typedef struct { static joystickInfo_t joy; -cvar_t *k_language; - cvar_t *in_midi; cvar_t *in_midiport; cvar_t *in_midichannel; @@ -408,30 +406,30 @@ void IN_DIMouse( int *mx, int *my ) { switch (od.dwOfs) { case DIMOFS_BUTTON0: if (od.dwData & 0x80) - Sys_QueEvent( od.dwTimeStamp, SE_KEY, K_MOUSE1, qtrue, 0, NULL ); + Sys_QueEvent( od.dwTimeStamp, SE_KEY, A_MOUSE1, qtrue, 0, NULL ); else - Sys_QueEvent( od.dwTimeStamp, SE_KEY, K_MOUSE1, qfalse, 0, NULL ); + Sys_QueEvent( od.dwTimeStamp, SE_KEY, A_MOUSE1, qfalse, 0, NULL ); break; case DIMOFS_BUTTON1: if (od.dwData & 0x80) - Sys_QueEvent( od.dwTimeStamp, SE_KEY, K_MOUSE2, qtrue, 0, NULL ); + Sys_QueEvent( od.dwTimeStamp, SE_KEY, A_MOUSE2, qtrue, 0, NULL ); else - Sys_QueEvent( od.dwTimeStamp, SE_KEY, K_MOUSE2, qfalse, 0, NULL ); + Sys_QueEvent( od.dwTimeStamp, SE_KEY, A_MOUSE2, qfalse, 0, NULL ); break; case DIMOFS_BUTTON2: if (od.dwData & 0x80) - Sys_QueEvent( od.dwTimeStamp, SE_KEY, K_MOUSE3, qtrue, 0, NULL ); + Sys_QueEvent( od.dwTimeStamp, SE_KEY, A_MOUSE3, qtrue, 0, NULL ); else - Sys_QueEvent( od.dwTimeStamp, SE_KEY, K_MOUSE3, qfalse, 0, NULL ); + Sys_QueEvent( od.dwTimeStamp, SE_KEY, A_MOUSE3, qfalse, 0, NULL ); break; case DIMOFS_BUTTON3: if (od.dwData & 0x80) - Sys_QueEvent( od.dwTimeStamp, SE_KEY, K_MOUSE4, qtrue, 0, NULL ); + Sys_QueEvent( od.dwTimeStamp, SE_KEY, A_MOUSE4, qtrue, 0, NULL ); else - Sys_QueEvent( od.dwTimeStamp, SE_KEY, K_MOUSE4, qfalse, 0, NULL ); + Sys_QueEvent( od.dwTimeStamp, SE_KEY, A_MOUSE4, qfalse, 0, NULL ); break; } } @@ -549,29 +547,38 @@ void IN_StartupMouse( void ) IN_MouseEvent =========== */ +#define MAX_MOUSE_BUTTONS 5 + +static int mouseConvert[MAX_MOUSE_BUTTONS] = +{ + A_MOUSE1, + A_MOUSE2, + A_MOUSE3, + A_MOUSE4, + A_MOUSE5 +}; + void IN_MouseEvent (int mstate) { int i; if ( !s_wmv.mouseInitialized ) - return; - -// perform button actions - for (i = 0 ; i < 5 ; i++ ) { - if ( (mstate & (1< 255 || qkey < K_AUX1 ) + if ( qkey < A_AUX0 ) + { return; - + } Sys_QueEvent( g_wv.sysMsgTime, SE_KEY, qkey, qfalse, 0, NULL ); } @@ -981,13 +987,16 @@ static void MIDI_NoteOn( int note, int velocity ) int qkey; if ( velocity == 0 ) + { MIDI_NoteOff( note ); + } - qkey = note - 60 + K_AUX1; + qkey = note - 60 + A_AUX0; - if ( qkey > 255 || qkey < K_AUX1 ) + if ( qkey < A_AUX0 ) + { return; - + } Sys_QueEvent( g_wv.sysMsgTime, SE_KEY, qkey, qtrue, 0, NULL ); } diff --git a/CODE-mp/win32/win_local.h b/CODE-mp/win32/win_local.h index ba4bba6..0b4b2f8 100644 --- a/CODE-mp/win32/win_local.h +++ b/CODE-mp/win32/win_local.h @@ -48,7 +48,7 @@ LONG WINAPI MainWndProc ( void Conbuf_AppendText( const char *msg ); -void SNDDMA_Activate( void ); +void SNDDMA_Activate( qboolean bAppActive ); int SNDDMA_InitDS (); typedef struct diff --git a/CODE-mp/win32/win_main.cpp b/CODE-mp/win32/win_main.cpp index c7e6f2c..21035a0 100644 --- a/CODE-mp/win32/win_main.cpp +++ b/CODE-mp/win32/win_main.cpp @@ -428,7 +428,7 @@ void QDECL Sys_Error( const char *error, ... ) { Sys_DestroyConsole(); Com_ShutdownZoneMemory(); -// Com_ShutdownHunkMemory(); + Com_ShutdownHunkMemory(); exit (1); } @@ -443,7 +443,7 @@ void Sys_Quit( void ) { IN_Shutdown(); Sys_DestroyConsole(); Com_ShutdownZoneMemory(); -// Com_ShutdownHunkMemory(); + Com_ShutdownHunkMemory(); exit (0); } @@ -1469,27 +1469,22 @@ void QuickMemTest(void) { // err... // - LPCSTR psContinue = "Your machine failed to allocate %dMB in a memory test, which may mean you'll have problems running this game all the way through.\n\nContinue anyway?"; - LPCSTR psNoMem = "Insufficient memory to run this game!\n"; - - switch (Language_GetIntegerValue()) - { - case SP_LANGUAGE_GERMAN: - - psContinue = "Ihr Computer konnte bei einem Speichertest keine %dMB reservieren, daher werden Sie mit dem Starten des Spiels Probleme haben.\n\nDennoch fortsetzen?"; - psNoMem = "Unzureichender Speicher zum Starten!\n"; - break; - - case SP_LANGUAGE_FRENCH: - - psContinue = "Votre système n'a pu allouer %d Mo lors d'une vérification de la mémoire, ce qui signifie que vous aurez peut-être du mal à faire fonctionner ce jeu. \n\nSouhaitez-vous continuer malgré tout ?"; - psNoMem = "Mémoire insuffisante pour lancer ce jeu !\n"; - break; - } + extern qboolean Language_IsAsian(void); + LPCSTR psContinue = Language_IsAsian() ? + "Your machine failed to allocate %dMB in a memory test, which may mean you'll have problems running this game all the way through.\n\nContinue anyway?" + : + SP_GetStringTextString("CON_TEXT_FAILED_MEMTEST"); + // ( since it's too much hassle doing MBCS code pages and decodings etc for MessageBox command ) #define GetYesNo(psQuery) (!!(MessageBox(NULL,psQuery,"Query",MB_YESNO|MB_ICONWARNING|MB_TASKMODAL)==IDYES)) if (!GetYesNo(va(psContinue,iMemTestMegs))) { + LPCSTR psNoMem = Language_IsAsian() ? + "Insufficient memory to run this game!\n" + : + SP_GetStringTextString("CON_TEXT_INSUFFICIENT_MEMORY"); + // ( since it's too much hassle doing MBCS code pages and decodings etc for MessageBox command ) + Com_Error( ERR_FATAL, psNoMem ); } } diff --git a/CODE-mp/win32/win_shared.cpp b/CODE-mp/win32/win_shared.cpp index c53344f..e4bcec5 100644 --- a/CODE-mp/win32/win_shared.cpp +++ b/CODE-mp/win32/win_shared.cpp @@ -332,15 +332,6 @@ int Sys_GetCPUSpeedOld() { timeBeginPeriod(1); - DWORD clockStart = timeGetTime(); - DWORD clockEnd = clockStart + 100; - - while(clockEnd < clockStart) - { - clockStart = timeGetTime(); - clockEnd = clockStart + 100; - } - #ifdef WIN32 int iPriority; HANDLE hThread = GetCurrentThread(); @@ -352,6 +343,9 @@ int Sys_GetCPUSpeedOld() } #endif // WIN32 + DWORD clockStart = timeGetTime(); + DWORD clockEnd = clockStart + 100; + unsigned long start; unsigned long end; @@ -372,11 +366,11 @@ int Sys_GetCPUSpeedOld() #ifdef WIN32 - // Reset priority - if ( iPriority != THREAD_PRIORITY_ERROR_RETURN ) - { - SetThreadPriority(hThread, iPriority); - } + // Reset priority + if ( iPriority != THREAD_PRIORITY_ERROR_RETURN ) + { + SetThreadPriority(hThread, iPriority); + } #endif // WIN32 timeEndPeriod(1); @@ -462,8 +456,8 @@ int Sys_GetCPUSpeed() t0 = t1; // Reset Initial Time - while ((unsigned long)t1.LowPart-(unsigned long)t0.LowPart<1000 ) { - // Loop until 1000 ticks have passed since last read of hi-res counter. This allows for elapsed time for sampling. + while ((unsigned long)t1.LowPart-(unsigned long)t0.LowPart<2000 ) { + // Loop until enough ticks have passed since last read of hi-res counter. This allows for elapsed time for sampling. QueryPerformanceCounter(&t1); __asm { rdtsc; // Read Time Stamp @@ -503,6 +497,10 @@ int Sys_GetCPUSpeed() if ( ticks%count_freq.LowPart > count_freq.LowPart/2 ) ticks++; // Round up if necessary + if (!ticks){ + ticks++; // prevent DIV by ZERO + } + freq = cycles/ticks; // Cycles / us = MHz if ( cycles%ticks > ticks/2 ) @@ -517,6 +515,10 @@ int Sys_GetCPUSpeed() (abs(3 * freq3-total) > 3*TOLERANCE ))); // Compare last three calculations to average of last three calculations. + if (!total_ticks){ + total_ticks++; // prevent DIV by ZERO + } + // Try one more significant digit. freq3 = ( total_cycles * 10 ) / total_ticks; freq2 = ( total_cycles * 100 ) / total_ticks; diff --git a/CODE-mp/win32/win_snd.cpp b/CODE-mp/win32/win_snd.cpp index 5b910d9..8f842d3 100644 --- a/CODE-mp/win32/win_snd.cpp +++ b/CODE-mp/win32/win_snd.cpp @@ -8,6 +8,7 @@ HRESULT (WINAPI *pDirectSoundCreate)(GUID FAR *lpGUID, LPDIRECTSOUND FAR *lplpDS #define SECONDARY_BUFFER_SIZE 0x10000 +extern int s_UseOpenAL; static qboolean dsound_init; static int sample16; @@ -358,7 +359,13 @@ SNDDMA_Activate When we change windows we need to do this ================= */ -void SNDDMA_Activate( void ) { +void SNDDMA_Activate( qboolean bAppActive ) +{ + if (s_UseOpenAL) + { + S_MuteAllSounds(!bAppActive); + } + if ( !pDS ) { return; } diff --git a/CODE-mp/win32/win_syscon.cpp b/CODE-mp/win32/win_syscon.cpp index 8a617e1..fbe5658 100644 --- a/CODE-mp/win32/win_syscon.cpp +++ b/CODE-mp/win32/win_syscon.cpp @@ -182,8 +182,6 @@ static LONG WINAPI ConWndProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lPara } extern void CompleteCommand( void ) ; -extern int nextHistoryLine; // the last line in the history buffer, not masked -extern int historyLine; // the line being displayed from history buffer LONG WINAPI InputLineWndProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { @@ -210,44 +208,44 @@ LONG WINAPI InputLineWndProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam Sys_Print( va( "]%s\n", inputBuffer ) ); - strcpy(g_consoleField.buffer, inputBuffer); - historyEditLines[nextHistoryLine % COMMAND_HISTORY] = g_consoleField; - nextHistoryLine++; - historyLine = nextHistoryLine; + strcpy(kg.g_consoleField.buffer, inputBuffer); + kg.historyEditLines[kg.nextHistoryLine % COMMAND_HISTORY] = kg.g_consoleField; + kg.nextHistoryLine++; + kg.historyLine = kg.nextHistoryLine; return 0; } else if (wParam == 9 ) { GetWindowText( s_wcd.hwndInputLine, inputBuffer, sizeof( inputBuffer ) ); - strcpy(g_consoleField.buffer, inputBuffer); + strcpy(kg.g_consoleField.buffer, inputBuffer); CompleteCommand(); - SetWindowText( s_wcd.hwndInputLine, g_consoleField.buffer); - SendMessage(s_wcd.hwndInputLine, EM_SETSEL, strlen(g_consoleField.buffer) , MAKELONG(0xffff, 0xffff) ); + SetWindowText( s_wcd.hwndInputLine, kg.g_consoleField.buffer); + SendMessage(s_wcd.hwndInputLine, EM_SETSEL, strlen(kg.g_consoleField.buffer) , MAKELONG(0xffff, 0xffff) ); } case WM_KEYDOWN: if (wParam == VK_UP) { - if ( nextHistoryLine - historyLine < COMMAND_HISTORY && historyLine > 0 ) + if ( kg.nextHistoryLine - kg.historyLine < COMMAND_HISTORY && kg.historyLine > 0 ) { - historyLine--; + kg.historyLine--; } - g_consoleField = historyEditLines[ historyLine % COMMAND_HISTORY ]; - SetWindowText( s_wcd.hwndInputLine, g_consoleField.buffer); - SendMessage(s_wcd.hwndInputLine, EM_SETSEL, strlen(g_consoleField.buffer) , MAKELONG(0xffff, 0xffff) ); + kg.g_consoleField = kg.historyEditLines[ kg.historyLine % COMMAND_HISTORY ]; + SetWindowText( s_wcd.hwndInputLine, kg.g_consoleField.buffer); + SendMessage(s_wcd.hwndInputLine, EM_SETSEL, strlen(kg.g_consoleField.buffer) , MAKELONG(0xffff, 0xffff) ); return 0; } else if (wParam == VK_DOWN) { - if (historyLine == nextHistoryLine) + if (kg.historyLine == kg.nextHistoryLine) { return 0; } - historyLine++; - g_consoleField = historyEditLines[ historyLine % COMMAND_HISTORY ]; - SetWindowText( s_wcd.hwndInputLine, g_consoleField.buffer); - SendMessage(s_wcd.hwndInputLine, EM_SETSEL, strlen(g_consoleField.buffer) , MAKELONG(0xffff, 0xffff) ); + kg.historyLine++; + kg.g_consoleField = kg.historyEditLines[ kg.historyLine % COMMAND_HISTORY ]; + SetWindowText( s_wcd.hwndInputLine, kg.g_consoleField.buffer); + SendMessage(s_wcd.hwndInputLine, EM_SETSEL, strlen(kg.g_consoleField.buffer) , MAKELONG(0xffff, 0xffff) ); return 0; } break; @@ -562,7 +560,7 @@ void Sys_SetErrorText( const char *buf ) if ( !s_wcd.hwndErrorBox ) { s_wcd.hwndErrorBox = CreateWindow( "static", NULL, WS_CHILD | WS_VISIBLE | SS_SUNKEN, - 6, 5, 526, 30, + 6, 5, s_wcd.windowWidth-20, 30, s_wcd.hWnd, ( HMENU ) ERRORBOX_ID, // child window ID g_wv.hInstance, NULL ); diff --git a/CODE-mp/win32/win_wndproc.cpp b/CODE-mp/win32/win_wndproc.cpp index 0ce2551..d778a51 100644 --- a/CODE-mp/win32/win_wndproc.cpp +++ b/CODE-mp/win32/win_wndproc.cpp @@ -4,6 +4,9 @@ WinVars_t g_wv; +// The only directly referenced keycode - the console key (which gives different ascii codes depending on locale) +#define CONSOLE_SCAN_CODE 0x29 + #ifndef WM_MOUSEWHEEL #define WM_MOUSEWHEEL (WM_MOUSELAST+1) // message that will be supported by the OS #endif @@ -94,117 +97,156 @@ static void VID_AppActivate(BOOL fActive, BOOL minimize) //========================================================================== -static byte s_scantokey[128] = - { -// 0 1 2 3 4 5 6 7 -// 8 9 A B C D E F - 0 , 27, '1', '2', '3', '4', '5', '6', - '7', '8', '9', '0', '-', '=', K_BACKSPACE, 9, // 0 - 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', - 'o', 'p', '[', ']', 13 , K_CTRL,'a', 's', // 1 - 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', - '\'' , '`', K_SHIFT,'\\', 'z', 'x', 'c', 'v', // 2 - 'b', 'n', 'm', ',', '.', '/', K_SHIFT,'*', - K_ALT,' ', K_CAPSLOCK , K_F1, K_F2, K_F3, K_F4, K_F5, // 3 - K_F6, K_F7, K_F8, K_F9, K_F10, K_PAUSE, 0 , K_HOME, - K_UPARROW,K_PGUP,K_KP_MINUS,K_LEFTARROW,K_KP_5,K_RIGHTARROW, K_KP_PLUS,K_END, //4 - K_DOWNARROW,K_PGDN,K_INS,K_DEL,0,0, 0, K_F11, - K_F12,0 , 0 , 0 , 0 , 0 , 0 , 0, // 5 - 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0, - 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0, // 6 - 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0, - 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 // 7 -}; -static byte s_scantokey_german[128] = - { -// 0 1 2 3 4 5 6 7 -// 8 9 A B C D E F - 0 , 27, '1', '2', '3', '4', '5', '6', - '7', '8', '9', '0', '?', '\'', K_BACKSPACE, 9, // 0 - 'q', 'w', 'e', 'r', 't', 'z', 'u', 'i', - 'o', 'p', '=', '+', 13 , K_CTRL, 'a', 's', // 1 - 'd', 'f', 'g', 'h', 'j', 'k', 'l', '[', - ']' , '`', K_SHIFT,'#', 'y', 'x', 'c', 'v', // 2 - 'b', 'n', 'm', ',', '.', '-', K_SHIFT,'*', - K_ALT,' ', K_CAPSLOCK , K_F1, K_F2, K_F3, K_F4, K_F5, // 3 - K_F6, K_F7, K_F8, K_F9, K_F10, K_PAUSE, 0 , K_HOME, - K_UPARROW,K_PGUP,K_KP_MINUS,K_LEFTARROW,K_KP_5,K_RIGHTARROW, K_KP_PLUS,K_END, //4 - K_DOWNARROW,K_PGDN,K_INS,K_DEL,0,0, '<', K_F11, - K_F12,0 , 0 , 0 , 0 , 0 , 0 , 0, // 5 - 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0, - 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0, // 6 - 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0, - 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 // 7 -}; - -static byte s_scantokey_french[128] = - { -// 0 1 2 3 4 5 6 7 -// 8 9 A B C D E F - 0 , 27, '1', '2', '3', '4', '5', '6', - '7', '8', '9', '0', ')', '=', K_BACKSPACE, 9, // 0 - 'a', 'z', 'e', 'r', 't', 'y', 'u', 'i', - 'o', 'p', '^', '$', 13 , K_CTRL, 'q', 's', // 1 - 'd', 'f', 'g', 'h', 'j', 'k', 'l', 'm', - '%' , '`', K_SHIFT,'*', 'w', 'x', 'c', 'v', // 2 - 'b', 'n', ',', ';', ':', '!', K_SHIFT,'*', - K_ALT,' ', K_CAPSLOCK , K_F1, K_F2, K_F3, K_F4, K_F5, // 3 - K_F6, K_F7, K_F8, K_F9, K_F10, K_PAUSE, 0 , K_HOME, - K_UPARROW,K_PGUP,K_KP_MINUS,K_LEFTARROW,K_KP_5,K_RIGHTARROW, K_KP_PLUS,K_END, //4 - K_DOWNARROW,K_PGDN,K_INS,K_DEL,0,0, '<', K_F11, - K_F12,0 , 0 , 0 , 0 , 0 , 0 , 0, // 5 - 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0, - 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0, // 6 - 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0, - 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 // 7 -}; - -static byte s_scantokey_spanish[128] = -{ -// 0 1 2 3 4 5 6 7 -// 8 9 A B C D E F - 0 , 27, '1', '2', '3', '4', '5', '6', - '7', '8', '9', '0', '\'', '!', K_BACKSPACE, 9, // 0 - 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', - 'o', 'p', '[', ']', 13 , K_CTRL, 'a', 's', // 1 - 'd', 'f', 'g', 'h', 'j', 'k', 'l', '=', - '{' , '`', K_SHIFT,'}', 'z', 'x', 'c', 'v', // 2 - 'b', 'n', 'm', ',', '.', '-', K_SHIFT,'*', - K_ALT,' ', K_CAPSLOCK , K_F1, K_F2, K_F3, K_F4, K_F5, // 3 - K_F6, K_F7, K_F8, K_F9, K_F10, K_PAUSE, 0 , K_HOME, - K_UPARROW,K_PGUP,K_KP_MINUS,K_LEFTARROW,K_KP_5,K_RIGHTARROW, K_KP_PLUS,K_END, //4 - K_DOWNARROW,K_PGDN,K_INS,K_DEL,0,0, '<', K_F11, - K_F12,0 , 0 , 0 , 0 , 0 , 0 , 0, // 5 - 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0, - 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0, // 6 - 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0, - 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 // 7 -}; - -static byte s_scantokey_italian[128] = -{ -// 0 1 2 3 4 5 6 7 -// 8 9 A B C D E F - 0 , 27, '1', '2', '3', '4', '5', '6', - '7', '8', '9', '0', '\'', '^', K_BACKSPACE, 9, // 0 - 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', - 'o', 'p', '[', ']', 13 , K_CTRL, 'a', 's', // 1 - 'd', 'f', 'g', 'h', 'j', 'k', 'l', '@', - '#' , '`', K_SHIFT,'=', 'z', 'x', 'c', 'v', // 2 - 'b', 'n', 'm', ',', '.', '-', K_SHIFT,'*', - K_ALT,' ', K_CAPSLOCK , K_F1, K_F2, K_F3, K_F4, K_F5, // 3 - K_F6, K_F7, K_F8, K_F9, K_F10, K_PAUSE, 0 , K_HOME, - K_UPARROW,K_PGUP,K_KP_MINUS,K_LEFTARROW,K_KP_5,K_RIGHTARROW, K_KP_PLUS,K_END, //4 - K_DOWNARROW,K_PGDN,K_INS,K_DEL,0,0, '<', K_F11, - K_F12,0 , 0 , 0 , 0 , 0 , 0 , 0, // 5 - 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0, - 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0, // 6 - 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0, - 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 // 7 -}; - -extern cvar_t *k_language; +static byte virtualKeyConvert[0x92][2] = +{ + { 0, 0 }, + { A_MOUSE1, A_MOUSE1 }, // VK_LBUTTON 01 Left mouse button + { A_MOUSE2, A_MOUSE2 }, // VK_RBUTTON 02 Right mouse button + { 0, 0 }, // VK_CANCEL 03 Control-break processing + { A_MOUSE3, A_MOUSE3 }, // VK_MBUTTON 04 Middle mouse button (three-button mouse) + { A_MOUSE4, A_MOUSE4 }, // VK_XBUTTON1 05 Windows 2000/XP: X1 mouse button + { A_MOUSE5, A_MOUSE5 }, // VK_XBUTTON2 06 Windows 2000/XP: X2 mouse button + { 0, 0 }, // 07 Undefined + { A_BACKSPACE, A_BACKSPACE }, // VK_BACK 08 BACKSPACE key + { A_TAB, A_TAB }, // VK_TAB 09 TAB key + { 0, 0 }, // 0A Reserved + { 0, 0 }, // 0B Reserved + { A_KP_5, 0 }, // VK_CLEAR 0C CLEAR key + { A_ENTER, A_KP_ENTER }, // VK_RETURN 0D ENTER key + { 0, 0 }, // 0E Undefined + { 0, 0 }, // 0F Undefined + { A_SHIFT, A_SHIFT }, // VK_SHIFT 10 SHIFT key + { A_CTRL, A_CTRL }, // VK_CONTROL 11 CTRL key + { A_ALT, A_ALT }, // VK_MENU 12 ALT key + { A_PAUSE, A_PAUSE }, // VK_PAUSE 13 PAUSE key + { A_CAPSLOCK, A_CAPSLOCK }, // VK_CAPITAL 14 CAPS LOCK key + { 0, 0 }, // VK_KANA 15 IME Kana mode + { 0, 0 }, // 16 Undefined + { 0, 0 }, // VK_JUNJA 17 IME Junja mode + { 0, 0 }, // VK_FINAL 18 IME final mode + { 0, 0 }, // VK_KANJI 19 IME Kanji mode + { 0, 0 }, // 1A Undefined + { A_ESCAPE, A_ESCAPE }, // VK_ESCAPE 1B ESC key + { 0, 0 }, // VK_CONVERT 1C IME convert + { 0, 0 }, // VK_NONCONVERT 1D IME nonconvert + { 0, 0 }, // VK_ACCEPT 1E IME accept + { 0, 0 }, // VK_MODECHANGE 1F IME mode change request + { A_SPACE, A_SPACE }, // VK_SPACE 20 SPACEBAR + { A_KP_9, A_PAGE_UP }, // VK_PRIOR 21 PAGE UP key + { A_KP_3, A_PAGE_DOWN }, // VK_NEXT 22 PAGE DOWN key + { A_KP_1, A_END }, // VK_END 23 END key + { A_KP_7, A_HOME }, // VK_HOME 24 HOME key + { A_KP_4, A_CURSOR_LEFT }, // VK_LEFT 25 LEFT ARROW key + { A_KP_8, A_CURSOR_UP }, // VK_UP 26 UP ARROW key + { A_KP_6, A_CURSOR_RIGHT }, // VK_RIGHT 27 RIGHT ARROW key + { A_KP_2, A_CURSOR_DOWN }, // VK_DOWN 28 DOWN ARROW key + { 0, 0 }, // VK_SELECT 29 SELECT key + { 0, 0 }, // VK_PRINT 2A PRINT key + { 0, 0 }, // VK_EXECUTE 2B EXECUTE key + { A_PRINTSCREEN, A_PRINTSCREEN }, // VK_SNAPSHOT 2C PRINT SCREEN key + { A_KP_0, A_INSERT }, // VK_INSERT 2D INS key + { A_KP_PERIOD, A_DELETE }, // VK_DELETE 2E DEL key + { 0, 0 }, // VK_HELP 2F HELP key + { A_0, A_0 }, // 30 0 key + { A_1, A_1 }, // 31 1 key + { A_2, A_2 }, // 32 2 key + { A_3, A_3 }, // 33 3 key + { A_4, A_4 }, // 34 4 key + { A_5, A_5 }, // 35 5 key + { A_6, A_6 }, // 36 6 key + { A_7, A_7 }, // 37 7 key + { A_8, A_8 }, // 38 8 key + { A_9, A_9 }, // 39 9 key + { 0, 0 }, // 3A Undefined + { 0, 0 }, // 3B Undefined + { 0, 0 }, // 3C Undefined + { 0, 0 }, // 3D Undefined + { 0, 0 }, // 3E Undefined + { 0, 0 }, // 3F Undefined + { 0, 0 }, // 40 Undefined + { A_CAP_A, A_CAP_A }, // 41 A key + { A_CAP_B, A_CAP_B }, // 42 B key + { A_CAP_C, A_CAP_C }, // 43 C key + { A_CAP_D, A_CAP_D }, // 44 D key + { A_CAP_E, A_CAP_E }, // 45 E key + { A_CAP_F, A_CAP_F }, // 46 F key + { A_CAP_G, A_CAP_G }, // 47 G key + { A_CAP_H, A_CAP_H }, // 48 H key + { A_CAP_I, A_CAP_I }, // 49 I key + { A_CAP_J, A_CAP_J }, // 4A J key + { A_CAP_K, A_CAP_K }, // 4B K key + { A_CAP_L, A_CAP_L }, // 4C L key + { A_CAP_M, A_CAP_M }, // 4D M key + { A_CAP_N, A_CAP_N }, // 4E N key + { A_CAP_O, A_CAP_O }, // 4F O key + { A_CAP_P, A_CAP_P }, // 50 P key + { A_CAP_Q, A_CAP_Q }, // 51 Q key + { A_CAP_R, A_CAP_R }, // 52 R key + { A_CAP_S, A_CAP_S }, // 53 S key + { A_CAP_T, A_CAP_T }, // 54 T key + { A_CAP_U, A_CAP_U }, // 55 U key + { A_CAP_V, A_CAP_V }, // 56 V key + { A_CAP_W, A_CAP_W }, // 57 W key + { A_CAP_X, A_CAP_X }, // 58 X key + { A_CAP_Y, A_CAP_Y }, // 59 Y key + { A_CAP_Z, A_CAP_Z }, // 5A Z key + { 0, 0 }, // VK_LWIN 5B Left Windows key (Microsoft® Natural® keyboard) + { 0, 0 }, // VK_RWIN 5C Right Windows key (Natural keyboard) + { 0, 0 }, // VK_APPS 5D Applications key (Natural keyboard) + { 0, 0 }, // 5E Reserved + { 0, 0 }, // VK_SLEEP 5F Computer Sleep key + { A_KP_0, A_KP_0 }, // VK_NUMPAD0 60 Numeric keypad 0 key + { A_KP_1, A_KP_1 }, // VK_NUMPAD1 61 Numeric keypad 1 key + { A_KP_2, A_KP_2 }, // VK_NUMPAD2 62 Numeric keypad 2 key + { A_KP_3, A_KP_3 }, // VK_NUMPAD3 63 Numeric keypad 3 key + { A_KP_4, A_KP_4 }, // VK_NUMPAD4 64 Numeric keypad 4 key + { A_KP_5, A_KP_5 }, // VK_NUMPAD5 65 Numeric keypad 5 key + { A_KP_6, A_KP_6 }, // VK_NUMPAD6 66 Numeric keypad 6 key + { A_KP_7, A_KP_7 }, // VK_NUMPAD7 67 Numeric keypad 7 key + { A_KP_8, A_KP_8 }, // VK_NUMPAD8 68 Numeric keypad 8 key + { A_KP_9, A_KP_9 }, // VK_NUMPAD9 69 Numeric keypad 9 key + { A_MULTIPLY, A_MULTIPLY }, // VK_MULTIPLY 6A Multiply key + { A_KP_PLUS, A_KP_PLUS }, // VK_ADD 6B Add key + { 0, 0 }, // VK_SEPARATOR 6C Separator key + { A_KP_MINUS, A_KP_MINUS }, // VK_SUBTRACT 6D Subtract key + { A_KP_PERIOD, A_KP_PERIOD }, // VK_DECIMAL 6E Decimal key + { A_DIVIDE, A_DIVIDE }, // VK_DIVIDE 6F Divide key + { A_F1, A_F1 }, // VK_F1 70 F1 key + { A_F2, A_F2 }, // VK_F2 71 F2 key + { A_F3, A_F3 }, // VK_F3 72 F3 key + { A_F4, A_F4 }, // VK_F4 73 F4 key + { A_F5, A_F5 }, // VK_F5 74 F5 key + { A_F6, A_F6 }, // VK_F6 75 F6 key + { A_F7, A_F7 }, // VK_F7 76 F7 key + { A_F8, A_F8 }, // VK_F8 77 F8 key + { A_F9, A_F9 }, // VK_F9 78 F9 key + { A_F10, A_F10 }, // VK_F10 79 F10 key + { A_F11, A_F11 }, // VK_F11 7A F11 key + { A_F12, A_F12 }, // VK_F12 7B F12 key + { 0, 0 }, // VK_F13 7C F13 key + { 0, 0 }, // VK_F14 7D F14 key + { 0, 0 }, // VK_F15 7E F15 key + { 0, 0 }, // VK_F16 7F F16 key + { 0, 0 }, // VK_F17 80H F17 key + { 0, 0 }, // VK_F18 81H F18 key + { 0, 0 }, // VK_F19 82H F19 key + { 0, 0 }, // VK_F20 83H F20 key + { 0, 0 }, // VK_F21 84H F21 key + { 0, 0 }, // VK_F22 85H F22 key + { 0, 0 }, // VK_F23 86H F23 key + { 0, 0 }, // VK_F24 87H F24 key + { 0, 0 }, // 88 Unassigned + { 0, 0 }, // 89 Unassigned + { 0, 0 }, // 8A Unassigned + { 0, 0 }, // 8B Unassigned + { 0, 0 }, // 8C Unassigned + { 0, 0 }, // 8D Unassigned + { 0, 0 }, // 8E Unassigned + { 0, 0 }, // 8F Unassigned + { A_NUMLOCK, A_NUMLOCK }, // VK_NUMLOCK 90 NUM LOCK key + { A_SCROLLLOCK, A_SCROLLLOCK } // VK_SCROLL 91 +}; /* ======= @@ -213,83 +255,35 @@ MapKey Map from windows to quake keynums ======= */ -static int MapKey (int key) +static int MapKey (ulong key, word wParam) { - int result; - int modified; - qboolean is_extended; + ulong result, scan, extended; -// Com_Printf( "0x%x\n", key); - - modified = ( key >> 16 ) & 255; - - if ( modified > 127 ) - return 0; - - if ( key & ( 1 << 24 ) ) + // Check for the console key (hard code to the key you would expect) + scan = ( key >> 16 ) & 0xff; + if(scan == CONSOLE_SCAN_CODE) { - is_extended = qtrue; - } - else - { - is_extended = qfalse; + return(A_CONSOLE); } - result = s_scantokey[modified]; - if ( !Q_stricmp(k_language->string, "deutsch") ) { - result = s_scantokey_german[modified]; - } else if ( !Q_stricmp(k_language->string, "francais") ) { - result = s_scantokey_french[modified]; - } else if ( !Q_stricmp(k_language->string, "espanol") ) { - result = s_scantokey_spanish[modified]; - } else if ( !Q_stricmp(k_language->string, "italiano") ) { - result = s_scantokey_italian[modified]; - } - - - if ( !is_extended ) + // Try to convert the virtual key directly + result = 0; + extended = (key >> 24) & 1; + if(wParam > 0 && wParam <= VK_SCROLL) { - switch ( result ) - { - case K_HOME: - return K_KP_HOME; - case K_UPARROW: - return K_KP_UPARROW; - case K_PGUP: - return K_KP_PGUP; - case K_LEFTARROW: - return K_KP_LEFTARROW; - case K_RIGHTARROW: - return K_KP_RIGHTARROW; - case K_END: - return K_KP_END; - case K_DOWNARROW: - return K_KP_DOWNARROW; - case K_PGDN: - return K_KP_PGDN; - case K_INS: - return K_KP_INS; - case K_DEL: - return K_KP_DEL; - default: - return result; - } + result = virtualKeyConvert[wParam][extended]; } - else + // Get the unshifted ascii code (if any) + if(!result) { - switch ( result ) - { - case K_PAUSE: - return K_KP_NUMLOCK; - case 0x0D: - return K_KP_ENTER; - case 0x2F: - return K_KP_SLASH; - case 0xAF: - return K_KP_PLUS; - } - return result; + result = MapVirtualKey(wParam, 2) & 0xff; } + // Output any debug prints +// if(in_debug && in_debug->integer & 1) +// { +// Com_Printf("WM_KEY: %x : %x : %x\n", key, wParam, result); +// } + return(result); } @@ -312,18 +306,19 @@ LONG WINAPI MainWndProc ( WPARAM wParam, LPARAM lParam) { + byte code; if ( uMsg == MSH_MOUSEWHEEL ) { if ( ( ( int ) wParam ) > 0 ) { - Sys_QueEvent( g_wv.sysMsgTime, SE_KEY, K_MWHEELUP, qtrue, 0, NULL ); - Sys_QueEvent( g_wv.sysMsgTime, SE_KEY, K_MWHEELUP, qfalse, 0, NULL ); + Sys_QueEvent( g_wv.sysMsgTime, SE_KEY, A_MWHEELUP, qtrue, 0, NULL ); + Sys_QueEvent( g_wv.sysMsgTime, SE_KEY, A_MWHEELUP, qfalse, 0, NULL ); } else { - Sys_QueEvent( g_wv.sysMsgTime, SE_KEY, K_MWHEELDOWN, qtrue, 0, NULL ); - Sys_QueEvent( g_wv.sysMsgTime, SE_KEY, K_MWHEELDOWN, qfalse, 0, NULL ); + Sys_QueEvent( g_wv.sysMsgTime, SE_KEY, A_MWHEELDOWN, qtrue, 0, NULL ); + Sys_QueEvent( g_wv.sysMsgTime, SE_KEY, A_MWHEELDOWN, qfalse, 0, NULL ); } return DefWindowProc (hWnd, uMsg, wParam, lParam); } @@ -338,13 +333,13 @@ LONG WINAPI MainWndProc ( // if ( ( short ) HIWORD( wParam ) > 0 ) { - Sys_QueEvent( g_wv.sysMsgTime, SE_KEY, K_MWHEELUP, qtrue, 0, NULL ); - Sys_QueEvent( g_wv.sysMsgTime, SE_KEY, K_MWHEELUP, qfalse, 0, NULL ); + Sys_QueEvent( g_wv.sysMsgTime, SE_KEY, A_MWHEELUP, qtrue, 0, NULL ); + Sys_QueEvent( g_wv.sysMsgTime, SE_KEY, A_MWHEELUP, qfalse, 0, NULL ); } else { - Sys_QueEvent( g_wv.sysMsgTime, SE_KEY, K_MWHEELDOWN, qtrue, 0, NULL ); - Sys_QueEvent( g_wv.sysMsgTime, SE_KEY, K_MWHEELDOWN, qfalse, 0, NULL ); + Sys_QueEvent( g_wv.sysMsgTime, SE_KEY, A_MWHEELDOWN, qtrue, 0, NULL ); + Sys_QueEvent( g_wv.sysMsgTime, SE_KEY, A_MWHEELDOWN, qfalse, 0, NULL ); } break; @@ -402,7 +397,7 @@ LONG WINAPI MainWndProc ( fMinimized = (BOOL) HIWORD(wParam); VID_AppActivate( fActive != WA_INACTIVE, fMinimized); - SNDDMA_Activate(); + SNDDMA_Activate( (qboolean)(fActive != WA_INACTIVE && !fMinimized) ); } break; @@ -473,12 +468,14 @@ LONG WINAPI MainWndProc ( break; case WM_SYSCOMMAND: - if ( wParam == SC_SCREENSAVE ) + if ( (wParam&0xFFF0) == SC_SCREENSAVE || (wParam&0xFFF0) == SC_MONITORPOWER) + { return 0; + } break; case WM_SYSKEYDOWN: - if ( wParam == 13 ) + if ( wParam == VK_RETURN ) { if ( r_fullscreen ) { @@ -489,16 +486,40 @@ LONG WINAPI MainWndProc ( } // fall through case WM_KEYDOWN: - Sys_QueEvent( g_wv.sysMsgTime, SE_KEY, MapKey( lParam ), qtrue, 0, NULL ); + code = MapKey( lParam, wParam ); + if(code) + { + Sys_QueEvent( g_wv.sysMsgTime, SE_KEY, code, qtrue, 0, NULL ); + } break; case WM_SYSKEYUP: case WM_KEYUP: - Sys_QueEvent( g_wv.sysMsgTime, SE_KEY, MapKey( lParam ), qfalse, 0, NULL ); + code = MapKey( lParam, wParam ); + if(code) + { + Sys_QueEvent( g_wv.sysMsgTime, SE_KEY, code, qfalse, 0, NULL ); + } break; case WM_CHAR: - Sys_QueEvent( g_wv.sysMsgTime, SE_CHAR, wParam, 0, 0, NULL ); + if(((lParam >> 16) & 0xff) != CONSOLE_SCAN_CODE) + { + Sys_QueEvent( g_wv.sysMsgTime, SE_CHAR, wParam, 0, 0, NULL ); + } + // Output any debug prints +// if(in_debug && in_debug->integer & 2) +// { +// Com_Printf("WM_CHAR: %x\n", wParam); +// } + break; + + case WM_POWERBROADCAST: + if (wParam == PBT_APMQUERYSUSPEND) + { + Com_Printf("Cannot go into hibernate / standby mode while game is running!\n"); + return BROADCAST_QUERY_DENY; + } break; } diff --git a/code/IFC22.dll b/code/IFC22.dll new file mode 100644 index 0000000..44331c8 Binary files /dev/null and b/code/IFC22.dll differ diff --git a/code/StarWars.opt b/code/StarWars.opt index 61c73dc..dbaca37 100644 Binary files a/code/StarWars.opt and b/code/StarWars.opt differ diff --git a/code/base/ext_data/NPCs.cfg b/code/base/ext_data/NPCs.cfg index 034e381..68a0719 100644 --- a/code/base/ext_data/NPCs.cfg +++ b/code/base/ext_data/NPCs.cfg @@ -1158,7 +1158,7 @@ STOfficer evasion 5 intelligence 5 rank ensign - scale 110 + scale 105 playerTeam enemy enemyTeam player // race klingon @@ -1226,7 +1226,7 @@ STOfficerAlt evasion 5 intelligence 5 rank ensign - scale 110 + scale 105 playerTeam enemy enemyTeam player // race klingon @@ -1262,7 +1262,7 @@ STCommander evasion 5 intelligence 5 rank ensign - scale 110 + scale 105 playerTeam enemy enemyTeam player // race klingon diff --git a/code/base/ext_data/items.dat b/code/base/ext_data/items.dat index 537abb4..41d9e7c 100644 --- a/code/base/ext_data/items.dat +++ b/code/base/ext_data/items.dat @@ -149,7 +149,7 @@ max 10 10 12 itemname ITM_THERMAL_DET_PICKUP classname weapon_thermal -worldmodel models/weapons2/thermal/thermal_w.glm +worldmodel models/weapons2/thermal/thermal_pu.md3 icon gfx/hud/w_icon_thermal // Amount of ammo given with weapon count 50 @@ -163,7 +163,7 @@ max 10 10 12 itemname ITM_TRIP_MINE_PICKUP classname weapon_trip_mine -worldmodel models/weapons2/laser_trap/laser_trap_w.glm +worldmodel models/weapons2/laser_trap/laser_trap_pu.md3 icon gfx/hud/w_icon_tripmine // Amount of ammo given with weapon count 50 @@ -177,7 +177,7 @@ max 10 10 12 itemname ITM_DET_PACK_PICKUP classname weapon_det_pack -worldmodel models/weapons2/detpack/det_pack_w.glm +worldmodel models/weapons2/detpack/det_pack_pu.md3 icon gfx/hud/w_icon_detpack // Amount of ammo given with weapon count 50 diff --git a/code/base/ext_data/vssver.scc b/code/base/ext_data/vssver.scc index 4fc4fca..c15cbd6 100644 Binary files a/code/base/ext_data/vssver.scc and b/code/base/ext_data/vssver.scc differ diff --git a/code/base/ext_data/weapons.dat b/code/base/ext_data/weapons.dat index e6d7975..7953799 100644 --- a/code/base/ext_data/weapons.dat +++ b/code/base/ext_data/weapons.dat @@ -92,6 +92,7 @@ weaponclass weapon_stun_baton weaponmodel models/weapons2/stun_baton/baton.md3 weaponIcon gfx/hud/w_icon_stunbaton firingsound sound/weapons/baton/idle.wav +firingforce fffx/weapons/baton/idle barrelcount 3 ammotype 1 ammolowcount 5 @@ -141,7 +142,9 @@ altrange 8192 muzzleEffect bryar/muzzle_flash altmuzzleEffect bryar/altmuzzle_flash altchargesound sound/weapons/bryar/altcharge.wav -selectSound sound/weapons/bryar/select.wav +altchargeforce fffx/weapons/bryar/altcharge +selectSound sound/weapons/bryar/select.wav +selectforce fffx/weapons/bryar/select } // WP_BLASTER @@ -163,6 +166,7 @@ altmissileFuncName blaster_alt_func muzzleEffect blaster/muzzle_flash altmuzzleEffect blaster/altmuzzle_flash selectSound sound/weapons/blaster/select.wav +selectforce fffx/weapons/blaster/select } // WP_DISRUPTOR @@ -183,7 +187,9 @@ altrange 8192 muzzleEffect disruptor/muzzle_flash altmuzzleEffect disruptor/altmuzzle_flash selectSound sound/weapons/disruptor/select.wav +selectforce fffx/weapons/disruptor/select altchargesound sound/weapons/disruptor/altCharge.wav +altchargeforce fffx/weapons/disruptor/altcharge } // WP_BOWCASTER @@ -193,6 +199,7 @@ weaponclass weapon_bowcaster weaponmodel models/weapons2/bowcaster/bowcaster.md3 weaponIcon gfx/hud/w_icon_bowcaster altchargesound sound/weapons/bowcaster/altcharge.wav +altchargeforce fffx/weapons/bowcaster/altcharge ammotype 3 ammolowcount 15 energypershot 5 @@ -206,7 +213,9 @@ altmissileFuncName bowcaster_func muzzleEffect bowcaster/muzzle_flash altmuzzleEffect bowcaster/altmuzzle_flash selectSound sound/weapons/bowcaster/select.wav +selectforce fffx/weapons/bowcaster/select chargesound sound/weapons/bowcaster/altcharge.wav +chargeforce fffx/weapons/bowcaster/altcharge } // WP_REPEATER @@ -229,6 +238,7 @@ altmissileFuncName repeater_alt_func muzzleEffect repeater/muzzle_flash altmuzzleEffect repeater/altmuzzle_flash selectSound sound/weapons/repeater/select.wav +selectforce fffx/weapons/repeater/select } // WP_DEMP2 @@ -250,7 +260,9 @@ muzzleEffect demp2/muzzle_flash altmissileFuncName demp2_alt_func altmuzzleEffect demp2/altmuzzle_flash selectSound sound/weapons/demp2/select.wav +selectforce fffx/weapons/demp2/select altchargesound sound/weapons/demp2/altCharge.wav +altchargeforce fffx/weapons/demp2/altcharge } @@ -276,6 +288,7 @@ muzzleEffect flechette/muzzle_flash altmuzzleEffect flechette/altmuzzle_flash altmissileModel models/weapons2/golan_arms/projectile.md3 selectSound sound/weapons/flechette/select.wav +selectforce fffx/weapons/flechette/select } // WP_ROCKET_LAUNCHER @@ -306,6 +319,7 @@ altmissileModel models/weapons2/merr_sonn/projectile.md3 missilesound sound/weapons/rocket/missleloop.wav altmissilesound sound/weapons/rocket/missleloop.wav selectSound sound/weapons/rocket/select.wav +selectforce fffx/weapons/rocket/select } @@ -327,8 +341,11 @@ missileModel models/weapons2/thermal/thermal_proj.md3 altmissileModel models/weapons2/thermal/thermal_proj.md3 barrelcount 0 chargesound sound/weapons/thermal/charge.wav +chargeforce fffx/weapons/thermal/charge altchargesound sound/weapons/thermal/charge.wav +altchargeforce fffx/weapons/thermal/charge selectSound sound/weapons/thermal/select.wav +selectforce fffx/weapons/thermal/select muzzleEffect thermal/muzzle_flash } @@ -349,6 +366,7 @@ altrange 8192 missileModel models/weapons2/laser_trap/laser_trap_w.glm altmissileModel models/weapons2/laser_trap/laser_trap_w.glm selectSound sound/weapons/detpack/select.wav +selectforce fffx/weapons/detpack/select muzzleEffect tripmine/muzzle_flash } @@ -369,6 +387,7 @@ altfiretime 400 altrange 8192 missileModel models/weapons2/detpack/det_pack_proj.glm selectSound sound/weapons/detpack/select.wav +selectforce fffx/weapons/detpack/select muzzleEffect detpack/muzzle_flash } diff --git a/code/base/jk2config.cfg b/code/base/jk2config.cfg index 77fff94..b8a8a75 100644 --- a/code/base/jk2config.cfg +++ b/code/base/jk2config.cfg @@ -1,7 +1,17 @@ // generated by Star Wars Jedi Outcast, do not modify unbindall +bind SHIFT "+speed" +bind CTRL "+use" +bind ALT "+altattack" bind TAB "datapad" bind ENTER "invuse" +bind KP_PGDN "use_seeker" +bind KP_LEFTARROW "use_lightamp_goggles" +bind KP_5 "use_sentry" +bind F1 "force_throw" +bind F2 "force_pull" +bind F3 "force_speed" +bind F4 "force_distract" bind SPACE "+moveup" bind , "+moveleft" bind - "weapon 0" @@ -18,196 +28,193 @@ bind 7 "weapon 7" bind 8 "weapon 8" bind 9 "weapon 9" bind = "screenshot silent" +bind A "+moveleft" +bind B "use_bacta" +bind C "+movedown" +bind D "+moveright" +bind E "+use" +bind F "+useforce" +bind G "zoom" +bind L "saberAttackCycle" +bind M "datapad" +bind P "cg_thirdperson !" +bind Q "weapprev" +bind R "weapnext" +bind S "+back" +bind V "+strafe" +bind W "+forward" +bind X "forcenext" +bind Z "forceprev" bind [ "invprev" bind \ "weapongrabbed" bind ] "invnext" bind ` "toggleconsole" -bind a "+moveleft" -bind b "use_bacta" -bind c "+movedown" -bind d "+moveright" -bind e "+use" -bind f "+useforce" -bind g "zoom" -bind l "saberAttackCycle" -bind m "datapad" -bind p "cg_thirdperson !" -bind q "weapprev" -bind r "weapnext" -bind s "+back" -bind v "+strafe" -bind w "+forward" -bind x "forcenext" -bind z "forceprev" bind ~ "toggleconsole" -bind UPARROW "+forward" -bind DOWNARROW "+back" -bind LEFTARROW "+left" -bind RIGHTARROW "+right" -bind ALT "+altattack" -bind CTRL "+use" -bind SHIFT "+speed" -bind PGDN "+lookdown" -bind PGUP "+lookup" -bind END "centerview" -bind F1 "force_throw" -bind F2 "force_pull" -bind F3 "force_speed" -bind F4 "force_distract" bind F5 "force_heal" bind F6 "+force_grip" bind F7 "+force_lightning" +bind MWHEELUP "weapprev" +bind MWHEELDOWN "weapnext" +bind MOUSE1 "+attack" +bind MOUSE2 "+altattack" +bind PGUP "+lookup" bind F9 "load quik" bind F10 "uimenu ingameloadmenu" bind F11 "uimenu ingamesavemenu" bind F12 "save quik*" -bind KP_LEFTARROW "use_lightamp_goggles" -bind KP_5 "use_sentry" -bind KP_PGDN "use_seeker" -bind MOUSE1 "+attack" -bind MOUSE2 "+altattack" +bind END "centerview" +bind PGDN "+lookdown" bind MOUSE3 "zoom" -bind MWHEELDOWN "weapnext" -bind MWHEELUP "weapprev" -seta d_slowmodeath "3" -seta ui_iscensored "0" -seta g_saberAutoAim "1" -seta g_saberAnimSpeed "1" -seta g_saberMoveSpeed "1" -seta g_saberRealisticCombat "0" -seta g_saberAutoBlocking "1" -seta g_subtitles "2" -seta g_dismemberProbabilities "0" -seta g_dismemberment "4" -seta g_spskill "1" -seta cg_reliableAnimSounds "1" -seta cg_gunAutoFirst "1" -seta cg_saberAutoThird "1" -seta cg_bobroll "0.002" -seta cg_bobpitch "0.002" -seta cg_bobup "0.005" -seta cg_runroll "0.005" -seta cg_runpitch "0.002" -seta cg_simpleItems "0" -seta cg_crosshairY "0" -seta cg_crosshairX "0" -seta cg_crosshairSize "24" -seta cg_crosshairForceHint "1" -seta cg_crosshairIdentifyTarget "1" -seta cg_dynamicCrosshair "1" -seta cg_drawAmmoWarning "1" -seta cg_drawSnapshot "0" -seta cg_drawFPS "0" -seta cg_drawTimer "0" -seta cg_drawStatus "1" -seta cg_draw2D "1" -seta cg_stereoSeparation "0.4" -seta cg_drawGun "1" -seta cm_playerCurveClip "1" -seta cg_hudFiles "ui/jk2hud.txt" -seta ui_bigFont "0.4" -seta ui_smallFont "0.25" -seta ui_menuFiles "ui/menus.txt" -seta cg_marks "1" -seta cg_drawCrosshair "1" -seta s_soundpoolmegs "25" -seta s_UseOpenAL "0" -seta s_mp3overhead "31760" -seta s_language "english" -seta s_mixPreStep "0.05" -seta s_mixahead "0.2" -seta s_allowDynamicMusic "1" -seta s_khz "22" -seta s_separation "0.5" -seta s_musicvolume "0.25" -seta s_volumeVoice "1.0" -seta s_volume "0.5" -seta vid_ypos "0" -seta vid_xpos "0" -seta r_lastValidRenderer "GeForce2 MX/AGP/SSE2" -seta r_modelpoolmegs "20" -seta cg_shadows "1" -seta r_showtriscolor "0" -seta r_primitives "0" -seta r_facePlaneCull "1" -seta r_gamma "1" -seta r_swapInterval "0" -seta r_textureMode "GL_LINEAR_MIPMAP_LINEAR" -seta r_finish "0" -seta r_dlightBacks "1" -seta r_dynamiclight "1" -seta r_drawSun "0" -seta r_fastsky "0" -seta r_ignoreGLErrors "1" -seta r_lodscale "10" -seta r_flares "1" -seta r_lodbias "0" -seta r_lodCurveError "250" -seta r_intensity "1" -seta r_ignoreFastPath "1" -seta r_subdivisions "4" -seta r_vertexLight "0" -seta r_simpleMipMaps "1" -seta r_customaspect "1" -seta r_customheight "1024" -seta r_customwidth "1600" -seta r_mode "3" -seta r_ignorehwgamma "0" -seta r_depthbits "0" -seta r_stencilbits "8" -seta r_stereo "0" -seta r_colorbits "0" -seta r_texturebitslm "0" -seta r_texturebits "0" -seta r_detailtextures "1" -seta r_picmip "1" -seta r_ext_texture_filter_anisotropic "1" -seta r_ext_texture_env_add "1" -seta r_ext_compiled_vertex_array "1" -seta r_ext_multitexture "1" -seta r_ext_gamma_control "1" -seta r_ext_preferred_tc_method "0" -seta r_ext_compress_lightmaps "0" -seta r_ext_compress_textures "1" -seta r_allowExtensions "1" -seta handicap "100" -seta sex "male" -seta snaps "20" -seta name "Kyle" -seta m_filter "0" -seta m_side "0.25" -seta m_forward "0.25" -seta m_yaw "0.022" -seta m_pitch "0.022" -seta cg_autoswitch "1" -seta cl_VideoQuality "0" -seta cl_ingameVideo "1" -seta cl_freelook "1" -seta cl_mouseAccel "0" -seta sensitivity "5" -seta cl_run "1" -seta cl_packetdup "1" -seta cl_maxpackets "30" -seta cl_anglespeedkey "1.5" -seta cl_pitchspeed "140" -seta cl_yawspeed "140" -seta panoNumShots "10" -seta conAlpha "1.6" -seta ff_defaultTension "1" -seta use_ff "0" -seta k_language "american" -seta joy_ybutton "0" -seta joy_xbutton "1" -seta js_ffmult "3.0" -seta joy_threshold "0.15" -seta in_joyBallScale "0.02" -seta in_joystick "0" -seta in_mouse "-1" -seta in_mididevice "0" -seta in_midichannel "1" -seta in_midiport "1" -seta in_midi "0" -seta sp_language "0" -seta com_maxfps "85" +bind UPARROW "+forward" +bind DOWNARROW "+back" +bind LEFTARROW "+left" +bind RIGHTARROW "+right" +bind JOY0 "+attack" +bind JOY1 "+attack" +seta cg_missionInfoCentered "1" +seta ui_r_glCustom "4" seta r_overBrightBits "1" +seta com_maxfps "85" +seta sp_language "0" +seta in_midi "0" +seta in_midiport "1" +seta in_midichannel "1" +seta in_mididevice "0" +seta in_mouse "-1" +seta in_joystick "1" +seta in_joyBallScale "0.02" +seta joy_threshold "0.15" +seta js_ffmult "3.0" +seta joy_xbutton "1" +seta joy_ybutton "0" +seta k_language "american" +seta use_ff "1" +seta ff_defaultTension "1" +seta conAlpha "1.6" +seta panoNumShots "10" +seta cl_yawspeed "140" +seta cl_pitchspeed "140" +seta cl_anglespeedkey "1.5" +seta cl_maxpackets "30" +seta cl_packetdup "1" +seta cl_run "1" +seta sensitivity "5" +seta cl_mouseAccel "0" +seta cl_freelook "1" +seta cl_ingameVideo "1" +seta cl_VideoQuality "0" +seta cg_autoswitch "1" +seta m_pitch "0.022" +seta m_yaw "0.022" +seta m_forward "0.25" +seta m_side "0.25" +seta m_filter "0" +seta name "Kyle" +seta snaps "20" +seta sex "male" +seta handicap "100" +seta r_allowExtensions "1" +seta r_ext_compress_textures "1" +seta r_ext_compress_lightmaps "0" +seta r_ext_preferred_tc_method "0" +seta r_ext_gamma_control "1" +seta r_ext_multitexture "1" +seta r_ext_compiled_vertex_array "1" +seta r_ext_texture_env_add "1" +seta r_ext_texture_filter_anisotropic "1" +seta r_picmip "1" +seta r_detailtextures "1" +seta r_texturebits "0" +seta r_texturebitslm "0" +seta r_colorbits "0" +seta r_stereo "0" +seta r_stencilbits "8" +seta r_depthbits "0" +seta r_ignorehwgamma "0" +seta r_mode "3" +seta r_customwidth "1600" +seta r_customheight "768" +seta r_customaspect "2" +seta r_simpleMipMaps "1" +seta r_vertexLight "0" +seta r_subdivisions "4" +seta r_ignoreFastPath "1" +seta r_intensity "1" +seta r_lodCurveError "250" +seta r_lodbias "0" +seta r_flares "1" +seta r_lodscale "10" +seta r_ignoreGLErrors "1" +seta r_fastsky "0" +seta r_drawSun "0" +seta r_dynamiclight "1" +seta r_dlightBacks "1" +seta r_finish "0" +seta r_textureMode "GL_LINEAR_MIPMAP_LINEAR" +seta r_swapInterval "0" +seta r_gamma "1" +seta r_facePlaneCull "1" +seta r_primitives "0" +seta r_showtriscolor "0" +seta cg_shadows "1" +seta r_modelpoolmegs "20" +seta r_lastValidRenderer "GeForce2 MX/AGP/SSE2" +seta vid_xpos "7" +seta vid_ypos "1" +seta s_volume "0.546875" +seta s_volumeVoice "1.0" +seta s_musicvolume "0.460938" +seta s_separation "0.5" +seta s_khz "22" +seta s_allowDynamicMusic "1" +seta s_mixahead "0.2" +seta s_mixPreStep "0.05" +seta s_mp3overhead "31760" +seta s_UseOpenAL "1" +seta s_soundpoolmegs "25" +seta cg_drawCrosshair "1" +seta cg_marks "1" +seta ui_menuFiles "ui/menus.txt" +seta ui_smallFont "0.25" +seta ui_bigFont "0.4" +seta cg_hudFiles "ui/jk2hud.txt" +seta cm_playerCurveClip "1" +seta cg_drawGun "1" +seta cg_stereoSeparation "0.4" +seta cg_draw2D "1" +seta cg_drawStatus "1" +seta cg_drawTimer "0" +seta cg_drawFPS "0" +seta cg_drawSnapshot "0" +seta cg_drawAmmoWarning "1" +seta cg_dynamicCrosshair "1" +seta cg_crosshairIdentifyTarget "1" +seta cg_crosshairForceHint "1" +seta cg_crosshairSize "24" +seta cg_crosshairX "0" +seta cg_crosshairY "0" +seta cg_simpleItems "0" +seta cg_runpitch "0.002" +seta cg_runroll "0.005" +seta cg_bobup "0.005" +seta cg_bobpitch "0.002" +seta cg_bobroll "0.002" +seta cg_saberAutoThird "1" +seta cg_gunAutoFirst "1" +seta cg_reliableAnimSounds "1" +seta g_spskill "1" +seta g_dismemberment "3" +seta g_dismemberProbabilities "0" +seta g_subtitles "2" +seta g_saberAutoBlocking "1" +seta g_saberRealisticCombat "0" +seta g_saberMoveSpeed "1" +seta g_saberAnimSpeed "1" +seta g_saberAutoAim "1" +seta ui_iscensored "0" +seta d_slowmodeath "3" +seta s_language "espanoles" +seta r_weatherScale "1" +seta ff_channels "0,0;1,0;2,0;3,0;4,0;5,0" +seta ff_delay "40" seta r_fullscreen "0" diff --git a/code/cgame/FxScheduler.cpp b/code/cgame/FxScheduler.cpp index 4869a5e..30ef1e2 100644 --- a/code/cgame/FxScheduler.cpp +++ b/code/cgame/FxScheduler.cpp @@ -299,6 +299,12 @@ int CFxScheduler::ParseEffect( const char *file, CGPGroup *base ) { type = Sound; } +#ifdef _IMMERSION + else if ( !stricmp( grpName, "forcefeedback" )) + { + type = Force; + } +#endif // _IMMERSION else if ( !stricmp( grpName, "cylinder" )) { type = Cylinder; @@ -579,6 +585,60 @@ void CFxScheduler::PlayEffect( int id, vec3_t origin, vec3_t forward ) PlayEffect( id, origin, axis ); } +#ifdef _IMMERSION +//------------------------------------------------------ +// PlayEffect +// Handles scheduling an effect so all the components +// happen at the specified time. Takes a fwd vector +// and builds a right and up vector +// +// Input: +// Effect file id, the origin, a fwd vector, and clientNum +// +// Return: +// none +//------------------------------------------------------ +void CFxScheduler::PlayEffect( int id, int clientNum, vec3_t origin, vec3_t forward ) +{ + vec3_t axis[3]; + + // Take the forward vector and create two arbitrary but perpendicular vectors + VectorCopy( forward, axis[0] ); + MakeNormalVectors( forward, axis[1], axis[2] ); + + PlayEffect( id, origin, axis, -1, clientNum ); +} + +//------------------------------------------------------ +// PlayEffect +// Handles scheduling an effect so all the components +// happen at the specified time. Takes a forward vector +// and uses this to complete the axis field. +// +// Input: +// Effect file name, the origin, and a forward vector +// +// Return: +// none +//------------------------------------------------------ +void CFxScheduler::PlayEffect( const char *file, int clientNum, vec3_t origin, vec3_t forward ) +{ + char sfile[MAX_QPATH]; + + // Get an extenstion stripped version of the file + COM_StripExtension( file, sfile ); + + PlayEffect( mEffectIDs[sfile], clientNum, origin, forward ); + +#ifndef FINAL_BUILD + if ( mEffectIDs[sfile] == 0 ) + { + theFxHelper.Print( "CFxScheduler::PlayEffect unregistered/non-existent effect: %s\n", file ); + } +#endif +} + +#endif // _IMMERSION //------------------------------------------------------ // PlayEffect // Handles scheduling an effect so all the components @@ -602,7 +662,11 @@ void CFxScheduler::PlayEffect( const char *file, vec3_t origin, vec3_t axis[3], // This is a horribly dumb thing to have to do, but QuakeIII might not have calc'd the lerpOrigin // for the entity we may be trying to bolt onto. We like having the correct origin, so we are // forced to call this function.... +#ifdef _IMMERSION + if ( entNum > -1 ) +#else if ( entNum != -1 ) +#endif // _IMMERSION { CG_CalcEntityLerpPositions( &cg_entities[entNum] ); } @@ -826,6 +890,15 @@ void CFxScheduler::CreateEffect( CPrimitiveTemplate *fx, int clientID, int delay theFxHelper.PlaySound( NULL, clientID, CHAN_WEAPON, fx->mMediaHandles.GetHandle() ); break; +#ifdef _IMMERSION + //--------- + case Force: + //--------- + + // Analogous to Sound (same assumption defined in RegisterForce) + theFxHelper.PlayForce( clientID, fx->mMediaHandles.GetHandle() ); + break; +#endif // _IMMERSION //--------- case Light: //--------- @@ -916,6 +989,13 @@ void CFxScheduler::PlayEffect( int id, vec3_t origin, vec3_t axis[3], const int int modelNum = 0, boltNum = 0; int entityNum = entNum; +#ifdef _IMMERSION + entityNum = + ( entNum < -1 // HACKHACKHACK (negative if effect plays uncentered on an entity) + ? FF_CLIENT( entNum ) // decode -2 as entNum=0, -3 as entNum=1, ... + : entNum // default + ); +#endif // _IMMERSION if ( boltInfo > 0 ) { // extract the wraith ID from the bolt info @@ -973,6 +1053,15 @@ void CFxScheduler::PlayEffect( int id, vec3_t origin, vec3_t axis[3], const int // if the delay is so small, we may as well just create this bit right now if ( delay < 1 && !forceScheduling ) { +#ifdef _IMMERSION + CreateEffect + ( prim + , (boltInfo == -1 && entNum > -1 ? cg_entities[entNum].lerpOrigin : origin) + , axis + , -delay + , entityNum + ); +#else if ( boltInfo == -1 && entNum != -1 ) { // Find out where the entity currently is @@ -982,6 +1071,7 @@ void CFxScheduler::PlayEffect( int id, vec3_t origin, vec3_t axis[3], const int { CreateEffect( prim, origin, axis, -delay ); } +#endif // _IMMERSION } else { @@ -994,11 +1084,19 @@ void CFxScheduler::PlayEffect( int id, vec3_t origin, vec3_t axis[3], const int if ( boltInfo == -1 ) { +#ifdef _IMMERSION + if ( entNum <= -1 ) +#else if ( entNum == -1 ) +#endif // _IMMERSION { // we aren't bolting, so make sure the spawn system knows this by putting -1's in these fields sfx->mBoltNum = -1; +#ifdef _IMMERSION + sfx->mEntNum = entNum; // always negative +#else sfx->mEntNum = -1; +#endif // _IMMERSION sfx->mModelNum = 0; if ( origin ) @@ -1140,6 +1238,22 @@ void CFxScheduler::AddScheduledEffects( void ) } else if ((*itr)->mBoltNum == -1) {// ok, are we spawning a bolt on effect or a normal one? +#ifdef _IMMERSION + int entNum = (*itr)->mEntNum; + int hitEntNum = + ( entNum < -1 + ? FF_CLIENT( entNum ) + : entNum + ); + + CreateEffect + ( (*itr)->mpTemplate + , (entNum >= 0 ? cg_entities[entNum].lerpOrigin : (*itr)->mOrigin) + , (*itr)->mAxis + , theFxHelper.mTime - (*itr)->mStartTime + , hitEntNum + ); +#else if ( (*itr)->mEntNum != -1 ) { // Find out where the entity currently is @@ -1153,6 +1267,7 @@ void CFxScheduler::AddScheduledEffects( void ) (*itr)->mOrigin, (*itr)->mAxis, theFxHelper.mTime - (*itr)->mStartTime ); } +#endif // _IMMERSION } else { @@ -1200,9 +1315,19 @@ void CFxScheduler::AddScheduledEffects( void ) // only do this if we found the bolt if (doesBoltExist) { +#ifdef _IMMERSION + CreateEffect + ( (*itr)->mpTemplate + , origin + , axis + , theFxHelper.mTime - (*itr)->mStartTime + , oldEntNum < -1 ? FF_CLIENT( oldEntNum ) : -1 + ); +#else CreateEffect( (*itr)->mpTemplate, origin, axis, theFxHelper.mTime - (*itr)->mStartTime ); +#endif // _IMMERSION } } @@ -1231,7 +1356,11 @@ void CFxScheduler::AddScheduledEffects( void ) // Return: // none //------------------------------------------------------ +#ifdef _IMMERSION +void CFxScheduler::CreateEffect( CPrimitiveTemplate *fx, vec3_t origin, vec3_t axis[3], int lateTime, int hitEntNum ) +#else void CFxScheduler::CreateEffect( CPrimitiveTemplate *fx, vec3_t origin, vec3_t axis[3], int lateTime ) +#endif // _IMMERSION { vec3_t org, org2, temp, vel, accel, @@ -1433,7 +1562,11 @@ void CFxScheduler::CreateEffect( CPrimitiveTemplate *fx, vec3_t origin, vec3_t a // handle RGB color, but only for types that will use it //--------------------------------------------------------------------------- +#ifdef _IMMERSION + if ( fx->mType != Sound && fx->mType != FxRunner && fx->mType != CameraShake && fx->mType != Force ) +#else if ( fx->mType != Sound && fx->mType != FxRunner && fx->mType != CameraShake ) +#endif // _IMMERSION { if ( fx->mSpawnFlags & FX_RGB_COMPONENT_INTERP ) { @@ -1588,6 +1721,16 @@ void CFxScheduler::CreateEffect( CPrimitiveTemplate *fx, vec3_t origin, vec3_t a } break; +#ifdef _IMMERSION + //--------- + case Force: + //--------- + + if ( hitEntNum > -1 ) // Fix me: Allow or abolish FF_LOCAL_CLIENT? + theFxHelper.PlayForce( hitEntNum, fx->mMediaHandles.GetHandle() ); + break; + +#endif // _IMMERSION //--------- case FxRunner: //--------- diff --git a/code/cgame/FxScheduler.h b/code/cgame/FxScheduler.h index ed20238..cb5e47a 100644 --- a/code/cgame/FxScheduler.h +++ b/code/cgame/FxScheduler.h @@ -133,6 +133,9 @@ enum EPrimType Cylinder, Emitter, // emits effects as it moves, can also attach a chunk Sound, +#ifdef _IMMERSION + Force, +#endif // _IMMERSION Decal, // projected onto architecture OrientedParticle, Electricity, @@ -296,6 +299,9 @@ public: bool ParseModels( CGPValue *grp ); bool ParseShaders( CGPValue *grp ); bool ParseSounds( CGPValue *grp ); +#ifdef _IMMERSION + bool ParseForces( CGPValue *grp ); +#endif // _IMMERSION bool ParseImpactFxStrings( CGPValue *grp ); bool ParseDeathFxStrings( CGPValue *grp ); @@ -410,7 +416,11 @@ private: void AddPrimitiveToEffect( SEffectTemplate *fx, CPrimitiveTemplate *prim ); int ParseEffect( const char *file, CGPGroup *base ); +#ifdef _IMMERSION + void CreateEffect( CPrimitiveTemplate *fx, vec3_t origin, vec3_t axis[3], int lateTime, int hitEntNum = -1 ); +#else void CreateEffect( CPrimitiveTemplate *fx, vec3_t origin, vec3_t axis[3], int lateTime ); +#endif // _IMMERSION void CreateEffect( CPrimitiveTemplate *fx, int clientID, int lateTime ); public: @@ -431,6 +441,10 @@ public: void PlayEffect( const char *file, int clientID ); +#ifdef _IMMERSION // for ff-system + void PlayEffect( int id, int clientNum, vec3_t org, vec3_t fwd ); + void PlayEffect( const char *file, int clientNum, vec3_t origin, vec3_t forward ); +#endif // _IMMERSION void AddScheduledEffects( void ); // call once per CGame frame int NumScheduledFx() { return mFxSchedule.size(); } diff --git a/code/cgame/FxSystem.cpp b/code/cgame/FxSystem.cpp index b6ee4d4..64fe222 100644 --- a/code/cgame/FxSystem.cpp +++ b/code/cgame/FxSystem.cpp @@ -136,3 +136,16 @@ void SFxHelper::CameraShake( vec3_t origin, float intensity, int radius, int tim { CG_ExplosionEffects( origin, intensity, radius, time ); } +#ifdef _IMMERSION +//------------------------------------------------------ +ffHandle_t SFxHelper::RegisterForce( const char *force, int channel ) +{ + return cgi_FF_Register( force, channel ); +} + +//------------------------------------------------------ +void SFxHelper::PlayForce( int entityNum, ffHandle_t ff ) +{ + cgi_FF_Start( ff, entityNum ); +} +#endif // _IMMERSION \ No newline at end of file diff --git a/code/cgame/FxSystem.h b/code/cgame/FxSystem.h index 2b7eab8..f987185 100644 --- a/code/cgame/FxSystem.h +++ b/code/cgame/FxSystem.h @@ -58,6 +58,10 @@ struct SFxHelper void PlaySound( vec3_t origin, int entityNum, int entchannel, sfxHandle_t sfx ); int RegisterSound( const char *sound ); +#ifdef _IMMERSION + void PlayForce( int entityNum, ffHandle_t ff ); + ffHandle_t RegisterForce( const char *force, int channel ); +#endif // _IMMERSION // Physics/collision void Trace( trace_t *tr, vec3_t start, vec3_t min, vec3_t max, vec3_t end, int skipEntNum, int flags ); diff --git a/code/cgame/FxTemplate.cpp b/code/cgame/FxTemplate.cpp index d2201e2..043622f 100644 --- a/code/cgame/FxTemplate.cpp +++ b/code/cgame/FxTemplate.cpp @@ -1500,6 +1500,61 @@ bool CPrimitiveTemplate::ParseSounds( CGPValue *grp ) return true; } +#ifdef _IMMERSION +//------------------------------------------------------ +// ParseForces +// Reads in a group of forces and registers them +// +// input: +// Parse group that contains the list of forces to parse +// +// return: +// success of parse operation. +//------------------------------------------------------ +bool CPrimitiveTemplate::ParseForces( CGPValue *grp ) +{ + const char *val; + int handle; + + if ( grp->IsList() ) + { + // If we are a list we have to do separate processing + CGPObject *list = grp->GetList(); + + while ( list ) + { + // name is actually the value contained in the list + val = list->GetName(); + + // Assumes FF_CHANNEL_WEAPON because sound mechanism assumes this + handle = theFxHelper.RegisterForce( val, FF_CHANNEL_WEAPON ); + mMediaHandles.AddHandle( handle ); + + list = (CGPValue *)list->GetNext(); + } + } + else + { + // Let's get a value + val = grp->GetTopValue(); + + if ( val ) + { + // Assumes FF_CHANNEL_WEAPON because sound mechanism assumes this + handle = theFxHelper.RegisterForce( val, FF_CHANNEL_WEAPON ); + mMediaHandles.AddHandle( handle ); + } + else + { + // empty "list" + theFxHelper.Print( "CPrimitiveTemplate::ParseForces called with an empty list!\n" ); + return false; + } + } + + return true; +} +#endif // _IMMERSION //------------------------------------------------------ // ParseModels // Reads in a group of models and registers them @@ -2143,6 +2198,12 @@ bool CPrimitiveTemplate::ParsePrimitive( CGPGroup *grp ) { ParseSounds( pairs ); } +#ifdef _IMMERSION + else if ( !stricmp( key, "forces" ) || !stricmp( key, "force" )) + { + ParseForces( pairs ); + } +#endif // _IMMERSION else if ( !stricmp( key, "impactfx" )) { ParseImpactFxStrings( pairs ); diff --git a/code/cgame/cg_camera.cpp b/code/cgame/cg_camera.cpp index ef8471e..7c3807f 100644 --- a/code/cgame/cg_camera.cpp +++ b/code/cgame/cg_camera.cpp @@ -720,7 +720,9 @@ void CGCam_FollowUpdate ( void ) if ( !num_subjects ) // Bad cameragroup { +#ifndef FINAL_BUILD gi.Printf(S_COLOR_RED"ERROR: Camera Focus unable to locate cameragroup: %s\n", client_camera.cameraGroup); +#endif return; } @@ -1211,6 +1213,10 @@ void CGCam_Shake( float intensity, int duration ) client_camera.shake_intensity = intensity; client_camera.shake_duration = duration; client_camera.shake_start = cg.time; +#ifdef _IMMERSION + // FIX ME: This is far too weak... but I don't want it to interfere with other effects. + cgi_FF_Shake( int(intensity * 625), duration ); // 625 = (10000 / MAX_SHAKE_INTENSITY) +#endif // _IMMERSION } /* diff --git a/code/cgame/cg_consolecmds.cpp b/code/cgame/cg_consolecmds.cpp index 0deb8a6..18bd6c1 100644 --- a/code/cgame/cg_consolecmds.cpp +++ b/code/cgame/cg_consolecmds.cpp @@ -59,14 +59,14 @@ extern float cg_zoomFov; //from cg_view.cpp void CG_ToggleBinoculars( void ) { - if ( in_camera) + if ( in_camera || !cg.snap ) { return; } if ( cg.zoomMode == 0 || cg.zoomMode >= 2 ) // not zoomed or currently zoomed with the disruptor or LA goggles { - if ( cg.snap->ps.saberActive && cg.snap->ps.saberInFlight && cg.snap->ps.stats[STAT_HEALTH] > 0 ) + if ( (cg.snap->ps.saberActive && cg.snap->ps.saberInFlight) || cg.snap->ps.stats[STAT_HEALTH] <= 0) {//can't select binoculars when throwing saber //FIXME: indicate this to the player return; @@ -96,25 +96,31 @@ void CG_ToggleBinoculars( void ) } cgi_S_StartSound( NULL, cg.snap->ps.clientNum, CHAN_AUTO, cgs.media.zoomStart ); +#ifdef _IMMERSION + cgi_FF_Start( cgs.media.zoomStartForce, cg.snap->ps.clientNum ); +#endif // _IMMERSION } else { cg.zoomMode = 0; cg.zoomTime = cg.time; cgi_S_StartSound( NULL, cg.snap->ps.clientNum, CHAN_AUTO, cgs.media.zoomEnd ); +#ifdef _IMMERSION + cgi_FF_Start( cgs.media.zoomEndForce, cg.snap->ps.clientNum ); +#endif // _IMMERSION } } void CG_ToggleLAGoggles( void ) { - if ( in_camera) + if ( in_camera || !cg.snap) { return; } if ( cg.zoomMode == 0 || cg.zoomMode < 3 ) // not zoomed or currently zoomed with the disruptor or regular binoculars { - if ( cg.snap->ps.saberActive && cg.snap->ps.saberInFlight && cg.snap->ps.stats[STAT_HEALTH] > 0 ) + if ( (cg.snap->ps.saberActive && cg.snap->ps.saberInFlight) || cg.snap->ps.stats[STAT_HEALTH] <= 0 ) {//can't select binoculars when throwing saber //FIXME: indicate this to the player return; @@ -138,12 +144,18 @@ void CG_ToggleLAGoggles( void ) } cgi_S_StartSound( NULL, cg.snap->ps.clientNum, CHAN_AUTO, cgs.media.zoomStart ); +#ifdef _IMMERSION + cgi_FF_Start( cgs.media.zoomStartForce, cg.snap->ps.clientNum ); +#endif // _IMMERSION } else { cg.zoomMode = 0; cg.zoomTime = cg.time; cgi_S_StartSound( NULL, cg.snap->ps.clientNum, CHAN_AUTO, cgs.media.zoomEnd ); +#ifdef _IMMERSION + cgi_FF_Start( cgs.media.zoomEndForce, cg.snap->ps.clientNum ); +#endif // _IMMERSION } } diff --git a/code/cgame/cg_draw.cpp b/code/cgame/cg_draw.cpp index 9d37f4a..f98acb2 100644 --- a/code/cgame/cg_draw.cpp +++ b/code/cgame/cg_draw.cpp @@ -2282,7 +2282,10 @@ static void CG_Draw2D( void ) CG_DrawGameText(); if ( in_camera ) + {//still draw the saber clash flare, but nothing else + CG_SaberClashFlare(); return; + } if ( CG_RenderingFromMiscCamera()) { @@ -2384,24 +2387,37 @@ static void CG_Draw2D( void ) cgi_SP_GetStringTextString( "INGAME_DATAPAD_UPDATED", text, sizeof(text) ); + int x_pos = 0; y_pos = (SCREEN_HEIGHT/2)+80; - w = cgi_R_Font_StrLenPixels(text,cgs.media.qhFontSmall, 1.0f); - cgi_R_Font_DrawString((SCREEN_WIDTH/2)-(w/2), y_pos, text, colorTable[CT_LTRED1], cgs.media.qhFontMedium, -1, 1.0f); + if ( cg_missionInfoCentered.integer ) + { + w = cgi_R_Font_StrLenPixels(text,cgs.media.qhFontSmall, 1.0f); + x_pos = (SCREEN_WIDTH/2)-(w/2); + } + cgi_R_Font_DrawString(x_pos, y_pos, text, colorTable[CT_LTRED1], cgs.media.qhFontMedium, -1, 1.0f); if (cg_updatedDataPadForcePower1.integer) { y_pos += 25; cgi_SP_GetStringTextString("INGAME_NEW_FORCE_POWER_INFO", text, sizeof(text) ); - w = cgi_R_Font_StrLenPixels(text,cgs.media.qhFontSmall, 1.0f); - cgi_R_Font_DrawString((SCREEN_WIDTH/2)-(w/2), y_pos, text, colorTable[CT_LTRED1], cgs.media.qhFontMedium, -1, 1.0f); + if ( cg_missionInfoCentered.integer ) + { + w = cgi_R_Font_StrLenPixels(text,cgs.media.qhFontSmall, 1.0f); + x_pos = (SCREEN_WIDTH/2)-(w/2); + } + cgi_R_Font_DrawString(x_pos, y_pos, text, colorTable[CT_LTRED1], cgs.media.qhFontMedium, -1, 1.0f); } if (cg_updatedDataPadObjective.integer) { y_pos += 25; cgi_SP_GetStringTextString( "INGAME_NEW_OBJECTIVE_INFO", text, sizeof(text) ); - w = cgi_R_Font_StrLenPixels(text,cgs.media.qhFontSmall, 1.0f); - cgi_R_Font_DrawString((SCREEN_WIDTH/2)-(w/2), y_pos, text, colorTable[CT_LTRED1], cgs.media.qhFontMedium, -1, 1.0f); + if ( cg_missionInfoCentered.integer ) + { + w = cgi_R_Font_StrLenPixels(text,cgs.media.qhFontSmall, 1.0f); + x_pos = (SCREEN_WIDTH/2)-(w/2); + } + cgi_R_Font_DrawString(x_pos, y_pos, text, colorTable[CT_LTRED1], cgs.media.qhFontMedium, -1, 1.0f); } // if (cent->gent->client->sess.missionObjectivesShown<3) diff --git a/code/cgame/cg_ents.cpp b/code/cgame/cg_ents.cpp index 5617a1c..937ffe9 100644 --- a/code/cgame/cg_ents.cpp +++ b/code/cgame/cg_ents.cpp @@ -1931,7 +1931,7 @@ extern cvar_t *g_saberRealisticCombat; } } if ( owner->client->NPC_class == CLASS_PROTOCOL - || g_dismemberment->integer > 3 + || g_dismemberment->integer >= 11381138 || g_saberRealisticCombat->integer ) { //wait 100ms before allowing owner to be dismembered again diff --git a/code/cgame/cg_event.cpp b/code/cgame/cg_event.cpp index c30eb5e..6479a6e 100644 --- a/code/cgame/cg_event.cpp +++ b/code/cgame/cg_event.cpp @@ -9,6 +9,9 @@ #include "..\game\anims.h" +#ifdef _IMMERSION +#include "../ff/ff.h" +#endif // _IMMERSION extern void CG_TryPlayCustomSound( vec3_t origin, int entityNum, soundChannel_t channel, const char *soundName, int customSoundSet ); //========================================================================== @@ -227,6 +230,26 @@ static void CG_UseItem( centity_t *cent ) } +#ifdef _IMMERSION +qboolean CG_ConfigForce( int index, const char *&name, int &channel ) +{ + qboolean result = qfalse; + const char *configstring = CG_ConfigString( CS_FORCES + index ); + + result = qboolean + ( configstring + && sscanf( configstring, "%d", &channel ) == 1 + ); + + if ( result ) + { + name = strchr( configstring, ',' ) + 1; + result = qboolean( name != (char *)1 ); + } + + return result; +} +#endif // _IMMERSION /* ============== CG_EntityEvent @@ -272,8 +295,14 @@ void CG_EntityEvent( centity_t *cent, vec3_t position ) { if (cg_footsteps.integer) { if ( cent->gent && cent->gent->s.number == 0 && !cg.renderingThirdPerson )//!cg_thirdPerson.integer ) {//Everyone else has keyframed footsteps in animsounds.cfg +#ifdef _IMMERSION + int index = rand()&3; + cgi_S_StartSound (NULL, es->number, CHAN_BODY, cgs.media.footsteps[ FOOTSTEP_NORMAL ][index] ); + cgi_FF_Start( cgs.media.footstepForces[ FOOTSTEP_NORMAL ][ index ], es->number ); +#else cgi_S_StartSound (NULL, es->number, CHAN_BODY, cgs.media.footsteps[ FOOTSTEP_NORMAL ][rand()&3] ); +#endif // _IMMERSION } } break; @@ -283,29 +312,53 @@ void CG_EntityEvent( centity_t *cent, vec3_t position ) { { if ( cent->gent && cent->gent->s.number == 0 && !cg.renderingThirdPerson )//!cg_thirdPerson.integer ) {//Everyone else has keyframed footsteps in animsounds.cfg +#ifdef _IMMERSION + int index = rand()&3; + cgi_S_StartSound (NULL, es->number, CHAN_BODY, cgs.media.footsteps[ FOOTSTEP_METAL ][index] ); + cgi_FF_Start( cgs.media.footstepForces[ FOOTSTEP_METAL ][ index ], es->number ); +#else cgi_S_StartSound (NULL, es->number, CHAN_BODY, cgs.media.footsteps[ FOOTSTEP_METAL ][rand()&3] ); +#endif // _IMMERSION } } break; case EV_FOOTSPLASH: DEBUGNAME("EV_FOOTSPLASH"); if (cg_footsteps.integer) { +#ifdef _IMMERSION + int index = rand()&3; + cgi_S_StartSound (NULL, es->number, CHAN_BODY, cgs.media.footsteps[ FOOTSTEP_SPLASH ][index] ); + cgi_FF_Start( cgs.media.footstepForces[ FOOTSTEP_SPLASH ][ index ], es->number ); +#else cgi_S_StartSound (NULL, es->number, CHAN_BODY, cgs.media.footsteps[ FOOTSTEP_SPLASH ][rand()&3] ); +#endif // _IMMERSION } break; case EV_FOOTWADE: DEBUGNAME("EV_FOOTWADE"); if (cg_footsteps.integer) { +#ifdef _IMMERSION + int index = rand()&3; + cgi_S_StartSound (NULL, es->number, CHAN_BODY, cgs.media.footsteps[ FOOTSTEP_WADE ][index] ); + cgi_FF_Start( cgs.media.footstepForces[ FOOTSTEP_WADE ][ index ], es->number ); +#else cgi_S_StartSound (NULL, es->number, CHAN_BODY, cgs.media.footsteps[ FOOTSTEP_WADE ][rand()&3] ); +#endif // _IMMERSION } break; case EV_SWIM: DEBUGNAME("EV_SWIM"); if (cg_footsteps.integer) { +#ifdef _IMMERSION + int index = rand()&3; + cgi_S_StartSound (NULL, es->number, CHAN_BODY, cgs.media.footsteps[ FOOTSTEP_SWIM ][index] ); + cgi_FF_Start( cgs.media.footstepForces[ FOOTSTEP_SWIM ][ index ], es->number ); +#else cgi_S_StartSound (NULL, es->number, CHAN_BODY, cgs.media.footsteps[ FOOTSTEP_SWIM ][rand()&3] ); +#endif // _IMMERSION } break; @@ -313,6 +366,9 @@ void CG_EntityEvent( centity_t *cent, vec3_t position ) { case EV_FALL_SHORT: DEBUGNAME("EV_FALL_SHORT"); cgi_S_StartSound( NULL, es->number, CHAN_AUTO, cgs.media.landSound ); +#ifdef _IMMERSION + cgi_FF_Start( cgs.media.landForce, es->number ); +#endif // _IMMERSION if ( clientNum == cg.predicted_player_state.clientNum ) { // smooth landing z changes cg.landChange = -8; @@ -326,6 +382,9 @@ void CG_EntityEvent( centity_t *cent, vec3_t position ) { if ( g_entities[es->number].health <= 0 ) {//dead cgi_S_StartSound( NULL, es->number, CHAN_AUTO, cgs.media.landSound ); +#ifdef _IMMERSION + cgi_FF_Start( cgs.media.landForce, es->number ); +#endif // _IMMERSION } else if ( g_entities[es->number].s.weapon == WP_SABER ) {//jedi @@ -406,16 +465,25 @@ void CG_EntityEvent( centity_t *cent, vec3_t position ) { case EV_WATER_TOUCH: DEBUGNAME("EV_WATER_TOUCH"); cgi_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.watrInSound ); +#ifdef _IMMERSION + cgi_FF_Start( cgs.media.watrInSound, es->number ); +#endif // _IMMERSION break; case EV_WATER_LEAVE: DEBUGNAME("EV_WATER_LEAVE"); cgi_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.watrOutSound ); +#ifdef _IMMERSION + cgi_FF_Start( cgs.media.watrOutSound, es->number ); +#endif // _IMMERSION break; case EV_WATER_UNDER: DEBUGNAME("EV_WATER_UNDER"); cgi_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.watrUnSound ); +#ifdef _IMMERSION + cgi_FF_Start( cgs.media.watrUnSound, es->number ); +#endif // _IMMERSION break; case EV_WATER_CLEAR: @@ -454,6 +522,9 @@ void CG_EntityEvent( centity_t *cent, vec3_t position ) { } item = &bg_itemlist[ index ]; cgi_S_StartSound (NULL, es->number, CHAN_AUTO, cgi_S_RegisterSound( item->pickup_sound ) ); +#ifdef _IMMERSION + cgi_FF_Start( cgi_FF_Register( item->pickup_force, FF_CHANNEL_TOUCH ), es->number ); +#endif // _IMMERSION // show icon and name on status bar if ( es->number == cg.snap->ps.clientNum ) { @@ -496,11 +567,17 @@ void CG_EntityEvent( centity_t *cent, vec3_t position ) { { // custom select sound cgi_S_StartSound (NULL, es->number, CHAN_AUTO, cgi_S_RegisterSound( weaponData[cg.weaponSelect].selectSnd )); +#ifdef _IMMERSION + cgi_FF_Start( cgi_FF_Register( weaponData[cg.weaponSelect].selectFrc, FF_CHANNEL_WEAPON ), es->number ); +#endif // _IMMERSION } else { // generic sound cgi_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.selectSound ); +#ifdef _IMMERSION + cgi_FF_Start( cgs.media.selectForce, es->number ); +#endif // _IMMERSION } break; @@ -705,6 +782,49 @@ void CG_EntityEvent( centity_t *cent, vec3_t position ) { } break; +#ifdef _IMMERSION + case EV_ENTITY_FORCE: // Plays force on entity + DEBUGNAME("EV_ENTITY_FORCE"); + if ( !cgs.force_precache[ es->eventParm ] ) + { + const char *name; + int channel; + if ( CG_ConfigForce( es->eventParm, name, channel ) ) + { + cgs.force_precache[ es->eventParm ] = cgi_FF_Register( name, channel ); + } + } + cgi_FF_Start( cgs.force_precache[ es->eventParm ], es->number ); + break; + + case EV_GLOBAL_FORCE: + case EV_AREA_FORCE: + DEBUGNAME("EV_AREA_FORCE"); // Plays force for anyone + if ( !cgs.force_precache[ es->eventParm ] ) + { + const char *name; + int channel; + if ( CG_ConfigForce( es->eventParm, name, channel ) ) + { + cgs.force_precache[ es->eventParm ] = cgi_FF_Register( name, channel ); + } + } + cgi_FF_Start( cgs.force_precache[ es->eventParm ], es->number ); + break; + + case EV_FORCE_STOP: + DEBUGNAME("EV_FORCE_STOP"); + if ( es->eventParm < 0 ) + { + cgi_FF_StopAll( ); + } + else if ( es->eventParm < MAX_FORCES && cgs.force_precache[ es->eventParm ] ) + { + cgi_FF_Stop( cgs.force_precache[ es->eventParm ], es->number ); + } + + break; +#endif // _IMMERSION case EV_DRUGGED: DEBUGNAME("EV_DRUGGED"); if ( cent->gent && cent->gent->owner && cent->gent->owner->s.number == 0 ) @@ -776,6 +896,13 @@ void CG_EntityEvent( centity_t *cent, vec3_t position ) { CrossProduct( axis[0], axis[1], axis[2] ); // the entNum the effect may be attached to +#ifdef _IMMERSION + if ( es->saberActive ) + { + theFxScheduler.PlayEffect( s, cent->lerpOrigin, axis, -1, FF_CLIENT( es->otherEntityNum ) ); + } + else +#endif // _IMMERSION if ( es->otherEntityNum ) { theFxScheduler.PlayEffect( s, cent->lerpOrigin, axis, -1, es->otherEntityNum ); diff --git a/code/cgame/cg_info.cpp b/code/cgame/cg_info.cpp index 434653d..714bec8 100644 --- a/code/cgame/cg_info.cpp +++ b/code/cgame/cg_info.cpp @@ -40,6 +40,8 @@ static void MissionPrint_Line(const int color, const int objectIndex, int &missi char finalText[2048]; qhandle_t graphic; + int iYPixelsPerLine = cgi_R_Font_HeightPixels(cgs.media.qhFontMedium, 1.0f) * (cgi_Language_IsAsian() ? 1.2f : 1.0f ); + cgi_SP_GetStringText( PACKAGE_OBJECTIVES<<8|objectIndex , finalText, sizeof(finalText) ); pixelLen = cgi_R_Font_StrLenPixels(finalText, cgs.media.qhFontMedium, 1.0f); @@ -54,7 +56,7 @@ static void MissionPrint_Line(const int color, const int objectIndex, int &missi */ if (pixelLen < 500) // One shot - small enough to print entirely on one line { - y =missionYpos + (18 * (missionYcnt)); + y =missionYpos + (iYPixelsPerLine * (missionYcnt)); if (obj_graphics[0]) { y += 32 + 4; @@ -67,7 +69,8 @@ static void MissionPrint_Line(const int color, const int objectIndex, int &missi { y += 32 + 4; } - CG_DrawProportionalString(108, y,str, CG_SMALLFONT, colorTable[color] ); + //CG_DrawProportionalString(108, y,str, CG_SMALLFONT, colorTable[color] ); + cgi_R_Font_DrawString (108, y, str, colorTable[color], cgs.media.qhFontMedium, -1, 1.0f); ++missionYcnt; } // Text is too long, break into lines. @@ -107,7 +110,7 @@ static void MissionPrint_Line(const int color, const int objectIndex, int &missi pixelLen = 0; charLen = 1; - y = missionYpos + (18 * missionYcnt); + y = missionYpos + (iYPixelsPerLine * missionYcnt); CG_DrawProportionalString(108, y, holdText, CG_SMALLFONT, colorTable[color] ); ++missionYcnt; @@ -116,7 +119,7 @@ static void MissionPrint_Line(const int color, const int objectIndex, int &missi { ++charLen; - y = missionYpos + (18 * missionYcnt); + y = missionYpos + (iYPixelsPerLine * missionYcnt); Q_strncpyz( holdText, strBegin, charLen); CG_DrawProportionalString(108, y, holdText, CG_SMALLFONT, colorTable[color] ); @@ -132,21 +135,21 @@ static void MissionPrint_Line(const int color, const int objectIndex, int &missi // Special case hack if (objectIndex == DOOM_COMM_OBJ4) { - y = missionYpos + (18 * missionYcnt); + y = missionYpos + (iYPixelsPerLine * missionYcnt); graphic = cgi_R_RegisterShaderNoMip("textures/system/securitycode"); CG_DrawPic( 320 - (128/2), y+8, 128, 32, graphic ); obj_graphics[0] = qtrue; } else if (objectIndex == KEJIM_POST_OBJ3) { - y = missionYpos + (18 * missionYcnt); + y = missionYpos + (iYPixelsPerLine * missionYcnt); graphic = cgi_R_RegisterShaderNoMip("textures/system/securitycode_red"); CG_DrawPic( 320 - (32/2), y+8, 32, 32, graphic ); obj_graphics[1] = qtrue; } else if (objectIndex == KEJIM_POST_OBJ4) { - y =missionYpos + (18 * missionYcnt); + y =missionYpos + (iYPixelsPerLine * missionYcnt); if (obj_graphics[1]) { y += 32 + 4; @@ -157,7 +160,7 @@ static void MissionPrint_Line(const int color, const int objectIndex, int &missi } else if (objectIndex == KEJIM_POST_OBJ5) { - y =missionYpos + (18 * missionYcnt); + y =missionYpos + (iYPixelsPerLine * missionYcnt); if (obj_graphics[1]) { y += 32 + 4; @@ -180,6 +183,7 @@ MissionInformation_Draw void MissionInformation_Draw( centity_t *cent ) { int i,totalY; + int iYPixelsPerLine = cgi_R_Font_HeightPixels(cgs.media.qhFontMedium, 1.0f) * (cgi_Language_IsAsian() ? 1.2f : 1.0f ); missionInfo_Updated = qfalse; // This will stop the text from flashing cg.missionInfoFlashTime = 0; @@ -199,7 +203,7 @@ void MissionInformation_Draw( centity_t *cent ) { if (cent->gent->client->sess.mission_objectives[i].display) { - totalY = missionYpos + (18 * (missionYcnt))+9; + totalY = missionYpos + (iYPixelsPerLine * (missionYcnt))+(iYPixelsPerLine/2); if (obj_graphics[0]) { totalY += 32 + 4; @@ -230,7 +234,8 @@ void MissionInformation_Draw( centity_t *cent ) if (!missionYcnt) { cgi_SP_GetStringTextString( "INGAME_OBJNONE", text, sizeof(text) ); - CG_DrawProportionalString(108, missionYpos, text, CG_SMALLFONT, colorTable[CT_LTBLUE1] ); +// CG_DrawProportionalString(108, missionYpos, text, CG_SMALLFONT, colorTable[CT_LTBLUE1] ); + cgi_R_Font_DrawString (108, missionYpos, text, colorTable[CT_LTBLUE1], cgs.media.qhFontMedium, -1, 1.0f); } } @@ -380,7 +385,7 @@ void CG_DrawInformation( void ) { CG_DrawPic( 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, levelshot ); } - if ( g_eSavedGameJustLoaded != eFULL && !strcmp(s,"kejim_post") )//special case for first map! + if ( g_eSavedGameJustLoaded != eFULL && (!strcmp(s,"kejim_post") || !strcmp(s,"demo")) )//special case for first map! { char text[1024]={0}; cgi_SP_GetStringTextString( "INGAME_ALONGTIME", text, sizeof(text) ); diff --git a/code/cgame/cg_local.h b/code/cgame/cg_local.h index 83e5a1f..bbaf858 100644 --- a/code/cgame/cg_local.h +++ b/code/cgame/cg_local.h @@ -62,7 +62,7 @@ #define GIANT_HEIGHT 48 #define MAX_PRINTTEXT 128 -#define MAX_CAPTIONTEXT 64 +#define MAX_CAPTIONTEXT 32 // we don't need 64 now since we don't use this for scroll text, and I needed to change a hardwired 128 to 256, so... #define MAX_LCARSTEXT 128 @@ -362,7 +362,7 @@ typedef struct { char printText[MAX_PRINTTEXT][128]; int printTextY; - char captionText[MAX_CAPTIONTEXT][128]; + char captionText[MAX_CAPTIONTEXT][256/*128*/]; // bosted for taiwanese squealy radio static speech in kejim post int captionTextY; int scrollTextLines; // Number of lines being printed @@ -594,6 +594,7 @@ extern vmCvar_t cg_panoNumShots; extern vmCvar_t fx_freeze; extern vmCvar_t fx_debug; +extern vmCvar_t cg_missionInfoCentered; extern vmCvar_t cg_missionInfoFlashTime; extern vmCvar_t cg_hudFiles; @@ -930,7 +931,7 @@ void cgi_UpdateScreen( void ); void cgi_CM_LoadMap( const char *mapname ); int cgi_CM_NumInlineModels( void ); clipHandle_t cgi_CM_InlineModel( int index ); // 0 = world, 1+ = bmodels -clipHandle_t cgi_CM_TempBoxModel( const vec3_t mins, const vec3_t maxs ); +clipHandle_t cgi_CM_TempBoxModel( const vec3_t mins, const vec3_t maxs );//, const int contents ); int cgi_CM_PointContents( const vec3_t p, clipHandle_t model ); int cgi_CM_TransformedPointContents( const vec3_t p, clipHandle_t model, const vec3_t origin, const vec3_t angles ); void cgi_CM_BoxTrace( trace_t *results, const vec3_t start, const vec3_t end, @@ -965,6 +966,15 @@ void cgi_S_StartBackgroundTrack( const char *intro, const char *loop, qboolean b float cgi_S_GetSampleLength( sfxHandle_t sfx); +#ifdef _IMMERSION +void cgi_FF_Start( ffHandle_t ff, int clientNum ); +void cgi_FF_Ensure( ffHandle_t ff, int clientNum ); +void cgi_FF_Stop( ffHandle_t ff, int clientNum ); +void cgi_FF_StopAll( void ); +void cgi_FF_Shake( int intensity, int duration ); +ffHandle_t cgi_FF_Register( const char *name, int channel ); +void cgi_FF_AddLoopingForce( ffHandle_t handle, int entNum ); +#else // I've made these into ints instead of original typedefs to cut down on rebuild time // if I update the module they're in. No point in rebuilding all CGAME modules... // @@ -973,6 +983,7 @@ void cgi_FF_EnsureFX( int iFX ); void cgi_FF_StopFX( int iFX ); void cgi_FF_StopAllFX( void ); +#endif // _IMMERSION @@ -990,6 +1001,7 @@ int cgi_R_Font_StrLenChars(const char *text); int cgi_R_Font_HeightPixels(const int iFontIndex, const float scale = 1.0f); void cgi_R_Font_DrawString(int ox, int oy, const char *text, const float *rgba, const int setIndex, int iMaxPixelWidth, const float scale = 1.0f); qboolean cgi_Language_IsAsian(void); +qboolean cgi_Language_UsesSpaces(void); unsigned cgi_AnyLanguage_ReadCharFromString( const char **ppText, qboolean *pbIsTrailingPunctuation = NULL ); // a scene is built up by calls to R_ClearScene and the various R_Add functions. diff --git a/code/cgame/cg_main.cpp b/code/cgame/cg_main.cpp index 7536017..ff8e327 100644 --- a/code/cgame/cg_main.cpp +++ b/code/cgame/cg_main.cpp @@ -10,6 +10,9 @@ #include "..\game\characters.h" #include "cg_lights.h" +#ifdef _IMMERSION +#include "../ff/ff.h" +#endif // _IMMERSION #include "../qcommon/sstring.h" //NOTENOTE: Be sure to change the mirrored code in g_shared.h typedef map< sstring_t, unsigned char, less, allocator< unsigned char > > namePrecache_m; @@ -287,6 +290,7 @@ vmCvar_t cg_panoNumShots; vmCvar_t fx_freeze; vmCvar_t fx_debug; +vmCvar_t cg_missionInfoCentered; vmCvar_t cg_missionInfoFlashTime; vmCvar_t cg_hudFiles; @@ -395,6 +399,7 @@ cvarTable_t cvarTable[] = { { &cg_developer, "developer", "", 0 }, { &cg_timescale, "timescale", "1", 0 }, { &cg_skippingcin, "skippingCinematic", "0", CVAR_ROM}, + { &cg_missionInfoCentered, "cg_missionInfoCentered", "1", CVAR_ARCHIVE }, { &cg_missionInfoFlashTime, "cg_missionInfoFlashTime", "10000", 0 }, { &cg_hudFiles, "cg_hudFiles", "ui/jk2hud.txt", CVAR_ARCHIVE}, /* @@ -601,6 +606,54 @@ void CG_RegisterItemSounds( int itemNum ) { } } +#ifdef _IMMERSION +/* +================= +CG_RegisterItemForces + +The server says this item is used on this level +================= +*/ +void CG_RegisterItemForces( int itemNum ) { + gitem_t *item; + char data[MAX_QPATH]; + char *s, *start; + int len; + + item = &bg_itemlist[ itemNum ]; + + if (item->pickup_force) + { + cgi_FF_Register( item->pickup_force, FF_CHANNEL_TOUCH ); + } + + // parse the space seperated precache string for other media + s = item->forces; + if (!s || !s[0]) + return; + + while (*s) { + start = s; + while (*s && *s != ' ') { + s++; + } + + len = s-start; + if (len >= MAX_QPATH) { + CG_Error( "PrecacheItem: %s has bad precache string", + item->classname); + return; + } + memcpy (data, start, len); + data[len] = 0; + if ( *s ) { + s++; + } + + cgi_FF_Register( data, FF_CHANNEL_TOUCH ); + } +} +#endif // _IMMERSION /* ====================== @@ -747,6 +800,73 @@ static void CG_RegisterSounds( void ) { } } +#ifdef _IMMERSION +extern qboolean CG_ConfigForce( int index, const char *&name, int &channel ); +/* +================= +CG_RegisterForces + +called during a precache command +================= +*/ +static void CG_RegisterForces( void ) +{ + char name[512]; + int i, channel; + const char *forceName; + + cgs.media.selectForce = cgi_FF_Register( "fffx/weapons/change", FF_CHANNEL_WEAPON ); + + for (i=0 ; i<4 ; i++) { + Com_sprintf (name, sizeof(name), "fffx/player/footsteps/step%i", i+1); + cgs.media.footstepForces[FOOTSTEP_NORMAL][i] = cgi_FF_Register( name, FF_CHANNEL_FOOT ); + + Com_sprintf (name, sizeof(name), "fffx/player/footsteps/splash%i", i+1); + cgs.media.footstepForces[FOOTSTEP_SPLASH][i] = cgi_FF_Register( name, FF_CHANNEL_FOOT ); + + Com_sprintf (name, sizeof(name), "fffx/player/footsteps/clank%i", i+1); + cgs.media.footstepForces[FOOTSTEP_METAL][i] = cgi_FF_Register( name, FF_CHANNEL_FOOT ); + + // should these always be registered?? + Com_sprintf (name, sizeof(name), "fffx/player/footsteps/boot%i", i+1); + cgi_FF_Register( name, FF_CHANNEL_FOOT ); + } + + cgs.media.noAmmoForce = cgi_FF_Register( "fffx/weapons/noammo", FF_CHANNEL_WEAPON ); + cgs.media.landForce = cgi_FF_Register( "fffx/player/land1", FF_CHANNEL_BODY ); + + cgs.media.watrInForce = cgi_FF_Register( "fffx/player/watr_in", FF_CHANNEL_BODY ); + cgs.media.watrOutForce = cgi_FF_Register( "fffx/player/watr_out", FF_CHANNEL_BODY ); + cgs.media.watrUnForce = cgi_FF_Register( "fffx/player/watr_un", FF_CHANNEL_BODY ); + + cgs.media.zoomStartForce = cgi_FF_Register( "fffx/interface/zoomstart", FF_CHANNEL_WEAPON ); + cgs.media.zoomLoopForce = cgi_FF_Register( "fffx/interface/zoomloop", FF_CHANNEL_WEAPON ); + cgs.media.zoomEndForce = cgi_FF_Register( "fffx/interface/zoomend", FF_CHANNEL_WEAPON ); + + cgs.media.grenadeBounce1Force = cgi_FF_Register( "fffx/weapons/thermal/bounce1", FF_CHANNEL_WEAPON ); + cgs.media.grenadeBounce2Force = cgi_FF_Register( "fffx/weapons/thermal/bounce2", FF_CHANNEL_WEAPON ); + + for ( i = 1 ; i < bg_numItems ; i++ ) + { + CG_RegisterItemForces( i ); + } + + for ( i = 1 ; i < MAX_FORCES ; i++ ) + { + if ( !CG_ConfigForce( i, forceName, channel ) ) + break; + + if ( forceName[0] == '*' ) { + continue; // custom force??? + } + if (i&31) { + CG_LoadingString( forceName ); + } + + cgs.force_precache[i] = cgi_FF_Register( forceName, channel ); + } +} +#endif // _IMMERSION /* ============================================================================= @@ -1607,6 +1727,9 @@ Ghoul2 Insert End CG_RegisterSounds(); +#ifdef _IMMERSION + CG_RegisterForces(); +#endif // _IMMERSION CG_RegisterGraphics(); @@ -1775,6 +1898,7 @@ Called before every level change or subsystem restart */ void CG_Shutdown( void ) { + in_camera = false; FX_Free(); } @@ -3172,7 +3296,7 @@ int showDataPadPowers[MAX_DPSHOWPOWERS] = FP_SABER_OFFENSE, }; -char *showDataPadPowersName[MAX_DPSHOWPOWERS] = +/*char *showDataPadPowersName[MAX_DPSHOWPOWERS] = { "HEAL2", "JUMP2", @@ -3186,6 +3310,8 @@ char *showDataPadPowersName[MAX_DPSHOWPOWERS] = "SABER_DEFENSE2", "SABER_OFFENSE2", }; +/* + /* =============== ForcePower_Valid diff --git a/code/cgame/cg_media.h b/code/cgame/cg_media.h index 0636b73..61082b1 100644 --- a/code/cgame/cg_media.h +++ b/code/cgame/cg_media.h @@ -255,6 +255,28 @@ typedef struct { //blaster reflection sounds sfxHandle_t blasterReflectSound[3]; +#ifdef _IMMERSION + ffHandle_t grenadeBounce1Force; + ffHandle_t grenadeBounce2Force; + + ffHandle_t selectForce; + + ffHandle_t footstepForces[FOOTSTEP_TOTAL][4]; + + ffHandle_t noAmmoForce; + + ffHandle_t landForce; + ffHandle_t messageLitForce; + + ffHandle_t watrInForce; + ffHandle_t watrOutForce; + ffHandle_t watrUnForce; + + ffHandle_t zoomStartForce; + ffHandle_t zoomLoopForce; + ffHandle_t zoomEndForce; + ffHandle_t disruptorZoomLoopForce; +#endif // _IMMERSION } cgMedia_t; @@ -322,6 +344,9 @@ typedef struct { // qhandle_t model_draw[MAX_MODELS]; sfxHandle_t sound_precache[MAX_SOUNDS]; +#ifdef _IMMERSION + ffHandle_t force_precache[MAX_FORCES]; +#endif // _IMMERSION // Ghoul2 start qhandle_t skins[MAX_CHARSKINS]; diff --git a/code/cgame/cg_players.cpp b/code/cgame/cg_players.cpp index 3e3a53e..78cb883 100644 --- a/code/cgame/cg_players.cpp +++ b/code/cgame/cg_players.cpp @@ -263,7 +263,8 @@ static sfxHandle_t CG_CustomSound( int entityNum, const char *soundName, int cus if ( !g_entities[entityNum].client ) { // No client, this should never happen, so just use kyle's sounds - ci = &g_entities[0].client->clientInfo; + //ci = &g_entities[0].client->clientInfo; + ci = &cgs.clientinfo[entityNum]; } else { @@ -4130,6 +4131,38 @@ int CG_SaberHumSoundForEnt( gentity_t *gent ) } return saberHumSound; } +#ifdef _IMMERSION +int CG_SaberHumForceForEnt( gentity_t *gent ) +{ + //now: based on saber type and npc, pick correct hum sound + int saberHumForce = cgi_FF_Register( "fffx/weapons/saber/saberhum1", FF_CHANNEL_WEAPON ); + if ( gent && gent->client ) + { + if ( gent->client->NPC_class == CLASS_DESANN ) + {//desann + saberHumForce = cgi_FF_Register( "fffx/weapons/saber/saberhum2", FF_CHANNEL_WEAPON ); + } + else if ( gent->client->NPC_class == CLASS_LUKE ) + {//luke + saberHumForce = cgi_FF_Register( "fffx/weapons/saber/saberhum5", FF_CHANNEL_WEAPON ); + } + else if ( gent->client->NPC_class == CLASS_KYLE ) + {//Kyle NPC and player + saberHumForce = cgi_FF_Register( "fffx/weapons/saber/saberhum4", FF_CHANNEL_WEAPON ); + } + else if ( gent->client->playerTeam == TEAM_ENEMY )//NPC_class == CLASS_TAVION ) + {//reborn, shadowtroopers, tavion + saberHumForce = cgi_FF_Register( "fffx/weapons/saber/saberhum3", FF_CHANNEL_WEAPON ); + } + else + {//allies + //use default + //saberHumSound = cgi_S_RegisterSound( "sound/weapons/saber/saberhum1.wav" ); + } + } + return saberHumForce; +} +#endif // _IMMERSION /* =============== CG_StopWeaponSounds @@ -4153,6 +4186,12 @@ void CG_StopWeaponSounds( centity_t *cent ) cent->lerpOrigin, vec3_origin, CG_SaberHumSoundForEnt( &g_entities[cent->currentState.clientNum] ) ); +#ifdef _IMMERSION + cgi_FF_AddLoopingForce + ( CG_SaberHumForceForEnt( &g_entities[cent->currentState.clientNum] ) + , cent->currentState.number + ); +#endif // _IMMERSION return; } @@ -4174,6 +4213,12 @@ void CG_StopWeaponSounds( centity_t *cent ) cgi_S_StartSound( cent->lerpOrigin, cent->currentState.number, CHAN_WEAPON, weapon->stopSound ); } +#ifdef _IMMERSION + if ( weapon->stopForce ) + { + cgi_FF_Start( weapon->stopForce, cent->currentState.number ); + } +#endif // _IMMERSION cent->pe.lightningFiring = qfalse; } return; @@ -4191,6 +4236,12 @@ void CG_StopWeaponSounds( centity_t *cent ) { cgi_S_AddLoopingSound( cent->currentState.number, cent->lerpOrigin, vec3_origin, weapon->altFiringSound ); } +#ifdef _IMMERSION + if ( weapon->altFiringForce ) + { + cgi_FF_AddLoopingForce( weapon->altFiringForce, cent->currentState.number ); + } +#endif // _IMMERSION cent->pe.lightningFiring = qtrue; } else if ( cent->currentState.eFlags & EF_FIRING ) @@ -4204,6 +4255,12 @@ void CG_StopWeaponSounds( centity_t *cent ) cgi_S_AddLoopingSound( cent->currentState.number, cent->lerpOrigin, vec3_origin, weapon->firingSound ); } +#ifdef _IMMERSION + if ( weapon->firingForce ) + { + cgi_FF_AddLoopingForce( weapon->firingForce, cent->currentState.number/*, vec3_origin*/ ); + } +#endif // _IMMERSION } } @@ -4573,6 +4630,12 @@ Ghoul2 Insert End */ if ( !Q_irand( 0, 10 ) ) {//FIXME: don't do this this way.... :) +#ifdef _IMMERSION + if ( !cent->currentState.saberInFlight ) + { + cgi_FF_Start( cgi_FF_Register( "fffx/weapons/saber/hitwater", FF_CHANNEL_WEAPON ), cent->currentState.number ); + } +#endif // _IMMERSION vec3_t spot; VectorCopy( trace.endpos, spot ); spot[2] += 4; @@ -4599,7 +4662,16 @@ Ghoul2 Insert End if ( cg.time - cent->gent->client->ps.saberHitWallSoundDebounceTime >= 100 ) {//ugh, need to have a real sound debouncer... or do this game-side cent->gent->client->ps.saberHitWallSoundDebounceTime = cg.time; +#ifdef _IMMERSION + int index = Q_irand( 1, 3 ); + cgi_S_StartSound ( cent->lerpOrigin, cent->currentState.clientNum, CHAN_WEAPON, cgi_S_RegisterSound( va ( "sound/weapons/saber/saberhitwall%d.wav", index ) ) ); + if ( !cent->currentState.saberInFlight ) + { + cgi_FF_Start( cgi_FF_Register( va( "fffx/weapons/saber/saberhitwall%d", index ), FF_CHANNEL_WEAPON ), cent->currentState.clientNum ); + } +#else cgi_S_StartSound ( cent->lerpOrigin, cent->currentState.clientNum, CHAN_ITEM, cgi_S_RegisterSound( va ( "sound/weapons/saber/saberhitwall%d.wav", Q_irand( 1, 3 ) ) ) ); +#endif // _IMMERSION } } } @@ -4651,6 +4723,13 @@ Ghoul2 Insert End // if we happen to be timescaled or running in a high framerate situation, we don't want to flood // the system with very small trail slices...but perhaps doing it by distance would yield better results? + if ( saberTrail->lastTime > cg.time ) + {//after a pause, cg.time jumps ahead in time for one frame + //and lastTime gets set to that and will freak out, so, since + //it's never valid for saberTrail->lastTime to be > cg.time, + //cap it to cg.time here + saberTrail->lastTime = cg.time; + } if ( cg.time > saberTrail->lastTime + 2 && saberTrail->inAction ) // 2ms { if ( saberTrail->inAction && cg.time < saberTrail->lastTime + 300 ) // if we have a stale segment, don't draw until we have a fresh one @@ -4875,7 +4954,7 @@ void CG_Player( centity_t *cent ) { ent.renderfx |= RF_SHADOW_PLANE; } ent.renderfx |= RF_LIGHTING_ORIGIN; // use the same origin for all - if ( cent->gent->NPC->scriptFlags & SCF_MORELIGHT ) + if ( cent->gent->NPC && cent->gent->NPC->scriptFlags & SCF_MORELIGHT ) { ent.renderfx |= RF_MORELIGHT; //bigger than normal min light } @@ -5234,14 +5313,23 @@ extern vmCvar_t cg_thirdPersonAlpha; if ( !cent->gent->client->ps.saberLength ) { qhandle_t saberOnSound; +#ifdef _IMMERSION + ffHandle_t saberOnForce; +#endif // _IMMERSION if ( cent->gent->client->playerTeam == TEAM_PLAYER ) { saberOnSound = cgi_S_RegisterSound( "sound/weapons/saber/saberon.wav" ); +#ifdef _IMMERSION + saberOnForce = cgi_FF_Register( "fffx/weapons/saber/saberon", FF_CHANNEL_WEAPON ); +#endif // _IMMERSION } else { saberOnSound = cgi_S_RegisterSound( "sound/weapons/saber/enemy_saber_on.wav" ); +#ifdef _IMMERSION + saberOnForce = cgi_FF_Register( "fffx/weapons/saber/enemy_saber_on", FF_CHANNEL_WEAPON ); +#endif // _IMMERSION } if ( !cent->gent->client->ps.weaponTime ) {//make us play the turn on anim @@ -5256,6 +5344,9 @@ extern vmCvar_t cg_thirdPersonAlpha; else { cgi_S_StartSound (NULL, cent->currentState.number, CHAN_AUTO, saberOnSound ); +#ifdef _IMMERSION + cgi_FF_Start( saberOnForce, cent->currentState.number ); +#endif // _IMMERSION } } if ( cg.frametime > 0 ) @@ -5612,7 +5703,7 @@ Ghoul2 Insert End } // get the animation state (after rotation, to allow feet shuffle) - // NB: Also plays keyframed animSounds (Bob- hope you dont mind, I was here late and at about 5:30 Am i needed to do something to keep me awake and i figured you wouldn't mind- you might want to check it, though, to make sure I wasn't smoking crack and missed something important, it is pretty late and I'm getting pretty close to being up for 24 hours here, so i wouldn't doubt if I might have messed something up, but i tested it and it looked right.... noticed in old code base i was doing it wrong too, which explains why I was getting so many damn sounds all the time! I had to lower the probabilities because it seemed like i was getting way too many sounds, and that was the problem! Well, should be fixed now I think...) + // NB: Also plays keyframed animSounds (Bob- hope you dont mind, I was here late and at about 5:30 Am i needed to do something to keep me awake and i figured you wouldn't mind- you might want to check it, though, to make sure I wasn't smoking crack and missed something important, it is pretty late and I'm getting pretty close to being up for 24 hours here, so i wouldn't doubt if I might have messed something up, but i tested it and it looked right.... noticed in old code base i was doing it wrong too, whic h explains why I was getting so many damn sounds all the time! I had to lower the probabilities because it seemed like i was getting way too many sounds, and that was the problem! Well, should be fixed now I think...) CG_PlayerAnimation( cent, &legs.oldframe, &legs.frame, &legs.backlerp, &torso.oldframe, &torso.frame, &torso.backlerp ); @@ -5845,6 +5936,9 @@ Ghoul2 Insert End else { cgi_S_StartSound (NULL, cent->currentState.number, CHAN_AUTO, cgi_S_RegisterSound( "sound/weapons/saber/saberon.wav" ) ); +#ifdef _IMMERSION + cgi_FF_Start( cgi_FF_Register( "fffx/weapons/saber/saberon", FF_CHANNEL_WEAPON ), cent->currentState.number ); +#endif // _IMMERSION } } cent->gent->client->ps.saberLength += cent->gent->client->ps.saberLengthMax/6 * cg.frametime/100;//= saberLengthMax; diff --git a/code/cgame/cg_playerstate.cpp b/code/cgame/cg_playerstate.cpp index 6414541..8c40c53 100644 --- a/code/cgame/cg_playerstate.cpp +++ b/code/cgame/cg_playerstate.cpp @@ -87,6 +87,9 @@ void CG_CheckAmmo( void ) // play a sound on transitions if ( cg.lowAmmoWarning != previous ) { cgi_S_StartLocalSound( cgs.media.noAmmoSound, CHAN_LOCAL_SOUND ); //"sound/weapons/noammo.wav" +#ifdef _IMMERSION + cgi_FF_Start( cgs.media.noAmmoForce, FF_CLIENT_LOCAL ); +#endif // _IMMERSION } } @@ -185,6 +188,9 @@ void CG_DamageFeedback( int yawByte, int pitchByte, int damage ) { cg.damageValue = kick; cg.v_dmg_time = cg.time + DAMAGE_TIME; cg.damageTime = cg.snap->serverTime; +#ifdef _IMMERSION + cgi_FF_Start( cgi_FF_Register( "fffx/player/damage", FF_CHANNEL_DAMAGE ), cg.snap->ps.clientNum ); +#endif // _IMMERSION } diff --git a/code/cgame/cg_predict.cpp b/code/cgame/cg_predict.cpp index 6a9a88e..3a87411 100644 --- a/code/cgame/cg_predict.cpp +++ b/code/cgame/cg_predict.cpp @@ -105,7 +105,7 @@ void CG_ClipMoveToEntities ( const vec3_t start, const vec3_t mins, const vec3_t bmins[2] = -zd; bmaxs[2] = zu; - cmodel = cgi_CM_TempBoxModel( bmins, bmaxs ); + cmodel = cgi_CM_TempBoxModel( bmins, bmaxs );//, cent->gent->contents ); VectorCopy( vec3_origin, angles ); VectorCopy( cent->lerpOrigin, origin ); } diff --git a/code/cgame/cg_public.h b/code/cgame/cg_public.h index b832363..13520be 100644 --- a/code/cgame/cg_public.h +++ b/code/cgame/cg_public.h @@ -52,7 +52,7 @@ functions imported from the main executable ================================================================== */ -#define CGAME_IMPORT_API_VERSION 3 +#define CGAME_IMPORT_API_VERSION 4 typedef enum { CG_PRINT, @@ -90,10 +90,19 @@ typedef enum { CG_S_RESPATIALIZE, CG_S_REGISTERSOUND, CG_S_STARTBACKGROUNDTRACK, +#ifdef _IMMERSION + CG_FF_START, + CG_FF_STOP, + CG_FF_STOPALL, + CG_FF_SHAKE, + CG_FF_REGISTER, + CG_FF_ADDLOOPINGFORCE, +#else CG_FF_STARTFX, CG_FF_ENSUREFX, CG_FF_STOPFX, CG_FF_STOPALLFX, +#endif // _IMMERSION CG_R_LOADWORLDMAP, CG_R_REGISTERMODEL, CG_R_REGISTERSKIN, @@ -105,6 +114,7 @@ typedef enum { CG_R_FONTHEIGHTPIXELS, CG_R_FONTDRAWSTRING, CG_LANGUAGE_ISASIAN, + CG_LANGUAGE_USESSPACES, CG_ANYLANGUAGE_READFROMSTRING, CG_R_CLEARSCENE, CG_R_ADDREFENTITYTOSCENE, diff --git a/code/cgame/cg_syscalls.cpp b/code/cgame/cg_syscalls.cpp index 1d1beb3..acd7181 100644 --- a/code/cgame/cg_syscalls.cpp +++ b/code/cgame/cg_syscalls.cpp @@ -8,12 +8,16 @@ +#ifdef _IMMERSION +#include "../ff/ff.h" +#else ///////////////////// this is a bit kludgy, but it only gives access to one // enum table because of the #define. May get changed. #define CGAME_ONLY #include "../client/fffx.h" // ///////////////////// +#endif // _IMMERSION @@ -116,8 +120,8 @@ clipHandle_t cgi_CM_InlineModel( int index ) { return syscall( CG_CM_INLINEMODEL, index ); } -clipHandle_t cgi_CM_TempBoxModel( const vec3_t mins, const vec3_t maxs ) { - return syscall( CG_CM_TEMPBOXMODEL, mins, maxs ); +clipHandle_t cgi_CM_TempBoxModel( const vec3_t mins, const vec3_t maxs ) {//, const int contents ) { + return syscall( CG_CM_TEMPBOXMODEL, mins, maxs );//, contents ); } int cgi_CM_PointContents( const vec3_t p, clipHandle_t model ) { @@ -209,6 +213,34 @@ float cgi_S_GetSampleLength( sfxHandle_t sfx ) { return syscall( CG_S_GETSAMPLELENGTH, sfx); } +#ifdef _IMMERSION + +void cgi_FF_Start( ffHandle_t ff, int clientNum ){ + syscall( CG_FF_START, ff, clientNum ); +} + +void cgi_FF_Stop( ffHandle_t ff, int clientNum ){ + syscall( CG_FF_STOP, ff, clientNum ); +} + +void cgi_FF_StopAll( void ){ + syscall( CG_FF_STOPALL ); +} + +void cgi_FF_Shake( int intensity, int duration ){ + syscall( CG_FF_SHAKE, intensity, duration ); +} + +ffHandle_t cgi_FF_Register( const char *name, int channel ){ + return syscall( CG_FF_REGISTER, name, channel ); +} + +void cgi_FF_AddLoopingForce( ffHandle_t handle, int entNum ){ + syscall( CG_FF_ADDLOOPINGFORCE, handle, entNum ); +} + +#else + void cgi_FF_StartFX( int iFX ){ syscall( CG_FF_STARTFX, iFX ); } @@ -225,6 +257,7 @@ void cgi_FF_StopAllFX( void ){ syscall( CG_FF_STOPALLFX ); } +#endif // _IMMERSION void cgi_R_LoadWorldMap( const char *mapname ) { syscall( CG_R_LOADWORLDMAP, mapname ); } @@ -268,6 +301,11 @@ qboolean cgi_Language_IsAsian( void ) return syscall( CG_LANGUAGE_ISASIAN ); } +qboolean cgi_Language_UsesSpaces(void) +{ + return syscall( CG_LANGUAGE_USESSPACES ); +} + unsigned int cgi_AnyLanguage_ReadCharFromString( const char **ppText, qboolean *pbIsTrailingPunctuation /* = NULL */ ) { return syscall( CG_ANYLANGUAGE_READFROMSTRING, ppText, pbIsTrailingPunctuation ); diff --git a/code/cgame/cg_text.cpp b/code/cgame/cg_text.cpp index ca6bf08..5da3d0b 100644 --- a/code/cgame/cg_text.cpp +++ b/code/cgame/cg_text.cpp @@ -309,53 +309,58 @@ const char *CG_DisplayBoxedText(int iBoxX, int iBoxY, int iBoxWidth, int iBoxHei Q_strcat(sLineForDisplay, sizeof(sLineForDisplay),va("%c",uiLetter & 0xFF)); } - // record last-good linebreak pos... (ie if we've just concat'd a punctuation point (western or asian) or space) - // - if (bIsTrailingPunctuation || uiLetter == ' ') - { - psBestLineBreakSrcPos = psCurrentTextReadPos; - } - if (uiLetter == '\n') { // explicit new line... // sLineForDisplay[ strlen(sLineForDisplay)-1 ] = '\0'; // kill the CR psReadPosAtLineStart = psCurrentTextReadPos; + psBestLineBreakSrcPos = psCurrentTextReadPos; break; // print this line } else - if ( cgi_R_Font_StrLenPixels(sLineForDisplay, iFontHandle, fScale) >= (iBoxWidth - 16) ) - { + if ( cgi_R_Font_StrLenPixels(sLineForDisplay, iFontHandle, fScale) >= iBoxWidth ) + { // reached screen edge, so cap off string at bytepos after last good position... // - if (psBestLineBreakSrcPos == psReadPosAtLineStart) + if (uiLetter > 255 && bIsTrailingPunctuation && !cgi_Language_UsesSpaces()) { - // aarrrggh!!!!! we'll only get here is someone has fed in a (probably) garbage string, - // since it doesn't have a single space or punctuation mark right the way across one line - // of the screen. So far, this has only happened in testing when I hardwired a taiwanese - // string into this function while the game was running in english (which should NEVER happen - // normally). On the other hand I suppose it'psCurrentTextReadPos entirely possible that some taiwanese string - // might have no punctuation at all, so... + // Special case, don't consider line breaking if you're on an asian punctuation char of + // a language that doesn't use spaces... // - psBestLineBreakSrcPos = psLastGood_s; // force a break after last good letter } + else + { + if (psBestLineBreakSrcPos == psReadPosAtLineStart) + { + // aarrrggh!!!!! we'll only get here is someone has fed in a (probably) garbage string, + // since it doesn't have a single space or punctuation mark right the way across one line + // of the screen. So far, this has only happened in testing when I hardwired a taiwanese + // string into this function while the game was running in english (which should NEVER happen + // normally). On the other hand I suppose it'psCurrentTextReadPos entirely possible that some taiwanese string + // might have no punctuation at all, so... + // + psBestLineBreakSrcPos = psLastGood_s; // force a break after last good letter + } - sLineForDisplay[ psBestLineBreakSrcPos - psReadPosAtLineStart ] = '\0'; - psReadPosAtLineStart = psCurrentTextReadPos = psBestLineBreakSrcPos; - break; // print this line + sLineForDisplay[ psBestLineBreakSrcPos - psReadPosAtLineStart ] = '\0'; + psReadPosAtLineStart = psCurrentTextReadPos = psBestLineBreakSrcPos; + break; // print this line + } + } + + // record last-good linebreak pos... (ie if we've just concat'd a punctuation point (western or asian) or space) + // + if (bIsTrailingPunctuation || uiLetter == ' ' || (uiLetter > 255 && !cgi_Language_UsesSpaces())) + { + psBestLineBreakSrcPos = psCurrentTextReadPos; } } // ... and print it... // -// int iWidth = cgi_R_Font_StrLenPixels( sLineForDisplay, iFontHandle, iFontScale ); -// if (iWidth) -// { -// int x = BoxX; // ignore this for now -----> (SCREEN_WIDTH-iWidth) / 2; - cgi_R_Font_DrawString(iBoxX, iYpos, sLineForDisplay, v4Color, iFontHandle, -1, fScale); - iYpos += iFontHeightAdvance; -// } + cgi_R_Font_DrawString(iBoxX, iYpos, sLineForDisplay, v4Color, iFontHandle, -1, fScale); + iYpos += iFontHeightAdvance; // and echo to console in dev mode... // @@ -512,13 +517,6 @@ void CG_CaptionText( const char *str, int sound, int y ) Q_strcat(cg.captionText[i],sizeof(cg.captionText[i]),va("%c",uiLetter & 0xFF)); } - // record last-good linebreak pos... (ie if we've just concat'd a punctuation point (western or asian) or space) - // - if (bIsTrailingPunctuation || uiLetter == ' ') - { - psBestLineBreakSrcPos = s; - } - if (uiLetter == '\n') { // explicit new line... @@ -526,29 +524,46 @@ void CG_CaptionText( const char *str, int sound, int y ) cg.captionText[i][ strlen(cg.captionText[i])-1 ] = '\0'; // kill the CR i++; holds = s; + psBestLineBreakSrcPos = s; cg.scrollTextLines++; } else - if ( cgi_R_Font_StrLenPixels(cg.captionText[i], cgs.media.qhFontMedium, fFontScale) >= SCREEN_WIDTH - 16) + if ( cgi_R_Font_StrLenPixels(cg.captionText[i], cgs.media.qhFontMedium, fFontScale) >= SCREEN_WIDTH) { // reached screen edge, so cap off string at bytepos after last good position... // - if (psBestLineBreakSrcPos == holds) + if (uiLetter > 255 && bIsTrailingPunctuation && !cgi_Language_UsesSpaces()) { - // aarrrggh!!!!! we'll only get here is someone has fed in a (probably) garbage string, - // since it doesn't have a single space or punctuation mark right the way across one line - // of the screen. So far, this has only happened in testing when I hardwired a taiwanese - // string into this function while the game was running in english (which should NEVER happen - // normally). On the other hand I suppose it's entirely possible that some taiwanese string - // might have no punctuation at all, so... + // Special case, don't consider line breaking if you're on an asian punctuation char of + // a language that doesn't use spaces... // - psBestLineBreakSrcPos = psLastGood_s; // force a break after last good letter } + else + { + if (psBestLineBreakSrcPos == holds) + { + // aarrrggh!!!!! we'll only get here is someone has fed in a (probably) garbage string, + // since it doesn't have a single space or punctuation mark right the way across one line + // of the screen. So far, this has only happened in testing when I hardwired a taiwanese + // string into this function while the game was running in english (which should NEVER happen + // normally). On the other hand I suppose it's entirely possible that some taiwanese string + // might have no punctuation at all, so... + // + psBestLineBreakSrcPos = psLastGood_s; // force a break after last good letter + } - cg.captionText[i][ psBestLineBreakSrcPos - holds ] = '\0'; - holds = s = psBestLineBreakSrcPos; - i++; - cg.scrollTextLines++; + cg.captionText[i][ psBestLineBreakSrcPos - holds ] = '\0'; + holds = s = psBestLineBreakSrcPos; + i++; + cg.scrollTextLines++; + } + } + + // record last-good linebreak pos... (ie if we've just concat'd a punctuation point (western or asian) or space) + // + if (bIsTrailingPunctuation || uiLetter == ' ' || (uiLetter > 255 && !cgi_Language_UsesSpaces())) + { + psBestLineBreakSrcPos = s; } } diff --git a/code/cgame/cg_view.cpp b/code/cgame/cg_view.cpp index c801178..0fe68ff 100644 --- a/code/cgame/cg_view.cpp +++ b/code/cgame/cg_view.cpp @@ -793,8 +793,9 @@ static void CG_OffsetThirdPersonView( void ) // We must now take the angle taken from the camera target and location. VectorSubtract(cameraCurTarget, cameraCurLoc, diff); + //Com_Printf( "%s\n", vtos(diff) ); float dist = VectorNormalize(diff); - if ( !dist ) + if ( dist < 1.0f ) {//must be hitting something, need some value to calc angles, so use cam forward VectorCopy( camerafwd, diff ); } @@ -1392,18 +1393,30 @@ static qboolean CG_CalcFov( void ) { if ( zoomSoundTime < cg.time ) { sfxHandle_t snd; +#ifdef _IMMERSION +// ffHandle_t ff; +#endif // _IMMERSION if ( cg.zoomMode == 1 ) { snd = cgs.media.zoomLoop; +#ifdef _IMMERSION +// ff = cgs.media.zoomLoopForce; +#endif // _IMMERSION } else { snd = cgs.media.disruptorZoomLoop; +#ifdef _IMMERSION +// ff = cgs.media.disruptorZoomLoopForce; +#endif // _IMMERSION } // huh? This could probably just be added as a looping sound?? cgi_S_StartSound( cg.refdef.vieworg, ENTITYNUM_WORLD, CHAN_LOCAL, snd ); +#ifdef _IMMERSION +// cgi_FF_Start( ff, cg.snap->ps.clientNum ); +#endif // _IMMERSION zoomSoundTime = cg.time + 150; } } @@ -1665,6 +1678,13 @@ static qboolean CG_CalcViewValues( void ) { CGCam_UpdateSmooth( cg.refdef.vieworg, cg.refdefViewAngles ); CGCam_UpdateShake( cg.refdef.vieworg, cg.refdefViewAngles ); + /* + if ( in_camera ) + { + Com_Printf( "%s %s\n", vtos(client_camera.origin), vtos(cg.refdef.vieworg) ); + } + */ + // see if we are drugged by an interrogator. We muck with the angles here, just a bit earlier, we mucked with the FOV if ( cg.wonkyTime > 0 && cg.wonkyTime > cg.time ) { diff --git a/code/cgame/cg_weapons.cpp b/code/cgame/cg_weapons.cpp index d303188..32e9968 100644 --- a/code/cgame/cg_weapons.cpp +++ b/code/cgame/cg_weapons.cpp @@ -8,12 +8,16 @@ #include "..\game\anims.h" +#ifdef _IMMERSION +#include "../ff/ff.h" +#else ///////////////////// this is a bit kludgy, but it only gives access to one // enum table because of the #define. May get changed. #define CGAME_ONLY #include "../client/fffx.h" // ///////////////////// +#endif // _IMMERSION extern void CG_LightningBolt( centity_t *cent, vec3_t origin ); @@ -69,6 +73,22 @@ void CG_RegisterWeapon( int weaponNum ) { // set up in view weapon model weaponInfo->weaponModel = cgi_R_RegisterModel( weaponData[weaponNum].weaponMdl ); + {//in case the weaponmodel isn't _w, precache the _w.glm + char weaponModel[64]; + + strcpy (weaponModel, weaponData[weaponNum].weaponMdl); + if (char *spot = strstr(weaponModel, ".md3") ) + { + *spot = 0; + spot = strstr(weaponModel, "_w");//i'm using the in view weapon array instead of scanning the item list, so put the _w back on + if (!spot) + { + strcat (weaponModel, "_w"); + } + strcat (weaponModel, ".glm"); //and change to ghoul2 + } + gi.G2API_PrecacheGhoul2Model( weaponModel ); // correct way is item->world_model + } if ( weaponInfo->weaponModel == NULL ) { @@ -150,6 +170,26 @@ void CG_RegisterWeapon( int weaponNum ) { weaponInfo->selectSound = cgi_S_RegisterSound( weaponData[weaponNum].selectSnd ); } +#ifdef _IMMERSION + if (weaponData[weaponNum].firingFrc[0]) { + weaponInfo->firingForce = cgi_FF_Register( weaponData[weaponNum].firingFrc, FF_CHANNEL_WEAPON ); + } + if (weaponData[weaponNum].altFiringFrc[0]) { + weaponInfo->altFiringForce = cgi_FF_Register( weaponData[weaponNum].altFiringFrc, FF_CHANNEL_WEAPON ); + } + if (weaponData[weaponNum].stopFrc[0]) { + weaponInfo->stopForce = cgi_FF_Register( weaponData[weaponNum].stopFrc, FF_CHANNEL_WEAPON ); + } + if (weaponData[weaponNum].chargeFrc[0]) { + weaponInfo->chargeForce = cgi_FF_Register( weaponData[weaponNum].chargeFrc, FF_CHANNEL_WEAPON ); + } + if (weaponData[weaponNum].altChargeFrc[0]) { + weaponInfo->altChargeForce = cgi_FF_Register( weaponData[weaponNum].altChargeFrc, FF_CHANNEL_WEAPON ); + } + if (weaponData[weaponNum].selectFrc[0]) { + weaponInfo->selectForce = cgi_FF_Register( weaponData[weaponNum].selectFrc, FF_CHANNEL_WEAPON ); + } +#endif // _IMMERSION // give us missile models if we should if (weaponData[weaponNum].missileMdl[0]) { weaponInfo->missileModel = cgi_R_RegisterModel(weaponData[weaponNum].missileMdl ); @@ -259,6 +299,42 @@ void CG_RegisterWeapon( int weaponNum ) { { cgi_S_RegisterSound( va( "sound/weapons/saber/rainfizz%d.wav", i ) ); } +#ifdef _IMMERSION + cgi_FF_Register( "fffx/weapons/saber/saberon", FF_CHANNEL_WEAPON ); + cgi_FF_Register( "fffx/weapons/saber/enemy_saber_on", FF_CHANNEL_WEAPON ); + cgi_FF_Register( "fffx/weapons/saber/saberonquick", FF_CHANNEL_WEAPON ); + cgi_FF_Register( "fffx/weapons/saber/saberoff", FF_CHANNEL_WEAPON ); + cgi_FF_Register( "fffx/weapons/saber/enemy_saber_off", FF_CHANNEL_WEAPON ); + cgi_FF_Register( "fffx/weapons/saber/saberspinoff", FF_CHANNEL_WEAPON ); + cgi_FF_Register( "fffx/weapons/saber/saberoffquick", FF_CHANNEL_WEAPON ); + for ( i = 1; i < 4; i++ ) + { + cgi_FF_Register( va( "fffx/weapons/saber/saberbounce%d", i ), FF_CHANNEL_WEAPON ); + } + cgi_FF_Register( "fffx/weapons/saber/saberhit", FF_CHANNEL_WEAPON ); + for ( i = 1; i < 4; i++ ) + { + cgi_FF_Register( va( "fffx/weapons/saber/saberhitwall%d", i ), FF_CHANNEL_WEAPON ); + } + for ( i = 1; i < 10; i++ ) + { + cgi_FF_Register( va( "fffx/weapons/saber/saberblock%d", i ), FF_CHANNEL_WEAPON ); + } + for ( i = 1; i < 6; i++ ) + { + cgi_FF_Register( va( "fffx/weapons/saber/saberhum%d", i ), FF_CHANNEL_WEAPON ); + } + for ( i = 1; i < 10; i++ ) + { + cgi_FF_Register( va( "fffx/weapons/saber/saberhup%d", i ), FF_CHANNEL_WEAPON ); + } + cgi_FF_Register( "fffx/weapons/saber/hitwater", FF_CHANNEL_WEAPON ); + cgi_FF_Register( "fffx/weapons/saber/boiling", FF_CHANNEL_WEAPON ); + for ( i = 1; i < 4; i++ ) + { + cgi_FF_Register( va( "fffx/weapons/saber/rainfizz%d", i ), FF_CHANNEL_WEAPON ); + } +#endif // _IMMERSION //force sounds cgi_S_RegisterSound( "sound/weapons/force/heal.mp3" ); @@ -346,6 +422,9 @@ void CG_RegisterWeapon( int weaponNum ) { cgi_S_RegisterSound( "sound/weapons/disruptor/zoomstart.wav" ); cgi_S_RegisterSound( "sound/weapons/disruptor/zoomend.wav" ); cgs.media.disruptorZoomLoop = cgi_S_RegisterSound( "sound/weapons/disruptor/zoomloop.wav" ); +#ifdef _IMMERSION + cgs.media.disruptorZoomLoopForce = cgi_FF_Register( "fffx/weapons/disruptor/zoomloop", FF_CHANNEL_WEAPON ); +#endif // _IMMERSION // Disruptor gun zoom interface cgs.media.disruptorMask = cgi_R_RegisterShader( "gfx/2d/cropCircle2"); @@ -2399,6 +2478,9 @@ void CG_Weapon_f( void ) else { cgi_S_StartSound (NULL, cg.snap->ps.clientNum, CHAN_AUTO, cgi_S_RegisterSound( "sound/weapons/saber/saberoff.wav" ) ); +#ifdef _IMMERSION + cgi_FF_Start( cgi_FF_Register( "fffx/weapons/saber/saberoff", FF_CHANNEL_WEAPON ), cg.snap->ps.clientNum ); +#endif // _IMMERSION } } else @@ -2466,7 +2548,9 @@ void CG_OutOfAmmoChange( void ) { int i; int original; +#ifndef _IMMERSION cgi_FF_StartFX( fffx_OutOfAmmo ); +#endif // _IMMERSION if ( cg.weaponSelectTime + 200 > cg.time ) return; @@ -2571,6 +2655,7 @@ void CG_FireWeapon( centity_t *cent, qboolean alt_fire ) } } +#ifndef _IMMERSION // force feedback... // if ( cent->gent->s.number == 0 ) @@ -2623,6 +2708,7 @@ void CG_FireWeapon( centity_t *cent, qboolean alt_fire ) cgi_FF_StartFX( fffx_OutOfAmmo ); break; } +#endif // _IMMERSION // Do overcharge sound that get's added to the top /* if (( ent->powerups & ( 1<currentState.saberActive ) + { + cgi_FF_Start( cgs.media.grenadeBounce1Force, cent->currentState.otherEntityNum ); + } +#endif // _IMMERSION } else { cgi_S_StartSound( origin, ENTITYNUM_WORLD, CHAN_AUTO, cgs.media.grenadeBounce2 ); +#ifdef _IMMERSION + if ( cent->currentState.saberActive ) + { + cgi_FF_Start( cgs.media.grenadeBounce2Force, cent->currentState.otherEntityNum ); + } +#endif // _IMMERSION } break; case WP_BOWCASTER: +#ifdef _IMMERSION + if ( cent->currentState.saberActive ) + theFxScheduler.PlayEffect( cgs.effects.bowcasterBounceEffect, FF_CLIENT( cent->currentState.otherEntityNum ), origin, normal ); + else +#endif // _IMMERSION theFxScheduler.PlayEffect( cgs.effects.bowcasterBounceEffect, origin, normal ); break; case WP_FLECHETTE: +#ifdef _IMMERSION + if ( cent->currentState.saberActive ) + theFxScheduler.PlayEffect( "flechette/ricochet", FF_CLIENT( cent->currentState.otherEntityNum ), origin, normal ); + else +#endif // _IMMERSION theFxScheduler.PlayEffect( "flechette/ricochet", origin, normal ); break; default: if ( rand() & 1 ) { cgi_S_StartSound( origin, ENTITYNUM_WORLD, CHAN_AUTO, cgs.media.grenadeBounce1 ); +#ifdef _IMMERSION + if ( cent->currentState.saberActive ) + { + cgi_FF_Start( cgs.media.grenadeBounce1Force, cent->currentState.otherEntityNum ); + } +#endif // _IMMERSION } else { cgi_S_StartSound( origin, ENTITYNUM_WORLD, CHAN_AUTO, cgs.media.grenadeBounce2 ); +#ifdef _IMMERSION + if ( cent->currentState.saberActive ) + { + cgi_FF_Start( cgs.media.grenadeBounce2Force, cent->currentState.otherEntityNum ); + } +#endif // _IMMERSION } break; } diff --git a/code/cgame/strip_objectives.h b/code/cgame/strip_objectives.h index 300ae94..6cdd560 100644 --- a/code/cgame/strip_objectives.h +++ b/code/cgame/strip_objectives.h @@ -70,8 +70,13 @@ enum OBJECTIVES_KEJIM_POST_OBJ5 = 0x0836, OBJECTIVES_ARTUS_DETENTION_OBJ3 = 0x0837, OBJECTIVES_DOOM_COMM_OBJ4 = 0x0838, - OBJECTIVES_DOOM_SHIELDS_OBJ3 = 0x0839 + OBJECTIVES_DOOM_SHIELDS_OBJ3 = 0x0839, + OBJECTIVES_DEMO_OBJ1 = 0x083a, + OBJECTIVES_DEMO_OBJ2 = 0x083b, + OBJECTIVES_DEMO_OBJ3 = 0x083c, + OBJECTIVES_DEMO_OBJ4 = 0x083d }; #endif // __strip_objectives_h + diff --git a/code/cgame/vssver.scc b/code/cgame/vssver.scc index 341b394..9888250 100644 Binary files a/code/cgame/vssver.scc and b/code/cgame/vssver.scc differ diff --git a/code/client/cl_cgame.cpp b/code/client/cl_cgame.cpp index 0358383..7828c98 100644 --- a/code/client/cl_cgame.cpp +++ b/code/client/cl_cgame.cpp @@ -7,7 +7,12 @@ #include "client.h" +#ifdef _IMMERSION +#include "../ff/cl_ff.h" +#include "../ff/ff.h" +#else #include "fffx.h" +#endif // _IMMERSION #include "vmachine.h" vm_t cgvm; @@ -432,7 +437,7 @@ int CL_CgameSystemCalls( int *args ) { case CG_CM_INLINEMODEL: return CM_InlineModel( args[1] ); case CG_CM_TEMPBOXMODEL: - return CM_TempBoxModel( (const float *) VMA(1), (const float *) VMA(2) ); + return CM_TempBoxModel( (const float *) VMA(1), (const float *) VMA(2) );//, (int) VMA(3) ); case CG_CM_POINTCONTENTS: return CM_PointContents( (float *)VMA(1), args[2] ); case CG_CM_TRANSFORMEDPOINTCONTENTS: @@ -506,6 +511,25 @@ int CL_CgameSystemCalls( int *args ) { return 0; case CG_S_GETSAMPLELENGTH: return S_GetSampleLengthInMilliSeconds( args[1]); +#ifdef _IMMERSION + case CG_FF_START: + CL_FF_Start( (ffHandle_t) args[1], (int) args[2] ); + return 0; + case CG_FF_STOP: + CL_FF_Stop( (ffHandle_t) args[1], (int) args[2] ); + return 0; + case CG_FF_STOPALL: + FF_StopAll(); + return 0; + case CG_FF_SHAKE: + FF_Shake( (int) args[1], (int) args[2] ); + return 0; + case CG_FF_REGISTER: + return FF_Register( (const char *) VMA(1), (int) args[2] ); + case CG_FF_ADDLOOPINGFORCE: + CL_FF_AddLoopingForce( (ffHandle_t) args[1], (int) args[2] ); + return 0; +#else case CG_FF_STARTFX: FFFX_START( (ffFX_e) args[1] ); return 0; @@ -518,6 +542,7 @@ int CL_CgameSystemCalls( int *args ) { case CG_FF_STOPALLFX: FFFX_STOPALL; return 0; +#endif // _IMMERSION case CG_R_LOADWORLDMAP: re.LoadWorld( (const char *) VMA(1) ); return 0; @@ -542,6 +567,8 @@ int CL_CgameSystemCalls( int *args ) { return 0; case CG_LANGUAGE_ISASIAN: return re.Language_IsAsian(); + case CG_LANGUAGE_USESSPACES: + return re.Language_UsesSpaces(); case CG_ANYLANGUAGE_READFROMSTRING: return re.AnyLanguage_ReadCharFromString( (const char **) args[1], (qboolean *) VMA(2) ); case CG_R_CLEARSCENE: diff --git a/code/client/cl_cin.cpp b/code/client/cl_cin.cpp index 7b7a4e4..da5f38b 100644 --- a/code/client/cl_cin.cpp +++ b/code/client/cl_cin.cpp @@ -903,7 +903,7 @@ static void readQuadInfo( byte *qData ) cinTable[currentHandle].drawY = 256; } if (cinTable[currentHandle].CIN_WIDTH != 256 || cinTable[currentHandle].CIN_HEIGHT != 256) { - Com_Printf("HACK: approxmimating cinematic for Rage Pro or Voodoo\n"); + Com_DPrintf("HACK: approxmimating cinematic for Rage Pro or Voodoo\n"); } } } @@ -1691,7 +1691,7 @@ static void PlayCinematic(const char *arg, const char *s, qboolean qbInGame) qbPlayingInGameCinematic = qbInGame; - if ((s && s[0] == '1') || Q_stricmp(arg,"end.roq")==0) { + if ((s && s[0] == '1') || Q_stricmp(arg,"video/end.roq")==0) { bits |= CIN_hold; } if (s && s[0] == '2') { @@ -1712,7 +1712,18 @@ static void PlayCinematic(const char *arg, const char *s, qboolean qbInGame) if (!stricmp(arg,"video/jk0101_sw.roq")) { psAudioFile = "music/cinematic_1"; - hCrawl = re.RegisterShader( va("menu/video/tc_%d",sp_language->integer) ); + if ( Cvar_VariableIntegerValue("com_demo") ) + { + hCrawl = re.RegisterShader( "menu/video/tc_demo" );//demo version of text crawl + } + else + { + hCrawl = re.RegisterShader( va("menu/video/tc_%d",sp_language->integer) ); + if (!hCrawl) + { + hCrawl = re.RegisterShader( "menu/video/tc_0" );//failed, so go back to english + } + } bits |= CIN_hold; } else diff --git a/code/client/cl_console.cpp b/code/client/cl_console.cpp index e11f9e6..95ec8ec 100644 --- a/code/client/cl_console.cpp +++ b/code/client/cl_console.cpp @@ -31,8 +31,8 @@ void Con_ToggleConsole_f (void) { return; } - Field_Clear( &g_consoleField ); - g_consoleField.widthInChars = g_console_field_width; + Field_Clear( &kg.g_consoleField ); + kg.g_consoleField.widthInChars = g_console_field_width; Con_ClearNotify (); @@ -83,7 +83,7 @@ void Con_Dump_f (void) if (Cmd_Argc() != 2) { - Com_Printf ("usage: condump \n"); + Com_Printf (SP_GetStringTextString("CON_TEXT_DUMP_USAGE")); return; } @@ -230,11 +230,11 @@ void Con_Init (void) { con_conspeed = Cvar_Get ("scr_conspeed", "3", 0); con_conAlpha= Cvar_Get( "conAlpha", "1.6", CVAR_ARCHIVE ); - Field_Clear( &g_consoleField ); - g_consoleField.widthInChars = g_console_field_width; + Field_Clear( &kg.g_consoleField ); + kg.g_consoleField.widthInChars = g_console_field_width; for ( i = 0 ; i < COMMAND_HISTORY ; i++ ) { - Field_Clear( &historyEditLines[i] ); - historyEditLines[i].widthInChars = g_console_field_width; + Field_Clear( &kg.historyEditLines[i] ); + kg.historyEditLines[i].widthInChars = g_console_field_width; } Cmd_AddCommand ("toggleconsole", Con_ToggleConsole_f); @@ -371,13 +371,13 @@ void Con_DrawInput (void) { return; } - y = con.vislines - ( SMALLCHAR_HEIGHT * 2 ); + y = con.vislines - ( SMALLCHAR_HEIGHT * (re.Language_IsAsian() ? 1.5 : 2) ); re.SetColor( con.color ); SCR_DrawSmallChar( con.xadjust + 1 * SMALLCHAR_WIDTH, y, ']' ); - Field_Draw( &g_consoleField, con.xadjust + 2 * SMALLCHAR_WIDTH, y, + Field_Draw( &kg.g_consoleField, con.xadjust + 2 * SMALLCHAR_WIDTH, y, SCREEN_WIDTH - 3 * SMALLCHAR_WIDTH, qtrue ); } @@ -413,19 +413,49 @@ void Con_DrawNotify (void) if (time > con_notifytime->value*1000) continue; text = con.text + (i % con.totallines)*con.linewidth; - - for (x = 0 ; x < con.linewidth ; x++) { - if ( ( text[x] & 0xff ) == ' ' ) { - continue; - } - if ( ( (text[x]>>8)&7 ) != currentColor ) { - currentColor = (text[x]>>8)&7; - re.SetColor( g_color_table[currentColor] ); - } - SCR_DrawSmallChar( con.xadjust + (x+1)*SMALLCHAR_WIDTH, v, text[x] & 0xff ); - } - v += SMALLCHAR_HEIGHT; + // asian language needs to use the new font system to print glyphs... + // + // (ignore colours since we're going to print the whole thing as one string) + // + if (re.Language_IsAsian()) + { + static int iFontIndex = re.RegisterFont("ocr_a"); // this seems naughty + const float fFontScale = 0.75f*con.yadjust; + const int iPixelHeightToAdvance = 2+(1.3/con.yadjust) * re.Font_HeightPixels(iFontIndex, fFontScale); // for asian spacing, since we don't want glyphs to touch. + + // concat the text to be printed... + // + char sTemp[4096]={0}; // ott + for (x = 0 ; x < con.linewidth ; x++) + { + if ( ( (text[x]>>8)&7 ) != currentColor ) { + currentColor = (text[x]>>8)&7; + strcat(sTemp,va("^%i", (text[x]>>8)&7) ); + } + strcat(sTemp,va("%c",text[x] & 0xFF)); + } + // + // and print... + // + re.Font_DrawString(con.xadjust*(con.xadjust + (1*SMALLCHAR_WIDTH/*aesthetics*/)), con.yadjust*(v), sTemp, g_color_table[currentColor], iFontIndex, -1, fFontScale); + + v += iPixelHeightToAdvance; + } + else + { + for (x = 0 ; x < con.linewidth ; x++) { + if ( ( text[x] & 0xff ) == ' ' ) { + continue; + } + if ( ( (text[x]>>8)&7 ) != currentColor ) { + currentColor = (text[x]>>8)&7; + re.SetColor( g_color_table[currentColor] ); + } + SCR_DrawSmallChar( con.xadjust + (x+1)*SMALLCHAR_WIDTH, v, text[x] & 0xff ); + } + v += SMALLCHAR_HEIGHT; + } } re.SetColor( NULL ); @@ -528,7 +558,20 @@ void Con_DrawSolidConsole( float frac ) currentColor = 7; re.SetColor( g_color_table[currentColor] ); - for (i=0 ; i>8)&7 ) != currentColor ) { - currentColor = (text[x]>>8)&7; - re.SetColor( g_color_table[currentColor] ); + // asian language needs to use the new font system to print glyphs... + // + // (ignore colours since we're going to print the whole thing as one string) + // + if (re.Language_IsAsian()) + { + // concat the text to be printed... + // + char sTemp[4096]={0}; // ott + for (x = 0 ; x < con.linewidth ; x++) + { + if ( ( (text[x]>>8)&7 ) != currentColor ) { + currentColor = (text[x]>>8)&7; + strcat(sTemp,va("^%i", (text[x]>>8)&7) ); + } + strcat(sTemp,va("%c",text[x] & 0xFF)); + } + // + // and print... + // + re.Font_DrawString(con.xadjust*(con.xadjust + (1*SMALLCHAR_WIDTH/*(aesthetics)*/)), con.yadjust*(y), sTemp, g_color_table[currentColor], iFontIndexForAsian, -1, fFontScaleForAsian); + } + else + { + for (x=0 ; x>8)&7 ) != currentColor ) { + currentColor = (text[x]>>8)&7; + re.SetColor( g_color_table[currentColor] ); + } + SCR_DrawSmallChar( con.xadjust + (x+1)*SMALLCHAR_WIDTH, y, text[x] & 0xff ); } - SCR_DrawSmallChar( con.xadjust + (x+1)*SMALLCHAR_WIDTH, y, text[x] & 0xff ); } } @@ -648,7 +717,7 @@ void Con_Bottom( void ) { void Con_Close( void ) { - Field_Clear( &g_consoleField ); + Field_Clear( &kg.g_consoleField ); Con_ClearNotify (); cls.keyCatchers &= ~KEYCATCH_CONSOLE; con.finalFrac = 0; // none visible diff --git a/code/client/cl_input.cpp b/code/client/cl_input.cpp index 8494e56..d61136b 100644 --- a/code/client/cl_input.cpp +++ b/code/client/cl_input.cpp @@ -486,7 +486,7 @@ void CL_CmdButtons( usercmd_t *cmd ) { // allow the game to know if any key at all is // currently pressed, even if it isn't bound to anything - if ( anykeydown && !cls.keyCatchers ) { + if ( kg.anykeydown && !cls.keyCatchers ) { cmd->buttons |= BUTTON_ANY; } } diff --git a/code/client/cl_keys.cpp b/code/client/cl_keys.cpp index 422d255..e6d8b96 100644 --- a/code/client/cl_keys.cpp +++ b/code/client/cl_keys.cpp @@ -12,537 +12,352 @@ key up events are sent even if in console mode */ -field_t historyEditLines[COMMAND_HISTORY]; -int nextHistoryLine; // the last line in the history buffer, not masked -int historyLine; // the line being displayed from history buffer - // will be <= nextHistoryLine - -field_t g_consoleField; field_t chatField; -qboolean key_overstrikeMode; qboolean key_wastab; // Hit tab once already? char keymatch_part[256]; char keymatch_last[256]; -qboolean anykeydown; -qkey_t keys[MAX_KEYS]; +keyGlobals_t kg; - -typedef struct { - char *name; - int keynum; -} keyname_t; - -// names not in this list can either be lowercase ascii, or '0xnn' hex sequences -keyname_t keynames[] = -{ - {"TAB", K_TAB}, - {"ENTER", K_ENTER}, - {"ESCAPE", K_ESCAPE}, - {"SPACE", K_SPACE}, - {"BACKSPACE", K_BACKSPACE}, - {"UPARROW", K_UPARROW}, - {"DOWNARROW", K_DOWNARROW}, - {"LEFTARROW", K_LEFTARROW}, - {"RIGHTARROW", K_RIGHTARROW}, - - {"ALT", K_ALT}, - {"CTRL", K_CTRL}, - {"SHIFT", K_SHIFT}, - - {"CAPSLOCK", K_CAPSLOCK}, - - {"F1", K_F1}, - {"F2", K_F2}, - {"F3", K_F3}, - {"F4", K_F4}, - {"F5", K_F5}, - {"F6", K_F6}, - {"F7", K_F7}, - {"F8", K_F8}, - {"F9", K_F9}, - {"F10", K_F10}, - {"F11", K_F11}, - {"F12", K_F12}, - - {"INS", K_INS}, - {"DEL", K_DEL}, - {"PGDN", K_PGDN}, - {"PGUP", K_PGUP}, - {"HOME", K_HOME}, - {"END", K_END}, - - {"MOUSE1", K_MOUSE1}, - {"MOUSE2", K_MOUSE2}, - {"MOUSE3", K_MOUSE3}, - {"MOUSE4", K_MOUSE4}, - {"MOUSE5", K_MOUSE5}, - - {"MWHEELUP", K_MWHEELUP }, - {"MWHEELDOWN", K_MWHEELDOWN }, - - {"JOY1", K_JOY1}, - {"JOY2", K_JOY2}, - {"JOY3", K_JOY3}, - {"JOY4", K_JOY4}, - {"JOY5", K_JOY5}, - {"JOY6", K_JOY6}, - {"JOY7", K_JOY7}, - {"JOY8", K_JOY8}, - {"JOY9", K_JOY9}, - {"JOY10", K_JOY10}, - {"JOY11", K_JOY11}, - {"JOY12", K_JOY12}, - {"JOY13", K_JOY13}, - {"JOY14", K_JOY14}, - {"JOY15", K_JOY15}, - {"JOY16", K_JOY16}, - {"JOY17", K_JOY17}, - {"JOY18", K_JOY18}, - {"JOY19", K_JOY19}, - {"JOY20", K_JOY20}, - {"JOY21", K_JOY21}, - {"JOY22", K_JOY22}, - {"JOY23", K_JOY23}, - {"JOY24", K_JOY24}, - {"JOY25", K_JOY25}, - {"JOY26", K_JOY26}, - {"JOY27", K_JOY27}, - {"JOY28", K_JOY28}, - {"JOY29", K_JOY29}, - {"JOY30", K_JOY30}, - {"JOY31", K_JOY31}, - {"JOY32", K_JOY32}, - - {"AUX1", K_AUX1}, - {"AUX2", K_AUX2}, - {"AUX3", K_AUX3}, - {"AUX4", K_AUX4}, - {"AUX5", K_AUX5}, - {"AUX6", K_AUX6}, - {"AUX7", K_AUX7}, - {"AUX8", K_AUX8}, - {"AUX9", K_AUX9}, - {"AUX10", K_AUX10}, - {"AUX11", K_AUX11}, - {"AUX12", K_AUX12}, - {"AUX13", K_AUX13}, - {"AUX14", K_AUX14}, - {"AUX15", K_AUX15}, - {"AUX16", K_AUX16}, - - {"KP_HOME", K_KP_HOME }, - {"KP_UPARROW", K_KP_UPARROW }, - {"KP_PGUP", K_KP_PGUP }, - {"KP_LEFTARROW", K_KP_LEFTARROW }, - {"KP_5", K_KP_5 }, - {"KP_RIGHTARROW", K_KP_RIGHTARROW }, - {"KP_END", K_KP_END }, - {"KP_DOWNARROW", K_KP_DOWNARROW }, - {"KP_PGDN", K_KP_PGDN }, - {"KP_ENTER", K_KP_ENTER }, - {"KP_INS", K_KP_INS }, - {"KP_DEL", K_KP_DEL }, - {"KP_SLASH", K_KP_SLASH }, - {"KP_MINUS", K_KP_MINUS }, - {"KP_PLUS", K_KP_PLUS }, - {"KP_NUMLOCK", K_KP_NUMLOCK }, - {"KP_STAR", K_KP_STAR }, - {"KP_EQUALS", K_KP_EQUALS }, - - {"PAUSE", K_PAUSE}, - - {"SEMICOLON", ';'}, // because a raw semicolon seperates commands - - {"COMMAND", K_COMMAND}, //mac - - {NULL,0} +// do NOT blithely change any of the key names (3rd field) here, since they have to match the key binds +// in the CFG files, they're also prepended with "KEYNAME_" when looking up StripEd references +// +keyname_t keynames[MAX_KEYS] = +{ + { 0x00, 0x00, NULL, A_NULL, false }, + { 0x01, 0x01, "SHIFT", A_SHIFT, false }, + { 0x02, 0x02, "CTRL", A_CTRL, false }, + { 0x03, 0x03, "ALT", A_ALT, false }, + { 0x04, 0x04, "CAPSLOCK", A_CAPSLOCK, false }, + { 0x05, 0x05, "KP_NUMLOCK", A_NUMLOCK, false }, + { 0x06, 0x06, "SCROLLLOCK", A_SCROLLLOCK, false }, + { 0x07, 0x07, "PAUSE", A_PAUSE, false }, + { 0x08, 0x08, "BACKSPACE", A_BACKSPACE, false }, + { 0x09, 0x09, "TAB", A_TAB, false }, + { 0x0a, 0x0a, "ENTER", A_ENTER, false }, + { 0x0b, 0x0b, "KP_PLUS", A_KP_PLUS, false }, + { 0x0c, 0x0c, "KP_MINUS", A_KP_MINUS, false }, + { 0x0d, 0x0d, "KP_ENTER", A_KP_ENTER, false }, + { 0x0e, 0x0e, "KP_DEL", A_KP_PERIOD, false }, + { 0x0f, 0x0f, NULL, A_PRINTSCREEN, false }, + { 0x10, 0x10, "KP_INS", A_KP_0, false }, + { 0x11, 0x11, "KP_END", A_KP_1, false }, + { 0x12, 0x12, "KP_DOWNARROW", A_KP_2, false }, + { 0x13, 0x13, "KP_PGDN", A_KP_3, false }, + { 0x14, 0x14, "KP_LEFTARROW", A_KP_4, false }, + { 0x15, 0x15, "KP_5", A_KP_5, false }, + { 0x16, 0x16, "KP_RIGHTARROW", A_KP_6, false }, + { 0x17, 0x17, "KP_HOME", A_KP_7, false }, + { 0x18, 0x18, "KP_UPARROW", A_KP_8, false }, + { 0x19, 0x19, "KP_PGUP", A_KP_9, false }, + { 0x1a, 0x1a, "CONSOLE", A_CONSOLE, false }, + { 0x1b, 0x1b, "ESCAPE", A_ESCAPE, false }, + { 0x1c, 0x1c, "F1", A_F1, true }, + { 0x1d, 0x1d, "F2", A_F2, true }, + { 0x1e, 0x1e, "F3", A_F3, true }, + { 0x1f, 0x1f, "F4", A_F4, true }, + + { 0x20, 0x20, "SPACE", A_SPACE, false }, + { (word)'!', (word)'!', NULL, A_PLING, false }, + { (word)'"', (word)'"', NULL, A_DOUBLE_QUOTE, false }, + { (word)'#', (word)'#', NULL, A_HASH, false }, + { (word)'$', (word)'$', NULL, A_STRING, false }, + { (word)'%', (word)'%', NULL, A_PERCENT, false }, + { (word)'&', (word)'&', NULL, A_AND, false }, + { 0x27, 0x27, NULL, A_SINGLE_QUOTE, false }, + { (word)'(', (word)'(', NULL, A_OPEN_BRACKET, false }, + { (word)')', (word)')', NULL, A_CLOSE_BRACKET, false }, + { (word)'*', (word)'*', NULL, A_STAR, false }, + { (word)'+', (word)'+', NULL, A_PLUS, false }, + { (word)',', (word)',', NULL, A_COMMA, false }, + { (word)'-', (word)'-', NULL, A_MINUS, false }, + { (word)'.', (word)'.', NULL, A_PERIOD, false }, + { (word)'/', (word)'/', NULL, A_FORWARD_SLASH, false }, + { (word)'0', (word)'0', NULL, A_0, false }, + { (word)'1', (word)'1', NULL, A_1, false }, + { (word)'2', (word)'2', NULL, A_2, false }, + { (word)'3', (word)'3', NULL, A_3, false }, + { (word)'4', (word)'4', NULL, A_4, false }, + { (word)'5', (word)'5', NULL, A_5, false }, + { (word)'6', (word)'6', NULL, A_6, false }, + { (word)'7', (word)'7', NULL, A_7, false }, + { (word)'8', (word)'8', NULL, A_8, false }, + { (word)'9', (word)'9', NULL, A_9, false }, + { (word)':', (word)':', NULL, A_COLON, false }, + { (word)';', (word)';', "SEMICOLON", A_SEMICOLON, false }, + { (word)'<', (word)'<', NULL, A_LESSTHAN, false }, + { (word)'=', (word)'=', NULL, A_EQUALS, false }, + { (word)'>', (word)'>', NULL, A_GREATERTHAN, false }, + { (word)'?', (word)'?', NULL, A_QUESTION, false }, + + { (word)'@', (word)'@', NULL, A_AT, false }, + { (word)'A', (word)'a', NULL, A_CAP_A, false }, + { (word)'B', (word)'b', NULL, A_CAP_B, false }, + { (word)'C', (word)'c', NULL, A_CAP_C, false }, + { (word)'D', (word)'d', NULL, A_CAP_D, false }, + { (word)'E', (word)'e', NULL, A_CAP_E, false }, + { (word)'F', (word)'f', NULL, A_CAP_F, false }, + { (word)'G', (word)'g', NULL, A_CAP_G, false }, + { (word)'H', (word)'h', NULL, A_CAP_H, false }, + { (word)'I', (word)'i', NULL, A_CAP_I, false }, + { (word)'J', (word)'j', NULL, A_CAP_J, false }, + { (word)'K', (word)'k', NULL, A_CAP_K, false }, + { (word)'L', (word)'l', NULL, A_CAP_L, false }, + { (word)'M', (word)'m', NULL, A_CAP_M, false }, + { (word)'N', (word)'n', NULL, A_CAP_N, false }, + { (word)'O', (word)'o', NULL, A_CAP_O, false }, + { (word)'P', (word)'p', NULL, A_CAP_P, false }, + { (word)'Q', (word)'q', NULL, A_CAP_Q, false }, + { (word)'R', (word)'r', NULL, A_CAP_R, false }, + { (word)'S', (word)'s', NULL, A_CAP_S, false }, + { (word)'T', (word)'t', NULL, A_CAP_T, false }, + { (word)'U', (word)'u', NULL, A_CAP_U, false }, + { (word)'V', (word)'v', NULL, A_CAP_V, false }, + { (word)'W', (word)'w', NULL, A_CAP_W, false }, + { (word)'X', (word)'x', NULL, A_CAP_X, false }, + { (word)'Y', (word)'y', NULL, A_CAP_Y, false }, + { (word)'Z', (word)'z', NULL, A_CAP_Z, false }, + { (word)'[', (word)'[', NULL, A_OPEN_SQUARE, false }, + { 0x5c, 0x5c, NULL, A_BACKSLASH, false }, + { (word)']', (word)']', NULL, A_CLOSE_SQUARE, false }, + { (word)'^', (word)'^', NULL, A_CARET, false }, + { (word)'_', (word)'_', NULL, A_UNDERSCORE, false }, + + { 0x60, 0x60, NULL, A_LEFT_SINGLE_QUOTE, false }, + { (word)'A', (word)'a', NULL, A_LOW_A, false }, + { (word)'B', (word)'b', NULL, A_LOW_B, false }, + { (word)'C', (word)'c', NULL, A_LOW_C, false }, + { (word)'D', (word)'d', NULL, A_LOW_D, false }, + { (word)'E', (word)'e', NULL, A_LOW_E, false }, + { (word)'F', (word)'f', NULL, A_LOW_F, false }, + { (word)'G', (word)'g', NULL, A_LOW_G, false }, + { (word)'H', (word)'h', NULL, A_LOW_H, false }, + { (word)'I', (word)'i', NULL, A_LOW_I, false }, + { (word)'J', (word)'j', NULL, A_LOW_J, false }, + { (word)'K', (word)'k', NULL, A_LOW_K, false }, + { (word)'L', (word)'l', NULL, A_LOW_L, false }, + { (word)'M', (word)'m', NULL, A_LOW_M, false }, + { (word)'N', (word)'n', NULL, A_LOW_N, false }, + { (word)'O', (word)'o', NULL, A_LOW_O, false }, + { (word)'P', (word)'p', NULL, A_LOW_P, false }, + { (word)'Q', (word)'q', NULL, A_LOW_Q, false }, + { (word)'R', (word)'r', NULL, A_LOW_R, false }, + { (word)'S', (word)'s', NULL, A_LOW_S, false }, + { (word)'T', (word)'t', NULL, A_LOW_T, false }, + { (word)'U', (word)'u', NULL, A_LOW_U, false }, + { (word)'V', (word)'v', NULL, A_LOW_V, false }, + { (word)'W', (word)'w', NULL, A_LOW_W, false }, + { (word)'X', (word)'x', NULL, A_LOW_X, false }, + { (word)'Y', (word)'y', NULL, A_LOW_Y, false }, + { (word)'Z', (word)'z', NULL, A_LOW_Z, false }, + { (word)'{', (word)'{', NULL, A_OPEN_BRACE, false }, + { (word)'|', (word)'|', NULL, A_BAR, false }, + { (word)'}', (word)'}', NULL, A_CLOSE_BRACE, false }, + { (word)'~', (word)'~', NULL, A_TILDE, false }, + { 0x7f, 0x7f, "DEL", A_DELETE, false }, + + { 0x80, 0x80, "EURO", A_EURO, false }, + { 0x81, 0x81, "SHIFT", A_SHIFT2, false }, + { 0x82, 0x82, "CTRL", A_CTRL2, false }, + { 0x83, 0x83, "ALT", A_ALT2, false }, + { 0x84, 0x84, "F5", A_F5, true }, + { 0x85, 0x85, "F6", A_F6, true }, + { 0x86, 0x86, "F7", A_F7, true }, + { 0x87, 0x87, "F8", A_F8, true }, + { 0x88, 0x88, "CIRCUMFLEX", A_CIRCUMFLEX, false }, + { 0x89, 0x89, "MWHEELUP", A_MWHEELUP, false }, + { 0x8a, 0x9a, NULL, A_CAP_SCARON, false }, // ****** + { 0x8b, 0x8b, "MWHEELDOWN", A_MWHEELDOWN, false }, + { 0x8c, 0x9c, NULL, A_CAP_OE, false }, // ****** + { 0x8d, 0x8d, "MOUSE1", A_MOUSE1, false }, + { 0x8e, 0x8e, "MOUSE2", A_MOUSE2, false }, + { 0x8f, 0x8f, "INS", A_INSERT, false }, + { 0x90, 0x90, "HOME", A_HOME, false }, + { 0x91, 0x91, "PGUP", A_PAGE_UP, false }, + { 0x92, 0x92, NULL, A_RIGHT_SINGLE_QUOTE, false }, + { 0x93, 0x93, NULL, A_LEFT_DOUBLE_QUOTE, false }, + { 0x94, 0x94, NULL, A_RIGHT_DOUBLE_QUOTE, false }, + { 0x95, 0x95, "F9", A_F9, true }, + { 0x96, 0x96, "F10", A_F10, true }, + { 0x97, 0x97, "F11", A_F11, true }, + { 0x98, 0x98, "F12", A_F12, true }, + { 0x99, 0x99, NULL, A_TRADEMARK, false }, + { 0x8a, 0x9a, NULL, A_LOW_SCARON, false }, // ****** + { 0x9b, 0x9b, "SHIFT_ENTER", A_ENTER, false }, + { 0x8c, 0x9c, NULL, A_LOW_OE, false }, // ****** + { 0x9d, 0x9d, "END", A_END, false }, + { 0x9e, 0x9e, "PGDN", A_PAGE_DOWN, false }, + { 0x9f, 0xff, NULL, A_CAP_YDIERESIS, false }, // ****** + + { 0xa0, 0, "SHIFT_SPACE", A_SPACE, false }, + { 0xa1, 0xa1, NULL, A_EXCLAMDOWN, false }, // upside down '!' - undisplayable + { (word)(byte)'¢', (word)(byte)'¢', NULL, A_CENT, false }, + { (word)(byte)'£', (word)(byte)'£', NULL, A_POUND, false }, + { 0xa4, 0, "SHIFT_KP_ENTER", A_KP_ENTER, false }, + { (word)(byte)'¥', (word)(byte)'¥', NULL, A_YEN, false }, + { 0xa6, 0xa6, "MOUSE3", A_MOUSE3, false }, + { 0xa7, 0xa7, "MOUSE4", A_MOUSE4, false }, + { 0xa8, 0xa8, "MOUSE5", A_MOUSE5, false }, + { (word)(byte)'©', (word)(byte)'©', NULL, A_COPYRIGHT, false }, + { 0xaa, 0xaa, "UPARROW", A_CURSOR_UP, false }, + { 0xab, 0xab, "DOWNARROW", A_CURSOR_DOWN, false }, + { 0xac, 0xac, "LEFTARROW", A_CURSOR_LEFT, false }, + { 0xad, 0xad, "RIGHTARROW", A_CURSOR_RIGHT, false }, + { (word)(byte)'®', (word)(byte)'®', NULL, A_REGISTERED, false }, + { 0xaf, 0, NULL, A_UNDEFINED_7, false }, + { 0xb0, 0, NULL, A_UNDEFINED_8, false }, + { 0xb1, 0, NULL, A_UNDEFINED_9, false }, + { 0xb2, 0, NULL, A_UNDEFINED_10, false }, + { 0xb3, 0, NULL, A_UNDEFINED_11, false }, + { 0xb4, 0, NULL, A_UNDEFINED_12, false }, + { 0xb5, 0, NULL, A_UNDEFINED_13, false }, + { 0xb6, 0, NULL, A_UNDEFINED_14, false }, + { 0xb7, 0, NULL, A_UNDEFINED_15, false }, + { 0xb8, 0, NULL, A_UNDEFINED_16, false }, + { 0xb9, 0, NULL, A_UNDEFINED_17, false }, + { 0xba, 0, NULL, A_UNDEFINED_18, false }, + { 0xbb, 0, NULL, A_UNDEFINED_19, false }, + { 0xbc, 0, NULL, A_UNDEFINED_20, false }, + { 0xbd, 0, NULL, A_UNDEFINED_21, false }, + { 0xbe, 0, NULL, A_UNDEFINED_22, false }, + { (word)(byte)'¿', (word)(byte)'¿', NULL, A_QUESTION_DOWN, false }, + + { (word)(byte)'À', (word)(byte)'à', NULL, A_CAP_AGRAVE, false }, + { (word)(byte)'Á', (word)(byte)'á', NULL, A_CAP_AACUTE, false }, + { (word)(byte)'Â', (word)(byte)'â', NULL, A_CAP_ACIRCUMFLEX, false }, + { (word)(byte)'Ã', (word)(byte)'ã', NULL, A_CAP_ATILDE, false }, + { (word)(byte)'Ä', (word)(byte)'ä', NULL, A_CAP_ADIERESIS, false }, + { (word)(byte)'Å', (word)(byte)'å', NULL, A_CAP_ARING, false }, + { (word)(byte)'Æ', (word)(byte)'æ', NULL, A_CAP_AE, false }, + { (word)(byte)'Ç', (word)(byte)'ç', NULL, A_CAP_CCEDILLA, false }, + { (word)(byte)'È', (word)(byte)'è', NULL, A_CAP_EGRAVE, false }, + { (word)(byte)'É', (word)(byte)'é', NULL, A_CAP_EACUTE, false }, + { (word)(byte)'Ê', (word)(byte)'ê', NULL, A_CAP_ECIRCUMFLEX, false }, + { (word)(byte)'Ë', (word)(byte)'ë', NULL, A_CAP_EDIERESIS, false }, + { (word)(byte)'Ì', (word)(byte)'ì', NULL, A_CAP_IGRAVE, false }, + { (word)(byte)'Í', (word)(byte)'í', NULL, A_CAP_IACUTE, false }, + { (word)(byte)'Î', (word)(byte)'î', NULL, A_CAP_ICIRCUMFLEX, false }, + { (word)(byte)'Ï', (word)(byte)'ï', NULL, A_CAP_IDIERESIS, false }, + { (word)(byte)'Ð', (word)(byte)'ð', NULL, A_CAP_ETH, false }, + { (word)(byte)'Ñ', (word)(byte)'ñ', NULL, A_CAP_NTILDE, false }, + { (word)(byte)'Ò', (word)(byte)'ò', NULL, A_CAP_OGRAVE, false }, + { (word)(byte)'Ó', (word)(byte)'ó', NULL, A_CAP_OACUTE, false }, + { (word)(byte)'Ô', (word)(byte)'ô', NULL, A_CAP_OCIRCUMFLEX, false }, + { (word)(byte)'Õ', (word)(byte)'õ', NULL, A_CAP_OTILDE, false }, + { (word)(byte)'Ö', (word)(byte)'ö', NULL, A_CAP_ODIERESIS, false }, + { (word)(byte)'×', (word)(byte)'×', "KP_STAR", A_MULTIPLY, false }, + { (word)(byte)'Ø', (word)(byte)'ø', NULL, A_CAP_OSLASH, false }, + { (word)(byte)'Ù', (word)(byte)'ù', NULL, A_CAP_UGRAVE, false }, + { (word)(byte)'Ú', (word)(byte)'ú', NULL, A_CAP_UACUTE, false }, + { (word)(byte)'Û', (word)(byte)'û', NULL, A_CAP_UCIRCUMFLEX, false }, + { (word)(byte)'Ü', (word)(byte)'ü', NULL, A_CAP_UDIERESIS, false }, + { (word)(byte)'Ý', (word)(byte)'ý', NULL, A_CAP_YACUTE, false }, + { (word)(byte)'Þ', (word)(byte)'þ', NULL, A_CAP_THORN, false }, + { (word)(byte)'ß', (word)(byte)'ß', NULL, A_GERMANDBLS, false }, + + { (word)(byte)'À', (word)(byte)'à', NULL, A_LOW_AGRAVE, false }, + { (word)(byte)'Á', (word)(byte)'á', NULL, A_LOW_AACUTE, false }, + { (word)(byte)'Â', (word)(byte)'â', NULL, A_LOW_ACIRCUMFLEX, false }, + { (word)(byte)'Ã', (word)(byte)'ã', NULL, A_LOW_ATILDE, false }, + { (word)(byte)'Ä', (word)(byte)'ä', NULL, A_LOW_ADIERESIS, false }, + { (word)(byte)'Å', (word)(byte)'å', NULL, A_LOW_ARING, false }, + { (word)(byte)'Æ', (word)(byte)'æ', NULL, A_LOW_AE, false }, + { (word)(byte)'Ç', (word)(byte)'ç', NULL, A_LOW_CCEDILLA, false }, + { (word)(byte)'È', (word)(byte)'è', NULL, A_LOW_EGRAVE, false }, + { (word)(byte)'É', (word)(byte)'é', NULL, A_LOW_EACUTE, false }, + { (word)(byte)'Ê', (word)(byte)'ê', NULL, A_LOW_ECIRCUMFLEX, false }, + { (word)(byte)'Ë', (word)(byte)'ë', NULL, A_LOW_EDIERESIS, false }, + { (word)(byte)'Ì', (word)(byte)'ì', NULL, A_LOW_IGRAVE, false }, + { (word)(byte)'Í', (word)(byte)'í', NULL, A_LOW_IACUTE, false }, + { (word)(byte)'Î', (word)(byte)'î', NULL, A_LOW_ICIRCUMFLEX, false }, + { (word)(byte)'Ï', (word)(byte)'ï', NULL, A_LOW_IDIERESIS, false }, + { (word)(byte)'Ð', (word)(byte)'ð', NULL, A_LOW_ETH, false }, + { (word)(byte)'Ñ', (word)(byte)'ñ', NULL, A_LOW_NTILDE, false }, + { (word)(byte)'Ò', (word)(byte)'ò', NULL, A_LOW_OGRAVE, false }, + { (word)(byte)'Ó', (word)(byte)'ó', NULL, A_LOW_OACUTE, false }, + { (word)(byte)'Ô', (word)(byte)'ô', NULL, A_LOW_OCIRCUMFLEX, false }, + { (word)(byte)'Õ', (word)(byte)'õ', NULL, A_LOW_OTILDE, false }, + { (word)(byte)'Ö', (word)(byte)'ö', NULL, A_LOW_ODIERESIS, false }, + { (word)(byte)'÷', (word)(byte)'÷', "KP_SLASH", A_DIVIDE, false }, + { (word)(byte)'Ø', (word)(byte)'ø', NULL, A_LOW_OSLASH, false }, + { (word)(byte)'Ù', (word)(byte)'ù', NULL, A_LOW_UGRAVE, false }, + { (word)(byte)'Ú', (word)(byte)'ú', NULL, A_LOW_UACUTE, false }, + { (word)(byte)'Û', (word)(byte)'û', NULL, A_LOW_UCIRCUMFLEX, false }, + { (word)(byte)'Ü', (word)(byte)'ü', NULL, A_LOW_UDIERESIS, false }, + { (word)(byte)'Ý', (word)(byte)'ý', NULL, A_LOW_YACUTE, false }, + { (word)(byte)'Þ', (word)(byte)'þ', NULL, A_LOW_THORN, false }, + { 0x9f, 0xff, NULL, A_LOW_YDIERESIS, false }, // ******* + + { 0x100, 0x100, "JOY0", A_JOY0, false }, + { 0x101, 0x101, "JOY1", A_JOY1, false }, + { 0x102, 0x102, "JOY2", A_JOY2, false }, + { 0x103, 0x103, "JOY3", A_JOY3, false }, + { 0x104, 0x104, "JOY4", A_JOY4, false }, + { 0x105, 0x105, "JOY5", A_JOY5, false }, + { 0x106, 0x106, "JOY6", A_JOY6, false }, + { 0x107, 0x107, "JOY7", A_JOY7, false }, + { 0x108, 0x108, "JOY8", A_JOY8, false }, + { 0x109, 0x109, "JOY9", A_JOY9, false }, + { 0x10a, 0x10a, "JOY10", A_JOY10, false }, + { 0x10b, 0x10b, "JOY11", A_JOY11, false }, + { 0x10c, 0x10c, "JOY12", A_JOY12, false }, + { 0x10d, 0x10d, "JOY13", A_JOY13, false }, + { 0x10e, 0x10e, "JOY14", A_JOY14, false }, + { 0x10f, 0x10f, "JOY15", A_JOY15, false }, + { 0x110, 0x110, "JOY16", A_JOY16, false }, + { 0x111, 0x111, "JOY17", A_JOY17, false }, + { 0x112, 0x112, "JOY18", A_JOY18, false }, + { 0x113, 0x113, "JOY19", A_JOY19, false }, + { 0x114, 0x114, "JOY20", A_JOY20, false }, + { 0x115, 0x115, "JOY21", A_JOY21, false }, + { 0x116, 0x116, "JOY22", A_JOY22, false }, + { 0x117, 0x117, "JOY23", A_JOY23, false }, + { 0x118, 0x118, "JOY24", A_JOY24, false }, + { 0x119, 0x119, "JOY25", A_JOY25, false }, + { 0x11a, 0x11a, "JOY26", A_JOY26, false }, + { 0x11b, 0x11b, "JOY27", A_JOY27, false }, + { 0x11c, 0x11c, "JOY28", A_JOY28, false }, + { 0x11d, 0x11d, "JOY29", A_JOY29, false }, + { 0x11e, 0x11e, "JOY30", A_JOY30, false }, + { 0x11f, 0x11f, "JOY31", A_JOY31, false }, + + { 0x120, 0x120, "AUX0", A_AUX0, false }, + { 0x121, 0x121, "AUX1", A_AUX1, false }, + { 0x122, 0x122, "AUX2", A_AUX2, false }, + { 0x123, 0x123, "AUX3", A_AUX3, false }, + { 0x124, 0x124, "AUX4", A_AUX4, false }, + { 0x125, 0x125, "AUX5", A_AUX5, false }, + { 0x126, 0x126, "AUX6", A_AUX6, false }, + { 0x127, 0x127, "AUX7", A_AUX7, false }, + { 0x128, 0x128, "AUX8", A_AUX8, false }, + { 0x129, 0x129, "AUX9", A_AUX9, false }, + { 0x12a, 0x12a, "AUX10", A_AUX10, false }, + { 0x12b, 0x12b, "AUX11", A_AUX11, false }, + { 0x12c, 0x12c, "AUX12", A_AUX12, false }, + { 0x12d, 0x12d, "AUX13", A_AUX13, false }, + { 0x12e, 0x12e, "AUX14", A_AUX14, false }, + { 0x12f, 0x12f, "AUX15", A_AUX15, false }, + { 0x130, 0x130, "AUX16", A_AUX16, false }, + { 0x131, 0x131, "AUX17", A_AUX17, false }, + { 0x132, 0x132, "AUX18", A_AUX18, false }, + { 0x133, 0x133, "AUX19", A_AUX19, false }, + { 0x134, 0x134, "AUX20", A_AUX20, false }, + { 0x135, 0x135, "AUX21", A_AUX21, false }, + { 0x136, 0x136, "AUX22", A_AUX22, false }, + { 0x137, 0x137, "AUX23", A_AUX23, false }, + { 0x138, 0x138, "AUX24", A_AUX24, false }, + { 0x139, 0x139, "AUX25", A_AUX25, false }, + { 0x13a, 0x13a, "AUX26", A_AUX26, false }, + { 0x13b, 0x13b, "AUX27", A_AUX27, false }, + { 0x13c, 0x13c, "AUX28", A_AUX28, false }, + { 0x13d, 0x13d, "AUX29", A_AUX29, false }, + { 0x13e, 0x13e, "AUX30", A_AUX30, false }, + { 0x13f, 0x13f, "AUX31", A_AUX31, false } }; -//english printed keynames, for when we want what's printed to be different -//from the "technical" bind label -keyname_t keynames_e[] = -{ - {"TAB", K_TAB}, - {"ENTER", K_ENTER}, - {"ESCAPE", K_ESCAPE}, - {"SPACE", K_SPACE}, - {"BACKSPACE", K_BACKSPACE}, - {"UP", K_UPARROW}, - {"DOWN", K_DOWNARROW}, - {"LEFT", K_LEFTARROW}, - {"RIGHT", K_RIGHTARROW}, - {"ALT", K_ALT}, - {"CTRL", K_CTRL}, - {"SHIFT", K_SHIFT}, - - {"COMMAND", K_COMMAND}, - - {"CAPSLOCK", K_CAPSLOCK}, - - - {"F1", K_F1}, - {"F2", K_F2}, - {"F3", K_F3}, - {"F4", K_F4}, - {"F5", K_F5}, - {"F6", K_F6}, - {"F7", K_F7}, - {"F8", K_F8}, - {"F9", K_F9}, - {"F10", K_F10}, - {"F11", K_F11}, - {"F12", K_F12}, - - {"INS", K_INS}, - {"DEL", K_DEL}, - {"PGDN", K_PGDN}, - {"PGUP", K_PGUP}, - {"HOME", K_HOME}, - {"END", K_END}, - - {"MOUSE1", K_MOUSE1}, - {"MOUSE2", K_MOUSE2}, - {"MOUSE3", K_MOUSE3}, - {"MOUSE4", K_MOUSE4}, - {"MOUSE5", K_MOUSE5}, - - {"MWHEELUP", K_MWHEELUP }, - {"MWHEELDOWN", K_MWHEELDOWN }, - - {"JOY1", K_JOY1}, - {"JOY2", K_JOY2}, - {"JOY3", K_JOY3}, - {"JOY4", K_JOY4}, - {"JOY5", K_JOY5}, - {"JOY6", K_JOY6}, - {"JOY7", K_JOY7}, - {"JOY8", K_JOY8}, - {"JOY9", K_JOY9}, - {"JOY10", K_JOY10}, - {"JOY11", K_JOY11}, - {"JOY12", K_JOY12}, - {"JOY13", K_JOY13}, - {"JOY14", K_JOY14}, - {"JOY15", K_JOY15}, - {"JOY16", K_JOY16}, - {"JOY17", K_JOY17}, - {"JOY18", K_JOY18}, - {"JOY19", K_JOY19}, - {"JOY20", K_JOY20}, - {"JOY21", K_JOY21}, - {"JOY22", K_JOY22}, - {"JOY23", K_JOY23}, - {"JOY24", K_JOY24}, - {"JOY25", K_JOY25}, - {"JOY26", K_JOY26}, - {"JOY27", K_JOY27}, - {"JOY28", K_JOY28}, - {"JOY29", K_JOY29}, - {"JOY30", K_JOY30}, - {"JOY31", K_JOY31}, - {"JOY32", K_JOY32}, - - {"AUX1", K_AUX1}, - {"AUX2", K_AUX2}, - {"AUX3", K_AUX3}, - {"AUX4", K_AUX4}, - {"AUX5", K_AUX5}, - {"AUX6", K_AUX6}, - {"AUX7", K_AUX7}, - {"AUX8", K_AUX8}, - {"AUX9", K_AUX9}, - {"AUX10", K_AUX10}, - {"AUX11", K_AUX11}, - {"AUX12", K_AUX12}, - {"AUX13", K_AUX13}, - {"AUX14", K_AUX14}, - {"AUX15", K_AUX15}, - {"AUX16", K_AUX16}, - - {"KP_HOME", K_KP_HOME }, - {"KP_UP", K_KP_UPARROW }, - {"KP_PGUP", K_KP_PGUP }, - {"KP_LEFT", K_KP_LEFTARROW }, - {"KP_5", K_KP_5 }, - {"KP_RIGHT", K_KP_RIGHTARROW }, - {"KP_END", K_KP_END }, - {"KP_DOWN", K_KP_DOWNARROW }, - {"KP_PGDN", K_KP_PGDN }, - {"KP_ENTER", K_KP_ENTER }, - {"KP_INS", K_KP_INS }, - {"KP_DEL", K_KP_DEL }, - {"KP_SLASH", K_KP_SLASH }, - {"KP_MINUS", K_KP_MINUS }, - {"KP_PLUS", K_KP_PLUS }, - {"KP_NUMLOCK", K_KP_NUMLOCK }, - {"KP_STAR", K_KP_STAR }, - {"KP_EQUALS", K_KP_EQUALS }, - - {"PAUSE", K_PAUSE}, - - {"SEMICOLON", ';'}, // because a raw semicolon seperates commands - - {NULL,0} -}; - -keyname_t keynames_d[] = //deutsch -{ - {"TAB", K_TAB}, - {"EINGABETASTE", K_ENTER}, - {"ESC", K_ESCAPE}, - {"LEERTASTE", K_SPACE}, - {"RÜCKTASTE", K_BACKSPACE}, - {"PFEILT.AUF", K_UPARROW}, - {"PFEILT.UNTEN", K_DOWNARROW}, - {"PFEILT.LINKS", K_LEFTARROW}, - {"PFEILT.RECHTS", K_RIGHTARROW}, - - {"ALT", K_ALT}, - {"STRG", K_CTRL}, - {"UMSCHALT", K_SHIFT}, - - {"FESTSTELLT", K_CAPSLOCK}, - - {"F1", K_F1}, - {"F2", K_F2}, - {"F3", K_F3}, - {"F4", K_F4}, - {"F5", K_F5}, - {"F6", K_F6}, - {"F7", K_F7}, - {"F8", K_F8}, - {"F9", K_F9}, - {"F10", K_F10}, - {"F11", K_F11}, - {"F12", K_F12}, - - {"EINFG", K_INS}, - {"ENTF", K_DEL}, - {"BILD-AB", K_PGDN}, - {"BILD-AUF", K_PGUP}, - {"POS1", K_HOME}, - {"ENDE", K_END}, - - {"MAUS1", K_MOUSE1}, - {"MAUS2", K_MOUSE2}, - {"MAUS3", K_MOUSE3}, - {"MAUS4", K_MOUSE4}, - {"MAUS5", K_MOUSE5}, - - {"MRADOBEN", K_MWHEELUP }, - {"MRADUNTEN", K_MWHEELDOWN }, - - {"JOY1", K_JOY1}, - {"JOY2", K_JOY2}, - {"JOY3", K_JOY3}, - {"JOY4", K_JOY4}, - {"JOY5", K_JOY5}, - {"JOY6", K_JOY6}, - {"JOY7", K_JOY7}, - {"JOY8", K_JOY8}, - {"JOY9", K_JOY9}, - {"JOY10", K_JOY10}, - {"JOY11", K_JOY11}, - {"JOY12", K_JOY12}, - {"JOY13", K_JOY13}, - {"JOY14", K_JOY14}, - {"JOY15", K_JOY15}, - {"JOY16", K_JOY16}, - {"JOY17", K_JOY17}, - {"JOY18", K_JOY18}, - {"JOY19", K_JOY19}, - {"JOY20", K_JOY20}, - {"JOY21", K_JOY21}, - {"JOY22", K_JOY22}, - {"JOY23", K_JOY23}, - {"JOY24", K_JOY24}, - {"JOY25", K_JOY25}, - {"JOY26", K_JOY26}, - {"JOY27", K_JOY27}, - {"JOY28", K_JOY28}, - {"JOY29", K_JOY29}, - {"JOY30", K_JOY30}, - {"JOY31", K_JOY31}, - {"JOY32", K_JOY32}, - - {"AUX1", K_AUX1}, - {"AUX2", K_AUX2}, - {"AUX3", K_AUX3}, - {"AUX4", K_AUX4}, - {"AUX5", K_AUX5}, - {"AUX6", K_AUX6}, - {"AUX7", K_AUX7}, - {"AUX8", K_AUX8}, - {"AUX9", K_AUX9}, - {"AUX10", K_AUX10}, - {"AUX11", K_AUX11}, - {"AUX12", K_AUX12}, - {"AUX13", K_AUX13}, - {"AUX14", K_AUX14}, - {"AUX15", K_AUX15}, - {"AUX16", K_AUX16}, - - {"ZB_POS1", K_KP_HOME }, - {"ZB_PFEILT.AUF", K_KP_UPARROW }, - {"ZB_BILD-AUF", K_KP_PGUP }, - {"ZB_PFEILT.LINKS", K_KP_LEFTARROW }, - {"ZB_5", K_KP_5 }, - {"ZB_PFEILT.RECHTS",K_KP_RIGHTARROW }, - {"ZB_ENDE", K_KP_END }, - {"ZB_PFEILT.UNTEN", K_KP_DOWNARROW }, - {"ZB_BILD-AB", K_KP_PGDN }, - {"ZB_ENTER", K_KP_ENTER }, - {"ZB_EINFG", K_KP_INS }, - {"ZB_ENTF", K_KP_DEL }, - {"ZB_SLASH", K_KP_SLASH }, - {"ZB_MINUS", K_KP_MINUS }, - {"ZB_PLUS", K_KP_PLUS }, - {"ZB_NUM", K_KP_NUMLOCK }, - {"ZB_*", K_KP_STAR }, - {"ZB_EQUALS", K_KP_EQUALS }, - - {"PAUSE", K_PAUSE}, - - {"COMMAND", K_COMMAND}, //mac - {NULL,0} -}; //end german - -keyname_t keynames_f[] = //french -{ - {"TAB", K_TAB}, - {"ENTREE", K_ENTER}, - {"ECHAP", K_ESCAPE}, - {"ESPACE", K_SPACE}, - {"RETOUR", K_BACKSPACE}, - {"HAUT", K_UPARROW}, - {"BAS", K_DOWNARROW}, - {"GAUCHE", K_LEFTARROW}, - {"DROITE", K_RIGHTARROW}, - - {"ALT", K_ALT}, - {"CTRL", K_CTRL}, - {"MAJ", K_SHIFT}, - - {"VERRMAJ", K_CAPSLOCK}, - - {"F1", K_F1}, - {"F2", K_F2}, - {"F3", K_F3}, - {"F4", K_F4}, - {"F5", K_F5}, - {"F6", K_F6}, - {"F7", K_F7}, - {"F8", K_F8}, - {"F9", K_F9}, - {"F10", K_F10}, - {"F11", K_F11}, - {"F12", K_F12}, - - {"INSER", K_INS}, - {"SUPPR", K_DEL}, - {"PGBAS", K_PGDN}, - {"PGHAUT", K_PGUP}, - {"ORIGINE", K_HOME}, - {"FIN", K_END}, - - {"SOURIS1", K_MOUSE1}, - {"SOURIS2", K_MOUSE2}, - {"SOURIS3", K_MOUSE3}, - {"SOURIS4", K_MOUSE4}, - {"SOURIS5", K_MOUSE5}, - - {"MOLETTEHT.", K_MWHEELUP }, - {"MOLETTEBAS", K_MWHEELDOWN }, - - {"JOY1", K_JOY1}, - {"JOY2", K_JOY2}, - {"JOY3", K_JOY3}, - {"JOY4", K_JOY4}, - {"JOY5", K_JOY5}, - {"JOY6", K_JOY6}, - {"JOY7", K_JOY7}, - {"JOY8", K_JOY8}, - {"JOY9", K_JOY9}, - {"JOY10", K_JOY10}, - {"JOY11", K_JOY11}, - {"JOY12", K_JOY12}, - {"JOY13", K_JOY13}, - {"JOY14", K_JOY14}, - {"JOY15", K_JOY15}, - {"JOY16", K_JOY16}, - {"JOY17", K_JOY17}, - {"JOY18", K_JOY18}, - {"JOY19", K_JOY19}, - {"JOY20", K_JOY20}, - {"JOY21", K_JOY21}, - {"JOY22", K_JOY22}, - {"JOY23", K_JOY23}, - {"JOY24", K_JOY24}, - {"JOY25", K_JOY25}, - {"JOY26", K_JOY26}, - {"JOY27", K_JOY27}, - {"JOY28", K_JOY28}, - {"JOY29", K_JOY29}, - {"JOY30", K_JOY30}, - {"JOY31", K_JOY31}, - {"JOY32", K_JOY32}, - - {"AUX1", K_AUX1}, - {"AUX2", K_AUX2}, - {"AUX3", K_AUX3}, - {"AUX4", K_AUX4}, - {"AUX5", K_AUX5}, - {"AUX6", K_AUX6}, - {"AUX7", K_AUX7}, - {"AUX8", K_AUX8}, - {"AUX9", K_AUX9}, - {"AUX10", K_AUX10}, - {"AUX11", K_AUX11}, - {"AUX12", K_AUX12}, - {"AUX13", K_AUX13}, - {"AUX14", K_AUX14}, - {"AUX15", K_AUX15}, - {"AUX16", K_AUX16}, - - {"PN_ORIGINE", K_KP_HOME }, - {"PN_HAUT", K_KP_UPARROW }, - {"PN_PGBAS", K_KP_PGUP }, - {"PN_GAUCHE", K_KP_LEFTARROW }, - {"PN_5", K_KP_5 }, - {"PN_DROITE", K_KP_RIGHTARROW }, - {"PN_FIN", K_KP_END }, - {"PN_BAS", K_KP_DOWNARROW }, - {"PN_PGBAS", K_KP_PGDN }, - {"PN_ENTR", K_KP_ENTER }, - {"PN_INSER", K_KP_INS }, - {"PN_SUPPR", K_KP_DEL }, - {"PN_SLASH", K_KP_SLASH }, - {"PN_MOINS", K_KP_MINUS }, - {"PN_PLUS", K_KP_PLUS }, - {"PN_VERRNUM", K_KP_NUMLOCK }, - {"PN_*", K_KP_STAR }, - {"PN_EQUALS", K_KP_EQUALS }, - - {"PAUSE", K_PAUSE}, - - {"COMMAND", K_COMMAND}, //mac - - {"POINT-VIRGULE", ';' }, // because a raw semicolon seperates commands - - {NULL,0} -}; //end french - -/* -============================================================================= - -EDIT FIELDS - -============================================================================= -*/ /* @@ -615,7 +430,7 @@ void Field_VariableSizeDraw( field_t *edit, int x, int y, int width, int size, q return; // off blink } - if ( key_overstrikeMode ) { + if ( kg.key_overstrikeMode ) { cursorChar = 11; } else { cursorChar = 10; @@ -677,14 +492,15 @@ void Field_KeyDownEvent( field_t *edit, int key ) { int len; // shift-insert is paste - if ( ( ( key == K_INS ) || ( key == K_KP_INS ) ) && keys[K_SHIFT].down ) { + if ( ( key == A_INSERT ) && kg.keys[A_SHIFT].down ) + { Field_Paste( edit ); return; } len = strlen( edit->buffer ); - if ( key == K_DEL ) { + if ( key == A_DELETE ) { if ( edit->cursor < len ) { memmove( edit->buffer + edit->cursor, edit->buffer + edit->cursor + 1, len - edit->cursor ); @@ -692,7 +508,7 @@ void Field_KeyDownEvent( field_t *edit, int key ) { return; } - if ( key == K_RIGHTARROW ) + if ( key == A_CURSOR_RIGHT ) { if ( edit->cursor < len ) { edit->cursor++; @@ -704,7 +520,7 @@ void Field_KeyDownEvent( field_t *edit, int key ) { return; } - if ( key == K_LEFTARROW ) + if ( key == A_CURSOR_LEFT ) { if ( edit->cursor > 0 ) { edit->cursor--; @@ -716,18 +532,21 @@ void Field_KeyDownEvent( field_t *edit, int key ) { return; } - if ( key == K_HOME || ( tolower(key) == 'a' && keys[K_CTRL].down ) ) { + if ( key == A_HOME || ( keynames[key].lower == 'a' && kg.keys[A_CTRL].down ) ) + { edit->cursor = 0; return; } - if ( key == K_END || ( tolower(key) == 'e' && keys[K_CTRL].down ) ) { + if ( key == A_END || ( keynames[key].lower == 'e' && kg.keys[A_CTRL].down ) ) + { edit->cursor = len; return; } - if ( key == K_INS ) { - key_overstrikeMode = !key_overstrikeMode; + if ( key == A_INSERT ) + { + kg.key_overstrikeMode = !kg.key_overstrikeMode; return; } } @@ -784,7 +603,7 @@ void Field_CharEvent( field_t *edit, int ch ) { return; } - if ( key_overstrikeMode ) { + if ( kg.key_overstrikeMode ) { if ( edit->cursor == MAX_EDIT_LINE - 1 ) return; edit->buffer[edit->cursor] = ch; @@ -843,7 +662,7 @@ void CompleteCommand( void ) field_t *edit; static qboolean checking_cmd; - edit = &g_consoleField; + edit = &kg.g_consoleField; if (key_wastab) { @@ -917,7 +736,7 @@ Handles history and console scrollback */ void Console_Key (int key) { // ctrl-L clears screen - if ( key == 'l' && keys[K_CTRL].down ) { + if ( keynames[ key ].lower == 'l' && kg.keys[A_CTRL].down ) { Cbuf_AddText ("clear\n"); key_wastab = qfalse; // For double tabbing on a cvar return; @@ -929,18 +748,18 @@ void Console_Key (int key) { } */ // enter finishes the line - if ( key == K_ENTER || key == K_KP_ENTER ) { - Cbuf_AddText( g_consoleField.buffer ); // valid command + if ( key == A_ENTER || key == A_KP_ENTER ) { + Cbuf_AddText( kg.g_consoleField.buffer ); // valid command Cbuf_AddText ("\n"); - Com_Printf ( "]%s\n", g_consoleField.buffer ); + Com_Printf ( "]%s\n", kg.g_consoleField.buffer ); // copy line to history buffer - historyEditLines[nextHistoryLine % COMMAND_HISTORY] = g_consoleField; - nextHistoryLine++; - historyLine = nextHistoryLine; + kg.historyEditLines[kg.nextHistoryLine % COMMAND_HISTORY] = kg.g_consoleField; + kg.nextHistoryLine++; + kg.historyLine = kg.nextHistoryLine; - Field_Clear( &g_consoleField ); - g_consoleField.widthInChars = g_console_field_width; + Field_Clear( &kg.g_consoleField ); + kg.g_consoleField.widthInChars = g_console_field_width; if ( cls.state == CA_DISCONNECTED ) { SCR_UpdateScreen (); // force an update, because the command } // may take some time @@ -950,7 +769,7 @@ void Console_Key (int key) { // command completion - if (key == K_TAB) { + if (key == A_TAB) { CompleteCommand(); return; } @@ -959,52 +778,52 @@ void Console_Key (int key) { // command history (ctrl-p ctrl-n for unix style) - if ( ( key == K_UPARROW ) || ( key == K_KP_UPARROW ) || - ( ( tolower(key) == 'p' ) && keys[K_CTRL].down ) ) + if ( ( key == A_CURSOR_UP ) || ( ( keynames[ key ].lower == 'p' ) && kg.keys[A_CTRL].down ) ) { - if ( nextHistoryLine - historyLine < COMMAND_HISTORY - && historyLine > 0 ) { - historyLine--; + if ( kg.nextHistoryLine - kg.historyLine < COMMAND_HISTORY && kg.historyLine > 0 ) + { + kg.historyLine--; } - g_consoleField = historyEditLines[ historyLine % COMMAND_HISTORY ]; + kg.g_consoleField = kg.historyEditLines[ kg.historyLine % COMMAND_HISTORY ]; return; } - if ( ( key == K_DOWNARROW ) || ( key == K_KP_DOWNARROW ) || - ( ( tolower(key) == 'n' ) && keys[K_CTRL].down ) ) + if ( ( key == A_CURSOR_DOWN ) || ( ( keynames[ key ].lower == 'n' ) && kg.keys[A_CTRL].down ) ) { - if (historyLine == nextHistoryLine) + if (kg.historyLine == kg.nextHistoryLine) return; - historyLine++; - g_consoleField = historyEditLines[ historyLine % COMMAND_HISTORY ]; + kg.historyLine++; + kg.g_consoleField = kg.historyEditLines[ kg.historyLine % COMMAND_HISTORY ]; return; } // console scrolling - if ( key == K_PGUP ) { + if ( key == A_PAGE_UP ) { Con_PageUp(); return; } - if ( key == K_PGDN ) { + if ( key == A_PAGE_DOWN ) { Con_PageDown(); return; } // ctrl-home = top of console - if ( key == K_HOME && keys[K_CTRL].down ) { + if ( key == A_HOME && kg.keys[A_CTRL].down ) + { Con_Top(); return; } // ctrl-end = bottom of console - if ( key == K_END && keys[K_CTRL].down ) { + if ( key == A_END && kg.keys[A_CTRL].down ) + { Con_Bottom(); return; } // pass to the normal editline routine - Field_KeyDownEvent( &g_consoleField, key ); + Field_KeyDownEvent( &kg.g_consoleField, key ); } //============================================================================ @@ -1020,13 +839,13 @@ In game talk message void Message_Key( int key ) { char buffer[MAX_STRING_CHARS]; - if (key == K_ESCAPE) { + if (key == A_ESCAPE) { cls.keyCatchers &= ~KEYCATCH_MESSAGE; Field_Clear( &chatField ); return; } - if ( key == K_ENTER || key == K_KP_ENTER ) + if ( key == A_ENTER || key == A_KP_ENTER ) { if ( chatField.buffer[0] && cls.state == CA_ACTIVE ) { Com_sprintf( buffer, sizeof( buffer ), "say \"%s\"\n", chatField.buffer ); @@ -1045,12 +864,12 @@ void Message_Key( int key ) { qboolean Key_GetOverstrikeMode( void ) { - return key_overstrikeMode; + return kg.key_overstrikeMode; } void Key_SetOverstrikeMode( qboolean state ) { - key_overstrikeMode = state; + kg.key_overstrikeMode = state; } @@ -1064,7 +883,7 @@ qboolean Key_IsDown( int keynum ) { return qfalse; } - return keys[keynum].down; + return kg.keys[ keynames[keynum].upper ].down; } @@ -1081,49 +900,154 @@ to be configured even if they don't have defined names. =================== */ int Key_StringToKeynum( char *str ) { - keyname_t *kn; + int i; - if ( !str || !str[0] ) { + if ( !str || !str[0] ) + { return -1; } - if ( !str[1] ) { - return str[0]; + // If single char bind, presume ascii char bind + if ( !str[1] ) + { + return keynames[ (unsigned char)str[0] ].upper; + } + + // scan for a text match + for ( i = 0 ; i < MAX_KEYS ; i++ ) + { + if ( keynames[i].name && !stricmp( str, keynames[i].name ) ) + { + return keynames[i].keynum; + } } // check for hex code - if ( str[0] == '0' && str[1] == 'x' && strlen( str ) == 4) { + if ( str[0] == '0' && str[1] == 'x' && strlen( str ) == 4) + { int n1, n2; n1 = str[2]; - if ( n1 >= '0' && n1 <= '9' ) { + if ( n1 >= '0' && n1 <= '9' ) + { n1 -= '0'; - } else if ( n1 >= 'a' && n1 <= 'f' ) { - n1 = n1 - 'a' + 10; - } else { + } + else if ( n1 >= 'A' && n1 <= 'F' ) + { + n1 = n1 - 'A' + 10; + } + else + { n1 = 0; } n2 = str[3]; - if ( n2 >= '0' && n2 <= '9' ) { + if ( n2 >= '0' && n2 <= '9' ) + { n2 -= '0'; - } else if ( n2 >= 'a' && n2 <= 'f' ) { - n2 = n2 - 'a' + 10; - } else { + } + else if ( n2 >= 'A' && n2 <= 'F' ) + { + n2 = n2 - 'A' + 10; + } + else + { n2 = 0; } - return n1 * 16 + n2; } - // scan for a text match - for ( kn=keynames ; kn->name ; kn++ ) { - if ( !Q_stricmp( str,kn->name ) ) - return kn->keynum; - } - return -1; } + +static char tinyString[16]; +static const char *Key_KeynumValid( int keynum ) +{ + if ( keynum == -1 ) + { + return ""; + } + if ( keynum < 0 || keynum >= MAX_KEYS ) + { + return ""; + } + return NULL; +} + +static const char *Key_KeyToName( int keynum ) +{ + return keynames[keynum].name; +} + + +static const char *Key_KeyToAscii( int keynum ) +{ + if(!keynames[keynum].lower) + { + return(NULL); + } + if(keynum == A_SPACE) + { + tinyString[0] = (char)A_SHIFT_SPACE; + } + else if(keynum == A_ENTER) + { + tinyString[0] = (char)A_SHIFT_ENTER; + } + else if(keynum == A_KP_ENTER) + { + tinyString[0] = (char)A_SHIFT_KP_ENTER; + } + else + { + tinyString[0] = keynames[keynum].upper; + } + tinyString[1] = 0; + return tinyString; +} + +static const char *Key_KeyToHex( int keynum ) +{ + int i, j; + + i = keynum >> 4; + j = keynum & 15; + + tinyString[0] = '0'; + tinyString[1] = 'x'; + tinyString[2] = i > 9 ? i - 10 + 'A' : i + '0'; + tinyString[3] = j > 9 ? j - 10 + 'A' : j + '0'; + tinyString[4] = 0; + + return tinyString; +} + +// Returns the ascii code of the keynum +const char *Key_KeynumToAscii( int keynum ) +{ + const char *name; + + name = Key_KeynumValid(keynum); + + // check for printable ascii + if ( !name && keynum > 0 && keynum < 256 ) + { + name = Key_KeyToAscii(keynum); + } + // Check for name (for JOYx and AUXx buttons) + if ( !name ) + { + name = Key_KeyToName(keynum); + } + // Fallback to hex number + if ( !name ) + { + name = Key_KeyToHex(keynum); + } + return name; +} + + /* =================== Key_KeynumToString @@ -1132,62 +1056,29 @@ Returns a string (either a single ascii char, a K_* name, or a 0x11 hex string) given keynum. =================== */ -char *Key_KeynumToString( int keynum, qboolean bTranslate ) { //note: translate is only called for menu display not configs - keyname_t *kn; - static char tinystr[5]; - int i, j; +// Returns a console/config file friendly name for the key +const char *Key_KeynumToString( int keynum ) +{ + const char *name; - if ( keynum == -1 ) { - return ""; + name = Key_KeynumValid(keynum); + + // Check for friendly name + if ( !name ) + { + name = Key_KeyToName(keynum); } - - if ( keynum < 0 || keynum > 255 ) { - return ""; + // check for printable ascii + if ( !name && keynum > 0 && keynum < 256) + { + name = Key_KeyToAscii(keynum); } - - // check for printable ascii (don't use quote) - if ( keynum > 32 && keynum < 127 && keynum != '"' ) { - tinystr[0] = keynum; - tinystr[1] = 0; - if (keynum == ';' && !bTranslate) { - //fall through and use keyname table - } else { - return tinystr; - } + // Fallback to hex number + if ( !name ) + { + name = Key_KeyToHex(keynum); } - - - kn=keynames; //init to english - if (bTranslate) { - if ( sp_language->integer == SP_LANGUAGE_GERMAN ) { - kn=keynames_d; //use german - } else if ( sp_language->integer == SP_LANGUAGE_FRENCH ) { - kn=keynames_f; //use french - } - else //rww - this is actually English and doesn't need to be "translated". - { //however, certain key names are too long to display right, this does the trick. - kn=keynames_e; - } - } - - // check for a key string - for ( ; kn->name ; kn++ ) { - if (keynum == kn->keynum) { - return kn->name; - } - } - - // make a hex string - i = keynum >> 4; - j = keynum & 15; - - tinystr[0] = '0'; - tinystr[1] = 'x'; - tinystr[2] = i > 9 ? i - 10 + 'a' : i + '0'; - tinystr[3] = j > 9 ? j - 10 + 'a' : j + '0'; - tinystr[4] = 0; - - return tinystr; + return name; } @@ -1202,12 +1093,16 @@ void Key_SetBinding( int keynum, const char *binding ) { } // free old bindings - if ( keys[ keynum ].binding ) { - Z_Free( keys[ keynum ].binding ); + if ( kg.keys[ keynames[keynum].upper ].binding ) { + Z_Free( kg.keys[ keynames[keynum].upper ].binding ); + kg.keys[ keynames[keynum].upper ].binding = NULL; } // allocate memory for new binding - keys[keynum].binding = CopyString( binding ); + if (binding) + { + kg.keys[ keynames[keynum].upper ].binding = CopyString( binding ); + } // consider this like modifying an archived cvar, so the // file write will be triggered at the next oportunity @@ -1225,8 +1120,8 @@ char *Key_GetBinding( int keynum ) { return ""; } - assert (keynum < (sizeof(keys)/sizeof(keys[0]))); - return keys[ keynum ].binding; + assert (keynum < (sizeof(kg.keys)/sizeof(kg.keys[0]))); + return kg.keys[ keynum ].binding; } @@ -1264,9 +1159,13 @@ void Key_Unbindall_f (void) { int i; - for (i=0 ; i<256 ; i++) - if (keys[i].binding) + for (i = 0; i < MAX_KEYS ; i++) + { + if (kg.keys[i].binding) + { Key_SetBinding (i, ""); + } + } } @@ -1296,8 +1195,8 @@ void Key_Bind_f (void) if (c == 2) { - if (keys[b].binding) - Com_Printf ("\"%s\" = \"%s\"\n", Cmd_Argv(1), keys[b].binding ); + if (kg.keys[b].binding) + Com_Printf ("\"%s\" = \"%s\"\n", Cmd_Argv(1), kg.keys[b].binding ); else Com_Printf ("\"%s\" is not bound\n", Cmd_Argv(1) ); return; @@ -1326,9 +1225,9 @@ void Key_WriteBindings( fileHandle_t f ) { int i; FS_Printf (f, "unbindall\n" ); - for (i=0 ; i<256 ; i++) { - if (keys[i].binding && keys[i].binding[0] ) { - FS_Printf (f, "bind %s \"%s\"\n", Key_KeynumToString(i, qfalse), keys[i].binding); + for (i=0 ; i= 200) { - Com_Printf ("%s is unbound, use controls menu to set.\n" - , Key_KeynumToString( key, qfalse ) ); - } - } else if (kb[0] == '+') { - // button commands add keynum and time as parms so that multiple - // sources can be discriminated and subframe corrected - Com_sprintf (cmd, sizeof(cmd), "%s %i %i\n", kb, key, time); - Cbuf_AddText (cmd); - } else { - // down-only command - Cbuf_AddText (kb); - Cbuf_AddText ("\n"); - } + CL_ActionEvent(key, true, time); } } @@ -1515,7 +1431,7 @@ void CL_CharEvent( int key ) { // distribute the key down event to the apropriate handler if ( cls.keyCatchers & KEYCATCH_CONSOLE ) { - Field_CharEvent( &g_consoleField, key ); + Field_CharEvent( &kg.g_consoleField, key ); } else if ( cls.keyCatchers & KEYCATCH_UI ) { @@ -1527,7 +1443,7 @@ void CL_CharEvent( int key ) { } else if ( cls.state == CA_DISCONNECTED ) { - Field_CharEvent( &g_consoleField, key ); + Field_CharEvent( &kg.g_consoleField, key ); } } @@ -1541,14 +1457,15 @@ void Key_ClearStates (void) { int i; - anykeydown = qfalse; + kg.anykeydown = qfalse; + kg.keyDownCount = 0; for ( i=0 ; i < MAX_KEYS ; i++ ) { - if ( keys[i].down ) { + if ( kg.keys[i].down ) { CL_KeyEvent( i, qfalse, 0 ); } - keys[i].down = 0; - keys[i].repeats = 0; + kg.keys[i].down = 0; + kg.keys[i].repeats = 0; } } diff --git a/code/client/cl_main.cpp b/code/client/cl_main.cpp index 87b531a..3937db3 100644 --- a/code/client/cl_main.cpp +++ b/code/client/cl_main.cpp @@ -8,7 +8,12 @@ #include "client.h" #include "client_ui.h" #include +#ifdef _IMMERSION +#include "../ff/ff.h" +#include "../ff/cl_ff.h" +#else #include "fffx.h" +#endif // _IMMERSION #include "../ghoul2/g2.h" #define RETRANSMIT_TIMEOUT 3000 // time between connection packet retransmits @@ -156,6 +161,10 @@ void CL_FlushMemory( void ) { cls.soundRegistered = qfalse; cls.rendererStarted = qfalse; +#ifdef _IMMERSION + CL_ShutdownFF(); + cls.forceStarted = qfalse; +#endif // _IMMERSION } /* @@ -409,6 +418,10 @@ void CL_Vid_Restart_f( void ) { cls.cgameStarted = qfalse; cls.soundRegistered = qfalse; +#ifdef _IMMERSION + CL_ShutdownFF(); + cls.forceStarted = qfalse; +#endif // _IMMERSION // unpause so the cgame definately gets a snapshot and renders a frame Cvar_Set( "cl_paused", "0" ); } @@ -440,6 +453,34 @@ void CL_Snd_Restart_f( void ) { extern void AS_ParseSets(void); AS_ParseSets(); } +#ifdef _IMMERSION +/* +================= +CL_FF_Restart_f +================= +*/ +void CL_FF_Restart_f( void ) { + + if ( FF_IsInitialized() ) + { + // Apply cvar changes w/o losing registered effects + // Allows changing devices in-game without restarting the map + if ( !FF_Init() ) + FF_Shutdown(); // error (shouldn't happen) + } + else if ( cls.state >= CA_PRIMED ) // maybe > CA_DISCONNECTED + { + // Restart map or menu + CL_Vid_Restart_f(); + } + else if ( cls.uiStarted ) + { + // Restart menu + CL_ShutdownUI(); + cls.forceStarted = qfalse; + } +} +#endif // _IMMERSION /* ================== CL_Configstrings_f @@ -521,7 +562,7 @@ void CL_CheckForResend( void ) { case CA_CHALLENGING: // sending back the challenge - port = Cvar_VariableValue ("qport"); + port = Cvar_VariableIntegerValue("qport"); UI_UpdateConnectionString( va("(%i)", clc.connectPacketCount ) ); @@ -629,7 +670,7 @@ void CL_ConnectionlessPacket( netadr_t from, msg_t *msg ) { NET_AdrToString( clc.serverAddress ) ); return; } - Netchan_Setup (NS_CLIENT, &clc.netchan, from, Cvar_VariableValue( "qport" ) ); + Netchan_Setup (NS_CLIENT, &clc.netchan, from, Cvar_VariableIntegerValue( "qport" ) ); cls.state = CA_CONNECTED; clc.lastPacketSentTime = -9999; // send first packet immediately return; @@ -877,6 +918,9 @@ void CL_Frame ( int msec,float fractionMsec ) { // update audio S_Update(); +#ifdef _IMMERSION + FF_Update(); +#endif // _IMMERSION // advance local effects for next frame SCR_RunCinematic(); @@ -952,7 +996,12 @@ void CL_StartHunkUsers( void ) { cls.whiteShader = re.RegisterShader( "white" ); cls.consoleShader = re.RegisterShader( "console" ); g_console_field_width = cls.glconfig.vidWidth / SMALLCHAR_WIDTH - 2; - g_consoleField.widthInChars = g_console_field_width; + kg.g_consoleField.widthInChars = g_console_field_width; +#ifndef _IMMERSION + //------- + // The latest Immersion Force Feedback system initializes here, not through + // win32 input system. Therefore, the window handle is valid :) + //------- // now that the renderer has started up we know that the global hWnd is now valid, // so we can now go ahead and (re)setup the input stuff that needs hWnds for DI... @@ -965,6 +1014,7 @@ void CL_StartHunkUsers( void ) { extern void Sys_In_Restart_f( void ); Sys_In_Restart_f(); } +#endif // _IMMERSION } if ( !cls.soundStarted ) { @@ -977,6 +1027,12 @@ void CL_StartHunkUsers( void ) { S_BeginRegistration(); } +#ifdef _IMMERSION + if ( !cls.forceStarted ) { + cls.forceStarted = qtrue; + CL_InitFF(); + } +#endif // _IMMERSION if ( !cls.uiStarted ) { cls.uiStarted = qtrue; CL_InitUI(); @@ -1066,7 +1122,10 @@ CL_Init void CL_Init( void ) { Com_Printf( "----- Client Initialization -----\n" ); - Con_Init (); + SP_Register("con_text", SP_REGISTER_REQUIRED); //reference is CON_TEXT + SP_Register("keynames", SP_REGISTER_REQUIRED); // reference is KEYNAMES + + Con_Init (); CL_ClearState (); @@ -1150,6 +1209,9 @@ void CL_Init( void ) { Cmd_AddCommand ("uimenu", CL_GenericMenu_f); Cmd_AddCommand ("datapad", CL_DataPad_f); Cmd_AddCommand ("endscreendissolve", CL_EndScreenDissolve_f); +#ifdef _IMMERSION + Cmd_AddCommand ("ff_restart", CL_FF_Restart_f); +#endif // _IMMERSION CL_InitRef(); @@ -1192,6 +1254,9 @@ void CL_Shutdown( void ) { S_Shutdown(); CL_ShutdownRef(); +#ifdef _IMMERSION + CL_ShutdownFF(); +#endif // _IMMERSION Cmd_RemoveCommand ("cmd"); Cmd_RemoveCommand ("configstrings"); Cmd_RemoveCommand ("clientinfo"); diff --git a/code/client/cl_parse.cpp b/code/client/cl_parse.cpp index 46b7e52..3e23663 100644 --- a/code/client/cl_parse.cpp +++ b/code/client/cl_parse.cpp @@ -324,6 +324,13 @@ void CL_SystemInfoChanged( void ) { Cvar_Set( key, value ); } + extern cvar_t *s_language; + if ( ( Q_stricmp( "DEUTSCH", s_language->string ) == 0 )//voice language is German + || (sp_language->integer == SP_LANGUAGE_GERMAN )//text language is German + || Cvar_VariableIntegerValue("ui_iscensored") == 1 ) + { + Cvar_Set( "g_dismemberment", "0"); + } } void UI_UpdateConnectionString( char *string ); diff --git a/code/client/cl_ui.cpp b/code/client/cl_ui.cpp index 7afdcfa..1e31a40 100644 --- a/code/client/cl_ui.cpp +++ b/code/client/cl_ui.cpp @@ -69,8 +69,18 @@ static void GetClipboardData( char *buf, int buflen ) { Key_KeynumToStringBuf ==================== */ -void Key_KeynumToStringBuf( int keynum, char *buf, int buflen ) { - Q_strncpyz( buf, Key_KeynumToString( keynum, qtrue ), buflen ); +// only ever called by binding-display code, therefore returns non-technical "friendly" names +// in any language that don't necessarily match those in the config file... +// +void Key_KeynumToStringBuf( int keynum, char *buf, int buflen ) +{ + const char *psKeyName = Key_KeynumToString( keynum/*, qtrue */); + + // see if there's a more friendly (or localised) name... + // + const char *psKeyNameFriendly = SP_GetStringTextString( va("KEYNAMES_KEYNAME_%s",psKeyName) ); + + Q_strncpyz( buf, (psKeyNameFriendly && psKeyNameFriendly[0]) ? psKeyNameFriendly : psKeyName, buflen ); } /* @@ -190,6 +200,8 @@ CL_InitUI void CL_InitUI( void ) { uiimport_t uii; + SP_Register("keynames", 0/*SP_REGISTER_REQUIRED*/); // reference is KEYNAMES + memset( &uii, 0, sizeof( uii ) ); uii.Printf = Com_Printf; @@ -229,6 +241,7 @@ void CL_InitUI( void ) { uii.R_Font_HeightPixels = re.Font_HeightPixels; uii.R_Font_DrawString = re.Font_DrawString; uii.Language_IsAsian = re.Language_IsAsian; + uii.Language_UsesSpaces = re.Language_UsesSpaces; uii.AnyLanguage_ReadCharFromString = re.AnyLanguage_ReadCharFromString; uii.SG_GetSaveImage = SG_GetSaveImage; diff --git a/code/client/client.h b/code/client/client.h index 53e235d..5721061 100644 --- a/code/client/client.h +++ b/code/client/client.h @@ -192,6 +192,9 @@ typedef struct { qboolean soundRegistered; qboolean uiStarted; qboolean cgameStarted; +#ifdef _IMMERSION + qboolean forceStarted; +#endif // _IMMERSION int framecount; int frametime; // msec since last frame @@ -327,7 +330,7 @@ void CL_WritePacket( void ); void IN_CenterView (void); float CL_KeyState (kbutton_t *key); -char *Key_KeynumToString( int keynum, qboolean bTranslate ); //note: translate is only called for menu display not configs +const char *Key_KeynumToString( int keynum/*, qboolean bTranslate*/ ); //note: translate is only called for menu display not configs // // cl_parse.c diff --git a/code/client/keycodes.h b/code/client/keycodes.h index 03d030d..8d0f171 100644 --- a/code/client/keycodes.h +++ b/code/client/keycodes.h @@ -1,136 +1,342 @@ #ifndef __KEYCODES_H__ #define __KEYCODES_H__ -// -// these are the key numbers that should be passed to CL_KeyEvent -// +// these are the key numbers that should be passed to KeyEvent -// normal keys should be passed as lowercased ascii +typedef enum +{ + A_NULL = 0, + A_SHIFT, + A_CTRL, + A_ALT, + A_CAPSLOCK, + A_NUMLOCK, + A_SCROLLLOCK, + A_PAUSE, + A_BACKSPACE, + A_TAB, + A_ENTER, + A_KP_PLUS, + A_KP_MINUS, + A_KP_ENTER, + A_KP_PERIOD, + A_PRINTSCREEN, + A_KP_0, + A_KP_1, + A_KP_2, + A_KP_3, + A_KP_4, + A_KP_5, + A_KP_6, + A_KP_7, + A_KP_8, + A_KP_9, + A_CONSOLE, + A_ESCAPE, + A_F1, + A_F2, + A_F3, + A_F4, -typedef enum { - K_TAB = 9, - K_ENTER = 13, - K_ESCAPE = 27, - K_SPACE = 32, + A_SPACE, + A_PLING, + A_DOUBLE_QUOTE, + A_HASH, + A_STRING, + A_PERCENT, + A_AND, + A_SINGLE_QUOTE, + A_OPEN_BRACKET, + A_CLOSE_BRACKET, + A_STAR, + A_PLUS, + A_COMMA, + A_MINUS, + A_PERIOD, + A_FORWARD_SLASH, + A_0, + A_1, + A_2, + A_3, + A_4, + A_5, + A_6, + A_7, + A_8, + A_9, + A_COLON, + A_SEMICOLON, + A_LESSTHAN, + A_EQUALS, + A_GREATERTHAN, + A_QUESTION, - K_BACKSPACE = 127, + A_AT, + A_CAP_A, + A_CAP_B, + A_CAP_C, + A_CAP_D, + A_CAP_E, + A_CAP_F, + A_CAP_G, + A_CAP_H, + A_CAP_I, + A_CAP_J, + A_CAP_K, + A_CAP_L, + A_CAP_M, + A_CAP_N, + A_CAP_O, + A_CAP_P, + A_CAP_Q, + A_CAP_R, + A_CAP_S, + A_CAP_T, + A_CAP_U, + A_CAP_V, + A_CAP_W, + A_CAP_X, + A_CAP_Y, + A_CAP_Z, + A_OPEN_SQUARE, + A_BACKSLASH, + A_CLOSE_SQUARE, + A_CARET, + A_UNDERSCORE, - K_COMMAND = 128, - K_CAPSLOCK, - K_POWER, - K_PAUSE, + A_LEFT_SINGLE_QUOTE, + A_LOW_A, + A_LOW_B, + A_LOW_C, + A_LOW_D, + A_LOW_E, + A_LOW_F, + A_LOW_G, + A_LOW_H, + A_LOW_I, + A_LOW_J, + A_LOW_K, + A_LOW_L, + A_LOW_M, + A_LOW_N, + A_LOW_O, + A_LOW_P, + A_LOW_Q, + A_LOW_R, + A_LOW_S, + A_LOW_T, + A_LOW_U, + A_LOW_V, + A_LOW_W, + A_LOW_X, + A_LOW_Y, + A_LOW_Z, + A_OPEN_BRACE, + A_BAR, + A_CLOSE_BRACE, + A_TILDE, + A_DELETE, - K_UPARROW, - K_DOWNARROW, - K_LEFTARROW, - K_RIGHTARROW, + A_EURO, + A_SHIFT2, + A_CTRL2, + A_ALT2, + A_F5, + A_F6, + A_F7, + A_F8, + A_CIRCUMFLEX, + A_MWHEELUP, + A_CAP_SCARON, + A_MWHEELDOWN, + A_CAP_OE, + A_MOUSE1, + A_MOUSE2, + A_INSERT, + A_HOME, + A_PAGE_UP, + A_RIGHT_SINGLE_QUOTE, + A_LEFT_DOUBLE_QUOTE, + A_RIGHT_DOUBLE_QUOTE, + A_F9, + A_F10, + A_F11, + A_F12, + A_TRADEMARK, + A_LOW_SCARON, + A_SHIFT_ENTER, + A_LOW_OE, + A_END, + A_PAGE_DOWN, + A_CAP_YDIERESIS, - K_ALT, - K_CTRL, - K_SHIFT, - K_INS, - K_DEL, - K_PGDN, - K_PGUP, - K_HOME, - K_END, + A_SHIFT_SPACE, + A_EXCLAMDOWN, + A_CENT, + A_POUND, + A_SHIFT_KP_ENTER, + A_YEN, + A_MOUSE3, + A_MOUSE4, + A_MOUSE5, + A_COPYRIGHT, + A_CURSOR_UP, + A_CURSOR_DOWN, + A_CURSOR_LEFT, + A_CURSOR_RIGHT, + A_REGISTERED, + A_UNDEFINED_7, + A_UNDEFINED_8, + A_UNDEFINED_9, + A_UNDEFINED_10, + A_UNDEFINED_11, + A_UNDEFINED_12, + A_UNDEFINED_13, + A_UNDEFINED_14, + A_UNDEFINED_15, + A_UNDEFINED_16, + A_UNDEFINED_17, + A_UNDEFINED_18, + A_UNDEFINED_19, + A_UNDEFINED_20, + A_UNDEFINED_21, + A_UNDEFINED_22, + A_QUESTION_DOWN, - 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, + A_CAP_AGRAVE, + A_CAP_AACUTE, + A_CAP_ACIRCUMFLEX, + A_CAP_ATILDE, + A_CAP_ADIERESIS, + A_CAP_ARING, + A_CAP_AE, + A_CAP_CCEDILLA, + A_CAP_EGRAVE, + A_CAP_EACUTE, + A_CAP_ECIRCUMFLEX, + A_CAP_EDIERESIS, + A_CAP_IGRAVE, + A_CAP_IACUTE, + A_CAP_ICIRCUMFLEX, + A_CAP_IDIERESIS, + A_CAP_ETH, + A_CAP_NTILDE, + A_CAP_OGRAVE, + A_CAP_OACUTE, + A_CAP_OCIRCUMFLEX, + A_CAP_OTILDE, + A_CAP_ODIERESIS, + A_MULTIPLY, + A_CAP_OSLASH, + A_CAP_UGRAVE, + A_CAP_UACUTE, + A_CAP_UCIRCUMFLEX, + A_CAP_UDIERESIS, + A_CAP_YACUTE, + A_CAP_THORN, + A_GERMANDBLS, - 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, + A_LOW_AGRAVE, + A_LOW_AACUTE, + A_LOW_ACIRCUMFLEX, + A_LOW_ATILDE, + A_LOW_ADIERESIS, + A_LOW_ARING, + A_LOW_AE, + A_LOW_CCEDILLA, + A_LOW_EGRAVE, + A_LOW_EACUTE, + A_LOW_ECIRCUMFLEX, + A_LOW_EDIERESIS, + A_LOW_IGRAVE, + A_LOW_IACUTE, + A_LOW_ICIRCUMFLEX, + A_LOW_IDIERESIS, + A_LOW_ETH, + A_LOW_NTILDE, + A_LOW_OGRAVE, + A_LOW_OACUTE, + A_LOW_OCIRCUMFLEX, + A_LOW_OTILDE, + A_LOW_ODIERESIS, + A_DIVIDE, + A_LOW_OSLASH, + A_LOW_UGRAVE, + A_LOW_UACUTE, + A_LOW_UCIRCUMFLEX, + A_LOW_UDIERESIS, + A_LOW_YACUTE, + A_LOW_THORN, + A_LOW_YDIERESIS, + + A_JOY0, + A_JOY1, + A_JOY2, + A_JOY3, + A_JOY4, + A_JOY5, + A_JOY6, + A_JOY7, + A_JOY8, + A_JOY9, + A_JOY10, + A_JOY11, + A_JOY12, + A_JOY13, + A_JOY14, + A_JOY15, + A_JOY16, + A_JOY17, + A_JOY18, + A_JOY19, + A_JOY20, + A_JOY21, + A_JOY22, + A_JOY23, + A_JOY24, + A_JOY25, + A_JOY26, + A_JOY27, + A_JOY28, + A_JOY29, + A_JOY30, + A_JOY31, - K_MOUSE1, - K_MOUSE2, - K_MOUSE3, - K_MOUSE4, - K_MOUSE5, + A_AUX0, + A_AUX1, + A_AUX2, + A_AUX3, + A_AUX4, + A_AUX5, + A_AUX6, + A_AUX7, + A_AUX8, + A_AUX9, + A_AUX10, + A_AUX11, + A_AUX12, + A_AUX13, + A_AUX14, + A_AUX15, + A_AUX16, + A_AUX17, + A_AUX18, + A_AUX19, + A_AUX20, + A_AUX21, + A_AUX22, + A_AUX23, + A_AUX24, + A_AUX25, + A_AUX26, + A_AUX27, + A_AUX28, + A_AUX29, + A_AUX30, + A_AUX31, - 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; + MAX_KEYS +} fakeAscii_t; // The menu code needs to get both key and char events, but diff --git a/code/client/keys.h b/code/client/keys.h index 5ecb234..5e1df4a 100644 --- a/code/client/keys.h +++ b/code/client/keys.h @@ -1,17 +1,14 @@ #include "keycodes.h" -#define MAX_KEYS 256 - typedef struct { qboolean down; int repeats; // if > 1, it is autorepeating char *binding; } qkey_t; -extern qboolean key_overstrikeMode; -extern qkey_t keys[MAX_KEYS]; +#define MAX_EDIT_LINE 256 +#define COMMAND_HISTORY 32 -#define MAX_EDIT_LINE 256 typedef struct { int cursor; int scroll; @@ -19,18 +16,42 @@ typedef struct { char buffer[MAX_EDIT_LINE]; } field_t; +typedef struct keyGlobals_s +{ + field_t historyEditLines[COMMAND_HISTORY]; + + int nextHistoryLine; // the last line in the history buffer, not masked + int historyLine; // the line being displayed from history buffer + // will be <= nextHistoryLine + field_t g_consoleField; + + qboolean anykeydown; + qboolean key_overstrikeMode; + int keyDownCount; + + qkey_t keys[MAX_KEYS]; +} keyGlobals_t; + + +typedef struct +{ + word upper; + word lower; + char *name; + int keynum; + bool menukey; +} keyname_t; + +extern keyGlobals_t kg; +extern keyname_t keynames[MAX_KEYS]; + void Field_Clear( field_t *edit ); void Field_KeyDownEvent( field_t *edit, int key ); void Field_CharEvent( field_t *edit, int ch ); void Field_Draw( field_t *edit, int x, int y, int width, qboolean showCursor ); void Field_BigDraw( field_t *edit, int x, int y, int width, qboolean showCursor ); -#define COMMAND_HISTORY 32 -extern field_t historyEditLines[COMMAND_HISTORY]; - -extern field_t g_consoleField; extern field_t chatField; -extern qboolean anykeydown; void Key_WriteBindings( fileHandle_t f ); void Key_SetBinding( int keynum, const char *binding ); diff --git a/code/client/snd_dma.cpp b/code/client/snd_dma.cpp index 58f8ee1..f019cec 100644 --- a/code/client/snd_dma.cpp +++ b/code/client/snd_dma.cpp @@ -197,7 +197,7 @@ int s_entityWavVol_back[MAX_GENTITIES]; * \**************************************************************************************************/ -int s_UseOpenAL = true; // Determines if using Open AL or the default software mixer +int s_UseOpenAL = false; // Determines if using Open AL or the default software mixer ALfloat listener_pos[3]; // Listener Position ALfloat listener_ori[6]; // Listener Orientation @@ -456,7 +456,7 @@ void S_Init( void ) { // Reached limit of sources break; } - alSourcef(s_channels[i].alSource, AL_REFERENCE_DISTANCE, 250.0f); + alSourcef(s_channels[i].alSource, AL_REFERENCE_DISTANCE, 400.0f); if (alGetError() != AL_NO_ERROR) { break; @@ -464,12 +464,6 @@ void S_Init( void ) { s_numChannels++; } -//#ifdef _DEBUG -// char szString[256]; -// sprintf(szString, "Created %d Open AL Sources\n", s_numChannels); -// OutputDebugString(szString); -//#endif - // Generate AL Buffers for streaming audio playback (used for MP3s) ch = s_channels + 1; for (i = 1; i < s_numChannels; i++, ch++) @@ -1386,6 +1380,7 @@ Entchannel 0 will never override a playing sound */ void S_StartSound(const vec3_t origin, int entityNum, int entchannel, sfxHandle_t sfxHandle ) { + int i; channel_t *ch; /*const*/ sfx_t *sfx; @@ -1411,6 +1406,44 @@ void S_StartSound(const vec3_t origin, int entityNum, int entchannel, sfxHandle_ Com_Printf( "%i : %s on (%d)\n", s_paintedtime, sfx->sSoundName, entityNum ); } + if (s_UseOpenAL) + { + if (entchannel == CHAN_WEAPON) + { + // Check if we are playing a 'charging' sound, if so, stop it now .. + ch = s_channels + 1; + for (i = 1; i < s_numChannels; i++, ch++) + { + if ((ch->entnum == entityNum) && (ch->entchannel == CHAN_WEAPON) && (ch->thesfx) && (strstr(strlwr(ch->thesfx->sSoundName), "altcharge") != NULL)) + { + // Stop this sound + alSourceStop(ch->alSource); + alSourcei(ch->alSource, AL_BUFFER, NULL); + ch->bPlaying = false; + ch->thesfx = NULL; + break; + } + } + } + else + { + ch = s_channels + 1; + for (i = 1; i < s_numChannels; i++, ch++) + { + if ((ch->entnum == entityNum) && (ch->thesfx) && (strstr(strlwr(ch->thesfx->sSoundName), "falling") != NULL)) + { + // Stop this sound + alSourceStop(ch->alSource); + alSourcei(ch->alSource, AL_BUFFER, NULL); + ch->bPlaying = false; + ch->thesfx = NULL; + break; + } + } + } + } + + // pick a channel to play on ch = S_PickChannel( entityNum, entchannel ); @@ -1617,6 +1650,7 @@ void S_StopSounds(void) for (i = 0; i < s_numChannels; i++, ch++) { alSourceStop(s_channels[i].alSource); + alSourcei(s_channels[i].alSource, AL_BUFFER, NULL); ch->thesfx = NULL; memset(&ch->MP3StreamHeader, 0, sizeof(MP3STREAM)); ch->bLooping = false; @@ -2077,14 +2111,14 @@ void S_UpdateEntityPosition( int entityNum, const vec3_t origin ) ch = s_channels; for (i = 0; i < s_numChannels; i++, ch++) { - if ((s_channels[i].bPlaying) & (s_channels[i].entnum == entityNum)) + if ((s_channels[i].bPlaying) & (s_channels[i].entnum == entityNum) & (!s_channels[i].bLooping)) { pos[0] = origin[0]; pos[1] = origin[2]; pos[2] = -origin[1]; alSourcefv(s_channels[i].alSource, AL_POSITION, pos); - if (s_bEALFileLoaded) + if ((s_bEALFileLoaded) && !( ch->entchannel == CHAN_VOICE || ch->entchannel == CHAN_VOICE_ATTEN || ch->entchannel == CHAN_VOICE_GLOBAL ) ) { UpdateEAXBuffer(ch); } @@ -2246,12 +2280,6 @@ void S_Respatialize( int entityNum, const vec3_t head, vec3_t axis[3], qboolean listener_pos[2] = -head[1]; alListenerfv(AL_POSITION, listener_pos); -//#ifdef _DEBUG -// char szString[256]; -// sprintf(szString, "Listener at %f,%f,%f\n", listener_pos[0], listener_pos[1], listener_pos[2]); -// OutputDebugString(szString); -//#endif - listener_ori[0] = axis[0][0]; listener_ori[1] = axis[0][2]; listener_ori[2] = -axis[0][1]; @@ -2543,6 +2571,8 @@ void S_Update_(void) { int i,j; int source; float pos[3]; + EAXOBSTRUCTIONPROPERTIES eaxOBProp; + EAXOCCLUSIONPROPERTIES eaxOCProp; #ifdef _DEBUG char szString[256]; #endif @@ -2560,13 +2590,7 @@ void S_Update_(void) { { if ( !ch->thesfx || (ch->bPlaying)) continue; - -// if ( ch->entchannel == CHAN_VOICE || ch->entchannel == CHAN_VOICE_ATTEN || ch->entchannel == CHAN_VOICE_GLOBAL ) -// snd_vol = voice_vol; -// else -// snd_vol = normal_vol; - - + source = ch - s_channels; // Get position of source @@ -2606,21 +2630,40 @@ void S_Update_(void) { } alSourcefv(s_channels[source].alSource, AL_POSITION, pos); - -//#ifdef _DEBUG -// sprintf(szString, "Sound %s on channel %d at %f,%f,%f\n", ch->thesfx->sSoundName, source, pos[0], pos[1], pos[2]); -// OutputDebugString(szString); -//#endif - alSourcei(s_channels[source].alSource, AL_LOOPING, AL_FALSE); if ( ch->entchannel == CHAN_VOICE || ch->entchannel == CHAN_VOICE_ATTEN || ch->entchannel == CHAN_VOICE_GLOBAL ) + { + alSourcef(s_channels[source].alSource, AL_REFERENCE_DISTANCE, 1500.0f); alSourcef(s_channels[source].alSource, AL_GAIN, ((float)(ch->master_vol) * s_volumeVoice->value) / 255.0f); + + if (s_bEAX) + { + // Switch-off Occlusion + Obstruction + eaxOBProp.lObstruction = EAXBUFFER_DEFAULTOBSTRUCTION; + eaxOBProp.flObstructionLFRatio = EAXBUFFER_DEFAULTOBSTRUCTIONLFRATIO; + + eaxOCProp.lOcclusion = EAXBUFFER_DEFAULTOCCLUSION; + eaxOCProp.flOcclusionLFRatio = EAXBUFFER_DEFAULTOCCLUSIONLFRATIO; + eaxOCProp.flOcclusionRoomRatio = EAXBUFFER_DEFAULTOCCLUSIONROOMRATIO; + eaxOCProp.flOcclusionDirectRatio = EAXBUFFER_DEFAULTOCCLUSIONDIRECTRATIO; + + s_eaxSet(&DSPROPSETID_EAX_BufferProperties, DSPROPERTY_EAXBUFFER_OBSTRUCTIONPARAMETERS, + ch->alSource, &eaxOBProp, sizeof(EAXOBSTRUCTIONPROPERTIES)); + + s_eaxSet(&DSPROPSETID_EAX_BufferProperties, DSPROPERTY_EAXBUFFER_OCCLUSIONPARAMETERS, + ch->alSource, &eaxOCProp, sizeof(EAXOCCLUSIONPROPERTIES)); + } + } else + { + alSourcef(s_channels[source].alSource, AL_REFERENCE_DISTANCE, 400.f); alSourcef(s_channels[source].alSource, AL_GAIN, ((float)(ch->master_vol) * s_volume->value) / 255.f); - if (s_bEALFileLoaded) - UpdateEAXBuffer(ch); + if (s_bEALFileLoaded) + UpdateEAXBuffer(ch); + } + int nBytesDecoded = 0; int nTotalBytesDecoded = 0; @@ -2786,7 +2829,7 @@ void UpdateSingleShotSounds() ALint processed; channel_t *ch; #ifdef _DEBUG - char szString[245]; + char szString[256]; #endif // Firstly, check if any single-shot sounds have completed, or if they need more data (for streaming Sources), @@ -2796,7 +2839,7 @@ void UpdateSingleShotSounds() { ch->bProcessed = false; if ((s_channels[i].bPlaying) && (!ch->bLooping)) - { + { // Single-shot if (s_channels[i].bStreaming == false) { @@ -3029,6 +3072,7 @@ void UpdateLoopingSounds() for (j = 0; j < numLoopSounds; j++) { loop = &loopSounds[j]; + if ((loop->bProcessed == false) && (ch->thesfx == loop->sfx)) { // Same sound - wrong position @@ -3076,6 +3120,7 @@ void UpdateLoopingSounds() for (j = 0; j < numLoopSounds; j++) { loop = &loopSounds[j]; + if (loop->bProcessed == false) { ch = S_PickChannel(0,0); @@ -3113,9 +3158,10 @@ void UpdateLoopingSounds() alSourcei(s_channels[source].alSource, AL_BUFFER, ch->thesfx->Buffer); alSourcefv(s_channels[source].alSource, AL_POSITION, pos); alSourcei(s_channels[source].alSource, AL_LOOPING, AL_TRUE); + alSourcef(s_channels[source].alSource, AL_REFERENCE_DISTANCE, 400.f); alSourcef(s_channels[source].alSource, AL_GAIN, ((float)(ch->master_vol) * s_volume->value) / 255.0f); alSourcei(s_channels[source].alSource, AL_SOURCE_RELATIVE, ch->fixed_origin ? AL_TRUE : AL_FALSE); - + if (s_bEALFileLoaded) UpdateEAXBuffer(ch); diff --git a/code/client/snd_mem.cpp b/code/client/snd_mem.cpp index ab61fae..ef43eca 100644 --- a/code/client/snd_mem.cpp +++ b/code/client/snd_mem.cpp @@ -496,9 +496,9 @@ void R_CheckMP3s( const char *psDir ) void S_MP3_CalcVols_f( void ) { char sStartDir[MAX_QPATH] = {"sound"}; - const char sUsage[] = "Usage: mp3_calcvols [-rescan] [startdir (default='sound')]\n"; + const char sUsage[] = "Usage: mp3_calcvols [-rescan] \ne.g. mp3_calcvols sound/chars"; - if (Cmd_Argc()>4) // 3 optional arguments + if (Cmd_Argc() == 1 || Cmd_Argc()>4) // 3 optional arguments { Com_Printf(sUsage); return; @@ -569,12 +569,13 @@ static qboolean S_LoadSound_FileLoadAndNameAdjuster(char *psFilename, byte **pDa if (com_buildScript->integer) { fileHandle_t hFile; + //German strncpy(psVoice,"chr_d",5); // same number of letters as "chars" - FS_FOpenFileRead(psFilename, &hFile, qfalse); //cache this file + FS_FOpenFileRead(psFilename, &hFile, qfalse); //cache the wav if (!hFile) { strcpy(&psFilename[iNameStrlen-3],"mp3"); //not there try mp3 - FS_FOpenFileRead(psFilename, &hFile, qfalse); //cache this file + FS_FOpenFileRead(psFilename, &hFile, qfalse); //cache the mp3 } if (hFile) { @@ -582,19 +583,35 @@ static qboolean S_LoadSound_FileLoadAndNameAdjuster(char *psFilename, byte **pDa } strcpy(&psFilename[iNameStrlen-3],"wav"); //put it back to wav + //French strncpy(psVoice,"chr_f",5); // same number of letters as "chars" - FS_FOpenFileRead(psFilename, &hFile, qfalse); //cahce this file + FS_FOpenFileRead(psFilename, &hFile, qfalse); //cache the wav if (!hFile) { strcpy(&psFilename[iNameStrlen-3],"mp3"); //not there try mp3 - FS_FOpenFileRead(psFilename, &hFile, qfalse); //cache this file + FS_FOpenFileRead(psFilename, &hFile, qfalse); //cache the mp3 } if (hFile) { FS_FCloseFile(hFile); } - strncpy(psVoice,"chars",5); //put it back to chars strcpy(&psFilename[iNameStrlen-3],"wav"); //put it back to wav + + //Spanish + strncpy(psVoice,"chr_e",5); // same number of letters as "chars" + FS_FOpenFileRead(psFilename, &hFile, qfalse); //cache the wav + if (!hFile) + { + strcpy(&psFilename[iNameStrlen-3],"mp3"); //not there try mp3 + FS_FOpenFileRead(psFilename, &hFile, qfalse); //cache the mp3 + } + if (hFile) + { + FS_FCloseFile(hFile); + } + strcpy(&psFilename[iNameStrlen-3],"wav"); //put it back to wav + + strncpy(psVoice,"chars",5); //put it back to chars } // account for foreign voices... @@ -604,11 +621,14 @@ static qboolean S_LoadSound_FileLoadAndNameAdjuster(char *psFilename, byte **pDa { strncpy(psVoice,"chr_d",5); // same number of letters as "chars" } - else - if (s_language && stricmp("FRANCAIS",s_language->string)==0) + else if (s_language && stricmp("FRANCAIS",s_language->string)==0) { strncpy(psVoice,"chr_f",5); // same number of letters as "chars" } + else if (s_language && stricmp("ESPANOL",s_language->string)==0) + { + strncpy(psVoice,"chr_e",5); // same number of letters as "chars" + } else { psVoice = NULL; // use this ptr as a flag as to whether or not we substituted with a foreign version @@ -630,46 +650,7 @@ static qboolean S_LoadSound_FileLoadAndNameAdjuster(char *psFilename, byte **pDa if (psVoice) // were we trying to load foreign? { // yep, so fallback to re-try the english... - // - - - // this doesn't work that well, there are just FAR too many exception (probetalk, gonktalk, headjump etc) - // that this fails to do english fallback on. If I put the check the other way round, then the list of - // what's not acceptable is also pretty long. Just forget it I guess... - // -#if 0 -/* - if (0) // set to 0 to be disabled - { - // NEW BIT!!! We can sort of make this work by only allowing vocal fallback to certain noises, - // this stops foreigners whining that their languages aren't fully localised... - // - const char *psBasePart = strrchr(psFilename,'/'); - psBasePart = psBasePart ? psBasePart+1 : psFilename; // probably irrelevant here, but good practice - - // quicker to say what's allowed than what's forbidden (based on quick dir check)... - // - if (! - ( - !strnicmp(psBasePart,"choke",5) || - !strnicmp(psBasePart,"death",5) || - !strnicmp(psBasePart,"drown",5) || - !strnicmp(psBasePart,"falling",7) || - !strnicmp(psBasePart,"gasp",4) || - !strnicmp(psBasePart,"gurp",4) || - !strnicmp(psBasePart,"jump",4) || - !strnicmp(psBasePart,"land",4) || - !strnicmp(psBasePart,"pain",4) || - !strnicmp(psBasePart,"pushed",5) - ) - ) - { - return qfalse; - } - } -*/ -#endif - + // #ifndef FINAL_BUILD Com_Printf(S_COLOR_YELLOW "Foreign file missing: \"%s\"! (using English...)\n",psFilename); #endif diff --git a/code/client/vssver.scc b/code/client/vssver.scc index 25196b7..a9f535d 100644 Binary files a/code/client/vssver.scc and b/code/client/vssver.scc differ diff --git a/code/demo.bat b/code/demo.bat new file mode 100644 index 0000000..6994ef4 --- /dev/null +++ b/code/demo.bat @@ -0,0 +1,3 @@ +xcopy/y finalbuild\jk2sp.exe c:\send\quake +xcopy/y finalbuild\jk2gamex86.dll c:\send\quake +rd/s/q c:\send\game\base\saves diff --git a/code/ff/IFC/FeelitAPI.h b/code/ff/IFC/FeelitAPI.h new file mode 100644 index 0000000..bf50294 --- /dev/null +++ b/code/ff/IFC/FeelitAPI.h @@ -0,0 +1,1228 @@ +/********************************************************************** + Copyright (c) 1997-2000 Immersion Corporation + + Permission to use, copy, modify, distribute, and sell this + software and its documentation may be granted without fee; + interested parties are encouraged to request permission from + Immersion Corporation + 2158 Paragon Drive + San Jose, CA 95131 + 408-467-1900 + + IMMERSION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. + IN NO EVENT SHALL IMMERSION BE LIABLE FOR ANY SPECIAL, INDIRECT OR + CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, + NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + FILE: FeelitAPI.h + + PURPOSE: Feelit API + + STARTED: 09/08/97 + + NOTES/REVISIONS: + + 23-May-2000 MPR Added support for querying the number of effects that can be + downloaded to a device (FEELIT_PROPNUMEFFECTS and FEELIT_PROP_NUMEFFECTS). + Added a new device subtype, FEELIT_DEVICETYPEMOUSE_VIBRATION_FF. + Removed FEELIT_DEVICETYPE_HID. + + 06-Jun-2000 MPR Added FEELIT_PROP_DEVICEID. + + 08-Jun-2000 MPR Added MAKE_FEELIT_DEVICE_TYPE_DWORD. + +**********************************************************************/ + +#ifndef __FEELITAPI_INCLUDED__ +#define __FEELITAPI_INCLUDED__ + +#ifndef FEELIT_VERSION +#define FEELIT_VERSION 0x0103 +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef _WIN32 +#define COM_NO_WINDOWS_H +#include +#endif + +/**************************************************************************** + * + * Class IDs + * + ****************************************************************************/ + +DEFINE_GUID(CLSID_Feelit, 0x5959df60,0x2911,0x11d1,0xb0,0x49,0x00,0x20,0xaf,0x30,0x26,0x9a); +DEFINE_GUID(CLSID_FeelitDevice, 0x5959df61,0x2911,0x11d1,0xb0,0x49,0x00,0x20,0xaf,0x30,0x26,0x9a); + + +/**************************************************************************** + * + * Interfaces + * + ****************************************************************************/ + +DEFINE_GUID(IID_IFeelit, 0x5959df62,0x2911,0x11d1,0xb0,0x49,0x00,0x20,0xaf,0x30,0x26,0x9a); +DEFINE_GUID(IID_IFeelitDevice, 0x5959df63,0x2911,0x11d1,0xb0,0x49,0x00,0x20,0xaf,0x30,0x26,0x9a); +DEFINE_GUID(IID_IFeelitEffect, 0x5959df64,0x2911,0x11d1,0xb0,0x49,0x00,0x20,0xaf,0x30,0x26,0x9a); +DEFINE_GUID(IID_IFeelitConfig, 0x900c39e0,0xcc5c,0x11d2,0x8c,0x5d,0x00,0x10,0x5a,0x17,0x8a,0xd1); + + +/**************************************************************************** + * + * Predefined object types + * + ****************************************************************************/ + +DEFINE_GUID(GUID_Feelit_XAxis, 0x5959df65,0x2911,0x11d1,0xb0,0x49,0x00,0x20,0xaf,0x30,0x26,0x9a); +DEFINE_GUID(GUID_Feelit_YAxis, 0x5959df66,0x2911,0x11d1,0xb0,0x49,0x00,0x20,0xaf,0x30,0x26,0x9a); +DEFINE_GUID(GUID_Feelit_ZAxis, 0x5959df67,0x2911,0x11d1,0xb0,0x49,0x00,0x20,0xaf,0x30,0x26,0x9a); +DEFINE_GUID(GUID_Feelit_RxAxis, 0x5959df68,0x2911,0x11d1,0xb0,0x49,0x00,0x20,0xaf,0x30,0x26,0x9a); +DEFINE_GUID(GUID_Feelit_RyAxis, 0x5959df69,0x2911,0x11d1,0xb0,0x49,0x00,0x20,0xaf,0x30,0x26,0x9a); +DEFINE_GUID(GUID_Feelit_RzAxis, 0x5959df6a,0x2911,0x11d1,0xb0,0x49,0x00,0x20,0xaf,0x30,0x26,0x9a); +DEFINE_GUID(GUID_Feelit_Slider, 0x5959df6b,0x2911,0x11d1,0xb0,0x49,0x00,0x20,0xaf,0x30,0x26,0x9a); + +DEFINE_GUID(GUID_Feelit_Button, 0x5959df6c,0x2911,0x11d1,0xb0,0x49,0x00,0x20,0xaf,0x30,0x26,0x9a); +DEFINE_GUID(GUID_Feelit_Key, 0x5959df6d,0x2911,0x11d1,0xb0,0x49,0x00,0x20,0xaf,0x30,0x26,0x9a); + +DEFINE_GUID(GUID_Feelit_POV, 0x5959df6e,0x2911,0x11d1,0xb0,0x49,0x00,0x20,0xaf,0x30,0x26,0x9a); + +DEFINE_GUID(GUID_Feelit_Unknown, 0x5959df6f,0x2911,0x11d1,0xb0,0x49,0x00,0x20,0xaf,0x30,0x26,0x9a); + + +/**************************************************************************** + * + * Predefined Product GUIDs + * + ****************************************************************************/ + +DEFINE_GUID(GUID_Feelit_Mouse, 0x99bb5400,0x2b94,0x11d1,0xb0,0x49,0x00,0x20,0xaf,0x30,0x26,0x9a); + +/**************************************************************************** + * + * Force feedback effects + * + ****************************************************************************/ + + +/* Constant Force */ +DEFINE_GUID(GUID_Feelit_ConstantForce,0x5959df71,0x2911,0x11d1,0xb0,0x49,0x00,0x20,0xaf,0x30,0x26,0x9a); + +/* Ramp Force */ +DEFINE_GUID(GUID_Feelit_RampForce, 0x5959df72,0x2911,0x11d1,0xb0,0x49,0x00,0x20,0xaf,0x30,0x26,0x9a); + +/* Periodic Effects */ +DEFINE_GUID(GUID_Feelit_Square, 0x5959df73,0x2911,0x11d1,0xb0,0x49,0x00,0x20,0xaf,0x30,0x26,0x9a); +DEFINE_GUID(GUID_Feelit_Sine, 0x5959df74,0x2911,0x11d1,0xb0,0x49,0x00,0x20,0xaf,0x30,0x26,0x9a); +DEFINE_GUID(GUID_Feelit_Triangle, 0x5959df75,0x2911,0x11d1,0xb0,0x49,0x00,0x20,0xaf,0x30,0x26,0x9a); +DEFINE_GUID(GUID_Feelit_SawtoothUp, 0x5959df76,0x2911,0x11d1,0xb0,0x49,0x00,0x20,0xaf,0x30,0x26,0x9a); +DEFINE_GUID(GUID_Feelit_SawtoothDown,0x5959df77,0x2911,0x11d1,0xb0,0x49,0x00,0x20,0xaf,0x30,0x26,0x9a); + + +/* Conditions */ +DEFINE_GUID(GUID_Feelit_Spring, 0x5959df78,0x2911,0x11d1,0xb0,0x49,0x00,0x20,0xaf,0x30,0x26,0x9a); +DEFINE_GUID(GUID_Feelit_DeviceSpring,0x5959df83,0x2911,0x11d1,0xb0,0x49,0x00,0x20,0xaf,0x30,0x26,0x9a); +DEFINE_GUID(GUID_Feelit_Damper, 0x5959df79,0x2911,0x11d1,0xb0,0x49,0x00,0x20,0xaf,0x30,0x26,0x9a); +DEFINE_GUID(GUID_Feelit_Inertia, 0x5959df7a,0x2911,0x11d1,0xb0,0x49,0x00,0x20,0xaf,0x30,0x26,0x9a); +DEFINE_GUID(GUID_Feelit_Friction, 0x5959df7b,0x2911,0x11d1,0xb0,0x49,0x00,0x20,0xaf,0x30,0x26,0x9a); +DEFINE_GUID(GUID_Feelit_Texture, 0x5959df7c,0x2911,0x11d1,0xb0,0x49,0x00,0x20,0xaf,0x30,0x26,0x9a); +DEFINE_GUID(GUID_Feelit_Grid, 0x5959df7d,0x2911,0x11d1,0xb0,0x49,0x00,0x20,0xaf,0x30,0x26,0x9a); + +/* Enclosures */ +DEFINE_GUID(GUID_Feelit_Enclosure, 0x5959df7f,0x2911,0x11d1,0xb0,0x49,0x00,0x20,0xaf,0x30,0x26,0x9a); +DEFINE_GUID(GUID_Feelit_Ellipse, 0x5959df82,0x2911,0x11d1,0xb0,0x49,0x00,0x20,0xaf,0x30,0x26,0x9a); + +/* Custom Force */ +DEFINE_GUID(GUID_Feelit_CustomForce, 0x5959df7e,0x2911,0x11d1,0xb0,0x49,0x00,0x20,0xaf,0x30,0x26,0x9a); + +/**************************************************************************** + * + * Interfaces and Structures... + * + ****************************************************************************/ + + +/**************************************************************************** + * + * IFeelitEffect + * + ****************************************************************************/ + +#define FEELIT_FEFFECTTYPE_ALL 0x00000000 + +#define FEELIT_FEFFECTTYPE_CONSTANTFORCE 0x00000001 +#define FEELIT_FEFFECTTYPE_RAMPFORCE 0x00000002 +#define FEELIT_FEFFECTTYPE_PERIODIC 0x00000003 +#define FEELIT_FEFFECTTYPE_CONDITION 0x00000004 +#define FEELIT_FEFFECTTYPE_ENCLOSURE 0x00000005 +#define FEELIT_FEFFECTTYPE_ELLIPSE 0x00000006 +#define FEELIT_FEFFECTTYPE_TEXTURE 0x00000007 +#define FEELIT_FEFFECTTYPE_CUSTOMFORCE 0x000000F0 +#define FEELIT_FEFFECTTYPE_HARDWARE 0x000000FF + +#define FEELIT_FEFFECTTYPE_FFATTACK 0x00000200 +#define FEELIT_FEFFECTTYPE_FFFADE 0x00000400 +#define FEELIT_FEFFECTTYPE_SATURATION 0x00000800 +#define FEELIT_FEFFECTTYPE_POSNEGCOEFFICIENTS 0x00001000 +#define FEELIT_FEFFECTTYPE_POSNEGSATURATION 0x00002000 +#define FEELIT_FEFFECTTYPE_DEADBAND 0x00004000 + +#define FEELIT_EFFECTTYPE_GETTYPE(n) LOBYTE(n) +#define FEELIT_EFFECTTYPE_GETFLAGS(n) ( n & 0xFFFFFF00 ) + +#define FEELIT_DEGREES 100 +#define FEELIT_FFNOMINALMAX 10000 +#define FEELIT_SECONDS 1000000 + +typedef struct FEELIT_CONSTANTFORCE { + LONG lMagnitude; /* Magnitude of the effect, in the range -10000 to 10000 */ +} FEELIT_CONSTANTFORCE, *LPFEELIT_CONSTANTFORCE; +typedef const FEELIT_CONSTANTFORCE *LPCFEELIT_CONSTANTFORCE; + +typedef struct FEELIT_RAMPFORCE { + LONG lStart; /* Magnitude at start of effect. Range -10000 to 10000 */ + LONG lEnd; /* Magnitude at end of effect. Range -10000 to 10000 */ +} FEELIT_RAMPFORCE, *LPFEELIT_RAMPFORCE; +typedef const FEELIT_RAMPFORCE *LPCFEELIT_RAMPFORCE; + +typedef struct FEELIT_PERIODIC { + DWORD dwMagnitude; /* Magnitude of the effect, in the range 0 to 10000 */ + LONG lOffset; /* Force will be gen'd in range lOffset - dwMagnitude to lOffset + dwMagnitude */ + DWORD dwPhase; /* Position in cycle at wich playback begins. Range 0 - 35,999 */ + DWORD dwPeriod; /* Period (length of one cycle) of the effect in microseconds */ +} FEELIT_PERIODIC, *LPFEELIT_PERIODIC; +typedef const FEELIT_PERIODIC *LPCFEELIT_PERIODIC; + +typedef struct FEELIT_CONDITION { + LONG lCenter; /* Center-point in screen coords. Axis depends on that in FEELIT_EFFECT */ + LONG lPositiveCoefficient; /* Coef. on pos. side of the offset. Range -10000 to 10000 */ + LONG lNegativeCoefficient; /* Coef. on neg. side of the offset. Range -10000 to 10000 */ + DWORD dwPositiveSaturation; /* Max force output on pos. side of offset. Range 0 to 10000 */ + DWORD dwNegativeSaturation; /* Max force output on neg. side of offset. Range 0 to 10000 */ + LONG lDeadBand; /* Region around lOffset where condition is not active. Range 0 to 10000 */ +} FEELIT_CONDITION, *LPFEELIT_CONDITION; +typedef const FEELIT_CONDITION *LPCFEELIT_CONDITION; + +typedef struct FEELIT_TEXTURE { + DWORD dwSize; /* sizeof(FEELIT_TEXTURE) */ + LONG lOffset; /* Offset in screen coords of first texture from left or top edge */ + LONG lPosBumpMag; /* Magnitude of bumps felt when mouse travels in positive direction */ + DWORD dwPosBumpWidth; /* Width of bumps felt when mouse travels in positive direction */ + DWORD dwPosBumpSpacing; /* Center-to-Center spacing of bumps felt when mouse travels in positive direction */ + LONG lNegBumpMag; /* Magnitude of bumps felt when mouse travels in negative direction */ + DWORD dwNegBumpWidth; /* Width of bumps felt when mouse travels in negative direction */ + DWORD dwNegBumpSpacing; /* Center-to-Center spacing of bumps felt when mouse travels in negative direction */ +} FEELIT_TEXTURE, *LPFEELIT_TEXTURE; +typedef const FEELIT_TEXTURE *LPCFEELIT_TEXTURE; + +typedef struct FEELIT_CUSTOMFORCE { + DWORD cChannels; /* No. of channels (axes) affected by this force */ + DWORD dwSamplePeriod; /* Sample period in microseconds */ + DWORD cSamples; /* Total number of samples in the rglForceData */ + LPLONG rglForceData; /* long[cSamples]. Array of force values. Channels are interleaved */ +} FEELIT_CUSTOMFORCE, *LPFEELIT_CUSTOMFORCE; +typedef const FEELIT_CUSTOMFORCE *LPCFEELIT_CUSTOMFORCE; + +typedef struct FEELIT_ENVELOPE { + DWORD dwSize; /* sizeof(FEELIT_ENVELOPE) */ + DWORD dwAttackLevel; /* Ampl. for start of env., rel. to baseline. Range 0 to 10000 */ + DWORD dwAttackTime; /* Time, in microseconds, to reach sustain level */ + DWORD dwFadeLevel; /* Ampl. for end of env., rel. to baseline. Range 0 to 10000 */ + DWORD dwFadeTime; /* Time, in microseconds, to reach fade level */ +} FEELIT_ENVELOPE, *LPFEELIT_ENVELOPE; +typedef const FEELIT_ENVELOPE *LPCFEELIT_ENVELOPE; + +typedef struct FEELIT_EFFECT { + DWORD dwSize; /* sizeof(FEELIT_EFFECT) */ + GUID guidEffect; /* Effect Identifier */ + DWORD dwFlags; /* FEELIT_FEFFECT_* */ + DWORD dwDuration; /* Microseconds */ + DWORD dwSamplePeriod; /* RESERVED */ + DWORD dwGain; /* RESERVED */ + DWORD dwTriggerButton; /* RESERVED */ + DWORD dwTriggerRepeatInterval; /* RESERVED */ + DWORD cAxes; /* Number of axes */ + LPDWORD rgdwAxes; /* Array of axes */ + LPLONG rglDirection; /* Array of directions */ + LPFEELIT_ENVELOPE lpEnvelope; /* Optional */ + DWORD cbTypeSpecificParams; /* Size of params */ + LPVOID lpvTypeSpecificParams; /* Pointer to params */ + DWORD dwStartDelay; /* Microseconds delay */ +} FEELIT_EFFECT, *LPFEELIT_EFFECT; +typedef const FEELIT_EFFECT *LPCFEELIT_EFFECT; + + +/* Effect Flags */ +#define FEELIT_FEFFECT_OBJECTIDS 0x00000001 +#define FEELIT_FEFFECT_OBJECTOFFSETS 0x00000002 +#define FEELIT_FEFFECT_CARTESIAN 0x00000010 +#define FEELIT_FEFFECT_POLAR 0x00000020 +#define FEELIT_FEFFECT_SPHERICAL 0x00000040 + +/* Parameter Flags */ +#define FEELIT_FPARAM_DURATION 0x00000001 +#define FEELIT_FPARAM_SAMPLEPERIOD 0x00000002 +#define FEELIT_FPARAM_GAIN 0x00000004 +#define FEELIT_FPARAM_TRIGGERBUTTON 0x00000008 +#define FEELIT_FPARAM_TRIGGERREPEATINTERVAL 0x00000010 +#define FEELIT_FPARAM_AXES 0x00000020 +#define FEELIT_FPARAM_DIRECTION 0x00000040 +#define FEELIT_FPARAM_ENVELOPE 0x00000080 +#define FEELIT_FPARAM_TYPESPECIFICPARAMS 0x00000100 +#define FEELIT_FPARAM_STARTDELAY 0x00000200 +#define FEELIT_FPARAM_ALLPARAMS 0x000003FF +#define FEELIT_FPARAM_START 0x20000000 +#define FEELIT_FPARAM_NORESTART 0x40000000 +#define FEELIT_FPARAM_NODOWNLOAD 0x80000000 + +#define FEELIT_PARAM_NOTRIGGER 0xFFFFFFFF + +/* Start Flags */ +#define FEELIT_FSTART_SOLO 0x00000001 +#define FEELIT_FSTART_NODOWNLOAD 0x80000000 + +/* Status Flags */ +#define FEELIT_FSTATUS_PLAYING 0x00000001 +#define FEELIT_FSTATUS_EMULATED 0x00000002 + +/* Stiffness Mask Flags */ +#define FEELIT_FSTIFF_NONE 0x00000000 +#define FEELIT_FSTIFF_OUTERLEFTWALL 0x00000001 +#define FEELIT_FSTIFF_INNERLEFTWALL 0x00000002 +#define FEELIT_FSTIFF_INNERRIGHTWALL 0x00000004 +#define FEELIT_FSTIFF_OUTERRIGHTWALL 0x00000008 +#define FEELIT_FSTIFF_OUTERTOPWALL 0x00000010 +#define FEELIT_FSTIFF_INNERTOPWALL 0x00000020 +#define FEELIT_FSTIFF_INNERBOTTOMWALL 0x00000040 +#define FEELIT_FSTIFF_OUTERBOTTOMWALL 0x00000080 +#define FEELIT_FSTIFF_OUTERANYWALL ( FEELIT_FSTIFF_OUTERTOPWALL | FEELIT_FSTIFF_OUTERBOTTOMWALL | FEELIT_FSTIFF_OUTERLEFTWALL | FEELIT_FSTIFF_OUTERRIGHTWALL ) +#define FEELIT_FSTIFF_INBOUNDANYWALL FEELIT_FSTIFF_OUTERANYWALL +#define FEELIT_FSTIFF_INNERANYWALL ( FEELIT_FSTIFF_INNERTOPWALL | FEELIT_FSTIFF_INNERBOTTOMWALL | FEELIT_FSTIFF_INNERLEFTWALL | FEELIT_FSTIFF_INNERRIGHTWALL ) +#define FEELIT_FSTIFF_OUTBOUNDANYWALL FEELIT_FSTIFF_INNERANYWALL +#define FEELIT_FSTIFF_ANYWALL ( FEELIT_FSTIFF_OUTERANYWALL | FEELIT_FSTIFF_INNERANYWALL ) + +/* Clipping Mask Flags */ +#define FEELIT_FCLIP_NONE 0x00000000 +#define FEELIT_FCLIP_OUTERLEFTWALL 0x00000001 +#define FEELIT_FCLIP_INNERLEFTWALL 0x00000002 +#define FEELIT_FCLIP_INNERRIGHTWALL 0x00000004 +#define FEELIT_FCLIP_OUTERRIGHTWALL 0x00000008 +#define FEELIT_FCLIP_OUTERTOPWALL 0x00000010 +#define FEELIT_FCLIP_INNERTOPWALL 0x00000020 +#define FEELIT_FCLIP_INNERBOTTOMWALL 0x00000040 +#define FEELIT_FCLIP_OUTERBOTTOMWALL 0x00000080 +#define FEELIT_FCLIP_OUTERANYWALL ( FEELIT_FCLIP_OUTERTOPWALL | FEELIT_FCLIP_OUTERBOTTOMWALL | FEELIT_FCLIP_OUTERLEFTWALL | FEELIT_FCLIP_OUTERRIGHTWALL ) +#define FEELIT_FCLIP_INNERANYWALL ( FEELIT_FCLIP_INNERTOPWALL | FEELIT_FCLIP_INNERBOTTOMWALL | FEELIT_FCLIP_INNERLEFTWALL | FEELIT_FCLIP_INNERRIGHTWALL ) +#define FEELIT_FCLIP_ANYWALL ( FEELIT_FCLIP_OUTERANYWALL | FEELIT_FCLIP_INNERANYWALL ) + +typedef struct FEELIT_EFFESCAPE { + DWORD dwSize; /* sizeof( FEELIT_EFFESCAPE ) */ + DWORD dwCommand; /* Driver-specific command number */ + LPVOID lpvInBuffer; /* Buffer containing data required to perform the operation */ + DWORD cbInBuffer; /* Size, in bytes, of lpvInBuffer */ + LPVOID lpvOutBuffer; /* Buffer in which the operation's output data is returned */ + DWORD cbOutBuffer; /* Size, in bytes, of lpvOutBuffer */ +} FEELIT_EFFESCAPE, *LPFEELIT_EFFESCAPE; + + +#undef INTERFACE +#define INTERFACE IFeelitEffect + +DECLARE_INTERFACE_(IFeelitEffect, IUnknown) +{ + /*** IUnknown methods ***/ + STDMETHOD(QueryInterface)(THIS_ REFIID riid, LPVOID * ppvObj) PURE; + STDMETHOD_(ULONG,AddRef)(THIS) PURE; + STDMETHOD_(ULONG,Release)(THIS) PURE; + + /*** IFeelitEffect methods ***/ + STDMETHOD(GetEffectGuid)(THIS_ LPGUID) PURE; + STDMETHOD(GetParameters)(THIS_ LPFEELIT_EFFECT,DWORD) PURE; + STDMETHOD(SetParameters)(THIS_ LPCFEELIT_EFFECT,DWORD) PURE; + STDMETHOD(Start)(THIS_ DWORD,DWORD) PURE; + STDMETHOD(Stop)(THIS) PURE; + STDMETHOD(GetEffectStatus)(THIS_ LPDWORD) PURE; + STDMETHOD(Download)(THIS) PURE; + STDMETHOD(Unload)(THIS) PURE; + STDMETHOD(Escape)(THIS_ LPFEELIT_EFFESCAPE) PURE; +}; + +typedef struct IFeelitEffect *LPIFEELIT_EFFECT; + + +#if !defined(__cplusplus) || defined(CINTERFACE) +#define IFeelitEffect_QueryInterface(p,a,b) (p)->lpVtbl->QueryInterface(p,a,b) +#define IFeelitEffect_AddRef(p) (p)->lpVtbl->AddRef(p) +#define IFeelitEffect_Release(p) (p)->lpVtbl->Release(p) +#define IFeelitEffect_GetEffectGuid(p,a) (p)->lpVtbl->GetEffectGuid(p,a) +#define IFeelitEffect_GetParameters(p,a,b) (p)->lpVtbl->GetParameters(p,a,b) +#define IFeelitEffect_SetParameters(p,a,b) (p)->lpVtbl->SetParameters(p,a,b) +#define IFeelitEffect_Start(p,a,b) (p)->lpVtbl->Start(p,a,b) +#define IFeelitEffect_Stop(p) (p)->lpVtbl->Stop(p) +#define IFeelitEffect_GetEffectStatus(p,a) (p)->lpVtbl->GetEffectStatus(p,a) +#define IFeelitEffect_Download(p) (p)->lpVtbl->Download(p) +#define IFeelitEffect_Unload(p) (p)->lpVtbl->Unload(p) +#define IFeelitEffect_Escape(p,a) (p)->lpVtbl->Escape(p,a) +#else +#define IFeelitEffect_QueryInterface(p,a,b) (p)->QueryInterface(a,b) +#define IFeelitEffect_AddRef(p) (p)->AddRef() +#define IFeelitEffect_Release(p) (p)->Release() +#define IFeelitEffect_GetEffectGuid(p,a) (p)->GetEffectGuid(a) +#define IFeelitEffect_GetParameters(p,a,b) (p)->GetParameters(a,b) +#define IFeelitEffect_SetParameters(p,a,b) (p)->SetParameters(a,b) +#define IFeelitEffect_Start(p,a,b) (p)->Start(a,b) +#define IFeelitEffect_Stop(p) (p)->Stop() +#define IFeelitEffect_GetEffectStatus(p,a) (p)->GetEffectStatus(a) +#define IFeelitEffect_Download(p) (p)->Download() +#define IFeelitEffect_Unload(p) (p)->Unload() +#define IFeelitEffect_Escape(p,a) (p)->Escape(a) +#endif + + +typedef struct FEELIT_ENCLOSURE { + DWORD dwSize; /* sizeof(FEELIT_ENCLOSURE) */ + RECT rectBoundary; /* Rectangle defining the boundaries of the effect, in screen coords */ + DWORD dwTopAndBottomWallThickness; /* Thickness (pixels) of top/bottom walls. Must be < rectOutside.Height()/2 */ + DWORD dwLeftAndRightWallThickness; /* Thickness (pixels) of left/right walls. Must be < rectOutside.Width()/2 */ + LONG lTopAndBottomWallStiffness; /* Stiffness of horizontal borders */ + LONG lLeftAndRightWallStiffness; /* Stiffness of vertical borders */ + DWORD dwStiffnessMask; /* Borders where stiffness is turned on (FEELIT_FSTIFF*) */ + DWORD dwClippingMask; /* Borders where clipping is turned on (FEELIT_FCLIP*) */ + DWORD dwTopAndBottomWallSaturation; /* Saturation level of spring effect for top/bottom borders */ + DWORD dwLeftAndRightWallSaturation; /* Saturation level of spring effect for left/right borders */ + LPIFEELIT_EFFECT piInsideEffect; /* Interface pointer to effect active in inner area of the enclosure */ +} FEELIT_ENCLOSURE, *LPFEELIT_ENCLOSURE; +typedef const FEELIT_ENCLOSURE *LPCFEELIT_ENCLOSURE; + + +typedef struct FEELIT_ELLIPSE { + DWORD dwSize; /* sizeof(FEELIT_ELLIPSE) */ + RECT rectBoundary; /* Rectangle which circumscribes the ellipse (screen coords) */ + DWORD dwWallThickness; /* Thickness (pixels) of ellipse wall at its thickest point */ + LONG lStiffness; /* Stiffness of ellipse borders */ + DWORD dwStiffnessMask; /* Borders where stiffness is turned on (FEELIT_FSTIFF*) */ + DWORD dwClippingMask; /* Borders where clipping is turned on (FEELIT_FCLIP*) */ + DWORD dwSaturation; /* Saturation level of spring effect for ellipse borders */ + LPIFEELIT_EFFECT piInsideEffect; /* Interface pointer to effect active in inner area of the ellipse */ +} FEELIT_ELLIPSE, *LPFEELIT_ELLIPSE; +typedef const FEELIT_ELLIPSE *LPCFEELIT_ELLIPSE; + + +/**************************************************************************** + * + * IFeelitDevice + * + ****************************************************************************/ + +/* Device types */ +#define FEELIT_DEVICETYPE_DEVICE 1 +#define FEELIT_DEVICETYPE_MOUSE 2 + +/* Device subtypes */ +#define FEELIT_DEVICETYPEMOUSE_UNKNOWN 1 +#define FEELIT_DEVICETYPEMOUSE_TRADITIONAL_FF 2 +#define FEELIT_DEVICETYPEMOUSE_VIBRATION_FF 3 + +/* Device type macros */ +#define GET_FEELIT_DEVICE_TYPE(dwDevType) LOBYTE(dwDevType) +#define GET_FEELIT_DEVICE_SUBTYPE(dwDevType) HIBYTE(dwDevType) +#define MAKE_FEELIT_DEVICE_TYPE_DWORD(ucDevType, ucDevSubtype) (((DWORD) ((BYTE) ucDevSubtype << 8)) | (BYTE) ucDevType) + +typedef struct FEELIT_DEVCAPS { + DWORD dwSize; /* sizeof( FEELIT_DEVCAPS ) */ + DWORD dwFlags; /* FEELIT_FDEVCAPS_* */ + DWORD dwDevType; /* FEELIT_DEVICETYPE* */ + DWORD dwAxes; /* No. of axes available on the device */ + DWORD dwButtons; /* No. of buttons available on the device */ + DWORD dwPOVs; /* No. of point-of-view controllers on the device */ + DWORD dwFFSamplePeriod; /* Min. time btwn playback of consec. raw force commands */ + DWORD dwFFMinTimeResolution; /* Min. time, in microseconds, the device can resolve */ + DWORD dwFirmwareRevision; /* Firmware revision number of the device */ + DWORD dwHardwareRevision; /* Hardware revision number of the device */ + DWORD dwFFDriverVersion; /* Version number of the device driver */ +} FEELIT_DEVCAPS, *LPFEELIT_DEVCAPS; +typedef const FEELIT_DEVCAPS *LPCFEELIT_DEVCAPS; + +/* Device capabilities flags */ +#define FEELIT_FDEVCAPS_ATTACHED 0x00000001 +#define FEELIT_FDEVCAPS_POLLEDDEVICE 0x00000002 +#define FEELIT_FDEVCAPS_EMULATED 0x00000004 +#define FEELIT_FDEVCAPS_POLLEDDATAFORMAT 0x00000008 +#define FEELIT_FDEVCAPS_FORCEFEEDBACK 0x00000100 +#define FEELIT_FDEVCAPS_FFATTACK 0x00000200 +#define FEELIT_FDEVCAPS_FFFADE 0x00000400 +#define FEELIT_FDEVCAPS_SATURATION 0x00000800 +#define FEELIT_FDEVCAPS_POSNEGCOEFFICIENTS 0x00001000 +#define FEELIT_FDEVCAPS_POSNEGSATURATION 0x00002000 +#define FEELIT_FDEVCAPS_DEADBAND 0x00004000 + + +/* Data Format Type Flags */ + +#define FEELIT_FOBJDATAFMT_ALL 0x00000000 + +#define FEELIT_FOBJDATAFMT_RELAXIS 0x00000001 +#define FEELIT_FOBJDATAFMT_ABSAXIS 0x00000002 +#define FEELIT_FOBJDATAFMT_AXIS 0x00000003 + +#define FEELIT_FOBJDATAFMT_PSHBUTTON 0x00000004 +#define FEELIT_FOBJDATAFMT_TGLBUTTON 0x00000008 +#define FEELIT_FOBJDATAFMT_BUTTON 0x0000000C + +#define FEELIT_FOBJDATAFMT_POV 0x00000010 + +#define FEELIT_FOBJDATAFMT_COLLECTION 0x00000040 +#define FEELIT_FOBJDATAFMT_NODATA 0x00000080 +#define FEELIT_FOBJDATAFMT_FFACTUATOR 0x01000000 +#define FEELIT_FOBJDATAFMT_FFEFFECTTRIGGER 0x02000000 +#define FEELIT_FOBJDATAFMT_NOCOLLECTION 0x00FFFF00 + +#define FEELIT_FOBJDATAFMT_ANYINSTANCE 0x00FFFF00 +#define FEELIT_FOBJDATAFMT_INSTANCEMASK FEELIT_FOBJDATAFMT_ANYINSTANCE + + +/* Data Format Type Macros */ +#define FEELIT_OBJDATAFMT_MAKEINSTANCE(n) ((WORD)(n) << 8) +#define FEELIT_OBJDATAFMT_GETTYPE(n) LOBYTE(n) +#define FEELIT_OBJDATAFMT_GETINSTANCE(n) LOWORD((n) >> 8) +#define FEELIT_OBJDATAFMT_ENUMCOLLECTION(n) ((WORD)(n) << 8) + + +typedef struct _FEELIT_OBJECTDATAFORMAT { + const GUID *pguid; /* Unique ID for the axis, button, or other input source. */ + DWORD dwOfs; /* Offset in data packet where input source data is stored */ + DWORD dwType; /* Device type describing the object. (FEELIT_FOBJDATAFMT_*) */ + DWORD dwFlags; /* Aspect flags. Zero or more of FEELIT_FDEVOBJINST_ASPECT* */ +} FEELIT_OBJECTDATAFORMAT, *LPFEELIT_OBJECTDATAFORMAT; +typedef const FEELIT_OBJECTDATAFORMAT *LPCFEELIT_OBJECTDATAFORMAT; + +typedef struct _FEELIT_DATAFORMAT { + DWORD dwSize; /* sizeof( FEELIT_DATAFORMAT ) */ + DWORD dwObjSize; /* sizeof( FEELIT_OBJECTDATAFORMAT ) */ + DWORD dwFlags; /* One of FEELIT_FDATAFORMAT_* */ + DWORD dwDataSize; /* Size, in bytes, of data packet returned by the device */ + DWORD dwNumObjs; /* Number of object in the rgodf array */ + LPFEELIT_OBJECTDATAFORMAT rgodf; /* Ptr to array of FEELIT_OBJECTDATAFORMAT */ +} FEELIT_DATAFORMAT, *LPFEELIT_DATAFORMAT; +typedef const FEELIT_DATAFORMAT *LPCFEELIT_DATAFORMAT; + +/* Data Format Flags */ +#define FEELIT_FDATAFORMAT_ABSAXIS 0x00000001 +#define FEELIT_FDATAFORMAT_RELAXIS 0x00000002 + +/* Predefined Data Formats */ +extern const FEELIT_DATAFORMAT c_dfFeelitMouse; + +typedef struct FEELIT_DEVICEOBJECTINSTANCE { + DWORD dwSize; /* sizeof( FEELIT_DEVICEOBJECTINSTANCE ) */ + GUID guidType; /* Optional unique ID indicating object type */ + DWORD dwOfs; /* Offset within data format for data from this object */ + DWORD dwType; /* Device type describing the object. (FEELIT_FOBJDATAFMT_*) */ + DWORD dwFlags; /* Zero or more of FEELIT_FDEVOBJINST_* */ + CHAR tszName[MAX_PATH]; /* Name of object (e.g. "X-Axis") */ + DWORD dwFFMaxForce; /* Mag. of max force created by actuator for this object */ + DWORD dwFFForceResolution; /* Force resolution of the actuator for this object */ + WORD wCollectionNumber; /* RESERVED */ + WORD wDesignatorIndex; /* RESERVED */ + WORD wUsagePage; /* HID usage page associated with the object */ + WORD wUsage; /* HID usage associated with the object */ + DWORD dwDimension; /* Dimensional units in which object's value is reported */ + WORD wExponent; /* Exponent to associate with the demension */ + WORD wReserved; +} FEELIT_DEVICEOBJECTINSTANCE, *LPFEELIT_DEVICEOBJECTINSTANCE; +typedef const FEELIT_DEVICEOBJECTINSTANCE *LPCFEELIT_DEVICEOBJECTINSTANCE; + +typedef BOOL (FAR PASCAL * LPFEELIT_ENUMDEVICEOBJECTSCALLBACK)(LPCFEELIT_DEVICEOBJECTINSTANCE, LPVOID); + +/* Device Object Instance Flags */ +#define FEELIT_FDEVOBJINST_FFACTUATOR 0x00000001 +#define FEELIT_FDEVOBJINST_FFEFFECTTRIGGER 0x00000002 +#define FEELIT_FDEVOBJINST_POLLED 0x00008000 +#define FEELIT_FDEVOBJINST_ASPECTPOSITION 0x00000100 +#define FEELIT_FDEVOBJINST_ASPECTVELOCITY 0x00000200 +#define FEELIT_FDEVOBJINST_ASPECTACCEL 0x00000300 +#define FEELIT_FDEVOBJINST_ASPECTFORCE 0x00000400 +#define FEELIT_FDEVOBJINST_ASPECTMASK 0x00000F00 + +typedef struct FEELIT_PROPHEADER { + DWORD dwSize; /* Size of enclosing struct, to which this struct is header */ + DWORD dwHeaderSize; /* sizeof ( FEELIT_PROPHEADER ) */ + DWORD dwObj; /* Object for which the property is to be accessed */ + DWORD dwHow; /* Specifies how dwObj is interpreted. ( FEELIT_FPROPHEADER_* ) */ +} FEELIT_PROPHEADER, *LPFEELIT_PROPHEADER; +typedef const FEELIT_PROPHEADER *LPCFEELIT_PROPHEADER; + +/* Prop header flags */ +#define FEELIT_FPROPHEADER_DEVICE 0 +#define FEELIT_FPROPHEADER_BYOFFSET 1 +#define FEELIT_FPROPHEADER_BYID 2 + +typedef struct FEELIT_PROPDWORD { + FEELIT_PROPHEADER feelitph; /* Feelit property header struct */ + DWORD dwData; /* Property-specific value being retrieved */ +} FEELIT_PROPDWORD, *LPFEELIT_PROPDWORD; +typedef const FEELIT_PROPDWORD *LPCFEELIT_PROPDWORD; + +typedef struct FEELIT_PROPRANGE { + FEELIT_PROPHEADER feelitph; /* Feelit property header struct */ + LONG lMin; /* Lower limit of range, inclusive */ + LONG lMax; /* Upper limit of range, inclusive */ +} FEELIT_PROPRANGE, *LPFEELIT_PROPRANGE; +typedef const FEELIT_PROPRANGE *LPCFEELIT_PROPRANGE; + +#define FEELIT_PROPRANGE_NOMIN ((LONG)0x80000000) +#define FEELIT_PROPRANGE_NOMAX ((LONG)0x7FFFFFFF) + + +#ifdef __cplusplus +#define MAKE_FEELIT_PROP(prop) (*(const GUID *)(prop)) +#else +#define MAKE_FEELIT_PROP(prop) ((REFGUID)(prop)) +#endif + +#define FEELIT_PROP_BUFFERSIZE MAKE_FEELIT_PROP(1) +#define FEELIT_PROP_AXISMODE MAKE_FEELIT_PROP(2) +#define FEELIT_PROP_GRANULARITY MAKE_FEELIT_PROP(3) +#define FEELIT_PROP_RANGE MAKE_FEELIT_PROP(4) +#define FEELIT_PROP_DEADZONE MAKE_FEELIT_PROP(5) +#define FEELIT_PROP_SATURATION MAKE_FEELIT_PROP(6) +#define FEELIT_PROP_FFGAIN MAKE_FEELIT_PROP(7) +#define FEELIT_PROP_FFLOAD MAKE_FEELIT_PROP(8) +#define FEELIT_PROP_AUTOCENTER MAKE_FEELIT_PROP(9) +#define FEELIT_PROP_CALIBRATIONMODE MAKE_FEELIT_PROP(10) +#define FEELIT_PROP_DEVICEGAIN MAKE_FEELIT_PROP(11) +#define FEELIT_PROP_BALLISTICS MAKE_FEELIT_PROP(12) +#define FEELIT_PROP_SCREENSIZE MAKE_FEELIT_PROP(13) +#define FEELIT_PROP_ABSOLUTEMODE MAKE_FEELIT_PROP(14) +#define FEELIT_PROP_DEVICEMODE MAKE_FEELIT_PROP(15) +#define FEELIT_PROP_NUMEFFECTS MAKE_FEELIT_PROP(16) +#define FEELIT_PROP_DEVICEID MAKE_FEELIT_PROP(17) + +#define FEELIT_PROPAXISMODE_ABS 0 +#define FEELIT_PROPAXISMODE_REL 1 + +#define FEELIT_PROPAUTOCENTER_OFF 0 +#define FEELIT_PROPAUTOCENTER_ON 1 + +#define FEELIT_PROPCALIBRATIONMODE_COOKED 0 +#define FEELIT_PROPCALIBRATIONMODE_RAW 1 + +// Device configuration/control, for use by control panels +typedef struct FEELIT_PROPBALLISTICS { + FEELIT_PROPHEADER feelitph; /* Feelit property header struct */ + INT Sensitivity; /* Property-specific value */ + INT LowThreshhold; /* Property-specific value */ + INT HighThreshhold; /* Property-specific value */ +} FEELIT_PROPBALLISTICS, *LPFEELIT_PROPBALLISTICS; +typedef const FEELIT_PROPBALLISTICS *LPCFEELIT_PROPBALLISTICS; + +typedef struct FEELIT_PROPSCREENSIZE { + FEELIT_PROPHEADER feelitph; /* Feelit property header struct */ + DWORD dwXScreenSize; /* Max X screen coord value */ + DWORD dwYScreenSize; /* Max Y screen coord value */ +} FEELIT_PROPSCREENSIZE, *LPFEELIT_PROPSCREENSIZE; +typedef const FEELIT_PROPSCREENSIZE *LPCFEELIT_PROPSCREENSIZE; + +typedef struct FEELIT_PROPABSOLUTEMODE { + FEELIT_PROPHEADER feelitph; /* Feelit property header struct */ + BOOL bAbsMode; /* TRUE for Absolute mode FALSE for Relative mode */ +} FEELIT_PROPABSOLUTEMODE, *LPFEELIT_PROPABSOLUTEMODE; +typedef const FEELIT_PROPABSOLUTEMODE *LPCFEELIT_PROPABSOLUTEMODE; + +#define FEELIT_PROPDEVICEMODE_MOUSE 1 +#define FEELIT_PROPDEVICEMODE_JOYSTICK 2 + +// Number of effects. This is the number of effects (not the number of effect types) +// that can be downloaded to a device. dwTotalEffects includes any caching cababilities +// of the driver. dwHardwareEffects is strictly the number of effects that can be +// stored in the device hardware. Pay attention to dwHardwareEffects only if you're +// worried about optimizing for speed. +typedef struct FEELIT_PROPNUMEFFECTS { + FEELIT_PROPHEADER feelitph; /* Feelit property header struct */ + DWORD dwTotalEffects; /* Total number of effects a device driver can support */ + DWORD dwHardwareEffects; /* Number of effects the device hardware can hold */ +} FEELIT_PROPNUMEFFECTS, *LPFEELIT_PROPNUMEFFECTS; +typedef const FEELIT_PROPNUMEFFECTS *LPCFEELIT_PROPNUMEFFECTS; + + +typedef struct FEELIT_DEVICEOBJECTDATA { + DWORD dwOfs; /* Offset into current data format of this data's object */ + DWORD dwData; /* Data obtained from the device */ + DWORD dwTimeStamp; /* Tick count, in milliseconds, at which event was generated */ + DWORD dwSequence; /* Sequence number for this event */ +} FEELIT_DEVICEOBJECTDATA, *LPFEELIT_DEVICEOBJECTDATA; +typedef const FEELIT_DEVICEOBJECTDATA *LPCFEELIT_DEVICEOBJECTDATA; + +#define FEELIT_SEQUENCE_COMPARE(dwSequence1, cmp, dwSequence2) \ + ((int)((dwSequence1) - (dwSequence2)) cmp 0) + +/* GetDeviceData Flags */ +#define FEELIT_FGETDEVDATA_PEEK 0x00000001 + +/* Cooperative Level Flags */ +#define FEELIT_FCOOPLEVEL_EXCLUSIVE 0x00000001 +#define FEELIT_FCOOPLEVEL_NONEXCLUSIVE 0x00000002 +#define FEELIT_FCOOPLEVEL_FOREGROUND 0x00000004 +#define FEELIT_FCOOPLEVEL_BACKGROUND 0x00000008 + +typedef struct FEELIT_DEVICEINSTANCE { + DWORD dwSize; /* sizeof ( FEELIT_DEVICEINSTANCE ) */ + GUID guidInstance; /* Unique id for instance of device */ + GUID guidProduct; /* Unique id for the product */ + DWORD dwDevType; /* Device type (FEELIT_DEVICETYPE*) */ + CHAR tszInstanceName[MAX_PATH]; /* Friendly name for the instance (e.g. "Feelit Mouse 1") */ + CHAR tszProductName[MAX_PATH]; /* Friendly name for the product (e.g. "Feelit Mouse") */ + GUID guidFFDriver; /* Unique id for the driver being used for force feedback */ + WORD wUsagePage; /* HID usage page code (if the device driver is a HID device) */ + WORD wUsage; /* HID usage code (if the device driver is a HID device) */ +} FEELIT_DEVICEINSTANCE, *LPFEELIT_DEVICEINSTANCE; +typedef const FEELIT_DEVICEINSTANCE *LPCFEELIT_DEVICEINSTANCE; + +#define FEELIT_FCOMMAND_RESET 0x00000001 +#define FEELIT_FCOMMAND_STOPALL 0x00000002 +#define FEELIT_FCOMMAND_PAUSE 0x00000004 +#define FEELIT_FCOMMAND_CONTINUE 0x00000008 +#define FEELIT_FCOMMAND_SETACTUATORSON 0x00000010 +#define FEELIT_FCOMMAND_SETACTUATORSOFF 0x00000020 + +#define FEELIT_FDEVICESTATE_EMPTY 0x00000001 +#define FEELIT_FDEVICESTATE_STOPPED 0x00000002 +#define FEELIT_FDEVICESTATE_PAUSED 0x00000004 +#define FEELIT_FDEVICESTATE_ACTUATORSON 0x00000010 +#define FEELIT_FDEVICESTATE_ACTUATORSOFF 0x00000020 +#define FEELIT_FDEVICESTATE_POWERON 0x00000040 +#define FEELIT_FDEVICESTATE_POWEROFF 0x00000080 +#define FEELIT_FDEVICESTATE_SAFETYSWITCHON 0x00000100 +#define FEELIT_FDEVICESTATE_SAFETYSWITCHOFF 0x00000200 +#define FEELIT_FDEVICESTATE_USERFFSWITCHON 0x00000400 +#define FEELIT_FDEVICESTATE_USERFFSWITCHOFF 0x00000800 +#define FEELIT_FDEVICESTATE_DEVICELOST 0x80000000 + +typedef struct FEELIT_EFFECTINFO { + DWORD dwSize; /* sizeof( FEELIT_EFFECTINFO ) */ + GUID guid; /* Unique ID of the effect */ + DWORD dwEffType; /* Zero or more of FEELIT_FEFFECTTYPE_* */ + DWORD dwStaticParams; /* All params supported. Zero or more of FEELIT_FPARAM_* */ + DWORD dwDynamicParams; /* Params modifiable while effect playing. (FEELIT_FPARAM_*) */ + CHAR tszName[MAX_PATH]; /* Name of effect (e.g. "Enclosure" ) */ +} FEELIT_EFFECTINFO, *LPFEELIT_EFFECTINFO; +typedef const FEELIT_EFFECTINFO *LPCFEELIT_EFFECTINFO; + +typedef BOOL (FAR PASCAL * LPFEELIT_ENUMEFFECTSCALLBACK)(LPCFEELIT_EFFECTINFO, LPVOID); +typedef BOOL (FAR PASCAL * LPFEELIT_ENUMCREATEDEFFECTOBJECTSCALLBACK)(LPFEELIT_EFFECT, LPVOID); + + +/* + Feelit Events + +Feelit events are defined using a FEELIT_EVENT struct. They are created by +passing the struct to CreateFeelitEvent, which returns an HFEELITEVENT handle. +Feelit notifies clients that Feelit Event has triggered by sending a message to +the window handle associated with the event. Window handles are associated with +events using the hWndEventHandler param. of the FEELIT_EVENT struct. The window +message that Feelit sends to notify of an event, contains information in the +WPARAM and LPARAM as described below. + +DURING INITIALIZATION: +const UINT g_wmFeelitEvent = RegisterWindowMessage( FEELIT_EVENT_MSG_STRING ); + +IN MESSAGE LOOP: +if ( msgID == g_wmFeelitEvent ) +{ + WORD wRef = LOWORD(wParam); // 16-bit app-defined event id + WORD wfTriggers = HIWORD(wParam); // Trigger Flags + short xForce = (short) LOWORD(lParam); // Force applied along X-axis + short yForce = (short) HIWORD(lParam); // Force applied along Y-axis +} + +*/ + +#define FEELIT_EVENT_MSG_STRING "FEELIT_EVENT_MSG" + +typedef HANDLE HFEELITEVENT, *LPHFEELITEVENT; /* Handle type used to manage Feelit Events */ + +typedef struct FEELIT_EVENT { + DWORD dwSize; /* sizeof(FEELIT_EVENT) */ + HWND hWndEventHandler; /* Handle of window to which event msgs are sent */ + WORD wRef; /* 16-bit app-defined value to identify the event to the app */ + DWORD dwEventTriggerMask; /* Mask specifying events which trigger the callback (FEELIT_FTRIG*) */ + LPIFEELIT_EFFECT piEffect; /* Effect, if any, that this event is associated with */ +} FEELIT_EVENT, *LPFEELIT_EVENT; + +typedef const FEELIT_EVENT *LPCFEELIT_EVENT; + + +/* Event Trigger Flags */ + +#define FEELIT_FTRIG_NONE 0x00000000 +#define FEELIT_FTRIG_ENTER 0x00000001 +#define FEELIT_FTRIG_EXIT 0x00000002 +#define FEELIT_FTRIG_OUTER 0x00000004 +#define FEELIT_FTRIG_INBOUND FEELIT_FTRIG_OUTER +#define FEELIT_FTRIG_INNER 0x00000008 +#define FEELIT_FTRIG_OUTBOUND FEELIT_FTRIG_INNER +#define FEELIT_FTRIG_TOPWALL 0x00000010 +#define FEELIT_FTRIG_BOTTOMWALL 0x00000020 +#define FEELIT_FTRIG_LEFTWALL 0x00000040 +#define FEELIT_FTRIG_RIGHTWALL 0x00000080 +#define FEELIT_FTRIG_ANYWALL ( FEELIT_FTRIG_TOPWALL | FEELIT_FTRIG_BOTTOMWALL | FEELIT_FTRIG_LEFTWALL | FEELIT_FTRIG_RIGHTWALL ) +#define FEELIT_FTRIG_ONENTERANY ( FEELIT_FTRIG_ENTER | FEELIT_FTRIG_ANYWALL ) +#define FEELIT_FTRIG_ONEXITANY ( FEELIT_FTRIG_EXIT | FEELIT_FTRIG_ANYWALL ) +#define FEELIT_FTRIG_ONOUTERANY ( FEELIT_FTRIG_OUTER | FEELIT_FTRIG_ANYWALL ) +#define FEELIT_FTRIG_ONINBOUNDANY FEELIT_FTRIG_ONOUTERANY +#define FEELIT_FTRIG_ONINNERANY ( FEELIT_FTRIG_INNER | FEELIT_FTRIG_ANYWALL ) +#define FEELIT_FTRIG_ONOUTBOUNDANY FEELIT_FTRIG_ONINNERANY +#define FEELIT_FTRIG_ONANYENCLOSURE ( FEELIT_FTRIG_ONENTERANY | FEELIT_FTRIG_ONEXITANY | FEELIT_FTRIG_ONOUTERANY | FEELIT_FTRIG_ONINNERANY ) + +#define FEELIT_FTRIG_ONSCROLL 0x0000100 +#define FEELIT_FTRIG_ONEFFECTCOMPLETION 0x0000200 + +#undef INTERFACE +#define INTERFACE IFeelitDevice + +DECLARE_INTERFACE_(IFeelitDevice, IUnknown) +{ + /*** IUnknown methods ***/ + STDMETHOD(QueryInterface)(THIS_ REFIID riid, LPVOID * ppvObj) PURE; + STDMETHOD_(ULONG,AddRef)(THIS) PURE; + STDMETHOD_(ULONG,Release)(THIS) PURE; + + /*** IFeelitDevice methods ***/ + STDMETHOD(GetCapabilities)(THIS_ LPFEELIT_DEVCAPS) PURE; + STDMETHOD(EnumObjects)(THIS_ LPFEELIT_ENUMDEVICEOBJECTSCALLBACK,LPVOID,DWORD) PURE; + STDMETHOD(GetProperty)(THIS_ REFGUID,LPFEELIT_PROPHEADER) PURE; + STDMETHOD(SetProperty)(THIS_ REFGUID,LPCFEELIT_PROPHEADER) PURE; + STDMETHOD(Acquire)(THIS) PURE; + STDMETHOD(Unacquire)(THIS) PURE; + STDMETHOD(GetDeviceState)(THIS_ DWORD,LPVOID) PURE; + STDMETHOD(GetDeviceData)(THIS_ DWORD,LPFEELIT_DEVICEOBJECTDATA,LPDWORD,DWORD) PURE; + STDMETHOD(SetDataFormat)(THIS_ LPCFEELIT_DATAFORMAT) PURE; + STDMETHOD(SetEventNotification)(THIS_ HANDLE) PURE; + STDMETHOD(SetCooperativeLevel)(THIS_ HWND,DWORD) PURE; + STDMETHOD(GetObjectInfo)(THIS_ LPFEELIT_DEVICEOBJECTINSTANCE,DWORD,DWORD) PURE; + STDMETHOD(GetDeviceInfo)(THIS_ LPFEELIT_DEVICEINSTANCE) PURE; + STDMETHOD(RunControlPanel)(THIS_ HWND,DWORD) PURE; + STDMETHOD(CreateEffect)(THIS_ LPCFEELIT_EFFECT,LPIFEELIT_EFFECT *,LPUNKNOWN) PURE; + STDMETHOD(EnumEffects)(THIS_ LPFEELIT_ENUMEFFECTSCALLBACK,LPVOID,DWORD) PURE; + STDMETHOD(GetEffectInfo)(THIS_ LPFEELIT_EFFECTINFO,REFGUID) PURE; + STDMETHOD(GetForceFeedbackState)(THIS_ LPDWORD) PURE; + STDMETHOD(SendForceFeedbackCommand)(THIS_ DWORD) PURE; + STDMETHOD(EnumCreatedEffectObjects)(THIS_ LPFEELIT_ENUMCREATEDEFFECTOBJECTSCALLBACK,LPVOID,DWORD) PURE; + STDMETHOD(Escape)(THIS_ LPFEELIT_EFFESCAPE) PURE; + STDMETHOD(Poll)(THIS) PURE; + STDMETHOD(SendDeviceData)(THIS_ DWORD,LPFEELIT_DEVICEOBJECTDATA,LPDWORD,DWORD) PURE; + STDMETHOD(CreateFeelitEvent)(THIS_ LPCFEELIT_EVENT,LPHFEELITEVENT) PURE; + STDMETHOD(DestroyFeelitEvent)(THIS_ HFEELITEVENT) PURE; + STDMETHOD(EnableFeelitEvent)(THIS_ HFEELITEVENT,BOOL) PURE; + STDMETHOD(SetEventNotificationPeriodicity)(THIS_ DWORD) PURE; +}; + +typedef struct IFeelitDevice *LPIFEELIT_DEVICE; + +#if !defined(__cplusplus) || defined(CINTERFACE) +#define IFeelitDevice_QueryInterface(p,a,b) (p)->lpVtbl->QueryInterface(p,a,b) +#define IFeelitDevice_AddRef(p) (p)->lpVtbl->AddRef(p) +#define IFeelitDevice_Release(p) (p)->lpVtbl->Release(p) +#define IFeelitDevice_GetCapabilities(p,a) (p)->lpVtbl->GetCapabilities(p,a) +#define IFeelitDevice_EnumObjects(p,a,b,c) (p)->lpVtbl->EnumObjects(p,a,b,c) +#define IFeelitDevice_GetProperty(p,a,b) (p)->lpVtbl->GetProperty(p,a,b) +#define IFeelitDevice_SetProperty(p,a,b) (p)->lpVtbl->SetProperty(p,a,b) +#define IFeelitDevice_Acquire(p) (p)->lpVtbl->Acquire(p) +#define IFeelitDevice_Unacquire(p) (p)->lpVtbl->Unacquire(p) +#define IFeelitDevice_GetDeviceState(p,a,b) (p)->lpVtbl->GetDeviceState(p,a,b) +#define IFeelitDevice_GetDeviceData(p,a,b,c,d) (p)->lpVtbl->GetDeviceData(p,a,b,c,d) +#define IFeelitDevice_SetDataFormat(p,a) (p)->lpVtbl->SetDataFormat(p,a) +#define IFeelitDevice_SetEventNotification(p,a) (p)->lpVtbl->SetEventNotification(p,a) +#define IFeelitDevice_SetCooperativeLevel(p,a,b) (p)->lpVtbl->SetCooperativeLevel(p,a,b) +#define IFeelitDevice_GetObjectInfo(p,a,b,c) (p)->lpVtbl->GetObjectInfo(p,a,b,c) +#define IFeelitDevice_GetDeviceInfo(p,a) (p)->lpVtbl->GetDeviceInfo(p,a) +#define IFeelitDevice_RunControlPanel(p,a,b) (p)->lpVtbl->RunControlPanel(p,a,b) +#define IFeelitDevice_CreateEffect(p,a,b,c,d) (p)->lpVtbl->CreateEffect(p,a,b,c,d) +#define IFeelitDevice_EnumEffects(p,a,b,c) (p)->lpVtbl->EnumEffects(p,a,b,c) +#define IFeelitDevice_GetEffectInfo(p,a,b) (p)->lpVtbl->GetEffectInfo(p,a,b) +#define IFeelitDevice_GetForceFeedbackState(p,a) (p)->lpVtbl->GetForceFeedbackState(p,a) +#define IFeelitDevice_SendForceFeedbackCommand(p,a) (p)->lpVtbl->SendForceFeedbackCommand(p,a) +#define IFeelitDevice_EnumCreatedEffectObjects(p,a,b,c) (p)->lpVtbl->EnumCreatedEffectObjects(p,a,b,c) +#define IFeelitDevice_Escape(p,a) (p)->lpVtbl->Escape(p,a) +#define IFeelitDevice_Poll(p) (p)->lpVtbl->Poll(p) +#define IFeelitDevice_SendDeviceData(p,a,b,c,d) (p)->lpVtbl->SendDeviceData(p,a,b,c,d) +#define IFeelitDevice_CreateFeelitEvent(p,a,b) (p)->lpVtbl->CreateFeelitEvent(p,a,b) +#define IFeelitDevice_DestroyFeelitEvent(p,a) (p)->lpVtbl->DestroyFeelitEvent(p,a) +#define IFeelitDevice_EnableFeelitEvent(p,a,b) (p)->lpVtbl->EnableFeelitEvent(p,a,b) +#define IFeelitDevice_SetEventNotificationPeriodicity(p,a) (p)->lpVtbl->SetEventNotificationPeriodicity(p,a) +#else +#define IFeelitDevice_QueryInterface(p,a,b) (p)->QueryInterface(a,b) +#define IFeelitDevice_AddRef(p) (p)->AddRef() +#define IFeelitDevice_Release(p) (p)->Release() +#define IFeelitDevice_GetCapabilities(p,a) (p)->GetCapabilities(a) +#define IFeelitDevice_EnumObjects(p,a,b,c) (p)->EnumObjects(a,b,c) +#define IFeelitDevice_GetProperty(p,a,b) (p)->GetProperty(a,b) +#define IFeelitDevice_SetProperty(p,a,b) (p)->SetProperty(a,b) +#define IFeelitDevice_Acquire(p) (p)->Acquire() +#define IFeelitDevice_Unacquire(p) (p)->Unacquire() +#define IFeelitDevice_GetDeviceState(p,a,b) (p)->GetDeviceState(a,b) +#define IFeelitDevice_GetDeviceData(p,a,b,c,d) (p)->GetDeviceData(a,b,c,d) +#define IFeelitDevice_SetDataFormat(p,a) (p)->SetDataFormat(a) +#define IFeelitDevice_SetEventNotification(p,a) (p)->SetEventNotification(a) +#define IFeelitDevice_SetCooperativeLevel(p,a,b) (p)->SetCooperativeLevel(a,b) +#define IFeelitDevice_GetObjectInfo(p,a,b,c) (p)->GetObjectInfo(a,b,c) +#define IFeelitDevice_GetDeviceInfo(p,a) (p)->GetDeviceInfo(a) +#define IFeelitDevice_RunControlPanel(p,a,b) (p)->RunControlPanel(a,b) +#define IFeelitDevice_CreateEffect(p,a,b,c,d) (p)->CreateEffect(a,b,c,d) +#define IFeelitDevice_EnumEffects(p,a,b,c) (p)->EnumEffects(a,b,c) +#define IFeelitDevice_GetEffectInfo(p,a,b) (p)->GetEffectInfo(a,b) +#define IFeelitDevice_GetForceFeedbackState(p,a) (p)->GetForceFeedbackState(a) +#define IFeelitDevice_SendForceFeedbackCommand(p,a) (p)->SendForceFeedbackCommand(a) +#define IFeelitDevice_EnumCreatedEffectObjects(p,a,b,c) (p)->EnumCreatedEffectObjects(a,b,c) +#define IFeelitDevice_Escape(p,a) (p)->Escape(a) +#define IFeelitDevice_Poll(p) (p)->Poll() +#define IFeelitDevice_SendDeviceData(p,a,b,c,d) (p)->SendDeviceData(a,b,c,d) +#define IFeelitDevice_CreateFeelitEvent(p,a,b) (p)->CreateFeelitEvent(a,b) +#define IFeelitDevice_DestroyFeelitEvent(p,a) (p)->DestroyFeelitEvent(a) +#define IFeelitDevice_EnableFeelitEvent(p,a,b) (p)->EnableFeelitEvent(a,b) +#define IFeelitDevice_SetEventNotificationPeriodicity(p,a) (p)->SetEventNotificationPeriodicity(a) +#endif + +/**************************************************************************** + * + * Mouse State + * + ****************************************************************************/ + +typedef struct _FEELIT_MOUSESTATE { + LONG lXpos; + LONG lYpos; + LONG lZpos; + LONG lXforce; + LONG lYforce; + LONG lZforce; + BYTE rgbButtons[4]; +} FEELIT_MOUSESTATE, *LPFEELIT_MOUSESTATE; + +#define FEELIT_MOUSEOFFSET_XAXIS FIELD_OFFSET(FEELIT_MOUSESTATE, lXpos) +#define FEELIT_MOUSEOFFSET_YAXIS FIELD_OFFSET(FEELIT_MOUSESTATE, lYpos) +#define FEELIT_MOUSEOFFSET_ZAXIS FIELD_OFFSET(FEELIT_MOUSESTATE, lZpos) +#define FEELIT_MOUSEOFFSET_XFORCE FIELD_OFFSET(FEELIT_MOUSESTATE, lXforce) +#define FEELIT_MOUSEOFFSET_YFORCE FIELD_OFFSET(FEELIT_MOUSESTATE, lYforce) +#define FEELIT_MOUSEOFFSET_ZFORCE FIELD_OFFSET(FEELIT_MOUSESTATE, lZforce) +#define FEELIT_MOUSEOFFSET_BUTTON0 (FIELD_OFFSET(FEELIT_MOUSESTATE, rgbButtons) + 0) +#define FEELIT_MOUSEOFFSET_BUTTON1 (FIELD_OFFSET(FEELIT_MOUSESTATE, rgbButtons) + 1) +#define FEELIT_MOUSEOFFSET_BUTTON2 (FIELD_OFFSET(FEELIT_MOUSESTATE, rgbButtons) + 2) +#define FEELIT_MOUSEOFFSET_BUTTON3 (FIELD_OFFSET(FEELIT_MOUSESTATE, rgbButtons) + 3) + + +/**************************************************************************** + * + * IFeelit + * + ****************************************************************************/ + +#define FEELIT_ENUM_STOP 0 +#define FEELIT_ENUM_CONTINUE 1 + +typedef BOOL (FAR PASCAL * LPFEELIT_ENUMDEVICESCALLBACK)(LPCFEELIT_DEVICEINSTANCE, LPVOID); + +#define FEELIT_FENUMDEV_ALLDEVICES 0x00000000 +#define FEELIT_FENUMDEV_ATTACHEDONLY 0x00000001 +#define FEELIT_FENUMDEV_FORCEFEEDBACK 0x00000100 + +#undef INTERFACE +#define INTERFACE IFeelit + +DECLARE_INTERFACE_(IFeelit, IUnknown) +{ + /*** IUnknown methods ***/ + STDMETHOD(QueryInterface)(THIS_ REFIID riid, LPVOID * ppvObj) PURE; + STDMETHOD_(ULONG,AddRef)(THIS) PURE; + STDMETHOD_(ULONG,Release)(THIS) PURE; + + /*** IFeelit methods ***/ + STDMETHOD(CreateDevice)(THIS_ REFGUID,LPIFEELIT_DEVICE *,LPUNKNOWN) PURE; + STDMETHOD(EnumDevices)(THIS_ DWORD,LPFEELIT_ENUMDEVICESCALLBACK,LPVOID,DWORD) PURE; + STDMETHOD(GetDeviceStatus)(THIS_ REFGUID) PURE; + STDMETHOD(RunControlPanel)(THIS_ HWND,DWORD) PURE; + STDMETHOD(Initialize)(THIS_ HINSTANCE,DWORD) PURE; +}; + +typedef struct IFeelit *LPIFEELIT; + +#if !defined(__cplusplus) || defined(CINTERFACE) +#define IFeelit_QueryInterface(p,a,b) (p)->lpVtbl->QueryInterface(p,a,b) +#define IFeelit_AddRef(p) (p)->lpVtbl->AddRef(p) +#define IFeelit_Release(p) (p)->lpVtbl->Release(p) +#define IFeelit_CreateDevice(p,a,b,c) (p)->lpVtbl->CreateDevice(p,a,b,c) +#define IFeelit_EnumDevices(p,a,b,c,d) (p)->lpVtbl->EnumDevices(p,a,b,c,d) +#define IFeelit_GetDeviceStatus(p,a) (p)->lpVtbl->GetDeviceStatus(p,a) +#define IFeelit_RunControlPanel(p,a,b) (p)->lpVtbl->RunControlPanel(p,a,b) +#define IFeelit_Initialize(p,a,b) (p)->lpVtbl->Initialize(p,a,b) +#define IFeelit_FindDevice(p,a,b,c) (p)->lpVtbl->FindDevice(p,a,b,c) +#endif + +extern HRESULT WINAPI FeelitCreateA(HINSTANCE hinst, DWORD dwVersion, LPIFEELIT *ppFeelit, LPUNKNOWN punkOuter); +#define FeelitCreate FeelitCreateA + + +/**************************************************************************** + * + * Return Codes + * + ****************************************************************************/ + +/* + * The operation completed successfully. + */ +#define FEELIT_RESULT_OK S_OK + +/* + * The device exists but is not currently attached. + */ +#define FEELIT_RESULT_NOTATTACHED S_FALSE + +/* + * The device buffer overflowed. Some input was lost. + */ +#define FEELIT_RESULT_BUFFEROVERFLOW S_FALSE + +/* + * The change in device properties had no effect. + */ +#define FEELIT_RESULT_PROPNOEFFECT S_FALSE + +/* + * The operation had no effect. + */ +#define FEELIT_RESULT_NOEFFECT S_FALSE + +/* + * The device is a polled device. As a result, device buffering + * will not collect any data and event notifications will not be + * signalled until GetDeviceState is called. + */ +#define FEELIT_RESULT_POLLEDDEVICE ((HRESULT)0x00000002L) + +/* + * The parameters of the effect were successfully updated by + * IFeelitEffect::SetParameters, but the effect was not + * downloaded because the device is not exclusively acquired + * or because the FEELIT_FPARAM_NODOWNLOAD flag was passed. + */ +#define FEELIT_RESULT_DOWNLOADSKIPPED ((HRESULT)0x00000003L) + +/* + * The parameters of the effect were successfully updated by + * IFeelitEffect::SetParameters, but in order to change + * the parameters, the effect needed to be restarted. + */ +#define FEELIT_RESULT_EFFECTRESTARTED ((HRESULT)0x00000004L) + +/* + * The parameters of the effect were successfully updated by + * IFeelitEffect::SetParameters, but some of them were + * beyond the capabilities of the device and were truncated. + */ +#define FEELIT_RESULT_TRUNCATED ((HRESULT)0x00000008L) + +/* + * Equal to FEELIT_RESULT_EFFECTRESTARTED | FEELIT_RESULT_TRUNCATED. + */ +#define FEELIT_RESULT_TRUNCATEDANDRESTARTED ((HRESULT)0x0000000CL) + +/* + * The application requires a newer version of Feelit. + */ +#define FEELIT_ERROR_OLDFEELITVERSION \ + MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_OLD_WIN_VERSION) + +/* + * The application was written for an unsupported prerelease version + * of Feelit. + */ +#define FEELIT_ERROR_BETAFEELITVERSION \ + MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_RMODE_APP) + +/* + * The object could not be created due to an incompatible driver version + * or mismatched or incomplete driver components. + */ +#define FEELIT_ERROR_BADDRIVERVER \ + MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_BAD_DRIVER_LEVEL) + +/* + * The device or device instance or effect is not registered with Feelit. + */ +#define FEELIT_ERROR_DEVICENOTREG REGDB_E_CLASSNOTREG + +/* + * The requested object does not exist. + */ +#define FEELIT_ERROR_NOTFOUND \ + MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_FILE_NOT_FOUND) + +/* + * The requested object does not exist. + */ +#define FEELIT_ERROR_OBJECTNOTFOUND \ + MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_FILE_NOT_FOUND) + +/* + * An invalid parameter was passed to the returning function, + * or the object was not in a state that admitted the function + * to be called. + */ +#define FEELIT_ERROR_INVALIDPARAM E_INVALIDARG + +/* + * The specified interface is not supported by the object + */ +#define FEELIT_ERROR_NOINTERFACE E_NOINTERFACE + +/* + * An undetermined error occured inside the Feelit subsystem + */ +#define FEELIT_ERROR_GENERIC E_FAIL + +/* + * The Feelit subsystem couldn't allocate sufficient memory to complete the + * caller's request. + */ +#define FEELIT_ERROR_OUTOFMEMORY E_OUTOFMEMORY + +/* + * The function called is not supported at this time + */ +#define FEELIT_ERROR_UNSUPPORTED E_NOTIMPL + +/* + * This object has not been initialized + */ +#define FEELIT_ERROR_NOTINITIALIZED \ + MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_NOT_READY) + +/* + * This object is already initialized + */ +#define FEELIT_ERROR_ALREADYINITIALIZED \ + MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_ALREADY_INITIALIZED) + +/* + * This object does not support aggregation + */ +#define FEELIT_ERROR_NOAGGREGATION CLASS_E_NOAGGREGATION + +/* + * Another app has a higher priority level, preventing this call from + * succeeding. + */ +#define FEELIT_ERROR_OTHERAPPHASPRIO E_ACCESSDENIED + +/* + * Access to the device has been lost. It must be re-acquired. + */ +#define FEELIT_ERROR_INPUTLOST \ + MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_READ_FAULT) + +/* + * The operation cannot be performed while the device is acquired. + */ +#define FEELIT_ERROR_ACQUIRED \ + MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_BUSY) + +/* + * The operation cannot be performed unless the device is acquired. + */ +#define FEELIT_ERROR_NOTACQUIRED \ + MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_INVALID_ACCESS) + +/* + * The specified property cannot be changed. + */ +#define FEELIT_ERROR_READONLY E_ACCESSDENIED + +/* + * The device already has an event notification associated with it. + */ +#define FEELIT_ERROR_HANDLEEXISTS E_ACCESSDENIED + +/* + * Data is not yet available. + */ +#ifndef E_PENDING +#define E_PENDING 0x80070007L +#endif + +/* + * Unable to perform the requested operation because the user + * does not have sufficient privileges. + */ +#define FEELIT_ERROR_INSUFFICIENTPRIVS 0x80040200L + +/* + * The device is full. + */ +#define FEELIT_ERROR_DEVICEFULL 0x80040201L + +/* + * Not all the requested information fit into the buffer. + */ +#define FEELIT_ERROR_MOREDATA 0x80040202L + +/* + * The effect is not downloaded. + */ +#define FEELIT_ERROR_NOTDOWNLOADED 0x80040203L + +/* + * The device cannot be reinitialized because there are still effects + * attached to it. + */ +#define FEELIT_ERROR_HASEFFECTS 0x80040204L + +/* + * The operation cannot be performed unless the device is acquired + * in FEELIT_FCOOPLEVEL_EXCLUSIVE mode. + */ +#define FEELIT_ERROR_NOTEXCLUSIVEACQUIRED 0x80040205L + +/* + * The effect could not be downloaded because essential information + * is missing. For example, no axes have been associated with the + * effect, or no type-specific information has been created. + */ +#define FEELIT_ERROR_INCOMPLETEEFFECT 0x80040206L + +/* + * Attempted to read buffered device data from a device that is + * not buffered. + */ +#define FEELIT_ERROR_NOTBUFFERED 0x80040207L + +/* + * An attempt was made to modify parameters of an effect while it is + * playing. Not all hardware devices support altering the parameters + * of an effect while it is playing. + */ +#define FEELIT_ERROR_EFFECTPLAYING 0x80040208L + +/* + * An internal error occurred (inside the API or the driver) + */ +#define FEELIT_ERROR_INTERNAL 0x80040209L + +/* + * Effect set referenced by a command is not the active set + */ +#define FEELIT_ERROR_INACTIVE 0x8004020AL + +#ifdef __cplusplus +}; +#endif + + +#endif /* __FEELITAPI_INCLUDED__ */ + diff --git a/code/ff/IFC/IFC.h b/code/ff/IFC/IFC.h new file mode 100644 index 0000000..36fcf4c --- /dev/null +++ b/code/ff/IFC/IFC.h @@ -0,0 +1,79 @@ +/********************************************************************** + Copyright (c) 1997 - 2000 Immersion Corporation + + Permission to use, copy, modify, distribute, and sell this + software and its documentation may be granted without fee; + interested parties are encouraged to request permission from + Immersion Corporation + 801 Fox Lane + San Jose, CA 95131 + 408-467-1900 + + IMMERSION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. + IN NO EVENT SHALL IMMERSION BE LIABLE FOR ANY SPECIAL, INDIRECT OR + CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, + NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + FILE: IFC.h + + PURPOSE: Class Types for the Force Foundation Classes + + STARTED: 10/29/97 + + NOTES/REVISIONS: + 3/2/99 jrm (Jeff Mallett): Force-->Feel renaming + +**********************************************************************/ + + +#if !defined(AFX_IFC_H__135B88C4_4175_11D1_B049_0020AF30269A__INCLUDED_) +#define AFX_IFC_H__135B88C4_4175_11D1_B049_0020AF30269A__INCLUDED_ + +#if _MSC_VER >= 1000 +#pragma once +#endif // _MSC_VER >= 1000 + + +#include "ImmBox.h" +#include "ImmCondition.h" +#include "ImmConstant.h" +#include "ImmDamper.h" +#include "ImmDevice.h" +#include "ImmDevices.h" +#include "ImmDXDevice.h" +#include "ImmEffect.h" +#include "ImmEllipse.h" +#include "ImmEnclosure.h" +#include "ImmMouse.h" +#include "ImmFriction.h" +#include "ImmGrid.h" +#include "ImmInertia.h" +#include "ImmPeriodic.h" +#include "ImmProjects.h" +#include "ImmRamp.h" +#include "ImmSpring.h" +#include "ImmTexture.h" +#include "IFCErrors.h" + + +#endif // !defined(AFX_IFC_H__135B88C4_4175_11D1_B049_0020AF30269A__INCLUDED_) + + + + + + + + + + + + + + + + + diff --git a/code/ff/IFC/IFC22.dll b/code/ff/IFC/IFC22.dll new file mode 100644 index 0000000..44331c8 Binary files /dev/null and b/code/ff/IFC/IFC22.dll differ diff --git a/code/ff/IFC/IFC22.lib b/code/ff/IFC/IFC22.lib new file mode 100644 index 0000000..662c436 Binary files /dev/null and b/code/ff/IFC/IFC22.lib differ diff --git a/code/ff/IFC/IFCErrors.h b/code/ff/IFC/IFCErrors.h new file mode 100644 index 0000000..b25ff71 --- /dev/null +++ b/code/ff/IFC/IFCErrors.h @@ -0,0 +1,181 @@ +/********************************************************************** + Copyright (c) 1999 - 2000 Immersion Corporation + + Permission to use, copy, modify, distribute, and sell this + software and its documentation may be granted without fee; + interested parties are encouraged to request permission from + Immersion Corporation + 801 Fox Lane + San Jose, CA 95131 + 408-467-1900 + + IMMERSION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. + IN NO EVENT SHALL IMMERSION BE LIABLE FOR ANY SPECIAL, INDIRECT OR + CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, + NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + FILE: IFCErrors.h + + PURPOSE: Error codes returned in IFC; Error handling in IFC + + STARTED: 2/28/99 by Jeff Mallett + + NOTES/REVISIONS: + 3/2/99 jrm (Jeff Mallett): Force-->Feel renaming + 3/6/99 jrm: Added user error handling control + 3/15/99 jrm: __declspec(dllimport/dllexport) the whole class + +**********************************************************************/ + + +#if !defined(IFCERRORS_H__INCLUDED_) +#define IFCERRORS_H__INCLUDED_ + +#if _MSC_VER >= 1000 +#pragma once +#endif // _MSC_VER >= 1000 + +#ifndef _IFCDLL_ +#define DLLIFC __declspec(dllimport) +#else +#define DLLIFC __declspec(dllexport) +#endif + +#include +#include "ImmBaseTypes.h" + + +/**************************************************************************** + * + * Error Codes + * + ****************************************************************************/ + +typedef enum { + IFC_ERR_OK = 0, + + IFC_ERR_UNKNOWN_ERROR = 1, + + IFC_ERR_ALLOCATION_FAILED = 2, + IFC_ERR_INVALID_PARAMETER = 3, + IFC_ERR_NULL_PARAMETER = 4, + IFC_ERR_WRONG_FORM = 5, + + IFC_ERR_DEVICE_IS_NULL = 6, + IFC_ERR_INVALID_GUID = 7, + IFC_ERR_EFFECT_NOT_INITIALIZED = 8, + + IFC_ERR_CANT_INITIALIZE_DEVICE = 9, + + IFC_ERR_CANT_CREATE_EFFECT = 10, + IFC_ERR_CANT_CREATE_EFFECT_FROM_IFR = 11, + IFC_ERR_NO_EFFECTS_FOUND = 12, + IFC_ERR_EFFECT_IS_COMPOUND = 13, + + IFC_ERR_PROJECT_ALREADY_OPEN = 14, + IFC_ERR_PROJECT_NOT_OPEN = 15, + + IFC_ERR_NO_DX7_DEVICE = 16, + IFC_ERR_CANT_WRITE_IFR = 17, + + IFC_ERR_DINPUT_NOT_FOUND = 18, + IFC_ERR_IMMAPI_NOT_FOUND = 19, + + IFC_ERR_FILE_NOT_FOUND = 20, + IFC_ERR_NO_VERSION_INFO = 21 + +} IFC_ERROR_CODE; + +typedef enum { + IFC_OUTPUT_ERR_TO_DEBUG = 0x0001, + IFC_OUTPUT_ERR_TO_DIALOG = 0x0002 +} IFC_ERROR_HANDLING_FLAGS; + + +/**************************************************************************** + * + * Macros + * + ****************************************************************************/ + +// +// ------ PUBLIC MACROS ------ +// +#define IFC_GET_LAST_ERROR CIFCErrors::GetLastErrorCode() +#define IFC_SET_ERROR_HANDLING CIFCErrors::SetErrorHandling + + +// +// ------ PRIVATE MACROS ------ +// +#if (IFC_VERSION >= 0x0110) + #define IFC_SET_ERROR(err) CIFCErrors::SetErrorCode(err, __FILE__, __LINE__) +#else + #define IFC_SET_ERROR(err) CIFCErrors::SetErrorCode(err) +#endif +#define IFC_CLEAR_ERROR IFC_SET_ERROR(IFC_ERR_OK) + + + +/**************************************************************************** + * + * CIFCErrors + * + ****************************************************************************/ +// All members are static. Don't bother instantiating an object of this class. + +// +// ------ PUBLIC INTERFACE ------ +// + +class DLLIFC CIFCErrors +{ + // + // ATTRIBUTES + // + + public: + + static HRESULT + GetLastErrorCode() + { return m_Err; } + + static void + SetErrorHandling(unsigned long dwFlags) + { m_dwErrHandlingFlags = dwFlags; } + + +// +// ------ PRIVATE INTERFACE ------ +// + + // Internally used by IFC classes + static void + SetErrorCode( + HRESULT err +#if (IFC_VERSION >= 0x0110) + , const char *sFile, int nLine +#endif + ); + + // + // HELPERS + // + + protected: + + // + // INTERNAL DATA + // + + private: + + static HRESULT m_Err; + static unsigned long m_dwErrHandlingFlags; +}; + + +#endif // IFCERRORS_H__INCLUDED_ diff --git a/code/ff/IFC/ImmBaseTypes.h b/code/ff/IFC/ImmBaseTypes.h new file mode 100644 index 0000000..b58298f --- /dev/null +++ b/code/ff/IFC/ImmBaseTypes.h @@ -0,0 +1,359 @@ +/********************************************************************** + Copyright (c) 1997 - 2000 Immersion Corporation + + Permission to use, copy, modify, distribute, and sell this + software and its documentation may be granted without fee; + interested parties are encouraged to request permission from + Immersion Corporation + 801 Fox Lane + San Jose, CA 95131 + 408-467-1900 + + IMMERSION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. + IN NO EVENT SHALL IMMERSION BE LIABLE FOR ANY SPECIAL, INDIRECT OR + CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, + NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + FILE: ImmBaseTypes.h + + PURPOSE: Base Types for Feelit API Foundation Classes + + STARTED: 10/29/97 + + NOTES/REVISIONS: + 3/2/99 jrm (Jeff Mallett): Force-->Feel renaming + +**********************************************************************/ + + +#if !defined(AFX_IMMBASETYPES_H__135B88C4_4175_11D1_B049_0020AF30269A__INCLUDED_) +#define AFX_IMMBASETYPES_H__135B88C4_4175_11D1_B049_0020AF30269A__INCLUDED_ + +#if _MSC_VER >= 1000 +#pragma once +#endif // _MSC_VER >= 1000 + +//#include +#include "FeelitApi.h" + +// Version 0x0100 -- IFC10 +// Version 0x0101 -- IFC10p Special release: contains CImmProject::DestroyEffect +// Version 0x0110 -- IFC21 (and IFC20?) +#ifndef IFC_VERSION + #define IFC_VERSION 0x0110 +#endif + +//#if (IFC_VERSION >= 0x0101) + // This means that a user can call delete on a CImmCompoundEffect + // object that was allocated through a CImmProject::CreateEffect() + // and all will be well. +// #define PROTECT_AGAINST_DELETION +//#endif + +#if (IFC_VERSION >= 0x0110) + #define IFC_START_DELAY + #define IFC_EFFECT_CACHING +#endif + +// Add define for DirectInput Device emulating FEELit Device +#define FEELIT_DEVICETYPE_DIRECTINPUT 3 + + +//================================================================ +// TYPE WRAPPERS +//================================================================ + +// +// IMM --> FEELIT Wrappers +// +#define IMM_VERSION FEELIT_VERSION + +#define IMM_DEVICETYPE_DEVICE FEELIT_DEVICETYPE_DEVICE +#define IMM_DEVICETYPE_MOUSE FEELIT_DEVICETYPE_MOUSE +#define IMM_DEVICETYPE_HID FEELIT_DEVICETYPE_HID +#define IMM_DEVICETYPE_DIRECTINPUT FEELIT_DEVICETYPE_DIRECTINPUT + +#define IMM_EFFECT FEELIT_EFFECT +#define LPIMM_EFFECT LPFEELIT_EFFECT +#define LPCIMM_EFFECT LPCFEELIT_EFFECT + +#define IMM_CONDITION FEELIT_CONDITION +#define LPIMM_CONDITION LPFEELIT_CONDITION +#define LPCIMM_CONDITION LPCFEELIT_CONDITION + +#define IMM_CONSTANTFORCE FEELIT_CONSTANTFORCE +#define LPIMM_CONSTANTFORCE LPFEELIT_CONSTANTFORCE +#define LPCIMM_CONSTANTFORCE LPCFEELIT_CONSTANTFORCE + +#define IMM_ELLIPSE FEELIT_ELLIPSE +#define LPIMM_ELLIPSE LPFEELIT_ELLIPSE +#define LPCIMM_ELLIPSE LPCFEELIT_ELLIPSE + +#define IMM_ENCLOSURE FEELIT_ENCLOSURE +#define LPIMM_ENCLOSURE LPFEELIT_ENCLOSURE +#define LPCIMM_ENCLOSURE LPCFEELIT_ENCLOSURE + +#define IMM_PERIODIC FEELIT_PERIODIC +#define LPIMM_PERIODIC LPFEELIT_PERIODIC +#define LPCIMM_PERIODIC LPCFEELIT_PERIODIC + +#define IMM_RAMPFORCE FEELIT_RAMPFORCE +#define LPIMM_RAMPFORCE LPFEELIT_RAMPFORCE +#define LPCIMM_RAMPFORCE LPCFEELIT_RAMPFORCE + +#define IMM_TEXTURE FEELIT_TEXTURE +#define LPIMM_TEXTURE LPFEELIT_TEXTURE +#define LPCIMM_TEXTURE LPCFEELIT_TEXTURE + +#define IMM_ENVELOPE FEELIT_ENVELOPE +#define LPIMM_ENVELOPE LPFEELIT_ENVELOPE +#define LPCIMM_ENVELOPE LPCFEELIT_ENVELOPE + +#define LPIIMM_API LPIFEELIT +#define LPIIMM_EFFECT LPIFEELIT_EFFECT +#define LPIIMM_DEVICE LPIFEELIT_DEVICE + +#define IMM_CUSTOMFORCE FEELIT_CUSTOMFORCE +#define LPIMM_CUSTOMFORCE LPFEELIT_CUSTOMFORCE +#define LPCIMM_CUSTOMFORCE LPCFEELIT_CUSTOMFORCE + +#define LPIMM_ENUMDEVICESCALLBACK LPFEELIT_ENUMDEVICESCALLBACK + +/* Effect Types */ +#define IMM_EFFECTTYPE_ALL FEELIT_FEFFECTTYPE_ALL + +#define IMM_EFFECTTYPE_CONSTANTFORCE FEELIT_FEFFECTTYPE_CONSTANTFORCE +#define IMM_EFFECTTYPE_RAMPFORCE FEELIT_FEFFECTTYPE_RAMPFORCE +#define IMM_EFFECTTYPE_PERIODIC FEELIT_FEFFECTTYPE_PERIODIC +#define IMM_EFFECTTYPE_CONDITION FEELIT_FEFFECTTYPE_CONDITION +#define IMM_EFFECTTYPE_ENCLOSURE FEELIT_FEFFECTTYPE_ENCLOSURE +#define IMM_EFFECTTYPE_ELLIPSE FEELIT_FEFFECTTYPE_ELLIPSE +#define IMM_EFFECTTYPE_TEXTURE FEELIT_FEFFECTTYPE_TEXTURE +#define IMM_EFFECTTYPE_COMPOUND 0x00000008 +#define IMM_EFFECTTYPE_CUSTOMFORCE FEELIT_FEFFECTTYPE_CUSTOMFORCE +#define IMM_EFFECTTYPE_HARDWARE FEELIT_FEFFECTTYPE_HARDWARE + +#define IMM_EFFECTTYPE_FFATTACK FEELIT_FEFFECTTYPE_FFATTACK +#define IMM_EFFECTTYPE_FFFADE FEELIT_FEFFECTTYPE_FFFADE +#define IMM_EFFECTTYPE_SATURATION FEELIT_FEFFECTTYPE_SATURATION +#define IMM_EFFECTTYPE_POSNEGCOEFFICIENTS FEELIT_FEFFECTTYPE_POSNEGCOEFFICIENTS +#define IMM_EFFECTTYPE_POSNEGSATURATION FEELIT_FEFFECTTYPE_POSNEGSATURATION +#define IMM_EFFECTTYPE_DEADBAND FEELIT_FEFFECTTYPE_DEADBAND + +/* Units */ +#define IMM_DEGREES FEELIT_DEGREES +#define IMM_FFNOMINALMAX FEELIT_FFNOMINALMAX +#define IMM_SECONDS FEELIT_SECONDS + +/* Start Flags */ +#define IMM_START_SOLO FEELIT_FSTART_SOLO +#define IMM_START_NODOWNLOAD FEELIT_FSTART_NODOWNLOAD + +/* Status Flags */ +#define IMM_STATUS_PLAYING FEELIT_FSTATUS_PLAYING +#define IMM_STATUS_EMULATED FEELIT_FSTATUS_EMULATED + +/* Stiffness Mask Flags */ +#define IMM_STIFF_NONE FEELIT_FSTIFF_NONE +#define IMM_STIFF_OUTERLEFTWALL FEELIT_FSTIFF_OUTERLEFTWALL +#define IMM_STIFF_INNERLEFTWALL FEELIT_FSTIFF_INNERLEFTWALL +#define IMM_STIFF_INNERRIGHTWALL FEELIT_FSTIFF_INNERRIGHTWALL +#define IMM_STIFF_OUTERRIGHTWALL FEELIT_FSTIFF_OUTERRIGHTWALL +#define IMM_STIFF_OUTERTOPWALL FEELIT_FSTIFF_OUTERTOPWALL +#define IMM_STIFF_INNERTOPWALL FEELIT_FSTIFF_INNERTOPWALL +#define IMM_STIFF_INNERBOTTOMWALL FEELIT_FSTIFF_INNERBOTTOMWALL +#define IMM_STIFF_OUTERBOTTOMWALL FEELIT_FSTIFF_OUTERBOTTOMWALL +#define IMM_STIFF_OUTERANYWALL FEELIT_FSTIFF_OUTERANYWALL +#define IMM_STIFF_INBOUNDANYWALL FEELIT_FSTIFF_INBOUNDANYWALL +#define IMM_STIFF_INNERANYWALL FEELIT_FSTIFF_INNERANYWALL +#define IMM_STIFF_OUTBOUNDANYWALL FEELIT_FSTIFF_OUTBOUNDANYWALL +#define IMM_STIFF_ANYWALL FEELIT_FSTIFF_ANYWALL + +/* Clipping Mask Flags */ +#define IMM_CLIP_NONE FEELIT_FCLIP_NONE +#define IMM_CLIP_OUTERLEFTWALL FEELIT_FCLIP_OUTERLEFTWALL +#define IMM_CLIP_INNERLEFTWALL FEELIT_FCLIP_INNERLEFTWALL +#define IMM_CLIP_INNERRIGHTWALL FEELIT_FCLIP_INNERRIGHTWALL +#define IMM_CLIP_OUTERRIGHTWALL FEELIT_FCLIP_OUTERRIGHTWALL +#define IMM_CLIP_OUTERTOPWALL FEELIT_FCLIP_OUTERTOPWALL +#define IMM_CLIP_INNERTOPWALL FEELIT_FCLIP_INNERTOPWALL +#define IMM_CLIP_INNERBOTTOMWALL FEELIT_FCLIP_INNERBOTTOMWALL +#define IMM_CLIP_OUTERBOTTOMWALL FEELIT_FCLIP_OUTERBOTTOMWALL +#define IMM_CLIP_OUTERANYWALL FEELIT_FCLIP_OUTERANYWALL +#define IMM_CLIP_INNERANYWALL FEELIT_FCLIP_INNERANYWALL +#define IMM_CLIP_ANYWALL FEELIT_FCLIP_ANYWALL + +/* Device capabilities Stuct */ +#define IMM_DEVCAPS FEELIT_DEVCAPS +#define LPIMM_DEVCAPS LPFEELIT_DEVCAPS +#define LPCIMM_DEVCAPS LPCFEELIT_DEVCAPS + +/* Device capabilities flags */ +#define IMM_DEVCAPS_ATTACHED FEELIT_FDEVCAPS_ATTACHED +#define IMM_DEVCAPS_POLLEDDEVICE FEELIT_FDEVCAPS_POLLEDDEVICE +#define IMM_DEVCAPS_EMULATED FEELIT_FDEVCAPS_EMULATED +#define IMM_DEVCAPS_POLLEDDATAFORMAT FEELIT_FDEVCAPS_POLLEDDATAFORMAT +#define IMM_DEVCAPS_FORCEFEEDBACK FEELIT_FDEVCAPS_FORCEFEEDBACK +#define IMM_DEVCAPS_FFATTACK FEELIT_FDEVCAPS_FFATTACK +#define IMM_DEVCAPS_FFFADE FEELIT_FDEVCAPS_FFFADE +#define IMM_DEVCAPS_SATURATION FEELIT_FDEVCAPS_SATURATION +#define IMM_DEVCAPS_POSNEGCOEFFICIENTS FEELIT_FDEVCAPS_POSNEGCOEFFICIENTS +#define IMM_DEVCAPS_POSNEGSATURATION FEELIT_FDEVCAPS_POSNEGSATURATION +#define IMM_DEVCAPS_DEADBAND FEELIT_FDEVCAPS_DEADBAND + +#define LPIMM_DEVICEINSTANCE LPFEELIT_DEVICEINSTANCE +#define LPCIMM_DEVICEOBJECTINSTANCE LPCFEELIT_DEVICEOBJECTINSTANCE +#define LPCIMM_EFFECTINFO LPCFEELIT_EFFECTINFO + +#define IMM_PARAM_DURATION FEELIT_FPARAM_DURATION +#define IMM_PARAM_SAMPLEPERIOD FEELIT_FPARAM_SAMPLEPERIOD +#define IMM_PARAM_GAIN FEELIT_FPARAM_GAIN +#define IMM_PARAM_TRIGGERBUTTON FEELIT_FPARAM_TRIGGERBUTTON +#define IMM_PARAM_TRIGGERREPEATINTERVAL FEELIT_FPARAM_TRIGGERREPEATINTERVAL +#define IMM_PARAM_AXES FEELIT_FPARAM_AXES +#define IMM_PARAM_DIRECTION FEELIT_FPARAM_DIRECTION +#define IMM_PARAM_ENVELOPE FEELIT_FPARAM_ENVELOPE +#define IMM_PARAM_TYPESPECIFICPARAMS FEELIT_FPARAM_TYPESPECIFICPARAMS +#define IMM_PARAM_STARTDELAY FEELIT_FPARAM_STARTDELAY +#define IMM_PARAM_ALLPARAMS FEELIT_FPARAM_ALLPARAMS +#define IMM_PARAM_START FEELIT_FPARAM_START +#define IMM_PARAM_NORESTART FEELIT_FPARAM_NORESTART +#define IMM_PARAM_NODOWNLOAD FEELIT_FPARAM_NODOWNLOAD + +#define IMM_EFFECT_OBJECTIDS FEELIT_FEFFECT_OBJECTIDS +#define IMM_EFFECT_OBJECTOFFSETS FEELIT_FEFFECT_OBJECTOFFSETS +#define IMM_EFFECT_CARTESIAN FEELIT_FEFFECT_CARTESIAN +#define IMM_EFFECT_POLAR FEELIT_FEFFECT_POLAR +#define IMM_EFFECT_SPHERICAL FEELIT_FEFFECT_SPHERICAL + +#define IMM_PARAM_NOTRIGGER FEELIT_PARAM_NOTRIGGER + +/* Offsets */ +#define IMM_MOUSEOFFSET_XAXIS FEELIT_MOUSEOFFSET_XAXIS +#define IMM_MOUSEOFFSET_YAXIS FEELIT_MOUSEOFFSET_YAXIS +#define IMM_MOUSEOFFSET_ZAXIS FEELIT_MOUSEOFFSET_ZAXIS +#define IMM_MOUSEOFFSET_XFORCE FEELIT_MOUSEOFFSET_XFORCE +#define IMM_MOUSEOFFSET_YFORCE FEELIT_MOUSEOFFSET_YFORCE +#define IMM_MOUSEOFFSET_ZFORCE FEELIT_MOUSEOFFSET_ZFORCE +#define IMM_MOUSEOFFSET_BUTTON0 FEELIT_MOUSEOFFSET_BUTTON0 +#define IMM_MOUSEOFFSET_BUTTON1 FEELIT_MOUSEOFFSET_BUTTON1 +#define IMM_MOUSEOFFSET_BUTTON2 FEELIT_MOUSEOFFSET_BUTTON2 +#define IMM_MOUSEOFFSET_BUTTON3 FEELIT_MOUSEOFFSET_BUTTON3 + +/* Cooperative Level Flags */ +#define IMM_COOPLEVEL_FOREGROUND FEELIT_FCOOPLEVEL_FOREGROUND +#define IMM_COOPLEVEL_BACKGROUND FEELIT_FCOOPLEVEL_BACKGROUND + +/* Enumeration codes */ +#define IMM_ENUM_STOP FEELIT_ENUM_STOP +#define IMM_ENUM_CONTINUE FEELIT_ENUM_CONTINUE + +#define IMM_ENUMDEV_ALLDEVICES FEELIT_FENUMDEV_ALLDEVICES +#define IMM_ENUMDEV_ATTACHEDONLY FEELIT_FENUMDEV_ATTACHEDONLY +#define IMM_ENUMDEV_FORCEFEEDBACK FEELIT_FENUMDEV_FORCEFEEDBACK + +/* Return values */ +#define IMM_RESULT_OK FEELIT_RESULT_OK +#define IMM_RESULT_NOTATTACHED FEELIT_RESULT_NOTATTACHED +#define IMM_RESULT_BUFFEROVERFLOW FEELIT_RESULT_BUFFEROVERFLOW +#define IMM_RESULT_PROPNOEFFECT FEELIT_RESULT_PROPNOEFFECT +#define IMM_RESULT_NOEFFECT FEELIT_RESULT_NOEFFECT +#define IMM_RESULT_POLLEDDEVICE FEELIT_RESULT_POLLEDDEVICE +#define IMM_RESULT_DOWNLOADSKIPPED FEELIT_RESULT_DOWNLOADSKIPPED +#define IMM_RESULT_EFFECTRESTARTED FEELIT_RESULT_EFFECTRESTARTED +#define IMM_RESULT_TRUNCATED FEELIT_RESULT_TRUNCATED +#define IMM_RESULT_TRUNCATEDANDRESTARTED FEELIT_RESULT_TRUNCATEDANDRESTARTED +#define IMM_ERROR_OLDFEELITVERSION FEELIT_ERROR_OLDFEELITVERSION +#define IMM_ERROR_BETAFEELITVERSION FEELIT_ERROR_BETAFEELITVERSION +#define IMM_ERROR_BADDRIVERVER FEELIT_ERROR_BADDRIVERVER +#define IMM_ERROR_DEVICENOTREG FEELIT_ERROR_DEVICENOTREG +#define IMM_ERROR_NOTFOUND FEELIT_ERROR_NOTFOUND +#define IMM_ERROR_OBJECTNOTFOUND FEELIT_ERROR_OBJECTNOTFOUND +#define IMM_ERROR_INVALIDPARAM FEELIT_ERROR_INVALIDPARAM +#define IMM_ERROR_NOINTERFACE FEELIT_ERROR_NOINTERFACE +#define IMM_ERROR_GENERIC FEELIT_ERROR_GENERIC +#define IMM_ERROR_OUTOFMEMORY FEELIT_ERROR_OUTOFMEMORY +#define IMM_ERROR_UNSUPPORTED FEELIT_ERROR_UNSUPPORTED +#define IMM_ERROR_NOTINITIALIZED FEELIT_ERROR_NOTINITIALIZED +#define IMM_ERROR_ALREADYINITIALIZED FEELIT_ERROR_ALREADYINITIALIZED +#define IMM_ERROR_NOAGGREGATION FEELIT_ERROR_NOAGGREGATION +#define IMM_ERROR_OTHERAPPHASPRIO FEELIT_ERROR_OTHERAPPHASPRIO +#define IMM_ERROR_INPUTLOST FEELIT_ERROR_INPUTLOST +#define IMM_ERROR_ACQUIRED FEELIT_ERROR_ACQUIRED +#define IMM_ERROR_NOTACQUIRED FEELIT_ERROR_NOTACQUIRED +#define IMM_ERROR_READONLY FEELIT_ERROR_READONLY +#define IMM_ERROR_HANDLEEXISTS FEELIT_ERROR_HANDLEEXISTS +#define IMM_ERROR_INSUFFICIENTPRIVS FEELIT_ERROR_INSUFFICIENTPRIVS +#define IMM_ERROR_DEVICEFULL FEELIT_ERROR_DEVICEFULL +#define IMM_ERROR_MOREDATA FEELIT_ERROR_MOREDATA +#define IMM_ERROR_NOTDOWNLOADED FEELIT_ERROR_NOTDOWNLOADED +#define IMM_ERROR_HASEFFECTS FEELIT_ERROR_HASEFFECTS +#define IMM_ERROR_NOTEXCLUSIVEACQUIRED FEELIT_ERROR_NOTEXCLUSIVEACQUIRED +#define IMM_ERROR_INCOMPLETEEFFECT FEELIT_ERROR_INCOMPLETEEFFECT +#define IMM_ERROR_NOTBUFFERED FEELIT_ERROR_NOTBUFFERED +#define IMM_ERROR_EFFECTPLAYING FEELIT_ERROR_EFFECTPLAYING +#define IMM_ERROR_INTERNAL FEELIT_ERROR_INTERNAL +#define IMM_ERROR_INACTIVE FEELIT_ERROR_INACTIVE + +//================================================================ +// GUID WRAPPERS +//================================================================ + +// +// Immersion --> Feelit Wrappers +// +#define GUID_Imm_ConstantForce GUID_Feelit_ConstantForce +#define GUID_Imm_RampForce GUID_Feelit_RampForce +#define GUID_Imm_Square GUID_Feelit_Square +#define GUID_Imm_Sine GUID_Feelit_Sine +#define GUID_Imm_Triangle GUID_Feelit_Triangle +#define GUID_Imm_SawtoothUp GUID_Feelit_SawtoothUp +#define GUID_Imm_SawtoothDown GUID_Feelit_SawtoothDown +#define GUID_Imm_Spring GUID_Feelit_Spring +#define GUID_Imm_DeviceSpring GUID_Feelit_DeviceSpring +#define GUID_Imm_Damper GUID_Feelit_Damper +#define GUID_Imm_Inertia GUID_Feelit_Inertia +#define GUID_Imm_Friction GUID_Feelit_Friction +#define GUID_Imm_Texture GUID_Feelit_Texture +#define GUID_Imm_Grid GUID_Feelit_Grid +#define GUID_Imm_Enclosure GUID_Feelit_Enclosure +#define GUID_Imm_Ellipse GUID_Feelit_Ellipse +#define GUID_Imm_CustomForce GUID_Feelit_CustomForce + +#define CLSID_Imm CLSID_Feelit +#define CLSID_ImmDevice CLSID_FeelitDevice +#define GUID_Imm_XAxis GUID_Feelit_XAxis +#define GUID_Imm_YAxis GUID_Feelit_YAxis +#define GUID_Imm_ZAxis GUID_Feelit_ZAxis +#define GUID_Imm_RxAxis GUID_Feelit_RxAxis +#define GUID_Imm_RyAxis GUID_Feelit_RyAxis +#define GUID_Imm_RzAxis GUID_Feelit_RzAxis +#define GUID_Imm_Slider GUID_Feelit_Slider +#define GUID_Imm_Button GUID_Feelit_Button +#define GUID_Imm_Key GUID_Feelit_Key +#define GUID_Imm_POV GUID_Feelit_POV +#define GUID_Imm_Unknown GUID_Feelit_Unknown +#define GUID_Imm_Mouse GUID_Feelit_Mouse + + +#endif // !defined(AFX_IMMBASETYPES_H__135B88C4_4175_11D1_B049_0020AF30269A__INCLUDED_) + + + + + + + + + + + + + + + + + diff --git a/code/ff/IFC/ImmBox.h b/code/ff/IFC/ImmBox.h new file mode 100644 index 0000000..12eebbf --- /dev/null +++ b/code/ff/IFC/ImmBox.h @@ -0,0 +1,170 @@ +/********************************************************************** + Copyright (c) 1997 - 2000 Immersion Corporation + + Permission to use, copy, modify, distribute, and sell this + software and its documentation may be granted without fee; + interested parties are encouraged to request permission from + Immersion Corporation + 801 Fox Lane + San Jose, CA 95131 + 408-467-1900 + + IMMERSION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. + IN NO EVENT SHALL IMMERSION BE LIABLE FOR ANY SPECIAL, INDIRECT OR + CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, + NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + FILE: ImmBox.h + + PURPOSE: Box Class for Immersion Foundation Classes + + STARTED: 11/04/97 + + NOTES/REVISIONS: + 3/2/99 jrm (Jeff Mallett): Force-->Feel renaming + 3/15/99 jrm: __declspec(dllimport/dllexport) the whole class + 11/15/99 sdr (Steve Rank): Converted to IFC + +**********************************************************************/ + + +#if !defined(AFX_IMMBOX_H__135B88C4_4175_11D1_B049_0020AF30269A__INCLUDED_) +#define AFX_IMMBOX_H__135B88C4_4175_11D1_B049_0020AF30269A__INCLUDED_ + +#if _MSC_VER >= 1000 +#pragma once +#endif // _MSC_VER >= 1000 + +#ifndef _IFCDLL_ +#define DLLIFC __declspec(dllimport) +#else +#define DLLIFC __declspec(dllexport) +#endif + +#include "ImmBaseTypes.h" +#include "ImmEffect.h" +#include "ImmEnclosure.h" + + + +//================================================================ +// Constants +//================================================================ + +const POINT IMM_BOX_MOUSE_POS_AT_START = { MAXLONG, MAXLONG }; + +#define IMM_BOX_DEFAULT_STIFFNESS 5000 +#define IMM_BOX_DEFAULT_WIDTH 10 +#define IMM_BOX_DEFAULT_HEIGHT IMM_ENCLOSURE_HEIGHT_AUTO +#define IMM_BOX_DEFAULT_WALL_WIDTH IMM_ENCLOSURE_WALL_WIDTH_AUTO + +#define IMM_BOX_DEFAULT_CENTER_POINT IMM_BOX_MOUSE_POS_AT_START + + + + +//================================================================ +// CImmBox +//================================================================ + +// +// ------ PUBLIC INTERFACE ------ +// + +class DLLIFC CImmBox : public CImmEnclosure +{ + // + // CONSTRUCTOR/DESCTRUCTOR + // + + public: + + // Constructor + CImmBox(); + + // Destructor + virtual + ~CImmBox(); + + + // + // ATTRIBUTES + // + + public: + + + BOOL + ChangeParameters( + POINT pntCenter, + LONG lStiffness = IMM_EFFECT_DONT_CHANGE, + DWORD dwWidth = IMM_EFFECT_DONT_CHANGE, + DWORD dwHeight = IMM_EFFECT_DONT_CHANGE, + DWORD dwWallWidth = IMM_EFFECT_DONT_CHANGE, + CImmEffect* pInsideEffect = (CImmEffect*) IMM_EFFECT_DONT_CHANGE + ); + + BOOL + ChangeParameters( + LPCRECT pRectOutside, + LONG lStiffness = IMM_EFFECT_DONT_CHANGE, + DWORD dwWallWidth = IMM_EFFECT_DONT_CHANGE, + CImmEffect* pInsideEffect = (CImmEffect*) IMM_EFFECT_DONT_CHANGE + ); + + + // + // OPERATIONS + // + + public: + + + BOOL + Initialize( + CImmDevice* pDevice, + DWORD dwWidth = IMM_ENCLOSURE_DEFAULT_WIDTH, + DWORD dwHeight = IMM_ENCLOSURE_DEFAULT_HEIGHT, + LONG lStiffness = IMM_BOX_DEFAULT_STIFFNESS, + DWORD dwWallWidth = IMM_BOX_DEFAULT_WALL_WIDTH, + POINT pntCenter = IMM_BOX_DEFAULT_CENTER_POINT, + CImmEffect* pInsideEffect = NULL, + DWORD dwNoDownload = 0 + ); + + + BOOL + Initialize( + CImmDevice* pDevice, + LPCRECT pRectOutside, + LONG lStiffness = IMM_BOX_DEFAULT_STIFFNESS, + DWORD dwWallWidth = IMM_BOX_DEFAULT_WALL_WIDTH, + CImmEffect* pInsideEffect = NULL, + DWORD dwNoDownload = 0 + ); + + +// +// ------ PRIVATE INTERFACE ------ +// + + // + // HELPERS + // + + protected: + + + // + // INTERNAL DATA + // + + protected: + +}; + + +#endif // !defined(AFX_IMMBOX_H__135B88C4_4175_11D1_B049_0020AF30269A__INCLUDED_) diff --git a/code/ff/IFC/ImmCompoundEffect.h b/code/ff/IFC/ImmCompoundEffect.h new file mode 100644 index 0000000..9a39b3c --- /dev/null +++ b/code/ff/IFC/ImmCompoundEffect.h @@ -0,0 +1,228 @@ +/********************************************************************** + Copyright (c) 1999 - 2000 Immersion Corporation + + Permission to use, copy, modify, distribute, and sell this + software and its documentation may be granted without fee; + interested parties are encouraged to request permission from + Immersion Corporation + 801 Fox Lane + San Jose, CA 95131 + 408-467-1900 + + IMMERSION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. + IN NO EVENT SHALL IMMERSION BE LIABLE FOR ANY SPECIAL, INDIRECT OR + CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, + NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + FILE: ImmCompoundEffect.h + + PURPOSE: Manages Compound Effects for Force Foundation Classes + + STARTED: 2/24/99 by Jeff Mallett + + NOTES/REVISIONS: + 3/2/99 jrm (Jeff Mallett): Force-->Feel renaming + 3/15/99 jrm: __declspec(dllimport/dllexport) the whole class + +**********************************************************************/ + + +#include "ImmBaseTypes.h" +#include "ImmEffect.h" + +#include "ImmIFR.h" + +#if !defined(__FEELCOMPOUNDEFFECT_H) +#define __FEELCOMPOUNDEFFECT_H + +#if _MSC_VER >= 1000 +#pragma once +#endif // _MSC_VER >= 1000 + +#ifndef _IFCDLL_ +#define DLLIFC __declspec(dllimport) +#else +#define DLLIFC __declspec(dllexport) +#endif + +/* +** IMM_FFE_FILEEFFECT - struct used by DX7 to read and write to FFE +** files. This struct is different from DIFILEEFFECT due to the use +** of the non const LPDIEFFECT. An LPDIEFFECT is needed to be able to +** collect information from IFC class objects. This should be defined +** elsewhere, but no more appropriate header currently exists. +*/ +typedef struct IMM_FFE_FILEEFFECT{ + DWORD dwSize; + GUID GuidEffect; + LPDIEFFECT lpDiEffect; + CHAR szFriendlyName[MAX_PATH]; +}IMM_FFE_FILEEFFECT, *LPIMM_FFE_FILEEFFECT; + +//================================================================ +// CImmCompoundEffect +//================================================================ +// Represents a compound effect, such as might be created in +// Immersion Studio. Contains an array of effect objects. +// Methods iterate over component effects, passing the message +// to each one. +// Also, has stuff for being used by CImmProject: +// * next pointer so can be put on a linked list +// * force name + +// +// ------ PUBLIC INTERFACE ------ +// + +class DLLIFC CImmCompoundEffect +{ + // + // CONSTRUCTOR/DESTRUCTOR + // + +public://### protected: + // Constructs a CImmCompoundEffect + // Don't try to construct a CImmCompoundEffect yourself. + // Instead let CImmProject construct it for you. + CImmCompoundEffect( + IFREffect **hEffects, + long nEffects, + LPCSTR pEffectName + ); + + public: + + ~CImmCompoundEffect(); + + + // + // ATTRIBUTES + // + + public: + + long + GetNumberOfContainedEffects() const + { return m_nEffects; } + + const char * + GetName() const + { return m_lpszName; } + + GENERIC_EFFECT_PTR + GetContainedEffect( + long index + ); + + GENERIC_EFFECT_PTR + GetContainedEffect( + LPCSTR lpszEffectName + ); + + DWORD + GetEffectType(); + + // + // OPERATIONS + // + + public: + + // Start all the contained effects + BOOL Start( + DWORD dwIterations = IMM_EFFECT_DONT_CHANGE, + DWORD dwFlags = 0 + ); + + // Stop all the contained effects + BOOL Stop(); + + +// +// ------ PRIVATE INTERFACE ------ +// + + // + // HELPERS + // + + protected: + + BOOL initialize( + CImmDevice* pDevice, + IFREffect **hEffects, + DWORD dwNoDownload + ); + + BOOL + set_contained_effect( + GENERIC_EFFECT_PTR pObject, + int index = 0 + ); + + BOOL + set_name( + const char *lpszName + ); + + void + set_next( + CImmCompoundEffect *pNext + ) + { m_pNext = pNext; } + + CImmCompoundEffect * + get_next() const + { return m_pNext; } + + void + set_objID( + GUID* pobjID + ) + { m_objID = *pobjID; } + + BOOL + set_contained_obj_IDs( + GUID *guidList + ); + + int + buffer_ifr_object(TCHAR* pData); + + BOOL + get_ffe_object(LPIMM_FFE_FILEEFFECT pffeObject); + + + // + // FRIENDS + // + + public: + + friend class CImmProject; + + + // + // INTERNAL DATA + // + + protected: + + GENERIC_EFFECT_PTR *m_paEffects; // Array of force class object pointers + long m_nEffects; // Number of effects in m_paEffects + + private: + + char *m_lpszName; // Name of the compound effect + GUID m_objID; + GUID *m_pContainedObjIDs; + CImmCompoundEffect *m_pNext; // Next compound effect in the project +#ifdef PROTECT_AGAINST_DELETION + CImmProject *m_pOwningProject; +#endif +}; + +#endif diff --git a/code/ff/IFC/ImmCondition.h b/code/ff/IFC/ImmCondition.h new file mode 100644 index 0000000..6943365 --- /dev/null +++ b/code/ff/IFC/ImmCondition.h @@ -0,0 +1,451 @@ +/********************************************************************** + Copyright (c) 1997 - 2000 Immersion Corporation + + Permission to use, copy, modify, distribute, and sell this + software and its documentation may be granted without fee; + interested parties are encouraged to request permission from + Immersion Corporation + 801 Fox Lane + San Jose, CA 95131 + 408-467-1900 + + IMMERSION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. + IN NO EVENT SHALL IMMERSION BE LIABLE FOR ANY SPECIAL, INDIRECT OR + CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, + NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + FILE: ImmCondition.h + + PURPOSE: Immersion Foundation Classes Base Condition Effect + + STARTED: Oct.10.97 + + NOTES/REVISIONS: + Mar.02.99 jrm (Jeff Mallett): Force-->Feel renaming + Mar.02.99 jrm: Added GetIsCompatibleGUID + Mar.15.99 jrm: __declspec(dllimport/dllexport) the whole class + Nov.15.99 efw (Evan Wies): Converted to IFC + +**********************************************************************/ + + +#if !defined(AFX_IMMCondition_H__135B88C4_4175_11D1_B049_0020AF30269A__INCLUDED_) +#define AFX_IMMCondition_H__135B88C4_4175_11D1_B049_0020AF30269A__INCLUDED_ + +#if _MSC_VER >= 1000 +#pragma once +#endif // _MSC_VER >= 1000 + +#ifndef _IFCDLL_ +#define DLLIFC __declspec(dllimport) +#else +#define DLLIFC __declspec(dllexport) +#endif + +#include "ImmBaseTypes.h" +#include "ImmEffect.h" + + + +//================================================================ +// Constants +//================================================================ + +const POINT IMM_CONDITION_PT_NULL = { 0, 0 }; + +#define IMM_CONDITION_DEFAULT_COEFFICIENT 2500 +#define IMM_CONDITION_DEFAULT_SATURATION 10000 +#define IMM_CONDITION_DEFAULT_DEADBAND 100 +#define IMM_CONDITION_DEFAULT_CENTER_POINT IMM_EFFECT_MOUSE_POS_AT_START +#define IMM_CONDITION_DEFAULT_DURATION INFINITE + +typedef enum { + IC_NULL = 0, + IC_POSITIVE_COEFFICIENT, + IC_NEGATIVE_COEFFICIENT, + IC_POSITIVE_SATURATION, + IC_NEGATIVE_SATURATION, + IC_DEAD_BAND, + IC_AXIS, + IC_CENTER, + IC_DIRECTION_X, + IC_DIRECTION_Y, + IC_ANGLE, + IC_CONDITION_X, + IC_CONDITION_Y +} IC_ArgumentType; + +#define IC_CONDITION IC_CONDITION_X + + + +//================================================================ +// CImmCondition +//================================================================ + +// +// ------ PUBLIC INTERFACE ------ +// + +class DLLIFC CImmCondition : public CImmEffect +{ + // + // CONSTRUCTOR/DESCTRUCTOR + // + + public: + + // Constructor + CImmCondition( + const GUID& rguidEffect + ); + + // Destructor + virtual + ~CImmCondition(); + + + // + // ATTRIBUTES + // + + public: + + virtual BOOL + GetIsCompatibleGUID( + GUID &guid + ); + + virtual DWORD GetEffectType() + { return IMM_EFFECTTYPE_CONDITION; } + + // Use this form for single-axis and dual-axis effects + BOOL + ChangeConditionParams( + LPCIMM_CONDITION pConditionX, + LPCIMM_CONDITION pConditionY + ); + + // Use this form for directional effects + BOOL + ChangeConditionParams( + LPCIMM_CONDITION pCondition, + LONG lDirectionX, + LONG lDirectionY + ); + + // Use this form for directional effects + BOOL + ChangeConditionParamsPolar( + LPCIMM_CONDITION pCondition, + LONG lAngle + ); + + // Use this form for single-axis, dual-axis, or directional effects + BOOL + ChangeConditionParamsX( + LONG lPositiveCoefficient, + LONG lNegativeCoefficient = IMM_EFFECT_DONT_CHANGE, + DWORD dwPositiveSaturation = IMM_EFFECT_DONT_CHANGE, + DWORD dwNegativeSaturation = IMM_EFFECT_DONT_CHANGE, + LONG lDeadBand = IMM_EFFECT_DONT_CHANGE, + POINT pntCenter = IMM_EFFECT_DONT_CHANGE_POINT, + LONG lDirectionX = IMM_EFFECT_DONT_CHANGE, + LONG lDirectionY = IMM_EFFECT_DONT_CHANGE + ); + + BOOL + ChangeConditionParamsPolarX( + LONG lPositiveCoefficient, + LONG lNegativeCoefficient, + DWORD dwPositiveSaturation, + DWORD dwNegativeSaturation, + LONG lDeadBand, + POINT pntCenter, + LONG lAngle + ); + + BOOL + ChangeConditionParamsY( + LONG lPositiveCoefficient, + LONG lNegativeCoefficient = IMM_EFFECT_DONT_CHANGE, + DWORD dwPositiveSaturation = IMM_EFFECT_DONT_CHANGE, + DWORD dwNegativeSaturation = IMM_EFFECT_DONT_CHANGE, + LONG lDeadBand = IMM_EFFECT_DONT_CHANGE, + POINT pntCenter = IMM_EFFECT_DONT_CHANGE_POINT, + LONG lDirectionX = IMM_EFFECT_DONT_CHANGE, + LONG lDirectionY = IMM_EFFECT_DONT_CHANGE + ); + + BOOL + ChangeConditionParamsPolarY( + LONG lPositiveCoefficient, + LONG lNegativeCoefficient, + DWORD dwPositiveSaturation, + DWORD dwNegativeSaturation, + LONG lDeadBand, + POINT pntCenter, + LONG lAngle + ); + + // Use this form for single-axis, dual-axis symetrical, or directional effects + BOOL + ChangeConditionParams( + LONG lPositiveCoefficient, + LONG lNegativeCoefficient = IMM_EFFECT_DONT_CHANGE, + DWORD dwPositiveSaturation = IMM_EFFECT_DONT_CHANGE, + DWORD dwNegativeSaturation = IMM_EFFECT_DONT_CHANGE, + LONG lDeadBand = IMM_EFFECT_DONT_CHANGE, + POINT pntCenter = IMM_EFFECT_DONT_CHANGE_POINT, + LONG lDirectionX = IMM_EFFECT_DONT_CHANGE, + LONG lDirectionY = IMM_EFFECT_DONT_CHANGE + ); + + BOOL + ChangeConditionParamsPolar( + LONG lPositiveCoefficient, + LONG lNegativeCoefficient, + DWORD dwPositiveSaturation, + DWORD dwNegativeSaturation, + LONG lDeadBand, + POINT pntCenter, + LONG lAngle + ); + + BOOL ChangePositiveCoefficientX( LONG lPositiveCoefficient ); + BOOL ChangeNegativeCoefficientX( LONG lNegativeCoefficient ); + BOOL ChangePositiveSaturationX( DWORD dwPositiveSaturation ); + BOOL ChangeNegativeSaturationX( DWORD dwNegativeSaturation ); + BOOL ChangeDeadBandX( LONG lDeadBand ); + + BOOL ChangePositiveCoefficientY( LONG lPositiveCoefficient ); + BOOL ChangeNegativeCoefficientY( LONG lNegativeCoefficient ); + BOOL ChangePositiveSaturationY( DWORD dwPositiveSaturation ); + BOOL ChangeNegativeSaturationY( DWORD dwNegativeSaturation ); + BOOL ChangeDeadBandY( LONG lDeadBand ); + + BOOL ChangePositiveCoefficient( LONG lPositiveCoefficient ); + BOOL ChangeNegativeCoefficient( LONG lNegativeCoefficient ); + BOOL ChangePositiveSaturation( DWORD dwPositiveSaturation ); + BOOL ChangeNegativeSaturation( DWORD dwNegativeSaturation ); + BOOL ChangeDeadBand( LONG lDeadBand ); + + BOOL + SetCenter( + POINT pntCenter + ); + + BOOL + ChangeConditionParams2( + IC_ArgumentType type, + ... + ); + + BOOL GetPositiveCoefficientX( LONG &lPositiveCoefficient ); + BOOL GetNegativeCoefficientX( LONG &lNegativeCoefficient ); + BOOL GetPositiveSaturationX( DWORD &dwPositiveSaturation ); + BOOL GetNegativeSaturationX( DWORD &dwNegativeSaturation ); + BOOL GetDeadBandX( LONG &lDeadBand ); + + BOOL GetPositiveCoefficientY( LONG &lPositiveCoefficient ); + BOOL GetNegativeCoefficientY( LONG &lNegativeCoefficient ); + BOOL GetPositiveSaturationY( DWORD &dwPositiveSaturation ); + BOOL GetNegativeSaturationY( DWORD &dwNegativeSaturation ); + BOOL GetDeadBandY( LONG &lDeadBand ); + + BOOL GetAxis( DWORD &dwfAxis ); + BOOL GetCenter( POINT &pntCenter ); + + // + // OPERATIONS + // + + public: + + virtual BOOL + Initialize( + CImmDevice* pDevice, + const IMM_EFFECT &effect, + DWORD dwNoDownload = 0 + ); + + // Use this form for single-axis and dual-axis effects + BOOL + InitCondition( + CImmDevice* pDevice, + LPCIMM_CONDITION pConditionX, + LPCIMM_CONDITION pConditionY, + BOOL bUseDeviceCoordinates = FALSE, + DWORD dwNoDownload = 0 + ); + + + // Use this form for directional effects + BOOL + InitCondition( + CImmDevice* pDevice, + LPCIMM_CONDITION pCondition, + LONG lDirectionX, + LONG lDirectionY, + BOOL bUseDeviceCoordinates = FALSE, + DWORD dwNoDownload = 0 + ); + + + // Use this form for directional effects + BOOL + InitConditionPolar( + CImmDevice* pDevice, + LPCIMM_CONDITION pCondition, + LONG lAngle, + BOOL bUseDeviceCoordinates = FALSE, + DWORD dwNoDownload = 0 + ); + + + // Use this form for single-axis, dual-axis symetrical, or directional effects + BOOL + InitCondition( + CImmDevice* pDevice, + LONG lPositiveCoefficient = IMM_CONDITION_DEFAULT_COEFFICIENT, + LONG lNegativeCoefficient = IMM_CONDITION_DEFAULT_COEFFICIENT, + DWORD dwPositiveSaturation = IMM_CONDITION_DEFAULT_SATURATION, + DWORD dwNegativeSaturation = IMM_CONDITION_DEFAULT_SATURATION, + LONG lDeadBand = IMM_CONDITION_DEFAULT_DEADBAND, + DWORD dwfAxis = IMM_EFFECT_AXIS_BOTH, + POINT pntCenter = IMM_CONDITION_DEFAULT_CENTER_POINT, + LONG lDirectionX = IMM_EFFECT_DEFAULT_DIRECTION_X, + LONG lDirectionY = IMM_EFFECT_DEFAULT_DIRECTION_Y, + BOOL bUseDeviceCoordinates = FALSE, + DWORD dwNoDownload = 0 + ); + + // Use this form for directional effects + BOOL + InitConditionPolar( + CImmDevice* pDevice, + LONG lPositiveCoefficient = IMM_CONDITION_DEFAULT_COEFFICIENT, + LONG lNegativeCoefficient = IMM_CONDITION_DEFAULT_COEFFICIENT, + DWORD dwPositiveSaturation = IMM_CONDITION_DEFAULT_SATURATION, + DWORD dwNegativeSaturation = IMM_CONDITION_DEFAULT_SATURATION, + LONG lDeadBand = IMM_CONDITION_DEFAULT_DEADBAND, + POINT pntCenter = IMM_CONDITION_DEFAULT_CENTER_POINT, + LONG lAngle = IMM_EFFECT_DEFAULT_ANGLE, + BOOL bUseDeviceCoordinates = FALSE, + DWORD dwNoDownload = 0 + ); + + + virtual BOOL + Start( + DWORD dwIterations = 1, + DWORD dwFlags = 0, + BOOL bAllowStartDelayEmulation = true + ); + + +// +// ------ PRIVATE INTERFACE ------ +// + + // + // HELPERS + // + + protected: + + void + convert_line_point_to_offset( + POINT pntOnLine + ); + + BOOL + set_parameters( + DWORD dwfAxis, + DWORD dwfCoordinates, + LONG lDirection0, + LONG lDirection1, + LPCIMM_CONDITION pConditionX, + LPCIMM_CONDITION pConditionY + ); + + BOOL + set_parameters( + DWORD dwfAxis, + DWORD dwfCoordinates, + LONG lDirection0, + LONG lDirection1, + LONG lPositiveCoefficient, + LONG lNegativeCoefficient, + DWORD dwPositiveSaturation, + DWORD dwNegativeSaturation, + LONG lDeadBand, + POINT pntCenter + ); + + DWORD + change_parameters( + LONG lDirection0, + LONG lDirection1, + LONG lPositiveCoefficient, + LONG lNegativeCoefficient, + DWORD dwPositiveSaturation, + DWORD dwNegativeSaturation, + LONG lDeadBand, + POINT pntCenter, + int fAxis + ); + + DWORD + change_parameters( + LONG lDirection0, + LONG lDirection1, + LPCIMM_CONDITION pConditionX, + LPCIMM_CONDITION pConditionY + ); + + int + buffer_ifr_data( + TCHAR* pData + ); + + BOOL + get_ffe_data( + LPDIEFFECT pdiEffect + ); + + // + // INTERNAL DATA + // + + IMM_CONDITION m_aCondition[2]; + DWORD m_dwfAxis; + BOOL m_bUseMousePosAtStart; + + protected: + BOOL m_bUseDeviceCoordinates; + +}; + + +// +// INLINES +// + +inline BOOL +CImmCondition::GetIsCompatibleGUID(GUID &guid) +{ + return IsEqualGUID(guid, GUID_Imm_Spring) || + IsEqualGUID(guid, GUID_Imm_DeviceSpring) || + IsEqualGUID(guid, GUID_Imm_Damper) || + IsEqualGUID(guid, GUID_Imm_Inertia) || + IsEqualGUID(guid, GUID_Imm_Friction) || + IsEqualGUID(guid, GUID_Imm_Texture) || + IsEqualGUID(guid, GUID_Imm_Grid); +} + +#endif // !defined(AFX_IMMCondition_H__135B88C4_4175_11D1_B049_0020AF30269A__INCLUDED_) + diff --git a/code/ff/IFC/ImmConstant.h b/code/ff/IFC/ImmConstant.h new file mode 100644 index 0000000..6110dd2 --- /dev/null +++ b/code/ff/IFC/ImmConstant.h @@ -0,0 +1,219 @@ +/********************************************************************** + Copyright (c) 1997 - 2000 Immersion Corporation + + Permission to use, copy, modify, distribute, and sell this + software and its documentation may be granted without fee; + interested parties are encouraged to request permission from + Immersion Corporation + 801 Fox Lane + San Jose, CA 95131 + 408-467-1900 + + IMMERSION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. + IN NO EVENT SHALL IMMERSION BE LIABLE FOR ANY SPECIAL, INDIRECT OR + CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, + NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + FILE: ImmConstant.h + + PURPOSE: Base Constant Class for Immersion Foundation Classes + + STARTED: 11/03/97 + + NOTES/REVISIONS: + 3/2/99 jrm (Jeff Mallett): Force-->Feel renaming + 3/2/99 jrm: Added GetIsCompatibleGUID + 3/15/99 jrm: __declspec(dllimport/dllexport) the whole class + 11/15/99 sdr (Steve Rank): Converted to IFC +**********************************************************************/ + + +#if !defined(AFX_IMMCONSTANT_H__135B88C4_4175_11D1_B049_0020AF30269A__INCLUDED_) +#define AFX_IMMCONSTANT_H__135B88C4_4175_11D1_B049_0020AF30269A__INCLUDED_ + +#if _MSC_VER >= 1000 +#pragma once +#endif // _MSC_VER >= 1000 + +#ifndef _IFCDLL_ +#define DLLIFC __declspec(dllimport) +#else +#define DLLIFC __declspec(dllexport) +#endif + +#include "ImmBaseTypes.h" +#include "ImmEffect.h" + + + +//================================================================ +// Constants +//================================================================ + +const POINT IMM_CONSTANT_DEFAULT_DIRECTION = { 1, 0 }; +#define IMM_CONSTANT_DEFAULT_DURATION 1000 // Milliseconds +#define IMM_CONSTANT_DEFAULT_MAGNITUDE 5000 + + + +//================================================================ +// CImmConstant +//================================================================ + +// +// ------ PUBLIC INTERFACE ------ +// + +class DLLIFC CImmConstant : public CImmEffect +{ + // + // CONSTRUCTOR/DESTRUCTOR + // + + public: + + // Constructor + CImmConstant(); + + // Destructor + virtual + ~CImmConstant(); + + + // + // ATTRIBUTES + // + + public: + + virtual BOOL + GetIsCompatibleGUID( + GUID &guid + ); + + virtual DWORD GetEffectType() + { return IMM_EFFECTTYPE_CONSTANTFORCE; } + + BOOL + ChangeParameters( + LONG lDirectionX, + LONG lDirectionY, + DWORD dwDuration = IMM_EFFECT_DONT_CHANGE, + LONG lMagnitude = IMM_EFFECT_DONT_CHANGE, + LPIMM_ENVELOPE pEnvelope = (LPIMM_ENVELOPE) IMM_EFFECT_DONT_CHANGE_PTR + ); + + BOOL + ChangeParametersPolar( + LONG lAngle, + DWORD dwDuration = IMM_EFFECT_DONT_CHANGE, + LONG lMagnitude = IMM_EFFECT_DONT_CHANGE, + LPIMM_ENVELOPE pEnvelope = (LPIMM_ENVELOPE) IMM_EFFECT_DONT_CHANGE_PTR + ); + + BOOL ChangeMagnitude( LONG lMagnitude ); + BOOL GetMagnitude( LONG &lMagnitude ); + + // + // OPERATIONS + // + + public: + + virtual BOOL + Initialize( + CImmDevice* pDevice, + const IMM_EFFECT &effect, + DWORD dwNoDownload = 0 + ); + + virtual + BOOL + Initialize( + CImmDevice* pDevice, + LONG lDirectionX = IMM_EFFECT_DEFAULT_DIRECTION_X, + LONG lDirectionY = IMM_EFFECT_DEFAULT_DIRECTION_Y, + DWORD dwDuration = IMM_CONSTANT_DEFAULT_DURATION, + LONG lMagnitude = IMM_CONSTANT_DEFAULT_MAGNITUDE, + LPIMM_ENVELOPE pEnvelope = NULL, + DWORD dwNoDownload = 0 + ); + + virtual + BOOL + InitializePolar( + CImmDevice* pDevice, + LONG lAngle = IMM_EFFECT_DEFAULT_ANGLE, + DWORD dwDuration = IMM_CONSTANT_DEFAULT_DURATION, + LONG lMagnitude = IMM_CONSTANT_DEFAULT_MAGNITUDE, + LPIMM_ENVELOPE pEnvelope = NULL, + DWORD dwNoDownload = 0 + ); + + +// +// ------ PRIVATE INTERFACE ------ +// + + // + // HELPERS + // + + protected: + + BOOL + set_parameters( + DWORD dwfCoordinates, + LONG lDirection0, + LONG lDirection1, + DWORD dwDuration, + LONG lMagnitude, + LPIMM_ENVELOPE pEnvelope + ); + + DWORD + change_parameters( + LONG lDirection0, + LONG lDirection1, + DWORD dwDuration, + LONG lMagnitude, + LPIMM_ENVELOPE pEnvelope + ); + + int + buffer_ifr_data( + TCHAR* pData + ); + + BOOL + get_ffe_data( + LPDIEFFECT pdiEffect + ); + + // + // INTERNAL DATA + // + + IMM_CONSTANTFORCE m_ConstantForce; + + protected: + +}; + + + +// +// INLINES +// + +inline BOOL +CImmConstant::GetIsCompatibleGUID(GUID &guid) +{ + return IsEqualGUID(guid, GUID_Imm_ConstantForce); +} + + +#endif // !defined(AFX_IMMCONSTANT_H__135B88C4_4175_11D1_B049_0020AF30269A__INCLUDED_) diff --git a/code/ff/IFC/ImmDXDevice.h b/code/ff/IFC/ImmDXDevice.h new file mode 100644 index 0000000..d754799 --- /dev/null +++ b/code/ff/IFC/ImmDXDevice.h @@ -0,0 +1,148 @@ +/********************************************************************** + Copyright (c) 1997 - 2000 Immersion Corporation + + Permission to use, copy, modify, distribute, and sell this + software and its documentation may be granted without fee; + interested parties are encouraged to request permission from + Immersion Corporation + 801 Fox Lane + San Jose, CA 95131 + 408-467-1900 + + IMMERSION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. + IN NO EVENT SHALL IMMERSION BE LIABLE FOR ANY SPECIAL, INDIRECT OR + CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, + NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + FILE: ImmDXDevice.h + + PURPOSE: Abstraction of DirectX Force Feedback device + + STARTED: 10/10/97 + + NOTES/REVISIONS: + 3/2/99 jrm (Jeff Mallett): Force-->Feel renaming + 3/15/99 jrm: __declspec(dllimport/dllexport) the whole class + +**********************************************************************/ + +#ifndef ImmDXDevice_h +#define ImmDXDevice_h + +#ifndef _IFCDLL_ +#define DLLIFC __declspec(dllimport) +#else +#define DLLIFC __declspec(dllexport) +#endif + +#include "ImmDevice.h" + + +//================================================================ +// CImmDXDevice +//================================================================ + +// +// ------ PUBLIC INTERFACE ------ +// + +class DLLIFC CImmDXDevice : public CImmDevice +{ + + // + // CONSTRUCTOR/DESCTRUCTOR + // + + public: + + // Constructor + CImmDXDevice(); + + // Destructor + virtual + ~CImmDXDevice(); + + + // + // ATTRIBUTES + // + + public: + + virtual LPIIMM_API + GetAPI() + { return (LPIIMM_API) m_piApi; } // actually LPDIRECTINPUT + + virtual LPIIMM_DEVICE + GetDevice() + { return (LPIIMM_DEVICE) m_piDevice; } // actually LPDIRECTINPUTDEVICE2 + + virtual DWORD GetProductType(); + + virtual BOOL GetDriverVersion( + DWORD &dwFFDriverVersion, + DWORD &dwFirmwareRevision, + DWORD &dwHardwareRevision); + + virtual int GetProductName(LPTSTR lpszProductName, int nMaxCount); + virtual int GetProductGUIDString(LPTSTR lpszGUID, int nMaxCount); + virtual GUID GetProductGUID(); + + // + // OPERATIONS + // + + public: + + BOOL + Initialize( + HANDLE hinstApp, + HANDLE hwndApp, + LPDIRECTINPUT pDI = NULL, + LPDIRECTINPUTDEVICE2 piDevice = NULL, + BOOL bEnumerate = TRUE + ); + + virtual BOOL + GetCurrentPosition( long &lXPos, long &lYPos ); + +// +// ------ PRIVATE INTERFACE ------ +// + + // + // HELPERS + // + + protected: + + virtual void + reset(); + + friend class CImmDevices; + static BOOL CALLBACK + devices_enum_proc( + LPDIDEVICEINSTANCE pImmDevInst, + LPVOID pv + ); + + + // + // INTERNAL DATA + // + + protected: + + // TODO: these are unused... delete them in future rev + BOOL m_bpDIPreExist; + BOOL m_bpDIDevicePreExist; + // end of useless variables + + LPDIRECTINPUT m_piApi; + LPDIRECTINPUTDEVICE2 m_piDevice; +}; + +#endif // ForceDXDevice_h diff --git a/code/ff/IFC/ImmDamper.h b/code/ff/IFC/ImmDamper.h new file mode 100644 index 0000000..68000db --- /dev/null +++ b/code/ff/IFC/ImmDamper.h @@ -0,0 +1,185 @@ +/********************************************************************** + Copyright (c) 1997 - 2000 Immersion Corporation + + Permission to use, copy, modify, distribute, and sell this + software and its documentation may be granted without fee; + interested parties are encouraged to request permission from + Immersion Corporation + 801 Fox Lane + San Jose, CA 95131 + 408-467-1900 + + IMMERSION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. + IN NO EVENT SHALL IMMERSION BE LIABLE FOR ANY SPECIAL, INDIRECT OR + CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, + NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + FILE: ImmDamper.h + + PURPOSE: Immersion Foundation Classes Damper Effect + + STARTED: Oct.14.97 + + NOTES/REVISIONS: + Mar.02.99 jrm (Jeff Mallett): Force-->Feel renaming + Mar.02.99 jrm: Added GetIsCompatibleGUID + Mar.15.99 jrm: __declspec(dllimport/dllexport) the whole class + Nov.15.99 efw (Evan Wies): Converted to IFC + +**********************************************************************/ + + +#if !defined(AFX_IMMDamper_H__135B88C4_4175_11D1_B049_0020AF30269A__INCLUDED_) +#define AFX_IMMDamper_H__135B88C4_4175_11D1_B049_0020AF30269A__INCLUDED_ + +#if _MSC_VER >= 1000 +#pragma once +#endif // _MSC_VER >= 1000 + +#ifndef _IFCDLL_ +#define DLLIFC __declspec(dllimport) +#else +#define DLLIFC __declspec(dllexport) +#endif + +#include +#include "ImmCondition.h" + + +//================================================================ +// Constants +//================================================================ + +#define IMM_DAMPER_DEFAULT_VISCOSITY 2500 +#define IMM_DAMPER_DEFAULT_SATURATION 10000 +#define IMM_DAMPER_DEFAULT_MIN_VELOCITY 0 + + + +//================================================================ +// CImmDamper +//================================================================ + +// +// ------ PUBLIC INTERFACE ------ +// + +class DLLIFC CImmDamper : public CImmCondition +{ + // + // CONSTRUCTOR/DESTRUCTOR + // + + public: + + // Constructor + CImmDamper(); + + // Destructor + virtual ~CImmDamper(); + + + // + // ATTRIBUTES + // + + public: + + virtual BOOL + GetIsCompatibleGUID( + GUID &guid + ); + + BOOL + ChangeParameters( + LONG lViscosity, + DWORD dwSaturation = IMM_EFFECT_DONT_CHANGE, + DWORD dwMinVelocity = IMM_EFFECT_DONT_CHANGE, + LONG lDirectionX = IMM_EFFECT_DONT_CHANGE, + LONG lDirectionY = IMM_EFFECT_DONT_CHANGE + ); + + BOOL + ChangeParametersPolar( + LONG lViscosity, + DWORD dwSaturation, + DWORD dwMinVelocity, + LONG lAngle + ); + + BOOL ChangeViscosity( LONG lViscosity ); + + BOOL ChangeMinVelocityX( DWORD dwMinVelocity ); + BOOL ChangeMinVelocityY( DWORD dwMinVelocity ); + //For setting both axes to the same value + BOOL ChangeMinVelocity( DWORD dwMinVelocity ); + + BOOL GetViscosity( LONG &lViscosity ); + + BOOL GetMinVelocityX( DWORD &dwMinVelocity ); + BOOL GetMinVelocityY( DWORD &dwMinVelocity ); + + // + // OPERATIONS + // + + public: + + virtual BOOL + Initialize( + CImmDevice* pDevice, + DWORD dwViscosity = IMM_DAMPER_DEFAULT_VISCOSITY, + DWORD dwSaturation = IMM_DAMPER_DEFAULT_SATURATION, + DWORD dwMinVelocity = IMM_DAMPER_DEFAULT_MIN_VELOCITY, + DWORD dwfAxis = IMM_EFFECT_AXIS_BOTH, + LONG lDirectionX = IMM_EFFECT_DEFAULT_DIRECTION_X, + LONG lDirectionY = IMM_EFFECT_DEFAULT_DIRECTION_Y, + DWORD dwNoDownload = 0 + ); + + virtual BOOL + InitializePolar( + CImmDevice* pDevice, + DWORD dwViscosity, + DWORD dwSaturation, + DWORD dwMinVelocity, + LONG lAngle, + DWORD dwNoDownload = 0 + ); + + +// +// ------ PRIVATE INTERFACE ------ +// + + // + // HELPERS + // + + protected: + + // + // INTERNAL DATA + // + + protected: + +}; + + + +// +// INLINES +// + +inline BOOL +CImmDamper::GetIsCompatibleGUID(GUID &guid) +{ + return IsEqualGUID(guid, GUID_Imm_Damper); +} + + +#endif // !defined(AFX_IMMDamper_H__135B88C4_4175_11D1_B049_0020AF30269A__INCLUDED_) diff --git a/code/ff/IFC/ImmDevice.h b/code/ff/IFC/ImmDevice.h new file mode 100644 index 0000000..21b396e --- /dev/null +++ b/code/ff/IFC/ImmDevice.h @@ -0,0 +1,280 @@ +/********************************************************************** + Copyright (c) 1997 - 2000 Immersion Corporation + + Permission to use, copy, modify, distribute, and sell this + software and its documentation may be granted without fee; + interested parties are encouraged to request permission from + Immersion Corporation + 801 Fox Lane + San Jose, CA 95131 + 408-467-1900 + + IMMERSION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. + IN NO EVENT SHALL IMMERSION BE LIABLE FOR ANY SPECIAL, INDIRECT OR + CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, + NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + FILE: ImmDevice.h + + PURPOSE: Abstract Base Device Class for Force Foundation Classes + + STARTED: 10/10/97 + + NOTES/REVISIONS: + 3/2/99 jrm (Jeff Mallett): Force-->Feel renaming + 3/15/99 jrm: __declspec(dllimport/dllexport) the whole class + 3/16/99 jrm: Made abstract. Moved functionality to CImmMouse/CImmDXDevice + +**********************************************************************/ + +#if !defined(AFX_FORCEDEVICE_H__135B88C4_4175_11D1_B049_0020AF30269A__INCLUDED_) +#define AFX_FORCEDEVICE_H__135B88C4_4175_11D1_B049_0020AF30269A__INCLUDED_ + +#if _MSC_VER >= 1000 +#pragma once +#endif // _MSC_VER >= 1000 + +#ifndef _IFCDLL_ +#define DLLIFC __declspec(dllimport) +#else +#define DLLIFC __declspec(dllexport) +#endif + +#include +#include "ImmBaseTypes.h" + +#ifdef IFC_EFFECT_CACHING + #include "ImmEffectSuite.h" +#endif + + +//================================================================ +// Device and Technology types +//================================================================ + +//Company IDs +const DWORD IMM_OTHERPARTNER =0x01000000; +const DWORD IMM_IMMERSION =0x02000000; +const DWORD IMM_ACTLABS =0x03000000; +const DWORD IMM_ANKO =0x04000000; +const DWORD IMM_AVB =0x05000000; +const DWORD IMM_BOEDER =0x06000000; +const DWORD IMM_CHPRODUCTS =0x07000000; +const DWORD IMM_CHIC =0x08000000; +const DWORD IMM_GUILLEMOT =0x09000000; +const DWORD IMM_GENIUS =0x0a000000; +const DWORD IMM_HAPP =0x0b000000; +const DWORD IMM_INTERACT =0x0c000000; +const DWORD IMM_INTERACTIVEIO =0x0d000000; +const DWORD IMM_KYE =0x0e000000; +const DWORD IMM_LMP =0x0f000000; +const DWORD IMM_LOGITECH =0x10000000; +const DWORD IMM_MADCATZ =0x11000000; +const DWORD IMM_MICROSOFT =0x12000000; +const DWORD IMM_PADIX =0x13000000; +const DWORD IMM_PRIMAX =0x14000000; +const DWORD IMM_QUANTUM3D =0x15000000; +const DWORD IMM_ROCKFIRE =0x16000000; +const DWORD IMM_SCT =0x17000000; +const DWORD IMM_SMELECTRONIC =0x18000000; +const DWORD IMM_SYSGRATION =0x19000000; +const DWORD IMM_THRUSTMASTER =0x1a000000; +const DWORD IMM_TRUST =0x1b000000; +const DWORD IMM_VIKINGS =0x1c000000; + +// Device IDs +const DWORD IMM_OTHERDEVICE =0x00000001; +const DWORD IMM_JOYSTICK =0x00000002; +const DWORD IMM_WHEEL =0x00000003; +const DWORD IMM_GAMEPAD =0x00000004; +const DWORD IMM_ABSMOUSE =0x00000005; +const DWORD IMM_RELMOUSE =0x00000006; + +//Technology IDs +//Note that these are bit masks +const DWORD IMM_OTHERTECH =0x00000001; +const DWORD IMM_FULLFF =0x00000002; +const DWORD IMM_IHDFF =0x00000004; +const DWORD IMM_VIBROFF =0x00000008; + +//Product Types (not to be confused with product GUIDs) +const DWORD IMM_JOYSTICK_FULLFF = MAKELONG(IMM_FULLFF, IMM_JOYSTICK); +const DWORD IMM_WHEEL_FULLFF = MAKELONG(IMM_FULLFF, IMM_WHEEL); +const DWORD IMM_GAMEPAD_FULLFF = MAKELONG(IMM_FULLFF, IMM_GAMEPAD); +const DWORD IMM_ABSMOUSE_FULLFF = MAKELONG(IMM_FULLFF, IMM_ABSMOUSE); + +const DWORD IMM_JOYSTICK_IHDFF = MAKELONG(IMM_IHDFF, IMM_JOYSTICK); +const DWORD IMM_WHEEL_IHDFF = MAKELONG(IMM_IHDFF, IMM_WHEEL); +const DWORD IMM_GAMEPAD_IHDFF = MAKELONG(IMM_IHDFF, IMM_GAMEPAD); +const DWORD IMM_RELMOUSE_IHDFF = MAKELONG(IMM_IHDFF, IMM_RELMOUSE); + +const DWORD IMM_JOYSTICK_VIBROFF= MAKELONG(IMM_VIBROFF, IMM_JOYSTICK); +const DWORD IMM_WHEEL_VIBROFF = MAKELONG(IMM_VIBROFF, IMM_WHEEL); +const DWORD IMM_GAMEPAD_VIBROFF = MAKELONG(IMM_VIBROFF, IMM_GAMEPAD); +const DWORD IMM_RELMOUSE_VIBROFF= MAKELONG(IMM_VIBROFF, IMM_RELMOUSE); + +//================================================================ +// CImmDevice +//================================================================ + +// +// ------ PUBLIC INTERFACE ------ +// + +class DLLIFC CImmDevice +{ + // + // CONSTRUCTOR/DESCTRUCTOR + // + + public: + + // Constructor + CImmDevice(); + + // Destructor + virtual + ~CImmDevice(); + + + // + // ATTRIBUTES + // + + public: + + virtual LPIIMM_API + GetAPI() + = 0; // pure virtual function + + virtual LPIIMM_DEVICE // Will actually return LPDIRECTINPUTDEVICE2 for DX supported device + GetDevice() + = 0; // pure virtual function + + DWORD + GetDeviceType() const + { return m_dwDeviceType; } + + virtual DWORD GetProductType() = 0; + virtual BOOL GetDriverVersion( + DWORD &dwFFDriverVersion, + DWORD &dwFirmwareRevision, + DWORD &dwHardwareRevision) + = 0; + + virtual int GetProductName(LPTSTR lpszProductName, int nMaxCount) = 0; + virtual int GetProductGUIDString(LPTSTR lpszGUID, int nMaxCount) = 0; + virtual GUID GetProductGUID() = 0; + + static BOOL GetIFCVersion(DWORD &dwMajor, DWORD &dwMinor, DWORD &dwBuild, DWORD &dwBuildMinor); + static BOOL GetImmAPIVersion(DWORD &dwMajor, DWORD &dwMinor, DWORD &dwBuild, DWORD &dwBuildMinor); + static BOOL GetDXVersion(DWORD &dwMajor, DWORD &dwMinor, DWORD &dwBuild, DWORD &dwBuildMinor); + + // + // OPERATIONS + // + + public: + + static CImmDevice * + CreateDevice(HINSTANCE hinstApp, HWND hwndApp); + + virtual BOOL + GetCurrentPosition( long &lXPos, long &lYPos ) + = 0; // pure virtual function + + virtual BOOL + ChangeScreenResolution( + BOOL bAutoSet, + DWORD dwXScreenSize = 0, + DWORD dwYScreenSize = 0 + ); + + // The default state is using standard Win32 Mouse messages (e.g., WM_MOUSEMOVE) + // and functions (e.g, GetCursorPos). Call only to switch to relative mode + // if not using standard Win32 Mouse services (e.g., DirectInput) for mouse + // input. + BOOL + UsesWin32MouseServices( + BOOL bWin32MouseServ + ); + + // Another syntax for SwitchToAbsoluteMode. + // The default is Absolute mode. Call only to switch to Relative mode or + // to switch back to Absolute mode. + virtual BOOL + SwitchToAbsoluteMode( + BOOL bAbsMode + ); + +// +// ------ PRIVATE INTERFACE ------ +// + + // + // CACHING + // + +#ifdef IFC_EFFECT_CACHING + public: + + void Cache_AddEffect(CImmEffect *pImmEffect); + void Cache_RemoveEffect(const CImmEffect *pImmEffect); + void Cache_SwapOutEffect(); + + protected: + + void Cache_LoadEffectSuite(CImmEffectSuite *pSuite, BOOL bCreateOnDevice); + void Cache_UnloadEffectSuite(CImmEffectSuite *pSuite, BOOL bUnloadFromDevice); + + CEffectList m_Cache; // List of all effects created on device +#endif + + // + // HELPERS + // + + protected: + + // Performs device preparation by setting the device's parameters + virtual BOOL + prepare_device(); + + virtual void + reset() + = 0; // pure virtual function + + static BOOL CALLBACK + enum_didevices_proc( + LPDIDEVICEINSTANCE pImmDevInst, + LPVOID pv + ); + + static BOOL CALLBACK + enum_devices_proc( + LPIMM_DEVICEINSTANCE pImmDevInst, + LPVOID pv + ); + + void + detach_effects(); + + // + // INTERNAL DATA + // + + protected: + + BOOL m_bInitialized; + DWORD m_dwDeviceType; + GUID m_guidDevice; + BOOL m_bGuidValid; + DWORD m_dwProductType; + +}; + + +#endif // !defined(AFX_FORCEDEVICE_H__135B88C4_4175_11D1_B049_0020AF30269A__INCLUDED_) diff --git a/code/ff/IFC/ImmDevices.h b/code/ff/IFC/ImmDevices.h new file mode 100644 index 0000000..bd89210 --- /dev/null +++ b/code/ff/IFC/ImmDevices.h @@ -0,0 +1,156 @@ +/********************************************************************** + Copyright (c) 2000 Immersion Corporation + + Permission to use, copy, modify, distribute, and sell this + software and its documentation may be granted without fee; + interested parties are encouraged to request permission from + Immersion Corporation + 801 Fox Lane + San Jose, CA 95131 + 408-467-1900 + + IMMERSION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. + IN NO EVENT SHALL IMMERSION BE LIABLE FOR ANY SPECIAL, INDIRECT OR + CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, + NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + FILE: ImmDevices.h + + PURPOSE: Abstract Base Device Class for Immersion Foundation Classes + + STARTED: 3/29/00 + + NOTES/REVISIONS: + 3/29/00 jrm (Jeff Mallett): Started + +**********************************************************************/ + +#if !defined(AFX_FORCEDEVICES_H__135B88C4_4175_11D1_B049_0020AF30269A__INCLUDED_) +#define AFX_FORCEDEVICES_H__135B88C4_4175_11D1_B049_0020AF30269A__INCLUDED_ + +#if _MSC_VER >= 1000 +#pragma once +#endif // _MSC_VER >= 1000 + +#ifndef _IFCDLL_ +#define DLLIFC __declspec(dllimport) +#else +#define DLLIFC __declspec(dllexport) +#endif + +#include "ImmBaseTypes.h" + + + +typedef enum { + IMM_ENUMERATE_IMM_DEVICES = 0x00000001, + IMM_ENUMERATE_DX_DEVICES = 0x00000002, + IMM_ENUMERATE_ALL = 0xFFFFFFFF +} IMM_ENUMERATE; + +typedef enum { + IMM_NO_PREFERENCE = 0x00000000, + IMM_PREFER_IMM_DEVICES = 0x00000001, + IMM_PREFER_DX_DEVICES = 0x00000002 +} IMM_ENUMERATE_PREFERENCE; + +class CImmDevices; +class CInitializeEnum { +public: + HANDLE m_hinstApp; + HANDLE m_hwndApp; + DWORD m_dwCooperativeFlag; + CImmDevices *m_pDevices; + long m_lMaximumDevices; +}; + +//================================================================ +// CImmDevices +//================================================================ + +typedef class CImmDevice * IMM_DEVICE_PTR; + + +// +// ------ PUBLIC INTERFACE ------ +// + +class DLLIFC CImmDevices { + + // + // CONSTRUCTOR/DESCTRUCTOR + // + + public: + + CImmDevices(); + ~CImmDevices(); + + + // + // ATTRIBUTES + // + + public: + + long + GetNumDevices() + { return m_lNumDevices; } + + IMM_DEVICE_PTR + GetDevice(long lIndex); + + + // + // OPERATIONS + // + + public: + + void + AddDevice(IMM_DEVICE_PTR pDevice); + + long + CreateDevices( + HINSTANCE hinstApp, + HWND hwndApp, + long lMaximumDevices = -1, // means "all" + IMM_ENUMERATE type = IMM_ENUMERATE_ALL, + IMM_ENUMERATE_PREFERENCE preference = IMM_NO_PREFERENCE + ); + + +// +// ------ PRIVATE INTERFACE ------ +// + + // + // HELPERS + // + +protected: + + BOOL + enumerate_dx_devices(CInitializeEnum *pIE); + + BOOL + enumerate_imm_devices(CInitializeEnum *pIE); + + void + clean_up(); + + // + // INTERNAL DATA + // + + protected: + + long m_lNumDevices; + IMM_DEVICE_PTR *m_DeviceArray; +}; + +#endif // !defined(AFX_FORCEDEVICE_H__135B88C4_4175_11D1_B049_0020AF30269A__INCLUDED_) + diff --git a/code/ff/IFC/ImmEffect.h b/code/ff/IFC/ImmEffect.h new file mode 100644 index 0000000..dfeceea --- /dev/null +++ b/code/ff/IFC/ImmEffect.h @@ -0,0 +1,440 @@ +/********************************************************************** + Copyright (c) 1997 - 2000 Immersion Corporation + + Permission to use, copy, modify, distribute, and sell this + software and its documentation may be granted without fee; + interested parties are encouraged to request permission from + Immersion Corporation + 801 Fox Lane + San Jose, CA 95131 + 408-467-1900 + + IMMERSION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. + IN NO EVENT SHALL IMMERSION BE LIABLE FOR ANY SPECIAL, INDIRECT OR + CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, + NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + FILE: ImmEffect.h + + PURPOSE: Immersion Foundation Classes Base Effect + + STARTED: Oct.10.97 + + NOTES/REVISIONS: + Mar.02.99 jrm (Jeff Mallett): Force-->Feel renaming + Mar.02.99 jrm: Added GetIsCompatibleGUID and feel_to_DI_GUID + Mar.15.99 jrm: __declspec(dllimport/dllexport) the whole class + Nov.15.99 efw (Evan Wies): Converted to IFC + +**********************************************************************/ + + +#if !defined(AFX_IMMEffect_H__135B88C4_4175_11D1_B049_0020AF30269A__INCLUDED_) +#define AFX_IMMEffect_H__135B88C4_4175_11D1_B049_0020AF30269A__INCLUDED_ + +#if _MSC_VER >= 1000 +#pragma once +#endif // _MSC_VER >= 1000 + +#ifndef _IFCDLL_ +#define DLLIFC __declspec(dllimport) +#else +#define DLLIFC __declspec(dllexport) +#endif + +#include "ImmBaseTypes.h" +#include "ImmDevice.h" +class CImmProject; + +//================================================================ +// Constants +//================================================================ + +#define IMM_EFFECT_AXIS_X 1 +#define IMM_EFFECT_AXIS_Y 2 +#define IMM_EFFECT_AXIS_BOTH 3 +#define IMM_EFFECT_AXIS_DIRECTIONAL 4 +#define IMM_EFFECT_DONT_CHANGE MINLONG +#define IMM_EFFECT_DONT_CHANGE_PTR MAXDWORD +const POINT IMM_EFFECT_DONT_CHANGE_POINT = { 0xFFFFFFFF, 0xFFFFFFFF }; +const POINT IMM_EFFECT_MOUSE_POS_AT_START = { MAXLONG, MAXLONG }; + +#define IMM_EFFECT_DEFAULT_ENVELOPE NULL +#define IMM_EFFECT_DEFAULT_DIRECTION_X 1 +#define IMM_EFFECT_DEFAULT_DIRECTION_Y 1 +#define IMM_EFFECT_DEFAULT_ANGLE 0 + +// GENERIC_EFFECT_PTR +// This is really a pointer to a child of CImmEffect. +typedef class CImmEffect * GENERIC_EFFECT_PTR; + + +//================================================================ +// CImmEffect +//================================================================ + +// +// ------ PUBLIC INTERFACE ------ +// + +class DLLIFC CImmEffect +{ + // + // CONSTRUCTOR/DESTRUCTOR + // + + public: + + // Constructor + CImmEffect( + const GUID& rguidEffect + ); + + // Destructor + virtual + ~CImmEffect(); + + // + // ATTRIBUTES + // + + public: + + LPIIMM_EFFECT + GetEffect() + { return m_piImmEffect; } + + CImmDevice* + GetDevice() + { return m_pImmDevice; } + + BOOL + GetStatus( + DWORD* pdwStatus + ); + + void + GetParameters(IMM_EFFECT &Effect); + BOOL GetEnvelope( LPIMM_ENVELOPE pEnvelope ); + + BOOL GetDuration( DWORD &dwDuration ); + BOOL GetGain( DWORD &dwGain ); + BOOL GetStartDelay( DWORD &dwStartDelay ); + BOOL GetTriggerButton( DWORD &dwTriggerButton ); + BOOL GetTriggerRepeatInterval( DWORD &dwTriggerRepeatInterval ); + BOOL GetDirection( LONG &lDirectionX, LONG &lDirectionY ); + BOOL GetDirection( LONG &lAngle ); + + BOOL GetIterations( DWORD &dwIterations ); + + GUID + GetGUID() + { return m_guidEffect; } + + virtual BOOL + GetIsCompatibleGUID( + GUID & /* guid */ + ) + { return true; } + + virtual DWORD GetEffectType() + { return 0; } + + LPCSTR + GetName() + { return m_lpszName; } + + // Allocates an object of the correct IFC class from the given GUID + static GENERIC_EFFECT_PTR + NewObjectFromGUID( + GUID &guid + ); + + BOOL + ChangeBaseParams( + LONG lDirectionX, + LONG lDirectionY, + DWORD dwDuration = IMM_EFFECT_DONT_CHANGE, + LPIMM_ENVELOPE pEnvelope = (LPIMM_ENVELOPE) IMM_EFFECT_DONT_CHANGE_PTR, + DWORD dwSamplePeriod = IMM_EFFECT_DONT_CHANGE, + DWORD dwGain = IMM_EFFECT_DONT_CHANGE, + DWORD dwTriggerButton = IMM_EFFECT_DONT_CHANGE, + DWORD dwTriggerRepeatInterval = IMM_EFFECT_DONT_CHANGE +#ifdef IFC_START_DELAY + ,DWORD dwStartDelay = IMM_EFFECT_DONT_CHANGE // milliseconds +#endif + ); + + BOOL + ChangeBaseParamsPolar( + LONG lAngle, + DWORD dwDuration = IMM_EFFECT_DONT_CHANGE, // milliseconds + LPIMM_ENVELOPE pEnvelope = (LPIMM_ENVELOPE) IMM_EFFECT_DONT_CHANGE_PTR, + DWORD dwSamplePeriod = IMM_EFFECT_DONT_CHANGE, + DWORD dwGain = IMM_EFFECT_DONT_CHANGE, + DWORD dwTriggerButton = IMM_EFFECT_DONT_CHANGE, + DWORD dwTriggerRepeatInterval = IMM_EFFECT_DONT_CHANGE +#ifdef IFC_START_DELAY + ,DWORD dwStartDelay = IMM_EFFECT_DONT_CHANGE // milliseconds +#endif + ); + + BOOL + ChangeDirection( + LONG lDirectionX, + LONG lDirectionY + ); + + BOOL + ChangeDirection( + LONG lAngle + ); + + BOOL + ChangeDuration( + DWORD dwDuration + ); + + BOOL + ChangeGain( + DWORD dwGain + ); + + BOOL + ChangeStartDelay( + DWORD dwStartDelay + ); + + BOOL + ChangeTriggerButton( + DWORD dwTriggerButton + ); + + BOOL + ChangeTriggerRepeatInterval( + DWORD dwTriggerRepeatInterval + ); + + BOOL + ChangeIterations( + DWORD dwIterations + ); + + BOOL + ChangeEnvelope( + DWORD dwAttackLevel, + DWORD dwAttackTime, // microseconds + DWORD dwFadeLevel, + DWORD dwFadeTime // microseconds + ); + + BOOL + ChangeEnvelope( + LPIMM_ENVELOPE pEnvelope + ); + + + // + // OPERATIONS + // + + public: + + virtual BOOL + Initialize( + CImmDevice* pDevice, + const IMM_EFFECT &effect, + DWORD dwNoDownload = 0 + ); + + virtual BOOL + InitializeFromProject( + CImmProject &project, + LPCSTR lpszEffectName, + CImmDevice* pDevice = NULL, + DWORD dwNoDownload = 0 + ); + + virtual BOOL + Start( + DWORD dwIterations = IMM_EFFECT_DONT_CHANGE, + DWORD dwFlags = 0 +#ifdef IFC_START_DELAY + , BOOL bAllowStartDelayEmulation = true +#endif + ); + + virtual BOOL + Stop(); + + +// +// ------ PRIVATE INTERFACE ------ +// + + // + // CACHING + // + +#ifdef IFC_EFFECT_CACHING + + public: + + friend class CEffectList; + friend class CImmCompoundEffect; + + BOOL GetIsPlaying(); + BOOL GetIsTriggered() const; + short GetPriority() const { return m_Priority; } + void SetPriority(short priority) { m_Priority = priority; } + virtual HRESULT Unload(); + virtual void Reload(); + + //Althought public, this should only be used internally. + BOOL + set_outside_effect( + CImmEffect* pImmOutsideEffect + ); + + BOOL + get_is_inside_effect() + { return m_bIsInsideEffect; } + + public: + + ECacheState m_CacheState; // effect's status in the cache + BOOL m_bInCurrentSuite; // is the effect in the currently loaded suite? + short m_Priority; // Priority within suite: higher number is higher priority + DWORD m_dwLastStarted; // when last started (0 = never) or when param change made on device + DWORD m_dwLastStopped; // when last stopped (0 = not since last start) + DWORD m_dwLastLoaded; // when last loaded with CImmEffectSuite::Load or Create + + protected: + + CImmDevice *m_pImmDevice; // ### Use instead of m_piImmDevice +#endif + + // + // HELPERS + // + protected: + +#ifdef IFC_START_DELAY + void EmulateStartDelay( + DWORD dwIterations, + DWORD dwNoDownload + ); +#endif + +#ifdef IFC_EFFECT_CACHING + public: // initalize needs to be called by CImmDevice +#endif + BOOL + initialize( + CImmDevice* pDevice, + DWORD dwNoDownload + ); +#ifdef IFC_EFFECT_CACHING + protected: +#endif + + HRESULT + set_parameters_on_device( + DWORD dwFlags + ); + + BOOL + set_name( + const char *lpszName + ); + + void + imm_to_DI_GUID( + GUID &guid + ); + + void + DI_to_imm_GUID( + GUID &guid + ); + + void + reset(); + + void + reset_effect_struct(); + + void + reset_device(); + + void + buffer_direction( + TCHAR** pData + ); + + void + buffer_long_param( + TCHAR** pData, + LPCSTR lpszKey, + long lDefault, + long lValue + ); + + void + buffer_dword_param( + TCHAR** pData, + LPCSTR lpszKey, + DWORD dwDefault, + DWORD dwValue + ); + + virtual int + buffer_ifr_data( + TCHAR* pData + ); + + virtual BOOL + get_ffe_data( + LPDIEFFECT pdiEffect + ); + + + // + // INTERNAL DATA + // + + protected: + + IMM_EFFECT m_Effect; + DWORD m_dwaAxes[2]; + LONG m_laDirections[2]; + IMM_ENVELOPE m_Envelope; + + GUID m_guidEffect; + BOOL m_bIsPlaying; + DWORD m_dwDeviceType; + LPIIMM_DEVICE m_piImmDevice; // Might also be holding LPDIRECTINPUTDEVICE2 + LPIIMM_EFFECT m_piImmEffect; + DWORD m_cAxes; // Number of axes + DWORD m_dwNoDownload; + DWORD m_dwIterations; + char *m_lpszName; // Name of this effect primative + + // Needed for co-ordinating events for Enclosures/Ellipes and the inside effects. + BOOL m_bIsInsideEffect; + CImmEffect* m_pOutsideEffect; + +#ifdef IFC_START_DELAY + public: + // Prevents access to dangling pointer when this is deleted + // All relevent code may be removed when all hardware and drivers support start delay + CImmEffect **m_ppTimerRef; // pointer to pointer to this. +#endif +}; + + +#endif // !defined(AFX_ImmEffect_H__135B88C4_4175_11D1_B049_0020AF30269A__INCLUDED_) + diff --git a/code/ff/IFC/ImmEffectSuite.h b/code/ff/IFC/ImmEffectSuite.h new file mode 100644 index 0000000..e1ed622 --- /dev/null +++ b/code/ff/IFC/ImmEffectSuite.h @@ -0,0 +1,103 @@ + +/********************************************************************** + Copyright (c) 1999 - 2000 Immersion Corporation + + Permission to use, copy, modify, distribute, and sell this + software and its documentation may be granted without fee; + interested parties are encouraged to request permission from + Immersion Corporation + 801 Fox Lane + San Jose, CA 95131 + 408-467-1900 + + IMMERSION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. + IN NO EVENT SHALL IMMERSION BE LIABLE FOR ANY SPECIAL, INDIRECT OR + CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, + NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + FILE: ImmEffectSuite.h + + PURPOSE: Caching of effects + + STARTED: 6/16/99 Jeff Mallett + + NOTES/REVISIONS: + +**********************************************************************/ + +#if !defined(AFX_FEELEFFECTSUITE_H__135B88C4_4175_11D1_B049_0020AF30269A__INCLUDED_) +#define AFX_FEELEFFECTSUITE_H__135B88C4_4175_11D1_B049_0020AF30269A__INCLUDED_ + +#if _MSC_VER >= 1000 +#pragma once +#endif // _MSC_VER >= 1000 + +#ifndef _IFCDLL_ +#define DLLIFC __declspec(dllimport) +#else +#define DLLIFC __declspec(dllexport) +#endif + +#include "ImmBaseTypes.h" + +#ifdef IFC_EFFECT_CACHING + +class CImmDevice; //#include "ImmDevice.h" +class CImmEffect; //#include "ImmEffect.h" + +typedef enum { + IMMCACHE_NOT_ON_DEVICE, + IMMCACHE_ON_DEVICE, + IMMCACHE_SWAPPED_OUT +} ECacheState; + + +//================================================================ +// CEffectList, CEffectListElement +//================================================================ + +class DLLIFC CEffectListElement +{ +public: + CEffectListElement() : m_pImmEffect(NULL), m_pNext(NULL) { } + + CImmEffect *m_pImmEffect; + CEffectListElement *m_pNext; +}; + +class DLLIFC CEffectList +{ +public: + CEffectList() : m_pFirstEffect(NULL) { } + ~CEffectList(); + BOOL AddEffect(CImmEffect *pImmEffect); + BOOL RemoveEffect(const CImmEffect *pImmEffect); + void ClearDevice(CImmDevice *pImmDevice); + + CEffectListElement *m_pFirstEffect; +}; + + +//================================================================ +// CImmEffectSuite +//================================================================ + +class CImmEffectSuite +{ +public: + CImmEffectSuite() : m_bCurrentSuite(false) { } + CEffectListElement *GetFirstEffect(); + void AddEffect(CImmEffect *pImmEffect); + void RemoveEffect(CImmEffect *pImmEffect); + void SetPriorities(short priority); + + BOOL m_bCurrentSuite; // Is the suite the "current suite"? +private: + CEffectList m_EffectList; // List of effects in suite +}; + +#endif // IFC_EFFECT_CACHING +#endif // !defined(AFX_FEELEFFECTSUITE_H__135B88C4_4175_11D1_B049_0020AF30269A__INCLUDED_) diff --git a/code/ff/IFC/ImmEllipse.h b/code/ff/IFC/ImmEllipse.h new file mode 100644 index 0000000..155d416 --- /dev/null +++ b/code/ff/IFC/ImmEllipse.h @@ -0,0 +1,295 @@ +/********************************************************************** + Copyright (c) 1997 - 2000 Immersion Corporation + + Permission to use, copy, modify, distribute, and sell this + software and its documentation may be granted without fee; + interested parties are encouraged to request permission from + Immersion Corporation + 801 Fox Lane + San Jose, CA 95131 + 408-467-1900 + + IMMERSION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. + IN NO EVENT SHALL IMMERSION BE LIABLE FOR ANY SPECIAL, INDIRECT OR + CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, + NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + FILE: ImmEllipse.h + + PURPOSE: Base Ellipse Class for Immersion Foundation Classes + + STARTED: 10/29/97 + + NOTES/REVISIONS: + 3/2/99 jrm (Jeff Mallett): Force-->Feel renaming + 3/2/99 jrm: Added GetIsCompatibleGUID + 3/15/99 jrm: __declspec(dllimport/dllexport) the whole class + 11/15/99 sdr (Steve Rank): Converted to IFC + +**********************************************************************/ + + +#if !defined(AFX_IMMELLIPSE_H__135B88C4_4175_11D1_B049_0020AF30269A__INCLUDED_) +#define AFX_IMMELLIPSE_H__135B88C4_4175_11D1_B049_0020AF30269A__INCLUDED_ + +#if _MSC_VER >= 1000 +#pragma once +#endif // _MSC_VER >= 1000 + +#ifndef _IFCDLL_ +#define DLLIFC __declspec(dllimport) +#else +#define DLLIFC __declspec(dllexport) +#endif + +#include "ImmBaseTypes.h" +#include "ImmEffect.h" + + + +//================================================================ +// Constants +//================================================================ + +#define IMM_ELLIPSE_DEFAULT_STIFFNESS 5000 +#define IMM_ELLIPSE_DEFAULT_SATURATION 10000 +#define IMM_ELLIPSE_DEFAULT_WIDTH 10 +#define IMM_ELLIPSE_HEIGHT_AUTO MAXDWORD +#define IMM_ELLIPSE_DEFAULT_HEIGHT IMM_ELLIPSE_HEIGHT_AUTO +#define IMM_ELLIPSE_WALL_WIDTH_AUTO MAXDWORD +#define IMM_ELLIPSE_DEFAULT_WALL_WIDTH IMM_ELLIPSE_WALL_WIDTH_AUTO +#define IMM_ELLIPSE_DEFAULT_STIFFNESS_MASK IMM_STIFF_ANYWALL +#define IMM_ELLIPSE_DEFAULT_CLIPPING_MASK IMM_CLIP_NONE + +#define IMM_ELLIPSE_DEFAULT_CENTER_POINT IMM_EFFECT_MOUSE_POS_AT_START + + + + + +//================================================================ +// CImmEllipse +//================================================================ + +// +// ------ PUBLIC INTERFACE ------ +// + +class DLLIFC CImmEllipse : public CImmEffect +{ + // + // CONSTRUCTOR/DESCTRUCTOR + // + + public: + + // Constructor + CImmEllipse(); + + // Destructor + virtual + ~CImmEllipse(); + + + // + // ATTRIBUTES + // + + public: + + virtual BOOL + GetIsCompatibleGUID( + GUID &guid + ); + + virtual DWORD GetEffectType() + { return IMM_EFFECTTYPE_ELLIPSE; } + + BOOL + ChangeParameters( + POINT pntCenter, + DWORD dwWidth = IMM_EFFECT_DONT_CHANGE, + DWORD dwHeight = IMM_EFFECT_DONT_CHANGE, + LONG lStiffness = IMM_EFFECT_DONT_CHANGE, + DWORD dwWallThickness = IMM_EFFECT_DONT_CHANGE, + DWORD dwSaturation = IMM_EFFECT_DONT_CHANGE, + DWORD dwStiffnessMask = IMM_EFFECT_DONT_CHANGE, + DWORD dwClippingMask = IMM_EFFECT_DONT_CHANGE, + CImmEffect* pInsideEffect = (CImmEffect*) IMM_EFFECT_DONT_CHANGE, + LONG lAngle = IMM_EFFECT_DONT_CHANGE + ); + + BOOL + ChangeParameters( + LPCRECT pRectOutside, + LONG lStiffness = IMM_EFFECT_DONT_CHANGE, + DWORD dwWallThickness = IMM_EFFECT_DONT_CHANGE, + DWORD dwSaturation = IMM_EFFECT_DONT_CHANGE, + DWORD dwStiffnessMask = IMM_EFFECT_DONT_CHANGE, + DWORD dwClippingMask = IMM_EFFECT_DONT_CHANGE, + CImmEffect* pInsideEffect = (CImmEffect*) IMM_EFFECT_DONT_CHANGE, + LONG lAngle = IMM_EFFECT_DONT_CHANGE + ); + + + BOOL ChangeStiffness ( LONG lStiffness ); + BOOL ChangeWallThickness( DWORD dwThickness ); + BOOL ChangeSaturation ( DWORD dwSaturation ); + BOOL ChangeStiffnessMask( DWORD dwStiffnessMask ); + BOOL ChangeClippingMask ( DWORD dwClippingMask ); + BOOL ChangeInsideEffect ( CImmEffect* pInsideEffect ); + + BOOL + ChangeRect( + LPCRECT pRect + ); + + + BOOL + ChangeCenter( + POINT pntCenter + ); + + + BOOL + ChangeCenter( + LONG x, + LONG y + ); + + BOOL GetStiffness ( LONG &lStiffness ); + BOOL GetWallThickness( DWORD &dwThickness ); + BOOL GetSaturation ( DWORD &dwSaturation ); + BOOL GetStiffnessMask( DWORD &dwStiffnessMask ); + BOOL GetClippingMask ( DWORD &dwClippingMask ); + + BOOL GetRect( RECT* pRect ); + BOOL GetCenter( POINT &pntCenter ); + BOOL GetCenter( LONG &x, LONG &y); + + CImmEffect* GetInsideEffect(); + + // + // OPERATIONS + // + + public: + + virtual BOOL + Initialize( + CImmDevice* pDevice, + const IMM_EFFECT &effect, + DWORD dwNoDownload = 0 + ); + + BOOL + Initialize( + CImmDevice* pDevice, + DWORD dwWidth = IMM_ELLIPSE_DEFAULT_WIDTH, + DWORD dwHeight = IMM_ELLIPSE_DEFAULT_HEIGHT, + LONG lStiffness = IMM_ELLIPSE_DEFAULT_STIFFNESS, + DWORD dwWallWidth = IMM_ELLIPSE_DEFAULT_WALL_WIDTH, + DWORD dwSaturation = IMM_ELLIPSE_DEFAULT_SATURATION, + DWORD dwStiffnessMask = IMM_ELLIPSE_DEFAULT_STIFFNESS_MASK, + DWORD dwClippingMask = IMM_ELLIPSE_DEFAULT_CLIPPING_MASK, + POINT pntCenter = IMM_ELLIPSE_DEFAULT_CENTER_POINT, + CImmEffect* pInsideEffect = NULL, + LONG lAngle = IMM_EFFECT_DEFAULT_ANGLE, + DWORD dwNoDownload = 0 + ); + + + BOOL + Initialize( + CImmDevice* pDevice, + LPCRECT pRectOutside, + LONG lStiffness = IMM_ELLIPSE_DEFAULT_STIFFNESS, + DWORD dwWallWidth = IMM_ELLIPSE_DEFAULT_WALL_WIDTH, + DWORD dwSaturation = IMM_ELLIPSE_DEFAULT_SATURATION, + DWORD dwStiffnessMask = IMM_ELLIPSE_DEFAULT_STIFFNESS_MASK, + DWORD dwClippingMask = IMM_ELLIPSE_DEFAULT_CLIPPING_MASK, + CImmEffect* pInsideEffect = NULL, + LONG lAngle = IMM_EFFECT_DEFAULT_ANGLE, + DWORD dwNoDownload = 0 + ); + + + virtual BOOL + Start( + DWORD dwIterations = 1, + DWORD dwFlags = 0, + BOOL bAllowStartDelayEmulation = true + ); + + HRESULT Unload(); + void Reload(); + + +// +// ------ PRIVATE INTERFACE ------ +// + + // + // HELPERS + // + + protected: + + BOOL + set_parameters( + LPCRECT pRectOutside, + LONG lStiffness, + DWORD dwWallWidth, + DWORD dwSaturation, + DWORD dwStiffnessMask, + DWORD dwClippingMask, + CImmEffect* pInsideEffect, + LONG lAngle + ); + + DWORD + change_parameters( + LPCRECT prectBoundary, + LONG lStiffness, + DWORD dwWallThickness, + DWORD dwSaturation, + DWORD dwStiffnessMask, + DWORD dwClippingMask, + CImmEffect* pInsideEffect, + LONG lAngle + ); + + int + buffer_ifr_data( + TCHAR* pData + ); + + // + // INTERNAL DATA + // + + protected: + + IMM_ELLIPSE m_ellipse; + BOOL m_bUseMousePosAtStart; + + // Needed for co-ordinating events for Enclosures/Ellipes and the inside effects. + CImmEffect* m_pInsideEffect; +}; + + + +// +// INLINES +// + +inline BOOL +CImmEllipse::GetIsCompatibleGUID(GUID &guid) +{ + return IsEqualGUID(guid, GUID_Imm_Ellipse); +} + +#endif // !defined(AFX_IMMELLIPSE_H__135B88C4_4175_11D1_B049_0020AF30269A__INCLUDED_) diff --git a/code/ff/IFC/ImmEnclosure.h b/code/ff/IFC/ImmEnclosure.h new file mode 100644 index 0000000..4697b28 --- /dev/null +++ b/code/ff/IFC/ImmEnclosure.h @@ -0,0 +1,325 @@ +/********************************************************************** + Copyright (c) 1997 - 2000 Immersion Corporation + + Permission to use, copy, modify, distribute, and sell this + software and its documentation may be granted without fee; + interested parties are encouraged to request permission from + Immersion Corporation + 801 Fox Lane + San Jose, CA 95131 + 408-467-1900 + + IMMERSION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. + IN NO EVENT SHALL IMMERSION BE LIABLE FOR ANY SPECIAL, INDIRECT OR + CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, + NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + FILE: ImmEnclosure.h + + PURPOSE: Base Enclosure Class for Immersion Foundation Classes + + STARTED: 10/29/97 + + NOTES/REVISIONS: + 3/2/99 jrm (Jeff Mallett): Force-->Feel renaming + 3/2/99 jrm: Added GetIsCompatibleGUID + 3/15/99 jrm: __declspec(dllimport/dllexport) the whole class + 11/15/99 sdr (Steve Rank): Converted to IFC + +**********************************************************************/ + + +#if !defined(AFX_IMMENCLOSURE_H__135B88C4_4175_11D1_B049_0020AF30269A__INCLUDED_) +#define AFX_IMMENCLOSURE_H__135B88C4_4175_11D1_B049_0020AF30269A__INCLUDED_ + +#if _MSC_VER >= 1000 +#pragma once +#endif // _MSC_VER >= 1000 + +#ifndef _IFCDLL_ +#define DLLIFC __declspec(dllimport) +#else +#define DLLIFC __declspec(dllexport) +#endif + +#include "ImmBaseTypes.h" +#include "ImmEffect.h" + + +//================================================================ +// Constants +//================================================================ + + +#define IMM_ENCLOSURE_DEFAULT_STIFFNESS 5000 +#define IMM_ENCLOSURE_DEFAULT_SATURATION 10000 +#define IMM_ENCLOSURE_DEFAULT_WIDTH 10 +#define IMM_ENCLOSURE_HEIGHT_AUTO MAXDWORD +#define IMM_ENCLOSURE_DEFAULT_HEIGHT IMM_ENCLOSURE_HEIGHT_AUTO +#define IMM_ENCLOSURE_WALL_WIDTH_AUTO MAXDWORD +#define IMM_ENCLOSURE_DEFAULT_WALL_WIDTH IMM_ENCLOSURE_WALL_WIDTH_AUTO +#define IMM_ENCLOSURE_DEFAULT_STIFFNESS_MASK IMM_STIFF_ANYWALL +#define IMM_ENCLOSURE_DEFAULT_CLIPPING_MASK IMM_CLIP_NONE + +#define IMM_ENCLOSURE_DEFAULT_CENTER_POINT IMM_EFFECT_MOUSE_POS_AT_START + + + + + +//================================================================ +// CImmEnclosure +//================================================================ + +// +// ------ PUBLIC INTERFACE ------ +// + +class DLLIFC CImmEnclosure : public CImmEffect +{ + // + // CONSTRUCTOR/DESCTRUCTOR + // + + public: + + // Constructor + CImmEnclosure(); + + // Destructor + virtual + ~CImmEnclosure(); + + + // + // ATTRIBUTES + // + + public: + + virtual BOOL + GetIsCompatibleGUID( + GUID &guid + ); + + virtual DWORD GetEffectType() + { return IMM_EFFECTTYPE_ENCLOSURE; } + + BOOL + ChangeParameters( + POINT pntCenter, + DWORD dwWidth = IMM_EFFECT_DONT_CHANGE, + DWORD dwHeight = IMM_EFFECT_DONT_CHANGE, + LONG lTopAndBottomWallStiffness = IMM_EFFECT_DONT_CHANGE, + LONG lLeftAndRightWallStiffness = IMM_EFFECT_DONT_CHANGE, + DWORD dwTopAndBottomWallWallWidth = IMM_EFFECT_DONT_CHANGE, + DWORD dwLeftAndRightWallWallWidth = IMM_EFFECT_DONT_CHANGE, + DWORD dwTopAndBottomWallSaturation = IMM_EFFECT_DONT_CHANGE, + DWORD dwLeftAndRightWallSaturation = IMM_EFFECT_DONT_CHANGE, + DWORD dwStiffnessMask = IMM_EFFECT_DONT_CHANGE, + DWORD dwClippingMask = IMM_EFFECT_DONT_CHANGE, + CImmEffect* pInsideEffect = (CImmEffect*) IMM_EFFECT_DONT_CHANGE, + LONG lAngle = IMM_EFFECT_DONT_CHANGE + ); + + BOOL + ChangeParameters( + LPCRECT pRectOutside, + LONG lTopAndBottomWallStiffness = IMM_EFFECT_DONT_CHANGE, + LONG lLeftAndRightWallStiffness = IMM_EFFECT_DONT_CHANGE, + DWORD dwTopAndBottomWallWallThickness = IMM_EFFECT_DONT_CHANGE, + DWORD dwLeftAndRightWallWallThickness = IMM_EFFECT_DONT_CHANGE, + DWORD dwTopAndBottomWallSaturation = IMM_EFFECT_DONT_CHANGE, + DWORD dwLeftAndRightWallSaturation = IMM_EFFECT_DONT_CHANGE, + DWORD dwStiffnessMask = IMM_EFFECT_DONT_CHANGE, + DWORD dwClippingMask = IMM_EFFECT_DONT_CHANGE, + CImmEffect* pInsideEffect = (CImmEffect*) IMM_EFFECT_DONT_CHANGE, + LONG lAngle = IMM_EFFECT_DONT_CHANGE + ); + + BOOL ChangeTopAndBottomWallStiffness ( LONG lTopAndBottomWallStiffness ); + BOOL ChangeLeftAndRightWallStiffness ( LONG lLeftAndRightWallStiffness ); + BOOL ChangeTopAndBottomWallThickness ( DWORD dwTopAndBottomWallThickness ); + BOOL ChangeLeftAndRightWallThickness ( DWORD dwLeftAndRightWallThickness ); + BOOL ChangeTopAndBottomWallSaturation( DWORD dwTopAndBottomWallSaturation ); + BOOL ChangeLeftAndRightWallSaturation( DWORD dwLeftAndRightWallSaturation ); + BOOL ChangeStiffnessMask ( DWORD dwStiffnessMask ); + BOOL ChangeClippingMask ( DWORD dwClippingMask ); + BOOL ChangeInsideEffect ( CImmEffect* pInsideEffect ); + + BOOL + ChangeRect( + LPCRECT pRect + ); + + + BOOL + ChangeCenter( + POINT pntCenter + ); + + + BOOL + ChangeCenter( + LONG x, + LONG y + ); + + BOOL + ShowRect( + BOOL bRectOn + ); + + BOOL GetTopAndBottomWallStiffness ( LONG &lTopAndBottomWallStiffness ); + BOOL GetLeftAndRightWallStiffness ( LONG &lLeftAndRightWallStiffness ); + BOOL GetTopAndBottomWallThickness ( DWORD &dwTopAndBottomWallThickness ); + BOOL GetLeftAndRightWallThickness ( DWORD &dwLeftAndRightWallThickness ); + BOOL GetTopAndBottomWallSaturation ( DWORD &dwTopAndBottomWallSaturation ); + BOOL GetLeftAndRightWallSaturation ( DWORD &dwLeftAndRightWallSaturation ); + BOOL GetStiffnessMask ( DWORD &dwStiffnessMask ); + BOOL GetClippingMask ( DWORD &dwClippingMask ); + + BOOL GetRect( RECT* pRect ); + BOOL GetCenter( POINT &pntCenter ); + BOOL GetCenter( LONG &x, LONG &y); + + CImmEffect* GetInsideEffect (); + + // + // OPERATIONS + // + + public: + + virtual BOOL + Initialize( + CImmDevice* pDevice, + const IMM_EFFECT &effect, + DWORD dwNoDownload = 0 + ); + + BOOL + Initialize( + CImmDevice* pDevice, + DWORD dwWidth = IMM_ENCLOSURE_DEFAULT_WIDTH, + DWORD dwHeight = IMM_ENCLOSURE_DEFAULT_HEIGHT, + LONG lTopAndBottomWallStiffness = IMM_ENCLOSURE_DEFAULT_STIFFNESS, + LONG lLeftAndRightWallStiffness = IMM_ENCLOSURE_DEFAULT_STIFFNESS, + DWORD dwTopAndBottomWallWallWidth = IMM_ENCLOSURE_DEFAULT_WALL_WIDTH, + DWORD dwLeftAndRightWallWallWidth = IMM_ENCLOSURE_DEFAULT_WALL_WIDTH, + DWORD dwTopAndBottomWallSaturation = IMM_ENCLOSURE_DEFAULT_SATURATION, + DWORD dwLeftAndRightWallSaturation = IMM_ENCLOSURE_DEFAULT_SATURATION, + DWORD dwStiffnessMask = IMM_ENCLOSURE_DEFAULT_STIFFNESS_MASK, + DWORD dwClippingMask = IMM_ENCLOSURE_DEFAULT_CLIPPING_MASK, + POINT pntCenter = IMM_ENCLOSURE_DEFAULT_CENTER_POINT, + CImmEffect* pInsideEffect = NULL, + LONG lAngle = IMM_EFFECT_DEFAULT_ANGLE, + DWORD dwNoDownload = 0 + ); + + + BOOL + Initialize( + CImmDevice* pDevice, + LPCRECT pRectOutside, + LONG lTopAndBottomWallStiffness = IMM_ENCLOSURE_DEFAULT_STIFFNESS, + LONG lLeftAndRightWallStiffness = IMM_ENCLOSURE_DEFAULT_STIFFNESS, + DWORD dwTopAndBottomWallWallWidth = IMM_ENCLOSURE_DEFAULT_WALL_WIDTH, + DWORD dwLeftAndRightWallWallWidth = IMM_ENCLOSURE_DEFAULT_WALL_WIDTH, + DWORD dwTopAndBottomWallSaturation = IMM_ENCLOSURE_DEFAULT_SATURATION, + DWORD dwLeftAndRightWallSaturation = IMM_ENCLOSURE_DEFAULT_SATURATION, + DWORD dwStiffnessMask = IMM_ENCLOSURE_DEFAULT_STIFFNESS_MASK, + DWORD dwClippingMask = IMM_ENCLOSURE_DEFAULT_CLIPPING_MASK, + CImmEffect* pInsideEffect = NULL, + LONG lAngle = IMM_EFFECT_DEFAULT_ANGLE, + DWORD dwNoDownload = 0 + ); + + + virtual BOOL + Start( + DWORD dwIterations = 1, + DWORD dwFlags = 0, + BOOL bAllowStartDelayEmulation = true + ); + + virtual BOOL + Stop(); + + HRESULT Unload(); + void Reload(); + +// +// ------ PRIVATE INTERFACE ------ +// + + // + // HELPERS + // + + protected: + + BOOL + set_parameters( + LPCRECT pRectOutside, + LONG lTopAndBottomWallStiffness, + LONG lLeftAndRightWallStiffness, + DWORD dwTopAndBottomWallWallWidth, + DWORD dwLeftAndRightWallWallWidth, + DWORD dwTopAndBottomWallSaturation, + DWORD dwLeftAndRightWallSaturation, + DWORD dwStiffnessMask, + DWORD dwClippingMask, + CImmEffect* pInsideEffect, + LONG lAngle + ); + + DWORD + change_parameters( + LPCRECT prectBoundary, + LONG lTopAndBottomWallStiffness, + LONG lLeftAndRightWallStiffness, + DWORD dwTopAndBottomWallThickness, + DWORD dwLeftAndRightWallThickness, + DWORD dwTopAndBottomWallSaturation, + DWORD dwLeftAndRightWallSaturation, + DWORD dwStiffnessMask, + DWORD dwClippingMask, + CImmEffect* pInsideEffect, + LONG lAngle + ); + + int + buffer_ifr_data( + TCHAR* pData + ); + + // + // INTERNAL DATA + // + + protected: + + IMM_ENCLOSURE m_enclosure; + BOOL m_bUseMousePosAtStart; + + // Needed for co-ordinating events for Enclosures/Ellipes and the inside effects. + CImmEffect* m_pInsideEffect; + +}; + + +// +// INLINES +// + +inline BOOL +CImmEnclosure::GetIsCompatibleGUID(GUID &guid) +{ + return IsEqualGUID(guid, GUID_Imm_Enclosure); +} + +#endif // !defined(AFX_IMMENCLOSURE_H__135B88C4_4175_11D1_B049_0020AF30269A__INCLUDED_) diff --git a/code/ff/IFC/ImmFriction.h b/code/ff/IFC/ImmFriction.h new file mode 100644 index 0000000..fe97302 --- /dev/null +++ b/code/ff/IFC/ImmFriction.h @@ -0,0 +1,176 @@ +/********************************************************************** + Copyright (c) 1997 - 2000 Immersion Corporation + + Permission to use, copy, modify, distribute, and sell this + software and its documentation may be granted without fee; + interested parties are encouraged to request permission from + Immersion Corporation + 801 Fox Lane + San Jose, CA 95131 + 408-467-1900 + + IMMERSION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. + IN NO EVENT SHALL IMMERSION BE LIABLE FOR ANY SPECIAL, INDIRECT OR + CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, + NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + FILE: ImmFriction.h + + PURPOSE: Immersion Foundation Classes Friction Effect + + STARTED: Dec.29.97 + + NOTES/REVISIONS: + Mar.02.99 jrm (Jeff Mallett): Force-->Feel renaming + Mar.02.99 jrm: Added GetIsCompatibleGUID + Mar.15.99 jrm: __declspec(dllimport/dllexport) the whole class + Nov.15.99 efw (Evan Wies): Converted to IFC + +**********************************************************************/ + + +#if !defined(AFX_ImmFriction_H__135B88C4_4175_11D1_B049_0020AF30269A__INCLUDED_) +#define AFX_ImmFriction_H__135B88C4_4175_11D1_B049_0020AF30269A__INCLUDED_ + +#if _MSC_VER >= 1000 +#pragma once +#endif // _MSC_VER >= 1000 + +#ifndef _IFCDLL_ +#define DLLIFC __declspec(dllimport) +#else +#define DLLIFC __declspec(dllexport) +#endif + +#include +#include "ImmCondition.h" + + +//================================================================ +// Constants +//================================================================ + +#define IMM_FRICTION_DEFAULT_COEFFICIENT 2500 +#define IMM_FRICTION_DEFAULT_MIN_VELOCITY 0 + + +//================================================================ +// CImmFriction +//================================================================ + +// +// ------ PUBLIC INTERFACE ------ +// + +class DLLIFC CImmFriction : public CImmCondition +{ + // + // CONSTRUCTOR/DESTRUCTOR + // + + public: + + // Constructor + CImmFriction(); + + // Destructor + virtual + ~CImmFriction(); + + + // + // ATTRIBUTES + // + + public: + + virtual BOOL + GetIsCompatibleGUID( + GUID &guid + ); + + BOOL + ChangeParameters( + DWORD dwCoefficient, + DWORD dwMinVelocity = IMM_EFFECT_DONT_CHANGE, + LONG lDirectionX = IMM_EFFECT_DONT_CHANGE, + LONG lDirectionY = IMM_EFFECT_DONT_CHANGE + ); + + BOOL + ChangeParametersPolar( + DWORD dwCoefficient, + DWORD dwMinVelocity, + LONG lAngle + ); + + BOOL ChangeMinVelocityX( DWORD dwMinVelocity ); + BOOL ChangeMinVelocityY( DWORD dwMinVelocity ); + //For setting both axes to the same value + BOOL ChangeMinVelocity( DWORD dwMinVelocity ); + + BOOL GetMinVelocityX( DWORD &dwMinVelocity ); + BOOL GetMinVelocityY( DWORD &dwMinVelocity ); + + // + // OPERATIONS + // + + public: + + virtual BOOL + Initialize( + CImmDevice* pDevice, + DWORD dwCoefficient = IMM_FRICTION_DEFAULT_COEFFICIENT, + DWORD dwMinVelocity = IMM_FRICTION_DEFAULT_MIN_VELOCITY, + DWORD dwfAxis = IMM_EFFECT_AXIS_BOTH, + LONG lDirectionX = IMM_EFFECT_DEFAULT_DIRECTION_X, + LONG lDirectionY = IMM_EFFECT_DEFAULT_DIRECTION_Y, + DWORD dwNoDownload = 0 + ); + + virtual BOOL + InitializePolar( + CImmDevice* pDevice, + DWORD dwCoefficient, + DWORD dwMinVelocity, + LONG lAngle, + DWORD dwNoDownload = 0 + ); + + +// +// ------ PRIVATE INTERFACE ------ +// + + // + // HELPERS + // + + protected: + + // + // INTERNAL DATA + // + + protected: + +}; + + + +// +// INLINES +// + +inline BOOL +CImmFriction::GetIsCompatibleGUID(GUID &guid) +{ + return IsEqualGUID(guid, GUID_Imm_Friction); +} + + +#endif // !defined(AFX_ImmFriction_H__135B88C4_4175_11D1_B049_0020AF30269A__INCLUDED_) diff --git a/code/ff/IFC/ImmGrid.h b/code/ff/IFC/ImmGrid.h new file mode 100644 index 0000000..c91c152 --- /dev/null +++ b/code/ff/IFC/ImmGrid.h @@ -0,0 +1,179 @@ +/********************************************************************** + Copyright (c) 1997 - 2000 Immersion Corporation + + Permission to use, copy, modify, distribute, and sell this + software and its documentation may be granted without fee; + interested parties are encouraged to request permission from + Immersion Corporation + 801 Fox Lane + San Jose, CA 95131 + 408-467-1900 + + IMMERSION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. + IN NO EVENT SHALL IMMERSION BE LIABLE FOR ANY SPECIAL, INDIRECT OR + CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, + NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + FILE: ImmGrid.h + + PURPOSE: Immersion Foundation Classes Grid Effect + + STARTED: Dec.11.97 + + NOTES/REVISIONS: + Mar.02.99 jrm (Jeff Mallett): Force-->Feel renaming + Mar.02.99 jrm: Added GetIsCompatibleGUID + Mar.02.99 jrm: __declspec(dllimport/dllexport) the whole class + Nov.15.99 efw (Evan Wies): Converted to IFC + +**********************************************************************/ + + +#if !defined(AFX_IMMGrid_H__135B88C4_4175_11D1_B049_0020AF30269A__INCLUDED_) +#define AFX_IMMGrid_H__135B88C4_4175_11D1_B049_0020AF30269A__INCLUDED_ + +#if _MSC_VER >= 1000 +#pragma once +#endif // _MSC_VER >= 1000 + +#ifndef _IFCDLL_ +#define DLLIFC __declspec(dllimport) +#else +#define DLLIFC __declspec(dllexport) +#endif + +#include +#include "ImmCondition.h" + + +//================================================================ +// Constants +//================================================================ + +#define IMM_GRID_DEFAULT_HORIZ_OFFSET 0 +#define IMM_GRID_DEFAULT_VERT_OFFSET 0 +#define IMM_GRID_DEFAULT_HORIZ_SPACING 100 +#define IMM_GRID_DEFAULT_VERT_SPACING 100 +#define IMM_GRID_DEFAULT_NODE_STRENGTH 5000 +#define IMM_GRID_DEFAULT_NODE_SATURATION 10000 + + + +//================================================================ +// CImmGrid +//================================================================ + +// +// ------ PUBLIC INTERFACE ------ +// + +class DLLIFC CImmGrid : public CImmCondition +{ + // + // CONSTRUCTOR/DESTRUCTOR + // + + public: + + // Constructor + CImmGrid(); + + // Destructor + virtual + ~CImmGrid(); + + + // + // ATTRIBUTES + // + + public: + + virtual BOOL + GetIsCompatibleGUID( + GUID &guid + ); + + BOOL + ChangeParameters( + DWORD dwHorizSpacing, + DWORD dwVertSpacing = IMM_EFFECT_DONT_CHANGE, + LONG lHorizNodeStrength = IMM_EFFECT_DONT_CHANGE, + LONG lVertNodeStrength = IMM_EFFECT_DONT_CHANGE, + LONG lHorizOffset = IMM_EFFECT_DONT_CHANGE, + LONG lVertOffset = IMM_EFFECT_DONT_CHANGE, + DWORD dwHorizNodeSaturation = IMM_EFFECT_DONT_CHANGE, + DWORD dwVertNodeSaturation = IMM_EFFECT_DONT_CHANGE + ); + + BOOL ChangeHSpacing( DWORD dwHorizSpacing ); + BOOL ChangeVSpacing( DWORD dwVertSpacing ); + BOOL ChangeHNodeStrength( LONG lHorizNodeStrength ); + BOOL ChangeVNodeStrength( LONG lVertNodeStrength ); + BOOL ChangeOffset( POINT pntOffset ); + BOOL ChangeHNodeSaturation( DWORD dwHorizNodeSaturation ); + BOOL ChangeVNodeSaturation( DWORD dwVertNodeSaturation ); + + BOOL GetHSpacing( DWORD &dwHorizSpacing ); + BOOL GetVSpacing( DWORD &dwVertSpacing ); + BOOL GetHNodeStrength( LONG &lHorizNodeStrength ); + BOOL GetVNodeStrength( LONG &lVertNodeStrength ); + BOOL GetOffset( POINT &pntOffset ); + BOOL GetHNodeSaturation( DWORD &dwHorizNodeSaturation ); + BOOL GetVNodeSaturation( DWORD &dwVertNodeSaturation ); + + // + // OPERATIONS + // + + public: + + virtual BOOL + Initialize( + CImmDevice* pDevice, + DWORD dwHorizSpacing = IMM_GRID_DEFAULT_HORIZ_SPACING, + DWORD dwVertSpacing = IMM_GRID_DEFAULT_VERT_SPACING, + LONG lHorizNodeStrength = IMM_GRID_DEFAULT_NODE_STRENGTH, + LONG lVertNodeStrength = IMM_GRID_DEFAULT_NODE_STRENGTH, + DWORD dwHorizOffset = IMM_GRID_DEFAULT_HORIZ_OFFSET, + DWORD dwVertOffset = IMM_GRID_DEFAULT_VERT_OFFSET, + DWORD dwHorizNodeSaturation = IMM_GRID_DEFAULT_NODE_SATURATION, + DWORD dwVertNodeSaturation = IMM_GRID_DEFAULT_NODE_SATURATION, + DWORD dwNoDownload = 0 + ); + + +// +// ------ PRIVATE INTERFACE ------ +// + + // + // HELPERS + // + + protected: + + // + // INTERNAL DATA + // + + protected: + +}; + + + +// +// INLINES +// + +inline BOOL +CImmGrid::GetIsCompatibleGUID(GUID &guid) +{ + return IsEqualGUID(guid, GUID_Imm_Grid); +} + +#endif // !defined(AFX_IMMGrid_H__135B88C4_4175_11D1_B049_0020AF30269A__INCLUDED_) diff --git a/code/ff/IFC/ImmIFR.h b/code/ff/IFC/ImmIFR.h new file mode 100644 index 0000000..b24db3f --- /dev/null +++ b/code/ff/IFC/ImmIFR.h @@ -0,0 +1,308 @@ +/********************************************************************** + Copyright (c) 1999 - 2000 Immersion Corporation + + Permission to use, copy, modify, distribute, and sell this + software and its documentation may be granted without fee; + interested parties are encouraged to request permission from + Immersion Corporation + 801 Fox Lane + San Jose, CA 95131 + 408-467-1900 + + IMMERSION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. + IN NO EVENT SHALL IMMERSION BE LIABLE FOR ANY SPECIAL, INDIRECT OR + CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, + NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + FILE: FEELitIFR.h + + PURPOSE: Input/Output for IFR Files, FEELit version + + STARTED: + + NOTES/REVISIONS: + +**********************************************************************/ + +#if !defined( _IMMIFR_H_) +#define _IMMIFR_H_ + +#ifndef __FEELITAPI_INCLUDED__ + #error include 'dinput.h' before including this file for structures. +#endif /* !__DINPUT_INCLUDED__ */ + +#define IFRAPI __stdcall + +#if !defined(_IFCDLL_) +#define DLLAPI __declspec(dllimport) +#else +#define DLLAPI __declspec(dllexport) +#endif + +#if defined __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* +** CONSTANTS +*/ + +/* +** RT_IMMERSION - Resource type for IFR projects stored as resources. +** This is the resource type looked for by IFLoadProjectResource(). +*/ +#define RT_IMMERSION ((LPCSTR)"IMMERSION") + + +/* +** TYPES/STRUCTURES +*/ + +/* +** HIFRPROJECT - used to identify a loaded project as a whole. +** individual objects within a project are uniquely referenced by name. +** Created by the IFLoadProject*() functions and released by IFReleaseProject(). +*/ +typedef LPVOID HIFRPROJECT; + +/* +** IFREffect - contains the information needed to create a DI effect +** using IDirectInputEffect::CreateEffect(). An array of pointers to these +** structures is allocated and returned by IFCreateEffectStructs(). +*/ +typedef struct { + GUID guid; + DWORD dwIterations; + char *effectName; + LPIMM_EFFECT lpDIEffect; +} IFREffect; + + +/* +** FUNCTION DECLARATIONS +*/ + +/* +** IFLoadProjectResource() - Load a project from a resource. +** hRsrcModule - handle of the module containing the project definition resource. +** pRsrcName - name or MAKEINTRESOURCE(id) identifier of resource to load. +** pDevice - device for which the project is being loaded. If NULL, +** effects will be created generically, and IFCreateEffects() will fail. +** Returns an identifier for the loaded project, or NULL if unsuccessful. +*/ +DLLAPI +HIFRPROJECT +IFRAPI +IFRLoadProjectResource( + HMODULE hRsrcModule, + LPCSTR pRsrcName, + LPIIMM_DEVICE pDevice ); + +/* +** IFLoadProjectPointer() - Load a project from a pointer. +** pProject - points to a project definition. +** pDevice - device for which the project is being loaded. If NULL, +** effects will be created generically, and IFCreateEffects() will fail. +** Returns an identifier for the loaded project, or NULL if unsuccessful. +*/ +DLLAPI +HIFRPROJECT +IFRAPI +IFRLoadProjectPointer( + LPVOID pProject, + LPIIMM_DEVICE pDevice ); + +/* +** IFLoadProjectFile() - Load a project from a file. +** pProjectFileName - points to a project file name. +** pDevice - device for which the project is being loaded. If NULL, +** effects will be created generically, and IFCreateEffects() will fail. +** Returns an identifier for the loaded project, or NULL if unsuccessful. +*/ +DLLAPI +HIFRPROJECT +IFRAPI +IFRLoadProjectFile( + LPCSTR pProjectFileName, + LPIIMM_DEVICE pDevice ); + +/* +** IFRLoadProjectFromMemory() - Load a project from memory. +** +** In cases where a file or resource is readily accessible, it may +** be necessary to pass IFR formated information through memory. +** +** pProjectDef - memory addres that contains information from an IFR file. +** pDevice - device for which the project is being loaded. If NULL, +** effects will be created generically, and IFRCreateEffects() will fail. +** Returns an identifier for the loaded project, or NULL if unsuccessful. +*/ +DLLAPI +HIFRPROJECT +IFRAPI +IFRLoadProjectFromMemory( + LPVOID pProjectDef, + LPIIMM_DEVICE pDevice ); + +/* +** IFLoadProjectObjectPointer() - Load a project from a pointer to a single +** object definition (usually used only by the editor). +** pObject - points to an object definition. +** pDevice - device for which the project is being loaded. If NULL, +** effects will be created generically, and IFCreateEffects() will fail. +** Returns an identifier for the loaded project, or NULL if unsuccessful. +*/ +DLLAPI +HIFRPROJECT +IFRAPI +IFRLoadProjectObjectPointer( + LPVOID pObject, + LPIIMM_DEVICE pDevice ); + +/* +** IFReleaseProject() - Release a loaded project. +** hProject - identifies the project to be released. +** Returns TRUE if the project is released, FALSE if it is an invalid project. +*/ +DLLAPI +BOOL +IFRAPI +IFRReleaseProject( + HIFRPROJECT hProject ); + +/* +** IFCreateEffectStructs() - Create IFREffects for a named effect. +** hProject - identifies the project containing the object. +** pObjectName - name of the object for which to create structures. +** pNumEffects - if not NULL will be set to a count of the IFREffect +** structures in the array (not including the terminating NULL pointer.) +** Returns a pointer to the allocated array of pointers to IFREffect +** structures. The array is terminated with a NULL pointer. If the +** function fails, a NULL pointer is returned. +*/ +DLLAPI +IFREffect ** +IFRAPI +IFRCreateEffectStructs( + HIFRPROJECT hProject, + LPCSTR pObjectName, + int *pNumEffects ); + +DLLAPI +IFREffect ** +IFRAPI +IFRCreateEffectStructsByIndex( + HIFRPROJECT hProject, + int nObjectIndex, + int *pNumEffects ); + +DLLAPI +int +IFRAPI +IFRGetNumEffects( + HIFRPROJECT hProject + ); + +DLLAPI +LPCSTR +IFRAPI +IFRGetObjectNameByIndex( + HIFRPROJECT hProject, + int nObjectIndex ); + +DLLAPI +LPCSTR +IFRAPI +IFRGetObjectSoundPath( + HIFRPROJECT hProject, + LPCSTR pObjectName ); + +DLLAPI +DWORD +IFRAPI +IFRGetObjectType( + HIFRPROJECT hProject, + LPCSTR pObjectName ); + +DLLAPI +DWORD +IFRAPI +IFRGetObjectTypeByIndex( + HIFRPROJECT hProject, + int nObjectIndex ); + +DLLAPI +LPCSTR +IFRAPI +IFRGetObjectNameByGUID( + HIFRPROJECT hProject, + GUID *pGUID ); + +DLLAPI +GUID +IFRAPI +IFRGetObjectID( + HIFRPROJECT hProject, + LPCSTR pObjectName); + +DLLAPI +GUID* +IFRAPI +IFRGetContainedObjIDs( + HIFRPROJECT hProject, + LPCSTR pCompoundObjName); + + +/* +** IFReleaseEffectStructs() - Release an array of IFREffects. +** hProject - identifies the project for which the effects were created. +** pEffects - points to the array of IFREffect pointers to be released. +** Returns TRUE if the array is released, FALSE if it is an invalid array. +*/ +DLLAPI +BOOL +IFRAPI +IFRReleaseEffectStructs( + HIFRPROJECT hProject, + IFREffect **pEffects ); + +/* +** IFCreateEffects() - Creates the DirectInput effects using +** IDirectInput::CreateEffect(). +** hProject - identifies the project containing the object. +** pObjectName - name of the object for which to create effects. +** pNumEffects - if not NULL will be set to a count of the IDirectInputEffect +** pointers in the array (not including the terminating NULL pointer.) +** Returns a pointer to the allocated array of pointers to IDirectInputEffects. +** The array is terminated with a NULL pointer. If the function fails, +** a NULL pointer is returned. +*/ +DLLAPI +LPIIMM_EFFECT * +IFRAPI +IFRCreateEffects( + HIFRPROJECT hProject, + LPCSTR pObjectName, + int *pNumEffects ); + +/* +** IFReleaseEffects() - Releases an array of IDirectInputEffect structures. +** hProject - identifies the project for which the effects were created. +** pEffects - points to the array if IDirectInputEffect pointers to be released. +** Returns TRUE if the array is released, FALSE if it is an invalid array. +*/ +DLLAPI +BOOL +IFRAPI +IFRReleaseEffects( + HIFRPROJECT hProject, + LPIIMM_EFFECT *pEffects ); + +#if defined __cplusplus +} +#endif /* __cplusplus */ + +#endif /* !IMMIFR_h */ diff --git a/code/ff/IFC/ImmInertia.h b/code/ff/IFC/ImmInertia.h new file mode 100644 index 0000000..9a27cb3 --- /dev/null +++ b/code/ff/IFC/ImmInertia.h @@ -0,0 +1,183 @@ +/********************************************************************** + Copyright (c) 1997 - 2000 Immersion Corporation + + Permission to use, copy, modify, distribute, and sell this + software and its documentation may be granted without fee; + interested parties are encouraged to request permission from + Immersion Corporation + 801 Fox Lane + San Jose, CA 95131 + 408-467-1900 + + IMMERSION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. + IN NO EVENT SHALL IMMERSION BE LIABLE FOR ANY SPECIAL, INDIRECT OR + CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, + NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + FILE: ImmInertia.h + + PURPOSE: Immersion Foundation Classes Inertia Effect + + STARTED: Dec.29.97 + + NOTES/REVISIONS: + Mar.02.99 jrm (Jeff Mallett): Force-->Feel renaming + Mar.02.99 jrm: Added GetIsCompatibleGUID + Mar.15.99 jrm: __declspec(dllimport/dllexport) the whole class + Nov.15.99 efw (Evan Wies): Converted to IFC + +**********************************************************************/ + + +#if !defined(AFX_IMMInertia_H__135B88C4_4175_11D1_B049_0020AF30269A__INCLUDED_) +#define AFX_IMMInertia_H__135B88C4_4175_11D1_B049_0020AF30269A__INCLUDED_ + +#if _MSC_VER >= 1000 +#pragma once +#endif // _MSC_VER >= 1000 + +#ifndef _IFCDLL_ +#define DLLIFC __declspec(dllimport) +#else +#define DLLIFC __declspec(dllexport) +#endif + +#include +#include "ImmCondition.h" + + +//================================================================ +// Constants +//================================================================ + +#define IMM_INERTIA_DEFAULT_COEFFICIENT 2500 +#define IMM_INERTIA_DEFAULT_SATURATION 10000 +#define IMM_INERTIA_DEFAULT_MIN_ACCELERATION 0 + + + +//================================================================ +// CImmInertia +//================================================================ + +// +// ------ PUBLIC INTERFACE ------ +// + +class DLLIFC CImmInertia : public CImmCondition +{ + // + // CONSTRUCTOR/DESTRUCTOR + // + + public: + + // Constructor + CImmInertia(); + + // Destructor + virtual + ~CImmInertia(); + + + // + // ATTRIBUTES + // + + public: + + virtual BOOL + GetIsCompatibleGUID( + GUID &guid + ); + + BOOL + ChangeParameters( + DWORD dwCoefficient, + DWORD dwSaturation = IMM_EFFECT_DONT_CHANGE, + DWORD dwMinAcceleration = IMM_EFFECT_DONT_CHANGE, + LONG lDirectionX = IMM_EFFECT_DONT_CHANGE, + LONG lDirectionY = IMM_EFFECT_DONT_CHANGE + ); + + BOOL + ChangeParametersPolar( + DWORD dwCoefficient, + DWORD dwSaturation, + DWORD dwMinAcceleration, + LONG lAngle + ); + + + BOOL ChangeMinAccelerationX( DWORD dwMinAcceleration ); + BOOL ChangeMinAccelerationY( DWORD dwMinAcceleration ); + BOOL ChangeMinAcceleration( DWORD dwMinAcceleration ); + + BOOL GetMinAccelerationX( DWORD &dwMinAcceleration ); + BOOL GetMinAccelerationY( DWORD &dwMinAcceleration ); + + // + // OPERATIONS + // + + public: + + virtual BOOL + Initialize( + CImmDevice* pDevice, + DWORD dwCoefficient = IMM_INERTIA_DEFAULT_COEFFICIENT, + DWORD dwSaturation = IMM_INERTIA_DEFAULT_SATURATION, + DWORD dwMinAcceleration = IMM_INERTIA_DEFAULT_MIN_ACCELERATION, + DWORD dwfAxis = IMM_EFFECT_AXIS_BOTH, + LONG lDirectionX = IMM_EFFECT_DEFAULT_DIRECTION_X, + LONG lDirectionY = IMM_EFFECT_DEFAULT_DIRECTION_Y, + DWORD dwNoDownload = 0 + ); + + virtual BOOL + InitializePolar( + CImmDevice* pDevice, + DWORD dwCoefficient, + DWORD dwSaturation, + DWORD dwMinAcceleration, + LONG lAngle, + DWORD dwNoDownload = 0 + ); + + +// +// ------ PRIVATE INTERFACE ------ +// + + // + // HELPERS + // + + protected: + + // + // INTERNAL DATA + // + + protected: + +}; + + + +// +// INLINES +// + +inline BOOL +CImmInertia::GetIsCompatibleGUID(GUID &guid) +{ + return IsEqualGUID(guid, GUID_Imm_Inertia); +} + + +#endif // !defined(AFX_IMMInertia_H__135B88C4_4175_11D1_B049_0020AF30269A__INCLUDED_) + diff --git a/code/ff/IFC/ImmMouse.h b/code/ff/IFC/ImmMouse.h new file mode 100644 index 0000000..e639718 --- /dev/null +++ b/code/ff/IFC/ImmMouse.h @@ -0,0 +1,164 @@ +/********************************************************************** + Copyright (c) 1997 - 2000 Immersion Corporation + + Permission to use, copy, modify, distribute, and sell this + software and its documentation may be granted without fee; + interested parties are encouraged to request permission from + Immersion Corporation + 801 Fox Lane + San Jose, CA 95131 + 408-467-1900 + + IMMERSION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. + IN NO EVENT SHALL IMMERSION BE LIABLE FOR ANY SPECIAL, INDIRECT OR + CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, + NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + FILE: ImmMouse.h + + PURPOSE: Abstraction of Feelit mouse device + + STARTED: 10/10/97 + + NOTES/REVISIONS: + 3/2/99 jrm (Jeff Mallett): Force-->Feel renaming + 3/15/99 jrm: __declspec(dllimport/dllexport) the whole class + +**********************************************************************/ + +#ifndef ImmMouse_h +#define ImmMouse_h + +#ifndef _IFCDLL_ +#define DLLIFC __declspec(dllimport) +#else +#define DLLIFC __declspec(dllexport) +#endif + +#include "ImmDevice.h" + + +//================================================================ +// CImmMouse +//================================================================ + +// +// ------ PUBLIC INTERFACE ------ +// + +class DLLIFC CImmMouse : public CImmDevice +{ + + // + // CONSTRUCTOR/DESCTRUCTOR + // + + public: + + // Constructor + CImmMouse(); + + // Destructor + virtual + ~CImmMouse(); + + + // + // ATTRIBUTES + // + + public: + + virtual LPIIMM_API + GetAPI() + { return m_piApi; } + + virtual LPIIMM_DEVICE + GetDevice() + { return m_piDevice; } + + virtual DWORD GetProductType(); + + virtual BOOL GetDriverVersion( + DWORD &dwFFDriverVersion, + DWORD &dwFirmwareRevision, + DWORD &dwHardwareRevision); + + virtual int GetProductName(LPTSTR lpszProductName, int nMaxCount); + virtual int GetProductGUIDString(LPTSTR lpszGUID, int nMaxCount); + virtual GUID GetProductGUID(); + + BOOL + HaveImmMouse() + { return m_piDevice != NULL; } + + + // + // OPERATIONS + // + + public: + + BOOL + Initialize( + HANDLE hinstApp, + HANDLE hwndApp, + DWORD dwCooperativeFlag = IMM_COOPLEVEL_FOREGROUND, + BOOL bEnumerate = TRUE + ); + + virtual BOOL + ChangeScreenResolution( + BOOL bAutoSet, + DWORD dwXScreenSize = 0, + DWORD dwYScreenSize = 0 + ); + + // Another syntax for SwitchToAbsoluteMode. + // The default is Absolute mode. Call only to switch to Relative mode or + // to switch back to Absolute mode. + virtual BOOL + SwitchToAbsoluteMode( + BOOL bAbsMode + ); + + virtual BOOL + GetCurrentPosition( long &lXPos, long &lYPos ); + +// +// ------ PRIVATE INTERFACE ------ +// + + // + // HELPERS + // + + protected: + + virtual void + reset(); + + virtual BOOL + prepare_device(); + + friend class CImmDevices; + static BOOL CALLBACK + devices_enum_proc( + LPIMM_DEVICEINSTANCE pImmDevInst, + LPVOID pv + ); + + // + // INTERNAL DATA + // + + protected: + + LPIIMM_API m_piApi; + LPIIMM_DEVICE m_piDevice; +}; + +#endif // ImmMouse_h \ No newline at end of file diff --git a/code/ff/IFC/ImmPeriodic.h b/code/ff/IFC/ImmPeriodic.h new file mode 100644 index 0000000..096ed01 --- /dev/null +++ b/code/ff/IFC/ImmPeriodic.h @@ -0,0 +1,259 @@ +/********************************************************************** + Copyright (c) 1997 - 2000 Immersion Corporation + + Permission to use, copy, modify, distribute, and sell this + software and its documentation may be granted without fee; + interested parties are encouraged to request permission from + Immersion Corporation + 801 Fox Lane + San Jose, CA 95131 + 408-467-1900 + + IMMERSION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. + IN NO EVENT SHALL IMMERSION BE LIABLE FOR ANY SPECIAL, INDIRECT OR + CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, + NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + FILE: ImmPeriodic.h + + PURPOSE: Base Periodic Class for Immersion Foundation Classes + + STARTED: 11/03/97 + + NOTES/REVISIONS: + 3/2/99 jrm (Jeff Mallett): Force-->Feel renaming + 3/2/99 jrm: Added GetIsCompatibleGUID + 3/15/99 jrm: __declspec(dllimport/dllexport) the whole class + 11/15/99 sdr (Steve Rank): Converted to IFC + +**********************************************************************/ + + +#if !defined(AFX_IMMPERIODIC_H__135B88C4_4175_11D1_B049_0020AF30269A__INCLUDED_) +#define AFX_IMMPERIODIC_H__135B88C4_4175_11D1_B049_0020AF30269A__INCLUDED_ + +#if _MSC_VER >= 1000 +#pragma once +#endif // _MSC_VER >= 1000 + +#ifndef _IFCDLL_ +#define DLLIFC __declspec(dllimport) +#else +#define DLLIFC __declspec(dllexport) +#endif + +#include "ImmBaseTypes.h" +#include "ImmEffect.h" + + + +//================================================================ +// Constants +//================================================================ + +#define IMM_PERIODIC_DEFAULT_DURATION 1000 // Milliseconds +#define IMM_PERIODIC_DEFAULT_MAGNITUDE 5000 +#define IMM_PERIODIC_DEFAULT_PERIOD 100 // Milliseconds +#define IMM_PERIODIC_DEFAULT_OFFSET 0 +#define IMM_PERIODIC_DEFAULT_PHASE 0 // Degrees +#define IMM_PERIODIC_DEFAULT_DIRECTION_X 1 // Pixels +#define IMM_PERIODIC_DEFAULT_DIRECTION_Y 0 // Pixels +#define IMM_PERIODIC_DEFAULT_ANGLE 9000 // 100ths of degrees + + + + +//================================================================ +// CImmPeriodic +//================================================================ + +// +// ------ PUBLIC INTERFACE ------ +// + +class DLLIFC CImmPeriodic : public CImmEffect +{ + // + // CONSTRUCTOR/DESTRUCTOR + // + + public: + + // Constructors + + // You may use this form if you will immediately initialize it + // from an IFR file... + CImmPeriodic(); + + // Otherwise use this form... + CImmPeriodic( + const GUID& rguidEffect + ); + + // Destructor + virtual + ~CImmPeriodic(); + + + // + // ATTRIBUTES + // + + public: + + virtual BOOL + GetIsCompatibleGUID( + GUID &guid + ); + + virtual DWORD GetEffectType() + { return IMM_EFFECTTYPE_PERIODIC; } + + BOOL + ChangeParameters( + DWORD dwMagnitude, + DWORD dwPeriod = IMM_EFFECT_DONT_CHANGE, + DWORD dwDuration = IMM_EFFECT_DONT_CHANGE, + LONG lDirectionX = IMM_EFFECT_DONT_CHANGE, + LONG lDirectionY = IMM_EFFECT_DONT_CHANGE, + LONG lOffset = IMM_EFFECT_DONT_CHANGE, + DWORD dwPhase = IMM_EFFECT_DONT_CHANGE, + LPIMM_ENVELOPE pEnvelope = (LPIMM_ENVELOPE) IMM_EFFECT_DONT_CHANGE_PTR + ); + + BOOL + ChangeParametersPolar( + DWORD dwMagnitude, + DWORD dwPeriod = IMM_EFFECT_DONT_CHANGE, + DWORD dwDuration = IMM_EFFECT_DONT_CHANGE, + LONG lAngle = IMM_EFFECT_DONT_CHANGE, + LONG lOffset = IMM_EFFECT_DONT_CHANGE, + DWORD dwPhase = IMM_EFFECT_DONT_CHANGE, + LPIMM_ENVELOPE pEnvelope = (LPIMM_ENVELOPE) IMM_EFFECT_DONT_CHANGE_PTR + ); + + BOOL ChangeMagnitude( DWORD dwMagnitude ); + BOOL ChangePeriod( DWORD dwPeriod ); + BOOL ChangeOffset( LONG lOffset ); + BOOL ChangePhase( DWORD dwPhase ); + + BOOL GetMagnitude( DWORD &dwMagnitude ); + BOOL GetPeriod( DWORD &dwPeriod ); + BOOL GetOffset( LONG &lOffset ); + BOOL GetPhase( DWORD &dwPhase ); + + // + // OPERATIONS + // + + public: + + virtual BOOL + Initialize( + CImmDevice* pDevice, + const IMM_EFFECT &effect, + DWORD dwNoDownload = 0 + ); + + virtual BOOL + Initialize( + CImmDevice* pDevice, + DWORD dwMagnitude = IMM_PERIODIC_DEFAULT_MAGNITUDE, + DWORD dwPeriod = IMM_PERIODIC_DEFAULT_PERIOD, + DWORD dwDuration = IMM_PERIODIC_DEFAULT_DURATION, + LONG lDirectionX = IMM_PERIODIC_DEFAULT_DIRECTION_X, + LONG lDirectionY = IMM_PERIODIC_DEFAULT_DIRECTION_Y, + LONG lOffset = IMM_PERIODIC_DEFAULT_OFFSET, + DWORD dwPhase = IMM_PERIODIC_DEFAULT_PHASE, + LPIMM_ENVELOPE pEnvelope = NULL, + DWORD dwNoDownload = 0 + ); + + virtual BOOL + InitializePolar( + CImmDevice* pDevice, + DWORD dwMagnitude = IMM_PERIODIC_DEFAULT_MAGNITUDE, + DWORD dwPeriod = IMM_PERIODIC_DEFAULT_PERIOD, + DWORD dwDuration = IMM_PERIODIC_DEFAULT_DURATION, + LONG lAngle = IMM_PERIODIC_DEFAULT_ANGLE, + LONG lOffset = IMM_PERIODIC_DEFAULT_OFFSET, + DWORD dwPhase = IMM_PERIODIC_DEFAULT_PHASE, + LPIMM_ENVELOPE pEnvelope = NULL, + DWORD dwNoDownload = 0 + ); + + +// +// ------ PRIVATE INTERFACE ------ +// + + // + // HELPERS + // + + protected: + + BOOL + set_parameters( + DWORD dwfCoordinates, + LONG lDirection0, + LONG lDirection1, + DWORD dwDuration, + DWORD dwMagnitude, + DWORD dwPeriod, + LONG lOffset, + DWORD dwPhase, + LPIMM_ENVELOPE pEnvelope + ); + + DWORD + change_parameters( + LONG lDirection0, + LONG lDirection1, + DWORD dwDuration, + DWORD dwMagnitude, + DWORD dwPeriod, + LONG lOffset, + DWORD dwPhase, + LPIMM_ENVELOPE pEnvelope + ); + + int + buffer_ifr_data( + TCHAR* pData + ); + + BOOL + get_ffe_data( + LPDIEFFECT pdiEffect + ); + + // + // INTERNAL DATA + // + + protected: + + IMM_PERIODIC m_Periodic; + +}; + + +// +// INLINES +// + +inline BOOL +CImmPeriodic::GetIsCompatibleGUID(GUID &guid) +{ + return IsEqualGUID(guid, GUID_Imm_Sine) || + IsEqualGUID(guid, GUID_Imm_Square) || + IsEqualGUID(guid, GUID_Imm_Triangle) || + IsEqualGUID(guid, GUID_Imm_SawtoothUp) || + IsEqualGUID(guid, GUID_Imm_SawtoothDown); +} + +#endif // !defined(AFX_IMMPERIODIC_H__135B88C4_4175_11D1_B049_0020AF30269A__INCLUDED_) diff --git a/code/ff/IFC/ImmProjects.h b/code/ff/IFC/ImmProjects.h new file mode 100644 index 0000000..e121023 --- /dev/null +++ b/code/ff/IFC/ImmProjects.h @@ -0,0 +1,392 @@ +/********************************************************************** + Copyright (c) 1999 - 2000 Immersion Corporation + + Permission to use, copy, modify, distribute, and sell this + software and its documentation may be granted without fee; + interested parties are encouraged to request permission from + Immersion Corporation + 801 Fox Lane + San Jose, CA 95131 + 408-467-1900 + + IMMERSION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. + IN NO EVENT SHALL IMMERSION BE LIABLE FOR ANY SPECIAL, INDIRECT OR + CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, + NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + FILE: ImmProjects.h + + PURPOSE: CImmProject + Manages a set of forces in a project. + There will be a project for each opened IFR file. + CImmProjects + Manages a set of projects + + STARTED: 2/22/99 by Jeff Mallett + + + NOTES/REVISIONS: + 3/2/99 jrm (Jeff Mallett): Force-->Feel renaming + 3/15/99 jrm: __declspec(dllimport/dllexport) the whole class + +**********************************************************************/ + +#ifndef __IMM_PROJECTS_H +#define __IMM_PROJECTS_H + +#if _MSC_VER >= 1000 +#pragma once +#endif // _MSC_VER >= 1000 + +#ifndef _IFCDLL_ +#define DLLIFC __declspec(dllimport) +#else +#define DLLIFC __declspec(dllexport) +#endif + + +#include "IFCErrors.h" +#include "ImmBaseTypes.h" +#include "ImmDevice.h" +#include "ImmCompoundEffect.h" + +class CImmProjects; + + +//================================================================ +// CImmProject +//================================================================ + +// +// ------ PUBLIC INTERFACE ------ +// + +class DLLIFC CImmProject +{ + // + // CONSTRUCTOR/DESTRUCTOR + // + + public: + + CImmProject(); + + ~CImmProject(); + + void + Close(); + + + // + // ATTRIBUTES + // + + public: + + CImmDevice* + GetDevice() const + { return m_pDevice; } + + BOOL + GetIsOpen() const + { return m_hProj != NULL; } + + CImmCompoundEffect * + GetCreatedEffect( + LPCSTR lpszEffectName + ); + + CImmCompoundEffect * + GetCreatedEffect( + int nIndex + ); + + int + GetNumEffectsFromIFR(); + + LPCSTR + GetEffectNameFromIFRbyIndex( + int nEffectIndex + ); + + LPCSTR + GetEffectSoundPathFromIFR( + LPCSTR lpszEffectName + ); + + DWORD + GetEffectType( + LPCSTR lpszEffectName + ); + + DWORD + GetEffectTypeFromIFR( + LPCSTR lpszEffectName + ); + + DWORD + GetEffectTypeFromIFR( + int nEffectIndex + ); + + int + GetNumCreatedEffects() + { return m_nCreatedEffects;} + + // + // OPERATIONS + // + + public: + + BOOL + Start( + LPCSTR lpszEffectName = NULL, + DWORD dwIterations = IMM_EFFECT_DONT_CHANGE, + DWORD dwFlags = 0, + CImmDevice* pDevice = NULL + ); + + BOOL + Stop( + LPCSTR lpszEffectName = NULL + ); + + BOOL + OpenFile( + LPCSTR lpszFilePath, + CImmDevice *pDevice + ); + + BOOL + LoadProjectFromResource( + HMODULE hRsrcModule, + LPCSTR pRsrcName, + CImmDevice *pDevice + ); + + BOOL + LoadProjectFromMemory( + LPVOID pProjectDef, + CImmDevice *pDevice + ); + + BOOL + LoadProjectObjectPointer( + BYTE *pMem, + CImmDevice *pDevice + ); + + BOOL + WriteToFile( + LPCSTR lpszFilename + ); + + CImmCompoundEffect * + CreateEffect( + LPCSTR lpszEffectName, + CImmDevice* pDevice = NULL, + DWORD dwNoDownload = 0 + ); + + CImmCompoundEffect * + CreateEffectByIndex( + int nEffectIndex, + CImmDevice* pDevice = NULL, + DWORD dwNoDownload = 0 + ); + + CImmCompoundEffect * + AddEffect( + LPCSTR lpszEffectName, + GENERIC_EFFECT_PTR pObject + ); + +#if (IFC_VERSION >= 0x0101) + void + DestroyEffect( + CImmCompoundEffect *pCompoundEffect + ); +#endif + +// +// ------ PRIVATE INTERFACE ------ +// + + // + // HELPERS + // + + protected: + + void + set_next( + CImmProject *pNext + ) + { m_pNext = pNext; } + + CImmProject * + get_next() const + { return m_pNext; } + + void + append_effect_to_list( + CImmCompoundEffect* pEffect + ); +#if (IFC_VERSION >= 0x0101) + BOOL + remove_effect_from_list( + CImmCompoundEffect* pEffect + ); +#endif + + IFREffect ** + create_effect_structs( + LPCSTR lpszEffectName, + int &nEff + ); + + IFREffect ** + create_effect_structs_by_index( + int nEffectIndex, + int &nEff + ); + + BOOL + release_effect_structs( + IFREffect **hEffects + ); + + // + // FRIENDS + // + + public: + + friend BOOL + CImmEffect::InitializeFromProject( + CImmProject &project, + LPCSTR lpszEffectName, + CImmDevice* pDevice, /* = NULL */ + DWORD dwNoDownload // = 0 + ); + +#ifdef PROTECT_AGAINST_DELETION + friend CImmCompoundEffect::~CImmCompoundEffect(); +#endif + + friend class CImmProjects; + + // + // INTERNAL DATA + // + + protected: + + HIFRPROJECT m_hProj; + DWORD m_dwProjectFileType; + CImmCompoundEffect* m_pCreatedEffects; + CImmDevice* m_pDevice; + LPDIRECTINPUT m_piDI7; + LPDIRECTINPUTDEVICE2 m_piDIDevice7; + TCHAR m_szProjectFileName[MAX_PATH]; + + int m_nCreatedEffects; + + private: + + CImmProject* m_pNext; +}; + + + +//================================================================ +// CImmProjects +//================================================================ + +// +// ------ PUBLIC INTERFACE ------ +// + +class DLLIFC CImmProjects +{ + // + // CONSTRUCTOR/DESTRUCTOR + // + + public: + + CImmProjects() : m_pProjects(NULL) { } + + ~CImmProjects(); + + void + Close(); + + + // + // ATTRIBUTES + // + + public: + + CImmProject * + GetProject( + int index = 0 + ); + + + // + // OPERATIONS + // + + public: + + BOOL + Stop(); + + long + OpenFile( + LPCSTR lpszFilePath, + CImmDevice *pDevice + ); + + long + LoadProjectFromResource( + HMODULE hRsrcModule, + LPCSTR pRsrcName, + CImmDevice *pDevice + ); + + long + LoadProjectFromMemory( + LPVOID pProjectDef, + CImmDevice *pDevice + ); + + +// +// ------ PRIVATE INTERFACE ------ +// + + // + // HELPERS + // + + protected: + + + // + // INTERNAL DATA + // + protected: + + CImmProject *m_pProjects; +}; + + + +#endif // __IMM_PROJECTS_H diff --git a/code/ff/IFC/ImmRamp.h b/code/ff/IFC/ImmRamp.h new file mode 100644 index 0000000..3d854bf --- /dev/null +++ b/code/ff/IFC/ImmRamp.h @@ -0,0 +1,225 @@ +/********************************************************************** + Copyright (c) 1997 - 2000 Immersion Corporation + + Permission to use, copy, modify, distribute, and sell this + software and its documentation may be granted without fee; + interested parties are encouraged to request permission from + Immersion Corporation + 801 Fox Lane + San Jose, CA 95131 + 408-467-1900 + + IMMERSION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. + IN NO EVENT SHALL IMMERSION BE LIABLE FOR ANY SPECIAL, INDIRECT OR + CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, + NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + FILE: ImmRamp.h + + PURPOSE: Base Ramp Force Class for Immersion Foundation Classes + + STARTED: 12/11/97 + + NOTES/REVISIONS: + 3/2/99 jrm (Jeff Mallett): Force-->Feel renaming + 3/2/99 jrm: Added GetIsCompatibleGUID + 3/15/99 jrm: __declspec(dllimport/dllexport) the whole class + 11/15/99 sdr (Steve Rank): Converted to IFC + +**********************************************************************/ + + +#if !defined(AFX_IMMRAMP_H__135B88C4_4175_11D1_B049_0020AF30269A__INCLUDED_) +#define AFX_IMMRAMP_H__135B88C4_4175_11D1_B049_0020AF30269A__INCLUDED_ + +#if _MSC_VER >= 1000 +#pragma once +#endif // _MSC_VER >= 1000 + +#ifndef _IFCDLL_ +#define DLLIFC __declspec(dllimport) +#else +#define DLLIFC __declspec(dllexport) +#endif + +#include "ImmBaseTypes.h" +#include "ImmEffect.h" + + + +//================================================================ +// Constants +//================================================================ + +#define IMM_RAMP_DEFAULT_DURATION 1000 // Milliseconds +#define IMM_RAMP_DEFAULT_MAGNITUDE_START 0 +#define IMM_RAMP_DEFAULT_MAGNITUDE_END 10000 + + + +//================================================================ +// CImmRamp +//================================================================ + +// +// ------ PUBLIC INTERFACE ------ +// + +class DLLIFC CImmRamp : public CImmEffect +{ + // + // CONSTRUCTOR/DESTRUCTOR + // + + public: + + // Constructor + CImmRamp(); + + // Destructor + virtual + ~CImmRamp(); + + + // + // ATTRIBUTES + // + + public: + + virtual BOOL + GetIsCompatibleGUID( + GUID &guid + ); + + virtual DWORD GetEffectType() + { return IMM_EFFECTTYPE_RAMPFORCE; } + + BOOL + ChangeParameters( + LONG lDirectionX, + LONG lDirectionY, + DWORD dwDuration = IMM_EFFECT_DONT_CHANGE, + LONG lMagStart = IMM_EFFECT_DONT_CHANGE, + LONG lMagEnd = IMM_EFFECT_DONT_CHANGE, + LPIMM_ENVELOPE pEnvelope = (LPIMM_ENVELOPE) IMM_EFFECT_DONT_CHANGE_PTR + ); + + BOOL + ChangeParametersPolar( + LONG lAngle, + DWORD dwDuration = IMM_EFFECT_DONT_CHANGE, + LONG lMagStart = IMM_EFFECT_DONT_CHANGE, + LONG lMagEnd = IMM_EFFECT_DONT_CHANGE, + LPIMM_ENVELOPE pEnvelope = (LPIMM_ENVELOPE) IMM_EFFECT_DONT_CHANGE_PTR + ); + + BOOL ChangeStartMagnitude( LONG lMagStart ); + BOOL ChangeEndMagnitude( LONG lMagEnd ); + + BOOL GetStartMagnitude( LONG &lMagStart ); + BOOL GetEndMagnitude( LONG &lMagEnd ); + + // + // OPERATIONS + // + + public: + + virtual BOOL + Initialize( + CImmDevice* pDevice, + const IMM_EFFECT &effect, + DWORD dwFlags = 0 + ); + + virtual BOOL + Initialize( + CImmDevice* pDevice, + LONG lDirectionX = IMM_EFFECT_DEFAULT_DIRECTION_X, + LONG lDirectionY = IMM_EFFECT_DEFAULT_DIRECTION_Y, + DWORD dwDuration = IMM_RAMP_DEFAULT_DURATION, + LONG lMagStart = IMM_RAMP_DEFAULT_MAGNITUDE_START, + LONG lMagEnd = IMM_RAMP_DEFAULT_MAGNITUDE_END, + LPIMM_ENVELOPE pEnvelope = NULL, + DWORD dwFlags = 0 + ); + + virtual BOOL + InitializePolar( + CImmDevice* pDevice, + LONG lAngle = IMM_EFFECT_DEFAULT_ANGLE, + DWORD dwDuration = IMM_RAMP_DEFAULT_DURATION, + LONG lMagStart = IMM_RAMP_DEFAULT_MAGNITUDE_START, + LONG lMagEnd = IMM_RAMP_DEFAULT_MAGNITUDE_END, + LPIMM_ENVELOPE pEnvelope = NULL, + DWORD dwFlags = 0 + ); + + +// +// ------ PRIVATE INTERFACE ------ +// + + // + // HELPERS + // + + protected: + + BOOL + set_parameters( + DWORD dwfCoordinates, + LONG lDirection0, + LONG lDirection1, + DWORD dwDuration, + LONG lMagStart, + LONG lMagEnd, + LPIMM_ENVELOPE pEnvelope + ); + + DWORD + change_parameters( + LONG lDirection0, + LONG lDirection1, + DWORD dwDuration, + LONG lMagStart, + LONG lMagEnd, + LPIMM_ENVELOPE pEnvelope + ); + + int + buffer_ifr_data( + TCHAR* pData + ); + + BOOL + get_ffe_data( + LPDIEFFECT pdiEffect + ); + + // + // INTERNAL DATA + // + + protected: + + IMM_RAMPFORCE m_RampForce; + +}; + + +// +// INLINES +// + +inline BOOL +CImmRamp::GetIsCompatibleGUID(GUID &guid) +{ + return IsEqualGUID(guid, GUID_Imm_RampForce); +} + +#endif // !defined(AFX_IMMRAMP_H__135B88C4_4175_11D1_B049_0020AF30269A__INCLUDED_) diff --git a/code/ff/IFC/ImmSpring.h b/code/ff/IFC/ImmSpring.h new file mode 100644 index 0000000..1d48317 --- /dev/null +++ b/code/ff/IFC/ImmSpring.h @@ -0,0 +1,183 @@ +/********************************************************************** + Copyright (c) 1997 - 2000 Immersion Corporation + + Permission to use, copy, modify, distribute, and sell this + software and its documentation may be granted without fee; + interested parties are encouraged to request permission from + Immersion Corporation + 801 Fox Lane + San Jose, CA 95131 + 408-467-1900 + + IMMERSION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. + IN NO EVENT SHALL IMMERSION BE LIABLE FOR ANY SPECIAL, INDIRECT OR + CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, + NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + FILE: ImmSpring.h + + PURPOSE: Immersion Foundation Classes Spring Effect + + STARTED: Oct.10.97 + + NOTES/REVISIONS: + Mar.02.99 jrm (Jeff Mallett): Force-->Feel renaming + Mar.02.99 jrm: Added GetIsCompatibleGUID + Mar.15.99 jrm: __declspec(dllimport/dllexport) the whole class + Nov.15.99 efw (Evan Wies): Converted to IFC + +**********************************************************************/ + + +#if !defined(AFX_IMMSpring_H__135B88C4_4175_11D1_B049_0020AF30269A__INCLUDED_) +#define AFX_IMMSpring_H__135B88C4_4175_11D1_B049_0020AF30269A__INCLUDED_ + +#if _MSC_VER >= 1000 +#pragma once +#endif // _MSC_VER >= 1000 + +#ifndef _IFCDLL_ +#define DLLIFC __declspec(dllimport) +#else +#define DLLIFC __declspec(dllexport) +#endif + +#include +#include "ImmCondition.h" + + +//================================================================ +// Constants +//================================================================ + +#define IMM_SPRING_DEFAULT_STIFFNESS 2500 +#define IMM_SPRING_DEFAULT_SATURATION 10000 +#define IMM_SPRING_DEFAULT_DEADBAND 100 +#define IMM_SPRING_DEFAULT_CENTER_POINT IMM_EFFECT_MOUSE_POS_AT_START +#define IMM_SPRING_DEFAULT_DIRECTION_X 1 +#define IMM_SPRING_DEFAULT_DIRECTION_Y 0 +#define IMM_SPRING_DEFAULT_ANGLE 0 + + +//================================================================ +// CImmSpring +//================================================================ + +// +// ------ PUBLIC INTERFACE ------ +// + +class DLLIFC CImmSpring : public CImmCondition +{ + // + // CONSTRUCTOR/DESTRUCTOR + // + + public: + + // Constructor + CImmSpring(); + + // Destructor + virtual + ~CImmSpring(); + + + // + // ATTRIBUTES + // + + public: + + virtual BOOL + GetIsCompatibleGUID( + GUID &guid + ); + + BOOL + ChangeParameters( + POINT pntCenter, + LONG lStiffness = IMM_EFFECT_DONT_CHANGE, + DWORD dwSaturation = IMM_EFFECT_DONT_CHANGE, + DWORD dwDeadband = IMM_EFFECT_DONT_CHANGE, + LONG lDirectionX = IMM_EFFECT_DONT_CHANGE, + LONG lDirectionY = IMM_EFFECT_DONT_CHANGE + ); + + BOOL + ChangeParametersPolar( + POINT pntCenter, + LONG lStiffness, + DWORD dwSaturation, + DWORD dwDeadband, + LONG lAngle + ); + + // + // OPERATIONS + // + + public: + + virtual BOOL + Initialize( + CImmDevice* pDevice, + LONG lStiffness = IMM_SPRING_DEFAULT_STIFFNESS, + DWORD dwSaturation = IMM_SPRING_DEFAULT_SATURATION, + DWORD dwDeadband = IMM_SPRING_DEFAULT_DEADBAND, + DWORD dwfAxis = IMM_EFFECT_AXIS_BOTH, + POINT pntCenter = IMM_SPRING_DEFAULT_CENTER_POINT, + LONG lDirectionX = IMM_SPRING_DEFAULT_DIRECTION_X, + LONG lDirectionY = IMM_SPRING_DEFAULT_DIRECTION_Y, + BOOL bUseDeviceCoordinates = FALSE, + DWORD dwNoDownload = 0 + ); + + virtual BOOL + InitializePolar( + CImmDevice* pDevice, + LONG lStiffness, + DWORD dwSaturation, + DWORD dwDeadband, + POINT pntCenter, + LONG lAngle, + BOOL bUseDeviceCoordinates = FALSE, + DWORD dwNoDownload = 0 + ); + + +// +// ------ PRIVATE INTERFACE ------ +// + + // + // HELPERS + // + + protected: + + // + // INTERNAL DATA + // + + protected: + +}; + + + +// +// INLINES +// + +inline BOOL +CImmSpring::GetIsCompatibleGUID(GUID &guid) +{ + return IsEqualGUID(guid, GUID_Imm_Spring); +} + +#endif // !defined(AFX_IMMSpring_H__135B88C4_4175_11D1_B049_0020AF30269A__INCLUDED_) + diff --git a/code/ff/IFC/ImmTexture.h b/code/ff/IFC/ImmTexture.h new file mode 100644 index 0000000..df8bc38 --- /dev/null +++ b/code/ff/IFC/ImmTexture.h @@ -0,0 +1,407 @@ +/********************************************************************** + Copyright (c) 1997 - 2000 Immersion Corporation + + Permission to use, copy, modify, distribute, and sell this + software and its documentation may be granted without fee; + interested parties are encouraged to request permission from + Immersion Corporation + 801 Fox Lane + San Jose, CA 95131 + 408-467-1900 + + IMMERSION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. + IN NO EVENT SHALL IMMERSION BE LIABLE FOR ANY SPECIAL, INDIRECT OR + CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, + NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + FILE: ImmTexture.h + + PURPOSE: Texture Class for Feelit API Foundation Classes + + STARTED: 2/27/98 + + NOTES/REVISIONS: + 3/2/99 jrm (Jeff Mallett): Force-->Feel renaming + 3/2/99 jrm: Added GetIsCompatibleGUID + 3/15/99 jrm: __declspec(dllimport/dllexport) the whole class + +**********************************************************************/ + + +#if !defined(AFX_ImmTexture_H__135B88C4_4175_11D1_B049_0020AF30269A__INCLUDED_) +#define AFX_ImmTexture_H__135B88C4_4175_11D1_B049_0020AF30269A__INCLUDED_ + +#if _MSC_VER >= 1000 +#pragma once +#endif // _MSC_VER >= 1000 + +#ifndef _IFCDLL_ +#define DLLIFC __declspec(dllimport) +#else +#define DLLIFC __declspec(dllexport) +#endif + +#include +#include "ImmBaseTypes.h" +#include "ImmEffect.h" + + + +//================================================================ +// Constants +//================================================================ + +const POINT IMM_TEXTURE_PT_NULL = { 0, 0 }; +const POINT IMM_TEXTURE_DEFAULT_OFFSET_POINT = { 0, 0}; + +#define IMM_TEXTURE_DEFAULT_MAGNITUDE 5000 +#define IMM_TEXTURE_DEFAULT_WIDTH 10 +#define IMM_TEXTURE_DEFAULT_SPACING 20 + + +//================================================================ +// CImmTexture +//================================================================ + +// +// ------ PUBLIC INTERFACE ------ +// + +class DLLIFC CImmTexture : public CImmEffect +{ + // + // CONSTRUCTOR/DESTRUCTOR + // + + public: + + // Constructor + CImmTexture(); + + // Destructor + virtual + ~CImmTexture(); + + + // + // ATTRIBUTES + // + + public: + + virtual BOOL + GetIsCompatibleGUID( + GUID &guid + ); + + virtual DWORD GetEffectType() + { return IMM_EFFECTTYPE_TEXTURE; } + + // Use this form for single-axis and dual-axis effects + BOOL + ChangeTextureParams( + LPCIMM_TEXTURE pTextureX, + LPCIMM_TEXTURE pTextureY + ); + + // Use this form for directional effects + BOOL + ChangeTextureParams( + LPCIMM_TEXTURE pTexture, + LONG lDirectionX, + LONG lDirectionY + ); + + // Use this form for directional effects + BOOL + ChangeTextureParamsPolar( + LPCIMM_TEXTURE pTexture, + LONG lAngle + ); + + // Use this form for single-axis, dual-axis symetrical, or directional effects + BOOL + ChangeTextureParams( + LONG lPosBumpMag = IMM_EFFECT_DONT_CHANGE, + DWORD dwPosBumpWidth = IMM_EFFECT_DONT_CHANGE, + DWORD dwPosBumpSpacing = IMM_EFFECT_DONT_CHANGE, + LONG lNegBumpMag = IMM_EFFECT_DONT_CHANGE, + DWORD dwNegBumpWidth = IMM_EFFECT_DONT_CHANGE, + DWORD dwNegBumpSpacing = IMM_EFFECT_DONT_CHANGE, + POINT pntOffset = IMM_EFFECT_DONT_CHANGE_POINT, + LONG lDirectionX = IMM_EFFECT_DONT_CHANGE, + LONG lDirectionY = IMM_EFFECT_DONT_CHANGE + ); + + // Use this form for single-axis, dual-axis, or directional effects + BOOL + ChangeTextureParamsX( + LONG lPosBumpMag = IMM_EFFECT_DONT_CHANGE, + DWORD dwPosBumpWidth = IMM_EFFECT_DONT_CHANGE, + DWORD dwPosBumpSpacing = IMM_EFFECT_DONT_CHANGE, + LONG lNegBumpMag = IMM_EFFECT_DONT_CHANGE, + DWORD dwNegBumpWidth = IMM_EFFECT_DONT_CHANGE, + DWORD dwNegBumpSpacing = IMM_EFFECT_DONT_CHANGE, + POINT pntOffset = IMM_EFFECT_DONT_CHANGE_POINT, + LONG lDirectionX = IMM_EFFECT_DONT_CHANGE, + LONG lDirectionY = IMM_EFFECT_DONT_CHANGE + ); + + BOOL + ChangeTextureParamsY( + LONG lPosBumpMag = IMM_EFFECT_DONT_CHANGE, + DWORD dwPosBumpWidth = IMM_EFFECT_DONT_CHANGE, + DWORD dwPosBumpSpacing = IMM_EFFECT_DONT_CHANGE, + LONG lNegBumpMag = IMM_EFFECT_DONT_CHANGE, + DWORD dwNegBumpWidth = IMM_EFFECT_DONT_CHANGE, + DWORD dwNegBumpSpacing = IMM_EFFECT_DONT_CHANGE, + POINT pntOffset = IMM_EFFECT_DONT_CHANGE_POINT, + LONG lDirectionX = IMM_EFFECT_DONT_CHANGE, + LONG lDirectionY = IMM_EFFECT_DONT_CHANGE + ); + + // Use this form for single-axis, dual-axis symetrical, or directional effects + BOOL + ChangeTextureParamsPolar( + LONG lPosBumpMag = IMM_EFFECT_DONT_CHANGE, + DWORD dwPosBumpWidth = IMM_EFFECT_DONT_CHANGE, + DWORD dwPosBumpSpacing = IMM_EFFECT_DONT_CHANGE, + LONG lNegBumpMag = IMM_EFFECT_DONT_CHANGE, + DWORD dwNegBumpWidth = IMM_EFFECT_DONT_CHANGE, + DWORD dwNegBumpSpacing = IMM_EFFECT_DONT_CHANGE, + POINT pntOffset = IMM_EFFECT_DONT_CHANGE_POINT, + LONG lAngle = IMM_EFFECT_DONT_CHANGE + ); + + // Use this form for single-axis, dual-axis, or directional effects + BOOL + ChangeTextureParamsPolarX( + LONG lPosBumpMag = IMM_EFFECT_DONT_CHANGE, + DWORD dwPosBumpWidth = IMM_EFFECT_DONT_CHANGE, + DWORD dwPosBumpSpacing = IMM_EFFECT_DONT_CHANGE, + LONG lNegBumpMag = IMM_EFFECT_DONT_CHANGE, + DWORD dwNegBumpWidth = IMM_EFFECT_DONT_CHANGE, + DWORD dwNegBumpSpacing = IMM_EFFECT_DONT_CHANGE, + POINT pntOffset = IMM_EFFECT_DONT_CHANGE_POINT, + LONG lAngle = IMM_EFFECT_DONT_CHANGE + ); + + BOOL + ChangeTextureParamsPolarY( + LONG lPosBumpMag = IMM_EFFECT_DONT_CHANGE, + DWORD dwPosBumpWidth = IMM_EFFECT_DONT_CHANGE, + DWORD dwPosBumpSpacing = IMM_EFFECT_DONT_CHANGE, + LONG lNegBumpMag = IMM_EFFECT_DONT_CHANGE, + DWORD dwNegBumpWidth = IMM_EFFECT_DONT_CHANGE, + DWORD dwNegBumpSpacing = IMM_EFFECT_DONT_CHANGE, + POINT pntOffset = IMM_EFFECT_DONT_CHANGE_POINT, + LONG lAngle = IMM_EFFECT_DONT_CHANGE + ); + + // Use these to change the the X Axis parameters for a dual-axis effect + BOOL ChangePositiveBumpMagX( LONG lPosBumpMag ); + BOOL ChangeNegativeBumpMagX( LONG lNegBumpMag ); + BOOL ChangePositiveBumpSpacingX( DWORD dwPosBumpSpacing ); + BOOL ChangeNegativeBumpSpacingX( DWORD dwNegBumpSpacing ); + BOOL ChangePositiveBumpWidthX( DWORD dwPosBumpWidth ); + BOOL ChangeNegativeBumpWidthX( DWORD dwNegBumpWidth ); + + // Use these to change the the Y Axis parameters for a dual-axis effect + BOOL ChangePositiveBumpMagY( LONG lPosBumpMag ); + BOOL ChangeNegativeBumpMagY( LONG lNegBumpMag ); + BOOL ChangePositiveBumpSpacingY( DWORD dwPosBumpSpacing ); + BOOL ChangeNegativeBumpSpacingY( DWORD dwNegBumpSpacing ); + BOOL ChangePositiveBumpWidthY( DWORD dwPosBumpWidth ); + BOOL ChangeNegativeBumpWidthY( DWORD dwNegBumpWidth ); + + // Use these to change the the parameters for a single-axis or + // dual-axis symetrical effect + BOOL ChangePositiveBumpMag( LONG lPosBumpMag ); + BOOL ChangeNegativeBumpMag( LONG lNegBumpMag ); + BOOL ChangePositiveBumpSpacing( DWORD dwPosBumpSpacing ); + BOOL ChangeNegativeBumpSpacing( DWORD dwNegBumpSpacing ); + BOOL ChangePositiveBumpWidth( DWORD dwPosBumpWidth ); + BOOL ChangeNegativeBumpWidth( DWORD dwNegBumpWidth ); + + BOOL ChangeOffset( POINT pntOffset ); + + BOOL GetPositiveBumpMagX( LONG &lPosBumpMag ); + BOOL GetNegativeBumpMagX( LONG &lNegBumpMag ); + BOOL GetPositiveBumpSpacingX( DWORD &dwPosBumpSpacing ); + BOOL GetNegativeBumpSpacingX( DWORD &dwNegBumpSpacing ); + BOOL GetPositiveBumpWidthX( DWORD &dwPosBumpWidth ); + BOOL GetNegativeBumpWidthX( DWORD &dwNegBumpWidth ); + BOOL GetPositiveBumpMagY( LONG &lPosBumpMag ); + BOOL GetNegativeBumpMagY( LONG &lNegBumpMag ); + BOOL GetPositiveBumpSpacingY( DWORD &dwPosBumpSpacing ); + BOOL GetNegativeBumpSpacingY( DWORD &dwNegBumpSpacing ); + BOOL GetPositiveBumpWidthY( DWORD &dwPosBumpWidth ); + BOOL GetNegativeBumpWidthY( DWORD &dwNegBumpWidth ); + BOOL GetOffset( POINT &pntOffset ); + + // + // OPERATIONS + // + + public: + + virtual BOOL + Initialize( + CImmDevice* pDevice, + const IMM_EFFECT &effect, + DWORD dwNoDownload = 0 + ); + + // Use this form for single-axis and dual-axis effects + BOOL + InitTexture( + CImmDevice* pDevice, + LPCIMM_TEXTURE pTextureX, + LPCIMM_TEXTURE pTextureY, + DWORD dwNoDownload = 0 + ); + + + // Use this form for directional effects + BOOL + InitTexture( + CImmDevice* pDevice, + LPCIMM_TEXTURE pTexture, + LONG lDirectionX, + LONG lDirectionY, + DWORD dwNoDownload = 0 + ); + + + // Use this form for directional effects + BOOL + InitTexturePolar( + CImmDevice* pDevice, + LPCIMM_TEXTURE pTexture, + LONG lAngle, + DWORD dwNoDownload = 0 + ); + + + // Use this form for single-axis, dual-axis symetrical, or directional effects + BOOL + InitTexture( + CImmDevice* pDevice, + LONG lPosBumpMag = IMM_TEXTURE_DEFAULT_MAGNITUDE, + DWORD dwPosBumpWidth = IMM_TEXTURE_DEFAULT_WIDTH, + DWORD dwPosBumpSpacing = IMM_TEXTURE_DEFAULT_SPACING, + LONG lNegBumpMag = IMM_TEXTURE_DEFAULT_MAGNITUDE, + DWORD dwNegBumpWidth = IMM_TEXTURE_DEFAULT_WIDTH, + DWORD dwNegBumpSpacing = IMM_TEXTURE_DEFAULT_SPACING, + DWORD dwfAxis = IMM_EFFECT_AXIS_BOTH, + POINT pntOffset = IMM_TEXTURE_DEFAULT_OFFSET_POINT, + LONG lDirectionX = IMM_EFFECT_DEFAULT_DIRECTION_X, + LONG lDirectionY = IMM_EFFECT_DEFAULT_DIRECTION_Y, + DWORD dwNoDownload = 0 + ); + + // Use this form for directional effects + BOOL + InitTexturePolar( + CImmDevice* pDevice, + LONG lPosBumpMag = IMM_TEXTURE_DEFAULT_MAGNITUDE, + DWORD dwPosBumpWidth = IMM_TEXTURE_DEFAULT_WIDTH, + DWORD dwPosBumpSpacing = IMM_TEXTURE_DEFAULT_SPACING, + LONG lNegBumpMag = IMM_TEXTURE_DEFAULT_MAGNITUDE, + DWORD dwNegBumpWidth = IMM_TEXTURE_DEFAULT_WIDTH, + DWORD dwNegBumpSpacing = IMM_TEXTURE_DEFAULT_SPACING, + POINT pntOffset = IMM_TEXTURE_DEFAULT_OFFSET_POINT, + LONG lAngle = IMM_EFFECT_DEFAULT_ANGLE, + DWORD dwNoDownload = 0 + ); + + +// +// ------ PRIVATE INTERFACE ------ +// + + // + // HELPERS + // + + protected: + + BOOL + set_parameters( + DWORD dwfAxis, + DWORD dwfCoordinates, + LONG lDirection0, + LONG lDirection1, + LPCIMM_TEXTURE pTextureX, + LPCIMM_TEXTURE pTextureY + ); + + BOOL + set_parameters( + DWORD dwfAxis, + DWORD dwfCoordinates, + LONG lDirection0, + LONG lDirection1, + LONG lPosBumpMag, + DWORD dwPosBumpWidth, + DWORD dwPosBumpSpacing, + LONG lNegBumpMag, + DWORD dwNegBumpWidth, + DWORD dwNegBumpSpacing, + POINT pntOffset + ); + + DWORD + change_parameters( + LONG lDirection0, + LONG lDirection1, + LPCIMM_TEXTURE pTextureX, + LPCIMM_TEXTURE pTextureY + ); + + DWORD + change_parameters( + LONG lDirection0, + LONG lDirection1, + LONG lPosBumpMag, + DWORD dwPosBumpWidth, + DWORD dwPosBumpSpacing, + LONG lNegBumpMag, + DWORD dwNegBumpWidth, + DWORD dwNegBumpSpacing, + POINT pntOffset, + int fAxis + ); + + int + buffer_ifr_data( + TCHAR* pData + ); + + // + // INTERNAL DATA + // + + IMM_TEXTURE m_aTexture[2]; + DWORD m_dwfAxis; + + protected: + +}; + + + +// +// INLINES +// + +inline BOOL +CImmTexture::GetIsCompatibleGUID(GUID &guid) +{ + return IsEqualGUID(guid, GUID_Imm_Texture); +} + +#endif // !defined(AFX_ImmTexture_H__135B88C4_4175_11D1_B049_0020AF30269A__INCLUDED_) diff --git a/code/ff/IFC/vssver.scc b/code/ff/IFC/vssver.scc new file mode 100644 index 0000000..611a709 Binary files /dev/null and b/code/ff/IFC/vssver.scc differ diff --git a/code/ff/cl_ff.cpp b/code/ff/cl_ff.cpp new file mode 100644 index 0000000..6becc34 --- /dev/null +++ b/code/ff/cl_ff.cpp @@ -0,0 +1,72 @@ +//#include "../server/exe_headers.h" +#include "../client/client.h" + +#ifdef _IMMERSION + +#include "ff_public.h" +#include "ff.h" +#include "ff_snd.h" + +extern clientActive_t cl; + +void CL_InitFF( void ) +{ + cvar_t *use_ff = Cvar_Get( "use_ff", "1", CVAR_ARCHIVE ); + + if (!use_ff + || !use_ff->integer + || !FF_Init() + ){ + FF_Shutdown(); + } +} + +void CL_ShutdownFF( void ) +{ + FF_Shutdown(); +} + +qboolean IsLocalClient( int clientNum ) +{ + return qboolean + ( clientNum == 0 //clientNum == cl.snap.ps.clientNum + || clientNum == FF_CLIENT_LOCAL // assumed local + ); +} + +void CL_FF_Start( ffHandle_t ff, int clientNum ) +{ + if ( IsLocalClient( clientNum ) ) + { + //FF_Play( ff ); // plays instantly + FF_AddForce( ff ); // plays at end of frame + } +} + +void CL_FF_Stop( ffHandle_t ff, int clientNum ) +{ + if ( IsLocalClient( clientNum ) ) + { + FF_Stop( ff ); + } +} + +/* +void CL_FF_EnsurePlaying( ffHandle_t ff, int clientNum ) +{ + if ( IsLocalClient( clientNum ) ) + { + FF_EnsurePlaying( ff ); + } +} +*/ + +void CL_FF_AddLoopingForce( ffHandle_t ff, int clientNum ) +{ + if ( IsLocalClient( clientNum ) ) + { + FF_AddLoopingForce( ff ); + } +} + +#endif // _IMMERSION \ No newline at end of file diff --git a/code/ff/cl_ff.h b/code/ff/cl_ff.h new file mode 100644 index 0000000..fed1963 --- /dev/null +++ b/code/ff/cl_ff.h @@ -0,0 +1,13 @@ +#ifndef __CL_FF_H +#define __CL_FF_H + +#include "ff_public.h" + +void CL_InitFF ( void ); +void CL_ShutdownFF ( void ); + +void CL_FF_Start ( ffHandle_t ff, int clientNum = FF_CLIENT_LOCAL ); +void CL_FF_Stop ( ffHandle_t ff, int clientNum = FF_CLIENT_LOCAL ); +void CL_FF_AddLoopingForce ( ffHandle_t ff, int clientNum = FF_CLIENT_LOCAL ); + +#endif // __CL_FF_H diff --git a/code/ff/common_headers.h b/code/ff/common_headers.h new file mode 100644 index 0000000..476b77c --- /dev/null +++ b/code/ff/common_headers.h @@ -0,0 +1,50 @@ +#ifndef FF_COMMON_HEADERS_H +#define FF_COMMON_HEADERS_H + +#ifdef _IMMERSION + +#include "ff_local.h" + +#pragma warning(disable : 4018) // signed/unsigned mismatch +#pragma warning(disable : 4032) +#pragma warning(disable : 4051) +#pragma warning(disable : 4057) // slightly different base types +#pragma warning(disable : 4100) // unreferenced formal parameter +#pragma warning(disable : 4115) +#pragma warning(disable : 4125) // decimal digit terminates octal escape sequence +#pragma warning(disable : 4127) // conditional expression is constant +#pragma warning(disable : 4136) +#pragma warning(disable : 4152) // nonstandard extension, function/data pointer conversion in expression +#pragma warning(disable : 4201) +#pragma warning(disable : 4214) // bitfields on type other than int +#pragma warning(disable : 4244) // conversion from double to float +#pragma warning(disable : 4284) // return type not UDT +#pragma warning(disable : 4305) // truncation from const double to float +#pragma warning(disable : 4310) // cast truncates constant value +#pragma warning(disable : 4503) // decorated name length truncated +#pragma warning(disable : 4505) // unreferenced local function has been removed +#pragma warning(disable : 4511) // copy ctor could not be genned +#pragma warning(disable : 4512) // assignment op could not be genned +#pragma warning(disable : 4514) // unreffed inline removed +#pragma warning(disable : 4663) // c++ lang change +#pragma warning(disable : 4710) // not inlined +#pragma warning(disable : 4711) // selected for automatic inline expansion +#pragma warning(disable : 4220) // varargs matches remaining parameters +#pragma warning(disable : 4786) // identifier was truncated +#pragma warning(disable : 4800) // forcing value to bool 'true' or 'false' (performance warning) +#pragma warning(disable : 4702) +#pragma warning( push, 3 ) +#include +#include +#include +#include +#pragma warning( pop ) +using namespace std; + +#include "ifc.h" +#include "ff_utils.h" +#include "ff_system.h" + +#endif // _IMMERSION + +#endif // FF_COMMON_HEADERS_H diff --git a/code/ff/ff.cpp b/code/ff/ff.cpp new file mode 100644 index 0000000..fefab0a --- /dev/null +++ b/code/ff/ff.cpp @@ -0,0 +1,383 @@ +#include "common_headers.h" + +#ifdef _IMMERSION + +#define INITGUID // this will need removing if already defined in someone else's module. Only one must exist in whole game + +//#include "ff.h" +//#include "ff_ffset.h" +//#include "ff_compound.h" +//#include "ff_system.h" + +FFSystem gFFSystem; + +cvar_t *use_ff; +cvar_t *ensureShake; +cvar_t *ff_developer; +#ifdef FF_DELAY +cvar_t *ff_delay; +#endif +cvar_t *ff_channels; + +static const char *_pass = "SUCCEEDED"; +static const char *_fail = "FAILED"; + +const char *gChannelName[ FF_CHANNEL_MAX ] = +{ "FF_CHANNEL_WEAPON" +, "FF_CHANNEL_MENU" +, "FF_CHANNEL_TOUCH" +, "FF_CHANNEL_DAMAGE" +, "FF_CHANNEL_BODY" +, "FF_CHANNEL_FORCE" +, "FF_CHANNEL_FOOT" +}; + +// Enable/Disable Com_Printf in FF_* functions +#if( 1 ) +#ifdef FF_PRINT +#define FF_PROLOGUE( name, string ) qboolean result = qfalse; if ( FF_IsAvailable() ) { if ( ff_developer && ff_developer->integer ) Com_Printf( "%s: \"%s\" ", #name, string ); +#define FF_PROLOGUE_NOQUOTE( name, string ) qboolean result = qfalse; if ( FF_IsAvailable() ) { if ( ff_developer && ff_developer->integer ) Com_Printf( "%s: %s ", #name, string ); +#define FF_EPILOGUE FF_EPILOGUE_NORETURN; return result; +#define FF_EPILOGUE_NORETURN } if ( ff_developer && ff_developer->integer ) Com_Printf( "[%s]\n", ( result ? _pass : _fail ) ); +#define FF_RESULT( function ) result = qboolean( function ); +#else +#define FF_PROLOGUE( name, string ) qboolean result = qfalse; if ( FF_IsAvailable() ) { +#define FF_PROLOGUE_NOQUOTE( name, string ) qboolean result = qfalse; if ( FF_IsAvailable() ) { +#define FF_EPILOGUE FF_EPILOGUE_NORETURN; return result; +#define FF_EPILOGUE_NORETURN } +#define FF_RESULT( function ) result = qboolean( function ); +#endif +#else +#define FF_PROLOGUE( name, string ) qboolean result = qfalse; +#define FF_PROLOGUE_NOQUOTE( name, string ) qboolean result = qfalse; +#define FF_EPILOGUE return result; +#define FF_EPILOGUE_NORETURN +#define FF_RESULT( function ) result = qboolean( function ); +#endif + +////-------------- +/// FF_IsAvailable +//------------------ +// Test to see if force feedback is currently operating. This is almost useless. +// The only good it does currently is temporarily toggle effects on/off for users +// amusement... feedback on, feedback off, feedback on, feedback off. Results are +// instantaneous. FF_* calls basically skip themselves harmlessly. +// +// Assumptions: +// * External system unloads this module if no device is present. +// * External system unloads this module if feedback is disabled when system (re)starts +// +// Parameters: +// None +// +// Returns: +// - true: feedback currently enabled +// - false: feedback currently disabled +// +qboolean FF_IsAvailable(void) +{ + return (use_ff && use_ff->integer && gFFSystem.IsInitialized()) ? qtrue : qfalse; +} + +qboolean FF_IsInitialized(void) +{ + return gFFSystem.IsInitialized(); +} + +////------- +/// FF_Init +//----------- +// Initializes the force feedback system. +// +// This function may be called multiple times to apply changes in cvars. +// +// Assumptions: +// * If FF_Init returns qfalse, caller calls FF_Shutdown +// +// Parameters: +// None +// +// Returns: +// - qtrue: module initialized properly. +// - qfalse: module experienced an error. Caller MUST call FF_Shutdown. +// +qboolean FF_Init( void ) +{ + if ( !gFFSystem.IsInitialized() ) + { + // + // Console variable setup + // + +#ifdef FF_CONSOLECOMMAND + Cmd_AddCommand( "ff_stopall", CMD_FF_StopAll ); + Cmd_AddCommand( "ff_info", CMD_FF_Info ); +#endif + use_ff = Cvar_Get( "use_ff", "1", CVAR_ARCHIVE /*| CVAR_LATCH*/); + ensureShake = Cvar_Get( "ff_ensureShake", "1", CVAR_TEMP); + ff_developer = Cvar_Get( "ff_developer", "0", CVAR_TEMP); + ff_channels = Cvar_Get( "ff_channels", FF_CHANNEL, CVAR_ARCHIVE); +#ifdef FF_DELAY + ff_delay = Cvar_Get( "ff_delay", FF_DELAY, CVAR_ARCHIVE); +#endif + } + + return qboolean // assumes external system will call FF_Shutdown in case of failure + ( ff_channels != NULL + && gFFSystem.Init( ff_channels->string ) + ); +} + +////----------- +/// FF_Shutdown +//--------------- +// Shut force feedback system down and free resources. +// +// Assumptions: +// * Always called if FF_Init returns qfalse. ALWAYS. (Or memory leaks occur) +// * Never called twice in succession. (always in response to previous assumption) +// +// Parameters: +// None +// +// Returns: +// None +// +void FF_Shutdown(void) +{ +#ifdef FF_CONSOLECOMMAND + Cmd_RemoveCommand( "ff_stopall" ); + Cmd_RemoveCommand( "ff_info" ); +#endif + + gFFSystem.Shutdown(); +} + +////----------- +/// FF_Register +//--------------- +// Loads a named effect from an .ifr file through the game's file system. The handle +// returned is not tied to any particular device. The feedback system may even change +// which device receives the effect without the need to restart the external system. +// The is ONE EXCEPTION. If this module is not loaded when the registration phase +// passes, the external system will need to be restarted to register effects properly. +// +// Parameters: +// * name: effect name from .ifr (case-sensitive) +// * channel: channel to output effect. A channel may play on 0+ devices. +// * notfound: return a valid handle even if effect is not found +// - Allows temporary disabling of a channel in-game without losing effects +// - Only use with trusted effect names, not user input. See CMD_FF_Play. +// +// Returns: +// Handle to loaded effect +// +ffHandle_t FF_Register( const char *name, int channel, qboolean notfound ) +{ + ffHandle_t ff = FF_HANDLE_NULL; + + // Removed console print... too much spam with AddLoopingForce. +/* + FF_PROLOGUE( FF_Register, ( name ? name : "" ) ); + ff = gFFSystem.Register( name, channel, notfound ); + FF_RESULT( ff != FF_HANDLE_NULL ); + FF_EPILOGUE_NORETURN; +*/ + if ( FF_IsAvailable() ) + ff = gFFSystem.Register( name, channel, notfound ); + + return ff; +} + +////---------------- +/// FF_EnsurePlaying +//-------------------- +// Starts an effect if the effect is not currently playing. +// Does not restart currently playing effects. +// +// Parameters: +// * ff: handle of an effect +// +// Returns: +// - qtrue: effect started +// - qfalse: effect was not started +// +qboolean FF_EnsurePlaying(ffHandle_t ff) +{ + FF_PROLOGUE( FF_EnsurePlaying, gFFSystem.GetName( ff ) ); + FF_RESULT( gFFSystem.EnsurePlaying( ff ) ); + FF_EPILOGUE; +} + +////------- +/// FF_Play +//----------- +// Start an effect on its registered channel. +// +// Parameters +// * ff: handle to an effect +// +// Returns: +// - qtrue: effect started +// - qfalse: effect was not started +// +qboolean FF_Play(ffHandle_t ff) +{ + FF_PROLOGUE( FF_Play, gFFSystem.GetName( ff ) ); + FF_RESULT( gFFSystem.Play( ff ) ); + FF_EPILOGUE; +} + +////---------- +/// FF_StopAll +//-------------- +// Stop all currently playing effects. +// +// Parameters: +// None +// +// Returns: +// - qtrue: no errors occurred +// - qfalse: an error occurred +// +qboolean FF_StopAll(void) +{ + FF_PROLOGUE( FF_StopAll, "" ); + FF_RESULT( gFFSystem.StopAll() ); + FF_EPILOGUE; +} + +////------- +/// FF_Stop +//----------- +// Stop an effect. Only returns qfalse if there's an error +// +// Parameters: +// * ff: handle to a playing effect +// +// Returns: +// - qtrue: no errors occurred +// - qfalse: an error occurred +// +qboolean FF_Stop(ffHandle_t ff) +{ + FF_PROLOGUE( FF_Stop, gFFSystem.GetName( ff ) ); + FF_RESULT( gFFSystem.Stop( ff ) ); + FF_EPILOGUE; +} + + +////-------- +/// FF_Shake +//------------ +// Shake the mouse (play the special "shake" effect) at a given strength +// for a given duration. The shake effect can be a compound containing +// multiple component effects, but each component effect's magnitude and +// duration will be set to the parameters passed in this function. +// +// Parameters: +// * intensity [0..10000] - Magnitude of effect +// * duration [0..MAXINT] - Length of shake in milliseconds +// +// Returns: +// - qtrue: shake started +// - qfalse: shake did not start +// +qboolean FF_Shake(int intensity, int duration) +{ + char message[64]; + message[0] = 0; + sprintf( message, "intensity=%d, duration=%d", intensity, duration ); + FF_PROLOGUE_NOQUOTE( FF_Shake, message ); + FF_RESULT( gFFSystem.Shake( intensity, duration, qboolean( ensureShake->integer != qfalse ) ) ); + FF_EPILOGUE; +} + +#ifdef FF_CONSOLECOMMAND + +////-------------- +/// CMD_FF_StopAll +//------------------ +// Console function which stops all currently playing effects +// +// Parameters: +// None +// +// Returns: +// None +// +void CMD_FF_StopAll(void) +{ + // Display messages + if ( FF_StopAll() ) + { + Com_Printf( "stopping all effects\n" ); + } + else + { + Com_Printf( "failed to stop all effects\n" ); + } +} + +////----------- +/// CMD_FF_Info +//--------------- +// Console function which displays various ff-system information. +// +// Parameters: +// * 'devices' display list of ff devices currently connected +// * 'channels' display list of support ff channels +// * 'order' display search order used by ff name-resolution system (ff_ffset.cpp) +// * 'files' display currently loaded .ifr files sorted by device +// * 'effects' display currently registered effects sorted by device +// +// Returns: +// None +// +void CMD_FF_Info(void) +{ + TNameTable Unprocessed, Processed; + int i, max; + + for + ( i = 1, max = Cmd_Argc() + ; i < max + ; i++ + ){ + Unprocessed.push_back( Cmd_Argv( i ) ); + } + + if ( Unprocessed.size() == 0 ) + { + + if ( ff_developer->integer ) + Com_Printf( "Usage: ff_info [devices] [channels] [order] [files] [effects]\n" ); + else + Com_Printf( "Usage: ff_info [devices] [channels]\n" ); + + return; + } + + gFFSystem.Display( Unprocessed, Processed ); + + if ( Unprocessed.size() > 0 ) + { + Com_Printf( "invalid parameters:" ); + for + ( i = 0 + ; i < Unprocessed.size() + ; i++ + ){ + Com_Printf( " %s", Unprocessed[ i ].c_str() ); + } + + if ( ff_developer->integer ) + Com_Printf( "Usage: ff_info [devices] [channels] [order] [files] [effects]\n" ); + else + Com_Printf( "Usage: ff_info [devices] [channels]\n" ); + } +} + +#endif // FF_CONSOLECOMMAND + +#endif // _IMMERSION \ No newline at end of file diff --git a/code/ff/ff.h b/code/ff/ff.h new file mode 100644 index 0000000..8321c1b --- /dev/null +++ b/code/ff/ff.h @@ -0,0 +1,33 @@ +#ifndef __FF_H +#define __FF_H + +#include "../ff/ff_public.h" + +#ifdef _FF + +// +// Externally visible functions +// + +qboolean FF_Init (void); +void FF_Shutdown (void); +qboolean FF_IsAvailable (void); +qboolean FF_IsInitialized (void); +ffHandle_t FF_Register (const char* ff, int channel, qboolean notfound = qtrue); +qboolean FF_Play (ffHandle_t ff); +qboolean FF_EnsurePlaying (ffHandle_t ff); +qboolean FF_Stop (ffHandle_t ff); +qboolean FF_StopAll (void); +qboolean FF_Shake (int intensity, int duration); + +#ifdef FF_CONSOLECOMMAND +typedef void (*xcommand_t) (void); +void CMD_FF_StopAll (void); +void CMD_FF_Info (void); +#endif + +//ffExport_t* GetFFAPI ( int apiVersion, ffImport_t *ffimp ); + +#endif // _FF + +#endif // __FF_H diff --git a/code/ff/ff_ChannelCompound.h b/code/ff/ff_ChannelCompound.h new file mode 100644 index 0000000..1b9acda --- /dev/null +++ b/code/ff/ff_ChannelCompound.h @@ -0,0 +1,64 @@ +#ifndef FF_CHANNELCOMPOUND_H +#define FF_CHANNELCOMPOUND_H + +#include "ff_MultiCompound.h" + +////--------------- +/// ChannelCompound +//------------------- +// Stored in THandleTable. This class associates MultiCompound with some arbitrary 'channel.' +// Further, this class assumes that its MultiEffects have the same name and are probably +// initialized on different devices. None of this is enforced at this time. +// +class ChannelCompound : public MultiCompound +{ +protected: + int mChannel; +public: + ChannelCompound( int channel = FF_CHANNEL_MAX ) + : MultiCompound() + { + mChannel = + ( (channel >= 0 && channel < FF_CHANNEL_MAX) + ? channel + : FF_CHANNEL_MAX + ); + } + + ChannelCompound( Set &compound, int channel = FF_CHANNEL_MAX ) + : MultiCompound( compound ) + { + mChannel = + ( (channel >= 0 && channel < FF_CHANNEL_MAX) + ? channel + : FF_CHANNEL_MAX + ); + } + + int GetChannel() + { + return mChannel; + } + const char *GetName() + { + return mSet.size() + ? (*mSet.begin())->GetName() + : NULL + ; + } + qboolean operator == ( ChannelCompound &channelcompound ) + { + return qboolean + ( mChannel == channelcompound.mChannel + && (*(MultiCompound*)this) == *(MultiCompound*)&channelcompound + ); + } + qboolean operator != ( ChannelCompound &channelcompound ) + { + return qboolean( !( (*this) == channelcompound ) ); + } +}; + +typedef vector THandleTable; + +#endif // FF_CHANNELCOMPOUND_H diff --git a/code/ff/ff_ChannelSet.cpp b/code/ff/ff_ChannelSet.cpp new file mode 100644 index 0000000..0f6f7d3 --- /dev/null +++ b/code/ff/ff_ChannelSet.cpp @@ -0,0 +1,162 @@ +#include "common_headers.h" + +#ifdef _IMMERSION + +extern const char *gChannelName[]; + +////--------------------------- +/// FFChannelSet::ParseChannels +//------------------------------- +// This is the worst hack of a parser ever devised. +// +qboolean FFChannelSet::ParseChannels( const char *channels ) +{ + if ( !channels ) + return qfalse; + + int channel; + const char *pos; + + for + ( pos = channels + ; pos && sscanf( pos, "%d", &channel ) == 1 + ; + ){ + int device; + char *endpos; + endpos = strchr( pos, ';' ); + + if ( channel >= 0 && channel < FF_CHANNEL_MAX ) + { + for + ( pos = strchr( pos, ',' ) + ; pos && ( !endpos || pos < endpos ) && sscanf( pos, " ,%d", &device ) == 1 + ; pos = strchr( pos + 1, ',' ) + ){ + if ( device >= 0 && device < mSet.size() ) + { + for + ( ChannelIterator itChannel( mChannel, channel ) + ; itChannel != mChannel.end() + && (**itChannel).second != device // found duplicate + ; ++itChannel + ); + + // Don't allow duplicates + if ( itChannel == mChannel.end() ) + { + FFChannelSet::Channel::value_type Value( channel, device ); + Value.second = device; + mChannel.insert( Value ); + } + } + } + } + + pos = ( endpos ? endpos + 1 : NULL); + + } + + // FIX ME -- return qfalse if there is a parse error + return qtrue; +} + +////---------------------- +/// FFChannelSet::Register +//-------------------------- +// +// Assumptions: +// * 'compound' is empty of effects and contains the desired channel prior to entry. +// +// Parameters: +// * compound: its channel parameter is an input. its effect set is filled with registered +// - effects. 'compound' should not contain any effects prior to this function call. +// * name: effect name to register in each FFSet on the channel +// * create: qtrue if FFSet should create the effect, qfalse if it should just look it up. +// +qboolean FFChannelSet::Register( ChannelCompound &compound, const char *name, qboolean create ) +{ + for + ( ChannelIterator itChannel( mChannel, compound.GetChannel() ) + ; itChannel != mChannel.end() + ; ++itChannel + ){ + MultiEffect *Effect; + Effect = mSet[ (**itChannel).second ]->Register( name, create ); + if ( Effect ) + compound.GetSet().insert( Effect ); + } + + return qboolean( compound.GetSet().size() != 0 ); +} + +#ifdef FF_CONSOLECOMMAND + +void FFChannelSet::GetDisplayTokens( TNameTable &Tokens ) +{ + FFMultiSet::GetDisplayTokens( Tokens ); + Tokens.push_back( "channels" ); + Tokens.push_back( "devices" ); +} + + +void FFChannelSet::Display( TNameTable &Unprocessed, TNameTable &Processed ) +{ + FFMultiSet::Display( Unprocessed, Processed ); + + for + ( TNameTable::iterator itName = Unprocessed.begin() + ; itName != Unprocessed.end() + ; + ){ + if ( stricmp( "channels", (*itName).c_str() ) == 0 ) + { + Com_Printf( "[available channels]\n" ); + + for + ( int i = 0 + ; i < FF_CHANNEL_MAX + ; i++ + ){ + Com_Printf( "%d) %s devices:", i, gChannelName[ i ] ); + for + ( ChannelIterator itChannel( mChannel, i ) + ; itChannel != mChannel.end() + ; ++itChannel + ){ + Com_Printf( " %d", (**itChannel).second ); + } + Com_Printf( "\n" ); + } + + Processed.push_back( *itName ); + itName = Unprocessed.erase( itName ); + } + else if ( stricmp( "devices", (*itName).c_str() ) == 0 ) + { + Com_Printf( "[initialized devices]\n" ); + + for + ( int i = 0 + ; i < mDevices->GetNumDevices() + ; i++ + ){ + char ProductName[ FF_MAX_PATH ]; + ProductName[ 0 ] = 0; + mDevices->GetDevice( i )->GetProductName( ProductName, FF_MAX_PATH - 1 ); + Com_Printf( "%d) %s\n", i, ProductName ); + } + + Processed.push_back( *itName ); + itName = Unprocessed.erase( itName ); + } + else + { + itName++; + } + } +} + +#endif // FF_CONSOLECOMMAND + +#endif // _IMMERSION \ No newline at end of file diff --git a/code/ff/ff_ChannelSet.h b/code/ff/ff_ChannelSet.h new file mode 100644 index 0000000..022d940 --- /dev/null +++ b/code/ff/ff_ChannelSet.h @@ -0,0 +1,59 @@ +#ifndef FF_CHANNELSET_H +#define FF_CHANNELSET_H + +#include "ff_utils.h" +#include "ff_MultiSet.h" +#include "ff_ChannelCompound.h" + +//===[FFChannelSet]===================================================///////////// +// +// An extension to FFMultiSet that operates on a subset of its +// elements specified by a channel. This channel may be inherent +// to a ChannelCompound passed as a parameter. +// +//====================================================================///////////// + +class FFChannelSet : public FFMultiSet +{ +public: + typedef multimap Channel; +protected: + Channel mChannel; + qboolean ParseChannels( const char *channels ); +public: + qboolean Init( FFConfigParser &config, const char *channels ) + { + return qboolean + ( FFMultiSet::Init( config ) // Initialize devices + && ParseChannels( channels ) // Assign channels to devices + ); + } + void clear() + { + mChannel.clear(); + FFMultiSet::clear(); + } + qboolean Register( ChannelCompound &compound, const char *name, qboolean create ); + + // + // Optional + // +#ifdef FF_ACCESSOR +// Channel& GetAll() { return mChannel; } +#endif + +#ifdef FF_CONSOLECOMMAND + void Display( TNameTable &Unprocessed, TNameTable &Processed ); + static void GetDisplayTokens( TNameTable &Tokens ); +#endif +}; + +class ChannelIterator : public multimapIterator +{ +public: + ChannelIterator( FFChannelSet::Channel &map, int channel ) + : multimapIterator( map, channel ) + {} +}; + +#endif // FF_CHANNELSET_H \ No newline at end of file diff --git a/code/ff/ff_ConfigParser.cpp b/code/ff/ff_ConfigParser.cpp new file mode 100644 index 0000000..f8dd946 --- /dev/null +++ b/code/ff/ff_ConfigParser.cpp @@ -0,0 +1,483 @@ +#include "common_headers.h" + +#ifdef _IMMERSION + +//#include "ff_ConfigParser.h" +//#include "ifc.h" +//#include "ff_utils.h" + +////-------------------- +/// FFConfigParser::Init +//------------------------ +// Reads the force feedback configuration file. Call this once after the device +// is initialized. +// +// Parameters: +// * filename +// +// Returns: +// * qtrue - the effects set directory has been set according to the initialized +// device. (See base/fffx/fffx.cfg) +// * qfalse - no effects set could be determined for this device. +// +qboolean FFConfigParser::Init( const char *filename ) +{ + Clear(); // Always cleanup + + return qboolean( filename && Parse( LoadFile( filename ) ) ); +} + +////--------------------- +/// FFConfigParser::Clear +//------------------------- +// +// +// Parameters: +// +// Returns: +// +void FFConfigParser::Clear( void ) +{ + mMap.clear(); + mDefaultSet.clear(); +} + +////--------------------- +/// FFConfigParser::Parse +//------------------------- +// +// +// Parameters: +// +// Returns: +// +qboolean FFConfigParser::Parse( void *file ) +{ + qboolean result = qboolean( file != NULL ); + + if ( file ) + { + const char *token = 0, *pos = (const char*)file; + for + ( token = COM_ParseExt( &pos, qtrue ) + ; token[ 0 ] + && result // fail if any problem + ; token = COM_ParseExt( &pos, qtrue ) + ){ + if ( !stricmp( token, "ffdefaults" ) ) + { + result &= ParseDefaults( &pos ); + } + else + if ( !stricmp( token, "ffsets" ) ) + { + result &= ParseSets( &pos ); + } + else + { + // unexpected field + result = qfalse; + } + } + + FS_FreeFile( file ); + } + + return result; +} + +////--------------------------------- +/// FFConfigParser::ParseDefaultBlock +//------------------------------------- +// +// +// Parameters: +// +// Returns: +// +qboolean FFConfigParser::ParseDefault( const char **pos, TDeviceType &defaultSet ) +{ + qboolean result = qboolean( pos != NULL ); + + if ( pos ) + { + char *token = COM_ParseExt( pos, qtrue ); + if ( token[ 0 ] == '{' ) + { + for + ( token = COM_ParseExt( pos, qtrue ) + ; token[ 0 ] + && token[ 0 ] != '}' + && result // fail if any problem + ; token = COM_ParseExt( pos, qtrue ) + ){ + int device = 0; + + if ( sscanf( token, "%d", &device ) ) + { + string &str = defaultSet[ device ]; + if ( !str.size() ) + { + str = COM_ParseExt( pos, qfalse ); + result &= qboolean( str.size() > 0 ); + } + else + { + result = qfalse; +#ifdef FF_PRINT + ConsoleParseError + ( "Redefinition of DeviceType index" + , token + ); +#endif + } + } + else + { + result = qfalse; +#ifdef FF_PRINT + ConsoleParseError + ( "DeviceType field should begin with an integer" + , token + ); +#endif + } + } + } + } + + return result; +} + + + +////---------------------------- +/// FFConfigParser::ParseDefault +//-------------------------------- +// +// +// Parameters: +// +// Returns: +// +qboolean FFConfigParser::ParseDefaults( const char **pos ) +{ + qboolean result = qboolean( pos != NULL ); + + if ( pos ) + { + char *token = COM_ParseExt( pos, qtrue ); + if ( token[ 0 ] == '{' ) + { + for + ( token = COM_ParseExt( pos, qtrue ) + ; token[ 0 ] + && token[ 0 ] != '}' + && result // fail if any problem + ; token = COM_ParseExt( pos, qtrue ) + ){ + int techType = 0; + + if ( sscanf( token, "%d", &techType ) ) + { + TDeviceType &deviceType = mDefaultSet[ techType ]; + if ( !deviceType.size() ) + { + result &= ParseDefault( pos, deviceType ); + mDefaultPriority.push_back( techType ); + } + else + { + result = qfalse; +#ifdef FF_PRINT + ConsoleParseError + ( "Redefinition of TechType index" + , token + ); +#endif + } + } + else + { + result = qfalse; +#ifdef FF_PRINT + ConsoleParseError + ( "TechType fields should begin with integers" + , token + ); +#endif + } + } + } + else + { + // expected '{' + result = qfalse; + } + } + + return result; +} + +////-------------------------- +/// FFConfigParser::RightOfSet +//------------------------------ +// +// +// Parameters: +// +// Returns: +// +const char* FFConfigParser::RightOfSet( const char *effectname ) +{ + const char *s = effectname; + + // Check through all set names and test effectname against it + for + ( TMap::iterator itMap = mMap.begin() + ; itMap != mMap.end() && s == effectname + ; itMap++ + ){ + s = RightOf( effectname, (*itMap).first.c_str() ); + } + + return s ? s : effectname; +} + +qboolean FFConfigParser::ParseSetDevices( const char **pos, TDevice &device ) +{ + qboolean result = qboolean( pos != NULL ); + + if ( pos ) + { + char *token = COM_ParseExt( pos, qtrue ); + if ( token[ 0 ] == '{' ) + { + for + ( token = COM_ParseExt( pos, qtrue ) + ; token[ 0 ] + && token[ 0 ] != '}' + && result // fail if any problem + ; token = COM_ParseExt( pos, qtrue ) + ){ + device.insert( token ); + } + + result = qboolean( token[ 0 ] != 0 ); + } + else + { + // expected '{' + result = qfalse; + } + } + + return result; +} + +qboolean FFConfigParser::ParseSetIncludes( const char **pos, TInclude &include ) +{ + qboolean result = qboolean( pos != NULL ); + + if ( pos ) + { + char *token = COM_ParseExt( pos, qtrue ); + if ( token[ 0 ] == '{' ) + { + for + ( token = COM_ParseExt( pos, qtrue ) + ; token[ 0 ] + && token[ 0 ] != '}' + && result // fail if any problem + ; token = COM_ParseExt( pos, qtrue ) + ){ + include.push_back( token ); + } + + result = qboolean( token[ 0 ] != 0 ); + } + else + { + // expected '{' + result = qfalse; + } + } + + return result; +} + +qboolean FFConfigParser::ParseSet( const char **pos, TData &data ) +{ + qboolean result = qboolean( pos != NULL ); + + if ( pos ) + { + const char *oldpos = *pos; // allows set declarations with no attributes to have no "{}" + char *token = COM_ParseExt( pos, qtrue ); + if ( token[ 0 ] == '{' ) + { + for + ( token = COM_ParseExt( pos, qtrue ) + ; token[ 0 ] + && token[ 0 ] != '}' + && result // fail if any problem + ; token = COM_ParseExt( pos, qtrue ) + ){ + if ( !stricmp( token, "includes" ) ) + { + result &= ParseSetIncludes( pos, data.include ); + } + else + if ( !stricmp( token, "devices" ) ) + { + result &= ParseSetDevices( pos, data.device ); + } + else + { + result = qfalse; +#ifdef FF_PRINT + ConsoleParseError + ( "Invalid set parameter. Should be 'includes' or 'devices'" + , token + ); +#endif + } + } + } + else + { + // expected '{' (no longer expected!) + //result = qfalse; (no longer an error!) + *pos = oldpos; + } + } + + return result; +} + +////------------------------- +/// FFConfigParser::ParseSets +//----------------------------- +// +// +// Parameters: +// +// Returns: +// +qboolean FFConfigParser::ParseSets( const char **pos ) +{ + qboolean result = qboolean( pos != NULL ); + string groupName; + + if ( pos ) + { + char *token = COM_ParseExt( pos, qtrue ); + if ( token[ 0 ] == '{' ) + { + for + ( token = COM_ParseExt( pos, qtrue ) + ; token[ 0 ] + && token[ 0 ] != '}' + && result // fail if any problem + ; token = COM_ParseExt( pos, qtrue ) + ){ + TData &data = mMap[ token ]; + result &= ParseSet( pos, data ); + } + } + else + { + // expected '{' + result = qfalse; + } + } + + return result; +} + +////--------------------------- +/// FFConfigParser::GetIncludes +//------------------------------- +// +// +// Parameters: +// +// Returns: +// +FFConfigParser::TInclude& FFConfigParser::GetIncludes( const char *name ) +{ + TMap::iterator itMap = mMap.find( name ); + if ( itMap != mMap.end() ) + return (*itMap).second.include; + + // No includes present + static TInclude emptyInclude; + return emptyInclude; +} + +const char * FFConfigParser::GetFFSet( CImmDevice *Device ) +{ + char devName[ FF_MAX_PATH ]; + const char *ffset = NULL; + + // + // Check explicit name + // + + devName[0] = 0; + Device->GetProductName( devName, FF_MAX_PATH - 1 ); + for + ( TMap::iterator itmap = mMap.begin() + ; itmap != mMap.end() + ; itmap++ + ){ + TDevice::iterator itdev; + + itdev = (*itmap).second.device.find( devName ); + if ( itdev != (*itmap).second.device.end() ) + ffset = (*itmap).first.c_str(); + } + + + // + // Check device defaults + // + + for + ( int i = 0 + ; !ffset && i < mDefaultPriority.size() + ; i++ + ){ + int defaultTechType; + DWORD productType = Device->GetProductType(); + WORD deviceType = HIWORD( productType ); + WORD techType = LOWORD( productType ); + + defaultTechType = mDefaultPriority[ i ]; + + // + // Check for minimum required features + // + + if ( (techType & defaultTechType) >= defaultTechType ) + { + // + // Check that device exists in this technology section + // + + TDeviceType::iterator itDeviceType = mDefaultSet[ defaultTechType ].find( deviceType ); + if ( itDeviceType != mDefaultSet[ defaultTechType ].end() ) + { + ffset = (*itDeviceType).second.c_str(); + } + } + + // + // If not, try next technology section + // + } + + return ffset; +} + +#endif // _IMMERSION \ No newline at end of file diff --git a/code/ff/ff_ConfigParser.h b/code/ff/ff_ConfigParser.h new file mode 100644 index 0000000..18b8d88 --- /dev/null +++ b/code/ff/ff_ConfigParser.h @@ -0,0 +1,51 @@ +#ifndef __FF_CONFIGPARSER_H +#define __FF_CONFIGPARSER_H + +//#include "ff_public.h" // in precompiled header + +//class CImmDevice; + +class FFConfigParser +{ +public: + typedef vector TInclude; + typedef set TDevice; + typedef map TDeviceType; + typedef map TTechType; + typedef vector TDefaultPriority; + + typedef struct + { + TInclude include; + TDevice device; + } TData; + + typedef map TMap; + +protected: + TTechType mDefaultSet; + TDefaultPriority mDefaultPriority; + TMap mMap; // Contains all effect sets by name + + qboolean Parse( void *file ); + qboolean ParseSets( const char **pos ); + qboolean ParseSet( const char **pos, TData &data ); + qboolean ParseSetIncludes( const char **pos, TInclude &include ); + qboolean ParseSetDevices( const char **pos, TDevice &device ); + qboolean ParseDefaults( const char **pos ); + qboolean ParseDefault( const char **pos, TDeviceType &defaultSet ); + +public: + + qboolean Init( const char *filename/*, CImmDevice *Device = NULL*/ ); + void Clear( void ); + +// const char* RightOfBase( const char *effectname ); +// const char* RightOfGame( const char *effectname ); + const char* RightOfSet( const char *effectname ); + + const char* GetFFSet( CImmDevice *Device ); + TInclude& GetIncludes( const char *name = NULL ); +}; + +#endif // __FF_CONFIGPARSER_H diff --git a/code/ff/ff_HandleTable.cpp b/code/ff/ff_HandleTable.cpp new file mode 100644 index 0000000..b75f82b --- /dev/null +++ b/code/ff/ff_HandleTable.cpp @@ -0,0 +1,133 @@ +#include "common_headers.h" + +#ifdef _IMMERSION + +////---------------------- +/// FFHandleTable::Convert +//-------------------------- +// +// +ffHandle_t FFHandleTable::Convert( ChannelCompound &compound, const char *name, qboolean create ) +{ + ffHandle_t ff = FF_HANDLE_NULL; + + // Reserve a handle for effects that failed to create. + // Rerouting channels to other devices may cause an effect to become lost. + // This assumes that FF_Register is always called with legitimate effect names. + // See CMD_FF_Play on how to handle possibly-bogus user input. + // (It does not call this function) + if ( compound.GetSet().size() ) + ff = Convert( compound ); + else + { + for + ( FFHandleTable::RegFail::iterator itRegFail = mRegFail.begin() + ; itRegFail != mRegFail.end() + && (*itRegFail).second != name + ; itRegFail++ + ); + + ff = + ( itRegFail != mRegFail.end() + ? (*itRegFail).first + : FF_HANDLE_NULL + ); + } + + if ( ff == FF_HANDLE_NULL ) + { + mVector.push_back( compound ); + ff = mVector.size() - 1; + + // Remember effect name for future 'ff_restart' calls. + if ( create && !compound.GetSet().size() ) + mRegFail[ ff ] = name; + } + + return ff; +} + +////---------------------- +/// FFHandleTable::Convert +//-------------------------- +// Looks for 'compound' in the table. +// +// Assumes: +// * 'compound' is non-empty +// +// Returns: +// ffHandle_t +// +ffHandle_t FFHandleTable::Convert( ChannelCompound &compound ) +{ + for + ( int i = 1 + ; i < mVector.size() + && mVector[ i ] != compound + ; i++ + ); + + return + ( i < mVector.size() + ? i + : FF_HANDLE_NULL + ); +} + +////----------------------------- +/// FFHandleTable::GetFailedNames +//--------------------------------- +// +// +qboolean FFHandleTable::GetFailedNames( TNameTable &NameTable ) +{ + for + ( RegFail::iterator itRegFail = mRegFail.begin() + ; itRegFail != mRegFail.end() + ; itRegFail++ + ){ + NameTable[ (*itRegFail).first ] = (*itRegFail).second; + } + + return qboolean( mRegFail.size() != 0 ); +} + +////-------------------------- +/// FFHandleTable::GetChannels +//------------------------------ +// +// +qboolean FFHandleTable::GetChannels( vector &channel ) +{ + //ASSERT( channel.size() >= mVector.size() ); + + for + ( int i = 1 + ; i < mVector.size() + ; i++ + ){ + channel[ i ] = mVector[ i ].GetChannel(); + } + + return qtrue; +} + +const char *FFHandleTable::GetName( ffHandle_t ff ) +{ + const char *result = NULL; + + if ( !mVector[ ff ].IsEmpty() ) + { + result = mVector[ ff ].GetName(); + } + else + { + RegFail::iterator itRegFail = mRegFail.find( ff ); + if ( itRegFail != mRegFail.end() ) + result = (*itRegFail).second.c_str(); + } + + return result; +} + +#endif // _IMMERSION \ No newline at end of file diff --git a/code/ff/ff_HandleTable.h b/code/ff/ff_HandleTable.h new file mode 100644 index 0000000..c8171f4 --- /dev/null +++ b/code/ff/ff_HandleTable.h @@ -0,0 +1,61 @@ +#ifndef FF_HANDLETABLE_H +#define FF_HANDLETABLE_H + +//===[FFHandleTable]==================================================///////////// +// +// This table houses the master list of initialized effects. Indices +// into this table are handles used by external modules. This way +// effects may be reinitialized on other devices, removed entirely, +// and perused informatively at any time without invalidating pointers. +// +//====================================================================///////////// + +class FFHandleTable +{ +public: + typedef vector Vector; + typedef map RegFail; +protected: + Vector mVector; + RegFail mRegFail; +public: + FFHandleTable() + : mVector() + , mRegFail() + { + //Init(); // guarantees operator [] always works + } + void Init() + { + ChannelCompound handle_null; + mVector.push_back( handle_null ); + } + // Empties handle table except for FF_HANDLE_NULL + void clear() + { + mVector.clear(); + mRegFail.clear(); + //Init(); // guarantees operator [] always works + } + int size() + { + return mVector.size(); + } + ChannelCompound& operator [] ( ffHandle_t ff ) + { + return mVector[ InRange( ff, 0, mVector.size() - 1, FF_HANDLE_NULL ) ]; + } + qboolean GetFailedNames( TNameTable &NameTable ); + qboolean GetChannels( vector &channels ); + ffHandle_t Convert( ChannelCompound &compound, const char *name, qboolean create ); + ffHandle_t Convert( ChannelCompound &compound ); + const char *GetName( ffHandle_t ff ); + + // + // Optional + // +// qboolean Lookup( set &result, MultiEffect *effect, const char *name ); +// qboolean Lookup( set &result, set &effect, const char *name ); +}; + +#endif // FF_HANDLETABLE_H \ No newline at end of file diff --git a/code/ff/ff_MultiCompound.cpp b/code/ff/ff_MultiCompound.cpp new file mode 100644 index 0000000..42eca88 --- /dev/null +++ b/code/ff/ff_MultiCompound.cpp @@ -0,0 +1,201 @@ +#include "common_headers.h" + +#ifdef _IMMERSION + +////------------------ +/// MultiCompound::Add +//---------------------- +// Insert a single compound effect if it does not already exist. +// Only fails when parameter is NULL. +// +qboolean MultiCompound::Add( MultiEffect *effect ) +{ + return effect ? ( mSet.insert( effect ), qtrue ) : qfalse; +} + +////------------------ +/// MultiCompound::Add +//---------------------- +// Merge set of compound effects with current set. NULL pointers are excluded. +// Returns false if set contains any NULL pointers. +// +qboolean MultiCompound::Add( Set &effect ) +{ + qboolean result = qtrue; + + for + ( Set::iterator itSet = effect.begin() + ; itSet != effect.end() + ; itSet++ + ){ + result &= Add( *itSet ); + } + + return result; +} + +////-------------------- +/// MultiCompound::Start +//------------------------ +// Analogous to CImmCompoundEffect::Start. Starts all contained compound effects. +// Returns false if any effect returns false. +// +qboolean MultiCompound::Start() +{ + qboolean result = qtrue; + + for + ( Set::iterator itSet = mSet.begin() + ; itSet != mSet.end() + ; itSet++ + ){ + result &= (*itSet)->Start(); + } + + return qboolean + ( result + && mSet.size() != 0 + ); +} + +qboolean MultiCompound::IsPlaying() +{ + for + ( Set::iterator itSet = mSet.begin() + ; itSet != mSet.end() + ; itSet++ + ){ + if ( !(*itSet)->IsPlaying() ) + return qfalse; + } + + return qtrue; +} + +////---------------------------- +/// MultiCompound::EnsurePlaying +//-------------------------------- +// Starts any contained compound effects if they are not currently playing. +// Returns false if any effect returns false or any are playing. +// +qboolean MultiCompound::EnsurePlaying() +{ + qboolean result = qtrue; + + if ( !IsPlaying() ) + { + for + ( Set::iterator itSet = mSet.begin() + ; itSet != mSet.end() + ; itSet++ + ){ + result &= (*itSet)->Start(); + } + } + + return qboolean + ( result + && mSet.size() != 0 + ); +} + +////------------------- +/// MultiCompound::Stop +//----------------------- +// Analogous to CImmCompoundEffect::Stop. Stops all contained compound effects. +// Returns false if any effect returns false. +// +qboolean MultiCompound::Stop() +{ + qboolean result = qtrue; + + for + ( Set::iterator itSet = mSet.begin() + ; itSet != mSet.end() + ; itSet++ + ){ + result &= qboolean( (*itSet)->Stop() ); + } + + return qboolean + ( result + && mSet.size() != 0 + ); +} + +////----------------------------- +/// MultiCompound::ChangeDuration +//--------------------------------- +// Changes duration of all compounds. +// Returns false if any effect returns false. +// +qboolean MultiCompound::ChangeDuration( DWORD Duration ) +{ + qboolean result = qtrue; + + for + ( Set::iterator itSet = mSet.begin() + ; itSet != mSet.end() + ; itSet++ + ){ + result &= (*itSet)->ChangeDuration( Duration ); + } + + return qboolean + ( result + && mSet.size() != 0 + ); +} + +////------------------------- +/// MultiCompound::ChangeGain +//----------------------------- +// Changes gain of all compounds. +// Returns false if any effect returns false. +// +qboolean MultiCompound::ChangeGain( DWORD Gain ) +{ + qboolean result = qtrue; + + for + ( Set::iterator itSet = mSet.begin() + ; itSet != mSet.end() + ; itSet++ + ){ + result &= (*itSet)->ChangeGain( Gain ); + } + + return qboolean + ( result + && mSet.size() != 0 + ); +} + +////-------------------------- +/// MultiCompound::operator == +//------------------------------ +// Returns qtrue if the sets are EXACTLY equal, including order. This is not good +// in general. (Fix me) +// +qboolean MultiCompound::operator == ( MultiCompound &compound ) +{ + Set &other = compound.mSet; + qboolean result = qfalse; + + if ( mSet.size() == other.size() ) + { + for + ( Set::iterator itSet = mSet.begin(), itOther = other.begin() + ; itSet != mSet.end() + //&& itOther != other.end() // assumed since mSet.size() == other.size() + && (*itSet) == (*itOther) + ; itSet++, itOther++ + ); + + result = qboolean( itSet == mSet.end() ); + } + + return result; +} + +#endif // _IMMERSION \ No newline at end of file diff --git a/code/ff/ff_MultiCompound.h b/code/ff/ff_MultiCompound.h new file mode 100644 index 0000000..466794f --- /dev/null +++ b/code/ff/ff_MultiCompound.h @@ -0,0 +1,54 @@ +#ifndef FF_MULTICOMPOUND_H +#define FF_MULTICOMPOUND_H + +//#include "common_headers.h" +#include "ff_MultiEffect.h" + +////------------- +/// MultiCompound +//----------------- +// MultiCompound is a container for MultiEffect pointers. +// It is not a single, complex effect and should not be treated as such. +// +class MultiCompound +{ +public: + typedef set Set; +protected: + Set mSet; +public: + MultiCompound() + : mSet() + {} + + MultiCompound( Set &compound ) + : mSet() + { + Add( compound ); + } + + Set& GetSet() { return mSet; } + qboolean Add( MultiEffect *Compound ); + qboolean Add( Set &compound ); + + // CImmEffect iterations + qboolean Start(); + qboolean Stop(); + qboolean ChangeDuration( DWORD Duration ); + qboolean ChangeGain( DWORD Gain ); + + // Utilities + qboolean IsEmpty() { return qboolean( mSet.size() == 0 ); } + qboolean operator == ( MultiCompound &compound ); + qboolean operator != ( MultiCompound &compound ) + { + return qboolean( !( (*this) == compound ) ); + } + + // Other iterations + qboolean IsPlaying(); + qboolean EnsurePlaying(); + +}; + +#endif // FF_MULTICOMPOUND_H \ No newline at end of file diff --git a/code/ff/ff_MultiEffect.cpp b/code/ff/ff_MultiEffect.cpp new file mode 100644 index 0000000..1d8ec21 --- /dev/null +++ b/code/ff/ff_MultiEffect.cpp @@ -0,0 +1,273 @@ +#include "common_headers.h" + +#ifdef _IMMERSION + +////-------------------------- +/// MultiEffect::GetStartDelay +//------------------------------ +// Determines the shortest start delay. +// +qboolean MultiEffect::GetStartDelay( DWORD &StartDelay ) +{ + StartDelay = MAXDWORD; + qboolean result = qtrue; + + for + ( int i = 0, max = GetNumberOfContainedEffects() + ; i < max + ; i++ + ){ + DWORD CurrentStartDelay; + CImmEffect* pIE = GetContainedEffect( i ); + if ( pIE + && pIE->GetStartDelay( CurrentStartDelay ) + ){ + StartDelay = Min( StartDelay, CurrentStartDelay ); + } + else + { + result = qfalse; + } + } + + return qboolean + ( result + && max > 0 + ); +} + +////------------------------ +/// MultiEffect::GetDelayEnd +//---------------------------- +// Computes end of earliest start delay. Compare this value with ::GetTickCount() +// to determine if any component waveform started playing on the device. +// +qboolean MultiEffect::GetDelayEnd( DWORD &DelayEnd ) +{ + DelayEnd = MAXDWORD; + qboolean result = qtrue; + + for + ( int i = 0, max = GetNumberOfContainedEffects() + ; i < max + ; i++ + ){ + DWORD StartDelay; + CImmEffect* pIE = GetContainedEffect( i ); + if ( pIE + && pIE->GetStartDelay( StartDelay ) + ){ + DelayEnd = Min( DelayEnd, StartDelay + pIE->m_dwLastStarted ); + } + else + { + result = qfalse; + } + } + + return qboolean + ( result + && max > 0 + ); +} + +////--------------------------- +/// MultiEffect::ChangeDuration +//------------------------------- +// Analogous to CImmEffect::ChangeDuration. Changes duration of all component effects. +// Returns false if any effect returns false. Attempts to change duration of all effects +// regardless of individual return values. +// +qboolean MultiEffect::ChangeDuration( DWORD Duration ) +{ + DWORD CurrentDuration; + qboolean result = GetDuration( CurrentDuration ); + + if ( result ) + { + DWORD RelativeDuration = Duration - CurrentDuration; + + for + ( int i = 0, max = GetNumberOfContainedEffects() + ; i < max + ; i++ + ){ + IMM_ENVELOPE Envelope = {0}; + CImmEffect* pIE = GetContainedEffect( i ); + result &= qboolean + ( pIE + && pIE->GetDuration( CurrentDuration ) + && pIE->ChangeDuration( CurrentDuration + RelativeDuration ) + && ( !pIE->GetEnvelope( &Envelope ) + || ( Envelope.dwAttackTime = ( CurrentDuration ? (DWORD)((float)Envelope.dwAttackTime * (float)Duration / (float)CurrentDuration) : 0 ) + , Envelope.dwFadeTime = ( CurrentDuration ? (DWORD)((float)Envelope.dwFadeTime * (float)Duration / (float)CurrentDuration) : 0 ) + , pIE->ChangeEnvelope( &Envelope ) + ) + ) + ); + } + + result &= qboolean( max > 0 ); + } + + return result; +} + +////----------------------- +/// MultiEffect::ChangeGain +//--------------------------- +// Analogous to CImmEffect::ChangeGain. Changes gain of all component effects. +// Returns false if any effect returns false. Attempts to change gain of all effects +// regardless of individual return values. +// +qboolean MultiEffect::ChangeGain( DWORD Gain ) +{ + DWORD CurrentGain; + qboolean result = GetGain( CurrentGain ); + + if ( result ) + { + DWORD RelativeGain = Gain - CurrentGain; + + for + ( int i = 0, max = GetNumberOfContainedEffects() + ; i < max + ; i++ + ){ + CImmEffect* pIE = GetContainedEffect( i ); + result &= qboolean + ( pIE + && pIE->GetGain( CurrentGain ) + && pIE->ChangeGain( CurrentGain + RelativeGain ) + ); + } + + result &= qboolean( max > 0 ); + } + + return result; +} + +////---------------------- +/// MultiEffect::GetStatus +//-------------------------- +// Analogous to CImmEffect::GetStatus. ORs all status flags from all component effects. +// Returns false if any effect returns false. Attempts to get status of all effects +// regardless of individual return values. +// +qboolean MultiEffect::GetStatus( DWORD &Status ) +{ + Status = 0; + qboolean result = qtrue; + + for + ( int i = 0, max = GetNumberOfContainedEffects() + ; i < max + ; i++ + ){ + DWORD CurrentStatus; + CImmEffect* pIE = GetContainedEffect( i ); + if ( pIE + && pIE->GetStatus( &CurrentStatus ) + ){ + Status |= CurrentStatus; + } + else + { + result = qfalse; + } + } + + return qboolean + ( result + && max > 0 + ); +} + +qboolean MultiEffect::ChangeStartDelay( DWORD StartDelay ) +{ + DWORD CurrentStartDelay; + qboolean result = GetStartDelay( CurrentStartDelay ); + + if ( result ) + { + DWORD RelativeStartDelay = StartDelay - CurrentStartDelay; + + for + ( int i = 0, max = GetNumberOfContainedEffects() + ; i < max + ; i++ + ){ + CImmEffect* pIE = GetContainedEffect( i ); + result &= qboolean + ( pIE + && pIE->GetStartDelay( CurrentStartDelay ) + && pIE->ChangeStartDelay( CurrentStartDelay + RelativeStartDelay ) + ); + } + + result &= qboolean( max > 0 ); + } + + return result; +} + +qboolean MultiEffect::GetDuration( DWORD &Duration ) +{ + Duration = 0; + qboolean result = qtrue; + + for + ( int i = 0, max = GetNumberOfContainedEffects() + ; i < max + ; i++ + ){ + DWORD CurrentDuration; + CImmEffect* pIE = GetContainedEffect( i ); + if ( pIE + && pIE->GetDuration( CurrentDuration ) + ){ + Duration = Max( Duration, CurrentDuration ); + } + else + { + result = qfalse; + } + } + + return qboolean + ( result + && max > 0 + ); +} + +qboolean MultiEffect::GetGain( DWORD &Gain ) +{ + Gain = 0; + qboolean result = qtrue; + + for + ( int i = 0, max = GetNumberOfContainedEffects() + ; i < max + ; i++ + ){ + DWORD CurrentGain; + CImmEffect* pIE = GetContainedEffect( i ); + if ( pIE + && pIE->GetGain( CurrentGain ) + ){ + Gain = Max( Gain, CurrentGain ); + } + else + { + result = qfalse; + } + } + + return qboolean + ( result + && max > 0 + ); +} + +#endif // _IMMERSION \ No newline at end of file diff --git a/code/ff/ff_MultiEffect.h b/code/ff/ff_MultiEffect.h new file mode 100644 index 0000000..a7594e2 --- /dev/null +++ b/code/ff/ff_MultiEffect.h @@ -0,0 +1,59 @@ +#ifndef MULTIEFFECT_H +#define MULTIEFFECT_H + +//#include "common_headers.h" +//#include "ifc.h" + +////----------- +/// MultiEffect +//--------------- +// CImmCompoundEffect makes no assumption that its contained effects form a more +// complex, single effect. MultiEffect makes this assumption and provides member +// functions available in CImmEffect to operate on this "complex" effect. +// +// Do not instantiate. (Do not call constructor) +// Instead, cast existing CImmCompoundEffect* to MultiEffect* +// Utility functions are specific to the needs of this system. +// +class MultiEffect : public CImmCompoundEffect +{ +public: + // dummy constructor + MultiEffect() : CImmCompoundEffect( NULL, 0, NULL ) {} // Never call (cast instead) + + // CImmEffect extensions + qboolean GetStatus( DWORD &Status ); + qboolean GetStartDelay( DWORD &StartDelay ); + qboolean GetDuration( DWORD &Duration ); + qboolean GetGain( DWORD &Gain ); + qboolean ChangeDuration( DWORD Duration ); + qboolean ChangeGain( DWORD Gain ); + qboolean ChangeStartDelay( DWORD StartDelay ); + + // utility functions + qboolean GetDelayEnd( DWORD &DelayEnd ); + qboolean IsBeyondStartDelay() + { + DWORD DelayEnd; + return qboolean + ( GetDelayEnd( DelayEnd ) + && DelayEnd < ::GetTickCount() // Does not account for counter overflow. + ); + } + qboolean IsPlaying() + { + DWORD Status; + return qboolean( GetStatus( Status ) && (Status & IMM_STATUS_PLAYING) ); + } + + // CImmCompoundEffect overrides + qboolean Start( DWORD dwIterations = IMM_EFFECT_DONT_CHANGE, DWORD dwFlags = 0 ) + { + return qboolean + ( IsBeyondStartDelay() + && CImmCompoundEffect::Start( dwIterations, dwFlags ) + ); + } +}; + +#endif // MULTIEFFECT_H \ No newline at end of file diff --git a/code/ff/ff_MultiSet.cpp b/code/ff/ff_MultiSet.cpp new file mode 100644 index 0000000..aed6716 --- /dev/null +++ b/code/ff/ff_MultiSet.cpp @@ -0,0 +1,140 @@ +#include "common_headers.h" + +#ifdef _IMMERSION + +#include "..\win32\win_local.h" + +////---------------- +/// FFMultiSet::Init +//-------------------- +// Initializes all attached force feedback devices. An empty FFSet is created +// for each device. Each device will have its own copy of whatever .ifr file +// set 'config' specifies. +// +// Always pair with clear() +// +qboolean FFMultiSet::Init( FFSystem::Config &config ) +{ + mConfig = &config; + +#ifdef FF_PRINT + Com_Printf( "Feedback devices:\n" ); +#endif + + HINSTANCE hInstance = (HINSTANCE)g_wv.hInstance; + HWND hWnd = (HWND)g_wv.hWnd; + + mDevices = new CImmDevices; + if ( mDevices && mDevices->CreateDevices( hInstance, hWnd ) ) + { + for + ( int i = 0 + ; i < mDevices->GetNumDevices() + ; i++ + ){ + FFSet *ffSet = NULL; + ffSet = new FFSet( config, mDevices->GetDevice( i ) ); + if ( ffSet ) + { +#ifdef FF_PRINT + char ProductName[ FF_MAX_PATH ]; + *ProductName = 0; + mDevices->GetDevice( i )->GetProductName( ProductName, FF_MAX_PATH - 1 ); + Com_Printf( "%d) %s\n", i, ProductName ); +#endif + mSet.push_back( ffSet ); + } + } + } + + return qboolean( mSet.size() ); +} + +////------------------------------ +/// FFMultiSet::GetRegisteredNames +//---------------------------------- +// +// +qboolean FFMultiSet::GetRegisteredNames( TNameTable &NameTable ) +{ + for + ( int i = 0 + ; i < mSet.size() + ; i++ + ){ + mSet[ i ]->GetRegisteredNames( NameTable ); + } + + return qtrue; +} + +////------------------- +/// FFMultiSet::StopAll +//----------------------- +// Stops all effects in every FFSet. +// Returns qfalse if any return false. +// +qboolean FFMultiSet::StopAll() +{ + qboolean result = qtrue; + + for + ( int i = 0 + ; i < mSet.size() + ; i++ + ){ + result &= mSet[ i ]->StopAll(); + } + + return result; +} + +////----------------- +/// FFMultiSet::clear +//--------------------- +// Cleans up. +// +void FFMultiSet::clear() +{ + mConfig = NULL; + for + ( int i = 0 + ; i < mSet.size() + ; i++ + ){ + DeletePointer( mSet[ i ] ); + } + mSet.clear(); + DeletePointer( mDevices ); +} + +#ifdef FF_CONSOLECOMMAND + +void FFMultiSet::GetDisplayTokens( TNameTable &Tokens ) +{ + FFSet::GetDisplayTokens( Tokens ); +} + +////------------------- +/// FFMultiSet::Display +//----------------------- +// +// +void FFMultiSet::Display( TNameTable &Unprocessed, TNameTable &Processed ) +{ + for + ( int i = 0 + ; i < mSet.size() + ; i++ + ){ + TNameTable Temp1, Temp2; + Temp1.clear(); + Temp2.clear(); + Temp1.insert( Temp1.begin(), Processed.begin(), Processed.end() ); + mSet[ i ]->Display( Temp1, Temp2 ); + } +} + +#endif // FF_CONSOLECOMMAND + +#endif // _IMMERSION \ No newline at end of file diff --git a/code/ff/ff_MultiSet.h b/code/ff/ff_MultiSet.h new file mode 100644 index 0000000..b42cd99 --- /dev/null +++ b/code/ff/ff_MultiSet.h @@ -0,0 +1,43 @@ +#ifndef FF_MULTISET_H +#define FF_MULTISET_H + +#include "ff_ffset.h" + +//===[FFMultiSet]=====================================================///////////// +// +// A collection class of FFSet objects. These functions generally +// iterate over the entire set of FFSets, performing the same operation +// on all contained FFSets. +// +//====================================================================///////////// + +class FFMultiSet +{ +public: + typedef vector Set; +protected: + FFConfigParser *mConfig; + Set mSet; + CImmDevices *mDevices; +public: + qboolean Init( FFConfigParser &config ); +// qboolean Lookup( set &effect, const char *name ); + qboolean GetRegisteredNames( TNameTable &NameTable ); + qboolean StopAll(); + void clear(); + + // + // Optional + // +#ifdef FF_ACCESSOR + Set& GetSets() { return mSet; } + CImmDevices* GetDevices() { return mDevices; } +#endif + +#ifdef FF_CONSOLECOMMAND + void Display( TNameTable &Unprocessed, TNameTable &Processed ); + static void GetDisplayTokens( TNameTable &Tokens ); +#endif +}; + +#endif // FF_MULTISET_H \ No newline at end of file diff --git a/code/ff/ff_ffset.cpp b/code/ff/ff_ffset.cpp new file mode 100644 index 0000000..e8104bf --- /dev/null +++ b/code/ff/ff_ffset.cpp @@ -0,0 +1,356 @@ +#include "common_headers.h" + +#ifdef _IMMERSION + +//#include "ff.h" +//#include "ff_ffset.h" +//#include "ff_compound.h" +//#include "ff_system.h" + +extern cvar_t *ff_developer; +#ifdef FF_DELAY +extern cvar_t *ff_delay; +#endif + +extern FFSystem gFFSystem; + +FFSet::FFSet( FFConfigParser &ConfigParser, CImmDevice *Device ) +: mParser( ConfigParser ) +, mDevice( Device ) +, mInclude() +, mIncludePath() +{ + const char *setname = mParser.GetFFSet( mDevice ); + if ( setname ) + { + TProject temp; + mInclude.push_back( temp ); + mIncludePath.push_back( setname ); + InitIncludes( setname ); + } +} + +FFSet::~FFSet() +{ + for + ( TInclude::iterator itInclude = mInclude.begin() + ; itInclude != mInclude.end() + ; itInclude++ + ){ + for + ( TProject::iterator itProject = (*itInclude).begin() + ; itProject != (*itInclude).end() + ; itProject++ + ){ + DeletePointer( (*itProject).second ); + } + } +} + +void FFSet::InitIncludes( const char *setname ) +{ + FFConfigParser::TInclude &include = mParser.GetIncludes( setname ); + + for // each include listed in config file + ( int i = 0 + ; i < include.size() + ; i++ + ){ + for // each include entered into current list + ( int j = 0 + ; j < mIncludePath.size() + ; j++ + ){ + if ( include[ i ] == mIncludePath[ j ] ) // exists in current list + break; + } + + if ( j == mIncludePath.size() ) // does not exist in current list + { + TProject temp; + mInclude.push_back( temp ); + mIncludePath.push_back( include[ i ] ); + InitIncludes( include[ i ].c_str() ); // recurse + } + } +} + +MultiEffect* FFSet::Register( const char *path, qboolean create ) +{ + char outpath[ FF_MAX_PATH ]; + MultiEffect* effect = NULL; + + if ( FS_VerifyName( "FFSet::Register", path, outpath ) ) + { + for // each included set + ( int i = 0 + ; i < mInclude.size() && !effect + ; i++ + ){ + char setpath[ FF_MAX_PATH ], *afterincludepath; + // need to use explicit path if provided. + sprintf( setpath, "%s/%s", mIncludePath[ i ].c_str(), UncommonDirectory( path, mIncludePath[ i ].c_str() ) ); + afterincludepath = setpath + mIncludePath[ i ].length() + 1; + + for // each possible file/effectname combination + ( int separator = _rcpos( afterincludepath, '/' ) + ; separator >= 0 && !effect + ; separator = _rcpos( afterincludepath, '/', separator ) + ){ + CImmProject *immProject; + char temp[4]; + + temp[0] = 0; + afterincludepath[separator] = 0; + if ( stricmp( afterincludepath + separator - 4, ".ifr" ) ) + { + memcpy( temp, afterincludepath + separator + 1, 4 ); + sprintf( afterincludepath + separator, ".ifr" ); + } + + immProject = NULL; + + TProject::iterator itProject = mInclude[ i ].find( afterincludepath ); + if ( itProject != mInclude[ i ].end() ) + { + immProject = (*itProject).second; + } + else if ( create ) + { + void *buffer = LoadFile( setpath ); + if ( buffer ) + { + immProject = new CImmProject; + + if ( immProject ) + { + if ( !immProject->LoadProjectFromMemory( buffer, mDevice ) ) + { + DeletePointer( immProject ); +#ifdef FF_PRINT + if ( ff_developer->integer ) + Com_Printf( "...Corrupt or invalid file: %s\n", setpath ); + } + else + { + if ( ff_developer->integer ) + Com_Printf( "...Adding file \"%s\"\n", setpath ); +#endif FF_PRINT + } + } + + FS_FreeFile( buffer ); + } + + mInclude[ i ][ afterincludepath ] = immProject; + } + + if ( temp[ 0 ] ) + { + afterincludepath[ separator ] = '/'; + memcpy( afterincludepath + separator + 1, temp, 4 ); + } + + if ( immProject ) + { + effect = (MultiEffect*)immProject->GetCreatedEffect( afterincludepath + separator + 1 ); + if ( !effect && create ) + { + effect = (MultiEffect*)immProject->CreateEffect( afterincludepath + separator + 1, mDevice, IMM_PARAM_NODOWNLOAD ); +#ifdef FF_DELAY + // Delay the effect (better sound synchronization) + if ( effect + && ff_delay + //&& *ff_delay + ){ + effect->ChangeStartDelay( ff_delay->integer ); + } +#endif // FF_DELAY + } + } + } + } + } + + return effect; +} + +qboolean FFSet::StopAll( void ) +{ + for + ( TInclude::iterator itInclude = mInclude.begin() + ; itInclude != mInclude.end() + ; itInclude++ + ){ + for + ( TProject::iterator itProject = (*itInclude).begin() + ; itProject != (*itInclude).end() + ; itProject++ + ){ + if ( (*itProject).second ) + (*itProject).second->Stop(); + } + } + + return qtrue; +} + +void FFSet::GetRegisteredNames( TNameTable &NameTable ) +{ + FFSystem::Handle ffHandle = gFFSystem.GetHandles(); + + for + ( int IncludeIndex = 0 + ; IncludeIndex < mInclude.size() + ; IncludeIndex++ + ){ + for + ( TProject::iterator itProject = mInclude[ IncludeIndex ].begin() + ; itProject != mInclude[ IncludeIndex ].end() + ; itProject++ + ){ + char effectname[ FF_MAX_PATH ]; + int i; + + if ( !(*itProject).second ) + continue; + + i = 0; + + for + ( MultiEffect *Effect = (MultiEffect*)(*itProject).second->GetCreatedEffect( i ) + ; Effect + ; Effect = (MultiEffect*)(*itProject).second->GetCreatedEffect( ++i ) + ){ + sprintf( effectname, "%s/%s/%s", mIncludePath[ IncludeIndex ].c_str(), (*itProject).first.c_str(), Effect->GetName() ); + + for + ( int i = 0 + ; i < ffHandle.size() + ; i++ + ){ + ChannelCompound::Set &compound = ffHandle[ i ].GetSet(); + if + ( NameTable[ i ].length() == 0 + && compound.find( Effect ) != compound.end() + ){ + NameTable[ i ] = effectname; + } + } + } + } + } +} + +//////////////////////////////////////////////// + +#ifdef FF_CONSOLECOMMAND + +void FFSet::GetDisplayTokens( TNameTable &Tokens ) +{ + if ( ff_developer->integer ) + { + Tokens.push_back( "order" ); + Tokens.push_back( "files" ); + } +} + + +void FFSet::Display( TNameTable &Unprocessed, TNameTable &Processed ) +{ + for + ( TNameTable::iterator itName = Unprocessed.begin() + ; itName != Unprocessed.end() + ; + ){ + if ( stricmp( "order", (*itName).c_str() ) == 0 ) + { + if ( ff_developer->integer ) + DisplaySearchOrder(); + //else + // Com_Printf( "\"order\" only available when ff_developer is set\n" ); + + Processed.push_back( *itName ); + itName = Unprocessed.erase( itName ); + } + else + if ( stricmp( "files", (*itName).c_str() ) == 0 ) + { + if ( ff_developer->integer ) + DisplayLoadedFiles(); + //else + // Com_Printf( "\"files\" only available when ff_developer is set\n" ); + + Processed.push_back( *itName ); + itName = Unprocessed.erase( itName ); + } + else + { + itName++; + } + } + +} + +void FFSet::DisplaySearchOrder( void ) +{ + char ProductName[ FF_MAX_PATH ]; + *ProductName = 0; + mDevice->GetProductName( ProductName, FF_MAX_PATH - 1 ); + Com_Printf( "[search order] -\"%s\"\n", ProductName ); + + for + ( int i = 0 + ; i < mInclude.size() + ; i++ + ){ + Com_Printf( "%d) %s\n", i, mIncludePath[ i ].c_str() ); + } +} + +void FFSet::DisplayLoadedFiles( void ) +{ + int total = 0; +#ifdef _DEBUG + int nulltotal = 0; // Variable to indicate how bad my algorithm is +#endif + + char ProductName[ FF_MAX_PATH ]; + *ProductName = 0; + mDevice->GetProductName( ProductName, FF_MAX_PATH - 1 ); + Com_Printf( "[loaded files] -\"%s\"\n", ProductName ); + + for + ( int i = 0 + ; i < mInclude.size() + ; i++ + ){ + for + ( TProject::iterator itProject = mInclude[ i ].begin() + ; itProject != mInclude[ i ].end() + ; itProject++ + ){ + if ( (*itProject).second ) + { + ++total; + Com_Printf( "%s/%s\n", mIncludePath[ i ].c_str(), (*itProject).first.c_str() ); + } +#ifdef _DEBUG + else + { + ++nulltotal; + Com_Printf( "%s/%s [null]\n", mIncludePath[ i ].c_str(), (*itProject).first.c_str() ); + } +#endif + } + } + + Com_Printf( "Total: %d files\n", total ); +#ifdef _DEBUG + Com_Printf( "Total: %d null files\n", nulltotal ); +#endif +} + +#endif // FF_CONSOLECOMMAND + +#endif // _IMMERSION \ No newline at end of file diff --git a/code/ff/ff_ffset.h b/code/ff/ff_ffset.h new file mode 100644 index 0000000..1b34aab --- /dev/null +++ b/code/ff/ff_ffset.h @@ -0,0 +1,64 @@ +#ifndef FFSET_H +#define FFSET_H + +//#include "ff_ConfigParser.h" +//#include "ff_utils.h" +//#include "ff_compound.h" +//class MultiEffect; +//#include "ifc.h" +//class CImmDevice; +//class CImmProject; + +#include "ff_MultiEffect.h" + +class FFSet +{ + // + // Types + // +public: + typedef map TProject; + typedef vector TInclude; + typedef vector TIncludePath; + + // + // Variables + // +protected: + TInclude mInclude; + TIncludePath mIncludePath; + CImmDevice *mDevice; + FFConfigParser &mParser; + + // + // Functions + // +public: + FFSet( FFConfigParser &ConfigParser, CImmDevice *Device ); + ~FFSet(); + MultiEffect* Register( const char *path, qboolean create = qtrue ); + void GetRegisteredNames( TNameTable &NameTable ); + qboolean StopAll( void ); + +protected: + void InitIncludes( const char *setname = NULL ); + + // + // Optional + // +#ifdef FF_ACCESSOR +public: + CImmDevice* GetDevice( void ) { return mDevice; } +#endif + +#ifdef FF_CONSOLECOMMAND +public: + void Display( TNameTable &Unprocessed, TNameTable &Processed ); + void DisplaySearchOrder( void ); + void DisplayLoadedFiles( void ); + static void GetDisplayTokens( TNameTable &Tokens ); +#endif + +}; + +#endif // FFSET_H \ No newline at end of file diff --git a/code/ff/ff_local.h b/code/ff/ff_local.h new file mode 100644 index 0000000..7488e69 --- /dev/null +++ b/code/ff/ff_local.h @@ -0,0 +1,24 @@ +#ifndef FF_LOCAL_H +#define FF_LOCAL_H + +#define FF_ACCESSOR +#define FF_API_VERSION 1 + +// Better sound synchronization +// This is default value for cvar ff_delay. User may tweak this. +#define FF_DELAY "40" +// Default: all channels output to primary device +#define FF_CHANNEL "0,0;1,0;2,0;3,0;4,0;5,0" +// Optional system features +#define FF_PRINT +#ifdef FF_PRINT +#define FF_CONSOLECOMMAND +#endif +// (end) Optional system features + +#include "..\game\q_shared.h" // includes ff_public.h +#include "..\qcommon\qcommon.h" + +#define FF_MAX_PATH MAX_QPATH + +#endif // FF_LOCAL_H \ No newline at end of file diff --git a/code/ff/ff_public.h b/code/ff/ff_public.h new file mode 100644 index 0000000..96e2a1e --- /dev/null +++ b/code/ff/ff_public.h @@ -0,0 +1,43 @@ +#ifndef __FF_PUBLIC_H +#define __FF_PUBLIC_H + +#define FF_HANDLE_NULL 0 +#define FF_CLIENT_LOCAL (-2) +#define FF_CLIENT( client ) (FF_CLIENT_LOCAL - client) + +typedef int ffHandle_t; + +/* +enum FFChannel_e +{ FF_CHANNEL_WEAPON +, FF_CHANNEL_MENU +, FF_CHANNEL_TOUCH +, FF_CHANNEL_DAMAGE +, FF_CHANNEL_VEHICLE +, FF_CHANNEL_MAX +}; +*/ +#define FF_CHANNEL_WEAPON 0 +#define FF_CHANNEL_MENU 1 +#define FF_CHANNEL_TOUCH 2 +#define FF_CHANNEL_DAMAGE 3 +#define FF_CHANNEL_BODY 4 +#define FF_CHANNEL_FORCE 5 +#define FF_CHANNEL_FOOT 6 +#define FF_CHANNEL_MAX 7 + +#ifdef _FF + +/* +inline qboolean operator &= ( qboolean &lvalue, qboolean rvalue ) +{ + lvalue = qboolean( (int)lvalue && (int)rvalue ); + return lvalue; +} +*/ + +#include "../ff/ff.h" // basic system functions +#include "../ff/ff_snd.h" // sound system similarities +#endif // _FF + +#endif // __FF_PUBLIC_H \ No newline at end of file diff --git a/code/ff/ff_snd.cpp b/code/ff/ff_snd.cpp new file mode 100644 index 0000000..87f7112 --- /dev/null +++ b/code/ff/ff_snd.cpp @@ -0,0 +1,503 @@ +#include "common_headers.h" + +#ifdef _IMMERSION + +#include "ff_snd.h" +#include "ff.h" + +extern FFSystem gFFSystem; + +#define FF_GAIN_STEP 500 + +// +// Internal data structures +// +// This whole system should mirror snd_dma.cpp to some degree. +// Right now, not much works. + +/* +template +static T RelativeDistance( T Volume, T Min, T Max ) +{ + if ( Min == Max ) + if ( Volume < Min ) + return 0.f; + else + return 1.f; + + return (Volume - Min) / (Max - Min); +}; + +template +int Round( T value, int mod ) +{ + int intval = (int)value; + int intmod = intval % mod; + int roundup = intmod >= mod / 2; + + return + ( intval + ? roundup + ? intval + mod - intmod + : intval - intmod + : roundup + ? mod + : 0 + ); +} +*/ + +class SndForce +{ +public: + ffHandle_t mHandle; + int mRefs; + qboolean mPlaying; +// int mEntNum; +// vec3_t mOrigin; +// struct SDistanceLimits +// { int min; +// int max; +// } mDistance; + +public: + void zero() + { + mHandle = FF_HANDLE_NULL; + mRefs = 0; + mPlaying = qfalse; +// mEntNum = 0; +// mDistance.min = 0; +// mDistance.max = 0; +// mOrigin[0] = 1.f; +// mOrigin[1] = 0.f; +// mOrigin[2] = 0.f; + } + SndForce() + { + zero(); + } + SndForce( const SndForce &other ) + { + memcpy( this, &other, sizeof(SndForce) ); + } + SndForce( ffHandle_t handle/*, int entNum, const vec3_t origin, float maxDistance, float minDistance*/ ) + : mHandle( handle ) + , mRefs( 0 ) + , mPlaying( qfalse ) +// , mEntNum( entNum ) + { +// mDistance.min = minDistance; +// mDistance.max = maxDistance; +// memcpy( mOrigin, origin, sizeof(mOrigin) ); + } + void AddRef() + { + ++mRefs; + } + void SubRef() + { + --mRefs; + } + qboolean Update( void ) const + { + return qboolean + ( mRefs != 0 + && (ChannelCompound*)mHandle + ); + } +/* int GetGain() + { + float distance = 1.f - GetRelativeDistance(); + + return distance == 0.f + ? 10000 + : Clamp + ( Round + ( distance * 10000 + , FF_GAIN_STEP + ) + , 0 + , 10000 + ) + ; + } + float GetRelativeDistance() + { + return !mRefs + ? 1.f + : IsOrigin() + ? 0.f + : RelativeDistance + ( sqrt + ( mOrigin[0] * mOrigin[0] + + mOrigin[1] * mOrigin[1] + + mOrigin[2] * mOrigin[2] + ) + , mDistance.min + , mDistance.max + ) / mRefs + ; + } + qboolean IsOrigin() + { + return qboolean + ( !mOrigin[0] + && !mOrigin[1] + && !mOrigin[2] + ); + } + void Respatialize( int entNum, const vec3_t origin ) + { + extern vec3_t s_entityPosition[]; + + if ( mEntNum != entNum ) + { + // Assumes all forces follow its entity and is centered on entity + mOrigin[0] = s_entityPosition[ entNum ][0] - origin[0]; + mOrigin[1] = s_entityPosition[ entNum ][1] - origin[1]; + mOrigin[2] = s_entityPosition[ entNum ][2] - origin[2]; + } + else + { + memset( mOrigin, 0, sizeof(mOrigin) ); + } + }*/ + void operator += ( SndForce &other ); +}; + +// Fancy comparator +struct SndForceLess : public less +{ + bool operator() ( const SndForce &x, const SndForce &y ) + { + return bool + (/* x.mEntNum < y.mEntNum + ||*/x.mHandle < y.mHandle +// || x.mOrigin < y.mOrigin // uhhh... compare components + || x.mPlaying < y.mPlaying + ); + } +}; + + +class LoopForce : public SndForce +{ +public: + LoopForce(){} + LoopForce( const LoopForce &other ) + { + memcpy( this, &other, sizeof(LoopForce) ); + } + LoopForce( ffHandle_t handle/*int entNum, , const vec3_t origin, float maxDistance, float minDistance*/ ) + : SndForce( handle/*, entNum, origin, maxDistance, minDistance*/ ) + {} + + void Add( ffHandle_t ff/*, int entNum, const vec3_t origin*/ ); +// void Respatialize( int entNum, const vec3_t origin ); + qboolean Update( void ) + { + qboolean result = SndForce::Update(); + mRefs = 0; + return result; + } +}; + +class SndForceSet +{ +public: + typedef set PendingSet; + typedef map ActiveSet; + ActiveSet mActive; + PendingSet mPending; +public: + void Add( ffHandle_t handle/*, int entNum, const vec3_t origin, float maxDistance, float minDistance*/ ) + { + const_cast (*mPending.insert( SndForce( handle/*, entNum, origin, maxDistance, minDistance*/ ) ).first).AddRef(); + } + qboolean Update( void ); +/* void Respatialize( int entNum, const vec3_t origin ) + { + for + ( PendingSet::iterator itPending = mPending.begin() + ; itPending != mPending.end() + ; itPending++ + ){ + (*itPending).Respatialize( entNum, origin ); + } + }*/ +}; + +class LoopForceSet +{ +public: + typedef set PendingSet; + typedef map ActiveSet; + ActiveSet mActive; + PendingSet mPending; +public: + void Add( ffHandle_t handle/*, int entNum, const vec3_t origin, float maxDistance, float minDistance*/ ) + { + const_cast (*mPending.insert( LoopForce( handle/*, entNum, origin, maxDistance, minDistance*/ ) ).first).AddRef(); + } + qboolean Update( void ); +/* void Respatialize( int entNum, const vec3_t origin ) + { + for + ( PendingSet::iterator itPending = mPending.begin() + ; itPending != mPending.end() + ; itPending++ + ){ + (*itPending).Respatialize( entNum, origin ); + } + }*/ +}; + +class MasterForceSet +{ +protected: + int mEntityNum; +// vec3_t mOrigin; + SndForceSet mSnd; + LoopForceSet mLoop; + +public: + void Add( ffHandle_t handle/*, int entNum, const vec3_t origin, float maxDistance, float minDistance*/ ) + { + mSnd.Add( handle/*, entNum, origin, maxDistance, minDistance*/ ); + } + void AddLoop( ffHandle_t handle/*, int entNum, const vec3_t origin, float maxDistance, float minDistance*/ ) + { + mLoop.Add( handle/*, entNum, origin, maxDistance, minDistance*/ ); + } +/* void Respatialize( int entNum, const vec3_t origin ) + { + memcpy( mOrigin, origin, sizeof(mOrigin) ); + mEntityNum = entNum; + mSnd.Respatialize( entNum, origin ); + mLoop.Respatialize( entNum, origin ); + } +*/ void Update( void ); +}; + +// +// =================================================================================== +// + +static MasterForceSet _MasterForceSet; + +void FF_AddForce( ffHandle_t ff/*, int entNum, const vec3_t origin, float maxDistance, float minDistance*/ ) +{ + _MasterForceSet.Add( ff/*, entNum, origin, maxDistance, minDistance*/ ); +} + +void FF_AddLoopingForce( ffHandle_t ff/*, int entNum, const vec3_t origin, float maxDistance, float minDistance*/ ) +{ + _MasterForceSet.AddLoop( ff/*, entNum, origin, maxDistance, minDistance*/ ); +} +/* +void FF_Respatialize( int entNum, const vec3_t origin ) +{ + _MasterForceSet.Respatialize( entNum, origin ); +} +*/ +void FF_Update( void ) +{ + _MasterForceSet.Update(); +} + +// +// =================================================================================== +// + +void MasterForceSet::Update() +{ + mSnd.Update(); + mLoop.Update(); +} + +////----------------- +/// LoopForce::Update +//--------------------- +// Starts/Stops/Updates looping forces. +// Call once per frame after all looping forces have been added and respatialized. +// +qboolean LoopForceSet::Update() +{ + ActiveSet::iterator itActive; + PendingSet::iterator itPending; + + // Sum effects + ActiveSet active; + for + ( itPending = mPending.begin() + ; itPending != mPending.end() + ; itPending++ + ){ + if ( (const_cast (*itPending)).Update() ) + { + active[ (*itPending).mHandle ] += const_cast (*itPending) ; + } + } + + // Stop and remove unreferenced effects + for + ( itActive = mActive.begin() + ; itActive != mActive.end() + ; //itActive++ + ){ + if ( active.find( (*itActive).first ) != active.end() ) + { + itActive++; + } + else + { + SndForce &sndForce = (*itActive).second; + FF_Stop( sndForce.mHandle ); + itActive = mActive.erase( itActive ); + } + } + + // Decide whether to start or update + for + ( itActive = active.begin() + ; itActive != active.end() + ; itActive++ + ){ + SndForce &sndForce = mActive[ (*itActive).first ]; + sndForce.mHandle = (*itActive).first; + if ( sndForce.mPlaying ) + { + // Just update it + +// if ( (*itActive).second.GetGain() != sndForce.GetGain() ) +// { +// gFFSystem.ChangeGain( sndForce.mHandle, sndForce.GetGain() ); +// } + } + else + { + // Update and start it + +// gFFSystem.ChangeGain( sndForce.mHandle, sndForce.GetGain() ); + FF_Play( sndForce.mHandle ); + sndForce.mPlaying = qtrue; + } + } + + mPending.clear(); + + return qtrue; +} + +////------------------- +/// SndForceSet::Update +//----------------------- +// +// +qboolean SndForceSet::Update() +{ + ActiveSet::iterator itActive; + PendingSet::iterator itPending; +/* + // Remove finished effects from active //and pending sets + for + ( itActive = mActive.begin() + ; itActive != mActive.end() + ; //itActive++ + ){ + if ( gFFSystem.IsPlaying( (*itActive).first ) ) + { + ++itActive; + } + else + { +#if( 0 ) + for + ( itPending = mPending.begin() + ; itPending != mPending.end() + ; itPending++ + ){ + if + ( (*itPending).mHandle == (*itActive).first + && (*itPending).mPlaying + ){ + itPending = mPending.erase( itPending ); + } + } +#endif + itActive = mActive.erase( itActive ); + } + } +*/ + // Sum effects + ActiveSet start; + for + ( itPending = mPending.begin() + ; itPending != mPending.end() + ; itPending++ + ){ + if ( (*itPending).Update() ) + { + start[ (*itPending).mHandle ] += const_cast (*itPending); + } + } + + // Decide whether to start ( no updating one-shots ) + for + ( itActive = start.begin() + ; itActive != start.end() + ; itActive++ + ){ +/* SndForce &sndForce = mActive[ (*itActive).first ]; + sndForce.mHandle = (*itActive).first; + if ( (*itActive).second.GetGain() >= sndForce.GetGain() ) + { + //gFFSystem.ChangeGain( sndForce.mHandle, sndForce.GetGain() ); + FF_Start( sndForce.mHandle ); + sndForce.mPlaying = qtrue; + } +*/ FF_Play( (*itActive).first ); + } + + mPending.clear(); + + return qfalse; +} + +void SndForce::operator += ( SndForce &other ) +{ + /* + float dist = other.GetRelativeDistance(); + + if ( dist < 1.f ) + { + float thisdist = GetRelativeDistance(); + + if ( thisdist < 1.f ) + { + if ( dist == 0.f || thisdist == 0.f ) + { + mOrigin[0] = 0.f; + mOrigin[1] = 0.f; + mOrigin[2] = 0.f; + } + else + { + // This is so shitty + mOrigin[0] *= dist; + mOrigin[1] *= dist; + mOrigin[2] *= dist; + } + } + else + { + memcpy( mOrigin, other.mOrigin, sizeof(mOrigin) ); + } + */ + + mRefs += other.mRefs; +// } +} + +#endif // _IMMERSION \ No newline at end of file diff --git a/code/ff/ff_snd.h b/code/ff/ff_snd.h new file mode 100644 index 0000000..c0cb1dd --- /dev/null +++ b/code/ff/ff_snd.h @@ -0,0 +1,11 @@ +#ifndef FF_SND_H +#define FF_SND_H + +#include "../ff/ff_public.h" + +void FF_AddForce( ffHandle_t ff/*, int entNum, const vec3_t origin, float maxDistance, float minDistance*/ ); +void FF_AddLoopingForce( ffHandle_t ff/*, int entNum, const vec3_t origin, float maxDistance, float minDistance*/ ); +//void FF_Respatialize( int entNum, const vec3_t origin ); +void FF_Update( void ); + +#endif // FF_SND_H \ No newline at end of file diff --git a/code/ff/ff_system.cpp b/code/ff/ff_system.cpp new file mode 100644 index 0000000..7e5e18e --- /dev/null +++ b/code/ff/ff_system.cpp @@ -0,0 +1,151 @@ +#include "common_headers.h" + +#ifdef _IMMERSION + +//#include "ff.h" +//#include "ff_ffset.h" +//#include "ff_compound.h" +//#include "ff_system.h" + +extern cvar_t *ff_developer; + +////-------------- +/// FFSystem::Init +//------------------ +// +// +qboolean FFSystem::Init( const char *channels ) +{ + // kludgy restart mechanism + typedef struct + { TNameTable name; + vector channel; + } TRestartInfo; + TRestartInfo restart; + + if ( mInitialized ) + { + restart.name.resize( mHandle.size(), "" ); + restart.channel.resize( mHandle.size(), FF_CHANNEL_MAX ); + + mChannel.GetRegisteredNames( restart.name ); + mHandle.GetFailedNames( restart.name ); + mHandle.GetChannels( restart.channel ); + + Shutdown(); + } + + mHandle.Init(); + + if ( mConfig.Init( "fffx/fffx.cfg" ) // Process config file + && mChannel.Init( mConfig, channels ) ) // Init devices + { + if ( restart.name.size() > 1 ) + { + for + ( int i = 1 + ; i < restart.name.size() + ; i++ + ){ // ignore leading device-specific set name -- (may be switching devices) + Register( mConfig.RightOfSet( restart.name[ i ].c_str() ), restart.channel[ i ] ); + } + } + else + ffShake = Register( "fffx/player/shake", FF_CHANNEL_BODY ); + + mInitialized = qtrue; + } + + return mInitialized; +} + +#ifdef FF_CONSOLECOMMAND + +void FFSystem::GetDisplayTokens( TNameTable &Tokens ) +{ + FFChannelSet::GetDisplayTokens( Tokens ); + if ( ff_developer->integer ) + { + Tokens.push_back( "effects" ); + } +} + +void FFSystem::Display( TNameTable &Unprocessed, TNameTable &Processed ) +{ + for + ( TNameTable::iterator itName = Unprocessed.begin() + ; itName != Unprocessed.end() + ; + ){ + if ( stricmp( "effects", (*itName).c_str() ) == 0 ) + { + if ( ff_developer->integer ) + { + Com_Printf( "[registered effects]\n" ); + + TNameTable EffectNames; + int total = 0; + Channel::Set &ffSet = mChannel.GetSets(); + + for + ( int i = 0 + ; i < ffSet.size() + ; i++ + ){ + char ProductName[ FF_MAX_PATH ]; + *ProductName = 0; + ffSet[ i ]->GetDevice()->GetProductName( ProductName, FF_MAX_PATH - 1 ); + Com_Printf( "%s...\n", ProductName ); + + EffectNames.clear(); + EffectNames.resize( mHandle.size(), "" ); + ffSet[ i ]->GetRegisteredNames( EffectNames ); + + for + ( int j = 1 + ; j < EffectNames.size() + ; j++ + ){ + if ( EffectNames[ j ].length() ) + Com_Printf( "%3d) \"%s\" channel=%d\n", total++, EffectNames[ j ].c_str(), mHandle[ j ].GetChannel() ); + } + } + + EffectNames.clear(); + EffectNames.resize( mHandle.size(), "" ); + + if ( mHandle.GetFailedNames( EffectNames ) ) + { + Com_Printf( "Failed Registrants...\n" ); + for + ( int j = 1 + ; j < EffectNames.size() + ; j++ + ){ + if ( EffectNames[ j ].length() ) + Com_Printf( "%3d) \"%s\" channel=%d\n", total++, EffectNames[ j ].c_str(), mHandle[ j ].GetChannel() ); + } + } + } + //else + //{ + // Com_Printf( "\"effects\" only available when ff_developer is set\n" ); + //} + + Processed.push_back( *itName ); + itName = Unprocessed.erase( itName ); + } + else + { + itName++; + } + } + + mChannel.Display( Unprocessed, Processed ); +} + +#endif // FF_CONSOLECOMMAND + +#endif // _IMMERSION + + diff --git a/code/ff/ff_system.h b/code/ff/ff_system.h new file mode 100644 index 0000000..73c24c4 --- /dev/null +++ b/code/ff/ff_system.h @@ -0,0 +1,117 @@ +#ifndef FF_SYSTEM_H +#define FF_SYSTEM_H + +//#include "ff_utils.h" +//#include "ff_compound.h" +//#include "ff_ffset.h" +//#include "ff_configparser.h" + +#include "ff_ConfigParser.h" +#include "ff_ChannelSet.h" +#include "ff_HandleTable.h" + +//===[FFSystem]=======================================================///////////// +// +// The main system for a single user with multiple channels for +// multiple simultaneous devices. All this is factored and 'classy' +// with the intent to make it more readable and easy to track bugs. +// +// That's the intent, at least. +// +//====================================================================///////////// + +class FFSystem +{ +public: + typedef FFConfigParser Config; + typedef FFChannelSet Channel; + typedef FFHandleTable Handle; +protected: + Config mConfig; + Channel mChannel; + Handle mHandle; + qboolean mInitialized; + ffHandle_t ffShake; +public: + qboolean Init( const char *channels ); + void Shutdown() + { + mInitialized = qfalse; + mHandle.clear(); + mChannel.clear(); + mConfig.Clear(); + } + ffHandle_t Register( const char *name, int channel, qboolean notfound = qtrue, qboolean create = qtrue ) + { + ffHandle_t result = FF_HANDLE_NULL; + if ( name && name[ 0 ] ) + { + ChannelCompound compound( channel ); + mChannel.Register( compound, name, create ); + result = mHandle.Convert( compound, name, notfound ); + } + return result; + } + qboolean StopAll() + { + return mChannel.StopAll(); + } + const char* GetName( ffHandle_t ff ) + { + return mHandle.GetName( ff ); + } + qboolean Stop( ffHandle_t ff ) + { + return mHandle[ ff ].Stop(); + } + qboolean Play( ffHandle_t ff ) + { + return mHandle[ ff ].Start(); + } + qboolean EnsurePlaying( ffHandle_t ff ) + { + return mHandle[ ff ].EnsurePlaying(); + } + qboolean Shake( int intensity, int duration, qboolean ensure = qtrue ) + { + ChannelCompound &Compound = mHandle[ ffShake ]; + Compound.ChangeDuration( duration ); + Compound.ChangeGain( intensity ); + return ensure + ? EnsurePlaying( ffShake ) + : Compound.Start() + ; + } + qboolean IsInitialized() { return mInitialized; } + qboolean IsPlaying( ffHandle_t ff ) + { + return mHandle[ ff ].IsPlaying(); + } + qboolean ChangeGain( ffHandle_t ff, DWORD gain ) + { + return mHandle[ ff ].ChangeGain( gain ); + } + + // + // Optional + // +// qboolean Lookup( set &result, const char *name ) +// { +// set effect; +// return +// mChannel.Lookup( effect, name ) +// && mHandle.Lookup( result, effect, name ); +// } + +#ifdef FF_ACCESSOR +// Channel& GetChannels() { return mChannel; } // for CMD_FF_Info + Handle& GetHandles() { return mHandle; } // for CMD_FF_Info +#endif + +#ifdef FF_CONSOLECOMMAND + void Display( TNameTable &Unprocessed, TNameTable &Processed ); + void GetDisplayTokens( TNameTable &Tokens ); +#endif +}; + +#endif // FF_SYSTEM_H \ No newline at end of file diff --git a/code/ff/ff_utils.cpp b/code/ff/ff_utils.cpp new file mode 100644 index 0000000..1cb87ce --- /dev/null +++ b/code/ff/ff_utils.cpp @@ -0,0 +1,105 @@ +#include "common_headers.h" + +#ifdef _IMMERSION + +//#include "ff_utils.h" + +extern cvar_t *ff_developer; + +// +// Didn't know about strrchr. This is slightly different anyway. +// +int _rcpos( const char* string, char c, int pos ) +{ + int length = strlen( string ); + length = ( pos >= 0 && pos < length ? pos : length ); + for ( int i = length - 1; i >= 0; i-- ) + if ( string[i] == c ) + return i; + return -1; +} + +void* LoadFile( const char *filename ) +{ + void *buffer; + + int length = FS_ReadFile( filename, &buffer ); + + return length != -1 ? buffer : NULL; +} + +const char *UncommonDirectory( const char *target, const char *comp ) +{ + const char *pos = target; + + for + ( int i = 0 + ; target[ i ] && comp[ i ] && target[ i ] == comp[ i ] + ; i++ + ){ + if ( target[ i ] == '/' ) + pos = target + i + 1; + } + + if ( !comp[ i ] && target[ i ] == '/' ) + pos = target + i + 1; + else + if ( !target[ i ] && comp[ i ] == '/' ) + pos = target + i; + + return pos; +} + +////------- +/// RightOf +//----------- +// +// +// Parameters: +// +// Returns: +// +const char* RightOf( const char *str, const char *str2 ) +{ + if ( !str || !str2 ) + return NULL; + + const char *s = str; + int len1 = strlen( str ); + int len2 = strlen( str2 ); + + if ( (len2) + && (len1 >= len2) + ){ + s = strstr( str, str2 ); + if ( s ) + { + if ( ((s == str) && (*(s + len2) == '/')) + || ((*(s - 1) == '/') && (*(s + len2) == '/')) + ){ + s += len2 + 1; + } + } + } + + return s ? s : str; +} + +#ifdef FF_PRINT + +void ConsoleParseError( const char *message, const char *line, int pos /*=0*/) +{ + if ( ff_developer && ff_developer->integer ) + { + Com_Printf( "Parse error: %s\n%s\n%*c\n", message, line, pos + 1, '^' ); + } +} + +qboolean FS_VerifyName( const char *src, const char *name, char *out, int maxlen ) +{ + return qtrue; +} + +#endif // FF_PRINT + +#endif // _IMMERSION \ No newline at end of file diff --git a/code/ff/ff_utils.h b/code/ff/ff_utils.h new file mode 100644 index 0000000..24fa14c --- /dev/null +++ b/code/ff/ff_utils.h @@ -0,0 +1,154 @@ +#ifndef FF_UTILS_H +#define FF_UTILS_H + +//#include "ff_public.h" + +template +inline Type Clamp( Type arg, Type min, Type max ) +{; + if ( arg <= min ) + return min; + else + if ( arg > max ) + return max; + return arg; +} + +template +inline Type Max( Type arg, Type arg2 ) +{ + if ( arg < arg2 ) + return arg2; + return arg; +} + +template +inline Type Min( Type arg, Type arg2 ) +{ + if ( arg > arg2 ) + return arg2; + return arg; +} + +template +inline Type InRange( Type arg, Type min, Type max, Type invalid ) +{ + if ( arg < min || arg > max ) + return invalid; + return arg; +} + +typedef vector TNameTable; + +int _rcpos( const char* string, char c, int pos = -1 ); +void* LoadFile( const char *filename ); +const char *UncommonDirectory( const char *target, const char *comp ); +const char* RightOf( const char *str, const char *str2 ); + +template< class Type > +void DeletePointer( Type &Pointer, const char *String = 0 ) +{ + if ( Pointer ) + { +#ifdef FF_PRINT + if ( String ) + Com_Printf( "%s\n", String ); +#endif + delete Pointer; + Pointer = NULL; + } +} + +#ifdef FF_PRINT +void ConsoleParseError( const char *message, const char *line, int pos = 0 ); +#endif + +qboolean FS_VerifyName( const char *src, const char *name, char *out, int maxlen = FF_MAX_PATH ); + +//===[multimapIterator]================================================///////////// +// +// Convenience class for iterating through a multimap. It's not actually +// all that convenient :( It's slightly more intuitive than the +// actual multimap iteration logic. +// +//====================================================================///////////// + +template< class T > +class multimapIterator +{ +protected: + T::iterator mIt; + T &mMap; + T::key_type mKey; +public: + multimapIterator( T &map, T::key_type key ) + : mMap( map ) + , mKey( key ) + { + mIt = mMap.find( mKey ); + } + multimapIterator& operator ++ () + { + if ( mIt != mMap.end() ) + { + mIt++; + if ( (*mIt).first != mKey ) + mIt = mMap.end(); + } + return *this; + } + qboolean operator != ( T::iterator it ) + { + return qboolean( mIt != it ); + } + qboolean operator == ( T::iterator it ) + { + return qboolean( mIt == it ); + } + T::iterator operator * () + { + return mIt; // must dereference twice to access first and second + } + T::iterator operator = ( T::iterator it ) + { + mIt = it; + return mIt; + } + operator qboolean () + { + return qboolean( mIt != mMap.end() ); + } +}; + +/* +template< class T > +class multimapIteratorIterator +{ +protected: + multimapIterator mIt; + +public: + multimapIteratorIterator( T &map ) + : mIt( map, map.begin() ) + { + } + multimapIteratorIterator& operator ++ () + { + for + ( T::iterator last = *mIt + ; mIt + ; last = mIt, ++mIt + ); + + mIt = ++last; + + return *this; + } + multimapIterator& operator * () + { + return mIt; + } +}; +*/ + +#endif // FF_UTILS_H \ No newline at end of file diff --git a/code/ff/vssver.scc b/code/ff/vssver.scc new file mode 100644 index 0000000..2b827f3 Binary files /dev/null and b/code/ff/vssver.scc differ diff --git a/code/game/AI_GalakMech.cpp b/code/game/AI_GalakMech.cpp index 2ffe827..8cb14e0 100644 --- a/code/game/AI_GalakMech.cpp +++ b/code/game/AI_GalakMech.cpp @@ -435,7 +435,7 @@ static void GM_CheckMoveState( void ) if ( ( NPCInfo->goalEntity != NPC->enemy ) && ( NPCInfo->goalEntity != NULL ) ) { //Did we make it? - if ( NAV_HitNavGoal( NPC->currentOrigin, NPC->mins, NPC->maxs, NPCInfo->goalEntity->currentOrigin, 16 ) || + if ( NAV_HitNavGoal( NPC->currentOrigin, NPC->mins, NPC->maxs, NPCInfo->goalEntity->currentOrigin, 16, qfalse ) || ( !Q3_TaskIDPending( NPC, TID_MOVE_NAV ) && enemyLOS && enemyDist <= 10000 ) ) {//either hit our navgoal or our navgoal was not a crucial (scripted) one (maybe a combat point) and we're scouting and found our enemy NPC_ReachedGoal(); diff --git a/code/game/AI_Grenadier.cpp b/code/game/AI_Grenadier.cpp index 1160501..2b377b0 100644 --- a/code/game/AI_Grenadier.cpp +++ b/code/game/AI_Grenadier.cpp @@ -13,6 +13,7 @@ extern void G_SoundOnEnt( gentity_t *ent, soundChannel_t channel, const char *so extern void NPC_TempLookTarget( gentity_t *self, int lookEntNum, int minLookTime, int maxLookTime ); extern qboolean G_ExpandPointToBBox( vec3_t point, const vec3_t mins, const vec3_t maxs, int ignore, int clipmask ); extern void NPC_AimAdjust( int change ); +extern qboolean FlyingCreature( gentity_t *ent ); extern CNavigator navigator; @@ -341,7 +342,7 @@ static void Grenadier_CheckMoveState( void ) if ( ( NPCInfo->goalEntity != NPC->enemy ) && ( NPCInfo->goalEntity != NULL ) ) { //Did we make it? - if ( NAV_HitNavGoal( NPC->currentOrigin, NPC->mins, NPC->maxs, NPCInfo->goalEntity->currentOrigin, 16 ) || + if ( NAV_HitNavGoal( NPC->currentOrigin, NPC->mins, NPC->maxs, NPCInfo->goalEntity->currentOrigin, 16, FlyingCreature( NPC ) ) || ( NPCInfo->squadState == SQUAD_SCOUT && enemyLOS && enemyDist <= 10000 ) ) { int newSquadState = SQUAD_STAND_AND_SHOOT; diff --git a/code/game/AI_Jedi.cpp b/code/game/AI_Jedi.cpp index 87739c4..fddf86e 100644 --- a/code/game/AI_Jedi.cpp +++ b/code/game/AI_Jedi.cpp @@ -138,7 +138,18 @@ void NPC_Jedi_PlayConfusionSound( gentity_t *self ) { if ( self->health > 0 ) { - G_AddVoiceEvent( self, Q_irand( EV_CONFUSE1, EV_CONFUSE2 ), 2000 ); + if ( self->client && ( self->client->NPC_class == CLASS_TAVION || self->client->NPC_class == CLASS_DESANN ) ) + { + G_AddVoiceEvent( self, Q_irand( EV_CONFUSE1, EV_CONFUSE3 ), 2000 ); + } + else if ( Q_irand( 0, 1 ) ) + { + G_AddVoiceEvent( self, Q_irand( EV_TAUNT1, EV_TAUNT3 ), 2000 ); + } + else + { + G_AddVoiceEvent( self, Q_irand( EV_GLOAT1, EV_GLOAT3 ), 2000 ); + } } } @@ -2976,9 +2987,11 @@ static void Jedi_FaceEnemy( qboolean doPitch ) CalcEntitySpot( NPC->enemy, SPOT_HEAD, enemy_eyes ); //Find the desired angles - if ( NPC->client->ps.legsAnim == BOTH_A2_STABBACK1 - || NPC->client->ps.legsAnim == BOTH_CROUCHATTACKBACK1 - || NPC->client->ps.legsAnim == BOTH_ATTACK_BACK ) + if ( !NPC->client->ps.saberInFlight + && (NPC->client->ps.legsAnim == BOTH_A2_STABBACK1 + || NPC->client->ps.legsAnim == BOTH_CROUCHATTACKBACK1 + || NPC->client->ps.legsAnim == BOTH_ATTACK_BACK) + ) {//point *away* GetAnglesForDirection( enemy_eyes, eyes, angles ); } @@ -5149,7 +5162,7 @@ static void Jedi_Attack( void ) } if ( NPC->client->NPC_class == CLASS_TAVION - || (NPC->client->NPC_class == CLASS_DESANN&&g_spskill->integer) ) + || (g_spskill->integer && ( NPC->client->NPC_class == CLASS_DESANN || NPCInfo->rank >= Q_irand( RANK_CREWMAN, RANK_CAPTAIN )))) {//Tavion will kick in force speed if the player does... if ( NPC->enemy && !NPC->enemy->s.number diff --git a/code/game/AI_Sniper.cpp b/code/game/AI_Sniper.cpp index 144c055..d58eb70 100644 --- a/code/game/AI_Sniper.cpp +++ b/code/game/AI_Sniper.cpp @@ -12,6 +12,7 @@ extern void G_AddVoiceEvent( gentity_t *self, int event, int speakDebounceTime ) extern void G_SoundOnEnt( gentity_t *ent, soundChannel_t channel, const char *soundPath ); extern void NPC_TempLookTarget( gentity_t *self, int lookEntNum, int minLookTime, int maxLookTime ); extern qboolean G_ExpandPointToBBox( vec3_t point, const vec3_t mins, const vec3_t maxs, int ignore, int clipmask ); +extern qboolean FlyingCreature( gentity_t *ent ); extern CNavigator navigator; @@ -345,7 +346,7 @@ static void Sniper_CheckMoveState( void ) if ( ( NPCInfo->goalEntity != NPC->enemy ) && ( NPCInfo->goalEntity != NULL ) ) { //Did we make it? - if ( NAV_HitNavGoal( NPC->currentOrigin, NPC->mins, NPC->maxs, NPCInfo->goalEntity->currentOrigin, 16 ) || + if ( NAV_HitNavGoal( NPC->currentOrigin, NPC->mins, NPC->maxs, NPCInfo->goalEntity->currentOrigin, 16, FlyingCreature( NPC ) ) || ( NPCInfo->squadState == SQUAD_SCOUT && enemyLOS && enemyDist <= 10000 ) ) { int newSquadState = SQUAD_STAND_AND_SHOOT; diff --git a/code/game/AI_Stormtrooper.cpp b/code/game/AI_Stormtrooper.cpp index 4d02fe5..44c4859 100644 --- a/code/game/AI_Stormtrooper.cpp +++ b/code/game/AI_Stormtrooper.cpp @@ -20,6 +20,7 @@ extern void NPC_CheckGetNewWeapon( void ); extern qboolean Q3_TaskIDPending( gentity_t *ent, taskID_t taskType ); extern int GetTime ( int lastTime ); extern void NPC_AimAdjust( int change ); +extern qboolean FlyingCreature( gentity_t *ent ); extern CNavigator navigator; extern cvar_t *d_asynchronousGroupAI; @@ -740,26 +741,29 @@ NPC_ST_InvestigateEvent static qboolean NPC_ST_InvestigateEvent( int eventID, bool extraSuspicious ) { //If they've given themselves away, just take them as an enemy - if ( level.alertEvents[eventID].level == AEL_DISCOVERED && (NPCInfo->scriptFlags&SCF_LOOK_FOR_ENEMIES) ) + if ( NPCInfo->confusionTime < level.time ) { - NPCInfo->lastAlertID = level.alertEvents[eventID].ID; - if ( !level.alertEvents[eventID].owner || - !level.alertEvents[eventID].owner->client || - level.alertEvents[eventID].owner->health <= 0 || - level.alertEvents[eventID].owner->client->playerTeam != NPC->client->enemyTeam ) - {//not an enemy - return qfalse; + if ( level.alertEvents[eventID].level == AEL_DISCOVERED && (NPCInfo->scriptFlags&SCF_LOOK_FOR_ENEMIES) ) + { + NPCInfo->lastAlertID = level.alertEvents[eventID].ID; + if ( !level.alertEvents[eventID].owner || + !level.alertEvents[eventID].owner->client || + level.alertEvents[eventID].owner->health <= 0 || + level.alertEvents[eventID].owner->client->playerTeam != NPC->client->enemyTeam ) + {//not an enemy + return qfalse; + } + //FIXME: what if can't actually see enemy, don't know where he is... should we make them just become very alert and start looking for him? Or just let combat AI handle this... (act as if you lost him) + //ST_Speech( NPC, SPEECH_CHARGE, 0 ); + G_SetEnemy( NPC, level.alertEvents[eventID].owner ); + NPCInfo->enemyLastSeenTime = level.time; + TIMER_Set( NPC, "attackDelay", Q_irand( 500, 2500 ) ); + if ( level.alertEvents[eventID].type == AET_SOUND ) + {//heard him, didn't see him, stick for a bit + TIMER_Set( NPC, "roamTime", Q_irand( 500, 2500 ) ); + } + return qtrue; } - //FIXME: what if can't actually see enemy, don't know where he is... should we make them just become very alert and start looking for him? Or just let combat AI handle this... (act as if you lost him) - //ST_Speech( NPC, SPEECH_CHARGE, 0 ); - G_SetEnemy( NPC, level.alertEvents[eventID].owner ); - NPCInfo->enemyLastSeenTime = level.time; - TIMER_Set( NPC, "attackDelay", Q_irand( 500, 2500 ) ); - if ( level.alertEvents[eventID].type == AET_SOUND ) - {//heard him, didn't see him, stick for a bit - TIMER_Set( NPC, "roamTime", Q_irand( 500, 2500 ) ); - } - return qtrue; } //don't look at the same alert twice @@ -956,30 +960,42 @@ void NPC_BSST_Investigate( void ) WeaponThink( qtrue ); } - //Look for an enemy - if ( NPC_CheckPlayerTeamStealth() ) + if ( NPCInfo->confusionTime < level.time ) { - //NPCInfo->behaviorState = BS_HUNT_AND_KILL;//should be auto now - ST_Speech( NPC, SPEECH_DETECTED, 0 ); - NPCInfo->tempBehavior = BS_DEFAULT; - NPC_UpdateAngles( qtrue, qtrue ); - return; + if ( NPCInfo->scriptFlags&SCF_LOOK_FOR_ENEMIES ) + { + //Look for an enemy + if ( NPC_CheckPlayerTeamStealth() ) + { + //NPCInfo->behaviorState = BS_HUNT_AND_KILL;//should be auto now + ST_Speech( NPC, SPEECH_DETECTED, 0 ); + NPCInfo->tempBehavior = BS_DEFAULT; + NPC_UpdateAngles( qtrue, qtrue ); + return; + } + } } - int alertEvent = NPC_CheckAlertEvents( qtrue, qtrue, NPCInfo->lastAlertID ); - - //There is an event to look at - if ( alertEvent >= 0 ) + if ( !(NPCInfo->scriptFlags&SCF_IGNORE_ALERTS) ) { - if ( NPC_CheckForDanger( alertEvent ) ) - {//running like hell - ST_Speech( NPC, SPEECH_COVER, 0 );//FIXME: flee sound? - return; - } + int alertEvent = NPC_CheckAlertEvents( qtrue, qtrue, NPCInfo->lastAlertID ); - if ( level.alertEvents[alertEvent].ID != NPCInfo->lastAlertID ) + //There is an event to look at + if ( alertEvent >= 0 ) { - NPC_ST_InvestigateEvent( alertEvent, qtrue ); + if ( NPCInfo->confusionTime < level.time ) + { + if ( NPC_CheckForDanger( alertEvent ) ) + {//running like hell + ST_Speech( NPC, SPEECH_COVER, 0 );//FIXME: flee sound? + return; + } + } + + if ( level.alertEvents[alertEvent].ID != NPCInfo->lastAlertID ) + { + NPC_ST_InvestigateEvent( alertEvent, qtrue ); + } } } @@ -998,10 +1014,10 @@ void NPC_BSST_Investigate( void ) //FIXME: else, look for new alerts //See if we're searching for the noise's origin - if ( NPCInfo->localState == LSTATE_INVESTIGATE ) + if ( NPCInfo->localState == LSTATE_INVESTIGATE && (NPCInfo->goalEntity!=NULL) ) { //See if we're there - if ( NAV_HitNavGoal( NPC->currentOrigin, NPC->mins, NPC->maxs, NPCInfo->goalEntity->currentOrigin, 32 ) == qfalse ) + if ( NAV_HitNavGoal( NPC->currentOrigin, NPC->mins, NPC->maxs, NPCInfo->goalEntity->currentOrigin, 32, FlyingCreature( NPC ) ) == qfalse ) { ucmd.buttons |= BUTTON_WALKING; @@ -1052,19 +1068,19 @@ void NPC_BSST_Patrol( void ) return; } } + } - if ( !(NPCInfo->scriptFlags&SCF_IGNORE_ALERTS) ) + if ( !(NPCInfo->scriptFlags&SCF_IGNORE_ALERTS) ) + { + int alertEvent = NPC_CheckAlertEvents( qtrue, qtrue ); + + //There is an event to look at + if ( alertEvent >= 0 ) { - int alertEvent = NPC_CheckAlertEvents( qtrue, qtrue ); - - //There is an event to look at - if ( alertEvent >= 0 ) - { - if ( NPC_ST_InvestigateEvent( alertEvent, qfalse ) ) - {//actually going to investigate it - NPC_UpdateAngles( qtrue, qtrue ); - return; - } + if ( NPC_ST_InvestigateEvent( alertEvent, qfalse ) ) + {//actually going to investigate it + NPC_UpdateAngles( qtrue, qtrue ); + return; } } } @@ -1277,7 +1293,7 @@ static void ST_CheckMoveState( void ) if ( ( NPCInfo->goalEntity != NPC->enemy ) && ( NPCInfo->goalEntity != NULL ) ) { //Did we make it? - if ( NAV_HitNavGoal( NPC->currentOrigin, NPC->mins, NPC->maxs, NPCInfo->goalEntity->currentOrigin, 16 ) || + if ( NAV_HitNavGoal( NPC->currentOrigin, NPC->mins, NPC->maxs, NPCInfo->goalEntity->currentOrigin, 16, FlyingCreature( NPC ) ) || ( !Q3_TaskIDPending( NPC, TID_MOVE_NAV ) && NPCInfo->squadState == SQUAD_SCOUT && enemyLOS && enemyDist <= 10000 ) ) {//either hit our navgoal or our navgoal was not a crucial (scripted) one (maybe a combat point) and we're scouting and found our enemy int newSquadState = SQUAD_STAND_AND_SHOOT; diff --git a/code/game/NPC.cpp b/code/game/NPC.cpp index 193d273..341c444 100644 --- a/code/game/NPC.cpp +++ b/code/game/NPC.cpp @@ -50,9 +50,9 @@ cvar_t *d_JediAI; cvar_t *d_noGroupAI; cvar_t *d_asynchronousGroupAI; cvar_t *d_altRoutes; +cvar_t *d_patched; cvar_t *d_slowmodeath; -extern int eventClearTime; extern qboolean stop_icarus; gentity_t *NPC; @@ -65,6 +65,8 @@ void NPC_SetAnim(gentity_t *ent,int type,int anim,int priority); void pitch_roll_for_slope( gentity_t *forwhom, vec3_t pass_slope ); extern void GM_Dying( gentity_t *self ); +extern int eventClearTime; + void CorpsePhysics( gentity_t *self ) { // run the bot through the server like it was a real client @@ -93,7 +95,7 @@ void CorpsePhysics( gentity_t *self ) if ( level.time - self->s.time > 3000 ) {//been dead for 3 seconds - if ( g_dismemberment->integer < 4 && !g_saberRealisticCombat->integer ) + if ( g_dismemberment->integer < 11381138 && !g_saberRealisticCombat->integer ) {//can't be dismembered once dead if ( self->client->NPC_class != CLASS_PROTOCOL ) { @@ -1060,7 +1062,13 @@ void NPC_HandleAIFlags (void) NPCInfo->ffireFadeDebounce = level.time + 3000; } } - + if ( d_patched->integer ) + {//use patch-style navigation + if ( NPCInfo->consecutiveBlockedMoves > 20 ) + {//been stuck for a while, try again? + NPCInfo->consecutiveBlockedMoves = 0; + } + } } void NPC_AvoidWallsAndCliffs (void) @@ -2181,6 +2189,7 @@ void NPC_InitAI ( void ) d_noGroupAI = gi.cvar ( "d_noGroupAI", "0", CVAR_CHEAT ); d_asynchronousGroupAI = gi.cvar ( "d_asynchronousGroupAI", "1", CVAR_CHEAT ); d_altRoutes = gi.cvar ( "d_altRoutes", "1", CVAR_CHEAT ); + d_patched = gi.cvar ( "d_patched", "1", CVAR_CHEAT ); //0 = never (BORING) //1 = kyle only diff --git a/code/game/NPC_behavior.cpp b/code/game/NPC_behavior.cpp index e6d7451..0d42178 100644 --- a/code/game/NPC_behavior.cpp +++ b/code/game/NPC_behavior.cpp @@ -577,6 +577,7 @@ void NPC_BSFollowLeader (void) { if ( NPC->client->leader && NPC->client->leader->enemy + && NPC->client->leader->enemy != NPC && ( (NPC->client->leader->enemy->client&&NPC->client->leader->enemy->client->playerTeam==NPC->client->enemyTeam) ||(NPC->client->leader->enemy->svFlags&SVF_NONNPC_ENEMY&&NPC->client->leader->enemy->noDamageTeam==NPC->client->enemyTeam) ) && NPC->client->leader->enemy->health > 0 ) diff --git a/code/game/NPC_combat.cpp b/code/game/NPC_combat.cpp index 19b4c40..643dd00 100644 --- a/code/game/NPC_combat.cpp +++ b/code/game/NPC_combat.cpp @@ -53,7 +53,7 @@ NPC_AngerAlert #define ANGER_ALERT_RADIUS 512 #define ANGER_ALERT_SOUND_RADIUS 256 -static void G_AngerAlert( gentity_t *self ) +void G_AngerAlert( gentity_t *self ) { if ( self && self->NPC && (self->NPC->scriptFlags&SCF_NO_GROUPS) ) {//I'm not a team playa... @@ -451,7 +451,10 @@ void G_SetEnemy( gentity_t *self, gentity_t *enemy ) //Alert anyone else in the area if ( Q_stricmp( "desperado", self->NPC_type ) != 0 && Q_stricmp( "paladin", self->NPC_type ) != 0 ) {//special holodeck enemies exception - G_AngerAlert( self ); + if ( !(self->client->ps.eFlags&EF_FORCE_GRIPPED) ) + {//gripped people can't call for help + G_AngerAlert( self ); + } } //Stormtroopers don't fire right away! @@ -1348,6 +1351,9 @@ qboolean ValidEnemy(gentity_t *ent) if ( ent == NULL ) return qfalse; + if ( ent == NPC ) + return qfalse; + //if team_free, maybe everyone is an enemy? if ( !NPC->client->enemyTeam ) return qfalse; @@ -1577,7 +1583,7 @@ gentity_t *NPC_PickEnemy( gentity_t *closestTo, int enemyTeam, qboolean checkVis { newenemy = &g_entities[entNum]; - if ( (newenemy->client || newenemy->svFlags & SVF_NONNPC_ENEMY) && !(newenemy->flags & FL_NOTARGET) && !(newenemy->s.eFlags & EF_NODRAW)) + if ( newenemy != NPC && (newenemy->client || newenemy->svFlags & SVF_NONNPC_ENEMY) && !(newenemy->flags & FL_NOTARGET) && !(newenemy->s.eFlags & EF_NODRAW)) { if ( newenemy->health > 0 ) { @@ -2880,6 +2886,7 @@ gentity_t *NPC_SearchForWeapons( void ) found=&g_entities[i]; + //FIXME: Also look for ammo_racks that have weapons on them? if ( found->s.eType != ET_ITEM ) { continue; diff --git a/code/game/NPC_goal.cpp b/code/game/NPC_goal.cpp index 1365c26..2591c4e 100644 --- a/code/game/NPC_goal.cpp +++ b/code/game/NPC_goal.cpp @@ -8,6 +8,7 @@ #include "b_local.h" #include "Q3_Interface.h" +extern qboolean FlyingCreature( gentity_t *ent ); /* SetGoal */ @@ -137,7 +138,7 @@ ReachedGoal id removed checks against waypoints and is now checking surfaces */ -//qboolean NAV_HitNavGoal( vec3_t point, vec3_t mins, vec3_t maxs, gentity_t *goal ); +//qboolean NAV_HitNavGoal( vec3_t point, vec3_t mins, vec3_t maxs, gentity_t *goal, qboolean flying ); qboolean ReachedGoal( gentity_t *goal ) { //FIXME: For script waypoints, need a special check @@ -149,7 +150,7 @@ qboolean ReachedGoal( gentity_t *goal ) if ( goal->svFlags & SVF_NAVGOAL ) {//waypoint_navgoal - return NAV_HitNavGoal( NPC->currentOrigin, NPC->mins, NPC->maxs, goal ); + return NAV_HitNavGoal( NPC->currentOrigin, NPC->mins, NPC->maxs, goal, FlyingCreature( NPC ) ); } if ( goal == NPCInfo->tempGoal && !(goal->svFlags & SVF_NAVGOAL)) @@ -232,7 +233,7 @@ qboolean ReachedGoal( gentity_t *goal ) } } */ - return NAV_HitNavGoal( NPC->currentOrigin, NPC->mins, NPC->maxs, goal->currentOrigin, NPCInfo->goalRadius ); + return NAV_HitNavGoal( NPC->currentOrigin, NPC->mins, NPC->maxs, goal->currentOrigin, NPCInfo->goalRadius, FlyingCreature( NPC ) ); } /* diff --git a/code/game/NPC_move.cpp b/code/game/NPC_move.cpp index ec1211a..d805c0d 100644 --- a/code/game/NPC_move.cpp +++ b/code/game/NPC_move.cpp @@ -64,7 +64,7 @@ qboolean NPC_ClearPathToGoal( vec3_t dir, gentity_t *goal ) if ( goal->svFlags & SVF_NAVGOAL ) { //Okay, didn't get all the way there, let's see if we got close enough: - if ( NAV_HitNavGoal( trace.endpos, NPC->mins, NPC->maxs, goal->currentOrigin, NPCInfo->goalRadius ) ) + if ( NAV_HitNavGoal( trace.endpos, NPC->mins, NPC->maxs, goal->currentOrigin, NPCInfo->goalRadius, FlyingCreature( NPC ) ) ) { //VectorSubtract(goal->currentOrigin, NPC->currentOrigin, dir); return qtrue; @@ -292,7 +292,7 @@ qboolean NPC_GetMoveDirectionAltRoute( vec3_t out, float *distance, qboolean try memcpy( &tempInfo, &frameNavInfo, sizeof( tempInfo ) ); if ( NAVNEW_AvoidCollision( NPC, NPCInfo->goalEntity, tempInfo, qtrue, 5 ) == qfalse ) {//revert to macro nav - //Can't get straight to goal, deump tempInfo and use macro nav + //Can't get straight to goal, dump tempInfo and use macro nav if ( NAVNEW_MoveToGoal( NPC, frameNavInfo ) == WAYPOINT_NONE ) { //Can't reach goal, just face diff --git a/code/game/NPC_reactions.cpp b/code/game/NPC_reactions.cpp index 702a8f1..c1da586 100644 --- a/code/game/NPC_reactions.cpp +++ b/code/game/NPC_reactions.cpp @@ -15,12 +15,6 @@ extern qboolean G_CheckForStrongAttackMomentum( gentity_t *self ); extern void G_AddVoiceEvent( gentity_t *self, int event, int speakDebounceTime ); extern void G_SoundOnEnt( gentity_t *ent, soundChannel_t channel, const char *soundPath ); -float g_crosshairEntDist = Q3_INFINITE; -int g_crosshairSameEntTime = 0; -int g_crosshairEntNum = ENTITYNUM_NONE; -int g_crosshairEntTime = 0; -extern int teamLastEnemyTime[]; -extern cvar_t *g_spskill; extern int PM_AnimLength( int index, animNumber_t anim ); extern void cgi_S_StartSound( vec3_t origin, int entityNum, int entchannel, sfxHandle_t sfx ); extern qboolean Q3_TaskIDPending( gentity_t *ent, taskID_t taskType ); @@ -39,7 +33,15 @@ extern qboolean PM_FlippingAnim( int anim ); extern qboolean PM_RollingAnim( int anim ); extern qboolean PM_InCartwheel( int anim ); +extern cvar_t *g_spskill; +extern int teamLastEnemyTime[]; extern qboolean stop_icarus; +extern int killPlayerTimer; + +float g_crosshairEntDist = Q3_INFINITE; +int g_crosshairSameEntTime = 0; +int g_crosshairEntNum = ENTITYNUM_NONE; +int g_crosshairEntTime = 0; /* ------------------------- NPC_CheckAttacker @@ -56,6 +58,9 @@ static void NPC_CheckAttacker( gentity_t *other, int mod ) if ( !other ) return; + if ( other == NPC ) + return; + if ( !other->inuse ) return; @@ -365,7 +370,10 @@ void NPC_Pain( gentity_t *self, gentity_t *inflictor, gentity_t *other, vec3_t p // } } - if ( self->client->playerTeam && other->client && otherTeam == self->client->playerTeam && (!player->client->ps.viewEntity || other->s.number != player->client->ps.viewEntity)) + if ( self->client->playerTeam + && other->client + && otherTeam == self->client->playerTeam + && (!player->client->ps.viewEntity || other->s.number != player->client->ps.viewEntity)) {//hit by a teammate if ( other != self->enemy && self != other->enemy ) {//we weren't already enemies @@ -402,7 +410,11 @@ void NPC_Pain( gentity_t *self, gentity_t *inflictor, gentity_t *other, vec3_t p } else if ( self->NPC && !other->s.number )//should be assumed, but... {//dammit, stop that! - if ( self->NPC->ffireCount < 3+((2-g_spskill->integer)*2) ) + if ( self->NPC->charmedTime ) + {//mindtricked + return; + } + else if ( self->NPC->ffireCount < 3+((2-g_spskill->integer)*2) ) {//not mad enough yet //Com_Printf( "chck: %d < %d\n", self->NPC->ffireCount, 3+((2-g_spskill->integer)*2) ); if ( damage != -1 ) @@ -436,6 +448,10 @@ void NPC_Pain( gentity_t *self, gentity_t *inflictor, gentity_t *other, vec3_t p self->NPC->scriptFlags |= (SCF_CHASE_ENEMIES|SCF_NO_MIND_TRICK); //NOTE: we also stop ICARUS altogether stop_icarus = qtrue; + if ( !killPlayerTimer ) + { + killPlayerTimer = level.time + 10000; + } } } } @@ -454,14 +470,14 @@ void NPC_Pain( gentity_t *self, gentity_t *inflictor, gentity_t *other, vec3_t p NPC_ChoosePainAnimation( self, other, point, damage, mod, hitLoc, voiceEvent ); } //Check to take a new enemy - if ( NPC->enemy != other ) + if ( NPC->enemy != other && NPC != other ) {//not already mad at them NPC_CheckAttacker( other, mod ); } } //Attempt to run any pain instructions - if(self->client && self->NPC) + if ( self->client && self->NPC ) { //FIXME: This needs better heuristics perhaps if(self->health <= (self->max_health/3) && G_ActivateBehavior(self, BSET_FLEE) ) diff --git a/code/game/NPC_senses.cpp b/code/game/NPC_senses.cpp index 90be281..438e53a 100644 --- a/code/game/NPC_senses.cpp +++ b/code/game/NPC_senses.cpp @@ -11,6 +11,7 @@ #include #endif +extern int eventClearTime; /* qboolean G_ClearLineOfSight(const vec3_t point1, const vec3_t point2, int ignore, int clipmask) @@ -691,6 +692,11 @@ void ClearPlayerAlertEvents( void ) } //make sure this never drops below zero... if it does, something very very bad happened assert( level.numAlertEvents >= 0 ); + + if ( eventClearTime < level.time ) + {//this is just a 200ms debouncer so things that generate constant alerts (like corpses and missiles) add an alert every 200 ms + eventClearTime = level.time + ALERT_CLEAR_TIME; + } } qboolean RemoveOldestAlert( void ) diff --git a/code/game/NPC_spawn.cpp b/code/game/NPC_spawn.cpp index 0ea4482..786921d 100644 --- a/code/game/NPC_spawn.cpp +++ b/code/game/NPC_spawn.cpp @@ -57,10 +57,10 @@ extern void NPC_Mark2_Precache(void); extern void NPC_GalakMech_Precache( void ); extern void NPC_GalakMech_Init( gentity_t *ent ); extern void NPC_Protocol_Precache( void ); +extern int WP_SetSaberModel( gclient_t *client, class_t npcClass ); #define NSF_DROP_TO_FLOOR 16 -extern gitem_t *FindItemForAmmo( ammo_t ammo ); //void HirogenAlpha_Precache( void ); @@ -1723,6 +1723,8 @@ void SP_NPC_Kyle( gentity_t *self) { self->NPC_type = "Kyle"; + WP_SetSaberModel( NULL, CLASS_KYLE ); + SP_NPC_spawner( self ); } @@ -1765,6 +1767,8 @@ void SP_NPC_Luke( gentity_t *self) { self->NPC_type = "Luke"; + WP_SetSaberModel( NULL, CLASS_LUKE ); + SP_NPC_spawner( self ); } @@ -1793,6 +1797,8 @@ void SP_NPC_Tavion( gentity_t *self) { self->NPC_type = "Tavion"; + WP_SetSaberModel( NULL, CLASS_TAVION ); + SP_NPC_spawner( self ); } @@ -1845,6 +1851,8 @@ void SP_NPC_Desann( gentity_t *self) { self->NPC_type = "Desann"; + WP_SetSaberModel( NULL, CLASS_DESANN ); + SP_NPC_spawner( self ); } @@ -1917,6 +1925,7 @@ void SP_NPC_Jedi( gentity_t *self) } } + WP_SetSaberModel( NULL, CLASS_JEDI ); SP_NPC_spawner( self ); } @@ -2345,6 +2354,7 @@ void SP_NPC_Reborn( gentity_t *self) } } + WP_SetSaberModel( NULL, CLASS_REBORN ); SP_NPC_spawner( self ); } @@ -2370,6 +2380,7 @@ void SP_NPC_ShadowTrooper( gentity_t *self) } NPC_ShadowTrooper_Precache(); + WP_SetSaberModel( NULL, CLASS_SHADOWTROOPER ); SP_NPC_spawner( self ); } diff --git a/code/game/NPC_stats.cpp b/code/game/NPC_stats.cpp index 8110e3e..0e4f560 100644 --- a/code/game/NPC_stats.cpp +++ b/code/game/NPC_stats.cpp @@ -312,6 +312,35 @@ extern void CG_RegisterNPCCustomSounds( clientInfo_t *ci ); extern void CG_RegisterNPCEffects( team_t team ); extern void CG_ParseAnimationSndFile( const char *filename, int animFileIndex ); +//#define CONVENIENT_ANIMATION_FILE_DEBUG_THING + +#ifdef CONVENIENT_ANIMATION_FILE_DEBUG_THING +void SpewDebugStuffToFile(animation_t *bgGlobalAnimations) +{ + char BGPAFtext[40000]; + fileHandle_t f; + int i = 0; + + gi.FS_FOpenFile("file_of_debug_stuff_SP.txt", &f, FS_WRITE); + + if (!f) + { + return; + } + + BGPAFtext[0] = 0; + + while (i < MAX_ANIMATIONS) + { + strcat(BGPAFtext, va("%i %i\n", i, bgGlobalAnimations[i].frameLerp)); + i++; + } + + gi.FS_Write(BGPAFtext, strlen(BGPAFtext), f); + gi.FS_FCloseFile(f); +} +#endif + /* ====================== CG_ParseAnimationFile @@ -428,6 +457,13 @@ qboolean G_ParseAnimationFile( const char *af_filename ) animations[animNum].initialLerp = ceil(1000.0f / fabs(fps)); } +#ifdef CONVENIENT_ANIMATION_FILE_DEBUG_THING + if (strstr(af_filename, "humanoid")) + { + SpewDebugStuffToFile(animations); + } +#endif + return qtrue; } diff --git a/code/game/NPC_utils.cpp b/code/game/NPC_utils.cpp index d196ffe..5fea42d 100644 --- a/code/game/NPC_utils.cpp +++ b/code/game/NPC_utils.cpp @@ -237,8 +237,7 @@ qboolean NPC_UpdateAngles ( qboolean doPitch, qboolean doYaw ) yawSpeed = NPCInfo->stats.yawSpeed; } - if ( (NPC->client->NPC_class == CLASS_TAVION||NPC->client->NPC_class == CLASS_DESANN) - && NPC->client->ps.forcePowersActive&(1<s.weapon == WP_SABER && NPC->client->ps.forcePowersActive&(1<value; } @@ -917,6 +916,10 @@ qboolean NPC_ValidEnemy( gentity_t *ent ) if ( ent == NULL ) return qfalse; + //Must not be me + if ( ent == NPC ) + return qfalse; + //Must not be deleted if ( ent->inuse == qfalse ) return qfalse; diff --git a/code/game/Q3_Interface.cpp b/code/game/Q3_Interface.cpp index e6234b0..4530f33 100644 --- a/code/game/Q3_Interface.cpp +++ b/code/game/Q3_Interface.cpp @@ -112,7 +112,7 @@ stringID_table_t WPTable[] = "NULL",WP_NONE, ENUM2STRING(WP_NONE), // Player weapons - ENUM2STRING(WP_SABER), + ENUM2STRING(WP_SABER), // NOTE: lots of code assumes this is the first weapon (... which is crap) so be careful -Ste. ENUM2STRING(WP_BRYAR_PISTOL), ENUM2STRING(WP_BLASTER), ENUM2STRING(WP_DISRUPTOR), @@ -125,15 +125,17 @@ stringID_table_t WPTable[] = ENUM2STRING(WP_TRIP_MINE), ENUM2STRING(WP_DET_PACK), ENUM2STRING(WP_STUN_BATON), - // NPC enemy weapons - ENUM2STRING(WP_BOT_LASER), // Probe droid - Laser blast + //NOTE: player can only have up to 16 weapons), anything after that is enemy only ENUM2STRING(WP_MELEE), // Any ol' melee attack - ENUM2STRING(WP_TURRET), // turret guns + // NPC enemy weapons ENUM2STRING(WP_EMPLACED_GUN), + ENUM2STRING(WP_BOT_LASER), // Probe droid - Laser blast + ENUM2STRING(WP_TURRET), // turret guns ENUM2STRING(WP_ATST_MAIN), ENUM2STRING(WP_ATST_SIDE), ENUM2STRING(WP_TIE_FIGHTER), ENUM2STRING(WP_RAPID_FIRE_CONC), + ENUM2STRING(WP_BLASTER_PISTOL), // apparently some enemy only version of the blaster "", NULL }; @@ -753,17 +755,16 @@ static void Q3_SetObjective(const char *ObjEnum, int status) Q3_SetMissionFailed ------------------------- */ +extern void G_PlayerGuiltDeath( void ); static void Q3_SetMissionFailed(const char *TextEnum) { gentity_t *ent = &g_entities[0]; - ent->health = 0; - if ( ent->playerModel >= 0 && ent->ghoul2.size() ) - {// don't let 'em animate - gi.G2API_PauseBoneAnimIndex( &ent->ghoul2[ent->playerModel], ent->rootBone, cg.time ); - gi.G2API_PauseBoneAnimIndex( &ent->ghoul2[ent->playerModel], ent->motionBone, cg.time ); - gi.G2API_PauseBoneAnimIndex( &ent->ghoul2[ent->playerModel], ent->lowerLumbarBone, cg.time ); + if ( ent->health >= 0 ) + { + G_PlayerGuiltDeath(); } + ent->health = 0; //FIXME: what about other NPCs? Scripts? // statusTextIndex is looked at on the client side. @@ -3197,7 +3198,14 @@ void Q3_SetLoopSound(int entID, const char *name) return; } - index = G_SoundIndex( name ); + if ( self->s.eType == ET_MOVER ) + { + index = cgi_S_RegisterSound( name ); + } + else + { + index = G_SoundIndex( name ); + } if (index) { diff --git a/code/game/Q3_Interface.h b/code/game/Q3_Interface.h index 7e65d2e..c03d2eb 100644 --- a/code/game/Q3_Interface.h +++ b/code/game/Q3_Interface.h @@ -74,7 +74,7 @@ typedef enum //# setType_e SET_LOCKYAW,//## %s="off" # Lock legs to a certain yaw angle (or "off" or "auto" uses current) SET_FULLNAME,//## %s="NULL" # This name will appear when ent is scanned by tricorder SET_VIEWENTITY,//## %s="NULL" # Make the player look through this ent's eyes - also shunts player movement control to this ent - SET_LOOPSOUND,//## %s="NULL" # Looping sound to play on entity + SET_LOOPSOUND,//## %s="FILENAME" !!"W:\game\base\!!#sound\*.*" # Looping sound to play on entity SET_ICARUS_FREEZE,//## %s="NULL" # Specify name of entity to freeze - !!!NOTE!!! since the ent is frozen, it cannot unfreeze itself, you must have some other entity unfreeze a frozen ent!!! SET_ICARUS_UNFREEZE,//## %s="NULL" # Specify name of entity to unfreeze - !!!NOTE!!! since the ent is frozen, it cannot unfreeze itself, you must have some other entity unfreeze a frozen ent!!! diff --git a/code/game/b_local.h b/code/game/b_local.h index c9403c8..0d636a3 100644 --- a/code/game/b_local.h +++ b/code/game/b_local.h @@ -302,7 +302,7 @@ extern int NPC_FindSquadPoint( vec3_t position ); extern void ClearPlayerAlertEvents( void ); extern qboolean G_BoundsOverlap(const vec3_t mins1, const vec3_t maxs1, const vec3_t mins2, const vec3_t maxs2); -extern qboolean NAV_HitNavGoal( vec3_t point, vec3_t mins, vec3_t maxs, vec3_t dest, int radius ); +extern qboolean NAV_HitNavGoal( vec3_t point, vec3_t mins, vec3_t maxs, vec3_t dest, int radius, qboolean flying ); extern void NPC_SetMoveGoal( gentity_t *ent, vec3_t point, int radius, qboolean isNavGoal = qfalse, int combatPoint = -1, gentity_t *targetEnt = NULL ); diff --git a/code/game/bg_panimate.cpp b/code/game/bg_panimate.cpp index 66de564..4e07771 100644 --- a/code/game/bg_panimate.cpp +++ b/code/game/bg_panimate.cpp @@ -720,7 +720,7 @@ int PM_BrokenParryForAttack( int move ) return LS_V1_TR; break; case Q_T: - return LS_V1_B_; + return LS_V1_T_; break; case Q_TL: return LS_V1_TL; @@ -1142,6 +1142,7 @@ int PM_AttackForEnemyPos( qboolean allowFB ) && pm->ps->forcePowerLevel[FP_LEVITATION] > FORCE_LEVEL_1 //can force jump && !(pm->gent->flags&FL_LOCK_PLAYER_WEAPONS) // yes this locked weapons check also includes force powers, if we need a separate check later I'll make one && (pm->ps->groundEntityNum != ENTITYNUM_NONE||level.time-pm->ps->lastOnGround<=500) //on ground or just jumped + && ( pm->ps->clientNum || pm->ps->legsAnim == BOTH_JUMP1 || pm->ps->legsAnim == BOTH_FORCEJUMP1 || pm->ps->legsAnim == BOTH_INAIR1 || pm->ps->legsAnim == BOTH_FORCEINAIR1 )//either an NPC or in a non-flip forward jump && ( (pm->ps->clientNum&&!PM_ControlledByPlayer()&&!Q_irand(0,2)) || pm->cmd.upmove || (pm->ps->pm_flags&PMF_JUMPING) ) )//jumping {//flip over-forward down-attack if ( (!pm->ps->clientNum||PM_ControlledByPlayer()) || @@ -1302,6 +1303,7 @@ int PM_SaberJumpAttackMove( void ) int PM_SaberFlipOverAttackMove( void ) { //FIXME: check above for room enough to jump! + //FIXME: while in this jump, keep velocity[2] at a minimum until the end of the anim vec3_t fwdAngles, jumpFwd; VectorCopy( pm->ps->viewangles, fwdAngles ); @@ -1408,6 +1410,7 @@ int PM_SaberAttackForMovement( int forwardmove, int rightmove, int move ) && pm->ps->forcePowerLevel[FP_LEVITATION] > FORCE_LEVEL_1 //can force jump && !(pm->gent->flags&FL_LOCK_PLAYER_WEAPONS) // yes this locked weapons check also includes force powers, if we need a separate check later I'll make one && (pm->ps->groundEntityNum != ENTITYNUM_NONE||level.time-pm->ps->lastOnGround<=500) //on ground or just jumped + && ( pm->ps->clientNum || pm->ps->legsAnim == BOTH_JUMP1 || pm->ps->legsAnim == BOTH_FORCEJUMP1 || pm->ps->legsAnim == BOTH_INAIR1 || pm->ps->legsAnim == BOTH_FORCEINAIR1 )//either an NPC or in a non-flip forward jump && ((pm->ps->clientNum&&!PM_ControlledByPlayer()&&!Q_irand(0,2))||pm->cmd.upmove>0||pm->ps->pm_flags&PMF_JUMPING))//jumping {//flip over-forward down-attack if ( (!pm->ps->clientNum||PM_ControlledByPlayer()) || @@ -2146,7 +2149,7 @@ float PM_GetTimeScaleMod( gentity_t *gent ) { return (1.0 / g_timescale->value); } - else if ( gent && gent->client && (gent->client->NPC_class == CLASS_TAVION||gent->client->NPC_class == CLASS_DESANN) && gent->client->ps.forcePowersActive&(1<client && gent->client->ps.forcePowersActive&(1<value); } @@ -3431,7 +3434,7 @@ void PM_TorsoAnimation( void ) && pm->ps->weapon != WP_FLECHETTE && pm->ps->weapon != WP_ROCKET_LAUNCHER && ( PM_RunningAnim( pm->ps->legsAnim ) - || PM_WalkingAnim( pm->ps->legsAnim ) + || (PM_WalkingAnim( pm->ps->legsAnim ) && !pm->ps->clientNum) || PM_JumpingAnim( pm->ps->legsAnim ) || PM_SwimmingAnim( pm->ps->legsAnim ) ) ) {//running w/1-handed or light 2-handed weapon uses full-body anim if you're not using the weapon right now diff --git a/code/game/bg_pmove.cpp b/code/game/bg_pmove.cpp index 678791e..f7d6580 100644 --- a/code/game/bg_pmove.cpp +++ b/code/game/bg_pmove.cpp @@ -1276,7 +1276,7 @@ static qboolean PM_CheckJump( void ) && !(pm->gent->flags&FL_LOCK_PLAYER_WEAPONS) // yes this locked weapons check also includes force powers, if we need a separate check later I'll make one && (pm->ps->groundEntityNum != ENTITYNUM_NONE||level.time-pm->ps->lastOnGround<=500) )//on ground or just jumped {//flip over-forward down-attack - if ( (!pm->ps->clientNum||PM_ControlledByPlayer()) || + if ( ((!pm->ps->clientNum||PM_ControlledByPlayer())&&pm->cmd.forwardmove >= 0&&!pm->cmd.rightmove) || (pm->gent->NPC && (pm->gent->NPC->rank==RANK_CREWMAN||pm->gent->NPC->rank>=RANK_LT) ) ) {//only player or acrobat or boss and higher can do this vec3_t fwdAngles = {0,pm->ps->viewangles[YAW],0}; @@ -1296,7 +1296,10 @@ static qboolean PM_CheckJump( void ) if ( pm->cmd.forwardmove > 0 //going forward && pm->ps->forcePowerLevel[FP_LEVITATION] > FORCE_LEVEL_1 //can force jump && !(pm->gent->flags&FL_LOCK_PLAYER_WEAPONS) // yes this locked weapons check also includes force powers, if we need a separate check later I'll make one - && (pm->ps->legsAnim == BOTH_STAND2||pm->ps->legsAnim == BOTH_SABERFAST_STANCE||pm->ps->legsAnim == BOTH_SABERSLOW_STANCE||level.time-pm->ps->lastStationary<=500)//standing or just started moving + && ( pm->ps->legsAnim == BOTH_STAND2 + || pm->ps->legsAnim == BOTH_SABERFAST_STANCE + || pm->ps->legsAnim == BOTH_SABERSLOW_STANCE + || level.time-pm->ps->lastStationary <= 500 )//standing or just started moving && (pm->ps->groundEntityNum != ENTITYNUM_NONE||(pm->ps->clientNum&&!PM_ControlledByPlayer()&&level.time-pm->ps->lastOnGround<=500)))//on ground or just jumped if non-player {//strong attack: jump-hack if ( (!pm->ps->clientNum||PM_ControlledByPlayer()) || @@ -5551,6 +5554,9 @@ static void PM_BeginWeaponChange( int weapon ) { if ( pm->gent ) { G_SoundOnEnt( pm->gent, CHAN_WEAPON, "sound/weapons/saber/saberoffquick.wav" ); +#ifdef _IMMERSION + G_Force( pm->gent, G_ForceIndex( "fffx/weapons/saber/saberoffquick", FF_CHANNEL_WEAPON ) ); +#endif // _IMMERSION } PM_SetSaberMove(LS_PUTAWAY); } @@ -5796,13 +5802,22 @@ void PM_SetSaberMove(short newMove) //special check for *starting* a saber swing if ( pm->gent && pm->ps->saberLength > 1 ) { +#ifdef _IMMERSION + int index; +#endif // _IMMERSION if ( PM_SaberInAttack( newMove ) || PM_SaberInSpecialAttack( anim ) ) {//playing an attack if ( pm->ps->saberMove != newMove ) {//wasn't playing that attack before if ( PM_SaberInSpecialAttack( anim ) ) { +#ifdef _IMMERSION + index = Q_irand( 1, 3 ); + G_SoundOnEnt( pm->gent, CHAN_WEAPON, va( "sound/weapons/saber/saberhup%d.wav", index ) ); + G_Force( pm->gent, G_ForceIndex( va( "fffx/weapons/saber/saberhup%d", index ), FF_CHANNEL_WEAPON ) ); +#else G_SoundOnEnt( pm->gent, CHAN_WEAPON, va( "sound/weapons/saber/saberhup%d.wav", Q_irand( 1, 3 ) ) ); +#endif // _IMMERSION } else { @@ -5810,14 +5825,32 @@ void PM_SetSaberMove(short newMove) { case FORCE_LEVEL_4: case FORCE_LEVEL_3: +#ifdef _IMMERSION + index = Q_irand( 7, 9 ); + G_SoundOnEnt( pm->gent, CHAN_WEAPON, va( "sound/weapons/saber/saberhup%d.wav", index ) ); + G_Force( pm->gent, G_ForceIndex( va( "fffx/weapons/saber/saberhup%d", index ), FF_CHANNEL_WEAPON ) ); +#else G_SoundOnEnt( pm->gent, CHAN_WEAPON, va( "sound/weapons/saber/saberhup%d.wav", Q_irand( 7, 9 ) ) ); +#endif // _IMMERSION break; case FORCE_LEVEL_2: +#ifdef _IMMERSION + index = Q_irand( 4, 6 ); + G_SoundOnEnt( pm->gent, CHAN_WEAPON, va( "sound/weapons/saber/saberhup%d.wav", index ) ); + G_Force( pm->gent, G_ForceIndex( va( "fffx/weapons/saber/saberhup%d", index ), FF_CHANNEL_WEAPON ) ); +#else G_SoundOnEnt( pm->gent, CHAN_WEAPON, va( "sound/weapons/saber/saberhup%d.wav", Q_irand( 4, 6 ) ) ); +#endif // _IMMERSION break; case FORCE_LEVEL_5: case FORCE_LEVEL_1: +#ifdef _IMMERSION + index = Q_irand( 1, 3 ); + G_SoundOnEnt( pm->gent, CHAN_WEAPON, va( "sound/weapons/saber/saberhup%d.wav", index ) ); + G_Force( pm->gent, G_ForceIndex( va( "fffx/weapons/saber/saberhup%d", index ), FF_CHANNEL_WEAPON ) ); +#else G_SoundOnEnt( pm->gent, CHAN_WEAPON, va( "sound/weapons/saber/saberhup%d.wav", Q_irand( 1, 3 ) ) ); +#endif // _IMMERSION break; } } @@ -5825,7 +5858,13 @@ void PM_SetSaberMove(short newMove) } else if ( PM_SaberInStart( newMove ) && pm->ps->saberAnimLevel == FORCE_LEVEL_3 ) { +#ifdef _IMMERSION + index = Q_irand( 1, 3 ); + G_SoundOnEnt( pm->gent, CHAN_WEAPON, va( "sound/weapons/saber/saberhup%d.wav", index ) ); + G_Force( pm->gent, G_ForceIndex( va( "fffx/weapons/saber/saberhup%d", index ), FF_CHANNEL_WEAPON ) ); +#else G_SoundOnEnt( pm->gent, CHAN_WEAPON, va( "sound/weapons/saber/saberhup%d.wav", Q_irand( 1, 3 ) ) ); +#endif // _IMMERSION } } @@ -7508,7 +7547,7 @@ void PM_WeaponLightsaber(void) {//player always fires at normal speed addTime *= g_timescale->value; } - else if ( g_entities[pm->ps->clientNum].client && (g_entities[pm->ps->clientNum].client->NPC_class == CLASS_TAVION||g_entities[pm->ps->clientNum].client->NPC_class == CLASS_DESANN) && pm->ps->forcePowersActive&(1<ps->clientNum].client && pm->ps->forcePowersActive&(1<value; } @@ -7533,7 +7572,6 @@ void PM_WeaponLightsaber(void) addTime *= g_timescale->value; } else if ( g_entities[pm->ps->clientNum].client - && (g_entities[pm->ps->clientNum].client->NPC_class == CLASS_TAVION || g_entities[pm->ps->clientNum].client->NPC_class == CLASS_DESANN) && pm->ps->forcePowersActive&(1<value; @@ -7678,6 +7716,12 @@ static bool PM_DoChargedWeapons( void ) { G_SoundOnEnt( pm->gent, CHAN_WEAPON, weaponData[pm->ps->weapon].altChargeSnd ); } +#ifdef _IMMERSION + if ( cg_weapons[pm->ps->weapon].altChargeForce ) + { + G_Force( pm->gent, G_ForceIndex( weaponData[pm->ps->weapon].altChargeFrc, FF_CHANNEL_WEAPON ) ); + } +#endif // _IMMERSION } } else @@ -7695,10 +7739,25 @@ static bool PM_DoChargedWeapons( void ) pm->ps->weaponstate = WEAPON_CHARGING; pm->ps->weaponChargeTime = level.time; +#ifdef _IMMERSION + if ( pm->gent && !pm->gent->NPC ) // HACK: !NPC mostly for bowcaster and weequay + { + if ( cg_weapons[pm->ps->weapon].chargeSound ) + { + G_SoundOnEnt( pm->gent, CHAN_WEAPON, weaponData[pm->ps->weapon].chargeSnd ); + } + + if ( cg_weapons[pm->ps->weapon].chargeForce ) + { + G_Force( pm->gent, G_ForceIndex( weaponData[pm->ps->weapon].chargeFrc, FF_CHANNEL_WEAPON ) ); + } + } +#else if ( cg_weapons[pm->ps->weapon].chargeSound && pm->gent && !pm->gent->NPC ) // HACK: !NPC mostly for bowcaster and weequay { G_SoundOnEnt( pm->gent, CHAN_WEAPON, weaponData[pm->ps->weapon].chargeSnd ); } +#endif // _IMMERSION } } @@ -7713,6 +7772,11 @@ static bool PM_DoChargedWeapons( void ) // dumb, but since we shoot a charged weapon on button-up, we need to repress this button for now pm->cmd.buttons |= BUTTON_ATTACK; pm->ps->eFlags |= EF_FIRING; +#ifdef _IMMERSION + // HACKHACKHACK - charging sound effect stops when button released, + // but I can't find the place where this stop occurs... it's here for now... + G_ForceStop( pm->gent, G_ForceIndex( weaponData[pm->ps->weapon].chargeFrc, FF_CHANNEL_WEAPON ) ); +#endif // _IMMERSION } else if ( pm->ps->weaponstate == WEAPON_CHARGING_ALT ) { @@ -7720,6 +7784,11 @@ static bool PM_DoChargedWeapons( void ) // dumb, but since we shoot a charged weapon on button-up, we need to repress this button for now pm->cmd.buttons |= BUTTON_ALT_ATTACK; pm->ps->eFlags |= (EF_FIRING|EF_ALT_FIRING); +#ifdef _IMMERSION + // HACKHACKHACK - charging sound effect stops when button released, + // but I can't find the place where this stop occurs... it's here for now... + G_ForceStop( pm->gent, G_ForceIndex( weaponData[pm->ps->weapon].altChargeFrc, FF_CHANNEL_WEAPON ) ); +#endif // _IMMERSION } return false; // continue with the rest of the weapon code @@ -8319,7 +8388,6 @@ static void PM_Weapon( void ) addTime *= g_timescale->value; } else if ( g_entities[pm->ps->clientNum].client - && (g_entities[pm->ps->clientNum].client->NPC_class == CLASS_TAVION || g_entities[pm->ps->clientNum].client->NPC_class == CLASS_DESANN) && pm->ps->forcePowersActive&(1<value; @@ -8512,7 +8580,6 @@ void PM_SetSpecialMoveValues (void ) pml.frametime *= (1.0f/g_timescale->value); } else if ( g_entities[pm->ps->clientNum].client - && (g_entities[pm->ps->clientNum].client->NPC_class == CLASS_TAVION || g_entities[pm->ps->clientNum].client->NPC_class == CLASS_TAVION) && pm->ps->forcePowersActive&(1<value); @@ -8562,6 +8629,9 @@ void PM_AdjustAttackStates( pmove_t *pm ) if ( cg.zoomMode == 0 || cg.zoomMode == 3 ) { G_SoundOnEnt( pm->gent, CHAN_AUTO, "sound/weapons/disruptor/zoomstart.wav" ); +#ifdef _IMMERSION + G_Force( pm->gent, G_ForceIndex( "fffx/weapons/disruptor/zoomstart", FF_CHANNEL_WEAPON ) ); +#endif // _IMMERSION // not already zooming, so do it now cg.zoomMode = 2; cg.zoomLocked = qfalse; @@ -8570,6 +8640,9 @@ void PM_AdjustAttackStates( pmove_t *pm ) else if ( cg.zoomMode == 2 ) { G_SoundOnEnt( pm->gent, CHAN_AUTO, "sound/weapons/disruptor/zoomend.wav" ); +#ifdef _IMMERSION + G_Force( pm->gent, G_ForceIndex( "fffx/weapons/disruptor/zoomend", FF_CHANNEL_WEAPON ) ); +#endif // _IMMERSION // already zooming, so must be wanting to turn it off cg.zoomMode = 0; cg.zoomTime = cg.time; diff --git a/code/game/bg_public.h b/code/game/bg_public.h index b0dbe01..e75c3c3 100644 --- a/code/game/bg_public.h +++ b/code/game/bg_public.h @@ -297,6 +297,12 @@ typedef enum { EV_GENERAL_SOUND, EV_GLOBAL_SOUND, // no attenuation +#ifdef _IMMERSION + EV_ENTITY_FORCE, + EV_AREA_FORCE, + EV_GLOBAL_FORCE, + EV_FORCE_STOP, +#endif // _IMMERSION EV_PLAY_EFFECT, EV_PLAY_MUZZLE_EFFECT, @@ -524,6 +530,10 @@ typedef struct gitem_s { char *sounds; // string of all sounds this item will use vec3_t mins; // Bbox vec3_t maxs; // Bbox +#ifdef _IMMERSION + char *pickup_force; + char *forces; +#endif // _IMMERSION } gitem_t; // included in both the game dll and the client diff --git a/code/game/g_active.cpp b/code/game/g_active.cpp index a90b4c7..f714b4a 100644 --- a/code/game/g_active.cpp +++ b/code/game/g_active.cpp @@ -247,22 +247,27 @@ qboolean G_ValidateLookEnemy( gentity_t *self, gentity_t *enemy ) && enemy->noDamageTeam != self->client->playerTeam && enemy->health > 0 ) {//a turret - return qtrue; + //return qtrue; } - return qfalse; - } - - if ( enemy->health <= 0 && ((level.time-enemy->s.time) > 3000||!InFront(enemy->currentOrigin,self->currentOrigin,self->client->ps.viewangles,0.2f)||DistanceHorizontal(enemy->currentOrigin,self->currentOrigin)>16384))//>128 - {//corpse, been dead too long or too out of sight to be interesting - if ( !enemy->message ) + else { return qfalse; } } + else + { + if ( enemy->client->playerTeam == self->client->playerTeam ) + {//on same team + return qfalse; + } - if ( enemy->client->playerTeam == self->client->playerTeam ) - {//on same team - return qfalse; + if ( enemy->health <= 0 && ((level.time-enemy->s.time) > 3000||!InFront(enemy->currentOrigin,self->currentOrigin,self->client->ps.viewangles,0.2f)||DistanceHorizontal(enemy->currentOrigin,self->currentOrigin)>16384))//>128 + {//corpse, been dead too long or too out of sight to be interesting + if ( !enemy->message ) + { + return qfalse; + } + } } if ( (!InFront( enemy->currentOrigin, self->currentOrigin, self->client->ps.viewangles, 0.0f) || !G_ClearLOS( self, self->client->renderInfo.eyePoint, enemy ) ) @@ -1781,7 +1786,7 @@ extern void CG_ChangeWeapon( int num ); void RunEmplacedWeapon( gentity_t *ent, usercmd_t **ucmd ) { - if (( (*ucmd)->buttons & BUTTON_USE || (*ucmd)->forwardmove < 0 ) && ent->owner && ent->owner->delay + 500 < level.time ) + if (( (*ucmd)->buttons & BUTTON_USE || (*ucmd)->forwardmove < 0 || (*ucmd)->upmove > 0 ) && ent->owner && ent->owner->delay + 500 < level.time ) { ent->owner->s.loopSound = 0; @@ -1789,6 +1794,9 @@ void RunEmplacedWeapon( gentity_t *ent, usercmd_t **ucmd ) (*ucmd)->buttons &= ~BUTTON_USE; G_Sound( ent, G_SoundIndex( "sound/weapons/emplaced/emplaced_dismount.mp3" )); +#ifdef _IMMERSION + G_Force( ent, G_ForceIndex( "fffx/weapons/emplaced/emplaced_dismount", FF_CHANNEL_TOUCH ) ); +#endif // _IMMERSION } else { @@ -1943,9 +1951,11 @@ void G_CheckMovingLoopingSounds( gentity_t *ent, usercmd_t *ucmd ) switch( ent->client->NPC_class ) { case CLASS_R2D2: - case CLASS_R5D2: ent->s.loopSound = G_SoundIndex( "sound/chars/r2d2/misc/r2_move_lp.wav" ); break; + case CLASS_R5D2: + ent->s.loopSound = G_SoundIndex( "sound/chars/r2d2/misc/r2_move_lp2.wav" ); + break; case CLASS_MARK2: ent->s.loopSound = G_SoundIndex( "sound/chars/mark2/misc/mark2_move_lp" ); break; @@ -2127,6 +2137,9 @@ extern cvar_t *g_skippingcin; { // already zooming, so must be wanting to turn it off G_Sound( ent, G_SoundIndex( "sound/weapons/disruptor/zoomend.wav" )); +#ifdef _IMMERSION + G_Force( ent, G_ForceIndex( "fffx/weapons/disruptor/zoomend", FF_CHANNEL_WEAPON ) ); +#endif // _IMMERSION cg.zoomMode = 0; cg.zoomTime = cg.time; cg.zoomLocked = qfalse; diff --git a/code/game/g_breakable.cpp b/code/game/g_breakable.cpp index 7c00aac..31a4539 100644 --- a/code/game/g_breakable.cpp +++ b/code/game/g_breakable.cpp @@ -608,7 +608,7 @@ void misc_model_breakable_init( gentity_t *ent ) if ( ent->spawnflags & 1 ) {//Blocks movement - ent->contents = CONTENTS_BODY|CONTENTS_MONSTERCLIP|CONTENTS_BOTCLIP;//Was CONTENTS_SOLID, but only architecture should be this + ent->contents = CONTENTS_SOLID|CONTENTS_OPAQUE|CONTENTS_BODY|CONTENTS_MONSTERCLIP|CONTENTS_BOTCLIP;//Was CONTENTS_SOLID, but only architecture should be this } else if ( ent->health ) {//Can only be shot diff --git a/code/game/g_client.cpp b/code/game/g_client.cpp index 81c50fe..9545e3b 100644 --- a/code/game/g_client.cpp +++ b/code/game/g_client.cpp @@ -1623,11 +1623,11 @@ qboolean ClientSpawn(gentity_t *ent, SavedGameJustLoaded_e eSavedGameJustLoaded // ent->health = client->ps.stats[STAT_HEALTH] = client->ps.stats[STAT_MAX_HEALTH]; - ent->client->dismemberProbHead = 1; + ent->client->dismemberProbHead = 0; ent->client->dismemberProbArms = 5; ent->client->dismemberProbHands = 20; - ent->client->dismemberProbWaist = 1; - ent->client->dismemberProbLegs = 1; + ent->client->dismemberProbWaist = 0; + ent->client->dismemberProbLegs = 0; ent->client->ps.batteryCharge = 2500; diff --git a/code/game/g_combat.cpp b/code/game/g_combat.cpp index 002f967..fd219d2 100644 --- a/code/game/g_combat.cpp +++ b/code/game/g_combat.cpp @@ -28,7 +28,7 @@ extern gentity_t *player; gentity_t *g_lastClientDamaged; -int killPlayerTimer = 0; +extern int killPlayerTimer; extern void NPC_TempLookTarget ( gentity_t *self, int lookEntNum, int minLookTime, int maxLookTime ); extern void G_AddVoiceEvent( gentity_t *self, int event, int speakDebounceTime ); @@ -62,7 +62,7 @@ extern qboolean PM_SaberInStart( int move ); extern qboolean PM_SaberInReturn( int move ); extern int PM_AnimLength( int index, animNumber_t anim ); -qboolean G_CheckForLedge( gentity_t *self, vec3_t fallCheckDir, float checkDist ); +static int G_CheckForLedge( gentity_t *self, vec3_t fallCheckDir, float checkDist ); static int G_CheckSpecialDeathAnim( gentity_t *self, vec3_t point, int damage, int mod, int hitLoc ); static int G_PickDeathAnim( gentity_t *self, vec3_t point, int damage, int mod, int hitLoc ); static void G_TrackWeaponUsage( gentity_t *self, gentity_t *inflictor, int add, int mod ); @@ -120,17 +120,10 @@ gentity_t *TossClientItems( gentity_t *self ) { self->s.weapon = WP_NONE; - if ( weapon == WP_THERMAL ) - {//using thermal - if ( self->client->ps.torsoAnim == BOTH_ATTACK10 ) - {//we were getting ready to throw one, drop it! - self->client->ps.weaponChargeTime = level.time - FRAMETIME;//so it just kind of drops it - dropped = WP_DropThermal( self ); - } - else - {//drop the belt - item = FindItemForAmmo( AMMO_THERMAL ); - } + if ( weapon == WP_THERMAL && self->client->ps.torsoAnim == BOTH_ATTACK10 ) + {//we were getting ready to throw the thermal, drop it! + self->client->ps.weaponChargeTime = level.time - FRAMETIME;//so it just kind of drops it + dropped = WP_DropThermal( self ); } else {// find the item type for this weapon @@ -196,7 +189,9 @@ gentity_t *TossClientItems( gentity_t *self ) } } // well, dropped weapons are G2 models, so they have to be initialised if they want to draw..give us a radius so we don't get prematurely culled - if ( weapon != WP_THERMAL ) + if ( weapon != WP_THERMAL + && weapon != WP_TRIP_MINE + && weapon != WP_DET_PACK ) { gi.G2API_InitGhoul2Model( dropped->ghoul2, item->world_model, G_ModelIndex( item->world_model )); dropped->s.radius = 10; @@ -761,18 +756,6 @@ void G_MakeTeamVulnerable( void ) { continue; } - if ( !ent->client->squadname ) - { - continue; - } - if ( !ent->client->squadname[0] ) - { - continue; - } - if ( Q_stricmp(self->client->squadname, ent->client->squadname) ) - { - continue; - } ent->flags &= ~FL_UNDYING; newhealth = Q_irand( 5, 40 ); if ( ent->health > newhealth ) @@ -1187,7 +1170,7 @@ qboolean G_GetHitLocFromSurfName( gentity_t *ent, const char *surfName, int *hit { dismember = qtrue; } - else if ( g_dismemberment->integer > 3 || !ent->client->dismembered ) + else if ( g_dismemberment->integer >= 11381138 || !ent->client->dismembered ) { if ( ent->client && ent->client->NPC_class == CLASS_PROTOCOL ) { @@ -1832,7 +1815,7 @@ qboolean G_LimbLost( gentity_t *ent, int hitLoc ) } } -qboolean G_Dismember( gentity_t *ent, vec3_t point, +static qboolean G_Dismember( gentity_t *ent, vec3_t point, const char *limbBone, const char *rotateBone, char *limbName, char *limbCapName, char *stubCapName, char *limbTagName, char *stubTagName, int limbAnim, float limbRollBase, float limbPitchBase, @@ -2135,7 +2118,7 @@ static qboolean G_Dismemberable( gentity_t *self, int hitLoc ) {//cannot dismember me right now return qfalse; } - if ( g_dismemberment->integer < 4 && !g_saberRealisticCombat->integer ) + if ( g_dismemberment->integer < 11381138 && !g_saberRealisticCombat->integer ) { if ( g_dismemberProbabilities->value > 0.0f ) {//use the ent-specific dismemberProbabilities @@ -2172,7 +2155,7 @@ static qboolean G_Dismemberable( gentity_t *self, int hitLoc ) } //check probability of this happening on this npc - if ( floor((Q_flrand( 0, 100 )*g_dismemberProbabilities->value)) > dismemberProb*2.0f )//probabilities seemed really really low, had to crank them up + if ( floor((Q_flrand( 1, 100 )*g_dismemberProbabilities->value)) > dismemberProb*2.0f )//probabilities seemed really really low, had to crank them up { return qfalse; } @@ -2187,7 +2170,7 @@ static qboolean G_Dismemberable2( gentity_t *self, int hitLoc ) {//cannot dismember me right now return qfalse; } - if ( g_dismemberment->integer < 4 && !g_saberRealisticCombat->integer ) + if ( g_dismemberment->integer < 11381138 && !g_saberRealisticCombat->integer ) { if ( g_dismemberProbabilities->value <= 0.0f ) {//add the passed-in damage to the locationDamage array, check to see if it's taken enough damage to actually dismember @@ -2203,15 +2186,15 @@ static qboolean G_Dismemberable2( gentity_t *self, int hitLoc ) extern qboolean G_StandardHumanoid( const char *modelName ); qboolean G_DoDismemberment( gentity_t *self, vec3_t point, int mod, int damage, int hitLoc, qboolean force = qfalse ) { -extern cvar_t *g_s_language; -extern cvar_t *g_sp_language; +extern cvar_t *g_iscensored; // dismemberment -- FIXME: should have a check for how long npc has been dead so people can't // continue to dismember a dead body long after it's been dead - //NOTE that you can only cut one thing off unless the super dismemberment is > 3 - if ( ( g_dismemberment->integer || g_saberRealisticCombat->integer > 1 ) - && ( Q_stricmp( "DEUTSCH", g_s_language->string ) != 0 )//voice language is *not* German - && (g_sp_language->integer != SP_LANGUAGE_GERMAN )//text language is *not* German - && mod == MOD_SABER )//only lightsaber + //NOTE that you can only cut one thing off unless the dismemberment is >= 11381138 +#ifdef GERMAN_CENSORED + if ( 0 ) //germany == censorship +#else + if ( !g_iscensored->integer && ( g_dismemberment->integer || g_saberRealisticCombat->integer > 1 ) && mod == MOD_SABER )//only lightsaber +#endif {//FIXME: don't do strcmps here if ( G_StandardHumanoid( self->NPC_type ) && (force||g_dismemberProbabilities->value>0.0f||G_Dismemberable2( self, hitLoc )) ) @@ -3600,7 +3583,7 @@ extern void RunEmplacedWeapon( gentity_t *ent, usercmd_t **ucmd ); && attacker->client && attacker->client->ps.weapon == WP_SABER && !attacker->client->ps.saberInFlight - && (d_slowmodeath->integer > 4||lastInGroup))//either slow mo death level 5 (any enemy) or 4 and I was the last in my group + && (d_slowmodeath->integer > 4||lastInGroup||holdingSaber))//either slow mo death level 5 (any enemy) or 4 and I was the last in my group or I'm a saber user {//Matrix! G_StartMatrixEffect( self ); } @@ -3679,10 +3662,16 @@ extern void RunEmplacedWeapon( gentity_t *ent, usercmd_t **ucmd ); if ( self->client->playerTeam == TEAM_PLAYER ) { G_SoundOnEnt( self, CHAN_AUTO, "sound/weapons/saber/saberoff.wav" ); +#ifdef _IMMERSION + G_Force( self, G_ForceIndex( "fffx/weapons/saber/saberoff", FF_CHANNEL_WEAPON ) ); +#endif // _IMMERSION } else { G_SoundOnEnt( self, CHAN_AUTO, "sound/weapons/saber/enemy_saber_off.wav" ); +#ifdef _IMMERSION + G_Force( self, G_ForceIndex( "fffx/weapons/saber/enemy_saber_off", FF_CHANNEL_WEAPON ) ); +#endif // _IMMERSION } } } @@ -4121,7 +4110,11 @@ extern void RunEmplacedWeapon( gentity_t *ent, usercmd_t **ucmd ); } else { - if ( cliff_fall != 2 ) + if ( (self->client->ps.eFlags&EF_FORCE_GRIPPED) ) + {//killed while gripped - no loud scream + G_AlertTeam( self, attacker, 512, 32 ); + } + else if ( cliff_fall != 2 ) { if ( meansOfDeath == MOD_KNOCKOUT || meansOfDeath == MOD_MELEE ) { @@ -4623,7 +4616,7 @@ void G_ApplyKnockback( gentity_t *targ, vec3_t newDir, float knockback ) } } -int G_CheckForLedge( gentity_t *self, vec3_t fallCheckDir, float checkDist ) +static int G_CheckForLedge( gentity_t *self, vec3_t fallCheckDir, float checkDist ) { vec3_t start, end; trace_t tr; @@ -4651,7 +4644,7 @@ int G_CheckForLedge( gentity_t *self, vec3_t fallCheckDir, float checkDist ) return 0; } -void G_FriendlyFireReaction( gentity_t *self, gentity_t *other, int dflags ) +static void G_FriendlyFireReaction( gentity_t *self, gentity_t *other, int dflags ) { if ( (!player->client->ps.viewEntity || other->s.number != player->client->ps.viewEntity)) {//hit by a teammate @@ -5052,7 +5045,10 @@ void G_Damage( gentity_t *targ, gentity_t *inflictor, gentity_t *attacker, vec3_ // check for godmode, completely getting out of the damage if ( targ->flags & FL_GODMODE && !(dflags&DAMAGE_NO_PROTECTION) ) { - if ( targ->client && attacker->client && targ->client->playerTeam == attacker->client->playerTeam ) + if ( targ->client + && attacker->client + && targ->client->playerTeam == attacker->client->playerTeam + && (!targ->NPC || !targ->NPC->charmedTime) ) {//complain, but don't turn on them G_FriendlyFireReaction( targ, attacker, dflags ); } @@ -5327,7 +5323,10 @@ void G_Damage( gentity_t *targ, gentity_t *inflictor, gentity_t *attacker, vec3_ if ( yellAtAttacker ) { - G_FriendlyFireReaction( targ, attacker, dflags ); + if ( !targ->NPC || !targ->NPC->charmedTime ) + { + G_FriendlyFireReaction( targ, attacker, dflags ); + } } } } diff --git a/code/game/g_fx.cpp b/code/game/g_fx.cpp index 1537408..613f9cd 100644 --- a/code/game/g_fx.cpp +++ b/code/game/g_fx.cpp @@ -260,11 +260,16 @@ void SP_CreateSnow( gentity_t *ent ) G_SpawnInt( "count", "1000", &ent->count ); - sprintf( temp, "snow init %i", ent->count ); + cvar_t *r_weatherScale = gi.cvar( "r_weatherScale", "1", CVAR_ARCHIVE ); - G_FindConfigstringIndex( temp, CS_WORLD_FX, MAX_WORLD_FX, qtrue ); + if ( r_weatherScale->value > 0.0f ) + { + sprintf( temp, "snow init %i", (int)( ent->count * r_weatherScale->value )); - level.worldFlags |= WF_SNOWING; + G_FindConfigstringIndex( temp, CS_WORLD_FX, MAX_WORLD_FX, qtrue ); + + level.worldFlags |= WF_SNOWING; + } } /*QUAKED fx_rain (1 0 0) (-16 -16 -16) (16 16 16) @@ -279,11 +284,16 @@ void SP_CreateRain( gentity_t *ent ) G_SpawnInt( "count", "500", &ent->count ); - sprintf( temp, "rain init %i", ent->count ); + cvar_t *r_weatherScale = gi.cvar( "r_weatherScale", "1", CVAR_ARCHIVE ); - G_FindConfigstringIndex( temp, CS_WORLD_FX, MAX_WORLD_FX, qtrue ); + if ( r_weatherScale->value > 0.0f ) + { + sprintf( temp, "rain init %i", (int)( ent->count * r_weatherScale->value )); - level.worldFlags |= WF_RAINING; + G_FindConfigstringIndex( temp, CS_WORLD_FX, MAX_WORLD_FX, qtrue ); + + level.worldFlags |= WF_RAINING; + } } diff --git a/code/game/g_itemLoad.cpp b/code/game/g_itemLoad.cpp index 0034bc9..94f6a76 100644 --- a/code/game/g_itemLoad.cpp +++ b/code/game/g_itemLoad.cpp @@ -11,6 +11,9 @@ #include "g_items.h" #define PICKUPSOUND "sound/weapons/w_pkup.wav" +#ifdef _IMMERSION +#define PICKUPFORCE "fffx/weapons/w_pkup" +#endif // _IMMERSION //qboolean COM_ParseInt( char **data, int *i ); //qboolean COM_ParseString( char **data, char **s ); @@ -34,6 +37,9 @@ static void IT_PickupSound (const char **holdBuf); static void IT_Tag (const char **holdBuf); static void IT_Type (const char **holdBuf); static void IT_WorldModel (const char **holdBuf); +#ifdef _IMMERSION +static void IT_PickupForce( const char **holdBuf); +#endif // _IMMERSION typedef struct @@ -43,7 +49,11 @@ typedef struct } itemParms_t; +#ifdef _IMMERSION #define IT_PARM_MAX 11 +#else +#define IT_PARM_MAX 10 +#endif // _IMMERSION itemParms_t ItemParms[IT_PARM_MAX] = { @@ -57,6 +67,9 @@ itemParms_t ItemParms[IT_PARM_MAX] = "tag", IT_Tag, "type", IT_Type, "worldmodel", IT_WorldModel, +#ifdef _IMMERSION + "pickupforce", IT_PickupForce, +#endif // _IMMERSION }; static void IT_SetDefaults() @@ -74,6 +87,10 @@ static void IT_SetDefaults() bg_itemlist[itemParms.itemNum].pickup_sound = PICKUPSOUND; //give it a default sound bg_itemlist[itemParms.itemNum].precaches = NULL; bg_itemlist[itemParms.itemNum].sounds = NULL; +#ifdef _IMMERSION + bg_itemlist[itemParms.itemNum].pickup_force = PICKUPFORCE; + bg_itemlist[itemParms.itemNum].forces = NULL; +#endif // _IMMERSION } static void IT_Name(const char **holdBuf) @@ -583,6 +600,28 @@ static void IT_PickupSound(const char **holdBuf) bg_itemlist[itemParms.itemNum].pickup_sound = G_NewString(tokenStr); } +#ifdef _IMMERSION +static void IT_PickupForce(const char **holdBuf) +{ + int len; + const char *tokenStr; + + if (COM_ParseString(holdBuf,&tokenStr)) + { + return; + } + + len = strlen(tokenStr); + len++; + if (len > 32) + { + len = 32; + gi.Printf("WARNING: Pickup Force too long in external ITEMS.DAT '%s'\n", tokenStr); + } + + bg_itemlist[itemParms.itemNum].pickup_force = G_NewString(tokenStr); +} +#endif // _IMMERSION static void IT_ParseWeaponParms(const char **holdBuf) { static int weaponNum,ammoNum; diff --git a/code/game/g_items.cpp b/code/game/g_items.cpp index ae57f03..2e135ca 100644 --- a/code/game/g_items.cpp +++ b/code/game/g_items.cpp @@ -675,7 +675,10 @@ gentity_t *LaunchItem( gitem_t *item, vec3_t origin, vec3_t velocity, char *targ if ( item->giType == IT_WEAPON ) { // give weapon items zero pitch, a random yaw, and rolled onto their sides...but would be bad to do this for a bowcaster - if ( item->giTag != WP_BOWCASTER ) + if ( item->giTag != WP_BOWCASTER + && item->giTag != WP_THERMAL + && item->giTag != WP_TRIP_MINE + && item->giTag != WP_DET_PACK ) { VectorSet( dropped->s.angles, 0, crandom() * 180, 90.0f ); G_SetAngles( dropped, dropped->s.angles ); diff --git a/code/game/g_local.h b/code/game/g_local.h index 612f290..86a8816 100644 --- a/code/game/g_local.h +++ b/code/game/g_local.h @@ -271,6 +271,10 @@ void G_PlayEffect( int fxID, vec3_t origin, vec3_t fwd ); void G_PlayEffect( int fxID, vec3_t origin, vec3_t axis[3] ); void G_PlayEffect( int fxID, const int modelIndex, const int boltIndex, const int entNum); void G_PlayEffect( int fxID, int entNum, vec3_t fwd ); +#ifdef _IMMERSION +void G_PlayEffect( const char *name, int clientNum, vec3_t origin, vec3_t fwd ); +void G_PlayEffect( int fxID, int clientNum, vec3_t origin, vec3_t fwd ); +#endif // _IMMERSION void G_KillBox (gentity_t *ent); gentity_t *G_Find (gentity_t *from, int fieldofs, const char *match); @@ -286,6 +290,13 @@ gentity_t *G_TempEntity( vec3_t origin, int event ); void G_Sound( gentity_t *ent, int soundIndex ); void G_FreeEntity( gentity_t *e ); +#ifdef _IMMERSION +int G_ForceIndex( const char *name, int channel ); +void G_Force( gentity_t *ent, int forceIndex ); +void G_ForceArea( gentity_t *ent, int forceIndex ); +void G_ForceBroadcast( gentity_t *ent, int forceIndex ); +void G_ForceStop( gentity_t* ent, int forceIndex ); +#endif // _IMMERSION void G_TouchTriggers (gentity_t *ent); void G_TouchTeamClients (gentity_t *ent); void G_TouchSolids (gentity_t *ent); diff --git a/code/game/g_main.cpp b/code/game/g_main.cpp index 40ea739..f282728 100644 --- a/code/game/g_main.cpp +++ b/code/game/g_main.cpp @@ -12,11 +12,12 @@ #include "b_local.h" #include "anims.h" #include "g_icarus.h" +#include "objectives.h" #include "../cgame/cg_local.h" // yeah I know this is naughty, but we're shipping soon... -#include "../qcommon/stripPublic.h" extern CNavigator navigator; static int navCalcPathTime = 0; +int eventClearTime = 0; #define STEPSIZE 18 @@ -124,8 +125,7 @@ cvar_t *com_buildScript; cvar_t *g_skippingcin; cvar_t *g_AIsurrender; cvar_t *g_numEntities; -cvar_t *g_s_language; -cvar_t *g_sp_language; +cvar_t *g_iscensored; cvar_t *g_saberAutoBlocking; cvar_t *g_saberRealisticCombat; @@ -147,8 +147,6 @@ void ClearNPCGlobals( void ); extern void AI_UpdateGroups( void ); void ClearPlayerAlertEvents( void ); -int eventClearTime = 0; - extern void NPC_ShowDebugInfo (void); extern int killPlayerTimer; extern cvar_t *d_altRoutes; @@ -548,19 +546,18 @@ void G_InitCvars( void ) { g_subtitles = gi.cvar( "g_subtitles", "2", CVAR_ARCHIVE ); com_buildScript = gi.cvar ("com_buildscript", "0", 0); - g_saberAutoBlocking = gi.cvar( "g_saberAutoBlocking", "1", CVAR_ARCHIVE );//must press +block button to do any blocking - g_saberRealisticCombat = gi.cvar( "g_saberRealisticCombat", "0", CVAR_ARCHIVE );//makes collision more precise, increases damage - g_saberMoveSpeed = gi.cvar( "g_saberMoveSpeed", "1", CVAR_ARCHIVE );//how fast you run while attacking with a saber - g_saberAnimSpeed = gi.cvar( "g_saberAnimSpeed", "1", CVAR_ARCHIVE );//how fast saber animations run - g_saberAutoAim = gi.cvar( "g_saberAutoAim", "1", CVAR_ARCHIVE );//auto-aims at enemies when not moving or when just running forward + g_saberAutoBlocking = gi.cvar( "g_saberAutoBlocking", "1", CVAR_ARCHIVE|CVAR_CHEAT );//must press +block button to do any blocking + g_saberRealisticCombat = gi.cvar( "g_saberRealisticCombat", "0", CVAR_ARCHIVE|CVAR_CHEAT );//makes collision more precise, increases damage + g_saberMoveSpeed = gi.cvar( "g_saberMoveSpeed", "1", CVAR_ARCHIVE|CVAR_CHEAT );//how fast you run while attacking with a saber + g_saberAnimSpeed = gi.cvar( "g_saberAnimSpeed", "1", CVAR_ARCHIVE|CVAR_CHEAT );//how fast saber animations run + g_saberAutoAim = gi.cvar( "g_saberAutoAim", "1", CVAR_ARCHIVE|CVAR_CHEAT );//auto-aims at enemies when not moving or when just running forward g_AIsurrender = gi.cvar( "g_AIsurrender", "0", CVAR_CHEAT ); g_numEntities = gi.cvar( "g_numEntities", "0", CVAR_CHEAT ); - g_s_language = gi.cvar( "s_language", "english", (CVAR_ARCHIVE|CVAR_NORESTART) ); - g_sp_language = gi.cvar( "sp_language", va("%d", SP_LANGUAGE_ENGLISH), (CVAR_ARCHIVE|CVAR_NORESTART) ); gi.cvar( "newTotalSecrets", "0", CVAR_ROM ); gi.cvar_set("newTotalSecrets", "0");//used to carry over the count from SP_target_secret to ClientBegin + g_iscensored = gi.cvar( "ui_iscensored", "0", CVAR_ARCHIVE|CVAR_ROM|CVAR_INIT|CVAR_CHEAT|CVAR_NORESTART ); } /* @@ -702,6 +699,7 @@ void InitGame( const char *mapname, const char *spawntarget, int checkSum, cons level.dmBeatTime = 0; level.curAlertID = 1;//0 is default for lastAlertEvent, so... + eventClearTime = 0; } /* @@ -1146,8 +1144,28 @@ void UpdateTeamCounters( gentity_t *ent ) teamEnemyCount[ent->client->playerTeam]++; } */ +extern void G_SoundOnEnt( gentity_t *ent, soundChannel_t channel, const char *soundPath ); +void G_PlayerGuiltDeath( void ) +{ + if ( player && player->client ) + {//simulate death + player->client->ps.stats[STAT_HEALTH] = 0; + //turn off saber + if ( player->client->ps.weapon == WP_SABER && player->client->ps.saberActive ) + { + G_SoundOnEnt( player, CHAN_WEAPON, "sound/weapons/saber/saberoff.wav" ); + player->client->ps.saberActive = qfalse; + } + //play the "what have I done?!" anim + NPC_SetAnim( player, SETANIM_BOTH, BOTH_FORCEHEAL_START, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD ); + player->client->ps.legsAnimTimer = player->client->ps.torsoAnimTimer = -1; + //look at yourself + player->client->ps.stats[STAT_DEAD_YAW] = player->client->ps.viewangles[YAW]+180; + } +} extern void NPC_SetAnim(gentity_t *ent,int type,int anim,int priority); extern void G_MakeTeamVulnerable( void ); +int killPlayerTimer = 0; void G_CheckEndLevelTimers( gentity_t *ent ) { if ( killPlayerTimer && level.time > killPlayerTimer ) @@ -1156,24 +1174,13 @@ void G_CheckEndLevelTimers( gentity_t *ent ) ent->health = 0; if ( ent->client && ent->client->ps.stats[STAT_HEALTH] > 0 ) { - //simulate death - ent->client->ps.stats[STAT_HEALTH] = 0; + G_PlayerGuiltDeath(); + //cg.missionStatusShow = qtrue; + statusTextIndex = MAX_MISSIONFAILED; //debounce respawn time ent->client->respawnTime = level.time + 2000; - //play the "what have I done?!" anim -// NPC_SetAnim( ent, SETANIM_BOTH, BOTH_GUILT1, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD ); - /* - NPC_SetAnim( ent, SETANIM_TORSO, BOTH_SIT2TO1, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD ); - NPC_SetAnim( ent, SETANIM_LEGS, LEGS_KNEELDOWN1, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD ); - */ - ent->client->ps.torsoAnimTimer = -1; - ent->client->ps.legsAnimTimer = -1; - //look at yourself - ent->client->ps.stats[STAT_DEAD_YAW] = ent->client->ps.viewangles[YAW]+180; //stop all scripts - if (Q_stricmpn(level.mapname,"_holo",5)) { - stop_icarus = qtrue; - } + stop_icarus = qtrue; //make the team killable G_MakeTeamVulnerable(); } @@ -1206,6 +1213,7 @@ void NAV_CheckCalcPaths( void ) navCalcPathTime = 0; } } + /* ================ G_RunFrame @@ -1271,11 +1279,7 @@ void G_RunFrame( int levelTime ) { } //Look to clear out old events - //if ( eventClearTime < level.time ) - { - ClearPlayerAlertEvents(); - //eventClearTime = level.time + ALERT_CLEAR_TIME; - } + ClearPlayerAlertEvents(); //Run the frame for all entities // for ( i = 0, ent = &g_entities[0]; i < globals.num_entities ; i++, ent++) diff --git a/code/game/g_misc.cpp b/code/game/g_misc.cpp index d060927..32848bb 100644 --- a/code/game/g_misc.cpp +++ b/code/game/g_misc.cpp @@ -581,6 +581,10 @@ void camera_aim( gentity_t *self ) G_ClearViewEntity( player ); G_Sound( player, self->soundPos2 ); self->painDebounceTime = level.time + (self->wait*1000);//FRAMETIME*5;//don't check for player buttons for 500 ms + if ( player->client->usercmd.upmove > 0 ) + {//stop player from doing anything for a half second after + player->aimDebounceTime = level.time + 500; + } } else if ( self->painDebounceTime < level.time ) {//check for use button @@ -832,7 +836,7 @@ void SP_object_cargo_barrel1(gentity_t *ent) // ent->sounds = G_SoundIndex("sound/weapons/explosions/explode1.wav"); } - ent->contents = CONTENTS_SOLID; + ent->contents = CONTENTS_SOLID|CONTENTS_OPAQUE; if ( ent->spawnflags & 1 ) { @@ -2360,7 +2364,7 @@ void SP_misc_exploding_crate( gentity_t *ent ) VectorSet( ent->mins, -24, -24, 0 ); VectorSet( ent->maxs, 24, 24, 64 ); - ent->contents = CONTENTS_BODY|CONTENTS_MONSTERCLIP|CONTENTS_BOTCLIP;//CONTENTS_SOLID; + ent->contents = CONTENTS_SOLID|CONTENTS_OPAQUE|CONTENTS_BODY|CONTENTS_MONSTERCLIP|CONTENTS_BOTCLIP;//CONTENTS_SOLID; ent->takedamage = qtrue; G_SetOrigin( ent, ent->s.origin ); @@ -2506,7 +2510,7 @@ void SP_misc_crystal_crate( gentity_t *ent ) VectorSet( ent->maxs, 34, 34, 44 ); //Blocks movement - ent->contents = CONTENTS_BODY|CONTENTS_MONSTERCLIP|CONTENTS_BOTCLIP;//Was CONTENTS_SOLID, but only architecture should be this + ent->contents = CONTENTS_SOLID|CONTENTS_OPAQUE|CONTENTS_BODY|CONTENTS_MONSTERCLIP|CONTENTS_BOTCLIP;//Was CONTENTS_SOLID, but only architecture should be this if ( ent->spawnflags & 1 ) // non-solid { // Override earlier contents flag... @@ -2675,7 +2679,7 @@ void misc_atst_use( gentity_t *self, gentity_t *other, gentity_t *activator ) activator->activator = NULL; self->s.eFlags &= ~EF_NODRAW; self->svFlags &= ~SVF_NOCLIENT; - self->contents = CONTENTS_BODY|CONTENTS_MONSTERCLIP|CONTENTS_BOTCLIP; + self->contents = CONTENTS_SOLID|CONTENTS_BODY|CONTENTS_MONSTERCLIP|CONTENTS_BOTCLIP; self->takedamage = qtrue; //transfer armor tempHealth = self->health; @@ -2734,7 +2738,7 @@ void SP_misc_atst_drivable( gentity_t *ent ) VectorSet( ent->mins, ATST_MINS0, ATST_MINS1, ATST_MINS2 ); VectorSet( ent->maxs, ATST_MAXS0, ATST_MAXS1, ATST_MAXS2 ); - ent->contents = CONTENTS_BODY|CONTENTS_MONSTERCLIP|CONTENTS_BOTCLIP; + ent->contents = CONTENTS_SOLID|CONTENTS_BODY|CONTENTS_MONSTERCLIP|CONTENTS_BOTCLIP; ent->flags |= FL_SHIELDED; ent->takedamage = qtrue; if ( !ent->health ) diff --git a/code/game/g_misc_model.cpp b/code/game/g_misc_model.cpp index 2c550d7..bc262b2 100644 --- a/code/game/g_misc_model.cpp +++ b/code/game/g_misc_model.cpp @@ -778,7 +778,7 @@ void SP_misc_model_cargo_small( gentity_t *ent ) G_SpawnInt( "health", "25", &ent->health ); - SetMiscModelDefaults( ent, useF_NULL, "11", CONTENTS_SOLID, NULL, qtrue, NULL ); + SetMiscModelDefaults( ent, useF_NULL, "11", CONTENTS_SOLID|CONTENTS_OPAQUE|CONTENTS_BODY|CONTENTS_MONSTERCLIP|CONTENTS_BOTCLIP, NULL, qtrue, NULL ); ent->s.modelindex2 = G_ModelIndex("/models/map_objects/kejim/cargo_small.md3"); // Precache model // we only take damage from a heavy weapon class missile diff --git a/code/game/g_missile.cpp b/code/game/g_missile.cpp index 69fe295..903b3c8 100644 --- a/code/game/g_missile.cpp +++ b/code/game/g_missile.cpp @@ -18,40 +18,71 @@ extern qboolean PM_SaberInTransitionAny( int move ); extern qboolean PM_SaberInSpecialAttack( int anim ); //------------------------------------------------------------------------- +#ifdef _IMMERSION +void G_MissileBounceEffect( gentity_t *ent, int hitEntNum, vec3_t org, vec3_t dir ) +#else void G_MissileBounceEffect( gentity_t *ent, vec3_t org, vec3_t dir ) +#endif // _IMMERSION { //FIXME: have an EV_BOUNCE_MISSILE event that checks the s.weapon and does the appropriate effect switch( ent->s.weapon ) { case WP_BOWCASTER: +#ifdef _IMMERSION + G_PlayEffect( "bowcaster/deflect", hitEntNum, ent->currentOrigin, dir ); +#else G_PlayEffect( "bowcaster/deflect", ent->currentOrigin, dir ); +#endif // _IMMERSION break; case WP_BLASTER: case WP_BRYAR_PISTOL: +#ifdef _IMMERSION + G_PlayEffect( "blaster/deflect", hitEntNum, ent->currentOrigin, dir ); +#else G_PlayEffect( "blaster/deflect", ent->currentOrigin, dir ); +#endif // _IMMERSION break; default: { gentity_t *tent = G_TempEntity( org, EV_GRENADE_BOUNCE ); VectorCopy( dir, tent->pos1 ); tent->s.weapon = ent->s.weapon; +#ifdef _IMMERSION + if ( hitEntNum != -1 ) + { + tent->s.saberActive = 1; + tent->s.otherEntityNum = hitEntNum; + } +#endif // _IMMERSION } break; } } +#ifdef _IMMERSION +void G_MissileReflectEffect( gentity_t *ent, int hitEntNum, vec3_t org, vec3_t dir ) +#else void G_MissileReflectEffect( gentity_t *ent, vec3_t org, vec3_t dir ) +#endif // _IMMERSION { //FIXME: have an EV_BOUNCE_MISSILE event that checks the s.weapon and does the appropriate effect switch( ent->s.weapon ) { case WP_BOWCASTER: +#ifdef _IMMERSION + G_PlayEffect( "bowcaster/deflect", hitEntNum, ent->currentOrigin, dir ); +#else G_PlayEffect( "bowcaster/deflect", ent->currentOrigin, dir ); +#endif // _IMMERSION break; case WP_BLASTER: case WP_BRYAR_PISTOL: default: +#ifdef _IMMERSION + G_PlayEffect( "blaster/deflect", hitEntNum, ent->currentOrigin, dir ); +#else G_PlayEffect( "blaster/deflect", ent->currentOrigin, dir ); +#endif // _IMMERSION break; } } @@ -614,7 +645,11 @@ void G_MissileImpact( gentity_t *ent, trace_t *trace, int hitLoc=HL_NONE ) { G_MissileAddAlerts( ent ); } +#ifdef _IMMERSION + G_MissileBounceEffect( ent, (other->contents & CONTENTS_LIGHTSABER && !other->owner->s.saberInFlight ? other->owner->s.number : -1), trace->endpos, trace->plane.normal ); +#else G_MissileBounceEffect( ent, trace->endpos, trace->plane.normal ); +#endif // _IMMERSION return; } @@ -635,7 +670,12 @@ void G_MissileImpact( gentity_t *ent, trace_t *trace, int hitLoc=HL_NONE ) { ent->s.eFlags &= ~EF_BOUNCE_SHRAPNEL; } +#ifdef _IMMERSION + // might deflect flechette spam in bespin_platform.bsp + G_MissileBounceEffect( ent, (other->contents & CONTENTS_LIGHTSABER && !other->owner->s.saberInFlight ? other->owner->s.number : -1), trace->endpos, trace->plane.normal ); +#else G_MissileBounceEffect( ent, trace->endpos, trace->plane.normal ); +#endif // _IMMERSION return; } } @@ -710,14 +750,22 @@ void G_MissileImpact( gentity_t *ent, trace_t *trace, int hitLoc=HL_NONE ) //do the effect VectorCopy( ent->s.pos.trDelta, diff ); VectorNormalize( diff ); +#ifdef _IMMERSION + G_MissileReflectEffect( ent, other->owner->s.number, trace->endpos, trace->plane.normal ); +#else G_MissileReflectEffect( ent, trace->endpos, trace->plane.normal ); +#endif // _IMMERSION return; } } } else {//still do the bounce effect +#ifdef _IMMERSION + G_MissileReflectEffect( ent, other->owner->s.number, trace->endpos, trace->plane.normal ); +#else G_MissileReflectEffect( ent, trace->endpos, trace->plane.normal ); +#endif // _IMMERSION } } diff --git a/code/game/g_mover.cpp b/code/game/g_mover.cpp index d77f8db..b4ea063 100644 --- a/code/game/g_mover.cpp +++ b/code/game/g_mover.cpp @@ -1843,6 +1843,37 @@ void Reached_Train( gentity_t *ent ) { ent->s.apos.trType = TR_NONLINEAR_STOP; } } + else + { + if (( next->spawnflags & 4 )) + {//yaw + vec3_t angs; + + vectoangles( move, angs ); + AnglesSubtract( angs, ent->currentAngles, angs ); + + for ( int i = 0; i < 3; i++ ) + { + AngleNormalize360( angs[i] ); + } + VectorCopy( ent->currentAngles, ent->s.apos.trBase ); + ent->s.apos.trDelta[YAW] = angs[YAW] * 0.5f; + if (( next->spawnflags & 8 )) + {//roll, too + ent->s.apos.trDelta[ROLL] = angs[YAW] * -0.1f; + } + ent->s.apos.trTime = level.time; + ent->s.apos.trDuration = 2000; + if ( ent->alt_fire ) + { + ent->s.apos.trType = TR_LINEAR_STOP; + } + else + { + ent->s.apos.trType = TR_NONLINEAR_STOP; + } + } + } // This is for the tie fighter shooting gallery on doom detention, you could see them waiting under the bay, but the architecture couldn't easily be changed.. if (( next->spawnflags & 2 )) @@ -1942,7 +1973,7 @@ void Think_SetupTrainTargets( gentity_t *ent ) { -/*QUAKED path_corner (.5 .3 0) (-8 -8 -8) (8 8 8) TURN_TRAIN INVISIBLE +/*QUAKED path_corner (.5 .3 0) (-8 -8 -8) (8 8 8) TURN_TRAIN INVISIBLE YAW_TRAIN ROLL_TRAIN TURN_TRAIN func_train moving on this path will turn to face the next path_corner within 2 seconds INVISIBLE - train will become invisible ( but still solid ) when it reaches this path_corner. @@ -2031,7 +2062,7 @@ void SP_func_train (gentity_t *self) { { if ( VALIDSTRING( noise ) ) { - self->s.loopSound = G_SoundIndex( noise ); + self->s.loopSound = cgi_S_RegisterSound( noise );//G_SoundIndex( noise ); } } diff --git a/code/game/g_nav.cpp b/code/game/g_nav.cpp index a91f2bb..665e6ca 100644 --- a/code/game/g_nav.cpp +++ b/code/game/g_nav.cpp @@ -11,12 +11,15 @@ CNavigator navigator; extern qboolean G_EntIsUnlockedDoor( int entityNum ); extern qboolean G_EntIsDoor( int entityNum ); +extern qboolean G_EntIsBreakable( int entityNum ); +extern qboolean G_EntIsRemovableUsable( int entNum ); extern qboolean G_FindClosestPointOnLineSegment( const vec3_t start, const vec3_t end, const vec3_t from, vec3_t result ); extern void G_AddVoiceEvent( gentity_t *self, int event, int speakDebounceTime ); //For debug graphics extern void CG_Line( vec3_t start, vec3_t end, vec3_t color, float alpha ); extern void CG_Cube( vec3_t mins, vec3_t maxs, vec3_t color, float alpha ); extern void CG_CubeOutline( vec3_t mins, vec3_t maxs, int time, unsigned int color, float alpha ); +extern qboolean FlyingCreature( gentity_t *ent ); qboolean NAV_CheckAhead( gentity_t *self, vec3_t end, trace_t &trace, int clipmask ); void NAV_StoreWaypoint( gentity_t *ent ); @@ -130,7 +133,7 @@ NAV_HitNavGoal ------------------------- */ -qboolean NAV_HitNavGoal( vec3_t point, vec3_t mins, vec3_t maxs, vec3_t dest, int radius ) +qboolean NAV_HitNavGoal( vec3_t point, vec3_t mins, vec3_t maxs, vec3_t dest, int radius, qboolean flying ) { vec3_t dmins, dmaxs, pmins, pmaxs; @@ -141,8 +144,20 @@ qboolean NAV_HitNavGoal( vec3_t point, vec3_t mins, vec3_t maxs, vec3_t dest, in // a radius manually set! We can't do the smaller navgoals against // walls to get around this because player-sized traces to them // from angles will not work... - MCG - //FIXME: Allow for a little z difference? - return ( DistanceSquared(dest, point) <= (radius*radius) ); + if ( !flying ) + {//Allow for a little z difference + vec3_t diff; + VectorSubtract( point, dest, diff ); + if ( fabs(diff[2]) <= 24 ) + { + diff[2] = 0; + } + return ( VectorLengthSquared( diff ) <= (radius*radius) ); + } + else + {//must hit exactly + return ( DistanceSquared(dest, point) <= (radius*radius) ); + } //There is probably a better way to do this, either by preserving the original // mins and maxs of the navgoal and doing this check ONLY if the radius // is non-zero (like the original implementation) or some boolean to @@ -241,7 +256,7 @@ qboolean NAV_ClearPathToPoint( gentity_t *self, vec3_t pmins, vec3_t pmaxs, vec3 } //Okay, didn't get all the way there, let's see if we got close enough: - if ( NAV_HitNavGoal( self->currentOrigin, self->owner->mins, self->owner->maxs, trace.endpos, NPCInfo->goalRadius ) ) + if ( NAV_HitNavGoal( self->currentOrigin, self->owner->mins, self->owner->maxs, trace.endpos, NPCInfo->goalRadius, FlyingCreature( self->owner ) ) ) { return qtrue; } @@ -827,7 +842,7 @@ qboolean NAV_TestForBlocked( gentity_t *self, gentity_t *goal, gentity_t *blocke if ( blocker->s.eType == ET_ITEM ) return qfalse; - if ( NAV_HitNavGoal( blocker->currentOrigin, blocker->mins, blocker->maxs, goal->currentOrigin, 12 ) ) + if ( NAV_HitNavGoal( blocker->currentOrigin, blocker->mins, blocker->maxs, goal->currentOrigin, 12, qfalse ) ) { flags |= NIF_BLOCKED; @@ -940,19 +955,20 @@ int NAV_TestBestNode( gentity_t *self, int startID, int endID, qboolean failEdge } //See if we're too far above - if ( fabs( self->currentOrigin[2] - end[2] ) > 48 ) + if ( self->s.weapon != WP_SABER && fabs( self->currentOrigin[2] - end[2] ) > 48 ) { - return startID; } + else + { + //This is a work around + float radius = ( self->maxs[0] > self->maxs[1] ) ? self->maxs[0] : self->maxs[1]; + float dist = Distance( self->currentOrigin, end ); + float tFrac = 1.0f - ( radius / dist ); - //This is a work around - float radius = ( self->maxs[0] > self->maxs[1] ) ? self->maxs[0] : self->maxs[1]; - float dist = Distance( self->currentOrigin, end ); - float tFrac = 1.0f - ( radius / dist ); - - if ( trace.fraction >= tFrac ) - {//it's clear - return endID; + if ( trace.fraction >= tFrac ) + {//it's clear + return endID; + } } //Do a special check for doors @@ -971,7 +987,13 @@ int NAV_TestBestNode( gentity_t *self, int startID, int endID, qboolean failEdge return startID; } //we can keep heading to the door, it should open - return endID; + if ( self->s.weapon != WP_SABER && fabs( self->currentOrigin[2] - end[2] ) > 48 ) + {//too far above + } + else + { + return endID; + } } else if ( G_EntIsDoor( blocker->s.number ) ) {//a locked door! @@ -981,6 +1003,30 @@ int NAV_TestBestNode( gentity_t *self, int startID, int endID, qboolean failEdge navigator.AddFailedEdge( self->s.number, startID, endID ); } } + else if ( G_EntIsBreakable( blocker->s.number ) ) + {//do same for breakable brushes/models/glass? + //path is blocked by a breakable, mark it as such if instructed to do so + if ( failEdge ) + { + navigator.AddFailedEdge( self->s.number, startID, endID ); + } + } + else if ( G_EntIsRemovableUsable( blocker->s.number ) ) + {//and removable usables + //path is blocked by a removable usable, mark it as such if instructed to do so + if ( failEdge ) + { + navigator.AddFailedEdge( self->s.number, startID, endID ); + } + } + else if ( blocker->targetname && blocker->s.solid == SOLID_BMODEL && ((blocker->contents&CONTENTS_MONSTERCLIP)|| (blocker->contents&CONTENTS_BOTCLIP)) ) + {//some other kind of do not enter entity brush that will probably be removed + //path is blocked by a removable brushent, mark it as such if instructed to do so + if ( failEdge ) + { + navigator.AddFailedEdge( self->s.number, startID, endID ); + } + } } } //path is blocked @@ -1287,7 +1333,7 @@ radius - how far from the navgoal an ent can be before it thinks it reached it - void SP_waypoint_navgoal( gentity_t *ent ) { - int radius = ( ent->radius ) ? ((int)(ent->radius)|NAVGOAL_USE_RADIUS) : 12; + int radius = ( ent->radius ) ? (((int)ent->radius)|NAVGOAL_USE_RADIUS) : 12; VectorSet( ent->mins, -16, -16, -24 ); VectorSet( ent->maxs, 16, 16, 32 ); diff --git a/code/game/g_navigator.cpp b/code/game/g_navigator.cpp index ffaaaa2..398054b 100644 --- a/code/game/g_navigator.cpp +++ b/code/game/g_navigator.cpp @@ -17,6 +17,7 @@ extern qboolean G_EntIsBreakable( int entityNum ); extern qboolean G_EntIsRemovableUsable( int entNum ); extern cvar_t *d_altRoutes; +extern cvar_t *d_patched; static vec3_t wpMaxs = { 16, 16, 32 }; @@ -1765,6 +1766,28 @@ qboolean CNavigator::NodeFailed( gentity_t *ent, int nodeID ) return qfalse; } +qboolean CNavigator::NodesAreNeighbors( int startID, int endID ) +{//See if these 2 are neighbors + if ( startID == endID ) + { + return qfalse; + } + + CNode *start = m_nodes[startID]; + int nextID = -1; + //NOTE: we only check start because we assume all connections are 2-way + for ( int i = 0; i < start->GetNumEdges(); i++ ) + { + nextID = start->GetEdge(i); + if ( nextID == endID ) + { + return qtrue; + } + } + //not neighbors + return qfalse; +} + void CNavigator::ClearFailedEdge( failedEdge_t *failedEdge ) { if ( !failedEdge ) @@ -1863,6 +1886,14 @@ void CNavigator::AddFailedEdge( int entID, int startID, int endID ) if ( m_nodes.size() == 0 ) return; + if ( d_patched->integer ) + {//use patch-style navigation + if ( startID == endID ) + {//not an edge! + return; + } + } + //Validate the ent number if ( ( entID < 0 ) || ( entID > ENTITYNUM_NONE ) ) { @@ -1996,7 +2027,7 @@ qboolean CNavigator::CheckFailedEdge( failedEdge_t *failedEdge ) gentity_t *ent = (failedEdge->entIDentID]:NULL; int hitEntNum; - if ( !ent ) + if ( !ent || !ent->inuse || !ent->client || ent->health <= 0 ) { VectorSet( mins, DEFAULT_MINS_0, DEFAULT_MINS_1, DEFAULT_MINS_2+STEPSIZE ); VectorSet( maxs, DEFAULT_MAXS_0, DEFAULT_MAXS_1, DEFAULT_MAXS_2 ); diff --git a/code/game/g_navigator.h b/code/game/g_navigator.h index 51595ab..3b474be 100644 --- a/code/game/g_navigator.h +++ b/code/game/g_navigator.h @@ -185,6 +185,7 @@ public: void CheckFailedNodes( gentity_t *ent ); void AddFailedNode( gentity_t *ent, int nodeID ); qboolean NodeFailed( gentity_t *ent, int nodeID ); + qboolean NodesAreNeighbors( int startID, int endID ); void ClearFailedEdge( failedEdge_t *failedEdge ); void ClearAllFailedEdges( void ); qboolean EdgeFailed( int startID, int endID ); diff --git a/code/game/g_navnew.cpp b/code/game/g_navnew.cpp index 1489b27..7c62bb0 100644 --- a/code/game/g_navnew.cpp +++ b/code/game/g_navnew.cpp @@ -9,6 +9,9 @@ //Global navigator extern CNavigator navigator; extern cvar_t *d_altRoutes; +extern cvar_t *d_patched; +extern vec3_t playerMins; +extern vec3_t playerMaxs; qboolean NAV_CheckAhead( gentity_t *self, vec3_t end, trace_t &trace, int clipmask ); qboolean NAV_TestForBlocked( gentity_t *self, gentity_t *goal, gentity_t *blocker, float distance, int &flags ); @@ -137,6 +140,10 @@ void NAVNEW_PushBlocker( gentity_t *self, gentity_t *blocker, vec3_t right, qboo if ( leftSucc == 0.0f && rightSucc == 0.0f ) {//both sides failed + if ( d_patched->integer ) + {//use patch-style navigation + blocker->client->pushVecTime = 0; + } return; } @@ -462,6 +469,10 @@ qboolean NAVNEW_AvoidCollision( gentity_t *self, gentity_t *goal, navInfo_t &inf { if ( self->NPC->consecutiveBlockedMoves > blockedMovesLimit ) { + if ( d_patched->integer ) + {//use patch-style navigation + self->NPC->consecutiveBlockedMoves++; + } NPC_SetBlocked( self, info.blocker ); return qfalse; } @@ -506,6 +517,55 @@ qboolean NAVNEW_AvoidCollision( gentity_t *self, gentity_t *goal, navInfo_t &inf return qtrue; } +qboolean NAVNEW_TestNodeConnectionBlocked( int wp1, int wp2, gentity_t *ignoreEnt, int goalEntNum, qboolean checkWorld, qboolean checkEnts ) +{//see if the direct path between 2 nodes is blocked by architecture or an ent + vec3_t pos1, pos2, mins, maxs; + trace_t trace; + int clipmask = MASK_NPCSOLID|CONTENTS_BOTCLIP; + int ignoreEntNum; + + if ( !checkWorld && !checkEnts ) + {//duh, nothing to trace against + return qfalse; + } + navigator.GetNodePosition( wp1, pos1 ); + navigator.GetNodePosition( wp2, pos2 ); + + if ( !checkWorld ) + { + clipmask &= ~(CONTENTS_SOLID|CONTENTS_MONSTERCLIP|CONTENTS_BOTCLIP); + } + if ( !checkEnts ) + { + clipmask &= ~CONTENTS_BODY; + } + if ( ignoreEnt ) + { + VectorCopy( ignoreEnt->mins, mins ); + VectorCopy( ignoreEnt->maxs, maxs ); + ignoreEntNum = ignoreEnt->s.number; + } + else + { + VectorCopy( playerMins, mins ); + VectorCopy( playerMaxs, mins ); + ignoreEntNum = ENTITYNUM_NONE; + } + mins[2] += STEPSIZE; + //don't let box get inverted + if ( mins[2] > maxs[2] ) + { + mins[2] = maxs[2]; + } + + gi.trace( &trace, pos1, mins, maxs, pos2, ignoreEntNum, clipmask ); + if ( trace.fraction >= 1.0f || trace.entityNum == goalEntNum ) + {//clear or hit goal + return qfalse; + } + //hit something we weren't supposed to + return qtrue; +} /* ------------------------- NAVNEW_MoveToGoal @@ -594,7 +654,7 @@ int NAVNEW_MoveToGoal( gentity_t *self, navInfo_t &info ) {//we haven't already tried to go straight to goal or goal's wp if ( bestNode == self->NPC->goalEntity->waypoint ) {//our bestNode is the goal's wp - if ( NAV_HitNavGoal( self->currentOrigin, self->mins, self->maxs, origin, navigator.GetNodeRadius( bestNode ) ) ) + if ( NAV_HitNavGoal( self->currentOrigin, self->mins, self->maxs, origin, navigator.GetNodeRadius( bestNode ), FlyingCreature( self ) ) ) {//we're in the goal's wp inGoalWP = qtrue; //we're in the goalEntity's waypoint already @@ -612,7 +672,7 @@ int NAVNEW_MoveToGoal( gentity_t *self, navInfo_t &info ) {//we know it's clear or architecture //navigator.GetNodePosition( self->waypoint, origin ); /* - if ( NAV_HitNavGoal( self->currentOrigin, self->mins, self->maxs, origin, navigator.GetNodeRadius( bestNode ) ) ) + if ( NAV_HitNavGoal( self->currentOrigin, self->mins, self->maxs, origin, navigator.GetNodeRadius( bestNode ), FlyingCreature( self ) ) ) {//we're in the wp we're heading for already inBestWP = qtrue; } @@ -695,7 +755,15 @@ int NAVNEW_MoveToGoal( gentity_t *self, navInfo_t &info ) {//we headed toward our next waypoint (instead of our waypoint) and failed if ( d_altRoutes->integer ) {//mark this edge failed and try our waypoint - navigator.AddFailedEdge( self->s.number, self->waypoint, bestNode ); + //NOTE: don't assume there is something blocking the direct path + // between my waypoint and the bestNode... I could be off + // that path because of collision avoidance... + if ( d_patched->integer &&//use patch-style navigation + ( !navigator.NodesAreNeighbors( self->waypoint, bestNode ) + || NAVNEW_TestNodeConnectionBlocked( self->waypoint, bestNode, self, self->NPC->goalEntity->s.number, qfalse, qtrue ) ) ) + {//the direct path between these 2 nodes is blocked by an ent + navigator.AddFailedEdge( self->s.number, self->waypoint, bestNode ); + } bestNode = self->waypoint; } else diff --git a/code/game/g_public.h b/code/game/g_public.h index 9973e1f..4b2ca47 100644 --- a/code/game/g_public.h +++ b/code/game/g_public.h @@ -2,7 +2,7 @@ #define __G_PUBLIC_H__ // g_public.h -- game module information visible to server -#define GAME_API_VERSION 6 +#define GAME_API_VERSION 7 // entity->svFlags // the server does not know how to interpret most of the values diff --git a/code/game/g_roff.cpp b/code/game/g_roff.cpp index a261b40..a6b08c5 100644 --- a/code/game/g_roff.cpp +++ b/code/game/g_roff.cpp @@ -480,7 +480,8 @@ void G_Roff( gentity_t *ent ) #ifdef _DEBUG if ( g_developer->integer ) { - Com_Printf( S_COLOR_GREEN"ROFF dat: o:<%.2f %.2f %.2f> a:<%.2f %.2f %.2f>\n", + Com_Printf( S_COLOR_GREEN"ROFF dat: num: %d o:<%.2f %.2f %.2f> a:<%.2f %.2f %.2f>\n", + ent->roff_ctr, org[0], org[1], org[2], ang[0], ang[1], ang[2] ); } @@ -527,7 +528,6 @@ void G_Roff( gentity_t *ent ) // Store what the next apos->trBase should be VectorAdd( ent->pos2, ang, ent->pos2 ); - // Set up the origin interpolation //------------------------------------- VectorScale( org, roff->mLerp, ent->s.pos.trDelta ); @@ -540,6 +540,15 @@ void G_Roff( gentity_t *ent ) //make it true linear... FIXME: sticks around after ROFF is done, but do we really care? ent->alt_fire = qtrue; + + if ( !ent->e_ThinkFunc + && ent->s.eType != ET_MISSILE + && ent->s.eType != ET_ITEM + && ent->s.eType != ET_MOVER ) + {//will never set currentAngles & currentOrigin itself + EvaluateTrajectory( &ent->s.apos, level.time, ent->currentAngles ); + EvaluateTrajectory( &ent->s.pos, level.time, ent->currentOrigin ); + } } // See if the ROFF playback is done diff --git a/code/game/g_savegame.cpp b/code/game/g_savegame.cpp index dbedf71..f672f7f 100644 --- a/code/game/g_savegame.cpp +++ b/code/game/g_savegame.cpp @@ -90,7 +90,6 @@ field_t savefields_gNPC[] = field_t savefields_LevelLocals[] = { {strLLOFS(locationHead), F_GENTITY}, -// {strLLOFS(bodyQue), F_BODYQUEUE}, - MCG {strLLOFS(alertEvents), F_ALERTEVENT}, {strLLOFS(groups), F_AIGROUPS}, {NULL, 0, F_IGNORE} @@ -1015,10 +1014,10 @@ void ReadLevel(qboolean qbAutosave, qboolean qbLoadTransition) gi.ReadFromSaveGame('DONE', &iDONE, sizeof(iDONE)); } - +extern int killPlayerTimer; qboolean GameAllowedToSaveHere(void) { - return !in_camera; + return (!in_camera&&!killPlayerTimer); } //////////////////// eof ///////////////////// diff --git a/code/game/g_shared.h b/code/game/g_shared.h index c7e5aaf..90aff29 100644 --- a/code/game/g_shared.h +++ b/code/game/g_shared.h @@ -80,9 +80,9 @@ typedef enum //# material_e } material_t; //===From cg_local.h================================================ -#define DEFAULT_HEADMODEL "munroscav" -#define DEFAULT_TORSOMODEL "imperial/raider" -#define DEFAULT_LEGSMODEL "imperial/raider" +#define DEFAULT_HEADMODEL "" +#define DEFAULT_TORSOMODEL "" +#define DEFAULT_LEGSMODEL "mouse" // each client has an associated clientInfo_t // that contains media references necessary to present the @@ -871,6 +871,14 @@ typedef struct weaponInfo_s { sfxHandle_t selectSound; // sound played when weapon is selected +#ifdef _IMMERSION + ffHandle_t firingForce; + ffHandle_t altFiringForce; + ffHandle_t stopForce; + ffHandle_t chargeForce; + ffHandle_t altChargeForce; + ffHandle_t selectForce; +#endif // _IMMERSION } weaponInfo_t; extern sfxHandle_t CAS_GetBModelSound( const char *name, int stage ); diff --git a/code/game/g_target.cpp b/code/game/g_target.cpp index 2e21377..137a169 100644 --- a/code/game/g_target.cpp +++ b/code/game/g_target.cpp @@ -903,7 +903,14 @@ extern void G_ChangeMap (const char *mapname, const char *spawntarget, qboolean void target_level_change_use(gentity_t *self, gentity_t *other, gentity_t *activator) { G_ActivateBehavior(self,BSET_USE); - G_ChangeMap( self->message, self->target, (self->spawnflags&1) ); + if( self->message && !Q_stricmp( "disconnect", self->message ) ) + { + gi.SendConsoleCommand( "disconnect\n"); + } + else + { + G_ChangeMap( self->message, self->target, (self->spawnflags&1) ); + } if (self->spawnflags&2) //HIDEINFO { gi.cvar_set("cg_missionstatusscreen", "0"); diff --git a/code/game/g_turret.cpp b/code/game/g_turret.cpp index f8dfcb3..80a4ab0 100644 --- a/code/game/g_turret.cpp +++ b/code/game/g_turret.cpp @@ -126,7 +126,7 @@ static void turret_fire ( gentity_t *ent, vec3_t start, vec3_t dir ) bolt->splashDamage = 0; bolt->splashRadius = 0; bolt->methodOfDeath = MOD_ENERGY; - bolt->clipmask = MASK_SHOT; + bolt->clipmask = MASK_SHOT | CONTENTS_LIGHTSABER; bolt->trigger_formation = qfalse; // don't draw tail on first frame VectorSet( bolt->maxs, 1.5, 1.5, 1.5 ); @@ -1036,7 +1036,7 @@ void pas_fire( gentity_t *ent ) bolt->splashDamage = 0; bolt->splashRadius = 0; bolt->methodOfDeath = MOD_ENERGY; - bolt->clipmask = MASK_SHOT; + bolt->clipmask = MASK_SHOT | CONTENTS_LIGHTSABER; VectorSet( bolt->maxs, 1, 1, 1 ); VectorScale( bolt->maxs, -1, bolt->mins ); @@ -1996,6 +1996,10 @@ void panel_turret_think( gentity_t *self ) cg.overrides.active &= ~CG_OVERRIDE_FOV; cg.overrides.fov = 0; + if ( ucmd->upmove > 0 ) + {//stop player from doing anything for a half second after + player->aimDebounceTime = level.time + 500; + } // can be drawn // self->s.eFlags &= ~EF_NODRAW; diff --git a/code/game/g_utils.cpp b/code/game/g_utils.cpp index c93eaf2..c67bbce 100644 --- a/code/game/g_utils.cpp +++ b/code/game/g_utils.cpp @@ -150,6 +150,37 @@ void G_PlayEffect( const char *name, int clientNum ) VectorScale( tent->maxs, -1, tent->mins ); } +#ifdef _IMMERSION +// Play an effect at a position on an entity. +// Mostly for G_MissileBounceEffect so we can play an effect on the bouncee. +//----------------------------- +void G_PlayEffect( int fxID, int clientNum, vec3_t origin, vec3_t fwd ) +{ + gentity_t *tent; + vec3_t temp; + + tent = G_TempEntity( origin, EV_PLAY_EFFECT ); + tent->s.eventParm = fxID; + if ( clientNum != -1 ) + { + tent->s.saberActive = 1; + tent->s.otherEntityNum = clientNum; + } + VectorSet( tent->maxs, FX_ENT_RADIUS, FX_ENT_RADIUS, FX_ENT_RADIUS ); + VectorScale( tent->maxs, -1, tent->mins ); + VectorCopy( fwd, tent->s.angles ); + + // Assume angles, we'll do a cross product on the other end to finish up + MakeNormalVectors( fwd, tent->s.angles2, temp ); +} + +//----------------------------- +void G_PlayEffect( const char *name, int clientNum, vec3_t origin, vec3_t fwd ) +{ + G_PlayEffect( G_EffectIndex( name ), clientNum, origin, fwd ); +} + +#endif // _IMMERSION //----------------------------- void G_PlayEffect( int fxID, vec3_t origin, vec3_t axis[3] ) { @@ -1025,6 +1056,67 @@ void G_SoundBroadcast( gentity_t *ent, int soundIndex ) //============================================================================== +#ifdef _IMMERSION +int G_ForceIndex( const char *name, int channel ) +{ + if ( channel >= 0 && channel < FF_CHANNEL_MAX ) + { + // no point in storing a name with a bogus channel + // (registering an effect on multiple channels will eat up memory) + char temp[512]; + sprintf( temp, "%d,%s", channel, name ); + return G_FindConfigstringIndex ( temp, CS_FORCES, MAX_FORCES, qtrue ); + } + + return 0; +} + +gentity_t *G_OwnerClient( gentity_t *ent ) +{ + // This test is not adequate... should check for the following... + // 1) owned entity is touching client entity + // 2) owned entity is a weapon being used by client + for + ( + ; ent + && !ent->client + ; ent = ent->owner + ); + + return ent; +} + +void G_Force( gentity_t *ent, int forceIndex ) +{ + gentity_t *client = G_OwnerClient( ent ); + if ( client ) + { + G_AddEvent( client, EV_ENTITY_FORCE, forceIndex ); + } +} + +void G_ForceArea( gentity_t *ent, int forceIndex ) +{ + gentity_t *te; + + te = G_TempEntity( ent->s.origin, EV_AREA_FORCE ); + te->s.eventParm = forceIndex; +} + +void G_ForceBroadcast( gentity_t *ent, int forceIndex ) +{ + gentity_t *te; + + te = G_TempEntity( ent->s.origin, EV_GLOBAL_FORCE ); + te->s.eventParm = forceIndex; + te->svFlags |= SVF_BROADCAST; +} + +void G_ForceStop( gentity_t *ent, int forceIndex ) +{ + G_AddEvent( ent, EV_FORCE_STOP, forceIndex ); +} +#endif // _IMMERSION /* ================ @@ -1316,12 +1408,17 @@ void TryUse( gentity_t *ent ) */ } +extern int killPlayerTimer; void G_ChangeMap (const char *mapname, const char *spawntarget, qboolean hub) { // gi.Printf("Loading..."); //ignore if player is dead if (g_entities[0].client->ps.pm_type == PM_DEAD) return; + if ( killPlayerTimer ) + {//can't go to next map if your allies have turned on you + return; + } if ( spawntarget == NULL ) { spawntarget = ""; //prevent it from becoming "(null)" diff --git a/code/game/g_weapon.cpp b/code/game/g_weapon.cpp index abc0c6f..475da50 100644 --- a/code/game/g_weapon.cpp +++ b/code/game/g_weapon.cpp @@ -931,7 +931,7 @@ void WP_DisruptorAltFire( gentity_t *ent ) G_PlayEffect( G_EffectIndex( "disruptor/alt_hit" ), tr.endpos, tr.plane.normal ); if ( traceEnt->client && LogAccuracyHit( traceEnt, ent )) - { + {//NOTE: hitting multiple ents can still get you over 100% accuracy ent->client->ps.persistant[PERS_ACCURACY_HITS]++; } @@ -3029,6 +3029,9 @@ void WP_FireStunBaton( gentity_t *ent, qboolean alt_fire ) vec3_t mins, maxs, end, start; G_Sound( ent, G_SoundIndex( "sound/weapons/baton/fire" )); +#ifdef _IMMERSION + G_Force( ent, G_ForceIndex( "fffx/weapons/baton/fire", FF_CHANNEL_WEAPON ) ); +#endif // _IMMERSION VectorCopy( muzzle, start ); WP_TraceSetStart( ent, start, vec3_origin, vec3_origin ); @@ -3798,6 +3801,9 @@ extern void ChangeWeapon( gentity_t *ent, int newWeapon ); #endif G_Sound( self, G_SoundIndex( "sound/weapons/emplaced/emplaced_mount.mp3" )); +#ifdef _IMMERSION + G_Force( self, G_ForceIndex( "fffx/weapons/emplaced/emplaced_mount", FF_CHANNEL_TOUCH ) ); +#endif // _IMMERSION } } diff --git a/code/game/g_weaponLoad.cpp b/code/game/g_weaponLoad.cpp index 5825dd9..5faa59b 100644 --- a/code/game/g_weaponLoad.cpp +++ b/code/game/g_weaponLoad.cpp @@ -134,6 +134,14 @@ void WPN_MissileHitSound(const char **holdBuf); void WPN_AltMissileHitSound(const char **holdBuf); void WPN_MuzzleEffect(const char **holdBuf); void WPN_AltMuzzleEffect(const char **holdBuf); +//#ifdef _IMMERSION +void WPN_FiringFrc(const char **holdBuf); +void WPN_AltFiringFrc(const char **holdBuf); +void WPN_ChargeFrc(const char **holdBuf); +void WPN_AltChargeFrc(const char **holdBuf); +void WPN_StopFrc(const char **holdBuf); +void WPN_SelectFrc(const char **holdBuf); +//#endif // _IMMERSION typedef struct { @@ -181,6 +189,14 @@ wpnParms_t WpnParms[] = "altmissileHitSound", WPN_AltMissileHitSound, "muzzleEffect", WPN_MuzzleEffect, "altmuzzleEffect", WPN_AltMuzzleEffect +//#ifdef _IMMERSION +, "firingForce", WPN_FiringFrc +, "altFiringForce", WPN_AltFiringFrc +, "chargeForce", WPN_ChargeFrc +, "altChargeForce", WPN_AltChargeFrc +, "stopForce", WPN_StopFrc +, "selectForce", WPN_SelectFrc +//#endif // _IMMERSION }; const int WPN_PARM_MAX = sizeof(WpnParms) / sizeof(WpnParms[0]); @@ -535,6 +551,160 @@ void WPN_SelectSnd( const char **holdBuf ) Q_strncpyz( weaponData[wpnParms.weaponNum].selectSnd,tokenStr,len); } +//#ifdef _IMMERSION + +//-------------------------------------------- +void WPN_FiringFrc( const char **holdBuf ) +{ + const char *tokenStr; + int len; + + if ( COM_ParseString( holdBuf,&tokenStr )) + { + return; + } + + len = strlen( tokenStr ); + len++; + + if (len > 64) + { + len = 64; + gi.Printf(S_COLOR_YELLOW"WARNING: firingFrc too long in external WEAPONS.DAT '%s'\n", tokenStr); + } + +#ifdef _IMMERSION + Q_strncpyz( weaponData[wpnParms.weaponNum].firingFrc,tokenStr,len); +#endif +} + +//-------------------------------------------- +void WPN_AltFiringFrc( const char **holdBuf ) +{ + const char *tokenStr; + int len; + + if ( COM_ParseString( holdBuf,&tokenStr )) + { + return; + } + + len = strlen( tokenStr ); + len++; + + if (len > 64) + { + len = 64; + gi.Printf(S_COLOR_YELLOW"WARNING: altFiringFrc too long in external WEAPONS.DAT '%s'\n", tokenStr); + } + +#ifdef _IMMERSION + Q_strncpyz( weaponData[wpnParms.weaponNum].altFiringFrc,tokenStr,len); +#endif +} + +//-------------------------------------------- +void WPN_ChargeFrc( const char **holdBuf ) +{ + const char *tokenStr; + int len; + + if ( COM_ParseString( holdBuf,&tokenStr )) + { + return; + } + + len = strlen( tokenStr ); + len++; + + if (len > 64) + { + len = 64; + gi.Printf(S_COLOR_YELLOW"WARNING: chargeFrc too long in external WEAPONS.DAT '%s'\n", tokenStr); + } + +#ifdef _IMMERSION + Q_strncpyz( weaponData[wpnParms.weaponNum].chargeFrc,tokenStr,len); +#endif +} + +//-------------------------------------------- +void WPN_AltChargeFrc( const char **holdBuf ) +{ + const char *tokenStr; + int len; + + if ( COM_ParseString( holdBuf,&tokenStr )) + { + return; + } + + len = strlen( tokenStr ); + len++; + + if (len > 64) + { + len = 64; + gi.Printf(S_COLOR_YELLOW"WARNING: altChargeFrc too long in external WEAPONS.DAT '%s'\n", tokenStr); + } + +#ifdef _IMMERSION + Q_strncpyz( weaponData[wpnParms.weaponNum].altChargeFrc,tokenStr,len); +#endif +} + +//-------------------------------------------- +void WPN_StopFrc( const char **holdBuf ) +{ + const char *tokenStr; + int len; + + if ( COM_ParseString( holdBuf,&tokenStr )) + { + return; + } + + len = strlen( tokenStr ); + len++; + + if (len > 64) + { + len = 64; + gi.Printf(S_COLOR_YELLOW"WARNING: stopFrc too long in external WEAPONS.DAT '%s'\n", tokenStr); + } + +#ifdef _IMMERSION + Q_strncpyz( weaponData[wpnParms.weaponNum].stopFrc,tokenStr,len); +#endif +} + +//-------------------------------------------- +void WPN_SelectFrc( const char **holdBuf ) +{ + const char *tokenStr; + int len; + + if ( COM_ParseString( holdBuf,&tokenStr )) + { + return; + } + + len = strlen( tokenStr ); + len++; + + if (len > 64) + { + len = 64; + gi.Printf(S_COLOR_YELLOW"WARNING: selectFrc too long in external WEAPONS.DAT '%s'\n", tokenStr); + } + +#ifdef _IMMERSION + Q_strncpyz( weaponData[wpnParms.weaponNum].selectFrc,tokenStr,len); +#endif +} + +//#endif // _IMMERSION + //-------------------------------------------- void WPN_FireTime(const char **holdBuf) { diff --git a/code/game/game.dsp b/code/game/game.dsp index 7478572..a9bc87c 100644 --- a/code/game/game.dsp +++ b/code/game/game.dsp @@ -45,7 +45,7 @@ RSC=rc.exe # PROP Ignore_Export_Lib 0 # PROP Target_Dir "." # ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /c -# ADD CPP /nologo /G6 /W4 /GX /Zi /O2 /I "..\ICARUS" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /Yu"g_headers.h" /FD /c +# ADD CPP /nologo /G6 /W4 /GX /Zi /O2 /I "..\ICARUS" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "_IMMERSION" /Yu"g_headers.h" /FD /c # ADD BASE MTL /nologo /D "NDEBUG" /win32 # ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 # ADD BASE RSC /l 0x409 /d "NDEBUG" @@ -69,10 +69,10 @@ LINK32=link.exe # PROP Use_Debug_Libraries 1 # PROP Output_Dir "..\Debug" # PROP Intermediate_Dir "..\Debug\game" -# PROP Ignore_Export_Lib 1 +# PROP Ignore_Export_Lib 0 # PROP Target_Dir "." # ADD BASE CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /c -# ADD CPP /nologo /G6 /W4 /Gm /Gi /GX /ZI /Od /I "..\ICARUS" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FR /Yu"g_headers.h" /FD /c +# ADD CPP /nologo /G6 /W4 /Gm /Gi /GX /ZI /Od /I "..\ICARUS" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "_IMMERSION" /FR /Yu"g_headers.h" /FD /c # ADD BASE MTL /nologo /D "_DEBUG" /win32 # ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 # ADD BASE RSC /l 0x409 /d "_DEBUG" @@ -100,7 +100,7 @@ LINK32=link.exe # PROP Ignore_Export_Lib 0 # PROP Target_Dir "" # ADD BASE CPP /nologo /G6 /W4 /GX /Zi /O2 /I "..\ICARUS" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c -# ADD CPP /nologo /G6 /W4 /GX /O2 /I "..\ICARUS" /D "_WINDOWS" /D "WIN32" /D "NDEBUG" /D "FINAL_BUILD" /Yu"g_headers.h" /FD /c +# ADD CPP /nologo /G6 /W4 /GX /O2 /I "..\ICARUS" /D "NDEBUG" /D "FINAL_BUILD" /D "WIN32" /D "_WINDOWS" /D "_IMMERSION" /Yu"g_headers.h" /FD /c # ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 # ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 # ADD BASE RSC /l 0x409 /d "NDEBUG" @@ -126,10 +126,10 @@ LINK32=link.exe # PROP Use_Debug_Libraries 1 # PROP Output_Dir "..\SHDebug" # PROP Intermediate_Dir "..\SHDebug\game" -# PROP Ignore_Export_Lib 1 +# PROP Ignore_Export_Lib 0 # PROP Target_Dir "" # ADD BASE CPP /nologo /G6 /W4 /Gm /Gi /GX /ZI /Od /I "..\ICARUS" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FR /Yu"g_headers.h" /FD /c -# ADD CPP /nologo /G6 /W4 /Gm /Gi /GX /ZI /Od /I "..\ICARUS" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "MEM_DEBUG" /FR /Yu"g_headers.h" /FD /c +# ADD CPP /nologo /G6 /W4 /Gm /Gi /GX /ZI /Od /I "..\ICARUS" /D "_DEBUG" /D "MEM_DEBUG" /D "WIN32" /D "_WINDOWS" /D "_IMMERSION" /FR /Yu"g_headers.h" /FD /c # ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 # ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 # ADD BASE RSC /l 0x409 /d "_DEBUG" @@ -997,6 +997,14 @@ SOURCE=.\events.h # End Source File # Begin Source File +SOURCE=..\ff\ff.h +# End Source File +# Begin Source File + +SOURCE=..\ff\ff_public.h +# End Source File +# Begin Source File + SOURCE=..\client\fffx.h # End Source File # Begin Source File @@ -1093,6 +1101,10 @@ SOURCE=.\statindex.h # End Source File # Begin Source File +SOURCE=..\qcommon\stripPublic.h +# End Source File +# Begin Source File + SOURCE=.\surfaceflags.h # End Source File # Begin Source File diff --git a/code/game/game.plg b/code/game/game.plg index 529ec50..fe68714 100644 --- a/code/game/game.plg +++ b/code/game/game.plg @@ -6,31 +6,13 @@ --------------------Configuration: game - Win32 Debug--------------------

Command Lines

-Creating temporary file "C:\DOCUME~1\jmonroe\LOCALS~1\Temp\RSP89.tmp" with contents +Creating temporary file "C:\DOCUME~1\jmonroe\LOCALS~1\Temp\RSP4823.tmp" with contents [ -/nologo /G6 /MLd /W4 /Gm /Gi /GX /ZI /Od /I "..\ICARUS" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FR"..\Debug\game/" /Fp"..\Debug\game/game.pch" /Yu"g_headers.h" /Fo"..\Debug\game/" /Fd"..\Debug\game/" /FD /c -"C:\projects\jk2\CODE\Icarus\Sequencer.cpp" -"C:\projects\jk2\CODE\game\g_items.cpp" -"C:\projects\jk2\CODE\game\g_mover.cpp" -"C:\projects\jk2\CODE\game\g_svcmds.cpp" -"C:\projects\jk2\CODE\game\NPC_spawn.cpp" -"C:\projects\jk2\CODE\game\wp_saber.cpp" +/nologo /G6 /MLd /W4 /Gm /Gi /GX /ZI /Od /I "..\ICARUS" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /FR"..\Debug\game/" /Fo"..\Debug\game/" /Fd"..\Debug\game/" /FD /c +"C:\projects\jk2\CODE\game\g_weaponLoad.cpp" ] -Creating command line "cl.exe @C:\DOCUME~1\jmonroe\LOCALS~1\Temp\RSP89.tmp" -Creating temporary file "C:\DOCUME~1\jmonroe\LOCALS~1\Temp\RSP8A.tmp" with contents -[ -/nologo /G6 /MLd /W4 /Gm /Gi /GX /ZI /Od /I "..\ICARUS" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FR"..\Debug\game/" /Fp"..\Debug\game/game.pch" /Yu"common_headers.h" /Fo"..\Debug\game/" /Fd"..\Debug\game/" /FD /c -"C:\projects\jk2\CODE\game\bg_panimate.cpp" -] -Creating command line "cl.exe @C:\DOCUME~1\jmonroe\LOCALS~1\Temp\RSP8A.tmp" -Creating temporary file "C:\DOCUME~1\jmonroe\LOCALS~1\Temp\RSP8B.tmp" with contents -[ -/nologo /G6 /MLd /W4 /Gm /Gi /GX /ZI /Od /I "..\ICARUS" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FR"..\Debug\game/" /Fp"..\Debug\game/game.pch" /Yu"cg_headers.h" /Fo"..\Debug\game/" /Fd"..\Debug\game/" /FD /c -"C:\projects\jk2\CODE\cgame\cg_main.cpp" -"C:\projects\jk2\CODE\cgame\cg_players.cpp" -] -Creating command line "cl.exe @C:\DOCUME~1\jmonroe\LOCALS~1\Temp\RSP8B.tmp" -Creating temporary file "C:\DOCUME~1\jmonroe\LOCALS~1\Temp\RSP8C.tmp" with contents +Creating command line "cl.exe @C:\DOCUME~1\jmonroe\LOCALS~1\Temp\RSP4823.tmp" +Creating temporary file "C:\DOCUME~1\jmonroe\LOCALS~1\Temp\RSP4824.tmp" with contents [ kernel32.lib user32.lib winmm.lib /nologo /base:"0x20000000" /subsystem:windows /dll /incremental:yes /pdb:"..\Debug/jk2gamex86.pdb" /debug /machine:I386 /def:".\game.def" /out:"..\Debug/jk2gamex86.dll" /implib:"..\Debug/jk2gamex86.lib" \projects\jk2\CODE\Debug\game\BlockStream.obj @@ -45,6 +27,7 @@ kernel32.lib user32.lib winmm.lib /nologo /base:"0x20000000" /subsystem:windows \projects\jk2\CODE\Debug\game\bg_slidemove.obj \projects\jk2\CODE\Debug\game\cg_camera.obj \projects\jk2\CODE\Debug\game\cg_consolecmds.obj +\projects\jk2\CODE\Debug\game\cg_credits.obj \projects\jk2\CODE\Debug\game\cg_draw.obj \projects\jk2\CODE\Debug\game\cg_drawtools.obj \projects\jk2\CODE\Debug\game\cg_effects.obj @@ -159,24 +142,13 @@ kernel32.lib user32.lib winmm.lib /nologo /base:"0x20000000" /subsystem:windows \projects\jk2\CODE\Debug\game\tri_coll_test.obj \projects\jk2\CODE\Debug\game\wp_saber.obj ] -Creating command line "link.exe @C:\DOCUME~1\jmonroe\LOCALS~1\Temp\RSP8C.tmp" +Creating command line "link.exe @C:\DOCUME~1\jmonroe\LOCALS~1\Temp\RSP4824.tmp"

Output Window

Compiling... -Sequencer.cpp -g_items.cpp -g_mover.cpp -g_svcmds.cpp -NPC_spawn.cpp -wp_saber.cpp -Generating Code... -Compiling... -bg_panimate.cpp -Compiling... -cg_main.cpp -cg_players.cpp -Generating Code... +g_weaponLoad.cpp Linking... -Creating temporary file "C:\DOCUME~1\jmonroe\LOCALS~1\Temp\RSP90.tmp" with contents + Creating library ..\Debug/jk2gamex86.lib and object ..\Debug/jk2gamex86.exp +Creating temporary file "C:\DOCUME~1\jmonroe\LOCALS~1\Temp\RSP4829.tmp" with contents [ /nologo /o"..\Debug/game.bsc" \projects\jk2\CODE\Debug\game\g_headers.sbr @@ -192,6 +164,7 @@ Creating temporary file "C:\DOCUME~1\jmonroe\LOCALS~1\Temp\RSP90.tmp" with conte \projects\jk2\CODE\Debug\game\bg_slidemove.sbr \projects\jk2\CODE\Debug\game\cg_camera.sbr \projects\jk2\CODE\Debug\game\cg_consolecmds.sbr +\projects\jk2\CODE\Debug\game\cg_credits.sbr \projects\jk2\CODE\Debug\game\cg_draw.sbr \projects\jk2\CODE\Debug\game\cg_drawtools.sbr \projects\jk2\CODE\Debug\game\cg_effects.sbr @@ -304,7 +277,7 @@ Creating temporary file "C:\DOCUME~1\jmonroe\LOCALS~1\Temp\RSP90.tmp" with conte \projects\jk2\CODE\Debug\game\q_shared.sbr \projects\jk2\CODE\Debug\game\tri_coll_test.sbr \projects\jk2\CODE\Debug\game\wp_saber.sbr] -Creating command line "bscmake.exe @C:\DOCUME~1\jmonroe\LOCALS~1\Temp\RSP90.tmp" +Creating command line "bscmake.exe @C:\DOCUME~1\jmonroe\LOCALS~1\Temp\RSP4829.tmp" Creating browse info file...

Output Window

diff --git a/code/game/objectives.h b/code/game/objectives.h index e61dc26..e0fd04a 100644 --- a/code/game/objectives.h +++ b/code/game/objectives.h @@ -69,6 +69,10 @@ typedef enum //# Objective_e ARTUS_DETENTION_OBJ3, //# ARTUS DETENTION DOOM_COMM_OBJ4, //# DOOM COMM - GRAPHICS IN IT. DOOM_SHIELDS_OBJ3, //# DOOM SHIELDS + DEMO_OBJ1, //# DEMO + DEMO_OBJ2, //# DEMO + DEMO_OBJ3, //# DEMO + DEMO_OBJ4, //# DEMO //# #eol MAX_OBJECTIVES, @@ -205,6 +209,10 @@ stringID_table_t objectiveTable [] = ENUM2STRING(ARTUS_DETENTION_OBJ3), //# ARTUS DETENTION ENUM2STRING(DOOM_COMM_OBJ4), //# DOOM COMM - GRAPHICS IN IT. IT MUST BE LAST IN THE LIST ENUM2STRING(DOOM_SHIELDS_OBJ3), //# DOOM SHIELDS + ENUM2STRING(DEMO_OBJ1), //# DEMO + ENUM2STRING(DEMO_OBJ2), //# DEMO + ENUM2STRING(DEMO_OBJ3), //# DEMO + ENUM2STRING(DEMO_OBJ4), //# DEMO //stringID_table_t Must end with a null entry "", NULL diff --git a/code/game/q_shared.h b/code/game/q_shared.h index a688553..a6fd8e1 100644 --- a/code/game/q_shared.h +++ b/code/game/q_shared.h @@ -402,7 +402,8 @@ extern vec4_t colorTable[CT_MAX]; #define Q_COLOR_ESCAPE '^' -#define Q_IsColorString(p) ( p && *(p) == Q_COLOR_ESCAPE && *((p)+1) && *((p)+1) != Q_COLOR_ESCAPE ) +// you MUST have the last bit on here about colour strings being less than 7 or taiwanese strings register as colour!!!! +#define Q_IsColorString(p) ( p && *(p) == Q_COLOR_ESCAPE && *((p)+1) && *((p)+1) != Q_COLOR_ESCAPE && *((p)+1) <= '7' ) #define COLOR_BLACK '0' #define COLOR_RED '1' @@ -1168,6 +1169,9 @@ typedef struct { #define MAX_MODELS 256 // these are sent over the net as 8 bits #define MAX_SOUNDS 256 // so they cannot be blindly increased +#ifdef _IMMERSION +#define MAX_FORCES 96 +#endif // _IMMERSION #define MAX_SUBMODELS 512 // nine bits #define MAX_FX 128 @@ -1202,7 +1206,12 @@ Ghoul2 Insert End #define CS_MODELS 10 #define CS_SOUNDS (CS_MODELS+MAX_MODELS) +#ifdef _IMMERSION +#define CS_FORCES (CS_SOUNDS+MAX_SOUNDS) +#define CS_PLAYERS (CS_FORCES+MAX_FORCES) +#else #define CS_PLAYERS (CS_SOUNDS+MAX_SOUNDS) +#endif // _IMMERSION #define CS_LIGHT_STYLES (CS_PLAYERS+MAX_CLIENTS) #define CS_EFFECTS (CS_LIGHT_STYLES + (MAX_LIGHT_STYLES*3)) /* @@ -1652,5 +1661,8 @@ typedef enum #include "../game/genericparser2.h" +#ifdef _IMMERSION +#include "../ff/ff_public.h" +#endif // _IMMERSION #endif // __Q_SHARED_H diff --git a/code/game/vssver.scc b/code/game/vssver.scc index 5a56596..5e2dcbf 100644 Binary files a/code/game/vssver.scc and b/code/game/vssver.scc differ diff --git a/code/game/weapons.h b/code/game/weapons.h index 384f5d9..ca1adee 100644 --- a/code/game/weapons.h +++ b/code/game/weapons.h @@ -91,6 +91,14 @@ typedef struct weaponData_s char altChargeSnd[64]; // alt sound to start when the weapon initiates the charging sequence char selectSnd[64]; // the sound to play when this weapon gets selected +#ifdef _IMMERSION + char firingFrc[64]; + char altFiringFrc[64]; + char stopFrc[64]; + char chargeFrc[64]; + char altChargeFrc[64]; + char selectFrc[64]; +#endif // _IMMERSION int ammoIndex; // Index to proper ammo slot int ammoLow; // Count when ammo is low diff --git a/code/game/wp_saber.cpp b/code/game/wp_saber.cpp index 7ecdb13..89ac472 100644 --- a/code/game/wp_saber.cpp +++ b/code/game/wp_saber.cpp @@ -37,6 +37,7 @@ extern void G_SetViewEntity( gentity_t *self, gentity_t *viewEntity ); extern qboolean G_ControlledByPlayer( gentity_t *self ); extern void G_AddVoiceEvent( gentity_t *self, int event, int speakDebounceTime ); extern void CG_ChangeWeapon( int num ); +extern void G_AngerAlert( gentity_t *self ); extern void G_ReflectMissile( gentity_t *ent, gentity_t *missile, vec3_t forward ); extern int G_CheckLedgeDive( gentity_t *self, float checkDist, vec3_t checkVel, qboolean tryOpposite, qboolean tryPerp ); extern void G_BounceMissile( gentity_t *ent, trace_t *trace ); @@ -341,6 +342,47 @@ void G_Throw( gentity_t *targ, vec3_t newDir, float push ) } } +int WP_SetSaberModel( gclient_t *client, class_t npcClass ) +{ + if ( client ) + { + switch ( npcClass ) + { + case CLASS_DESANN://Desann + client->ps.saberModel = "models/weapons2/saber_desann/saber_w.glm"; + break; + case CLASS_LUKE://Luke + client->ps.saberModel = "models/weapons2/saber_luke/saber_w.glm"; + break; + case CLASS_KYLE://Kyle NPC and player + client->ps.saberModel = "models/weapons2/saber/saber_w.glm"; + break; + default://reborn and tavion and everyone else + client->ps.saberModel = "models/weapons2/saber_reborn/saber_w.glm"; + break; + } + return ( G_ModelIndex( client->ps.saberModel ) ); + } + else + { + switch ( npcClass ) + { + case CLASS_DESANN://Desann + return ( G_ModelIndex( "models/weapons2/saber_desann/saber_w.glm" ) ); + break; + case CLASS_LUKE://Luke + return ( G_ModelIndex( "models/weapons2/saber_luke/saber_w.glm" ) ); + break; + case CLASS_KYLE://Kyle NPC and player + return ( G_ModelIndex( "models/weapons2/saber/saber_w.glm" ) ); + break; + default://reborn and tavion and everyone else + return ( G_ModelIndex( "models/weapons2/saber_reborn/saber_w.glm" ) ); + break; + } + } +} + void WP_SaberInitBladeData( gentity_t *ent ) { gentity_t *saberent; @@ -442,23 +484,7 @@ void WP_SaberInitBladeData( gentity_t *ent ) Ghoul2 Insert Start */ //FIXME: get saberModel from NPCs.cfg for NPCs? - if ( ent->client->NPC_class == CLASS_DESANN ) - { - ent->client->ps.saberModel = "models/weapons2/saber_desann/saber_w.glm"; - } - else if ( ent->client->NPC_class == CLASS_LUKE ) - { - ent->client->ps.saberModel = "models/weapons2/saber_luke/saber_w.glm"; - } - else if ( ent->client->NPC_class == CLASS_KYLE ) - {//Kyle NPC and player - ent->client->ps.saberModel = "models/weapons2/saber/saber_w.glm"; - } - else - {//reborn and tavion and everyone else - ent->client->ps.saberModel = "models/weapons2/saber_reborn/saber_w.glm"; - } - saberent->s.modelindex = G_ModelIndex( ent->client->ps.saberModel ); + saberent->s.modelindex = WP_SetSaberModel( ent->client, ent->client->NPC_class ); gi.G2API_InitGhoul2Model( saberent->ghoul2, ent->client->ps.saberModel, saberent->s.modelindex ); // set up a bolt on the end so we can get where the sabre muzzle is - we can assume this is always bolt 0 gi.G2API_AddBolt( &saberent->ghoul2[0], "*flash" ); @@ -806,7 +832,7 @@ qboolean WP_SaberApplyDamage( gentity_t *ent, float baseDamage, int baseDFlags, {//already being knocked around dFlags |= DAMAGE_NO_KNOCKBACK; } - if ( g_dismemberment->integer > 3 || g_saberRealisticCombat->integer ) + if ( g_dismemberment->integer >= 11381138 || g_saberRealisticCombat->integer ) { dFlags |= DAMAGE_DISMEMBER; if ( hitDismember[i] ) @@ -1902,7 +1928,7 @@ qboolean WP_SabersCheckLock2( gentity_t *attacker, gentity_t *defender, sabersLo VectorClear( defender->client->ps.velocity ); attacker->client->ps.saberLockTime = defender->client->ps.saberLockTime = level.time + SABER_LOCK_TIME; attacker->client->ps.legsAnimTimer = attacker->client->ps.torsoAnimTimer = defender->client->ps.legsAnimTimer = defender->client->ps.torsoAnimTimer = SABER_LOCK_TIME; - attacker->client->ps.weaponTime = defender->client->ps.weaponTime = SABER_LOCK_TIME; + //attacker->client->ps.weaponTime = defender->client->ps.weaponTime = SABER_LOCK_TIME; attacker->client->ps.saberLockEnemy = defender->s.number; defender->client->ps.saberLockEnemy = attacker->s.number; @@ -3006,18 +3032,18 @@ void WP_SaberDamageTrace( gentity_t *ent ) if ( entAttacking && hitOwnerAttacking && ( entPowerLevel == hitOwnerPowerLevel - || (entPowerLevel > FORCE_LEVEL_2 && hitOwnerPowerLevel > FORCE_LEVEL_2) - || (entPowerLevel < FORCE_LEVEL_3 && hitOwnerPowerLevel < FORCE_LEVEL_3 && hitOwner->client->ps.forcePowerLevel[FP_SABER_OFFENSE] > FORCE_LEVEL_2 ) - || (entPowerLevel < FORCE_LEVEL_2 && hitOwnerPowerLevel < FORCE_LEVEL_3 && hitOwner->client->ps.forcePowerLevel[FP_SABER_OFFENSE] > FORCE_LEVEL_1 ) - || (hitOwnerPowerLevel < FORCE_LEVEL_3 && entPowerLevel < FORCE_LEVEL_3 && ent->client->ps.forcePowerLevel[FP_SABER_OFFENSE] > FORCE_LEVEL_2 ) - || (hitOwnerPowerLevel < FORCE_LEVEL_2 && entPowerLevel < FORCE_LEVEL_3 && ent->client->ps.forcePowerLevel[FP_SABER_OFFENSE] > FORCE_LEVEL_1 )) + || (entPowerLevel > FORCE_LEVEL_2 && hitOwnerPowerLevel > FORCE_LEVEL_2 ) + || (entPowerLevel < FORCE_LEVEL_3 && hitOwnerPowerLevel < FORCE_LEVEL_3 && hitOwner->client->ps.forcePowerLevel[FP_SABER_OFFENSE] > FORCE_LEVEL_2 && Q_irand( 0, 2 )) + || (entPowerLevel < FORCE_LEVEL_2 && hitOwnerPowerLevel < FORCE_LEVEL_3 && hitOwner->client->ps.forcePowerLevel[FP_SABER_OFFENSE] > FORCE_LEVEL_1 && Q_irand( 0, 1 )) + || (hitOwnerPowerLevel < FORCE_LEVEL_3 && entPowerLevel < FORCE_LEVEL_3 && ent->client->ps.forcePowerLevel[FP_SABER_OFFENSE] > FORCE_LEVEL_2 && !Q_irand( 0, 1 )) + || (hitOwnerPowerLevel < FORCE_LEVEL_2 && entPowerLevel < FORCE_LEVEL_3 && ent->client->ps.forcePowerLevel[FP_SABER_OFFENSE] > FORCE_LEVEL_1 && !Q_irand( 0, 1 ))) && WP_SabersCheckLock( ent, hitOwner ) ) { collisionResolved = qtrue; } else if ( hitOwnerAttacking && entDefending - && !Q_irand( 0, 1 ) + && !Q_irand( 0, 2 ) && (ent->client->ps.saberMove != LS_READY || (hitOwnerPowerLevel-ent->client->ps.forcePowerLevel[FP_SABER_DEFENSE]) < Q_irand( -6, 0 ) ) && ((hitOwnerPowerLevel < FORCE_LEVEL_3 && ent->client->ps.forcePowerLevel[FP_SABER_DEFENSE] > FORCE_LEVEL_2 )|| (hitOwnerPowerLevel < FORCE_LEVEL_2 && ent->client->ps.forcePowerLevel[FP_SABER_DEFENSE] > FORCE_LEVEL_1 )|| @@ -3029,7 +3055,7 @@ void WP_SaberDamageTrace( gentity_t *ent ) else if ( entAttacking && hitOwnerDefending ) {//I'm attacking hit, they're parrying qboolean activeDefense = (hitOwner->s.number||g_saberAutoBlocking->integer||hitOwner->client->ps.saberBlockingTime > level.time); - if ( !Q_irand( 0, 1 ) + if ( !Q_irand( 0, 2 ) && activeDefense && (hitOwner->client->ps.saberMove != LS_READY || (entPowerLevel-hitOwner->client->ps.forcePowerLevel[FP_SABER_DEFENSE]) < Q_irand( -6, 0 ) ) && ( ( entPowerLevel < FORCE_LEVEL_3 && hitOwner->client->ps.forcePowerLevel[FP_SABER_DEFENSE] > FORCE_LEVEL_2 ) @@ -3327,11 +3353,39 @@ void WP_SaberDamageTrace( gentity_t *ent ) { if ( deflected ) { +#ifdef _IMMERSION + int index = Q_irand(1,3); + G_Sound( ent, G_SoundIndex( va("sound/weapons/saber/saberbounce%d.wav", index) ) ); + int ff = G_ForceIndex( va("fffx/weapons/saber/saberbounce%d", index), FF_CHANNEL_WEAPON ); + if ( !ent->s.saberInFlight ) + { + G_Force( ent, ff ); + } + if ( hitOwner && !hitOwner->s.saberInFlight ) + { + G_Force( hitOwner, ff ); + } +#else G_Sound( ent, G_SoundIndex( va( "sound/weapons/saber/saberbounce%d.wav", Q_irand(1,3) ) ) ); +#endif // _IMMERSION } else { +#ifdef _IMMERSION + int index = Q_irand(1, 9); + G_Sound( ent, G_SoundIndex( va( "sound/weapons/saber/saberblock%d.wav", index) ) ); + int ff = G_ForceIndex( va("fffx/weapons/saber/saberblock%d", index), FF_CHANNEL_WEAPON ); + if ( !ent->s.saberInFlight ) + { + G_Force( ent, ff ); + } + if ( hitOwner && !hitOwner->s.saberInFlight ) + { + G_Force( hitOwner, ff ); + } +#else G_Sound( ent, G_SoundIndex( va( "sound/weapons/saber/saberblock%d.wav", Q_irand(1, 9) ) ) ); +#endif // _IMMERSION } } G_PlayEffect( "saber_block", saberHitLocation, saberHitNormal ); @@ -3409,7 +3463,21 @@ void WP_SaberDamageTrace( gentity_t *ent ) g_saberFlashTime = level.time-50; G_PlayEffect( "saber_cut", g_saberFlashPos, hitNorm ); } +#ifdef _IMMERSION + int index = Q_irand(1, 9); + G_Sound( ent, G_SoundIndex( va( "sound/weapons/saber/saberblock%d.wav", index ) ) ); + int ff = G_ForceIndex( va("fffx/weapons/saber/saberblock%d", index), FF_CHANNEL_WEAPON ); + if ( !ent->s.saberInFlight ) + { + G_Force( ent, ff ); + } + if ( !g_entities[ent->client->ps.saberLockEnemy].s.saberInFlight ) + { + G_Force( &g_entities[ent->client->ps.saberLockEnemy], ff ); + } +#else G_Sound( ent, G_SoundIndex( va( "sound/weapons/saber/saberblock%d.wav", Q_irand(1, 9) ) ) ); +#endif // _IMMERSION } } @@ -3421,7 +3489,13 @@ void WP_SaberDamageTrace( gentity_t *ent ) gi.Printf( "base damage was %4.2f\n", baseDamage ); } #endif +#ifdef _IMMERSION + int index = Q_irand( 1, 3 ); + G_Sound( ent, G_SoundIndex( va( "sound/weapons/saber/saberhit%d.wav", index ) ) ); + G_Force( ent, G_ForceIndex( va( "fffx/weapons/saber/saberhit%d", index), FF_CHANNEL_WEAPON ) ); +#else G_Sound( ent, G_SoundIndex( va( "sound/weapons/saber/saberhit%d.wav", Q_irand( 1, 3 ) ) ) ); +#endif // _IMMERSION } if ( hit_wall ) @@ -3880,8 +3954,13 @@ void WP_RunSaber( gentity_t *self, gentity_t *saber ) // trace a line from the previous position to the current position, // ignoring interactions with the missile owner + int clipmask = saber->clipmask; + if ( !self || !self->client || self->client->ps.saberLength <= 0 ) + {//don't keep hitting other sabers when turned off + clipmask &= ~CONTENTS_LIGHTSABER; + } gi.trace( &tr, saber->currentOrigin, saber->mins, saber->maxs, origin, - saber->owner ? saber->owner->s.number : ENTITYNUM_NONE, saber->clipmask ); + saber->owner ? saber->owner->s.number : ENTITYNUM_NONE, clipmask ); VectorCopy( tr.endpos, saber->currentOrigin ); @@ -4271,10 +4350,16 @@ void WP_SaberDrop( gentity_t *self, gentity_t *saber ) if ( self->client->playerTeam == TEAM_PLAYER ) { G_SoundOnEnt( saber, CHAN_AUTO, "sound/weapons/saber/saberoff.wav" ); +#ifdef _IMMERSION + G_Force( self, G_ForceIndex( "fffx/weapons/saber/saberoff", FF_CHANNEL_WEAPON ) ); +#endif // _IMMERSION } else { G_SoundOnEnt( saber, CHAN_AUTO, "sound/weapons/saber/enemy_saber_off.wav" ); +#ifdef _IMMERSION + G_Force( self, G_ForceIndex( "fffx/weapons/saber/enemy_saber_off", FF_CHANNEL_WEAPON ) ); +#endif // _IMMERSION } if ( self->health <= 0 ) @@ -4298,6 +4383,9 @@ void WP_SaberPull( gentity_t *self, gentity_t *saber ) saber->s.eFlags &= EF_BOUNCE_HALF; //play sound G_Sound( self, G_SoundIndex( "sound/weapons/force/pull.wav" ) ); +#ifdef _IMMERSION + G_Force( self, G_ForceIndex( "fffx/weapons/force/pull", FF_CHANNEL_WEAPON ) ); +#endif // _IMMERSION } } @@ -5539,6 +5627,9 @@ void ForceThrow( gentity_t *self, qboolean pull ) trace_t tr; int anim, hold, soundIndex, cost, actualCost; +#ifdef _IMMERSION + int forceIndex; +#endif // _IMMERSION if ( self->health <= 0 ) { return; @@ -5599,6 +5690,9 @@ void ForceThrow( gentity_t *self, qboolean pull ) //make sure this plays and that you cannot press fire for about 200ms after this anim = BOTH_FORCEPULL; soundIndex = G_SoundIndex( "sound/weapons/force/pull.wav" ); +#ifdef _IMMERSION + forceIndex = G_ForceIndex( "fffx/weapons/force/pull", FF_CHANNEL_WEAPON ); +#endif // _IMMERSION hold = 200; } else @@ -5611,6 +5705,9 @@ void ForceThrow( gentity_t *self, qboolean pull ) //make sure this plays and that you cannot press fire for about 1 second after this anim = BOTH_FORCEPUSH; soundIndex = G_SoundIndex( "sound/weapons/force/push.wav" ); +#ifdef _IMMERSION + forceIndex = G_ForceIndex( "fffx/weapons/force/push", FF_CHANNEL_WEAPON ); +#endif // _IMMERSION hold = 650; } @@ -5641,6 +5738,9 @@ void ForceThrow( gentity_t *self, qboolean pull ) self->client->ps.powerups[PW_FORCE_PUSH] = level.time + self->client->ps.torsoAnimTimer + 500; G_Sound( self, soundIndex ); +#ifdef _IMMERSION + G_Force( self, forceIndex ); +#endif // _IMMERSION VectorCopy( self->client->ps.viewangles, fwdangles ); //fwdangles[1] = self->client->ps.viewangles[1]; @@ -6491,6 +6591,9 @@ void ForceSpeed( gentity_t *self, int duration ) self->client->ps.forcePowerDuration[FP_SPEED] = level.time + duration; } G_Sound( self, G_SoundIndex( "sound/weapons/force/speed.wav" ) ); +#ifdef _IMMERSION + G_Force( self, G_ForceIndex( "fffx/weapons/force/speed", FF_CHANNEL_WEAPON ) ); +#endif // _IMMERSION } void ForceHeal( gentity_t *self ) @@ -6505,7 +6608,7 @@ void ForceHeal( gentity_t *self ) return; } - if ( self->painDebounceTime > level.time || self->client->ps.weaponTime ) + if ( self->painDebounceTime > level.time || (self->client->ps.weaponTime&&self->client->ps.weapon!=WP_NONE) ) {//can't initiate a heal while taking pain or attacking return; } @@ -6555,10 +6658,16 @@ void ForceHeal( gentity_t *self ) if ( self->client->playerTeam == TEAM_PLAYER ) { G_SoundOnEnt( self, CHAN_WEAPON, "sound/weapons/saber/saberoff.wav" ); +#ifdef _IMMERSION + G_Force( self, G_ForceIndex( "fffx/weapons/saber/saberoff", FF_CHANNEL_WEAPON ) ); +#endif // _IMMERSION } else { G_SoundOnEnt( self, CHAN_WEAPON, "sound/weapons/saber/enemy_saber_off.wav" ); +#ifdef _IMMERSION + G_Force( self, G_ForceIndex( "fffx/weapons/saber/enemy_saber_off", FF_CHANNEL_WEAPON ) ); +#endif // _IMMERSION } } } @@ -6575,6 +6684,9 @@ void ForceHeal( gentity_t *self ) //FIXME: always play healing effect G_SoundOnEnt( self, CHAN_ITEM, "sound/weapons/force/heal.mp3" ); +#ifdef _IMMERSION + G_Force( self, G_ForceIndex( "fffx/weapons/force/heal", FF_CHANNEL_WEAPON ) ); +#endif // _IMMERSION } extern void NPC_PlayConfusionSound( gentity_t *self ); @@ -6911,6 +7023,7 @@ void ForceGrip( gentity_t *self ) return; break; case CLASS_ATST://much too big to grip! + return; //no droids either...? case CLASS_GONK: case CLASS_R2D2: @@ -6919,6 +7032,7 @@ void ForceGrip( gentity_t *self ) case CLASS_MARK2: case CLASS_MOUSE://? case CLASS_PROTOCOL: + //*sigh*... in JK3, you'll be able to grab and move *anything*... return; break; case CLASS_PROBE: @@ -6980,6 +7094,9 @@ void ForceGrip( gentity_t *self ) //turn it off? traceEnt->client->ps.saberActive = qfalse; G_SoundOnEnt( traceEnt, CHAN_WEAPON, "sound/weapons/saber/saberoffquick.wav" ); +#ifdef _IMMERSION + G_Force( traceEnt, G_ForceIndex( "fffx/weapons/saber/saberoffquick", FF_CHANNEL_WEAPON ) ); +#endif // _IMMERSION } } } @@ -6998,6 +7115,10 @@ void ForceGrip( gentity_t *self ) self->client->ps.forcePowerDebounce[FP_GRIP] = level.time + 250; self->client->ps.forcePowerDuration[FP_GRIP] = level.time + 5000; traceEnt->s.loopSound = G_SoundIndex( "sound/weapons/force/grip.mp3" ); +#ifdef _IMMERSION + G_Force( self, G_ForceIndex( "fffx/weapons/force/gripcast", FF_CHANNEL_FORCE ) ); + //G_Force( traceEnt, G_ForceIndex( "fffx/weapons/force/grip", FF_CHANNEL_DAMAGE ) ); +#endif // _IMMERSION } else { @@ -7058,6 +7179,9 @@ void ForceLightning( gentity_t *self ) self->client->ps.saberBlocked = BLOCKED_NONE; G_SoundOnEnt( self, CHAN_BODY, "sound/weapons/force/lightning.wav" ); +#ifdef _IMMERSION + G_Force( self, G_ForceIndex( "fffx/weapons/force/lightning", FF_CHANNEL_WEAPON ) ); +#endif // _IMMERSION if ( self->client->ps.forcePowerLevel[FP_LIGHTNING] < FORCE_LEVEL_2 ) {//short burst //G_SoundOnEnt( self, CHAN_BODY, "sound/weapons/force/lightning.wav" ); @@ -7328,6 +7452,9 @@ void ForceJumpCharge( gentity_t *self, usercmd_t *ucmd ) if ( !self->client->ps.forceJumpCharge ) {//FIXME: this should last only as long as the actual charge-up G_SoundOnEnt( self, CHAN_BODY, "sound/weapons/force/jumpbuild.wav" ); +#ifdef _IMMERSION + G_Force( self, G_ForceIndex( "fffx/weapons/force/jumpbuild", FF_CHANNEL_WEAPON ) ); +#endif // _IMMERSION } //Increment self->client->ps.forceJumpCharge += forceJumpChargeInterval; @@ -7448,6 +7575,9 @@ void ForceJump( gentity_t *self, usercmd_t *ucmd ) } G_SoundOnEnt( self, CHAN_BODY, "sound/weapons/force/jump.wav" ); +#ifdef _IMMERSION + G_Force( self, G_ForceIndex( "fffx/weapons/force/jump", FF_CHANNEL_WEAPON ) ); +#endif // _IMMERSION float forceJumpChargeInterval = forceJumpStrength[self->client->ps.forcePowerLevel[FP_LEVITATION]]/(FORCE_JUMP_CHARGE_TIME/FRAMETIME); @@ -7734,6 +7864,8 @@ void WP_ForcePowerStop( gentity_t *self, forcePowers_t forcePower ) gi.cvar_set("timescale", "1"); } } + //FIXME: reset my current anim, keeping current frame, but with proper anim speed + // otherwise, the anim will continue playing at high speed self->s.loopSound = 0; break; case FP_PUSH: @@ -7805,9 +7937,14 @@ void WP_ForcePowerStop( gentity_t *self, forcePowers_t forcePower ) } } } - if ( gripEnt->NPC && !(gripEnt->NPC->aiFlags&NPCAI_DIE_ON_IMPACT) ) - {//not falling to their death - gripEnt->NPC->nextBStateThink = level.time + holdTime; + if ( gripEnt->NPC ) + { + if ( !(gripEnt->NPC->aiFlags&NPCAI_DIE_ON_IMPACT) ) + {//not falling to their death + gripEnt->NPC->nextBStateThink = level.time + holdTime; + } + //if still alive after stopped gripping, let them wake others up + G_AngerAlert( gripEnt ); } } } @@ -7882,11 +8019,17 @@ static void WP_ForcePowerRun( gentity_t *self, forcePowers_t forcePower, usercmd {//fully healed or used up all 25 if ( !Q3_TaskIDPending( self, TID_CHAN_VOICE ) ) { +#ifdef _IMMERSION + int index = Q_irand( 1, 4 ); + G_SoundOnEnt( self, CHAN_VOICE, va( "sound/weapons/force/heal%d.mp3", index ) ); + G_Force( self, G_ForceIndex( va( "fffx/weapons/force/heal%d", index ), FF_CHANNEL_WEAPON ) ); +#else G_SoundOnEnt( self, CHAN_VOICE, va( "sound/weapons/force/heal%d.mp3", Q_irand( 1, 4 ) ) ); +#endif // _IMMERSION } WP_ForcePowerStop( self, forcePower ); } - else if ( self->client->ps.forcePowerLevel[FP_HEAL] < FORCE_LEVEL_3 && ( (cmd->buttons&BUTTON_ATTACK) || (cmd->buttons&BUTTON_ALT_ATTACK) || self->painDebounceTime > level.time || self->client->ps.weaponTime ) ) + else if ( self->client->ps.forcePowerLevel[FP_HEAL] < FORCE_LEVEL_3 && ( (cmd->buttons&BUTTON_ATTACK) || (cmd->buttons&BUTTON_ALT_ATTACK) || self->painDebounceTime > level.time || (self->client->ps.weaponTime&&self->client->ps.weapon!=WP_NONE) ) ) {//attacked or was hit while healing... //stop healing WP_ForcePowerStop( self, forcePower ); diff --git a/code/openal32.dll b/code/openal32.dll index e65826b..78195c4 100644 Binary files a/code/openal32.dll and b/code/openal32.dll differ diff --git a/code/qcommon/cm_load.cpp b/code/qcommon/cm_load.cpp index 62e67d5..df7487d 100644 --- a/code/qcommon/cm_load.cpp +++ b/code/qcommon/cm_load.cpp @@ -109,6 +109,7 @@ void CMod_LoadSubmodels( lump_t *l ) { Com_Error (ERR_DROP, "Map with no models"); } + //FIXME: note that MAX_SUBMODELS - 1 is used for BOX_MODEL_HANDLE, if that slot gets used, that would be bad, no? if ( count > MAX_SUBMODELS ) { Com_Error( ERR_DROP, "MAX_SUBMODELS (%d) exceeded by %d", MAX_SUBMODELS, count-MAX_SUBMODELS ); } @@ -892,7 +893,7 @@ To keep everything totally uniform, bounding boxes are turned into small BSP trees instead of being compared directly. =================== */ -clipHandle_t CM_TempBoxModel( const vec3_t mins, const vec3_t maxs ) { +clipHandle_t CM_TempBoxModel( const vec3_t mins, const vec3_t maxs) {//, const int contents ) { box_planes[0].dist = maxs[0]; box_planes[1].dist = -maxs[0]; box_planes[2].dist = mins[0]; @@ -909,6 +910,9 @@ clipHandle_t CM_TempBoxModel( const vec3_t mins, const vec3_t maxs ) { VectorCopy( mins, box_brush->bounds[0] ); VectorCopy( maxs, box_brush->bounds[1] ); + //FIXME: this is the "correct" way, but not the way JK2 was designed around... fix for further projects + //box_brush->contents = contents; + return BOX_MODEL_HANDLE; } diff --git a/code/qcommon/cm_public.h b/code/qcommon/cm_public.h index fd0c512..02a8439 100644 --- a/code/qcommon/cm_public.h +++ b/code/qcommon/cm_public.h @@ -6,7 +6,7 @@ qboolean CM_DeleteCachedMap(qboolean bGuaranteedOkToDelete); void CM_LoadMap( const char *name, qboolean clientload, int *checksum); clipHandle_t CM_InlineModel( int index ); // 0 = world, 1 + are bmodels -clipHandle_t CM_TempBoxModel( const vec3_t mins, const vec3_t maxs ); +clipHandle_t CM_TempBoxModel( const vec3_t mins, const vec3_t maxs );//, const int contents ); void CM_ModelBounds( clipHandle_t model, vec3_t mins, vec3_t maxs ); int CM_ModelContents( clipHandle_t model ); diff --git a/code/qcommon/cmd.cpp b/code/qcommon/cmd.cpp index 2d88e75..ca27c0c 100644 --- a/code/qcommon/cmd.cpp +++ b/code/qcommon/cmd.cpp @@ -362,7 +362,7 @@ will point into this temporary buffer. ============ */ void Cmd_TokenizeString( const char *text_in ) { - const char *text; + const unsigned char *text; char *textOut; // clear previous args @@ -372,7 +372,7 @@ void Cmd_TokenizeString( const char *text_in ) { return; } - text = text_in; + text = (const unsigned char *)text_in; textOut = cmd_tokenized; while ( 1 ) { diff --git a/code/qcommon/common.cpp b/code/qcommon/common.cpp index 13fc7bf..71b63bc 100644 --- a/code/qcommon/common.cpp +++ b/code/qcommon/common.cpp @@ -56,7 +56,7 @@ cvar_t *com_logfile; // 1 = buffer log, 2 = flush after each print cvar_t *com_showtrace; cvar_t *com_version; cvar_t *com_buildScript; // for automated data building scripts -cvar_t *com_FirstTime; +//cvar_t *com_FirstTime; cvar_t *cl_paused; cvar_t *sv_paused; cvar_t *com_skippingcin; @@ -238,6 +238,7 @@ void QDECL Com_Error( int code, const char *fmt, ... ) { va_end (argptr); if ( code != ERR_DISCONNECT ) { + Cvar_Get("com_errorMessage", "", CVAR_ROM); //give com_errorMessage a default so it won't come back to life after a resetDefaults Cvar_Set("com_errorMessage", com_errorMessage); } @@ -1875,7 +1876,7 @@ void Com_Init( char *commandLine ) { com_skippingcin = Cvar_Get ("skippingCinematic", "0", CVAR_ROM); com_buildScript = Cvar_Get( "com_buildScript", "0", 0 ); - com_FirstTime = Cvar_Get( "com_FirstTime", "0", CVAR_ARCHIVE); +// com_FirstTime = Cvar_Get( "com_FirstTime", "0", CVAR_ARCHIVE); if ( com_developer && com_developer->integer ) { Cmd_AddCommand ("error", Com_Error_f); Cmd_AddCommand ("crash", Com_Crash_f ); @@ -1889,7 +1890,7 @@ void Com_Init( char *commandLine ) { Sys_Init(); // this also detects CPU type, so I can now do this CPU check below... - if( !com_FirstTime->integer ) // special request to detect and use top-settings for Intel Williamette chip... +/* if( !com_FirstTime->integer ) // special request to detect and use top-settings for Intel Williamette chip... { Cvar_Set( "com_FirstTime", "1" ); // only do this once // @@ -1902,7 +1903,7 @@ void Com_Init( char *commandLine ) { // Cbuf_Execute (); } } - +*/ Netchan_Init( Com_Milliseconds() & 0xffff ); // pick a port value that should be nice and random // VM_Init(); SV_Init(); @@ -1931,6 +1932,16 @@ void Com_Init( char *commandLine ) { } com_fullyInitialized = qtrue; Com_Printf ("--- Common Initialization Complete ---\n"); + +//HACKERY FOR THE DEUTSCH + if ( (Cvar_VariableIntegerValue("ui_iscensored") == 1) //if this was on before, set it again so it gets its flags + || sp_language->integer == SP_LANGUAGE_GERMAN ) + { + Cvar_Get( "ui_iscensored", "1", CVAR_ARCHIVE|CVAR_ROM|CVAR_INIT|CVAR_CHEAT|CVAR_NORESTART); + Cvar_Set( "ui_iscensored", "1"); //just in case it was archived + Cvar_Get( "g_dismemberment", "0", CVAR_ARCHIVE|CVAR_ROM|CVAR_INIT|CVAR_CHEAT); + Cvar_Set( "g_dismemberment", "0"); //just in case it was archived + } } catch (const char* reason) { diff --git a/code/qcommon/cvar.cpp b/code/qcommon/cvar.cpp index 0e9b073..63cddca 100644 --- a/code/qcommon/cvar.cpp +++ b/code/qcommon/cvar.cpp @@ -130,17 +130,15 @@ char *Cvar_CompleteVariable( const char *partial ) { return NULL; } - // check exact match - for ( cvar = cvar_vars ; cvar ; cvar = cvar->next ) { - if ( !Q_stricmp (partial,cvar->name) ) { - return cvar->name; - } - } - // check partial match for ( cvar=cvar_vars ; cvar ; cvar=cvar->next ) { if ( !Q_stricmpn (partial,cvar->name, len) ) { - return cvar->name; + if ( (cvar->flags & CVAR_CHEAT) && !cvar_cheats->integer ) { + continue; + } + else { + return cvar->name; + } } } @@ -184,15 +182,19 @@ char *Cvar_CompleteVariableNext (char *partial, char *last) { base = cvar_vars; } - // check exact match - for (cvar=base ; cvar ; cvar=cvar->next) - if (!Q_stricmp (partial,cvar->name)) - return cvar->name; // check partial match for (cvar=base ; cvar ; cvar=cvar->next) - if (!Q_stricmpn (partial,cvar->name, len)) - return cvar->name; + { + if (!Q_stricmpn (partial,cvar->name, len)) { + if ( (cvar->flags & CVAR_CHEAT) && !cvar_cheats->integer ) { + continue; + } + else { + return cvar->name; + } + } + } return NULL; } @@ -513,7 +515,7 @@ void Cvar_Toggle_f( void ) { return; } - v = Cvar_VariableValue( Cmd_Argv( 1 ) ); + v = Cvar_VariableIntegerValue( Cmd_Argv( 1 ) ); v = !v; Cvar_Set2 (Cmd_Argv(1), va("%i", v), qfalse); diff --git a/code/qcommon/files.cpp b/code/qcommon/files.cpp index f57e118..ab6d66a 100644 --- a/code/qcommon/files.cpp +++ b/code/qcommon/files.cpp @@ -157,7 +157,7 @@ or configs will never get loaded from disk! // every time a new demo pk3 file is built, this checksum must be updated. // the easiest way to get it is to just run the game and see what it spits out -#define DEMO_PAK_CHECKSUM 3766578759u +#define DEMO_PAK_CHECKSUM 1431467275 #define DEMO_PAK_MAXFILES 5174u // if this is defined, the executable positively won't work with any paks other @@ -2014,6 +2014,7 @@ static void FS_Startup( const char *gameName ) { fs_gamedirvar = Cvar_Get ("fs_game", "", CVAR_INIT|CVAR_SERVERINFO ); fs_restrict = Cvar_Get ("fs_restrict", "", CVAR_INIT ); + Cvar_Get( "com_demo", "", CVAR_INIT ); // set up cdpath if (fs_cdpath->string[0]) { @@ -2092,6 +2093,7 @@ static void FS_SetRestrictions( void ) { } #endif Cvar_Set( "fs_restrict", "1" ); + Cvar_Set( "com_demo", "1" ); Com_Printf( "\nRunning in restricted demo mode.\n\n" ); @@ -2150,7 +2152,7 @@ void FS_InitFilesystem( void ) { FS_Restart ================ */ -/* + void FS_Restart( void ) { // free anything we currently have loaded FS_Shutdown(); @@ -2168,7 +2170,6 @@ void FS_Restart( void ) { Com_Error( ERR_FATAL, "Couldn't load default.cfg" ); } } -*/ /* ======================================================================================== diff --git a/code/qcommon/strip.cpp b/code/qcommon/strip.cpp index e2831df..2d9a6ef 100644 --- a/code/qcommon/strip.cpp +++ b/code/qcommon/strip.cpp @@ -500,7 +500,7 @@ void cStringsSingle::SetText(const char *newText) // fix problems caused by fucking morons entering clever "rich" chars in to new text files *after* the auto-stripper // removed them all in the first place... // -// ONLY DO THIS FOR ENGLISH, OR IT BREAKS ASIAN STRINGS!!!!!!!!!!!!!!!!!!!!! +// ONLY DO THIS FOR EUROPEAN LANGUAGES, OR IT BREAKS ASIAN STRINGS!!!!!!!!!!!!!!!!!!!!! // static void FixIllegalChars(char *psText) { @@ -596,7 +596,8 @@ bool cStringsSingle::UnderstandToken(int token, char *data ) { // default to english in case there is no foreign if (LanguagePair->Name == TK_TEXT_LANGUAGE1 || LanguagePair->Name == TK_TEXT_LANGUAGE2 || - LanguagePair->Name == TK_TEXT_LANGUAGE3 + LanguagePair->Name == TK_TEXT_LANGUAGE3 || + LanguagePair->Name == TK_TEXT_LANGUAGE8 ) { FixIllegalChars(data); @@ -608,7 +609,8 @@ bool cStringsSingle::UnderstandToken(int token, char *data ) { if (LanguagePair->Name == TK_TEXT_LANGUAGE1 || LanguagePair->Name == TK_TEXT_LANGUAGE2 || - LanguagePair->Name == TK_TEXT_LANGUAGE3 + LanguagePair->Name == TK_TEXT_LANGUAGE3 || + LanguagePair->Name == TK_TEXT_LANGUAGE8 ) { FixIllegalChars(data); @@ -1092,6 +1094,8 @@ void SP_Init(void) SP_UpdateLanguage(); sp_language->modified = false; + + SP_Register("con_text", SP_REGISTER_REQUIRED); //reference is CON_TEXT } // called in Com_Frame, so don't take up any time! (can also be called during dedicated) diff --git a/code/qcommon/stv_version.h b/code/qcommon/stv_version.h index d405dc2..217ec24 100644 --- a/code/qcommon/stv_version.h +++ b/code/qcommon/stv_version.h @@ -1,6 +1,6 @@ // Current version of the single player game -#define Q3_VERSION "JK2: v1.02" +#define Q3_VERSION "JK2: v1.03" // end diff --git a/code/qcommon/vssver.scc b/code/qcommon/vssver.scc index d2a6661..8848695 100644 Binary files a/code/qcommon/vssver.scc and b/code/qcommon/vssver.scc differ diff --git a/code/renderer/tr_font.cpp b/code/renderer/tr_font.cpp index d31583c..0fd2a55 100644 --- a/code/renderer/tr_font.cpp +++ b/code/renderer/tr_font.cpp @@ -222,7 +222,7 @@ static int Japanese_CollapseShiftJISCode( unsigned int uiCode ) if ( ((uiCode>>8)&0xFF) >= (SHIFTJIS_HIBYTE_START1)-SHIFTJIS_HIBYTE_START0) { - uiCode -= ((SHIFTJIS_HIBYTE_START1)-SHIFTJIS_HIBYTE_STOP0)-1; + uiCode -= (((SHIFTJIS_HIBYTE_START1)-SHIFTJIS_HIBYTE_STOP0)-1) << 8; } uiCode = ((uiCode >> 8) * SHIFTJIS_CODES_PER_ROW) + (uiCode & 0xFF); @@ -338,6 +338,11 @@ qboolean Language_IsAsian(void) return (Language_IsKorean() || Language_IsTaiwanese() || Language_IsJapanese()); } +qboolean Language_UsesSpaces(void) +{ + return !(Language_IsTaiwanese() || Language_IsJapanese()); +} + // ====================================================================== @@ -496,7 +501,7 @@ void CFontInfo::UpdateAsianIfNeeded( bool bForceReEval /* = false */ ) // m_AsianGlyph.width = iCappedHeight; // square Asian chars same size as height of western set m_AsianGlyph.height = iCappedHeight; // "" - m_AsianGlyph.horizAdvance = iCappedHeight + (bTaiwanese?3:-1); // Asian chars contain a small amount of space in the glyph + m_AsianGlyph.horizAdvance = iCappedHeight + ((bTaiwanese||bJapanese)?3:-1); // Asian chars contain a small amount of space in the glyph m_AsianGlyph.horizOffset = 0; // "" // .. or you can use the mKoreanHack value (which is the same number as the calc below) m_AsianGlyph.baseline = mAscender + ((iCappedHeight - mHeight) >> 1); @@ -707,6 +712,13 @@ int RE_Font_StrLenPixels(const char *psText, const int iFontHandle, const float { return(0); } + + float fScaleA = fScale; + if (Language_IsAsian() && fScale > 0.7f ) + { + fScaleA = fScale * 0.75f; + } + while(*psText) { unsigned int uiLetter = AnyLanguage_ReadCharFromString( &psText ); @@ -718,7 +730,7 @@ int RE_Font_StrLenPixels(const char *psText, const int iFontHandle, const float { int iPixelAdvance = curfont->GetLetterHorizAdvance( uiLetter ); - iThisWidth += Round(iPixelAdvance * fScale); + iThisWidth += Round(iPixelAdvance * ((uiLetter > 255) ? fScaleA : fScale)); if (iThisWidth > iMaxWidth) { iMaxWidth = iThisWidth; @@ -769,10 +781,13 @@ int RE_Font_HeightPixels(const int iFontHandle, const float fScale) // void RE_Font_DrawString(int ox, int oy, const char *psText, const float *rgba, const int iFontHandle, int iMaxPixelWidth, const float fScale) { + static qboolean gbInShadow = qfalse; // MUST default to this int x, y, colour, offset; const glyphInfo_t *pLetter; qhandle_t hShader; + assert (psText); + if(iFontHandle & STYLE_BLINK) { if((ri.Milliseconds() >> 7) & 1) @@ -805,12 +820,23 @@ void RE_Font_DrawString(int ox, int oy, const char *psText, const float *rgba, c { return; } + + float fScaleA = fScale; + int iAsianYAdjust = 0; + if (Language_IsAsian() && fScale > 0.7f) + { + fScaleA = fScale * 0.75f; + iAsianYAdjust = /*Round*/((((float)curfont->GetPointSize() * fScale) - ((float)curfont->GetPointSize() * fScaleA))/2); + } + // Draw a dropshadow if required if(iFontHandle & STYLE_DROPSHADOW) { offset = Round(curfont->GetPointSize() * fScale * 0.075f); + gbInShadow = qtrue; RE_Font_DrawString(ox + offset, oy + offset, psText, colorTable[CT_DKGREY2], iFontHandle & SET_MASK, iMaxPixelWidth, fScale); + gbInShadow = qfalse; } RE_SetColor( rgba ); @@ -825,14 +851,19 @@ void RE_Font_DrawString(int ox, int oy, const char *psText, const float *rgba, c switch( uiLetter ) { case '^': - { colour = ColorIndex(*psText++); - RE_SetColor( g_color_table[colour] ); + if (!gbInShadow) + { + RE_SetColor( g_color_table[colour] ); } break; case 10: //linefeed x = ox; oy += Round(curfont->GetPointSize() * fScale); + if (Language_IsAsian()) + { + oy += 4; // this only comes into effect when playing in asian for "A long time ago in a galaxy" etc, all other text is line-broken in feeder functions + } break; case 13: // Return break; @@ -849,18 +880,19 @@ void RE_Font_DrawString(int ox, int oy, const char *psText, const float *rgba, c pLetter = curfont->GetLetter('.'); } - int iAdvancePixels = Round(pLetter->horizAdvance * fScale); + float fThisScale = uiLetter > 255 ? fScaleA : fScale; + int iAdvancePixels = Round(pLetter->horizAdvance * fThisScale); bNextTextWouldOverflow = ( iMaxPixelWidth != -1 && (((x+iAdvancePixels)-ox)>iMaxPixelWidth) ); if (!bNextTextWouldOverflow) { // this 'mbRoundCalcs' stuff is crap, but the only way to make the font code work. Sigh... - // - y = oy - (curfont->mbRoundCalcs ? Round(pLetter->baseline * fScale) : pLetter->baseline * fScale); + // + y = oy - (curfont->mbRoundCalcs ? Round(pLetter->baseline * fThisScale) : pLetter->baseline * fThisScale); RE_StretchPic ( x + Round(pLetter->horizOffset * fScale), // float x - y, // float y - curfont->mbRoundCalcs ? Round(pLetter->width * fScale) : pLetter->width * fScale, // float w - curfont->mbRoundCalcs ? Round(pLetter->height * fScale) : pLetter->height * fScale, // float h + (uiLetter > 255) ? y - iAsianYAdjust : y, // float y + curfont->mbRoundCalcs ? Round(pLetter->width * fThisScale) : pLetter->width * fThisScale, // float w + curfont->mbRoundCalcs ? Round(pLetter->height * fThisScale) : pLetter->height * fThisScale, // float h pLetter->s, // float s1 pLetter->t, // float t1 pLetter->s2, // float s2 diff --git a/code/renderer/tr_font.h b/code/renderer/tr_font.h index a61197a..836693d 100644 --- a/code/renderer/tr_font.h +++ b/code/renderer/tr_font.h @@ -73,7 +73,7 @@ int RE_Font_HeightPixels(const int iFontHandle, const float fScale = 1.0f); void RE_Font_DrawString(int ox, int oy, const char *psText, const float *rgba, const int iFontHandle, int iMaxPixelWidth, const float fScale = 1.0f); unsigned int AnyLanguage_ReadCharFromString( const char **ppsText, qboolean *pbIsTrailingPunctuation = NULL); qboolean Language_IsAsian(void); - +qboolean Language_UsesSpaces(void); #endif // #ifndef TR_FONT_H diff --git a/code/renderer/tr_init.cpp b/code/renderer/tr_init.cpp index 710d45f..ff4b571 100644 --- a/code/renderer/tr_init.cpp +++ b/code/renderer/tr_init.cpp @@ -1027,8 +1027,8 @@ void R_Register( void ) #endif r_facePlaneCull = ri.Cvar_Get ("r_facePlaneCull", "1", CVAR_ARCHIVE ); - r_surfaceSprites = ri.Cvar_Get ("r_surfaceSprites", "1", CVAR_CHEAT); - r_surfaceWeather = ri.Cvar_Get ("r_surfaceWeather", "0", 0); + r_surfaceSprites = ri.Cvar_Get ("r_surfaceSprites", "1", CVAR_TEMP); + r_surfaceWeather = ri.Cvar_Get ("r_surfaceWeather", "0", CVAR_TEMP); r_windSpeed = ri.Cvar_Get ("r_windSpeed", "0", 0); r_windAngle = ri.Cvar_Get ("r_windAngle", "0", 0); @@ -1393,6 +1393,7 @@ refexport_t *GetRefAPI ( int apiVersion, refimport_t *rimp ) { re.Font_HeightPixels = RE_Font_HeightPixels; re.Font_DrawString = RE_Font_DrawString; re.Language_IsAsian = Language_IsAsian; + re.Language_UsesSpaces = Language_UsesSpaces; re.AnyLanguage_ReadCharFromString = AnyLanguage_ReadCharFromString; #ifdef _NPATCH diff --git a/code/renderer/tr_public.h b/code/renderer/tr_public.h index 83b501e..f205095 100644 --- a/code/renderer/tr_public.h +++ b/code/renderer/tr_public.h @@ -107,6 +107,7 @@ typedef struct { int (*Font_StrLenChars) (const char *s); void (*Font_DrawString)(int x, int y, const char *s, const float *rgba, const int iFontHandle, int iMaxPixelWidth, const float scale = 1.0f); qboolean (*Language_IsAsian) (void); + qboolean (*Language_UsesSpaces) (void); unsigned int (*AnyLanguage_ReadCharFromString)( const char **ppsText, qboolean *pbIsTrailingPunctuation /* = NULL */); #ifdef _NPATCH diff --git a/code/renderer/vssver.scc b/code/renderer/vssver.scc index 0d83384..6dbae01 100644 Binary files a/code/renderer/vssver.scc and b/code/renderer/vssver.scc differ diff --git a/code/server/sv_game.cpp b/code/server/sv_game.cpp index 7488b34..f1b998b 100644 --- a/code/server/sv_game.cpp +++ b/code/server/sv_game.cpp @@ -332,22 +332,9 @@ void SV_InitGameProgs (void) { SV_ShutdownGameProgs (); } - if ( !Cvar_VariableValue("fs_restrict") && !Sys_CheckCD() ) + if ( !Cvar_VariableIntegerValue("fs_restrict") && !Sys_CheckCD() ) { - if (sp_language) // dunno if SP files are loaded at this point if no CD... - { - switch (sp_language->integer) - { - case SP_LANGUAGE_GERMAN: - Com_Error( ERR_NEED_CD, "Spiel CD nicht im Laufwerk" ); - break; // keep compiler happy - case SP_LANGUAGE_FRENCH: - Com_Error( ERR_NEED_CD, "CD de jeu pas dans le lecteur" ); - break; // keep compiler happy - } - } - - Com_Error( ERR_NEED_CD, "Game CD not in drive" ); + Com_Error( ERR_NEED_CD, SP_GetStringTextString("CON_TEXT_NEED_CD") ); //"Game CD not in drive" ); } // load a new game dll diff --git a/code/server/sv_init.cpp b/code/server/sv_init.cpp index 46bc05d..ec0c05e 100644 --- a/code/server/sv_init.cpp +++ b/code/server/sv_init.cpp @@ -198,7 +198,7 @@ void SV_SpawnServer( char *server, ForceReload_e eForceReload, qboolean bAllowSc Com_Printf ("Server: %s\n",server); // init client structures and svs.numSnapshotEntities - if ( !Cvar_VariableValue("sv_running") ) { + if ( !Cvar_VariableIntegerValue("sv_running") ) { SV_Startup(); } diff --git a/code/server/sv_savegame.cpp b/code/server/sv_savegame.cpp index 0827884..b5b6d29 100644 --- a/code/server/sv_savegame.cpp +++ b/code/server/sv_savegame.cpp @@ -102,6 +102,18 @@ LPCSTR SG_GetChidText(unsigned long chid) } +static const char *GetString_FailedToOpenSaveGame(const char *psFilename, qboolean bOpen) +{ + static char sTemp[256]; + + strcpy(sTemp,S_COLOR_RED); + + const char *psReference = bOpen ? "MENUS3_FAILED_TO_OPEN_SAVEGAME" : "MENUS3_FAILED_TO_CREATE_SAVEGAME"; + Q_strncpyz(sTemp + strlen(sTemp), va( SP_GetStringTextString(psReference), psFilename),sizeof(sTemp)); + strcat(sTemp,"\n"); + return sTemp; +} + // (copes with up to 8 ptr returns at once) // static LPCSTR SG_AddSavePath( LPCSTR psPathlessBaseName ) @@ -150,7 +162,7 @@ static qboolean SG_Create( LPCSTR psPathlessBaseName ) if(!fhSaveGame) { - Com_Printf(S_COLOR_RED "Failed to create new savegame file \"%s\"\n", psLocalFilename ); + Com_Printf(GetString_FailedToOpenSaveGame(psLocalFilename,qfalse));//S_COLOR_RED "Failed to create new savegame file \"%s\"\n", psLocalFilename ); return qfalse; } @@ -230,7 +242,7 @@ qboolean SG_Open( LPCSTR psPathlessBaseName ) if (!fhSaveGame) { // Com_Printf(S_COLOR_RED "Failed to open savegame file %s\n", psLocalFilename); - Com_DPrintf("Failed to open savegame file %s\n", psLocalFilename); + Com_DPrintf(GetString_FailedToOpenSaveGame(psLocalFilename, qtrue)); return qfalse; } @@ -381,11 +393,13 @@ void SV_LoadGame_f(void) Com_Printf (S_COLOR_CYAN "Loading game \"%s\"...\n", psFilename); - gbAlreadyDoingLoad = qtrue; - SG_ReadSavegame(psFilename); - //gbAlreadyDoingLoad = qfalse; // do NOT do this here now, need to wait until client spawn - - Com_Printf (S_COLOR_CYAN "Done.\n"); + gbAlreadyDoingLoad = qtrue; + if (!SG_ReadSavegame(psFilename)) { + gbAlreadyDoingLoad = qfalse; // do NOT do this here now, need to wait until client spawn, unless the load failed. + } else + { + Com_Printf (S_COLOR_CYAN "Done.\n"); + } } qboolean SG_GameAllowedToSaveHere(qboolean inCamera); @@ -918,7 +932,7 @@ qboolean SG_WriteSavegame(const char *psPathlessBaseName, qboolean qbAutosave) if(!SG_Create( "current" )) { - Com_Printf (S_COLOR_RED "Failed to create savegame\n"); + Com_Printf (GetString_FailedToOpenSaveGame("current",qfalse));//S_COLOR_RED "Failed to create savegame\n"); SG_WipeSavegame( "current" ); sv_testsave->value = fPrevTestSave; return qfalse; @@ -954,7 +968,7 @@ qboolean SG_WriteSavegame(const char *psPathlessBaseName, qboolean qbAutosave) SG_Close(); if (gbSGWriteFailed) { - Com_Printf (S_COLOR_RED "Failed to write savegame!\n"); + Com_Printf (GetString_FailedToOpenSaveGame("current",qfalse));//S_COLOR_RED "Failed to write savegame!\n"); SG_WipeSavegame( "current" ); sv_testsave->value = fPrevTestSave; return qfalse; @@ -979,7 +993,7 @@ qboolean SG_ReadSavegame(const char *psPathlessBaseName) if (!SG_Open( psPathlessBaseName )) { - Com_Printf (S_COLOR_RED "Failed to open savegame \"%s\"\n", psPathlessBaseName); + Com_Printf (GetString_FailedToOpenSaveGame(psPathlessBaseName, qtrue));//S_COLOR_RED "Failed to open savegame \"%s\"\n", psPathlessBaseName); sv_testsave->value = fPrevTestSave; return qfalse; } @@ -1020,7 +1034,7 @@ qboolean SG_ReadSavegame(const char *psPathlessBaseName) if(!SG_Close()) { - Com_Printf (S_COLOR_RED "Failed to close savegame\n"); + Com_Printf (GetString_FailedToOpenSaveGame(psPathlessBaseName,qfalse));//S_COLOR_RED "Failed to close savegame\n"); sv_testsave->value = fPrevTestSave; return qfalse; } diff --git a/code/server/sv_world.cpp b/code/server/sv_world.cpp index d9628a5..abf2a1f 100644 --- a/code/server/sv_world.cpp +++ b/code/server/sv_world.cpp @@ -50,7 +50,7 @@ clipHandle_t SV_ClipHandleForEntity( const gentity_t *ent ) { } // create a temp tree from bounding box sizes - return CM_TempBoxModel( ent->mins, ent->maxs ); + return CM_TempBoxModel( ent->mins, ent->maxs );//, ent->contents ); } diff --git a/code/server/vssver.scc b/code/server/vssver.scc index 01d5438..80d2607 100644 Binary files a/code/server/vssver.scc and b/code/server/vssver.scc differ diff --git a/code/starwars.dsp b/code/starwars.dsp index 02c3637..01002c4 100644 --- a/code/starwars.dsp +++ b/code/starwars.dsp @@ -45,7 +45,7 @@ RSC=rc.exe # PROP Ignore_Export_Lib 0 # PROP Target_Dir "" # ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /c -# ADD CPP /nologo /G6 /MT /W4 /GX /Zi /O2 /D "NDEBUG" /D "_JK2EXE" /D "WIN32" /D "_WINDOWS" /YX /FD /c +# ADD CPP /nologo /G6 /MT /W4 /GX /Zi /O2 /I "ff/ifc" /D "NDEBUG" /D "_JK2EXE" /D "WIN32" /D "_WINDOWS" /D "_IMMERSION" /D "_FF" /YX /FD /c # ADD BASE MTL /nologo /D "NDEBUG" /win32 # ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 # ADD BASE RSC /l 0x409 /d "NDEBUG" @@ -55,7 +55,7 @@ BSC32=bscmake.exe # ADD BSC32 /nologo LINK32=link.exe # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386 -# ADD LINK32 ALut.lib OpenAL32.lib win32/FeelIt/ffc10.lib advapi32.lib winmm.lib kernel32.lib user32.lib gdi32.lib ole32.lib wsock32.lib /nologo /stack:0x800000 /subsystem:windows /map /debug /machine:I386 /out:".\Release/jk2sp.exe" +# ADD LINK32 ALut.lib OpenAL32.lib advapi32.lib winmm.lib kernel32.lib user32.lib gdi32.lib ole32.lib wsock32.lib ff/ifc/ifc22.lib /nologo /stack:0x800000 /subsystem:windows /map /debug /machine:I386 /out:".\Release/jk2sp.exe" # SUBTRACT LINK32 /incremental:yes /nodefaultlib !ELSEIF "$(CFG)" == "starwars - Win32 Debug" @@ -72,7 +72,7 @@ LINK32=link.exe # PROP Ignore_Export_Lib 0 # PROP Target_Dir "" # ADD BASE CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /c -# ADD CPP /nologo /G6 /MTd /W4 /Gm /Gi /GX /ZI /Od /D "_DEBUG" /D "_JK2EXE" /D "WIN32" /D "_WINDOWS" /Fr /YX /FD /c +# ADD CPP /nologo /G6 /MTd /W4 /Gm /Gi /GX /ZI /Od /I "ff/ifc" /D "_DEBUG" /D "_JK2EXE" /D "WIN32" /D "_WINDOWS" /D "_IMMERSION" /D "_FF" /Fr /YX /FD /c # ADD BASE MTL /nologo /D "_DEBUG" /win32 # ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 # ADD BASE RSC /l 0x409 /d "_DEBUG" @@ -82,7 +82,7 @@ BSC32=bscmake.exe # ADD BSC32 /nologo /o"Debug/starwars.bsc" LINK32=link.exe # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386 -# ADD LINK32 ALut.lib OpenAL32.lib win32/FeelIt/ffc10d.lib advapi32.lib winmm.lib kernel32.lib user32.lib gdi32.lib ole32.lib wsock32.lib /nologo /stack:0x800000 /subsystem:windows /map /debug /machine:I386 /out:".\Debug/jk2sp.exe" +# ADD LINK32 ALut.lib OpenAL32.lib advapi32.lib winmm.lib kernel32.lib user32.lib gdi32.lib ole32.lib wsock32.lib ff/ifc/ifc22.lib /nologo /stack:0x800000 /subsystem:windows /map /debug /machine:I386 /out:".\Debug/jk2sp.exe" # SUBTRACT LINK32 /profile /incremental:no /nodefaultlib !ELSEIF "$(CFG)" == "starwars - Win32 FinalBuild" @@ -100,7 +100,7 @@ LINK32=link.exe # PROP Ignore_Export_Lib 0 # PROP Target_Dir "" # ADD BASE CPP /nologo /G6 /MT /W4 /GX /Zi /O2 /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "__USEA3D" /D "__A3D_GEOM" /YX /FD /c -# ADD CPP /nologo /G6 /MT /W4 /GX /Zi /O2 /D "NDEBUG" /D "FINAL_BUILD" /D "_JK2EXE" /D "WIN32" /D "_WINDOWS" /YX /FD /c +# ADD CPP /nologo /G6 /MT /W4 /GX /Zi /O2 /I "ff/ifc" /D "NDEBUG" /D "FINAL_BUILD" /D "_JK2EXE" /D "WIN32" /D "_WINDOWS" /D "_IMMERSION" /D "_FF" /YX /FD /c # ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 # ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 # ADD BASE RSC /l 0x409 /d "NDEBUG" @@ -111,7 +111,7 @@ BSC32=bscmake.exe LINK32=link.exe # ADD BASE LINK32 advapi32.lib winmm.lib kernel32.lib user32.lib gdi32.lib ole32.lib wsock32.lib /nologo /stack:0x800000 /subsystem:windows /map /debug /machine:I386 # SUBTRACT BASE LINK32 /incremental:yes /nodefaultlib -# ADD LINK32 ALut.lib OpenAL32.lib win32/FeelIt/ffc10.lib advapi32.lib winmm.lib kernel32.lib user32.lib gdi32.lib ole32.lib wsock32.lib /nologo /stack:0x800000 /subsystem:windows /map /debug /machine:I386 /out:".\FinalBuild/jk2sp.exe" +# ADD LINK32 ALut.lib OpenAL32.lib advapi32.lib winmm.lib kernel32.lib user32.lib gdi32.lib ole32.lib wsock32.lib ff/ifc/ifc22.lib /nologo /stack:0x800000 /subsystem:windows /map /debug /machine:I386 /out:".\FinalBuild/jk2sp.exe" # SUBTRACT LINK32 /incremental:yes /nodefaultlib !ELSEIF "$(CFG)" == "starwars - Win32 SHDebug" @@ -129,7 +129,7 @@ LINK32=link.exe # PROP Ignore_Export_Lib 0 # PROP Target_Dir "" # ADD BASE CPP /nologo /G6 /MTd /W4 /Gm /Gi /GX /ZI /Od /D "_NPATCH" /D "_DEBUG" /D "_JK2EXE" /D "WIN32" /D "_WINDOWS" /Fr /YX /FD /c -# ADD CPP /nologo /G6 /MTd /W4 /Gm /Gi /GX /ZI /Od /D "_DEBUG" /D "MEM_DEBUG" /D "_JK2EXE" /D "WIN32" /D "_WINDOWS" /Fr /YX /FD /c +# ADD CPP /nologo /G6 /MTd /W4 /Gm /Gi /GX /ZI /Od /I "ff/ifc" /D "_DEBUG" /D "MEM_DEBUG" /D "_JK2EXE" /D "WIN32" /D "_WINDOWS" /D "_IMMERSION" /D "_FF" /Fr /YX /FD /c # ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 # ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 # ADD BASE RSC /l 0x409 /fo"win32\winquake.res" /d "_DEBUG" @@ -140,7 +140,7 @@ BSC32=bscmake.exe LINK32=link.exe # ADD BASE LINK32 ALut.lib OpenAL32.lib win32/FeelIt/ffc10d.lib advapi32.lib winmm.lib kernel32.lib user32.lib gdi32.lib ole32.lib wsock32.lib /nologo /stack:0x800000 /subsystem:windows /map /debug /machine:I386 /out:".\Debug/jk2sp.exe" # SUBTRACT BASE LINK32 /profile /incremental:no /nodefaultlib -# ADD LINK32 ./shdebug/exe/smrtheap.obj ALut.lib OpenAL32.lib win32/FeelIt/ffc10d.lib advapi32.lib winmm.lib kernel32.lib user32.lib gdi32.lib ole32.lib wsock32.lib /nologo /stack:0x800000 /subsystem:windows /map /debug /machine:I386 /out:".\SHDebug/jk2sp.exe" +# ADD LINK32 ./shdebug/exe/smrtheap.obj ALut.lib OpenAL32.lib advapi32.lib winmm.lib kernel32.lib user32.lib gdi32.lib ole32.lib wsock32.lib ff/ifc/ifc22.lib /nologo /stack:0x800000 /subsystem:windows /map /debug /machine:I386 /out:".\SHDebug/jk2sp.exe" # SUBTRACT LINK32 /profile /incremental:no /nodefaultlib !ENDIF @@ -1010,102 +1010,127 @@ SOURCE=.\mp3code\wavep.c # Begin Source File SOURCE=.\win32\FeelIt\FeelBaseTypes.h +# PROP Exclude_From_Build 1 # End Source File # Begin Source File SOURCE=.\win32\FeelIt\FeelBox.h +# PROP Exclude_From_Build 1 # End Source File # Begin Source File SOURCE=.\win32\FeelIt\FeelCompoundEffect.h +# PROP Exclude_From_Build 1 # End Source File # Begin Source File SOURCE=.\win32\FeelIt\FeelCondition.h +# PROP Exclude_From_Build 1 # End Source File # Begin Source File SOURCE=.\win32\FeelIt\FeelConstant.h +# PROP Exclude_From_Build 1 # End Source File # Begin Source File SOURCE=.\win32\FeelIt\FeelDamper.h +# PROP Exclude_From_Build 1 # End Source File # Begin Source File SOURCE=.\win32\FeelIt\FeelDevice.h +# PROP Exclude_From_Build 1 # End Source File # Begin Source File SOURCE=.\win32\FeelIt\FeelDXDevice.h +# PROP Exclude_From_Build 1 # End Source File # Begin Source File SOURCE=.\win32\FeelIt\FeelEffect.h +# PROP Exclude_From_Build 1 # End Source File # Begin Source File SOURCE=.\win32\FeelIt\FeelEllipse.h +# PROP Exclude_From_Build 1 # End Source File # Begin Source File SOURCE=.\win32\FeelIt\FeelEnclosure.h +# PROP Exclude_From_Build 1 # End Source File # Begin Source File SOURCE=.\win32\FeelIt\FeelFriction.h +# PROP Exclude_From_Build 1 # End Source File # Begin Source File SOURCE=.\win32\FeelIt\FeelGrid.h +# PROP Exclude_From_Build 1 # End Source File # Begin Source File SOURCE=.\win32\FeelIt\FeelInertia.h +# PROP Exclude_From_Build 1 # End Source File # Begin Source File SOURCE=.\win32\FeelIt\FeelitAPI.h +# PROP Exclude_From_Build 1 # End Source File # Begin Source File SOURCE=.\win32\FeelIt\FEELitIFR.h +# PROP Exclude_From_Build 1 # End Source File # Begin Source File SOURCE=.\win32\FeelIt\FeelMouse.h +# PROP Exclude_From_Build 1 # End Source File # Begin Source File SOURCE=.\win32\FeelIt\FeelPeriodic.h +# PROP Exclude_From_Build 1 # End Source File # Begin Source File SOURCE=.\win32\FeelIt\FeelProjects.h +# PROP Exclude_From_Build 1 # End Source File # Begin Source File SOURCE=.\win32\FeelIt\FeelRamp.h +# PROP Exclude_From_Build 1 # End Source File # Begin Source File SOURCE=.\win32\FeelIt\FeelSpring.h +# PROP Exclude_From_Build 1 # End Source File # Begin Source File SOURCE=.\win32\FeelIt\FeelTexture.h +# PROP Exclude_From_Build 1 # End Source File # Begin Source File SOURCE=.\win32\FeelIt\FFC.h +# PROP Exclude_From_Build 1 # End Source File # Begin Source File SOURCE=.\win32\FeelIt\FFCErrors.h +# PROP Exclude_From_Build 1 # End Source File # Begin Source File SOURCE=.\win32\FeelIt\fffx_feel.h +# PROP Exclude_From_Build 1 # End Source File # End Group # Begin Group "ForceFeedback Binaries" @@ -1114,29 +1139,33 @@ SOURCE=.\win32\FeelIt\fffx_feel.h # Begin Source File SOURCE=.\win32\FeelIt\FFC10.dll +# PROP Exclude_From_Build 1 # End Source File # Begin Source File SOURCE=.\win32\FeelIt\FFC10d.dll +# PROP Exclude_From_Build 1 # End Source File # Begin Source File SOURCE=.\win32\FeelIt\FFC10d.lib +# PROP Exclude_From_Build 1 # End Source File # Begin Source File SOURCE=.\win32\FeelIt\FFC10.lib +# PROP Exclude_From_Build 1 # End Source File # End Group # Begin Source File SOURCE=.\win32\FeelIt\fffx.cpp -# SUBTRACT CPP /YX +# PROP Exclude_From_Build 1 # End Source File # Begin Source File SOURCE=.\win32\FeelIt\fffx_feel.cpp -# SUBTRACT CPP /YX +# PROP Exclude_From_Build 1 # End Source File # End Group # Begin Group "Ghoul2" @@ -1819,5 +1848,253 @@ SOURCE=.\encryption\sockets.cpp SOURCE=.\encryption\sockets.h # End Source File # End Group +# Begin Group "FF (Immersion)" + +# PROP Default_Filter "" +# Begin Group "IFC" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\ff\IFC\FeelitAPI.h +# End Source File +# Begin Source File + +SOURCE=.\ff\IFC\IFC.h +# End Source File +# Begin Source File + +SOURCE=.\ff\IFC\IFCErrors.h +# End Source File +# Begin Source File + +SOURCE=.\ff\IFC\ImmBaseTypes.h +# End Source File +# Begin Source File + +SOURCE=.\ff\IFC\ImmBox.h +# End Source File +# Begin Source File + +SOURCE=.\ff\IFC\ImmCompoundEffect.h +# End Source File +# Begin Source File + +SOURCE=.\ff\IFC\ImmCondition.h +# End Source File +# Begin Source File + +SOURCE=.\ff\IFC\ImmConstant.h +# End Source File +# Begin Source File + +SOURCE=.\ff\IFC\ImmDamper.h +# End Source File +# Begin Source File + +SOURCE=.\ff\IFC\ImmDevice.h +# End Source File +# Begin Source File + +SOURCE=.\ff\IFC\ImmDevices.h +# End Source File +# Begin Source File + +SOURCE=.\ff\IFC\ImmDXDevice.h +# End Source File +# Begin Source File + +SOURCE=.\ff\IFC\ImmEffect.h +# End Source File +# Begin Source File + +SOURCE=.\ff\IFC\ImmEffectSuite.h +# End Source File +# Begin Source File + +SOURCE=.\ff\IFC\ImmEllipse.h +# End Source File +# Begin Source File + +SOURCE=.\ff\IFC\ImmEnclosure.h +# End Source File +# Begin Source File + +SOURCE=.\ff\IFC\ImmFriction.h +# End Source File +# Begin Source File + +SOURCE=.\ff\IFC\ImmGrid.h +# End Source File +# Begin Source File + +SOURCE=.\ff\IFC\ImmIFR.h +# End Source File +# Begin Source File + +SOURCE=.\ff\IFC\ImmInertia.h +# End Source File +# Begin Source File + +SOURCE=.\ff\IFC\ImmMouse.h +# End Source File +# Begin Source File + +SOURCE=.\ff\IFC\ImmPeriodic.h +# End Source File +# Begin Source File + +SOURCE=.\ff\IFC\ImmProjects.h +# End Source File +# Begin Source File + +SOURCE=.\ff\IFC\ImmRamp.h +# End Source File +# Begin Source File + +SOURCE=.\ff\IFC\ImmSpring.h +# End Source File +# Begin Source File + +SOURCE=.\ff\IFC\ImmTexture.h +# End Source File +# End Group +# Begin Group "FF Binaries" + +# PROP Default_Filter "*.dll" +# Begin Source File + +SOURCE=.\IFC22.dll +# End Source File +# Begin Source File + +SOURCE=.\ff\IFC\IFC22.lib +# End Source File +# End Group +# Begin Source File + +SOURCE=.\ff\cl_ff.cpp +# SUBTRACT CPP /YX +# End Source File +# Begin Source File + +SOURCE=.\ff\cl_ff.h +# End Source File +# Begin Source File + +SOURCE=.\ff\common_headers.h +# End Source File +# Begin Source File + +SOURCE=.\ff\ff.cpp +# SUBTRACT CPP /YX +# End Source File +# Begin Source File + +SOURCE=.\ff\ff.h +# End Source File +# Begin Source File + +SOURCE=.\ff\ff_ChannelCompound.h +# End Source File +# Begin Source File + +SOURCE=.\ff\ff_ChannelSet.cpp +# SUBTRACT CPP /YX +# End Source File +# Begin Source File + +SOURCE=.\ff\ff_ChannelSet.h +# End Source File +# Begin Source File + +SOURCE=.\ff\ff_ConfigParser.cpp +# SUBTRACT CPP /YX +# End Source File +# Begin Source File + +SOURCE=.\ff\ff_ConfigParser.h +# End Source File +# Begin Source File + +SOURCE=.\ff\ff_ffset.cpp +# SUBTRACT CPP /YX +# End Source File +# Begin Source File + +SOURCE=.\ff\ff_ffset.h +# End Source File +# Begin Source File + +SOURCE=.\ff\ff_HandleTable.cpp +# SUBTRACT CPP /YX +# End Source File +# Begin Source File + +SOURCE=.\ff\ff_HandleTable.h +# End Source File +# Begin Source File + +SOURCE=.\ff\ff_local.h +# End Source File +# Begin Source File + +SOURCE=.\ff\ff_MultiCompound.cpp +# SUBTRACT CPP /YX +# End Source File +# Begin Source File + +SOURCE=.\ff\ff_MultiCompound.h +# End Source File +# Begin Source File + +SOURCE=.\ff\ff_MultiEffect.cpp +# SUBTRACT CPP /YX +# End Source File +# Begin Source File + +SOURCE=.\ff\ff_MultiEffect.h +# End Source File +# Begin Source File + +SOURCE=.\ff\ff_MultiSet.cpp +# SUBTRACT CPP /YX +# End Source File +# Begin Source File + +SOURCE=.\ff\ff_MultiSet.h +# End Source File +# Begin Source File + +SOURCE=.\ff\ff_public.h +# End Source File +# Begin Source File + +SOURCE=.\ff\ff_snd.cpp +# SUBTRACT CPP /YX +# End Source File +# Begin Source File + +SOURCE=.\ff\ff_snd.h +# End Source File +# Begin Source File + +SOURCE=.\ff\ff_system.cpp +# SUBTRACT CPP /YX +# End Source File +# Begin Source File + +SOURCE=.\ff\ff_system.h +# End Source File +# Begin Source File + +SOURCE=.\ff\ff_utils.cpp +# SUBTRACT CPP /YX +# End Source File +# Begin Source File + +SOURCE=.\ff\ff_utils.h +# End Source File +# End Group # End Target # End Project diff --git a/code/starwars.plg b/code/starwars.plg index 4d87f30..88d2420 100644 --- a/code/starwars.plg +++ b/code/starwars.plg @@ -3,537 +3,286 @@
 

Build Log

---------------------Configuration: starwars - Win32 FinalBuild-------------------- +--------------------Configuration: game - Win32 Debug--------------------

Command Lines

-Creating command line "rc.exe /l 0x409 /fo".\FinalBuild\exe/winquake.res" /i "win32" /d "NDEBUG" "C:\projects\jk2\CODE\win32\winquake.rc"" -Creating temporary file "C:\DOCUME~1\jmonroe\LOCALS~1\Temp\RSP6B3.tmp" with contents +Creating temporary file "C:\DOCUME~1\jmonroe\LOCALS~1\Temp\RSP4829.tmp" with contents [ -/nologo /G6 /MT /W4 /GX /Zi /O2 /D "NDEBUG" /D "FINAL_BUILD" /D "_JK2EXE" /D "WIN32" /D "_WINDOWS" /Fp".\FinalBuild\exe/starwars.pch" /Yu"..\server\exe_headers.h" /Fo".\FinalBuild\exe/" /Fd".\FinalBuild\exe/" /FD /c -"C:\projects\jk2\CODE\client\cl_cgame.cpp" -"C:\projects\jk2\CODE\client\cl_cin.cpp" -"C:\projects\jk2\CODE\client\cl_console.cpp" -"C:\projects\jk2\CODE\client\cl_input.cpp" -"C:\projects\jk2\CODE\client\cl_keys.cpp" -"C:\projects\jk2\CODE\client\cl_main.cpp" -"C:\projects\jk2\CODE\client\cl_mp3.cpp" -"C:\projects\jk2\CODE\client\cl_parse.cpp" -"C:\projects\jk2\CODE\client\cl_scrn.cpp" -"C:\projects\jk2\CODE\client\cl_ui.cpp" -"C:\projects\jk2\CODE\client\snd_ambient.cpp" -"C:\projects\jk2\CODE\client\snd_dma.cpp" -"C:\projects\jk2\CODE\client\snd_mem.cpp" -"C:\projects\jk2\CODE\client\snd_mix.cpp" -"C:\projects\jk2\CODE\client\snd_music.cpp" -"C:\projects\jk2\CODE\server\sv_ccmds.cpp" -"C:\projects\jk2\CODE\server\sv_client.cpp" -"C:\projects\jk2\CODE\server\sv_game.cpp" -"C:\projects\jk2\CODE\server\sv_init.cpp" -"C:\projects\jk2\CODE\server\sv_main.cpp" -"C:\projects\jk2\CODE\server\sv_savegame.cpp" -"C:\projects\jk2\CODE\server\sv_snapshot.cpp" -"C:\projects\jk2\CODE\server\sv_world.cpp" -"C:\projects\jk2\CODE\renderer\tr_animation.cpp" -"C:\projects\jk2\CODE\renderer\tr_backend.cpp" -"C:\projects\jk2\CODE\renderer\tr_bsp.cpp" -"C:\projects\jk2\CODE\renderer\tr_cmds.cpp" -"C:\projects\jk2\CODE\renderer\tr_curve.cpp" -"C:\projects\jk2\CODE\renderer\tr_draw.cpp" -"C:\projects\jk2\CODE\renderer\tr_font.cpp" -"C:\projects\jk2\CODE\renderer\tr_ghoul2.cpp" -"C:\projects\jk2\CODE\renderer\tr_image.cpp" -"C:\projects\jk2\CODE\renderer\tr_init.cpp" -"C:\projects\jk2\CODE\renderer\tr_jpeg_interface.cpp" -"C:\projects\jk2\CODE\renderer\tr_light.cpp" -"C:\projects\jk2\CODE\renderer\tr_main.cpp" -"C:\projects\jk2\CODE\renderer\tr_marks.cpp" -"C:\projects\jk2\CODE\renderer\tr_mesh.cpp" -"C:\projects\jk2\CODE\renderer\tr_model.cpp" -"C:\projects\jk2\CODE\renderer\tr_noise.cpp" -"C:\projects\jk2\CODE\renderer\tr_quicksprite.cpp" -"C:\projects\jk2\CODE\renderer\tr_scene.cpp" -"C:\projects\jk2\CODE\renderer\tr_shade.cpp" -"C:\projects\jk2\CODE\renderer\tr_shade_calc.cpp" -"C:\projects\jk2\CODE\renderer\tr_shader.cpp" -"C:\projects\jk2\CODE\renderer\tr_shadows.cpp" -"C:\projects\jk2\CODE\renderer\tr_sky.cpp" -"C:\projects\jk2\CODE\renderer\tr_stl.cpp" -"C:\projects\jk2\CODE\renderer\tr_surface.cpp" -"C:\projects\jk2\CODE\renderer\tr_surfacesprites.cpp" -"C:\projects\jk2\CODE\renderer\tr_world.cpp" -"C:\projects\jk2\CODE\renderer\tr_WorldEffects.cpp" -"C:\projects\jk2\CODE\win32\win_gamma.cpp" -"C:\projects\jk2\CODE\win32\win_glimp.cpp" -"C:\projects\jk2\CODE\win32\win_qgl.cpp" -"C:\projects\jk2\CODE\ui\ui_atoms.cpp" -"C:\projects\jk2\CODE\ui\ui_connect.cpp" -"C:\projects\jk2\CODE\ui\ui_debug.cpp" -"C:\projects\jk2\CODE\ui\ui_main.cpp" -"C:\projects\jk2\CODE\ui\ui_shared.cpp" -"C:\projects\jk2\CODE\ui\ui_syscalls.cpp" -"C:\projects\jk2\CODE\jpeg-6\jcapimin.cpp" -"C:\projects\jk2\CODE\jpeg-6\jccoefct.cpp" -"C:\projects\jk2\CODE\jpeg-6\jccolor.cpp" -"C:\projects\jk2\CODE\jpeg-6\jcdctmgr.cpp" -"C:\projects\jk2\CODE\jpeg-6\jchuff.cpp" -"C:\projects\jk2\CODE\jpeg-6\jcinit.cpp" -"C:\projects\jk2\CODE\jpeg-6\jcmainct.cpp" -"C:\projects\jk2\CODE\jpeg-6\jcmarker.cpp" -"C:\projects\jk2\CODE\jpeg-6\jcmaster.cpp" -"C:\projects\jk2\CODE\jpeg-6\jcomapi.cpp" -"C:\projects\jk2\CODE\jpeg-6\jcparam.cpp" -"C:\projects\jk2\CODE\jpeg-6\jcphuff.cpp" -"C:\projects\jk2\CODE\jpeg-6\jcprepct.cpp" -"C:\projects\jk2\CODE\jpeg-6\jcsample.cpp" -"C:\projects\jk2\CODE\jpeg-6\jctrans.cpp" -"C:\projects\jk2\CODE\jpeg-6\jdapimin.cpp" -"C:\projects\jk2\CODE\jpeg-6\jdapistd.cpp" -"C:\projects\jk2\CODE\jpeg-6\jdatadst.cpp" -"C:\projects\jk2\CODE\jpeg-6\jdatasrc.cpp" -"C:\projects\jk2\CODE\jpeg-6\jdcoefct.cpp" -"C:\projects\jk2\CODE\jpeg-6\jdcolor.cpp" -"C:\projects\jk2\CODE\jpeg-6\jddctmgr.cpp" -"C:\projects\jk2\CODE\jpeg-6\jdhuff.cpp" -"C:\projects\jk2\CODE\jpeg-6\jdinput.cpp" -"C:\projects\jk2\CODE\jpeg-6\jdmainct.cpp" -"C:\projects\jk2\CODE\jpeg-6\jdmarker.cpp" -"C:\projects\jk2\CODE\jpeg-6\jdmaster.cpp" -"C:\projects\jk2\CODE\jpeg-6\jdpostct.cpp" -"C:\projects\jk2\CODE\jpeg-6\jdsample.cpp" -"C:\projects\jk2\CODE\jpeg-6\jdtrans.cpp" -"C:\projects\jk2\CODE\jpeg-6\jerror.cpp" -"C:\projects\jk2\CODE\jpeg-6\jfdctflt.cpp" -"C:\projects\jk2\CODE\jpeg-6\jidctflt.cpp" -"C:\projects\jk2\CODE\jpeg-6\jmemmgr.cpp" -"C:\projects\jk2\CODE\jpeg-6\jmemnobs.cpp" -"C:\projects\jk2\CODE\jpeg-6\jutils.cpp" +/nologo /G6 /MLd /W4 /Gm /Gi /GX /ZI /Od /I "..\ICARUS" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "_IMMERSION" /FR"..\Debug\game/" /Fp"..\Debug\game/game.pch" /Yu"g_headers.h" /Fo"..\Debug\game/" /Fd"..\Debug\game/" /FD /c +"C:\projects\jk2\CODE\game\g_combat.cpp" ] -Creating command line "cl.exe @C:\DOCUME~1\jmonroe\LOCALS~1\Temp\RSP6B3.tmp" -Creating temporary file "C:\DOCUME~1\jmonroe\LOCALS~1\Temp\RSP6B4.tmp" with contents +Creating command line "cl.exe @C:\DOCUME~1\jmonroe\LOCALS~1\Temp\RSP4829.tmp" +Creating temporary file "C:\DOCUME~1\jmonroe\LOCALS~1\Temp\RSP482A.tmp" with contents [ -/nologo /G6 /MT /W4 /GX /Zi /O2 /D "NDEBUG" /D "FINAL_BUILD" /D "_JK2EXE" /D "WIN32" /D "_WINDOWS" /Fo".\FinalBuild\exe/" /Fd".\FinalBuild\exe/" /FD /c -"C:\projects\jk2\CODE\qcommon\cm_load.cpp" -"C:\projects\jk2\CODE\qcommon\cm_patch.cpp" -"C:\projects\jk2\CODE\qcommon\cm_polylib.cpp" -"C:\projects\jk2\CODE\qcommon\cm_test.cpp" -"C:\projects\jk2\CODE\qcommon\cm_trace.cpp" -"C:\projects\jk2\CODE\qcommon\cmd.cpp" -"C:\projects\jk2\CODE\qcommon\common.cpp" -"C:\projects\jk2\CODE\qcommon\cvar.cpp" -"C:\projects\jk2\CODE\qcommon\files.cpp" -"C:\projects\jk2\CODE\game\genericparser2.cpp" -"C:\projects\jk2\CODE\qcommon\hstring.cpp" -"C:\projects\jk2\CODE\qcommon\md4.cpp" -"C:\projects\jk2\CODE\qcommon\msg.cpp" -"C:\projects\jk2\CODE\qcommon\net_chan.cpp" -"C:\projects\jk2\CODE\game\q_math.cpp" -"C:\projects\jk2\CODE\game\q_shared.cpp" -"C:\projects\jk2\CODE\qcommon\strip.cpp" -"C:\projects\jk2\CODE\qcommon\unzip.cpp" -"C:\projects\jk2\CODE\client\vmachine.cpp" -"C:\projects\jk2\CODE\mp3code\cdct.c" -"C:\projects\jk2\CODE\mp3code\csbt.c" -"C:\projects\jk2\CODE\mp3code\csbtb.c" -"C:\projects\jk2\CODE\mp3code\csbtL3.c" -"C:\projects\jk2\CODE\mp3code\cup.c" -"C:\projects\jk2\CODE\mp3code\cupini.c" -"C:\projects\jk2\CODE\mp3code\cupL1.c" -"C:\projects\jk2\CODE\mp3code\cupl3.c" -"C:\projects\jk2\CODE\mp3code\cwin.c" -"C:\projects\jk2\CODE\mp3code\cwinb.c" -"C:\projects\jk2\CODE\mp3code\cwinm.c" -"C:\projects\jk2\CODE\mp3code\hwin.c" -"C:\projects\jk2\CODE\mp3code\l3dq.c" -"C:\projects\jk2\CODE\mp3code\l3init.c" -"C:\projects\jk2\CODE\mp3code\mdct.c" -"C:\projects\jk2\CODE\mp3code\mhead.c" -"C:\projects\jk2\CODE\mp3code\msis.c" -"C:\projects\jk2\CODE\mp3code\towave.c" -"C:\projects\jk2\CODE\mp3code\uph.c" -"C:\projects\jk2\CODE\mp3code\upsf.c" -"C:\projects\jk2\CODE\mp3code\wavep.c" -"C:\projects\jk2\CODE\win32\FeelIt\fffx.cpp" -"C:\projects\jk2\CODE\win32\FeelIt\fffx_feel.cpp" -"C:\projects\jk2\CODE\renderer\MatComp.c" -"C:\projects\jk2\CODE\encryption\buffer.cpp" -"C:\projects\jk2\CODE\encryption\cpp_interface.cpp" -"C:\projects\jk2\CODE\encryption\sockets.cpp" +kernel32.lib user32.lib winmm.lib /nologo /base:"0x20000000" /subsystem:windows /dll /incremental:yes /pdb:"..\Debug/jk2gamex86.pdb" /debug /machine:I386 /def:".\game.def" /out:"..\Debug/jk2gamex86.dll" /implib:"..\Debug/jk2gamex86.lib" +\projects\jk2\CODE\Debug\game\BlockStream.obj +\projects\jk2\CODE\Debug\game\Instance.obj +\projects\jk2\CODE\Debug\game\Sequence.obj +\projects\jk2\CODE\Debug\game\Sequencer.obj +\projects\jk2\CODE\Debug\game\TaskManager.obj +\projects\jk2\CODE\Debug\game\bg_misc.obj +\projects\jk2\CODE\Debug\game\bg_pangles.obj +\projects\jk2\CODE\Debug\game\bg_panimate.obj +\projects\jk2\CODE\Debug\game\bg_pmove.obj +\projects\jk2\CODE\Debug\game\bg_slidemove.obj +\projects\jk2\CODE\Debug\game\cg_camera.obj +\projects\jk2\CODE\Debug\game\cg_consolecmds.obj +\projects\jk2\CODE\Debug\game\cg_credits.obj +\projects\jk2\CODE\Debug\game\cg_draw.obj +\projects\jk2\CODE\Debug\game\cg_drawtools.obj +\projects\jk2\CODE\Debug\game\cg_effects.obj +\projects\jk2\CODE\Debug\game\cg_ents.obj +\projects\jk2\CODE\Debug\game\cg_event.obj +\projects\jk2\CODE\Debug\game\cg_headers.obj +\projects\jk2\CODE\Debug\game\cg_info.obj +\projects\jk2\CODE\Debug\game\cg_lights.obj +\projects\jk2\CODE\Debug\game\cg_localents.obj +\projects\jk2\CODE\Debug\game\cg_main.obj +\projects\jk2\CODE\Debug\game\cg_marks.obj +\projects\jk2\CODE\Debug\game\cg_players.obj +\projects\jk2\CODE\Debug\game\cg_playerstate.obj +\projects\jk2\CODE\Debug\game\cg_predict.obj +\projects\jk2\CODE\Debug\game\cg_scoreboard.obj +\projects\jk2\CODE\Debug\game\cg_servercmds.obj +\projects\jk2\CODE\Debug\game\cg_snapshot.obj +\projects\jk2\CODE\Debug\game\cg_syscalls.obj +\projects\jk2\CODE\Debug\game\cg_text.obj +\projects\jk2\CODE\Debug\game\cg_view.obj +\projects\jk2\CODE\Debug\game\cg_weapons.obj +\projects\jk2\CODE\Debug\game\FX_ATSTMain.obj +\projects\jk2\CODE\Debug\game\FX_Blaster.obj +\projects\jk2\CODE\Debug\game\FX_Bowcaster.obj +\projects\jk2\CODE\Debug\game\FX_BryarPistol.obj +\projects\jk2\CODE\Debug\game\FX_DEMP2.obj +\projects\jk2\CODE\Debug\game\FX_Disruptor.obj +\projects\jk2\CODE\Debug\game\FX_Emplaced.obj +\projects\jk2\CODE\Debug\game\FX_Flechette.obj +\projects\jk2\CODE\Debug\game\FX_HeavyRepeater.obj +\projects\jk2\CODE\Debug\game\FX_RocketLauncher.obj +\projects\jk2\CODE\Debug\game\FxParsing.obj +\projects\jk2\CODE\Debug\game\FxPrimitives.obj +\projects\jk2\CODE\Debug\game\FxScheduler.obj +\projects\jk2\CODE\Debug\game\FxSystem.obj +\projects\jk2\CODE\Debug\game\FxTemplate.obj +\projects\jk2\CODE\Debug\game\FxUtil.obj +\projects\jk2\CODE\Debug\game\AI_Atst.obj +\projects\jk2\CODE\Debug\game\AI_Default.obj +\projects\jk2\CODE\Debug\game\AI_Droid.obj +\projects\jk2\CODE\Debug\game\AI_GalakMech.obj +\projects\jk2\CODE\Debug\game\AI_Grenadier.obj +\projects\jk2\CODE\Debug\game\AI_Howler.obj +\projects\jk2\CODE\Debug\game\AI_ImperialProbe.obj +\projects\jk2\CODE\Debug\game\AI_Interrogator.obj +\projects\jk2\CODE\Debug\game\AI_Jedi.obj +\projects\jk2\CODE\Debug\game\AI_Mark1.obj +\projects\jk2\CODE\Debug\game\AI_Mark2.obj +\projects\jk2\CODE\Debug\game\AI_MineMonster.obj +\projects\jk2\CODE\Debug\game\AI_Remote.obj +\projects\jk2\CODE\Debug\game\AI_Seeker.obj +\projects\jk2\CODE\Debug\game\AI_Sentry.obj +\projects\jk2\CODE\Debug\game\AI_Sniper.obj +\projects\jk2\CODE\Debug\game\AI_Stormtrooper.obj +\projects\jk2\CODE\Debug\game\AI_Utils.obj +\projects\jk2\CODE\Debug\game\g_active.obj +\projects\jk2\CODE\Debug\game\g_breakable.obj +\projects\jk2\CODE\Debug\game\g_camera.obj +\projects\jk2\CODE\Debug\game\g_client.obj +\projects\jk2\CODE\Debug\game\g_cmds.obj +\projects\jk2\CODE\Debug\game\g_combat.obj +\projects\jk2\CODE\Debug\game\g_functions.obj +\projects\jk2\CODE\Debug\game\g_fx.obj +\projects\jk2\CODE\Debug\game\g_headers.obj +\projects\jk2\CODE\Debug\game\g_ICARUS.obj +\projects\jk2\CODE\Debug\game\g_inventory.obj +\projects\jk2\CODE\Debug\game\g_itemLoad.obj +\projects\jk2\CODE\Debug\game\g_items.obj +\projects\jk2\CODE\Debug\game\g_main.obj +\projects\jk2\CODE\Debug\game\g_mem.obj +\projects\jk2\CODE\Debug\game\g_misc.obj +\projects\jk2\CODE\Debug\game\g_misc_model.obj +\projects\jk2\CODE\Debug\game\g_missile.obj +\projects\jk2\CODE\Debug\game\g_mover.obj +\projects\jk2\CODE\Debug\game\g_nav.obj +\projects\jk2\CODE\Debug\game\g_navigator.obj +\projects\jk2\CODE\Debug\game\g_navnew.obj +\projects\jk2\CODE\Debug\game\g_object.obj +\projects\jk2\CODE\Debug\game\g_objectives.obj +\projects\jk2\CODE\Debug\game\g_ref.obj +\projects\jk2\CODE\Debug\game\g_roff.obj +\projects\jk2\CODE\Debug\game\g_savegame.obj +\projects\jk2\CODE\Debug\game\g_session.obj +\projects\jk2\CODE\Debug\game\g_spawn.obj +\projects\jk2\CODE\Debug\game\g_svcmds.obj +\projects\jk2\CODE\Debug\game\g_target.obj +\projects\jk2\CODE\Debug\game\G_Timer.obj +\projects\jk2\CODE\Debug\game\g_trigger.obj +\projects\jk2\CODE\Debug\game\g_turret.obj +\projects\jk2\CODE\Debug\game\g_usable.obj +\projects\jk2\CODE\Debug\game\g_utils.obj +\projects\jk2\CODE\Debug\game\g_weapon.obj +\projects\jk2\CODE\Debug\game\g_weaponLoad.obj +\projects\jk2\CODE\Debug\game\gameinfo.obj +\projects\jk2\CODE\Debug\game\genericparser2.obj +\projects\jk2\CODE\Debug\game\NPC.obj +\projects\jk2\CODE\Debug\game\NPC_behavior.obj +\projects\jk2\CODE\Debug\game\NPC_combat.obj +\projects\jk2\CODE\Debug\game\NPC_goal.obj +\projects\jk2\CODE\Debug\game\NPC_misc.obj +\projects\jk2\CODE\Debug\game\NPC_move.obj +\projects\jk2\CODE\Debug\game\NPC_reactions.obj +\projects\jk2\CODE\Debug\game\NPC_senses.obj +\projects\jk2\CODE\Debug\game\NPC_sounds.obj +\projects\jk2\CODE\Debug\game\NPC_spawn.obj +\projects\jk2\CODE\Debug\game\NPC_stats.obj +\projects\jk2\CODE\Debug\game\NPC_utils.obj +\projects\jk2\CODE\Debug\game\Q3_Interface.obj +\projects\jk2\CODE\Debug\game\Q3_Registers.obj +\projects\jk2\CODE\Debug\game\q_math.obj +\projects\jk2\CODE\Debug\game\q_shared.obj +\projects\jk2\CODE\Debug\game\tri_coll_test.obj +\projects\jk2\CODE\Debug\game\wp_saber.obj ] -Creating command line "cl.exe @C:\DOCUME~1\jmonroe\LOCALS~1\Temp\RSP6B4.tmp" -Creating temporary file "C:\DOCUME~1\jmonroe\LOCALS~1\Temp\RSP6B5.tmp" with contents -[ -/nologo /G6 /MT /W4 /GX /Zi /O2 /D "NDEBUG" /D "FINAL_BUILD" /D "_JK2EXE" /D "WIN32" /D "_WINDOWS" /Fp".\FinalBuild\exe/starwars.pch" /Yu"../server/exe_headers.h" /Fo".\FinalBuild\exe/" /Fd".\FinalBuild\exe/" /FD /c -"C:\projects\jk2\CODE\win32\win_input.cpp" -"C:\projects\jk2\CODE\win32\win_main.cpp" -"C:\projects\jk2\CODE\win32\win_shared.cpp" -"C:\projects\jk2\CODE\win32\win_snd.cpp" -"C:\projects\jk2\CODE\win32\win_syscon.cpp" -"C:\projects\jk2\CODE\win32\win_video.cpp" -"C:\projects\jk2\CODE\win32\win_wndproc.cpp" -"C:\projects\jk2\CODE\ghoul2\G2_API.cpp" -"C:\projects\jk2\CODE\ghoul2\G2_bolts.cpp" -"C:\projects\jk2\CODE\ghoul2\G2_bones.cpp" -"C:\projects\jk2\CODE\ghoul2\G2_misc.cpp" -"C:\projects\jk2\CODE\ghoul2\G2_surfaces.cpp" -] -Creating command line "cl.exe @C:\DOCUME~1\jmonroe\LOCALS~1\Temp\RSP6B5.tmp" -Creating temporary file "C:\DOCUME~1\jmonroe\LOCALS~1\Temp\RSP6B6.tmp" with contents -[ -/nologo /G6 /MT /W4 /GX /Zi /O2 /D "NDEBUG" /D "FINAL_BUILD" /D "_JK2EXE" /D "WIN32" /D "_WINDOWS" /Fp".\FinalBuild\exe/starwars.pch" /Yc"..\server\exe_headers.h" /Fo".\FinalBuild\exe/" /Fd".\FinalBuild\exe/" /FD /c -"C:\projects\jk2\CODE\server\exe_headers.cpp" -] -Creating command line "cl.exe @C:\DOCUME~1\jmonroe\LOCALS~1\Temp\RSP6B6.tmp" -Creating temporary file "C:\DOCUME~1\jmonroe\LOCALS~1\Temp\RSP6B7.tmp" with contents -[ -ALut.lib OpenAL32.lib win32/FeelIt/ffc10.lib advapi32.lib winmm.lib kernel32.lib user32.lib gdi32.lib ole32.lib wsock32.lib /nologo /stack:0x800000 /subsystem:windows /incremental:no /pdb:".\FinalBuild/jk2sp.pdb" /map:".\FinalBuild\exe/jk2sp.map" /debug /machine:I386 /out:".\FinalBuild/jk2sp.exe" -.\FinalBuild\exe\cl_cgame.obj -.\FinalBuild\exe\cl_cin.obj -.\FinalBuild\exe\cl_console.obj -.\FinalBuild\exe\cl_input.obj -.\FinalBuild\exe\cl_keys.obj -.\FinalBuild\exe\cl_main.obj -.\FinalBuild\exe\cl_mp3.obj -.\FinalBuild\exe\cl_parse.obj -.\FinalBuild\exe\cl_scrn.obj -.\FinalBuild\exe\cl_ui.obj -.\FinalBuild\exe\cm_load.obj -.\FinalBuild\exe\cm_patch.obj -.\FinalBuild\exe\cm_polylib.obj -.\FinalBuild\exe\cm_test.obj -.\FinalBuild\exe\cm_trace.obj -.\FinalBuild\exe\cmd.obj -.\FinalBuild\exe\common.obj -.\FinalBuild\exe\cvar.obj -.\FinalBuild\exe\exe_headers.obj -.\FinalBuild\exe\files.obj -.\FinalBuild\exe\genericparser2.obj -.\FinalBuild\exe\hstring.obj -.\FinalBuild\exe\md4.obj -.\FinalBuild\exe\msg.obj -.\FinalBuild\exe\net_chan.obj -.\FinalBuild\exe\q_math.obj -.\FinalBuild\exe\q_shared.obj -.\FinalBuild\exe\snd_ambient.obj -.\FinalBuild\exe\snd_dma.obj -.\FinalBuild\exe\snd_mem.obj -.\FinalBuild\exe\snd_mix.obj -.\FinalBuild\exe\snd_music.obj -.\FinalBuild\exe\strip.obj -.\FinalBuild\exe\sv_ccmds.obj -.\FinalBuild\exe\sv_client.obj -.\FinalBuild\exe\sv_game.obj -.\FinalBuild\exe\sv_init.obj -.\FinalBuild\exe\sv_main.obj -.\FinalBuild\exe\sv_savegame.obj -.\FinalBuild\exe\sv_snapshot.obj -.\FinalBuild\exe\sv_world.obj -.\FinalBuild\exe\unzip.obj -.\FinalBuild\exe\vmachine.obj -.\FinalBuild\exe\win_input.obj -.\FinalBuild\exe\win_main.obj -.\FinalBuild\exe\win_shared.obj -.\FinalBuild\exe\win_snd.obj -.\FinalBuild\exe\win_syscon.obj -.\FinalBuild\exe\win_video.obj -.\FinalBuild\exe\win_wndproc.obj -.\FinalBuild\exe\cdct.obj -.\FinalBuild\exe\csbt.obj -.\FinalBuild\exe\csbtb.obj -.\FinalBuild\exe\csbtL3.obj -.\FinalBuild\exe\cup.obj -.\FinalBuild\exe\cupini.obj -.\FinalBuild\exe\cupL1.obj -.\FinalBuild\exe\cupl3.obj -.\FinalBuild\exe\cwin.obj -.\FinalBuild\exe\cwinb.obj -.\FinalBuild\exe\cwinm.obj -.\FinalBuild\exe\hwin.obj -.\FinalBuild\exe\l3dq.obj -.\FinalBuild\exe\l3init.obj -.\FinalBuild\exe\mdct.obj -.\FinalBuild\exe\mhead.obj -.\FinalBuild\exe\msis.obj -.\FinalBuild\exe\towave.obj -.\FinalBuild\exe\uph.obj -.\FinalBuild\exe\upsf.obj -.\FinalBuild\exe\wavep.obj -.\FinalBuild\exe\fffx.obj -.\FinalBuild\exe\fffx_feel.obj -.\FinalBuild\exe\G2_API.obj -.\FinalBuild\exe\G2_bolts.obj -.\FinalBuild\exe\G2_bones.obj -.\FinalBuild\exe\G2_misc.obj -.\FinalBuild\exe\G2_surfaces.obj -.\FinalBuild\exe\MatComp.obj -.\FinalBuild\exe\tr_animation.obj -.\FinalBuild\exe\tr_backend.obj -.\FinalBuild\exe\tr_bsp.obj -.\FinalBuild\exe\tr_cmds.obj -.\FinalBuild\exe\tr_curve.obj -.\FinalBuild\exe\tr_draw.obj -.\FinalBuild\exe\tr_font.obj -.\FinalBuild\exe\tr_ghoul2.obj -.\FinalBuild\exe\tr_image.obj -.\FinalBuild\exe\tr_init.obj -.\FinalBuild\exe\tr_jpeg_interface.obj -.\FinalBuild\exe\tr_light.obj -.\FinalBuild\exe\tr_main.obj -.\FinalBuild\exe\tr_marks.obj -.\FinalBuild\exe\tr_mesh.obj -.\FinalBuild\exe\tr_model.obj -.\FinalBuild\exe\tr_noise.obj -.\FinalBuild\exe\tr_quicksprite.obj -.\FinalBuild\exe\tr_scene.obj -.\FinalBuild\exe\tr_shade.obj -.\FinalBuild\exe\tr_shade_calc.obj -.\FinalBuild\exe\tr_shader.obj -.\FinalBuild\exe\tr_shadows.obj -.\FinalBuild\exe\tr_sky.obj -.\FinalBuild\exe\tr_stl.obj -.\FinalBuild\exe\tr_surface.obj -.\FinalBuild\exe\tr_surfacesprites.obj -.\FinalBuild\exe\tr_world.obj -.\FinalBuild\exe\tr_WorldEffects.obj -.\FinalBuild\exe\win_gamma.obj -.\FinalBuild\exe\win_glimp.obj -.\FinalBuild\exe\win_qgl.obj -.\FinalBuild\exe\ui_atoms.obj -.\FinalBuild\exe\ui_connect.obj -.\FinalBuild\exe\ui_debug.obj -.\FinalBuild\exe\ui_main.obj -.\FinalBuild\exe\ui_shared.obj -.\FinalBuild\exe\ui_syscalls.obj -.\FinalBuild\exe\jcapimin.obj -.\FinalBuild\exe\jccoefct.obj -.\FinalBuild\exe\jccolor.obj -.\FinalBuild\exe\jcdctmgr.obj -.\FinalBuild\exe\jchuff.obj -.\FinalBuild\exe\jcinit.obj -.\FinalBuild\exe\jcmainct.obj -.\FinalBuild\exe\jcmarker.obj -.\FinalBuild\exe\jcmaster.obj -.\FinalBuild\exe\jcomapi.obj -.\FinalBuild\exe\jcparam.obj -.\FinalBuild\exe\jcphuff.obj -.\FinalBuild\exe\jcprepct.obj -.\FinalBuild\exe\jcsample.obj -.\FinalBuild\exe\jctrans.obj -.\FinalBuild\exe\jdapimin.obj -.\FinalBuild\exe\jdapistd.obj -.\FinalBuild\exe\jdatadst.obj -.\FinalBuild\exe\jdatasrc.obj -.\FinalBuild\exe\jdcoefct.obj -.\FinalBuild\exe\jdcolor.obj -.\FinalBuild\exe\jddctmgr.obj -.\FinalBuild\exe\jdhuff.obj -.\FinalBuild\exe\jdinput.obj -.\FinalBuild\exe\jdmainct.obj -.\FinalBuild\exe\jdmarker.obj -.\FinalBuild\exe\jdmaster.obj -.\FinalBuild\exe\jdpostct.obj -.\FinalBuild\exe\jdsample.obj -.\FinalBuild\exe\jdtrans.obj -.\FinalBuild\exe\jerror.obj -.\FinalBuild\exe\jfdctflt.obj -.\FinalBuild\exe\jidctflt.obj -.\FinalBuild\exe\jmemmgr.obj -.\FinalBuild\exe\jmemnobs.obj -.\FinalBuild\exe\jutils.obj -.\FinalBuild\exe\buffer.obj -.\FinalBuild\exe\cpp_interface.obj -.\FinalBuild\exe\sockets.obj -.\FinalBuild\exe\winquake.res -.\ALut.lib -.\OpenAL32.lib -.\win32\FeelIt\FFC10d.lib -.\win32\FeelIt\FFC10.lib -.\FinalBuild\jk2gamex86.lib -] -Creating command line "link.exe @C:\DOCUME~1\jmonroe\LOCALS~1\Temp\RSP6B7.tmp" +Creating command line "link.exe @C:\DOCUME~1\jmonroe\LOCALS~1\Temp\RSP482A.tmp"

Output Window

-Compiling resources... Compiling... -exe_headers.cpp -Compiling... -cl_cgame.cpp -cl_cin.cpp -cl_console.cpp -cl_input.cpp -cl_keys.cpp -cl_main.cpp -cl_mp3.cpp -cl_parse.cpp -cl_scrn.cpp -cl_ui.cpp -snd_ambient.cpp -snd_dma.cpp -snd_mem.cpp -snd_mix.cpp -snd_music.cpp -sv_ccmds.cpp -sv_client.cpp -sv_game.cpp -sv_init.cpp -sv_main.cpp -Generating Code... -Compiling... -sv_savegame.cpp -sv_snapshot.cpp -sv_world.cpp -tr_animation.cpp -tr_backend.cpp -tr_bsp.cpp -tr_cmds.cpp -tr_curve.cpp -tr_draw.cpp -tr_font.cpp -tr_ghoul2.cpp -tr_image.cpp -tr_init.cpp -tr_jpeg_interface.cpp -tr_light.cpp -tr_main.cpp -tr_marks.cpp -tr_mesh.cpp -tr_model.cpp -tr_noise.cpp -Generating Code... -Compiling... -tr_quicksprite.cpp -tr_scene.cpp -tr_shade.cpp -tr_shade_calc.cpp -tr_shader.cpp -tr_shadows.cpp -tr_sky.cpp -tr_stl.cpp -tr_surface.cpp -tr_surfacesprites.cpp -tr_world.cpp -tr_WorldEffects.cpp -win_gamma.cpp -win_glimp.cpp -win_qgl.cpp -ui_atoms.cpp -ui_connect.cpp -ui_debug.cpp -ui_main.cpp -ui_shared.cpp -Generating Code... -Compiling... -ui_syscalls.cpp -jcapimin.cpp -jccoefct.cpp -jccolor.cpp -jcdctmgr.cpp -jchuff.cpp -jcinit.cpp -jcmainct.cpp -jcmarker.cpp -jcmaster.cpp -jcomapi.cpp -jcparam.cpp -jcphuff.cpp -jcprepct.cpp -jcsample.cpp -jctrans.cpp -jdapimin.cpp -jdapistd.cpp -jdatadst.cpp -jdatasrc.cpp -Generating Code... -Compiling... -jdcoefct.cpp -jdcolor.cpp -jddctmgr.cpp -jdhuff.cpp -jdinput.cpp -jdmainct.cpp -jdmarker.cpp -jdmaster.cpp -jdpostct.cpp -jdsample.cpp -jdtrans.cpp -jerror.cpp -jfdctflt.cpp -jidctflt.cpp -jmemmgr.cpp -jmemnobs.cpp -jutils.cpp -Generating Code... -Compiling... -cm_load.cpp -cm_patch.cpp -cm_polylib.cpp -cm_test.cpp -cm_trace.cpp -cmd.cpp -common.cpp -cvar.cpp -files.cpp -genericparser2.cpp -hstring.cpp -md4.cpp -msg.cpp -net_chan.cpp -q_math.cpp -q_shared.cpp -strip.cpp -unzip.cpp -vmachine.cpp -Generating Code... -Compiling... -cdct.c -csbt.c -csbtb.c -csbtL3.c -cup.c -cupini.c -cupL1.c -cupl3.c -cwin.c -cwinb.c -cwinm.c -hwin.c -l3dq.c -l3init.c -mdct.c -mhead.c -msis.c -towave.c -uph.c -upsf.c -Generating Code... -Compiling... -wavep.c -Generating Code... -Compiling... -fffx.cpp -fffx_feel.cpp -Generating Code... -Compiling... -MatComp.c -Generating Code... -Compiling... -buffer.cpp -cpp_interface.cpp -sockets.cpp -Generating Code... -Compiling... -win_input.cpp -win_main.cpp -win_shared.cpp -win_snd.cpp -win_syscon.cpp -win_video.cpp -win_wndproc.cpp -G2_API.cpp -G2_bolts.cpp -G2_bones.cpp -G2_misc.cpp -G2_surfaces.cpp -Generating Code... +g_combat.cpp Linking... +Creating temporary file "C:\DOCUME~1\jmonroe\LOCALS~1\Temp\RSP482C.tmp" with contents +[ +/nologo /o"..\Debug/game.bsc" +\projects\jk2\CODE\Debug\game\g_headers.sbr +\projects\jk2\CODE\Debug\game\BlockStream.sbr +\projects\jk2\CODE\Debug\game\Instance.sbr +\projects\jk2\CODE\Debug\game\Sequence.sbr +\projects\jk2\CODE\Debug\game\Sequencer.sbr +\projects\jk2\CODE\Debug\game\TaskManager.sbr +\projects\jk2\CODE\Debug\game\bg_misc.sbr +\projects\jk2\CODE\Debug\game\bg_pangles.sbr +\projects\jk2\CODE\Debug\game\bg_panimate.sbr +\projects\jk2\CODE\Debug\game\bg_pmove.sbr +\projects\jk2\CODE\Debug\game\bg_slidemove.sbr +\projects\jk2\CODE\Debug\game\cg_camera.sbr +\projects\jk2\CODE\Debug\game\cg_consolecmds.sbr +\projects\jk2\CODE\Debug\game\cg_credits.sbr +\projects\jk2\CODE\Debug\game\cg_draw.sbr +\projects\jk2\CODE\Debug\game\cg_drawtools.sbr +\projects\jk2\CODE\Debug\game\cg_effects.sbr +\projects\jk2\CODE\Debug\game\cg_ents.sbr +\projects\jk2\CODE\Debug\game\cg_event.sbr +\projects\jk2\CODE\Debug\game\cg_headers.sbr +\projects\jk2\CODE\Debug\game\cg_info.sbr +\projects\jk2\CODE\Debug\game\cg_lights.sbr +\projects\jk2\CODE\Debug\game\cg_localents.sbr +\projects\jk2\CODE\Debug\game\cg_main.sbr +\projects\jk2\CODE\Debug\game\cg_marks.sbr +\projects\jk2\CODE\Debug\game\cg_players.sbr +\projects\jk2\CODE\Debug\game\cg_playerstate.sbr +\projects\jk2\CODE\Debug\game\cg_predict.sbr +\projects\jk2\CODE\Debug\game\cg_scoreboard.sbr +\projects\jk2\CODE\Debug\game\cg_servercmds.sbr +\projects\jk2\CODE\Debug\game\cg_snapshot.sbr +\projects\jk2\CODE\Debug\game\cg_syscalls.sbr +\projects\jk2\CODE\Debug\game\cg_text.sbr +\projects\jk2\CODE\Debug\game\cg_view.sbr +\projects\jk2\CODE\Debug\game\cg_weapons.sbr +\projects\jk2\CODE\Debug\game\FX_ATSTMain.sbr +\projects\jk2\CODE\Debug\game\FX_Blaster.sbr +\projects\jk2\CODE\Debug\game\FX_Bowcaster.sbr +\projects\jk2\CODE\Debug\game\FX_BryarPistol.sbr +\projects\jk2\CODE\Debug\game\FX_DEMP2.sbr +\projects\jk2\CODE\Debug\game\FX_Disruptor.sbr +\projects\jk2\CODE\Debug\game\FX_Emplaced.sbr +\projects\jk2\CODE\Debug\game\FX_Flechette.sbr +\projects\jk2\CODE\Debug\game\FX_HeavyRepeater.sbr +\projects\jk2\CODE\Debug\game\FX_RocketLauncher.sbr +\projects\jk2\CODE\Debug\game\FxParsing.sbr +\projects\jk2\CODE\Debug\game\FxPrimitives.sbr +\projects\jk2\CODE\Debug\game\FxScheduler.sbr +\projects\jk2\CODE\Debug\game\FxSystem.sbr +\projects\jk2\CODE\Debug\game\FxTemplate.sbr +\projects\jk2\CODE\Debug\game\FxUtil.sbr +\projects\jk2\CODE\Debug\game\AI_Atst.sbr +\projects\jk2\CODE\Debug\game\AI_Default.sbr +\projects\jk2\CODE\Debug\game\AI_Droid.sbr +\projects\jk2\CODE\Debug\game\AI_GalakMech.sbr +\projects\jk2\CODE\Debug\game\AI_Grenadier.sbr +\projects\jk2\CODE\Debug\game\AI_Howler.sbr +\projects\jk2\CODE\Debug\game\AI_ImperialProbe.sbr +\projects\jk2\CODE\Debug\game\AI_Interrogator.sbr +\projects\jk2\CODE\Debug\game\AI_Jedi.sbr +\projects\jk2\CODE\Debug\game\AI_Mark1.sbr +\projects\jk2\CODE\Debug\game\AI_Mark2.sbr +\projects\jk2\CODE\Debug\game\AI_MineMonster.sbr +\projects\jk2\CODE\Debug\game\AI_Remote.sbr +\projects\jk2\CODE\Debug\game\AI_Seeker.sbr +\projects\jk2\CODE\Debug\game\AI_Sentry.sbr +\projects\jk2\CODE\Debug\game\AI_Sniper.sbr +\projects\jk2\CODE\Debug\game\AI_Stormtrooper.sbr +\projects\jk2\CODE\Debug\game\AI_Utils.sbr +\projects\jk2\CODE\Debug\game\g_active.sbr +\projects\jk2\CODE\Debug\game\g_breakable.sbr +\projects\jk2\CODE\Debug\game\g_camera.sbr +\projects\jk2\CODE\Debug\game\g_client.sbr +\projects\jk2\CODE\Debug\game\g_cmds.sbr +\projects\jk2\CODE\Debug\game\g_combat.sbr +\projects\jk2\CODE\Debug\game\g_functions.sbr +\projects\jk2\CODE\Debug\game\g_fx.sbr +\projects\jk2\CODE\Debug\game\g_ICARUS.sbr +\projects\jk2\CODE\Debug\game\g_inventory.sbr +\projects\jk2\CODE\Debug\game\g_itemLoad.sbr +\projects\jk2\CODE\Debug\game\g_items.sbr +\projects\jk2\CODE\Debug\game\g_main.sbr +\projects\jk2\CODE\Debug\game\g_mem.sbr +\projects\jk2\CODE\Debug\game\g_misc.sbr +\projects\jk2\CODE\Debug\game\g_misc_model.sbr +\projects\jk2\CODE\Debug\game\g_missile.sbr +\projects\jk2\CODE\Debug\game\g_mover.sbr +\projects\jk2\CODE\Debug\game\g_nav.sbr +\projects\jk2\CODE\Debug\game\g_navigator.sbr +\projects\jk2\CODE\Debug\game\g_navnew.sbr +\projects\jk2\CODE\Debug\game\g_object.sbr +\projects\jk2\CODE\Debug\game\g_objectives.sbr +\projects\jk2\CODE\Debug\game\g_ref.sbr +\projects\jk2\CODE\Debug\game\g_roff.sbr +\projects\jk2\CODE\Debug\game\g_savegame.sbr +\projects\jk2\CODE\Debug\game\g_session.sbr +\projects\jk2\CODE\Debug\game\g_spawn.sbr +\projects\jk2\CODE\Debug\game\g_svcmds.sbr +\projects\jk2\CODE\Debug\game\g_target.sbr +\projects\jk2\CODE\Debug\game\G_Timer.sbr +\projects\jk2\CODE\Debug\game\g_trigger.sbr +\projects\jk2\CODE\Debug\game\g_turret.sbr +\projects\jk2\CODE\Debug\game\g_usable.sbr +\projects\jk2\CODE\Debug\game\g_utils.sbr +\projects\jk2\CODE\Debug\game\g_weapon.sbr +\projects\jk2\CODE\Debug\game\g_weaponLoad.sbr +\projects\jk2\CODE\Debug\game\gameinfo.sbr +\projects\jk2\CODE\Debug\game\genericparser2.sbr +\projects\jk2\CODE\Debug\game\NPC.sbr +\projects\jk2\CODE\Debug\game\NPC_behavior.sbr +\projects\jk2\CODE\Debug\game\NPC_combat.sbr +\projects\jk2\CODE\Debug\game\NPC_goal.sbr +\projects\jk2\CODE\Debug\game\NPC_misc.sbr +\projects\jk2\CODE\Debug\game\NPC_move.sbr +\projects\jk2\CODE\Debug\game\NPC_reactions.sbr +\projects\jk2\CODE\Debug\game\NPC_senses.sbr +\projects\jk2\CODE\Debug\game\NPC_sounds.sbr +\projects\jk2\CODE\Debug\game\NPC_spawn.sbr +\projects\jk2\CODE\Debug\game\NPC_stats.sbr +\projects\jk2\CODE\Debug\game\NPC_utils.sbr +\projects\jk2\CODE\Debug\game\Q3_Interface.sbr +\projects\jk2\CODE\Debug\game\Q3_Registers.sbr +\projects\jk2\CODE\Debug\game\q_math.sbr +\projects\jk2\CODE\Debug\game\q_shared.sbr +\projects\jk2\CODE\Debug\game\tri_coll_test.sbr +\projects\jk2\CODE\Debug\game\wp_saber.sbr] +Creating command line "bscmake.exe @C:\DOCUME~1\jmonroe\LOCALS~1\Temp\RSP482C.tmp" +Creating browse info file... +

Output Window

+

+--------------------Configuration: starwars - Win32 Debug-------------------- +

+

Command Lines

diff --git a/code/ui/ui_atoms.cpp b/code/ui/ui_atoms.cpp index 5fceff6..42a3ea4 100644 --- a/code/ui/ui_atoms.cpp +++ b/code/ui/ui_atoms.cpp @@ -47,7 +47,7 @@ void UI_SetActiveMenu( const char* menuname,const char *menuID ) { // this should be the ONLY way the menu system is brought up (besides the UI_ConsoleCommand below) - if (!ui.SG_GameAllowedToSaveHere(qtrue)) //don't check full sytem, only if incamera + if (cls.state != CA_DISCONNECTED && !ui.SG_GameAllowedToSaveHere(qtrue)) //don't check full sytem, only if incamera { return; } @@ -214,9 +214,6 @@ void UI_Init( int apiVersion, uiimport_t *uiimport ) ui.Cvar_Create( "cg_drawCrosshair", "1", CVAR_ARCHIVE ); ui.Cvar_Create( "cg_marks", "1", CVAR_ARCHIVE ); ui.Cvar_Create ("s_language", "english", CVAR_ARCHIVE | CVAR_NORESTART); - ui.Cvar_Create ("k_language", "", CVAR_ARCHIVE | CVAR_NORESTART); - - } // these are only here so the functions in q_shared.c can link diff --git a/code/ui/ui_connect.cpp b/code/ui/ui_connect.cpp index 404ce81..89de3ef 100644 --- a/code/ui/ui_connect.cpp +++ b/code/ui/ui_connect.cpp @@ -188,7 +188,7 @@ UI_KeyConnect */ void UI_KeyConnect( int key ) { - if ( key == K_ESCAPE ) + if ( key == A_ESCAPE ) { ui.Cmd_ExecuteText( EXEC_APPEND, "disconnect\n" ); return; diff --git a/code/ui/ui_local.h b/code/ui/ui_local.h index 9159c7b..18024fd 100644 --- a/code/ui/ui_local.h +++ b/code/ui/ui_local.h @@ -95,6 +95,12 @@ extern uiimport_t ui; #define MAX_MOVIES 256 +#define MAX_MODS 64 + +typedef struct { + const char *modName; + const char *modDescr; +} modInfo_t; typedef struct { displayContextDef_t uiDC; @@ -107,6 +113,7 @@ typedef struct { int effectsColor; int currentCrosshair; + modInfo_t modList[MAX_MODS]; int modIndex; qboolean teamLeader; @@ -158,6 +165,10 @@ void trap_R_AddRefEntityToScene( const refEntity_t *re ); void trap_R_RenderScene( const refdef_t *fd ); sfxHandle_t trap_S_RegisterSound( const char *sample, qboolean compressed ); void trap_S_StartLocalSound( sfxHandle_t sfx, int channelNum ); +#ifdef _IMMERSION +ffHandle_t trap_FF_Register( const char *name, int channel = FF_CHANNEL_MENU ); +void trap_FF_Start( ffHandle_t ff ); +#endif // _IMMERSION int PASSFLOAT( float x ); diff --git a/code/ui/ui_main.cpp b/code/ui/ui_main.cpp index ee02d63..c398f87 100644 --- a/code/ui/ui_main.cpp +++ b/code/ui/ui_main.cpp @@ -175,6 +175,36 @@ void _UI_Refresh( int realtime ) } } +/* +=============== +UI_LoadMods +=============== +*/ +static void UI_LoadMods() { + int numdirs; + char dirlist[2048]; + char *dirptr; + char *descptr; + int i; + int dirlen; + + uiInfo.modCount = 0; + numdirs = FS_GetFileList( "$modlist", "", dirlist, sizeof(dirlist) ); + dirptr = dirlist; + for( i = 0; i < numdirs; i++ ) { + dirlen = strlen( dirptr ) + 1; + descptr = dirptr + dirlen; + uiInfo.modList[uiInfo.modCount].modName = String_Alloc(dirptr); + uiInfo.modList[uiInfo.modCount].modDescr = String_Alloc(descptr); + dirptr += dirlen + strlen(descptr) + 1; + uiInfo.modCount++; + if (uiInfo.modCount >= MAX_MODS) { + break; + } + } + +} + /* ================ vmMain @@ -286,16 +316,13 @@ const char *UI_FeederItemText(float feederID, int index, int column, qhandle_t * return s_savedata[index].currentSaveFileDateTimeString; } } - if (feederID == FEEDER_MODS) - { - return ""; - } /* if (feederID == FEEDER_MAPS) { int actual; return UI_SelectedMap(index, &actual); } - else if (feederID == FEEDER_MODS) + else +*/ if (feederID == FEEDER_MODS) { if (index >= 0 && index < uiInfo.modCount) { @@ -309,6 +336,7 @@ const char *UI_FeederItemText(float feederID, int index, int column, qhandle_t * } } } +/* else if (feederID == FEEDER_DEMOS) { if (index >= 0 && index < uiInfo.demoCount) @@ -414,7 +442,7 @@ static qboolean UI_DeferMenuScript ( const char **args ) } // Defer if the video options were modified - deferred = Cvar_VariableValue ( "ui_r_modified" ) ? qtrue : qfalse; + deferred = Cvar_VariableIntegerValue( "ui_r_modified" ) ? qtrue : qfalse; if ( deferred ) { @@ -512,8 +540,6 @@ static qboolean UI_RunMenuScript ( const char **args ) ui.Cmd_ExecuteText( EXEC_APPEND, va("save %s\n", fileName)); s_savegame.saveFileCnt = -1; //force a refresh the next time around } - // FIXME BOB - do we want this? - /* else if (Q_stricmp(name, "LoadMods") == 0) { UI_LoadMods(); @@ -521,12 +547,17 @@ static qboolean UI_RunMenuScript ( const char **args ) else if (Q_stricmp(name, "RunMod") == 0) { Cvar_Set( "fs_game", uiInfo.modList[uiInfo.modIndex].modName); +extern void FS_Restart( void ); + FS_Restart(); Cbuf_ExecuteText( EXEC_APPEND, "vid_restart;" ); } + // FIXME BOB - do we want this? + /* else if (Q_stricmp(name, "RunDemo") == 0) { Cbuf_ExecuteText( EXEC_APPEND, va("demo %s\n", uiInfo.demoList[uiInfo.demoIndex])); - } */ + } + */ else if (Q_stricmp(name, "Quit") == 0) { Cbuf_ExecuteText( EXEC_NOW, "quit"); @@ -588,11 +619,22 @@ static qboolean UI_RunMenuScript ( const char **args ) else if (Q_stricmp(name, "startgame") == 0) { Menus_CloseAll(); + if ( Cvar_VariableIntegerValue("com_demo") ) + { #ifdef FINAL_BUILD - ui.Cmd_ExecuteText( EXEC_APPEND, "map kejim_post\n"); + ui.Cmd_ExecuteText( EXEC_APPEND, "map demo\n"); #else - ui.Cmd_ExecuteText( EXEC_APPEND, "devmap kejim_post\n"); + ui.Cmd_ExecuteText( EXEC_APPEND, "devmap demo\n"); #endif + } + else + { +#ifdef FINAL_BUILD + ui.Cmd_ExecuteText( EXEC_APPEND, "map kejim_post\n"); +#else + ui.Cmd_ExecuteText( EXEC_APPEND, "devmap kejim_post\n"); +#endif + } } else if (Q_stricmp(name, "startmap") == 0) { @@ -779,9 +821,9 @@ void Key_GetBindingBuf( int keynum, char *buf, int buflen ); static qboolean UI_Crosshair_HandleKey(int flags, float *special, int key) { - if (key == K_MOUSE1 || key == K_MOUSE2 || key == K_ENTER || key == K_KP_ENTER) + if (key == A_MOUSE1 || key == A_MOUSE2 || key == A_ENTER || key == A_KP_ENTER) { - if (key == K_MOUSE2) + if (key == A_MOUSE2) { uiInfo.currentCrosshair--; } else { @@ -886,6 +928,10 @@ void _UI_Init( qboolean inGameLoad ) uiInfo.uiDC.textWidth = &Text_Width; uiInfo.uiDC.feederItemImage = &UI_FeederItemImage; uiInfo.uiDC.feederItemText = &UI_FeederItemText; +#ifdef _IMMERSION + uiInfo.uiDC.registerForce = &trap_FF_Register; + uiInfo.uiDC.startForce = &trap_FF_Start; +#endif // _IMMERSION uiInfo.uiDC.ownerDrawHandleKey = &UI_OwnerDrawHandleKey; UI_Load(); @@ -913,22 +959,7 @@ void _UI_Init( qboolean inGameLoad ) Cvar_Set("ui_mousePitch", (trap_Cvar_VariableValue("m_pitch") >= 0) ? "0" : "1"); Cvar_Set("cg_endcredits", "0"); // Reset value - - // FIXME BOB - is this needed? -/* - uiInfo.serverStatus.currentServerCinematic = -1; - uiInfo.previewMovie = -1; - - if (trap_Cvar_VariableValue("ui_TeamArenaFirstRun") == 0) { - Cvar_Set("s_volume", "0.8"); - Cvar_Set("s_musicvolume", "0.5"); - Cvar_Set("ui_TeamArenaFirstRun", "1"); - } - - Cvar_Register(NULL, "debug_protocol", "", 0 ); - - Cvar_Set("ui_actualNetGameType", va("%d", ui_netGameType.integer)); - */ + Cvar_Set("ui_hidelang", "0"); //default to western, taiwanese config will set to hide european and show taiwanese on menu } @@ -1367,6 +1398,53 @@ qboolean Asset_Parse(char **buffer) continue; } +#ifdef _IMMERSION + + if (Q_stricmp(token, "menuEnterForce") == 0) + { + if (!PC_ParseStringMem((const char **) &tempStr)) + { + PC_ParseWarning("Bad 1st parameter for keyword 'menuEnterForce'"); + return qfalse; + } + uiInfo.uiDC.Assets.menuEnterForce = trap_FF_Register( tempStr ); + continue; + } + + if (Q_stricmp(token, "menuExitForce") == 0) + { + if (!PC_ParseStringMem((const char **) &tempStr)) + { + PC_ParseWarning("Bad 1st parameter for keyword 'menuExitForce'"); + return qfalse; + } + uiInfo.uiDC.Assets.menuExitForce = trap_FF_Register( tempStr ); + continue; + } + + if (Q_stricmp(token, "itemFocusForce") == 0) + { + if (!PC_ParseStringMem((const char **) &tempStr)) + { + PC_ParseWarning("Bad 1st parameter for keyword 'itemFocusForce'"); + return qfalse; + } + uiInfo.uiDC.Assets.itemFocusForce = trap_FF_Register( tempStr ); + continue; + } + + if (Q_stricmp(token, "menuBuzzForce") == 0) + { + if (!PC_ParseStringMem((const char **) &tempStr)) + { + PC_ParseWarning("Bad 1st parameter for keyword 'menuBuzzForce'"); + return qfalse; + } + uiInfo.uiDC.Assets.menuBuzzForce = trap_FF_Register( tempStr ); + continue; + } + +#endif // _IMMERSION if (Q_stricmp(token, "cursor") == 0) { if (!PC_ParseStringMem((const char **) &uiInfo.uiDC.Assets.cursorStr)) @@ -1461,6 +1539,13 @@ static void UI_Update(const char *name) ui.Cmd_ExecuteText( EXEC_APPEND, "snd_restart\n" ); return; } +#ifdef _IMMERSION + if (Q_stricmp(name, "ff") == 0) + { + ui.Cmd_ExecuteText( EXEC_APPEND, "ff_restart\n"); + return; + } +#endif // _IMMERSION if (Q_stricmp(name, "ui_SetName") == 0) { @@ -2195,7 +2280,7 @@ void _UI_KeyEvent( int key, qboolean down ) menuDef_t *menu = Menu_GetFocused(); if (menu) { - if (key == K_ESCAPE && down && !Menus_AnyFullScreenVisible()) + if (key == A_ESCAPE && down && !Menus_AnyFullScreenVisible()) { Menus_CloseAll(); } @@ -2500,8 +2585,8 @@ UI_ResetDefaults */ void UI_ResetDefaults( void ) { - ui.Cmd_ExecuteText( EXEC_APPEND, "exec default.cfg\n"); ui.Cmd_ExecuteText( EXEC_APPEND, "cvar_restart\n"); + ui.Cmd_ExecuteText( EXEC_APPEND, "exec default.cfg\n"); ui.Cmd_ExecuteText( EXEC_APPEND, "vid_restart\n" ); Cvar_Set("com_introPlayed", "1" ); } diff --git a/code/ui/ui_public.h b/code/ui/ui_public.h index c2e2786..6ffee7a 100644 --- a/code/ui/ui_public.h +++ b/code/ui/ui_public.h @@ -5,7 +5,7 @@ #include "../client/keycodes.h" -#define UI_API_VERSION 2 +#define UI_API_VERSION 3 typedef struct { @@ -53,6 +53,7 @@ typedef struct { int (*R_Font_HeightPixels)(const int setIndex, const float scale = 1.0f); void (*R_Font_DrawString)(int ox, int oy, const char *text, const float *rgba, const int setIndex, int iMaxPixelWidth, const float scale = 1.0f); qboolean (*Language_IsAsian) (void); + qboolean (*Language_UsesSpaces) (void); unsigned int (*AnyLanguage_ReadCharFromString)( const char **ppsText, qboolean *pbIsTrailingPunctuation /* = NULL */); // a scene is built up by calls to R_ClearScene and the various R_Add functions. diff --git a/code/ui/ui_shared.cpp b/code/ui/ui_shared.cpp index 5752f5b..f9f396f 100644 --- a/code/ui/ui_shared.cpp +++ b/code/ui/ui_shared.cpp @@ -1881,6 +1881,12 @@ qboolean Script_SetFocus(itemDef_t *item, const char **args) { DC->startLocalSound( DC->Assets.itemFocusSound, CHAN_LOCAL_SOUND ); } +#ifdef _IMMERSION + if (DC->Assets.itemFocusForce) + { + DC->startForce( DC->Assets.itemFocusForce ); + } +#endif // _IMMERSION } } @@ -2110,6 +2116,22 @@ qboolean Script_playLooped(itemDef_t *item, const char **args) return qtrue; } +#ifdef _IMMERSION +/* +================= +Script_FFPlay +================= +*/ +qboolean Script_FFPlay(itemDef_t *item, const char **args) +{ + const char *val; + if (String_Parse(args, &val)) + { + DC->startForce(DC->registerForce(val)); + } + return qtrue; +} +#endif // _IMMERSION /* ================= Script_Orbit @@ -2147,6 +2169,9 @@ commandDef_t commandList[] = {"orbit", &Script_Orbit}, // group/name {"play", &Script_Play}, // group/name {"playlooped", &Script_playLooped}, // group/name +#ifdef _IMMERSION + {"ffplay", &Script_FFPlay}, +#endif // _IMMERSION {"setasset", &Script_SetAsset}, // works on this {"setbackground", &Script_SetBackground}, // works on this {"setcolor", &Script_SetColor}, // works on this @@ -2286,9 +2311,28 @@ qboolean ItemParse_focusSound( itemDef_t *item) +#ifdef _IMMERSION +/* +=============== +ItemParse_focusForce + name +=============== +*/ +qboolean ItemParse_focusForce( itemDef_t *item) +{ + const char *temp; + + if (!PC_ParseStringMem((const char **)&temp)) + { //#ifdef _DEBUG //extern void UI_Debug_EnterReference(LPCSTR ps4LetterType, LPCSTR psItemString); //#endif + return qfalse; + } + item->focusForce = DC->registerForce(temp); + return qtrue; +} +#endif // _IMMERSION /* =============== @@ -3740,6 +3784,9 @@ keywordHash_t itemParseKeywords[] = { {"feeder", ItemParse_feeder, }, {"flag", ItemParse_flag, }, {"focusSound", ItemParse_focusSound, }, +#ifdef _IMMERSION + {"focusForce", ItemParse_focusForce, }, +#endif // _IMMERSION {"font", ItemParse_font, }, {"forecolor", ItemParse_forecolor, }, {"group", ItemParse_group, }, @@ -4078,14 +4125,14 @@ typedef struct { static bind_t g_bindings[] = { - {"invuse", K_ENTER, -1, -1, -1}, - {"force_throw", K_F1, -1, -1, -1}, - {"force_pull", K_F2, -1, -1, -1}, - {"force_speed", K_F3, -1, -1, -1}, - {"force_distract", K_F4, -1, -1, -1}, - {"force_heal", K_F5, -1, -1, -1}, - {"+force_grip", K_F6, -1, -1, -1}, - {"+force_lightning",K_F7, -1, -1, -1}, + {"invuse", A_ENTER, -1, -1, -1}, + {"force_throw", A_F1, -1, -1, -1}, + {"force_pull", A_F2, -1, -1, -1}, + {"force_speed", A_F3, -1, -1, -1}, + {"force_distract", A_F4, -1, -1, -1}, + {"force_heal", A_F5, -1, -1, -1}, + {"+force_grip", A_F6, -1, -1, -1}, + {"+force_lightning",A_F7, -1, -1, -1}, {"+useforce", 'f', -1, -1, -1}, {"forceprev", 'z', -1, -1, -1}, {"forcenext", 'x', -1, -1, -1}, @@ -4097,20 +4144,20 @@ static bind_t g_bindings[] = {"invnext", -1, -1, -1, -1}, {"invprev", -1, -1, -1, -1}, {"invuse", -1, -1, -1, -1}, - {"+speed", K_SHIFT, -1, -1, -1}, - {"+forward", K_UPARROW, -1, -1, -1}, - {"+back", K_DOWNARROW, -1, -1, -1}, + {"+speed", A_SHIFT, -1, -1, -1}, + {"+forward", A_CURSOR_UP, -1, -1, -1}, + {"+back", A_CURSOR_DOWN, -1, -1, -1}, {"+moveleft", ',', -1, -1, -1}, {"+moveright", '.', -1, -1, -1}, {"+moveup", 'v', -1, -1, -1}, {"+movedown", 'c', -1, -1, -1}, - {"+left", K_LEFTARROW, -1, -1, -1}, - {"+right", K_RIGHTARROW, -1, -1, -1}, - {"+strafe", K_ALT, -1, -1, -1}, - {"+lookup", K_PGDN, -1, -1, -1}, - {"+lookdown", K_DEL, -1, -1, -1}, + {"+left", A_CURSOR_LEFT, -1, -1, -1}, + {"+right", A_CURSOR_RIGHT, -1, -1, -1}, + {"+strafe", A_ALT, -1, -1, -1}, + {"+lookup", A_PAGE_DOWN, -1, -1, -1}, + {"+lookdown", A_DELETE, -1, -1, -1}, {"+mlook", '/', -1, -1, -1}, - {"centerview", K_END, -1, -1, -1}, + {"centerview", A_END, -1, -1, -1}, {"zoom", -1, -1, -1, -1}, {"weapon 0", -1, -1, -1, -1}, {"weapon 1", '1', -1, -1, -1}, @@ -4126,20 +4173,20 @@ static bind_t g_bindings[] = {"weapon 11", -1, -1, -1, -1}, {"weapon 12", -1, -1, -1, -1}, {"weapon 13", -1, -1, -1, -1}, - {"+attack", K_CTRL, -1, -1, -1}, + {"+attack", A_CTRL, -1, -1, -1}, {"+altattack", -1, -1, -1, -1}, {"weapprev", '[', -1, -1, -1}, {"weapnext", ']', -1, -1, -1}, {"+block", -1, -1, -1, -1}, - {"+use", K_SPACE, -1, -1, -1}, - {"datapad", K_TAB, -1, -1, -1}, - {"save quik*", K_F9, -1, -1, -1}, + {"+use", A_SPACE, -1, -1, -1}, + {"datapad", A_TAB, -1, -1, -1}, + {"save quik*", A_F9, -1, -1, -1}, {"load quik", -1, -1, -1, -1}, {"load auto", -1, -1, -1, -1}, {"cg_thirdperson !",'p', -1, -1, -1}, {"exitview", -1, -1, -1, -1}, - {"uimenu ingameloadmenu", K_F10, -1, -1, -1}, - {"uimenu ingamesavemenu", K_F11, -1, -1, -1}, + {"uimenu ingameloadmenu", A_F10, -1, -1, -1}, + {"uimenu ingamesavemenu", A_F11, -1, -1, -1}, {"saberAttackCycle",-1, -1, -1, -1}, }; @@ -4160,7 +4207,7 @@ static void Controls_GetKeyAssignment (char *command, int *twokeys) twokeys[0] = twokeys[1] = -1; count = 0; - for ( j = 0; j < 256; j++ ) + for ( j = 0; j < MAX_KEYS; j++ ) { DC->getBindingBuf( j, b, 256 ); if ( *b == 0 ) @@ -5237,13 +5284,13 @@ void BindingFromName(const char *cvar) { break; } - DC->keynumToStringBuf( b1, g_nameBind1, 32 ); + DC->keynumToStringBuf( b1, g_nameBind1, sizeof(g_nameBind1) ); Q_strupr(g_nameBind1); b2 = g_bindings[i].bind2; if (b2 != -1) { - DC->keynumToStringBuf( b2, g_nameBind2, 32 ); + DC->keynumToStringBuf( b2, g_nameBind2, sizeof(g_nameBind2) ); Q_strupr(g_nameBind2); strcat( g_nameBind1, va(" %s ",ui.SP_GetStringTextString("MENUS3_KEYBIND_OR")) ); @@ -5572,6 +5619,7 @@ void Item_Multi_Paint(itemDef_t *item) { text = SP_GetStringText(-(int)text); } + assert (text); if (item->text) @@ -6658,6 +6706,10 @@ qboolean Item_SetFocus(itemDef_t *item, float x, float y) itemDef_t *oldFocus; sfxHandle_t *sfx = &DC->Assets.itemFocusSound; qboolean playSound = qfalse; +#ifdef _IMMERSION + ffHandle_t *ff = &DC->Assets.itemFocusForce; + qboolean playForce = qfalse; +#endif // _IMMERSION menuDef_t *parent = (menuDef_t*)item->parent; // sanity check, non-null, not a decoration and does not already have the focus if (item == NULL || item->window.flags & WINDOW_DECORATION || item->window.flags & WINDOW_HASFOCUS || !(item->window.flags & WINDOW_VISIBLE)) @@ -6691,6 +6743,13 @@ qboolean Item_SetFocus(itemDef_t *item, float x, float y) sfx = &item->focusSound; } playSound = qtrue; +#ifdef _IMMERSION + if (item->focusForce) + { + ff = &item->focusForce; + } + playForce = qtrue; +#endif // _IMMERSION } else { @@ -6716,6 +6775,13 @@ qboolean Item_SetFocus(itemDef_t *item, float x, float y) sfx = &item->focusSound; } playSound = qtrue; +#ifdef _IMMERSION + if (item->focusForce) + { + ff = &item->focusForce; + } + playForce = qtrue; +#endif // _IMMERSION } if (playSound && sfx) @@ -6723,6 +6789,12 @@ qboolean Item_SetFocus(itemDef_t *item, float x, float y) DC->startLocalSound( *sfx, CHAN_LOCAL_SOUND ); } +#ifdef _IMMERSION + if (playForce && ff) + { + DC->startForce( *ff ); + } +#endif // _IMMERSION for (i = 0; i < parent->itemCount; i++) { if (parent->items[i] == item) @@ -7023,7 +7095,7 @@ qboolean Item_Bind_HandleKey(itemDef_t *item, int key, qboolean down) int i; menuDef_t *menu; - if (key == K_MOUSE1 && Rect_ContainsPoint(&item->window.rect, DC->cursorx, DC->cursory) && !g_waitingForKey) + if (key == A_MOUSE1 && Rect_ContainsPoint(&item->window.rect, DC->cursorx, DC->cursory) && !g_waitingForKey) { if (down) { @@ -7044,7 +7116,7 @@ qboolean Item_Bind_HandleKey(itemDef_t *item, int key, qboolean down) } return qtrue; } - else if (key == K_ENTER && !g_waitingForKey) + else if (key == A_ENTER && !g_waitingForKey) { if (down) { @@ -7079,12 +7151,12 @@ qboolean Item_Bind_HandleKey(itemDef_t *item, int key, qboolean down) switch (key) { - case K_ESCAPE: + case A_ESCAPE: g_waitingForKey = qfalse; Item_Bind_Ungrey(item); return qtrue; - case K_BACKSPACE: + case A_BACKSPACE: id = BindingIDFromName(item->cvar); if (id != -1) { @@ -7333,7 +7405,7 @@ qboolean Item_TextField_HandleKey(itemDef_t *item, int key) else { - if ( key == K_DEL || key == K_KP_DEL ) + if ( key == A_DELETE || key == A_KP_PERIOD ) { if ( item->cursorPos < len ) { @@ -7343,7 +7415,7 @@ qboolean Item_TextField_HandleKey(itemDef_t *item, int key) return qtrue; } - if ( key == K_RIGHTARROW || key == K_KP_RIGHTARROW ) + if ( key == A_CURSOR_RIGHT || key == A_KP_6 ) { if (editPtr->maxPaintChars && item->cursorPos >= editPtr->maxPaintChars && item->cursorPos < len) { @@ -7359,7 +7431,7 @@ qboolean Item_TextField_HandleKey(itemDef_t *item, int key) return qtrue; } - if ( key == K_LEFTARROW || key == K_KP_LEFTARROW ) + if ( key == A_CURSOR_LEFT|| key == A_KP_4 ) { if ( item->cursorPos > 0 ) { @@ -7372,14 +7444,14 @@ qboolean Item_TextField_HandleKey(itemDef_t *item, int key) return qtrue; } - if ( key == K_HOME || key == K_KP_HOME) + if ( key == A_HOME || key == A_KP_7) { item->cursorPos = 0; editPtr->paintOffset = 0; return qtrue; } - if ( key == K_END || key == K_KP_END) + if ( key == A_END || key == A_KP_1) { item->cursorPos = len; if(item->cursorPos > editPtr->maxPaintChars) @@ -7389,14 +7461,14 @@ qboolean Item_TextField_HandleKey(itemDef_t *item, int key) return qtrue; } - if ( key == K_INS || key == K_KP_INS ) + if ( key == A_INSERT || key == A_KP_0 ) { DC->setOverstrikeMode(!DC->getOverstrikeMode()); return qtrue; } } - if (key == K_TAB || key == K_DOWNARROW || key == K_KP_DOWNARROW) + if (key == A_TAB || key == A_CURSOR_DOWN || key == A_KP_2) { newItem = Menu_SetNextCursorItem((menuDef_t *) item->parent); if (newItem && (newItem->type == ITEM_TYPE_EDITFIELD || newItem->type == ITEM_TYPE_NUMERICFIELD)) @@ -7405,7 +7477,7 @@ qboolean Item_TextField_HandleKey(itemDef_t *item, int key) } } - if (key == K_UPARROW || key == K_KP_UPARROW) + if (key == A_CURSOR_UP || key == A_KP_8) { newItem = Menu_SetPrevCursorItem((menuDef_t *) item->parent); if (newItem && (newItem->type == ITEM_TYPE_EDITFIELD || newItem->type == ITEM_TYPE_NUMERICFIELD)) @@ -7414,7 +7486,7 @@ qboolean Item_TextField_HandleKey(itemDef_t *item, int key) } } - if ( key == K_ENTER || key == K_KP_ENTER || key == K_ESCAPE) + if ( key == A_ENTER || key == A_KP_ENTER || key == A_ESCAPE) { return qfalse; } @@ -7614,7 +7686,7 @@ qboolean Item_ListBox_HandleKey(itemDef_t *item, int key, qboolean down, qboolea if (item->window.flags & WINDOW_HORIZONTAL) { viewmax = (item->window.rect.w / listPtr->elementWidth); - if ( key == K_LEFTARROW || key == K_KP_LEFTARROW ) + if ( key == A_CURSOR_LEFT || key == A_KP_4 ) { if (!listPtr->notselectable) { @@ -7644,7 +7716,7 @@ qboolean Item_ListBox_HandleKey(itemDef_t *item, int key, qboolean down, qboolea } return qtrue; } - if ( key == K_RIGHTARROW || key == K_KP_RIGHTARROW ) + if ( key == A_CURSOR_RIGHT || key == A_KP_6 ) { if (!listPtr->notselectable) { @@ -7678,7 +7750,7 @@ qboolean Item_ListBox_HandleKey(itemDef_t *item, int key, qboolean down, qboolea else { viewmax = (item->window.rect.h / listPtr->elementHeight); - if ( key == K_UPARROW || key == K_KP_UPARROW ) + if ( key == A_CURSOR_UP || key == A_KP_8 ) { if (!listPtr->notselectable) { @@ -7708,7 +7780,7 @@ qboolean Item_ListBox_HandleKey(itemDef_t *item, int key, qboolean down, qboolea } return qtrue; } - if ( key == K_DOWNARROW || key == K_KP_DOWNARROW ) + if ( key == A_CURSOR_DOWN || key == A_KP_2 ) { if (!listPtr->notselectable) { @@ -7740,7 +7812,7 @@ qboolean Item_ListBox_HandleKey(itemDef_t *item, int key, qboolean down, qboolea } } // mouse hit - if (key == K_MOUSE1 || key == K_MOUSE2) + if (key == A_MOUSE1 || key == A_MOUSE2) { if (item->window.flags & WINDOW_LB_LEFTARROW) { @@ -7797,19 +7869,19 @@ qboolean Item_ListBox_HandleKey(itemDef_t *item, int key, qboolean down, qboolea } return qtrue; } - if ( key == K_HOME || key == K_KP_HOME) + if ( key == A_HOME || key == A_KP_7) { // home listPtr->startPos = 0; return qtrue; } - if ( key == K_END || key == K_KP_END) + if ( key == A_END || key == A_KP_1) { // end listPtr->startPos = max; return qtrue; } - if (key == K_PGUP || key == K_KP_PGUP ) + if (key == A_PAGE_UP || key == A_KP_9 ) { // page up if (!listPtr->notselectable) @@ -7840,7 +7912,7 @@ qboolean Item_ListBox_HandleKey(itemDef_t *item, int key, qboolean down, qboolea } return qtrue; } - if ( key == K_PGDN || key == K_KP_PGDN ) + if ( key == A_PAGE_DOWN || key == A_KP_3 ) { // page down if (!listPtr->notselectable) @@ -8111,7 +8183,7 @@ qboolean Item_YesNo_HandleKey(itemDef_t *item, int key) { if (Rect_ContainsPoint(&item->window.rect, DC->cursorx, DC->cursory) && item->window.flags & WINDOW_HASFOCUS && item->cvar) { - if (key == K_MOUSE1 || key == K_ENTER || key == K_MOUSE2 || key == K_MOUSE3) + if (key == A_MOUSE1 || key == A_ENTER || key == A_MOUSE2 || key == A_MOUSE3) { DC->setCVar(item->cvar, va("%i", !DC->getCVarValue(item->cvar))); return qtrue; @@ -8208,7 +8280,7 @@ qboolean Item_Multi_HandleKey(itemDef_t *item, int key) // if (Rect_ContainsPoint(&item->window.rect, DC->cursorx, DC->cursory) && item->window.flags & WINDOW_HASFOCUS && item->cvar) if (Rect_ContainsPoint(&item->window.rect, DC->cursorx, DC->cursory) && item->window.flags & WINDOW_HASFOCUS) { - if (key == K_MOUSE1 || key == K_ENTER || key == K_MOUSE2 || key == K_MOUSE3) + if (key == A_MOUSE1 || key == A_ENTER || key == A_MOUSE2 || key == A_MOUSE3) { if (item->cvar) { @@ -8265,7 +8337,7 @@ qboolean Item_Slider_HandleKey(itemDef_t *item, int key, qboolean down) //DC->Print("slider handle key\n"); if (item->window.flags & WINDOW_HASFOCUS && item->cvar && Rect_ContainsPoint(&item->window.rect, DC->cursorx, DC->cursory)) { - if (key == K_MOUSE1 || key == K_ENTER || key == K_MOUSE2 || key == K_MOUSE3) + if (key == A_MOUSE1 || key == A_ENTER || key == A_MOUSE2 || key == A_MOUSE3) { editFieldDef_t *editDef = (editFieldDef_s *) item->typeData; if (editDef) @@ -8323,7 +8395,7 @@ qboolean Item_HandleKey(itemDef_t *item, int key, qboolean down) } else { - if (down && key == K_MOUSE1 || key == K_MOUSE2 || key == K_MOUSE3) + if (down && key == A_MOUSE1 || key == A_MOUSE2 || key == A_MOUSE3) { Item_StartCapture(item, key); } @@ -8425,13 +8497,13 @@ void Menu_HandleKey(menuDef_t *menu, int key, qboolean down) inHandler = qfalse; return; } - else if (key == K_MOUSE1 || key == K_MOUSE2 || key == K_MOUSE3) + else if (key == A_MOUSE1 || key == A_MOUSE2 || key == A_MOUSE3) { g_editingField = qfalse; g_editItem = NULL; Display_MouseMove(NULL, DC->cursorx, DC->cursory); } - else if (key == K_TAB || key == K_UPARROW || key == K_DOWNARROW) + else if (key == A_TAB || key == A_CURSOR_UP || key == A_CURSOR_DOWN) { return; } @@ -8447,7 +8519,7 @@ void Menu_HandleKey(menuDef_t *menu, int key, qboolean down) if (down && !(menu->window.flags & WINDOW_POPUP) && !Rect_ContainsPoint(&menu->window.rect, DC->cursorx, DC->cursory)) { static qboolean inHandleKey = qfalse; - if (!inHandleKey && key == K_MOUSE1 || key == K_MOUSE2 || key == K_MOUSE3) + if (!inHandleKey && key == A_MOUSE1 || key == A_MOUSE2 || key == A_MOUSE3) { inHandleKey = qtrue; Menus_HandleOOBClick(menu, key, down); @@ -8494,32 +8566,32 @@ void Menu_HandleKey(menuDef_t *menu, int key, qboolean down) (Q_stricmp(menu->window.name,"datapadForcePowersMenu") == 0) || (Q_stricmp(menu->window.name,"datapadInventoryMenu") == 0)) { - key = K_ESCAPE; //pop on outta here + key = A_ESCAPE; //pop on outta here } } } // default handling switch ( key ) { - case K_F11: + case A_F11: if (DC->getCVarValue("developer")) { uis.debugMode ^= 1; } break; - case K_F12: + case A_F12: if (DC->getCVarValue("developer")) { DC->executeText(EXEC_APPEND, "screenshot\n"); } break; - case K_KP_UPARROW: - case K_UPARROW: + case A_KP_8: + case A_CURSOR_UP: Menu_SetPrevCursorItem(menu); break; - case K_ESCAPE: + case A_ESCAPE: if (!g_waitingForKey && menu->onESC) { itemDef_t it; @@ -8527,14 +8599,14 @@ void Menu_HandleKey(menuDef_t *menu, int key, qboolean down) Item_RunScript(&it, menu->onESC); } break; - case K_TAB: - case K_KP_DOWNARROW: - case K_DOWNARROW: + case A_TAB: + case A_KP_2: + case A_CURSOR_DOWN: Menu_SetNextCursorItem(menu); break; - case K_MOUSE1: - case K_MOUSE2: + case A_MOUSE1: + case A_MOUSE2: if (item) { if (item->type == ITEM_TYPE_TEXT) @@ -8564,29 +8636,31 @@ void Menu_HandleKey(menuDef_t *menu, int key, qboolean down) } 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 A_JOY0: + case A_JOY1: + case A_JOY2: + case A_JOY3: + case A_JOY4: + case A_AUX0: + case A_AUX1: + case A_AUX2: + case A_AUX3: + case A_AUX4: + case A_AUX5: + case A_AUX6: + case A_AUX7: + case A_AUX8: + case A_AUX9: + case A_AUX10: + case A_AUX11: + case A_AUX12: + case A_AUX13: + case A_AUX14: + case A_AUX15: + case A_AUX16: break; - case K_KP_ENTER: - case K_ENTER: + case A_KP_ENTER: + case A_ENTER: if (item) { if (item->type == ITEM_TYPE_EDITFIELD || item->type == ITEM_TYPE_NUMERICFIELD) diff --git a/code/ui/ui_shared.h b/code/ui/ui_shared.h index 285d698..6695337 100644 --- a/code/ui/ui_shared.h +++ b/code/ui/ui_shared.h @@ -123,6 +123,12 @@ typedef struct { sfxHandle_t menuExitSound; sfxHandle_t menuBuzzSound; sfxHandle_t itemFocusSound; +#ifdef _IMMERSION + ffHandle_t menuEnterForce; + ffHandle_t menuExitForce; + ffHandle_t menuBuzzForce; + ffHandle_t itemFocusForce; +#endif // _IMMERSION float fadeClamp; int fadeCycle; float fadeAmount; @@ -183,6 +189,10 @@ typedef struct { int (*textWidth) (const char *text, float scale, int iFontIndex); qhandle_t (*feederItemImage) (float feederID, int index); const char *(*feederItemText) (float feederID, int index, int column, qhandle_t *handle); +#ifdef _IMMERSION + ffHandle_t (*registerForce)(const char *name, int channel=FF_CHANNEL_MENU); + void (*startForce)(ffHandle_t ff); +#endif // _IMMERSION float yscale; float xscale; @@ -326,6 +336,9 @@ typedef struct itemDef_s { const char *enableCvar; // enable, disable, show, or hide based on value, this can contain a list int cvarFlags; // what type of action to take on cvarenables sfxHandle_t focusSound; // +#ifdef _IMMERSION + ffHandle_t focusForce; +#endif // _IMMERSION int numColors; // number of color ranges colorRangeDef_t colorRanges[MAX_COLOR_RANGES]; float special; // used for feeder id's etc.. diff per type diff --git a/code/ui/ui_syscalls.cpp b/code/ui/ui_syscalls.cpp index dbf57b7..7c69bbf 100644 --- a/code/ui/ui_syscalls.cpp +++ b/code/ui/ui_syscalls.cpp @@ -6,6 +6,9 @@ #include "ui_local.h" +#ifdef _IMMERSION +#include "../ff/ff.h" +#endif // _IMMERSION // this file is only included when building a dll // syscalls.asm is included instead when building a qvm @@ -82,6 +85,19 @@ sfxHandle_t trap_S_RegisterSound( const char *sample, qboolean compressed ) return S_RegisterSound(sample); } +#ifdef _IMMERSION + +void trap_FF_Start( ffHandle_t ff ) +{ + FF_AddForce( ff ); +} + +ffHandle_t trap_FF_Register( const char *name, int channel ) +{ + return FF_Register( name, channel, qtrue ); +} + +#endif // _IMMERSION void trap_Key_SetBinding( int keynum, const char *binding ) { diff --git a/code/ui/vssver.scc b/code/ui/vssver.scc index 8906894..5bfdffd 100644 Binary files a/code/ui/vssver.scc and b/code/ui/vssver.scc differ diff --git a/code/vssver.scc b/code/vssver.scc index 892875b..0c7571a 100644 Binary files a/code/vssver.scc and b/code/vssver.scc differ diff --git a/code/win32/vssver.scc b/code/win32/vssver.scc index 00f817d..e1a7cf6 100644 Binary files a/code/win32/vssver.scc and b/code/win32/vssver.scc differ diff --git a/code/win32/win_glimp.cpp b/code/win32/win_glimp.cpp index 8f75e06..ede29ba 100644 --- a/code/win32/win_glimp.cpp +++ b/code/win32/win_glimp.cpp @@ -730,45 +730,27 @@ static rserr_t GLW_SetMode( int mode, { if ( colorbits == 0 || ( !cdsFullscreen && colorbits >= 15 ) ) { - const char *psErrorTitle_English = "Low Desktop Color Depth"; - const char *psErrorBody_English = "It is highly unlikely that a correct windowed\n" + // since I can't be bothered trying to mess around with asian codepages and MBCS stuff for a windows + // error box that'll only appear if something's seriously fucked then I'm going to fallback to + // english text when these would otherwise be used... + // + char sErrorHead[1024]; // ott + + extern qboolean Language_IsAsian(void); + Q_strncpyz(sErrorHead, Language_IsAsian() ? "Low Desktop Color Depth" : SP_GetStringTextString("CON_TEXT_LOW_DESKTOP_COLOUR_DEPTH"), sizeof(sErrorHead) ); + + const char *psErrorBody = Language_IsAsian() ? + "It is highly unlikely that a correct windowed\n" "display can be initialized with the current\n" "desktop display depth. Select 'OK' to try\n" "anyway. Select 'Cancel' to try a fullscreen\n" - "mode instead."; - - const char *psErrorTitle_German = "Falsche Desktop-Farbtiefe"; - const char *psErrorBody_German = "Es ist unwahrscheinlich, dass bei der momentanen\n" - "Desktop-Farbiefe ein Fenstermodus initialisiert\n" - "werden kann. Mit 'OK' versuchen Sie es dennoch,\n" - "mit 'Abbrechen' wechselt das Spiel in den\n" - "Vollbildmodus."; - - const char *psErrorTitle_French = "Basse Intensité De la Couleur DeskTop"; - const char *psErrorBody_French = "Il est fortement peu probable qu'un correct windowed\n" - "l'affichage peut être initialisé avec la profondeur\n" - "de bureau actuelle d'affichage. Choisissez 'OK'\n" - "pour essayer de toute façon. Choisissez 'ANNUL'\n" - "pour essayer a fullscreen le mode à la place."; - - const char *psHeadText = psErrorTitle_English; - const char *psBodyText = psErrorBody_English; - - if (sp_language->integer == SP_LANGUAGE_GERMAN) - { - psHeadText = psErrorTitle_German; - psBodyText = psErrorBody_German; - } - else - if (sp_language->integer == SP_LANGUAGE_FRENCH) - { - psHeadText = psErrorTitle_French; - psBodyText = psErrorBody_French; - } + "mode instead." + : + SP_GetStringTextString("CON_TEXT_TRY_ANYWAY"); if ( MessageBox( NULL, - psBodyText, - psHeadText, + psErrorBody, + sErrorHead, MB_OKCANCEL | MB_ICONEXCLAMATION ) != IDOK ) { return RSERR_INVALID_MODE; @@ -1464,18 +1446,22 @@ extern qboolean Sys_LowPhysicalMemory(); ri.Cvar_Set( "r_textureMode", "GL_LINEAR_MIPMAP_NEAREST" ); } + if ( strstr( buf, "kyro" ) ) + { + ri.Cvar_Set( "r_ext_texture_filter_anisotropic", "0"); //KYROs have it avail, but suck at it! + ri.Cvar_Set( "r_ext_preferred_tc_method", "1"); //(Use DXT1 instead of DXT5 - same quality but much better performance on KYRO) + } + GLW_InitExtensions(); //this must be a really sucky card! if ( (glConfig.textureCompression == TC_NONE) || (glConfig.maxActiveTextures < 2) || (glConfig.maxTextureSize <= 512) ) { - ri.Cvar_Set( "r_picmip", "3"); - ri.Cvar_Set( "r_lodbias", "2"); - ri.Cvar_Set( "r_detailtextures", "0"); + ri.Cvar_Set( "r_picmip", "2"); ri.Cvar_Set( "r_colorbits", "16"); ri.Cvar_Set( "r_texturebits", "16"); - ri.Cvar_Set( "cg_shadows", "0"); ri.Cvar_Set( "r_mode", "3"); //force 640 + Cmd_ExecuteString ("exec low.cfg\n"); //get the rest which can be pulled in after init } } diff --git a/code/win32/win_input.cpp b/code/win32/win_input.cpp index 99a4b51..293cfaf 100644 --- a/code/win32/win_input.cpp +++ b/code/win32/win_input.cpp @@ -9,7 +9,9 @@ #include "../client/client.h" +#ifndef _IMMERSION #include "../client/fffx.h" +#endif // _IMMERSION #include "win_local.h" typedef struct { @@ -59,8 +61,6 @@ typedef struct { static joystickInfo_t joy; -cvar_t *k_language; - cvar_t *in_midi; cvar_t *in_midiport; cvar_t *in_midichannel; @@ -425,23 +425,23 @@ void IN_DIMouse( int *mx, int *my ) { switch (od.dwOfs) { case DIMOFS_BUTTON0: if (od.dwData & 0x80) - Sys_QueEvent( od.dwTimeStamp, SE_KEY, K_MOUSE1, qtrue, 0, NULL ); + Sys_QueEvent( od.dwTimeStamp, SE_KEY, A_MOUSE1, qtrue, 0, NULL ); else - Sys_QueEvent( od.dwTimeStamp, SE_KEY, K_MOUSE1, qfalse, 0, NULL ); + Sys_QueEvent( od.dwTimeStamp, SE_KEY, A_MOUSE1, qfalse, 0, NULL ); break; case DIMOFS_BUTTON1: if (od.dwData & 0x80) - Sys_QueEvent( od.dwTimeStamp, SE_KEY, K_MOUSE2, qtrue, 0, NULL ); + Sys_QueEvent( od.dwTimeStamp, SE_KEY, A_MOUSE2, qtrue, 0, NULL ); else - Sys_QueEvent( od.dwTimeStamp, SE_KEY, K_MOUSE2, qfalse, 0, NULL ); + Sys_QueEvent( od.dwTimeStamp, SE_KEY, A_MOUSE2, qfalse, 0, NULL ); break; case DIMOFS_BUTTON2: if (od.dwData & 0x80) - Sys_QueEvent( od.dwTimeStamp, SE_KEY, K_MOUSE3, qtrue, 0, NULL ); + Sys_QueEvent( od.dwTimeStamp, SE_KEY, A_MOUSE3, qtrue, 0, NULL ); else - Sys_QueEvent( od.dwTimeStamp, SE_KEY, K_MOUSE3, qfalse, 0, NULL ); + Sys_QueEvent( od.dwTimeStamp, SE_KEY, A_MOUSE3, qfalse, 0, NULL ); break; } } @@ -559,33 +559,43 @@ void IN_StartupMouse( void ) IN_MouseEvent =========== */ +#define MAX_MOUSE_BUTTONS 5 + +static int mouseConvert[MAX_MOUSE_BUTTONS] = +{ + A_MOUSE1, + A_MOUSE2, + A_MOUSE3, + A_MOUSE4, + A_MOUSE5 +}; + void IN_MouseEvent (int mstate) { int i; if ( !s_wmv.mouseInitialized ) - return; - -// perform button actions - for (i = 0 ; i < 5 ; i++ ) { - if ( (mstate & (1< 255 || qkey < K_AUX1 ) + if ( qkey < A_AUX0 ) + { return; - + } Sys_QueEvent( g_wv.sysMsgTime, SE_KEY, qkey, qfalse, 0, NULL ); } @@ -1017,13 +1029,16 @@ static void MIDI_NoteOn( int note, int velocity ) int qkey; if ( velocity == 0 ) + { MIDI_NoteOff( note ); + } - qkey = note - 60 + K_AUX1; + qkey = note - 60 + A_AUX0; - if ( qkey > 255 || qkey < K_AUX1 ) + if ( qkey < A_AUX0 ) + { return; - + } Sys_QueEvent( g_wv.sysMsgTime, SE_KEY, qkey, qtrue, 0, NULL ); } @@ -1077,7 +1092,7 @@ static void MidiInfo_f( void ) Com_Printf( "number of devices: %d\n", s_midiInfo.numDevices ); for ( i = 0; i < s_midiInfo.numDevices; i++ ) { - if ( i == Cvar_VariableValue( "in_mididevice" ) ) + if ( i == Cvar_VariableIntegerValue( "in_mididevice" ) ) Com_Printf( "***" ); else Com_Printf( "..." ); @@ -1093,7 +1108,7 @@ static void IN_StartupMIDI( void ) { int i; - if ( !Cvar_VariableValue( "in_midi" ) ) + if ( !Cvar_VariableIntegerValue( "in_midi" ) ) return; // diff --git a/code/win32/win_main.cpp b/code/win32/win_main.cpp index 622f371..394440b 100644 --- a/code/win32/win_main.cpp +++ b/code/win32/win_main.cpp @@ -1022,27 +1022,22 @@ static void QuickMemTest(void) { // err... // - LPCSTR psContinue = "Your machine failed to allocate %dMB in a memory test, which may mean you'll have problems running this game all the way through.\n\nContinue anyway?"; - LPCSTR psNoMem = "Insufficient memory to run this game!\n"; - - switch (Language_GetIntegerValue()) - { - case SP_LANGUAGE_GERMAN: - - psContinue = "Ihr Computer konnte bei einem Speichertest keine %dMB reservieren, daher werden Sie mit dem Starten des Spiels Probleme haben.\n\nDennoch fortsetzen?"; - psNoMem = "Unzureichender Speicher zum Starten!\n"; - break; - - case SP_LANGUAGE_FRENCH: - - psContinue = "Votre système n'a pu allouer %d Mo lors d'une vérification de la mémoire, ce qui signifie que vous aurez peut-être du mal à faire fonctionner ce jeu. \n\nSouhaitez-vous continuer malgré tout ?"; - psNoMem = "Mémoire insuffisante pour lancer ce jeu !\n"; - break; - } + extern qboolean Language_IsAsian(void); + LPCSTR psContinue = Language_IsAsian() ? + "Your machine failed to allocate %dMB in a memory test, which may mean you'll have problems running this game all the way through.\n\nContinue anyway?" + : + SP_GetStringTextString("CON_TEXT_FAILED_MEMTEST"); + // ( since it's too much hassle doing MBCS code pages and decodings etc for MessageBox command ) #define GetYesNo(psQuery) (!!(MessageBox(NULL,psQuery,"Query",MB_YESNO|MB_ICONWARNING|MB_TASKMODAL)==IDYES)) if (!GetYesNo(va(psContinue,iMemTestMegs))) { + LPCSTR psNoMem = Language_IsAsian() ? + "Insufficient memory to run this game!\n" + : + SP_GetStringTextString("CON_TEXT_INSUFFICIENT_MEMORY"); + // ( since it's too much hassle doing MBCS code pages and decodings etc for MessageBox command ) + Com_Error( ERR_FATAL, psNoMem ); } } diff --git a/code/win32/win_wndproc.cpp b/code/win32/win_wndproc.cpp index 78a205d..a47d824 100644 --- a/code/win32/win_wndproc.cpp +++ b/code/win32/win_wndproc.cpp @@ -8,14 +8,16 @@ #include "../client/client.h" #include "win_local.h" +// The only directly referenced keycode - the console key (which gives different ascii codes depending on locale) +#define CONSOLE_SCAN_CODE 0x29 + + WinVars_t g_wv; #ifndef WM_MOUSEWHEEL #define WM_MOUSEWHEEL (WM_MOUSELAST+1) // message that will be supported by the OS #endif -extern cvar_t *k_language; - static UINT MSH_MOUSEWHEEL; // Console variables that we need to access from this module @@ -98,143 +100,155 @@ static void VID_AppActivate(BOOL fActive, BOOL minimize) } } -//========================================================================== - -static byte s_scantokey[128] = - { -// 0 1 2 3 4 5 6 7 -// 8 9 A B C D E F - 0 , 27, '1', '2', '3', '4', '5', '6', - '7', '8', '9', '0', '-', '=', K_BACKSPACE, 9, // 0 - 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', - 'o', 'p', '[', ']', 13 , K_CTRL,'a', 's', // 1 - 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', - '\'' , '`', K_SHIFT,'\\', 'z', 'x', 'c', 'v', // 2 - 'b', 'n', 'm', ',', '.', '/', K_SHIFT,'*', - K_ALT,' ', K_CAPSLOCK , K_F1, K_F2, K_F3, K_F4, K_F5, // 3 - K_F6, K_F7, K_F8, K_F9, K_F10, K_PAUSE, 0 , K_HOME, - K_UPARROW,K_PGUP,K_KP_MINUS,K_LEFTARROW,K_KP_5,K_RIGHTARROW, K_KP_PLUS,K_END, //4 - K_DOWNARROW,K_PGDN,K_INS,K_DEL,0,0, 0, K_F11, - K_F12,0 , 0 , 0 , 0 , 0 , 0 , 0, // 5 - 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0, - 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0, // 6 - 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0, - 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 // 7 -}; - -static byte s_scantokey_german[128] = - { -// 0 1 2 3 4 5 6 7 -// 8 9 A B C D E F - 0 , 27, '1', '2', '3', '4', '5', '6', - '7', '8', '9', '0', '?', '\'', K_BACKSPACE, 9, // 0 - 'q', 'w', 'e', 'r', 't', 'z', 'u', 'i', - 'o', 'p', '=', '+', 13 , K_CTRL, 'a', 's', // 1 - 'd', 'f', 'g', 'h', 'j', 'k', 'l', '[', - ']' , '`', K_SHIFT,'#', 'y', 'x', 'c', 'v', // 2 - 'b', 'n', 'm', ',', '.', '-', K_SHIFT,'*', - K_ALT,' ', K_CAPSLOCK , K_F1, K_F2, K_F3, K_F4, K_F5, // 3 - K_F6, K_F7, K_F8, K_F9, K_F10, K_PAUSE, 0 , K_HOME, - K_UPARROW,K_PGUP,K_KP_MINUS,K_LEFTARROW,K_KP_5,K_RIGHTARROW, K_KP_PLUS,K_END, //4 - K_DOWNARROW,K_PGDN,K_INS,K_DEL,0,0, '<', K_F11, - K_F12,0 , 0 , 0 , 0 , 0 , 0 , 0, // 5 - 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0, - 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0, // 6 - 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0, - 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 // 7 -}; - -static byte s_scantokey_french[128] = - { -// 0 1 2 3 4 5 6 7 -// 8 9 A B C D E F - 0 , 27, '1', '2', '3', '4', '5', '6', - '7', '8', '9', '0', ')', '=', K_BACKSPACE, 9, // 0 - 'a', 'z', 'e', 'r', 't', 'y', 'u', 'i', - 'o', 'p', '^', '$', 13 , K_CTRL, 'q', 's', // 1 - 'd', 'f', 'g', 'h', 'j', 'k', 'l', 'm', - '%' , '`', K_SHIFT,'*', 'w', 'x', 'c', 'v', // 2 - 'b', 'n', ',', ';', ':', '!', K_SHIFT,'*', - K_ALT,' ', K_CAPSLOCK , K_F1, K_F2, K_F3, K_F4, K_F5, // 3 - K_F6, K_F7, K_F8, K_F9, K_F10, K_PAUSE, 0 , K_HOME, - K_UPARROW,K_PGUP,K_KP_MINUS,K_LEFTARROW,K_KP_5,K_RIGHTARROW, K_KP_PLUS,K_END, //4 - K_DOWNARROW,K_PGDN,K_INS,K_DEL,0,0, '<', K_F11, - K_F12,0 , 0 , 0 , 0 , 0 , 0 , 0, // 5 - 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0, - 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0, // 6 - 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0, - 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 // 7 -}; - -static byte s_scantokey_spanish[128] = -{ -// 0 1 2 3 4 5 6 7 -// 8 9 A B C D E F - 0 , 27, '1', '2', '3', '4', '5', '6', - '7', '8', '9', '0', '\'', '!', K_BACKSPACE, 9, // 0 - 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', - 'o', 'p', '[', ']', 13 , K_CTRL, 'a', 's', // 1 - 'd', 'f', 'g', 'h', 'j', 'k', 'l', '=', - '{' , '`', K_SHIFT,'}', 'z', 'x', 'c', 'v', // 2 - 'b', 'n', 'm', ',', '.', '-', K_SHIFT,'*', - K_ALT,' ', K_CAPSLOCK , K_F1, K_F2, K_F3, K_F4, K_F5, // 3 - K_F6, K_F7, K_F8, K_F9, K_F10, K_PAUSE, 0 , K_HOME, - K_UPARROW,K_PGUP,K_KP_MINUS,K_LEFTARROW,K_KP_5,K_RIGHTARROW, K_KP_PLUS,K_END, //4 - K_DOWNARROW,K_PGDN,K_INS,K_DEL,0,0, '<', K_F11, - K_F12,0 , 0 , 0 , 0 , 0 , 0 , 0, // 5 - 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0, - 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0, // 6 - 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0, - 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 // 7 -}; - -static byte s_scantokey_italian[128] = -{ -// 0 1 2 3 4 5 6 7 -// 8 9 A B C D E F - 0 , 27, '1', '2', '3', '4', '5', '6', - '7', '8', '9', '0', '\'', '^', K_BACKSPACE, 9, // 0 - 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', - 'o', 'p', '[', ']', 13 , K_CTRL, 'a', 's', // 1 - 'd', 'f', 'g', 'h', 'j', 'k', 'l', '@', - '#' , '`', K_SHIFT,'=', 'z', 'x', 'c', 'v', // 2 - 'b', 'n', 'm', ',', '.', '-', K_SHIFT,'*', - K_ALT,' ', K_CAPSLOCK , K_F1, K_F2, K_F3, K_F4, K_F5, // 3 - K_F6, K_F7, K_F8, K_F9, K_F10, K_PAUSE, 0 , K_HOME, - K_UPARROW,K_PGUP,K_KP_MINUS,K_LEFTARROW,K_KP_5,K_RIGHTARROW, K_KP_PLUS,K_END, //4 - K_DOWNARROW,K_PGDN,K_INS,K_DEL,0,0, '<', K_F11, - K_F12,0 , 0 , 0 , 0 , 0 , 0 , 0, // 5 - 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0, - 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0, // 6 - 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0, - 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 // 7 -}; - -/* -// returns true if key should be ignored because NUMLOCK is on and therefore KP arrows should be numbers only... -// -qboolean SwallowBadNumLockedKPKey( int iKey ) +static byte virtualKeyConvert[0x92][2] = { - switch (iKey) - { - case K_KP_HOME: - case K_KP_UPARROW: - case K_KP_PGUP: - case K_KP_LEFTARROW: - case K_KP_RIGHTARROW: - case K_KP_END: - case K_KP_DOWNARROW: - case K_KP_PGDN: - - if (GetKeyState(VK_NUMLOCK) & 0x8001) - { - return qtrue; - } - } - - return qfalse; -} -*/ + { 0, 0 }, + { A_MOUSE1, A_MOUSE1 }, // VK_LBUTTON 01 Left mouse button + { A_MOUSE2, A_MOUSE2 }, // VK_RBUTTON 02 Right mouse button + { 0, 0 }, // VK_CANCEL 03 Control-break processing + { A_MOUSE3, A_MOUSE3 }, // VK_MBUTTON 04 Middle mouse button (three-button mouse) + { A_MOUSE4, A_MOUSE4 }, // VK_XBUTTON1 05 Windows 2000/XP: X1 mouse button + { A_MOUSE5, A_MOUSE5 }, // VK_XBUTTON2 06 Windows 2000/XP: X2 mouse button + { 0, 0 }, // 07 Undefined + { A_BACKSPACE, A_BACKSPACE }, // VK_BACK 08 BACKSPACE key + { A_TAB, A_TAB }, // VK_TAB 09 TAB key + { 0, 0 }, // 0A Reserved + { 0, 0 }, // 0B Reserved + { A_KP_5, 0 }, // VK_CLEAR 0C CLEAR key + { A_ENTER, A_KP_ENTER }, // VK_RETURN 0D ENTER key + { 0, 0 }, // 0E Undefined + { 0, 0 }, // 0F Undefined + { A_SHIFT, A_SHIFT }, // VK_SHIFT 10 SHIFT key + { A_CTRL, A_CTRL }, // VK_CONTROL 11 CTRL key + { A_ALT, A_ALT }, // VK_MENU 12 ALT key + { A_PAUSE, A_PAUSE }, // VK_PAUSE 13 PAUSE key + { A_CAPSLOCK, A_CAPSLOCK }, // VK_CAPITAL 14 CAPS LOCK key + { 0, 0 }, // VK_KANA 15 IME Kana mode + { 0, 0 }, // 16 Undefined + { 0, 0 }, // VK_JUNJA 17 IME Junja mode + { 0, 0 }, // VK_FINAL 18 IME final mode + { 0, 0 }, // VK_KANJI 19 IME Kanji mode + { 0, 0 }, // 1A Undefined + { A_ESCAPE, A_ESCAPE }, // VK_ESCAPE 1B ESC key + { 0, 0 }, // VK_CONVERT 1C IME convert + { 0, 0 }, // VK_NONCONVERT 1D IME nonconvert + { 0, 0 }, // VK_ACCEPT 1E IME accept + { 0, 0 }, // VK_MODECHANGE 1F IME mode change request + { A_SPACE, A_SPACE }, // VK_SPACE 20 SPACEBAR + { A_KP_9, A_PAGE_UP }, // VK_PRIOR 21 PAGE UP key + { A_KP_3, A_PAGE_DOWN }, // VK_NEXT 22 PAGE DOWN key + { A_KP_1, A_END }, // VK_END 23 END key + { A_KP_7, A_HOME }, // VK_HOME 24 HOME key + { A_KP_4, A_CURSOR_LEFT }, // VK_LEFT 25 LEFT ARROW key + { A_KP_8, A_CURSOR_UP }, // VK_UP 26 UP ARROW key + { A_KP_6, A_CURSOR_RIGHT }, // VK_RIGHT 27 RIGHT ARROW key + { A_KP_2, A_CURSOR_DOWN }, // VK_DOWN 28 DOWN ARROW key + { 0, 0 }, // VK_SELECT 29 SELECT key + { 0, 0 }, // VK_PRINT 2A PRINT key + { 0, 0 }, // VK_EXECUTE 2B EXECUTE key + { A_PRINTSCREEN, A_PRINTSCREEN }, // VK_SNAPSHOT 2C PRINT SCREEN key + { A_KP_0, A_INSERT }, // VK_INSERT 2D INS key + { A_KP_PERIOD, A_DELETE }, // VK_DELETE 2E DEL key + { 0, 0 }, // VK_HELP 2F HELP key + { A_0, A_0 }, // 30 0 key + { A_1, A_1 }, // 31 1 key + { A_2, A_2 }, // 32 2 key + { A_3, A_3 }, // 33 3 key + { A_4, A_4 }, // 34 4 key + { A_5, A_5 }, // 35 5 key + { A_6, A_6 }, // 36 6 key + { A_7, A_7 }, // 37 7 key + { A_8, A_8 }, // 38 8 key + { A_9, A_9 }, // 39 9 key + { 0, 0 }, // 3A Undefined + { 0, 0 }, // 3B Undefined + { 0, 0 }, // 3C Undefined + { 0, 0 }, // 3D Undefined + { 0, 0 }, // 3E Undefined + { 0, 0 }, // 3F Undefined + { 0, 0 }, // 40 Undefined + { A_CAP_A, A_CAP_A }, // 41 A key + { A_CAP_B, A_CAP_B }, // 42 B key + { A_CAP_C, A_CAP_C }, // 43 C key + { A_CAP_D, A_CAP_D }, // 44 D key + { A_CAP_E, A_CAP_E }, // 45 E key + { A_CAP_F, A_CAP_F }, // 46 F key + { A_CAP_G, A_CAP_G }, // 47 G key + { A_CAP_H, A_CAP_H }, // 48 H key + { A_CAP_I, A_CAP_I }, // 49 I key + { A_CAP_J, A_CAP_J }, // 4A J key + { A_CAP_K, A_CAP_K }, // 4B K key + { A_CAP_L, A_CAP_L }, // 4C L key + { A_CAP_M, A_CAP_M }, // 4D M key + { A_CAP_N, A_CAP_N }, // 4E N key + { A_CAP_O, A_CAP_O }, // 4F O key + { A_CAP_P, A_CAP_P }, // 50 P key + { A_CAP_Q, A_CAP_Q }, // 51 Q key + { A_CAP_R, A_CAP_R }, // 52 R key + { A_CAP_S, A_CAP_S }, // 53 S key + { A_CAP_T, A_CAP_T }, // 54 T key + { A_CAP_U, A_CAP_U }, // 55 U key + { A_CAP_V, A_CAP_V }, // 56 V key + { A_CAP_W, A_CAP_W }, // 57 W key + { A_CAP_X, A_CAP_X }, // 58 X key + { A_CAP_Y, A_CAP_Y }, // 59 Y key + { A_CAP_Z, A_CAP_Z }, // 5A Z key + { 0, 0 }, // VK_LWIN 5B Left Windows key (Microsoft® Natural® keyboard) + { 0, 0 }, // VK_RWIN 5C Right Windows key (Natural keyboard) + { 0, 0 }, // VK_APPS 5D Applications key (Natural keyboard) + { 0, 0 }, // 5E Reserved + { 0, 0 }, // VK_SLEEP 5F Computer Sleep key + { A_KP_0, A_KP_0 }, // VK_NUMPAD0 60 Numeric keypad 0 key + { A_KP_1, A_KP_1 }, // VK_NUMPAD1 61 Numeric keypad 1 key + { A_KP_2, A_KP_2 }, // VK_NUMPAD2 62 Numeric keypad 2 key + { A_KP_3, A_KP_3 }, // VK_NUMPAD3 63 Numeric keypad 3 key + { A_KP_4, A_KP_4 }, // VK_NUMPAD4 64 Numeric keypad 4 key + { A_KP_5, A_KP_5 }, // VK_NUMPAD5 65 Numeric keypad 5 key + { A_KP_6, A_KP_6 }, // VK_NUMPAD6 66 Numeric keypad 6 key + { A_KP_7, A_KP_7 }, // VK_NUMPAD7 67 Numeric keypad 7 key + { A_KP_8, A_KP_8 }, // VK_NUMPAD8 68 Numeric keypad 8 key + { A_KP_9, A_KP_9 }, // VK_NUMPAD9 69 Numeric keypad 9 key + { A_MULTIPLY, A_MULTIPLY }, // VK_MULTIPLY 6A Multiply key + { A_KP_PLUS, A_KP_PLUS }, // VK_ADD 6B Add key + { 0, 0 }, // VK_SEPARATOR 6C Separator key + { A_KP_MINUS, A_KP_MINUS }, // VK_SUBTRACT 6D Subtract key + { A_KP_PERIOD, A_KP_PERIOD }, // VK_DECIMAL 6E Decimal key + { A_DIVIDE, A_DIVIDE }, // VK_DIVIDE 6F Divide key + { A_F1, A_F1 }, // VK_F1 70 F1 key + { A_F2, A_F2 }, // VK_F2 71 F2 key + { A_F3, A_F3 }, // VK_F3 72 F3 key + { A_F4, A_F4 }, // VK_F4 73 F4 key + { A_F5, A_F5 }, // VK_F5 74 F5 key + { A_F6, A_F6 }, // VK_F6 75 F6 key + { A_F7, A_F7 }, // VK_F7 76 F7 key + { A_F8, A_F8 }, // VK_F8 77 F8 key + { A_F9, A_F9 }, // VK_F9 78 F9 key + { A_F10, A_F10 }, // VK_F10 79 F10 key + { A_F11, A_F11 }, // VK_F11 7A F11 key + { A_F12, A_F12 }, // VK_F12 7B F12 key + { 0, 0 }, // VK_F13 7C F13 key + { 0, 0 }, // VK_F14 7D F14 key + { 0, 0 }, // VK_F15 7E F15 key + { 0, 0 }, // VK_F16 7F F16 key + { 0, 0 }, // VK_F17 80H F17 key + { 0, 0 }, // VK_F18 81H F18 key + { 0, 0 }, // VK_F19 82H F19 key + { 0, 0 }, // VK_F20 83H F20 key + { 0, 0 }, // VK_F21 84H F21 key + { 0, 0 }, // VK_F22 85H F22 key + { 0, 0 }, // VK_F23 86H F23 key + { 0, 0 }, // VK_F24 87H F24 key + { 0, 0 }, // 88 Unassigned + { 0, 0 }, // 89 Unassigned + { 0, 0 }, // 8A Unassigned + { 0, 0 }, // 8B Unassigned + { 0, 0 }, // 8C Unassigned + { 0, 0 }, // 8D Unassigned + { 0, 0 }, // 8E Unassigned + { 0, 0 }, // 8F Unassigned + { A_NUMLOCK, A_NUMLOCK }, // VK_NUMLOCK 90 NUM LOCK key + { A_SCROLLLOCK, A_SCROLLLOCK } // VK_SCROLL 91 +}; /* ======= @@ -243,82 +257,35 @@ MapKey Map from windows to quake keynums ======= */ -static int MapKey (int key) +static int MapKey (ulong key, word wParam) { - int result; - int modified; - qboolean is_extended; + ulong result, scan, extended; -// Com_Printf( "0x%x\n", key); - - modified = ( key >> 16 ) & 255; - - if ( modified > 127 ) - return 0; - - if ( key & ( 1 << 24 ) ) + // Check for the console key (hard code to the key you would expect) + scan = ( key >> 16 ) & 0xff; + if(scan == CONSOLE_SCAN_CODE) { - is_extended = qtrue; - } - else - { - is_extended = qfalse; + return(A_CONSOLE); } - result = s_scantokey[modified]; - if ( !Q_stricmp(k_language->string, "deutsch") ) { - result = s_scantokey_german[modified]; - } else if ( !Q_stricmp(k_language->string, "francais") ) { - result = s_scantokey_french[modified]; - } else if ( !Q_stricmp(k_language->string, "espanol") ) { - result = s_scantokey_spanish[modified]; - } else if ( !Q_stricmp(k_language->string, "italiano") ) { - result = s_scantokey_italian[modified]; - } - - if ( !is_extended ) + // Try to convert the virtual key directly + result = 0; + extended = (key >> 24) & 1; + if(wParam > 0 && wParam <= VK_SCROLL) { - switch ( result ) - { - case K_HOME: - return K_KP_HOME; - case K_UPARROW: - return K_KP_UPARROW; - case K_PGUP: - return K_KP_PGUP; - case K_LEFTARROW: - return K_KP_LEFTARROW; - case K_RIGHTARROW: - return K_KP_RIGHTARROW; - case K_END: - return K_KP_END; - case K_DOWNARROW: - return K_KP_DOWNARROW; - case K_PGDN: - return K_KP_PGDN; - case K_INS: - return K_KP_INS; - case K_DEL: - return K_KP_DEL; - default: - return result; - } + result = virtualKeyConvert[wParam][extended]; } - else + // Get the unshifted ascii code (if any) + if(!result) { - switch ( result ) - { - case K_PAUSE: - return K_KP_NUMLOCK; - case 0x0D: - return K_KP_ENTER; - case 0x2F: - return K_KP_SLASH; - case 0xAF: - return K_KP_PLUS; - } - return result; + result = MapVirtualKey(wParam, 2) & 0xff; } + // Output any debug prints +// if(in_debug && in_debug->integer & 1) +// { +// Com_Printf("WM_KEY: %x : %x : %x\n", key, wParam, result); +// } + return(result); } @@ -341,18 +308,19 @@ LONG WINAPI MainWndProc ( WPARAM wParam, LPARAM lParam) { + byte code; if ( uMsg == MSH_MOUSEWHEEL ) { if ( ( ( int ) wParam ) > 0 ) { - Sys_QueEvent( g_wv.sysMsgTime, SE_KEY, K_MWHEELUP, qtrue, 0, NULL ); - Sys_QueEvent( g_wv.sysMsgTime, SE_KEY, K_MWHEELUP, qfalse, 0, NULL ); + Sys_QueEvent( g_wv.sysMsgTime, SE_KEY, A_MWHEELUP, qtrue, 0, NULL ); + Sys_QueEvent( g_wv.sysMsgTime, SE_KEY, A_MWHEELUP, qfalse, 0, NULL ); } else { - Sys_QueEvent( g_wv.sysMsgTime, SE_KEY, K_MWHEELDOWN, qtrue, 0, NULL ); - Sys_QueEvent( g_wv.sysMsgTime, SE_KEY, K_MWHEELDOWN, qfalse, 0, NULL ); + Sys_QueEvent( g_wv.sysMsgTime, SE_KEY, A_MWHEELDOWN, qtrue, 0, NULL ); + Sys_QueEvent( g_wv.sysMsgTime, SE_KEY, A_MWHEELDOWN, qfalse, 0, NULL ); } return DefWindowProc (hWnd, uMsg, wParam, lParam); } @@ -367,13 +335,13 @@ LONG WINAPI MainWndProc ( // if ( ( short ) HIWORD( wParam ) > 0 ) { - Sys_QueEvent( g_wv.sysMsgTime, SE_KEY, K_MWHEELUP, qtrue, 0, NULL ); - Sys_QueEvent( g_wv.sysMsgTime, SE_KEY, K_MWHEELUP, qfalse, 0, NULL ); + Sys_QueEvent( g_wv.sysMsgTime, SE_KEY, A_MWHEELUP, qtrue, 0, NULL ); + Sys_QueEvent( g_wv.sysMsgTime, SE_KEY, A_MWHEELUP, qfalse, 0, NULL ); } else { - Sys_QueEvent( g_wv.sysMsgTime, SE_KEY, K_MWHEELDOWN, qtrue, 0, NULL ); - Sys_QueEvent( g_wv.sysMsgTime, SE_KEY, K_MWHEELDOWN, qfalse, 0, NULL ); + Sys_QueEvent( g_wv.sysMsgTime, SE_KEY, A_MWHEELDOWN, qtrue, 0, NULL ); + Sys_QueEvent( g_wv.sysMsgTime, SE_KEY, A_MWHEELDOWN, qfalse, 0, NULL ); } break; @@ -509,7 +477,7 @@ LONG WINAPI MainWndProc ( break; case WM_SYSKEYDOWN: - if ( wParam == 13 ) + if ( wParam == VK_RETURN ) { if ( sr_fullscreen ) { @@ -520,16 +488,40 @@ LONG WINAPI MainWndProc ( } // fall through case WM_KEYDOWN: - Sys_QueEvent( g_wv.sysMsgTime, SE_KEY, MapKey( lParam ), qtrue, 0, NULL ); + code = MapKey( lParam, wParam ); + if(code) + { + Sys_QueEvent( g_wv.sysMsgTime, SE_KEY, code, qtrue, 0, NULL ); + } break; case WM_SYSKEYUP: case WM_KEYUP: - Sys_QueEvent( g_wv.sysMsgTime, SE_KEY, MapKey( lParam ), qfalse, 0, NULL ); + code = MapKey( lParam, wParam ); + if(code) + { + Sys_QueEvent( g_wv.sysMsgTime, SE_KEY, code, qfalse, 0, NULL ); + } break; case WM_CHAR: - Sys_QueEvent( g_wv.sysMsgTime, SE_CHAR, wParam, 0, 0, NULL ); + if(((lParam >> 16) & 0xff) != CONSOLE_SCAN_CODE) + { + Sys_QueEvent( g_wv.sysMsgTime, SE_CHAR, wParam, 0, 0, NULL ); + } + // Output any debug prints +// if(in_debug && in_debug->integer & 2) +// { +// Com_Printf("WM_CHAR: %x\n", wParam); +// } + break; + + case WM_POWERBROADCAST: + if (wParam == PBT_APMQUERYSUSPEND) + { + Com_Printf("Cannot go into hibernate / standby mode while game is running!\n"); + return BROADCAST_QUERY_DENY; + } break; } diff --git a/ui/menudef.h b/ui/menudef.h index 56e6574..962fbf2 100644 --- a/ui/menudef.h +++ b/ui/menudef.h @@ -298,6 +298,9 @@ #define UI_SKIN_COLOR 287 #define UI_FORCE_POINTS 288 +//extra, for patch +#define UI_JEDI_NONJEDI 289 + #define VOICECHAT_GETFLAG "getflag" // command someone to get the flag #define VOICECHAT_OFFENSE "offense" // command someone to go on offense #define VOICECHAT_DEFEND "defend" // command someone to go on defense diff --git a/ui/vssver.scc b/ui/vssver.scc index 3fe239c..efc2429 100644 Binary files a/ui/vssver.scc and b/ui/vssver.scc differ