From 7e9f0c84abe6270e49f4bf0ad4ead6cb2593bf5a Mon Sep 17 00:00:00 2001 From: archive Date: Mon, 5 Jun 2000 00:00:00 +0000 Subject: [PATCH] as released 2000-06-05 --- Network/Delta.txt | 2 + Network/delta.lst | 234 ++ cl_dll/MOTD.cpp | 141 - cl_dll/ammo.cpp | 52 +- cl_dll/ammo_secondary.cpp | 2 +- cl_dll/ammohistory.cpp | 2 +- cl_dll/ammohistory.h | 1 - cl_dll/battery.cpp | 2 +- cl_dll/camera.h | 17 + cl_dll/cdll_int.cpp | 113 +- cl_dll/cl_dll.dsp | 248 +- cl_dll/cl_dll.dsw | 6 +- cl_dll/{util.h => cl_util.h} | 19 +- cl_dll/com_weapons.cpp | 277 ++ cl_dll/com_weapons.h | 41 + cl_dll/death.cpp | 221 +- cl_dll/demo.cpp | 103 + cl_dll/demo.h | 20 + cl_dll/entity.cpp | 914 +++++ cl_dll/ev_common.cpp | 198 + cl_dll/ev_hldm.cpp | 1112 ++++++ cl_dll/ev_hldm.h | 88 + cl_dll/events.cpp | 16 + cl_dll/eventscripts.h | 66 + cl_dll/flashlight.cpp | 2 +- cl_dll/geiger.cpp | 2 +- cl_dll/health.cpp | 2 +- cl_dll/health.h | 6 +- cl_dll/hl/hl_baseentity.cpp | 250 ++ cl_dll/hl/hl_events.cpp | 57 + cl_dll/hl/hl_objects.cpp | 28 + cl_dll/hl/hl_weapons.cpp | 822 ++++ cl_dll/hud.cpp | 312 +- cl_dll/hud.h | 112 +- cl_dll/hud_iface.h | 13 + cl_dll/hud_msg.cpp | 2 +- cl_dll/hud_redraw.cpp | 89 +- cl_dll/hud_servers.cpp | 1223 ++++++ cl_dll/hud_servers.h | 34 + cl_dll/hud_servers_priv.h | 91 + cl_dll/hud_update.cpp | 23 +- cl_dll/in_camera.cpp | 614 +++ cl_dll/in_defs.h | 14 + cl_dll/input.cpp | 957 +++++ cl_dll/inputw32.cpp | 940 +++++ cl_dll/kbutton.h | 11 + cl_dll/menu.cpp | 17 +- cl_dll/message.cpp | 2 +- cl_dll/mssccprj.scc | 3 +- cl_dll/saytext.cpp | 116 +- cl_dll/scoreboard.cpp | 528 --- cl_dll/status_icons.cpp | 13 +- cl_dll/statusbar.cpp | 12 +- cl_dll/text_message.cpp | 14 +- cl_dll/tf_defs.h | 1357 +++++++ cl_dll/train.cpp | 2 +- cl_dll/tri.cpp | 115 + cl_dll/util.cpp | 90 +- cl_dll/vgui_ClassMenu.cpp | 426 +++ cl_dll/vgui_ConsolePanel.cpp | 95 + cl_dll/vgui_ConsolePanel.h | 32 + cl_dll/vgui_ControlConfigPanel.cpp | 206 + cl_dll/vgui_ControlConfigPanel.h | 41 + cl_dll/vgui_CustomObjects.cpp | 441 +++ cl_dll/vgui_MOTDWindow.cpp | 147 + cl_dll/vgui_SchemeManager.cpp | 544 +++ cl_dll/vgui_SchemeManager.h | 47 + cl_dll/vgui_ScorePanel.cpp | 629 ++++ cl_dll/vgui_ScorePanel.h | 122 + cl_dll/vgui_ServerBrowser.cpp | 617 +++ cl_dll/vgui_ServerBrowser.h | 44 + cl_dll/vgui_TeamFortressViewport.cpp | 2134 +++++++++++ cl_dll/vgui_TeamFortressViewport.h | 1255 +++++++ cl_dll/vgui_int.cpp | 122 + cl_dll/vgui_int.h | 15 + cl_dll/vgui_teammenu.cpp | 389 ++ cl_dll/view.cpp | 1023 +++++ cl_dll/view.h | 8 + cl_dll/wrect.h | 9 + common/beamdef.h | 62 + common/cl_entity.h | 115 + common/con_nprint.h | 31 + {engine => common}/const.h | 52 +- common/crc.h | 51 + common/cvardef.h | 36 + common/demo_api.h | 31 + common/dlight.h | 33 + common/dll_state.h | 15 + common/engine_launcher_api.h | 101 + common/entity_state.h | 193 + common/entity_types.h | 26 + common/event_api.h | 51 + common/event_args.h | 51 + common/event_flags.h | 47 + common/exefuncs.h | 41 + common/in_buttons.h | 38 + common/mathlib.h | 146 + common/net_api.h | 92 + common/netadr.h | 40 + common/particledef.h | 57 + common/pmtrace.h | 43 + common/qfont.h | 40 + common/r_efx.h | 194 + common/ref_params.h | 69 + common/screenfade.h | 16 + common/studio_event.h | 29 + common/triangleapi.h | 54 + common/usercmd.h | 41 + common/weaponinfo.h | 52 + dedicated/Dedicated.dsp | 172 + dedicated/Makefile | 55 + dedicated/NetGame.ico | Bin 0 -> 1078 bytes dedicated/conproc.cpp | 417 +++ dedicated/conproc.h | 23 + dedicated/dedicated.h | 18 + dedicated/dedicated.rc | 72 + dedicated/engine.cpp | 331 ++ dedicated/enginecallback.h | 25 + dedicated/exports.h | 7 + dedicated/md5.cpp | 317 ++ dedicated/md5.h | 7 + dedicated/resource.h | 18 + dedicated/sys_ded.cpp | 1051 ++++++ dedicated/sys_ded.h | 14 + dlls/Makefile | 137 + dlls/activity.h | 2 +- dlls/activitymap.h | 2 +- dlls/airtank.cpp | 2 +- dlls/animating.cpp | 2 +- dlls/animation.cpp | 8 +- dlls/animation.h | 2 +- dlls/basemonster.h | 2 +- dlls/bmodels.cpp | 2 +- dlls/buttons.cpp | 2 +- dlls/cbase.cpp | 41 +- dlls/cbase.h | 9 +- dlls/cdll_dll.h | 2 +- dlls/client.cpp | 876 ++++- dlls/client.h | 26 +- dlls/combat.cpp | 36 +- dlls/crossbow.cpp | 8 +- dlls/crowbar.cpp | 8 +- dlls/decals.h | 2 +- dlls/doors.cpp | 2 +- dlls/doors.h | 2 +- dlls/effects.cpp | 4 +- dlls/effects.h | 2 +- dlls/egon.cpp | 8 +- dlls/enginecallback.h | 37 +- dlls/explode.cpp | 2 +- dlls/explode.h | 2 +- dlls/extdll.h | 35 +- dlls/func_break.cpp | 8 +- dlls/func_break.h | 2 +- dlls/func_tank.cpp | 5 +- dlls/game.cpp | 18 +- dlls/game.h | 8 +- dlls/gamerules.cpp | 6 +- dlls/gamerules.h | 2 +- dlls/gauss.cpp | 294 +- dlls/ggrenade.cpp | 2 +- dlls/globals.cpp | 2 +- dlls/h_ai.cpp | 2 +- dlls/h_battery.cpp | 2 +- dlls/h_cycler.cpp | 10 +- dlls/h_export.cpp | 8 +- dlls/handgrenade.cpp | 8 +- dlls/healthkit.cpp | 2 +- dlls/hornet.cpp | 2 +- dlls/hornet.h | 2 +- dlls/hornetgun.cpp | 8 +- dlls/items.cpp | 4 +- dlls/items.h | 2 +- dlls/lights.cpp | 16 +- dlls/maprules.cpp | 2 +- dlls/maprules.h | 2 +- dlls/monsterevent.h | 2 +- dlls/monsters.h | 2 +- dlls/mortar.cpp | 2 +- dlls/mp.dsp | 59 +- dlls/mp5.cpp | 39 +- dlls/mpstubb.cpp | 2 +- dlls/multiplay_gamerules.cpp | 527 ++- dlls/nodes.h | 2 +- dlls/pathcorner.cpp | 2 +- dlls/plane.cpp | 3 +- dlls/plane.h | 2 +- dlls/plats.cpp | 29 +- dlls/player.cpp | 365 +- dlls/player.h | 5 +- dlls/python.cpp | 60 +- dlls/rpg.cpp | 8 +- dlls/satchel.cpp | 10 +- dlls/saverestore.h | 2 +- dlls/schedule.h | 2 +- dlls/scriptevent.h | 2 +- dlls/shotgun.cpp | 52 +- dlls/singleplay_gamerules.cpp | 2 +- dlls/skill.cpp | 2 +- dlls/skill.h | 2 +- dlls/sound.cpp | 2 +- dlls/soundent.cpp | 2 +- dlls/soundent.h | 2 +- dlls/spectator.cpp | 2 +- dlls/spectator.h | 2 +- dlls/squeakgrenade.cpp | 19 +- dlls/subs.cpp | 2 +- dlls/talkmonster.h | 2 +- dlls/teamplay_gamerules.cpp | 36 +- dlls/teamplay_gamerules.h | 2 +- dlls/trains.h | 5 +- dlls/triggers.cpp | 4 +- dlls/tripmine.cpp | 8 +- dlls/util.cpp | 201 +- dlls/util.h | 48 +- dlls/vector.h | 2 +- dlls/weapons.cpp | 88 +- dlls/weapons.h | 50 +- dlls/world.cpp | 7 +- .../hl_wpn_glock.cpp} | 64 +- dlls/xen.cpp | 2 +- engine/{ANORMS.H => Anorms.h} | 0 engine/PROGS.H | 145 - engine/Progs.h | 82 + engine/cdll_int.h | 198 +- engine/custom.h | 47 +- engine/customentity.h | 44 - engine/cvardef.h | 34 - engine/edict.h | 27 + engine/eiface.h | 122 +- engine/keydefs.h | 121 + engine/progdefs.h | 52 +- engine/shake.h | 2 +- engine/studio.h | 4 +- pm_shared/pm_debug.c | 303 ++ pm_shared/pm_debug.h | 24 + pm_shared/pm_defs.h | 218 ++ pm_shared/pm_info.h | 22 + pm_shared/pm_materials.h | 33 + pm_shared/pm_math.c | 338 ++ pm_shared/pm_movevars.h | 40 + pm_shared/pm_shared.c | 3335 +++++++++++++++++ pm_shared/pm_shared.h | 32 + utils/bspinfo/mssccprj.scc | 3 +- utils/light/light.c | 221 ++ utils/light/light.dsp | 133 + utils/light/light.h | 54 + utils/light/ltface.c | 682 ++++ utils/light/trace.c | 199 + utils/makefont/makefont.cpp | 494 +++ utils/makefont/makefont.dsp | 138 + utils/makefont/makefont.dsw | 29 + utils/makels/mssccprj.scc | 3 +- utils/makevfont/StdAfx.cpp | 8 + utils/makevfont/StdAfx.h | 23 + utils/makevfont/fileimage.cpp | 198 + utils/makevfont/fileimage.h | 85 + utils/makevfont/fontfiles.pl | 99 + utils/makevfont/makevfont.cpp | 378 ++ utils/makevfont/makevfont.dsp | 123 + utils/makevfont/vfontdata.cpp | 77 + utils/makevfont/vfontdata.h | 44 + utils/mkmovie/mssccprj.scc | 3 +- utils/procinfo/lib/win32_vc6/procinfo.lib | Bin 0 -> 2468 bytes utils/procinfo/procinfo.h | 8 + utils/qbsp2/mssccprj.scc | 6 +- utils/qcsg/hullfile.c | 77 + utils/qcsg/hulls.txt | 4 + utils/qcsg/mssccprj.scc | 3 +- utils/qcsg/qcsg.c | 15 +- utils/qcsg/qcsg.dsp | 4 + utils/qlumpy/mssccprj.scc | 3 +- utils/qrad/mssccprj.scc | 3 +- utils/serverctrl/ServerCtrl.cpp | 61 + utils/serverctrl/ServerCtrl.h | 47 + utils/serverctrl/ServerCtrl.rc | 179 + utils/serverctrl/ServerCtrlDlg.cpp | 658 ++++ utils/serverctrl/ServerCtrlDlg.h | 79 + utils/serverctrl/StdAfx.cpp | 8 + utils/serverctrl/StdAfx.h | 26 + utils/serverctrl/res/serverctrl.ico | Bin 0 -> 1078 bytes utils/serverctrl/res/serverctrl.rc2 | 13 + utils/serverctrl/resource.h | 22 + utils/serverctrl/serverctrl.dsp | 144 + utils/smdlexp/mssccprj.scc | 3 +- utils/sprgen/mssccprj.scc | 3 +- utils/studiomdl/mssccprj.scc | 3 +- utils/vgui/include/VGUI.h | 101 + utils/vgui/include/VGUI_ActionSignal.h | 78 + utils/vgui/include/VGUI_App.h | 126 + utils/vgui/include/VGUI_Bitmap.h | 31 + utils/vgui/include/VGUI_BitmapTGA.h | 23 + utils/vgui/include/VGUI_Border.h | 39 + utils/vgui/include/VGUI_BorderLayout.h | 40 + utils/vgui/include/VGUI_BorderPair.h | 27 + utils/vgui/include/VGUI_BuildGroup.h | 61 + utils/vgui/include/VGUI_Button.h | 55 + utils/vgui/include/VGUI_ButtonController.h | 21 + utils/vgui/include/VGUI_ButtonGroup.h | 24 + utils/vgui/include/VGUI_ChangeSignal.h | 20 + utils/vgui/include/VGUI_CheckButton.h | 22 + utils/vgui/include/VGUI_Color.h | 38 + utils/vgui/include/VGUI_ComboKey.h | 28 + utils/vgui/include/VGUI_ConfigWizard.h | 34 + utils/vgui/include/VGUI_Cursor.h | 51 + utils/vgui/include/VGUI_Dar.h | 187 + utils/vgui/include/VGUI_DataInputStream.h | 43 + utils/vgui/include/VGUI_Desktop.h | 36 + utils/vgui/include/VGUI_DesktopIcon.h | 35 + utils/vgui/include/VGUI_EditPanel.h | 59 + utils/vgui/include/VGUI_EtchedBorder.h | 23 + utils/vgui/include/VGUI_FileInputStream.h | 32 + utils/vgui/include/VGUI_FlowLayout.h | 23 + utils/vgui/include/VGUI_FocusChangeSignal.h | 20 + utils/vgui/include/VGUI_FocusNavGroup.h | 29 + utils/vgui/include/VGUI_Font.h | 42 + utils/vgui/include/VGUI_Frame.h | 67 + utils/vgui/include/VGUI_FrameSignal.h | 21 + utils/vgui/include/VGUI_GridLayout.h | 24 + utils/vgui/include/VGUI_HeaderPanel.h | 59 + utils/vgui/include/VGUI_Image.h | 56 + utils/vgui/include/VGUI_ImagePanel.h | 27 + utils/vgui/include/VGUI_InputSignal.h | 34 + utils/vgui/include/VGUI_InputStream.h | 24 + utils/vgui/include/VGUI_IntChangeSignal.h | 20 + utils/vgui/include/VGUI_IntLabel.h | 29 + utils/vgui/include/VGUI_KeyCode.h | 120 + utils/vgui/include/VGUI_Label.h | 69 + utils/vgui/include/VGUI_Layout.h | 25 + utils/vgui/include/VGUI_LayoutInfo.h | 15 + utils/vgui/include/VGUI_LineBorder.h | 31 + utils/vgui/include/VGUI_ListPanel.h | 34 + utils/vgui/include/VGUI_LoweredBorder.h | 23 + utils/vgui/include/VGUI_Menu.h | 24 + utils/vgui/include/VGUI_MenuItem.h | 24 + utils/vgui/include/VGUI_MenuSeparator.h | 21 + utils/vgui/include/VGUI_MessageBox.h | 47 + utils/vgui/include/VGUI_MiniApp.h | 27 + utils/vgui/include/VGUI_MouseCode.h | 18 + utils/vgui/include/VGUI_Panel.h | 218 ++ utils/vgui/include/VGUI_PopupMenu.h | 24 + utils/vgui/include/VGUI_ProgressBar.h | 27 + utils/vgui/include/VGUI_RadioButton.h | 23 + utils/vgui/include/VGUI_RaisedBorder.h | 23 + utils/vgui/include/VGUI_RepaintSignal.h | 19 + utils/vgui/include/VGUI_Scheme.h | 76 + utils/vgui/include/VGUI_ScrollBar.h | 50 + utils/vgui/include/VGUI_ScrollPanel.h | 49 + utils/vgui/include/VGUI_Slider.h | 63 + utils/vgui/include/VGUI_StackLayout.h | 24 + utils/vgui/include/VGUI_String.h | 55 + utils/vgui/include/VGUI_Surface.h | 61 + utils/vgui/include/VGUI_SurfaceBase.h | 75 + utils/vgui/include/VGUI_SurfaceGL.h | 92 + utils/vgui/include/VGUI_TabPanel.h | 43 + utils/vgui/include/VGUI_TablePanel.h | 65 + utils/vgui/include/VGUI_TaskBar.h | 31 + utils/vgui/include/VGUI_TextEntry.h | 74 + utils/vgui/include/VGUI_TextGrid.h | 36 + utils/vgui/include/VGUI_TextImage.h | 52 + utils/vgui/include/VGUI_TextPanel.h | 40 + utils/vgui/include/VGUI_TickSignal.h | 16 + utils/vgui/include/VGUI_ToggleButton.h | 20 + utils/vgui/include/VGUI_TreeFolder.h | 30 + utils/vgui/include/VGUI_WizardPanel.h | 140 + utils/vgui/lib/win32_vc6/vgui.lib | Bin 0 -> 415712 bytes utils/visx2/mssccprj.scc | 3 +- 367 files changed, 38976 insertions(+), 2127 deletions(-) create mode 100644 Network/Delta.txt create mode 100644 Network/delta.lst delete mode 100644 cl_dll/MOTD.cpp create mode 100644 cl_dll/camera.h rename cl_dll/{util.h => cl_util.h} (87%) create mode 100644 cl_dll/com_weapons.cpp create mode 100644 cl_dll/com_weapons.h create mode 100644 cl_dll/demo.cpp create mode 100644 cl_dll/demo.h create mode 100644 cl_dll/entity.cpp create mode 100644 cl_dll/ev_common.cpp create mode 100644 cl_dll/ev_hldm.cpp create mode 100644 cl_dll/ev_hldm.h create mode 100644 cl_dll/events.cpp create mode 100644 cl_dll/eventscripts.h create mode 100644 cl_dll/hl/hl_baseentity.cpp create mode 100644 cl_dll/hl/hl_events.cpp create mode 100644 cl_dll/hl/hl_objects.cpp create mode 100644 cl_dll/hl/hl_weapons.cpp create mode 100644 cl_dll/hud_iface.h create mode 100644 cl_dll/hud_servers.cpp create mode 100644 cl_dll/hud_servers.h create mode 100644 cl_dll/hud_servers_priv.h create mode 100644 cl_dll/in_camera.cpp create mode 100644 cl_dll/in_defs.h create mode 100644 cl_dll/input.cpp create mode 100644 cl_dll/inputw32.cpp create mode 100644 cl_dll/kbutton.h delete mode 100644 cl_dll/scoreboard.cpp create mode 100644 cl_dll/tf_defs.h create mode 100644 cl_dll/tri.cpp create mode 100644 cl_dll/vgui_ClassMenu.cpp create mode 100644 cl_dll/vgui_ConsolePanel.cpp create mode 100644 cl_dll/vgui_ConsolePanel.h create mode 100644 cl_dll/vgui_ControlConfigPanel.cpp create mode 100644 cl_dll/vgui_ControlConfigPanel.h create mode 100644 cl_dll/vgui_CustomObjects.cpp create mode 100644 cl_dll/vgui_MOTDWindow.cpp create mode 100644 cl_dll/vgui_SchemeManager.cpp create mode 100644 cl_dll/vgui_SchemeManager.h create mode 100644 cl_dll/vgui_ScorePanel.cpp create mode 100644 cl_dll/vgui_ScorePanel.h create mode 100644 cl_dll/vgui_ServerBrowser.cpp create mode 100644 cl_dll/vgui_ServerBrowser.h create mode 100644 cl_dll/vgui_TeamFortressViewport.cpp create mode 100644 cl_dll/vgui_TeamFortressViewport.h create mode 100644 cl_dll/vgui_int.cpp create mode 100644 cl_dll/vgui_int.h create mode 100644 cl_dll/vgui_teammenu.cpp create mode 100644 cl_dll/view.cpp create mode 100644 cl_dll/view.h create mode 100644 cl_dll/wrect.h create mode 100644 common/beamdef.h create mode 100644 common/cl_entity.h create mode 100644 common/con_nprint.h rename {engine => common}/const.h (93%) create mode 100644 common/crc.h create mode 100644 common/cvardef.h create mode 100644 common/demo_api.h create mode 100644 common/dlight.h create mode 100644 common/dll_state.h create mode 100644 common/engine_launcher_api.h create mode 100644 common/entity_state.h create mode 100644 common/entity_types.h create mode 100644 common/event_api.h create mode 100644 common/event_args.h create mode 100644 common/event_flags.h create mode 100644 common/exefuncs.h create mode 100644 common/in_buttons.h create mode 100644 common/mathlib.h create mode 100644 common/net_api.h create mode 100644 common/netadr.h create mode 100644 common/particledef.h create mode 100644 common/pmtrace.h create mode 100644 common/qfont.h create mode 100644 common/r_efx.h create mode 100644 common/ref_params.h create mode 100644 common/screenfade.h create mode 100644 common/studio_event.h create mode 100644 common/triangleapi.h create mode 100644 common/usercmd.h create mode 100644 common/weaponinfo.h create mode 100644 dedicated/Dedicated.dsp create mode 100644 dedicated/Makefile create mode 100644 dedicated/NetGame.ico create mode 100644 dedicated/conproc.cpp create mode 100644 dedicated/conproc.h create mode 100644 dedicated/dedicated.h create mode 100644 dedicated/dedicated.rc create mode 100644 dedicated/engine.cpp create mode 100644 dedicated/enginecallback.h create mode 100644 dedicated/exports.h create mode 100644 dedicated/md5.cpp create mode 100644 dedicated/md5.h create mode 100644 dedicated/resource.h create mode 100644 dedicated/sys_ded.cpp create mode 100644 dedicated/sys_ded.h create mode 100644 dlls/Makefile rename dlls/{glock.cpp => wpn_shared/hl_wpn_glock.cpp} (77%) rename engine/{ANORMS.H => Anorms.h} (100%) delete mode 100644 engine/PROGS.H create mode 100644 engine/Progs.h delete mode 100644 engine/cvardef.h create mode 100644 engine/edict.h create mode 100644 engine/keydefs.h create mode 100644 pm_shared/pm_debug.c create mode 100644 pm_shared/pm_debug.h create mode 100644 pm_shared/pm_defs.h create mode 100644 pm_shared/pm_info.h create mode 100644 pm_shared/pm_materials.h create mode 100644 pm_shared/pm_math.c create mode 100644 pm_shared/pm_movevars.h create mode 100644 pm_shared/pm_shared.c create mode 100644 pm_shared/pm_shared.h create mode 100644 utils/light/light.c create mode 100644 utils/light/light.dsp create mode 100644 utils/light/light.h create mode 100644 utils/light/ltface.c create mode 100644 utils/light/trace.c create mode 100644 utils/makefont/makefont.cpp create mode 100644 utils/makefont/makefont.dsp create mode 100644 utils/makefont/makefont.dsw create mode 100644 utils/makevfont/StdAfx.cpp create mode 100644 utils/makevfont/StdAfx.h create mode 100644 utils/makevfont/fileimage.cpp create mode 100644 utils/makevfont/fileimage.h create mode 100644 utils/makevfont/fontfiles.pl create mode 100644 utils/makevfont/makevfont.cpp create mode 100644 utils/makevfont/makevfont.dsp create mode 100644 utils/makevfont/vfontdata.cpp create mode 100644 utils/makevfont/vfontdata.h create mode 100644 utils/procinfo/lib/win32_vc6/procinfo.lib create mode 100644 utils/procinfo/procinfo.h create mode 100644 utils/qcsg/hullfile.c create mode 100644 utils/qcsg/hulls.txt create mode 100644 utils/serverctrl/ServerCtrl.cpp create mode 100644 utils/serverctrl/ServerCtrl.h create mode 100644 utils/serverctrl/ServerCtrl.rc create mode 100644 utils/serverctrl/ServerCtrlDlg.cpp create mode 100644 utils/serverctrl/ServerCtrlDlg.h create mode 100644 utils/serverctrl/StdAfx.cpp create mode 100644 utils/serverctrl/StdAfx.h create mode 100644 utils/serverctrl/res/serverctrl.ico create mode 100644 utils/serverctrl/res/serverctrl.rc2 create mode 100644 utils/serverctrl/resource.h create mode 100644 utils/serverctrl/serverctrl.dsp create mode 100644 utils/vgui/include/VGUI.h create mode 100644 utils/vgui/include/VGUI_ActionSignal.h create mode 100644 utils/vgui/include/VGUI_App.h create mode 100644 utils/vgui/include/VGUI_Bitmap.h create mode 100644 utils/vgui/include/VGUI_BitmapTGA.h create mode 100644 utils/vgui/include/VGUI_Border.h create mode 100644 utils/vgui/include/VGUI_BorderLayout.h create mode 100644 utils/vgui/include/VGUI_BorderPair.h create mode 100644 utils/vgui/include/VGUI_BuildGroup.h create mode 100644 utils/vgui/include/VGUI_Button.h create mode 100644 utils/vgui/include/VGUI_ButtonController.h create mode 100644 utils/vgui/include/VGUI_ButtonGroup.h create mode 100644 utils/vgui/include/VGUI_ChangeSignal.h create mode 100644 utils/vgui/include/VGUI_CheckButton.h create mode 100644 utils/vgui/include/VGUI_Color.h create mode 100644 utils/vgui/include/VGUI_ComboKey.h create mode 100644 utils/vgui/include/VGUI_ConfigWizard.h create mode 100644 utils/vgui/include/VGUI_Cursor.h create mode 100644 utils/vgui/include/VGUI_Dar.h create mode 100644 utils/vgui/include/VGUI_DataInputStream.h create mode 100644 utils/vgui/include/VGUI_Desktop.h create mode 100644 utils/vgui/include/VGUI_DesktopIcon.h create mode 100644 utils/vgui/include/VGUI_EditPanel.h create mode 100644 utils/vgui/include/VGUI_EtchedBorder.h create mode 100644 utils/vgui/include/VGUI_FileInputStream.h create mode 100644 utils/vgui/include/VGUI_FlowLayout.h create mode 100644 utils/vgui/include/VGUI_FocusChangeSignal.h create mode 100644 utils/vgui/include/VGUI_FocusNavGroup.h create mode 100644 utils/vgui/include/VGUI_Font.h create mode 100644 utils/vgui/include/VGUI_Frame.h create mode 100644 utils/vgui/include/VGUI_FrameSignal.h create mode 100644 utils/vgui/include/VGUI_GridLayout.h create mode 100644 utils/vgui/include/VGUI_HeaderPanel.h create mode 100644 utils/vgui/include/VGUI_Image.h create mode 100644 utils/vgui/include/VGUI_ImagePanel.h create mode 100644 utils/vgui/include/VGUI_InputSignal.h create mode 100644 utils/vgui/include/VGUI_InputStream.h create mode 100644 utils/vgui/include/VGUI_IntChangeSignal.h create mode 100644 utils/vgui/include/VGUI_IntLabel.h create mode 100644 utils/vgui/include/VGUI_KeyCode.h create mode 100644 utils/vgui/include/VGUI_Label.h create mode 100644 utils/vgui/include/VGUI_Layout.h create mode 100644 utils/vgui/include/VGUI_LayoutInfo.h create mode 100644 utils/vgui/include/VGUI_LineBorder.h create mode 100644 utils/vgui/include/VGUI_ListPanel.h create mode 100644 utils/vgui/include/VGUI_LoweredBorder.h create mode 100644 utils/vgui/include/VGUI_Menu.h create mode 100644 utils/vgui/include/VGUI_MenuItem.h create mode 100644 utils/vgui/include/VGUI_MenuSeparator.h create mode 100644 utils/vgui/include/VGUI_MessageBox.h create mode 100644 utils/vgui/include/VGUI_MiniApp.h create mode 100644 utils/vgui/include/VGUI_MouseCode.h create mode 100644 utils/vgui/include/VGUI_Panel.h create mode 100644 utils/vgui/include/VGUI_PopupMenu.h create mode 100644 utils/vgui/include/VGUI_ProgressBar.h create mode 100644 utils/vgui/include/VGUI_RadioButton.h create mode 100644 utils/vgui/include/VGUI_RaisedBorder.h create mode 100644 utils/vgui/include/VGUI_RepaintSignal.h create mode 100644 utils/vgui/include/VGUI_Scheme.h create mode 100644 utils/vgui/include/VGUI_ScrollBar.h create mode 100644 utils/vgui/include/VGUI_ScrollPanel.h create mode 100644 utils/vgui/include/VGUI_Slider.h create mode 100644 utils/vgui/include/VGUI_StackLayout.h create mode 100644 utils/vgui/include/VGUI_String.h create mode 100644 utils/vgui/include/VGUI_Surface.h create mode 100644 utils/vgui/include/VGUI_SurfaceBase.h create mode 100644 utils/vgui/include/VGUI_SurfaceGL.h create mode 100644 utils/vgui/include/VGUI_TabPanel.h create mode 100644 utils/vgui/include/VGUI_TablePanel.h create mode 100644 utils/vgui/include/VGUI_TaskBar.h create mode 100644 utils/vgui/include/VGUI_TextEntry.h create mode 100644 utils/vgui/include/VGUI_TextGrid.h create mode 100644 utils/vgui/include/VGUI_TextImage.h create mode 100644 utils/vgui/include/VGUI_TextPanel.h create mode 100644 utils/vgui/include/VGUI_TickSignal.h create mode 100644 utils/vgui/include/VGUI_ToggleButton.h create mode 100644 utils/vgui/include/VGUI_TreeFolder.h create mode 100644 utils/vgui/include/VGUI_WizardPanel.h create mode 100644 utils/vgui/lib/win32_vc6/vgui.lib diff --git a/Network/Delta.txt b/Network/Delta.txt new file mode 100644 index 0000000..b801499 --- /dev/null +++ b/Network/Delta.txt @@ -0,0 +1,2 @@ +Place delta.lst in the valve\ folder ( or a customized copy can be placed in your game directory's folder ) + diff --git a/Network/delta.lst b/Network/delta.lst new file mode 100644 index 0000000..4d45ad7 --- /dev/null +++ b/Network/delta.lst @@ -0,0 +1,234 @@ +// structure name +// none == no conditional encode routine +// gamedll routine_name : before transmitting data, invoke the named function from the game .dll to reset fields as needed +// clientdll routine_name : same as above, except the routine is called via the client.dll + +clientdata_t none +{ + DEFINE_DELTA( flTimeStepSound, DT_INTEGER, 10, 1.0 ), + DEFINE_DELTA( origin[0], DT_SIGNED | DT_FLOAT, 21, 128.0 ), + DEFINE_DELTA( origin[1], DT_SIGNED | DT_FLOAT, 21, 128.0 ), + DEFINE_DELTA( velocity[0], DT_SIGNED | DT_FLOAT, 16, 8.0 ), + DEFINE_DELTA( velocity[1], DT_SIGNED | DT_FLOAT, 16, 8.0 ), + + DEFINE_DELTA( m_flNextAttack, DT_FLOAT | DT_SIGNED, 22, 1000.0 ), + + DEFINE_DELTA( origin[2], DT_SIGNED | DT_FLOAT, 21, 128.0 ), + DEFINE_DELTA( velocity[2], DT_SIGNED | DT_FLOAT, 16, 8.0 ), + + DEFINE_DELTA( ammo_nails, DT_SIGNED | DT_INTEGER, 10, 1.0 ), + DEFINE_DELTA( ammo_shells, DT_SIGNED | DT_INTEGER, 10, 1.0 ), + DEFINE_DELTA( ammo_cells, DT_SIGNED | DT_INTEGER, 10, 1.0 ), + DEFINE_DELTA( ammo_rockets, DT_SIGNED | DT_INTEGER, 10, 1.0 ), + + DEFINE_DELTA( m_iId, DT_INTEGER, 5, 1.0 ), + + DEFINE_DELTA( punchangle[2], DT_SIGNED | DT_FLOAT, 16, 8.0 ), + DEFINE_DELTA( flags, DT_INTEGER, 32, 1.0 ), // Cut to 3 bits? + DEFINE_DELTA( weaponanim, DT_INTEGER, 8, 1.0 ), + DEFINE_DELTA( health, DT_SIGNED | DT_FLOAT, 10, 1.0 ), // Cut # of bits? + DEFINE_DELTA( maxspeed, DT_FLOAT, 16, 10.0 ), + DEFINE_DELTA( flDuckTime, DT_INTEGER, 10, 1.0 ), + DEFINE_DELTA( view_ofs[2], DT_SIGNED | DT_FLOAT, 10, 4.0 ), + DEFINE_DELTA( punchangle[0], DT_SIGNED | DT_FLOAT, 16, 8.0 ), + DEFINE_DELTA( punchangle[1], DT_SIGNED | DT_FLOAT, 16, 8.0 ), + DEFINE_DELTA( viewmodel, DT_INTEGER, 10, 1.0 ), + DEFINE_DELTA( weapons, DT_INTEGER, 32, 1.0 ), + + DEFINE_DELTA( pushmsec, DT_INTEGER, 11, 1.0 ), + DEFINE_DELTA( deadflag, DT_INTEGER, 3, 1.0 ), + DEFINE_DELTA( fov, DT_FLOAT, 8, 1.0 ), + DEFINE_DELTA( physinfo, DT_STRING, 1, 1.0 ), + DEFINE_DELTA( bInDuck, DT_INTEGER, 1, 1.0 ), + DEFINE_DELTA( flSwimTime, DT_INTEGER, 10, 1.0 ), + DEFINE_DELTA( waterjumptime, DT_INTEGER, 15, 1.0 ), + DEFINE_DELTA( waterlevel, DT_INTEGER, 2, 1.0 ) +} + +entity_state_t gamedll Entity_Encode +{ + DEFINE_DELTA( animtime, DT_TIMEWINDOW_8, 8, 1.0 ), + DEFINE_DELTA( frame, DT_FLOAT, 8, 1.0 ), + DEFINE_DELTA( origin[0], DT_SIGNED | DT_FLOAT, 16, 8.0 ), + DEFINE_DELTA( angles[0], DT_ANGLE, 16, 1.0 ), + DEFINE_DELTA( angles[1], DT_ANGLE, 16, 1.0 ), + DEFINE_DELTA( origin[1], DT_SIGNED | DT_FLOAT, 16, 8.0 ), + DEFINE_DELTA( origin[2], DT_SIGNED | DT_FLOAT, 16, 8.0 ), + DEFINE_DELTA( sequence, DT_INTEGER, 8, 1.0 ), + DEFINE_DELTA( modelindex, DT_INTEGER, 10, 1.0 ), + DEFINE_DELTA( movetype, DT_INTEGER, 4, 1.0 ), + DEFINE_DELTA( solid, DT_SHORT, 3, 1.0 ), + DEFINE_DELTA( mins[0], DT_SIGNED | DT_FLOAT, 16, 8.0 ), + DEFINE_DELTA( mins[1], DT_SIGNED | DT_FLOAT, 16, 8.0 ), + DEFINE_DELTA( mins[2], DT_SIGNED | DT_FLOAT, 16, 8.0 ), + DEFINE_DELTA( maxs[0], DT_SIGNED | DT_FLOAT, 16, 8.0 ), + DEFINE_DELTA( maxs[1], DT_SIGNED | DT_FLOAT, 16, 8.0 ), + DEFINE_DELTA( maxs[2], DT_SIGNED | DT_FLOAT, 16, 8.0 ), + + DEFINE_DELTA( endpos[0], DT_SIGNED | DT_FLOAT, 13, 1.0 ), + DEFINE_DELTA( endpos[1], DT_SIGNED | DT_FLOAT, 13, 1.0 ), + DEFINE_DELTA( endpos[2], DT_SIGNED | DT_FLOAT, 13, 1.0 ), + DEFINE_DELTA( startpos[0], DT_SIGNED | DT_FLOAT, 13, 1.0 ), + DEFINE_DELTA( startpos[1], DT_SIGNED | DT_FLOAT, 13, 1.0 ), + DEFINE_DELTA( startpos[2], DT_SIGNED | DT_FLOAT, 13, 1.0 ), + DEFINE_DELTA( impacttime, DT_TIMEWINDOW_BIG, 13, 100.0 ), + DEFINE_DELTA( starttime, DT_TIMEWINDOW_BIG, 13, 100.0 ), + + DEFINE_DELTA( weaponmodel, DT_INTEGER, 10, 1.0 ), + DEFINE_DELTA( owner, DT_INTEGER, 5, 1.0 ), + DEFINE_DELTA( effects, DT_INTEGER, 8, 1.0 ), + DEFINE_DELTA( eflags, DT_INTEGER, 1, 1.0 ), + DEFINE_DELTA( angles[2], DT_ANGLE, 16, 1.0 ), + DEFINE_DELTA( colormap, DT_INTEGER, 16, 1.0 ), + DEFINE_DELTA( framerate, DT_SIGNED | DT_FLOAT, 8, 16.0 ), + DEFINE_DELTA( skin, DT_SHORT | DT_SIGNED, 9, 1.0 ), + DEFINE_DELTA( controller[0], DT_BYTE, 8, 1.0 ), + DEFINE_DELTA( controller[1], DT_BYTE, 8, 1.0 ), + DEFINE_DELTA( controller[2], DT_BYTE, 8, 1.0 ), + DEFINE_DELTA( controller[3], DT_BYTE, 8, 1.0 ), + DEFINE_DELTA( blending[0], DT_BYTE, 8, 1.0 ), + DEFINE_DELTA( blending[1], DT_BYTE, 8, 1.0 ), + DEFINE_DELTA( body, DT_INTEGER, 8, 1.0 ), + DEFINE_DELTA( rendermode, DT_INTEGER, 8, 1.0 ), + DEFINE_DELTA( renderamt, DT_INTEGER, 8, 1.0 ), + DEFINE_DELTA( renderfx, DT_INTEGER, 8, 1.0 ), + DEFINE_DELTA( scale, DT_FLOAT, 16, 256.0 ), + DEFINE_DELTA( rendercolor.r, DT_BYTE, 8, 1.0 ), + DEFINE_DELTA( rendercolor.g, DT_BYTE, 8, 1.0 ), + DEFINE_DELTA( rendercolor.b, DT_BYTE, 8, 1.0 ), + DEFINE_DELTA( aiment, DT_INTEGER, 11, 1.0 ), + DEFINE_DELTA( basevelocity[0], DT_SIGNED | DT_FLOAT, 16, 8.0 ), + DEFINE_DELTA( basevelocity[1], DT_SIGNED | DT_FLOAT, 16, 8.0 ), + DEFINE_DELTA( basevelocity[2], DT_SIGNED | DT_FLOAT, 16, 8.0 ) +} + +entity_state_player_t gamedll Player_Encode +{ + DEFINE_DELTA( animtime, DT_TIMEWINDOW_8, 8, 1.0 ), + DEFINE_DELTA( frame, DT_FLOAT, 8, 1.0 ), + DEFINE_DELTA( origin[0], DT_SIGNED | DT_FLOAT, 18, 32.0 ), + DEFINE_DELTA( angles[0], DT_ANGLE, 16, 1.0 ), + DEFINE_DELTA( angles[1], DT_ANGLE, 16, 1.0 ), + DEFINE_DELTA( origin[1], DT_SIGNED | DT_FLOAT, 18, 32.0 ), + DEFINE_DELTA( origin[2], DT_SIGNED | DT_FLOAT, 18, 32.0 ), + DEFINE_DELTA( gaitsequence, DT_INTEGER, 8, 1.0 ), + DEFINE_DELTA( sequence, DT_INTEGER, 8, 1.0 ), + DEFINE_DELTA( modelindex, DT_INTEGER, 10, 1.0 ), + DEFINE_DELTA( movetype, DT_INTEGER, 4, 1.0 ), + DEFINE_DELTA( solid, DT_SHORT, 3, 1.0 ), + DEFINE_DELTA( mins[0], DT_SIGNED | DT_FLOAT, 16, 8.0 ), + DEFINE_DELTA( mins[1], DT_SIGNED | DT_FLOAT, 16, 8.0 ), + DEFINE_DELTA( mins[2], DT_SIGNED | DT_FLOAT, 16, 8.0 ), + DEFINE_DELTA( maxs[0], DT_SIGNED | DT_FLOAT, 16, 8.0 ), + DEFINE_DELTA( maxs[1], DT_SIGNED | DT_FLOAT, 16, 8.0 ), + DEFINE_DELTA( maxs[2], DT_SIGNED | DT_FLOAT, 16, 8.0 ), + DEFINE_DELTA( weaponmodel, DT_INTEGER, 10, 1.0 ), + DEFINE_DELTA( team, DT_INTEGER, 4, 1.0 ) + DEFINE_DELTA( playerclass, DT_INTEGER, 4, 1.0 ) + DEFINE_DELTA( owner, DT_INTEGER, 5, 1.0 ), + DEFINE_DELTA( effects, DT_INTEGER, 8, 1.0 ), + DEFINE_DELTA( angles[2], DT_ANGLE, 16, 1.0 ), + DEFINE_DELTA( colormap, DT_INTEGER, 16, 1.0 ), + DEFINE_DELTA( framerate, DT_SIGNED | DT_FLOAT, 8, 16.0 ), + DEFINE_DELTA( skin, DT_SHORT | DT_SIGNED, 9, 1.0 ), + DEFINE_DELTA( controller[0], DT_BYTE, 8, 1.0 ), + DEFINE_DELTA( controller[1], DT_BYTE, 8, 1.0 ), + DEFINE_DELTA( controller[2], DT_BYTE, 8, 1.0 ), + DEFINE_DELTA( controller[3], DT_BYTE, 8, 1.0 ), + DEFINE_DELTA( blending[0], DT_BYTE, 8, 1.0 ), + DEFINE_DELTA( blending[1], DT_BYTE, 8, 1.0 ), + DEFINE_DELTA( body, DT_INTEGER, 8, 1.0 ), + DEFINE_DELTA( rendermode, DT_INTEGER, 8, 1.0 ), + DEFINE_DELTA( renderamt, DT_INTEGER, 8, 1.0 ), + DEFINE_DELTA( renderfx, DT_INTEGER, 8, 1.0 ), + DEFINE_DELTA( scale, DT_FLOAT, 16, 256.0 ), + DEFINE_DELTA( rendercolor.r, DT_BYTE, 8, 1.0 ), + DEFINE_DELTA( rendercolor.g, DT_BYTE, 8, 1.0 ), + DEFINE_DELTA( rendercolor.b, DT_BYTE, 8, 1.0 ), + DEFINE_DELTA( friction, DT_SIGNED | DT_FLOAT, 16, 8.0 ), + DEFINE_DELTA( usehull, DT_INTEGER, 1, 1.0 ), + DEFINE_DELTA( gravity, DT_SIGNED | DT_FLOAT, 16, 32.0 ), + DEFINE_DELTA( aiment, DT_INTEGER, 11, 1.0 ), + DEFINE_DELTA( basevelocity[0], DT_SIGNED | DT_FLOAT, 16, 8.0 ), + DEFINE_DELTA( basevelocity[1], DT_SIGNED | DT_FLOAT, 16, 8.0 ), + DEFINE_DELTA( basevelocity[2], DT_SIGNED | DT_FLOAT, 16, 8.0 ), + DEFINE_DELTA( spectator, DT_INTEGER, 1, 1.0 ) +} + +custom_entity_state_t gamedll Custom_Encode +{ + DEFINE_DELTA( rendermode, DT_INTEGER, 8, 1.0 ), + DEFINE_DELTA( origin[0], DT_SIGNED | DT_FLOAT, 17, 8.0 ), + DEFINE_DELTA( origin[1], DT_SIGNED | DT_FLOAT, 17, 8.0 ), + DEFINE_DELTA( origin[2], DT_SIGNED | DT_FLOAT, 17, 8.0 ), + DEFINE_DELTA( angles[0], DT_SIGNED | DT_FLOAT, 17, 8.0 ), + DEFINE_DELTA( angles[1], DT_SIGNED | DT_FLOAT, 17, 8.0 ), + DEFINE_DELTA( angles[2], DT_SIGNED | DT_FLOAT, 17, 8.0 ), + DEFINE_DELTA( sequence, DT_INTEGER, 16, 1.0 ), + DEFINE_DELTA( skin, DT_INTEGER, 16, 1.0 ), + DEFINE_DELTA( modelindex, DT_INTEGER, 16, 1.0 ), + DEFINE_DELTA_POST( scale, DT_FLOAT, 8, 1.0, 0.1 ), + DEFINE_DELTA( body, DT_INTEGER, 8, 1.0 ), + DEFINE_DELTA( rendercolor.r, DT_BYTE, 8, 1.0 ), + DEFINE_DELTA( rendercolor.g, DT_BYTE, 8, 1.0 ), + DEFINE_DELTA( rendercolor.b, DT_BYTE, 8, 1.0 ), + DEFINE_DELTA( renderfx, DT_INTEGER, 8, 1.0 ), + DEFINE_DELTA( renderamt, DT_INTEGER, 8, 1.0 ), + DEFINE_DELTA( frame, DT_FLOAT, 8, 1.0 ), + DEFINE_DELTA_POST( animtime, DT_FLOAT, 8, 1.0, 0.1 ) +} + +usercmd_t none +{ + DEFINE_DELTA( lerp_msec, DT_SHORT, 9, 1.0 ), + DEFINE_DELTA( msec, DT_BYTE, 8, 1.0 ), + DEFINE_DELTA( viewangles[1], DT_ANGLE, 16, 1.0 ), + DEFINE_DELTA( viewangles[0], DT_ANGLE, 16, 1.0 ), + DEFINE_DELTA( buttons, DT_SHORT, 16, 1.0 ), + DEFINE_DELTA( forwardmove, DT_SIGNED | DT_FLOAT, 12, 1.0 ), + DEFINE_DELTA( lightlevel, DT_BYTE, 8, 1.0 ), + DEFINE_DELTA( sidemove, DT_SIGNED | DT_FLOAT, 12, 1.0 ), + DEFINE_DELTA( upmove, DT_SIGNED | DT_FLOAT, 12, 1.0 ), + DEFINE_DELTA( impulse, DT_BYTE, 8, 1.0 ), + DEFINE_DELTA( viewangles[2], DT_ANGLE, 16, 1.0 ), + DEFINE_DELTA( impact_index, DT_INTEGER, 6, 1.0 ), + DEFINE_DELTA( impact_position[0], DT_SIGNED | DT_FLOAT, 16, 8.0 ), + DEFINE_DELTA( impact_position[1], DT_SIGNED | DT_FLOAT, 16, 8.0 ), + DEFINE_DELTA( impact_position[2], DT_SIGNED | DT_FLOAT, 16, 8.0 ) +} + +weapon_data_t none +{ + DEFINE_DELTA( m_flTimeWeaponIdle, DT_FLOAT | DT_SIGNED, 22, 1000.0 ), + DEFINE_DELTA( m_flNextPrimaryAttack, DT_FLOAT | DT_SIGNED, 22, 1000.0 ), + DEFINE_DELTA( m_flNextReload, DT_FLOAT | DT_SIGNED, 22, 1000.0 ), + DEFINE_DELTA( m_fNextAimBonus, DT_FLOAT | DT_SIGNED, 22, 1000.0 ), + DEFINE_DELTA( m_flNextSecondaryAttack, DT_FLOAT | DT_SIGNED, 22, 1000.0 ), + DEFINE_DELTA( m_iClip, DT_SIGNED | DT_INTEGER, 10, 1.0 ), + DEFINE_DELTA( m_flPumpTime, DT_FLOAT | DT_SIGNED, 22, 1000.0 ), + DEFINE_DELTA( m_fInSpecialReload, DT_INTEGER, 2, 1.0 ), + DEFINE_DELTA( m_fReloadTime, DT_FLOAT, 16, 100.0 ), + DEFINE_DELTA( m_fInReload, DT_INTEGER, 1, 1.0 ), + DEFINE_DELTA( m_fAimedDamage, DT_FLOAT, 6, 0.1 ), + DEFINE_DELTA( m_fInZoom, DT_INTEGER, 1, 1.0 ), + DEFINE_DELTA( m_iWeaponState, DT_INTEGER, 2, 1.0 ), + DEFINE_DELTA( m_iId, DT_INTEGER, 5, 1.0 ) +} + +event_t none +{ + DEFINE_DELTA( entindex, DT_INTEGER, 10, 1.0 ), + DEFINE_DELTA( bparam1, DT_INTEGER, 1, 1.0 ), + DEFINE_DELTA( bparam2, DT_INTEGER, 1, 1.0 ), + DEFINE_DELTA( origin[0], DT_SIGNED | DT_FLOAT, 16, 8.0 ), + DEFINE_DELTA( origin[1], DT_SIGNED | DT_FLOAT, 16, 8.0 ), + DEFINE_DELTA( origin[2], DT_SIGNED | DT_FLOAT, 16, 8.0 ), + DEFINE_DELTA( fparam1, DT_FLOAT | DT_SIGNED, 20, 100.0 ), + DEFINE_DELTA( fparam2, DT_FLOAT | DT_SIGNED, 20, 100.0 ), + DEFINE_DELTA( iparam1, DT_INTEGER | DT_SIGNED, 16, 1.0 ), + DEFINE_DELTA( iparam2, DT_INTEGER | DT_SIGNED, 16, 1.0 ), + DEFINE_DELTA( angles[0], DT_SIGNED | DT_FLOAT, 16, 8.0 ), + DEFINE_DELTA( angles[1], DT_SIGNED | DT_FLOAT, 16, 8.0 ), + DEFINE_DELTA( angles[2], DT_SIGNED | DT_FLOAT, 16, 8.0 ), + DEFINE_DELTA( ducking, DT_INTEGER, 1, 1.0 ) +} \ No newline at end of file diff --git a/cl_dll/MOTD.cpp b/cl_dll/MOTD.cpp deleted file mode 100644 index 903a914..0000000 --- a/cl_dll/MOTD.cpp +++ /dev/null @@ -1,141 +0,0 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -// -// MOTD.cpp -// -// for displaying a server-sent message of the day -// - -#include "hud.h" -#include "util.h" -#include "parsemsg.h" - -#include -#include - -DECLARE_MESSAGE( m_MOTD, MOTD ); - -int CHudMOTD::MOTD_DISPLAY_TIME; - -int CHudMOTD :: Init( void ) -{ - gHUD.AddHudElem( this ); - - HOOK_MESSAGE( MOTD ); - - CVAR_CREATE( "motd_display_time", "6", 0 ); - - m_iFlags &= ~HUD_ACTIVE; // start out inactive - m_szMOTD[0] = 0; - - return 1; -} - -int CHudMOTD :: VidInit( void ) -{ - // Load sprites here - - return 1; -} - -void CHudMOTD :: Reset( void ) -{ - m_iFlags &= ~HUD_ACTIVE; // start out inactive - m_szMOTD[0] = 0; - m_iLines = 0; - m_flActiveTill = 0; -} - -#define LINE_HEIGHT 13 - -int CHudMOTD :: Draw( float fTime ) -{ - // Draw MOTD line-by-line - - if ( m_flActiveTill < gHUD.m_flTime ) - { // finished with MOTD, disable it - m_szMOTD[0] = 0; - m_iLines = 0; - m_iFlags &= ~HUD_ACTIVE; - return 1; - } - - // cap activetill time to the display time - m_flActiveTill = min( gHUD.m_flTime + MOTD_DISPLAY_TIME, m_flActiveTill ); - - // find the top of where the MOTD should be drawn, so the whole thing is centered in the screen - int ypos = max(((ScreenHeight - (m_iLines * LINE_HEIGHT)) / 2) - 40, 30 ); // shift it up slightly - char *ch = m_szMOTD; - while ( *ch ) - { - int line_length = 0; // count the length of the current line - for ( char *next_line = ch; *next_line != '\n' && *next_line != 0; next_line++ ) - line_length += gHUD.m_scrinfo.charWidths[ *next_line ]; - char *top = next_line; - if ( *top == '\n' ) - *top = 0; - else - top = NULL; - - // find where to start drawing the line - int xpos = (ScreenWidth - line_length) / 2; - - gHUD.DrawHudString( xpos, ypos, ScreenWidth, ch, 255, 180, 0 ); - - ypos += LINE_HEIGHT; - - if ( top ) // restore - *top = '\n'; - ch = next_line; - if ( *ch == '\n' ) - ch++; - - if ( ypos > (ScreenHeight - 20) ) - break; // don't let it draw too low - } - - return 1; -} - -int CHudMOTD :: MsgFunc_MOTD( const char *pszName, int iSize, void *pbuf ) -{ - if ( m_iFlags & HUD_ACTIVE ) - { - Reset(); // clear the current MOTD in prep for this one - } - - BEGIN_READ( pbuf, iSize ); - - int is_finished = READ_BYTE(); - strcat( m_szMOTD, READ_STRING() ); - - if ( is_finished ) - { - m_iFlags |= HUD_ACTIVE; - - MOTD_DISPLAY_TIME = CVAR_GET_FLOAT( "motd_display_time" ); - - m_flActiveTill = gHUD.m_flTime + MOTD_DISPLAY_TIME; - - for ( char *sz = m_szMOTD; *sz != 0; sz++ ) // count the number of lines in the MOTD - { - if ( *sz == '\n' ) - m_iLines++; - } - } - - return 1; -} - diff --git a/cl_dll/ammo.cpp b/cl_dll/ammo.cpp index f08f155..ef796d3 100644 --- a/cl_dll/ammo.cpp +++ b/cl_dll/ammo.cpp @@ -19,13 +19,14 @@ // #include "hud.h" -#include "util.h" +#include "cl_util.h" #include "parsemsg.h" #include #include #include "ammohistory.h" +#include "vgui_TeamFortressViewport.h" WEAPON *gpActiveSel; // NULL means off, 1 means just the menu bar, otherwise // this points to the active weapon menu item @@ -35,6 +36,8 @@ client_sprite_t *GetSpriteList(client_sprite_t *pList, const char *psz, int iRes WeaponsResource gWR; +int g_weaponselect = 0; + void WeaponsResource :: LoadAllWeaponSprites( void ) { for (int i = 0; i < MAX_WEAPONS; i++) @@ -372,7 +375,10 @@ void CHudAmmo::Think(void) if (gHUD.m_iKeyBits & IN_ATTACK) { if (gpActiveSel != (WEAPON *)1) + { ServerCmd(gpActiveSel->szName); + g_weaponselect = gpActiveSel->iId; + } gpLastSel = gpActiveSel; gpActiveSel = NULL; @@ -430,13 +436,14 @@ void WeaponsResource :: SelectSlot( int iSlot, int fAdvance, int iDirection ) return; WEAPON *p = NULL; + bool fastSwitch = CVAR_GET_FLOAT( "hud_fastswitch" ) != 0; if ( (gpActiveSel == NULL) || (gpActiveSel == (WEAPON *)1) || (iSlot != gpActiveSel->iSlot) ) { PlaySound( "common/wpn_hudon.wav", 1 ); p = GetFirstPos( iSlot ); - if ( p && CVAR_GET_FLOAT( "hud_fastswitch" ) > 0 ) // check for fast weapon switch mode + if ( p && fastSwitch ) // check for fast weapon switch mode { // if fast weapon switch is on, then weapons can be selected in a single keypress // but only if there is only one item in the bucket @@ -444,6 +451,7 @@ void WeaponsResource :: SelectSlot( int iSlot, int fAdvance, int iDirection ) if ( !p2 ) { // only one active item in bucket, so change directly to weapon ServerCmd( p->szName ); + g_weaponselect = p->iId; return; } } @@ -458,13 +466,18 @@ void WeaponsResource :: SelectSlot( int iSlot, int fAdvance, int iDirection ) } - if ( !p ) // if no selection found, just display the weapon list - gpActiveSel = (WEAPON *)1; + if ( !p ) // no selection found + { + // just display the weapon list, unless fastswitch is on just ignore it + if ( !fastSwitch ) + gpActiveSel = (WEAPON *)1; + else + gpActiveSel = NULL; + } else gpActiveSel = p; } - //------------------------------------------------------------------------ // Message Handlers //------------------------------------------------------------------------ @@ -653,55 +666,64 @@ int CHudAmmo::MsgFunc_WeaponList(const char *pszName, int iSize, void *pbuf ) //------------------------------------------------------------------------ // Command Handlers //------------------------------------------------------------------------ +// Slot button pressed +void CHudAmmo::SlotInput( int iSlot ) +{ + // Let the Viewport use it first, for menus + if ( gViewPort && gViewPort->SlotInput( iSlot ) ) + return; + + gWR.SelectSlot(iSlot, FALSE, 1); +} void CHudAmmo::UserCmd_Slot1(void) { - gWR.SelectSlot(0, FALSE, 1); + SlotInput( 0 ); } void CHudAmmo::UserCmd_Slot2(void) { - gWR.SelectSlot(1, FALSE, 1); + SlotInput( 1 ); } void CHudAmmo::UserCmd_Slot3(void) { - gWR.SelectSlot(2, FALSE, 1); + SlotInput( 2 ); } void CHudAmmo::UserCmd_Slot4(void) { - gWR.SelectSlot(3, FALSE, 1); + SlotInput( 3 ); } void CHudAmmo::UserCmd_Slot5(void) { - gWR.SelectSlot(4, FALSE, 1); + SlotInput( 4 ); } void CHudAmmo::UserCmd_Slot6(void) { - gWR.SelectSlot(5, FALSE, 1); + SlotInput( 5 ); } void CHudAmmo::UserCmd_Slot7(void) { - gWR.SelectSlot(6, FALSE, 1); + SlotInput( 6 ); } void CHudAmmo::UserCmd_Slot8(void) { - gWR.SelectSlot(7, FALSE, 1); + SlotInput( 7 ); } void CHudAmmo::UserCmd_Slot9(void) { - gWR.SelectSlot(8, FALSE, 1); + SlotInput( 8 ); } void CHudAmmo::UserCmd_Slot10(void) { - gWR.SelectSlot(9, FALSE, 1); + SlotInput( 9 ); } void CHudAmmo::UserCmd_Close(void) diff --git a/cl_dll/ammo_secondary.cpp b/cl_dll/ammo_secondary.cpp index fdfefdf..c616373 100644 --- a/cl_dll/ammo_secondary.cpp +++ b/cl_dll/ammo_secondary.cpp @@ -19,7 +19,7 @@ // #include "hud.h" -#include "util.h" +#include "cl_util.h" #include #include #include "parsemsg.h" diff --git a/cl_dll/ammohistory.cpp b/cl_dll/ammohistory.cpp index 69130fd..dd6138e 100644 --- a/cl_dll/ammohistory.cpp +++ b/cl_dll/ammohistory.cpp @@ -18,7 +18,7 @@ #include "hud.h" -#include "util.h" +#include "cl_util.h" #include "parsemsg.h" #include diff --git a/cl_dll/ammohistory.h b/cl_dll/ammohistory.h index 2d61045..1a18179 100644 --- a/cl_dll/ammohistory.h +++ b/cl_dll/ammohistory.h @@ -90,7 +90,6 @@ public: int CountAmmo( int iId ); HSPRITE* GetAmmoPicFromWeapon( int iAmmoId, wrect_t& rect ); - }; extern WeaponsResource gWR; diff --git a/cl_dll/battery.cpp b/cl_dll/battery.cpp index c09128a..22dce33 100644 --- a/cl_dll/battery.cpp +++ b/cl_dll/battery.cpp @@ -19,7 +19,7 @@ // #include "hud.h" -#include "util.h" +#include "cl_util.h" #include "parsemsg.h" #include diff --git a/cl_dll/camera.h b/cl_dll/camera.h new file mode 100644 index 0000000..7b7cd01 --- /dev/null +++ b/cl_dll/camera.h @@ -0,0 +1,17 @@ +// Camera.h -- defines and such for a 3rd person camera +// NOTE: must include quakedef.h first + +#ifndef _CAMERA_H_ +#define _CAMEA_H_ + +// pitch, yaw, dist +extern vec3_t cam_ofs; +// Using third person camera +extern int cam_thirdperson; + +void CAM_Init( void ); +void CAM_ClearStates( void ); +void CAM_StartMouseMove(void); +void CAM_EndMouseMove(void); + +#endif // _CAMERA_H_ diff --git a/cl_dll/cdll_int.cpp b/cl_dll/cdll_int.cpp index 4781344..1070888 100644 --- a/cl_dll/cdll_int.cpp +++ b/cl_dll/cdll_int.cpp @@ -19,14 +19,28 @@ // #include "hud.h" -#include "util.h" +#include "cl_util.h" +#include "netadr.h" +#include "vgui_schememanager.h" + +extern "C" +{ +#include "pm_shared.h" +} + #include +#include "hud_servers.h" +#include "vgui_int.h" #define DLLEXPORT __declspec( dllexport ) cl_enginefunc_t gEngfuncs; CHud gHUD; +TeamFortressViewport *gViewPort = NULL; +void InitInput (void); +void EV_HookEvents( void ); +void IN_Commands( void ); /* ========================== @@ -43,8 +57,83 @@ int DLLEXPORT HUD_Init( void ); int DLLEXPORT HUD_Redraw( float flTime, int intermission ); int DLLEXPORT HUD_UpdateClientData( client_data_t *cdata, float flTime ); int DLLEXPORT HUD_Reset ( void ); +void DLLEXPORT HUD_PlayerMove( struct playermove_s *ppmove, int server ); +void DLLEXPORT HUD_PlayerMoveInit( struct playermove_s *ppmove ); +char DLLEXPORT HUD_PlayerMoveTexture( char *name ); +int DLLEXPORT HUD_ConnectionlessPacket( struct netadr_s *net_from, const char *args, char *response_buffer, int *response_buffer_size ); +int DLLEXPORT HUD_GetHullBounds( int hullnumber, float *mins, float *maxs ); +void DLLEXPORT HUD_Frame( double time ); } +/* +================================ +HUD_GetHullBounds + + Engine calls this to enumerate player collision hulls, for prediction. Return 0 if the hullnumber doesn't exist. +================================ +*/ +int DLLEXPORT HUD_GetHullBounds( int hullnumber, float *mins, float *maxs ) +{ + int iret = 0; + + switch ( hullnumber ) + { + case 0: // Normal player + mins = Vector(-16, -16, -36); + maxs = Vector(16, 16, 36); + iret = 1; + break; + case 1: // Crouched player + mins = Vector(-16, -16, -18 ); + maxs = Vector(16, 16, 18 ); + iret = 1; + break; + case 2: // Point based hull + mins = Vector( 0, 0, 0 ); + maxs = Vector( 0, 0, 0 ); + iret = 1; + break; + } + + return iret; +} + +/* +================================ +HUD_ConnectionlessPacket + + Return 1 if the packet is valid. Set response_buffer_size if you want to send a response packet. Incoming, it holds the max + size of the response_buffer, so you must zero it out if you choose not to respond. +================================ +*/ +int DLLEXPORT HUD_ConnectionlessPacket( struct netadr_s *net_from, const char *args, char *response_buffer, int *response_buffer_size ) +{ + // Parse stuff from args + int max_buffer_size = *response_buffer_size; + + // Zero it out since we aren't going to respond. + // If we wanted to response, we'd write data into response_buffer + *response_buffer_size = 0; + + // Since we don't listen for anything here, just respond that it's a bogus message + // If we didn't reject the message, we'd return 1 for success instead. + return 0; +} + +void DLLEXPORT HUD_PlayerMoveInit( struct playermove_s *ppmove ) +{ + PM_Init( ppmove ); +} + +char DLLEXPORT HUD_PlayerMoveTexture( char *name ) +{ + return PM_FindTextureType( name ); +} + +void DLLEXPORT HUD_PlayerMove( struct playermove_s *ppmove, int server ) +{ + PM_Move( ppmove, server ); +} int DLLEXPORT Initialize( cl_enginefunc_t *pEnginefuncs, int iVersion ) { @@ -59,6 +148,8 @@ int DLLEXPORT Initialize( cl_enginefunc_t *pEnginefuncs, int iVersion ) memcpy(&gEngfuncs, pEnginefuncs, sizeof(cl_enginefunc_t)); + EV_HookEvents(); + return 1; } @@ -76,6 +167,9 @@ so the HUD can reinitialize itself. int DLLEXPORT HUD_VidInit( void ) { gHUD.VidInit(); + + VGui_Startup(); + return 1; } @@ -91,7 +185,9 @@ the hud variables. int DLLEXPORT HUD_Init( void ) { + InitInput(); gHUD.Init(); + Scheme_Init(); return 1; } @@ -129,6 +225,8 @@ returns 1 if anything has been changed, 0 otherwise. int DLLEXPORT HUD_UpdateClientData(client_data_t *pcldata, float flTime ) { + IN_Commands(); + return gHUD.UpdateClientData(pcldata, flTime ); } @@ -144,4 +242,17 @@ int DLLEXPORT HUD_Reset( void ) { gHUD.VidInit(); return 1; +} + +/* +========================== +HUD_Frame + +Called by engine every frame that client .dll is loaded +========================== +*/ + +void DLLEXPORT HUD_Frame( double time ) +{ + ServersThink( time ); } \ No newline at end of file diff --git a/cl_dll/cl_dll.dsp b/cl_dll/cl_dll.dsp index 0a60106..0c84ef6 100644 --- a/cl_dll/cl_dll.dsp +++ b/cl_dll/cl_dll.dsp @@ -40,9 +40,10 @@ RSC=rc.exe # PROP Use_Debug_Libraries 0 # PROP Output_Dir ".\Release" # PROP Intermediate_Dir ".\Release" +# 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 /MT /W3 /GX /Zi /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /Zi /O2 /I "..\engine" /I "..\common" /I "..\pm_shared" /I "..\utils\vgui\include" /I "..\dlls" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c # ADD BASE MTL /nologo /D "NDEBUG" /win32 # ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 # ADD BASE RSC /l 0x409 /d "NDEBUG" @@ -52,14 +53,14 @@ 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 /dll /machine:I386 -# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib /nologo /subsystem:windows /dll /map /machine:I386 /out:".\Release\client.dll" -# Begin Custom Build - Copying to \half-life\mp\cl_dlls +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib winmm.lib ../utils/vgui/lib/win32_vc6/vgui.lib wsock32.lib /nologo /subsystem:windows /dll /map /machine:I386 /out:".\Release\client.dll" +# Begin Custom Build - Copying to \quiver\valve\cl_dlls TargetDir=.\Release InputPath=.\Release\client.dll SOURCE="$(InputPath)" -"\half-life\mp\cl_dlls\client.dll" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" - copy $(TargetDir)\client.dll \half-life\mp\cl_dlls +"\quiver\valve\cl_dlls\client.dll" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + copy $(TargetDir)\client.dll \quiver\valve\cl_dlls # End Custom Build @@ -74,9 +75,10 @@ SOURCE="$(InputPath)" # PROP Use_Debug_Libraries 1 # PROP Output_Dir ".\Debug" # PROP Intermediate_Dir ".\Debug" +# 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 /G5 /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /FR /YX /FD /c +# ADD CPP /nologo /G5 /MTd /W3 /Gm /GX /ZI /Od /I "..\engine" /I "..\common" /I "..\pm_shared" /I "..\utils\vgui\include" /I "..\dlls" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /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" @@ -86,7 +88,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 /dll /debug /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 /nologo /subsystem:windows /dll /debug /machine:I386 /out:".\Debug\client.dll" +# ADD LINK32 oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib winmm.lib ../utils/vgui/lib/win32_vc6/vgui.lib wsock32.lib /nologo /subsystem:windows /dll /debug /machine:I386 /out:".\Debug\client.dll" # Begin Custom Build - Copying to \half-life\mp\cl_dlls TargetDir=.\Debug InputPath=.\Debug\client.dll @@ -106,6 +108,34 @@ SOURCE="$(InputPath)" # Begin Group "Source Files" # PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat;for;f90" +# Begin Group "hl" + +# PROP Default_Filter "*.cpp" +# Begin Source File + +SOURCE=.\ev_hldm.cpp +# End Source File +# Begin Source File + +SOURCE=.\hl\hl_baseentity.cpp +# End Source File +# Begin Source File + +SOURCE=.\hl\hl_events.cpp +# End Source File +# Begin Source File + +SOURCE=.\hl\hl_objects.cpp +# End Source File +# Begin Source File + +SOURCE=.\hl\hl_weapons.cpp +# End Source File +# Begin Source File + +SOURCE=..\dlls\wpn_shared\hl_wpn_glock.cpp +# End Source File +# End Group # Begin Source File SOURCE=.\ammo.cpp @@ -128,10 +158,30 @@ SOURCE=.\cdll_int.cpp # End Source File # Begin Source File +SOURCE=.\com_weapons.cpp +# End Source File +# Begin Source File + SOURCE=.\death.cpp # End Source File # Begin Source File +SOURCE=.\demo.cpp +# End Source File +# Begin Source File + +SOURCE=.\entity.cpp +# End Source File +# Begin Source File + +SOURCE=.\ev_common.cpp +# End Source File +# Begin Source File + +SOURCE=.\events.cpp +# End Source File +# Begin Source File + SOURCE=.\flashlight.cpp # End Source File # Begin Source File @@ -156,10 +206,26 @@ SOURCE=.\hud_redraw.cpp # End Source File # Begin Source File +SOURCE=.\hud_servers.cpp +# End Source File +# Begin Source File + SOURCE=.\hud_update.cpp # End Source File # Begin Source File +SOURCE=.\in_camera.cpp +# End Source File +# Begin Source File + +SOURCE=.\input.cpp +# End Source File +# Begin Source File + +SOURCE=.\inputw32.cpp +# End Source File +# Begin Source File + SOURCE=.\menu.cpp # End Source File # Begin Source File @@ -168,10 +234,6 @@ SOURCE=.\message.cpp # End Source File # Begin Source File -SOURCE=.\MOTD.cpp -# End Source File -# Begin Source File - SOURCE=.\parsemsg.cpp # End Source File # Begin Source File @@ -180,11 +242,19 @@ SOURCE=.\parsemsg.h # End Source File # Begin Source File -SOURCE=.\saytext.cpp +SOURCE=..\pm_shared\pm_debug.c # End Source File # Begin Source File -SOURCE=.\scoreboard.cpp +SOURCE=..\pm_shared\pm_math.c +# End Source File +# Begin Source File + +SOURCE=..\pm_shared\pm_shared.c +# End Source File +# Begin Source File + +SOURCE=.\saytext.cpp # End Source File # Begin Source File @@ -204,8 +274,60 @@ SOURCE=.\train.cpp # End Source File # Begin Source File +SOURCE=.\tri.cpp +# End Source File +# Begin Source File + SOURCE=.\util.cpp # End Source File +# Begin Source File + +SOURCE=.\vgui_ClassMenu.cpp +# End Source File +# Begin Source File + +SOURCE=.\vgui_ConsolePanel.cpp +# End Source File +# Begin Source File + +SOURCE=.\vgui_ControlConfigPanel.cpp +# End Source File +# Begin Source File + +SOURCE=.\vgui_CustomObjects.cpp +# End Source File +# Begin Source File + +SOURCE=.\vgui_int.cpp +# End Source File +# Begin Source File + +SOURCE=.\vgui_MOTDWindow.cpp +# End Source File +# Begin Source File + +SOURCE=.\vgui_SchemeManager.cpp +# End Source File +# Begin Source File + +SOURCE=.\vgui_ScorePanel.cpp +# End Source File +# Begin Source File + +SOURCE=.\vgui_ServerBrowser.cpp +# End Source File +# Begin Source File + +SOURCE=.\vgui_TeamFortressViewport.cpp +# End Source File +# Begin Source File + +SOURCE=.\vgui_teammenu.cpp +# End Source File +# Begin Source File + +SOURCE=.\view.cpp +# End Source File # End Group # Begin Group "Header Files" @@ -220,10 +342,30 @@ SOURCE=.\ammohistory.h # End Source File # Begin Source File +SOURCE=.\camera.h +# End Source File +# Begin Source File + SOURCE=.\cl_dll.h # End Source File # Begin Source File +SOURCE=.\com_weapons.h +# End Source File +# Begin Source File + +SOURCE=.\demo.h +# End Source File +# Begin Source File + +SOURCE=.\ev_hldm.h +# End Source File +# Begin Source File + +SOURCE=.\eventscripts.h +# End Source File +# Begin Source File + SOURCE=.\health.h # End Source File # Begin Source File @@ -232,12 +374,92 @@ SOURCE=.\hud.h # End Source File # Begin Source File +SOURCE=.\hud_iface.h +# End Source File +# Begin Source File + +SOURCE=.\hud_servers.h +# End Source File +# Begin Source File + +SOURCE=.\hud_servers_priv.h +# End Source File +# Begin Source File + +SOURCE=.\in_defs.h +# End Source File +# Begin Source File + +SOURCE=.\kbutton.h +# End Source File +# Begin Source File + +SOURCE=..\pm_shared\pm_debug.h +# End Source File +# Begin Source File + +SOURCE=..\pm_shared\pm_defs.h +# End Source File +# Begin Source File + +SOURCE=..\pm_shared\pm_info.h +# End Source File +# Begin Source File + +SOURCE=..\pm_shared\pm_materials.h +# End Source File +# Begin Source File + +SOURCE=..\pm_shared\pm_movevars.h +# End Source File +# Begin Source File + +SOURCE=..\pm_shared\pm_shared.h +# End Source File +# Begin Source File + SOURCE=.\util.h # End Source File # Begin Source File SOURCE=.\util_vector.h # End Source File +# Begin Source File + +SOURCE=.\vgui_ConsolePanel.h +# End Source File +# Begin Source File + +SOURCE=.\vgui_ControlConfigPanel.h +# End Source File +# Begin Source File + +SOURCE=.\vgui_int.h +# End Source File +# Begin Source File + +SOURCE=.\vgui_SchemeManager.h +# End Source File +# Begin Source File + +SOURCE=.\vgui_ScorePanel.h +# End Source File +# Begin Source File + +SOURCE=.\vgui_ServerBrowser.h +# End Source File +# Begin Source File + +SOURCE=.\vgui_TeamFortressViewport.h +# End Source File +# Begin Source File + +SOURCE=.\view.h +# End Source File +# Begin Source File + +SOURCE=.\wrect.h +# End Source File # End Group # Begin Group "Resource Files" diff --git a/cl_dll/cl_dll.dsw b/cl_dll/cl_dll.dsw index b4d58e9..2a9dcfb 100644 --- a/cl_dll/cl_dll.dsw +++ b/cl_dll/cl_dll.dsw @@ -8,7 +8,7 @@ Project: "cl_dll"=.\cl_dll.dsp - Package Owner=<4> Package=<5> {{{ begin source code control - "$/GoldSrc/cl_dll", HGEBAAAA + "$/HLStandardSDK/SourceCode/cl_dll", NUWHAAAA . end source code control }}} @@ -23,10 +23,6 @@ Global: Package=<5> {{{ - begin source code control - "$/GoldSrc/cl_dll", HGEBAAAA - . - end source code control }}} Package=<3> diff --git a/cl_dll/util.h b/cl_dll/cl_util.h similarity index 87% rename from cl_dll/util.h rename to cl_dll/cl_util.h index 2cda99d..4d48c80 100644 --- a/cl_dll/util.h +++ b/cl_dll/cl_util.h @@ -13,12 +13,15 @@ * ****/ // -// util.h +// cl_util.h // -#include +#include "cvardef.h" -#include "../engine/cvardef.h" +#ifndef TRUE +#define TRUE 1 +#define FALSE 0 +#endif // Macros to hook function calls into the HUD object #define HOOK_MESSAGE(x) gEngfuncs.pfnHookUserMsg(#x, __MsgFunc_##x ); @@ -37,7 +40,7 @@ inline float CVAR_GET_FLOAT( const char *x ) { return gEngfuncs.pfnGetCvarFloat( (char*)x ); } inline char* CVAR_GET_STRING( const char *x ) { return gEngfuncs.pfnGetCvarString( (char*)x ); } -inline void CVAR_CREATE( const char *cv, const char *val, const int flags ) { gEngfuncs.pfnRegisterVariable( (char*)cv, (char*)val, flags ); } +inline struct cvar_s *CVAR_CREATE( const char *cv, const char *val, const int flags ) { return gEngfuncs.pfnRegisterVariable( (char*)cv, (char*)val, flags ); } #define SPR_Load (*gEngfuncs.pfnSPR_Load) #define SPR_Set (*gEngfuncs.pfnSPR_Set) @@ -125,6 +128,14 @@ void ScaleColors( int &r, int &g, int &b, int a ); #define VectorSubtract(a,b,c) {(c)[0]=(a)[0]-(b)[0];(c)[1]=(a)[1]-(b)[1];(c)[2]=(a)[2]-(b)[2];} #define VectorAdd(a,b,c) {(c)[0]=(a)[0]+(b)[0];(c)[1]=(a)[1]+(b)[1];(c)[2]=(a)[2]+(b)[2];} #define VectorCopy(a,b) {(b)[0]=(a)[0];(b)[1]=(a)[1];(b)[2]=(a)[2];} +#define VectorClear(a) { a[0]=0.0;a[1]=0.0;a[2]=0.0;} +float Length(const float *v); +void VectorMA (const float *veca, float scale, const float *vecb, float *vecc); +void VectorScale (const float *in, float scale, float *out); +float VectorNormalize (float *v); +void VectorInverse ( float *v ); + +extern vec3_t vec3_origin; // disable 'possible loss of data converting float to int' warning message #pragma warning( disable: 4244 ) diff --git a/cl_dll/com_weapons.cpp b/cl_dll/com_weapons.cpp new file mode 100644 index 0000000..1db60f7 --- /dev/null +++ b/cl_dll/com_weapons.cpp @@ -0,0 +1,277 @@ +/*** +* +* Copyright (c) 1999, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ + +// Com_Weapons.cpp +// Shared weapons common/shared functions +#include +#include "hud.h" +#include "cl_util.h" +#include "com_weapons.h" + +#include "const.h" +#include "entity_state.h" +#include "r_efx.h" + +// g_runfuncs is true if this is the first time we've "predicated" a particular movement/firing +// command. If it is 1, then we should play events/sounds etc., otherwise, we just will be +// updating state info, but not firing events +int g_runfuncs = 0; + +// During our weapon prediction processing, we'll need to reference some data that is part of +// the final state passed into the postthink functionality. We'll set this pointer and then +// reset it to NULL as appropriate +struct local_state_s *g_finalstate = NULL; + +/* +==================== +COM_Log + +Log debug messages to file ( appends ) +==================== +*/ +void COM_Log( char *pszFile, char *fmt, ...) +{ + va_list argptr; + char string[1024]; + FILE *fp; + char *pfilename; + + if ( !pszFile ) + { + pfilename = "c:\\hllog.txt"; + } + else + { + pfilename = pszFile; + } + + va_start (argptr,fmt); + vsprintf (string, fmt,argptr); + va_end (argptr); + + fp = fopen( pfilename, "a+t"); + if (fp) + { + fprintf(fp, "%s", string); + fclose(fp); + } +} + +// remember the current animation for the view model, in case we get out of sync with +// server. +static int g_currentanim; + +/* +===================== +HUD_SendWeaponAnim + +Change weapon model animation +===================== +*/ +void HUD_SendWeaponAnim( int iAnim, int body, int force ) +{ + // Don't actually change it. + if ( !g_runfuncs && !force ) + return; + + g_currentanim = iAnim; + + // Tell animation system new info + gEngfuncs.pfnWeaponAnim( iAnim, body ); +} + +/* +===================== +HUD_GetWeaponAnim + +Retrieve current predicted weapon animation +===================== +*/ +int HUD_GetWeaponAnim( void ) +{ + return g_currentanim; +} + +/* +===================== +HUD_PlaySound + +Play a sound, if we are seeing this command for the first time +===================== +*/ +void HUD_PlaySound( char *sound, float volume ) +{ + if ( !g_runfuncs || !g_finalstate ) + return; + + gEngfuncs.pfnPlaySoundByNameAtLocation( sound, volume, (float *)&g_finalstate->playerstate.origin ); +} + +/* +===================== +HUD_PlaybackEvent + +Directly queue up an event on the client +===================== +*/ +void HUD_PlaybackEvent( int flags, const edict_t *pInvoker, unsigned short eventindex, float delay, + float *origin, float *angles, float fparam1, float fparam2, int iparam1, int iparam2, int bparam1, int bparam2 ) +{ + vec3_t org; + vec3_t ang; + + if ( !g_runfuncs || !g_finalstate ) + return; + + // Weapon prediction events are assumed to occur at the player's origin + org = g_finalstate->playerstate.origin; + ang = v_angles; + gEngfuncs.pfnPlaybackEvent( flags, pInvoker, eventindex, delay, (float *)&org, (float *)&ang, fparam1, fparam2, iparam1, iparam2, bparam1, bparam2 ); +} + +/* +===================== +HUD_SetMaxSpeed + +===================== +*/ +void HUD_SetMaxSpeed( const edict_t *ed, float speed ) +{ +} + + +/* +===================== +UTIL_WeaponTimeBase + +Always 0.0 on client, even if not predicting weapons ( won't get called + in that case ) +===================== +*/ +float UTIL_WeaponTimeBase( void ) +{ + return 0.0; +} + +static unsigned int glSeed = 0; + +unsigned int seed_table[ 256 ] = +{ + 28985, 27138, 26457, 9451, 17764, 10909, 28790, 8716, 6361, 4853, 17798, 21977, 19643, 20662, 10834, 20103, + 27067, 28634, 18623, 25849, 8576, 26234, 23887, 18228, 32587, 4836, 3306, 1811, 3035, 24559, 18399, 315, + 26766, 907, 24102, 12370, 9674, 2972, 10472, 16492, 22683, 11529, 27968, 30406, 13213, 2319, 23620, 16823, + 10013, 23772, 21567, 1251, 19579, 20313, 18241, 30130, 8402, 20807, 27354, 7169, 21211, 17293, 5410, 19223, + 10255, 22480, 27388, 9946, 15628, 24389, 17308, 2370, 9530, 31683, 25927, 23567, 11694, 26397, 32602, 15031, + 18255, 17582, 1422, 28835, 23607, 12597, 20602, 10138, 5212, 1252, 10074, 23166, 19823, 31667, 5902, 24630, + 18948, 14330, 14950, 8939, 23540, 21311, 22428, 22391, 3583, 29004, 30498, 18714, 4278, 2437, 22430, 3439, + 28313, 23161, 25396, 13471, 19324, 15287, 2563, 18901, 13103, 16867, 9714, 14322, 15197, 26889, 19372, 26241, + 31925, 14640, 11497, 8941, 10056, 6451, 28656, 10737, 13874, 17356, 8281, 25937, 1661, 4850, 7448, 12744, + 21826, 5477, 10167, 16705, 26897, 8839, 30947, 27978, 27283, 24685, 32298, 3525, 12398, 28726, 9475, 10208, + 617, 13467, 22287, 2376, 6097, 26312, 2974, 9114, 21787, 28010, 4725, 15387, 3274, 10762, 31695, 17320, + 18324, 12441, 16801, 27376, 22464, 7500, 5666, 18144, 15314, 31914, 31627, 6495, 5226, 31203, 2331, 4668, + 12650, 18275, 351, 7268, 31319, 30119, 7600, 2905, 13826, 11343, 13053, 15583, 30055, 31093, 5067, 761, + 9685, 11070, 21369, 27155, 3663, 26542, 20169, 12161, 15411, 30401, 7580, 31784, 8985, 29367, 20989, 14203, + 29694, 21167, 10337, 1706, 28578, 887, 3373, 19477, 14382, 675, 7033, 15111, 26138, 12252, 30996, 21409, + 25678, 18555, 13256, 23316, 22407, 16727, 991, 9236, 5373, 29402, 6117, 15241, 27715, 19291, 19888, 19847 +}; + +unsigned int U_Random( void ) +{ + glSeed *= 69069; + glSeed += seed_table[ glSeed & 0xff ]; + + return ( ++glSeed & 0x0fffffff ); +} + +void U_Srand( unsigned int seed ) +{ + glSeed = seed_table[ seed & 0xff ]; +} + +/* +===================== +UTIL_SharedRandomLong +===================== +*/ +int UTIL_SharedRandomLong( unsigned int seed, int low, int high ) +{ + unsigned int range; + + U_Srand( (int)seed + low + high ); + + range = high - low + 1; + if ( !(range - 1) ) + { + return low; + } + else + { + int offset; + int rnum; + + rnum = U_Random(); + + offset = rnum % range; + + return (low + offset); + } +} + +/* +===================== +UTIL_SharedRandomFloat +===================== +*/ +float UTIL_SharedRandomFloat( unsigned int seed, float low, float high ) +{ + // + unsigned int range; + + U_Srand( (int)seed + *(int *)&low + *(int *)&high ); + + U_Random(); + U_Random(); + + range = high - low; + if ( !range ) + { + return low; + } + else + { + int tensixrand; + float offset; + + tensixrand = U_Random() & 65535; + + offset = (float)tensixrand / 65536.0; + + return (low + offset * range ); + } +} + +/* +====================== +stub_* + +stub functions for such things as precaching. So we don't have to modify weapons code that + is compiled into both game and client .dlls. +====================== +*/ +int stub_PrecacheModel ( char* s ) { return 0; } +int stub_PrecacheSound ( char* s ) { return 0; } +unsigned short stub_PrecacheEvent ( int type, const char *s ) { return 0; } +const char *stub_NameForFunction ( unsigned long function ) { return "func"; } +void stub_SetModel ( edict_t *e, const char *m ) {} diff --git a/cl_dll/com_weapons.h b/cl_dll/com_weapons.h new file mode 100644 index 0000000..ca175b8 --- /dev/null +++ b/cl_dll/com_weapons.h @@ -0,0 +1,41 @@ +// com_weapons.h +// Shared weapons common function prototypes +#if !defined( COM_WEAPONSH ) +#define COM_WEAPONSH +#ifdef _WIN32 +#pragma once +#endif + +#include "hud_iface.h" + +extern "C" +{ + void _DLLEXPORT HUD_PostRunCmd( struct local_state_s *from, struct local_state_s *to, struct usercmd_s *cmd, int runfuncs, double time, unsigned int random_seed ); +} + +void COM_Log( char *pszFile, char *fmt, ...); +int CL_IsDead( void ); + +float UTIL_SharedRandomFloat( unsigned int seed, float low, float high ); +int UTIL_SharedRandomLong( unsigned int seed, int low, int high ); + +int HUD_GetWeaponAnim( void ); +void HUD_SendWeaponAnim( int iAnim, int body, int force ); +void HUD_PlaySound( char *sound, float volume ); +void HUD_PlaybackEvent( int flags, const struct edict_s *pInvoker, unsigned short eventindex, float delay, float *origin, float *angles, float fparam1, float fparam2, int iparam1, int iparam2, int bparam1, int bparam2 ); +void HUD_SetMaxSpeed( const struct edict_s *ed, float speed ); +int stub_PrecacheModel( char* s ); +int stub_PrecacheSound( char* s ); +unsigned short stub_PrecacheEvent( int type, const char *s ); +const char *stub_NameForFunction ( unsigned long function ); +void stub_SetModel ( struct edict_s *e, const char *m ); + + +extern cvar_t *cl_lw; + +extern int g_runfuncs; +extern vec3_t v_angles; +extern float g_lastFOV; +extern struct local_state_s *g_finalstate; + +#endif \ No newline at end of file diff --git a/cl_dll/death.cpp b/cl_dll/death.cpp index 42a4e63..1566725 100644 --- a/cl_dll/death.cpp +++ b/cl_dll/death.cpp @@ -16,22 +16,26 @@ // death notice // #include "hud.h" -#include "util.h" +#include "cl_util.h" #include "parsemsg.h" #include #include +#include "vgui_TeamFortressViewport.h" DECLARE_MESSAGE( m_DeathNotice, DeathMsg ); struct DeathNoticeItem { - char szKiller[MAX_PLAYER_NAME_LENGTH]; - char szVictim[MAX_PLAYER_NAME_LENGTH]; + char szKiller[MAX_PLAYER_NAME_LENGTH*2]; + char szVictim[MAX_PLAYER_NAME_LENGTH*2]; int iId; // the index number of the associated sprite int iSuicide; int iTeamKill; + int iNonPlayerKill; float flDisplayTime; + float *KillerColor; + float *VictimColor; }; #define MAX_DEATHNOTICES 4 @@ -41,6 +45,23 @@ static int DEATHNOTICE_DISPLAY_TIME = 6; DeathNoticeItem rgDeathNoticeList[ MAX_DEATHNOTICES + 1 ]; +float g_ColorBlue[3] = { 0.6, 0.8, 1.0 }; +float g_ColorRed[3] = { 1.0, 0.25, 0.25 }; +float g_ColorGreen[3] = { 0.6, 1.0, 0.6 }; +float g_ColorYellow[3] = { 1.0, 0.7, 0.0 }; + +float *GetClientColor( int clientIndex ) +{ + switch ( g_PlayerExtraInfo[clientIndex].teamnumber ) + { + case 1: return g_ColorBlue; + case 2: return g_ColorRed; + case 3: return g_ColorYellow; + case 4: return g_ColorGreen; + } + + return NULL; +} int CHudDeathNotice :: Init( void ) { @@ -86,35 +107,45 @@ int CHudDeathNotice :: Draw( float flTime ) rgDeathNoticeList[i].flDisplayTime = min( rgDeathNoticeList[i].flDisplayTime, gHUD.m_flTime + DEATHNOTICE_DISPLAY_TIME ); - // Draw the death notice - - y = DEATHNOTICE_TOP + (20 * i); //!!! - - int id = (rgDeathNoticeList[i].iId == -1) ? m_HUD_d_skull : rgDeathNoticeList[i].iId; - x = ScreenWidth - ConsoleStringLen(rgDeathNoticeList[i].szVictim) - (gHUD.GetSpriteRect(id).right - gHUD.GetSpriteRect(id).left); - - if ( !rgDeathNoticeList[i].iSuicide ) + // Only draw if the viewport will let me + if ( gViewPort && gViewPort->AllowedToPrintText() ) { - x -= (5 + ConsoleStringLen( rgDeathNoticeList[i].szKiller ) ); + // Draw the death notice + y = DEATHNOTICE_TOP + (20 * i); //!!! - // Draw killers name - x = 5 + DrawConsoleString( x, y, rgDeathNoticeList[i].szKiller ); + int id = (rgDeathNoticeList[i].iId == -1) ? m_HUD_d_skull : rgDeathNoticeList[i].iId; + x = ScreenWidth - ConsoleStringLen(rgDeathNoticeList[i].szVictim) - (gHUD.GetSpriteRect(id).right - gHUD.GetSpriteRect(id).left); + + if ( !rgDeathNoticeList[i].iSuicide ) + { + x -= (5 + ConsoleStringLen( rgDeathNoticeList[i].szKiller ) ); + + // Draw killers name + if ( rgDeathNoticeList[i].KillerColor ) + gEngfuncs.pfnDrawSetTextColor( rgDeathNoticeList[i].KillerColor[0], rgDeathNoticeList[i].KillerColor[1], rgDeathNoticeList[i].KillerColor[2] ); + x = 5 + DrawConsoleString( x, y, rgDeathNoticeList[i].szKiller ); + } + + r = 255; g = 80; b = 0; + if ( rgDeathNoticeList[i].iTeamKill ) + { + r = 10; g = 240; b = 10; // display it in sickly green + } + + // Draw death weapon + SPR_Set( gHUD.GetSprite(id), r, g, b ); + SPR_DrawAdditive( 0, x, y, &gHUD.GetSpriteRect(id) ); + + x += (gHUD.GetSpriteRect(id).right - gHUD.GetSpriteRect(id).left); + + // Draw victims name (if it was a player that was killed) + if (rgDeathNoticeList[i].iNonPlayerKill == FALSE) + { + if ( rgDeathNoticeList[i].VictimColor ) + gEngfuncs.pfnDrawSetTextColor( rgDeathNoticeList[i].VictimColor[0], rgDeathNoticeList[i].VictimColor[1], rgDeathNoticeList[i].VictimColor[2] ); + x = DrawConsoleString( x, y, rgDeathNoticeList[i].szVictim ); + } } - - r = 255; g = 80; b = 0; - if ( rgDeathNoticeList[i].iTeamKill ) - { - r = 10; g = 240; b = 10; // display it in sickly green - } - - // Draw death weapon - SPR_Set( gHUD.GetSprite(id), r, g, b ); - SPR_DrawAdditive( 0, x, y, &gHUD.GetSpriteRect(id) ); - - x += (gHUD.GetSpriteRect(id).right - gHUD.GetSpriteRect(id).left); - - // Draw victims name - x = DrawConsoleString( x, y, rgDeathNoticeList[i].szVictim ); } return 1; @@ -134,7 +165,8 @@ int CHudDeathNotice :: MsgFunc_DeathMsg( const char *pszName, int iSize, void *p strcpy( killedwith, "d_" ); strncat( killedwith, READ_STRING(), 32 ); - gHUD.m_Scoreboard.DeathMsg( killer, victim ); + if (gViewPort) + gViewPort->DeathMsg( killer, victim ); for ( int i = 0; i < MAX_DEATHNOTICES; i++ ) { @@ -147,23 +179,56 @@ int CHudDeathNotice :: MsgFunc_DeathMsg( const char *pszName, int iSize, void *p i = MAX_DEATHNOTICES - 1; } - gHUD.m_Scoreboard.GetAllPlayersInfo(); + if (gViewPort) + gViewPort->GetAllPlayersInfo(); - char *killer_name = gHUD.m_Scoreboard.m_PlayerInfoList[ killer ].name; - char *victim_name = gHUD.m_Scoreboard.m_PlayerInfoList[ victim ].name; + // Get the Killer's name + char *killer_name = g_PlayerInfoList[ killer ].name; if ( !killer_name ) + { killer_name = ""; + rgDeathNoticeList[i].szKiller[0] = 0; + } + else + { + rgDeathNoticeList[i].KillerColor = GetClientColor( killer ); + strncpy( rgDeathNoticeList[i].szKiller, killer_name, MAX_PLAYER_NAME_LENGTH ); + rgDeathNoticeList[i].szKiller[MAX_PLAYER_NAME_LENGTH-1] = 0; + } + + // Get the Victim's name + char *victim_name = NULL; + // If victim is -1, the killer killed a specific, non-player object (like a sentrygun) + if ( ((char)victim) != -1 ) + victim_name = g_PlayerInfoList[ victim ].name; if ( !victim_name ) + { victim_name = ""; + rgDeathNoticeList[i].szVictim[0] = 0; + } + else + { + rgDeathNoticeList[i].VictimColor = GetClientColor( victim ); + strncpy( rgDeathNoticeList[i].szVictim, victim_name, MAX_PLAYER_NAME_LENGTH ); + rgDeathNoticeList[i].szVictim[MAX_PLAYER_NAME_LENGTH-1] = 0; + } - strncpy( rgDeathNoticeList[i].szKiller, killer_name, MAX_PLAYER_NAME_LENGTH ); - strncpy( rgDeathNoticeList[i].szVictim, victim_name, MAX_PLAYER_NAME_LENGTH ); + // Is it a non-player object kill? + if ( ((char)victim) == -1 ) + { + rgDeathNoticeList[i].iNonPlayerKill = TRUE; - if ( killer == victim || killer == 0 ) - rgDeathNoticeList[i].iSuicide = TRUE; + // Store the object's name in the Victim slot (skip the d_ bit) + strcpy( rgDeathNoticeList[i].szVictim, killedwith+2 ); + } + else + { + if ( killer == victim || killer == 0 ) + rgDeathNoticeList[i].iSuicide = TRUE; - if ( !strcmp( killedwith, "d_teammate" ) ) - rgDeathNoticeList[i].iTeamKill = TRUE; + if ( !strcmp( killedwith, "d_teammate" ) ) + rgDeathNoticeList[i].iTeamKill = TRUE; + } // Find the sprite in the list int spr = gHUD.GetSpriteIndex( killedwith ); @@ -173,48 +238,58 @@ int CHudDeathNotice :: MsgFunc_DeathMsg( const char *pszName, int iSize, void *p DEATHNOTICE_DISPLAY_TIME = CVAR_GET_FLOAT( "hud_deathnotice_time" ); rgDeathNoticeList[i].flDisplayTime = gHUD.m_flTime + DEATHNOTICE_DISPLAY_TIME; - // record the death notice in the console - if ( rgDeathNoticeList[i].iSuicide ) - { - ConsolePrint( rgDeathNoticeList[i].szVictim ); - - if ( !strcmp( killedwith, "d_world" ) ) - { - ConsolePrint( " died" ); - } - else - { - ConsolePrint( " killed self" ); - } - } - else if ( rgDeathNoticeList[i].iTeamKill ) + if (rgDeathNoticeList[i].iNonPlayerKill) { ConsolePrint( rgDeathNoticeList[i].szKiller ); - ConsolePrint( " killed his teammate " ); + ConsolePrint( " killed a " ); ConsolePrint( rgDeathNoticeList[i].szVictim ); + ConsolePrint( "\n" ); } else { - ConsolePrint( rgDeathNoticeList[i].szKiller ); - ConsolePrint( " killed " ); - ConsolePrint( rgDeathNoticeList[i].szVictim ); + // record the death notice in the console + if ( rgDeathNoticeList[i].iSuicide ) + { + ConsolePrint( rgDeathNoticeList[i].szVictim ); + + if ( !strcmp( killedwith, "d_world" ) ) + { + ConsolePrint( " died" ); + } + else + { + ConsolePrint( " killed self" ); + } + } + else if ( rgDeathNoticeList[i].iTeamKill ) + { + ConsolePrint( rgDeathNoticeList[i].szKiller ); + ConsolePrint( " killed his teammate " ); + ConsolePrint( rgDeathNoticeList[i].szVictim ); + } + else + { + ConsolePrint( rgDeathNoticeList[i].szKiller ); + ConsolePrint( " killed " ); + ConsolePrint( rgDeathNoticeList[i].szVictim ); + } + + if ( killedwith && *killedwith && (*killedwith > 13 ) && strcmp( killedwith, "d_world" ) && !rgDeathNoticeList[i].iTeamKill ) + { + ConsolePrint( " with " ); + + // replace the code names with the 'real' names + if ( !strcmp( killedwith+2, "egon" ) ) + strcpy( killedwith, "d_gluon gun" ); + if ( !strcmp( killedwith+2, "gauss" ) ) + strcpy( killedwith, "d_tau cannon" ); + + ConsolePrint( killedwith+2 ); // skip over the "d_" part + } + + ConsolePrint( "\n" ); } - if ( killedwith && *killedwith && (*killedwith > 13 ) && strcmp( killedwith, "d_world" ) && !rgDeathNoticeList[i].iTeamKill ) - { - ConsolePrint( " with " ); - - // replace the code names with the 'real' names - if ( !strcmp( killedwith+2, "egon" ) ) - strcpy( killedwith, "d_gluon gun" ); - if ( !strcmp( killedwith+2, "gauss" ) ) - strcpy( killedwith, "d_tau cannon" ); - - ConsolePrint( killedwith+2 ); // skip over the "d_" part - } - - ConsolePrint( "\n" ); - return 1; } diff --git a/cl_dll/demo.cpp b/cl_dll/demo.cpp new file mode 100644 index 0000000..ad60465 --- /dev/null +++ b/cl_dll/demo.cpp @@ -0,0 +1,103 @@ +/*** +* +* Copyright (c) 1999, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +#include "hud.h" +#include "cl_util.h" +#include "demo.h" +#include "demo_api.h" +#include + +#define DLLEXPORT __declspec( dllexport ) + +int g_demosniper = 0; +int g_demosniperdamage = 0; +float g_demosniperorg[3]; +float g_demosniperangles[3]; +float g_demozoom; + +// FIXME: There should be buffer helper functions to avoid all of the *(int *)& crap. + +extern "C" +{ + void DLLEXPORT Demo_ReadBuffer( int size, unsigned char *buffer ); +} + +/* +===================== +Demo_WriteBuffer + +Write some data to the demo stream +===================== +*/ +void Demo_WriteBuffer( int type, int size, unsigned char *buffer ) +{ + int pos = 0; + unsigned char buf[ 32 * 1024 ]; + *( int * )&buf[pos] = type; + pos+=sizeof( int ); + + memcpy( &buf[pos], buffer, size ); + + // Write full buffer out + gEngfuncs.pDemoAPI->WriteBuffer( size + sizeof( int ), buf ); +} + +/* +===================== +Demo_ReadBuffer + +Engine wants us to parse some data from the demo stream +===================== +*/ +void DLLEXPORT Demo_ReadBuffer( int size, unsigned char *buffer ) +{ + int type; + int i = 0; + + type = *( int * )buffer; + i += sizeof( int ); + switch ( type ) + { + case TYPE_SNIPERDOT: + g_demosniper = *(int * )&buffer[ i ]; + i += sizeof( int ); + + if ( g_demosniper ) + { + g_demosniperdamage = *( int * )&buffer[ i ]; + i += sizeof( int ); + + g_demosniperangles[ 0 ] = *(float *)&buffer[i]; + i += sizeof( float ); + g_demosniperangles[ 1 ] = *(float *)&buffer[i]; + i += sizeof( float ); + g_demosniperangles[ 2 ] = *(float *)&buffer[i]; + i += sizeof( float ); + g_demosniperorg[ 0 ] = *(float *)&buffer[i]; + i += sizeof( float ); + g_demosniperorg[ 1 ] = *(float *)&buffer[i]; + i += sizeof( float ); + g_demosniperorg[ 2 ] = *(float *)&buffer[i]; + i += sizeof( float ); + } + break; + case TYPE_ZOOM: + g_demozoom = *(float * )&buffer[ i ]; + i += sizeof( float ); + break; + default: + gEngfuncs.Con_DPrintf( "Unknown demo buffer type, skipping.\n" ); + break; + } +} \ No newline at end of file diff --git a/cl_dll/demo.h b/cl_dll/demo.h new file mode 100644 index 0000000..b0cc01d --- /dev/null +++ b/cl_dll/demo.h @@ -0,0 +1,20 @@ +#if !defined( DEMOH ) +#define DEMOH +#pragma once + +// Types of demo messages we can write/parse +enum +{ + TYPE_SNIPERDOT = 0, + TYPE_ZOOM +}; + +void Demo_WriteBuffer( int type, int size, unsigned char *buffer ); + +extern int g_demosniper; +extern int g_demosniperdamage; +extern float g_demosniperorg[3]; +extern float g_demosniperangles[3]; +extern float g_demozoom; + +#endif \ No newline at end of file diff --git a/cl_dll/entity.cpp b/cl_dll/entity.cpp new file mode 100644 index 0000000..a247897 --- /dev/null +++ b/cl_dll/entity.cpp @@ -0,0 +1,914 @@ +// Client side entity management functions + +#include + +#include "hud.h" +#include "cl_util.h" +#include "const.h" +#include "entity_types.h" +#include "studio_event.h" // def. of mstudioevent_t +#include "r_efx.h" +#include "event_api.h" +#include "pm_defs.h" +#include "pmtrace.h" + +#define DLLEXPORT __declspec( dllexport ) + +void Game_AddObjects( void ); + +extern vec3_t v_origin; + +extern "C" +{ + int DLLEXPORT HUD_AddEntity( int type, struct cl_entity_s *ent, const char *modelname ); + void DLLEXPORT HUD_CreateEntities( void ); + void DLLEXPORT HUD_StudioEvent( const struct mstudioevent_s *event, const struct cl_entity_s *entity ); + void DLLEXPORT HUD_TxferLocalOverrides( struct entity_state_s *state, const struct clientdata_s *client ); + void DLLEXPORT HUD_ProcessPlayerState( struct entity_state_s *dst, const struct entity_state_s *src ); + void DLLEXPORT HUD_TxferPredictionData ( struct entity_state_s *ps, const struct entity_state_s *pps, struct clientdata_s *pcd, const struct clientdata_s *ppcd, struct weapon_data_s *wd, const struct weapon_data_s *pwd ); + void DLLEXPORT HUD_TempEntUpdate( double frametime, double client_time, double cl_gravity, struct tempent_s **ppTempEntFree, struct tempent_s **ppTempEntActive, int ( *Callback_AddVisibleEntity )( struct cl_entity_s *pEntity ), void ( *Callback_TempEntPlaySound )( struct tempent_s *pTemp, float damp ) ); + struct cl_entity_s DLLEXPORT *HUD_GetUserEntity( int index ); +} + +/* +======================== +HUD_AddEntity + Return 0 to filter entity from visible list for rendering +======================== +*/ +int DLLEXPORT HUD_AddEntity( int type, struct cl_entity_s *ent, const char *modelname ) +{ + switch ( type ) + { + case ET_NORMAL: + case ET_PLAYER: + case ET_BEAM: + case ET_TEMPENTITY: + case ET_FRAGMENTED: + default: + break; + } + + return 1; +} + +/* +========================= +HUD_TxferLocalOverrides + +The server sends us our origin with extra precision as part of the clientdata structure, not during the normal +playerstate update in entity_state_t. In order for these overrides to eventually get to the appropriate playerstate +structure, we need to copy them into the state structure at this point. +========================= +*/ +void DLLEXPORT HUD_TxferLocalOverrides( struct entity_state_s *state, const struct clientdata_s *client ) +{ + VectorCopy( client->origin, state->origin ); + + // Spectator + state->iuser1 = client->iuser1; + state->iuser2 = client->iuser2; +} + +/* +========================= +HUD_ProcessPlayerState + +We have received entity_state_t for this player over the network. We need to copy appropriate fields to the +playerstate structure +========================= +*/ +void DLLEXPORT HUD_ProcessPlayerState( struct entity_state_s *dst, const struct entity_state_s *src ) +{ + // Copy in network data + VectorCopy( src->origin, dst->origin ); + VectorCopy( src->angles, dst->angles ); + + VectorCopy( src->velocity, dst->velocity ); + + dst->frame = src->frame; + dst->modelindex = src->modelindex; + dst->skin = src->skin; + dst->effects = src->effects; + dst->weaponmodel = src->weaponmodel; + dst->movetype = src->movetype; + dst->sequence = src->sequence; + dst->animtime = src->animtime; + + dst->solid = src->solid; + + dst->rendermode = src->rendermode; + dst->renderamt = src->renderamt; + dst->rendercolor.r = src->rendercolor.r; + dst->rendercolor.g = src->rendercolor.g; + dst->rendercolor.b = src->rendercolor.b; + dst->renderfx = src->renderfx; + + dst->framerate = src->framerate; + dst->body = src->body; + + memcpy( &dst->controller[0], &src->controller[0], 4 * sizeof( byte ) ); + memcpy( &dst->blending[0], &src->blending[0], 2 * sizeof( byte ) ); + + VectorCopy( src->basevelocity, dst->basevelocity ); + + dst->friction = src->friction; + dst->gravity = src->gravity; + dst->gaitsequence = src->gaitsequence; + dst->spectator = src->spectator; + dst->usehull = src->usehull; + dst->playerclass = src->playerclass; + dst->team = src->team; + dst->colormap = src->colormap; + + // Save off some data so other areas of the Client DLL can get to it + cl_entity_t *player = gEngfuncs.GetLocalPlayer(); // Get the local player's index + if ( dst->number == player->index ) + { + g_iPlayerClass = dst->playerclass; + g_iTeamNumber = dst->team; + g_iUser1 = src->iuser1; + g_iUser2 = src->iuser2; + } +} + +/* +========================= +HUD_TxferPredictionData + +Because we can predict an arbitrary number of frames before the server responds with an update, we need to be able to copy client side prediction data in + from the state that the server ack'd receiving, which can be anywhere along the predicted frame path ( i.e., we could predict 20 frames into the future and the server ack's + up through 10 of those frames, so we need to copy persistent client-side only state from the 10th predicted frame to the slot the server + update is occupying. +========================= +*/ +void DLLEXPORT HUD_TxferPredictionData ( struct entity_state_s *ps, const struct entity_state_s *pps, struct clientdata_s *pcd, const struct clientdata_s *ppcd, struct weapon_data_s *wd, const struct weapon_data_s *pwd ) +{ + ps->oldbuttons = pps->oldbuttons; + ps->flFallVelocity = pps->flFallVelocity; + ps->iStepLeft = pps->iStepLeft; + ps->playerclass = pps->playerclass; + + pcd->viewmodel = ppcd->viewmodel; + pcd->m_iId = ppcd->m_iId; + pcd->ammo_shells = ppcd->ammo_shells; + pcd->ammo_nails = ppcd->ammo_nails; + pcd->ammo_cells = ppcd->ammo_cells; + pcd->ammo_rockets = ppcd->ammo_rockets; + pcd->m_flNextAttack = ppcd->m_flNextAttack; + pcd->fov = ppcd->fov; + pcd->weaponanim = ppcd->weaponanim; + pcd->tfstate = ppcd->tfstate; + pcd->maxspeed = ppcd->maxspeed; + + pcd->deadflag = ppcd->deadflag; + + // Spectator + pcd->iuser1 = ppcd->iuser1; + pcd->iuser2 = ppcd->iuser2; + + memcpy( wd, pwd, 32 * sizeof( weapon_data_t ) ); +} + +/* +//#define TEST_IT +#if defined( TEST_IT ) + +cl_entity_t mymodel[9]; + +void MoveModel( void ) +{ + cl_entity_t *player; + int i, j; + int modelindex; + struct model_s *mod; + + // Load it up with some bogus data + player = gEngfuncs.GetLocalPlayer(); + if ( !player ) + return; + + mod = gEngfuncs.CL_LoadModel( "models/sentry3.mdl", &modelindex ); + for ( i = 0; i < 3; i++ ) + { + for ( j = 0; j < 3; j++ ) + { + // Don't draw over ourself... + if ( ( i == 1 ) && ( j == 1 ) ) + continue; + + mymodel[ i * 3 + j ] = *player; + + mymodel[ i * 3 + j ].player = 0; + + mymodel[ i * 3 + j ].model = mod; + mymodel[ i * 3 + j ].curstate.modelindex = modelindex; + + // Move it out a bit + mymodel[ i * 3 + j ].origin[0] = player->origin[0] + 50 * ( 1 - i ); + mymodel[ i * 3 + j ].origin[1] = player->origin[1] + 50 * ( 1 - j ); + + gEngfuncs.CL_CreateVisibleEntity( ET_NORMAL, &mymodel[i*3+j] ); + } + } + +} + +#endif + +//#define TRACE_TEST +#if defined( TRACE_TEST ) + +extern int hitent; + +cl_entity_t hit; + +void TraceModel( void ) +{ + cl_entity_t *ent; + + if ( hitent <= 0 ) + return; + + // Load it up with some bogus data + ent = gEngfuncs.GetEntityByIndex( hitent ); + if ( !ent ) + return; + + hit = *ent; + //hit.curstate.rendermode = kRenderTransTexture; + //hit.curstate.renderfx = kRenderFxGlowShell; + //hit.curstate.renderamt = 100; + + hit.origin[2] += 40; + + gEngfuncs.CL_CreateVisibleEntity( ET_NORMAL, &hit ); +} + +#endif +*/ + +/* +void ParticleCallback( struct particle_s *particle, float frametime ) +{ + int i; + + for ( i = 0; i < 3; i++ ) + { + particle->org[ i ] += particle->vel[ i ] * frametime; + } +} + +cvar_t *color = NULL; +void Particles( void ) +{ + static float lasttime; + float curtime; + + curtime = gEngfuncs.GetClientTime(); + + if ( ( curtime - lasttime ) < 2.0 ) + return; + + if ( !color ) + { + color = gEngfuncs.pfnRegisterVariable ( "color","255 0 0", 0 ); + } + + lasttime = curtime; + + // Create a few particles + particle_t *p; + int i, j; + + for ( i = 0; i < 1000; i++ ) + { + int r, g, b; + p = gEngfuncs.pEfxAPI->R_AllocParticle( ParticleCallback ); + if ( !p ) + break; + + for ( j = 0; j < 3; j++ ) + { + p->org[ j ] = v_origin[ j ] + gEngfuncs.pfnRandomFloat( -32.0, 32.0 );; + p->vel[ j ] = gEngfuncs.pfnRandomFloat( -100.0, 100.0 ); + } + + if ( color ) + { + sscanf( color->string, "%i %i %i", &r, &g, &b ); + } + else + { + r = 192; + g = 0; + b = 0; + } + + p->color = gEngfuncs.pEfxAPI->R_LookupColor( r, g, b ); + gEngfuncs.pEfxAPI->R_GetPackedColor( &p->packedColor, p->color ); + + // p->die is set to current time so all you have to do is add an additional time to it + p->die += 3.0; + } +} +*/ + +/* +void TempEntCallback ( struct tempent_s *ent, float frametime, float currenttime ) +{ + int i; + + for ( i = 0; i < 3; i++ ) + { + ent->entity.curstate.origin[ i ] += ent->entity.baseline.origin[ i ] * frametime; + } +} + +void TempEnts( void ) +{ + static float lasttime; + float curtime; + + curtime = gEngfuncs.GetClientTime(); + + if ( ( curtime - lasttime ) < 10.0 ) + return; + + lasttime = curtime; + + TEMPENTITY *p; + int i, j; + struct model_s *mod; + vec3_t origin; + int index; + + mod = gEngfuncs.CL_LoadModel( "sprites/laserdot.spr", &index ); + + for ( i = 0; i < 100; i++ ) + { + for ( j = 0; j < 3; j++ ) + { + origin[ j ] = v_origin[ j ]; + if ( j != 2 ) + { + origin[ j ] += 75; + } + } + + p = gEngfuncs.pEfxAPI->CL_TentEntAllocCustom( (float *)&origin, mod, 0, TempEntCallback ); + if ( !p ) + break; + + for ( j = 0; j < 3; j++ ) + { + p->entity.curstate.origin[ j ] = origin[ j ]; + + // Store velocity in baseline origin + p->entity.baseline.origin[ j ] = gEngfuncs.pfnRandomFloat( -100, 100 ); + } + + // p->die is set to current time so all you have to do is add an additional time to it + p->die += 10.0; + } +} +*/ + +#if defined( BEAM_TEST ) +// Note can't index beam[ 0 ] in Beam callback, so don't use that index +// Room for 1 beam ( 0 can't be used ) +static cl_entity_t beams[ 2 ]; + +void BeamEndModel( void ) +{ + cl_entity_t *player, *model; + int modelindex; + struct model_s *mod; + + // Load it up with some bogus data + player = gEngfuncs.GetLocalPlayer(); + if ( !player ) + return; + + mod = gEngfuncs.CL_LoadModel( "models/sentry3.mdl", &modelindex ); + if ( !mod ) + return; + + // Slot 1 + model = &beams[ 1 ]; + + *model = *player; + model->player = 0; + model->model = mod; + model->curstate.modelindex = modelindex; + + // Move it out a bit + model->origin[0] = player->origin[0] - 100; + model->origin[1] = player->origin[1]; + + model->attachment[0] = model->origin; + model->attachment[1] = model->origin; + model->attachment[2] = model->origin; + model->attachment[3] = model->origin; + + gEngfuncs.CL_CreateVisibleEntity( ET_NORMAL, model ); +} + +void Beams( void ) +{ + static float lasttime; + float curtime; + struct model_s *mod; + int index; + + BeamEndModel(); + + curtime = gEngfuncs.GetClientTime(); + float end[ 3 ]; + + if ( ( curtime - lasttime ) < 10.0 ) + return; + + mod = gEngfuncs.CL_LoadModel( "sprites/laserbeam.spr", &index ); + if ( !mod ) + return; + + lasttime = curtime; + + end [ 0 ] = v_origin.x + 100; + end [ 1 ] = v_origin.y + 100; + end [ 2 ] = v_origin.z; + + BEAM *p1; + p1 = gEngfuncs.pEfxAPI->R_BeamEntPoint( -1, end, index, + 10.0, 2.0, 0.3, 1.0, 5.0, 0.0, 1.0, 1.0, 1.0, 1.0 ); +} +#endif + +/* +========================= +HUD_CreateEntities + +Gives us a chance to add additional entities to the render this frame +========================= +*/ +void DLLEXPORT HUD_CreateEntities( void ) +{ + // e.g., create a persistent cl_entity_t somewhere. + // Load an appropriate model into it ( gEngfuncs.CL_LoadModel ) + // Call gEngfuncs.CL_CreateVisibleEntity to add it to the visedicts list +/* +#if defined( TEST_IT ) + MoveModel(); +#endif + +#if defined( TRACE_TEST ) + TraceModel(); +#endif +*/ +/* + Particles(); +*/ +/* + TempEnts(); +*/ + +#if defined( BEAM_TEST ) + Beams(); +#endif + + // Add in any game specific objects + Game_AddObjects(); +} + +/* +========================= +HUD_StudioEvent + +The entity's studio model description indicated an event was +fired during this frame, handle the event by it's tag ( e.g., muzzleflash, sound ) +========================= +*/ +void DLLEXPORT HUD_StudioEvent( const struct mstudioevent_s *event, const struct cl_entity_s *entity ) +{ + switch( event->event ) + { + case 5001: + gEngfuncs.pEfxAPI->R_MuzzleFlash( (float *)&entity->attachment[0], atoi( event->options) ); + break; + case 5011: + gEngfuncs.pEfxAPI->R_MuzzleFlash( (float *)&entity->attachment[1], atoi( event->options) ); + break; + case 5021: + gEngfuncs.pEfxAPI->R_MuzzleFlash( (float *)&entity->attachment[2], atoi( event->options) ); + break; + case 5031: + gEngfuncs.pEfxAPI->R_MuzzleFlash( (float *)&entity->attachment[3], atoi( event->options) ); + break; + case 5002: + gEngfuncs.pEfxAPI->R_SparkEffect( (float *)&entity->attachment[0], atoi( event->options), -100, 100 ); + break; + // Client side sound + case 5004: + gEngfuncs.pfnPlaySoundByNameAtLocation( (char *)event->options, 1.0, (float *)&entity->attachment[0] ); + break; + default: + break; + } +} + +/* +================= +CL_UpdateTEnts + +Simulation and cleanup of temporary entities +================= +*/ +void DLLEXPORT HUD_TempEntUpdate ( + double frametime, // Simulation time + double client_time, // Absolute time on client + double cl_gravity, // True gravity on client + TEMPENTITY **ppTempEntFree, // List of freed temporary ents + TEMPENTITY **ppTempEntActive, // List + int ( *Callback_AddVisibleEntity )( cl_entity_t *pEntity ), + void ( *Callback_TempEntPlaySound )( TEMPENTITY *pTemp, float damp ) ) +{ + static int gTempEntFrame = 0; + int i; + TEMPENTITY *pTemp, *pnext, *pprev; + float freq, gravity, gravitySlow, life, fastFreq; + + // Nothing to simulate + if ( !*ppTempEntActive ) + return; + + // in order to have tents collide with players, we have to run the player prediction code so + // that the client has the player list. We run this code once when we detect any COLLIDEALL + // tent, then set this BOOL to true so the code doesn't get run again if there's more than + // one COLLIDEALL ent for this update. (often are). + gEngfuncs.pEventAPI->EV_SetUpPlayerPrediction( false, true ); + + // Store off the old count + gEngfuncs.pEventAPI->EV_PushPMStates(); + + // Now add in all of the players. + gEngfuncs.pEventAPI->EV_SetSolidPlayers ( -1 ); + + // !!!BUGBUG -- This needs to be time based + gTempEntFrame = (gTempEntFrame+1) & 31; + + pTemp = *ppTempEntActive; + + // !!! Don't simulate while paused.... This is sort of a hack, revisit. + if ( frametime <= 0 ) + { + while ( pTemp ) + { + if ( !(pTemp->flags & FTENT_NOMODEL ) ) + { + Callback_AddVisibleEntity( &pTemp->entity ); + } + pTemp = pTemp->next; + } + goto finish; + } + + pprev = NULL; + freq = client_time * 0.01; + fastFreq = client_time * 5.5; + gravity = -frametime * cl_gravity; + gravitySlow = gravity * 0.5; + + while ( pTemp ) + { + int active; + + active = 1; + + life = pTemp->die - client_time; + pnext = pTemp->next; + if ( life < 0 ) + { + if ( pTemp->flags & FTENT_FADEOUT ) + { + if (pTemp->entity.curstate.rendermode == kRenderNormal) + pTemp->entity.curstate.rendermode = kRenderTransTexture; + pTemp->entity.curstate.renderamt = pTemp->entity.baseline.renderamt * ( 1 + life * pTemp->fadeSpeed ); + if ( pTemp->entity.curstate.renderamt <= 0 ) + active = 0; + + } + else + active = 0; + } + if ( !active ) // Kill it + { + pTemp->next = *ppTempEntFree; + *ppTempEntFree = pTemp; + if ( !pprev ) // Deleting at head of list + *ppTempEntActive = pnext; + else + pprev->next = pnext; + } + else + { + pprev = pTemp; + + VectorCopy( pTemp->entity.origin, pTemp->entity.prevstate.origin ); + + if ( pTemp->flags & FTENT_SPARKSHOWER ) + { + // Adjust speed if it's time + // Scale is next think time + if ( client_time > pTemp->entity.baseline.scale ) + { + // Show Sparks + gEngfuncs.pEfxAPI->R_SparkEffect( pTemp->entity.origin, 8, -200, 200 ); + + // Reduce life + pTemp->entity.baseline.framerate -= 0.1; + + if ( pTemp->entity.baseline.framerate <= 0.0 ) + { + pTemp->die = client_time; + } + else + { + // So it will die no matter what + pTemp->die = client_time + 0.5; + + // Next think + pTemp->entity.baseline.scale = client_time + 0.1; + } + } + } + else if ( pTemp->flags & FTENT_PLYRATTACHMENT ) + { + cl_entity_t *pClient; + + pClient = gEngfuncs.GetEntityByIndex( pTemp->clientIndex ); + + VectorAdd( pClient->origin, pTemp->tentOffset, pTemp->entity.origin ); + } + else if ( pTemp->flags & FTENT_SINEWAVE ) + { + pTemp->x += pTemp->entity.baseline.origin[0] * frametime; + pTemp->y += pTemp->entity.baseline.origin[1] * frametime; + + pTemp->entity.origin[0] = pTemp->x + sin( pTemp->entity.baseline.origin[2] + client_time * pTemp->entity.prevstate.frame ) * (10*pTemp->entity.curstate.framerate); + pTemp->entity.origin[1] = pTemp->y + sin( pTemp->entity.baseline.origin[2] + fastFreq + 0.7 ) * (8*pTemp->entity.curstate.framerate); + pTemp->entity.origin[2] += pTemp->entity.baseline.origin[2] * frametime; + } + else if ( pTemp->flags & FTENT_SPIRAL ) + { + float s, c; + s = sin( pTemp->entity.baseline.origin[2] + fastFreq ); + c = cos( pTemp->entity.baseline.origin[2] + fastFreq ); + + pTemp->entity.origin[0] += pTemp->entity.baseline.origin[0] * frametime + 8 * sin( client_time * 20 + (int)pTemp ); + pTemp->entity.origin[1] += pTemp->entity.baseline.origin[1] * frametime + 4 * sin( client_time * 30 + (int)pTemp ); + pTemp->entity.origin[2] += pTemp->entity.baseline.origin[2] * frametime; + } + else + { + for ( i = 0; i < 3; i++ ) + pTemp->entity.origin[i] += pTemp->entity.baseline.origin[i] * frametime; + } + + if ( pTemp->flags & FTENT_SPRANIMATE ) + { + pTemp->entity.curstate.frame += frametime * pTemp->entity.curstate.framerate; + if ( pTemp->entity.curstate.frame >= pTemp->frameMax ) + { + pTemp->entity.curstate.frame = pTemp->entity.curstate.frame - (int)(pTemp->entity.curstate.frame); + + if ( !(pTemp->flags & FTENT_SPRANIMATELOOP) ) + { + // this animating sprite isn't set to loop, so destroy it. + pTemp->die = client_time; + pTemp = pnext; + continue; + } + } + } + else if ( pTemp->flags & FTENT_SPRCYCLE ) + { + pTemp->entity.curstate.frame += frametime * 10; + if ( pTemp->entity.curstate.frame >= pTemp->frameMax ) + { + pTemp->entity.curstate.frame = pTemp->entity.curstate.frame - (int)(pTemp->entity.curstate.frame); + } + } +// Experiment +#if 0 + if ( pTemp->flags & FTENT_SCALE ) + pTemp->entity.curstate.framerate += 20.0 * (frametime / pTemp->entity.curstate.framerate); +#endif + + if ( pTemp->flags & FTENT_ROTATE ) + { + pTemp->entity.angles[0] += pTemp->entity.baseline.angles[0] * frametime; + pTemp->entity.angles[1] += pTemp->entity.baseline.angles[1] * frametime; + pTemp->entity.angles[2] += pTemp->entity.baseline.angles[2] * frametime; + + VectorCopy( pTemp->entity.angles, pTemp->entity.latched.prevangles ); + } + + if ( pTemp->flags & (FTENT_COLLIDEALL | FTENT_COLLIDEWORLD) ) + { + vec3_t traceNormal; + float traceFraction = 1; + + if ( pTemp->flags & FTENT_COLLIDEALL ) + { + pmtrace_t pmtrace; + physent_t *pe; + + gEngfuncs.pEventAPI->EV_SetTraceHull( 2 ); + + gEngfuncs.pEventAPI->EV_PlayerTrace( pTemp->entity.prevstate.origin, pTemp->entity.origin, PM_STUDIO_BOX, -1, &pmtrace ); + + + if ( pmtrace.fraction != 1 ) + { + pe = gEngfuncs.pEventAPI->EV_GetPhysent( pmtrace.ent ); + + if ( !pmtrace.ent || ( pe->info != pTemp->clientIndex ) ) + { + traceFraction = pmtrace.fraction; + VectorCopy( pmtrace.plane.normal, traceNormal ); + + if ( pTemp->hitcallback ) + { + (*pTemp->hitcallback)( pTemp, &pmtrace ); + } + } + } + } + else if ( pTemp->flags & FTENT_COLLIDEWORLD ) + { + pmtrace_t pmtrace; + + gEngfuncs.pEventAPI->EV_SetTraceHull( 2 ); + + gEngfuncs.pEventAPI->EV_PlayerTrace( pTemp->entity.prevstate.origin, pTemp->entity.origin, PM_STUDIO_BOX | PM_WORLD_ONLY, -1, &pmtrace ); + + if ( pmtrace.fraction != 1 ) + { + traceFraction = pmtrace.fraction; + VectorCopy( pmtrace.plane.normal, traceNormal ); + + if ( pTemp->flags & FTENT_SPARKSHOWER ) + { + // Chop spark speeds a bit more + // + VectorScale( pTemp->entity.baseline.origin, 0.6, pTemp->entity.baseline.origin ); + + if ( Length( pTemp->entity.baseline.origin ) < 10 ) + { + pTemp->entity.baseline.framerate = 0.0; + } + } + + if ( pTemp->hitcallback ) + { + (*pTemp->hitcallback)( pTemp, &pmtrace ); + } + } + } + + if ( traceFraction != 1 ) // Decent collision now, and damping works + { + float proj, damp; + + // Place at contact point + VectorMA( pTemp->entity.prevstate.origin, traceFraction*frametime, pTemp->entity.baseline.origin, pTemp->entity.origin ); + // Damp velocity + damp = pTemp->bounceFactor; + if ( pTemp->flags & (FTENT_GRAVITY|FTENT_SLOWGRAVITY) ) + { + damp *= 0.5; + if ( traceNormal[2] > 0.9 ) // Hit floor? + { + if ( pTemp->entity.baseline.origin[2] <= 0 && pTemp->entity.baseline.origin[2] >= gravity*3 ) + { + damp = 0; // Stop + pTemp->flags &= ~(FTENT_ROTATE|FTENT_GRAVITY|FTENT_SLOWGRAVITY|FTENT_COLLIDEWORLD|FTENT_SMOKETRAIL); + pTemp->entity.angles[0] = 0; + pTemp->entity.angles[2] = 0; + } + } + } + + if (pTemp->hitSound) + { + Callback_TempEntPlaySound(pTemp, damp); + } + + if (pTemp->flags & FTENT_COLLIDEKILL) + { + // die on impact + pTemp->flags &= ~FTENT_FADEOUT; + pTemp->die = client_time; + } + else + { + // Reflect velocity + if ( damp != 0 ) + { + proj = DotProduct( pTemp->entity.baseline.origin, traceNormal ); + VectorMA( pTemp->entity.baseline.origin, -proj*2, traceNormal, pTemp->entity.baseline.origin ); + // Reflect rotation (fake) + + pTemp->entity.angles[1] = -pTemp->entity.angles[1]; + } + + if ( damp != 1 ) + { + + VectorScale( pTemp->entity.baseline.origin, damp, pTemp->entity.baseline.origin ); + VectorScale( pTemp->entity.angles, 0.9, pTemp->entity.angles ); + } + } + } + } + + + if ( (pTemp->flags & FTENT_FLICKER) && gTempEntFrame == pTemp->entity.curstate.effects ) + { + dlight_t *dl = gEngfuncs.pEfxAPI->CL_AllocDlight (0); + VectorCopy (pTemp->entity.origin, dl->origin); + dl->radius = 60; + dl->color.r = 255; + dl->color.g = 120; + dl->color.b = 0; + dl->die = client_time + 0.01; + } + + if ( pTemp->flags & FTENT_SMOKETRAIL ) + { + gEngfuncs.pEfxAPI->R_RocketTrail (pTemp->entity.prevstate.origin, pTemp->entity.origin, 1); + } + + if ( pTemp->flags & FTENT_GRAVITY ) + pTemp->entity.baseline.origin[2] += gravity; + else if ( pTemp->flags & FTENT_SLOWGRAVITY ) + pTemp->entity.baseline.origin[2] += gravitySlow; + + if ( pTemp->flags & FTENT_CLIENTCUSTOM ) + { + if ( pTemp->callback ) + { + ( *pTemp->callback )( pTemp, frametime, client_time ); + } + } + + // Cull to PVS (not frustum cull, just PVS) + if ( !(pTemp->flags & FTENT_NOMODEL ) ) + { + if ( !Callback_AddVisibleEntity( &pTemp->entity ) ) + { + if ( !(pTemp->flags & FTENT_PERSIST) ) + { + pTemp->die = client_time; // If we can't draw it this frame, just dump it. + pTemp->flags &= ~FTENT_FADEOUT; // Don't fade out, just die + } + } + } + } + pTemp = pnext; + } + +finish: + // Restore state info + gEngfuncs.pEventAPI->EV_PopPMStates(); +} + +/* +================= +HUD_GetUserEntity + +If you specify negative numbers for beam start and end point entities, then + the engine will call back into this function requesting a pointer to a cl_entity_t + object that describes the entity to attach the beam onto. + +Indices must start at 1, not zero. +================= +*/ +cl_entity_t DLLEXPORT *HUD_GetUserEntity( int index ) +{ +#if defined( BEAM_TEST ) + // None by default, you would return a valic pointer if you create a client side + // beam and attach it to a client side entity. + if ( index > 0 && index <= 1 ) + { + return &beams[ index ]; + } + else + { + return NULL; + } +#else + return NULL; +#endif +} \ No newline at end of file diff --git a/cl_dll/ev_common.cpp b/cl_dll/ev_common.cpp new file mode 100644 index 0000000..fb9494b --- /dev/null +++ b/cl_dll/ev_common.cpp @@ -0,0 +1,198 @@ +/*** +* +* Copyright (c) 1999, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +// shared event functions +#include "hud.h" +#include "cl_util.h" +#include "const.h" +#include "entity_state.h" +#include "cl_entity.h" + +#include "r_efx.h" + +#include "eventscripts.h" +#include "event_api.h" + +/* +================= +GetEntity + +Return's the requested cl_entity_t +================= +*/ +struct cl_entity_s *GetEntity( int idx ) +{ + return gEngfuncs.GetEntityByIndex( idx ); +} + +/* +================= +GetViewEntity + +Return's the current weapon/view model +================= +*/ +struct cl_entity_s *GetViewEntity( void ) +{ + return gEngfuncs.GetViewModel(); +} + +/* +================= +EV_CreateTracer + +Creates a tracer effect +================= +*/ +void EV_CreateTracer( float *start, float *end ) +{ + gEngfuncs.pEfxAPI->R_TracerEffect( start, end ); +} + +/* +================= +EV_IsPlayer + +Is the entity's index in the player range? +================= +*/ +qboolean EV_IsPlayer( int idx ) +{ + if ( idx >= 1 && idx <= gEngfuncs.GetMaxClients() ) + return true; + + return false; +} + +/* +================= +EV_IsLocal + +Is the entity == the local player +================= +*/ +qboolean EV_IsLocal( int idx ) +{ + return gEngfuncs.pEventAPI->EV_IsLocal( idx - 1 ) ? true : false; +} + +/* +================= +EV_GetGunPosition + +Figure out the height of the gun +================= +*/ +void EV_GetGunPosition( event_args_t *args, float *pos, float *origin ) +{ + int idx; + vec3_t view_ofs; + + idx = args->entindex; + + VectorClear( view_ofs ); + view_ofs[2] = DEFAULT_VIEWHEIGHT; + + if ( EV_IsPlayer( idx ) ) + { + if ( EV_IsLocal( idx ) ) + { + // Grab predicted result for local player + gEngfuncs.pEventAPI->EV_LocalPlayerViewheight( view_ofs ); + } + else if ( args->ducking == 1 ) + { + view_ofs[2] = VEC_DUCK_VIEW; + } + } + + VectorAdd( origin, view_ofs, pos ); +} + +/* +================= +EV_EjectBrass + +Bullet shell casings +================= +*/ +void EV_EjectBrass( float *origin, float *velocity, float rotation, int model, int soundtype ) +{ + vec3_t endpos; + VectorClear( endpos ); + endpos[1] = rotation; + gEngfuncs.pEfxAPI->R_TempModel( origin, velocity, endpos, 2.5, model, soundtype ); +} + +/* +================= +EV_GetDefaultShellInfo + +Determine where to eject shells from +================= +*/ +void EV_GetDefaultShellInfo( event_args_t *args, float *origin, float *velocity, float *ShellVelocity, float *ShellOrigin, float *forward, float *right, float *up, float forwardScale, float upScale, float rightScale ) +{ + int i; + vec3_t view_ofs; + float fR, fU; + + int idx; + + idx = args->entindex; + + VectorClear( view_ofs ); + view_ofs[2] = DEFAULT_VIEWHEIGHT; + + if ( EV_IsPlayer( idx ) ) + { + if ( EV_IsLocal( idx ) ) + { + gEngfuncs.pEventAPI->EV_LocalPlayerViewheight( view_ofs ); + } + else if ( args->ducking == 1 ) + { + view_ofs[2] = VEC_DUCK_VIEW; + } + } + + fR = gEngfuncs.pfnRandomFloat( 50, 70 ); + fU = gEngfuncs.pfnRandomFloat( 100, 150 ); + + for ( i = 0; i < 3; i++ ) + { + ShellVelocity[i] = velocity[i] + right[i] * fR + up[i] * fU + forward[i] * 25; + ShellOrigin[i] = origin[i] + view_ofs[i] + up[i] * upScale + forward[i] * forwardScale + right[i] * rightScale; + } +} + +/* +================= +EV_MuzzleFlash + +Flag weapon/view model for muzzle flash +================= +*/ +void EV_MuzzleFlash( void ) +{ + // Add muzzle flash to current weapon model + cl_entity_t *ent = GetViewEntity(); + if ( !ent ) + { + return; + } + + // Or in the muzzle flash + ent->curstate.effects |= EF_MUZZLEFLASH; +} \ No newline at end of file diff --git a/cl_dll/ev_hldm.cpp b/cl_dll/ev_hldm.cpp new file mode 100644 index 0000000..ac3002a --- /dev/null +++ b/cl_dll/ev_hldm.cpp @@ -0,0 +1,1112 @@ +/*** +* +* Copyright (c) 1999, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +#include "hud.h" +#include "cl_util.h" +#include "const.h" +#include "entity_state.h" +#include "cl_entity.h" +#include "entity_types.h" +#include "usercmd.h" +#include "pm_defs.h" +#include "pm_materials.h" + +#include "eventscripts.h" +#include "ev_hldm.h" + +#include "r_efx.h" +#include "event_api.h" +#include "event_args.h" +#include "in_defs.h" + +#include + +static int tracerCount[ 32 ]; + +extern "C" char PM_FindTextureType( char *name ); + +void V_PunchAxis( int axis, float punch ); + +extern "C" +{ + +// HLDM +void EV_FireGlock1( struct event_args_s *args ); +void EV_FireGlock2( struct event_args_s *args ); +void EV_FireShotGunSingle( struct event_args_s *args ); +void EV_FireShotGunDouble( struct event_args_s *args ); +void EV_FireMP5( struct event_args_s *args ); +void EV_FirePython( struct event_args_s *args ); +void EV_FireGauss( struct event_args_s *args ); +void EV_SpinGauss( struct event_args_s *args ); +void EV_TrainPitchAdjust( struct event_args_s *args ); +} + +#define VECTOR_CONE_1DEGREES Vector( 0.00873, 0.00873, 0.00873 ) +#define VECTOR_CONE_2DEGREES Vector( 0.01745, 0.01745, 0.01745 ) +#define VECTOR_CONE_3DEGREES Vector( 0.02618, 0.02618, 0.02618 ) +#define VECTOR_CONE_4DEGREES Vector( 0.03490, 0.03490, 0.03490 ) +#define VECTOR_CONE_5DEGREES Vector( 0.04362, 0.04362, 0.04362 ) +#define VECTOR_CONE_6DEGREES Vector( 0.05234, 0.05234, 0.05234 ) +#define VECTOR_CONE_7DEGREES Vector( 0.06105, 0.06105, 0.06105 ) +#define VECTOR_CONE_8DEGREES Vector( 0.06976, 0.06976, 0.06976 ) +#define VECTOR_CONE_9DEGREES Vector( 0.07846, 0.07846, 0.07846 ) +#define VECTOR_CONE_10DEGREES Vector( 0.08716, 0.08716, 0.08716 ) +#define VECTOR_CONE_15DEGREES Vector( 0.13053, 0.13053, 0.13053 ) +#define VECTOR_CONE_20DEGREES Vector( 0.17365, 0.17365, 0.17365 ) + +// play a strike sound based on the texture that was hit by the attack traceline. VecSrc/VecEnd are the +// original traceline endpoints used by the attacker, iBulletType is the type of bullet that hit the texture. +// returns volume of strike instrument (crowbar) to play +float EV_HLDM_PlayTextureSound( int idx, pmtrace_t *ptr, float *vecSrc, float *vecEnd, int iBulletType ) +{ + // hit the world, try to play sound based on texture material type + char chTextureType = CHAR_TEX_CONCRETE; + float fvol; + float fvolbar; + char *rgsz[4]; + int cnt; + float fattn = ATTN_NORM; + int entity; + char *pTextureName; + char texname[ 64 ]; + char szbuffer[ 64 ]; + + entity = gEngfuncs.pEventAPI->EV_IndexFromTrace( ptr ); + + // FIXME check if playtexture sounds movevar is set + // + + chTextureType = 0; + + // Player + if ( entity >= 1 && entity <= gEngfuncs.GetMaxClients() ) + { + // hit body + chTextureType = CHAR_TEX_FLESH; + } + else if ( entity == 0 ) + { + // get texture from entity or world (world is ent(0)) + pTextureName = (char *)gEngfuncs.pEventAPI->EV_TraceTexture( ptr->ent, vecSrc, vecEnd ); + + if ( pTextureName ) + { + strcpy( texname, pTextureName ); + pTextureName = texname; + + // strip leading '-0' or '+0~' or '{' or '!' + if (*pTextureName == '-' || *pTextureName == '+') + { + pTextureName += 2; + } + + if (*pTextureName == '{' || *pTextureName == '!' || *pTextureName == '~' || *pTextureName == ' ') + { + pTextureName++; + } + + // '}}' + strcpy( szbuffer, pTextureName ); + szbuffer[ CBTEXTURENAMEMAX - 1 ] = 0; + + // get texture type + chTextureType = PM_FindTextureType( szbuffer ); + } + } + + switch (chTextureType) + { + default: + case CHAR_TEX_CONCRETE: fvol = 0.9; fvolbar = 0.6; + rgsz[0] = "player/pl_step1.wav"; + rgsz[1] = "player/pl_step2.wav"; + cnt = 2; + break; + case CHAR_TEX_METAL: fvol = 0.9; fvolbar = 0.3; + rgsz[0] = "player/pl_metal1.wav"; + rgsz[1] = "player/pl_metal2.wav"; + cnt = 2; + break; + case CHAR_TEX_DIRT: fvol = 0.9; fvolbar = 0.1; + rgsz[0] = "player/pl_dirt1.wav"; + rgsz[1] = "player/pl_dirt2.wav"; + rgsz[2] = "player/pl_dirt3.wav"; + cnt = 3; + break; + case CHAR_TEX_VENT: fvol = 0.5; fvolbar = 0.3; + rgsz[0] = "player/pl_duct1.wav"; + rgsz[1] = "player/pl_duct1.wav"; + cnt = 2; + break; + case CHAR_TEX_GRATE: fvol = 0.9; fvolbar = 0.5; + rgsz[0] = "player/pl_grate1.wav"; + rgsz[1] = "player/pl_grate4.wav"; + cnt = 2; + break; + case CHAR_TEX_TILE: fvol = 0.8; fvolbar = 0.2; + rgsz[0] = "player/pl_tile1.wav"; + rgsz[1] = "player/pl_tile3.wav"; + rgsz[2] = "player/pl_tile2.wav"; + rgsz[3] = "player/pl_tile4.wav"; + cnt = 4; + break; + case CHAR_TEX_SLOSH: fvol = 0.9; fvolbar = 0.0; + rgsz[0] = "player/pl_slosh1.wav"; + rgsz[1] = "player/pl_slosh3.wav"; + rgsz[2] = "player/pl_slosh2.wav"; + rgsz[3] = "player/pl_slosh4.wav"; + cnt = 4; + break; + case CHAR_TEX_WOOD: fvol = 0.9; fvolbar = 0.2; + rgsz[0] = "debris/wood1.wav"; + rgsz[1] = "debris/wood2.wav"; + rgsz[2] = "debris/wood3.wav"; + cnt = 3; + break; + case CHAR_TEX_GLASS: + case CHAR_TEX_COMPUTER: + fvol = 0.8; fvolbar = 0.2; + rgsz[0] = "debris/glass1.wav"; + rgsz[1] = "debris/glass2.wav"; + rgsz[2] = "debris/glass3.wav"; + cnt = 3; + break; + case CHAR_TEX_FLESH: + if (iBulletType == BULLET_PLAYER_CROWBAR) + return 0.0; // crowbar already makes this sound + fvol = 1.0; fvolbar = 0.2; + rgsz[0] = "weapons/bullet_hit1.wav"; + rgsz[1] = "weapons/bullet_hit2.wav"; + fattn = 1.0; + cnt = 2; + break; + } + + // play material hit sound + gEngfuncs.pEventAPI->EV_PlaySound( 0, ptr->endpos, CHAN_STATIC, rgsz[gEngfuncs.pfnRandomLong(0,cnt-1)], fvol, fattn, 0, 96 + gEngfuncs.pfnRandomLong(0,0xf) ); + return fvolbar; +} + +char *EV_HLDM_DamageDecal( physent_t *pe ) +{ + static char decalname[ 32 ]; + int idx; + + if ( pe->classnumber == 1 ) + { + idx = gEngfuncs.pfnRandomLong( 0, 2 ); + sprintf( decalname, "{break%i", idx + 1 ); + } + else if ( pe->rendermode != kRenderNormal ) + { + sprintf( decalname, "{bproof1" ); + } + else + { + idx = gEngfuncs.pfnRandomLong( 0, 4 ); + sprintf( decalname, "{shot%i", idx + 1 ); + } + return decalname; +} + +void EV_HLDM_GunshotDecalTrace( pmtrace_t *pTrace, char *decalName ) +{ + int iRand; + physent_t *pe; + + gEngfuncs.pEfxAPI->R_BulletImpactParticles( pTrace->endpos ); + + iRand = gEngfuncs.pfnRandomLong(0,0x7FFF); + if ( iRand < (0x7fff/2) )// not every bullet makes a sound. + { + switch( iRand % 5) + { + case 0: gEngfuncs.pEventAPI->EV_PlaySound( -1, pTrace->endpos, 0, "weapons/ric1.wav", 1.0, ATTN_NORM, 0, PITCH_NORM ); break; + case 1: gEngfuncs.pEventAPI->EV_PlaySound( -1, pTrace->endpos, 0, "weapons/ric2.wav", 1.0, ATTN_NORM, 0, PITCH_NORM ); break; + case 2: gEngfuncs.pEventAPI->EV_PlaySound( -1, pTrace->endpos, 0, "weapons/ric3.wav", 1.0, ATTN_NORM, 0, PITCH_NORM ); break; + case 3: gEngfuncs.pEventAPI->EV_PlaySound( -1, pTrace->endpos, 0, "weapons/ric4.wav", 1.0, ATTN_NORM, 0, PITCH_NORM ); break; + case 4: gEngfuncs.pEventAPI->EV_PlaySound( -1, pTrace->endpos, 0, "weapons/ric5.wav", 1.0, ATTN_NORM, 0, PITCH_NORM ); break; + } + } + + pe = gEngfuncs.pEventAPI->EV_GetPhysent( pTrace->ent ); + + // Only decal brush models such as the world etc. + if ( decalName && decalName[0] && pe && ( pe->solid == SOLID_BSP || pe->movetype == MOVETYPE_PUSHSTEP ) ) + { + if ( CVAR_GET_FLOAT( "r_decals" ) ) + { + gEngfuncs.pEfxAPI->R_DecalShoot( + gEngfuncs.pEfxAPI->Draw_DecalIndex( gEngfuncs.pEfxAPI->Draw_DecalIndexFromName( decalName ) ), + gEngfuncs.pEventAPI->EV_IndexFromTrace( pTrace ), 0, pTrace->endpos, 0 ); + } + } +} + +void EV_HLDM_DecalGunshot( pmtrace_t *pTrace, int iBulletType ) +{ + physent_t *pe; + + pe = gEngfuncs.pEventAPI->EV_GetPhysent( pTrace->ent ); + + if ( pe && pe->solid == SOLID_BSP ) + { + switch( iBulletType ) + { + case BULLET_PLAYER_9MM: + case BULLET_MONSTER_9MM: + case BULLET_PLAYER_MP5: + case BULLET_MONSTER_MP5: + case BULLET_PLAYER_BUCKSHOT: + case BULLET_PLAYER_357: + default: + // smoke and decal + EV_HLDM_GunshotDecalTrace( pTrace, EV_HLDM_DamageDecal( pe ) ); + break; + } + } +} + +int EV_HLDM_CheckTracer( int idx, float *vecSrc, float *end, float *forward, float *right, int iBulletType, int iTracerFreq, int *tracerCount ) +{ + int tracer = 0; + int i; + qboolean player = idx >= 1 && idx <= gEngfuncs.GetMaxClients() ? true : false; + + if ( iTracerFreq != 0 && ( (*tracerCount)++ % iTracerFreq) == 0 ) + { + vec3_t vecTracerSrc; + + if ( player ) + { + vec3_t offset( 0, 0, -4 ); + + // adjust tracer position for player + for ( i = 0; i < 3; i++ ) + { + vecTracerSrc[ i ] = vecSrc[ i ] + offset[ i ] + right[ i ] * 2 + forward[ i ] * 16; + } + } + else + { + VectorCopy( vecSrc, vecTracerSrc ); + } + + if ( iTracerFreq != 1 ) // guns that always trace also always decal + tracer = 1; + + switch( iBulletType ) + { + case BULLET_PLAYER_MP5: + case BULLET_MONSTER_MP5: + case BULLET_MONSTER_9MM: + case BULLET_MONSTER_12MM: + default: + EV_CreateTracer( vecTracerSrc, end ); + break; + } + } + + return tracer; +} + +/* +================ +FireBullets + +Go to the trouble of combining multiple pellets into a single damage call. +================ +*/ +void EV_HLDM_FireBullets( int idx, float *forward, float *right, float *up, int cShots, float *vecSrc, float *vecDirShooting, float *vecSpread, float flDistance, int iBulletType, int iTracerFreq, int *tracerCount ) +{ + int i; + pmtrace_t tr; + int iShot; + vec3_t vecRight, vecUp; + int tracer; + + VectorCopy( right, vecRight ); + VectorCopy( up, vecUp ); + + for ( iShot = 1; iShot <= cShots; iShot++ ) + { + vec3_t vecDir, vecEnd; + + // get circular gaussian spread + vec3_t spread; + do { + spread[0] = gEngfuncs.pfnRandomFloat(-0.5,0.5) + gEngfuncs.pfnRandomFloat(-0.5,0.5); + spread[1] = gEngfuncs.pfnRandomFloat(-0.5,0.5) + gEngfuncs.pfnRandomFloat(-0.5,0.5); + spread[2] = spread[0] * spread[0] + spread[1] *spread[1]; + } while (spread[2] > 1); + + for ( i = 0 ; i < 3; i++ ) + { + vecDir[i] = vecDirShooting[i] + spread[ 0 ] * vecSpread[ 0 ] * vecRight[ i ] + spread[ 1 ] * vecSpread[ 1 ] * up [ i ]; + vecEnd[i] = vecSrc[ i ] + flDistance * vecDir[ i ]; + } + + gEngfuncs.pEventAPI->EV_SetUpPlayerPrediction( false, true ); + + // Store off the old count + gEngfuncs.pEventAPI->EV_PushPMStates(); + + // Now add in all of the players. + gEngfuncs.pEventAPI->EV_SetSolidPlayers ( idx - 1 ); + + gEngfuncs.pEventAPI->EV_SetTraceHull( 2 ); + gEngfuncs.pEventAPI->EV_PlayerTrace( vecSrc, vecEnd, PM_STUDIO_BOX, -1, &tr ); + + tracer = EV_HLDM_CheckTracer( idx, vecSrc, tr.endpos, forward, right, iBulletType, iTracerFreq, tracerCount ); + + // do damage, paint decals + if ( tr.fraction != 1.0 ) + { + switch(iBulletType) + { + default: + case BULLET_PLAYER_9MM: + if ( !tracer ) + { + EV_HLDM_PlayTextureSound( idx, &tr, vecSrc, vecEnd, iBulletType ); + EV_HLDM_DecalGunshot( &tr, iBulletType ); + } + break; + case BULLET_PLAYER_MP5: + if ( !tracer ) + { + EV_HLDM_PlayTextureSound( idx, &tr, vecSrc, vecEnd, iBulletType ); + EV_HLDM_DecalGunshot( &tr, iBulletType ); + } + break; + case BULLET_PLAYER_BUCKSHOT: + if ( !tracer ) + { + EV_HLDM_DecalGunshot( &tr, iBulletType ); + } + break; + case BULLET_PLAYER_357: + if ( !tracer ) + { + EV_HLDM_PlayTextureSound( idx, &tr, vecSrc, vecEnd, iBulletType ); + EV_HLDM_DecalGunshot( &tr, iBulletType ); + } + break; + + } + } + + gEngfuncs.pEventAPI->EV_PopPMStates(); + } +} + +void EV_FireGlock1( event_args_t *args ) +{ + int idx; + vec3_t origin; + vec3_t angles; + vec3_t velocity; + int empty; + + int i; + vec3_t ShellVelocity; + vec3_t ShellOrigin; + int shell; + vec3_t vecSrc, vecAiming; + vec3_t vecSpread; + vec3_t up, right, forward; + float flSpread = 0.01; + + idx = args->entindex; + VectorCopy( args->origin, origin ); + VectorCopy( args->angles, angles ); + VectorCopy( args->velocity, velocity ); + + empty = args->bparam1; + AngleVectors( angles, forward, right, up ); + + shell = gEngfuncs.pEventAPI->EV_FindModelIndex ("models/shell.mdl");// brass shell + + if ( EV_IsLocal( idx ) ) + { + EV_MuzzleFlash(); + gEngfuncs.pEventAPI->EV_WeaponAnimation( empty ? GLOCK_SHOOT_EMPTY : GLOCK_SHOOT, 2 ); + } + + EV_GetDefaultShellInfo( args, origin, velocity, ShellVelocity, ShellOrigin, forward, right, up, 20, -12, 4 ); + + EV_EjectBrass ( ShellOrigin, ShellVelocity, angles[ YAW ], shell, TE_BOUNCE_SHELL ); + + gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, "weapons/pl_gun3.wav", gEngfuncs.pfnRandomFloat(0.92, 1.0), ATTN_NORM, 0, 98 + gEngfuncs.pfnRandomLong( 0, 3 ) ); + + EV_GetGunPosition( args, vecSrc, origin ); + + VectorCopy( forward, vecAiming ); + + for ( i = 0; i < 3; i++ ) + { + vecSpread[ i ] = flSpread; + } + + EV_HLDM_FireBullets( idx, forward, right, up, 1, vecSrc, vecAiming, vecSpread, 8192, BULLET_PLAYER_9MM, 0, &tracerCount[idx-1] ); + + if ( EV_IsLocal( idx ) ) + { + V_PunchAxis( 0, -2.0 ); + } +} + +void EV_FireGlock2( event_args_t *args ) +{ + int idx; + vec3_t origin; + vec3_t angles; + vec3_t velocity; + + int i; + vec3_t ShellVelocity; + vec3_t ShellOrigin; + int shell; + vec3_t vecSrc, vecAiming; + vec3_t vecSpread; + vec3_t up, right, forward; + float flSpread = 0.1; + + idx = args->entindex; + VectorCopy( args->origin, origin ); + VectorCopy( args->angles, angles ); + VectorCopy( args->velocity, velocity ); + + AngleVectors( angles, forward, right, up ); + + shell = gEngfuncs.pEventAPI->EV_FindModelIndex ("models/shell.mdl");// brass shell + + if ( EV_IsLocal( idx ) ) + { + // Add muzzle flash to current weapon model + EV_MuzzleFlash(); + gEngfuncs.pEventAPI->EV_WeaponAnimation( GLOCK_SHOOT, 2 ); + } + + EV_GetDefaultShellInfo( args, origin, velocity, ShellVelocity, ShellOrigin, forward, right, up, 20, -12, 4 ); + + EV_EjectBrass ( ShellOrigin, ShellVelocity, angles[ YAW ], shell, TE_BOUNCE_SHELL ); + + gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, "weapons/pl_gun3.wav", gEngfuncs.pfnRandomFloat(0.92, 1.0), ATTN_NORM, 0, 98 + gEngfuncs.pfnRandomLong( 0, 3 ) ); + + EV_GetGunPosition( args, vecSrc, origin ); + + VectorCopy( forward, vecAiming ); + + for ( i = 0; i < 3; i++ ) + { + vecSpread[ i ] = flSpread; + } + + EV_HLDM_FireBullets( idx, forward, right, up, 1, vecSrc, vecAiming, vecSpread, 8192, BULLET_PLAYER_9MM, 0, &tracerCount[idx-1] ); + + if ( EV_IsLocal( idx ) ) + { + V_PunchAxis( 0, -2.0 ); + } +} + +void EV_FireShotGunDouble( event_args_t *args ) +{ + int idx; + vec3_t origin; + vec3_t angles; + vec3_t velocity; + + int i, j; + vec3_t ShellVelocity; + vec3_t ShellOrigin; + int shell; + vec3_t vecSrc, vecAiming; + vec3_t vecSpread; + vec3_t up, right, forward; + float flSpread = 0.01; + + idx = args->entindex; + VectorCopy( args->origin, origin ); + VectorCopy( args->angles, angles ); + VectorCopy( args->velocity, velocity ); + + AngleVectors( angles, forward, right, up ); + + shell = gEngfuncs.pEventAPI->EV_FindModelIndex ("models/shotgunshell.mdl");// brass shell + + if ( EV_IsLocal( idx ) ) + { + // Add muzzle flash to current weapon model + EV_MuzzleFlash(); + gEngfuncs.pEventAPI->EV_WeaponAnimation( SHOTGUN_FIRE2, 2 ); + } + + for ( j = 0; j < 2; j++ ) + { + EV_GetDefaultShellInfo( args, origin, velocity, ShellVelocity, ShellOrigin, forward, right, up, 32, -12, 6 ); + + EV_EjectBrass ( ShellOrigin, ShellVelocity, angles[ YAW ], shell, TE_BOUNCE_SHOTSHELL ); + } + + gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, "weapons/dbarrel1.wav", gEngfuncs.pfnRandomFloat(0.98, 1.0), ATTN_NORM, 0, 85 + gEngfuncs.pfnRandomLong( 0, 0x1f ) ); + + EV_GetGunPosition( args, vecSrc, origin ); + VectorCopy( forward, vecAiming ); + + if ( gEngfuncs.GetMaxClients() > 1 ) + { + for ( i = 0; i < 3; i++ ) + { + vecSpread[0] = 0.17365; + vecSpread[1] = 0.04362; + vecSpread[2] = 0.00; + } + + EV_HLDM_FireBullets( idx, forward, right, up, 8, vecSrc, vecAiming, vecSpread, 2048, BULLET_PLAYER_BUCKSHOT, 0, &tracerCount[idx-1] ); + } + else + { + EV_HLDM_FireBullets( idx, forward, right, up, 12, vecSrc, vecAiming, VECTOR_CONE_10DEGREES, 2048, BULLET_PLAYER_BUCKSHOT, 0, &tracerCount[idx-1] ); + } + + if ( EV_IsLocal( idx ) ) + { + V_PunchAxis( 0, -10.0 ); + } +} + +void EV_FireShotGunSingle( event_args_t *args ) +{ + int idx; + vec3_t origin; + vec3_t angles; + vec3_t velocity; + + int i; + vec3_t ShellVelocity; + vec3_t ShellOrigin; + int shell; + vec3_t vecSrc, vecAiming; + vec3_t vecSpread; + vec3_t up, right, forward; + float flSpread = 0.01; + + idx = args->entindex; + VectorCopy( args->origin, origin ); + VectorCopy( args->angles, angles ); + VectorCopy( args->velocity, velocity ); + + AngleVectors( angles, forward, right, up ); + + shell = gEngfuncs.pEventAPI->EV_FindModelIndex ("models/shotgunshell.mdl");// brass shell + + if ( EV_IsLocal( idx ) ) + { + // Add muzzle flash to current weapon model + EV_MuzzleFlash(); + gEngfuncs.pEventAPI->EV_WeaponAnimation( SHOTGUN_FIRE, 2 ); + } + + EV_GetDefaultShellInfo( args, origin, velocity, ShellVelocity, ShellOrigin, forward, right, up, 32, -12, 6 ); + + EV_EjectBrass ( ShellOrigin, ShellVelocity, angles[ YAW ], shell, TE_BOUNCE_SHOTSHELL ); + + gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, "weapons/sbarrel1.wav", gEngfuncs.pfnRandomFloat(0.95, 1.0), ATTN_NORM, 0, 93 + gEngfuncs.pfnRandomLong( 0, 0x1f ) ); + + EV_GetGunPosition( args, vecSrc, origin ); + VectorCopy( forward, vecAiming ); + + if ( gEngfuncs.GetMaxClients() > 1 ) + { + for ( i = 0; i < 3; i++ ) + { + vecSpread[0] = 0.08716; + vecSpread[1] = 0.04362; + vecSpread[2] = 0.00; + } + + EV_HLDM_FireBullets( idx, forward, right, up, 4, vecSrc, vecAiming, vecSpread, 2048, BULLET_PLAYER_BUCKSHOT, 0, &tracerCount[idx-1] ); + } + else + { + EV_HLDM_FireBullets( idx, forward, right, up, 6, vecSrc, vecAiming, VECTOR_CONE_10DEGREES, 2048, BULLET_PLAYER_BUCKSHOT, 0, &tracerCount[idx-1] ); + } + + if ( EV_IsLocal( idx ) ) + { + V_PunchAxis( 0, -5.0 ); + } +} + +void EV_FireMP5( event_args_t *args ) +{ + int idx; + vec3_t origin; + vec3_t angles; + vec3_t velocity; + + vec3_t ShellVelocity; + vec3_t ShellOrigin; + int shell; + vec3_t vecSrc, vecAiming; + vec3_t up, right, forward; + float flSpread = 0.01; + + idx = args->entindex; + VectorCopy( args->origin, origin ); + VectorCopy( args->angles, angles ); + VectorCopy( args->velocity, velocity ); + + AngleVectors( angles, forward, right, up ); + + shell = gEngfuncs.pEventAPI->EV_FindModelIndex ("models/shell.mdl");// brass shell + + if ( EV_IsLocal( idx ) ) + { + // Add muzzle flash to current weapon model + EV_MuzzleFlash(); + gEngfuncs.pEventAPI->EV_WeaponAnimation( MP5_FIRE1 + gEngfuncs.pfnRandomLong(0,2), 2 ); + } + + EV_GetDefaultShellInfo( args, origin, velocity, ShellVelocity, ShellOrigin, forward, right, up, 20, -12, 4 ); + + EV_EjectBrass ( ShellOrigin, ShellVelocity, angles[ YAW ], shell, TE_BOUNCE_SHELL ); + + switch( gEngfuncs.pfnRandomLong( 0, 1 ) ) + { + case 0: + gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, "weapons/hks1.wav", 1, ATTN_NORM, 0, 94 + gEngfuncs.pfnRandomLong( 0, 0xf ) ); + break; + case 1: + gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, "weapons/hks2.wav", 1, ATTN_NORM, 0, 94 + gEngfuncs.pfnRandomLong( 0, 0xf ) ); + break; + } + + EV_GetGunPosition( args, vecSrc, origin ); + VectorCopy( forward, vecAiming ); + + if ( gEngfuncs.GetMaxClients() > 1 ) + { + EV_HLDM_FireBullets( idx, forward, right, up, 1, vecSrc, vecAiming, VECTOR_CONE_6DEGREES, 8192, BULLET_PLAYER_MP5, 2, &tracerCount[idx-1] ); + } + else + { + EV_HLDM_FireBullets( idx, forward, right, up, 1, vecSrc, vecAiming, VECTOR_CONE_3DEGREES, 8192, BULLET_PLAYER_MP5, 2, &tracerCount[idx-1] ); + } + + if ( EV_IsLocal( idx ) ) + { + V_PunchAxis( 0, gEngfuncs.pfnRandomFloat( -2, 2 ) ); + } +} + +void EV_FirePython( event_args_t *args ) +{ + int idx; + vec3_t origin; + vec3_t angles; + vec3_t velocity; + + vec3_t vecSrc, vecAiming; + vec3_t up, right, forward; + float flSpread = 0.01; + + idx = args->entindex; + VectorCopy( args->origin, origin ); + VectorCopy( args->angles, angles ); + VectorCopy( args->velocity, velocity ); + + AngleVectors( angles, forward, right, up ); + + if ( EV_IsLocal( idx ) ) + { + // Python uses different body in multiplayer versus single player + int multiplayer = gEngfuncs.GetMaxClients() == 1 ? 0 : 1; + + // Add muzzle flash to current weapon model + EV_MuzzleFlash(); + gEngfuncs.pEventAPI->EV_WeaponAnimation( PYTHON_FIRE1, multiplayer ? 1 : 0 ); + } + + switch( gEngfuncs.pfnRandomLong( 0, 1 ) ) + { + case 0: + gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, "weapons/357_shot1.wav", gEngfuncs.pfnRandomFloat(0.8, 0.9), ATTN_NORM, 0, PITCH_NORM ); + break; + case 1: + gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, "weapons/357_shot2.wav", gEngfuncs.pfnRandomFloat(0.8, 0.9), ATTN_NORM, 0, PITCH_NORM ); + break; + } + + EV_GetGunPosition( args, vecSrc, origin ); + + VectorCopy( forward, vecAiming ); + + EV_HLDM_FireBullets( idx, forward, right, up, 1, vecSrc, vecAiming, VECTOR_CONE_1DEGREES, 8192, BULLET_PLAYER_357, 0, &tracerCount[idx-1] ); + + if ( EV_IsLocal( idx ) ) + { + V_PunchAxis( 0, -10.0 ); + } +} + +#define SND_CHANGE_PITCH (1<<7) // duplicated in protocol.h change sound pitch + +void EV_SpinGauss( event_args_t *args ) +{ + int idx; + vec3_t origin; + vec3_t angles; + vec3_t velocity; + int iSoundState = 0; + + int pitch; + + idx = args->entindex; + VectorCopy( args->origin, origin ); + VectorCopy( args->angles, angles ); + VectorCopy( args->velocity, velocity ); + + pitch = args->iparam1; + + iSoundState = args->bparam1 ? SND_CHANGE_PITCH : 0; + + gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, "ambience/pulsemachine.wav", 1.0, ATTN_NORM, iSoundState, pitch ); +} + +// FIXME, pass m_fPrimaryFire in as parameter!!! +void EV_FireGauss( event_args_t *args ) +{ + int idx; + vec3_t origin; + vec3_t angles; + vec3_t velocity; + float flDamage = args->fparam1; + int primaryfire = args->bparam1; + + int m_fPrimaryFire = args->bparam1; + int m_iWeaponVolume = GAUSS_PRIMARY_FIRE_VOLUME; + vec3_t vecSrc; + vec3_t vecDest; + edict_t *pentIgnore; + pmtrace_t tr, beam_tr; + float flMaxFrac = 1.0; + int nTotal = 0; + int fHasPunched = 0; + int fFirstBeam = 1; + int nMaxHits = 10; + physent_t *pEntity; + int m_iBeam, m_iGlow, m_iBalls; + vec3_t up, right, forward; + + idx = args->entindex; + VectorCopy( args->origin, origin ); + VectorCopy( args->angles, angles ); + VectorCopy( args->velocity, velocity ); + + // Make sure we don't have a gauss spin event in the queue for this guy + gEngfuncs.pEventAPI->EV_KillEvents( idx, "events/gaussspin.sc" ); + +// Con_Printf( "Firing gauss with %f\n", flDamage ); + EV_GetGunPosition( args, vecSrc, origin ); + + m_iBeam = gEngfuncs.pEventAPI->EV_FindModelIndex( "sprites/smoke.spr" ); + m_iBalls = m_iGlow = gEngfuncs.pEventAPI->EV_FindModelIndex( "sprites/hotglow.spr" ); + + AngleVectors( angles, forward, right, up ); + + VectorMA( vecSrc, 8192, forward, vecDest ); + + if ( EV_IsLocal( idx ) ) + { + V_PunchAxis( 0, -2.0 ); + gEngfuncs.pEventAPI->EV_WeaponAnimation( GAUSS_FIRE2, 2 ); + } + + gEngfuncs.pEventAPI->EV_StopSound( idx, CHAN_WEAPON, "ambience/pulsemachine.wav" ); + + gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, "weapons/gauss2.wav", 0.5 + flDamage * (1.0 / 400.0), ATTN_NORM, 0, 85 + gEngfuncs.pfnRandomLong( 0, 0x1f ) ); + + while (flDamage > 10 && nMaxHits > 0) + { + nMaxHits--; + + gEngfuncs.pEventAPI->EV_SetUpPlayerPrediction( false, true ); + + // Store off the old count + gEngfuncs.pEventAPI->EV_PushPMStates(); + + // Now add in all of the players. + gEngfuncs.pEventAPI->EV_SetSolidPlayers ( idx - 1 ); + + gEngfuncs.pEventAPI->EV_SetTraceHull( 2 ); + gEngfuncs.pEventAPI->EV_PlayerTrace( vecSrc, vecDest, PM_STUDIO_BOX, -1, &tr ); + + gEngfuncs.pEventAPI->EV_PopPMStates(); + + if ( tr.allsolid ) + break; + + pEntity = gEngfuncs.pEventAPI->EV_GetPhysent( tr.ent ); + if ( pEntity == NULL ) + break; + + if (fFirstBeam) + { + if ( EV_IsLocal( idx ) ) + { + // Add muzzle flash to current weapon model + EV_MuzzleFlash(); + } + fFirstBeam = 0; + + gEngfuncs.pEfxAPI->R_BeamEntPoint( + idx | 0x1000, + tr.endpos, + m_iBeam, + 0.1, + m_fPrimaryFire ? 1.0 : 2.5, + 0.0, + m_fPrimaryFire ? 128.0 : flDamage, + 0, + 0, + 0, + m_fPrimaryFire ? 255 : 255, + m_fPrimaryFire ? 128 : 255, + m_fPrimaryFire ? 0 : 255 + ); + } + else + { + gEngfuncs.pEfxAPI->R_BeamPoints( vecSrc, + tr.endpos, + m_iBeam, + 0.1, + m_fPrimaryFire ? 1.0 : 2.5, + 0.0, + m_fPrimaryFire ? 128.0 : flDamage, + 0, + 0, + 0, + m_fPrimaryFire ? 255 : 255, + m_fPrimaryFire ? 128 : 255, + m_fPrimaryFire ? 0 : 255 + ); + } + + if ( pEntity->solid == SOLID_BSP ) + { + float n; + + pentIgnore = NULL; + + n = -DotProduct( tr.plane.normal, forward ); + + if (n < 0.5) // 60 degrees + { + // ALERT( at_console, "reflect %f\n", n ); + // reflect + vec3_t r; + + VectorMA( forward, 2.0 * n, tr.plane.normal, r ); + + flMaxFrac = flMaxFrac - tr.fraction; + + VectorCopy( r, forward ); + + VectorMA( tr.endpos, 8.0, forward, vecSrc ); + VectorMA( vecSrc, 8192.0, forward, vecDest ); + + gEngfuncs.pEfxAPI->R_TempSprite( tr.endpos, vec3_origin, 0.2, m_iGlow, kRenderGlow, kRenderFxNoDissipation, flDamage * n / 255.0, flDamage * n * 0.5 * 0.1, FTENT_FADEOUT ); + + { + vec3_t fwd; + VectorAdd( tr.endpos, tr.plane.normal, fwd ); + gEngfuncs.pEfxAPI->R_Sprite_Trail( TE_SPRITETRAIL, tr.endpos, fwd, m_iBalls, (int)(n * flDamage * 0.3), 0.1, gEngfuncs.pfnRandomFloat( 10, 20 ) / 100.0, 100, + 255, 200 ); + } + + // lose energy + if ( n == 0 ) + { + n = 0.1; + } + + flDamage = flDamage * (1 - n); + + } + else + { + // tunnel + EV_HLDM_DecalGunshot( &tr, BULLET_MONSTER_12MM ); + + gEngfuncs.pEfxAPI->R_TempSprite( tr.endpos, vec3_origin, 1.0, m_iGlow, kRenderGlow, kRenderFxNoDissipation, flDamage / 255.0, 6.0, FTENT_FADEOUT ); + + // limit it to one hole punch + if (fHasPunched) + { + break; + } + fHasPunched = 1; + + // try punching through wall if secondary attack (primary is incapable of breaking through) + if ( !m_fPrimaryFire ) + { + vec3_t start; + + VectorMA( tr.endpos, 8.0, forward, start ); + + // Store off the old count + gEngfuncs.pEventAPI->EV_PushPMStates(); + + // Now add in all of the players. + gEngfuncs.pEventAPI->EV_SetSolidPlayers ( idx - 1 ); + + gEngfuncs.pEventAPI->EV_SetTraceHull( 2 ); + gEngfuncs.pEventAPI->EV_PlayerTrace( start, vecDest, PM_STUDIO_BOX, -1, &beam_tr ); + + if ( !beam_tr.allsolid ) + { + vec3_t delta; + float n; + + // trace backwards to find exit point + + gEngfuncs.pEventAPI->EV_PlayerTrace( beam_tr.endpos, tr.endpos, PM_STUDIO_BOX, -1, &beam_tr ); + + VectorSubtract( beam_tr.endpos, tr.endpos, delta ); + + n = Length( delta ); + + if (n < flDamage) + { + if (n == 0) + n = 1; + flDamage -= n; + + // absorption balls + { + vec3_t fwd; + VectorSubtract( tr.endpos, forward, fwd ); + gEngfuncs.pEfxAPI->R_Sprite_Trail( TE_SPRITETRAIL, tr.endpos, fwd, m_iBalls, 3, 0.1, gEngfuncs.pfnRandomFloat( 10, 20 ) / 100.0, 100, + 255, 100 ); + } + + //////////////////////////////////// WHAT TO DO HERE + // CSoundEnt::InsertSound ( bits_SOUND_COMBAT, pev->origin, NORMAL_EXPLOSION_VOLUME, 3.0 ); + + EV_HLDM_DecalGunshot( &beam_tr, BULLET_MONSTER_12MM ); + + gEngfuncs.pEfxAPI->R_TempSprite( beam_tr.endpos, vec3_origin, 0.1, m_iGlow, kRenderGlow, kRenderFxNoDissipation, flDamage / 255.0, 6.0, FTENT_FADEOUT ); + + // balls + { + vec3_t fwd; + VectorSubtract( beam_tr.endpos, forward, fwd ); + gEngfuncs.pEfxAPI->R_Sprite_Trail( TE_SPRITETRAIL, beam_tr.endpos, fwd, m_iBalls, (int)(flDamage * 0.3), 0.1, gEngfuncs.pfnRandomFloat( 10, 20 ) / 100.0, 200, + 255, 40 ); + } + + VectorAdd( beam_tr.endpos, forward, vecSrc ); + } + } + else + { + flDamage = 0; + } + + gEngfuncs.pEventAPI->EV_PopPMStates(); + } + else + { + if ( m_fPrimaryFire ) + { + // slug doesn't punch through ever with primary + // fire, so leave a little glowy bit and make some balls + gEngfuncs.pEfxAPI->R_TempSprite( tr.endpos, vec3_origin, 0.2, m_iGlow, kRenderGlow, kRenderFxNoDissipation, 200.0 / 255.0, 0.3, FTENT_FADEOUT ); + + { + vec3_t fwd; + VectorAdd( tr.endpos, tr.plane.normal, fwd ); + gEngfuncs.pEfxAPI->R_Sprite_Trail( TE_SPRITETRAIL, tr.endpos, fwd, m_iBalls, 8, 0.6, gEngfuncs.pfnRandomFloat( 10, 20 ) / 100.0, 100, + 255, 200 ); + } + } + + flDamage = 0; + } + } + } + else + { + VectorAdd( tr.endpos, forward, vecSrc ); + } + } +} + +void EV_TrainPitchAdjust( event_args_t *args ) +{ + int idx; + vec3_t origin; + + unsigned short us_params; + int noise; + float m_flVolume; + int pitch; + int stop; + + char sz[ 256 ]; + + idx = args->entindex; + + VectorCopy( args->origin, origin ); + + us_params = (unsigned short)args->iparam1; + stop = args->bparam1; + + m_flVolume = (float)(us_params & 0x003f)/40.0; + noise = (int)(((us_params) >> 12 ) & 0x0007); + pitch = (int)( 10.0 * (float)( ( us_params >> 6 ) & 0x003f ) ); + + switch ( noise ) + { + case 1: strcpy( sz, "plats/ttrain1.wav"); break; + case 2: strcpy( sz, "plats/ttrain2.wav"); break; + case 3: strcpy( sz, "plats/ttrain3.wav"); break; + case 4: strcpy( sz, "plats/ttrain4.wav"); break; + case 5: strcpy( sz, "plats/ttrain6.wav"); break; + case 6: strcpy( sz, "plats/ttrain7.wav"); break; + default: + // no sound + strcpy( sz, "" ); + return; + } + + if ( stop ) + { + gEngfuncs.pEventAPI->EV_StopSound( idx, CHAN_STATIC, sz ); + } + else + { + gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_STATIC, sz, m_flVolume, ATTN_NORM, SND_CHANGE_PITCH, pitch ); + } +} + +int EV_TFC_IsAllyTeam( int iTeam1, int iTeam2 ) +{ + return 0; +} \ No newline at end of file diff --git a/cl_dll/ev_hldm.h b/cl_dll/ev_hldm.h new file mode 100644 index 0000000..9857b34 --- /dev/null +++ b/cl_dll/ev_hldm.h @@ -0,0 +1,88 @@ +#if !defined ( EV_HLDMH ) +#define EV_HLDMH + +// bullet types +typedef enum +{ + BULLET_NONE = 0, + BULLET_PLAYER_9MM, // glock + BULLET_PLAYER_MP5, // mp5 + BULLET_PLAYER_357, // python + BULLET_PLAYER_BUCKSHOT, // shotgun + BULLET_PLAYER_CROWBAR, // crowbar swipe + + BULLET_MONSTER_9MM, + BULLET_MONSTER_MP5, + BULLET_MONSTER_12MM, +} Bullet; + +enum glock_e { + GLOCK_IDLE1 = 0, + GLOCK_IDLE2, + GLOCK_IDLE3, + GLOCK_SHOOT, + GLOCK_SHOOT_EMPTY, + GLOCK_RELOAD, + GLOCK_RELOAD_NOT_EMPTY, + GLOCK_DRAW, + GLOCK_HOLSTER, + GLOCK_ADD_SILENCER +}; + +enum shotgun_e { + SHOTGUN_IDLE = 0, + SHOTGUN_FIRE, + SHOTGUN_FIRE2, + SHOTGUN_RELOAD, + SHOTGUN_PUMP, + SHOTGUN_START_RELOAD, + SHOTGUN_DRAW, + SHOTGUN_HOLSTER, + SHOTGUN_IDLE4, + SHOTGUN_IDLE_DEEP +}; + +enum mp5_e +{ + MP5_LONGIDLE = 0, + MP5_IDLE1, + MP5_LAUNCH, + MP5_RELOAD, + MP5_DEPLOY, + MP5_FIRE1, + MP5_FIRE2, + MP5_FIRE3, +}; + +enum python_e { + PYTHON_IDLE1 = 0, + PYTHON_FIDGET, + PYTHON_FIRE1, + PYTHON_RELOAD, + PYTHON_HOLSTER, + PYTHON_DRAW, + PYTHON_IDLE2, + PYTHON_IDLE3 +}; + +#define GAUSS_PRIMARY_CHARGE_VOLUME 256// how loud gauss is while charging +#define GAUSS_PRIMARY_FIRE_VOLUME 450// how loud gauss is when discharged + +enum gauss_e { + GAUSS_IDLE = 0, + GAUSS_IDLE2, + GAUSS_FIDGET, + GAUSS_SPINUP, + GAUSS_SPIN, + GAUSS_FIRE, + GAUSS_FIRE2, + GAUSS_HOLSTER, + GAUSS_DRAW +}; + +void EV_HLDM_GunshotDecalTrace( pmtrace_t *pTrace, char *decalName ); +void EV_HLDM_DecalGunshot( pmtrace_t *pTrace, int iBulletType ); +int EV_HLDM_CheckTracer( int idx, float *vecSrc, float *end, float *forward, float *right, int iBulletType, int iTracerFreq, int *tracerCount ); +void EV_HLDM_FireBullets( int idx, float *forward, float *right, float *up, int cShots, float *vecSrc, float *vecDirShooting, float *vecSpread, float flDistance, int iBulletType, int iTracerFreq, int *tracerCount ); + +#endif // EV_HLDMH \ No newline at end of file diff --git a/cl_dll/events.cpp b/cl_dll/events.cpp new file mode 100644 index 0000000..60061f1 --- /dev/null +++ b/cl_dll/events.cpp @@ -0,0 +1,16 @@ +#include "hud.h" +#include "cl_util.h" + +void Game_HookEvents( void ); + +/* +=================== +EV_HookEvents + +See if game specific code wants to hook any events. +=================== +*/ +void EV_HookEvents( void ) +{ + Game_HookEvents(); +} \ No newline at end of file diff --git a/cl_dll/eventscripts.h b/cl_dll/eventscripts.h new file mode 100644 index 0000000..b946ae4 --- /dev/null +++ b/cl_dll/eventscripts.h @@ -0,0 +1,66 @@ +// eventscripts.h +#if !defined ( EVENTSCRIPTSH ) +#define EVENTSCRIPTSH + +// defaults for clientinfo messages +#define DEFAULT_VIEWHEIGHT 28 +#define VEC_DUCK_VIEW 12 + +#define FTENT_FADEOUT 0x00000080 + +#define DMG_GENERIC 0 // generic damage was done +#define DMG_CRUSH (1 << 0) // crushed by falling or moving object +#define DMG_BULLET (1 << 1) // shot +#define DMG_SLASH (1 << 2) // cut, clawed, stabbed +#define DMG_BURN (1 << 3) // heat burned +#define DMG_FREEZE (1 << 4) // frozen +#define DMG_FALL (1 << 5) // fell too far +#define DMG_BLAST (1 << 6) // explosive blast damage +#define DMG_CLUB (1 << 7) // crowbar, punch, headbutt +#define DMG_SHOCK (1 << 8) // electric shock +#define DMG_SONIC (1 << 9) // sound pulse shockwave +#define DMG_ENERGYBEAM (1 << 10) // laser or other high energy beam +#define DMG_NEVERGIB (1 << 12) // with this bit OR'd in, no damage type will be able to gib victims upon death +#define DMG_ALWAYSGIB (1 << 13) // with this bit OR'd in, any damage type can be made to gib victims upon death. + +// time-based damage +//mask off TF-specific stuff too +#define DMG_TIMEBASED (~(0xff003fff)) // mask for time-based damage + +#define DMG_DROWN (1 << 14) // Drowning +#define DMG_FIRSTTIMEBASED DMG_DROWN + +#define DMG_PARALYZE (1 << 15) // slows affected creature down +#define DMG_NERVEGAS (1 << 16) // nerve toxins, very bad +#define DMG_POISON (1 << 17) // blood poisioning +#define DMG_RADIATION (1 << 18) // radiation exposure +#define DMG_DROWNRECOVER (1 << 19) // drowning recovery +#define DMG_ACID (1 << 20) // toxic chemicals or acid burns +#define DMG_SLOWBURN (1 << 21) // in an oven +#define DMG_SLOWFREEZE (1 << 22) // in a subzero freezer +#define DMG_MORTAR (1 << 23) // Hit by air raid (done to distinguish grenade from mortar) + +//TF ADDITIONS +#define DMG_IGNITE (1 << 24) // Players hit by this begin to burn +#define DMG_RADIUS_MAX (1 << 25) // Radius damage with this flag doesn't decrease over distance +#define DMG_RADIUS_QUAKE (1 << 26) // Radius damage is done like Quake. 1/2 damage at 1/2 radius. +#define DMG_IGNOREARMOR (1 << 27) // Damage ignores target's armor +#define DMG_AIMED (1 << 28) // Does Hit location damage +#define DMG_WALLPIERCING (1 << 29) // Blast Damages ents through walls + +#define DMG_CALTROP (1<<30) +#define DMG_HALLUC (1<<31) + +// Some of these are HL/TFC specific? +void EV_EjectBrass( float *origin, float *velocity, float rotation, int model, int soundtype ); +void EV_GetGunPosition( struct event_args_s *args, float *pos, float *origin ); +void EV_GetDefaultShellInfo( struct event_args_s *args, float *origin, float *velocity, float *ShellVelocity, float *ShellOrigin, float *forward, float *right, float *up, float forwardScale, float upScale, float rightScale ); +qboolean EV_IsLocal( int idx ); +qboolean EV_IsPlayer( int idx ); +void EV_CreateTracer( float *start, float *end ); + +struct cl_entity_s *GetEntity( int idx ); +struct cl_entity_s *GetViewEntity( void ); +void EV_MuzzleFlash( void ); + +#endif // EVENTSCRIPTSH diff --git a/cl_dll/flashlight.cpp b/cl_dll/flashlight.cpp index 69361a9..ffe8156 100644 --- a/cl_dll/flashlight.cpp +++ b/cl_dll/flashlight.cpp @@ -19,7 +19,7 @@ // #include "hud.h" -#include "util.h" +#include "cl_util.h" #include "parsemsg.h" #include diff --git a/cl_dll/geiger.cpp b/cl_dll/geiger.cpp index 21d0abc..dc2575f 100644 --- a/cl_dll/geiger.cpp +++ b/cl_dll/geiger.cpp @@ -19,7 +19,7 @@ // #include "hud.h" -#include "util.h" +#include "cl_util.h" #include #include #include diff --git a/cl_dll/health.cpp b/cl_dll/health.cpp index df238cf..3d9268e 100644 --- a/cl_dll/health.cpp +++ b/cl_dll/health.cpp @@ -23,7 +23,7 @@ #include "MATH.H" #include "hud.h" -#include "util.h" +#include "cl_util.h" #include "parsemsg.h" #include diff --git a/cl_dll/health.h b/cl_dll/health.h index 59e401e..a67fdd4 100644 --- a/cl_dll/health.h +++ b/cl_dll/health.h @@ -110,6 +110,9 @@ public: int m_iHealth; int m_HUD_dmg_bio; int m_HUD_cross; + float m_fAttackFront, m_fAttackRear, m_fAttackLeft, m_fAttackRight; + void GetPainColor( int &r, int &g, int &b ); + float m_fFade; private: HSPRITE m_hSprite; @@ -117,11 +120,8 @@ private: DAMAGE_IMAGE m_dmg[NUM_DMG_TYPES]; int m_bitsDamage; - float m_fFade; - void GetPainColor( int &r, int &g, int &b ); int DrawPain(float fTime); int DrawDamage(float fTime); - float m_fAttackFront, m_fAttackRear, m_fAttackLeft, m_fAttackRight; void CalcDamageDirection(vec3_t vecFrom); void UpdateTiles(float fTime, long bits); }; diff --git a/cl_dll/hl/hl_baseentity.cpp b/cl_dll/hl/hl_baseentity.cpp new file mode 100644 index 0000000..68934de --- /dev/null +++ b/cl_dll/hl/hl_baseentity.cpp @@ -0,0 +1,250 @@ +/*** +* +* Copyright (c) 1999, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ + +/* +========================== +This file contains "stubs" of class member implementations so that we can predict certain + weapons client side. From time to time you might find that you need to implement part of the + these functions. If so, cut it from here, paste it in hl_weapons.cpp or somewhere else and + add in the functionality you need. +========================== +*/ +#include "extdll.h" +#include "util.h" +#include "cbase.h" +#include "player.h" +#include "weapons.h" +#include "nodes.h" + +// Globals used by game logic +const Vector g_vecZero = Vector( 0, 0, 0 ); +int gmsgWeapPickup = 0; +enginefuncs_t g_engfuncs; +globalvars_t *gpGlobals; + +ItemInfo CBasePlayerItem::ItemInfoArray[MAX_WEAPONS]; + +void EMIT_SOUND_DYN(edict_t *entity, int channel, const char *sample, float volume, float attenuation, int flags, int pitch) { } + +// CBaseEntity Stubs +int CBaseEntity :: TakeHealth( float flHealth, int bitsDamageType ) { return 1; } +int CBaseEntity :: TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType ) { return 1; } +CBaseEntity *CBaseEntity::GetNextTarget( void ) { return NULL; } +int CBaseEntity::Save( CSave &save ) { return 1; } +int CBaseEntity::Restore( CRestore &restore ) { return 1; } +void CBaseEntity::SetObjectCollisionBox( void ) { } +int CBaseEntity :: Intersects( CBaseEntity *pOther ) { return 0; } +void CBaseEntity :: MakeDormant( void ) { } +int CBaseEntity :: IsDormant( void ) { return 0; } +BOOL CBaseEntity :: IsInWorld( void ) { return TRUE; } +int CBaseEntity::ShouldToggle( USE_TYPE useType, BOOL currentState ) { return 0; } +int CBaseEntity :: DamageDecal( int bitsDamageType ) { return -1; } +CBaseEntity * CBaseEntity::Create( char *szName, const Vector &vecOrigin, const Vector &vecAngles, edict_t *pentOwner ) { return NULL; } +void CBaseEntity::SUB_Remove( void ) { } + +// CBaseDelay Stubs +void CBaseDelay :: KeyValue( struct KeyValueData_s * ) { } +int CBaseDelay::Restore( class CRestore & ) { return 1; } +int CBaseDelay::Save( class CSave & ) { return 1; } + +// CBaseAnimating Stubs +int CBaseAnimating::Restore( class CRestore & ) { return 1; } +int CBaseAnimating::Save( class CSave & ) { return 1; } + +// DEBUG Stubs +edict_t *DBG_EntOfVars( const entvars_t *pev ) { return NULL; } +void DBG_AssertFunction(BOOL fExpr, const char* szExpr, const char* szFile, int szLine, const char* szMessage) { } + +// UTIL_* Stubs +void UTIL_PrecacheOther( const char *szClassname ) { } +void UTIL_BloodDrips( const Vector &origin, const Vector &direction, int color, int amount ) { } +void UTIL_DecalTrace( TraceResult *pTrace, int decalNumber ) { } +void UTIL_GunshotDecalTrace( TraceResult *pTrace, int decalNumber ) { } +void UTIL_MakeVectors( const Vector &vecAngles ) { } +BOOL UTIL_IsValidEntity( edict_t *pent ) { return TRUE; } +void UTIL_SetOrigin( entvars_t *, const Vector &org ) { } +BOOL UTIL_GetNextBestWeapon( CBasePlayer *pPlayer, CBasePlayerItem *pCurrentWeapon ) { return TRUE; } +void UTIL_LogPrintf(char *,...) { } +void UTIL_ClientPrintAll( int,char const *,char const *,char const *,char const *,char const *) { } +void ClientPrint( entvars_t *client, int msg_dest, const char *msg_name, const char *param1, const char *param2, const char *param3, const char *param4 ) { } + +// CBaseToggle Stubs +int CBaseToggle::Restore( class CRestore & ) { return 1; } +int CBaseToggle::Save( class CSave & ) { return 1; } +void CBaseToggle :: KeyValue( struct KeyValueData_s * ) { } + +// CGrenade Stubs +void CGrenade::BounceSound( void ) { } +void CGrenade::Explode( Vector, Vector ) { } +void CGrenade::Explode( TraceResult *, int ) { } +void CGrenade::Killed( entvars_t *, int ) { } +void CGrenade::Spawn( void ) { } + +CBaseEntity* CBaseMonster :: CheckTraceHullAttack( float flDist, int iDamage, int iDmgType ) { return NULL; } +void CBaseMonster :: Look ( int iDistance ) { } +float CBaseAnimating :: StudioFrameAdvance ( float flInterval ) { return 0.0; } +int CBaseMonster::IRelationship ( CBaseEntity *pTarget ) { return 0; } +CBaseEntity *CBaseMonster :: BestVisibleEnemy ( void ) { return NULL; } +BOOL CBaseMonster :: FInViewCone ( CBaseEntity *pEntity ) { return FALSE; } +BOOL CBaseMonster :: FInViewCone ( Vector *pOrigin ) { return FALSE; } +BOOL CBaseEntity :: FVisible ( CBaseEntity *pEntity ) { return FALSE; } +BOOL CBaseEntity :: FVisible ( const Vector &vecOrigin ) { return FALSE; } +void CBaseMonster :: MakeIdealYaw( Vector vecTarget ) { } +float CBaseMonster::ChangeYaw ( int yawSpeed ) { return 0; } +int CBaseAnimating :: LookupActivity ( int activity ) { return 0; } +int CBaseAnimating :: LookupActivityHeaviest ( int activity ) { return 0; } +int CBaseAnimating :: LookupSequence ( const char *label ) { return 0; } +void CBaseAnimating :: ResetSequenceInfo ( ) { } +BOOL CBaseAnimating :: GetSequenceFlags( ) { return FALSE; } +void CBaseAnimating :: DispatchAnimEvents ( float flInterval ) { } +float CBaseAnimating :: SetBoneController ( int iController, float flValue ) { return 0.0; } +void CBaseAnimating :: InitBoneControllers ( void ) { } +float CBaseAnimating :: SetBlending ( int iBlender, float flValue ) { return 0; } +void CBaseAnimating :: GetBonePosition ( int iBone, Vector &origin, Vector &angles ) { } +void CBaseAnimating :: GetAttachment ( int iAttachment, Vector &origin, Vector &angles ) { } +int CBaseAnimating :: FindTransition( int iEndingSequence, int iGoalSequence, int *piDir ) { return -1; } +void CBaseAnimating :: GetAutomovement( Vector &origin, Vector &angles, float flInterval ) { } +void CBaseAnimating :: SetBodygroup( int iGroup, int iValue ) { } +int CBaseAnimating :: GetBodygroup( int iGroup ) { return 0; } +void CBaseEntity::TraceAttack(entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType) { } +void CBaseEntity::FireBullets(ULONG cShots, Vector vecSrc, Vector vecDirShooting, Vector vecSpread, float flDistance, int iBulletType, int iTracerFreq, int iDamage, entvars_t *pevAttacker ) { } +void CBaseEntity :: TraceBleed( float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType ) { } +void CBaseMonster :: MakeDamageBloodDecal ( int cCount, float flNoise, TraceResult *ptr, const Vector &vecDir ) { } +void CBaseMonster::ReportAIState( void ) { } +void CBaseMonster :: KeyValue( KeyValueData *pkvd ) { } +BOOL CBaseMonster :: FCheckAITrigger ( void ) { return FALSE; } +void CBaseMonster::CorpseFallThink( void ) { } +void CBaseMonster :: MonsterInitDead( void ) { } +void CBaseMonster :: TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType) { } +BOOL CBaseMonster :: ShouldFadeOnDeath( void ) { return FALSE; } +void CBaseMonster :: RadiusDamage(entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int iClassIgnore, int bitsDamageType ) { } +void CBaseMonster :: RadiusDamage( Vector vecSrc, entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int iClassIgnore, int bitsDamageType ) { } +void CBaseMonster::FadeMonster( void ) { } +void CBaseMonster :: GibMonster( void ) { } +BOOL CBaseMonster :: HasHumanGibs( void ) { return FALSE; } +BOOL CBaseMonster :: HasAlienGibs( void ) { return FALSE; } +Activity CBaseMonster :: GetDeathActivity ( void ) { return ACT_DIE_HEADSHOT; } +void CBaseMonster::BecomeDead( void ) {} +void CBaseMonster :: Killed( entvars_t *pevAttacker, int iGib ) {} +int CBaseMonster :: TakeHealth (float flHealth, int bitsDamageType) { return 0; } +int CBaseMonster :: TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ) { return 0; } + +int TrainSpeed(int iSpeed, int iMax) { return 0; } +void CBasePlayer :: DeathSound( void ) { } +int CBasePlayer :: TakeHealth( float flHealth, int bitsDamageType ) { return 0; } +void CBasePlayer :: TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType) { } +int CBasePlayer :: TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ) { return 0; } +void CBasePlayer::RemoveAllItems( BOOL removeSuit ) { } +void CBasePlayer::SetAnimation( PLAYER_ANIM playerAnim ) { } +void CBasePlayer::WaterMove() { } +BOOL CBasePlayer::IsOnLadder( void ) { return FALSE; } +void CBasePlayer::PlayerDeathThink(void) { } +void CBasePlayer::StartDeathCam( void ) { } +void CBasePlayer::StartObserver( Vector vecPosition, Vector vecViewAngle ) { } +void CBasePlayer::PlayerUse ( void ) { } +void CBasePlayer::Jump() { } +void CBasePlayer::Duck( ) { } +int CBasePlayer::Classify ( void ) { return 0; } +void CBasePlayer :: PlayStepSound(int step, float fvol) { } +void CBasePlayer :: UpdateStepSound( void ) { } +void CBasePlayer::PreThink(void) { } +void CBasePlayer::CheckTimeBasedDamage() { } +void CBasePlayer :: UpdateGeigerCounter( void ) { } +void CBasePlayer::CheckSuitUpdate() { } +void CBasePlayer::SetSuitUpdate(char *name, int fgroup, int iNoRepeatTime) { } +void CBasePlayer :: UpdatePlayerSound ( void ) { } +void CBasePlayer::PostThink() { } +void CBasePlayer :: Precache( void ) { } +int CBasePlayer::Save( CSave &save ) { return 0; } +void CBasePlayer::RenewItems(void) { } +int CBasePlayer::Restore( CRestore &restore ) { return 0; } +void CBasePlayer::SelectNextItem( int iItem ) { } +BOOL CBasePlayer::HasWeapons( void ) { return FALSE; } +void CBasePlayer::SelectPrevItem( int iItem ) { } +CBaseEntity *FindEntityForward( CBaseEntity *pMe ) { return NULL; } +BOOL CBasePlayer :: FlashlightIsOn( void ) { return FALSE; } +void CBasePlayer :: FlashlightTurnOn( void ) { } +void CBasePlayer :: FlashlightTurnOff( void ) { } +void CBasePlayer :: ForceClientDllUpdate( void ) { } +void CBasePlayer::ImpulseCommands( ) { } +void CBasePlayer::CheatImpulseCommands( int iImpulse ) { } +int CBasePlayer::AddPlayerItem( CBasePlayerItem *pItem ) { return FALSE; } +int CBasePlayer::RemovePlayerItem( CBasePlayerItem *pItem ) { return FALSE; } +void CBasePlayer::ItemPreFrame() { } +void CBasePlayer::ItemPostFrame() { } +int CBasePlayer::AmmoInventory( int iAmmoIndex ) { return -1; } +int CBasePlayer::GetAmmoIndex(const char *psz) { return -1; } +void CBasePlayer::SendAmmoUpdate(void) { } +void CBasePlayer :: UpdateClientData( void ) { } +BOOL CBasePlayer :: FBecomeProne ( void ) { return TRUE; } +void CBasePlayer :: BarnacleVictimBitten ( entvars_t *pevBarnacle ) { } +void CBasePlayer :: BarnacleVictimReleased ( void ) { } +int CBasePlayer :: Illumination( void ) { return 0; } +void CBasePlayer :: EnableControl(BOOL fControl) { } +Vector CBasePlayer :: GetAutoaimVector( float flDelta ) { return g_vecZero; } +Vector CBasePlayer :: AutoaimDeflection( Vector &vecSrc, float flDist, float flDelta ) { return g_vecZero; } +void CBasePlayer :: ResetAutoaim( ) { } +void CBasePlayer :: SetCustomDecalFrames( int nFrames ) { } +int CBasePlayer :: GetCustomDecalFrames( void ) { return -1; } +void CBasePlayer::DropPlayerItem ( char *pszItemName ) { } +BOOL CBasePlayer::HasPlayerItem( CBasePlayerItem *pCheckItem ) { return FALSE; } +BOOL CBasePlayer :: SwitchWeapon( CBasePlayerItem *pWeapon ) { return FALSE; } +Vector CBasePlayer :: GetGunPosition( void ) { return g_vecZero; } +const char *CBasePlayer::TeamID( void ) { return ""; } +int CBasePlayer :: GiveAmmo( int iCount, char *szName, int iMax ) { return 0; } +void CBasePlayer::AddPoints( int score, BOOL bAllowNegativeScore ) { } +void CBasePlayer::AddPointsToTeam( int score, BOOL bAllowNegativeScore ) { } + +void ClearMultiDamage(void) { } +void ApplyMultiDamage(entvars_t *pevInflictor, entvars_t *pevAttacker ) { } +void AddMultiDamage( entvars_t *pevInflictor, CBaseEntity *pEntity, float flDamage, int bitsDamageType) { } +void SpawnBlood(Vector vecSpot, int bloodColor, float flDamage) { } +int DamageDecal( CBaseEntity *pEntity, int bitsDamageType ) { return 0; } +void DecalGunshot( TraceResult *pTrace, int iBulletType ) { } +void EjectBrass ( const Vector &vecOrigin, const Vector &vecVelocity, float rotation, int model, int soundtype ) { } +void AddAmmoNameToAmmoRegistry( const char *szAmmoname ) { } +int CBasePlayerItem::Restore( class CRestore & ) { return 1; } +int CBasePlayerItem::Save( class CSave & ) { return 1; } +int CBasePlayerWeapon::Restore( class CRestore & ) { return 1; } +int CBasePlayerWeapon::Save( class CSave & ) { return 1; } +void CBasePlayerItem :: SetObjectCollisionBox( void ) { } +void CBasePlayerItem :: FallInit( void ) { } +void CBasePlayerItem::FallThink ( void ) { } +void CBasePlayerItem::Materialize( void ) { } +void CBasePlayerItem::AttemptToMaterialize( void ) { } +void CBasePlayerItem :: CheckRespawn ( void ) { } +CBaseEntity* CBasePlayerItem::Respawn( void ) { return NULL; } +void CBasePlayerItem::DefaultTouch( CBaseEntity *pOther ) { } +void CBasePlayerItem::DestroyItem( void ) { } +int CBasePlayerItem::AddToPlayer( CBasePlayer *pPlayer ) { return TRUE; } +void CBasePlayerItem::Drop( void ) { } +void CBasePlayerItem::Kill( void ) { } +void CBasePlayerItem::Holster( int skiplocal ) { } +void CBasePlayerItem::AttachToPlayer ( CBasePlayer *pPlayer ) { } +int CBasePlayerWeapon::AddDuplicate( CBasePlayerItem *pOriginal ) { return 0; } +int CBasePlayerWeapon::AddToPlayer( CBasePlayer *pPlayer ) { return FALSE; } +int CBasePlayerWeapon::UpdateClientData( CBasePlayer *pPlayer ) { return 0; } +BOOL CBasePlayerWeapon :: AddPrimaryAmmo( int iCount, char *szName, int iMaxClip, int iMaxCarry ) { return TRUE; } +BOOL CBasePlayerWeapon :: AddSecondaryAmmo( int iCount, char *szName, int iMax ) { return TRUE; } +BOOL CBasePlayerWeapon :: IsUseable( void ) { return TRUE; } +int CBasePlayerWeapon::PrimaryAmmoIndex( void ) { return -1; } +int CBasePlayerWeapon::SecondaryAmmoIndex( void ) { return -1; } +void CBasePlayerAmmo::Spawn( void ) { } +CBaseEntity* CBasePlayerAmmo::Respawn( void ) { return this; } +void CBasePlayerAmmo::Materialize( void ) { } +void CBasePlayerAmmo :: DefaultTouch( CBaseEntity *pOther ) { } +int CBasePlayerWeapon::ExtractAmmo( CBasePlayerWeapon *pWeapon ) { return 0; } +int CBasePlayerWeapon::ExtractClipAmmo( CBasePlayerWeapon *pWeapon ) { return 0; } +void CBasePlayerWeapon::RetireWeapon( void ) { } \ No newline at end of file diff --git a/cl_dll/hl/hl_events.cpp b/cl_dll/hl/hl_events.cpp new file mode 100644 index 0000000..1302fb4 --- /dev/null +++ b/cl_dll/hl/hl_events.cpp @@ -0,0 +1,57 @@ +/*** +* +* Copyright (c) 1999, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +#include "../hud.h" +#include "../cl_util.h" +#include "event_api.h" + +extern "C" +{ +// HLDM +void EV_FireGlock1( struct event_args_s *args ); +void EV_FireGlock2( struct event_args_s *args ); +void EV_FireShotGunSingle( struct event_args_s *args ); +void EV_FireShotGunDouble( struct event_args_s *args ); +void EV_FireMP5( struct event_args_s *args ); +void EV_FirePython( struct event_args_s *args ); +void EV_FireGauss( struct event_args_s *args ); +void EV_SpinGauss( struct event_args_s *args ); +void EV_TrainPitchAdjust( struct event_args_s *args ); +} + +/* +====================== +Game_HookEvents + +Associate script file name with callback functions. Callback's must be extern "C" so + the engine doesn't get confused about name mangling stuff. Note that the format is + always the same. Of course, a clever mod team could actually embed parameters, behavior + into the actual .sc files and create a .sc file parser and hook their functionality through + that.. i.e., a scripting system. + +That was what we were going to do, but we ran out of time...oh well. +====================== +*/ +void Game_HookEvents( void ) +{ + gEngfuncs.pfnHookEvent( "events/glock1.sc", EV_FireGlock1 ); + gEngfuncs.pfnHookEvent( "events/glock2.sc", EV_FireGlock2 ); + gEngfuncs.pfnHookEvent( "events/shotgun1.sc", EV_FireShotGunSingle ); + gEngfuncs.pfnHookEvent( "events/shotgun2.sc", EV_FireShotGunDouble ); + gEngfuncs.pfnHookEvent( "events/mp5.sc", EV_FireMP5 ); + gEngfuncs.pfnHookEvent( "events/python.sc", EV_FirePython ); + gEngfuncs.pfnHookEvent( "events/gauss.sc", EV_FireGauss ); + gEngfuncs.pfnHookEvent( "events/gaussspin.sc", EV_SpinGauss ); + gEngfuncs.pfnHookEvent( "events/train.sc", EV_TrainPitchAdjust ); +} \ No newline at end of file diff --git a/cl_dll/hl/hl_objects.cpp b/cl_dll/hl/hl_objects.cpp new file mode 100644 index 0000000..179ab86 --- /dev/null +++ b/cl_dll/hl/hl_objects.cpp @@ -0,0 +1,28 @@ +/*** +* +* Copyright (c) 1999, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +#include "../hud.h" +#include "../cl_util.h" +#include "../demo.h" + +/* +===================== +Game_AddObjects + +Add game specific, client-side objects here +===================== +*/ +void Game_AddObjects( void ) +{ +} \ No newline at end of file diff --git a/cl_dll/hl/hl_weapons.cpp b/cl_dll/hl/hl_weapons.cpp new file mode 100644 index 0000000..06ce808 --- /dev/null +++ b/cl_dll/hl/hl_weapons.cpp @@ -0,0 +1,822 @@ +/*** +* +* Copyright (c) 1999, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +#include "extdll.h" +#include "util.h" +#include "cbase.h" +#include "monsters.h" +#include "weapons.h" +#include "nodes.h" +#include "player.h" + +#include "usercmd.h" +#include "entity_state.h" +#include "demo_api.h" +#include "pm_defs.h" +#include "event_api.h" +#include "r_efx.h" + +#include "../hud_iface.h" +#include "../com_weapons.h" +#include "../demo.h" + +extern globalvars_t *gpGlobals; + +// Pool of client side entities/entvars_t +static entvars_t ev[ 32 ]; +static int num_ents = 0; + +// The entity we'll use to represent the local client +static CBasePlayer player; + +// Local version of game .dll global variables ( time, etc. ) +static globalvars_t Globals; + +static CBasePlayerWeapon *g_pWpns[ 32 ]; + +// HLDM Weapon placeholder entities. +CGlock g_Glock; + +/* +====================== +AlertMessage + +Print debug messages to console +====================== +*/ +void AlertMessage( ALERT_TYPE atype, char *szFmt, ... ) +{ + va_list argptr; + static char string[1024]; + + va_start (argptr, szFmt); + vsprintf (string, szFmt,argptr); + va_end (argptr); + + gEngfuncs.Con_Printf( "cl: " ); + gEngfuncs.Con_Printf( string ); +} + +/* +===================== +HUD_PrepEntity + +Links the raw entity to an entvars_s holder. If a player is passed in as the owner, then +we set up the m_pPlayer field. +===================== +*/ +void HUD_PrepEntity( CBaseEntity *pEntity, CBasePlayer *pWeaponOwner ) +{ + memset( &ev[ num_ents ], 0, sizeof( entvars_t ) ); + pEntity->pev = &ev[ num_ents++ ]; + + pEntity->Precache(); + pEntity->Spawn(); + + if ( pWeaponOwner ) + { + ItemInfo info; + + ((CBasePlayerWeapon *)pEntity)->m_pPlayer = pWeaponOwner; + + ((CBasePlayerWeapon *)pEntity)->GetItemInfo( &info ); + + g_pWpns[ info.iId ] = (CBasePlayerWeapon *)pEntity; + } +} + +/* +===================== +CBaseEntity :: Killed + +If weapons code "kills" an entity, just set its effects to EF_NODRAW +===================== +*/ +void CBaseEntity :: Killed( entvars_t *pevAttacker, int iGib ) +{ + pev->effects |= EF_NODRAW; +} + +/* +===================== +CBasePlayerWeapon :: DefaultReload +===================== +*/ +BOOL CBasePlayerWeapon :: DefaultReload( int iClipSize, int iAnim, float fDelay ) +{ +#if 0 // FIXME, need to know primary ammo to get this right + if (m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] <= 0) + return FALSE; + + int j = min(iClipSize - m_iClip, m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType]); + + if (j == 0) + return FALSE; +#endif + + m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + fDelay; + + //!!UNDONE -- reload sound goes here !!! + SendWeaponAnim( iAnim ); + + m_fInReload = TRUE; + + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 3; + return TRUE; +} + +/* +===================== +CBasePlayerWeapon :: CanDeploy +===================== +*/ +BOOL CBasePlayerWeapon :: CanDeploy( void ) +{ + BOOL bHasAmmo = 0; + + if ( !pszAmmo1() ) + { + // this weapon doesn't use ammo, can always deploy. + return TRUE; + } + + if ( pszAmmo1() ) + { + bHasAmmo |= (m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] != 0); + } + if ( pszAmmo2() ) + { + bHasAmmo |= (m_pPlayer->m_rgAmmo[m_iSecondaryAmmoType] != 0); + } + if (m_iClip > 0) + { + bHasAmmo |= 1; + } + if (!bHasAmmo) + { + return FALSE; + } + + return TRUE; +} + +/* +===================== +CBasePlayerWeapon :: DefaultDeploy + +===================== +*/ +BOOL CBasePlayerWeapon :: DefaultDeploy( char *szViewModel, char *szWeaponModel, int iAnim, char *szAnimExt, int skiplocal ) +{ + if ( !CanDeploy() ) + return FALSE; + + gEngfuncs.CL_LoadModel( szViewModel, &m_pPlayer->pev->viewmodel ); + + SendWeaponAnim( iAnim ); + + m_pPlayer->m_flNextAttack = 0.5; + m_flTimeWeaponIdle = 1.0; + return TRUE; +} + +/* +===================== +CBasePlayerWeapon :: PlayEmptySound + +===================== +*/ +BOOL CBasePlayerWeapon :: PlayEmptySound( void ) +{ + if (m_iPlayEmptySound) + { + HUD_PlaySound( "weapons/357_cock1.wav", 0.8 ); + m_iPlayEmptySound = 0; + return 0; + } + return 0; +} + +/* +===================== +CBasePlayerWeapon :: ResetEmptySound + +===================== +*/ +void CBasePlayerWeapon :: ResetEmptySound( void ) +{ + m_iPlayEmptySound = 1; +} + +/* +===================== +CBasePlayerWeapon::Holster + +Put away weapon +===================== +*/ +void CBasePlayerWeapon::Holster( int skiplocal /* = 0 */ ) +{ + m_fInReload = FALSE; // cancel any reload in progress. + m_pPlayer->pev->viewmodel = 0; +} + +/* +===================== +CBasePlayerWeapon::SendWeaponAnim + +Animate weapon model +===================== +*/ +void CBasePlayerWeapon::SendWeaponAnim( int iAnim, int skiplocal ) +{ + m_pPlayer->pev->weaponanim = iAnim; + + int body = 0; + + HUD_SendWeaponAnim( iAnim, body, 0 ); +} + +/* +===================== +CBasePlayerWeapon::ItemPostFrame + +Handles weapon firing, reloading, etc. +===================== +*/ +void CBasePlayerWeapon::ItemPostFrame( void ) +{ + if ((m_fInReload) && (m_pPlayer->m_flNextAttack <= 0.0)) + { +#if 0 // FIXME, need ammo on client to make this work right + // complete the reload. + int j = min( iMaxClip() - m_iClip, m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType]); + + // Add them to the clip + m_iClip += j; + m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] -= j; +#else + m_iClip += 10; +#endif + m_fInReload = FALSE; + } + + if ((m_pPlayer->pev->button & IN_ATTACK2) && (m_flNextSecondaryAttack <= 0.0)) + { + if ( pszAmmo2() && !m_pPlayer->m_rgAmmo[SecondaryAmmoIndex()] ) + { + m_fFireOnEmpty = TRUE; + } + + SecondaryAttack(); + m_pPlayer->pev->button &= ~IN_ATTACK2; + } + else if ((m_pPlayer->pev->button & IN_ATTACK) && (m_flNextPrimaryAttack <= 0.0)) + { + if ( (m_iClip == 0 && pszAmmo1()) || (iMaxClip() == -1 && !m_pPlayer->m_rgAmmo[PrimaryAmmoIndex()] ) ) + { + m_fFireOnEmpty = TRUE; + } + + PrimaryAttack(); + } + else if ( m_pPlayer->pev->button & IN_RELOAD && iMaxClip() != WEAPON_NOCLIP && !m_fInReload ) + { + // reload when reload is pressed, or if no buttons are down and weapon is empty. + Reload(); + } + else if ( !(m_pPlayer->pev->button & (IN_ATTACK|IN_ATTACK2) ) ) + { + // no fire buttons down + + m_fFireOnEmpty = FALSE; + + // weapon is useable. Reload if empty and weapon has waited as long as it has to after firing + if ( m_iClip == 0 && !(iFlags() & ITEM_FLAG_NOAUTORELOAD) && m_flNextPrimaryAttack < 0.0 ) + { + Reload(); + return; + } + + WeaponIdle( ); + return; + } + + // catch all + if ( ShouldWeaponIdle() ) + { + WeaponIdle(); + } +} + +/* +===================== +CBasePlayer::SelectItem + + Switch weapons +===================== +*/ +void CBasePlayer::SelectItem(const char *pstr) +{ + if (!pstr) + return; + + CBasePlayerItem *pItem = NULL; + + if (!pItem) + return; + + + if (pItem == m_pActiveItem) + return; + + if (m_pActiveItem) + m_pActiveItem->Holster( ); + + m_pLastItem = m_pActiveItem; + m_pActiveItem = pItem; + + if (m_pActiveItem) + { + m_pActiveItem->Deploy( ); + } +} + +/* +===================== +CBasePlayer::SelectLastItem + +===================== +*/ +void CBasePlayer::SelectLastItem(void) +{ + if (!m_pLastItem) + { + return; + } + + if ( m_pActiveItem && !m_pActiveItem->CanHolster() ) + { + return; + } + + if (m_pActiveItem) + m_pActiveItem->Holster( ); + + CBasePlayerItem *pTemp = m_pActiveItem; + m_pActiveItem = m_pLastItem; + m_pLastItem = pTemp; + m_pActiveItem->Deploy( ); +} + +/* +===================== +CBasePlayer::Killed + +===================== +*/ +void CBasePlayer::Killed( entvars_t *pevAttacker, int iGib ) +{ + // Holster weapon immediately, to allow it to cleanup + if (m_pActiveItem) + m_pActiveItem->Holster( ); +} + +/* +===================== +CBasePlayer::Spawn + +===================== +*/ +void CBasePlayer::Spawn( void ) +{ + if (m_pActiveItem) + m_pActiveItem->Deploy( ); +} + +/* +===================== +UTIL_TraceLine + +Don't actually trace, but act like the trace didn't hit anything. +===================== +*/ +void UTIL_TraceLine( const Vector &vecStart, const Vector &vecEnd, IGNORE_MONSTERS igmon, edict_t *pentIgnore, TraceResult *ptr ) +{ + memset( ptr, 0, sizeof( *ptr ) ); + ptr->flFraction = 1.0; +} + +/* +===================== +UTIL_ParticleBox + +For debugging, draw a box around a player made out of particles +===================== +*/ +void UTIL_ParticleBox( CBasePlayer *player, float *mins, float *maxs, float life, unsigned char r, unsigned char g, unsigned char b ) +{ + int i; + vec3_t mmin, mmax; + + for ( i = 0; i < 3; i++ ) + { + mmin[ i ] = player->pev->origin[ i ] + mins[ i ]; + mmax[ i ] = player->pev->origin[ i ] + maxs[ i ]; + } + + gEngfuncs.pEfxAPI->R_ParticleBox( (float *)&mmin, (float *)&mmax, 5.0, 0, 255, 0 ); +} + +/* +===================== +UTIL_ParticleBoxes + +For debugging, draw boxes for other collidable players +===================== +*/ +void UTIL_ParticleBoxes( void ) +{ + int idx; + physent_t *pe; + cl_entity_t *player; + vec3_t mins, maxs; + + gEngfuncs.pEventAPI->EV_SetUpPlayerPrediction( false, true ); + + // Store off the old count + gEngfuncs.pEventAPI->EV_PushPMStates(); + + player = gEngfuncs.GetLocalPlayer(); + // Now add in all of the players. + gEngfuncs.pEventAPI->EV_SetSolidPlayers ( player->index - 1 ); + + for ( idx = 1; idx < 100; idx++ ) + { + pe = gEngfuncs.pEventAPI->EV_GetPhysent( idx ); + if ( !pe ) + break; + + if ( pe->info >= 1 && pe->info <= gEngfuncs.GetMaxClients() ) + { + mins = pe->origin + pe->mins; + maxs = pe->origin + pe->maxs; + + gEngfuncs.pEfxAPI->R_ParticleBox( (float *)&mins, (float *)&maxs, 0, 0, 255, 2.0 ); + } + } + + gEngfuncs.pEventAPI->EV_PopPMStates(); +} + +/* +===================== +UTIL_ParticleLine + +For debugging, draw a line made out of particles +===================== +*/ +void UTIL_ParticleLine( CBasePlayer *player, float *start, float *end, float life, unsigned char r, unsigned char g, unsigned char b ) +{ + gEngfuncs.pEfxAPI->R_ParticleLine( start, end, r, g, b, life ); +} + +/* +===================== +CBasePlayerWeapon::PrintState + +For debugging, print out state variables to log file +===================== +*/ +void CBasePlayerWeapon::PrintState( void ) +{ + COM_Log( "c:\\hl.log", "%.4f ", gpGlobals->time ); + COM_Log( "c:\\hl.log", "%.4f ", m_pPlayer->m_flNextAttack ); + COM_Log( "c:\\hl.log", "%.4f ", m_flNextPrimaryAttack ); + COM_Log( "c:\\hl.log", "%.4f ", m_flTimeWeaponIdle - gpGlobals->time); + COM_Log( "c:\\hl.log", "%i ", m_iClip ); +} + +/* +===================== +HUD_InitClientWeapons + +Set up weapons, player and functions needed to run weapons code client-side. +===================== +*/ +void HUD_InitClientWeapons( void ) +{ + static int initialized = 0; + if ( initialized ) + return; + + initialized = 1; + + // Set up pointer ( dummy object ) + gpGlobals = &Globals; + + // Fill in current time ( probably not needed ) + gpGlobals->time = gEngfuncs.GetClientTime(); + + // Fake functions + g_engfuncs.pfnPrecacheModel = stub_PrecacheModel; + g_engfuncs.pfnPrecacheSound = stub_PrecacheSound; + g_engfuncs.pfnPrecacheEvent = stub_PrecacheEvent; + g_engfuncs.pfnNameForFunction = stub_NameForFunction; + g_engfuncs.pfnSetModel = stub_SetModel; + g_engfuncs.pfnSetClientMaxspeed = HUD_SetMaxSpeed; + + // Handled locally + g_engfuncs.pfnPlaybackEvent = HUD_PlaybackEvent; + g_engfuncs.pfnAlertMessage = AlertMessage; + + // Pass through to engine + g_engfuncs.pfnPrecacheEvent = gEngfuncs.pfnPrecacheEvent; + g_engfuncs.pfnRandomFloat = gEngfuncs.pfnRandomFloat; + g_engfuncs.pfnRandomLong = gEngfuncs.pfnRandomLong; + + // Allocate a slot for the local player + HUD_PrepEntity( &player , NULL ); + + // Allocate slot(s) for each weapon that we are going to be predicting + HUD_PrepEntity( &g_Glock , &player ); +} + +/* +===================== +HUD_WeaponsPostThink + +Run Weapon firing code on client +===================== +*/ +void HUD_WeaponsPostThink( local_state_s *from, local_state_s *to, usercmd_t *cmd, double time, unsigned int random_seed ) +{ + int i; + int buttonsChanged; + CBasePlayerWeapon *pWeapon = NULL; + CBasePlayerWeapon *pCurrent; + weapon_data_t nulldata, *pfrom, *pto; + static int lasthealth; + + memset( &nulldata, 0, sizeof( nulldata ) ); + + HUD_InitClientWeapons(); + + // Get current clock + gpGlobals->time = time; + + // Fill in data based on selected weapon + // FIXME, make this a method in each weapon? where you pass in an entity_state_t *? + switch ( from->client.m_iId ) + { + case WEAPON_GLOCK: + pWeapon = &g_Glock; + break; + } + + // We are not predicting the current weapon, just bow out here. + if ( !pWeapon ) + return; + + for ( i = 0; i < 32; i++ ) + { + pCurrent = g_pWpns[ i ]; + if ( !pCurrent ) + { + continue; + } + + pfrom = &from->weapondata[ i ]; + + pCurrent->m_fInReload = pfrom->m_fInReload; + pCurrent->m_iClip = pfrom->m_iClip; + pCurrent->m_flNextPrimaryAttack = pfrom->m_flNextPrimaryAttack; + pCurrent->m_flNextSecondaryAttack = pfrom->m_flNextSecondaryAttack; + pCurrent->m_flTimeWeaponIdle = pfrom->m_flTimeWeaponIdle; + } + + // For random weapon events, use this seed to seed random # generator + player.random_seed = random_seed; + + // Get old buttons from previous state. + player.m_afButtonLast = from->playerstate.oldbuttons; + + // Which buttsons chave changed + buttonsChanged = (player.m_afButtonLast ^ cmd->buttons); // These buttons have changed this frame + + // Debounced button codes for pressed/released + // The changed ones still down are "pressed" + player.m_afButtonPressed = buttonsChanged & cmd->buttons; + // The ones not down are "released" + player.m_afButtonReleased = buttonsChanged & (~cmd->buttons); + + // Set player variables that weapons code might check/alter + player.pev->button = cmd->buttons; + + player.pev->velocity = from->client.velocity; + player.pev->flags = from->client.flags; + + player.pev->deadflag = from->client.deadflag; + player.pev->waterlevel = from->client.waterlevel; + player.pev->maxspeed = from->client.maxspeed; + player.pev->fov = from->client.fov; + player.pev->weaponanim = from->client.weaponanim; + player.pev->viewmodel = from->client.viewmodel; + player.m_flNextAttack = from->client.m_flNextAttack; + + // Point to current weapon object + if ( from->client.m_iId ) + { + player.m_pActiveItem = g_pWpns[ from->client.m_iId ]; + } + + // Store pointer to our destination entity_state_t so we can get our origin, etc. from it + // for setting up events on the client + g_finalstate = to; + + // Don't go firing anything if we have died. + // Or if we don't have a weapon model deployed + if ( ( player.pev->deadflag != ( DEAD_DISCARDBODY + 1 ) ) && !CL_IsDead() && player.pev->viewmodel ) + { + if ( player.m_flNextAttack <= 0 ) + { + pWeapon->ItemPostFrame(); + } + } + + // If we are running events/etc. go ahead and see if we + // managed to die between last frame and this one + // If so, run the appropriate player killed or spawn function + if ( g_runfuncs ) + { + if ( to->client.health <= 0 && lasthealth > 0 ) + { + player.Killed( NULL, 0 ); + } + else if ( to->client.health > 0 && lasthealth <= 0 ) + { + player.Spawn(); + } + + lasthealth = to->client.health; + } + + // Assume that we are not going to switch weapons + to->client.m_iId = from->client.m_iId; + + // Now see if we issued a changeweapon command ( and we're not dead ) + if ( cmd->weaponselect && ( player.pev->deadflag != ( DEAD_DISCARDBODY + 1 ) ) ) + { + // Switched to a different weapon? + if ( from->weapondata[ cmd->weaponselect ].m_iId == cmd->weaponselect ) + { + CBasePlayerWeapon *pNew = g_pWpns[ cmd->weaponselect ]; + if ( pNew && ( pNew != pWeapon ) ) + { + // Put away old weapon + if (player.m_pActiveItem) + player.m_pActiveItem->Holster( ); + + player.m_pLastItem = player.m_pActiveItem; + player.m_pActiveItem = pNew; + + // Deploy new weapon + if (player.m_pActiveItem) + { + player.m_pActiveItem->Deploy( ); + } + + // Update weapon id so we can predict things correctly. + to->client.m_iId = cmd->weaponselect; + } + } + } + + // Copy in results of predcition code + to->client.viewmodel = player.pev->viewmodel; + to->client.fov = player.pev->fov; + to->client.weaponanim = player.pev->weaponanim; + to->client.m_flNextAttack = player.m_flNextAttack; + to->client.maxspeed = player.pev->maxspeed; + + // Make sure that weapon animation matches what the game .dll is telling us + // over the wire ( fixes some animation glitches ) + if ( g_runfuncs && ( HUD_GetWeaponAnim() != to->client.weaponanim ) ) + { + int body = 2; + // Force a fixed anim down to viewmodel + HUD_SendWeaponAnim( to->client.weaponanim, body, 1 ); + } + + for ( i = 0; i < 32; i++ ) + { + pCurrent = g_pWpns[ i ]; + + pto = &to->weapondata[ i ]; + + if ( !pCurrent ) + { + memset( pto, 0, sizeof( weapon_data_t ) ); + continue; + } + + pto->m_fInReload = pCurrent->m_fInReload; + pto->m_iClip = pCurrent->m_iClip; + pto->m_flNextPrimaryAttack = pCurrent->m_flNextPrimaryAttack; + pto->m_flNextSecondaryAttack = pCurrent->m_flNextSecondaryAttack; + pto->m_flTimeWeaponIdle = pCurrent->m_flTimeWeaponIdle; + + // Decrement weapon counters, server does this at same time ( during post think, after doing everything else ) + pto->m_flNextReload -= cmd->msec / 1000.0; + pto->m_fNextAimBonus -= cmd->msec / 1000.0; + pto->m_flNextPrimaryAttack -= cmd->msec / 1000.0; + pto->m_flNextSecondaryAttack -= cmd->msec / 1000.0; + pto->m_flTimeWeaponIdle -= cmd->msec / 1000.0; + + if ( pto->m_flPumpTime != -9999 ) + { + pto->m_flPumpTime -= cmd->msec / 1000.0; + if ( pto->m_flPumpTime < -0.001 ) + pto->m_flPumpTime = -0.001; + } + + if ( pto->m_fNextAimBonus < -1.0 ) + { + pto->m_fNextAimBonus = -1.0; + } + + if ( pto->m_flNextPrimaryAttack < -1.0 ) + { + pto->m_flNextPrimaryAttack = -1.0; + } + + if ( pto->m_flNextSecondaryAttack < -0.001 ) + { + pto->m_flNextSecondaryAttack = -0.001; + } + + if ( pto->m_flTimeWeaponIdle < -0.001 ) + { + pto->m_flTimeWeaponIdle = -0.001; + } + + if ( pto->m_flNextReload < -0.001 ) + { + pto->m_flNextReload = -0.001; + } + } + + // m_flNextAttack is now part of the weapons, but is part of the player instead + to->client.m_flNextAttack -= cmd->msec / 1000.0; + if ( to->client.m_flNextAttack < -0.001 ) + { + to->client.m_flNextAttack = -0.001; + } + + // Wipe it so we can't use it after this frame + g_finalstate = NULL; +} + +/* +===================== +HUD_PostRunCmd + +Client calls this during prediction, after it has moved the player and updated any info changed into to-> +time is the current client clock based on prediction +cmd is the command that caused the movement, etc +runfuncs is 1 if this is the first time we've predicted this command. If so, sounds and effects should play, otherwise, they should +be ignored +===================== +*/ +void _DLLEXPORT HUD_PostRunCmd( struct local_state_s *from, struct local_state_s *to, struct usercmd_s *cmd, int runfuncs, double time, unsigned int random_seed ) +{ + g_runfuncs = runfuncs; + + // Only run post think stuff for glock for the sample + // implementation +#if defined( CLIENT_WEAPONS ) + if ( cl_lw && cl_lw->value && + from->client.m_iId == WEAPON_GLOCK ) + { + HUD_WeaponsPostThink( from, to, cmd, time, random_seed ); + } + else +#endif + { + to->client.fov = g_lastFOV; + } + + // All games can use FOV state + g_lastFOV = to->client.fov; +} diff --git a/cl_dll/hud.cpp b/cl_dll/hud.cpp index d47ec66..399b860 100644 --- a/cl_dll/hud.cpp +++ b/cl_dll/hud.cpp @@ -19,13 +19,23 @@ // #include "hud.h" -#include "util.h" +#include "cl_util.h" #include #include #include "parsemsg.h" +#include "hud_servers.h" +#include "vgui_TeamFortressViewport.h" + +#include "demo.h" +#include "demo_api.h" extern client_sprite_t *GetSpriteList(client_sprite_t *pList, const char *psz, int iRes, int iCount); +extern cvar_t *sensitivity; +cvar_t *cl_lw = NULL; + +void ShutdownInput (void); + //DECLARE_MESSAGE(m_Logo, Logo) int __MsgFunc_Logo(const char *pszName, int iSize, void *pbuf) { @@ -59,7 +69,147 @@ int __MsgFunc_GameMode(const char *pszName, int iSize, void *pbuf ) return gHUD.MsgFunc_GameMode( pszName, iSize, pbuf ); } +// TFFree Command Menu +void __CmdFunc_OpenCommandMenu(void) +{ + if ( gViewPort ) + { + gViewPort->ShowCommandMenu(); + } +} +// TFC "special" command +void __CmdFunc_InputPlayerSpecial(void) +{ + if ( gViewPort ) + { + gViewPort->InputPlayerSpecial(); + } +} + +void __CmdFunc_CloseCommandMenu(void) +{ + if ( gViewPort ) + { + gViewPort->InputSignalHideCommandMenu(); + } +} + +void __CmdFunc_ForceCloseCommandMenu( void ) +{ + if ( gViewPort ) + { + gViewPort->HideCommandMenu(); + } +} + +void __CmdFunc_ToggleServerBrowser( void ) +{ + if ( gViewPort ) + { + gViewPort->ToggleServerBrowser(); + } +} + +// TFFree Command Menu Message Handlers +int __MsgFunc_ValClass(const char *pszName, int iSize, void *pbuf) +{ + if (gViewPort) + return gViewPort->MsgFunc_ValClass( pszName, iSize, pbuf ); + return 0; +} + +int __MsgFunc_TeamNames(const char *pszName, int iSize, void *pbuf) +{ + if (gViewPort) + return gViewPort->MsgFunc_TeamNames( pszName, iSize, pbuf ); + return 0; +} + +int __MsgFunc_Feign(const char *pszName, int iSize, void *pbuf) +{ + if (gViewPort) + return gViewPort->MsgFunc_Feign( pszName, iSize, pbuf ); + return 0; +} + +int __MsgFunc_Detpack(const char *pszName, int iSize, void *pbuf) +{ + if (gViewPort) + return gViewPort->MsgFunc_Detpack( pszName, iSize, pbuf ); + return 0; +} + +int __MsgFunc_VGUIMenu(const char *pszName, int iSize, void *pbuf) +{ + if (gViewPort) + return gViewPort->MsgFunc_VGUIMenu( pszName, iSize, pbuf ); + return 0; +} + +int __MsgFunc_MOTD(const char *pszName, int iSize, void *pbuf) +{ + if (gViewPort) + return gViewPort->MsgFunc_MOTD( pszName, iSize, pbuf ); + return 0; +} + +int __MsgFunc_BuildSt(const char *pszName, int iSize, void *pbuf) +{ + if (gViewPort) + return gViewPort->MsgFunc_BuildSt( pszName, iSize, pbuf ); + return 0; +} + +int __MsgFunc_RandomPC(const char *pszName, int iSize, void *pbuf) +{ + if (gViewPort) + return gViewPort->MsgFunc_RandomPC( pszName, iSize, pbuf ); + return 0; +} + +int __MsgFunc_ServerName(const char *pszName, int iSize, void *pbuf) +{ + if (gViewPort) + return gViewPort->MsgFunc_ServerName( pszName, iSize, pbuf ); + return 0; +} + +int __MsgFunc_ScoreInfo(const char *pszName, int iSize, void *pbuf) +{ + if (gViewPort) + return gViewPort->MsgFunc_ScoreInfo( pszName, iSize, pbuf ); + return 0; +} + +int __MsgFunc_TeamScore(const char *pszName, int iSize, void *pbuf) +{ + if (gViewPort) + return gViewPort->MsgFunc_TeamScore( pszName, iSize, pbuf ); + return 0; +} + +int __MsgFunc_TeamInfo(const char *pszName, int iSize, void *pbuf) +{ + if (gViewPort) + return gViewPort->MsgFunc_TeamInfo( pszName, iSize, pbuf ); + return 0; +} + +int __MsgFunc_Spectator(const char *pszName, int iSize, void *pbuf) +{ + if (gViewPort) + return gViewPort->MsgFunc_Spectator( pszName, iSize, pbuf ); + return 0; +} + +int __MsgFunc_AllowSpec(const char *pszName, int iSize, void *pbuf) +{ + if (gViewPort) + return gViewPort->MsgFunc_AllowSpec( pszName, iSize, pbuf ); + return 0; +} + // This is called every time the DLL is loaded void CHud :: Init( void ) { @@ -70,11 +220,39 @@ void CHud :: Init( void ) HOOK_MESSAGE( SetFOV ); HOOK_MESSAGE( Concuss ); + // TFFree CommandMenu + HOOK_COMMAND( "+commandmenu", OpenCommandMenu ); + HOOK_COMMAND( "-commandmenu", CloseCommandMenu ); + HOOK_COMMAND( "ForceCloseCommandMenu", ForceCloseCommandMenu ); + HOOK_COMMAND( "special", InputPlayerSpecial ); + HOOK_COMMAND( "togglebrowser", ToggleServerBrowser ); + + HOOK_MESSAGE( ValClass ); + HOOK_MESSAGE( TeamNames ); + HOOK_MESSAGE( Feign ); + HOOK_MESSAGE( Detpack ); + HOOK_MESSAGE( MOTD ); + HOOK_MESSAGE( BuildSt ); + HOOK_MESSAGE( RandomPC ); + HOOK_MESSAGE( ServerName ); + HOOK_MESSAGE( ScoreInfo ); + HOOK_MESSAGE( TeamScore ); + HOOK_MESSAGE( TeamInfo ); + + HOOK_MESSAGE( Spectator ); + HOOK_MESSAGE( AllowSpec ); + + // VGUI Menus + HOOK_MESSAGE( VGUIMenu ); + m_iLogo = 0; m_iFOV = 0; CVAR_CREATE( "zoom_sensitivity_ratio", "1.2", 0 ); - CVAR_CREATE( "default_fov", "90", 0 ); + default_fov = CVAR_CREATE( "default_fov", "90", 0 ); + m_pCvarStealMouse = CVAR_CREATE( "hud_capturemouse", "1", FCVAR_ARCHIVE ); + + cl_lw = gEngfuncs.pfnGetCvarPointer( "cl_lw" ); m_pSpriteList = NULL; @@ -101,8 +279,6 @@ void CHud :: Init( void ) m_Battery.Init(); m_Flash.Init(); m_Message.Init(); - m_Scoreboard.Init(); - m_MOTD.Init(); m_StatusBar.Init(); m_DeathNotice.Init(); m_AmmoSecondary.Init(); @@ -111,6 +287,8 @@ void CHud :: Init( void ) m_SayText.Init(); m_Menu.Init(); + + ServersInit(); MsgFunc_ResetHUD(0, 0, NULL ); } @@ -122,6 +300,20 @@ CHud :: ~CHud() delete [] m_rghSprites; delete [] m_rgrcRects; delete [] m_rgszSpriteNames; + + if ( m_pHudList ) + { + HUDLIST *pList; + while ( m_pHudList ) + { + pList = m_pHudList; + m_pHudList = m_pHudList->pNext; + free( pList ); + } + m_pHudList = NULL; + } + + ServersShutdown(); } // GetSpriteIndex() @@ -151,6 +343,7 @@ void CHud :: VidInit( void ) // m_hsprFont = LoadSprite("sprites/%d_font.spr"); m_hsprLogo = 0; + m_hsprCursor = 0; if (ScreenWidth < 640) m_iRes = 320; @@ -231,8 +424,6 @@ void CHud :: VidInit( void ) m_Battery.VidInit(); m_Flash.VidInit(); m_Message.VidInit(); - m_Scoreboard.VidInit(); - m_MOTD.VidInit(); m_StatusBar.VidInit(); m_DeathNotice.VidInit(); m_SayText.VidInit(); @@ -252,6 +443,100 @@ int CHud::MsgFunc_Logo(const char *pszName, int iSize, void *pbuf) return 1; } +float g_lastFOV = 0.0; + +/* +============ +COM_FileBase +============ +*/ +// Extracts the base name of a file (no path, no extension, assumes '/' as path separator) +void COM_FileBase ( const char *in, char *out) +{ + int len, start, end; + + len = strlen( in ); + + // scan backward for '.' + end = len - 1; + while ( end && in[end] != '.' && in[end] != '/' && in[end] != '\\' ) + end--; + + if ( in[end] != '.' ) // no '.', copy to end + end = len-1; + else + end--; // Found ',', copy to left of '.' + + + // Scan backward for '/' + start = len-1; + while ( start >= 0 && in[start] != '/' && in[start] != '\\' ) + start--; + + if ( in[start] != '/' && in[start] != '\\' ) + start = 0; + else + start++; + + // Length of new sting + len = end - start + 1; + + // Copy partial string + strncpy( out, &in[start], len ); + // Terminate it + out[len] = 0; +} + +/* +================= +HUD_IsGame + +================= +*/ +int HUD_IsGame( const char *game ) +{ + const char *gamedir; + char gd[ 1024 ]; + + gamedir = gEngfuncs.pfnGetGameDirectory(); + if ( gamedir && gamedir[0] ) + { + COM_FileBase( gamedir, gd ); + if ( !stricmp( gd, game ) ) + return 1; + } + return 0; +} + +/* +===================== +HUD_GetFOV + +Returns last FOV +===================== +*/ +float HUD_GetFOV( void ) +{ + if ( gEngfuncs.pDemoAPI->IsRecording() ) + { + // Write it + int i = 0; + unsigned char buf[ 100 ]; + + // Active + *( float * )&buf[ i ] = g_lastFOV; + i += sizeof( float ); + + Demo_WriteBuffer( TYPE_ZOOM, i, buf ); + } + + if ( gEngfuncs.pDemoAPI->IsPlayingback() ) + { + g_lastFOV = g_demozoom; + } + return g_lastFOV; +} + int CHud::MsgFunc_SetFOV(const char *pszName, int iSize, void *pbuf) { BEGIN_READ( pbuf, iSize ); @@ -259,6 +544,14 @@ int CHud::MsgFunc_SetFOV(const char *pszName, int iSize, void *pbuf) int newfov = READ_BYTE(); int def_fov = CVAR_GET_FLOAT( "default_fov" ); + int tfc = 0; + tfc = HUD_IsGame( "tfc" ); + + if ( tfc && cl_lw && cl_lw->value ) + return 1; + + g_lastFOV = newfov; + if ( newfov == 0 ) { m_iFOV = def_fov; @@ -279,7 +572,7 @@ int CHud::MsgFunc_SetFOV(const char *pszName, int iSize, void *pbuf) else { // set a new sensitivity that is proportional to the change from the FOV default - m_flMouseSensitivity = CVAR_GET_FLOAT("sensitivity") * ((float)newfov / (float)def_fov) * CVAR_GET_FLOAT("zoom_sensitivity_ratio"); + m_flMouseSensitivity = sensitivity->value * ((float)newfov / (float)def_fov) * CVAR_GET_FLOAT("zoom_sensitivity_ratio"); } return 1; @@ -316,4 +609,9 @@ void CHud::AddHudElem(CHudBase *phudelem) ptemp->pNext = pdl; } +float CHud::GetSensitivity( void ) +{ + return m_flMouseSensitivity; +} + diff --git a/cl_dll/hud.h b/cl_dll/hud.h index 8b03efb..171fdba 100644 --- a/cl_dll/hud.h +++ b/cl_dll/hud.h @@ -25,11 +25,7 @@ #define RGB_REDISH 0x00FF1010 //255,160,0 #define RGB_GREENISH 0x0000A000 //0,160,0 -typedef struct rect_s -{ - int left, right, top, bottom; -} wrect_t; - +#include "wrect.h" #include "cl_dll.h" #include "ammo.h" @@ -54,6 +50,8 @@ typedef struct { #define MAX_PLAYER_NAME_LENGTH 32 +#define MAX_MOTD_LENGTH 1024 + // //----------------------------------------------------- // @@ -98,6 +96,7 @@ public: int MsgFunc_ItemPickup( const char *pszName, int iSize, void *pbuf ); int MsgFunc_HideWeapon( const char *pszName, int iSize, void *pbuf ); + void SlotInput( int iSlot ); void _cdecl UserCmd_Slot1( void ); void _cdecl UserCmd_Slot2( void ); void _cdecl UserCmd_Slot3( void ); @@ -189,6 +188,9 @@ private: // //----------------------------------------------------- // +// REMOVED: Vgui has replaced this. +// +/* class CHudMOTD : public CHudBase { public: @@ -200,12 +202,12 @@ public: int MsgFunc_MOTD( const char *pszName, int iSize, void *pbuf ); protected: - enum { MAX_MOTD_LENGTH = 241, }; static int MOTD_DISPLAY_TIME; char m_szMOTD[ MAX_MOTD_LENGTH ]; - float m_flActiveTill; + float m_flActiveRemaining; int m_iLines; }; +*/ // //----------------------------------------------------- @@ -239,6 +241,9 @@ protected: // //----------------------------------------------------- // +// REMOVED: Vgui has replaced this. +// +/* class CHudScoreboard: public CHudBase { public: @@ -254,34 +259,6 @@ public: int MsgFunc_TeamScore( const char *pszName, int iSize, void *pbuf ); void DeathMsg( int killer, int victim ); - enum { - MAX_PLAYERS = 64, - MAX_TEAMS = 64, - MAX_TEAM_NAME = 16, - }; - - struct extra_player_info_t { - short frags; - short deaths; - char teamname[MAX_TEAM_NAME]; - }; - - struct team_info_t { - char name[MAX_TEAM_NAME]; - short frags; - short deaths; - short ping; - short packetloss; - short ownteam; - short players; - int already_drawn; - int scores_overriden; - }; - - hud_player_info_t m_PlayerInfoList[MAX_PLAYERS+1]; // player info from the engine - extra_player_info_t m_PlayerExtraInfo[MAX_PLAYERS+1]; // additional player info sent directly to the client dll - team_info_t m_TeamInfo[MAX_TEAMS+1]; - int m_iNumTeams; int m_iLastKilledBy; @@ -290,7 +267,47 @@ public: int m_iShowscoresHeld; void GetAllPlayersInfo( void ); +private: + struct cvar_s *cl_showpacketloss; + }; +*/ + +enum +{ + MAX_PLAYERS = 64, + MAX_TEAMS = 64, + MAX_TEAM_NAME = 16, +}; + +struct extra_player_info_t +{ + short frags; + short deaths; + short playerclass; + short teamnumber; + char teamname[MAX_TEAM_NAME]; +}; + +struct team_info_t +{ + char name[MAX_TEAM_NAME]; + short frags; + short deaths; + short ping; + short packetloss; + short ownteam; + short players; + int already_drawn; + int scores_overriden; + int teamnumber; +}; + +extern hud_player_info_t g_PlayerInfoList[MAX_PLAYERS+1]; // player info from the engine +extern extra_player_info_t g_PlayerExtraInfo[MAX_PLAYERS+1]; // additional player info sent directly to the client dll +extern team_info_t g_TeamInfo[MAX_TEAMS+1]; +extern int g_IsSpectator[MAX_PLAYERS+1]; + // //----------------------------------------------------- @@ -340,7 +357,7 @@ public: int VidInit( void ); int Draw( float flTime ); int MsgFunc_SayText( const char *pszName, int iSize, void *pbuf ); - void SayTextPrint( const char *pszBuf, int iBufSize ); + void SayTextPrint( const char *pszBuf, int iBufSize, int clientIndex = -1 ); void EnsureTextFitsInOneLineAndWrapIfHaveTo( int line ); }; @@ -422,8 +439,8 @@ class CHudTextMessage: public CHudBase { public: int Init( void ); - char *LocaliseTextString( const char *msg, char *dst_buffer, int buffer_size ); - char *BufferedLocaliseTextString( const char *msg ); + static char *LocaliseTextString( const char *msg, char *dst_buffer, int buffer_size ); + static char *BufferedLocaliseTextString( const char *msg ); char *LookupString( const char *msg_name, int *msg_dest = NULL ); int MsgFunc_TextMsg(const char *pszName, int iSize, void *pbuf); }; @@ -501,11 +518,12 @@ private: }; - // //----------------------------------------------------- // +typedef struct cvar_s cvar_t; + class CHud { private: @@ -520,6 +538,7 @@ private: public: + HSPRITE m_hsprCursor; float m_flTime; // the current client time float m_fOldTime; // the time at which the HUD was last redrawn double m_flTimeDelta; // the difference between flTime and fOldTime @@ -530,6 +549,7 @@ public: int m_iFOV; int m_Teamplay; int m_iRes; + cvar_t *m_pCvarStealMouse; int m_iFontHeight; int DrawHudNumber(int x, int y, int iFlags, int iNumber, int r, int g, int b ); @@ -545,6 +565,7 @@ private: wrect_t *m_rgrcRects; /*[HUD_SPRITE_COUNT]*/ char *m_rgszSpriteNames; /*[HUD_SPRITE_COUNT][MAX_SPRITE_NAME_LENGTH]*/ + struct cvar_s *default_fov; public: HSPRITE GetSprite( int index ) { @@ -566,8 +587,6 @@ public: CHudTrain m_Train; CHudFlashlight m_Flash; CHudMessage m_Message; - CHudScoreboard m_Scoreboard; - CHudMOTD m_MOTD; CHudStatusBar m_StatusBar; CHudDeathNotice m_DeathNotice; CHudSayText m_SayText; @@ -606,6 +625,17 @@ public: void AddHudElem(CHudBase *p); + float GetSensitivity(); + }; +class TeamFortressViewport; + extern CHud gHUD; +extern TeamFortressViewport *gViewPort; + +extern int g_iPlayerClass; +extern int g_iTeamNumber; +extern int g_iUser1; +extern int g_iUser2; + diff --git a/cl_dll/hud_iface.h b/cl_dll/hud_iface.h new file mode 100644 index 0000000..90d45e9 --- /dev/null +++ b/cl_dll/hud_iface.h @@ -0,0 +1,13 @@ +#if !defined( HUD_IFACEH ) +#define HUD_IFACEH +#pragma once + +#define EXPORT _declspec( dllexport ) +#define _DLLEXPORT __declspec( dllexport ) + +typedef int (*pfnUserMsgHook)(const char *pszName, int iSize, void *pbuf); +#include "wrect.h" +#include "../engine/cdll_int.h" +extern cl_enginefunc_t gEngfuncs; + +#endif \ No newline at end of file diff --git a/cl_dll/hud_msg.cpp b/cl_dll/hud_msg.cpp index 9bc6cd3..c0199ad 100644 --- a/cl_dll/hud_msg.cpp +++ b/cl_dll/hud_msg.cpp @@ -17,7 +17,7 @@ // #include "hud.h" -#include "util.h" +#include "cl_util.h" #include "parsemsg.h" /// USER-DEFINED SERVER MESSAGE HANDLERS diff --git a/cl_dll/hud_redraw.cpp b/cl_dll/hud_redraw.cpp index d52c242..280707d 100644 --- a/cl_dll/hud_redraw.cpp +++ b/cl_dll/hud_redraw.cpp @@ -17,8 +17,9 @@ // #include #include "hud.h" -#include "util.h" +#include "cl_util.h" +#include "vgui_TeamFortressViewport.h" #define MAX_LOGO_FRAMES 56 @@ -30,10 +31,18 @@ int grgLogoFrame[MAX_LOGO_FRAMES] = }; +extern int g_iVisibleMouse; + +float HUD_GetFOV( void ); + +extern cvar_t *sensitivity; + // Think void CHud::Think(void) { + int newfov; HUDLIST *pList = m_pHudList; + while (pList) { if (pList->p->m_iFlags & HUD_ACTIVE) @@ -41,10 +50,34 @@ void CHud::Think(void) pList = pList->pNext; } + newfov = HUD_GetFOV(); + if ( newfov == 0 ) + { + m_iFOV = default_fov->value; + } + else + { + m_iFOV = newfov; + } + + // the clients fov is actually set in the client data update section of the hud + + // Set a new sensitivity + if ( m_iFOV == default_fov->value ) + { + // reset to saved sensitivity + m_flMouseSensitivity = 0; + } + else + { + // set a new sensitivity that is proportional to the change from the FOV default + m_flMouseSensitivity = sensitivity->value * ((float)newfov / (float)default_fov->value) * CVAR_GET_FLOAT("zoom_sensitivity_ratio"); + } + // think about default fov if ( m_iFOV == 0 ) { // only let players adjust up in fov, and only if they are not overriden by something else - m_iFOV = max( CVAR_GET_FLOAT( "default_fov" ), 90 ); + m_iFOV = max( default_fov->value, 90 ); } } @@ -56,11 +89,39 @@ int CHud :: Redraw( float flTime, int intermission ) m_fOldTime = m_flTime; // save time of previous redraw m_flTime = flTime; m_flTimeDelta = (double)m_flTime - m_fOldTime; + static m_flShotTime = 0; // Clock was reset, reset delta if ( m_flTimeDelta < 0 ) m_flTimeDelta = 0; + // Bring up the scoreboard during intermission + if (gViewPort) + { + if ( m_iIntermission && !intermission ) + { + // Have to do this here so the scoreboard goes away + m_iIntermission = intermission; + gViewPort->HideCommandMenu(); + gViewPort->HideScoreBoard(); + } + else if ( !m_iIntermission && intermission ) + { + gViewPort->HideCommandMenu(); + gViewPort->ShowScoreBoard(); + + // Take a screenshot if the client's got the cvar set + if ( CVAR_GET_FLOAT( "hud_takesshots" ) != 0 ) + m_flShotTime = flTime + 1.0; // Take a screenshot in a second + } + } + + if (m_flShotTime && m_flShotTime < flTime) + { + gEngfuncs.pfnClientCmd("snapshot\n"); + m_flShotTime = 0; + } + m_iIntermission = intermission; // if no redrawing is necessary @@ -72,7 +133,7 @@ int CHud :: Redraw( float flTime, int intermission ) { if ( !intermission ) { - if ((pList->p->m_iFlags & HUD_ACTIVE) && !(m_iHideHUDDisplay & HIDEHUD_ALL)) + if ( (pList->p->m_iFlags & HUD_ACTIVE) && !(m_iHideHUDDisplay & HIDEHUD_ALL) ) pList->p->Draw(flTime); } else @@ -105,6 +166,28 @@ int CHud :: Redraw( float flTime, int intermission ) SPR_DrawAdditive(i, x, y, NULL); } + /* + if ( g_iVisibleMouse ) + { + void IN_GetMousePos( int *mx, int *my ); + int mx, my; + + IN_GetMousePos( &mx, &my ); + + if (m_hsprCursor == 0) + { + char sz[256]; + sprintf( sz, "sprites/cursor.spr" ); + m_hsprCursor = SPR_Load( sz ); + } + + SPR_Set(m_hsprCursor, 250, 250, 250 ); + + // Draw the logo at 20 fps + SPR_DrawAdditive( 0, mx, my, NULL ); + } + */ + return 1; } diff --git a/cl_dll/hud_servers.cpp b/cl_dll/hud_servers.cpp new file mode 100644 index 0000000..c3c64da --- /dev/null +++ b/cl_dll/hud_servers.cpp @@ -0,0 +1,1223 @@ +// hud_servers.cpp +#include "hud.h" +#include "cl_util.h" +#include "hud_servers_priv.h" +#include "hud_servers.h" +#include "net_api.h" +#include +#include + +static int context_id; + +// Default master server address in case we can't read any from woncomm.lst file +#define VALVE_MASTER_ADDRESS "half-life.east.won.net" +#define PORT_MASTER 27010 +#define PORT_SERVER 27015 + +// File where we really should look for master servers +#define MASTER_PARSE_FILE "woncomm.lst" + +#define MAX_QUERIES 20 + +#define NET_API gEngfuncs.pNetAPI + +static CHudServers *g_pServers = NULL; + +/* +=================== +ListResponse + +Callback from engine +=================== +*/ +void NET_CALLBACK ListResponse( struct net_response_s *response ) +{ + if ( g_pServers ) + { + g_pServers->ListResponse( response ); + } +} + +/* +=================== +ServerResponse + +Callback from engine +=================== +*/ +void NET_CALLBACK ServerResponse( struct net_response_s *response ) +{ + if ( g_pServers ) + { + g_pServers->ServerResponse( response ); + } +} + +/* +=================== +PingResponse + +Callback from engine +=================== +*/ +void NET_CALLBACK PingResponse( struct net_response_s *response ) +{ + if ( g_pServers ) + { + g_pServers->PingResponse( response ); + } +} + +/* +=================== +RulesResponse + +Callback from engine +=================== +*/ +void NET_CALLBACK RulesResponse( struct net_response_s *response ) +{ + if ( g_pServers ) + { + g_pServers->RulesResponse( response ); + } +} +/* +=================== +PlayersResponse + +Callback from engine +=================== +*/ +void NET_CALLBACK PlayersResponse( struct net_response_s *response ) +{ + if ( g_pServers ) + { + g_pServers->PlayersResponse( response ); + } +} +/* +=================== +ListResponse + +=================== +*/ +void CHudServers::ListResponse( struct net_response_s *response ) +{ + request_t *list; + request_t *p; + int c = 0; + + if ( !( response->error == NET_SUCCESS ) ) + return; + + if ( response->type != NETAPI_REQUEST_SERVERLIST ) + return; + + if ( response->response ) + { + list = ( request_t * ) response->response; + while ( list ) + { + c++; + + //if ( c < 40 ) + { + // Copy from parsed stuff + p = new request_t; + p->context = -1; + p->remote_address = list->remote_address; + p->next = m_pServerList; + m_pServerList = p; + } + + // Move on + list = list->next; + } + } + + gEngfuncs.Con_Printf( "got list\n" ); + + m_nQuerying = 1; + m_nActiveQueries = 0; +} + +/* +=================== +ServerResponse + +=================== +*/ +void CHudServers::ServerResponse( struct net_response_s *response ) +{ + char *szresponse; + request_t *p; + server_t *browser; + int len; + char sz[ 32 ]; + + // Remove from active list + p = FindRequest( response->context, m_pActiveList ); + if ( p ) + { + RemoveServerFromList( &m_pActiveList, p ); + m_nActiveQueries--; + } + + if ( response->error != NET_SUCCESS ) + return; + + switch ( response->type ) + { + case NETAPI_REQUEST_DETAILS: + if ( response->response ) + { + szresponse = (char *)response->response; + len = strlen( szresponse ) + 100 + 1; + sprintf( sz, "%i", (int)( 1000.0 * response->ping ) ); + + browser = new server_t; + browser->remote_address = response->remote_address; + browser->info = new char[ len ]; + browser->ping = (int)( 1000.0 * response->ping ); + strcpy( browser->info, szresponse ); + + NET_API->SetValueForKey( browser->info, "address", gEngfuncs.pNetAPI->AdrToString( &response->remote_address ), len ); + NET_API->SetValueForKey( browser->info, "ping", sz, len ); + + AddServer( &m_pServers, browser ); + } + break; + default: + break; + } +} + +/* +=================== +PingResponse + +=================== +*/ +void CHudServers::PingResponse( struct net_response_s *response ) +{ + char sz[ 32 ]; + + if ( response->error != NET_SUCCESS ) + return; + + switch ( response->type ) + { + case NETAPI_REQUEST_PING: + sprintf( sz, "%.2f", 1000.0 * response->ping ); + + gEngfuncs.Con_Printf( "ping == %s\n", sz ); + break; + default: + break; + } +} + +/* +=================== +RulesResponse + +=================== +*/ +void CHudServers::RulesResponse( struct net_response_s *response ) +{ + char *szresponse; + + if ( response->error != NET_SUCCESS ) + return; + + switch ( response->type ) + { + case NETAPI_REQUEST_RULES: + if ( response->response ) + { + szresponse = (char *)response->response; + + gEngfuncs.Con_Printf( "rules %s\n", szresponse ); + } + break; + default: + break; + } +} + +/* +=================== +PlayersResponse + +=================== +*/ +void CHudServers::PlayersResponse( struct net_response_s *response ) +{ + char *szresponse; + + if ( response->error != NET_SUCCESS ) + return; + + switch ( response->type ) + { + case NETAPI_REQUEST_PLAYERS: + if ( response->response ) + { + szresponse = (char *)response->response; + + gEngfuncs.Con_Printf( "players %s\n", szresponse ); + } + break; + default: + break; + } +} + +/* +=================== +CompareServers + +Return 1 if p1 is "less than" p2, 0 otherwise +=================== +*/ +int CHudServers::CompareServers( server_t *p1, server_t *p2 ) +{ + const char *n1, *n2; + + if ( p1->ping < p2->ping ) + return 1; + + if ( p1->ping == p2->ping ) + { + // Pings equal, sort by second key: hostname + if ( p1->info && p2->info ) + { + n1 = NET_API->ValueForKey( p1->info, "hostname" ); + n2 = NET_API->ValueForKey( p2->info, "hostname" ); + + if ( n1 && n2 ) + { + if ( stricmp( n1, n2 ) < 0 ) + return 1; + } + } + } + + return 0; +} + +/* +=================== +AddServer + +=================== +*/ +void CHudServers::AddServer( server_t **ppList, server_t *p ) +{ +server_t *list; + + if ( !ppList || ! p ) + return; + + m_nServerCount++; + + // What sort key? Ping? + list = *ppList; + + // Head of list? + if ( !list ) + { + p->next = NULL; + *ppList = p; + return; + } + + // Put on head of list + if ( CompareServers( p, list ) ) + { + p->next = *ppList; + *ppList = p; + } + else + { + while ( list->next ) + { + // Insert before list next + if ( CompareServers( p, list->next ) ) + { + p->next = list->next->next; + list->next = p; + return; + } + + list = list->next; + } + + // Just add at end + p->next = NULL; + list->next = p; + } +} + +/* +=================== +Think + +=================== +*/ +void CHudServers::Think( double time ) +{ + m_fElapsed += time; + + if ( !m_nRequesting ) + return; + + if ( !m_nQuerying ) + return; + + QueryThink(); + + if ( ServerListSize() > 0 ) + return; + + m_dStarted = 0.0; + m_nRequesting = 0; + m_nDone = 0; + m_nQuerying = 0; + m_nActiveQueries = 0; +} + +/* +=================== +QueryThink + +=================== +*/ +void CHudServers::QueryThink( void ) +{ + request_t *p; + + if ( !m_nRequesting || m_nDone ) + return; + + if ( !m_nQuerying ) + return; + + if ( m_nActiveQueries > MAX_QUERIES ) + return; + + // Nothing left + if ( !m_pServerList ) + return; + + while ( 1 ) + { + p = m_pServerList; + + // No more in list? + if ( !p ) + break; + + // Move to next + m_pServerList = m_pServerList->next; + + // Setup context_id + p->context = context_id; + + // Start up query on this one + NET_API->SendRequest( context_id++, NETAPI_REQUEST_DETAILS, 0, 2.0, &p->remote_address, ::ServerResponse ); + + // Increment active list + m_nActiveQueries++; + + // Add to active list + p->next = m_pActiveList; + m_pActiveList = p; + + // Too many active? + if ( m_nActiveQueries > MAX_QUERIES ) + break; + } +} + +/* +================== +ServerListSize + +# of servers in active query and in pending to be queried lists +================== +*/ +int CHudServers::ServerListSize( void ) +{ + int c = 0; + request_t *p; + + p = m_pServerList; + while ( p ) + { + c++; + p = p->next; + } + + p = m_pActiveList; + while ( p ) + { + c++; + p = p->next; + } + + return c; +} + +/* +=================== +FindRequest + +Look up a request by context id +=================== +*/ +CHudServers::request_t *CHudServers::FindRequest( int context, request_t *pList ) +{ + request_t *p; + p = pList; + while ( p ) + { + if ( context == p->context ) + return p; + + p = p->next; + } + return NULL; +} + +/* +=================== +RemoveServerFromList + +Remote, but don't delete, item from *ppList +=================== +*/ +void CHudServers::RemoveServerFromList( request_t **ppList, request_t *item ) +{ + request_t *p, *n; + request_t *newlist = NULL; + + if ( !ppList ) + return; + + p = *ppList; + while ( p ) + { + n = p->next; + if ( p != item ) + { + p->next = newlist; + newlist = p; + } + p = n; + } + *ppList = newlist; +} + +/* +=================== +ClearRequestList + +=================== +*/ +void CHudServers::ClearRequestList( request_t **ppList ) +{ + request_t *p, *n; + + if ( !ppList ) + return; + + p = *ppList; + while ( p ) + { + n = p->next; + delete p; + p = n; + } + *ppList = NULL; +} + +/* +=================== +ClearServerList + +=================== +*/ +void CHudServers::ClearServerList( server_t **ppList ) +{ + server_t *p, *n; + + if ( !ppList ) + return; + + p = *ppList; + while ( p ) + { + n = p->next; + delete[] p->info; + delete p; + p = n; + } + *ppList = NULL; +} + +int CompareField( CHudServers::server_t *p1, CHudServers::server_t *p2, const char *fieldname, int iSortOrder ) +{ + const char *sz1, *sz2; + float fv1, fv2; + + sz1 = NET_API->ValueForKey( p1->info, fieldname ); + sz2 = NET_API->ValueForKey( p2->info, fieldname ); + + fv1 = atof( sz1 ); + fv2 = atof( sz2 ); + + if ( fv1 && fv2 ) + { + if ( fv1 > fv2 ) + return iSortOrder; + else if ( fv1 < fv2 ) + return -iSortOrder; + else + return 0; + } + + // String compare + return stricmp( sz1, sz2 ); +} + +int CALLBACK ServerListCompareFunc( CHudServers::server_t *p1, CHudServers::server_t *p2, const char *fieldname ) +{ + if (!p1 || !p2) // No meaningful comparison + return 0; + + int iSortOrder = 1; + + int retval = 0; + + retval = CompareField( p1, p2, fieldname, iSortOrder ); + + return retval; +} + +static char g_fieldname[ 256 ]; +int __cdecl FnServerCompare(const void *elem1, const void *elem2 ) +{ + CHudServers::server_t *list1, *list2; + + list1 = *(CHudServers::server_t **)elem1; + list2 = *(CHudServers::server_t **)elem2; + + return ServerListCompareFunc( list1, list2, g_fieldname ); +} + +void CHudServers::SortServers( const char *fieldname ) +{ + server_t *p; + // Create a list + if ( !m_pServers ) + return; + + strcpy( g_fieldname, fieldname ); + + int i; + int c = 0; + + p = m_pServers; + while ( p ) + { + c++; + p = p->next; + } + + server_t **pSortArray; + + pSortArray = new server_t *[ c ]; + memset( pSortArray, 0, c * sizeof( server_t * ) ); + + // Now copy the list into the pSortArray: + p = m_pServers; + i = 0; + while ( p ) + { + pSortArray[ i++ ] = p; + p = p->next; + } + + // Now do that actual sorting. + size_t nCount = c; + size_t nSize = sizeof( server_t * ); + + qsort( + pSortArray, + (size_t)nCount, + (size_t)nSize, + FnServerCompare + ); + + // Now rebuild the list. + m_pServers = pSortArray[0]; + for ( i = 0; i < c - 1; i++ ) + { + pSortArray[ i ]->next = pSortArray[ i + 1 ]; + } + pSortArray[ c - 1 ]->next = NULL; + + // Clean Up. + delete[] pSortArray; +} + +/* +=================== +GetServer + +Return particular server +=================== +*/ +CHudServers::server_t *CHudServers::GetServer( int server ) +{ + int c = 0; + server_t *p; + + p = m_pServers; + while ( p ) + { + if ( c == server ) + return p; + + c++; + p = p->next; + } + return NULL; +} + +/* +=================== +GetServerInfo + +Return info ( key/value ) string for particular server +=================== +*/ +char *CHudServers::GetServerInfo( int server ) +{ + server_t *p = GetServer( server ); + if ( p ) + { + return p->info; + } + return NULL; +} + +/* +=================== +CancelRequest + +Kill all pending requests in engine +=================== +*/ +void CHudServers::CancelRequest( void ) +{ + m_nRequesting = 0; + m_nQuerying = 0; + m_nDone = 1; + + NET_API->CancelAllRequests(); +} + +/* +================== +LoadMasterAddresses + +Loads the master server addresses from file and into the passed in array +================== +*/ +int CHudServers::LoadMasterAddresses( int maxservers, int *count, netadr_t *padr ) +{ + int i; + char szMaster[ 256 ]; + char szMasterFile[256]; + char *pbuffer = NULL; + char *pstart = NULL ; + netadr_t adr; + char szAdr[64]; + int nPort; + int nCount = 0; + bool bIgnore; + int nDefaultPort; + + // Assume default master and master file + strcpy( szMaster, VALVE_MASTER_ADDRESS ); // IP:PORT string + strcpy( szMasterFile, MASTER_PARSE_FILE ); + + // See if there is a command line override + i = gEngfuncs.CheckParm( "-comm", &pstart ); + if ( i && pstart ) + { + strcpy (szMasterFile, pstart ); + } + + // Read them in from proper file + pbuffer = (char *)gEngfuncs.COM_LoadFile( szMasterFile, 5, NULL ); // Use malloc + if ( !pbuffer ) + { + goto finish_master; + } + + pstart = pbuffer; + + while ( nCount < maxservers ) + { + pstart = gEngfuncs.COM_ParseFile( pstart, m_szToken ); + + if ( strlen(m_szToken) <= 0) + break; + + bIgnore = true; + + if ( !stricmp( m_szToken, "Master" ) ) + { + nDefaultPort = PORT_MASTER; + bIgnore = FALSE; + } + + // Now parse all addresses between { } + pstart = gEngfuncs.COM_ParseFile( pstart, m_szToken ); + if ( strlen(m_szToken) <= 0 ) + break; + + if ( stricmp ( m_szToken, "{" ) ) + break; + + // Parse addresses until we get to "}" + while ( nCount < maxservers ) + { + char base[256]; + + // Now parse all addresses between { } + pstart = gEngfuncs.COM_ParseFile( pstart, m_szToken ); + + if (strlen(m_szToken) <= 0) + break; + + if ( !stricmp ( m_szToken, "}" ) ) + break; + + sprintf( base, "%s", m_szToken ); + + pstart = gEngfuncs.COM_ParseFile( pstart, m_szToken ); + + if (strlen(m_szToken) <= 0) + break; + + if ( stricmp( m_szToken, ":" ) ) + break; + + pstart = gEngfuncs.COM_ParseFile( pstart, m_szToken ); + + if (strlen(m_szToken) <= 0) + break; + + nPort = atoi ( m_szToken ); + if ( !nPort ) + nPort = nDefaultPort; + + sprintf( szAdr, "%s:%i", base, nPort ); + + // Can we resolve it any better + if ( !NET_API->StringToAdr( szAdr, &adr ) ) + bIgnore = true; + + if ( !bIgnore ) + { + padr[ nCount++ ] = adr; + } + } + } + +finish_master: + if ( !nCount ) + { + sprintf( szMaster, VALVE_MASTER_ADDRESS ); // IP:PORT string + + // Convert to netadr_t + if ( NET_API->StringToAdr ( szMaster, &adr ) ) + { + + padr[ nCount++ ] = adr; + } + } + + *count = nCount; + + if ( pbuffer ) + { + gEngfuncs.COM_FreeFile( pbuffer ); + } + + return ( nCount > 0 ) ? 1 : 0; +} + +/* +=================== +RequestList + +Request list of game servers from master +=================== +*/ +void CHudServers::RequestList( void ) +{ + m_nRequesting = 1; + m_nDone = 0; + m_dStarted = m_fElapsed; + + int count = 0; + netadr_t adr; + + if ( !LoadMasterAddresses( 1, &count, &adr ) ) + { + gEngfuncs.Con_DPrintf( "SendRequest: Unable to read master server addresses\n" ); + return; + } + + ClearRequestList( &m_pActiveList ); + ClearRequestList( &m_pServerList ); + ClearServerList( &m_pServers ); + + m_nServerCount = 0; + + // Make sure networking system has started. + NET_API->InitNetworking(); + + // Kill off left overs if any + NET_API->CancelAllRequests(); + + // Request Server List from master + NET_API->SendRequest( context_id++, NETAPI_REQUEST_SERVERLIST, 0, 5.0, &adr, ::ListResponse ); +} + +void CHudServers::RequestBroadcastList( int clearpending ) +{ + m_nRequesting = 1; + m_nDone = 0; + m_dStarted = m_fElapsed; + + netadr_t adr; + memset( &adr, 0, sizeof( adr ) ); + + if ( clearpending ) + { + ClearRequestList( &m_pActiveList ); + ClearRequestList( &m_pServerList ); + ClearServerList( &m_pServers ); + + m_nServerCount = 0; + } + + // Make sure to byte swap server if necessary ( using "host" to "net" conversion + adr.port = htons( PORT_SERVER ); + + // Make sure networking system has started. + NET_API->InitNetworking(); + + if ( clearpending ) + { + // Kill off left overs if any + NET_API->CancelAllRequests(); + } + + adr.type = NA_BROADCAST; + + // Request Servers from LAN via IP + NET_API->SendRequest( context_id++, NETAPI_REQUEST_DETAILS, FNETAPI_MULTIPLE_RESPONSE, 5.0, &adr, ::ServerResponse ); + + adr.type = NA_BROADCAST_IPX; + + // Request Servers from LAN via IPX ( if supported ) + NET_API->SendRequest( context_id++, NETAPI_REQUEST_DETAILS, FNETAPI_MULTIPLE_RESPONSE, 5.0, &adr, ::ServerResponse ); +} + +void CHudServers::ServerPing( int server ) +{ + server_t *p; + + p = GetServer( server ); + if ( !p ) + return; + + // Make sure networking system has started. + NET_API->InitNetworking(); + + // Request Server List from master + NET_API->SendRequest( context_id++, NETAPI_REQUEST_PING, 0, 5.0, &p->remote_address, ::PingResponse ); +} + +void CHudServers::ServerRules( int server ) +{ + server_t *p; + + p = GetServer( server ); + if ( !p ) + return; + + // Make sure networking system has started. + NET_API->InitNetworking(); + + // Request Server List from master + NET_API->SendRequest( context_id++, NETAPI_REQUEST_RULES, 0, 5.0, &p->remote_address, ::RulesResponse ); +} + +void CHudServers::ServerPlayers( int server ) +{ + server_t *p; + + p = GetServer( server ); + if ( !p ) + return; + + // Make sure networking system has started. + NET_API->InitNetworking(); + + // Request Server List from master + NET_API->SendRequest( context_id++, NETAPI_REQUEST_PLAYERS, 0, 5.0, &p->remote_address, ::PlayersResponse ); +} + +int CHudServers::isQuerying() +{ + return m_nRequesting ? 1 : 0; +} + + +/* +=================== +GetServerCount + +Return number of servers in browser list +=================== +*/ +int CHudServers::GetServerCount( void ) +{ + return m_nServerCount; +} + +/* +=================== +CHudServers + +=================== +*/ +CHudServers::CHudServers( void ) +{ + m_nRequesting = 0; + m_dStarted = 0.0; + m_nDone = 0; + m_pServerList = NULL; + m_pServers = NULL; + m_pActiveList = NULL; + m_nQuerying = 0; + m_nActiveQueries = 0; + + m_fElapsed = 0.0; + + + m_pPingRequest = NULL; + m_pRulesRequest = NULL; + m_pPlayersRequest = NULL; +} + +/* +=================== +~CHudServers + +=================== +*/ +CHudServers::~CHudServers( void ) +{ + ClearRequestList( &m_pActiveList ); + ClearRequestList( &m_pServerList ); + ClearServerList( &m_pServers ); + + m_nServerCount = 0; + + if ( m_pPingRequest ) + { + delete m_pPingRequest; + m_pPingRequest = NULL; + + } + + if ( m_pRulesRequest ) + { + delete m_pRulesRequest; + m_pRulesRequest = NULL; + } + + if ( m_pPlayersRequest ) + { + delete m_pPlayersRequest; + m_pPlayersRequest = NULL; + } +} + +/////////////////////////////// +// +// PUBLIC APIs +// +/////////////////////////////// + +/* +=================== +ServersGetCount + +=================== +*/ +int ServersGetCount( void ) +{ + if ( g_pServers ) + { + return g_pServers->GetServerCount(); + } + return 0; +} + +int ServersIsQuerying( void ) +{ + if ( g_pServers ) + { + return g_pServers->isQuerying(); + } + return 0; +} + +/* +=================== +ServersGetInfo + +=================== +*/ +const char *ServersGetInfo( int server ) +{ + if ( g_pServers ) + { + return g_pServers->GetServerInfo( server ); + } + + return NULL; +} + +void SortServers( const char *fieldname ) +{ + if ( g_pServers ) + { + g_pServers->SortServers( fieldname ); + } +} + +/* +=================== +ServersShutdown + +=================== +*/ +void ServersShutdown( void ) +{ + if ( g_pServers ) + { + delete g_pServers; + g_pServers = NULL; + } +} + +/* +=================== +ServersInit + +=================== +*/ +void ServersInit( void ) +{ + // Kill any previous instance + ServersShutdown(); + + g_pServers = new CHudServers(); +} + +/* +=================== +ServersThink + +=================== +*/ +void ServersThink( double time ) +{ + if ( g_pServers ) + { + g_pServers->Think( time ); + } +} + +/* +=================== +ServersCancel + +=================== +*/ +void ServersCancel( void ) +{ + if ( g_pServers ) + { + g_pServers->CancelRequest(); + } +} + +// Requests +/* +=================== +ServersList + +=================== +*/ +void ServersList( void ) +{ + if ( g_pServers ) + { + g_pServers->RequestList(); + } +} + +void BroadcastServersList( int clearpending ) +{ + if ( g_pServers ) + { + g_pServers->RequestBroadcastList( clearpending ); + } +} + +void ServerPing( int server ) +{ + if ( g_pServers ) + { + g_pServers->ServerPing( server ); + } +} + +void ServerRules( int server ) +{ + if ( g_pServers ) + { + g_pServers->ServerRules( server ); + } +} + +void ServerPlayers( int server ) +{ + if ( g_pServers ) + { + g_pServers->ServerPlayers( server ); + } +} \ No newline at end of file diff --git a/cl_dll/hud_servers.h b/cl_dll/hud_servers.h new file mode 100644 index 0000000..cb8a725 --- /dev/null +++ b/cl_dll/hud_servers.h @@ -0,0 +1,34 @@ +#if !defined( HUD_SERVERSH ) +#define HUD_SERVERSH +#pragma once + +#define NET_CALLBACK /* */ + +// Dispatchers +void NET_CALLBACK ListResponse( struct net_response_s *response ); +void NET_CALLBACK ServerResponse( struct net_response_s *response ); +void NET_CALLBACK PingResponse( struct net_response_s *response ); +void NET_CALLBACK RulesResponse( struct net_response_s *response ); +void NET_CALLBACK PlayersResponse( struct net_response_s *response ); + +void ServersInit( void ); +void ServersShutdown( void ); +void ServersThink( double time ); +void ServersCancel( void ); + +// Get list and get server info from each +void ServersList( void ); + +// Query for IP / IPX LAN servers +void BroadcastServersList( int clearpending ); + +void ServerPing( int server ); +void ServerRules( int server ); +void ServerPlayers( int server ); + +int ServersGetCount( void ); +const char *ServersGetInfo( int server ); +int ServersIsQuerying( void ); +void SortServers( const char *fieldname ); + +#endif // HUD_SERVERSH \ No newline at end of file diff --git a/cl_dll/hud_servers_priv.h b/cl_dll/hud_servers_priv.h new file mode 100644 index 0000000..a571f2d --- /dev/null +++ b/cl_dll/hud_servers_priv.h @@ -0,0 +1,91 @@ +#if !defined( HUD_SERVERS_PRIVH ) +#define HUD_SERVERS_PRIVH +#pragma once + +#include "netadr.h" + +class CHudServers +{ +public: + typedef struct request_s + { + struct request_s *next; + netadr_t remote_address; + int context; + } request_t; + + typedef struct server_s + { + struct server_s *next; + netadr_t remote_address; + char *info; + int ping; + } server_t; + + CHudServers(); + ~CHudServers(); + + void Think( double time ); + void QueryThink( void ); + int isQuerying( void ); + + int LoadMasterAddresses( int maxservers, int *count, netadr_t *padr ); + + void RequestList( void ); + void RequestBroadcastList( int clearpending ); + + void ServerPing( int server ); + void ServerRules( int server ); + void ServerPlayers( int server ); + + void CancelRequest( void ); + + int CompareServers( server_t *p1, server_t *p2 ); + + void ClearServerList( server_t **ppList ); + void ClearRequestList( request_t **ppList ); + + void AddServer( server_t **ppList, server_t *p ); + + void RemoveServerFromList( request_t **ppList, request_t *item ); + + request_t *FindRequest( int context, request_t *pList ); + + int ServerListSize( void ); + char *GetServerInfo( int server ); + int GetServerCount( void ); + void SortServers( const char *fieldname ); + + void ListResponse( struct net_response_s *response ); + void ServerResponse( struct net_response_s *response ); + void PingResponse( struct net_response_s *response ); + void RulesResponse( struct net_response_s *response ); + void PlayersResponse( struct net_response_s *response ); +private: + + server_t *GetServer( int server ); + + // + char m_szToken[ 1024 ]; + int m_nRequesting; + int m_nDone; + + double m_dStarted; + + request_t *m_pServerList; + request_t *m_pActiveList; + + server_t *m_pServers; + + int m_nServerCount; + + int m_nActiveQueries; + int m_nQuerying; + double m_fElapsed; + + request_t *m_pPingRequest; + request_t *m_pRulesRequest; + request_t *m_pPlayersRequest; +}; + +#endif // HUD_SERVERS_PRIVH \ No newline at end of file diff --git a/cl_dll/hud_update.cpp b/cl_dll/hud_update.cpp index 18536ae..c8ccbac 100644 --- a/cl_dll/hud_update.cpp +++ b/cl_dll/hud_update.cpp @@ -18,25 +18,34 @@ #include #include "hud.h" -#include "util.h" +#include "cl_util.h" #include +#include +int CL_ButtonBits( int ); +void CL_ResetButtonBits( int bits ); +extern float v_idlescale; +float in_fov; +extern void HUD_SetCmdBits( int bits ); int CHud::UpdateClientData(client_data_t *cdata, float time) { memcpy(m_vecOrigin, cdata->origin, sizeof(vec3_t)); memcpy(m_vecAngles, cdata->viewangles, sizeof(vec3_t)); - m_iKeyBits = cdata->iKeyBits; + + m_iKeyBits = CL_ButtonBits( 0 ); m_iWeaponBits = cdata->iWeaponBits; - gHUD.Think(); - cdata->iKeyBits = m_iKeyBits; + in_fov = cdata->fov; + + Think(); + cdata->fov = m_iFOV; - cdata->view_idlescale = m_iConcussionEffect; + + v_idlescale = m_iConcussionEffect; - if ( m_flMouseSensitivity ) - cdata->mouse_sensitivity = m_flMouseSensitivity; + CL_ResetButtonBits( m_iKeyBits ); // return 1 if in anything in the client_data struct has been changed, 0 otherwise return 1; diff --git a/cl_dll/in_camera.cpp b/cl_dll/in_camera.cpp new file mode 100644 index 0000000..3d2a867 --- /dev/null +++ b/cl_dll/in_camera.cpp @@ -0,0 +1,614 @@ +#include "hud.h" +#include "cl_util.h" +#include "camera.h" +#include "kbutton.h" +#include "cvardef.h" +#include "usercmd.h" +#include "const.h" +#include "camera.h" +#include "in_defs.h" + +#include "windows.h" + +float CL_KeyState (kbutton_t *key); + +extern "C" +{ + void DLLEXPORT CAM_Think( void ); + int DLLEXPORT CL_IsThirdPerson( void ); + void DLLEXPORT CL_CameraOffset( float *ofs ); +} + +extern cl_enginefunc_t gEngfuncs; + +//-------------------------------------------------- Constants + +#define CAM_DIST_DELTA 1.0 +#define CAM_ANGLE_DELTA 2.5 +#define CAM_ANGLE_SPEED 2.5 +#define CAM_MIN_DIST 30.0 +#define CAM_ANGLE_MOVE .5 +#define MAX_ANGLE_DIFF 10.0 +#define PITCH_MAX 90.0 +#define PITCH_MIN 0 +#define YAW_MAX 135.0 +#define YAW_MIN -135.0 + +enum ECAM_Command +{ + CAM_COMMAND_NONE = 0, + CAM_COMMAND_TOTHIRDPERSON = 1, + CAM_COMMAND_TOFIRSTPERSON = 2 +}; + +//-------------------------------------------------- Global Variables + +cvar_t *cam_command; +cvar_t *cam_snapto; +cvar_t *cam_idealyaw; +cvar_t *cam_idealpitch; +cvar_t *cam_idealdist; +cvar_t *cam_contain; + +cvar_t *c_maxpitch; +cvar_t *c_minpitch; +cvar_t *c_maxyaw; +cvar_t *c_minyaw; +cvar_t *c_maxdistance; +cvar_t *c_mindistance; + +// pitch, yaw, dist +vec3_t cam_ofs; + + +// In third person +int cam_thirdperson; +int cam_mousemove; //true if we are moving the cam with the mouse, False if not +int iMouseInUse=0; +int cam_distancemove; +extern int mouse_x, mouse_y; //used to determine what the current x and y values are +int cam_old_mouse_x, cam_old_mouse_y; //holds the last ticks mouse movement +POINT cam_mouse; +//-------------------------------------------------- Local Variables + +static kbutton_t cam_pitchup, cam_pitchdown, cam_yawleft, cam_yawright; +static kbutton_t cam_in, cam_out, cam_move; + +//-------------------------------------------------- Prototypes + +void CAM_ToThirdPerson(void); +void CAM_ToFirstPerson(void); +void CAM_StartDistance(void); +void CAM_EndDistance(void); + + +//-------------------------------------------------- Local Functions + +float MoveToward( float cur, float goal, float maxspeed ) +{ + if( cur != goal ) + { + if( abs( cur - goal ) > 180.0 ) + { + if( cur < goal ) + cur += 360.0; + else + cur -= 360.0; + } + + if( cur < goal ) + { + if( cur < goal - 1.0 ) + cur += ( goal - cur ) / 4.0; + else + cur = goal; + } + else + { + if( cur > goal + 1.0 ) + cur -= ( cur - goal ) / 4.0; + else + cur = goal; + } + } + + + // bring cur back into range + if( cur < 0 ) + cur += 360.0; + else if( cur >= 360 ) + cur -= 360; + + return cur; +} + + +//-------------------------------------------------- Gobal Functions + +typedef struct +{ + vec3_t boxmins, boxmaxs;// enclose the test object along entire move + float *mins, *maxs; // size of the moving object + vec3_t mins2, maxs2; // size when clipping against mosnters + float *start, *end; + trace_t trace; + int type; + edict_t *passedict; + qboolean monsterclip; +} moveclip_t; + +extern trace_t SV_ClipMoveToEntity (edict_t *ent, vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end); + +void DLLEXPORT CAM_Think( void ) +{ + vec3_t origin; + vec3_t ext, pnt, camForward, camRight, camUp; + moveclip_t clip; + float dist; + vec3_t camAngles; + float flSensitivity; +#ifdef LATER + int i; +#endif + vec3_t viewangles; + + switch( (int) cam_command->value ) + { + case CAM_COMMAND_TOTHIRDPERSON: + CAM_ToThirdPerson(); + break; + + case CAM_COMMAND_TOFIRSTPERSON: + CAM_ToFirstPerson(); + break; + + case CAM_COMMAND_NONE: + default: + break; + } + + if( !cam_thirdperson ) + return; + +#ifdef LATER + if ( cam_contain->value ) + { + gEngfuncs.GetClientOrigin( origin ); + ext[0] = ext[1] = ext[2] = 0.0; + } +#endif + + camAngles[ PITCH ] = cam_idealpitch->value; + camAngles[ YAW ] = cam_idealyaw->value; + dist = cam_idealdist->value; + // + //movement of the camera with the mouse + // + if (cam_mousemove) + { + //get windows cursor position + GetCursorPos (&cam_mouse); + //check for X delta values and adjust accordingly + //eventually adjust YAW based on amount of movement + //don't do any movement of the cam using YAW/PITCH if we are zooming in/out the camera + if (!cam_distancemove) + { + + //keep the camera within certain limits around the player (ie avoid certain bad viewing angles) + if (cam_mouse.x>gEngfuncs.GetWindowCenterX()) + { + //if ((camAngles[YAW]>=225.0)||(camAngles[YAW]<135.0)) + if (camAngles[YAW]value) + { + camAngles[ YAW ] += (CAM_ANGLE_MOVE)*((cam_mouse.x-gEngfuncs.GetWindowCenterX())/2); + } + if (camAngles[YAW]>c_maxyaw->value) + { + + camAngles[YAW]=c_maxyaw->value; + } + } + else if (cam_mouse.x225.0)) + if (camAngles[YAW]>c_minyaw->value) + { + camAngles[ YAW ] -= (CAM_ANGLE_MOVE)* ((gEngfuncs.GetWindowCenterX()-cam_mouse.x)/2); + + } + if (camAngles[YAW]value) + { + camAngles[YAW]=c_minyaw->value; + + } + } + + //check for y delta values and adjust accordingly + //eventually adjust PITCH based on amount of movement + //also make sure camera is within bounds + if (cam_mouse.y>gEngfuncs.GetWindowCenterY()) + { + if(camAngles[PITCH]value) + { + camAngles[PITCH] +=(CAM_ANGLE_MOVE)* ((cam_mouse.y-gEngfuncs.GetWindowCenterY())/2); + } + if (camAngles[PITCH]>c_maxpitch->value) + { + camAngles[PITCH]=c_maxpitch->value; + } + } + else if (cam_mouse.yc_minpitch->value) + { + camAngles[PITCH] -= (CAM_ANGLE_MOVE)*((gEngfuncs.GetWindowCenterY()-cam_mouse.y)/2); + } + if (camAngles[PITCH]value) + { + camAngles[PITCH]=c_minpitch->value; + } + } + + //set old mouse coordinates to current mouse coordinates + //since we are done with the mouse + + if ( ( flSensitivity = gHUD.GetSensitivity() ) != 0 ) + { + cam_old_mouse_x=cam_mouse.x*flSensitivity; + cam_old_mouse_y=cam_mouse.y*flSensitivity; + } + else + { + cam_old_mouse_x=cam_mouse.x; + cam_old_mouse_y=cam_mouse.y; + } + SetCursorPos (gEngfuncs.GetWindowCenterX(), gEngfuncs.GetWindowCenterY()); + } + } + + //Nathan code here + if( CL_KeyState( &cam_pitchup ) ) + camAngles[ PITCH ] += CAM_ANGLE_DELTA; + else if( CL_KeyState( &cam_pitchdown ) ) + camAngles[ PITCH ] -= CAM_ANGLE_DELTA; + + if( CL_KeyState( &cam_yawleft ) ) + camAngles[ YAW ] -= CAM_ANGLE_DELTA; + else if( CL_KeyState( &cam_yawright ) ) + camAngles[ YAW ] += CAM_ANGLE_DELTA; + + if( CL_KeyState( &cam_in ) ) + { + dist -= CAM_DIST_DELTA; + if( dist < CAM_MIN_DIST ) + { + // If we go back into first person, reset the angle + camAngles[ PITCH ] = 0; + camAngles[ YAW ] = 0; + dist = CAM_MIN_DIST; + } + + } + else if( CL_KeyState( &cam_out ) ) + dist += CAM_DIST_DELTA; + + if (cam_distancemove) + { + if (cam_mouse.y>gEngfuncs.GetWindowCenterY()) + { + if(distvalue) + { + dist +=CAM_DIST_DELTA * ((cam_mouse.y-gEngfuncs.GetWindowCenterY())/2); + } + if (dist>c_maxdistance->value) + { + dist=c_maxdistance->value; + } + } + else if (cam_mouse.yc_mindistance->value) + { + dist -= (CAM_DIST_DELTA)*((gEngfuncs.GetWindowCenterY()-cam_mouse.y)/2); + } + if (distvalue) + { + dist=c_mindistance->value; + } + } + //set old mouse coordinates to current mouse coordinates + //since we are done with the mouse + cam_old_mouse_x=cam_mouse.x*gHUD.GetSensitivity(); + cam_old_mouse_y=cam_mouse.y*gHUD.GetSensitivity(); + SetCursorPos (gEngfuncs.GetWindowCenterX(), gEngfuncs.GetWindowCenterY()); + } +#ifdef LATER + if( cam_contain->value ) + { + // check new ideal + VectorCopy( origin, pnt ); + AngleVectors( camAngles, camForward, camRight, camUp ); + for (i=0 ; i<3 ; i++) + pnt[i] += -dist*camForward[i]; + + // check line from r_refdef.vieworg to pnt + memset ( &clip, 0, sizeof ( moveclip_t ) ); + clip.trace = SV_ClipMoveToEntity( sv.edicts, r_refdef.vieworg, ext, ext, pnt ); + if( clip.trace.fraction == 1.0 ) + { + // update ideal + cam_idealpitch->value = camAngles[ PITCH ]; + cam_idealyaw->value = camAngles[ YAW ]; + cam_idealdist->value = dist; + } + } + else +#endif + { + // update ideal + cam_idealpitch->value = camAngles[ PITCH ]; + cam_idealyaw->value = camAngles[ YAW ]; + cam_idealdist->value = dist; + } + + // Move towards ideal + VectorCopy( cam_ofs, camAngles ); + + gEngfuncs.GetViewAngles( (float *)viewangles ); + + if( cam_snapto->value ) + { + camAngles[ YAW ] = cam_idealyaw->value + viewangles[ YAW ]; + camAngles[ PITCH ] = cam_idealpitch->value + viewangles[ PITCH ]; + camAngles[ 2 ] = cam_idealdist->value; + } + else + { + if( camAngles[ YAW ] - viewangles[ YAW ] != cam_idealyaw->value ) + camAngles[ YAW ] = MoveToward( camAngles[ YAW ], cam_idealyaw->value + viewangles[ YAW ], CAM_ANGLE_SPEED ); + + if( camAngles[ PITCH ] - viewangles[ PITCH ] != cam_idealpitch->value ) + camAngles[ PITCH ] = MoveToward( camAngles[ PITCH ], cam_idealpitch->value + viewangles[ PITCH ], CAM_ANGLE_SPEED ); + + if( abs( camAngles[ 2 ] - cam_idealdist->value ) < 2.0 ) + camAngles[ 2 ] = cam_idealdist->value; + else + camAngles[ 2 ] += ( cam_idealdist->value - camAngles[ 2 ] ) / 4.0; + } +#ifdef LATER + if( cam_contain->value ) + { + // Test new position + dist = camAngles[ ROLL ]; + camAngles[ ROLL ] = 0; + + VectorCopy( origin, pnt ); + AngleVectors( camAngles, camForward, camRight, camUp ); + for (i=0 ; i<3 ; i++) + pnt[i] += -dist*camForward[i]; + + // check line from r_refdef.vieworg to pnt + memset ( &clip, 0, sizeof ( moveclip_t ) ); + ext[0] = ext[1] = ext[2] = 0.0; + clip.trace = SV_ClipMoveToEntity( sv.edicts, r_refdef.vieworg, ext, ext, pnt ); + if( clip.trace.fraction != 1.0 ) + return; + } +#endif + cam_ofs[ 0 ] = camAngles[ 0 ]; + cam_ofs[ 1 ] = camAngles[ 1 ]; + cam_ofs[ 2 ] = dist; +} + +extern void KeyDown (kbutton_t *b); // HACK +extern void KeyUp (kbutton_t *b); // HACK + +void CAM_PitchUpDown(void) { KeyDown( &cam_pitchup ); } +void CAM_PitchUpUp(void) { KeyUp( &cam_pitchup ); } +void CAM_PitchDownDown(void) { KeyDown( &cam_pitchdown ); } +void CAM_PitchDownUp(void) { KeyUp( &cam_pitchdown ); } +void CAM_YawLeftDown(void) { KeyDown( &cam_yawleft ); } +void CAM_YawLeftUp(void) { KeyUp( &cam_yawleft ); } +void CAM_YawRightDown(void) { KeyDown( &cam_yawright ); } +void CAM_YawRightUp(void) { KeyUp( &cam_yawright ); } +void CAM_InDown(void) { KeyDown( &cam_in ); } +void CAM_InUp(void) { KeyUp( &cam_in ); } +void CAM_OutDown(void) { KeyDown( &cam_out ); } +void CAM_OutUp(void) { KeyUp( &cam_out ); } + +void CAM_ToThirdPerson(void) +{ + vec3_t viewangles; + +#if !defined( _DEBUG ) + if ( gEngfuncs.GetMaxClients() > 1 ) + { + // no thirdperson in multiplayer. + return; + } +#endif + + gEngfuncs.GetViewAngles( (float *)viewangles ); + + if( !cam_thirdperson ) + { + cam_thirdperson = 1; + + cam_ofs[ YAW ] = viewangles[ YAW ]; + cam_ofs[ PITCH ] = viewangles[ PITCH ]; + cam_ofs[ 2 ] = CAM_MIN_DIST; + } + + gEngfuncs.Cvar_SetValue( "cam_command", 0 ); +} + +void CAM_ToFirstPerson(void) +{ + cam_thirdperson = 0; + + gEngfuncs.Cvar_SetValue( "cam_command", 0 ); +} + +void CAM_ToggleSnapto( void ) +{ + cam_snapto->value = !cam_snapto->value; +} + +void CAM_Init( void ) +{ + gEngfuncs.pfnAddCommand( "+campitchup", CAM_PitchUpDown ); + gEngfuncs.pfnAddCommand( "-campitchup", CAM_PitchUpUp ); + gEngfuncs.pfnAddCommand( "+campitchdown", CAM_PitchDownDown ); + gEngfuncs.pfnAddCommand( "-campitchdown", CAM_PitchDownUp ); + gEngfuncs.pfnAddCommand( "+camyawleft", CAM_YawLeftDown ); + gEngfuncs.pfnAddCommand( "-camyawleft", CAM_YawLeftUp ); + gEngfuncs.pfnAddCommand( "+camyawright", CAM_YawRightDown ); + gEngfuncs.pfnAddCommand( "-camyawright", CAM_YawRightUp ); + gEngfuncs.pfnAddCommand( "+camin", CAM_InDown ); + gEngfuncs.pfnAddCommand( "-camin", CAM_InUp ); + gEngfuncs.pfnAddCommand( "+camout", CAM_OutDown ); + gEngfuncs.pfnAddCommand( "-camout", CAM_OutUp ); + gEngfuncs.pfnAddCommand( "thirdperson", CAM_ToThirdPerson ); + gEngfuncs.pfnAddCommand( "firstperson", CAM_ToFirstPerson ); + gEngfuncs.pfnAddCommand( "+cammousemove",CAM_StartMouseMove); + gEngfuncs.pfnAddCommand( "-cammousemove",CAM_EndMouseMove); + gEngfuncs.pfnAddCommand( "+camdistance", CAM_StartDistance ); + gEngfuncs.pfnAddCommand( "-camdistance", CAM_EndDistance ); + gEngfuncs.pfnAddCommand( "snapto", CAM_ToggleSnapto ); + + cam_command = gEngfuncs.pfnRegisterVariable ( "cam_command", "0", 0 ); // tells camera to go to thirdperson + cam_snapto = gEngfuncs.pfnRegisterVariable ( "cam_snapto", "0", 0 ); // snap to thirdperson view + cam_idealyaw = gEngfuncs.pfnRegisterVariable ( "cam_idealyaw", "90", 0 ); // thirdperson yaw + cam_idealpitch = gEngfuncs.pfnRegisterVariable ( "cam_idealpitch", "0", 0 ); // thirperson pitch + cam_idealdist = gEngfuncs.pfnRegisterVariable ( "cam_idealdist", "64", 0 ); // thirdperson distance + cam_contain = gEngfuncs.pfnRegisterVariable ( "cam_contain", "0", 0 ); // contain camera to world + + c_maxpitch = gEngfuncs.pfnRegisterVariable ( "c_maxpitch", "90.0", 0 ); + c_minpitch = gEngfuncs.pfnRegisterVariable ( "c_minpitch", "0.0", 0 ); + c_maxyaw = gEngfuncs.pfnRegisterVariable ( "c_maxyaw", "135.0", 0 ); + c_minyaw = gEngfuncs.pfnRegisterVariable ( "c_minyaw", "-135.0", 0 ); + c_maxdistance = gEngfuncs.pfnRegisterVariable ( "c_maxdistance", "200.0", 0 ); + c_mindistance = gEngfuncs.pfnRegisterVariable ( "c_mindistance", "30.0", 0 ); +} + +void CAM_ClearStates( void ) +{ + vec3_t viewangles; + + gEngfuncs.GetViewAngles( (float *)viewangles ); + + cam_pitchup.state = 0; + cam_pitchdown.state = 0; + cam_yawleft.state = 0; + cam_yawright.state = 0; + cam_in.state = 0; + cam_out.state = 0; + + cam_thirdperson = 0; + cam_command->value = 0; + cam_mousemove=0; + + cam_snapto->value = 0; + cam_distancemove = 0; + + cam_ofs[ 0 ] = 0.0; + cam_ofs[ 1 ] = 0.0; + cam_ofs[ 2 ] = CAM_MIN_DIST; + + cam_idealpitch->value = viewangles[ PITCH ]; + cam_idealyaw->value = viewangles[ YAW ]; + cam_idealdist->value = CAM_MIN_DIST; +} + +void CAM_StartMouseMove(void) +{ + float flSensitivity; + + //only move the cam with mouse if we are in third person. + if (cam_thirdperson) + { + //set appropriate flags and initialize the old mouse position + //variables for mouse camera movement + if (!cam_mousemove) + { + cam_mousemove=1; + iMouseInUse=1; + GetCursorPos (&cam_mouse); + + if ( ( flSensitivity = gHUD.GetSensitivity() ) != 0 ) + { + cam_old_mouse_x=cam_mouse.x*flSensitivity; + cam_old_mouse_y=cam_mouse.y*flSensitivity; + } + else + { + cam_old_mouse_x=cam_mouse.x; + cam_old_mouse_y=cam_mouse.y; + } + } + } + //we are not in 3rd person view..therefore do not allow camera movement + else + { + cam_mousemove=0; + iMouseInUse=0; + } +} + +//the key has been released for camera movement +//tell the engine that mouse camera movement is off +void CAM_EndMouseMove(void) +{ + cam_mousemove=0; + iMouseInUse=0; +} + + +//---------------------------------------------------------- +//routines to start the process of moving the cam in or out +//using the mouse +//---------------------------------------------------------- +void CAM_StartDistance(void) +{ + //only move the cam with mouse if we are in third person. + if (cam_thirdperson) + { + //set appropriate flags and initialize the old mouse position + //variables for mouse camera movement + if (!cam_distancemove) + { + cam_distancemove=1; + cam_mousemove=1; + iMouseInUse=1; + GetCursorPos (&cam_mouse); + cam_old_mouse_x=cam_mouse.x*gHUD.GetSensitivity(); + cam_old_mouse_y=cam_mouse.y*gHUD.GetSensitivity(); + } + } + //we are not in 3rd person view..therefore do not allow camera movement + else + { + cam_distancemove=0; + cam_mousemove=0; + iMouseInUse=0; + } +} + +//the key has been released for camera movement +//tell the engine that mouse camera movement is off +void CAM_EndDistance(void) +{ + cam_distancemove=0; + cam_mousemove=0; + iMouseInUse=0; +} + +int DLLEXPORT CL_IsThirdPerson( void ) +{ + return cam_thirdperson ? 1 : 0; +} + +void DLLEXPORT CL_CameraOffset( float *ofs ) +{ + VectorCopy( cam_ofs, ofs ); +} \ No newline at end of file diff --git a/cl_dll/in_defs.h b/cl_dll/in_defs.h new file mode 100644 index 0000000..30e22d2 --- /dev/null +++ b/cl_dll/in_defs.h @@ -0,0 +1,14 @@ +#if !defined( IN_DEFSH ) +#define IN_DEFSH +#pragma once + +// up / down +#define PITCH 0 +// left / right +#define YAW 1 +// fall over +#define ROLL 2 + +#define DLLEXPORT __declspec( dllexport ) + +#endif \ No newline at end of file diff --git a/cl_dll/input.cpp b/cl_dll/input.cpp new file mode 100644 index 0000000..f883948 --- /dev/null +++ b/cl_dll/input.cpp @@ -0,0 +1,957 @@ +// cl.input.c -- builds an intended movement command to send to the server + +//xxxxxx Move bob and pitch drifting code here and other stuff from view if needed + +// Quake is a trademark of Id Software, Inc., (c) 1996 Id Software, Inc. All +// rights reserved. +#include "hud.h" +#include "cl_util.h" +#include "camera.h" +extern "C" +{ +#include "kbutton.h" +} +#include "cvardef.h" +#include "usercmd.h" +#include "const.h" +#include "camera.h" +#include "in_defs.h" +#include "view.h" +#include +#include + +#include "vgui_TeamFortressViewport.h" + +extern "C" +{ + struct kbutton_s DLLEXPORT *KB_Find( const char *name ); + void DLLEXPORT CL_CreateMove ( float frametime, struct usercmd_s *cmd, int active ); + void DLLEXPORT HUD_Shutdown( void ); + int DLLEXPORT HUD_Key_Event( int eventcode, int keynum, const char *pszCurrentBinding ); +} + +extern int g_weaponselect; +extern cl_enginefunc_t gEngfuncs; + +// Defined in pm_math.c +extern "C" float anglemod( float a ); + +void IN_Init (void); +void IN_Move ( float frametime, usercmd_t *cmd); +void IN_Shutdown( void ); +void V_Init( void ); +void VectorAngles( const float *forward, float *angles ); +int CL_ButtonBits( int ); + +// xxx need client dll function to get and clear impuse +extern cvar_t *in_joystick; + +int in_impulse = 0; +int in_cancel = 0; + +cvar_t *m_pitch; +cvar_t *m_yaw; +cvar_t *m_forward; +cvar_t *m_side; + +cvar_t *lookstrafe; +cvar_t *lookspring; +cvar_t *cl_pitchup; +cvar_t *cl_pitchdown; +cvar_t *cl_upspeed; +cvar_t *cl_forwardspeed; +cvar_t *cl_backspeed; +cvar_t *cl_sidespeed; +cvar_t *cl_movespeedkey; +cvar_t *cl_yawspeed; +cvar_t *cl_pitchspeed; +cvar_t *cl_anglespeedkey; +cvar_t *cl_vsmoothing; +/* +=============================================================================== + +KEY BUTTONS + +Continuous button event tracking is complicated by the fact that two different +input sources (say, mouse button 1 and the control key) can both press the +same button, but the button should only be released when both of the +pressing key have been released. + +When a key event issues a button command (+forward, +attack, etc), it appends +its key number as a parameter to the command so it can be matched up with +the release. + +state bit 0 is the current state of the key +state bit 1 is edge triggered on the up to down transition +state bit 2 is edge triggered on the down to up transition + +=============================================================================== +*/ + + +kbutton_t in_mlook; +kbutton_t in_klook; +kbutton_t in_jlook; +kbutton_t in_left; +kbutton_t in_right; +kbutton_t in_forward; +kbutton_t in_back; +kbutton_t in_lookup; +kbutton_t in_lookdown; +kbutton_t in_moveleft; +kbutton_t in_moveright; +kbutton_t in_strafe; +kbutton_t in_speed; +kbutton_t in_use; +kbutton_t in_jump; +kbutton_t in_attack; +kbutton_t in_attack2; +kbutton_t in_up; +kbutton_t in_down; +kbutton_t in_duck; +kbutton_t in_reload; +kbutton_t in_alt1; +kbutton_t in_score; +kbutton_t in_break; +kbutton_t in_graph; // Display the netgraph + +typedef struct kblist_s +{ + struct kblist_s *next; + kbutton_t *pkey; + char name[32]; +} kblist_t; + +kblist_t *g_kbkeys = NULL; + +/* +============ +KB_ConvertString + +Removes references to +use and replaces them with the keyname in the output string. If + a binding is unfound, then the original text is retained. +NOTE: Only works for text with +word in it. +============ +*/ +int KB_ConvertString( char *in, char **ppout ) +{ + char sz[ 4096 ]; + char binding[ 64 ]; + char *p; + char *pOut; + char *pEnd; + const char *pBinding; + + if ( !ppout ) + return 0; + + *ppout = NULL; + p = in; + pOut = sz; + while ( *p ) + { + if ( *p == '+' ) + { + pEnd = binding; + while ( *p && ( isalnum( *p ) || ( pEnd == binding ) ) && ( ( pEnd - binding ) < 63 ) ) + { + *pEnd++ = *p++; + } + + *pEnd = '\0'; + + pBinding = NULL; + if ( strlen( binding + 1 ) > 0 ) + { + // See if there is a binding for binding? + pBinding = gEngfuncs.Key_LookupBinding( binding + 1 ); + } + + if ( pBinding ) + { + *pOut++ = '['; + pEnd = (char *)pBinding; + } + else + { + pEnd = binding; + } + + while ( *pEnd ) + { + *pOut++ = *pEnd++; + } + + if ( pBinding ) + { + *pOut++ = ']'; + } + } + else + { + *pOut++ = *p++; + } + } + + *pOut = '\0'; + + pOut = ( char * )malloc( strlen( sz ) + 1 ); + strcpy( pOut, sz ); + *ppout = pOut; + + return 1; +} + +/* +============ +KB_Find + +Allows the engine to get a kbutton_t directly ( so it can check +mlook state, etc ) for saving out to .cfg files +============ +*/ +struct kbutton_s DLLEXPORT *KB_Find( const char *name ) +{ + kblist_t *p; + p = g_kbkeys; + while ( p ) + { + if ( !stricmp( name, p->name ) ) + return p->pkey; + + p = p->next; + } + return NULL; +} + +/* +============ +KB_Add + +Add a kbutton_t * to the list of pointers the engine can retrieve via KB_Find +============ +*/ +void KB_Add( const char *name, kbutton_t *pkb ) +{ + kblist_t *p; + kbutton_t *kb; + + kb = KB_Find( name ); + + if ( kb ) + return; + + p = ( kblist_t * )malloc( sizeof( kblist_t ) ); + memset( p, 0, sizeof( *p ) ); + + strcpy( p->name, name ); + p->pkey = pkb; + + p->next = g_kbkeys; + g_kbkeys = p; +} + +/* +============ +KB_Init + +Add kbutton_t definitions that the engine can query if needed +============ +*/ +void KB_Init( void ) +{ + g_kbkeys = NULL; + + KB_Add( "in_graph", &in_graph ); + KB_Add( "in_mlook", &in_mlook ); + KB_Add( "in_jlook", &in_jlook ); +} + +/* +============ +KB_Shutdown + +Clear kblist +============ +*/ +void KB_Shutdown( void ) +{ + kblist_t *p, *n; + p = g_kbkeys; + while ( p ) + { + n = p->next; + free( p ); + p = n; + } + g_kbkeys = NULL; +} + +/* +============ +KeyDown +============ +*/ +void KeyDown (kbutton_t *b) +{ + int k; + char *c; + + c = gEngfuncs.Cmd_Argv(1); + if (c[0]) + k = atoi(c); + else + k = -1; // typed manually at the console for continuous down + + if (k == b->down[0] || k == b->down[1]) + return; // repeating key + + if (!b->down[0]) + b->down[0] = k; + else if (!b->down[1]) + b->down[1] = k; + else + { + gEngfuncs.Con_DPrintf ("Three keys down for a button '%c' '%c' '%c'!\n", b->down[0], b->down[1], c); + return; + } + + if (b->state & 1) + return; // still down + b->state |= 1 + 2; // down + impulse down +} + +/* +============ +KeyUp +============ +*/ +void KeyUp (kbutton_t *b) +{ + int k; + char *c; + + c = gEngfuncs.Cmd_Argv(1); + if (c[0]) + k = atoi(c); + else + { // typed manually at the console, assume for unsticking, so clear all + b->down[0] = b->down[1] = 0; + b->state = 4; // impulse up + return; + } + + if (b->down[0] == k) + b->down[0] = 0; + else if (b->down[1] == k) + b->down[1] = 0; + else + return; // key up without coresponding down (menu pass through) + if (b->down[0] || b->down[1]) + { + //Con_Printf ("Keys down for button: '%c' '%c' '%c' (%d,%d,%d)!\n", b->down[0], b->down[1], c, b->down[0], b->down[1], c); + return; // some other key is still holding it down + } + + if (!(b->state & 1)) + return; // still up (this should not happen) + + b->state &= ~1; // now up + b->state |= 4; // impulse up +} + +/* +============ +HUD_Key_Event + +Return 1 to allow engine to process the key, otherwise, act on it as needed +============ +*/ +int DLLEXPORT HUD_Key_Event( int down, int keynum, const char *pszCurrentBinding ) +{ + if (gViewPort) + return gViewPort->KeyInput(down, keynum, pszCurrentBinding); + + return 1; +} + +void IN_BreakDown( void ) { KeyDown( &in_break );}; +void IN_BreakUp( void ) { KeyUp( &in_break ); }; +void IN_KLookDown (void) {KeyDown(&in_klook);} +void IN_KLookUp (void) {KeyUp(&in_klook);} +void IN_JLookDown (void) {KeyDown(&in_jlook);} +void IN_JLookUp (void) {KeyUp(&in_jlook);} +void IN_MLookDown (void) {KeyDown(&in_mlook);} +void IN_UpDown(void) {KeyDown(&in_up);} +void IN_UpUp(void) {KeyUp(&in_up);} +void IN_DownDown(void) {KeyDown(&in_down);} +void IN_DownUp(void) {KeyUp(&in_down);} +void IN_LeftDown(void) {KeyDown(&in_left);} +void IN_LeftUp(void) {KeyUp(&in_left);} +void IN_RightDown(void) {KeyDown(&in_right);} +void IN_RightUp(void) {KeyUp(&in_right);} +void IN_ForwardDown(void) {KeyDown(&in_forward);} +void IN_ForwardUp(void) {KeyUp(&in_forward);} +void IN_BackDown(void) {KeyDown(&in_back);} +void IN_BackUp(void) {KeyUp(&in_back);} +void IN_LookupDown(void) {KeyDown(&in_lookup);} +void IN_LookupUp(void) {KeyUp(&in_lookup);} +void IN_LookdownDown(void) {KeyDown(&in_lookdown);} +void IN_LookdownUp(void) {KeyUp(&in_lookdown);} +void IN_MoveleftDown(void) {KeyDown(&in_moveleft);} +void IN_MoveleftUp(void) {KeyUp(&in_moveleft);} +void IN_MoverightDown(void) {KeyDown(&in_moveright);} +void IN_MoverightUp(void) {KeyUp(&in_moveright);} +void IN_SpeedDown(void) {KeyDown(&in_speed);} +void IN_SpeedUp(void) {KeyUp(&in_speed);} +void IN_StrafeDown(void) {KeyDown(&in_strafe);} +void IN_StrafeUp(void) {KeyUp(&in_strafe);} + +// needs capture by hud/vgui also +extern void __CmdFunc_InputPlayerSpecial(void); +void IN_Attack2Down(void) +{ + KeyDown(&in_attack2); + __CmdFunc_InputPlayerSpecial(); +} + +void IN_Attack2Up(void) {KeyUp(&in_attack2);} +void IN_UseDown (void) {KeyDown(&in_use);} +void IN_UseUp (void) {KeyUp(&in_use);} +void IN_JumpDown (void) {KeyDown(&in_jump);} +void IN_JumpUp (void) {KeyUp(&in_jump);} +void IN_DuckDown(void) {KeyDown(&in_duck);} +void IN_DuckUp(void) {KeyUp(&in_duck);} +void IN_ReloadDown(void) {KeyDown(&in_reload);} +void IN_ReloadUp(void) {KeyUp(&in_reload);} +void IN_Alt1Down(void) {KeyDown(&in_alt1);} +void IN_Alt1Up(void) {KeyUp(&in_alt1);} +void IN_GraphDown(void) {KeyDown(&in_graph);} +void IN_GraphUp(void) {KeyUp(&in_graph);} + +void IN_AttackDown(void) +{ + KeyDown( &in_attack ); +} + +void IN_AttackUp(void) +{ + KeyUp( &in_attack ); + in_cancel = 0; +} + +// Special handling +void IN_Cancel(void) +{ + in_cancel = 1; +} + +void IN_Impulse (void) +{ + in_impulse = atoi( gEngfuncs.Cmd_Argv(1) ); +} + +void IN_ScoreDown(void) +{ + KeyDown(&in_score); + if ( gViewPort ) + { + gViewPort->ShowScoreBoard(); + } +} + +void IN_ScoreUp(void) +{ + KeyUp(&in_score); + if ( gViewPort ) + { + gViewPort->HideScoreBoard(); + } +} + +void IN_MLookUp (void) +{ + KeyUp( &in_mlook ); + if ( !( in_mlook.state & 1 ) && lookspring->value ) + { + V_StartPitchDrift(); + } +} + +/* +=============== +CL_KeyState + +Returns 0.25 if a key was pressed and released during the frame, +0.5 if it was pressed and held +0 if held then released, and +1.0 if held for the entire time +=============== +*/ +float CL_KeyState (kbutton_t *key) +{ + float val = 0.0; + int impulsedown, impulseup, down; + + impulsedown = key->state & 2; + impulseup = key->state & 4; + down = key->state & 1; + + if ( impulsedown && !impulseup ) + { + // pressed and held this frame? + val = down ? 0.5 : 0.0; + } + + if ( impulseup && !impulsedown ) + { + // released this frame? + val = down ? 0.0 : 0.0; + } + + if ( !impulsedown && !impulseup ) + { + // held the entire frame? + val = down ? 1.0 : 0.0; + } + + if ( impulsedown && impulseup ) + { + if ( down ) + { + // released and re-pressed this frame + val = 0.75; + } + else + { + // pressed and released this frame + val = 0.25; + } + } + + // clear impulses + key->state &= 1; + return val; +} + +/* +================ +CL_AdjustAngles + +Moves the local angle positions +================ +*/ +void CL_AdjustAngles ( float frametime, float *viewangles ) +{ + float speed; + float up, down; + + if (in_speed.state & 1) + { + speed = frametime * cl_anglespeedkey->value; + } + else + { + speed = frametime; + } + + if (!(in_strafe.state & 1)) + { + viewangles[YAW] -= speed*cl_yawspeed->value*CL_KeyState (&in_right); + viewangles[YAW] += speed*cl_yawspeed->value*CL_KeyState (&in_left); + viewangles[YAW] = anglemod(viewangles[YAW]); + } + if (in_klook.state & 1) + { + V_StopPitchDrift (); + viewangles[PITCH] -= speed*cl_pitchspeed->value * CL_KeyState (&in_forward); + viewangles[PITCH] += speed*cl_pitchspeed->value * CL_KeyState (&in_back); + } + + up = CL_KeyState (&in_lookup); + down = CL_KeyState(&in_lookdown); + + viewangles[PITCH] -= speed*cl_pitchspeed->value * up; + viewangles[PITCH] += speed*cl_pitchspeed->value * down; + + if (up || down) + V_StopPitchDrift (); + + if (viewangles[PITCH] > cl_pitchdown->value) + viewangles[PITCH] = cl_pitchdown->value; + if (viewangles[PITCH] < -cl_pitchup->value) + viewangles[PITCH] = -cl_pitchup->value; + + if (viewangles[ROLL] > 50) + viewangles[ROLL] = 50; + if (viewangles[ROLL] < -50) + viewangles[ROLL] = -50; +} + +/* +================ +CL_CreateMove + +Send the intended movement message to the server +if active == 1 then we are 1) not playing back demos ( where our commands are ignored ) and +2 ) we have finished signing on to server +================ +*/ +void DLLEXPORT CL_CreateMove ( float frametime, struct usercmd_s *cmd, int active ) +{ + float spd; + vec3_t viewangles; + static vec3_t oldangles; + + if ( active ) + { + //memset( viewangles, 0, sizeof( vec3_t ) ); + //viewangles[ 0 ] = viewangles[ 1 ] = viewangles[ 2 ] = 0.0; + gEngfuncs.GetViewAngles( (float *)viewangles ); + + CL_AdjustAngles ( frametime, viewangles ); + + memset (cmd, 0, sizeof(*cmd)); + + gEngfuncs.SetViewAngles( (float *)viewangles ); + + if ( in_strafe.state & 1 ) + { + cmd->sidemove += cl_sidespeed->value * CL_KeyState (&in_right); + cmd->sidemove -= cl_sidespeed->value * CL_KeyState (&in_left); + } + + cmd->sidemove += cl_sidespeed->value * CL_KeyState (&in_moveright); + cmd->sidemove -= cl_sidespeed->value * CL_KeyState (&in_moveleft); + + cmd->upmove += cl_upspeed->value * CL_KeyState (&in_up); + cmd->upmove -= cl_upspeed->value * CL_KeyState (&in_down); + + if ( !(in_klook.state & 1 ) ) + { + cmd->forwardmove += cl_forwardspeed->value * CL_KeyState (&in_forward); + cmd->forwardmove -= cl_backspeed->value * CL_KeyState (&in_back); + } + + // adjust for speed key + if ( in_speed.state & 1 ) + { + cmd->forwardmove *= cl_movespeedkey->value; + cmd->sidemove *= cl_movespeedkey->value; + cmd->upmove *= cl_movespeedkey->value; + } + + // clip to maxspeed + spd = gEngfuncs.GetClientMaxspeed(); + if ( spd != 0.0 ) + { + // scale the 3 speeds so that the total velocity is not > cl.maxspeed + float fmov = sqrt( (cmd->forwardmove*cmd->forwardmove) + (cmd->sidemove*cmd->sidemove) + (cmd->upmove*cmd->upmove) ); + + if ( fmov > spd ) + { + float fratio = spd / fmov; + cmd->forwardmove *= fratio; + cmd->sidemove *= fratio; + cmd->upmove *= fratio; + } + } + + // Allow mice and other controllers to add their inputs + IN_Move ( frametime, cmd ); + } + + cmd->impulse = in_impulse; + in_impulse = 0; + + cmd->weaponselect = g_weaponselect; + g_weaponselect = 0; + // + // set button and flag bits + // + cmd->buttons = CL_ButtonBits( 1 ); + + // Using joystick? + if ( in_joystick->value ) + { + if ( cmd->forwardmove > 0 ) + { + cmd->buttons |= IN_FORWARD; + } + else if ( cmd->forwardmove < 0 ) + { + cmd->buttons |= IN_BACK; + } + } + + gEngfuncs.GetViewAngles( (float *)viewangles ); + // Set current view angles. + + if ( gHUD.m_Health.m_iHealth > 0 ) + { + VectorCopy( viewangles, cmd->viewangles ); + VectorCopy( viewangles, oldangles ); + } + else + { + VectorCopy( oldangles, cmd->viewangles ); + } +} + +/* +============ +CL_IsDead + +Returns 1 if health is <= 0 +============ +*/ +int CL_IsDead( void ) +{ + return ( gHUD.m_Health.m_iHealth <= 0 ) ? 1 : 0; +} + +/* +============ +CL_ButtonBits + +Returns appropriate button info for keyboard and mouse state +Set bResetState to 1 to clear old state info +============ +*/ +int CL_ButtonBits( int bResetState ) +{ + int bits = 0; + + if ( in_attack.state & 3 ) + { + bits |= IN_ATTACK; + } + + if (in_duck.state & 3) + { + bits |= IN_DUCK; + } + + if (in_jump.state & 3) + { + bits |= IN_JUMP; + } + + if ( in_forward.state & 3 ) + { + bits |= IN_FORWARD; + } + + if (in_back.state & 3) + { + bits |= IN_BACK; + } + + if (in_use.state & 3) + { + bits |= IN_USE; + } + + if (in_cancel) + { + bits |= IN_CANCEL; + } + + if ( in_left.state & 3 ) + { + bits |= IN_LEFT; + } + + if (in_right.state & 3) + { + bits |= IN_RIGHT; + } + + if ( in_moveleft.state & 3 ) + { + bits |= IN_MOVELEFT; + } + + if (in_moveright.state & 3) + { + bits |= IN_MOVERIGHT; + } + + if (in_attack2.state & 3) + { + bits |= IN_ATTACK2; + } + + if (in_reload.state & 3) + { + bits |= IN_RELOAD; + } + + if (in_alt1.state & 3) + { + bits |= IN_ALT1; + } + + if ( in_score.state & 3 ) + { + bits |= IN_SCORE; + } + + // Dead or in intermission? Shore scoreboard, too + if ( CL_IsDead() || gHUD.m_iIntermission ) + { + bits |= IN_SCORE; + } + + if ( bResetState ) + { + in_attack.state &= ~2; + in_duck.state &= ~2; + in_jump.state &= ~2; + in_forward.state &= ~2; + in_back.state &= ~2; + in_use.state &= ~2; + in_left.state &= ~2; + in_right.state &= ~2; + in_moveleft.state &= ~2; + in_moveright.state &= ~2; + in_attack2.state &= ~2; + in_reload.state &= ~2; + in_alt1.state &= ~2; + in_score.state &= ~2; + } + + return bits; +} + +/* +============ +CL_ResetButtonBits + +============ +*/ +void CL_ResetButtonBits( int bits ) +{ + int bitsNew = CL_ButtonBits( 0 ) ^ bits; + + // Has the attack button been changed + if ( bitsNew & IN_ATTACK ) + { + // Was it pressed? or let go? + if ( bits & IN_ATTACK ) + { + KeyDown( &in_attack ); + } + else + { + // totally clear state + in_attack.state &= ~7; + } + } +} + +/* +============ +InitInput +============ +*/ +void InitInput (void) +{ + gEngfuncs.pfnAddCommand ("+moveup",IN_UpDown); + gEngfuncs.pfnAddCommand ("-moveup",IN_UpUp); + gEngfuncs.pfnAddCommand ("+movedown",IN_DownDown); + gEngfuncs.pfnAddCommand ("-movedown",IN_DownUp); + gEngfuncs.pfnAddCommand ("+left",IN_LeftDown); + gEngfuncs.pfnAddCommand ("-left",IN_LeftUp); + gEngfuncs.pfnAddCommand ("+right",IN_RightDown); + gEngfuncs.pfnAddCommand ("-right",IN_RightUp); + gEngfuncs.pfnAddCommand ("+forward",IN_ForwardDown); + gEngfuncs.pfnAddCommand ("-forward",IN_ForwardUp); + gEngfuncs.pfnAddCommand ("+back",IN_BackDown); + gEngfuncs.pfnAddCommand ("-back",IN_BackUp); + gEngfuncs.pfnAddCommand ("+lookup", IN_LookupDown); + gEngfuncs.pfnAddCommand ("-lookup", IN_LookupUp); + gEngfuncs.pfnAddCommand ("+lookdown", IN_LookdownDown); + gEngfuncs.pfnAddCommand ("-lookdown", IN_LookdownUp); + gEngfuncs.pfnAddCommand ("+strafe", IN_StrafeDown); + gEngfuncs.pfnAddCommand ("-strafe", IN_StrafeUp); + gEngfuncs.pfnAddCommand ("+moveleft", IN_MoveleftDown); + gEngfuncs.pfnAddCommand ("-moveleft", IN_MoveleftUp); + gEngfuncs.pfnAddCommand ("+moveright", IN_MoverightDown); + gEngfuncs.pfnAddCommand ("-moveright", IN_MoverightUp); + gEngfuncs.pfnAddCommand ("+speed", IN_SpeedDown); + gEngfuncs.pfnAddCommand ("-speed", IN_SpeedUp); + gEngfuncs.pfnAddCommand ("+attack", IN_AttackDown); + gEngfuncs.pfnAddCommand ("-attack", IN_AttackUp); + gEngfuncs.pfnAddCommand ("+attack2", IN_Attack2Down); + gEngfuncs.pfnAddCommand ("-attack2", IN_Attack2Up); + gEngfuncs.pfnAddCommand ("+use", IN_UseDown); + gEngfuncs.pfnAddCommand ("-use", IN_UseUp); + gEngfuncs.pfnAddCommand ("+jump", IN_JumpDown); + gEngfuncs.pfnAddCommand ("-jump", IN_JumpUp); + gEngfuncs.pfnAddCommand ("impulse", IN_Impulse); + gEngfuncs.pfnAddCommand ("+klook", IN_KLookDown); + gEngfuncs.pfnAddCommand ("-klook", IN_KLookUp); + gEngfuncs.pfnAddCommand ("+mlook", IN_MLookDown); + gEngfuncs.pfnAddCommand ("-mlook", IN_MLookUp); + gEngfuncs.pfnAddCommand ("+jlook", IN_JLookDown); + gEngfuncs.pfnAddCommand ("-jlook", IN_JLookUp); + gEngfuncs.pfnAddCommand ("+duck", IN_DuckDown); + gEngfuncs.pfnAddCommand ("-duck", IN_DuckUp); + gEngfuncs.pfnAddCommand ("+reload", IN_ReloadDown); + gEngfuncs.pfnAddCommand ("-reload", IN_ReloadUp); + gEngfuncs.pfnAddCommand ("+alt1", IN_Alt1Down); + gEngfuncs.pfnAddCommand ("-alt1", IN_Alt1Up); + gEngfuncs.pfnAddCommand ("+score", IN_ScoreDown); + gEngfuncs.pfnAddCommand ("-score", IN_ScoreUp); + gEngfuncs.pfnAddCommand ("+showscores", IN_ScoreDown); + gEngfuncs.pfnAddCommand ("-showscores", IN_ScoreUp); + gEngfuncs.pfnAddCommand ("+graph", IN_GraphDown); + gEngfuncs.pfnAddCommand ("-graph", IN_GraphUp); + gEngfuncs.pfnAddCommand ("+break",IN_BreakDown); + gEngfuncs.pfnAddCommand ("-break",IN_BreakUp); + + lookstrafe = gEngfuncs.pfnRegisterVariable ( "lookstrafe", "0", FCVAR_ARCHIVE ); + lookspring = gEngfuncs.pfnRegisterVariable ( "lookspring", "0", FCVAR_ARCHIVE ); + cl_anglespeedkey = gEngfuncs.pfnRegisterVariable ( "cl_anglespeedkey", "0.67", 0 ); + cl_yawspeed = gEngfuncs.pfnRegisterVariable ( "cl_yawspeed", "210", 0 ); + cl_pitchspeed = gEngfuncs.pfnRegisterVariable ( "cl_pitchspeed", "225", 0 ); + cl_upspeed = gEngfuncs.pfnRegisterVariable ( "cl_upspeed", "320", 0 ); + cl_forwardspeed = gEngfuncs.pfnRegisterVariable ( "cl_forwardspeed", "400", FCVAR_ARCHIVE ); + cl_backspeed = gEngfuncs.pfnRegisterVariable ( "cl_backspeed", "400", FCVAR_ARCHIVE ); + cl_sidespeed = gEngfuncs.pfnRegisterVariable ( "cl_sidespeed", "400", 0 ); + cl_movespeedkey = gEngfuncs.pfnRegisterVariable ( "cl_movespeedkey", "0.3", 0 ); + cl_pitchup = gEngfuncs.pfnRegisterVariable ( "cl_pitchup", "89", 0 ); + cl_pitchdown = gEngfuncs.pfnRegisterVariable ( "cl_pitchdown", "89", 0 ); + + cl_vsmoothing = gEngfuncs.pfnRegisterVariable ( "cl_vsmoothing", "0.05", FCVAR_ARCHIVE ); + + m_pitch = gEngfuncs.pfnRegisterVariable ( "m_pitch","0.022", FCVAR_ARCHIVE ); + m_yaw = gEngfuncs.pfnRegisterVariable ( "m_yaw","0.022", FCVAR_ARCHIVE ); + m_forward = gEngfuncs.pfnRegisterVariable ( "m_forward","1", FCVAR_ARCHIVE ); + m_side = gEngfuncs.pfnRegisterVariable ( "m_side","0.8", FCVAR_ARCHIVE ); + + // Initialize third person camera controls. + CAM_Init(); + // Initialize inputs + IN_Init(); + // Initialize keyboard + KB_Init(); + // Initialize view system + V_Init(); +} + +/* +============ +ShutdownInput +============ +*/ +void ShutdownInput (void) +{ + IN_Shutdown(); + KB_Shutdown(); +} + +void DLLEXPORT HUD_Shutdown( void ) +{ + ShutdownInput(); +} \ No newline at end of file diff --git a/cl_dll/inputw32.cpp b/cl_dll/inputw32.cpp new file mode 100644 index 0000000..9477059 --- /dev/null +++ b/cl_dll/inputw32.cpp @@ -0,0 +1,940 @@ +// in_win.c -- windows 95 mouse and joystick code +// 02/21/97 JCB Added extended DirectInput code to support external controllers. + +#include "hud.h" +#include "cl_util.h" +#include "camera.h" +#include "kbutton.h" +#include "cvardef.h" +#include "usercmd.h" +#include "const.h" +#include "camera.h" +#include "in_defs.h" +#include "../engine/keydefs.h" +#include "view.h" +#include "windows.h" + +#define MOUSE_BUTTON_COUNT 5 + +// Set this to 1 to show mouse cursor. Experimental +int g_iVisibleMouse = 0; + +extern "C" +{ + void DLLEXPORT IN_ActivateMouse( void ); + void DLLEXPORT IN_DeactivateMouse( void ); + void DLLEXPORT IN_MouseEvent (int mstate); + void DLLEXPORT IN_Accumulate (void); + void DLLEXPORT IN_ClearStates (void); +} + +extern cl_enginefunc_t gEngfuncs; + +extern int iMouseInUse; + +extern kbutton_t in_strafe; +extern kbutton_t in_mlook; +extern kbutton_t in_speed; +extern kbutton_t in_jlook; + +extern cvar_t *m_pitch; +extern cvar_t *m_yaw; +extern cvar_t *m_forward; +extern cvar_t *m_side; + +extern cvar_t *lookstrafe; +extern cvar_t *lookspring; +extern cvar_t *cl_pitchdown; +extern cvar_t *cl_pitchup; +extern cvar_t *cl_yawspeed; +extern cvar_t *cl_sidespeed; +extern cvar_t *cl_forwardspeed; +extern cvar_t *cl_pitchspeed; +extern cvar_t *cl_movespeedkey; + +// mouse variables +cvar_t *m_filter; +cvar_t *sensitivity; + +int mouse_buttons; +int mouse_oldbuttonstate; +POINT current_pos; +int mouse_x, mouse_y, old_mouse_x, old_mouse_y, mx_accum, my_accum; + +static int restore_spi; +static int originalmouseparms[3], newmouseparms[3] = {0, 0, 1}; +static int mouseactive; +int mouseinitialized; +static int mouseparmsvalid; +static int mouseshowtoggle = 1; + +// joystick defines and variables +// where should defines be moved? +#define JOY_ABSOLUTE_AXIS 0x00000000 // control like a joystick +#define JOY_RELATIVE_AXIS 0x00000010 // control like a mouse, spinner, trackball +#define JOY_MAX_AXES 6 // X, Y, Z, R, U, V +#define JOY_AXIS_X 0 +#define JOY_AXIS_Y 1 +#define JOY_AXIS_Z 2 +#define JOY_AXIS_R 3 +#define JOY_AXIS_U 4 +#define JOY_AXIS_V 5 + +enum _ControlList +{ + AxisNada = 0, + AxisForward, + AxisLook, + AxisSide, + AxisTurn +}; + +DWORD dwAxisFlags[JOY_MAX_AXES] = +{ + JOY_RETURNX, + JOY_RETURNY, + JOY_RETURNZ, + JOY_RETURNR, + JOY_RETURNU, + JOY_RETURNV +}; + +DWORD dwAxisMap[ JOY_MAX_AXES ]; +DWORD dwControlMap[ JOY_MAX_AXES ]; +PDWORD pdwRawValue[ JOY_MAX_AXES ]; + +// none of these cvars are saved over a session +// this means that advanced controller configuration needs to be executed +// each time. this avoids any problems with getting back to a default usage +// or when changing from one controller to another. this way at least something +// works. +cvar_t *in_joystick; +cvar_t *joy_name; +cvar_t *joy_advanced; +cvar_t *joy_advaxisx; +cvar_t *joy_advaxisy; +cvar_t *joy_advaxisz; +cvar_t *joy_advaxisr; +cvar_t *joy_advaxisu; +cvar_t *joy_advaxisv; +cvar_t *joy_forwardthreshold; +cvar_t *joy_sidethreshold; +cvar_t *joy_pitchthreshold; +cvar_t *joy_yawthreshold; +cvar_t *joy_forwardsensitivity; +cvar_t *joy_sidesensitivity; +cvar_t *joy_pitchsensitivity; +cvar_t *joy_yawsensitivity; +cvar_t *joy_wwhack1; +cvar_t *joy_wwhack2; + +int joy_avail, joy_advancedinit, joy_haspov; +DWORD joy_oldbuttonstate, joy_oldpovstate; + +int joy_id; +DWORD joy_flags; +DWORD joy_numbuttons; + +static JOYINFOEX ji; + +/* +=========== +Force_CenterView_f +=========== +*/ +void Force_CenterView_f (void) +{ + vec3_t viewangles; + + if (!iMouseInUse) + { + gEngfuncs.GetViewAngles( (float *)viewangles ); + viewangles[PITCH] = 0; + gEngfuncs.SetViewAngles( (float *)viewangles ); + } +} + +/* +=========== +IN_ActivateMouse +=========== +*/ +void DLLEXPORT IN_ActivateMouse (void) +{ + if (mouseinitialized) + { + if (mouseparmsvalid) + restore_spi = SystemParametersInfo (SPI_SETMOUSE, 0, newmouseparms, 0); + mouseactive = 1; + } +} + +/* +=========== +IN_DeactivateMouse +=========== +*/ +void DLLEXPORT IN_DeactivateMouse (void) +{ + if (mouseinitialized) + { + if (restore_spi) + SystemParametersInfo (SPI_SETMOUSE, 0, originalmouseparms, 0); + + mouseactive = 0; + } +} + +/* +=========== +IN_StartupMouse +=========== +*/ +void IN_StartupMouse (void) +{ + if ( gEngfuncs.CheckParm ("-nomouse", NULL ) ) + return; + + mouseinitialized = 1; + mouseparmsvalid = SystemParametersInfo (SPI_GETMOUSE, 0, originalmouseparms, 0); + + if (mouseparmsvalid) + { + if ( gEngfuncs.CheckParm ("-noforcemspd", NULL ) ) + newmouseparms[2] = originalmouseparms[2]; + + if ( gEngfuncs.CheckParm ("-noforcemaccel", NULL ) ) + { + newmouseparms[0] = originalmouseparms[0]; + newmouseparms[1] = originalmouseparms[1]; + } + + if ( gEngfuncs.CheckParm ("-noforcemparms", NULL ) ) + { + newmouseparms[0] = originalmouseparms[0]; + newmouseparms[1] = originalmouseparms[1]; + newmouseparms[2] = originalmouseparms[2]; + } + } + + mouse_buttons = MOUSE_BUTTON_COUNT; +} + +/* +=========== +IN_Shutdown +=========== +*/ +void IN_Shutdown (void) +{ + IN_DeactivateMouse (); +} + +/* +=========== +IN_GetMousePos + +Ask for mouse position from engine +=========== +*/ +void IN_GetMousePos( int *mx, int *my ) +{ + gEngfuncs.GetMousePosition( mx, my ); +} + +/* +=========== +IN_ResetMouse + +FIXME: Call through to engine? +=========== +*/ +void IN_ResetMouse( void ) +{ + SetCursorPos ( gEngfuncs.GetWindowCenterX(), gEngfuncs.GetWindowCenterY() ); +} + +/* +=========== +IN_MouseEvent +=========== +*/ +void DLLEXPORT IN_MouseEvent (int mstate) +{ + int i; + + if ( iMouseInUse || g_iVisibleMouse ) + return; + + // perform button actions + for (i=0 ; ivalue) + { + mouse_x = (mx + old_mouse_x) * 0.5; + mouse_y = (my + old_mouse_y) * 0.5; + } + else + { + mouse_x = mx; + mouse_y = my; + } + + old_mouse_x = mx; + old_mouse_y = my; + + if ( gHUD.GetSensitivity() != 0 ) + { + mouse_x *= gHUD.GetSensitivity(); + mouse_y *= gHUD.GetSensitivity(); + } + else + { + mouse_x *= sensitivity->value; + mouse_y *= sensitivity->value; + } + + // add mouse X/Y movement to cmd + if ( (in_strafe.state & 1) || (lookstrafe->value && (in_mlook.state & 1) )) + cmd->sidemove += m_side->value * mouse_x; + else + viewangles[YAW] -= m_yaw->value * mouse_x; + + if ( (in_mlook.state & 1) && !(in_strafe.state & 1)) + { + viewangles[PITCH] += m_pitch->value * mouse_y; + if (viewangles[PITCH] > cl_pitchdown->value) + viewangles[PITCH] = cl_pitchdown->value; + if (viewangles[PITCH] < -cl_pitchup->value) + viewangles[PITCH] = -cl_pitchup->value; + } + else + { + if ((in_strafe.state & 1) && gEngfuncs.IsNoClipping() ) + { + cmd->upmove -= m_forward->value * mouse_y; + } + else + { + cmd->forwardmove -= m_forward->value * mouse_y; + } + } + + // if the mouse has moved, force it to the center, so there's room to move + if ( mx || my ) + { + IN_ResetMouse(); + } + } + + gEngfuncs.SetViewAngles( (float *)viewangles ); + +/* +//#define TRACE_TEST +#if defined( TRACE_TEST ) + { + int mx, my; + void V_Move( int mx, int my ); + IN_GetMousePos( &mx, &my ); + V_Move( mx, my ); + } +#endif +*/ +} + +/* +=========== +IN_Accumulate +=========== +*/ +void DLLEXPORT IN_Accumulate (void) +{ + //only accumulate mouse if we are not moving the camera with the mouse + if ( !iMouseInUse && !g_iVisibleMouse ) + { + if (mouseactive) + { + GetCursorPos (¤t_pos); + + mx_accum += current_pos.x - gEngfuncs.GetWindowCenterX(); + my_accum += current_pos.y - gEngfuncs.GetWindowCenterY(); + + // force the mouse to the center, so there's room to move + IN_ResetMouse(); + } + } + +} + +/* +=================== +IN_ClearStates +=================== +*/ +void DLLEXPORT IN_ClearStates (void) +{ + if ( !mouseactive ) + return; + + mx_accum = 0; + my_accum = 0; + mouse_oldbuttonstate = 0; +} + +/* +=============== +IN_StartupJoystick +=============== +*/ +void IN_StartupJoystick (void) +{ + int numdevs; + JOYCAPS jc; + MMRESULT mmr; + + // assume no joystick + joy_avail = 0; + + // abort startup if user requests no joystick + if ( gEngfuncs.CheckParm ("-nojoy", NULL ) ) + return; + + // verify joystick driver is present + if ((numdevs = joyGetNumDevs ()) == 0) + { + gEngfuncs.Con_DPrintf ("joystick not found -- driver not present\n\n"); + return; + } + + // cycle through the joystick ids for the first valid one + for (joy_id=0 ; joy_idvalue == 0.0) + { + // default joystick initialization + // 2 axes only with joystick control + dwAxisMap[JOY_AXIS_X] = AxisTurn; + // dwControlMap[JOY_AXIS_X] = JOY_ABSOLUTE_AXIS; + dwAxisMap[JOY_AXIS_Y] = AxisForward; + // dwControlMap[JOY_AXIS_Y] = JOY_ABSOLUTE_AXIS; + } + else + { + if ( strcmp ( joy_name->string, "joystick") != 0 ) + { + // notify user of advanced controller + gEngfuncs.Con_Printf ("\n%s configured\n\n", joy_name->string); + } + + // advanced initialization here + // data supplied by user via joy_axisn cvars + dwTemp = (DWORD) joy_advaxisx->value; + dwAxisMap[JOY_AXIS_X] = dwTemp & 0x0000000f; + dwControlMap[JOY_AXIS_X] = dwTemp & JOY_RELATIVE_AXIS; + dwTemp = (DWORD) joy_advaxisy->value; + dwAxisMap[JOY_AXIS_Y] = dwTemp & 0x0000000f; + dwControlMap[JOY_AXIS_Y] = dwTemp & JOY_RELATIVE_AXIS; + dwTemp = (DWORD) joy_advaxisz->value; + dwAxisMap[JOY_AXIS_Z] = dwTemp & 0x0000000f; + dwControlMap[JOY_AXIS_Z] = dwTemp & JOY_RELATIVE_AXIS; + dwTemp = (DWORD) joy_advaxisr->value; + dwAxisMap[JOY_AXIS_R] = dwTemp & 0x0000000f; + dwControlMap[JOY_AXIS_R] = dwTemp & JOY_RELATIVE_AXIS; + dwTemp = (DWORD) joy_advaxisu->value; + dwAxisMap[JOY_AXIS_U] = dwTemp & 0x0000000f; + dwControlMap[JOY_AXIS_U] = dwTemp & JOY_RELATIVE_AXIS; + dwTemp = (DWORD) joy_advaxisv->value; + dwAxisMap[JOY_AXIS_V] = dwTemp & 0x0000000f; + dwControlMap[JOY_AXIS_V] = dwTemp & JOY_RELATIVE_AXIS; + } + + // compute the axes to collect from DirectInput + joy_flags = JOY_RETURNCENTERED | JOY_RETURNBUTTONS | JOY_RETURNPOV; + for (i = 0; i < JOY_MAX_AXES; i++) + { + if (dwAxisMap[i] != AxisNada) + { + joy_flags |= dwAxisFlags[i]; + } + } +} + + +/* +=========== +IN_Commands +=========== +*/ +void IN_Commands (void) +{ + int i, key_index; + DWORD buttonstate, povstate; + + if (!joy_avail) + { + return; + } + + + // loop through the joystick buttons + // key a joystick event or auxillary event for higher number buttons for each state change + buttonstate = ji.dwButtons; + for (i=0 ; i < (int)joy_numbuttons ; i++) + { + if ( (buttonstate & (1<value != 0.0) + { + ji.dwUpos += 100; + } + return 1; + } + else + { + // read error occurred + // turning off the joystick seems too harsh for 1 read error,\ + // but what should be done? + // Con_Printf ("IN_ReadJoystick: no response\n"); + // joy_avail = 0; + return 0; + } +} + + +/* +=========== +IN_JoyMove +=========== +*/ +void IN_JoyMove ( float frametime, usercmd_t *cmd ) +{ + float speed, aspeed; + float fAxisValue, fTemp; + int i; + vec3_t viewangles; + + gEngfuncs.GetViewAngles( (float *)viewangles ); + + + // complete initialization if first time in + // this is needed as cvars are not available at initialization time + if( joy_advancedinit != 1 ) + { + Joy_AdvancedUpdate_f(); + joy_advancedinit = 1; + } + + // verify joystick is available and that the user wants to use it + if (!joy_avail || !in_joystick->value) + { + return; + } + + // collect the joystick data, if possible + if (IN_ReadJoystick () != 1) + { + return; + } + + if (in_speed.state & 1) + speed = cl_movespeedkey->value; + else + speed = 1; + + aspeed = speed * frametime; + + // loop through the axes + for (i = 0; i < JOY_MAX_AXES; i++) + { + // get the floating point zero-centered, potentially-inverted data for the current axis + fAxisValue = (float) *pdwRawValue[i]; + // move centerpoint to zero + fAxisValue -= 32768.0; + + if (joy_wwhack2->value != 0.0) + { + if (dwAxisMap[i] == AxisTurn) + { + // this is a special formula for the Logitech WingMan Warrior + // y=ax^b; where a = 300 and b = 1.3 + // also x values are in increments of 800 (so this is factored out) + // then bounds check result to level out excessively high spin rates + fTemp = 300.0 * pow(abs(fAxisValue) / 800.0, 1.3); + if (fTemp > 14000.0) + fTemp = 14000.0; + // restore direction information + fAxisValue = (fAxisValue > 0.0) ? fTemp : -fTemp; + } + } + + // convert range from -32768..32767 to -1..1 + fAxisValue /= 32768.0; + + switch (dwAxisMap[i]) + { + case AxisForward: + if ((joy_advanced->value == 0.0) && (in_jlook.state & 1)) + { + // user wants forward control to become look control + if (fabs(fAxisValue) > joy_pitchthreshold->value) + { + // if mouse invert is on, invert the joystick pitch value + // only absolute control support here (joy_advanced is 0) + if (m_pitch->value < 0.0) + { + viewangles[PITCH] -= (fAxisValue * joy_pitchsensitivity->value) * aspeed * cl_pitchspeed->value; + } + else + { + viewangles[PITCH] += (fAxisValue * joy_pitchsensitivity->value) * aspeed * cl_pitchspeed->value; + } + V_StopPitchDrift(); + } + else + { + // no pitch movement + // disable pitch return-to-center unless requested by user + // *** this code can be removed when the lookspring bug is fixed + // *** the bug always has the lookspring feature on + if(lookspring->value == 0.0) + { + V_StopPitchDrift(); + } + } + } + else + { + // user wants forward control to be forward control + if (fabs(fAxisValue) > joy_forwardthreshold->value) + { + cmd->forwardmove += (fAxisValue * joy_forwardsensitivity->value) * speed * cl_forwardspeed->value; + } + } + break; + + case AxisSide: + if (fabs(fAxisValue) > joy_sidethreshold->value) + { + cmd->sidemove += (fAxisValue * joy_sidesensitivity->value) * speed * cl_sidespeed->value; + } + break; + + case AxisTurn: + if ((in_strafe.state & 1) || (lookstrafe->value && (in_jlook.state & 1))) + { + // user wants turn control to become side control + if (fabs(fAxisValue) > joy_sidethreshold->value) + { + cmd->sidemove -= (fAxisValue * joy_sidesensitivity->value) * speed * cl_sidespeed->value; + } + } + else + { + // user wants turn control to be turn control + if (fabs(fAxisValue) > joy_yawthreshold->value) + { + if(dwControlMap[i] == JOY_ABSOLUTE_AXIS) + { + viewangles[YAW] += (fAxisValue * joy_yawsensitivity->value) * aspeed * cl_yawspeed->value; + } + else + { + viewangles[YAW] += (fAxisValue * joy_yawsensitivity->value) * speed * 180.0; + } + + } + } + break; + + case AxisLook: + if (in_jlook.state & 1) + { + if (fabs(fAxisValue) > joy_pitchthreshold->value) + { + // pitch movement detected and pitch movement desired by user + if(dwControlMap[i] == JOY_ABSOLUTE_AXIS) + { + viewangles[PITCH] += (fAxisValue * joy_pitchsensitivity->value) * aspeed * cl_pitchspeed->value; + } + else + { + viewangles[PITCH] += (fAxisValue * joy_pitchsensitivity->value) * speed * 180.0; + } + V_StopPitchDrift(); + } + else + { + // no pitch movement + // disable pitch return-to-center unless requested by user + // *** this code can be removed when the lookspring bug is fixed + // *** the bug always has the lookspring feature on + if( lookspring->value == 0.0 ) + { + V_StopPitchDrift(); + } + } + } + break; + + default: + break; + } + } + + // bounds check pitch + if (viewangles[PITCH] > cl_pitchdown->value) + viewangles[PITCH] = cl_pitchdown->value; + if (viewangles[PITCH] < -cl_pitchup->value) + viewangles[PITCH] = -cl_pitchup->value; + + gEngfuncs.SetViewAngles( (float *)viewangles ); + +} + +/* +=========== +IN_Move +=========== +*/ +void IN_Move ( float frametime, usercmd_t *cmd) +{ + if ( !iMouseInUse && mouseactive ) + { + IN_MouseMove ( frametime, cmd); + } + + IN_JoyMove ( frametime, cmd); +} + +/* +=========== +IN_Init +=========== +*/ +void IN_Init (void) +{ + m_filter = gEngfuncs.pfnRegisterVariable ( "m_filter","0", FCVAR_ARCHIVE ); + sensitivity = gEngfuncs.pfnRegisterVariable ( "sensitivity","3", FCVAR_ARCHIVE ); // user mouse sensitivity setting. + + in_joystick = gEngfuncs.pfnRegisterVariable ( "joystick","0", FCVAR_ARCHIVE ); + joy_name = gEngfuncs.pfnRegisterVariable ( "joyname", "joystick", 0 ); + joy_advanced = gEngfuncs.pfnRegisterVariable ( "joyadvanced", "0", 0 ); + joy_advaxisx = gEngfuncs.pfnRegisterVariable ( "joyadvaxisx", "0", 0 ); + joy_advaxisy = gEngfuncs.pfnRegisterVariable ( "joyadvaxisy", "0", 0 ); + joy_advaxisz = gEngfuncs.pfnRegisterVariable ( "joyadvaxisz", "0", 0 ); + joy_advaxisr = gEngfuncs.pfnRegisterVariable ( "joyadvaxisr", "0", 0 ); + joy_advaxisu = gEngfuncs.pfnRegisterVariable ( "joyadvaxisu", "0", 0 ); + joy_advaxisv = gEngfuncs.pfnRegisterVariable ( "joyadvaxisv", "0", 0 ); + joy_forwardthreshold = gEngfuncs.pfnRegisterVariable ( "joyforwardthreshold", "0.15", 0 ); + joy_sidethreshold = gEngfuncs.pfnRegisterVariable ( "joysidethreshold", "0.15", 0 ); + joy_pitchthreshold = gEngfuncs.pfnRegisterVariable ( "joypitchthreshold", "0.15", 0 ); + joy_yawthreshold = gEngfuncs.pfnRegisterVariable ( "joyyawthreshold", "0.15", 0 ); + joy_forwardsensitivity = gEngfuncs.pfnRegisterVariable ( "joyforwardsensitivity", "-1.0", 0 ); + joy_sidesensitivity = gEngfuncs.pfnRegisterVariable ( "joysidesensitivity", "-1.0", 0 ); + joy_pitchsensitivity = gEngfuncs.pfnRegisterVariable ( "joypitchsensitivity", "1.0", 0 ); + joy_yawsensitivity = gEngfuncs.pfnRegisterVariable ( "joyyawsensitivity", "-1.0", 0 ); + joy_wwhack1 = gEngfuncs.pfnRegisterVariable ( "joywwhack1", "0.0", 0 ); + joy_wwhack2 = gEngfuncs.pfnRegisterVariable ( "joywwhack2", "0.0", 0 ); + + gEngfuncs.pfnAddCommand ("force_centerview", Force_CenterView_f); + gEngfuncs.pfnAddCommand ("joyadvancedupdate", Joy_AdvancedUpdate_f); + + IN_StartupMouse (); + IN_StartupJoystick (); +} \ No newline at end of file diff --git a/cl_dll/kbutton.h b/cl_dll/kbutton.h new file mode 100644 index 0000000..c3a7c13 --- /dev/null +++ b/cl_dll/kbutton.h @@ -0,0 +1,11 @@ +#if !defined( KBUTTONH ) +#define KBUTTONH +#pragma once + +typedef struct kbutton_s +{ + int down[2]; // key nums holding it down + int state; // low bit is down state +} kbutton_t; + +#endif // !KBUTTONH \ No newline at end of file diff --git a/cl_dll/menu.cpp b/cl_dll/menu.cpp index 5e78dfb..9748449 100644 --- a/cl_dll/menu.cpp +++ b/cl_dll/menu.cpp @@ -18,16 +18,20 @@ // generic menu handler // #include "hud.h" -#include "util.h" +#include "cl_util.h" #include "parsemsg.h" #include #include +#include "vgui_TeamFortressViewport.h" + #define MAX_MENU_STRING 512 char g_szMenuString[MAX_MENU_STRING]; char g_szPrelocalisedMenuString[MAX_MENU_STRING]; +int KB_ConvertString( char *in, char **ppout ); + DECLARE_MESSAGE( m_Menu, ShowMenu ); int CHudMenu :: Init( void ) @@ -73,7 +77,7 @@ int CHudMenu :: Draw( float flTime ) } // don't draw the menu if the scoreboard is being shown - if ( gHUD.m_Scoreboard.m_iShowscoresHeld ) + if ( gViewPort && gViewPort->IsScoreBoardVisible() ) return 1; // draw the menu, along the left-hand side of the screen @@ -131,6 +135,8 @@ void CHudMenu :: SelectMenuItem( int menu_item ) // if this message is never received, then scores will simply be the combined totals of the players. int CHudMenu :: MsgFunc_ShowMenu( const char *pszName, int iSize, void *pbuf ) { + char *temp = NULL; + BEGIN_READ( pbuf, iSize ); m_bitsValidSlots = READ_SHORT(); @@ -157,6 +163,13 @@ int CHudMenu :: MsgFunc_ShowMenu( const char *pszName, int iSize, void *pbuf ) if ( !NeedMore ) { // we have the whole string, so we can localise it now strcpy( g_szMenuString, gHUD.m_TextMessage.BufferedLocaliseTextString( g_szPrelocalisedMenuString ) ); + + // Swap in characters + if ( KB_ConvertString( g_szMenuString, &temp ) ) + { + strcpy( g_szMenuString, temp ); + free( temp ); + } } m_fMenuDisplayed = 1; diff --git a/cl_dll/message.cpp b/cl_dll/message.cpp index 80c8dd6..b0a6754 100644 --- a/cl_dll/message.cpp +++ b/cl_dll/message.cpp @@ -19,7 +19,7 @@ // #include "hud.h" -#include "util.h" +#include "cl_util.h" #include #include #include "parsemsg.h" diff --git a/cl_dll/mssccprj.scc b/cl_dll/mssccprj.scc index f943c7b..bad9ab2 100644 --- a/cl_dll/mssccprj.scc +++ b/cl_dll/mssccprj.scc @@ -1,4 +1,5 @@ SCC = This is a Source Code Control file [cl_dll.mak] -SCC_Project_Name = "$/HLStandardSDK/SourceCode/cl_dll", NUWHAAAA +SCC_Aux_Path = "\\Jeeves\VSSCODE\" +SCC_Project_Name = "$/Sdk/Standard/cl_dll", UBZBAAAA diff --git a/cl_dll/saytext.cpp b/cl_dll/saytext.cpp index 34a66c8..f7cb992 100644 --- a/cl_dll/saytext.cpp +++ b/cl_dll/saytext.cpp @@ -19,14 +19,18 @@ // #include "hud.h" -#include "util.h" +#include "cl_util.h" #include "parsemsg.h" #include #include +#include "vgui_TeamFortressViewport.h" + +extern float *GetClientColor( int clientIndex ); + #define MAX_LINES 5 -#define MAX_CHARS_PER_LINE 128 /* it can be less than this, depending on char size */ +#define MAX_CHARS_PER_LINE 256 /* it can be less than this, depending on char size */ // allow 20 pixels on either side of the text #define MAX_LINE_WIDTH ( ScreenWidth - 40 ) @@ -34,6 +38,8 @@ static float SCROLL_SPEED = 5; static char g_szLineBuffer[ MAX_LINES + 1 ][ MAX_CHARS_PER_LINE ]; +static float *g_pflNameColors[ MAX_LINES + 1 ]; +static int g_iNameLengths[ MAX_LINES + 1 ]; static float flScrollTime = 0; // the time at which the lines next scroll up static int Y_START = 0; @@ -58,6 +64,8 @@ int CHudSayText :: Init( void ) void CHudSayText :: InitHUDData( void ) { memset( g_szLineBuffer, 0, sizeof g_szLineBuffer ); + memset( g_pflNameColors, 0, sizeof g_pflNameColors ); + memset( g_iNameLengths, 0, sizeof g_iNameLengths ); } int CHudSayText :: VidInit( void ) @@ -66,22 +74,31 @@ int CHudSayText :: VidInit( void ) } -void ScrollTextUp( void ) +int ScrollTextUp( void ) { ConsolePrint( g_szLineBuffer[0] ); // move the first line into the console buffer + g_szLineBuffer[MAX_LINES][0] = 0; memmove( g_szLineBuffer[0], g_szLineBuffer[1], sizeof(g_szLineBuffer) - sizeof(g_szLineBuffer[0]) ); // overwrite the first line + memmove( &g_pflNameColors[0], &g_pflNameColors[1], sizeof(g_pflNameColors) - sizeof(g_pflNameColors[0]) ); + memmove( &g_iNameLengths[0], &g_iNameLengths[1], sizeof(g_iNameLengths) - sizeof(g_iNameLengths[0]) ); + g_szLineBuffer[MAX_LINES-1][0] = 0; if ( g_szLineBuffer[0][0] == ' ' ) // also scroll up following lines { g_szLineBuffer[0][0] = 2; - ScrollTextUp(); + return 1 + ScrollTextUp(); } + + return 1; } int CHudSayText :: Draw( float flTime ) { int y = Y_START; + if ( gViewPort && gViewPort->AllowedToPrintText() == FALSE ) + return 1; + // make sure the scrolltime is within reasonable bounds, to guard against the clock being reset flScrollTime = min( flScrollTime, flTime + SCROLL_SPEED ); @@ -105,7 +122,27 @@ int CHudSayText :: Draw( float flTime ) for ( int i = 0; i < MAX_LINES; i++ ) { if ( *g_szLineBuffer[i] ) - DrawConsoleString( LINE_START, y, g_szLineBuffer[i] ); + { + if ( *g_szLineBuffer[i] == 2 && g_pflNameColors[i] ) + { + // it's a saytext string + static char buf[MAX_PLAYER_NAME_LENGTH+32]; + + // draw the first x characters in the player color + strncpy( buf, g_szLineBuffer[i], min(g_iNameLengths[i], MAX_PLAYER_NAME_LENGTH+32) ); + buf[ min(g_iNameLengths[i], MAX_PLAYER_NAME_LENGTH+31) ] = 0; + gEngfuncs.pfnDrawSetTextColor( g_pflNameColors[i][0], g_pflNameColors[i][1], g_pflNameColors[i][2] ); + int x = DrawConsoleString( LINE_START, y, buf ); + + // color is reset after each string draw + DrawConsoleString( x, y, g_szLineBuffer[i] + g_iNameLengths[i] ); + } + else + { + // normal draw + DrawConsoleString( LINE_START, y, g_szLineBuffer[i] ); + } + } y += line_height; } @@ -119,13 +156,16 @@ int CHudSayText :: MsgFunc_SayText( const char *pszName, int iSize, void *pbuf ) BEGIN_READ( pbuf, iSize ); int client_index = READ_BYTE(); // the client who spoke the message - SayTextPrint( READ_STRING(), iSize - 1 ); + SayTextPrint( READ_STRING(), iSize - 1, client_index ); return 1; } -void CHudSayText :: SayTextPrint( const char *pszBuf, int iBufSize ) +void CHudSayText :: SayTextPrint( const char *pszBuf, int iBufSize, int clientIndex ) { + if ( gViewPort && gViewPort->AllowedToPrintText() == FALSE ) + return; + // find an empty string slot for ( int i = 0; i < MAX_LINES; i++ ) { @@ -139,6 +179,27 @@ void CHudSayText :: SayTextPrint( const char *pszBuf, int iBufSize ) i = MAX_LINES - 1; } + g_iNameLengths[i] = 0; + g_pflNameColors[i] = NULL; + + // if it's a say message, search for the players name in the string + if ( *pszBuf == 2 && clientIndex > 0 ) + { + GetPlayerInfo( clientIndex, &g_PlayerInfoList[clientIndex] ); + const char *pName = g_PlayerInfoList[clientIndex].name; + + if ( pName ) + { + const char *nameInString = strstr( pszBuf, pName ); + + if ( nameInString ) + { + g_iNameLengths[i] = strlen( pName ) + (nameInString - pszBuf); + g_pflNameColors[i] = GetClientColor( clientIndex ); + } + } + } + strncpy( g_szLineBuffer[i], pszBuf, max(iBufSize -1, MAX_CHARS_PER_LINE-1) ); // make sure the text fits in one line @@ -155,9 +216,9 @@ void CHudSayText :: SayTextPrint( const char *pszBuf, int iBufSize ) PlaySound( "misc/talk.wav", 1 ); if ( ScreenHeight >= 480 ) - Y_START = ScreenHeight - 45; + Y_START = ScreenHeight - 60; else - Y_START = ScreenHeight - 35; + Y_START = ScreenHeight - 45; Y_START -= (line_height * (MAX_LINES+1)); } @@ -175,6 +236,21 @@ void CHudSayText :: EnsureTextFitsInOneLineAndWrapIfHaveTo( int line ) char *last_break = NULL; for ( char *x = g_szLineBuffer[line]; *x != 0; x++ ) { + // check for a color change, if so skip past it + if ( x[0] == '/' && x[1] == '(' ) + { + x += 2; + // skip forward until past mode specifier + while ( *x != 0 && *x != ')' ) + x++; + + if ( *x != 0 ) + x++; + + if ( *x == 0 ) + break; + } + char buf[2]; buf[1] = 0; @@ -193,15 +269,23 @@ void CHudSayText :: EnsureTextFitsInOneLineAndWrapIfHaveTo( int line ) x = last_break; // find an empty string slot - for ( int j = 0; j < MAX_LINES; j++ ) + int j; + do { - if ( ! *g_szLineBuffer[j] ) - break; - } - if ( j == MAX_LINES ) - { - j = MAX_LINES - 1; + for ( j = 0; j < MAX_LINES; j++ ) + { + if ( ! *g_szLineBuffer[j] ) + break; + } + if ( j == MAX_LINES ) + { + // need to make more room to display text, scroll stuff up then fix the pointers + int linesmoved = ScrollTextUp(); + line -= linesmoved; + last_break = last_break - (sizeof(g_szLineBuffer[0]) * linesmoved); + } } + while ( j == MAX_LINES ); // copy remaining string into next buffer, making sure it starts with a space character if ( (char)*last_break == (char)' ' ) diff --git a/cl_dll/scoreboard.cpp b/cl_dll/scoreboard.cpp deleted file mode 100644 index 79ddafc..0000000 --- a/cl_dll/scoreboard.cpp +++ /dev/null @@ -1,528 +0,0 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -// -// Scoreboard.cpp -// -// implementation of CHudScoreboard class -// - -#include "hud.h" -#include "util.h" -#include "parsemsg.h" - -#include -#include - -DECLARE_COMMAND( m_Scoreboard, ShowScores ); -DECLARE_COMMAND( m_Scoreboard, HideScores ); - -DECLARE_MESSAGE( m_Scoreboard, ScoreInfo ); -DECLARE_MESSAGE( m_Scoreboard, TeamInfo ); -DECLARE_MESSAGE( m_Scoreboard, TeamScore ); - -int CHudScoreboard :: Init( void ) -{ - gHUD.AddHudElem( this ); - - // Hook messages & commands here - HOOK_COMMAND( "+showscores", ShowScores ); - HOOK_COMMAND( "-showscores", HideScores ); - - HOOK_MESSAGE( ScoreInfo ); - HOOK_MESSAGE( TeamScore ); - HOOK_MESSAGE( TeamInfo ); - - InitHUDData(); - - return 1; -} - - -int CHudScoreboard :: VidInit( void ) -{ - // Load sprites here - - return 1; -} - -void CHudScoreboard :: InitHUDData( void ) -{ - memset( m_PlayerExtraInfo, 0, sizeof m_PlayerExtraInfo ); - m_iLastKilledBy = 0; - m_fLastKillTime = 0; - m_iPlayerNum = 0; - m_iNumTeams = 0; - memset( m_TeamInfo, 0, sizeof m_TeamInfo ); - - m_iFlags &= ~HUD_ACTIVE; // starts out inactive - - m_iFlags |= HUD_INTERMISSION; // is always drawn during an intermission -} - -/* The scoreboard -We have a minimum width of 1-320 - we could have the field widths scale with it? -*/ - -// X positions -// relative to the side of the scoreboard -#define NAME_RANGE_MIN 20 -#define NAME_RANGE_MAX 145 -#define KILLS_RANGE_MIN 130 -#define KILLS_RANGE_MAX 170 -#define DIVIDER_POS 180 -#define DEATHS_RANGE_MIN 185 -#define DEATHS_RANGE_MAX 210 -#define PING_RANGE_MIN 245 -#define PING_RANGE_MAX 295 - -#define SCOREBOARD_WIDTH 320 - - -// Y positions -#define ROW_GAP 13 -#define ROW_RANGE_MIN 15 -#define ROW_RANGE_MAX ( ScreenHeight - 50 ) - -int CHudScoreboard :: Draw( float fTime ) -{ - if ( !m_iShowscoresHeld && gHUD.m_Health.m_iHealth > 0 && !gHUD.m_iIntermission ) - return 1; - - GetAllPlayersInfo(); - - // just sort the list on the fly - // list is sorted first by frags, then by deaths - float list_slot = 0; - int xpos_rel = (ScreenWidth - SCOREBOARD_WIDTH) / 2; - - // print the heading line - int ypos = ROW_RANGE_MIN + (list_slot * ROW_GAP); - int xpos = NAME_RANGE_MIN + xpos_rel; - - if ( !gHUD.m_Teamplay ) - gHUD.DrawHudString( xpos, ypos, NAME_RANGE_MAX + xpos_rel, "Player", 255, 140, 0 ); - else - gHUD.DrawHudString( xpos, ypos, NAME_RANGE_MAX + xpos_rel, "Teams", 255, 140, 0 ); - - gHUD.DrawHudStringReverse( KILLS_RANGE_MAX + xpos_rel, ypos, 0, "kills", 255, 140, 0 ); - gHUD.DrawHudString( DIVIDER_POS + xpos_rel, ypos, ScreenWidth, "/", 255, 140, 0 ); - gHUD.DrawHudString( DEATHS_RANGE_MIN + xpos_rel + 5, ypos, ScreenWidth, "deaths", 255, 140, 0 ); - gHUD.DrawHudString( PING_RANGE_MAX + xpos_rel - 35, ypos, ScreenWidth, "latency", 255, 140, 0 ); - - list_slot += 1.2; - ypos = ROW_RANGE_MIN + (list_slot * ROW_GAP); - xpos = NAME_RANGE_MIN + xpos_rel; - FillRGBA( xpos - 5, ypos, PING_RANGE_MAX - 5, 1, 255, 140, 0, 255); // draw the seperator line - - list_slot += 0.8; - - if ( !gHUD.m_Teamplay ) - { - // it's not teamplay, so just draw a simple player list - DrawPlayers( xpos_rel, list_slot ); - return 1; - } - - // clear out team scores - for ( int i = 1; i <= m_iNumTeams; i++ ) - { - if ( !m_TeamInfo[i].scores_overriden ) - m_TeamInfo[i].frags = m_TeamInfo[i].deaths = 0; - m_TeamInfo[i].ping = m_TeamInfo[i].packetloss = 0; - } - - // recalc the team scores, then draw them - for ( i = 1; i < MAX_PLAYERS; i++ ) - { - if ( m_PlayerInfoList[i].name == NULL ) - continue; // empty player slot, skip - - if ( m_PlayerExtraInfo[i].teamname[0] == 0 ) - continue; // skip over players who are not in a team - - // find what team this player is in - for ( int j = 1; j <= m_iNumTeams; j++ ) - { - if ( !stricmp( m_PlayerExtraInfo[i].teamname, m_TeamInfo[j].name ) ) - break; - } - if ( j > m_iNumTeams ) // player is not in a team, skip to the next guy - continue; - - if ( !m_TeamInfo[j].scores_overriden ) - { - m_TeamInfo[j].frags += m_PlayerExtraInfo[i].frags; - m_TeamInfo[j].deaths += m_PlayerExtraInfo[i].deaths; - } - - m_TeamInfo[j].ping += m_PlayerInfoList[i].ping; - m_TeamInfo[j].packetloss += m_PlayerInfoList[i].packetloss; - - if ( m_PlayerInfoList[i].thisplayer ) - m_TeamInfo[j].ownteam = TRUE; - else - m_TeamInfo[j].ownteam = FALSE; - } - - // find team ping/packetloss averages - for ( i = 1; i <= m_iNumTeams; i++ ) - { - m_TeamInfo[i].already_drawn = FALSE; - - if ( m_TeamInfo[i].players > 0 ) - { - m_TeamInfo[i].ping /= m_TeamInfo[i].players; // use the average ping of all the players in the team as the teams ping - m_TeamInfo[i].packetloss /= m_TeamInfo[i].players; // use the average ping of all the players in the team as the teams ping - } - } - - // Draw the teams - while ( 1 ) - { - int highest_frags = -99999; int lowest_deaths = 99999; - int best_team = 0; - - for ( i = 1; i <= m_iNumTeams; i++ ) - { - if ( m_TeamInfo[i].players < 0 ) - continue; - - if ( !m_TeamInfo[i].already_drawn && m_TeamInfo[i].frags >= highest_frags ) - { - if ( m_TeamInfo[i].frags > highest_frags || m_TeamInfo[i].deaths < lowest_deaths ) - { - best_team = i; - lowest_deaths = m_TeamInfo[i].deaths; - highest_frags = m_TeamInfo[i].frags; - } - } - } - - // draw the best team on the scoreboard - if ( !best_team ) - break; - - // draw out the best team - team_info_t *team_info = &m_TeamInfo[best_team]; - - ypos = ROW_RANGE_MIN + (list_slot * ROW_GAP); - - // check we haven't drawn too far down - if ( ypos > ROW_RANGE_MAX ) // don't draw to close to the lower border - break; - - xpos = NAME_RANGE_MIN + xpos_rel; - int r = 255, g = 225, b = 55; // draw the stuff kinda yellowish - - if ( team_info->ownteam ) // if it is their team, draw the background different color - { - // overlay the background in blue, then draw the score text over it - FillRGBA( NAME_RANGE_MIN + xpos_rel - 5, ypos, PING_RANGE_MAX - 5, ROW_GAP, 0, 0, 255, 70 ); - } - - // draw their name (left to right) - gHUD.DrawHudString( xpos, ypos, NAME_RANGE_MAX + xpos_rel, team_info->name, r, g, b ); - - // draw kills (right to left) - xpos = KILLS_RANGE_MAX + xpos_rel; - gHUD.DrawHudNumberString( xpos, ypos, KILLS_RANGE_MIN + xpos_rel, team_info->frags, r, g, b ); - - // draw divider - xpos = DIVIDER_POS + xpos_rel; - gHUD.DrawHudString( xpos, ypos, xpos + 20, "/", r, g, b ); - - // draw deaths - xpos = DEATHS_RANGE_MAX + xpos_rel; - gHUD.DrawHudNumberString( xpos, ypos, DEATHS_RANGE_MIN + xpos_rel, team_info->deaths, r, g, b ); - - // draw ping - // draw ping & packetloss - static char buf[64]; - sprintf( buf, "%d", team_info->ping ); - xpos = ((PING_RANGE_MAX - PING_RANGE_MIN) / 2) + PING_RANGE_MIN + xpos_rel + 25; - UnpackRGB( r, g, b, RGB_YELLOWISH ); - gHUD.DrawHudStringReverse( xpos, ypos, xpos - 50, buf, r, g, b ); - - /* Packetloss removed on Kelly 'shipping nazi' Bailey's orders - sprintf( buf, " %d", team_info->packetloss ); - gHUD.DrawHudString( xpos, ypos, xpos+50, buf, r, g, b ); - */ - - team_info->already_drawn = TRUE; // set the already_drawn to be TRUE, so this team won't get drawn again - list_slot++; - - // draw all the players that belong to this team, indented slightly - list_slot = DrawPlayers( xpos_rel, list_slot, 10, team_info->name ); - } - - // draw all the players who are not in a team - list_slot += 0.5; - DrawPlayers( xpos_rel, list_slot, 0, "" ); - - return 1; -} - -// returns the ypos where it finishes drawing -int CHudScoreboard :: DrawPlayers( int xpos_rel, float list_slot, int nameoffset, char *team ) -{ - // draw the players, in order, and restricted to team if set - while ( 1 ) - { - // Find the top ranking player - int highest_frags = -99999; int lowest_deaths = 99999; - int best_player = 0; - - for ( int i = 1; i < MAX_PLAYERS; i++ ) - { - if ( m_PlayerInfoList[i].name && m_PlayerExtraInfo[i].frags >= highest_frags ) - { - if ( !(team && stricmp(m_PlayerExtraInfo[i].teamname, team)) ) // make sure it is the specified team - { - extra_player_info_t *pl_info = &m_PlayerExtraInfo[i]; - if ( pl_info->frags > highest_frags || pl_info->deaths < lowest_deaths ) - { - best_player = i; - lowest_deaths = pl_info->deaths; - highest_frags = pl_info->frags; - } - } - } - } - - if ( !best_player ) - break; - - // draw out the best player - hud_player_info_t *pl_info = &m_PlayerInfoList[best_player]; - - int ypos = ROW_RANGE_MIN + (list_slot * ROW_GAP); - - // check we haven't drawn too far down - if ( ypos > ROW_RANGE_MAX ) // don't draw to close to the lower border - break; - - int xpos = NAME_RANGE_MIN + xpos_rel; - int r = 255, g = 255, b = 255; - if ( best_player == m_iLastKilledBy && m_fLastKillTime && m_fLastKillTime > gHUD.m_flTime ) - { - if ( pl_info->thisplayer ) - { // green is the suicide color? i wish this could do grey... - FillRGBA( NAME_RANGE_MIN + xpos_rel - 5, ypos, PING_RANGE_MAX - 5, ROW_GAP, 80, 155, 0, 70 ); - } - else - { // Highlight the killers name - overlay the background in red, then draw the score text over it - FillRGBA( NAME_RANGE_MIN + xpos_rel - 5, ypos, PING_RANGE_MAX - 5, ROW_GAP, 255, 0, 0, ((float)15 * (float)(m_fLastKillTime - gHUD.m_flTime)) ); - } - } - else if ( pl_info->thisplayer ) // if it is their name, draw it a different color - { - // overlay the background in blue, then draw the score text over it - FillRGBA( NAME_RANGE_MIN + xpos_rel - 5, ypos, PING_RANGE_MAX - 5, ROW_GAP, 0, 0, 255, 70 ); - } - - // draw their name (left to right) - gHUD.DrawHudString( xpos + nameoffset, ypos, NAME_RANGE_MAX + xpos_rel, pl_info->name, r, g, b ); - - // draw kills (right to left) - xpos = KILLS_RANGE_MAX + xpos_rel; - gHUD.DrawHudNumberString( xpos, ypos, KILLS_RANGE_MIN + xpos_rel, m_PlayerExtraInfo[best_player].frags, r, g, b ); - - // draw divider - xpos = DIVIDER_POS + xpos_rel; - gHUD.DrawHudString( xpos, ypos, xpos + 20, "/", r, g, b ); - - // draw deaths - xpos = DEATHS_RANGE_MAX + xpos_rel; - gHUD.DrawHudNumberString( xpos, ypos, DEATHS_RANGE_MIN + xpos_rel, m_PlayerExtraInfo[best_player].deaths, r, g, b ); - - // draw ping & packetloss - static char buf[64]; - sprintf( buf, "%d", m_PlayerInfoList[best_player].ping ); - xpos = ((PING_RANGE_MAX - PING_RANGE_MIN) / 2) + PING_RANGE_MIN + xpos_rel + 25; - gHUD.DrawHudStringReverse( xpos, ypos, xpos - 50, buf, r, g, b ); - - /* Packetloss removed on Kelly 'shipping nazi' Bailey's orders - if ( m_PlayerInfoList[best_player].packetloss >= 63 ) - { - UnpackRGB( r, g, b, RGB_REDISH ); - sprintf( buf, " !!!!" ); - } - else - { - sprintf( buf, " %d", m_PlayerInfoList[best_player].packetloss ); - } - - gHUD.DrawHudString( xpos, ypos, xpos+50, buf, r, g, b ); - */ - - pl_info->name = NULL; // set the name to be NULL, so this client won't get drawn again - list_slot++; - } - - return list_slot; -} - - -void CHudScoreboard :: GetAllPlayersInfo( void ) -{ - for ( int i = 1; i < MAX_PLAYERS; i++ ) - { - GetPlayerInfo( i, &m_PlayerInfoList[i] ); - - if ( m_PlayerInfoList[i].thisplayer ) - m_iPlayerNum = i; // !!!HACK: this should be initialized elsewhere... maybe gotten from the engine - } -} - -int CHudScoreboard :: MsgFunc_ScoreInfo( const char *pszName, int iSize, void *pbuf ) -{ - m_iFlags |= HUD_ACTIVE; - - BEGIN_READ( pbuf, iSize ); - short cl = READ_BYTE(); - short frags = READ_SHORT(); - short deaths = READ_SHORT(); - - if ( cl > 0 && cl <= MAX_PLAYERS ) - { - m_PlayerExtraInfo[cl].frags = frags; - m_PlayerExtraInfo[cl].deaths = deaths; - } - - return 1; -} - -// Message handler for TeamInfo message -// accepts two values: -// byte: client number -// string: client team name -int CHudScoreboard :: MsgFunc_TeamInfo( const char *pszName, int iSize, void *pbuf ) -{ - BEGIN_READ( pbuf, iSize ); - short cl = READ_BYTE(); - - if ( cl > 0 && cl <= MAX_PLAYERS ) - { // set the players team - strncpy( m_PlayerExtraInfo[cl].teamname, READ_STRING(), MAX_TEAM_NAME ); - } - - // rebuild the list of teams - - // clear out player counts from teams - for ( int i = 1; i <= m_iNumTeams; i++ ) - { - m_TeamInfo[i].players = 0; - } - - // rebuild the team list - GetAllPlayersInfo(); - m_iNumTeams = 0; - for ( i = 1; i < MAX_PLAYERS; i++ ) - { - if ( m_PlayerInfoList[i].name == NULL ) - continue; - - if ( m_PlayerExtraInfo[i].teamname[0] == 0 ) - continue; // skip over players who are not in a team - - // is this player in an existing team? - for ( int j = 1; j <= m_iNumTeams; j++ ) - { - if ( m_TeamInfo[j].name[0] == '\0' ) - break; - - if ( !stricmp( m_PlayerExtraInfo[i].teamname, m_TeamInfo[j].name ) ) - break; - } - - if ( j > m_iNumTeams ) - { // they aren't in a listed team, so make a new one - // search through for an empty team slot - for ( int j = 1; j <= m_iNumTeams; j++ ) - { - if ( m_TeamInfo[j].name[0] == '\0' ) - break; - } - m_iNumTeams = max( j, m_iNumTeams ); - - strncpy( m_TeamInfo[j].name, m_PlayerExtraInfo[i].teamname, MAX_TEAM_NAME ); - m_TeamInfo[j].players = 0; - } - - m_TeamInfo[j].players++; - } - - // clear out any empty teams - for ( i = 1; i <= m_iNumTeams; i++ ) - { - if ( m_TeamInfo[i].players < 1 ) - memset( &m_TeamInfo[i], 0, sizeof(team_info_t) ); - } - - return 1; -} - -// Message handler for TeamScore message -// accepts three values: -// string: team name -// short: teams kills -// short: teams deaths -// if this message is never received, then scores will simply be the combined totals of the players. -int CHudScoreboard :: MsgFunc_TeamScore( const char *pszName, int iSize, void *pbuf ) -{ - BEGIN_READ( pbuf, iSize ); - char *TeamName = READ_STRING(); - - // find the team matching the name - for ( int i = 1; i <= m_iNumTeams; i++ ) - { - if ( !stricmp( TeamName, m_TeamInfo[i].name ) ) - break; - } - if ( i > m_iNumTeams ) - return 1; - - // use this new score data instead of combined player scores - m_TeamInfo[i].scores_overriden = TRUE; - m_TeamInfo[i].frags = READ_SHORT(); - m_TeamInfo[i].deaths = READ_SHORT(); - - return 1; -} - -void CHudScoreboard :: DeathMsg( int killer, int victim ) -{ - // if we were the one killed, or the world killed us, set the scoreboard to indicate suicide - if ( victim == m_iPlayerNum || killer == 0 ) - { - m_iLastKilledBy = killer ? killer : m_iPlayerNum; - m_fLastKillTime = gHUD.m_flTime + 10; // display who we were killed by for 10 seconds - - if ( killer == m_iPlayerNum ) - m_iLastKilledBy = m_iPlayerNum; - } -} - - - -void CHudScoreboard :: UserCmd_ShowScores( void ) -{ - m_iShowscoresHeld = TRUE; -} - -void CHudScoreboard :: UserCmd_HideScores( void ) -{ - m_iShowscoresHeld = FALSE; -} diff --git a/cl_dll/status_icons.cpp b/cl_dll/status_icons.cpp index 371594e..3cb5da7 100644 --- a/cl_dll/status_icons.cpp +++ b/cl_dll/status_icons.cpp @@ -16,10 +16,14 @@ // status_icons.cpp // #include "hud.h" -#include "util.h" +#include "cl_util.h" +#include "const.h" +#include "entity_state.h" +#include "cl_entity.h" #include #include #include "parsemsg.h" +#include "event_api.h" DECLARE_MESSAGE( m_StatusIcons, StatusIcon ); @@ -132,6 +136,13 @@ void CHudStatusIcons::EnableIcon( char *pszIconName, unsigned char red, unsigned m_IconList[i].g = green; m_IconList[i].b = blue; strcpy( m_IconList[i].szSpriteName, pszIconName ); + + // Hack: Play Timer sound when a grenade icon is played (in 0.8 seconds) + if ( strstr(m_IconList[i].szSpriteName, "grenade") ) + { + cl_entity_t *pthisplayer = gEngfuncs.GetLocalPlayer(); + gEngfuncs.pEventAPI->EV_PlaySound( pthisplayer->index, pthisplayer->origin, CHAN_STATIC, "weapons/timer.wav", 1.0, ATTN_NORM, 0, PITCH_NORM ); + } } void CHudStatusIcons::DisableIcon( char *pszIconName ) diff --git a/cl_dll/statusbar.cpp b/cl_dll/statusbar.cpp index e9d74c6..6b2f28a 100644 --- a/cl_dll/statusbar.cpp +++ b/cl_dll/statusbar.cpp @@ -20,7 +20,7 @@ // #include "hud.h" -#include "util.h" +#include "cl_util.h" #include "parsemsg.h" #include @@ -129,10 +129,10 @@ void CHudStatusBar :: ParseStatusString( int line_num ) switch ( valtype ) { case 'p': // player name - GetPlayerInfo( indexval, &gHUD.m_Scoreboard.m_PlayerInfoList[indexval] ); - if ( gHUD.m_Scoreboard.m_PlayerInfoList[indexval].name != NULL ) + GetPlayerInfo( indexval, &g_PlayerInfoList[indexval] ); + if ( g_PlayerInfoList[indexval].name != NULL ) { - strncpy( szRepString, gHUD.m_Scoreboard.m_PlayerInfoList[indexval].name, MAX_PLAYER_NAME_LENGTH ); + strncpy( szRepString, g_PlayerInfoList[indexval].name, MAX_PLAYER_NAME_LENGTH ); } else { @@ -178,9 +178,9 @@ int CHudStatusBar :: Draw( float fTime ) int Y_START; if ( ScreenHeight >= 480 ) - Y_START = ScreenHeight - 45; + Y_START = ScreenHeight - 55; else - Y_START = ScreenHeight - 35; + Y_START = ScreenHeight - 45; int x = 5; int y = Y_START - ( TextHeight * i ); // draw along bottom of screen diff --git a/cl_dll/text_message.cpp b/cl_dll/text_message.cpp index 7cb1f60..277f8b0 100644 --- a/cl_dll/text_message.cpp +++ b/cl_dll/text_message.cpp @@ -21,11 +21,13 @@ // #include "hud.h" -#include "util.h" +#include "cl_util.h" #include #include #include "parsemsg.h" +#include "vgui_TeamFortressViewport.h" + DECLARE_MESSAGE( m_TextMessage, TextMsg ); int CHudTextMessage::Init(void) @@ -52,7 +54,7 @@ char *CHudTextMessage::LocaliseTextString( const char *msg, char *dst_buffer, in // cut msg name out of string static char word_buf[255]; char *wdst = word_buf, *word_start = src; - for ( ++src ; *src >= 'A' && *src <= 'z'; wdst++, src++ ) + for ( ++src ; (*src >= 'A' && *src <= 'z') || (*src >= '0' && *src <= '9'); wdst++, src++ ) { *wdst = *src; } @@ -90,8 +92,9 @@ char *CHudTextMessage::LocaliseTextString( const char *msg, char *dst_buffer, in // As above, but with a local static buffer char *CHudTextMessage::BufferedLocaliseTextString( const char *msg ) { - char dst_buffer[1024]; - return LocaliseTextString( msg, dst_buffer, 1024 ); + static char dst_buffer[1024]; + LocaliseTextString( msg, dst_buffer, 1024 ); + return dst_buffer; } // Simplified version of LocaliseTextString; assumes string is only one word @@ -179,6 +182,9 @@ int CHudTextMessage::MsgFunc_TextMsg( const char *pszName, int iSize, void *pbuf StripEndNewlineFromString( sstr4 ); char *psz = szBuf[5]; + if ( gViewPort && gViewPort->AllowedToPrintText() == FALSE ) + return 1; + switch ( msg_dest ) { case HUD_PRINTCENTER: diff --git a/cl_dll/tf_defs.h b/cl_dll/tf_defs.h new file mode 100644 index 0000000..38e0f9f --- /dev/null +++ b/cl_dll/tf_defs.h @@ -0,0 +1,1357 @@ +/*** +* +* Copyright (c) 1998, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +****/ + +#ifndef __TF_DEFS_H +#define __TF_DEFS_H + +//=========================================================================== +// OLD OPTIONS.QC +//=========================================================================== +#define DEFAULT_AUTOZOOM FALSE +#define WEINER_SNIPER // autoaiming for sniper rifle +#define FLAME_MAXWORLDNUM 20 // maximum number of flames in the world. DO NOT PUT BELOW 20. + +//#define MAX_WORLD_PIPEBOMBS 15 // This is divided between teams - this is the most you should have on a net server +#define MAX_PLAYER_PIPEBOMBS 8 // maximum number of pipebombs any 1 player can have active +#define MAX_PLAYER_AMMOBOXES 3 // maximum number of ammoboxes any 1 player can have active + +//#define MAX_WORLD_FLARES 9 // This is the total number of flares allowed in the world at one time +//#define MAX_WORLD_AMMOBOXES 20 // This is divided between teams - this is the most you should have on a net server +#define GR_TYPE_MIRV_NO 4 // Number of Mirvs a Mirv Grenade breaks into +#define GR_TYPE_NAPALM_NO 8 // Number of flames napalm grenade breaks into (unused if net server) +#define MEDIKIT_IS_BIOWEAPON // Medikit acts as a bioweapon against enemies + +#define TEAM_HELP_RATE 60 // used only if teamplay bit 64 (help team with lower score) is set. + // 60 is a mild setting, and won't make too much difference + // increasing it _decreases_ the amount of help the losing team gets + // Minimum setting is 1, which would really help the losing team + +#define DISPLAY_CLASS_HELP TRUE // Change this to #OFF if you don't want the class help to + // appear whenever a player connects +#define NEVER_TEAMFRAGS FALSE // teamfrags options always off +#define ALWAYS_TEAMFRAGS FALSE // teamfrags options always on +#define CHECK_SPEEDS TRUE // makes sure players aren't moving too fast +#define SNIPER_RIFLE_RELOAD_TIME 1.5 // seconds + +#define MAPBRIEFING_MAXTEXTLENGTH 512 +#define PLAYER_PUSH_VELOCITY 50 // Players push teammates if they're moving under this speed + +// Debug Options +//#define MAP_DEBUG // Debug for Map code. I suggest running in a hi-res + // mode and/or piping the output from the server to a file. +#ifdef MAP_DEBUG + #define MDEBUG(x) x +#else + #define MDEBUG(x) +#endif +//#define VERBOSE // Verbose Debugging on/off + +//=========================================================================== +// OLD QUAKE Defs +//=========================================================================== +// items +#define IT_AXE 4096 +#define IT_SHOTGUN 1 +#define IT_SUPER_SHOTGUN 2 +#define IT_NAILGUN 4 +#define IT_SUPER_NAILGUN 8 +#define IT_GRENADE_LAUNCHER 16 +#define IT_ROCKET_LAUNCHER 32 +#define IT_LIGHTNING 64 +#define IT_EXTRA_WEAPON 128 + +#define IT_SHELLS 256 +#define IT_NAILS 512 +#define IT_ROCKETS 1024 +#define IT_CELLS 2048 + +#define IT_ARMOR1 8192 +#define IT_ARMOR2 16384 +#define IT_ARMOR3 32768 +#define IT_SUPERHEALTH 65536 + +#define IT_KEY1 131072 +#define IT_KEY2 262144 + +#define IT_INVISIBILITY 524288 +#define IT_INVULNERABILITY 1048576 +#define IT_SUIT 2097152 +#define IT_QUAD 4194304 +#define IT_HOOK 8388608 + +#define IT_KEY3 16777216 // Stomp invisibility +#define IT_KEY4 33554432 // Stomp invulnerability + +//=========================================================================== +// TEAMFORTRESS Defs +//=========================================================================== +// TeamFortress State Flags +#define TFSTATE_GRENPRIMED 1 // Whether the player has a primed grenade +#define TFSTATE_RELOADING 2 // Whether the player is reloading +#define TFSTATE_ALTKILL 4 // #TRUE if killed with a weapon not in self.weapon: NOT USED ANYMORE +#define TFSTATE_RANDOMPC 8 // Whether Playerclass is random, new one each respawn +#define TFSTATE_INFECTED 16 // set when player is infected by the bioweapon +#define TFSTATE_INVINCIBLE 32 // Player has permanent Invincibility (Usually by GoalItem) +#define TFSTATE_INVISIBLE 64 // Player has permanent Invisibility (Usually by GoalItem) +#define TFSTATE_QUAD 128 // Player has permanent Quad Damage (Usually by GoalItem) +#define TFSTATE_RADSUIT 256 // Player has permanent Radsuit (Usually by GoalItem) +#define TFSTATE_BURNING 512 // Is on fire +#define TFSTATE_GRENTHROWING 1024 // is throwing a grenade +#define TFSTATE_AIMING 2048 // is using the laser sight +#define TFSTATE_ZOOMOFF 4096 // doesn't want the FOV changed when zooming +#define TFSTATE_RESPAWN_READY 8192 // is waiting for respawn, and has pressed fire +#define TFSTATE_HALLUCINATING 16384 // set when player is hallucinating +#define TFSTATE_TRANQUILISED 32768 // set when player is tranquilised +#define TFSTATE_CANT_MOVE 65536 // set when player is setting a detpack +#define TFSTATE_RESET_FLAMETIME 131072 // set when the player has to have his flames increased in health + +// Defines used by TF_T_Damage (see combat.qc) +#define TF_TD_IGNOREARMOUR 1 // Bypasses the armour of the target +#define TF_TD_NOTTEAM 2 // Doesn't damage a team member (indicates direct fire weapon) +#define TF_TD_NOTSELF 4 // Doesn't damage self + +#define TF_TD_OTHER 0 // Ignore armorclass +#define TF_TD_SHOT 1 // Bullet damage +#define TF_TD_NAIL 2 // Nail damage +#define TF_TD_EXPLOSION 4 // Explosion damage +#define TF_TD_ELECTRICITY 8 // Electric damage +#define TF_TD_FIRE 16 // Fire damage +#define TF_TD_NOSOUND 256 // Special damage. Makes no sound/painframe, etc + +/*==================================================*/ +/* Toggleable Game Settings */ +/*==================================================*/ +#define TF_RESPAWNDELAY1 5 // seconds of waiting before player can respawn +#define TF_RESPAWNDELAY2 10 // seconds of waiting before player can respawn +#define TF_RESPAWNDELAY3 20 // seconds of waiting before player can respawn + +#define TEAMPLAY_NORMAL 1 +#define TEAMPLAY_HALFDIRECT 2 +#define TEAMPLAY_NODIRECT 4 +#define TEAMPLAY_HALFEXPLOSIVE 8 +#define TEAMPLAY_NOEXPLOSIVE 16 +#define TEAMPLAY_LESSPLAYERSHELP 32 +#define TEAMPLAY_LESSSCOREHELP 64 +#define TEAMPLAY_HALFDIRECTARMOR 128 +#define TEAMPLAY_NODIRECTARMOR 256 +#define TEAMPLAY_HALFEXPARMOR 512 +#define TEAMPLAY_NOEXPARMOR 1024 +#define TEAMPLAY_HALFDIRMIRROR 2048 +#define TEAMPLAY_FULLDIRMIRROR 4096 +#define TEAMPLAY_HALFEXPMIRROR 8192 +#define TEAMPLAY_FULLEXPMIRROR 16384 + +#define TEAMPLAY_TEAMDAMAGE (TEAMPLAY_NODIRECT | TEAMPLAY_HALFDIRECT | TEAMPLAY_HALFEXPLOSIVE | TEAMPLAY_NOEXPLOSIVE) +// FortressMap stuff +#define TEAM1_CIVILIANS 1 +#define TEAM2_CIVILIANS 2 +#define TEAM3_CIVILIANS 4 +#define TEAM4_CIVILIANS 8 + +// Defines for the playerclass +#define PC_UNDEFINED 0 + +#define PC_SCOUT 1 +#define PC_SNIPER 2 +#define PC_SOLDIER 3 +#define PC_DEMOMAN 4 +#define PC_MEDIC 5 +#define PC_HVYWEAP 6 +#define PC_PYRO 7 +#define PC_SPY 8 +#define PC_ENGINEER 9 + +// Insert new class definitions here + +// PC_RANDOM _MUST_ be the third last class +#define PC_RANDOM 10 // Random playerclass +#define PC_CIVILIAN 11 // Civilians are a special class. They cannot + // be chosen by players, only enforced by maps +#define PC_LASTCLASS 12 // Use this as the high-boundary for any loops + // through the playerclass. + +// These are just for the scanner +#define SCAN_SENTRY 13 +#define SCAN_GOALITEM 14 + +// Values returned by CheckArea +enum +{ + CAREA_CLEAR, + CAREA_BLOCKED, + CAREA_NOBUILD +}; + +/*==================================================*/ +/* Impulse Defines */ +/*==================================================*/ +// Alias check to see whether they already have the aliases +#define TF_ALIAS_CHECK 13 + +// CTF Support Impulses +#define HOOK_IMP1 22 +#define FLAG_INFO 23 +#define HOOK_IMP2 39 + +// Axe +#define AXE_IMP 40 + +// Camera Impulse +#define TF_CAM_TARGET 50 +#define TF_CAM_ZOOM 51 +#define TF_CAM_ANGLE 52 +#define TF_CAM_VEC 53 +#define TF_CAM_PROJECTILE 54 +#define TF_CAM_PROJECTILE_Z 55 +#define TF_CAM_REVANGLE 56 +#define TF_CAM_OFFSET 57 +#define TF_CAM_DROP 58 +#define TF_CAM_FADETOBLACK 59 +#define TF_CAM_FADEFROMBLACK 60 +#define TF_CAM_FADETOWHITE 61 +#define TF_CAM_FADEFROMWHITE 62 + +// Last Weapon impulse +#define TF_LAST_WEAPON 69 + +// Status Bar Resolution Settings. Same as CTF to maintain ease of use. +#define TF_STATUSBAR_RES_START 71 +#define TF_STATUSBAR_RES_END 81 + +// Clan Messages +#define TF_MESSAGE_1 82 +#define TF_MESSAGE_2 83 +#define TF_MESSAGE_3 84 +#define TF_MESSAGE_4 85 +#define TF_MESSAGE_5 86 + +#define TF_CHANGE_CLASS 99 // Bring up the Class Change menu + +// Added to PC_??? to get impulse to use if this clashes with your +// own impulses, just change this value, not the PC_?? +#define TF_CHANGEPC 100 +// The next few impulses are all the class selections +//PC_SCOUT 101 +//PC_SNIPER 102 +//PC_SOLDIER 103 +//PC_DEMOMAN 104 +//PC_MEDIC 105 +//PC_HVYWEAP 106 +//PC_PYRO 107 +//PC_RANDOM 108 +//PC_CIVILIAN 109 // Cannot be used +//PC_SPY 110 +//PC_ENGINEER 111 + +// Help impulses +#define TF_DISPLAYLOCATION 118 +#define TF_STATUS_QUERY 119 + +#define TF_HELP_MAP 131 + +// Information impulses +#define TF_INVENTORY 135 +#define TF_SHOWTF 136 +#define TF_SHOWLEGALCLASSES 137 + +// Team Impulses +#define TF_TEAM_1 140 // Join Team 1 +#define TF_TEAM_2 141 // Join Team 2 +#define TF_TEAM_3 142 // Join Team 3 +#define TF_TEAM_4 143 // Join Team 4 +#define TF_TEAM_CLASSES 144 // Impulse to display team classes +#define TF_TEAM_SCORES 145 // Impulse to display team scores +#define TF_TEAM_LIST 146 // Impulse to display the players in each team. + +// Grenade Impulses +#define TF_GRENADE_1 150 // Prime grenade type 1 +#define TF_GRENADE_2 151 // Prime grenade type 2 +#define TF_GRENADE_T 152 // Throw primed grenade + +// Impulses for new items +//#define TF_SCAN 159 // Scanner Pre-Impulse +#define TF_AUTO_SCAN 159 // Scanner On/Off +#define TF_SCAN_ENEMY 160 // Impulses to toggle scanning of enemies +#define TF_SCAN_FRIENDLY 161 // Impulses to toggle scanning of friendlies +//#define TF_SCAN_10 162 // Scan using 10 enery (1 cell) +#define TF_SCAN_SOUND 162 // Scanner sounds on/off +#define TF_SCAN_30 163 // Scan using 30 energy (2 cells) +#define TF_SCAN_100 164 // Scan using 100 energy (5 cells) +#define TF_DETPACK_5 165 // Detpack set to 5 seconds +#define TF_DETPACK_20 166 // Detpack set to 20 seconds +#define TF_DETPACK_50 167 // Detpack set to 50 seconds +#define TF_DETPACK 168 // Detpack Pre-Impulse +#define TF_DETPACK_STOP 169 // Impulse to stop setting detpack +#define TF_PB_DETONATE 170 // Detonate Pipebombs + +// Special skill +#define TF_SPECIAL_SKILL 171 + +// Ammo Drop impulse +#define TF_DROP_AMMO 172 + +// Reload impulse +#define TF_RELOAD 173 + +// auto-zoom toggle +#define TF_AUTOZOOM 174 + +// drop/pass commands +#define TF_DROPKEY 175 + +// Select Medikit +#define TF_MEDIKIT 176 + +// Spy Impulses +#define TF_SPY_SPY 177 // On net, go invisible, on LAN, change skin/color +#define TF_SPY_DIE 178 // Feign Death + +// Engineer Impulses +#define TF_ENGINEER_BUILD 179 +#define TF_ENGINEER_SANDBAG 180 + +// Medic +#define TF_MEDIC_HELPME 181 + +// Status bar +#define TF_STATUSBAR_ON 182 +#define TF_STATUSBAR_OFF 183 + +// Discard impulse +#define TF_DISCARD 184 + +// ID Player impulse +#define TF_ID 185 + +// Clan Battle impulses +#define TF_SHOWIDS 186 + +// More Engineer Impulses +#define TF_ENGINEER_DETDISP 187 +#define TF_ENGINEER_DETSENT 188 + +// Admin Commands +#define TF_ADMIN_DEAL_CYCLE 189 +#define TF_ADMIN_KICK 190 +#define TF_ADMIN_BAN 191 +#define TF_ADMIN_COUNTPLAYERS 192 +#define TF_ADMIN_CEASEFIRE 193 + +// Drop Goal Items +#define TF_DROPGOALITEMS 194 + +// More Admin Commands +#define TF_ADMIN_NEXT 195 + +// More Engineer Impulses +#define TF_ENGINEER_DETEXIT 196 +#define TF_ENGINEER_DETENTRANCE 197 + +// Yet MORE Admin Commands +#define TF_ADMIN_LISTIPS 198 + +// Silent Spy Feign +#define TF_SPY_SILENTDIE 199 + + +/*==================================================*/ +/* Colors */ +/*==================================================*/ +#define TEAM1_COLOR 150 +#define TEAM2_COLOR 250 +#define TEAM3_COLOR 45 +#define TEAM4_COLOR 100 + +/*==================================================*/ +/* Defines for the ENGINEER's Building ability */ +/*==================================================*/ +// Ammo costs +#define AMMO_COST_SHELLS 2 // Metal needed to make 1 shell +#define AMMO_COST_NAILS 1 +#define AMMO_COST_ROCKETS 2 +#define AMMO_COST_CELLS 2 + +// Building types +#define BUILD_DISPENSER 1 +#define BUILD_SENTRYGUN 2 +#define BUILD_MORTAR 3 +#define BUILD_TELEPORTER_ENTRANCE 4 +#define BUILD_TELEPORTER_EXIT 5 + +// Building metal costs +#define BUILD_COST_DISPENSER 100 // Metal needed to built +#define BUILD_COST_SENTRYGUN 130 +#define BUILD_COST_MORTAR 150 +#define BUILD_COST_TELEPORTER 125 + +#define BUILD_COST_SANDBAG 20 // Built with a separate alias + +// Building times +#define BUILD_TIME_DISPENSER 2 // seconds to build +#define BUILD_TIME_SENTRYGUN 5 +#define BUILD_TIME_MORTAR 5 +#define BUILD_TIME_TELEPORTER 4 + +// Building health levels +#define BUILD_HEALTH_DISPENSER 150 // Health of the building +#define BUILD_HEALTH_SENTRYGUN 150 +#define BUILD_HEALTH_MORTAR 200 +#define BUILD_HEALTH_TELEPORTER 80 + +// Dispenser's maximum carrying capability +#define BUILD_DISPENSER_MAX_SHELLS 400 +#define BUILD_DISPENSER_MAX_NAILS 600 +#define BUILD_DISPENSER_MAX_ROCKETS 300 +#define BUILD_DISPENSER_MAX_CELLS 400 +#define BUILD_DISPENSER_MAX_ARMOR 500 + +// Build state sent down to client +#define BS_BUILDING (1<<0) +#define BS_HAS_DISPENSER (1<<1) +#define BS_HAS_SENTRYGUN (1<<2) +#define BS_CANB_DISPENSER (1<<3) +#define BS_CANB_SENTRYGUN (1<<4) +/*==================================================*/ +/* Ammo quantities for dropping & dispenser use */ +/*==================================================*/ +#define DROP_SHELLS 20 +#define DROP_NAILS 20 +#define DROP_ROCKETS 10 +#define DROP_CELLS 10 +#define DROP_ARMOR 40 + +/*==================================================*/ +/* Team Defines */ +/*==================================================*/ +#define TM_MAX_NO 4 // Max number of teams. Simply changing this value isn't enough. + // A new global to hold new team colors is needed, and more flags + // in the spawnpoint spawnflags may need to be used. + // Basically, don't change this unless you know what you're doing :) + +/*==================================================*/ +/* New Weapon Defines */ +/*==================================================*/ +#define WEAP_HOOK 1 +#define WEAP_BIOWEAPON 2 +#define WEAP_MEDIKIT 4 +#define WEAP_SPANNER 8 +#define WEAP_AXE 16 +#define WEAP_SNIPER_RIFLE 32 +#define WEAP_AUTO_RIFLE 64 +#define WEAP_SHOTGUN 128 +#define WEAP_SUPER_SHOTGUN 256 +#define WEAP_NAILGUN 512 +#define WEAP_SUPER_NAILGUN 1024 +#define WEAP_GRENADE_LAUNCHER 2048 +#define WEAP_FLAMETHROWER 4096 +#define WEAP_ROCKET_LAUNCHER 8192 +#define WEAP_INCENDIARY 16384 +#define WEAP_ASSAULT_CANNON 32768 +#define WEAP_LIGHTNING 65536 +#define WEAP_DETPACK 131072 +#define WEAP_TRANQ 262144 +#define WEAP_LASER 524288 +// still room for 12 more weapons +// but we can remove some by giving the weapons +// a weapon mode (like the rifle) + +// HL-compatible weapon numbers +#define WEAPON_HOOK 1 +#define WEAPON_BIOWEAPON (WEAPON_HOOK+1) +#define WEAPON_MEDIKIT (WEAPON_HOOK+2) +#define WEAPON_SPANNER (WEAPON_HOOK+3) +#define WEAPON_AXE (WEAPON_HOOK+4) +#define WEAPON_SNIPER_RIFLE (WEAPON_HOOK+5) +#define WEAPON_AUTO_RIFLE (WEAPON_HOOK+6) +#define WEAPON_TF_SHOTGUN (WEAPON_HOOK+7) +#define WEAPON_SUPER_SHOTGUN (WEAPON_HOOK+8) +#define WEAPON_NAILGUN (WEAPON_HOOK+9) +#define WEAPON_SUPER_NAILGUN (WEAPON_HOOK+10) +#define WEAPON_GRENADE_LAUNCHER (WEAPON_HOOK+11) +#define WEAPON_FLAMETHROWER (WEAPON_HOOK+12) +#define WEAPON_ROCKET_LAUNCHER (WEAPON_HOOK+13) +#define WEAPON_INCENDIARY (WEAPON_HOOK+14) +#define WEAPON_ASSAULT_CANNON (WEAPON_HOOK+16) +#define WEAPON_LIGHTNING (WEAPON_HOOK+17) +#define WEAPON_DETPACK (WEAPON_HOOK+18) +#define WEAPON_TRANQ (WEAPON_HOOK+19) +#define WEAPON_LASER (WEAPON_HOOK+20) +#define WEAPON_PIPEBOMB_LAUNCHER (WEAPON_HOOK+21) +#define WEAPON_KNIFE (WEAPON_HOOK+22) +#define WEAPON_BENCHMARK (WEAPON_HOOK+23) + +/*==================================================*/ +/* New Weapon Related Defines */ +/*==================================================*/ +// shots per reload +#define RE_SHOTGUN 8 +#define RE_SUPER_SHOTGUN 16 // 8 shots +#define RE_GRENADE_LAUNCHER 6 +#define RE_ROCKET_LAUNCHER 4 + +// reload times +#define RE_SHOTGUN_TIME 2 +#define RE_SUPER_SHOTGUN_TIME 3 +#define RE_GRENADE_LAUNCHER_TIME 4 +#define RE_ROCKET_LAUNCHER_TIME 5 + +// Maximum velocity you can move and fire the Sniper Rifle +#define WEAP_SNIPER_RIFLE_MAX_MOVE 50 + +// Medikit +#define WEAP_MEDIKIT_HEAL 200 // Amount medikit heals per hit +#define WEAP_MEDIKIT_OVERHEAL 50 // Amount of superhealth over max_health the medikit will dispense + +// Spanner +#define WEAP_SPANNER_REPAIR 10 + +// Detpack +#define WEAP_DETPACK_DISARMTIME 3 // Time it takes to disarm a Detpack +#define WEAP_DETPACK_SETTIME 3 // Time it takes to set a Detpack +#define WEAP_DETPACK_SIZE 700 // Explosion Size +#define WEAP_DETPACK_GOAL_SIZE 1500 // Explosion Size for goal triggering +#define WEAP_DETPACK_BITS_NO 12 // Bits that detpack explodes into + +// Tranquiliser Gun +#define TRANQ_TIME 15 + +// Grenades +#define GR_PRIMETIME 3 +#define GR_CALTROP_PRIME 0.5 +#define GR_TYPE_NONE 0 +#define GR_TYPE_NORMAL 1 +#define GR_TYPE_CONCUSSION 2 +#define GR_TYPE_NAIL 3 +#define GR_TYPE_MIRV 4 +#define GR_TYPE_NAPALM 5 +//#define GR_TYPE_FLARE 6 +#define GR_TYPE_GAS 7 +#define GR_TYPE_EMP 8 +#define GR_TYPE_CALTROP 9 +//#define GR_TYPE_FLASH 10 + +// Defines for WeaponMode +#define GL_NORMAL 0 +#define GL_PIPEBOMB 1 + +// Defines for OLD Concussion Grenade +#define GR_OLD_CONCUSS_TIME 5 +#define GR_OLD_CONCUSS_DEC 20 + +// Defines for Concussion Grenade +#define GR_CONCUSS_TIME 0.25 +#define GR_CONCUSS_DEC 10 +#define MEDIUM_PING 150 +#define HIGH_PING 200 + +// Defines for the Gas Grenade +#define GR_HALLU_TIME 0.3 +#define GR_OLD_HALLU_TIME 0.5 +#define GR_HALLU_DEC 2.5 + +// Defines for the BioInfection +#define BIO_JUMP_RADIUS 128 // The distance the bioinfection can jump between players + +/*==================================================*/ +/* New Items */ +/*==================================================*/ +#define NIT_SCANNER 1 + +#define NIT_SILVER_DOOR_OPENED #IT_KEY1 // 131072 +#define NIT_GOLD_DOOR_OPENED #IT_KEY2 // 262144 + +/*==================================================*/ +/* New Item Flags */ +/*==================================================*/ +#define NIT_SCANNER_ENEMY 1 // Detect enemies +#define NIT_SCANNER_FRIENDLY 2 // Detect friendlies (team members) +#define NIT_SCANNER_SOUND 4 // Motion detection. Only report moving entities. + +/*==================================================*/ +/* New Item Related Defines */ +/*==================================================*/ +#define NIT_SCANNER_POWER 25 // The amount of power spent on a scan with the scanner + // is multiplied by this to get the scanrange. +#define NIT_SCANNER_MAXCELL 50 // The maximum number of cells than can be used in one scan +#define NIT_SCANNER_MIN_MOVEMENT 50 // The minimum velocity an entity must have to be detected + // by scanners that only detect movement + +/*==================================================*/ +/* Variables used for New Weapons and Reloading */ +/*==================================================*/ +// Armor Classes : Bitfields. Use the "armorclass" of armor for the Armor Type. +#define AT_SAVESHOT 1 // Kevlar : Reduces bullet damage by 15% +#define AT_SAVENAIL 2 // Wood :) : Reduces nail damage by 15% +#define AT_SAVEEXPLOSION 4 // Blast : Reduces explosion damage by 15% +#define AT_SAVEELECTRICITY 8 // Shock : Reduces electricity damage by 15% +#define AT_SAVEFIRE 16 // Asbestos : Reduces fire damage by 15% + +/*==========================================================================*/ +/* TEAMFORTRESS CLASS DETAILS */ +/*==========================================================================*/ +// Class Details for SCOUT +#define PC_SCOUT_SKIN 4 // Skin for this class when Classkin is on. +#define PC_SCOUT_MAXHEALTH 75 // Maximum Health Level +#define PC_SCOUT_MAXSPEED 400 // Maximum movement speed +#define PC_SCOUT_MAXSTRAFESPEED 400 // Maximum strafing movement speed +#define PC_SCOUT_MAXARMOR 50 // Maximum Armor Level, of any armor class +#define PC_SCOUT_INITARMOR 25 // Armor level when respawned +#define PC_SCOUT_MAXARMORTYPE 0.3 // Maximum level of Armor absorption +#define PC_SCOUT_INITARMORTYPE 0.3 // Absorption Level of armor when respawned +#define PC_SCOUT_ARMORCLASSES 3 // #AT_SAVESHOT | #AT_SAVENAIL <-Armor Classes allowed for this class +#define PC_SCOUT_INITARMORCLASS 0 // Armorclass worn when respawned +#define PC_SCOUT_WEAPONS WEAP_AXE | WEAP_SHOTGUN | WEAP_NAILGUN +#define PC_SCOUT_MAXAMMO_SHOT 50 // Maximum amount of shot ammo this class can carry +#define PC_SCOUT_MAXAMMO_NAIL 200 // Maximum amount of nail ammo this class can carry +#define PC_SCOUT_MAXAMMO_CELL 100 // Maximum amount of cell ammo this class can carry +#define PC_SCOUT_MAXAMMO_ROCKET 25 // Maximum amount of rocket ammo this class can carry +#define PC_SCOUT_INITAMMO_SHOT 25 // Amount of shot ammo this class has when respawned +#define PC_SCOUT_INITAMMO_NAIL 100 // Amount of nail ammo this class has when respawned +#define PC_SCOUT_INITAMMO_CELL 50 // Amount of cell ammo this class has when respawned +#define PC_SCOUT_INITAMMO_ROCKET 0 // Amount of rocket ammo this class has when respawned +#define PC_SCOUT_GRENADE_TYPE_1 GR_TYPE_CALTROP // <- 1st Type of Grenade this class has +#define PC_SCOUT_GRENADE_TYPE_2 GR_TYPE_CONCUSSION // <- 2nd Type of Grenade this class has +#define PC_SCOUT_GRENADE_INIT_1 2 // Number of grenades of Type 1 this class has when respawned +#define PC_SCOUT_GRENADE_INIT_2 3 // Number of grenades of Type 2 this class has when respawned +#define PC_SCOUT_TF_ITEMS NIT_SCANNER // <- TeamFortress Items this class has + +#define PC_SCOUT_MOTION_MIN_I 0.5 // < Short range +#define PC_SCOUT_MOTION_MIN_MOVE 50 // Minimum vlen of player velocity to be picked up by motion detector +#define PC_SCOUT_SCAN_TIME 2 // # of seconds between each scan pulse +#define PC_SCOUT_SCAN_RANGE 100 // Default scanner range +#define PC_SCOUT_SCAN_COST 2 // Default scanner cell useage per scan + +// Class Details for SNIPER +#define PC_SNIPER_SKIN 5 +#define PC_SNIPER_MAXHEALTH 90 +#define PC_SNIPER_MAXSPEED 300 +#define PC_SNIPER_MAXSTRAFESPEED 300 +#define PC_SNIPER_MAXARMOR 50 +#define PC_SNIPER_INITARMOR 0 +#define PC_SNIPER_MAXARMORTYPE 0.3 +#define PC_SNIPER_INITARMORTYPE 0.3 +#define PC_SNIPER_ARMORCLASSES 3 // #AT_SAVESHOT | #AT_SAVENAIL +#define PC_SNIPER_INITARMORCLASS 0 +#define PC_SNIPER_WEAPONS WEAP_SNIPER_RIFLE | WEAP_AUTO_RIFLE | WEAP_AXE | WEAP_NAILGUN +#define PC_SNIPER_MAXAMMO_SHOT 75 +#define PC_SNIPER_MAXAMMO_NAIL 100 +#define PC_SNIPER_MAXAMMO_CELL 50 +#define PC_SNIPER_MAXAMMO_ROCKET 25 +#define PC_SNIPER_INITAMMO_SHOT 60 +#define PC_SNIPER_INITAMMO_NAIL 50 +#define PC_SNIPER_INITAMMO_CELL 0 +#define PC_SNIPER_INITAMMO_ROCKET 0 +#define PC_SNIPER_GRENADE_TYPE_1 GR_TYPE_NORMAL +#define PC_SNIPER_GRENADE_TYPE_2 GR_TYPE_NONE +#define PC_SNIPER_GRENADE_INIT_1 2 +#define PC_SNIPER_GRENADE_INIT_2 0 +#define PC_SNIPER_TF_ITEMS 0 + +// Class Details for SOLDIER +#define PC_SOLDIER_SKIN 6 +#define PC_SOLDIER_MAXHEALTH 100 +#define PC_SOLDIER_MAXSPEED 240 +#define PC_SOLDIER_MAXSTRAFESPEED 240 +#define PC_SOLDIER_MAXARMOR 200 +#define PC_SOLDIER_INITARMOR 100 +#define PC_SOLDIER_MAXARMORTYPE 0.8 +#define PC_SOLDIER_INITARMORTYPE 0.8 +#define PC_SOLDIER_ARMORCLASSES 31 // ALL +#define PC_SOLDIER_INITARMORCLASS 0 +#define PC_SOLDIER_WEAPONS WEAP_AXE | WEAP_SHOTGUN | WEAP_SUPER_SHOTGUN | WEAP_ROCKET_LAUNCHER +#define PC_SOLDIER_MAXAMMO_SHOT 100 +#define PC_SOLDIER_MAXAMMO_NAIL 100 +#define PC_SOLDIER_MAXAMMO_CELL 50 +#define PC_SOLDIER_MAXAMMO_ROCKET 50 +#define PC_SOLDIER_INITAMMO_SHOT 50 +#define PC_SOLDIER_INITAMMO_NAIL 0 +#define PC_SOLDIER_INITAMMO_CELL 0 +#define PC_SOLDIER_INITAMMO_ROCKET 10 +#define PC_SOLDIER_GRENADE_TYPE_1 GR_TYPE_NORMAL +#define PC_SOLDIER_GRENADE_TYPE_2 GR_TYPE_NAIL +#define PC_SOLDIER_GRENADE_INIT_1 4 +#define PC_SOLDIER_GRENADE_INIT_2 1 +#define PC_SOLDIER_TF_ITEMS 0 + +#define MAX_NAIL_GRENS 2 // Can only have 2 Nail grens active +#define MAX_NAPALM_GRENS 2 // Can only have 2 Napalm grens active +#define MAX_GAS_GRENS 2 // Can only have 2 Gas grenades active +#define MAX_MIRV_GRENS 2 // Can only have 2 Mirv's +#define MAX_CONCUSSION_GRENS 3 +#define MAX_CALTROP_CANS 3 + +// Class Details for DEMOLITION MAN +#define PC_DEMOMAN_SKIN 1 +#define PC_DEMOMAN_MAXHEALTH 90 +#define PC_DEMOMAN_MAXSPEED 280 +#define PC_DEMOMAN_MAXSTRAFESPEED 280 +#define PC_DEMOMAN_MAXARMOR 120 +#define PC_DEMOMAN_INITARMOR 50 +#define PC_DEMOMAN_MAXARMORTYPE 0.6 +#define PC_DEMOMAN_INITARMORTYPE 0.6 +#define PC_DEMOMAN_ARMORCLASSES 31 // ALL +#define PC_DEMOMAN_INITARMORCLASS 0 +#define PC_DEMOMAN_WEAPONS WEAP_AXE | WEAP_SHOTGUN | WEAP_GRENADE_LAUNCHER | WEAP_DETPACK +#define PC_DEMOMAN_MAXAMMO_SHOT 75 +#define PC_DEMOMAN_MAXAMMO_NAIL 50 +#define PC_DEMOMAN_MAXAMMO_CELL 50 +#define PC_DEMOMAN_MAXAMMO_ROCKET 50 +#define PC_DEMOMAN_MAXAMMO_DETPACK 1 +#define PC_DEMOMAN_INITAMMO_SHOT 30 +#define PC_DEMOMAN_INITAMMO_NAIL 0 +#define PC_DEMOMAN_INITAMMO_CELL 0 +#define PC_DEMOMAN_INITAMMO_ROCKET 20 +#define PC_DEMOMAN_INITAMMO_DETPACK 1 +#define PC_DEMOMAN_GRENADE_TYPE_1 GR_TYPE_NORMAL +#define PC_DEMOMAN_GRENADE_TYPE_2 GR_TYPE_MIRV +#define PC_DEMOMAN_GRENADE_INIT_1 4 +#define PC_DEMOMAN_GRENADE_INIT_2 4 +#define PC_DEMOMAN_TF_ITEMS 0 + +// Class Details for COMBAT MEDIC +#define PC_MEDIC_SKIN 3 +#define PC_MEDIC_MAXHEALTH 90 +#define PC_MEDIC_MAXSPEED 320 +#define PC_MEDIC_MAXSTRAFESPEED 320 +#define PC_MEDIC_MAXARMOR 100 +#define PC_MEDIC_INITARMOR 50 +#define PC_MEDIC_MAXARMORTYPE 0.6 +#define PC_MEDIC_INITARMORTYPE 0.3 +#define PC_MEDIC_ARMORCLASSES 11 // ALL except EXPLOSION +#define PC_MEDIC_INITARMORCLASS 0 +#define PC_MEDIC_WEAPONS WEAP_BIOWEAPON | WEAP_MEDIKIT | WEAP_SHOTGUN | WEAP_SUPER_SHOTGUN | WEAP_SUPER_NAILGUN +#define PC_MEDIC_MAXAMMO_SHOT 75 +#define PC_MEDIC_MAXAMMO_NAIL 150 +#define PC_MEDIC_MAXAMMO_CELL 50 +#define PC_MEDIC_MAXAMMO_ROCKET 25 +#define PC_MEDIC_MAXAMMO_MEDIKIT 100 +#define PC_MEDIC_INITAMMO_SHOT 50 +#define PC_MEDIC_INITAMMO_NAIL 50 +#define PC_MEDIC_INITAMMO_CELL 0 +#define PC_MEDIC_INITAMMO_ROCKET 0 +#define PC_MEDIC_INITAMMO_MEDIKIT 50 +#define PC_MEDIC_GRENADE_TYPE_1 GR_TYPE_NORMAL +#define PC_MEDIC_GRENADE_TYPE_2 GR_TYPE_CONCUSSION +#define PC_MEDIC_GRENADE_INIT_1 3 +#define PC_MEDIC_GRENADE_INIT_2 2 +#define PC_MEDIC_TF_ITEMS 0 +#define PC_MEDIC_REGEN_TIME 3 // Number of seconds between each regen. +#define PC_MEDIC_REGEN_AMOUNT 2 // Amount of health regenerated each regen. + +// Class Details for HVYWEAP +#define PC_HVYWEAP_SKIN 2 +#define PC_HVYWEAP_MAXHEALTH 100 +#define PC_HVYWEAP_MAXSPEED 230 +#define PC_HVYWEAP_MAXSTRAFESPEED 230 +#define PC_HVYWEAP_MAXARMOR 300 +#define PC_HVYWEAP_INITARMOR 150 +#define PC_HVYWEAP_MAXARMORTYPE 0.8 +#define PC_HVYWEAP_INITARMORTYPE 0.8 +#define PC_HVYWEAP_ARMORCLASSES 31 // ALL +#define PC_HVYWEAP_INITARMORCLASS 0 +#define PC_HVYWEAP_WEAPONS WEAP_ASSAULT_CANNON | WEAP_AXE | WEAP_SHOTGUN | WEAP_SUPER_SHOTGUN +#define PC_HVYWEAP_MAXAMMO_SHOT 200 +#define PC_HVYWEAP_MAXAMMO_NAIL 200 +#define PC_HVYWEAP_MAXAMMO_CELL 50 +#define PC_HVYWEAP_MAXAMMO_ROCKET 25 +#define PC_HVYWEAP_INITAMMO_SHOT 200 +#define PC_HVYWEAP_INITAMMO_NAIL 0 +#define PC_HVYWEAP_INITAMMO_CELL 30 +#define PC_HVYWEAP_INITAMMO_ROCKET 0 +#define PC_HVYWEAP_GRENADE_TYPE_1 GR_TYPE_NORMAL +#define PC_HVYWEAP_GRENADE_TYPE_2 GR_TYPE_MIRV +#define PC_HVYWEAP_GRENADE_INIT_1 4 +#define PC_HVYWEAP_GRENADE_INIT_2 1 +#define PC_HVYWEAP_TF_ITEMS 0 +#define PC_HVYWEAP_CELL_USAGE 7 // Amount of cells spent to power up assault cannon + + + +// Class Details for PYRO +#define PC_PYRO_SKIN 21 +#define PC_PYRO_MAXHEALTH 100 +#define PC_PYRO_MAXSPEED 300 +#define PC_PYRO_MAXSTRAFESPEED 300 +#define PC_PYRO_MAXARMOR 150 +#define PC_PYRO_INITARMOR 50 +#define PC_PYRO_MAXARMORTYPE 0.6 +#define PC_PYRO_INITARMORTYPE 0.6 +#define PC_PYRO_ARMORCLASSES 27 // ALL except EXPLOSION +#define PC_PYRO_INITARMORCLASS 16 // #AT_SAVEFIRE +#define PC_PYRO_WEAPONS WEAP_INCENDIARY | WEAP_FLAMETHROWER | WEAP_AXE | WEAP_SHOTGUN +#define PC_PYRO_MAXAMMO_SHOT 40 +#define PC_PYRO_MAXAMMO_NAIL 50 +#define PC_PYRO_MAXAMMO_CELL 200 +#define PC_PYRO_MAXAMMO_ROCKET 20 +#define PC_PYRO_INITAMMO_SHOT 20 +#define PC_PYRO_INITAMMO_NAIL 0 +#define PC_PYRO_INITAMMO_CELL 120 +#define PC_PYRO_INITAMMO_ROCKET 5 +#define PC_PYRO_GRENADE_TYPE_1 GR_TYPE_NORMAL +#define PC_PYRO_GRENADE_TYPE_2 GR_TYPE_NAPALM +#define PC_PYRO_GRENADE_INIT_1 1 +#define PC_PYRO_GRENADE_INIT_2 4 +#define PC_PYRO_TF_ITEMS 0 +#define PC_PYRO_ROCKET_USAGE 3 // Number of rockets per incendiary cannon shot + +// Class Details for SPY +#define PC_SPY_SKIN 22 +#define PC_SPY_MAXHEALTH 90 +#define PC_SPY_MAXSPEED 300 +#define PC_SPY_MAXSTRAFESPEED 300 +#define PC_SPY_MAXARMOR 100 +#define PC_SPY_INITARMOR 25 +#define PC_SPY_MAXARMORTYPE 0.6 // Was 0.3 +#define PC_SPY_INITARMORTYPE 0.6 // Was 0.3 +#define PC_SPY_ARMORCLASSES 27 // ALL except EXPLOSION +#define PC_SPY_INITARMORCLASS 0 +#define PC_SPY_WEAPONS WEAP_AXE | WEAP_TRANQ | WEAP_SUPER_SHOTGUN | WEAP_NAILGUN +#define PC_SPY_MAXAMMO_SHOT 40 +#define PC_SPY_MAXAMMO_NAIL 100 +#define PC_SPY_MAXAMMO_CELL 30 +#define PC_SPY_MAXAMMO_ROCKET 15 +#define PC_SPY_INITAMMO_SHOT 40 +#define PC_SPY_INITAMMO_NAIL 50 +#define PC_SPY_INITAMMO_CELL 10 +#define PC_SPY_INITAMMO_ROCKET 0 +#define PC_SPY_GRENADE_TYPE_1 GR_TYPE_NORMAL +#define PC_SPY_GRENADE_TYPE_2 GR_TYPE_GAS +#define PC_SPY_GRENADE_INIT_1 2 +#define PC_SPY_GRENADE_INIT_2 2 +#define PC_SPY_TF_ITEMS 0 +#define PC_SPY_CELL_REGEN_TIME 5 +#define PC_SPY_CELL_REGEN_AMOUNT 1 +#define PC_SPY_CELL_USAGE 3 // Amount of cells spent while invisible +#define PC_SPY_GO_UNDERCOVER_TIME 4 // Time it takes to go undercover + +// Class Details for ENGINEER +#define PC_ENGINEER_SKIN 22 // Not used anymore +#define PC_ENGINEER_MAXHEALTH 80 +#define PC_ENGINEER_MAXSPEED 300 +#define PC_ENGINEER_MAXSTRAFESPEED 300 +#define PC_ENGINEER_MAXARMOR 50 +#define PC_ENGINEER_INITARMOR 25 +#define PC_ENGINEER_MAXARMORTYPE 0.6 +#define PC_ENGINEER_INITARMORTYPE 0.3 +#define PC_ENGINEER_ARMORCLASSES 31 // ALL +#define PC_ENGINEER_INITARMORCLASS 0 +#define PC_ENGINEER_WEAPONS WEAP_SPANNER | WEAP_LASER | WEAP_SUPER_SHOTGUN +#define PC_ENGINEER_MAXAMMO_SHOT 50 +#define PC_ENGINEER_MAXAMMO_NAIL 50 +#define PC_ENGINEER_MAXAMMO_CELL 200 // synonymous with metal +#define PC_ENGINEER_MAXAMMO_ROCKET 30 +#define PC_ENGINEER_INITAMMO_SHOT 20 +#define PC_ENGINEER_INITAMMO_NAIL 25 +#define PC_ENGINEER_INITAMMO_CELL 100 // synonymous with metal +#define PC_ENGINEER_INITAMMO_ROCKET 0 +#define PC_ENGINEER_GRENADE_TYPE_1 GR_TYPE_NORMAL +#define PC_ENGINEER_GRENADE_TYPE_2 GR_TYPE_EMP +#define PC_ENGINEER_GRENADE_INIT_1 2 +#define PC_ENGINEER_GRENADE_INIT_2 2 +#define PC_ENGINEER_TF_ITEMS 0 + +// Class Details for CIVILIAN +#define PC_CIVILIAN_SKIN 22 +#define PC_CIVILIAN_MAXHEALTH 50 +#define PC_CIVILIAN_MAXSPEED 240 +#define PC_CIVILIAN_MAXSTRAFESPEED 240 +#define PC_CIVILIAN_MAXARMOR 0 +#define PC_CIVILIAN_INITARMOR 0 +#define PC_CIVILIAN_MAXARMORTYPE 0 +#define PC_CIVILIAN_INITARMORTYPE 0 +#define PC_CIVILIAN_ARMORCLASSES 0 +#define PC_CIVILIAN_INITARMORCLASS 0 +#define PC_CIVILIAN_WEAPONS WEAP_AXE +#define PC_CIVILIAN_MAXAMMO_SHOT 0 +#define PC_CIVILIAN_MAXAMMO_NAIL 0 +#define PC_CIVILIAN_MAXAMMO_CELL 0 +#define PC_CIVILIAN_MAXAMMO_ROCKET 0 +#define PC_CIVILIAN_INITAMMO_SHOT 0 +#define PC_CIVILIAN_INITAMMO_NAIL 0 +#define PC_CIVILIAN_INITAMMO_CELL 0 +#define PC_CIVILIAN_INITAMMO_ROCKET 0 +#define PC_CIVILIAN_GRENADE_TYPE_1 0 +#define PC_CIVILIAN_GRENADE_TYPE_2 0 +#define PC_CIVILIAN_GRENADE_INIT_1 0 +#define PC_CIVILIAN_GRENADE_INIT_2 0 +#define PC_CIVILIAN_TF_ITEMS 0 + + +/*==========================================================================*/ +/* TEAMFORTRESS GOALS */ +/*==========================================================================*/ +// For all these defines, see the tfortmap.txt that came with the zip +// for complete descriptions. +// Defines for Goal Activation types : goal_activation (in goals) +#define TFGA_TOUCH 1 // Activated when touched +#define TFGA_TOUCH_DETPACK 2 // Activated when touched by a detpack explosion +#define TFGA_REVERSE_AP 4 // Activated when AP details are _not_ met +#define TFGA_SPANNER 8 // Activated when hit by an engineer's spanner +#define TFGA_DROPTOGROUND 2048 // Drop to Ground when spawning + +// Defines for Goal Effects types : goal_effect +#define TFGE_AP 1 // AP is affected. Default. +#define TFGE_AP_TEAM 2 // All of the AP's team. +#define TFGE_NOT_AP_TEAM 4 // All except AP's team. +#define TFGE_NOT_AP 8 // All except AP. +#define TFGE_WALL 16 // If set, walls stop the Radius effects +#define TFGE_SAME_ENVIRONMENT 32 // If set, players in a different environment to the Goal are not affected +#define TFGE_TIMER_CHECK_AP 64 // If set, Timer Goals check their critera for all players fitting their effects + +// Defines for Goal Result types : goal_result +#define TFGR_SINGLE 1 // Goal can only be activated once +#define TFGR_ADD_BONUSES 2 // Any Goals activated by this one give their bonuses +#define TFGR_ENDGAME 4 // Goal fires Intermission, displays scores, and ends level +#define TFGR_NO_ITEM_RESULTS 8 // GoalItems given by this Goal don't do results +#define TFGR_REMOVE_DISGUISE 16 // Prevent/Remove undercover from any Spy +#define TFGR_FORCE_RESPAWN 32 // Forces the player to teleport to a respawn point +#define TFGR_DESTROY_BUILDINGS 64 // Destroys this player's buildings, if anys + +// Defines for Goal Group Result types : goal_group +// None! +// But I'm leaving this variable in there, since it's fairly likely +// that some will show up sometime. + +// Defines for Goal Item types, : goal_activation (in items) +#define TFGI_GLOW 1 // Players carrying this GoalItem will glow +#define TFGI_SLOW 2 // Players carrying this GoalItem will move at half-speed +#define TFGI_DROP 4 // Players dying with this item will drop it +#define TFGI_RETURN_DROP 8 // Return if a player with it dies +#define TFGI_RETURN_GOAL 16 // Return if a player with it has it removed by a goal's activation +#define TFGI_RETURN_REMOVE 32 // Return if it is removed by TFGI_REMOVE +#define TFGI_REVERSE_AP 64 // Only pickup if the player _doesn't_ match AP Details +#define TFGI_REMOVE 128 // Remove if left untouched for 2 minutes after being dropped +#define TFGI_KEEP 256 // Players keep this item even when they die +#define TFGI_ITEMGLOWS 512 // Item glows when on the ground +#define TFGI_DONTREMOVERES 1024 // Don't remove results when the item is removed +#define TFGI_DROPTOGROUND 2048 // Drop To Ground when spawning +#define TFGI_CANBEDROPPED 4096 // Can be voluntarily dropped by players +#define TFGI_SOLID 8192 // Is solid... blocks bullets, etc + +// Defines for methods of GoalItem returning +#define GI_RET_DROP_DEAD 0 // Dropped by a dead player +#define GI_RET_DROP_LIVING 1 // Dropped by a living player +#define GI_RET_GOAL 2 // Returned by a Goal +#define GI_RET_TIME 3 // Returned due to timeout + +// Defines for TeamSpawnpoints : goal_activation (in teamspawns) +#define TFSP_MULTIPLEITEMS 1 // Give out the GoalItem multiple times +#define TFSP_MULTIPLEMSGS 2 // Display the message multiple times + +// Defines for TeamSpawnpoints : goal_effects (in teamspawns) +#define TFSP_REMOVESELF 1 // Remove itself after being spawned on + +// Defines for Goal States +#define TFGS_ACTIVE 1 +#define TFGS_INACTIVE 2 +#define TFGS_REMOVED 3 +#define TFGS_DELAYED 4 + +// Defines for GoalItem Removing from Player Methods +#define GI_DROP_PLAYERDEATH 0 // Dropped by a dying player +#define GI_DROP_REMOVEGOAL 1 // Removed by a Goal +#define GI_DROP_PLAYERDROP 2 // Dropped by a player + +// Legal Playerclass Handling +#define TF_ILL_SCOUT 1 +#define TF_ILL_SNIPER 2 +#define TF_ILL_SOLDIER 4 +#define TF_ILL_DEMOMAN 8 +#define TF_ILL_MEDIC 16 +#define TF_ILL_HVYWEP 32 +#define TF_ILL_PYRO 64 +#define TF_ILL_RANDOMPC 128 +#define TF_ILL_SPY 256 +#define TF_ILL_ENGINEER 512 + +// Addition classes +#define CLASS_TFGOAL 128 +#define CLASS_TFGOAL_TIMER 129 +#define CLASS_TFGOAL_ITEM 130 +#define CLASS_TFSPAWN 131 + +/*==========================================================================*/ +/* Flamethrower */ +/*==========================================================================*/ +#define FLAME_PLYRMAXTIME 4.5 // lifetime in seconds of a flame on a player +#define FLAME_MAXBURNTIME 8 // lifetime in seconds of a flame on the world (big ones) +#define NAPALM_MAXBURNTIME 20 // lifetime in seconds of flame from a napalm grenade +#define FLAME_MAXPLYRFLAMES 4 // maximum number of flames on a player +#define FLAME_NUMLIGHTS 1 // maximum number of light flame +#define FLAME_BURNRATIO 0.3 // the chance of a flame not 'sticking' +#define GR_TYPE_FLAMES_NO 15 // number of flames spawned when a grenade explode +#define FLAME_DAMAGE_TIME 1 // Interval between damage burns from flames +#define FLAME_EFFECT_TIME 0.2 // frequency at which we display flame effects. +#define FLAME_THINK_TIME 0.1 // Seconds between times the flame checks burn + +/*==================================================*/ +/* CTF Support defines */ +/*==================================================*/ +#define CTF_FLAG1 1 +#define CTF_FLAG2 2 +#define CTF_DROPOFF1 3 +#define CTF_DROPOFF2 4 +#define CTF_SCORE1 5 +#define CTF_SCORE2 6 + +//.float hook_out; + +/*==================================================*/ +/* Camera defines */ +/*==================================================*/ +/* +float live_camera; +.float camdist; +.vector camangle; +.entity camera_list; +*/ + +/*==================================================*/ +/* QuakeWorld defines */ +/*==================================================*/ +/* +float already_chosen_map; + +// grappling hook variables +.entity hook; +.float on_hook; +.float fire_held_down;// flag - TRUE if player is still holding down the + // fire button after throwing a hook. +*/ +/*==================================================*/ +/* Server Settings */ +/*==================================================*/ +// Admin modes +#define ADMIN_MODE_NONE 0 +#define ADMIN_MODE_DEAL 1 + +/*==================================================*/ +/* Death Message defines */ +/*==================================================*/ +#define DMSG_SHOTGUN 1 +#define DMSG_SSHOTGUN 2 +#define DMSG_NAILGUN 3 +#define DMSG_SNAILGUN 4 +#define DMSG_GRENADEL 5 +#define DMSG_ROCKETL 6 +#define DMSG_LIGHTNING 7 +#define DMSG_GREN_HAND 8 +#define DMSG_GREN_NAIL 9 +#define DMSG_GREN_MIRV 10 +#define DMSG_GREN_PIPE 11 +#define DMSG_DETPACK 12 +#define DMSG_BIOWEAPON 13 +#define DMSG_BIOWEAPON_ATT 14 +#define DMSG_FLAME 15 +#define DMSG_DETPACK_DIS 16 +#define DMSG_AXE 17 +#define DMSG_SNIPERRIFLE 18 +#define DMSG_AUTORIFLE 19 +#define DMSG_ASSAULTCANNON 20 +#define DMSG_HOOK 21 +#define DMSG_BACKSTAB 22 +#define DMSG_MEDIKIT 23 +#define DMSG_GREN_GAS 24 +#define DMSG_TRANQ 25 +#define DMSG_LASERBOLT 26 +#define DMSG_SENTRYGUN_BULLET 27 +#define DMSG_SNIPERLEGSHOT 28 +#define DMSG_SNIPERHEADSHOT 29 +#define DMSG_GREN_EMP 30 +#define DMSG_GREN_EMP_AMMO 31 +#define DMSG_SPANNER 32 +#define DMSG_INCENDIARY 33 +#define DMSG_SENTRYGUN_ROCKET 34 +#define DMSG_GREN_FLASH 35 +#define DMSG_TRIGGER 36 +#define DMSG_MIRROR 37 +#define DMSG_SENTRYDEATH 38 +#define DMSG_DISPENSERDEATH 39 +#define DMSG_GREN_AIRPIPE 40 +#define DMSG_CALTROP 41 + +/*==================================================*/ +// TOGGLEFLAGS +/*==================================================*/ +// Some of the toggleflags aren't used anymore, but the bits are still +// there to provide compatability with old maps +#define TFLAG_CLASS_PERSIST (1 << 0) // Persistent Classes Bit +#define TFLAG_CHEATCHECK (1 << 1) // Cheatchecking Bit +#define TFLAG_RESPAWNDELAY (1 << 2) // RespawnDelay bit +//#define TFLAG_UN (1 << 3) // NOT USED ANYMORE +#define TFLAG_OLD_GRENS (1 << 3) // Use old concussion grenade and flash grenade +#define TFLAG_UN2 (1 << 4) // NOT USED ANYMORE +#define TFLAG_UN3 (1 << 5) // NOT USED ANYMORE +#define TFLAG_UN4 (1 << 6) // NOT USED ANYMORE: Was Autoteam. CVAR tfc_autoteam used now. +#define TFLAG_TEAMFRAGS (1 << 7) // Individual Frags, or Frags = TeamScore +#define TFLAG_FIRSTENTRY (1 << 8) // Used to determine the first time toggleflags is set + // In a map. Cannot be toggled by players. +#define TFLAG_SPYINVIS (1 << 9) // Spy invisible only +#define TFLAG_GRAPPLE (1 << 10) // Grapple on/off +//#define TFLAG_FULLTEAMSCORE (1 << 11) // Each Team's score is TeamScore + Frags +#define TFLAG_FLAGEMULATION (1 << 12) // Flag emulation on for old TF maps +#define TFLAG_USE_STANDARD (1 << 13) // Use the TF War standard for Flag emulation + +#define TFLAG_FRAGSCORING (1 << 14) // Use frag scoring only + +/*======================*/ +// Menu stuff // +/*======================*/ + +#define MENU_DEFAULT 1 +#define MENU_TEAM 2 +#define MENU_CLASS 3 +#define MENU_MAPBRIEFING 4 +#define MENU_INTRO 5 +#define MENU_CLASSHELP 6 +#define MENU_CLASSHELP2 7 +#define MENU_REPEATHELP 8 + + + +#define MENU_SPY 12 +#define MENU_SPY_SKIN 13 +#define MENU_SPY_COLOR 14 +#define MENU_ENGINEER 15 +#define MENU_ENGINEER_FIX_DISPENSER 16 +#define MENU_ENGINEER_FIX_SENTRYGUN 17 +#define MENU_ENGINEER_FIX_MORTAR 18 +#define MENU_DISPENSER 19 +#define MENU_CLASS_CHANGE 20 +#define MENU_TEAM_CHANGE 21 + +#define MENU_REFRESH_RATE 25 + +//============================ +// Timer Types +#define TF_TIMER_ANY 0 +#define TF_TIMER_CONCUSSION 1 +#define TF_TIMER_INFECTION 2 +#define TF_TIMER_HALLUCINATION 3 +#define TF_TIMER_TRANQUILISATION 4 +#define TF_TIMER_ROTHEALTH 5 +#define TF_TIMER_REGENERATION 6 +#define TF_TIMER_GRENPRIME 7 +#define TF_TIMER_CELLREGENERATION 8 +#define TF_TIMER_DETPACKSET 9 +#define TF_TIMER_DETPACKDISARM 10 +#define TF_TIMER_BUILD 11 +#define TF_TIMER_CHECKBUILDDISTANCE 12 +#define TF_TIMER_DISGUISE 13 + +// Non Player timers +#define TF_TIMER_RETURNITEM 100 +#define TF_TIMER_DELAYEDGOAL 101 + +//============================ +// Teamscore printing +#define TS_PRINT_SHORT 1 +#define TS_PRINT_LONG 2 +#define TS_PRINT_LONG_TO_ALL 3 + +#ifndef TF_DEFS_ONLY +/*==================================================*/ +/* GLOBAL VARIABLES */ +/*==================================================*/ +// FortressMap stuff +extern float number_of_teams; // number of teams supported by the map +extern int illegalclasses[5]; // Illegal playerclasses for all teams +extern int civilianteams; // Bitfield holding Civilian teams +extern Vector rgbcolors[5]; // RGB colors for each of the 4 teams +extern int teamcolors[5]; // Colours for each of the 4 teams +extern int teamscores[5]; // Goal Score of each team +extern int g_iOrderedTeams[5]; // Teams ordered into order of winners->losers +extern int teamfrags[5]; // Total Frags for each team +extern int teamlives[5]; // Number of lives each team's players have +extern int teammaxplayers[5]; // Max number of players allowed in each team +extern float teamadvantage[5]; // only used if the teamplay equalisation bits are set + // stores the damage ratio players take/give +extern int teamallies[5]; // Keeps track of which teams are allied +extern string_t team_names[5]; + +extern BOOL CTF_Map; +extern BOOL birthday; +extern BOOL christmas; + +extern float num_world_flames; + +// Clan Battle stuff +extern float clan_scores_dumped; +extern float cb_prematch_time; +extern float fOldPrematch; +extern float fOldCeaseFire; +extern float cb_ceasefire_time; +extern float last_id; +extern float spy_off; +extern float old_grens; +extern float flagem_checked; +extern float flNextEqualisationCalc; +extern BOOL cease_fire; +extern BOOL initial_cease_fire; +extern BOOL last_cease_fire; +// Autokick stuff +extern float autokick_kills; + +extern float deathmsg; // Global, which is set before every T_Damage, to indicate + // the death message that should be used. + +extern char *sTeamSpawnNames[]; +extern char *sClassNames[]; +extern char *sClassModelFiles[]; +extern char *sClassModels[]; +extern char *sClassCfgs[]; +extern char *sGrenadeNames[]; +extern string_t team_menu_string; + +extern int toggleflags; // toggleable flags + +extern CBaseEntity* g_pLastSpawns[5]; +extern BOOL g_bFirstClient; + +extern float g_fNextPrematchAlert; + +typedef struct +{ + int ip; + edict_t *pEdict; +} ip_storage_t; + +extern ip_storage_t g_IpStorage[32]; + +class CGhost; +/*==========================================================================*/ +BOOL ClassIsRestricted(float tno, int pc); +char* GetTeamName(int tno); +int TeamFortress_GetNoPlayers(); +void DestroyBuilding(CBaseEntity *eng, char *bld); +void teamsprint( int tno, CBaseEntity *ignore, int msg_dest, const char *st, const char *param1 = NULL, const char *param2 = NULL, const char *param3 = NULL ); +float anglemod( float v ); + +// Team Funcs +BOOL TeamFortress_TeamIsCivilian(float tno); +void TeamFortress_TeamShowScores(BOOL bLong, CBasePlayer *pPlayer); +BOOL TeamFortress_TeamPutPlayerInTeam(); +void TeamFortress_TeamSetColor(int tno); +void TeamFortress_TeamIncreaseScore(int tno, int scoretoadd); +int TeamFortress_TeamGetScoreFrags(int tno); +int TeamFortress_TeamGetNoPlayers(int tno); +float TeamEqualiseDamage(CBaseEntity *targ, CBaseEntity *attacker, float damage); +BOOL IsSpawnPointValid( Vector &pos ); +BOOL TeamFortress_SortTeams( void ); +void DumpClanScores( void ); +void CalculateTeamEqualiser(); + +// mapscript funcs +void ParseTFServerSettings(); +void ParseTFMapSettings(); +CBaseEntity* Finditem(int ino); +CBaseEntity* Findgoal(int gno); +CBaseEntity* Findteamspawn(int gno); +void RemoveGoal(CBaseEntity *Goal); +void tfgoalitem_GiveToPlayer(CBaseEntity *Item, CBasePlayer *AP, CBaseEntity *Goal); +void dremove( CBaseEntity *te ); +void tfgoalitem_RemoveFromPlayer(CBaseEntity *Item, CBasePlayer *AP, int iMethod); +void tfgoalitem_drop(CBaseEntity *Item, BOOL PAlive, CBasePlayer *P); +void DisplayItemStatus(CBaseEntity *Goal, CBasePlayer *Player, CBaseEntity *Item); +void tfgoalitem_checkgoalreturn(CBaseEntity *Item); +void DoGoalWork(CBaseEntity *Goal, CBasePlayer *AP); +void DoResults(CBaseEntity *Goal, CBasePlayer *AP, BOOL bAddBonuses); +void DoGroupWork(CBaseEntity *Goal, CBasePlayer *AP); +// hooks into the mapscript for all entities +BOOL ActivateDoResults(CBaseEntity *Goal, CBasePlayer *AP, CBaseEntity *ActivatingGoal); +BOOL ActivationSucceeded(CBaseEntity *Goal, CBasePlayer *AP, CBaseEntity *ActivatingGoal); + +// prematch & ceasefire +void Display_Prematch(); +void Check_Ceasefire(); + +// admin +void KickPlayer( CBaseEntity *pTarget ); +void BanPlayer( CBaseEntity *pTarget ); +CGhost *FindGhost( int iGhostID ); +int GetBattleID( edict_t *pEntity ); + +extern cvar_t tfc_spam_penalty1;// the initial gag penalty for a spammer (seconds) +extern cvar_t tfc_spam_penalty2;// incremental gag penalty (seconds) for each time gagged spammer continues to speak. +extern cvar_t tfc_spam_limit; // at this many points, gag the spammer +extern cvar_t tfc_clanbattle, tfc_clanbattle_prematch, tfc_prematch, tfc_clanbattle_ceasefire, tfc_balance_teams, tfc_balance_scores; +extern cvar_t tfc_clanbattle_locked, tfc_birthday, tfc_autokick_kills, tfc_fragscoring, tfc_autokick_time, tfc_adminpwd; +extern cvar_t weaponstay, footsteps, flashlight, aimcrosshair, falldamage, teamplay; + +/*==========================================================================*/ +class CTFFlame : public CBaseMonster +{ +public: + void Spawn( void ); + void Precache( void ); + void EXPORT FlameThink( void ); + static CTFFlame *FlameSpawn( CBaseEntity *pOwner, CBaseEntity *pTarget ); + void FlameDestroy( void ); + + float m_flNextDamageTime; +}; + +/*==========================================================================*/ +// MAPSCRIPT CLASSES +class CTFGoal : public CBaseAnimating +{ +public: + void Spawn( void ); + void StartGoal( void ); + void EXPORT PlaceGoal( void ); + void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); + int Classify ( void ) { return CLASS_TFGOAL; } + + void SetObjectCollisionBox( void ); +}; + +class CTFGoalItem : public CTFGoal +{ +public: + void Spawn( void ); + void StartItem( void ); + void EXPORT PlaceItem( void ); + int Classify ( void ) { return CLASS_TFGOAL_ITEM; } + + float m_flDroppedAt; +}; + +class CTFTimerGoal : public CTFGoal +{ +public: + void Spawn( void ); + int Classify ( void ) { return CLASS_TFGOAL_TIMER; } +}; + +class CTFSpawn : public CBaseEntity +{ +public: + void Spawn( void ); + int Classify ( void ) { return CLASS_TFSPAWN; } +}; + +class CTFDetect : public CBaseEntity +{ +public: + void Spawn( void ); + int Classify ( void ) { return CLASS_TFGOAL; } +}; + +class CTelefragDeath : public CBaseEntity +{ +public: + void Spawn( void ); + void EXPORT DeathTouch( CBaseEntity *pOther ); +}; + +#endif // TF_DEFS_ONLY +#endif // __TF_DEFS_H + + diff --git a/cl_dll/train.cpp b/cl_dll/train.cpp index 6cbe340..1258286 100644 --- a/cl_dll/train.cpp +++ b/cl_dll/train.cpp @@ -19,7 +19,7 @@ // #include "hud.h" -#include "util.h" +#include "cl_util.h" #include #include #include "parsemsg.h" diff --git a/cl_dll/tri.cpp b/cl_dll/tri.cpp new file mode 100644 index 0000000..99a975d --- /dev/null +++ b/cl_dll/tri.cpp @@ -0,0 +1,115 @@ +// Triangle rendering, if any + +#include "hud.h" +#include "cl_util.h" + +// Triangle rendering apis are in gEngfuncs.pTriAPI + +#include "const.h" +#include "entity_state.h" +#include "cl_entity.h" +#include "triangleapi.h" + +#define DLLEXPORT __declspec( dllexport ) + +extern "C" +{ + void DLLEXPORT HUD_DrawNormalTriangles( void ); + void DLLEXPORT HUD_DrawTransparentTriangles( void ); +}; + +//#define TEST_IT +#if defined( TEST_IT ) + +/* +================= +Draw_Triangles + +Example routine. Draws a sprite offset from the player origin. +================= +*/ +void Draw_Triangles( void ) +{ + cl_entity_t *player; + vec3_t org; + + // Load it up with some bogus data + player = gEngfuncs.GetLocalPlayer(); + if ( !player ) + return; + + org = player->origin; + + org.x += 50; + org.y += 50; + + if (gHUD.m_hsprCursor == 0) + { + char sz[256]; + sprintf( sz, "sprites/cursor.spr" ); + gHUD.m_hsprCursor = SPR_Load( sz ); + } + + if ( !gEngfuncs.pTriAPI->SpriteTexture( (struct model_s *)gEngfuncs.GetSpritePointer( gHUD.m_hsprCursor ), 0 )) + { + return; + } + + // Create a triangle, sigh + gEngfuncs.pTriAPI->RenderMode( kRenderNormal ); + gEngfuncs.pTriAPI->CullFace( TRI_NONE ); + gEngfuncs.pTriAPI->Begin( TRI_QUADS ); + // Overload p->color with index into tracer palette, p->packedColor with brightness + gEngfuncs.pTriAPI->Color4f( 1.0, 1.0, 1.0, 1.0 ); + // UNDONE: This gouraud shading causes tracers to disappear on some cards (permedia2) + gEngfuncs.pTriAPI->Brightness( 1 ); + gEngfuncs.pTriAPI->TexCoord2f( 0, 0 ); + gEngfuncs.pTriAPI->Vertex3f( org.x, org.y, org.z ); + + gEngfuncs.pTriAPI->Brightness( 1 ); + gEngfuncs.pTriAPI->TexCoord2f( 0, 1 ); + gEngfuncs.pTriAPI->Vertex3f( org.x, org.y + 50, org.z ); + + gEngfuncs.pTriAPI->Brightness( 1 ); + gEngfuncs.pTriAPI->TexCoord2f( 1, 1 ); + gEngfuncs.pTriAPI->Vertex3f( org.x + 50, org.y + 50, org.z ); + + gEngfuncs.pTriAPI->Brightness( 1 ); + gEngfuncs.pTriAPI->TexCoord2f( 1, 0 ); + gEngfuncs.pTriAPI->Vertex3f( org.x + 50, org.y, org.z ); + + gEngfuncs.pTriAPI->End(); + gEngfuncs.pTriAPI->RenderMode( kRenderNormal ); +} + +#endif + +/* +================= +HUD_DrawNormalTriangles + +Non-transparent triangles-- add them here +================= +*/ +void DLLEXPORT HUD_DrawNormalTriangles( void ) +{ + +#if defined( TEST_IT ) +// Draw_Triangles(); +#endif +} + +/* +================= +HUD_DrawTransparentTriangles + +Render any triangles with transparent rendermode needs here +================= +*/ +void DLLEXPORT HUD_DrawTransparentTriangles( void ) +{ + +#if defined( TEST_IT ) +// Draw_Triangles(); +#endif +} \ No newline at end of file diff --git a/cl_dll/util.cpp b/cl_dll/util.cpp index 41e080b..9bbbd78 100644 --- a/cl_dll/util.cpp +++ b/cl_dll/util.cpp @@ -23,10 +23,98 @@ #include "MATH.H" #include "hud.h" -#include "util.h" +#include "cl_util.h" #include +#ifndef M_PI +#define M_PI 3.14159265358979323846 // matches value in gcc v2 math.h +#endif +vec3_t vec3_origin( 0, 0, 0 ); + +double sqrt(double x); + +float Length(const float *v) +{ + int i; + float length; + + length = 0; + for (i=0 ; i< 3 ; i++) + length += v[i]*v[i]; + length = sqrt (length); // FIXME + + return length; +} + +void VectorAngles( const float *forward, float *angles ) +{ + float tmp, yaw, pitch; + + if (forward[1] == 0 && forward[0] == 0) + { + yaw = 0; + if (forward[2] > 0) + pitch = 90; + else + pitch = 270; + } + else + { + yaw = (atan2(forward[1], forward[0]) * 180 / M_PI); + if (yaw < 0) + yaw += 360; + + tmp = sqrt (forward[0]*forward[0] + forward[1]*forward[1]); + pitch = (atan2(forward[2], tmp) * 180 / M_PI); + if (pitch < 0) + pitch += 360; + } + + angles[0] = pitch; + angles[1] = yaw; + angles[2] = 0; +} + +float VectorNormalize (float *v) +{ + float length, ilength; + + length = v[0]*v[0] + v[1]*v[1] + v[2]*v[2]; + length = sqrt (length); // FIXME + + if (length) + { + ilength = 1/length; + v[0] *= ilength; + v[1] *= ilength; + v[2] *= ilength; + } + + return length; + +} + +void VectorInverse ( float *v ) +{ + v[0] = -v[0]; + v[1] = -v[1]; + v[2] = -v[2]; +} + +void VectorScale (const float *in, float scale, float *out) +{ + out[0] = in[0]*scale; + out[1] = in[1]*scale; + out[2] = in[2]*scale; +} + +void VectorMA (const float *veca, float scale, const float *vecb, float *vecc) +{ + vecc[0] = veca[0] + scale*vecb[0]; + vecc[1] = veca[1] + scale*vecb[1]; + vecc[2] = veca[2] + scale*vecb[2]; +} HSPRITE LoadSprite(const char *pszName) { diff --git a/cl_dll/vgui_ClassMenu.cpp b/cl_dll/vgui_ClassMenu.cpp new file mode 100644 index 0000000..0c1ca7a --- /dev/null +++ b/cl_dll/vgui_ClassMenu.cpp @@ -0,0 +1,426 @@ +//=========== (C) Copyright 1999 Valve, L.L.C. All rights reserved. =========== +// +// The copyright to the contents herein is the property of Valve, L.L.C. +// The contents may be used and/or copied only with the written permission of +// Valve, L.L.C., or in accordance with the terms and conditions stipulated in +// the agreement/contract under which the contents have been supplied. +// +// Purpose: TFC Class Menu +// +// $Workfile: $ +// $Date: $ +// +//----------------------------------------------------------------------------- +// $Log: $ +// +// $NoKeywords: $ +//============================================================================= + +#include "VGUI_Font.h" +#include + +#include "hud.h" +#include "cl_util.h" +#include "camera.h" +#include "kbutton.h" +#include "cvardef.h" +#include "usercmd.h" +#include "const.h" +#include "camera.h" +#include "in_defs.h" +#include "parsemsg.h" + +#include "vgui_int.h" +#include "vgui_TeamFortressViewport.h" +#include "vgui_ServerBrowser.h" + +// Class Menu Dimensions +#define CLASSMENU_TITLE_X XRES(40) +#define CLASSMENU_TITLE_Y YRES(32) +#define CLASSMENU_TOPLEFT_BUTTON_X XRES(40) +#define CLASSMENU_TOPLEFT_BUTTON_Y YRES(80) +#define CLASSMENU_BUTTON_SIZE_X XRES(124) +#define CLASSMENU_BUTTON_SIZE_Y YRES(24) +#define CLASSMENU_BUTTON_SPACER_Y YRES(8) +#define CLASSMENU_WINDOW_X XRES(176) +#define CLASSMENU_WINDOW_Y YRES(80) +#define CLASSMENU_WINDOW_SIZE_X XRES(424) +#define CLASSMENU_WINDOW_SIZE_Y YRES(312) +#define CLASSMENU_WINDOW_TEXT_X XRES(150) +#define CLASSMENU_WINDOW_TEXT_Y YRES(80) +#define CLASSMENU_WINDOW_NAME_X XRES(150) +#define CLASSMENU_WINDOW_NAME_Y YRES(8) +#define CLASSMENU_WINDOW_PLAYERS_Y YRES(42) + +// Creation +CClassMenuPanel::CClassMenuPanel(int iTrans, int iRemoveMe, int x,int y,int wide,int tall) : CMenuPanel(iTrans, iRemoveMe, x,y,wide,tall) +{ + // don't show class graphics at below 640x480 resolution + bool bShowClassGraphic = true; + if ( ScreenWidth < 640 ) + { + bShowClassGraphic = false; + } + + memset( m_pClassImages, 0, sizeof(m_pClassImages) ); + + // Get the scheme used for the Titles + CSchemeManager *pSchemes = gViewPort->GetSchemeManager(); + + // schemes + SchemeHandle_t hTitleScheme = pSchemes->getSchemeHandle( "Title Font" ); + SchemeHandle_t hClassWindowText = pSchemes->getSchemeHandle( "Briefing Text" ); + + // color schemes + int r, g, b, a; + + // Create the title + Label *pLabel = new Label( "", CLASSMENU_TITLE_X, CLASSMENU_TITLE_Y ); + pLabel->setParent( this ); + pLabel->setFont( pSchemes->getFont(hTitleScheme) ); + pSchemes->getFgColor( hTitleScheme, r, g, b, a ); + pLabel->setFgColor( r, g, b, a ); + pSchemes->getBgColor( hTitleScheme, r, g, b, a ); + pLabel->setBgColor( r, g, b, a ); + pLabel->setContentAlignment( vgui::Label::a_west ); + pLabel->setText(gHUD.m_TextMessage.BufferedLocaliseTextString("#Title_SelectYourClass")); + + // Create the Scroll panel + m_pScrollPanel = new CTFScrollPanel( CLASSMENU_WINDOW_X, CLASSMENU_WINDOW_Y, CLASSMENU_WINDOW_SIZE_X, CLASSMENU_WINDOW_SIZE_Y ); + m_pScrollPanel->setParent(this); + //force the scrollbars on, so after the validate clientClip will be smaller + m_pScrollPanel->setScrollBarAutoVisible(false, false); + m_pScrollPanel->setScrollBarVisible(true, true); + m_pScrollPanel->setBorder( new LineBorder( Color(255 * 0.7,170 * 0.7,0,0) ) ); + m_pScrollPanel->validate(); + + int clientWide=m_pScrollPanel->getClient()->getWide(); + + //turn scrollpanel back into auto show scrollbar mode and validate + m_pScrollPanel->setScrollBarAutoVisible(false,true); + m_pScrollPanel->setScrollBarVisible(false,false); + m_pScrollPanel->validate(); + + // Create the Class buttons + for (int i = 0; i <= PC_RANDOM; i++) + { + char sz[256]; + int iYPos = CLASSMENU_TOPLEFT_BUTTON_Y + ( (CLASSMENU_BUTTON_SIZE_Y + CLASSMENU_BUTTON_SPACER_Y) * i ); + + ActionSignal *pASignal = new CMenuHandler_StringCommandClassSelect( sTFClassSelection[i], true ); + + // Class button + sprintf(sz, "%s", CHudTextMessage::BufferedLocaliseTextString( sLocalisedClasses[i] ) ); + m_pButtons[i] = new ClassButton( i, sz, CLASSMENU_TOPLEFT_BUTTON_X, iYPos, CLASSMENU_BUTTON_SIZE_X, CLASSMENU_BUTTON_SIZE_Y, true); + // RandomPC uses '0' + if ( i >= 1 && i <= 9 ) + { + sprintf(sz,"%d",i); + } + else + { + sprintf(sz,"0"); + } + m_pButtons[i]->setBoundKey( sz[0] ); + m_pButtons[i]->setContentAlignment( vgui::Label::a_west ); + m_pButtons[i]->addActionSignal( pASignal ); + m_pButtons[i]->addInputSignal( new CHandler_MenuButtonOver(this, i) ); + m_pButtons[i]->setParent( this ); + + // Create the Class Info Window + //m_pClassInfoPanel[i] = new CTransparentPanel( 255, CLASSMENU_WINDOW_X, CLASSMENU_WINDOW_Y, CLASSMENU_WINDOW_SIZE_X, CLASSMENU_WINDOW_SIZE_Y ); + m_pClassInfoPanel[i] = new CTransparentPanel( 255, 0, 0, clientWide, CLASSMENU_WINDOW_SIZE_Y ); + m_pClassInfoPanel[i]->setParent( m_pScrollPanel->getClient() ); + //m_pClassInfoPanel[i]->setVisible( false ); + + // don't show class pic in lower resolutions + int textOffs = XRES(8); + + if ( bShowClassGraphic ) + { + textOffs = CLASSMENU_WINDOW_NAME_X; + } + + // Create the Class Name Label + sprintf(sz, "#Title_%s", sTFClassSelection[i]); + char* localName=CHudTextMessage::BufferedLocaliseTextString( sz ); + Label *pNameLabel = new Label( "", textOffs, CLASSMENU_WINDOW_NAME_Y ); + pNameLabel->setFont( pSchemes->getFont(hTitleScheme) ); + pNameLabel->setParent( m_pClassInfoPanel[i] ); + pSchemes->getFgColor( hTitleScheme, r, g, b, a ); + pNameLabel->setFgColor( r, g, b, a ); + pSchemes->getBgColor( hTitleScheme, r, g, b, a ); + pNameLabel->setBgColor( r, g, b, a ); + pNameLabel->setContentAlignment( vgui::Label::a_west ); + //pNameLabel->setBorder(new LineBorder()); + pNameLabel->setText(localName); + + // Create the Class Image + if ( bShowClassGraphic ) + { + for ( int team = 0; team < 2; team++ ) + { + if ( team == 1 ) + { + sprintf( sz, "%sred", sTFClassSelection[i] ); + } + else + { + sprintf( sz, "%sblue", sTFClassSelection[i] ); + } + + m_pClassImages[team][i] = new CImageLabel( sz, 0, 0, CLASSMENU_WINDOW_TEXT_X, CLASSMENU_WINDOW_TEXT_Y ); + + CImageLabel *pLabel = m_pClassImages[team][i]; + pLabel->setParent( m_pClassInfoPanel[i] ); + //pLabel->setBorder(new LineBorder()); + + if ( team != 1 ) + { + pLabel->setVisible( false ); + } + + // Reposition it based upon it's size + int xOut, yOut; + pNameLabel->getTextSize( xOut, yOut ); + pLabel->setPos( (CLASSMENU_WINDOW_TEXT_X - pLabel->getWide()) / 2, yOut /2 ); + } + } + + // Create the Player count string + gHUD.m_TextMessage.LocaliseTextString( "#Title_CurrentlyOnYourTeam", m_sPlayersOnTeamString, STRLENMAX_PLAYERSONTEAM ); + m_pPlayers[i] = new Label( "", textOffs, CLASSMENU_WINDOW_PLAYERS_Y ); + m_pPlayers[i]->setParent( m_pClassInfoPanel[i] ); + m_pPlayers[i]->setBgColor( 0, 0, 0, 255 ); + m_pPlayers[i]->setContentAlignment( vgui::Label::a_west ); + m_pPlayers[i]->setFont( pSchemes->getFont(hClassWindowText) ); + + // Open up the Class Briefing File + sprintf(sz, "classes/short_%s.txt", sTFClassSelection[i]); + char *cText = "Class Description not available."; + char *pfile = (char*)gEngfuncs.COM_LoadFile( sz, 5, NULL ); + if (pfile) + cText = pfile; + + // Create the Text info window + TextPanel *pTextWindow = new TextPanel(cText, textOffs, CLASSMENU_WINDOW_TEXT_Y, (CLASSMENU_WINDOW_SIZE_X - textOffs)-5, CLASSMENU_WINDOW_SIZE_Y - CLASSMENU_WINDOW_TEXT_Y); + pTextWindow->setParent( m_pClassInfoPanel[i] ); + pTextWindow->setFont( pSchemes->getFont(hClassWindowText) ); + pSchemes->getFgColor( hClassWindowText, r, g, b, a ); + pTextWindow->setFgColor( r, g, b, a ); + pSchemes->getBgColor( hClassWindowText, r, g, b, a ); + pTextWindow->setBgColor( r, g, b, a ); + + // Resize the Info panel to fit it all + int wide,tall; + pTextWindow->getTextImage()->getTextSizeWrapped( wide,tall); + pTextWindow->setSize(wide,tall); + //pTextWindow->setBorder(new LineBorder()); + int xx,yy; + pTextWindow->getPos(xx,yy); + int maxX=xx+wide; + int maxY=yy+tall; + + //check to see if the image goes lower than the text + //just use the red teams [0] images + if(m_pClassImages[0][i]!=null) + { + m_pClassImages[0][i]->getPos(xx,yy); + if((yy+m_pClassImages[0][i]->getTall())>maxY) + { + maxY=yy+m_pClassImages[0][i]->getTall(); + } + } + + m_pClassInfoPanel[i]->setSize( maxX , maxY ); + //m_pClassInfoPanel[i]->setBorder(new LineBorder()); + + } + + // Create the Cancel button + m_pCancelButton = new CommandButton( gHUD.m_TextMessage.BufferedLocaliseTextString( "#Menu_Cancel" ), CLASSMENU_TOPLEFT_BUTTON_X, 0, CLASSMENU_BUTTON_SIZE_X, CLASSMENU_BUTTON_SIZE_Y); + m_pCancelButton->setParent( this ); + m_pCancelButton->addActionSignal( new CMenuHandler_TextWindow(HIDE_TEXTWINDOW) ); + + m_iCurrentInfo = 0; + +} + + +// Update +void CClassMenuPanel::Update() +{ + // Don't allow the player to join a team if they're not in a team + if (!g_iTeamNumber) + return; + + int iYPos = CLASSMENU_TOPLEFT_BUTTON_Y; + + // Cycle through the rest of the buttons + for (int i = 0; i <= PC_RANDOM; i++) + { + bool bCivilian = (gViewPort->GetValidClasses(g_iTeamNumber) == -1); + + if ( bCivilian ) + { + // If this team can only be civilians, only the civilian button's visible + if (i == 0) + { + m_pButtons[0]->setVisible( true ); + SetActiveInfo( 0 ); + iYPos += CLASSMENU_BUTTON_SIZE_Y + CLASSMENU_BUTTON_SPACER_Y; + } + else + { + m_pButtons[i]->setVisible( false ); + } + } + else + { + if ( m_pButtons[i]->IsNotValid() || i == 0 ) + { + m_pButtons[i]->setVisible( false ); + } + else + { + m_pButtons[i]->setVisible( true ); + m_pButtons[i]->setPos( CLASSMENU_TOPLEFT_BUTTON_X, iYPos ); + iYPos += CLASSMENU_BUTTON_SIZE_Y + CLASSMENU_BUTTON_SPACER_Y; + + // Start with the first option up + if (!m_iCurrentInfo) + SetActiveInfo( i ); + } + } + + // Now count the number of teammembers of this class + int iTotal = 0; + for ( int j = 1; j < MAX_PLAYERS; j++ ) + { + if ( g_PlayerInfoList[j].name == NULL ) + continue; // empty player slot, skip + if ( g_PlayerExtraInfo[j].teamname[0] == 0 ) + continue; // skip over players who are not in a team + if ( g_PlayerInfoList[j].thisplayer ) + continue; // skip this player + if ( g_PlayerExtraInfo[j].teamnumber != g_iTeamNumber ) + continue; // skip over players in other teams + + // If this team is forced to be civilians, just count the number of teammates + if ( g_PlayerExtraInfo[j].playerclass != i && !bCivilian ) + continue; + + iTotal++; + } + + char sz[256]; + sprintf(sz, m_sPlayersOnTeamString, iTotal); + m_pPlayers[i]->setText( sz ); + + // Set the text color to the teamcolor + m_pPlayers[i]->setFgColor( iTeamColors[g_iTeamNumber][0], iTeamColors[g_iTeamNumber][1], iTeamColors[g_iTeamNumber][2], 0 ); + + // set the graphic to be the team pick + for ( int team = 0; team < MAX_TEAMS; team++ ) + { + // unset all the other images + if ( m_pClassImages[team][i] ) + { + m_pClassImages[team][i]->setVisible( false ); + } + + // set the current team image + if ( m_pClassImages[g_iTeamNumber-1][i] != NULL ) + { + m_pClassImages[g_iTeamNumber-1][i]->setVisible( true ); + } + else if ( m_pClassImages[0][i] ) + { + m_pClassImages[0][i]->setVisible( true ); + } + } + } + + // If the player already has a class, make the cancel button visible + if ( g_iPlayerClass ) + { + m_pCancelButton->setPos( CLASSMENU_TOPLEFT_BUTTON_X, iYPos ); + m_pCancelButton->setVisible( true ); + } + else + { + m_pCancelButton->setVisible( false ); + } +} + +//====================================== +// Key inputs for the Class Menu +bool CClassMenuPanel::SlotInput( int iSlot ) +{ + if ( (iSlot < 0) || (iSlot > 9) ) + return false; + if ( !m_pButtons[ iSlot ] ) + return false; + + // Is the button pushable? (0 is special case) + if (iSlot == 0) + { + // Selects Civilian and RandomPC + if ( gViewPort->GetValidClasses(g_iTeamNumber) == -1 ) + { + m_pButtons[ 0 ]->fireActionSignal(); + return true; + } + + // Select RandomPC + iSlot = 10; + } + + if ( !(m_pButtons[ iSlot ]->IsNotValid()) ) + { + m_pButtons[ iSlot ]->fireActionSignal(); + return true; + } + + return false; +} + +//====================================== +// Update the Class menu before opening it +void CClassMenuPanel::Open( void ) +{ + Update(); + CMenuPanel::Open(); +} + +//----------------------------------------------------------------------------- +// Purpose: Called each time a new level is started. +//----------------------------------------------------------------------------- +void CClassMenuPanel::Initialize( void ) +{ + setVisible( false ); + m_pScrollPanel->setScrollValue( 0, 0 ); +} + +//====================================== +// Mouse is over a class button, bring up the class info +void CClassMenuPanel::SetActiveInfo( int iInput ) +{ + // Remove all the Info panels and bring up the specified one + for (int i = 0; i <= PC_RANDOM; i++) + { + m_pButtons[i]->setArmed( false ); + m_pClassInfoPanel[i]->setVisible( false ); + } + + if ( iInput > PC_RANDOM || iInput < 0 ) + iInput = 0; + + m_pButtons[iInput]->setArmed( true ); + m_pClassInfoPanel[iInput]->setVisible( true ); + m_iCurrentInfo = iInput; + + m_pScrollPanel->setScrollValue(0,0); + m_pScrollPanel->validate(); +} + diff --git a/cl_dll/vgui_ConsolePanel.cpp b/cl_dll/vgui_ConsolePanel.cpp new file mode 100644 index 0000000..bb8f9cf --- /dev/null +++ b/cl_dll/vgui_ConsolePanel.cpp @@ -0,0 +1,95 @@ + +#include"vgui_ConsolePanel.h" +#include"hud.h" +#include +#include +#include +#include +#include + +using namespace vgui; + + +namespace +{ + +class Handler : public ActionSignal +{ +private: + + ConsolePanel* _consolePanel; + +public: + + Handler(ConsolePanel* consolePanel) + { + _consolePanel=consolePanel; + } + +public: + + virtual void actionPerformed(Panel* panel) + { + _consolePanel->doExecCommand(); + } + +}; + +} + + + +ConsolePanel::ConsolePanel(int x,int y,int wide,int tall) : Panel(x,y,wide,tall) +{ + setBorder(new EtchedBorder()); + + _textGrid=new TextGrid(80,21,5,5,200,100); + _textGrid->setBorder(new LoweredBorder()); + _textGrid->setParent(this); + + _textEntry=new TextEntry("",5,5,200,20); + _textEntry->setParent(this); + _textEntry->addActionSignal(new Handler(this)); +} + +int ConsolePanel::print(const char* text) +{ + return _textGrid->printf("%s",text); +} + +int ConsolePanel::vprintf(const char* format,va_list argList) +{ + return _textGrid->vprintf(format,argList); +} + +int ConsolePanel::printf(const char* format,...) +{ + va_list argList; + va_start(argList,format); + int ret=vprintf(format,argList); + va_end(argList); + return ret; +} + +void ConsolePanel::doExecCommand() +{ + char buf[2048]; + _textEntry->getText(0,buf,2048); + _textEntry->setText(null,0); + gEngfuncs.pfnClientCmd(buf); +} + +void ConsolePanel::setSize(int wide,int tall) +{ + Panel::setSize(wide,tall); + + getPaintSize(wide,tall); + + _textGrid->setBounds(5,5,wide-10,tall-35); + _textEntry->setBounds(5,tall-25,wide-10,20); +} + + + + + diff --git a/cl_dll/vgui_ConsolePanel.h b/cl_dll/vgui_ConsolePanel.h new file mode 100644 index 0000000..8edfc03 --- /dev/null +++ b/cl_dll/vgui_ConsolePanel.h @@ -0,0 +1,32 @@ + +#ifndef CONSOLEPANEL_H +#define CONSOLEPANEL_H + +#include +#include + +namespace vgui +{ +class TextGrid; +class TextEntry; +} + + +class ConsolePanel : public vgui::Panel +{ +private: + vgui::TextGrid* _textGrid; + vgui::TextEntry* _textEntry; +public: + ConsolePanel(int x,int y,int wide,int tall); +public: + virtual void setSize(int wide,int tall); + virtual int print(const char* text); + virtual int vprintf(const char* format,va_list argList); + virtual int printf(const char* format,...); + virtual void doExecCommand(); +}; + + + +#endif \ No newline at end of file diff --git a/cl_dll/vgui_ControlConfigPanel.cpp b/cl_dll/vgui_ControlConfigPanel.cpp new file mode 100644 index 0000000..2abe1fb --- /dev/null +++ b/cl_dll/vgui_ControlConfigPanel.cpp @@ -0,0 +1,206 @@ + +#include +#include"vgui_ControlConfigPanel.h" +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace vgui; + +namespace +{ +class FooTablePanel : public TablePanel +{ +private: + Label* _label; + TextEntry* _textEntry; + ControlConfigPanel* _controlConfigPanel; +public: + FooTablePanel(ControlConfigPanel* controlConfigPanel,int x,int y,int wide,int tall,int columnCount) : TablePanel(x,y,wide,tall,columnCount) + { + _controlConfigPanel=controlConfigPanel; + _label=new Label("You are a dumb monkey",0,0,100,20); + _label->setBgColor(Scheme::sc_primary3); + _label->setFgColor(Scheme::sc_primary1); + _label->setFont(Scheme::sf_primary3); + + _textEntry=new TextEntry("",0,0,100,20); + //_textEntry->setFont(Scheme::sf_primary3); + } +public: + virtual int getRowCount() + { + return _controlConfigPanel->GetCVarCount(); + } + virtual int getCellTall(int row) + { + return 12; + } + virtual Panel* getCellRenderer(int column,int row,bool columnSelected,bool rowSelected,bool cellSelected) + { + char cvar[128],desc[128],bind[128],bindAlt[128]; + _controlConfigPanel->GetCVar(row,cvar,128,desc,128); + + if(cellSelected) + { + _label->setBgColor(Scheme::sc_primary1); + _label->setFgColor(Scheme::sc_primary3); + } + else + if(rowSelected) + { + _label->setBgColor(Scheme::sc_primary2); + _label->setFgColor(Scheme::sc_primary1); + } + else + { + _label->setBgColor(Scheme::sc_primary3); + _label->setFgColor(Scheme::sc_primary1); + } + + switch(column) + { + case 0: + { + _label->setText(desc); + _label->setContentAlignment(Label::a_west); + break; + } + case 1: + { + _controlConfigPanel->GetCVarBind(cvar,bind,128,bindAlt,128); + _label->setText(bind); + _label->setContentAlignment(Label::a_center); + break; + } + case 2: + { + _controlConfigPanel->GetCVarBind(cvar,bind,128,bindAlt,128); + _label->setText(bindAlt); + _label->setContentAlignment(Label::a_center); + break; + } + default: + { + _label->setText(""); + break; + } + } + + return _label; + } + virtual Panel* startCellEditing(int column,int row) + { + _textEntry->setText("Goat",strlen("Goat")); + _textEntry->requestFocus(); + return _textEntry; + } +}; +} + +ControlConfigPanel::ControlConfigPanel(int x,int y,int wide,int tall) : Panel(x,y,wide,tall) +{ + setPaintBorderEnabled(false); + setPaintBackgroundEnabled(false); + setPaintEnabled(false); + + _actionLabel=new Label("Action"); + _actionLabel->setBgColor(Scheme::sc_primary3); + _actionLabel->setFgColor(Scheme::sc_primary3); + + _keyButtonLabel=new Label("Key / Button"); + _keyButtonLabel->setBgColor(Scheme::sc_primary3); + _keyButtonLabel->setFgColor(Scheme::sc_primary3); + + _alternateLabel=new Label("Alternate"); + _alternateLabel->setBgColor(Scheme::sc_primary3); + _alternateLabel->setFgColor(Scheme::sc_primary3); + + _headerPanel=new HeaderPanel(0,0,wide,20); + _headerPanel->setParent(this); + + _headerPanel->addSectionPanel(_actionLabel); + _headerPanel->addSectionPanel(_keyButtonLabel); + _headerPanel->addSectionPanel(_alternateLabel); + + _headerPanel->setSliderPos( 0, wide/2 ); + _headerPanel->setSliderPos( 1, (wide/2) + (wide/4) ); + _headerPanel->setSliderPos( 2, wide ); + + _scrollPanel=new ScrollPanel(0,20,wide,tall-20); + _scrollPanel->setParent(this); + _scrollPanel->setPaintBorderEnabled(false); + _scrollPanel->setPaintBackgroundEnabled(false); + _scrollPanel->setPaintEnabled(false); + _scrollPanel->getClient()->setPaintBorderEnabled(false); + _scrollPanel->getClient()->setPaintBackgroundEnabled(false); + _scrollPanel->getClient()->setPaintEnabled(false); + _scrollPanel->setScrollBarVisible(false,true); + + _tablePanel=new FooTablePanel(this,0,0,_scrollPanel->getClient()->getWide(),800, 3); + _tablePanel->setParent(_scrollPanel->getClient()); + _tablePanel->setHeaderPanel(_headerPanel); + _tablePanel->setBgColor(Color(200,0,0,255)); + _tablePanel->setFgColor(Color(Scheme::sc_primary2)); + _tablePanel->setGridVisible(true,true); + _tablePanel->setGridSize(1,1); +} + +void ControlConfigPanel::AddCVar(const char* cvar,const char* desc) +{ + _cvarDar.addElement(vgui_strdup(cvar)); + _descDar.addElement(vgui_strdup(desc)); +} + +int ControlConfigPanel::GetCVarCount() +{ + return _cvarDar.getCount(); +} + +void ControlConfigPanel::GetCVar(int index,char* cvar,int cvarLen,char* desc,int descLen) +{ + vgui_strcpy(cvar,cvarLen,_cvarDar[index]); + vgui_strcpy(desc,descLen,_descDar[index]); +} + +void ControlConfigPanel::AddCVarFromInputStream(InputStream* is) +{ + if(is==null) + { + return; + } + + DataInputStream dis(is); + + bool success; + + while(1) + { + char buf[256],cvar[128],desc[128]; + dis.readLine(buf,256,success); + if(!success) + { + break; + } + if(sscanf(buf,"\"%[^\"]\" \"%[^\"]\"",cvar,desc)==2) + { + AddCVar(cvar,desc); + } + } +} + +void ControlConfigPanel::GetCVarBind(const char* cvar,char* bind,int bindLen,char* bindAlt,int bindAltLen) +{ + sprintf(bind,"%s : Bind",cvar); + sprintf(bindAlt,"%s : BindAlt",cvar); +} + +void ControlConfigPanel::SetCVarBind(const char* cvar,const char* bind,const char* bindAlt) +{ +} + diff --git a/cl_dll/vgui_ControlConfigPanel.h b/cl_dll/vgui_ControlConfigPanel.h new file mode 100644 index 0000000..9a5a41f --- /dev/null +++ b/cl_dll/vgui_ControlConfigPanel.h @@ -0,0 +1,41 @@ + +#ifndef CONTROLCONFIGPANEL_H +#define CONTROLCONFIGPANEL_H + +#include +#include + +namespace vgui +{ +class HeaderPanel; +class TablePanel; +class ScrollPanel; +class InputStream; +class Label; +} + +class ControlConfigPanel : public vgui::Panel +{ +private: + vgui::HeaderPanel* _headerPanel; + vgui::TablePanel* _tablePanel; + vgui::ScrollPanel* _scrollPanel; + vgui::Dar _cvarDar; + vgui::Dar _descDar; + vgui::Label* _actionLabel; + vgui::Label* _keyButtonLabel; + vgui::Label* _alternateLabel; +public: + ControlConfigPanel(int x,int y,int wide,int tall); +public: + void AddCVar(const char* cvar,const char* desc); + void AddCVarFromInputStream(vgui::InputStream* is); + int GetCVarCount(); + void GetCVar(int index,char* cvar,int cvarLen,char* desc,int descLen); + void GetCVarBind(const char* cvar,char* bind,int bindLen,char* bindAlt,int bindAltLen); + void SetCVarBind(const char* cvar,const char* bind,const char* bindAlt); +}; + + + +#endif \ No newline at end of file diff --git a/cl_dll/vgui_CustomObjects.cpp b/cl_dll/vgui_CustomObjects.cpp new file mode 100644 index 0000000..ce8cfad --- /dev/null +++ b/cl_dll/vgui_CustomObjects.cpp @@ -0,0 +1,441 @@ +//=========== (C) Copyright 1999 Valve, L.L.C. All rights reserved. =========== +// +// The copyright to the contents herein is the property of Valve, L.L.C. +// The contents may be used and/or copied only with the written permission of +// Valve, L.L.C., or in accordance with the terms and conditions stipulated in +// the agreement/contract under which the contents have been supplied. +// +// Purpose: Contains implementation of various VGUI-derived objects +// +// $Workfile: $ +// $Date: $ +// +//----------------------------------------------------------------------------- +// $Log: $ +// +// $NoKeywords: $ +//============================================================================= + +#include "VGUI_Font.h" + +#include "hud.h" +#include "cl_util.h" +#include "camera.h" +#include "kbutton.h" +#include "cvardef.h" +#include "usercmd.h" +#include "const.h" +#include "camera.h" +#include "in_defs.h" +#include "parsemsg.h" + +#include "vgui_int.h" +#include "vgui_TeamFortressViewport.h" +#include "vgui_ServerBrowser.h" + +// Arrow filenames +char *sArrowFilenames[] = +{ + "arrowup", + "arrowdn", + "arrowlt", + "arrowrt", +}; + +//----------------------------------------------------------------------------- +// Purpose: Loads a .tga file and returns a pointer to the VGUI tga object +//----------------------------------------------------------------------------- +BitmapTGA *LoadTGA( const char* pImageName ) +{ + BitmapTGA *pTGA; + + char sz[256]; + sprintf(sz, "%%d_%s", pImageName); + + // Load the Image + FileInputStream* fis = new FileInputStream( GetVGUITGAName(sz), false ); + pTGA = new BitmapTGA(fis,true); + fis->close(); + + return pTGA; +} + +//=========================================================== +// All TFC Hud buttons are derived from this one. +CommandButton::CommandButton( const char* text,int x,int y,int wide,int tall, bool bNoHighlight) : Button("",x,y,wide,tall) +{ + m_iPlayerClass = 0; + m_bNoHighlight = bNoHighlight; + Init(); + setText( text ); +} + +CommandButton::CommandButton( int iPlayerClass, const char* text,int x,int y,int wide,int tall) : Button("",x,y,wide,tall) +{ + m_iPlayerClass = iPlayerClass; + m_bNoHighlight = false; + Init(); + setText( text ); +} + +void CommandButton::Init( void ) +{ + m_pSubMenu = NULL; + m_pSubLabel = NULL; + m_pParentMenu = NULL; + + // Set text color to orange + setFgColor(Scheme::sc_primary1); + + // left align + setContentAlignment( vgui::Label::a_west ); + + // Add the Highlight signal + if (!m_bNoHighlight) + addInputSignal( new CHandler_CommandButtonHighlight(this) ); + + // not bound to any button yet + m_cBoundKey = 0; +} + +//----------------------------------------------------------------------------- +// Purpose: Prepends the button text with the current bound key +// if no bound key, then a clear space ' ' instead +//----------------------------------------------------------------------------- +void CommandButton::RecalculateText( void ) +{ + char szBuf[128]; + + if ( m_cBoundKey != 0 ) + { + sprintf( szBuf, " %c %s", m_cBoundKey, m_sMainText ); + szBuf[MAX_BUTTON_SIZE-1] = 0; + } + else + { + // just draw a space if no key bound + sprintf( szBuf, " %s", m_sMainText ); + szBuf[MAX_BUTTON_SIZE-1] = 0; + } + + Button::setText( szBuf ); +} + +void CommandButton::setText( const char *text ) +{ + strncpy( m_sMainText, text, MAX_BUTTON_SIZE ); + m_sMainText[MAX_BUTTON_SIZE-1] = 0; + + RecalculateText(); +} + +void CommandButton::setBoundKey( char boundKey ) +{ + m_cBoundKey = boundKey; + RecalculateText(); +} + +char CommandButton::getBoundKey( void ) +{ + return m_cBoundKey; +} + +void CommandButton::AddSubMenu( CCommandMenu *pNewMenu ) +{ + m_pSubMenu = pNewMenu; + + // Prevent this button from being pushed + setMouseClickEnabled( MOUSE_LEFT, false ); +} + +void CommandButton::UpdateSubMenus( int iAdjustment ) +{ + if ( m_pSubMenu ) + m_pSubMenu->RecalculatePositions( iAdjustment ); +} + +void CommandButton::paint() +{ + // Make the sub label paint the same as the button + if ( m_pSubLabel ) + { + if ( isSelected() ) + m_pSubLabel->PushDown(); + else + m_pSubLabel->PushUp(); + } + + // draw armed button text in white + if ( isArmed() ) + { + setFgColor( Scheme::sc_secondary2 ); + } + else + { + setFgColor( Scheme::sc_primary1 ); + } + + Button::paint(); +} + +void CommandButton::paintBackground() +{ + if ( isArmed() ) + { + // Orange highlight background + drawSetColor( Scheme::sc_primary2 ); + drawFilledRect(0,0,_size[0],_size[1]); + } + + // Orange Border + drawSetColor( Scheme::sc_secondary1 ); + drawOutlinedRect(0,0,_size[0],_size[1]); +} + +//----------------------------------------------------------------------------- +// Purpose: Highlights the current button, and all it's parent menus +//----------------------------------------------------------------------------- +void CommandButton::cursorEntered( void ) +{ + // unarm all the other buttons in this menu + CCommandMenu *containingMenu = getParentMenu(); + if ( containingMenu ) + { + containingMenu->ClearButtonsOfArmedState(); + + // make all our higher buttons armed + CCommandMenu *pCParent = containingMenu->GetParentMenu(); + if ( pCParent ) + { + CommandButton *pParentButton = pCParent->FindButtonWithSubmenu( containingMenu ); + + pParentButton->cursorEntered(); + } + } + + // arm ourselves + setArmed( true ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CommandButton::cursorExited( void ) +{ + // only clear ourselves if we have do not have a containing menu + // only stay armed if we have a sub menu + // the buttons only unarm themselves when another button is armed instead + if ( !getParentMenu() || !GetSubMenu() ) + { + setArmed( false ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: Returns the command menu that the button is part of, if any +// Output : CCommandMenu * +//----------------------------------------------------------------------------- +CCommandMenu *CommandButton::getParentMenu( void ) +{ + return m_pParentMenu; +} + +//----------------------------------------------------------------------------- +// Purpose: Sets the menu that contains this button +// Input : *pParentMenu - +//----------------------------------------------------------------------------- +void CommandButton::setParentMenu( CCommandMenu *pParentMenu ) +{ + m_pParentMenu = pParentMenu; +} + + +//=========================================================== +int ClassButton::IsNotValid() +{ + // If this is the main ChangeClass button, remove it if the player's only able to be civilians + if ( m_iPlayerClass == -1 ) + { + if (gViewPort->GetValidClasses(g_iTeamNumber) == -1) + return true; + + return false; + } + + // Is it an illegal class? + if ((gViewPort->GetValidClasses(0) & sTFValidClassInts[ m_iPlayerClass ]) || (gViewPort->GetValidClasses(g_iTeamNumber) & sTFValidClassInts[ m_iPlayerClass ])) + return true; + + // Only check current class if they've got autokill on + bool bAutoKill = CVAR_GET_FLOAT( "hud_classautokill" ) != 0; + if ( bAutoKill ) + { + // Is it the player's current class? + if ( (gViewPort->IsRandomPC() && m_iPlayerClass == PC_RANDOM) || (!gViewPort->IsRandomPC() && (m_iPlayerClass == g_iPlayerClass)) ) + return true; + } + + return false; +} + +//=========================================================== +// Button with Class image beneath it +CImageLabel::CImageLabel( const char* pImageName,int x,int y ) : Label( "", x,y ) +{ + setContentFitted(true); + m_pTGA = LoadTGA(pImageName); + setImage( m_pTGA ); +} + +CImageLabel::CImageLabel( const char* pImageName,int x,int y,int wide,int tall ) : Label( "", x,y,wide,tall ) +{ + setContentFitted(true); + m_pTGA = LoadTGA(pImageName); + setImage( m_pTGA ); +} + +//=========================================================== +// Image size +int CImageLabel::getImageWide( void ) +{ + int iXSize, iYSize; + m_pTGA->getSize( iXSize, iYSize ); + return iXSize; +} + +int CImageLabel::getImageTall( void ) +{ + int iXSize, iYSize; + m_pTGA->getSize( iXSize, iYSize ); + return iYSize; +} + +//=========================================================== +// Various overloaded paint functions for Custom VGUI objects +void CCommandMenu::paintBackground() +{ + // Transparent black background + drawSetColor(Scheme::sc_primary3); + drawFilledRect(0,0,_size[0],_size[1]); +} + +//================================================================================= +// CUSTOM SCROLLPANEL +//================================================================================= +CTFScrollButton::CTFScrollButton(int iArrow, const char* text,int x,int y,int wide,int tall) : CommandButton(text,x,y,wide,tall) +{ + // Set text color to orange + setFgColor(Scheme::sc_primary1); + + // Load in the arrow + m_pTGA = LoadTGA( sArrowFilenames[iArrow] ); + setImage( m_pTGA ); + + // Highlight signal + InputSignal *pISignal = new CHandler_CommandButtonHighlight(this); + addInputSignal(pISignal); +} + +void CTFScrollButton::paint( void ) +{ + // draw armed button text in white + if ( isArmed() ) + { + m_pTGA->setColor( Color(255,255,255, 0) ); + } + else + { + m_pTGA->setColor( Color(255,255,255, 128) ); + } + + m_pTGA->doPaint(this); +} + +void CTFScrollButton::paintBackground( void ) +{ +/* + if ( isArmed() ) + { + // Orange highlight background + drawSetColor( Scheme::sc_primary2 ); + drawFilledRect(0,0,_size[0],_size[1]); + } + + // Orange Border + drawSetColor( Scheme::sc_secondary1 ); + drawOutlinedRect(0,0,_size[0]-1,_size[1]); +*/ +} + +void CTFSlider::paintBackground( void ) +{ + int wide,tall,nobx,noby; + getPaintSize(wide,tall); + getNobPos(nobx,noby); + + // Border + drawSetColor( Scheme::sc_secondary1 ); + drawOutlinedRect( 0,0,wide,tall ); + + if( isVertical() ) + { + // Nob Fill + drawSetColor( Scheme::sc_primary2 ); + drawFilledRect( 0,nobx,wide,noby ); + + // Nob Outline + drawSetColor( Scheme::sc_primary1 ); + drawOutlinedRect( 0,nobx,wide,noby ); + } + else + { + // Nob Fill + drawSetColor( Scheme::sc_primary2 ); + drawFilledRect( nobx,0,noby,tall ); + + // Nob Outline + drawSetColor( Scheme::sc_primary1 ); + drawOutlinedRect( nobx,0,noby,tall ); + } +} + +CTFScrollPanel::CTFScrollPanel(int x,int y,int wide,int tall) : ScrollPanel(x,y,wide,tall) +{ + ScrollBar *pScrollBar = getVerticalScrollBar(); + pScrollBar->setButton( new CTFScrollButton( ARROW_UP, "", 0,0,16,16 ), 0 ); + pScrollBar->setButton( new CTFScrollButton( ARROW_DOWN, "", 0,0,16,16 ), 1 ); + pScrollBar->setSlider( new CTFSlider(0,wide-1,wide,(tall-(wide*2))+2,true) ); + pScrollBar->setPaintBorderEnabled(false); + pScrollBar->setPaintBackgroundEnabled(false); + pScrollBar->setPaintEnabled(false); + + pScrollBar = getHorizontalScrollBar(); + pScrollBar->setButton( new CTFScrollButton( ARROW_LEFT, "", 0,0,16,16 ), 0 ); + pScrollBar->setButton( new CTFScrollButton( ARROW_RIGHT, "", 0,0,16,16 ), 1 ); + pScrollBar->setSlider( new CTFSlider(tall,0,wide-(tall*2),tall,false) ); + pScrollBar->setPaintBorderEnabled(false); + pScrollBar->setPaintBackgroundEnabled(false); + pScrollBar->setPaintEnabled(false); +} + + +//================================================================================= +// CUSTOM HANDLERS +//================================================================================= +void CHandler_MenuButtonOver::cursorEntered(Panel *panel) +{ + if ( gViewPort && m_pMenuPanel ) + { + m_pMenuPanel->SetActiveInfo( m_iButton ); + } +} + +void CMenuHandler_StringCommandClassSelect::actionPerformed(Panel* panel) +{ + CMenuHandler_StringCommand::actionPerformed( panel ); + + bool bAutoKill = CVAR_GET_FLOAT( "hud_classautokill" ) != 0; + if ( bAutoKill && g_iPlayerClass != 0 ) + gEngfuncs.pfnClientCmd("kill"); +} + diff --git a/cl_dll/vgui_MOTDWindow.cpp b/cl_dll/vgui_MOTDWindow.cpp new file mode 100644 index 0000000..ef4b606 --- /dev/null +++ b/cl_dll/vgui_MOTDWindow.cpp @@ -0,0 +1,147 @@ +//=========== (C) Copyright 1999 Valve, L.L.C. All rights reserved. =========== +// +// The copyright to the contents herein is the property of Valve, L.L.C. +// The contents may be used and/or copied only with the written permission of +// Valve, L.L.C., or in accordance with the terms and conditions stipulated in +// the agreement/contract under which the contents have been supplied. +// +// Purpose: +// +// $Workfile: $ +// $Date: $ +// +//----------------------------------------------------------------------------- +// $Log: $ +// +// $NoKeywords: $ +//============================================================================= + +#include "VGUI_Font.h" +#include "VGUI_ScrollPanel.h" +#include "VGUI_TextImage.h" + +#include + +#include "hud.h" +#include "cl_util.h" +#include "camera.h" +#include "kbutton.h" +#include "const.h" + +#include "vgui_int.h" +#include "vgui_TeamFortressViewport.h" +#include "vgui_ServerBrowser.h" + +#define MOTD_TITLE_X XRES(16) +#define MOTD_TITLE_Y YRES(16) + +#define MOTD_WINDOW_X XRES(112) +#define MOTD_WINDOW_Y YRES(80) +#define MOTD_WINDOW_SIZE_X XRES(424) +#define MOTD_WINDOW_SIZE_Y YRES(312) + +//----------------------------------------------------------------------------- +// Purpose: Displays the MOTD and basic server information +//----------------------------------------------------------------------------- +class CMessageWindowPanel : public CMenuPanel +{ +public: + CMessageWindowPanel( const char *szMOTD, const char *szTitle, int iShadeFullScreen, int iRemoveMe, int x, int y, int wide, int tall ); + +private: + CTransparentPanel *m_pBackgroundPanel; + +}; + +//----------------------------------------------------------------------------- +// Purpose: Creates a new CMessageWindowPanel +// Output : CMenuPanel - interface to the panel +//----------------------------------------------------------------------------- +CMenuPanel *CMessageWindowPanel_Create( const char *szMOTD, const char *szTitle, int iShadeFullscreen, int iRemoveMe, int x, int y, int wide, int tall ) +{ + return new CMessageWindowPanel( szMOTD, szTitle, iShadeFullscreen, iRemoveMe, x, y, wide, tall ); +} + +//----------------------------------------------------------------------------- +// Purpose: Constructs a message panel +//----------------------------------------------------------------------------- +CMessageWindowPanel::CMessageWindowPanel( const char *szMOTD, const char *szTitle, int iShadeFullscreen, int iRemoveMe, int x, int y, int wide, int tall ) : CMenuPanel( iShadeFullscreen ? 100 : 255, iRemoveMe, x, y, wide, tall ) +{ + // Get the scheme used for the Titles + CSchemeManager *pSchemes = gViewPort->GetSchemeManager(); + + // schemes + SchemeHandle_t hTitleScheme = pSchemes->getSchemeHandle( "Title Font" ); + SchemeHandle_t hMOTDText = pSchemes->getSchemeHandle( "Briefing Text" ); + + // color schemes + int r, g, b, a; + + // Create the window + m_pBackgroundPanel = new CTransparentPanel( iShadeFullscreen ? 255 : 100, MOTD_WINDOW_X, MOTD_WINDOW_Y, MOTD_WINDOW_SIZE_X, MOTD_WINDOW_SIZE_Y ); + m_pBackgroundPanel->setParent( this ); + m_pBackgroundPanel->setBorder( new LineBorder( Color(255 * 0.7,170 * 0.7,0,0)) ); + m_pBackgroundPanel->setVisible( true ); + + int iXSize,iYSize,iXPos,iYPos; + m_pBackgroundPanel->getPos( iXPos,iYPos ); + m_pBackgroundPanel->getSize( iXSize,iYSize ); + + // Create the title + Label *pLabel = new Label( "", iXPos + MOTD_TITLE_X, iYPos + MOTD_TITLE_Y ); + pLabel->setParent( this ); + pLabel->setFont( pSchemes->getFont(hTitleScheme) ); + pLabel->setFont( Scheme::sf_primary1 ); + + pSchemes->getFgColor( hTitleScheme, r, g, b, a ); + pLabel->setFgColor( r, g, b, a ); + pLabel->setFgColor( Scheme::sc_primary1 ); + pSchemes->getBgColor( hTitleScheme, r, g, b, a ); + pLabel->setBgColor( r, g, b, a ); + pLabel->setContentAlignment( vgui::Label::a_west ); + pLabel->setText(szTitle); + + // Create the Scroll panel + ScrollPanel *pScrollPanel = new CTFScrollPanel( iXPos + XRES(16), iYPos + MOTD_TITLE_Y*2 + YRES(16), iXSize - XRES(32), iYSize - (YRES(48) + BUTTON_SIZE_Y*2) ); + pScrollPanel->setParent(this); + //force the scrollbars on so clientClip will take them in account after the validate + pScrollPanel->setScrollBarAutoVisible(false, false); + pScrollPanel->setScrollBarVisible(true, true); + pScrollPanel->validate(); + + // Create the text panel + TextPanel *pText = new TextPanel( "", 0,0, 64,64); + pText->setParent( pScrollPanel->getClient() ); + + // get the font and colors from the scheme + pText->setFont( pSchemes->getFont(hMOTDText) ); + pSchemes->getFgColor( hMOTDText, r, g, b, a ); + pText->setFgColor( r, g, b, a ); + pSchemes->getBgColor( hMOTDText, r, g, b, a ); + pText->setBgColor( r, g, b, a ); + pText->setText(szMOTD); + pText->setSize(pScrollPanel->getClientClip()->getWide()-2, 5000); + + // Get the total size of the MOTD text and resize the text panel + int iScrollSizeX, iScrollSizeY; + pText->getTextImage()->getTextSizeWrapped( iScrollSizeX, iScrollSizeY ); + pText->setSize( iScrollSizeX , iScrollSizeY ); + //pText->setBorder(new LineBorder()); + + //turn the scrollbars back into automode + pScrollPanel->setScrollBarAutoVisible(true, true); + pScrollPanel->setScrollBarVisible(false, false); + + pScrollPanel->validate(); + + CommandButton *pButton = new CommandButton( CHudTextMessage::BufferedLocaliseTextString( "#Menu_OK" ), iXPos + XRES(16), iYPos + iYSize - YRES(16) - BUTTON_SIZE_Y, CMENU_SIZE_X, BUTTON_SIZE_Y); + pButton->addActionSignal(new CMenuHandler_TextWindow(HIDE_TEXTWINDOW)); + pButton->setParent(this); + +} + + + + + + diff --git a/cl_dll/vgui_SchemeManager.cpp b/cl_dll/vgui_SchemeManager.cpp new file mode 100644 index 0000000..0c09b6b --- /dev/null +++ b/cl_dll/vgui_SchemeManager.cpp @@ -0,0 +1,544 @@ +//=========== (C) Copyright 1999 Valve, L.L.C. All rights reserved. =========== +// +// The copyright to the contents herein is the property of Valve, L.L.C. +// The contents may be used and/or copied only with the written permission of +// Valve, L.L.C., or in accordance with the terms and conditions stipulated in +// the agreement/contract under which the contents have been supplied. +// +// Purpose: +// +// $Workfile: $ +// $Date: $ +// +//----------------------------------------------------------------------------- +// $Log: $ +// +// $NoKeywords: $ +//============================================================================= + +#include "hud.h" +#include "vgui_SchemeManager.h" +#include "cvardef.h" + +#include + + +cvar_t *g_CV_BitmapFonts; + + +void Scheme_Init() +{ + g_CV_BitmapFonts = gEngfuncs.pfnRegisterVariable("bitmapfonts", "1", 0); +} + + + +//----------------------------------------------------------------------------- +// Purpose: Scheme managers data container +//----------------------------------------------------------------------------- +class CSchemeManager::CScheme +{ +public: + enum { + SCHEME_NAME_LENGTH = 32, + FONT_NAME_LENGTH = 48, + FONT_FILENAME_LENGTH = 64, + }; + + // name + char schemeName[SCHEME_NAME_LENGTH]; + + // font + char fontName[FONT_NAME_LENGTH]; + + int fontSize; + int fontWeight; + + vgui::Font *font; + int ownFontPointer; // true if the font is ours to delete + + // scheme + byte fgColor[4]; + byte bgColor[4]; + byte armedFgColor[4]; + byte armedBgColor[4]; + byte mousedownFgColor[4]; + byte mousedownBgColor[4]; + byte borderColor[4]; + + // construction/destruction + CScheme(); + ~CScheme(); +}; + +CSchemeManager::CScheme::CScheme() +{ + schemeName[0] = 0; + fontName[0] = 0; + fontSize = 0; + fontWeight = 0; + font = NULL; + ownFontPointer = false; +} + +CSchemeManager::CScheme::~CScheme() +{ + // only delete our font pointer if we own it + if ( ownFontPointer ) + { + delete font; + } +} + +//----------------------------------------------------------------------------- +// Purpose: resolution information +// !! needs to be shared out +//----------------------------------------------------------------------------- +static int g_ResArray[] = +{ + 320, + 400, + 512, + 640, + 800, + 1024, + 1152, + 1280, + 1600 +}; +static int g_NumReses = sizeof(g_ResArray) / sizeof(int); + +static byte *LoadFileByResolution( const char *filePrefix, int xRes, const char *filePostfix ) +{ + // find our resolution in the res array + int resNum = g_NumReses - 1; + while ( g_ResArray[resNum] > xRes ) + { + resNum--; + + if ( resNum < 0 ) + return NULL; + } + + // try open the file + byte *pFile = NULL; + while ( 1 ) + { + + // try load + char fname[256]; + sprintf( fname, "%s%d%s", filePrefix, g_ResArray[resNum], filePostfix ); + pFile = gEngfuncs.COM_LoadFile( fname, 5, NULL ); + + if ( pFile ) + break; + + if ( resNum == 0 ) + return NULL; + + resNum--; + }; + + return pFile; +} + +static void ParseRGBAFromString( byte colorArray[4], const char *colorVector ) +{ + int r, g, b, a; + sscanf( colorVector, "%d %d %d %d", &r, &g, &b, &a ); + colorArray[0] = r; + colorArray[1] = g; + colorArray[2] = b; + colorArray[3] = a; +} + +//----------------------------------------------------------------------------- +// Purpose: initializes the scheme manager +// loading the scheme files for the current resolution +// Input : xRes - +// yRes - dimensions of output window +//----------------------------------------------------------------------------- +CSchemeManager::CSchemeManager( int xRes, int yRes ) +{ + // basic setup + m_pSchemeList = NULL; + m_iNumSchemes = 0; + + // find the closest matching scheme file to our resolution + char token[1024]; + char *pFile = (char*)LoadFileByResolution( "", xRes, "_textscheme.txt" ); + m_xRes = xRes; + + char *pFileStart = pFile; + + byte *pFontData; + int fontFileLength; + char fontFilename[512]; + + // + // Read the scheme descriptions from the text file, into a temporary array + // format is simply: + // = + // + // a of "SchemeName" signals a new scheme is being described + // + + const static int numTmpSchemes = 64; + static CScheme tmpSchemes[numTmpSchemes]; + memset( tmpSchemes, 0, sizeof(tmpSchemes) ); + int currentScheme = -1; + CScheme *pScheme = NULL; + + if ( !pFile ) + { + gEngfuncs.Con_DPrintf( "Unable to find *_textscheme.txt\n"); + goto buildDefaultFont; + } + + // record what has been entered so we can create defaults from the different values + bool hasFgColor, hasBgColor, hasArmedFgColor, hasArmedBgColor, hasMouseDownFgColor, hasMouseDownBgColor; + + pFile = gEngfuncs.COM_ParseFile( pFile, token ); + while ( strlen(token) > 0 && (currentScheme < numTmpSchemes) ) + { + // get the paramName name + static const int tokenSize = 64; + char paramName[tokenSize], paramValue[tokenSize]; + + strncpy( paramName, token, tokenSize ); + paramName[tokenSize-1] = 0; // ensure null termination + + // get the '=' character + pFile = gEngfuncs.COM_ParseFile( pFile, token ); + if ( stricmp( token, "=" ) ) + { + if ( currentScheme < 0 ) + { + gEngfuncs.Con_Printf( "error parsing font scheme text file at file start - expected '=', found '%s''\n", token ); + } + else + { + gEngfuncs.Con_Printf( "error parsing font scheme text file at scheme '%s' - expected '=', found '%s''\n", tmpSchemes[currentScheme].schemeName, token ); + } + break; + } + + // get paramValue + pFile = gEngfuncs.COM_ParseFile( pFile, token ); + strncpy( paramValue, token, tokenSize ); + paramValue[tokenSize-1] = 0; // ensure null termination + + // is this a new scheme? + if ( !stricmp(paramName, "SchemeName") ) + { + // setup the defaults for the current scheme + if ( pScheme ) + { + // foreground color defaults (normal -> armed -> mouse down) + if ( !hasFgColor ) + { + pScheme->fgColor[0] = pScheme->fgColor[1] = pScheme->fgColor[2] = pScheme->fgColor[3] = 255; + } + if ( !hasArmedFgColor ) + { + memcpy( pScheme->armedFgColor, pScheme->fgColor, sizeof(pScheme->armedFgColor) ); + } + if ( !hasMouseDownFgColor ) + { + memcpy( pScheme->mousedownFgColor, pScheme->armedFgColor, sizeof(pScheme->mousedownFgColor) ); + } + + // background color (normal -> armed -> mouse down) + if ( !hasBgColor ) + { + pScheme->bgColor[0] = pScheme->bgColor[1] = pScheme->bgColor[2] = pScheme->bgColor[3] = 0; + } + if ( !hasArmedBgColor ) + { + memcpy( pScheme->armedBgColor, pScheme->bgColor, sizeof(pScheme->armedBgColor) ); + } + if ( !hasMouseDownBgColor ) + { + memcpy( pScheme->mousedownBgColor, pScheme->armedBgColor, sizeof(pScheme->mousedownBgColor) ); + } + + // font size + if ( !pScheme->fontSize ) + { + pScheme->fontSize = 17; + } + if ( !pScheme->fontName[0] ) + { + strcpy( pScheme->fontName, "Arial" ); + } + } + + // create the new scheme + currentScheme++; + pScheme = &tmpSchemes[currentScheme]; + hasFgColor = hasBgColor = hasArmedFgColor = hasArmedBgColor = hasMouseDownFgColor = hasMouseDownBgColor = false; + + strncpy( pScheme->schemeName, paramValue, CScheme::SCHEME_NAME_LENGTH ); + pScheme->schemeName[CScheme::SCHEME_NAME_LENGTH-1] = '\0'; // ensure null termination of string + } + + if ( !pScheme ) + { + gEngfuncs.Con_Printf( "font scheme text file MUST start with a 'SchemeName'\n"); + break; + } + + // pull the data out into the scheme + if ( !stricmp(paramName, "FontName") ) + { + strncpy( pScheme->fontName, paramValue, CScheme::FONT_NAME_LENGTH ); + pScheme->fontName[CScheme::FONT_NAME_LENGTH-1] = 0; + } + else if ( !stricmp(paramName, "FontSize") ) + { + pScheme->fontSize = atoi( paramValue ); + } + else if ( !stricmp(paramName, "FontWeight") ) + { + pScheme->fontWeight = atoi( paramValue ); + } + else if ( !stricmp(paramName, "FgColor") ) + { + ParseRGBAFromString( pScheme->fgColor, paramValue ); + hasFgColor = true; + } + else if ( !stricmp(paramName, "BgColor") ) + { + ParseRGBAFromString( pScheme->bgColor, paramValue ); + hasBgColor = true; + } + else if ( !stricmp(paramName, "FgColorArmed") ) + { + ParseRGBAFromString( pScheme->armedFgColor, paramValue ); + hasArmedFgColor = true; + } + else if ( !stricmp(paramName, "BgColorArmed") ) + { + ParseRGBAFromString( pScheme->armedBgColor, paramValue ); + hasArmedBgColor = true; + } + else if ( !stricmp(paramName, "FgColorMousedown") ) + { + ParseRGBAFromString( pScheme->mousedownFgColor, paramValue ); + hasMouseDownFgColor = true; + } + else if ( !stricmp(paramName, "BgColorMousedown") ) + { + ParseRGBAFromString( pScheme->mousedownBgColor, paramValue ); + hasMouseDownBgColor = true; + } + else if ( !stricmp(paramName, "BorderColor") ) + { + ParseRGBAFromString( pScheme->borderColor, paramValue ); + hasMouseDownBgColor = true; + } + + // get the new token last, so we now if the loop needs to be continued or not + pFile = gEngfuncs.COM_ParseFile( pFile, token ); + } + + // free the file + gEngfuncs.COM_FreeFile( pFileStart ); + + +buildDefaultFont: + + // make sure we have at least 1 valid font + if ( currentScheme < 0 ) + { + currentScheme = 0; + strcpy( tmpSchemes[0].schemeName, "Default Scheme" ); + strcpy( tmpSchemes[0].fontName, "Arial" ); + tmpSchemes[0].fontSize = 0; + tmpSchemes[0].fgColor[0] = tmpSchemes[0].fgColor[1] = tmpSchemes[0].fgColor[2] = tmpSchemes[0].fgColor[3] = 255; + tmpSchemes[0].armedFgColor[0] = tmpSchemes[0].armedFgColor[1] = tmpSchemes[0].armedFgColor[2] = tmpSchemes[0].armedFgColor[3] = 255; + tmpSchemes[0].mousedownFgColor[0] = tmpSchemes[0].mousedownFgColor[1] = tmpSchemes[0].mousedownFgColor[2] = tmpSchemes[0].mousedownFgColor[3] = 255; + } + + // we have the full list of schemes in the tmpSchemes array + // now allocate the correct sized list + m_iNumSchemes = currentScheme + 1; // 0-based index + m_pSchemeList = new CScheme[ m_iNumSchemes ]; + + // copy in the data + memcpy( m_pSchemeList, tmpSchemes, sizeof(CScheme) * m_iNumSchemes ); + + // create the fonts + for ( int i = 0; i < m_iNumSchemes; i++ ) + { + m_pSchemeList[i].font = NULL; + + // see if the current font values exist in a previously loaded font + for ( int j = 0; j < i; j++ ) + { + // check if the font name, size, and weight are the same + if ( !stricmp(m_pSchemeList[i].fontName, m_pSchemeList[j].fontName) + && m_pSchemeList[i].fontSize == m_pSchemeList[j].fontSize + && m_pSchemeList[i].fontWeight == m_pSchemeList[j].fontWeight ) + { + // copy the pointer, but mark i as not owning it + m_pSchemeList[i].font = m_pSchemeList[j].font; + m_pSchemeList[i].ownFontPointer = false; + } + } + + // if we haven't found the font already, load it ourselves + if ( !m_pSchemeList[i].font ) + { + fontFileLength = -1; + pFontData = NULL; + + if(g_CV_BitmapFonts && g_CV_BitmapFonts->value) + { + sprintf(fontFilename, "gfx\\vgui\\fonts\\%d_%s.tga", m_xRes, m_pSchemeList[i].schemeName); + pFontData = gEngfuncs.COM_LoadFile( fontFilename, 5, &fontFileLength ); + if(!pFontData) + gEngfuncs.Con_Printf("Missing bitmap font: %s\n", fontFilename); + } + + m_pSchemeList[i].font = new vgui::Font( + m_pSchemeList[i].fontName, + pFontData, + fontFileLength, + m_pSchemeList[i].fontSize, + 0, + 0, + m_pSchemeList[i].fontWeight, + false, + false, + false, + false); + + m_pSchemeList[i].ownFontPointer = true; + } + + // fix up alpha values; VGUI uses 1-A (A=0 being solid, A=255 transparent) + m_pSchemeList[i].fgColor[3] = 255 - m_pSchemeList[i].fgColor[3]; + m_pSchemeList[i].bgColor[3] = 255 - m_pSchemeList[i].bgColor[3]; + m_pSchemeList[i].armedFgColor[3] = 255 - m_pSchemeList[i].armedFgColor[3]; + m_pSchemeList[i].armedBgColor[3] = 255 - m_pSchemeList[i].armedBgColor[3]; + m_pSchemeList[i].mousedownFgColor[3] = 255 - m_pSchemeList[i].mousedownFgColor[3]; + m_pSchemeList[i].mousedownBgColor[3] = 255 - m_pSchemeList[i].mousedownBgColor[3]; + } +} + +//----------------------------------------------------------------------------- +// Purpose: frees all the memory used by the scheme manager +//----------------------------------------------------------------------------- +CSchemeManager::~CSchemeManager() +{ + delete [] m_pSchemeList; + m_iNumSchemes = 0; +} + +//----------------------------------------------------------------------------- +// Purpose: Finds a scheme in the list, by name +// Input : char *schemeName - string name of the scheme +// Output : SchemeHandle_t handle to the scheme +//----------------------------------------------------------------------------- +SchemeHandle_t CSchemeManager::getSchemeHandle( const char *schemeName ) +{ + // iterate through the list + for ( int i = 0; i < m_iNumSchemes; i++ ) + { + if ( !stricmp(schemeName, m_pSchemeList[i].schemeName) ) + return i; + } + + return 0; +} + +//----------------------------------------------------------------------------- +// Purpose: always returns a valid scheme handle +// Input : schemeHandle - +// Output : CScheme +//----------------------------------------------------------------------------- +CSchemeManager::CScheme *CSchemeManager::getSafeScheme( SchemeHandle_t schemeHandle ) +{ + if ( schemeHandle < m_iNumSchemes ) + return m_pSchemeList + schemeHandle; + + return m_pSchemeList; +} + + +//----------------------------------------------------------------------------- +// Purpose: Returns the schemes pointer to a font +// Input : schemeHandle - +// Output : vgui::Font +//----------------------------------------------------------------------------- +vgui::Font *CSchemeManager::getFont( SchemeHandle_t schemeHandle ) +{ + return getSafeScheme( schemeHandle )->font; +} + +void CSchemeManager::getFgColor( SchemeHandle_t schemeHandle, int &r, int &g, int &b, int &a ) +{ + CScheme *pScheme = getSafeScheme( schemeHandle ); + r = pScheme->fgColor[0]; + g = pScheme->fgColor[1]; + b = pScheme->fgColor[2]; + a = pScheme->fgColor[3]; +} + +void CSchemeManager::getBgColor( SchemeHandle_t schemeHandle, int &r, int &g, int &b, int &a ) +{ + CScheme *pScheme = getSafeScheme( schemeHandle ); + r = pScheme->bgColor[0]; + g = pScheme->bgColor[1]; + b = pScheme->bgColor[2]; + a = pScheme->bgColor[3]; +} + +void CSchemeManager::getFgArmedColor( SchemeHandle_t schemeHandle, int &r, int &g, int &b, int &a ) +{ + CScheme *pScheme = getSafeScheme( schemeHandle ); + r = pScheme->armedFgColor[0]; + g = pScheme->armedFgColor[1]; + b = pScheme->armedFgColor[2]; + a = pScheme->armedFgColor[3]; +} + +void CSchemeManager::getBgArmedColor( SchemeHandle_t schemeHandle, int &r, int &g, int &b, int &a ) +{ + CScheme *pScheme = getSafeScheme( schemeHandle ); + r = pScheme->armedBgColor[0]; + g = pScheme->armedBgColor[1]; + b = pScheme->armedBgColor[2]; + a = pScheme->armedBgColor[3]; +} + +void CSchemeManager::getFgMousedownColor( SchemeHandle_t schemeHandle, int &r, int &g, int &b, int &a ) +{ + CScheme *pScheme = getSafeScheme( schemeHandle ); + r = pScheme->mousedownFgColor[0]; + g = pScheme->mousedownFgColor[1]; + b = pScheme->mousedownFgColor[2]; + a = pScheme->mousedownFgColor[3]; +} + +void CSchemeManager::getBgMousedownColor( SchemeHandle_t schemeHandle, int &r, int &g, int &b, int &a ) +{ + CScheme *pScheme = getSafeScheme( schemeHandle ); + r = pScheme->mousedownBgColor[0]; + g = pScheme->mousedownBgColor[1]; + b = pScheme->mousedownBgColor[2]; + a = pScheme->mousedownBgColor[3]; +} + +void CSchemeManager::getBorderColor( SchemeHandle_t schemeHandle, int &r, int &g, int &b, int &a ) +{ + CScheme *pScheme = getSafeScheme( schemeHandle ); + r = pScheme->borderColor[0]; + g = pScheme->borderColor[1]; + b = pScheme->borderColor[2]; + a = pScheme->borderColor[3]; +} + + + diff --git a/cl_dll/vgui_SchemeManager.h b/cl_dll/vgui_SchemeManager.h new file mode 100644 index 0000000..6be3753 --- /dev/null +++ b/cl_dll/vgui_SchemeManager.h @@ -0,0 +1,47 @@ +#include + + +// handle to an individual scheme +typedef int SchemeHandle_t; + + +// Register console variables, etc.. +void Scheme_Init(); + + +//----------------------------------------------------------------------------- +// Purpose: Handles the loading of text scheme description from disk +// supports different font/color/size schemes at different resolutions +//----------------------------------------------------------------------------- +class CSchemeManager +{ +public: + // initialization + CSchemeManager( int xRes, int yRes ); + virtual ~CSchemeManager(); + + // scheme handling + SchemeHandle_t getSchemeHandle( const char *schemeName ); + + // getting info from schemes + vgui::Font *getFont( SchemeHandle_t schemeHandle ); + void getFgColor( SchemeHandle_t schemeHandle, int &r, int &g, int &b, int &a ); + void getBgColor( SchemeHandle_t schemeHandle, int &r, int &g, int &b, int &a ); + void getFgArmedColor( SchemeHandle_t schemeHandle, int &r, int &g, int &b, int &a ); + void getBgArmedColor( SchemeHandle_t schemeHandle, int &r, int &g, int &b, int &a ); + void getFgMousedownColor( SchemeHandle_t schemeHandle, int &r, int &g, int &b, int &a ); + void getBgMousedownColor( SchemeHandle_t schemeHandle, int &r, int &g, int &b, int &a ); + void getBorderColor( SchemeHandle_t schemeHandle, int &r, int &g, int &b, int &a ); + +private: + class CScheme; + CScheme *m_pSchemeList; + int m_iNumSchemes; + + // Resolution we were initted at. + int m_xRes; + + CScheme *getSafeScheme( SchemeHandle_t schemeHandle ); +}; + + diff --git a/cl_dll/vgui_ScorePanel.cpp b/cl_dll/vgui_ScorePanel.cpp new file mode 100644 index 0000000..d431eb9 --- /dev/null +++ b/cl_dll/vgui_ScorePanel.cpp @@ -0,0 +1,629 @@ +//=========== (C) Copyright 1999 Valve, L.L.C. All rights reserved. =========== +// +// The copyright to the contents herein is the property of Valve, L.L.C. +// The contents may be used and/or copied only with the written permission of +// Valve, L.L.C., or in accordance with the terms and conditions stipulated in +// the agreement/contract under which the contents have been supplied. +// +// Purpose: VGUI scoreboard +// +// $Workfile: $ +// $Date: $ +// +//----------------------------------------------------------------------------- +// $Log: $ +// +// $NoKeywords: $ +//============================================================================= + + +#include + +#include "hud.h" +#include "cl_util.h" +#include "const.h" +#include "entity_state.h" +#include "cl_entity.h" +#include "vgui_TeamFortressViewport.h" +#include "vgui_ScorePanel.h" + +hud_player_info_t g_PlayerInfoList[MAX_PLAYERS+1]; // player info from the engine +extra_player_info_t g_PlayerExtraInfo[MAX_PLAYERS+1]; // additional player info sent directly to the client dll +team_info_t g_TeamInfo[MAX_TEAMS+1]; +int g_IsSpectator[MAX_PLAYERS+1]; + +int HUD_IsGame( const char *game ); +int EV_TFC_IsAllyTeam( int iTeam1, int iTeam2 ); + +// Scoreboard dimensions +#define SBOARD_TITLE_SIZE_Y YRES(24) +#define SBOARD_HEADER_SIZE_Y YRES(40) +#define SBOARD_TABLE_X XRES(16) +#define SBOARD_TABLE_Y (SBOARD_TITLE_SIZE_Y + SBOARD_HEADER_SIZE_Y) + +#define SBOARD_TEAM_CELL_SIZE_Y YRES(20) +#define SBOARD_CELL_SIZE_Y YRES(13) + +// Column sizes +#define CSIZE_NAME XRES(140) +#define CSIZE_CLASS CSIZE_NAME + XRES(64) +#define CSIZE_KILLS CSIZE_CLASS + XRES(60) +#define CSIZE_DEATHS CSIZE_KILLS + XRES(64) + +#define SMALL_CSIZE_NAME XRES(124) +#define SMALL_CSIZE_CLASS SMALL_CSIZE_NAME + XRES(60) +#define SMALL_CSIZE_KILLS SMALL_CSIZE_CLASS + XRES(64) +#define SMALL_CSIZE_DEATHS SMALL_CSIZE_KILLS + XRES(70) + +#define TEAM_NO 0 +#define TEAM_YES 1 +#define TEAM_UNASSIGNED 2 +#define TEAM_SPECTATORS 3 + +// Team Colors used in the scoreboard +int ScoreColorsBG[5][3] = +{ + { 0, 0, 0 }, + { 66, 114, 247 }, + { 220, 51, 38 }, + { 236, 212, 48 }, + { 68, 199, 42 }, +}; + +int ScoreColorsFG[5][3] = +{ + { 255, 255, 255 }, + { 170, 193, 251 }, + { 215, 151, 146 }, + { 227, 203, 46 }, + { 143, 215, 142 }, +}; + +//----------------------------------------------------------------------------- +// Purpose: Set different cell heights for Teams and Players +//----------------------------------------------------------------------------- +int ScoreTablePanel::getCellTall(int row) +{ + if ( m_iIsATeam[row] ) + return SBOARD_TEAM_CELL_SIZE_Y; + + return SBOARD_CELL_SIZE_Y; +} + +//----------------------------------------------------------------------------- +// Purpose: Render each of the cells in the Table +//----------------------------------------------------------------------------- +Panel* ScoreTablePanel::getCellRenderer(int column,int row,bool columnSelected,bool rowSelected,bool cellSelected) +{ + char sz[128]; + hud_player_info_t *pl_info = NULL; + team_info_t *team_info = NULL; + + if ( m_iIsATeam[row] == TEAM_YES ) + { + // Get the team's data + team_info = &g_TeamInfo[ m_iSortedRows[row] ]; + + // White text for team names + m_pLabel->setFgColor(Scheme::sc_white); + + // Set background color + m_pLabel->setBgColor( ScoreColorsBG[ team_info->teamnumber ][0], ScoreColorsBG[ team_info->teamnumber ][1], ScoreColorsBG[ team_info->teamnumber ][2], 128 ); + } + else if ( m_iIsATeam[row] == TEAM_UNASSIGNED || m_iIsATeam[row] == TEAM_SPECTATORS ) + { + // White text for team names + m_pLabel->setFgColor(Scheme::sc_white); + + // Set background color + m_pLabel->setBgColor( 0,0,0, 255 ); + } + else + { + // Grey text for player names + m_pLabel->setFgColor( ScoreColorsFG[ g_PlayerExtraInfo[ m_iSortedRows[row] ].teamnumber ][0], ScoreColorsFG[ g_PlayerExtraInfo[ m_iSortedRows[row] ].teamnumber ][1], ScoreColorsFG[ g_PlayerExtraInfo[ m_iSortedRows[row] ].teamnumber ][2], 128 ); + + // Get the player's data + pl_info = &g_PlayerInfoList[ m_iSortedRows[row] ]; + + // Set background color + if ( pl_info->thisplayer ) // if it is their name, draw it a different color + { + // Highlight this player + m_pLabel->setFgColor(Scheme::sc_white); + m_pLabel->setBgColor( ScoreColorsBG[ g_PlayerExtraInfo[ m_iSortedRows[row] ].teamnumber ][0], ScoreColorsBG[ g_PlayerExtraInfo[ m_iSortedRows[row] ].teamnumber ][1], ScoreColorsBG[ g_PlayerExtraInfo[ m_iSortedRows[row] ].teamnumber ][2], 196 ); + } + else if ( m_iSortedRows[row] == m_iLastKilledBy && m_fLastKillTime && m_fLastKillTime > gHUD.m_flTime ) + { + // Killer's name + m_pLabel->setBgColor( 255,0,0, 255 - ((float)15 * (float)(m_fLastKillTime - gHUD.m_flTime)) ); + } + else + { + m_pLabel->setBgColor( 0,0,0, 255 ); + } + } + + // Align + if (column <= 1) + { + if ( m_iIsATeam[row] ) + m_pLabel->setContentAlignment( vgui::Label::a_southwest ); + else + m_pLabel->setContentAlignment( vgui::Label::a_west ); + } + else + { + if ( m_iIsATeam[row] ) + m_pLabel->setContentAlignment( vgui::Label::a_south ); + else + m_pLabel->setContentAlignment( vgui::Label::a_center ); + } + + // Fill out with the correct data + if ( m_iIsATeam[row] ) + { + int i; + char sz2[128]; + strcpy(sz, ""); + + switch (column) + { + case 0: + if ( m_iIsATeam[row] == TEAM_UNASSIGNED ) + { + sprintf( sz2, CHudTextMessage::BufferedLocaliseTextString( "#Unassigned" ) ); + } + else if ( m_iIsATeam[row] == TEAM_SPECTATORS ) + { + sprintf( sz2, CHudTextMessage::BufferedLocaliseTextString( "#Spectators" ) ); + } + else + { + sprintf( sz2, CHudTextMessage::BufferedLocaliseTextString( team_info->name ) ); + } + + // Uppercase it + for (i = 0; i < (int)strlen(sz2); i++) + { + if ( *(sz2 + i) ) + sz[i] = toupper( *(sz2 + i) ); + } + sz[i] = '\0'; + + // Append the number of players + if ( m_iIsATeam[row] == TEAM_YES ) + { + if (team_info->players == 1) + sprintf(sz, "%s (1 player)", sz ); + else + sprintf(sz, "%s (%d players)", sz, team_info->players ); + } + break; + case 1: + // No class for teams + break; + case 2: + if ( m_iIsATeam[row] == TEAM_YES ) + sprintf(sz, "%d", team_info->frags ); + break; + case 3: + if ( m_iIsATeam[row] == TEAM_YES ) + sprintf(sz, "%d", team_info->deaths ); + break; + case 4: + if ( m_iIsATeam[row] == TEAM_YES ) + sprintf(sz, "%d", team_info->ping ); + break; + default: + break; + } + + m_pLabel->setText(sz); + } + else + { + bool bShowClass = false; + + switch (column) + { + case 0: + sprintf(sz, " %s", pl_info->name); + break; + case 1: + // No class for other team's members (unless allied or spectator) + if ( gViewPort && EV_TFC_IsAllyTeam( g_iTeamNumber, g_PlayerExtraInfo[ m_iSortedRows[row] ].teamnumber ) ) + bShowClass = true; + // Don't show classes if this client hasnt picked a team yet + if ( g_iTeamNumber == 0 ) + bShowClass = false; + if ( g_iUser1 ) + bShowClass = true; + + if (bShowClass) + { + // Only print Civilian if this team are all civilians + bool bNoClass = false; + if ( g_PlayerExtraInfo[ m_iSortedRows[row] ].playerclass == 0 ) + { + if ( gViewPort->GetValidClasses( g_PlayerExtraInfo[ m_iSortedRows[row] ].teamnumber ) != -1 ) + bNoClass = true; + } + + if (bNoClass) + sprintf(sz, ""); + else + sprintf( sz, "%s", CHudTextMessage::BufferedLocaliseTextString( sLocalisedClasses[ g_PlayerExtraInfo[ m_iSortedRows[row] ].playerclass ] ) ); + } + else + { + strcpy(sz, ""); + } + break; + case 2: + sprintf(sz, "%d", g_PlayerExtraInfo[ m_iSortedRows[row] ].frags ); + break; + case 3: + sprintf(sz, "%d", g_PlayerExtraInfo[ m_iSortedRows[row] ].deaths ); + break; + case 4: + sprintf(sz, "%d", g_PlayerInfoList[ m_iSortedRows[row] ].ping ); + break; + default: + strcpy(sz, ""); + } + + m_pLabel->setText(sz); + } + + return m_pLabel; +} + +//----------------------------------------------------------------------------- +// Purpose: Create the ScoreBoard panel +//----------------------------------------------------------------------------- +ScorePanel::ScorePanel(int x,int y,int wide,int tall) : Panel(x,y,wide,tall) +{ + setBorder( new LineBorder( Color(255 * 0.7,170 * 0.7,0,0) ) ); + setBgColor( 0,0,0, 100 ); + + m_pTitleLabel = new Label( " SCORES", 0,0, wide, SBOARD_TITLE_SIZE_Y ); + m_pTitleLabel->setBgColor( Scheme::sc_primary2 ); + m_pTitleLabel->setFgColor( Scheme::sc_primary1 ); + m_pTitleLabel->setContentAlignment( vgui::Label::a_west ); + m_pTitleLabel->setParent(this); + + _headerPanel = new HeaderPanel( SBOARD_TABLE_X, SBOARD_TITLE_SIZE_Y, wide - (SBOARD_TABLE_X * 2), SBOARD_HEADER_SIZE_Y); + _headerPanel->setParent(this); + + // BUGBUG: This isn't working. gHUD.m_Teamplay hasn't been initialized yet. + if ( gHUD.m_Teamplay ) + _headerPanel->addSectionPanel( new CLabelHeader( CHudTextMessage::BufferedLocaliseTextString( "#TEAMS" ), true) ); + else + _headerPanel->addSectionPanel( new CLabelHeader( CHudTextMessage::BufferedLocaliseTextString( "#PLAYERS" ), true) ); + + if ( HUD_IsGame( "tfc" ) ) + _headerPanel->addSectionPanel( new CLabelHeader( CHudTextMessage::BufferedLocaliseTextString( "#CLASS" ), true) ); + else + _headerPanel->addSectionPanel( new CLabelHeader("", true) ); + + _headerPanel->addSectionPanel( new CLabelHeader( CHudTextMessage::BufferedLocaliseTextString( "#SCORE" )) ); + _headerPanel->addSectionPanel( new CLabelHeader( CHudTextMessage::BufferedLocaliseTextString( "#DEATHS")) ); + _headerPanel->addSectionPanel( new CLabelHeader( CHudTextMessage::BufferedLocaliseTextString( "#LATENCY")) ); + _headerPanel->setBgColor( 0,0,0, 255 ); + + // Need to special case 400x300, because the titles just wont fit otherwise + if ( ScreenWidth == 400 ) + { + _headerPanel->setSliderPos( 0, SMALL_CSIZE_NAME ); + _headerPanel->setSliderPos( 1, SMALL_CSIZE_CLASS ); + _headerPanel->setSliderPos( 2, SMALL_CSIZE_KILLS ); + _headerPanel->setSliderPos( 3, SMALL_CSIZE_DEATHS ); + _headerPanel->setSliderPos( 4, wide - (SBOARD_TABLE_X * 2) - 1 ); + } + else + { + _headerPanel->setSliderPos( 0, CSIZE_NAME ); + _headerPanel->setSliderPos( 1, CSIZE_CLASS ); + _headerPanel->setSliderPos( 2, CSIZE_KILLS ); + _headerPanel->setSliderPos( 3, CSIZE_DEATHS ); + _headerPanel->setSliderPos( 4, wide - (SBOARD_TABLE_X * 2) - 1 ); + } + + _tablePanel = new ScoreTablePanel(SBOARD_TABLE_X, SBOARD_TABLE_Y, wide - (SBOARD_TABLE_X * 2), tall - SBOARD_TABLE_Y, NUM_COLUMNS); + _tablePanel->setParent(this); + _tablePanel->setHeaderPanel(_headerPanel); + _tablePanel->setBgColor( 0,0,0, 255 ); + + Initialize(); +} + +//----------------------------------------------------------------------------- +// Purpose: Called each time a new level is started. +//----------------------------------------------------------------------------- +void ScorePanel::Initialize( void ) +{ + // Clear out scoreboard data + _tablePanel->m_iLastKilledBy = 0; + _tablePanel->m_fLastKillTime = 0; + m_iPlayerNum = 0; + m_iNumTeams = 0; + memset( g_PlayerExtraInfo, 0, sizeof g_PlayerExtraInfo ); + memset( g_TeamInfo, 0, sizeof g_TeamInfo ); +} + +//----------------------------------------------------------------------------- +// Purpose: Set the size of the header and table when this panel's size changes +//----------------------------------------------------------------------------- +void ScorePanel::setSize(int wide,int tall) +{ + Panel::setSize(wide,tall); + + _headerPanel->setBounds(0,0,wide,SBOARD_HEADER_SIZE_Y); + _tablePanel->setBounds(0,20,wide,tall - SBOARD_HEADER_SIZE_Y); +} + +//----------------------------------------------------------------------------- +// Purpose: Recalculate the internal scoreboard data +//----------------------------------------------------------------------------- +void ScorePanel::Update() +{ + // Set the title + if (gViewPort->m_szServerName) + { + char sz[MAX_SERVERNAME_LENGTH + 16]; + sprintf(sz, " SCORES: %s", gViewPort->m_szServerName ); + m_pTitleLabel->setText(sz); + } + + _tablePanel->m_iRows = 0; + gViewPort->GetAllPlayersInfo(); + + // Clear out sorts + for (int i = 0; i < MAX_PLAYERS; i++) + { + _tablePanel->m_iSortedRows[i] = 0; + _tablePanel->m_iIsATeam[i] = TEAM_NO; + _tablePanel->m_bHasBeenSorted[i] = false; + } + + // If it's not teamplay, sort all the players. Otherwise, sort the teams. + if ( !gHUD.m_Teamplay ) + SortPlayers( 0, NULL ); + else + SortTeams(); +} + +//----------------------------------------------------------------------------- +// Purpose: Sort all the teams +//----------------------------------------------------------------------------- +void ScorePanel::SortTeams() +{ + // clear out team scores + for ( int i = 1; i <= m_iNumTeams; i++ ) + { + if ( !g_TeamInfo[i].scores_overriden ) + g_TeamInfo[i].frags = g_TeamInfo[i].deaths = 0; + g_TeamInfo[i].ping = g_TeamInfo[i].packetloss = 0; + } + + // recalc the team scores, then draw them + for ( i = 1; i < MAX_PLAYERS; i++ ) + { + if ( g_PlayerInfoList[i].name == NULL ) + continue; // empty player slot, skip + + if ( g_PlayerExtraInfo[i].teamname[0] == 0 ) + continue; // skip over players who are not in a team + + // find what team this player is in + for ( int j = 1; j <= m_iNumTeams; j++ ) + { + if ( !stricmp( g_PlayerExtraInfo[i].teamname, g_TeamInfo[j].name ) ) + break; + } + if ( j > m_iNumTeams ) // player is not in a team, skip to the next guy + continue; + + if ( !g_TeamInfo[j].scores_overriden ) + { + g_TeamInfo[j].frags += g_PlayerExtraInfo[i].frags; + g_TeamInfo[j].deaths += g_PlayerExtraInfo[i].deaths; + } + + g_TeamInfo[j].ping += g_PlayerInfoList[i].ping; + g_TeamInfo[j].packetloss += g_PlayerInfoList[i].packetloss; + + if ( g_PlayerInfoList[i].thisplayer ) + g_TeamInfo[j].ownteam = TRUE; + else + g_TeamInfo[j].ownteam = FALSE; + + // Set the team's number (used for team colors) + g_TeamInfo[j].teamnumber = g_PlayerExtraInfo[i].teamnumber; + } + + // find team ping/packetloss averages + for ( i = 1; i <= m_iNumTeams; i++ ) + { + g_TeamInfo[i].already_drawn = FALSE; + + if ( g_TeamInfo[i].players > 0 ) + { + g_TeamInfo[i].ping /= g_TeamInfo[i].players; // use the average ping of all the players in the team as the teams ping + g_TeamInfo[i].packetloss /= g_TeamInfo[i].players; // use the average ping of all the players in the team as the teams ping + } + } + + // Draw the teams + while ( 1 ) + { + int highest_frags = -99999; int lowest_deaths = 99999; + int best_team = 0; + + for ( i = 1; i <= m_iNumTeams; i++ ) + { + if ( g_TeamInfo[i].players < 1 ) + continue; + + if ( !g_TeamInfo[i].already_drawn && g_TeamInfo[i].frags >= highest_frags ) + { + if ( g_TeamInfo[i].frags > highest_frags || g_TeamInfo[i].deaths < lowest_deaths ) + { + best_team = i; + lowest_deaths = g_TeamInfo[i].deaths; + highest_frags = g_TeamInfo[i].frags; + } + } + } + + // draw the best team on the scoreboard + if ( !best_team ) + break; + + // Put this team in the sorted list + _tablePanel->m_iSortedRows[ _tablePanel->m_iRows ] = best_team; + _tablePanel->m_iIsATeam[ _tablePanel->m_iRows ] = TEAM_YES; + g_TeamInfo[best_team].already_drawn = TRUE; // set the already_drawn to be TRUE, so this team won't get sorted again + _tablePanel->m_iRows++; + + // Now sort all the players on this team + SortPlayers( 0, g_TeamInfo[best_team].name ); + } + + // Now add all the spectators + SortPlayers( TEAM_SPECTATORS, NULL ); + + // Now add all the players who aren't in a team yet + SortPlayers( TEAM_UNASSIGNED, NULL ); +} + +//----------------------------------------------------------------------------- +// Purpose: Sort a list of players +//----------------------------------------------------------------------------- +void ScorePanel::SortPlayers( int iTeam, char *team ) +{ + bool bCreatedTeam = false; + + // draw the players, in order, and restricted to team if set + while ( 1 ) + { + // Find the top ranking player + int highest_frags = -99999; int lowest_deaths = 99999; + int best_player; + best_player = 0; + + for ( int i = 1; i < MAX_PLAYERS; i++ ) + { + if ( _tablePanel->m_bHasBeenSorted[i] == false && g_PlayerInfoList[i].name && g_PlayerExtraInfo[i].frags >= highest_frags ) + { + cl_entity_t *ent = gEngfuncs.GetEntityByIndex( i ); + + if ( ent && ((iTeam == TEAM_SPECTATORS && g_IsSpectator[i] != 0) || (iTeam != TEAM_SPECTATORS && !(team && stricmp(g_PlayerExtraInfo[i].teamname, team)))) ) + { + extra_player_info_t *pl_info = &g_PlayerExtraInfo[i]; + if ( pl_info->frags > highest_frags || pl_info->deaths < lowest_deaths ) + { + best_player = i; + lowest_deaths = pl_info->deaths; + highest_frags = pl_info->frags; + } + } + } + } + + if ( !best_player ) + break; + + // If we haven't created the Team yet, do it first + if (!bCreatedTeam && iTeam) + { + _tablePanel->m_iIsATeam[ _tablePanel->m_iRows ] = iTeam; + _tablePanel->m_iRows++; + + bCreatedTeam = true; + } + + // Put this player in the sorted list + _tablePanel->m_iSortedRows[ _tablePanel->m_iRows ] = best_player; + _tablePanel->m_bHasBeenSorted[ best_player ] = true; + _tablePanel->m_iRows++; + } +} + +//----------------------------------------------------------------------------- +// Purpose: Recalculate the existing teams in the match +//----------------------------------------------------------------------------- +void ScorePanel::RebuildTeams() +{ + // clear out player counts from teams + for ( int i = 1; i <= m_iNumTeams; i++ ) + { + g_TeamInfo[i].players = 0; + } + + // rebuild the team list + gViewPort->GetAllPlayersInfo(); + m_iNumTeams = 0; + for ( i = 1; i < MAX_PLAYERS; i++ ) + { + if ( g_PlayerInfoList[i].name == NULL ) + continue; + + if ( g_PlayerExtraInfo[i].teamname[0] == 0 ) + continue; // skip over players who are not in a team + + // is this player in an existing team? + for ( int j = 1; j <= m_iNumTeams; j++ ) + { + if ( g_TeamInfo[j].name[0] == '\0' ) + break; + + if ( !stricmp( g_PlayerExtraInfo[i].teamname, g_TeamInfo[j].name ) ) + break; + } + + if ( j > m_iNumTeams ) + { // they aren't in a listed team, so make a new one + // search through for an empty team slot + for ( int j = 1; j <= m_iNumTeams; j++ ) + { + if ( g_TeamInfo[j].name[0] == '\0' ) + break; + } + m_iNumTeams = max( j, m_iNumTeams ); + + strncpy( g_TeamInfo[j].name, g_PlayerExtraInfo[i].teamname, MAX_TEAM_NAME ); + g_TeamInfo[j].players = 0; + } + + g_TeamInfo[j].players++; + } + + // clear out any empty teams + for ( i = 1; i <= m_iNumTeams; i++ ) + { + if ( g_TeamInfo[i].players < 1 ) + memset( &g_TeamInfo[i], 0, sizeof(team_info_t) ); + } + + // Update the scoreboard + Update(); +} + +//----------------------------------------------------------------------------- +// Purpose: Setup highlights for player names in scoreboard +//----------------------------------------------------------------------------- +void ScorePanel::DeathMsg( int killer, int victim ) +{ + // if we were the one killed, or the world killed us, set the scoreboard to indicate suicide + if ( victim == m_iPlayerNum || killer == 0 ) + { + _tablePanel->m_iLastKilledBy = killer ? killer : m_iPlayerNum; + _tablePanel->m_fLastKillTime = gHUD.m_flTime + 10; // display who we were killed by for 10 seconds + + if ( killer == m_iPlayerNum ) + _tablePanel->m_iLastKilledBy = m_iPlayerNum; + } +} + diff --git a/cl_dll/vgui_ScorePanel.h b/cl_dll/vgui_ScorePanel.h new file mode 100644 index 0000000..89cb340 --- /dev/null +++ b/cl_dll/vgui_ScorePanel.h @@ -0,0 +1,122 @@ + +#ifndef SCOREPANEL_H +#define SCOREPANEL_H + +#include +#include +#include +#include +#include + +#define MAX_SCORES 10 + +// Scoreboard cells +#define NUM_COLUMNS 5 +#define NUM_ROWS (MAX_PLAYERS + MAX_TEAMS) + +// Scoreboard positions +#define SBOARD_INDENT_X XRES(104) +#define SBOARD_INDENT_Y YRES(40) + +using namespace vgui; + +//----------------------------------------------------------------------------- +// Purpose: Custom label for cells in the Scoreboard's Table Header +//----------------------------------------------------------------------------- +class CLabelHeader : public Label +{ +private: + void Init( void ) + { + setFont( Scheme::sf_primary1 ); + setFgColor( Scheme::sc_primary1 ); + setBgColor( 0,0,0, 255 ); + } +public: + + CLabelHeader(const char* text,int x,int y,int wide,int tall) : Label(text,x,y,wide,tall) + { + Init(); + } + + CLabelHeader(const char* text, bool bAlignLeft = false) : Label(text) + { + Init(); + + if (bAlignLeft) + setContentAlignment(Label::a_west); + } +}; + +//----------------------------------------------------------------------------- +// Purpose: Custom Table for the scoreboard +//----------------------------------------------------------------------------- +class ScoreTablePanel : public TablePanel +{ +private: + TextGrid *_textGrid; + Label *m_pLabel; + +public: + int m_iRows; + int m_iSortedRows[NUM_ROWS]; + int m_iIsATeam[NUM_ROWS]; + bool m_bHasBeenSorted[MAX_PLAYERS]; + int m_iLastKilledBy; + int m_fLastKillTime; + +public: + ScoreTablePanel(int x,int y,int wide,int tall,int columnCount) : TablePanel(x,y,wide,tall,columnCount) + { + setCellEditingEnabled(false); + + m_pLabel = new Label( "", 0, 0, wide, tall ); + m_pLabel->setFont( Scheme::sf_primary2 ); + } + virtual int getRowCount() + { + return m_iRows; + } + virtual Panel* startCellEditing(int column,int row) + { + return null; + } + virtual Panel* getCellRenderer(int column,int row,bool columnSelected,bool rowSelected,bool cellSelected); + virtual int getCellTall(int row); +}; + +//----------------------------------------------------------------------------- +// Purpose: Scoreboard back panel +//----------------------------------------------------------------------------- +class ScorePanel : public Panel +{ +private: + HeaderPanel *_headerPanel; + ScoreTablePanel *_tablePanel; + Label *m_pTitleLabel; + +public: + int m_iNumTeams; + int m_iPlayerNum; + int m_iShowscoresHeld; + +public: + ScorePanel(int x,int y,int wide,int tall); + virtual void setSize(int wide,int tall); + + void Update( void ); + void SortTeams( void ); + void SortPlayers( int iTeam, char *team ); + void RebuildTeams( void ); + void DeathMsg( int killer, int victim ); + + void Initialize( void ); + + void Open( void ) + { + RebuildTeams(); + setVisible(true); + } +}; + +#endif \ No newline at end of file diff --git a/cl_dll/vgui_ServerBrowser.cpp b/cl_dll/vgui_ServerBrowser.cpp new file mode 100644 index 0000000..0db0d4c --- /dev/null +++ b/cl_dll/vgui_ServerBrowser.cpp @@ -0,0 +1,617 @@ + +#include +#include +#include +#include +#include +#include + +#include "hud.h" +#include "cl_util.h" +#include "hud_servers.h" +#include "net_api.h" + +#include "vgui_TeamFortressViewport.h" +#include "vgui_ServerBrowser.h" + +using namespace vgui; + +namespace +{ + +#define MAX_SB_ROWS 24 + +#define NUM_COLUMNS 5 + +#define HEADER_SIZE_Y YRES(18) + +// Column sizes +#define CSIZE_ADDRESS XRES(200) +#define CSIZE_SERVER XRES(400) +#define CSIZE_MAP XRES(500) +#define CSIZE_CURRENT XRES(570) +#define CSIZE_PING XRES(640) + +#define CELL_HEIGHT YRES(15) + +class ServerBrowserTablePanel; + +class CBrowser_InputSignal : public InputSignal +{ +private: + ServerBrowserTablePanel *m_pBrowser; +public: + CBrowser_InputSignal( ServerBrowserTablePanel *pBrowser ) + { + m_pBrowser = pBrowser; + } + + virtual void cursorMoved(int x,int y,Panel* panel) {}; + virtual void cursorEntered(Panel* panel){}; + virtual void cursorExited(Panel* Panel) {}; + + virtual void mousePressed(MouseCode code,Panel* panel); + + virtual void mouseDoublePressed(MouseCode code,Panel* panel); + virtual void mouseReleased(MouseCode code,Panel* panel) {}; + virtual void mouseWheeled(int delta,Panel* panel) {}; + virtual void keyPressed(KeyCode code,Panel* panel) {}; + virtual void keyTyped(KeyCode code,Panel* panel) {}; + virtual void keyReleased(KeyCode code,Panel* panel) {}; + virtual void keyFocusTicked(Panel* panel) {}; +}; + +class ServerBrowserTablePanel : public TablePanel +{ +private: + Label *m_pLabel; + int m_nMouseOverRow; + +public: + + ServerBrowserTablePanel( int x,int y,int wide,int tall,int columnCount) : TablePanel( x,y,wide,tall,columnCount) + { + m_pLabel = new Label( "", 0, 0 /*,wide, tall*/ ); + + m_nMouseOverRow = 0; + } + +public: + void setMouseOverRow( int row ) + { + m_nMouseOverRow = row; + } + + void DoSort( char *sortkey ) + { + // Request server list and refresh servers... + SortServers( sortkey ); + } + + void DoRefresh( void ) + { + // Request server list and refresh servers... + ServersList(); + BroadcastServersList( 0 ); + } + + void DoBroadcastRefresh( void ) + { + // Request server list and refresh servers... + BroadcastServersList( 1 ); + } + + void DoStop( void ) + { + // Stop requesting + ServersCancel(); + } + + void DoCancel( void ) + { + ClientCmd( "togglebrowser\n" ); + } + + void DoConnect( void ) + { + const char *info; + const char *address; + char sz[ 256 ]; + + info = ServersGetInfo( m_nMouseOverRow ); + if ( !info ) + return; + + address = gEngfuncs.pNetAPI->ValueForKey( info, "address" ); + //gEngfuncs.Con_Printf( "Connecting to %s\n", address ); + + sprintf( sz, "connect %s\n", address ); + + ClientCmd( sz ); + + DoCancel(); + } + + void DoPing( void ) + { + ServerPing( 0 ); + ServerRules( 0 ); + ServerPlayers( 0 ); + } + + virtual int getRowCount() + { + int rowcount; + int height, width; + + getSize( width, height ); + + // Space for buttons + height -= YRES(20); + height = max( 0, height ); + + rowcount = height / CELL_HEIGHT; + + return rowcount; + } + + virtual int getCellTall(int row) + { + return CELL_HEIGHT - 2; + } + + virtual Panel* getCellRenderer(int column,int row,bool columnSelected,bool rowSelected,bool cellSelected) + { + const char *info; + const char *val, *val2; + char sz[ 32 ]; + + info = ServersGetInfo( row ); + + if ( row == m_nMouseOverRow ) + { + m_pLabel->setFgColor( 200, 240, 63, 100 ); + } + else + { + m_pLabel->setFgColor( 255, 255, 255, 0 ); + } + m_pLabel->setBgColor( 0, 0, 0, 200 ); + m_pLabel->setContentAlignment( vgui::Label::a_west ); + m_pLabel->setFont( Scheme::sf_primary2 ); + + if ( info ) + { + // Fill out with the correct data + switch ( column ) + { + case 0: + val = gEngfuncs.pNetAPI->ValueForKey( info, "address" ); + if ( val ) + { + strncpy( sz, val, 31 ); + sz[ 31 ] = '\0'; + // Server Name; + m_pLabel->setText( sz ); + } + break; + case 1: + val = gEngfuncs.pNetAPI->ValueForKey( info, "hostname" ); + if ( val ) + { + strncpy( sz, val, 31 ); + sz[ 31 ] = '\0'; + // Server Map; + m_pLabel->setText( sz ); + } + break; + case 2: + val = gEngfuncs.pNetAPI->ValueForKey( info, "map" ); + if ( val ) + { + strncpy( sz, val, 31 ); + sz[ 31 ] = '\0'; + // Server Name; + m_pLabel->setText( sz ); + } + break; + case 3: + val = gEngfuncs.pNetAPI->ValueForKey( info, "current" ); + val2 = gEngfuncs.pNetAPI->ValueForKey( info, "max" ); + if ( val && val2 ) + { + sprintf( sz, "%s/%s", val, val2 ); + sz[ 31 ] = '\0'; + // Server Map; + m_pLabel->setText( sz ); + } + break; + case 4: + val = gEngfuncs.pNetAPI->ValueForKey( info, "ping" ); + if ( val ) + { + strncpy( sz, val, 31 ); + sz[ 31 ] = '\0'; + // Server Name; + m_pLabel->setText( sz ); + } + break; + default: + break; + } + } + else + { + if ( !row && !column ) + { + if ( ServersIsQuerying() ) + { + m_pLabel->setText( "Waiting for servers to respond..." ); + } + else + { + m_pLabel->setText( "Press 'Refresh' to search for servers..." ); + } + } + else + { + m_pLabel->setText( "" ); + } + } + + return m_pLabel; + } + + virtual Panel* startCellEditing(int column,int row) + { + return null; + } + +}; + +class ConnectHandler : public ActionSignal +{ +private: + ServerBrowserTablePanel *m_pBrowser; + +public: + ConnectHandler( ServerBrowserTablePanel *browser ) + { + m_pBrowser = browser; + } + + virtual void actionPerformed( Panel *panel ) + { + m_pBrowser->DoConnect(); + } +}; + +class RefreshHandler : public ActionSignal +{ +private: + ServerBrowserTablePanel *m_pBrowser; + +public: + RefreshHandler( ServerBrowserTablePanel *browser ) + { + m_pBrowser = browser; + } + + virtual void actionPerformed( Panel *panel ) + { + m_pBrowser->DoRefresh(); + } +}; + +class BroadcastRefreshHandler : public ActionSignal +{ +private: + ServerBrowserTablePanel *m_pBrowser; + +public: + BroadcastRefreshHandler( ServerBrowserTablePanel *browser ) + { + m_pBrowser = browser; + } + + virtual void actionPerformed( Panel *panel ) + { + m_pBrowser->DoBroadcastRefresh(); + } +}; + +class StopHandler : public ActionSignal +{ +private: + ServerBrowserTablePanel *m_pBrowser; + +public: + StopHandler( ServerBrowserTablePanel *browser ) + { + m_pBrowser = browser; + } + + virtual void actionPerformed( Panel *panel ) + { + m_pBrowser->DoStop(); + } +}; + +class CancelHandler : public ActionSignal +{ +private: + ServerBrowserTablePanel *m_pBrowser; + +public: + CancelHandler( ServerBrowserTablePanel *browser ) + { + m_pBrowser = browser; + } + + virtual void actionPerformed( Panel *panel ) + { + m_pBrowser->DoCancel(); + } +}; + +class PingHandler : public ActionSignal +{ +private: + ServerBrowserTablePanel *m_pBrowser; + +public: + PingHandler( ServerBrowserTablePanel *browser ) + { + m_pBrowser = browser; + } + + virtual void actionPerformed( Panel *panel ) + { + m_pBrowser->DoPing(); + } +}; + +class SortHandler : public ActionSignal +{ +private: + ServerBrowserTablePanel *m_pBrowser; + +public: + SortHandler( ServerBrowserTablePanel *browser ) + { + m_pBrowser = browser; + } + + virtual void actionPerformed( Panel *panel ) + { + m_pBrowser->DoSort( "map" ); + } +}; + +} + +class LabelSortInputHandler : public InputSignal +{ +private: + ServerBrowserTablePanel *m_pBrowser; + char m_szSortKey[ 64 ]; + +public: + LabelSortInputHandler( ServerBrowserTablePanel *pBrowser, char *name ) + { + m_pBrowser = pBrowser; + strcpy( m_szSortKey, name ); + } + + virtual void cursorMoved(int x,int y,Panel* panel) {}; + virtual void cursorEntered(Panel* panel){}; + virtual void cursorExited(Panel* Panel) {}; + + virtual void mousePressed(MouseCode code,Panel* panel) + { + m_pBrowser->DoSort( m_szSortKey ); + } + + virtual void mouseDoublePressed(MouseCode code,Panel* panel) + { + m_pBrowser->DoSort( m_szSortKey ); + } + + virtual void mouseReleased(MouseCode code,Panel* panel) {}; + virtual void mouseWheeled(int delta,Panel* panel) {}; + virtual void keyPressed(KeyCode code,Panel* panel) {}; + virtual void keyTyped(KeyCode code,Panel* panel) {}; + virtual void keyReleased(KeyCode code,Panel* panel) {}; + virtual void keyFocusTicked(Panel* panel) {}; +}; + +class CSBLabel : public Label +{ + +private: + char m_szSortKey[ 64 ]; + ServerBrowserTablePanel *m_pBrowser; + +public: + CSBLabel( char *name, char *sortkey ) : Label( name ) + { + m_pBrowser = NULL; + + strcpy( m_szSortKey, sortkey ); + + int label_bg_r = 120, + label_bg_g = 75, + label_bg_b = 32, + label_bg_a = 200; + + int label_fg_r = 255, + label_fg_g = 0, + label_fg_b = 0, + label_fg_a = 0; + + setContentAlignment( vgui::Label::a_west ); + setFgColor( label_fg_r, label_fg_g, label_fg_b, label_fg_a ); + setBgColor( label_bg_r, label_bg_g, label_bg_b, label_bg_a ); + setFont( Scheme::sf_primary2 ); + + } + + void setTable( ServerBrowserTablePanel *browser ) + { + m_pBrowser = browser; + + addInputSignal( new LabelSortInputHandler( (ServerBrowserTablePanel * )m_pBrowser, m_szSortKey ) ); + } +}; + +ServerBrowser::ServerBrowser(int x,int y,int wide,int tall) : CTransparentPanel( 100, x,y,wide,tall ) +{ + int i; + + _headerPanel = new HeaderPanel(0,0,wide,HEADER_SIZE_Y); + _headerPanel->setParent(this); + _headerPanel->setFgColor( 100,100,100, 100 ); + _headerPanel->setBgColor( 0, 0, 0, 100 ); + + CSBLabel *pLabel[5]; + + pLabel[0] = new CSBLabel( "Address", "address" ); + pLabel[1] = new CSBLabel( "Server", "hostname" ); + pLabel[2] = new CSBLabel( "Map", "map" ); + pLabel[3] = new CSBLabel( "Current", "current" ); + pLabel[4] = new CSBLabel( "Latency", "ping" ); + + for ( i = 0; i < 5; i++ ) + { + _headerPanel->addSectionPanel( pLabel[i] ); + } + + // _headerPanel->setFont( Scheme::sf_primary1 ); + + _headerPanel->setSliderPos( 0, CSIZE_ADDRESS ); + _headerPanel->setSliderPos( 1, CSIZE_SERVER ); + _headerPanel->setSliderPos( 2, CSIZE_MAP ); + _headerPanel->setSliderPos( 3, CSIZE_CURRENT ); + _headerPanel->setSliderPos( 4, CSIZE_PING ); + + _tablePanel = new ServerBrowserTablePanel( 0, HEADER_SIZE_Y, wide, tall - HEADER_SIZE_Y, NUM_COLUMNS ); + _tablePanel->setParent(this); + _tablePanel->setHeaderPanel(_headerPanel); + _tablePanel->setFgColor( 100,100,100, 100 ); + _tablePanel->setBgColor( 0, 0, 0, 100 ); + + _tablePanel->addInputSignal( new CBrowser_InputSignal( (ServerBrowserTablePanel *)_tablePanel ) ); + + for ( i = 0; i < 5; i++ ) + { + pLabel[i]->setTable( (ServerBrowserTablePanel * )_tablePanel ); + } + + int bw = 80, bh = 15; + int by = tall - HEADER_SIZE_Y; + + int btnx = 10; + + _connectButton = new CommandButton( "Connect", btnx, by, bw, bh ); + _connectButton->setParent( this ); + _connectButton->addActionSignal( new ConnectHandler( (ServerBrowserTablePanel * )_tablePanel ) ); + + btnx += bw; + + _refreshButton = new CommandButton( "Refresh", btnx, by, bw, bh ); + _refreshButton->setParent( this ); + _refreshButton->addActionSignal( new RefreshHandler( (ServerBrowserTablePanel * )_tablePanel ) ); + + /* + btnx += bw; + + _broadcastRefreshButton = new CommandButton( "LAN", btnx, by, bw, bh ); + _broadcastRefreshButton->setParent( this ); + _broadcastRefreshButton->addActionSignal( new BroadcastRefreshHandler( (ServerBrowserTablePanel * )_tablePanel ) ); + */ + + btnx += bw; + + _stopButton = new CommandButton( "Stop", btnx, by, bw, bh ); + _stopButton->setParent( this ); + _stopButton->addActionSignal( new StopHandler( (ServerBrowserTablePanel * )_tablePanel ) ); + + /* + btnx += bw; + + _pingButton = new CommandButton( "Test", btnx, by, bw, bh ); + _pingButton->setParent( this ); + _pingButton->addActionSignal( new PingHandler( (ServerBrowserTablePanel * )_tablePanel ) ); + + btnx += bw; + + _sortButton = new CommandButton( "Sort", btnx, by, bw, bh ); + _sortButton->setParent( this ); + _sortButton->addActionSignal( new SortHandler( (ServerBrowserTablePanel * )_tablePanel ) ); + */ + + btnx += bw; + + _cancelButton = new CommandButton( "Close", btnx, by, bw, bh ); + _cancelButton->setParent( this ); + _cancelButton->addActionSignal( new CancelHandler( (ServerBrowserTablePanel * )_tablePanel ) ); + + setPaintBorderEnabled(false); + setPaintBackgroundEnabled(false); + setPaintEnabled(false); + +} + +void ServerBrowser::setSize(int wide,int tall) +{ + Panel::setSize(wide,tall); + + _headerPanel->setBounds(0,0,wide,HEADER_SIZE_Y); + _tablePanel->setBounds(0,HEADER_SIZE_Y,wide,tall - HEADER_SIZE_Y); + + _connectButton->setBounds( 5, tall - HEADER_SIZE_Y, 75, 15 ); + _refreshButton->setBounds( 85, tall - HEADER_SIZE_Y, 75, 15 ); + /* + _broadcastRefreshButton->setBounds( 165, tall - HEADER_SIZE_Y, 75, 15 ); + */ + _stopButton->setBounds( 165, tall - HEADER_SIZE_Y, 75, 15 ); + /* + _pingButton->setBounds( 325, tall - HEADER_SIZE_Y, 75, 15 ); + */ + _cancelButton->setBounds( 245, tall - HEADER_SIZE_Y, 75, 15 ); +} + +void CBrowser_InputSignal::mousePressed(MouseCode code,Panel* panel) +{ + int x, y; + int therow = 2; + + if ( code != MOUSE_LEFT ) + return; + + panel->getApp()->getCursorPos(x,y); + panel->screenToLocal( x, y ); + + therow = y / CELL_HEIGHT; + + // Figure out which row it's on + m_pBrowser->setMouseOverRow( therow ); +} + +void CBrowser_InputSignal::mouseDoublePressed(MouseCode code,Panel* panel) +{ + int x, y; + int therow = 2; + + if ( code != MOUSE_LEFT ) + return; + + panel->getApp()->getCursorPos(x,y); + panel->screenToLocal( x, y ); + + therow = y / CELL_HEIGHT; + + // Figure out which row it's on + m_pBrowser->setMouseOverRow( therow ); + m_pBrowser->DoConnect(); +} diff --git a/cl_dll/vgui_ServerBrowser.h b/cl_dll/vgui_ServerBrowser.h new file mode 100644 index 0000000..7dc819a --- /dev/null +++ b/cl_dll/vgui_ServerBrowser.h @@ -0,0 +1,44 @@ + +#ifndef ServerBrowser_H +#define ServerBrowser_H + +#include + +namespace vgui +{ +class Button; +class TablePanel; +class HeaderPanel; +} + +class CTransparentPanel; +class CommandButton; + +// Scoreboard positions +#define SB_X_INDENT (20 * ((float)ScreenHeight / 640)) +#define SB_Y_INDENT (20 * ((float)ScreenHeight / 480)) + +class ServerBrowser : public CTransparentPanel +{ +private: + HeaderPanel * _headerPanel; + TablePanel* _tablePanel; + + CommandButton* _connectButton; + CommandButton* _refreshButton; + CommandButton* _broadcastRefreshButton; + CommandButton* _stopButton; + CommandButton* _sortButton; + CommandButton* _cancelButton; + + CommandButton* _pingButton; + +public: + ServerBrowser(int x,int y,int wide,int tall); +public: + virtual void setSize(int wide,int tall); +}; + + + +#endif \ No newline at end of file diff --git a/cl_dll/vgui_TeamFortressViewport.cpp b/cl_dll/vgui_TeamFortressViewport.cpp new file mode 100644 index 0000000..eb59f2d --- /dev/null +++ b/cl_dll/vgui_TeamFortressViewport.cpp @@ -0,0 +1,2134 @@ +//=========== (C) Copyright 1999 Valve, L.L.C. All rights reserved. =========== +// +// The copyright to the contents herein is the property of Valve, L.L.C. +// The contents may be used and/or copied only with the written permission of +// Valve, L.L.C., or in accordance with the terms and conditions stipulated in +// the agreement/contract under which the contents have been supplied. +// +// Purpose: Client DLL VGUI Viewport +// +// $Workfile: $ +// $Date: $ +// +//----------------------------------------------------------------------------- +// $Log: $ +// +// $NoKeywords: $ +//============================================================================= +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "hud.h" +#include "cl_util.h" +#include "camera.h" +#include "kbutton.h" +#include "cvardef.h" +#include "usercmd.h" +#include "const.h" +#include "camera.h" +#include "in_defs.h" +#include "parsemsg.h" +#include "../engine/keydefs.h" +#include "demo.h" +#include "demo_api.h" + +#include "vgui_int.h" +#include "vgui_TeamFortressViewport.h" +#include "vgui_ServerBrowser.h" +#include "vgui_ScorePanel.h" + +extern int g_iVisibleMouse; +class CCommandMenu; +int g_iPlayerClass; +int g_iTeamNumber; +int g_iUser1; +int g_iUser2; + +void IN_ResetMouse( void ); +extern CMenuPanel *CMessageWindowPanel_Create( const char *szMOTD, const char *szTitle, int iShadeFullscreen, int iRemoveMe, int x, int y, int wide, int tall ); + +using namespace vgui; + +// Team Colors +int iTeamColors[5][3] = +{ + { 255, 255, 255 }, + { 66, 115, 247 }, + { 220, 51, 38 }, + { 240, 135, 0 }, + { 115, 240, 115 }, +}; + +// Used for Class specific buttons +char *sTFClasses[] = +{ + "", + "SCOUT", + "SNIPER", + "SOLDIER", + "DEMOMAN", + "MEDIC", + "HWGUY", + "PYRO", + "SPY", + "ENGINEER", + "CIVILIAN", +}; + +char *sLocalisedClasses[] = +{ + "#Civilian", + "#Scout", + "#Sniper", + "#Soldier", + "#Demoman", + "#Medic", + "#HWGuy", + "#Pyro", + "#Spy", + "#Engineer", + "#Random", + "#Civilian", +}; + +char *sTFClassSelection[] = +{ + "civilian", + "scout", + "sniper", + "soldier", + "demoman", + "medic", + "hwguy", + "pyro", + "spy", + "engineer", + "randompc", + "civilian", +}; + +int iBuildingCosts[] = +{ + BUILD_COST_DISPENSER, + BUILD_COST_SENTRYGUN +}; + +// This maps class numbers to the Invalid Class bit. +// This is needed for backwards compatability in maps that were finished before +// all the classes were in TF. Hence the wacky sequence. +int sTFValidClassInts[] = +{ + 0, + TF_ILL_SCOUT, + TF_ILL_SNIPER, + TF_ILL_SOLDIER, + TF_ILL_DEMOMAN, + TF_ILL_MEDIC, + TF_ILL_HVYWEP, + TF_ILL_PYRO, + TF_ILL_SPY, + TF_ILL_ENGINEER, + TF_ILL_RANDOMPC, +}; + +// Get the name of TGA file, based on GameDir +char* GetVGUITGAName(const char *pszName) +{ + int i; + char sz[256]; + static char gd[256]; + const char *gamedir; + + if (ScreenWidth < 640) + i = 320; + else + i = 640; + sprintf(sz, pszName, i); + + gamedir = gEngfuncs.pfnGetGameDirectory(); + sprintf(gd, "%s/gfx/vgui/%s.tga",gamedir,sz); + + return gd; +} + +//================================================================ +// COMMAND MENU +//================================================================ +void CCommandMenu::AddButton( CommandButton *pButton ) +{ + if (m_iButtons >= MAX_BUTTONS) + return; + + m_aButtons[m_iButtons] = pButton; + m_iButtons++; + pButton->setParent( this ); + pButton->setFont( Scheme::sf_primary3 ); + + // give the button a default key binding + if ( m_iButtons < 10 ) + { + pButton->setBoundKey( m_iButtons + '0' ); + } + else if ( m_iButtons == 10 ) + { + pButton->setBoundKey( '0' ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: Tries to find a button that has a key bound to the input, and +// presses the button if found +// Input : keyNum - the character number of the input key +// Output : Returns true if the command menu should close, false otherwise +//----------------------------------------------------------------------------- +bool CCommandMenu::KeyInput( int keyNum ) +{ + // loop through all our buttons looking for one bound to keyNum + for ( int i = 0; i < m_iButtons; i++ ) + { + if ( !m_aButtons[i]->IsNotValid() ) + { + if ( m_aButtons[i]->getBoundKey() == keyNum ) + { + // hit the button + if ( m_aButtons[i]->GetSubMenu() ) + { + // open the sub menu + gViewPort->SetCurrentCommandMenu( m_aButtons[i]->GetSubMenu() ); + return false; + } + else + { + // run the bound command + m_aButtons[i]->fireActionSignal(); + return true; + } + } + } + } + + return false; +} + +//----------------------------------------------------------------------------- +// Purpose: clears the current menus buttons of any armed (highlighted) +// state, and all their sub buttons +//----------------------------------------------------------------------------- +void CCommandMenu::ClearButtonsOfArmedState( void ) +{ + for ( int i = 0; i < GetNumButtons(); i++ ) + { + m_aButtons[i]->setArmed( false ); + + if ( m_aButtons[i]->GetSubMenu() ) + { + m_aButtons[i]->GetSubMenu()->ClearButtonsOfArmedState(); + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *pSubMenu - +// Output : CommandButton +//----------------------------------------------------------------------------- +CommandButton *CCommandMenu::FindButtonWithSubmenu( CCommandMenu *pSubMenu ) +{ + for ( int i = 0; i < GetNumButtons(); i++ ) + { + if ( m_aButtons[i]->GetSubMenu() == pSubMenu ) + return m_aButtons[i]; + } + + return NULL; +} + +// Recalculate the visible buttons +bool CCommandMenu::RecalculateVisibles( int iNewYPos, bool bHideAll ) +{ + int iCurrentY = 0; + int iXPos, iYPos; + bool bHasButton = false; + + if (iNewYPos) + setPos( _pos[0], iNewYPos ); + + // Cycle through all the buttons in this menu, and see which will be visible + for (int i = 0; i < m_iButtons; i++) + { + int iClass = m_aButtons[i]->GetPlayerClass(); + if ( (iClass && iClass != g_iPlayerClass ) || ( m_aButtons[i]->IsNotValid() ) || bHideAll ) + { + m_aButtons[i]->setVisible( false ); + if ( m_aButtons[i]->GetSubMenu() != NULL ) + { + (m_aButtons[i]->GetSubMenu())->RecalculateVisibles( _pos[1] + iCurrentY, true ); + } + } + else + { + // If it's got a submenu, force it to check visibilities + if ( m_aButtons[i]->GetSubMenu() != NULL ) + { + if ( !(m_aButtons[i]->GetSubMenu())->RecalculateVisibles( _pos[1] + iCurrentY, false ) ) + { + // The submenu had no visible buttons, so don't display this button + m_aButtons[i]->setVisible( false ); + continue; + } + } + + m_aButtons[i]->setVisible( true ); + + // Make sure it's at the right Y position + m_aButtons[i]->getPos( iXPos, iYPos ); + m_aButtons[i]->setPos( iXPos, iCurrentY ); + + iCurrentY += BUTTON_SIZE_Y - 1; + bHasButton = true; + } + } + + // Set Size + setSize( _size[0], iCurrentY + 1 ); + + return bHasButton; +} + +// Make sure all submenus can fit on the screen +void CCommandMenu::RecalculatePositions( int iYOffset ) +{ + int iNewYPos = _pos[1] + iYOffset; + int iAdjust = 0; + + // Calculate if this is going to fit onscreen, and shuffle it up if it won't + int iBottom = iNewYPos + _size[1]; + if ( iBottom > ScreenHeight ) + { + // Move in increments of button sizes + while (iAdjust < (iBottom - ScreenHeight)) + { + iAdjust += BUTTON_SIZE_Y - 1; + } + iNewYPos -= iAdjust; + + // Make sure it doesn't move off the top of the screen (the menu's too big to fit it all) + if ( iNewYPos < 0 ) + { + iAdjust -= (0 - iNewYPos); + iNewYPos = 0; + } + } + + // We need to force all menus below this one to update their positions now, because they + // might have submenus riding off buttons in this menu that have just shifted. + for (int i = 0; i < m_iButtons; i++) + m_aButtons[i]->UpdateSubMenus( iAdjust ); + + setPos( _pos[0], iNewYPos ); +} + + +// Make this menu and all menus above it in the chain visible +void CCommandMenu::MakeVisible( CCommandMenu *pChildMenu ) +{ +/* + // Push down the button leading to the child menu + for (int i = 0; i < m_iButtons; i++) + { + if ( (pChildMenu != NULL) && (m_aButtons[i]->GetSubMenu() == pChildMenu) ) + { + m_aButtons[i]->setArmed( true ); + } + else + { + m_aButtons[i]->setArmed( false ); + } + } +*/ + + setVisible(true); + if (m_pParentMenu) + m_pParentMenu->MakeVisible( this ); +} + +//================================================================ +// CreateSubMenu +CCommandMenu *TeamFortressViewport::CreateSubMenu( CommandButton *pButton, CCommandMenu *pParentMenu ) +{ + int iXPos = 0; + int iYPos = 0; + int iWide = CMENU_SIZE_X; + int iTall = 0; + + if (pParentMenu) + { + iXPos = pParentMenu->GetXOffset() + CMENU_SIZE_X - 1; + iYPos = pParentMenu->GetYOffset() + BUTTON_SIZE_Y * (m_pCurrentCommandMenu->GetNumButtons() - 1); + } + + CCommandMenu *pMenu = new CCommandMenu(pParentMenu, iXPos, iYPos, iWide, iTall ); + pMenu->setParent(this); + pButton->AddSubMenu( pMenu ); + pButton->setFont( Scheme::sf_primary3 ); + + // Create the Submenu-open signal + InputSignal *pISignal = new CMenuHandler_PopupSubMenuInput(pButton, pMenu); + pButton->addInputSignal(pISignal); + + // Put a > to show it's a submenu + CImageLabel *pLabel = new CImageLabel( "arrow", CMENU_SIZE_X - SUBMENU_SIZE_X, SUBMENU_SIZE_Y ); + pLabel->setParent(pButton); + pLabel->addInputSignal(pISignal); + + // Reposition + pLabel->getPos( iXPos, iYPos ); + pLabel->setPos( CMENU_SIZE_X - pLabel->getImageWide(), (BUTTON_SIZE_Y - pLabel->getImageTall()) / 2 ); + + // Create the mouse off signal for the Label too + if (!pButton->m_bNoHighlight) + pLabel->addInputSignal( new CHandler_CommandButtonHighlight(pButton) ); + + return pMenu; +} + +//----------------------------------------------------------------------------- +// Purpose: Makes sure the memory allocated for TeamFortressViewport is nulled out +// Input : stAllocateBlock - +// Output : void * +//----------------------------------------------------------------------------- +void *TeamFortressViewport::operator new( size_t stAllocateBlock ) +{ +// void *mem = Panel::operator new( stAllocateBlock ); + void *mem = ::operator new( stAllocateBlock ); + memset( mem, 0, stAllocateBlock ); + return mem; +} + +//----------------------------------------------------------------------------- +// Purpose: InputSignal handler for the main viewport +//----------------------------------------------------------------------------- +class CViewPortInputHandler : public InputSignal +{ +public: + bool bPressed; + + CViewPortInputHandler() + { + } + + virtual void cursorMoved(int x,int y,Panel* panel) {} + virtual void cursorEntered(Panel* panel) {} + virtual void cursorExited(Panel* panel) {} + virtual void mousePressed(MouseCode code,Panel* panel) + { + if ( code != MOUSE_LEFT ) + { + // send a message to close the command menu + // this needs to be a message, since a direct call screws the timing + gEngfuncs.pfnClientCmd( "ForceCloseCommandMenu\n" ); + } + } + virtual void mouseReleased(MouseCode code,Panel* panel) + { + } + + virtual void mouseDoublePressed(MouseCode code,Panel* panel) {} + virtual void mouseWheeled(int delta,Panel* panel) {} + virtual void keyPressed(KeyCode code,Panel* panel) {} + virtual void keyTyped(KeyCode code,Panel* panel) {} + virtual void keyReleased(KeyCode code,Panel* panel) {} + virtual void keyFocusTicked(Panel* panel) {} +}; + + +//================================================================ +TeamFortressViewport::TeamFortressViewport(int x,int y,int wide,int tall) : Panel(x,y,wide,tall), m_SchemeManager(wide,tall) +{ + gViewPort = this; + m_iInitialized = false; + m_pTeamMenu = NULL; + m_pClassMenu = NULL; + m_pScoreBoard = NULL; + m_pSpectatorMenu = NULL; + m_pCurrentMenu = NULL; + m_pCurrentCommandMenu = NULL; + + CVAR_CREATE( "hud_classautokill", "1", FCVAR_ARCHIVE ); // controls whether or not to suicide immediately on TF class switch + CVAR_CREATE( "hud_takesshots", "0", FCVAR_ARCHIVE ); // controls whether or not to automatically take screenshots at the end of a round + + Initialize(); + addInputSignal( new CViewPortInputHandler ); + + int r, g, b, a; + + Scheme* pScheme = App::getInstance()->getScheme(); + + // primary text color + // Get the colors + //!! two different types of scheme here, need to integrate + SchemeHandle_t hPrimaryScheme = m_SchemeManager.getSchemeHandle( "Primary Button Text" ); + { + // font + pScheme->setFont( Scheme::sf_primary1, m_SchemeManager.getFont(hPrimaryScheme) ); + + // text color + m_SchemeManager.getFgColor( hPrimaryScheme, r, g, b, a ); + pScheme->setColor(Scheme::sc_primary1, r, g, b, a ); // sc_primary1 is non-transparent orange + + // background color (transparent black) + m_SchemeManager.getBgColor( hPrimaryScheme, r, g, b, a ); + pScheme->setColor(Scheme::sc_primary3, r, g, b, a ); + + // armed foreground color + m_SchemeManager.getFgArmedColor( hPrimaryScheme, r, g, b, a ); + pScheme->setColor(Scheme::sc_secondary2, r, g, b, a ); + + // armed background color + m_SchemeManager.getBgArmedColor( hPrimaryScheme, r, g, b, a ); + pScheme->setColor(Scheme::sc_primary2, r, g, b, a ); + + //!! need to get this color from scheme file + // used for orange borders around buttons + m_SchemeManager.getBorderColor( hPrimaryScheme, r, g, b, a ); + // pScheme->setColor(Scheme::sc_secondary1, r, g, b, a ); + pScheme->setColor(Scheme::sc_secondary1, 255*0.7, 170*0.7, 0, 0); + } + + // Change the second primary font (used in the scoreboard) + SchemeHandle_t hScoreboardScheme = m_SchemeManager.getSchemeHandle( "Scoreboard Text" ); + { + pScheme->setFont(Scheme::sf_primary2, m_SchemeManager.getFont(hScoreboardScheme) ); + } + + // Change the third primary font (used in command menu) + SchemeHandle_t hCommandMenuScheme = m_SchemeManager.getSchemeHandle( "CommandMenu Text" ); + { + pScheme->setFont(Scheme::sf_primary3, m_SchemeManager.getFont(hCommandMenuScheme) ); + } + + App::getInstance()->setScheme(pScheme); + + // VGUI MENUS + CreateTeamMenu(); + CreateClassMenu(); + CreateScoreBoard(); + CreateCommandMenu(); + CreateServerBrowser(); + CreateSpectatorMenu(); +} + +//----------------------------------------------------------------------------- +// Purpose: Called everytime a new level is started. Viewport clears out it's data. +//----------------------------------------------------------------------------- +void TeamFortressViewport::Initialize( void ) +{ + // Force each menu to Initialize + if (m_pTeamMenu) + { + m_pTeamMenu->Initialize(); + } + if (m_pClassMenu) + { + m_pClassMenu->Initialize(); + } + if (m_pScoreBoard) + { + m_pScoreBoard->Initialize(); + HideScoreBoard(); + } + if (m_pSpectatorMenu) + { + // Spectator menu doesn't need initializing + m_pSpectatorMenu->setVisible( false ); + } + + // Make sure all menus are hidden + HideVGUIMenu(); + HideCommandMenu(); + + // Clear out some data + m_iGotAllMOTD = true; + m_iRandomPC = false; + m_flScoreBoardLastUpdated = 0; + + // reset player info + g_iPlayerClass = 0; + g_iTeamNumber = 0; + + strcpy(m_sMapName, ""); + strcpy(m_szServerName, ""); + for (int i = 0; i < 5; i++) + { + m_iValidClasses[i] = 0; + strcpy(m_sTeamNames[i], ""); + } + + App::getInstance()->setCursorOveride( App::getInstance()->getScheme()->getCursor(Scheme::SchemeCursor::scu_none) ); +} + +class CException; +//----------------------------------------------------------------------------- +// Purpose: Read the Command Menu structure from the txt file and create the menu. +//----------------------------------------------------------------------------- +void TeamFortressViewport::CreateCommandMenu( void ) +{ + // COMMAND MENU + // Create the root of the Command Menu + m_pCommandMenus[0] = new CCommandMenu(NULL, 0, CMENU_TOP, CMENU_SIZE_X, 300); // This will be resized once we know how many items are in it + m_pCommandMenus[0]->setParent(this); + m_pCommandMenus[0]->setVisible(false); + m_iNumMenus = 1; + m_iCurrentTeamNumber = m_iUser1 = m_iUser2 = 0; + + // Read Command Menu from the txt file + char token[1024]; + char *pfile = (char*)gEngfuncs.COM_LoadFile("commandmenu.txt", 5, NULL); + if (!pfile) + { + gEngfuncs.Con_DPrintf( "Unable to open commandmenu.txt\n"); + SetCurrentCommandMenu( NULL ); + return; + } + +try +{ + // First, read in the localisation strings + + // Detpack strings + gHUD.m_TextMessage.LocaliseTextString( "#DetpackSet_For5Seconds", m_sDetpackStrings[0], MAX_BUTTON_SIZE ); + gHUD.m_TextMessage.LocaliseTextString( "#DetpackSet_For20Seconds", m_sDetpackStrings[1], MAX_BUTTON_SIZE ); + gHUD.m_TextMessage.LocaliseTextString( "#DetpackSet_For50Seconds", m_sDetpackStrings[2], MAX_BUTTON_SIZE ); + + // Now start parsing the menu structure + m_pCurrentCommandMenu = m_pCommandMenus[0]; + char szLastButtonText[32] = "file start"; + pfile = gEngfuncs.COM_ParseFile(pfile, token); + while ( ( strlen ( token ) > 0 ) && ( m_iNumMenus < MAX_MENUS ) ) + { + // Keep looping until we hit the end of this menu + while ( token[0] != '}' && ( strlen( token ) > 0 ) ) + { + char cText[32] = ""; + char cBoundKey[32] = ""; + char cCustom[32] = ""; + static const int cCommandLength = 128; + char cCommand[cCommandLength] = ""; + char szMap[MAX_MAPNAME] = ""; + int iPlayerClass = 0; + int iCustom = false; + int iTeamOnly = 0; + bool bGetExtraToken = true; + CommandButton *pButton = NULL; + + // We should never be here without a Command Menu + if (!m_pCurrentCommandMenu) + { + gEngfuncs.Con_Printf("Error in Commandmenu.txt file after '%s'.\n", szLastButtonText ); + m_iInitialized = false; + return; + } + + // token should already be the bound key, or the custom name + strncpy( cCustom, token, 32 ); + cCustom[31] = '\0'; + + // See if it's a custom button + if (!strcmp(cCustom, "CUSTOM") ) + { + iCustom = true; + + // Get the next token + pfile = gEngfuncs.COM_ParseFile(pfile, token); + } + // See if it's a map + else if (!strcmp(cCustom, "MAP") ) + { + // Get the mapname + pfile = gEngfuncs.COM_ParseFile(pfile, token); + strncpy( szMap, token, MAX_MAPNAME ); + szMap[MAX_MAPNAME-1] = '\0'; + + // Get the next token + pfile = gEngfuncs.COM_ParseFile(pfile, token); + } + else if ( !strncmp(cCustom, "TEAM", 4) ) // TEAM1, TEAM2, TEAM3, TEAM4 + { + // make it a team only button + iTeamOnly = atoi( cCustom + 4 ); + + // Get the next token + pfile = gEngfuncs.COM_ParseFile(pfile, token); + } + else + { + // See if it's a Class + for (int i = 1; i <= PC_ENGINEER; i++) + { + if ( !strcmp(token, sTFClasses[i]) ) + { + // Save it off + iPlayerClass = i; + + // Get the button text + pfile = gEngfuncs.COM_ParseFile(pfile, token); + break; + } + } + } + + // Get the button bound key + strncpy( cBoundKey, token, 32 ); + cText[31] = '\0'; + + // Get the button text + pfile = gEngfuncs.COM_ParseFile(pfile, token); + strncpy( cText, token, 32 ); + cText[31] = '\0'; + + // save off the last button text we've come across (for error reporting) + strcpy( szLastButtonText, cText ); + + // Get the button command + pfile = gEngfuncs.COM_ParseFile(pfile, token); + strncpy( cCommand, token, cCommandLength ); + cCommand[cCommandLength - 1] = '\0'; + + // Custom button handling + if ( iCustom ) + { + pButton = CreateCustomButton( cText, cCommand ); + + // Get the next token to see if we're a menu + pfile = gEngfuncs.COM_ParseFile(pfile, token); + + if ( token[0] == '{' ) + { + strcpy( cCommand, token ); + } + else + { + bGetExtraToken = false; + } + } + else if ( szMap[0] != '\0' ) + { + // create a map button + pButton = new MapButton(szMap, cText,0, BUTTON_SIZE_Y * m_pCurrentCommandMenu->GetNumButtons(), CMENU_SIZE_X, BUTTON_SIZE_Y); + } + else if ( iTeamOnly ) + { + // button that only shows up if the player is on team iTeamOnly + pButton = new TeamOnlyCommandButton( iTeamOnly, cText,0, BUTTON_SIZE_Y * m_pCurrentCommandMenu->GetNumButtons(), CMENU_SIZE_X, BUTTON_SIZE_Y ); + } + else + { + // normal button + pButton = new CommandButton( iPlayerClass, cText,0, BUTTON_SIZE_Y * m_pCurrentCommandMenu->GetNumButtons(), CMENU_SIZE_X, BUTTON_SIZE_Y ); + } + + // add the button into the command menu + if ( pButton ) + { + m_pCurrentCommandMenu->AddButton( pButton ); + pButton->setBoundKey( cBoundKey[0] ); + pButton->setParentMenu( m_pCurrentCommandMenu ); + + // Override font in CommandMenu + pButton->setFont( Scheme::sf_primary3 ); + } + + // Find out if it's a submenu or a button we're dealing with + if ( cCommand[0] == '{' ) + { + if ( m_iNumMenus >= MAX_MENUS ) + { + gEngfuncs.Con_Printf( "Too many menus in commandmenu.txt past '%s'\n", szLastButtonText ); + } + else + { + // Create the menu + m_pCommandMenus[m_iNumMenus] = CreateSubMenu(pButton, m_pCurrentCommandMenu); + m_pCurrentCommandMenu = m_pCommandMenus[m_iNumMenus]; + m_iNumMenus++; + } + } + else if ( !iCustom ) + { + // Create the button and attach it to the current menu + pButton->addActionSignal(new CMenuHandler_StringCommand(cCommand)); + // Create an input signal that'll popup the current menu + pButton->addInputSignal( new CMenuHandler_PopupSubMenuInput(pButton, m_pCurrentCommandMenu) ); + } + + // Get the next token + if ( bGetExtraToken ) + { + pfile = gEngfuncs.COM_ParseFile(pfile, token); + } + } + + // Move back up a menu + m_pCurrentCommandMenu = m_pCurrentCommandMenu->GetParentMenu(); + + pfile = gEngfuncs.COM_ParseFile(pfile, token); + } +} +catch( CException *e ) +{ + e; + //e->Delete(); + e = NULL; + m_iInitialized = false; + return; +} + + SetCurrentMenu( NULL ); + SetCurrentCommandMenu( NULL ); + gEngfuncs.COM_FreeFile( pfile ); + + m_iInitialized = true; +} + +//----------------------------------------------------------------------------- +// Purpose: Creates all the class choices under a spy's disguise menus, and +// maps a command to them +// Output : CCommandMenu +//----------------------------------------------------------------------------- +CCommandMenu *TeamFortressViewport::CreateDisguiseSubmenu( CommandButton *pButton, CCommandMenu *pParentMenu, const char *commandText ) +{ + // create the submenu, under which the class choices will be listed + CCommandMenu *pMenu = CreateSubMenu( pButton, pParentMenu ); + m_pCommandMenus[m_iNumMenus] = pMenu; + m_iNumMenus++; + + // create the class choice buttons + for ( int i = PC_SCOUT; i <= PC_ENGINEER; i++ ) + { + CommandButton *pDisguiseButton = new CommandButton( CHudTextMessage::BufferedLocaliseTextString( sLocalisedClasses[i] ), 0, BUTTON_SIZE_Y, CMENU_SIZE_X, BUTTON_SIZE_Y ); + + char sz[256]; + sprintf(sz, "%s %d", commandText, i ); + pDisguiseButton->addActionSignal(new CMenuHandler_StringCommand(sz)); + + pMenu->AddButton( pDisguiseButton ); + } + + return pMenu; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *pButtonText - +// *pButtonName - +// Output : CommandButton +//----------------------------------------------------------------------------- +CommandButton *TeamFortressViewport::CreateCustomButton( char *pButtonText, char *pButtonName ) +{ + CommandButton *pButton = NULL; + CCommandMenu *pMenu = NULL; + + // ChangeTeam + if ( !strcmp( pButtonName, "!CHANGETEAM" ) ) + { + // ChangeTeam Submenu + pButton = new CommandButton(pButtonText, 0, BUTTON_SIZE_Y * 2, CMENU_SIZE_X, BUTTON_SIZE_Y); + + // Create the submenu + pMenu = CreateSubMenu(pButton, m_pCurrentCommandMenu); + m_pCommandMenus[m_iNumMenus] = pMenu; + m_iNumMenus++; + + // ChangeTeam buttons + for (int i = 0; i < 4; i++) + { + char sz[256]; + sprintf(sz, "jointeam %d", i+1); + m_pTeamButtons[i] = new TeamButton(i+1, "teamname", 0, BUTTON_SIZE_Y, CMENU_SIZE_X, BUTTON_SIZE_Y); + m_pTeamButtons[i]->addActionSignal(new CMenuHandler_StringCommandWatch( sz )); + pMenu->AddButton( m_pTeamButtons[i] ); + } + + // Auto Assign button + m_pTeamButtons[4] = new TeamButton(5, gHUD.m_TextMessage.BufferedLocaliseTextString( "#Team_AutoAssign" ), 0, BUTTON_SIZE_Y, CMENU_SIZE_X, BUTTON_SIZE_Y); + m_pTeamButtons[4]->addActionSignal(new CMenuHandler_StringCommand( "jointeam 5" )); + pMenu->AddButton( m_pTeamButtons[4] ); + + // Spectate button + m_pTeamButtons[5] = new SpectateButton( CHudTextMessage::BufferedLocaliseTextString( "#Menu_Spectate" ), 0, BUTTON_SIZE_Y, CMENU_SIZE_X, BUTTON_SIZE_Y, false); + m_pTeamButtons[5]->addActionSignal(new CMenuHandler_StringCommand( "spectate" )); + pMenu->AddButton( m_pTeamButtons[5] ); + } + // ChangeClass + else if ( !strcmp( pButtonName, "!CHANGECLASS" ) ) + { + // Create the Change class menu + pButton = new ClassButton(-1, pButtonText, 0, BUTTON_SIZE_Y, CMENU_SIZE_X, BUTTON_SIZE_Y, false); + + // ChangeClass Submenu + pMenu = CreateSubMenu(pButton, m_pCurrentCommandMenu); + m_pCommandMenus[m_iNumMenus] = pMenu; + m_iNumMenus++; + + for (int i = PC_SCOUT; i <= PC_RANDOM; i++ ) + { + char sz[256]; + + // ChangeClass buttons + CHudTextMessage::LocaliseTextString( sLocalisedClasses[i], sz, 256 ); + ClassButton *pClassButton = new ClassButton( i, sz, 0, BUTTON_SIZE_Y, CMENU_SIZE_X, BUTTON_SIZE_Y, false); + + sprintf(sz, "%s", sTFClassSelection[i]); + pClassButton->addActionSignal(new CMenuHandler_StringCommandClassSelect(sz)); + pMenu->AddButton( pClassButton ); + } + } + // Map Briefing + else if ( !strcmp( pButtonName, "!MAPBRIEFING" ) ) + { + pButton = new CommandButton(pButtonText, 0, BUTTON_SIZE_Y * m_pCurrentCommandMenu->GetNumButtons(), CMENU_SIZE_X, BUTTON_SIZE_Y); + pButton->addActionSignal(new CMenuHandler_TextWindow(MENU_MAPBRIEFING)); + // Create an input signal that'll popup the current menu + pButton->addInputSignal( new CMenuHandler_PopupSubMenuInput(pButton, m_pCurrentCommandMenu) ); + } + // Class Descriptions + else if ( !strcmp( pButtonName, "!CLASSDESC" ) ) + { + pButton = new ClassButton(0, pButtonText, 0, BUTTON_SIZE_Y * m_pCurrentCommandMenu->GetNumButtons(), CMENU_SIZE_X, BUTTON_SIZE_Y, false); + pButton->addActionSignal(new CMenuHandler_TextWindow(MENU_CLASSHELP)); + // Create an input signal that'll popup the current menu + pButton->addInputSignal( new CMenuHandler_PopupSubMenuInput(pButton, m_pCurrentCommandMenu) ); + } + else if ( !strcmp( pButtonName, "!SERVERINFO" ) ) + { + pButton = new ClassButton(0, pButtonText, 0, BUTTON_SIZE_Y * m_pCurrentCommandMenu->GetNumButtons(), CMENU_SIZE_X, BUTTON_SIZE_Y, false); + pButton->addActionSignal(new CMenuHandler_TextWindow(MENU_INTRO)); + // Create an input signal that'll popup the current menu + pButton->addInputSignal( new CMenuHandler_PopupSubMenuInput(pButton, m_pCurrentCommandMenu) ); + } + // Spy abilities + else if ( !strcmp( pButtonName, "!SPY" ) ) + { + pButton = new DisguiseButton( 0, pButtonText, 0, BUTTON_SIZE_Y, CMENU_SIZE_X, BUTTON_SIZE_Y ); + } + // Feign + else if ( !strcmp( pButtonName, "!FEIGN" ) ) + { + pButton = new FeignButton(FALSE, pButtonText, 0, BUTTON_SIZE_Y, CMENU_SIZE_X, BUTTON_SIZE_Y); + pButton->addActionSignal(new CMenuHandler_StringCommand( "feign" )); + // Create an input signal that'll popup the current menu + pButton->addInputSignal( new CMenuHandler_PopupSubMenuInput(pButton, m_pCurrentCommandMenu) ); + } + // Feign Silently + else if ( !strcmp( pButtonName, "!FEIGNSILENT" ) ) + { + pButton = new FeignButton(FALSE, pButtonText, 0, BUTTON_SIZE_Y, CMENU_SIZE_X, BUTTON_SIZE_Y); + pButton->addActionSignal(new CMenuHandler_StringCommand( "sfeign" )); + // Create an input signal that'll popup the current menu + pButton->addInputSignal( new CMenuHandler_PopupSubMenuInput(pButton, m_pCurrentCommandMenu) ); + } + // Stop Feigning + else if ( !strcmp( pButtonName, "!FEIGNSTOP" ) ) + { + pButton = new FeignButton(TRUE, pButtonText, 0, BUTTON_SIZE_Y, CMENU_SIZE_X, BUTTON_SIZE_Y); + pButton->addActionSignal(new CMenuHandler_StringCommand( "feign" )); + // Create an input signal that'll popup the current menu + pButton->addInputSignal( new CMenuHandler_PopupSubMenuInput(pButton, m_pCurrentCommandMenu) ); + } + // Disguise + else if ( !strcmp( pButtonName, "!DISGUISEENEMY" ) ) + { + // Create the disguise enemy button, which active only if there are 2 teams + pButton = new DisguiseButton(DISGUISE_TEAM2, pButtonText, 0, BUTTON_SIZE_Y, CMENU_SIZE_X, BUTTON_SIZE_Y); + CreateDisguiseSubmenu( pButton, m_pCurrentCommandMenu, "disguise_enemy" ); + } + else if ( !strcmp( pButtonName, "!DISGUISEFRIENDLY" ) ) + { + // Create the disguise friendly button, which active only if there are 1 or 2 teams + pButton = new DisguiseButton(DISGUISE_TEAM1 | DISGUISE_TEAM2, pButtonText, 0, BUTTON_SIZE_Y, CMENU_SIZE_X, BUTTON_SIZE_Y); + CreateDisguiseSubmenu( pButton, m_pCurrentCommandMenu, "disguise_friendly" ); + } + else if ( !strcmp( pButtonName, "!DISGUISE" ) ) + { + // Create the Disguise button + pButton = new DisguiseButton( DISGUISE_TEAM3 | DISGUISE_TEAM4, pButtonText, 0, BUTTON_SIZE_Y, CMENU_SIZE_X, BUTTON_SIZE_Y); + CCommandMenu *pDisguiseMenu = CreateSubMenu( pButton, m_pCurrentCommandMenu ); + m_pCommandMenus[m_iNumMenus] = pDisguiseMenu; + m_iNumMenus++; + + // Disguise Enemy submenu buttons + for ( int i = 1; i <= 4; i++ ) + { + // only show the 4th disguise button if we have 4 teams + m_pDisguiseButtons[i] = new DisguiseButton( ((i < 4) ? DISGUISE_TEAM3 : 0) | DISGUISE_TEAM4, "Disguise", 0, BUTTON_SIZE_Y, CMENU_SIZE_X, BUTTON_SIZE_Y); + + pDisguiseMenu->AddButton( m_pDisguiseButtons[i] ); + + char sz[256]; + sprintf( sz, "disguise %d", i ); + CreateDisguiseSubmenu( m_pDisguiseButtons[i], pDisguiseMenu, sz ); + } + } + // Start setting a Detpack + else if ( !strcmp( pButtonName, "!DETPACKSTART" ) ) + { + // Detpack Submenu + pButton = new DetpackButton(2, pButtonText, 0, BUTTON_SIZE_Y * 2, CMENU_SIZE_X, BUTTON_SIZE_Y); + + // Create the submenu + pMenu = CreateSubMenu(pButton, m_pCurrentCommandMenu); + m_pCommandMenus[m_iNumMenus] = pMenu; + m_iNumMenus++; + + // Set detpack buttons + CommandButton *pDetButton; + pDetButton = new CommandButton(m_sDetpackStrings[0], 0, BUTTON_SIZE_Y, CMENU_SIZE_X, BUTTON_SIZE_Y); + pDetButton->addActionSignal(new CMenuHandler_StringCommand("detstart 5")); + pMenu->AddButton( pDetButton ); + pDetButton = new CommandButton(m_sDetpackStrings[1], 0, BUTTON_SIZE_Y, CMENU_SIZE_X, BUTTON_SIZE_Y); + pDetButton->addActionSignal(new CMenuHandler_StringCommand("detstart 20")); + pMenu->AddButton( pDetButton ); + pDetButton = new CommandButton(m_sDetpackStrings[2], 0, BUTTON_SIZE_Y, CMENU_SIZE_X, BUTTON_SIZE_Y); + pDetButton->addActionSignal(new CMenuHandler_StringCommand("detstart 50")); + pMenu->AddButton( pDetButton ); + } + // Stop setting a Detpack + else if ( !strcmp( pButtonName, "!DETPACKSTOP" ) ) + { + pButton = new DetpackButton(1, pButtonText, 0, BUTTON_SIZE_Y, CMENU_SIZE_X, BUTTON_SIZE_Y); + pButton->addActionSignal(new CMenuHandler_StringCommand( "detstop" )); + // Create an input signal that'll popup the current menu + pButton->addInputSignal( new CMenuHandler_PopupSubMenuInput(pButton, m_pCurrentCommandMenu) ); + } + // Engineer building + else if ( !strcmp( pButtonName, "!BUILD" ) ) + { + // only appears if the player is an engineer, and either they have built something or have enough metal to build + pButton = new BuildButton( BUILDSTATE_BASE, 0, pButtonText, 0, BUTTON_SIZE_Y * 2, CMENU_SIZE_X, BUTTON_SIZE_Y); + } + else if ( !strcmp( pButtonName, "!BUILDSENTRY" ) ) + { + pButton = new BuildButton( BUILDSTATE_CANBUILD, BuildButton::SENTRYGUN, pButtonText, 0, BUTTON_SIZE_Y * 2, CMENU_SIZE_X, BUTTON_SIZE_Y); + pButton->addActionSignal(new CMenuHandler_StringCommand("build 2")); + // Create an input signal that'll popup the current menu + pButton->addInputSignal( new CMenuHandler_PopupSubMenuInput(pButton, m_pCurrentCommandMenu) ); + } + else if ( !strcmp( pButtonName, "!BUILDDISPENSER" ) ) + { + pButton = new BuildButton( BUILDSTATE_CANBUILD, BuildButton::DISPENSER, pButtonText, 0, BUTTON_SIZE_Y * 2, CMENU_SIZE_X, BUTTON_SIZE_Y); + pButton->addActionSignal(new CMenuHandler_StringCommand("build 1")); + // Create an input signal that'll popup the current menu + pButton->addInputSignal( new CMenuHandler_PopupSubMenuInput(pButton, m_pCurrentCommandMenu) ); + } + else if ( !strcmp( pButtonName, "!ROTATESENTRY180" ) ) + { + pButton = new BuildButton( BUILDSTATE_HASBUILDING, BuildButton::SENTRYGUN, pButtonText, 0, BUTTON_SIZE_Y * 2, CMENU_SIZE_X, BUTTON_SIZE_Y); + pButton->addActionSignal(new CMenuHandler_StringCommand("rotatesentry180")); + // Create an input signal that'll popup the current menu + pButton->addInputSignal( new CMenuHandler_PopupSubMenuInput(pButton, m_pCurrentCommandMenu) ); + } + else if ( !strcmp( pButtonName, "!ROTATESENTRY" ) ) + { + pButton = new BuildButton( BUILDSTATE_HASBUILDING, BuildButton::SENTRYGUN, pButtonText, 0, BUTTON_SIZE_Y * 2, CMENU_SIZE_X, BUTTON_SIZE_Y); + pButton->addActionSignal(new CMenuHandler_StringCommand("rotatesentry")); + // Create an input signal that'll popup the current menu + pButton->addInputSignal( new CMenuHandler_PopupSubMenuInput(pButton, m_pCurrentCommandMenu) ); + } + else if ( !strcmp( pButtonName, "!DISMANTLEDISPENSER" ) ) + { + pButton = new BuildButton( BUILDSTATE_HASBUILDING, BuildButton::DISPENSER, pButtonText, 0, BUTTON_SIZE_Y * 2, CMENU_SIZE_X, BUTTON_SIZE_Y); + pButton->addActionSignal(new CMenuHandler_StringCommand("dismantle 1")); + // Create an input signal that'll popup the current menu + pButton->addInputSignal( new CMenuHandler_PopupSubMenuInput(pButton, m_pCurrentCommandMenu) ); + } + else if ( !strcmp( pButtonName, "!DISMANTLESENTRY" ) ) + { + pButton = new BuildButton( BUILDSTATE_HASBUILDING, BuildButton::SENTRYGUN, pButtonText, 0, BUTTON_SIZE_Y * 2, CMENU_SIZE_X, BUTTON_SIZE_Y); + pButton->addActionSignal(new CMenuHandler_StringCommand("dismantle 2")); + // Create an input signal that'll popup the current menu + pButton->addInputSignal( new CMenuHandler_PopupSubMenuInput(pButton, m_pCurrentCommandMenu) ); + } + else if ( !strcmp( pButtonName, "!DETONATEDISPENSER" ) ) + { + pButton = new BuildButton( BUILDSTATE_HASBUILDING, BuildButton::DISPENSER, pButtonText, 0, BUTTON_SIZE_Y * 2, CMENU_SIZE_X, BUTTON_SIZE_Y); + pButton->addActionSignal(new CMenuHandler_StringCommand("detdispenser")); + // Create an input signal that'll popup the current menu + pButton->addInputSignal( new CMenuHandler_PopupSubMenuInput(pButton, m_pCurrentCommandMenu) ); + } + else if ( !strcmp( pButtonName, "!DETONATESENTRY" ) ) + { + pButton = new BuildButton( BUILDSTATE_HASBUILDING, BuildButton::SENTRYGUN, pButtonText, 0, BUTTON_SIZE_Y * 2, CMENU_SIZE_X, BUTTON_SIZE_Y); + pButton->addActionSignal(new CMenuHandler_StringCommand("detsentry")); + // Create an input signal that'll popup the current menu + pButton->addInputSignal( new CMenuHandler_PopupSubMenuInput(pButton, m_pCurrentCommandMenu) ); + } + // Stop building + else if ( !strcmp( pButtonName, "!BUILDSTOP" ) ) + { + pButton = new BuildButton( BUILDSTATE_BUILDING, 0, pButtonText, 0, BUTTON_SIZE_Y * 2, CMENU_SIZE_X, BUTTON_SIZE_Y); + pButton->addActionSignal(new CMenuHandler_StringCommand("build")); + // Create an input signal that'll popup the current menu + pButton->addInputSignal( new CMenuHandler_PopupSubMenuInput(pButton, m_pCurrentCommandMenu) ); + } + + return pButton; +} + +void TeamFortressViewport::ToggleServerBrowser() +{ + if (!m_iInitialized) + return; + + if ( !m_pServerBrowser ) + return; + + if ( m_pServerBrowser->isVisible() ) + { + m_pServerBrowser->setVisible( false ); + } + else + { + m_pServerBrowser->setVisible( true ); + } + + UpdateCursorState(); +} + +//======================================================================= +void TeamFortressViewport::ShowCommandMenu() +{ + if (!m_iInitialized) + return; + + // Not visible while undefined + if (g_iPlayerClass == 0) + return; + + // is the command menu open? + if ( m_pCurrentCommandMenu ) + { + HideCommandMenu(); + return; + } + + // Not visible while in intermission + if ( gHUD.m_iIntermission ) + return; + + // Recalculate visible menus + UpdateCommandMenu(); + HideVGUIMenu(); + + SetCurrentCommandMenu( m_pCommandMenus[0] ); + m_flMenuOpenTime = gHUD.m_flTime; + UpdateCursorState(); + + // get command menu parameters + for ( int i = 2; i < gEngfuncs.Cmd_Argc(); i++ ) + { + const char *param = gEngfuncs.Cmd_Argv( i - 1 ); + if ( param ) + { + if ( m_pCurrentCommandMenu->KeyInput(param[0]) ) + { + // kill the menu open time, since the key input is final + HideCommandMenu(); + } + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: Handles the key input of "-commandmenu" +// Input : +//----------------------------------------------------------------------------- +void TeamFortressViewport::InputSignalHideCommandMenu() +{ + if (!m_iInitialized) + return; + + // if they've just tapped the command menu key, leave it open + if ( (m_flMenuOpenTime + 0.3) > gHUD.m_flTime ) + return; + + HideCommandMenu(); +} + +//----------------------------------------------------------------------------- +// Purpose: Hides the command menu +//----------------------------------------------------------------------------- +void TeamFortressViewport::HideCommandMenu( void ) +{ + if (!m_iInitialized) + return; + + if ( m_pCommandMenus[0] ) + { + m_pCommandMenus[0]->ClearButtonsOfArmedState(); + } + + m_flMenuOpenTime = 0.0f; + SetCurrentCommandMenu( NULL ); + UpdateCursorState(); +} + +//----------------------------------------------------------------------------- +// Purpose: Bring up the scoreboard +//----------------------------------------------------------------------------- +void TeamFortressViewport::ShowScoreBoard( void ) +{ + if (m_pScoreBoard) + { + // No Scoreboard in single-player + if ( gEngfuncs.GetMaxClients() > 1 ) + { + m_pScoreBoard->Open(); + UpdateCursorState(); + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: Returns true if the scoreboard is up +//----------------------------------------------------------------------------- +bool TeamFortressViewport::IsScoreBoardVisible( void ) +{ + if (m_pScoreBoard) + return m_pScoreBoard->isVisible(); + + return false; +} + +//----------------------------------------------------------------------------- +// Purpose: Hide the scoreboard +//----------------------------------------------------------------------------- +void TeamFortressViewport::HideScoreBoard( void ) +{ + // Prevent removal of scoreboard during intermission + if ( gHUD.m_iIntermission ) + return; + + if (m_pScoreBoard) + { + m_pScoreBoard->setVisible(false); + UpdateCursorState(); + } +} + +//----------------------------------------------------------------------------- +// Purpose: Activate's the player special ability +// called when the player hits their "special" key +//----------------------------------------------------------------------------- +void TeamFortressViewport::InputPlayerSpecial( void ) +{ + if (!m_iInitialized) + return; + + if ( g_iPlayerClass == PC_ENGINEER || g_iPlayerClass == PC_SPY ) + { + ShowCommandMenu(); + + if ( m_pCurrentCommandMenu ) + { + m_pCurrentCommandMenu->KeyInput( '7' ); + } + } + else + { + // if it's any other class, just send the command down to the server + ClientCmd( "_special" ); + } +} + +// Set the submenu of the Command Menu +void TeamFortressViewport::SetCurrentCommandMenu( CCommandMenu *pNewMenu ) +{ + for (int i = 0; i < m_iNumMenus; i++) + m_pCommandMenus[i]->setVisible(false); + + m_pCurrentCommandMenu = pNewMenu; + + if (m_pCurrentCommandMenu) + m_pCurrentCommandMenu->MakeVisible( NULL ); +} + +void TeamFortressViewport::UpdateCommandMenu() +{ + m_pCommandMenus[0]->RecalculateVisibles( 0, false ); + m_pCommandMenus[0]->RecalculatePositions( 0 ); +} + +void TeamFortressViewport::UpdateSpectatorMenu() +{ + char sz[64]; + + if (!m_pSpectatorMenu) + return; + + if (m_iUser1) + { + m_pSpectatorMenu->setVisible( true ); + + if (m_iUser2 > 0) + { + // Locked onto a target, show the player's name + sprintf(sz, "#Spec_Mode%d : %s", m_iUser1, g_PlayerInfoList[ m_iUser2 ].name); + m_pSpectatorLabel->setText( CHudTextMessage::BufferedLocaliseTextString( sz ) ); + } + else + { + sprintf(sz, "#Spec_Mode%d", m_iUser1); + m_pSpectatorLabel->setText( CHudTextMessage::BufferedLocaliseTextString( sz ) ); + } + } + else + { + m_pSpectatorMenu->setVisible( false ); + } +} + +//====================================================================== +void TeamFortressViewport::CreateScoreBoard( void ) +{ + m_pScoreBoard = new ScorePanel(SBOARD_INDENT_X,SBOARD_INDENT_Y, ScreenWidth - (SBOARD_INDENT_X * 2), ScreenHeight - (SBOARD_INDENT_Y * 2)); + m_pScoreBoard->setParent(this); + m_pScoreBoard->setVisible(false); +} + +void TeamFortressViewport::CreateServerBrowser( void ) +{ + m_pServerBrowser = new ServerBrowser( 0, 0, ScreenWidth, ScreenHeight ); + m_pServerBrowser->setParent(this); + m_pServerBrowser->setVisible(false); +} + + +//====================================================================== +// Set the VGUI Menu +void TeamFortressViewport::SetCurrentMenu( CMenuPanel *pMenu ) +{ + m_pCurrentMenu = pMenu; + if ( m_pCurrentMenu ) + { + // Don't open menus in demo playback + if ( gEngfuncs.pDemoAPI->IsPlayingback() ) + return; + + m_pCurrentMenu->Open(); + } +} + +//================================================================ +// Text Window +CMenuPanel* TeamFortressViewport::CreateTextWindow( int iTextToShow ) +{ + char sz[256]; + char *cText; + char *pfile = NULL; + static const int MAX_TITLE_LENGTH = 32; + char cTitle[MAX_TITLE_LENGTH]; + + if ( iTextToShow == SHOW_MOTD ) + { + if (!m_szServerName || !m_szServerName[0]) + strcpy( cTitle, "Half-Life" ); + else + strncpy( cTitle, m_szServerName, MAX_TITLE_LENGTH ); + cTitle[MAX_TITLE_LENGTH-1] = 0; + cText = m_szMOTD; + } + else if ( iTextToShow == SHOW_MAPBRIEFING ) + { + // Get the current mapname, and open it's map briefing text + if (m_sMapName && m_sMapName[0]) + { + strcpy( sz, "maps/"); + strcat( sz, m_sMapName ); + strcat( sz, ".txt" ); + } + else + { + const char *level = gEngfuncs.pfnGetLevelName(); + if (!level) + return NULL; + + strcpy( sz, level ); + char *ch = strchr( sz, '.' ); + *ch = '\0'; + strcat( sz, ".txt" ); + + // pull out the map name + strcpy( m_sMapName, level ); + ch = strchr( m_sMapName, '.' ); + if ( ch ) + { + *ch = 0; + } + + ch = strchr( m_sMapName, '/' ); + if ( ch ) + { + // move the string back over the '/' + memmove( m_sMapName, ch+1, strlen(ch)+1 ); + } + } + + pfile = (char*)gEngfuncs.COM_LoadFile( sz, 5, NULL ); + + if (!pfile) + return NULL; + + cText = pfile; + + strncpy( cTitle, m_sMapName, MAX_TITLE_LENGTH ); + cTitle[MAX_TITLE_LENGTH-1] = 0; + } + else if ( iTextToShow == SHOW_CLASSDESC ) + { + switch ( g_iPlayerClass ) + { + case PC_SCOUT: cText = CHudTextMessage::BufferedLocaliseTextString( "#Help_scout" ); + CHudTextMessage::LocaliseTextString( "#Title_scout", cTitle, MAX_TITLE_LENGTH ); break; + case PC_SNIPER: cText = CHudTextMessage::BufferedLocaliseTextString( "#Help_sniper" ); + CHudTextMessage::LocaliseTextString( "#Title_sniper", cTitle, MAX_TITLE_LENGTH ); break; + case PC_SOLDIER: cText = CHudTextMessage::BufferedLocaliseTextString( "#Help_soldier" ); + CHudTextMessage::LocaliseTextString( "#Title_soldier", cTitle, MAX_TITLE_LENGTH ); break; + case PC_DEMOMAN: cText = CHudTextMessage::BufferedLocaliseTextString( "#Help_demoman" ); + CHudTextMessage::LocaliseTextString( "#Title_demoman", cTitle, MAX_TITLE_LENGTH ); break; + case PC_MEDIC: cText = CHudTextMessage::BufferedLocaliseTextString( "#Help_medic" ); + CHudTextMessage::LocaliseTextString( "#Title_medic", cTitle, MAX_TITLE_LENGTH ); break; + case PC_HVYWEAP: cText = CHudTextMessage::BufferedLocaliseTextString( "#Help_hwguy" ); + CHudTextMessage::LocaliseTextString( "#Title_hwguy", cTitle, MAX_TITLE_LENGTH ); break; + case PC_PYRO: cText = CHudTextMessage::BufferedLocaliseTextString( "#Help_pyro" ); + CHudTextMessage::LocaliseTextString( "#Title_pyro", cTitle, MAX_TITLE_LENGTH ); break; + case PC_SPY: cText = CHudTextMessage::BufferedLocaliseTextString( "#Help_spy" ); + CHudTextMessage::LocaliseTextString( "#Title_spy", cTitle, MAX_TITLE_LENGTH ); break; + case PC_ENGINEER: cText = CHudTextMessage::BufferedLocaliseTextString( "#Help_engineer" ); + CHudTextMessage::LocaliseTextString( "#Title_engineer", cTitle, MAX_TITLE_LENGTH ); break; + case PC_CIVILIAN: cText = CHudTextMessage::BufferedLocaliseTextString( "#Help_civilian" ); + CHudTextMessage::LocaliseTextString( "#Title_civilian", cTitle, MAX_TITLE_LENGTH ); break; + default: + return NULL; + } + + if ( g_iPlayerClass == PC_CIVILIAN ) + { + sprintf(sz, "classes/long_civilian.txt"); + } + else + { + sprintf(sz, "classes/long_%s.txt", sTFClassSelection[ g_iPlayerClass ]); + } + char *pfile = (char*)gEngfuncs.COM_LoadFile( sz, 5, NULL ); + if (pfile) + { + cText = pfile; + } + } + + // if we're in the game (ie. have selected a class), flag the menu to be only grayed in the dialog box, instead of full screen + CMenuPanel *pMOTDPanel = CMessageWindowPanel_Create( cText, cTitle, g_iPlayerClass == PC_UNDEFINED, false, 0, 0, ScreenWidth, ScreenHeight ); + pMOTDPanel->setParent( this ); + + if ( pfile ) + gEngfuncs.COM_FreeFile( pfile ); + + return pMOTDPanel; +} + +//================================================================ +// VGUI Menus +void TeamFortressViewport::ShowVGUIMenu( int iMenu ) +{ + CMenuPanel *pNewMenu = NULL; + + // Don't open menus in demo playback + if ( gEngfuncs.pDemoAPI->IsPlayingback() ) + return; + + // Don't create one if it's already in the list + if (m_pCurrentMenu) + { + CMenuPanel *pMenu = m_pCurrentMenu; + while (pMenu != NULL) + { + if (pMenu->GetMenuID() == iMenu) + return; + pMenu = pMenu->GetNextMenu(); + } + } + + switch ( iMenu ) + { + case MENU_TEAM: + pNewMenu = ShowTeamMenu(); + break; + + // Map Briefing removed now that it appears in the team menu + case MENU_MAPBRIEFING: + pNewMenu = CreateTextWindow( SHOW_MAPBRIEFING ); + break; + + case MENU_INTRO: + pNewMenu = CreateTextWindow( SHOW_MOTD ); + break; + + case MENU_CLASSHELP: + pNewMenu = CreateTextWindow( SHOW_CLASSDESC ); + break; + + case MENU_CLASS: + pNewMenu = ShowClassMenu(); + break; + + default: + break; + } + + if (!pNewMenu) + return; + + // Close the Command Menu if it's open + HideCommandMenu(); + + pNewMenu->SetMenuID( iMenu ); + pNewMenu->SetActive( true ); + + // See if another menu is visible, and if so, cache this one for display once the other one's finished + if (m_pCurrentMenu) + { + m_pCurrentMenu->SetNextMenu( pNewMenu ); + } + else + { + m_pCurrentMenu = pNewMenu; + m_pCurrentMenu->Open(); + UpdateCursorState(); + } +} + +// Removes all VGUI Menu's onscreen +void TeamFortressViewport::HideVGUIMenu() +{ + while (m_pCurrentMenu) + { + HideTopMenu(); + } +} + +// Remove the top VGUI menu, and bring up the next one +void TeamFortressViewport::HideTopMenu() +{ + if (m_pCurrentMenu) + { + // Close the top one + m_pCurrentMenu->Close(); + + // Bring up the next one + gViewPort->SetCurrentMenu( m_pCurrentMenu->GetNextMenu() ); + } + + UpdateCursorState(); +} + +// Return TRUE if the HUD's allowed to print text messages +bool TeamFortressViewport::AllowedToPrintText( void ) +{ + // Prevent text messages when fullscreen menus are up + if ( m_pCurrentMenu && g_iPlayerClass == 0 ) + { + int iId = m_pCurrentMenu->GetMenuID(); + if ( iId == MENU_TEAM || iId == MENU_CLASS || iId == MENU_INTRO || iId == MENU_CLASSHELP ) + return FALSE; + } + + return TRUE; +} + +//====================================================================================== +// TEAM MENU +//====================================================================================== +// Bring up the Team selection Menu +CMenuPanel* TeamFortressViewport::ShowTeamMenu() +{ + // Don't open menus in demo playback + if ( gEngfuncs.pDemoAPI->IsPlayingback() ) + return NULL; + + m_pTeamMenu->Reset(); + return m_pTeamMenu; +} + +void TeamFortressViewport::CreateTeamMenu() +{ + // Create the panel + m_pTeamMenu = new CTeamMenuPanel(100, false, 0, 0, ScreenWidth, ScreenHeight); + m_pTeamMenu->setParent( this ); + m_pTeamMenu->setVisible( false ); +} + +//====================================================================================== +// CLASS MENU +//====================================================================================== +// Bring up the Class selection Menu +CMenuPanel* TeamFortressViewport::ShowClassMenu() +{ + // Don't open menus in demo playback + if ( gEngfuncs.pDemoAPI->IsPlayingback() ) + return NULL; + + m_pClassMenu->Reset(); + return m_pClassMenu; +} + +void TeamFortressViewport::CreateClassMenu() +{ + // Create the panel + m_pClassMenu = new CClassMenuPanel(100, false, 0, 0, ScreenWidth, ScreenHeight); + m_pClassMenu->setParent(this); + m_pClassMenu->setVisible( false ); +} + +//====================================================================================== +// SPECTATOR MENU +//====================================================================================== +// Spectator "Menu" explaining the Spectator buttons +void TeamFortressViewport::CreateSpectatorMenu() +{ + // Create the Panel + m_pSpectatorMenu = new CTransparentPanel(100, 0, ScreenHeight - YRES(60), ScreenWidth, YRES(60)); + m_pSpectatorMenu->setParent(this); + m_pSpectatorMenu->setVisible(false); + + // Get the scheme used for the Titles + CSchemeManager *pSchemes = gViewPort->GetSchemeManager(); + + // schemes + SchemeHandle_t hTitleScheme = pSchemes->getSchemeHandle( "Title Font" ); + SchemeHandle_t hHelpText = pSchemes->getSchemeHandle( "Primary Button Text" ); + + // color schemes + int r, g, b, a; + + // Create the title + m_pSpectatorLabel = new Label( "Spectator", 0, 0, ScreenWidth, YRES(25) ); + m_pSpectatorLabel->setParent( m_pSpectatorMenu ); + m_pSpectatorLabel->setFont( pSchemes->getFont(hTitleScheme) ); + pSchemes->getFgColor( hTitleScheme, r, g, b, a ); + m_pSpectatorLabel->setFgColor( r, g, b, a ); + pSchemes->getBgColor( hTitleScheme, r, g, b, a ); + m_pSpectatorLabel->setBgColor( r, g, b, 255 ); + m_pSpectatorLabel->setContentAlignment( vgui::Label::a_north ); + + // Create the Help + Label *pLabel = new Label( CHudTextMessage::BufferedLocaliseTextString( "#Spec_Help" ), 0, YRES(25), ScreenWidth, YRES(15) ); + pLabel->setParent( m_pSpectatorMenu ); + pLabel->setFont( pSchemes->getFont(hHelpText) ); + pSchemes->getFgColor( hHelpText, r, g, b, a ); + pLabel->setFgColor( r, g, b, a ); + pSchemes->getBgColor( hHelpText, r, g, b, a ); + pLabel->setBgColor( r, g, b, 255 ); + pLabel->setContentAlignment( vgui::Label::a_north ); + + pLabel = new Label( CHudTextMessage::BufferedLocaliseTextString( "#Spec_Help2" ), 0, YRES(40), ScreenWidth, YRES(20) ); + pLabel->setParent( m_pSpectatorMenu ); + pLabel->setFont( pSchemes->getFont(hHelpText) ); + pSchemes->getFgColor( hHelpText, r, g, b, a ); + pLabel->setFgColor( r, g, b, a ); + pSchemes->getBgColor( hHelpText, r, g, b, a ); + pLabel->setBgColor( r, g, b, 255 ); + pLabel->setContentAlignment( vgui::Label::a_center ); +} + +//====================================================================================== +// UPDATE HUD SECTIONS +//====================================================================================== +// We've got an update on player info +// Recalculate any menus that use it. +void TeamFortressViewport::UpdateOnPlayerInfo() +{ + if (m_pTeamMenu) + m_pTeamMenu->Update(); + if (m_pClassMenu) + m_pClassMenu->Update(); + if (m_pScoreBoard) + m_pScoreBoard->Update(); +} + +void TeamFortressViewport::UpdateCursorState() +{ + // Need cursor if any VGUI window is up + if ( m_pCurrentMenu || m_pTeamMenu->isVisible() || m_pServerBrowser->isVisible() ) + { + g_iVisibleMouse = true; + App::getInstance()->setCursorOveride( App::getInstance()->getScheme()->getCursor(Scheme::SchemeCursor::scu_arrow) ); + return; + } + else if ( m_pCurrentCommandMenu ) + { + // commandmenu doesn't have cursor if hud_capturemouse is turned off + if ( gHUD.m_pCvarStealMouse->value != 0.0f ) + { + g_iVisibleMouse = true; + App::getInstance()->setCursorOveride( App::getInstance()->getScheme()->getCursor(Scheme::SchemeCursor::scu_arrow) ); + return; + } + } + + IN_ResetMouse(); + g_iVisibleMouse = false; + App::getInstance()->setCursorOveride( App::getInstance()->getScheme()->getCursor(Scheme::SchemeCursor::scu_none) ); +} + +void TeamFortressViewport::UpdateHighlights() +{ + if (m_pCurrentCommandMenu) + m_pCurrentCommandMenu->MakeVisible( NULL ); +} + +void TeamFortressViewport::GetAllPlayersInfo( void ) +{ + for ( int i = 1; i < MAX_PLAYERS; i++ ) + { + GetPlayerInfo( i, &g_PlayerInfoList[i] ); + + if ( g_PlayerInfoList[i].thisplayer ) + m_pScoreBoard->m_iPlayerNum = i; // !!!HACK: this should be initialized elsewhere... maybe gotten from the engine + } +} + +void TeamFortressViewport::paintBackground() +{ + // See if the command menu is visible and needs recalculating due to some external change + if ( g_iTeamNumber != m_iCurrentTeamNumber ) + { + UpdateCommandMenu(); + + if ( m_pClassMenu ) + { + m_pClassMenu->Update(); + } + + m_iCurrentTeamNumber = g_iTeamNumber; + } + + if ( g_iPlayerClass != m_iCurrentPlayerClass ) + { + UpdateCommandMenu(); + + m_iCurrentPlayerClass = g_iPlayerClass; + } + + // See if the Spectator Menu needs to be update + if ( g_iUser1 != m_iUser1 || g_iUser2 != m_iUser2 ) + { + m_iUser1 = g_iUser1; + m_iUser2 = g_iUser2; + UpdateSpectatorMenu(); + } + + // Update the Scoreboard, if it's visible + if ( m_pScoreBoard->isVisible() && (m_flScoreBoardLastUpdated < gHUD.m_flTime) ) + { + m_pScoreBoard->Update(); + m_flScoreBoardLastUpdated = gHUD.m_flTime + 0.5; + } + + int extents[4]; + getAbsExtents(extents[0],extents[1],extents[2],extents[3]); + VGui_ViewportPaintBackground(extents); +} + +//================================================================ +// Input Handler for Drag N Drop panels +void CDragNDropHandler::cursorMoved(int x,int y,Panel* panel) +{ + if(m_bDragging) + { + App::getInstance()->getCursorPos(x,y); + m_pPanel->setPos(m_iaDragOrgPos[0]+(x-m_iaDragStart[0]),m_iaDragOrgPos[1]+(y-m_iaDragStart[1])); + + if(m_pPanel->getParent()!=null) + { + m_pPanel->getParent()->repaint(); + } + } +} + +void CDragNDropHandler::mousePressed(MouseCode code,Panel* panel) +{ + int x,y; + App::getInstance()->getCursorPos(x,y); + m_bDragging=true; + m_iaDragStart[0]=x; + m_iaDragStart[1]=y; + m_pPanel->getPos(m_iaDragOrgPos[0],m_iaDragOrgPos[1]); + App::getInstance()->setMouseCapture(panel); + + m_pPanel->setDragged(m_bDragging); + m_pPanel->requestFocus(); +} + +void CDragNDropHandler::mouseReleased(MouseCode code,Panel* panel) +{ + m_bDragging=false; + m_pPanel->setDragged(m_bDragging); + App::getInstance()->setMouseCapture(null); +} + +//================================================================ +// Number Key Input +bool TeamFortressViewport::SlotInput( int iSlot ) +{ + // If there's a menu up, give it the input + if ( m_pCurrentMenu ) + return m_pCurrentMenu->SlotInput( iSlot ); + + return FALSE; +} + +// Direct Key Input +int TeamFortressViewport::KeyInput( int down, int keynum, const char *pszCurrentBinding ) +{ + // Enter gets out of Spectator Mode by bringing up the Team Menu + if (m_iUser1 && gEngfuncs.Con_IsVisible() == false ) + { + if ( down && (keynum == K_ENTER || keynum == K_KP_ENTER) ) + ShowVGUIMenu( MENU_TEAM ); + } + + // Open Text Window? + if (m_pCurrentMenu && gEngfuncs.Con_IsVisible() == false) + { + int iMenuID = m_pCurrentMenu->GetMenuID(); + + // Get number keys as Input for Team/Class menus + if (iMenuID == MENU_TEAM || iMenuID == MENU_CLASS) + { + // Escape gets you out of Team/Class menus if the Cancel button is visible + if ( keynum == K_ESCAPE ) + { + if ( (iMenuID == MENU_TEAM && g_iTeamNumber) || (iMenuID == MENU_CLASS && g_iPlayerClass) ) + { + HideTopMenu(); + return 0; + } + } + + for (int i = '0'; i <= '9'; i++) + { + if ( down && (keynum == i) ) + { + SlotInput( i - '0' ); + return 0; + } + } + } + + // Grab enter keys to close TextWindows + if ( down && (keynum == K_ENTER || keynum == K_KP_ENTER || keynum == K_SPACE || keynum == K_ESCAPE) ) + { + if ( iMenuID == MENU_MAPBRIEFING || iMenuID == MENU_INTRO || iMenuID == MENU_CLASSHELP ) + { + HideTopMenu(); + return 0; + } + } + + // Grab jump key on Team Menu as autoassign + if ( pszCurrentBinding && down && !strcmp(pszCurrentBinding, "+jump") ) + { + if (iMenuID == MENU_TEAM) + { + m_pTeamMenu->SlotInput(5); + return 0; + } + } + + } + + // if we're in a command menu, try hit one of it's buttons + if ( down && m_pCurrentCommandMenu ) + { + // Escape hides the command menu + if ( keynum == K_ESCAPE ) + { + HideCommandMenu(); + return 0; + } + + // only trap the number keys + if ( keynum >= '0' && keynum <= '9' ) + { + if ( m_pCurrentCommandMenu->KeyInput(keynum) ) + { + // a final command has been issued, so close the command menu + HideCommandMenu(); + } + + return 0; + } + } + + return 1; +} + +//================================================================ +// Message Handlers +int TeamFortressViewport::MsgFunc_ValClass(const char *pszName, int iSize, void *pbuf ) +{ + BEGIN_READ( pbuf, iSize ); + + for (int i = 0; i < 5; i++) + m_iValidClasses[i] = READ_SHORT(); + + // Force the menu to update + UpdateCommandMenu(); + + return 1; +} + +int TeamFortressViewport::MsgFunc_TeamNames(const char *pszName, int iSize, void *pbuf ) +{ + BEGIN_READ( pbuf, iSize ); + + m_iNumberOfTeams = READ_BYTE(); + + for (int i = 0; i < m_iNumberOfTeams; i++) + { + int teamNum = i + 1; + + gHUD.m_TextMessage.LocaliseTextString( READ_STRING(), m_sTeamNames[teamNum], MAX_TEAMNAME_SIZE ); + + // Set the team name buttons + if (m_pTeamButtons[i]) + m_pTeamButtons[i]->setText( m_sTeamNames[teamNum] ); + + // Set the disguise buttons + if (m_pDisguiseButtons[i]) + m_pDisguiseButtons[i]->setText( m_sTeamNames[teamNum] ); + } + + // Update the Team Menu + if (m_pTeamMenu) + m_pTeamMenu->Update(); + + return 1; +} + +int TeamFortressViewport::MsgFunc_Feign(const char *pszName, int iSize, void *pbuf ) +{ + BEGIN_READ( pbuf, iSize ); + + m_iIsFeigning = READ_BYTE(); + + // Force the menu to update + UpdateCommandMenu(); + + return 1; +} + +int TeamFortressViewport::MsgFunc_Detpack(const char *pszName, int iSize, void *pbuf ) +{ + BEGIN_READ( pbuf, iSize ); + + m_iIsSettingDetpack = READ_BYTE(); + + // Force the menu to update + UpdateCommandMenu(); + + return 1; +} + +int TeamFortressViewport::MsgFunc_VGUIMenu(const char *pszName, int iSize, void *pbuf ) +{ + BEGIN_READ( pbuf, iSize ); + + int iMenu = READ_BYTE(); + + // Map briefing includes the name of the map (because it's sent down before the client knows what map it is) + if (iMenu == MENU_MAPBRIEFING) + { + strncpy( m_sMapName, READ_STRING(), sizeof(m_sMapName) ); + m_sMapName[ sizeof(m_sMapName) - 1 ] = '\0'; + } + + // Bring up the menu6 + ShowVGUIMenu( iMenu ); + + return 1; +} + +int TeamFortressViewport::MsgFunc_MOTD( const char *pszName, int iSize, void *pbuf ) +{ + if (m_iGotAllMOTD) + m_szMOTD[0] = 0; + + BEGIN_READ( pbuf, iSize ); + + m_iGotAllMOTD = READ_BYTE(); + strncat( m_szMOTD, READ_STRING(), sizeof(m_szMOTD) - strlen(m_szMOTD) ); + m_szMOTD[ sizeof(m_szMOTD)-1 ] = '\0'; + + if ( m_iGotAllMOTD ) + { + ShowVGUIMenu( MENU_INTRO ); + } + + return 1; +} + +int TeamFortressViewport::MsgFunc_BuildSt( const char *pszName, int iSize, void *pbuf ) +{ + BEGIN_READ( pbuf, iSize ); + + m_iBuildState = READ_BYTE(); + + // Force the menu to update + UpdateCommandMenu(); + + return 1; +} + +int TeamFortressViewport::MsgFunc_RandomPC( const char *pszName, int iSize, void *pbuf ) +{ + BEGIN_READ( pbuf, iSize ); + + m_iRandomPC = READ_BYTE(); + + return 1; +} + +int TeamFortressViewport::MsgFunc_ServerName( const char *pszName, int iSize, void *pbuf ) +{ + BEGIN_READ( pbuf, iSize ); + + strncpy( m_szServerName, READ_STRING(), MAX_SERVERNAME_LENGTH ); + + return 1; +} + +int TeamFortressViewport::MsgFunc_ScoreInfo( const char *pszName, int iSize, void *pbuf ) +{ + BEGIN_READ( pbuf, iSize ); + short cl = READ_BYTE(); + short frags = READ_SHORT(); + short deaths = READ_SHORT(); + short playerclass = READ_SHORT(); + short teamnumber = READ_SHORT(); + + if ( cl > 0 && cl <= MAX_PLAYERS ) + { + g_PlayerExtraInfo[cl].frags = frags; + g_PlayerExtraInfo[cl].deaths = deaths; + g_PlayerExtraInfo[cl].playerclass = playerclass; + g_PlayerExtraInfo[cl].teamnumber = teamnumber; + + UpdateOnPlayerInfo(); + } + + return 1; +} + +// Message handler for TeamScore message +// accepts three values: +// string: team name +// short: teams kills +// short: teams deaths +// if this message is never received, then scores will simply be the combined totals of the players. +int TeamFortressViewport::MsgFunc_TeamScore( const char *pszName, int iSize, void *pbuf ) +{ + BEGIN_READ( pbuf, iSize ); + char *TeamName = READ_STRING(); + + // find the team matching the name + for ( int i = 1; i <= m_pScoreBoard->m_iNumTeams; i++ ) + { + if ( !stricmp( TeamName, g_TeamInfo[i].name ) ) + break; + } + + if ( i > m_pScoreBoard->m_iNumTeams ) + return 1; + + // use this new score data instead of combined player scoresw + g_TeamInfo[i].scores_overriden = TRUE; + g_TeamInfo[i].frags = READ_SHORT(); + g_TeamInfo[i].deaths = READ_SHORT(); + + return 1; +} + +// Message handler for TeamInfo message +// accepts two values: +// byte: client number +// string: client team name +int TeamFortressViewport::MsgFunc_TeamInfo( const char *pszName, int iSize, void *pbuf ) +{ + if (!m_pScoreBoard) + return 1; + + BEGIN_READ( pbuf, iSize ); + short cl = READ_BYTE(); + + if ( cl > 0 && cl <= MAX_PLAYERS ) + { + // set the players team + strncpy( g_PlayerExtraInfo[cl].teamname, READ_STRING(), MAX_TEAM_NAME ); + } + + // rebuild the list of teams + m_pScoreBoard->RebuildTeams(); + + return 1; +} + +void TeamFortressViewport::DeathMsg( int killer, int victim ) +{ + m_pScoreBoard->DeathMsg(killer,victim); +} + +int TeamFortressViewport::MsgFunc_Spectator( const char *pszName, int iSize, void *pbuf ) +{ + BEGIN_READ( pbuf, iSize ); + + short cl = READ_BYTE(); + if ( cl > 0 && cl <= MAX_PLAYERS ) + { + g_IsSpectator[cl] = READ_BYTE(); + } + + return 1; +} + +int TeamFortressViewport::MsgFunc_AllowSpec( const char *pszName, int iSize, void *pbuf ) +{ + BEGIN_READ( pbuf, iSize ); + + m_iAllowSpectators = READ_BYTE(); + + // Force the menu to update + UpdateCommandMenu(); + + // If the team menu is up, update it too + if (m_pTeamMenu) + m_pTeamMenu->Update(); + + return 1; +} diff --git a/cl_dll/vgui_TeamFortressViewport.h b/cl_dll/vgui_TeamFortressViewport.h new file mode 100644 index 0000000..61257fa --- /dev/null +++ b/cl_dll/vgui_TeamFortressViewport.h @@ -0,0 +1,1255 @@ + +#ifndef TEAMFORTRESSVIEWPORT_H +#define TEAMFORTRESSVIEWPORT_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// custom scheme handling +#include "vgui_SchemeManager.h" + +#define TF_DEFS_ONLY +#include "tf_defs.h" + +using namespace vgui; + +class Cursor; +class ScorePanel; +class CCommandMenu; +class CommandLabel; +class CommandButton; +class BuildButton; +class ClassButton; +class CMenuPanel; +class ServerBrowser; +class DragNDropPanel; +class CTransparentPanel; +class CClassMenuPanel; +class CTeamMenuPanel; + +char* GetVGUITGAName(const char *pszName); +BitmapTGA *LoadTGA( const char* pImageName ); +void ScaleColors( int &r, int &g, int &b, int a ); +extern char *sTFClassSelection[]; +extern int sTFValidClassInts[]; +extern char *sLocalisedClasses[]; +extern int iTeamColors[5][3]; + +#define MAX_SERVERNAME_LENGTH 32 + +// Use this to set any co-ords in 640x480 space +#define XRES(x) (x * ((float)ScreenWidth / 640)) +#define YRES(y) (y * ((float)ScreenHeight / 480)) + +// Command Menu positions +#define MAX_MENUS 40 +#define MAX_BUTTONS 100 + +#define BUTTON_SIZE_Y YRES(30) +#define CMENU_SIZE_X XRES(160) + +#define SUBMENU_SIZE_X (CMENU_SIZE_X / 8) +#define SUBMENU_SIZE_Y (BUTTON_SIZE_Y / 6) + +#define CMENU_TOP (BUTTON_SIZE_Y * 4) + +#define MAX_TEAMNAME_SIZE 64 +#define MAX_BUTTON_SIZE 32 + +// Map Briefing Window +#define MAPBRIEF_INDENT 30 + +// Team Menu +#define TMENU_INDENT_X (30 * ((float)ScreenHeight / 640)) +#define TMENU_HEADER 100 +#define TMENU_SIZE_X (ScreenWidth - (TMENU_INDENT_X * 2)) +#define TMENU_SIZE_Y (TMENU_HEADER + BUTTON_SIZE_Y * 7) +#define TMENU_PLAYER_INDENT (((float)TMENU_SIZE_X / 3) * 2) +#define TMENU_INDENT_Y (((float)ScreenHeight - TMENU_SIZE_Y) / 2) + +// Class Menu +#define CLMENU_INDENT_X (30 * ((float)ScreenHeight / 640)) +#define CLMENU_HEADER 100 +#define CLMENU_SIZE_X (ScreenWidth - (CLMENU_INDENT_X * 2)) +#define CLMENU_SIZE_Y (CLMENU_HEADER + BUTTON_SIZE_Y * 11) +#define CLMENU_PLAYER_INDENT (((float)CLMENU_SIZE_X / 3) * 2) +#define CLMENU_INDENT_Y (((float)ScreenHeight - CLMENU_SIZE_Y) / 2) + +// Arrows +enum +{ + ARROW_UP, + ARROW_DOWN, + ARROW_LEFT, + ARROW_RIGHT, +}; + +//============================================================================== +// VIEWPORT PIECES +//============================================================ +// Wrapper for an Image Label without a background +class CImageLabel : public Label +{ +public: + BitmapTGA *m_pTGA; + +public: + CImageLabel( const char* pImageName,int x,int y ); + CImageLabel( const char* pImageName,int x,int y,int wide,int tall ); + + virtual int getImageTall(); + virtual int getImageWide(); + + virtual void paintBackground() + { + // Do nothing, so the background's left transparent. + } +}; + +// Command Label +// Overridden label so we can darken it when submenus open +class CommandLabel : public Label +{ +private: + int m_iState; + +public: + CommandLabel(const char* text,int x,int y,int wide,int tall) : Label(text,x,y,wide,tall) + { + m_iState = false; + } + + void PushUp() + { + m_iState = false; + repaint(); + } + + void PushDown() + { + m_iState = true; + repaint(); + } +}; + +//============================================================ +// Command Buttons +class CommandButton : public Button +{ +private: + int m_iPlayerClass; + + // Submenus under this button + CCommandMenu *m_pSubMenu; + CCommandMenu *m_pParentMenu; + CommandLabel *m_pSubLabel; + + char m_sMainText[MAX_BUTTON_SIZE]; + char m_cBoundKey; + + SchemeHandle_t m_hTextScheme; + + void RecalculateText( void ); + +public: + bool m_bNoHighlight; + +public: + // Constructors + CommandButton( const char* text,int x,int y,int wide,int tall, bool bNoHighlight = false); + CommandButton( int iPlayerClass, const char* text,int x,int y,int wide,int tall); + + void Init( void ); + + // Menu Handling + void AddSubMenu( CCommandMenu *pNewMenu ); + void AddSubLabel( CommandLabel *pSubLabel ) + { + m_pSubLabel = pSubLabel; + } + + virtual int IsNotValid( void ) + { + return false; + } + + void UpdateSubMenus( int iAdjustment ); + int GetPlayerClass() { return m_iPlayerClass; }; + CCommandMenu *GetSubMenu() { return m_pSubMenu; }; + + CCommandMenu *getParentMenu( void ); + void setParentMenu( CCommandMenu *pParentMenu ); + + // Overloaded vgui functions + virtual void paint(); + virtual void setText( const char *text ); + virtual void paintBackground(); + + void cursorEntered( void ); + void cursorExited( void ); + + void setBoundKey( char boundKey ); + char getBoundKey( void ); +}; + +//============================================================ +// Command Menus +class CCommandMenu : public Panel +{ +private: + CCommandMenu *m_pParentMenu; + int m_iXOffset; + int m_iYOffset; + + // Buttons in this menu + CommandButton *m_aButtons[ MAX_BUTTONS ]; + int m_iButtons; + +public: + CCommandMenu( CCommandMenu *pParentMenu, int x,int y,int wide,int tall ) : Panel(x,y,wide,tall) + { + m_pParentMenu = pParentMenu; + m_iXOffset = x; + m_iYOffset = y; + m_iButtons = 0; + } + + void AddButton( CommandButton *pButton ); + bool RecalculateVisibles( int iNewYPos, bool bHideAll ); + void RecalculatePositions( int iYOffset ); + void MakeVisible( CCommandMenu *pChildMenu ); + + CCommandMenu *GetParentMenu() { return m_pParentMenu; }; + int GetXOffset() { return m_iXOffset; }; + int GetYOffset() { return m_iYOffset; }; + int GetNumButtons() { return m_iButtons; }; + CommandButton *FindButtonWithSubmenu( CCommandMenu *pSubMenu ); + + void ClearButtonsOfArmedState( void ); + + + bool KeyInput( int keyNum ); + + virtual void paintBackground(); +}; + +//============================================================================== +class TeamFortressViewport : public Panel +{ +private: + vgui::Cursor* _cursorNone; + vgui::Cursor* _cursorArrow; + + int m_iInitialized; + + CCommandMenu *m_pCommandMenus[ MAX_MENUS ]; + CCommandMenu *m_pCurrentCommandMenu; + float m_flMenuOpenTime; + float m_flScoreBoardLastUpdated; + int m_iNumMenus; + int m_iCurrentTeamNumber; + int m_iCurrentPlayerClass; + int m_iUser1; + int m_iUser2; + + // VGUI Menus + void CreateTeamMenu( void ); + CMenuPanel* ShowTeamMenu( void ); + void CreateClassMenu( void ); + CMenuPanel* ShowClassMenu( void ); + void CreateSpectatorMenu( void ); + + // Scheme handler + CSchemeManager m_SchemeManager; + + // MOTD + int m_iGotAllMOTD; + char m_szMOTD[ MAX_MOTD_LENGTH ]; + + // Command Menu Team buttons + CommandButton *m_pTeamButtons[6]; + CommandButton *m_pDisguiseButtons[5]; + BuildButton *m_pBuildButtons[3]; + BuildButton *m_pBuildActiveButtons[3]; + + // Server Browser + ServerBrowser *m_pServerBrowser; + + // Spectator "menu" + CTransparentPanel *m_pSpectatorMenu; + Label *m_pSpectatorLabel; + int m_iAllowSpectators; + + // Data for specific sections of the Command Menu + int m_iValidClasses[5]; + int m_iIsFeigning; + int m_iIsSettingDetpack; + int m_iNumberOfTeams; + int m_iBuildState; + int m_iRandomPC; + char m_sTeamNames[5][MAX_TEAMNAME_SIZE]; + + // Localisation strings + char m_sDetpackStrings[3][MAX_BUTTON_SIZE]; + + char m_sMapName[64]; +public: + TeamFortressViewport(int x,int y,int wide,int tall); + void Initialize( void ); + + void CreateCommandMenu( void ); + void CreateScoreBoard( void ); + void CreateServerBrowser( void ); + CommandButton *CreateCustomButton( char *pButtonText, char *pButtonName ); + CCommandMenu *CreateDisguiseSubmenu( CommandButton *pButton, CCommandMenu *pParentMenu, const char *commandText ); + + void UpdateCursorState( void ); + void UpdateCommandMenu( void ); + void UpdateOnPlayerInfo( void ); + void UpdateHighlights( void ); + void UpdateSpectatorMenu( void ); + + int KeyInput( int down, int keynum, const char *pszCurrentBinding ); + void InputPlayerSpecial( void ); + void GetAllPlayersInfo( void ); + void DeathMsg( int killer, int victim ); + + void ShowCommandMenu( void ); + void InputSignalHideCommandMenu( void ); + void HideCommandMenu( void ); + void SetCurrentCommandMenu( CCommandMenu *pNewMenu ); + void SetCurrentMenu( CMenuPanel *pMenu ); + + void ShowScoreBoard( void ); + void HideScoreBoard( void ); + bool IsScoreBoardVisible( void ); + + bool AllowedToPrintText( void ); + + void ShowVGUIMenu( int iMenu ); + void HideVGUIMenu( void ); + void HideTopMenu( void ); + + void ToggleServerBrowser( void ); + + CMenuPanel* CreateTextWindow( int iTextToShow ); + + CCommandMenu *CreateSubMenu( CommandButton *pButton, CCommandMenu *pParentMenu ); + + // Data Handlers + int GetValidClasses(int iTeam) { return m_iValidClasses[iTeam]; }; + int GetNumberOfTeams() { return m_iNumberOfTeams; }; + int GetIsFeigning() { return m_iIsFeigning; }; + int GetIsSettingDetpack() { return m_iIsSettingDetpack; }; + int GetBuildState() { return m_iBuildState; }; + int IsRandomPC() { return m_iRandomPC; }; + char *GetTeamName( int iTeam ) { return m_sTeamNames[iTeam]; }; + int GetAllowSpectators() { return m_iAllowSpectators; }; + + // Message Handlers + int MsgFunc_ValClass(const char *pszName, int iSize, void *pbuf ); + int MsgFunc_TeamNames(const char *pszName, int iSize, void *pbuf ); + int MsgFunc_Feign(const char *pszName, int iSize, void *pbuf ); + int MsgFunc_Detpack(const char *pszName, int iSize, void *pbuf ); + int MsgFunc_VGUIMenu(const char *pszName, int iSize, void *pbuf ); + int MsgFunc_MOTD( const char *pszName, int iSize, void *pbuf ); + int MsgFunc_BuildSt( const char *pszName, int iSize, void *pbuf ); + int MsgFunc_RandomPC( const char *pszName, int iSize, void *pbuf ); + int MsgFunc_ServerName( const char *pszName, int iSize, void *pbuf ); + int MsgFunc_ScoreInfo( const char *pszName, int iSize, void *pbuf ); + int MsgFunc_TeamScore( const char *pszName, int iSize, void *pbuf ); + int MsgFunc_TeamInfo( const char *pszName, int iSize, void *pbuf ); + int MsgFunc_Spectator( const char *pszName, int iSize, void *pbuf ); + int MsgFunc_AllowSpec( const char *pszName, int iSize, void *pbuf ); + + // Input + bool SlotInput( int iSlot ); + + virtual void paintBackground(); + + CSchemeManager *GetSchemeManager( void ) { return &m_SchemeManager; } + + void *operator new( size_t stAllocateBlock ); + +public: + // VGUI Menus + CMenuPanel *m_pCurrentMenu; + CTeamMenuPanel *m_pTeamMenu; + CClassMenuPanel *m_pClassMenu; + ScorePanel *m_pScoreBoard; + char m_szServerName[ MAX_SERVERNAME_LENGTH ]; +}; + +//============================================================ +// Command Menu Button Handlers +#define MAX_COMMAND_SIZE 256 + +class CMenuHandler_StringCommand : public ActionSignal +{ +protected: + char m_pszCommand[MAX_COMMAND_SIZE]; + int m_iCloseVGUIMenu; +public: + CMenuHandler_StringCommand( char *pszCommand ) + { + strncpy( m_pszCommand, pszCommand, MAX_COMMAND_SIZE); + m_pszCommand[MAX_COMMAND_SIZE-1] = '\0'; + m_iCloseVGUIMenu = false; + } + + CMenuHandler_StringCommand( char *pszCommand, int iClose ) + { + strncpy( m_pszCommand, pszCommand, MAX_COMMAND_SIZE); + m_pszCommand[MAX_COMMAND_SIZE-1] = '\0'; + m_iCloseVGUIMenu = true; + } + + virtual void actionPerformed(Panel* panel) + { + gEngfuncs.pfnClientCmd(m_pszCommand); + + if (m_iCloseVGUIMenu) + gViewPort->HideTopMenu(); + else + gViewPort->HideCommandMenu(); + } +}; + +// This works the same as CMenuHandler_StringCommand, except it watches the string command +// for specific commands, and modifies client vars based upon them. +class CMenuHandler_StringCommandWatch : public CMenuHandler_StringCommand +{ +private: +public: + CMenuHandler_StringCommandWatch( char *pszCommand ) : CMenuHandler_StringCommand( pszCommand ) + { + } + + CMenuHandler_StringCommandWatch( char *pszCommand, int iClose ) : CMenuHandler_StringCommand( pszCommand, iClose ) + { + } + + virtual void actionPerformed(Panel* panel) + { + CMenuHandler_StringCommand::actionPerformed( panel ); + + // Try to guess the player's new team (it'll be corrected if it's wrong) + if ( !strcmp( m_pszCommand, "jointeam 1" ) ) + g_iTeamNumber = 1; + else if ( !strcmp( m_pszCommand, "jointeam 2" ) ) + g_iTeamNumber = 2; + else if ( !strcmp( m_pszCommand, "jointeam 3" ) ) + g_iTeamNumber = 3; + else if ( !strcmp( m_pszCommand, "jointeam 4" ) ) + g_iTeamNumber = 4; + } +}; + +// Used instead of CMenuHandler_StringCommand for Class Selection buttons. +// Checks the state of hud_classautokill and kills the player if set +class CMenuHandler_StringCommandClassSelect : public CMenuHandler_StringCommand +{ +private: +public: + CMenuHandler_StringCommandClassSelect( char *pszCommand ) : CMenuHandler_StringCommand( pszCommand ) + { + } + + CMenuHandler_StringCommandClassSelect( char *pszCommand, int iClose ) : CMenuHandler_StringCommand( pszCommand, iClose ) + { + } + + virtual void actionPerformed(Panel* panel); +}; + +class CMenuHandler_PopupSubMenuInput : public InputSignal +{ +private: + CCommandMenu *m_pSubMenu; + Button *m_pButton; +public: + CMenuHandler_PopupSubMenuInput( Button *pButton, CCommandMenu *pSubMenu ) + { + m_pSubMenu = pSubMenu; + m_pButton = pButton; + } + + virtual void cursorMoved(int x,int y,Panel* panel) + { + //gViewPort->SetCurrentCommandMenu( m_pSubMenu ); + } + + virtual void cursorEntered(Panel* panel) + { + gViewPort->SetCurrentCommandMenu( m_pSubMenu ); + + if (m_pButton) + m_pButton->setArmed(true); + }; + virtual void cursorExited(Panel* Panel) {}; + virtual void mousePressed(MouseCode code,Panel* panel) {}; + virtual void mouseDoublePressed(MouseCode code,Panel* panel) {}; + virtual void mouseReleased(MouseCode code,Panel* panel) {}; + virtual void mouseWheeled(int delta,Panel* panel) {}; + virtual void keyPressed(KeyCode code,Panel* panel) {}; + virtual void keyTyped(KeyCode code,Panel* panel) {}; + virtual void keyReleased(KeyCode code,Panel* panel) {}; + virtual void keyFocusTicked(Panel* panel) {}; +}; + +class CMenuHandler_LabelInput : public InputSignal +{ +private: + ActionSignal *m_pActionSignal; +public: + CMenuHandler_LabelInput( ActionSignal *pSignal ) + { + m_pActionSignal = pSignal; + } + + virtual void mousePressed(MouseCode code,Panel* panel) + { + m_pActionSignal->actionPerformed( panel ); + } + + virtual void mouseReleased(MouseCode code,Panel* panel) {}; + virtual void cursorEntered(Panel* panel) {}; + virtual void cursorExited(Panel* Panel) {}; + virtual void cursorMoved(int x,int y,Panel* panel) {}; + virtual void mouseDoublePressed(MouseCode code,Panel* panel) {}; + virtual void mouseWheeled(int delta,Panel* panel) {}; + virtual void keyPressed(KeyCode code,Panel* panel) {}; + virtual void keyTyped(KeyCode code,Panel* panel) {}; + virtual void keyReleased(KeyCode code,Panel* panel) {}; + virtual void keyFocusTicked(Panel* panel) {}; +}; + +#define HIDE_TEXTWINDOW 0 +#define SHOW_MAPBRIEFING 1 +#define SHOW_CLASSDESC 2 +#define SHOW_MOTD 3 + +class CMenuHandler_TextWindow : public ActionSignal +{ +private: + int m_iState; +public: + CMenuHandler_TextWindow( int iState ) + { + m_iState = iState; + } + + virtual void actionPerformed(Panel* panel) + { + if (m_iState == HIDE_TEXTWINDOW) + { + gViewPort->HideTopMenu(); + } + else + { + gViewPort->HideCommandMenu(); + gViewPort->ShowVGUIMenu( m_iState ); + } + } +}; + +class CDragNDropHandler : public InputSignal +{ +private: + DragNDropPanel* m_pPanel; + bool m_bDragging; + int m_iaDragOrgPos[2]; + int m_iaDragStart[2]; + +public: + CDragNDropHandler(DragNDropPanel* pPanel) + { + m_pPanel = pPanel; + m_bDragging = false; + } + + void cursorMoved(int x,int y,Panel* panel); + void mousePressed(MouseCode code,Panel* panel); + void mouseReleased(MouseCode code,Panel* panel); + + void mouseDoublePressed(MouseCode code,Panel* panel) {}; + void cursorEntered(Panel* panel) {}; + void cursorExited(Panel* panel) {}; + void mouseWheeled(int delta,Panel* panel) {}; + void keyPressed(KeyCode code,Panel* panel) {}; + void keyTyped(KeyCode code,Panel* panel) {}; + void keyReleased(KeyCode code,Panel* panel) {}; + void keyFocusTicked(Panel* panel) {}; +}; + +class CHandler_MenuButtonOver : public InputSignal +{ +private: + int m_iButton; + CMenuPanel *m_pMenuPanel; +public: + CHandler_MenuButtonOver( CMenuPanel *pPanel, int iButton ) + { + m_iButton = iButton; + m_pMenuPanel = pPanel; + } + + void cursorEntered(Panel *panel); + + void cursorMoved(int x,int y,Panel* panel) {}; + void mousePressed(MouseCode code,Panel* panel) {}; + void mouseReleased(MouseCode code,Panel* panel) {}; + void mouseDoublePressed(MouseCode code,Panel* panel) {}; + void cursorExited(Panel* panel) {}; + void mouseWheeled(int delta,Panel* panel) {}; + void keyPressed(KeyCode code,Panel* panel) {}; + void keyTyped(KeyCode code,Panel* panel) {}; + void keyReleased(KeyCode code,Panel* panel) {}; + void keyFocusTicked(Panel* panel) {}; +}; + +class CHandler_ButtonHighlight : public InputSignal +{ +private: + Button *m_pButton; +public: + CHandler_ButtonHighlight( Button *pButton ) + { + m_pButton = pButton; + } + + virtual void cursorEntered(Panel* panel) + { + m_pButton->setArmed(true); + }; + virtual void cursorExited(Panel* Panel) + { + m_pButton->setArmed(false); + }; + virtual void mousePressed(MouseCode code,Panel* panel) {}; + virtual void mouseReleased(MouseCode code,Panel* panel) {}; + virtual void cursorMoved(int x,int y,Panel* panel) {}; + virtual void mouseDoublePressed(MouseCode code,Panel* panel) {}; + virtual void mouseWheeled(int delta,Panel* panel) {}; + virtual void keyPressed(KeyCode code,Panel* panel) {}; + virtual void keyTyped(KeyCode code,Panel* panel) {}; + virtual void keyReleased(KeyCode code,Panel* panel) {}; + virtual void keyFocusTicked(Panel* panel) {}; +}; + +//----------------------------------------------------------------------------- +// Purpose: Special handler for highlighting of command menu buttons +//----------------------------------------------------------------------------- +class CHandler_CommandButtonHighlight : public CHandler_ButtonHighlight +{ +private: + CommandButton *m_pCommandButton; +public: + CHandler_CommandButtonHighlight( CommandButton *pButton ) : CHandler_ButtonHighlight( pButton ) + { + m_pCommandButton = pButton; + } + + virtual void cursorEntered( Panel *panel ) + { + m_pCommandButton->cursorEntered(); + } + + virtual void cursorExited( Panel *panel ) + { + m_pCommandButton->cursorExited(); + } +}; + + +//================================================================ +// Overidden Command Buttons for special visibilities +class ClassButton : public CommandButton +{ +protected: + int m_iPlayerClass; + +public: + ClassButton( int iClass, const char* text,int x,int y,int wide,int tall, bool bNoHighlight ) : CommandButton( text,x,y,wide,tall, bNoHighlight) + { + m_iPlayerClass = iClass; + } + + virtual int IsNotValid(); +}; + +class TeamButton : public CommandButton +{ +private: + int m_iTeamNumber; +public: + TeamButton( int iTeam, const char* text,int x,int y,int wide,int tall ) : CommandButton( text,x,y,wide,tall) + { + m_iTeamNumber = iTeam; + } + + virtual int IsNotValid() + { + int iTeams = gViewPort->GetNumberOfTeams(); + // Never valid if there's only 1 team + if (iTeams == 1) + return true; + + // Auto Team's always visible + if (m_iTeamNumber == 5) + return false; + + if (iTeams >= m_iTeamNumber && m_iTeamNumber != g_iTeamNumber) + return false; + + return true; + } +}; + +class FeignButton : public CommandButton +{ +private: + int m_iFeignState; +public: + FeignButton( int iState, const char* text,int x,int y,int wide,int tall ) : CommandButton( text,x,y,wide,tall) + { + m_iFeignState = iState; + } + + virtual int IsNotValid() + { + // Only visible for spies + if (g_iPlayerClass != PC_SPY) + return true; + + if (m_iFeignState == gViewPort->GetIsFeigning()) + return false; + + return true; + } +}; + +class SpectateButton : public CommandButton +{ +public: + SpectateButton( const char* text,int x,int y,int wide,int tall, bool bNoHighlight ) : CommandButton( text,x,y,wide,tall, bNoHighlight) + { + } + + virtual int IsNotValid() + { + // Only visible if the server allows it + if ( gViewPort->GetAllowSpectators() != 0 ) + return false; + + return true; + } +}; + +#define DISGUISE_TEAM1 (1<<0) +#define DISGUISE_TEAM2 (1<<1) +#define DISGUISE_TEAM3 (1<<2) +#define DISGUISE_TEAM4 (1<<3) + +class DisguiseButton : public CommandButton +{ +private: + int m_iValidTeamsBits; + int m_iThisTeam; +public: + DisguiseButton( int iValidTeamNumsBits, const char* text,int x,int y,int wide,int tall ) : CommandButton( text,x,y,wide,tall,false ) + { + m_iValidTeamsBits = iValidTeamNumsBits; + } + + virtual int IsNotValid() + { + // Only visible for spies + if ( g_iPlayerClass != PC_SPY ) + return true; + + // if it's not tied to a specific team, then always show (for spies) + if ( !m_iValidTeamsBits ) + return false; + + // if we're tied to a team make sure we can change to that team + int iTmp = 1 << (gViewPort->GetNumberOfTeams() - 1); + if ( m_iValidTeamsBits & iTmp ) + return false; + + return true; + } +}; + +class DetpackButton : public CommandButton +{ +private: + int m_iDetpackState; +public: + DetpackButton( int iState, const char* text,int x,int y,int wide,int tall ) : CommandButton( text,x,y,wide,tall) + { + m_iDetpackState = iState; + } + + virtual int IsNotValid() + { + // Only visible for demomen + if (g_iPlayerClass != PC_DEMOMAN) + return true; + + if (m_iDetpackState == gViewPort->GetIsSettingDetpack()) + return false; + + return true; + } +}; + +extern int iBuildingCosts[]; +#define BUILDSTATE_HASBUILDING (1<<0) // Data is building ID (1 = Dispenser, 2 = Sentry) +#define BUILDSTATE_BUILDING (1<<1) +#define BUILDSTATE_BASE (1<<2) +#define BUILDSTATE_CANBUILD (1<<3) // Data is building ID (0 = Dispenser, 1 = Sentry) + +class BuildButton : public CommandButton +{ +private: + int m_iBuildState; + int m_iBuildData; + +public: + enum Buildings + { + DISPENSER = 0, + SENTRYGUN = 1, + }; + + BuildButton( int iState, int iData, const char* text,int x,int y,int wide,int tall ) : CommandButton( text,x,y,wide,tall) + { + m_iBuildState = iState; + m_iBuildData = iData; + } + + virtual int IsNotValid() + { + // Only visible for engineers + if (g_iPlayerClass != PC_ENGINEER) + return true; + + // If this isn't set, it's only active when they're not building + if (m_iBuildState & BUILDSTATE_BUILDING) + { + // Make sure the player's building + if ( !(gViewPort->GetBuildState() & BS_BUILDING) ) + return true; + } + else + { + // Make sure the player's not building + if ( gViewPort->GetBuildState() & BS_BUILDING ) + return true; + } + + if (m_iBuildState & BUILDSTATE_BASE) + { + // Only appear if we've got enough metal to build something, or something already built + if ( gViewPort->GetBuildState() & (BS_HAS_SENTRYGUN | BS_HAS_DISPENSER | BS_CANB_SENTRYGUN | BS_CANB_DISPENSER) ) + return false; + + return true; + } + + // Must have a building + if (m_iBuildState & BUILDSTATE_HASBUILDING) + { + if ( m_iBuildData == BuildButton::DISPENSER && !(gViewPort->GetBuildState() & BS_HAS_DISPENSER) ) + return true; + if ( m_iBuildData == BuildButton::SENTRYGUN && !(gViewPort->GetBuildState() & BS_HAS_SENTRYGUN) ) + return true; + } + + // Can build something + if (m_iBuildState & BUILDSTATE_CANBUILD) + { + // Make sure they've got the ammo and don't have one already + if ( m_iBuildData == BuildButton::DISPENSER && (gViewPort->GetBuildState() & BS_CANB_DISPENSER) ) + return false; + if ( m_iBuildData == BuildButton::SENTRYGUN && (gViewPort->GetBuildState() & BS_CANB_SENTRYGUN) ) + return false; + + return true; + } + + return false; + } +}; + +#define MAX_MAPNAME 256 + +class MapButton : public CommandButton +{ +private: + char m_szMapName[ MAX_MAPNAME ]; + +public: + MapButton( const char *pMapName, const char* text,int x,int y,int wide,int tall ) : CommandButton( text,x,y,wide,tall) + { + sprintf( m_szMapName, "maps/%s.bsp", pMapName ); + } + + virtual int IsNotValid() + { + const char *level = gEngfuncs.pfnGetLevelName(); + if (!level) + return true; + + // Does it match the current map name? + if ( strcmp(m_szMapName, level) ) + return true; + + return false; + } +}; + +//----------------------------------------------------------------------------- +// Purpose: CommandButton which is only displayed if the player is on team X +//----------------------------------------------------------------------------- +class TeamOnlyCommandButton : public CommandButton +{ +private: + int m_iTeamNum; + +public: + TeamOnlyCommandButton( int iTeamNum, const char* text,int x,int y,int wide,int tall ) : + CommandButton( text, x, y, wide, tall ), m_iTeamNum(iTeamNum) {} + + virtual int IsNotValid() + { + if ( g_iTeamNumber != m_iTeamNum ) + return true; + + return CommandButton::IsNotValid(); + } +}; + +//============================================================ +// Panel that can be dragged around +class DragNDropPanel : public Panel +{ +private: + bool m_bBeingDragged; + LineBorder *m_pBorder; +public: + DragNDropPanel(int x,int y,int wide,int tall) : Panel(x,y,wide,tall) + { + m_bBeingDragged = false; + + // Create the Drag Handler + addInputSignal( new CDragNDropHandler(this) ); + + // Create the border (for dragging) + m_pBorder = new LineBorder(); + } + + virtual void setDragged( bool bState ) + { + m_bBeingDragged = bState; + + if (m_bBeingDragged) + setBorder(m_pBorder); + else + setBorder(NULL); + } +}; + +//================================================================ +// Panel that draws itself with a transparent black background +class CTransparentPanel : public Panel +{ +private: + int m_iTransparency; +public: + CTransparentPanel(int iTrans, int x,int y,int wide,int tall) : Panel(x,y,wide,tall) + { + m_iTransparency = iTrans; + } + + virtual void paintBackground() + { + if (m_iTransparency) + { + // Transparent black background + drawSetColor( 0,0,0, m_iTransparency ); + drawFilledRect(0,0,_size[0],_size[1]); + } + } +}; + +//================================================================ +// Menu Panel that supports buffering of menus +class CMenuPanel : public CTransparentPanel +{ +private: + CMenuPanel *m_pNextMenu; + int m_iMenuID; + int m_iRemoveMe; + int m_iIsActive; + float m_flOpenTime; +public: + CMenuPanel(int iRemoveMe, int x,int y,int wide,int tall) : CTransparentPanel(100, x,y,wide,tall) + { + Reset(); + m_iRemoveMe = iRemoveMe; + } + + CMenuPanel(int iTrans, int iRemoveMe, int x,int y,int wide,int tall) : CTransparentPanel(iTrans, x,y,wide,tall) + { + Reset(); + m_iRemoveMe = iRemoveMe; + } + + virtual void Reset( void ) + { + m_pNextMenu = NULL; + m_iIsActive = false; + m_flOpenTime = 0; + } + + void SetNextMenu( CMenuPanel *pNextPanel ) + { + if (m_pNextMenu) + m_pNextMenu->SetNextMenu( pNextPanel ); + else + m_pNextMenu = pNextPanel; + } + + void SetMenuID( int iID ) + { + m_iMenuID = iID; + } + + void SetActive( int iState ) + { + m_iIsActive = iState; + } + + virtual void Open( void ) + { + setVisible( true ); + + // Note the open time, so we can delay input for a bit + m_flOpenTime = gHUD.m_flTime; + } + + virtual void Close( void ) + { + setVisible( false ); + m_iIsActive = false; + + if ( m_iRemoveMe ) + gViewPort->removeChild( this ); + + // This MenuPanel has now been deleted. Don't append code here. + } + + int ShouldBeRemoved() { return m_iRemoveMe; }; + CMenuPanel* GetNextMenu() { return m_pNextMenu; }; + int GetMenuID() { return m_iMenuID; }; + int IsActive() { return m_iIsActive; }; + float GetOpenTime() { return m_flOpenTime; }; + + // Numeric input + virtual bool SlotInput( int iSlot ) { return false; }; + virtual void SetActiveInfo( int iInput ) {}; +}; + +//================================================================ +// Custom drawn scroll bars +class CTFScrollButton : public CommandButton +{ +private: + BitmapTGA *m_pTGA; + +public: + CTFScrollButton(int iArrow, const char* text,int x,int y,int wide,int tall); + + virtual void paint( void ); + virtual void paintBackground( void ); +}; + +// Custom drawn slider bar +class CTFSlider : public Slider +{ +public: + CTFSlider(int x,int y,int wide,int tall,bool vertical) : Slider(x,y,wide,tall,vertical) + { + }; + + virtual void paintBackground( void ); +}; + +// Custom drawn scrollpanel +class CTFScrollPanel : public ScrollPanel +{ +public: + CTFScrollPanel(int x,int y,int wide,int tall); +}; + +//================================================================ +// Menu Panels that take key input +//============================================================ +class CClassMenuPanel : public CMenuPanel +{ +private: + CTransparentPanel *m_pClassInfoPanel[PC_LASTCLASS]; + Label *m_pPlayers[PC_LASTCLASS]; + ClassButton *m_pButtons[PC_LASTCLASS]; + CommandButton *m_pCancelButton; + ScrollPanel *m_pScrollPanel; + + CImageLabel *m_pClassImages[MAX_TEAMS][PC_LASTCLASS]; + + int m_iCurrentInfo; + + enum { STRLENMAX_PLAYERSONTEAM = 128 }; + char m_sPlayersOnTeamString[STRLENMAX_PLAYERSONTEAM]; + +public: + CClassMenuPanel(int iTrans, int iRemoveMe, int x,int y,int wide,int tall); + + virtual bool SlotInput( int iSlot ); + virtual void Open( void ); + virtual void Update( void ); + virtual void SetActiveInfo( int iInput ); + virtual void Initialize( void ); + + virtual void Reset( void ) + { + CMenuPanel::Reset(); + m_iCurrentInfo = 0; + } +}; + +class CTeamMenuPanel : public CMenuPanel +{ +public: + ScrollPanel *m_pScrollPanel; + CTransparentPanel *m_pTeamWindow; + Label *m_pMapTitle; + TextPanel *m_pBriefing; + TextPanel *m_pTeamInfoPanel[6]; + CommandButton *m_pButtons[6]; + bool m_bUpdatedMapName; + CommandButton *m_pCancelButton; + CommandButton *m_pSpectateButton; + + int m_iCurrentInfo; + +public: + CTeamMenuPanel(int iTrans, int iRemoveMe, int x,int y,int wide,int tall); + + virtual bool SlotInput( int iSlot ); + virtual void Open( void ); + virtual void Update( void ); + virtual void SetActiveInfo( int iInput ); + virtual void paintBackground( void ); + + virtual void Initialize( void ); + + virtual void Reset( void ) + { + CMenuPanel::Reset(); + m_iCurrentInfo = 0; + } +}; + +//========================================================= +// Specific Menus to handle old HUD sections +class CHealthPanel : public DragNDropPanel +{ +private: + BitmapTGA *m_pHealthTGA; + Label *m_pHealthLabel; +public: + CHealthPanel(int x,int y,int wide,int tall) : DragNDropPanel(x,y,wide,tall) + { + // Load the Health icon + FileInputStream* fis = new FileInputStream( GetVGUITGAName("%d_hud_health"), false); + m_pHealthTGA = new BitmapTGA(fis,true); + fis->close(); + + // Create the Health Label + int iXSize,iYSize; + m_pHealthTGA->getSize(iXSize,iYSize); + m_pHealthLabel = new Label("",0,0,iXSize,iYSize); + m_pHealthLabel->setImage(m_pHealthTGA); + m_pHealthLabel->setParent(this); + + // Set panel dimension + // Shouldn't be needed once Billy's fized setImage not recalculating the size + //setSize( iXSize + 100, gHUD.m_iFontHeight + 10 ); + //m_pHealthLabel->setPos( 10, (getTall() - iYSize) / 2 ); + } + + virtual void paintBackground() + { + } + + void paint() + { + // Get the paint color + int r,g,b,a; + // Has health changed? Flash the health # + if (gHUD.m_Health.m_fFade) + { + gHUD.m_Health.m_fFade -= (gHUD.m_flTimeDelta * 20); + if (gHUD.m_Health.m_fFade <= 0) + { + a = MIN_ALPHA; + gHUD.m_Health.m_fFade = 0; + } + + // Fade the health number back to dim + a = MIN_ALPHA + (gHUD.m_Health.m_fFade/FADE_TIME) * 128; + } + else + a = MIN_ALPHA; + + gHUD.m_Health.GetPainColor( r, g, b ); + ScaleColors(r, g, b, a ); + + // If health is getting low, make it bright red + if (gHUD.m_Health.m_iHealth <= 15) + a = 255; + + int iXSize,iYSize, iXPos, iYPos; + m_pHealthTGA->getSize(iXSize,iYSize); + m_pHealthTGA->getPos(iXPos, iYPos); + + // Paint the player's health + int x = gHUD.DrawHudNumber( iXPos + iXSize + 5, iYPos + 5, DHN_3DIGITS | DHN_DRAWZERO, gHUD.m_Health.m_iHealth, r, g, b); + + // Draw the vertical line + int HealthWidth = gHUD.GetSpriteRect(gHUD.m_HUD_number_0).right - gHUD.GetSpriteRect(gHUD.m_HUD_number_0).left; + x += HealthWidth / 2; + FillRGBA(x, iYPos + 5, HealthWidth / 10, gHUD.m_iFontHeight, 255, 160, 0, a); + } +}; + +#endif \ No newline at end of file diff --git a/cl_dll/vgui_int.cpp b/cl_dll/vgui_int.cpp new file mode 100644 index 0000000..c51ffe4 --- /dev/null +++ b/cl_dll/vgui_int.cpp @@ -0,0 +1,122 @@ + +#include"vgui_int.h" +#include +#include +#include +#include +#include +#include +#include +#include "hud.h" +#include "cl_util.h" +#include "camera.h" +#include "kbutton.h" +#include "cvardef.h" +#include "usercmd.h" +#include "const.h" +#include "camera.h" +#include "in_defs.h" +#include "vgui_TeamFortressViewport.h" +#include "vgui_ControlConfigPanel.h" + +namespace +{ + +class TexturePanel : public Panel , public ActionSignal +{ +private: + int _bindIndex; + TextEntry* _textEntry; +public: + TexturePanel() : Panel(0,0,256,276) + { + _bindIndex=2700; + _textEntry=new TextEntry("2700",0,0,128,20); + _textEntry->setParent(this); + _textEntry->addActionSignal(this); + } +public: + virtual bool isWithin(int x,int y) + { + return _textEntry->isWithin(x,y); + } +public: + virtual void actionPerformed(Panel* panel) + { + char buf[256]; + _textEntry->getText(0,buf,256); + sscanf(buf,"%d",&_bindIndex); + } +protected: + virtual void paintBackground() + { + Panel::paintBackground(); + + int wide,tall; + getPaintSize(wide,tall); + + drawSetColor(0,0,255,0); + drawSetTexture(_bindIndex); + drawTexturedRect(0,19,257,257); + } + +}; + +} + +using namespace vgui; + +void VGui_ViewportPaintBackground(int extents[4]) +{ + gEngfuncs.VGui_ViewportPaintBackground(extents); +} + +void* VGui_GetPanel() +{ + return (Panel*)gEngfuncs.VGui_GetPanel(); +} + +void VGui_Startup() +{ + Panel* root=(Panel*)VGui_GetPanel(); + root->setBgColor(128,128,0,0); + //root->setNonPainted(false); + //root->setBorder(new LineBorder()); + root->setLayout(new BorderLayout(0)); + + + //root->getSurfaceBase()->setEmulatedCursorVisible(true); + + if (gViewPort != NULL) + { +// root->removeChild(gViewPort); + + // free the memory +// delete gViewPort; +// gViewPort = NULL; + + gViewPort->Initialize(); + } + else + { + gViewPort = new TeamFortressViewport(0,0,root->getWide(),root->getTall()); + gViewPort->setParent(root); + } + + /* + TexturePanel* texturePanel=new TexturePanel(); + texturePanel->setParent(gViewPort); + */ + +} + +void VGui_Shutdown() +{ + delete gViewPort; + gViewPort = NULL; +} + + + + + diff --git a/cl_dll/vgui_int.h b/cl_dll/vgui_int.h new file mode 100644 index 0000000..36e6658 --- /dev/null +++ b/cl_dll/vgui_int.h @@ -0,0 +1,15 @@ + +#ifndef VGUI_INT_H +#define VGUI_INT_H + +extern "C" +{ +void VGui_Startup(); +void VGui_Shutdown(); + +//Only safe to call from inside subclass of Panel::paintBackground +void VGui_ViewportPaintBackground(int extents[4]); +} + + +#endif \ No newline at end of file diff --git a/cl_dll/vgui_teammenu.cpp b/cl_dll/vgui_teammenu.cpp new file mode 100644 index 0000000..9edbfca --- /dev/null +++ b/cl_dll/vgui_teammenu.cpp @@ -0,0 +1,389 @@ +//=========== (C) Copyright 1999 Valve, L.L.C. All rights reserved. =========== +// +// The copyright to the contents herein is the property of Valve, L.L.C. +// The contents may be used and/or copied only with the written permission of +// Valve, L.L.C., or in accordance with the terms and conditions stipulated in +// the agreement/contract under which the contents have been supplied. +// +// Purpose: TFC Team Menu +// +// $Workfile: $ +// $Date: $ +// +//----------------------------------------------------------------------------- +// $Log: $ +// +// $NoKeywords: $ +//============================================================================= + +#include "vgui_int.h" +#include "VGUI_Font.h" +#include "VGUI_ScrollPanel.h" +#include "VGUI_TextImage.h" + +#include "hud.h" +#include "cl_util.h" +#include "vgui_TeamFortressViewport.h" + +// Team Menu Dimensions +#define TEAMMENU_TITLE_X XRES(40) +#define TEAMMENU_TITLE_Y YRES(32) +#define TEAMMENU_TOPLEFT_BUTTON_X XRES(40) +#define TEAMMENU_TOPLEFT_BUTTON_Y YRES(80) +#define TEAMMENU_BUTTON_SIZE_X XRES(124) +#define TEAMMENU_BUTTON_SIZE_Y YRES(24) +#define TEAMMENU_BUTTON_SPACER_Y YRES(8) +#define TEAMMENU_WINDOW_X XRES(176) +#define TEAMMENU_WINDOW_Y YRES(80) +#define TEAMMENU_WINDOW_SIZE_X XRES(424) +#define TEAMMENU_WINDOW_SIZE_Y YRES(312) +#define TEAMMENU_WINDOW_TITLE_X XRES(16) +#define TEAMMENU_WINDOW_TITLE_Y YRES(16) +#define TEAMMENU_WINDOW_TEXT_X XRES(16) +#define TEAMMENU_WINDOW_TEXT_Y YRES(48) +#define TEAMMENU_WINDOW_TEXT_SIZE_Y YRES(178) +#define TEAMMENU_WINDOW_INFO_X XRES(16) +#define TEAMMENU_WINDOW_INFO_Y YRES(234) + +// Creation +CTeamMenuPanel::CTeamMenuPanel(int iTrans, int iRemoveMe, int x,int y,int wide,int tall) : CMenuPanel(iTrans, iRemoveMe, x,y,wide,tall) +{ + // Get the scheme used for the Titles + CSchemeManager *pSchemes = gViewPort->GetSchemeManager(); + + // schemes + SchemeHandle_t hTitleScheme = pSchemes->getSchemeHandle( "Title Font" ); + SchemeHandle_t hTeamWindowText = pSchemes->getSchemeHandle( "Briefing Text" ); + SchemeHandle_t hTeamInfoText = pSchemes->getSchemeHandle( "Team Info Text" ); + + // get the Font used for the Titles + Font *pTitleFont = pSchemes->getFont( hTitleScheme ); + int r, g, b, a; + + // Create the title + Label *pLabel = new Label( "", TEAMMENU_TITLE_X, TEAMMENU_TITLE_Y ); + pLabel->setParent( this ); + pLabel->setFont( pTitleFont ); + pSchemes->getFgColor( hTitleScheme, r, g, b, a ); + pLabel->setFgColor( r, g, b, a ); + pSchemes->getBgColor( hTitleScheme, r, g, b, a ); + pLabel->setBgColor( r, g, b, a ); + pLabel->setContentAlignment( vgui::Label::a_west ); + pLabel->setText(gHUD.m_TextMessage.BufferedLocaliseTextString("#Title_SelectYourTeam")); + + // Create the Info Window + m_pTeamWindow = new CTransparentPanel( 255, TEAMMENU_WINDOW_X, TEAMMENU_WINDOW_Y, TEAMMENU_WINDOW_SIZE_X, TEAMMENU_WINDOW_SIZE_Y ); + m_pTeamWindow->setParent( this ); + m_pTeamWindow->setBorder( new LineBorder( Color(255*0.7,170*0.7,0,0 )) ); + + // Create the Map Name Label + m_pMapTitle = new Label( "", TEAMMENU_WINDOW_TITLE_X, TEAMMENU_WINDOW_TITLE_Y ); + m_pMapTitle->setFont( pTitleFont ); + m_pMapTitle->setParent( m_pTeamWindow ); + pSchemes->getFgColor( hTitleScheme, r, g, b, a ); + m_pMapTitle->setFgColor( r, g, b, a ); + pSchemes->getBgColor( hTitleScheme, r, g, b, a ); + m_pMapTitle->setBgColor( r, g, b, a ); + m_pMapTitle->setContentAlignment( vgui::Label::a_west ); + + // Create the Scroll panel + m_pScrollPanel = new CTFScrollPanel( TEAMMENU_WINDOW_TEXT_X, TEAMMENU_WINDOW_TEXT_Y, TEAMMENU_WINDOW_SIZE_X - (TEAMMENU_WINDOW_TEXT_X * 2), TEAMMENU_WINDOW_TEXT_SIZE_Y ); + m_pScrollPanel->setParent(m_pTeamWindow); + m_pScrollPanel->setScrollBarVisible(false, false); + + // Create the Map Briefing panel + m_pBriefing = new TextPanel("", 0,0, TEAMMENU_WINDOW_SIZE_X - TEAMMENU_WINDOW_TEXT_X, TEAMMENU_WINDOW_TEXT_SIZE_Y ); + m_pBriefing->setParent( m_pScrollPanel->getClient() ); + m_pBriefing->setFont( pSchemes->getFont(hTeamWindowText) ); + pSchemes->getFgColor( hTeamWindowText, r, g, b, a ); + m_pBriefing->setFgColor( r, g, b, a ); + pSchemes->getBgColor( hTeamWindowText, r, g, b, a ); + m_pBriefing->setBgColor( r, g, b, a ); + + m_pBriefing->setText("Map Description not available."); + + // Team Menu buttons + for (int i = 1; i <= 5; i++) + { + char sz[256]; + + int iYPos = TEAMMENU_TOPLEFT_BUTTON_Y + ( (TEAMMENU_BUTTON_SIZE_Y + TEAMMENU_BUTTON_SPACER_Y) * i ); + + // Team button + m_pButtons[i] = new CommandButton( "", TEAMMENU_TOPLEFT_BUTTON_X, iYPos, TEAMMENU_BUTTON_SIZE_X, TEAMMENU_BUTTON_SIZE_Y, true); + m_pButtons[i]->setParent( this ); + m_pButtons[i]->setContentAlignment( vgui::Label::a_west ); + m_pButtons[i]->setVisible( false ); + + // AutoAssign button uses special case + if (i == 5) + { + m_pButtons[5]->setBoundKey( '5' ); + m_pButtons[5]->setText( gHUD.m_TextMessage.BufferedLocaliseTextString("#Team_AutoAssign") ); + m_pButtons[5]->setVisible( true ); + } + + // Create the Signals + sprintf(sz, "jointeam %d", i); + m_pButtons[i]->addActionSignal( new CMenuHandler_StringCommandWatch( sz, true ) ); + m_pButtons[i]->addInputSignal( new CHandler_MenuButtonOver(this, i) ); + + // Create the Team Info panel + m_pTeamInfoPanel[i] = new TextPanel("", TEAMMENU_WINDOW_INFO_X, TEAMMENU_WINDOW_INFO_Y, TEAMMENU_WINDOW_SIZE_X - TEAMMENU_WINDOW_INFO_X, TEAMMENU_WINDOW_SIZE_X - TEAMMENU_WINDOW_INFO_Y ); + m_pTeamInfoPanel[i]->setParent( m_pTeamWindow ); + m_pTeamInfoPanel[i]->setFont( pSchemes->getFont(hTeamInfoText) ); + m_pTeamInfoPanel[i]->setFgColor( iTeamColors[i][0], iTeamColors[i][1], iTeamColors[i][2], 0 ); + m_pTeamInfoPanel[i]->setBgColor( 0,0,0, 255 ); + } + + // Create the Cancel button + m_pCancelButton = new CommandButton( CHudTextMessage::BufferedLocaliseTextString( "#Menu_Cancel" ), TEAMMENU_TOPLEFT_BUTTON_X, 0, TEAMMENU_BUTTON_SIZE_X, TEAMMENU_BUTTON_SIZE_Y); + m_pCancelButton->setParent( this ); + m_pCancelButton->addActionSignal( new CMenuHandler_TextWindow(HIDE_TEXTWINDOW) ); + + // Create the Spectate button + m_pSpectateButton = new SpectateButton( CHudTextMessage::BufferedLocaliseTextString( "#Menu_Spectate" ), TEAMMENU_TOPLEFT_BUTTON_X, 0, TEAMMENU_BUTTON_SIZE_X, TEAMMENU_BUTTON_SIZE_Y, true); + m_pSpectateButton->setParent( this ); + m_pSpectateButton->addActionSignal( new CMenuHandler_StringCommand( "spectate", true ) ); + m_pSpectateButton->setBoundKey( '6' ); + m_pSpectateButton->addInputSignal( new CHandler_MenuButtonOver(this, 6) ); + + Initialize(); +} + +//----------------------------------------------------------------------------- +// Purpose: Called each time a new level is started. +//----------------------------------------------------------------------------- +void CTeamMenuPanel::Initialize( void ) +{ + m_bUpdatedMapName = false; + m_iCurrentInfo = 0; + m_pScrollPanel->setScrollValue( 0, 0 ); +} + +//----------------------------------------------------------------------------- +// Purpose: Called everytime the Team Menu is displayed +//----------------------------------------------------------------------------- +void CTeamMenuPanel::Update( void ) +{ + int iYPos = TEAMMENU_TOPLEFT_BUTTON_Y; + + // Set the team buttons + for (int i = 1; i <= 4; i++) + { + if (m_pButtons[i]) + { + if ( i <= gViewPort->GetNumberOfTeams() ) + { + m_pButtons[i]->setText( gViewPort->GetTeamName(i) ); + + // bound key replacement + char sz[32]; + sprintf( sz, "%d", i ); + m_pButtons[i]->setBoundKey( sz[0] ); + + m_pButtons[i]->setVisible( true ); + m_pButtons[i]->setPos( TEAMMENU_TOPLEFT_BUTTON_X, iYPos ); + iYPos += TEAMMENU_BUTTON_SIZE_Y + TEAMMENU_BUTTON_SPACER_Y; + + // Start with the first option up + if (!m_iCurrentInfo) + SetActiveInfo( i ); + + char szPlayerList[ (MAX_PLAYER_NAME_LENGTH + 3) * 31 ]; // name + ", " + strcpy(szPlayerList, "\n"); + // Update the Team Info + // Now count the number of teammembers of this class + int iTotal = 0; + for ( int j = 1; j < MAX_PLAYERS; j++ ) + { + if ( g_PlayerInfoList[j].name == NULL ) + continue; // empty player slot, skip + if ( g_PlayerInfoList[j].thisplayer ) + continue; // skip this player + if ( g_PlayerExtraInfo[j].teamnumber != i ) + continue; // skip over players in other teams + + iTotal++; + if (iTotal > 1) + strncat( szPlayerList, ", ", sizeof(szPlayerList) - strlen(szPlayerList) ); + strncat( szPlayerList, g_PlayerInfoList[j].name, sizeof(szPlayerList) - strlen(szPlayerList) ); + szPlayerList[ sizeof(szPlayerList) - 1 ] = '\0'; + } + + if (iTotal > 0) + { + // Set the text of the info Panel + char szText[ ((MAX_PLAYER_NAME_LENGTH + 3) * 31) + 256 ]; + if (iTotal == 1) + sprintf(szText, "%s: %d Player (%d points)", gViewPort->GetTeamName(i), iTotal, g_TeamInfo[i].frags ); + else + sprintf(szText, "%s: %d Players (%d points)", gViewPort->GetTeamName(i), iTotal, g_TeamInfo[i].frags ); + strncat( szText, szPlayerList, sizeof(szText) - strlen(szText) ); + szText[ sizeof(szText) - 1 ] = '\0'; + + m_pTeamInfoPanel[i]->setText( szText ); + } + else + { + m_pTeamInfoPanel[i]->setText( "" ); + } + } + else + { + // Hide the button (may be visible from previous maps) + m_pButtons[i]->setVisible( false ); + } + } + } + + // Move the AutoAssign button into place + m_pButtons[5]->setPos( TEAMMENU_TOPLEFT_BUTTON_X, iYPos ); + iYPos += TEAMMENU_BUTTON_SIZE_Y + TEAMMENU_BUTTON_SPACER_Y; + + // Spectate button + if (m_pSpectateButton->IsNotValid()) + { + m_pSpectateButton->setVisible( false ); + } + else + { + m_pSpectateButton->setPos( TEAMMENU_TOPLEFT_BUTTON_X, iYPos ); + m_pSpectateButton->setVisible( true ); + iYPos += TEAMMENU_BUTTON_SIZE_Y + TEAMMENU_BUTTON_SPACER_Y; + } + + // If the player is already in a team, make the cancel button visible + if ( g_iTeamNumber ) + { + m_pCancelButton->setPos( TEAMMENU_TOPLEFT_BUTTON_X, iYPos ); + iYPos += TEAMMENU_BUTTON_SIZE_Y + TEAMMENU_BUTTON_SPACER_Y; + m_pCancelButton->setVisible( true ); + } + else + { + m_pCancelButton->setVisible( false ); + } + + // Set the Map Title + if (!m_bUpdatedMapName) + { + const char *level = gEngfuncs.pfnGetLevelName(); + if (level && level[0]) + { + char sz[256]; + char szTitle[256]; + char *ch; + + // Update the level name + strcpy( sz, level ); + ch = strchr( sz, '/' ); + if (!ch) + ch = strchr( sz, '\\' ); + strcpy( szTitle, ch+1 ); + ch = strchr( szTitle, '.' ); + *ch = '\0'; + m_pMapTitle->setText( szTitle ); + *ch = '.'; + + // Update the map briefing + strcpy( sz, level ); + ch = strchr( sz, '.' ); + *ch = '\0'; + strcat( sz, ".txt" ); + char *pfile = (char*)gEngfuncs.COM_LoadFile( sz, 5, NULL ); + if (pfile) + { + m_pBriefing->setText( pfile ); + + // Get the total size of the Briefing text and resize the text panel + int iXSize, iYSize; + m_pBriefing->getTextImage()->getTextSize( iXSize, iYSize ); + m_pBriefing->setSize( iXSize, iYSize ); + } + + m_bUpdatedMapName = true; + } + } + + m_pScrollPanel->validate(); +} + +//===================================== +// Key inputs +bool CTeamMenuPanel::SlotInput( int iSlot ) +{ + // Check for AutoAssign + if ( iSlot == 5) + { + m_pButtons[5]->fireActionSignal(); + return true; + } + + // Spectate + if ( iSlot == 6) + { + m_pSpectateButton->fireActionSignal(); + return true; + } + + // Otherwise, see if a particular team is selectable + if ( (iSlot < 1) || (iSlot > gViewPort->GetNumberOfTeams()) ) + return false; + if ( !m_pButtons[ iSlot ] ) + return false; + + // Is the button pushable? + if ( m_pButtons[ iSlot ]->isVisible() ) + { + m_pButtons[ iSlot ]->fireActionSignal(); + return true; + } + + return false; +} + +//====================================== +// Update the Team menu before opening it +void CTeamMenuPanel::Open( void ) +{ + Update(); + CMenuPanel::Open(); +} + +void CTeamMenuPanel::paintBackground() +{ + // make sure we get the map briefing up + if ( !m_bUpdatedMapName ) + Update(); + + CMenuPanel::paintBackground(); +} + +//====================================== +// Mouse is over a team button, bring up the class info +void CTeamMenuPanel::SetActiveInfo( int iInput ) +{ + // Remove all the Info panels and bring up the specified one + m_pSpectateButton->setArmed( false ); + for (int i = 1; i <= 5; i++) + { + m_pButtons[i]->setArmed( false ); + m_pTeamInfoPanel[i]->setVisible( false ); + } + + // 6 is Spectate + if (iInput == 6) + { + m_pSpectateButton->setArmed( true ); + } + else + { + m_pButtons[iInput]->setArmed( true ); + m_pTeamInfoPanel[iInput]->setVisible( true ); + } + + m_iCurrentInfo = iInput; + + m_pScrollPanel->validate(); +} diff --git a/cl_dll/view.cpp b/cl_dll/view.cpp new file mode 100644 index 0000000..bff341d --- /dev/null +++ b/cl_dll/view.cpp @@ -0,0 +1,1023 @@ +// view/refresh setup functions + +#include "hud.h" +#include "cl_util.h" +#include "cvardef.h" +#include "usercmd.h" +#include "const.h" + +#include "entity_state.h" +#include "cl_entity.h" +#include "ref_params.h" +#include "in_defs.h" // PITCH YAW ROLL +#include "pm_movevars.h" +#include "pm_shared.h" +#include "pmtrace.h" +#include "screenfade.h" +#include "shake.h" + +// Spectator Mode +extern "C" +{ + float vecNewViewAngles[3]; + int iHasNewViewAngles; + float vecNewViewOrigin[3]; + int iHasNewViewOrigin; + int iIsSpectator; +} + +#ifndef M_PI +#define M_PI 3.14159265358979323846 // matches value in gcc v2 math.h +#endif + +extern "C" +{ + int CL_IsThirdPerson( void ); + void CL_CameraOffset( float *ofs ); + + void DLLEXPORT V_CalcRefdef( struct ref_params_s *pparams ); + + void PM_ParticleLine( float *start, float *end, int pcolor, float life, float vert); + int PM_GetInfo( int ent ); + +} + +void V_DropPunchAngle ( float frametime, float *ev_punchangle ); +void VectorAngles( const float *forward, float *angles ); + +/* +The view is allowed to move slightly from it's true position for bobbing, +but if it exceeds 8 pixels linear distance (spherical, not box), the list of +entities sent from the server may not include everything in the pvs, especially +when crossing a water boudnary. +*/ + +extern cvar_t *cl_forwardspeed; +extern cvar_t *chase_active; +extern cvar_t *scr_ofsx, *scr_ofsy, *scr_ofsz; +extern cvar_t *cl_vsmoothing; + +vec3_t v_origin, v_angles; + +vec3_t ev_punchangle; + +cvar_t *scr_ofsx; +cvar_t *scr_ofsy; +cvar_t *scr_ofsz; + +cvar_t *v_centermove; +cvar_t *v_centerspeed; + +cvar_t *cl_bobcycle; +cvar_t *cl_bob; +cvar_t *cl_bobup; +cvar_t *cl_waterdist; + +// These cvars are not registered (so users can't cheat), so set the ->value field directly +// Register these cvars in V_Init() if needed for easy tweaking +cvar_t v_iyaw_cycle = {"v_iyaw_cycle", "2", 0, 2}; +cvar_t v_iroll_cycle = {"v_iroll_cycle", "0.5", 0, 0.5}; +cvar_t v_ipitch_cycle = {"v_ipitch_cycle", "1", 0, 1}; +cvar_t v_iyaw_level = {"v_iyaw_level", "0.3", 0, 0.3}; +cvar_t v_iroll_level = {"v_iroll_level", "0.1", 0, 0.1}; +cvar_t v_ipitch_level = {"v_ipitch_level", "0.3", 0, 0.3}; + +float v_idlescale; // used by TFC for concussion grenade effect + +//============================================================================= +void V_NormalizeAngles( float *angles ) +{ + int i; + // Normalize angles + for ( i = 0; i < 3; i++ ) + { + if ( angles[i] > 180.0 ) + { + angles[i] -= 360.0; + } + else if ( angles[i] < -180.0 ) + { + angles[i] += 360.0; + } + } +} + +/* +=================== +V_InterpolateAngles + +Interpolate Euler angles. +FIXME: Use Quaternions to avoid discontinuities +Frac is 0.0 to 1.0 ( i.e., should probably be clamped, but doesn't have to be ) +=================== +*/ +void V_InterpolateAngles( float *start, float *end, float *output, float frac ) +{ + int i; + float ang1, ang2; + float d; + + V_NormalizeAngles( start ); + V_NormalizeAngles( end ); + + for ( i = 0 ; i < 3 ; i++ ) + { + ang1 = start[i]; + ang2 = end[i]; + + d = ang2 - ang1; + if ( d > 180 ) + { + d -= 360; + } + else if ( d < -180 ) + { + d += 360; + } + + output[i] = ang1 + d * frac; + } + + V_NormalizeAngles( output ); +} + +// Quakeworld bob code, this fixes jitters in the mutliplayer since the clock (pparams->time) isn't quite linear +float V_CalcBob ( struct ref_params_s *pparams ) +{ + static double bobtime; + static float bob; + float cycle; + static float lasttime; + vec3_t vel; + + if ( pparams->spectator || iIsSpectator ) + return 0; + + if ( pparams->onground == -1 || + pparams->time == lasttime ) + { + // just use old value + return bob; + } + + lasttime = pparams->time; + + bobtime += pparams->frametime; + cycle = bobtime - (int)( bobtime / cl_bobcycle->value ) * cl_bobcycle->value; + cycle /= cl_bobcycle->value; + + if ( cycle < cl_bobup->value ) + { + cycle = M_PI * cycle / cl_bobup->value; + } + else + { + cycle = M_PI + M_PI * ( cycle - cl_bobup->value )/( 1.0 - cl_bobup->value ); + } + + // bob is proportional to simulated velocity in the xy plane + // (don't count Z, or jumping messes it up) + VectorCopy( pparams->simvel, vel ); + vel[2] = 0; + + bob = sqrt( vel[0] * vel[0] + vel[1] * vel[1] ) * cl_bob->value; + bob = bob * 0.3 + bob * 0.7 * sin(cycle); + bob = min( bob, 4 ); + bob = max( bob, -7 ); + return bob; + +} + +/* +=============== +V_CalcRoll +Used by view and sv_user +=============== +*/ +float V_CalcRoll (vec3_t angles, vec3_t velocity, float rollangle, float rollspeed ) +{ + float sign; + float side; + float value; + vec3_t forward, right, up; + + AngleVectors ( angles, forward, right, up ); + + side = DotProduct (velocity, right); + sign = side < 0 ? -1 : 1; + side = fabs( side ); + + value = rollangle; + if (side < rollspeed) + { + side = side * value / rollspeed; + } + else + { + side = value; + } + return side * sign; +} + +typedef struct pitchdrift_s +{ + float pitchvel; + int nodrift; + float driftmove; + double laststop; +} pitchdrift_t; + +static pitchdrift_t pd; + +void V_StartPitchDrift( void ) +{ + if ( pd.laststop == gEngfuncs.GetClientTime() ) + { + return; // something else is keeping it from drifting + } + + if ( pd.nodrift || !pd.pitchvel ) + { + pd.pitchvel = v_centerspeed->value; + pd.nodrift = 0; + pd.driftmove = 0; + } +} + +void V_StopPitchDrift ( void ) +{ + pd.laststop = gEngfuncs.GetClientTime(); + pd.nodrift = 1; + pd.pitchvel = 0; +} + +/* +=============== +V_DriftPitch + +Moves the client pitch angle towards idealpitch sent by the server. + +If the user is adjusting pitch manually, either with lookup/lookdown, +mlook and mouse, or klook and keyboard, pitch drifting is constantly stopped. +=============== +*/ +void V_DriftPitch ( struct ref_params_s *pparams ) +{ + float delta, move; + + if ( gEngfuncs.IsNoClipping() || !pparams->onground || pparams->demoplayback || pparams->spectator ) + { + pd.driftmove = 0; + pd.pitchvel = 0; + return; + } + + // don't count small mouse motion + if (pd.nodrift) + { + if ( fabs( pparams->cmd->forwardmove ) < cl_forwardspeed->value ) + pd.driftmove = 0; + else + pd.driftmove += pparams->frametime; + + if ( pd.driftmove > v_centermove->value) + { + V_StartPitchDrift (); + } + return; + } + + delta = pparams->idealpitch - pparams->cl_viewangles[PITCH]; + + if (!delta) + { + pd.pitchvel = 0; + return; + } + + move = pparams->frametime * pd.pitchvel; + pd.pitchvel += pparams->frametime * v_centerspeed->value; + +//Con_Printf ("move: %f (%f)\n", move, pparams->frametime); + + if (delta > 0) + { + if (move > delta) + { + pd.pitchvel = 0; + move = delta; + } + pparams->cl_viewangles[PITCH] += move; + } + else if (delta < 0) + { + if (move > -delta) + { + pd.pitchvel = 0; + move = -delta; + } + pparams->cl_viewangles[PITCH] -= move; + } +} + +/* +============================================================================== + VIEW RENDERING +============================================================================== +*/ + +/* +================== +V_CalcGunAngle +================== +*/ +void V_CalcGunAngle ( struct ref_params_s *pparams ) +{ + cl_entity_t *viewent; + + viewent = gEngfuncs.GetViewModel(); + if ( !viewent ) + return; + + viewent->angles[YAW] = pparams->viewangles[YAW] + pparams->crosshairangle[YAW]; + viewent->angles[PITCH] = -pparams->viewangles[PITCH] + pparams->crosshairangle[PITCH] * 0.25; + viewent->angles[ROLL] -= v_idlescale * sin(pparams->time*v_iroll_cycle.value) * v_iroll_level.value; + + // don't apply all of the v_ipitch to prevent normally unseen parts of viewmodel from coming into view. + viewent->angles[PITCH] -= v_idlescale * sin(pparams->time*v_ipitch_cycle.value) * (v_ipitch_level.value * 0.5); + viewent->angles[YAW] -= v_idlescale * sin(pparams->time*v_iyaw_cycle.value) * v_iyaw_level.value; + + VectorCopy( viewent->angles, viewent->curstate.angles ); + VectorCopy( viewent->angles, viewent->latched.prevangles ); +} + +/* +============== +V_AddIdle + +Idle swaying +============== +*/ +void V_AddIdle ( struct ref_params_s *pparams ) +{ + pparams->viewangles[ROLL] += v_idlescale * sin(pparams->time*v_iroll_cycle.value) * v_iroll_level.value; + pparams->viewangles[PITCH] += v_idlescale * sin(pparams->time*v_ipitch_cycle.value) * v_ipitch_level.value; + pparams->viewangles[YAW] += v_idlescale * sin(pparams->time*v_iyaw_cycle.value) * v_iyaw_level.value; +} + + +/* +============== +V_CalcViewRoll + +Roll is induced by movement and damage +============== +*/ +void V_CalcViewRoll ( struct ref_params_s *pparams ) +{ + float side; + cl_entity_t *viewentity; + + viewentity = gEngfuncs.GetEntityByIndex( pparams->viewentity ); + if ( !viewentity ) + return; + + side = V_CalcRoll ( viewentity->angles, pparams->simvel, pparams->movevars->rollangle, pparams->movevars->rollspeed ); + + pparams->viewangles[ROLL] += side; + + if ( pparams->health <= 0 && ( pparams->viewheight[2] != 0 ) ) + { + // only roll the view if the player is dead and the viewheight[2] is nonzero + // this is so deadcam in multiplayer will work. + pparams->viewangles[ROLL] = 80; // dead view angle + return; + } +} + + +/* +================== +V_CalcIntermissionRefdef + +================== +*/ +void V_CalcIntermissionRefdef ( struct ref_params_s *pparams ) +{ + cl_entity_t *ent, *view; + float old; + +// don't allow cheats in multiplayer +#if !defined( _DEBUG ) + if ( pparams->maxclients > 1 ) + { + gEngfuncs.Cvar_SetValue ("scr_ofsx", 0); + gEngfuncs.Cvar_SetValue ("scr_ofsy", 0); + gEngfuncs.Cvar_SetValue ("scr_ofsz", 0); + } +#endif + + // ent is the player model ( visible when out of body ) + ent = gEngfuncs.GetLocalPlayer(); + + // view is the weapon model (only visible from inside body ) + view = gEngfuncs.GetViewModel(); + + VectorCopy ( pparams->simorg, pparams->vieworg ); + VectorCopy ( pparams->cl_viewangles, pparams->viewangles ); + + view->model = NULL; + + // allways idle in intermission + old = v_idlescale; + v_idlescale = 1; + + V_AddIdle ( pparams ); + + v_idlescale = old; + + v_origin = pparams->vieworg; + v_angles = pparams->viewangles; +} + +#define ORIGIN_BACKUP 64 +#define ORIGIN_MASK ( ORIGIN_BACKUP - 1 ) + +typedef struct +{ + float Origins[ ORIGIN_BACKUP ][3]; + float OriginTime[ ORIGIN_BACKUP ]; + + float Angles[ ORIGIN_BACKUP ][3]; + float AngleTime[ ORIGIN_BACKUP ]; + + int CurrentOrigin; + int CurrentAngle; +} viewinterp_t; + +/* +================== +V_CalcRefdef + +================== +*/ +void V_CalcNormalRefdef ( struct ref_params_s *pparams ) +{ + cl_entity_t *ent, *view; + int i; + vec3_t angles; + float bob, waterOffset; + static viewinterp_t ViewInterp; + + static float oldz = 0; + static float lasttime; + + static float lastang[3]; + vec3_t angdelta; + + vec3_t camAngles, camForward, camRight, camUp; + cl_entity_t *pwater; + + // don't allow cheats in multiplayer + if ( pparams->maxclients > 1 ) + { + scr_ofsx->value = 0.0; + scr_ofsy->value = 0.0; + scr_ofsz->value = 0.0; + } + + + V_DriftPitch ( pparams ); + + // ent is the player model ( visible when out of body ) + ent = gEngfuncs.GetLocalPlayer(); + + // view is the weapon model (only visible from inside body ) + view = gEngfuncs.GetViewModel(); + + // transform the view offset by the model's matrix to get the offset from + // model origin for the view + bob = V_CalcBob ( pparams ); + + // Observer angle capturing and smoothing + if ( iHasNewViewOrigin ) + { + // Get the angles from the physics code + VectorCopy( vecNewViewOrigin, pparams->vieworg ); + VectorCopy( vecNewViewOrigin, pparams->simorg ); + } + + // refresh position + VectorCopy ( pparams->simorg, pparams->vieworg ); + pparams->vieworg[2] += ( bob ); + VectorAdd( pparams->vieworg, pparams->viewheight, pparams->vieworg ); + + // Observer angle capturing and smoothing + if ( iHasNewViewAngles ) + { + // Get the angles from the physics code + VectorCopy( vecNewViewAngles, pparams->cl_viewangles ); + } + + VectorSubtract( pparams->cl_viewangles, lastang, angdelta ); + if ( Length( angdelta ) != 0.0 ) + { + VectorCopy( pparams->cl_viewangles, ViewInterp.Angles[ ViewInterp.CurrentAngle & ORIGIN_MASK ] ); + ViewInterp.AngleTime[ ViewInterp.CurrentAngle & ORIGIN_MASK ] = pparams->time; + ViewInterp.CurrentAngle++; + + VectorCopy( pparams->cl_viewangles, lastang ); + } + + if ( cl_vsmoothing && cl_vsmoothing->value && ( iIsSpectator & SPEC_SMOOTH_ANGLES ) ) + { + int foundidx; + int i; + float t; + + if ( cl_vsmoothing->value < 0.0 ) + { + gEngfuncs.Cvar_SetValue( "cl_vsmoothing", 0.0 ); + } + + t = pparams->time - cl_vsmoothing->value; + + for ( i = 1; i < ORIGIN_MASK; i++ ) + { + foundidx = ViewInterp.CurrentAngle - 1 - i; + if ( ViewInterp.AngleTime[ foundidx & ORIGIN_MASK ] <= t ) + break; + } + + if ( i < ORIGIN_MASK && ViewInterp.AngleTime[ foundidx & ORIGIN_MASK ] != 0.0 ) + { + // Interpolate + double dt; + + dt = ViewInterp.AngleTime[ (foundidx + 1) & ORIGIN_MASK ] - ViewInterp.AngleTime[ foundidx & ORIGIN_MASK ]; + if ( dt > 0.0 ) + { + double frac; + + frac = ( t - ViewInterp.AngleTime[ foundidx & ORIGIN_MASK] ) / dt; + frac = min( 1.0, frac ); + + // interpolate angles + V_InterpolateAngles( ViewInterp.Angles[ foundidx & ORIGIN_MASK ], ViewInterp.Angles[ (foundidx + 1) & ORIGIN_MASK ], pparams->cl_viewangles, frac ); + + VectorCopy( pparams->cl_viewangles, vecNewViewAngles ); + } + } + } + + VectorCopy ( pparams->cl_viewangles, pparams->viewangles ); + + gEngfuncs.V_CalcShake(); + gEngfuncs.V_ApplyShake( pparams->vieworg, pparams->viewangles, 1.0 ); + + // never let view origin sit exactly on a node line, because a water plane can + // dissapear when viewed with the eye exactly on it. + // FIXME, we send origin at 1/128 now, change this? + // the server protocol only specifies to 1/16 pixel, so add 1/32 in each axis + + pparams->vieworg[0] += 1.0/32; + pparams->vieworg[1] += 1.0/32; + pparams->vieworg[2] += 1.0/32; + + // Check for problems around water, move the viewer artificially if necessary + // -- this prevents drawing errors in GL due to waves + + waterOffset = 0; + if ( pparams->waterlevel >= 2 ) + { + int i, contents, waterDist, waterEntity; + vec3_t point; + waterDist = cl_waterdist->value; + + if ( pparams->hardware ) + { + waterEntity = gEngfuncs.PM_WaterEntity( pparams->simorg ); + if ( waterEntity >= 0 && waterEntity < pparams->max_entities ) + { + pwater = gEngfuncs.GetEntityByIndex( waterEntity ); + if ( pwater && ( pwater->model != NULL ) ) + { + waterDist += ( pwater->curstate.scale * 16 ); // Add in wave height + } + } + } + else + { + waterEntity = 0; // Don't need this in software + } + + VectorCopy( pparams->vieworg, point ); + + // Eyes are above water, make sure we're above the waves + if ( pparams->waterlevel == 2 ) + { + point[2] -= waterDist; + for ( i = 0; i < waterDist; i++ ) + { + contents = gEngfuncs.PM_PointContents( point, NULL ); + if ( contents > CONTENTS_WATER ) + break; + point[2] += 1; + } + waterOffset = (point[2] + waterDist) - pparams->vieworg[2]; + } + else + { + // eyes are under water. Make sure we're far enough under + point[2] += waterDist; + + for ( i = 0; i < waterDist; i++ ) + { + contents = gEngfuncs.PM_PointContents( point, NULL ); + if ( contents <= CONTENTS_WATER ) + break; + point[2] -= 1; + } + waterOffset = (point[2] - waterDist) - pparams->vieworg[2]; + } + } + + pparams->vieworg[2] += waterOffset; + + V_CalcViewRoll ( pparams ); + + V_AddIdle ( pparams ); + + // offsets + VectorCopy( pparams->cl_viewangles, angles ); + + AngleVectors ( angles, pparams->forward, pparams->right, pparams->up ); + + for ( i=0 ; i<3 ; i++ ) + { + pparams->vieworg[i] += scr_ofsx->value*pparams->forward[i] + scr_ofsy->value*pparams->right[i] + scr_ofsz->value*pparams->up[i]; + } + + // Treating cam_ofs[2] as the distance + if( CL_IsThirdPerson() ) + { + vec3_t ofs; + + ofs[0] = ofs[1] = ofs[2] = 0.0; + + CL_CameraOffset( (float *)&ofs ); + + VectorCopy( ofs, camAngles ); + camAngles[ ROLL ] = 0; + + AngleVectors( camAngles, camForward, camRight, camUp ); + + for ( i = 0; i < 3; i++ ) + { + pparams->vieworg[ i ] += -ofs[2] * camForward[ i ]; + } + } + + // Give gun our viewangles + VectorCopy ( pparams->cl_viewangles, view->angles ); + + // set up gun position + V_CalcGunAngle ( pparams ); + + // Use predicted origin as view origin. + VectorCopy ( pparams->simorg, view->origin ); + view->origin[2] += ( waterOffset ); + VectorAdd( view->origin, pparams->viewheight, view->origin ); + + // Let the viewmodel shake at about 10% of the amplitude + gEngfuncs.V_ApplyShake( view->origin, view->angles, 0.9 ); + + for ( i = 0; i < 3; i++ ) + { + view->origin[ i ] += bob * 0.4 * pparams->forward[ i ]; + } + view->origin[2] += bob; + + // throw in a little tilt. + view->angles[YAW] -= bob * 0.5; + view->angles[ROLL] -= bob * 1; + view->angles[PITCH] -= bob * 0.3; + + // pushing the view origin down off of the same X/Z plane as the ent's origin will give the + // gun a very nice 'shifting' effect when the player looks up/down. If there is a problem + // with view model distortion, this may be a cause. (SJB). + view->origin[2] -= 1; + + // fudge position around to keep amount of weapon visible + // roughly equal with different FOV + if (pparams->viewsize == 110) + { + view->origin[2] += 1; + } + else if (pparams->viewsize == 100) + { + view->origin[2] += 2; + } + else if (pparams->viewsize == 90) + { + view->origin[2] += 1; + } + else if (pparams->viewsize == 80) + { + view->origin[2] += 0.5; + } + + // Add in the punchangle, if any + VectorAdd ( pparams->viewangles, pparams->punchangle, pparams->viewangles ); + + // Include client side punch, too + VectorAdd ( pparams->viewangles, (float *)&ev_punchangle, pparams->viewangles); + + V_DropPunchAngle ( pparams->frametime, (float *)&ev_punchangle ); + + // smooth out stair step ups +#if 1 + if ( !pparams->smoothing && pparams->onground && pparams->simorg[2] - oldz > 0) + { + float steptime; + + steptime = pparams->time - lasttime; + if (steptime < 0) + //FIXME I_Error ("steptime < 0"); + steptime = 0; + + oldz += steptime * 150; + if (oldz > pparams->simorg[2]) + oldz = pparams->simorg[2]; + if (pparams->simorg[2] - oldz > 18) + oldz = pparams->simorg[2]- 18; + pparams->vieworg[2] += oldz - pparams->simorg[2]; + view->origin[2] += oldz - pparams->simorg[2]; + } + else + { + oldz = pparams->simorg[2]; + } +#endif + + { + static float lastorg[3]; + vec3_t delta; + + VectorSubtract( pparams->simorg, lastorg, delta ); + + if ( Length( delta ) != 0.0 ) + { + VectorCopy( pparams->simorg, ViewInterp.Origins[ ViewInterp.CurrentOrigin & ORIGIN_MASK ] ); + ViewInterp.OriginTime[ ViewInterp.CurrentOrigin & ORIGIN_MASK ] = pparams->time; + ViewInterp.CurrentOrigin++; + + VectorCopy( pparams->simorg, lastorg ); + } + } + + // Smooth out whole view in multiplayer when on trains, lifts + if ( cl_vsmoothing && cl_vsmoothing->value && + ( ( iIsSpectator & SPEC_SMOOTH_ORIGIN ) || (pparams->smoothing && ( pparams->maxclients > 1 ) ) ) ) + { + int foundidx; + int i; + float t; + + if ( cl_vsmoothing->value < 0.0 ) + { + gEngfuncs.Cvar_SetValue( "cl_vsmoothing", 0.0 ); + } + + t = pparams->time - cl_vsmoothing->value; + + for ( i = 1; i < ORIGIN_MASK; i++ ) + { + foundidx = ViewInterp.CurrentOrigin - 1 - i; + if ( ViewInterp.OriginTime[ foundidx & ORIGIN_MASK ] <= t ) + break; + } + + if ( i < ORIGIN_MASK && ViewInterp.OriginTime[ foundidx & ORIGIN_MASK ] != 0.0 ) + { + // Interpolate + vec3_t delta; + double frac; + double dt; + vec3_t neworg; + + dt = ViewInterp.OriginTime[ (foundidx + 1) & ORIGIN_MASK ] - ViewInterp.OriginTime[ foundidx & ORIGIN_MASK ]; + if ( dt > 0.0 ) + { + frac = ( t - ViewInterp.OriginTime[ foundidx & ORIGIN_MASK] ) / dt; + frac = min( 1.0, frac ); + VectorSubtract( ViewInterp.Origins[ ( foundidx + 1 ) & ORIGIN_MASK ], ViewInterp.Origins[ foundidx & ORIGIN_MASK ], delta ); + VectorMA( ViewInterp.Origins[ foundidx & ORIGIN_MASK ], frac, delta, neworg ); + + // Dont interpolate large changes + if ( Length( delta ) < 64 ) + { + VectorSubtract( neworg, pparams->simorg, delta ); + + VectorAdd( pparams->simorg, delta, pparams->simorg ); + VectorAdd( pparams->vieworg, delta, pparams->vieworg ); + VectorAdd( view->origin, delta, view->origin ); + + VectorCopy( pparams->simorg, vecNewViewOrigin ); + } + } + } + } + + // Store off v_angles before munging for third person + v_angles = pparams->viewangles; + + if ( CL_IsThirdPerson() ) + { + VectorCopy( camAngles, pparams->viewangles); + } + + // override all previous settings if the viewent isn't the client + if ( pparams->viewentity > pparams->maxclients ) + { + cl_entity_t *viewentity; + viewentity = gEngfuncs.GetEntityByIndex( pparams->viewentity ); + if ( viewentity ) + { + VectorCopy( viewentity->origin, pparams->vieworg ); + VectorCopy( viewentity->angles, pparams->viewangles ); + + // Store off overridden viewangles + v_angles = pparams->viewangles; + } + } + + lasttime = pparams->time; + + v_origin = pparams->vieworg; +} + +void DLLEXPORT V_CalcRefdef( struct ref_params_s *pparams ) +{ + // intermission / finale rendering + if ( pparams->intermission ) + { + V_CalcIntermissionRefdef ( pparams ); + } + else if ( !pparams->paused ) + { + V_CalcNormalRefdef ( pparams ); + } + +/* +// Example of how to overlay the whole screen with red at 50 % alpha +#define SF_TEST +#if defined SF_TEST + { + screenfade_t sf; + gEngfuncs.pfnGetScreenFade( &sf ); + + sf.fader = 255; + sf.fadeg = 0; + sf.fadeb = 0; + sf.fadealpha = 128; + sf.fadeFlags = FFADE_STAYOUT | FFADE_OUT; + + gEngfuncs.pfnSetScreenFade( &sf ); + } +#endif +*/ +} + +/* +============= +V_DropPunchAngle + +============= +*/ +void V_DropPunchAngle ( float frametime, float *ev_punchangle ) +{ + float len; + + len = VectorNormalize ( ev_punchangle ); + len -= (10.0 + len * 0.5) * frametime; + len = max( len, 0.0 ); + VectorScale ( ev_punchangle, len, ev_punchangle ); +} + +/* +============= +V_PunchAxis + +Client side punch effect +============= +*/ +void V_PunchAxis( int axis, float punch ) +{ + ev_punchangle[ axis ] = punch; +} + +/* +============= +V_Init +============= +*/ +void V_Init (void) +{ + gEngfuncs.pfnAddCommand ("centerview", V_StartPitchDrift ); + + scr_ofsx = gEngfuncs.pfnRegisterVariable( "scr_ofsx","0", 0 ); + scr_ofsy = gEngfuncs.pfnRegisterVariable( "scr_ofsy","0", 0 ); + scr_ofsz = gEngfuncs.pfnRegisterVariable( "scr_ofsz","0", 0 ); + + v_centermove = gEngfuncs.pfnRegisterVariable( "v_centermove", "0.15", 0 ); + v_centerspeed = gEngfuncs.pfnRegisterVariable( "v_centerspeed","500", 0 ); + + cl_bobcycle = gEngfuncs.pfnRegisterVariable( "cl_bobcycle","0.8", 0 );// best default for my experimental gun wag (sjb) + cl_bob = gEngfuncs.pfnRegisterVariable( "cl_bob","0.01", 0 );// best default for my experimental gun wag (sjb) + cl_bobup = gEngfuncs.pfnRegisterVariable( "cl_bobup","0.5", 0 ); + cl_waterdist = gEngfuncs.pfnRegisterVariable( "cl_waterdist","4", 0 ); +} + + +//#define TRACE_TEST +#if defined( TRACE_TEST ) + +extern float in_fov; +/* +==================== +CalcFov +==================== +*/ +float CalcFov (float fov_x, float width, float height) +{ + float a; + float x; + + if (fov_x < 1 || fov_x > 179) + fov_x = 90; // error, set to 90 + + x = width/tan(fov_x/360*M_PI); + + a = atan (height/x); + + a = a*360/M_PI; + + return a; +} + +int hitent = -1; + +void V_Move( int mx, int my ) +{ + float fov; + float fx, fy; + float dx, dy; + float c_x, c_y; + float dX, dY; + vec3_t forward, up, right; + vec3_t newangles; + + vec3_t farpoint; + pmtrace_t tr; + + fov = CalcFov( in_fov, (float)ScreenWidth, (float)ScreenHeight ); + + c_x = (float)ScreenWidth / 2.0; + c_y = (float)ScreenHeight / 2.0; + + dx = (float)mx - c_x; + dy = (float)my - c_y; + + // Proportion we moved in each direction + fx = dx / c_x; + fy = dy / c_y; + + dX = fx * in_fov / 2.0 ; + dY = fy * fov / 2.0; + + newangles = v_angles; + + newangles[ YAW ] -= dX; + newangles[ PITCH ] += dY; + + // Now rotate v_forward around that point + AngleVectors ( newangles, forward, right, up ); + + farpoint = v_origin + 8192 * forward; + + // Trace + tr = *(gEngfuncs.PM_TraceLine( (float *)&v_origin, (float *)&farpoint, PM_TRACELINE_PHYSENTSONLY, 2 /*point sized hull*/, -1 )); + + if ( tr.fraction != 1.0 && tr.ent != 0 ) + { + hitent = PM_GetInfo( tr.ent ); + PM_ParticleLine( (float *)&v_origin, (float *)&tr.endpos, 5, 1.0, 0.0 ); + } + else + { + hitent = -1; + } +} + +#endif \ No newline at end of file diff --git a/cl_dll/view.h b/cl_dll/view.h new file mode 100644 index 0000000..83d6566 --- /dev/null +++ b/cl_dll/view.h @@ -0,0 +1,8 @@ +#if !defined ( VIEWH ) +#define VIEWH +#pragma once + +void V_StartPitchDrift( void ); +void V_StopPitchDrift( void ); + +#endif // !VIEWH \ No newline at end of file diff --git a/cl_dll/wrect.h b/cl_dll/wrect.h new file mode 100644 index 0000000..1346fab --- /dev/null +++ b/cl_dll/wrect.h @@ -0,0 +1,9 @@ +#if !defined( WRECTH ) +#define WRECTH + +typedef struct rect_s +{ + int left, right, top, bottom; +} wrect_t; + +#endif \ No newline at end of file diff --git a/common/beamdef.h b/common/beamdef.h new file mode 100644 index 0000000..6ff8917 --- /dev/null +++ b/common/beamdef.h @@ -0,0 +1,62 @@ +/*** +* +* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +#if !defined ( BEAMDEFH ) +#define BEAMDEFH +#ifdef _WIN32 +#pragma once +#endif + +#define FBEAM_STARTENTITY 0x00000001 +#define FBEAM_ENDENTITY 0x00000002 +#define FBEAM_FADEIN 0x00000004 +#define FBEAM_FADEOUT 0x00000008 +#define FBEAM_SINENOISE 0x00000010 +#define FBEAM_SOLID 0x00000020 +#define FBEAM_SHADEIN 0x00000040 +#define FBEAM_SHADEOUT 0x00000080 +#define FBEAM_STARTVISIBLE 0x10000000 // Has this client actually seen this beam's start entity yet? +#define FBEAM_ENDVISIBLE 0x20000000 // Has this client actually seen this beam's end entity yet? +#define FBEAM_ISACTIVE 0x40000000 +#define FBEAM_FOREVER 0x80000000 + +typedef struct beam_s BEAM; +struct beam_s +{ + BEAM *next; + int type; + int flags; + vec3_t source; + vec3_t target; + vec3_t delta; + float t; // 0 .. 1 over lifetime of beam + float freq; + float die; + float width; + float amplitude; + float r, g, b; + float brightness; + float speed; + float frameRate; + float frame; + int segments; + int startEntity; + int endEntity; + int modelIndex; + int frameCount; + struct model_s *pFollowModel; + struct particle_s *particles; +}; + +#endif \ No newline at end of file diff --git a/common/cl_entity.h b/common/cl_entity.h new file mode 100644 index 0000000..9cfc963 --- /dev/null +++ b/common/cl_entity.h @@ -0,0 +1,115 @@ +/*** +* +* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +// cl_entity.h +#if !defined( CL_ENTITYH ) +#define CL_ENTITYH +#ifdef _WIN32 +#pragma once +#endif + +typedef struct efrag_s +{ + struct mleaf_s *leaf; + struct efrag_s *leafnext; + struct cl_entity_s *entity; + struct efrag_s *entnext; +} efrag_t; + +typedef struct +{ + byte mouthopen; // 0 = mouth closed, 255 = mouth agape + byte sndcount; // counter for running average + int sndavg; // running average +} mouth_t; + +typedef struct +{ + float prevanimtime; + float sequencetime; + byte prevseqblending[2]; + vec3_t prevorigin; + vec3_t prevangles; + + int prevsequence; + float prevframe; + + byte prevcontroller[4]; + byte prevblending[2]; +} latchedvars_t; + +typedef struct +{ + // Time stamp for this movement + float animtime; + + vec3_t origin; + vec3_t angles; +} position_history_t; + +typedef struct cl_entity_s cl_entity_t; + +#define HISTORY_MAX 64 // Must be power of 2 +#define HISTORY_MASK ( HISTORY_MAX - 1 ) + + +#if !defined( ENTITY_STATEH ) +#include "entity_state.h" +#endif + +#if !defined( PROGS_H ) +#include "progs.h" +#endif + +struct cl_entity_s +{ + int index; // Index into cl_entities ( should match actual slot, but not necessarily ) + + qboolean player; // True if this entity is a "player" + + entity_state_t baseline; // The original state from which to delta during an uncompressed message + entity_state_t prevstate; // The state information from the penultimate message received from the server + entity_state_t curstate; // The state information from the last message received from server + + int current_position; // Last received history update index + position_history_t ph[ HISTORY_MAX ]; // History of position and angle updates for this player + + mouth_t mouth; // For synchronizing mouth movements. + + latchedvars_t latched; // Variables used by studio model rendering routines + + // Information based on interplocation, extrapolation, prediction, or just copied from last msg received. + // + float lastmove; + + // Actual render position and angles + vec3_t origin; + vec3_t angles; + + // Attachment points + vec3_t attachment[4]; + + // Other entity local information + int trivial_accept; + + struct model_s *model; // cl.model_precache[ curstate.modelindes ]; all visible entities have a model + struct efrag_s *efrag; // linked list of efrags + struct mnode_s *topnode; // for bmodels, first world node that splits bmodel, or NULL if not split + + float syncbase; // for client-side animations -- used by obsolete alias animation system, remove? + int visframe; // last frame this entity was found in an active leaf + colorVec cvFloorColor; +}; + +#endif // !CL_ENTITYH \ No newline at end of file diff --git a/common/con_nprint.h b/common/con_nprint.h new file mode 100644 index 0000000..627d9f5 --- /dev/null +++ b/common/con_nprint.h @@ -0,0 +1,31 @@ +/*** +* +* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +#if !defined( CON_NPRINTH ) +#define CON_NPRINTH +#ifdef _WIN32 +#pragma once +#endif + +typedef struct con_nprint_s +{ + int index; // Row # + float time_to_live; // # of seconds before it dissappears + float color[ 3 ]; // RGB colors ( 0.0 -> 1.0 scale ) +} con_nprint_t; + +void Con_NPrintf( int idx, char *fmt, ... ); +void Con_NXPrintf( struct con_nprint_s *info, char *fmt, ... ); + +#endif \ No newline at end of file diff --git a/engine/const.h b/common/const.h similarity index 93% rename from engine/const.h rename to common/const.h index b992521..5489c13 100644 --- a/engine/const.h +++ b/common/const.h @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, Valve LLC. All rights reserved. +* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. * * This product contains software technology licensed from Id * Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. @@ -28,7 +28,7 @@ #define FL_MONSTER (1<<5) #define FL_GODMODE (1<<6) #define FL_NOTARGET (1<<7) -//#define FL_ITEM (1<<8) // NOT USED +#define FL_SKIPLOCALHOST (1<<8) // Don't send entity to local host, it's predicting this entity itself #define FL_ONGROUND (1<<9) // At rest / on the ground #define FL_PARTIALGROUND (1<<10) // not all corners are valid #define FL_WATERJUMP (1<<11) // player jumping out of water @@ -109,6 +109,9 @@ #define EF_NOINTERP 32 // don't interpolate the next frame #define EF_LIGHT 64 // rocket flare glow sprite #define EF_NODRAW 128 // don't draw entity + +// entity flags +#define EFLAG_SLERP 1 // do studio interpolation of this entity // // temp entity events @@ -176,6 +179,7 @@ // byte (life in 0.1's) // byte (width in 0.1's) // byte (amplitude in 0.01's) +// short (sprite model index) #define TE_BEAMENTS 8 // short (start entity) @@ -546,15 +550,15 @@ // byte ( color ) this is an index into an array of color vectors in the engine. (0 - ) // byte ( length * 10 ) -#define MSG_BROADCAST 0 // unreliable to all -#define MSG_ONE 1 // reliable to one (msg_entity) -#define MSG_ALL 2 // reliable to all -#define MSG_INIT 3 // write to the init string -#define MSG_PVS 4 // Ents in PVS of org -#define MSG_PAS 5 // Ents in PAS of org -#define MSG_PVS_R 6 // Reliable to PVS -#define MSG_PAS_R 7 // Reliable to PAS - +#define MSG_BROADCAST 0 // unreliable to all +#define MSG_ONE 1 // reliable to one (msg_entity) +#define MSG_ALL 2 // reliable to all +#define MSG_INIT 3 // write to the init string +#define MSG_PVS 4 // Ents in PVS of org +#define MSG_PAS 5 // Ents in PAS of org +#define MSG_PVS_R 6 // Reliable to PVS +#define MSG_PAS_R 7 // Reliable to PAS +#define MSG_ONE_UNRELIABLE 8 // Send to one client, but don't put in reliable stream, put in unreliable datagram ( could be dropped ) // contents of a spot in the world #define CONTENTS_EMPTY -1 @@ -616,22 +620,9 @@ #define SF_TRAIN_PASSABLE 8 // Train is not solid -- used to make water trains // buttons -#define IN_ATTACK (1 << 0) -#define IN_JUMP (1 << 1) -#define IN_DUCK (1 << 2) -#define IN_FORWARD (1 << 3) -#define IN_BACK (1 << 4) -#define IN_USE (1 << 5) -#define IN_CANCEL (1 << 6) -#define IN_LEFT (1 << 7) -#define IN_RIGHT (1 << 8) -#define IN_MOVELEFT (1 << 9) -#define IN_MOVERIGHT (1 << 10) -#define IN_ATTACK2 (1 << 11) -#define IN_RUN (1 << 12) -#define IN_RELOAD (1 << 13) -#define IN_ALT1 (1 << 14) -#define IN_ALT2 (1 << 15) +#ifndef IN_BUTTONS_H +#include "in_buttons.h" +#endif // Break Model Defines @@ -725,13 +716,18 @@ typedef struct unsigned r, g, b, a; } colorVec; +#ifdef _WIN32 #pragma pack(push,2) +#endif + typedef struct { unsigned short r, g, b, a; } PackedColorVec; -#pragma pack(pop) +#ifdef _WIN32 +#pragma pack(pop) +#endif typedef struct link_s { struct link_s *prev, *next; diff --git a/common/crc.h b/common/crc.h new file mode 100644 index 0000000..9852d00 --- /dev/null +++ b/common/crc.h @@ -0,0 +1,51 @@ +/*** +* +* Copyright (c) 1999, 2000, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +/* crc.h */ +#ifndef CRC_H +#define CRC_H +#ifdef _WIN32 +#pragma once +#endif + +// MD5 Hash +typedef struct +{ + unsigned int buf[4]; + unsigned int bits[2]; + unsigned char in[64]; +} MD5Context_t; + + +typedef unsigned long CRC32_t; +void CRC32_Init(CRC32_t *pulCRC); +CRC32_t CRC32_Final(CRC32_t pulCRC); +void CRC32_ProcessBuffer(CRC32_t *pulCRC, void *p, int len); +void CRC32_ProcessByte(CRC32_t *pulCRC, unsigned char ch); +int CRC_File(CRC32_t *crcvalue, char *pszFileName); +unsigned char COM_BlockSequenceCRCByte(unsigned char *base, int length, int sequence); + +void MD5Init(MD5Context_t *context); +void MD5Update(MD5Context_t *context, unsigned char const *buf, + unsigned int len); +void MD5Final(unsigned char digest[16], MD5Context_t *context); +void Transform(unsigned int buf[4], unsigned int const in[16]); + +int MD5_Hash_File(unsigned char digest[16], char *pszFileName, int bUsefopen, int bSeed, unsigned int seed[4]); +char *MD5_Print(unsigned char hash[16]); +int MD5_Hash_CachedFile(unsigned char digest[16], unsigned char *pCache, int nFileSize, int bSeed, unsigned int seed[4]); + +int CRC_MapFile(CRC32_t *crcvalue, char *pszFileName); + +#endif diff --git a/common/cvardef.h b/common/cvardef.h new file mode 100644 index 0000000..897e24e --- /dev/null +++ b/common/cvardef.h @@ -0,0 +1,36 @@ +/*** +* +* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +#ifndef CVARDEF_H +#define CVARDEF_H + +#define FCVAR_ARCHIVE (1<<0) // set to cause it to be saved to vars.rc +#define FCVAR_USERINFO (1<<1) // changes the client's info string +#define FCVAR_SERVER (1<<2) // notifies players when changed +#define FCVAR_EXTDLL (1<<3) // defined by external DLL +#define FCVAR_CLIENTDLL (1<<4) // defined by the client dll +#define FCVAR_PROTECTED (1<<5) // It's a server cvar, but we don't send the data since it's a password, etc. Sends 1 if it's not bland/zero, 0 otherwise as value +#define FCVAR_SPONLY (1<<6) // This cvar cannot be changed by clients connected to a multiplayer server. +#define FCVAR_PRINTABLEONLY (1<<7) // This cvar's string cannot contain unprintable characters ( e.g., used for player name etc ). +#define FCVAR_UNLOGGED (1<<8) // If this is a FCVAR_SERVER, don't log changes to the log file / console if we are creating a log + +typedef struct cvar_s +{ + char *name; + char *string; + int flags; + float value; + struct cvar_s *next; +} cvar_t; +#endif \ No newline at end of file diff --git a/common/demo_api.h b/common/demo_api.h new file mode 100644 index 0000000..3f9464b --- /dev/null +++ b/common/demo_api.h @@ -0,0 +1,31 @@ +/*** +* +* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +#if !defined ( DEMO_APIH ) +#define DEMO_APIH +#ifdef _WIN32 +#pragma once +#endif + +typedef struct demo_api_s +{ + int ( *IsRecording ) ( void ); + int ( *IsPlayingback ) ( void ); + int ( *IsTimeDemo ) ( void ); + void ( *WriteBuffer ) ( int size, unsigned char *buffer ); +} demo_api_t; + +extern demo_api_t demoapi; + +#endif \ No newline at end of file diff --git a/common/dlight.h b/common/dlight.h new file mode 100644 index 0000000..88a80e6 --- /dev/null +++ b/common/dlight.h @@ -0,0 +1,33 @@ +/*** +* +* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +#if !defined ( DLIGHTH ) +#define DLIGHTH +#ifdef _WIN32 +#pragma once +#endif + +typedef struct +{ + vec3_t origin; + float radius; + color24 color; + float die; // stop lighting after this time + float decay; // drop this each second + float minlight; // don't add when contributing less + int key; + qboolean dark; // subtracts light instead of adding +} dlight_t; + +#endif \ No newline at end of file diff --git a/common/dll_state.h b/common/dll_state.h new file mode 100644 index 0000000..eaf598c --- /dev/null +++ b/common/dll_state.h @@ -0,0 +1,15 @@ +//DLL State Flags + +#define DLL_INACTIVE 0 // no dll +#define DLL_ACTIVE 1 // dll is running +#define DLL_PAUSED 2 // dll is paused +#define DLL_CLOSE 3 // closing down dll +#define DLL_TRANS 4 // Level Transition + +// DLL Pause reasons + +#define DLL_NORMAL 0 // User hit Esc or something. +#define DLL_QUIT 4 // Quit now + +// DLL Substate info ( not relevant ) +#define ENG_NORMAL (1<<0) diff --git a/common/engine_launcher_api.h b/common/engine_launcher_api.h new file mode 100644 index 0000000..0b63260 --- /dev/null +++ b/common/engine_launcher_api.h @@ -0,0 +1,101 @@ +// engine/launcher interface +#if !defined( ENGINE_LAUNCHER_APIH ) +#define ENGINE_LAUNCHER_APIH +#ifdef _WIN32 +#pragma once +#endif + +//typedef void ( *xcommand_t ) ( void ); + +#define RENDERTYPE_UNDEFINED 0 +#define RENDERTYPE_SOFTWARE 1 +#define RENDERTYPE_HARDWARE 2 + +#define ENGINE_LAUNCHER_API_VERSION 1 + +typedef struct engine_api_s +{ + int version; + int rendertype; + int size; + + // Functions + int ( *GetEngineState ) ( void ); + void ( *Cbuf_AddText ) ( char *text ); // append cmd at end of buf + void ( *Cbuf_InsertText ) ( char *text ); // insert cmd at start of buf + void ( *Cmd_AddCommand ) ( char *cmd_name, void ( *funcname )( void ) ); + int ( *Cmd_Argc ) ( void ); + char *( *Cmd_Args ) ( void ); + char *( *Cmd_Argv ) ( int arg ); + void ( *Con_Printf ) ( char *, ... ); + void ( *Con_SafePrintf ) ( char *, ... ); + void ( *Cvar_Set ) ( char *var_name, char *value ); + void ( *Cvar_SetValue ) ( char *var_name, float value ); + int ( *Cvar_VariableInt ) ( char *var_name ); + char *( *Cvar_VariableString ) ( char *var_name ); + float ( *Cvar_VariableValue ) ( char *var_name ); + void ( *ForceReloadProfile ) ( void ); + int ( *GetGameInfo ) ( struct GameInfo_s *pGI, char *pszChannel ); + void ( *GameSetBackground ) ( int bBack ); + void ( *GameSetState ) ( int iState ); + void ( *GameSetSubState ) ( int iState ); + int ( *GetPauseState ) ( void ); + int ( *Host_Frame ) ( float time, int iState, int *stateInfo ); + void ( *Host_GetHostInfo ) ( float *fps, int *nActive, int *nSpectators, int *nMaxPlayers, char *pszMap ); + void ( *Host_Shutdown ) ( void ); + int ( *Game_Init ) ( char *lpCmdLine, unsigned char *pMem, int iSize, struct exefuncs_s *pef, void *, int ); + void ( *IN_ActivateMouse ) ( void ); + void ( *IN_ClearStates ) ( void ); + void ( *IN_DeactivateMouse ) ( void ); + void ( *IN_MouseEvent ) ( int mstate ); + void ( *Keyboard_ReturnToGame ) ( void ); + void ( *Key_ClearStates ) ( void ); + void ( *Key_Event ) ( int key, int down ); + int ( *LoadGame ) ( const char *pszSlot ); + void ( *S_BlockSound ) ( void ); + void ( *S_ClearBuffer ) ( void ); + void ( *S_GetDSPointer ) ( struct IDirectSound **lpDS, struct IDirectSoundBuffer **lpDSBuf ); + void *( *S_GetWAVPointer ) ( void ); + void ( *S_UnblockSound ) ( void ); + int ( *SaveGame ) ( const char *pszSlot, const char *pszComment ); + void ( *SetAuth ) ( void *pobj ); + void ( *SetMessagePumpDisableMode ) ( int bMode ); + void ( *SetPauseState ) ( int bPause ); + void ( *SetStartupMode ) ( int bMode ); + void ( *SNDDMA_Shutdown ) ( void ); + void ( *Snd_AcquireBuffer ) ( void ); + void ( *Snd_ReleaseBuffer ) ( void ); + void ( *StoreProfile ) ( void ); + double ( *Sys_FloatTime ) ( void ); + void ( *VID_UpdateWindowVars ) ( void *prc, int x, int y ); + void ( *VID_UpdateVID ) ( struct viddef_s *pvid ); + + // VGUI interfaces + void ( *VGui_CallEngineSurfaceProc ) ( void* hwnd, unsigned int msg, unsigned int wparam, long lparam ); + + // notifications that the launcher is taking/giving focus to the engine + void ( *EngineTakingFocus ) ( void ); + void ( *LauncherTakingFocus ) ( void ); + +#ifdef _WIN32 + // Only filled in by rendertype RENDERTYPE_HARDWARE + void ( *GL_Init ) ( void ); + int ( *GL_SetMode ) ( HWND hwndGame, HDC *pmaindc, HGLRC *pbaseRC, int fD3D, const char *p, const char *pszCmdLine ); + void ( *GL_Shutdown ) ( HWND hwnd, HDC hdc, HGLRC hglrc ); + + void ( *QGL_D3DShared ) ( struct tagD3DGlobals *d3dGShared ); + + int ( WINAPI *glSwapBuffers ) ( HDC dc ); +#else + // NOT USED IN LINUX!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + void ( *GL_Init ) ( void ); + void ( *GL_SetMode ) ( void ); + void ( *GL_Shutdown ) ( void ); + void ( *QGL_D3DShared ) ( void ); + void ( *glSwapBuffers ) ( void ); + // LINUX +#endif + +} engine_api_t; + +#endif // ENGINE_LAUNCHER_APIH \ No newline at end of file diff --git a/common/entity_state.h b/common/entity_state.h new file mode 100644 index 0000000..ee5c101 --- /dev/null +++ b/common/entity_state.h @@ -0,0 +1,193 @@ +/*** +* +* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +#if !defined( ENTITY_STATEH ) +#define ENTITY_STATEH +#ifdef _WIN32 +#pragma once +#endif + +// For entityType below +#define ENTITY_NORMAL (1<<0) +#define ENTITY_BEAM (1<<1) + +// Entity state is used for the baseline and for delta compression of a packet of +// entities that is sent to a client. +typedef struct entity_state_s entity_state_t; + +struct entity_state_s +{ +// Fields which are filled in by routines outside of delta compression + int entityType; + // Index into cl_entities array for this entity. + int number; + float msg_time; + + // Message number last time the player/entity state was updated. + int messagenum; + + // Fields which can be transitted and reconstructed over the network stream + vec3_t origin; + vec3_t angles; + + int modelindex; + int sequence; + float frame; + int colormap; + short skin; + short solid; + int effects; + float scale; + + byte eflags; + + // Render information + int rendermode; + int renderamt; + color24 rendercolor; + int renderfx; + + int movetype; + float animtime; + float framerate; + int body; + byte controller[4]; + byte blending[4]; + vec3_t velocity; + + // Send bbox down to client for use during prediction. + vec3_t mins; + vec3_t maxs; + + int aiment; + // If owned by a player, the index of that player ( for projectiles ). + int owner; + + // Friction, for prediction. + float friction; + // Gravity multiplier + float gravity; + +// PLAYER SPECIFIC + int team; + int playerclass; + int health; + qboolean spectator; + int weaponmodel; + int gaitsequence; + // If standing on conveyor, e.g. + vec3_t basevelocity; + // Use the crouched hull, or the regular player hull. + int usehull; + // Latched buttons last time state updated. + int oldbuttons; + // -1 = in air, else pmove entity number + int onground; + int iStepLeft; + // How fast we are falling + float flFallVelocity; + + float fov; + int weaponanim; + + // Parametric movement overrides + vec3_t startpos; + vec3_t endpos; + float impacttime; + float starttime; + + // For mods + int iuser1; + int iuser2; + int iuser3; + int iuser4; + float fuser1; + float fuser2; + float fuser3; + float fuser4; + vec3_t vuser1; + vec3_t vuser2; + vec3_t vuser3; + vec3_t vuser4; +}; + +#include "pm_info.h" + +typedef struct clientdata_s +{ + vec3_t origin; + vec3_t velocity; + + int viewmodel; + vec3_t punchangle; + int flags; + int waterlevel; + int watertype; + vec3_t view_ofs; + float health; + + int bInDuck; + + int weapons; // remove? + + int flTimeStepSound; + int flDuckTime; + int flSwimTime; + int waterjumptime; + + float maxspeed; + + float fov; + int weaponanim; + + int m_iId; + int ammo_shells; + int ammo_nails; + int ammo_cells; + int ammo_rockets; + float m_flNextAttack; + + int tfstate; + + int pushmsec; + + int deadflag; + + char physinfo[ MAX_PHYSINFO_STRING ]; + + // For mods + int iuser1; + int iuser2; + int iuser3; + int iuser4; + float fuser1; + float fuser2; + float fuser3; + float fuser4; + vec3_t vuser1; + vec3_t vuser2; + vec3_t vuser3; + vec3_t vuser4; +} clientdata_t; + +#include "weaponinfo.h" + +typedef struct local_state_s +{ + entity_state_t playerstate; + clientdata_t client; + weapon_data_t weapondata[ 32 ]; +} local_state_t; + +#endif // !ENTITY_STATEH \ No newline at end of file diff --git a/common/entity_types.h b/common/entity_types.h new file mode 100644 index 0000000..56c8f92 --- /dev/null +++ b/common/entity_types.h @@ -0,0 +1,26 @@ +/*** +* +* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +// entity_types.h +#if !defined( ENTITY_TYPESH ) +#define ENTITY_TYPESH + +#define ET_NORMAL 0 +#define ET_PLAYER 1 +#define ET_TEMPENTITY 2 +#define ET_BEAM 3 +// BMODEL or SPRITE that was split across BSP nodes +#define ET_FRAGMENTED 4 + +#endif // !ENTITY_TYPESH \ No newline at end of file diff --git a/common/event_api.h b/common/event_api.h new file mode 100644 index 0000000..2299ed9 --- /dev/null +++ b/common/event_api.h @@ -0,0 +1,51 @@ +/*** +* +* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +#if !defined ( EVENT_APIH ) +#define EVENT_APIH +#ifdef _WIN32 +#pragma once +#endif + +#define EVENT_API_VERSION 1 + +typedef struct event_api_s +{ + int version; + void ( *EV_PlaySound ) ( int ent, float *origin, int channel, const char *sample, float volume, float attenuation, int fFlags, int pitch ); + void ( *EV_StopSound ) ( int ent, int channel, const char *sample ); + int ( *EV_FindModelIndex )( const char *pmodel ); + int ( *EV_IsLocal ) ( int playernum ); + int ( *EV_LocalPlayerDucking ) ( void ); + void ( *EV_LocalPlayerViewheight ) ( float * ); + void ( *EV_LocalPlayerBounds ) ( int hull, float *mins, float *maxs ); + int ( *EV_IndexFromTrace) ( struct pmtrace_s *pTrace ); + struct physent_s *( *EV_GetPhysent ) ( int idx ); + void ( *EV_SetUpPlayerPrediction ) ( int dopred, int bIncludeLocalClient ); + void ( *EV_PushPMStates ) ( void ); + void ( *EV_PopPMStates ) ( void ); + void ( *EV_SetSolidPlayers ) (int playernum); + void ( *EV_SetTraceHull ) ( int hull ); + void ( *EV_PlayerTrace ) ( float *start, float *end, int traceFlags, int ignore_pe, struct pmtrace_s *tr ); + void ( *EV_WeaponAnimation ) ( int sequence, int body ); + unsigned short ( *EV_PrecacheEvent ) ( int type, const char* psz ); + void ( *EV_PlaybackEvent ) ( int flags, const struct edict_s *pInvoker, unsigned short eventindex, float delay, float *origin, float *angles, float fparam1, float fparam2, int iparam1, int iparam2, int bparam1, int bparam2 ); + const char *( *EV_TraceTexture ) ( int ground, float *vstart, float *vend ); + void ( *EV_StopAllSounds ) ( int entnum, int entchannel ); + void ( *EV_KillEvents ) ( int entnum, const char *eventname ); +} event_api_t; + +extern event_api_t eventapi; + +#endif diff --git a/common/event_args.h b/common/event_args.h new file mode 100644 index 0000000..a6b4eec --- /dev/null +++ b/common/event_args.h @@ -0,0 +1,51 @@ +/*** +* +* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +#if !defined( EVENT_ARGSH ) +#define EVENT_ARGSH +#ifdef _WIN32 +#pragma once +#endif + +// Event was invoked with stated origin +#define FEVENT_ORIGIN ( 1<<0 ) + +// Event was invoked with stated angles +#define FEVENT_ANGLES ( 1<<1 ) + +typedef struct event_args_s +{ + int flags; + + // Transmitted + int entindex; + + float origin[3]; + float angles[3]; + float velocity[3]; + + int ducking; + + float fparam1; + float fparam2; + + int iparam1; + int iparam2; + + int bparam1; + int bparam2; +} event_args_t; + +#endif + diff --git a/common/event_flags.h b/common/event_flags.h new file mode 100644 index 0000000..166ff68 --- /dev/null +++ b/common/event_flags.h @@ -0,0 +1,47 @@ +/*** +* +* Copyright (c) 1999, 2000, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +#if !defined( EVENT_FLAGSH ) +#define EVENT_FLAGSH +#ifdef _WIN32 +#pragma once +#endif + +// Skip local host for event send. +#define FEV_NOTHOST (1<<0) + +// Send the event reliably. You must specify the origin and angles and use +// PLAYBACK_EVENT_FULL for this to work correctly on the server for anything +// that depends on the event origin/angles. I.e., the origin/angles are not +// taken from the invoking edict for reliable events. +#define FEV_RELIABLE (1<<1) + +// Don't restrict to PAS/PVS, send this event to _everybody_ on the server ( useful for stopping CHAN_STATIC +// sounds started by client event when client is not in PVS anymore ( hwguy in TFC e.g. ). +#define FEV_GLOBAL (1<<2) + +// If this client already has one of these events in its queue, just update the event instead of sending it as a duplicate +// +#define FEV_UPDATE (1<<3) + +// Only send to entity specified as the invoker +#define FEV_HOSTONLY (1<<4) + +// Only send if the event was created on the server. +#define FEV_SERVER (1<<5) + +// Only issue event client side ( from shared code ) +#define FEV_CLIENT (1<<6) + +#endif \ No newline at end of file diff --git a/common/exefuncs.h b/common/exefuncs.h new file mode 100644 index 0000000..de5d47a --- /dev/null +++ b/common/exefuncs.h @@ -0,0 +1,41 @@ +// exefuncs.h +#ifndef EXEFUNCS_H +#define EXEFUNCS_H + +// Engine hands this to DLLs for functionality callbacks +typedef struct exefuncs_s +{ + int fMMX; + int iCPUMhz; + void (*unused1)(void); + void (*unused2)(void); + void (*unused3)(void); + void (*unused4)(void); + void (*VID_ForceLockState)(int lk); + int (*VID_ForceUnlockedAndReturnState)(void); + void (*unused5)(void); + void (*unused6)(void); + void (*unused7)(void); + void (*unused8)(void); + void (*unused9)(void); + void (*unused10)(void); + void (*unused11)(void); + void (*unused12)(void); + void (*unused13)(void); + void (*unused14)(void); + void (*unused15)(void); + void (*ErrorMessage)(int nLevel, const char *pszErrorMessage); + void (*unused16)(void); + void (*Sys_Printf)(char *fmt, ...); + void (*unused17)(void); + void (*unused18)(void); + void (*unused19)(void); + void (*unused20)(void); + void (*unused21)(void); + void (*unused22)(void); + void (*unused23)(void); + void (*unused24)(void); + void (*unused25)(void); +} exefuncs_t; + +#endif \ No newline at end of file diff --git a/common/in_buttons.h b/common/in_buttons.h new file mode 100644 index 0000000..cbca13c --- /dev/null +++ b/common/in_buttons.h @@ -0,0 +1,38 @@ +/*** +* +* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +#ifndef IN_BUTTONS_H +#define IN_BUTTONS_H +#ifdef _WIN32 +#pragma once +#endif + +#define IN_ATTACK (1 << 0) +#define IN_JUMP (1 << 1) +#define IN_DUCK (1 << 2) +#define IN_FORWARD (1 << 3) +#define IN_BACK (1 << 4) +#define IN_USE (1 << 5) +#define IN_CANCEL (1 << 6) +#define IN_LEFT (1 << 7) +#define IN_RIGHT (1 << 8) +#define IN_MOVELEFT (1 << 9) +#define IN_MOVERIGHT (1 << 10) +#define IN_ATTACK2 (1 << 11) +#define IN_RUN (1 << 12) +#define IN_RELOAD (1 << 13) +#define IN_ALT1 (1 << 14) +#define IN_SCORE (1 << 15) // Used by client.dll for when scoreboard is held down + +#endif // IN_BUTTONS_H \ No newline at end of file diff --git a/common/mathlib.h b/common/mathlib.h new file mode 100644 index 0000000..a6293ae --- /dev/null +++ b/common/mathlib.h @@ -0,0 +1,146 @@ +/*** +* +* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +// mathlib.h + +typedef float vec_t; +typedef vec_t vec3_t[3]; +typedef vec_t vec4_t[4]; // x,y,z,w +typedef vec_t vec5_t[5]; + +typedef short vec_s_t; +typedef vec_s_t vec3s_t[3]; +typedef vec_s_t vec4s_t[4]; // x,y,z,w +typedef vec_s_t vec5s_t[5]; + +typedef int fixed4_t; +typedef int fixed8_t; +typedef int fixed16_t; + +#ifndef M_PI +#define M_PI 3.14159265358979323846 // matches value in gcc v2 math.h +#endif + +struct mplane_s; + +extern vec3_t vec3_origin; +extern int nanmask; + +#define IS_NAN(x) (((*(int *)&x)&nanmask)==nanmask) + +#define DotProduct(x,y) ((x)[0]*(y)[0]+(x)[1]*(y)[1]+(x)[2]*(y)[2]) +#define VectorSubtract(a,b,c) {(c)[0]=(a)[0]-(b)[0];(c)[1]=(a)[1]-(b)[1];(c)[2]=(a)[2]-(b)[2];} +#define VectorAdd(a,b,c) {(c)[0]=(a)[0]+(b)[0];(c)[1]=(a)[1]+(b)[1];(c)[2]=(a)[2]+(b)[2];} +#define VectorCopy(a,b) {(b)[0]=(a)[0];(b)[1]=(a)[1];(b)[2]=(a)[2];} +#define VectorClear(a) {(a)[0]=0.0;(a)[1]=0.0;(a)[2]=0.0;} + +void VectorMA (const vec3_t veca, float scale, const vec3_t vecb, vec3_t vecc); + +vec_t _DotProduct (vec3_t v1, vec3_t v2); +void _VectorSubtract (vec3_t veca, vec3_t vecb, vec3_t out); +void _VectorAdd (vec3_t veca, vec3_t vecb, vec3_t out); +void _VectorCopy (vec3_t in, vec3_t out); + +int VectorCompare (const vec3_t v1, const vec3_t v2); +float Length (const vec3_t v); +void CrossProduct (const vec3_t v1, const vec3_t v2, vec3_t cross); +float VectorNormalize (vec3_t v); // returns vector length +void VectorInverse (vec3_t v); +void VectorScale (const vec3_t in, vec_t scale, vec3_t out); +int Q_log2(int val); + +void R_ConcatRotations (float in1[3][3], float in2[3][3], float out[3][3]); +void R_ConcatTransforms (float in1[3][4], float in2[3][4], float out[3][4]); + +// Here are some "manual" INLINE routines for doing floating point to integer conversions +extern short new_cw, old_cw; + +typedef union DLONG { + int i[2]; + double d; + float f; + } DLONG; + +extern DLONG dlong; + +#ifdef _WIN32 +void __inline set_fpu_cw(void) +{ +_asm + { wait + fnstcw old_cw + wait + mov ax, word ptr old_cw + or ah, 0xc + mov word ptr new_cw,ax + fldcw new_cw + } +} + +int __inline quick_ftol(float f) +{ + _asm { + // Assumes that we are already in chop mode, and only need a 32-bit int + fld DWORD PTR f + fistp DWORD PTR dlong + } + return dlong.i[0]; +} + +void __inline restore_fpu_cw(void) +{ + _asm fldcw old_cw +} +#else +#define set_fpu_cw() /* */ +#define quick_ftol(f) ftol(f) +#define restore_fpu_cw() /* */ +#endif + +void FloorDivMod (double numer, double denom, int *quotient, + int *rem); +fixed16_t Invert24To16(fixed16_t val); +int GreatestCommonDivisor (int i1, int i2); + +void AngleVectors (const vec3_t angles, vec3_t forward, vec3_t right, vec3_t up); +void AngleVectorsTranspose (const vec3_t angles, vec3_t forward, vec3_t right, vec3_t up); +#define AngleIVectors AngleVectorsTranspose + +void AngleMatrix (const vec3_t angles, float (*matrix)[4] ); +void AngleIMatrix (const vec3_t angles, float (*matrix)[4] ); +void VectorTransform (const vec3_t in1, float in2[3][4], vec3_t out); + +void VectorMatrix( vec3_t forward, vec3_t right, vec3_t up); +void VectorAngles( const vec3_t forward, vec3_t angles ); + +int BoxOnPlaneSide (vec3_t emins, vec3_t emaxs, struct mplane_s *plane); +float anglemod(float a); + + + +#define BOX_ON_PLANE_SIDE(emins, emaxs, p) \ + (((p)->type < 3)? \ + ( \ + ((p)->dist <= (emins)[(p)->type])? \ + 1 \ + : \ + ( \ + ((p)->dist >= (emaxs)[(p)->type])?\ + 2 \ + : \ + 3 \ + ) \ + ) \ + : \ + BoxOnPlaneSide( (emins), (emaxs), (p))) diff --git a/common/net_api.h b/common/net_api.h new file mode 100644 index 0000000..769a6f2 --- /dev/null +++ b/common/net_api.h @@ -0,0 +1,92 @@ +#if !defined( NET_APIH ) +#define NET_APIH +#ifdef _WIN32 +#pragma once +#endif + +#if !defined ( NETADRH ) +#include "netadr.h" +#endif + +#define NETAPI_REQUEST_SERVERLIST ( 0 ) // Doesn't need a remote address +#define NETAPI_REQUEST_PING ( 1 ) +#define NETAPI_REQUEST_RULES ( 2 ) +#define NETAPI_REQUEST_PLAYERS ( 3 ) +#define NETAPI_REQUEST_DETAILS ( 4 ) + +// Set this flag for things like broadcast requests, etc. where the engine should not +// kill the request hook after receiving the first response +#define FNETAPI_MULTIPLE_RESPONSE ( 1<<0 ) + +typedef void ( *net_api_response_func_t ) ( struct net_response_s *response ); + +#define NET_SUCCESS ( 0 ) +#define NET_ERROR_TIMEOUT ( 1<<0 ) +#define NET_ERROR_PROTO_UNSUPPORTED ( 1<<1 ) +#define NET_ERROR_UNDEFINED ( 1<<2 ) + +typedef struct net_adrlist_s +{ + struct net_adrlist_s *next; + netadr_t remote_address; +} net_adrlist_t; + +typedef struct net_response_s +{ + // NET_SUCCESS or an error code + int error; + + // Context ID + int context; + // Type + int type; + + // Server that is responding to the request + netadr_t remote_address; + + // Response RTT ping time + double ping; + // Key/Value pair string ( separated by backlash \ characters ) + // WARNING: You must copy this buffer in the callback function, because it is freed + // by the engine right after the call!!!! + // ALSO: For NETAPI_REQUEST_SERVERLIST requests, this will be a pointer to a linked list of net_adrlist_t's + void *response; +} net_response_t; + +typedef struct net_status_s +{ + // Connected to remote server? 1 == yes, 0 otherwise + int connected; + // Client's IP address + netadr_t local_address; + // Address of remote server + netadr_t remote_address; + // Packet Loss ( as a percentage ) + int packet_loss; + // Latency, in seconds ( multiply by 1000.0 to get milliseconds ) + double latency; + // Connection time, in seconds + double connection_time; + // Rate setting ( for incoming data ) + double rate; +} net_status_t; + +typedef struct net_api_s +{ + // APIs + void ( *InitNetworking )( void ); + void ( *Status ) ( struct net_status_s *status ); + void ( *SendRequest) ( int context, int request, int flags, double timeout, struct netadr_s *remote_address, net_api_response_func_t response ); + void ( *CancelRequest ) ( int context ); + void ( *CancelAllRequests ) ( void ); + char *( *AdrToString ) ( struct netadr_s *a ); + int ( *CompareAdr ) ( struct netadr_s *a, struct netadr_s *b ); + int ( *StringToAdr ) ( char *s, struct netadr_s *a ); + const char *( *ValueForKey ) ( const char *s, const char *key ); + void ( *RemoveKey ) ( char *s, const char *key ); + void ( *SetValueForKey ) (char *s, const char *key, const char *value, int maxsize ); +} net_api_t; + +extern net_api_t netapi; + +#endif // NET_APIH \ No newline at end of file diff --git a/common/netadr.h b/common/netadr.h new file mode 100644 index 0000000..593903a --- /dev/null +++ b/common/netadr.h @@ -0,0 +1,40 @@ +/*** +* +* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +// netadr.h +#ifndef NETADR_H +#define NETADR_H +#ifdef _WIN32 +#pragma once +#endif + +typedef enum +{ + NA_UNUSED, + NA_LOOPBACK, + NA_BROADCAST, + NA_IP, + NA_IPX, + NA_BROADCAST_IPX +} netadrtype_t; + +typedef struct netadr_s +{ + netadrtype_t type; + unsigned char ip[4]; + unsigned char ipx[10]; + unsigned short port; +} netadr_t; + +#endif // NETADR_H \ No newline at end of file diff --git a/common/particledef.h b/common/particledef.h new file mode 100644 index 0000000..c2f3ef1 --- /dev/null +++ b/common/particledef.h @@ -0,0 +1,57 @@ +/*** +* +* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +#if !defined( PARTICLEDEFH ) +#define PARTICLEDEFH +#ifdef _WIN32 +#pragma once +#endif + +typedef enum { + pt_static, + pt_grav, + pt_slowgrav, + pt_fire, + pt_explode, + pt_explode2, + pt_blob, + pt_blob2, + pt_vox_slowgrav, + pt_vox_grav, + pt_clientcustom // Must have callback function specified +} ptype_t; + +// !!! if this is changed, it must be changed in d_ifacea.h too !!! +typedef struct particle_s +{ +// driver-usable fields + vec3_t org; + short color; + short packedColor; +// drivers never touch the following fields + struct particle_s *next; + vec3_t vel; + float ramp; + float die; + ptype_t type; + void (*deathfunc)( struct particle_s *particle ); + + // for pt_clientcusttom, we'll call this function each frame + void (*callback)( struct particle_s *particle, float frametime ); + + // for deathfunc, etc. + unsigned char context; +} particle_t; + +#endif \ No newline at end of file diff --git a/common/pmtrace.h b/common/pmtrace.h new file mode 100644 index 0000000..02bf18c --- /dev/null +++ b/common/pmtrace.h @@ -0,0 +1,43 @@ +/*** +* +* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +#if !defined( PMTRACEH ) +#define PMTRACEH +#ifdef _WIN32 +#pragma once +#endif + +typedef struct +{ + vec3_t normal; + float dist; +} pmplane_t; + +typedef struct pmtrace_s pmtrace_t; + +struct pmtrace_s +{ + qboolean allsolid; // if true, plane is not valid + qboolean startsolid; // if true, the initial point was in a solid area + qboolean inopen, inwater; // End point is in empty space or in water + float fraction; // time completed, 1.0 = didn't hit anything + vec3_t endpos; // final position + pmplane_t plane; // surface normal at impact + int ent; // entity at impact + vec3_t deltavelocity; // Change in player's velocity caused by impact. + // Only run on server. + int hitgroup; +}; + +#endif \ No newline at end of file diff --git a/common/qfont.h b/common/qfont.h new file mode 100644 index 0000000..4233191 --- /dev/null +++ b/common/qfont.h @@ -0,0 +1,40 @@ +/*** +* +* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +#if !defined( QFONTH ) +#define QFONTH +#ifdef _WIN32 +#pragma once +#endif + +// Font stuff + +#define NUM_GLYPHS 256 + +typedef struct +{ + short startoffset; + short charwidth; +} charinfo; + +typedef struct qfont_s +{ + int width, height; + int rowcount; + int rowheight; + charinfo fontinfo[ NUM_GLYPHS ]; + byte data[4]; +} qfont_t; + +#endif // qfont.h \ No newline at end of file diff --git a/common/r_efx.h b/common/r_efx.h new file mode 100644 index 0000000..e8881bd --- /dev/null +++ b/common/r_efx.h @@ -0,0 +1,194 @@ +/*** +* +* Copyright (c) 1999, 2000, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +#if !defined ( R_EFXH ) +#define R_EFXH +#pragma once + +// particle_t +#if !defined( PARTICLEDEFH ) +#include "particledef.h" +#endif + +// BEAM +#if !defined( BEAMDEFH ) +#include "beamdef.h" +#endif + +// dlight_t +#if !defined ( DLIGHTH ) +#include "dlight.h" +#endif + +// cl_entity_t +#if !defined( CL_ENTITYH ) +#include "cl_entity.h" +#endif + +/* +// FOR REFERENCE, These are the built-in tracer colors. Note, color 4 is the one +// that uses the tracerred/tracergreen/tracerblue and traceralpha cvar settings +color24 gTracerColors[] = +{ + { 255, 255, 255 }, // White + { 255, 0, 0 }, // Red + { 0, 255, 0 }, // Green + { 0, 0, 255 }, // Blue + { 0, 0, 0 }, // Tracer default, filled in from cvars, etc. + { 255, 167, 17 }, // Yellow-orange sparks + { 255, 130, 90 }, // Yellowish streaks (garg) + { 55, 60, 144 }, // Blue egon streak + { 255, 130, 90 }, // More Yellowish streaks (garg) + { 255, 140, 90 }, // More Yellowish streaks (garg) + { 200, 130, 90 }, // More red streaks (garg) + { 255, 120, 70 }, // Darker red streaks (garg) +}; +*/ + +// Temporary entity array +#define TENTPRIORITY_LOW 0 +#define TENTPRIORITY_HIGH 1 + +// TEMPENTITY flags +#define FTENT_NONE 0x00000000 +#define FTENT_SINEWAVE 0x00000001 +#define FTENT_GRAVITY 0x00000002 +#define FTENT_ROTATE 0x00000004 +#define FTENT_SLOWGRAVITY 0x00000008 +#define FTENT_SMOKETRAIL 0x00000010 +#define FTENT_COLLIDEWORLD 0x00000020 +#define FTENT_FLICKER 0x00000040 +#define FTENT_FADEOUT 0x00000080 +#define FTENT_SPRANIMATE 0x00000100 +#define FTENT_HITSOUND 0x00000200 +#define FTENT_SPIRAL 0x00000400 +#define FTENT_SPRCYCLE 0x00000800 +#define FTENT_COLLIDEALL 0x00001000 // will collide with world and slideboxes +#define FTENT_PERSIST 0x00002000 // tent is not removed when unable to draw +#define FTENT_COLLIDEKILL 0x00004000 // tent is removed upon collision with anything +#define FTENT_PLYRATTACHMENT 0x00008000 // tent is attached to a player (owner) +#define FTENT_SPRANIMATELOOP 0x00010000 // animating sprite doesn't die when last frame is displayed +#define FTENT_SPARKSHOWER 0x00020000 +#define FTENT_NOMODEL 0x00040000 // Doesn't have a model, never try to draw ( it just triggers other things ) +#define FTENT_CLIENTCUSTOM 0x00080000 // Must specify callback. Callback function is responsible for killing tempent and updating fields ( unless other flags specify how to do things ) + +typedef struct tempent_s TEMPENTITY; +typedef struct tempent_s +{ + int flags; + float die; + float frameMax; + float x; + float y; + float z; + float fadeSpeed; + float bounceFactor; + int hitSound; + void ( *hitcallback ) ( struct tempent_s *ent, struct pmtrace_s *ptr ); + void ( *callback ) ( struct tempent_s *ent, float frametime, float currenttime ); + TEMPENTITY *next; + int priority; + short clientIndex; // if attached, this is the index of the client to stick to + // if COLLIDEALL, this is the index of the client to ignore + // TENTS with FTENT_PLYRATTACHMENT MUST set the clientindex! + + vec3_t tentOffset; // if attached, client origin + tentOffset = tent origin. + cl_entity_t entity; + + // baseline.origin - velocity + // baseline.renderamt - starting fadeout intensity + // baseline.angles - angle velocity +} TEMPENTITY; + +typedef struct efx_api_s efx_api_t; + +struct efx_api_s +{ + particle_t *( *R_AllocParticle ) ( void ( *callback ) ( struct particle_s *particle, float frametime ) ); + void ( *R_BlobExplosion ) ( float * org ); + void ( *R_Blood ) ( float * org, float * dir, int pcolor, int speed ); + void ( *R_BloodSprite ) ( float * org, int colorindex, int modelIndex, int modelIndex2, float size ); + void ( *R_BloodStream ) ( float * org, float * dir, int pcolor, int speed ); + void ( *R_BreakModel ) ( float *pos, float *size, float *dir, float random, float life, int count, int modelIndex, char flags ); + void ( *R_Bubbles ) ( float * mins, float * maxs, float height, int modelIndex, int count, float speed ); + void ( *R_BubbleTrail ) ( float * start, float * end, float height, int modelIndex, int count, float speed ); + void ( *R_BulletImpactParticles ) ( float * pos ); + void ( *R_EntityParticles ) ( struct cl_entity_s *ent ); + void ( *R_Explosion ) ( float *pos, int model, float scale, float framerate, int flags ); + void ( *R_FizzEffect ) ( struct cl_entity_s *pent, int modelIndex, int density ); + void ( *R_FireField ) ( float * org, int radius, int modelIndex, int count, int flags, float life ); + void ( *R_FlickerParticles ) ( float * org ); + void ( *R_FunnelSprite ) ( float *org, int modelIndex, int reverse ); + void ( *R_Implosion ) ( float * end, float radius, int count, float life ); + void ( *R_LargeFunnel ) ( float * org, int reverse ); + void ( *R_LavaSplash ) ( float * org ); + void ( *R_MultiGunshot ) ( float * org, float * dir, float * noise, int count, int decalCount, int *decalIndices ); + void ( *R_MuzzleFlash ) ( float *pos1, int type ); + void ( *R_ParticleBox ) ( float *mins, float *maxs, unsigned char r, unsigned char g, unsigned char b, float life ); + void ( *R_ParticleBurst ) ( float * pos, int size, int color, float life ); + void ( *R_ParticleExplosion ) ( float * org ); + void ( *R_ParticleExplosion2 ) ( float * org, int colorStart, int colorLength ); + void ( *R_ParticleLine ) ( float * start, float *end, unsigned char r, unsigned char g, unsigned char b, float life ); + void ( *R_PlayerSprites ) ( int client, int modelIndex, int count, int size ); + void ( *R_Projectile ) ( float * origin, float * velocity, int modelIndex, int life, int owner, void (*hitcallback)( struct tempent_s *ent, struct pmtrace_s *ptr ) ); + void ( *R_RicochetSound ) ( float * pos ); + void ( *R_RicochetSprite ) ( float *pos, struct model_s *pmodel, float duration, float scale ); + void ( *R_RocketFlare ) ( float *pos ); + void ( *R_RocketTrail ) ( float * start, float * end, int type ); + void ( *R_RunParticleEffect ) ( float * org, float * dir, int color, int count ); + void ( *R_ShowLine ) ( float * start, float * end ); + void ( *R_SparkEffect ) ( float *pos, int count, int velocityMin, int velocityMax ); + void ( *R_SparkShower ) ( float *pos ); + void ( *R_SparkStreaks ) ( float * pos, int count, int velocityMin, int velocityMax ); + void ( *R_Spray ) ( float * pos, float * dir, int modelIndex, int count, int speed, int spread, int rendermode ); + void ( *R_Sprite_Explode ) ( TEMPENTITY *pTemp, float scale, int flags ); + void ( *R_Sprite_Smoke ) ( TEMPENTITY *pTemp, float scale ); + void ( *R_Sprite_Spray ) ( float * pos, float * dir, int modelIndex, int count, int speed, int iRand ); + void ( *R_Sprite_Trail ) ( int type, float * start, float * end, int modelIndex, int count, float life, float size, float amplitude, int renderamt, float speed ); + void ( *R_Sprite_WallPuff ) ( TEMPENTITY *pTemp, float scale ); + void ( *R_StreakSplash ) ( float * pos, float * dir, int color, int count, float speed, int velocityMin, int velocityMax ); + void ( *R_TracerEffect ) ( float * start, float * end ); + void ( *R_UserTracerParticle ) ( float * org, float * vel, float life, int colorIndex, float length, unsigned char deathcontext, void ( *deathfunc)( struct particle_s *particle ) ); + particle_t *( *R_TracerParticles ) ( float * org, float * vel, float life ); + void ( *R_TeleportSplash ) ( float * org ); + void ( *R_TempSphereModel ) ( float *pos, float speed, float life, int count, int modelIndex ); + TEMPENTITY *( *R_TempModel ) ( float *pos, float *dir, float *angles, float life, int modelIndex, int soundtype ); + TEMPENTITY *( *R_DefaultSprite ) ( float *pos, int spriteIndex, float framerate ); + TEMPENTITY *( *R_TempSprite ) ( float *pos, float *dir, float scale, int modelIndex, int rendermode, int renderfx, float a, float life, int flags ); + int ( *Draw_DecalIndex ) ( int id ); + int ( *Draw_DecalIndexFromName ) ( char *name ); + void ( *R_DecalShoot ) ( int textureIndex, int entity, int modelIndex, float * position, int flags ); + void ( *R_AttachTentToPlayer ) ( int client, int modelIndex, float zoffset, float life ); + void ( *R_KillAttachedTents ) ( int client ); + BEAM *( *R_BeamCirclePoints ) ( int type, float * start, float * end, int modelIndex, float life, float width, float amplitude, float brightness, float speed, int startFrame, float framerate, float r, float g, float b ); + BEAM *( *R_BeamEntPoint ) ( int startEnt, float * end, int modelIndex, float life, float width, float amplitude, float brightness, float speed, int startFrame, float framerate, float r, float g, float b ); + BEAM *( *R_BeamEnts ) ( int startEnt, int endEnt, int modelIndex, float life, float width, float amplitude, float brightness, float speed, int startFrame, float framerate, float r, float g, float b ); + BEAM *( *R_BeamFollow ) ( int startEnt, int modelIndex, float life, float width, float r, float g, float b, float brightness ); + void ( *R_BeamKill ) ( int deadEntity ); + BEAM *( *R_BeamLightning ) ( float * start, float * end, int modelIndex, float life, float width, float amplitude, float brightness, float speed ); + BEAM *( *R_BeamPoints ) ( float * start, float * end, int modelIndex, float life, float width, float amplitude, float brightness, float speed, int startFrame, float framerate, float r, float g, float b ); + BEAM *( *R_BeamRing ) ( int startEnt, int endEnt, int modelIndex, float life, float width, float amplitude, float brightness, float speed, int startFrame, float framerate, float r, float g, float b ); + dlight_t *( *CL_AllocDlight ) ( int key ); + dlight_t *( *CL_AllocElight ) ( int key ); + TEMPENTITY *( *CL_TempEntAlloc ) ( float * org, struct model_s *model ); + TEMPENTITY *( *CL_TempEntAllocNoModel ) ( float * org ); + TEMPENTITY *( *CL_TempEntAllocHigh ) ( float * org, struct model_s *model ); + TEMPENTITY *( *CL_TentEntAllocCustom ) ( float *origin, struct model_s *model, int high, void ( *callback ) ( struct tempent_s *ent, float frametime, float currenttime ) ); + void ( *R_GetPackedColor ) ( short *packed, short color ); + short ( *R_LookupColor ) ( unsigned char r, unsigned char g, unsigned char b ); +}; + +extern efx_api_t efx; + +#endif \ No newline at end of file diff --git a/common/ref_params.h b/common/ref_params.h new file mode 100644 index 0000000..28078f5 --- /dev/null +++ b/common/ref_params.h @@ -0,0 +1,69 @@ +/*** +* +* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +#if !defined( REF_PARAMSH ) +#define REF_PARAMSH + +typedef struct ref_params_s +{ + // Output + float vieworg[3]; + float viewangles[3]; + + float forward[3]; + float right[3]; + float up[3]; + + // Client frametime; + float frametime; + // Client time + float time; + + // Misc + int intermission; + int paused; + int spectator; + int onground; + int waterlevel; + + float simvel[3]; + float simorg[3]; + + float viewheight[3]; + float idealpitch; + + float cl_viewangles[3]; + + int health; + float crosshairangle[3]; + float viewsize; + + float punchangle[3]; + int maxclients; + int viewentity; + int playernum; + int max_entities; + int demoplayback; + int hardware; + + int smoothing; + + // Last issued usercmd + struct usercmd_s *cmd; + + // Movevars + struct movevars_s *movevars; +} ref_params_t; + +#endif // !REF_PARAMSH \ No newline at end of file diff --git a/common/screenfade.h b/common/screenfade.h new file mode 100644 index 0000000..3e08dca --- /dev/null +++ b/common/screenfade.h @@ -0,0 +1,16 @@ +#if !defined( SCREENFADEH ) +#define SCREENFADEH +#ifdef _WIN32 +#pragma once +#endif + +typedef struct screenfade_s +{ + float fadeSpeed; // How fast to fade (tics / second) (+ fade in, - fade out) + float fadeEnd; // When the fading hits maximum + float fadeReset; // When to reset to not fading (for fadeout and hold) + byte fader, fadeg, fadeb, fadealpha; // Fade color + int fadeFlags; // Fading flags +} screenfade_t; + +#endif // !SCREENFADEH \ No newline at end of file diff --git a/common/studio_event.h b/common/studio_event.h new file mode 100644 index 0000000..93c2860 --- /dev/null +++ b/common/studio_event.h @@ -0,0 +1,29 @@ +/*** +* +* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +#if !defined( STUDIO_EVENTH ) +#define STUDIO_EVENTH +#ifdef _WIN32 +#pragma once +#endif + +typedef struct mstudioevent_s +{ + int frame; + int event; + int type; + char options[64]; +} mstudioevent_t; + +#endif // STUDIO_EVENTH \ No newline at end of file diff --git a/common/triangleapi.h b/common/triangleapi.h new file mode 100644 index 0000000..a89918f --- /dev/null +++ b/common/triangleapi.h @@ -0,0 +1,54 @@ +/*** +* +* Copyright (c) 1999, 2000, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +#if !defined( TRIANGLEAPIH ) +#define TRIANGLEAPIH +#pragma once + +typedef enum +{ + TRI_FRONT = 0, + TRI_NONE = 1, +} TRICULLSTYLE; + +#define TRI_API_VERSION 1 + +#define TRI_TRIANGLES 0 +#define TRI_TRIANGLE_FAN 1 +#define TRI_QUADS 2 +#define TRI_POLYGON 3 +#define TRI_LINES 4 +#define TRI_TRIANGLE_STRIP 5 +#define TRI_QUAD_STRIP 6 + +typedef struct triangleapi_s +{ + int version; + + void ( *RenderMode )( int mode ); + void ( *Begin )( int primitiveCode ); + void ( *End ) ( void ); + + void ( *Color4f ) ( float r, float g, float b, float a ); + void ( *Color4ub ) ( unsigned char r, unsigned char g, unsigned char b, unsigned char a ); + void ( *TexCoord2f ) ( float u, float v ); + void ( *Vertex3fv ) ( float *worldPnt ); + void ( *Vertex3f ) ( float x, float y, float z ); + void ( *Brightness ) ( float brightness ); + void ( *CullFace ) ( TRICULLSTYLE style ); + int ( *SpriteTexture ) ( struct model_s *pSpriteModel, int frame ); + int ( *WorldToScreen ) ( float *world, float *screen ); // Returns 1 if it's z clipped +} triangleapi_t; + +#endif // !TRIANGLEAPIH \ No newline at end of file diff --git a/common/usercmd.h b/common/usercmd.h new file mode 100644 index 0000000..3c69c70 --- /dev/null +++ b/common/usercmd.h @@ -0,0 +1,41 @@ +/*** +* +* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +#ifndef USERCMD_H +#define USERCMD_H +#ifdef _WIN32 +#pragma once +#endif + +typedef struct usercmd_s +{ + short lerp_msec; // Interpolation time on client + byte msec; // Duration in ms of command + vec3_t viewangles; // Command view angles. + +// intended velocities + float forwardmove; // Forward velocity. + float sidemove; // Sideways velocity. + float upmove; // Upward velocity. + byte lightlevel; // Light level at spot where we are standing. + unsigned short buttons; // Attack buttons + byte impulse; // Impulse command issued. + byte weaponselect; // Current weapon id + +// Experimental player impact stuff. + int impact_index; + vec3_t impact_position; +} usercmd_t; + +#endif // USERCMD_H \ No newline at end of file diff --git a/common/weaponinfo.h b/common/weaponinfo.h new file mode 100644 index 0000000..50f940c --- /dev/null +++ b/common/weaponinfo.h @@ -0,0 +1,52 @@ +/*** +* +* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +#if !defined ( WEAPONINFOH ) +#define WEAPONINFOH +#ifdef _WIN32 +#pragma once +#endif + +// Info about weapons player might have in his/her possession +typedef struct weapon_data_s +{ + int m_iId; + int m_iClip; + + float m_flNextPrimaryAttack; + float m_flNextSecondaryAttack; + float m_flTimeWeaponIdle; + + int m_fInReload; + int m_fInSpecialReload; + float m_flNextReload; + float m_flPumpTime; + float m_fReloadTime; + + float m_fAimedDamage; + float m_fNextAimBonus; + int m_fInZoom; + int m_iWeaponState; + + int iuser1; + int iuser2; + int iuser3; + int iuser4; + float fuser1; + float fuser2; + float fuser3; + float fuser4; +} weapon_data_t; + +#endif \ No newline at end of file diff --git a/dedicated/Dedicated.dsp b/dedicated/Dedicated.dsp new file mode 100644 index 0000000..8d61c5c --- /dev/null +++ b/dedicated/Dedicated.dsp @@ -0,0 +1,172 @@ +# Microsoft Developer Studio Project File - Name="Dedicated" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Application" 0x0101 + +CFG=Dedicated - Win32 Release +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "Dedicated.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "Dedicated.mak" CFG="Dedicated - Win32 Release" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "Dedicated - Win32 Release" (based on "Win32 (x86) Application") +!MESSAGE "Dedicated - Win32 Debug" (based on "Win32 (x86) Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName ""$/GoldSrc/dedicated", DJEBAAAA" +# PROP Scc_LocalPath "." +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "Dedicated - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir ".\Release" +# PROP BASE Intermediate_Dir ".\Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir ".\Release" +# PROP Intermediate_Dir ".\Release" +# 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 /MT /W3 /GX /O2 /I "..\engine" /I "..\common" /I "..\dedicated" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "DEDICATED" /D "LAUNCHERONLY" /YX /FD /c +# ADD BASE MTL /nologo /D "NDEBUG" /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# 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 wsock32.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 winmm.lib ..\utils\procinfo\lib\win32_vc6\procinfo.lib /nologo /subsystem:windows /machine:I386 /out:".\Release/hlds.exe" +# SUBTRACT LINK32 /map /debug +# Begin Custom Build +ProjDir=. +InputPath=.\Release\hlds.exe +InputName=hlds +SOURCE="$(InputPath)" + +"$(ProjDir)\..\..\$(InputName).exe" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + xcopy $(InputPath) $(ProjDir)\..\..\ /R /Q + +# End Custom Build + +!ELSEIF "$(CFG)" == "Dedicated - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir ".\Debug" +# PROP BASE Intermediate_Dir ".\Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir ".\Debug" +# PROP Intermediate_Dir ".\Debug" +# 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 /MTd /W3 /Gm /GX /ZI /Od /I "..\engine" /I "..\common" /I "..\dedicated" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "DEDICATED" /D "LAUNCHERONLY" /YX /FD /c +# ADD BASE MTL /nologo /D "_DEBUG" /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# 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 /debug /machine:I386 +# ADD LINK32 wsock32.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 winmm.lib ..\utils\procinfo\lib\win32_vc6\procinfo.lib /nologo /subsystem:windows /map /debug /machine:I386 /out:".\Debug/hlds.exe" +# Begin Custom Build +ProjDir=. +InputPath=.\Debug\hlds.exe +InputName=hlds +SOURCE="$(InputPath)" + +"$(ProjDir)\..\..\$(InputName).exe" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + xcopy $(InputPath) $(ProjDir)\..\..\ /R /Q + +# End Custom Build + +!ENDIF + +# Begin Target + +# Name "Dedicated - Win32 Release" +# Name "Dedicated - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat;for;f90" +# Begin Source File + +SOURCE=.\conproc.cpp +# End Source File +# Begin Source File + +SOURCE=.\dedicated.rc +# End Source File +# Begin Source File + +SOURCE=.\engine.cpp +# End Source File +# Begin Source File + +SOURCE=.\md5.cpp +# End Source File +# Begin Source File + +SOURCE=.\sys_ded.cpp +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl;fi;fd" +# Begin Source File + +SOURCE=.\conproc.h +# End Source File +# Begin Source File + +SOURCE=..\common\crc.h +# End Source File +# Begin Source File + +SOURCE=.\dedicated.h +# End Source File +# Begin Source File + +SOURCE=.\md5.h +# End Source File +# Begin Source File + +SOURCE=.\resource.h +# End Source File +# Begin Source File + +SOURCE=.\sys_ded.h +# End Source File +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;cnt;rtf;gif;jpg;jpeg;jpe" +# Begin Source File + +SOURCE=.\NetGame.ico +# End Source File +# End Group +# End Target +# End Project diff --git a/dedicated/Makefile b/dedicated/Makefile new file mode 100644 index 0000000..a4dfef7 --- /dev/null +++ b/dedicated/Makefile @@ -0,0 +1,55 @@ +# +# hlds_run (front end for hlds_l) Makefile for Linux i386 +# +# May 2000, Leon Hartwig (hartwig@valvesoftware.com) +# + +#make sure this is the correct compiler for your system +CC=gcc + +SRCDIR=. +OBJDIR=$(SRCDIR)/obj + +#safe optimization +CFLAGS=-w -m486 -O1 + +#full optimization +#CFLAGS=-w -m486 -O2 \ + -ffast-math -funroll-loops \ + -fexpensive-optimizations -malign-loops=2 \ + -malign-jumps=2 -malign-functions=2 + +#use these when debugging +#CFLAGS=$(BASE_CFLAGS) -g + +LDFLAGS=-lgcc -ldl + +AR=ar +RANLIB=ranlib + +INCLUDEDIRS=-I. -I../common + +DO_CC=$(CC) $(INCLUDEDIRS) $(CFLAGS) -o $@ -c $< + +############################################################################# +# HLDS FRONT END +############################################################################# + +$(OBJDIR)/%.o: $(SRCDIR)/%.cpp + $(DO_CC) + +OBJ = \ + $(OBJDIR)/sys_ded.o \ + $(OBJDIR)/engine.o \ + $(OBJDIR)/md5.o + +hlds_run : neat $(OBJ) + $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(OBJ) +neat: + -mkdir $(OBJDIR) +clean: + -rm -f $(OBJ) + -rm -f hlds_run +spotless: clean + -rm -r $(OBJDIR) + diff --git a/dedicated/NetGame.ico b/dedicated/NetGame.ico new file mode 100644 index 0000000000000000000000000000000000000000..db6831e6afe3670fc013671f4723d28232ad3a5e GIT binary patch literal 1078 zcmc&yyKciU3}n*IMZ8Iyry_e6dFwBAvPTOUB9DfKh=1eH>0hLGlx?6uh5{YRM0|+H zlSNVFAV+E2lTf~nBJZ%LQ;p9Dk+&C-Gxl1n53GZ{LW_*RK9>>jpx&O-d`mRcB7o0Q0uLI<9UbXWpJxHMc}9wZa>~ zO`6jLGSt!Q +#include +#include +#include "conproc.h" + +static HANDLE heventDone; +static HANDLE hfileBuffer; +static HANDLE heventChildSend; +static HANDLE heventParentSend; +static HANDLE hStdout; +static HANDLE hStdin; + +/* +============== +SetConsoleCXCY + +============== +*/ +BOOL SetConsoleCXCY(HANDLE hStdout, int cx, int cy) +{ + CONSOLE_SCREEN_BUFFER_INFO info; + COORD coordMax; + + coordMax = GetLargestConsoleWindowSize(hStdout); + + if (cy > coordMax.Y) + cy = coordMax.Y; + + if (cx > coordMax.X) + cx = coordMax.X; + + if (!GetConsoleScreenBufferInfo(hStdout, &info)) + return FALSE; + +// height + info.srWindow.Left = 0; + info.srWindow.Right = info.dwSize.X - 1; + info.srWindow.Top = 0; + info.srWindow.Bottom = cy - 1; + + if (cy < info.dwSize.Y) + { + if (!SetConsoleWindowInfo(hStdout, TRUE, &info.srWindow)) + return FALSE; + + info.dwSize.Y = cy; + + if (!SetConsoleScreenBufferSize(hStdout, info.dwSize)) + return FALSE; + } + else if (cy > info.dwSize.Y) + { + info.dwSize.Y = cy; + + if (!SetConsoleScreenBufferSize(hStdout, info.dwSize)) + return FALSE; + + if (!SetConsoleWindowInfo(hStdout, TRUE, &info.srWindow)) + return FALSE; + } + + if (!GetConsoleScreenBufferInfo(hStdout, &info)) + return FALSE; + +// width + info.srWindow.Left = 0; + info.srWindow.Right = cx - 1; + info.srWindow.Top = 0; + info.srWindow.Bottom = info.dwSize.Y - 1; + + if (cx < info.dwSize.X) + { + if (!SetConsoleWindowInfo(hStdout, TRUE, &info.srWindow)) + return FALSE; + + info.dwSize.X = cx; + + if (!SetConsoleScreenBufferSize(hStdout, info.dwSize)) + return FALSE; + } + else if (cx > info.dwSize.X) + { + info.dwSize.X = cx; + + if (!SetConsoleScreenBufferSize(hStdout, info.dwSize)) + return FALSE; + + if (!SetConsoleWindowInfo(hStdout, TRUE, &info.srWindow)) + return FALSE; + } + + return TRUE; +} + +/* +============== +GetMappedBuffer + +============== +*/ +LPVOID GetMappedBuffer (HANDLE hfileBuffer) +{ + LPVOID pBuffer; + + pBuffer = MapViewOfFile (hfileBuffer, + FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, 0); + + return pBuffer; +} + +/* +============== +ReleaseMappedBuffer + +============== +*/ +void ReleaseMappedBuffer (LPVOID pBuffer) +{ + UnmapViewOfFile (pBuffer); +} + +/* +============== +GetScreenBufferLines + +============== +*/ +BOOL GetScreenBufferLines (int *piLines) +{ + CONSOLE_SCREEN_BUFFER_INFO info; + BOOL bRet; + + bRet = GetConsoleScreenBufferInfo (hStdout, &info); + + if (bRet) + *piLines = info.dwSize.Y; + + return bRet; +} + +/* +============== +SetScreenBufferLines + +============== +*/ +BOOL SetScreenBufferLines (int iLines) +{ + return SetConsoleCXCY (hStdout, 80, iLines); +} + +/* +============== +ReadText + +============== +*/ +BOOL ReadText (LPTSTR pszText, int iBeginLine, int iEndLine) +{ + COORD coord; + DWORD dwRead; + BOOL bRet; + + coord.X = 0; + coord.Y = iBeginLine; + + bRet = ReadConsoleOutputCharacter( + hStdout, + pszText, + 80 * (iEndLine - iBeginLine + 1), + coord, + &dwRead); + + // Make sure it's null terminated. + if (bRet) + pszText[dwRead] = '\0'; + + return bRet; +} + +/* +============== +CharToCode + +============== +*/ +int CharToCode (char c) +{ + char upper; + + upper = toupper(c); + + switch (c) + { + case 13: + return 28; + + default: + break; + } + + if (isalpha(c)) + return (30 + upper - 65); + + if (isdigit(c)) + return (1 + upper - 47); + + return c; +} + +/* +============== +WriteText + +============== +*/ +BOOL WriteText (LPCTSTR szText) +{ + DWORD dwWritten; + INPUT_RECORD rec; + char upper, *sz; + + sz = (LPTSTR) szText; + + while (*sz) + { + // 13 is the code for a carriage return (\n) instead of 10. + if (*sz == 10) + *sz = 13; + + upper = toupper(*sz); + + rec.EventType = KEY_EVENT; + rec.Event.KeyEvent.bKeyDown = TRUE; + rec.Event.KeyEvent.wRepeatCount = 1; + rec.Event.KeyEvent.wVirtualKeyCode = upper; + rec.Event.KeyEvent.wVirtualScanCode = CharToCode (*sz); + rec.Event.KeyEvent.uChar.AsciiChar = *sz; + rec.Event.KeyEvent.uChar.UnicodeChar = *sz; + rec.Event.KeyEvent.dwControlKeyState = isupper(*sz) ? 0x80 : 0x0; + + WriteConsoleInput( + hStdin, + &rec, + 1, + &dwWritten); + + rec.Event.KeyEvent.bKeyDown = FALSE; + + WriteConsoleInput( + hStdin, + &rec, + 1, + &dwWritten); + + sz++; + } + + return TRUE; +} + +/* +============== +RequestProc + +============== +*/ +unsigned _stdcall RequestProc (void *arg) +{ + int *pBuffer; + DWORD dwRet; + HANDLE heventWait[2]; + int iBeginLine, iEndLine; + + heventWait[0] = heventParentSend; + heventWait[1] = heventDone; + + while (1) + { + dwRet = WaitForMultipleObjects (2, heventWait, FALSE, INFINITE); + + // heventDone fired, so we're exiting. + if (dwRet == WAIT_OBJECT_0 + 1) + break; + + pBuffer = (int *) GetMappedBuffer (hfileBuffer); + + // hfileBuffer is invalid. Just leave. + if (!pBuffer) + { + Sys_Printf ("Request Proc: Invalid -HFILE handle\n"); + break; + } + + switch (pBuffer[0]) + { + case CCOM_WRITE_TEXT: + // Param1 : Text + pBuffer[0] = WriteText ((LPCTSTR) (pBuffer + 1)); + break; + + case CCOM_GET_TEXT: + // Param1 : Begin line + // Param2 : End line + iBeginLine = pBuffer[1]; + iEndLine = pBuffer[2]; + pBuffer[0] = ReadText ((LPTSTR) (pBuffer + 1), iBeginLine, + iEndLine); + break; + + case CCOM_GET_SCR_LINES: + // No params + pBuffer[0] = GetScreenBufferLines (&pBuffer[1]); + break; + + case CCOM_SET_SCR_LINES: + // Param1 : Number of lines + pBuffer[0] = SetScreenBufferLines (pBuffer[1]); + break; + } + + ReleaseMappedBuffer (pBuffer); + SetEvent (heventChildSend); + } + + _endthreadex (0); + return 0; +} + +/* +============== +DeinitConProc + +============== +*/ +void DeinitConProc (void) +{ + if ( heventDone ) + { + SetEvent ( heventDone ); + } +} + +/* +============== +InitConProc + +============== +*/ +void InitConProc ( void ) +{ + unsigned threadAddr; + HANDLE hFile = (HANDLE)0; + HANDLE heventParent = (HANDLE)0; + HANDLE heventChild = (HANDLE)0; + int WantHeight = 50; + char *p; + + // give external front ends a chance to hook into the console + if ( CheckParm ( "-HFILE", &p ) && p ) + { + hFile = (HANDLE)atoi ( p ); + } + + if ( CheckParm ( "-HPARENT", &p ) && p ) + { + heventParent = (HANDLE)atoi ( p ); + } + + if ( CheckParm ( "-HCHILD", &p ) && p ) + { + heventChild = (HANDLE)atoi ( p ); + } + + // ignore if we don't have all the events. + if ( !hFile || !heventParent || !heventChild ) + { + //Sys_Printf ("\n\nNo external front end present.\n" ); + return; + } + + Sys_Printf( "\n\nInitConProc: Setting up external control.\n" ); + + hfileBuffer = hFile; + heventParentSend = heventParent; + heventChildSend = heventChild; + + // So we'll know when to go away. + heventDone = CreateEvent (NULL, FALSE, FALSE, NULL); + if (!heventDone) + { + Sys_Printf ("InitConProc: Couldn't create heventDone\n"); + return; + } + + if (!_beginthreadex (NULL, 0, RequestProc, NULL, 0, &threadAddr)) + { + CloseHandle (heventDone); + Sys_Printf ("InitConProc: Couldn't create third party thread\n"); + return; + } + + // save off the input/output handles. + hStdout = GetStdHandle (STD_OUTPUT_HANDLE); + hStdin = GetStdHandle (STD_INPUT_HANDLE); + + if ( CheckParm( "-conheight", &p ) && p ) + { + WantHeight = atoi( p ); + } + + // Force 80 character width, at least 25 character height + SetConsoleCXCY( hStdout, 80, WantHeight ); +} diff --git a/dedicated/conproc.h b/dedicated/conproc.h new file mode 100644 index 0000000..3f05574 --- /dev/null +++ b/dedicated/conproc.h @@ -0,0 +1,23 @@ +// conproc.h -- support for external server monitoring programs +#ifndef INC_CONPROCH +#define INC_CONPROCH + +#define CCOM_WRITE_TEXT 0x2 +// Param1 : Text + +#define CCOM_GET_TEXT 0x3 +// Param1 : Begin line +// Param2 : End line + +#define CCOM_GET_SCR_LINES 0x4 +// No params + +#define CCOM_SET_SCR_LINES 0x5 +// Param1 : Number of lines + +void InitConProc ( void ); +void DeinitConProc ( void ); + +void WriteStatusText( char *psz ); + +#endif // !INC_CONPROCH \ No newline at end of file diff --git a/dedicated/dedicated.h b/dedicated/dedicated.h new file mode 100644 index 0000000..f2ee783 --- /dev/null +++ b/dedicated/dedicated.h @@ -0,0 +1,18 @@ +// dedicated.h +#ifndef INC_DEDICATEDH +#define INC_DEDICATEDH + +int Eng_Frame ( int fForce, double time ); +int Eng_Load ( const char *cmdline, struct exefuncs_s *pef, int memory, void *pmembase, const char *psz, int iSubMode ); +void Eng_Unload ( void); +void Eng_SetState ( int ); +void Eng_SetSubState ( int ); + + +char *CheckParm ( const char *psz, char **ppszValue = (char **)0 ); + + +extern int gDLLState; +extern int gDLLStateInfo; + +#endif \ No newline at end of file diff --git a/dedicated/dedicated.rc b/dedicated/dedicated.rc new file mode 100644 index 0000000..fb4196e --- /dev/null +++ b/dedicated/dedicated.rc @@ -0,0 +1,72 @@ +//Microsoft Developer Studio generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (U.S.) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) +#endif //_WIN32 + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +IDI_HALFLIFE ICON DISCARDABLE "NetGame.ico" + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE DISCARDABLE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE DISCARDABLE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE DISCARDABLE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + +#endif // English (U.S.) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/dedicated/engine.cpp b/dedicated/engine.cpp new file mode 100644 index 0000000..cb08657 --- /dev/null +++ b/dedicated/engine.cpp @@ -0,0 +1,331 @@ +#ifdef _WIN32 +#include +#else +#include +#include +#include +#endif + +#include "dedicated.h" +#include "dll_state.h" +#include "enginecallback.h" +#include "sys_ded.h" + +int iWait = 0; +int fDeferedPause = 0; + +int gDLLState; +int gDLLStateInfo; +long ghMod = 0; + +static engine_api_t nullapi; +engine_api_t engineapi = nullapi; + +typedef int (*engine_api_func)( int version, int size, struct engine_api_s *api ); + +/* +============== +Eng_LoadFunctions + +Load engine->front end interface, if possible +============== +*/ +int Eng_LoadFunctions( long hMod ) +{ + engine_api_func pfnEngineAPI; + + pfnEngineAPI = ( engine_api_func )Sys_GetProcAddress( hMod, "Sys_EngineAPI" ); + if ( !pfnEngineAPI ) + return 0; + + if ( !(*pfnEngineAPI)( ENGINE_LAUNCHER_API_VERSION, sizeof( engine_api_t ), &engineapi ) ) + return 0; + + // All is okay + return 1; +} + +/* +============== +Eng_LoadStubs + +Force NULL interface +============== +*/ +void Eng_LoadStubs( void ) +{ + // No callbacks in dedicated server since engine should always be loaded. + memset( &engineapi, 0, sizeof( engineapi ) ); + + engineapi.version = ENGINE_LAUNCHER_API_VERSION; + engineapi.rendertype = RENDERTYPE_UNDEFINED; + engineapi.size = sizeof( engine_api_t ); +} + +/* +============== +Eng_Unload + +Free engine .dll and reset interfaces +============== +*/ +void Eng_Unload(void) +{ + if ( ghMod ) + { + Sys_FreeLibrary(ghMod); + ghMod = 0; + } + + Eng_LoadStubs(); + + gDLLState = 0; + gDLLStateInfo = 0; +} + +/* +============== +Eng_KillEngine + +Load failure on engine +============== +*/ +void Eng_KillEngine( long *phMod ) +{ + Sys_FreeLibrary( ghMod ); + ghMod = *phMod = 0; + + Eng_LoadStubs(); +} + +/* +============== +Eng_Load + +Try to load the engine with specified command line, etc. etc. and the specified .dll +============== +*/ +int Eng_Load( const char *cmdline, struct exefuncs_s *pef, int memory, void *pmembase, const char *psz, int iSubMode ) +{ + char szLastDLL[ 100 ]; + long hMod = (long)NULL; + +#if defined( _DEBUG ) + char *p; + + if ( psz && !stricmp( psz, "sw.dll" ) && CheckParm( "-force", &p ) && p ) + { + psz = p; + } +#endif + + // Are we loading a different engine? + if ( psz && ghMod && !strcmp( psz, szLastDLL ) ) + { + return 1; + } + + if ( ghMod ) + { + Eng_KillEngine( &hMod ); + } + + if ( !psz ) + { + hMod = 0; + Eng_LoadStubs(); + } + else if ( !ghMod ) + { + hMod = Sys_LoadLibrary( (char *)psz ); + if ( !hMod ) + { + return 0; + } + + // Load function table from engine + if ( !Eng_LoadFunctions( hMod ) ) + { + Sys_FreeLibrary( hMod ); + Eng_LoadStubs(); + return 0; + } + + // Activate engine + Eng_SetState( DLL_ACTIVE ); + } + + Eng_SetSubState( iSubMode ); + + strcpy( szLastDLL, psz ); + + ghMod = hMod; + + if ( ghMod ) + { + static char *szEmpty = ""; + + char *p = (char *)cmdline; + if ( !p ) + { + p = szEmpty; + } + + if ( !engineapi.Game_Init( p, (unsigned char *)pmembase, memory, pef, NULL, 1) ) + { + Sys_FreeLibrary(ghMod); + ghMod = hMod = 0; + return 0; + } + + if ( engineapi.SetStartupMode ) + { + engineapi.SetStartupMode( 1 ); + } + + if ( engineapi.Host_Frame ) + { + Eng_Frame( 1, 0.05 ); + } + + if ( engineapi.SetStartupMode ) + { + engineapi.SetStartupMode( 0 ); + } + } + return 1; +} + +/* +============== +Eng_Frame + +Run a frame in the engine, if it's loaded. +============== +*/ +int Eng_Frame( int fForce, double time ) +{ + if ( ( gDLLState != DLL_ACTIVE ) && !fForce ) + return 0; + + if ( gDLLState ) + { + gDLLStateInfo = DLL_NORMAL; + + int iState = engineapi.Host_Frame ( (float)time, gDLLState, &gDLLStateInfo ); + + // Special Signal + if ( gDLLStateInfo != DLL_NORMAL ) + { + switch (gDLLStateInfo) + { + case DLL_QUIT: + Eng_Unload(); +#ifdef _WIN32 + PostQuitMessage(0); +#else + exit( 0 ); +#endif + break; + default: + break; + } + } + + // Are we in our transistion counter? + if (iWait) + { + iWait--; + + // Defer all pauses until we're ready to bring up the launcher + if (iState == DLL_PAUSED) + { + fDeferedPause = 1; + Eng_SetState(DLL_ACTIVE); + iState = DLL_ACTIVE; + } + + // Are we done waiting, if so, did someone request a pause? + if (!iWait && fDeferedPause) + { + //force a pause + iState = DLL_PAUSED; + gDLLState = DLL_ACTIVE; + fDeferedPause = 0; + } + } + + // Are we now in a transistion? + if (iState == DLL_TRANS) + { + iState = DLL_ACTIVE; + iWait = 5; // Let's wait N frames before we'll allow a pause + Eng_SetState(DLL_ACTIVE); + } + + // Has the state changed? + if (iState != gDLLState) + { + Eng_SetState(iState); + } + } + + if ( gDLLState == DLL_CLOSE ) + { + static int bQuitting = 0; + + if ( !bQuitting ) + { + bQuitting = 1; + engineapi.Cbuf_AddText( "killserver\n" ); + Eng_Frame( 1, 0.05 ); + Sys_Sleep( 100 ); + Eng_Frame( 1, 0.05 ); + Sys_Sleep( 100 ); + return gDLLState; + } + + Eng_Unload(); + +#ifdef _WIN32 + PostQuitMessage(0); +#else + exit( 0 ); +#endif + } + + return gDLLState; +} + +/* +============== +Eng_SetSubState + +============== +*/ +void Eng_SetSubState(int iSubState) +{ + if ( !engineapi.GameSetSubState ) + return; + + if ( iSubState != ENG_NORMAL ) + { + engineapi.GameSetSubState( iSubState ); + } +} + +/* +============== +Eng_SetState + +============== +*/ +void Eng_SetState(int iState) +{ + gDLLState = iState; + + if (engineapi.GameSetState) + { + engineapi.GameSetState( iState ); + } +} diff --git a/dedicated/enginecallback.h b/dedicated/enginecallback.h new file mode 100644 index 0000000..273f6a8 --- /dev/null +++ b/dedicated/enginecallback.h @@ -0,0 +1,25 @@ +// enginecallback.h +#ifndef INC_ENGINECALLBACKH +#define INC_ENGINECALLBACKH + +typedef enum +{ + // A dedicated server with no ability to start a client + ca_dedicated, + // Full screen console with no connection + ca_disconnected, + // Challenge requested, waiting for response or to resend connection request. + ca_connecting, + // valid netcon, talking to a server, waiting for server data + ca_connected, + // valid netcon, autodownloading + ca_uninitialized, + // d/l complete, ready game views should be displayed + ca_active +} cactive_t; + +#include "engine_launcher_api.h" + +extern engine_api_t engineapi; + +#endif // !INC_ENGINECALLBACKH diff --git a/dedicated/exports.h b/dedicated/exports.h new file mode 100644 index 0000000..7648c65 --- /dev/null +++ b/dedicated/exports.h @@ -0,0 +1,7 @@ +// functions exported from front end to engine +#ifndef INC_EXPORTSH +#define INC_EXPORTSH + +extern void ErrorMessage(int nLevel, const char *pszErrorMessage); + +#endif // !INC_EXPORTSH \ No newline at end of file diff --git a/dedicated/md5.cpp b/dedicated/md5.cpp new file mode 100644 index 0000000..ea5b3c6 --- /dev/null +++ b/dedicated/md5.cpp @@ -0,0 +1,317 @@ +/////////////////////////// +// md5.cpp : MD5 hashing functions +// +#include +#include +#include +#include "md5.h" + +// MD5 Hash +typedef struct +{ + unsigned int buf[ 4 ]; + unsigned int bits[ 2 ]; + unsigned char in[ 64 ]; +} MD5Context_t; + +/* The four core functions - F1 is optimized somewhat */ +/* #define F1(x, y, z) (x & y | ~x & z) */ +#define F1(x, y, z) (z ^ (x & (y ^ z))) +#define F2(x, y, z) F1(z, x, y) +#define F3(x, y, z) (x ^ y ^ z) +#define F4(x, y, z) (y ^ (x | ~z)) + +/* This is the central step in the MD5 algorithm. */ +#define MD5STEP(f, w, x, y, z, data, s) ( w += f(x, y, z) + data, w = w<>(32-s), w += x ) + +/* +================= +MD5Transform + +The core of the MD5 algorithm, this alters an existing MD5 hash to +reflect the addition of 16 longwords of new data. MD5Update blocks +the data and converts bytes into longwords for this routine. +================= +*/ +void MD5Transform( unsigned int buf[4], unsigned int const in[16] ) +{ + register unsigned int a, b, c, d; + + a = buf[0]; + b = buf[1]; + c = buf[2]; + d = buf[3]; + + MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7); + MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12); + MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17); + MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22); + MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7); + MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12); + MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17); + MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22); + MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7); + MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12); + MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17); + MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22); + MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7); + MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12); + MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17); + MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22); + + MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5); + MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9); + MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14); + MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20); + MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5); + MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9); + MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14); + MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20); + MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5); + MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9); + MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14); + MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20); + MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5); + MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9); + MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14); + MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20); + + MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4); + MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11); + MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16); + MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23); + MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4); + MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11); + MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16); + MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23); + MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4); + MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11); + MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16); + MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23); + MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4); + MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11); + MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16); + MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23); + + MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6); + MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10); + MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15); + MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21); + MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6); + MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10); + MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15); + MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21); + MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6); + MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10); + MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15); + MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21); + MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6); + MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10); + MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15); + MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21); + + buf[0] += a; + buf[1] += b; + buf[2] += c; + buf[3] += d; +} + +/* +================== +MD5Init + +Start MD5 accumulation. Set bit count to 0 and buffer to mysterious initialization constants. +================== +*/ +void MD5Init(MD5Context_t *ctx) +{ + ctx->buf[0] = 0x67452301; + ctx->buf[1] = 0xefcdab89; + ctx->buf[2] = 0x98badcfe; + ctx->buf[3] = 0x10325476; + + ctx->bits[0] = 0; + ctx->bits[1] = 0; +} + +/* +=================== +MD5Update + +Update context to reflect the concatenation of another buffer full of bytes. +=================== +*/ +void MD5Update( MD5Context_t *ctx, unsigned char const *buf, unsigned int len ) +{ + unsigned int t; + + /* Update bitcount */ + + t = ctx->bits[0]; + if ((ctx->bits[0] = t + ((unsigned int) len << 3)) < t) + ctx->bits[1]++; /* Carry from low to high */ + ctx->bits[1] += len >> 29; + + t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */ + + /* Handle any leading odd-sized chunks */ + + if (t) + { + unsigned char *p = (unsigned char *) ctx->in + t; + + t = 64 - t; + if (len < t) + { + memcpy(p, buf, len); + return; + } + memcpy(p, buf, t); + //byteReverse(ctx->in, 16); + MD5Transform(ctx->buf, (unsigned int *) ctx->in); + buf += t; + len -= t; + } + /* Process data in 64-byte chunks */ + + while (len >= 64) + { + memcpy(ctx->in, buf, 64); + //byteReverse(ctx->in, 16); + MD5Transform(ctx->buf, (unsigned int *) ctx->in); + buf += 64; + len -= 64; + } + + /* Handle any remaining bytes of data. */ + memcpy(ctx->in, buf, len); +} + +/* +=============== +MD5Final + +Final wrapup - pad to 64-byte boundary with the bit pattern +1 0* (64-bit count of bits processed, MSB-first) +=============== +*/ +void MD5Final(unsigned char digest[16], MD5Context_t *ctx) +{ + unsigned count; + unsigned char *p; + + /* Compute number of bytes mod 64 */ + count = (ctx->bits[0] >> 3) & 0x3F; + + /* Set the first char of padding to 0x80. This is safe since there is + always at least one byte free */ + p = ctx->in + count; + *p++ = 0x80; + + /* Bytes of padding needed to make 64 bytes */ + count = 64 - 1 - count; + + /* Pad out to 56 mod 64 */ + if (count < 8) + { + /* Two lots of padding: Pad the first block to 64 bytes */ + memset(p, 0, count); + //byteReverse(ctx->in, 16); + MD5Transform(ctx->buf, (unsigned int *) ctx->in); + + /* Now fill the next block with 56 bytes */ + memset(ctx->in, 0, 56); + } + else + { + /* Pad block to 56 bytes */ + memset(p, 0, count - 8); + } + //byteReverse(ctx->in, 14); + + /* Append length in bits and transform */ + ((unsigned int *) ctx->in)[14] = ctx->bits[0]; + ((unsigned int *) ctx->in)[15] = ctx->bits[1]; + + MD5Transform(ctx->buf, (unsigned int *) ctx->in); + //byteReverse((unsigned char *) ctx->buf, 4); + memcpy(digest, ctx->buf, 16); + memset(ctx, 0, sizeof(ctx)); /* In case it's sensitive */ +} + +/* +=================== +MD5_Hash_File + + ================== +*/ +int MD5_Hash_File(unsigned char digest[16], char *pszFileName ) +{ + FILE *fp; + unsigned char chunk[1024]; + int bytesread; + MD5Context_t ctx; + int size; + + memset( &ctx, 0, sizeof(MD5Context_t) ); + + MD5Init( &ctx ); + + fp = fopen( pszFileName, "rb" ); + if ( !fp ) + return 0; + + fseek ( fp, 0, SEEK_END ); + size = ftell ( fp ); + fseek ( fp, 0, SEEK_SET ); + + if ( size <= 0 ) + { + fclose ( fp ); + return 0; + } + + // Now read in 1K chunks + while ( size > 0 ) + { + if ( size > 1024 ) + { + bytesread = fread(chunk, 1, 1024, fp); + } + else + { + bytesread = fread(chunk, 1, size, fp); + } + + // If any data was received, CRC it. + if ( bytesread > 0 ) + { + size -= bytesread; + MD5Update(&ctx, chunk, bytesread); + } + + // We we are end of file, break loop and return + if ( feof( fp ) ) + { + break; + } + + // If there was a disk error, indicate failure. + if ( ferror(fp) ) + { + fclose(fp); + return 0; + } + } + + if ( fp ) + { + fclose(fp); + } + + MD5Final( digest, &ctx ); + + return 1; +} + + diff --git a/dedicated/md5.h b/dedicated/md5.h new file mode 100644 index 0000000..fcfdd70 --- /dev/null +++ b/dedicated/md5.h @@ -0,0 +1,7 @@ +#if !defined( MD5H ) +#define MD5H +#pragma once + +int MD5_Hash_File(unsigned char digest[16], char *pszFileName ); + +#endif \ No newline at end of file diff --git a/dedicated/resource.h b/dedicated/resource.h new file mode 100644 index 0000000..34a4394 --- /dev/null +++ b/dedicated/resource.h @@ -0,0 +1,18 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Developer Studio generated include file. +// Used by Dedicated.rc +// +#define IDI_HALFLIFE 101 +#define IDD_CDKEY 102 +#define IDC_KEY 1000 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 104 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1001 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/dedicated/sys_ded.cpp b/dedicated/sys_ded.cpp new file mode 100644 index 0000000..899316b --- /dev/null +++ b/dedicated/sys_ded.cpp @@ -0,0 +1,1051 @@ +#ifdef _WIN32 +#include +#else +#include +#include +#include +#include +#include +#include +#include +#endif + +#include +#include + +#include "sys_ded.h" +#include "conproc.h" +#include "dedicated.h" +#include "exefuncs.h" +#include "crc.h" + +#include "dll_state.h" +#include "enginecallback.h" +#include "md5.h" +#if defined( _WIN32 ) +#include "../utils/procinfo/procinfo.h" +#endif + +#ifdef _WIN32 +static const char *g_pszengine = "sw.dll"; +#else +static const char *g_pszengine = "engine_i386.so"; +static char g_szEXEName[ 256 ]; +#endif + +#define MINIMUM_WIN_MEMORY 0x0c00000 +#define MAXIMUM_WIN_MEMORY 0x2000000 // max 32 mb +#define FIFTEEN_MEGS ( 15 * 1024 * 1024 ) + +#ifdef _WIN32 +static HANDLE hinput; +static HANDLE houtput; +#endif + +// System Memory & Size +static unsigned char *gpMemBase = NULL; +static int giMemSize = 0x1800000; // 24 Mb Linux heapsize + +exefuncs_t ef; + +static char console_text[256]; +static int console_textlen; + +static long hDLLThirdParty = 0L; + +char *gpszCmdLine = NULL; + +void Sys_Sleep( int msec ) +{ +#ifdef _WIN32 + Sleep( msec ); +#else + usleep(msec * 1000); +#endif +} + +void *Sys_GetProcAddress( long library, const char *name ) +{ +#ifdef _WIN32 + return ( void * )GetProcAddress( (HMODULE)library, name ); +#else // LINUX + return dlsym( (void *)library, name ); +#endif +} + +long Sys_LoadLibrary( char *lib ) +{ + void *hDll = NULL; + +#ifdef _WIN32 + hDll = ::LoadLibrary( lib ); +#else + char cwd[1024]; + char absolute_lib[1024]; + + if (!getcwd(cwd, sizeof(cwd))) + Sys_ErrorMessage(1, "Sys_LoadLibrary: Couldn't determine current directory."); + + if (cwd[strlen(cwd)-1] == '/') + cwd[strlen(cwd)-1] = 0; + + sprintf(absolute_lib, "%s/%s", cwd, lib); + + hDll = dlopen( absolute_lib, RTLD_NOW ); + if ( !hDll ) + { + Sys_ErrorMessage( 1, dlerror() ); + } +#endif + return (long)hDll; +} + +void Sys_FreeLibrary( long library ) +{ + if ( !library ) + return; + +#ifdef _WIN32 + ::FreeLibrary( (HMODULE)library ); +#else + dlclose( (void *)library ); +#endif +} + +int Sys_GetExecutableName( char *out ) +{ +#ifdef _WIN32 + if ( !::GetModuleFileName( ( HINSTANCE )GetModuleHandle( NULL ), out, 256 ) ) + { + return 0; + } +#else + strcpy( out, g_szEXEName ); +#endif + return 1; +} + +/* +============== +Sys_ErrorMessage + +Engine is erroring out, display error in message box +============== +*/ +void Sys_ErrorMessage( int level, const char *msg ) +{ +#ifdef _WIN32 + MessageBox( NULL, msg, "Half-Life", MB_OK ); + PostQuitMessage(0); +#else + printf( "%s\n", msg ); + exit( -1 ); +#endif +} + +#ifdef _WIN32 +/* +============== +UpdateStatus + +Update status line at top of console if engine is running +============== +*/ +void UpdateStatus( int force ) +{ + static double tLast = 0.0; + double tCurrent; + char szPrompt[256]; + int n, spec, nMax; + char szMap[32]; + float fps; + + if ( !engineapi.Host_GetHostInfo ) + return; + + tCurrent = (float)( timeGetTime() / 1000.0f ); + + engineapi.Host_GetHostInfo( &fps, &n, &spec, &nMax, szMap ); + + if ( !force ) + { + if ( ( tCurrent - tLast ) < 0.5f ) + return; + } + + tLast = tCurrent; + + sprintf( szPrompt, "%.1f fps %2i(%2i spec)/%2i on %16s", (float)fps, n, spec, nMax, szMap); + + WriteStatusText( szPrompt ); +} +#endif + +/* +================ +Sys_ConsoleOutput + +Print text to the dedicated console +================ +*/ +void Sys_ConsoleOutput (char *string) +{ +#ifdef _WIN32 + unsigned long dummy; + char text[256]; + + if (console_textlen) + { + text[0] = '\r'; + memset(&text[1], ' ', console_textlen); + text[console_textlen+1] = '\r'; + text[console_textlen+2] = 0; + WriteFile(houtput, text, console_textlen+2, &dummy, NULL); + } + + WriteFile(houtput, string, strlen(string), &dummy, NULL); + + if (console_textlen) + { + WriteFile(houtput, console_text, console_textlen, &dummy, NULL); + } + UpdateStatus( 1 /* force */ ); +#else + printf( string ); + fflush(stdout); +#endif +} + +/* +============== +Sys_Printf + +Engine is printing to console +============== +*/ +void Sys_Printf(char *fmt, ...) +{ + // Dump text to debugging console. + va_list argptr; + char szText[1024]; + + va_start (argptr, fmt); + vsprintf (szText, fmt, argptr); + va_end (argptr); + + // Get Current text and append it. + Sys_ConsoleOutput( szText ); +} + +/* +============== +Load3rdParty + +Load support for third party .dlls ( gamehost ) +============== +*/ +void Load3rdParty( void ) +{ + // Only do this if the server operator wants the support. + // ( In case of malicious code, too ) + if ( CheckParm( "-usegh" ) ) + { + hDLLThirdParty = Sys_LoadLibrary( "ghostinj.dll" ); + } +} + +/* +============ +StripExtension + +Strips the extension off a filename. Works backward to insure stripping +of extensions only, and not parts of the path that might contain a +period (i.e. './hlds_run'). +============ +*/ +void StripExtension (char *in, char *out) +{ + char * in_current = in + strlen(in); + char * out_current = out + strlen(in); + int found_extension = 0; + + while (in_current >= in) { + if ((found_extension == 0) && (*in_current == '.')) { + *out_current = 0; + found_extension = 1; + } + else { + if ((*in_current == '/') || (*in_current == '\\')) + found_extension = 1; + + *out_current = *in_current; + } + + in_current--; + out_current--; + } +} + +/* +============== +CheckExeChecksum + +Simple self-crc check +============== +*/ +int CheckExeChecksum( void ) +{ + unsigned char g_MD5[16]; + char szFileName[ 256 ]; + unsigned int newdat = 0; + unsigned int olddat; + char datfile[ 256 ]; + + // Get our filename + if ( !Sys_GetExecutableName( szFileName ) ) + { + return 0; + } + + // compute raw 16 byte hash value + if ( !MD5_Hash_File( g_MD5, szFileName ) ) + { + return 0; + } + + StripExtension( szFileName, datfile ); + + strcat( datfile, ".dat" ); + + // Check .dat file ( or write a new one if running with -newdat ) + FILE *fp = fopen( datfile, "rb" ); + if ( !fp || CheckParm( "-newdat" ) ) // No existing file, or we are asked to create a new one + { + if ( fp ) + { + fclose( fp ); + } + + newdat = *(unsigned int *)&g_MD5[0]; + fp = fopen ( datfile, "wb" ); + if ( fp ) + { + fwrite( &newdat, sizeof( unsigned int ), 1, fp ); + fclose( fp ); + } + } + else + { + int bOk = 0; + + if ( fread( &newdat, sizeof( unsigned int ), 1, fp ) == 1 ) + bOk = 1; + + fclose( fp ); + + if ( bOk ) + { + olddat = *(unsigned int *)&g_MD5[0]; + if ( olddat != newdat ) + { + const char *pmsg = "Your Half-Life executable appears to have been modified. Please check your system for viruses and then re-install Half-Life."; + +#ifdef _WIN32 + MessageBox( NULL, pmsg, "Half-Life Dedicated Server", MB_OK ); +#else + printf( "%s\n", pmsg ); +#endif + return 0; + } + } + } + + return 1; +} + +/* +============== +EF_VID_ForceUnlockedAndReturnState + +Dummy funcion called by engine +============== +*/ +int EF_VID_ForceUnlockedAndReturnState(void) +{ + return 0; +} + +/* +============== +EF_VID_ForceLockState + +Dummy funcion called by engine +============== +*/ +void EF_VID_ForceLockState(int) +{ +} + +/* +============== +CheckParm + +Search for psz in command line to .exe, if **ppszValue is set, then the pointer is + directed at the NEXT argument in the command line +============== +*/ +char *CheckParm(const char *psz, char **ppszValue) +{ + int i; + static char sz[128]; + char *pret; + + if (!gpszCmdLine) + return NULL; + + pret = strstr( gpszCmdLine, psz ); + + // should we return a pointer to the value? + if (pret && ppszValue) + { + char *p1 = pret; + *ppszValue = NULL; + + while ( *p1 && (*p1 != 32)) + p1++; + + if (p1 != 0) + { + char *p2 = ++p1; + + for ( i = 0; i < 128; i++ ) + { + if ( !*p2 || (*p2 == 32)) + break; + sz[i] = *p2++; + } + + sz[i] = 0; + *ppszValue = &sz[0]; + } + } + + return pret; +} + +/* +============== +InitInstance + +============== +*/ +int InitInstance( void ) +{ + Load3rdParty(); + +#if !defined( _DEBUG ) + if ( !CheckExeChecksum() ) + return 0; +#endif + + Eng_SetState( DLL_INACTIVE ); + + memset( &ef, 0, sizeof( ef ) ); + + // Function pointers used by dedicated server + ef.Sys_Printf = Sys_Printf; + ef.ErrorMessage = Sys_ErrorMessage; + + ef.VID_ForceLockState = EF_VID_ForceLockState; + ef.VID_ForceUnlockedAndReturnState = EF_VID_ForceUnlockedAndReturnState; + +#ifdef _WIN32 + // Data + ef.fMMX = PROC_IsMMX(); + ef.iCPUMhz = PROC_GetSpeed(); // in MHz +#endif + + return 1; +} + +/* +================ +Sys_ConsoleInput + +================ +*/ +#ifdef _WIN32 +char *Sys_ConsoleInput (void) +{ + INPUT_RECORD recs[1024]; + unsigned long dummy; + int ch; + unsigned long numread, numevents; + + while ( 1 ) + { + if (!GetNumberOfConsoleInputEvents (hinput, &numevents)) + { + exit( -1 ); + } + + if (numevents <= 0) + break; + + if ( !ReadConsoleInput(hinput, recs, 1, &numread) ) + { + exit( -1 ); + } + + if (numread != 1) + { + exit( -1 ); + } + + if ( recs[0].EventType == KEY_EVENT ) + { + if ( !recs[0].Event.KeyEvent.bKeyDown ) + { + ch = recs[0].Event.KeyEvent.uChar.AsciiChar; + switch (ch) + { + case '\r': + WriteFile(houtput, "\r\n", 2, &dummy, NULL); + if (console_textlen) + { + console_text[console_textlen] = 0; + console_textlen = 0; + return console_text; + } + break; + + case '\b': + if (console_textlen) + { + console_textlen--; + WriteFile(houtput, "\b \b", 3, &dummy, NULL); + } + break; + + default: + if (ch >= ' ') + { + if (console_textlen < sizeof(console_text)-2) + { + WriteFile(houtput, &ch, 1, &dummy, NULL); + console_text[console_textlen] = ch; + console_textlen++; + } + } + + break; + + } + } + } + } + + return NULL; +} +#else +char *Sys_ConsoleInput(void) +{ + char ch; + int len; + fd_set fdset; + struct timeval timeout; + char szInput[256]; + char iInput = 0; + + 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; + + while (read(0,&ch,1)) + { + if (iInput >= 255) + continue; + + if (ch == 10) + { + char *pszret = NULL; + + //Null terminate string and return if we have anything + szInput[iInput] = 0; + + if (iInput > 0) + pszret = szInput; + + iInput = 0; + return pszret; + } + + szInput[iInput++] = ch; + } + + return NULL; +} +#endif + +#ifdef _WIN32 +/* +============== +WriteStatusText + +============== +*/ +void WriteStatusText( char *szText ) +{ + char szFullLine[81]; + COORD coord; + DWORD dwWritten = 0; + WORD wAttrib[80]; + + int i; + + for ( i = 0; i < 80; i++ ) + { + wAttrib[i] = FOREGROUND_RED | FOREGROUND_INTENSITY; + } + + memset( szFullLine, 0, 81 ); + strcpy( szFullLine, szText ); + + coord.X = 0; + coord.Y = 0; + + WriteConsoleOutputAttribute( houtput, wAttrib, 80, coord, &dwWritten ); + WriteConsoleOutputCharacter( houtput, szFullLine, 80, coord, &dwWritten ); +} +#endif + +/* +============== +CreateConsoleWindow + +Create console window ( overridable? ) +============== +*/ +int CreateConsoleWindow( void ) +{ +#ifdef _WIN32 + if ( !AllocConsole () ) + { + return 0; + } + + hinput = GetStdHandle (STD_INPUT_HANDLE); + houtput = GetStdHandle (STD_OUTPUT_HANDLE); + + InitConProc(); +#endif + + return 1; +} + +/* +============== +DestroyConsoleWindow + +============== +*/ +void DestroyConsoleWindow( void ) +{ +#ifdef _WIN32 + FreeConsole (); + + // shut down QHOST hooks if necessary + DeinitConProc (); +#endif +} + +/* +============== +ProcessConsoleInput + +============== +*/ +void ProcessConsoleInput( void ) +{ + char *s; + + if ( !engineapi.Cbuf_AddText ) + return; + + do + { + s = Sys_ConsoleInput (); + if (s) + { + char szBuf[ 256 ]; + sprintf( szBuf, "%s\n", s ); + engineapi.Cbuf_AddText ( szBuf ); + } + } while (s); +} + +/* +================ +GameInit +================ +*/ +int GameInit(void) +{ + char *p; +#ifdef _WIN32 + MEMORYSTATUS Buffer; + + memset( &Buffer, 0, sizeof( Buffer ) ); + Buffer.dwLength = sizeof( MEMORYSTATUS ); + + GlobalMemoryStatus ( &Buffer ); + + // take the greater of all the available memory or half the total memory, + // but at least 10 Mb and no more than 32 Mb, unless they explicitly + // request otherwise + giMemSize = Buffer.dwTotalPhys; + + if ( giMemSize < FIFTEEN_MEGS ) + { + return 0; + } + + if ( giMemSize < (int)( Buffer.dwTotalPhys >> 1 ) ) + { + giMemSize = (int)( Buffer.dwTotalPhys >> 1 ); + } + + // At least 10 mb, even if we have to swap a lot. + if (giMemSize <= MINIMUM_WIN_MEMORY) + { + giMemSize = MINIMUM_WIN_MEMORY; + } + else if (giMemSize > MAXIMUM_WIN_MEMORY) + { + giMemSize = MAXIMUM_WIN_MEMORY; + } +#endif + + // Command line override + if ( (CheckParm ("-heapsize", &p ) ) && p ) + { + giMemSize = atoi( p ) * 1024; + } + + // Command line to force running with minimal memory. + if (CheckParm ("-minmemory", NULL)) + { + giMemSize = MINIMUM_WIN_MEMORY; + } + + // Try and allocated it +#ifdef _WIN32 + gpMemBase = (unsigned char *)::GlobalAlloc( GMEM_FIXED, giMemSize ); +#else + gpMemBase = (unsigned char *)malloc( giMemSize ); +#endif + if (!gpMemBase) + { + return 0; + } + +#ifdef _WIN32 + // Check that we are running on Win32 + OSVERSIONINFO vinfo; + vinfo.dwOSVersionInfoSize = sizeof(vinfo); + + if ( !GetVersionEx ( &vinfo ) ) + { + return 0; + } + + if ( vinfo.dwPlatformId == VER_PLATFORM_WIN32s ) + { + return 0; + } + +#endif + + if ( !Eng_Load( gpszCmdLine, &ef, giMemSize, gpMemBase, g_pszengine, DLL_NORMAL ) ) + { + return 0; + } + + Eng_SetState( DLL_ACTIVE ); + + return 1; +} + +/* +============== +GameShutdown + +============== +*/ +void GameShutdown( void ) +{ + Eng_Unload(); + + if ( gpMemBase ) + { +#ifdef _WIN32 + ::GlobalFree( gpMemBase ); +#else + free( gpMemBase ); +#endif + gpMemBase = NULL; + } +} + +#ifdef _WIN32 +/* +============== +WinMain + +EXE entry point +============== +*/ +int PASCAL WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdLine, int nCmdShow ) +{ + int iret = -1; + + // Store off command line for argument searching + gpszCmdLine = strdup( GetCommandLine() ); + + if ( !InitInstance() ) + { + goto cleanup; + } + + if ( !CreateConsoleWindow() ) + { + goto cleanup; + } + + if ( !GameInit() ) + { + goto cleanup; + } + + if ( engineapi.SetStartupMode ) + { + engineapi.SetStartupMode( 1 ); + } + + while ( 1 ) + { + int bDone = 0; + + static double oldtime = 0.0; + + MSG msg; + double newtime; + double dtime; + + // Try to allow other apps to get some CPU + Sys_Sleep( 1 ); + + if ( !engineapi.Sys_FloatTime ) + break; + + while ( 1 ) + { + newtime = engineapi.Sys_FloatTime(); + if ( newtime < oldtime ) + { + oldtime = newtime - 0.05; + } + + dtime = newtime - oldtime; + + if ( dtime > 0.001 ) + break; + + // Running really fast, yield some time to other apps + Sys_Sleep( 1 ); + } + + while ( ::PeekMessage( &msg, NULL, 0, 0, PM_NOREMOVE ) ) + { + if (!::GetMessage( &msg, NULL, 0, 0)) + { + bDone = 1; + break; + } + + ::TranslateMessage( &msg ); + ::DispatchMessage( &msg ); + } + + if ( bDone ) + break; + + ProcessConsoleInput(); + + if ( engineapi.Host_Frame ) + { + Eng_Frame( 0, dtime ); + } + + UpdateStatus( 0 /* don't force */ ); + + oldtime = newtime; + } + + GameShutdown(); + + DestroyConsoleWindow(); + + iret = 1; + +cleanup: + + if ( gpszCmdLine ) + { + free( gpszCmdLine ); + } + + return iret; +} + +#else + +#define MAX_LINUX_CMDLINE 512 + +static char cmdline[ MAX_LINUX_CMDLINE ]; + +void BuildCmdLine( int argc, char **argv ) +{ + int len; + int i; + + for (len = 0, i = 1; i < argc; i++) + { + len += strlen(argv[i]) + 1; + } + + if ( len > MAX_LINUX_CMDLINE ) + { + printf( "command line too long, %i max\n", MAX_LINUX_CMDLINE ); + exit(-1); + return; + } + + cmdline[0] = '\0'; + for ( i = 1; i < argc; i++ ) + { + if ( i > 1 ) + { + strcat( cmdline, " " ); + } + strcat( cmdline, argv[ i ] ); + } +} + +char *GetCommandLine( void ) +{ + return cmdline; +} + +int main(int argc, char **argv) +{ + int iret = -1; + +#ifdef _DEBUG + strcpy(g_szEXEName, "hlds_run.dbg" ); +#else + strcpy(g_szEXEName, *argv); +#endif + // Store off command line for argument searching + BuildCmdLine(argc, argv); + gpszCmdLine = strdup( GetCommandLine() ); + + if ( !InitInstance() ) + { + goto cleanup; + } + + if ( !CreateConsoleWindow() ) + { + goto cleanup; + } + + if ( !GameInit() ) + { + goto cleanup; + } + + if ( engineapi.SetStartupMode ) + { + engineapi.SetStartupMode( 1 ); + } + + while ( 1 ) + { + char *p; + static double oldtime = 0.0; + + double newtime; + double dtime; + + // Try to allow other apps to get some CPU + Sys_Sleep( 1 ); + + if ( !engineapi.Sys_FloatTime ) + break; + + while ( 1 ) + { + newtime = engineapi.Sys_FloatTime(); + if ( newtime < oldtime ) + { + oldtime = newtime - 0.05; + } + + dtime = newtime - oldtime; + + if ( dtime > 0.001 ) + break; + + // Running really fast, yield some time to other apps + Sys_Sleep( 1 ); + } + + Eng_Frame( 0, dtime ); + + p = Sys_ConsoleInput(); + if ( p ) + { + engineapi.Cbuf_AddText( p ); + engineapi.Cbuf_AddText( "\n" ); + } + + oldtime = newtime; + } + + GameShutdown(); + + DestroyConsoleWindow(); + + iret = 1; + +cleanup: + + if ( gpszCmdLine ) + { + free( gpszCmdLine ); + } + + if ( hDLLThirdParty ) + { + Sys_FreeLibrary( hDLLThirdParty ); + hDLLThirdParty = 0L; + } + + return iret; +} + +#endif diff --git a/dedicated/sys_ded.h b/dedicated/sys_ded.h new file mode 100644 index 0000000..36e9f65 --- /dev/null +++ b/dedicated/sys_ded.h @@ -0,0 +1,14 @@ +#if !defined( SYS_DEDH ) +#define SYS_DEDH +#ifdef _WIN32 +#pragma once +#endif + +long Sys_LoadLibrary( char *lib ); +void Sys_FreeLibrary( long library ); +void *Sys_GetProcAddress( long library, const char *name ); +void Sys_Sleep( int msec ); +void Sys_Printf(char *fmt, ...); +void Sys_ErrorMessage( int level, const char *msg ); + +#endif // SYS_DEDH \ No newline at end of file diff --git a/dlls/Makefile b/dlls/Makefile new file mode 100644 index 0000000..9203566 --- /dev/null +++ b/dlls/Makefile @@ -0,0 +1,137 @@ +# +# Half-Life StandardSDK 2.0 mp_i386.so Makefile for i386 Linux +# +# April 2000 by Leon Hartwig (jehannum@planethalflife.com) +# + +DLLNAME=mp + +ARCH=i386 + +#make sure this is the correct compiler for your system +CC=gcc + +DLL_SRCDIR=. +WPN_SHARED_SRCDIR=./wpn_shared +PM_SHARED_SRCDIR=../pm_shared + +DLL_OBJDIR=$(DLL_SRCDIR)/obj +WPN_SHARED_OBJDIR=$(WPN_SHARED_SRCDIR)/obj +PM_SHARED_OBJDIR=$(PM_SHARED_SRCDIR)/obj + +BASE_CFLAGS=-Dstricmp=strcasecmp -D_strnicmp=strncasecmp -Dstrnicmp=strncasecmp + +#safe optimization +CFLAGS=$(BASE_CFLAGS) -w -m486 -O1 + +#full optimization +#CFLAGS=$(BASE_CFLAGS) -w -m486 -O2 -ffast-math -funroll-loops \ + -fomit-frame-pointer -fexpensive-optimizations -malign-loops=2 \ + -malign-jumps=2 -malign-functions=2 + +#use these when debugging +#CFLAGS=$(BASE_CFLAGS) -g + +INCLUDEDIRS=-I. -I../engine -I../common -I../pm_shared + +LDFLAGS= + +SHLIBEXT=so +SHLIBCFLAGS=-fPIC +SHLIBLDFLAGS=-shared + +DO_CC=$(CC) $(CFLAGS) $(SHLIBCFLAGS) $(INCLUDEDIRS) -o $@ -c $< + +############################################################################# +# SETUP AND BUILD +# GAME +############################################################################# + +$(DLL_OBJDIR)/%.o: $(DLL_SRCDIR)/%.cpp + $(DO_CC) + +$(WPN_SHARED_OBJDIR)/%.o: $(WPN_SHARED_SRCDIR)/%.cpp + $(DO_CC) + +$(PM_SHARED_OBJDIR)/%.o: $(PM_SHARED_SRCDIR)/%.c + $(DO_CC) + +OBJ = \ + $(DLL_OBJDIR)/airtank.o \ + $(DLL_OBJDIR)/animating.o \ + $(DLL_OBJDIR)/animation.o \ + $(DLL_OBJDIR)/bmodels.o \ + $(DLL_OBJDIR)/buttons.o \ + $(DLL_OBJDIR)/cbase.o \ + $(DLL_OBJDIR)/client.o \ + $(DLL_OBJDIR)/combat.o \ + $(DLL_OBJDIR)/crossbow.o \ + $(DLL_OBJDIR)/crowbar.o \ + $(DLL_OBJDIR)/doors.o \ + $(DLL_OBJDIR)/effects.o \ + $(DLL_OBJDIR)/egon.o \ + $(DLL_OBJDIR)/explode.o \ + $(DLL_OBJDIR)/func_break.o \ + $(DLL_OBJDIR)/func_tank.o \ + $(DLL_OBJDIR)/game.o \ + $(DLL_OBJDIR)/gamerules.o \ + $(DLL_OBJDIR)/gauss.o \ + $(DLL_OBJDIR)/ggrenade.o \ + $(DLL_OBJDIR)/globals.o \ + $(DLL_OBJDIR)/h_ai.o \ + $(DLL_OBJDIR)/h_battery.o \ + $(DLL_OBJDIR)/h_cycler.o \ + $(DLL_OBJDIR)/h_export.o \ + $(DLL_OBJDIR)/handgrenade.o \ + $(DLL_OBJDIR)/healthkit.o \ + $(DLL_OBJDIR)/hornet.o \ + $(DLL_OBJDIR)/hornetgun.o \ + $(DLL_OBJDIR)/items.o \ + $(DLL_OBJDIR)/lights.o \ + $(DLL_OBJDIR)/maprules.o \ + $(DLL_OBJDIR)/mortar.o \ + $(DLL_OBJDIR)/mp5.o \ + $(DLL_OBJDIR)/mpstubb.o \ + $(DLL_OBJDIR)/multiplay_gamerules.o \ + $(DLL_OBJDIR)/pathcorner.o \ + $(DLL_OBJDIR)/plane.o \ + $(DLL_OBJDIR)/plats.o \ + $(DLL_OBJDIR)/player.o \ + $(DLL_OBJDIR)/python.o \ + $(DLL_OBJDIR)/rpg.o \ + $(DLL_OBJDIR)/satchel.o \ + $(DLL_OBJDIR)/shotgun.o \ + $(DLL_OBJDIR)/singleplay_gamerules.o \ + $(DLL_OBJDIR)/skill.o \ + $(DLL_OBJDIR)/sound.o \ + $(DLL_OBJDIR)/soundent.o \ + $(DLL_OBJDIR)/spectator.o \ + $(DLL_OBJDIR)/squeakgrenade.o \ + $(DLL_OBJDIR)/subs.o \ + $(DLL_OBJDIR)/teamplay_gamerules.o \ + $(DLL_OBJDIR)/triggers.o \ + $(DLL_OBJDIR)/tripmine.o \ + $(DLL_OBJDIR)/util.o \ + $(DLL_OBJDIR)/weapons.o \ + $(DLL_OBJDIR)/world.o \ + $(DLL_OBJDIR)/xen.o \ + $(WPN_SHARED_OBJDIR)/hl_wpn_glock.o \ + $(PM_SHARED_OBJDIR)/pm_debug.o \ + $(PM_SHARED_OBJDIR)/pm_math.o \ + $(PM_SHARED_OBJDIR)/pm_shared.o + +$(DLLNAME)_$(ARCH).$(SHLIBEXT) : neat $(OBJ) + $(CC) $(CFLAGS) $(SHLIBLDFLAGS) $(LDFLAGS) -o $@ $(OBJ) + +neat: + -mkdir $(DLL_OBJDIR) + -mkdir $(WPN_SHARED_OBJDIR) + -mkdir $(PM_SHARED_OBJDIR) +clean: + -rm -f $(OBJ) + -rm -f $(DLLNAME)_$(ARCH).$(SHLIBEXT) +spotless: clean + -rm -r $(DLL_OBJDIR) + -rm -r $(WPN_SHARED_OBJDIR) + -rm -r $(PM_SHARED_OBJDIR) + diff --git a/dlls/activity.h b/dlls/activity.h index b44de8b..cb2e7e1 100644 --- a/dlls/activity.h +++ b/dlls/activity.h @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, Valve LLC. All rights reserved. +* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. * * This product contains software technology licensed from Id * Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. diff --git a/dlls/activitymap.h b/dlls/activitymap.h index b02c666..606f6f1 100644 --- a/dlls/activitymap.h +++ b/dlls/activitymap.h @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, Valve LLC. All rights reserved. +* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. * * This product contains software technology licensed from Id * Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. diff --git a/dlls/airtank.cpp b/dlls/airtank.cpp index 5559222..0bbde7f 100644 --- a/dlls/airtank.cpp +++ b/dlls/airtank.cpp @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, Valve LLC. All rights reserved. +* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. * * This product contains software technology licensed from Id * Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. diff --git a/dlls/animating.cpp b/dlls/animating.cpp index 28adfc1..3f97a41 100644 --- a/dlls/animating.cpp +++ b/dlls/animating.cpp @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, Valve LLC. All rights reserved. +* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. * * This product contains software technology licensed from Id * Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. diff --git a/dlls/animation.cpp b/dlls/animation.cpp index 3ae95b1..91998d0 100644 --- a/dlls/animation.cpp +++ b/dlls/animation.cpp @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, Valve LLC. All rights reserved. +* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. * * This product contains software technology licensed from Id * Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. @@ -16,15 +16,19 @@ #include #include +typedef bool BOOL; + // hack into header files that we can ship typedef int qboolean; typedef unsigned char byte; #include "../utils/common/mathlib.h" #include "const.h" -#include "progs.h" #include "progdefs.h" +#include "edict.h" #include "eiface.h" +#include "studio.h" + #include "../engine/studio.h" #ifndef ACTIVITY_H diff --git a/dlls/animation.h b/dlls/animation.h index db6898a..5dc0dd5 100644 --- a/dlls/animation.h +++ b/dlls/animation.h @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, Valve LLC. All rights reserved. +* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. * * This product contains software technology licensed from Id * Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. diff --git a/dlls/basemonster.h b/dlls/basemonster.h index 24f09af..d0894e4 100644 --- a/dlls/basemonster.h +++ b/dlls/basemonster.h @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, Valve LLC. All rights reserved. +* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. * * This product contains software technology licensed from Id * Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. diff --git a/dlls/bmodels.cpp b/dlls/bmodels.cpp index f0dadac..75258f6 100644 --- a/dlls/bmodels.cpp +++ b/dlls/bmodels.cpp @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, Valve LLC. All rights reserved. +* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. * * This product contains software technology licensed from Id * Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. diff --git a/dlls/buttons.cpp b/dlls/buttons.cpp index cb8ec9b..f7ae613 100644 --- a/dlls/buttons.cpp +++ b/dlls/buttons.cpp @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, Valve LLC. All rights reserved. +* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. * * This product contains software technology licensed from Id * Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. diff --git a/dlls/cbase.cpp b/dlls/cbase.cpp index af8d01a..0da11db 100644 --- a/dlls/cbase.cpp +++ b/dlls/cbase.cpp @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, Valve LLC. All rights reserved. +* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. * * This product contains software technology licensed from Id * Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. @@ -21,6 +21,10 @@ #include "gamerules.h" #include "game.h" +extern "C" void PM_Move ( struct playermove_s *ppmove, int server ); +extern "C" void PM_Init ( struct playermove_s *ppmove ); +extern "C" char PM_FindTextureType( char *name ); + void EntvarsKeyvalue( entvars_t *pev, KeyValueData *pkvd ); extern Vector VecBModelOrigin( entvars_t* pevBModel ); @@ -54,6 +58,7 @@ static DLL_FUNCTIONS gFunctionTable = ClientCommand, //pfnClientCommand ClientUserInfoChanged, //pfnClientUserInfoChanged ServerActivate, //pfnServerActivate + ServerDeactivate, //pfnServerDeactivate PlayerPreThink, //pfnPlayerPreThink PlayerPostThink, //pfnPlayerPostThink @@ -68,6 +73,26 @@ static DLL_FUNCTIONS gFunctionTable = SpectatorConnect, //pfnSpectatorConnect Called when spectator joins server SpectatorDisconnect, //pfnSpectatorDisconnect Called when spectator leaves the server SpectatorThink, //pfnSpectatorThink Called when spectator sends a command packet (usercmd_t) + + Sys_Error, //pfnSys_Error Called when engine has encountered an error + + PM_Move, //pfnPM_Move + PM_Init, //pfnPM_Init Server version of player movement initialization + PM_FindTextureType, //pfnPM_FindTextureType + + SetupVisibility, //pfnSetupVisibility Set up PVS and PAS for networking for this client + UpdateClientData, //pfnUpdateClientData Set up data sent only to specific client + AddToFullPack, //pfnAddToFullPack + CreateBaseline, //pfnCreateBaseline Tweak entity baseline for network encoding, allows setup of player baselines, too. + RegisterEncoders, //pfnRegisterEncoders Callbacks for network encoding + GetWeaponData, //pfnGetWeaponData + CmdStart, //pfnCmdStart + CmdEnd, //pfnCmdEnd + ConnectionlessPacket, //pfnConnectionlessPacket + GetHullBounds, //pfnGetHullBounds + CreateInstancedBaselines, //pfnCreateInstancedBaselines + InconsistentFile, //pfnInconsistentFile + AllowLagCompensation, //pfnAllowLagCompensation }; static void SetObjectCollisionBox( entvars_t *pev ); @@ -75,12 +100,26 @@ static void SetObjectCollisionBox( entvars_t *pev ); int GetEntityAPI( DLL_FUNCTIONS *pFunctionTable, int interfaceVersion ) { if ( !pFunctionTable || interfaceVersion != INTERFACE_VERSION ) + { return FALSE; + } memcpy( pFunctionTable, &gFunctionTable, sizeof( DLL_FUNCTIONS ) ); return TRUE; } +int GetEntityAPI2( DLL_FUNCTIONS *pFunctionTable, int *interfaceVersion ) +{ + if ( !pFunctionTable || *interfaceVersion != INTERFACE_VERSION ) + { + // Tell engine what version we had, so it can figure out who is out of date. + *interfaceVersion = INTERFACE_VERSION; + return FALSE; + } + + memcpy( pFunctionTable, &gFunctionTable, sizeof( DLL_FUNCTIONS ) ); + return TRUE; +} int DispatchSpawn( edict_t *pent ) { diff --git a/dlls/cbase.h b/dlls/cbase.h index 5f75258..cf7976a 100644 --- a/dlls/cbase.h +++ b/dlls/cbase.h @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, Valve LLC. All rights reserved. +* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. * * This product contains software technology licensed from Id * Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. @@ -51,9 +51,14 @@ CBaseEntity // C functions for external declarations that call the appropriate C++ methods +#ifdef _WIN32 #define EXPORT _declspec( dllexport ) +#else +#define EXPORT +#endif extern "C" EXPORT int GetEntityAPI( DLL_FUNCTIONS *pFunctionTable, int interfaceVersion ); +extern "C" EXPORT int GetEntityAPI2( DLL_FUNCTIONS *pFunctionTable, int *interfaceVersion ); extern int DispatchSpawn( edict_t *pent ); extern void DispatchKeyValue( edict_t *pentKeyvalue, KeyValueData *pkvd ); @@ -287,8 +292,10 @@ public: #ifdef _DEBUG void FunctionCheck( void *pFunction, char *name ) { +#ifdef _WIN32 if (pFunction && !NAME_FOR_FUNCTION((unsigned long)(pFunction)) ) ALERT( at_error, "No EXPORT: %s:%s (%08lx)\n", STRING(pev->classname), name, (unsigned long)pFunction ); +#endif // _WIN32 } BASEPTR ThinkSet( BASEPTR func, char *name ) diff --git a/dlls/cdll_dll.h b/dlls/cdll_dll.h index 619324b..ef0e066 100644 --- a/dlls/cdll_dll.h +++ b/dlls/cdll_dll.h @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, Valve LLC. All rights reserved. +* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. * * This product contains software technology licensed from Id * Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. diff --git a/dlls/client.cpp b/dlls/client.cpp index 126b7f2..aa44e3a 100644 --- a/dlls/client.cpp +++ b/dlls/client.cpp @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, Valve LLC. All rights reserved. +* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. * * This product contains software technology licensed from Id * Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. @@ -32,6 +32,11 @@ #include "client.h" #include "soundent.h" #include "gamerules.h" +#include "customentity.h" +#include "weapons.h" +#include "weaponinfo.h" +#include "usercmd.h" +#include "netadr.h" extern DLL_GLOBAL ULONG g_ulModelIndexPlayer; extern DLL_GLOBAL BOOL g_fGameOver; @@ -42,7 +47,7 @@ extern void CopyToBodyQue(entvars_t* pev); extern int giPrecacheGrunt; extern int gmsgSayText; - +void LinkUserMessages( void ); /* * used by kill command and disconnect command * ROBIN: Moved here from player.cpp, to allow multiple player models @@ -184,7 +189,10 @@ void ClientPutInServer( edict_t *pEntity ) pPlayer->SetCustomDecalFrames(-1); // Assume none; // Allocate a CBasePlayer for pev, and call spawn - pPlayer->Spawn() ; + pPlayer->Spawn(); + + // Reset interpolation during first frame + pPlayer->pev->effects |= EF_NOINTERP; } //// HOST_SAY @@ -287,7 +295,7 @@ void Host_Say( edict_t *pEntity, int teamonly ) continue; MESSAGE_BEGIN( MSG_ONE, gmsgSayText, NULL, client->pev ); - WRITE_BYTE( ENTINDEX(client->edict()) ); + WRITE_BYTE( ENTINDEX(pEntity) ); WRITE_STRING( text ); MESSAGE_END(); @@ -412,12 +420,31 @@ void ClientUserInfoChanged( edict_t *pEntity, char *infobuffer ) g_pGameRules->ClientUserInfoChanged( GetClassPtr((CBasePlayer *)&pEntity->v), infobuffer ); } +static int g_serveractive = 0; + +void ServerDeactivate( void ) +{ + // It's possible that the engine will call this function more times than is necessary + // Therefore, only run it one time for each call to ServerActivate + if ( g_serveractive != 1 ) + { + return; + } + + g_serveractive = 0; + + // Peform any shutdown operations here... + // +} void ServerActivate( edict_t *pEdictList, int edictCount, int clientMax ) { int i; CBaseEntity *pClass; + // Every call to ServerActivate should be matched by a call to ServerDeactivate + g_serveractive = 1; + // Clients have not been initialized yet for ( i = 0; i < edictCount; i++ ) { @@ -439,6 +466,9 @@ void ServerActivate( edict_t *pEdictList, int edictCount, int clientMax ) ALERT( at_console, "Can't instance %s\n", STRING(pEdictList[i].v.classname) ); } } + + // Link user messages here to make sure first client can get them... + LinkUserMessages(); } @@ -638,6 +668,18 @@ const char *GetGameDescription() return "Half-Life"; } +/* +================ +Sys_Error + +Engine is going to shut down, allows setting a breakpoint in game .dll to catch that occasion +================ +*/ +void Sys_Error( const char *error_string ) +{ + // Default case, do nothing. MOD AUTHORS: Add code ( e.g., _asm { int 3 }; here to cause a breakpoint for debugging your game .dlls +} + /* ================ PlayerCustomization @@ -727,3 +769,829 @@ void SpectatorThink( edict_t *pEntity ) if (pPlayer) pPlayer->SpectatorThink( ); } + + +//////////////////////////////////////////////////////// +// PAS and PVS routines for client messaging +// + +/* +================ +SetupVisibility + +A client can have a separate "view entity" indicating that his/her view should depend on the origin of that +view entity. If that's the case, then pViewEntity will be non-NULL and will be used. Otherwise, the current +entity's origin is used. Either is offset by the view_ofs to get the eye position. + +From the eye position, we set up the PAS and PVS to use for filtering network messages to the client. At this point, we could + override the actual PAS or PVS values, or use a different origin. + +NOTE: Do not cache the values of pas and pvs, as they depend on reusable memory in the engine, they are only good for this one frame +================ +*/ +void SetupVisibility( edict_t *pViewEntity, edict_t *pClient, unsigned char **pvs, unsigned char **pas ) +{ + Vector org; + edict_t *pView = pClient; + + // Find the client's PVS + if ( pViewEntity ) + { + pView = pViewEntity; + } + + org = pView->v.origin + pView->v.view_ofs; + if ( pView->v.flags & FL_DUCKING ) + { + org = org + ( VEC_HULL_MIN - VEC_DUCK_HULL_MIN ); + } + + *pvs = ENGINE_SET_PVS ( (float *)&org ); + *pas = ENGINE_SET_PAS ( (float *)&org ); +} + +#include "entity_state.h" + +/* +AddToFullPack + +Return 1 if the entity state has been filled in for the ent and the entity will be propagated to the client, 0 otherwise + +state is the server maintained copy of the state info that is transmitted to the client +a MOD could alter values copied into state to send the "host" a different look for a particular entity update, etc. +e and ent are the entity that is being added to the update, if 1 is returned +host is the player's edict of the player whom we are sending the update to +player is 1 if the ent/e is a player and 0 otherwise +pSet is either the PAS or PVS that we previous set up. We can use it to ask the engine to filter the entity against the PAS or PVS. +we could also use the pas/ pvs that we set in SetupVisibility, if we wanted to. Caching the value is valid in that case, but still only for the current frame +*/ +int AddToFullPack( struct entity_state_s *state, int e, edict_t *ent, edict_t *host, int hostflags, int player, unsigned char *pSet ) +{ + int i; + + // don't send if flagged for NODRAW and it's not the host getting the message + if ( ( ent->v.effects == EF_NODRAW ) && + ( ent != host ) ) + return 0; + + // Ignore ents without valid / visible models + if ( !ent->v.modelindex || !STRING( ent->v.model ) ) + return 0; + + // Don't send spectators to other players + if ( ( ent->v.flags & FL_SPECTATOR ) && ( ent != host ) ) + { + return 0; + } + + // Ignore if not the host and not touching a PVS/PAS leaf + // If pSet is NULL, then the test will always succeed and the entity will be added to the update + if ( ent != host ) + { + if ( !ENGINE_CHECK_VISIBILITY( (const struct edict_s *)ent, pSet ) ) + { + return 0; + } + } + + + // Don't send entity to local client if the client says it's predicting the entity itself. + if ( ent->v.flags & FL_SKIPLOCALHOST ) + { + if ( ( hostflags & 1 ) && ( ent->v.owner == host ) ) + return 0; + } + + if ( host->v.groupinfo ) + { + UTIL_SetGroupTrace( host->v.groupinfo, GROUP_OP_AND ); + + // Should always be set, of course + if ( ent->v.groupinfo ) + { + if ( g_groupop == GROUP_OP_AND ) + { + if ( !(ent->v.groupinfo & host->v.groupinfo ) ) + return 0; + } + else if ( g_groupop == GROUP_OP_NAND ) + { + if ( ent->v.groupinfo & host->v.groupinfo ) + return 0; + } + } + + UTIL_UnsetGroupTrace(); + } + + memset( state, 0, sizeof( *state ) ); + + // Assign index so we can track this entity from frame to frame and + // delta from it. + state->number = e; + state->entityType = ENTITY_NORMAL; + + // Flag custom entities. + if ( ent->v.flags & FL_CUSTOMENTITY ) + { + state->entityType = ENTITY_BEAM; + } + + // + // Copy state data + // + + // Round animtime to nearest millisecond + state->animtime = (int)(1000.0 * ent->v.animtime ) / 1000.0; + + memcpy( state->origin, ent->v.origin, 3 * sizeof( float ) ); + memcpy( state->angles, ent->v.angles, 3 * sizeof( float ) ); + memcpy( state->mins, ent->v.mins, 3 * sizeof( float ) ); + memcpy( state->maxs, ent->v.maxs, 3 * sizeof( float ) ); + + memcpy( state->startpos, ent->v.startpos, 3 * sizeof( float ) ); + memcpy( state->endpos, ent->v.endpos, 3 * sizeof( float ) ); + + state->impacttime = ent->v.impacttime; + state->starttime = ent->v.starttime; + + state->modelindex = ent->v.modelindex; + + state->frame = ent->v.frame; + + state->skin = ent->v.skin; + state->effects = ent->v.effects; + + // This non-player entity is being moved by the game .dll and not the physics simulation system + // make sure that we interpolate it's position on the client if it moves + if ( !player && + ent->v.animtime && + ent->v.velocity[ 0 ] == 0 && + ent->v.velocity[ 1 ] == 0 && + ent->v.velocity[ 2 ] == 0 ) + { + state->eflags |= EFLAG_SLERP; + } + + state->scale = ent->v.scale; + state->solid = ent->v.solid; + state->colormap = ent->v.colormap; + state->movetype = ent->v.movetype; + state->sequence = ent->v.sequence; + state->framerate = ent->v.framerate; + state->body = ent->v.body; + + for (i = 0; i < 4; i++) + { + state->controller[i] = ent->v.controller[i]; + } + + for (i = 0; i < 2; i++) + { + state->blending[i] = ent->v.blending[i]; + } + + state->rendermode = ent->v.rendermode; + state->renderamt = ent->v.renderamt; + state->renderfx = ent->v.renderfx; + state->rendercolor.r = ent->v.rendercolor[0]; + state->rendercolor.g = ent->v.rendercolor[1]; + state->rendercolor.b = ent->v.rendercolor[2]; + + state->aiment = 0; + if ( ent->v.aiment ) + { + state->aiment = ENTINDEX( ent->v.aiment ); + } + + state->owner = 0; + if ( ent->v.owner ) + { + int owner = ENTINDEX( ent->v.owner ); + + // Only care if owned by a player + if ( owner >= 1 && owner <= gpGlobals->maxClients ) + { + state->owner = owner; + } + } + + // HACK: Somewhat... + // Class is overridden for non-players to signify a breakable glass object ( sort of a class? ) + if ( !player ) + { + state->playerclass = ent->v.playerclass; + } + + // Special stuff for players only + if ( player ) + { + memcpy( state->basevelocity, ent->v.basevelocity, 3 * sizeof( float ) ); + + state->weaponmodel = MODEL_INDEX( STRING( ent->v.weaponmodel ) ); + state->gaitsequence = ent->v.gaitsequence; + state->spectator = ent->v.flags & FL_SPECTATOR; + state->friction = ent->v.friction; + + state->gravity = ent->v.gravity; +// state->team = ent->v.team; +// state->playerclass = ent->v.playerclass; + state->usehull = ( ent->v.flags & FL_DUCKING ) ? 1 : 0; + state->health = ent->v.health; + } + + return 1; +} + +// defaults for clientinfo messages +#define DEFAULT_VIEWHEIGHT 28 + +/* +=================== +CreateBaseline + +Creates baselines used for network encoding, especially for player data since players are not spawned until connect time. +=================== +*/ +void CreateBaseline( int player, int eindex, struct entity_state_s *baseline, struct edict_s *entity, int playermodelindex, vec3_t player_mins, vec3_t player_maxs ) +{ + baseline->origin = entity->v.origin; + baseline->angles = entity->v.angles; + baseline->frame = entity->v.frame; + baseline->skin = (short)entity->v.skin; + + // render information + baseline->rendermode = (byte)entity->v.rendermode; + baseline->renderamt = (byte)entity->v.renderamt; + baseline->rendercolor.r = (byte)entity->v.rendercolor[0]; + baseline->rendercolor.g = (byte)entity->v.rendercolor[1]; + baseline->rendercolor.b = (byte)entity->v.rendercolor[2]; + baseline->renderfx = (byte)entity->v.renderfx; + + if ( player ) + { + baseline->mins = player_mins; + baseline->maxs = player_maxs; + + baseline->colormap = eindex; + baseline->modelindex = playermodelindex; + baseline->friction = 1.0; + baseline->movetype = MOVETYPE_WALK; + + baseline->scale = entity->v.scale; + baseline->solid = SOLID_SLIDEBOX; + baseline->framerate = 1.0; + baseline->gravity = 1.0; + + } + else + { + baseline->mins = entity->v.mins; + baseline->maxs = entity->v.maxs; + + baseline->colormap = 0; + baseline->modelindex = entity->v.modelindex;//SV_ModelIndex(pr_strings + entity->v.model); + baseline->movetype = entity->v.movetype; + + baseline->scale = entity->v.scale; + baseline->solid = entity->v.solid; + baseline->framerate = entity->v.framerate; + baseline->gravity = entity->v.gravity; + } +} + +typedef struct +{ + char name[32]; + int field; +} entity_field_alias_t; + +#define FIELD_ORIGIN0 0 +#define FIELD_ORIGIN1 1 +#define FIELD_ORIGIN2 2 +#define FIELD_ANGLES0 3 +#define FIELD_ANGLES1 4 +#define FIELD_ANGLES2 5 + +static entity_field_alias_t entity_field_alias[]= +{ + { "origin[0]", 0 }, + { "origin[1]", 0 }, + { "origin[2]", 0 }, + { "angles[0]", 0 }, + { "angles[1]", 0 }, + { "angles[2]", 0 }, +}; + +void Entity_FieldInit( struct delta_s *pFields ) +{ + entity_field_alias[ FIELD_ORIGIN0 ].field = DELTA_FINDFIELD( pFields, entity_field_alias[ FIELD_ORIGIN0 ].name ); + entity_field_alias[ FIELD_ORIGIN1 ].field = DELTA_FINDFIELD( pFields, entity_field_alias[ FIELD_ORIGIN1 ].name ); + entity_field_alias[ FIELD_ORIGIN2 ].field = DELTA_FINDFIELD( pFields, entity_field_alias[ FIELD_ORIGIN2 ].name ); + entity_field_alias[ FIELD_ANGLES0 ].field = DELTA_FINDFIELD( pFields, entity_field_alias[ FIELD_ANGLES0 ].name ); + entity_field_alias[ FIELD_ANGLES1 ].field = DELTA_FINDFIELD( pFields, entity_field_alias[ FIELD_ANGLES1 ].name ); + entity_field_alias[ FIELD_ANGLES2 ].field = DELTA_FINDFIELD( pFields, entity_field_alias[ FIELD_ANGLES2 ].name ); +} + +/* +================== +Entity_Encode + +Callback for sending entity_state_t info over network. +FIXME: Move to script +================== +*/ +void Entity_Encode( struct delta_s *pFields, const unsigned char *from, const unsigned char *to ) +{ + entity_state_t *f, *t; + + int localplayer = 0; + static int initialized = 0; + + if ( !initialized ) + { + Entity_FieldInit( pFields ); + initialized = 1; + } + + f = (entity_state_t *)from; + t = (entity_state_t *)to; + + // Never send origin to local player, it's sent with more resolution in clientdata_t structure + localplayer = ( t->number - 1 ) == ENGINE_CURRENT_PLAYER(); + if ( localplayer ) + { + DELTA_UNSETBYINDEX( pFields, entity_field_alias[ FIELD_ORIGIN0 ].field ); + DELTA_UNSETBYINDEX( pFields, entity_field_alias[ FIELD_ORIGIN1 ].field ); + DELTA_UNSETBYINDEX( pFields, entity_field_alias[ FIELD_ORIGIN2 ].field ); + } + + if ( ( t->impacttime != 0 ) && ( t->starttime != 0 ) ) + { + DELTA_UNSETBYINDEX( pFields, entity_field_alias[ FIELD_ORIGIN0 ].field ); + DELTA_UNSETBYINDEX( pFields, entity_field_alias[ FIELD_ORIGIN1 ].field ); + DELTA_UNSETBYINDEX( pFields, entity_field_alias[ FIELD_ORIGIN2 ].field ); + + DELTA_UNSETBYINDEX( pFields, entity_field_alias[ FIELD_ANGLES0 ].field ); + DELTA_UNSETBYINDEX( pFields, entity_field_alias[ FIELD_ANGLES1 ].field ); + DELTA_UNSETBYINDEX( pFields, entity_field_alias[ FIELD_ANGLES2 ].field ); + } + + if ( ( t->movetype == MOVETYPE_FOLLOW ) && + ( t->aiment != 0 ) ) + { + DELTA_UNSETBYINDEX( pFields, entity_field_alias[ FIELD_ORIGIN0 ].field ); + DELTA_UNSETBYINDEX( pFields, entity_field_alias[ FIELD_ORIGIN1 ].field ); + DELTA_UNSETBYINDEX( pFields, entity_field_alias[ FIELD_ORIGIN2 ].field ); + } + else if ( t->aiment != f->aiment ) + { + DELTA_SETBYINDEX( pFields, entity_field_alias[ FIELD_ORIGIN0 ].field ); + DELTA_SETBYINDEX( pFields, entity_field_alias[ FIELD_ORIGIN1 ].field ); + DELTA_SETBYINDEX( pFields, entity_field_alias[ FIELD_ORIGIN2 ].field ); + } +} + +static entity_field_alias_t player_field_alias[]= +{ + { "origin[0]", 0 }, + { "origin[1]", 0 }, + { "origin[2]", 0 }, +}; + +void Player_FieldInit( struct delta_s *pFields ) +{ + player_field_alias[ FIELD_ORIGIN0 ].field = DELTA_FINDFIELD( pFields, player_field_alias[ FIELD_ORIGIN0 ].name ); + player_field_alias[ FIELD_ORIGIN1 ].field = DELTA_FINDFIELD( pFields, player_field_alias[ FIELD_ORIGIN1 ].name ); + player_field_alias[ FIELD_ORIGIN2 ].field = DELTA_FINDFIELD( pFields, player_field_alias[ FIELD_ORIGIN2 ].name ); +} + +/* +================== +Player_Encode + +Callback for sending entity_state_t for players info over network. +================== +*/ +void Player_Encode( struct delta_s *pFields, const unsigned char *from, const unsigned char *to ) +{ + entity_state_t *f, *t; + int localplayer = 0; + static int initialized = 0; + + if ( !initialized ) + { + Player_FieldInit( pFields ); + initialized = 1; + } + + f = (entity_state_t *)from; + t = (entity_state_t *)to; + + // Never send origin to local player, it's sent with more resolution in clientdata_t structure + localplayer = ( t->number - 1 ) == ENGINE_CURRENT_PLAYER(); + if ( localplayer ) + { + DELTA_UNSETBYINDEX( pFields, entity_field_alias[ FIELD_ORIGIN0 ].field ); + DELTA_UNSETBYINDEX( pFields, entity_field_alias[ FIELD_ORIGIN1 ].field ); + DELTA_UNSETBYINDEX( pFields, entity_field_alias[ FIELD_ORIGIN2 ].field ); + } + + if ( ( t->movetype == MOVETYPE_FOLLOW ) && + ( t->aiment != 0 ) ) + { + DELTA_UNSETBYINDEX( pFields, entity_field_alias[ FIELD_ORIGIN0 ].field ); + DELTA_UNSETBYINDEX( pFields, entity_field_alias[ FIELD_ORIGIN1 ].field ); + DELTA_UNSETBYINDEX( pFields, entity_field_alias[ FIELD_ORIGIN2 ].field ); + } + else if ( t->aiment != f->aiment ) + { + DELTA_SETBYINDEX( pFields, entity_field_alias[ FIELD_ORIGIN0 ].field ); + DELTA_SETBYINDEX( pFields, entity_field_alias[ FIELD_ORIGIN1 ].field ); + DELTA_SETBYINDEX( pFields, entity_field_alias[ FIELD_ORIGIN2 ].field ); + } +} + +#define CUSTOMFIELD_ORIGIN0 0 +#define CUSTOMFIELD_ORIGIN1 1 +#define CUSTOMFIELD_ORIGIN2 2 +#define CUSTOMFIELD_ANGLES0 3 +#define CUSTOMFIELD_ANGLES1 4 +#define CUSTOMFIELD_ANGLES2 5 +#define CUSTOMFIELD_SKIN 6 +#define CUSTOMFIELD_SEQUENCE 7 +#define CUSTOMFIELD_ANIMTIME 8 + +entity_field_alias_t custom_entity_field_alias[]= +{ + { "origin[0]", 0 }, + { "origin[1]", 0 }, + { "origin[2]", 0 }, + { "angles[0]", 0 }, + { "angles[1]", 0 }, + { "angles[2]", 0 }, + { "skin", 0 }, + { "sequence", 0 }, + { "animtime", 0 }, +}; + +void Custom_Entity_FieldInit( struct delta_s *pFields ) +{ + custom_entity_field_alias[ CUSTOMFIELD_ORIGIN0 ].field = DELTA_FINDFIELD( pFields, custom_entity_field_alias[ CUSTOMFIELD_ORIGIN0 ].name ); + custom_entity_field_alias[ CUSTOMFIELD_ORIGIN1 ].field = DELTA_FINDFIELD( pFields, custom_entity_field_alias[ CUSTOMFIELD_ORIGIN1 ].name ); + custom_entity_field_alias[ CUSTOMFIELD_ORIGIN2 ].field = DELTA_FINDFIELD( pFields, custom_entity_field_alias[ CUSTOMFIELD_ORIGIN2 ].name ); + custom_entity_field_alias[ CUSTOMFIELD_ANGLES0 ].field = DELTA_FINDFIELD( pFields, custom_entity_field_alias[ CUSTOMFIELD_ANGLES0 ].name ); + custom_entity_field_alias[ CUSTOMFIELD_ANGLES1 ].field = DELTA_FINDFIELD( pFields, custom_entity_field_alias[ CUSTOMFIELD_ANGLES1 ].name ); + custom_entity_field_alias[ CUSTOMFIELD_ANGLES2 ].field = DELTA_FINDFIELD( pFields, custom_entity_field_alias[ CUSTOMFIELD_ANGLES2 ].name ); + custom_entity_field_alias[ CUSTOMFIELD_SKIN ].field = DELTA_FINDFIELD( pFields, custom_entity_field_alias[ CUSTOMFIELD_SKIN ].name ); + custom_entity_field_alias[ CUSTOMFIELD_SEQUENCE ].field= DELTA_FINDFIELD( pFields, custom_entity_field_alias[ CUSTOMFIELD_SEQUENCE ].name ); + custom_entity_field_alias[ CUSTOMFIELD_ANIMTIME ].field= DELTA_FINDFIELD( pFields, custom_entity_field_alias[ CUSTOMFIELD_ANIMTIME ].name ); +} + +/* +================== +Custom_Encode + +Callback for sending entity_state_t info ( for custom entities ) over network. +FIXME: Move to script +================== +*/ +void Custom_Encode( struct delta_s *pFields, const unsigned char *from, const unsigned char *to ) +{ + entity_state_t *f, *t; + int beamType; + static int initialized = 0; + + if ( !initialized ) + { + Custom_Entity_FieldInit( pFields ); + initialized = 1; + } + + f = (entity_state_t *)from; + t = (entity_state_t *)to; + + beamType = t->rendermode & 0x0f; + + if ( beamType != BEAM_POINTS && beamType != BEAM_ENTPOINT ) + { + DELTA_UNSETBYINDEX( pFields, custom_entity_field_alias[ CUSTOMFIELD_ORIGIN0 ].field ); + DELTA_UNSETBYINDEX( pFields, custom_entity_field_alias[ CUSTOMFIELD_ORIGIN1 ].field ); + DELTA_UNSETBYINDEX( pFields, custom_entity_field_alias[ CUSTOMFIELD_ORIGIN2 ].field ); + } + + if ( beamType != BEAM_POINTS ) + { + DELTA_UNSETBYINDEX( pFields, custom_entity_field_alias[ CUSTOMFIELD_ANGLES0 ].field ); + DELTA_UNSETBYINDEX( pFields, custom_entity_field_alias[ CUSTOMFIELD_ANGLES1 ].field ); + DELTA_UNSETBYINDEX( pFields, custom_entity_field_alias[ CUSTOMFIELD_ANGLES2 ].field ); + } + + if ( beamType != BEAM_ENTS && beamType != BEAM_ENTPOINT ) + { + DELTA_UNSETBYINDEX( pFields, custom_entity_field_alias[ CUSTOMFIELD_SKIN ].field ); + DELTA_UNSETBYINDEX( pFields, custom_entity_field_alias[ CUSTOMFIELD_SEQUENCE ].field ); + } + + // animtime is compared by rounding first + // see if we really shouldn't actually send it + if ( (int)f->animtime == (int)t->animtime ) + { + DELTA_UNSETBYINDEX( pFields, custom_entity_field_alias[ CUSTOMFIELD_ANIMTIME ].field ); + } +} + +/* +================= +RegisterEncoders + +Allows game .dll to override network encoding of certain types of entities and tweak values, etc. +================= +*/ +void RegisterEncoders( void ) +{ + DELTA_ADDENCODER( "Entity_Encode", Entity_Encode ); + DELTA_ADDENCODER( "Custom_Encode", Custom_Encode ); + DELTA_ADDENCODER( "Player_Encode", Player_Encode ); +} + +int GetWeaponData( struct edict_s *player, struct weapon_data_s *info ) +{ +#if defined( CLIENT_WEAPONS ) + int i; + weapon_data_t *item; + entvars_t *pev = &player->v; + CBasePlayer *pl = ( CBasePlayer *) CBasePlayer::Instance( pev ); + CBasePlayerWeapon *gun; + + ItemInfo II; + + memset( info, 0, 32 * sizeof( weapon_data_t ) ); + + if ( !pl ) + return 1; + + // go through all of the weapons and make a list of the ones to pack + for ( i = 0 ; i < MAX_ITEM_TYPES ; i++ ) + { + if ( pl->m_rgpPlayerItems[ i ] ) + { + // there's a weapon here. Should I pack it? + CBasePlayerItem *pPlayerItem = pl->m_rgpPlayerItems[ i ]; + + while ( pPlayerItem ) + { + gun = (CBasePlayerWeapon *)pPlayerItem->GetWeaponPtr(); + if ( gun && gun->UseDecrement() ) + { + // Get The ID. + memset( &II, 0, sizeof( II ) ); + gun->GetItemInfo( &II ); + + if ( II.iId >= 0 && II.iId < 32 ) + { + item = &info[ II.iId ]; + + item->m_iId = II.iId; + item->m_iClip = gun->m_iClip; + + item->m_flTimeWeaponIdle = max( gun->m_flTimeWeaponIdle, -0.001 ); + item->m_flNextPrimaryAttack = max( gun->m_flNextPrimaryAttack, -0.001 ); + item->m_flNextSecondaryAttack = max( gun->m_flNextSecondaryAttack, -0.001 ); + item->m_fInReload = gun->m_fInReload; + } + } + pPlayerItem = pPlayerItem->m_pNext; + } + } + } +#else + memset( info, 0, 32 * sizeof( weapon_data_t ) ); +#endif + return 1; +} + +/* +================= +UpdateClientData + +Data sent to current client only +engine sets cd to 0 before calling. +================= +*/ +void UpdateClientData ( const struct edict_s *ent, int sendweapons, struct clientdata_s *cd ) +{ + cd->flags = ent->v.flags; + cd->health = ent->v.health; + + cd->viewmodel = MODEL_INDEX( STRING( ent->v.viewmodel ) ); + cd->waterlevel = ent->v.waterlevel; + cd->watertype = ent->v.watertype; + cd->weapons = ent->v.weapons; + + // Vectors + cd->origin = ent->v.origin; + cd->velocity = ent->v.velocity; + cd->view_ofs = ent->v.view_ofs; + cd->punchangle = ent->v.punchangle; + + cd->bInDuck = ent->v.bInDuck; + cd->flTimeStepSound = ent->v.flTimeStepSound; + cd->flDuckTime = ent->v.flDuckTime; + cd->flSwimTime = ent->v.flSwimTime; + cd->waterjumptime = ent->v.teleport_time; + + strcpy( cd->physinfo, ENGINE_GETPHYSINFO( ent ) ); + + cd->maxspeed = ent->v.maxspeed; + cd->fov = ent->v.fov; + cd->weaponanim = ent->v.weaponanim; + + cd->pushmsec = ent->v.pushmsec; + +#if defined( CLIENT_WEAPONS ) + if ( sendweapons ) + { + entvars_t *pev = (entvars_t *)&ent->v; + CBasePlayer *pl = ( CBasePlayer *) CBasePlayer::Instance( pev ); + + if ( pl ) + { + cd->m_flNextAttack = pl->m_flNextAttack; + + if ( pl->m_pActiveItem ) + { + CBasePlayerWeapon *gun; + gun = (CBasePlayerWeapon *)pl->m_pActiveItem->GetWeaponPtr(); + if ( gun && gun->UseDecrement() ) + { + ItemInfo II; + memset( &II, 0, sizeof( II ) ); + gun->GetItemInfo( &II ); + + cd->m_iId = II.iId; + } + } + } + } +#endif +} + +/* +================= +CmdStart + +We're about to run this usercmd for the specified player. We can set up groupinfo and masking here, etc. +This is the time to examine the usercmd for anything extra. This call happens even if think does not. +================= +*/ +void CmdStart( const edict_t *player, const struct usercmd_s *cmd, unsigned int random_seed ) +{ + entvars_t *pev = (entvars_t *)&player->v; + CBasePlayer *pl = ( CBasePlayer *) CBasePlayer::Instance( pev ); + + if( !pl ) + return; + + if ( pl->pev->groupinfo != 0 ) + { + UTIL_SetGroupTrace( pl->pev->groupinfo, GROUP_OP_AND ); + } + + pl->random_seed = random_seed; +} + +/* +================= +CmdEnd + +Each cmdstart is exactly matched with a cmd end, clean up any group trace flags, etc. here +================= +*/ +void CmdEnd ( const edict_t *player ) +{ + entvars_t *pev = (entvars_t *)&player->v; + CBasePlayer *pl = ( CBasePlayer *) CBasePlayer::Instance( pev ); + + if( !pl ) + return; + if ( pl->pev->groupinfo != 0 ) + { + UTIL_UnsetGroupTrace(); + } +} + +/* +================================ +ConnectionlessPacket + + Return 1 if the packet is valid. Set response_buffer_size if you want to send a response packet. Incoming, it holds the max + size of the response_buffer, so you must zero it out if you choose not to respond. +================================ +*/ +int ConnectionlessPacket( const struct netadr_s *net_from, const char *args, char *response_buffer, int *response_buffer_size ) +{ + // Parse stuff from args + int max_buffer_size = *response_buffer_size; + + // Zero it out since we aren't going to respond. + // If we wanted to response, we'd write data into response_buffer + *response_buffer_size = 0; + + // Since we don't listen for anything here, just respond that it's a bogus message + // If we didn't reject the message, we'd return 1 for success instead. + return 0; +} + +/* +================================ +GetHullBounds + + Engine calls this to enumerate player collision hulls, for prediction. Return 0 if the hullnumber doesn't exist. +================================ +*/ +int GetHullBounds( int hullnumber, float *mins, float *maxs ) +{ + int iret = 0; + + switch ( hullnumber ) + { + case 0: // Normal player + mins = VEC_HULL_MIN; + maxs = VEC_HULL_MAX; + iret = 1; + break; + case 1: // Crouched player + mins = VEC_DUCK_HULL_MIN; + maxs = VEC_DUCK_HULL_MAX; + iret = 1; + break; + case 2: // Point based hull + mins = Vector( 0, 0, 0 ); + maxs = Vector( 0, 0, 0 ); + iret = 1; + break; + } + + return iret; +} + +/* +================================ +CreateInstancedBaselines + +Create pseudo-baselines for items that aren't placed in the map at spawn time, but which are likely +to be created during play ( e.g., grenades, ammo packs, projectiles, corpses, etc. ) +================================ +*/ +void CreateInstancedBaselines ( void ) +{ + int iret = 0; + entity_state_t state; + + memset( &state, 0, sizeof( state ) ); + + // Create any additional baselines here for things like grendates, etc. + // iret = ENGINE_INSTANCE_BASELINE( pc->pev->classname, &state ); + + // Destroy objects. + //UTIL_Remove( pc ); +} + +/* +================================ +InconsistentFile + +One of the ENGINE_FORCE_UNMODIFIED files failed the consistency check for the specified player + Return 0 to allow the client to continue, 1 to force immediate disconnection ( with an optional disconnect message of up to 256 characters ) +================================ +*/ +int InconsistentFile( const edict_t *player, const char *filename, char *disconnect_message ) +{ + // Server doesn't care? + if ( CVAR_GET_FLOAT( "mp_consistency" ) != 1 ) + return 0; + + // Default behavior is to kick the player + sprintf( disconnect_message, "Server is enforcing file consistency for %s\n", filename ); + + // Kick now with specified disconnect message. + return 1; +} + +/* +================================ +AllowLagCompensation + + The game .dll should return 1 if lag compensation should be allowed ( could also just set + the sv_unlag cvar. + Most games right now should return 0, until client-side weapon prediction code is written + and tested for them ( note you can predict weapons, but not do lag compensation, too, + if you want. +================================ +*/ +int AllowLagCompensation( void ) +{ + return 0; +} + diff --git a/dlls/client.h b/dlls/client.h index c2f9d52..5c254c2 100644 --- a/dlls/client.h +++ b/dlls/client.h @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, Valve LLC. All rights reserved. +* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. * * This product contains software technology licensed from Id * Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. @@ -23,6 +23,7 @@ extern void ClientPutInServer( edict_t *pEntity ); extern void ClientCommand( edict_t *pEntity ); extern void ClientUserInfoChanged( edict_t *pEntity, char *infobuffer ); extern void ServerActivate( edict_t *pEdictList, int edictCount, int clientMax ); +extern void ServerDeactivate( void ); extern void StartFrame( void ); extern void PlayerPostThink( edict_t *pEntity ); extern void PlayerPreThink( edict_t *pEntity ); @@ -38,4 +39,27 @@ extern void SpectatorConnect ( edict_t *pEntity ); extern void SpectatorDisconnect ( edict_t *pEntity ); extern void SpectatorThink ( edict_t *pEntity ); +extern void Sys_Error( const char *error_string ); + +extern void SetupVisibility( edict_t *pViewEntity, edict_t *pClient, unsigned char **pvs, unsigned char **pas ); +extern void UpdateClientData ( const struct edict_s *ent, int sendweapons, struct clientdata_s *cd ); +extern int AddToFullPack( struct entity_state_s *state, int e, edict_t *ent, edict_t *host, int hostflags, int player, unsigned char *pSet ); +extern void CreateBaseline( int player, int eindex, struct entity_state_s *baseline, struct edict_s *entity, int playermodelindex, vec3_t player_mins, vec3_t player_maxs ); +extern void RegisterEncoders( void ); + +extern int GetWeaponData( struct edict_s *player, struct weapon_data_s *info ); + +extern void CmdStart( const edict_t *player, const struct usercmd_s *cmd, unsigned int random_seed ); +extern void CmdEnd ( const edict_t *player ); + +extern int ConnectionlessPacket( const struct netadr_s *net_from, const char *args, char *response_buffer, int *response_buffer_size ); + +extern int GetHullBounds( int hullnumber, float *mins, float *maxs ); + +extern void CreateInstancedBaselines ( void ); + +extern int InconsistentFile( const edict_t *player, const char *filename, char *disconnect_message ); + +extern int AllowLagCompensation( void ); + #endif // CLIENT_H diff --git a/dlls/combat.cpp b/dlls/combat.cpp index 98f9195..0246fa3 100644 --- a/dlls/combat.cpp +++ b/dlls/combat.cpp @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, Valve LLC. All rights reserved. +* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. * * This product contains software technology licensed from Id * Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. @@ -1420,6 +1420,7 @@ void CBaseEntity::FireBullets(ULONG cShots, Vector vecSrc, Vector vecDirShooting switch( iBulletType ) { case BULLET_PLAYER_MP5: + break; case BULLET_MONSTER_MP5: case BULLET_MONSTER_9MM: case BULLET_MONSTER_12MM: @@ -1433,20 +1434,7 @@ void CBaseEntity::FireBullets(ULONG cShots, Vector vecSrc, Vector vecDirShooting WRITE_COORD( tr.vecEndPos.y ); WRITE_COORD( tr.vecEndPos.z ); MESSAGE_END(); - break; - /* - case BULLET_12MM: - WRITE_BYTE(MSG_BROADCAST, SVC_TEMPENTITY); - WRITE_BYTE(MSG_BROADCAST, TE_RAILTRAIL); - WRITE_COORD(MSG_BROADCAST, vecSrc.x); - WRITE_COORD(MSG_BROADCAST, vecSrc.y); - WRITE_COORD(MSG_BROADCAST, vecSrc.z); - WRITE_COORD(MSG_BROADCAST, tr.vecEndPos.x); - WRITE_COORD(MSG_BROADCAST, tr.vecEndPos.y); - WRITE_COORD(MSG_BROADCAST, tr.vecEndPos.z); - break; - */ } } // do damage, paint decals @@ -1466,39 +1454,19 @@ void CBaseEntity::FireBullets(ULONG cShots, Vector vecSrc, Vector vecDirShooting default: case BULLET_PLAYER_9MM: pEntity->TraceAttack(pevAttacker, gSkillData.plrDmg9MM, vecDir, &tr, DMG_BULLET); - if ( !tracer ) - { - TEXTURETYPE_PlaySound(&tr, vecSrc, vecEnd, iBulletType); - DecalGunshot( &tr, iBulletType ); - } break; case BULLET_PLAYER_MP5: pEntity->TraceAttack(pevAttacker, gSkillData.plrDmgMP5, vecDir, &tr, DMG_BULLET); - if ( !tracer ) - { - TEXTURETYPE_PlaySound(&tr, vecSrc, vecEnd, iBulletType); - DecalGunshot( &tr, iBulletType ); - } break; case BULLET_PLAYER_BUCKSHOT: // make distance based! pEntity->TraceAttack(pevAttacker, gSkillData.plrDmgBuckshot, vecDir, &tr, DMG_BULLET); - if ( !tracer ) - { - // TEXTURETYPE_PlaySound(&tr, vecSrc, vecEnd, iBulletType); - DecalGunshot( &tr, iBulletType ); - } break; case BULLET_PLAYER_357: pEntity->TraceAttack(pevAttacker, gSkillData.plrDmg357, vecDir, &tr, DMG_BULLET); - if ( !tracer ) - { - TEXTURETYPE_PlaySound(&tr, vecSrc, vecEnd, iBulletType); - DecalGunshot( &tr, iBulletType ); - } break; case BULLET_MONSTER_9MM: diff --git a/dlls/crossbow.cpp b/dlls/crossbow.cpp index 7020a72..4eb2631 100644 --- a/dlls/crossbow.cpp +++ b/dlls/crossbow.cpp @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, Valve LLC. All rights reserved. +* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. * * This product contains software technology licensed from Id * Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. @@ -249,7 +249,7 @@ public: void SecondaryAttack( void ); int AddToPlayer( CBasePlayer *pPlayer ); BOOL Deploy( ); - void Holster( ); + void Holster( int skiplocal = 0 ); void Reload( void ); void WeaponIdle( void ); @@ -317,7 +317,7 @@ BOOL CCrossbow::Deploy( ) return DefaultDeploy( "models/v_crossbow.mdl", "models/p_crossbow.mdl", CROSSBOW_DRAW2, "bow" ); } -void CCrossbow::Holster( ) +void CCrossbow::Holster( int skiplocal /* = 0 */ ) { m_fInReload = FALSE;// cancel any reload in progress. @@ -326,7 +326,7 @@ void CCrossbow::Holster( ) SecondaryAttack( ); } - m_pPlayer->m_flNextAttack = gpGlobals->time + 0.5; + m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 0.5; if (m_iClip) SendWeaponAnim( CROSSBOW_HOLSTER1 ); else diff --git a/dlls/crowbar.cpp b/dlls/crowbar.cpp index 9c1a465..77b74c7 100644 --- a/dlls/crowbar.cpp +++ b/dlls/crowbar.cpp @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, Valve LLC. All rights reserved. +* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. * * This product contains software technology licensed from Id * Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. @@ -39,7 +39,7 @@ public: void PrimaryAttack( void ); int Swing( int fFirst ); BOOL Deploy( void ); - void Holster( void ); + void Holster( int skiplocal = 0 ); int m_iSwing; TraceResult m_trHit; }; @@ -106,9 +106,9 @@ BOOL CCrowbar::Deploy( ) return DefaultDeploy( "models/v_crowbar.mdl", "models/p_crowbar.mdl", CROWBAR_DRAW, "crowbar" ); } -void CCrowbar::Holster( ) +void CCrowbar::Holster( int skiplocal /* = 0 */ ) { - m_pPlayer->m_flNextAttack = gpGlobals->time + 0.5; + m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 0.5; SendWeaponAnim( CROWBAR_HOLSTER ); } diff --git a/dlls/decals.h b/dlls/decals.h index bfb3ed5..addf929 100644 --- a/dlls/decals.h +++ b/dlls/decals.h @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, Valve LLC. All rights reserved. +* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. * * This product contains software technology licensed from Id * Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. diff --git a/dlls/doors.cpp b/dlls/doors.cpp index 5877252..1f1471b 100644 --- a/dlls/doors.cpp +++ b/dlls/doors.cpp @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, Valve LLC. All rights reserved. +* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. * * This product contains software technology licensed from Id * Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. diff --git a/dlls/doors.h b/dlls/doors.h index a4e7b62..51fc896 100644 --- a/dlls/doors.h +++ b/dlls/doors.h @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, Valve LLC. All rights reserved. +* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. * * This product contains software technology licensed from Id * Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. diff --git a/dlls/effects.cpp b/dlls/effects.cpp index 1d3d4d2..4a5bc98 100644 --- a/dlls/effects.cpp +++ b/dlls/effects.cpp @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, Valve LLC. All rights reserved. +* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. * * This product contains software technology licensed from Id * Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. @@ -1809,7 +1809,7 @@ Vector CBlood::BloodPosition( CBaseEntity *pActivator ) void CBlood::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) { if ( pev->spawnflags & SF_BLOOD_STREAM ) - UTIL_BloodStream( BloodPosition(pActivator), Direction(), Color(), BloodAmount() ); + UTIL_BloodStream( BloodPosition(pActivator), Direction(), (Color() == BLOOD_COLOR_RED) ? 70 : Color(), BloodAmount() ); else UTIL_BloodDrips( BloodPosition(pActivator), Direction(), Color(), BloodAmount() ); diff --git a/dlls/effects.h b/dlls/effects.h index 9b5430b..e7e9fe4 100644 --- a/dlls/effects.h +++ b/dlls/effects.h @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, Valve LLC. All rights reserved. +* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. * * This product contains software technology licensed from Id * Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. diff --git a/dlls/egon.cpp b/dlls/egon.cpp index 46e3265..dc5a705 100644 --- a/dlls/egon.cpp +++ b/dlls/egon.cpp @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, Valve LLC. All rights reserved. +* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. * * This product contains software technology licensed from Id * Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. @@ -65,7 +65,7 @@ public: int AddToPlayer( CBasePlayer *pPlayer ); BOOL Deploy( void ); - void Holster( void ); + void Holster( int skiplocal = 0 ); void CreateEffect( void ); void UpdateEffect( const Vector &startPoint, const Vector &endPoint, float timeBlend ); @@ -186,9 +186,9 @@ int CEgon::AddToPlayer( CBasePlayer *pPlayer ) -void CEgon::Holster( void ) +void CEgon::Holster( int skiplocal /* = 0 */ ) { - m_pPlayer->m_flNextAttack = gpGlobals->time + 0.5; + m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 0.5; // m_flTimeWeaponIdle = gpGlobals->time + UTIL_RandomFloat ( 10, 15 ); SendWeaponAnim( EGON_HOLSTER ); diff --git a/dlls/enginecallback.h b/dlls/enginecallback.h index d8c8a6a..469995e 100644 --- a/dlls/enginecallback.h +++ b/dlls/enginecallback.h @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, Valve LLC. All rights reserved. +* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. * * This product contains software technology licensed from Id * Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. @@ -14,6 +14,10 @@ ****/ #ifndef ENGINECALLBACK_H #define ENGINECALLBACK_H +#pragma once + +#include "event_flags.h" + // Must be provided by user of this code extern enginefuncs_t g_engfuncs; @@ -120,4 +124,35 @@ inline void *GET_PRIVATE( edict_t *pent ) #define NUMBER_OF_ENTITIES (*g_engfuncs.pfnNumberOfEntities) #define IS_DEDICATED_SERVER (*g_engfuncs.pfnIsDedicatedServer) +#define CVAR_GET_POINTER (*g_engfuncs.pfnCVarGetPointer) + +#define PRECACHE_EVENT (*g_engfuncs.pfnPrecacheEvent) +#define PLAYBACK_EVENT_FULL (*g_engfuncs.pfnPlaybackEvent) + +#define ENGINE_SET_PVS (*g_engfuncs.pfnSetFatPVS) +#define ENGINE_SET_PAS (*g_engfuncs.pfnSetFatPAS) + +#define ENGINE_CHECK_VISIBILITY (*g_engfuncs.pfnCheckVisibility) + +#define DELTA_SET ( *g_engfuncs.pfnDeltaSetField ) +#define DELTA_UNSET ( *g_engfuncs.pfnDeltaUnsetField ) +#define DELTA_ADDENCODER ( *g_engfuncs.pfnDeltaAddEncoder ) +#define ENGINE_CURRENT_PLAYER ( *g_engfuncs.pfnGetCurrentPlayer ) + +#define ENGINE_CANSKIP ( *g_engfuncs.pfnCanSkipPlayer ) + +#define DELTA_FINDFIELD ( *g_engfuncs.pfnDeltaFindField ) +#define DELTA_SETBYINDEX ( *g_engfuncs.pfnDeltaSetFieldByIndex ) +#define DELTA_UNSETBYINDEX ( *g_engfuncs.pfnDeltaUnsetFieldByIndex ) + +#define ENGINE_GETPHYSINFO ( *g_engfuncs.pfnGetPhysicsInfoString ) + +#define ENGINE_SETGROUPMASK ( *g_engfuncs.pfnSetGroupMask ) + +#define ENGINE_INSTANCE_BASELINE ( *g_engfuncs.pfnCreateInstancedBaseline ) + +#define ENGINE_FORCE_UNMODIFIED ( *g_engfuncs.pfnForceUnmodified ) + +#define PLAYER_CNX_STATS ( *g_engfuncs.pfnGetPlayerStats ) + #endif //ENGINECALLBACK_H \ No newline at end of file diff --git a/dlls/explode.cpp b/dlls/explode.cpp index c6146d6..a4c6c51 100644 --- a/dlls/explode.cpp +++ b/dlls/explode.cpp @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, Valve LLC. All rights reserved. +* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. * * This product contains software technology licensed from Id * Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. diff --git a/dlls/explode.h b/dlls/explode.h index 26d08aa..22434f2 100644 --- a/dlls/explode.h +++ b/dlls/explode.h @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, Valve LLC. All rights reserved. +* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. * * This product contains software technology licensed from Id * Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. diff --git a/dlls/extdll.h b/dlls/extdll.h index dc8aeb8..f16452a 100644 --- a/dlls/extdll.h +++ b/dlls/extdll.h @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, Valve LLC. All rights reserved. +* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. * * This product contains software technology licensed from Id * Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. @@ -32,6 +32,7 @@ #pragma warning(disable : 4514) // unreferenced inline function removed #pragma warning(disable : 4100) // unreferenced formal parameter +#ifdef _WIN32 // Prevent tons of unused windows definitions #define WIN32_LEAN_AND_MEAN #define NOWINRES @@ -39,11 +40,38 @@ #define NOMCX #define NOIME #include "WINDOWS.H" - + // Misc C-runtime library headers #include "STDIO.H" #include "STDLIB.H" #include "MATH.H" + +#else +#include +#include +#include +#include +#include +#include +#include + +#define MAX_PATH PATH_MAX +#define ULONG ulong +#define FALSE 0 +#define TRUE 1 + +#ifndef max +#define max(a,b) (((a) > (b)) ? (a) : (b)) +#endif + +#ifndef min +#define min(a,b) (((a) < (b)) ? (a) : (b)) +#endif + +#define itoa(a,b,c) sprintf(b, "%d", a) + +typedef unsigned char BYTE; +#endif // Header file containing definition of globalvars_t and entvars_t typedef int func_t; // @@ -58,7 +86,8 @@ typedef float vec_t; // needed before including progdefs.h // Shared engine/DLL constants #include "const.h" -#include "progs.h" +#include "progdefs.h" +#include "edict.h" // Shared header describing protocol between engine and DLLs #include "eiface.h" diff --git a/dlls/func_break.cpp b/dlls/func_break.cpp index 6c3d0c2..60c8c9e 100644 --- a/dlls/func_break.cpp +++ b/dlls/func_break.cpp @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, Valve LLC. All rights reserved. +* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. * * This product contains software technology licensed from Id * Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. @@ -155,6 +155,12 @@ void CBreakable::Spawn( void ) m_angle = pev->angles.y; pev->angles.y = 0; + // HACK: matGlass can receive decals, we need the client to know about this + // so use class to store the material flag + if ( m_Material == matGlass ) + { + pev->playerclass = 1; + } SET_MODEL(ENT(pev), STRING(pev->model) );//set size and link into world. diff --git a/dlls/func_break.h b/dlls/func_break.h index f478036..41a31a7 100644 --- a/dlls/func_break.h +++ b/dlls/func_break.h @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, Valve LLC. All rights reserved. +* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. * * This product contains software technology licensed from Id * Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. diff --git a/dlls/func_tank.cpp b/dlls/func_tank.cpp index 543c12a..bdbb9ff 100644 --- a/dlls/func_tank.cpp +++ b/dlls/func_tank.cpp @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, Valve LLC. All rights reserved. +* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. * * This product contains software technology licensed from Id * Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. @@ -666,6 +666,9 @@ void CFuncTank::Fire( const Vector &barrelEnd, const Vector &forward, entvars_t pSprite->AnimateAndDie( 60 ); pSprite->SetTransparency( kRenderTransAdd, 255, 255, 255, 255, kRenderFxNoDissipation ); pSprite->SetScale( m_spriteScale ); + + // Hack Hack, make it stick around for at least 100 ms. + pSprite->pev->nextthink += 0.1; } SUB_UseTargets( this, USE_TOGGLE, 0 ); } diff --git a/dlls/game.cpp b/dlls/game.cpp index fdccdc9..9789b29 100644 --- a/dlls/game.cpp +++ b/dlls/game.cpp @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, Valve LLC. All rights reserved. +* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. * * This product contains software technology licensed from Id * Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. @@ -23,6 +23,10 @@ cvar_t mapcyclefile = {"mapcyclefile","mapcycle.txt"}; cvar_t servercfgfile = {"servercfgfile","server.cfg"}; cvar_t lservercfgfile = {"lservercfgfile","listenserver.cfg"}; +// multiplayer server rules +cvar_t fragsleft = {"mp_fragsleft","0", FCVAR_SERVER | FCVAR_UNLOGGED }; // Don't spam console/log files/users with this changing +cvar_t timeleft = {"mp_timeleft","0" , FCVAR_SERVER | FCVAR_UNLOGGED }; // " " + // multiplayer server rules cvar_t teamplay = {"mp_teamplay","0", FCVAR_SERVER }; cvar_t fraglimit = {"mp_fraglimit","0", FCVAR_SERVER }; @@ -31,7 +35,6 @@ cvar_t friendlyfire= {"mp_friendlyfire","0", FCVAR_SERVER }; cvar_t falldamage = {"mp_falldamage","0", FCVAR_SERVER }; cvar_t weaponstay = {"mp_weaponstay","0", FCVAR_SERVER }; cvar_t forcerespawn= {"mp_forcerespawn","1", FCVAR_SERVER }; -cvar_t footsteps = {"mp_footsteps","1", FCVAR_SERVER }; cvar_t flashlight = {"mp_flashlight","0", FCVAR_SERVER }; cvar_t aimcrosshair= {"mp_autocrosshair","1", FCVAR_SERVER }; cvar_t decalfrequency = {"decalfrequency","30", FCVAR_SERVER }; @@ -40,6 +43,10 @@ cvar_t teamoverride = {"mp_teamoverride","1" }; cvar_t defaultteam = {"mp_defaultteam","0" }; cvar_t allowmonsters={"mp_allowmonsters","0", FCVAR_SERVER }; +cvar_t *g_psv_gravity = NULL; +cvar_t *g_psv_aim = NULL; +cvar_t *g_footsteps = NULL; + //CVARS FOR SKILL LEVEL SETTINGS // Agrunt cvar_t sk_agrunt_health1 = {"sk_agrunt_health1","0"}; @@ -447,6 +454,9 @@ cvar_t sk_player_leg3 = { "sk_player_leg3","1" }; void GameDLLInit( void ) { // Register cvars here: + g_psv_gravity = CVAR_GET_POINTER( "sv_gravity" ); + g_psv_aim = CVAR_GET_POINTER( "sv_aim" ); + g_footsteps = CVAR_GET_POINTER( "mp_footsteps" ); CVAR_REGISTER (&displaysoundlist); CVAR_REGISTER (&mapcyclefile); @@ -457,11 +467,13 @@ void GameDLLInit( void ) CVAR_REGISTER (&fraglimit); CVAR_REGISTER (&timelimit); + CVAR_REGISTER (&fragsleft); + CVAR_REGISTER (&timeleft); + CVAR_REGISTER (&friendlyfire); CVAR_REGISTER (&falldamage); CVAR_REGISTER (&weaponstay); CVAR_REGISTER (&forcerespawn); - CVAR_REGISTER (&footsteps); CVAR_REGISTER (&flashlight); CVAR_REGISTER (&aimcrosshair); CVAR_REGISTER (&decalfrequency); diff --git a/dlls/game.h b/dlls/game.h index f2332bf..2e0d03a 100644 --- a/dlls/game.h +++ b/dlls/game.h @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, Valve LLC. All rights reserved. +* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. * * This product contains software technology licensed from Id * Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. @@ -31,7 +31,6 @@ extern cvar_t friendlyfir; extern cvar_t falldamage; extern cvar_t weaponstay; extern cvar_t forcerespaw; -extern cvar_t footsteps; extern cvar_t flashlight; extern cvar_t aimcrosshair; extern cvar_t decalfrequency; @@ -39,4 +38,9 @@ extern cvar_t teamlist; extern cvar_t teamoverride; extern cvar_t defaultteam; +// Engine Cvars +extern cvar_t *g_psv_gravity; +extern cvar_t *g_psv_aim; +extern cvar_t *g_footsteps; + #endif // GAME_H diff --git a/dlls/gamerules.cpp b/dlls/gamerules.cpp index 23d24dd..188cba4 100644 --- a/dlls/gamerules.cpp +++ b/dlls/gamerules.cpp @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, Valve LLC. All rights reserved. +* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. * * This product contains software technology licensed from Id * Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. @@ -76,6 +76,10 @@ edict_t *CGameRules :: GetPlayerSpawnSpot( CBasePlayer *pPlayer ) //========================================================= BOOL CGameRules::CanHavePlayerItem( CBasePlayer *pPlayer, CBasePlayerItem *pWeapon ) { + // only living players can have items + if ( pPlayer->pev->deadflag != DEAD_NO ) + return FALSE; + if ( pWeapon->pszAmmo1() ) { if ( !CanHaveAmmo( pPlayer, pWeapon->pszAmmo1(), pWeapon->iMaxAmmo1() ) ) diff --git a/dlls/gamerules.h b/dlls/gamerules.h index 081b65b..27dc43d 100644 --- a/dlls/gamerules.h +++ b/dlls/gamerules.h @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, Valve LLC. All rights reserved. +* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. * * This product contains software technology licensed from Id * Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. diff --git a/dlls/gauss.cpp b/dlls/gauss.cpp index 8734fcf..93ac25b 100644 --- a/dlls/gauss.cpp +++ b/dlls/gauss.cpp @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, Valve LLC. All rights reserved. +* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. * * This product contains software technology licensed from Id * Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. @@ -55,7 +55,7 @@ public: int AddToPlayer( CBasePlayer *pPlayer ); BOOL Deploy( void ); - void Holster( void ); + void Holster( int skiplocal = 0 ); void PrimaryAttack( void ); void SecondaryAttack( void ); @@ -77,7 +77,12 @@ public: // was this weapon just fired primary or secondary? // we need to know so we can pick the right set of effects. BOOL m_fPrimaryFire; + +private: + unsigned short m_usGaussFire; + unsigned short m_usGaussSpin; }; + LINK_ENTITY_TO_CLASS( weapon_gauss, CGauss ); @@ -131,6 +136,9 @@ void CGauss::Precache( void ) m_iGlow = PRECACHE_MODEL( "sprites/hotglow.spr" ); m_iBalls = PRECACHE_MODEL( "sprites/hotglow.spr" ); m_iBeam = PRECACHE_MODEL( "sprites/smoke.spr" ); + + m_usGaussFire = PRECACHE_EVENT( 1, "events/gauss.sc" ); + m_usGaussSpin = PRECACHE_EVENT( 1, "events/gaussspin.sc" ); } int CGauss::AddToPlayer( CBasePlayer *pPlayer ) @@ -169,9 +177,9 @@ BOOL CGauss::Deploy( ) } -void CGauss::Holster( ) +void CGauss::Holster( int skiplocal /* = 0 */ ) { - m_pPlayer->m_flNextAttack = gpGlobals->time + 0.5; + m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 0.5; // m_flTimeWeaponIdle = gpGlobals->time + RANDOM_FLOAT ( 10, 15 ); SendWeaponAnim( GAUSS_HOLSTER ); m_fInAttack = 0; @@ -192,7 +200,7 @@ void CGauss::PrimaryAttack() if (m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] < 2) { PlayEmptySound( ); - m_pPlayer->m_flNextAttack = gpGlobals->time + 0.5; + m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 0.5; return; } @@ -205,7 +213,7 @@ void CGauss::PrimaryAttack() StartFire(); m_fInAttack = 0; m_flTimeWeaponIdle = gpGlobals->time + 1.0; - m_pPlayer->m_flNextAttack = gpGlobals->time + 0.2; + m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 0.2; } void CGauss::SecondaryAttack() @@ -233,7 +241,7 @@ void CGauss::SecondaryAttack() if (m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] <= 0) { EMIT_SOUND(ENT(m_pPlayer->pev), CHAN_WEAPON, "weapons/357_cock1.wav", 0.8, ATTN_NORM); - m_pPlayer->m_flNextAttack = gpGlobals->time + 0.5; + m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 0.5; return; } @@ -249,7 +257,9 @@ void CGauss::SecondaryAttack() m_fInAttack = 1; m_flTimeWeaponIdle = gpGlobals->time + 0.5; m_flStartCharge = gpGlobals->time; - EMIT_SOUND_DYN(ENT(m_pPlayer->pev), CHAN_WEAPON, "ambience/pulsemachine.wav",1.0 , ATTN_NORM, 0, 110 ); + + PLAYBACK_EVENT_FULL( 0, m_pPlayer->edict(), m_usGaussSpin, 0.0, (float *)&g_vecZero, (float *)&g_vecZero, 0.0, 0.0, 110, 0, 0, 0 ); + m_iSoundState = SND_CHANGE_PITCH; } else if (m_fInAttack == 1) @@ -268,7 +278,7 @@ void CGauss::SecondaryAttack() StartFire(); m_fInAttack = 0; m_flTimeWeaponIdle = gpGlobals->time + 1.0; - m_pPlayer->m_flNextAttack = gpGlobals->time + 1; + m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 1; return; } @@ -302,8 +312,8 @@ void CGauss::SecondaryAttack() if (m_iSoundState == 0) ALERT( at_console, "sound state %d\n", m_iSoundState ); - EMIT_SOUND_DYN(ENT(m_pPlayer->pev), CHAN_WEAPON, "ambience/pulsemachine.wav", 1.0, ATTN_NORM, m_iSoundState, pitch); - + PLAYBACK_EVENT_FULL( 0, m_pPlayer->edict(), m_usGaussSpin, 0.0, (float *)&g_vecZero, (float *)&g_vecZero, 0.0, 0.0, pitch, 0, ( m_iSoundState == SND_CHANGE_PITCH ) ? 1 : 0, 0 ); + m_iSoundState = SND_CHANGE_PITCH; // hack for going through level transitions m_pPlayer->m_iWeaponVolume = GAUSS_PRIMARY_CHARGE_VOLUME; @@ -317,7 +327,7 @@ void CGauss::SecondaryAttack() m_fInAttack = 0; m_flTimeWeaponIdle = gpGlobals->time + 1.0; - m_pPlayer->m_flNextAttack = gpGlobals->time + 1.0; + m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 1.0; m_pPlayer->TakeDamage( VARS(eoNullEntity), VARS(eoNullEntity), 50, DMG_SHOCK ); UTIL_ScreenFade( m_pPlayer, Vector(255,128,0), 2, 0.5, 128, FFADE_IN ); @@ -356,7 +366,6 @@ void CGauss::StartFire( void ) { // fixed damage on primary attack flDamage = gSkillData.plrDmgGauss; - m_pPlayer->pev->punchangle.x = -2;// punch now, after building aim vector } if (m_fInAttack != 3) @@ -376,13 +385,9 @@ void CGauss::StartFire( void ) m_pPlayer->pev->velocity.z = flZVel; } - SendWeaponAnim( GAUSS_FIRE2 ); - // player "shoot" animation m_pPlayer->SetAnimation( PLAYER_ATTACK1 ); } - STOP_SOUND( ENT(m_pPlayer->pev), CHAN_WEAPON, "ambience/pulsemachine.wav" ); - EMIT_SOUND_DYN(ENT(m_pPlayer->pev), CHAN_WEAPON, "weapons/gauss2.wav", 0.5 + flDamage * (1.0 / 400.0), ATTN_NORM, 0, 85 + RANDOM_LONG(0,0x1f)); // time until aftershock 'static discharge' sound m_flPlayAftershock = gpGlobals->time + RANDOM_FLOAT(0.3, 0.8); @@ -413,6 +418,9 @@ void CGauss::Fire( Vector vecOrigSrc, Vector vecDir, float flDamage ) // ALERT( at_console, "%f %f\n", tr.flFraction, flMaxFrac ); + // Pass in correct values here + PLAYBACK_EVENT_FULL( FEV_RELIABLE, m_pPlayer->edict(), m_usGaussFire, 0.0, (float *)&g_vecZero, (float *)&g_vecZero, flDamage, 0.0, 0, 0, m_fPrimaryFire ? 1 : 0, 0 ); + while (flDamage > 10 && nMaxHits > 0) { nMaxHits--; @@ -432,104 +440,10 @@ void CGauss::Fire( Vector vecOrigSrc, Vector vecDir, float flDamage ) { m_pPlayer->pev->effects |= EF_MUZZLEFLASH; fFirstBeam = 0; - - Vector tmpSrc = vecSrc + gpGlobals->v_up * -8 + gpGlobals->v_right * 3; - - // don't draw beam until the damn thing looks like it's coming out of the barrel - // draw beam - MESSAGE_BEGIN( MSG_PAS, SVC_TEMPENTITY, tr.vecEndPos ); - WRITE_BYTE( TE_BEAMENTPOINT ); - WRITE_SHORT( m_pPlayer->entindex() + 0x1000 ); - WRITE_COORD( tr.vecEndPos.x); - WRITE_COORD( tr.vecEndPos.y); - WRITE_COORD( tr.vecEndPos.z); - WRITE_SHORT( m_iBeam ); - WRITE_BYTE( 0 ); // startframe - WRITE_BYTE( 0 ); // framerate - WRITE_BYTE( 1 ); // life - - if ( m_fPrimaryFire ) - { - WRITE_BYTE( 10 ); // width - } - else - { - WRITE_BYTE( 25 ); // width - } - - WRITE_BYTE( 0 ); // noise - - if ( m_fPrimaryFire ) - { - WRITE_BYTE( 255 ); // r, g, b - WRITE_BYTE( 128 ); // r, g, b - WRITE_BYTE( 0 ); // r, g, b - - WRITE_BYTE( 128 ); // brightness - } - else - { - // secondary shot is always white, and intensity based on charge - WRITE_BYTE( 255 ); // r, g, b - WRITE_BYTE( 255 ); // r, g, b - WRITE_BYTE( 255 ); // r, g, b - - WRITE_BYTE( flDamage ); // brightness - } - - WRITE_BYTE( 0 ); // speed - MESSAGE_END(); - nTotal += 26; } else { - // draw beam - MESSAGE_BEGIN( MSG_PAS, SVC_TEMPENTITY, vecSrc ); - WRITE_BYTE( TE_BEAMPOINTS); - WRITE_COORD( vecSrc.x); - WRITE_COORD( vecSrc.y); - WRITE_COORD( vecSrc.z); - WRITE_COORD( tr.vecEndPos.x); - WRITE_COORD( tr.vecEndPos.y); - WRITE_COORD( tr.vecEndPos.z); - WRITE_SHORT( m_iBeam ); - WRITE_BYTE( 0 ); // startframe - WRITE_BYTE( 0 ); // framerate - WRITE_BYTE( 1 ); // life - - if ( m_fPrimaryFire ) - { - WRITE_BYTE( 10 ); // width - } - else - { - WRITE_BYTE( 25 ); // width - } - - WRITE_BYTE( 0 ); // noise - - if ( m_fPrimaryFire ) - { - // primary shot always looks full intensity - WRITE_BYTE( 255 ); // r, g, b - WRITE_BYTE( 128 ); // r, g, b - WRITE_BYTE( 0 ); // r, g, b - - WRITE_BYTE( 128 ); // brightness - } - else - { - // secondary shot is always white, and intensity based on charge - WRITE_BYTE( 255 ); // r, g, b - WRITE_BYTE( 255 ); // r, g, b - WRITE_BYTE( 255 ); // r, g, b - - WRITE_BYTE( flDamage ); // brightness - } - - WRITE_BYTE( 0 ); // speed - MESSAGE_END(); nTotal += 26; } @@ -565,37 +479,8 @@ void CGauss::Fire( Vector vecOrigSrc, Vector vecDir, float flDamage ) // explode a bit m_pPlayer->RadiusDamage( tr.vecEndPos, pev, m_pPlayer->pev, flDamage * n, CLASS_NONE, DMG_BLAST ); - // bounce wall glow - MESSAGE_BEGIN( MSG_PAS, SVC_TEMPENTITY, tr.vecEndPos ); - WRITE_BYTE( TE_GLOWSPRITE ); - WRITE_COORD( tr.vecEndPos.x); // pos - WRITE_COORD( tr.vecEndPos.y); - WRITE_COORD( tr.vecEndPos.z); - WRITE_SHORT( m_iGlow ); // model - WRITE_BYTE( flDamage * n * 0.5 ); // life * 10 - WRITE_BYTE( 2 ); // size * 10 - WRITE_BYTE( flDamage * n ); // brightness - MESSAGE_END(); - nTotal += 13; - // balls - MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, tr.vecEndPos ); - WRITE_BYTE( TE_SPRITETRAIL );// TE_RAILTRAIL); - WRITE_COORD( tr.vecEndPos.x ); - WRITE_COORD( tr.vecEndPos.y ); - WRITE_COORD( tr.vecEndPos.z ); - WRITE_COORD( tr.vecEndPos.x + tr.vecPlaneNormal.x ); - WRITE_COORD( tr.vecEndPos.y + tr.vecPlaneNormal.y ); - WRITE_COORD( tr.vecEndPos.z + tr.vecPlaneNormal.z ); - WRITE_SHORT( m_iBalls ); // model - WRITE_BYTE( n * flDamage * 0.3 ); // count - WRITE_BYTE( 10 ); // life * 10 - WRITE_BYTE( RANDOM_LONG( 1, 2 ) ); // size * 10 - WRITE_BYTE( 10 ); // amplitude * 0.1 - WRITE_BYTE( 20 ); // speed * 100 - MESSAGE_END(); - nTotal += 21; // lose energy @@ -604,20 +489,6 @@ void CGauss::Fire( Vector vecOrigSrc, Vector vecDir, float flDamage ) } else { - // tunnel - DecalGunshot( &tr, BULLET_MONSTER_12MM ); - - // entry wall glow - MESSAGE_BEGIN( MSG_PAS, SVC_TEMPENTITY, tr.vecEndPos ); - WRITE_BYTE( TE_GLOWSPRITE ); - WRITE_COORD( tr.vecEndPos.x); // pos - WRITE_COORD( tr.vecEndPos.y); - WRITE_COORD( tr.vecEndPos.z); - WRITE_SHORT( m_iGlow ); // model - WRITE_BYTE( 60 ); // life * 10 - WRITE_BYTE( 10 ); // size * 10 - WRITE_BYTE( flDamage ); // brightness - MESSAGE_END(); nTotal += 13; // limit it to one hole punch @@ -643,62 +514,22 @@ void CGauss::Fire( Vector vecOrigSrc, Vector vecDir, float flDamage ) // ALERT( at_console, "punch %f\n", n ); - // absorption balls - MESSAGE_BEGIN( MSG_PAS, SVC_TEMPENTITY, tr.vecEndPos ); - WRITE_BYTE( TE_SPRITETRAIL );// TE_RAILTRAIL); - WRITE_COORD( tr.vecEndPos.x ); - WRITE_COORD( tr.vecEndPos.y ); - WRITE_COORD( tr.vecEndPos.z ); - WRITE_COORD( tr.vecEndPos.x - vecDir.x ); - WRITE_COORD( tr.vecEndPos.y - vecDir.y ); - WRITE_COORD( tr.vecEndPos.z - vecDir.z ); - WRITE_SHORT( m_iBalls ); // model - WRITE_BYTE( 3 ); // count - WRITE_BYTE( 10 ); // life * 10 - WRITE_BYTE( RANDOM_LONG( 1, 2 ) ); // size * 10 - WRITE_BYTE( 10 ); // amplitude * 0.1 - WRITE_BYTE( 1 ); // speed * 100 - MESSAGE_END(); - nTotal += 21; - // exit blast damage - m_pPlayer->RadiusDamage( beam_tr.vecEndPos + vecDir * 8, pev, m_pPlayer->pev, flDamage, CLASS_NONE, DMG_BLAST ); + //m_pPlayer->RadiusDamage( beam_tr.vecEndPos + vecDir * 8, pev, m_pPlayer->pev, flDamage, CLASS_NONE, DMG_BLAST ); + float damage_radius; + + if ( g_pGameRules->IsMultiplayer() ) + { + damage_radius = flDamage * 1.75; // Old code == 2.5 + } + else + { + damage_radius = flDamage * 2.5; + } + + ::RadiusDamage( beam_tr.vecEndPos + vecDir * 8, pev, m_pPlayer->pev, flDamage, damage_radius, CLASS_NONE, DMG_BLAST ); CSoundEnt::InsertSound ( bits_SOUND_COMBAT, pev->origin, NORMAL_EXPLOSION_VOLUME, 3.0 ); - DecalGunshot( &beam_tr, BULLET_MONSTER_12MM ); - nTotal += 19; - - // exit wall glow - MESSAGE_BEGIN( MSG_PAS, SVC_TEMPENTITY, beam_tr.vecEndPos ); - WRITE_BYTE( TE_GLOWSPRITE ); - WRITE_COORD( beam_tr.vecEndPos.x); // pos - WRITE_COORD( beam_tr.vecEndPos.y); - WRITE_COORD( beam_tr.vecEndPos.z); - WRITE_SHORT( m_iGlow ); // model - WRITE_BYTE( 60 ); // life * 10 - WRITE_BYTE( 10 ); // size * 10 - WRITE_BYTE( flDamage ); // brightness - MESSAGE_END(); - nTotal += 13; - - // balls - MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, beam_tr.vecEndPos ); - WRITE_BYTE( TE_SPRITETRAIL );// TE_RAILTRAIL); - WRITE_COORD( beam_tr.vecEndPos.x ); - WRITE_COORD( beam_tr.vecEndPos.y ); - WRITE_COORD( beam_tr.vecEndPos.z ); - WRITE_COORD( beam_tr.vecEndPos.x + vecDir.x ); - WRITE_COORD( beam_tr.vecEndPos.y + vecDir.y ); - WRITE_COORD( beam_tr.vecEndPos.z + vecDir.z ); - WRITE_SHORT( m_iBalls ); // model - WRITE_BYTE( flDamage * 0.3 ); // count - WRITE_BYTE( 10 ); // life * 10 - WRITE_BYTE( RANDOM_LONG( 1, 2 ) ); // size * 10 - WRITE_BYTE( 20 ); // amplitude * 0.1 - WRITE_BYTE( 40 ); // speed * 100 - MESSAGE_END(); - nTotal += 21; - vecSrc = beam_tr.vecEndPos + vecDir; } } @@ -711,40 +542,6 @@ void CGauss::Fire( Vector vecOrigSrc, Vector vecDir, float flDamage ) else { //ALERT( at_console, "blocked solid\n" ); - - if ( m_fPrimaryFire ) - { - // slug doesn't punch through ever with primary - // fire, so leave a little glowy bit and make some balls - MESSAGE_BEGIN( MSG_PAS, SVC_TEMPENTITY, tr.vecEndPos ); - WRITE_BYTE( TE_GLOWSPRITE ); - WRITE_COORD( tr.vecEndPos.x); // pos - WRITE_COORD( tr.vecEndPos.y); - WRITE_COORD( tr.vecEndPos.z); - WRITE_SHORT( m_iGlow ); // model - WRITE_BYTE( 20 ); // life * 10 - WRITE_BYTE( 3 ); // size * 10 - WRITE_BYTE( 200 ); // brightness - MESSAGE_END(); - - - MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, tr.vecEndPos ); - WRITE_BYTE( TE_SPRITETRAIL );// TE_RAILTRAIL); - WRITE_COORD( tr.vecEndPos.x ); - WRITE_COORD( tr.vecEndPos.y ); - WRITE_COORD( tr.vecEndPos.z ); - WRITE_COORD( tr.vecEndPos.x + tr.vecPlaneNormal.x ); - WRITE_COORD( tr.vecEndPos.y + tr.vecPlaneNormal.y ); - WRITE_COORD( tr.vecEndPos.z + tr.vecPlaneNormal.z ); - WRITE_SHORT( m_iBalls ); // model - WRITE_BYTE( 8 ); // count - WRITE_BYTE( 6 ); // life * 10 - WRITE_BYTE( RANDOM_LONG( 1, 2 ) ); // size * 10 - WRITE_BYTE( 10 ); // amplitude * 0.1 - WRITE_BYTE( 20 ); // speed * 100 - MESSAGE_END(); - } - flDamage = 0; } @@ -814,11 +611,6 @@ void CGauss::WeaponIdle( void ) } } - - - - - class CGaussAmmo : public CBasePlayerAmmo { void Spawn( void ) @@ -844,14 +636,4 @@ class CGaussAmmo : public CBasePlayerAmmo }; LINK_ENTITY_TO_CLASS( ammo_gaussclip, CGaussAmmo ); - - - - - - - - - - #endif \ No newline at end of file diff --git a/dlls/ggrenade.cpp b/dlls/ggrenade.cpp index c85c324..502a7dc 100644 --- a/dlls/ggrenade.cpp +++ b/dlls/ggrenade.cpp @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, Valve LLC. All rights reserved. +* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. * * This product contains software technology licensed from Id * Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. diff --git a/dlls/globals.cpp b/dlls/globals.cpp index b5c734b..b4432e9 100644 --- a/dlls/globals.cpp +++ b/dlls/globals.cpp @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, Valve LLC. All rights reserved. +* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. * * This product contains software technology licensed from Id * Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. diff --git a/dlls/h_ai.cpp b/dlls/h_ai.cpp index 80d63cf..1fb1963 100644 --- a/dlls/h_ai.cpp +++ b/dlls/h_ai.cpp @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, Valve LLC. All rights reserved. +* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. * * This product contains software technology licensed from Id * Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. diff --git a/dlls/h_battery.cpp b/dlls/h_battery.cpp index de31953..7e24e11 100644 --- a/dlls/h_battery.cpp +++ b/dlls/h_battery.cpp @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, Valve LLC. All rights reserved. +* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. * * This product contains software technology licensed from Id * Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. diff --git a/dlls/h_cycler.cpp b/dlls/h_cycler.cpp index c47b61f..85a0f40 100644 --- a/dlls/h_cycler.cpp +++ b/dlls/h_cycler.cpp @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, Valve LLC. All rights reserved. +* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. * * This product contains software technology licensed from Id * Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. @@ -315,7 +315,7 @@ public: void PrimaryAttack( void ); void SecondaryAttack( void ); BOOL Deploy( void ); - void Holster( void ); + void Holster( int skiplocal = 0 ); int m_iszModel; int m_iModel; }; @@ -342,16 +342,16 @@ void CWeaponCycler::Spawn( ) BOOL CWeaponCycler::Deploy( ) { m_pPlayer->pev->viewmodel = m_iszModel; - m_pPlayer->m_flNextAttack = gpGlobals->time + 1.0; + m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 1.0; SendWeaponAnim( 0 ); m_iClip = 0; return TRUE; } -void CWeaponCycler::Holster( ) +void CWeaponCycler::Holster( int skiplocal /* = 0 */ ) { - m_pPlayer->m_flNextAttack = gpGlobals->time + 0.5; + m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 0.5; } diff --git a/dlls/h_export.cpp b/dlls/h_export.cpp index 22399eb..01257a7 100644 --- a/dlls/h_export.cpp +++ b/dlls/h_export.cpp @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, Valve LLC. All rights reserved. +* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. * * This product contains software technology licensed from Id * Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. @@ -26,6 +26,7 @@ #include "cbase.h" +#ifdef _WIN32 // Required DLL entry point BOOL WINAPI DllMain( HINSTANCE hinstDLL, @@ -40,12 +41,17 @@ BOOL WINAPI DllMain( } return TRUE; } +#endif // Holds engine functionality callbacks enginefuncs_t g_engfuncs; globalvars_t *gpGlobals; +#ifdef _WIN32 void DLLEXPORT GiveFnptrsToDll( enginefuncs_t* pengfuncsFromEngine, globalvars_t *pGlobals ) +#else +extern "C" void DLLEXPORT GiveFnptrsToDll( enginefuncs_t* pengfuncsFromEngine, globalvars_t *pGlobals ) +#endif { memcpy(&g_engfuncs, pengfuncsFromEngine, sizeof(enginefuncs_t)); gpGlobals = pGlobals; diff --git a/dlls/handgrenade.cpp b/dlls/handgrenade.cpp index fef93f4..6ebe79e 100644 --- a/dlls/handgrenade.cpp +++ b/dlls/handgrenade.cpp @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, Valve LLC. All rights reserved. +* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. * * This product contains software technology licensed from Id * Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. @@ -46,7 +46,7 @@ public: void PrimaryAttack( void ); BOOL Deploy( void ); BOOL CanHolster( void ); - void Holster( void ); + void Holster( int skiplocal = 0 ); void WeaponIdle( void ); float m_flStartThrow; float m_flReleaseThrow; @@ -105,9 +105,9 @@ BOOL CHandGrenade::CanHolster( void ) return ( m_flStartThrow == 0 ); } -void CHandGrenade::Holster( ) +void CHandGrenade::Holster( int skiplocal /* = 0 */ ) { - m_pPlayer->m_flNextAttack = gpGlobals->time + 0.5; + m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 0.5; if (m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType]) { SendWeaponAnim( HANDGRENADE_HOLSTER ); diff --git a/dlls/healthkit.cpp b/dlls/healthkit.cpp index 10d3b42..d5055d9 100644 --- a/dlls/healthkit.cpp +++ b/dlls/healthkit.cpp @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, Valve LLC. All rights reserved. +* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. * * This product contains software technology licensed from Id * Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. diff --git a/dlls/hornet.cpp b/dlls/hornet.cpp index 1eaaef1..3165f0a 100644 --- a/dlls/hornet.cpp +++ b/dlls/hornet.cpp @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, Valve LLC. All rights reserved. +* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. * * This product contains software technology licensed from Id * Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. diff --git a/dlls/hornet.h b/dlls/hornet.h index 2145c76..fe7c9a1 100644 --- a/dlls/hornet.h +++ b/dlls/hornet.h @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, Valve LLC. All rights reserved. +* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. * * This product contains software technology licensed from Id * Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. diff --git a/dlls/hornetgun.cpp b/dlls/hornetgun.cpp index 226194e..0a5800a 100644 --- a/dlls/hornetgun.cpp +++ b/dlls/hornetgun.cpp @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, Valve LLC. All rights reserved. +* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. * * This product contains software technology licensed from Id * Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. @@ -47,7 +47,7 @@ public: void SecondaryAttack( void ); BOOL Deploy( void ); BOOL IsUseable( void ); - void Holster( void ); + void Holster( int skiplocal = 0 ); void Reload( void ); void WeaponIdle( void ); float m_flNextAnimTime; @@ -126,9 +126,9 @@ BOOL CHgun::Deploy( ) return DefaultDeploy( "models/v_hgun.mdl", "models/p_hgun.mdl", HGUN_UP, "hive" ); } -void CHgun::Holster( ) +void CHgun::Holster( int skiplocal /* = 0 */ ) { - m_pPlayer->m_flNextAttack = gpGlobals->time + 0.5; + m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 0.5; // m_flTimeWeaponIdle = gpGlobals->time + RANDOM_FLOAT ( 10, 15 ); SendWeaponAnim( HGUN_DOWN ); diff --git a/dlls/items.cpp b/dlls/items.cpp index ccafa6d..69b11ed 100644 --- a/dlls/items.cpp +++ b/dlls/items.cpp @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, Valve LLC. All rights reserved. +* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. * * This product contains software technology licensed from Id * Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. @@ -321,6 +321,8 @@ class CItemLongJump : public CItem { pPlayer->m_fLongJump = TRUE;// player now has longjump module + g_engfuncs.pfnSetPhysicsKeyValue( pPlayer->edict(), "slj", "1" ); + MESSAGE_BEGIN( MSG_ONE, gmsgItemPickup, NULL, pPlayer->pev ); WRITE_STRING( STRING(pev->classname) ); MESSAGE_END(); diff --git a/dlls/items.h b/dlls/items.h index d4c00e8..d8ce770 100644 --- a/dlls/items.h +++ b/dlls/items.h @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, Valve LLC. All rights reserved. +* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. * * This product contains software technology licensed from Id * Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. diff --git a/dlls/lights.cpp b/dlls/lights.cpp index 4695aa7..925acf8 100644 --- a/dlls/lights.cpp +++ b/dlls/lights.cpp @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, Valve LLC. All rights reserved. +* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. * * This product contains software technology licensed from Id * Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. @@ -170,11 +170,11 @@ void CEnvLight::KeyValue( KeyValueData* pkvd ) pkvd->fHandled = TRUE; sprintf( szColor, "%d", r ); - CVAR_SET_STRING( "cl_skycolor_r", szColor ); + CVAR_SET_STRING( "sv_skycolor_r", szColor ); sprintf( szColor, "%d", g ); - CVAR_SET_STRING( "cl_skycolor_g", szColor ); + CVAR_SET_STRING( "sv_skycolor_g", szColor ); sprintf( szColor, "%d", b ); - CVAR_SET_STRING( "cl_skycolor_b", szColor ); + CVAR_SET_STRING( "sv_skycolor_b", szColor ); } else { @@ -189,11 +189,11 @@ void CEnvLight :: Spawn( void ) UTIL_MakeAimVectors( pev->angles ); sprintf( szVector, "%f", gpGlobals->v_forward.x ); - CVAR_SET_STRING( "cl_skyvec_x", szVector ); + CVAR_SET_STRING( "sv_skyvec_x", szVector ); sprintf( szVector, "%f", gpGlobals->v_forward.y ); - CVAR_SET_STRING( "cl_skyvec_y", szVector ); + CVAR_SET_STRING( "sv_skyvec_y", szVector ); sprintf( szVector, "%f", gpGlobals->v_forward.z ); - CVAR_SET_STRING( "cl_skyvec_z", szVector ); + CVAR_SET_STRING( "sv_skyvec_z", szVector ); CLight::Spawn( ); -} +} \ No newline at end of file diff --git a/dlls/maprules.cpp b/dlls/maprules.cpp index 20f8b85..bc3b5ba 100644 --- a/dlls/maprules.cpp +++ b/dlls/maprules.cpp @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, Valve LLC. All rights reserved. +* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. * * This product contains software technology licensed from Id * Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. diff --git a/dlls/maprules.h b/dlls/maprules.h index 8b4867c..636ab2e 100644 --- a/dlls/maprules.h +++ b/dlls/maprules.h @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, Valve LLC. All rights reserved. +* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. * * This product contains software technology licensed from Id * Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. diff --git a/dlls/monsterevent.h b/dlls/monsterevent.h index 34de446..b8dbcab 100644 --- a/dlls/monsterevent.h +++ b/dlls/monsterevent.h @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, Valve LLC. All rights reserved. +* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. * * This product contains software technology licensed from Id * Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. diff --git a/dlls/monsters.h b/dlls/monsters.h index fa24dac..d245b7b 100644 --- a/dlls/monsters.h +++ b/dlls/monsters.h @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, Valve LLC. All rights reserved. +* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. * * This product contains software technology licensed from Id * Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. diff --git a/dlls/mortar.cpp b/dlls/mortar.cpp index 64dbeb1..ffc4456 100644 --- a/dlls/mortar.cpp +++ b/dlls/mortar.cpp @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, Valve LLC. All rights reserved. +* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. * * This product contains software technology licensed from Id * Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. diff --git a/dlls/mp.dsp b/dlls/mp.dsp index 5f7ceab..3403c16 100644 --- a/dlls/mp.dsp +++ b/dlls/mp.dsp @@ -43,7 +43,7 @@ RSC=rc.exe # PROP Intermediate_Dir ".\Releasemp" # PROP Target_Dir "" # ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /c -# ADD CPP /nologo /G5 /MT /W3 /GX /Zi /O2 /I "..\engine" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "VALVE_DLL" /YX /FD /c +# ADD CPP /nologo /G5 /MT /W3 /GX /Zi /O2 /I "..\dlls" /I "..\engine" /I "..\common" /I "..\pm_shared" /I "..\\" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "VALVE_DLL" /YX /FD /c # SUBTRACT CPP /Fr # ADD BASE MTL /nologo /D "NDEBUG" /win32 # ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 @@ -80,7 +80,7 @@ SOURCE="$(InputPath)" # PROP Intermediate_Dir ".\debugmp" # PROP Target_Dir "" # ADD BASE CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /c -# ADD CPP /nologo /G5 /MTd /W3 /Gm /GX /ZI /Od /I "..\engine" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "VALVE_DLL" /FR /YX /FD /c +# ADD CPP /nologo /G5 /MTd /W3 /Gm /GX /ZI /Od /I "..\dlls" /I "..\engine" /I "..\common" /I "..\pm_shared" /I "..\\" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "VALVE_DLL" /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" @@ -117,7 +117,7 @@ SOURCE="$(InputPath)" # PROP Target_Dir "" # ADD BASE CPP /nologo /G5 /MT /W3 /GX /Zi /O2 /I "..\engine" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "QUIVER" /D "VOXEL" /D "QUAKE2" /D "VALVE_DLL" /YX /c # SUBTRACT BASE CPP /Fr -# ADD CPP /nologo /G5 /MT /W3 /GX /Zi /O2 /I "..\engine" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "VALVE_DLL" /YX /FD /c +# ADD CPP /nologo /G5 /MT /W3 /GX /Zi /O2 /I "..\dlls" /I "..\engine" /I "..\common" /I "..\pm_shared" /I "..\\" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "VALVE_DLL" /YX /FD /c # SUBTRACT CPP /Fr # ADD BASE MTL /nologo /D "NDEBUG" /win32 # ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 @@ -168,6 +168,15 @@ SOURCE=.\animating.cpp # Begin Source File SOURCE=.\animation.cpp + +!IF "$(CFG)" == "mp - Win32 Release" + +!ELSEIF "$(CFG)" == "mp - Win32 Debug" + +!ELSEIF "$(CFG)" == "mp - Win32 Profile" + +!ENDIF + # End Source File # Begin Source File @@ -243,10 +252,6 @@ SOURCE=.\globals.cpp # End Source File # Begin Source File -SOURCE=.\glock.cpp -# End Source File -# Begin Source File - SOURCE=.\h_ai.cpp # End Source File # Begin Source File @@ -271,6 +276,10 @@ SOURCE=.\healthkit.cpp # End Source File # Begin Source File +SOURCE=.\wpn_shared\hl_wpn_glock.cpp +# End Source File +# Begin Source File + SOURCE=.\hornet.cpp # End Source File # Begin Source File @@ -323,6 +332,18 @@ SOURCE=.\player.cpp # End Source File # Begin Source File +SOURCE=..\pm_shared\pm_debug.c +# End Source File +# Begin Source File + +SOURCE=..\pm_shared\pm_math.c +# End Source File +# Begin Source File + +SOURCE=..\pm_shared\pm_shared.c +# End Source File +# Begin Source File + SOURCE=.\python.cpp # End Source File # Begin Source File @@ -495,6 +516,30 @@ SOURCE=.\player.h # End Source File # Begin Source File +SOURCE=..\pm_shared\pm_debug.h +# End Source File +# Begin Source File + +SOURCE=..\pm_shared\pm_defs.h +# End Source File +# Begin Source File + +SOURCE=..\pm_shared\pm_info.h +# End Source File +# Begin Source File + +SOURCE=..\pm_shared\pm_materials.h +# End Source File +# Begin Source File + +SOURCE=..\pm_shared\pm_movevars.h +# End Source File +# Begin Source File + +SOURCE=..\pm_shared\pm_shared.h +# End Source File +# Begin Source File + SOURCE=.\saverestore.h # End Source File # Begin Source File diff --git a/dlls/mp5.cpp b/dlls/mp5.cpp index 4b362d1..6f3f622 100644 --- a/dlls/mp5.cpp +++ b/dlls/mp5.cpp @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, Valve LLC. All rights reserved. +* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. * * This product contains software technology licensed from Id * Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. @@ -53,6 +53,8 @@ public: void WeaponIdle( void ); float m_flNextAnimTime; int m_iShell; +private: + unsigned short m_usMP5; }; LINK_ENTITY_TO_CLASS( weapon_mp5, CMP5 ); LINK_ENTITY_TO_CLASS( weapon_9mmAR, CMP5 ); @@ -103,6 +105,8 @@ void CMP5::Precache( void ) PRECACHE_SOUND( "weapons/glauncher2.wav" ); PRECACHE_SOUND ("weapons/357_cock1.wav"); + + m_usMP5 = PRECACHE_EVENT( 1, "events/mp5.sc" ); } int CMP5::GetItemInfo(ItemInfo *p) @@ -157,41 +161,16 @@ void CMP5::PrimaryAttack() return; } + PLAYBACK_EVENT( 0, m_pPlayer->edict(), m_usMP5 ); + m_pPlayer->m_iWeaponVolume = NORMAL_GUN_VOLUME; m_pPlayer->m_iWeaponFlash = NORMAL_GUN_FLASH; m_iClip--; - m_pPlayer->pev->effects = (int)(m_pPlayer->pev->effects) | EF_MUZZLEFLASH; - - - if (1 || m_flNextAnimTime < gpGlobals->time) - { - SendWeaponAnim( MP5_FIRE1 + RANDOM_LONG(0,2)); - m_flNextAnimTime = gpGlobals->time + 0.2; - } - // player "shoot" animation m_pPlayer->SetAnimation( PLAYER_ATTACK1 ); - switch( RANDOM_LONG(0,1) ) - { - case 0: EMIT_SOUND_DYN(ENT(m_pPlayer->pev), CHAN_WEAPON, "weapons/hks1.wav", 1, ATTN_NORM, 0, 94 + RANDOM_LONG(0,0xf)); break; - case 1: EMIT_SOUND_DYN(ENT(m_pPlayer->pev), CHAN_WEAPON, "weapons/hks2.wav", 1, ATTN_NORM, 0, 94 + RANDOM_LONG(0,0xf)); break; -// case 2: EMIT_SOUND(ENT(m_pPlayer->pev), CHAN_WEAPON, "weapons/hks3.wav", 1, ATTN_NORM); break; - } - - UTIL_MakeVectors( m_pPlayer->pev->v_angle + m_pPlayer->pev->punchangle ); - - Vector vecShellVelocity = m_pPlayer->pev->velocity - + gpGlobals->v_right * RANDOM_FLOAT(50,70) - + gpGlobals->v_up * RANDOM_FLOAT(100,150) - + gpGlobals->v_forward * 25; - EjectBrass ( pev->origin + m_pPlayer->pev->view_ofs - + gpGlobals->v_up * -12 - + gpGlobals->v_forward * 20 - + gpGlobals->v_right * 4, vecShellVelocity, pev->angles.y, m_iShell, TE_BOUNCE_SHELL); - Vector vecSrc = m_pPlayer->GetGunPosition( ); Vector vecAiming = m_pPlayer->GetAutoaimVector( AUTOAIM_5DEGREES ); @@ -215,12 +194,8 @@ void CMP5::PrimaryAttack() m_flNextPrimaryAttack = gpGlobals->time + 0.1; m_flTimeWeaponIdle = gpGlobals->time + RANDOM_FLOAT ( 10, 15 ); - - m_pPlayer->pev->punchangle.x = RANDOM_FLOAT( -2, 2 ); } - - void CMP5::SecondaryAttack( void ) { // don't fire underwater diff --git a/dlls/mpstubb.cpp b/dlls/mpstubb.cpp index 48e8f96..b01e53b 100644 --- a/dlls/mpstubb.cpp +++ b/dlls/mpstubb.cpp @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, Valve LLC. All rights reserved. +* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. * * This product contains software technology licensed from Id * Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. diff --git a/dlls/multiplay_gamerules.cpp b/dlls/multiplay_gamerules.cpp index 51e9c5d..89368b1 100644 --- a/dlls/multiplay_gamerules.cpp +++ b/dlls/multiplay_gamerules.cpp @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, Valve LLC. All rights reserved. +* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. * * This product contains software technology licensed from Id * Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. @@ -139,11 +139,17 @@ void CHalfLifeMultiplay::RefreshSkillData( void ) // longest the intermission can last, in seconds #define MAX_INTERMISSION_TIME 120 +extern cvar_t timeleft, fragsleft; //========================================================= //========================================================= void CHalfLifeMultiplay :: Think ( void ) { ///// Check game rules ///// + static int last_frags; + static int last_time; + + int frags_remaining = 0; + int time_remaining = 0; if ( g_fGameOver ) // someone else quit the game already { @@ -159,6 +165,8 @@ void CHalfLifeMultiplay :: Think ( void ) float flTimeLimit = timelimit.value * 60; float flFragLimit = fraglimit.value; + time_remaining = (int)(flTimeLimit ? ( flTimeLimit - gpGlobals->time ) : 0); + if ( flTimeLimit != 0 && gpGlobals->time >= flTimeLimit ) { GoToIntermission(); @@ -167,6 +175,9 @@ void CHalfLifeMultiplay :: Think ( void ) if ( flFragLimit ) { + int bestfrags = 9999; + int remain; + // check if any player is over the frag limit for ( int i = 1; i <= gpGlobals->maxClients; i++ ) { @@ -177,8 +188,35 @@ void CHalfLifeMultiplay :: Think ( void ) GoToIntermission(); return; } + + + if ( pPlayer ) + { + remain = flFragLimit - pPlayer->pev->frags; + if ( remain < bestfrags ) + { + bestfrags = remain; + } + } + } + frags_remaining = bestfrags; } + + // Updates when frags change + if ( frags_remaining != last_frags ) + { + g_engfuncs.pfnCvar_DirectSet( &fragsleft, UTIL_VarArgs( "%i", frags_remaining ) ); + } + + // Updates once per second + if ( timeleft.value != last_time ) + { + g_engfuncs.pfnCvar_DirectSet( &timeleft, UTIL_VarArgs( "%i", time_remaining ) ); + } + + last_frags = frags_remaining; + last_time = time_remaining; } @@ -904,7 +942,7 @@ int CHalfLifeMultiplay::PlayerRelationship( CBaseEntity *pPlayer, CBaseEntity *p BOOL CHalfLifeMultiplay :: PlayFootstepSounds( CBasePlayer *pl, float fvol ) { - if ( CVAR_GET_FLOAT( "mp_footsteps" ) == 0 ) + if ( g_footsteps && g_footsteps->value == 0 ) return FALSE; if ( pl->IsOnLadder() || pl->pev->velocity.Length2D() > 220 ) @@ -942,73 +980,492 @@ void CHalfLifeMultiplay :: GoToIntermission( void ) m_iEndIntermissionButtonHit = FALSE; } -void CHalfLifeMultiplay :: ChangeLevel( void ) +#define MAX_RULE_BUFFER 1024 + +typedef struct mapcycle_item_s { - char szNextMap[32]; - char szFirstMapInList[32]; - strcpy( szFirstMapInList, "hldm1" ); // the absolute default level is hldm1 + struct mapcycle_item_s *next; - // find the map to change to + char mapname[ 32 ]; + int minplayers, maxplayers; + char rulebuffer[ MAX_RULE_BUFFER ]; +} mapcycle_item_t; - char *mapcfile = (char*)CVAR_GET_STRING( "mapcyclefile" ); - ASSERT( mapcfile != NULL ); - strcpy( szNextMap, STRING(gpGlobals->mapname) ); - strcpy( szFirstMapInList, STRING(gpGlobals->mapname) ); +typedef struct mapcycle_s +{ + struct mapcycle_item_s *items; + struct mapcycle_item_s *next_item; +} mapcycle_t; +/* +============== +DestroyMapCycle + +Clean up memory used by mapcycle when switching it +============== +*/ +void DestroyMapCycle( mapcycle_t *cycle ) +{ + mapcycle_item_t *p, *n, *start; + p = cycle->items; + if ( p ) + { + start = p; + p = p->next; + while ( p != start ) + { + n = p->next; + delete p; + p = n; + } + + delete cycle->items; + } + cycle->items = NULL; + cycle->next_item = NULL; +} + +static char com_token[ 1500 ]; + +/* +============== +COM_Parse + +Parse a token out of a string +============== +*/ +char *COM_Parse (char *data) +{ + int c; + int len; + + len = 0; + com_token[0] = 0; + + if (!data) + return NULL; + +// skip whitespace +skipwhite: + while ( (c = *data) <= ' ') + { + if (c == 0) + return NULL; // end of file; + data++; + } + +// skip // comments + if (c=='/' && data[1] == '/') + { + while (*data && *data != '\n') + data++; + goto skipwhite; + } + + +// handle quoted strings specially + if (c == '\"') + { + data++; + while (1) + { + c = *data++; + if (c=='\"' || !c) + { + com_token[len] = 0; + return data; + } + com_token[len] = c; + len++; + } + } + +// parse single characters + if (c=='{' || c=='}'|| c==')'|| c=='(' || c=='\'' || c == ',' ) + { + com_token[len] = c; + len++; + com_token[len] = 0; + return data+1; + } + +// parse a regular word + do + { + com_token[len] = c; + data++; + len++; + c = *data; + if (c=='{' || c=='}'|| c==')'|| c=='(' || c=='\'' || c == ',' ) + break; + } while (c>32); + + com_token[len] = 0; + return data; +} + +/* +============== +COM_TokenWaiting + +Returns 1 if additional data is waiting to be processed on this line +============== +*/ +int COM_TokenWaiting( char *buffer ) +{ + char *p; + + p = buffer; + while ( *p && *p!='\n') + { + if ( !isspace( *p ) || isalnum( *p ) ) + return 1; + + p++; + } + + return 0; +} + +/* +============== +ReloadMapCycleFile + + +Parses mapcycle.txt file into mapcycle_t structure +============== +*/ +int ReloadMapCycleFile( char *filename, mapcycle_t *cycle ) +{ + char szBuffer[ MAX_RULE_BUFFER ]; + char szMap[ 32 ]; int length; char *pFileList; - char *aFileList = pFileList = (char*)LOAD_FILE_FOR_ME( mapcfile, &length ); + char *aFileList = pFileList = (char*)LOAD_FILE_FOR_ME( filename, &length ); + int hasbuffer; + mapcycle_item_s *item, *newlist = NULL, *next; + if ( pFileList && length ) { // the first map name in the file becomes the default - sscanf( pFileList, " %32s", szNextMap ); - if ( IS_MAP_VALID( szNextMap ) ) - strcpy( szFirstMapInList, szNextMap ); - - // keep pulling mapnames out of the list until the current mapname - // if the current mapname isn't found, load the first map in the list - BOOL next_map_is_it = FALSE; while ( 1 ) { - while ( *pFileList && isspace( *pFileList ) ) pFileList++; // skip over any whitespace - if ( !(*pFileList) ) + hasbuffer = 0; + memset( szBuffer, 0, MAX_RULE_BUFFER ); + + pFileList = COM_Parse( pFileList ); + if ( strlen( com_token ) <= 0 ) break; - char cBuf[32]; - int ret = sscanf( pFileList, " %32s", cBuf ); - // Check the map name is valid - if ( ret != 1 || *cBuf < 13 ) - break; + strcpy( szMap, com_token ); - if ( next_map_is_it ) + // Any more tokens on this line? + if ( COM_TokenWaiting( pFileList ) ) { - // check that it is a valid map file - if ( IS_MAP_VALID( cBuf ) ) + pFileList = COM_Parse( pFileList ); + if ( strlen( com_token ) > 0 ) { - strcpy( szNextMap, cBuf ); - break; + hasbuffer = 1; + strcpy( szBuffer, com_token ); } } - if ( FStrEq( cBuf, STRING(gpGlobals->mapname) ) ) - { // we've found our map; next map is the one to change to - next_map_is_it = TRUE; + // Check map + if ( IS_MAP_VALID( szMap ) ) + { + // Create entry + char *s; + + item = new mapcycle_item_s; + + strcpy( item->mapname, szMap ); + + item->minplayers = 0; + item->maxplayers = 0; + + memset( item->rulebuffer, 0, MAX_RULE_BUFFER ); + + if ( hasbuffer ) + { + s = g_engfuncs.pfnInfoKeyValue( szBuffer, "minplayers" ); + if ( s && s[0] ) + { + item->minplayers = atoi( s ); + item->minplayers = max( item->minplayers, 0 ); + item->minplayers = min( item->minplayers, gpGlobals->maxClients ); + } + s = g_engfuncs.pfnInfoKeyValue( szBuffer, "maxplayers" ); + if ( s && s[0] ) + { + item->maxplayers = atoi( s ); + item->maxplayers = max( item->maxplayers, 0 ); + item->maxplayers = min( item->maxplayers, gpGlobals->maxClients ); + } + + // Remove keys + // + g_engfuncs.pfnInfo_RemoveKey( szBuffer, "minplayers" ); + g_engfuncs.pfnInfo_RemoveKey( szBuffer, "maxplayers" ); + + strcpy( item->rulebuffer, szBuffer ); + } + + item->next = cycle->items; + cycle->items = item; + } + else + { + ALERT( at_console, "Skipping %s from mapcycle, not a valid map\n", szMap ); } - pFileList += strlen( cBuf ); + } FREE_FILE( aFileList ); } + // Fixup circular list pointer + item = cycle->items; + + // Reverse it to get original order + while ( item ) + { + next = item->next; + item->next = newlist; + newlist = item; + item = next; + } + cycle->items = newlist; + item = cycle->items; + + // Didn't parse anything + if ( !item ) + { + return 0; + } + + while ( item->next ) + { + item = item->next; + } + item->next = cycle->items; + + cycle->next_item = item->next; + + return 1; +} + +/* +============== +CountPlayers + +Determine the current # of active players on the server for map cycling logic +============== +*/ +int CountPlayers( void ) +{ + int num = 0; + + for ( int i = 1; i <= gpGlobals->maxClients; i++ ) + { + CBaseEntity *pEnt = UTIL_PlayerByIndex( i ); + + if ( pEnt ) + { + num = num + 1; + } + } + + return num; +} + +/* +============== +ExtractCommandString + +Parse commands/key value pairs to issue right after map xxx command is issued on server + level transition +============== +*/ +void ExtractCommandString( char *s, char *szCommand ) +{ + // Now make rules happen + char pkey[512]; + char value[512]; // use two buffers so compares + // work without stomping on each other + char *o; + + if ( *s == '\\' ) + s++; + + while (1) + { + o = pkey; + while ( *s != '\\' ) + { + if ( !*s ) + return; + *o++ = *s++; + } + *o = 0; + s++; + + o = value; + + while (*s != '\\' && *s) + { + if (!*s) + return; + *o++ = *s++; + } + *o = 0; + + strcat( szCommand, pkey ); + if ( strlen( value ) > 0 ) + { + strcat( szCommand, " " ); + strcat( szCommand, value ); + } + strcat( szCommand, "\n" ); + + if (!*s) + return; + s++; + } +} + +/* +============== +ChangeLevel + +Server is changing to a new level, check mapcycle.txt for map name and setup info +============== +*/ +void CHalfLifeMultiplay :: ChangeLevel( void ) +{ + static char szPreviousMapCycleFile[ 256 ]; + static mapcycle_t mapcycle; + + char szNextMap[32]; + char szFirstMapInList[32]; + char szCommands[ 1500 ]; + char szRules[ 1500 ]; + int minplayers = 0, maxplayers = 0; + strcpy( szFirstMapInList, "hldm1" ); // the absolute default level is hldm1 + + int curplayers; + BOOL do_cycle = TRUE; + + // find the map to change to + char *mapcfile = (char*)CVAR_GET_STRING( "mapcyclefile" ); + ASSERT( mapcfile != NULL ); + + szCommands[ 0 ] = '\0'; + szRules[ 0 ] = '\0'; + + curplayers = CountPlayers(); + + // Has the map cycle filename changed? + if ( stricmp( mapcfile, szPreviousMapCycleFile ) ) + { + strcpy( szPreviousMapCycleFile, mapcfile ); + + DestroyMapCycle( &mapcycle ); + + if ( !ReloadMapCycleFile( mapcfile, &mapcycle ) || ( !mapcycle.items ) ) + { + ALERT( at_console, "Unable to load map cycle file %s\n", mapcfile ); + do_cycle = FALSE; + } + } + + if ( do_cycle && mapcycle.items ) + { + BOOL keeplooking = FALSE; + BOOL found = FALSE; + mapcycle_item_s *item; + + // Assume current map + strcpy( szNextMap, STRING(gpGlobals->mapname) ); + strcpy( szFirstMapInList, STRING(gpGlobals->mapname) ); + + // Traverse list + for ( item = mapcycle.next_item; item->next != mapcycle.next_item; item = item->next ) + { + keeplooking = FALSE; + + ASSERT( item != NULL ); + + if ( item->minplayers != 0 ) + { + if ( curplayers >= item->minplayers ) + { + found = TRUE; + minplayers = item->minplayers; + } + else + { + keeplooking = TRUE; + } + } + + if ( item->maxplayers != 0 ) + { + if ( curplayers <= item->maxplayers ) + { + found = TRUE; + maxplayers = item->maxplayers; + } + else + { + keeplooking = TRUE; + } + } + + if ( keeplooking ) + continue; + + found = TRUE; + break; + } + + if ( !found ) + { + item = mapcycle.next_item; + } + + // Increment next item pointer + mapcycle.next_item = item->next; + + // Perform logic on current item + strcpy( szNextMap, item->mapname ); + + ExtractCommandString( item->rulebuffer, szCommands ); + strcpy( szRules, item->rulebuffer ); + } + if ( !IS_MAP_VALID(szNextMap) ) + { strcpy( szNextMap, szFirstMapInList ); + } g_fGameOver = TRUE; ALERT( at_console, "CHANGE LEVEL: %s\n", szNextMap ); + if ( minplayers || maxplayers ) + { + ALERT( at_console, "PLAYER COUNT: min %i max %i current %i\n", minplayers, maxplayers, curplayers ); + } + if ( strlen( szRules ) > 0 ) + { + ALERT( at_console, "RULES: %s\n", szRules ); + } CHANGE_LEVEL( szNextMap, NULL ); + if ( strlen( szCommands ) > 0 ) + { + SERVER_COMMAND( szCommands ); + } } #define MAX_MOTD_CHUNK 60 diff --git a/dlls/nodes.h b/dlls/nodes.h index eb73baf..6bc7c89 100644 --- a/dlls/nodes.h +++ b/dlls/nodes.h @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, Valve LLC. All rights reserved. +* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. * * This product contains software technology licensed from Id * Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. diff --git a/dlls/pathcorner.cpp b/dlls/pathcorner.cpp index f9e56c3..1d0ff3e 100644 --- a/dlls/pathcorner.cpp +++ b/dlls/pathcorner.cpp @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, Valve LLC. All rights reserved. +* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. * * This product contains software technology licensed from Id * Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. diff --git a/dlls/plane.cpp b/dlls/plane.cpp index c96bf46..06bfa46 100644 --- a/dlls/plane.cpp +++ b/dlls/plane.cpp @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, Valve LLC. All rights reserved. +* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. * * This product contains software technology licensed from Id * Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. @@ -13,6 +13,7 @@ * ****/ #include "extdll.h" +#include "util.h" #include "plane.h" //========================================================= diff --git a/dlls/plane.h b/dlls/plane.h index ea2aa33..918cc02 100644 --- a/dlls/plane.h +++ b/dlls/plane.h @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, Valve LLC. All rights reserved. +* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. * * This product contains software technology licensed from Id * Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. diff --git a/dlls/plats.cpp b/dlls/plats.cpp index 013f164..16a0c3d 100644 --- a/dlls/plats.cpp +++ b/dlls/plats.cpp @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, Valve LLC. All rights reserved. +* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. * * This product contains software technology licensed from Id * Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. @@ -1098,7 +1098,17 @@ void CFuncTrackTrain :: StopSound( void ) // if sound playing, stop it if (m_soundPlaying && pev->noise) { + unsigned short us_encode; + unsigned short us_sound = ( ( unsigned short )( m_sounds ) & 0x0007 ) << 12; + + us_encode = us_sound; + + PLAYBACK_EVENT_FULL( FEV_RELIABLE | FEV_UPDATE, edict(), m_usAdjustPitch, 0.0, + (float *)&g_vecZero, (float *)&g_vecZero, 0.0, 0.0, us_encode, 0, 1, 0 ); + + /* STOP_SOUND(ENT(pev), CHAN_STATIC, (char*)STRING(pev->noise)); + */ EMIT_SOUND_DYN(ENT(pev), CHAN_ITEM, "plats/ttrain_brake1.wav", m_flVolume, ATTN_NORM, 0, 100); } @@ -1127,8 +1137,24 @@ void CFuncTrackTrain :: UpdateSound( void ) } else { +/* // update pitch EMIT_SOUND_DYN(ENT(pev), CHAN_STATIC, (char*)STRING(pev->noise), m_flVolume, ATTN_NORM, SND_CHANGE_PITCH, (int) flpitch); +*/ + // volume 0.0 - 1.0 - 6 bits + // m_sounds 3 bits + // flpitch = 6 bits + // 15 bits total + + unsigned short us_encode; + unsigned short us_sound = ( ( unsigned short )( m_sounds ) & 0x0007 ) << 12; + unsigned short us_pitch = ( ( unsigned short )( flpitch / 10.0 ) & 0x003f ) << 6; + unsigned short us_volume = ( ( unsigned short )( m_flVolume * 40.0 ) & 0x003f ); + + us_encode = us_sound | us_pitch | us_volume; + + PLAYBACK_EVENT_FULL( FEV_RELIABLE | FEV_UPDATE, edict(), m_usAdjustPitch, 0.0, + (float *)&g_vecZero, (float *)&g_vecZero, 0.0, 0.0, us_encode, 0, 0, 0 ); } } @@ -1519,6 +1545,7 @@ void CFuncTrackTrain :: Precache( void ) PRECACHE_SOUND("plats/ttrain_brake1.wav"); PRECACHE_SOUND("plats/ttrain_start1.wav"); + m_usAdjustPitch = PRECACHE_EVENT( 1, "events/train.sc" ); } // This class defines the volume of space that the player must stand in to control the train diff --git a/dlls/player.cpp b/dlls/player.cpp index e37d4e9..ea4a16c 100644 --- a/dlls/player.cpp +++ b/dlls/player.cpp @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, Valve LLC. All rights reserved. +* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. * * This product contains software technology licensed from Id * Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. @@ -186,6 +186,48 @@ int gmsgSayText = 0; int gmsgTextMsg = 0; int gmsgSetFOV = 0; int gmsgShowMenu = 0; +int gmsgGeigerRange = 0; + +void LinkUserMessages( void ) +{ + // Already taken care of? + if ( gmsgSelAmmo ) + { + return; + } + + gmsgSelAmmo = REG_USER_MSG("SelAmmo", sizeof(SelAmmo)); + gmsgCurWeapon = REG_USER_MSG("CurWeapon", 3); + gmsgGeigerRange = REG_USER_MSG("Geiger", 1); + gmsgFlashlight = REG_USER_MSG("Flashlight", 2); + gmsgFlashBattery = REG_USER_MSG("FlashBat", 1); + gmsgHealth = REG_USER_MSG( "Health", 1 ); + gmsgDamage = REG_USER_MSG( "Damage", 12 ); + gmsgBattery = REG_USER_MSG( "Battery", 2); + gmsgTrain = REG_USER_MSG( "Train", 1); + gmsgHudText = REG_USER_MSG( "HudText", -1 ); + gmsgSayText = REG_USER_MSG( "SayText", -1 ); + gmsgTextMsg = REG_USER_MSG( "TextMsg", -1 ); + gmsgWeaponList = REG_USER_MSG("WeaponList", -1); + gmsgResetHUD = REG_USER_MSG("ResetHUD", 1); // called every respawn + gmsgInitHUD = REG_USER_MSG("InitHUD", 0 ); // called every time a new player joins the server + gmsgShowGameTitle = REG_USER_MSG("GameTitle", 1); + gmsgDeathMsg = REG_USER_MSG( "DeathMsg", -1 ); + gmsgScoreInfo = REG_USER_MSG( "ScoreInfo", 5 ); + gmsgTeamInfo = REG_USER_MSG( "TeamInfo", -1 ); // sets the name of a player's team + gmsgTeamScore = REG_USER_MSG( "TeamScore", -1 ); // sets the score of a team on the scoreboard + gmsgGameMode = REG_USER_MSG( "GameMode", 1 ); + gmsgMOTD = REG_USER_MSG( "MOTD", -1 ); + gmsgAmmoPickup = REG_USER_MSG( "AmmoPickup", 2 ); + gmsgWeapPickup = REG_USER_MSG( "WeapPickup", 1 ); + gmsgItemPickup = REG_USER_MSG( "ItemPickup", -1 ); + gmsgHideWeapon = REG_USER_MSG( "HideWeapon", 1 ); + gmsgSetFOV = REG_USER_MSG( "SetFOV", 1 ); + gmsgShowMenu = REG_USER_MSG( "ShowMenu", -1 ); + gmsgShake = REG_USER_MSG("ScreenShake", sizeof(ScreenShake)); + gmsgFade = REG_USER_MSG("ScreenFade", sizeof(ScreenFade)); + gmsgAmmoX = REG_USER_MSG("AmmoX", 2); +} LINK_ENTITY_TO_CLASS( player, CBasePlayer ); @@ -332,7 +374,10 @@ Vector CBasePlayer :: GetGunPosition( ) { // UTIL_MakeVectors(pev->v_angle); // m_HackedGunPos = pev->view_ofs; - return pev->origin + pev->view_ofs; + Vector origin; + + origin = pev->origin + pev->view_ofs; + return origin; } //========================================================= @@ -816,14 +861,12 @@ void CBasePlayer::Killed( entvars_t *pevAttacker, int iGib ) } SetAnimation( PLAYER_DIE ); - + + m_iRespawnFrames = 0; + pev->modelindex = g_ulModelIndexPlayer; // don't use eyes -#if !defined(DUCKFIX) - pev->view_ofs = Vector(0,0,-8); -#endif pev->deadflag = DEAD_DYING; - pev->solid = SOLID_NOT; pev->movetype = MOVETYPE_TOSS; ClearBits(pev->flags, FL_ONGROUND); if (pev->velocity.z < 10) @@ -858,6 +901,7 @@ void CBasePlayer::Killed( entvars_t *pevAttacker, int iGib ) if ( ( pev->health < -40 && iGib != GIB_NEVER ) || iGib == GIB_ALWAYS ) { + pev->solid = SOLID_NOT; GibMonster(); // This clears pev->model pev->effects |= EF_NODRAW; return; @@ -1129,6 +1173,7 @@ void CBasePlayer::WaterMove() { if (FBitSet(pev->flags, FL_INWATER)) { +#if 0 // play leave water sound switch (RANDOM_LONG(0,3)) { @@ -1137,6 +1182,7 @@ void CBasePlayer::WaterMove() case 2: EMIT_SOUND(ENT(pev), CHAN_BODY, "player/pl_wade3.wav", 1, ATTN_NORM); break; case 3: EMIT_SOUND(ENT(pev), CHAN_BODY, "player/pl_wade4.wav", 1, ATTN_NORM); break; } +#endif ClearBits(pev->flags, FL_INWATER); } @@ -1170,6 +1216,7 @@ void CBasePlayer::WaterMove() if (!FBitSet(pev->flags, FL_INWATER)) { +#if 0 // player enter water sound if (pev->watertype == CONTENT_WATER) { @@ -1181,6 +1228,7 @@ void CBasePlayer::WaterMove() case 3: EMIT_SOUND(ENT(pev), CHAN_BODY, "player/pl_wade4.wav", 1, ATTN_NORM); break; } } +#endif SetBits(pev->flags, FL_INWATER); pev->dmgtime = 0; @@ -1197,42 +1245,6 @@ BOOL CBasePlayer::IsOnLadder( void ) return (pev->movetype == MOVETYPE_FLY); } - -// -// check for a jump-out-of-water -// -void CBasePlayer::CheckWaterJump( ) -{ - if ( IsOnLadder() ) // Don't water jump if on a ladders? (This prevents the bug where - return; // you bounce off water when you are facing it on a ladder). - - Vector vecStart = pev->origin; - vecStart.z += 8; - - UTIL_MakeVectors(pev->angles); - gpGlobals->v_forward.z = 0; - gpGlobals->v_forward = gpGlobals->v_forward.Normalize(); - - Vector vecEnd = vecStart + gpGlobals->v_forward * 24; - - TraceResult tr; - UTIL_TraceLine(vecStart, vecEnd, ignore_monsters, ENT(pev)/*pentIgnore*/, &tr); - if (tr.flFraction < 1) // solid at waist - { - vecStart.z += pev->maxs.z - 8; - vecEnd = vecStart + gpGlobals->v_forward * 24; - pev->movedir = tr.vecPlaneNormal * -50; - UTIL_TraceLine(vecStart, vecEnd, ignore_monsters, ENT(pev)/*pentIgnore*/, &tr); - if (tr.flFraction == 1) // open at eye level - { - SetBits(pev->flags, FL_WATERJUMP); - pev->velocity.z = 225; - pev->teleport_time = gpGlobals->time + 2; // safety net - } - } -} - - void CBasePlayer::PlayerDeathThink(void) { float flForward; @@ -1260,8 +1272,8 @@ void CBasePlayer::PlayerDeathThink(void) { StudioFrameAdvance( ); - m_iRespawnFrames++; - if ( m_iRespawnFrames < 60 ) // animations should be no longer than this + m_iRespawnFrames++; // Note, these aren't necessarily real "frames", so behavior is dependent on # of client movement commands + if ( m_iRespawnFrames < 120 ) // Animations should be no longer than this return; } @@ -1273,7 +1285,7 @@ void CBasePlayer::PlayerDeathThink(void) pev->effects |= EF_NOINTERP; pev->framerate = 0.0; - BOOL fAnyButtonDown = (pev->button); + BOOL fAnyButtonDown = (pev->button & ~IN_SCORE ); // wait for all buttons released if (pev->deadflag == DEAD_DEAD) @@ -1489,7 +1501,6 @@ void CBasePlayer::PlayerUse ( void ) void CBasePlayer::Jump() { - float flScale; Vector vecWallCheckDir;// direction we're tracing a line to find a wall when walljumping Vector vecAdjustedVelocity; Vector vecSpot; @@ -1500,27 +1511,6 @@ void CBasePlayer::Jump() if (pev->waterlevel >= 2) { - switch ((int)pev->watertype) - { - case CONTENT_WATER: flScale = 100; break; - case CONTENT_SLIME: flScale = 80; break; - default: flScale = 50; break; - } - - pev->velocity.z = flScale; - - // play swiming sound - if (m_flSwimTime < gpGlobals->time) - { - m_flSwimTime = gpGlobals->time + 1; - switch (RANDOM_LONG(0,3)) - { - case 0: EMIT_SOUND(ENT(pev), CHAN_BODY, "player/pl_wade1.wav", 1, ATTN_NORM); break; - case 1: EMIT_SOUND(ENT(pev), CHAN_BODY, "player/pl_wade2.wav", 1, ATTN_NORM); break; - case 2: EMIT_SOUND(ENT(pev), CHAN_BODY, "player/pl_wade3.wav", 1, ATTN_NORM); break; - case 3: EMIT_SOUND(ENT(pev), CHAN_BODY, "player/pl_wade4.wav", 1, ATTN_NORM); break; - } - } return; } @@ -1538,49 +1528,22 @@ void CBasePlayer::Jump() // many features in this function use v_forward, so makevectors now. UTIL_MakeVectors (pev->angles); - ClearBits(pev->flags, FL_ONGROUND); // don't stairwalk - SetAnimation( PLAYER_JUMP ); - // play step sound for current texture at full volume - - PlayStepSound(MapTextureTypeStepType(m_chTextureType), 1.0); - if ( FBitSet(pev->flags, FL_DUCKING ) || FBitSet(m_afPhysicsFlags, PFLAG_DUCKING) ) { if ( m_fLongJump && (pev->button & IN_DUCK) && gpGlobals->time - m_flDuckTime < 1 && pev->velocity.Length() > 50 ) - {// If jump pressed within a second of duck while moving, long jump! -// ALERT ( at_console, "LongJump!" ); - - // play longjump 'servo' sound - if ( RANDOM_LONG(0,1) ) - { - ; // UNDONE: EMIT_SOUND(ENT(pev), CHAN_VOICE, "player/pl_pain2.wav", 1, ATTN_NORM); - } - else - { - ; // UNDONE: EMIT_SOUND(ENT(pev), CHAN_VOICE, "player/pl_pain4.wav", 1, ATTN_NORM); - } - - pev->punchangle.x = -5; - pev->velocity = gpGlobals->v_forward * (PLAYER_LONGJUMP_SPEED * 1.6); - pev->velocity.z = sqrt( 2 * 800 * 56.0 ); // jump 56 units + { SetAnimation( PLAYER_SUPERJUMP ); } - else - {// ducking jump - pev->velocity.z = sqrt( 2 * 800 * 45.0 ); // jump 45 units - } - } - else - { - pev->velocity.z = sqrt( 2 * 800 * 45.0 ); // jump 45 units } // If you're standing on a conveyor, add it's velocity to yours (for momentum) entvars_t *pevGround = VARS(pev->groundentity); if ( pevGround && (pevGround->flags & FL_CONVEYOR) ) + { pev->velocity = pev->velocity + pev->basevelocity; + } } @@ -1603,87 +1566,12 @@ void FixPlayerCrouchStuck( edict_t *pPlayer ) } } -// It takes 0.4 seconds to duck -#define TIME_TO_DUCK 0.4 - -// This is a little more complicated now than it used to be, but I think for the better - -// The player's origin no longer moves when ducking. If you start ducking while standing on ground, -// your view offset is non-linearly blended to the ducking position and then your hull is changed. -// In air, duck works just like it used to - you pick up your feet (more like tucking). -// PFLAG_DUCKING was added to track the state where the player is in the process of ducking, but hasn't -// reached the crouched position yet. -// -// A few of nice side effects of this are: -// a) On ground status does not change when ducking (good on trains, etc) -// b) origin stays constant -// c) Superjump can begin while still in run animation (nice when looking at others in multiplayer) -// void CBasePlayer::Duck( ) { - float time, duckFraction; - if (pev->button & IN_DUCK) { -#if !defined(DUCKFIX) - if ( (m_afButtonPressed & IN_DUCK) && !(pev->flags & FL_DUCKING) ) - { - m_flDuckTime = gpGlobals->time; - SetBits(m_afPhysicsFlags,PFLAG_DUCKING); // We are in the process of ducking - } - time = (gpGlobals->time - m_flDuckTime); - - // if we're not already done ducking - if ( FBitSet( m_afPhysicsFlags, PFLAG_DUCKING ) ) - { - // Finish ducking immediately if duck time is over or not on ground - if ( time >= TIME_TO_DUCK || !(pev->flags & FL_ONGROUND) ) - { - // HACKHACK - Fudge for collision bug - no time to fix this properly - if ( pev->flags & FL_ONGROUND ) - { - pev->origin = pev->origin - (VEC_DUCK_HULL_MIN - VEC_HULL_MIN); - FixPlayerCrouchStuck( edict() ); - } - - - UTIL_SetOrigin( pev, pev->origin ); - - UTIL_SetSize(pev, VEC_DUCK_HULL_MIN, VEC_DUCK_HULL_MAX); - pev->view_ofs = VEC_DUCK_VIEW; - SetBits(pev->flags,FL_DUCKING); // Hull is duck hull - ClearBits(m_afPhysicsFlags,PFLAG_DUCKING); // Done ducking (don't ease-in when the player hits the ground) - } - else - { - // Calc parametric time - duckFraction = UTIL_SplineFraction( time, (1.0/TIME_TO_DUCK) ); - pev->view_ofs = ((VEC_DUCK_VIEW - (VEC_DUCK_HULL_MIN - VEC_HULL_MIN)) * duckFraction) + (VEC_VIEW * (1-duckFraction)); - } - } -#endif SetAnimation( PLAYER_WALK ); } - else - { -#if !defined(DUCKFIX) - TraceResult trace; - Vector newOrigin = pev->origin; - - if ( pev->flags & FL_ONGROUND ) - newOrigin = newOrigin + (VEC_DUCK_HULL_MIN - VEC_HULL_MIN); - - UTIL_TraceHull( newOrigin, newOrigin, dont_ignore_monsters, human_hull, ENT(pev), &trace ); - - if ( !trace.fStartSolid ) - { - ClearBits(pev->flags,FL_DUCKING); - ClearBits(m_afPhysicsFlags,PFLAG_DUCKING); - pev->view_ofs = VEC_VIEW; - UTIL_SetSize(pev, VEC_HULL_MIN, VEC_HULL_MAX); - pev->origin = newOrigin; - } -#endif - } } // @@ -2086,8 +1974,6 @@ void CBasePlayer :: UpdateStepSound( void ) // 35% volume if ducking if ( pev->flags & FL_DUCKING ) fvol *= 0.35; - - PlayStepSound(step, fvol); } } @@ -2130,13 +2016,6 @@ void CBasePlayer::PreThink(void) CheckSuitUpdate(); - if (pev->waterlevel == 2) - CheckWaterJump(); - else if ( pev->waterlevel == 0 ) - { - pev->flags &= ~FL_WATERJUMP; // Clear this if out of water - } - if (pev->deadflag >= DEAD_DYING) { PlayerDeathThink(); @@ -2479,8 +2358,6 @@ Things powered by the battery */ // if in range of radiation source, ping geiger counter -int gmsgGeigerRange; - #define GEIGERDELAY 0.25 void CBasePlayer :: UpdateGeigerCounter( void ) @@ -2820,10 +2697,10 @@ void CBasePlayer :: UpdatePlayerSound ( void ) void CBasePlayer::PostThink() { if ( g_fGameOver ) - return; // intermission or finale + goto pt_end; // intermission or finale if (!IsAlive()) - return; + goto pt_end; // Handle Tank controlling if ( m_pTank != NULL ) @@ -2865,12 +2742,6 @@ void CBasePlayer::PostThink() else if ( m_flFallVelocity > PLAYER_MAX_SAFE_FALL_SPEED ) {// after this point, we start doing damage - switch ( RANDOM_LONG(0,1) ) - { - case 0: EMIT_SOUND(ENT(pev), CHAN_VOICE, "player/pl_fallpain2.wav", 1, ATTN_NORM); - case 1: EMIT_SOUND(ENT(pev), CHAN_VOICE, "player/pl_fallpain3.wav", 1, ATTN_NORM); - } - float flFallDamage = g_pGameRules->FlPlayerFallDamage( this ); if ( flFallDamage > pev->health ) @@ -2882,6 +2753,7 @@ void CBasePlayer::PostThink() if ( flFallDamage > 0 ) { TakeDamage(VARS(eoNullEntity), VARS(eoNullEntity), flFallDamage, DMG_FALL ); + pev->punchangle.x = 0; } fvol = 1.0; @@ -2901,23 +2773,6 @@ void CBasePlayer::PostThink() // get current texture under player right away m_flTimeStepSound = 0; UpdateStepSound(); - - // play step sound for current texture - PlayStepSound(MapTextureTypeStepType(m_chTextureType), fvol); - - // knock the screen around a little bit, temporary effect - pev->punchangle.x = m_flFallVelocity * 0.018; // punch x axis - - if ( pev->punchangle.x > 8 ) - { - pev->punchangle.x = 8; - } - - if ( RANDOM_LONG(0,1) ) - { - pev->punchangle.z = m_flFallVelocity * 0.009; - } - } if ( IsAlive() ) @@ -2954,6 +2809,45 @@ void CBasePlayer::PostThink() // Track button info so we can detect 'pressed' and 'released' buttons next frame m_afButtonLast = pev->button; + +pt_end: +#if defined( CLIENT_WEAPONS ) + // Decay timers on weapons + // go through all of the weapons and make a list of the ones to pack + for ( int i = 0 ; i < MAX_ITEM_TYPES ; i++ ) + { + if ( m_rgpPlayerItems[ i ] ) + { + CBasePlayerItem *pPlayerItem = m_rgpPlayerItems[ i ]; + + while ( pPlayerItem ) + { + CBasePlayerWeapon *gun; + + gun = (CBasePlayerWeapon *)pPlayerItem->GetWeaponPtr(); + + if ( gun && gun->UseDecrement() ) + { + gun->m_flNextPrimaryAttack = max( gun->m_flNextPrimaryAttack - gpGlobals->frametime, -1.0 ); + gun->m_flNextSecondaryAttack = max( gun->m_flNextSecondaryAttack - gpGlobals->frametime, -0.001 ); + + if ( gun->m_flTimeWeaponIdle != 1000 ) + { + gun->m_flTimeWeaponIdle = max( gun->m_flTimeWeaponIdle - gpGlobals->frametime, -0.001 ); + } + } + + pPlayerItem = pPlayerItem->m_pNext; + } + } + } + + m_flNextAttack -= gpGlobals->frametime; + if ( m_flNextAttack < -0.001 ) + m_flNextAttack = -0.001; +#else + return; +#endif } @@ -3095,10 +2989,16 @@ void CBasePlayer::Spawn( void ) pev->deadflag = DEAD_NO; pev->dmg_take = 0; pev->dmg_save = 0; + pev->friction = 1.0; + pev->gravity = 1.0; m_bitsHUDDamage = -1; m_bitsDamageType = 0; m_afPhysicsFlags = 0; m_fLongJump = FALSE;// no longjump module. + + g_engfuncs.pfnSetPhysicsKeyValue( edict(), "slj", "0" ); + g_engfuncs.pfnSetPhysicsKeyValue( edict(), "hl", "1" ); + m_iFOV = 0;// init field of view. m_iClientFOV = -1; // make sure fov reset is sent @@ -3112,7 +3012,7 @@ void CBasePlayer::Spawn( void ) m_flFieldOfView = 0.5;// some monsters use this to determine whether or not the player is looking at them. m_bloodColor = BLOOD_COLOR_RED; - m_flNextAttack = gpGlobals->time; + m_flNextAttack = UTIL_WeaponTimeBase(); StartSneaking(); m_iFlashBattery = 99; @@ -3198,37 +3098,8 @@ void CBasePlayer :: Precache( void ) m_iTrain = TRAIN_NEW; - gmsgSelAmmo = REG_USER_MSG("SelAmmo", sizeof(SelAmmo)); - gmsgCurWeapon = REG_USER_MSG("CurWeapon", 3); - gmsgGeigerRange = REG_USER_MSG("Geiger", 1); - gmsgFlashlight = REG_USER_MSG("Flashlight", 2); - gmsgFlashBattery = REG_USER_MSG("FlashBat", 1); - gmsgHealth = REG_USER_MSG( "Health", 1 ); - gmsgDamage = REG_USER_MSG( "Damage", 12 ); - gmsgBattery = REG_USER_MSG( "Battery", 2); - gmsgTrain = REG_USER_MSG( "Train", 1); - gmsgHudText = REG_USER_MSG( "HudText", -1 ); - gmsgSayText = REG_USER_MSG( "SayText", -1 ); - gmsgTextMsg = REG_USER_MSG( "TextMsg", -1 ); - gmsgWeaponList = REG_USER_MSG("WeaponList", -1); - gmsgResetHUD = REG_USER_MSG("ResetHUD", 1); // called every respawn - gmsgInitHUD = REG_USER_MSG("InitHUD", 0 ); // called every time a new player joins the server - gmsgShowGameTitle = REG_USER_MSG("GameTitle", 1); - gmsgDeathMsg = REG_USER_MSG( "DeathMsg", -1 ); - gmsgScoreInfo = REG_USER_MSG( "ScoreInfo", 5 ); - gmsgTeamInfo = REG_USER_MSG( "TeamInfo", -1 ); // sets the name of a player's team - gmsgTeamScore = REG_USER_MSG( "TeamScore", -1 ); // sets the score of a team on the scoreboard - gmsgGameMode = REG_USER_MSG( "GameMode", 1 ); - gmsgMOTD = REG_USER_MSG( "MOTD", -1 ); - gmsgAmmoPickup = REG_USER_MSG( "AmmoPickup", 2 ); - gmsgWeapPickup = REG_USER_MSG( "WeapPickup", 1 ); - gmsgItemPickup = REG_USER_MSG( "ItemPickup", -1 ); - gmsgHideWeapon = REG_USER_MSG( "HideWeapon", 1 ); - gmsgSetFOV = REG_USER_MSG( "SetFOV", 1 ); - gmsgShowMenu = REG_USER_MSG( "ShowMenu", -1 ); - gmsgShake = REG_USER_MSG("ScreenShake", sizeof(ScreenShake)); - gmsgFade = REG_USER_MSG("ScreenFade", sizeof(ScreenFade)); - gmsgAmmoX = REG_USER_MSG("AmmoX", 2); + // Make sure any necessary user messages have been registered + LinkUserMessages(); m_iUpdateTime = 5; // won't update for 1/2 a second @@ -3286,7 +3157,7 @@ int CBasePlayer::Restore( CRestore &restore ) if ( FBitSet(pev->flags, FL_DUCKING) ) { // Use the crouch HACK - FixPlayerCrouchStuck( edict() ); + // FixPlayerCrouchStuck( edict() ); UTIL_SetSize(pev, VEC_DUCK_HULL_MIN, VEC_DUCK_HULL_MAX); } else @@ -4068,7 +3939,11 @@ Called every frame by the player PreThink */ void CBasePlayer::ItemPreFrame() { +#if defined( CLIENT_WEAPONS ) + if ( m_flNextAttack > 0 ) +#else if ( gpGlobals->time < m_flNextAttack ) +#endif { return; } @@ -4095,8 +3970,14 @@ void CBasePlayer::ItemPostFrame() if ( m_pTank != NULL ) return; + #if defined( CLIENT_WEAPONS ) + if ( m_flNextAttack > 0 ) +#else if ( gpGlobals->time < m_flNextAttack ) +#endif + { return; + } ImpulseCommands(); diff --git a/dlls/player.h b/dlls/player.h index 037ec55..0cbf4ad 100644 --- a/dlls/player.h +++ b/dlls/player.h @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, Valve LLC. All rights reserved. +* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. * * This product contains software technology licensed from Id * Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. @@ -71,6 +71,8 @@ typedef enum class CBasePlayer : public CBaseMonster { public: + int random_seed; // See that is shared between client & server for shared weapons code + int m_iPlayerSound;// the index of the sound list slot reserved for this player int m_iTargetVolume;// ideal sound volume. int m_iWeaponVolume;// how loud the player's weapon is right now. @@ -247,7 +249,6 @@ public: void SendAmmoUpdate(void); void WaterMove( void ); - void CheckWaterJump( void ); void EXPORT PlayerDeathThink( void ); void PlayerUse( void ); diff --git a/dlls/python.cpp b/dlls/python.cpp index 1439c40..5cc0af3 100644 --- a/dlls/python.cpp +++ b/dlls/python.cpp @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, Valve LLC. All rights reserved. +* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. * * This product contains software technology licensed from Id * Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. @@ -45,12 +45,15 @@ public: void PrimaryAttack( void ); void SecondaryAttack( void ); BOOL Deploy( void ); - void Holster( void ); + void Holster( int skiplocal = 0 ); void Reload( void ); void WeaponIdle( void ); float m_flSoundDelay; BOOL m_fInZoom;// don't save this. + +private: + unsigned short m_usFirePython; }; LINK_ENTITY_TO_CLASS( weapon_python, CPython ); LINK_ENTITY_TO_CLASS( weapon_357, CPython ); @@ -110,6 +113,8 @@ void CPython::Precache( void ) PRECACHE_SOUND ("weapons/357_cock1.wav"); PRECACHE_SOUND ("weapons/357_shot1.wav"); PRECACHE_SOUND ("weapons/357_shot2.wav"); + + m_usFirePython = PRECACHE_EVENT( 1, "events/python.sc" ); } BOOL CPython::Deploy( ) @@ -128,7 +133,7 @@ BOOL CPython::Deploy( ) } -void CPython::Holster( ) +void CPython::Holster( int skiplocal /* = 0 */ ) { m_fInReload = FALSE;// cancel any reload in progress. @@ -137,7 +142,7 @@ void CPython::Holster( ) SecondaryAttack(); } - m_pPlayer->m_flNextAttack = gpGlobals->time + 1.0; + m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 1.0; m_flTimeWeaponIdle = gpGlobals->time + 10 + RANDOM_FLOAT ( 0, 5 ); SendWeaponAnim( PYTHON_HOLSTER ); } @@ -179,52 +184,25 @@ void CPython::PrimaryAttack() Reload( ); else { - // if (m_iClip == 0) - //PlayEmptySound( ); - EMIT_SOUND(ENT(m_pPlayer->pev), CHAN_WEAPON, "weapons/357_cock1.wav", 0.8, ATTN_NORM); m_flNextPrimaryAttack = gpGlobals->time + 0.15; } return; } -/* - if (m_iClip <= 0) - { - Reload( ); - if (m_iClip == 0) - PlayEmptySound( ); - return; - } -*/ + + PLAYBACK_EVENT( 0, m_pPlayer->edict(), m_usFirePython ); + m_pPlayer->m_iWeaponVolume = LOUD_GUN_VOLUME; m_pPlayer->m_iWeaponFlash = BRIGHT_GUN_FLASH; m_iClip--; -/* - if (m_iClip || m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] == 0) -*/ - SendWeaponAnim( PYTHON_FIRE1 ); + // player "shoot" animation + m_pPlayer->SetAnimation( PLAYER_ATTACK1 ); - // player "shoot" animation - m_pPlayer->SetAnimation( PLAYER_ATTACK1 ); -/* - else - Reload( ); -*/ m_pPlayer->pev->effects = (int)(m_pPlayer->pev->effects) | EF_MUZZLEFLASH; - switch(RANDOM_LONG(0,1)) - { - case 0: - EMIT_SOUND(ENT(m_pPlayer->pev), CHAN_WEAPON, "weapons/357_shot1.wav", RANDOM_FLOAT(0.8, 0.9), ATTN_NORM); - break; - case 1: - EMIT_SOUND(ENT(m_pPlayer->pev), CHAN_WEAPON, "weapons/357_shot2.wav", RANDOM_FLOAT(0.8, 0.9), ATTN_NORM); - break; - } - UTIL_MakeVectors( m_pPlayer->pev->v_angle + m_pPlayer->pev->punchangle ); Vector vecSrc = m_pPlayer->GetGunPosition( ); @@ -238,7 +216,6 @@ void CPython::PrimaryAttack() m_flNextPrimaryAttack = gpGlobals->time + 0.75; m_flTimeWeaponIdle = gpGlobals->time + RANDOM_FLOAT ( 10, 15 ); - m_pPlayer->pev->punchangle.x -= 10; } @@ -268,15 +245,6 @@ void CPython::WeaponIdle( void ) { EMIT_SOUND(ENT(m_pPlayer->pev), CHAN_WEAPON, "weapons/357_reload1.wav", RANDOM_FLOAT(0.8, 0.9), ATTN_NORM); m_flSoundDelay = 0; - - /* - for (int i = 0; i < 6; i++) - { - EjectBrass ( m_pPlayer->pev->origin, - Vector( RANDOM_FLOAT( -10.0, 10.0 ), RANDOM_FLOAT( -10.0, 10.0 ), (float)0.0 ), - m_pPlayer->pev->angles.y, TE_BOUNCE_SHELL); - } - */ } if (m_flTimeWeaponIdle > gpGlobals->time) diff --git a/dlls/rpg.cpp b/dlls/rpg.cpp index 605dc08..815df82 100644 --- a/dlls/rpg.cpp +++ b/dlls/rpg.cpp @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, Valve LLC. All rights reserved. +* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. * * This product contains software technology licensed from Id * Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. @@ -70,7 +70,7 @@ public: BOOL Deploy( void ); BOOL CanHolster( void ); - void Holster( void ); + void Holster( int skiplocal = 0 ); void PrimaryAttack( void ); void SecondaryAttack( void ); @@ -511,11 +511,11 @@ BOOL CRpg::CanHolster( void ) return TRUE; } -void CRpg::Holster( ) +void CRpg::Holster( int skiplocal /* = 0 */ ) { m_fInReload = FALSE;// cancel any reload in progress. - m_pPlayer->m_flNextAttack = gpGlobals->time + 0.5; + m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 0.5; // m_flTimeWeaponIdle = gpGlobals->time + RANDOM_FLOAT ( 10, 15 ); SendWeaponAnim( RPG_HOLSTER1 ); if (m_pSpot) diff --git a/dlls/satchel.cpp b/dlls/satchel.cpp index 18fdbe3..ab34ca7 100644 --- a/dlls/satchel.cpp +++ b/dlls/satchel.cpp @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, Valve LLC. All rights reserved. +* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. * * This product contains software technology licensed from Id * Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. @@ -186,7 +186,7 @@ public: BOOL Deploy( void ); BOOL IsUseable( void ); - void Holster( void ); + void Holster( int skiplocal = 0 ); void WeaponIdle( void ); void Throw( void ); int m_chargeReady; @@ -332,15 +332,15 @@ BOOL CSatchel::Deploy( ) strcpy( m_pPlayer->m_szAnimExtention, "trip" ); } - m_pPlayer->m_flNextAttack = gpGlobals->time + 1.0; + m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 1.0; m_flTimeWeaponIdle = gpGlobals->time + RANDOM_FLOAT ( 10, 15 ); return TRUE; } -void CSatchel::Holster( ) +void CSatchel::Holster( int skiplocal /* = 0 */ ) { - m_pPlayer->m_flNextAttack = gpGlobals->time + 0.5; + m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 0.5; if (m_chargeReady) { diff --git a/dlls/saverestore.h b/dlls/saverestore.h index a0aaf54..4b5b1ef 100644 --- a/dlls/saverestore.h +++ b/dlls/saverestore.h @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, Valve LLC. All rights reserved. +* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. * * This product contains software technology licensed from Id * Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. diff --git a/dlls/schedule.h b/dlls/schedule.h index 10f36ad..45e7ffc 100644 --- a/dlls/schedule.h +++ b/dlls/schedule.h @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, Valve LLC. All rights reserved. +* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. * * This product contains software technology licensed from Id * Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. diff --git a/dlls/scriptevent.h b/dlls/scriptevent.h index d660e4b..b3f5314 100644 --- a/dlls/scriptevent.h +++ b/dlls/scriptevent.h @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, Valve LLC. All rights reserved. +* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. * * This product contains software technology licensed from Id * Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. diff --git a/dlls/shotgun.cpp b/dlls/shotgun.cpp index b19816f..429b281 100644 --- a/dlls/shotgun.cpp +++ b/dlls/shotgun.cpp @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, Valve LLC. All rights reserved. +* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. * * This product contains software technology licensed from Id * Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. @@ -61,6 +61,9 @@ public: float m_flNextReload; int m_iShell; float m_flPumpTime; +private: + unsigned short m_usDoubleFire; + unsigned short m_usSingleFire; }; LINK_ENTITY_TO_CLASS( weapon_shotgun, CShotgun ); @@ -110,6 +113,9 @@ void CShotgun::Precache( void ) PRECACHE_SOUND ("weapons/357_cock1.wav"); // gun empty sound PRECACHE_SOUND ("weapons/scock1.wav"); // cock gun + + m_usSingleFire = PRECACHE_EVENT( 1, "events/shotgun1.sc" ); + m_usDoubleFire = PRECACHE_EVENT( 1, "events/shotgun2.sc" ); } int CShotgun::AddToPlayer( CBasePlayer *pPlayer ) @@ -168,29 +174,16 @@ void CShotgun::PrimaryAttack() return; } + PLAYBACK_EVENT( 0, m_pPlayer->edict(), m_usSingleFire ); + m_pPlayer->m_iWeaponVolume = LOUD_GUN_VOLUME; m_pPlayer->m_iWeaponFlash = NORMAL_GUN_FLASH; m_iClip--; - m_pPlayer->pev->effects = (int)(m_pPlayer->pev->effects) | EF_MUZZLEFLASH; - - SendWeaponAnim( SHOTGUN_FIRE ); // player "shoot" animation m_pPlayer->SetAnimation( PLAYER_ATTACK1 ); - UTIL_MakeVectors( m_pPlayer->pev->v_angle + m_pPlayer->pev->punchangle ); - - Vector vecShellVelocity = m_pPlayer->pev->velocity - + gpGlobals->v_right * RANDOM_FLOAT(50,70) - + gpGlobals->v_up * RANDOM_FLOAT(100,150) - + gpGlobals->v_forward * 25; - - EjectBrass ( m_pPlayer->pev->origin + m_pPlayer->pev->view_ofs + gpGlobals->v_up * -12 + gpGlobals->v_forward * 20 + gpGlobals->v_right * 4 , vecShellVelocity, pev->angles.y, m_iShell, TE_BOUNCE_SHOTSHELL); - - EMIT_SOUND_DYN(ENT(m_pPlayer->pev), CHAN_WEAPON, "weapons/sbarrel1.wav", RANDOM_FLOAT(0.95, 1.0), ATTN_NORM, 0, 93 + RANDOM_LONG(0,0x1f)); - - Vector vecSrc = m_pPlayer->GetGunPosition( ); Vector vecAiming = m_pPlayer->GetAutoaimVector( AUTOAIM_5DEGREES ); @@ -219,8 +212,6 @@ void CShotgun::PrimaryAttack() else m_flTimeWeaponIdle = 0.75; m_fInReload = 0; - - m_pPlayer->pev->punchangle.x -= 5; } @@ -241,33 +232,16 @@ void CShotgun::SecondaryAttack( void ) return; } + PLAYBACK_EVENT( 0, m_pPlayer->edict(), m_usDoubleFire ); + m_pPlayer->m_iWeaponVolume = LOUD_GUN_VOLUME; m_pPlayer->m_iWeaponFlash = NORMAL_GUN_FLASH; m_iClip -= 2; - m_pPlayer->pev->effects = (int)(m_pPlayer->pev->effects) | EF_MUZZLEFLASH; - - SendWeaponAnim( SHOTGUN_FIRE2 ); - // player "shoot" animation m_pPlayer->SetAnimation( PLAYER_ATTACK1 ); - UTIL_MakeVectors( m_pPlayer->pev->v_angle + m_pPlayer->pev->punchangle ); - - Vector vecShellVelocity = m_pPlayer->pev->velocity - + gpGlobals->v_right * RANDOM_FLOAT(50,70) - + gpGlobals->v_up * RANDOM_FLOAT(100,150) - + gpGlobals->v_forward * 25; - EjectBrass ( m_pPlayer->pev->origin + m_pPlayer->pev->view_ofs + gpGlobals->v_up * -12 + gpGlobals->v_forward * 20 + gpGlobals->v_right * 4 , vecShellVelocity, pev->angles.y, m_iShell, TE_BOUNCE_SHOTSHELL); - vecShellVelocity = m_pPlayer->pev->velocity - + gpGlobals->v_right * RANDOM_FLOAT(50,70) - + gpGlobals->v_up * RANDOM_FLOAT(100,150) - + gpGlobals->v_forward * 25; - EjectBrass ( m_pPlayer->pev->origin + m_pPlayer->pev->view_ofs + gpGlobals->v_up * -12 + gpGlobals->v_forward * 20 + gpGlobals->v_right * 4 , vecShellVelocity, pev->angles.y, m_iShell, TE_BOUNCE_SHOTSHELL); - - EMIT_SOUND_DYN(ENT(m_pPlayer->pev), CHAN_WEAPON, "weapons/dbarrel1.wav", RANDOM_FLOAT(0.98, 1.0), ATTN_NORM, 0, 85 + RANDOM_LONG(0,0x1f)); - Vector vecSrc = m_pPlayer->GetGunPosition( ); Vector vecAiming = m_pPlayer->GetAutoaimVector( AUTOAIM_5DEGREES ); @@ -298,8 +272,6 @@ void CShotgun::SecondaryAttack( void ) m_flTimeWeaponIdle = 1.5; m_fInReload = 0; - - m_pPlayer->pev->punchangle.x -= 10; } @@ -320,7 +292,7 @@ void CShotgun::Reload( void ) { SendWeaponAnim( SHOTGUN_START_RELOAD ); m_fInReload = 1; - m_pPlayer->m_flNextAttack = gpGlobals->time + 0.6; + m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 0.6; m_flTimeWeaponIdle = gpGlobals->time + 0.6; m_flNextPrimaryAttack = gpGlobals->time + 1.0; m_flNextSecondaryAttack = gpGlobals->time + 1.0; diff --git a/dlls/singleplay_gamerules.cpp b/dlls/singleplay_gamerules.cpp index 160757a..9adccdc 100644 --- a/dlls/singleplay_gamerules.cpp +++ b/dlls/singleplay_gamerules.cpp @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, Valve LLC. All rights reserved. +* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. * * This product contains software technology licensed from Id * Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. diff --git a/dlls/skill.cpp b/dlls/skill.cpp index 6718db5..71c7b1d 100644 --- a/dlls/skill.cpp +++ b/dlls/skill.cpp @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, Valve LLC. All rights reserved. +* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. * * This product contains software technology licensed from Id * Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. diff --git a/dlls/skill.h b/dlls/skill.h index 3b0cf9e..63ec8f7 100644 --- a/dlls/skill.h +++ b/dlls/skill.h @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, Valve LLC. All rights reserved. +* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. * * This product contains software technology licensed from Id * Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. diff --git a/dlls/sound.cpp b/dlls/sound.cpp index 32b4943..40c8475 100644 --- a/dlls/sound.cpp +++ b/dlls/sound.cpp @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, Valve LLC. All rights reserved. +* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. * * This product contains software technology licensed from Id * Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. diff --git a/dlls/soundent.cpp b/dlls/soundent.cpp index ff16d49..bd4fa81 100644 --- a/dlls/soundent.cpp +++ b/dlls/soundent.cpp @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, Valve LLC. All rights reserved. +* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. * * This product contains software technology licensed from Id * Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. diff --git a/dlls/soundent.h b/dlls/soundent.h index 9753aa3..5e03b6a 100644 --- a/dlls/soundent.h +++ b/dlls/soundent.h @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, Valve LLC. All rights reserved. +* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. * * This product contains software technology licensed from Id * Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. diff --git a/dlls/spectator.cpp b/dlls/spectator.cpp index 28002eb..a794d3d 100644 --- a/dlls/spectator.cpp +++ b/dlls/spectator.cpp @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, Valve LLC. All rights reserved. +* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. * * This product contains software technology licensed from Id * Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. diff --git a/dlls/spectator.h b/dlls/spectator.h index f4c4ef3..aa2e73e 100644 --- a/dlls/spectator.h +++ b/dlls/spectator.h @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, Valve LLC. All rights reserved. +* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. * * This product contains software technology licensed from Id * Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. diff --git a/dlls/squeakgrenade.cpp b/dlls/squeakgrenade.cpp index 657a746..c035a24 100644 --- a/dlls/squeakgrenade.cpp +++ b/dlls/squeakgrenade.cpp @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, Valve LLC. All rights reserved. +* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. * * This product contains software technology licensed from Id * Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. @@ -338,7 +338,7 @@ void CSqueakGrenade::SuperBounceTouch( CBaseEntity *pOther ) // higher pitch as squeeker gets closer to detonation time flpitch = 155.0 - 60.0 * ((m_flDie - gpGlobals->time) / SQUEEK_DETONATE_DELAY); - if ( pOther->pev->takedamage && m_flNextAttack < gpGlobals->time) + if ( pOther->pev->takedamage && m_flNextAttack < gpGlobals->time ) { // attack! @@ -418,7 +418,7 @@ public: void PrimaryAttack( void ); void SecondaryAttack( void ); BOOL Deploy( void ); - void Holster( void ); + void Holster( int skiplocal = 0 ); void WeaponIdle( void ); int m_fJustThrown; }; @@ -487,7 +487,7 @@ BOOL CSqueak::Deploy( ) } -void CSqueak::Holster( ) +void CSqueak::Holster( int skiplocal /* = 0 */ ) { m_pPlayer->m_flNextAttack = gpGlobals->time + 0.5; @@ -510,9 +510,18 @@ void CSqueak::PrimaryAttack() { UTIL_MakeVectors( m_pPlayer->pev->v_angle ); TraceResult tr; + Vector trace_origin; + + // HACK HACK: Ugly hacks to handle change in origin based on new physics code for players + // Move origin up if crouched and start trace a bit outside of body ( 20 units instead of 16 ) + trace_origin = m_pPlayer->pev->origin; + if ( m_pPlayer->pev->flags & FL_DUCKING ) + { + trace_origin = trace_origin - ( VEC_HULL_MIN - VEC_DUCK_HULL_MIN ); + } // find place to toss monster - UTIL_TraceLine( m_pPlayer->pev->origin + gpGlobals->v_forward * 16, m_pPlayer->pev->origin + gpGlobals->v_forward * 64, dont_ignore_monsters, NULL, &tr ); + UTIL_TraceLine( trace_origin + gpGlobals->v_forward * 20, trace_origin + gpGlobals->v_forward * 64, dont_ignore_monsters, NULL, &tr ); if (tr.fAllSolid == 0 && tr.fStartSolid == 0 && tr.flFraction > 0.25) { diff --git a/dlls/subs.cpp b/dlls/subs.cpp index 87c024a..a068c95 100644 --- a/dlls/subs.cpp +++ b/dlls/subs.cpp @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, Valve LLC. All rights reserved. +* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. * * This product contains software technology licensed from Id * Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. diff --git a/dlls/talkmonster.h b/dlls/talkmonster.h index 01ebedd..cf4b324 100644 --- a/dlls/talkmonster.h +++ b/dlls/talkmonster.h @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, Valve LLC. All rights reserved. +* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. * * This product contains software technology licensed from Id * Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. diff --git a/dlls/teamplay_gamerules.cpp b/dlls/teamplay_gamerules.cpp index d648a15..8eae4a4 100644 --- a/dlls/teamplay_gamerules.cpp +++ b/dlls/teamplay_gamerules.cpp @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, Valve LLC. All rights reserved. +* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. * * This product contains software technology licensed from Id * Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. @@ -66,9 +66,16 @@ CHalfLifeTeamplay :: CHalfLifeTeamplay() RecountTeams(); } +extern cvar_t timeleft, fragsleft; + void CHalfLifeTeamplay :: Think ( void ) { ///// Check game rules ///// + static int last_frags; + static int last_time; + + int frags_remaining = 0; + int time_remaining = 0; if ( g_fGameOver ) // someone else quit the game already { @@ -78,6 +85,8 @@ void CHalfLifeTeamplay :: Think ( void ) float flTimeLimit = CVAR_GET_FLOAT("mp_timelimit") * 60; + time_remaining = (int)(flTimeLimit ? ( flTimeLimit - gpGlobals->time ) : 0); + if ( flTimeLimit != 0 && gpGlobals->time >= flTimeLimit ) { GoToIntermission(); @@ -87,6 +96,9 @@ void CHalfLifeTeamplay :: Think ( void ) float flFragLimit = fraglimit.value; if ( flFragLimit ) { + int bestfrags = 9999; + int remain; + // check if any team is over the frag limit for ( int i = 0; i < num_teams; i++ ) { @@ -95,8 +107,30 @@ void CHalfLifeTeamplay :: Think ( void ) GoToIntermission(); return; } + + remain = flFragLimit - team_scores[i]; + if ( remain < bestfrags ) + { + bestfrags = remain; + } } + frags_remaining = bestfrags; } + + // Updates when frags change + if ( frags_remaining != last_frags ) + { + g_engfuncs.pfnCvar_DirectSet( &fragsleft, UTIL_VarArgs( "%i", frags_remaining ) ); + } + + // Updates once per second + if ( timeleft.value != last_time ) + { + g_engfuncs.pfnCvar_DirectSet( &timeleft, UTIL_VarArgs( "%i", time_remaining ) ); + } + + last_frags = frags_remaining; + last_time = time_remaining; } //========================================================= diff --git a/dlls/teamplay_gamerules.h b/dlls/teamplay_gamerules.h index 54bf402..05632e4 100644 --- a/dlls/teamplay_gamerules.h +++ b/dlls/teamplay_gamerules.h @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, Valve LLC. All rights reserved. +* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. * * This product contains software technology licensed from Id * Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. diff --git a/dlls/trains.h b/dlls/trains.h index 449e852..d7ee1a3 100644 --- a/dlls/trains.h +++ b/dlls/trains.h @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, Valve LLC. All rights reserved. +* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. * * This product contains software technology licensed from Id * Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. @@ -119,6 +119,9 @@ public: float m_flVolume; float m_flBank; float m_oldSpeed; + +private: + unsigned short m_usAdjustPitch; }; #endif diff --git a/dlls/triggers.cpp b/dlls/triggers.cpp index f66f692..9af5b68 100644 --- a/dlls/triggers.cpp +++ b/dlls/triggers.cpp @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, Valve LLC. All rights reserved. +* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. * * This product contains software technology licensed from Id * Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. @@ -1991,7 +1991,7 @@ LINK_ENTITY_TO_CLASS( trigger_endsection, CTriggerEndSection ); void CTriggerEndSection::EndSectionUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) { // Only save on clients - if ( !pActivator->IsNetClient() ) + if ( pActivator && !pActivator->IsNetClient() ) return; SetUse( NULL ); diff --git a/dlls/tripmine.cpp b/dlls/tripmine.cpp index 8ffa2ae..4134976 100644 --- a/dlls/tripmine.cpp +++ b/dlls/tripmine.cpp @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, Valve LLC. All rights reserved. +* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. * * This product contains software technology licensed from Id * Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. @@ -366,7 +366,7 @@ public: void PrimaryAttack( void ); BOOL Deploy( void ); - void Holster( void ); + void Holster( int skiplocal = 0 ); void WeaponIdle( void ); }; LINK_ENTITY_TO_CLASS( weapon_tripmine, CTripmine ); @@ -424,9 +424,9 @@ BOOL CTripmine::Deploy( ) } -void CTripmine::Holster( ) +void CTripmine::Holster( int skiplocal /* = 0 */ ) { - m_pPlayer->m_flNextAttack = gpGlobals->time + 0.5; + m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 0.5; if (!m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType]) { diff --git a/dlls/util.cpp b/dlls/util.cpp index a15016d..2a79212 100644 --- a/dlls/util.cpp +++ b/dlls/util.cpp @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, Valve LLC. All rights reserved. +* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. * * This product contains software technology licensed from Id * Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. @@ -31,6 +31,179 @@ #include "weapons.h" #include "gamerules.h" +/* +===================== +UTIL_WeaponTimeBase + +Time basis for weapons ( zero based of predicting client weapons ) +===================== +*/ +float UTIL_WeaponTimeBase( void ) +{ +#if defined( CLIENT_WEAPONS ) + return 0.0; +#else + return gpGlobals->time; +#endif +} + +static unsigned int glSeed = 0; + +unsigned int seed_table[ 256 ] = +{ + 28985, 27138, 26457, 9451, 17764, 10909, 28790, 8716, 6361, 4853, 17798, 21977, 19643, 20662, 10834, 20103, + 27067, 28634, 18623, 25849, 8576, 26234, 23887, 18228, 32587, 4836, 3306, 1811, 3035, 24559, 18399, 315, + 26766, 907, 24102, 12370, 9674, 2972, 10472, 16492, 22683, 11529, 27968, 30406, 13213, 2319, 23620, 16823, + 10013, 23772, 21567, 1251, 19579, 20313, 18241, 30130, 8402, 20807, 27354, 7169, 21211, 17293, 5410, 19223, + 10255, 22480, 27388, 9946, 15628, 24389, 17308, 2370, 9530, 31683, 25927, 23567, 11694, 26397, 32602, 15031, + 18255, 17582, 1422, 28835, 23607, 12597, 20602, 10138, 5212, 1252, 10074, 23166, 19823, 31667, 5902, 24630, + 18948, 14330, 14950, 8939, 23540, 21311, 22428, 22391, 3583, 29004, 30498, 18714, 4278, 2437, 22430, 3439, + 28313, 23161, 25396, 13471, 19324, 15287, 2563, 18901, 13103, 16867, 9714, 14322, 15197, 26889, 19372, 26241, + 31925, 14640, 11497, 8941, 10056, 6451, 28656, 10737, 13874, 17356, 8281, 25937, 1661, 4850, 7448, 12744, + 21826, 5477, 10167, 16705, 26897, 8839, 30947, 27978, 27283, 24685, 32298, 3525, 12398, 28726, 9475, 10208, + 617, 13467, 22287, 2376, 6097, 26312, 2974, 9114, 21787, 28010, 4725, 15387, 3274, 10762, 31695, 17320, + 18324, 12441, 16801, 27376, 22464, 7500, 5666, 18144, 15314, 31914, 31627, 6495, 5226, 31203, 2331, 4668, + 12650, 18275, 351, 7268, 31319, 30119, 7600, 2905, 13826, 11343, 13053, 15583, 30055, 31093, 5067, 761, + 9685, 11070, 21369, 27155, 3663, 26542, 20169, 12161, 15411, 30401, 7580, 31784, 8985, 29367, 20989, 14203, + 29694, 21167, 10337, 1706, 28578, 887, 3373, 19477, 14382, 675, 7033, 15111, 26138, 12252, 30996, 21409, + 25678, 18555, 13256, 23316, 22407, 16727, 991, 9236, 5373, 29402, 6117, 15241, 27715, 19291, 19888, 19847 +}; + +unsigned int U_Random( void ) +{ + glSeed *= 69069; + glSeed += seed_table[ glSeed & 0xff ]; + + return ( ++glSeed & 0x0fffffff ); +} + +void U_Srand( unsigned int seed ) +{ + glSeed = seed_table[ seed & 0xff ]; +} + +/* +===================== +UTIL_SharedRandomLong +===================== +*/ +int UTIL_SharedRandomLong( unsigned int seed, int low, int high ) +{ + + unsigned int range; + + U_Srand( (int)seed + low + high ); + + range = high - low + 1; + if ( !(range - 1) ) + { + return low; + } + else + { + int offset; + int rnum; + + rnum = U_Random(); + + offset = rnum % range; + + return (low + offset); + } +} + +/* +===================== +UTIL_SharedRandomFloat +===================== +*/ +float UTIL_SharedRandomFloat( unsigned int seed, float low, float high ) +{ + // + unsigned int range; + + U_Srand( (int)seed + *(int *)&low + *(int *)&high ); + + U_Random(); + U_Random(); + + range = high - low; + if ( !range ) + { + return low; + } + else + { + int tensixrand; + float offset; + + tensixrand = U_Random() & 65535; + + offset = (float)tensixrand / 65536.0; + + return (low + offset * range ); + } +} + +void UTIL_ParametricRocket( entvars_t *pev, Vector vecOrigin, Vector vecAngles, edict_t *owner ) +{ + pev->startpos = vecOrigin; + // Trace out line to end pos + TraceResult tr; + UTIL_MakeVectors( vecAngles ); + UTIL_TraceLine( pev->startpos, pev->startpos + gpGlobals->v_forward * 8192, ignore_monsters, owner, &tr); + pev->endpos = tr.vecEndPos; + + // Now compute how long it will take based on current velocity + Vector vecTravel = pev->endpos - pev->startpos; + float travelTime = 0.0; + if ( pev->velocity.Length() > 0 ) + { + travelTime = vecTravel.Length() / pev->velocity.Length(); + } + pev->starttime = gpGlobals->time; + pev->impacttime = gpGlobals->time + travelTime; +} + +int g_groupmask = 0; +int g_groupop = 0; + +// Normal overrides +void UTIL_SetGroupTrace( int groupmask, int op ) +{ + g_groupmask = groupmask; + g_groupop = op; + + ENGINE_SETGROUPMASK( g_groupmask, g_groupop ); +} + +void UTIL_UnsetGroupTrace( void ) +{ + g_groupmask = 0; + g_groupop = 0; + + ENGINE_SETGROUPMASK( 0, 0 ); +} + +// Smart version, it'll clean itself up when it pops off stack +UTIL_GroupTrace::UTIL_GroupTrace( int groupmask, int op ) +{ + m_oldgroupmask = g_groupmask; + m_oldgroupop = g_groupop; + + g_groupmask = groupmask; + g_groupop = op; + + ENGINE_SETGROUPMASK( g_groupmask, g_groupop ); +} + +UTIL_GroupTrace::~UTIL_GroupTrace( void ) +{ + g_groupmask = m_oldgroupmask; + g_groupop = m_oldgroupop; + + ENGINE_SETGROUPMASK( g_groupmask, g_groupop ); +} TYPEDESCRIPTION gEntvarsDescription[] = { @@ -181,6 +354,11 @@ DBG_AssertFunction( } #endif // DEBUG +BOOL UTIL_GetNextBestWeapon( CBasePlayer *pPlayer, CBasePlayerItem *pCurrentWeapon ) +{ + return g_pGameRules->GetNextBestWeapon( pPlayer, pCurrentWeapon ); +} + // ripped this out of the engine float UTIL_AngleMod(float a) { @@ -1594,6 +1772,27 @@ void CSaveRestoreBuffer :: BufferRewind( int size ) m_pdata->size -= size; } +#ifndef _WIN32 +extern "C" { + unsigned _rotr ( unsigned val, int shift) { + register unsigned lobit; /* non-zero means lo bit set */ + register unsigned num = val; /* number to rotate */ + + shift &= 0x1f; /* modulo 32 -- this will also make + negative shifts work */ + + while (shift--) { + lobit = num & 1; /* get high bit */ + num >>= 1; /* shift right one bit */ + if (lobit) + num |= 0x80000000; /* set hi bit if lo bit was set */ + } + + return num; + } +} +#endif + unsigned int CSaveRestoreBuffer :: HashString( const char *pszToken ) { unsigned int hash = 0; diff --git a/dlls/util.h b/dlls/util.h index 065068f..ee07d0a 100644 --- a/dlls/util.h +++ b/dlls/util.h @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, Valve LLC. All rights reserved. +* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. * * This product contains software technology licensed from Id * Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. @@ -87,7 +87,7 @@ typedef int BOOL; // The _declspec forces them to be exported by name so we can do a lookup with GetProcAddress() // The function is used to intialize / allocate the object for the entity #define LINK_ENTITY_TO_CLASS(mapClassName,DLLClassName) \ - extern "C" _declspec( dllexport ) void mapClassName( entvars_t *pev ); \ + extern "C" EXPORT void mapClassName( entvars_t *pev ); \ void mapClassName( entvars_t *pev ) { GetClassPtr( (DLLClassName *)pev ); } @@ -291,6 +291,10 @@ inline void UTIL_CenterPrintAll( const char *msg_name, const char *param1 = NU UTIL_ClientPrintAll( HUD_PRINTCENTER, msg_name, param1, param2, param3, param4 ); } +class CBasePlayerItem; +class CBasePlayer; +extern BOOL UTIL_GetNextBestWeapon( CBasePlayer *pPlayer, CBasePlayerItem *pCurrentWeapon ); + // prints messages through the HUD extern void ClientPrint( entvars_t *client, int msg_dest, const char *msg_name, const char *param1 = NULL, const char *param2 = NULL, const char *param3 = NULL, const char *param4 = NULL ); @@ -407,21 +411,15 @@ extern DLL_GLOBAL int g_Language; #define VEC_VIEW Vector( 0, 0, 28 ) -#define VEC_DUCK_HULL_MIN Vector(-16, -16, -18 ) -#define VEC_DUCK_HULL_MAX Vector( 16, 16, 18) -#define VEC_DUCK_VIEW Vector( 0, 0, 12 ) +#define VEC_DUCK_HULL_MIN Vector(-16, -16, -18 ) +#define VEC_DUCK_HULL_MAX Vector( 16, 16, 18) +#define VEC_DUCK_VIEW Vector( 0, 0, 12 ) #define SVC_TEMPENTITY 23 #define SVC_INTERMISSION 30 #define SVC_CDTRACK 32 #define SVC_WEAPONANIM 35 #define SVC_ROOMTYPE 37 -#define SVC_ADDANGLE 38 // [vec3] add this angle to the view angle -#define SVC_NEWUSERMSG 39 -#define SVC_CROSSHAIRANGLE 50 -#define SVC_SOUNDFADE 51 -#define SVC_CLIENTMAXSPEED 52 - // triggers #define SF_TRIGGER_ALLOWMONSTERS 1// monsters allowed to fire this trigger @@ -522,3 +520,31 @@ void EMIT_GROUPNAME_SUIT(edict_t *entity, const char *groupname); EMIT_SOUND_DYN ( ENT(pev), chan , array [ RANDOM_LONG(0,ARRAYSIZE( array )-1) ], 1.0, ATTN_NORM, 0, RANDOM_LONG(95,105) ); #define RANDOM_SOUND_ARRAY( array ) (array) [ RANDOM_LONG(0,ARRAYSIZE( (array) )-1) ] + + +#define PLAYBACK_EVENT( flags, who, index ) PLAYBACK_EVENT_FULL( flags, who, index, 0, (float *)&g_vecZero, (float *)&g_vecZero, 0.0, 0.0, 0, 0, 0, 0 ); +#define PLAYBACK_EVENT_DELAY( flags, who, index, delay ) PLAYBACK_EVENT_FULL( flags, who, index, delay, (float *)&g_vecZero, (float *)&g_vecZero, 0.0, 0.0, 0, 0, 0, 0 ); + +#define GROUP_OP_AND 0 +#define GROUP_OP_NAND 1 + +extern int g_groupmask; +extern int g_groupop; + +class UTIL_GroupTrace +{ +public: + UTIL_GroupTrace( int groupmask, int op ); + ~UTIL_GroupTrace( void ); + +private: + int m_oldgroupmask, m_oldgroupop; +}; + +void UTIL_SetGroupTrace( int groupmask, int op ); +void UTIL_UnsetGroupTrace( void ); + +int UTIL_SharedRandomLong( unsigned int seed, int low, int high ); +float UTIL_SharedRandomFloat( unsigned int seed, float low, float high ); + +float UTIL_WeaponTimeBase( void ); diff --git a/dlls/vector.h b/dlls/vector.h index 282e3b9..3a10197 100644 --- a/dlls/vector.h +++ b/dlls/vector.h @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, Valve LLC. All rights reserved. +* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. * * This product contains software technology licensed from Id * Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. diff --git a/dlls/weapons.cpp b/dlls/weapons.cpp index a6f2db1..a6aa07d 100644 --- a/dlls/weapons.cpp +++ b/dlls/weapons.cpp @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, Valve LLC. All rights reserved. +* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. * * This product contains software technology licensed from Id * Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. @@ -618,9 +618,25 @@ void CBasePlayerItem::DefaultTouch( CBaseEntity *pOther ) SUB_UseTargets( pOther, USE_TOGGLE, 0 ); // UNDONE: when should this happen? } +BOOL CanAttack( float attack_time, float curtime, BOOL isPredicted ) +{ +#if defined( CLIENT_WEAPONS ) + if ( !isPredicted ) +#else + if ( 1 ) +#endif + { + return ( attack_time <= curtime ) ? TRUE : FALSE; + } + else + { + return ( attack_time <= 0.0 ) ? TRUE : FALSE; + } +} + void CBasePlayerWeapon::ItemPostFrame( void ) { - if ((m_fInReload) && (m_pPlayer->m_flNextAttack <= gpGlobals->time)) + if ((m_fInReload) && ( m_pPlayer->m_flNextAttack <= UTIL_WeaponTimeBase() ) ) { // complete the reload. int j = min( iMaxClip() - m_iClip, m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType]); @@ -632,7 +648,7 @@ void CBasePlayerWeapon::ItemPostFrame( void ) m_fInReload = FALSE; } - if ((m_pPlayer->pev->button & IN_ATTACK2) && (m_flNextSecondaryAttack <= gpGlobals->time)) + if ((m_pPlayer->pev->button & IN_ATTACK2) && CanAttack( m_flNextSecondaryAttack, gpGlobals->time, UseDecrement() ) ) { if ( pszAmmo2() && !m_pPlayer->m_rgAmmo[SecondaryAmmoIndex()] ) { @@ -642,7 +658,7 @@ void CBasePlayerWeapon::ItemPostFrame( void ) SecondaryAttack(); m_pPlayer->pev->button &= ~IN_ATTACK2; } - else if ((m_pPlayer->pev->button & IN_ATTACK) && (m_flNextPrimaryAttack <= gpGlobals->time)) + else if ((m_pPlayer->pev->button & IN_ATTACK) && CanAttack( m_flNextPrimaryAttack, gpGlobals->time, UseDecrement() ) ) { if ( (m_iClip == 0 && pszAmmo1()) || (iMaxClip() == -1 && !m_pPlayer->m_rgAmmo[PrimaryAmmoIndex()] ) ) { @@ -662,19 +678,19 @@ void CBasePlayerWeapon::ItemPostFrame( void ) m_fFireOnEmpty = FALSE; - if ( !IsUseable() && m_flNextPrimaryAttack < gpGlobals->time ) + if ( !IsUseable() && m_flNextPrimaryAttack < ( UseDecrement() ? 0.0 : gpGlobals->time ) ) { // weapon isn't useable, switch. if ( !(iFlags() & ITEM_FLAG_NOAUTOSWITCHEMPTY) && g_pGameRules->GetNextBestWeapon( m_pPlayer, this ) ) { - m_flNextPrimaryAttack = gpGlobals->time + 0.3; + m_flNextPrimaryAttack = ( UseDecrement() ? 0.0 : gpGlobals->time ) + 0.3; return; } } else { // weapon is useable. Reload if empty and weapon has waited as long as it has to after firing - if ( m_iClip == 0 && !(iFlags() & ITEM_FLAG_NOAUTORELOAD) && m_flNextPrimaryAttack < gpGlobals->time ) + if ( m_iClip == 0 && !(iFlags() & ITEM_FLAG_NOAUTORELOAD) && m_flNextPrimaryAttack < ( UseDecrement() ? 0.0 : gpGlobals->time ) ) { Reload(); return; @@ -724,7 +740,7 @@ void CBasePlayerItem::Kill( void ) pev->nextthink = gpGlobals->time + .1; } -void CBasePlayerItem::Holster( void ) +void CBasePlayerItem::Holster( int skiplocal /* = 0 */ ) { m_pPlayer->pev->viewmodel = 0; m_pPlayer->pev->weaponmodel = 0; @@ -778,6 +794,7 @@ int CBasePlayerWeapon::AddToPlayer( CBasePlayer *pPlayer ) int CBasePlayerWeapon::UpdateClientData( CBasePlayer *pPlayer ) { + BOOL bSend = FALSE; int state = 0; if ( pPlayer->m_pActiveItem == this ) { @@ -787,7 +804,31 @@ int CBasePlayerWeapon::UpdateClientData( CBasePlayer *pPlayer ) state = 1; } - if ( !pPlayer->m_fWeapon || pPlayer->m_pActiveItem != pPlayer->m_pClientActiveItem || m_iClip != m_iClientClip || state != m_iClientWeaponState || pPlayer->m_iFOV != pPlayer->m_iClientFOV ) + // Forcing send of all data! + if ( !pPlayer->m_fWeapon ) + { + bSend = TRUE; + } + + // This is the current or last weapon, so the state will need to be updated + if ( this == pPlayer->m_pActiveItem || + this == pPlayer->m_pClientActiveItem ) + { + if ( pPlayer->m_pActiveItem != pPlayer->m_pClientActiveItem ) + { + bSend = TRUE; + } + } + + // If the ammo, state, or fov has changed, update the weapon + if ( m_iClip != m_iClientClip || + state != m_iClientWeaponState || + pPlayer->m_iFOV != pPlayer->m_iClientFOV ) + { + bSend = TRUE; + } + + if ( bSend ) { MESSAGE_BEGIN( MSG_ONE, gmsgCurWeapon, NULL, pPlayer->pev ); WRITE_BYTE( state ); @@ -807,8 +848,15 @@ int CBasePlayerWeapon::UpdateClientData( CBasePlayer *pPlayer ) } -void CBasePlayerWeapon::SendWeaponAnim( int iAnim ) +void CBasePlayerWeapon::SendWeaponAnim( int iAnim, int skiplocal ) { + m_pPlayer->pev->weaponanim = iAnim; + +#if defined( CLIENT_WEAPONS ) + if ( skiplocal && ENGINE_CANSKIP( m_pPlayer->edict() ) ) + return; +#endif + MESSAGE_BEGIN( MSG_ONE, SVC_WEAPONANIM, NULL, m_pPlayer->pev ); WRITE_BYTE( iAnim ); // sequence number WRITE_BYTE( pev->body ); // weaponmodel bodygroup. @@ -919,7 +967,7 @@ BOOL CBasePlayerWeapon :: CanDeploy( void ) return TRUE; } -BOOL CBasePlayerWeapon :: DefaultDeploy( char *szViewModel, char *szWeaponModel, int iAnim, char *szAnimExt ) +BOOL CBasePlayerWeapon :: DefaultDeploy( char *szViewModel, char *szWeaponModel, int iAnim, char *szAnimExt, int skiplocal /* = 0 */ ) { if (!CanDeploy( )) return FALSE; @@ -927,10 +975,10 @@ BOOL CBasePlayerWeapon :: DefaultDeploy( char *szViewModel, char *szWeaponModel, m_pPlayer->pev->viewmodel = MAKE_STRING(szViewModel); m_pPlayer->pev->weaponmodel = MAKE_STRING(szWeaponModel); strcpy( m_pPlayer->m_szAnimExtention, szAnimExt ); - SendWeaponAnim( iAnim ); + SendWeaponAnim( iAnim, skiplocal ); - m_pPlayer->m_flNextAttack = gpGlobals->time + 0.5; - m_flTimeWeaponIdle = gpGlobals->time + 1.0; + m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 0.5; + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 1.0; return TRUE; } @@ -946,14 +994,14 @@ BOOL CBasePlayerWeapon :: DefaultReload( int iClipSize, int iAnim, float fDelay if (j == 0) return FALSE; - m_pPlayer->m_flNextAttack = gpGlobals->time + fDelay; + m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + fDelay; //!!UNDONE -- reload sound goes here !!! - SendWeaponAnim( iAnim ); + SendWeaponAnim( iAnim, UseDecrement() ? 1 : 0 ); m_fInReload = TRUE; - m_flTimeWeaponIdle = gpGlobals->time + 3; + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 3; return TRUE; } @@ -987,7 +1035,7 @@ int CBasePlayerWeapon::SecondaryAmmoIndex( void ) return -1; } -void CBasePlayerWeapon::Holster( void ) +void CBasePlayerWeapon::Holster( int skiplocal /* = 0 */ ) { m_fInReload = FALSE; // cancel any reload in progress. m_pPlayer->pev->viewmodel = 0; @@ -1443,4 +1491,6 @@ void CWeaponBox::SetObjectCollisionBox( void ) pev->absmax = pev->origin + Vector(16, 16, 16); } - +void CBasePlayerWeapon::PrintState( void ) +{ +} diff --git a/dlls/weapons.h b/dlls/weapons.h index 0d09c23..ae30d1b 100644 --- a/dlls/weapons.h +++ b/dlls/weapons.h @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, Valve LLC. All rights reserved. +* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. * * This product contains software technology licensed from Id * Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. @@ -241,7 +241,7 @@ public: { return TRUE; }; virtual BOOL CanHolster( void ) { return TRUE; };// can this weapon be put away right now? - virtual void Holster( ); + virtual void Holster( int skiplocal = 0 ); virtual void UpdateItemInfo( void ) { return; }; virtual void ItemPreFrame( void ) { return; } // called each frame by the player PreThink @@ -256,6 +256,8 @@ public: virtual int UpdateClientData( CBasePlayer *pPlayer ) { return 0; } + virtual CBasePlayerItem *GetWeaponPtr( void ) { return NULL; }; + static ItemInfo ItemInfoArray[ MAX_WEAPONS ]; static AmmoInfo AmmoInfoArray[ MAX_AMMO_SLOTS ]; @@ -310,11 +312,11 @@ public: virtual BOOL PlayEmptySound( void ); virtual void ResetEmptySound( void ); - virtual void SendWeaponAnim( int iAnim ); + virtual void SendWeaponAnim( int iAnim, int skiplocal = 0 ); // skiplocal is 1 if client is predicting weapon animations virtual BOOL CanDeploy( void ); virtual BOOL IsUseable( void ); - BOOL DefaultDeploy( char *szViewModel, char *szWeaponModel, int iAnim, char *szAnimExt ); + BOOL DefaultDeploy( char *szViewModel, char *szWeaponModel, int iAnim, char *szAnimExt, int skiplocal = 0 ); int DefaultReload( int iClipSize, int iAnim, float fDelay ); virtual void ItemPostFrame( void ); // called each frame by the player PostThink @@ -326,11 +328,16 @@ public: virtual int UpdateClientData( CBasePlayer *pPlayer ); // sends hud info to client dll, if things have changed virtual void RetireWeapon( void ); virtual BOOL ShouldWeaponIdle( void ) {return FALSE; }; - virtual void Holster( void ); - + virtual void Holster( int skiplocal = 0 ); + virtual BOOL UseDecrement( void ) { return FALSE; }; + int PrimaryAmmoIndex(); int SecondaryAmmoIndex(); + void PrintState( void ); + + virtual CBasePlayerItem *GetWeaponPtr( void ) { return (CBasePlayerItem *)this; }; + float m_flNextPrimaryAttack; // soonest time ItemPostFrame will call PrimaryAttack float m_flNextSecondaryAttack; // soonest time ItemPostFrame will call SecondaryAttack float m_flTimeWeaponIdle; // soonest time ItemPostFrame will call WeaponIdle @@ -446,5 +453,36 @@ public: int m_cAmmoTypes;// how many ammo types packed into this box (if packed by a level designer) }; +class CGlock : public CBasePlayerWeapon +{ +public: + void Spawn( void ); + void Precache( void ); + int iItemSlot( void ) { return 2; } + int GetItemInfo(ItemInfo *p); + + void PrimaryAttack( void ); + void SecondaryAttack( void ); + void GlockFire( float flSpread, float flCycleTime, BOOL fUseAutoAim ); + BOOL Deploy( void ); + void Reload( void ); + void WeaponIdle( void ); + + virtual BOOL UseDecrement( void ) + { +#if defined( CLIENT_WEAPONS ) + return TRUE; +#else + return FALSE; +#endif + } + +private: + int m_iShell; + + + unsigned short m_usFireGlock1; + unsigned short m_usFireGlock2; +}; #endif // WEAPONS_H diff --git a/dlls/world.cpp b/dlls/world.cpp index 92ddb1d..d91670e 100644 --- a/dlls/world.cpp +++ b/dlls/world.cpp @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, Valve LLC. All rights reserved. +* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. * * This product contains software technology licensed from Id * Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. @@ -549,6 +549,11 @@ void CWorld :: Precache( void ) PRECACHE_MODEL( "models/agibs.mdl" ); } + PRECACHE_SOUND ("weapons/ric1.wav"); + PRECACHE_SOUND ("weapons/ric2.wav"); + PRECACHE_SOUND ("weapons/ric3.wav"); + PRECACHE_SOUND ("weapons/ric4.wav"); + PRECACHE_SOUND ("weapons/ric5.wav"); // // Setup light animation tables. 'a' is total darkness, 'z' is maxbright. // diff --git a/dlls/glock.cpp b/dlls/wpn_shared/hl_wpn_glock.cpp similarity index 77% rename from dlls/glock.cpp rename to dlls/wpn_shared/hl_wpn_glock.cpp index dfc575a..e1de76f 100644 --- a/dlls/glock.cpp +++ b/dlls/wpn_shared/hl_wpn_glock.cpp @@ -34,22 +34,6 @@ enum glock_e { GLOCK_ADD_SILENCER }; -class CGlock : public CBasePlayerWeapon -{ -public: - void Spawn( void ); - void Precache( void ); - int iItemSlot( void ) { return 2; } - int GetItemInfo(ItemInfo *p); - - void PrimaryAttack( void ); - void SecondaryAttack( void ); - void GlockFire( float flSpread, float flCycleTime, BOOL fUseAutoAim ); - BOOL Deploy( void ); - void Reload( void ); - void WeaponIdle( void ); - int m_iShell; -}; LINK_ENTITY_TO_CLASS( weapon_glock, CGlock ); LINK_ENTITY_TO_CLASS( weapon_9mmhandgun, CGlock ); @@ -81,6 +65,9 @@ void CGlock::Precache( void ) PRECACHE_SOUND ("weapons/pl_gun1.wav");//silenced handgun PRECACHE_SOUND ("weapons/pl_gun2.wav");//silenced handgun PRECACHE_SOUND ("weapons/pl_gun3.wav");//handgun + + m_usFireGlock1 = PRECACHE_EVENT( 1, "events/glock1.sc" ); + m_usFireGlock2 = PRECACHE_EVENT( 1, "events/glock2.sc" ); } int CGlock::GetItemInfo(ItemInfo *p) @@ -103,7 +90,7 @@ int CGlock::GetItemInfo(ItemInfo *p) BOOL CGlock::Deploy( ) { // pev->body = 1; - return DefaultDeploy( "models/v_9mmhandgun.mdl", "models/p_9mmhandgun.mdl", GLOCK_DRAW, "onehanded" ); + return DefaultDeploy( "models/v_9mmhandgun.mdl", "models/p_9mmhandgun.mdl", GLOCK_DRAW, "onehanded", /*UseDecrement() ? 1 : 0*/ 0 ); } void CGlock::SecondaryAttack( void ) @@ -123,7 +110,7 @@ void CGlock::GlockFire( float flSpread , float flCycleTime, BOOL fUseAutoAim ) if (m_fFireOnEmpty) { PlayEmptySound(); - m_flNextPrimaryAttack = gpGlobals->time + 0.2; + m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.2; } return; @@ -133,14 +120,27 @@ void CGlock::GlockFire( float flSpread , float flCycleTime, BOOL fUseAutoAim ) m_pPlayer->pev->effects = (int)(m_pPlayer->pev->effects) | EF_MUZZLEFLASH; +#if defined ( OLD_WEAPONS ) if (m_iClip != 0) SendWeaponAnim( GLOCK_SHOOT ); else SendWeaponAnim( GLOCK_SHOOT_EMPTY ); +#endif + + int flags; + +#if defined( CLIENT_WEAPONS ) + flags = FEV_NOTHOST; +#else + flags = 0; +#endif + + PLAYBACK_EVENT_FULL( flags, m_pPlayer->edict(), fUseAutoAim ? m_usFireGlock1 : m_usFireGlock2, 0.0, (float *)&g_vecZero, (float *)&g_vecZero, 0.0, 0.0, 0, 0, ( m_iClip == 0 ) ? 1 : 0, 0 ); // player "shoot" animation m_pPlayer->SetAnimation( PLAYER_ATTACK1 ); +#if defined ( OLD_WEAPONS ) UTIL_MakeVectors( m_pPlayer->pev->v_angle + m_pPlayer->pev->punchangle ); Vector vecShellVelocity = m_pPlayer->pev->velocity @@ -148,13 +148,14 @@ void CGlock::GlockFire( float flSpread , float flCycleTime, BOOL fUseAutoAim ) + gpGlobals->v_up * RANDOM_FLOAT(100,150) + gpGlobals->v_forward * 25; EjectBrass ( pev->origin + m_pPlayer->pev->view_ofs + gpGlobals->v_up * -12 + gpGlobals->v_forward * 32 + gpGlobals->v_right * 6 , vecShellVelocity, pev->angles.y, m_iShell, TE_BOUNCE_SHELL ); +#endif // silenced if (pev->body == 1) { m_pPlayer->m_iWeaponVolume = QUIET_GUN_VOLUME; m_pPlayer->m_iWeaponFlash = DIM_GUN_FLASH; - +#if defined ( OLD_WEAPONS ) switch(RANDOM_LONG(0,1)) { case 0: @@ -164,13 +165,16 @@ void CGlock::GlockFire( float flSpread , float flCycleTime, BOOL fUseAutoAim ) EMIT_SOUND(ENT(m_pPlayer->pev), CHAN_WEAPON, "weapons/pl_gun2.wav", RANDOM_FLOAT(0.9, 1.0), ATTN_NORM); break; } +#endif } else { // non-silenced m_pPlayer->m_iWeaponVolume = NORMAL_GUN_VOLUME; m_pPlayer->m_iWeaponFlash = NORMAL_GUN_FLASH; +#if defined ( OLD_WEAPONS ) EMIT_SOUND_DYN(ENT(m_pPlayer->pev), CHAN_WEAPON, "weapons/pl_gun3.wav", RANDOM_FLOAT(0.92, 1.0), ATTN_NORM, 0, 98 + RANDOM_LONG(0,3)); +#endif } Vector vecSrc = m_pPlayer->GetGunPosition( ); @@ -186,15 +190,18 @@ void CGlock::GlockFire( float flSpread , float flCycleTime, BOOL fUseAutoAim ) } m_pPlayer->FireBullets( 1, vecSrc, vecAiming, Vector( flSpread, flSpread, flSpread ), 8192, BULLET_PLAYER_9MM, 0 ); - m_flNextPrimaryAttack = m_flNextSecondaryAttack = gpGlobals->time + flCycleTime; + + m_flNextPrimaryAttack = m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + flCycleTime; if (!m_iClip && m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] <= 0) // HEV suit - indicate out of ammo condition m_pPlayer->SetSuitUpdate("!HEV_AMO0", FALSE, 0); - m_flTimeWeaponIdle = gpGlobals->time + RANDOM_FLOAT ( 10, 15 ); + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 ); +#if defined ( OLD_WEAPONS ) m_pPlayer->pev->punchangle.x -= 2; +#endif } @@ -209,7 +216,7 @@ void CGlock::Reload( void ) if (iResult) { - m_flTimeWeaponIdle = gpGlobals->time + RANDOM_FLOAT ( 10, 15 ); + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 ); } } @@ -221,30 +228,31 @@ void CGlock::WeaponIdle( void ) m_pPlayer->GetAutoaimVector( AUTOAIM_10DEGREES ); - if (m_flTimeWeaponIdle > gpGlobals->time) + if ( m_flTimeWeaponIdle > UTIL_WeaponTimeBase() ) return; // only idle if the slid isn't back if (m_iClip != 0) { int iAnim; - float flRand = RANDOM_FLOAT(0, 1); + float flRand = UTIL_SharedRandomFloat( m_pPlayer->random_seed, 0.0, 1.0 ); + if (flRand <= 0.3 + 0 * 0.75) { iAnim = GLOCK_IDLE3; - m_flTimeWeaponIdle = gpGlobals->time + 49.0 / 16; + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 49.0 / 16; } else if (flRand <= 0.6 + 0 * 0.875) { iAnim = GLOCK_IDLE1; - m_flTimeWeaponIdle = gpGlobals->time + 60.0 / 16.0; + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 60.0 / 16.0; } else { iAnim = GLOCK_IDLE2; - m_flTimeWeaponIdle = gpGlobals->time + 40.0 / 16.0; + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 40.0 / 16.0; } - SendWeaponAnim( iAnim ); + SendWeaponAnim( iAnim, 1 ); } } diff --git a/dlls/xen.cpp b/dlls/xen.cpp index 055a18c..c1d1a9a 100644 --- a/dlls/xen.cpp +++ b/dlls/xen.cpp @@ -1,6 +1,6 @@ /*** * -* Copyright (c) 1999, Valve LLC. All rights reserved. +* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. * * This product contains software technology licensed from Id * Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. diff --git a/engine/ANORMS.H b/engine/Anorms.h similarity index 100% rename from engine/ANORMS.H rename to engine/Anorms.h diff --git a/engine/PROGS.H b/engine/PROGS.H deleted file mode 100644 index 2a9e430..0000000 --- a/engine/PROGS.H +++ /dev/null @@ -1,145 +0,0 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -#ifndef PROGS_H -#define PROGS_H - -#include "progdefs.h" - -#ifndef EIFACE_H -// Forward declare this type to avoid problems -typedef struct saverestore_s SAVERESTOREDATA; -#endif - -// Entity state is used for the baseline and for delta compression of a packet of -// entities that is sent to a client. -typedef struct -{ - int entityType; // Normal or Custom to know how to parse the entity. - int number; // Index into cl_entities array for this entity. - int flags; // The delta compression bit header. - - vec3_t origin; - vec3_t angles; - - int modelindex; - int sequence; - float frame; - int colormap; - short skin; - short solid; - int effects; - float scale; - - // render information - int rendermode; - int renderamt; - color24 rendercolor; - int renderfx; - - // Added for entity delta compression - //vec3_t msg_origins[2]; - //vec3_t msg_angles[2]; - - int movetype; - float animtime; - float framerate; - int body; - byte controller[4]; - byte blending[4]; - vec3_t velocity; - - vec3_t mins; // Send bbox down to client for use during prediction. - vec3_t maxs; - - int aiment; -} entity_state_t; - -#define MAX_ENT_LEAFS 24 -typedef struct edict_s -{ - qboolean free; - int serialnumber; - link_t area; // linked to a division node or leaf - - int num_leafs; - short leafnums[MAX_ENT_LEAFS]; - - entity_state_t baseline; - - float freetime; // sv.time when the object was freed - - void* pvPrivateData; // Alloced and freed by engine, used by DLLs - - entvars_t v; // C exported fields from progs -// other fields from progs come immediately after -} edict_t; -#define EDICT_FROM_AREA(l) STRUCT_FROM_LINK(l,edict_t,area) - -//============================================================================ - -extern char *pr_strings; -extern globalvars_t gGlobalVariables; - -//============================================================================ - -edict_t *ED_Alloc (void); -void ED_Free (edict_t *ed); - -char *ED_NewString (const char *string); -// returns a copy of the string allocated from the server's string heap - -void ED_Print (edict_t *ed); -void ED_Write (SAVERESTOREDATA *save, edict_t *ed); -char *ED_ParseEdict (char *data, edict_t *ent); - - -//void ED_WriteGlobals ( SAVERESTOREDATA *save ); -//void ED_ParseGlobals (char *data); - -void ED_LoadFromFile (char *data); - -//define EDICT_NUM(n) ((edict_t *)(sv.edicts+ (n)*pr_edict_size)) -//define NUM_FOR_EDICT(e) (((byte *)(e) - sv.edicts)/pr_edict_size) - -edict_t *EDICT_NUM(int n); -int NUM_FOR_EDICT(const edict_t *e); - -#define EDICT_TO_PROG(e) ((byte *)e - (byte *)sv.edicts) -#define PROG_TO_EDICT(e) ((edict_t *)((byte *)sv.edicts + e)) - -//============================================================================ - -#if 0 -#define G_FLOAT(o) (pr_globals[o]) -#define G_INT(o) (*(int *)&pr_globals[o]) -#define G_EDICT(o) ((edict_t *)((byte *)sv.edicts+ *(int *)&pr_globals[o])) -#define G_EDICTNUM(o) NUM_FOR_EDICT(G_EDICT(o)) -#define G_VECTOR(o) (&pr_globals[o]) -#define G_STRING(o) (pr_strings + *(string_t *)&pr_globals[o]) -#define G_FUNCTION(o) (*(func_t *)&pr_globals[o]) - -#define E_FLOAT(e,o) (((float*)&e->v)[o]) -#define E_INT(e,o) (*(int *)&((float*)&e->v)[o]) -#define E_VECTOR(e,o) (&((float*)&e->v)[o]) -#endif -#define E_STRING(e,o) (pr_strings + *(string_t *)&((char *)&e->v)[o]) - -extern int type_size[8]; - -void ED_PrintEdicts (void); -void ED_PrintNum (int ent); - - -#endif // PROGS_H \ No newline at end of file diff --git a/engine/Progs.h b/engine/Progs.h new file mode 100644 index 0000000..b070527 --- /dev/null +++ b/engine/Progs.h @@ -0,0 +1,82 @@ +/*** +* +* Copyright (c) 1999, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +#ifndef PROGS_H +#define PROGS_H + +#include "progdefs.h" + +// 16 simultaneous events, max +#define MAX_EVENT_QUEUE 64 + +#define DEFAULT_EVENT_RESENDS 1 + +#include "event_flags.h" + +typedef struct event_info_s event_info_t; + +#include "event_args.h" + +struct event_info_s +{ + unsigned short index; // 0 implies not in use + + short packet_index; // Use data from state info for entity in delta_packet . -1 implies separate info based on event + // parameter signature + short entity_index; // The edict this event is associated with + + float fire_time; // if non-zero, the time when the event should be fired ( fixed up on the client ) + + event_args_t args; + +// CLIENT ONLY + int flags; // Reliable or not, etc. + +}; + +typedef struct event_state_s event_state_t; + +struct event_state_s +{ + struct event_info_s ei[ MAX_EVENT_QUEUE ]; +}; + +#if !defined( ENTITY_STATEH ) +#include "entity_state.h" +#endif + +#if !defined( EDICT_H ) +#include "edict.h" +#endif + +#define STRUCT_FROM_LINK(l,t,m) ((t *)((byte *)l - (int)&(((t *)0)->m))) +#define EDICT_FROM_AREA(l) STRUCT_FROM_LINK(l,edict_t,area) + +//============================================================================ + +extern char *pr_strings; +extern globalvars_t gGlobalVariables; + +//============================================================================ + +edict_t *ED_Alloc (void); +void ED_Free (edict_t *ed); +void ED_LoadFromFile (char *data); + +edict_t *EDICT_NUM(int n); +int NUM_FOR_EDICT(const edict_t *e); + +#define PROG_TO_EDICT(e) ((edict_t *)((byte *)sv.edicts + e)) + +#endif // PROGS_H \ No newline at end of file diff --git a/engine/cdll_int.h b/engine/cdll_int.h index 73f7d51..8801448 100644 --- a/engine/cdll_int.h +++ b/engine/cdll_int.h @@ -47,16 +47,9 @@ typedef struct client_data_s vec3_t origin; // fields that can be changed by the cldll - float viewheight; - float maxspeed; vec3_t viewangles; - vec3_t punchangle; - int iKeyBits; // Keyboard bits int iWeaponBits; float fov; // field of view - float view_idlescale; // view shake/rotate - float mouse_sensitivity; - } client_data_t; typedef struct client_sprite_s @@ -104,82 +97,169 @@ typedef struct typedef struct cl_enginefuncs_s { // sprite handlers - HSPRITE (*pfnSPR_Load) ( const char *szPicName ); - int (*pfnSPR_Frames) ( HSPRITE hPic ); - int (*pfnSPR_Height) ( HSPRITE hPic, int frame ); - int (*pfnSPR_Width) ( HSPRITE hPic, int frame ); - void (*pfnSPR_Set) ( HSPRITE hPic, int r, int g, int b ); - void (*pfnSPR_Draw) ( int frame, int x, int y, const wrect_t *prc); - void (*pfnSPR_DrawHoles) ( int frame, int x, int y, const wrect_t *prc ); - void (*pfnSPR_DrawAdditive) ( int frame, int x, int y, const wrect_t *prc ); - void (*pfnSPR_EnableScissor) ( int x, int y, int width, int height ); - void (*pfnSPR_DisableScissor)( void ); - client_sprite_t *(*pfnSPR_GetList) ( char *psz, int *piCount); + HSPRITE ( *pfnSPR_Load ) ( const char *szPicName ); + int ( *pfnSPR_Frames ) ( HSPRITE hPic ); + int ( *pfnSPR_Height ) ( HSPRITE hPic, int frame ); + int ( *pfnSPR_Width ) ( HSPRITE hPic, int frame ); + void ( *pfnSPR_Set ) ( HSPRITE hPic, int r, int g, int b ); + void ( *pfnSPR_Draw ) ( int frame, int x, int y, const wrect_t *prc ); + void ( *pfnSPR_DrawHoles ) ( int frame, int x, int y, const wrect_t *prc ); + void ( *pfnSPR_DrawAdditive ) ( int frame, int x, int y, const wrect_t *prc ); + void ( *pfnSPR_EnableScissor ) ( int x, int y, int width, int height ); + void ( *pfnSPR_DisableScissor ) ( void ); + client_sprite_t *( *pfnSPR_GetList ) ( char *psz, int *piCount ); // screen handlers - void (*pfnFillRGBA) ( int x, int y, int width, int height, int r, int g, int b, int a); - int (*pfnGetScreenInfo) ( SCREENINFO *pscrinfo); - void (*pfnSetCrosshair) ( HSPRITE hspr, wrect_t rc, int r, int g, int b); + void ( *pfnFillRGBA ) ( int x, int y, int width, int height, int r, int g, int b, int a ); + int ( *pfnGetScreenInfo ) ( SCREENINFO *pscrinfo ); + void ( *pfnSetCrosshair ) ( HSPRITE hspr, wrect_t rc, int r, int g, int b ); // cvar handlers - int (*pfnRegisterVariable) ( char *szName, char *szValue, int flags ); - float (*pfnGetCvarFloat) ( char *szName ); - char* (*pfnGetCvarString) ( char *szName ); + struct cvar_s *( *pfnRegisterVariable ) ( char *szName, char *szValue, int flags ); + float ( *pfnGetCvarFloat ) ( char *szName ); + char* ( *pfnGetCvarString ) ( char *szName ); // command handlers - int (*pfnAddCommand) ( char *cmd_name, void (*function)(void) ); - int (*pfnHookUserMsg) ( char *szMsgName, pfnUserMsgHook pfn ); - int (*pfnServerCmd) ( char *szCmdString ); - int (*pfnClientCmd) ( char *szCmdString ); + int ( *pfnAddCommand ) ( char *cmd_name, void (*function)(void) ); + int ( *pfnHookUserMsg ) ( char *szMsgName, pfnUserMsgHook pfn ); + int ( *pfnServerCmd ) ( char *szCmdString ); + int ( *pfnClientCmd ) ( char *szCmdString ); - void (*pfnGetPlayerInfo) ( int ent_num, hud_player_info_t *pinfo ); + void ( *pfnGetPlayerInfo ) ( int ent_num, hud_player_info_t *pinfo ); // sound handlers - void (*pfnPlaySoundByName) ( char *szSound, float volume ); - void (*pfnPlaySoundByIndex) ( int iSound, float volume ); + void ( *pfnPlaySoundByName ) ( char *szSound, float volume ); + void ( *pfnPlaySoundByIndex ) ( int iSound, float volume ); // vector helpers - void (*pfnAngleVectors) (const float * vecAngles, float * forward, float * right, float * up); + void ( *pfnAngleVectors ) ( const float * vecAngles, float * forward, float * right, float * up ); // text message system - client_textmessage_t *(*pfnTextMessageGet) ( const char *pName ); - int (*pfnDrawCharacter) ( int x, int y, int number, int r, int g, int b ); - int (*pfnDrawConsoleString) ( int x, int y, char *string ); - void (*pfnDrawConsoleStringLen) ( const char *string, int *length, int *height ); - void (*pfnConsolePrint) ( const char *string ); - void (*pfnCenterPrint) ( const char *string ); + client_textmessage_t *( *pfnTextMessageGet ) ( const char *pName ); + int ( *pfnDrawCharacter ) ( int x, int y, int number, int r, int g, int b ); + int ( *pfnDrawConsoleString ) ( int x, int y, char *string ); + void ( *pfnDrawSetTextColor ) ( float r, float g, float b ); + void ( *pfnDrawConsoleStringLen )( const char *string, int *length, int *height ); + void ( *pfnConsolePrint ) ( const char *string ); + void ( *pfnCenterPrint ) ( const char *string ); + + +// Added for user input processing + int ( *GetWindowCenterX ) ( void ); + int ( *GetWindowCenterY ) ( void ); + void ( *GetViewAngles ) ( float * ); + void ( *SetViewAngles ) ( float * ); + int ( *GetMaxClients ) ( void ); + void ( *Cvar_SetValue ) ( char *cvar, float value ); + + int (*Cmd_Argc) (void); + char *( *Cmd_Argv ) ( int arg ); + void ( *Con_Printf ) ( char *fmt, ... ); + void ( *Con_DPrintf ) ( char *fmt, ... ); + void ( *Con_NPrintf ) ( int pos, char *fmt, ... ); + void ( *Con_NXPrintf ) ( struct con_nprint_s *info, char *fmt, ... ); + + const char *( *PhysInfo_ValueForKey ) ( const char *key ); + const char *( *ServerInfo_ValueForKey )( const char *key ); + float ( *GetClientMaxspeed ) ( void ); + int ( *CheckParm ) ( char *parm, char **ppnext ); + void ( *Key_Event ) ( int key, int down ); + void ( *GetMousePosition ) ( int *mx, int *my ); + int ( *IsNoClipping ) ( void ); + + struct cl_entity_s *( *GetLocalPlayer ) ( void ); + struct cl_entity_s *( *GetViewModel ) ( void ); + struct cl_entity_s *( *GetEntityByIndex ) ( int idx ); + + float ( *GetClientTime ) ( void ); + void ( *V_CalcShake ) ( void ); + void ( *V_ApplyShake ) ( float *origin, float *angles, float factor ); + + int ( *PM_PointContents ) ( float *point, int *truecontents ); + int ( *PM_WaterEntity ) ( float *p ); + struct pmtrace_s *( *PM_TraceLine ) ( float *start, float *end, int flags, int usehull, int ignore_pe ); + + struct model_s *( *CL_LoadModel ) ( const char *modelname, int *index ); + int ( *CL_CreateVisibleEntity ) ( int type, struct cl_entity_s *ent ); + + const struct model_s * ( *GetSpritePointer ) ( HSPRITE hSprite ); + void ( *pfnPlaySoundByNameAtLocation ) ( char *szSound, float volume, float *origin ); + + unsigned short ( *pfnPrecacheEvent ) ( int type, const char* psz ); + void ( *pfnPlaybackEvent ) ( int flags, const struct edict_s *pInvoker, unsigned short eventindex, float delay, float *origin, float *angles, float fparam1, float fparam2, int iparam1, int iparam2, int bparam1, int bparam2 ); + void ( *pfnWeaponAnim ) ( int iAnim, int body ); + float ( *pfnRandomFloat ) ( float flLow, float flHigh ); + long ( *pfnRandomLong ) ( long lLow, long lHigh ); + void ( *pfnHookEvent ) ( char *name, void ( *pfnEvent )( struct event_args_s *args ) ); + int (*Con_IsVisible) (); + const char *( *pfnGetGameDirectory ) ( void ); + struct cvar_s *( *pfnGetCvarPointer ) ( const char *szName ); + const char *( *Key_LookupBinding ) ( const char *pBinding ); + const char *( *pfnGetLevelName ) ( void ); + void ( *pfnGetScreenFade ) ( struct screenfade_s *fade ); + void ( *pfnSetScreenFade ) ( struct screenfade_s *fade ); + void *( *VGui_GetPanel ) ( ); + void ( *VGui_ViewportPaintBackground ) (int extents[4]); + + byte* (*COM_LoadFile) ( char *path, int usehunk, int *pLength ); + char* (*COM_ParseFile) ( char *data, char *token ); + void (*COM_FreeFile) ( void *buffer ); + + struct triangleapi_s *pTriAPI; + struct efx_api_s *pEfxAPI; + struct event_api_s *pEventAPI; + struct demo_api_s *pDemoAPI; + struct net_api_s *pNetAPI; } cl_enginefunc_t; +#ifndef IN_BUTTONS_H +#include "in_buttons.h" +#endif -// ! duplicate macro's! really bad coding practice -// buttons -#define IN_ATTACK (1 << 0) -#define IN_JUMP (1 << 1) -#define IN_DUCK (1 << 2) -#define IN_FORWARD (1 << 3) -#define IN_BACK (1 << 4) -#define IN_USE (1 << 5) -#define IN_CANCEL (1 << 6) -#define IN_LEFT (1 << 7) -#define IN_RIGHT (1 << 8) -#define IN_MOVELEFT (1 << 9) -#define IN_MOVERIGHT (1 << 10) -#define IN_ATTACK2 (1 << 11) -#define IN_RUN (1 << 12) -#define IN_RELOAD (1 << 13) -#define IN_ALT1 (1 << 14) -#define IN_ALT2 (1 << 15) - - -#define CLDLL_INTERFACE_VERSION 6 +#define CLDLL_INTERFACE_VERSION 7 extern void ClientDLL_Init( void ); // from cdll_int.c extern void ClientDLL_Shutdown( void ); extern void ClientDLL_HudInit( void ); extern void ClientDLL_HudVidInit( void ); extern void ClientDLL_UpdateClientData( void ); +extern void ClientDLL_Frame( double time ); extern void ClientDLL_HudRedraw( int intermission ); +extern void ClientDLL_MoveClient( struct playermove_s *ppmove ); +extern void ClientDLL_ClientMoveInit( struct playermove_s *ppmove ); +extern char ClientDLL_ClientTextureType( char *name ); +extern void ClientDLL_CreateMove( float frametime, struct usercmd_s *cmd, int active ); +extern void ClientDLL_ActivateMouse( void ); +extern void ClientDLL_DeactivateMouse( void ); +extern void ClientDLL_MouseEvent( int mstate ); +extern void ClientDLL_ClearStates( void ); +extern int ClientDLL_IsThirdPerson( void ); +extern void ClientDLL_GetCameraOffsets( float *ofs ); +extern int ClientDLL_GraphKeyDown( void ); +extern struct kbutton_s *ClientDLL_FindKey( const char *name ); +extern void ClientDLL_CAM_Think( void ); +extern void ClientDLL_IN_Accumulate( void ); +extern void ClientDLL_CalcRefdef( struct ref_params_s *pparams ); +extern int ClientDLL_AddEntity( int type, struct cl_entity_s *ent ); +extern void ClientDLL_CreateEntities( void ); + +extern void ClientDLL_DrawNormalTriangles( void ); +extern void ClientDLL_DrawTransparentTriangles( void ); +extern void ClientDLL_StudioEvent( const struct mstudioevent_s *event, const struct cl_entity_s *entity ); +extern void ClientDLL_PostRunCmd( struct local_state_s *from, struct local_state_s *to, struct usercmd_s *cmd, int runfuncs, double time, unsigned int random_seed ); +extern void ClientDLL_TxferLocalOverrides( struct entity_state_s *state, const struct clientdata_s *client ); +extern void ClientDLL_ProcessPlayerState( struct entity_state_s *dst, const struct entity_state_s *src ); +extern void ClientDLL_TxferPredictionData ( struct entity_state_s *ps, const struct entity_state_s *pps, struct clientdata_s *pcd, const struct clientdata_s *ppcd, struct weapon_data_s *wd, const struct weapon_data_s *pwd ); +extern void ClientDLL_ReadDemoBuffer( int size, unsigned char *buffer ); +extern int ClientDLL_ConnectionlessPacket( const struct netadr_s *net_from, const char *args, char *response_buffer, int *response_buffer_size ); +extern int ClientDLL_GetHullBounds( int hullnumber, float *mins, float *maxs ); + +extern void ClientDLL_VGui_ConsolePrint(const char* text); + +extern int ClientDLL_Key_Event( int down, int keynum, const char *pszCurrentBinding ); +extern void ClientDLL_TempEntUpdate( double ft, double ct, double grav, struct tempent_s **ppFreeTE, struct tempent_s **ppActiveTE, int ( *addTEntity )( struct cl_entity_s *pEntity ), void ( *playTESound )( struct tempent_s *pTemp, float damp ) ); +extern struct cl_entity_s *ClientDLL_GetUserEntity( int index ); #endif // CDLL_INT_H diff --git a/engine/custom.h b/engine/custom.h index c594026..9e33d77 100644 --- a/engine/custom.h +++ b/engine/custom.h @@ -14,8 +14,11 @@ ****/ // Customization.h -#ifndef INC_CUSTOMIZATION -#define INC_CUSTOMIZATION +#ifndef CUSTOM_H +#define CUSTOM_H +#ifdef _WIN32 +#pragma once +#endif #define MAX_QPATH 64 // Must match value in quakedefs.h @@ -25,24 +28,34 @@ // For automatic downloading. typedef enum { - t_sound, + t_sound = 0, t_skin, t_model, t_decal, - t_generic + t_generic, + t_eventscript } resourcetype_t; +// Fake type for world +#define t_world 6 + +typedef struct +{ + int size; +} _resourceinfo_t; + +typedef struct resourceinfo_s +{ + _resourceinfo_t info[ 7 ]; +} resourceinfo_t; + #define RES_FATALIFMISSING (1<<0) // Disconnect if we can't get this file. #define RES_WASMISSING (1<<1) // Do we have the file locally, did we get it ok? #define RES_CUSTOM (1<<2) // Is this resource one that corresponds to another player's customization // or is it a server startup resource. -// MD5 Hash -typedef struct -{ - unsigned int buf[4]; - unsigned int bits[2]; - unsigned char in[64]; -} MD5Context_t; +#define RES_REQUESTED (1<<3) // Already requested a download of this one + +#include "crc.h" typedef struct resource_s { @@ -56,6 +69,7 @@ typedef struct resource_s unsigned char rgucMD5_hash[16]; // To determine if we already have it. unsigned char playernum; // Which player index this resource is associated with, if it's a custom resource. + unsigned char rguc_reserved[ 32 ]; // For future expansion struct resource_s *pNext; // Next in chain. struct resource_s *pPrev; } resource_t; @@ -73,4 +87,13 @@ typedef struct customization_s struct customization_s *pNext; // Next in chain } customization_t; -#endif // !Customization \ No newline at end of file +#define FCUST_FROMHPAK ( 1<<0 ) +#define FCUST_WIPEDATA ( 1<<1 ) +#define FCUST_IGNOREINIT ( 1<<2 ) + +void COM_ClearCustomizationList( struct customization_s *pHead, qboolean bCleanDecals); +qboolean COM_CreateCustomization( struct customization_s *pListHead, struct resource_s *pResource, int playernumber, int flags, + struct customization_s **pCustomization, int *nLumps ); +int COM_SizeofResourceList ( struct resource_s *pList, struct resourceinfo_s *ri ); + +#endif // CUSTOM_H \ No newline at end of file diff --git a/engine/customentity.h b/engine/customentity.h index 1a73c64..21d3713 100644 --- a/engine/customentity.h +++ b/engine/customentity.h @@ -15,51 +15,7 @@ #ifndef CUSTOMENTITY_H #define CUSTOMENTITY_H - // Custom Entities -#define CUSTOM_TYPE ( (1<>CUSTOM_SHIFT) -#define SET_CUSTOM_TYPE(customType) ( ((customType< + +#pragma warning(disable : 4244) +#pragma warning(disable : 4305) + +extern playermove_t *pmove; + +// Expand debugging BBOX particle hulls by this many units. +#define BOX_GAP 0.0f + +static int PM_boxpnt[6][4] = +{ + { 0, 4, 6, 2 }, // +X + { 0, 1, 5, 4 }, // +Y + { 0, 2, 3, 1 }, // +Z + { 7, 5, 1, 3 }, // -X + { 7, 3, 2, 6 }, // -Y + { 7, 6, 4, 5 }, // -Z +}; + +void PM_ShowClipBox( void ) +{ +#if defined( _DEBUG ) + if ( !pmove->runfuncs ) + return; + + // More debugging, draw the particle bbox for player and for the entity we are looking directly at. + // aslo prints entity info to the console overlay. + if ( !pmove->server ) + return; + + // Draw entity in center of view + // Also draws the normal to the clip plane that intersects our movement ray. Leaves a particle + // trail at the intersection point. + PM_ViewEntity(); + + // Show our BBOX in particles. + //PM_DrawBBox( pmove->player_mins[pmove->usehull], pmove->player_maxs[pmove->usehull], pmove->origin, 132, 0.1 ); +/* + { + int i; + for ( i = 0; i < pmove->numphysent; i++ ) + { + if ( pmove->physents[ i ].info >= 1 && pmove->physents[ i ].info <= 4 ) + { + PM_DrawBBox( pmove->player_mins[pmove->usehull], pmove->player_maxs[pmove->usehull], pmove->physents[i].origin, 132, 0.1 ); + } + } + } +*/ +#endif +} + +/* +=============== +PM_ParticleLine(vec3_t start, vec3_t end, int color, float life) + +================ +*/ +void PM_ParticleLine(vec3_t start, vec3_t end, int pcolor, float life, float vert) +{ + float linestep = 2.0f; + float curdist; + float len; + vec3_t curpos; + vec3_t diff; + int i; + // Determine distance; + + VectorSubtract(end, start, diff); + + len = VectorNormalize(diff); + + curdist = 0; + while (curdist <= len) + { + for (i = 0; i < 3; i++) + curpos[i] = start[i] + curdist * diff[i]; + + pmove->PM_Particle( curpos, pcolor, life, 0, vert); + curdist += linestep; + } + +} + +/* +================ +PM_DrawRectangle(vec3_t tl, vec3_t br) + +================ +*/ +void PM_DrawRectangle(vec3_t tl, vec3_t bl, vec3_t tr, vec3_t br, int pcolor, float life) +{ + PM_ParticleLine(tl, bl, pcolor, life, 0); + PM_ParticleLine(bl, br, pcolor, life, 0); + PM_ParticleLine(br, tr, pcolor, life, 0); + PM_ParticleLine(tr, tl, pcolor, life, 0); +} + +/* +================ +PM_DrawPhysEntBBox(int num) + +================ +*/ +void PM_DrawPhysEntBBox(int num, int pcolor, float life) +{ + physent_t *pe; + vec3_t org; + int j; + vec3_t tmp; + vec3_t p[8]; + float gap = BOX_GAP; + vec3_t modelmins, modelmaxs; + + if (num >= pmove->numphysent || + num <= 0) + return; + + pe = &pmove->physents[num]; + + if (pe->model) + { + VectorCopy(pe->origin, org); + + pmove->PM_GetModelBounds( pe->model, modelmins, modelmaxs ); + for (j = 0; j < 8; j++) + { + tmp[0] = (j & 1) ? modelmins[0] - gap : modelmaxs[0] + gap; + tmp[1] = (j & 2) ? modelmins[1] - gap : modelmaxs[1] + gap; + tmp[2] = (j & 4) ? modelmins[2] - gap : modelmaxs[2] + gap; + + VectorCopy(tmp, p[j]); + } + + // If the bbox should be rotated, do that + if (pe->angles[0] || pe->angles[1] || pe->angles[2]) + { + vec3_t forward, right, up; + + AngleVectorsTranspose(pe->angles, forward, right, up); + for (j = 0; j < 8; j++) + { + VectorCopy(p[j], tmp); + p[j][0] = DotProduct ( tmp, forward ); + p[j][1] = DotProduct ( tmp, right ); + p[j][2] = DotProduct ( tmp, up ); + } + } + + // Offset by entity origin, if any. + for (j = 0; j < 8; j++) + VectorAdd(p[j], org, p[j]); + + for (j = 0; j < 6; j++) + { + PM_DrawRectangle( + p[PM_boxpnt[j][1]], + p[PM_boxpnt[j][0]], + p[PM_boxpnt[j][2]], + p[PM_boxpnt[j][3]], + pcolor, life); + } + } + else + { + for (j = 0; j < 8; j++) + { + tmp[0] = (j & 1) ? pe->mins[0] : pe->maxs[0]; + tmp[1] = (j & 2) ? pe->mins[1] : pe->maxs[1]; + tmp[2] = (j & 4) ? pe->mins[2] : pe->maxs[2]; + + VectorAdd(tmp, pe->origin, tmp); + VectorCopy(tmp, p[j]); + } + + for (j = 0; j < 6; j++) + { + PM_DrawRectangle( + p[PM_boxpnt[j][1]], + p[PM_boxpnt[j][0]], + p[PM_boxpnt[j][2]], + p[PM_boxpnt[j][3]], + pcolor, life); + } + + } +} + +/* +================ +PM_DrawBBox(vec3_t mins, vec3_t maxs, vec3_t origin, int pcolor, float life) + +================ +*/ +void PM_DrawBBox(vec3_t mins, vec3_t maxs, vec3_t origin, int pcolor, float life) +{ + int j; + + vec3_t tmp; + vec3_t p[8]; + float gap = BOX_GAP; + + for (j = 0; j < 8; j++) + { + tmp[0] = (j & 1) ? mins[0] - gap : maxs[0] + gap; + tmp[1] = (j & 2) ? mins[1] - gap : maxs[1] + gap ; + tmp[2] = (j & 4) ? mins[2] - gap : maxs[2] + gap ; + + VectorAdd(tmp, origin, tmp); + VectorCopy(tmp, p[j]); + } + + for (j = 0; j < 6; j++) + { + PM_DrawRectangle( + p[PM_boxpnt[j][1]], + p[PM_boxpnt[j][0]], + p[PM_boxpnt[j][2]], + p[PM_boxpnt[j][3]], + pcolor, life); + } +} + + +#ifndef DEDICATED + +/* +================ +PM_ViewEntity + +Shows a particle trail from player to entity in crosshair. +Shows particles at that entities bbox + +Tries to shoot a ray out by about 128 units. +================ +*/ +void PM_ViewEntity( void ) +{ + vec3_t forward, right, up; + float raydist = 256.0f; + vec3_t origin; + vec3_t end; + int i; + pmtrace_t trace; + int pcolor = 77; + float fup; + +#if 0 + if ( !pm_showclip.value ) + return; +#endif + + AngleVectors (pmove->angles, forward, right, up); // Determine movement angles + + VectorCopy( pmove->origin, origin); + + fup = 0.5*( pmove->player_mins[pmove->usehull][2] + pmove->player_maxs[pmove->usehull][2] ); + fup += pmove->view_ofs[2]; + fup -= 4; + + for (i = 0; i < 3; i++) + { + end[i] = origin[i] + raydist * forward[i]; + } + + trace = pmove->PM_PlayerTrace( origin, end, PM_STUDIO_BOX, -1 ); + + if (trace.ent > 0) // Not the world + { + pcolor = 111; + } + + // Draw the hull or bbox. + if (trace.ent > 0) + { + PM_DrawPhysEntBBox(trace.ent, pcolor, 0.3f); + } +} + +#endif \ No newline at end of file diff --git a/pm_shared/pm_debug.h b/pm_shared/pm_debug.h new file mode 100644 index 0000000..d9818a4 --- /dev/null +++ b/pm_shared/pm_debug.h @@ -0,0 +1,24 @@ +/*** +* +* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +#ifndef PM_DEBUG_H +#define PM_DEBUG_H +#pragma once + +void PM_ViewEntity( void ); +void PM_DrawBBox(vec3_t mins, vec3_t maxs, vec3_t origin, int pcolor, float life); +void PM_ParticleLine(vec3_t start, vec3_t end, int pcolor, float life, float vert); +void PM_ShowClipBox( void ); + +#endif // PMOVEDBG_H \ No newline at end of file diff --git a/pm_shared/pm_defs.h b/pm_shared/pm_defs.h new file mode 100644 index 0000000..1e3e498 --- /dev/null +++ b/pm_shared/pm_defs.h @@ -0,0 +1,218 @@ +/*** +* +* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +// pm_defs.h +#if !defined( PM_DEFSH ) +#define PM_DEFSH +#pragma once + +#define MAX_PHYSENTS 600 // Must have room for all entities in the world. +#define MAX_MOVEENTS 64 +#define MAX_CLIP_PLANES 5 + +#define PM_NORMAL 0x00000000 +#define PM_STUDIO_IGNORE 0x00000001 // Skip studio models +#define PM_STUDIO_BOX 0x00000002 // Use boxes for non-complex studio models (even in traceline) +#define PM_GLASS_IGNORE 0x00000004 // Ignore entities with non-normal rendermode +#define PM_WORLD_ONLY 0x00000008 // Only trace against the world + +// Values for flags parameter of PM_TraceLine +#define PM_TRACELINE_ANYVISIBLE 0 +#define PM_TRACELINE_PHYSENTSONLY 1 + +#include "pm_info.h" + +// PM_PlayerTrace results. +#include "pmtrace.h" + +#if !defined ( USERCMD_H ) +#include "usercmd.h" +#endif + +// physent_t +typedef struct physent_s +{ + char name[32]; // Name of model, or "player" or "world". + int player; + vec3_t origin; // Model's origin in world coordinates. + struct model_s *model; // only for bsp models + struct model_s *studiomodel; // SOLID_BBOX, but studio clip intersections. + vec3_t mins, maxs; // only for non-bsp models + int info; // For client or server to use to identify (index into edicts or cl_entities) + vec3_t angles; // rotated entities need this info for hull testing to work. + + int solid; // Triggers and func_door type WATER brushes are SOLID_NOT + int skin; // BSP Contents for such things like fun_door water brushes. + int rendermode; // So we can ignore glass + + // Complex collision detection. + float frame; + int sequence; + byte controller[4]; + byte blending[2]; + + int movetype; + int takedamage; + int blooddecal; + int team; + int classnumber; + + // For mods + int iuser1; + int iuser2; + int iuser3; + int iuser4; + float fuser1; + float fuser2; + float fuser3; + float fuser4; + vec3_t vuser1; + vec3_t vuser2; + vec3_t vuser3; + vec3_t vuser4; +} physent_t; + +typedef struct playermove_s playermove_t; + +struct playermove_s +{ + int player_index; // So we don't try to run the PM_CheckStuck nudging too quickly. + qboolean server; // For debugging, are we running physics code on server side? + + qboolean multiplayer; // 1 == multiplayer server + float time; // realtime on host, for reckoning duck timing + float frametime; // Duration of this frame + + vec3_t forward, right, up; // Vectors for angles + // player state + vec3_t origin; // Movement origin. + vec3_t angles; // Movement view angles. + vec3_t oldangles; // Angles before movement view angles were looked at. + vec3_t velocity; // Current movement direction. + vec3_t movedir; // For waterjumping, a forced forward velocity so we can fly over lip of ledge. + vec3_t basevelocity; // Velocity of the conveyor we are standing, e.g. + + // For ducking/dead + vec3_t view_ofs; // Our eye position. + float flDuckTime; // Time we started duck + qboolean bInDuck; // In process of ducking or ducked already? + + // For walking/falling + int flTimeStepSound; // Next time we can play a step sound + int iStepLeft; + + float flFallVelocity; + vec3_t punchangle; + + float flSwimTime; + + float flNextPrimaryAttack; + + int effects; // MUZZLE FLASH, e.g. + + int flags; // FL_ONGROUND, FL_DUCKING, etc. + int usehull; // 0 = regular player hull, 1 = ducked player hull, 2 = point hull + float gravity; // Our current gravity and friction. + float friction; + int oldbuttons; // Buttons last usercmd + float waterjumptime; // Amount of time left in jumping out of water cycle. + qboolean dead; // Are we a dead player? + int deadflag; + int spectator; // Should we use spectator physics model? + int movetype; // Our movement type, NOCLIP, WALK, FLY + + int onground; + int waterlevel; + int watertype; + int oldwaterlevel; + + char sztexturename[256]; + char chtexturetype; + + float maxspeed; + float clientmaxspeed; // Player specific maxspeed + + // For mods + int iuser1; + int iuser2; + int iuser3; + int iuser4; + float fuser1; + float fuser2; + float fuser3; + float fuser4; + vec3_t vuser1; + vec3_t vuser2; + vec3_t vuser3; + vec3_t vuser4; + // world state + // Number of entities to clip against. + int numphysent; + physent_t physents[MAX_PHYSENTS]; + // Number of momvement entities (ladders) + int nummoveent; + // just a list of ladders + physent_t moveents[MAX_MOVEENTS]; + + // All things being rendered, for tracing against things you don't actually collide with + int numvisent; + physent_t visents[ MAX_PHYSENTS ]; + + // input to run through physics. + usercmd_t cmd; + + // Trace results for objects we collided with. + int numtouch; + pmtrace_t touchindex[MAX_PHYSENTS]; + + char physinfo[ MAX_PHYSINFO_STRING ]; // Physics info string + + struct movevars_s *movevars; + vec3_t player_mins[ 4 ]; + vec3_t player_maxs[ 4 ]; + + // Common functions + const char *(*PM_Info_ValueForKey) ( const char *s, const char *key ); + void (*PM_Particle)( vec3_t origin, int color, float life, int zpos, int zvel); + int (*PM_TestPlayerPosition) (vec3_t pos, pmtrace_t *ptrace ); + void (*Con_NPrintf)( int idx, char *fmt, ... ); + void (*Con_DPrintf)( char *fmt, ... ); + void (*Con_Printf)( char *fmt, ... ); + double (*Sys_FloatTime)( void ); + void (*PM_StuckTouch)( int hitent, pmtrace_t *ptraceresult ); + int (*PM_PointContents) (vec3_t p, int *truecontents /*filled in if this is non-null*/ ); + int (*PM_TruePointContents) (vec3_t p); + int (*PM_HullPointContents) ( struct hull_s *hull, int num, vec3_t p); + pmtrace_t (*PM_PlayerTrace) (vec3_t start, vec3_t end, int traceFlags, int ignore_pe ); + struct pmtrace_s *(*PM_TraceLine)( float *start, float *end, int flags, int usehulll, int ignore_pe ); + long (*RandomLong)( long lLow, long lHigh ); + float (*RandomFloat)( float flLow, float flHigh ); + int (*PM_GetModelType)( struct model_s *mod ); + void (*PM_GetModelBounds)( struct model_s *mod, vec3_t mins, vec3_t maxs ); + void *(*PM_HullForBsp)( physent_t *pe, vec3_t offset ); + float (*PM_TraceModel)( physent_t *pEnt, vec3_t start, vec3_t end, trace_t *trace ); + int (*COM_FileSize)(char *filename); + byte *(*COM_LoadFile) (char *path, int usehunk, int *pLength); + void (*COM_FreeFile) ( void *buffer ); + char *(*memfgets)( byte *pMemFile, int fileSize, int *pFilePos, char *pBuffer, int bufferSize ); + + // Functions + // Run functions for this frame? + qboolean runfuncs; + void (*PM_PlaySound) ( int channel, const char *sample, float volume, float attenuation, int fFlags, int pitch ); + const char *(*PM_TraceTexture) ( int ground, vec3_t vstart, vec3_t vend ); + void (*PM_PlaybackEventFull) ( int flags, int clientindex, unsigned short eventindex, float delay, float *origin, float *angles, float fparam1, float fparam2, int iparam1, int iparam2, int bparam1, int bparam2 ); +}; + +#endif diff --git a/pm_shared/pm_info.h b/pm_shared/pm_info.h new file mode 100644 index 0000000..fd380d1 --- /dev/null +++ b/pm_shared/pm_info.h @@ -0,0 +1,22 @@ +/*** +* +* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +// Physics info string definition +#if !defined( PM_INFOH ) +#define PM_INFOH +#pragma once + +#define MAX_PHYSINFO_STRING 256 + +#endif // PM_INFOH \ No newline at end of file diff --git a/pm_shared/pm_materials.h b/pm_shared/pm_materials.h new file mode 100644 index 0000000..8974238 --- /dev/null +++ b/pm_shared/pm_materials.h @@ -0,0 +1,33 @@ +/*** +* +* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +#if !defined( PM_MATERIALSH ) +#define PM_MATERIALSH +#pragma once + +#define CBTEXTURENAMEMAX 13 // only load first n chars of name + +#define CHAR_TEX_CONCRETE 'C' // texture types +#define CHAR_TEX_METAL 'M' +#define CHAR_TEX_DIRT 'D' +#define CHAR_TEX_VENT 'V' +#define CHAR_TEX_GRATE 'G' +#define CHAR_TEX_TILE 'T' +#define CHAR_TEX_SLOSH 'S' +#define CHAR_TEX_WOOD 'W' +#define CHAR_TEX_COMPUTER 'P' +#define CHAR_TEX_GLASS 'Y' +#define CHAR_TEX_FLESH 'F' + +#endif // !PM_MATERIALSH \ No newline at end of file diff --git a/pm_shared/pm_math.c b/pm_shared/pm_math.c new file mode 100644 index 0000000..51c59f9 --- /dev/null +++ b/pm_shared/pm_math.c @@ -0,0 +1,338 @@ +/*** +* +* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +// pm_math.c -- math primitives + +#include "mathlib.h" +#include "const.h" +#include + +// up / down +#define PITCH 0 +// left / right +#define YAW 1 +// fall over +#define ROLL 2 + +#pragma warning(disable : 4244) + +vec3_t vec3_origin = {0,0,0}; +int nanmask = 255<<23; + +float anglemod(float a) +{ + a = (360.0/65536) * ((int)(a*(65536/360.0)) & 65535); + return a; +} + +void AngleVectors (const vec3_t angles, vec3_t forward, vec3_t right, vec3_t up) +{ + float angle; + float sr, sp, sy, cr, cp, cy; + + angle = angles[YAW] * (M_PI*2 / 360); + sy = sin(angle); + cy = cos(angle); + angle = angles[PITCH] * (M_PI*2 / 360); + sp = sin(angle); + cp = cos(angle); + angle = angles[ROLL] * (M_PI*2 / 360); + sr = sin(angle); + cr = cos(angle); + + if (forward) + { + forward[0] = cp*cy; + forward[1] = cp*sy; + forward[2] = -sp; + } + if (right) + { + right[0] = (-1*sr*sp*cy+-1*cr*-sy); + right[1] = (-1*sr*sp*sy+-1*cr*cy); + right[2] = -1*sr*cp; + } + if (up) + { + up[0] = (cr*sp*cy+-sr*-sy); + up[1] = (cr*sp*sy+-sr*cy); + up[2] = cr*cp; + } +} + +void AngleVectorsTranspose (const vec3_t angles, vec3_t forward, vec3_t right, vec3_t up) +{ + float angle; + float sr, sp, sy, cr, cp, cy; + + angle = angles[YAW] * (M_PI*2 / 360); + sy = sin(angle); + cy = cos(angle); + angle = angles[PITCH] * (M_PI*2 / 360); + sp = sin(angle); + cp = cos(angle); + angle = angles[ROLL] * (M_PI*2 / 360); + sr = sin(angle); + cr = cos(angle); + + if (forward) + { + forward[0] = cp*cy; + forward[1] = (sr*sp*cy+cr*-sy); + forward[2] = (cr*sp*cy+-sr*-sy); + } + if (right) + { + right[0] = cp*sy; + right[1] = (sr*sp*sy+cr*cy); + right[2] = (cr*sp*sy+-sr*cy); + } + if (up) + { + up[0] = -sp; + up[1] = sr*cp; + up[2] = cr*cp; + } +} + + +void AngleMatrix (const vec3_t angles, float (*matrix)[4] ) +{ + float angle; + float sr, sp, sy, cr, cp, cy; + + angle = angles[YAW] * (M_PI*2 / 360); + sy = sin(angle); + cy = cos(angle); + angle = angles[PITCH] * (M_PI*2 / 360); + sp = sin(angle); + cp = cos(angle); + angle = angles[ROLL] * (M_PI*2 / 360); + sr = sin(angle); + cr = cos(angle); + + // matrix = (YAW * PITCH) * ROLL + matrix[0][0] = cp*cy; + matrix[1][0] = cp*sy; + matrix[2][0] = -sp; + matrix[0][1] = sr*sp*cy+cr*-sy; + matrix[1][1] = sr*sp*sy+cr*cy; + matrix[2][1] = sr*cp; + matrix[0][2] = (cr*sp*cy+-sr*-sy); + matrix[1][2] = (cr*sp*sy+-sr*cy); + matrix[2][2] = cr*cp; + matrix[0][3] = 0.0; + matrix[1][3] = 0.0; + matrix[2][3] = 0.0; +} + +void AngleIMatrix (const vec3_t angles, float matrix[3][4] ) +{ + float angle; + float sr, sp, sy, cr, cp, cy; + + angle = angles[YAW] * (M_PI*2 / 360); + sy = sin(angle); + cy = cos(angle); + angle = angles[PITCH] * (M_PI*2 / 360); + sp = sin(angle); + cp = cos(angle); + angle = angles[ROLL] * (M_PI*2 / 360); + sr = sin(angle); + cr = cos(angle); + + // matrix = (YAW * PITCH) * ROLL + matrix[0][0] = cp*cy; + matrix[0][1] = cp*sy; + matrix[0][2] = -sp; + matrix[1][0] = sr*sp*cy+cr*-sy; + matrix[1][1] = sr*sp*sy+cr*cy; + matrix[1][2] = sr*cp; + matrix[2][0] = (cr*sp*cy+-sr*-sy); + matrix[2][1] = (cr*sp*sy+-sr*cy); + matrix[2][2] = cr*cp; + matrix[0][3] = 0.0; + matrix[1][3] = 0.0; + matrix[2][3] = 0.0; +} + + +void VectorTransform (const vec3_t in1, float in2[3][4], vec3_t out) +{ + out[0] = DotProduct(in1, in2[0]) + in2[0][3]; + out[1] = DotProduct(in1, in2[1]) + in2[1][3]; + out[2] = DotProduct(in1, in2[2]) + in2[2][3]; +} + + +int VectorCompare (const vec3_t v1, const vec3_t v2) +{ + int i; + + for (i=0 ; i<3 ; i++) + if (v1[i] != v2[i]) + return 0; + + return 1; +} + +void VectorMA (const vec3_t veca, float scale, const vec3_t vecb, vec3_t vecc) +{ + vecc[0] = veca[0] + scale*vecb[0]; + vecc[1] = veca[1] + scale*vecb[1]; + vecc[2] = veca[2] + scale*vecb[2]; +} + + +vec_t _DotProduct (vec3_t v1, vec3_t v2) +{ + return v1[0]*v2[0] + v1[1]*v2[1] + v1[2]*v2[2]; +} + +void _VectorSubtract (vec3_t veca, vec3_t vecb, vec3_t out) +{ + out[0] = veca[0]-vecb[0]; + out[1] = veca[1]-vecb[1]; + out[2] = veca[2]-vecb[2]; +} + +void _VectorAdd (vec3_t veca, vec3_t vecb, vec3_t out) +{ + out[0] = veca[0]+vecb[0]; + out[1] = veca[1]+vecb[1]; + out[2] = veca[2]+vecb[2]; +} + +void _VectorCopy (vec3_t in, vec3_t out) +{ + out[0] = in[0]; + out[1] = in[1]; + out[2] = in[2]; +} + +void CrossProduct (const vec3_t v1, const vec3_t v2, vec3_t cross) +{ + cross[0] = v1[1]*v2[2] - v1[2]*v2[1]; + cross[1] = v1[2]*v2[0] - v1[0]*v2[2]; + cross[2] = v1[0]*v2[1] - v1[1]*v2[0]; +} + +double sqrt(double x); + +float Length(const vec3_t v) +{ + int i; + float length; + + length = 0; + for (i=0 ; i< 3 ; i++) + length += v[i]*v[i]; + length = sqrt (length); // FIXME + + return length; +} + +float VectorNormalize (vec3_t v) +{ + float length, ilength; + + length = v[0]*v[0] + v[1]*v[1] + v[2]*v[2]; + length = sqrt (length); // FIXME + + if (length) + { + ilength = 1/length; + v[0] *= ilength; + v[1] *= ilength; + v[2] *= ilength; + } + + return length; + +} + +void VectorInverse (vec3_t v) +{ + v[0] = -v[0]; + v[1] = -v[1]; + v[2] = -v[2]; +} + +void VectorScale (const vec3_t in, vec_t scale, vec3_t out) +{ + out[0] = in[0]*scale; + out[1] = in[1]*scale; + out[2] = in[2]*scale; +} + + +int Q_log2(int val) +{ + int answer=0; + while (val>>=1) + answer++; + return answer; +} + +void VectorMatrix( vec3_t forward, vec3_t right, vec3_t up) +{ + vec3_t tmp; + + if (forward[0] == 0 && forward[1] == 0) + { + right[0] = 1; + right[1] = 0; + right[2] = 0; + up[0] = -forward[2]; + up[1] = 0; + up[2] = 0; + return; + } + + tmp[0] = 0; tmp[1] = 0; tmp[2] = 1.0; + CrossProduct( forward, tmp, right ); + VectorNormalize( right ); + CrossProduct( right, forward, up ); + VectorNormalize( up ); +} + + +void VectorAngles( const vec3_t forward, vec3_t angles ) +{ + float tmp, yaw, pitch; + + if (forward[1] == 0 && forward[0] == 0) + { + yaw = 0; + if (forward[2] > 0) + pitch = 90; + else + pitch = 270; + } + else + { + yaw = (atan2(forward[1], forward[0]) * 180 / M_PI); + if (yaw < 0) + yaw += 360; + + tmp = sqrt (forward[0]*forward[0] + forward[1]*forward[1]); + pitch = (atan2(forward[2], tmp) * 180 / M_PI); + if (pitch < 0) + pitch += 360; + } + + angles[0] = pitch; + angles[1] = yaw; + angles[2] = 0; +} \ No newline at end of file diff --git a/pm_shared/pm_movevars.h b/pm_shared/pm_movevars.h new file mode 100644 index 0000000..61bfd05 --- /dev/null +++ b/pm_shared/pm_movevars.h @@ -0,0 +1,40 @@ +// pm_movevars.h +#if !defined( PM_MOVEVARSH ) +#define PM_MOVEVARSH + +// movevars_t // Physics variables. +typedef struct movevars_s movevars_t; + +struct movevars_s +{ + float gravity; // Gravity for map + float stopspeed; // Deceleration when not moving + float maxspeed; // Max allowed speed + float spectatormaxspeed; + float accelerate; // Acceleration factor + float airaccelerate; // Same for when in open air + float wateraccelerate; // Same for when in water + float friction; + float edgefriction; // Extra friction near dropofs + float waterfriction; // Less in water + float entgravity; // 1.0 + float bounce; // Wall bounce value. 1.0 + float stepsize; // sv_stepsize; + float maxvelocity; // maximum server velocity. + float zmax; // Max z-buffer range (for GL) + float waveHeight; // Water wave height (for GL) + qboolean footsteps; // Play footstep sounds + char skyName[32]; // Name of the sky map + float rollangle; + float rollspeed; + float skycolor_r; // Sky color + float skycolor_g; // + float skycolor_b; // + float skyvec_x; // Sky vector + float skyvec_y; // + float skyvec_z; // +}; + +extern movevars_t movevars; + +#endif \ No newline at end of file diff --git a/pm_shared/pm_shared.c b/pm_shared/pm_shared.c new file mode 100644 index 0000000..f97c42b --- /dev/null +++ b/pm_shared/pm_shared.c @@ -0,0 +1,3335 @@ +/*** +* +* Copyright (c) 1999, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ + +#include +#include "mathlib.h" +#include "const.h" +#include "usercmd.h" +#include "pm_defs.h" +#include "pm_shared.h" +#include "pm_movevars.h" +#include "pm_debug.h" +#include // NULL +#include // sqrt +#include // strcpy +#include // atoi +#include // isspace + +#ifdef CLIENT_DLL + // Spectator Mode + float vecNewViewAngles[3]; + float vecNewViewOrigin[3]; + int iHasNewViewAngles; + int iHasNewViewOrigin; + int iIsSpectator; +#endif + +static int pm_shared_initialized = 0; + +#pragma warning( disable : 4305 ) + +typedef enum {mod_brush, mod_sprite, mod_alias, mod_studio} modtype_t; + +playermove_t *pmove = NULL; + +typedef struct +{ + int planenum; + short children[2]; // negative numbers are contents +} dclipnode_t; + +typedef struct mplane_s +{ + vec3_t normal; // surface normal + float dist; // closest appoach to origin + byte type; // for texture axis selection and fast side tests + byte signbits; // signx + signy<<1 + signz<<1 + byte pad[2]; +} mplane_t; + +typedef struct hull_s +{ + dclipnode_t *clipnodes; + mplane_t *planes; + int firstclipnode; + int lastclipnode; + vec3_t clip_mins; + vec3_t clip_maxs; +} hull_t; + +// Ducking time +#define TIME_TO_DUCK 0.4 +#define VEC_DUCK_HULL_MIN -18 +#define VEC_DUCK_HULL_MAX 18 +#define VEC_DUCK_VIEW 12 +#define PM_DEAD_VIEWHEIGHT -8 +#define MAX_CLIMB_SPEED 200 +#define STUCK_MOVEUP 1 +#define STUCK_MOVEDOWN -1 +#define VEC_HULL_MIN -36 +#define VEC_HULL_MAX 36 +#define VEC_VIEW 28 +#define STOP_EPSILON 0.1 + +#define CTEXTURESMAX 512 // max number of textures loaded +#define CBTEXTURENAMEMAX 13 // only load first n chars of name + +#define CHAR_TEX_CONCRETE 'C' // texture types +#define CHAR_TEX_METAL 'M' +#define CHAR_TEX_DIRT 'D' +#define CHAR_TEX_VENT 'V' +#define CHAR_TEX_GRATE 'G' +#define CHAR_TEX_TILE 'T' +#define CHAR_TEX_SLOSH 'S' +#define CHAR_TEX_WOOD 'W' +#define CHAR_TEX_COMPUTER 'P' +#define CHAR_TEX_GLASS 'Y' +#define CHAR_TEX_FLESH 'F' + +#define STEP_CONCRETE 0 // default step sound +#define STEP_METAL 1 // metal floor +#define STEP_DIRT 2 // dirt, sand, rock +#define STEP_VENT 3 // ventillation duct +#define STEP_GRATE 4 // metal grating +#define STEP_TILE 5 // floor tiles +#define STEP_SLOSH 6 // shallow liquid puddle +#define STEP_WADE 7 // wading in liquid +#define STEP_LADDER 8 // climbing ladder + +#define PLAYER_FATAL_FALL_SPEED 1024// approx 60 feet +#define PLAYER_MAX_SAFE_FALL_SPEED 580// approx 20 feet +#define DAMAGE_FOR_FALL_SPEED (float) 100 / ( PLAYER_FATAL_FALL_SPEED - PLAYER_MAX_SAFE_FALL_SPEED )// damage per unit per second. +#define PLAYER_MIN_BOUNCE_SPEED 200 +#define PLAYER_FALL_PUNCH_THRESHHOLD (float)350 // won't punch player's screen/make scrape noise unless player falling at least this fast. + +#define PLAYER_LONGJUMP_SPEED 350 // how fast we longjump + +// double to float warning +#pragma warning(disable : 4244) +#define max(a, b) (((a) > (b)) ? (a) : (b)) +#define min(a, b) (((a) < (b)) ? (a) : (b)) +// up / down +#define PITCH 0 +// left / right +#define YAW 1 +// fall over +#define ROLL 2 + +#define MAX_CLIENTS 32 + +#define CONTENTS_CURRENT_0 -9 +#define CONTENTS_CURRENT_90 -10 +#define CONTENTS_CURRENT_180 -11 +#define CONTENTS_CURRENT_270 -12 +#define CONTENTS_CURRENT_UP -13 +#define CONTENTS_CURRENT_DOWN -14 + +#define CONTENTS_TRANSLUCENT -15 + +static vec3_t rgv3tStuckTable[54]; +static int rgStuckLast[MAX_CLIENTS][2]; + +// Texture names +static int gcTextures = 0; +static char grgszTextureName[CTEXTURESMAX][CBTEXTURENAMEMAX]; +static char grgchTextureType[CTEXTURESMAX]; + +int g_onladder = 0; + +void PM_SwapTextures( int i, int j ) +{ + char chTemp; + char szTemp[ CBTEXTURENAMEMAX ]; + + strcpy( szTemp, grgszTextureName[ i ] ); + chTemp = grgchTextureType[ i ]; + + strcpy( grgszTextureName[ i ], grgszTextureName[ j ] ); + grgchTextureType[ i ] = grgchTextureType[ j ]; + + strcpy( grgszTextureName[ j ], szTemp ); + grgchTextureType[ j ] = chTemp; +} + +void PM_SortTextures( void ) +{ + // Bubble sort, yuck, but this only occurs at startup and it's only 512 elements... + // + int i, j; + + for ( i = 0 ; i < gcTextures; i++ ) + { + for ( j = i + 1; j < gcTextures; j++ ) + { + if ( stricmp( grgszTextureName[ i ], grgszTextureName[ j ] ) > 0 ) + { + // Swap + // + PM_SwapTextures( i, j ); + } + } + } +} + +void PM_InitTextureTypes() +{ + char buffer[512]; + int i, j; + byte *pMemFile; + int fileSize, filePos; + static qboolean bTextureTypeInit = false; + + if ( bTextureTypeInit ) + return; + + memset(&(grgszTextureName[0][0]), 0, CTEXTURESMAX * CBTEXTURENAMEMAX); + memset(grgchTextureType, 0, CTEXTURESMAX); + + gcTextures = 0; + memset(buffer, 0, 512); + + fileSize = pmove->COM_FileSize( "sound/materials.txt" ); + pMemFile = pmove->COM_LoadFile( "sound/materials.txt", 5, NULL ); + if ( !pMemFile ) + return; + + filePos = 0; + // for each line in the file... + while ( pmove->memfgets( pMemFile, fileSize, &filePos, buffer, 511 ) != NULL && (gcTextures < CTEXTURESMAX) ) + { + // skip whitespace + i = 0; + while(buffer[i] && isspace(buffer[i])) + i++; + + if (!buffer[i]) + continue; + + // skip comment lines + if (buffer[i] == '/' || !isalpha(buffer[i])) + continue; + + // get texture type + grgchTextureType[gcTextures] = toupper(buffer[i++]); + + // skip whitespace + while(buffer[i] && isspace(buffer[i])) + i++; + + if (!buffer[i]) + continue; + + // get sentence name + j = i; + while (buffer[j] && !isspace(buffer[j])) + j++; + + if (!buffer[j]) + continue; + + // null-terminate name and save in sentences array + j = min (j, CBTEXTURENAMEMAX-1+i); + buffer[j] = 0; + strcpy(&(grgszTextureName[gcTextures++][0]), &(buffer[i])); + } + + // Must use engine to free since we are in a .dll + pmove->COM_FreeFile ( pMemFile ); + + PM_SortTextures(); + + bTextureTypeInit = true; +} + +char PM_FindTextureType( char *name ) +{ + int left, right, pivot; + int val; + + assert( pm_shared_initialized ); + + left = 0; + right = gcTextures - 1; + + while ( left <= right ) + { + pivot = ( left + right ) / 2; + + val = strnicmp( name, grgszTextureName[ pivot ], CBTEXTURENAMEMAX-1 ); + if ( val == 0 ) + { + return grgchTextureType[ pivot ]; + } + else if ( val > 0 ) + { + left = pivot + 1; + } + else if ( val < 0 ) + { + right = pivot - 1; + } + } + + return CHAR_TEX_CONCRETE; +} + +void PM_PlayStepSound( int step, float fvol ) +{ + static int iSkipStep = 0; + int irand; + vec3_t hvel; + + pmove->iStepLeft = !pmove->iStepLeft; + + if ( !pmove->runfuncs ) + { + return; + } + + irand = pmove->RandomLong(0,1) + ( pmove->iStepLeft * 2 ); + + // FIXME mp_footsteps needs to be a movevar + if ( pmove->multiplayer && !pmove->movevars->footsteps ) + return; + + VectorCopy( pmove->velocity, hvel ); + hvel[2] = 0.0; + + if ( pmove->multiplayer && ( !g_onladder && Length( hvel ) <= 220 ) ) + return; + + // irand - 0,1 for right foot, 2,3 for left foot + // used to alternate left and right foot + // FIXME, move to player state + + switch (step) + { + default: + case STEP_CONCRETE: + switch (irand) + { + // right foot + case 0: pmove->PM_PlaySound( CHAN_BODY, "player/pl_step1.wav", fvol, ATTN_NORM, 0, PITCH_NORM ); break; + case 1: pmove->PM_PlaySound( CHAN_BODY, "player/pl_step3.wav", fvol, ATTN_NORM, 0, PITCH_NORM ); break; + // left foot + case 2: pmove->PM_PlaySound( CHAN_BODY, "player/pl_step2.wav", fvol, ATTN_NORM, 0, PITCH_NORM ); break; + case 3: pmove->PM_PlaySound( CHAN_BODY, "player/pl_step4.wav", fvol, ATTN_NORM, 0, PITCH_NORM ); break; + } + break; + case STEP_METAL: + switch(irand) + { + // right foot + case 0: pmove->PM_PlaySound( CHAN_BODY, "player/pl_metal1.wav", fvol, ATTN_NORM, 0, PITCH_NORM ); break; + case 1: pmove->PM_PlaySound( CHAN_BODY, "player/pl_metal3.wav", fvol, ATTN_NORM, 0, PITCH_NORM ); break; + // left foot + case 2: pmove->PM_PlaySound( CHAN_BODY, "player/pl_metal2.wav", fvol, ATTN_NORM, 0, PITCH_NORM ); break; + case 3: pmove->PM_PlaySound( CHAN_BODY, "player/pl_metal4.wav", fvol, ATTN_NORM, 0, PITCH_NORM ); break; + } + break; + case STEP_DIRT: + switch(irand) + { + // right foot + case 0: pmove->PM_PlaySound( CHAN_BODY, "player/pl_dirt1.wav", fvol, ATTN_NORM, 0, PITCH_NORM ); break; + case 1: pmove->PM_PlaySound( CHAN_BODY, "player/pl_dirt3.wav", fvol, ATTN_NORM, 0, PITCH_NORM ); break; + // left foot + case 2: pmove->PM_PlaySound( CHAN_BODY, "player/pl_dirt2.wav", fvol, ATTN_NORM, 0, PITCH_NORM ); break; + case 3: pmove->PM_PlaySound( CHAN_BODY, "player/pl_dirt4.wav", fvol, ATTN_NORM, 0, PITCH_NORM ); break; + } + break; + case STEP_VENT: + switch(irand) + { + // right foot + case 0: pmove->PM_PlaySound( CHAN_BODY, "player/pl_duct1.wav", fvol, ATTN_NORM, 0, PITCH_NORM ); break; + case 1: pmove->PM_PlaySound( CHAN_BODY, "player/pl_duct3.wav", fvol, ATTN_NORM, 0, PITCH_NORM ); break; + // left foot + case 2: pmove->PM_PlaySound( CHAN_BODY, "player/pl_duct2.wav", fvol, ATTN_NORM, 0, PITCH_NORM ); break; + case 3: pmove->PM_PlaySound( CHAN_BODY, "player/pl_duct4.wav", fvol, ATTN_NORM, 0, PITCH_NORM ); break; + } + break; + case STEP_GRATE: + switch(irand) + { + // right foot + case 0: pmove->PM_PlaySound( CHAN_BODY, "player/pl_grate1.wav", fvol, ATTN_NORM, 0, PITCH_NORM ); break; + case 1: pmove->PM_PlaySound( CHAN_BODY, "player/pl_grate3.wav", fvol, ATTN_NORM, 0, PITCH_NORM ); break; + // left foot + case 2: pmove->PM_PlaySound( CHAN_BODY, "player/pl_grate2.wav", fvol, ATTN_NORM, 0, PITCH_NORM ); break; + case 3: pmove->PM_PlaySound( CHAN_BODY, "player/pl_grate4.wav", fvol, ATTN_NORM, 0, PITCH_NORM ); break; + } + break; + case STEP_TILE: + if ( !pmove->RandomLong(0,4) ) + irand = 4; + switch(irand) + { + // right foot + case 0: pmove->PM_PlaySound( CHAN_BODY, "player/pl_tile1.wav", fvol, ATTN_NORM, 0, PITCH_NORM ); break; + case 1: pmove->PM_PlaySound( CHAN_BODY, "player/pl_tile3.wav", fvol, ATTN_NORM, 0, PITCH_NORM ); break; + // left foot + case 2: pmove->PM_PlaySound( CHAN_BODY, "player/pl_tile2.wav", fvol, ATTN_NORM, 0, PITCH_NORM ); break; + case 3: pmove->PM_PlaySound( CHAN_BODY, "player/pl_tile4.wav", fvol, ATTN_NORM, 0, PITCH_NORM ); break; + case 4: pmove->PM_PlaySound( CHAN_BODY, "player/pl_tile5.wav", fvol, ATTN_NORM, 0, PITCH_NORM ); break; + } + break; + case STEP_SLOSH: + switch(irand) + { + // right foot + case 0: pmove->PM_PlaySound( CHAN_BODY, "player/pl_slosh1.wav", fvol, ATTN_NORM, 0, PITCH_NORM ); break; + case 1: pmove->PM_PlaySound( CHAN_BODY, "player/pl_slosh3.wav", fvol, ATTN_NORM, 0, PITCH_NORM ); break; + // left foot + case 2: pmove->PM_PlaySound( CHAN_BODY, "player/pl_slosh2.wav", fvol, ATTN_NORM, 0, PITCH_NORM ); break; + case 3: pmove->PM_PlaySound( CHAN_BODY, "player/pl_slosh4.wav", fvol, ATTN_NORM, 0, PITCH_NORM ); break; + } + break; + case STEP_WADE: + if ( iSkipStep == 0 ) + { + iSkipStep++; + break; + } + + if ( iSkipStep++ == 3 ) + { + iSkipStep = 0; + } + + switch (irand) + { + // right foot + case 0: pmove->PM_PlaySound( CHAN_BODY, "player/pl_wade1.wav", fvol, ATTN_NORM, 0, PITCH_NORM ); break; + case 1: pmove->PM_PlaySound( CHAN_BODY, "player/pl_wade2.wav", fvol, ATTN_NORM, 0, PITCH_NORM ); break; + // left foot + case 2: pmove->PM_PlaySound( CHAN_BODY, "player/pl_wade3.wav", fvol, ATTN_NORM, 0, PITCH_NORM ); break; + case 3: pmove->PM_PlaySound( CHAN_BODY, "player/pl_wade4.wav", fvol, ATTN_NORM, 0, PITCH_NORM ); break; + } + break; + case STEP_LADDER: + switch(irand) + { + // right foot + case 0: pmove->PM_PlaySound( CHAN_BODY, "player/pl_ladder1.wav", fvol, ATTN_NORM, 0, PITCH_NORM ); break; + case 1: pmove->PM_PlaySound( CHAN_BODY, "player/pl_ladder3.wav", fvol, ATTN_NORM, 0, PITCH_NORM ); break; + // left foot + case 2: pmove->PM_PlaySound( CHAN_BODY, "player/pl_ladder2.wav", fvol, ATTN_NORM, 0, PITCH_NORM ); break; + case 3: pmove->PM_PlaySound( CHAN_BODY, "player/pl_ladder4.wav", fvol, ATTN_NORM, 0, PITCH_NORM ); break; + } + break; + } +} + +int PM_MapTextureTypeStepType(char chTextureType) +{ + switch (chTextureType) + { + default: + case CHAR_TEX_CONCRETE: return STEP_CONCRETE; + case CHAR_TEX_METAL: return STEP_METAL; + case CHAR_TEX_DIRT: return STEP_DIRT; + case CHAR_TEX_VENT: return STEP_VENT; + case CHAR_TEX_GRATE: return STEP_GRATE; + case CHAR_TEX_TILE: return STEP_TILE; + case CHAR_TEX_SLOSH: return STEP_SLOSH; + } +} + +/* +==================== +PM_CatagorizeTextureType + +Determine texture info for the texture we are standing on. +==================== +*/ +void PM_CatagorizeTextureType( void ) +{ + vec3_t start, end; + const char *pTextureName; + + VectorCopy( pmove->origin, start ); + VectorCopy( pmove->origin, end ); + + // Straight down + end[2] -= 64; + + // Fill in default values, just in case. + pmove->sztexturename[0] = '\0'; + pmove->chtexturetype = CHAR_TEX_CONCRETE; + + pTextureName = pmove->PM_TraceTexture( pmove->onground, start, end ); + if ( !pTextureName ) + return; + + // strip leading '-0' or '+0~' or '{' or '!' + if (*pTextureName == '-' || *pTextureName == '+') + pTextureName += 2; + + if (*pTextureName == '{' || *pTextureName == '!' || *pTextureName == '~' || *pTextureName == ' ') + pTextureName++; + // '}}' + + strcpy( pmove->sztexturename, pTextureName); + pmove->sztexturename[ CBTEXTURENAMEMAX - 1 ] = 0; + + // get texture type + pmove->chtexturetype = PM_FindTextureType( pmove->sztexturename ); +} + +void PM_UpdateStepSound( void ) +{ + int fWalking; + float fvol; + vec3_t knee; + vec3_t feet; + vec3_t center; + float height; + float speed; + float velrun; + float velwalk; + float flduck; + int fLadder; + int step; + + if ( pmove->flTimeStepSound > 0 ) + return; + + if ( pmove->flags & FL_FROZEN ) + return; + + PM_CatagorizeTextureType(); + + speed = Length( pmove->velocity ); + + // determine if we are on a ladder + fLadder = ( pmove->movetype == MOVETYPE_FLY );// IsOnLadder(); + + // UNDONE: need defined numbers for run, walk, crouch, crouch run velocities!!!! + if ( ( pmove->flags & FL_DUCKING) || fLadder ) + { + velwalk = 60; // These constants should be based on cl_movespeedkey * cl_forwardspeed somehow + velrun = 80; // UNDONE: Move walking to server + flduck = 100; + } + else + { + velwalk = 120; + velrun = 210; + flduck = 0; + } + + // If we're on a ladder or on the ground, and we're moving fast enough, + // play step sound. Also, if pmove->flTimeStepSound is zero, get the new + // sound right away - we just started moving in new level. + if ( (fLadder || ( pmove->onground != -1 ) ) && + ( Length( pmove->velocity ) > 0.0 ) && + ( speed >= velwalk || !pmove->flTimeStepSound ) ) + { + fWalking = speed < velrun; + + VectorCopy( pmove->origin, center ); + VectorCopy( pmove->origin, knee ); + VectorCopy( pmove->origin, feet ); + + height = pmove->player_maxs[ pmove->usehull ][ 2 ] - pmove->player_mins[ pmove->usehull ][ 2 ]; + + knee[2] = pmove->origin[2] - 0.3 * height; + feet[2] = pmove->origin[2] - 0.5 * height; + + // find out what we're stepping in or on... + if (fLadder) + { + step = STEP_LADDER; + fvol = 0.35; + pmove->flTimeStepSound = 350; + } + else if ( pmove->PM_PointContents ( knee, NULL ) == CONTENTS_WATER ) + { + step = STEP_WADE; + fvol = 0.65; + pmove->flTimeStepSound = 600; + } + else if ( pmove->PM_PointContents ( feet, NULL ) == CONTENTS_WATER ) + { + step = STEP_SLOSH; + fvol = fWalking ? 0.2 : 0.5; + pmove->flTimeStepSound = fWalking ? 400 : 300; + } + else + { + // find texture under player, if different from current texture, + // get material type + step = PM_MapTextureTypeStepType( pmove->chtexturetype ); + + switch ( pmove->chtexturetype ) + { + default: + case CHAR_TEX_CONCRETE: + fvol = fWalking ? 0.2 : 0.5; + pmove->flTimeStepSound = fWalking ? 400 : 300; + break; + + case CHAR_TEX_METAL: + fvol = fWalking ? 0.2 : 0.5; + pmove->flTimeStepSound = fWalking ? 400 : 300; + break; + + case CHAR_TEX_DIRT: + fvol = fWalking ? 0.25 : 0.55; + pmove->flTimeStepSound = fWalking ? 400 : 300; + break; + + case CHAR_TEX_VENT: + fvol = fWalking ? 0.4 : 0.7; + pmove->flTimeStepSound = fWalking ? 400 : 300; + break; + + case CHAR_TEX_GRATE: + fvol = fWalking ? 0.2 : 0.5; + pmove->flTimeStepSound = fWalking ? 400 : 300; + break; + + case CHAR_TEX_TILE: + fvol = fWalking ? 0.2 : 0.5; + pmove->flTimeStepSound = fWalking ? 400 : 300; + break; + + case CHAR_TEX_SLOSH: + fvol = fWalking ? 0.2 : 0.5; + pmove->flTimeStepSound = fWalking ? 400 : 300; + break; + } + } + + pmove->flTimeStepSound += flduck; // slower step time if ducking + + // play the sound + // 35% volume if ducking + if ( pmove->flags & FL_DUCKING ) + { + fvol *= 0.35; + } + + PM_PlayStepSound( step, fvol ); + } +} + +/* +================ +PM_AddToTouched + +Add's the trace result to touch list, if contact is not already in list. +================ +*/ +qboolean PM_AddToTouched(pmtrace_t tr, vec3_t impactvelocity) +{ + int i; + + for (i = 0; i < pmove->numtouch; i++) + { + if (pmove->touchindex[i].ent == tr.ent) + break; + } + if (i != pmove->numtouch) // Already in list. + return false; + + VectorCopy( impactvelocity, tr.deltavelocity ); + + if (pmove->numtouch >= MAX_PHYSENTS) + pmove->Con_DPrintf("Too many entities were touched!\n"); + + pmove->touchindex[pmove->numtouch++] = tr; + return true; +} + +/* +================ +PM_CheckVelocity + +See if the player has a bogus velocity value. +================ +*/ +void PM_CheckVelocity () +{ + int i; + +// +// bound velocity +// + for (i=0 ; i<3 ; i++) + { + // See if it's bogus. + if (IS_NAN(pmove->velocity[i])) + { + pmove->Con_Printf ("PM Got a NaN velocity %i\n", i); + pmove->velocity[i] = 0; + } + if (IS_NAN(pmove->origin[i])) + { + pmove->Con_Printf ("PM Got a NaN origin on %i\n", i); + pmove->origin[i] = 0; + } + + // Bound it. + if (pmove->velocity[i] > pmove->movevars->maxvelocity) + { + pmove->Con_DPrintf ("PM Got a velocity too high on %i\n", i); + pmove->velocity[i] = pmove->movevars->maxvelocity; + } + else if (pmove->velocity[i] < -pmove->movevars->maxvelocity) + { + pmove->Con_DPrintf ("PM Got a velocity too low on %i\n", i); + pmove->velocity[i] = -pmove->movevars->maxvelocity; + } + } +} + +/* +================== +PM_ClipVelocity + +Slide off of the impacting object +returns the blocked flags: +0x01 == floor +0x02 == step / wall +================== +*/ +int PM_ClipVelocity (vec3_t in, vec3_t normal, vec3_t out, float overbounce) +{ + float backoff; + float change; + float angle; + int i, blocked; + + angle = normal[ 2 ]; + + blocked = 0x00; // Assume unblocked. + if (angle > 0) // If the plane that is blocking us has a positive z component, then assume it's a floor. + blocked |= 0x01; // + if (!angle) // If the plane has no Z, it is vertical (wall/step) + blocked |= 0x02; // + + // Determine how far along plane to slide based on incoming direction. + // Scale by overbounce factor. + backoff = DotProduct (in, normal) * overbounce; + + for (i=0 ; i<3 ; i++) + { + change = normal[i]*backoff; + out[i] = in[i] - change; + // If out velocity is too small, zero it out. + if (out[i] > -STOP_EPSILON && out[i] < STOP_EPSILON) + out[i] = 0; + } + + // Return blocking flags. + return blocked; +} + +void PM_AddCorrectGravity () +{ + float ent_gravity; + + if ( pmove->waterjumptime ) + return; + + if (pmove->gravity) + ent_gravity = pmove->gravity; + else + ent_gravity = 1.0; + + // Add gravity so they'll be in the correct position during movement + // yes, this 0.5 looks wrong, but it's not. + pmove->velocity[2] -= (ent_gravity * pmove->movevars->gravity * 0.5 * pmove->frametime ); + pmove->velocity[2] += pmove->basevelocity[2] * pmove->frametime; + pmove->basevelocity[2] = 0; + + PM_CheckVelocity(); +} + + +void PM_FixupGravityVelocity () +{ + float ent_gravity; + + if ( pmove->waterjumptime ) + return; + + if (pmove->gravity) + ent_gravity = pmove->gravity; + else + ent_gravity = 1.0; + + // Get the correct velocity for the end of the dt + pmove->velocity[2] -= (ent_gravity * pmove->movevars->gravity * pmove->frametime * 0.5 ); + + PM_CheckVelocity(); +} + +/* +============ +PM_FlyMove + +The basic solid body movement clip that slides along multiple planes +============ +*/ +int PM_FlyMove (void) +{ + int bumpcount, numbumps; + vec3_t dir; + float d; + int numplanes; + vec3_t planes[MAX_CLIP_PLANES]; + vec3_t primal_velocity, original_velocity; + vec3_t new_velocity; + int i, j; + pmtrace_t trace; + vec3_t end; + float time_left, allFraction; + int blocked; + + numbumps = 4; // Bump up to four times + + blocked = 0; // Assume not blocked + numplanes = 0; // and not sliding along any planes + VectorCopy (pmove->velocity, original_velocity); // Store original velocity + VectorCopy (pmove->velocity, primal_velocity); + + allFraction = 0; + time_left = pmove->frametime; // Total time for this movement operation. + + for (bumpcount=0 ; bumpcountvelocity[0] && !pmove->velocity[1] && !pmove->velocity[2]) + break; + + // Assume we can move all the way from the current origin to the + // end point. + for (i=0 ; i<3 ; i++) + end[i] = pmove->origin[i] + time_left * pmove->velocity[i]; + + // See if we can make it from origin to end point. + trace = pmove->PM_PlayerTrace (pmove->origin, end, PM_NORMAL, -1 ); + + allFraction += trace.fraction; + // If we started in a solid object, or we were in solid space + // the whole way, zero out our velocity and return that we + // are blocked by floor and wall. + if (trace.allsolid) + { // entity is trapped in another solid + VectorCopy (vec3_origin, pmove->velocity); + //Con_DPrintf("Trapped 4\n"); + return 4; + } + + // If we moved some portion of the total distance, then + // copy the end position into the pmove->origin and + // zero the plane counter. + if (trace.fraction > 0) + { // actually covered some distance + VectorCopy (trace.endpos, pmove->origin); + VectorCopy (pmove->velocity, original_velocity); + numplanes = 0; + } + + // If we covered the entire distance, we are done + // and can return. + if (trace.fraction == 1) + break; // moved the entire distance + + //if (!trace.ent) + // Sys_Error ("PM_PlayerTrace: !trace.ent"); + + // Save entity that blocked us (since fraction was < 1.0) + // for contact + // Add it if it's not already in the list!!! + PM_AddToTouched(trace, pmove->velocity); + + // If the plane we hit has a high z component in the normal, then + // it's probably a floor + if (trace.plane.normal[2] > 0.7) + { + blocked |= 1; // floor + } + // If the plane has a zero z component in the normal, then it's a + // step or wall + if (!trace.plane.normal[2]) + { + blocked |= 2; // step / wall + //Con_DPrintf("Blocked by %i\n", trace.ent); + } + + // Reduce amount of pmove->frametime left by total time left * fraction + // that we covered. + time_left -= time_left * trace.fraction; + + // Did we run out of planes to clip against? + if (numplanes >= MAX_CLIP_PLANES) + { // this shouldn't really happen + // Stop our movement if so. + VectorCopy (vec3_origin, pmove->velocity); + //Con_DPrintf("Too many planes 4\n"); + + break; + } + + // Set up next clipping plane + VectorCopy (trace.plane.normal, planes[numplanes]); + numplanes++; +// + +// modify original_velocity so it parallels all of the clip planes +// + if ( pmove->movetype == MOVETYPE_WALK && + ((pmove->onground == -1) || (pmove->friction != 1)) ) // relfect player velocity + { + for ( i = 0; i < numplanes; i++ ) + { + if ( planes[i][2] > 0.7 ) + {// floor or slope + PM_ClipVelocity( original_velocity, planes[i], new_velocity, 1 ); + VectorCopy( new_velocity, original_velocity ); + } + else + PM_ClipVelocity( original_velocity, planes[i], new_velocity, 1.0 + pmove->movevars->bounce * (1-pmove->friction) ); + } + + VectorCopy( new_velocity, pmove->velocity ); + VectorCopy( new_velocity, original_velocity ); + } + else + { + for (i=0 ; ivelocity, + 1); + for (j=0 ; jvelocity, planes[j]) < 0) + break; // not ok + } + if (j == numplanes) // Didn't have to clip, so we're ok + break; + } + + // Did we go all the way through plane set + if (i != numplanes) + { // go along this plane + // pmove->velocity is set in clipping call, no need to set again. + ; + } + else + { // go along the crease + if (numplanes != 2) + { + //Con_Printf ("clip velocity, numplanes == %i\n",numplanes); + VectorCopy (vec3_origin, pmove->velocity); + //Con_DPrintf("Trapped 4\n"); + + break; + } + CrossProduct (planes[0], planes[1], dir); + d = DotProduct (dir, pmove->velocity); + VectorScale (dir, d, pmove->velocity ); + } + + // + // if original velocity is against the original velocity, stop dead + // to avoid tiny occilations in sloping corners + // + if (DotProduct (pmove->velocity, primal_velocity) <= 0) + { + //Con_DPrintf("Back\n"); + VectorCopy (vec3_origin, pmove->velocity); + break; + } + } + } + + if ( allFraction == 0 ) + { + VectorCopy (vec3_origin, pmove->velocity); + //Con_DPrintf( "Don't stick\n" ); + } + + return blocked; +} + +/* +============== +PM_Accelerate +============== +*/ +void PM_Accelerate (vec3_t wishdir, float wishspeed, float accel) +{ + int i; + float addspeed, accelspeed, currentspeed; + + // Dead player's don't accelerate + if (pmove->dead) + return; + + // If waterjumping, don't accelerate + if (pmove->waterjumptime) + return; + + // See if we are changing direction a bit + currentspeed = DotProduct (pmove->velocity, wishdir); + + // Reduce wishspeed by the amount of veer. + addspeed = wishspeed - currentspeed; + + // If not going to add any speed, done. + if (addspeed <= 0) + return; + + // Determine amount of accleration. + accelspeed = accel * pmove->frametime * wishspeed * pmove->friction; + + // Cap at addspeed + if (accelspeed > addspeed) + accelspeed = addspeed; + + // Adjust velocity. + for (i=0 ; i<3 ; i++) + { + pmove->velocity[i] += accelspeed * wishdir[i]; + } +} + +/* +===================== +PM_WalkMove + +Only used by players. Moves along the ground when player is a MOVETYPE_WALK. +====================== +*/ +void PM_WalkMove () +{ + int clip; + int oldonground; + int i; + + vec3_t wishvel; + float spd; + float fmove, smove; + vec3_t wishdir; + float wishspeed; + + vec3_t dest, start; + vec3_t original, originalvel; + vec3_t down, downvel; + float downdist, updist; + + pmtrace_t trace; + + // Copy movement amounts + fmove = pmove->cmd.forwardmove; + smove = pmove->cmd.sidemove; + + // Zero out z components of movement vectors + pmove->forward[2] = 0; + pmove->right[2] = 0; + + VectorNormalize (pmove->forward); // Normalize remainder of vectors. + VectorNormalize (pmove->right); // + + for (i=0 ; i<2 ; i++) // Determine x and y parts of velocity + wishvel[i] = pmove->forward[i]*fmove + pmove->right[i]*smove; + + wishvel[2] = 0; // Zero out z part of velocity + + VectorCopy (wishvel, wishdir); // Determine maginitude of speed of move + wishspeed = VectorNormalize(wishdir); + +// +// Clamp to server defined max speed +// + if (wishspeed > pmove->maxspeed) + { + VectorScale (wishvel, pmove->maxspeed/wishspeed, wishvel); + wishspeed = pmove->maxspeed; + } + + // Set pmove velocity + pmove->velocity[2] = 0; + PM_Accelerate (wishdir, wishspeed, pmove->movevars->accelerate); + pmove->velocity[2] = 0; + + // Add in any base velocity to the current velocity. + VectorAdd (pmove->velocity, pmove->basevelocity, pmove->velocity ); + + spd = Length( pmove->velocity ); + + if (spd < 1.0f) + { + VectorClear( pmove->velocity ); + return; + } + + // If we are not moving, do nothing + //if (!pmove->velocity[0] && !pmove->velocity[1] && !pmove->velocity[2]) + // return; + + oldonground = pmove->onground; + +// first try just moving to the destination + dest[0] = pmove->origin[0] + pmove->velocity[0]*pmove->frametime; + dest[1] = pmove->origin[1] + pmove->velocity[1]*pmove->frametime; + dest[2] = pmove->origin[2]; + + // first try moving directly to the next spot + VectorCopy (dest, start); + trace = pmove->PM_PlayerTrace (pmove->origin, dest, PM_NORMAL, -1 ); + // If we made it all the way, then copy trace end + // as new player position. + if (trace.fraction == 1) + { + VectorCopy (trace.endpos, pmove->origin); + return; + } + + if (oldonground == -1 && // Don't walk up stairs if not on ground. + pmove->waterlevel == 0) + return; + + if (pmove->waterjumptime) // If we are jumping out of water, don't do anything more. + return; + + // Try sliding forward both on ground and up 16 pixels + // take the move that goes farthest + VectorCopy (pmove->origin, original); // Save out original pos & + VectorCopy (pmove->velocity, originalvel); // velocity. + + // Slide move + clip = PM_FlyMove (); + + // Copy the results out + VectorCopy (pmove->origin , down); + VectorCopy (pmove->velocity, downvel); + + // Reset original values. + VectorCopy (original, pmove->origin); + + VectorCopy (originalvel, pmove->velocity); + + // Start out up one stair height + VectorCopy (pmove->origin, dest); + dest[2] += pmove->movevars->stepsize; + + trace = pmove->PM_PlayerTrace (pmove->origin, dest, PM_NORMAL, -1 ); + // If we started okay and made it part of the way at least, + // copy the results to the movement start position and then + // run another move try. + if (!trace.startsolid && !trace.allsolid) + { + VectorCopy (trace.endpos, pmove->origin); + } + +// slide move the rest of the way. + clip = PM_FlyMove (); + +// Now try going back down from the end point +// press down the stepheight + VectorCopy (pmove->origin, dest); + dest[2] -= pmove->movevars->stepsize; + + trace = pmove->PM_PlayerTrace (pmove->origin, dest, PM_NORMAL, -1 ); + + // If we are not on the ground any more then + // use the original movement attempt + if ( trace.plane.normal[2] < 0.7) + goto usedown; + // If the trace ended up in empty space, copy the end + // over to the origin. + if (!trace.startsolid && !trace.allsolid) + { + VectorCopy (trace.endpos, pmove->origin); + } + // Copy this origion to up. + VectorCopy (pmove->origin, pmove->up); + + // decide which one went farther + downdist = (down[0] - original[0])*(down[0] - original[0]) + + (down[1] - original[1])*(down[1] - original[1]); + updist = (pmove->up[0] - original[0])*(pmove->up[0] - original[0]) + + (pmove->up[1] - original[1])*(pmove->up[1] - original[1]); + + if (downdist > updist) + { +usedown: + VectorCopy (down , pmove->origin); + VectorCopy (downvel, pmove->velocity); + } else // copy z value from slide move + pmove->velocity[2] = downvel[2]; + +} + +/* +================== +PM_Friction + +Handles both ground friction and water friction +================== +*/ +void PM_Friction (void) +{ + float *vel; + float speed, newspeed, control; + float friction; + float drop; + vec3_t newvel; + + // If we are in water jump cycle, don't apply friction + if (pmove->waterjumptime) + return; + + // Get velocity + vel = pmove->velocity; + + // Calculate speed + speed = sqrt(vel[0]*vel[0] +vel[1]*vel[1] + vel[2]*vel[2]); + + // If too slow, return + if (speed < 0.1f) + { + return; + } + + drop = 0; + +// apply ground friction + if (pmove->onground != -1) // On an entity that is the ground + { + vec3_t start, stop; + pmtrace_t trace; + + start[0] = stop[0] = pmove->origin[0] + vel[0]/speed*16; + start[1] = stop[1] = pmove->origin[1] + vel[1]/speed*16; + start[2] = pmove->origin[2] + pmove->player_mins[pmove->usehull][2]; + stop[2] = start[2] - 34; + + trace = pmove->PM_PlayerTrace (start, stop, PM_NORMAL, -1 ); + + if (trace.fraction == 1.0) + friction = pmove->movevars->friction*pmove->movevars->edgefriction; + else + friction = pmove->movevars->friction; + + // Grab friction value. + //friction = pmove->movevars->friction; + + friction *= pmove->friction; // player friction? + + // Bleed off some speed, but if we have less than the bleed + // threshhold, bleed the theshold amount. + control = (speed < pmove->movevars->stopspeed) ? + pmove->movevars->stopspeed : speed; + // Add the amount to t'he drop amount. + drop += control*friction*pmove->frametime; + } + +// apply water friction +// if (pmove->waterlevel) +// drop += speed * pmove->movevars->waterfriction * waterlevel * pmove->frametime; + +// scale the velocity + newspeed = speed - drop; + if (newspeed < 0) + newspeed = 0; + + // Determine proportion of old speed we are using. + newspeed /= speed; + + // Adjust velocity according to proportion. + newvel[0] = vel[0] * newspeed; + newvel[1] = vel[1] * newspeed; + newvel[2] = vel[2] * newspeed; + + VectorCopy( newvel, pmove->velocity ); +} + +void PM_AirAccelerate (vec3_t wishdir, float wishspeed, float accel) +{ + int i; + float addspeed, accelspeed, currentspeed, wishspd = wishspeed; + + if (pmove->dead) + return; + if (pmove->waterjumptime) + return; + + // Cap speed + //wishspd = VectorNormalize (pmove->wishveloc); + + if (wishspd > 30) + wishspd = 30; + // Determine veer amount + currentspeed = DotProduct (pmove->velocity, wishdir); + // See how much to add + addspeed = wishspd - currentspeed; + // If not adding any, done. + if (addspeed <= 0) + return; + // Determine acceleration speed after acceleration + + accelspeed = accel * wishspeed * pmove->frametime * pmove->friction; + // Cap it + if (accelspeed > addspeed) + accelspeed = addspeed; + + // Adjust pmove vel. + for (i=0 ; i<3 ; i++) + { + pmove->velocity[i] += accelspeed*wishdir[i]; + } +} + +/* +=================== +PM_WaterMove + +=================== +*/ +void PM_WaterMove (void) +{ + int i; + vec3_t wishvel; + float wishspeed; + vec3_t wishdir; + vec3_t start, dest; + vec3_t temp; + pmtrace_t trace; + + float speed, newspeed, addspeed, accelspeed; + +// +// user intentions +// + for (i=0 ; i<3 ; i++) + wishvel[i] = pmove->forward[i]*pmove->cmd.forwardmove + pmove->right[i]*pmove->cmd.sidemove; + + // Sinking after no other movement occurs + if (!pmove->cmd.forwardmove && !pmove->cmd.sidemove && !pmove->cmd.upmove) + wishvel[2] -= 60; // drift towards bottom + else // Go straight up by upmove amount. + wishvel[2] += pmove->cmd.upmove; + + // Copy it over and determine speed + VectorCopy (wishvel, wishdir); + wishspeed = VectorNormalize(wishdir); + + // Cap speed. + if (wishspeed > pmove->maxspeed) + { + VectorScale (wishvel, pmove->maxspeed/wishspeed, wishvel); + wishspeed = pmove->maxspeed; + } + // Slow us down a bit. + wishspeed *= 0.8; + + VectorAdd (pmove->velocity, pmove->basevelocity, pmove->velocity); +// Water friction + VectorCopy(pmove->velocity, temp); + speed = VectorNormalize(temp); + if (speed) + { + newspeed = speed - pmove->frametime * speed * pmove->movevars->friction * pmove->friction; + + if (newspeed < 0) + newspeed = 0; + VectorScale (pmove->velocity, newspeed/speed, pmove->velocity); + } + else + newspeed = 0; + +// +// water acceleration +// + if ( wishspeed < 0.1f ) + { + return; + } + + addspeed = wishspeed - newspeed; + if (addspeed > 0) + { + + VectorNormalize(wishvel); + accelspeed = pmove->movevars->accelerate * wishspeed * pmove->frametime * pmove->friction; + if (accelspeed > addspeed) + accelspeed = addspeed; + + for (i = 0; i < 3; i++) + pmove->velocity[i] += accelspeed * wishvel[i]; + } + +// Now move +// assume it is a stair or a slope, so press down from stepheight above + VectorMA (pmove->origin, pmove->frametime, pmove->velocity, dest); + VectorCopy (dest, start); + start[2] += pmove->movevars->stepsize + 1; + trace = pmove->PM_PlayerTrace (start, dest, PM_NORMAL, -1 ); + if (!trace.startsolid && !trace.allsolid) // FIXME: check steep slope? + { // walked up the step, so just keep result and exit + VectorCopy (trace.endpos, pmove->origin); + return; + } + + // Try moving straight along out normal path. + PM_FlyMove (); +} + + +/* +=================== +PM_AirMove + +=================== +*/ +void PM_AirMove (void) +{ + int i; + vec3_t wishvel; + float fmove, smove; + vec3_t wishdir; + float wishspeed; + + // Copy movement amounts + fmove = pmove->cmd.forwardmove; + smove = pmove->cmd.sidemove; + + // Zero out z components of movement vectors + pmove->forward[2] = 0; + pmove->right[2] = 0; + // Renormalize + VectorNormalize (pmove->forward); + VectorNormalize (pmove->right); + + // Determine x and y parts of velocity + for (i=0 ; i<2 ; i++) + { + wishvel[i] = pmove->forward[i]*fmove + pmove->right[i]*smove; + } + // Zero out z part of velocity + wishvel[2] = 0; + + // Determine maginitude of speed of move + VectorCopy (wishvel, wishdir); + wishspeed = VectorNormalize(wishdir); + + // Clamp to server defined max speed + if (wishspeed > pmove->maxspeed) + { + VectorScale (wishvel, pmove->maxspeed/wishspeed, wishvel); + wishspeed = pmove->maxspeed; + } + + PM_AirAccelerate (wishdir, wishspeed, pmove->movevars->airaccelerate); + + // Add in any base velocity to the current velocity. + VectorAdd (pmove->velocity, pmove->basevelocity, pmove->velocity ); + + PM_FlyMove (); +} + +qboolean PM_InWater( void ) +{ + return ( pmove->waterlevel > 1 ); +} + +/* +============= +PM_CheckWater + +Sets pmove->waterlevel and pmove->watertype values. +============= +*/ +qboolean PM_CheckWater () +{ + vec3_t point; + int cont; + int truecont; + float height; + float heightover2; + + // Pick a spot just above the players feet. + point[0] = pmove->origin[0] + (pmove->player_mins[pmove->usehull][0] + pmove->player_maxs[pmove->usehull][0]) * 0.5; + point[1] = pmove->origin[1] + (pmove->player_mins[pmove->usehull][1] + pmove->player_maxs[pmove->usehull][1]) * 0.5; + point[2] = pmove->origin[2] + pmove->player_mins[pmove->usehull][2] + 1; + + // Assume that we are not in water at all. + pmove->waterlevel = 0; + pmove->watertype = CONTENTS_EMPTY; + + // Grab point contents. + cont = pmove->PM_PointContents (point, &truecont ); + // Are we under water? (not solid and not empty?) + if (cont <= CONTENTS_WATER && cont > CONTENTS_TRANSLUCENT ) + { + // Set water type + pmove->watertype = cont; + + // We are at least at level one + pmove->waterlevel = 1; + + height = (pmove->player_mins[pmove->usehull][2] + pmove->player_maxs[pmove->usehull][2]); + heightover2 = height * 0.5; + + // Now check a point that is at the player hull midpoint. + point[2] = pmove->origin[2] + heightover2; + cont = pmove->PM_PointContents (point, NULL ); + // If that point is also under water... + if (cont <= CONTENTS_WATER && cont > CONTENTS_TRANSLUCENT ) + { + // Set a higher water level. + pmove->waterlevel = 2; + + // Now check the eye position. (view_ofs is relative to the origin) + point[2] = pmove->origin[2] + pmove->view_ofs[2]; + + cont = pmove->PM_PointContents (point, NULL ); + if (cont <= CONTENTS_WATER && cont > CONTENTS_TRANSLUCENT ) + pmove->waterlevel = 3; // In over our eyes + } + + // Adjust velocity based on water current, if any. + if ( ( truecont <= CONTENTS_CURRENT_0 ) && + ( truecont >= CONTENTS_CURRENT_DOWN ) ) + { + // The deeper we are, the stronger the current. + static vec3_t current_table[] = + { + {1, 0, 0}, {0, 1, 0}, {-1, 0, 0}, + {0, -1, 0}, {0, 0, 1}, {0, 0, -1} + }; + + VectorMA (pmove->basevelocity, 50.0*pmove->waterlevel, current_table[CONTENTS_CURRENT_0 - truecont], pmove->basevelocity); + } + } + + return pmove->waterlevel > 1; +} + +/* +============= +PM_CatagorizePosition +============= +*/ +void PM_CatagorizePosition (void) +{ + vec3_t point; + pmtrace_t tr; + +// if the player hull point one unit down is solid, the player +// is on ground + +// see if standing on something solid + + // Doing this before we move may introduce a potential latency in water detection, but + // doing it after can get us stuck on the bottom in water if the amount we move up + // is less than the 1 pixel 'threshold' we're about to snap to. Also, we'll call + // this several times per frame, so we really need to avoid sticking to the bottom of + // water on each call, and the converse case will correct itself if called twice. + PM_CheckWater(); + + point[0] = pmove->origin[0]; + point[1] = pmove->origin[1]; + point[2] = pmove->origin[2] - 2; + + if (pmove->velocity[2] > 180) // Shooting up really fast. Definitely not on ground. + { + pmove->onground = -1; + } + else + { + // Try and move down. + tr = pmove->PM_PlayerTrace (pmove->origin, point, PM_NORMAL, -1 ); + // If we hit a steep plane, we are not on ground + if ( tr.plane.normal[2] < 0.7) + pmove->onground = -1; // too steep + else + pmove->onground = tr.ent; // Otherwise, point to index of ent under us. + + // If we are on something... + if (pmove->onground != -1) + { + // Then we are not in water jump sequence + pmove->waterjumptime = 0; + // If we could make the move, drop us down that 1 pixel + if (pmove->waterlevel < 2 && !tr.startsolid && !tr.allsolid) + VectorCopy (tr.endpos, pmove->origin); + } + + // Standing on an entity other than the world + if (tr.ent > 0) // So signal that we are touching something. + { + PM_AddToTouched(tr, pmove->velocity); + } + } +} + +/* +================= +PM_GetRandomStuckOffsets + +When a player is stuck, it's costly to try and unstick them +Grab a test offset for the player based on a passed in index +================= +*/ +int PM_GetRandomStuckOffsets(int nIndex, int server, vec3_t offset) +{ + // Last time we did a full + int idx; + idx = rgStuckLast[nIndex][server]++; + + VectorCopy(rgv3tStuckTable[idx % 54], offset); + + return (idx % 54); +} + +void PM_ResetStuckOffsets(int nIndex, int server) +{ + rgStuckLast[nIndex][server] = 0; +} + +/* +================= +NudgePosition + +If pmove->origin is in a solid position, +try nudging slightly on all axis to +allow for the cut precision of the net coordinates +================= +*/ +#define PM_CHECKSTUCK_MINTIME 0.05 // Don't check again too quickly. + +int PM_CheckStuck (void) +{ + vec3_t base; + vec3_t offset; + vec3_t test; + int hitent; + int idx; + float fTime; + int i; + pmtrace_t traceresult; + + static float rgStuckCheckTime[MAX_CLIENTS][2]; // Last time we did a full + + // If position is okay, exit + hitent = pmove->PM_TestPlayerPosition (pmove->origin, &traceresult ); + if (hitent == -1 ) + { + PM_ResetStuckOffsets( pmove->player_index, pmove->server ); + return 0; + } + + VectorCopy (pmove->origin, base); + + // + // Deal with precision error in network. + // + if (!pmove->server) + { + // World or BSP model + if ( ( hitent == 0 ) || + ( pmove->physents[hitent].model != NULL ) ) + { + int nReps = 0; + PM_ResetStuckOffsets( pmove->player_index, pmove->server ); + do + { + i = PM_GetRandomStuckOffsets(pmove->player_index, pmove->server, offset); + + VectorAdd(base, offset, test); + if (pmove->PM_TestPlayerPosition (test, &traceresult ) == -1) + { + PM_ResetStuckOffsets( pmove->player_index, pmove->server ); + + VectorCopy ( test, pmove->origin ); + return 0; + } + nReps++; + } while (nReps < 54); + } + } + + // Only an issue on the client. + + if (pmove->server) + idx = 0; + else + idx = 1; + + fTime = pmove->Sys_FloatTime(); + // Too soon? + if (rgStuckCheckTime[pmove->player_index][idx] >= + ( fTime - PM_CHECKSTUCK_MINTIME ) ) + { + return 1; + } + rgStuckCheckTime[pmove->player_index][idx] = fTime; + + pmove->PM_StuckTouch( hitent, &traceresult ); + + i = PM_GetRandomStuckOffsets(pmove->player_index, pmove->server, offset); + + VectorAdd(base, offset, test); + if ( ( hitent = pmove->PM_TestPlayerPosition ( test, NULL ) ) == -1 ) + { + //Con_DPrintf("Nudged\n"); + + PM_ResetStuckOffsets( pmove->player_index, pmove->server ); + + if (i >= 27) + VectorCopy ( test, pmove->origin ); + + return 0; + } + + // If player is flailing while stuck in another player ( should never happen ), then see + // if we can't "unstick" them forceably. + if ( pmove->cmd.buttons & ( IN_JUMP | IN_DUCK | IN_ATTACK ) && ( pmove->physents[ hitent ].player != 0 ) ) + { + float x, y, z; + float xystep = 8.0; + float zstep = 18.0; + float xyminmax = xystep; + float zminmax = 4 * zstep; + + for ( z = 0; z <= zminmax; z += zstep ) + { + for ( x = -xyminmax; x <= xyminmax; x += xystep ) + { + for ( y = -xyminmax; y <= xyminmax; y += xystep ) + { + VectorCopy( base, test ); + test[0] += x; + test[1] += y; + test[2] += z; + + if ( pmove->PM_TestPlayerPosition ( test, NULL ) == -1 ) + { + VectorCopy( test, pmove->origin ); + return 0; + } + } + } + } + } + + //VectorCopy (base, pmove->origin); + + return 1; +} + +#define CHASE_DISTANCE 112 // Desired distance from target +#define CHASE_PADDING 4 // Minimum allowable distance between the view and a solid face + +// Get the origin of the Observer based around the target's position and angles +void GetChaseOrigin( vec3_t targetangles, int iTargetIndex, vec3_t offset, vec3_t *returnvec ) +{ + vec3_t forward; + vec3_t vecEnd; + vec3_t vecStart; + struct pmtrace_s *trace; + physent_t *target; + + target = &(pmove->physents[ iTargetIndex ]); + + // Trace back from the target using the player's view angles + AngleVectors(targetangles, forward, NULL, NULL); + + // Without view_ofs, just guess at adding 28 (standing player) to the origin to get the eye-height + VectorCopy( target->origin, vecStart ); + vecStart[2] += 28; + VectorMA(offset, CHASE_DISTANCE, forward, vecEnd); + VectorSubtract( vecStart, vecEnd, vecEnd ); + + trace = pmove->PM_TraceLine( vecStart, vecEnd, 0, 2, iTargetIndex ); + + // Return the position + VectorMA( trace->endpos, CHASE_PADDING, trace->plane.normal, *returnvec ); + +#ifdef CLIENT_DLL + // pmove->Con_NPrintf( 9, "vecStart %f %f %f.\n", vecStart[0], vecStart[1], vecStart[2] ); + // pmove->Con_NPrintf( 10, " vecEnd %f %f %f.\n", vecEnd[0], vecEnd[1], vecEnd[2] ); + // pmove->Con_NPrintf( 11, " EndPos %f %f %f.\n", trace->endpos[0], trace->endpos[1], trace->endpos[2] ); +#endif +} + +/* +=============== +PM_SpectatorMove +=============== +*/ +void PM_SpectatorMove (void) +{ + float speed, drop, friction, control, newspeed; + //float accel; + float currentspeed, addspeed, accelspeed; + int i; + vec3_t wishvel; + float fmove, smove; + vec3_t wishdir; + float wishspeed; + +#ifdef CLIENT_DLL + if ( pmove->runfuncs ) + { + // Set spectator flag + iIsSpectator = SPEC_IS_SPECTATOR; + } +#endif + + // Are we locked onto a target? + if ( pmove->iuser2 ) + { + vec3_t vecViewAngle; + vec3_t vecNewOrg; + vec3_t vecOffset; + int i; + + // Find the client this player's targeting + for (i = 0; i < pmove->numphysent; i++) + { + if ( pmove->physents[i].info == pmove->iuser2 ) + break; + } + + if (i == pmove->numphysent) + return; + + VectorCopy( vec3_origin, vecOffset ); + + // Calculate a camera position based upon the target's origin and angles + if (pmove->iuser1 == 1) + { + // Locked onto the target + VectorCopy( pmove->physents[i].angles, vecViewAngle ); + vecViewAngle[0] = 0; + +#ifdef CLIENT_DLL + if ( pmove->runfuncs ) + { + // Force the client to start smoothing both the spectator's origin and angles + iIsSpectator |= (SPEC_SMOOTH_ANGLES | SPEC_SMOOTH_ORIGIN); + } +#endif + } + else + { + // Freelooking around the target + VectorCopy( pmove->angles, vecViewAngle ); + } + + GetChaseOrigin( vecViewAngle, i, vecOffset, &vecNewOrg); + VectorCopy( vecNewOrg, pmove->origin ); + VectorCopy( vecViewAngle, pmove->angles ); + VectorCopy( vec3_origin, pmove->velocity ); + +#ifdef CLIENT_DLL + if ( pmove->runfuncs ) + { + // Copy the desired angles into the client global var so we can force them to the player's view + VectorCopy( pmove->angles, vecNewViewAngles ); + iHasNewViewAngles = true; + VectorCopy( pmove->origin, vecNewViewOrigin ); + iHasNewViewOrigin = true; + } +#endif + } + else + { + // Move around in normal spectator method + // friction + speed = Length (pmove->velocity); + if (speed < 1) + { + VectorCopy (vec3_origin, pmove->velocity) + } + else + { + drop = 0; + + friction = pmove->movevars->friction*1.5; // extra friction + control = speed < pmove->movevars->stopspeed ? pmove->movevars->stopspeed : speed; + drop += control*friction*pmove->frametime; + + // scale the velocity + newspeed = speed - drop; + if (newspeed < 0) + newspeed = 0; + newspeed /= speed; + + VectorScale (pmove->velocity, newspeed, pmove->velocity); + } + + // accelerate + fmove = pmove->cmd.forwardmove; + smove = pmove->cmd.sidemove; + + VectorNormalize (pmove->forward); + VectorNormalize (pmove->right); + + for (i=0 ; i<3 ; i++) + { + wishvel[i] = pmove->forward[i]*fmove + pmove->right[i]*smove; + } + wishvel[2] += pmove->cmd.upmove; + + VectorCopy (wishvel, wishdir); + wishspeed = VectorNormalize(wishdir); + + // + // clamp to server defined max speed + // + if (wishspeed > pmove->movevars->spectatormaxspeed) + { + VectorScale (wishvel, pmove->movevars->spectatormaxspeed/wishspeed, wishvel); + wishspeed = pmove->movevars->spectatormaxspeed; + } + + currentspeed = DotProduct(pmove->velocity, wishdir); + addspeed = wishspeed - currentspeed; + if (addspeed <= 0) + return; + accelspeed = pmove->movevars->accelerate*pmove->frametime*wishspeed; + if (accelspeed > addspeed) + accelspeed = addspeed; + + for (i=0 ; i<3 ; i++) + pmove->velocity[i] += accelspeed*wishdir[i]; + + // move + VectorMA (pmove->origin, pmove->frametime, pmove->velocity, pmove->origin); + } +} + +/* +================== +PM_SplineFraction + +Use for ease-in, ease-out style interpolation (accel/decel) +Used by ducking code. +================== +*/ +float PM_SplineFraction( float value, float scale ) +{ + float valueSquared; + + value = scale * value; + valueSquared = value * value; + + // Nice little ease-in, ease-out spline-like curve + return 3 * valueSquared - 2 * valueSquared * value; +} + +void PM_FixPlayerCrouchStuck( int direction ) +{ + int hitent; + int i; + vec3_t test; + + hitent = pmove->PM_TestPlayerPosition ( pmove->origin, NULL ); + if (hitent == -1 ) + return; + + VectorCopy( pmove->origin, test ); + for ( i = 0; i < 36; i++ ) + { + pmove->origin[2] += direction; + hitent = pmove->PM_TestPlayerPosition ( pmove->origin, NULL ); + if (hitent == -1 ) + return; + } + + VectorCopy( test, pmove->origin ); // Failed +} + +void PM_Duck( void ) +{ + int i; + float time; + float duckFraction; + + int buttonsChanged = ( pmove->oldbuttons ^ pmove->cmd.buttons ); // These buttons have changed this frame + int nButtonPressed = buttonsChanged & pmove->cmd.buttons; // The changed ones still down are "pressed" + + int duckchange = buttonsChanged & IN_DUCK ? 1 : 0; + int duckpressed = nButtonPressed & IN_DUCK ? 1 : 0; + + if ( pmove->cmd.buttons & IN_DUCK ) + { + pmove->oldbuttons |= IN_DUCK; + } + else + { + pmove->oldbuttons &= ~IN_DUCK; + } + + if ( pmove->dead ) + return; + + if ( ( pmove->cmd.buttons & IN_DUCK ) || ( pmove->bInDuck ) || ( pmove->flags & FL_DUCKING ) ) + { + pmove->cmd.forwardmove *= 0.333; + pmove->cmd.sidemove *= 0.333; + pmove->cmd.upmove *= 0.333; + + if ( pmove->cmd.buttons & IN_DUCK ) + { + if ( (nButtonPressed & IN_DUCK ) && !( pmove->flags & FL_DUCKING ) ) + { + // Use 1 second so super long jump will work + pmove->flDuckTime = 1000; + pmove->bInDuck = true; + } + + time = max( 0.0, ( 1.0 - (float)pmove->flDuckTime / 1000.0 ) ); + + if ( pmove->bInDuck ) + { + // Finish ducking immediately if duck time is over or not on ground + if ( ( (float)pmove->flDuckTime / 1000.0 <= ( 1.0 - TIME_TO_DUCK ) ) || + ( pmove->onground == -1 ) ) + { + pmove->usehull = 1; + pmove->view_ofs[2] = VEC_DUCK_VIEW; + pmove->flags |= FL_DUCKING; + pmove->bInDuck = false; + + // HACKHACK - Fudge for collision bug - no time to fix this properly + if ( pmove->onground != -1 ) + { + for ( i = 0; i < 3; i++ ) + { + pmove->origin[i] -= ( pmove->player_mins[1][i] - pmove->player_mins[0][i] ); + } + // See if we are stuck? + PM_FixPlayerCrouchStuck( STUCK_MOVEUP ); + + // Recatagorize position since ducking can change origin + PM_CatagorizePosition(); + } + } + else + { + float fMore = (VEC_DUCK_HULL_MIN - VEC_HULL_MIN); + + // Calc parametric time + duckFraction = PM_SplineFraction( time, (1.0/TIME_TO_DUCK) ); + pmove->view_ofs[2] = ((VEC_DUCK_VIEW - fMore ) * duckFraction) + (VEC_VIEW * (1-duckFraction)); + } + } + } + else + { + pmtrace_t trace; + vec3_t newOrigin; + + VectorCopy( pmove->origin, newOrigin ); + + if ( pmove->onground != -1 ) + { + for ( i = 0; i < 3; i++ ) + { + newOrigin[i] += ( pmove->player_mins[1][i] - pmove->player_mins[0][i] ); + } + } + + trace = pmove->PM_PlayerTrace( newOrigin, newOrigin, PM_NORMAL, -1 ); + + if ( !trace.startsolid ) + { + pmove->usehull = 0; + + // Oh, no, changing hulls stuck us into something, try unsticking downward first. + trace = pmove->PM_PlayerTrace( newOrigin, newOrigin, PM_NORMAL, -1 ); + if ( trace.startsolid ) + { + // See if we are stuck? If so, stay ducked with the duck hull until we have a clear spot + //Con_Printf( "unstick got stuck\n" ); + pmove->usehull = 1; + return; + } + + pmove->flags &= ~FL_DUCKING; + pmove->bInDuck = false; + pmove->view_ofs[2] = VEC_VIEW; + pmove->flDuckTime = 0; + + VectorCopy( newOrigin, pmove->origin ); + + // Recatagorize position since ducking can change origin + PM_CatagorizePosition(); + } + } + } +} + +void PM_LadderMove( physent_t *pLadder ) +{ + vec3_t ladderCenter; + trace_t trace; + qboolean onFloor; + vec3_t floor; + vec3_t modelmins, modelmaxs; + + if ( pmove->movetype == MOVETYPE_NOCLIP ) + return; + + pmove->PM_GetModelBounds( pLadder->model, modelmins, modelmaxs ); + + VectorAdd( modelmins, modelmaxs, ladderCenter ); + VectorScale( ladderCenter, 0.5, ladderCenter ); + + pmove->movetype = MOVETYPE_FLY; + + // On ladder, convert movement to be relative to the ladder + + VectorCopy( pmove->origin, floor ); + floor[2] += pmove->player_mins[pmove->usehull][2] - 1; + + if ( pmove->PM_PointContents( floor, NULL ) == CONTENTS_SOLID ) + onFloor = true; + else + onFloor = false; + + pmove->gravity = 0; + pmove->PM_TraceModel( pLadder, pmove->origin, ladderCenter, &trace ); + if ( trace.fraction != 1.0 ) + { + float forward = 0, right = 0; + vec3_t vpn, v_right; + + AngleVectors( pmove->angles, vpn, v_right, NULL ); + if ( pmove->cmd.buttons & IN_BACK ) + forward -= MAX_CLIMB_SPEED; + if ( pmove->cmd.buttons & IN_FORWARD ) + forward += MAX_CLIMB_SPEED; + if ( pmove->cmd.buttons & IN_MOVELEFT ) + right -= MAX_CLIMB_SPEED; + if ( pmove->cmd.buttons & IN_MOVERIGHT ) + right += MAX_CLIMB_SPEED; + + if ( pmove->cmd.buttons & IN_JUMP ) + { + pmove->movetype = MOVETYPE_WALK; + VectorScale( trace.plane.normal, 270, pmove->velocity ); + } + else + { + if ( forward != 0 || right != 0 ) + { + vec3_t velocity, perp, cross, lateral, tmp; + float normal; + + //ALERT(at_console, "pev %.2f %.2f %.2f - ", + // pev->velocity.x, pev->velocity.y, pev->velocity.z); + // Calculate player's intended velocity + //Vector velocity = (forward * gpGlobals->v_forward) + (right * gpGlobals->v_right); + VectorScale( vpn, forward, velocity ); + VectorMA( velocity, right, v_right, velocity ); + + + // Perpendicular in the ladder plane + // Vector perp = CrossProduct( Vector(0,0,1), trace.vecPlaneNormal ); + // perp = perp.Normalize(); + VectorClear( tmp ); + tmp[2] = 1; + CrossProduct( tmp, trace.plane.normal, perp ); + VectorNormalize( perp ); + + + // decompose velocity into ladder plane + normal = DotProduct( velocity, trace.plane.normal ); + // This is the velocity into the face of the ladder + VectorScale( trace.plane.normal, normal, cross ); + + + // This is the player's additional velocity + VectorSubtract( velocity, cross, lateral ); + + // This turns the velocity into the face of the ladder into velocity that + // is roughly vertically perpendicular to the face of the ladder. + // NOTE: It IS possible to face up and move down or face down and move up + // because the velocity is a sum of the directional velocity and the converted + // velocity through the face of the ladder -- by design. + CrossProduct( trace.plane.normal, perp, tmp ); + VectorMA( lateral, -normal, tmp, pmove->velocity ); + if ( onFloor && normal > 0 ) // On ground moving away from the ladder + { + VectorMA( pmove->velocity, MAX_CLIMB_SPEED, trace.plane.normal, pmove->velocity ); + } + //pev->velocity = lateral - (CrossProduct( trace.vecPlaneNormal, perp ) * normal); + } + else + { + VectorClear( pmove->velocity ); + } + } + } +} + +physent_t *PM_Ladder( void ) +{ + int i; + physent_t *pe; + hull_t *hull; + int num; + vec3_t test; + + for ( i = 0; i < pmove->nummoveent; i++ ) + { + pe = &pmove->moveents[i]; + + if ( pe->model && (modtype_t)pmove->PM_GetModelType( pe->model ) == mod_brush && pe->skin == CONTENTS_LADDER ) + { + + hull = (hull_t *)pmove->PM_HullForBsp( pe, test ); + num = hull->firstclipnode; + + // Offset the test point appropriately for this hull. + VectorSubtract ( pmove->origin, test, test); + + // Test the player's hull for intersection with this model + if ( pmove->PM_HullPointContents (hull, num, test) == CONTENTS_EMPTY) + continue; + + return pe; + } + } + + return NULL; +} + + + +void PM_WaterJump (void) +{ + if ( pmove->waterjumptime > 10000 ) + { + pmove->waterjumptime = 10000; + } + + if ( !pmove->waterjumptime ) + return; + + pmove->waterjumptime -= pmove->cmd.msec; + if ( pmove->waterjumptime < 0 || + !pmove->waterlevel ) + { + pmove->waterjumptime = 0; + pmove->flags &= ~FL_WATERJUMP; + } + + pmove->velocity[0] = pmove->movedir[0]; + pmove->velocity[1] = pmove->movedir[1]; +} + +/* +============ +PM_AddGravity + +============ +*/ +void PM_AddGravity () +{ + float ent_gravity; + + if (pmove->gravity) + ent_gravity = pmove->gravity; + else + ent_gravity = 1.0; + + // Add gravity incorrectly + pmove->velocity[2] -= (ent_gravity * pmove->movevars->gravity * pmove->frametime ); + pmove->velocity[2] += pmove->basevelocity[2] * pmove->frametime; + pmove->basevelocity[2] = 0; + PM_CheckVelocity(); +} +/* +============ +PM_PushEntity + +Does not change the entities velocity at all +============ +*/ +pmtrace_t PM_PushEntity (vec3_t push) +{ + pmtrace_t trace; + vec3_t end; + + VectorAdd (pmove->origin, push, end); + + trace = pmove->PM_PlayerTrace (pmove->origin, end, PM_NORMAL, -1 ); + + VectorCopy (trace.endpos, pmove->origin); + + // So we can run impact function afterwards. + if (trace.fraction < 1.0 && + !trace.allsolid) + { + PM_AddToTouched(trace, pmove->velocity); + } + + return trace; +} + +/* +============ +PM_Physics_Toss() + +Dead player flying through air., e.g. +============ +*/ +void PM_Physics_Toss() +{ + pmtrace_t trace; + vec3_t move; + float backoff; + + PM_CheckWater(); + + if (pmove->velocity[2] > 0) + pmove->onground = -1; + + // If on ground and not moving, return. + if ( pmove->onground != -1 ) + { + if (VectorCompare(pmove->basevelocity, vec3_origin) && + VectorCompare(pmove->velocity, vec3_origin)) + return; + } + + PM_CheckVelocity (); + +// add gravity + if ( pmove->movetype != MOVETYPE_FLY && + pmove->movetype != MOVETYPE_BOUNCEMISSILE && + pmove->movetype != MOVETYPE_FLYMISSILE ) + PM_AddGravity (); + +// move origin + // Base velocity is not properly accounted for since this entity will move again after the bounce without + // taking it into account + VectorAdd (pmove->velocity, pmove->basevelocity, pmove->velocity); + + PM_CheckVelocity(); + VectorScale (pmove->velocity, pmove->frametime, move); + VectorSubtract (pmove->velocity, pmove->basevelocity, pmove->velocity); + + trace = PM_PushEntity (move); // Should this clear basevelocity + + PM_CheckVelocity(); + + if (trace.allsolid) + { + // entity is trapped in another solid + pmove->onground = trace.ent; + VectorCopy (vec3_origin, pmove->velocity); + return; + } + + if (trace.fraction == 1) + { + PM_CheckWater(); + return; + } + + + if (pmove->movetype == MOVETYPE_BOUNCE) + backoff = 2.0 - pmove->friction; + else if (pmove->movetype == MOVETYPE_BOUNCEMISSILE) + backoff = 2.0; + else + backoff = 1; + + PM_ClipVelocity (pmove->velocity, trace.plane.normal, pmove->velocity, backoff); + + // stop if on ground + if (trace.plane.normal[2] > 0.7) + { + float vel; + vec3_t base; + + VectorClear( base ); + if (pmove->velocity[2] < pmove->movevars->gravity * pmove->frametime) + { + // we're rolling on the ground, add static friction. + pmove->onground = trace.ent; + pmove->velocity[2] = 0; + } + + vel = DotProduct( pmove->velocity, pmove->velocity ); + + // Con_DPrintf("%f %f: %.0f %.0f %.0f\n", vel, trace.fraction, ent->velocity[0], ent->velocity[1], ent->velocity[2] ); + + if (vel < (30 * 30) || (pmove->movetype != MOVETYPE_BOUNCE && pmove->movetype != MOVETYPE_BOUNCEMISSILE)) + { + pmove->onground = trace.ent; + VectorCopy (vec3_origin, pmove->velocity); + } + else + { + VectorScale (pmove->velocity, (1.0 - trace.fraction) * pmove->frametime * 0.9, move); + trace = PM_PushEntity (move); + } + VectorSubtract( pmove->velocity, base, pmove->velocity ) + } + +// check for in water + PM_CheckWater(); +} + +/* +==================== +PM_NoClip + +==================== +*/ +void PM_NoClip() +{ + int i; + vec3_t wishvel; + float fmove, smove; +// float currentspeed, addspeed, accelspeed; + + // Copy movement amounts + fmove = pmove->cmd.forwardmove; + smove = pmove->cmd.sidemove; + + VectorNormalize ( pmove->forward ); + VectorNormalize ( pmove->right ); + + for (i=0 ; i<3 ; i++) // Determine x and y parts of velocity + { + wishvel[i] = pmove->forward[i]*fmove + pmove->right[i]*smove; + } + wishvel[2] += pmove->cmd.upmove; + + VectorMA (pmove->origin, pmove->frametime, wishvel, pmove->origin); + + // Zero out the velocity so that we don't accumulate a huge downward velocity from + // gravity, etc. + VectorClear( pmove->velocity ); + +} + +/* +============= +PM_Jump +============= +*/ +void PM_Jump (void) +{ + int i; + qboolean tfc = false; + + qboolean cansuperjump = false; + + if (pmove->dead) + { + pmove->oldbuttons |= IN_JUMP ; // don't jump again until released + return; + } + + tfc = atoi( pmove->PM_Info_ValueForKey( pmove->physinfo, "tfc" ) ) == 1 ? true : false; + + // Spy that's feigning death cannot jump + if ( tfc && + ( pmove->deadflag == ( DEAD_DISCARDBODY + 1 ) ) ) + { + return; + } + + // See if we are waterjumping. If so, decrement count and return. + if ( pmove->waterjumptime ) + { + pmove->waterjumptime -= pmove->cmd.msec; + if (pmove->waterjumptime < 0) + { + pmove->waterjumptime = 0; + } + return; + } + + // If we are in the water most of the way... + if (pmove->waterlevel >= 2) + { // swimming, not jumping + pmove->onground = -1; + + if (pmove->watertype == CONTENTS_WATER) // We move up a certain amount + pmove->velocity[2] = 100; + else if (pmove->watertype == CONTENTS_SLIME) + pmove->velocity[2] = 80; + else // LAVA + pmove->velocity[2] = 50; + + // play swiming sound + if ( pmove->flSwimTime <= 0 ) + { + // Don't play sound again for 1 second + pmove->flSwimTime = 1000; + switch ( pmove->RandomLong( 0, 3 ) ) + { + case 0: + pmove->PM_PlaySound( CHAN_BODY, "player/pl_wade1.wav", 1, ATTN_NORM, 0, PITCH_NORM ); + break; + case 1: + pmove->PM_PlaySound( CHAN_BODY, "player/pl_wade2.wav", 1, ATTN_NORM, 0, PITCH_NORM ); + break; + case 2: + pmove->PM_PlaySound( CHAN_BODY, "player/pl_wade3.wav", 1, ATTN_NORM, 0, PITCH_NORM ); + break; + case 3: + pmove->PM_PlaySound( CHAN_BODY, "player/pl_wade4.wav", 1, ATTN_NORM, 0, PITCH_NORM ); + break; + } + } + + return; + } + + // No more effect + if ( pmove->onground == -1 ) + { + // Flag that we jumped. + // HACK HACK HACK + // Remove this when the game .dll no longer does physics code!!!! + pmove->oldbuttons |= IN_JUMP; // don't jump again until released + return; // in air, so no effect + } + + if ( pmove->oldbuttons & IN_JUMP ) + return; // don't pogo stick + + // In the air now. + pmove->onground = -1; + + if ( tfc ) + { + pmove->PM_PlaySound( CHAN_BODY, "player/plyrjmp8.wav", 0.5, ATTN_NORM, 0, PITCH_NORM ); + } + else + { + PM_PlayStepSound( PM_MapTextureTypeStepType( pmove->chtexturetype ), 1.0 ); + } + + // See if user can super long jump? + cansuperjump = atoi( pmove->PM_Info_ValueForKey( pmove->physinfo, "slj" ) ) == 1 ? true : false; + + // Acclerate upward + // If we are ducking... + if ( ( pmove->bInDuck ) || ( pmove->flags & FL_DUCKING ) ) + { + // Adjust for super long jump module + // UNDONE -- note this should be based on forward angles, not current velocity. + if ( cansuperjump && + ( pmove->cmd.buttons & IN_DUCK ) && + ( pmove->flDuckTime > 0 ) && + Length( pmove->velocity ) > 50 ) + { + pmove->punchangle[0] = -5; + + for (i =0; i < 2; i++) + { + pmove->velocity[i] = pmove->forward[i] * PLAYER_LONGJUMP_SPEED * 1.6; + } + + pmove->velocity[2] = sqrt(2 * 800 * 56.0); + } + else + { + pmove->velocity[2] = sqrt(2 * 800 * 45.0); + } + } + else + { + pmove->velocity[2] = sqrt(2 * 800 * 45.0); + } + + // Decay it for simulation + PM_FixupGravityVelocity(); + + // Flag that we jumped. + pmove->oldbuttons |= IN_JUMP; // don't jump again until released +} + +/* +============= +PM_CheckWaterJump +============= +*/ +#define WJ_HEIGHT 8 +void PM_CheckWaterJump (void) +{ + vec3_t vecStart, vecEnd; + vec3_t flatforward; + vec3_t flatvelocity; + float curspeed; + pmtrace_t tr; + int savehull; + + // Already water jumping. + if ( pmove->waterjumptime ) + return; + + // Don't hop out if we just jumped in + if ( pmove->velocity[2] < -180 ) + return; // only hop out if we are moving up + + // See if we are backing up + flatvelocity[0] = pmove->velocity[0]; + flatvelocity[1] = pmove->velocity[1]; + flatvelocity[2] = 0; + + // Must be moving + curspeed = VectorNormalize( flatvelocity ); + + // see if near an edge + flatforward[0] = pmove->forward[0]; + flatforward[1] = pmove->forward[1]; + flatforward[2] = 0; + VectorNormalize (flatforward); + + // Are we backing into water from steps or something? If so, don't pop forward + if ( curspeed != 0.0 && ( DotProduct( flatvelocity, flatforward ) < 0.0 ) ) + return; + + VectorCopy( pmove->origin, vecStart ); + vecStart[2] += WJ_HEIGHT; + + VectorMA ( vecStart, 24, flatforward, vecEnd ); + + // Trace, this trace should use the point sized collision hull + savehull = pmove->usehull; + pmove->usehull = 2; + tr = pmove->PM_PlayerTrace( vecStart, vecEnd, PM_NORMAL, -1 ); + if ( tr.fraction < 1.0 && fabs( tr.plane.normal[2] ) < 0.1f ) // Facing a near vertical wall? + { + vecStart[2] += pmove->player_maxs[ savehull ][2] - WJ_HEIGHT; + VectorMA( vecStart, 24, flatforward, vecEnd ); + VectorMA( vec3_origin, -50, tr.plane.normal, pmove->movedir ); + + tr = pmove->PM_PlayerTrace( vecStart, vecEnd, PM_NORMAL, -1 ); + if ( tr.fraction == 1.0 ) + { + pmove->waterjumptime = 2000; + pmove->velocity[2] = 225; + pmove->oldbuttons |= IN_JUMP; + pmove->flags |= FL_WATERJUMP; + } + } + + // Reset the collision hull + pmove->usehull = savehull; +} + +void PM_CheckFalling( void ) +{ + if ( pmove->onground != -1 && + !pmove->dead && + pmove->flFallVelocity >= PLAYER_FALL_PUNCH_THRESHHOLD ) + { + float fvol = 0.5; + + if ( pmove->waterlevel > 0 ) + { + } + else if ( pmove->flFallVelocity > PLAYER_MAX_SAFE_FALL_SPEED ) + { + // NOTE: In the original game dll , there were no breaks after these cases, causing the first one to + // cascade into the second + //switch ( RandomLong(0,1) ) + //{ + //case 0: + //pmove->PM_PlaySound( CHAN_VOICE, "player/pl_fallpain2.wav", 1, ATTN_NORM, 0, PITCH_NORM ); + //break; + //case 1: + pmove->PM_PlaySound( CHAN_VOICE, "player/pl_fallpain3.wav", 1, ATTN_NORM, 0, PITCH_NORM ); + // break; + //} + fvol = 1.0; + } + else if ( pmove->flFallVelocity > PLAYER_MAX_SAFE_FALL_SPEED / 2 ) + { + qboolean tfc = false; + tfc = atoi( pmove->PM_Info_ValueForKey( pmove->physinfo, "tfc" ) ) == 1 ? true : false; + + if ( tfc ) + { + pmove->PM_PlaySound( CHAN_VOICE, "player/pl_fallpain3.wav", 1, ATTN_NORM, 0, PITCH_NORM ); + } + + fvol = 0.85; + } + else if ( pmove->flFallVelocity < PLAYER_MIN_BOUNCE_SPEED ) + { + fvol = 0; + } + + if ( fvol > 0.0 ) + { + // Play landing step right away + pmove->flTimeStepSound = 0; + + PM_UpdateStepSound(); + + // play step sound for current texture + PM_PlayStepSound( PM_MapTextureTypeStepType( pmove->chtexturetype ), fvol ); + + // Knock the screen around a little bit, temporary effect + pmove->punchangle[ 2 ] = pmove->flFallVelocity * 0.013; // punch z axis + + if ( pmove->punchangle[ 0 ] > 8 ) + { + pmove->punchangle[ 0 ] = 8; + } + } + } + + if ( pmove->onground != -1 ) + { + pmove->flFallVelocity = 0; + } +} + +/* +================= +PM_PlayWaterSounds + +================= +*/ +void PM_PlayWaterSounds( void ) +{ + // Did we enter or leave water? + if ( ( pmove->oldwaterlevel == 0 && pmove->waterlevel != 0 ) || + ( pmove->oldwaterlevel != 0 && pmove->waterlevel == 0 ) ) + { + switch ( pmove->RandomLong(0,3) ) + { + case 0: + pmove->PM_PlaySound( CHAN_BODY, "player/pl_wade1.wav", 1, ATTN_NORM, 0, PITCH_NORM ); + break; + case 1: + pmove->PM_PlaySound( CHAN_BODY, "player/pl_wade2.wav", 1, ATTN_NORM, 0, PITCH_NORM ); + break; + case 2: + pmove->PM_PlaySound( CHAN_BODY, "player/pl_wade3.wav", 1, ATTN_NORM, 0, PITCH_NORM ); + break; + case 3: + pmove->PM_PlaySound( CHAN_BODY, "player/pl_wade4.wav", 1, ATTN_NORM, 0, PITCH_NORM ); + break; + } + } +} + +/* +=============== +PM_CalcRoll + +=============== +*/ +float PM_CalcRoll (vec3_t angles, vec3_t velocity, float rollangle, float rollspeed ) +{ + float sign; + float side; + float value; + vec3_t forward, right, up; + + AngleVectors (angles, forward, right, up); + + side = DotProduct (velocity, right); + + sign = side < 0 ? -1 : 1; + + side = fabs(side); + + value = rollangle; + + if (side < rollspeed) + { + side = side * value / rollspeed; + } + else + { + side = value; + } + + return side * sign; +} + +/* +============= +PM_DropPunchAngle + +============= +*/ +void PM_DropPunchAngle ( vec3_t punchangle ) +{ + float len; + + len = VectorNormalize ( punchangle ); + len -= (10.0 + len * 0.5) * pmove->frametime; + len = max( len, 0.0 ); + VectorScale ( punchangle, len, punchangle); +} + +/* +============== +PM_CheckParamters + +============== +*/ +void PM_CheckParamters( void ) +{ + float spd; + float maxspeed; + vec3_t v_angle; + + spd = ( pmove->cmd.forwardmove * pmove->cmd.forwardmove ) + + ( pmove->cmd.sidemove * pmove->cmd.sidemove ) + + ( pmove->cmd.upmove * pmove->cmd.upmove ); + spd = sqrt( spd ); + + maxspeed = pmove->clientmaxspeed; //atof( pmove->PM_Info_ValueForKey( pmove->physinfo, "maxspd" ) ); + if ( maxspeed != 0.0 ) + { + pmove->maxspeed = min( maxspeed, pmove->maxspeed ); + } + + if ( ( spd != 0.0 ) && + ( spd > pmove->maxspeed ) ) + { + float fRatio = pmove->maxspeed / spd; + pmove->cmd.forwardmove *= fRatio; + pmove->cmd.sidemove *= fRatio; + pmove->cmd.upmove *= fRatio; + } + + if ( pmove->flags & FL_FROZEN || + pmove->flags & FL_ONTRAIN || + pmove->dead ) + { + pmove->cmd.forwardmove = 0; + pmove->cmd.sidemove = 0; + pmove->cmd.upmove = 0; + } + + + PM_DropPunchAngle( pmove->punchangle ); + + // Take angles from command. + if ( !pmove->dead ) + { + VectorCopy ( pmove->cmd.viewangles, v_angle ); + VectorAdd( v_angle, pmove->punchangle, v_angle ); + + // Set up view angles. + pmove->angles[ROLL] = PM_CalcRoll ( v_angle, pmove->velocity, pmove->movevars->rollangle, pmove->movevars->rollspeed )*4; + pmove->angles[PITCH] = v_angle[PITCH]; + pmove->angles[YAW] = v_angle[YAW]; + } + else + { + VectorCopy( pmove->oldangles, pmove->angles ); + } + + // Set dead player view_offset + if ( pmove->dead ) + { + pmove->view_ofs[2] = PM_DEAD_VIEWHEIGHT; + } + + // Adjust client view angles to match values used on server. + if (pmove->angles[YAW] > 180.0f) + { + pmove->angles[YAW] -= 360.0f; + } + +} + +void PM_ReduceTimers( void ) +{ + if ( pmove->flTimeStepSound > 0 ) + { + pmove->flTimeStepSound -= pmove->cmd.msec; + if ( pmove->flTimeStepSound < 0 ) + { + pmove->flTimeStepSound = 0; + } + } + if ( pmove->flDuckTime > 0 ) + { + pmove->flDuckTime -= pmove->cmd.msec; + if ( pmove->flDuckTime < 0 ) + { + pmove->flDuckTime = 0; + } + } + if ( pmove->flSwimTime > 0 ) + { + pmove->flSwimTime -= pmove->cmd.msec; + if ( pmove->flSwimTime < 0 ) + { + pmove->flSwimTime = 0; + } + } +} + +/* +============= +PlayerMove + +Returns with origin, angles, and velocity modified in place. + +Numtouch and touchindex[] will be set if any of the physents +were contacted during the move. +============= +*/ +void PM_PlayerMove ( qboolean server ) +{ + physent_t *pLadder = NULL; + + // Are we running server code? + pmove->server = server; + + // Adjust speeds etc. + PM_CheckParamters(); + + // Assume we don't touch anything + pmove->numtouch = 0; + + // # of msec to apply movement + pmove->frametime = pmove->cmd.msec * 0.001; + + PM_ReduceTimers(); + + // Convert view angles to vectors + AngleVectors (pmove->angles, pmove->forward, pmove->right, pmove->up); + + // PM_ShowClipBox(); + +#ifdef CLIENT_DLL + if ( pmove->runfuncs ) + { + iIsSpectator = false; + iHasNewViewAngles = false; + iHasNewViewOrigin = false; + } +#endif + + // Special handling for spectator and observers. (iuser1 is set if the player's in observer mode) + if ( pmove->spectator || pmove->iuser1 > 0 ) + { + PM_SpectatorMove(); + PM_CatagorizePosition(); + return; + } + + // Always try and unstick us unless we are in NOCLIP mode + if ( pmove->movetype != MOVETYPE_NOCLIP && pmove->movetype != MOVETYPE_NONE ) + { + if ( PM_CheckStuck() ) + { + return; // Can't move, we're stuck + } + } + + // Now that we are "unstuck", see where we are ( waterlevel and type, pmove->onground ). + PM_CatagorizePosition(); + + // Store off the starting water level + pmove->oldwaterlevel = pmove->waterlevel; + + // If we are not on ground, store off how fast we are moving down + if ( pmove->onground == -1 ) + { + pmove->flFallVelocity = -pmove->velocity[2]; + } + + g_onladder = 0; + // Don't run ladder code if dead or on a train + if ( !pmove->dead && !(pmove->flags & FL_ONTRAIN) ) + { + pLadder = PM_Ladder(); + if ( pLadder ) + { + g_onladder = 1; + } + } + + PM_UpdateStepSound(); + + PM_Duck(); + + // Don't run ladder code if dead or on a train + if ( !pmove->dead && !(pmove->flags & FL_ONTRAIN) ) + { + if ( pLadder ) + { + PM_LadderMove( pLadder ); + } + else if ( pmove->movetype != MOVETYPE_WALK && + pmove->movetype != MOVETYPE_NOCLIP ) + { + // Clear ladder stuff unless player is noclipping + // it will be set immediately again next frame if necessary + pmove->movetype = MOVETYPE_WALK; + } + } + + // Slow down, I'm pulling it! (a box maybe) but only when I'm standing on ground + if ( ( pmove->onground != -1 ) && ( pmove->cmd.buttons & IN_USE) ) + { + VectorScale( pmove->velocity, 0.3, pmove->velocity ); + } + + // Handle movement + switch ( pmove->movetype ) + { + default: + pmove->Con_DPrintf("Bogus pmove player movetype %i on (%i) 0=cl 1=sv\n", pmove->movetype, pmove->server); + break; + + case MOVETYPE_NONE: + break; + + case MOVETYPE_NOCLIP: + PM_NoClip(); + break; + + case MOVETYPE_TOSS: + case MOVETYPE_BOUNCE: + PM_Physics_Toss(); + break; + + case MOVETYPE_FLY: + + PM_CheckWater(); + + // Was jump button pressed? + // If so, set velocity to 270 away from ladder. This is currently wrong. + // Also, set MOVE_TYPE to walk, too. + if ( pmove->cmd.buttons & IN_JUMP ) + { + if ( !pLadder ) + { + PM_Jump (); + } + } + else + { + pmove->oldbuttons &= ~IN_JUMP; + } + + // Perform the move accounting for any base velocity. + VectorAdd (pmove->velocity, pmove->basevelocity, pmove->velocity); + PM_FlyMove (); + VectorSubtract (pmove->velocity, pmove->basevelocity, pmove->velocity); + break; + + case MOVETYPE_WALK: + if ( !PM_InWater() ) + { + PM_AddCorrectGravity(); + } + + // If we are leaping out of the water, just update the counters. + if ( pmove->waterjumptime ) + { + PM_WaterJump(); + PM_FlyMove(); + + // Make sure waterlevel is set correctly + PM_CheckWater(); + return; + } + + // If we are swimming in the water, see if we are nudging against a place we can jump up out + // of, and, if so, start out jump. Otherwise, if we are not moving up, then reset jump timer to 0 + if ( pmove->waterlevel >= 2 ) + { + if ( pmove->waterlevel == 2 ) + { + PM_CheckWaterJump(); + } + + // If we are falling again, then we must not trying to jump out of water any more. + if ( pmove->velocity[2] < 0 && pmove->waterjumptime ) + { + pmove->waterjumptime = 0; + } + + // Was jump button pressed? + if (pmove->cmd.buttons & IN_JUMP) + { + PM_Jump (); + } + else + { + pmove->oldbuttons &= ~IN_JUMP; + } + + // Perform regular water movement + PM_WaterMove(); + + VectorSubtract (pmove->velocity, pmove->basevelocity, pmove->velocity); + + // Get a final position + PM_CatagorizePosition(); + } + else + + // Not underwater + { + // Was jump button pressed? + if ( pmove->cmd.buttons & IN_JUMP ) + { + if ( !pLadder ) + { + PM_Jump (); + } + } + else + { + pmove->oldbuttons &= ~IN_JUMP; + } + + // Fricion is handled before we add in any base velocity. That way, if we are on a conveyor, + // we don't slow when standing still, relative to the conveyor. + if ( pmove->onground != -1 ) + { + pmove->velocity[2] = 0.0; + PM_Friction(); + } + + // Make sure velocity is valid. + PM_CheckVelocity(); + + // Are we on ground now + if ( pmove->onground != -1 ) + { + PM_WalkMove(); + } + else + { + PM_AirMove(); // Take into account movement when in air. + } + + // Set final flags. + PM_CatagorizePosition(); + + // Now pull the base velocity back out. + // Base velocity is set if you are on a moving object, like + // a conveyor (or maybe another monster?) + VectorSubtract (pmove->velocity, pmove->basevelocity, pmove->velocity ); + + // Make sure velocity is valid. + PM_CheckVelocity(); + + // Add any remaining gravitational component. + if ( !PM_InWater() ) + { + PM_FixupGravityVelocity(); + } + + // If we are on ground, no downward velocity. + if ( pmove->onground != -1 ) + { + pmove->velocity[2] = 0; + } + + // See if we landed on the ground with enough force to play + // a landing sound. + PM_CheckFalling(); + } + + // Did we enter or leave the water? + PM_PlayWaterSounds(); + break; + } +} + +void PM_CreateStuckTable( void ) +{ + float x, y, z; + int idx; + int i; + float zi[3]; + + memset(rgv3tStuckTable, 0, 54 * sizeof(vec3_t)); + + idx = 0; + // Little Moves. + x = y = 0; + // Z moves + for (z = -0.125 ; z <= 0.125 ; z += 0.125) + { + rgv3tStuckTable[idx][0] = x; + rgv3tStuckTable[idx][1] = y; + rgv3tStuckTable[idx][2] = z; + idx++; + } + x = z = 0; + // Y moves + for (y = -0.125 ; y <= 0.125 ; y += 0.125) + { + rgv3tStuckTable[idx][0] = x; + rgv3tStuckTable[idx][1] = y; + rgv3tStuckTable[idx][2] = z; + idx++; + } + y = z = 0; + // X moves + for (x = -0.125 ; x <= 0.125 ; x += 0.125) + { + rgv3tStuckTable[idx][0] = x; + rgv3tStuckTable[idx][1] = y; + rgv3tStuckTable[idx][2] = z; + idx++; + } + + // Remaining multi axis nudges. + for ( x = - 0.125; x <= 0.125; x += 0.250 ) + { + for ( y = - 0.125; y <= 0.125; y += 0.250 ) + { + for ( z = - 0.125; z <= 0.125; z += 0.250 ) + { + rgv3tStuckTable[idx][0] = x; + rgv3tStuckTable[idx][1] = y; + rgv3tStuckTable[idx][2] = z; + idx++; + } + } + } + + // Big Moves. + x = y = 0; + zi[0] = 0.0f; + zi[1] = 1.0f; + zi[2] = 6.0f; + + for (i = 0; i < 3; i++) + { + // Z moves + z = zi[i]; + rgv3tStuckTable[idx][0] = x; + rgv3tStuckTable[idx][1] = y; + rgv3tStuckTable[idx][2] = z; + idx++; + } + + x = z = 0; + + // Y moves + for (y = -2.0f ; y <= 2.0f ; y += 2.0) + { + rgv3tStuckTable[idx][0] = x; + rgv3tStuckTable[idx][1] = y; + rgv3tStuckTable[idx][2] = z; + idx++; + } + y = z = 0; + // X moves + for (x = -2.0f ; x <= 2.0f ; x += 2.0f) + { + rgv3tStuckTable[idx][0] = x; + rgv3tStuckTable[idx][1] = y; + rgv3tStuckTable[idx][2] = z; + idx++; + } + + // Remaining multi axis nudges. + for (i = 0 ; i < 3; i++) + { + z = zi[i]; + + for (x = -2.0f ; x <= 2.0f ; x += 2.0f) + { + for (y = -2.0f ; y <= 2.0f ; y += 2.0) + { + rgv3tStuckTable[idx][0] = x; + rgv3tStuckTable[idx][1] = y; + rgv3tStuckTable[idx][2] = z; + idx++; + } + } + } +} + + + +/* +This modume implements the shared player physics code between any particular game and +the engine. The same PM_Move routine is built into the game .dll and the client .dll and is +invoked by each side as appropriate. There should be no distinction, internally, between server +and client. This will ensure that prediction behaves appropriately. +*/ + +void PM_Move ( struct playermove_s *ppmove, int server ) +{ + assert( pm_shared_initialized ); + + pmove = ppmove; + + PM_PlayerMove( ( server != 0 ) ? true : false ); + + if ( pmove->onground != -1 ) + { + pmove->flags |= FL_ONGROUND; + } + else + { + pmove->flags &= ~FL_ONGROUND; + } + + // In single player, reset friction after each movement to FrictionModifier Triggers work still. + if ( !pmove->multiplayer && ( pmove->movetype == MOVETYPE_WALK ) ) + { + pmove->friction = 1.0f; + } +} + +int PM_GetInfo( int ent ) +{ + if ( ent >= 0 && ent <= pmove->numvisent ) + { + return pmove->visents[ ent ].info; + } + return -1; +} + +void PM_Init( struct playermove_s *ppmove ) +{ + assert( !pm_shared_initialized ); + + pmove = ppmove; + + PM_CreateStuckTable(); + PM_InitTextureTypes(); + + pm_shared_initialized = 1; +} diff --git a/pm_shared/pm_shared.h b/pm_shared/pm_shared.h new file mode 100644 index 0000000..eede8b5 --- /dev/null +++ b/pm_shared/pm_shared.h @@ -0,0 +1,32 @@ +/*** +* +* Copyright (c) 1999, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ + +// +// pm_shared.h +// +#if !defined( PM_SHAREDH ) +#define PM_SHAREDH +#pragma once + +void PM_Init( struct playermove_s *ppmove ); +void PM_Move ( struct playermove_s *ppmove, int server ); +char PM_FindTextureType( char *name ); + +// Spectator flags +#define SPEC_IS_SPECTATOR (1<<0) +#define SPEC_SMOOTH_ANGLES (1<<1) +#define SPEC_SMOOTH_ORIGIN (1<<2) + +#endif \ No newline at end of file diff --git a/utils/bspinfo/mssccprj.scc b/utils/bspinfo/mssccprj.scc index 249ea30..28c912c 100644 --- a/utils/bspinfo/mssccprj.scc +++ b/utils/bspinfo/mssccprj.scc @@ -1,4 +1,5 @@ SCC = This is a Source Code Control file [bspinfo.mak] -SCC_Project_Name = "$/HLStandardSDK/SourceCode/utils/bspinfo", NBXHAAAA +SCC_Aux_Path = "\\Jeeves\VSSCODE\" +SCC_Project_Name = "$/Sdk/Standard/utils/bspinfo", CFZBAAAA diff --git a/utils/light/light.c b/utils/light/light.c new file mode 100644 index 0000000..6ef9984 --- /dev/null +++ b/utils/light/light.c @@ -0,0 +1,221 @@ +// lighting.c + +#include "light.h" + +/* + +NOTES +----- + +*/ + +float scaledist = 1.0; +float scalecos = 0.5; +float rangescale = 0.5; + +byte *filebase, *file_p, *file_end; + +dmodel_t *bspmodel; + +vec3_t bsp_origin; + +qboolean extrasamples; +qboolean hicolor; +qboolean clamp192 = true; + +float minlights[MAX_MAP_FACES]; + +lightentity_t lightentities[MAX_MAP_ENTITIES]; +int numlightentities; + + +/* +================== +LoadEntities +================== +*/ +void LoadEntities (void) +{ + char *s, *s2; + entity_t *e; + lightentity_t *le; + int i, j; + + ParseEntities (); + +// go through all the entities + for (i=1 ; iclassname, s); + s = ValueForKey( e, "_light" ); + if( s ) + { + double v1, v2, v3; + + v1 = v2 = v3 = 0; + if( sscanf( s, "%lf %lf %lf", &v1, &v2, &v3) != 3 ) + v2 = v3 = v1; + + le->light[0] = v1; + le->light[1] = v2; + le->light[2] = v3; + } + else + { + le->light[0] = DEFAULTLIGHTLEVEL; + le->light[1] = DEFAULTLIGHTLEVEL; + le->light[2] = DEFAULTLIGHTLEVEL; + } + + le->style = FloatForKey (e, "style"); + le->angle = FloatForKey (e, "angle"); + GetVectorForKey (e, "origin", le->origin); + + s = ValueForKey (e, "target"); + if (!s[0]) + continue; + + // find matching targetname + for (j=1 ; jtargetent = true; + GetVectorForKey (&entities[j], "origin", le->targetorigin); + break; + } + } + if (j == num_entities) + printf ("WARNING: entity %i has unmatched target %s\n", i, s); + } + + qprintf ("%d lightentities\n", numlightentities); + +} + + +byte *GetFileSpace (int size) +{ + byte *buf; + + ThreadLock(); + file_p = (byte *)(((long)file_p + 3)&~3); + buf = file_p; + file_p += size; + ThreadUnlock(); + if (file_p > file_end) + Error ("GetFileSpace: overrun"); + return buf; +} + + + +/* +============= +LightWorld +============= +*/ +void LightWorld (void) +{ + filebase = file_p = dlightdata; + file_end = filebase + MAX_MAP_LIGHTING; + + RunThreadsOnIndividual (numfaces, true, LightFace); + + lightdatasize = file_p - filebase; + + printf ("lightdatasize: %i\n", lightdatasize); +} + + +/* +======== +main + +light modelfile +======== +*/ +int main (int argc, char **argv) +{ + int i; + double start, end; + char source[1024]; + + printf("Light.exe Version 1.3 Id Software and valve (%s)\n", __DATE__ ); + printf ("----- LightFaces ----\n"); + + // default to 24-bit light info + hicolor = true; + + for (i=1 ; i +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=light - Win32 Release +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "light.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "light.mak" CFG="light - Win32 Release" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "light - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "light - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "light - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir ".\Release" +# PROP BASE Intermediate_Dir ".\Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir ".\Release" +# PROP Intermediate_Dir ".\Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /YX /c +# ADD CPP /nologo /GX /O2 /I "..\common" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# 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: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 /nologo /subsystem:console /machine:I386 + +!ELSEIF "$(CFG)" == "light - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir ".\Debug" +# PROP BASE Intermediate_Dir ".\Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir ".\Debug" +# PROP Intermediate_Dir ".\Debug" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /YX /c +# ADD CPP /nologo /Gm /GX /ZI /Od /I "..\common" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /FR /YX /FD /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# 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:console /debug /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 /nologo /subsystem:console /debug /machine:I386 + +!ENDIF + +# Begin Target + +# Name "light - Win32 Release" +# Name "light - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat;for;f90" +# Begin Source File + +SOURCE=..\common\bspfile.c +# End Source File +# Begin Source File + +SOURCE=..\common\cmdlib.c +# End Source File +# Begin Source File + +SOURCE=.\light.c +# End Source File +# Begin Source File + +SOURCE=.\ltface.c +# End Source File +# Begin Source File + +SOURCE=..\common\mathlib.c +# End Source File +# Begin Source File + +SOURCE=..\common\scriplib.c +# End Source File +# Begin Source File + +SOURCE=..\common\threads.c +# End Source File +# Begin Source File + +SOURCE=.\trace.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl;fi;fd" +# Begin Source File + +SOURCE=.\light.h +# End Source File +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;cnt;rtf;gif;jpg;jpeg;jpe" +# End Group +# End Target +# End Project diff --git a/utils/light/light.h b/utils/light/light.h new file mode 100644 index 0000000..d24ecae --- /dev/null +++ b/utils/light/light.h @@ -0,0 +1,54 @@ + +#include "cmdlib.h" +#include "mathlib.h" +#include "bspfile.h" +#include "threads.h" + + +#define DEFAULTLIGHTLEVEL 300 + +typedef struct entity_s +{ + char classname[64]; + vec3_t origin; + float angle; + vec3_t light; + int style; + qboolean targetent; + vec3_t targetorigin; +} lightentity_t; + +extern lightentity_t lightentities[MAX_MAP_ENTITIES]; +extern int numlightentities; + +#define ON_EPSILON 0.1 + +#define MAXLIGHTS 1024 + +void LoadNodes (char *file); +qboolean TestLine (vec3_t start, vec3_t stop); + +void LightFace (int surfnum); +void LightLeaf (dleaf_t *leaf); + +void MakeTnodes (dmodel_t *bm); + +extern float scaledist; +extern float scalecos; +extern float rangescale; + +extern int c_culldistplane, c_proper; + +byte *GetFileSpace (int size); +extern byte *filebase; + +extern vec3_t bsp_origin; +extern vec3_t bsp_xvector; +extern vec3_t bsp_yvector; + +void TransformSample (vec3_t in, vec3_t out); +void RotateSample (vec3_t in, vec3_t out); + +extern qboolean extrasamples; + +extern float minlights[MAX_MAP_FACES]; diff --git a/utils/light/ltface.c b/utils/light/ltface.c new file mode 100644 index 0000000..e6f8c99 --- /dev/null +++ b/utils/light/ltface.c @@ -0,0 +1,682 @@ + +#include "light.h" + +extern qboolean hicolor; +extern qboolean clamp192; + +/* +============ +CastRay + +Returns the distance between the points, or -1 if blocked +============= +*/ +vec_t CastRay (vec3_t p1, vec3_t p2) +{ + int i; + vec_t t; + qboolean trace; + + trace = TestLine (p1, p2); + + if (!trace) + return -1; // ray was blocked + + t = 0; + for (i=0 ; i< 3 ; i++) + t += (p2[i]-p1[i]) * (p2[i]-p1[i]); + + if (t == 0) + t = 1; // don't blow up... + return sqrt(t); +} + +/* +=============================================================================== + +SAMPLE POINT DETERMINATION + +void SetupBlock (dface_t *f) Returns with surfpt[] set + +This is a little tricky because the lightmap covers more area than the face. +If done in the straightforward fashion, some of the +sample points will be inside walls or on the other side of walls, causing +false shadows and light bleeds. + +To solve this, I only consider a sample point valid if a line can be drawn +between it and the exact midpoint of the face. If invalid, it is adjusted +towards the center until it is valid. + +(this doesn't completely work) + +=============================================================================== +*/ + +#define SINGLEMAP (18*18*4) + +typedef struct +{ + vec3_t lightmaps[MAXLIGHTMAPS][SINGLEMAP]; + int numlightstyles; + vec_t *light; + vec_t facedist; + vec3_t facenormal; + + int numsurfpt; + vec3_t surfpt[SINGLEMAP]; + + vec3_t texorg; + vec3_t worldtotex[2]; // s = (world - texorg) . worldtotex[0] + vec3_t textoworld[2]; // world = texorg + s * textoworld[0] + + vec_t exactmins[2], exactmaxs[2]; + + int texmins[2], texsize[2]; + int lightstyles[256]; + int surfnum; + dface_t *face; +} lightinfo_t; + + +/* +================ +CalcFaceVectors + +Fills in texorg, worldtotex. and textoworld +================ +*/ +void CalcFaceVectors (lightinfo_t *l) +{ + texinfo_t *tex; + int i, j; + vec3_t texnormal; + float distscale; + vec_t dist, len; + + tex = &texinfo[l->face->texinfo]; + +// convert from float to vec_t + for (i=0 ; i<2 ; i++) + for (j=0 ; j<3 ; j++) + l->worldtotex[i][j] = tex->vecs[i][j]; + +// calculate a normal to the texture axis. points can be moved along this +// without changing their S/T + texnormal[0] = tex->vecs[1][1]*tex->vecs[0][2] + - tex->vecs[1][2]*tex->vecs[0][1]; + texnormal[1] = tex->vecs[1][2]*tex->vecs[0][0] + - tex->vecs[1][0]*tex->vecs[0][2]; + texnormal[2] = tex->vecs[1][0]*tex->vecs[0][1] + - tex->vecs[1][1]*tex->vecs[0][0]; + VectorNormalize (texnormal); + +// flip it towards plane normal + distscale = DotProduct (texnormal, l->facenormal); + if (!distscale) + Error ("Texture axis perpendicular to face"); + if (distscale < 0) + { + distscale = -distscale; + VectorSubtract (vec3_origin, texnormal, texnormal); + } + +// distscale is the ratio of the distance along the texture normal to +// the distance along the plane normal + distscale = 1/distscale; + + for (i=0 ; i<2 ; i++) + { + len = VectorLength (l->worldtotex[i]); + dist = DotProduct (l->worldtotex[i], l->facenormal); + dist *= distscale; + VectorMA (l->worldtotex[i], -dist, texnormal, l->textoworld[i]); + VectorScale (l->textoworld[i], (1/len)*(1/len), l->textoworld[i]); + } + + +// calculate texorg on the texture plane + for (i=0 ; i<3 ; i++) + l->texorg[i] = -tex->vecs[0][3]* l->textoworld[0][i] - tex->vecs[1][3] * l->textoworld[1][i]; + +// project back to the face plane + dist = DotProduct (l->texorg, l->facenormal) - l->facedist - 1; + dist *= distscale; + VectorMA (l->texorg, -dist, texnormal, l->texorg); + +} + +/* +================ +CalcFaceExtents + +Fills in s->texmins[] and s->texsize[] +also sets exactmins[] and exactmaxs[] +================ +*/ +void CalcFaceExtents (lightinfo_t *l) +{ + dface_t *s; + vec_t mins[2], maxs[2], val; + int i,j, e; + dvertex_t *v; + texinfo_t *tex; + + s = l->face; + + mins[0] = mins[1] = 999999; + maxs[0] = maxs[1] = -99999; + + tex = &texinfo[s->texinfo]; + + for (i=0 ; inumedges ; i++) + { + e = dsurfedges[s->firstedge+i]; + if (e >= 0) + v = dvertexes + dedges[e].v[0]; + else + v = dvertexes + dedges[-e].v[1]; + + for (j=0 ; j<2 ; j++) + { + val = v->point[0] * tex->vecs[j][0] + + v->point[1] * tex->vecs[j][1] + + v->point[2] * tex->vecs[j][2] + + tex->vecs[j][3]; + if (val < mins[j]) + mins[j] = val; + if (val > maxs[j]) + maxs[j] = val; + } + } + + for (i=0 ; i<2 ; i++) + { + l->exactmins[i] = mins[i]; + l->exactmaxs[i] = maxs[i]; + + mins[i] = floor(mins[i]/16); + maxs[i] = ceil(maxs[i]/16); + + l->texmins[i] = mins[i]; + l->texsize[i] = maxs[i] - mins[i]; + if (l->texsize[i] > 17) + Error ("Bad surface extents"); + } +} + +/* +================= +CalcPoints + +For each texture aligned grid point, back project onto the plane +to get the world xyz value of the sample point +================= +*/ +int c_bad; +void CalcPoints (lightinfo_t *l) +{ + int i; + int s, t, j; + int w, h, step; + vec_t starts, startt, us, ut; + vec_t *surf; + vec_t mids, midt; + vec3_t facemid, move; + +// +// fill in surforg +// the points are biased towards the center of the surface +// to help avoid edge cases just inside walls +// + surf = l->surfpt[0]; + mids = (l->exactmaxs[0] + l->exactmins[0])/2; + midt = (l->exactmaxs[1] + l->exactmins[1])/2; + + for (j=0 ; j<3 ; j++) + facemid[j] = l->texorg[j] + l->textoworld[0][j]*mids + l->textoworld[1][j]*midt; + + if (extrasamples) + { // extra filtering + h = (l->texsize[1]+1)*2; + w = (l->texsize[0]+1)*2; + starts = (l->texmins[0]-0.5)*16; + startt = (l->texmins[1]-0.5)*16; + step = 8; + } + else + { + h = l->texsize[1]+1; + w = l->texsize[0]+1; + starts = l->texmins[0]*16; + startt = l->texmins[1]*16; + step = 16; + } + + l->numsurfpt = w * h; + for (t=0 ; ttexorg[j] + l->textoworld[0][j]*us + + l->textoworld[1][j]*ut; + + if (CastRay (facemid, surf) != -1) + break; // got it + if (i & 1) + { + if (us > mids) + { + us -= 8; + if (us < mids) + us = mids; + } + else + { + us += 8; + if (us > mids) + us = mids; + } + } + else + { + if (ut > midt) + { + ut -= 8; + if (ut < midt) + ut = midt; + } + else + { + ut += 8; + if (ut > midt) + ut = midt; + } + } + + // move surf 8 pixels towards the center + VectorSubtract (facemid, surf, move); + VectorNormalize (move); + VectorMA (surf, 8, move, surf); + } + if (i == 2) + c_bad++; + } + } + +} + + +/* +=============================================================================== + +FACE LIGHTING + +=============================================================================== +*/ + +int c_culldistplane, c_proper; + +/* +================ +SingleLightFace +================ +*/ +void SingleLightFace (lightentity_t *light, lightinfo_t *l) +{ + vec_t dist; + vec3_t incoming; + vec_t angle; + vec_t add; + vec_t *surf; + qboolean hit; + int mapnum; + int size; + int c, i; + vec3_t rel; + vec3_t spotvec; + vec_t falloff; + vec3_t *lightsamp; + float intensity; + + VectorSubtract (light->origin, bsp_origin, rel); + dist = scaledist * (DotProduct (rel, l->facenormal) - l->facedist); + +// don't bother with lights behind the surface + if (dist <= 0) + return; + +// don't bother with light too far away + intensity = ( light->light[ 0 ] + light->light[ 1 ] + light->light[ 2 ] ) / 3.0; + if( dist > intensity ) + { + c_culldistplane++; + return; + } + + if (light->targetent) + { + VectorSubtract (light->targetorigin, light->origin, spotvec); + VectorNormalize (spotvec); + if (!light->angle) + falloff = -cos(20*Q_PI/180); + else + falloff = -cos(light->angle/2*Q_PI/180); + } + else + falloff = 0; // shut up compiler warnings + + mapnum = 0; + for (mapnum=0 ; mapnumnumlightstyles ; mapnum++) + if (l->lightstyles[mapnum] == light->style) + break; + lightsamp = l->lightmaps[mapnum]; + if (mapnum == l->numlightstyles) + { // init a new light map + if (mapnum == MAXLIGHTMAPS) + { + printf ("WARNING: Too many light styles on a face\n"); + return; + } + size = (l->texsize[1]+1)*(l->texsize[0]+1); + for (i=0 ; isurfpt[0]; + for (c=0 ; cnumsurfpt ; c++, surf+=3) + { + dist = CastRay(light->origin, surf)*scaledist; + if (dist < 0) + continue; // light doesn't reach + + VectorSubtract (light->origin, surf, incoming); + VectorNormalize (incoming); + angle = DotProduct (incoming, l->facenormal); + if (light->targetent) + { // spotlight cutoff + if (DotProduct (spotvec, incoming) > falloff) + continue; + } + + angle = (1.0-scalecos) + scalecos*angle; + for( i=0; i<3; i++ ) + { + add = light->light[i] - dist; + add *= angle; + if (add < 0) + continue; + + lightsamp[c][i] += add; + } + + // check intensity + intensity = ( lightsamp[ c ][ 0 ] + lightsamp[ c ][ 1 ] + lightsamp[ c ][ 2 ] ) / 3.0; + if( intensity > 1 ) // ignore real tiny lights + hit = true; + } + + if (mapnum == l->numlightstyles && hit) + { + l->lightstyles[mapnum] = light->style; + l->numlightstyles++; // the style has some real data now + } +} + +/* +============ +FixMinlight +============ +*/ +void FixMinlight (lightinfo_t *l) +{ + int i, j; + float minlight; + + minlight = minlights[l->surfnum]; + + // if minlight is set, there must be a style 0 light map + if (!minlight) + return; + + for (i=0 ; i< l->numlightstyles ; i++) + { + if (l->lightstyles[i] == 0) + break; + } + if (i == l->numlightstyles) + { + if (l->numlightstyles == MAXLIGHTMAPS) + return; // oh well.. + + for (j=0 ; jnumsurfpt ; j++) + { + l->lightmaps[i][j][0] = minlight; + l->lightmaps[i][j][1] = minlight; + l->lightmaps[i][j][2] = minlight; + } + + l->lightstyles[i] = 0; + l->numlightstyles++; + } + else + { + for (j=0 ; jnumsurfpt ; j++) + { + float intensity = ( l->lightmaps[i][j][0] + l->lightmaps[i][j][1] + l->lightmaps[i][j][2] ) / 3.0; + + if ( intensity < minlight ) + { + l->lightmaps[i][j][0] = minlight; + l->lightmaps[i][j][1] = minlight; + l->lightmaps[i][j][2] = minlight; + } + } + } +} + + +/* +============ +LightFace +============ +*/ +void LightFace (int surfnum) +{ + dface_t *f; + lightinfo_t l; + int s, t; + int i,j,c; + vec3_t total; + int size; + int lightmapwidth, lightmapsize; + byte *out; + vec3_t *light; + int w, h; + int clamp = 192; + float clampfactor = 0.75; + + if ( !clamp192 ) + { + clamp = 255; + clampfactor = 1.0; + } + + f = dfaces + surfnum; + +// +// some surfaces don't need lightmaps +// + f->lightofs = -1; + for (j=0 ; jstyles[j] = 255; + + if ( texinfo[f->texinfo].flags & TEX_SPECIAL) + { // non-lit texture + return; + } + + memset (&l, 0, sizeof(l)); + l.surfnum = surfnum; + l.face = f; + +// +// rotate plane +// + VectorCopy (dplanes[f->planenum].normal, l.facenormal); + l.facedist = dplanes[f->planenum].dist; + if (f->side) + { + VectorSubtract (vec3_origin, l.facenormal, l.facenormal); + l.facedist = -l.facedist; + } + + + + CalcFaceVectors (&l); + CalcFaceExtents (&l); + CalcPoints (&l); + + lightmapwidth = l.texsize[0]+1; + + size = lightmapwidth*(l.texsize[1]+1); + if (size > SINGLEMAP) + Error ("Bad lightmap size"); + + for (i=0 ; istyles[i] = l.lightstyles[i]; + + if( hicolor ) + lightmapsize = size*l.numlightstyles*3; + else + lightmapsize = size * l.numlightstyles; + + out = GetFileSpace (lightmapsize); + f->lightofs = out - filebase; + +// extra filtering + h = (l.texsize[1]+1)*2; + w = (l.texsize[0]+1)*2; + + for (i=0 ; i< l.numlightstyles ; i++) + { + if (l.lightstyles[i] == 0xff) + Error ("Wrote empty lightmap"); + light = l.lightmaps[i]; + c = 0; + for (t=0 ; t<=l.texsize[1] ; t++) + { + for (s=0 ; s<=l.texsize[0] ; s++, c++) + { + if (extrasamples) + { +#ifdef OLD_CODE + // filtered sample + VectorCopy( light[t*2*w+s*2], total ); + VectorAdd( total, light[t*2*w+s*2+1], total ); + VectorAdd( total, light[(t*2+1)*w+s*2], total ); + VectorAdd( total, light[(t*2+1)*w+s*2+1], total ); + VectorScale( total, 0.25, total ); +#else + int u, v; + float weight[3][3] = + { + { 5, 9, 5 }, + { 9, 16, 9 }, + { 5, 9, 5 }, + }; + float divisor = 0.0; + VectorFill(total,0); + for ( u = 0; u < 3; u++ ) + { + for ( v = 0; v < 3; v++ ) + { + if ( s+u-2>=0 && t+v-1>=0 && s+u-1 <= w && t+v-1 <= h) + { + vec3_t sample; + VectorScale( light[((t*2)+(v-1))*w + ((s*2)+(u-1))], weight[u][v], sample ); + divisor += weight[u][v]; + VectorAdd( total, sample, total ); + } + } + } +#endif + if ( divisor > 1.0 ) + VectorScale( total, 1/divisor, total ); + total[0] = max(total[0],0.0); + total[1] = max(total[1],0.0); + total[2] = max(total[2],0.0); + } + else + VectorCopy( light[ c ], total ); + + // Scale + VectorScale( total, rangescale, total ); + + // Clamp + if( hicolor ) + { + for( j=0; j<3; j++ ) + { + total[ j ] *= clampfactor; + + if( total[j] > clamp) + total[j] = clamp; + else if (total[j] < 0) + Error ("light < 0"); + + *out++ = (byte) total[j]; + } + } + else + { + int intensity = total[ 0 ] + total[ 1 ] + total[ 2 ]; + if( intensity > 255 ) + intensity = 255; + else if( intensity < 0 ) + Error( "light < 0" ); + + *out++ = (byte) intensity; + } + } + } + } +} + diff --git a/utils/light/trace.c b/utils/light/trace.c new file mode 100644 index 0000000..63e224c --- /dev/null +++ b/utils/light/trace.c @@ -0,0 +1,199 @@ +// trace.c + +#include "light.h" + +typedef struct tnode_s +{ + int type; + vec3_t normal; + float dist; + int children[2]; + int pad; +} tnode_t; + +tnode_t *tnodes, *tnode_p; + +/* +============== +MakeTnode + +Converts the disk node structure into the efficient tracing structure +============== +*/ +void MakeTnode (int nodenum) +{ + tnode_t *t; + dplane_t *plane; + int i; + dnode_t *node; + + t = tnode_p++; + + node = dnodes + nodenum; + plane = dplanes + node->planenum; + + t->type = plane->type; + VectorCopy (plane->normal, t->normal); + t->dist = plane->dist; + + for (i=0 ; i<2 ; i++) + { + if (node->children[i] < 0) + t->children[i] = dleafs[-node->children[i] - 1].contents; + else + { + t->children[i] = tnode_p - tnodes; + MakeTnode (node->children[i]); + } + } + +} + + +/* +============= +MakeTnodes + +Loads the node structure out of a .bsp file to be used for light occlusion +============= +*/ +void MakeTnodes (dmodel_t *bm) +{ + if (!numnodes) + Error ("Map has no nodes\n"); + tnode_p = tnodes = malloc(numnodes * sizeof(tnode_t)); + + MakeTnode (0); +} + + + +/* +============================================================================== + +LINE TRACING + +The major lighting operation is a point to point visibility test, performed +by recursive subdivision of the line by the BSP tree. + +============================================================================== +*/ + +typedef struct +{ + vec3_t backpt; + int side; + int node; +} tracestack_t; + + +/* +============== +TestLine +============== +*/ +qboolean TestLine (vec3_t start, vec3_t stop) +{ + int node; + float front, back; + tracestack_t *tstack_p; + int side; + float frontx,fronty, frontz, backx, backy, backz; + tracestack_t tracestack[64]; + tnode_t *tnode; + + frontx = start[0]; + fronty = start[1]; + frontz = start[2]; + backx = stop[0]; + backy = stop[1]; + backz = stop[2]; + + tstack_p = tracestack; + node = 0; + + while (1) + { + while (node < 0 && node != CONTENTS_SOLID) + { + // pop up the stack for a back side + tstack_p--; + if (tstack_p < tracestack) + return true; + node = tstack_p->node; + + // set the hit point for this plane + + frontx = backx; + fronty = backy; + frontz = backz; + + // go down the back side + + backx = tstack_p->backpt[0]; + backy = tstack_p->backpt[1]; + backz = tstack_p->backpt[2]; + + node = tnodes[tstack_p->node].children[!tstack_p->side]; + } + + if (node == CONTENTS_SOLID) + return false; // DONE! + + tnode = &tnodes[node]; + + switch (tnode->type) + { + case PLANE_X: + front = frontx - tnode->dist; + back = backx - tnode->dist; + break; + case PLANE_Y: + front = fronty - tnode->dist; + back = backy - tnode->dist; + break; + case PLANE_Z: + front = frontz - tnode->dist; + back = backz - tnode->dist; + break; + default: + front = (frontx*tnode->normal[0] + fronty*tnode->normal[1] + frontz*tnode->normal[2]) - tnode->dist; + back = (backx*tnode->normal[0] + backy*tnode->normal[1] + backz*tnode->normal[2]) - tnode->dist; + break; + } + + if (front > -ON_EPSILON && back > -ON_EPSILON) +// if (front > 0 && back > 0) + { + node = tnode->children[0]; + continue; + } + + if (front < ON_EPSILON && back < ON_EPSILON) +// if (front <= 0 && back <= 0) + { + node = tnode->children[1]; + continue; + } + + side = front < 0; + + front = front / (front-back); + + tstack_p->node = node; + tstack_p->side = side; + tstack_p->backpt[0] = backx; + tstack_p->backpt[1] = backy; + tstack_p->backpt[2] = backz; + + tstack_p++; + + backx = frontx + front*(backx-frontx); + backy = fronty + front*(backy-fronty); + backz = frontz + front*(backz-frontz); + + node = tnode->children[side]; + } +} + + diff --git a/utils/makefont/makefont.cpp b/utils/makefont/makefont.cpp new file mode 100644 index 0000000..ea8d568 --- /dev/null +++ b/utils/makefont/makefont.cpp @@ -0,0 +1,494 @@ +/*** +* +* Copyright (c) 1999, 2000 Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ + +#define _NOENUMQBOOL + +#include + +extern "C" +{ + #include "cmdlib.h" + #include "wadlib.h" +} +#include "qfont.h" + +#define DEFAULT_FONT "Arial" + +#define FONT_TAG 6 // Font's are the 6th tag after the TYP_LUMPY base ( 64 )...i.e., type == 70 + +BOOL bItalic = FALSE; +BOOL bBold = FALSE; +BOOL bUnderline = FALSE; + +char fontname[ 256 ]; +int pointsize[3] = { 9, 11, 15 }; + +/* +================= +zeromalloc + +Allocates and zeroes memory +================= +*/ +void *zeromalloc( size_t size ) +{ + unsigned char *pbuffer; + pbuffer = ( unsigned char * )malloc( size ); + if ( !pbuffer ) + { + printf( "Failed on allocation of %i bytes", size ); + exit( -1 ); + } + + memset( pbuffer, 0, size ); + return ( void * )pbuffer; +} + +/* +================= +Draw_SetupConsolePalette + +Set's the palette to full brightness ( 192 ) and +set's up palette entry 0 -- black +================= +*/ +void Draw_SetupConsolePalette( unsigned char *pal ) +{ + unsigned char *pPalette; + int i; + + pPalette = pal; + + *(short *)pPalette = 3 * 256; + pPalette += sizeof( short ); + + for ( i = 0; i < 256; i++ ) + { + pPalette[3 * i + 0 ] = i; + pPalette[3 * i + 1 ] = i; + pPalette[3 * i + 2 ] = i; + } + + // Set palette zero correctly + pPalette[ 0 ] = 0; + pPalette[ 1 ] = 0; + pPalette[ 2 ] = 0; +} + +/* +================= +CreateConsoleFont + +Renders TT font into memory dc and creates appropriate qfont_t structure +================= +*/ + +// YWB: Sigh, VC 6.0's global optimizer causes weird stack fixups in release builds. Disable the globabl optimizer for this function. +#pragma optimize( "g", off ) +qfont_t *CreateConsoleFont( char *pszFont, int nPointSize, BOOL bItalic, BOOL bUnderline, BOOL bBold, int *outsize ) +{ + HDC hdc; + HDC hmemDC; + HBITMAP hbm, oldbm; + RECT rc; + HFONT fnt, oldfnt; + int startchar = 32; + int c; + int i, j; + int x, y; + int nScans; + unsigned char *bits; + BITMAPINFO tempbmi; + BITMAPINFO *pbmi; + BITMAPINFOHEADER *pbmheader; + unsigned char *pqdata; + unsigned char *pCur; + int x1, y1; + unsigned char *pPalette; + qfont_t *pqf = NULL; + int fullsize; + int w = 16; + int h = (128-32)/16; + int charheight = nPointSize + 5; + int charwidth = 16; + RECT rcChar; + + // Create the font + fnt = CreateFont( -nPointSize, 0, 0, 0, bBold ? FW_HEAVY : FW_MEDIUM, bItalic, bUnderline, 0, ANSI_CHARSET, OUT_TT_PRECIS, CLIP_DEFAULT_PRECIS, PROOF_QUALITY, VARIABLE_PITCH | FF_DONTCARE, pszFont ); + + bits = NULL; + + fullsize = sizeof( qfont_t ) - 4 + ( 128 * w * charwidth ) + sizeof(short) + 768 + 64; + + // Store off final size + *outsize = fullsize; + + pqf = ( qfont_t * )zeromalloc( fullsize ); + pqdata = (unsigned char *)pqf + sizeof( qfont_t ) - 4; + + pPalette = pqdata + ( 128 * w * charwidth ); + + // Configure palette + Draw_SetupConsolePalette( pPalette ); + + hdc = GetDC( NULL ); + hmemDC = CreateCompatibleDC( hdc ); + + rc.top = 0; + rc.left = 0; + rc.right = charwidth * w; + rc.bottom = charheight * h; + + hbm = CreateBitmap( charwidth * w, charheight * h, 1, 1, NULL ); + oldbm = (HBITMAP)SelectObject( hmemDC, hbm ); + oldfnt = (HFONT)SelectObject( hmemDC, fnt ); + + SetTextColor( hmemDC, 0x00ffffff ); + SetBkMode( hmemDC, TRANSPARENT ); + + // Paint black background + FillRect( hmemDC, &rc, (HBRUSH)GetStockObject( BLACK_BRUSH ) ); + + // Draw character set into memory DC + for ( j = 0; j < h; j++ ) + { + for ( i = 0; i < w; i++ ) + { + x = i * charwidth; + y = j * charheight; + + c = (char)( startchar + j * w + i ); + + // Only draw printable characters, of course + if ( isprint( c ) && c <= 127 ) + { + // Draw it. + rcChar.left = x + 1; + rcChar.top = y + 1; + rcChar.right = x + charwidth - 1; + rcChar.bottom = y + charheight - 1; + + DrawText( hmemDC, (char *)&c, 1, &rcChar, DT_NOPREFIX | DT_LEFT ); + } + } + } + + // Now turn the qfont into raw format + memset( &tempbmi, 0, sizeof( BITMAPINFO ) ); + pbmheader = ( BITMAPINFOHEADER * )&tempbmi; + + pbmheader->biSize = sizeof( BITMAPINFOHEADER ); + pbmheader->biWidth = w * charwidth; + pbmheader->biHeight = -h * charheight; + pbmheader->biPlanes = 1; + pbmheader->biBitCount = 1; + pbmheader->biCompression = BI_RGB; + + // Find out how big the bitmap is + nScans = GetDIBits( hmemDC, hbm, 0, h * charheight, NULL, &tempbmi, DIB_RGB_COLORS ); + + // Allocate space for all bits + pbmi = ( BITMAPINFO * )zeromalloc( sizeof ( BITMAPINFOHEADER ) + 2 * sizeof( RGBQUAD ) + pbmheader->biSizeImage ); + + memcpy( pbmi, &tempbmi, sizeof( BITMAPINFO ) ); + + bits = ( unsigned char * )pbmi + sizeof( BITMAPINFOHEADER ) + 2 * sizeof( RGBQUAD ); + + // Now read in bits + nScans = GetDIBits( hmemDC, hbm, 0, h * charheight, bits, pbmi, DIB_RGB_COLORS ); + + if ( nScans > 0 ) + { + // Now convert to proper raw format + // + // Now get results from dib + pqf->height = 128; // Always set to 128 + pqf->width = charwidth; + pqf->rowheight = charheight; + pqf->rowcount = h; + pCur = pqdata; + + // Set everything to index 255 ( 0xff ) == transparent + memset( pCur, 0xFF, w * charwidth * pqf->height ); + + for ( j = 0; j < h; j++ ) + { + for ( i = 0; i < w; i++ ) + { + int edge = 1; + int bestwidth; + x = i * charwidth; + y = j * charheight; + + + c = (char)( startchar + j * w + i ); + + pqf->fontinfo[ c ].charwidth = charwidth; + pqf->fontinfo[ c ].startoffset = y * w * charwidth + x; + + bestwidth = 0; + + // In this first pass, place the black drop shadow so characters draw ok in the engine against + // most backgrounds. + // YWB: FIXME, apply a box filter and enable blending? + + // Make it all transparent for starters + for ( y1 = 0; y1 < charheight; y1++ ) + { + for ( x1 = 0; x1 < charwidth; x1++ ) + { + int offset; + offset = ( y + y1 ) * w * charwidth + x + x1 ; + // Dest + pCur = pqdata + offset; + // Assume transparent + pCur[0] = 255; + } + } + + // Put black pixels below and to the right of each pixel + for ( y1 = edge; y1 < charheight - edge; y1++ ) + { + for ( x1 = 0; x1 < charwidth; x1++ ) + { + int offset; + int srcoffset; + + int xx0, yy0; + + offset = ( y + y1 ) * w * charwidth + x + x1 ; + + // Dest + pCur = pqdata + offset; + + for ( xx0 = -edge; xx0 <= edge; xx0++ ) + { + for ( yy0 = -edge; yy0 <= edge; yy0++ ) + { + srcoffset = ( y + y1 + yy0 ) * w * charwidth + x + x1 + xx0; + + if ( bits[ srcoffset >> 3 ] & ( 1 << ( 7 - srcoffset & 7 ) ) ) + { + // Near Black + pCur[0] = 32; + } + } + } + } + } + + // Now copy in the actual font pixels + for ( y1 = 0; y1 < charheight; y1++ ) + { + for ( x1 = 0; x1 < charwidth; x1++ ) + { + int offset; + + offset = ( y + y1 ) * w * charwidth + x + x1; + + // Dest + pCur = pqdata + offset; + + if ( bits[ offset >> 3 ] & ( 1 << ( 7 - offset & 7 ) ) ) + { + if ( x1 > bestwidth ) + { + bestwidth = x1; + } + + // Full color + // FIXME: Enable true palette support in engine? + pCur[0] = 192; + } + } + } + + // bestwidth += 1; + /* + // Now blend it + for ( y1 = 0; y1 < charheight; y1++ ) + { + for ( x1 = 0; x1 < charwidth; x1++ ) + { + int offset; + + offset = ( y + y1 ) * w * charwidth + x + x1; + + // Dest + pCur = pqdata + offset; + + if ( bits[ offset >> 3 ] & ( 1 << ( 7 - offset & 7 ) ) ) + { + if ( x1 > bestwidth ) + { + bestwidth = x1; + } + + // Full color + // FIXME: Enable true palette support in engine? + pCur[0] = 192; + } + } + } + */ + + // Space character width + if ( c == 32 ) + { + bestwidth = 8; + } + else + { + // Small characters needs can be padded a bit so they don't run into each other + if ( bestwidth <= 14 ) + { + bestwidth += 2; + } + } + + // Store off width + pqf->fontinfo[ c ].charwidth = bestwidth; + } + } + } + + // Free memory bits + free ( pbmi ); + + SelectObject( hmemDC, oldfnt ); + DeleteObject( fnt ); + + SelectObject( hmemDC, oldbm ); + + DeleteObject( hbm ); + + DeleteDC( hmemDC ); + ReleaseDC( NULL, hdc ); + + return pqf; +} + +#pragma optimize( "g", on ) + +/* +================= +main + +================= +*/ +int main(int argc, char* argv[]) +{ + int i; + DWORD start, end; + char destfile[1024]; + char sz[ 32 ]; + int outsize[ 3 ]; + + qfont_t *fonts[ 3 ]; + + strcpy( fontname, DEFAULT_FONT ); + + printf("makefont.exe Version 1.0 by valve (%s)\n", __DATE__ ); + + printf ("----- Creating Console Font ----\n"); + + for (i=1 ; i= argc ) + { + Error( "Makefont: Insufficient point sizes specified\n" ); + } + pointsize[0] = atoi( argv[i+1] ); + pointsize[1] = atoi( argv[i+2] ); + pointsize[2] = atoi( argv[i+3] ); + i += 3; + } + else if (!strcmp(argv[i],"-italic")) + { + bItalic = TRUE; + printf ( "italic set\n"); + } + else if (!strcmp(argv[i],"-bold")) + { + bBold = TRUE; + printf ( "bold set\n"); + } + else if (!strcmp(argv[i],"-underline")) + { + bUnderline = TRUE; + printf ( "underline set\n"); + } + else if ( argv[i][0] == '-' ) + { + Error ("Unknown option \"%s\"", argv[i]); + } + else + break; + } + + if ( i != argc - 1 ) + { + Error ("usage: makefont [-font \"fontname\"] [-italic] [-underline] [-bold] [-pointsizes sm med lg] outfile"); + } + + printf( "Creating %i, %i, and %i point %s fonts\n", pointsize[0], pointsize[1], pointsize[2], fontname ); + + start = timeGetTime(); + + // Create the fonts + for ( i = 0 ; i < 3; i++ ) + { + fonts[ i ] = CreateConsoleFont( fontname, pointsize[i], bItalic, bUnderline, bBold, &outsize[ i ] ); + } + + // Create wad file + strcpy (destfile, argv[argc - 1]); + StripExtension (destfile); + DefaultExtension (destfile, ".wad"); + + NewWad( destfile, false ); + + // Add fonts as lumps + for ( i = 0; i < 3; i++ ) + { + sprintf( sz, "font%i", i ); + AddLump( sz, fonts[ i ], outsize[ i ], TYP_LUMPY + FONT_TAG, false ); + } + + // Store results as a WAD3 + // NOTE: ( should be named fonts.wad in the valve\ subdirectory ) + WriteWad( 3 ); + + // Clean up memory + for ( i = 0 ; i < 3; i++ ) + { + free( fonts[ i ] ); + } + + end = timeGetTime (); + + printf ( "%5.5f seconds elapsed\n", (float)( end - start )/1000.0 ); + + // Display for a second since it might not be running from command prompt + Sleep( 1000 ); + return 0; +} diff --git a/utils/makefont/makefont.dsp b/utils/makefont/makefont.dsp new file mode 100644 index 0000000..aece6e0 --- /dev/null +++ b/utils/makefont/makefont.dsp @@ -0,0 +1,138 @@ +# Microsoft Developer Studio Project File - Name="makefont" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=makefont - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "makefont.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "makefont.mak" CFG="makefont - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "makefont - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "makefont - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "makefont - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /Yu"stdafx.h" /FD /c +# ADD CPP /nologo /W3 /GX /Zi /O2 /I "../../common" /I "../common" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX"qfont.h" /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# 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 winmm.lib /nologo /subsystem:console /debug /machine:I386 +# Begin Special Build Tool +TargetPath=.\Release\makefont.exe +SOURCE="$(InputPath)" +PostBuild_Desc=Copyint to valve\ +PostBuild_Cmds=xcopy $(TargetPath) ..\..\..\valve /r /i +# End Special Build Tool + +!ELSEIF "$(CFG)" == "makefont - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# 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" /Yu"stdafx.h" /FD /GZ /c +# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /I "../../common" /I "../common" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX"qfont.h" /FD /GZ /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# 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 winmm.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# Begin Special Build Tool +TargetPath=.\Debug\makefont.exe +SOURCE="$(InputPath)" +PostBuild_Desc=Copyint to valve\ +PostBuild_Cmds=xcopy $(TargetPath) ..\..\..\valve /r /i +# End Special Build Tool + +!ENDIF + +# Begin Target + +# Name "makefont - Win32 Release" +# Name "makefont - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\common\cmdlib.c +# End Source File +# Begin Source File + +SOURCE=.\makefont.cpp +# End Source File +# Begin Source File + +SOURCE=..\common\wadlib.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=..\common\cmdlib.h +# End Source File +# Begin Source File + +SOURCE=.\StdAfx.h +# End Source File +# Begin Source File + +SOURCE=..\common\wadlib.h +# End Source File +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# End Group +# Begin Source File + +SOURCE=.\ReadMe.txt +# End Source File +# End Target +# End Project diff --git a/utils/makefont/makefont.dsw b/utils/makefont/makefont.dsw new file mode 100644 index 0000000..a717f8c --- /dev/null +++ b/utils/makefont/makefont.dsw @@ -0,0 +1,29 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "makefont"=.\makefont.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/utils/makels/mssccprj.scc b/utils/makels/mssccprj.scc index dcdb7e8..db5158e 100644 --- a/utils/makels/mssccprj.scc +++ b/utils/makels/mssccprj.scc @@ -1,4 +1,5 @@ SCC = This is a Source Code Control file [makels.mak] -SCC_Project_Name = "$/HLStandardSDK/SourceCode/utils/makels", MCXHAAAA +SCC_Aux_Path = "\\Jeeves\VSSCODE\" +SCC_Project_Name = "$/Sdk/Standard/utils/makels", LGZBAAAA diff --git a/utils/makevfont/StdAfx.cpp b/utils/makevfont/StdAfx.cpp new file mode 100644 index 0000000..afb75a8 --- /dev/null +++ b/utils/makevfont/StdAfx.cpp @@ -0,0 +1,8 @@ +// stdafx.cpp : source file that includes just the standard includes +// makevfont.pch will be the pre-compiled header +// stdafx.obj will contain the pre-compiled type information + +#include "stdafx.h" + +// TODO: reference any additional headers you need in STDAFX.H +// and not in this file diff --git a/utils/makevfont/StdAfx.h b/utils/makevfont/StdAfx.h new file mode 100644 index 0000000..0027f8c --- /dev/null +++ b/utils/makevfont/StdAfx.h @@ -0,0 +1,23 @@ +// stdafx.h : include file for standard system include files, +// or project specific include files that are used frequently, but +// are changed infrequently +// + +#if !defined(AFX_STDAFX_H__BAA53BFF_1A0D_11D4_8B54_009027BA6863__INCLUDED_) +#define AFX_STDAFX_H__BAA53BFF_1A0D_11D4_8B54_009027BA6863__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + + +#include +#include + + +// TODO: reference additional headers your program requires here + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ will insert additional declarations immediately before the previous line. + +#endif // !defined(AFX_STDAFX_H__BAA53BFF_1A0D_11D4_8B54_009027BA6863__INCLUDED_) diff --git a/utils/makevfont/fileimage.cpp b/utils/makevfont/fileimage.cpp new file mode 100644 index 0000000..bb1265f --- /dev/null +++ b/utils/makevfont/fileimage.cpp @@ -0,0 +1,198 @@ + +#include +#include "fileimage.h" + + +// TGA header. +#pragma pack(1) + class TGAFileHeader + { + public: + unsigned char m_IDLength; + unsigned char m_ColorMapType; + unsigned char m_ImageType; + unsigned short m_CMapStart; + unsigned short m_CMapLength; + unsigned char m_CMapDepth; + unsigned short m_XOffset; + unsigned short m_YOffset; + unsigned short m_Width; + unsigned short m_Height; + unsigned char m_PixelDepth; + unsigned char m_ImageDescriptor; + }; +#pragma pack() + + + +// ---------------------------------------------------------------------------------------- // +// FileImageStream_Memory. +// ---------------------------------------------------------------------------------------- // +FileImageStream_Memory::FileImageStream_Memory(void *pData, int dataLen) +{ + m_pData = (unsigned char*)pData; + m_DataLen = dataLen; + m_CurPos = 0; + m_bError = false; +} + +void FileImageStream_Memory::Read(void *pData, int len) +{ + unsigned char *pOut; + int i; + + pOut = (unsigned char*)pData; + for(i=0; i < len; i++) + { + if(m_CurPos < m_DataLen) + { + pOut[i] = m_pData[m_CurPos]; + ++m_CurPos; + } + else + { + pOut[i] = 0; + m_bError = true; + } + } +} + +bool FileImageStream_Memory::ErrorStatus() +{ + bool ret=m_bError; + m_bError=false; + return ret; +} + + + +// ---------------------------------------------------------------------------------------- // +// Encode/decode functions. +// ---------------------------------------------------------------------------------------- // +static void WriteRun(unsigned char *pColor, FILE *fp, int runLength) +{ + unsigned char runCount; + + runCount = runLength - 1; + runCount |= (1 << 7); + fwrite(&runCount, 1, 1, fp); + fwrite(pColor, 1, 4, fp); +} + + +// Load in a 32-bit TGA file. +bool Load32BitTGA( + FileImageStream *fp, + FileImage *pImage) +{ + TGAFileHeader hdr; + char dummyChar; + int i, x, y; + long color; + int runLength, curOut; + unsigned char *pLine; + unsigned char packetHeader; + + + pImage->Term(); + + // Read and verify the header. + fp->Read(&hdr, sizeof(hdr)); + if(hdr.m_PixelDepth != 32 || hdr.m_ImageType != 10) + return false; + + // Skip the ID area.. + for(i=0; i < hdr.m_IDLength; i++) + fp->Read(&dummyChar, 1); + + pImage->m_Width = hdr.m_Width; + pImage->m_Height = hdr.m_Height; + pImage->m_pData = new unsigned char[hdr.m_Width * hdr.m_Height * 4]; + if(!pImage->m_pData) + return false; + + // Read in the data.. + for(y=pImage->m_Height-1; y >= 0; y--) + { + pLine = &pImage->m_pData[y*pImage->m_Width*4]; + + curOut = 0; + while(curOut < pImage->m_Width) + { + fp->Read(&packetHeader, 1); + + runLength = (int)(packetHeader & ~(1 << 7)) + 1; + if(curOut + runLength > pImage->m_Width) + return false; + + if(packetHeader & (1 << 7)) + { + fp->Read(&color, 4); + for(x=0; x < runLength; x++) + { + *((long*)pLine) = color; + pLine += 4; + } + } + else + { + for(x=0; x < runLength; x++) + { + fp->Read(&color, 4); + *((long*)pLine) = color; + pLine += 4; + } + } + + curOut += runLength; + } + } + + return true; +} + + +// Write a 32-bit TGA file. +void Save32BitTGA( + FILE *fp, + FileImage *pImage) +{ + TGAFileHeader hdr; + int y, runStart, x; + unsigned char *pLine; + + + memset(&hdr, 0, sizeof(hdr)); + hdr.m_PixelDepth = 32; + hdr.m_ImageType = 10; // Run-length encoded RGB. + hdr.m_Width = pImage->m_Width; + hdr.m_Height = pImage->m_Height; + + fwrite(&hdr, 1, sizeof(hdr), fp); + + // Lines are written bottom-up. + for(y=pImage->m_Height-1; y >= 0; y--) + { + pLine = &pImage->m_pData[y*pImage->m_Width*4]; + + runStart = 0; + for(x=0; x < pImage->m_Width; x++) + { + if((x - runStart) >= 128 || + *((long*)&pLine[runStart*4]) != *((long*)&pLine[x*4])) + { + // Encode this run. + WriteRun(&pLine[runStart*4], fp, x - runStart); + runStart = x; + } + } + + // Encode the last run. + if(x - runStart > 0) + { + WriteRun(&pLine[runStart*4], fp, x - runStart); + } + } +} + + diff --git a/utils/makevfont/fileimage.h b/utils/makevfont/fileimage.h new file mode 100644 index 0000000..8bd6800 --- /dev/null +++ b/utils/makevfont/fileimage.h @@ -0,0 +1,85 @@ + +#ifndef __FILEIMAGE_H__ +#define __FILEIMAGE_H__ + + + #include + + + class FileImageStream + { + public: + virtual void Read(void *pOut, int len)=0; + + // Returns true if there were any Read errors. + // Clears error status. + virtual bool ErrorStatus()=0; + }; + + + // Use to read out of a memory buffer.. + class FileImageStream_Memory : public FileImageStream + { + public: + FileImageStream_Memory(void *pData, int dataLen); + + virtual void Read(void *pOut, int len); + virtual bool ErrorStatus(); + + + private: + unsigned char *m_pData; + int m_DataLen; + int m_CurPos; + bool m_bError; + }; + + + + // Generic image representation.. + class FileImage + { + public: + FileImage() + { + Clear(); + } + + ~FileImage() + { + Term(); + } + + void Term() + { + if(m_pData) + delete [] m_pData; + + Clear(); + } + + // Clear the structure without deallocating. + void Clear() + { + m_Width = m_Height = 0; + m_pData = NULL; + } + + int m_Width, m_Height; + unsigned char *m_pData; + }; + + + // Functions to load/save FileImages. + bool Load32BitTGA( + FileImageStream *fp, + FileImage *pImage); + + void Save32BitTGA( + FILE *fp, + FileImage *pImage); + + +#endif + + diff --git a/utils/makevfont/fontfiles.pl b/utils/makevfont/fontfiles.pl new file mode 100644 index 0000000..3763a38 --- /dev/null +++ b/utils/makevfont/fontfiles.pl @@ -0,0 +1,99 @@ + +##################################################################################### +# FontFiles.pl +# Parses the VGUI scheme text files and generates font bitmaps. +# Font bitmaps go in valve\gfx\vgui\fonts or tfc\gfx\vgui\fonts. +##################################################################################### + +##################################################################################### +# NOTE TO MOD AUTHORS +# Point gameDir at the game's root directory. +##################################################################################### + + +$gameDir = "..\\..\\.."; + +# Other paths +$searchDir = "$gameDir\\tfc"; +$makevfontCmd = "release\\makevfont.exe"; +$outDir = "$gameDir\\valve\\gfx\\vgui\\fonts"; + + +# Open stuff and make sure it all exists. +open (TESTFILE1, $makevfontCmd) or die "File $makevfontCmd doesn't exist, please edit the script to point to the right location.\n"; +opendir(DIR, $searchDir) or die "Directory $searchDir doesn't exist, please edit the script to point to the right location.\n"; +opendir(TESTDIR1, $outDir) or die "Directory $outDir doesn't exist, please edit the script to point to the right location.\n"; + + +while($_ = readdir(DIR)) +{ + if($_ =~ /_textscheme.txt/) + { + # Get the filename. + $filename = $_; + + # Extract the prefix. + s{ + (.*)_textscheme\.txt + }{$1}x; + $prefix = $_; + + # Parse it. + $schemeName = ""; + $fontName = ""; + $fontSize = ""; + + open(FILE, "$searchDir\\$filename") or die "Cannot open $filename for read!"; + while() + { + if($_ =~ /SchemeName.*=.*/) + { + # Get SchemeName. + s{ + SchemeName.*=.*\"(.*)\" + }{$1}x; + s{(.*)\n}{$1}x; # For some reason, it captures the carriage return here.. + $schemeName = $_; + } + else + { + if($_ =~ /FontName.*=.*/) + { + # Get FontName. + s{ + FontName.*=.*\"(.*)\" + }{$1}x; + s{(.*)\n}{$1}x; # For some reason, it captures the carriage return here.. + $fontName = $_; + } + else + { + if($_ =~ /FontSize.*=.*/) + { + # Get FontSize. + s{ + FontSize.*=[ ]*(.*) + }{$1}x; + s{(.*)\n}{$1}x; # For some reason, it captures the carriage return here.. + $fontSize = $_; + } + } + } + + if($schemeName =~ /.+/ && $fontName =~ /.+/ && $fontSize =~ /.+/) + { + # Ok, found a scheme.. generate a file for it. + $cmd = "$makevfontCmd -font \"$fontName\" -pointsize $fontSize \"$outDir\\$prefix\_$schemeName.tga\"\n"; + print "$cmd"; + system("$cmd"); + print "\n"; + + $schemeName = ""; + $fontName = ""; + $fontSize = ""; + } + } + } +} + + diff --git a/utils/makevfont/makevfont.cpp b/utils/makevfont/makevfont.cpp new file mode 100644 index 0000000..82ce2a4 --- /dev/null +++ b/utils/makevfont/makevfont.cpp @@ -0,0 +1,378 @@ +// makevfont.cpp : Defines the entry point for the console application. +// + +#include "stdafx.h" +#include "fileimage.h" +#include "vfontdata.h" + + + + +bool CreateVFont( + char *pOutFile, + char *pFontName, + int pointSize, + bool bItalic, + bool bBold, + bool bUnderline) +{ + HFONT hFont, hOldFont; + int i; + char theChar; + SIZE charSize; + int bitmapCharWidth, bitmapCharHeight; + HDC hDC, hMemDC; + bool bRet; + RECT rc, rcChar; + HBITMAP hBitmap, hOldBitmap; + BITMAPINFOHEADER *pbmheader; + BITMAPINFO tempbmi; + BITMAPINFO *pbmi; + unsigned char *bits; + int nScans; + FileImage fileImage; + FILE *fp; + + + hFont = hOldFont = NULL; + hDC = hMemDC = NULL; + hBitmap = hOldBitmap = NULL; + pbmi = NULL; + bRet = true; + + + // Make the font. + hFont = CreateFont( + pointSize, + 0, + 0, + 0, + bBold ? FW_HEAVY : FW_MEDIUM, + bItalic, + bUnderline, + 0, + ANSI_CHARSET, + OUT_TT_PRECIS, + CLIP_DEFAULT_PRECIS, + PROOF_QUALITY, + VARIABLE_PITCH | FF_DONTCARE, + pFontName); + + if(!hFont) + { + printf("CreateFont failed!\n"); + goto HANDLE_ERROR; + } + + hDC = GetDC(NULL); + hMemDC = CreateCompatibleDC(hDC); + if(!hMemDC) + { + printf("CreateCompatibleDC failed!\n"); + goto HANDLE_ERROR; + } + hOldFont = (HFONT)SelectObject(hMemDC, hFont); + + // Figure out the biggest character. + bitmapCharWidth = bitmapCharHeight = 0; + for(i=0; i < NUM_VFONT_CHARS; i++) + { + theChar = (char)i; + if(!GetTextExtentPoint32(hMemDC, &theChar, 1, &charSize)) + { + printf("GetTextExtentPoint32 failed!\n"); + goto HANDLE_ERROR; + } + + if(charSize.cx > bitmapCharWidth) + bitmapCharWidth = charSize.cx; + + if(charSize.cy > bitmapCharHeight) + bitmapCharHeight = charSize.cy; + } + + // We get 1 pixel of padding because, for some reason, Windows likes to clip off the left pixel + // on some letters like W. + bitmapCharWidth++; + + // Setup our bitmap. + hBitmap = CreateBitmap(bitmapCharWidth * NUM_VFONT_CHARS, bitmapCharHeight, 1, 1, NULL); + if(!hBitmap) + { + printf("CreateBitmap failed!\n"); + goto HANDLE_ERROR; + } + hOldBitmap = (HBITMAP)SelectObject(hMemDC, hBitmap); + + SetTextColor( hMemDC, 0x00ffffff ); + SetBkMode( hMemDC, TRANSPARENT ); + + // Fill the background. + rc.left = rc.top = 0; + rc.right = bitmapCharWidth * NUM_VFONT_CHARS; + rc.bottom = bitmapCharHeight; + FillRect( hMemDC, &rc, (HBRUSH)GetStockObject( BLACK_BRUSH ) ); + + // Draw characters in. + for(i=0; i < NUM_VFONT_CHARS; i++) + { + // Draw the letter in the first slot for a letter. + rcChar.left = 0; + rcChar.top = 0; + rcChar.right = bitmapCharWidth; + rcChar.bottom = bitmapCharHeight; + FillRect( hMemDC, &rcChar, (HBRUSH)GetStockObject( BLACK_BRUSH ) ); + + if(i != '\t') + { + rcChar.left = 1; // 1-pixel border for letters like W... + theChar = (char)i; + DrawText(hMemDC, &theChar, 1, &rcChar, DT_NOPREFIX | DT_LEFT); + + // Blit into the correct spot (by drawing/blitting, it sort of automatically clips the letter into + // its box (Windows seems to want to draw some of them out of their bounding box). + rcChar.left = i * bitmapCharWidth; + rcChar.top = 0; + rcChar.right = (i+1) * bitmapCharWidth; + rcChar.bottom = bitmapCharHeight; + + if(!BitBlt(hMemDC, + i * bitmapCharWidth, + 0, + bitmapCharWidth, + bitmapCharHeight, + hMemDC, + 0, + 0, + SRCCOPY)) + { + printf("BitBlt failed!\n"); + goto HANDLE_ERROR; + } + } + } + + // Get the bits out. + memset(&tempbmi, 0, sizeof(BITMAPINFO)); + pbmheader = ( BITMAPINFOHEADER * )&tempbmi; + + pbmheader->biSize = sizeof( BITMAPINFOHEADER ); + pbmheader->biWidth = bitmapCharWidth * NUM_VFONT_CHARS; + pbmheader->biHeight = -bitmapCharHeight; + pbmheader->biPlanes = 1; + pbmheader->biBitCount = 32; + pbmheader->biCompression = BI_RGB; + + // Figure out how many bytes to allocate and setup a buffer. + nScans = GetDIBits(hMemDC, hBitmap, 0, bitmapCharHeight, NULL, &tempbmi, DIB_RGB_COLORS); + pbmi = ( BITMAPINFO * )malloc( sizeof ( BITMAPINFOHEADER ) + 2 * sizeof( RGBQUAD ) + pbmheader->biSizeImage ); + memcpy( pbmi, &tempbmi, sizeof( BITMAPINFO ) ); + bits = ( unsigned char * )pbmi + sizeof( BITMAPINFOHEADER ) + 2 * sizeof( RGBQUAD ); + + // Read the bits in. + nScans = GetDIBits(hMemDC, hBitmap, 0, bitmapCharHeight, bits, pbmi, DIB_RGB_COLORS); + if(nScans == 0) + { + printf("GetDIBits failed!\n"); + goto HANDLE_ERROR; + } + + + // Save as a PCX/TGA file. + fp = fopen(pOutFile, "wb"); + if(!fp) + { + printf("fopen(%s, \"wb\") failed!\n", pOutFile); + goto HANDLE_ERROR; + } + + fileImage.m_Width = bitmapCharWidth * NUM_VFONT_CHARS; + fileImage.m_Height = bitmapCharHeight; + fileImage.m_pData = (unsigned char*)bits; + Save32BitTGA(fp, &fileImage); + fileImage.Clear(); + + fclose(fp); + + goto CLEANUP; + + +HANDLE_ERROR:; + bRet = false; + + +CLEANUP:; + if(hMemDC) + { + if(hOldBitmap) + SelectObject(hMemDC, hOldBitmap); + + if(hOldFont) + SelectObject(hMemDC, hOldFont); + + DeleteDC(hMemDC); + } + + if(hBitmap) + { + DeleteObject(hBitmap); + } + + if(hFont) + { + DeleteObject(hFont); + } + + if(pbmi) + { + free(pbmi); + } + + return true; +} + + +/* +// Writes out a test string to "testout.tga" using the font it just generated for debugging purposes. +void DoTest(char *pFilename) +{ + // TEST. + FILE *fp; + VFontData fontData; + char *pStr = "Blah blah blah. This is a string of text I am printing out. \"Here is something in quotes, blah blah blah.\""; + int len, curXOffset, iChar, width, x, y; + HWND hWnd; + HDC hDC; + FileImage outImage; + + + + fp=fopen(pFilename, "rb"); + LoadVFontDataFrom32BitTGA(fp, &fontData); + + int spacing=1; + + len = strlen(pStr); + outImage.m_Width = fontData.m_BitmapCharWidth * len + len*spacing; + outImage.m_Height = fontData.m_BitmapCharHeight; + outImage.m_pData = new unsigned char[outImage.m_Width * outImage.m_Height * 4]; + memset(outImage.m_pData, 0, outImage.m_Width*outImage.m_Height); + + hWnd = GetDesktopWindow(); + hDC = GetDC(hWnd); + + curXOffset = 0; + for(iChar=0; iChar < len; iChar++) + { + width = fontData.m_CharWidths[(unsigned char)pStr[iChar]]+1; + for(y=0; y < fontData.m_BitmapCharHeight; y++) + { + for(x=0; x < width; x++) + { + if(fontData.m_pBitmap[y*fontData.GetLineWidth()+x+(unsigned char)pStr[iChar]*fontData.m_BitmapCharWidth]) + { + *((unsigned long*)&outImage.m_pData[(y*outImage.m_Width+curXOffset+x)*4]) = 0xFFFFFFFF; + } + else + { + *((long*)&outImage.m_pData[(y*outImage.m_Width+curXOffset+x)*4]) = 0; + } + } + + for(x=0; x < spacing; x++) + { + *((long*)&outImage.m_pData[(y*outImage.m_Width+curXOffset+width+x)*4]) = 0; + } + } + + curXOffset += width + spacing; + } + + ReleaseDC(hWnd, hDC); + + fclose(fp); + + + fp = fopen("testout.tga", "wb"); + Save32BitTGA(fp, &outImage); + fclose(fp); +} +*/ + + +int main(int argc, char* argv[]) +{ + char fontName[256]; + int pointSize; + bool bItalic, bBold, bUnderline; + int i; + + + // Setup defaults. + strcpy(fontName, "Arial"); + pointSize = 7; + bItalic = bBold = bUnderline = false; + + + printf("makevfont.exe Version 1.0 by Valve (%s)\n", __DATE__ ); + printf ("----- Creating Font ----\n"); + + + // Read parameters in. + for (i=1 ; i= argc ) + { + printf( "MakeVFont: Insufficient point sizes specified\n" ); + return -1; + } + pointSize = atoi( argv[i+1] ); + i += 1; + } + else if (!strcmp(argv[i],"-italic")) + { + bItalic = true; + printf ( "italic set\n"); + } + else if (!strcmp(argv[i],"-bold")) + { + bBold = true; + printf ( "bold set\n"); + } + else if (!strcmp(argv[i],"-underline")) + { + bUnderline = true; + printf ( "underline set\n"); + } + else if ( argv[i][0] == '-' ) + { + printf("Unknown option \"%s\"", argv[i]); + return -1; + } + else + break; + } + + if ( i != argc - 1 ) + { + printf("usage: makevfont [-font \"fontname\"] [-italic] [-underline] [-bold] [-pointsize size] outfile"); + return -1; + } + + CreateVFont( + argv[argc-1], + fontName, + pointSize, + bItalic, + bBold, + bUnderline); + + return 0; +} diff --git a/utils/makevfont/makevfont.dsp b/utils/makevfont/makevfont.dsp new file mode 100644 index 0000000..d023e7b --- /dev/null +++ b/utils/makevfont/makevfont.dsp @@ -0,0 +1,123 @@ +# Microsoft Developer Studio Project File - Name="makevfont" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=makevfont - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "makevfont.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "makevfont.mak" CFG="makevfont - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "makevfont - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "makevfont - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "makevfont - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /Yu"stdafx.h" /FD /c +# ADD CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /Yu"stdafx.h" /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# 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 /nologo /subsystem:console /machine:I386 + +!ELSEIF "$(CFG)" == "makevfont - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /Yu"stdafx.h" /FD /GZ /c +# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /Yu"stdafx.h" /FD /GZ /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# 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 /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "makevfont - Win32 Release" +# Name "makevfont - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\fileimage.cpp +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=.\makevfont.cpp +# End Source File +# Begin Source File + +SOURCE=.\StdAfx.cpp +# ADD CPP /Yc"stdafx.h" +# End Source File +# Begin Source File + +SOURCE=.\vfontdata.cpp +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=.\StdAfx.h +# End Source File +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# End Group +# Begin Source File + +SOURCE=.\ReadMe.txt +# End Source File +# End Target +# End Project diff --git a/utils/makevfont/vfontdata.cpp b/utils/makevfont/vfontdata.cpp new file mode 100644 index 0000000..6f75e77 --- /dev/null +++ b/utils/makevfont/vfontdata.cpp @@ -0,0 +1,77 @@ + +#include "vfontdata.h" +#include "fileimage.h" + + + +VFontData::VFontData() +{ + m_BitmapCharWidth = m_BitmapCharHeight = 0; + m_pBitmap = NULL; +} + +VFontData::~VFontData() +{ + if(m_pBitmap) + delete [] m_pBitmap; +} + + + +bool LoadVFontDataFrom32BitTGA(FileImageStream *fp, VFontData *pData) +{ + FileImage fileImage; + unsigned char *pInLine, *pOutLine; + int i, x, y; + int rightX; + + + if(!Load32BitTGA(fp, &fileImage)) + return false; + + pData->m_pBitmap = new unsigned char[fileImage.m_Width * fileImage.m_Height]; + if(!pData->m_pBitmap) + return false; + + pData->m_BitmapCharWidth = fileImage.m_Width / NUM_VFONT_CHARS; + pData->m_BitmapCharHeight = fileImage.m_Height; + + // Convert the data and figure out the extents of each letter. + for(i=0; i < NUM_VFONT_CHARS; i++) + { + pInLine = &fileImage.m_pData[i * pData->m_BitmapCharWidth * 4]; + pOutLine = &pData->m_pBitmap[i * pData->m_BitmapCharWidth]; + + rightX = 0; + for(y=0; y < pData->m_BitmapCharHeight; y++) + { + for(x=0; x < pData->m_BitmapCharWidth; x++) + { + if(*((long*)&pInLine[x*4])) + { + pOutLine[x] = 1; + if(x > rightX) + rightX = x; + } + else + { + pOutLine[x] = 0; + } + } + + pInLine += pData->m_BitmapCharWidth * NUM_VFONT_CHARS * 4; + pOutLine += pData->m_BitmapCharWidth * NUM_VFONT_CHARS; + } + + // Wouldn't normally detect any spacing for the space character.. + if(i == ' ') + pData->m_CharWidths[i] = pData->m_BitmapCharWidth / 4; + else + pData->m_CharWidths[i] = rightX; + } + + return true; +} + + + diff --git a/utils/makevfont/vfontdata.h b/utils/makevfont/vfontdata.h new file mode 100644 index 0000000..a552094 --- /dev/null +++ b/utils/makevfont/vfontdata.h @@ -0,0 +1,44 @@ + +#ifndef __VFONTDATA_H__ +#define __VFONTDATA_H__ + + + #include + #include "fileimage.h" + + + #define NUM_VFONT_CHARS 256 + + + class VFontData + { + public: + VFontData(); + ~VFontData(); + + // Line width in pixels. + int GetLineWidth() {return m_BitmapCharWidth * NUM_VFONT_CHARS;} + + + public: + + int m_CharWidths[NUM_VFONT_CHARS]; + + // The letters are placed in the bitmap at constant spacing. + // m_CharWidths is used while drawing. + int m_BitmapCharWidth; + int m_BitmapCharHeight; + + // Each pixel is a byte - 1 or 0. + unsigned char *m_pBitmap; + }; + + + // Setup a VFontData from a TGA file. + bool LoadVFontDataFrom32BitTGA(FileImageStream *fp, VFontData *pData); + + +#endif + + + diff --git a/utils/mkmovie/mssccprj.scc b/utils/mkmovie/mssccprj.scc index 29391de..70bf234 100644 --- a/utils/mkmovie/mssccprj.scc +++ b/utils/mkmovie/mssccprj.scc @@ -1,4 +1,5 @@ SCC = This is a Source Code Control file [mkmovie.mak] -SCC_Project_Name = "$/HLStandardSDK/SourceCode/utils/mkmovie", YCXHAAAA +SCC_Aux_Path = "\\Jeeves\VSSCODE\" +SCC_Project_Name = "$/Sdk/Standard/utils/mkmovie", XGZBAAAA diff --git a/utils/procinfo/lib/win32_vc6/procinfo.lib b/utils/procinfo/lib/win32_vc6/procinfo.lib new file mode 100644 index 0000000000000000000000000000000000000000..536951d9e420bac9a83513bf6867609fd764086f GIT binary patch literal 2468 zcmcImO>7%Q6n>jc?BE31&`|NKy2x-r7&}f(eo*ViF(krn9RH+l<96eCH^~MkHugGH z0->N#A!|X(rMI-AIaG){QknyDl|!iDzyU?!ii%`G4iyq2sv^vL`~|*zfG?9dx_hjkMLF-8-HA8k#WyKnDP~-Q3QObV` z((~mo;cax7G;sRwf6caOdr#Wk-fFVe8IwI8l2TG4C&e?_bW&cPOWV`4i?{>TQfTY? zw=ta#2P>l!t67oGnEYHPy!`by11s$Sui!3_*~P4sR92+Q9Y6>{gtn^QOct;!(siYd zb0EIkq_bLrGtD{=>h@4~x~&pSA+2;Yo>kLSl&y8E*cn9KkDAs>o0$U9K;NYm-#WyOS&z)sDc#j6|l?IJcZx_B%e&+DQzm&m7- zlsr3>$4A_bz6)78^ zPp8COHW|+=aw?~vbULsnGn8A!JjwJ@#x9GcGhIL#@eOAe6@lmI^lG&F_nnRmo^xn| zv7l|aaxM@-t08N{-Dzt$?dV|OIS+c8VK4%MQlCS>i$ zqB@Y}xmEOZ4*k&``=J))Mux0|MG^9oV@5fXC7372R#A5*(zC#GR38r8qaA(ahLN>rQKW8hMV+YpTISchA0&t<)Bwocmb})4*-SCw`k8|C(v} zwIT@eQbrIIc}c>E2wpr65Cr^dNQv@FtB)B$kgg}Cj3T7uoPtvAZXvNOrlhP3{sBxs B`e*] [-draw] [-glview] [-noclip] [-onlyents] [-proj ] [-threads #] [-v] mapfile"); + Error ("usage: qcsg [-nowadtextures] [-wadinclude ] [-draw] [-glview] [-noclip] [-onlyents] [-proj ] [-threads #] [-v] [-hullfile ] mapfile"); SetThreadPriority(GetCurrentThread(),THREAD_PRIORITY_ABOVE_NORMAL); start = I_FloatTime (); + CheckHullFile( hullfile, qhullfile ); + ThreadSetDefault (); SetQdirFromPath (argv[i]); diff --git a/utils/qcsg/qcsg.dsp b/utils/qcsg/qcsg.dsp index ff913f0..a0da9f4 100644 --- a/utils/qcsg/qcsg.dsp +++ b/utils/qcsg/qcsg.dsp @@ -101,6 +101,10 @@ SOURCE=.\gldraw.c # End Source File # Begin Source File +SOURCE=.\hullfile.c +# End Source File +# Begin Source File + SOURCE=.\map.c # End Source File # Begin Source File diff --git a/utils/qlumpy/mssccprj.scc b/utils/qlumpy/mssccprj.scc index 593c272..be6f84c 100644 --- a/utils/qlumpy/mssccprj.scc +++ b/utils/qlumpy/mssccprj.scc @@ -1,4 +1,5 @@ SCC = This is a Source Code Control file [qlumpy.mak] -SCC_Project_Name = "$/HLStandardSDK/SourceCode/utils/qlumpy", CEXHAAAA +SCC_Aux_Path = "\\Jeeves\VSSCODE\" +SCC_Project_Name = "$/Sdk/Standard/utils/qlumpy", HIZBAAAA diff --git a/utils/qrad/mssccprj.scc b/utils/qrad/mssccprj.scc index 128dec3..c9a109f 100644 --- a/utils/qrad/mssccprj.scc +++ b/utils/qrad/mssccprj.scc @@ -1,4 +1,5 @@ SCC = This is a Source Code Control file [qrad.mak] -SCC_Project_Name = "$/HLStandardSDK/SourceCode/utils/qrad", JEXHAAAA +SCC_Aux_Path = "\\Jeeves\VSSCODE\" +SCC_Project_Name = "$/Sdk/Standard/utils/qrad", OIZBAAAA diff --git a/utils/serverctrl/ServerCtrl.cpp b/utils/serverctrl/ServerCtrl.cpp new file mode 100644 index 0000000..4dc8854 --- /dev/null +++ b/utils/serverctrl/ServerCtrl.cpp @@ -0,0 +1,61 @@ +// ServerCtrl.cpp : Defines the class behaviors for the application. +// + +#include "stdafx.h" +#include "ServerCtrl.h" +#include "ServerCtrlDlg.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// CServerCtrlApp + +BEGIN_MESSAGE_MAP(CServerCtrlApp, CWinApp) + //{{AFX_MSG_MAP(CServerCtrlApp) + //}}AFX_MSG + ON_COMMAND(ID_HELP, CWinApp::OnHelp) +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// CServerCtrlApp construction + +CServerCtrlApp::CServerCtrlApp() +{ +} + +///////////////////////////////////////////////////////////////////////////// +// The one and only CServerCtrlApp object + +CServerCtrlApp theApp; + +///////////////////////////////////////////////////////////////////////////// +// CServerCtrlApp initialization + +BOOL CServerCtrlApp::InitInstance() +{ + // Standard initialization + +#ifdef _AFXDLL + Enable3dControls(); // Call this when using MFC in a shared DLL +#else + Enable3dControlsStatic(); // Call this when linking to MFC statically +#endif + + CServerCtrlDlg dlg; + m_pMainWnd = &dlg; + int nResponse = dlg.DoModal(); + if (nResponse == IDOK) + { + } + else if (nResponse == IDCANCEL) + { + } + + // Since the dialog has been closed, return FALSE so that we exit the + // application, rather than start the application's message pump. + return FALSE; +} diff --git a/utils/serverctrl/ServerCtrl.h b/utils/serverctrl/ServerCtrl.h new file mode 100644 index 0000000..32a2e75 --- /dev/null +++ b/utils/serverctrl/ServerCtrl.h @@ -0,0 +1,47 @@ +// ServerCtrl.h : main header file for the ServerCtrl application +// + +#if !defined(AFX_ServerCtrl_H__E2974CA6_EF9F_11D3_A4D9_00105A1727F3__INCLUDED_) +#define AFX_ServerCtrl_H__E2974CA6_EF9F_11D3_A4D9_00105A1727F3__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +#ifndef __AFXWIN_H__ + #error include 'stdafx.h' before including this file for PCH +#endif + +#include "resource.h" // main symbols + +///////////////////////////////////////////////////////////////////////////// +// CServerCtrlApp: +// See ServerCtrl.cpp for the implementation of this class +// + +class CServerCtrlApp : public CWinApp +{ +public: + CServerCtrlApp(); + +// Overrides + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(CServerCtrlApp) + public: + virtual BOOL InitInstance(); + //}}AFX_VIRTUAL + +// Implementation + + //{{AFX_MSG(CServerCtrlApp) + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; + + +///////////////////////////////////////////////////////////////////////////// + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ will insert additional declarations immediately before the previous line. + +#endif // !defined(AFX_ServerCtrl_H__E2974CA6_EF9F_11D3_A4D9_00105A1727F3__INCLUDED_) diff --git a/utils/serverctrl/ServerCtrl.rc b/utils/serverctrl/ServerCtrl.rc new file mode 100644 index 0000000..e1f4da5 --- /dev/null +++ b/utils/serverctrl/ServerCtrl.rc @@ -0,0 +1,179 @@ +//Microsoft Developer Studio generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (U.S.) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE DISCARDABLE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE DISCARDABLE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE DISCARDABLE +BEGIN + "#define _AFX_NO_SPLITTER_RESOURCES\r\n" + "#define _AFX_NO_OLE_RESOURCES\r\n" + "#define _AFX_NO_TRACKER_RESOURCES\r\n" + "#define _AFX_NO_PROPERTY_RESOURCES\r\n" + "\r\n" + "#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)\r\n" + "#ifdef _WIN32\r\n" + "LANGUAGE 9, 1\r\n" + "#pragma code_page(1252)\r\n" + "#endif //_WIN32\r\n" + "#include ""res\\serverctrl.rc2"" // non-Microsoft Visual C++ edited resources\r\n" + "#include ""afxres.rc"" // Standard components\r\n" + "#endif\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +IDR_MAINFRAME ICON DISCARDABLE "res\\serverctrl.ico" + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_SERVERCTRL_DIALOG DIALOGEX 0, 0, 549, 281 +STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU +EXSTYLE WS_EX_APPWINDOW +CAPTION "Valve Server Controller" +FONT 8, "MS Sans Serif" +BEGIN + PUSHBUTTON "Execute",IDC_BTN_EXECUTE,160,7,48,12 + PUSHBUTTON "Get Text",IDC_BTN_GET,159,24,48,12 + PUSHBUTTON "Start Server",IDC_BTN_START,478,54,64,12 + DEFPUSHBUTTON "OK",IDOK,492,7,50,14 + EDITTEXT IDC_EDIT_COMMANDS,7,7,144,12,ES_AUTOHSCROLL + EDITTEXT IDC_EDIT_CONSOLE,7,56,434,218,ES_MULTILINE | + ES_AUTOVSCROLL | ES_AUTOHSCROLL | ES_READONLY +END + + +#ifndef _MAC +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 1,0,0,1 + PRODUCTVERSION 1,0,0,1 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x4L + FILETYPE 0x1L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904B0" + BEGIN + VALUE "CompanyName", "\0" + VALUE "FileDescription", "serverctrl MFC Application\0" + VALUE "FileVersion", "1, 0, 0, 1\0" + VALUE "InternalName", "serverctrl\0" + VALUE "LegalCopyright", "Copyright (C) 2000\0" + VALUE "LegalTrademarks", "\0" + VALUE "OriginalFilename", "serverctrl.EXE\0" + VALUE "ProductName", "serverctrl Application\0" + VALUE "ProductVersion", "1, 0, 0, 1\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END + +#endif // !_MAC + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO DISCARDABLE +BEGIN + IDD_SERVERCTRL_DIALOG, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 542 + TOPMARGIN, 7 + BOTTOMMARGIN, 274 + END +END +#endif // APSTUDIO_INVOKED + +#endif // English (U.S.) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// +#define _AFX_NO_SPLITTER_RESOURCES +#define _AFX_NO_OLE_RESOURCES +#define _AFX_NO_TRACKER_RESOURCES +#define _AFX_NO_PROPERTY_RESOURCES + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +#ifdef _WIN32 +LANGUAGE 9, 1 +#pragma code_page(1252) +#endif //_WIN32 +#include "res\serverctrl.rc2" // non-Microsoft Visual C++ edited resources +#include "afxres.rc" // Standard components +#endif + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/utils/serverctrl/ServerCtrlDlg.cpp b/utils/serverctrl/ServerCtrlDlg.cpp new file mode 100644 index 0000000..cdf162b --- /dev/null +++ b/utils/serverctrl/ServerCtrlDlg.cpp @@ -0,0 +1,658 @@ +// ServerCtrlDlg.cpp : implementation file +// + +#include "stdafx.h" +#include +#include +#include "ServerCtrl.h" +#include "ServerCtrlDlg.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +// Each ENGINE command token is a 32 bit integer + +#define ENGINE_ISSUE_COMMANDS 0x2 +// Param1 : char * text to issue + +#define ENGINE_RETRIEVE_CONSOLE_CONTENTS 0x3 +// Param1 : int32 Begin line +// Param2 : int32 End line + +#define ENGINE_RETRIEVE_GET_CONSOLE_HEIGHT 0x4 +// No params + +#define ENGINE_RETRIEVE_SET_CONSOLE_HEIGHT 0x5 +// Param1 : int32 Number of lines + +///////////////////////////////////////////////////////////////////////////// +// CServerCtrlDlg dialog + +CServerCtrlDlg::CServerCtrlDlg(CWnd* pParent /*=NULL*/) + : CDialog(CServerCtrlDlg::IDD, pParent) +{ + //{{AFX_DATA_INIT(CServerCtrlDlg) + // NOTE: the ClassWizard will add member initialization here + //}}AFX_DATA_INIT + m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME); + + memset( &PI, 0, sizeof( PI ) ); + + m_nPendingRequest = 0; + m_nPendingLines = 0; + + m_hMappedFile = (HANDLE)0; + m_hSend = (HANDLE)0; + m_hReceive = (HANDLE)0; + + m_bOnlyPumpIfMessageInQueue = FALSE; +} + +void CServerCtrlDlg::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); + //{{AFX_DATA_MAP(CServerCtrlDlg) + // NOTE: the ClassWizard will add DDX and DDV calls here + //}}AFX_DATA_MAP +} + +BEGIN_MESSAGE_MAP(CServerCtrlDlg, CDialog) + //{{AFX_MSG_MAP(CServerCtrlDlg) + ON_WM_PAINT() + ON_WM_QUERYDRAGICON() + ON_BN_CLICKED(IDC_BTN_START, OnBtnStart) + ON_BN_CLICKED(IDC_BTN_EXECUTE, OnBtnExecute) + ON_BN_CLICKED(IDC_BTN_GET, OnBtnGet) + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +int CServerCtrlDlg::RunModalLoop(DWORD dwFlags) +{ + ASSERT(::IsWindow(m_hWnd)); // window must be created + ASSERT(!(m_nFlags & WF_MODALLOOP)); // window must not already be in modal state + + // for tracking the idle time state + BOOL bIdle = TRUE; + LONG lIdleCount = 0; + BOOL bShowIdle = (dwFlags & MLF_SHOWONIDLE) && !(GetStyle() & WS_VISIBLE); + HWND hWndParent = ::GetParent(m_hWnd); + m_nFlags |= (WF_MODALLOOP|WF_CONTINUEMODAL); + MSG* pMsg = &AfxGetThread()->m_msgCur; + + // acquire and dispatch messages until the modal state is done + for (;;) + { + ASSERT(ContinueModal()); + + int iRet = RMLPreIdle(); + + if (iRet < 0) + goto ExitModal; + else if (iRet > 0) + continue; + + // phase1: check to see if we can do idle work + while (bIdle && + !::PeekMessage(pMsg, NULL, NULL, NULL, PM_NOREMOVE)) + { + ASSERT(ContinueModal()); + + // show the dialog when the message queue goes idle + if (bShowIdle) + { + ShowWindow(SW_SHOWNORMAL); + UpdateWindow(); + bShowIdle = FALSE; + } + + // call OnIdle while in bIdle state + if (!(dwFlags & MLF_NOIDLEMSG) && hWndParent != NULL && lIdleCount == 0) + { + // send WM_ENTERIDLE to the parent + ::SendMessage(hWndParent, WM_ENTERIDLE, MSGF_DIALOGBOX, (LPARAM)m_hWnd); + } + if ((dwFlags & MLF_NOKICKIDLE) || + !SendMessage(WM_KICKIDLE, MSGF_DIALOGBOX, lIdleCount++)) + { + // stop idle processing next time + bIdle = FALSE; + } + } + + // phase2: pump messages while available + do + { + BOOL ShouldPump = TRUE; + + ASSERT(ContinueModal()); + + // See if we are requiring messages to be in queue? + if ( m_bOnlyPumpIfMessageInQueue ) + { + // If there isn't a message, don't turn over control to PumpMessage + // since it will block + if ( !::PeekMessage( pMsg, NULL, NULL, NULL, PM_NOREMOVE ) ) + { + ShouldPump = FALSE; + } + } + + // pump message, but quit on WM_QUIT + if ( ShouldPump ) + { + if (!AfxGetThread()->PumpMessage()) + { + AfxPostQuitMessage(0); + return -1; + } + + // show the window when certain special messages rec'd + if (bShowIdle && + (pMsg->message == 0x118 || pMsg->message == WM_SYSKEYDOWN)) + { + ShowWindow(SW_SHOWNORMAL); + UpdateWindow(); + bShowIdle = FALSE; + } + + if (!ContinueModal()) + goto ExitModal; + + // reset "no idle" state after pumping "normal" message + if (AfxGetThread()->IsIdleMessage(pMsg)) + { + bIdle = TRUE; + lIdleCount = 0; + } + } + + } while (::PeekMessage(pMsg, NULL, NULL, NULL, PM_NOREMOVE)); + } +ExitModal: + m_nFlags &= ~(WF_MODALLOOP|WF_CONTINUEMODAL); + return m_nModalResult; +} + +int CServerCtrlDlg::DoModal() +{ + // can be constructed with a resource template or InitModalIndirect + ASSERT(m_lpszTemplateName != NULL || m_hDialogTemplate != NULL || + m_lpDialogTemplate != NULL); + + // load resource as necessary + LPCDLGTEMPLATE lpDialogTemplate = m_lpDialogTemplate; + HGLOBAL hDialogTemplate = m_hDialogTemplate; + HINSTANCE hInst = AfxGetResourceHandle(); + if (m_lpszTemplateName != NULL) + { + hInst = AfxFindResourceHandle(m_lpszTemplateName, RT_DIALOG); + HRSRC hResource = ::FindResource(hInst, m_lpszTemplateName, RT_DIALOG); + hDialogTemplate = LoadResource(hInst, hResource); + } + if (hDialogTemplate != NULL) + lpDialogTemplate = (LPCDLGTEMPLATE)LockResource(hDialogTemplate); + + // return -1 in case of failure to load the dialog template resource + if (lpDialogTemplate == NULL) + return -1; + + // disable parent (before creating dialog) + HWND hWndParent = PreModal(); + AfxUnhookWindowCreate(); + BOOL bEnableParent = FALSE; + if (hWndParent != NULL && ::IsWindowEnabled(hWndParent)) + { + ::EnableWindow(hWndParent, FALSE); + bEnableParent = TRUE; + } + + TRY + { + // create modeless dialog + AfxHookWindowCreate(this); + if (CreateDlgIndirect(lpDialogTemplate, + CWnd::FromHandle(hWndParent), hInst)) + { + if (m_nFlags & WF_CONTINUEMODAL) + { + // enter modal loop + DWORD dwFlags = MLF_SHOWONIDLE; + if (GetStyle() & DS_NOIDLEMSG) + dwFlags |= MLF_NOIDLEMSG; + VERIFY(RunModalLoop(dwFlags) == m_nModalResult); + } + + // hide the window before enabling the parent, etc. + if (m_hWnd != NULL) + SetWindowPos(NULL, 0, 0, 0, 0, SWP_HIDEWINDOW| + SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER); + } + } + CATCH_ALL(e) + { + //DELETE_EXCEPTION(e); + m_nModalResult = -1; + } + END_CATCH_ALL + + if (bEnableParent) + ::EnableWindow(hWndParent, TRUE); + if (hWndParent != NULL && ::GetActiveWindow() == m_hWnd) + ::SetActiveWindow(hWndParent); + + // destroy modal window + DestroyWindow(); + PostModal(); + + // unlock/free resources as necessary + if (m_lpszTemplateName != NULL || m_hDialogTemplate != NULL) + UnlockResource(hDialogTemplate); + if (m_lpszTemplateName != NULL) + FreeResource(hDialogTemplate); + + return m_nModalResult; +} + +void CServerCtrlDlg::SetPumpIfQueued( BOOL bValue ) +{ + m_bOnlyPumpIfMessageInQueue = bValue; +} + +///////////////////////////////////////////////////////////////////////////// +// CServerCtrlDlg message handlers + +BOOL CServerCtrlDlg::OnInitDialog() +{ + CDialog::OnInitDialog(); + + SetIcon(m_hIcon, TRUE); // Set big icon + SetIcon(m_hIcon, FALSE); // Set small icon + + // TODO: Add extra initialization here + SetPumpIfQueued( TRUE ); + + return TRUE; // return TRUE unless you set the focus to a control +} + +// If you add a minimize button to your dialog, you will need the code below +// to draw the icon. For MFC applications using the document/view model, +// this is automatically done for you by the framework. + +void CServerCtrlDlg::OnPaint() +{ + if (IsIconic()) + { + CPaintDC dc(this); // device context for painting + + SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0); + + // Center icon in client rectangle + int cxIcon = GetSystemMetrics(SM_CXICON); + int cyIcon = GetSystemMetrics(SM_CYICON); + CRect rect; + GetClientRect(&rect); + int x = (rect.Width() - cxIcon + 1) / 2; + int y = (rect.Height() - cyIcon + 1) / 2; + + // Draw the icon + dc.DrawIcon(x, y, m_hIcon); + } + else + { + CDialog::OnPaint(); + } +} + +HCURSOR CServerCtrlDlg::OnQueryDragIcon() +{ + return (HCURSOR) m_hIcon; +} + +///////////////////////////////////// +///////////////////////////////////// +// IMPORTANT STUFF STARTS HERE +///////////////////////////////////// + +/* +===================== +ProcessMappedResponse + +The engine has signaled the receive event, see what the results of the command we issued are. +===================== +*/ +int CServerCtrlDlg::ProcessMappedResponse( void ) +{ + char *psz; + int *pBuffer; + int i; + char line[ 1024 ]; + char szwindow[ 4096 ]; + CEdit *pEdit; + + pBuffer = (int *)GetMappedBuffer ( m_hMappedFile ); + + // buffer is invalid. Just leave. + if ( !pBuffer ) + { + return 0; + } + + // Will be non-zero upon success + if ( pBuffer[0] ) + { + switch ( m_nPendingRequest ) + { + case ENGINE_RETRIEVE_CONSOLE_CONTENTS: + // Write text lines to console area + pEdit = (CEdit *)GetDlgItem( IDC_EDIT_CONSOLE ); + if ( pEdit ) + { + szwindow[ 0 ] = '\0'; + + for ( i = 0; i < m_nPendingLines; i++ ) + { + // Skip first int32 result code + // Lines are assumed to be 80 characters wide + psz = (char *)( pBuffer + 1 ) + 80 * i; + strncpy( line, psz, 80 ); + line[ 79 ] = '\0'; + + strcat( szwindow, line ); + if ( i != ( m_nPendingLines ) - 1 ) + { + strcat( szwindow, "\r\n" ); + } + } + + // Send to display control + pEdit->SetWindowText( szwindow ); + } + break; + + default: + break; + } + } + + // Reset results stuff + m_nPendingRequest = 0; + m_nPendingLines = 0; + + // Free up buffer pointer + ReleaseMappedBuffer( pBuffer ); + + return 1; +} + +/* +============== +GetMappedBuffer + +============== +*/ +LPVOID CServerCtrlDlg::GetMappedBuffer (HANDLE hfileBuffer) +{ + LPVOID pBuffer; + pBuffer = MapViewOfFile (hfileBuffer, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, 0); + return pBuffer; +} + +/* +============== +ReleaseMappedBuffer + +============== +*/ +void CServerCtrlDlg::ReleaseMappedBuffer (LPVOID pBuffer) +{ + UnmapViewOfFile (pBuffer); +} + +/* +============== +OnBtnStart + +============== +*/ +void CServerCtrlDlg::OnBtnStart( void ) +{ + STARTUPINFO SI; + + // Still active? Or did user kill it or did it crash + if ( PI.hProcess ) + { + DWORD dwEC; + if ( GetExitCodeProcess( PI.hProcess, &dwEC ) ) + { + if ( dwEC == STILL_ACTIVE ) + { + return; + } + else + { + memset( &PI, 0, sizeof( PI ) ); + CloseHandles(); + } + } + } + + // Really still active + if ( PI.hProcess || m_hMappedFile || m_hSend || m_hReceive ) + return; + + // Startup dedicated server + SECURITY_ATTRIBUTES SA; + memset( &SA, 0, sizeof( SA ) ); + SA.nLength = sizeof( SA ); + + // HLDS must be able to inherit the handles we pass via command line so we need to mark the handle as inheritable + SA.bInheritHandle = TRUE; + SA.lpSecurityDescriptor = NULL; + + // Create handles && hlds process + m_hMappedFile = CreateFileMapping( (HANDLE)0xFFFFFFFF, &SA, PAGE_READWRITE, 0, 16384, NULL ); + if ( !m_hMappedFile ) + { + AfxMessageBox( "Couldn't create mapped file", MB_OK ); + return; + } + + // Uses same security attributes to make handle inheritable + m_hSend = CreateEvent( &SA, FALSE, FALSE, NULL ); + m_hReceive = CreateEvent( &SA, FALSE, FALSE, NULL ); + + memset( &SI, 0, sizeof( SI ) ); + SI.cb = sizeof( SI ); + + memset( &PI, 0, sizeof( PI ) ); + + char sz[ 256 ]; + char szdir[ 256 ]; + + // FIXME: You'll want to fill in your executable path here, of course. + // The key thing is to invoke the engine using the three HANDLES that were just created + sprintf( szdir, "d:\\quiver" ); + sprintf( sz, "%s\\hlds.exe +sv_lan 1 -HFILE %i -HPARENT %i -HCHILD %i", szdir, (int)m_hMappedFile, (int)m_hSend, (int)m_hReceive ); + + // Run it + if ( !CreateProcess( NULL, sz, &SA, NULL, TRUE, 0, NULL, szdir, &SI, &PI ) ) + { + AfxMessageBox( "Couldn't create dedicated server process? Correct path", MB_OK ); + } +} + +/* +============== +~CServerCtrlDlg + +============== +*/ +CServerCtrlDlg::~CServerCtrlDlg( void ) +{ + // Quitting the front end can kill HLDS, if you want it to, since we created that process + if ( PI.hProcess ) + { + // Kill process + TerminateProcess( PI.hProcess, 0 ); + memset( &PI, 0, sizeof( PI ) ); + } + + // Close remaining handles. + CloseHandles(); +} + +/* +============== +OnBtnExecute + +User wants to issue commands +============== +*/ +void CServerCtrlDlg::OnBtnExecute( void ) +{ + if ( !m_hSend || !m_hMappedFile ) + return; + + // Get commands + CEdit *pEdit = (CEdit *)GetDlgItem( IDC_EDIT_COMMANDS ); + if ( pEdit ) + { + CString cmds; + pEdit->GetWindowText( cmds ); + + // Get buffer + char *sz = (char *)GetMappedBuffer( m_hMappedFile ); + if ( sz ) + { + // Write command int32 token + *(int *)&sz[ 0 ] = ENGINE_ISSUE_COMMANDS; + + // Write rest of line, including a return character ( necessary? ) + sprintf( sz + sizeof( int ), "%s\n", (char *)(LPCSTR)cmds ); + + // Release the buffer + ReleaseMappedBuffer( sz ); + + // Store off what we are expecting in return buffer + m_nPendingRequest = ENGINE_ISSUE_COMMANDS; + + // Signal HLDS to check for requests + SetEvent( m_hSend ); + } + } +} + +/* +============== +OnBtnGet + +============== +*/ +void CServerCtrlDlg::OnBtnGet( void ) +{ + RefreshText(); +} + +/* +============== +CloseHandles + +============== +*/ +void CServerCtrlDlg::CloseHandles( void ) +{ + if (m_hMappedFile ) + { + CloseHandle( m_hMappedFile ); + m_hMappedFile = ( HANDLE)0; + } + + if ( m_hSend ) + { + CloseHandle( m_hSend ); + m_hSend = (HANDLE)0; + } + + if ( m_hReceive ) + { + CloseHandle( m_hReceive ); + m_hReceive = (HANDLE)0; + } +} + +/* +============== +RefreshText + +============== +*/ +void CServerCtrlDlg::RefreshText( void ) +{ + if ( !m_hSend || !m_hMappedFile ) + return; + + int i = 0; + char *sz = (char *)GetMappedBuffer( m_hMappedFile ); + if ( sz ) + { + // Command token + *(int *)&sz[ i ] = ENGINE_RETRIEVE_CONSOLE_CONTENTS; + i += sizeof( int ); + + // Start at line 0 + *(int *)&sz[ i ] = 0; + i += sizeof( int ); + + // End at line 23 ( assumes 24 line console ) + *(int *)&sz[ i ] = 23; + i += sizeof( int ); + + // Done creating commands + ReleaseMappedBuffer( sz ); + + // Store off pending state info + m_nPendingRequest = ENGINE_RETRIEVE_CONSOLE_CONTENTS; + m_nPendingLines = 23 - 0 + 1; + + // Signal HLDS that we have written commands to the buffer + SetEvent( m_hSend ); + } +} + +/* +============== +RMLPreIdle + +Called every "frame" by the modal dialog loop +============== +*/ +int CServerCtrlDlg::RMLPreIdle(void) +{ + static DWORD lastupdate; + DWORD currenttime; + + // Haven't started up HLDS + if ( !m_hReceive || !m_hSend || !m_hMappedFile ) + return 0; + + // Refresh console text every 1/2 second + currenttime = timeGetTime(); + if ( ( currenttime - lastupdate ) > 500 ) + { + lastupdate = currenttime; + + RefreshText(); + } + + // Has event fired? Signaling that we have received a response from the engine? + if ( WaitForSingleObject( m_hReceive, 0 ) == WAIT_OBJECT_0 ) + { + // Process response + ProcessMappedResponse(); + } + + return 0; +} \ No newline at end of file diff --git a/utils/serverctrl/ServerCtrlDlg.h b/utils/serverctrl/ServerCtrlDlg.h new file mode 100644 index 0000000..d9558c7 --- /dev/null +++ b/utils/serverctrl/ServerCtrlDlg.h @@ -0,0 +1,79 @@ +// ServerCtrlDlg.h : header file +// + +#if !defined(AFX_ServerCtrlDLG_H__E2974CA8_EF9F_11D3_A4D9_00105A1727F3__INCLUDED_) +#define AFX_ServerCtrlDLG_H__E2974CA8_EF9F_11D3_A4D9_00105A1727F3__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +///////////////////////////////////////////////////////////////////////////// +// CServerCtrlDlg dialog + +class CServerCtrlDlg : public CDialog +{ +// Construction +public: + CServerCtrlDlg( CWnd* pParent = NULL ); // standard constructor + ~CServerCtrlDlg( void ); + + void CloseHandles( void ); + + virtual int RMLPreIdle(void); + + int RunModalLoop(DWORD dwFlags); + int DoModal( void ); + + void SetPumpIfQueued( BOOL bValue ); + + void RefreshText( void ); + + int ProcessMappedResponse( void ); + LPVOID GetMappedBuffer ( HANDLE hfileBuffer ); + void ReleaseMappedBuffer ( LPVOID pBuffer ); + +// Dialog Data + //{{AFX_DATA(CServerCtrlDlg) + enum { IDD = IDD_SERVERCTRL_DIALOG }; + // NOTE: the ClassWizard will add data members here + //}}AFX_DATA + + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(CServerCtrlDlg) + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support + //}}AFX_VIRTUAL + +// Implementation +protected: + HICON m_hIcon; + + // Generated message map functions + //{{AFX_MSG(CServerCtrlDlg) + virtual BOOL OnInitDialog(); + afx_msg void OnPaint(); + afx_msg HCURSOR OnQueryDragIcon(); + afx_msg void OnBtnStart(); + afx_msg void OnBtnExecute(); + afx_msg void OnBtnGet(); + //}}AFX_MSG + DECLARE_MESSAGE_MAP() + +private: + + PROCESS_INFORMATION PI; // Information about the HLDS process ( mostly the HANDLE ) + HANDLE m_hMappedFile; // Shared file for sending/receiving commands to HLDS + HANDLE m_hSend; // Event that will be signaled when we have written commands into mapped file + HANDLE m_hReceive; // Engine will set this when it has readied response to our commands + + int m_nPendingRequest; // The last request we issued + int m_nPendingLines; // Number of console lines we want to receive + + BOOL m_bOnlyPumpIfMessageInQueue; // TRUE if we should only go into PumpMessage ( which blocks ) if we have seen a message in the MSG queue using PeekMessage +}; + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ will insert additional declarations immediately before the previous line. + +#endif // !defined(AFX_ServerCtrlDLG_H__E2974CA8_EF9F_11D3_A4D9_00105A1727F3__INCLUDED_) diff --git a/utils/serverctrl/StdAfx.cpp b/utils/serverctrl/StdAfx.cpp new file mode 100644 index 0000000..c7d7a26 --- /dev/null +++ b/utils/serverctrl/StdAfx.cpp @@ -0,0 +1,8 @@ +// stdafx.cpp : source file that includes just the standard includes +// serverctrl.pch will be the pre-compiled header +// stdafx.obj will contain the pre-compiled type information + +#include "stdafx.h" + + + diff --git a/utils/serverctrl/StdAfx.h b/utils/serverctrl/StdAfx.h new file mode 100644 index 0000000..07a55ff --- /dev/null +++ b/utils/serverctrl/StdAfx.h @@ -0,0 +1,26 @@ +// stdafx.h : include file for standard system include files, +// or project specific include files that are used frequently, but +// are changed infrequently +// + +#if !defined(AFX_STDAFX_H__E2974CAA_EF9F_11D3_A4D9_00105A1727F3__INCLUDED_) +#define AFX_STDAFX_H__E2974CAA_EF9F_11D3_A4D9_00105A1727F3__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers + +#include // MFC core and standard components +#include // MFC extensions +#include // MFC support for Internet Explorer 4 Common Controls +#ifndef _AFX_NO_AFXCMN_SUPPORT +#include // MFC support for Windows Common Controls +#endif // _AFX_NO_AFXCMN_SUPPORT + + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ will insert additional declarations immediately before the previous line. + +#endif // !defined(AFX_STDAFX_H__E2974CAA_EF9F_11D3_A4D9_00105A1727F3__INCLUDED_) diff --git a/utils/serverctrl/res/serverctrl.ico b/utils/serverctrl/res/serverctrl.ico new file mode 100644 index 0000000000000000000000000000000000000000..7eef0bcbe6580a6f464d688906172c2d9de44262 GIT binary patch literal 1078 zcmc&zF>b>!3}jLb9s)T}@Kod(893@u8ajANzT`op9^o+)S?=nU(FD@%0s)Sg^oyC8{H z9myetc;MEP)59v(LMa~xK8Yu^jIR*H22uCFiq5%C{s7(PJi>o15i^bmX4(vPxWAio z9ryY#AU_jfnd047-@`)XzL?%iS$gQyFP{44kS9X)fN{{QoL~hO-&=q&20Zr*cxFAt PkaNE{wR~2C$NfnjhSXWT literal 0 HcmV?d00001 diff --git a/utils/serverctrl/res/serverctrl.rc2 b/utils/serverctrl/res/serverctrl.rc2 new file mode 100644 index 0000000..b69c4f1 --- /dev/null +++ b/utils/serverctrl/res/serverctrl.rc2 @@ -0,0 +1,13 @@ +// +// SERVERCTRL.RC2 - resources Microsoft Visual C++ does not edit directly +// + +#ifdef APSTUDIO_INVOKED + #error this file is not editable by Microsoft Visual C++ +#endif //APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// Add manually edited resources here... + +///////////////////////////////////////////////////////////////////////////// diff --git a/utils/serverctrl/resource.h b/utils/serverctrl/resource.h new file mode 100644 index 0000000..e5c644c --- /dev/null +++ b/utils/serverctrl/resource.h @@ -0,0 +1,22 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Developer Studio generated include file. +// Used by serverctrl.rc +// +#define IDD_SERVERCTRL_DIALOG 102 +#define IDR_MAINFRAME 128 +#define IDC_EDIT_COMMANDS 1000 +#define IDC_BTN_EXECUTE 1001 +#define IDC_BTN_START 1003 +#define IDC_BTN_GET 1004 +#define IDC_EDIT_CONSOLE 1005 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 129 +#define _APS_NEXT_COMMAND_VALUE 32771 +#define _APS_NEXT_CONTROL_VALUE 1006 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/utils/serverctrl/serverctrl.dsp b/utils/serverctrl/serverctrl.dsp new file mode 100644 index 0000000..76267fa --- /dev/null +++ b/utils/serverctrl/serverctrl.dsp @@ -0,0 +1,144 @@ +# Microsoft Developer Studio Project File - Name="serverctrl" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Application" 0x0101 + +CFG=serverctrl - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "serverctrl.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "serverctrl.mak" CFG="serverctrl - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "serverctrl - Win32 Release" (based on "Win32 (x86) Application") +!MESSAGE "serverctrl - Win32 Debug" (based on "Win32 (x86) Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "serverctrl - Win32 Release" + +# PROP BASE Use_MFC 5 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 5 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /Yu"stdafx.h" /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /Yu"stdafx.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" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 /nologo /subsystem:windows /machine:I386 +# ADD LINK32 winmm.lib /nologo /subsystem:windows /machine:I386 + +!ELSEIF "$(CFG)" == "serverctrl - Win32 Debug" + +# PROP BASE Use_MFC 5 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 5 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /Yu"stdafx.h" /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /Yu"stdafx.h" /FD /GZ /c +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept +# ADD LINK32 winmm.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "serverctrl - Win32 Release" +# Name "serverctrl - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\ServerCtrl.cpp +# End Source File +# Begin Source File + +SOURCE=.\ServerCtrl.rc +# End Source File +# Begin Source File + +SOURCE=.\ServerCtrlDlg.cpp +# End Source File +# Begin Source File + +SOURCE=.\StdAfx.cpp +# ADD CPP /Yc"stdafx.h" +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=.\Resource.h +# End Source File +# Begin Source File + +SOURCE=.\ServerCtrl.h +# End Source File +# Begin Source File + +SOURCE=.\ServerCtrlDlg.h +# End Source File +# Begin Source File + +SOURCE=.\StdAfx.h +# End Source File +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# Begin Source File + +SOURCE=.\res\serverctrl.ico +# End Source File +# Begin Source File + +SOURCE=.\res\serverctrl.rc2 +# End Source File +# End Group +# End Target +# End Project diff --git a/utils/smdlexp/mssccprj.scc b/utils/smdlexp/mssccprj.scc index e121d3e..e2547f5 100644 --- a/utils/smdlexp/mssccprj.scc +++ b/utils/smdlexp/mssccprj.scc @@ -1,4 +1,5 @@ SCC = This is a Source Code Control file [smdlexp.mak] -SCC_Project_Name = "$/HLStandardSDK/SourceCode/utils/smdlexp", TEXHAAAA +SCC_Aux_Path = "\\Jeeves\VSSCODE\" +SCC_Project_Name = "$/Sdk/Standard/utils/smdlexp", YIZBAAAA diff --git a/utils/sprgen/mssccprj.scc b/utils/sprgen/mssccprj.scc index a17d994..de63216 100644 --- a/utils/sprgen/mssccprj.scc +++ b/utils/sprgen/mssccprj.scc @@ -1,4 +1,5 @@ SCC = This is a Source Code Control file [sprgen.mak] -SCC_Project_Name = "$/HLStandardSDK/SourceCode/utils/sprgen", CFXHAAAA +SCC_Aux_Path = "\\Jeeves\VSSCODE\" +SCC_Project_Name = "$/Sdk/Standard/utils/sprgen", HJZBAAAA diff --git a/utils/studiomdl/mssccprj.scc b/utils/studiomdl/mssccprj.scc index e7facb3..9fbe338 100644 --- a/utils/studiomdl/mssccprj.scc +++ b/utils/studiomdl/mssccprj.scc @@ -1,4 +1,5 @@ SCC = This is a Source Code Control file [studiomdl.mak] -SCC_Project_Name = "$/HLStandardSDK/SourceCode/utils/studiomdl", IFXHAAAA +SCC_Aux_Path = "\\Jeeves\VSSCODE\" +SCC_Project_Name = "$/Sdk/Standard/utils/studiomdl", NJZBAAAA diff --git a/utils/vgui/include/VGUI.h b/utils/vgui/include/VGUI.h new file mode 100644 index 0000000..9549c30 --- /dev/null +++ b/utils/vgui/include/VGUI.h @@ -0,0 +1,101 @@ + +#ifndef VGUI_H +#define VGUI_H + +//If you are going to add stuff to the vgui core... +// +//Keep it simple. +// +//Never put code in a header. +// +//The name of the class is the name of the the file +// +//Each class gets its own .cpp file for its definition and a .h for its header. Helper +//classes can be used but only within the .cpp and not referenceable from anywhere else. +// +//Don't add unneeded files. Keep the API clean. +// +//No platform specific code in vgui\lib-src\vgui dir. Code in vgui\lib-src\vgui should +//only include from vgui\include or standard C includes. ie, if I see windows.h included +//anywhere but vgui\lib-src\win32 I will hunt you down and kill you. Don't give me any crap +//that mfc is platform inspecific. +// +//Always use <> and not "" for includes +// +//Use minimum dependencies in headers. Don't include another header if you can get away +//with forward declaring (which is usually the case) +// +//No macros in headers. They are tools of satan. This also means no use of DEFINEs, use enum +// +//Minimize global functions +// +//No global variables. +// +//Panel is getting pretty plump, try and avoid adding junk to it if you can + +//TODO: Look and Feel support +// add Panel::setPaintProxy, if _paintProxy exists, it calls _paintProxy->paint +// instead of Panel::paint. Components should implement their painting in a seperate +// plugin class. Perhaps to encourage this, Panel::paint should just go away completely +// The other option is to have Panel have the interface Paintable +// class Paintable +// { +// public: +// virtual void paint()=0; +// }; +// Then a component can implement its paint in the class itself and then call +// setPaintProxy(this). If this is the case _paintProxy->paint should always be called +// and never Panel::paint from within paintTraverse +//TODO: Figure out the 'Valve' Look and Feel and implement that instead of a the Java one +//TODO: Determine ownership policy for Borders, Layouts, etc.. +//TODO: tooltips support +//TODO: ComboKey (hot key support) +//TODO: add Background.cpp, remove paintBackground from all components +// Panel implements setBackground, Panel::paintBackground calls _background->paintBackground +// similiar to the way Border works. +//TODO: Builtin components should never overide paintBackground, only paint +//TODO: All protected members should be converted to private +//TODO: All member variables should be moved to the top of the class prototype +//TODO: All private methods should be prepended with private +//TODO: Use of word internal in method names is not consistent and confusing +//TODO: Cleanup so bullshit publics are properly named, maybe even figure out +// a naming convention for them +//TODO: Breakup InputSignal into logical pieces +//TODO: Button is in a state of disarray, it should have ButtonModel support +//TODO: get rid of all the stupid strdup laziness, convert to vgui_strdup +//TODO: actually figure out policy on String and implement it consistently +//TODO: implement createLayoutInfo for other Layouts than need it +//TODO: BorderLayout should have option for a null LayoutInfo defaulting to center +//TODO: SurfaceBase should go away, put it in Surface +//TODO: ActionSignals and other Signals should just set a flag when they fire. +// then App can come along later and fire all the signals +//TODO: Change all method naming to starting with a capital letter. + +#ifdef _WIN32 +# define VGUIAPI __declspec( dllexport ) +#else +# define VGUIAPI +#endif + +#define null 0L + +typedef unsigned char uchar; +typedef unsigned short ushort; +typedef unsigned int uint; +typedef unsigned long ulong; + +namespace vgui +{ + +VGUIAPI void vgui_setMalloc(void* (*malloc)(size_t size)); +VGUIAPI void vgui_setFree(void (*free)(void* memblock)); +VGUIAPI void vgui_strcpy(char* dst,int dstLen,const char* src); +VGUIAPI char* vgui_strdup(const char* src); +VGUIAPI int vgui_printf(const char* format,...); +VGUIAPI int vgui_dprintf(const char* format,...); +VGUIAPI int vgui_dprintf2(const char* format,...); + +} + +#endif + diff --git a/utils/vgui/include/VGUI_ActionSignal.h b/utils/vgui/include/VGUI_ActionSignal.h new file mode 100644 index 0000000..8c7798e --- /dev/null +++ b/utils/vgui/include/VGUI_ActionSignal.h @@ -0,0 +1,78 @@ + +#ifndef VGUI_ACTIONSIGNAL_H +#define VGUI_ACTIONSIGNAL_H + +#include + +/* + +TODO: maybe try something like this.. + +class VGUIAPI ActionSignal +{ +}; + +class VGUIAPI ActionSignalSimple : public ActionSignal +{ +public: + virtual void actionPerformed(Panel* panel)=0; +}; + +class VGUIAPI ActionSignalInt : public ActionSignal +{ +public: + virtual void actionPerformed(int value,Panel* panel)=0; +}; + + +DefaultButtonModel would implement: + +virtual void addActionSignal(ActionSignal* s) +{ + if(s!=null) + { + _actionSignalDar.putElement(s); + } +} + +virtual void fireActionSignal() +{ + for(int i=0;i<_actionSignalDar.getCount();i++) + { + ActionSignal* signal=_actionSignalDar[i]; + + ActionSignalSimple* ss=dynamic_cast(signal); + if(ss!=null) + { + ss->actionPerformed(this); + } + + ActionSignalCommand* si=dynamic_cast(signal); + if(si!=null) + { + si->actionPerformed(_intValue,this); + } + } +} + + +*/ + +#include + +namespace vgui +{ + +class Panel; + +class VGUIAPI ActionSignal +{ +public: + virtual void actionPerformed(Panel* panel)=0; +}; + +} + +#endif + + diff --git a/utils/vgui/include/VGUI_App.h b/utils/vgui/include/VGUI_App.h new file mode 100644 index 0000000..b44f155 --- /dev/null +++ b/utils/vgui/include/VGUI_App.h @@ -0,0 +1,126 @@ + +#ifndef VGUI_APP_H +#define VGUI_APP_H + +#include +#include +#include +#include +#include + +namespace vgui +{ + +enum MouseCode; +enum KeyCode; +class Panel; +class TickSignal; +class Scheme; +class TickSignal; +class SurfaceBase; + +class VGUIAPI App +{ +public: + App(); + App(bool externalMain); +public: + static App* getInstance(); + //TODO: the public and public bullshit are all messed up, need to organize + //TODO: actually all of the access needs to be properly thought out while you are at it +public: + virtual void start(); + virtual void stop(); + virtual void externalTick(); + virtual bool wasMousePressed(MouseCode code,Panel* panel); + virtual bool wasMouseDoublePressed(MouseCode code,Panel* panel); + virtual bool isMouseDown(MouseCode code,Panel* panel); + virtual bool wasMouseReleased(MouseCode code,Panel* panel); + virtual bool wasKeyPressed(KeyCode code,Panel* panel); + virtual bool isKeyDown(KeyCode code,Panel* panel); + virtual bool wasKeyTyped(KeyCode code,Panel* panel); + virtual bool wasKeyReleased(KeyCode code,Panel* panel); + virtual void addTickSignal(TickSignal* s); + virtual void setCursorPos(int x,int y); + virtual void getCursorPos(int& x,int& y); + virtual void setMouseCapture(Panel* panel); + virtual void setMouseArena(int x0,int y0,int x1,int y1,bool enabled); + virtual void setMouseArena(Panel* panel); + virtual void requestFocus(Panel* panel); + virtual Panel* getFocus(); + virtual void repaintAll(); + virtual void setScheme(Scheme* scheme); + virtual Scheme* getScheme(); + virtual void enableBuildMode(); + virtual long getTimeMillis(); + virtual char getKeyCodeChar(KeyCode code,bool shifted); + virtual void getKeyCodeText(KeyCode code,char* buf,int buflen); + virtual int getClipboardTextCount(); + virtual void setClipboardText(const char* text,int textLen); + virtual int getClipboardText(int offset,char* buf,int bufLen); + virtual void reset(); + virtual void internalSetMouseArena(int x0,int y0,int x1,int y1,bool enabled); + virtual bool setRegistryString(const char* key,const char* value); + virtual bool getRegistryString(const char* key,char* value,int valueLen); + virtual bool setRegistryInteger(const char* key,int value); + virtual bool getRegistryInteger(const char* key,int& value); + virtual void setCursorOveride(Cursor* cursor); + virtual Cursor* getCursorOveride(); + virtual void setMinimumTickMillisInterval(int interval); +public: //bullshit public stuff + virtual void main(int argc,char* argv[])=0; + virtual void run(); + virtual void internalCursorMoved(int x,int y,SurfaceBase* surfaceBase); //expects input in surface space + virtual void internalMousePressed(MouseCode code,SurfaceBase* surfaceBase); + virtual void internalMouseDoublePressed(MouseCode code,SurfaceBase* surfaceBase); + virtual void internalMouseReleased(MouseCode code,SurfaceBase* surfaceBase); + virtual void internalMouseWheeled(int delta,SurfaceBase* surfaceBase); + virtual void internalKeyPressed(KeyCode code,SurfaceBase* surfaceBase); + virtual void internalKeyTyped(KeyCode code,SurfaceBase* surfaceBase); + virtual void internalKeyReleased(KeyCode code,SurfaceBase* surfaceBase); +private: + virtual void init(); + virtual void updateMouseFocus(int x,int y,SurfaceBase* surfaceBase); + virtual void setMouseFocus(Panel* newMouseFocus); +protected: + virtual void surfaceBaseCreated(SurfaceBase* surfaceBase); + virtual void surfaceBaseDeleted(SurfaceBase* surfaceBase); + virtual void platTick(); + virtual void internalTick(); +protected: + static App* _instance; +protected: + bool _running; + bool _externalMain; + Dar _surfaceBaseDar; + Panel* _keyFocus; + Panel* _oldMouseFocus; + Panel* _mouseFocus; + Panel* _mouseCapture; + Panel* _wantedKeyFocus; + bool _mousePressed[MOUSE_LAST]; + bool _mouseDoublePressed[MOUSE_LAST]; + bool _mouseDown[MOUSE_LAST]; + bool _mouseReleased[MOUSE_LAST]; + bool _keyPressed[KEY_LAST]; + bool _keyTyped[KEY_LAST]; + bool _keyDown[KEY_LAST]; + bool _keyReleased[KEY_LAST]; + Dar _tickSignalDar; + Scheme* _scheme; + bool _buildMode; + bool _wantedBuildMode; + Panel* _mouseArenaPanel; + Cursor* _cursor[Cursor::DefaultCursor::dc_last]; + Cursor* _cursorOveride; +private: + long _nextTickMillis; + long _minimumTickMillisInterval; + friend class SurfaceBase; +}; +} + +#endif + + + diff --git a/utils/vgui/include/VGUI_Bitmap.h b/utils/vgui/include/VGUI_Bitmap.h new file mode 100644 index 0000000..f82b10c --- /dev/null +++ b/utils/vgui/include/VGUI_Bitmap.h @@ -0,0 +1,31 @@ + +#ifndef VGUI_BITMAP_H +#define VGUI_BITMAP_H + +#include +#include + +namespace vgui +{ + +class Panel; + +class VGUIAPI Bitmap : public Image +{ +private: + int _id; + bool _uploaded; +public: + Bitmap(); +protected: + virtual void setSize(int wide,int tall); + virtual void setRGBA(int x,int y,uchar r,uchar g,uchar b,uchar a); +public: + virtual void paint(Panel* panel); +protected: + uchar* _rgba; +}; + +} + +#endif \ No newline at end of file diff --git a/utils/vgui/include/VGUI_BitmapTGA.h b/utils/vgui/include/VGUI_BitmapTGA.h new file mode 100644 index 0000000..c8e3ab3 --- /dev/null +++ b/utils/vgui/include/VGUI_BitmapTGA.h @@ -0,0 +1,23 @@ + +#ifndef VGUI_BITMAPTGA_H +#define VGUI_BITMAPTGA_H + +#include + +namespace vgui +{ + +class Panel; +class InputStream; + +class VGUIAPI BitmapTGA : public Bitmap +{ +public: + BitmapTGA(InputStream* is,bool invertAlpha); +private: + virtual bool loadTGA(InputStream* is,bool invertAlpha); +}; + +} + +#endif \ No newline at end of file diff --git a/utils/vgui/include/VGUI_Border.h b/utils/vgui/include/VGUI_Border.h new file mode 100644 index 0000000..3210123 --- /dev/null +++ b/utils/vgui/include/VGUI_Border.h @@ -0,0 +1,39 @@ + +#ifndef VGUI_BORDER_H +#define VGUI_BORDER_H + +#include +#include + +//TODO: all borders should be titled + +namespace vgui +{ + +class Panel; + +class VGUIAPI Border : public Image +{ +public: + Border(); + Border(int left,int top,int right,int bottom); +public: + virtual void setInset(int left,int top,int right,int bottom); + virtual void getInset(int& left,int& top,int& right,int& bottom); +protected: + virtual void drawFilledRect(int x0,int y0,int x1,int y1); + virtual void drawOutlinedRect(int x0,int y0,int x1,int y1); + virtual void drawSetTextPos(int x,int y); + virtual void drawPrintText(int x,int y,const char* str,int strlen); + virtual void drawPrintChar(int x,int y,char ch); +protected: + int _inset[4]; +private: + Panel* _panel; +friend class Panel; +friend class BorderPair; +}; + +} + +#endif \ No newline at end of file diff --git a/utils/vgui/include/VGUI_BorderLayout.h b/utils/vgui/include/VGUI_BorderLayout.h new file mode 100644 index 0000000..194e7de --- /dev/null +++ b/utils/vgui/include/VGUI_BorderLayout.h @@ -0,0 +1,40 @@ + +#ifndef VGUI_BORDERLAYOUT_H +#define VGUI_BORDERLAYOUT_H + +#include +#include + +namespace vgui +{ + +class LayoutInfo; + +class VGUIAPI BorderLayout : public Layout +{ +public: + enum Alignment + { + a_center=0, + a_north, + a_south, + a_east, + a_west, + }; +private: + int _inset; +public: + BorderLayout(int inset); +public: + virtual void performLayout(Panel* panel); + virtual LayoutInfo* createLayoutInfo(Alignment alignment); +}; + +} + +#endif + + + + + diff --git a/utils/vgui/include/VGUI_BorderPair.h b/utils/vgui/include/VGUI_BorderPair.h new file mode 100644 index 0000000..c28be9a --- /dev/null +++ b/utils/vgui/include/VGUI_BorderPair.h @@ -0,0 +1,27 @@ + +#ifndef VGUI_BORDERPAIR_H +#define VGUI_BORDERPAIR_H + +#include +#include + +namespace vgui +{ + +class Panel; + +class VGUIAPI BorderPair : public Border +{ +public: + BorderPair(Border* border0,Border* border1); +public: + virtual void doPaint(Panel* panel); +protected: + virtual void paint(Panel* panel); +protected: + Border* _border[2]; +}; + +} + +#endif \ No newline at end of file diff --git a/utils/vgui/include/VGUI_BuildGroup.h b/utils/vgui/include/VGUI_BuildGroup.h new file mode 100644 index 0000000..27c7afa --- /dev/null +++ b/utils/vgui/include/VGUI_BuildGroup.h @@ -0,0 +1,61 @@ + +#ifndef VGUI_BUILDGROUP_H +#define VGUI_BUILDGROUP_H + +#include +#include + + +namespace vgui +{ + +enum KeyCode; +enum MouseCode; +class Panel; +class Cursor; +class ChangeSignal; + +class VGUIAPI BuildGroup +{ +private: + bool _enabled; + int _snapX; + int _snapY; + Cursor* _cursor_sizenwse; + Cursor* _cursor_sizenesw; + Cursor* _cursor_sizewe; + Cursor* _cursor_sizens; + Cursor* _cursor_sizeall; + bool _dragging; + MouseCode _dragMouseCode; + int _dragStartPanelPos[2]; + int _dragStartCursorPos[2]; + Panel* _currentPanel; + Dar _currentPanelChangeSignalDar; + Dar _panelDar; + Dar _panelNameDar; +public: + BuildGroup(); +public: + virtual void setEnabled(bool state); + virtual bool isEnabled(); + virtual void addCurrentPanelChangeSignal(ChangeSignal* s); + virtual Panel* getCurrentPanel(); + virtual void copyPropertiesToClipboard(); +private: + virtual void applySnap(Panel* panel); + virtual void fireCurrentPanelChangeSignal(); +protected: + friend class Panel; + virtual void panelAdded(Panel* panel,const char* panelName); + virtual void cursorMoved(int x,int y,Panel* panel); + virtual void mousePressed(MouseCode code,Panel* panel); + virtual void mouseReleased(MouseCode code,Panel* panel); + virtual void mouseDoublePressed(MouseCode code,Panel* panel); + virtual void keyTyped(KeyCode code,Panel* panel); + virtual Cursor* getCursor(Panel* panel); +}; + +} + +#endif \ No newline at end of file diff --git a/utils/vgui/include/VGUI_Button.h b/utils/vgui/include/VGUI_Button.h new file mode 100644 index 0000000..614d463 --- /dev/null +++ b/utils/vgui/include/VGUI_Button.h @@ -0,0 +1,55 @@ + +#ifndef VGUI_BUTTON_H +#define VGUI_BUTTON_H + +#include +#include +#include + +namespace vgui +{ + +enum MouseCode; +class ButtonController; +class ButtonGroup; +class ActionSignal; + +//TODO: Button should be derived from an AbstractButton +class VGUIAPI Button : public Label +{ +public: + Button(const char* text,int x,int y,int wide,int tall); + Button(const char* text,int x,int y); +private: + void init(); +public: + virtual void setSelected(bool state); + virtual void setSelectedDirect(bool state); + virtual void setArmed(bool state); + virtual bool isSelected(); + virtual void doClick(); + virtual void addActionSignal(ActionSignal* s); + virtual void setButtonGroup(ButtonGroup* buttonGroup); + virtual bool isArmed(); + virtual void setButtonBorderEnabled(bool state); + virtual void setMouseClickEnabled(MouseCode code,bool state); + virtual bool isMouseClickEnabled(MouseCode code); + virtual void fireActionSignal(); + virtual Panel* createPropertyPanel(); +protected: + virtual void setButtonController(ButtonController* _buttonController); + virtual void paintBackground(); +protected: + char* _text; + bool _armed; + bool _selected; + bool _buttonBorderEnabled; + Dar _actionSignalDar; + int _mouseClickMask; + ButtonGroup* _buttonGroup; + ButtonController* _buttonController; +}; + +} + +#endif \ No newline at end of file diff --git a/utils/vgui/include/VGUI_ButtonController.h b/utils/vgui/include/VGUI_ButtonController.h new file mode 100644 index 0000000..3020c14 --- /dev/null +++ b/utils/vgui/include/VGUI_ButtonController.h @@ -0,0 +1,21 @@ + +#ifndef VGUI_BUTTONCONTROLLER_H +#define VGUI_BUTTONCONTROLLER_H + +#include + +namespace vgui +{ + +class Button; + +class VGUIAPI ButtonController +{ +public: + virtual void addSignals(Button* button)=0; + virtual void removeSignals(Button* button)=0; +}; + +} + +#endif diff --git a/utils/vgui/include/VGUI_ButtonGroup.h b/utils/vgui/include/VGUI_ButtonGroup.h new file mode 100644 index 0000000..82cecaf --- /dev/null +++ b/utils/vgui/include/VGUI_ButtonGroup.h @@ -0,0 +1,24 @@ + +#ifndef VGUI_BUTTONGROUP_H +#define VGUI_BUTTONGROUP_H + +#include +#include + +namespace vgui +{ + +class Button; + +class VGUIAPI ButtonGroup +{ +public: + virtual void addButton(Button* button); + virtual void setSelected(Button* button); +protected: + Dar _buttonDar; +}; + +} + +#endif \ No newline at end of file diff --git a/utils/vgui/include/VGUI_ChangeSignal.h b/utils/vgui/include/VGUI_ChangeSignal.h new file mode 100644 index 0000000..9b183a9 --- /dev/null +++ b/utils/vgui/include/VGUI_ChangeSignal.h @@ -0,0 +1,20 @@ + +#ifndef VGUI_CHANGESIGNAL_H +#define VGUI_CHANGESIGNAL_H + +#include + +namespace vgui +{ + +class Panel; + +class VGUIAPI ChangeSignal +{ +public: + virtual void valueChanged(Panel* panel)=0; +}; + +} + +#endif \ No newline at end of file diff --git a/utils/vgui/include/VGUI_CheckButton.h b/utils/vgui/include/VGUI_CheckButton.h new file mode 100644 index 0000000..e2551e3 --- /dev/null +++ b/utils/vgui/include/VGUI_CheckButton.h @@ -0,0 +1,22 @@ + +#ifndef VGUI_CHECKBUTTON_H +#define VGUI_CHECKBUTTON_H + +#include +#include + +namespace vgui +{ + +class VGUIAPI CheckButton : public ToggleButton +{ +public: + CheckButton(const char* text,int x,int y,int wide,int tall); + CheckButton(const char* text,int x,int y); +protected: + virtual void paintBackground(); +}; + +} + +#endif \ No newline at end of file diff --git a/utils/vgui/include/VGUI_Color.h b/utils/vgui/include/VGUI_Color.h new file mode 100644 index 0000000..a291caf --- /dev/null +++ b/utils/vgui/include/VGUI_Color.h @@ -0,0 +1,38 @@ + +#ifndef VGUI_COLOR_H +#define VGUI_COLOR_H + +#include +#include + +//TODO: rename getColor(r,g,b,a) to getRGBA(r,g,b,a) +//TODO: rename setColor(r,g,b,a) to setRGBA(r,g,b,a) +//TODO: rename getColor(sc) to getSchemeColor(sc) +//TODO: rename setColor(sc) to setSchemeColor(sc) + +namespace vgui +{ + +class VGUIAPI Color +{ +private: + uchar _color[4]; + Scheme::SchemeColor _schemeColor; +public: + Color(); + Color(int r,int g,int b,int a); + Color(Scheme::SchemeColor sc); +private: + virtual void init(); +public: + virtual void setColor(int r,int g,int b,int a); + virtual void setColor(Scheme::SchemeColor sc); + virtual void getColor(int& r,int& g,int& b,int& a); + virtual void getColor(Scheme::SchemeColor& sc); + virtual int operator[](int index); +}; + +} + + +#endif diff --git a/utils/vgui/include/VGUI_ComboKey.h b/utils/vgui/include/VGUI_ComboKey.h new file mode 100644 index 0000000..5f03446 --- /dev/null +++ b/utils/vgui/include/VGUI_ComboKey.h @@ -0,0 +1,28 @@ + +#ifndef VGUI_COMBOKEY_H +#define VGUI_COMBOKEY_H + +#include + +namespace vgui +{ + +enum KeyCode; + +class ComboKey +{ +public: + ComboKey(KeyCode code,KeyCode modifier); +public: + bool isTwoCombo(KeyCode code,KeyCode modifier); +protected: + bool check(KeyCode code); +protected: + KeyCode _keyCode[2]; +friend class Panel; +}; + +} + + +#endif \ No newline at end of file diff --git a/utils/vgui/include/VGUI_ConfigWizard.h b/utils/vgui/include/VGUI_ConfigWizard.h new file mode 100644 index 0000000..0d1bfda --- /dev/null +++ b/utils/vgui/include/VGUI_ConfigWizard.h @@ -0,0 +1,34 @@ + +#ifndef VGUI_CONFIGWIZARD_H +#define VGUI_CONFIGWIZARD_H + +#include +#include + +namespace vgui +{ + +class TreeFolder; +class Panel; +class Button; + +class VGUIAPI ConfigWizard : public Panel +{ +public: + ConfigWizard(int x,int y,int wide,int tall); +public: + virtual void setSize(int wide,int tall); + virtual Panel* getClient(); + virtual TreeFolder* getFolder(); +protected: + TreeFolder* _treeFolder; + Panel* _client; + Button* _okButton; + Button* _cancelButton; + Button* _applyButton; + Button* _helpButton; +}; + +} + +#endif \ No newline at end of file diff --git a/utils/vgui/include/VGUI_Cursor.h b/utils/vgui/include/VGUI_Cursor.h new file mode 100644 index 0000000..c51f1e8 --- /dev/null +++ b/utils/vgui/include/VGUI_Cursor.h @@ -0,0 +1,51 @@ + +#ifndef VGUI_CURSOR_H +#define VGUI_CURSOR_H + +#include + +namespace vgui +{ + +class Bitmap; + +class VGUIAPI Cursor +{ +public: + enum DefaultCursor + { + dc_user, + dc_none, + dc_arrow, + dc_ibeam, + dc_hourglass, + dc_crosshair, + dc_up, + dc_sizenwse, + dc_sizenesw, + dc_sizewe, + dc_sizens, + dc_sizeall, + dc_no, + dc_hand, + dc_last, + }; +private: + int _hotspot[2]; + Bitmap* _bitmap; + DefaultCursor _dc; +public: + Cursor(DefaultCursor dc); + Cursor(Bitmap* bitmap,int hotspotX,int hotspotY); +public: + virtual void getHotspot(int& x,int& y); +private: + virtual void privateInit(Bitmap* bitmap,int hotspotX,int hotspotY); +public: + virtual Bitmap* getBitmap(); + virtual DefaultCursor getDefaultCursor(); +}; + +} + +#endif \ No newline at end of file diff --git a/utils/vgui/include/VGUI_Dar.h b/utils/vgui/include/VGUI_Dar.h new file mode 100644 index 0000000..48c0b55 --- /dev/null +++ b/utils/vgui/include/VGUI_Dar.h @@ -0,0 +1,187 @@ + +#ifndef VGUI_DAR_H +#define VGUI_DAR_H + +#include +#include +#include + + + +namespace vgui +{ + +//Simple lightweight dynamic array implementation +template class VGUIAPI Dar +{ +public: + Dar() + { + _count=0; + _capacity=0; + _data=null; + ensureCapacity(4); + } + Dar(int initialCapacity) + { + _count=0; + _capacity=0; + _data=null; + ensureCapacity(initialCapacity); + } +public: + void ensureCapacity(int wantedCapacity) + { + if(wantedCapacity<=_capacity){return;} + + //double capacity until it is >= wantedCapacity + //this could be done with math, but iterative is just so much more fun + int newCapacity=_capacity; + if(newCapacity==0){newCapacity=1;} + while(newCapacity_capacity)) + { + return; + } + _count=count; + } + int getCount() + { + return _count; + } + void addElement(ELEMTYPE elem) + { + ensureCapacity(_count+1); + _data[_count]=elem; + _count++; + } + bool hasElement(ELEMTYPE elem) + { + for(int i=0;i<_count;i++) + { + if(_data[i]==elem) + { + return true; + } + } + return false; + } + void putElement(ELEMTYPE elem) + { + if(hasElement(elem)) + { + return; + } + addElement(elem); + } + void insertElementAt(ELEMTYPE elem,int index) + { + if((index<0)||(index>_count)) + { + return; + } + if((index==_count)||(_count==0)) + { + addElement(elem); + } + else + { + addElement(elem); //just to make sure it is big enough + for(int i=_count-1;i>index;i--) + { + _data[i]=_data[i-1]; + } + _data[index]=elem; + } + } + void setElementAt(ELEMTYPE elem,int index) + { + if((index<0)||(index>=_count)) + { + return; + } + _data[index]=elem; + } + void removeElementAt(int index) + { + if((index<0)||(index>=_count)) + { + return; + } + + //slide everything to the right of index, left one. + for(int i=index;i<(_count-1);i++) + { + _data[i]=_data[i+1]; + } + _count--; + } + void removeElement(ELEMTYPE elem) + { + for(int i=0;i<_count;i++) + { + if(_data[i]==elem) + { + removeElementAt(i); + break; + } + } + } + void removeAll() + { + _count=0; + } + ELEMTYPE operator[](int index) + { + if((index<0)||(index>=_count)) + { + return null; + } + return _data[index]; + } +protected: + int _count; + int _capacity; + ELEMTYPE* _data; +}; + +//forward referencing all the template types used so they get exported +template class VGUIAPI Dar; +template class VGUIAPI Dar; +template class VGUIAPI Dar; +template class VGUIAPI Dar; +template class VGUIAPI Dar; +template class VGUIAPI Dar; +template class VGUIAPI Dar; +template class VGUIAPI Dar; +template class VGUIAPI Dar; +template class VGUIAPI Dar; +template class VGUIAPI Dar; +template class VGUIAPI Dar*>; +template class VGUIAPI Dar; +template class VGUIAPI Dar; +template class VGUIAPI Dar; +template class VGUIAPI Dar; +template class VGUIAPI Dar; +template class VGUIAPI Dar; + + +} + + +#endif \ No newline at end of file diff --git a/utils/vgui/include/VGUI_DataInputStream.h b/utils/vgui/include/VGUI_DataInputStream.h new file mode 100644 index 0000000..4e621a3 --- /dev/null +++ b/utils/vgui/include/VGUI_DataInputStream.h @@ -0,0 +1,43 @@ + +#ifndef VGUI_DATAINPUTSTREAM_H +#define VGUI_DATAINPUTSTREAM_H + +#include +#include + +namespace vgui +{ + +class VGUIAPI DataInputStream : virtual public InputStream +{ +private: + InputStream* _is; +public: + DataInputStream(InputStream* is); +public: + virtual void seekStart(bool& success); + virtual void seekRelative(int count,bool& success); + virtual void seekEnd(bool& success); + virtual int getAvailable(bool& success); + //virtual uchar readUChar(bool& success); + virtual void readUChar(uchar* buf,int count,bool& success); + virtual void close(bool& success); + virtual void close(); +public: + virtual bool readBool(bool& success); + virtual char readChar(bool& success); + virtual uchar readUChar(bool& success); + virtual short readShort(bool& success); + virtual ushort readUShort(bool& success); + virtual int readInt(bool& success); + virtual uint readUInt(bool& success); + virtual long readLong(bool& success); + virtual ulong readULong(bool& success); + virtual float readFloat(bool& success); + virtual double readDouble(bool& success); + virtual void readLine(char* buf,int bufLen,bool& success); +}; + +} + +#endif \ No newline at end of file diff --git a/utils/vgui/include/VGUI_Desktop.h b/utils/vgui/include/VGUI_Desktop.h new file mode 100644 index 0000000..e64baa2 --- /dev/null +++ b/utils/vgui/include/VGUI_Desktop.h @@ -0,0 +1,36 @@ + +#ifndef VGUI_DESKTOP_H +#define VGUI_DESKTOP_H + +#include +#include +#include + +namespace vgui +{ + +class DesktopIcon; +class TaskBar; + +class VGUIAPI Desktop : public Panel +{ +public: + Desktop(int x,int y,int wide,int tall); +public: + virtual void setSize(int wide,int tall); + virtual void iconActivated(DesktopIcon* icon); + virtual void addIcon(DesktopIcon* icon); + virtual void arrangeIcons(); + virtual Panel* getBackground(); + virtual Panel* getForeground(); +protected: + Panel* _background; + Panel* _foreground; + TaskBar* _taskBar; + Dar _desktopIconDar; + int _cascade[2]; +}; + +} + +#endif \ No newline at end of file diff --git a/utils/vgui/include/VGUI_DesktopIcon.h b/utils/vgui/include/VGUI_DesktopIcon.h new file mode 100644 index 0000000..05ced10 --- /dev/null +++ b/utils/vgui/include/VGUI_DesktopIcon.h @@ -0,0 +1,35 @@ + +#ifndef VGUI_DESKTOPICON_H +#define VGUI_DESKTOPICON_H + +#include +#include + +namespace vgui +{ + +class MiniApp; +class Image; +class Desktop; + +class VGUIAPI DesktopIcon : public Panel +{ +public: + DesktopIcon(MiniApp* miniApp,Image* image); +public: + virtual void doActivate(); + virtual void setImage(Image* image); +public: //bullshit public + virtual void setDesktop(Desktop* desktop); + virtual MiniApp* getMiniApp(); +protected: + virtual void paintBackground(); +protected: + Desktop* _desktop; + MiniApp* _miniApp; + Image* _image; +}; + +} + +#endif \ No newline at end of file diff --git a/utils/vgui/include/VGUI_EditPanel.h b/utils/vgui/include/VGUI_EditPanel.h new file mode 100644 index 0000000..f6e4542 --- /dev/null +++ b/utils/vgui/include/VGUI_EditPanel.h @@ -0,0 +1,59 @@ + +#ifndef VGUI_EDITPANEL_H +#define VGUI_EDITPANEL_H + +#include +#include +#include + +namespace vgui +{ + +class Font; + +class VGUIAPI EditPanel : public Panel +{ +public: + EditPanel(int x,int y,int wide,int tall); +public: + virtual void doCursorUp(); + virtual void doCursorDown(); + virtual void doCursorLeft(); + virtual void doCursorRight(); + virtual void doCursorToStartOfLine(); + virtual void doCursorToEndOfLine(); + virtual void doCursorInsertChar(char ch); + virtual void doCursorBackspace(); + virtual void doCursorNewLine(); + virtual void doCursorDelete(); + virtual void doCursorPrintf(char* format,...); + virtual int getLineCount(); + virtual int getVisibleLineCount(); + virtual void setCursorBlink(bool state); + virtual void setFont(Font* font); + virtual void getText(int lineIndex, int offset,char* buf,int bufLen); + +public: //bullshit public + void getCursorBlink(bool& blink,int& nextBlinkTime); +protected: + virtual void paintBackground(); + virtual void paint(); + virtual void addLine(); + virtual Dar* getLine(int lineIndex); + virtual void setChar(Dar* lineDar,int x,char ch,char fill); + virtual void setChar(Dar* lineDar,int x,char ch); + virtual void shiftLineLeft(Dar* lineDar,int x,int count); + virtual void shiftLineRight(Dar* lineDar,int x,int count); +private: + virtual int spatialCharOffsetBetweenTwoLines(Dar* srcDar,Dar* dstDar,int x); +protected: + Dar*> _lineDarDar; + int _cursor[2]; + bool _cursorBlink; + int _cursorNextBlinkTime; + Font* _font; +}; + +} + +#endif \ No newline at end of file diff --git a/utils/vgui/include/VGUI_EtchedBorder.h b/utils/vgui/include/VGUI_EtchedBorder.h new file mode 100644 index 0000000..25225ad --- /dev/null +++ b/utils/vgui/include/VGUI_EtchedBorder.h @@ -0,0 +1,23 @@ + +#ifndef VGUI_ETCHEDBORDER_H +#define VGUI_ETCHEDBORDER_H + +#include +#include + +namespace vgui +{ + +class Panel; + +class VGUIAPI EtchedBorder : public Border +{ +public: + EtchedBorder(); +protected: + virtual void paint(Panel* panel); +}; + +} + +#endif \ No newline at end of file diff --git a/utils/vgui/include/VGUI_FileInputStream.h b/utils/vgui/include/VGUI_FileInputStream.h new file mode 100644 index 0000000..a131999 --- /dev/null +++ b/utils/vgui/include/VGUI_FileInputStream.h @@ -0,0 +1,32 @@ + +#ifndef VGUI_FILEINPUTSTREAM_H +#define VGUI_FILEINPUTSTREAM_H + +//TODO : figure out how to get stdio out of here, I think std namespace is broken for FILE for forward declaring does not work in vc6 + +#include +#include + +namespace vgui +{ + +class VGUIAPI FileInputStream : public InputStream +{ +private: + FILE* _fp; +public: + FileInputStream(const char* fileName,bool textMode); +public: + virtual void seekStart(bool& success); + virtual void seekRelative(int count,bool& success); + virtual void seekEnd(bool& success); + virtual int getAvailable(bool& success); + virtual uchar readUChar(bool& success); + virtual void readUChar(uchar* buf,int count,bool& success); + virtual void close(bool& success); + virtual void close(); +}; + +} + +#endif diff --git a/utils/vgui/include/VGUI_FlowLayout.h b/utils/vgui/include/VGUI_FlowLayout.h new file mode 100644 index 0000000..45403a1 --- /dev/null +++ b/utils/vgui/include/VGUI_FlowLayout.h @@ -0,0 +1,23 @@ + +#ifndef VGUI_FLOWLAYOUT_H +#define VGUI_FLOWLAYOUT_H + +#include +#include + +namespace vgui +{ + +class VGUIAPI FlowLayout : public Layout +{ +private: + int _hgap; +public: + FlowLayout(int hgap); +public: + virtual void performLayout(Panel* panel); +}; + +} + +#endif \ No newline at end of file diff --git a/utils/vgui/include/VGUI_FocusChangeSignal.h b/utils/vgui/include/VGUI_FocusChangeSignal.h new file mode 100644 index 0000000..925e457 --- /dev/null +++ b/utils/vgui/include/VGUI_FocusChangeSignal.h @@ -0,0 +1,20 @@ + +#ifndef VGUI_FOCUSCHANGESIGNAL_H +#define VGUI_FOCUSCHANGESIGNAL_H + +#include + +namespace vgui +{ + +class Panel; + +class VGUIAPI FocusChangeSignal +{ +public: + virtual void focusChanged(bool lost,Panel* panel)=0; +}; + +} + +#endif \ No newline at end of file diff --git a/utils/vgui/include/VGUI_FocusNavGroup.h b/utils/vgui/include/VGUI_FocusNavGroup.h new file mode 100644 index 0000000..647efd0 --- /dev/null +++ b/utils/vgui/include/VGUI_FocusNavGroup.h @@ -0,0 +1,29 @@ + +#ifndef VGUI_FOCUSNAVGROUP_H +#define VGUI_FOCUSNAVGROUP_H + +#include +#include + +namespace vgui +{ + +class Panel; + +class VGUIAPI FocusNavGroup +{ +public: + FocusNavGroup(); +protected: + virtual void addPanel(Panel* panel); + virtual void requestFocusPrev(); + virtual void requestFocusNext(); + virtual void setCurrentPanel(Panel* panel); +protected: + Dar _panelDar; + int _currentIndex; +friend class Panel; +}; +} + +#endif \ No newline at end of file diff --git a/utils/vgui/include/VGUI_Font.h b/utils/vgui/include/VGUI_Font.h new file mode 100644 index 0000000..ef2dbb0 --- /dev/null +++ b/utils/vgui/include/VGUI_Font.h @@ -0,0 +1,42 @@ + +#ifndef VGUI_FONT_H +#define VGUI_FONT_H + +#include + +namespace vgui +{ + +class BaseFontPlat; + +//TODO: cursors and fonts should work like gl binds +class VGUIAPI Font + { + public: + Font(const char* name,int tall,int wide,float rotation,int weight,bool italic,bool underline,bool strikeout,bool symbol); + // If pFileData is non-NULL, then it will try to load the 32-bit (RLE) TGA file. If that fails, + // it will create the font using the specified parameters. + // pUniqueName should be set if pFileData and fileDataLen are set so it can determine if a font is already loaded. + Font(const char* name,void *pFileData,int fileDataLen, int tall,int wide,float rotation,int weight,bool italic,bool underline,bool strikeout,bool symbol); + private: + virtual void init(const char* name,void *pFileData,int fileDataLen, int tall,int wide,float rotation,int weight,bool italic,bool underline,bool strikeout,bool symbol); + public: + BaseFontPlat* getPlat(); + virtual void getCharRGBA(int ch,int rgbaX,int rgbaY,int rgbaWide,int rgbaTall,uchar* rgba); + virtual void getCharABCwide(int ch,int& a,int& b,int& c); + virtual void getTextSize(const char* text,int& wide,int& tall); + virtual int getTall(); + virtual int getId(); + protected: + char* _name; + BaseFontPlat* _plat; + int _id; + friend class Surface; + }; + + +void Font_Reset(); + +} + +#endif \ No newline at end of file diff --git a/utils/vgui/include/VGUI_Frame.h b/utils/vgui/include/VGUI_Frame.h new file mode 100644 index 0000000..f047dc8 --- /dev/null +++ b/utils/vgui/include/VGUI_Frame.h @@ -0,0 +1,67 @@ + +#ifndef VGUI_FRAME_H +#define VGUI_FRAME_H + +#include +#include +#include + +namespace vgui +{ + +class Button; +class FrameSignal; + +class VGUIAPI Frame : public Panel + { + public: + Frame(int x,int y,int wide,int tall); + public: + virtual void setSize(int wide,int tall); + virtual void setInternal(bool state); + virtual void paintBackground(); + virtual bool isInternal(); + virtual Panel* getClient(); + virtual void setTitle(const char* title); + virtual void getTitle(char* buf,int bufLen); + virtual void setMoveable(bool state); + virtual void setSizeable(bool state); + virtual bool isMoveable(); + virtual bool isSizeable(); + virtual void addFrameSignal(FrameSignal* s); + virtual void setVisible(bool state); + virtual void setMenuButtonVisible(bool state); + virtual void setTrayButtonVisible(bool state); + virtual void setMinimizeButtonVisible(bool state); + virtual void setMaximizeButtonVisible(bool state); + virtual void setCloseButtonVisible(bool state); + public: //bullshit public + virtual void fireClosingSignal(); + virtual void fireMinimizingSignal(); + protected: + char* _title; + bool _internal; + bool _sizeable; + bool _moveable; + Panel* _topGrip; + Panel* _bottomGrip; + Panel* _leftGrip; + Panel* _rightGrip; + Panel* _topLeftGrip; + Panel* _topRightGrip; + Panel* _bottomLeftGrip; + Panel* _bottomRightGrip; + Panel* _captionGrip; + Panel* _client; + Button* _trayButton; + Button* _minimizeButton; + Button* _maximizeButton; + Button* _closeButton; + Button* _menuButton; + Dar _frameSignalDar; + Frame* _resizeable; + }; + +} + +#endif diff --git a/utils/vgui/include/VGUI_FrameSignal.h b/utils/vgui/include/VGUI_FrameSignal.h new file mode 100644 index 0000000..1ca67df --- /dev/null +++ b/utils/vgui/include/VGUI_FrameSignal.h @@ -0,0 +1,21 @@ + +#ifndef VGUI_FRAMESIGNAL_H +#define VGUI_FRAMESIGNAL_H + +#include + +namespace vgui +{ + +class Frame; + +class VGUIAPI FrameSignal +{ +public: + virtual void closing(Frame* frame)=0; + virtual void minimizing(Frame* frame,bool toTray)=0; +}; + +} + +#endif \ No newline at end of file diff --git a/utils/vgui/include/VGUI_GridLayout.h b/utils/vgui/include/VGUI_GridLayout.h new file mode 100644 index 0000000..fda35f2 --- /dev/null +++ b/utils/vgui/include/VGUI_GridLayout.h @@ -0,0 +1,24 @@ + +#ifndef VGUI_GRIDLAYOUT_H +#define VGUI_GRIDLAYOUT_H + +#include +#include + +namespace vgui +{ + +/* +class VGUIAPI GridLayout : public Layout +{ +public: + GridLayout(int rows,int cols,int hgap,int vgap); +protected: + int _rows; + int _cols; +}; +*/ + +} + +#endif \ No newline at end of file diff --git a/utils/vgui/include/VGUI_HeaderPanel.h b/utils/vgui/include/VGUI_HeaderPanel.h new file mode 100644 index 0000000..13a8daa --- /dev/null +++ b/utils/vgui/include/VGUI_HeaderPanel.h @@ -0,0 +1,59 @@ + +#ifndef VGUI_HEADERPANEL_H +#define VGUI_HEADERPANEL_H + +#include +#include +#include +#include + +namespace vgui +{ + +enum MouseCode; +class ChangeSignal; + +class VGUIAPI HeaderPanel : public Panel +{ + +private: + + Dar _sliderPanelDar; + Dar _sectionPanelDar; + Dar _changeSignalDar; + Panel* _sectionLayer; + int _sliderWide; + bool _dragging; + int _dragSliderIndex; + int _dragSliderStartPos; + int _dragSliderStartX; + +public: + + HeaderPanel(int x,int y,int wide,int tall); + +protected: + + virtual void performLayout(); + +public: + + virtual void addSectionPanel(Panel* panel); + virtual void setSliderPos(int sliderIndex,int pos); + virtual int getSectionCount(); + virtual void getSectionExtents(int sectionIndex,int& x0,int& x1); + virtual void addChangeSignal(ChangeSignal* s); + +public: //bullshit public + + virtual void fireChangeSignal(); + virtual void privateCursorMoved(int x,int y,Panel* panel); + virtual void privateMousePressed(MouseCode code,Panel* panel); + virtual void privateMouseReleased(MouseCode code,Panel* panel); + +}; + +} + +#endif + diff --git a/utils/vgui/include/VGUI_Image.h b/utils/vgui/include/VGUI_Image.h new file mode 100644 index 0000000..46c0575 --- /dev/null +++ b/utils/vgui/include/VGUI_Image.h @@ -0,0 +1,56 @@ + +#ifndef VGUI_IMAGE_H +#define VGUI_IMAGE_H + +#include +#include +#include + +//TODO:: needs concept of insets + +namespace vgui +{ + +class Panel; + +class VGUIAPI Image +{ +friend class Panel; +private: + int _pos[2]; + int _size[2]; + Panel* _panel; + Color _color; +public: + Image(); +public: + virtual void setPos(int x,int y); + virtual void getPos(int& x,int& y); + virtual void getSize(int& wide,int& tall); + virtual void setColor(Color color); + virtual void getColor(Color& color); +protected: + virtual void setSize(int wide,int tall); + virtual void drawSetColor(Scheme::SchemeColor sc); + virtual void drawSetColor(int r,int g,int b,int a); + virtual void drawFilledRect(int x0,int y0,int x1,int y1); + virtual void drawOutlinedRect(int x0,int y0,int x1,int y1); + virtual void drawSetTextFont(Scheme::SchemeFont sf); + virtual void drawSetTextFont(Font* font); + virtual void drawSetTextColor(Scheme::SchemeColor sc); + virtual void drawSetTextColor(int r,int g,int b,int a); + virtual void drawSetTextPos(int x,int y); + virtual void drawPrintText(const char* str,int strlen); + virtual void drawPrintText(int x,int y,const char* str,int strlen); + virtual void drawPrintChar(char ch); + virtual void drawPrintChar(int x,int y,char ch); + virtual void drawSetTextureRGBA(int id,const char* rgba,int wide,int tall); + virtual void drawSetTexture(int id); + virtual void drawTexturedRect(int x0,int y0,int x1,int y1); + virtual void paint(Panel* panel); +public: + virtual void doPaint(Panel* panel); +}; +} + +#endif \ No newline at end of file diff --git a/utils/vgui/include/VGUI_ImagePanel.h b/utils/vgui/include/VGUI_ImagePanel.h new file mode 100644 index 0000000..b33c3d6 --- /dev/null +++ b/utils/vgui/include/VGUI_ImagePanel.h @@ -0,0 +1,27 @@ + +#ifndef VGUI_IMAGEPANEL_H +#define VGUI_IMAGEPANEL_H + +#include +#include + +namespace vgui +{ + +class Image; + +class VGUIAPI ImagePanel : public Panel +{ +public: + ImagePanel(Image* image); +public: + virtual void setImage(Image* image); +protected: + virtual void paintBackground(); +protected: + Image* _image; +}; + +} + +#endif \ No newline at end of file diff --git a/utils/vgui/include/VGUI_InputSignal.h b/utils/vgui/include/VGUI_InputSignal.h new file mode 100644 index 0000000..e421d0b --- /dev/null +++ b/utils/vgui/include/VGUI_InputSignal.h @@ -0,0 +1,34 @@ + +#ifndef VGUI_INPUTSIGNAL_H +#define VGUI_INPUTSIGNAL_H + +#include + +namespace vgui +{ + +enum MouseCode; +enum KeyCode; +class Panel; + +//these are lumped into one for simplicity sake right now +class VGUIAPI InputSignal +{ +public: + virtual void cursorMoved(int x,int y,Panel* panel)=0; + virtual void cursorEntered(Panel* panel)=0; + virtual void cursorExited(Panel* panel)=0; + virtual void mousePressed(MouseCode code,Panel* panel)=0; + virtual void mouseDoublePressed(MouseCode code,Panel* panel)=0; + virtual void mouseReleased(MouseCode code,Panel* panel)=0; + virtual void mouseWheeled(int delta,Panel* panel)=0; + virtual void keyPressed(KeyCode code,Panel* panel)=0; + virtual void keyTyped(KeyCode code,Panel* panel)=0; + virtual void keyReleased(KeyCode code,Panel* panel)=0; + virtual void keyFocusTicked(Panel* panel)=0; + //virtual void hotKeyTyped(const HotKey* hotKey,Panel* panel)=0; +}; + +} + +#endif \ No newline at end of file diff --git a/utils/vgui/include/VGUI_InputStream.h b/utils/vgui/include/VGUI_InputStream.h new file mode 100644 index 0000000..e9eddc2 --- /dev/null +++ b/utils/vgui/include/VGUI_InputStream.h @@ -0,0 +1,24 @@ + +#ifndef VGUI_FILE_H +#define VGUI_FILE_H + +#include + +namespace vgui +{ + +class VGUIAPI InputStream +{ +public: + virtual void seekStart(bool& success)=0; + virtual void seekRelative(int count,bool& success)=0; + virtual void seekEnd(bool& success)=0; + virtual int getAvailable(bool& success)=0; + virtual uchar readUChar(bool& success)=0; + virtual void readUChar(uchar* buf,int count,bool& success)=0; + virtual void close(bool& success)=0; +}; + +} + +#endif \ No newline at end of file diff --git a/utils/vgui/include/VGUI_IntChangeSignal.h b/utils/vgui/include/VGUI_IntChangeSignal.h new file mode 100644 index 0000000..f238d28 --- /dev/null +++ b/utils/vgui/include/VGUI_IntChangeSignal.h @@ -0,0 +1,20 @@ + +#ifndef VGUI_INTCHANGESIGNAL_H +#define VGUI_INTCHANGESIGNAL_H + +#include + +namespace vgui +{ + +class Panel; + +class VGUIAPI IntChangeSignal +{ +public: + virtual void intChanged(int value,Panel* panel)=0; +}; + +} + +#endif \ No newline at end of file diff --git a/utils/vgui/include/VGUI_IntLabel.h b/utils/vgui/include/VGUI_IntLabel.h new file mode 100644 index 0000000..157b452 --- /dev/null +++ b/utils/vgui/include/VGUI_IntLabel.h @@ -0,0 +1,29 @@ + +#ifndef VGUI_INTLABEL_H +#define VGUI_INTLABEL_H + +#include +#include +#include + +namespace vgui +{ + +class Panel; + +class VGUIAPI IntLabel : public Label , public IntChangeSignal +{ +public: + IntLabel(int value,int x,int y,int wide,int tall); +public: + virtual void setValue(int value); + virtual void intChanged(int value,Panel* panel); +protected: + virtual void paintBackground(); +protected: + int _value; +}; + +} + +#endif diff --git a/utils/vgui/include/VGUI_KeyCode.h b/utils/vgui/include/VGUI_KeyCode.h new file mode 100644 index 0000000..374d50f --- /dev/null +++ b/utils/vgui/include/VGUI_KeyCode.h @@ -0,0 +1,120 @@ + +#ifndef VGUI_KEYCODE_H +#define VGUI_KEYCODE_H + +#include + +namespace vgui +{ +enum VGUIAPI KeyCode +{ + KEY_0=0, + KEY_1, + KEY_2, + KEY_3, + KEY_4, + KEY_5, + KEY_6, + KEY_7, + KEY_8, + KEY_9, + KEY_A, + KEY_B, + KEY_C, + KEY_D, + KEY_E, + KEY_F, + KEY_G, + KEY_H, + KEY_I, + KEY_J, + KEY_K, + KEY_L, + KEY_M, + KEY_N, + KEY_O, + KEY_P, + KEY_Q, + KEY_R, + KEY_S, + KEY_T, + KEY_U, + KEY_V, + KEY_W, + KEY_X, + KEY_Y, + KEY_Z, + KEY_PAD_0, + KEY_PAD_1, + KEY_PAD_2, + KEY_PAD_3, + KEY_PAD_4, + KEY_PAD_5, + KEY_PAD_6, + KEY_PAD_7, + KEY_PAD_8, + KEY_PAD_9, + KEY_PAD_DIVIDE, + KEY_PAD_MULTIPLY, + KEY_PAD_MINUS, + KEY_PAD_PLUS, + KEY_PAD_ENTER, + KEY_PAD_DECIMAL, + KEY_LBRACKET, + KEY_RBRACKET, + KEY_SEMICOLON, + KEY_APOSTROPHE, + KEY_BACKQUOTE, + KEY_COMMA, + KEY_PERIOD, + KEY_SLASH, + KEY_BACKSLASH, + KEY_MINUS, + KEY_EQUAL, + KEY_ENTER, + KEY_SPACE, + KEY_BACKSPACE, + KEY_TAB, + KEY_CAPSLOCK, + KEY_NUMLOCK, + KEY_ESCAPE, + KEY_SCROLLLOCK, + KEY_INSERT, + KEY_DELETE, + KEY_HOME, + KEY_END, + KEY_PAGEUP, + KEY_PAGEDOWN, + KEY_BREAK, + KEY_LSHIFT, + KEY_RSHIFT, + KEY_LALT, + KEY_RALT, + KEY_LCONTROL, + KEY_RCONTROL, + KEY_LWIN, + KEY_RWIN, + KEY_APP, + KEY_UP, + KEY_LEFT, + KEY_DOWN, + KEY_RIGHT, + KEY_F1, + KEY_F2, + KEY_F3, + KEY_F4, + KEY_F5, + KEY_F6, + KEY_F7, + KEY_F8, + KEY_F9, + KEY_F10, + KEY_F11, + KEY_F12, + KEY_LAST, +}; +} + + +#endif + diff --git a/utils/vgui/include/VGUI_Label.h b/utils/vgui/include/VGUI_Label.h new file mode 100644 index 0000000..2617bd4 --- /dev/null +++ b/utils/vgui/include/VGUI_Label.h @@ -0,0 +1,69 @@ + +#ifndef VGUI_LABEL_H +#define VGUI_LABEL_H + +#include +#include +#include + +//TODO: this should use a TextImage for the text + +namespace vgui +{ + +class Panel; +class TextImage; + +class VGUIAPI Label : public Panel +{ +public: + enum Alignment + { + a_northwest=0, + a_north, + a_northeast, + a_west, + a_center, + a_east, + a_southwest, + a_south, + a_southeast, + }; +public: + Label(int textBufferLen,const char* text,int x,int y,int wide,int tall); + Label(const char* text,int x,int y,int wide,int tall); + Label(const char* text,int x,int y); + Label(const char* text); +private: + void init(int textBufferLen,const char* text,bool textFitted); +public: + virtual void setImage(Image* image); + virtual void setText(int textBufferLen,const char* text); + virtual void setText(const char* format,...); + virtual void setFont(Scheme::SchemeFont schemeFont); + virtual void setFont(Font* font); + virtual void getTextSize(int& wide,int& tall); + virtual void getContentSize(int& wide,int& tall); + virtual void setTextAlignment(Alignment alignment); + virtual void setContentAlignment(Alignment alignment); + virtual Panel* createPropertyPanel(); + virtual void setFgColor(int r,int g,int b,int a); + virtual void setFgColor(vgui::Scheme::SchemeColor sc); + virtual void setContentFitted(bool state); +protected: + virtual void computeAlignment(int& tx0,int& ty0,int& tx1,int& ty1,int& ix0,int& iy0,int& ix1,int& iy1,int& minX,int& minY,int& maxX,int& maxY); + virtual void paint(); + virtual void recomputeMinimumSize(); +protected: + bool _textEnabled; + bool _imageEnabled; + bool _contentFitted; + Alignment _textAlignment; + Alignment _contentAlignment; + TextImage* _textImage; + Image* _image; +}; + +} + +#endif \ No newline at end of file diff --git a/utils/vgui/include/VGUI_Layout.h b/utils/vgui/include/VGUI_Layout.h new file mode 100644 index 0000000..f76bf7e --- /dev/null +++ b/utils/vgui/include/VGUI_Layout.h @@ -0,0 +1,25 @@ + +#ifndef VGUI_LAYOUT_H +#define VGUI_LAYOUT_H + +#include + +namespace vgui +{ + +class Panel; + +class VGUIAPI Layout +{ +//private: +// Panel* _panel; +public: + Layout(); +public: + //virtual void setPanel(Panel* panel); //called by Panel::setLayout + virtual void performLayout(Panel* panel); +}; + +} + +#endif \ No newline at end of file diff --git a/utils/vgui/include/VGUI_LayoutInfo.h b/utils/vgui/include/VGUI_LayoutInfo.h new file mode 100644 index 0000000..5f87181 --- /dev/null +++ b/utils/vgui/include/VGUI_LayoutInfo.h @@ -0,0 +1,15 @@ + +#ifndef VGUI_LAYOUTINFO_H +#define VGUI_LAYOUTINFO_H + +namespace vgui +{ + +class VGUIAPI LayoutInfo +{ + virtual LayoutInfo* getThis()=0; +}; + +} + +#endif \ No newline at end of file diff --git a/utils/vgui/include/VGUI_LineBorder.h b/utils/vgui/include/VGUI_LineBorder.h new file mode 100644 index 0000000..c72a354 --- /dev/null +++ b/utils/vgui/include/VGUI_LineBorder.h @@ -0,0 +1,31 @@ + +#ifndef VGUI_LINEBORDER_H +#define VGUI_LINEBORDER_H + +#include +#include +#include + +namespace vgui +{ + +class Panel; + +class VGUIAPI LineBorder : public Border +{ +private: + Color _color; +public: + LineBorder(); + LineBorder(int thickness); + LineBorder(Color color); + LineBorder(int thickness,Color color); +private: + virtual void init(int thickness,Color color); +protected: + virtual void paint(Panel* panel); +}; + +} + +#endif \ No newline at end of file diff --git a/utils/vgui/include/VGUI_ListPanel.h b/utils/vgui/include/VGUI_ListPanel.h new file mode 100644 index 0000000..8c11000 --- /dev/null +++ b/utils/vgui/include/VGUI_ListPanel.h @@ -0,0 +1,34 @@ + +#ifndef VGUI_LISTPANEL_H +#define VGUI_LISTPANEL_H + +#include +#include + +namespace vgui +{ + +class ScrollBar; + +//TODO: make a ScrollPanel and use a constrained one for _vpanel in ListPanel +class VGUIAPI ListPanel : public Panel +{ +public: + ListPanel(int x,int y,int wide,int tall); +public: + virtual void setSize(int wide,int tall); + virtual void addString(const char* str); + virtual void addItem(Panel* panel); + virtual void setPixelScroll(int value); + virtual void translatePixelScroll(int delta); +protected: + virtual void performLayout(); + virtual void paintBackground(); +protected: + Panel* _vpanel; + ScrollBar* _scroll; +}; + +} + +#endif \ No newline at end of file diff --git a/utils/vgui/include/VGUI_LoweredBorder.h b/utils/vgui/include/VGUI_LoweredBorder.h new file mode 100644 index 0000000..079f1bd --- /dev/null +++ b/utils/vgui/include/VGUI_LoweredBorder.h @@ -0,0 +1,23 @@ + +#ifndef VGUI_LOWEREDBORDER_H +#define VGUI_LOWEREDBORDER_H + +#include +#include + +namespace vgui +{ + +class Panel; + +class VGUIAPI LoweredBorder : public Border +{ +public: + LoweredBorder(); +protected: + virtual void paint(Panel* panel); +}; + +} + +#endif \ No newline at end of file diff --git a/utils/vgui/include/VGUI_Menu.h b/utils/vgui/include/VGUI_Menu.h new file mode 100644 index 0000000..bd840ea --- /dev/null +++ b/utils/vgui/include/VGUI_Menu.h @@ -0,0 +1,24 @@ + +#ifndef VGUI_MENU_H +#define VGUI_MENU_H + +#include +#include + +namespace vgui +{ + +class Panel; + +class VGUIAPI Menu : public Panel +{ +public: + Menu(int x,int y,int wide,int tall); + Menu(int wide,int tall); +public: + virtual void addMenuItem(Panel* panel); +}; + +} + +#endif \ No newline at end of file diff --git a/utils/vgui/include/VGUI_MenuItem.h b/utils/vgui/include/VGUI_MenuItem.h new file mode 100644 index 0000000..07dc070 --- /dev/null +++ b/utils/vgui/include/VGUI_MenuItem.h @@ -0,0 +1,24 @@ + +#ifndef VGUI_MENUITEM_H +#define VGUI_MENUITEM_H + +#include +#include + +namespace vgui +{ + +class Menu; + +class VGUIAPI MenuItem : public Button +{ +public: + MenuItem(const char* text); + MenuItem(const char* text,Menu* subMenu); +protected: + Menu* _subMenu; +}; + +} + +#endif \ No newline at end of file diff --git a/utils/vgui/include/VGUI_MenuSeparator.h b/utils/vgui/include/VGUI_MenuSeparator.h new file mode 100644 index 0000000..e145135 --- /dev/null +++ b/utils/vgui/include/VGUI_MenuSeparator.h @@ -0,0 +1,21 @@ + +#ifndef VGUI_MENUSEPARATOR_H +#define VGUI_MENUSEPARATOR_H + +#include +#include + +namespace vgui +{ + +class VGUIAPI MenuSeparator : public Label +{ +public: + MenuSeparator(const char* text); +protected: + virtual void paintBackground(); +}; + +} + +#endif \ No newline at end of file diff --git a/utils/vgui/include/VGUI_MessageBox.h b/utils/vgui/include/VGUI_MessageBox.h new file mode 100644 index 0000000..6b68e20 --- /dev/null +++ b/utils/vgui/include/VGUI_MessageBox.h @@ -0,0 +1,47 @@ + +#ifndef VGUI_MESSAGEBOX_H +#define VGUI_MESSAGEBOX_H + +#include +#include +#include + + +namespace vgui +{ + +class Label; +class Button; +class ActionSignal; + +class VGUIAPI MessageBox : public Frame +{ + +private: + + Label* _messageLabel; + Button* _okButton; + Dar _actionSignalDar; + +public: + + MessageBox(const char* title,const char* text,int x,int y); + +protected: + + virtual void performLayout(); + +public: + + virtual void addActionSignal(ActionSignal* s); + virtual void fireActionSignal(); + +}; + +} + + + + + +#endif \ No newline at end of file diff --git a/utils/vgui/include/VGUI_MiniApp.h b/utils/vgui/include/VGUI_MiniApp.h new file mode 100644 index 0000000..aa9d9e9 --- /dev/null +++ b/utils/vgui/include/VGUI_MiniApp.h @@ -0,0 +1,27 @@ + +#ifndef VGUI_MINIAPP_H +#define VGUI_MINIAPP_H + +#include + +namespace vgui +{ + +class Frame; + +class VGUIAPI MiniApp +{ +public: + MiniApp(); +public: + virtual void getName(char* buf,int bufLen); + virtual Frame* createInstance()=0; +protected: + virtual void setName(const char* name); +protected: + char* _name; +}; + +} + +#endif \ No newline at end of file diff --git a/utils/vgui/include/VGUI_MouseCode.h b/utils/vgui/include/VGUI_MouseCode.h new file mode 100644 index 0000000..5a7228b --- /dev/null +++ b/utils/vgui/include/VGUI_MouseCode.h @@ -0,0 +1,18 @@ + +#ifndef VGUI_MOUSECODE_H +#define VGUI_MOUSECODE_H + +#include + +namespace vgui +{ +enum VGUIAPI MouseCode +{ + MOUSE_LEFT=0, + MOUSE_RIGHT, + MOUSE_MIDDLE, + MOUSE_LAST, +}; +} + +#endif \ No newline at end of file diff --git a/utils/vgui/include/VGUI_Panel.h b/utils/vgui/include/VGUI_Panel.h new file mode 100644 index 0000000..365d67c --- /dev/null +++ b/utils/vgui/include/VGUI_Panel.h @@ -0,0 +1,218 @@ + +#ifndef VGUI_PANEL_H +#define VGUI_PANEL_H + + +/* + +TODO: + +Maybe have the border know who they are added to. +A border can only be added to 1 thing, and will be +removed from the other. That way they can actually +be memory managed. Also do Layout's this way too. + +TODO: + outlinedRect should have a thickness arg + +*/ + + +#include +#include +#include +#include + +namespace vgui +{ + +enum KeyCode; +enum MouseCode; +class SurfaceBase; +class FocusChangeSignal; +class InputSignal; +class Cursor; +class Layout; +class FocusNavGroup; +class Border; +class Font; +class BuildGroup; +class App; +class LayoutInfo; + +class VGUIAPI Panel +{ +public: + Panel(); + Panel(int x,int y,int wide,int tall); +private: + void init(int x,int y,int wide,int tall); +public: + virtual void setPos(int x,int y); + virtual void getPos(int& x,int& y); + virtual void setSize(int wide,int tall); + virtual void getSize(int& wide,int& tall); + virtual void setBounds(int x,int y,int wide,int tall); + virtual void getBounds(int& x,int& y,int& wide,int& tall); + virtual int getWide(); + virtual int getTall(); + virtual Panel* getParent(); + virtual void setVisible(bool state); + virtual bool isVisible(); + virtual bool isVisibleUp(); + virtual void repaint(); + virtual void repaintAll(); + virtual void getAbsExtents(int& x0,int& y0,int& x1,int& y1); + virtual void getClipRect(int& x0,int& y0,int& x1,int& y1); + virtual void setParent(Panel* newParent); + virtual void addChild(Panel* child); + virtual void insertChildAt(Panel* child,int index); + virtual void removeChild(Panel* child); + virtual bool wasMousePressed(MouseCode code); + virtual bool wasMouseDoublePressed(MouseCode code); + virtual bool isMouseDown(MouseCode code); + virtual bool wasMouseReleased(MouseCode code); + virtual bool wasKeyPressed(KeyCode code); + virtual bool isKeyDown(KeyCode code); + virtual bool wasKeyTyped(KeyCode code); + virtual bool wasKeyReleased(KeyCode code); + virtual void addInputSignal(InputSignal* s); + virtual void removeInputSignal(InputSignal* s); + virtual void addRepaintSignal(RepaintSignal* s); + virtual void removeRepaintSignal(RepaintSignal* s); + virtual bool isWithin(int x,int y); //in screen space + virtual Panel* isWithinTraverse(int x,int y); + virtual void localToScreen(int& x,int& y); + virtual void screenToLocal(int& x,int& y); + virtual void setCursor(Cursor* cursor); + virtual void setCursor(Scheme::SchemeCursor scu); + virtual Cursor* getCursor(); + virtual void setMinimumSize(int wide,int tall); + virtual void getMinimumSize(int& wide,int& tall); + virtual void requestFocus(); + virtual bool hasFocus(); + virtual int getChildCount(); + virtual Panel* getChild(int index); + virtual void setLayout(Layout* layout); + virtual void invalidateLayout(bool layoutNow); + virtual void setFocusNavGroup(FocusNavGroup* focusNavGroup); + virtual void requestFocusPrev(); + virtual void requestFocusNext(); + virtual void addFocusChangeSignal(FocusChangeSignal* s); + virtual bool isAutoFocusNavEnabled(); + virtual void setAutoFocusNavEnabled(bool state); + virtual void setBorder(Border* border); + virtual void setPaintBorderEnabled(bool state); + virtual void setPaintBackgroundEnabled(bool state); + virtual void setPaintEnabled(bool state); + virtual void getInset(int& left,int& top,int& right,int& bottom); + virtual void getPaintSize(int& wide,int& tall); + virtual void setPreferredSize(int wide,int tall); + virtual void getPreferredSize(int& wide,int& tall); + virtual SurfaceBase* getSurfaceBase(); + virtual bool isEnabled(); + virtual void setEnabled(bool state); + virtual void setBuildGroup(BuildGroup* buildGroup,const char* panelPersistanceName); + virtual bool isBuildGroupEnabled(); + virtual void removeAllChildren(); + virtual void repaintParent(); + virtual Panel* createPropertyPanel(); + virtual void getPersistanceText(char* buf,int bufLen); + virtual void applyPersistanceText(const char* buf); + virtual void setFgColor(Scheme::SchemeColor sc); + virtual void setBgColor(Scheme::SchemeColor sc); + virtual void setFgColor(int r,int g,int b,int a); + virtual void setBgColor(int r,int g,int b,int a); + virtual void getFgColor(int& r,int& g,int& b,int& a); + virtual void getBgColor(int& r,int& g,int& b,int& a); + virtual void setBgColor(Color color); + virtual void setFgColor(Color color); + virtual void getBgColor(Color& color); + virtual void getFgColor(Color& color); + virtual void setAsMouseCapture(bool state); + virtual void setAsMouseArena(bool state); + virtual App* getApp(); + virtual void getVirtualSize(int& wide,int& tall); + virtual void setLayoutInfo(LayoutInfo* layoutInfo); + virtual LayoutInfo* getLayoutInfo(); + virtual bool isCursorNone(); +public: //bullshit public + virtual void solveTraverse(); + virtual void paintTraverse(); + virtual void setSurfaceBaseTraverse(SurfaceBase* surfaceBase); +protected: + virtual void performLayout(); + virtual void internalPerformLayout(); + virtual void drawSetColor(Scheme::SchemeColor sc); + virtual void drawSetColor(int r,int g,int b,int a); + virtual void drawFilledRect(int x0,int y0,int x1,int y1); + virtual void drawOutlinedRect(int x0,int y0,int x1,int y1); + virtual void drawSetTextFont(Scheme::SchemeFont sf); + virtual void drawSetTextFont(Font* font); + virtual void drawSetTextColor(Scheme::SchemeColor sc); + virtual void drawSetTextColor(int r,int g,int b,int a); + virtual void drawSetTextPos(int x,int y); + virtual void drawPrintText(const char* str,int strlen); + virtual void drawPrintText(int x,int y,const char* str,int strlen); + virtual void drawPrintChar(char ch); + virtual void drawPrintChar(int x,int y,char ch); + virtual void drawSetTextureRGBA(int id,const char* rgba,int wide,int tall); + virtual void drawSetTexture(int id); + virtual void drawTexturedRect(int x0,int y0,int x1,int y1); + virtual void solve(); + virtual void paintTraverse(bool repaint); + virtual void paintBackground(); + virtual void paint(); + virtual void paintBuildOverlay(); + virtual void internalCursorMoved(int x,int y); + virtual void internalCursorEntered(); + virtual void internalCursorExited(); + virtual void internalMousePressed(MouseCode code); + virtual void internalMouseDoublePressed(MouseCode code); + virtual void internalMouseReleased(MouseCode code); + virtual void internalMouseWheeled(int delta); + virtual void internalKeyPressed(KeyCode code); + virtual void internalKeyTyped(KeyCode code); + virtual void internalKeyReleased(KeyCode code); + virtual void internalKeyFocusTicked(); + virtual void internalFocusChanged(bool lost); + virtual void internalSetCursor(); +protected: + int _pos[2]; + int _size[2]; + int _loc[2]; + int _minimumSize[2]; + int _preferredSize[2]; + Dar _childDar; + Panel* _parent; + SurfaceBase* _surfaceBase; + Dar _inputSignalDar; + Dar _repaintSignalDar; + int _clipRect[4]; + Cursor* _cursor; + Scheme::SchemeCursor _schemeCursor; + bool _visible; + Layout* _layout; + bool _needsLayout; + FocusNavGroup* _focusNavGroup; + Dar _focusChangeSignalDar; + bool _autoFocusNavEnabled; + Border* _border; +private: + bool _needsRepaint; + bool _enabled; + BuildGroup* _buildGroup; + Color _fgColor; + Color _bgColor; + LayoutInfo* _layoutInfo; + bool _paintBorderEnabled; + bool _paintBackgroundEnabled; + bool _paintEnabled; +friend class Panel; +friend class App; +friend class SurfaceBase; +friend class Image; +}; +} + +#endif diff --git a/utils/vgui/include/VGUI_PopupMenu.h b/utils/vgui/include/VGUI_PopupMenu.h new file mode 100644 index 0000000..3305eee --- /dev/null +++ b/utils/vgui/include/VGUI_PopupMenu.h @@ -0,0 +1,24 @@ + +#ifndef VGUI_POPUPMENU_H +#define VGUI_POPUPMENU_H + +#include +#include + +namespace vgui +{ + +class Panel; + +class VGUIAPI PopupMenu : public Menu +{ +public: + PopupMenu(int x,int y,int wide,int tall); + PopupMenu(int wide,int tall); +public: + virtual void showModal(Panel* panel); +}; + +} + +#endif \ No newline at end of file diff --git a/utils/vgui/include/VGUI_ProgressBar.h b/utils/vgui/include/VGUI_ProgressBar.h new file mode 100644 index 0000000..304715d --- /dev/null +++ b/utils/vgui/include/VGUI_ProgressBar.h @@ -0,0 +1,27 @@ + +#ifndef VGUI_PROGRESSBAR_H +#define VGUI_PROGRESSBAR_H + +#include +#include + +namespace vgui +{ + +class VGUIAPI ProgressBar : public Panel +{ +private: + int _segmentCount; + float _progress; +public: + ProgressBar(int segmentCount); +protected: + virtual void paintBackground(); +public: + virtual void setProgress(float progress); + virtual int getSegmentCount(); +}; + +} + +#endif \ No newline at end of file diff --git a/utils/vgui/include/VGUI_RadioButton.h b/utils/vgui/include/VGUI_RadioButton.h new file mode 100644 index 0000000..7a79000 --- /dev/null +++ b/utils/vgui/include/VGUI_RadioButton.h @@ -0,0 +1,23 @@ + +#ifndef VGUI_RADIOBUTTON_H +#define VGUI_RADIOBUTTON_H + +#include +#include + +namespace vgui +{ + +class VGUIAPI RadioButton : public ToggleButton +{ +public: + RadioButton(const char* text,int x,int y,int wide,int tall); + RadioButton(const char* text,int x,int y); +protected: + virtual void paintBackground(); +}; + +} + +#endif + diff --git a/utils/vgui/include/VGUI_RaisedBorder.h b/utils/vgui/include/VGUI_RaisedBorder.h new file mode 100644 index 0000000..8da5047 --- /dev/null +++ b/utils/vgui/include/VGUI_RaisedBorder.h @@ -0,0 +1,23 @@ + +#ifndef VGUI_RAISEDBORDER_H +#define VGUI_RAISEDBORDER_H + +#include +#include + +namespace vgui +{ + +class Panel; + +class VGUIAPI RaisedBorder : public Border +{ +public: + RaisedBorder(); +protected: + virtual void paint(Panel* panel); +}; + +} + +#endif \ No newline at end of file diff --git a/utils/vgui/include/VGUI_RepaintSignal.h b/utils/vgui/include/VGUI_RepaintSignal.h new file mode 100644 index 0000000..4f56ef9 --- /dev/null +++ b/utils/vgui/include/VGUI_RepaintSignal.h @@ -0,0 +1,19 @@ + +#ifndef VGUI_REPAINTSIGNAL_H +#define VGUI_REPAINTSIGNAL_H + + + +namespace vgui +{ + +class RepaintSignal +{ +public: + virtual void panelRepainted(Panel* panel)=0; +}; + +} + + +#endif \ No newline at end of file diff --git a/utils/vgui/include/VGUI_Scheme.h b/utils/vgui/include/VGUI_Scheme.h new file mode 100644 index 0000000..f606c02 --- /dev/null +++ b/utils/vgui/include/VGUI_Scheme.h @@ -0,0 +1,76 @@ + +#ifndef VGUI_SCHEME_H +#define VGUI_SCHEME_H + +#include + + +namespace vgui +{ + +class Font; +class Cursor; + +class VGUIAPI Scheme +{ +public: + enum SchemeColor + { + sc_user=0, + sc_black, + sc_white, + sc_primary1, + sc_primary2, + sc_primary3, + sc_secondary1, + sc_secondary2, + sc_secondary3, + sc_last, + }; + enum SchemeFont + { + sf_user=0, + sf_primary1, + sf_primary2, + sf_primary3, + sf_secondary1, + sf_last, + }; + enum SchemeCursor + { + scu_user=0, + scu_none, + scu_arrow, + scu_ibeam, + scu_hourglass, + scu_crosshair, + scu_up, + scu_sizenwse, + scu_sizenesw, + scu_sizewe, + scu_sizens, + scu_sizeall, + scu_no, + scu_hand, + scu_last, + }; +public: + Scheme(); +public: + virtual void setColor(SchemeColor sc,int r,int g,int b,int a); + virtual void getColor(SchemeColor sc,int& r,int& g,int& b,int& a); + virtual void setFont(SchemeFont sf,Font* font); + virtual Font* getFont(SchemeFont sf); + virtual void setCursor(SchemeCursor sc,Cursor* cursor); + virtual Cursor* getCursor(SchemeCursor sc); +protected: + int _color[sc_last][4]; + Font* _font[sf_last]; + Cursor* _cursor[scu_last]; + friend class Panel; + friend class Canvas; +}; + +} + +#endif \ No newline at end of file diff --git a/utils/vgui/include/VGUI_ScrollBar.h b/utils/vgui/include/VGUI_ScrollBar.h new file mode 100644 index 0000000..c1c03e0 --- /dev/null +++ b/utils/vgui/include/VGUI_ScrollBar.h @@ -0,0 +1,50 @@ + +#ifndef VGUI_SCROLLBAR_H +#define VGUI_SCROLLBAR_H + +#include +#include +#include + +namespace vgui +{ + +class IntChangeSignal; +class Button; +class Slider; + +class VGUIAPI ScrollBar : public Panel +{ +public: + ScrollBar(int x,int y,int wide,int tall,bool vertical); +public: + virtual void setValue(int value); + virtual int getValue(); + virtual void addIntChangeSignal(IntChangeSignal* s); + virtual void setRange(int min,int max); + virtual void setRangeWindow(int rangeWindow); + virtual void setRangeWindowEnabled(bool state); + virtual void setSize(int wide,int tall); + virtual bool isVertical(); + virtual bool hasFullRange(); + virtual void setButton(Button* button,int index); + virtual Button* getButton(int index); + virtual void setSlider(Slider* slider); + virtual Slider* getSlider(); + virtual void doButtonPressed(int buttonIndex); + virtual void setButtonPressedScrollValue(int value); + virtual void validate(); +public: //bullshit public + virtual void fireIntChangeSignal(); +protected: + virtual void performLayout(); +protected: + Button* _button[2]; + Slider* _slider; + Dar _intChangeSignalDar; + int _buttonPressedScrollValue; +}; + +} + +#endif \ No newline at end of file diff --git a/utils/vgui/include/VGUI_ScrollPanel.h b/utils/vgui/include/VGUI_ScrollPanel.h new file mode 100644 index 0000000..4b57d54 --- /dev/null +++ b/utils/vgui/include/VGUI_ScrollPanel.h @@ -0,0 +1,49 @@ + +#ifndef VGUI_SCROLLPANEL_H +#define VGUI_SCROLLPANEL_H + +#include +#include + +//NOTE: You need to call validate anytime you change a scrollbar + +namespace vgui +{ + +class ScrollBar; + +class VGUIAPI ScrollPanel : public Panel +{ +private: + Panel* _clientClip; + Panel* _client; + ScrollBar* _horizontalScrollBar; + ScrollBar* _verticalScrollBar; + bool _autoVisible[2]; +public: + ScrollPanel(int x,int y,int wide,int tall); +protected: + virtual void setSize(int wide,int tall); +public: + virtual void setScrollBarVisible(bool horizontal,bool vertical); + virtual void setScrollBarAutoVisible(bool horizontal,bool vertical); + virtual Panel* getClient(); + virtual Panel* getClientClip(); + virtual void setScrollValue(int horizontal,int vertical); + virtual void getScrollValue(int& horizontal,int& vertical); + virtual void recomputeClientSize(); + virtual ScrollBar* getHorizontalScrollBar(); + virtual ScrollBar* getVerticalScrollBar(); + virtual void validate(); +public: //bullshit public + virtual void recomputeScroll(); +}; + +} + + + + + + +#endif diff --git a/utils/vgui/include/VGUI_Slider.h b/utils/vgui/include/VGUI_Slider.h new file mode 100644 index 0000000..eb79274 --- /dev/null +++ b/utils/vgui/include/VGUI_Slider.h @@ -0,0 +1,63 @@ + +#ifndef VGUI_SLIDER_H +#define VGUI_SLIDER_H + +#include +#include +#include + +namespace vgui +{ + +enum MouseCode; +class IntChangeSignal; + +class VGUIAPI Slider : public Panel +{ +private: + bool _vertical; + bool _dragging; + int _nobPos[2]; + int _nobDragStartPos[2]; + int _dragStartPos[2]; + Dar _intChangeSignalDar; + int _range[2]; + int _value; + int _rangeWindow; + bool _rangeWindowEnabled; + int _buttonOffset; +public: + Slider(int x,int y,int wide,int tall,bool vertical); +public: + virtual void setValue(int value); + virtual int getValue(); + virtual bool isVertical(); + virtual void addIntChangeSignal(IntChangeSignal* s); + virtual void setRange(int min,int max); + virtual void getRange(int& min,int& max); + virtual void setRangeWindow(int rangeWindow); + virtual void setRangeWindowEnabled(bool state); + virtual void setSize(int wide,int tall); + virtual void getNobPos(int& min, int& max); + virtual bool hasFullRange(); + virtual void setButtonOffset(int buttonOffset); +private: + virtual void recomputeNobPosFromValue(); + virtual void recomputeValueFromNobPos(); +public: //bullshit public + virtual void privateCursorMoved(int x,int y,Panel* panel); + virtual void privateMousePressed(MouseCode code,Panel* panel); + virtual void privateMouseReleased(MouseCode code,Panel* panel); +protected: + virtual void fireIntChangeSignal(); + virtual void paintBackground(); +}; + +} + +#endif + + + + + diff --git a/utils/vgui/include/VGUI_StackLayout.h b/utils/vgui/include/VGUI_StackLayout.h new file mode 100644 index 0000000..e6d9e80 --- /dev/null +++ b/utils/vgui/include/VGUI_StackLayout.h @@ -0,0 +1,24 @@ + +#ifndef VGUI_STACKLAYOUT_H +#define VGUI_STACKLAYOUT_H + +#include +#include + +namespace vgui +{ + +class VGUIAPI StackLayout : public Layout +{ +private: + int _vgap; + bool _fitWide; +public: + StackLayout(int vgap,bool fitWide); +public: + virtual void performLayout(Panel* panel); +}; + +} + +#endif \ No newline at end of file diff --git a/utils/vgui/include/VGUI_String.h b/utils/vgui/include/VGUI_String.h new file mode 100644 index 0000000..1cdc576 --- /dev/null +++ b/utils/vgui/include/VGUI_String.h @@ -0,0 +1,55 @@ + +#ifndef VGUI_STRING_H +#define VGUI_STRING_H + +#include + + +namespace vgui +{ + +class VGUIAPI String +{ + +friend class String; + +private: + + char* _text; + +public: + + String(); + String(const char* text); + String(const String& src); + +public: + + ~String(); + +private: + + int getCount(const char* text); + +public: + + int getCount(); + String operator+(String text); + String operator+(const char* text); + bool operator==(String text); + bool operator==(const char* text); + char operator[](int index); + const char* getChars(); + +public: + + static void test(); + +}; + + +} + + +#endif + diff --git a/utils/vgui/include/VGUI_Surface.h b/utils/vgui/include/VGUI_Surface.h new file mode 100644 index 0000000..ba1eda4 --- /dev/null +++ b/utils/vgui/include/VGUI_Surface.h @@ -0,0 +1,61 @@ + +#ifndef VGUI_SURFACE_H +#define VGUI_SURFACE_H + +#include +#include +#include + +namespace vgui +{ + +class Panel; +class Cursor; + +class VGUIAPI Surface : public SurfaceBase +{ +public: + Surface(Panel* embeddedPanel); +public: + virtual void setTitle(const char* title); + virtual bool setFullscreenMode(int wide,int tall,int bpp); + virtual void setWindowedMode(); + virtual void setAsTopMost(bool state); + virtual int getModeInfoCount(); + virtual void createPopup(Panel* embeddedPanel); + virtual bool hasFocus(); + virtual bool isWithin(int x,int y); +protected: + virtual int createNewTextureID(void); + virtual void drawSetColor(int r,int g,int b,int a); + virtual void drawFilledRect(int x0,int y0,int x1,int y1); + virtual void drawOutlinedRect(int x0,int y0,int x1,int y1); + virtual void drawSetTextFont(Font* font); + virtual void drawSetTextColor(int r,int g,int b,int a); + virtual void drawSetTextPos(int x,int y); + virtual void drawPrintText(const char* text,int textLen); + virtual void drawSetTextureRGBA(int id,const char* rgba,int wide,int tall); + virtual void drawSetTexture(int id); + virtual void drawTexturedRect(int x0,int y0,int x1,int y1); + virtual void invalidate(Panel *panel); + virtual bool createPlat(); + virtual bool recreateContext(); + virtual void enableMouseCapture(bool state); + virtual void setCursor(Cursor* cursor); + virtual void swapBuffers(); + virtual void pushMakeCurrent(Panel* panel,bool useInsets); + virtual void popMakeCurrent(Panel* panel); + virtual void applyChanges(); +protected: + class SurfacePlat* _plat; + bool _needsSwap; + Panel* _embeddedPanel; + Dar _modeInfoDar; + friend class App; + friend class Panel; +}; + +} + +#endif + diff --git a/utils/vgui/include/VGUI_SurfaceBase.h b/utils/vgui/include/VGUI_SurfaceBase.h new file mode 100644 index 0000000..50224cf --- /dev/null +++ b/utils/vgui/include/VGUI_SurfaceBase.h @@ -0,0 +1,75 @@ + +#ifndef VGUI_SURFACEBASE_H +#define VGUI_SURFACEBASE_H + +#include +#include + +namespace vgui +{ + +class Panel; +class Cursor; +class Font; +class App; +class ImagePanel; + +class VGUIAPI SurfaceBase +{ +public: + SurfaceBase(Panel* embeddedPanel); +protected: + ~SurfaceBase(); +public: + virtual Panel* getPanel(); + virtual void requestSwap(); + virtual void resetModeInfo(); + virtual int getModeInfoCount(); + virtual bool getModeInfo(int mode,int& wide,int& tall,int& bpp); + virtual App* getApp(); + virtual void setEmulatedCursorVisible(bool state); + virtual void setEmulatedCursorPos(int x,int y); +public: + virtual void setTitle(const char* title)=0; + virtual bool setFullscreenMode(int wide,int tall,int bpp)=0; + virtual void setWindowedMode()=0; + virtual void setAsTopMost(bool state)=0; + virtual void createPopup(Panel* embeddedPanel)=0; + virtual bool hasFocus()=0; + virtual bool isWithin(int x,int y)=0; + virtual int createNewTextureID(void)=0; +protected: + virtual void addModeInfo(int wide,int tall,int bpp); +protected: + virtual void drawSetColor(int r,int g,int b,int a)=0; + virtual void drawFilledRect(int x0,int y0,int x1,int y1)=0; + virtual void drawOutlinedRect(int x0,int y0,int x1,int y1)=0; + virtual void drawSetTextFont(Font* font)=0; + virtual void drawSetTextColor(int r,int g,int b,int a)=0; + virtual void drawSetTextPos(int x,int y)=0; + virtual void drawPrintText(const char* text,int textLen)=0; + virtual void drawSetTextureRGBA(int id,const char* rgba,int wide,int tall)=0; + virtual void drawSetTexture(int id)=0; + virtual void drawTexturedRect(int x0,int y0,int x1,int y1)=0; + virtual void invalidate(Panel *panel)=0; + virtual void enableMouseCapture(bool state)=0; + virtual void setCursor(Cursor* cursor)=0; + virtual void swapBuffers()=0; + virtual void pushMakeCurrent(Panel* panel,bool useInsets)=0; + virtual void popMakeCurrent(Panel* panel)=0; + virtual void applyChanges()=0; +protected: + bool _needsSwap; + App* _app; + Panel* _embeddedPanel; + Dar _modeInfoDar; + ImagePanel* _emulatedCursor; + Cursor* _currentCursor; +friend class App; +friend class Panel; +}; + +} + +#endif + diff --git a/utils/vgui/include/VGUI_SurfaceGL.h b/utils/vgui/include/VGUI_SurfaceGL.h new file mode 100644 index 0000000..bec574b --- /dev/null +++ b/utils/vgui/include/VGUI_SurfaceGL.h @@ -0,0 +1,92 @@ + +#ifndef VGUI_SURFACEGL_H +#define VGUI_SURFACEGL_H + +//macros borrowed from GLUT to get rid of win32 dependent junk in gl headers +#ifdef _WIN32 +# ifndef APIENTRY +# define VGUI_APIENTRY_DEFINED +# if (_MSC_VER >= 800) || defined(_STDCALL_SUPPORTED) +# define APIENTRY __stdcall +# else +# define APIENTRY +# endif +# endif +# ifndef CALLBACK +# define VGUI_CALLBACK_DEFINED +# if (defined(_M_MRX000) || defined(_M_IX86) || defined(_M_ALPHA) || defined(_M_PPC)) && !defined(MIDL_PASS) +# define CALLBACK __stdcall +# else +# define CALLBACK +# endif +# endif +# ifndef WINGDIAPI +# define VGUI_WINGDIAPI_DEFINED +# define WINGDIAPI __declspec(dllimport) +# endif +# ifndef _WCHAR_T_DEFINED +typedef unsigned short wchar_t; +# define _WCHAR_T_DEFINED +# endif +# pragma comment(lib,"opengl32.lib") +#endif + +#include +#include + +#ifdef VGUI_APIENTRY_DEFINED +# undef VGUI_APIENTRY_DEFINED +# undef APIENTRY +#endif + +#ifdef VGUI_CALLBACK_DEFINED +# undef VGUI_CALLBACK_DEFINED +# undef CALLBACK +#endif + +#ifdef VGUI_WINGDIAPI_DEFINED +# undef VGUI_WINGDIAPI_DEFINED +# undef WINGDIAPI +#endif + + + +#include +#include +#include + +namespace vgui +{ + +class VGUIAPI SurfaceGL : public Surface +{ +public: + SurfaceGL(Panel* embeddedPanel); +public: + virtual void createPopup(Panel* embeddedPanel); +protected: + virtual bool recreateContext(); + virtual void pushMakeCurrent(Panel* panel,bool useInsets); + virtual void popMakeCurrent(Panel* panel); + virtual void makeCurrent(); + virtual void swapBuffers(); + virtual void setColor(int r,int g,int b); + virtual void filledRect(int x0,int y0,int x1,int y1); + virtual void outlinedRect(int x0,int y0,int x1,int y1); + virtual void setTextFont(Font* font); + virtual void setTextColor(int r,int g,int b); + virtual void setDrawPos(int x,int y); + virtual void printText(const char* str,int strlen); + virtual void setTextureRGBA(int id,const char* rgba,int wide,int tall); + virtual void setTexture(int id); + virtual void texturedRect(int x0,int y0,int x1,int y1); +protected: + int _drawPos[2]; + uchar _drawColor[3]; + uchar _drawTextColor[3]; +}; + +} + +#endif + diff --git a/utils/vgui/include/VGUI_TabPanel.h b/utils/vgui/include/VGUI_TabPanel.h new file mode 100644 index 0000000..f267051 --- /dev/null +++ b/utils/vgui/include/VGUI_TabPanel.h @@ -0,0 +1,43 @@ + +#ifndef VGUI_TABPANEL_H +#define VGUI_TABPANEL_H + +#include +#include + +namespace vgui +{ + +class ButtonGroup; + +class VGUIAPI TabPanel : public Panel +{ +public: + enum TabPlacement + { + tp_top=0, + tp_bottom, + tp_left, + tp_right, + }; +public: + TabPanel(int x,int y,int wide,int tall); +public: + virtual Panel* addTab(const char* text); + virtual void setSelectedTab(Panel* tab); + virtual void setSize(int wide,int tall); +protected: + virtual void recomputeLayoutTop(); + virtual void recomputeLayout(); +protected: + TabPlacement _tabPlacement; + Panel* _tabArea; + Panel* _clientArea; + Panel* _selectedTab; + Panel* _selectedPanel; + ButtonGroup* _buttonGroup; +}; + +} + +#endif \ No newline at end of file diff --git a/utils/vgui/include/VGUI_TablePanel.h b/utils/vgui/include/VGUI_TablePanel.h new file mode 100644 index 0000000..07a0ecd --- /dev/null +++ b/utils/vgui/include/VGUI_TablePanel.h @@ -0,0 +1,65 @@ + +#ifndef VGUI_TABLEPANEL_H +#define VGUI_TABLEPANEL_H + +#include +#include +#include + +namespace vgui +{ + +class HeaderPanel; + +class VGUIAPI TablePanel : public Panel +{ +friend class FooVGuiTablePanelHandler; +private: + vgui::Dar _columnDar; + bool _gridVisible[2]; + int _gridWide; + int _gridTall; + int _selectedCell[2]; + int _mouseOverCell[2]; + int _editableCell[2]; + Panel* _fakeInputPanel; + bool _columnSelectionEnabled; + bool _rowSelectionEnabled; + bool _cellSelectionEnabled; + Panel* _editableCellPanel; + int _virtualSize[2]; + bool _cellEditingEnabled; +public: + TablePanel(int x,int y,int wide,int tall,int columnCount); +public: + virtual void setCellEditingEnabled(bool state); + virtual void setColumnCount(int columnCount); + virtual void setGridVisible(bool horizontal,bool vertical); + virtual void setGridSize(int gridWide,int gridTall); + virtual int getColumnCount(); + virtual void setColumnExtents(int column,int x0,int x1); + virtual void setSelectedCell(int column,int row); + virtual void getSelectedCell(int& column,int& row); + virtual void setHeaderPanel(HeaderPanel* header); + virtual void setColumnSelectionEnabled(bool state); + virtual void setRowSelectionEnabled(bool state); + virtual void setCellSectionEnabled(bool state); + virtual void setEditableCell(int column,int row); + virtual void stopCellEditing(); + virtual void getVirtualSize(int& wide,int& tall); + virtual int getRowCount()=0; + virtual int getCellTall(int row)=0; + virtual Panel* getCellRenderer(int column,int row,bool columnSelected,bool rowSelected,bool cellSelected)=0; + virtual Panel* startCellEditing(int column,int row)=0; +protected: + virtual void paint(); + virtual Panel* isWithinTraverse(int x,int y); +private: + virtual void privateMousePressed(MouseCode code,Panel* panel); + virtual void privateMouseDoublePressed(MouseCode code,Panel* panel); + virtual void privateKeyTyped(KeyCode code,Panel* panel); +}; + +} + +#endif \ No newline at end of file diff --git a/utils/vgui/include/VGUI_TaskBar.h b/utils/vgui/include/VGUI_TaskBar.h new file mode 100644 index 0000000..37b7f4f --- /dev/null +++ b/utils/vgui/include/VGUI_TaskBar.h @@ -0,0 +1,31 @@ + +#ifndef VGUI_TASKBAR_H +#define VGUI_TASKBAR_H + +#include +#include +#include + +namespace vgui +{ + +class Frame; +class Button; + +class VGUIAPI TaskBar : public Panel +{ +public: + TaskBar(int x,int y,int wide,int tall); +public: + virtual void addFrame(Frame* frame); +protected: + virtual void performLayout(); +protected: + Dar _frameDar; + Dar _taskButtonDar; + Panel* _tray; +}; + +} + +#endif \ No newline at end of file diff --git a/utils/vgui/include/VGUI_TextEntry.h b/utils/vgui/include/VGUI_TextEntry.h new file mode 100644 index 0000000..5e18d61 --- /dev/null +++ b/utils/vgui/include/VGUI_TextEntry.h @@ -0,0 +1,74 @@ + +#ifndef VGUI_TEXTENTRY_H +#define VGUI_TEXTENTRY_H + +#include +#include +#include + +namespace vgui +{ + +enum MouseCode; +enum KeyCode; +class ActionSignal; + +class VGUIAPI TextEntry : public Panel , public InputSignal +{ +public: + TextEntry(const char* text,int x,int y,int wide,int tall); +public: + virtual void setText(const char* text,int textLen); + virtual void getText(int offset,char* buf,int bufLen); + virtual void resetCursorBlink(); + virtual void doGotoLeft(); + virtual void doGotoRight(); + virtual void doGotoFirstOfLine(); + virtual void doGotoEndOfLine(); + virtual void doInsertChar(char ch); + virtual void doBackspace(); + virtual void doDelete(); + virtual void doSelectNone(); + virtual void doCopySelected(); + virtual void doPaste(); + virtual void doPasteSelected(); + virtual void doDeleteSelected(); + virtual void addActionSignal(ActionSignal* s); + virtual void setFont(Font* font); + virtual void setTextHidden(bool bHideText); +protected: + virtual void paintBackground(); + virtual void setCharAt(char ch,int index); +protected: + virtual void fireActionSignal(); + virtual bool getSelectedRange(int& cx0,int& cx1); + virtual bool getSelectedPixelRange(int& cx0,int& cx1); + virtual int cursorToPixelSpace(int cursorPos); + virtual void selectCheck(); +protected: //InputSignal + virtual void cursorMoved(int x,int y,Panel* panel); + virtual void cursorEntered(Panel* panel); + virtual void cursorExited(Panel* panel); + virtual void mousePressed(MouseCode code,Panel* panel); + virtual void mouseDoublePressed(MouseCode code,Panel* panel); + virtual void mouseReleased(MouseCode code,Panel* panel); + virtual void mouseWheeled(int delta,Panel* panel); + virtual void keyPressed(KeyCode code,Panel* panel); + virtual void keyTyped(KeyCode code,Panel* panel); + virtual void keyReleased(KeyCode code,Panel* panel); + virtual void keyFocusTicked(Panel* panel); +protected: + Dar _lineDar; + int _cursorPos; + bool _cursorBlink; + bool _hideText; + long _cursorNextBlinkTime; + int _cursorBlinkRate; + int _select[2]; + Dar _actionSignalDar; + Font* _font; +}; + +} + +#endif \ No newline at end of file diff --git a/utils/vgui/include/VGUI_TextGrid.h b/utils/vgui/include/VGUI_TextGrid.h new file mode 100644 index 0000000..a8b408c --- /dev/null +++ b/utils/vgui/include/VGUI_TextGrid.h @@ -0,0 +1,36 @@ + +#ifndef VGUI_TEXTGRID_H +#define VGUI_TEXTGRID_H + +#include +#include +#include + +namespace vgui +{ + +class VGUIAPI TextGrid : public Panel +{ +public: + TextGrid(int gridWide,int gridTall,int x,int y,int wide,int tall); +public: + virtual void setGridSize(int wide,int tall); + virtual void newLine(); + virtual void setXY(int x,int y); + //virtual void setBgColor(int r,int g,int b); + //virtual void setFgColor(int r,int g,int b); + virtual int vprintf(const char* format,va_list argList); + virtual int printf(const char* format,...); +protected: + virtual void paintBackground(); +protected: + int _xy[2]; + int _bgColor[3]; + int _fgColor[3]; + char* _grid; //[_gridSize[0]*_gridSize[1]*7] ch,br,bg,bb,fr,fg,fb + int _gridSize[2]; +}; + +} + +#endif \ No newline at end of file diff --git a/utils/vgui/include/VGUI_TextImage.h b/utils/vgui/include/VGUI_TextImage.h new file mode 100644 index 0000000..83a2a5a --- /dev/null +++ b/utils/vgui/include/VGUI_TextImage.h @@ -0,0 +1,52 @@ + +#ifndef VGUI_TEXTIMAGE_H +#define VGUI_TEXTIMAGE_H + +#include +#include +#include + + +//TODO: need to add wrapping flag instead of being arbitrary about when wrapping and auto-resizing actually happens +// This is probably why you are having problems if you had text in a constructor and then changed the font + +namespace vgui +{ + +class Panel; +class Font; +class App; + +class VGUIAPI TextImage : public Image +{ +private: + char* _text; + int _textBufferLen; + vgui::Scheme::SchemeFont _schemeFont; + vgui::Font* _font; + int _textColor[4]; + vgui::Scheme::SchemeColor _textSchemeColor; +public: + TextImage(int textBufferLen,const char* text); + TextImage(const char* text); +private: + virtual void init(int textBufferLen,const char* text); +public: + virtual void getTextSize(int& wide,int& tall); + virtual void getTextSizeWrapped(int& wide,int& tall); + virtual Font* getFont(); + virtual void setText(int textBufferLen,const char* text); + virtual void setText(const char* text); + virtual void setFont(vgui::Scheme::SchemeFont schemeFont); + virtual void setFont(vgui::Font* font); + virtual void setSize(int wide,int tall); +protected: + virtual void paint(Panel* panel); +}; + +} + +#endif + + + diff --git a/utils/vgui/include/VGUI_TextPanel.h b/utils/vgui/include/VGUI_TextPanel.h new file mode 100644 index 0000000..ecd1aa1 --- /dev/null +++ b/utils/vgui/include/VGUI_TextPanel.h @@ -0,0 +1,40 @@ + +#ifndef VGUI_TEXTPANEL_H +#define VGUI_TEXTPANEL_H + +#include +#include +#include + +//NOTE : If you are having trouble with this class, your problem is probably in TextImage + +namespace vgui +{ + +class TextImage; +class Font; + +class VGUIAPI TextPanel : public Panel +{ +private: + TextImage* _textImage; +public: + TextPanel(const char* text,int x,int y,int wide,int tall); +public: + virtual void setText(const char* text); + virtual void setFont(vgui::Scheme::SchemeFont schemeFont); + virtual void setFont(vgui::Font* font); + virtual void setSize(int wide,int tall); + virtual void setFgColor(int r,int g,int b,int a); + virtual void setFgColor(Scheme::SchemeColor sc); + virtual TextImage* getTextImage(); +protected: + virtual void paint(); +}; + +} + +#endif + + + diff --git a/utils/vgui/include/VGUI_TickSignal.h b/utils/vgui/include/VGUI_TickSignal.h new file mode 100644 index 0000000..8845998 --- /dev/null +++ b/utils/vgui/include/VGUI_TickSignal.h @@ -0,0 +1,16 @@ + +#ifndef VGUI_TICKSIGNAL_H +#define VGUI_TICKSIGNAL_H + +#include + +namespace vgui +{ +class VGUIAPI TickSignal + { + public: + virtual void ticked()=0; + }; +} + +#endif \ No newline at end of file diff --git a/utils/vgui/include/VGUI_ToggleButton.h b/utils/vgui/include/VGUI_ToggleButton.h new file mode 100644 index 0000000..96b304e --- /dev/null +++ b/utils/vgui/include/VGUI_ToggleButton.h @@ -0,0 +1,20 @@ + +#ifndef VGUI_TOGGLEBUTTON_H +#define VGUI_TOGGLEBUTTON_H + +#include +#include + +namespace vgui +{ + +class VGUIAPI ToggleButton : public Button +{ +public: + ToggleButton(const char* text,int x,int y,int wide,int tall); + ToggleButton(const char* text,int x,int y); +}; + +} + +#endif \ No newline at end of file diff --git a/utils/vgui/include/VGUI_TreeFolder.h b/utils/vgui/include/VGUI_TreeFolder.h new file mode 100644 index 0000000..be145c2 --- /dev/null +++ b/utils/vgui/include/VGUI_TreeFolder.h @@ -0,0 +1,30 @@ + +#ifndef VGUI_TREEFOLDER_H +#define VGUI_TREEFOLDER_H + +#include +#include + +namespace vgui +{ + +class VGUIAPI TreeFolder : public Panel +{ +public: + TreeFolder(const char* name); + TreeFolder(const char* name,int x,int y); +protected: + virtual void init(const char* name); +public: + virtual void setOpenedTraverse(bool state); + virtual void setOpened(bool state); + virtual bool isOpened(); +protected: + virtual void paintBackground(); +protected: + bool _opened; +}; + +} + +#endif \ No newline at end of file diff --git a/utils/vgui/include/VGUI_WizardPanel.h b/utils/vgui/include/VGUI_WizardPanel.h new file mode 100644 index 0000000..96cbc6e --- /dev/null +++ b/utils/vgui/include/VGUI_WizardPanel.h @@ -0,0 +1,140 @@ + +#ifndef VGUI_WIZARDPANEL_H +#define VGUI_WIZARDPANEL_H + +#include +#include + +namespace vgui +{ + +class ActionSignal; + +class VGUIAPI WizardPanel : public Panel +{ + +public: + + class VGUIAPI WizardPage : public Panel + { + + friend class WizardPanel; + + private: + + WizardPage* _backWizardPage; + WizardPage* _nextWizardPage; + bool _backButtonEnabled; + bool _nextButtonEnabled; + bool _finishedButtonEnabled; + bool _cancelButtonEnabled; + bool _backButtonVisible; + bool _nextButtonVisible; + bool _finishedButtonVisible; + bool _cancelButtonVisible; + char* _backButtonText; + char* _nextButtonText; + char* _finishedButtonText; + char* _cancelButtonText; + Dar _switchingToBackPageSignalDar; + Dar _switchingToNextPageSignalDar; + char* _title; + Panel* _wantedFocus; + + private: + + virtual void fireSwitchingToBackPageSignals(); + virtual void fireSwitchingToNextPageSignals(); + virtual void init(); + + public: + + WizardPage(); + WizardPage(int wide,int tall); + + public: + + virtual void setBackWizardPage(WizardPage* backWizardPage); + virtual void setNextWizardPage(WizardPage* nextWizardPage); + virtual WizardPage* getBackWizardPage(); + virtual WizardPage* getNextWizardPage(); + + virtual bool isBackButtonEnabled(); + virtual bool isNextButtonEnabled(); + virtual bool isFinishedButtonEnabled(); + virtual bool isCancelButtonEnabled(); + virtual void setBackButtonEnabled(bool state); + virtual void setNextButtonEnabled(bool state); + virtual void setFinishedButtonEnabled(bool state); + virtual void setCancelButtonEnabled(bool state); + + virtual bool isBackButtonVisible(); + virtual bool isNextButtonVisible(); + virtual bool isFinishedButtonVisible(); + virtual bool isCancelButtonVisible(); + virtual void setBackButtonVisible(bool state); + virtual void setNextButtonVisible(bool state); + virtual void setFinishedButtonVisible(bool state); + virtual void setCancelButtonVisible(bool state); + + virtual void getBackButtonText(char* text,int textLen); + virtual void getNextButtonText(char* text,int textLen); + virtual void getFinishedButtonText(char* text,int textLen); + virtual void getCancelButtonText(char* text,int textLen); + virtual void setBackButtonText(const char* text); + virtual void setNextButtonText(const char* text); + virtual void setFinishedButtonText(const char* text); + virtual void setCancelButtonText(const char* text); + + virtual void setWantedFocus(Panel* panel); + virtual Panel* getWantedFocus(); + + virtual void addSwitchingToBackPageSignal(ActionSignal* s); + virtual void addSwitchingToNextPageSignal(ActionSignal* s); + + virtual void setTitle(const char* title); + virtual void getTitle(char* buf,int bufLen); + + }; + +private: + + Button* _backButton; + Button* _nextButton; + Button* _finishedButton; + Button* _cancelButton; + WizardPage* _currentWizardPage; + Dar _pageChangedActionSignalDar; + +private: + + virtual void fireFinishedActionSignal(); + virtual void fireCancelledActionSignal(); + virtual void firePageChangedActionSignal(); + +protected: + + virtual void performLayout(); + +public: + + WizardPanel(int x,int y,int wide,int tall); + +public: + + virtual void setCurrentWizardPage(WizardPage* currentWizardPage); + virtual void addFinishedActionSignal(ActionSignal* s); + virtual void addCancelledActionSignal(ActionSignal* s); + virtual void addPageChangedActionSignal(ActionSignal* s); + virtual void doBack(); + virtual void doNext(); + virtual void getCurrentWizardPageTitle(char* buf,int bufLen); + virtual WizardPage* getCurrentWizardPage(); + +}; + +} + + +#endif + diff --git a/utils/vgui/lib/win32_vc6/vgui.lib b/utils/vgui/lib/win32_vc6/vgui.lib new file mode 100644 index 0000000000000000000000000000000000000000..ddb2c91207b900d9b88b7a9c0eae2b28f3c45438 GIT binary patch literal 415712 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

G`7IlL5oue0W=xp7Pi~vg?;bM)a?VJ{m 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 mZ*ToLL^VPUp-jlwz$My%F-$AXS8lj{ZMpWK}Bw literal 0 HcmV?d00001 diff --git a/utils/visx2/mssccprj.scc b/utils/visx2/mssccprj.scc index c68f8be..3ddd63e 100644 --- a/utils/visx2/mssccprj.scc +++ b/utils/visx2/mssccprj.scc @@ -1,4 +1,5 @@ SCC = This is a Source Code Control file [vis.mak] -SCC_Project_Name = "$/HLStandardSDK/SourceCode/utils/visx2", RFXHAAAA +SCC_Aux_Path = "\\Jeeves\VSSCODE\" +SCC_Project_Name = "$/Sdk/Standard/utils/visx2", ZNZBAAAA