Compare commits

...
491 Commits
Author SHA1 Message Date
OM cf51e14cf5 Added FPS counter 2023-05-19 20:52:10 +02:00
OM 7fb383c810 Updated README with new screenshot 2023-05-19 20:51:51 +02:00
OM 34f66963e3 Implemented DrawStatCompass 2023-05-19 19:26:46 +02:00
OM 6059063b67 Added "constant" parameter for "rgbGen" 2023-05-19 17:48:24 +02:00
OM 8bf57017ac Proper implementation of *RE_AddPolyToScene*
+ Increased *MAX_POLYS* and *MAX_POLYVERTS*
2023-05-19 17:48:09 +02:00
OM 9f1d35a11b Statbar fix
Implemented *UIFakkLabel::DrawStatbar*
2023-05-19 17:34:01 +02:00
OM aa51987077 Moved *BG_EvaluateTrajectory* from *game/bg_misc.cpp* to *cgame/cg_ents.c* 2023-05-19 17:27:38 +02:00
OM 64055d2580 Using RT_MODEL instead of ET_MODELANIM_SKEL 2023-05-19 16:59:44 +02:00
OM 45e82c590e Set numSpheresUsed to 0 2023-05-19 16:59:20 +02:00
OM 0c92890ef2 Implemented CGEN_STATIC 2023-05-19 16:59:08 +02:00
OM 03e8a64283 Added parent support in *RE_AddRefEntityToScene* 2023-05-19 16:58:46 +02:00
OM 4e14535f08 Fixed stats not drawing properly 2023-05-19 15:44:42 +02:00
OM 356e7c51fc Fixed widget alignment problem 2023-05-19 15:44:31 +02:00
OM 52a146d664 Updated README (added screenshot) 2023-05-19 14:09:03 +02:00
OM 76f107230c Exchanged SURF_NOLIGHTMAP and SURF_HINT 2023-05-19 13:57:35 +02:00
OM 4a49b15649 Removed CONTENTS_FOG
Added more surface params
2023-05-19 13:56:07 +02:00
OM 6c448694b6 Fixed static models color rendering 2023-05-19 13:40:29 +02:00
OM 34a1cee89b Made sure to unpack static models correctly 2023-05-19 13:40:18 +02:00
OM 29239dadfa Don't call ri.Hunk_Alloc when there are no texmods 2023-05-19 13:40:03 +02:00
OM e5a4574f92 Added *R_DistanceCullPointAndRadius* 2023-05-19 13:39:31 +02:00
OM 2d70547f9d Cleanup 2023-05-19 03:21:04 +02:00
OM f6279e8c17 *R_RecursiveWorldNode* now take the fog frustum into account, it also calls *R_AddPermanentMarkFragmentSurfaces* and set the vis static models 2023-05-19 03:20:50 +02:00
OM 18ade839c6 Added more shader commands
More fox support
2023-05-19 03:19:56 +02:00
OM b72eb8c6cc Using PLANE_NON_AXIAL instead of 3 2023-05-19 03:13:37 +02:00
OM e0446db81d Added one more mark function 2023-05-19 03:13:23 +02:00
OM a8bb9aaa77 Using qglFogi instead 2023-05-19 03:12:55 +02:00
OM 6595c3c673 Added sprites and ter marks to the render scene 2023-05-19 02:12:03 +02:00
OM 4ecf3195a5 Added *R_CullLocalBoxOffset* 2023-05-19 02:11:45 +02:00
OM 02f0e309e3 Implemented *R_ClearRealDlights*, *R_UploadDlights* and *R_AllocLMBlock* 2023-05-19 02:11:28 +02:00
OM 0fdfcf48f9 Added *RB_ComputeShadowVolume* (not implemented) 2023-05-19 02:10:56 +02:00
OM e9b5c7efd5 Initialize extension and level marks
Initialize the font debug string
2023-05-19 02:10:38 +02:00
OM 2a32b75815 Added GL flags 2023-05-19 02:10:19 +02:00
OM d966afe4ef Added *g_bInfoworldtris* 2023-05-19 02:10:03 +02:00
OM 92e2d42e19 Pre-added marks functions 2023-05-19 02:09:28 +02:00
OM 58e5e3fd63 Added multi-texture GL values
Don't iterate the stage if it has a skyAlpha gen near invisibility
2023-05-19 02:09:13 +02:00
OM b61c7b3988 Fog fixes 2023-05-19 02:08:32 +02:00
OM ee030f27e2 Early implementation of fog and sky portal 2023-05-19 00:29:13 +02:00
OM 02df95fc21 Updated the README file 2023-05-18 20:54:12 +02:00
OM 03100b47c1 Set the project name to openmohaa 2023-05-18 20:24:09 +02:00
OM 67444b0f15 Fixed sound being muted on startup 2023-05-18 20:21:38 +02:00
OM f6ae9a2b43 Incremented the version number 2023-05-18 20:16:19 +02:00
OM 98cd85bc9a Fixed compilation under Linux 2023-05-18 20:07:54 +02:00
OM 83a83b08f6 Export PDB of app & modules 2023-05-18 19:56:46 +02:00
OM 448e9010dc Fixed alias random indexes being wrong 2023-05-18 19:47:50 +02:00
OM ce69ed75f7 Reverted to Quake 3 sound system 2023-05-18 19:47:37 +02:00
OM 6ac70d6b7c Fixed terrain patch not drawing properly 2023-05-18 18:51:45 +02:00
OM 4f588d939d Prevent spawning a tempmodel that has the world as a tempmodel 2023-05-18 18:45:25 +02:00
OM f6ebdd1998 Better multitexture / bundle support 2023-05-18 18:17:32 +02:00
OM 7438dd709c Fixed terrain unpacking 2023-05-18 18:17:18 +02:00
OM 1207b46937 Fixed terrains vertices being wrongly rendered 2023-05-18 17:15:52 +02:00
OM 497f853171 Fixed terrain varnodes being badly loaded 2023-05-18 17:14:00 +02:00
OM 4984f8b925 nextBundle fix 2023-05-18 16:40:17 +02:00
OM a1d581df39 Introducing full LOD terrain support 2023-05-18 14:41:37 +02:00
OM 6db89a5440 Wrong dedicated condition for CL_SetFrameNumber 2023-05-18 01:40:18 +02:00
OM 4671aa9893 Replaced memset with a *for* loop 2023-05-18 01:36:13 +02:00
OM 4d66b35ba1 Added *SV_SetFrameNumber* and *CL_SetFrameNumber* so TIKI cache can get refreshed 2023-05-18 01:35:58 +02:00
OM 4b6bb674c5 Set the console name to OpenMoHAA 2023-05-18 01:13:32 +02:00
OM c9a4fc65a2 Implemented the dm box 2023-05-18 01:13:11 +02:00
OM d84b22aa5c Using boxstate_t namespace 2023-05-18 01:03:44 +02:00
OM 1f484e3e15 Implemented *UIDMConsole::KeyEnter* 2023-05-18 00:54:56 +02:00
OM 8beec0a84d Using size_t for UIFont::Print 2023-05-18 00:54:37 +02:00
OM f66475d957 Moved item_t structure to each UI*Box 2023-05-18 00:54:25 +02:00
OM 5bef94f671 Implemented UIGMBox 2023-05-18 00:54:12 +02:00
OM 08ba82bcb6 Fixed DMConsoleCommandHandler crash
Fixed UI_PrintConsole not printing to the correct box
2023-05-18 00:53:47 +02:00
OM 2c5225bce2 Removed Quake3 colors 2023-05-18 00:53:13 +02:00
OM 1e18b027a0 Fixed Listener::EventPending always returning true regardless of the event 2023-05-18 00:52:27 +02:00
OM 44b69efde5 Implemented console hiders 2023-05-17 21:51:09 +02:00
OM 78f810e943 Delete font when destroying *UIWidget*
Calling *IsDead()* instead of *BindActive* in *UIWidget::SendSignal*
2023-05-17 21:50:50 +02:00
OM 8e14620067 Fixed *UIWindowManager::getResponder* returning immediately 2023-05-17 21:49:59 +02:00
OM e3b5279f2e Added UIFloatingWindow destructor 2023-05-17 21:49:37 +02:00
OM c7bc06746c Added floatingconsole destructors
UIFloatingDMConsole is now partially implemented
2023-05-17 21:49:20 +02:00
OM d074eea927 Using AddObject instead of AddUniqueObject 2023-05-17 21:48:42 +02:00
OM cb0aab4aa2 Initialize m_clicktime to -20000 2023-05-17 19:09:49 +02:00
OM 7268d9a733 Stack overflow fix with lines 2023-05-17 19:09:25 +02:00
OM 4a2278ffc7 Small m_background_color tweak by default 2023-05-17 19:08:48 +02:00
OM e0c2329e44 Multiply by 60 always 2023-05-17 19:08:28 +02:00
OM 64934be8bc Fixed *str::str* crashing on 0-length string 2023-05-17 19:08:10 +02:00
OM d232388e2d Fixed message colors 2023-05-17 19:07:32 +02:00
OM 63c5057a45 Moved HUD_WINDOW_COLOR to UWindowColor 2023-05-17 19:07:22 +02:00
OM 407a30408d Fixed unmovable window 2023-05-17 17:38:17 +02:00
OM 0dc31e22b4 Fixed vertical scrollbar upper arrow 2023-05-17 17:38:11 +02:00
OM da89c99586 Implemented *UIConsole::AddHistory* and *UIConsole::OnSizeChanged* 2023-05-17 17:31:09 +02:00
OM 55b91adb45 Implemented the vertical scrollbar 2023-05-17 17:30:22 +02:00
OM 699f8b1b01 *UI_PrintConsole*: Fixed the console always printing after the first character 2023-05-17 17:30:07 +02:00
OM 0b14732f9e Fixed *IterateFromTail* 2023-05-17 17:29:39 +02:00
OM 2bbba486a4 Semi-console implementation 2023-05-17 15:54:51 +02:00
OM 7eeec056c8 Semi vertscroll implementation 2023-05-17 15:54:31 +02:00
OM a7a224054a Implemented UIFloatingWindow 2023-05-17 15:54:20 +02:00
OM fad9529c61 Export W_Button_Pressed 2023-05-17 15:54:06 +02:00
OM c1ae133cf1 Fixed main menu loop 2023-05-17 15:53:53 +02:00
OM cf14b84876 Using MOHAA's R_CreateImage and R_LoadImage 2023-05-17 00:25:27 +02:00
OM 3f2d62db4a Fixed no mipmaps shader, better quality for UI 2023-05-17 00:05:22 +02:00
OM 717a56c116 *CG_LandingSound*: Initialize iEffectNum to -1 2023-05-16 23:49:44 +02:00
OM 21958db630 Made static models rendering work 2023-05-16 23:35:39 +02:00
OM bba11beb39 Reset static models rendering properly 2023-05-16 23:34:50 +02:00
OM 0e33f8258a *TIKI_GetSkelAnimFrame2*: fixed radius/mins/maxes parameters being unused 2023-05-16 22:04:07 +02:00
OM 8ff70d1ceb Fixed border colors 2023-05-16 22:02:45 +02:00
OM fe0e345a8d Fixed weaponbar 2023-05-16 22:02:25 +02:00
OM 6e3b83bd3a Fixed the weapon bar not working properly 2023-05-16 20:19:25 +02:00
OM 08dfaa8e1e Motion fixes 2023-05-16 20:19:13 +02:00
OM a4e0e7b697 L_ProcessPendingEvents tweaks 2023-05-16 20:18:43 +02:00
OM 7064abc862 Added activation and mouse events for View3D 2023-05-16 19:03:10 +02:00
OM 4b449772b3 LayoutAlign fix
Return last responder in *UIWidget::FindResponder* instead
2023-05-16 19:02:46 +02:00
OM 2db3eb868a Fixed view events and active controls not working properly 2023-05-16 19:02:16 +02:00
OM 32028ccf1d Fixed UList crash 2023-05-16 19:01:57 +02:00
OM 5200e886d7 Fixed menus locking up, and menus not hiding 2023-05-16 19:01:44 +02:00
OM 73cf84506b Added *UIFloatingWindow::W_ClosePressed* and *UIFloatingWindow::W_MinimizePressed* 2023-05-16 19:01:21 +02:00
OM bad116e615 Implemented uibutton.cpp 2023-05-16 19:01:01 +02:00
OM 6dfc8b8f32 Fixed signals not working properly 2023-05-16 19:00:43 +02:00
OM 2ccd63e31a Updated keys with mohaa keys 2023-05-16 19:00:15 +02:00
OM 7b0132f2fb Fixed user eyes 2023-05-16 18:59:56 +02:00
OM d1d87edaa1 Fixed widget position 2023-05-16 16:23:13 +02:00
OM c36757be06 Fixed layout virtualres on children widgets 2023-05-16 16:22:55 +02:00
OM 6807471464 Fixed font string position 2023-05-16 16:22:42 +02:00
OM 9787c5c235 Added more shader commands 2023-05-16 14:12:47 +02:00
OM 707de8d342 Initialize tess.vertexColorValid 2023-05-16 14:12:20 +02:00
OM 57d24335cc Made cntColors as a byte instead 2023-05-16 14:11:53 +02:00
OM 27ce5af057 *RefreshMaterial*: call Rend_RefreshMaterial instead 2023-05-16 14:11:09 +02:00
OM 5a474b84c8 Fixed UI_Update not refreshing UI in main menu 2023-05-16 14:10:50 +02:00
OM 4dcd1111fb overbright bits fix 2023-05-16 14:09:18 +02:00
OM f47474bd27 *UIWidget::set2D*: Fixed Y position 2023-05-16 00:07:36 +02:00
OM fb254bf4f4 *RB_CalcColorFromConstant*: fixed bad constant color 2023-05-16 00:07:22 +02:00
OM 4ef4c86808 Operating reordering 2023-05-16 00:07:03 +02:00
OM 93d6d00b4a Implemented View3D::FrameInitialized 2023-05-16 00:06:52 +02:00
OM 77b5648094 set backEnd.in2D to qtrue instead of 1 2023-05-15 21:33:25 +02:00
OM 28b434e56d Fixed backEnd.in2D being uninitialized 2023-05-15 21:26:44 +02:00
OM b6ab949337 type fix for *CGEN_LIGHTING_GRID* 2023-05-15 21:26:33 +02:00
OM d113d292eb Renamed *GLS_SET2D* to *GLS_DEPTHTEST_DISABLE* 2023-05-15 21:26:14 +02:00
OM 8a855f37a2 Fixed *FONT_JUSTVERT_BOTTOM* 2023-05-15 21:25:51 +02:00
OM 38e46221bd it seems that *UIWidget::getClientFrame* should return a 0 position 2023-05-15 21:25:27 +02:00
OM 2c816c0846 Fixed characters being printed on the same X offset 2023-05-15 21:24:56 +02:00
OM 9abc35bc18 Fixed colors not working properly (used floats instead of bytes) 2023-05-15 20:15:06 +02:00
OM 5b141089c3 Added support for a few colorGen_t and alphaGen_t values 2023-05-15 20:14:45 +02:00
OM 7fb4de0c6c Implemented *MenuManager::ClearMenus*
Fixed *MenuManager::ForceMenu* not registering the menu in the menu stack
2023-05-15 20:13:54 +02:00
OM 52cb234142 Made SetColor work properly
Initialize m_bgfill in *UIWidgetContainer*'s constructor
2023-05-15 20:13:04 +02:00
OM c88a3f5a24 Fixed *UIWindowManager::DeactivateCurrentSmart* not working properly 2023-05-15 20:12:25 +02:00
OM f93ea7ab8d Replaced float* with vec4_t 2023-05-15 20:11:53 +02:00
OM 83a6f2a03f Implemented View3D's constructor 2023-05-15 20:11:41 +02:00
OM f4ed87b30a Fixed UI_ParseLoadMapinfo crashing 2023-05-15 20:11:23 +02:00
OM a14db185bd Initialize m_lock to false 2023-05-15 17:27:42 +02:00
OM dc96125c61 Implemented View3D::Draw2D 2023-05-15 17:27:31 +02:00
OM 2af3dee1d8 Implemented Set2DWindow 2023-05-15 17:27:05 +02:00
OM 0e1b92a5eb Fixed corrupted memory due to TIKI 2023-05-15 16:50:19 +02:00
OM 4b04bfaea2 Fixed weights being completely wrong 2023-05-15 16:49:44 +02:00
OM 1e843cfb78 Fixed DLL dbg suffix 2023-05-15 16:48:36 +02:00
OM 71548aff04 Append "-dbg" 2023-05-15 15:33:35 +02:00
OM 3f412058f7 Using HeapAlloc to test for memory corruption on WIN32 and DEBUG 2023-05-15 15:33:28 +02:00
OM a7c0a086c4 Fixed x64 windows procedure 2023-05-15 15:33:12 +02:00
OM 2af56d8a2e Fixed R_ColorShiftLightingBytes for lightmaps 2023-05-15 14:59:20 +02:00
OM e7768ce390 Fixed CG_Splash trace crash 2023-05-15 14:58:57 +02:00
OM 2b6bd8c8d2 Fixed dynamic light issues 2023-05-15 14:21:16 +02:00
OM 8ec2359d26 Fixed x64 crash 2023-05-12 00:10:27 +02:00
OM 26a7e3c25a x64 fix try 2023-05-12 00:01:26 +02:00
OM e605159f7f Removed R_InitSkins 2023-05-11 23:28:36 +02:00
OM 6198c4ceee Fixed win64 compilation errors 2023-05-11 23:18:40 +02:00
OM f020b2e8ed Added more libs to install 2023-05-11 22:48:36 +02:00
OM 21916a5ab7 Reduced compilation warnings with overrides 2023-05-11 22:48:26 +02:00
OM 7228a07e50 Fixed Linux compilation errors 2023-05-11 22:48:13 +02:00
OM 04388fe6d2 Added linux platform files 2023-05-11 22:47:34 +02:00
OM e9e43e3525 Added OpenGL install 2023-05-11 22:11:11 +02:00
OM 54c5f49918 Added docker files for compiling on different platforms 2023-05-11 20:47:08 +02:00
OM 8b73d676cb Fakk modifications 2023-05-11 18:56:40 +02:00
OM e99f9599f3 Return value fix 2023-05-11 18:46:14 +02:00
OM ecf59afd51 const param fix 2023-05-11 18:45:56 +02:00
OM d0b9890213 Added more shader stage parameters 2023-05-10 23:47:23 +02:00
OM 0f4e22947b Implemented R_DrawString 2023-05-10 23:19:08 +02:00
OM 454b5c6988 RE_RenderScene: Reset TIKI caches 2023-05-10 20:56:58 +02:00
OM cb7144bf82 Added R_VisDebug 2023-05-10 20:56:38 +02:00
OM 3c16267738 Implemented View3D::Pressed 2023-05-10 20:56:26 +02:00
OM c62185ef04 Fixed skeleton morph and weight 2023-05-10 20:39:59 +02:00
OM 3865e1a784 Fixed UI crashing on exit 2023-05-10 20:39:49 +02:00
OM 849e213d95 Dlight tweak 2023-05-10 20:29:49 +02:00
OM 1c9055b705 Added sky portal unimplemented functions 2023-05-10 20:19:12 +02:00
OM d447ec1c14 Redundantly load fix 2023-05-10 20:18:49 +02:00
OM 195ed5872a Implemented View3D::OnActivate 2023-05-10 19:34:21 +02:00
OM f985785629 CL_ShutdownCGame: don't set the key catcher 2023-05-10 19:34:09 +02:00
OM e31b284243 Using Key_SetCatcher instead of setting the variable directly 2023-05-10 19:33:50 +02:00
OM 6a3f7d89bb Fixes for UList 2023-05-10 19:33:26 +02:00
OM 537c381644 Fixed rendering crashes 2023-05-10 18:26:17 +02:00
OM 776d3fa897 Added all mohaa renderer Cvars 2023-05-10 18:21:26 +02:00
OM b4ad70dc20 Fixed server connection issue 2023-05-10 18:21:21 +02:00
OM 95c0f4fe2d Fixed renderer crash 2023-05-10 17:07:10 +02:00
OM 08cf0462dc CL_MapLoading refactor + added connectStartTime 2023-05-10 00:52:29 +02:00
OM 102e395133 Fixed loadString empty 2023-05-10 00:52:05 +02:00
OM 6c552b0cb3 Added com_dedicated check in Com_Frame 2023-05-10 00:51:32 +02:00
OM 929cb3eb79 JPEG-6 fix 2023-05-10 00:51:18 +02:00
OM e1f391fa4b made tr.images statically allocated 2023-05-10 00:00:40 +02:00
OM eddd56f770 R_FindShader fix 2023-05-09 23:47:26 +02:00
OM 0fad7c1ad6 Ubertools modifications 2023-05-09 22:54:13 +02:00
OM 797ae47b46 Renderer fixes 2023-05-09 21:58:24 +02:00
OM 5b89e25e9b Fixed null spawnthing crash 2023-05-09 21:21:16 +02:00
OM 048c555973 TIKI crash fix 2023-05-09 21:21:11 +02:00
OM 4824f8a3b3 MOHAA BSP implementation 2023-05-09 20:49:04 +02:00
OM 082465ac98 Fixed infinite loop issue 2023-05-09 20:08:35 +02:00
OM 15a00c0792 Fixed some functions not matched
Initialize terrain marks
2023-05-09 20:08:28 +02:00
OM a01cf19c47 Fixed some functions not matched 2023-05-09 20:08:06 +02:00
OM 86cfa42f2c ri.Hunk_Alloc: use CL_RefStaticMalloc instead 2023-05-09 20:07:40 +02:00
OM 8a821b51bd Fixed usereyes uninitialized 2023-05-09 20:07:17 +02:00
OM 79baec1625 Initialize localization 2023-05-09 20:06:56 +02:00
OM f43930db63 Updated README 2023-05-09 20:03:34 +02:00
L c93faed19a Pre-added renderer files 2023-05-09 19:18:16 +02:00
L 0d7b822216 Implemented R_LoadFont 2023-05-09 19:13:37 +02:00
L e268c47e16 Fixed title name 2023-05-09 17:51:44 +02:00
L 521af45611 Fixed all errors (now compile & link) 2023-05-09 17:50:29 +02:00
L b96afa380c Fixed NET_Init called twice 2023-05-08 23:41:06 +02:00
L 10d73cd784 Allow WITH_CLIENT 2023-05-08 23:36:41 +02:00
L 50a2578a49 Fixed unix build compilation 2023-05-08 23:34:24 +02:00
L c7f877c8b4 Added Quake III arena unix/win32 folders 2023-05-08 22:58:54 +02:00
L 8451cff91e Compilation fixes 2023-05-08 20:07:45 +02:00
L e2910930da Readded ioq3 renderer 2023-05-08 19:53:53 +02:00
L 410fa7ac15 Moved restuff 2023-05-08 17:42:54 +02:00
L 8908890d72 Quick compilation fixes (still linker errors) 2023-05-08 14:59:08 +02:00
L 53c1c94dac Using Quake 3 renderer 2023-05-08 14:33:37 +02:00
L 5a87b21efc Fixed all compilation errors 2023-05-08 00:02:31 +02:00
L 26944dcf4a Fixed renderer compile errors 2023-05-07 22:19:54 +02:00
L f68b402d24 Other fixes 2023-05-07 21:32:30 +02:00
L 72f090b289 Fixed openmohaa.exe compilation (only 102 linker errors) 2023-05-07 21:28:54 +02:00
L 7030c23994 Fixed compilation issues 2023-05-07 20:38:08 +02:00
L 4ce1bb71e4 Implemented CG_AddBulletTracers and added other functions 2023-05-07 19:46:10 +02:00
L f30b1cb409 Implemented all 2D functions 2023-05-07 19:37:56 +02:00
L 6c3a4e7a18 const char* param fix 2023-05-07 19:36:53 +02:00
L 50fe18d41f Renamed beam flags 2023-05-07 19:36:45 +02:00
L 9f879d978d Fixed beam flags 2023-05-07 17:58:41 +02:00
L d805881721 Added more beams features 2023-05-07 17:45:07 +02:00
L 2f2a4d0ad6 Fixed rain float values 2023-05-07 17:45:01 +02:00
L b5bcd68038 Added CG_Rain implementation 2023-05-07 16:50:59 +02:00
L 1a44bd8fec Added cg_vehicle.cpp and moved stub treads code 2023-05-07 16:50:32 +02:00
L f2714340e7 Various FX fixes like color and spawning 2023-05-07 15:32:10 +02:00
L 16a007e214 Fixed crashes 2023-05-07 15:21:58 +02:00
L c463974c15 Fixed scores not showing properly 2023-05-07 14:49:16 +02:00
L 422d16e8eb Crash fixes 2023-05-07 14:45:23 +02:00
L 288b208921 Added a way to debug memory allocations 2023-05-07 14:43:30 +02:00
L 830ed4957b Implemented scoreboard 2023-05-07 14:43:07 +02:00
L 7cea7392a4 Implemented all commands 2023-05-06 23:37:05 +02:00
L 77ebd44d19 Implemented specialeffect_t::AddNewCommand 2023-05-06 23:36:57 +02:00
L 3f84bdf285 Using beam linked list 2023-05-06 23:07:04 +02:00
L 8d4d9fec39 More flags 2023-05-06 23:06:53 +02:00
L 18981a9f29 tweaks 2023-05-06 23:06:41 +02:00
L 68edccef05 Fixed const char* param 2023-05-06 23:06:32 +02:00
L ecd2c0a742 Implemented more basic methods 2023-05-06 21:12:13 +02:00
L 7975ae0353 Added some flags 2023-05-06 21:10:23 +02:00
L 9fadfb3577 Added more T2 flags
Implemented few basic methods
2023-05-06 20:54:14 +02:00
L 88a9d4a076 Implemented VSS_SourcePhysics 2023-05-06 20:31:58 +02:00
L 2e06403b17 Added MASK_VOLUMETRIC_SMOKE 2023-05-06 20:31:46 +02:00
L a7db332547 Added CG_ClipMoveToEntities declaration 2023-05-06 20:31:37 +02:00
L 845c725b9a Implemented CG_GetShaderUnderCrosshair 2023-05-06 19:16:35 +02:00
L 99f886f350 Implemented UI commands 2023-05-06 19:10:28 +02:00
L 59fad24126 Implemented CG_GetCHShader and CG_EditCHShader 2023-05-06 19:10:06 +02:00
L 0a94d50c4f CG_ParseServerinfo: set cvars and show huds depending on the game type 2023-05-06 18:48:32 +02:00
L ec5cba6188 Added more commands 2023-05-06 18:48:05 +02:00
L 03d72d4240 Fixed viewkick 2023-05-06 17:50:41 +02:00
L 3e6afaf509 Implemented DeleteEmitters, LandingSound, BodyFallSound, GetTagPositionAndOrientation, CG_ProcessInitCommands, and CG_ProcessCacheInitCommands 2023-05-06 17:27:25 +02:00
L 0885ee5227 Added CG_BodyFallSound (unimplemented) 2023-05-06 17:26:28 +02:00
L b327ff5159 Added EffectsEventQueueNode
Implemented ProcessPendingEventsForEntity, PostEventForEntity, Footstep, and SelectProcessEvent
2023-05-06 17:02:40 +02:00
L 6fd62d4ad9 Added EffectsEventQueueNode 2023-05-06 17:01:55 +02:00
L d10034b9ce tweak 2023-05-06 17:01:44 +02:00
L 1c21143f07 CG_Footstep param fix 2023-05-06 17:01:28 +02:00
L b6dfd7db06 Implemented viewkick 2023-05-06 16:15:28 +02:00
L a5c596f928 Implemented almost everything in this file except VSS_SourcePhysics 2023-05-06 15:47:25 +02:00
L d2d658c42f Added RandomizeRange 2023-05-06 15:47:00 +02:00
L 4925c20b71 tweaks 2023-05-06 15:46:51 +02:00
L 6f352b10c2 Added missing VSS functions 2023-05-06 12:06:23 +02:00
L ee5f9281ea Fixed CG_General tiki 2023-05-06 12:06:12 +02:00
L 8bc6499944 Added events 2023-05-05 23:43:27 +02:00
L 237d2962d0 Added BeginTagSpawnLinked 2023-05-05 23:43:19 +02:00
L c649d27f75 Added stubs and unimplemented methods/functions 2023-05-05 22:58:34 +02:00
L 20237c0aa3 Implemented ClientSpecialEffectsManager::LoadEffects 2023-05-05 21:12:09 +02:00
L 61eacd739b fixes 2023-05-05 21:11:57 +02:00
L d459191f01 Implemented SetCurrentSFX and ClearCurrentSFX 2023-05-05 21:11:48 +02:00
L e28ea74549 Implemented ClientSpecialEffectsManager::ExecuteEffect and ClientSpecialEffectsManager::MakeEffect_Normal 2023-05-05 20:43:57 +02:00
L 026c1264fe Added pEvent member 2023-05-05 20:43:37 +02:00
L 5b85ab4dc6 Implemented CG_MakeExplosionEffect and CG_MakeVehicleEffect 2023-05-05 20:43:23 +02:00
L c2a266c845 Added 2023-05-05 20:43:00 +02:00
L 031b575955 fix 2023-05-05 20:36:41 +02:00
L 278e84580e Fixed negative bobbing 2023-05-05 00:00:56 +02:00
L d697a93a73 Implemented CG_LandingSound 2023-05-04 23:45:01 +02:00
L be89c1fa1f Implemented CG_FootstepMain and CG_MeleeImpact 2023-05-04 23:27:00 +02:00
L c6b832294c Fixed CG_ParseCGMessage 2023-05-04 23:26:17 +02:00
L 791881338b Fixed left footsteps 2023-05-04 23:26:01 +02:00
L e2fb54781e Added running/equipment anim flags 2023-05-04 23:25:24 +02:00
L 98236d5662 Implemented CG_ClipMoveToEntities 2023-05-04 23:25:05 +02:00
L d8cfe96b0f Implemented CG_MakeBulletTracer 2023-05-04 21:07:44 +02:00
L f84b61a94d Fixed temp model crashes 2023-05-04 21:07:33 +02:00
L ead4cfc94e Implemented ClientGameCommandManager::PlaySound 2023-05-04 20:51:24 +02:00
L f0a2a28650 Implemented CG_ParseCGMessage 2023-05-04 20:30:52 +02:00
L c3fcb5f8c5 Fixed missing structs 2023-05-04 20:30:38 +02:00
L f1b745ea9c Added CG_MeleeImpact 2023-05-04 20:30:25 +02:00
L f505142244 Fixed vec3_t *origin parameter for PlaySound 2023-05-04 20:30:02 +02:00
L 1b0bc7c104 Added bullet tracers 2023-05-04 20:29:43 +02:00
L 6fbf496a02 Fixed cg_t struct for ta 2023-05-04 20:29:37 +02:00
L 79f5d11415 Renamed ida.h to ida_aa.h 2023-05-04 18:50:27 +02:00
L f8395b6264 Fixed lightingOrigin 2023-05-03 23:27:20 +02:00
L 031952374a Fixed arms angles when looking up 2023-05-03 23:09:47 +02:00
L 221de56d95 Fixed pos offset and crouch 2023-05-03 23:09:34 +02:00
L a469c448de Added explanation 2023-05-03 21:31:34 +02:00
L 110e60e3dd Fixed SetTime parameter (should be an int) in clientGameImport_t 2023-05-03 21:20:50 +02:00
L 59cd7d5116 Predict pmove enhancements 2023-05-03 21:20:32 +02:00
L bb59e3c3f2 tweaks 2023-05-03 21:19:59 +02:00
L ac7ec18a37 Fixed interpolation issue 2023-05-03 20:53:33 +02:00
L ca34d8de85 CG_ProcessSnapshots for different server 2023-05-03 20:53:20 +02:00
L 8ab663d5d8 Implemented PmoveAdjustAngleSettings_Client 2023-05-03 20:53:04 +02:00
L 670de51637 Fixed bad animations 2023-05-03 20:10:52 +02:00
L 5eba2f5662 Fixed Anim_CrossblendTime return value 2023-05-03 20:03:55 +02:00
L 863a730271 Using vmAnim_e enum 2023-05-03 19:38:24 +02:00
L 0fc3ecf67e CG_OffsetFirstPersonView: fixed height delta applied incorrectly 2023-05-03 19:32:19 +02:00
L 864986ae9a Fixed view model anim not rendering 2023-05-03 19:31:52 +02:00
L 0e597e8bf7 Fixed CG_AddPacketEntities for parent/children entities 2023-05-03 19:31:37 +02:00
L 860b660f61 Added vmAnim_e 2023-05-03 19:31:09 +02:00
L 0058f255e6 Implemented CG_CalcViewModelMovement 2023-05-02 23:29:41 +02:00
L fc1392dfd6 Implemented CG_OffsetFirstPersonView (mostly) 2023-05-02 23:03:23 +02:00
L 6e53b67310 Added more fcomp flags 2023-05-02 22:51:21 +02:00
L a6aea380fe Added MASK_VIEWSOLID 2023-05-02 22:51:08 +02:00
L 0a46fa69b9 Tweaks 2023-05-02 22:50:58 +02:00
L c2c4cd07e0 CG_AttachEntity: fixed attach_offset and lightingOrigin 2023-05-02 20:24:24 +02:00
L bfb6416cfa ClientGameCommandManager::PlaySound: fixed crash when alias_list is NULL 2023-05-02 20:13:48 +02:00
L 377a979fa8 Added view model animation prefixes
Implemented CG_GetVMAnimPrefixIndex and CG_ViewModelAnimation
2023-05-02 20:13:29 +02:00
L 8cf2dffb79 CG_OffsetFirstPersonView: removed assertion 2023-05-02 20:04:35 +02:00
L 66f153d087 Fields fixes 2023-05-02 20:03:58 +02:00
L d7a594c124 Implemented CG_ModelAnim 2023-05-02 20:03:45 +02:00
L 830caf2c2c Moved WEAPON_CLASS definitions to bg_public.h 2023-05-02 20:03:28 +02:00
L 28190c6649 CG_ProcessEntityCommands return boolean
CG_ClientCommands stub
2023-05-02 20:03:15 +02:00
L 125095d52e Implemented CG_Footstep 2023-05-01 20:31:51 +02:00
L f00d992755 TIKI_Orientation tweak 2023-05-01 20:31:38 +02:00
L e86ece9da1 Updated README 2023-05-01 20:08:26 +02:00
L 7dd3d9a0bf Commented client compilation out (except cgame) 2023-05-01 19:57:13 +02:00
L 213696bdfc CG_ModelAnim partial implementation 2023-05-01 19:56:43 +02:00
L b64e597d53 refEntity_t struct fix 2023-05-01 19:56:28 +02:00
L 186344d8de Added TAF_AUTOFOOTSTEPS 2023-05-01 19:26:03 +02:00
L 42e0be0f78 Added viewmodel stub functions 2023-05-01 19:25:52 +02:00
L 388d3bef62 Unused CG_Footstep 2023-05-01 19:22:05 +02:00
L 7757f3a3c4 Stub CG_Footstep
Stub CG_LandingSound
2023-05-01 19:21:44 +02:00
L cab948d988 Added CG_OffsetFirstPersonView declaration 2023-05-01 19:21:24 +02:00
L 4852182aa0 Added parentEntityNumber to R_AddRefEntityToScene
Added ET_MODELANIM_SKEL in CG_AddCEntity
2023-05-01 17:28:48 +02:00
L 434aba95eb Added parentEntityNumber to R_AddRefEntityToScene 2023-05-01 17:28:14 +02:00
L 0a5ca66a64 Added VSS vars initialization 2023-05-01 17:08:32 +02:00
L 533356be0f Added more test emitter variables 2023-05-01 17:08:17 +02:00
L 4cc0149073 Added sfxManager extern variable 2023-05-01 17:08:02 +02:00
L d28f117979 Fixed differentServer check 2023-05-01 17:07:51 +02:00
L c14d13007c Raised MAX_ENTITIES_IN_SNAPSHOT to 1024 2023-05-01 17:06:39 +02:00
L df8a12664c Added rain initialization 2023-05-01 17:06:27 +02:00
L ca79cf659b Added more cvars and initialization 2023-05-01 17:06:15 +02:00
L 86034d5a98 Fixes 2023-05-01 17:05:51 +02:00
L 8f4258716f Added VSS sources related methods 2023-05-01 15:49:45 +02:00
L 3be28b528a Added specialeffect_t and specialeffectcommand_t constructors
Implemented CG_InitializeSpecialEffectsManager, ContinueEffectExecution and MakeEffect_* methods
2023-05-01 15:40:39 +02:00
L e3dd8c46de Added specialeffect_t and specialeffectcommand_t constructors 2023-05-01 15:39:53 +02:00
L 72f9f20b53 Added clientNum in cg_t
Added vss extern variables
Added a declarations for scoreboard, specialfx, ui, volumetric smoke, console cmds and cg_marks
2023-05-01 15:16:04 +02:00
L bb33f7fbcd Moved MAX_HUDDRAW_ELEMENTS to q_shared.h 2023-05-01 15:15:13 +02:00
L 1ed03b0716 Using LISTENER_Cvar_Get macro 2023-05-01 15:15:01 +02:00
L ec4c8458f0 Added MAX_RES_NAME 2023-05-01 15:14:50 +02:00
L 4480b5815e Added VSS variables
Added CG_AddVSSSources stub
2023-05-01 15:14:39 +02:00
L 5709800f1a Implemented CG_Eye* 2023-05-01 15:14:17 +02:00
L a11b2ec07b Implemented CG_HudPrint_f 2023-05-01 15:14:05 +02:00
L 5220a7c2f7 Implemented CG_ParseStats, CG_Stopwatch_f, CG_ServerLag_f
Added MOH:AA server commands in CG_ServerCommand
2023-05-01 15:13:50 +02:00
L 99d6d3dc7a Added CG_PrepScoreBoardInfo and implemented some scoreboard functions 2023-05-01 15:13:20 +02:00
L 914e036fe2 Added clientNum parameter to CG_Init 2023-05-01 15:12:57 +02:00
L c87cce4091 Added more cvars
CG_Init fixes
Added more CG_Shutdown logic
2023-05-01 15:12:42 +02:00
L 161c5f9b84 Implemented CG_RefreshHudDrawElements
Added more stubs
2023-05-01 15:12:01 +02:00
L cc28cbb012 Added scores functions
Implemented all weapon commands
2023-05-01 15:11:39 +02:00
L 5aa9b21d2f Removed RestartAllEmitters
Added CG_DeleteEmitters
2023-05-01 15:11:08 +02:00
L d56097ed06 Compiler warning fix 2023-05-01 15:10:46 +02:00
L e1da479646 More stubs 2023-05-01 15:10:26 +02:00
L 95138d4c5b Added ClientSpecialEffectsManager 2023-05-01 15:10:17 +02:00
L 6a03d7978d fixes 2023-05-01 15:10:02 +02:00
L c5235a340b Error fix 2023-05-01 00:25:22 +02:00
L d1348de690 indentation 2023-05-01 00:25:08 +02:00
L 1d28e9f4f3 Added all client game exports 2023-05-01 00:17:30 +02:00
L 5580ecacf9 Added declarations for function stubs 2023-05-01 00:11:10 +02:00
L c69270e50a CG_Beam: using float color instead of byte 2023-05-01 00:10:59 +02:00
L d98703234b Added command stubs 2023-05-01 00:10:41 +02:00
L 493d11d404 Added CG_Eye* function stubs 2023-05-01 00:10:23 +02:00
L f78c2b826c Impact marks and commands modifications 2023-05-01 00:10:07 +02:00
L dbe8428789 Added scoreboard functions stub 2023-05-01 00:09:27 +02:00
L ecf0157dba CG_GetColumnName return const char* 2023-05-01 00:09:16 +02:00
L eebeaafd9d Added cg_marks.c function stubs 2023-05-01 00:08:56 +02:00
L 1dbfe29970 CG_ParseCGMessage() stub 2023-05-01 00:08:43 +02:00
L 769fb56285 Added cg_ui.cpp stub 2023-05-01 00:08:23 +02:00
L 39623d910b FS_ReadFile doesn't take a quiet parameter on client 2023-04-30 23:30:26 +02:00
L 0e0c9a9b37 Added more imports
Fixed FS_ReadFile not taking quiet parameter
2023-04-30 23:30:00 +02:00
L d8cffd6adf Added GetCGameAPI export 2023-04-30 23:29:21 +02:00
L 990f820333 Replaced keyNum_t with int for CG_CheckCaptureKey 2023-04-30 23:28:01 +02:00
L 9f70dc9ef8 Only compile cgame module 2023-04-30 20:37:50 +02:00
L 8851a005b0 Removed entNum parameter in TIKI_Name inside clientGameImport_t 2023-04-30 20:37:35 +02:00
L ed24b4b95a Removed the use of CG_AdjustPositionForMover
Fixed CG_PredictPlayerState interpolation
2023-04-30 20:37:17 +02:00
L fb0cea2056 Added CG_InitializeSpecialEffectsManager declaration 2023-04-30 20:36:51 +02:00
L 385c7bd904 Removed the use of CG_Item 2023-04-30 20:36:40 +02:00
L 7e0147d842 Fixed compilation issues with CGAME_DLL 2023-04-30 20:36:22 +02:00
L e49bb9af31 Compilation error fixes 2023-04-30 20:20:58 +02:00
L 7daa98c9fa Constant string fix 2023-04-30 20:20:45 +02:00
L 144c3b3c75 Replaced tikihandle with dtiki_t 2023-04-30 20:20:36 +02:00
L 5a9852c292 Fixed wrong offsets for ClientGameCommandManager 2023-04-30 17:39:03 +02:00
L d3e3446781 Added cg_specialfx.h header file 2023-04-30 17:22:57 +02:00
L ed770e53e1 Fixed CG_CreateBeam color 2023-04-30 17:22:49 +02:00
L 9ec34ad19d stub test emitter 2023-04-30 17:03:26 +02:00
L 1cd8a3e0fc Fixed surface type mask 2023-04-30 16:58:55 +02:00
L 97f400564a Using dtiki_t* rather than tiki handle 2023-04-30 16:58:44 +02:00
L e73bda2161 Added ida_cgame_aa.h for CGame module 2023-04-30 16:33:54 +02:00
L 19ea1ac76f Fixed TIKI_Name parameter 2023-04-30 16:33:17 +02:00
L ce53e2c57d Removed CGAME_DLL checks 2023-04-30 14:54:23 +02:00
L 9df167cea1 Added MASK_SURF_TYPE 2023-04-30 14:53:35 +02:00
L 6b8ffca431 CG_OffsetFirstPersonView: stub function
Removed CG_InterpolateView
CG_CalcViewValues implementation, todo damage angles and viewkick
CG_DrawActiveFrame: Added frameTime, removed info screen text check
2023-04-30 14:53:19 +02:00
L 835f60f00b Using TIKI_Orientation instead of Tag_LerpedOrientation
Fixed current_tiki check
2023-04-30 14:52:12 +02:00
L 42171cc799 Added CG_InitializeSpecialEffectsManager 2023-04-30 14:51:44 +02:00
L dda56346bc CG_ResetEntity: reset frameinfos as well as foot on ground
Using PMF_RESPAWNED instead of PMF_TIME_TELEPORT
CG_SetNextSnap: server time restart fix
2023-04-30 14:51:23 +02:00
L 0745c42af9 Using const char* instead of char* for names
Added *frameTime* integer parameter to CG_DrawActiveFrame
2023-04-30 14:50:11 +02:00
L 1e876faffc CG_ResetPlayerEntity: removed camera stuff 2023-04-30 14:49:35 +02:00
L 8bd7acd1da Renamed CG_InitMarkPolys to CG_InitMarks 2023-04-30 14:49:13 +02:00
L 12a53f36cc CG_ProcessConfigString: Process rain and tiki
CG_PrepRefresh: Avoid clearing scene, and added more shaders
CG_GameStateReceived: Initialize special effects manager and objectives
CG_ServerRestarted: Reset VSS sources and objectives
2023-04-30 14:48:55 +02:00
L 4b9894b2bc Removed CG_Item as it's not used anymore 2023-04-30 14:47:43 +02:00
L 4b020c54ee Added stub functions 2023-04-30 14:47:27 +02:00
L 672d9fc4a2 Replaced tikihandle with dtiki_t* 2023-04-30 14:47:18 +02:00
L 9a9b20276e CG_CreateModelBeam: using cgi.R_Model_GetHandle 2023-04-30 14:46:56 +02:00
L f73419ca8d Modified cg_t and cgs_t to add MOH:AA fields
Added shaders and fonts in media_t
Added cobjective_t and crain_t
Renamed CG_InitMarkPolys to CG_InitMarks
Added CG_ResetVSSSources
2023-04-30 14:46:24 +02:00
L b113a4c38c Added stub MOH:AA source files 2023-04-30 14:15:14 +02:00
L d811a58297 Rearrangement + ability to compile cgame + client (doesn't compile currently) 2023-04-30 01:45:26 +02:00
L 79d8b91977 Fixed re issue 2023-04-30 01:44:53 +02:00
L abfb82f340 Multiple compilation errors fixes #1 2023-04-30 01:42:57 +02:00
L c3e027c54f Fixed GAME_DLL issue with entity 2023-04-30 01:42:36 +02:00
L 67322b2665 Moved *surfaceflags.h* to *../qcommon/surfaceflags.h* 2023-04-30 01:42:22 +02:00
L 423112b2fd Removed ET_SPRITE 2023-04-30 01:10:05 +02:00
L d48f252bb0 Include tiki.h 2023-04-30 01:09:57 +02:00
L 054d833dd6 Added SlerpQuaternion 2023-04-30 01:09:45 +02:00
L 45b8178295 Include TIKI 2023-04-30 00:05:21 +02:00
L 1cf4076be1 Added MAX_HUDDRAW_ELEMENTS 2023-04-30 00:05:07 +02:00
L 6e59e30f17 Only declare functions when compiling the APP module 2023-04-30 00:04:55 +02:00
L 353ed34a71 Fixed errors with Container<> 2023-04-30 00:04:23 +02:00
L 6e0ce3f0e4 Moved a few structs to *code/cgame/tr_types.h* 2023-04-30 00:04:12 +02:00
L dc6d3ca5c6 Restored hdelement_t and clientAnim_t 2023-04-30 00:03:37 +02:00
L 5b5fb1c4d6 Removed CGAME_DLL check 2023-04-30 00:03:11 +02:00
L 29f328abf0 Added Ubertools CGAME module 2023-04-30 00:02:16 +02:00
L fbd03b6a26 Debloated g_local.h include files 2023-04-29 21:56:38 +02:00
L f5a58decf5 MSG_PackCoord: forgot int cast 2023-02-08 14:48:26 +01:00
L 595958d578 MSG_PackCoord: use rounded coordinate 2023-02-08 14:47:57 +01:00
L 034ceb2a99 Updated README 2023-02-08 14:26:12 +01:00
L 59b113b2dc Updated C version requirements (C99 required)
Added libraries for older compilers
2023-02-08 14:26:01 +01:00
L 4239d215b8 Updated README 2023-02-08 14:07:26 +01:00
L d5d5274b6f Fixed generation issue with CMake 3.5.2 2023-02-08 14:04:47 +01:00
L 6f325cb294 Useless comments removed 2023-02-08 13:56:20 +01:00
L a07a7359b6 Changed default hostname (so openmohaa can be recognized) 2023-02-07 21:23:27 +01:00
L 89983b1508 Updated README 2023-02-07 21:20:15 +01:00
L 31bd29b92b Project can now be compiled using CMake 3.5 2023-02-07 21:18:17 +01:00
L db7e785734 Fixed size_t length comparison with number below 0 2023-02-07 21:17:48 +01:00
L d40d4e8d79 Updated README 2023-02-07 20:55:55 +01:00
L bf02aee57d Reduced C++ standard requirement down to C++11
Requires pthreads in *NIX (because of gamespy)
Using CMake 3.12 instead (required because of *add_compile_definitions* command)
2023-02-07 20:52:08 +01:00
L f91d5f9fe9 Added support for ScriptVariable move 2023-02-07 20:50:26 +01:00
L 1296918abe Removed usage of *constexpr* in storeTop/loadTop (using separate methods instead) 2023-02-07 20:50:09 +01:00
L f9e7f344be Reduced compile warnings (especially on clang) 2023-02-07 20:49:31 +01:00
L de40d640d5 Set minimum cmake version to 3.5 2023-02-07 19:38:31 +01:00
L 6eb1ec3cf5 Fixed compilation issues with g++ 2023-02-06 19:24:01 +01:00
L d4e366ee14 Using sizeof(type[x]) instead of sizeof(type) * x 2023-02-05 22:18:20 +01:00
L ca25bb983f Removed unused methods 2023-02-05 22:17:54 +01:00
L 9c62ece9bd Fixed classinfo being NULL for the *Game* class 2023-02-05 21:12:51 +01:00
L 84c7acfeed Added _DEBUG compiler macro for Debug configuration 2023-02-05 21:11:37 +01:00
L 319e3baa78 Fixed endianness in SkeletorCacheFileCallback 2023-02-05 20:11:28 +01:00
L d496c0b14d Added .gitignore 2023-02-05 14:33:53 +01:00
L b9bab148ee Added "-dbg" suffix for debug builds 2023-02-05 14:15:24 +01:00
L cba4af3d65 Using latest ioq3 win_resource.rc with win_manifest.xml usage 2023-02-05 14:02:38 +01:00
L 22bcbaeebe Set embed manifest to false on WIN32 with MSVC 2023-02-05 14:02:18 +01:00
smallmodel d8c59163fa Merge pull request #37 from DraGo0oN/patch
Fixed omohaaded binary icon for windows
2023-02-05 13:59:24 +01:00
DraGoN 7e60d9c422 Fixed omohaaded binary icon for windows 2023-02-05 14:54:04 +02:00
L 0d2eb7f693 Added OPM header 2023-02-05 13:27:22 +01:00
L 35b767402b Indent 2023-02-05 13:27:12 +01:00
L 85e481d3cd Added win_manifest.xml from ioquake3 2023-02-05 11:00:09 +01:00
L 29061bea50 Fixed send_heartbeat sending to the wrong address 2023-02-05 02:08:47 +01:00
L 5fecffc451 Fixed wrong client ping value in gamespy players callback 2023-02-05 01:58:52 +01:00
L 4fc3054c0d Renamed LAYOUT.txt to LAYOUT.md (Markdown) 2023-02-05 01:54:57 +01:00
L a08b6b9c3e Updated LAYOUT.txt 2023-02-05 01:50:46 +01:00
L 7f7faea586 Added support for GameSpy heartbeat 2023-02-05 01:41:56 +01:00
L 64520b9073 Added GameSpy initialization and shutdown 2023-02-05 01:41:45 +01:00
L 92f58d2144 Added GameSpy function declaration 2023-02-05 01:41:31 +01:00
L bdc3de775a Added TARGET_GAME_NAME definition for GameSpy 2023-02-05 01:40:35 +01:00
L 8ec6fcd9fe Added old qr gamespy implementation 2023-02-05 01:40:14 +01:00
L cfc40a401a Added qr_t def 2023-02-05 01:39:50 +01:00
L 296e0c271b Fixed gamespy compilation error on unix 2023-02-05 01:38:42 +01:00
L 7f5fcd410e Added gamespy SDK to the build 2023-02-04 21:00:31 +01:00
L dd44f78fc5 Added gamespy SDK 2023-02-04 21:00:01 +01:00
L 294ca5ffd2 indent 2023-02-04 19:56:06 +01:00
L 2763cfbd46 Merge branch 'master' of github.com:openmoh/openmohaa 2023-02-04 18:41:17 +01:00
L a015c2f9e1 Removed unused files 2023-02-04 18:40:57 +01:00
smallmodel 7976de03db Merge pull request #35 from DraGo0oN/patch-1
Fixed gamearm binary name for arm64
2023-02-04 11:56:01 +01:00
DraGoN 04b64f6518 Fixed gamearm binary name for arm64 2023-02-04 00:48:37 +02:00
L 365615e62c Added aarch64 platform 2023-02-03 22:33:57 +01:00
L 0d791b0d23 Added s390x in TargetArch 2023-02-03 22:33:48 +01:00
L 637de9d278 Fixed const warning for Copy*Swap 2023-02-03 22:01:32 +01:00
L 1ac9f79595 Fixed gamex64 binary name (now gamex86_64 even on Windows) 2023-02-03 21:26:12 +01:00
L a8ed9948d8 Fixed compilation issues on big-endian targets 2023-02-03 21:13:13 +01:00
L 5852ef095a removed CXX_STANDARD
Added "code/parser" as private include for fgame
2023-02-03 20:26:27 +01:00
L a361546fc7 playerstart.h rename 2023-02-03 20:22:22 +01:00
L 6e7d80071c playerstart.h rename 2023-02-03 20:22:12 +01:00
L 50a1f0728b Added dl libs for Unix 2023-02-03 20:05:34 +01:00
L 5cdc8e6ec0 Removed ./ui (useless) 2023-02-03 19:59:12 +01:00
L 22fccb381a Updated README 2023-02-03 19:03:33 +01:00
1209 changed files with 333627 additions and 978328 deletions

No files matched your search

+46
View File
@@ -0,0 +1,46 @@
build
Makefile.local
*.swp
*tags
*~
# OS X
####################
.Spotlight-V100/
.Trashes/
._*
.AppleDouble
.DS_Store
.LSOverride
Icon?
make-macosx-values.local
# Xcode
####################
*.mode1v3
*.mode2v3
*.pbxuser
*.perspectivev3
*.user
*.xcuserstate
*.moved-aside
*~.nib
.idea/
DerivedData/
project.xcworkspace/
xcuserdata/
profile
!default.pbxuser
!default.mode1v3
!default.mode2v3
!default.perspectivev3
# Microsoft Visual Studio
####################
*.sdf
*.opensdf
*.suo
.vs
out
code_unfinished/*
+177 -54
View File
@@ -1,5 +1,5 @@
cmake_minimum_required(VERSION 3.10)
project(omohaaded)
cmake_minimum_required(VERSION 3.5)
project(openmohaa)
include(TargetArch.cmake)
@@ -24,7 +24,7 @@ endif()
set(TARGET_BASE_GAME "main${TARGET_BASE_SUFFIX}")
if(MSVC)
add_compile_definitions(_CRT_SECURE_NO_WARNINGS _CRT_NONSTDC_NO_DEPRECATE)
add_definitions(-D_CRT_SECURE_NO_WARNINGS -D_CRT_NONSTDC_NO_DEPRECATE)
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
add_compile_options(-Wno-comment)
# Ignore warnings for code like 'assert("Assert string")'
@@ -32,9 +32,11 @@ elseif(CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
endif()
IF("${TARGET_ARCH}" STREQUAL "x86_64")
set(TARGET_ARCH_SUFFIX "x64")
set(TARGET_ARCH_SUFFIX "x86_64")
ELSEIF("${TARGET_ARCH}" STREQUAL "i386")
set(TARGET_ARCH_SUFFIX "x86")
ELSEIF("${TARGET_ARCH}" STREQUAL "arm64")
set(TARGET_ARCH_SUFFIX "arm64")
ELSEIF("${TARGET_ARCH}" MATCHES "arm(.*)")
set(TARGET_ARCH_SUFFIX "arm")
ELSE()
@@ -53,6 +55,17 @@ ELSE()
set(TARGET_PLATFORM_PREFIX "")
ENDIF()
IF(CMAKE_BUILD_TYPE MATCHES Debug)
set(TARGET_CONFIG_SUFFIX "-dbg")
add_definitions(-D_DEBUG)
ELSE()
set(TARGET_CONFIG_SUFFIX "")
ENDIF()
# Common stuff
## For modules
set(SOURCES_SHARED
"code/qcommon/class.cpp"
"code/qcommon/con_set.cpp"
@@ -69,45 +82,48 @@ set(SOURCES_SHARED
"code/script/scriptvariable.cpp"
)
# Shared libraries
file(GLOB_RECURSE SOURCES_BG "code/game/bg_*.cpp")
## Server game library
file(GLOB_RECURSE SOURCES_GAME "code/game/*.c" "code/game/*.cpp" "code/parser/*.cpp" "code/script/*.cpp")
set(SOURCES_GAME_LIB ${SOURCES_SHARED} ${SOURCES_GAME})
add_library(fgame SHARED ${SOURCES_GAME_LIB})
target_compile_definitions(fgame PRIVATE GAME_DLL ARCHIVE_SUPPORTED TARGET_GAME_TYPE=${TARGET_GAME_TYPE})
target_include_directories(fgame PUBLIC "code/qcommon" "code/parser" "code/script" "code/game")
target_compile_features(fgame PUBLIC cxx_std_17)
set_property(TARGET fgame PROPERTY CXX_STANDARD 17)
set_target_properties(fgame PROPERTIES PREFIX "${TARGET_PLATFORM_PREFIX}")
set_target_properties(fgame PROPERTIES OUTPUT_NAME "game${TARGET_ARCH_SUFFIX}")
set_target_properties(fgame PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${TARGET_BASE_GAME}")
INSTALL(TARGETS fgame DESTINATION "${TARGET_BASE_GAME}")
## Client game library
## TODO! Build the cgame shared library
# Applications
## Code for all executables
## For executable
### Platform-specific code
if(WIN32)
set(SOURCES_PLATFORM_SPECIFIC
"code/sys/con_win32.c"
"code/sys/sys_win32.c"
"code/sys/win_bounds.cpp"
"code/sys/win_localization.cpp"
WIN32
"code/win32/win_bounds.cpp"
"code/win32/win_localization.cpp"
"code/win32/win_main.c"
"code/win32/win_net.c"
"code/win32/win_shared.c"
"code/win32/win_syscon.c"
"code/win32/win_wndproc.c"
"code/win32/win_resource.rc"
)
set(SOURCES_CLIENT_PLATFORM_SPECIFIC
"code/win32/win_gamma.c"
"code/win32/win_glimp.c"
"code/win32/win_input.c"
"code/win32/win_qgl.c"
"code/win32/win_snd.c"
)
else()
set(SOURCES_PLATFORM_SPECIFIC
"code/sys/con_tty.c"
"code/sys/sys_unix.c"
"code/unix/linux_signals.c"
"code/unix/unix_main.c"
"code/unix/unix_net.c"
"code/unix/unix_shared.c"
# These are still used even they're prefixed 'win'
"code/sys/win_bounds.cpp"
"code/sys/win_localization.cpp"
"code/win32/win_bounds.cpp"
"code/win32/win_localization.cpp"
)
set(SOURCES_CLIENT_PLATFORM_SPECIFIC
"code/unix/linux_common.c"
"code/unix/linux_glimp.c"
"code/unix/linux_joystick.c"
"code/unix/linux_qgl.c"
"code/unix/linux_snd.c"
)
endif()
@@ -133,46 +149,153 @@ set(SOURCES_COMMON
"code/qcommon/memory.c"
"code/qcommon/msg.cpp"
"code/qcommon/net_chan.c"
"code/qcommon/net_ip.c"
"code/qcommon/q_math.c"
"code/qcommon/q_shared.c"
"code/qcommon/tiki_main.cpp"
"code/qcommon/tiki_script.cpp"
"code/qcommon/unzip.c"
# Main stuff
"code/sys/sys_main.c"
"code/sys/sys_autoupdater.c"
"code/sys/con_log.c"
# Gamespy
"code/gamespy/sv_gamespy.c"
"code/gamespy/sv_gqueryreporting.c"
)
file(GLOB_RECURSE SOURCES_SKEL "code/tiki/*.cpp" "code/skeletor/*.cpp")
set(SOURCES_APP ${SOURCES_SHARED} ${SOURCES_COMMON} ${SOURCES_SKEL})
## Executables
# Targets
### Client version
### TODO! Build the executable client (without the server part)
## Server
### Listen version
### TODO! Build the executable, full version (both client and server)
### Server game library
file(GLOB_RECURSE SOURCES_GAME "code/game/*.c" "code/game/*.cpp" "code/parser/*.cpp" "code/script/*.cpp")
set(SOURCES_GAME_LIB ${SOURCES_SHARED} ${SOURCES_GAME})
### Dedicated version
add_library(fgame SHARED ${SOURCES_GAME_LIB})
target_compile_definitions(fgame PRIVATE GAME_DLL ARCHIVE_SUPPORTED TARGET_GAME_TYPE=${TARGET_GAME_TYPE})
target_include_directories(fgame PUBLIC "code/qcommon" "code/script" "code/game")
target_include_directories(fgame PRIVATE "code/parser")
target_compile_features(fgame PUBLIC cxx_nullptr)
target_compile_features(fgame PUBLIC c_variadic_macros)
set_target_properties(fgame PROPERTIES PREFIX "${TARGET_PLATFORM_PREFIX}")
set_target_properties(fgame PROPERTIES OUTPUT_NAME "game${TARGET_ARCH_SUFFIX}${TARGET_CONFIG_SUFFIX}")
set_target_properties(fgame PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${TARGET_BASE_GAME}")
INSTALL(TARGETS fgame DESTINATION "${TARGET_BASE_GAME}")
include("code/gamespy/gcd.cmake")
### Server executable
file(GLOB_RECURSE SOURCES_SERVER "code/server/*.c" "code/server/*.cpp")
set(SOURCES_SERVER_APP ${SOURCES_APP} ${SOURCES_SERVER})
add_executable(omohaaded ${SOURCES_SERVER_APP} ${SOURCES_PLATFORM_SPECIFIC} "code/null/null_client.c" "code/null/null_input.c" "code/null/null_snddma.c")
set_property(TARGET omohaaded PROPERTY CXX_STANDARD 11)
target_compile_features(omohaaded PUBLIC cxx_constexpr)
target_compile_definitions(omohaaded PRIVATE NO_SCRIPTENGINE DEDICATED TARGET_GAME_TYPE=${TARGET_GAME_TYPE})
target_compile_features(omohaaded PUBLIC cxx_std_17)
target_include_directories(omohaaded PUBLIC "code/qcommon" "code/script" "code/server" "code/SDL2/include")
set_target_properties(omohaaded PROPERTIES OUTPUT_NAME "omohaaded${TARGET_BASE_SUFFIX}${TARGET_ARCH_SUFFIX}")
add_executable(omohaaded ${SOURCES_PLATFORM_SPECIFIC} ${SOURCES_SERVER_APP} "code/null/null_client.c" "code/null/null_input.c" "code/null/null_snddma.c")
target_compile_definitions(omohaaded PRIVATE NO_SCRIPTENGINE APP_MODULE DEDICATED TARGET_GAME_TYPE=${TARGET_GAME_TYPE})
target_compile_features(omohaaded PUBLIC cxx_nullptr)
target_compile_features(omohaaded PUBLIC c_variadic_macros)
# Gamespy dependency
add_dependencies(omohaaded gcd)
target_link_libraries(omohaaded PRIVATE gcd)
target_include_directories(omohaaded PUBLIC "code/qcommon" "code/script" "code/gamespy" "code/server" "code/SDL2/include")
set_target_properties(omohaaded PROPERTIES OUTPUT_NAME "omohaaded${TARGET_BASE_SUFFIX}${TARGET_ARCH_SUFFIX}${TARGET_CONFIG_SUFFIX}")
if(WIN32)
target_link_libraries(omohaaded wsock32 ws2_32)
target_link_libraries(omohaaded winmm)
if (MSVC)
target_link_options(omohaaded PRIVATE "/MANIFEST:NO")
endif()
target_link_libraries(omohaaded PRIVATE wsock32 ws2_32)
target_link_libraries(omohaaded PRIVATE winmm)
INSTALL(FILES $<TARGET_PDB_FILE:fgame> DESTINATION "${TARGET_BASE_GAME}" OPTIONAL)
INSTALL(FILES $<TARGET_PDB_FILE:omohaaded> DESTINATION "./" OPTIONAL)
elseif(UNIX)
find_package(Threads)
target_link_libraries(omohaaded PRIVATE ${CMAKE_DL_LIBS} ${CMAKE_THREAD_LIBS_INIT})
target_link_libraries(omohaaded PRIVATE m)
target_link_libraries(omohaaded PRIVATE stdc++)
endif()
INSTALL(TARGETS omohaaded DESTINATION "./")
if (WITH_CLIENT)
## Client
### Client game library
file(GLOB_RECURSE SOURCES_CGAME "code/cgame/*.c" "code/cgame/*.cpp")
set(SOURCES_CGAME_LIB ${SOURCES_SHARED} ${SOURCES_CGAME} ${SOURCES_BG})
add_library(cgame SHARED ${SOURCES_CGAME_LIB})
target_compile_definitions(cgame PRIVATE CGAME_DLL NO_SCRIPTENGINE TARGET_GAME_TYPE=${TARGET_GAME_TYPE})
target_include_directories(cgame PUBLIC "code/qcommon" "code/cgame" "code/script")
target_compile_features(cgame PUBLIC cxx_nullptr)
target_compile_features(cgame PUBLIC c_variadic_macros)
set_target_properties(cgame PROPERTIES PREFIX "${TARGET_PLATFORM_PREFIX}")
set_target_properties(cgame PROPERTIES OUTPUT_NAME "cgame${TARGET_ARCH_SUFFIX}${TARGET_CONFIG_SUFFIX}")
set_target_properties(cgame PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${TARGET_BASE_GAME}")
INSTALL(TARGETS cgame DESTINATION "${TARGET_BASE_GAME}")
### Executable
file(GLOB_RECURSE SOURCES_JPEG_8 "code/jpeg-8c/*.c")
add_library(jpeg8 STATIC ${SOURCES_JPEG_8})
target_include_directories(jpeg8 PRIVATE "code/jpeg-8c")
file(GLOB_RECURSE SOURCES_CLIENT "code/client/*.c" "code/client/*.cpp" "code/qcommon/puff.c")
file(GLOB_RECURSE SOURCES_UILIB "code/uilib/*.c" "code/uilib/*.cpp")
file(GLOB_RECURSE SOURCES_RENDERER "code/renderer/*.c" "code/renderer/*.cpp")
#file(GLOB_RECURSE SOURCES_RENDERER "code/sdl/*.c" "code/renderercommon/*.c" "code/renderergl2/*.c" "code/renderergl2/*.cpp")
set(SOURCES_CLIENT_APP ${SOURCES_APP} ${SOURCES_SERVER} ${SOURCES_CLIENT} ${SOURCES_UILIB} ${SOURCES_LIBS} ${SOURCES_RENDERER})
add_executable(openmohaa ${SOURCES_PLATFORM_SPECIFIC} ${SOURCES_CLIENT_APP} ${SOURCES_CLIENT_PLATFORM_SPECIFIC})
target_compile_definitions(openmohaa PRIVATE NO_SCRIPTENGINE APP_MODULE TARGET_GAME_TYPE=${TARGET_GAME_TYPE})
target_compile_features(openmohaa PUBLIC cxx_nullptr)
target_compile_features(openmohaa PUBLIC c_variadic_macros)
target_link_libraries(openmohaa PRIVATE jpeg8)
# Gamespy dependency
add_dependencies(openmohaa gcd)
target_link_libraries(openmohaa PRIVATE gcd)
target_include_directories(openmohaa PUBLIC "code/qcommon" "code/script" "code/gamespy" "code/server" "code/client" "code/uilib" "code/SDL2/include" "code/jpeg-8c")
set_target_properties(openmohaa PROPERTIES OUTPUT_NAME "openmohaa${TARGET_BASE_SUFFIX}${TARGET_ARCH_SUFFIX}${TARGET_CONFIG_SUFFIX}")
if(WIN32)
if (MSVC)
target_link_options(openmohaa PRIVATE "/MANIFEST:NO")
#add_library(sdl2 SHARED IMPORTED)
#set_target_properties(sdl2 PROPERTIES
# IMPORTED_IMPLIB "${CMAKE_SOURCE_DIR}/code/libs/win32/SDL2.lib"
#)
#
#add_library(sdl2main SHARED IMPORTED)
#set_target_properties(sdl2main PROPERTIES
# IMPORTED_IMPLIB "${CMAKE_SOURCE_DIR}/code/libs/win32/SDL2main.lib"
#)
#
#add_library(glew32 SHARED IMPORTED)
#set_target_properties(glew32 PROPERTIES
# IMPORTED_IMPLIB "${CMAKE_SOURCE_DIR}/code/libs/win32/glew32.lib"
#)
target_link_libraries(openmohaa PRIVATE opengl32)
endif()
target_link_libraries(openmohaa PRIVATE wsock32 ws2_32)
target_link_libraries(openmohaa PRIVATE winmm)
INSTALL(FILES $<TARGET_PDB_FILE:cgame> DESTINATION "${TARGET_BASE_GAME}" OPTIONAL)
INSTALL(FILES $<TARGET_PDB_FILE:openmohaa> DESTINATION "./" OPTIONAL)
elseif(UNIX)
find_package(OpenGL REQUIRED)
find_package(GLUT REQUIRED)
find_package(X11 REQUIRED)
find_package(Threads)
target_include_directories(openmohaa PRIVATE ${OPENGL_INCLUDE_DIRS} ${GLUT_INCLUDE_DIRS})
target_link_libraries(openmohaa PRIVATE ${OPENGL_LIBRARIES} ${GLUT_LIBRARY} ${CMAKE_DL_LIBS} ${CMAKE_THREAD_LIBS_INIT})
target_link_libraries(openmohaa PRIVATE m)
target_link_libraries(openmohaa PRIVATE stdc++)
target_link_libraries(openmohaa PRIVATE ${X11_LIBRARIES} ${X11_Xxf86vm_LIB} ${X11_Xext_LIB} Xxf86dga)
endif()
INSTALL(TARGETS openmohaa DESTINATION "./")
endif()
+23
View File
@@ -0,0 +1,23 @@
# File layout
| Path | Description |
| ---------------------|-------------------------------------------------------------------
| build/ | Output files |
| code/ | OpenMoHAA source code |
| code/cgame | Client game code |
| code/client | Client (network stuff, snapshots, etc) |
| code/game | Server game code (game logic stuff, etc) |
| code/gamespy | Gamespy SDK |
| code/mohui | MoHAA User Interface |
| code/null | Null redirector (used by the OpenMoHAA Dedicated Server) |
| code/parser | Flex/Bison parser |
| code/qcommon | Global shared stuff such as maths |
| code/renderer | OpenMoHAA renderer |
| code/sdl(12) | SDL code |
| code/script | Script engine |
| code/server | Server code (networkn snapshots, handling clients etc) |
| code/skeletor | Skeleton model engine |
| code/sys | Main application system |
| code/tiki | Complete TIKI engine |
| code/uilib | UI library (Ubertools stuff) |
| misc/ | Project stuff, definition files and various resources stuff. |
-20
View File
@@ -1,20 +0,0 @@
File layout
======================
build/ --> Output files
code/ --> OpenMoHAA source code
code/cgame --> Client game code
code/cgame_hook --> Client game patch for MoHAA (hooks the default cgamex86.dll)
code/client --> Client (network stuff, snapshots, etc)
code/game --> Server game code (game logic stuff, etc)
code/globalcpp --> C++ Global stuff such as the Script Engine & Parser
code/mohui --> MoHAA User Interface
code/null --> Null redirector (used by the OpenMoHAA Dedicated Server)
code/qcommon --> Global shared stuff such as maths
code/renderer --> OpenMoHAA renderer
code/renderer_gl3 --> Newest renderer (not working and buggy)
code/sdl(12) --> SDL code
code/server --> Server code (networkn snapshots, handling clients etc)
code/sys --> Main application system
code/testutils --> Test utility for scripts and various stuff
misc/ --> Project stuff, definition files and various resources stuff.
+37 -19
View File
@@ -13,28 +13,37 @@
[![Discord Banner 1](https://discordapp.com/api/guilds/596049712579215361/widget.png?style=banner2)](https://discord.gg/NYtH58R)
## Current State
---
OpenMoHAA is still in its early days.
### Server
The server version can successfully be built. There are few unimplemented stuff from the game library :
The server version can successfully be built.
Some stuff are not working as intended, such as Actor or Vehicle. These systems are both almost fully implemented, but not really in stable state.
- Actor
- Vehicle
Overall the server part and the game module are almost fully implemented, but the stability may vary, there may be some minor bugs and crashes.
### Client
There is currently no client build because the client code is currently unusable. Here is what's missing or unimplemented :
The client version of OpenMoHAA is partially implemented and not stable currently. The cgame module is partially implemented as well, but is compatible with the original MOH:AA game. Credits to **Heavy Metal: F.A.K.K. 2**'s SDK for the cgame module.
- cgame (using F.A.K.K build)
- rendering (mostly advanced)
- sound (must be reworked)
- UI
Here is the current working state for each part of the engine:
| Part name | Full | Almost | Half | Early | Bad | Not working | Comment |
|-------------------------|------|--------|------|-------|-----|-------------|-------------------------------------------------------------------|
| Audio | | | | | x | | Very basic implementation from Quake III |
| CG Module | | x | | | | | Missing FX, Marks and decals |
| Client | | | x | | | | Missing GameSpy, server list, binds, map picker, ... |
| Collision | x | | | | | | |
| Model/TIKI/Skeletor | x | | | | | | |
| Renderer | | | | x | | | Missing ghost, marks, sphere lights, sky portal, sun flare, swipe |
| Server | | x | | | | | Probably a few bugs remaining |
| Server module (fgame) | | x | | | | | Actor, vehicle, and few gameplay bugs |
| UI | | | | x | | | Has core features only (menu, widgets, console, hud, urc loading) |
## Running
---
Backup the existing **gamex86.dll** (rename it to **gamex86.bak**).
Backup existing mohaa files, **cgamex86.dll** and **gamex86.dll** (set their extension to **.bak**)
a) extract archive to your MOHAA installation directory.
@@ -51,27 +60,37 @@ https://learn.microsoft.com/en-US/cpp/windows/latest-supported-vc-redist?view=ms
You can now start a local OpenMOHAA server or play on a server.
## Compiling
---
OpenMoHAA supports both x86 and x64 architectures, and although the target platform is Windows, it still can be compiled for other platforms, and even other architectures.
These are the tools required for all platforms :
- CMake
- Flex and Bison
- Clang (at least version 11)
At least C++17 is required. Avoid GCC/G++ because it uses nonstandard extensions.
- CMake >= 3.5
- Flex and Bison (currently not used)
- A C++11 compiler is required.
The installation directory can be set to MOHAA directory.
The client build and successfully be built by adding `-DWITH_CLIENT=1` to the CMake command line.
### Linux
These are the tools required on Unix :
- Clang >= 3.3 or GCC >= 4.8.1
**clang-3.5** and **gcc-4.8.5** should work (tested on Ubuntu 16.04).
1 line install command with latest clang version : `sudo apt-get install -y ninja-build cmake make clang-15 lld-15 flex bison`
### Windows
Visual Studio (2019 or 2022) is generally preferred.
## Screenshots
![](docs/images/opm_50b_1.png)
![](docs/images/opm_50b_2.png)
## Third party
---
### SDL
@@ -108,7 +127,6 @@ https://xiph.org/vorbis/
https://opus-codec.org/
## URL
---
- https://openmohaa.sourceforge.net/
- https://x-null.net/
+4
View File
@@ -46,6 +46,10 @@ set(archdetect_c_code "
#else
#error cmake_ARCH ppc
#endif
#elif defined __s390__
#error cmake_ARCH s390
#elif defined __s390x__
#error cmake_ARCH s390x
#endif
#error cmake_ARCH unknown
-1231
View File
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
+964
View File
@@ -0,0 +1,964 @@
/*
===========================================================================
Copyright (C) 2023 the OpenMoHAA team
This file is part of OpenMoHAA source code.
OpenMoHAA source code is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the License,
or (at your option) any later version.
OpenMoHAA source code is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with OpenMoHAA source code; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
// DESCRIPTION:
// client side entity commands
/*
The cg_command system is used for a variety of different functions, but mostly it is
used for spawning client side temp models. Either through the use of emitters or
commands that are tied to various frames of animation.
The ctempmodel_t class is the data structure for all of the static tempmodels.
These are updated every frame and refEntity and refSprite data is created and added
to the renderer for drawing.
The spawnthing_t is the intermediate data holder. When the TIKI file is processed
the spawnthing_t is cleared out and values are assigned based on the commands issued.
cg_common_data is a list of common data elements that are the same in the ctempmodel_t and
the spawhthing_t
After the m_spawnthing is filled in, 1 or more ctempmodel_t structures are spawned.
The ClientCommandManager is the listener that process all of the commands in the
TIKI file, similar to ScriptMaster in the server game dll.
*/
#pragma once
#include "cg_local.h"
#include "listener.h"
#include "script.h"
#include "vector.h"
#include "../qcommon/qcommon.h"
#define EMITTER_DEFAULT_LIFE 1000
#define MAX_EMITTERS 32
#define MAX_SWIPES 32
#define T_RANDSCALE (1 << 0)
#define T_SCALEANIM (1 << 1)
#define T_SPHERE (1 << 2)
#define T_INWARDSPHERE (1 << 3)
#define T_CIRCLE (1 << 4)
#define T_FADE (1 << 5)
#define T_DIETOUCH (1 << 6)
#define T_ANGLES (1 << 7)
#define T_WAVE (1 << 8)
#define T_SWARM (1 << 9)
#define T_ALIGN (1 << 10)
#define T_COLLISION (1 << 11)
#define T_FLICKERALPHA (1 << 12)
#define T_DLIGHT (1 << 13)
#define T_FADEIN (1 << 14)
#define T_GLOBALFADEIN (1 << 15)
#define T_GLOBALFADEOUT (1 << 16)
#define T_PARENTLINK (1 << 17)
#define T_RANDOMROLL (1 << 18)
#define T_HARDLINK (1 << 19)
#define T_ANIMATEONCE (1 << 20)
#define T_BEAMTHING (1 << 21)
#define T_RANDVELAXIS (1 << 22)
#define T_BOUNCESOUND (1 << 23)
#define T_BOUNCESOUNDONCE (1 << 24)
#define T_TWINKLE (1 << 25)
#define T_TWINKLE_OFF (1 << 26)
#define T_ALIGNONCE (1 << 27)
#define T_SCALEUPDOWN (1 << 28)
#define T_AUTOCALCLIFE (1 << 29)
#define T_ASSIGNED_NUMBER (1 << 30)
#define T_DETAIL (1 << 31)
#define T2_MOVE (1 << 0)
#define T2_AMOVE (1 << 1)
#define T2_ACCEL (1 << 2)
#define T2_TRAIL (1 << 3)
#define T2_PHYSICS_EVERYFRAME (1 << 4)
#define T2_TEMPORARY_DECAL (1 << 5)
#define T2_BOUNCE_DECAL (1 << 6)
#define T2_PARALLEL (1 << 7)
#define T2_VOLUMETRIC (1 << 8)
#define T2_WIND_AFFECT (1 << 10)
#define T2_SPRITEGRIDLIGHTING (1 << 11)
#define T2_WATERONLY (1 << 12)
#define T2_ALIGNSTRETCH (1 << 13)
#define T2_ALWAYSDRAW (1 << 14)
#define T2_CLAMP_VEL (1 << 15)
#define T2_CLAMP_VEL_AXIS (1 << 16)
#define T2_CONE (1 << 17)
#define T2_RADIALVELOCITY (1 << 18)
#define T2_FRICTION (1 << 19)
#define T2_VARYCOLOR (1 << 20)
class spawnthing_t;
class specialeffect_t;
typedef enum { NOT_RANDOM, RANDOM, CRANDOM } randtype_t;
class cg_common_data : public Class
{
public:
cg_common_data();
int life;
int createTime;
Vector origin;
Vector oldorigin;
Vector accel;
Vector angles;
Vector velocity;
Vector avelocity;
Vector parentOrigin;
Vector parentMins;
Vector parentMaxs;
Vector minVel;
Vector maxVel;
float color[4];
float alpha;
float scaleRate;
float scalemin;
float scalemax;
float bouncefactor;
int bouncecount;
int maxbouncecount;
str bouncesound;
int bouncesound_delay;
int flags;
int flags2;
dtiki_t* tiki;
int swarmfreq;
float swarmmaxspeed;
float swarmdelta;
float lightIntensity;
int lightType;
int fadeintime;
int fadedelay;
int parent;
int collisionmask;
int min_twinkletimeoff;
int max_twinkletimeoff;
int min_twinkletimeon;
int max_twinkletimeon;
int lightstyle;
int physicsRate;
float scale;
float scale2;
str swipe_shader;
str swipe_tag_start;
str swipe_tag_end;
str shadername;
float swipe_life;
float friction;
float decal_orientation;
float decal_radius;
};
inline cg_common_data::cg_common_data()
{
int i;
bouncesound_delay = 0;
life = 0;
createTime = 0;
alpha = 0;
fadedelay = 0;
lightIntensity = 0;
lightType = (dlighttype_t)0;
bouncefactor = 0;
bouncecount = 0;
maxbouncecount = 0;
scaleRate = 0;
scale = 1;
scalemin = 0;
scalemax = 0;
swarmfreq = 0;
swarmmaxspeed = 0;
swarmdelta = 0;
flags = 0;
flags2 = 0;
fadeintime = 0;
parent = 0;
tiki = nullptr;
collisionmask = 0;
min_twinkletimeoff = 0;
max_twinkletimeoff = 0;
min_twinkletimeon = 0;
max_twinkletimeoff = 0;
lightstyle = -1;
physicsRate = 10;
for (i = 0; i < 4; i++) {
color[i] = 0;
}
}
class ctempmodel_t : public Class
{
public:
ctempmodel_t();
class ctempmodel_t* next;
class ctempmodel_t* prev;
cg_common_data cgd;
str modelname;
refEntity_t lastEnt;
refEntity_t ent;
int number;
int lastAnimTime;
int lastPhysicsTime;
int killTime;
int next_bouncesound_time;
int seed;
int twinkleTime;
int aliveTime;
qboolean addedOnce;
qboolean lastEntValid;
spawnthing_t* m_spawnthing;
void (*touchfcn)(ctempmodel_t* ct, trace_t* trace);
};
inline ctempmodel_t::ctempmodel_t()
{
number = 0;
lastPhysicsTime = 0;
lastAnimTime = 0;
killTime = 0;
next_bouncesound_time = 0;
seed = 0;
twinkleTime = 0;
aliveTime = 0;
addedOnce = qfalse;
lastEntValid = qfalse;
}
enum class vsstypes_t : unsigned char {
VST_DEFAULT,
VST_GUN,
VST_IMPACT,
VST_DIRT,
VST_HEAVY,
VST_STEAM,
VST_MIST,
VST_SGREN,
VST_GRENADE,
VST_FIRE,
VST_GREASEFIRE,
VST_DEBRIS,
NUM_VSS_TYPES
};
class cvssource_t : public Class
{
public:
cvssource_t* next;
cvssource_t* prev;
cvssource_t* stnext;
int stindex;
Vector lastOrigin;
float lastRadius;
float lastDensity;
float lastColor[3];
float lastLighting[3];
Vector newOrigin;
float newRadius;
float newDensity;
float newColor[3];
float newLighting[3];
float ooRadius;
Vector velocity;
float startAlpha;
int roll;
Vector repulsion;
int lifeTime;
int collisionmask;
int parent;
int flags;
int flags2;
int smokeType;
float typeInfo;
float fadeMult;
float scaleMult;
int lastPhysicsTime;
int lastLightingTime;
qboolean lastValid;
};
class cvssourcestate_t : public Class
{
public:
Vector origin;
float color[3];
float radius;
float density;
};
#define LIFE_SWIPE 1
#define MAX_SWIPE_POINTS 64
struct swipepoint_t {
vec3_t points[2];
float time;
};
class swipething_t : public Class
{
public:
qboolean enabled;
str tagname_start;
str tagname_end;
int entitynum;
float startcolor[4];
float endcolor[4];
swipepoint_t swipepoints[MAX_SWIPE_POINTS];
swipepoint_t cntPoint;
int num_live_swipes;
int first_swipe;
float life;
qhandle_t shader;
void Init();
};
inline void swipething_t::Init()
{
int i;
enabled = qfalse;
tagname_start = "";
tagname_end = "";
entitynum = -1;
for (i = 0; i < 4; i++) {
startcolor[i] = 1.f;
endcolor[i] = 0.f;
}
for (i = 0; i < MAX_SWIPE_POINTS; i++) {
VectorSet(swipepoints[i].points[0], 0.f, 0.f, 0.f);
VectorSet(swipepoints[i].points[1], 0.f, 0.f, 0.f);
swipepoints[i].time = 0.f;
}
num_live_swipes = 0;
first_swipe = 0;
}
// Enttracker is used to keep track of client side tempmodels. They are
// assigned a number from a pool of 256.
class enttracker_t : public Class
{
public:
enttracker_t();
int AssignNumber(void);
protected:
qboolean usedNumbers[256];
virtual void RemoveEntity(int entnum);
};
inline enttracker_t::enttracker_t()
{
memset(usedNumbers, 0, sizeof(usedNumbers));
}
inline void enttracker_t::RemoveEntity(int entnum)
{
// If the entnum is a magic number, then clear out the usedNumber field, so
// that it may be reused for this emitter.
if (entnum >= MAGIC_UNUSED_NUMBER) {
entnum -= MAGIC_UNUSED_NUMBER;
assert(entnum >= 0);
assert(entnum < 256);
usedNumbers[entnum] = qfalse;
}
}
inline int enttracker_t::AssignNumber(void)
{
int i;
// These numbers are used for client side tempmodels that are emitters
// themselves. Since they don't have real entity_numbers, they must be
// assigned a MAGIC number so we can keep track of the last time that the
// model emitted something.
// Search for a number that is not used
for (i = 0; i < 256; i++) {
if (!usedNumbers[i]) {
usedNumbers[i] = qtrue;
return MAGIC_UNUSED_NUMBER + i;
}
}
return -1;
}
class emittertime_t : public Class
{
public:
int entity_number;
int last_emit_time;
Vector oldorigin;
qboolean active;
qboolean lerp_emitter;
};
// emitterthing_t is used to keep track of the last time and emitter was updated
// for a particular entity number. It inherits from the enttracker_t so it can
// manage client side tempmodels
class emitterthing_t : public enttracker_t
{
protected:
Container<emittertime_t> m_emittertimes; // A list of entity numbers and the
// last time they emitted
public:
emittertime_t* GetEmitTime(int entnum);
virtual void RemoveEntity(int entnum);
qboolean startoff;
};
inline void emitterthing_t::RemoveEntity(int entnum)
{
int num, count;
emittertime_t* et;
if (entnum == -1) {
return;
}
count = m_emittertimes.NumObjects();
for (num = count; num >= 1; num--) {
et = &m_emittertimes.ObjectAt(num);
if (et->entity_number == entnum) {
m_emittertimes.RemoveObjectAt(num);
}
}
enttracker_t::RemoveEntity(entnum);
}
inline emittertime_t* emitterthing_t::GetEmitTime(int entnum)
{
int num, count;
emittertime_t* et;
count = m_emittertimes.NumObjects();
for (num = 1; num <= count; num++) {
et = &m_emittertimes.ObjectAt(num);
if (et->entity_number == entnum) {
return et;
}
}
// Add a new entry if we didn't find it already
et = &m_emittertimes.ObjectAt(m_emittertimes.AddObject({}));
et->entity_number = entnum;
et->last_emit_time = cg.time;
et->lerp_emitter = qfalse;
if (this->startoff) {
et->active = qfalse;
} else {
et->active = qtrue;
}
return et;
}
class commandtime_t : public Class
{
public:
int entity_number;
int command_number;
int last_command_time;
};
// This class is used for keeping track of the last time an entity executed a
// particular command. A command number must be assigned externally by the user
class commandthing_t : public enttracker_t
{
Container<commandtime_t*> m_commandtimes; // A list of entity numbers and the last time they
// executed a command
public:
commandtime_t* GetLastCommandTime(int entnum, int commandnum);
virtual void RemoveEntity(int entnum);
};
inline void commandthing_t::RemoveEntity(int entnum)
{
int num, count;
commandtime_t* ct;
count = m_commandtimes.NumObjects();
for (num = count; num >= 1; num--) {
ct = m_commandtimes.ObjectAt(num);
if (ct->entity_number == entnum) {
m_commandtimes.RemoveObjectAt(num);
}
}
enttracker_t::RemoveEntity(entnum);
}
inline commandtime_t* commandthing_t::GetLastCommandTime(int entnum,
int commandnum)
{
int num, count;
commandtime_t* ct;
// Search for this entity number
count = m_commandtimes.NumObjects();
for (num = 1; num <= count; num++) {
ct = m_commandtimes.ObjectAt(num);
if ((ct->entity_number == entnum) &&
(ct->command_number == commandnum)) {
return ct;
}
}
// Add a new entry if we didn't find it
ct = new commandtime_t;
ct->entity_number = entnum;
ct->command_number = commandnum;
ct->last_command_time = 0;
m_commandtimes.AddObject(ct);
return ct;
}
class spawnthing_t : public emitterthing_t
{
public:
Container<str>
m_modellist; // A list of models that should be spawned from the emitter
Container<str> m_taglist; // A list of tags to create beams
cg_common_data cgd;
int entnum;
Vector origin_offset_base;
Vector origin_offset_amplitude;
Vector axis_offset_base;
Vector axis_offset_amplitude;
Vector randvel_base;
Vector randvel_amplitude;
Vector avelocity_base;
Vector avelocity_amplitude;
Vector angles_amplitude;
vec3_t axis[3];
vec3_t tag_axis[3];
float life_random;
float forwardVelocity;
float sphereRadius;
float coneHeight;
float spawnRate;
int lastTime;
int count;
int tagnum;
str emittername;
str animName;
float dcolor[3];
qboolean dlight;
int numtempmodels;
float linked_origin[3];
float linked_axis[3][3];
float fMinRangeSquared;
float fMaxRangeSquared;
// beam stuff also impact trace stuff
str startTag;
str endTag;
float length;
float min_offset;
float max_offset;
float overlap;
float numSubdivisions;
float delay;
float toggledelay;
int beamflags;
int numspherebeams;
float endalpha;
float spreadx;
float spready;
qboolean use_last_trace_end;
void (*touchfcn)(ctempmodel_t* ct, trace_t* trace);
str GetModel(void);
void SetModel(str model);
};
inline void spawnthing_t::SetModel(str model)
{
m_modellist.ClearObjectList();
m_modellist.AddObject(model);
}
inline str spawnthing_t::GetModel(void)
{
int num, index;
num = m_modellist.NumObjects();
if (!num) {
return "";
}
index = (num * random()) + 1;
if (index > num) {
index = num;
}
return m_modellist.ObjectAt(index);
}
// Keeps track of beams that are created by entities that need their positions
// updated every frame
class beamthing_t : public emitterthing_t
{
public:
str beamname;
str shadername;
str startTag;
str endTag;
int numSubdivisions;
dtiki_t *tiki;
float alpha;
float scale;
int flags;
float length;
int life;
float min_offset;
float max_offset;
float overlap;
int delay;
byte modulate[4];
};
#define MAX_TEMPMODELS 1024
#define MAX_BEAMS 4096
class ClientGameCommandManager : public Listener
{
private:
spawnthing_t m_localemitter; // local emitter used by animation commands
ctempmodel_t m_active_tempmodels;
ctempmodel_t* m_free_tempmodels;
ctempmodel_t m_tempmodels[MAX_TEMPMODELS];
cvssource_t m_active_vsssources;
cvssource_t* m_free_vsssources;
cvssource_t* m_vsssources;
int m_iAllocatedvsssources;
spawnthing_t* m_spawnthing;
Container<spawnthing_t*> m_emitters; // Global emitters set up by client commands
int m_seed;
commandthing_t m_command_time_manager; // Keeps track of entity numbers and the last
// time they executed particular commands
specialeffect_t* m_pCurrentSfx;
int m_iLastVSSRepulsionTime;
float m_fEventWait;
void (ClientGameCommandManager::*endblockfcn)(void);
cvssource_t* AllocateVSSSource();
void FreeVSSSource(cvssource_t *p);
void SpawnVSSSource(int count, int timealive);
void EventViewKick(Event* ev);
void Print(Event* ev);
void StartBlock(Event* ev);
void EndBlock(Event* ev);
void UpdateSpawnThing(spawnthing_t* ep);
void EmitterStartOff(Event* ev);
void SetAlpha(Event* ev);
void SetDieTouch(Event* ev);
void SetBounceFactor(Event* ev);
void SetBounceSound(Event* ev);
void SetBounceSoundOnce(Event* ev);
void SetModel(Event* ev);
void SetLife(Event* ev);
void SetColor(Event* ev);
void SetColorRange(Event* ev);
void SetLightstyle(Event* ev);
void SetRadialVelocity(Event* ev);
void SetVelocity(Event* ev);
void SetAngularVelocity(Event* ev);
void SetCount(Event* ev);
void SetScale(Event* ev);
void SetScaleUpDown(Event* ev);
void SetScaleMin(Event* ev);
void SetScaleMax(Event* ev);
void SetScaleRate(Event* ev);
void SetRandomVelocity(Event* ev);
void SetRandomVelocityAlongAxis(Event* ev);
void SetAccel(Event* ev);
void SetFriction(Event* ev);
void SetVaryColor(Event* ev);
void SetFade(Event* ev);
void SetFadeDelay(Event* ev);
void SetSpawnRange(Event* ev);
void SetSpawnRate(Event* ev);
void SetOriginOffset(Event* ev);
void SetOffsetAlongAxis(Event* ev);
void SetCone(Event* ev);
void SetCircle(Event* ev);
void SetSphere(Event* ev);
void SetInwardSphere(Event* ev);
void SetRandomRoll(Event* ev);
void SetVolumetric(Event* ev);
void SetSwarm(Event* ev);
void SetAlign(Event* ev);
void SetAlignOnce(Event* ev);
void SetCollision(Event* ev);
void SetFlickerAlpha(Event* ev);
void SetFadeIn(Event* ev);
void SetEntityColor(Event* ev);
void SetGlobalFade(Event* ev);
void SetRadius(Event* ev);
void SetParentLink(Event* ev);
void SetHardLink(Event* ev);
void SetAngles(Event* ev);
void ParentAngles(Event* ev);
void EmitterAngles(Event* ev);
void SetTwinkle(Event* ev);
void SetTrail(Event* ev);
void SetPhysicsRate(Event* ev);
void SetBounceDecal(Event* ev);
void UpdateSwarm(ctempmodel_t* p);
void BeginOriginSpawn(Event* ev);
void EndOriginSpawn(void);
void BeginOriginBeamSpawn(Event* ev);
void EndOriginBeamSpawn(void);
void BeginOriginBeamEmitter(Event* ev);
void EndOriginBeamEmitter(void);
void BeginTagSpawn(Event* ev);
void BeginTagSpawnLinked(Event* ev);
void EndTagSpawn(void);
void BeginTagBeamSpawn(Event* ev);
void EndTagBeamSpawn(void);
void BeginTagEmitter(Event* ev);
void EndTagEmitter(void);
void BeginOriginEmitter(Event* ev);
void EndOriginEmitter(void);
void BeginTagBeamEmitter(Event* ev);
void EndTagBeamEmitter(void);
void EmitterOn(Event* ev);
void EmitterOff(Event* ev);
void RainTouch(Event* ev);
void Sound(Event* ev);
void SetCurrentTiki(Event* ev);
void StopSound(Event* ev);
void StopAliasChannel(Event* ev);
void LoopSound(Event* ev);
void Cache(Event* ev);
void CacheImage(Event* ev);
void CacheFont(Event* ev);
void AliasCache(Event* ev);
void Alias(Event* ev);
void CacheAlias(Event* ev);
void Client(Event* ev);
void TagDynamicLight(Event* ev);
void OriginDynamicLight(Event* ev);
void DynamicLight(Event* ev);
void BlockDynamicLight(Event* ev);
void EndBlockDynamicLight();
void GetOrientation(int tagnum, spawnthing_t* sp);
void Swipe(Event* ev);
void SwipeOn(Event* ev);
void SwipeOff(Event* ev);
void AnimateOnce(Event* ev);
void SetAnim(Event* ev);
void SetDecalRadius(Event* ev);
void SetDecalOrientation(Event* ev);
void TagList(Event* ev);
void SetParallel(Event* ev);
void Footstep(Event* ev);
void LandingSound(Event* ev);
void BodyFallSound(Event* ev);
void SetAlwaysDraw(Event* ev);
void SetDetail(Event* ev);
void SetWindAffect(Event* ev);
void SpriteGridLighting(Event* ev);
void SetWaterOnly(Event* ev);
void SetAlignStretch(Event* ev);
void SetClampVel(Event* ev);
void SetClampVelAxis(Event* ev);
ctempmodel_t* AllocateTempModel(void);
qboolean TempModelPhysics(ctempmodel_t* p, float ftime, float time2,
float scale);
qboolean TempModelRealtimeEffects(ctempmodel_t* p, float ftime, float time2,
float scale);
qboolean LerpTempModel(refEntity_t* newEnt, ctempmodel_t* p, float frac);
void SpawnEffect(int count, int timealive);
void SpawnTempModel(int count, int timealive = 0);
void FreeTempModel(ctempmodel_t* le);
void AnimateTempModel(ctempmodel_t* ent, Vector origin,
refEntity_t* newEnt);
void OtherTempModelEffects(ctempmodel_t* p, Vector origin,
refEntity_t* newEnt);
qboolean IsBlockCommand(const str& name);
void SetBaseAndAmplitude(Event* ev, Vector& base, Vector& amplitude);
// Beam stuff
void SetSubdivisions(Event* ev);
void SetMinOffset(Event* ev);
void SetMaxOffset(Event* ev);
void SetShader(Event* ev);
void SetLength(Event* ev);
void SetBeamDelay(Event* ev);
void SetBeamToggleDelay(Event* ev);
void SetBeamPersist(Event* ev);
void SetBeamOffsetEndpoints(Event* ev);
void SetBeamSphere(Event* ev);
void SetSpread(Event* ev);
void SetUseLastTraceEnd(Event* ev);
void SetEndAlpha(Event* ev);
void SetEyeLimits(Event* ev);
void SetEyeMovement(Event* ev);
void StartSFX(Event* ev);
void StartSFXDelayed(Event* ev);
void StartSFXCommand(Event* ev, qboolean bDelayed);
void EndIgnoreSfxBlock();
void RandomChance(Event* ev);
void DelayedRepeat(Event* ev);
void CommandDelay(Event* ev);
void SpawnTreads(Event* ev);
void TreadsOff(Event* ev);
bool GetTagPositionAndOrientation(int tagnum, orientation_t* new_or);
bool GetTagPositionAndOrientation(str tagname, orientation_t* new_or);
public:
CLASS_PROTOTYPE(ClientGameCommandManager);
ClientGameCommandManager();
void AddTempModels(void);
void UpdateEmitter(dtiki_t* tiki, vec3_t axis[3], int entity_number,
int parent_number, Vector entity_origin);
void UpdateBeam(dtiki_t *tiki, int entity_number, spawnthing_t* beamthing);
void PlaySound(str sound_name, vec3_t origin = NULL,
int channel = CHAN_AUTO, float volume = -1,
float min_distance = -1, float pitch = -1, int argstype = 0);
spawnthing_t* InitializeSpawnthing(spawnthing_t* ep);
void SpawnEffect(int count, spawnthing_t* sp);
void FreeAllTempModels(void);
void RestartAllEmitters(void);
void InitializeTempModels(void);
void InitializeTempModelCvars(void);
void InitializeEmitters(void);
void RemoveClientEntity(int number, dtiki_t* tiki, centity_t* cent,
ctempmodel_t* p = NULL);
void ClearSwipes(void);
void ResetTempModels(void);
void SpawnTempModel(int count, spawnthing_t* sp);
inline void SetSpawnthing(spawnthing_t* st) { m_spawnthing = st; };
spawnthing_t* CreateNewEmitter(str emittername);
spawnthing_t* CreateNewEmitter(void);
spawnthing_t* GetEmitterByName(str emittername);
void DeleteEmitters(dtiki_t* tiki);
void CGEvent(centity_t* cent);
void ProcessPendingEventsForEntity();
qboolean PostEventForEntity(Event *ev, float fWait);
qboolean SelectProcessEvent(Event *ev);
void TestEffectEndFunc();
void AddVSSSources();
void InitializeVSSCvars();
void InitializeVSSSources();
void ResetVSSSources();
void ResetVSSSources(Event* ev);
void SetCurrentSFX(specialeffect_t* pSFX);
void ClearCurrentSFX();
void AddTreadMarkSources();
void InitializeTreadMarkCvars();
void InitializeTreadMarkSources();
void ResetTreadMarkSources();
void ResetTreadMarkSources(Event* ev);
void InitializeRainCvars();
void InitializeBeams();
};
class EmitterLoader : public Listener
{
private:
bool emitterActive;
public:
CLASS_PROTOTYPE(EmitterLoader);
EmitterLoader();
bool Load(Script&);
void ProcessEmitter(Script&);
void Emitter(Event* ev);
};
class EffectsEventQueueNode {
public:
Event* event;
int inttime;
int flags;
int entity_num;
EffectsEventQueueNode* prev;
EffectsEventQueueNode* next;
#ifdef _DEBUG
str name;
#endif
EffectsEventQueueNode() { prev = this; next = this; }
EffectsEventQueueNode(Event* event, int inttime, int flags, int entity_num)
{
this->event = event;
this->inttime = inttime;
this->flags = flags;
this->entity_num = entity_num;
}
int GetEntityNum() { return entity_num; }
};
extern ClientGameCommandManager commandManager;
+469 -233
View File
@@ -1,45 +1,32 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
Copyright (C) 2023 the OpenMoHAA team
This file is part of Quake III Arena source code.
This file is part of OpenMoHAA source code.
Quake III Arena source code is free software; you can redistribute it
OpenMoHAA source code is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the License,
or (at your option) any later version.
Quake III Arena source code is distributed in the hope that it will be
OpenMoHAA source code is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Quake III Arena source code; if not, write to the Free Software
along with OpenMoHAA source code; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
//
// cg_consolecmds.c -- text commands typed in at the local console, or
// executed by a key binding
// DESCRIPTION:
// text commands typed in at the local console, or executed by a key binding
#include "cg_local.h"
void CG_TargetCommand_f( void ) {
int targetNum;
char *test;
targetNum = CG_CrosshairPlayer();
if (!targetNum ) {
return;
}
test = cgi.Argv( 1 );
cgi.SendConsoleCommand( va( "gc %i %i", targetNum, atoi( test ) ) );
}
void CG_TargetCommand_f(void);
/*
=================
@@ -48,11 +35,11 @@ CG_SizeUp_f
Keybinding command
=================
*/
static void CG_SizeUp_f (void) {
cgi.Cvar_Set("cg_viewsize", va("%i",(int)(cg_viewsize->integer+10)));
static void CG_SizeUp_f(void)
{
cgi.Cvar_Set("viewsize", va("%i", (int)(cg_viewsize->integer + 10)));
}
/*
=================
CG_SizeDown_f
@@ -60,11 +47,11 @@ CG_SizeDown_f
Keybinding command
=================
*/
static void CG_SizeDown_f (void) {
cgi.Cvar_Set("cg_viewsize", va("%i",(int)(cg_viewsize->integer-10)));
static void CG_SizeDown_f(void)
{
cgi.Cvar_Set("viewsize", va("%i", (int)(cg_viewsize->integer - 10)));
}
/*
=============
CG_Viewpos_f
@@ -72,189 +59,352 @@ CG_Viewpos_f
Debugging command to print the current position
=============
*/
static void CG_Viewpos_f (void) {
CG_Printf ("(%i %i %i) : %i\n", (int)cg.refdef.vieworg[0],
(int)cg.refdef.vieworg[1], (int)cg.refdef.vieworg[2],
(int)cg.refdefViewAngles[YAW]);
static void CG_Viewpos_f(void)
{
cgi.Printf("(%i %i %i) : %i\n", (int)cg.refdef.vieworg[0],
(int)cg.refdef.vieworg[1], (int)cg.refdef.vieworg[2],
(int)cg.refdefViewAngles[YAW]);
}
void CG_SetDesiredObjectiveAlpha(float fAlpha)
{
cg.ObjectivesDesiredAlpha = fAlpha;
cg.ObjectivesAlphaTime = (float)(cg.time + 250);
cg.ObjectivesBaseAlpha = cg.ObjectivesCurrentAlpha;
}
static void CG_ScoresDown_f( void ) {
void CG_ScoresDown_f( void )
{
if (cgs.gametype == GT_SINGLE_PLAYER)
{
if (!cg.scoresRequestTime) {
cg.scoresRequestTime = cg.time;
CG_SetDesiredObjectiveAlpha(1.0f);
}
if ( cg.scoresRequestTime + 1000 < cg.time ) {
// the scores are more than two seconds out of data,
// so request new ones
cg.scoresRequestTime = cg.time;
cgi.SendClientCommand( "score" );
return;
}
// leave the current scores up if they were already
// displayed, but if this is the first hit, clear them out
if ( !cg.showScores ) {
cg.showScores = qtrue;
cg.numScores = 0;
}
} else {
// show the cached contents even if they just pressed if it
// is within two seconds
if ( cg.scoresRequestTime + 2000 >= cg.time )
{
// send another request
cg.showScores = qtrue;
CG_PrepScoreBoardInfo();
cgi.UI_ShowScoreBoard(cg.scoresMenuName);
return;
}
cg.scoresRequestTime = cg.time;
cgi.SendClientCommand( "score" );
if ( !cg.showScores ) {
// don't display anything until first score returns
cg.showScores = qtrue;
CG_PrepScoreBoardInfo();
cgi.UI_ShowScoreBoard(cg.scoresMenuName);
}
cg.scoreBoardShowing = qtrue;
cgi.Cvar_Set( "ui_showscores", "1" );
}
static void CG_ScoresUp_f( void ) {
if ( cg.showScores ) {
cg.showScores = qfalse;
cg.scoreFadeTime = cg.time;
}
cg.scoreBoardShowing = qfalse;
cgi.Cvar_Set( "ui_showscores", "0" );
void CG_ScoresUp_f( void )
{
if (cgs.gametype == GT_SINGLE_PLAYER)
{
if (!cg.scoresRequestTime)
{
cg.scoresRequestTime = cg.time;
CG_SetDesiredObjectiveAlpha(0.0f);
}
return;
}
if (!cg.showScores) {
return;
}
cg.showScores = qfalse;
cgi.UI_HideScoreBoard(cg.scoresMenuName);
}
static void CG_TellTarget_f( void ) {
int clientNum;
char command[128];
char *message;
baseshader_t* CG_GetShaderUnderCrosshair(qboolean bVerbose, trace_t* pRetTrace)
{
vec3_t vPos, vEnd;
vec3_t axis[3];
baseshader_t* pShader;
trace_t trace;
clientNum = CG_CrosshairPlayer();
if ( clientNum == -1 ) {
return;
}
AnglesToAxis(cg.refdefViewAngles, axis);
vPos[0] = cg.refdef.vieworg[0];
vPos[1] = cg.refdef.vieworg[1];
vPos[2] = cg.refdef.vieworg[2];
VectorMA(vPos, 4096.0, axis[0], vEnd);
message = cgi.Args();
Com_sprintf( command, 128, "tell %i %s", clientNum, message );
cgi.SendClientCommand( command );
CG_Trace(&trace, vPos, vec3_origin, vec3_origin, vEnd, 0, MASK_SHOT, 0, 0, "CG_GetShaderUnderCrosshair");
if (trace.startsolid || trace.fraction == 1.0) {
return NULL;
}
if (bVerbose)
{
cgi.Printf(
"Surface hit at (%i %i %i)\n",
(int)trace.endpos[0],
(int)trace.endpos[1],
(int)trace.endpos[2]);
}
pShader = cgi.GetShader(trace.shaderNum);
if (pRetTrace) {
*pRetTrace = trace;
}
return pShader;
}
static void CG_TellAttacker_f( void ) {
int clientNum;
char command[128];
char *message;
clientNum = CG_LastAttacker();
if ( clientNum == -1 ) {
return;
}
message = cgi.Args();
Com_sprintf( command, 128, "tell %i %s", clientNum, message );
cgi.SendClientCommand( command );
static void CG_PrintContentTypes(int iContentFlags)
{
// FIXME: unimplemented
}
static void CG_PrintSurfaceProperties(int iSurfaceFlags)
{
// FIXME: unimplemented
}
static void CG_PrintSurfaceType(int iSurfType)
{
// FIXME: unimplemented
}
void CG_GetCHShader(void)
{
trace_t trace;
baseshader_t* pShader;
pShader = CG_GetShaderUnderCrosshair(qtrue, &trace);
cgi.Printf("\n");
if (pShader)
{
if (pShader->surfaceFlags & SURF_SKY)
{
cgi.Printf("Hit the sky\n");
}
else
{
cgi.Printf("Shader: %s\n", pShader->shader);
cgi.Printf("Shader Contents:");
CG_PrintContentTypes(pShader->contentFlags);
cgi.Printf("\n");
cgi.Printf("Shader Surface Properties:");
CG_PrintSurfaceProperties(pShader->surfaceFlags);
cgi.Printf("\n");
cgi.Printf("Shader Surfacetype: ");
CG_PrintSurfaceType(pShader->surfaceFlags);
cgi.Printf("\n");
cgi.Printf("Trace Contents:");
CG_PrintContentTypes(trace.contents);
cgi.Printf("\n");
cgi.Printf("Trace Surface Properties:");
CG_PrintSurfaceProperties(trace.surfaceFlags);
cgi.Printf("\n");
cgi.Printf("Trace Surfacetype: ");
CG_PrintSurfaceType(trace.surfaceFlags);
cgi.Printf("\n\n");
}
}
else
{
cgi.Printf("No surface selected\n");
}
}
void CG_EditCHShader(void)
{
char name[1024];
baseshader_t* pShader;
pShader = CG_GetShaderUnderCrosshair(qfalse, NULL);
if (pShader)
{
strcpy(name, "editspecificshader ");
strcat(name, pShader->shader);
strcat(name, "\n");
cgi.AddCommand(name);
}
else
{
cgi.Printf("No surface selected\n");
}
}
#if 0
/*
==================
CG_StartOrbit_f
==================
=============================================================================
MODEL TESTING
The viewthing and gun positioning tools from Q2 have been integrated and
enhanced into a single model testing facility.
Model viewing can begin with either "testmodel <modelname>" or "testgun <modelname>".
The names must be the full pathname after the basedir, like
"models/weapons/v_launch/tris.md3" or "players/male/tris.md3"
Testmodel will create a fake entity 100 units in front of the current view
position, directly facing the viewer. It will remain immobile, so you can
move around it to view it from different angles.
Testgun will cause the model to follow the player around and supress the real
view weapon model. The default frame 0 of most guns is completely off screen,
so you will probably have to cycle a couple frames to see it.
"nextframe", "prevframe", "nextskin", and "prevskin" commands will change the
frame or skin of the testmodel. These are bound to F5, F6, F7, and F8 in
q3default.cfg.
Note that none of the model testing features update while the game is paused, so
it may be convenient to test with deathmatch set to 1 so that bringing down the
console doesn't pause the game.
=============================================================================
*/
static void CG_StartOrbit_f( void ) {
char var[MAX_TOKEN_CHARS];
/*
=================
CG_TestModel_f
cgi.Cvar_VariableStringBuffer( "developer", var, sizeof( var ) );
if ( !atoi(var) ) {
return;
}
if (cg_cameraOrbit->value != 0) {
cgi.Cvar_Set ("cg_cameraOrbit", "0");
cgi.Cvar_Set("cg_thirdPerson", "0");
} else {
cgi.Cvar_Set("cg_cameraOrbit", "5");
cgi.Cvar_Set("cg_thirdPerson", "1");
cgi.Cvar_Set("cg_thirdPersonAngle", "0");
cgi.Cvar_Set("cg_thirdPersonRange", "100");
}
}
Creates an entity in front of the current position, which
can then be moved around
=================
*/
void CG_TestModel_f (void) {
vec3_t angles;
static void CG_LocationPrint_f(void) {
char *buffer;
int x,y;
buffer = cgi.Argv( 1 );
x = atoi(buffer);
buffer = cgi.Argv( 2 );
y = atoi(buffer);
buffer = cgi.Argv( 3 );
buffer[511] = 0;
CG_LocationPrint( buffer, x, y, SMALLCHAR_WIDTH );
}
// su44: in MoHAA, "useweaponclass pistol/rifle/etc"
// commands are usually bound to 1,2,3,4,5,6 keys
static void CG_UseWeaponClass_f(void) {
const char *name;
if(cgi.Argc() < 2) {
CG_Printf("usage: useweaponclass <weaponclassname>\n");
memset( &cg.testModelEntity, 0, sizeof(cg.testModelEntity) );
if ( cgi.Argc() < 2 ) {
return;
}
// get weapon classname
name = CG_Argv(1);
if(!Q_stricmp(name,"pistol")) {
cg.iWeaponCommand = 1;
} else if(!Q_stricmp(name,"rifle")) {
cg.iWeaponCommand = 2;
} else if(!Q_stricmp(name,"smg")) {
cg.iWeaponCommand = 3;
} else if(!Q_stricmp(name,"mg")) {
cg.iWeaponCommand = 4;
} else if(!Q_stricmp(name,"grenade")) {
cg.iWeaponCommand = 5;
} else if(!Q_stricmp(name,"heavy")) {
cg.iWeaponCommand = 6;
} else if(!Q_stricmp(name,"item2")) {
cg.iWeaponCommand = 8; // su44: AFAIK it's not used at all in MoHAA
} else if(!Q_stricmp(name,"item3")) {
cg.iWeaponCommand = 9; // su44: AFAIK it's not used at all in MoHAA
} else if(!Q_stricmp(name,"item4")) {
cg.iWeaponCommand = 10; // su44: AFAIK it's not used at all in MoHAA
} else if(!Q_stricmp(name,"item") || !Q_stricmp(name,"item1")) {
cg.iWeaponCommand = 7; // su44: I think it's used for "Papers" item
} else {
CG_Printf("useweaponclass: unknown weapon %s\n", name);
Q_strncpyz (cg.testModelName, cgi.Argv( 1 ), MAX_QPATH );
cg.testModelEntity.hModel = cgi.R_RegisterModel( cg.testModelName );
if ( cgi.Argc() == 3 ) {
cg.testModelEntity.backlerp = atof( cgi.Argv( 2 ) );
cg.testModelEntity.frame = 1;
cg.testModelEntity.oldframe = 0;
}
cg.iWeaponCommandSend = 0;
if (! cg.testModelEntity.hModel ) {
cgi.Printf( "Can't register model\n" );
return;
}
VectorMA( cg.refdef.vieworg, 100, cg.refdef.viewaxis[0], cg.testModelEntity.origin );
angles[PITCH] = 0;
angles[YAW] = 180 + cg.refdefViewAngles[1];
angles[ROLL] = 0;
AnglesToAxis( angles, cg.testModelEntity.axis );
cg.testGun = qfalse;
}
void CG_TestModelNextFrame_f (void) {
cg.testModelEntity.frame++;
cgi.Printf( "frame %i\n", cg.testModelEntity.frame );
}
void CG_TestModelPrevFrame_f (void) {
cg.testModelEntity.frame--;
cgi.Printf( "frame %i\n", cg.testModelEntity.frame );
}
void CG_TestModelNextSkin_f (void) {
cg.testModelEntity.skinNum++;
cgi.Printf( "skin %i\n", cg.testModelEntity.skinNum );
}
void CG_TestModelPrevSkin_f (void) {
cg.testModelEntity.skinNum--;
if ( cg.testModelEntity.skinNum < 0 ) {
cg.testModelEntity.skinNum = 0;
}
cgi.Printf( "skin %i\n", cg.testModelEntity.skinNum );
}
void CG_AddTestModel (void) {
// re-register the model, because the level may have changed
cg.testModelEntity.hModel = cgi.R_RegisterModel( cg.testModelName );
if (! cg.testModelEntity.hModel ) {
cgi.Printf ("Can't register model\n");
return;
}
cgi.R_AddRefEntityToScene( &cg.testModelEntity );
}
#endif
typedef struct {
char *cmd;
void (*function)(void);
char* cmd;
void (*function)(void);
} consoleCommand_t;
static consoleCommand_t commands[] = {
{ "testgun", CG_TestGun_f },
{ "testmodel", CG_TestModel_f },
{ "testmodelanim", CG_TestModelAnim_f },
{ "testmodelanimspeedscale", CG_TestModelAnimSpeedScale_f },
{ "nextframe", CG_TestModelNextFrame_f },
{ "prevframe", CG_TestModelPrevFrame_f },
{ "nextskin", CG_TestModelNextSkin_f },
{ "prevskin", CG_TestModelPrevSkin_f },
{ "viewpos", CG_Viewpos_f },
{ "+scores", CG_ScoresDown_f },
{ "-scores", CG_ScoresUp_f },
{ "+zoom", CG_ZoomDown_f },
{ "-zoom", CG_ZoomUp_f },
{ "sizeup", CG_SizeUp_f },
{ "sizedown", CG_SizeDown_f },
{ "weapnext", CG_NextWeapon_f },
{ "weapprev", CG_PrevWeapon_f },
{ "tell_target", CG_TellTarget_f },
{ "tell_attacker", CG_TellAttacker_f },
{ "tcmd", CG_TargetCommand_f },
{ "startOrbit", CG_StartOrbit_f },
//{ "camera", CG_Camera_f },
{ "locationprint", CG_LocationPrint_f },
// su44: MoHAA commands
{ "toggleitem", CG_ToggleItem_f },
{ "weapdrop", CG_DropWeapon_f },
{ "holster", CG_HolsterWeapon_f },
{ "weapnext", CG_NextWeapon_f },
{ "weapprev", CG_PrevWeapon_f },
{ "useweaponclass", CG_UseWeaponClass_f },
static consoleCommand_t commands[] = {
{ "useweaponclass", &CG_UseWeaponClass_f },
{ "weapnext", &CG_NextWeapon_f },
{ "weapprev", &CG_PrevWeapon_f },
{ "uselast", &CG_UseLastWeapon_f },
{ "holster", &CG_HolsterWeapon_f },
{ "weapdrop", &CG_DropWeapon_f },
{ "toggleitem", &CG_ToggleItem_f },
{ "+scores", &CG_ScoresDown_f },
{ "-scores", &CG_ScoresUp_f },
{ "viewpos", &CG_Viewpos_f },
{ "sizeup", &CG_SizeUp_f },
{ "sizedown", &CG_SizeDown_f },
{ "cg_eventlist", &CG_EventList_f },
{ "cg_eventhelp", &CG_EventHelp_f },
{ "cg_dumpevents", &CG_DumpEventHelp_f },
{ "cg_pendingevents", &CG_PendingEvents_f },
{ "cg_classlist", &CG_ClassList_f },
{ "cg_classtree", &CG_ClassTree_f },
{ "cg_classevents", &CG_ClassEvents_f },
{ "cg_dumpclassevents", &CG_DumpClassEvents_f },
{ "cg_dumpallclasses", &CG_DumpAllClasses_f },
{ "testemitter", &CG_TestEmitter_f },
{ "triggertestemitter", &CG_TriggerTestEmitter_f },
{ "prevemittercommand", &CG_PrevEmitterCommand_f },
{ "nextemittercommand", &CG_NextEmitterCommand_f },
{ "newemittercommand", &CG_NewEmitterCommand_f },
{ "deleteemittercommand", &CG_DeleteEmitterCommand_f },
{ "dumpemitter", &CG_DumpEmitter_f },
{ "loademitter", &CG_LoadEmitter_f },
{ "resetvss", &CG_ResetVSSSources },
{ "getchshader", &CG_GetCHShader },
{ "editchshader", &CG_EditCHShader },
{ "messagemode", &CG_MessageMode_f },
{ "messagemode_all", &CG_MessageMode_All_f },
{ "messagemode_team", &CG_MessageMode_Team_f },
{ "messagemode_private", &CG_MessageMode_Private_f },
{ "say", &CG_MessageSingleAll_f },
{ "sayteam", &CG_MessageSingleTeam_f },
{ "teamsay", &CG_MessageSingleTeam_f },
{ "sayprivate", &CG_MessageSingleClient_f },
{ "sayone", &CG_MessageSingleClient_f },
{ "wisper", &CG_MessageSingleClient_f },
{ "instamsg_main", &CG_InstaMessageMain_f },
{ "instamsg_group_a", &CG_InstaMessageGroupA_f },
{ "instamsg_group_b", &CG_InstaMessageGroupB_f },
{ "instamsg_group_c", &CG_InstaMessageGroupC_f },
{ "instamsg_group_d", &CG_InstaMessageGroupD_f },
{ "instamsg_group_e", &CG_InstaMessageGroupE_f },
{ "pushmenu_teamselect", &CG_PushMenuTeamSelect_f },
{ "pushmenu_weaponselect", &CG_PushMenuWeaponSelect_f },
};
/*
=================
CG_ConsoleCommand
@@ -263,23 +413,23 @@ The string has been tokenized and can be retrieved with
Cmd_Argc() / Cmd_Argv()
=================
*/
qboolean CG_ConsoleCommand( void ) {
const char *cmd;
int i;
qboolean CG_ConsoleCommand(void)
{
const char* cmd;
int i;
cmd = CG_Argv(0);
cmd = cgi.Argv(0);
for ( i = 0 ; i < sizeof( commands ) / sizeof( commands[0] ) ; i++ ) {
if ( !Q_stricmp( cmd, commands[i].cmd ) ) {
commands[i].function();
return qtrue;
}
}
for (i = 0; i < sizeof(commands) / sizeof(commands[0]); i++) {
if (!Q_stricmp(cmd, commands[i].cmd)) {
commands[i].function();
return qtrue;
}
}
return qfalse;
return qfalse;
}
/*
=================
CG_InitConsoleCommands
@@ -288,49 +438,135 @@ Let the client system know about all of our commands
so it can perform tab completion
=================
*/
void CG_InitConsoleCommands( void ) {
int i;
void CG_InitConsoleCommands(void)
{
int i;
for ( i = 0 ; i < sizeof( commands ) / sizeof( commands[0] ) ; i++ ) {
cgi.AddCommand( commands[i].cmd, NULL );
}
for (i = 0; i < sizeof(commands) / sizeof(commands[0]); i++) {
cgi.AddCommand(commands[i].cmd);
}
//
// the game server will interpret these commands, which will be automatically
// forwarded to the server after they are not recognized locally
//
// wombat: mohaa servers understand the following
cgi.AddCommand( "dog", NULL ); // Sets the god mode cheat or toggles it.
cgi.AddCommand ("notarget", NULL ); // Toggles the notarget cheat.
cgi.AddCommand ("noclip", NULL ); // Toggles the noclip cheat.
cgi.AddCommand ("weapdrop", NULL ); // Drops the player's current weapon.
cgi.AddCommand ("reload", NULL ); // Reloads the player's weapon
cgi.AddCommand ("give", NULL ); // Gives the player the specified thing (weapon, ammo, item, etc.) and optionally the amount.
cgi.AddCommand ("jump", NULL ); // Makes the player jump.
cgi.AddCommand ("holster", NULL ); // Holsters all wielded weapons, or unholsters previously put away weapons
// su44
cgi.AddCommand ("join_team", NULL ); // Join the specified team (allies or axis)
cgi.AddCommand ("auto_join_team", NULL ); // Join the team with fewer players
cgi.AddCommand ("spectator", NULL ); // Become a spectator
// wombat: mohaa arena what is that???
cgi.AddCommand ("join_arena", NULL ); // Join the specified arena
cgi.AddCommand ("leave_arena", NULL ); // Leave the current arena
cgi.AddCommand ("create_team", NULL ); // Create a team in the current arena
cgi.AddCommand ("leave_team", NULL ); // Leave the current team
cgi.AddCommand ("arena_ui", NULL ); // Refresh the arena UI
cgi.AddCommand ("callvote", NULL ); // Player calls a vote
cgi.AddCommand ("vote", NULL ); // Player votes either yes or no
cgi.AddCommand ("primarydmweapon", NULL ); // Sets the player's primary DM weapon
// primarydmweapon rifle / smg / mg / heavy / shotgun
cgi.AddCommand ("kill", NULL );
cgi.AddCommand ("say", NULL );
cgi.AddCommand ("sayone", NULL ); // talk to one client
cgi.AddCommand ("sayprivate", NULL ); // same as sayone??
cgi.AddCommand ("sayteam", NULL ); // talk to team
cgi.AddCommand ("teamsay", NULL ); // talk to team
cgi.AddCommand("callvote");
cgi.AddCommand("vote");
}
void CG_Mapinfo_f(void)
{
cgi.Printf("---------------------\n");
cgi.R_PrintBSPFileSizes();
cgi.CM_PrintBSPFileSizes();
cgi.Printf("---------------------\n");
}
void CG_PushMenuTeamSelect_f(void)
{
if (cgs.gametype == GT_SINGLE_PLAYER) {
return;
}
cgi.Cmd_Execute(EXEC_NOW, "ui_getplayermodel\n");
switch (cgs.gametype) {
case GT_FFA:
cgi.Cmd_Execute(EXEC_NOW, "pushmenu SelectFFAModel\n");
break;
case GT_OBJECTIVE:
cgi.Cmd_Execute(EXEC_NOW, "pushmenu ObjSelectTeam\n");
break;
default:
cgi.Cmd_Execute(EXEC_NOW, "pushmenu SelectTeam\n");
break;
}
}
void CG_PushMenuWeaponSelect_f(void)
{
if (cgs.gametype == GT_SINGLE_PLAYER) {
return;
}
cgi.Cmd_Execute(EXEC_NOW, "pushmenu SelectPrimaryWeapon\n");
}
void CG_UseWeaponClass_f(void)
{
const char* cmd;
cmd = cgi.Argv(1);
if (!Q_stricmp(cmd, "pistol")) {
cg.iWeaponCommand = WEAPON_COMMAND_USE_PISTOL;
} else if (!Q_stricmp(cmd, "rifle")) {
cg.iWeaponCommand = WEAPON_COMMAND_USE_RIFLE;
} else if (!Q_stricmp(cmd, "smg")) {
cg.iWeaponCommand = WEAPON_COMMAND_USE_SMG;
} else if (!Q_stricmp(cmd, "mg")) {
cg.iWeaponCommand = WEAPON_COMMAND_USE_MG;
} else if (!Q_stricmp(cmd, "grenade")) {
cg.iWeaponCommand = WEAPON_COMMAND_USE_GRENADE;
} else if (!Q_stricmp(cmd, "heavy")) {
cg.iWeaponCommand = WEAPON_COMMAND_USE_HEAVY;
} else if (!Q_stricmp(cmd, "item1") || !Q_stricmp(cmd, "item")) {
cg.iWeaponCommand = WEAPON_COMMAND_USE_ITEM1;
} else if (!Q_stricmp(cmd, "item2")) {
cg.iWeaponCommand = WEAPON_COMMAND_USE_ITEM2;
} else if (!Q_stricmp(cmd, "item3")) {
cg.iWeaponCommand = WEAPON_COMMAND_USE_ITEM3;
} else if (!Q_stricmp(cmd, "item4")) {
cg.iWeaponCommand = WEAPON_COMMAND_USE_ITEM4;
}
cg.iWeaponCommandSend = 0;
}
void CG_NextWeapon_f(void)
{
cg.iWeaponCommand = WEAPON_COMMAND_USE_NEXT_WEAPON;
cg.iWeaponCommandSend = 0;
}
void CG_PrevWeapon_f(void)
{
cg.iWeaponCommand = WEAPON_COMMAND_USE_PREV_WEAPON;
cg.iWeaponCommandSend = 0;
}
void CG_UseLastWeapon_f(void)
{
cg.iWeaponCommand = WEAPON_COMMAND_USE_LAST_WEAPON;
cg.iWeaponCommandSend = 0;
}
void CG_HolsterWeapon_f(void)
{
cg.iWeaponCommand = WEAPON_COMMAND_HOLSTER;
cg.iWeaponCommandSend = 0;
}
void CG_DropWeapon_f(void)
{
cg.iWeaponCommand = WEAPON_COMMAND_DROP;
cg.iWeaponCommandSend = 0;
}
void CG_ToggleItem_f(void)
{
cg.iWeaponCommand = WEAPON_COMMAND_USE_ITEM1;
cg.iWeaponCommandSend = 0;
}
int CG_WeaponCommandButtonBits(void)
{
int iShiftedWeaponCommand;
iShiftedWeaponCommand = cg.iWeaponCommand;
if (!iShiftedWeaponCommand) {
return 0;
}
cg.iWeaponCommandSend++;
if (cg.iWeaponCommandSend > 2) {
cg.iWeaponCommand = 0;
}
return (iShiftedWeaponCommand << 7) & WEAPON_COMMAND_MASK;
}
-1576
View File
File diff suppressed because it is too large. Load diff
-245
View File
@@ -1,245 +0,0 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
This file is part of Quake III Arena source code.
Quake III Arena source code is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the License,
or (at your option) any later version.
Quake III Arena source code is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Quake III Arena source code; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
//
// cg_drawtools.c -- helper functions called by cg_draw, cg_scoreboard, cg_info, etc
#include "cg_local.h"
/*
================
CG_AdjustFrom640
Adjusted for resolution and screen aspect ratio
================
*/
void CG_AdjustFrom640( float *x, float *y, float *w, float *h ) {
#if 0
// adjust for wide screens
if ( cgs.glconfig.vidWidth * 480 > cgs.glconfig.vidHeight * 640 ) {
*x += 0.5 * ( cgs.glconfig.vidWidth - ( cgs.glconfig.vidHeight * 640 / 480 ) );
}
#endif
// scale for screen sizes
*x *= cgs.screenXScale;
*y *= cgs.screenYScale;
*w *= cgs.screenXScale;
*h *= cgs.screenYScale;
}
/*
================
CG_FillRect
Coordinates are 640*480 virtual values
=================
*/
void CG_FillRect( float x, float y, float width, float height, const float *color ) {
cgi.R_SetColor( color );
CG_AdjustFrom640( &x, &y, &width, &height );
cgi.R_DrawStretchPic( x, y, width, height, 0, 0, 0, 0, cgs.media.whiteShader );
cgi.R_SetColor( NULL );
}
/*
================
CG_DrawSides
Coords are virtual 640x480
================
*/
void CG_DrawSides(float x, float y, float w, float h, float size) {
CG_AdjustFrom640( &x, &y, &w, &h );
size *= cgs.screenXScale;
cgi.R_DrawStretchPic( x, y, size, h, 0, 0, 0, 0, cgs.media.whiteShader );
cgi.R_DrawStretchPic( x + w - size, y, size, h, 0, 0, 0, 0, cgs.media.whiteShader );
}
void CG_DrawTopBottom(float x, float y, float w, float h, float size) {
CG_AdjustFrom640( &x, &y, &w, &h );
size *= cgs.screenYScale;
cgi.R_DrawStretchPic( x, y, w, size, 0, 0, 0, 0, cgs.media.whiteShader );
cgi.R_DrawStretchPic( x, y + h - size, w, size, 0, 0, 0, 0, cgs.media.whiteShader );
}
/*
================
UI_DrawRect
Coordinates are 640*480 virtual values
=================
*/
void CG_DrawRect( float x, float y, float width, float height, float size, const float *color ) {
cgi.R_SetColor( color );
CG_DrawTopBottom(x, y, width, height, size);
CG_DrawSides(x, y, width, height, size);
cgi.R_SetColor( NULL );
}
/*
================
CG_DrawPic
Coordinates are 640*480 virtual values
=================
*/
void CG_DrawPic( float x, float y, float width, float height, qhandle_t hShader ) {
CG_AdjustFrom640( &x, &y, &width, &height );
cgi.R_DrawStretchPic( x, y, width, height, 0, 0, 1, 1, hShader );
}
/*
=================
CG_DrawStrlen
Returns character count, skiping color escape codes
=================
*/
int CG_DrawStrlen( const char *str ) {
const char *s = str;
int count = 0;
// while ( *s ) {
// if ( Q_IsColorString( s ) ) {
// s += 2;
// } else {
// count++;
// s++;
// }
// }
return cgi.R_Text_Width( &cgs.media.verdana, str, -1, qtrue );
}
/*
=============
CG_TileClearBox
This repeats a 64*64 tile graphic to fill the screen around a sized down
refresh window.
=============
*/
static void CG_TileClearBox( int x, int y, int w, int h, qhandle_t hShader ) {
float s1, t1, s2, t2;
s1 = x/64.0;
t1 = y/64.0;
s2 = (x+w)/64.0;
t2 = (y+h)/64.0;
cgi.R_DrawStretchPic( x, y, w, h, s1, t1, s2, t2, hShader );
}
/*
==============
CG_TileClear
Clear around a sized down screen
==============
*/
void CG_TileClear( void ) {
int top, bottom, left, right;
int w, h;
w = cgs.glconfig.vidWidth;
h = cgs.glconfig.vidHeight;
if ( cg.refdef.x == 0 && cg.refdef.y == 0 &&
cg.refdef.width == w && cg.refdef.height == h ) {
return; // full screen rendering
}
top = cg.refdef.y;
bottom = top + cg.refdef.height-1;
left = cg.refdef.x;
right = left + cg.refdef.width-1;
// clear above view screen
CG_TileClearBox( 0, 0, w, top, cgs.media.backTileShader );
// clear below view screen
CG_TileClearBox( 0, bottom, w, h - bottom, cgs.media.backTileShader );
// clear left of view screen
CG_TileClearBox( 0, top, left, bottom - top + 1, cgs.media.backTileShader );
// clear right of view screen
CG_TileClearBox( right, top, w - right, bottom - top + 1, cgs.media.backTileShader );
}
/*
================
CG_FadeColor
================
*/
float *CG_FadeColor( int startMsec, int totalMsec ) {
static vec4_t color;
int t;
if ( startMsec == 0 ) {
return NULL;
}
t = cg.time - startMsec;
if ( t >= totalMsec ) {
return NULL;
}
// fade out
if ( totalMsec - t < FADE_TIME ) {
color[3] = ( totalMsec - t ) * 1.0/FADE_TIME;
} else {
color[3] = 1.0;
}
color[0] = color[1] = color[2] = 1;
return color;
}
/*
==================
CG_DrawStringExt
Draws a multi-colored string with a drop shadow, optionally forcing
to a fixed color.
Coordinates are at 640 by 480 virtual resolution
==================
*/
void CG_DrawStringExt( int x, int y, const char *string, const float *setColor,
qboolean forceColor, qboolean shadow, int charWidth, int charHeight, int maxChars ) {
if(string == 0 || string[0] == 0)
return;
cgi.R_SetColor(setColor);
cgi.R_Text_Paint(&cgs.media.verdana, x, y, 1, 1, string, 0, maxChars, qfalse, qfalse);
}
void CG_DrawBigString( int x, int y, const char *s, float alpha ) {
float color[4];
color[0] = color[1] = color[2] = 1.0;
color[3] = alpha;
CG_DrawStringExt( x, y, s, color, qfalse, qtrue, BIGCHAR_WIDTH, BIGCHAR_HEIGHT, 0 );
}
File diff suppressed because it is too large. Load diff
-453
View File
@@ -1,453 +0,0 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
This file is part of Quake III Arena source code.
Quake III Arena source code is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the License,
or (at your option) any later version.
Quake III Arena source code is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Quake III Arena source code; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
//
// cg_effects.c -- these functions generate localentities, usually as a result
// of event processing
#include "cg_local.h"
/*
==================
CG_BubbleTrail
Bullets shot underwater
==================
*/
void CG_BubbleTrail( vec3_t start, vec3_t end, float spacing ) {
//vec3_t move;
//vec3_t vec;
//float len;
//int i;
//if ( cg_noProjectileTrail->integer ) {
// return;
//}
//VectorCopy (start, move);
//VectorSubtract (end, start, vec);
//len = VectorNormalize (vec);
//// advance a random amount first
//i = rand() % (int)spacing;
//VectorMA( move, i, vec, move );
//VectorScale (vec, spacing, vec);
//for ( ; i < len; i += spacing ) {
// localEntity_t *le;
// refEntity_t *re;
// le = CG_AllocLocalEntity();
// le->leFlags = LEF_PUFF_DONT_SCALE;
// le->leType = LE_MOVE_SCALE_FADE;
// le->startTime = cg.time;
// le->endTime = cg.time + 1000 + random() * 250;
// le->lifeRate = 1.0 / ( le->endTime - le->startTime );
// re = &le->refEntity;
// re->shaderTime = cg.time / 1000.0f;
// re->reType = RT_SPRITE;
// re->rotation = 0;
// re->radius = 3;
// re->customShader = cgs.media.waterBubbleShader;
// re->shaderRGBA[0] = 0xff;
// re->shaderRGBA[1] = 0xff;
// re->shaderRGBA[2] = 0xff;
// re->shaderRGBA[3] = 0xff;
// le->color[3] = 1.0;
// le->pos.trType = TR_LINEAR;
// le->pos.trTime = cg.time;
// VectorCopy( move, le->pos.trBase );
// le->pos.trDelta[0] = crandom()*5;
// le->pos.trDelta[1] = crandom()*5;
// le->pos.trDelta[2] = crandom()*5 + 6;
// VectorAdd (move, vec, move);
//}
}
/*
=====================
CG_SmokePuff
Adds a smoke puff or blood trail localEntity.
=====================
*/
localEntity_t *CG_SmokePuff( const vec3_t p, const vec3_t vel,
float radius,
float r, float g, float b, float a,
float duration,
int startTime,
int fadeInTime,
int leFlags,
qhandle_t hShader ) {
// static int seed = 0x92;
// localEntity_t *le;
// refEntity_t *re;
//// int fadeInTime = startTime + duration / 2;
//
// le = CG_AllocLocalEntity();
// le->leFlags = leFlags;
// le->radius = radius;
//
// re = &le->refEntity;
// re->rotation = Q_random( &seed ) * 360;
// re->radius = radius;
// re->shaderTime = startTime / 1000.0f;
//
// le->leType = LE_MOVE_SCALE_FADE;
// le->startTime = startTime;
// le->fadeInTime = fadeInTime;
// le->endTime = startTime + duration;
// if ( fadeInTime > startTime ) {
// le->lifeRate = 1.0 / ( le->endTime - le->fadeInTime );
// }
// else {
// le->lifeRate = 1.0 / ( le->endTime - le->startTime );
// }
// le->color[0] = r;
// le->color[1] = g;
// le->color[2] = b;
// le->color[3] = a;
//
//
// le->pos.trType = TR_LINEAR;
// le->pos.trTime = startTime;
// VectorCopy( vel, le->pos.trDelta );
// VectorCopy( p, le->pos.trBase );
//
// VectorCopy( p, re->origin );
// re->customShader = hShader;
//
// // rage pro can't alpha fade, so use a different shader
// if ( cgs.glconfig.hardwareType == GLHW_RAGEPRO ) {
// re->customShader = cgs.media.smokePuffRageProShader;
// re->shaderRGBA[0] = 0xff;
// re->shaderRGBA[1] = 0xff;
// re->shaderRGBA[2] = 0xff;
// re->shaderRGBA[3] = 0xff;
// } else {
// re->shaderRGBA[0] = le->color[0] * 0xff;
// re->shaderRGBA[1] = le->color[1] * 0xff;
// re->shaderRGBA[2] = le->color[2] * 0xff;
// re->shaderRGBA[3] = 0xff;
// }
//
// re->reType = RT_SPRITE;
// re->radius = le->radius;
//
// return le;
return 0;
}
/*
==================
CG_ScorePlum
==================
*/
void CG_ScorePlum( int client, vec3_t org, int score ) {
localEntity_t *le;
refEntity_t *re;
vec3_t angles;
static vec3_t lastPos;
// only visualize for the client that scored
if (client != cg.predictedPlayerState.clientNum || cg_scorePlum->integer == 0) {
return;
}
le = CG_AllocLocalEntity();
le->leFlags = 0;
le->leType = LE_SCOREPLUM;
le->startTime = cg.time;
le->endTime = cg.time + 4000;
le->lifeRate = 1.0 / ( le->endTime - le->startTime );
le->color[0] = le->color[1] = le->color[2] = le->color[3] = 1.0;
le->radius = score;
VectorCopy( org, le->pos.trDelta );
if (org[2] >= lastPos[2] - 20 && org[2] <= lastPos[2] + 20) {
le->pos.trDelta[ 2 ] -= 20;
}
//CG_Printf( "Plum origin %i %i %i -- %i\n", (int)org[0], (int)org[1], (int)org[2], (int)Distance(org, lastPos));
VectorCopy(org, lastPos);
re = &le->refEntity;
re->reType = RT_SPRITE;
re->radius = 16;
VectorClear(angles);
AnglesToAxis( angles, re->axis );
}
/*
====================
CG_MakeExplosion
====================
*/
localEntity_t *CG_MakeExplosion( vec3_t origin, vec3_t dir,
qhandle_t hModel, qhandle_t shader,
int msec, qboolean isSprite ) {
float ang;
localEntity_t *ex;
int offset;
vec3_t tmpVec, newOrigin;
if ( msec <= 0 ) {
CG_Error( "CG_MakeExplosion: msec = %i", msec );
}
// skew the time a bit so they aren't all in sync
offset = rand() & 63;
ex = CG_AllocLocalEntity();
if ( isSprite ) {
ex->leType = LE_SPRITE_EXPLOSION;
// randomly rotate sprite orientation
ex->refEntity.rotation = rand() % 360;
VectorScale( dir, 16, tmpVec );
VectorAdd( tmpVec, origin, newOrigin );
} else {
ex->leType = LE_EXPLOSION;
VectorCopy( origin, newOrigin );
// set axis with random rotate
if ( !dir ) {
AxisClear( ex->refEntity.axis );
} else {
ang = rand() % 360;
VectorCopy( dir, ex->refEntity.axis[0] );
RotateAroundDirection( ex->refEntity.axis, ang );
}
}
ex->startTime = cg.time - offset;
ex->endTime = ex->startTime + msec;
// bias the time so all shader effects start correctly
ex->refEntity.shaderTime = ex->startTime / 1000.0f;
ex->refEntity.model = hModel;
ex->refEntity.customShader = shader;
// set origin
VectorCopy( newOrigin, ex->refEntity.origin );
VectorCopy( newOrigin, ex->refEntity.oldorigin );
ex->color[0] = ex->color[1] = ex->color[2] = 1.0;
return ex;
}
/*
=================
CG_Bleed
This is the spurt of blood when a character gets hit
=================
*/
void CG_Bleed( vec3_t origin, int entityNum ) {
localEntity_t *ex;
if ( !cg_blood->integer ) {
return;
}
ex = CG_AllocLocalEntity();
ex->leType = LE_EXPLOSION;
ex->startTime = cg.time;
ex->endTime = ex->startTime + 500;
VectorCopy ( origin, ex->refEntity.origin);
ex->refEntity.reType = RT_SPRITE;
ex->refEntity.rotation = rand() % 360;
ex->refEntity.radius = 24;
ex->refEntity.customShader = 0; //cgs.media.bloodExplosionShader;
// don't show player's own blood in view
if ( entityNum == cg.snap->ps.clientNum ) {
ex->refEntity.renderfx |= RF_THIRD_PERSON;
}
}
/*
==================
CG_LaunchGib
==================
*/
void CG_LaunchGib( vec3_t origin, vec3_t velocity, qhandle_t hModel ) {
localEntity_t *le;
refEntity_t *re;
le = CG_AllocLocalEntity();
re = &le->refEntity;
le->leType = LE_FRAGMENT;
le->startTime = cg.time;
le->endTime = le->startTime + 5000 + random() * 3000;
VectorCopy( origin, re->origin );
AxisCopy( axisDefault, re->axis );
re->model = hModel;
VectorCopy( origin, le->pos.trDelta );
VectorCopy( velocity, le->pos.trDelta );
le->pos.trTime = cg.time;
le->bounceFactor = 0.6f;
le->leBounceSoundType = LEBS_BLOOD;
le->leMarkType = LEMT_BLOOD;
}
/*
===================
CG_GibPlayer
Generated a bunch of gibs launching out from the bodies location
===================
*/
#define GIB_VELOCITY 250
#define GIB_JUMP 250
void CG_GibPlayer( vec3_t playerOrigin ) {
//vec3_t origin, velocity;
//if ( !cg_blood->integer ) {
// return;
//}
//VectorCopy( playerOrigin, origin );
//velocity[0] = crandom()*GIB_VELOCITY;
//velocity[1] = crandom()*GIB_VELOCITY;
//velocity[2] = GIB_JUMP + crandom()*GIB_VELOCITY;
//if ( rand() & 1 ) {
// CG_LaunchGib( origin, velocity, cgs.media.gibSkull );
//} else {
// CG_LaunchGib( origin, velocity, cgs.media.gibBrain );
//}
//// allow gibs to be turned off for speed
//if ( !cg_gibs->integer ) {
// return;
//}
//VectorCopy( playerOrigin, origin );
//velocity[0] = crandom()*GIB_VELOCITY;
//velocity[1] = crandom()*GIB_VELOCITY;
//velocity[2] = GIB_JUMP + crandom()*GIB_VELOCITY;
//CG_LaunchGib( origin, velocity, cgs.media.gibAbdomen );
//VectorCopy( playerOrigin, origin );
//velocity[0] = crandom()*GIB_VELOCITY;
//velocity[1] = crandom()*GIB_VELOCITY;
//velocity[2] = GIB_JUMP + crandom()*GIB_VELOCITY;
//CG_LaunchGib( origin, velocity, cgs.media.gibArm );
//VectorCopy( playerOrigin, origin );
//velocity[0] = crandom()*GIB_VELOCITY;
//velocity[1] = crandom()*GIB_VELOCITY;
//velocity[2] = GIB_JUMP + crandom()*GIB_VELOCITY;
//CG_LaunchGib( origin, velocity, cgs.media.gibChest );
//VectorCopy( playerOrigin, origin );
//velocity[0] = crandom()*GIB_VELOCITY;
//velocity[1] = crandom()*GIB_VELOCITY;
//velocity[2] = GIB_JUMP + crandom()*GIB_VELOCITY;
//CG_LaunchGib( origin, velocity, cgs.media.gibFist );
//VectorCopy( playerOrigin, origin );
//velocity[0] = crandom()*GIB_VELOCITY;
//velocity[1] = crandom()*GIB_VELOCITY;
//velocity[2] = GIB_JUMP + crandom()*GIB_VELOCITY;
//CG_LaunchGib( origin, velocity, cgs.media.gibFoot );
//VectorCopy( playerOrigin, origin );
//velocity[0] = crandom()*GIB_VELOCITY;
//velocity[1] = crandom()*GIB_VELOCITY;
//velocity[2] = GIB_JUMP + crandom()*GIB_VELOCITY;
//CG_LaunchGib( origin, velocity, cgs.media.gibForearm );
//VectorCopy( playerOrigin, origin );
//velocity[0] = crandom()*GIB_VELOCITY;
//velocity[1] = crandom()*GIB_VELOCITY;
//velocity[2] = GIB_JUMP + crandom()*GIB_VELOCITY;
//CG_LaunchGib( origin, velocity, cgs.media.gibIntestine );
//VectorCopy( playerOrigin, origin );
//velocity[0] = crandom()*GIB_VELOCITY;
//velocity[1] = crandom()*GIB_VELOCITY;
//velocity[2] = GIB_JUMP + crandom()*GIB_VELOCITY;
//CG_LaunchGib( origin, velocity, cgs.media.gibLeg );
//VectorCopy( playerOrigin, origin );
//velocity[0] = crandom()*GIB_VELOCITY;
//velocity[1] = crandom()*GIB_VELOCITY;
//velocity[2] = GIB_JUMP + crandom()*GIB_VELOCITY;
//CG_LaunchGib( origin, velocity, cgs.media.gibLeg );
}
/*
==================
CG_LaunchGib
==================
*/
void CG_LaunchExplode( vec3_t origin, vec3_t velocity, qhandle_t hModel ) {
localEntity_t *le;
refEntity_t *re;
le = CG_AllocLocalEntity();
re = &le->refEntity;
le->leType = LE_FRAGMENT;
le->startTime = cg.time;
le->endTime = le->startTime + 10000 + random() * 6000;
VectorCopy( origin, re->origin );
AxisCopy( axisDefault, re->axis );
re->model = hModel;
VectorCopy( origin, le->pos.trDelta );
VectorCopy( velocity, le->pos.trDelta );
le->pos.trTime = cg.time;
le->bounceFactor = 0.1f;
le->leBounceSoundType = LEBS_BRASS;
le->leMarkType = LEMT_NONE;
}
+492 -375
View File
File diff suppressed because it is too large. Load diff
@@ -1,6 +1,6 @@
/*
===========================================================================
Copyright (C) 2015 the OpenMoHAA team
Copyright (C) 2023 the OpenMoHAA team
This file is part of OpenMoHAA source code.
@@ -20,15 +20,20 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
typedef struct UIBindButton_s {
UIButton baseClass;
str m_bindcommand;
int m_bindindex;
qboolean m_getkey;
qboolean m_alternate;
str m_entersound;
str m_activesound;
str m_last_keyname;
UIReggedMaterial *m_mat;
} UIBindButton;
// DESCRIPTION:
// handle entity events at snapshot or playerstate transitions
#include "cg_local.h"
/*
==============
CG_EntityEvent
An entity has an event value
==============
*/
void CG_EntityEvent( centity_t *cent, vec3_t position )
{
}
-613
View File
@@ -1,613 +0,0 @@
/*
===========================================================================
Copyright (C) 2011 su44
This file is part of OpenMoHAA source code.
OpenMoHAA source code is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the License,
or (at your option) any later version.
OpenMoHAA source code is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with OpenMoHAA source code; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
// cg_eventSystem.c
#include "cg_local.h"
#include "../qcommon/tiki_local.h"
typedef struct event_s {
centity_t *ent;
char buffer[1024];
int execTime; // event should be executed and fried if cg.time >= ev->execTime
struct event_s *next,*prev; // linked list
} event_t;
#define MAX_PENDING_EVENTS 512
static event_t events[MAX_PENDING_EVENTS];
static event_t cg_pendingEvents; // double linked list
static event_t *cg_freeEvents; // single linked list
void CG_InitEventSystem() {
int i;
memset( events, 0, sizeof( events ) );
cg_pendingEvents.next = &cg_pendingEvents;
cg_pendingEvents.prev = &cg_pendingEvents;
cg_freeEvents = events;
for ( i = 0 ; i < MAX_PENDING_EVENTS - 1 ; i++ ) {
events[i].next = &events[i+1];
}
}
/*
Generates a random float component for MoHAA events.
If random is specified, the component will range from 0 to specified value.
If crandom is specified, the component will range from -specified to +specified value.
If range is specified, the component needs two values; it will randomly pick a number in the range
from the first number to the first number plus the second number.
This is used by "randvel", "randvelaxis", "offset", "offsetalongaxis", "angles", MoHAA events
*/
float CG_ParseEventFloatParm(char **text) {
char *token;
float value;
token = COM_ParseExt( text, qfalse );
if(!Q_stricmp(token,"random")) {
token = COM_ParseExt( text, qfalse );
value = random()*atof(token);
} else if(!Q_stricmp(token,"crandom")) {
token = COM_ParseExt( text, qfalse );
value = crandom()*atof(token);
} else if(!Q_stricmp(token,"range")) {
float range;
token = COM_ParseExt( text, qfalse );
value = atof(token);
token = COM_ParseExt( text, qfalse );
range = atof(token);
value += random()*range;
} else {
#if 0
CG_Printf("CG_ParseEventFloatParm: unknown first parm, expected 'random', 'crandom' or 'range', found %s\n",token);
value = 0;
#else
value = atof(token);
#endif
}
return value;
}
// this is used by both "tagspawn" and "originspawn" events
void CG_ProcessSpawnEvent(centity_t *ent, vec3_t spawnOrigin, vec3_t spawnAngles, char *text) {
char *token;
qhandle_t h;
tiki_t *tiki;
vec3_t v;
localEntity_t *le;
char *dot;
// skip optional paramter(s) ? see rechamber anim of weapons/kar98.tik
do {
token = COM_ParseExt( &text, qtrue );
if(token[0]==0) {
CG_Printf("'***spawn' event without parameters block\n");
return;
}
} while(token[0] != '(');
if(token[1] == 0) {
token = COM_ParseExt( &text, qtrue );
} else {
token++;
}
le = CG_AllocLocalEntity();
le->endTime = cg.time + 10000;
le->leType = LE_SKIP;
//le->leFlags = LEF_TUMBLE;
le->pos.trTime = cg.time - (rand()&15);
VectorCopy( spawnOrigin, le->pos.trDelta );
VectorCopy(spawnOrigin,le->refEntity.origin);
VectorCopy( spawnAngles, le->angles.trDelta );
AnglesToAxis(spawnAngles,le->refEntity.axis);
tiki = le->tiki;
// parse parameters ( ... ) block
while(token[0] != ')') {
if(token[0]==0) {
CG_Printf("'***spawn' missing ')' in tiki %s\n",tiki->name);
return;
}
Q_strlwr(token);
if(!strcmp(token,"spawnrange")) {
token = COM_ParseExt( &text, qtrue );
} else if(!strcmp(token,"spawnrate")) {
token = COM_ParseExt( &text, qtrue );
} else if(!strcmp(token,"count")) {
token = COM_ParseExt( &text, qtrue );
} else if(!strcmp(token,"model")) {
// both .tik and .spr models are used here
token = COM_ParseExt( &text, qtrue );
h = cgi.R_RegisterModel(token);
le->refEntity.model = h;
le->leType = LE_FRAGMENT;
dot = strchr(token,'.');
if(dot && !Q_stricmp(dot+1,"tik")) {
le->tiki = cgi.TIKI_RegisterModel(token);
}
} else if(!strcmp(token,"color")) {
token = COM_ParseExt( &text, qfalse );
token = COM_ParseExt( &text, qfalse );
token = COM_ParseExt( &text, qfalse );
} else if(!strcmp(token,"varycolor")) {
token = COM_ParseExt( &text, qfalse );
} else if(!strcmp(token,"alpha")) {
token = COM_ParseExt( &text, qfalse );
} else if(!strcmp(token,"offset")) {
token = COM_ParseExt( &text, qfalse ); // x
token = COM_ParseExt( &text, qfalse ); // y
token = COM_ParseExt( &text, qfalse ); // z
} else if(!strcmp(token,"offsetalongaxis")) {
v[0] = CG_ParseEventFloatParm(&text); // x
v[1] = CG_ParseEventFloatParm(&text); // y
v[2] = CG_ParseEventFloatParm(&text); // z
} else if(!strcmp(token,"randvelaxis")) {
v[0] = CG_ParseEventFloatParm(&text); // x
v[1] = CG_ParseEventFloatParm(&text); // y
v[2] = CG_ParseEventFloatParm(&text); // z
} else if(!strcmp(token,"scale")) {
token = COM_ParseExt( &text, qtrue );
} else if(!strcmp(token,"scalemin")) {
token = COM_ParseExt( &text, qtrue );
} else if(!strcmp(token,"scalemax")) {
token = COM_ParseExt( &text, qtrue );
} else if(!strcmp(token,"scalerate")) {
token = COM_ParseExt( &text, qtrue );
} else if(!strcmp(token,"velocity")) {
token = COM_ParseExt( &text, qtrue ); // forwardVelocity
} else if(!strcmp(token,"angles")) {
v[0] = CG_ParseEventFloatParm(&text);
v[1] = CG_ParseEventFloatParm(&text);
v[2] = CG_ParseEventFloatParm(&text);
VectorCopy( v, le->angles.trDelta );
AnglesToAxis(v,le->refEntity.axis);
} else if(!strcmp(token,"randvel")) {
v[0] = CG_ParseEventFloatParm(&text);
v[1] = CG_ParseEventFloatParm(&text);
v[2] = CG_ParseEventFloatParm(&text);
VectorCopy(v,le->pos.trDelta);
} else if(!strcmp(token,"emitterangles")) {
token = COM_ParseExt( &text, qfalse ); // pitchofs
token = COM_ParseExt( &text, qfalse ); // yawofs
token = COM_ParseExt( &text, qfalse ); // rollofs
} else if(!strcmp(token,"avelocity")) {
// crandom keyword is used for avelocity in weapons/mp40.tik
v[YAW] = CG_ParseEventFloatParm(&text); // yawVel
v[PITCH] = CG_ParseEventFloatParm(&text); // pitchVel
v[ROLL] = CG_ParseEventFloatParm(&text); // rollVel
//VectorCopy(v,le->apos.trDelta);
} else if(!strcmp(token,"accel")) {
// NOTE: This acceleration is applied using the world axis
token = COM_ParseExt( &text, qfalse ); // accelX
token = COM_ParseExt( &text, qfalse ); // accelY
token = COM_ParseExt( &text, qfalse ); // accelZ
} else if(!strcmp(token,"physicsrate")) {
token = COM_ParseExt( &text, qtrue );
if(!Q_stricmp(token,"every")) {
}
} else if(!strcmp(token,"life")) {
token = COM_ParseExt( &text, qtrue );
le->endTime = cg.time + atof(token)*1000;
} else if(!strcmp(token,"fadedelay")) {
token = COM_ParseExt( &text, qtrue );
} else if(!strcmp(token,"alignstretch")) {
token = COM_ParseExt( &text, qfalse ); // scaleMultiplier
} else if(!strcmp(token,"alignonce")) {
} else if(!strcmp(token,"align")) {
} else if(!strcmp(token,"collision")) {
} else if(!strcmp(token,"fade")) {
} else if(!strcmp(token,"randomroll")) {
} else if(!strcmp(token,"spritegridlighting")) {
} else if(!strcmp(token,"volumetric")) {
// set the effect to spawn volumetric sources rather than tempmodels
} else if(!strcmp(token,"wateronly")) {
// makes the temp model remove itself if it leaves water
} else if(!strcmp(token,"wind")) {
// makes the temp model be affected by wind
} else if(!strcmp(token,"bouncefactor")) {
token = COM_ParseExt( &text, qtrue );
le->bounceFactor = atof(token);
} else if(!strcmp(token,"bouncesoundonce")) {
token = COM_ParseExt( &text, qtrue );
} else if(!strcmp(token,"friction")) {
token = COM_ParseExt( &text, qtrue );
} else {
//CG_Printf("Uknown '***spawn' parameter %s\n",token);
}
COM_ParseExt( &text, qtrue );
}
}
void CG_ProcessEventText(centity_t *ent, const char *eventText) {
char str[128];
char *text;
char *token;
float f;
int i;
int boneName;
tiki_t *tiki;
vec3_t v,a;
text = (char*)eventText;
again:
// if(cg_printEvents.integer)
// CG_Printf("CG_ProcessEventText: event %s\n",eventText);
// get event name
token = COM_ParseExt( &text, qtrue );
Q_strlwr(token);
if(!strcmp(token,"sound")) {
// syntax: sound( String soundName,
// [ String channelName ], [ Float volume ],
// [ Float min_distance ], [ Float pitch ],
// [ Float randompitch ], [ String randomvolume ] )
char *name;
//float volume, minDist, pitch, randompitch;
soundChannel_t channel;
ubersound_t* sound;
name = COM_ParseExt( &text, qtrue );
sound = CG_GetUbersound(name);
if (!sound)
return;
token = COM_ParseExt( &text, qtrue );
if ( token[0] ) {
if ( !Q_strncmp( token, "auto", MAX_QPATH ) )
channel = CHAN_AUTO;
else if ( !Q_strncmp( token, "body", MAX_QPATH ) )
channel = CHAN_BODY;
else if ( !Q_strncmp( token, "item", MAX_QPATH ) )
channel = CHAN_ITEM;
else if ( !Q_strncmp( token, "weaponidle", MAX_QPATH ) )
channel = CHAN_WEAPONIDLE;
else if ( !Q_strncmp( token, "voice", MAX_QPATH ) )
channel = CHAN_VOICE;
else if ( !Q_strncmp( token, "local", MAX_QPATH ) )
channel = CHAN_LOCAL;
else if ( !Q_strncmp( token, "weapon", MAX_QPATH ) )
channel = CHAN_WEAPON;
else if ( !Q_strncmp( token, "dialog_secondary", MAX_QPATH ) )
channel = CHAN_DIALOG_SECONDARY;
else if ( !Q_strncmp( token, "dialog", MAX_QPATH ) )
channel = CHAN_DIALOG;
else if ( !Q_strncmp( token, "menu", MAX_QPATH ) )
channel = CHAN_MENU;
else {
//CG_Printf( "Event sound unrecognized channel %s for %s\n", token, name );
channel = sound->channel;
}
//token = COM_ParseExt( &text, qtrue );
} else channel = sound->channel;
/* if ( token[0] ) {
volume = atof( token );
token = COM_ParseExt( &text, qtrue );
}
minDist = atof( COM_ParseExt( &text, qtrue ) );
pitch = atof( COM_ParseExt( &text, qtrue ) );
randompitch = atof( COM_ParseExt( &text, qtrue ) );
randomvolume = COM_ParseExt( &text, qtrue );*/
#if 0
cgi.S_StartSound( ent->currentState.origin, -1, channel, sound->sfxHandle );
#else
cgi.S_StartSound( 0, ent->currentState.number, channel, sound->sfxHandle );
#endif
} else if(!strcmp(token,"stopsound")) {
// syntax: stopsound( String channelName )
// TODO
} else if(!strcmp(token,"loopsound")) {
// syntax: loopsound( String soundName, [ Float volume ],
// [ Float min_distance ], Float pitch )
char *name;
//float volume, minDist, pitch;
ubersound_t* snd;
name = COM_ParseExt( &text, qtrue );
snd = CG_GetUbersound(name);
/* volume = atof( COM_ParseExt( &text, qtrue ) );
minDist = atof( COM_ParseExt( &text, qtrue ) );
pitch = atof( COM_ParseExt( &text, qtrue ) );
*/
if (snd)
cgi.S_AddLoopingSound( ent->currentState.number, ent->currentState.origin, vec3_origin, snd->sfxHandle );
} else if(!strcmp(token,"stoploopsound")) {
cgi.S_StopLoopingSound( ent->currentState.number );
} else if(!strcmp(token,"stopaliaschannel")) {
token = COM_ParseExt( &text, qtrue );
} else if(!strcmp(token,"viewkick")) {
// viewkick( Float pitchmin, Float pitchmax,
// Float yawmin, Float yawmax, Float recenterspeed,
// String patters, Float pitchmax, Float yawmax )
// TODO
} else if(!strcmp(token,"cache")) {
token = COM_ParseExt( &text, qtrue );
//CG_Printf("Caching %s...\n",token);
cgi.R_RegisterModel(token);
} else if(!strcmp(token,"commanddelay")) {
token = COM_ParseExt( &text, qtrue );
f = atof(token);
CG_PostEvent(ent,text,f*1000);
} else if(!strcmp(token,"originspawn")) {
CG_ProcessSpawnEvent(ent,ent->lerpOrigin, ent->lerpAngles, text);
} else if(!strcmp(token,"tagspawn")) {
tiki = cgs.gameTIKIs[ent->currentState.modelindex];
if(!tiki) {
CG_Printf("'tagspawn' event cast on entity with null TIKI\n");
return;
}
// parse tagname
token = COM_ParseExt( &text, qtrue );
// find tag in tiki
boneName = cgi.TIKI_GetBoneNameIndex(token);
for(i = 0; i < tiki->numBones; i++) {
if(tiki->boneNames[i] == boneName) {
break;
}
}
if(i == tiki->numBones) {
CG_Printf("Cant find bone %s in tiki %s for 'tagspawn' event\n",token,tiki->name);
return;
}
if(ent->bones == 0) {
CG_Printf("'tagspawn' event cast on entity with null bones ptr\n");
return;
}
CG_CentBoneIndexLocal2World(i,ent,v,a);
CG_ProcessSpawnEvent(ent,v,a,text);
} else if(!strcmp(token,"tagspawnlinked")) {
return; // FIXME!
} else if(!strcmp(token,"tagdlight")) {
float r,g,b,intensity;
// tagdlight( String tagName, Float red, Float green,
// Float blue, Float intensity, Float life,
// [ String intvel ], [ String type1 ] )
/*
Spawn a dynamic light from the specified tag
The red,green,blue parms are the color of the light
The intensity is the radius of the light
type is the type of light to create (lensflare,viewlensflare,additive)
*/
tiki = cgs.gameTIKIs[ent->currentState.modelindex];
if(!tiki) {
CG_Printf("'tagdlight' event cast on entity with null TIKI\n");
return;
}
// parse tagname
token = COM_ParseExt( &text, qtrue );
// find tag in tiki
boneName = cgi.TIKI_GetBoneNameIndex(token);
for(i = 0; i < tiki->numBones; i++) {
if(tiki->boneNames[i] == boneName) {
break;
}
}
if(i == tiki->numBones) {
CG_Printf("Cant find bone %s in tiki %s for 'tagdlight' event\n",token,tiki->name);
return;
}
if(ent->bones == 0) {
CG_Printf("'tagdlight' event cast on entity with null bones ptr\n");
return;
}
token = COM_ParseExt( &text, qtrue );
r = atof(token);
token = COM_ParseExt( &text, qtrue );
g = atof(token);
token = COM_ParseExt( &text, qtrue );
b = atof(token);
token = COM_ParseExt( &text, qtrue );
intensity = atof(token);
// optional parameters
token = COM_ParseExt( &text, qtrue );
if(token[0]) {
// TODO
token = COM_ParseExt( &text, qtrue );
if(token[0]) {
if(!Q_stricmp(token,"addictive")) {
} else if(!Q_stricmp(token,"lensflare")) {
} else if(!Q_stricmp(token,"viewlensflare")) {
}
}
}
CG_CentBoneIndexLocal2World(i,ent,v,0);
cgi.R_AddLightToScene(v,intensity,r,g,b);
} else if(!strcmp(token,"sfx")) {
goto again;
} else if(!strcmp(token,"bodyfall")) {
} else if(!strcmp(token,"footstep")) {
int iRunning;
int iEquipment;
//footstep( String tag, String sRunning, [ Integer iEquipment ] )
// plays a footstep sound that is appropriate to the surface
// we are currently stepping on.
// sRunning should be set to run, walk, or ladder
tiki = cgs.gameTIKIs[ent->currentState.modelindex];
if(!tiki) {
CG_Printf("'footstep' event cast on entity with null TIKI\n");
return;
}
// parse tagname
token = COM_ParseExt( &text, qfalse );
strcpy(str,token);
/*
// find tag in tiki
boneName = cgi.TIKI_GetBoneNameIndex(token);
for(i = 0; i < tiki->numBones; i++) {
if(tiki->boneNames[i] == boneName) {
break;
}
}
if(i == tiki->numBones) {
CG_Printf("Cant find bone %s in tiki %s for 'footstep' event\n",token,tiki->name);
return;
}
if(ent->bones == 0) {
CG_Printf("'footstep' event cast on entity with null bones ptr\n");
return;
}
*/
// sRunning
token = COM_ParseExt( &text, qfalse );
if(!Q_stricmp(token,"run")) {
//iRunning = ??;
} else if(!Q_stricmp(token,"walk")) {
//iRunning = ??;
} else if(!Q_stricmp(token,"ladder")) {
//iRunning = ??;
} else if(!Q_stricmp(token,"R")) {
//iRunning = ??;
} else if(!Q_stricmp(token,"L")) {
//iRunning = ??;
} else {
//iRunning = ??;
CG_Printf("'footstep' event: unknown sRunning type %s\n",token);
}
// Integer iEquipment
token = COM_ParseExt( &text, qfalse );
iEquipment = 0;
if(token[0]) {
iEquipment = atoi(token);
}
iRunning = 0;
CG_Footstep(str,ent,/*0,*/iRunning,iEquipment);
} else if(!strcmp(token,"emitteroff")) {
} else if(!strcmp(token,"emitteron")) {
} else {
CG_Printf("CG_ProcessEventText: unknown event %s\n",token);
}
}
void CG_FreeEvent(event_t *ev) {
if ( !ev->prev ) {
CG_Error( "CG_FreeEvent: not active" );
}
// remove from the doubly linked active list
ev->prev->next = ev->next;
ev->next->prev = ev->prev;
// the free list is only singly linked
ev->next = cg_freeEvents;
cg_freeEvents = ev;
}
event_t *CG_AllocEvent() {
event_t *ev;
if ( !cg_freeEvents ) {
CG_Printf("CG_AllocEvent: no free events\n");
return 0;
}
ev = cg_freeEvents;
cg_freeEvents = cg_freeEvents->next;
memset( ev, 0, sizeof( *ev ) );
// link into the active list
ev->next = cg_pendingEvents.next;
ev->prev = &cg_pendingEvents;
cg_pendingEvents.next->prev = ev;
cg_pendingEvents.next = ev;
return ev;
}
void CG_PostEvent(centity_t *ent, const char *eventText, int eventDelay) {
event_t *ev;
ev = CG_AllocEvent();
if(!ev)
return; // failed to alloc an event
ev->ent = ent;
strcpy(ev->buffer,eventText);
ev->execTime = cg.time + eventDelay;
}
void CG_ProcessEvent(event_t *ev) {
CG_ProcessEventText(ev->ent,ev->buffer);
CG_FreeEvent(ev);
}
void CG_ProcessPendingEvents() {
event_t *ev, *next;
ev = cg_pendingEvents.next;
for ( ; ev != &cg_pendingEvents ; ev = next ) {
// grab next now, so if the event is freed we
// still have it
next = ev->next;
if ( cg.time >= ev->execTime ) {
// execute it
CG_ProcessEventText(ev->ent, ev->buffer);
// and free
CG_FreeEvent(ev);
continue;
}
}
}
+628
View File
@@ -0,0 +1,628 @@
/*
===========================================================================
Copyright (C) 2023 the OpenMoHAA team
This file is part of OpenMoHAA source code.
OpenMoHAA source code is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the License,
or (at your option) any later version.
OpenMoHAA source code is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with OpenMoHAA source code; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
// DESCRIPTION:
// light style code
#include "cg_local.h"
/*
===================================================================
LIGHT STYLE CODE
===================================================================
*/
#define MAX_LIGHTSTYLE_LENGTH 128
#define MAX_LIGHTSTYLE_NAME_LENGTH 64
typedef struct
{
char name[ MAX_LIGHTSTYLE_NAME_LENGTH ];
qboolean hasalpha;
int length;
float map[ MAX_LIGHTSTYLE_LENGTH ][ 4 ];
} clightstyle_t;
clightstyle_t cg_lightstyle[ MAX_LIGHTSTYLES * 2 ];
/*
================
CG_LightStyleColor
================
*/
qboolean CG_LightStyleColor( int style, int realtime, float color[4], qboolean clamp )
{
clightstyle_t *ls;
int i, time;
float frac;
qboolean at_end;
time = realtime / 50;
frac = ( realtime - ( time * 50.0f ) ) / 50.0f;
memset( color, 0, sizeof( color ) );
if ( ( style < 0 ) || ( style >= ( MAX_LIGHTSTYLES * 2 ) ) )
{
cgi.DPrintf ("CG_LightStyleColor: style out of range.\n");
return qtrue;
}
ls = &cg_lightstyle[ style ];
if ( !ls->length )
{
cgi.DPrintf ("CG_LightStyleColor: style %d has zero length.\n", style);
return qtrue;
}
// by default we are not at the end
at_end = qfalse;
if ( clamp )
{
if ( time >= ls->length )
{
time = ls->length - 1;
at_end = qtrue;
}
}
else
{
time %= ls->length;
}
//
// only lerp if we are before the end
//
if ( time == ls->length - 1 )
{
memcpy( color, ls->map[ time ], 4 * sizeof( ls->map[ time ][ 0 ] ) );
}
else
{
for( i = 0; i < 4; i++ )
{
color[ i ] = ls->map[ time ][ i ] + frac * ( ls->map[ time + 1 ][ i ] - ls->map[ time ][ i ] );
}
}
if ( !ls->hasalpha )
color[ 3 ] = 1;
return at_end;
}
/*
=============
LoadTGA
=============
*/
static qboolean LoadTGA(const char * name, byte ** pic, int *width, int *height, qboolean * hasalpha )
{
int columns, rows, numPixels;
byte *pixbuf;
int row, column;
byte *buf_p;
byte *buffer;
TargaHeader targa_header;
byte *targa_rgba;
byte targa_palette[ 256 * 4 ];
int i;
*pic = NULL;
*hasalpha = false;
//
// load the file
//
cgi.FS_ReadFile(name, (void **)&buffer, qtrue);
if (!buffer)
{
cgi.DPrintf( "TGA File not found: %s\n", name );
return false;
}
buf_p = buffer;
targa_header.id_length = *buf_p++;
targa_header.colormap_type = *buf_p++;
targa_header.image_type = *buf_p++;
targa_header.colormap_index = LittleShort ( *((short *)buf_p) );
buf_p += 2;
targa_header.colormap_length = LittleShort ( *((short *)buf_p) );
buf_p += 2;
targa_header.colormap_size = *buf_p++ / 8;
targa_header.x_origin = LittleShort ( *((short *)buf_p) );
buf_p += 2;
targa_header.y_origin = LittleShort ( *((short *)buf_p) );
buf_p += 2;
targa_header.width = LittleShort ( *((short *)buf_p) );
buf_p += 2;
targa_header.height = LittleShort ( *((short *)buf_p) );
buf_p += 2;
targa_header.pixel_size = *buf_p++;
targa_header.attributes = *buf_p++;
if (targa_header.image_type!=1
&& targa_header.image_type!=2
&& targa_header.image_type!=10)
{
cgi.DPrintf("LoadTGA: Only type 1, 2 and 10 targa RGB images supported\n");
return false;
}
if ( (targa_header.colormap_type !=0 && targa_header.colormap_type !=1)
|| (targa_header.pixel_size!=32 && targa_header.pixel_size!=24 && targa_header.pixel_size!=8))
{
cgi.DPrintf("LoadTGA: Only 24, 32 and colormap images supported (no colormaps)\n");
return false;
}
columns = targa_header.width;
rows = targa_header.height;
numPixels = columns * rows;
if (width)
*width = columns;
if (height)
*height = rows;
targa_rgba = ( byte * )cgi.Malloc( numPixels * 4 );
*pic = targa_rgba;
if (targa_header.id_length != 0)
buf_p += targa_header.id_length; // skip TARGA image comment
for (i=0;i<targa_header.colormap_length;i++)
{
byte blue = *buf_p++;
byte green = *buf_p++;
byte red = *buf_p++;
byte alpha = 0xff;
if (targa_header.colormap_size == 4)
alpha = *buf_p++;
targa_palette[i*4+0] = red;
targa_palette[i*4+1] = green;
targa_palette[i*4+2] = blue;
targa_palette[i*4+3] = alpha;
if (alpha != 0xff)
*hasalpha = true;
}
if (targa_header.image_type==1)
{
for(row=rows-1; row>=0; row--)
{
pixbuf = targa_rgba + row*columns;
for(column=0; column<columns; column++)
{
switch (targa_header.pixel_size)
{
case 8:
*pixbuf++ = targa_palette[ *buf_p * 4 + 0];
*pixbuf++ = targa_palette[ *buf_p * 4 + 1];
*pixbuf++ = targa_palette[ *buf_p * 4 + 2];
*pixbuf++ = targa_palette[ *buf_p * 4 + 3];
buf_p++;
break;
}
}
}
}
else if (targa_header.image_type==2) { // Uncompressed, RGB images
for(row=rows-1; row>=0; row--) {
pixbuf = targa_rgba + row*columns*4;
for(column=0; column<columns; column++) {
unsigned char red,green,blue,alphabyte;
switch (targa_header.pixel_size) {
case 24:
blue = *buf_p++;
green = *buf_p++;
red = *buf_p++;
*pixbuf++ = red;
*pixbuf++ = green;
*pixbuf++ = blue;
*pixbuf++ = 255;
break;
case 32:
blue = *buf_p++;
green = *buf_p++;
red = *buf_p++;
alphabyte = *buf_p++;
*pixbuf++ = red;
*pixbuf++ = green;
*pixbuf++ = blue;
*pixbuf++ = alphabyte;
if (alphabyte != 0xff)
*hasalpha = true;
break;
}
}
}
}
else if (targa_header.image_type==10) { // Runlength encoded RGB images
unsigned char red,green,blue,alphabyte,packetHeader,packetSize,j;
for(row=rows-1; row>=0; row--) {
pixbuf = targa_rgba + row*columns*4;
for(column=0; column<columns; ) {
packetHeader= *buf_p++;
packetSize = 1 + (packetHeader & 0x7f);
if (packetHeader & 0x80) { // run-length packet
switch (targa_header.pixel_size) {
case 32:
blue = *buf_p++;
green = *buf_p++;
red = *buf_p++;
alphabyte = *buf_p++;
if (alphabyte != 0xff)
*hasalpha = true;
break;
case 24:
default:
blue = *buf_p++;
green = *buf_p++;
red = *buf_p++;
alphabyte = 255;
break;
}
for(j=0;j<packetSize;j++) {
*pixbuf++=red;
*pixbuf++=green;
*pixbuf++=blue;
*pixbuf++=alphabyte;
column++;
if (column==columns) { // run spans across rows
column=0;
if (row>0)
row--;
else
goto breakOut;
pixbuf = targa_rgba + row*columns*4;
}
}
}
else { // non run-length packet
for(j=0;j<packetSize;j++) {
switch (targa_header.pixel_size) {
default:
case 24:
blue = *buf_p++;
green = *buf_p++;
red = *buf_p++;
*pixbuf++ = red;
*pixbuf++ = green;
*pixbuf++ = blue;
*pixbuf++ = 255;
break;
case 32:
blue = *buf_p++;
green = *buf_p++;
red = *buf_p++;
alphabyte = *buf_p++;
*pixbuf++ = red;
*pixbuf++ = green;
*pixbuf++ = blue;
*pixbuf++ = alphabyte;
if (alphabyte != 0xff)
*hasalpha = true;
break;
}
column++;
if (column==columns) { // pixel packet run spans across rows
column=0;
if (row>0)
row--;
else
goto breakOut;
pixbuf = targa_rgba + row*columns*4;
}
}
}
}
breakOut:;
}
}
cgi.FS_FreeFile( buffer );
return true;
}
void createLightstyleFromTGA( int num, const char *filename )
{
byte *data=0;
int i, j, width, height;
qboolean hasalpha;
if (!LoadTGA(filename, &data, &width, &height, &hasalpha))
{
return;
}
if ( width > MAX_LIGHTSTYLE_LENGTH )
{
cgi.DPrintf("createLightstyleFromTGA: Light style too large, truncating.\n",filename);
width = MAX_LIGHTSTYLE_LENGTH;
}
strncpy( cg_lightstyle[ num ].name, filename, MAX_LIGHTSTYLE_NAME_LENGTH );
cg_lightstyle[ num ].hasalpha = hasalpha;
cg_lightstyle[ num ].length = width;
for( i = 0; i < width; i++ )
{
for ( j = 0; j < 4; j++ )
{
cg_lightstyle[ num ].map[ i ][ j ] = ( float )data[ ( i * 4 ) + j ] / 255.0f;
}
}
if ( data )
cgi.Free( data );
}
void CG_SetLightStyle( int num, const char *s )
{
const char *r, *g, *b, *a;
int j, k, n;
size_t len;
float t;
if ( ( num < 0 ) || ( num >= ( MAX_LIGHTSTYLES * 2 ) ) )
{
cgi.DPrintf ("CG_SetLightStyle: num out of range.\n");
return;
}
len = strlen( s );
if ( !Q_stricmp( &s[ len - 4 ], ".tga" ) )
{
createLightstyleFromTGA( num, s );
return;
}
if ( !s )
return;
r = strchr( s, 'R' );
g = strchr( s, 'G' );
b = strchr( s, 'B' );
a = strchr( s, 'A' );
n = 0;
if (r)
n++;
if (g)
n++;
if (b)
n++;
if (a)
n++;
if (!n)
n++;
if (!a)
cg_lightstyle[ num ].hasalpha = false;
else
cg_lightstyle[ num ].hasalpha = true;
j = strlen (s) / n;
if (j >= MAX_LIGHTSTYLE_LENGTH)
{
cgi.DPrintf ( "svc_lightstyle length=%i", j);
j = MAX_LIGHTSTYLE_LENGTH - 1;
}
if ( !r && !g && !b && !a )
{
cg_lightstyle[ num ].length = j;
for( k = 0; k < j; k++ )
{
t = ( float )( s[ k ] - 'a' ) * 127.5f / 12.5;
if ( t > 255 )
{
t = 255.0f;
}
cg_lightstyle[ num ].map[ k ][ 0 ] = t / 255.0f;
cg_lightstyle[ num ].map[ k ][ 1 ] = t / 255.0f;
cg_lightstyle[ num ].map[ k ][ 2 ] = t / 255.0f;
cg_lightstyle[ num ].map[ k ][ 3 ] = 1;
}
}
else
{
n = 0;
// red
k = 0;
t = 0;
if ( r )
{
r++;
while( ( r[ k ] >= 'a' ) && ( r[ k ] <= 'z' ) )
{
t = ( float )( r[ k ] - 'a' ) * 127.5f / 12.5;
if ( t > 255 )
{
t = 255.0f;
}
cg_lightstyle[ num ].map[ k ][ 0 ] = t / 255.0f;
k++;
}
n = k;
}
while( k < MAX_LIGHTSTYLE_LENGTH )
{
cg_lightstyle[ num ].map[ k++ ][ 0 ] = t / 255.0f;
}
// green
k = 0;
t = 0;
if ( g )
{
g++;
while( ( g[ k ] >= 'a' ) && ( g[ k ] <= 'z' ) )
{
t = ( float )( g[ k ] - 'a' ) * 127.5f / 12.5;
if ( t > 255 )
{
t = 255.0f;
}
cg_lightstyle[ num ].map[ k ][ 1 ] = t / 255.0f;
k++;
}
n = max( n, k );
}
while( k < MAX_LIGHTSTYLE_LENGTH )
{
cg_lightstyle[ num ].map[ k++ ][ 1 ] = t / 255.0f;
}
// blue
k = 0;
t = 0;
if ( b )
{
b++;
while( ( b[ k ] >= 'a' ) && ( b[ k ] <= 'z' ) )
{
t = ( float )( b[ k ] - 'a' ) * 127.5f / 12.5;
if ( t > 255 )
{
t = 255.0f;
}
cg_lightstyle[ num ].map[ k ][ 2 ] = t / 255.0f;
k++;
}
n = max( n, k );
}
while( k < MAX_LIGHTSTYLE_LENGTH )
{
cg_lightstyle[ num ].map[ k++ ][ 2 ] = t / 255.0f;
}
// alpha
k = 0;
t = 255;
if ( a )
{
a++;
while( ( a[ k ] >= 'a' ) && ( a[ k ] <= 'z' ) )
{
t = ( float )( a[ k ] - 'a' ) * 127.5f / 25;
if ( t > 255 )
{
t = 255.0f;
}
cg_lightstyle[ num ].map[ k ][ 3 ] = t / 255.0f;
k++;
}
n = max( n, k );
}
while( k < MAX_LIGHTSTYLE_LENGTH )
{
cg_lightstyle[ num ].map[ k++ ][ 3 ] = t / 255.0f;
}
cg_lightstyle[ num ].length = n;
}
}
/*
================
CG_GetLightStyle
================
*/
int CG_GetLightStyle( const char * name )
{
int i;
for( i = MAX_LIGHTSTYLES; i < MAX_LIGHTSTYLES * 2; i++ )
{
if ( !Q_stricmp( cg_lightstyle[ i ].name, name ) )
{
return i;
}
}
return -1;
}
/*
================
CG_GetFreeLightStyle
================
*/
int CG_GetFreeLightStyle( void )
{
int i;
for( i = MAX_LIGHTSTYLES; i < MAX_LIGHTSTYLES * 2; i++ )
{
if ( !cg_lightstyle[ i ].name[ 0 ] )
{
return i;
}
}
return -1;
}
/*
================
CG_ClearLightStyles
================
*/
void CG_ClearLightStyles( void )
{
memset( cg_lightstyle, 0, sizeof( cg_lightstyle ) );
}
/*
================
CG_RegisterLightStyle
================
*/
int CG_RegisterLightStyle( const char * name )
{
int num;
num = CG_GetLightStyle( name );
if ( num == -1 )
{
num = CG_GetFreeLightStyle();
if ( num != -1 )
{
CG_SetLightStyle( num, name );
}
else
{
cgi.DPrintf ("CG_RegisterLightStyle: no free spots for lightstyle %s.\n");
}
}
return num;
}
+666 -769
View File
File diff suppressed because it is too large. Load diff
-683
View File
@@ -1,683 +0,0 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
This file is part of Quake III Arena source code.
Quake III Arena source code is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the License,
or (at your option) any later version.
Quake III Arena source code is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Quake III Arena source code; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
//
// cg_localents.c -- every frame, generate renderer commands for locally
// processed entities, like smoke puffs, gibs, shells, etc.
#include "cg_local.h"
#define MAX_LOCAL_ENTITIES 512
localEntity_t cg_localEntities[MAX_LOCAL_ENTITIES];
localEntity_t cg_activeLocalEntities; // double linked list
localEntity_t *cg_freeLocalEntities; // single linked list
/*
===================
CG_InitLocalEntities
This is called at startup and for tournement restarts
===================
*/
void CG_InitLocalEntities( void ) {
int i;
memset( cg_localEntities, 0, sizeof( cg_localEntities ) );
cg_activeLocalEntities.next = &cg_activeLocalEntities;
cg_activeLocalEntities.prev = &cg_activeLocalEntities;
cg_freeLocalEntities = cg_localEntities;
for ( i = 0 ; i < MAX_LOCAL_ENTITIES - 1 ; i++ ) {
cg_localEntities[i].next = &cg_localEntities[i+1];
}
}
/*
==================
CG_FreeLocalEntity
==================
*/
void CG_FreeLocalEntity( localEntity_t *le ) {
if ( !le->prev ) {
CG_Error( "CG_FreeLocalEntity: not active" );
}
// remove from the doubly linked active list
le->prev->next = le->next;
le->next->prev = le->prev;
// the free list is only singly linked
le->next = cg_freeLocalEntities;
cg_freeLocalEntities = le;
}
/*
===================
CG_AllocLocalEntity
Will allways succeed, even if it requires freeing an old active entity
===================
*/
localEntity_t *CG_AllocLocalEntity( void ) {
localEntity_t *le;
if ( !cg_freeLocalEntities ) {
// no free entities, so free the one at the end of the chain
// remove the oldest active entity
CG_FreeLocalEntity( cg_activeLocalEntities.prev );
}
le = cg_freeLocalEntities;
cg_freeLocalEntities = cg_freeLocalEntities->next;
memset( le, 0, sizeof( *le ) );
// link into the active list
le->next = cg_activeLocalEntities.next;
le->prev = &cg_activeLocalEntities;
cg_activeLocalEntities.next->prev = le;
cg_activeLocalEntities.next = le;
return le;
}
/*
====================================================================================
FRAGMENT PROCESSING
A fragment localentity interacts with the environment in some way (hitting walls),
or generates more localentities along a trail.
====================================================================================
*/
/*
================
CG_BloodTrail
Leave expanding blood puffs behind gibs
================
*/
void CG_BloodTrail( localEntity_t *le ) {
//int t;
//int t2;
//int step;
//vec3_t newOrigin;
//localEntity_t *blood;
//step = 150;
//t = step * ( (cg.time - cg.frametime + step ) / step );
//t2 = step * ( cg.time / step );
//for ( ; t <= t2; t += step ) {
// BG_EvaluateTrajectory( &le->pos, t, newOrigin );
// blood = CG_SmokePuff( newOrigin, vec3_origin,
// 20, // radius
// 1, 1, 1, 1, // color
// 2000, // trailTime
// t, // startTime
// 0, // fadeInTime
// 0, // flags
// cgs.media.bloodTrailShader );
// // use the optimized version
// blood->leType = LE_FALL_SCALE_FADE;
// // drop a total of 40 units over its lifetime
// blood->pos.trDelta[2] = 40;
//}
}
/*
================
CG_FragmentBounceMark
================
*/
void CG_FragmentBounceMark( localEntity_t *le, trace_t *trace ) {
//int radius;
//if ( le->leMarkType == LEMT_BLOOD ) {
// radius = 16 + (rand()&31);
// CG_ImpactMark( cgs.media.bloodMarkShader, trace->endpos, trace->plane.normal, random()*360,
// 1,1,1,1, qtrue, radius, qfalse );
//} else if ( le->leMarkType == LEMT_BURN ) {
// radius = 8 + (rand()&15);
// CG_ImpactMark( cgs.media.burnMarkShader, trace->endpos, trace->plane.normal, random()*360,
// 1,1,1,1, qtrue, radius, qfalse );
//}
//// don't allow a fragment to make multiple marks, or they
//// pile up while settling
//le->leMarkType = LEMT_NONE;
}
/*
================
CG_FragmentBounceSound
================
*/
void CG_FragmentBounceSound( localEntity_t *le, trace_t *trace ) {
// don't allow a fragment to make multiple bounce sounds,
// or it gets too noisy as they settle
le->leBounceSoundType = LEBS_NONE;
}
/*
================
CG_ReflectVelocity
================
*/
void CG_ReflectVelocity( localEntity_t *le, trace_t *trace ) {
vec3_t velocity;
float dot;
int hitTime;
// reflect the velocity on the trace plane
hitTime = cg.time - cg.frametime + cg.frametime * trace->fraction;
BG_EvaluateTrajectoryDelta( &le->pos, hitTime, velocity );
dot = DotProduct( velocity, trace->plane.normal );
VectorMA( velocity, -2*dot, trace->plane.normal, le->pos.trDelta );
VectorScale( le->pos.trDelta, le->bounceFactor, le->pos.trDelta );
VectorCopy( trace->endpos, le->pos.trDelta );
le->pos.trTime = cg.time;
// check for stop, making sure that even on low FPS systems it doesn't bobble
if ( trace->allsolid ||
( trace->plane.normal[2] > 0 &&
( le->pos.trDelta[2] < 40 || le->pos.trDelta[2] < -cg.frametime * le->pos.trDelta[2] ) ) ) {
} else {
}
}
/*
================
CG_AddFragment
================
*/
void CG_AddFragment( localEntity_t *le ) {
vec3_t newOrigin;
trace_t trace;
refEntity_t *e;
tiki_t *tiki;
// if that's a tiki, we need to animate it
if(le->tiki) {
float time = 0;
int anim = 0;
e = &le->refEntity;
tiki = le->tiki;
e->bones = cgi.TIKI_GetBones(tiki->numBones);
cgi.TIKI_AppendFrameBoundsAndRadius(tiki,anim,time,&e->radius,e->bounds);
cgi.TIKI_SetChannels(tiki,anim,time,1,e->bones);
cgi.TIKI_Animate(tiki,e->bones);
}
// calculate new position
BG_EvaluateTrajectory( &le->pos, cg.time, newOrigin );
// trace a line from previous position to new position
CG_Trace( &trace, le->refEntity.origin, NULL, NULL, newOrigin, -1, CONTENTS_SOLID );
if ( trace.fraction == 1.0 ) {
// still in free fall
VectorCopy( newOrigin, le->refEntity.origin );
if ( le->leFlags & LEF_TUMBLE ) {
vec3_t angles;
BG_EvaluateTrajectory( &le->angles, cg.time, angles );
AnglesToAxis( angles, le->refEntity.axis );
}
cgi.R_AddRefEntityToScene( &le->refEntity );
// add a blood trail
if ( le->leBounceSoundType == LEBS_BLOOD ) {
CG_BloodTrail( le );
}
return;
}
// if it is in a nodrop zone, remove it
// this keeps gibs from waiting at the bottom of pits of death
// and floating levels
if ( cgi.CM_PointContents( trace.endpos, 0 ) & CONTENTS_NODROP ) {
CG_FreeLocalEntity( le );
return;
}
// leave a mark
CG_FragmentBounceMark( le, &trace );
// do a bouncy sound
CG_FragmentBounceSound( le, &trace );
// reflect the velocity on the trace plane
CG_ReflectVelocity( le, &trace );
cgi.R_AddRefEntityToScene( &le->refEntity );
}
/*
=====================================================================
TRIVIAL LOCAL ENTITIES
These only do simple scaling or modulation before passing to the renderer
=====================================================================
*/
/*
====================
CG_AddFadeRGB
====================
*/
void CG_AddFadeRGB( localEntity_t *le ) {
refEntity_t *re;
float c;
re = &le->refEntity;
c = ( le->endTime - cg.time ) * le->lifeRate;
c *= 0xff;
re->shaderRGBA[0] = le->color[0] * c;
re->shaderRGBA[1] = le->color[1] * c;
re->shaderRGBA[2] = le->color[2] * c;
re->shaderRGBA[3] = le->color[3] * c;
cgi.R_AddRefEntityToScene( re );
}
/*
==================
CG_AddMoveScaleFade
==================
*/
static void CG_AddMoveScaleFade( localEntity_t *le ) {
refEntity_t *re;
float c;
vec3_t delta;
float len;
re = &le->refEntity;
if ( le->fadeInTime > le->startTime && cg.time < le->fadeInTime ) {
// fade / grow time
c = 1.0 - (float) ( le->fadeInTime - cg.time ) / ( le->fadeInTime - le->startTime );
}
else {
// fade / grow time
c = ( le->endTime - cg.time ) * le->lifeRate;
}
re->shaderRGBA[3] = 0xff * c * le->color[3];
if ( !( le->leFlags & LEF_PUFF_DONT_SCALE ) ) {
re->radius = le->radius * ( 1.0 - c ) + 8;
}
BG_EvaluateTrajectory( &le->pos, cg.time, re->origin );
// if the view would be "inside" the sprite, kill the sprite
// so it doesn't add too much overdraw
VectorSubtract( re->origin, cg.refdef.vieworg, delta );
len = VectorLength( delta );
if ( len < le->radius ) {
CG_FreeLocalEntity( le );
return;
}
cgi.R_AddRefEntityToScene( re );
}
/*
===================
CG_AddScaleFade
For rocket smokes that hang in place, fade out, and are
removed if the view passes through them.
There are often many of these, so it needs to be simple.
===================
*/
static void CG_AddScaleFade( localEntity_t *le ) {
refEntity_t *re;
float c;
vec3_t delta;
float len;
re = &le->refEntity;
// fade / grow time
c = ( le->endTime - cg.time ) * le->lifeRate;
re->shaderRGBA[3] = 0xff * c * le->color[3];
re->radius = le->radius * ( 1.0 - c ) + 8;
// if the view would be "inside" the sprite, kill the sprite
// so it doesn't add too much overdraw
VectorSubtract( re->origin, cg.refdef.vieworg, delta );
len = VectorLength( delta );
if ( len < le->radius ) {
CG_FreeLocalEntity( le );
return;
}
cgi.R_AddRefEntityToScene( re );
}
/*
=================
CG_AddFallScaleFade
This is just an optimized CG_AddMoveScaleFade
For blood mists that drift down, fade out, and are
removed if the view passes through them.
There are often 100+ of these, so it needs to be simple.
=================
*/
static void CG_AddFallScaleFade( localEntity_t *le ) {
refEntity_t *re;
float c;
vec3_t delta;
float len;
re = &le->refEntity;
// fade time
c = ( le->endTime - cg.time ) * le->lifeRate;
re->shaderRGBA[3] = 0xff * c * le->color[3];
re->origin[ 2 ] = le->pos.trDelta[ 2 ] - ( 1.0 - c ) * le->pos.trDelta[ 2 ];
re->radius = le->radius * ( 1.0 - c ) + 16;
// if the view would be "inside" the sprite, kill the sprite
// so it doesn't add too much overdraw
VectorSubtract( re->origin, cg.refdef.vieworg, delta );
len = VectorLength( delta );
if ( len < le->radius ) {
CG_FreeLocalEntity( le );
return;
}
cgi.R_AddRefEntityToScene( re );
}
/*
================
CG_AddExplosion
================
*/
static void CG_AddExplosion( localEntity_t *ex ) {
refEntity_t *ent;
ent = &ex->refEntity;
// add the entity
cgi.R_AddRefEntityToScene(ent);
// add the dlight
if ( ex->light ) {
float light;
light = (float)( cg.time - ex->startTime ) / ( ex->endTime - ex->startTime );
if ( light < 0.5 ) {
light = 1.0;
} else {
light = 1.0 - ( light - 0.5 ) * 2;
}
light = ex->light * light;
cgi.R_AddLightToScene(ent->origin, light, ex->lightColor[0], ex->lightColor[1], ex->lightColor[2] );
}
}
/*
================
CG_AddSpriteExplosion
================
*/
static void CG_AddSpriteExplosion( localEntity_t *le ) {
refEntity_t re;
float c;
re = le->refEntity;
c = ( le->endTime - cg.time ) / ( float ) ( le->endTime - le->startTime );
if ( c > 1 ) {
c = 1.0; // can happen during connection problems
}
re.shaderRGBA[0] = 0xff;
re.shaderRGBA[1] = 0xff;
re.shaderRGBA[2] = 0xff;
re.shaderRGBA[3] = 0xff * c * 0.33;
re.reType = RT_SPRITE;
re.radius = 42 * ( 1.0 - c ) + 30;
cgi.R_AddRefEntityToScene( &re );
// add the dlight
if ( le->light ) {
float light;
light = (float)( cg.time - le->startTime ) / ( le->endTime - le->startTime );
if ( light < 0.5 ) {
light = 1.0;
} else {
light = 1.0 - ( light - 0.5 ) * 2;
}
light = le->light * light;
cgi.R_AddLightToScene(re.origin, light, le->lightColor[0], le->lightColor[1], le->lightColor[2] );
}
}
/*
===================
CG_AddScorePlum
===================
*/
#define NUMBER_SIZE 8
void CG_AddScorePlum( localEntity_t *le ) {
//refEntity_t *re;
//vec3_t origin, delta, dir, vec, up = {0, 0, 1};
//float c, len;
//int i, score, digits[10], numdigits, negative;
//re = &le->refEntity;
//c = ( le->endTime - cg.time ) * le->lifeRate;
//score = le->radius;
//if (score < 0) {
// re->shaderRGBA[0] = 0xff;
// re->shaderRGBA[1] = 0x11;
// re->shaderRGBA[2] = 0x11;
//}
//else {
// re->shaderRGBA[0] = 0xff;
// re->shaderRGBA[1] = 0xff;
// re->shaderRGBA[2] = 0xff;
// if (score >= 50) {
// re->shaderRGBA[1] = 0;
// } else if (score >= 20) {
// re->shaderRGBA[0] = re->shaderRGBA[1] = 0;
// } else if (score >= 10) {
// re->shaderRGBA[2] = 0;
// } else if (score >= 2) {
// re->shaderRGBA[0] = re->shaderRGBA[2] = 0;
// }
//}
//if (c < 0.25)
// re->shaderRGBA[3] = 0xff * 4 * c;
//else
// re->shaderRGBA[3] = 0xff;
//re->radius = NUMBER_SIZE / 2;
//VectorCopy(le->pos.trBase, origin);
//origin[2] += 110 - c * 100;
//VectorSubtract(cg.refdef.vieworg, origin, dir);
//CrossProduct(dir, up, vec);
//VectorNormalize(vec);
//VectorMA(origin, -10 + 20 * sin(c * 2 * M_PI), vec, origin);
//// if the view would be "inside" the sprite, kill the sprite
//// so it doesn't add too much overdraw
//VectorSubtract( origin, cg.refdef.vieworg, delta );
//len = VectorLength( delta );
//if ( len < 20 ) {
// CG_FreeLocalEntity( le );
// return;
//}
//negative = qfalse;
//if (score < 0) {
// negative = qtrue;
// score = -score;
//}
//for (numdigits = 0; !(numdigits && !score); numdigits++) {
// digits[numdigits] = score % 10;
// score = score / 10;
//}
//if (negative) {
// digits[numdigits] = 10;
// numdigits++;
//}
//for (i = 0; i < numdigits; i++) {
// VectorMA(origin, (float) (((float) numdigits / 2) - i) * NUMBER_SIZE, vec, re->origin);
// re->customShader = cgs.media.numberShaders[digits[numdigits-1-i]];
// cgi.R_AddRefEntityToScene( re );
//}
}
//==============================================================================
/*
===================
CG_AddLocalEntities
===================
*/
void CG_AddLocalEntities( void ) {
localEntity_t *le, *next;
// walk the list backwards, so any new local entities generated
// (trails, marks, etc) will be present this frame
le = cg_activeLocalEntities.prev;
for ( ; le != &cg_activeLocalEntities ; le = next ) {
// grab next now, so if the local entity is freed we
// still have it
next = le->prev;
if ( cg.time >= le->endTime ) {
CG_FreeLocalEntity( le );
continue;
}
switch ( le->leType ) {
default:
CG_Error( "Bad leType: %i", le->leType );
break;
case LE_SKIP:
// do nothing
break;
case LE_MARK:
break;
case LE_SPRITE_EXPLOSION:
CG_AddSpriteExplosion( le );
break;
case LE_EXPLOSION:
CG_AddExplosion( le );
break;
case LE_FRAGMENT: // gibs and brass
CG_AddFragment( le );
break;
case LE_MOVE_SCALE_FADE: // water bubbles
CG_AddMoveScaleFade( le );
break;
case LE_FADE_RGB: // teleporters, railtrails
CG_AddFadeRGB( le );
break;
case LE_FALL_SCALE_FADE: // gib blood trails
CG_AddFallScaleFade( le );
break;
case LE_SCALE_FADE: // rocket trails
CG_AddScaleFade( le );
break;
case LE_SCOREPLUM:
CG_AddScorePlum( le );
break;
#ifdef MISSIONPACK
case LE_KAMIKAZE:
CG_AddKamikaze( le );
break;
case LE_INVULIMPACT:
CG_AddInvulnerabilityImpact( le );
break;
case LE_INVULJUICED:
CG_AddInvulnerabilityJuiced( le );
break;
case LE_SHOWREFENTITY:
CG_AddRefEntity( le );
break;
#endif
}
}
}
+642 -677
View File
File diff suppressed because it is too large. Load diff
+346 -1905
View File
File diff suppressed because it is too large. Load diff
+980 -319
View File
File diff suppressed because it is too large. Load diff
+229
View File
@@ -0,0 +1,229 @@
/*
===========================================================================
Copyright (C) 2023 the OpenMoHAA team
This file is part of OpenMoHAA source code.
OpenMoHAA source code is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the License,
or (at your option) any later version.
OpenMoHAA source code is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with OpenMoHAA source code; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
// DESCRIPTION:
// Nature effects
#include "cg_local.h"
#include "cg_commands.h"
cvar_t* cg_rain;
cvar_t* cg_rain_drawcoverage;
void RainTouch(ctempmodel_t* ct, trace_t* trace)
{
Vector norm, neworg;
ct->ent.hModel = cgi.R_RegisterModel("splash_z.spr");
ct->cgd.velocity = vec_zero;
ct->cgd.accel = vec_zero;
ct->killTime = cg.time + 400;
norm = trace->plane.normal;
norm.x = -norm.x;
norm.y = -norm.y;
ct->cgd.angles = norm.toAngles();
ct->ent.scale = 0.3f;
ct->cgd.scaleRate = 4.0;
ct->cgd.flags |= T_FADE;
neworg = trace->endpos + norm * 0.2f;
VectorCopy(neworg, ct->ent.origin);
}
void ClientGameCommandManager::RainTouch(Event* ev)
{
// FIXME: unimplemented
}
void ClientGameCommandManager::InitializeRainCvars()
{
int i;
cg_rain = cgi.Cvar_Get("cg_rain", "0", CVAR_ARCHIVE);
cg_rain_drawcoverage = cgi.Cvar_Get("cg_rain_drawcoverage", "0", CVAR_SAVEGAME | CVAR_SERVER_CREATED | CVAR_SYSTEMINFO);
cg.rain.density = 0.0;
cg.rain.speed = 2048.0f;
cg.rain.length = 90.0f;
cg.rain.min_dist = 512.0f;
cg.rain.width = 1.0f;
cg.rain.speed_vary = 512;
cg.rain.slant = 50;
for (i = 0; i < MAX_RAIN_SHADERS; i++) {
cg.rain.shader[i][0] = 0;
}
cg.rain.numshaders = 0;
}
void CG_Rain(centity_t* cent)
{
int iLife;
vec3_t mins, maxs;
vec3_t vOmins, vOmaxs, vOe;
float fcolor[4];
vec3_t vStart, vEnd;
int iNumSpawn;
int i;
int iRandom;
float fDensity;
vec3_t vLength;
const char* shadername;
fcolor[0] = 1.0;
fcolor[1] = 1.0;
fcolor[2] = 1.0;
fcolor[3] = 1.0;
if (!cg_rain->integer || paused->integer) {
return;
}
cgi.R_ModelBounds(cgs.inlineDrawModel[cent->currentState.modelindex], mins, maxs);
vOmins[0] = mins[0] + cent->lerpOrigin[0];
if (vOmins[0] < cg.snap->ps.origin[0] - cg.rain.min_dist) {
vOmins[0] = cg.snap->ps.origin[0] - cg.rain.min_dist;
}
vOmins[1] = mins[1] + cent->lerpOrigin[1];
if (vOmins[1] < cg.snap->ps.origin[1] - cg.rain.min_dist) {
vOmins[1] = cg.snap->ps.origin[1] - cg.rain.min_dist;
}
vOmins[2] = mins[2] + cent->lerpOrigin[2];
vOmaxs[0] = maxs[0] + cent->lerpOrigin[0];
if (vOmaxs[0] > cg.rain.min_dist + cg.snap->ps.origin[0]) {
vOmaxs[0] = cg.rain.min_dist + cg.snap->ps.origin[0];
}
vOmaxs[1] = maxs[1] + cent->lerpOrigin[1];
if (vOmaxs[1] > cg.rain.min_dist + cg.snap->ps.origin[1]) {
vOmaxs[1] = cg.rain.min_dist + cg.snap->ps.origin[1];
}
vOmaxs[2] = maxs[2] + cent->lerpOrigin[2];
if (vOmins[0] > vOmaxs[0]) {
return;
}
if (vOmins[1] > vOmaxs[1]) {
return;
}
if (cg_rain_drawcoverage->integer)
{
cgi.R_DebugLine(
Vector(vOmins[0], vOmins[1], vOmins[2]),
Vector(vOmaxs[0], vOmins[1], vOmins[2]),
1.0, 0.0, 0.0, 1.0
);
cgi.R_DebugLine(
Vector(vOmaxs[0], vOmins[1], vOmins[2]),
Vector(vOmaxs[0], vOmaxs[1], vOmins[2]),
1.0, 0.0, 0.0, 1.0
);
cgi.R_DebugLine(
Vector(vOmaxs[0], vOmaxs[1], vOmins[2]),
Vector(vOmins[0], vOmaxs[1], vOmins[2]),
1.0, 0.0, 0.0, 1.0
);
cgi.R_DebugLine(
Vector(vOmins[0], vOmaxs[1], vOmins[2]),
Vector(vOmins[0], vOmins[1], vOmins[2]),
1.0, 0.0, 0.0, 1.0
);
}
VectorSubtract(vOmaxs, vOmins, vOe);
fDensity = cg.rain.density / 200.0;
iNumSpawn = (int)(sqrt(vOe[0] * vOe[1]) * fDensity);
if (iNumSpawn > MAX_BEAMS) {
iNumSpawn = MAX_BEAMS;
}
iRandom = rand();
if (cg.rain.numshaders) {
shadername = cg.rain.shader[iRandom % cg.rain.numshaders];
}
else {
shadername = cg.rain.shader[0];
}
for (i = 0; i < iNumSpawn; ++i)
{
iLife = (int)(vOe[2] / ((float)(iRandom % cg.rain.speed_vary) + cg.rain.speed) * 1000.0);
vStart[0] = (float)(iRandom % (int)(vOe[0] + 1.0)) + vOmins[0];
iRandom = ((214013 * iRandom + 2531011) >> 16) & 0x7FFF;
vStart[1] = (float)(iRandom % (int)(vOe[1] + 1.0)) + vOmins[1];
vStart[2] = vOmaxs[2];
if (cg.snap)
{
vLength[0] = cg.snap->ps.origin[0] - vStart[0];
vLength[1] = cg.snap->ps.origin[1] - vStart[1];
vLength[2] = 0.0;
if (cg.rain.min_dist * cg.rain.min_dist < VectorLengthSquared(vLength)) {
continue;
}
}
vEnd[0] = (float)(iRandom % cg.rain.slant) + vStart[0] + vss_wind_x->value;
iRandom = ((214013 * iRandom + 2531011) >> 16) & 0x7FFF;
vEnd[1] = (float)(iRandom % cg.rain.slant) + vStart[1] + vss_wind_y->value;
vEnd[2] = vOmins[2];
CG_CreateBeam(
vStart,
vec_zero,
0,
1,
1.0,
cg.rain.width,
BEAM_INVERTED_FAST,
1000.0,
iLife,
qtrue,
vEnd,
0,
0,
0,
1,
0,
shadername,
fcolor,
0,
0.0,
cg.rain.length,
1.0,
0,
"raineffect"
);
}
}
-653
View File
@@ -1,653 +0,0 @@
/*
===========================================================================
Copyright (C) 2011 su44
This file is part of OpenMoHAA source code.
OpenMoHAA source code is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the License,
or (at your option) any later version.
OpenMoHAA source code is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with OpenMoHAA source code; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
// cg_parsemsg.c
#include "cg_local.h"
#define MAX_HDELEMENTS 256
hdelement_t hdelements[MAX_HDELEMENTS];
typedef struct {
float i_vBarrel[3];
float i_vStart[3];
float (*i_vEnd)[3];
int i_iNumBullets;
qboolean iLarge;
int iTracerVisible;
qboolean bIgnoreEntities;
} bullet_tracer_t;
#define MAX_IMPACTS 64
#define MAX_BULLER_TRACERS 32
#define MAX_BULLET_TRACE_BULLETS 1024
// bullet tracers
static bullet_tracer_t bullet_tracers[MAX_BULLER_TRACERS];
static int bullet_tracers_count;
static float bullet_tracer_bullets[MAX_BULLET_TRACE_BULLETS][3];
static int bullet_tracer_bullets_count;
// wall impacts
static vec3_t wall_impact_pos[MAX_IMPACTS];
static vec3_t wall_impact_norm[MAX_IMPACTS];
static int wall_impact_large[MAX_IMPACTS];
static int wall_impact_type[MAX_IMPACTS]; // 0,2,3,4,5
static int wall_impact_count;
// flesh impacts
static vec3_t flesh_impact_pos[MAX_IMPACTS];
static vec3_t flesh_impact_norm[MAX_IMPACTS];
static int flesh_impact_large[MAX_IMPACTS];
static int flesh_impact_type[MAX_IMPACTS];
static int flesh_impact_count;
static int current_entity_number;
void CG_MakeBulletHole(float *i_vPos, float *i_vNorm, int iLarge,
trace_t *pPreTrace, qboolean bMakeSound) {
char *s;
#if 0
// su44: make an "explosion" effect here so I can debug bullet holes coordinates
CG_MakeExplosion(i_vPos,vec3_origin,0,cgi.R_RegisterShader("heavy_pipe"),250,qtrue);
#endif
s = "bhole_";
// TODO: choose an appropriate decal shader and play hit sound
CG_ImpactMark(cgi.R_RegisterShader("bhole_wood"),i_vPos,i_vNorm,0,1,1,1,1,qfalse,8,qfalse);
}
void CG_AddBulletImpacts() {
int i;
char *s;
int type;
for(i = 0; i < wall_impact_count; i++) {
CG_MakeBulletHole(wall_impact_pos[i],wall_impact_norm[i],
wall_impact_large[i],0,qtrue);
type = wall_impact_type[i];
if(type) {
if ( wall_impact_type[i] < 2 || wall_impact_type[i] > 3 )
s = "snd_bh_metal";
else
s = "snd_bh_wood";
//CG_PlaySound(s,wall_impact_pos[i],-1,
}
}
for(i = 0; i < flesh_impact_count; i++) {
}
}
static void CG_MakeBubbleTrail(float *i_vStart, float *i_vEnd, int iLarge) {
// TODO
}
// this is called from CG_MakeBulletTracerInternal
static void CG_BulletTracerEffect(float *i_vStart, float *i_vEnd)
{
byte fTracerColor[4]; // su44: in MoHAA it was "float[4]"
int iLife;
vec3_t vNewStart;
int v2;
VectorCopy(i_vStart,vNewStart);
v2 = 1;
iLife = 20;
fTracerColor[0] = 255;
fTracerColor[1] = 255;
fTracerColor[2] = 255;
fTracerColor[3] = 255;
CG_CreateBeam(
vNewStart, // start
vec3_origin, // dir
0, // owner
1, // model
1.0, // alpha
1.0, // scale
8192, // flags
1000.0, // len
iLife, // life
1, // qboolean create
i_vEnd, // endpointvec
0, // min_ofs
0, // maxs_ofs
0, // overlap
1, // numSubdivions
0, // delay
"tracer", // beamshadername
fTracerColor, // modulate (in FAKK that's a byte[4], in MoH that's float[4])
0, // numSphereBeams
0.0, // sphereradius
v2, //toggleDelay
1.0, //endapha
0, // renderfx
"tracereffect"); // name
}
static void CG_MakeBulletTracerInternal(float *i_vBarrel, float *i_vStart,
float (*i_vEnd)[3], int i_iNumBullets, qboolean iLarge,
int iTracerVisible, qboolean bIgnoreEntities) {
trace_t tr;
int i;
for(i = 0; i < i_iNumBullets; i++) {
CG_BulletTracerEffect(i_vBarrel,i_vEnd[i]);
CG_Trace(&tr,i_vBarrel,vec3_origin,vec3_origin,i_vEnd[i],-1,MASK_SHOT);
if(tr.fraction != 1.f && tr.allsolid == qfalse) {
CG_MakeBulletHole(tr.endpos,tr.plane.normal,iLarge,&tr,qfalse);
} else {
// su44: it happens quite often. Is it a bug?
//CG_Printf("CG_MakeBulletTracerInternal: missed\n");
}
}
}
static void CG_MakeBulletTracer(float *i_vBarrel, float *i_vStart,
float (*i_vEnd)[3], int i_iNumBullets, qboolean iLarge,
int iTracerVisible, qboolean bIgnoreEntities) {
bullet_tracer_t *bt;
int i;
if(bullet_tracers_count < MAX_BULLER_TRACERS) {
if(i_iNumBullets + bullet_tracer_bullets_count < MAX_BULLET_TRACE_BULLETS) {
bt = bullet_tracers + bullet_tracers_count;
VectorCopy(i_vBarrel,bt->i_vBarrel);
VectorCopy(i_vStart,bt->i_vStart);
bt->i_vEnd = &bullet_tracer_bullets[bullet_tracer_bullets_count];
bt->i_iNumBullets = i_iNumBullets;
bt->iLarge = iLarge;
bt->iTracerVisible = iTracerVisible;
bt->bIgnoreEntities = bIgnoreEntities;
bullet_tracers_count++;
for(i = 0; i < i_iNumBullets; i++) {
VectorCopy(i_vEnd[i],bullet_tracer_bullets[bullet_tracer_bullets_count]);
bullet_tracer_bullets_count++;
}
} else {
CG_Printf("CG_MakeBulletTracerInternal: MAX_BULLET_TRACE_BULLETS exceeded\n");
}
} else {
CG_Printf("CG_MakeBulletTracer: MAX_BULLER_TRACERS exceeded\n");
}
}
// su44: this should be called after CG_AddPacketEntities and before CG_DrawActive
void CG_AddBulletTracers() {
int i;
bullet_tracer_t *bt;
bt = bullet_tracers;
for(i = 0; i < bullet_tracers_count; i++,bt++) {
CG_MakeBulletTracerInternal(bt->i_vBarrel,bt->i_vStart,bt->i_vEnd,bt->i_iNumBullets,
bt->iLarge,bt->iTracerVisible,bt->bIgnoreEntities);
}
bullet_tracers_count = 0;
bullet_tracer_bullets_count = 0;
}
static void CG_MakeExplosionEffect(float *vPos, int iType) {
CG_MakeExplosion(vPos,vec3_origin,0,cgi.R_RegisterShader("gren_explosion"),1000,qtrue);
}
static void CG_MakeEffect_Normal(int iEffect, vec3_t vPos, vec3_t vNormal) {
// TODO
}
static void CG_SpawnEffectModel(const char *model, vec3_t origin) {
localEntity_t *le;
vec3_t spawnAngles = { 0, 0, 0 };
qhandle_t h;
le = CG_AllocLocalEntity();
le->endTime = cg.time + 5000;
le->leType = LE_SKIP;
le->pos.trTime = cg.time - (rand()&15);
VectorCopy( origin, le->pos.trDelta );
VectorCopy(origin,le->refEntity.origin);
VectorCopy( spawnAngles, le->angles.trDelta );
AnglesToAxis(spawnAngles,le->refEntity.axis);
h = cgi.R_RegisterModel(model);
le->refEntity.model = h;
le->leType = LE_FRAGMENT;
le->tiki = cgi.TIKI_RegisterModel(model);
}
void CG_HudDrawElements() {
int i;
hdelement_t *hdi;
//if ( cg_huddraw_force.integer || cg_hud.integer )
{
hdi = hdelements;
for ( i = 0; i < MAX_HDELEMENTS; i++, hdi++ ) {
if ( hdi->hShader || hdi->string[0] ) {
if ( hdi->vColor[3] != 0.f ) {
float x = hdi->iX;
float y = hdi->iY;
float w = hdi->iWidth;
float h = hdi->iHeight;
if ( hdi->iHorizontalAlign == 1 ) {
if ( hdi->bVirtualScreen )
x = 320.f - w * 0.5f + x;
else
x = cgs.glconfig.vidWidth * 0.5f - w * 0.5f + x;
} else {
if ( hdi->iHorizontalAlign == 2 ) {
if ( hdi->bVirtualScreen )
x = x + 640.f;
else
x = cgs.glconfig.vidWidth + x;
}
}
if ( hdi->iVerticalAlign == 1 ) {
if ( hdi->bVirtualScreen )
y = 240.f - h * 0.5f + y;
else
y = cgs.glconfig.vidHeight * 0.5f - h * 0.5f + y;
} else {
if ( hdi->iVerticalAlign == 2 ) {
if ( hdi->bVirtualScreen )
y = y + 480.f;
else
y = cgs.glconfig.vidHeight + y;
}
}
cgi.R_SetColor(hdi->vColor);
// su44: that's wrong
if(hdi->bVirtualScreen) {
if(x > 640)
x -= 640;
if(x < 0)
x += 640;
if(y > 480)
y -= 480;
if(y < 0)
y += 480;
}
if ( hdi->string[0] ) {
if ( hdi->pFont.glyphs[0].glyph ) {
cgi.R_Text_Paint(&hdi->pFont, x, y, 1, 1, hdi->string,0,-1, qfalse, hdi->bVirtualScreen);
} else {
cgi.R_Text_Paint(&cgs.media.verdana, x, y, 1, 1, hdi->string,0,-1, qfalse, hdi->bVirtualScreen);
}
} else {
if ( hdi->bVirtualScreen )
CG_AdjustFrom640(&x, &y, &w, &h);
cgi.R_DrawStretchPic(x, y, w, h, 0.f, 0.f, 1.f, 1.f, hdi->hShader);
}
}
}
}
}
}
static void CG_HudDrawShader (int iInfo) {
hdelement_t *hdi = hdelements + iInfo;
if(hdi->shaderName[0]) {
hdi->hShader = cgi.R_RegisterShaderNoMip(hdi->shaderName);
} else {
hdi->hShader = 0;
}
}
static void CG_HudDrawFont (int iInfo) {
hdelement_t *hdi = hdelements + iInfo;
if(hdi->fontName[0]) {
cgi.R_RegisterFont(hdi->fontName,0,&hdi->pFont);
} else {
memset(&hdi->pFont,0,sizeof(hdi->pFont));
}
}
static void CG_PlaySound(char *sound_name, float *origin, int channel,
float volume, float min_distance, float pitch, int argstype) {
ubersound_t* sound;
sound = CG_GetUbersound(sound_name);
if(sound)
cgi.S_StartSound( origin, -1, sound->channel, sound->sfxHandle );
}
/*
=====================
CG_ParseCGMessage
=====================
*/
void CG_ParseCGMessage() {
int msgtype;
vec3_t vecStart, vecTmp, vecEnd, vecArray[64];
int iCount, iLarge;
int i, iTemp;
char *s;
hdelement_t *hde;
// thats a hack, it should be done somewhere else [?]
wall_impact_count = 0;
flesh_impact_count = 0;
do {
msgtype = cgi.MSG_ReadBits( 6 );
if(cg_debugCGMessages->integer) {
Com_Printf( "CG_ParseCGMessage: command type %i\n", msgtype );
}
switch ( msgtype ) {
case 1: // BulletTracer (visible?)
vecTmp[0] = cgi.MSG_ReadCoord();
vecTmp[1] = cgi.MSG_ReadCoord();
vecTmp[2] = cgi.MSG_ReadCoord();
case 2: // BulletTracer (invisible?)
case 5: // BubbleTrail
vecStart[0] = cgi.MSG_ReadCoord();
vecStart[1] = cgi.MSG_ReadCoord();
vecStart[2] = cgi.MSG_ReadCoord();
if ( msgtype != 1 ) {
vecTmp[0] = vecStart[0];
vecTmp[1] = vecStart[1];
vecTmp[2] = vecStart[2];
}
vecArray[0][0] = cgi.MSG_ReadCoord();
vecArray[0][1] = cgi.MSG_ReadCoord();
vecArray[0][2] = cgi.MSG_ReadCoord();
iLarge = cgi.MSG_ReadBits( 1 );
if(msgtype==5) {
CG_MakeBubbleTrail(vecStart,vecArray[0],iLarge);
} else if(msgtype==1) {
// su44: I am not sure about the last parameters...
CG_MakeBulletTracer(vecTmp, vecStart, vecArray, 1, iLarge, 1, 1);
} else { //msgtype == 2
CG_MakeBulletTracer(vecTmp, vecStart, vecArray, 1, iLarge, 0, 1);
}
break;
case 3: // BulletTracer multiple times
vecTmp[0] = cgi.MSG_ReadCoord();
vecTmp[1] = cgi.MSG_ReadCoord();
vecTmp[2] = cgi.MSG_ReadCoord();
iTemp = cgi.MSG_ReadBits( 6 );
case 4: // BulletTracer multiple times (shotgun shot)
if ( msgtype == 4 )
iTemp = 0;
vecStart[0] = cgi.MSG_ReadCoord();
vecStart[1] = cgi.MSG_ReadCoord();
vecStart[2] = cgi.MSG_ReadCoord();
iLarge = cgi.MSG_ReadBits( 1 );
iCount = cgi.MSG_ReadBits( 6 );
// this check is missing in MOHAA code, so this has buffer overflow risk in AA
if ( iCount > 64 )
Com_Error( ERR_DROP, "CG message type 4 sent too many data.\n" );
for (i=0;i<iCount;i++) {
vecArray[i][0] = cgi.MSG_ReadCoord();
vecArray[i][1] = cgi.MSG_ReadCoord();
vecArray[i][2] = cgi.MSG_ReadCoord();
}
CG_MakeBulletTracer(vecTmp, vecStart, vecArray, iCount, iLarge, iTemp, 1);
break;
case 6: // wall impact
case 7: // flesh impact
case 8: // flesh impact (?)
case 9: // wall impact (?)
case 10: // wall impact (?)
vecStart[0] = cgi.MSG_ReadCoord();
vecStart[1] = cgi.MSG_ReadCoord();
vecStart[2] = cgi.MSG_ReadCoord();
cgi.MSG_ReadDir( vecEnd );
iLarge = cgi.MSG_ReadBits( 1 );
switch (msgtype) {
case 6:
if(wall_impact_count < MAX_IMPACTS) {
VectorCopy(vecStart,wall_impact_pos[wall_impact_count]);
VectorCopy(vecEnd,wall_impact_norm[wall_impact_count]);
wall_impact_large[wall_impact_count] = iLarge;
wall_impact_type[wall_impact_count] = 0;
wall_impact_count++;
}
break;
case 7:
if(flesh_impact_count < MAX_IMPACTS) {
// inverse hit normal, I dont know why,
// but that's done by MoHAA
VectorInverse(vecEnd);
VectorCopy(vecStart,flesh_impact_pos[flesh_impact_count]);
VectorCopy(vecEnd,flesh_impact_norm[flesh_impact_count]);
flesh_impact_large[flesh_impact_count] = iLarge;
flesh_impact_count++;
}
break;
case 8:
if(flesh_impact_count < MAX_IMPACTS) {
// same here?
VectorInverse(vecEnd);
VectorCopy(vecStart,flesh_impact_pos[flesh_impact_count]);
VectorCopy(vecEnd,flesh_impact_norm[flesh_impact_count]);
flesh_impact_large[flesh_impact_count] = iLarge;
flesh_impact_count++;
}
break;
case 9:
if(wall_impact_count < MAX_IMPACTS) {
VectorCopy(vecStart,wall_impact_pos[wall_impact_count]);
VectorCopy(vecEnd,wall_impact_norm[wall_impact_count]);
wall_impact_large[wall_impact_count] = iLarge;
if(iLarge) {
wall_impact_type[wall_impact_count] = 3;
} else {
wall_impact_type[wall_impact_count] = 2;
}
wall_impact_count++;
}
break;
case 10:
if(wall_impact_count < MAX_IMPACTS) {
VectorCopy(vecStart,wall_impact_pos[wall_impact_count]);
VectorCopy(vecEnd,wall_impact_norm[wall_impact_count]);
wall_impact_large[wall_impact_count] = iLarge;
if(iLarge) {
wall_impact_type[wall_impact_count] = 5;
} else {
wall_impact_type[wall_impact_count] = 4;
}
wall_impact_count++;
}
break;
default:
break;
}
break;
case 11:
vecStart[0] = cgi.MSG_ReadCoord();
vecStart[1] = cgi.MSG_ReadCoord();
vecStart[2] = cgi.MSG_ReadCoord();
vecEnd[0] = cgi.MSG_ReadCoord();
vecEnd[1] = cgi.MSG_ReadCoord();
vecEnd[2] = cgi.MSG_ReadCoord();
CG_MeleeImpact(vecStart,vecEnd);
break;
case 12: // m1 frag/stiel grenade explosion
case 13: // bazooka/panzershrek projectile explosion
vecStart[0] = cgi.MSG_ReadCoord();
vecStart[1] = cgi.MSG_ReadCoord();
vecStart[2] = cgi.MSG_ReadCoord();
CG_MakeExplosionEffect(vecStart,msgtype);
break;
default: //unknown message
Com_Error(ERR_DROP, "CG_ParseCGMessage: Unknown CG Message %i", msgtype);
break;
case 14:
case 15: // MakeEffect
case 16:
case 17:
case 18:
case 19: // oil barrel effect
case 20:
case 21: // oil barrel effect top
case 22: // oil barrel effect top - first hit
vecStart[0] = cgi.MSG_ReadCoord();
vecStart[1] = cgi.MSG_ReadCoord();
vecStart[2] = cgi.MSG_ReadCoord();
cgi.MSG_ReadDir( vecEnd );
CG_MakeEffect_Normal(msgtype/* + 67*/,vecStart,vecEnd);
break;
case 23: // broke crate
case 24: // broke glass window
vecStart[0] = cgi.MSG_ReadCoord();
vecStart[1] = cgi.MSG_ReadCoord();
vecStart[2] = cgi.MSG_ReadCoord();
i = cgi.MSG_ReadByte();
if(msgtype == 23) {
s = va("models/fx/crates/debris_%i.tik",i);
} else {
s = va("models/fx/windows/debris_%i.tik",i);
}
CG_SpawnEffectModel(s, vecStart);
break;
case 25: // Bullet tracer
vecTmp[0] = cgi.MSG_ReadCoord();
vecTmp[1] = cgi.MSG_ReadCoord();
vecTmp[2] = cgi.MSG_ReadCoord();
vecStart[0] = cgi.MSG_ReadCoord();
vecStart[1] = cgi.MSG_ReadCoord();
vecStart[2] = cgi.MSG_ReadCoord();
vecArray[0][0] = cgi.MSG_ReadCoord();
vecArray[0][1] = cgi.MSG_ReadCoord();
vecArray[0][2] = cgi.MSG_ReadCoord();
iLarge = cgi.MSG_ReadBits( 1 );
CG_MakeBulletTracer(vecTmp,vecStart,vecArray,1,iLarge,0,1);
break;
case 26: // Bullet tracer
vecTmp[0] = 0;
vecTmp[1] = 0;
vecTmp[2] = 0;
vecStart[0] = cgi.MSG_ReadCoord();
vecStart[1] = cgi.MSG_ReadCoord();
vecStart[2] = cgi.MSG_ReadCoord();
vecArray[0][0] = cgi.MSG_ReadCoord();
vecArray[0][1] = cgi.MSG_ReadCoord();
vecArray[0][2] = cgi.MSG_ReadCoord();
iLarge = cgi.MSG_ReadBits( 1 );
CG_MakeBulletTracer(vecTmp,vecStart,vecArray,1,iLarge,0,1);
break;
case 27: // HUD drawing...
i = cgi.MSG_ReadByte();
hde = hdelements + i;
Q_strncpyz( hde->shaderName, cgi.MSG_ReadString(), sizeof(hde->shaderName) );
hde->string[0] = 0;
memset(&hde->pFont,0,sizeof(hde->pFont));
hde->fontName[0] = 0;
CG_HudDrawShader(i);
break;
case 28: // HUD drawing...
i = cgi.MSG_ReadByte();
hde = hdelements + i;
hde->iHorizontalAlign = cgi.MSG_ReadBits( 2 );
hde->iHorizontalAlign = cgi.MSG_ReadBits( 2 );
break;
case 29:
i = cgi.MSG_ReadByte();
hde = hdelements + i;
hde->iX = cgi.MSG_ReadShort();
hde->iY = cgi.MSG_ReadShort();
hde->iWidth = cgi.MSG_ReadShort();
hde->iHeight = cgi.MSG_ReadShort();
break;
case 30:
i = cgi.MSG_ReadByte();
hde = hdelements + i;
hde->bVirtualScreen = cgi.MSG_ReadBits( 1 );
break;
case 31: // huddraw_color
i = cgi.MSG_ReadByte();
hde = hdelements + i;
hde->vColor[0] = cgi.MSG_ReadByte()*0.003921568859368563;
hde->vColor[1] = cgi.MSG_ReadByte()*0.003921568859368563;
hde->vColor[2] = cgi.MSG_ReadByte()*0.003921568859368563;
break;
case 32: // huddraw_alpha
i = cgi.MSG_ReadByte();
hde = hdelements + i;
hde->vColor[3] = cgi.MSG_ReadByte()*0.003921568859368563;
break;
case 33: // huddraw_string
i = cgi.MSG_ReadByte();
hde = hdelements + i;
hde->hShader = 0;
Q_strncpyz( hde->string, cgi.MSG_ReadString(), sizeof(hde->string) );
break;
case 34: // huddraw_font
i = cgi.MSG_ReadByte();
hde = hdelements + i;
Q_strncpyz( hde->fontName, cgi.MSG_ReadString(), sizeof(hde->fontName) );
hde->hShader = 0;
hde->shaderName[0] = 0;
CG_HudDrawFont(i);
break;
case 35:
case 36:
// TODO - play sound (?)
//CG_PlaySound(s, 0, 5, 2.0, -1.0, vecStart, 1);
break;
case 37: // voicechat message (squad command, taunt, etc...)
vecStart[0] = cgi.MSG_ReadCoord();
vecStart[1] = cgi.MSG_ReadCoord();
vecStart[2] = cgi.MSG_ReadCoord();
iTemp = cgi.MSG_ReadBits( 1 );
// read client index
i = cgi.MSG_ReadBits( 6 );
// read voicechat sound alias
s = cgi.MSG_ReadString();
if(iTemp) {
current_entity_number = i;
}
//CG_Printf("Case 37: iTemp %i, i %i, s %s\n",iTemp,i,s);
// play an aliased sound from uberdialog.scr
// wombat: only if there is a sound to be played
if ( *s )
CG_PlaySound(s,vecStart,5,-1.0,-1.0,-1.0,0);
break;
}
} while ( cgi.MSG_ReadBits(1) );
}
+691
View File
@@ -0,0 +1,691 @@
/*
===========================================================================
Copyright (C) 2023 the OpenMoHAA team
This file is part of OpenMoHAA source code.
OpenMoHAA source code is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the License,
or (at your option) any later version.
OpenMoHAA source code is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with OpenMoHAA source code; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
// DESCRIPTION:
// CGM buffer parser
#include "cg_local.h"
#include "cg_parsemsg.h"
#include "cg_specialfx.h"
#include "str.h"
extern int current_entity_number;
typedef struct {
vec3_t i_vBarrel;
vec3_t i_vStart;
vec3_t* i_vEnd;
int i_iNumBullets;
qboolean iLarge;
int iTracerVisible;
qboolean bIgnoreEntities;
} bullet_tracer_t;
#define MAX_BULLET_TRACERS 32
#define MAX_BULLET_TRACE_BULLETS 1024
#define MAX_IMPACTS 64
static int bullet_tracers_count;
static int bullet_tracer_bullets_count;
static int wall_impact_count;
static int flesh_impact_count;
static bullet_tracer_t bullet_tracers[MAX_BULLET_TRACERS];
static vec3_t bullet_tracer_bullets[MAX_BULLET_TRACE_BULLETS];
static vec3_t wall_impact_pos[MAX_IMPACTS];
static vec3_t wall_impact_norm[MAX_IMPACTS];
static int wall_impact_large[MAX_IMPACTS];
static int wall_impact_type[MAX_IMPACTS];
static vec3_t flesh_impact_pos[MAX_IMPACTS];
static vec3_t flesh_impact_norm[MAX_IMPACTS];
static int flesh_impact_large[MAX_IMPACTS];
static void CG_MakeBulletHole(vec3_t i_vPos, vec3_t i_vNorm, int iLarge, trace_t* pPreTrace, qboolean bMakeSound)
{
// FIXME: unimplemented
}
static void CG_MakeBubbleTrail(vec3_t i_vStart, vec3_t i_vEnd, int iLarge)
{
// FIXME: unimplemented
}
static void CG_BulletTracerEffect(vec3_t i_vStart, vec3_t i_vEnd)
{
// FIXME: unimplemented
}
static void CG_MakeBulletTracerInternal(vec3_t i_vBarrel, vec3_t i_vStart, vec3_t *i_vEnd, int i_iNumBullets, qboolean iLarge, int iTracerVisible, qboolean bIgnoreEntities)
{
// FIXME: unimplemented
}
static void CG_MakeBulletTracer(vec3_t i_vBarrel, vec3_t i_vStart, vec3_t* i_vEnd, int i_iNumBullets, qboolean iLarge, int iTracerVisible, qboolean bIgnoreEntities) {
bullet_tracer_t* bullet_tracer;
int i;
if (bullet_tracer_bullets_count >= MAX_BULLET_TRACERS) {
Com_Printf("CG_MakeBulletTracer: MAX_BULLET_TRACERS exceeded\n");
return;
}
if (i_iNumBullets + bullet_tracers_count >= MAX_BULLET_TRACE_BULLETS) {
Com_Printf("CG_MakeBulletTracerInternal: MAX_BULLET_TRACE_BULLETS exceeded\n");
return;
}
bullet_tracer = &bullet_tracers[bullet_tracer_bullets_count++];
VectorCopy(i_vBarrel, bullet_tracer->i_vBarrel);
VectorCopy(i_vStart, bullet_tracer->i_vStart);
bullet_tracer->i_vEnd = &bullet_tracer_bullets[bullet_tracers_count];
bullet_tracer->i_iNumBullets = i_iNumBullets;
for (i = 0; i < i_iNumBullets; ++i)
{
bullet_tracer_bullets[bullet_tracers_count][0] = (*i_vEnd)[i];
bullet_tracer_bullets[bullet_tracers_count][1] = (*i_vEnd)[i + 1];
bullet_tracer_bullets[bullet_tracers_count++][2] = (*i_vEnd)[i + 2];
}
bullet_tracer->iLarge = iLarge;
bullet_tracer->iTracerVisible = iTracerVisible;
bullet_tracer->bIgnoreEntities = bIgnoreEntities;
}
void CG_AddBulletTracers()
{
int i;
for (i = 0; i < bullet_tracer_bullets_count; ++i) {
CG_MakeBulletTracerInternal(
bullet_tracers[i].i_vBarrel,
bullet_tracers[i].i_vStart,
bullet_tracers[i].i_vEnd,
bullet_tracers[i].i_iNumBullets,
bullet_tracers[i].iLarge,
bullet_tracers[i].iTracerVisible,
bullet_tracers[i].bIgnoreEntities
);
}
bullet_tracer_bullets_count = 0;
bullet_tracers_count = 0;
}
void CG_AddBulletImpacts()
{
// FIXME: unimplemented
}
void CG_MakeExplosionEffect(vec3_t vPos, int iType) {
int iSurfType;
int iBaseEffect;
int iSurfEffect;
float fRadius;
vec3_t vEnd;
str sMark;
trace_t trace;
qhandle_t shader;
vEnd[0] = vPos[0];
vEnd[1] = vPos[1];
vEnd[2] = vPos[2] - 64.0;
fRadius = 64.0;
if ((CG_PointContents(vPos, 0)) & MASK_WATER)
{
iBaseEffect = 73;
sfxManager.MakeEffect_Normal(iBaseEffect, vPos, Vector(0, 0, 1));
return;
}
switch (iType)
{
case 12:
iBaseEffect = 63;
break;
case 13:
iBaseEffect = 64;
break;
default:
iBaseEffect = 63;
break;
}
CG_Trace(
&trace,
vPos,
vec_zero,
vec_zero,
vEnd,
ENTITYNUM_NONE,
MASK_EXPLOSION,
qfalse,
qtrue,
"CG_MakeExplosionEffect"
);
if (trace.fraction == 1.0 || trace.startsolid)
{
// exploded in the air
sfxManager.MakeEffect_Normal(iBaseEffect, vPos, Vector(0, 0, 1));
return;
}
VectorMA(trace.endpos, 32.0, trace.plane.normal, vPos);
iSurfType = trace.surfaceFlags & MASK_SURF_TYPE;
switch (iSurfType)
{
case SURF_FOLIAGE:
iSurfEffect = 77;
fRadius = 0;
break;
case SURF_SNOW:
iSurfEffect = 78;
fRadius = 0;
break;
case SURF_CARPET:
iSurfEffect = 79;
break;
case SURF_SAND:
iSurfEffect = 76;
fRadius = 0;
break;
case SURF_PUDDLE:
iSurfEffect = -1;
fRadius = 0;
break;
case SURF_GLASS:
iSurfEffect = -1;
fRadius = 0;
break;
case SURF_GRAVEL:
iSurfEffect = 75;
break;
case SURF_MUD:
iSurfEffect = 72;
fRadius = 0;
break;
case SURF_DIRT:
iSurfEffect = 69;
fRadius = 0;
break;
case SURF_GRILL:
iSurfEffect = 70;
fRadius = 0;
break;
case SURF_GRASS:
iSurfEffect = 71;
break;
case SURF_ROCK:
iSurfEffect = 68;
break;
case SURF_PAPER:
iSurfEffect = 65;
break;
case SURF_WOOD:
iSurfEffect = 66;
break;
case SURF_METAL:
iSurfEffect = 67;
break;
default:
iSurfEffect = -1;
break;
}
sMark = "blastmark";
if (fRadius)
{
float value = (rand() & 0x7FFF) / 32767.0 - 0.5;
fRadius *= (value + value) * 0.1 + 1.0;
shader = cgi.R_RegisterShader(sMark.c_str());
CG_ImpactMarkSimple(
shader,
trace.endpos,
trace.plane.normal,
random() * 360.0,
fRadius,
1, 1, 1, 1,
qfalse,
qfalse,
qtrue,
qfalse
);
}
VectorMA(vPos, 1.0, trace.plane.normal, vPos);
if (iSurfEffect != -1)
{
sfxManager.MakeEffect_Normal(
iSurfEffect,
Vector(trace.endpos) + Vector(trace.plane.normal),
trace.plane.normal
);
}
sfxManager.MakeEffect_Normal(
iSurfEffect,
vPos,
trace.plane.normal
);
}
void CG_MakeVehicleEffect(vec3_t i_vStart, vec3_t i_vEnd , vec3_t i_vDir) {
vec3_t vDir, vFrom, vDest;
trace_t trace;
VectorSubtract(i_vEnd, i_vStart, vDir);
VectorNormalizeFast(vDir);
VectorMA(i_vEnd, -16.0, vDir, vFrom);
VectorMA(i_vEnd, 16.0, vDir, vDest);
CG_Trace(&trace, vFrom, vec_zero, vec_zero, vDest, ENTITYNUM_NONE, MASK_PLAYERSOLID, qfalse, qtrue, "CG_MakeBulletHole");
cgi.R_DebugLine(vFrom, trace.endpos, 1.0, 1.0, 1.0, 1.0);
}
void CG_ParseCGMessage()
{
int i;
int iType;
int iLarge;
int iInfo;
int iCount;
char* szTmp;
vec3_t vStart, vEnd, vTmp;
vec3_t vEndArray[MAX_IMPACTS];
qboolean bMoreCGameMessages = qtrue;
while (bMoreCGameMessages) {
iType = cgi.MSG_ReadBits(6);
switch (iType)
{
case 1:
case 2:
case 5:
if (iType == 1)
{
vTmp[0] = cgi.MSG_ReadCoord();
vTmp[1] = cgi.MSG_ReadCoord();
vTmp[2] = cgi.MSG_ReadCoord();
}
vStart[0] = cgi.MSG_ReadCoord();
vStart[1] = cgi.MSG_ReadCoord();
vStart[2] = cgi.MSG_ReadCoord();
if (iType != 1)
{
vTmp[0] = vStart[0];
vTmp[1] = vStart[1];
vTmp[2] = vStart[2];
}
vEndArray[0][0] = cgi.MSG_ReadCoord();
vEndArray[0][1] = cgi.MSG_ReadCoord();
vEndArray[0][2] = cgi.MSG_ReadCoord();
iLarge = cgi.MSG_ReadBits(1);
if (iType == 1) {
CG_MakeBulletTracer(vTmp, vStart, vEndArray, 1, iLarge, qfalse, qtrue);
}
else if (iType == 2) {
CG_MakeBulletTracer(vTmp, vStart, vEndArray, 1, iLarge, qfalse, qtrue);
}
else {
CG_MakeBubbleTrail(vStart, vEndArray[0], iLarge);
}
break;
case 3:
case 4:
if (iType == 3)
{
vTmp[0] = cgi.MSG_ReadCoord();
vTmp[1] = cgi.MSG_ReadCoord();
vTmp[2] = cgi.MSG_ReadCoord();
iInfo = cgi.MSG_ReadBits(6);
}
else
{
iInfo = 0;
}
vStart[0] = cgi.MSG_ReadCoord();
vStart[1] = cgi.MSG_ReadCoord();
vStart[2] = cgi.MSG_ReadCoord();
iLarge = cgi.MSG_ReadBits(1);
iCount = cgi.MSG_ReadBits(6);
for (i = 0; i < iCount; ++i)
{
vEndArray[i][0] = cgi.MSG_ReadCoord();
vEndArray[i][1] = cgi.MSG_ReadCoord();
vEndArray[i][2] = cgi.MSG_ReadCoord();
}
if (iCount) {
CG_MakeBulletTracer(vTmp, vStart, vEndArray, iCount, iLarge, iInfo, qtrue);
}
break;
case 6:
case 7:
case 8:
case 9:
case 10:
vStart[0] = cgi.MSG_ReadCoord();
vStart[1] = cgi.MSG_ReadCoord();
vStart[2] = cgi.MSG_ReadCoord();
cgi.MSG_ReadDir(vEnd);
iLarge = cgi.MSG_ReadBits(1);
switch (iType)
{
case 6:
if (wall_impact_count < MAX_IMPACTS)
{
VectorCopy(vStart, wall_impact_pos[wall_impact_count]);
VectorCopy(vEnd, wall_impact_norm[wall_impact_count]);
wall_impact_large[wall_impact_count] = iLarge;
wall_impact_type[wall_impact_count] = 0;
wall_impact_count++;
}
break;
case 7:
if (flesh_impact_count < MAX_IMPACTS)
{
// negative
VectorNegate(vEnd, vEnd);
VectorCopy(vStart, flesh_impact_pos[flesh_impact_count]);
VectorCopy(vEnd, flesh_impact_norm[flesh_impact_count]);
flesh_impact_large[flesh_impact_count] = iLarge;
flesh_impact_count++;
}
break;
case 8:
if (flesh_impact_count < MAX_IMPACTS)
{
// negative
VectorNegate(vEnd, vEnd);
VectorCopy(vStart, flesh_impact_pos[flesh_impact_count]);
VectorCopy(vEnd, flesh_impact_norm[flesh_impact_count]);
flesh_impact_large[flesh_impact_count] = iLarge;
flesh_impact_count++;
}
break;
case 9:
if (wall_impact_count < MAX_IMPACTS)
{
VectorCopy(vStart, wall_impact_pos[wall_impact_count]);
VectorCopy(vEnd, wall_impact_norm[wall_impact_count]);
wall_impact_large[wall_impact_count] = iLarge;
wall_impact_type[wall_impact_count] = (iLarge != 0) + 2;
wall_impact_count++;
}
break;
case 10:
if (wall_impact_count < MAX_IMPACTS)
{
VectorCopy(vStart, wall_impact_pos[wall_impact_count]);
VectorCopy(vEnd, wall_impact_norm[wall_impact_count]);
wall_impact_large[wall_impact_count] = iLarge;
wall_impact_type[wall_impact_count] = (iLarge != 0) + 4;
wall_impact_count++;
}
break;
default:
continue;
}
break;
case 11:
vStart[0] = cgi.MSG_ReadCoord();
vStart[1] = cgi.MSG_ReadCoord();
vStart[2] = cgi.MSG_ReadCoord();
vEnd[0] = cgi.MSG_ReadCoord();
vEnd[1] = cgi.MSG_ReadCoord();
vEnd[2] = cgi.MSG_ReadCoord();
CG_MeleeImpact(vStart, vEnd);
break;
case 12:
case 13:
vStart[0] = cgi.MSG_ReadCoord();
vStart[1] = cgi.MSG_ReadCoord();
vStart[2] = cgi.MSG_ReadCoord();
CG_MakeExplosionEffect(vStart, iType);
break;
case 15:
case 16:
case 17:
case 18:
case 19:
case 20:
case 21:
case 22:
vStart[0] = cgi.MSG_ReadCoord();
vStart[1] = cgi.MSG_ReadCoord();
vStart[2] = cgi.MSG_ReadCoord();
cgi.MSG_ReadDir(vEnd);
sfxManager.MakeEffect_Normal(iType + 67, vStart, vEnd);
break;
case 23:
case 24:
{
str sEffect;
char cTmp[8];
vec3_t axis[3];
vStart[0] = cgi.MSG_ReadCoord();
vStart[1] = cgi.MSG_ReadCoord();
vStart[2] = cgi.MSG_ReadCoord();
iLarge = cgi.MSG_ReadByte();
// get the integer as string
snprintf(cTmp, sizeof(cTmp), "%d", iLarge);
if (iType == 23) {
sEffect = "models/fx/crates/debris_";
}
else {
sEffect = "models/fx/windows/debris_";
}
sEffect += cTmp;
sEffect += ".tik";
VectorSet(axis[0], 0, 0, 1);
VectorSet(axis[1], 0, 1, 0);
VectorSet(axis[2], 1, 0, 0);
cgi.R_SpawnEffectModel(sEffect.c_str(), vStart, axis);
}
break;
case 25:
vTmp[0] = cgi.MSG_ReadCoord();
vTmp[1] = cgi.MSG_ReadCoord();
vTmp[2] = cgi.MSG_ReadCoord();
vStart[0] = cgi.MSG_ReadCoord();
vStart[1] = cgi.MSG_ReadCoord();
vStart[2] = cgi.MSG_ReadCoord();
vEndArray[0][0] = cgi.MSG_ReadCoord();
vEndArray[0][1] = cgi.MSG_ReadCoord();
vEndArray[0][2] = cgi.MSG_ReadCoord();
iLarge = cgi.MSG_ReadBits(1);
CG_MakeBulletTracer(vTmp, vStart, vEndArray, 1, iLarge, qtrue, qtrue);
break;
case 26:
memset(vTmp, 0, sizeof(vTmp));
vStart[0] = cgi.MSG_ReadCoord();
vStart[1] = cgi.MSG_ReadCoord();
vStart[2] = cgi.MSG_ReadCoord();
vEndArray[0][0] = cgi.MSG_ReadCoord();
vEndArray[0][1] = cgi.MSG_ReadCoord();
vEndArray[0][2] = cgi.MSG_ReadCoord();
iLarge = cgi.MSG_ReadBits(1);
CG_MakeBulletTracer(vTmp, vStart, vEndArray, 1, iLarge, qfalse, qtrue);
break;
case 27:
iInfo = cgi.MSG_ReadByte();
strcpy(cgi.HudDrawElements[iInfo].shaderName, cgi.MSG_ReadString());
cgi.HudDrawElements[iInfo].string[0] = 0;
cgi.HudDrawElements[iInfo].pFont = NULL;
cgi.HudDrawElements[iInfo].fontName[0] = 0;
// set the shader
CG_HudDrawShader(iInfo);
break;
case 28:
iInfo = cgi.MSG_ReadByte();
cgi.HudDrawElements[iInfo].iHorizontalAlign = cgi.MSG_ReadBits(2);
cgi.HudDrawElements[iInfo].iVerticalAlign = cgi.MSG_ReadBits(2);
break;
case 29:
iInfo = cgi.MSG_ReadByte();
cgi.HudDrawElements[iInfo].iX = cgi.MSG_ReadShort();
cgi.HudDrawElements[iInfo].iY = cgi.MSG_ReadShort();
cgi.HudDrawElements[iInfo].iWidth = cgi.MSG_ReadShort();
cgi.HudDrawElements[iInfo].iHeight = cgi.MSG_ReadShort();
break;
case 30:
iInfo = cgi.MSG_ReadByte();
cgi.HudDrawElements[iInfo].bVirtualScreen = cgi.MSG_ReadBits(1);
break;
case 31:
cgi.HudDrawElements[iInfo].vColor[0] = cgi.MSG_ReadByte() / 255.0;
cgi.HudDrawElements[iInfo].vColor[1] = cgi.MSG_ReadByte() / 255.0;
cgi.HudDrawElements[iInfo].vColor[2] = cgi.MSG_ReadByte() / 255.0;
break;
case 32:
cgi.HudDrawElements[iInfo].vColor[3] = cgi.MSG_ReadByte() / 255.0;
break;
case 33:
iInfo = cgi.MSG_ReadByte();
cgi.HudDrawElements[iInfo].hShader = 0;
strcpy(cgi.HudDrawElements[iInfo].string, cgi.MSG_ReadString());
break;
case 34:
iInfo = cgi.MSG_ReadByte();
strcpy(cgi.HudDrawElements[iInfo].fontName, cgi.MSG_ReadString());
cgi.HudDrawElements[iInfo].hShader = 0;
cgi.HudDrawElements[iInfo].shaderName[0] = 0;
// load the font
CG_HudDrawFont(iInfo);
break;
case 35:
case 36:
{
int iOldEnt;
iOldEnt = current_entity_number;
current_entity_number = cg.snap->ps.clientNum;
if (iType == 36) {
commandManager.PlaySound(
"dm_kill_notify",
NULL,
CHAN_LOCAL,
2.0,
-1,
-1,
1
);
}
else {
commandManager.PlaySound(
"dm_hit_notify",
NULL,
CHAN_LOCAL,
2.0,
-1,
-1,
1
);
}
current_entity_number = iOldEnt;
}
break;
case 37:
{
int iOldEnt;
vStart[0] = cgi.MSG_ReadCoord();
vStart[1] = cgi.MSG_ReadCoord();
vStart[2] = cgi.MSG_ReadCoord();
iLarge = cgi.MSG_ReadBits(1);
iInfo = cgi.MSG_ReadBits(6);
szTmp = cgi.MSG_ReadString();
iOldEnt = current_entity_number;
if (iLarge) {
current_entity_number = iInfo;
commandManager.PlaySound(
szTmp,
vStart,
CHAN_LOCAL,
-1,
-1,
-1,
0
);
}
else {
current_entity_number = cg.snap->ps.clientNum;
commandManager.PlaySound(
szTmp,
vStart,
CHAN_AUTO,
-1,
-1,
-1,
1
);
}
current_entity_number = iOldEnt;
}
break;
}
bMoreCGameMessages = cgi.MSG_ReadBits(1);
}
// FIXME: unimplemented
}
@@ -1,6 +1,6 @@
/*
===========================================================================
Copyright (C) 2015 the OpenMoHAA team
Copyright (C) 2023 the OpenMoHAA team
This file is part of OpenMoHAA source code.
@@ -20,13 +20,19 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
#ifndef __EDITFIELD_H__
#define __EDITFIELD_H__
// DESCRIPTION:
// CGM buffer parser
typedef struct EditField_s {
char m_buffer[ 256 ];
int m_cursor;
} EditField;
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
void CG_AddBulletTracers();
void CG_AddBulletImpacts();
void CG_ParseCGMessage();
#ifdef __cplusplus
}
#endif
File diff suppressed because it is too large. Load diff
+76
View File
@@ -0,0 +1,76 @@
/*
===========================================================================
Copyright (C) 2023 the OpenMoHAA team
This file is part of OpenMoHAA source code.
OpenMoHAA source code is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the License,
or (at your option) any later version.
OpenMoHAA source code is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with OpenMoHAA source code; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
// DESCRIPTION:
// Player functions for the cgame
#include "cg_local.h"
#include "cg_commands.h"
/*
player entities generate a great deal of information from implicit ques
taken from the entityState_t
*/
//=====================================================================
/*
===============
CG_ResetPlayerEntity
A player just came into view or teleported, so reset all animation info
===============
*/
void CG_ResetPlayerEntity( centity_t *cent )
{
cent->errorTime = -99999; // guarantee no error decay added
cent->extrapolated = qfalse;
VectorCopy(cent->currentState.origin, cent->lerpOrigin);
VectorCopy(cent->lerpOrigin, cent->rawOrigin);
VectorCopy(cent->currentState.angles, cent->lerpAngles);
VectorCopy(cent->lerpAngles, cent->rawAngles);
if (cent->currentState.number == cg.snap->ps.clientNum)
{
// initialize the camera position
VectorCopy(cent->lerpOrigin, cg.currentViewPos);
// initialize the camera angles
VectorCopy(cent->lerpAngles, cg.currentViewAngles);
}
// Reset splash info
cent->splash_still_count = 0;
}
/*
===============
CG_Player
===============
*/
void CG_Player( centity_t *cent )
{
//CG_PlayerSplash( cent );
}
-396
View File
@@ -1,396 +0,0 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
This file is part of Quake III Arena source code.
Quake III Arena source code is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the License,
or (at your option) any later version.
Quake III Arena source code is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Quake III Arena source code; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
//
// cg_players.c -- handle the media and animation for player entities
#include "cg_local.h"
/*
=============================================================================
CLIENT INFO
=============================================================================
*/
/*
======================
CG_NewClientInfo
======================
*/
// su44: it seems MoHAA's CS_PLAYERS
// contains only player names.
void CG_NewClientInfo( int clientNum ) {
clientInfo_t *ci;
clientInfo_t newInfo;
const char *configstring;
const char *v;
ci = &cgs.clientinfo[clientNum];
configstring = CG_ConfigString( clientNum + CS_PLAYERS );
if ( !configstring[0] ) {
memset( ci, 0, sizeof( *ci ) );
return; // player just left
}
// build into a temp buffer so the defer checks can use
// the old value
memset( &newInfo, 0, sizeof( newInfo ) );
// isolate the player's name
v = Info_ValueForKey(configstring, "name");
Q_strncpyz( newInfo.name, v, sizeof( newInfo.name ) );
// replace whatever was there with the new one
*ci = newInfo;
}
//==========================================================================
/*
===============
CG_PlayerFloatSprite
Float a sprite over the player's head
===============
*/
static void CG_PlayerFloatSprite( centity_t *cent, qhandle_t shader ) {
int rf;
refEntity_t ent;
int b;
if ( cent->currentState.number == cg.snap->ps.clientNum && !cg.renderingThirdPerson ) {
rf = RF_THIRD_PERSON; // only show in mirrors
} else {
rf = 0;
}
memset( &ent, 0, sizeof( ent ) );
// su44: try to get "eyes bone" bone position and use it to position the sprite
if(cent->bones && cgs.gameTIKIs[cent->currentState.modelindex] &&
(b = cgi.TIKI_GetBoneIndex(cgs.gameTIKIs[cent->currentState.modelindex],"eyes bone")) != -1) {
vec3_t dummy;
CG_BoneLocal2World(&cent->bones[b],cent->lerpOrigin,cent->lerpAngles,ent.origin,dummy);
ent.origin[2] += 24;
} else {
VectorCopy( cent->lerpOrigin, ent.origin );
ent.origin[2] += 98;
}
ent.reType = RT_SPRITE;
ent.customShader = shader;
ent.radius = 8;
ent.renderfx = rf;
ent.shaderRGBA[0] = 255;
ent.shaderRGBA[1] = 255;
ent.shaderRGBA[2] = 255;
ent.shaderRGBA[3] = 255;
cgi.R_AddRefEntityToScene( &ent );
}
/*
===============
CG_ExtractPlayerTeam
su44: extract player team from entityState_t::eFlags
and save it to cg.clientinfo
===============
*/
void CG_ExtractPlayerTeam( centity_t *cent ) {
clientInfo_t *ci;
if( cent->currentState.number >= cgs.maxclients ) {
CG_Error("CG_ExtractPlayerTeam on non-client entity (%i)", cent->currentState.number );
}
ci = &cgs.clientinfo[cent->currentState.number];
// MoHAA sends ET_PLAYER team in entityFlags
if(cent->currentState.eFlags & EF_AXIS) {
ci->team = TEAM_AXIS;
} else if(cent->currentState.eFlags & EF_ALLIES) {
ci->team = TEAM_ALLIES;
//} else if(cent->currentState.eFlags & EF_SPECTATOR) {
// ci->team = TEAM_SPECTATOR;
} else {
ci->team = TEAM_FREEFORALL;
}
}
/*
===============
CG_PlayerSprites
Float sprites over the player's head
===============
*/
void CG_PlayerSprites( centity_t *cent ) {
//int team;
//if ( cent->currentState.eFlags & EF_CONNECTION ) {
// CG_PlayerFloatSprite( cent, cgs.media.connectionShader );
// return;
//}
//if ( cent->currentState.eFlags & EF_TALK ) {
// CG_PlayerFloatSprite( cent, cgs.media.balloonShader );
// return;
//}
//team = cgs.clientinfo[ cent->currentState.clientNum ].team;
//if ( !(cent->currentState.eFlags & EF_DEAD) &&
// cg.snap->ps.stats[STAT_TEAM] == team &&
// cgs.gametype >= GT_TEAM) {
// if (cg_drawFriend->integer) {
// //CG_PlayerFloatSprite( cent, cgs.media.friendShader );
// }
// return;
//}
// show team icons over friend heads
if(cgs.gametype >= GT_TEAM && !(cent->currentState.eFlags & EF_DEAD)) {
if(cent->currentState.eFlags & EF_AXIS && cg.snap->ps.stats[STAT_TEAM] == TEAM_AXIS) {
CG_PlayerFloatSprite(cent,cgi.R_RegisterShader("textures/hud/axis.tga"));
} else if(cent->currentState.eFlags & EF_ALLIES && cg.snap->ps.stats[STAT_TEAM] == TEAM_ALLIES) {
CG_PlayerFloatSprite(cent,cgi.R_RegisterShader("textures/hud/allies.tga"));
}
}
}
/*
===============
CG_PlayerShadow
Returns the Z component of the surface being shadowed
should it return a full plane instead of a Z?
===============
*/
#define SHADOW_DISTANCE 128
static qboolean CG_PlayerShadow( centity_t *cent, float *shadowPlane ) {
vec3_t end, mins = {-15, -15, 0}, maxs = {15, 15, 2};
trace_t trace;
float alpha;
*shadowPlane = 0;
if ( cg_shadows->integer == 0 ) {
return qfalse;
}
// send a trace down from the player to the ground
VectorCopy( cent->lerpOrigin, end );
end[2] -= SHADOW_DISTANCE;
cgi.CM_BoxTrace( &trace, cent->lerpOrigin, end, mins, maxs, 0, MASK_PLAYERSOLID, qfalse );
// no shadow if too high
if ( trace.fraction == 1.0 || trace.startsolid || trace.allsolid ) {
return qfalse;
}
*shadowPlane = trace.endpos[2] + 1;
if ( cg_shadows->integer != 1 ) { // no mark for stencil or projection shadows
return qtrue;
}
// fade the shadow out with height
alpha = 1.0 - trace.fraction;
// hack / FPE - bogus planes?
//assert( DotProduct( trace.plane.normal, trace.plane.normal ) != 0.0f )
// add the mark as a temporary, so it goes directly to the renderer
// without taking a spot in the cg_marks array
CG_ImpactMark( cgs.media.shadowMarkShader, trace.endpos, trace.plane.normal,
/*cent->pe.legs.yawAngle*/ 0 , alpha,alpha,alpha,1, qfalse, 24, qtrue );
return qtrue;
}
/*
===============
CG_PlayerSplash
Draw a mark at the water surface
===============
*/
static void CG_PlayerSplash( centity_t *cent ) {
//vec3_t start, end;
//trace_t trace;
//int contents;
//polyVert_t verts[4];
//if ( !cg_shadows->integer ) {
// return;
//}
//VectorCopy( cent->lerpOrigin, end );
//end[2] -= 24;
//// if the feet aren't in liquid, don't make a mark
//// this won't handle moving water brushes, but they wouldn't draw right anyway...
//contents = cgi.CM_PointContents( end, 0 );
//if ( !( contents & ( CONTENTS_WATER | CONTENTS_SLIME | CONTENTS_LAVA ) ) ) {
// return;
//}
//VectorCopy( cent->lerpOrigin, start );
//start[2] += 32;
//// if the head isn't out of liquid, don't make a mark
//contents = cgi.CM_PointContents( start, 0 );
//if ( contents & ( CONTENTS_SOLID | CONTENTS_WATER | CONTENTS_SLIME | CONTENTS_LAVA ) ) {
// return;
//}
//// trace down to find the surface
//cgi.CM_BoxTrace( &trace, start, end, NULL, NULL, 0, ( CONTENTS_WATER | CONTENTS_SLIME | CONTENTS_LAVA ) );
//if ( trace.fraction == 1.0 ) {
// return;
//}
//// create a mark polygon
//VectorCopy( trace.endpos, verts[0].xyz );
//verts[0].xyz[0] -= 32;
//verts[0].xyz[1] -= 32;
//verts[0].st[0] = 0;
//verts[0].st[1] = 0;
//verts[0].modulate[0] = 255;
//verts[0].modulate[1] = 255;
//verts[0].modulate[2] = 255;
//verts[0].modulate[3] = 255;
//VectorCopy( trace.endpos, verts[1].xyz );
//verts[1].xyz[0] -= 32;
//verts[1].xyz[1] += 32;
//verts[1].st[0] = 0;
//verts[1].st[1] = 1;
//verts[1].modulate[0] = 255;
//verts[1].modulate[1] = 255;
//verts[1].modulate[2] = 255;
//verts[1].modulate[3] = 255;
//VectorCopy( trace.endpos, verts[2].xyz );
//verts[2].xyz[0] += 32;
//verts[2].xyz[1] += 32;
//verts[2].st[0] = 1;
//verts[2].st[1] = 1;
//verts[2].modulate[0] = 255;
//verts[2].modulate[1] = 255;
//verts[2].modulate[2] = 255;
//verts[2].modulate[3] = 255;
//VectorCopy( trace.endpos, verts[3].xyz );
//verts[3].xyz[0] += 32;
//verts[3].xyz[1] -= 32;
//verts[3].st[0] = 1;
//verts[3].st[1] = 0;
//verts[3].modulate[0] = 255;
//verts[3].modulate[1] = 255;
//verts[3].modulate[2] = 255;
//verts[3].modulate[3] = 255;
//cgi.R_AddPolyToScene( cgs.media.wakeMarkShader, 4, verts );
}
/*
=================
CG_LightVerts
=================
*/
int CG_LightVerts( vec3_t normal, int numVerts, polyVert_t *verts )
{
#if 0
int i, j;
float incoming;
vec3_t ambientLight;
vec3_t lightDir;
vec3_t directedLight;
for (i = 0; i < numVerts; i++) {
incoming = DotProduct (normal, lightDir);
if ( incoming <= 0 ) {
verts[i].modulate[0] = ambientLight[0];
verts[i].modulate[1] = ambientLight[1];
verts[i].modulate[2] = ambientLight[2];
verts[i].modulate[3] = 255;
continue;
}
j = ( ambientLight[0] + incoming * directedLight[0] );
if ( j > 255 ) {
j = 255;
}
verts[i].modulate[0] = j;
j = ( ambientLight[1] + incoming * directedLight[1] );
if ( j > 255 ) {
j = 255;
}
verts[i].modulate[1] = j;
j = ( ambientLight[2] + incoming * directedLight[2] );
if ( j > 255 ) {
j = 255;
}
verts[i].modulate[2] = j;
verts[i].modulate[3] = 255;
}
#endif
return qtrue;
}
/*
===============
CG_Player
===============
*/
void CG_Player( centity_t *cent ) {
}
//=====================================================================
/*
===============
CG_ResetPlayerEntity
A player just came into view or teleported, so reset all animation info
===============
*/
void CG_ResetPlayerEntity( centity_t *cent ) {
cent->errorTime = -99999; // guarantee no error decay added
cent->extrapolated = qfalse;
//BG_EvaluateTrajectory( &cent->currentState.pos, cg.time, cent->lerpOrigin );
//BG_EvaluateTrajectory( &cent->currentState.apos, cg.time, cent->lerpAngles );
VectorCopy( cent->currentState.origin, cent->lerpOrigin );
VectorCopy( cent->currentState.angles, cent->lerpAngles );
VectorCopy( cent->lerpOrigin, cent->rawOrigin );
VectorCopy( cent->lerpAngles, cent->rawAngles );
}
+12 -152
View File
@@ -1,182 +1,42 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
Copyright (C) 2023 the OpenMoHAA team
This file is part of Quake III Arena source code.
This file is part of OpenMoHAA source code.
Quake III Arena source code is free software; you can redistribute it
OpenMoHAA source code is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the License,
or (at your option) any later version.
Quake III Arena source code is distributed in the hope that it will be
OpenMoHAA source code is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Quake III Arena source code; if not, write to the Free Software
along with OpenMoHAA source code; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
//
// cg_playerstate.c -- this file acts on changes in a new playerState_t
// DESCRIPTION:
//
// this file acts on changes in a new playerState_t.
// With normal play, this will be done after local prediction, but when
// following another player or playing back a demo, it will be checked
// when the snapshot transitions like all the other entities
#include "cg_local.h"
/*
==============
CG_DamageFeedback
==============
*/
void CG_DamageFeedback( int yawByte, int pitchByte, int damage ) {
float left, front, up;
float kick;
int health;
float scale;
vec3_t dir;
vec3_t angles;
float dist;
float yaw, pitch;
// show the attacking player's head and name in corner
cg.attackerTime = cg.time;
// the lower on health you are, the greater the view kick will be
health = cg.snap->ps.stats[STAT_HEALTH];
if ( health < 40 ) {
scale = 1;
} else {
scale = 40.0 / health;
}
kick = damage * scale;
if (kick < 5)
kick = 5;
if (kick > 10)
kick = 10;
// if yaw and pitch are both 255, make the damage always centered (falling, etc)
if ( yawByte == 255 && pitchByte == 255 ) {
cg.damageX = 0;
cg.damageY = 0;
cg.v_dmg_roll = 0;
cg.v_dmg_pitch = -kick;
} else {
// positional
pitch = pitchByte / 255.0 * 360;
yaw = yawByte / 255.0 * 360;
angles[PITCH] = pitch;
angles[YAW] = yaw;
angles[ROLL] = 0;
AngleVectors( angles, dir, NULL, NULL );
VectorSubtract( vec3_origin, dir, dir );
front = DotProduct (dir, cg.refdef.viewaxis[0] );
left = DotProduct (dir, cg.refdef.viewaxis[1] );
up = DotProduct (dir, cg.refdef.viewaxis[2] );
dir[0] = front;
dir[1] = left;
dir[2] = 0;
dist = VectorLength( dir );
if ( dist < 0.1 ) {
dist = 0.1f;
}
cg.v_dmg_roll = kick * left;
cg.v_dmg_pitch = -kick * front;
if ( front <= 0.1 ) {
front = 0.1f;
}
cg.damageX = -left / front;
cg.damageY = up / dist;
}
// clamp the position
if ( cg.damageX > 1.0 ) {
cg.damageX = 1.0;
}
if ( cg.damageX < - 1.0 ) {
cg.damageX = -1.0;
}
if ( cg.damageY > 1.0 ) {
cg.damageY = 1.0;
}
if ( cg.damageY < - 1.0 ) {
cg.damageY = -1.0;
}
// don't let the screen flashes vary as much
if ( kick > 10 ) {
kick = 10;
}
cg.damageValue = kick;
cg.v_dmg_time = cg.time + DAMAGE_TIME;
cg.damageTime = cg.snap->serverTime;
}
/*
================
CG_Respawn
A respawn happened this snapshot
================
*/
void CG_Respawn( void ) {
// no error decay on player movement
cg.thisFrameTeleport = qtrue;
// display weapons available
cg.weaponSelectTime = cg.time;
}
/*
===============
CG_TransitionPlayerState
===============
*/
void CG_TransitionPlayerState( playerState_t *ps, playerState_t *ops ) {
return;//this souhld be empty
////////////////////
// check for changing follow mode
if ( ps->clientNum != ops->clientNum ) {
cg.thisFrameTeleport = qtrue;
// make sure we don't get any unwanted transition effects
*ops = *ps;
}
void CG_TransitionPlayerState( playerState_t *ps, playerState_t *ops )
{
// damage events (player is getting wounded)
//if ( ps->damageEvent != ops->damageEvent && ps->damageCount ) {
// CG_DamageFeedback( ps->damageYaw, ps->damagePitch, ps->damageCount );
//}
// respawning - TODO
//if ( ps->persistant[PERS_SPAWN_COUNT] != ops->persistant[PERS_SPAWN_COUNT] ) {
// CG_Respawn();
//}
if ( cg.mapRestart ) {
CG_Respawn();
cg.mapRestart = qfalse;
}
// smooth the ducking viewheight change
if ( ps->viewheight != ops->viewheight ) {
cg.duckChange = ps->viewheight - ops->viewheight;
cg.duckTime = cg.time;
}
}
}
+409 -397
View File
@@ -1,38 +1,39 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
Copyright (C) 2023 the OpenMoHAA team
This file is part of Quake III Arena source code.
This file is part of OpenMoHAA source code.
Quake III Arena source code is free software; you can redistribute it
OpenMoHAA source code is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the License,
or (at your option) any later version.
Quake III Arena source code is distributed in the hope that it will be
OpenMoHAA source code is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Quake III Arena source code; if not, write to the Free Software
along with OpenMoHAA source code; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
//
// cg_predict.c -- this file generates cg.predictedPlayerState by either
// DESCRIPTION:
// this file generates cg.predicted_player_state by either
// interpolating between snapshots from the server or locally predicting
// ahead the client's movement.
// It also handles local physics interaction, like fragments bouncing off walls
// ahead the client's movement. It also handles local physics interaction,
// like fragments bouncing off walls
#include "cg_local.h"
static pmove_t cg_pmove;
static pmove_t cg_pmove;
static int cg_numSolidEntities;
static centity_t *cg_solidEntities[MAX_ENTITIES_IN_SNAPSHOT];
static int cg_numTriggerEntities;
static centity_t *cg_triggerEntities[MAX_ENTITIES_IN_SNAPSHOT];
static int cg_numSolidEntities;
static centity_t* cg_solidEntities[MAX_ENTITIES_IN_SNAPSHOT];
static int cg_numTriggerEntities;
// static centity_t *cg_triggerEntities[MAX_ENTITIES_IN_SNAPSHOT];
/*
====================
@@ -43,37 +44,41 @@ of the entities that are actually solid, to make for more
efficient collision detection
====================
*/
void CG_BuildSolidList( void ) {
int i;
centity_t *cent;
snapshot_t *snap;
entityState_t *ent;
void CG_BuildSolidList(void)
{
int i;
centity_t* cent;
snapshot_t* snap;
entityState_t* ent;
cg_numSolidEntities = 0;
cg_numTriggerEntities = 0;
cg_numSolidEntities = 0;
cg_numTriggerEntities = 0;
if ( cg.nextSnap && !cg.nextFrameTeleport && !cg.thisFrameTeleport ) {
snap = cg.nextSnap;
} else {
snap = cg.snap;
}
if (cg.nextSnap && !cg.nextFrameTeleport && !cg.thisFrameTeleport) {
snap = cg.nextSnap;
} else {
snap = cg.snap;
}
for ( i = 0 ; i < snap->numEntities ; i++ ) {
cent = &cg_entities[ snap->entities[ i ].number ];
ent = &cent->currentState;
for (i = 0; i < snap->numEntities; i++) {
cent = &cg_entities[snap->entities[i].number];
ent = &cent->currentState;
if ( ent->eType == ET_ITEM || ent->eType == ET_PUSH_TRIGGER || ent->eType == ET_TELEPORT_TRIGGER ) {
cg_triggerEntities[cg_numTriggerEntities] = cent;
cg_numTriggerEntities++;
continue;
}
if (ent->eType == ET_ITEM || ent->eType == ET_PUSH_TRIGGER ||
ent->eType == ET_TELEPORT_TRIGGER) {
/*
cg_triggerEntities[cg_numTriggerEntities] = cent;
cg_numTriggerEntities++;
*/
continue;
}
if ( cent->nextState.solid ) {
cg_solidEntities[cg_numSolidEntities] = cent;
cg_numSolidEntities++;
continue;
}
}
if (cent->nextState.solid) {
cg_solidEntities[cg_numSolidEntities] = cent;
cg_numSolidEntities++;
continue;
}
}
}
/*
@@ -82,61 +87,78 @@ CG_ClipMoveToEntities
====================
*/
static void CG_ClipMoveToEntities ( const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end,
int skipNumber, int mask, trace_t *tr ) {
int i, x, zd, zu;
trace_t trace;
entityState_t *ent;
clipHandle_t cmodel;
vec3_t bmins, bmaxs;
vec3_t origin, angles;
centity_t *cent;
void CG_ClipMoveToEntities(const vec3_t start, const vec3_t mins,
const vec3_t maxs, const vec3_t end,
int skipNumber, int mask, trace_t* tr,
qboolean cylinder)
for ( i = 0 ; i < cg_numSolidEntities ; i++ ) {
cent = cg_solidEntities[ i ];
ent = &cent->currentState;
{
int i;
trace_t trace;
entityState_t* ent;
clipHandle_t cmodel;
vec3_t bmins, bmaxs;
vec3_t origin, angles;
centity_t* cent;
if ( ent->number == skipNumber ) {
continue;
}
for (i = 0; i < cg_numSolidEntities; i++) {
cent = cg_solidEntities[i];
ent = &cent->currentState;
if ( ent->solid == SOLID_BMODEL ) {
// special value for bmodel
cmodel = cgi.CM_InlineModel( ent->modelindex );
VectorCopy( cent->lerpAngles, angles );
//BG_EvaluateTrajectory( &cent->currentState.pos, cg.physicsTime, origin );
// su44: BG_EvaluateTrajectory isnt used in MoHAA
VectorCopy(cent->lerpOrigin,origin);
} else {
// encoded bbox
x = (ent->solid & 255);
zd = ((ent->solid>>8) & 255);
zu = ((ent->solid>>16) & 255) - 32;
if (ent->number == skipNumber) {
continue;
}
bmins[0] = bmins[1] = -x;
bmaxs[0] = bmaxs[1] = x;
bmins[2] = -zd;
bmaxs[2] = zu;
if (ent->solid == SOLID_BMODEL) {
// special value for bmodel
cmodel = cgi.CM_InlineModel(ent->modelindex);
if (!cmodel) {
continue;
}
} else {
IntegerToBoundingBox(ent->solid, bmins, bmaxs);
cmodel = cgi.CM_TempBoxModel(
bmins, bmaxs,
CONTENTS_BBOX);
}
cmodel = cgi.CM_TempBoxModel( bmins, bmaxs, qfalse );
VectorCopy( vec3_origin, angles );
VectorCopy( cent->lerpOrigin, origin );
}
VectorCopy(cent->lerpOrigin, origin);
if (ent->eFlags & EF_LINKANGLES) {
VectorCopy(cent->lerpAngles, angles);
}
else {
VectorClear(angles);
}
cgi.CM_TransformedBoxTrace(&trace, start, end, mins, maxs, cmodel, mask,
origin, angles, cylinder);
cgi.CM_TransformedBoxTrace ( &trace, start, end,
mins, maxs, cmodel, mask, origin, angles, qfalse );
if (trace.allsolid || trace.fraction < tr->fraction) {
trace.entityNum = ent->number;
*tr = trace;
} else if (trace.startsolid) {
tr->startsolid = qtrue;
}
}
}
if (trace.allsolid || trace.fraction < tr->fraction) {
trace.entityNum = ent->number;
*tr = trace;
} else if (trace.startsolid) {
tr->startsolid = qtrue;
}
if ( tr->allsolid ) {
return;
}
}
void CG_ShowTrace(trace_t* trace, int passent, const char* reason)
{
char text[1024];
assert(reason);
assert(trace);
sprintf(text, "%0.2f : Pass (%d) Frac %f Hit (%d): '%s'\n",
(float)cg.time / 1000.0f, passent, trace->fraction,
trace->entityNum, reason ? reason : "");
if (cg_traceinfo->integer == 3) {
cgi.DebugPrintf(text);
} else {
cgi.DPrintf(text);
}
}
/*
@@ -144,9 +166,34 @@ static void CG_ClipMoveToEntities ( const vec3_t start, const vec3_t mins, const
CG_Trace
================
*/
void CG_Trace( trace_t *result, const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end,
int skipNumber, int mask ) {
CG_PlayerTrace( result, start, mins, maxs, end, skipNumber, mask, qfalse, qfalse );
void CG_Trace(trace_t* result, const vec3_t start, const vec3_t mins,
const vec3_t maxs, const vec3_t end, int skipNumber, int mask,
qboolean cylinder, qboolean cliptoentities,
const char* description)
{
trace_t t;
cgi.CM_BoxTrace(&t, start, end, mins, maxs, 0, mask, cylinder);
t.entityNum = t.fraction != 1.0 ? ENTITYNUM_WORLD : ENTITYNUM_NONE;
// If starting in a solid make sure the world is set as the entitynum
if (t.startsolid) {
t.entityNum = ENTITYNUM_WORLD;
}
if (cliptoentities) {
// check all other solid models
CG_ClipMoveToEntities(start, mins, maxs, end, skipNumber, mask, &t,
cylinder);
}
*result = t;
if (cg_traceinfo->integer) {
CG_ShowTrace(result, skipNumber, description);
}
}
/*
@@ -154,16 +201,13 @@ void CG_Trace( trace_t *result, const vec3_t start, const vec3_t mins, const vec
CG_PlayerTrace
================
*/
void CG_PlayerTrace( trace_t *result, const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end,
int skipNumber, int mask, int capsule, qboolean traceDeep ) {
trace_t t;
void CG_PlayerTrace(trace_t* result, const vec3_t start, const vec3_t mins,
const vec3_t maxs, const vec3_t end, int skipNumber,
int mask, qboolean cylinder, qboolean tracedeep)
cgi.CM_BoxTrace( &t, start, end, mins, maxs, 0, mask, traceDeep );
t.entityNum = t.fraction != 1.0 ? ENTITYNUM_WORLD : ENTITYNUM_NONE;
// check all other solid models
CG_ClipMoveToEntities( start, mins, maxs, end, skipNumber, mask, &t );
*result = t;
{
CG_Trace(result, start, mins, maxs, end, skipNumber, mask, cylinder, qtrue,
"PlayerTrace");
}
/*
@@ -171,165 +215,157 @@ void CG_PlayerTrace( trace_t *result, const vec3_t start, const vec3_t mins, con
CG_PointContents
================
*/
int CG_PointContents( const vec3_t point, int passEntityNum ) {
int i;
entityState_t *ent;
centity_t *cent;
clipHandle_t cmodel;
int contents;
int CG_PointContents(const vec3_t point, int passEntityNum)
{
int i;
entityState_t* ent;
centity_t* cent;
clipHandle_t cmodel;
int contents;
contents = cgi.CM_PointContents (point, 0);
contents = cgi.CM_PointContents(point, 0);
for ( i = 0 ; i < cg_numSolidEntities ; i++ ) {
cent = cg_solidEntities[ i ];
for (i = 0; i < cg_numSolidEntities; i++) {
cent = cg_solidEntities[i];
ent = &cent->currentState;
ent = &cent->currentState;
if ( ent->number == passEntityNum ) {
continue;
}
if (ent->number == passEntityNum) {
continue;
}
if (ent->solid != SOLID_BMODEL) { // special value for bmodel
continue;
}
if (ent->solid != SOLID_BMODEL) { // special value for bmodel
continue;
}
cmodel = cgi.CM_InlineModel( ent->modelindex );
if ( !cmodel ) {
continue;
}
cmodel = cgi.CM_InlineModel(ent->modelindex);
if (!cmodel) {
continue;
}
contents |= cgi.CM_TransformedPointContents( point, cmodel, ent->origin, ent->angles );
}
contents |= cgi.CM_TransformedPointContents(point, cmodel, ent->origin,
ent->angles);
}
return contents;
return contents;
}
/*
========================
CG_InterpolatePlayerStateCamera
Generates cg.predicted_player_state by interpolating between
cg.snap->player_state and cg.nextFrame->player_state
========================
*/
static void CG_InterpolatePlayerStateCamera(void)
{
float f;
int i;
snapshot_t *prev, *next;
prev = cg.snap;
next = cg.nextSnap;
//
// copy in the current ones if nothing else
//
VectorCopy(cg.predicted_player_state.camera_angles, cg.camera_angles);
VectorCopy(cg.predicted_player_state.camera_origin, cg.camera_origin);
cg.camera_fov = cg.predicted_player_state.fov;
// if the next frame is a teleport, we can't lerp to it
if (cg.nextFrameCameraCut) {
return;
}
if (!next || next->serverTime <= prev->serverTime) {
return;
}
f = (float)(cg.time - prev->serverTime) /
(next->serverTime - prev->serverTime);
// interpolate fov
cg.camera_fov = prev->ps.fov + f * (next->ps.fov - prev->ps.fov);
if (!(cg.snap->ps.pm_flags & PMF_CAMERA_VIEW)) {
return;
}
for (i = 0; i < 3; i++) {
cg.camera_origin[i] =
prev->ps.camera_origin[i] +
f * (next->ps.camera_origin[i] - prev->ps.camera_origin[i]);
cg.camera_angles[i] =
LerpAngle(prev->ps.camera_angles[i], next->ps.camera_angles[i], f);
}
}
/*
========================
CG_InterpolatePlayerState
Generates cg.predictedPlayerState by interpolating between
Generates cg.predicted_player_state by interpolating between
cg.snap->player_state and cg.nextFrame->player_state
========================
*/
static void CG_InterpolatePlayerState( qboolean grabAngles ) {
float f;
int i;
playerState_t *out;
snapshot_t *prev, *next;
static void CG_InterpolatePlayerState(qboolean grabAngles)
{
float f;
int i;
playerState_t* out;
snapshot_t *prev, *next;
out = &cg.predictedPlayerState;
prev = cg.snap;
next = cg.nextSnap;
out = &cg.predicted_player_state;
prev = cg.snap;
next = cg.nextSnap;
*out = cg.snap->ps;
*out = cg.snap->ps;
// if we are still allowing local input, short circuit the view angles
if ( grabAngles ) {
usercmd_t cmd;
int cmdNum;
// interpolate the camera if necessary
CG_InterpolatePlayerStateCamera();
cmdNum = cgi.GetCurrentCmdNumber();
cgi.GetUserCmd( cmdNum, &cmd );
// if we are still allowing local input, short circuit the view angles
if (grabAngles) {
usercmd_t cmd;
int cmdNum;
PM_UpdateViewAngles( out, &cmd );
}
cmdNum = cgi.GetCurrentCmdNumber();
cgi.GetUserCmd(cmdNum, &cmd);
// if the next frame is a teleport, we can't lerp to it
if ( cg.nextFrameTeleport ) {
return;
}
PM_UpdateViewAngles(out, &cmd);
}
if ( !next || next->serverTime <= prev->serverTime ) {
return;
}
// if the next frame is a teleport, we can't lerp to it
if (cg.nextFrameTeleport) {
return;
}
f = (float)( cg.time - prev->serverTime ) / ( next->serverTime - prev->serverTime );
if (!next || next->serverTime <= prev->serverTime) {
return;
}
i = next->ps.bobCycle;
if ( i < prev->ps.bobCycle ) {
i += 256; // handle wraparound
}
out->bobCycle = prev->ps.bobCycle + f * ( i - prev->ps.bobCycle );
out->fLeanAngle = prev->ps.fLeanAngle +
f * (next->ps.fLeanAngle - prev->ps.fLeanAngle );
for ( i = 0 ; i < 3 ; i++ ) {
out->origin[i] = prev->ps.origin[i] + f * (next->ps.origin[i] - prev->ps.origin[i] );
if ( !grabAngles ) {
out->viewangles[i] = LerpAngle(
prev->ps.viewangles[i], next->ps.viewangles[i], f );
}
out->velocity[i] = prev->ps.velocity[i] +
f * (next->ps.velocity[i] - prev->ps.velocity[i] );
}
f = cg.frameInterpolation;
for (i = 0; i < 3; i++) {
out->origin[i] =
prev->ps.origin[i] + f * (next->ps.origin[i] - prev->ps.origin[i]);
if (!grabAngles) {
out->viewangles[i] =
LerpAngle(prev->ps.viewangles[i], next->ps.viewangles[i], f);
}
out->velocity[i] = prev->ps.velocity[i] +
f * (next->ps.velocity[i] - prev->ps.velocity[i]);
}
}
/*
=========================
CG_TouchTriggerPrediction
Predict push triggers and items
=========================
*/
static void CG_TouchTriggerPrediction( void ) {
int i;
trace_t trace;
entityState_t *ent;
clipHandle_t cmodel;
centity_t *cent;
qboolean spectator;
// dead clients don't activate triggers
if ( cg.predictedPlayerState.stats[STAT_HEALTH] <= 0 ) {
return;
}
spectator = ( cg.predictedPlayerState.pm_type == PM_NOCLIP );
if ( cg.predictedPlayerState.pm_type != PM_NORMAL && !spectator ) {
return;
}
for ( i = 0 ; i < cg_numTriggerEntities ; i++ ) {
cent = cg_triggerEntities[ i ];
ent = &cent->currentState;
if ( ent->solid != SOLID_BMODEL ) {
continue;
}
cmodel = cgi.CM_InlineModel( ent->modelindex );
if ( !cmodel ) {
continue;
}
cgi.CM_BoxTrace( &trace, cg.predictedPlayerState.origin, cg.predictedPlayerState.origin,
cg_pmove.mins, cg_pmove.maxs, cmodel, -1, qfalse );
if ( !trace.startsolid ) {
continue;
}
if ( ent->eType == ET_TELEPORT_TRIGGER ) {
cg.hyperspace = qtrue;
} else if ( ent->eType == ET_PUSH_TRIGGER ) {
//BG_TouchJumpPad( &cg.predictedPlayerState, ent );
}
}
}
/*
=================
CG_PredictPlayerState
Generates cg.predictedPlayerState for the current cg.time
cg.predictedPlayerState is guaranteed to be valid after exiting.
Generates cg.predicted_player_state for the current cg.time
cg.predicted_player_state is guaranteed to be valid after exiting.
For demo playback, this will be an interpolation between two valid
playerState_t.
@@ -350,207 +386,183 @@ We detect prediction errors and allow them to be decayed off over several frames
to ease the jerk.
=================
*/
void CG_PredictPlayerState( void ) {
int cmdNum, current;
playerState_t oldPlayerState;
qboolean moved;
usercmd_t oldestCmd;
usercmd_t latestCmd;
//FIXME: stub
cg.hyperspace = qfalse; // will be set if touching a trigger_teleport
void CG_PredictPlayerState(void)
{
int cmdNum, current;
playerState_t oldPlayerState;
qboolean moved;
usercmd_t latestCmd;
// if this is the first frame we must guarantee
// predictedPlayerState is valid even if there is some
// other error condition
if ( !cg.validPPS ) {
cg.validPPS = qtrue;
cg.predictedPlayerState = cg.snap->ps;
}
cg.hyperspace = qfalse; // will be set if touching a trigger_teleport
// if this is the first frame we must guarantee
// predicted_player_state is valid even if there is some
// other error condition
if (!cg.validPPS) {
cg.validPPS = qtrue;
cg.predicted_player_state = cg.snap->ps;
}
// demo playback just copies the moves
if ( cg.demoPlayback || (cg.snap->ps.pm_flags & PMF_NO_PREDICTION ) || (cg.snap->ps.pm_flags & PMF_FROZEN) ) {
CG_InterpolatePlayerState( qfalse );
return;
}
// demo playback just copies the moves
if (cg.demoPlayback || (cg.snap->ps.pm_flags & PMF_NO_PREDICTION) ||
(cg.snap->ps.pm_flags & PMF_FROZEN)) {
CG_InterpolatePlayerState(qfalse);
return;
}
// non-predicting local movement will grab the latest angles
if ( cg_nopredict->integer || cg_synchronousClients->integer || cg.snap->ps.pm_type & PM_NOCLIP) {
CG_InterpolatePlayerState( qtrue );
return;
}
// non-predicting local movement will grab the latest angles
// FIXME
// Noclip is jittery for some reason, so I'm disabling prediction while
// noclipping
if (cg_nopredict->integer || cg_synchronousClients->integer ||
(cg.snap->ps.pm_type == PM_NOCLIP)) {
CG_InterpolatePlayerState(qtrue);
return;
}
#if 1
// su44: temporary disabling playerstate prediction
CG_InterpolatePlayerState( qtrue );
return;
#endif
// prepare for pmove
cg_pmove.ps = &cg.predicted_player_state;
cg_pmove.trace = CG_PlayerTrace;
cg_pmove.pointcontents = CG_PointContents;
// prepare for pmove
cg_pmove.ps = &cg.predictedPlayerState;
cg_pmove.trace = CG_PlayerTrace;
cg_pmove.pointcontents = CG_PointContents;
if ( cg_pmove.ps->pm_type == PM_DEAD ) {
cg_pmove.tracemask = MASK_PLAYERSOLID & ~CONTENTS_BODY;
}
else {
cg_pmove.tracemask = MASK_PLAYERSOLID;
}
if ( cg.snap->ps.stats[STAT_TEAM] == TEAM_SPECTATOR ) {
cg_pmove.tracemask &= ~CONTENTS_BODY; // spectators can fly through bodies
}
cg_pmove.noFootsteps = ( cgs.dmflags & DF_NO_FOOTSTEPS ) > 0;
if (cg_pmove.ps->pm_type == PM_DEAD) {
cg_pmove.tracemask = MASK_PLAYERSOLID & ~CONTENTS_BODY;
} else {
cg_pmove.tracemask = MASK_PLAYERSOLID;
}
// save the state before the pmove so we can detect transitions
oldPlayerState = cg.predictedPlayerState;
cg_pmove.noFootsteps = (cgs.dmflags & DF_NO_FOOTSTEPS) > 0;
current = cgi.GetCurrentCmdNumber();
// save the state before the pmove so we can detect transitions
oldPlayerState = cg.predicted_player_state;
// if we don't have the commands right after the snapshot, we
// can't accurately predict a current position, so just freeze at
// the last good position we had
cmdNum = current - CMD_BACKUP + 1;
cgi.GetUserCmd( cmdNum, &oldestCmd );
if ( oldestCmd.serverTime > cg.snap->ps.commandTime
&& oldestCmd.serverTime < cg.time ) { // special check for map_restart
if ( cg_showmiss->integer ) {
CG_Printf ("exceeded PACKET_BACKUP on commands\n");
}
return;
}
current = cgi.GetCurrentCmdNumber();
// get the latest command so we can know which commands are from previous map_restarts
cgi.GetUserCmd( current, &latestCmd );
// get the latest command so we can know which commands are from previous
// map_restarts
cgi.GetUserCmd(current, &latestCmd);
// get the most recent information we have, even if
// the server time is beyond our current cg.time,
// because predicted player positions are going to
// be ahead of everything else anyway
if ( cg.nextSnap && !cg.nextFrameTeleport && !cg.thisFrameTeleport ) {
cg.predictedPlayerState = cg.nextSnap->ps;
cg.physicsTime = cg.nextSnap->serverTime;
} else {
cg.predictedPlayerState = cg.snap->ps;
cg.physicsTime = cg.snap->serverTime;
}
// get the most recent information we have, even if
// the server time is beyond our current cg.time,
// because predicted player positions are going to
// be ahead of everything else anyway
if (cg.nextSnap && !cg.nextFrameTeleport && !cg.thisFrameTeleport) {
cg.predicted_player_state = cg.nextSnap->ps;
cg.physicsTime = cg.nextSnap->serverTime;
} else {
cg.predicted_player_state = cg.snap->ps;
cg.physicsTime = cg.snap->serverTime;
}
if ( pmove_msec->integer < 8 ) {
cgi.Cvar_Set("pmove_msec", "8");
}
else if (pmove_msec->integer > 33) {
cgi.Cvar_Set("pmove_msec", "33");
}
if (pmove_msec->integer >= 8)
{
if (pmove_msec->integer > 33)
cgi.Cvar_Set("pmove_msec", "33");
}
else
{
cgi.Cvar_Set("pmove_msec", "8");
}
cg_pmove.pmove_fixed = pmove_fixed->integer;// | cg_pmove_fixed->integer;
cg_pmove.pmove_msec = pmove_msec->integer;
cg_pmove.pmove_fixed = pmove_fixed->integer;
cg_pmove.pmove_msec = pmove_msec->integer;
// run cmds
moved = qfalse;
for ( cmdNum = current - CMD_BACKUP + 1 ; cmdNum <= current ; cmdNum++ ) {
// get the command
cgi.GetUserCmd( cmdNum, &cg_pmove.cmd );
// run cmds
moved = qfalse;
for (cmdNum = current - CMD_BACKUP + 1; cmdNum <= current; cmdNum++) {
// get the command
cgi.GetUserCmd(cmdNum, &cg_pmove.cmd);
if ( cg_pmove.pmove_fixed ) {
PM_UpdateViewAngles( cg_pmove.ps, &cg_pmove.cmd );
}
if (cg_pmove.pmove_fixed) {
PM_UpdateViewAngles(cg_pmove.ps, &cg_pmove.cmd);
}
// don't do anything if the time is before the snapshot player time
if ( cg_pmove.cmd.serverTime <= cg.predictedPlayerState.commandTime ) {
continue;
}
// don't do anything if the time is before the snapshot player time
if (cg_pmove.cmd.serverTime <= cg.predicted_player_state.commandTime) {
continue;
}
// don't do anything if the command was from a previous map_restart
if ( cg_pmove.cmd.serverTime > latestCmd.serverTime ) {
continue;
}
// don't do anything if the command was from a previous map_restart
if (cg_pmove.cmd.serverTime > latestCmd.serverTime) {
continue;
}
// check for a prediction error from last frame
// on a lan, this will often be the exact value
// from the snapshot, but on a wan we will have
// to predict several commands to get to the point
// we want to compare
if ( cg.predictedPlayerState.commandTime == oldPlayerState.commandTime ) {
vec3_t delta;
float len;
// check for a prediction error from last frame
// on a lan, this will often be the exact value
// from the snapshot, but on a wan we will have
// to predict several commands to get to the point
// we want to compare
if (cg.predicted_player_state.commandTime ==
oldPlayerState.commandTime) {
if ( cg.thisFrameTeleport ) {
// a teleport will not cause an error decay
VectorClear( cg.predictedError );
if ( cg_showmiss->integer ) {
CG_Printf( "PredictionTeleport\n" );
}
cg.thisFrameTeleport = qfalse;
} else {
vec3_t adjusted;
CG_AdjustPositionForMover( cg.predictedPlayerState.origin,
cg.predictedPlayerState.groundEntityNum, cg.physicsTime, cg.oldTime, adjusted );
if (cg.thisFrameTeleport) {
// a teleport will not cause an error decay
VectorClear(cg.predictedError);
cg.thisFrameTeleport = qfalse;
if (cg_showmiss->integer) {
cgi.Printf("PredictionTeleport\n");
}
}
}
if ( cg_showmiss->integer ) {
if (!VectorCompare( oldPlayerState.origin, adjusted )) {
CG_Printf("prediction error\n");
}
}
VectorSubtract( oldPlayerState.origin, adjusted, delta );
len = VectorLength( delta );
if ( len > 0.1 ) {
if ( cg_showmiss->integer ) {
CG_Printf("Prediction miss: %f\n", len);
}
if ( cg_errorDecay->integer ) {
int t;
float f;
// if our feet are falling, don't try to move
if (cg_pmove.ps->feetfalling && (cg_pmove.waterlevel < 2)) {
cg_pmove.cmd.forwardmove = 0;
cg_pmove.cmd.rightmove = 0;
}
t = cg.time - cg.predictedErrorTime;
f = ( cg_errorDecay->value - t ) / cg_errorDecay->value;
if ( f < 0 ) {
f = 0;
}
if ( f > 0 && cg_showmiss->integer ) {
CG_Printf("Double prediction decay: %f\n", f);
}
VectorScale( cg.predictedError, f, cg.predictedError );
} else {
VectorClear( cg.predictedError );
}
VectorAdd( delta, cg.predictedError, cg.predictedError );
cg.predictedErrorTime = cg.oldTime;
}
}
}
if (cg_pmove.pmove_fixed) {
cg_pmove.cmd.serverTime = pmove_msec->integer
* ((cg_pmove.cmd.serverTime + pmove_msec->integer - 1)
/ pmove_msec->integer);
}
if ( cg_pmove.pmove_fixed ) {
cg_pmove.cmd.serverTime = ((cg_pmove.cmd.serverTime + pmove_msec->integer-1) / pmove_msec->integer) * pmove_msec->integer;
}
Pmove(&cg_pmove);
Pmove (&cg_pmove);
moved = qtrue;
moved = qtrue;
// add push trigger movement effects
// CG_TouchTriggerPrediction();
}
// add push trigger movement effects
CG_TouchTriggerPrediction();
if (cg_showmiss->integer > 1) {
cgi.Printf("[%i : %i] ", cg_pmove.cmd.serverTime, cg.time);
}
// check for predictable events that changed from previous predictions
//CG_CheckChangedPredictableEvents(&cg.predictedPlayerState);
}
// interpolate the camera if necessary
CG_InterpolatePlayerStateCamera();
if ( cg_showmiss->integer > 1 ) {
CG_Printf( "[%i : %i] ", cg_pmove.cmd.serverTime, cg.time );
}
// Interpolate the player position
if (cg.predicted_player_state.groundEntityNum != ENTITYNUM_WORLD) {
centity_t* cent;
vec3_t offset;
if ( !moved ) {
if ( cg_showmiss->integer ) {
CG_Printf( "not moved\n" );
}
return;
}
cent = &cg_entities[cg.predicted_player_state.groundEntityNum];
// adjust for the movement of the groundentity
CG_AdjustPositionForMover( cg.predictedPlayerState.origin,
cg.predictedPlayerState.groundEntityNum,
cg.physicsTime, cg.time, cg.predictedPlayerState.origin );
if (cent->interpolate) {
float f;
// fire events and other transition triggered things
CG_TransitionPlayerState( &cg.predictedPlayerState, &oldPlayerState );
f = cg.frameInterpolation - 1.0;
offset[0] = (cent->nextState.origin[0] - cg_entities[cg.predicted_player_state.groundEntityNum].currentState.origin[0]) * f;
offset[1] = (cent->nextState.origin[1] - cg_entities[cg.predicted_player_state.groundEntityNum].currentState.origin[1]) * f;
offset[2] = (cent->nextState.origin[2] - cg_entities[cg.predicted_player_state.groundEntityNum].currentState.origin[2]) * f;
cg.predicted_player_state.origin[0] += offset[0];
cg.predicted_player_state.origin[1] += offset[1];
cg.predicted_player_state.origin[2] += offset[2];
}
}
// adjust for the movement of the groundentity
if (!moved) {
if (cg_showmiss->integer) {
cgi.Printf("not moved\n");
}
return;
}
// fire events and other transition triggered things
CG_TransitionPlayerState(&cg.predicted_player_state, &oldPlayerState);
}
+356 -519
View File
@@ -1,41 +1,45 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
Copyright (C) 2023 the OpenMoHAA team
This file is part of Quake III Arena source code.
This file is part of OpenMoHAA source code.
Quake III Arena source code is free software; you can redistribute it
OpenMoHAA source code is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the License,
or (at your option) any later version.
Quake III Arena source code is distributed in the hope that it will be
OpenMoHAA source code is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Quake III Arena source code; if not, write to the Free Software
along with OpenMoHAA source code; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
//
// DESCRIPTION:
// client game public interfaces
#ifndef __CG_PUBLIC_H__
#define __CG_PUBLIC_H__
#include <tiki.h>
#ifdef __cplusplus
extern "C"
{
#endif
#define CMD_BACKUP 128
#define CMD_MASK (CMD_BACKUP - 1)
#define MAGIC_UNUSED_NUMBER 7777
#define CMD_BACKUP 128
#define CMD_MASK (CMD_BACKUP - 1)
// allow a lot of command backups for very fast systems
// multiple commands may be combined into a single packet, so this
// needs to be larger than PACKET_BACKUP
#define MAX_ENTITIES_IN_SNAPSHOT 1024
#define MAX_SOUNDS_IN_SNAPSHOT 64
#define MAX_HUDDRAW_ELEMENTS 256
#define MAX_ENTITIES_IN_SNAPSHOT 1024
// snapshots are a view of the server at a given time
@@ -43,83 +47,36 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
// but they may not be sent if a client's rate level is exceeded, or
// they may be dropped by the network.
typedef struct {
int snapFlags; // SNAPFLAG_RATE_DELAYED, etc
int ping;
int snapFlags; // SNAPFLAG_RATE_DELAYED, etc
int ping;
int serverTime; // server time the message is valid for (in msec)
int serverTime; // server time the message is valid for (in msec)
byte areamask[MAX_MAP_AREA_BYTES]; // portalarea visibility bits
byte areamask[MAX_MAP_AREA_BYTES]; // portalarea visibility bits
playerState_t ps; // complete information about the current player at this time
playerState_t ps; // complete information about the current player at this time
int numEntities; // all of the entities that need to be presented
entityState_t entities[MAX_ENTITIES_IN_SNAPSHOT]; // at the time of this snapshot
int numEntities; // all of the entities that need to be presented
entityState_t entities[MAX_ENTITIES_IN_SNAPSHOT]; // at the time of this snapshot
int numServerCommands; // text based server commands to execute when this
int serverCommandSequence; // snapshot becomes current
int numServerCommands; // text based server commands to execute when this
int serverCommandSequence; // snapshot becomes current
int number_of_sounds;
server_sound_t sounds[MAX_SOUNDS_IN_SNAPSHOT];
int number_of_sounds;
server_sound_t sounds[ MAX_SERVER_SOUNDS ];
} snapshot_t;
typedef struct stopwatch_s {
int iStartTime;
int iEndTime;
} stopwatch_t;
typedef struct hdelement_s {
qhandle_t hShader;
char shaderName[ 64 ];
int iX;
int iY;
int iWidth;
int iHeight;
float vColor[ 4 ];
int iHorizontalAlign;
int iVerticalAlign;
qboolean bVirtualScreen;
char string[ 2048 ];
char fontName[ 64 ];
fontheader_t *pFont;
} hdelement_t;
/*
==================================================================
clientAnim_t structure, wiped each new gamestate
reserved for viewmodelanim
==================================================================
*/
typedef struct clientAnim_s
typedef struct stopWatch_s
{
frameInfo_t vmFrameInfo[ MAX_FRAMEINFOS ];
int lastVMAnim;
int lastVMAnimChanged;
int iStartTime;
int iEndTime;
int currentVMAnimSlot;
int currentVMDuration;
qboolean crossBlending;
int lastEquippedWeaponStat;
char lastActiveItem[ 80 ];
int lastAnimPrefixIndex;
vec3_t currentVMPosOffset;
refEntity_t ref;
dtiki_t *tiki;
} clientAnim_t;
enum {
CGAME_EVENT_NONE,
CGAME_EVENT_TEAMMENU,
CGAME_EVENT_SCOREBOARD,
CGAME_EVENT_EDITHUD
};
} stopWatch_t;
typedef struct AliasList_s AliasList_t;
typedef struct AliasListNode_s AliasListNode_t;
typedef struct dtiki_s dtiki_t;
typedef struct tiki_cmd_s tiki_cmd_t;
/*
==================================================================
@@ -129,416 +86,7 @@ functions imported from the main executable
==================================================================
*/
#define CGAME_IMPORT_API_VERSION 4
#if 0
typedef struct clientGameImport_s {
// print message on the local console
void( *Printf )( const char *fmt, ... );
void( *DPrintf )( const char *fmt, ... );
// abort the game
void( *Error )( int level, const char *fmt, ... );
// milliseconds should only be used for performance tuning, never
// for anything game related. Get time from the CG_DrawActiveFrame parameter
int( *Milliseconds )( void );
void *( *Malloc )( int size );
void( *Free )( void *ptr );
// console variable interaction
cvar_t *( *Cvar_Get )( const char *varName, const char *varValue, int varFlags );
void( *Cvar_Register )( vmCvar_t *vmCvar, const char *varName, const char *defaultValue, int flags );
void( *Cvar_Update )( vmCvar_t *vmCvar );
void( *Cvar_Set )( const char *var_name, const char *value );
void( *Cvar_VariableStringBuffer )( const char *var_name, char *buffer, int bufsize );
// ServerCommand and ConsoleCommand parameter access
int( *Argc )( void );
char *( *Argv )( int n );
char *( *Args )( void );
// filesystem access
// returns length of file
int( *FS_FOpenFile )( const char *qpath, fileHandle_t *f, fsMode_t mode );
int ( *FS_Read )( void *buffer, int len, fileHandle_t f );
int ( *FS_Write )( const void *buffer, int len, fileHandle_t f );
void ( *FS_FCloseFile )( fileHandle_t f );
int ( *FS_GetFileList )( const char *path, const char *extension, char *listbuf, int bufsize );
int ( *FS_Seek )( fileHandle_t f, long offset, fsOrigin_t origin ); // fsOrigin_t
int ( *FS_ReadFile )( const char *name, void **buffer, qboolean quiet );
void ( *FS_FreeFile )( void *buffer );
int ( *FS_WriteFile )( const char *qpath, const void *buffer, int size );
int ( *FS_FOpenFileWrite )( const char *name );
void ( *FS_Flush )( fileHandle_t f );
// add commands to the local console as if they were typed in
// for map changing, etc. The command is not executed immediately,
// but will be executed in order the next time console commands
// are processed
void( *SendConsoleCommand )( const char *text );
// register a command name so the console can perform command completion.
// FIXME: replace this with a normal console command "defineCommand"?
void( *AddCommand )( const char *cmdName, xcommand_t function );
// send a string to the server over the network
void( *SendClientCommand )( const char *s );
// force a screen update, only used during gamestate load
void( *UpdateScreen )( void );
// model collision
void( *CM_LoadMap )( const char *mapname );
int( *CM_NumInlineModels )( void );
clipHandle_t( *CM_InlineModel )( int index ); // 0 = world, 1+ = bmodels
clipHandle_t( *CM_TempBoxModel )( const vec3_t mins, const vec3_t maxs, qboolean capsule );
int( *CM_PointContents )( const vec3_t p, clipHandle_t model );
int( *CM_TransformedPointContents )( const vec3_t p, clipHandle_t model, const vec3_t origin, const vec3_t angles );
void( *CM_BoxTrace )( trace_t *results, const vec3_t start, const vec3_t end,
const vec3_t mins, const vec3_t maxs,
clipHandle_t model, int brushmask, qboolean capsule );
void( *CM_TransformedBoxTrace )( trace_t *results, const vec3_t start, const vec3_t end,
const vec3_t mins, const vec3_t maxs,
clipHandle_t model, int brushmask,
const vec3_t origin, const vec3_t angles, qboolean capsule );
// Returns the projection of a polygon onto the solid brushes in the world
int( *CM_MarkFragments )( int numPoints, const vec3_t *points,
const vec3_t projection,
int maxPoints, vec3_t pointBuffer,
int maxFragments, markFragment_t *fragmentBuffer );
// normal sounds will have their volume dynamically changed as their entity
// moves and the listener moves
void( *S_StartSound )( vec3_t origin, int entityNum, int entchannel, sfxHandle_t sfx );
void( *S_StopLoopingSound )( int entnum );
// a local sound is always played full volume
void( *S_StartLocalSound )( sfxHandle_t sfx, int channelNum );
void( *S_ClearLoopingSounds )( qboolean killall );
void( *S_AddLoopingSound )( int entityNum, const vec3_t origin, const vec3_t velocity, sfxHandle_t sfx );
void( *S_AddRealLoopingSound )( int entityNum, const vec3_t origin, const vec3_t velocity, sfxHandle_t sfx );
void( *S_UpdateEntityPosition )( int entityNum, const vec3_t origin );
// respatialize recalculates the volumes of sound as they should be heard by the
// given entityNum and position
void( *S_Respatialize )( int entityNum, const vec3_t origin, vec3_t axis[ 3 ], int inwater );
sfxHandle_t( *S_RegisterSound )( const char *sample, qboolean compressed ); // returns buzz if not found
void( *S_StartBackgroundTrack )( const char *intro, const char *loop ); // empty name stops music
void( *S_StopBackgroundTrack )( void );
void( *R_LoadWorldMap )( const char *mapname );
// all media should be registered during level startup to prevent
// hitches during gameplay
qhandle_t( *R_RegisterModel )( const char *name ); // returns rgb axis if not found
qhandle_t( *R_RegisterSkin )( const char *name ); // returns all white if not found
qhandle_t( *R_RegisterShader )( const char *name ); // returns all white if not found
qhandle_t( *R_RegisterShaderNoMip )( const char *name ); // returns all white if not found
// a scene is built up by calls to R_ClearScene and the various R_Add functions.
// Nothing is drawn until R_RenderScene is called.
void( *R_ClearScene )( void );
void( *R_AddRefEntityToScene )( const refEntity_t *re );
// polys are intended for simple wall marks, not really for doing
// significant construction
void( *R_AddPolyToScene )( qhandle_t hShader, int numVerts, const polyVert_t *verts );
void( *R_AddPolysToScene )( qhandle_t hShader, int numVerts, const polyVert_t *verts, int numPolys );
void( *R_AddLightToScene )( const vec3_t org, float intensity, float r, float g, float b );
int( *R_LightForPoint )( vec3_t point, vec3_t ambientLight, vec3_t directedLight, vec3_t lightDir );
void( *R_RenderScene )( const refdef_t *fd );
void( *R_SetColor )( const float *rgba ); // NULL = 1,1,1,1
void( *R_DrawStretchPic )( float x, float y, float w, float h,
float s1, float t1, float s2, float t2, qhandle_t hShader );
void( *R_ModelBounds )( clipHandle_t model, vec3_t mins, vec3_t maxs );
int( *R_LerpTag )( orientation_t *tag, clipHandle_t mod, int startFrame, int endFrame,
float frac, const char *tagName );
void( *R_RemapShader )( const char *oldShader, const char *newShader, const char *timeOffset );
// The glconfig_t will not change during the life of a cgame.
// If it needs to change, the entire cgame will be restarted, because
// all the qhandle_t are then invalid.
void( *GetGlconfig )( glconfig_t *glconfig );
// the gamestate should be grabbed at startup, and whenever a
// configstring changes
void( *GetGameState )( gameState_t *gamestate );
// cgame will poll each frame to see if a newer snapshot has arrived
// that it is interested in. The time is returned seperately so that
// snapshot latency can be calculated.
void( *GetCurrentSnapshotNumber )( int *snapshotNumber, int *serverTime );
// a snapshot get can fail if the snapshot (or the entties it holds) is so
// old that it has fallen out of the client system queue
qboolean( *GetSnapshot )( int snapshotNumber, snapshot_t *snapshot );
// retrieve a text command from the server stream
// the current snapshot will hold the number of the most recent command
// qfalse can be returned if the client system handled the command
// argc )() / argv )() can be used to examine the parameters of the command
qboolean( *GetServerCommand )( int serverCommandNumber );
// returns the most recent command number that can be passed to GetUserCmd
// this will always be at least one higher than the number in the current
// snapshot, and it may be quite a few higher if it is a fast computer on
// a lagged connection
int( *GetCurrentCmdNumber )( void );
qboolean( *GetUserCmd )( int cmdNumber, usercmd_t *ucmd );
// used for the weapon select and zoom
void( *SetUserCmdValue )( int stateValue, float sensitivityScale );
int( *MemoryRemaining )( void );
void( *R_RegisterFont )( const char *fontName, int pointSize, fontInfo_t *font );
qboolean( *Key_IsDown )( int keynum );
int( *Key_GetCatcher )( void );
void( *Key_SetCatcher )( int catcher );
int( *Key_GetKey )( const char *binding );
// ley0k: animation system
const char *( *Anim_NameForNum )( tiki_t *tiki, int animNum );
int( *Anim_NumForName )( tiki_t *tiki, const char *name );
int( *Anim_Random )( tiki_t *tiki, const char *name );
int( *Anim_NumFrames )( tiki_t *tiki, int animNum );
float( *Anim_Time )( tiki_t *tiki, int animNum );
float( *Anim_Frametime )( tiki_t *tiki, int animNum );
int ( *Anim_Delta )( tiki_t *tiki, int animNum, vec3_t delta );
int ( *Anim_Flags )( tiki_t *tiki, int animNum );
float ( *Anim_CrossblendTime )( tiki_t *tiki, int animNum );
qboolean ( *Anim_HasCommands )( tiki_t *tiki, int animNum );
qboolean ( *Frame_Commands )( tiki_t *tiki, int animNum, int frameNum, tiki_cmd_t *tikiCmds );
qboolean( *Frame_CommandsTime )( tiki_t *pmdl, int animNum, float start, float end, tiki_cmd_t *tikiCmd );
// ley0k: TIKI tags
int ( *Tag_NumForName )( tiki_t *tiki, const char * name );
const char *( *Tag_NameForNum )( tiki_t *tiki, int num );
// IneQuation, wombat
int ( *R_Text_Width )( fontInfo_t *font, const char *text, int limit, qboolean useColourCodes );
int ( *R_Text_Height )( fontInfo_t *font, const char *text, int limit, qboolean useColourCodes );
void ( *R_Text_Paint )( fontInfo_t *font, float x, float y, float scale, float alpha, const char *text, float adjust, int limit, qboolean useColourCodes, qboolean is640 );
void ( *R_Text_PaintChar )( fontInfo_t *font, float x, float y, float scale, int c, qboolean is640 );
// su44: MoHAA TIKI model system API
tiki_t* ( *TIKI_RegisterModel )( const char *fname );
bone_t* ( *TIKI_GetBones )( int numBones );
void ( *TIKI_SetChannels )( struct tiki_s *tiki, int animIndex, float animTime, float animWeight, bone_t *bones );
void ( *TIKI_AppendFrameBoundsAndRadius )( struct tiki_s *tiki, int animIndex, float animTime, float *outRadius, vec3_t outBounds[ 2 ] );
void ( *TIKI_Animate )( struct tiki_s *tiki, bone_t *bones );
int ( *TIKI_GetBoneNameIndex )( const char *boneName );
int ( *TIKI_GetAnimIndex )( tiki_t *tiki, const char *animName ); // returns -1 if not found
int ( *TIKI_GetBoneIndex )( tiki_t *tiki, const char *boneName ); // returns -1 if not found
void ( *SetEyeInfo )( vec3_t origin, vec3_t angles );
// su44: these are here only for cg_parsemsg.c
int ( *MSG_ReadBits )( int bits );
int ( *MSG_ReadByte )();
int ( *MSG_ReadShort )();
float ( *MSG_ReadCoord )();
void ( *MSG_ReadDir )( vec3_t dir );
char *( *MSG_ReadString )();
// su44: I need these for cg_beam.c
int ( *R_GetShaderWidth )( qhandle_t shader );
int ( *R_GetShaderHeight )( qhandle_t shader );
int ( *CIN_PlayCinematic )( const char *arg0, int xpos, int ypos, int width, int height, int bits );
e_status ( *CIN_StopCinematic )( int handle );
e_status ( *CIN_RunCinematic )( int handle );
void ( *CIN_DrawCinematic )( int handle );
void ( *CIN_SetExtents )( int handle, int x, int y, int w, int h );
qboolean ( *loadCamera )( const char *name );
void ( *startCamera )( int time );
qboolean ( *getCameraInfo )( int time, vec3_t *origin, vec3_t *angles );
qboolean ( *GetEntityToken )( char *buffer, int bufferSize );
clientAnim_t *anim;
} clientGameImport_t;
#endif
typedef struct clientGameImport_s {
int apiVersion;
void ( *Printf )( const char *fmt, ... );
void ( *DPrintf )( const char *fmt, ... );
void ( *DebugPrintf )( const char *fmt, ... );
void * ( *Malloc )( size_t size );
void ( *Free )( void *ptr );
void ( *Error )( int level, const char *fmt, ... );
int ( *Milliseconds )( );
const char * ( *LV_ConvertString )( const char *string );
cvar_t * ( *Cvar_Get )( const char *varName, const char *varValue, int varFlags );
void ( *Cvar_Set )( const char *varName, const char *varValue );
int ( *Argc )( );
char * ( *Argv )( int arg );
char * ( *Args )( );
void ( *AddCommand )( const char *cmdName );
void ( *Cmd_Stuff )( const char *text );
void ( *Cmd_Execute )( int exec_when, const char *text );
void ( *Cmd_TokenizeString )( const char *textIn );
int ( *FS_ReadFile )( const char *qpath, void **buffer, qboolean quiet );
void ( *FS_FreeFile )( void *buffer );
int ( *FS_WriteFile )( const char *qpath, const void *buffer, int size );
void ( *FS_WriteTextFile )( const char *qpath, const void *buffer, int size );
void ( *SendConsoleCommand )( const char *text );
int ( *MSG_ReadBits )( int bits );
int ( *MSG_ReadChar )( );
int ( *MSG_ReadByte )( );
int ( *MSG_ReadSVC )( );
int ( *MSG_ReadShort )( );
int ( *MSG_ReadLong )( );
float ( *MSG_ReadFloat )( );
char * ( *MSG_ReadString )( );
char * ( *MSG_ReadStringLine )( );
float ( *MSG_ReadAngle8 )( );
float ( *MSG_ReadAngle16 )( );
void ( *MSG_ReadData )( void *data, int len );
float ( *MSG_ReadCoord )( );
void ( *MSG_ReadDir )( vec3_t dir );
void ( *SendClientCommand )( const char *text );
void ( *CM_LoadMap )( const char *name );
clipHandle_t ( *CM_InlineModel )( int index );
int ( *CM_NumInlineModels )( );
int ( *CM_PointContents )( const vec3_t point, clipHandle_t model );
int ( *CM_TransformedPointContents )( const vec3_t point, clipHandle_t model, const vec3_t origin, const vec3_t angles );
void ( *CM_BoxTrace )( trace_t *results, const vec3_t start, const vec3_t end, const vec3_t mins, const vec3_t maxs, int model, int brushMask, int cylinder );
void ( *CM_TransformedBoxTrace )( trace_t *results, const vec3_t start, const vec3_t end, const vec3_t mins, const vec3_t maxs, int model, int brushMask, const vec3_t origin, const vec3_t angles, int cylinder );
clipHandle_t ( *CM_TempBoxModel )( const vec3_t mins, const vec3_t maxs, int contents );
void ( *CM_PrintBSPFileSizes )( );
qboolean ( *CM_LeafInPVS )( int leaf1, int leaf2 );
int ( *CM_PointLeafnum )( const vec3_t p );
int ( *R_MarkFragments )( int numPoints, const vec3_t *points, const vec3_t projection, int maxPoints, vec3_t pointBuffer, int maxFragments, markFragment_t *fragmentBuffer, float fRadiusSquared );
int ( *R_MarkFragmentsForInlineModel )( clipHandle_t bmodel, vec3_t vAngles, vec3_t vOrigin, int numPoints, vec3_t *points, vec3_t projection, int maxPoints, vec3_t pointBuffer, int maxFragments, markFragment_t *fragmentBuffer, float fRadiusSquared );
void ( *R_GetInlineModelBounds )( int index, vec3_t mins, vec3_t maxs );
void ( *R_GetLightingForDecal )( vec3_t light, vec3_t facing, vec3_t origin );
void ( *R_GetLightingForSmoke )( vec3_t light, vec3_t origin );
int ( *R_GatherLightSources )( vec3_t pos, vec3_t *lightPos, vec3_t *lightIntensity, int maxLights );
void ( *S_StartSound )( const vec3_t origin, int entNum, int entChannel, sfxHandle_t sfxHandle, float volume, float minDist, float pitch, float maxDist, int streamed );
void ( *S_StartLocalSound )( const char *sound_name );
void ( *S_StopSound )( int entNum, int channel );
void ( *S_ClearLoopingSounds )( );
void ( *S_AddLoopingSound )( const vec3_t origin, const vec3_t velocity, sfxHandle_t sfxHandle, float volume, float minDist, float maxDist, float pitch, int flags );
void ( *S_Respatialize )( int entityNum, const vec3_t head, vec3_t axis[3] );
void ( *S_BeginRegistration )( );
sfxHandle_t ( *S_RegisterSound )( const char *name, qboolean streamed );
void ( *S_EndRegistration )( );
void ( *S_UpdateEntity )( int entityNum, const vec3_t origin, const vec3_t velocity, qboolean useListener );
void ( *S_SetReverb )( int reverbType, float reverbLevel );
void ( *S_SetGlobalAmbientVolumeLevel )( float volume );
float ( *S_GetSoundTime )( sfxHandle_t handle );
int ( *S_ChannelNameToNum )( const char *name );
const char * ( *S_ChannelNumToName )( int channel );
int ( *S_IsSoundPlaying )( int channelNumber, const char *name );
void ( *MUSIC_NewSoundtrack )( const char *name );
void( *MUSIC_UpdateMood )( int current, int fallback );
void ( *MUSIC_UpdateVolume )( float volume, float fadeTime );
float * ( *get_camera_offset )( qboolean *lookActive, qboolean *resetView );
void ( *R_ClearScene )( );
void ( *R_RenderScene )( const refdef_t *fd );
void ( *R_LoadWorldMap )( const char *name );
void ( *R_PrintBSPFileSizes )( );
int ( *MapVersion )( );
int ( *R_MapVersion )( );
qhandle_t ( *R_RegisterModel )( const char *name );
qhandle_t ( *R_SpawnEffectModel )( const char *name, vec3_t pos, vec3_t axis[3] );
qhandle_t ( *R_RegisterServerModel )( const char *name );
void ( *R_UnregisterServerModel )( qhandle_t hModel );
qhandle_t ( *R_RegisterSkin )( const char *name );
qhandle_t ( *R_RegisterShader )( const char *name );
qhandle_t ( *R_RegisterShaderNoMip )( const char *name );
void ( *R_AddRefEntityToScene )( const refEntity_t *ent, int parentEntityNumber );
void ( *R_AddRefSpriteToScene )( const refEntity_t *ent );
void ( *R_AddLightToScene )( const vec3_t org, float intensity, float r, float g, float b, int type );
qboolean ( *R_AddPolyToScene )( qhandle_t hShader, int numVerts, const polyVert_t *verts, int renderFx );
void ( *R_AddTerrainMarkToScene )( int terrainIndex, qhandle_t hShader, int numVerts, polyVert_t *verts, int renderFx );
void ( *R_SetColor )( const vec4_t rgba );
void ( *R_DrawStretchPic )( float x, float y, float w, float h, float s1, float t1, float s2, float t2, qhandle_t hShader );
fontheader_t * ( *R_LoadFont )( const char *name );
void( *R_DrawString )( fontheader_t *font, const char *text, float x, float y, int maxLen, qboolean virtualScreen );
refEntity_t * ( *R_GetRenderEntity )( int entityNumber );
void ( *R_ModelBounds )( clipHandle_t model, vec3_t mins, vec3_t maxs );
float ( *R_ModelRadius )( qhandle_t handle );
float ( *R_Noise )( float x, float y, float z, float t );
void ( *R_DebugLine )( vec3_t start, vec3_t end, float r, float g, float b, float alpha );
baseshader_t * ( *GetShader )( int shaderNum );
void ( *R_SwipeBegin )( float thistime, float life, qhandle_t shader );
void ( *R_SwipePoint )( vec3_t point1, vec3_t point2, float time );
void ( *R_SwipeEnd )( );
int ( *R_GetShaderWidth )( qhandle_t hShader );
int ( *R_GetShaderHeight )( qhandle_t hShader );
void ( *R_DrawBox )( float x, float y, float w, float h );
void ( *GetGameState )( gameState_t *gameState );
int ( *GetSnapshot )( int snapshotNumber, snapshot_t *snapshot );
int ( *GetServerStartTime )( );
void ( *SetTime )( int time );
void ( *GetCurrentSnapshotNumber )( int *snapshotNumber, int *serverTime );
void ( *GetGlconfig )( glconfig_t *glConfig );
qboolean ( *GetParseEntityState )( int parseEntityNumber, entityState_t *state );
int ( *GetCurrentCmdNumber )( );
qboolean ( *GetUserCmd )( int cmdNumber, usercmd_t *userCmd );
qboolean ( *GetServerCommand )( int serverCommandNumber, qboolean differentServer );
qboolean ( *Alias_Add )( const char *alias, const char *name, const char *parameters );
qboolean( *Alias_ListAdd )( AliasList_t *list, const char *alias, const char *name, const char *parameters );
const char * ( *Alias_FindRandom )( const char *alias, AliasListNode_t **ret );
const char * ( *Alias_ListFindRandom )( AliasList_t *list, const char *alias, AliasListNode_t **ret );
void ( *Alias_Dump )( );
void ( *Alias_Clear )( );
AliasList_t * ( *AliasList_New )( const char *name );
void( *Alias_ListFindRandomRange )( AliasList_t *list, const char *alias, int *minIndex, int *maxIndex, float *totalWeight );
AliasList_t * ( *Alias_GetGlobalList )( );
void ( *UI_ShowMenu )( const char *name, qboolean bForce );
void ( *UI_HideMenu )( const char *name, qboolean bForce );
int ( *UI_FontStringWidth )( fontheader_t *font, const char *string, int maxLen );
int ( *Key_StringToKeynum )( const char *str );
const char * ( *Key_KeynumToBindString )( int keyNum );
void ( *Key_GetKeysForCommand )( const char *command, int *key1, int *key2 );
dtiki_t * ( *R_Model_GetHandle )( qhandle_t handle );
int ( *TIKI_NumAnims )( dtiki_t *pmdl );
void ( *TIKI_CalculateBounds )( dtiki_t *pmdl, float scale, vec3_t mins, vec3_t maxs );
const char * ( *TIKI_Name )( dtiki_t *tiki );
void * ( *TIKI_GetSkeletor )( dtiki_t *tiki, int entNum );
void ( *TIKI_SetEyeTargetPos )( dtiki_t *tiki, int entNum, vec3_t pos );
const char * ( *Anim_NameForNum )( dtiki_t *tiki, int animNum );
int ( *Anim_NumForName )( dtiki_t *tiki, const char *name );
int ( *Anim_Random )( dtiki_t *tiki, const char *name );
int ( *Anim_NumFrames )( dtiki_t *tiki, int animNum );
float ( *Anim_Time )( dtiki_t *tiki, int animNum );
float ( *Anim_Frametime )( dtiki_t *tiki, int animNum );
void ( *Anim_Delta )( dtiki_t *tiki, int animNum, vec3_t delta );
int ( *Anim_Flags )( dtiki_t *tiki, int animNum );
int ( *Anim_FlagsSkel )( dtiki_t *tiki, int animNum );
float ( *Anim_CrossblendTime )( dtiki_t *tiki, int animNum );
qboolean ( *Anim_HasCommands )( dtiki_t *tiki, int animNum );
qboolean ( *Frame_Commands )( dtiki_t *tiki, int animNum, int frameNum, tiki_cmd_t *tikiCmds );
qboolean ( *Frame_CommandsTime )( dtiki_t *pmdl, int animNum, float start, float end, tiki_cmd_t *tikiCmd );
int ( *Surface_NameToNum )( dtiki_t *pmdl, const char *name );
int ( *Tag_NumForName )( dtiki_t *pmdl, const char *name );
const char * ( *Tag_NameForNum )( dtiki_t *pmdl, int animNum );
void ( *ForceUpdatePose )( refEntity_t *model );
orientation_t ( *TIKI_Orientation )( refEntity_t *model, int tagNum );
qboolean ( *TIKI_IsOnGround )( refEntity_t *model, int tagNum, float threshold );
void ( *UI_ShowScoreBoard )( const char *menuName );
void ( *UI_HideScoreBoard )( );
void ( *UI_SetScoreBoardItem )( int itemNumber, const char *data1, const char *data2, const char *data3, const char *data4, const char *data5, const char *data6, const char *data7, const char *data8, vec3_t textColor, vec3_t backColor, qboolean isHeader );
void ( *UI_DeleteScoreBoardItems )( int maxIndex );
void ( *UI_ToggleDMMessageConsole )( int consoleMode );
dtiki_t * ( *TIKI_FindTiki )( const char *path );
void ( *LoadResource )( const char *name );
void ( *FS_CanonicalFilename )( char *name );
cvar_t *fsDebug;
hdelement_t *hudDrawElements;
clientAnim_t *anim;
stopwatch_t *stopWatch;
void *pUnknownVar;
} clientGameImport_t;
#define CGAME_IMPORT_API_VERSION 3
/*
==================================================================
@@ -548,40 +96,329 @@ functions exported to the main executable
==================================================================
*/
typedef struct clientGameExport_s {
void ( *CG_Init )( clientGameImport_t *imported, int serverMessageNum, int serverCommandSequence, int clientNum );
void ( *CG_Shutdown )( void );
void ( *CG_DrawActiveFrame )( int serverTime, int frametime, stereoFrame_t stereoView, qboolean demoPlayback );
qboolean ( *CG_ConsoleCommand )( void );
void ( *CG_GetRendererConfig )( void );
void ( *CG_Draw2D )( void );
void ( *CG_EyePosition )( vec3_t *eyePos );
void ( *CG_EyeOffset )( vec3_t *eyeOffset );
void ( *CG_EyeAngles )( vec3_t *eyeAngles );
float ( *CG_SensitivityScale )( );
void ( *CG_ParseCGMessage )( );
void ( *CG_RefreshHudDrawElements )( );
void ( *CG_HudDrawShader )( int info );
void ( *CG_HudDrawFont )( int info );
int ( *CG_GetParent )( int entNum );
float ( *CG_GetObjectiveAlpha )( );
int ( *CG_PermanentMark )( vec3_t origin, vec3_t dir, float orientation, float sScale, float tScale, float red, float green, float blue, float alpha, qboolean doLighting, float sCenter, float tCenter, markFragment_t *markFragments, void *polyVerts );
int ( *CG_PermanentTreadMarkDecal )( treadMark_t *treadMark, qboolean startSegment, qboolean doLighting, markFragment_t *markFragments, void *polyVerts );
int ( *CG_PermanentUpdateTreadMark )( treadMark_t *treadMark, float alpha, float minSegment, float maxSegment, float maxOffset, float texScale );
void ( *CG_ProcessInitCommands )( dtiki_t *tiki, refEntity_t *ent );
void ( *CG_EndTiki )( dtiki_t *tiki );
char *( *CG_GetColumnName )( int columnNum, int *columnWidth );
void ( *CG_GetScoreBoardColor )( float *red, float *green, float *blue, float *alpha );
void ( *CG_GetScoreBoardFontColor )( float *red, float *green, float *blue, float *alpha );
int ( *CG_GetScoreBoardDrawHeader )( );
void ( *CG_GetScoreBoardPosition )( float *x, float *y, float *width, float *height );
int ( *CG_WeaponCommandButtonBits )( );
int ( *CG_CheckCaptureKey )( int key, qboolean down, unsigned int time );
typedef struct
{
int apiversion;
//============== general services ==================
qboolean ( *CG_Command_ProcessFile )( char *name, qboolean quiet, dtiki_t *curTiki );
// print message on the local console
void (*Printf)( const char *fmt, ...);
void (*DPrintf)( const char *fmt, ...);
void (*DebugPrintf)( const char *fmt, ...);
// managed memory allocation
void *(*Malloc)( int size );
void (*Free)( void *block );
// abort the game
void (*Error)( int errorLevel, const char *fmt, ...);
// milliseconds should only be used for profiling, never
// for anything game related. Get time from CG_ReadyToBuildScene.
int (*Milliseconds)( void );
// localization
const char* (*LV_ConvertString)(const char* string);
// console variable interaction
cvar_t * (*Cvar_Get)( const char *var_name, const char *value, int flags );
void (*Cvar_Set)( const char *var_name, const char *value );
// ClientCommand and ConsoleCommand parameter access
int (*Argc)( void );
char * (*Argv)( int n );
char * (*Args)( void ); // concatenation of all argv >= 1
void (*AddCommand)( const char *cmd );
void (*Cmd_Stuff)(const char* text);
void (*Cmd_Execute)(cbufExec_t execWhen, const char* text);
void (*Cmd_TokenizeString)(const char* textIn);
// a -1 return means the file does not exist
// NULL can be passed for buf to just determine existance
int (*FS_ReadFile)( const char *name, void **buf, qboolean quiet );
void (*FS_FreeFile)( void *buf );
int (*FS_WriteFile)( const char *qpath, const void *buffer, int size );
void (*FS_WriteTextFile)( const char *qpath, const void *buffer, int size );
// add commands to the local console as if they were typed in
// for map changing, etc. The command is not executed immediately,
// but will be executed in order the next time console commands
// are processed
void (*SendConsoleCommand)( const char *text );
// =========== client specific functions ===============
// send a string to the server over the network
int (*MSG_ReadBits)(int bits);
int (*MSG_ReadChar)();
int (*MSG_ReadByte)();
int (*MSG_ReadSVC)();
int (*MSG_ReadShort)();
int (*MSG_ReadLong)();
float (*MSG_ReadFloat)();
char* (*MSG_ReadString)();
char* (*MSG_ReadStringLine)();
float (*MSG_ReadAngle8)();
float (*MSG_ReadAngle16)();
void (*MSG_ReadData)(void* data, int len);
float (*MSG_ReadCoord)();
void (*MSG_ReadDir)(vec3_t dir);
void (*SendClientCommand)( const char *s );
// CM functions
void (*CM_LoadMap)( const char *name );
clipHandle_t (*CM_InlineModel)( int index ); // 0 = world, 1+ = bmodels
int (*CM_NumInlineModels)( void );
int (*CM_PointContents)( const vec3_t p, int headnode );
int (*CM_TransformedPointContents)(const vec3_t p, clipHandle_t model, const vec3_t origin, const vec3_t angles);
void (*CM_BoxTrace)( trace_t *results, const vec3_t start, const vec3_t end,
const vec3_t mins, const vec3_t maxs,
int headnode, int brushmask, qboolean cylinder );
void (*CM_TransformedBoxTrace)( trace_t *results, const vec3_t start, const vec3_t end,
const vec3_t mins, const vec3_t maxs,
int headnode, int brushmask,
const vec3_t origin, const vec3_t angles,
qboolean cylinder
);
clipHandle_t (*CM_TempBoxModel)( const vec3_t mins, const vec3_t maxs, int contents );
void (*CM_PrintBSPFileSizes)();
qboolean (*CM_LeafInPVS)(int leaf1, int leaf2);
int (*CM_PointLeafnum)(const vec3_t p);
int (*R_MarkFragments)( int numPoints, const vec3_t *points, const vec3_t projection,
int maxPoints, vec3_t pointBuffer,
int maxFragments, markFragment_t *fragmentBuffer, float fRadiusSquared );
int (*R_MarkFragmentsForInlineModel)(clipHandle_t bmodel, const vec3_t vAngles, const vec3_t vOrigin,
int numPoints, const vec3_t *points, const vec3_t projection,
int maxPoints, vec3_t pointBuffer,
int maxFragments, markFragment_t *fragmentBuffer, float fRadiusSquared );
void (*R_GetInlineModelBounds)(int index, vec3_t mins, vec3_t maxs);
void (*R_GetLightingForDecal)(vec3_t light, vec3_t facing, vec3_t origin);
void (*R_GetLightingForSmoke)(vec3_t light, vec3_t origin);
int (*R_GatherLightSources)(const vec3_t pos, vec3_t* lightPos, vec3_t* lightIntensity, int maxLights);
// =========== sound function calls ===============
void (*S_StartSound)(const vec3_t origin, int entNum, int entChannel, sfxHandle_t sfxHandle, float volume, float minDist, float pitch, float maxDist, int streamed);
void (*S_StartLocalSound)(const char* soundName, qboolean forceLoad);
void (*S_StopSound)( int entnum, int channel );
void (*S_ClearLoopingSounds)(void);
void (*S_AddLoopingSound)(const vec3_t origin, const vec3_t velocity, sfxHandle_t sfxHandle, float volume, float minDist, float maxDist, float pitch, int flags);
void (*S_Respatialize)( int entityNum, const vec3_t origin, vec3_t axis[3] );
void (*S_BeginRegistration)( void );
sfxHandle_t (*S_RegisterSound)( const char *sample, int streamed );
void (*S_EndRegistration)( void );
void (*S_UpdateEntity)( int entityNum, const vec3_t origin, const vec3_t velocity, qboolean use_listener );
void (*S_SetReverb)( int reverb_type, float reverb_level );
void (*S_SetGlobalAmbientVolumeLevel)( float volume );
float (*S_GetSoundTime)(sfxHandle_t handle);
int (*S_ChannelNameToNum)(const char* name);
const char* (*S_ChannelNumToName)(int channel);
int (*S_IsSoundPlaying)(int channelNumber, const char* name);
// =========== music function calls ===============
void (*MUSIC_NewSoundtrack)( const char *name );
void (*MUSIC_UpdateMood)( int current_mood, int fallback_mood );
void (*MUSIC_UpdateVolume)( float volume, float fade_time );
// =========== camera function calls ===============
float * (*get_camera_offset)( qboolean *lookactive, qboolean *resetview );
// =========== renderer function calls ================
void (*R_ClearScene)( void );
void (*R_RenderScene)( const refdef_t *fd );
void (*R_LoadWorldMap)(const char* mapname);
void (*R_PrintBSPFileSizes)();
int (*MapVersion)();
int (*R_MapVersion)();
qhandle_t (*R_RegisterModel)( const char *name );
qhandle_t (*R_SpawnEffectModel)(const char* name, vec3_t pos, vec3_t axis[3]);
qhandle_t (*R_RegisterServerModel)(const char* name);
void (*R_UnregisterServerModel)(qhandle_t hModel);
qhandle_t (*R_RegisterSkin)( const char *name );
qhandle_t (*R_RegisterShader)( const char *name );
qhandle_t (*R_RegisterShaderNoMip)( const char *name );
void (*R_AddRefEntityToScene)(const refEntity_t *ent, int parentEntityNumber );
void (*R_AddRefSpriteToScene)(const refEntity_t *ent );
void (*R_AddLightToScene)(const vec3_t origin, float intensity, float r, float g, float b, int type );
qboolean (*R_AddPolyToScene)(qhandle_t hShader, int numVerts, const polyVert_t* verts, int renderfx);
void (*R_AddTerrainMarkToScene)(int terrainIndex, qhandle_t hShader, int numVerts, const polyVert_t* verts, int renderFx);
void (*R_SetColor)( const vec4_t rgba ); // NULL = 1,1,1,1
void (*R_DrawStretchPic) ( float x, float y, float w, float h,
float s1, float t1, float s2, float t2,
qhandle_t hShader ); // 0 = white
fontheader_t* (*R_LoadFont)(const char* name);
void (*R_DrawString)(fontheader_t* font, const char* text, float x, float y, int maxLen, qboolean virtualScreen);
refEntity_t * (*R_GetRenderEntity)( int entityNumber );
void (*R_ModelBounds)( clipHandle_t model, vec3_t mins, vec3_t maxs );
float (*R_ModelRadius)( clipHandle_t model );
float (*R_Noise)( float x, float y, float z, float t );
void (*R_DebugLine)(const vec3_t start, const vec3_t end, float r, float g, float b, float alpha);
baseshader_t* (*GetShader)(int shaderNum);
// =========== Swipes =============
void (*R_SwipeBegin) ( float thistime, float life, qhandle_t shader );
void (*R_SwipePoint) ( vec3_t p1, vec3_t p2, float time );
void (*R_SwipeEnd) ( void );
int (*R_GetShaderWidth)( qhandle_t shader );
int (*R_GetShaderHeight)( qhandle_t shader );
void (*R_DrawBox)( float x, float y, float w, float h );
// =========== data shared with the client =============
void (*GetGameState)( gameState_t *gamestate );
int (*GetSnapshot)( int snapshotNumber, snapshot_t *snapshot );
int (*GetServerStartTime)();
void (*SetTime)(int time);
void (*GetCurrentSnapshotNumber)( int *snapshotNumber, int *serverTime );
void (*GetGlconfig)( glconfig_t *glconfig );
// will return false if the number is so old that it doesn't exist in the buffer anymore
qboolean (*GetParseEntityState)( int parseEntityNumber, entityState_t *state );
int (*GetCurrentCmdNumber)( void ); // returns the most recent command number
// which is the local predicted command for
// the following frame
qboolean (*GetUserCmd)( int cmdNumber, usercmd_t *ucmd );
qboolean (*GetServerCommand)(int serverCommandNumber, qboolean differentServer);
// ALIAS STUFF
qboolean (*Alias_Add)( const char * alias, const char * name, const char *parameters );
qboolean (*Alias_ListAdd)(AliasList_t* list, const char* alias, const char* name, const char* parameters);
const char* (*Alias_FindRandom)(const char* alias, AliasListNode_t **ret);
const char* (*Alias_ListFindRandom)(AliasList_t* list, const char* alias, AliasListNode_t** ret);
void (*Alias_Dump)( void );
void (*Alias_Clear)( void );
AliasList_t* (*AliasList_New)(const char* name);
void (*Alias_ListFindRandomRange)(AliasList_t* list, const char* alias, int* minIndex, int* maxIndex, float* totalWeight);
AliasList_t* (*Alias_GetGlobalList)();
// ==================== UI STUFF ==========================
void (*UI_ShowMenu)(const char* name, qboolean bForce);
void (*UI_HideMenu)(const char* name, qboolean bForce);
int (*UI_FontStringWidth)(fontheader_t* font, const char* string, int maxLen);
int (*Key_StringToKeynum)(const char* str);
const char* (*Key_KeynumToBindString)(int keyNum);
void (*Key_GetKeysForCommand)(const char* command, int* key1, int* key2);
// ==================== TIKI STUFF ==========================
// TIKI SPECIFIC STUFF
dtiki_t* (*R_Model_GetHandle)(qhandle_t handle);
int (*TIKI_NumAnims)(dtiki_t* pmdl);
void (*TIKI_CalculateBounds)(dtiki_t* pmdl, float scale, vec3_t mins, vec3_t maxs);
const char* (*TIKI_Name)(dtiki_t* tiki);
void* (*TIKI_GetSkeletor)(dtiki_t* tiki, int entNum);
void (*TIKI_SetEyeTargetPos)(dtiki_t* tiki, int entNum, vec3_t pos);
// ANIM SPECIFIC STUFF
const char * (*Anim_NameForNum) (dtiki_t* tiki, int animnum );
int (*Anim_NumForName) (dtiki_t* tiki, const char * name );
int (*Anim_Random) (dtiki_t* tiki, const char * name );
int (*Anim_NumFrames) (dtiki_t* tiki, int animnum );
float (*Anim_Time) (dtiki_t* tiki, int animnum);
float (*Anim_Frametime) (dtiki_t* tiki, int animnum);
void (*Anim_Delta) (dtiki_t* tiki, int animnum, vec3_t delta );
int (*Anim_Flags) (dtiki_t* tiki, int animnum);
int (*Anim_FlagsSkel) (dtiki_t* tiki, int animnum);
float (*Anim_CrossblendTime) (dtiki_t* tiki, int animnum );
qboolean (*Anim_HasCommands) (dtiki_t* tiki, int animnum );
// FRAME SPECIFIC STUFF
qboolean (*Frame_Commands) (dtiki_t* tiki, int animnum, int framenum, tiki_cmd_t * tiki_cmd );
qboolean (*Frame_CommandsTime) (dtiki_t* tiki, int animnum, float start, float end, tiki_cmd_t * tiki_cmd );
// SURFACE SPECIFIC STUFF
int (*Surface_NameToNum) (dtiki_t* tiki, const char * name );
//const char * (*Surface_NumToName) (dtiki_t* tiki, int num );
//int (*Surface_Flags) (dtiki_t* tiki, int num );
//int (*Surface_NumSkins) (dtiki_t* tiki, int num );
// TAG SPECIFIC STUFF
int (*Tag_NumForName) (dtiki_t* tiki, const char * name );
const char * (*Tag_NameForNum) (dtiki_t* tiki, int num );
void (*ForceUpdatePose)(refEntity_t* model);
orientation_t (*TIKI_Orientation)(refEntity_t* model, int tagNum);
qboolean (*TIKI_IsOnGround)(refEntity_t* model, int tagNum, float threshold);
// MISCELLANEOUS SPECIFIC STUFF
void (*UI_ShowScoreBoard)(const char* menuName);
void (*UI_HideScoreBoard)();
void (*UI_SetScoreBoardItem)(int itemNumber, const char* data1,
const char* data2, const char* data3,
const char* data4, const char* data5,
const char* data6, const char* data7,
const char* data8, const vec4_t textColor,
const vec4_t backColor, qboolean isHeader);
void (*UI_DeleteScoreBoardItems)(int maxIndex);
void (*UI_ToggleDMMessageConsole)(int consoleMode);
dtiki_t* (*TIKI_FindTiki)(const char* path);
void (*LoadResource)(const char* name);
void (*FS_CanonicalFilename)(char* name);
cvar_t* fsDebug;
hdelement_t* HudDrawElements;
clientAnim_t* anim;
stopWatch_t* stopWatch;
} clientGameImport_t;
/*
==================================================================
functions exported to the main executable
==================================================================
*/
typedef struct {
void (*CG_Init)( clientGameImport_t *imported, int serverMessageNum, int serverCommandSequence, int clientNum );
void (*CG_Shutdown)( void );
void (*CG_DrawActiveFrame)( int serverTime, int frameTime, stereoFrame_t stereoView, qboolean demoPlayback );
qboolean (*CG_ConsoleCommand)( void );
void (*CG_GetRendererConfig)( void );
void (*CG_Draw2D)( void );
void (*CG_EyePosition)(vec3_t* eyePos);
void (*CG_EyeOffset)(vec3_t* eyeOffset);
void (*CG_EyeAngles)(vec3_t* eyeAngles);
float (*CG_SensitivityScale)();
void (*CG_ParseCGMessage)();
void (*CG_RefreshHudDrawElements)();
void (*CG_HudDrawShader)(int info);
void (*CG_HudDrawFont)(int info);
int (*CG_GetParent)(int entNum);
float (*CG_GetObjectiveAlpha)();
int (*CG_PermanentMark)(const vec3_t origin, const vec3_t dir, float orientation, float sScale, float tScale, float red, float green, float blue, float alpha, qboolean doLighting, float sCenter, float tCenter, markFragment_t* markFragments, void* polyVerts);
int (*CG_PermanentTreadMarkDecal)(treadMark_t* treadMark, qboolean startSegment, qboolean doLighting, markFragment_t* markFragments, void* polyVerts);
int (*CG_PermanentUpdateTreadMark)(treadMark_t* treadMark, float alpha, float minSegment, float maxSegment, float maxOffset, float texScale);
void (*CG_ProcessInitCommands)(dtiki_t* tiki, refEntity_t* ent);
void (*CG_EndTiki)(dtiki_t* tiki);
const char* (*CG_GetColumnName)(int columnNum, int* columnWidth);
void (*CG_GetScoreBoardColor)(float* red, float* green, float* blue, float* alpha);
void (*CG_GetScoreBoardFontColor)(float* red, float* green, float* blue, float* alpha);
int (*CG_GetScoreBoardDrawHeader)();
void (*CG_GetScoreBoardPosition)(float* x, float* y, float* width, float* height);
int (*CG_WeaponCommandButtonBits)();
int (*CG_CheckCaptureKey)(int key, qboolean down, unsigned int time);
// FIXME
//prof_cgame_t* profStruct;
qboolean (*CG_Command_ProcessFile)(char* name, qboolean quiet, dtiki_t* curTiki);
} clientGameExport_t;
//----------------------------------------------
#ifdef CGAME_DLL
#ifdef WIN32
__declspec(dllexport)
#else
__attribute__((visibility("default")))
#endif
#endif
clientGameExport_t* GetCGameAPI(void);
#ifdef __cplusplus
}
#endif
#endif // __CG_PUBLIC_H__
-175
View File
@@ -1,175 +0,0 @@
/*
===========================================================================
Copyright (C) 2011 su44
This file is part of OpenMoHAA source code.
OpenMoHAA source code is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the License,
or (at your option) any later version.
OpenMoHAA source code is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with OpenMoHAA source code; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
// cg_rain.c - MoHAA rain/snow effects
#include "cg_local.h"
void CG_InitRainEffect() {
cg.rain.density = 0;
cg.rain.speed = 2048.0;
cg.rain.length = 90.0;
cg.rain.min_dist = 512.0;
cg.rain.width = 1.f;
cg.rain.speed_vary = 512;
cg.rain.slant = 50;
memset(cg.rain.shader,0,sizeof(cg.rain.shader));
strcpy(cg.rain.shader[0],"textures/hud/allies"); // only for debuging
cg.rain.numshaders = 0;
}
void CG_RainCSUpdated(int num, const char *str) {
if( num == CS_RAIN_DENSITY ) {
cg.rain.density = atof(str);
} else if( num == CS_RAIN_SPEED ) {
cg.rain.speed = atof(str);
} else if( num == CS_RAIN_SPEEDVARY ) {
cg.rain.speed_vary = atof(str);
} else if( num == CS_RAIN_SLANT ) {
cg.rain.slant = atof(str);
} else if( num == CS_RAIN_LENGTH ) {
cg.rain.length = atof(str);
} else if( num == CS_RAIN_MINDIST ) {
cg.rain.min_dist = atof(str);
} else if( num == CS_RAIN_WIDTH ) {
cg.rain.width = atof(str);
} else if( num == CS_RAIN_SHADER ) {
if(cg.rain.numshaders) {
int i;
for(i = 0; i < cg.rain.numshaders; i++) {
sprintf(cg.rain.shader[i],"%s%i",str,i);
}
}
} else if( num == CS_RAIN_NUMSHADERS ) {
cg.rain.numshaders = atoi(str);
} else {
CG_Error("CG_RainCSUpdated: unknown cs index\n");
}
}
void CG_Rain(centity_t *cent) {
char *shadername;
vec3_t vEnd;
vec3_t vStart;
//vec4_t fcolor;
byte fcolor[4]; // su44: in MoHAA that's a float[4]
vec3_t maxs;
vec3_t mins;
float f;
vec3_t tMins,tMaxs;
vec3_t size;
int i;
int density;
int r;
fcolor[0] = 1.f;
fcolor[1] = 1.f;
fcolor[2] = 1.f;
fcolor[3] = 1.f;
//if ( !cg_rain.integer )
// return;
cgi.R_ModelBounds(cgs.gameModels[cent->currentState.modelindex],mins,maxs);
tMins[0] = mins[0] + cent->lerpOrigin[0];
f = cg.snap->ps.origin[0] - cg.rain.min_dist;
if ( f > tMins[0] )
tMins[0] = f;
tMins[1] = mins[1] + cent->lerpOrigin[1];
f = cg.snap->ps.origin[1] - cg.rain.min_dist;
if ( f > tMins[1] )
tMins[1] = f;
tMins[2] = mins[2] + cent->lerpOrigin[2];
tMaxs[0] = maxs[0] + cent->lerpOrigin[0];
f = cg.snap->ps.origin[0] + cg.rain.min_dist;
if ( f > tMaxs[0] )
tMaxs[0] = f;
tMaxs[1] = maxs[1] + cent->lerpOrigin[1];
f = cg.snap->ps.origin[1] + cg.rain.min_dist;
if( f > tMaxs[1] )
tMaxs[1] = f;
tMaxs[2] = maxs[2] + cent->lerpOrigin[2];
if ( tMins[0] >= tMaxs[0] )
return;
if (tMins[1] >= tMaxs[1] )
return;
size[0] = tMaxs[0] - tMins[0];
size[1] = tMaxs[1] - tMins[1];
size[2] = tMaxs[2] - tMins[2];
density = (signed int)(cg.rain.density / 200.0 * sqrt(size[1] * size[0]));
if ( density > 4096 )
density = 4096;
r = rand();
if ( cg.rain.numshaders ) {
shadername = &cg.rain.shader[r % cg.rain.numshaders][0];
} else {
shadername = &cg.rain.shader[0][0];
}
for(i = 0; i < density; i++) {
int iLife;
iLife = (signed int)(size[2] / ((long double)(r % cg.rain.speed_vary) + cg.rain.speed) * 1000.0);
f = (long double)(r % (signed int)(size[0] + 1.0));
r = ((214013 * r + 2531011) >> 16) & 0x7FFF;
vStart[2] = tMaxs[2];
vStart[0] = f + tMins[0];
vStart[1] = (long double)(r % (signed int)(size[1] + 1.0)) + tMins[1];
//if( )
{
f = r % cg.rain.slant;
r = ((214013 * r + 2531011) >> 16) & 0x7FFF;
vEnd[0] = f + vStart[0] + /*vss_wind_x->value*/8;
vEnd[1] = (r % cg.rain.slant) + vStart[1] + /*vss_wind_y->value*/4;
vEnd[2] = tMins[2];
CG_CreateBeam(
vStart, // start
vec3_origin,// dir
0, // owner
1, // model
1.0, // alpha
cg.rain.width, // scale
16384, // flags
0, // length <- isnt smth wrong there?
iLife, // life
1, // create
vEnd, // endpointvec
0, // min_offset
0, // max_offset
0, // overlap
1, // numSubdivisions
0, // delay
shadername, // beamshadername
fcolor, // modulate (byte[4] here, float[4] in MoHAA)
0, // numspherebeams
0.0, // sphereradius
cg.rain.length, // toggledelay
1.0, // endalpha
0, // renderfx
"raineffect"); // name
}
}
}
+367
View File
@@ -0,0 +1,367 @@
/*
===========================================================================
Copyright (C) 2023 the OpenMoHAA team
This file is part of OpenMoHAA source code.
OpenMoHAA source code is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the License,
or (at your option) any later version.
OpenMoHAA source code is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with OpenMoHAA source code; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
// DESCRIPTION:
// Scoreboard
#include "cg_local.h"
void CG_GetScoreBoardColor(float* fR, float* fG, float* fB, float* fA)
{
*fR = 0.0f;
*fG = 0.0f;
*fB = 0.0f;
*fA = 0.7f;
}
void CG_GetScoreBoardFontColor(float* fR, float* fG, float* fB, float* fA)
{
*fR = 1.0f;
*fG = 1.0f;
*fB = 1.0f;
*fA = 1.0f;
}
void CG_GetScoreBoardPosition(float* fX, float* fY, float* fW, float* fH)
{
*fX = 32.0;
*fY = 56.0;
*fW = 384.0;
*fH = 392.0;
}
int CG_GetScoreBoardDrawHeader()
{
return 0;
}
const char* CG_GetColumnName(int iColumnNum, int* iColumnWidth)
{
int iReturnWidth;
const char* pszReturnString;
switch (iColumnNum) {
case 0:
iReturnWidth = 128;
pszReturnString = "Name";
break;
case 1:
iReturnWidth = 64;
pszReturnString = "Kills";
break;
case 2:
iReturnWidth = 64;
pszReturnString = "Deaths";
if (cgs.gametype > GT_TEAM) {
pszReturnString = "Total";
}
break;
case 3:
iReturnWidth = 64;
pszReturnString = "Time";
break;
case 4:
iReturnWidth = 64;
pszReturnString = "Ping";
break;
default:
iReturnWidth = 0;
pszReturnString = 0;
break;
}
if (iColumnWidth) {
*iColumnWidth = iReturnWidth;
}
return pszReturnString;
}
void CG_PrepScoreBoardInfo()
{
switch (cgs.gametype) {
case GT_OBJECTIVE:
strcpy(cg.scoresMenuName, "Obj_Scoreboard");
break;
case GT_TEAM_ROUNDS:
strcpy(cg.scoresMenuName, "DM_Round_Scoreboard");
break;
default:
strcpy(cg.scoresMenuName, "DM_Scoreboard");
break;
}
}
void CG_ParseScores()
{
int i;
int iEntryCount;
int iClientTeam, iClientNum;
int iDatumCount;
int iMatchTeam;
qboolean bIsDead, bIsHeader;
char szString2[MAX_STRING_TOKENS];
char szString3[MAX_STRING_TOKENS];
char szString4[MAX_STRING_TOKENS];
char szString5[MAX_STRING_TOKENS];
char szString6[MAX_STRING_TOKENS];
const char* pszClientInfo;
float vSameTeamTextColor[4];
float vSameTeamBackColor[4];
float vOtherTeamTextColor[4];
float vOtherTeamBackColor[4];
float vNoTeamTextColor[4];
float vNoTeamBackColor[4];
float vThisClientTextColor[4];
float vThisClientBackColor[4];
float vDeadTextColorDead[4];
float* pItemTextColor;
float* pItemBackColor;
iMatchTeam = -1;
vSameTeamTextColor[0] = 1.0f;
vSameTeamTextColor[1] = 1.0f;
vSameTeamTextColor[2] = 1.0f;
vSameTeamTextColor[3] = 1.0f;
vSameTeamBackColor[0] = 0.1f;
vSameTeamBackColor[1] = 0.5f;
vSameTeamBackColor[2] = 0.1f;
vSameTeamBackColor[3] = 0.4f;
vOtherTeamTextColor[0] = 1.0f;
vOtherTeamTextColor[1] = 1.0f;
vOtherTeamTextColor[2] = 1.0f;
vOtherTeamTextColor[3] = 1.0f;
vOtherTeamBackColor[0] = 0.5f;
vOtherTeamBackColor[1] = 0.1f;
vOtherTeamBackColor[2] = 0.1f;
vOtherTeamBackColor[3] = 0.4f;
vNoTeamTextColor[0] = 1.0f;
vNoTeamTextColor[1] = 1.0f;
vNoTeamTextColor[2] = 1.0f;
vNoTeamTextColor[3] = 1.0f;
vNoTeamBackColor[0] = 0.1f;
vNoTeamBackColor[1] = 0.1f;
vNoTeamBackColor[2] = 0.1f;
vNoTeamBackColor[3] = 0.4f;
vDeadTextColorDead[0] = 1.0f;
vDeadTextColorDead[1] = 0.1f;
vDeadTextColorDead[2] = 0.1f;
vDeadTextColorDead[3] = 1.0f;
vThisClientTextColor[0] = 0.0f;
vThisClientTextColor[1] = 0.0f;
vThisClientTextColor[2] = 0.0f;
vThisClientTextColor[3] = 1.0f;
if (cgs.gametype > GT_FFA)
{
vThisClientBackColor[0] = 0.5f;
vThisClientBackColor[1] = 0.75f;
vThisClientBackColor[2] = 0.5f;
}
else
{
vThisClientBackColor[0] = 0.75f;
vThisClientBackColor[1] = 0.75f;
vThisClientBackColor[2] = 0.75f;
}
vThisClientBackColor[3] = 0.8f;
if (cgs.gametype > GT_FFA)
{
iDatumCount = 6;
iMatchTeam = cg.snap->ps.stats[STAT_TEAM];
if (iMatchTeam != TEAM_ALLIES && iMatchTeam != TEAM_AXIS)
{
iMatchTeam = TEAM_ALLIES;
vThisClientTextColor[0] = 0.0f;
vThisClientTextColor[1] = 0.0f;
vThisClientTextColor[2] = 0.0f;
vThisClientBackColor[0] = 0.75f;
vThisClientBackColor[1] = 0.75f;
vThisClientBackColor[2] = 0.75f;
}
}
else
{
// free-for-all
iDatumCount = 5;
}
iEntryCount = atoi(cgi.Argv(1));
if (iEntryCount > MAX_CLIENTS) {
iEntryCount = MAX_CLIENTS;
}
for (i = 0; i < iEntryCount; ++i)
{
bIsHeader = qfalse;
if (cgs.gametype > GT_FFA)
{
iClientNum = atoi(cgi.Argv(2 + iDatumCount * i));
iClientTeam = atoi(cgi.Argv(3 + iDatumCount * i));
if (iClientTeam >= 0) {
bIsDead = qfalse;
}
else {
bIsDead = qtrue;
iClientTeam = -iClientTeam;
}
if (iClientNum == -1)
{
bIsHeader = qtrue;
switch (iClientTeam)
{
case 1:
strcpy(szString2, "Spectators");
break;
case 2:
strcpy(szString2, "Free-For-Allers");
break;
case 3:
strcpy(szString2, "Allies");
break;
case 4:
strcpy(szString2, "Axis");
break;
default:
strcpy(szString2, "No Team");
break;
}
}
else if (iClientNum == -2)
{
// spectating
szString2[0] = 0;
}
else
{
pszClientInfo = CG_ConfigString(CS_PLAYERS + iClientNum);
strcpy(szString2, Info_ValueForKey(pszClientInfo, "name"));
}
strcpy(szString3, cgi.Argv(4 + iDatumCount * i));
strcpy(szString4, cgi.Argv(5 + iDatumCount * i));
strcpy(szString5, cgi.Argv(6 + iDatumCount * i));
strcpy(szString6, cgi.Argv(7 + iDatumCount * i));
if (iClientNum == cg.snap->ps.clientNum)
{
pItemTextColor = vThisClientTextColor;
pItemBackColor = vThisClientBackColor;
}
else if (iClientNum == -2)
{
pItemTextColor = vNoTeamTextColor;
pItemBackColor = vNoTeamBackColor;
}
else if (iClientTeam == TEAM_ALLIES || iClientTeam == TEAM_AXIS)
{
if (iClientTeam == iMatchTeam)
{
pItemTextColor = vSameTeamTextColor;
pItemBackColor = vSameTeamBackColor;
}
else
{
pItemTextColor = vOtherTeamTextColor;
pItemBackColor = vOtherTeamBackColor;
}
}
else
{
pItemTextColor = vNoTeamTextColor;
pItemBackColor = vNoTeamBackColor;
}
if (bIsDead) {
pItemTextColor = vDeadTextColorDead;
}
}
else
{
iClientNum = atoi(cgi.Argv(2 + iDatumCount * i));
if (iClientNum >= 0)
{
pszClientInfo = CG_ConfigString(CS_PLAYERS + iClientNum);
strcpy(szString2, Info_ValueForKey(pszClientInfo, "name"));
strcpy(szString3, cgi.Argv(3 + iDatumCount * i));
strcpy(szString4, cgi.Argv(4 + iDatumCount * i));
strcpy(szString5, cgi.Argv(5 + iDatumCount * i));
strcpy(szString6, cgi.Argv(6 + iDatumCount * i));
}
else
{
if (iClientNum == -3)
{
strcpy(szString2, "Players");
bIsHeader = qtrue;
}
else if (iClientNum == -2)
{
strcpy(szString2, "Spectators");
bIsHeader = qtrue;
}
else
{
// unknown
szString2[0] = 0;
}
szString3[0] = 0;
szString4[0] = 0;
szString5[0] = 0;
szString6[0] = 0;
}
if (iClientNum == cg.snap->ps.clientNum)
{
pItemTextColor = vThisClientTextColor;
pItemBackColor = vThisClientBackColor;
}
else
{
pItemTextColor = vNoTeamTextColor;
pItemBackColor = vNoTeamBackColor;
}
}
cgi.UI_SetScoreBoardItem(
i,
szString2,
szString3,
szString4,
szString5,
szString6,
NULL,
NULL,
NULL,
pItemTextColor,
pItemBackColor,
bIsHeader
);
}
cgi.UI_DeleteScoreBoardItems(iEntryCount);
}
+161 -451
View File
@@ -1,28 +1,27 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
Copyright (C) 2023 the OpenMoHAA team
This file is part of Quake III Arena source code.
This file is part of OpenMoHAA source code.
Quake III Arena source code is free software; you can redistribute it
OpenMoHAA source code is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the License,
or (at your option) any later version.
Quake III Arena source code is distributed in the hope that it will be
OpenMoHAA source code is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Quake III Arena source code; if not, write to the Free Software
along with OpenMoHAA source code; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
//
// cg_servercmds.c -- reliably sequenced text commands sent by the server
// these are processed at snapshot transition time, so there will definately
// be a valid snapshot this frame
// DESCRIPTION:
// cg_servercmds.c -- text commands sent by the server
#include "cg_local.h"
@@ -34,60 +33,66 @@ This is called explicitly when the gamestate is first received,
and whenever the server updates any serverinfo flagged cvars
================
*/
void CG_ParseServerinfo( void ) {
const char *info;
char *mapname;
void CG_ParseServerinfo(void)
{
const char* info;
const char* mapname;
char map[MAX_QPATH];
char* spawnpos;
info = CG_ConfigString( CS_SERVERINFO );
cgs.gametype = atoi( Info_ValueForKey( info, "g_gametype" ) );
cgi.Cvar_Set("g_gametype", va("%i", cgs.gametype));
cgs.dmflags = atoi( Info_ValueForKey( info, "dmflags" ) );
cgs.teamflags = atoi( Info_ValueForKey( info, "teamflags" ) );
cgs.fraglimit = atoi( Info_ValueForKey( info, "fraglimit" ) );
cgs.capturelimit = atoi( Info_ValueForKey( info, "capturelimit" ) );
cgs.timelimit = atoi( Info_ValueForKey( info, "timelimit" ) );
cgs.maxclients = atoi( Info_ValueForKey( info, "sv_maxclients" ) );
mapname = Info_ValueForKey( info, "mapname" );
Com_sprintf( cgs.mapname, sizeof( cgs.mapname ), "maps/%s.bsp", mapname );
cgi.Cvar_Set( "cg_scoreboardpic", Info_ValueForKey( info,"g_scoreboardpic" ) );
}
info = CG_ConfigString(CS_SERVERINFO);
cgs.gametype = atoi(Info_ValueForKey(info, "g_gametype"));
cgs.dmflags = atoi(Info_ValueForKey(info, "dmflags"));
cgs.teamflags = atoi(Info_ValueForKey(info, "teamflags"));
cgs.fraglimit = atoi(Info_ValueForKey(info, "fraglimit"));
cgs.timelimit = atoi(Info_ValueForKey(info, "timelimit"));
cgs.maxclients = atoi(Info_ValueForKey(info, "sv_maxclients"));
/*
==================
CG_ParseWarmup
==================
*/
static void CG_ParseWarmup( void ) {
const char *info;
int warmup;
cgi.Cvar_Set("cg_gametype", Info_ValueForKey(info, "g_gametype"));
cgi.Cvar_Set("cg_fraglimit", Info_ValueForKey(info, "fraglimit"));
cgi.Cvar_Set("cg_timelimit", Info_ValueForKey(info, "timelimit"));
cgi.Cvar_Set("cg_maxclients", Info_ValueForKey(info, "sv_gametype"));
cgi.Cvar_Set("cg_obj_alliedtext1", Info_ValueForKey(info, "g_obj_alliedtext1"));
cgi.Cvar_Set("cg_obj_alliedtext2", Info_ValueForKey(info, "g_obj_alliedtext2"));
cgi.Cvar_Set("cg_obj_alliedtext3", Info_ValueForKey(info, "g_obj_alliedtext3"));
cgi.Cvar_Set("cg_obj_axistext1", Info_ValueForKey(info, "cg_obj_axistext1"));
cgi.Cvar_Set("cg_obj_axistext2", Info_ValueForKey(info, "cg_obj_axistext2"));
cgi.Cvar_Set("cg_obj_axistext3", Info_ValueForKey(info, "cg_obj_axistext3"));
cgi.Cvar_Set("cg_scoreboardpic", Info_ValueForKey(info, "g_scoreboardpic"));
cgi.Cvar_Set("cg_scoreboardpicover", Info_ValueForKey(info, "g_scoreboardpicover"));
info = CG_ConfigString( CS_WARMUP );
mapname = Info_ValueForKey(info, "mapname");
warmup = atoi( info );
cg.warmupCount = -1;
spawnpos = strchr(mapname, '$');
if (spawnpos) {
Q_strncpyz(map, mapname, spawnpos - mapname + 1);
} else {
strcpy(map, mapname);
}
if ( warmup == 0 && cg.warmup ) {
Com_sprintf(cgs.mapname, sizeof(cgs.mapname), "maps/%s.bsp", map);
} else if ( warmup > 0 && cg.warmup <= 0 ) {
{
// cgi.S_StartLocalSound( cgs.media.countPrepareSound, CHAN_ANNOUNCER );
}
}
cg.warmup = warmup;
}
/*
================
CG_SetConfigValues
Called on load to set the initial values from configure strings
================
*/
void CG_SetConfigValues( void ) {
cgs.levelStartTime = atoi( CG_ConfigString( CS_LEVEL_START_TIME ) );
cg.warmup = atoi( CG_ConfigString( CS_WARMUP ) );
// hide/show huds
if (cgs.gametype)
{
cgi.Cmd_Execute(EXEC_NOW, "ui_addhud hud_timelimit\n");
if (cgs.fraglimit)
{
cgi.Cmd_Execute(EXEC_NOW, "ui_addhud hud_fraglimit\n");
cgi.Cmd_Execute(EXEC_NOW, "ui_removehud hud_score\n");
}
else
{
cgi.Cmd_Execute(EXEC_NOW, "ui_addhud hud_score\n");
cgi.Cmd_Execute(EXEC_NOW, "ui_removehud hud_fraglimit\n");
}
}
else
{
cgi.Cmd_Execute(EXEC_NOW, "ui_removehud hud_timelimit\n");
cgi.Cmd_Execute(EXEC_NOW, "ui_removehud hud_fraglimit\n");
cgi.Cmd_Execute(EXEC_NOW, "ui_removehud hud_score\n");
}
}
/*
@@ -96,296 +101,74 @@ CG_ConfigStringModified
================
*/
static void CG_ConfigStringModified( void ) {
const char *str;
int num;
char buffer[MAX_QPATH];
static void CG_ConfigStringModified(void)
{
int num;
num = atoi( CG_Argv( 1 ) );
num = atoi(cgi.Argv(1));
// get the gamestate from the client system, which will have the
// new configstring already integrated
cgi.GetGameState( &cgs.gameState );
// get the gamestate from the client system, which will have the
// new configstring already integrated
cgi.GetGameState(&cgs.gameState);
// look up the individual string that was modified
str = CG_ConfigString( num );
// do something with it if necessary
if ( num == CS_MUSIC ) {
CG_StartMusic();
} else if ( num == CS_SERVERINFO ) {
CG_ParseServerinfo();
} else if ( num == CS_WARMUP ) {
CG_ParseWarmup();
} else if( num >= CS_RAIN_DENSITY && num <= CS_RAIN_NUMSHADERS) {
CG_RainCSUpdated(num,str);
} else if ( num == CS_FOGINFO ) {
sscanf(str, "%d %f %f %f %f", &cg.farplane_cull, &cg.farplane_distance,
&cg.farplane_color[0], &cg.farplane_color[1], &cg.farplane_color[2]);
} else if ( num == CS_LEVEL_START_TIME ) {
cgs.levelStartTime = atoi( str );
} else if ( num >= CS_MODELS && num < CS_MODELS+MAX_MODELS ) {
cgs.gameModels[ num-CS_MODELS ] = cgi.R_RegisterModel( str );
if(str[0] && str[0] != '*') {
cgs.gameTIKIs[num-CS_MODELS] = cgi.TIKI_RegisterModel( str );
if(cgs.gameTIKIs[num-CS_MODELS] == 0) {
CG_Printf("CG_ConfigStringModified: failed to load tiki file %s (%i)\n",str,num-CS_MODELS);
}
}
} else if ( num >= CS_SOUNDS && num < CS_SOUNDS+MAX_SOUNDS ) {
if ( str[0] != '*' ) { // player specific sounds don't register here
Q_strncpyz( buffer, str, sizeof(buffer) );
if (buffer[strlen( buffer )-1] == '0' || buffer[strlen( buffer )-1] == '1')
buffer[strlen( buffer )-1] = 0;
cgs.gameSounds[ num-CS_SOUNDS] = cgi.S_RegisterSound( buffer, qfalse );
}
} else if ( num >= CS_PLAYERS && num < CS_PLAYERS+MAX_CLIENTS ) {
CG_NewClientInfo( num - CS_PLAYERS );
} else if( num >= CS_WEAPONS && num < CS_TEAMS ) {
CG_RegisterItemName(num - CS_WEAPONS, str);
}
}
/*
=======================
CG_AddToTeamChat
=======================
*/
static void CG_AddToTeamChat( const char *str ) {
int len;
char *p, *ls;
int lastcolor;
int chatHeight;
if (cg_teamChatHeight->integer < TEAMCHAT_HEIGHT) {
chatHeight = cg_teamChatHeight->integer;
} else {
chatHeight = TEAMCHAT_HEIGHT;
}
if (chatHeight <= 0 || cg_teamChatTime->integer <= 0) {
// team chat disabled, dump into normal chat
cgs.teamChatPos = cgs.teamLastChatPos = 0;
return;
}
len = 0;
p = cgs.teamChatMsgs[cgs.teamChatPos % chatHeight];
*p = 0;
lastcolor = '7';
ls = NULL;
while (*str) {
if (len > TEAMCHAT_WIDTH - 1) {
if (ls) {
str -= (p - ls);
str++;
p -= (p - ls);
}
*p = 0;
cgs.teamChatMsgTimes[cgs.teamChatPos % chatHeight] = cg.time;
cgs.teamChatPos++;
p = cgs.teamChatMsgs[cgs.teamChatPos % chatHeight];
*p = 0;
*p++ = Q_COLOR_ESCAPE;
*p++ = lastcolor;
len = 0;
ls = NULL;
}
if ( Q_IsColorString( str ) ) {
*p++ = *str++;
lastcolor = *str;
*p++ = *str++;
continue;
}
if (*str == ' ') {
ls = p;
}
*p++ = *str++;
len++;
}
*p = 0;
cgs.teamChatMsgTimes[cgs.teamChatPos % chatHeight] = cg.time;
cgs.teamChatPos++;
if (cgs.teamChatPos - cgs.teamLastChatPos > chatHeight)
cgs.teamLastChatPos = cgs.teamChatPos - chatHeight;
CG_ProcessConfigString(num);
}
/*
===============
CG_MapRestart
================
CG_ParseStats
The server has issued a map_restart, so the next snapshot
is completely new and should not be interpolated to.
A tournement restart will clear everything, but doesn't
require a reload of all the media
===============
================
*/
static void CG_MapRestart( void ) {
if ( cg_showmiss->integer ) {
CG_Printf( "CG_MapRestart\n" );
}
CG_InitLocalEntities();
CG_InitMarkPolys();
CG_ClearParticles ();
// make sure the "3 frags left" warnings play again
cg.fraglimitWarnings = 0;
cg.timelimitWarnings = 0;
cg.mapRestart = qtrue;
CG_StartMusic();
cgi.S_ClearLoopingSounds(qtrue);
// we really should clear more parts of cg here and stop sounds
// play the "fight" sound if this is a restart without warmup
if ( cg.warmup == 0 /* && cgs.gametype == GT_TOURNAMENT */) {
// cgi.S_StartLocalSound( cgs.media.countFightSound, CHAN_ANNOUNCER );
CG_CenterPrint( "FIGHT!", 120, GIANTCHAR_WIDTH*2 );
}
cgi.Cvar_Set("cg_thirdPerson", "0");
static void CG_ParseStats()
{
cgi.Cvar_Set("ui_NumObjectives", cgi.Argv(1));
cgi.Cvar_Set("ui_NumComplete", cgi.Argv(2));
cgi.Cvar_Set("ui_NumShotsFired", cgi.Argv(3));
cgi.Cvar_Set("ui_NumHits", cgi.Argv(4));
cgi.Cvar_Set("ui_Accuracy", cgi.Argv(5));
cgi.Cvar_Set("ui_PreferredWeapon", cgi.Argv(6));
cgi.Cvar_Set("ui_NumHitsTaken", cgi.Argv(7));
cgi.Cvar_Set("ui_NumObjectsDestroyed", cgi.Argv(8));
cgi.Cvar_Set("ui_NumEnemysKilled", cgi.Argv(9));
cgi.Cvar_Set("ui_HeadShots", cgi.Argv(10));
cgi.Cvar_Set("ui_TorsoShots", cgi.Argv(11));
cgi.Cvar_Set("ui_LeftLegShots", cgi.Argv(12));
cgi.Cvar_Set("ui_RightLegShots", cgi.Argv(13));
cgi.Cvar_Set("ui_GroinShots", cgi.Argv(14));
cgi.Cvar_Set("ui_LeftArmShots", cgi.Argv(15));
cgi.Cvar_Set("ui_RightArmShots", cgi.Argv(16));
cgi.Cvar_Set("ui_GunneryEvaluation", cgi.Argv(17));
cgi.Cvar_Set("ui_gotmedal", cgi.Argv(18));
cgi.Cvar_Set("ui_success", cgi.Argv(19));
cgi.Cvar_Set("ui_failed", cgi.Argv(20));
}
/*
=================
CG_RemoveChatEscapeChar
=================
================
CG_Stopwatch_f
================
*/
static void CG_RemoveChatEscapeChar( char *text ) {
int i, l;
static void CG_Stopwatch_f()
{
if (cgi.Argc() != 3) {
Com_Error(1, "stopwatch didn't have 2 parameters");
}
l = 0;
for ( i = 0; text[i]; i++ ) {
if (text[i] == '\x19')
continue;
text[l++] = text[i];
}
text[l] = '\0';
}
// Wombat: Lists of blocked and allowed stufftext commands
const char *stufftextBlock[] = {
"quit"
};
typedef struct {
char *cmd;
int args;
} stufftextCommand_t;
stufftextCommand_t stufftextSafe[] = {
{ "pushmenu_teamselect", 0 },
{ "pushmenu_weaponselect", 0 },
{ "wait", 1 },
{ "locationprint", 3 }, // locationprint <x> <y> <text ... >
{ "add", 2 }, // add <variable> <amount>
// su44: these are used on "-(V)ethod-Clan" server ( 8.9.16.34:12203 )
// for some kind of anticheat
{ "set", 2 }, // set <variable> <value>
{ "setu", 2 }, // setu <variable> <value>
};
/*
=================
CG_StufftextCommand
Wombat: MOHAA servers may send certain server commands
that contain console commands supposed to be executed
on the client's console.
I don't like the idea that a remote machine can execute
*anything*, so i think i will implement a filter to pass only
sane commands...
=================
*/
void CG_StufftextCommand( const char *cmd ) {
int i;
char *ptr;
const char *ptr2;
ptr = ( char * )cmd;
ptr2 = COM_Parse(&ptr);
for ( i = 0 ; i < sizeof( stufftextBlock ) / sizeof( stufftextBlock[0] ) ; i++ ) {
if ( !Q_stricmp( ptr2, stufftextBlock[i] ) ) {
return;
}
}
// wombat: some servers use ST commands for anti-cheat measures
// we don't use the whitelist right now...
Com_Printf( "^3Executing stufftext command: \"%s\"\n", cmd );
cgi.SendConsoleCommand( cmd );
return;
for ( i = 0 ; i < sizeof( stufftextSafe ) / sizeof( stufftextSafe[0] ) ; i++ ) {
if ( !Q_stricmp( ptr2, stufftextSafe[i].cmd ) ) {
cgi.SendConsoleCommand( cmd );
return;
}
}
Com_Printf( "Unlisted stufftext command: \"%s\"\n", cmd );
cgi.stopWatch->iStartTime = 1000 * atoi(cgi.Argv(1));
cgi.stopWatch->iEndTime = cgi.stopWatch->iStartTime + 1000 * atoi(cgi.Argv(2));
}
/*
=================
CG_AddGameMessage
================
CG_ServerLag_f
To be printed below the compass
=================
================
*/
void CG_AddGameMessage( const char *cmd, serverMessageType_t smt ) {
ubersound_t *click;
click = CG_GetUbersound( "click" );
switch ( smt ) {
case SMT_YELLOW:
case SMT_WHITE:
if ( cg.gameMessageTime == 0 )
cg.gameMessageTime = cg.time;
cg.gameMessageTypes[cg.gameMessagePtr2] = smt;
Q_strncpyz( cg.gameMessages[cg.gameMessagePtr2], cmd, sizeof(cg.gameMessages[cg.gameMessagePtr2]) );
CG_Printf( "Game Message: %s", cmd );
cgi.S_StartLocalSound( click->sfxHandle, click->channel );
cg.gameMessagePtr2 = (cg.gameMessagePtr2+1) % MAX_GAMEMESSAGES;
if ( cg.gameMessagePtr2 == cg.gameMessagePtr1 ) {
cg.gameMessagePtr1 = (cg.gameMessagePtr1+1) % MAX_GAMEMESSAGES;
cg.gameMessageTime = cg.time;
}
break;
case SMT_CHAT:
CG_Printf( "Chat: %s", cmd );
cgi.S_StartLocalSound( click->sfxHandle, click->channel );
case SMT_DEATH:
if ( cg.chatDeathMessageTime == 0 )
cg.chatDeathMessageTime = cg.time;
cg.chatDeathMessageTypes[cg.chatDeathMessagePtr2] = smt;
Q_strncpyz( cg.chatDeathMessages[cg.chatDeathMessagePtr2], cmd, sizeof(cg.chatDeathMessages[cg.chatDeathMessagePtr2]) );
if ( smt == SMT_DEATH )
CG_Printf( "Death: %s", cmd );
cg.chatDeathMessagePtr2 = (cg.chatDeathMessagePtr2+1) % MAX_CHATDEATHMESSAGES;
if (cg.chatDeathMessagePtr2 == cg.chatDeathMessagePtr1 ) {
cg.chatDeathMessagePtr1 = (cg.chatDeathMessagePtr1+1) % MAX_CHATDEATHMESSAGES;
cg.chatDeathMessageTime = cg.time;
}
break;
case SMT_UNKNOWN:
CG_Printf( "Unknown Message: %s", cmd );
break;
}
static void CG_ServerLag_f()
{
cgs.serverLagTime = cg.time;
}
/*
@@ -396,133 +179,59 @@ The string has been tokenized and can be retrieved with
Cmd_Argc() / Cmd_Argv()
=================
*/
static void CG_ServerCommand( void ) {
const char *cmd;
char stufftextBuffer[512];
const char *ptr;
char letter;
int i;
int lastpos;
static void CG_ServerCommand(void)
{
const char* cmd;
cmd = CG_Argv(0);
cmd = cgi.Argv(0);
if ( !cmd[0] ) {
// server claimed the command
return;
}
if (!cmd[0]) {
// server claimed the command
return;
}
// wombat: stufftext is something specific to MOHAA
if ( !strcmp( cmd, "stufftext" ) ) {
if (!strcmp(cmd, "cs")) {
CG_ConfigStringModified();
return;
}
ptr = CG_Argv(1);
for ( i=0,lastpos=0; i<sizeof(stufftextBuffer);i++ ) {
letter = *(ptr + i);
if ( i == sizeof(stufftextBuffer) && letter != 0 ) {
Com_Printf( "WARNING: Max. stufftext command length (%i) exceeded.\n", sizeof(stufftextBuffer) );
return;
}
if ( letter == ';' ) {
letter = 0;
stufftextBuffer[i] =letter;
CG_StufftextCommand( &stufftextBuffer[lastpos] );
lastpos = i+1;
}
else if ( letter == 0 ) {
stufftextBuffer[i] =letter;
CG_StufftextCommand( &stufftextBuffer[lastpos] );
return;
}
else stufftextBuffer[i] =letter;
}
return;
}
if (!strcmp(cmd, "print") || !strcmp(cmd, "hudprint")) {
cgi.Printf("%s", cgi.Argv(1));
if (!strcmp(cmd, "hudprint")) {
CG_HudPrint_f();
}
return;
}
if (!strcmp(cmd, "stufftext")) {
cgi.Cmd_Stuff(cgi.Argv(1));
cgi.Cmd_Stuff("\n");
return;
}
if ( !strcmp( cmd, "cp" ) ) {
CG_CenterPrint( CG_Argv(1), SCREEN_HEIGHT * 0.30, BIGCHAR_WIDTH );
return;
}
if (!strcmp(cmd, "scores")) {
CG_ParseScores();
return;
}
if ( !strcmp( cmd, "cs" ) ) {
CG_ConfigStringModified();
return;
}
if (!strcmp(cmd, "stats")) {
CG_ParseStats();
return;
}
if ( !strcmp( cmd, "print" ) ) {
// TODO: print to screen, too
const char *ptr;
serverMessageType_t smt;
if (!strcmp(cmd, "stopwatch")) {
CG_Stopwatch_f();
return;
}
ptr = CG_Argv(1);
smt = (serverMessageType_t)*ptr;
if (!strcmp(cmd, "svlag")) {
CG_ServerLag_f();
return;
}
if ( smt < SMT_MAX )
CG_AddGameMessage( ptr + 1, smt );
else
CG_Printf( "%s", ptr );
return;
}
// su44: chats are handled differently in MoH
// if ( !strcmp( cmd, "chat" ) ) {
// if ( !cg_teamChatsOnly->integer ) {
//// cgi.S_StartLocalSound( cgs.media.talkSound, CHAN_LOCAL_SOUND );
// Q_strncpyz( text, CG_Argv(1), MAX_SAY_TEXT );
// CG_RemoveChatEscapeChar( text );
// CG_Printf( "%s\n", text );
// }
// return;
// }
//
// if ( !strcmp( cmd, "tchat" ) ) {
//// cgi.S_StartLocalSound( cgs.media.talkSound, CHAN_LOCAL_SOUND );
// Q_strncpyz( text, CG_Argv(1), MAX_SAY_TEXT );
// CG_RemoveChatEscapeChar( text );
// CG_AddToTeamChat( text );
// CG_Printf( "%s\n", text );
// return;
// }
if ( !strcmp( cmd, "scores" ) ) {
//CG_ParseScores();
Q_strncpyz( cg.aScore, cgi.Args(), sizeof( cg.aScore ) );
return;
}
//if ( !strcmp( cmd, "map_restart" ) ) {
// CG_MapRestart();
// return;
//}
// clientLevelShot is sent before taking a special screenshot for
// the menu system during development
if ( !strcmp( cmd, "clientLevelShot" ) ) {
cg.levelShot = qtrue;
return;
}
// MoHAA's stopwatch
if ( !strcmp( cmd, "stopwatch" ) ) {
// TODO
return;
}
if ( !strcmp( cmd, "svlag" ) ) {
// TODO
return;
}
// su44: send just before server map change
if ( !strcmp( cmd, "fadesound" ) ) {
// TODO
return;
}
CG_Printf( "Unknown client game command: %s\n", cmd );
cgi.Printf("Unknown client game command: %s\n", cmd);
}
/*
====================
CG_ExecuteNewServerCommands
@@ -531,10 +240,11 @@ Execute all of the server commands that were received along
with this this snapshot.
====================
*/
void CG_ExecuteNewServerCommands( int latestSequence ) {
while ( cgs.serverCommandSequence < latestSequence ) {
if ( cgi.GetServerCommand( ++cgs.serverCommandSequence ) ) {
CG_ServerCommand();
}
}
void CG_ExecuteNewServerCommands(int latestSequence, qboolean differentServer)
{
while (cgs.serverCommandSequence < latestSequence) {
if (cgi.GetServerCommand(++cgs.serverCommandSequence, differentServer)) {
CG_ServerCommand();
}
}
}
+335 -344
View File
@@ -1,43 +1,101 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
Copyright (C) 2023 the OpenMoHAA team
This file is part of Quake III Arena source code.
This file is part of OpenMoHAA source code.
Quake III Arena source code is free software; you can redistribute it
OpenMoHAA source code is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the License,
or (at your option) any later version.
Quake III Arena source code is distributed in the hope that it will be
OpenMoHAA source code is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Quake III Arena source code; if not, write to the Free Software
along with OpenMoHAA source code; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
//
// cg_snapshot.c -- things that happen on snapshot transition,
// not necessarily every single rendered frame
// DESCRIPTION:
// things that happen on snapshot transition, not necessarily every
// single frame
#include "cg_local.h"
#include "../qcommon/tiki_local.h"
#include "tiki.h"
/*
==================
CG_ResetEntity
==================
*/
static void CG_ResetEntity( centity_t *cent ) {
VectorCopy (cent->currentState.origin, cent->lerpOrigin);
VectorCopy (cent->currentState.angles, cent->lerpAngles);
if ( cent->currentState.eType == ET_PLAYER ) {
CG_ResetPlayerEntity( cent );
}
static void CG_ResetEntity(centity_t* cent)
{
dtiki_t* tiki;
int i;
VectorCopy(cent->currentState.origin, cent->lerpOrigin);
VectorCopy(cent->currentState.angles, cent->lerpAngles);
// if we just teleported, all we care about is the position and orientation
// information
if (cent->teleported) {
cent->teleported = qfalse;
return;
}
// reset local color
cent->client_color[0] = 1;
cent->client_color[1] = 1;
cent->client_color[2] = 1;
cent->client_color[3] = 1;
// Make sure entity starts with no loop sound
cent->tikiLoopSound = 0;
// Reset client flags
cent->clientFlags = 0;
// Reset splash info
cent->splash_last_spawn_time = 0;
cent->splash_still_count = -1;
tiki = cgi.R_Model_GetHandle(cgs.model_draw[cent->currentState.modelindex]);
// reset client command
CG_RemoveClientEntity(cent->currentState.number, tiki, cent);
// reset the animation for the entities
if (tiki && tiki->a->bIsCharacter) {
for (i = 0; i < MAX_FRAMEINFOS; i++) {
cent->animLast[i] = cent->currentState.frameInfo[i].index;
cent->animLastTimes[i] = cent->currentState.frameInfo[i].time;
if (cent->currentState.frameInfo[i].weight) {
cent->animLastWeight |= 1 << i;
} else {
// zero-weight shouldn't count
cent->animLastWeight &= ~(1 << i);
}
}
} else {
// clear all the last animations
for (i = 0; i < MAX_FRAMEINFOS; i++) {
cent->animLast[i] = -1;
}
cent->animLastWeight = 0;
}
cent->usageIndexLast = 0;
cent->bFootOnGround_Left = qtrue;
cent->bFootOnGround_Right = qtrue;
if (cent->currentState.eType == ET_PLAYER) {
CG_ResetPlayerEntity(cent);
}
}
/*
@@ -47,148 +105,66 @@ CG_TransitionEntity
cent->nextState is moved to cent->currentState and events are fired
===============
*/
static int TIKI_FrameNumForTime(tiki_t *tiki, int animIndex, float animTime) {
int i;
tikiAnim_t *anim;
if(tiki->numAnims <= animIndex) {
Com_Printf("TIKI_FrameNumForTime: animIndex %i out of range %i\n",animIndex,tiki->numAnims);
return 0;
}
anim = tiki->anims[animIndex];
if(anim->numFrames == 1) {
return 0;
}
i = 0;
while(animTime > anim->frameTime) {
animTime -= anim->frameTime;
i++;
}
return i;
}
static void CG_ExecuteFrameCommands(centity_t *cent, tikiAnim_t *anim, int frameIndex) {
int i;
tikiCommand_t *cmd;
cmd = anim->clientCmds;
for(i = 0; i < anim->numClientCmds; i++,cmd++) {
if(cmd->frame == frameIndex) {
//CG_Printf("Frame %i command %s\n",cmd->frame,cmd->text);
//CG_ProcessEventText(cent,cmd->text);
CG_PostEvent(cent,cmd->text,0);
}
}
}
static void CG_ExecuteFramesCommands(centity_t *cent, tikiAnim_t *anim, int start, int stop) {
int i;
tikiCommand_t *cmd;
cmd = anim->clientCmds;
for(i = 0; i < anim->numClientCmds; i++,cmd++) {
if(cmd->frame >= start && cmd->frame <= stop) {
//CG_Printf("Frame %i command %s\n",cmd->frame,cmd->text);
//CG_ProcessEventText(cent,cmd->text);
CG_PostEvent(cent,cmd->text,0);
}
}
}
static void CG_TransitionEntity(centity_t* cent)
{
cent->currentState = cent->nextState;
cent->currentValid = qtrue;
static void CG_TransitionEntity( centity_t *cent ) {
frameInfo_t *fi0, *fi1;
tiki_t *tiki0,*tiki1;
tikiAnim_t *a0, *a1;
int f0, f1;
int i;
tiki0 = cgs.gameTIKIs[cent->currentState.modelindex];
tiki1 = cgs.gameTIKIs[cent->nextState.modelindex];
if(tiki0 || tiki1) {
// su44: It should be placed somewhere else soon
fi0 = cent->currentState.frameInfo;
fi1 = cent->nextState.frameInfo;
for(i = 0; i < 16; i++,fi0++,fi1++) {
if(fi0->weight && tiki0 && fi0->index < tiki0->numAnims) {
a0 = tiki0->anims[fi0->index];
f0 = TIKI_FrameNumForTime(tiki0,fi0->index,fi0->time);
if(fi1->weight && tiki1 && fi1->index < tiki1->numAnims) {
if(fi0->index != fi1->index || tiki0 != tiki1) {
a1 = tiki1->anims[fi1->index];
CG_ExecuteFrameCommands(cent,a0,TIKI_FRAME_EXIT);
CG_ExecuteFrameCommands(cent,a1,TIKI_FRAME_ENTRY);
} else {
f1 = TIKI_FrameNumForTime(tiki1,fi1->index,fi1->time);
if(f1 > f0) {
CG_ExecuteFramesCommands(cent,a0,f0,f1);
} else {
CG_ExecuteFramesCommands(cent,a0,f1,f0);
}
}
} else {
// anim has stopped
//CG_ExecuteFramesCommands(cent,anim,fi0->
CG_ExecuteFrameCommands(cent,a0,TIKI_FRAME_EXIT);
}
} else if(fi1->weight && tiki1 && fi1->index < tiki1->numAnims) {
// anim is starting
a1 = tiki1->anims[fi1->index];
f1 = TIKI_FrameNumForTime(tiki1,fi1->index,fi1->time);
CG_ExecuteFrameCommands(cent,a1,TIKI_FRAME_ENTRY);
}
}
}
cent->currentState = cent->nextState;
cent->currentValid = qtrue;
// reset if the entity wasn't in the last frame or was teleported
if (!cent->interpolate) {
CG_ResetEntity(cent);
}
// reset if the entity wasn't in the last frame or was teleported
if ( !cent->interpolate ) {
CG_ResetEntity( cent );
}
// clear the next state. if will be set by the next CG_SetNextSnap
cent->interpolate = qfalse;
// reset the teleported state
cent->teleported = qfalse;
// clear the next state. if will be set by the next CG_SetNextSnap
cent->interpolate = qfalse;
if (cent->currentState.eType == ET_EVENTS) {
CG_Event(cent);
}
}
/*
==================
CG_SetInitialSnapshot
This will only happen on the very first snapshot, or
on tourney restarts. All other times will use
on tourney restarts. All other times will use
CG_TransitionSnapshot instead.
FIXME: Also called by map_restart?
==================
*/
void CG_SetInitialSnapshot( snapshot_t *snap ) {
int i;
centity_t *cent;
entityState_t *state;
void CG_SetInitialSnapshot(snapshot_t* snap)
{
int i;
centity_t* cent;
entityState_t* state;
cg.snap = snap;
cg.snap = snap;
BG_PlayerStateToEntityState( &snap->ps, &cg_entities[ snap->ps.clientNum ].currentState, qfalse );
// sort out solid entities
CG_BuildSolidList();
// sort out solid entities
CG_BuildSolidList();
CG_ExecuteNewServerCommands(snap->serverCommandSequence, qfalse);
CG_ExecuteNewServerCommands( snap->serverCommandSequence );
for (i = 0; i < cg.snap->numEntities; i++) {
state = &cg.snap->entities[i];
cent = &cg_entities[state->number];
// set our local weapon selection pointer to
// what the server has indicated the current weapon is
CG_Respawn();
cent->currentState = *state;
cent->interpolate = qfalse;
cent->currentValid = qtrue;
for ( i = 0 ; i < cg.snap->numEntities ; i++ ) {
state = &cg.snap->entities[ i ];
cent = &cg_entities[ state->number ];
CG_ResetEntity(cent);
}
memcpy(&cent->currentState, state, sizeof(entityState_t));
//cent->currentState = *state;
cent->interpolate = qfalse;
cent->currentValid = qtrue;
CG_ResetEntity( cent );
}
cgi.MUSIC_UpdateMood(snap->ps.current_music_mood,
snap->ps.fallback_music_mood);
cgi.MUSIC_UpdateVolume(snap->ps.music_volume,
snap->ps.music_volume_fade_time);
cgi.S_SetReverb(snap->ps.reverb_type, snap->ps.reverb_level);
}
/*
===================
CG_TransitionSnapshot
@@ -196,86 +172,81 @@ CG_TransitionSnapshot
The transition point from snap to nextSnap has passed
===================
*/
static void CG_TransitionSnapshot( void ) {
centity_t *cent;
snapshot_t *oldFrame;
int i;
static void CG_TransitionSnapshot(qboolean differentServer)
{
centity_t* cent;
snapshot_t* oldFrame;
int i;
server_sound_t *snd;
if (differentServer) {
CG_ServerRestarted();
}
if ( !cg.snap ) {
CG_Error( "CG_TransitionSnapshot: NULL cg.snap" );
}
if ( !cg.nextSnap ) {
CG_Error( "CG_TransitionSnapshot: NULL cg.nextSnap" );
}
// execute any server string commands before transitioning entities
CG_ExecuteNewServerCommands(cg.nextSnap->serverCommandSequence, differentServer);
// execute any server string commands before transitioning entities
CG_ExecuteNewServerCommands( cg.nextSnap->serverCommandSequence );
// clear the currentValid flag for all entities in the existing snapshot
for (i = 0; i < cg.snap->numEntities; i++) {
cent = &cg_entities[cg.snap->entities[i].number];
cent->currentValid = qfalse;
}
// if we had a map_restart, set everthing with initial
if ( !cg.snap ) {
}
// move nextSnap to snap and do the transitions
oldFrame = cg.snap;
cg.snap = cg.nextSnap;
// clear the currentValid flag for all entities in the existing snapshot
for ( i = 0 ; i < cg.snap->numEntities ; i++ ) {
cent = &cg_entities[ cg.snap->entities[ i ].number ];
cent->currentValid = qfalse;
}
// FAKK: Commented out to make our stuff work
// cg_entities[ cg.snap->ps.clientNum ].interpolate = qfalse;
// move nextSnap to snap and do the transitions
oldFrame = cg.snap;
cg.snap = cg.nextSnap;
for (i = 0; i < cg.snap->numEntities; i++) {
cent = &cg_entities[cg.snap->entities[i].number];
if (differentServer) {
cent->interpolate = qfalse;
cent->teleported = qfalse;
}
CG_TransitionEntity(cent);
}
BG_PlayerStateToEntityState( &cg.snap->ps, &cg_entities[ cg.snap->ps.clientNum ].currentState, qfalse );
cg_entities[ cg.snap->ps.clientNum ].interpolate = qfalse;
for (i = 0; i < cg.snap->number_of_sounds; i++) {
CG_ProcessSound(&cg.snap->sounds[i]);
}
for ( i = 0 ; i < cg.snap->numEntities ; i++ ) {
cent = &cg_entities[ cg.snap->entities[ i ].number ];
CG_TransitionEntity( cent );
cgi.MUSIC_UpdateMood(cg.snap->ps.current_music_mood, cg.snap->ps.fallback_music_mood);
cg.nextSnap = NULL;
// remember time of snapshot this entity was last updated in
cent->snapShotTime = cg.snap->serverTime;
}
// check for playerstate transition events
if (oldFrame) {
playerState_t *ops, *ps;
ops = &oldFrame->ps;
ps = &cg.snap->ps;
for ( i=0;i<cg.snap->number_of_sounds;i++ ) {
snd = &cg.snap->sounds[i];
if ( snd->sound_index == 0 ) // wombat: we get these sometimes, no clue why
continue;
if (snd->stop_flag) {
cgi.S_StopLoopingSound( snd->entity_number );
}
else {
cgi.S_StartSound( snd->origin, snd->entity_number, snd->channel, cgs.gameSounds[snd->sound_index] );
}
}
// teleporting checks are irrespective of prediction
if (ps->pm_flags & PMF_RESPAWNED) {
cg.thisFrameTeleport = qtrue;
}
cg.nextSnap = NULL;
if ((ops->music_volume != ps->music_volume) ||
(ops->music_volume_fade_time != ps->music_volume_fade_time)) {
cgi.MUSIC_UpdateVolume(ps->music_volume,
ps->music_volume_fade_time);
}
// check for playerstate transition events
if ( oldFrame ) {
playerState_t *ops, *ps;
ops = &oldFrame->ps;
ps = &cg.snap->ps;
// teleporting checks are irrespective of prediction
//if ( ( ps->eFlags ^ ops->eFlags ) & EF_TELEPORT_BIT ) {
// cg.thisFrameTeleport = qtrue; // will be cleared by prediction code
//}
// if we are not doing client side movement prediction for any
// reason, then the client events and view changes will be issued now
if ( cg.demoPlayback /*|| (cg.snap->ps.pm_flags & PMF_FOLLOW)*/
|| cg_nopredict->integer || cg_synchronousClients->integer ) {
CG_TransitionPlayerState( ps, ops );
}
}
if ((ops->reverb_type != ps->reverb_type) ||
(ops->reverb_level != ps->reverb_level)) {
cgi.S_SetReverb(ps->reverb_type, ps->reverb_level);
}
// if we are not doing client side movement prediction for any
// reason, then the client events and view changes will be issued now
if (cg.demoPlayback || (cg.snap->ps.pm_flags & PMF_NO_PREDICTION) ||
cg_nopredict->integer || cg_synchronousClients->integer) {
CG_TransitionPlayerState(ps, ops);
}
}
}
/*
===================
CG_SetNextSnap
@@ -283,58 +254,71 @@ CG_SetNextSnap
A new snapshot has just been read in from the client system.
===================
*/
static void CG_SetNextSnap( snapshot_t *snap ) {
int num;
entityState_t *es;
centity_t *cent;
static void CG_SetNextSnap(snapshot_t* snap)
{
int num;
entityState_t* es;
centity_t* cent;
cg.nextSnap = snap;
cg.nextSnap = snap;
BG_PlayerStateToEntityState( &snap->ps, &cg_entities[ snap->ps.clientNum ].nextState, qfalse );
cg_entities[ cg.snap->ps.clientNum ].interpolate = qtrue;
cg_entities[cg.snap->ps.clientNum].interpolate = qtrue;
// check for extrapolation errors
for ( num = 0 ; num < snap->numEntities ; num++ ) {
es = &snap->entities[num];
cent = &cg_entities[ es->number ];
// check for extrapolation errors
for (num = 0; num < snap->numEntities; num++) {
es = &snap->entities[num];
cent = &cg_entities[es->number];
memcpy(&cent->nextState, es, sizeof(entityState_t));
//cent->nextState = *es;
cent->nextState = *es;
// if this frame is a teleport, or the entity wasn't in the
// previous frame, don't interpolate
if ( !cent->currentValid || ( ( cent->currentState.eFlags ^ es->eFlags ) & EF_TELEPORT_BIT ) ) {
cent->interpolate = qfalse;
} else {
cent->interpolate = qtrue;
}
}
// if this frame is a teleport, or the entity wasn't in the
// previous frame, don't interpolate
if (!cent->currentValid ||
((cent->currentState.eFlags ^ es->eFlags) & EF_TELEPORT_BIT) ||
(cent->currentState.parent != es->parent) ||
(cent->currentState.modelindex != es->modelindex)) {
cent->interpolate = qfalse;
// if this isn't the first frame and we have valid data, set the
// teleport flag
if (cent->currentValid) {
cent->teleported = qtrue;
}
} else {
cent->interpolate = qtrue;
}
}
// if the next frame is a teleport for the playerstate, we
// can't interpolate during demos
//if ( cg.snap && ( ( snap->ps.eFlags ^ cg.snap->ps.eFlags ) & EF_TELEPORT_BIT ) ) {
// cg.nextFrameTeleport = qtrue;
//} else
{
cg.nextFrameTeleport = qfalse;
}
// if the next frame is a teleport for the playerstate, we
// can't interpolate during demos
if (cg.snap && (snap->ps.pm_flags & PMF_RESPAWNED)) {
cg.nextFrameTeleport = qtrue;
} else {
cg.nextFrameTeleport = qfalse;
}
// if changing follow mode, don't interpolate
if ( cg.nextSnap->ps.clientNum != cg.snap->ps.clientNum ) {
cg.nextFrameTeleport = qtrue;
}
// if changing follow mode, don't interpolate
if (cg.nextSnap->ps.clientNum != cg.snap->ps.clientNum) {
cg.nextFrameTeleport = qtrue;
}
// if changing server restarts, don't interpolate
if ( ( cg.nextSnap->snapFlags ^ cg.snap->snapFlags ) & SNAPFLAG_SERVERCOUNT ) {
cg.nextFrameTeleport = qtrue;
}
// if the camera cut bit changed, than the next frame is a camera cut
if ((cg.nextSnap->ps.camera_flags & CF_CAMERA_CUT_BIT) !=
(cg.snap->ps.camera_flags & CF_CAMERA_CUT_BIT)) {
cg.nextFrameCameraCut = qtrue;
} else {
cg.nextFrameCameraCut = qfalse;
}
// sort out solid entities
CG_BuildSolidList();
// if changing server restarts, don't interpolate
if (snap->serverTime < cgi.GetServerStartTime()) {
// reset the camera
cg.nextFrameTeleport = qtrue;
}
// sort out solid entities
CG_BuildSolidList();
}
/*
========================
CG_ReadNextSnapshot
@@ -345,55 +329,50 @@ times if the client system fails to return a
valid snapshot.
========================
*/
static snapshot_t *CG_ReadNextSnapshot( void ) {
qboolean r;
snapshot_t *dest;
static snapshot_t* CG_ReadNextSnapshot(void)
{
qboolean r;
snapshot_t* dest;
if ( cg.latestSnapshotNum > cgs.processedSnapshotNum + 1000 ) {
CG_Printf( "WARNING: CG_ReadNextSnapshot: way out of range, %i > %i",
cg.latestSnapshotNum, cgs.processedSnapshotNum );
}
if (cg.latestSnapshotNum > cgs.processedSnapshotNum + 1000) {
cgi.Error(ERR_DROP, "CG_ReadNextSnapshot: way out of range, %i > %i",
cg.latestSnapshotNum, cgs.processedSnapshotNum);
}
while ( cgs.processedSnapshotNum < cg.latestSnapshotNum ) {
// decide which of the two slots to load it into
if ( cg.snap == &cg.activeSnapshots[0] ) {
dest = &cg.activeSnapshots[1];
} else {
dest = &cg.activeSnapshots[0];
}
while (cgs.processedSnapshotNum < cg.latestSnapshotNum) {
// decide which of the two slots to load it into
if (cg.snap == &cg.activeSnapshots[0]) {
dest = &cg.activeSnapshots[1];
} else {
dest = &cg.activeSnapshots[0];
}
// try to read the snapshot from the client system
cgs.processedSnapshotNum++;
r = cgi.GetSnapshot( cgs.processedSnapshotNum, dest );
// try to read the snapshot from the client system
cgs.processedSnapshotNum++;
r = cgi.GetSnapshot(cgs.processedSnapshotNum, dest);
// FIXME: why would cgi.GetSnapshot return a snapshot with the same server time
if ( cg.snap && r && dest->serverTime == cg.snap->serverTime ) {
//continue;
}
// if it succeeded, return
if (r) {
CG_AddLagometerSnapshotInfo(dest);
return dest;
}
// if it succeeded, return
if ( r ) {
CG_AddLagometerSnapshotInfo( dest );
return dest;
}
// a GetSnapshot will return failure if the snapshot
// never arrived, or is so old that its entities
// have been shoved off the end of the circular
// buffer in the client system.
// a GetSnapshot will return failure if the snapshot
// never arrived, or is so old that its entities
// have been shoved off the end of the circular
// buffer in the client system.
// record as a dropped packet
CG_AddLagometerSnapshotInfo(NULL);
// record as a dropped packet
CG_AddLagometerSnapshotInfo( NULL );
// If there are additional snapshots, continue trying to
// read them.
}
// If there are additional snapshots, continue trying to
// read them.
}
// nothing left to read
return NULL;
// nothing left to read
return NULL;
}
/*
============
CG_ProcessSnapshots
@@ -413,80 +392,92 @@ of an interpolating one)
============
*/
void CG_ProcessSnapshots( void ) {
snapshot_t *snap;
int n;
void CG_ProcessSnapshots(void)
{
snapshot_t* snap;
int n;
qboolean differentServer;
// see what the latest snapshot the client system has is
cgi.GetCurrentSnapshotNumber( &n, &cg.latestSnapshotTime );
if ( n != cg.latestSnapshotNum ) {
if ( n < cg.latestSnapshotNum ) {
// this should never happen
CG_Error( "CG_ProcessSnapshots: n < cg.latestSnapshotNum" );
}
cg.latestSnapshotNum = n;
}
// see what the latest snapshot the client system has is
cgi.GetCurrentSnapshotNumber(&n, &cg.latestSnapshotTime);
if (n != cg.latestSnapshotNum) {
if (n < cg.latestSnapshotNum) {
// this should never happen
cgi.Error(ERR_DROP,
"CG_ProcessSnapshots: n < cg.latestSnapshotNum");
}
cg.latestSnapshotNum = n;
}
// If we have yet to receive a snapshot, check for it.
// Once we have gotten the first snapshot, cg.snap will
// always have valid data for the rest of the game
while ( !cg.snap ) {
snap = CG_ReadNextSnapshot();
if ( !snap ) {
// we can't continue until we get a snapshot
return;
}
// If we have yet to receive a snapshot, check for it.
// Once we have gotten the first snapshot, cg.snap will
// always have valid data for the rest of the game
while (!cg.snap) {
snap = CG_ReadNextSnapshot();
if (!snap) {
// we can't continue until we get a snapshot
return;
}
// set our weapon selection to what
// the playerstate is currently using
if ( !( snap->snapFlags & SNAPFLAG_NOT_ACTIVE ) ) {
CG_SetInitialSnapshot( snap );
}
}
// set our weapon selection to what
// the playerstate is currently using
if (!(snap->snapFlags & SNAPFLAG_NOT_ACTIVE)) {
CG_SetInitialSnapshot(snap);
}
}
// loop until we either have a valid nextSnap with a serverTime
// greater than cg.time to interpolate towards, or we run
// out of available snapshots
do {
// if we don't have a nextframe, try and read a new one in
if ( !cg.nextSnap ) {
snap = CG_ReadNextSnapshot();
// loop until we either have a valid nextSnap with a serverTime
// greater than cg.time to interpolate towards, or we run
// out of available snapshots
do {
// if we don't have a nextframe, try and read a new one in
if (!cg.nextSnap) {
snap = CG_ReadNextSnapshot();
// if we still don't have a nextframe, we will just have to
// extrapolate
if ( !snap ) {
break;
}
// if we still don't have a nextframe, we will just have to
// extrapolate
if (!snap) {
break;
}
CG_SetNextSnap( snap );
CG_SetNextSnap(snap);
// if time went backwards, we have a level restart
if (cg.nextSnap->serverTime < cg.snap->serverTime) {
// only drop if this is not a restart or loadgame
if (!((cg.nextSnap->snapFlags ^ cg.snap->snapFlags) &
SNAPFLAG_SERVERCOUNT)) {
cgi.Error(
ERR_DROP,
"CG_ProcessSnapshots: Server time went backwards");
}
}
}
// if time went backwards, we have a level restart
if ( cg.nextSnap->serverTime < cg.snap->serverTime ) {
CG_Error( "CG_ProcessSnapshots: Server time went backwards" );
}
}
differentServer = cg.snap->serverTime <= cgi.GetServerStartTime();
// if our time is < nextFrame's, we have a nice interpolating state
if ( cg.time >= cg.snap->serverTime && cg.time < cg.nextSnap->serverTime ) {
break;
}
// if our time is < nextFrame's, we have a nice interpolating state
if (cg.time >= cg.snap->serverTime &&
cg.time < cg.nextSnap->serverTime &&
!differentServer) {
break;
}
// we have passed the transition from nextFrame to frame
CG_TransitionSnapshot();
} while ( 1 );
// assert our valid conditions upon exiting
if ( cg.snap == NULL ) {
CG_Error( "CG_ProcessSnapshots: cg.snap == NULL" );
}
if ( cg.time < cg.snap->serverTime ) {
// this can happen right after a vid_restart
cg.time = cg.snap->serverTime;
}
if ( cg.nextSnap != NULL && cg.nextSnap->serverTime <= cg.time ) {
CG_Error( "CG_ProcessSnapshots: cg.nextSnap->serverTime <= cg.time" );
}
// we have passed the transition from nextFrame to frame
CG_TransitionSnapshot(differentServer);
} while (1);
// assert our valid conditions upon exiting
if (cg.snap == NULL) {
cgi.Error(ERR_DROP, "CG_ProcessSnapshots: cg.snap == NULL");
}
if (cg.time < cg.snap->serverTime) {
// this can happen right after a vid_restart
cg.time = cg.snap->serverTime;
cgi.SetTime(cg.time);
}
if (cg.nextSnap != NULL && cg.nextSnap->serverTime <= cg.time) {
cgi.Error(ERR_DROP,
"CG_ProcessSnapshots: cg.nextSnap->serverTime <= cg.time");
}
}
@@ -1,6 +1,6 @@
/*
===========================================================================
Copyright (C) 2015 the OpenMoHAA team
Copyright (C) 2023 the OpenMoHAA team
This file is part of OpenMoHAA source code.
@@ -20,25 +20,20 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
typedef struct UColor_s {
float r;
float g;
float b;
float a;
} UColor;
// DESCRIPTION:
// Sound function
typedef struct UColorHSV_s {
float h;
float s;
float v;
float a;
} UColorHSV;
#include "cg_local.h"
typedef enum { DARK, REALLYDARK, LIGHT, NORMAL } colorType_t;
typedef struct UBorderColor_s {
UColor dark;
UColor reallydark;
UColor light;
UColor original;
} UBorderColor;
void CG_ProcessSound( server_sound_t *sound )
{
if ( sound->stop_flag )
{
cgi.S_StopSound( sound->entity_number, sound->channel );
}
else
{
cgi.S_StartSound( sound->origin, sound->entity_number, sound->channel, cgs.sound_precache[sound->sound_index],
sound->volume, sound->min_dist, sound->pitch, sound->maxDist, sound->streamed );
}
}
-234
View File
@@ -1,234 +0,0 @@
/*
===========================================================================
Copyright (C) 2011 su44
This file is part of OpenMoHAA source code.
OpenMoHAA source code is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the License,
or (at your option) any later version.
OpenMoHAA source code is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with OpenMoHAA source code; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
// cg_specialfx.c - MoHAA special effects
#include "cg_local.h"
// MoHAA footstep sounds (from ubersound.scr) :
// snd_step_paper, snd_step_glass, snd_step_wood, snd_step_metal,
// snd_step_grill, snd_step_stone, snd_step_dirt, snd_step_grass,
// snd_step_mud, snd_step_puddle, snd_step_gravel, snd_step_sand,
// snd_step_foliage, snd_step_snow, snd_step_carpet
// BODY MOVEMENT
// snd_step_equipment - (equipment; for walking)
// snd_step_wade - (wade; for when wading through deeper water)
static void CG_FootstepMain(trace_t *trace, int iRunning, int iEquipment) {
char sSoundName[MAX_QPATH] = "snd_step_";
int contents;
int surfaceFlags;
vec3_t pos;
ubersound_t *snd = 0;
if ( !iRunning )
return;
// su44: it seems that trace_t::surfaceFlags
// are not set if trace_t::allsolid == qtrue
if( trace->allsolid == qtrue )
return;
if ( iEquipment ) {
snd = CG_GetUbersound( "snd_step_equipment" );
if (snd)
cgi.S_StartSound( trace->endpos, trace->entityNum, CHAN_ITEM, snd->sfxHandle );
}
surfaceFlags = trace->surfaceFlags;
contents = CG_PointContents(trace->endpos,-1);
if (contents & (CONTENTS_LAVA|CONTENTS_SLIME|CONTENTS_WATER) ) {
// wombat: we test if the water is deep or shallow
VectorCopy( trace->endpos, pos );
pos[2] += 16.0f;
contents = CG_PointContents(pos,-1);
if (contents & (CONTENTS_LAVA|CONTENTS_SLIME|CONTENTS_WATER) )
snd = CG_GetUbersound( "snd_step_wade" );
else
snd = CG_GetUbersound( "snd_step_puddle" );
} else {
if ( surfaceFlags & SURF_PAPER ) {
snd = CG_GetUbersound( "snd_step_paper" );
}
else if ( surfaceFlags & SURF_WOOD ) {
snd = CG_GetUbersound( "snd_step_wood" );
}
else if ( surfaceFlags & SURF_METAL ) {
snd = CG_GetUbersound( "snd_step_metal" );
}
else if ( surfaceFlags & SURF_ROCK ) {
snd = CG_GetUbersound( "snd_step_stone" );
}
else if ( surfaceFlags & SURF_DIRT ) {
snd = CG_GetUbersound( "snd_step_dirt" );
}
else if ( surfaceFlags & SURF_GRILL ) {
snd = CG_GetUbersound( "snd_step_grill" );
}
else if ( surfaceFlags & SURF_GRASS ) {
snd = CG_GetUbersound( "snd_step_grass" );
}
else if ( surfaceFlags & SURF_MUD ) {
snd = CG_GetUbersound( "snd_step_mud" );
}
else if ( surfaceFlags & SURF_PUDDLE ) {
snd = CG_GetUbersound( "snd_step_puddle" );
}
else if ( surfaceFlags & SURF_GLASS ) {
snd = CG_GetUbersound( "snd_step_glass" );
}
else if ( surfaceFlags & SURF_GRAVEL ) {
snd = CG_GetUbersound( "snd_step_gravel" );
}
else if ( surfaceFlags & SURF_SAND ) {
snd = CG_GetUbersound( "snd_step_sand" );
}
else if ( surfaceFlags & SURF_FOLIAGE ) {
snd = CG_GetUbersound( "snd_step_foliage" );
}
else if ( surfaceFlags & SURF_SNOW ) {
snd = CG_GetUbersound( "snd_step_snow" );
}
else if ( surfaceFlags & SURF_CARPET ) {
snd = CG_GetUbersound( "snd_step_carpet" );
}
}
if ( !snd ) {
if(trace->surfaceFlags) {
CG_Printf( "CG_FootstepMain: could not load sound for surface %i\n", trace->surfaceFlags );
}
return;
}
cgi.S_StartSound( trace->endpos, trace->entityNum, CHAN_BODY, snd->sfxHandle );
}
void CG_MeleeImpact(float *vStart, float *vEnd) {
trace_t trace;
float vMins[3] = { -4.0, -4.0, 0 };
float vMaxs[3] = { 4.0, 4.0, 2.0 };
CG_Trace(&trace,vStart,vMins,vMaxs,vEnd,1023,MASK_SHOT);
if(trace.fraction != 1.f) {
CG_FootstepMain(&trace,1,0);
}
}
void CG_Footstep(char *szTagName, centity_t *ent, /*refEntity_t *pREnt,*/
int iRunning, int iEquipment)
{
int mask;
int cylinder;
int cliptoentities;
trace_t trace;
vec3_t mins, maxs;
vec3_t vStart, vEnd, forward;
// CG_Printf("CG_Footstep: %s\n",szTagName);
vStart[0] = ent->lerpOrigin[0];
vStart[1] = ent->lerpOrigin[1];
vStart[2] = ent->lerpOrigin[2] + 8.0;
if ( szTagName ) {
tiki_t *tiki;
int boneName;
int tagIndex;
vec3_t a;
tiki = cgs.gameTIKIs[ent->currentState.modelindex];
if(tiki == 0) {
CG_Printf("CG_Footstep: tiki is NULL\n");
return;
}
// find tag in tiki
boneName = cgi.TIKI_GetBoneNameIndex(szTagName);
for(tagIndex = 0; tagIndex < tiki->numBones; tagIndex++) {
if(tiki->boneNames[tagIndex] == boneName) {
break;
}
}
if(tagIndex == tiki->numBones) {
CG_Printf("CG_Footstep: Cant find bone %s in tiki %s f\n",szTagName,tiki->name);
return;
}
if(ent->bones == 0) {
CG_Printf("CG_Footstep: entity has null bones ptr\n");
return;
}
CG_CentBoneIndexLocal2World(tagIndex, ent, vStart, a);
vStart[2] += 8;
}
if ( iRunning == -1 ) {
AngleVectors(ent->lerpAngles, forward, 0, 0);
vStart[0] = forward[0] * -16.0 + vStart[0];
vStart[1] = forward[1] * -16.0 + vStart[1];
vStart[2] = forward[2] * -16.0 + vStart[2];
vEnd[0] = forward[0] * 64.0 + vStart[0];
vEnd[1] = forward[1] * 64.0 + vStart[1];
vEnd[2] = forward[2] * 64.0 + vStart[2];
mins[0] = -2.0;
mins[1] = -2.0;
mins[2] = -8.0;
maxs[0] = 2.0;
maxs[1] = 2.0;
maxs[2] = 8.0;
} else {
vEnd[0] = vStart[0];
vEnd[1] = vStart[1];
vStart[2] = vStart[2] + 16.0;
vEnd[2] = vStart[2] - 64.0;
mins[0] = -4.0;
mins[1] = -4.0;
mins[2] = 0.0;
maxs[0] = 4.0;
maxs[1] = 4.0;
maxs[2] = 2.0;
}
if ( ent->currentState.eType == ET_PLAYER ) {
cliptoentities = 1;
cylinder = 1;
mask = MASK_TREADMARK;
} else {
cliptoentities = 0;
cylinder = 0;
mask = MASK_FOOTSTEP;
}
CG_Trace(&trace, vStart, mins, maxs, vEnd,
ent->currentState.number, mask/*, cylinder, cliptoentities*/);
if ( trace.fraction != 1.0 ) {
int equip;
if (rand() > RAND_MAX*0.70)
equip = qtrue; // play only in 30% of cases
else equip = qfalse;
CG_FootstepMain(&trace, iRunning, equip);
} else {
//if ( cg_debugFootsteps.integer )
// CG_Printf("Footstep: missed floor\n");
}
}
File diff suppressed because it is too large. Load diff
+83
View File
@@ -0,0 +1,83 @@
/*
===========================================================================
Copyright (C) 2023 the OpenMoHAA team
This file is part of OpenMoHAA source code.
OpenMoHAA source code is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the License,
or (at your option) any later version.
OpenMoHAA source code is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with OpenMoHAA source code; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
// DESCRIPTION:
// Special Effects code
#pragma once
#include "cg_local.h"
#include "cg_commands.h"
#include "class.h"
#define MAX_SPECIAL_EFFECT_COMMANDS 32
class specialeffectcommand_t : public Class {
public:
spawnthing_t* emitter;
float fCommandTime;
void (*endfcn)();
Event *pEvent;
public:
specialeffectcommand_t();
};
class specialeffect_t : public Class
{
public:
int m_iCommandCount;
specialeffectcommand_t* m_commands[MAX_SPECIAL_EFFECT_COMMANDS];
public:
specialeffect_t();
specialeffectcommand_t* AddNewCommand();
};
#define MAX_SPECIAL_EFFECTS 99
#define SPECIAL_EFFECT_TEST MAX_SPECIAL_EFFECTS - 1
class ClientSpecialEffectsManager : public Listener {
specialeffect_t m_effects[99];
qboolean m_bEffectsLoaded;
int m_iNumPendingEvents;
public:
CLASS_PROTOTYPE(ClientSpecialEffectsManager);
private:
void ContinueEffectExecution(Event* ev);
void ExecuteEffect(int iEffect, int iStartCommand, Vector vPos, Vector vAngles, float axis[3][3]);
public:
ClientSpecialEffectsManager();
void LoadEffects();
qboolean EffectsPending();
void MakeEffect_Normal(int iEffect, Vector vPos, Vector vNormal);
void MakeEffect_Angles(int iEffect, Vector vPos, Vector vAngles);
void MakeEffect_Axis(int iEffect, Vector vPos, float axis[3][3]);
specialeffect_t* GetTestEffectPointer();
};
extern ClientSpecialEffectsManager sfxManager;
+289
View File
@@ -0,0 +1,289 @@
/*
===========================================================================
Copyright (C) 2023 the OpenMoHAA team
This file is part of OpenMoHAA source code.
OpenMoHAA source code is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the License,
or (at your option) any later version.
OpenMoHAA source code is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with OpenMoHAA source code; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
// DESCRIPTION:
// General swiping functions
#include "cg_commands.h"
swipething_t m_swipes[MAX_SWIPES];
extern int current_entity_number;
extern refEntity_t *current_entity;
extern dtiki_t* current_tiki;
extern centity_t *current_centity;
void ClientGameCommandManager::SwipeOn
(
Event *ev
)
{
// Make a swipe for this if available
int i;
int freeswipe = -1;
str tagname_start,tagname_end;
qhandle_t shader;
if ( ev->NumArgs () != 4 )
return;
shader = cgi.R_RegisterShader( ev->GetString( 1 ) );
tagname_start = ev->GetString( 2 );
tagname_end = ev->GetString( 3 );
for ( i=0; i < MAX_SWIPES; i++ )
{
swipething_t &swipe = m_swipes[i];
if ( !swipe.enabled ||
(
( swipe.entitynum == current_entity_number ) &&
( tagname_start == swipe.tagname_start ) &&
( tagname_end == swipe.tagname_end ) &&
( shader == swipe.shader )
)
)
{
freeswipe = i;
break;
}
}
if ( freeswipe == -1 )
return;
swipething_t &swipe = m_swipes[freeswipe];
if ( !swipe.enabled )
{
swipe.Init ();
swipe.enabled = qtrue;
swipe.entitynum = current_entity_number;
}
swipe.shader = cgi.R_RegisterShader( ev->GetString( 1 ) );
swipe.tagname_start = ev->GetString ( 2 );
swipe.tagname_end = ev->GetString ( 3 );
swipe.life = ev->GetFloat ( 4 ) * 1000.f;
if ( current_centity )
current_centity->clientFlags |= CF_UPDATESWIPE;
}
void ClientGameCommandManager::SwipeOff
(
Event *ev
)
{
qboolean was_enabled;
int i;
was_enabled = qfalse;
for ( i=0; i < MAX_SWIPES; i++ )
{
swipething_t &swipe = m_swipes[i];
if ( swipe.enabled && swipe.entitynum == current_entity_number )
{
swipe.enabled = qfalse;
was_enabled = qtrue;
}
}
if ( was_enabled )
{
//cgi.R_SwipeBegin ( 0.f, 0.f, -1 );
//cgi.R_SwipeEnd ();
if ( current_centity )
current_centity->clientFlags &= ~CF_UPDATESWIPE;
}
}
void ClientGameCommandManager::Swipe
(
Event *ev
)
{
// This does a swipe effect on the entity
int i,swipenum;
orientation_t _or;
int tagnum_start,tagnum_end;
qboolean add_cnt_point = qfalse;
vec3_t tmp;
assert(current_entity);
assert(current_tiki);
if (!current_entity || !current_tiki)
{
return;
}
// Let's find us a new (or current) swipe
for ( swipenum=0; swipenum < MAX_SWIPES; swipenum++ )
{
swipething_t &swipe = m_swipes[swipenum];
if ( swipe.enabled && swipe.entitynum == current_entity_number )
{
while ( swipe.num_live_swipes > 1 )
{
i = ( swipe.first_swipe + 1 ) % MAX_SWIPE_POINTS;
swipepoint_t &swipepoint = swipe.swipepoints[i];
if ( swipepoint.time < cg.time - swipe.life )
{
// then let's delete the previous
swipe.first_swipe = ( swipe.first_swipe + 1 ) % MAX_SWIPE_POINTS;
swipe.num_live_swipes--;
}
else
{
break;
}
}
if ( swipe.num_live_swipes == 1 )
{
swipepoint_t &swipepoint = swipe.swipepoints[swipe.first_swipe];
if ( swipepoint.time < cg.time - swipe.life )
{
swipe.num_live_swipes = 0;
}
}
swipe.cntPoint.time = cg.time;
VectorCopy ( current_entity->origin, swipe.cntPoint.points[0] );
tagnum_start = cgi.Tag_NumForName( current_tiki, swipe.tagname_start.c_str() );
_or = cgi.TIKI_Orientation(current_entity, tagnum_start);
// Clear out the points
VectorClear ( tmp );
VectorClear ( swipe.cntPoint.points[0] );
VectorClear ( swipe.cntPoint.points[1] );
if ( ev->NumArgs() > 0 )
VectorCopy( ev->GetVector( 1 ), tmp );
else
VectorCopy ( current_entity->origin, tmp );
// Transform the origin of the tag by the axis of the entity and add it to the origin of the entity
for ( i = 0; i < 3; i++ )
{
VectorMA ( tmp, _or.origin[i], current_entity->axis[i], tmp );
}
// Copy tmp into the startpoint
VectorCopy ( tmp, swipe.cntPoint.points[0] );
tagnum_end = cgi.Tag_NumForName( current_tiki, swipe.tagname_end.c_str() );
_or = cgi.TIKI_Orientation(current_entity, tagnum_end);
if ( ev->NumArgs() > 0 )
VectorCopy( ev->GetVector( 1 ), tmp );
else
VectorCopy ( current_entity->origin, tmp );
// Transform the origin of the tag by the axis of the entity and add it to the origin of the entity
for ( i = 0; i < 3; i++ )
{
VectorMA ( tmp, _or.origin[i], current_entity->axis[i], tmp );
}
// Copy tmp into the startpoint
VectorCopy ( tmp, swipe.cntPoint.points[1] );
if ( swipe.num_live_swipes == 0 )
add_cnt_point = qtrue;
else
{
float deltime = swipe.life / float ( MAX_SWIPES );
swipepoint_t &lastpoint = swipe.swipepoints[ ( swipe.first_swipe + swipe.num_live_swipes - 1 ) % MAX_SWIPE_POINTS];
if ( swipe.cntPoint.time - lastpoint.time >= deltime )
add_cnt_point = qtrue;
}
cgi.R_SwipeBegin ( cg.time, swipe.life, swipe.shader );
if ( add_cnt_point )
{
swipepoint_t &swipepoint = swipe.swipepoints[ ( swipe.first_swipe + swipe.num_live_swipes ) % MAX_SWIPE_POINTS];
swipepoint = swipe.cntPoint;
if ( swipe.num_live_swipes == MAX_SWIPE_POINTS )
swipe.first_swipe = ( swipe.first_swipe + 1 ) % MAX_SWIPE_POINTS;
else
swipe.num_live_swipes++;
}
for ( i = 0; i != swipe.num_live_swipes; i++ )
{
swipepoint_t &swipepoint = swipe.swipepoints[ ( swipe.first_swipe + i ) % MAX_SWIPE_POINTS];
cgi.R_SwipePoint ( swipepoint.points[0], swipepoint.points[1], swipepoint.time );
}
if ( !add_cnt_point )
cgi.R_SwipePoint ( swipe.cntPoint.points[0], swipe.cntPoint.points[1], swipe.cntPoint.time );
cgi.R_SwipeEnd ();
}
}
}
void ClientGameCommandManager::ClearSwipes
(
void
)
{
int i;
for ( i=0; i < MAX_SWIPES; i++ )
{
swipething_t &swipe = m_swipes[i];
swipe.enabled = qfalse;
}
cgi.R_SwipeBegin ( 0.f, 0.f, -1 );
cgi.R_SwipeEnd ();
}
/*
===================
CG_ClearSwipes
This is called at startup and for tournement restarts
===================
*/
void CG_ClearSwipes( void )
{
commandManager.ClearSwipes();
}
@@ -1,6 +1,6 @@
/*
===========================================================================
Copyright (C) 2015 the OpenMoHAA team
Copyright (C) 2023 the OpenMoHAA team
This file is part of OpenMoHAA source code.
@@ -20,7 +20,5 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
typedef struct UIPoint2D_s {
float x;
float y;
} UIPoint2D;
// DESCRIPTION:
// Temporary models effects
+484
View File
@@ -0,0 +1,484 @@
/*
===========================================================================
Copyright (C) 2023 the OpenMoHAA team
This file is part of OpenMoHAA source code.
OpenMoHAA source code is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the License,
or (at your option) any later version.
OpenMoHAA source code is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with OpenMoHAA source code; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
// DESCRIPTION:
// testemitter functions. Used for designing emitters in game
#include "cg_commands.h"
#include "cg_specialfx.h"
cvar_t* cg_te_alpha;
cvar_t* cg_te_dietouch;
cvar_t* cg_te_bouncefactor;
cvar_t* cg_te_scale;
cvar_t* cg_te_scalemin;
cvar_t* cg_te_scalemax;
cvar_t* cg_te_model;
cvar_t* cg_te_life;
cvar_t* cg_te_color_r;
cvar_t* cg_te_color_g;
cvar_t* cg_te_color_b;
cvar_t* cg_te_accel_x;
cvar_t* cg_te_accel_y;
cvar_t* cg_te_accel_z;
cvar_t* cg_te_count;
cvar_t* cg_te_fade;
cvar_t* cg_te_fadedelay;
cvar_t* cg_te_fadein;
cvar_t* cg_te_spawnrate;
cvar_t* cg_te_offsbase_x;
cvar_t* cg_te_offsbase_y;
cvar_t* cg_te_offsbase_z;
cvar_t* cg_te_offsamp_x;
cvar_t* cg_te_offsamp_y;
cvar_t* cg_te_offsamp_z;
cvar_t* cg_te_scalerate;
cvar_t* cg_te_circle;
cvar_t* cg_te_sphere;
cvar_t* cg_te_insphere;
cvar_t* cg_te_radius;
cvar_t* cg_te_align;
cvar_t* cg_te_flickeralpha;
cvar_t* cg_te_collision;
cvar_t* cg_te_randomroll;
cvar_t* cg_te_anglesbase_p;
cvar_t* cg_te_anglesbase_y;
cvar_t* cg_te_anglesbase_r;
cvar_t* cg_te_anglesamp_p;
cvar_t* cg_te_anglesamp_y;
cvar_t* cg_te_anglesamp_r;
cvar_t* cg_te_forwardvel;
cvar_t* cg_te_randvelbase_x;
cvar_t* cg_te_randvelbase_y;
cvar_t* cg_te_randvelbase_z;
cvar_t* cg_te_randvelamp_x;
cvar_t* cg_te_randvelamp_y;
cvar_t* cg_te_randvelamp_z;
cvar_t* cg_te_clampvelmin_x;
cvar_t* cg_te_clampvelmax_x;
cvar_t* cg_te_clampvelmin_y;
cvar_t* cg_te_clampvelmax_y;
cvar_t* cg_te_clampvelmin_z;
cvar_t* cg_te_clampvelmax_z;
cvar_t* cg_te_clampvelaxis;
cvar_t* cg_te_volumetric;
cvar_t* cg_te_randaxis;
cvar_t* cg_te_axisoffsbase_x;
cvar_t* cg_te_axisoffsbase_y;
cvar_t* cg_te_axisoffsbase_z;
cvar_t* cg_te_axisoffsamp_x;
cvar_t* cg_te_axisoffsamp_y;
cvar_t* cg_te_axisoffsamp_z;
cvar_t* cg_te_swarm_freq;
cvar_t* cg_te_swarm_maxspeed;
cvar_t* cg_te_swarm_delta;
cvar_t* cg_te_avelbase_p;
cvar_t* cg_te_avelbase_y;
cvar_t* cg_te_avelbase_r;
cvar_t* cg_te_avelamp_p;
cvar_t* cg_te_avelamp_y;
cvar_t* cg_te_avelamp_r;
cvar_t* cg_te_radial_scale;
cvar_t* cg_te_radial_min;
cvar_t* cg_te_radial_max;
cvar_t* cg_te_friction;
cvar_t* cg_te_varycolor;
cvar_t* cg_te_spritegridlighting;
cvar_t* cg_te_cone_height;
cvar_t* cg_te_alignstretch_scale;
cvar_t* cg_te_spawnrange_a;
cvar_t* cg_te_spawnrange_b;
cvar_t* cg_te_command_time;
cvar_t* cg_te_singlelinecommand;
cvar_t* cg_te_tag;
cvar_t* cg_te_xangles;
cvar_t* cg_te_yangles;
cvar_t* cg_te_zangles;
class specialeffect_t;
refEntity_t te_refEnt;
cvar_t* cg_te_emittermodel;
cvar_t* cg_te_mode;
cvar_t* cg_te_mode_name;
cvar_t* cg_te_currCommand;
cvar_t* cg_te_numCommands;
float te_vEmitterOrigin[3];
int te_iNumCommands;
int te_iCurrCommand;
specialeffect_t *pTesteffect;
#define MAX_TESTEMITTERS_SAVE 32
str cg_te_alphaG[MAX_TESTEMITTERS_SAVE];
str cg_te_dietouchG[MAX_TESTEMITTERS_SAVE];
str cg_te_bouncefactorG[MAX_TESTEMITTERS_SAVE];
str cg_te_scaleG[MAX_TESTEMITTERS_SAVE];
str cg_te_scaleminG[MAX_TESTEMITTERS_SAVE];
str cg_te_scalemaxG[MAX_TESTEMITTERS_SAVE];
str cg_te_modelG[MAX_TESTEMITTERS_SAVE];
str cg_te_lifeG[MAX_TESTEMITTERS_SAVE];
str cg_te_color_rG[MAX_TESTEMITTERS_SAVE];
str cg_te_color_gG[MAX_TESTEMITTERS_SAVE];
str cg_te_color_bG[MAX_TESTEMITTERS_SAVE];
str cg_te_accel_xG[MAX_TESTEMITTERS_SAVE];
str cg_te_accel_yG[MAX_TESTEMITTERS_SAVE];
str cg_te_accel_zG[MAX_TESTEMITTERS_SAVE];
str cg_te_countG[MAX_TESTEMITTERS_SAVE];
str cg_te_fadeG[MAX_TESTEMITTERS_SAVE];
str cg_te_fadedelayG[MAX_TESTEMITTERS_SAVE];
str cg_te_fadeinG[MAX_TESTEMITTERS_SAVE];
str cg_te_spawnrateG[MAX_TESTEMITTERS_SAVE];
str cg_te_offsbase_xG[MAX_TESTEMITTERS_SAVE];
str cg_te_offsbase_yG[MAX_TESTEMITTERS_SAVE];
str cg_te_offsbase_zG[MAX_TESTEMITTERS_SAVE];
str cg_te_offsamp_xG[MAX_TESTEMITTERS_SAVE];
str cg_te_offsamp_yG[MAX_TESTEMITTERS_SAVE];
str cg_te_offsamp_zG[MAX_TESTEMITTERS_SAVE];
str cg_te_scalerateG[MAX_TESTEMITTERS_SAVE];
str cg_te_circleG[MAX_TESTEMITTERS_SAVE];
str cg_te_sphereG[MAX_TESTEMITTERS_SAVE];
str cg_te_insphereG[MAX_TESTEMITTERS_SAVE];
str cg_te_radiusG[MAX_TESTEMITTERS_SAVE];
str cg_te_alignG[MAX_TESTEMITTERS_SAVE];
str cg_te_flickeralphaG[MAX_TESTEMITTERS_SAVE];
str cg_te_collisionG[MAX_TESTEMITTERS_SAVE];
str cg_te_randomrollG[MAX_TESTEMITTERS_SAVE];
str cg_te_anglesbase_pG[MAX_TESTEMITTERS_SAVE];
str cg_te_anglesbase_yG[MAX_TESTEMITTERS_SAVE];
str cg_te_anglesbase_rG[MAX_TESTEMITTERS_SAVE];
str cg_te_anglesamp_pG[MAX_TESTEMITTERS_SAVE];
str cg_te_anglesamp_yG[MAX_TESTEMITTERS_SAVE];
str cg_te_anglesamp_rG[MAX_TESTEMITTERS_SAVE];
str cg_te_forwardvelG[MAX_TESTEMITTERS_SAVE];
str cg_te_randvelbase_xG[MAX_TESTEMITTERS_SAVE];
str cg_te_randvelbase_yG[MAX_TESTEMITTERS_SAVE];
str cg_te_randvelbase_zG[MAX_TESTEMITTERS_SAVE];
str cg_te_randvelamp_xG[MAX_TESTEMITTERS_SAVE];
str cg_te_randvelamp_yG[MAX_TESTEMITTERS_SAVE];
str cg_te_randvelamp_zG[MAX_TESTEMITTERS_SAVE];
str cg_te_clampvelmin_xG[MAX_TESTEMITTERS_SAVE];
str cg_te_clampvelmax_xG[MAX_TESTEMITTERS_SAVE];
str cg_te_clampvelmin_yG[MAX_TESTEMITTERS_SAVE];
str cg_te_clampvelmax_yG[MAX_TESTEMITTERS_SAVE];
str cg_te_clampvelmin_zG[MAX_TESTEMITTERS_SAVE];
str cg_te_clampvelmax_zG[MAX_TESTEMITTERS_SAVE];
str cg_te_clampvelaxisG[MAX_TESTEMITTERS_SAVE];
str cg_te_volumetricG[MAX_TESTEMITTERS_SAVE];
str cg_te_randaxisG[MAX_TESTEMITTERS_SAVE];
str cg_te_axisoffsbase_xG[MAX_TESTEMITTERS_SAVE];
str cg_te_axisoffsbase_yG[MAX_TESTEMITTERS_SAVE];
str cg_te_axisoffsbase_zG[MAX_TESTEMITTERS_SAVE];
str cg_te_axisoffsamp_xG[MAX_TESTEMITTERS_SAVE];
str cg_te_axisoffsamp_yG[MAX_TESTEMITTERS_SAVE];
str cg_te_axisoffsamp_zG[MAX_TESTEMITTERS_SAVE];
str cg_te_swarm_freqG[MAX_TESTEMITTERS_SAVE];
str cg_te_swarm_maxspeedG[MAX_TESTEMITTERS_SAVE];
str cg_te_swarm_deltaG[MAX_TESTEMITTERS_SAVE];
str cg_te_avelbase_pG[MAX_TESTEMITTERS_SAVE];
str cg_te_avelbase_yG[MAX_TESTEMITTERS_SAVE];
str cg_te_avelbase_rG[MAX_TESTEMITTERS_SAVE];
str cg_te_avelamp_pG[MAX_TESTEMITTERS_SAVE];
str cg_te_avelamp_yG[MAX_TESTEMITTERS_SAVE];
str cg_te_avelamp_rG[MAX_TESTEMITTERS_SAVE];
str cg_te_radial_scaleG[MAX_TESTEMITTERS_SAVE];
str cg_te_radial_minG[MAX_TESTEMITTERS_SAVE];
str cg_te_radial_maxG[MAX_TESTEMITTERS_SAVE];
str cg_te_frictionG[MAX_TESTEMITTERS_SAVE];
str cg_te_varycolorG[MAX_TESTEMITTERS_SAVE];
str cg_te_spritegridlightingG[MAX_TESTEMITTERS_SAVE];
str cg_te_spawnrange_aG[MAX_TESTEMITTERS_SAVE];
str cg_te_spawnrange_bG[MAX_TESTEMITTERS_SAVE];
str cg_te_cone_heightG[MAX_TESTEMITTERS_SAVE];
str cg_te_alignstretch_scaleG[MAX_TESTEMITTERS_SAVE];
str cg_te_command_timeG[MAX_TESTEMITTERS_SAVE];
str cg_te_singlelinecommandG[MAX_TESTEMITTERS_SAVE];
str cg_te_tagG[MAX_TESTEMITTERS_SAVE];
spawnthing_t* testspawnthing = NULL;
void CG_SaveEffectCommandCvars(int iCommand)
{
cg_te_alphaG[iCommand] = cg_te_alpha->string;
cg_te_dietouchG[iCommand] = cg_te_dietouch->string;
cg_te_bouncefactorG[iCommand] = cg_te_bouncefactor->string;
cg_te_scaleG[iCommand] = cg_te_scale->string;
cg_te_scaleminG[iCommand] = cg_te_scalemin->string;
cg_te_scalemaxG[iCommand] = cg_te_scalemax->string;
cg_te_modelG[iCommand] = cg_te_model->string;
cg_te_lifeG[iCommand] = cg_te_life->string;
cg_te_color_rG[iCommand] = cg_te_color_r->string;
cg_te_color_gG[iCommand] = cg_te_color_g->string;
cg_te_color_bG[iCommand] = cg_te_color_b->string;
cg_te_accel_xG[iCommand] = cg_te_accel_x->string;
cg_te_accel_yG[iCommand] = cg_te_accel_y->string;
cg_te_accel_zG[iCommand] = cg_te_accel_z->string;
cg_te_countG[iCommand] = cg_te_count->string;
cg_te_fadeG[iCommand] = cg_te_fade->string;
cg_te_fadedelayG[iCommand] = cg_te_fadedelay->string;
cg_te_fadeinG[iCommand] = cg_te_fadein->string;
cg_te_spawnrateG[iCommand] = cg_te_spawnrate->string;
cg_te_offsbase_xG[iCommand] = cg_te_offsbase_x->string;
cg_te_offsbase_yG[iCommand] = cg_te_offsbase_y->string;
cg_te_offsbase_zG[iCommand] = cg_te_offsbase_z->string;
cg_te_offsamp_xG[iCommand] = cg_te_offsamp_x->string;
cg_te_offsamp_yG[iCommand] = cg_te_offsamp_y->string;
cg_te_offsamp_zG[iCommand] = cg_te_offsamp_z->string;
cg_te_scalerateG[iCommand] = cg_te_scalerate->string;
cg_te_circleG[iCommand] = cg_te_circle->string;
cg_te_sphereG[iCommand] = cg_te_sphere->string;
cg_te_insphereG[iCommand] = cg_te_insphere->string;
cg_te_radiusG[iCommand] = cg_te_radius->string;
cg_te_alignG[iCommand] = cg_te_align->string;
cg_te_flickeralphaG[iCommand] = cg_te_flickeralpha->string;
cg_te_collisionG[iCommand] = cg_te_collision->string;
cg_te_randomrollG[iCommand] = cg_te_randomroll->string;
cg_te_anglesbase_pG[iCommand] = cg_te_anglesbase_p->string;
cg_te_anglesbase_yG[iCommand] = cg_te_anglesbase_y->string;
cg_te_anglesbase_rG[iCommand] = cg_te_anglesbase_r->string;
cg_te_anglesamp_pG[iCommand] = cg_te_anglesamp_p->string;
cg_te_anglesamp_yG[iCommand] = cg_te_anglesamp_y->string;
cg_te_anglesamp_rG[iCommand] = cg_te_anglesamp_r->string;
cg_te_forwardvelG[iCommand] = cg_te_forwardvel->string;
cg_te_randvelbase_xG[iCommand] = cg_te_randvelbase_x->string;
cg_te_randvelbase_yG[iCommand] = cg_te_randvelbase_y->string;
cg_te_randvelbase_zG[iCommand] = cg_te_randvelbase_z->string;
cg_te_randvelamp_xG[iCommand] = cg_te_randvelamp_x->string;
cg_te_randvelamp_yG[iCommand] = cg_te_randvelamp_y->string;
cg_te_randvelamp_zG[iCommand] = cg_te_randvelamp_z->string;
cg_te_clampvelmin_xG[iCommand] = cg_te_clampvelmin_x->string;
cg_te_clampvelmax_xG[iCommand] = cg_te_clampvelmax_x->string;
cg_te_clampvelmin_yG[iCommand] = cg_te_clampvelmin_y->string;
cg_te_clampvelmax_yG[iCommand] = cg_te_clampvelmax_y->string;
cg_te_clampvelmin_zG[iCommand] = cg_te_clampvelmin_z->string;
cg_te_clampvelmax_zG[iCommand] = cg_te_clampvelmax_z->string;
cg_te_clampvelaxisG[iCommand] = cg_te_clampvelaxis->string;
cg_te_volumetricG[iCommand] = cg_te_volumetric->string;
cg_te_randaxisG[iCommand] = cg_te_randaxis->string;
cg_te_axisoffsbase_xG[iCommand] = cg_te_axisoffsbase_x->string;
cg_te_axisoffsbase_yG[iCommand] = cg_te_axisoffsbase_y->string;
cg_te_axisoffsbase_zG[iCommand] = cg_te_axisoffsbase_z->string;
cg_te_axisoffsamp_xG[iCommand] = cg_te_axisoffsamp_x->string;
cg_te_axisoffsamp_yG[iCommand] = cg_te_axisoffsamp_y->string;
cg_te_axisoffsamp_zG[iCommand] = cg_te_axisoffsamp_z->string;
cg_te_swarm_freqG[iCommand] = cg_te_swarm_freq->string;
cg_te_swarm_maxspeedG[iCommand] = cg_te_swarm_maxspeed->string;
cg_te_swarm_deltaG[iCommand] = cg_te_swarm_delta->string;
cg_te_avelbase_pG[iCommand] = cg_te_avelbase_p->string;
cg_te_avelbase_yG[iCommand] = cg_te_avelbase_y->string;
cg_te_avelbase_rG[iCommand] = cg_te_avelbase_r->string;
cg_te_avelamp_pG[iCommand] = cg_te_avelamp_p->string;
cg_te_avelamp_yG[iCommand] = cg_te_avelamp_y->string;
cg_te_avelamp_rG[iCommand] = cg_te_avelamp_r->string;
cg_te_radial_scaleG[iCommand] = cg_te_radial_scale->string;
cg_te_radial_minG[iCommand] = cg_te_radial_min->string;
cg_te_radial_maxG[iCommand] = cg_te_radial_max->string;
cg_te_frictionG[iCommand] = cg_te_friction->string;
cg_te_varycolorG[iCommand] = cg_te_varycolor->string;
cg_te_spritegridlightingG[iCommand] = cg_te_spritegridlighting->string;
cg_te_spawnrange_aG[iCommand] = cg_te_spawnrange_a->string;
cg_te_spawnrange_bG[iCommand] = cg_te_spawnrange_b->string;
cg_te_cone_heightG[iCommand] = cg_te_cone_height->string;
cg_te_alignstretch_scaleG[iCommand] = cg_te_alignstretch_scale->string;
cg_te_command_timeG[iCommand] = cg_te_command_time->string;
cg_te_singlelinecommandG[iCommand] = cg_te_singlelinecommand->string;
cg_te_tagG[iCommand] = cg_te_tag->string;
}
void CG_ResetEffectCommandCvars()
{
// FIXME: unimplemented
}
void CG_SetTestEmitterValues()
{
// FIXME: unimplemented
}
void CG_UpdateTestEmitter(void)
{
// FIXME: unimplemented
}
void CG_SortEffectCommands()
{
// FIXME: unimplemented
}
void CG_TriggerTestEmitter_f(void)
{
// FIXME: unimplemented
}
void CG_DumpBaseAndAmplitude(str* buff, char* prefix, Vector* base, Vector* amplitude)
{
// FIXME: unimplemented
}
void CG_DumpEmitter_f(void)
{
// FIXME: unimplemented
}
void CG_LoadBaseAndAmplitude(char** pBufer, char* szCvarX, char* szCvarY, char* szCvarZ, char* szCvarXAmp, char* szCvarYAmp, char* szCvarZAmp)
{
// FIXME: unimplemented
}
void CG_LoadEmitter_f(void)
{
// FIXME: unimplemented
}
void CG_TestEmitter_f(void)
{
// FIXME: unimplemented
}
void CG_PrevEmitterCommand_f(void)
{
// FIXME: unimplemented
}
void CG_NextEmitterCommand_f(void)
{
// FIXME: unimplemented
}
void CG_NewEmitterCommand_f(void)
{
// FIXME: unimplemented
}
void CG_DeleteEmitterCommand_f(void)
{
// FIXME: unimplemented
}
void CG_InitTestEmitter(void)
{
cg_te_life = cgi.Cvar_Get("cg_te_life", "1", 0);
cg_te_alpha = cgi.Cvar_Get("cg_te_alpha", "1", 0);
cg_te_dietouch = cgi.Cvar_Get("cg_te_dietouch", "0", 0);
cg_te_bouncefactor = cgi.Cvar_Get("cg_te_bouncefactor", "0.3", 0);
cg_te_scale = cgi.Cvar_Get("cg_te_scale", "1", 0);
cg_te_scalemin = cgi.Cvar_Get("cg_te_scalemin", "0", 0);
cg_te_scalemax = cgi.Cvar_Get("cg_te_scalemax", "0", 0);
cg_te_model = cgi.Cvar_Get("cg_te_model", "none", 0);
cg_te_life = cgi.Cvar_Get("cg_te_life", "1", 0);
cg_te_color_r = cgi.Cvar_Get("cg_te_color_r", "1", 0);
cg_te_color_g = cgi.Cvar_Get("cg_te_color_g", "1", 0);
cg_te_color_b = cgi.Cvar_Get("cg_te_color_b", "1", 0);
cg_te_accel_x = cgi.Cvar_Get("cg_te_accel_x", "0", 0);
cg_te_accel_y = cgi.Cvar_Get("cg_te_accel_y", "0", 0);
cg_te_accel_z = cgi.Cvar_Get("cg_te_accel_z", "0", 0);
cg_te_count = cgi.Cvar_Get("cg_te_count", "1", 0);
cg_te_fade = cgi.Cvar_Get("cg_te_fade", "0", 0);
cg_te_fadedelay = cgi.Cvar_Get("cg_te_fadedelay", "0", 0);
cg_te_fadein = cgi.Cvar_Get("cg_te_fadein", "0", 0);
cg_te_spawnrate = cgi.Cvar_Get("cg_te_spawnrate", "1", 0);
cg_te_scalerate = cgi.Cvar_Get("cg_te_scalerate", "0", 0);
cg_te_circle = cgi.Cvar_Get("cg_te_circle", "0", 0);
cg_te_sphere = cgi.Cvar_Get("cg_te_sphere", "0", 0);
cg_te_insphere = cgi.Cvar_Get("cg_te_insphere", "0", 0);
cg_te_radius = cgi.Cvar_Get("cg_te_radius", "0", 0);
cg_te_align = cgi.Cvar_Get("cg_te_align", "0", 0);
cg_te_flickeralpha = cgi.Cvar_Get("cg_te_flickeralpha", "0", 0);
cg_te_collision = cgi.Cvar_Get("cg_te_collision", "0", 0);
cg_te_randomroll = cgi.Cvar_Get("cg_te_randomroll", "0", 0);
cg_te_offsbase_x = cgi.Cvar_Get("cg_te_offsbase_x", "0", 0);
cg_te_offsbase_y = cgi.Cvar_Get("cg_te_offsbase_y", "0", 0);
cg_te_offsbase_z = cgi.Cvar_Get("cg_te_offsbase_z", "0", 0);
cg_te_offsamp_x = cgi.Cvar_Get("cg_te_offsamp_x", "0", 0);
cg_te_offsamp_y = cgi.Cvar_Get("cg_te_offsamp_y", "0", 0);
cg_te_offsamp_z = cgi.Cvar_Get("cg_te_offsamp_z", "0", 0);
cg_te_anglesbase_p = cgi.Cvar_Get("cg_te_anglesbase_p", "0", 0);
cg_te_anglesbase_y = cgi.Cvar_Get("cg_te_anglesbase_y", "0", 0);
cg_te_anglesbase_r = cgi.Cvar_Get("cg_te_anglesbase_r", "0", 0);
cg_te_anglesamp_p = cgi.Cvar_Get("cg_te_anglesamp_p", "0", 0);
cg_te_anglesamp_y = cgi.Cvar_Get("cg_te_anglesamp_y", "0", 0);
cg_te_anglesamp_r = cgi.Cvar_Get("cg_te_anglesamp_r", "0", 0);
cg_te_randvelbase_x = cgi.Cvar_Get("cg_te_randvelbase_x", "0", 0);
cg_te_randvelbase_y = cgi.Cvar_Get("cg_te_randvelbase_y", "0", 0);
cg_te_randvelbase_z = cgi.Cvar_Get("cg_te_randvelbase_z", "0", 0);
cg_te_randvelamp_x = cgi.Cvar_Get("cg_te_randvelamp_x", "0", 0);
cg_te_randvelamp_y = cgi.Cvar_Get("cg_te_randvelamp_y", "0", 0);
cg_te_randvelamp_z = cgi.Cvar_Get("cg_te_randvelamp_z", "0", 0);
cg_te_clampvelmin_x = cgi.Cvar_Get("cg_te_clampvelmin_x", "-9999", 0);
cg_te_clampvelmax_x = cgi.Cvar_Get("cg_te_clampvelmax_x", "9999", 0);
cg_te_clampvelmin_y = cgi.Cvar_Get("cg_te_clampvelmin_y", "-9999", 0);
cg_te_clampvelmax_y = cgi.Cvar_Get("cg_te_clampvelmax_y", "9999", 0);
cg_te_clampvelmin_z = cgi.Cvar_Get("cg_te_clampvelmin_z", "-9999", 0);
cg_te_clampvelmax_z = cgi.Cvar_Get("cg_te_clampvelmax_z", "9999", 0);
cg_te_clampvelaxis = cgi.Cvar_Get("cg_te_clampvelaxis", "0", 0);
cg_te_forwardvel = cgi.Cvar_Get("cg_te_forwardvel", "0", 0);
cg_te_volumetric = cgi.Cvar_Get("cg_te_volumetric", "0", 0);
cg_te_randaxis = cgi.Cvar_Get("cg_te_randaxis", "0", 0);
cg_te_axisoffsbase_x = cgi.Cvar_Get("cg_te_axisoffsbase_x", "0", 0);
cg_te_axisoffsbase_y = cgi.Cvar_Get("cg_te_axisoffsbase_y", "0", 0);
cg_te_axisoffsbase_z = cgi.Cvar_Get("cg_te_axisoffsbase_z", "0", 0);
cg_te_axisoffsamp_x = cgi.Cvar_Get("cg_te_axisoffsamp_x", "0", 0);
cg_te_axisoffsamp_y = cgi.Cvar_Get("cg_te_axisoffsamp_y", "0", 0);
cg_te_axisoffsamp_z = cgi.Cvar_Get("cg_te_axisoffsamp_z", "0", 0);
cg_te_swarm_freq = cgi.Cvar_Get("cg_te_swarm_freq", "0", 0);
cg_te_swarm_maxspeed = cgi.Cvar_Get("cg_te_swarm_maxspeed", "0", 0);
cg_te_swarm_delta = cgi.Cvar_Get("cg_te_swarm_delta", "0", 0);
cg_te_avelbase_p = cgi.Cvar_Get("cg_te_avelbase_p", "0", 0);
cg_te_avelbase_y = cgi.Cvar_Get("cg_te_avelbase_y", "0", 0);
cg_te_avelbase_r = cgi.Cvar_Get("cg_te_avelbase_r", "0", 0);
cg_te_avelamp_p = cgi.Cvar_Get("cg_te_avelamp_p", "0", 0);
cg_te_avelamp_y = cgi.Cvar_Get("cg_te_avelamp_y", "0", 0);
cg_te_avelamp_r = cgi.Cvar_Get("cg_te_avelamp_r", "0", 0);
cg_te_radial_scale = cgi.Cvar_Get("cg_te_radial_scale", "0", 0);
cg_te_radial_min = cgi.Cvar_Get("cg_te_radial_min", "0", 0);
cg_te_radial_max = cgi.Cvar_Get("cg_te_radial_max", "0", 0);
cg_te_friction = cgi.Cvar_Get("cg_te_friction", "0", 0);
cg_te_varycolor = cgi.Cvar_Get("cg_te_varycolor", "0", 0);
cg_te_spritegridlighting = cgi.Cvar_Get("cg_te_spritegridlighting", "0", 0);
cg_te_spawnrange_a = cgi.Cvar_Get("cg_te_spawnrange_a", "0", 0);
cg_te_spawnrange_b = cgi.Cvar_Get("cg_te_spawnrange_b", "0", 0);
cg_te_cone_height = cgi.Cvar_Get("cg_te_cone_height", "0", 0);
cg_te_alignstretch_scale = cgi.Cvar_Get("cg_te_alignstretch_scale", "0", 0);
cg_te_command_time = cgi.Cvar_Get("cg_te_command_time", "0", 0);
cg_te_singlelinecommand = cgi.Cvar_Get("cg_te_singlelinecommand", "", 0);
cg_te_tag = cgi.Cvar_Get("cg_te_tag", "", 0);
for (int i = 0; i < MAX_TESTEMITTERS_SAVE; ++i) {
CG_SaveEffectCommandCvars(i);
}
cg_te_xangles = cgi.Cvar_Get("cg_te_xangles", "0", 0);
cg_te_yangles = cgi.Cvar_Get("cg_te_yangles", "0", 0);
cg_te_zangles = cgi.Cvar_Get("cg_te_zangles", "0", 0);
cg_te_emittermodel = cgi.Cvar_Get("cg_te_emittermodel", "", 0);
cg_te_mode = cgi.Cvar_Get("cg_te_mode", "0", 0);
cg_te_mode_name = cgi.Cvar_Get("cg_te_mode_name", "Emitter Mode", 0);
cg_te_currCommand = cgi.Cvar_Get("cg_te_currCommand", "0", 0);
te_vEmitterOrigin[2] = 0.0;
te_vEmitterOrigin[1] = 0.0;
te_vEmitterOrigin[0] = 0.0;
te_refEnt.scale = 0.0;
cg_te_numCommands = cgi.Cvar_Get("cg_te_numCommands", "0", 0);
te_iNumCommands = 0;
te_iCurrCommand = 0;
pTesteffect = sfxManager.GetTestEffectPointer();
}
-298
View File
@@ -1,298 +0,0 @@
/*
===========================================================================
Copyright (C) 2010-2011 Michael Rieder
This file is part of OpenMohaa source code.
OpenMohaa source code is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the License,
or (at your option) any later version.
OpenMohaa source code is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with OpenMohaa source code; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
#include "cg_local.h"
#define MAX_UBERSOUNDS 8192
ubersound_t snd_indexes[MAX_UBERSOUNDS];
int snd_numIndexes;
char *buffer;
#define FILE_HASH_SIZE 256
static ubersound_t* hashTable[FILE_HASH_SIZE];
static long generateHashValue( const char *fname ) {
int i;
long hash;
char letter;
hash = 0;
i = 0;
while (fname[i] != '\0') {
letter = tolower(fname[i]);
hash+=(long)(letter)*(i+119);
i++;
}
hash &= (FILE_HASH_SIZE-1);
return hash;
}
static ubersound_t* US_Find( const char *snd_name ) {
ubersound_t* snd;
long hash;
hash = generateHashValue(snd_name);
for (snd=hashTable[hash] ; snd ; snd=snd->hashNext) {
if (!Q_stricmp(snd_name, snd->name)) {
return snd;
}
}
return NULL;
}
ubersound_t* CG_GetUbersound( const char *name ) {
ubersound_t *snd;
snd = US_Find( name );
if ( !snd ) {
CG_Printf( "CG_GetUbersound: sound \"%s\" not found.\n", name );
return NULL;
}
// if there are more than one version, choose randomly
if ( snd->variations ) {
int i, var;
var = rand();
var *= snd->variations;
var /= RAND_MAX+1;
// CG_Printf( "random sound %i of %i\n", var, snd->variations );
for (i=0;i<var;i++)
snd = snd->nextVariation;
}
if ( snd->hasLoaded == qfalse )
snd->sfxHandle = cgi.S_RegisterSound( snd->wavfile, qfalse );
return snd;
}
void CG_ParseUSline( char **ptr, ubersound_t *snd ) {
const char *chan;
const char *token;
// name
Q_strncpyz( snd->name, COM_Parse(ptr), sizeof(snd->name) );
Q_strncpyz( snd->wavfile, COM_Parse(ptr), sizeof(snd->wavfile) );
// soundparms
if ( !Q_strncmp( COM_Parse(ptr), "soundparms", MAX_QPATH ) ) {
snd->basevol = atof(COM_Parse(ptr));
snd->volmod = atof(COM_Parse(ptr));
snd->basepitch = atof(COM_Parse(ptr));
snd->pitchmod = atof(COM_Parse(ptr));
snd->minDist = atof(COM_Parse(ptr));
snd->maxDist = atof(COM_Parse(ptr));
// channel
chan = COM_Parse(ptr);
if ( !Q_strncmp( chan, "auto", MAX_QPATH ) )
snd->channel = CHAN_AUTO;
else if ( !Q_strncmp( chan, "body", MAX_QPATH ) )
snd->channel = CHAN_BODY;
else if ( !Q_strncmp( chan, "item", MAX_QPATH ) )
snd->channel = CHAN_ITEM;
else if ( !Q_strncmp( chan, "weaponidle", MAX_QPATH ) )
snd->channel = CHAN_WEAPONIDLE;
else if ( !Q_strncmp( chan, "voice", MAX_QPATH ) )
snd->channel = CHAN_VOICE;
else if ( !Q_strncmp( chan, "local", MAX_QPATH ) )
snd->channel = CHAN_LOCAL;
else if ( !Q_strncmp( chan, "weapon", MAX_QPATH ) )
snd->channel = CHAN_WEAPON;
else if ( !Q_strncmp( chan, "dialog_secondary", MAX_QPATH ) )
snd->channel = CHAN_DIALOG_SECONDARY;
else if ( !Q_strncmp( chan, "dialog", MAX_QPATH ) )
snd->channel = CHAN_DIALOG;
else if ( !Q_strncmp( chan, "menu", MAX_QPATH ) )
snd->channel = CHAN_MENU;
else
CG_Printf( "Ubersound unrecognized channel %s for %s\n", chan, snd->name );
// loaded /Streamed
chan = COM_Parse(ptr);
if ( !Q_strncmp( chan, "loaded", MAX_QPATH ) )
snd->loaded = qtrue;
else if ( !Q_strncmp( chan, "streamed", MAX_QPATH ) )
snd->loaded = qfalse;
else
CG_Printf( "Ubersound unrecognized loaded state %s for %s\n", chan, snd->name );
}
token = COM_Parse(ptr);
// subtitle - su44: we need this for ubersound/uberdialog.scr loading
if ( !Q_stricmp( token, "subtitle" ) ) {
Q_strncpyz( snd->subtitle, COM_Parse(ptr), sizeof(snd->subtitle) );
token = COM_Parse(ptr);
}
// maplist
if ( !Q_stricmp( token, "maps" ) )
Q_strncpyz( snd->mapstring, COM_Parse(ptr), MAPSTRING_LENGTH );
}
qboolean US_CheckMapstring( const char *mapstring ) {
char *ptr;
const char *token;
ptr = (char*)mapstring;
token = COM_Parse(&ptr);
while (*token) {
if ( strstr( cgs.mapname, token ) )
return qtrue;
token = COM_Parse(&ptr);
}
return qfalse;
}
void CG_LoadUberSoundFile( const char *fname, qboolean sndVar ) {
// sndVar decides whether the last digit (if it is a digit) provides a variation of the same sound
int len;
const char *token;
char *ptr;
qboolean end;
ubersound_t *oldSnd, *newSnd;
int i;
CG_Printf( "=== Loading %s ===\n", fname );
len = cgi.FS_ReadFile( fname, &buffer, qfalse );
if( len <= 0 ) {
CG_Printf( "couldn't load %s. file not found.\n", fname );
return;
}
end = qfalse;
ptr = buffer;
token = COM_Parse( &ptr );
while (*token) {
newSnd = &snd_indexes[snd_numIndexes];
if ( !Q_strncmp(token,"aliascache",MAX_QPATH) || !Q_strncmp(token,"alias",MAX_QPATH) ) {
CG_ParseUSline( &ptr, newSnd );
if ( US_CheckMapstring( newSnd->mapstring ) == qtrue ) {
int variation;
variation = atoi(newSnd->name + strlen(newSnd->name)-1);
if ( sndVar == qtrue && variation ) {
newSnd->name[strlen(newSnd->name)-1] = 0;
oldSnd = US_Find(newSnd->name);
if ( oldSnd ) {
oldSnd->variations++;
for (i=oldSnd->variations;i>2;i--)
oldSnd = oldSnd->nextVariation;
oldSnd->nextVariation = newSnd;
if ( newSnd->loaded == qtrue ) {
newSnd->sfxHandle = cgi.S_RegisterSound( newSnd->wavfile, qfalse );
newSnd->hasLoaded = qtrue;
}
snd_numIndexes++;
if ( snd_numIndexes >= MAX_UBERSOUNDS ) {
snd_numIndexes--;
CG_Error( "CG_LoadUbersound: too many aliascaches in file.\n" );
}
continue;
}
else newSnd->variations++;
}
i = generateHashValue(newSnd->name);
oldSnd = hashTable[i];
if (oldSnd) {
while (oldSnd->hashNext)
oldSnd = oldSnd->hashNext;
oldSnd->hashNext = newSnd;
}
else
hashTable[i] = newSnd;
if ( newSnd->loaded == qtrue ) {
newSnd->sfxHandle = cgi.S_RegisterSound( newSnd->wavfile, qfalse );
newSnd->hasLoaded = qtrue;
}
snd_numIndexes++;
if ( snd_numIndexes >= MAX_UBERSOUNDS ) {
snd_numIndexes--;
CG_Error( "CG_LoadUbersound: too many aliascaches in file.\n" );
}
} else {
Com_Memset(newSnd,0,sizeof(ubersound_t) );
}
} //su44: "end" token is missing in MoHAA's uberdialog.scr
//else if ( !Q_strncmp( token, "end", MAX_QPATH ) ) {
// end = qtrue;
// break;
//}
token = COM_Parse( &ptr );
}
//if ( end == qfalse )
// Com_Printf( "CG_LoadUbersound hit end of file without end statement\n" );
cgi.FS_FreeFile( buffer );
CG_Printf( "=== Finished %s ===\n", fname );
}
void CG_LoadUbersound( void ) {
Com_Memset(snd_indexes, 0, sizeof(snd_indexes));
Com_Memset(hashTable, 0, sizeof(hashTable));
snd_numIndexes = 0;
CG_LoadUberSoundFile(UBERSOUND_FILE, qtrue);
// su44: used by MoHAA voicechats
CG_LoadUberSoundFile(UBERDIALOG_FILE, qfalse);
}
const char* CG_LoadMusic( const char *musicfile ) {
int len;
const char *token;
char *ptr;
char path[MAX_QPATH];
char name[MAX_QPATH];
if( !musicfile[ 0 ] )
{
return "";
}
CG_Printf( "=== Loading %s ===\n", musicfile );
len = cgi.FS_ReadFile( musicfile, &buffer, qfalse );
if( len <= 0 ) {
CG_Printf( "couldn't load %s. file not found.\n", musicfile );
return NULL;
}
ptr = buffer;
token = COM_Parse( &ptr );
while (*token) {
if ( !Q_strncmp(token,"path",MAX_QPATH) )
Q_strncpyz( path, COM_Parse(&ptr), MAX_QPATH );
else if ( !Q_strncmp(token,"normal",MAX_QPATH) )
Q_strncpyz( name, COM_Parse(&ptr), MAX_QPATH );
token = COM_Parse( &ptr );
}
Q_snprintf( buffer, MAX_QPATH, "%s/%s", path, name );
return buffer;
}
+205
View File
@@ -0,0 +1,205 @@
/*
===========================================================================
Copyright (C) 2023 the OpenMoHAA team
This file is part of OpenMoHAA source code.
OpenMoHAA source code is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the License,
or (at your option) any later version.
OpenMoHAA source code is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with OpenMoHAA source code; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
// DESCRIPTION:
// UI features
#include "cg_local.h"
#include "str.h"
void CG_MessageMode_f(void)
{
if (!cgs.gametype) {
return;
}
cgi.UI_ToggleDMMessageConsole(300);
}
void CG_MessageMode_All_f(void)
{
if (!cgs.gametype) {
return;
}
cgi.UI_ToggleDMMessageConsole(100);
}
void CG_MessageMode_Team_f(void)
{
if (!cgs.gametype) {
return;
}
cgi.UI_ToggleDMMessageConsole(200);
}
void CG_MessageMode_Private_f(void)
{
int clientNum;
if (!cgs.gametype) {
return;
}
clientNum = atoi(cgi.Argv(1)) - 1;
if (clientNum < 0 || clientNum >= MAX_CLIENTS)
{
cgi.Printf(HUD_MESSAGE_CHAT_WHITE "Message Error: %s is a bad client number\n", cgi.Argv(1));
return;
}
cgi.UI_ToggleDMMessageConsole(clientNum);
}
void CG_MessageSingleAll_f(void)
{
if (!cgs.gametype) {
return;
}
if (cgi.Argc() > 1) {
cgi.SendClientCommand(va("dmmessage 0 %s\n", cgi.Args()));
}
else {
cgi.UI_ToggleDMMessageConsole(-100);
}
}
void CG_MessageSingleTeam_f(void)
{
if (!cgs.gametype) {
return;
}
if (cgi.Argc() > 1) {
cgi.SendClientCommand(va("dmmessage -1 %s\n", cgi.Args()));
}
else {
cgi.UI_ToggleDMMessageConsole(-200);
}
}
void CG_MessageSingleClient_f(void)
{
int clientNum;
if (!cgs.gametype) {
return;
}
clientNum = atoi(cgi.Argv(1));
if (clientNum < 1 || clientNum > MAX_CLIENTS)
{
cgi.Printf(HUD_MESSAGE_CHAT_WHITE "Message Error: %s is a bad client number\n", cgi.Argv(1));
return;
}
if (cgi.Argc() > 2)
{
int i;
str sString;
sString = "dmmessage ";
sString += va("%i", clientNum);
// copy the rest
for (i = 2; i < cgi.Argc(); i++) {
sString += va("%s", cgi.Argv(i));
}
sString += "\n";
cgi.SendClientCommand(sString.c_str());
}
else {
cgi.UI_ToggleDMMessageConsole(-clientNum);
}
}
void CG_InstaMessageMain_f(void)
{
if (!voiceChat->integer) {
return;
}
if (!cgs.gametype) {
return;
}
cg.iInstaMessageMenu = -1;
}
void CG_InstaMessageGroupA_f(void)
{
if (!cgs.gametype) {
return;
}
cg.iInstaMessageMenu = 1;
}
void CG_InstaMessageGroupB_f(void)
{
if (!cgs.gametype) {
return;
}
cg.iInstaMessageMenu = 2;
}
void CG_InstaMessageGroupC_f(void)
{
if (!cgs.gametype) {
return;
}
cg.iInstaMessageMenu = 3;
}
void CG_InstaMessageGroupD_f(void)
{
if (!cgs.gametype) {
return;
}
cg.iInstaMessageMenu = 4;
}
void CG_InstaMessageGroupE_f(void)
{
if (!cgs.gametype) {
return;
}
cg.iInstaMessageMenu = 5;
}
void CG_HudPrint_f(void)
{
cgi.Printf("\x1%s", cgi.Argv(0));
}
int CG_CheckCaptureKey(int key, qboolean down, unsigned int time)
{
// FIXME: unimplemented
return 0;
}
+42
View File
@@ -0,0 +1,42 @@
/*
===========================================================================
Copyright (C) 2023 the OpenMoHAA team
This file is part of OpenMoHAA source code.
OpenMoHAA source code is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the License,
or (at your option) any later version.
OpenMoHAA source code is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with OpenMoHAA source code; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
// DESCRIPTION:
// Vehicles
#include "cg_local.h"
#include "cg_commands.h"
void CG_Vehicle(centity_t* cent)
{
}
void ClientGameCommandManager::SpawnTreads(Event* ev)
{
// stub
}
void ClientGameCommandManager::TreadsOff(Event* ev)
{
// stub
}
+678 -729
View File
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
-446
View File
@@ -1,446 +0,0 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
This file is part of Quake III Arena source code.
Quake III Arena source code is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the License,
or (at your option) any later version.
Quake III Arena source code is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Quake III Arena source code; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
//
// cg_weapons.c -- events and effects dealing with weapons
#include "cg_local.h"
/*
==========================
CG_MachineGunEjectBrass
==========================
*/
static void CG_MachineGunEjectBrass( centity_t *cent ) {
/*localEntity_t *le;
refEntity_t *re;
vec3_t velocity, xvelocity;
vec3_t offset, xoffset;
float waterScale = 1.0f;
vec3_t v[3];
if ( cg_brassTime.integer <= 0 ) {
return;
}
le = CG_AllocLocalEntity();
re = &le->refEntity;
velocity[0] = 0;
velocity[1] = -50 + 40 * crandom();
velocity[2] = 100 + 50 * crandom();
le->leType = LE_FRAGMENT;
le->startTime = cg.time;
le->endTime = le->startTime + cg_brassTime.integer + ( cg_brassTime.integer / 4 ) * random();
le->pos.trType = TR_GRAVITY;
le->pos.trTime = cg.time - (rand()&15);
AnglesToAxis( cent->lerpAngles, v );
offset[0] = 8;
offset[1] = -4;
offset[2] = 24;
xoffset[0] = offset[0] * v[0][0] + offset[1] * v[1][0] + offset[2] * v[2][0];
xoffset[1] = offset[0] * v[0][1] + offset[1] * v[1][1] + offset[2] * v[2][1];
xoffset[2] = offset[0] * v[0][2] + offset[1] * v[1][2] + offset[2] * v[2][2];
VectorAdd( cent->lerpOrigin, xoffset, re->origin );
VectorCopy( re->origin, le->pos.trBase );
if ( CG_PointContents( re->origin, -1 ) & CONTENTS_WATER ) {
waterScale = 0.10f;
}
xvelocity[0] = velocity[0] * v[0][0] + velocity[1] * v[1][0] + velocity[2] * v[2][0];
xvelocity[1] = velocity[0] * v[0][1] + velocity[1] * v[1][1] + velocity[2] * v[2][1];
xvelocity[2] = velocity[0] * v[0][2] + velocity[1] * v[1][2] + velocity[2] * v[2][2];
VectorScale( xvelocity, waterScale, le->pos.trDelta );
AxisCopy( axisDefault, re->axis );
re->hModel = cgs.media.machinegunBrassModel;
le->bounceFactor = 0.4 * waterScale;
le->angles.trType = TR_LINEAR;
le->angles.trTime = cg.time;
le->angles.trBase[0] = rand()&31;
le->angles.trBase[1] = rand()&31;
le->angles.trBase[2] = rand()&31;
le->angles.trDelta[0] = 2;
le->angles.trDelta[1] = 1;
le->angles.trDelta[2] = 0;
le->leFlags = LEF_TUMBLE;
le->leBounceSoundType = LEBS_BRASS;
le->leMarkType = LEMT_NONE;*/
}
/*
==========================
CG_ShotgunEjectBrass
==========================
*/
static void CG_ShotgunEjectBrass( centity_t *cent ) {
//localEntity_t *le;
//refEntity_t *re;
//vec3_t velocity, xvelocity;
//vec3_t offset, xoffset;
//vec3_t v[3];
//int i;
//if ( cg_brassTime.integer <= 0 ) {
// return;
//}
//for ( i = 0; i < 2; i++ ) {
// float waterScale = 1.0f;
// le = CG_AllocLocalEntity();
// re = &le->refEntity;
// velocity[0] = 60 + 60 * crandom();
// if ( i == 0 ) {
// velocity[1] = 40 + 10 * crandom();
// } else {
// velocity[1] = -40 + 10 * crandom();
// }
// velocity[2] = 100 + 50 * crandom();
// le->leType = LE_FRAGMENT;
// le->startTime = cg.time;
// le->endTime = le->startTime + cg_brassTime.integer*3 + cg_brassTime.integer * random();
// le->pos.trType = TR_GRAVITY;
// le->pos.trTime = cg.time;
// AnglesToAxis( cent->lerpAngles, v );
// offset[0] = 8;
// offset[1] = 0;
// offset[2] = 24;
// xoffset[0] = offset[0] * v[0][0] + offset[1] * v[1][0] + offset[2] * v[2][0];
// xoffset[1] = offset[0] * v[0][1] + offset[1] * v[1][1] + offset[2] * v[2][1];
// xoffset[2] = offset[0] * v[0][2] + offset[1] * v[1][2] + offset[2] * v[2][2];
// VectorAdd( cent->lerpOrigin, xoffset, re->origin );
// VectorCopy( re->origin, le->pos.trBase );
// if ( CG_PointContents( re->origin, -1 ) & CONTENTS_WATER ) {
// waterScale = 0.10f;
// }
// xvelocity[0] = velocity[0] * v[0][0] + velocity[1] * v[1][0] + velocity[2] * v[2][0];
// xvelocity[1] = velocity[0] * v[0][1] + velocity[1] * v[1][1] + velocity[2] * v[2][1];
// xvelocity[2] = velocity[0] * v[0][2] + velocity[1] * v[1][2] + velocity[2] * v[2][2];
// VectorScale( xvelocity, waterScale, le->pos.trDelta );
// AxisCopy( axisDefault, re->axis );
// re->hModel = cgs.media.shotgunBrassModel;
// le->bounceFactor = 0.3f;
// le->angles.trType = TR_LINEAR;
// le->angles.trTime = cg.time;
// le->angles.trBase[0] = rand()&31;
// le->angles.trBase[1] = rand()&31;
// le->angles.trBase[2] = rand()&31;
// le->angles.trDelta[0] = 1;
// le->angles.trDelta[1] = 0.5;
// le->angles.trDelta[2] = 0;
// le->leFlags = LEF_TUMBLE;
// le->leBounceSoundType = LEBS_BRASS;
// le->leMarkType = LEMT_NONE;
//}
}
#ifdef MISSIONPACK
/*
==========================
CG_NailgunEjectBrass
==========================
*/
static void CG_NailgunEjectBrass( centity_t *cent ) {
localEntity_t *smoke;
vec3_t origin;
vec3_t v[3];
vec3_t offset;
vec3_t xoffset;
vec3_t up;
AnglesToAxis( cent->lerpAngles, v );
offset[0] = 0;
offset[1] = -12;
offset[2] = 24;
xoffset[0] = offset[0] * v[0][0] + offset[1] * v[1][0] + offset[2] * v[2][0];
xoffset[1] = offset[0] * v[0][1] + offset[1] * v[1][1] + offset[2] * v[2][1];
xoffset[2] = offset[0] * v[0][2] + offset[1] * v[1][2] + offset[2] * v[2][2];
VectorAdd( cent->lerpOrigin, xoffset, origin );
VectorSet( up, 0, 0, 64 );
smoke = CG_SmokePuff( origin, up, 32, 1, 1, 1, 0.33f, 700, cg.time, 0, 0, cgs.media.smokePuffShader );
// use the optimized local entity add
smoke->leType = LE_SCALE_FADE;
}
#endif
/*
========================================================================================
VIEW WEAPON
========================================================================================
*/
/*
==============
CG_CalculateWeaponPosition
==============
*/
static void CG_CalculateWeaponPosition( vec3_t origin, vec3_t angles ) {
float scale;
int delta;
float fracsin;
VectorCopy( cg.refdef.vieworg, origin );
VectorCopy( cg.refdefViewAngles, angles );
// on odd legs, invert some angles
if ( cg.bobcycle & 1 ) {
scale = -cg.xyspeed;
} else {
scale = cg.xyspeed;
}
// gun angles from bobbing
angles[ROLL] += scale * cg.bobfracsin * 0.005;
angles[YAW] += scale * cg.bobfracsin * 0.01;
angles[PITCH] += cg.xyspeed * cg.bobfracsin * 0.005;
// drop the weapon when landing
delta = cg.time - cg.landTime;
if ( delta < LAND_DEFLECT_TIME ) {
origin[2] += cg.landChange*0.25 * delta / LAND_DEFLECT_TIME;
} else if ( delta < LAND_DEFLECT_TIME + LAND_RETURN_TIME ) {
origin[2] += cg.landChange*0.25 *
(LAND_DEFLECT_TIME + LAND_RETURN_TIME - delta) / LAND_RETURN_TIME;
}
#if 0
// drop the weapon when stair climbing
delta = cg.time - cg.stepTime;
if ( delta < STEP_TIME/2 ) {
origin[2] -= cg.stepChange*0.25 * delta / (STEP_TIME/2);
} else if ( delta < STEP_TIME ) {
origin[2] -= cg.stepChange*0.25 * (STEP_TIME - delta) / (STEP_TIME/2);
}
#endif
// idle drift
scale = cg.xyspeed + 40;
fracsin = sin( cg.time * 0.001 );
angles[ROLL] += scale * fracsin * 0.01;
angles[YAW] += scale * fracsin * 0.01;
angles[PITCH] += scale * fracsin * 0.01;
}
/*
==============
CG_AddViewWeapon
Add the weapon, and flash for the player's view
==============
*/
void CG_AddViewWeapon( playerState_t *ps ) {
//refEntity_t hand;
//centity_t *cent;
//clientInfo_t *ci;
//float fovOffset;
//vec3_t angles;
////if ( ps->stats[STAT_TEAM] == TEAM_SPECTATOR ) {
//// return;
////}
//if ( ps->pm_type == PM_INTERMISSION ) {
// return;
//}
//// no gun if in third person view or a camera is active
////if ( cg.renderingThirdPerson || cg.cameraMode) {
//if ( cg.renderingThirdPerson ) {
// return;
//}
////// allow the gun to be completely removed
////if ( !cg_drawGun.integer ) {
//// vec3_t origin;
//// if ( cg.predictedPlayerState.eFlags & EF_FIRING ) {
//// // special hack for lightning gun...
//// VectorCopy( cg.refdef.vieworg, origin );
//// VectorMA( origin, -8, cg.refdef.viewaxis[2], origin );
//// CG_LightningBolt( &cg_entities[ps->clientNum], origin );
//// }
//// return;
////}
//// don't draw if testing a gun model
//if ( cg.testGun ) {
// return;
//}
//// drop gun lower at higher fov
//if ( cg_fov.integer > 90 ) {
// fovOffset = -0.2 * ( cg_fov.integer - 90 );
//} else {
// fovOffset = 0;
//}
//cent = &cg.predictedPlayerEntity; // &cg_entities[cg.snap->ps.clientNum];
//memset (&hand, 0, sizeof(hand));
//// set up gun position
//CG_CalculateWeaponPosition( hand.origin, angles );
//VectorMA( hand.origin, cg_gun_x.value, cg.refdef.viewaxis[0], hand.origin );
//VectorMA( hand.origin, cg_gun_y.value, cg.refdef.viewaxis[1], hand.origin );
//VectorMA( hand.origin, (cg_gun_z.value+fovOffset), cg.refdef.viewaxis[2], hand.origin );
//AnglesToAxis( angles, hand.axis );
//// map torso animations to weapon animations
//if ( cg_gun_frame.integer ) {
// // development tool
// hand.frame = hand.oldframe = cg_gun_frame.integer;
// hand.backlerp = 0;
//} else {
// // get clientinfo for animation map
// ci = &cgs.clientinfo[ cent->currentState.clientNum ];
// hand.frame = CG_MapTorsoToWeaponFrame( ci, cent->pe.torso.frame );
// hand.oldframe = CG_MapTorsoToWeaponFrame( ci, cent->pe.torso.oldFrame );
// hand.backlerp = cent->pe.torso.backlerp;
//}
//hand.hModel = weapon->handsModel;
//hand.renderfx = RF_DEPTHHACK | RF_FIRST_PERSON | RF_MINLIGHT;
//// add everything onto the hand
//CG_AddPlayerWeapon( &hand, ps, &cg.predictedPlayerEntity, ps->stats[STAT_TEAM] );
}
/*
==============================================================================
WEAPON SELECTION
==============================================================================
*/
/*
===============
CG_NextWeapon_f
===============
*/
void CG_NextWeapon_f( void ) {
cg.iWeaponCommand = 12;
cg.iWeaponCommandSend = 0;
}
/*
===============
CG_PrevWeapon_f
===============
*/
void CG_PrevWeapon_f( void ) {
cg.iWeaponCommand = 11;
cg.iWeaponCommandSend = 0;
}
/*
===============
CG_PrevWeapon_f
===============
*/
void CG_UseLastWeapon_f( void )
{
cg.iWeaponCommand = 13;
cg.iWeaponCommandSend = 0;
}
/*
===============
CG_HolsterWeapon_f
===============
*/
void CG_HolsterWeapon_f( void )
{
cg.iWeaponCommand = 14;
cg.iWeaponCommandSend = 0;
}
/*
===============
CG_DropWeapon_f
===============
*/
void CG_DropWeapon_f( void )
{
cg.iWeaponCommand = 15;
cg.iWeaponCommandSend = 0;
}
/*
===============
CG_ToggleItem_f
===============
*/
void CG_ToggleItem_f()
{
cg.iWeaponCommand = 7;
cg.iWeaponCommandSend = 0;
}
// su44: encode current weapon command for MoHAA
int CG_WeaponCommandButtonBits() {
int ret;
if( !cg.iWeaponCommand )
return 0;
ret = (cg.iWeaponCommand << 7) & 0x780;
cg.iWeaponCommandSend++;
if( cg.iWeaponCommandSend > 2 )
cg.iWeaponCommand = 0;
return ret;
}
+275
View File
@@ -0,0 +1,275 @@
/*
===========================================================================
Copyright (C) 2023 the OpenMoHAA team
This file is part of OpenMoHAA source code.
OpenMoHAA source code is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the License,
or (at your option) any later version.
OpenMoHAA source code is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with OpenMoHAA source code; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
// DESCRIPTION:
// Renderer types
#ifndef __TR_TYPES_H
#define __TR_TYPES_H
#define MAX_DLIGHTS 32 // can't be increased, because bit flags are used on surfaces
#define MAX_ENTITIES 1023 // can't be increased without changing drawsurf bit packing
#define MAX_POINTS 32
#define MAX_SPRITES 1024
// refdef flags
#define RDF_NOWORLDMODEL 1 // used for player configuration screen
#define RDF_HYPERSPACE 4 // teleportation effect
typedef struct
{
float pos[2];
float size[2];
} letterloc_t;
typedef struct fontheader_s
{
int indirection[256];
letterloc_t locations[256];
char name[64];
float height;
float aspectRatio;
void *shader;
int trhandle; // the last renderer handle this font used
} fontheader_t;
typedef struct {
vec3_t xyz;
float st[2];
byte modulate[4];
} polyVert_t;
typedef struct poly_s {
qhandle_t hShader;
int numVerts;
polyVert_t *verts;
} poly_t;
typedef enum {
RT_MODEL,
RT_SPRITE,
RT_BEAM,
RT_PORTALSURFACE, // doesn't draw anything, just info for portals
RT_MAX_REF_ENTITY_TYPE
} refEntityType_t;
typedef enum {
lensflare = ( 1 << 0 ),
viewlensflare = ( 1 << 1 ),
additive = ( 1 << 2 )
} dlighttype_t;
struct tikiFrame_s;
struct dtiki_s;
typedef struct {
refEntityType_t reType;
int renderfx;
qhandle_t hModel; // opaque type outside refresh
qhandle_t hOldModel;
// most recent data
vec3_t lightingOrigin; // so multi-part models can be lit identically (RF_LIGHTING_ORIGIN)
int parentEntity;
vec3_t axis[3]; // rotation vectors
qboolean nonNormalizedAxes; // axis are not normalized, i.e. they have scale
float origin[3]; // also used as MODEL_BEAM's "from"
frameInfo_t frameInfo[MAX_FRAMEINFOS];
float actionWeight;
short wasframe;
float scale; // scale of the thing
// previous data for frame interpolation
float oldorigin[3]; // also used as MODEL_BEAM's "to"
// texturing
int skinNum; // inline skin index
qhandle_t customShader; // use one image for the entire thing
// misc
byte shaderRGBA[4]; // colors used by colorSrc=vertex shaders
float shaderTexCoord[2]; // texture coordinates used by tcMod=vertex modifiers
float shaderTime; // subtracted from refdef time to control effect start times
int entityNumber; // the real entity number
byte surfaces[MAX_MODEL_SURFACES]; // the surface state of the entity
float shader_data[ 2 ]; // data passed in from shader manipulation
int *bone_tag;
vec4_t *bone_quat;
// renderer use only
struct tikiFrame_s *of,
*nf;
struct dtiki_s *tiki;
int bonestart;
int morphstart;
qboolean hasMorph;
// extra sprite information
float radius;
float rotation;
} refEntity_t;
#define MAX_RENDER_STRINGS 8
#define MAX_RENDER_STRING_LENGTH 32
typedef struct {
int x, y, width, height;
float fov_x, fov_y;
vec3_t vieworg;
vec3_t viewaxis[3]; // transformation matrix
// time in milliseconds for shader effects and other time dependent rendering issues
int time;
int rdflags; // RDF_NOWORLDMODEL, etc
// 1 bits will prevent the associated area from rendering at all
byte areamask[MAX_MAP_AREA_BYTES];
// fog stuff
float farplane_distance;
vec3_t farplane_color;
qboolean farplane_cull;
// sky portal stuff
qboolean sky_portal;
float sky_alpha;
vec3_t sky_origin;
vec3_t sky_axis[ 3 ];
} refdef_t;
typedef enum {
STEREO_CENTER,
STEREO_LEFT,
STEREO_RIGHT
} stereoFrame_t;
/*
** glconfig_t
**
** Contains variables specific to the OpenGL configuration
** being run right now. These are constant once the OpenGL
** subsystem is initialized.
*/
typedef enum {
TC_NONE,
TC_S3TC, // this is for the GL_S3_s3tc extension.
TC_S3TC_ARB // this is for the GL_EXT_texture_compression_s3tc extension.
} textureCompression_t;
typedef enum {
GLDRV_ICD, // driver is integrated with window system
// WARNING: there are tests that check for
// > GLDRV_ICD for minidriverness, so this
// should always be the lowest value in this
// enum set
GLDRV_STANDALONE, // driver is a non-3Dfx standalone driver
GLDRV_VOODOO, // driver is a 3Dfx standalone driver
// XreaL BEGIN
GLDRV_DEFAULT, // old OpenGL system
GLDRV_OPENGL3, // new driver system
GLDRV_MESA // crap
// XreaL END
} glDriverType_t;
typedef enum {
GLHW_GENERIC, // where everthing works the way it should
GLHW_3DFX_2D3D, // Voodoo Banshee or Voodoo3, relevant since if this is
// the hardware type then there can NOT exist a secondary
// display adapter
GLHW_RIVA128, // where you can't interpolate alpha
GLHW_RAGEPRO, // where you can't modulate alpha on alpha textures
GLHW_PERMEDIA2, // where you don't have src*dst
// XreaL BEGIN
GLHW_ATI, // where you don't have proper GLSL support
GLHW_ATI_DX10, // ATI Radeon HD series DX10 hardware
GLHW_NV_DX10 // Geforce 8/9 class DX10 hardware
// XreaL END
} glHardwareType_t;
typedef struct {
char renderer_string[ MAX_STRING_CHARS ];
char vendor_string[ MAX_STRING_CHARS ];
char version_string[ MAX_STRING_CHARS ];
char extensions_string[ MAX_STRING_CHARS * 2 ];
int maxTextureSize; // queried from GL
int maxActiveTextures; // multitexture ability
int colorBits, depthBits, stencilBits;
glDriverType_t driverType;
glHardwareType_t hardwareType;
qboolean deviceSupportsGamma;
textureCompression_t textureCompression;
qboolean textureEnvAddAvailable;
int vidWidth, vidHeight;
// aspect is the screen's physical width / height, which may be different
// than scrWidth / scrHeight if the pixels are non-square
// normal screens should be 4/3, but wide aspect monitors may be 16/9
float windowAspect;
int displayFrequency;
// synonymous with "does rendering consume the entire screen?", therefore
// a Voodoo or Voodoo2 will have this set to TRUE, as will a Win32 ICD that
// used CDS.
qboolean isFullscreen;
qboolean stereoEnabled;
qboolean smpActive; // dual processor
int registerCombinerAvailable;
qboolean secondaryColorAvailable;
qboolean VAR;
qboolean fence;
// ioq3
int numTextureUnits;
} glconfig_t;
#if !defined _WIN32
#define _3DFX_DRIVER_NAME "libMesaVoodooGL.so.3.1"
#define OPENGL_DRIVER_NAME "libGL.so"
#else
#define _3DFX_DRIVER_NAME "3dfxvgl"
#define OPENGL_DRIVER_NAME "opengl32"
#endif // !defined _WIN32
#endif // __TR_TYPES_H
+48 -111
View File
@@ -23,11 +23,9 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#include "client.h"
#include "cl_ui.h"
#include "../botlib/botlib.h"
#include "tiki.h"
#include <localization.h>
extern botlib_export_t *botlib_export;
extern qboolean loadCamera(const char *name);
extern void startCamera(int time);
extern qboolean getCameraInfo(int time, vec3_t *origin, vec3_t *angles);
@@ -47,33 +45,30 @@ CL_GetGlconfig
====================
*/
void CL_GetGlconfig( glconfig_t *glconfig ) {
glconfig_ver19_t *pgl = ( glconfig_ver19_t * )glconfig;
strncpy( pgl->renderer_string, cls.glconfig.renderer_string, sizeof( pgl->renderer_string ) );
strncpy( pgl->vendor_string, cls.glconfig.vendor_string, sizeof( pgl->vendor_string ) );
strncpy( pgl->version_string, cls.glconfig.version_string, sizeof( pgl->version_string ) );
strncpy( pgl->extensions_string, cls.glconfig.extensions_string, sizeof( pgl->extensions_string ) );
pgl->maxTextureSize = cls.glconfig.maxTextureSize;
pgl->numTextureUnits = cls.glconfig.numTextureUnits;
pgl->colorBits = cls.glconfig.colorBits;
pgl->depthBits = cls.glconfig.depthBits;
pgl->stencilBits = cls.glconfig.stencilBits;
pgl->driverType = cls.glconfig.driverType;
pgl->hardwareType = cls.glconfig.hardwareType;
pgl->deviceSupportsGamma = cls.glconfig.deviceSupportsGamma;
pgl->textureCompression = cls.glconfig.textureCompression;
pgl->textureEnvAddAvailable = cls.glconfig.textureEnvAddAvailable;
pgl->vidWidth = cls.glconfig.vidWidth;
pgl->vidHeight = cls.glconfig.vidHeight;
pgl->windowAspect = cls.glconfig.windowAspect;
pgl->displayFrequency = cls.glconfig.displayFrequency;
pgl->isFullscreen = cls.glconfig.isFullscreen;
pgl->stereoEnabled = cls.glconfig.stereoEnabled;
pgl->smpActive = cls.glconfig.smpActive;
pgl->registerCombinerAvailable = cls.glconfig.registerCombinerAvailable;
pgl->secondaryColorAvailable = cls.glconfig.secondaryColorAvailable;
pgl->VAR = cls.glconfig.VAR;
pgl->fence = cls.glconfig.fence;
strncpy( glconfig->renderer_string, cls.glconfig.renderer_string, sizeof( glconfig->renderer_string ) );
strncpy( glconfig->vendor_string, cls.glconfig.vendor_string, sizeof( glconfig->vendor_string ) );
strncpy( glconfig->version_string, cls.glconfig.version_string, sizeof( glconfig->version_string ) );
strncpy( glconfig->extensions_string, cls.glconfig.extensions_string, sizeof( glconfig->extensions_string ) );
glconfig->maxTextureSize = cls.glconfig.maxTextureSize;
glconfig->colorBits = cls.glconfig.colorBits;
glconfig->depthBits = cls.glconfig.depthBits;
glconfig->stencilBits = cls.glconfig.stencilBits;
glconfig->driverType = cls.glconfig.driverType;
glconfig->hardwareType = cls.glconfig.hardwareType;
glconfig->deviceSupportsGamma = cls.glconfig.deviceSupportsGamma;
glconfig->textureCompression = cls.glconfig.textureCompression;
glconfig->textureEnvAddAvailable = cls.glconfig.textureEnvAddAvailable;
glconfig->vidWidth = cls.glconfig.vidWidth;
glconfig->vidHeight = cls.glconfig.vidHeight;
glconfig->windowAspect = cls.glconfig.windowAspect;
glconfig->displayFrequency = cls.glconfig.displayFrequency;
glconfig->isFullscreen = cls.glconfig.isFullscreen;
glconfig->stereoEnabled = cls.glconfig.stereoEnabled;
glconfig->smpActive = cls.glconfig.smpActive;
glconfig->registerCombinerAvailable = cls.glconfig.registerCombinerAvailable;
glconfig->secondaryColorAvailable = cls.glconfig.secondaryColorAvailable;
glconfig->VAR = cls.glconfig.VAR;
glconfig->fence = cls.glconfig.fence;
}
@@ -205,9 +200,9 @@ qboolean CL_GetSnapshot( int snapshotNumber, snapshot_t *snapshot ) {
// wombat: sounds
count = clSnap->number_of_sounds;
if ( snapshot->number_of_sounds > MAX_SOUNDS_IN_SNAPSHOT ) {
Com_DPrintf( "CL_GetSnapshot: truncated %i sounds to %i\n", count, MAX_SOUNDS_IN_SNAPSHOT );
count = MAX_SOUNDS_IN_SNAPSHOT;
if ( snapshot->number_of_sounds > MAX_SERVER_SOUNDS) {
Com_DPrintf( "CL_GetSnapshot: truncated %i sounds to %i\n", count, MAX_SERVER_SOUNDS);
count = MAX_SERVER_SOUNDS;
}
snapshot->number_of_sounds = count;
Com_Memcpy( snapshot->sounds, clSnap->sounds, sizeof(snapshot->sounds[0])*count );
@@ -357,31 +352,6 @@ rescan:
Com_Error( ERR_SERVERDISCONNECT, "Server disconnected\n" );
}
if ( !strcmp( cmd, "bcs0" ) ) {
Com_sprintf( bigConfigString, BIG_INFO_STRING, "cs %s \"%s", Cmd_Argv(1), Cmd_Argv(2) );
return qfalse;
}
if ( !strcmp( cmd, "bcs1" ) ) {
s = Cmd_Argv(2);
if( strlen(bigConfigString) + strlen(s) >= BIG_INFO_STRING ) {
Com_Error( ERR_DROP, "bcs exceeded BIG_INFO_STRING" );
}
strcat( bigConfigString, s );
return qfalse;
}
if ( !strcmp( cmd, "bcs2" ) ) {
s = Cmd_Argv(2);
if( strlen(bigConfigString) + strlen(s) + 1 >= BIG_INFO_STRING ) {
Com_Error( ERR_DROP, "bcs exceeded BIG_INFO_STRING" );
}
strcat( bigConfigString, s );
strcat( bigConfigString, "\"" );
s = bigConfigString;
goto rescan;
}
if ( !strcmp( cmd, "cs" ) ) {
CL_ConfigstringModified();
// reparse the string, because CL_ConfigstringModified may have done another Cmd_TokenizeString()
@@ -389,33 +359,6 @@ rescan:
return qtrue;
}
if ( !strcmp( cmd, "map_restart" ) ) {
// clear notify lines and outgoing commands before passing
// the restart to the cgame
Con_ClearNotify();
Com_Memset( cl.cmds, 0, sizeof( cl.cmds ) );
return qtrue;
}
// the clientLevelShot command is used during development
// to generate 128*128 screenshots from the intermission
// point of levels for the menu system to use
// we pass it along to the cgame to make apropriate adjustments,
// but we also clear the console and notify lines here
if ( !strcmp( cmd, "clientLevelShot" ) ) {
// don't do it if we aren't running the server locally,
// otherwise malicious remote servers could overwrite
// the existing thumbnails
if ( !com_sv_running->integer ) {
return qfalse;
}
// close the console
Con_Close();
// take a special screenshot next frame
Cbuf_AddText( "wait ; wait ; wait ; wait ; screenshot levelshot\n" );
return qtrue;
}
// we may want to put a "connect to other server" command here
// cgame can now act on the command
@@ -441,7 +384,7 @@ void CL_CM_LoadMap( const char *mapname ) {
CL_CG_Malloc
====================
*/
void *CL_CG_Malloc( int size )
void *CL_CG_Malloc(int size )
{
return Z_TagMalloc( size, TAG_CGAME );
}
@@ -483,7 +426,6 @@ CL_ShutdownCGame
====================
*/
void CL_ShutdownCGame( void ) {
Key_SetCatcher( Key_GetCatcher( ) & ~KEYCATCH_CGAME );
cls.cgameStarted = qfalse;
if( cge )
@@ -523,8 +465,8 @@ sfxHandle_t CL_RegisterSound( const char *sample, qboolean streamed ) {
CL_StartLocalSound
====================
*/
void CL_StartLocalSound( const char *sound_name ) {
S_StartLocalSound( sound_name, qfalse );
void CL_StartLocalSound(const char* soundName, qboolean forceLoad) {
S_StartLocalSoundByName(soundName, qfalse );
}
/*
@@ -611,8 +553,8 @@ void CL_InitCGameDLL( clientGameImport_t *cgi, clientGameExport_t **cge ) {
cgi->S_StartLocalSound = CL_StartLocalSound;
cgi->S_StopSound = S_StopSound;
cgi->S_AddLoopingSound = S_AddLoopingSound;
cgi->S_ClearLoopingSounds = S_ClearLoopingSounds;
cgi->S_Respatialize = S_Respatialize;
cgi->S_ClearLoopingSounds = S_ClearLoopingSoundsNoParam;
cgi->S_Respatialize = S_RespatializeOld;
cgi->S_BeginRegistration = S_BeginRegistration;
cgi->S_EndRegistration = S_EndRegistration;
cgi->S_UpdateEntity = S_UpdateEntity;
@@ -739,10 +681,11 @@ void CL_InitCGameDLL( clientGameImport_t *cgi, clientGameExport_t **cge ) {
cgi->FS_CanonicalFilename = FS_CanonicalFilename;
cgi->fsDebug = fs_debug;
cgi->hudDrawElements = cls.HudDrawElements;
cgi->HudDrawElements = cls.HudDrawElements;
cgi->anim = &cls.anim;
cgi->stopWatch = &cls.stopwatch;
cgi->pUnknownVar = NULL;
// FIXME
//cgi->pUnknownVar = NULL;
cls.cgameStarted = qtrue;
}
@@ -756,20 +699,20 @@ static void CL_ViewModelAnimation_Init() {
int i;
for( i = 0; i < MAX_FRAMEINFOS; i++ ) {
cls.anim.vmFrameInfo[ i ].index = 0;
cls.anim.vmFrameInfo[ i ].time = 0.0;
cls.anim.vmFrameInfo[ i ].weight = 0.0;
cls.anim.g_VMFrameInfo[ i ].index = 0;
cls.anim.g_VMFrameInfo[ i ].time = 0.0;
cls.anim.g_VMFrameInfo[ i ].weight = 0.0;
}
VectorClear( cls.anim.currentVMPosOffset );
cls.anim.lastVMAnim = -1;
cls.anim.lastVMAnimChanged = -1;
cls.anim.currentVMAnimSlot = 0;
cls.anim.currentVMDuration = 9999;
cls.anim.crossBlending = qfalse;
cls.anim.lastEquippedWeaponStat = -1;
cls.anim.lastActiveItem[ 0 ] = 0;
cls.anim.lastAnimPrefixIndex = 0;
VectorClear( cls.anim.g_vCurrentVMPosOffset );
cls.anim.g_iLastVMAnim = -1;
cls.anim.g_iLastVMAnimChanged = -1;
cls.anim.g_iCurrentVMAnimSlot = 0;
cls.anim.g_iCurrentVMDuration = 9999;
cls.anim.g_bCrossblending = qfalse;
cls.anim.g_iLastEquippedWeaponStat = -1;
cls.anim.g_szLastActiveItem[ 0 ] = 0;
cls.anim.g_iLastAnimPrefixIndex = 0;
}
/*
@@ -833,9 +776,6 @@ void CL_InitCGame( void ) {
t1 = Sys_Milliseconds();
// put away the console
Con_Close();
// find the current mapname
info = cl.gameState.stringData + cl.gameState.stringOffsets[ CS_SERVERINFO ];
mapname = Info_ValueForKey( info, "mapname" );
@@ -874,9 +814,6 @@ void CL_InitCGame( void ) {
t2 = Sys_Milliseconds();
// clear anything that got printed
Con_ClearNotify();
Com_Printf( "CL_InitCGame: %5.2f seconds\n", ( t2 - t1 ) / 1000.0 );
}
+5 -52
View File
@@ -133,7 +133,7 @@ static cin_cache cinTable[MAX_VIDEO_HANDLES];
static int currentHandle = -1;
static int CL_handle = -1;
extern int s_soundtime; // sample PAIRS
extern "C" int s_soundtime; // sample PAIRS
void CIN_CloseAllVideos(void) {
@@ -1142,17 +1142,17 @@ redump:
case ZA_SOUND_MONO:
if (!cinTable[currentHandle].silent) {
ssize = RllDecodeMonoToStereo( framedata, sbuf, cinTable[currentHandle].RoQFrameSize, 0, (unsigned short)cinTable[currentHandle].roq_flags);
S_RawSamples(0, ssize, 22050, 2, 1, (byte *)sbuf, 1.0f, -1);
S_RawSamples(0, 22050, 2, 1, (byte *)sbuf, 1.0f);
}
break;
case ZA_SOUND_STEREO:
if (!cinTable[currentHandle].silent) {
if (cinTable[currentHandle].numQuads == -1) {
S_Update();
s_rawend[0] = s_soundtime;
s_rawend = s_soundtime;
}
ssize = RllDecodeStereoToStereo( framedata, sbuf, cinTable[currentHandle].RoQFrameSize, 0, (unsigned short)cinTable[currentHandle].roq_flags);
S_RawSamples(0, ssize, 22050, 2, 2, (byte *)sbuf, 1.0f, -1);
S_RawSamples(0, 22050, 2, 2, (byte *)sbuf, 1.0f);
}
break;
case ROQ_QUAD_INFO:
@@ -1467,11 +1467,9 @@ int CIN_PlayCinematic( const char *arg, int x, int y, int w, int h, int systemBi
if (cinTable[currentHandle].alterGameState) {
cls.state = CA_CINEMATIC;
}
Con_Close();
if (!cinTable[currentHandle].silent) {
s_rawend[0] = s_soundtime;
s_rawend = s_soundtime;
}
return currentHandle;
@@ -1645,48 +1643,3 @@ void SCR_StopCinematic(void) {
CL_handle = -1;
}
}
void CIN_UploadCinematic(int handle) {
if (handle >= 0 && handle < MAX_VIDEO_HANDLES) {
if (!cinTable[handle].buf) {
return;
}
if (cinTable[handle].playonwalls <= 0 && cinTable[handle].dirty) {
if (cinTable[handle].playonwalls == 0) {
cinTable[handle].playonwalls = -1;
} else {
if (cinTable[handle].playonwalls == -1) {
cinTable[handle].playonwalls = -2;
} else {
cinTable[handle].dirty = qfalse;
}
}
}
// Resample the video if needed
if (cinTable[handle].dirty && (cinTable[handle].CIN_WIDTH != cinTable[handle].drawX || cinTable[handle].CIN_HEIGHT != cinTable[handle].drawY)) {
int *buf2;
buf2 = ( int * )Hunk_AllocateTempMemory( 256*256*4 );
CIN_ResampleCinematic(handle, buf2);
re.UploadCinematic( cinTable[handle].CIN_WIDTH, cinTable[handle].CIN_HEIGHT, 256, 256, (byte *)buf2, handle, qtrue);
cinTable[handle].dirty = qfalse;
Hunk_FreeTempMemory(buf2);
} else {
// Upload video at normal resolution
re.UploadCinematic( cinTable[handle].CIN_WIDTH, cinTable[handle].CIN_HEIGHT, cinTable[handle].drawX, cinTable[handle].drawY,
cinTable[handle].buf, handle, cinTable[handle].dirty);
cinTable[handle].dirty = qfalse;
}
if (cl_inGameVideo->integer == 0 && cinTable[handle].playonwalls == 1) {
cinTable[handle].playonwalls--;
}
else if (cl_inGameVideo->integer != 0 && cinTable[handle].playonwalls != 1) {
cinTable[handle].playonwalls = 1;
}
}
}
-789
View File
@@ -1,789 +0,0 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
This file is part of Quake III Arena source code.
Quake III Arena source code is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the License,
or (at your option) any later version.
Quake III Arena source code is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Quake III Arena source code; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
// console.c
#include "client.h"
int g_console_field_width = 78;
int g_console_charWidth = SMALLCHAR_WIDTH, g_console_charHeight = SMALLCHAR_HEIGHT;
#define NUM_CON_TIMES 4
#define CON_TEXTSIZE 32768
typedef struct {
qboolean initialized;
short text[CON_TEXTSIZE];
int current; // line where next message will be printed
int x; // offset in current line for next print
int display; // bottom of console displays this line
int linewidth; // characters across screen
int totallines; // total lines in console scrollback
float xadjust; // for wide aspect screens
float displayFrac; // aproaches finalFrac at scr_conspeed
float finalFrac; // 0.0 to 1.0 lines of console to display
int vislines; // in scanlines
int times[NUM_CON_TIMES]; // cls.realtime time the line was generated
// for transparent notify lines
vec4_t color;
} console_t;
extern console_t con;
console_t con;
cvar_t *con_conspeed;
cvar_t *con_notifytime;
cvar_t *con_drawnotify;
#define DEFAULT_CONSOLE_WIDTH 78
vec4_t console_color = {1.0, 1.0, 1.0, 1.0};
/*
================
Con_ToggleConsole_f
================
*/
void Con_ToggleConsole_f (void) {
// Can't toggle the console when it's the only thing available
if ( cls.state == CA_DISCONNECTED && Key_GetCatcher( ) == KEYCATCH_CONSOLE ) {
return;
}
Field_Clear( &g_consoleField );
g_consoleField.widthInChars = g_console_field_width;
Con_ClearNotify ();
Key_SetCatcher( Key_GetCatcher( ) ^ KEYCATCH_CONSOLE );
}
/*
================
Con_MessageMode_f
================
*/
void Con_MessageMode_f (void) {
chat_playerNum = -1;
chat_team = qfalse;
Field_Clear( &chatField );
chatField.widthInChars = 30;
Key_SetCatcher( Key_GetCatcher( ) ^ KEYCATCH_MESSAGE );
}
/*
================
Con_MessageMode2_f
================
*/
void Con_MessageMode2_f (void) {
chat_playerNum = -1;
chat_team = qtrue;
Field_Clear( &chatField );
chatField.widthInChars = 25;
Key_SetCatcher( Key_GetCatcher( ) ^ KEYCATCH_MESSAGE );
}
/*
================
Con_MessageMode3_f
================
*/
void Con_MessageMode3_f (void) {
chat_team = qfalse;
Field_Clear( &chatField );
chatField.widthInChars = 30;
Key_SetCatcher( Key_GetCatcher( ) ^ KEYCATCH_MESSAGE );
}
/*
================
Con_MessageMode4_f
================
*/
void Con_MessageMode4_f (void) {
chat_team = qfalse;
Field_Clear( &chatField );
chatField.widthInChars = 30;
Key_SetCatcher( Key_GetCatcher( ) ^ KEYCATCH_MESSAGE );
}
/*
================
Con_Clear_f
================
*/
void Con_Clear_f (void) {
int i;
for ( i = 0 ; i < CON_TEXTSIZE ; i++ ) {
con.text[i] = (ColorIndex(COLOR_WHITE)<<8) | ' ';
}
Con_Bottom(); // go to end
}
/*
================
Con_Dump_f
Save the console contents out to a file
================
*/
void Con_Dump_f (void)
{
int l, x, i;
short *line;
fileHandle_t f;
char buffer[1024];
if (Cmd_Argc() != 2)
{
Com_Printf ("usage: condump <filename>\n");
return;
}
Com_Printf ("Dumped console text to %s.\n", Cmd_Argv(1) );
f = FS_FOpenFileWrite( Cmd_Argv( 1 ) );
if (!f)
{
Com_Printf ("ERROR: couldn't open.\n");
return;
}
// skip empty lines
for (l = con.current - con.totallines + 1 ; l <= con.current ; l++)
{
line = con.text + (l%con.totallines)*con.linewidth;
for (x=0 ; x<con.linewidth ; x++)
if ((line[x] & 0xff) != ' ')
break;
if (x != con.linewidth)
break;
}
// write the remaining lines
buffer[con.linewidth] = 0;
for ( ; l <= con.current ; l++)
{
line = con.text + (l%con.totallines)*con.linewidth;
for(i=0; i<con.linewidth; i++)
buffer[i] = line[i] & 0xff;
for (x=con.linewidth-1 ; x>=0 ; x--)
{
if (buffer[x] == ' ')
buffer[x] = 0;
else
break;
}
strcat( buffer, "\n" );
FS_Write(buffer, strlen(buffer), f);
}
FS_FCloseFile( f );
}
/*
================
Con_ClearNotify
================
*/
void Con_ClearNotify( void ) {
int i;
for ( i = 0 ; i < NUM_CON_TIMES ; i++ ) {
con.times[i] = 0;
}
}
/*
================
Con_CheckResize
If the line width has changed, reformat the buffer.
================
*/
void Con_CheckResize (void)
{
int i, j, width, oldwidth, oldtotallines, numlines, numchars;
short tbuf[CON_TEXTSIZE];
width = (SCREEN_WIDTH / g_console_charWidth) - 2;
if (width == con.linewidth)
return;
if (width < 1) // video hasn't been initialized yet
{
width = DEFAULT_CONSOLE_WIDTH;
con.linewidth = width;
con.totallines = CON_TEXTSIZE / con.linewidth;
for(i=0; i<CON_TEXTSIZE; i++)
con.text[i] = (ColorIndex(COLOR_WHITE)<<8) | ' ';
}
else
{
oldwidth = con.linewidth;
con.linewidth = width;
oldtotallines = con.totallines;
con.totallines = CON_TEXTSIZE / con.linewidth;
numlines = oldtotallines;
if (con.totallines < numlines)
numlines = con.totallines;
numchars = oldwidth;
if (con.linewidth < numchars)
numchars = con.linewidth;
Com_Memcpy (tbuf, con.text, CON_TEXTSIZE * sizeof(short));
for(i=0; i<CON_TEXTSIZE; i++)
con.text[i] = (ColorIndex(COLOR_WHITE)<<8) | ' ';
for (i=0 ; i<numlines ; i++)
{
for (j=0 ; j<numchars ; j++)
{
con.text[(con.totallines - 1 - i) * con.linewidth + j] =
tbuf[((con.current - i + oldtotallines) %
oldtotallines) * oldwidth + j];
}
}
Con_ClearNotify ();
}
con.current = con.totallines - 1;
con.display = con.current;
}
/*
================
Con_Init
================
*/
void Con_Init (void) {
int i;
con_notifytime = Cvar_Get ("con_notifytime", "3", 0);
con_conspeed = Cvar_Get ("scr_conspeed", "3", 0);
con_drawnotify = Cvar_Get ("con_drawnotify", "0", 0);
Field_Clear( &g_consoleField );
g_consoleField.widthInChars = g_console_field_width;
for ( i = 0 ; i < COMMAND_HISTORY ; i++ ) {
Field_Clear( &historyEditLines[i] );
historyEditLines[i].widthInChars = g_console_field_width;
}
CL_LoadConsoleHistory( );
Cmd_AddCommand ("toggleconsole", Con_ToggleConsole_f);
Cmd_AddCommand ("messagemode", Con_MessageMode_f);
Cmd_AddCommand ("messagemode2", Con_MessageMode2_f);
Cmd_AddCommand ("messagemode3", Con_MessageMode3_f);
Cmd_AddCommand ("messagemode4", Con_MessageMode4_f);
Cmd_AddCommand ("clear", Con_Clear_f);
Cmd_AddCommand ("condump", Con_Dump_f);
}
/*
===============
Con_Linefeed
===============
*/
void Con_Linefeed (qboolean skipnotify)
{
int i;
// mark time for transparent overlay
if (con.current >= 0)
{
if (skipnotify)
con.times[con.current % NUM_CON_TIMES] = 0;
else
con.times[con.current % NUM_CON_TIMES] = cls.realtime;
}
con.x = 0;
if (con.display == con.current)
con.display++;
con.current++;
for(i=0; i<con.linewidth; i++)
con.text[(con.current%con.totallines)*con.linewidth+i] = (ColorIndex(COLOR_WHITE)<<8) | ' ';
}
/*
================
CL_ConsolePrint
Handles cursor positioning, line wrapping, etc
All console printing must go through this in order to be logged to disk
If no console is visible, the text will appear at the top of the game window
================
*/
void CL_ConsolePrint( char *txt ) {
int y;
int c, l;
int color;
qboolean skipnotify = qfalse; // NERVE - SMF
int prev; // NERVE - SMF
// TTimo - prefix for text that shows up in console but not in notify
// backported from RTCW
if ( !Q_strncmp( txt, "[skipnotify]", 12 ) ) {
skipnotify = qtrue;
txt += 12;
}
// for some demos we don't want to ever show anything on the console
if ( cl_noprint && cl_noprint->integer ) {
return;
}
if (!con.initialized) {
con.color[0] =
con.color[1] =
con.color[2] =
con.color[3] = 1.0f;
con.linewidth = -1;
Con_CheckResize ();
con.initialized = qtrue;
}
color = ColorIndex(COLOR_WHITE);
while ( (c = *txt) != 0 ) {
if ( Q_IsColorString( txt ) ) {
color = ColorIndex( *(txt+1) );
txt += 2;
continue;
}
// count word length
for (l=0 ; l< con.linewidth ; l++) {
if ( txt[l] <= ' ') {
break;
}
}
// word wrap
if (l != con.linewidth && (con.x + l >= con.linewidth) ) {
Con_Linefeed(skipnotify);
}
txt++;
switch (c)
{
case '\n':
Con_Linefeed (skipnotify);
break;
case '\r':
con.x = 0;
break;
default: // display character and advance
y = con.current % con.totallines;
con.text[y*con.linewidth+con.x] = (color << 8) | c;
con.x++;
if (con.x >= con.linewidth) {
Con_Linefeed(skipnotify);
con.x = 0;
}
break;
}
}
// mark time for transparent overlay
if (con.current >= 0) {
// NERVE - SMF
if ( skipnotify ) {
prev = con.current % NUM_CON_TIMES - 1;
if ( prev < 0 )
prev = NUM_CON_TIMES - 1;
con.times[prev] = 0;
}
else
// -NERVE - SMF
con.times[con.current % NUM_CON_TIMES] = cls.realtime;
}
}
/*
==============================================================================
DRAWING
==============================================================================
*/
/*
================
Con_DrawInput
Draw the editline after a ] prompt
================
*/
void Con_DrawInput (void) {
int y;
if ( cls.state != CA_DISCONNECTED && !(Key_GetCatcher( ) & KEYCATCH_CONSOLE ) ) {
return;
}
y = con.vislines - ( g_console_charHeight * 2 );
re.SetColor( con.color );
re.Text_PaintChar(&cls.consoleFont, con.xadjust + 1 * g_console_charWidth, y, 1.f, ']', 0);
Field_Draw(&cls.consoleFont, &g_consoleField, con.xadjust + 2 * g_console_charWidth, y,
SCREEN_WIDTH - 3 * g_console_charWidth, qtrue, qtrue);
}
/*
================
Con_DrawNotify
Draws the last few lines of output transparently over the game top
================
*/
void Con_DrawNotify (void)
{
int x, v;
short *text;
int i;
int time;
int skip;
int currentColor;
currentColor = 7;
re.SetColor( g_color_table[currentColor] );
v = 0;
for (i= con.current-NUM_CON_TIMES+1 ; i<=con.current ; i++)
{
if (i < 0)
continue;
time = con.times[i % NUM_CON_TIMES];
if (time == 0)
continue;
time = cls.realtime - time;
if (time > con_notifytime->value*1000)
continue;
text = con.text + (i % con.totallines)*con.linewidth;
if (Key_GetCatcher( ) & (KEYCATCH_UI | KEYCATCH_CGAME) ) {
continue;
}
for (x = 0 ; x < con.linewidth ; x++) {
if ( ( text[x] & 0xff ) == ' ' ) {
continue;
}
if ( ( (text[x]>>8)&7 ) != currentColor ) {
currentColor = (text[x]>>8)&7;
re.SetColor( g_color_table[currentColor] );
}
re.Text_PaintChar(&cls.consoleFont, cl_conXOffset->integer + con.xadjust + (x+1)*g_console_charWidth, v, 1.f, text[x] & 0xff,0);
}
v += g_console_charHeight;
}
re.SetColor( NULL );
if (Key_GetCatcher( ) & (KEYCATCH_UI | KEYCATCH_CGAME) ) {
return;
}
// draw the chat line
if ( Key_GetCatcher( ) & KEYCATCH_MESSAGE )
{
if (chat_team)
{
//SCR_DrawBigString (8, v, "say_team:", 1.0f, qfalse );
re.Text_Paint(&cls.consoleFont, 8, v, 1.f, 1.f, "say_team:", 0, 0, qtrue,qfalse);
skip = 10;
}
else
{
//SCR_DrawBigString (8, v, "say:", 1.0f, qfalse );
re.Text_Paint(&cls.consoleFont, 8, v, 1.f, 1.f, "say:", 0, 0, qtrue,qfalse);
skip = 5;
}
// TODO: make this use facfont?
Field_BigDraw(&cls.consoleFont, &chatField, skip * g_console_charWidth, v,
SCREEN_WIDTH - ( skip + 1 ) * g_console_charWidth, qtrue, qtrue );
v += g_console_charHeight;
}
}
/*
================
Con_DrawSolidConsole
Draws the console with the solid background
================
*/
void Con_DrawSolidConsole( float frac ) {
int i, x, y;
int rows;
short *text;
int row;
int lines;
// qhandle_t conShader;
int currentColor;
vec4_t color;
lines = cls.glconfig.vidHeight * frac;
if (lines <= 0)
return;
if (lines > cls.glconfig.vidHeight )
lines = cls.glconfig.vidHeight;
// on wide screens, we will center the text
con.xadjust = 0;
SCR_AdjustFrom640( &con.xadjust, NULL, NULL, NULL );
// draw the background
y = frac * SCREEN_HEIGHT - 2;
if ( y < 1 ) {
y = 0;
}
else {
//SCR_DrawPic( 0, 0, SCREEN_WIDTH, y, cls.consoleShader );
// IneQuation: transparent MoHAA-style console
color[0] = 0.1125f;
color[1] = 0.15f;
color[2] = 0.21f;
color[3] = 0.85f;
SCR_FillRect(0, 0, SCREEN_WIDTH, y, color);
}
color[0] = 0.7f;
color[1] = 0.6f;
color[2] = 0.05f;
color[3] = 1;
SCR_FillRect( 0, y, SCREEN_WIDTH, 2, color );
// draw the version number
/*color[0] = 0.7;
color[1] = 0.6;
color[2] = 0.05;
color[3] = 1;*/
re.SetColor( color/*g_color_table[ColorIndex(COLOR_RED)]*/ );
i = strlen( Q3_VERSION );
for (x=0 ; x<i ; x++) {
re.Text_PaintChar(&cls.consoleFont, cls.glconfig.vidWidth - ( i - x ) * g_console_charWidth,
(lines-(g_console_charHeight+g_console_charHeight/2)), 1.f, Q3_VERSION[x], 0);
}
// draw the text
con.vislines = lines;
rows = (lines - g_console_charWidth) / g_console_charWidth; // rows of text to draw
y = lines - g_console_charHeight * 3;
// draw from the bottom up
if (con.display != con.current)
{
// draw arrows to show the buffer is backscrolled
re.SetColor( g_color_table[ColorIndex(COLOR_RED)] );
for (x=0 ; x<con.linewidth ; x+=4)
re.Text_PaintChar(&cls.consoleFont, con.xadjust + (x+1)*SMALLCHAR_WIDTH, y, 1.f, '^',0);
y -= SMALLCHAR_HEIGHT;
rows--;
}
row = con.display;
if ( con.x == 0 ) {
row--;
}
currentColor = 7;
re.SetColor( g_color_table[currentColor] );
for (i=0 ; i<rows ; i++, y -= g_console_charHeight, row--)
{
if (row < 0)
break;
if (con.current - row >= con.totallines) {
// past scrollback wrap point
continue;
}
text = con.text + (row % con.totallines)*con.linewidth;
for (x=0 ; x<con.linewidth ; x++) {
if ( ( text[x] & 0xff ) == ' ' ) {
continue;
}
if ( ( (text[x]>>8)&7 ) != currentColor ) {
currentColor = (text[x]>>8)&7;
re.SetColor(g_color_table[currentColor]);
}
re.Text_PaintChar(&cls.consoleFont, con.xadjust + (x+1)*g_console_charWidth, y, 1.f, text[x] & 0xff,0);
}
}
// draw the input prompt, user text, and cursor if desired
Con_DrawInput ();
re.SetColor( NULL );
}
/*
==================
Con_DrawConsole
==================
*/
void Con_DrawConsole( void ) {
// check for console width changes from a vid mode change
Con_CheckResize ();
// if disconnected, render console full screen
if ( cls.state == CA_DISCONNECTED ) {
if ( !( Key_GetCatcher( ) & (KEYCATCH_UI | KEYCATCH_CGAME)) ) {
Con_DrawSolidConsole( 1.0 );
return;
}
}
if ( con.displayFrac ) {
Con_DrawSolidConsole( con.displayFrac );
} else {
// draw notify lines
if ( cls.state == CA_ACTIVE && con_drawnotify->integer ) {
Con_DrawNotify ();
}
}
}
//================================================================
/*
==================
Con_RunConsole
Scroll it up or down
==================
*/
void Con_RunConsole (void) {
// decide on the destination height of the console
if ( Key_GetCatcher( ) & KEYCATCH_CONSOLE )
con.finalFrac = 0.5; // half screen
else
con.finalFrac = 0; // none visible
// scroll towards the destination height
if (con.finalFrac < con.displayFrac)
{
con.displayFrac -= con_conspeed->value*cls.realFrametime*0.001;
if (con.finalFrac > con.displayFrac)
con.displayFrac = con.finalFrac;
}
else if (con.finalFrac > con.displayFrac)
{
con.displayFrac += con_conspeed->value*cls.realFrametime*0.001;
if (con.finalFrac < con.displayFrac)
con.displayFrac = con.finalFrac;
}
}
void Con_PageUp( void ) {
con.display -= 2;
if ( con.current - con.display >= con.totallines ) {
con.display = con.current - con.totallines + 1;
}
}
void Con_PageDown( void ) {
con.display += 2;
if (con.display > con.current) {
con.display = con.current;
}
}
void Con_Top( void ) {
con.display = con.totallines;
if ( con.current - con.display >= con.totallines ) {
con.display = con.current - con.totallines + 1;
}
}
void Con_Bottom( void ) {
con.display = con.current;
}
void Con_Close( void ) {
if ( !com_cl_running->integer ) {
return;
}
Field_Clear( &g_consoleField );
Con_ClearNotify ();
Key_SetCatcher( Key_GetCatcher( ) & ~KEYCATCH_CONSOLE );
con.finalFrac = 0; // none visible
con.displayFrac = 0;
}
+1 -1
View File
@@ -23,7 +23,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
// cl_consolecmds.cpp : New client console commands.
#include "client.h"
#include "glb_local.h"
#include "listener.h"
/*
===============
+40 -17
View File
@@ -696,27 +696,43 @@ void CL_CreateNewCommands( void ) {
cmd = &cl.cmds[cmdNum];
}
/*
=================
CL_GetEyeInfo
CL_EyeInfo
Create a new usereyes_t structure for this frame
Gather eyes data from client game module
=================
*/
void CL_GetEyeInfo(usereyes_t *info) {
info->angles[0] = cl.eyeAngles[0];
info->angles[1] = cl.eyeAngles[1];
VectorCopy(cl.eyeOrigin,info->ofs);
}
/*
=================
CL_SetEyeInfo
=================
*/
void CL_SetEyeInfo(vec3_t origin, vec3_t angles) {
VectorCopy(angles,cl.eyeAngles);
VectorCopy(origin,cl.eyeOrigin);
void CL_EyeInfo(usereyes_t* info) {
int i;
vec3_t vAngles, vOfs;
if (cge) {
// copy the eye offset
cge->CG_EyeOffset(&vOfs);
for (i = 0; i < 3; i++) {
vOfs[i] += 0.5;
if (vOfs[i] < -127.0) {
vOfs[i] = -127.0;
} else if (vOfs[i] > 128.0) {
vOfs[i] = 128.0;
}
info->ofs[i] = vOfs[i];
}
cge->CG_EyeAngles(&vAngles);
info->angles[0] = vAngles[0];
info->angles[1] = vAngles[1];
} else {
// clear the eye offset
for (i = 0; i < 3; i++) {
info->ofs[i] = 0;
}
info->angles[0] = info->angles[1] = 0.0;
}
}
/*
@@ -872,7 +888,7 @@ void CL_WritePacket( void ) {
// write the command count
MSG_WriteByte( &buf, count );
CL_GetEyeInfo( &eyeInfo );
CL_EyeInfo( &eyeInfo );
MSG_WriteDeltaEyeInfo( &buf, &cl.outPackets[ oldPacketNum ].p_eyeinfo, &eyeInfo );
// use the checksum feed in the key
key = clc.checksumFeed;
@@ -889,6 +905,13 @@ void CL_WritePacket( void ) {
oldcmd = cmd;
}
}
else {
eyeInfo.ofs[0] = 0;
eyeInfo.ofs[1] = 0;
eyeInfo.ofs[2] = 0;
eyeInfo.angles[0] = cl.viewangles[0];
eyeInfo.angles[1] = cl.viewangles[1];
}
//
// deliver the message
+3 -3
View File
@@ -45,7 +45,7 @@ public:
void setType( inventory_type_t *t );
void Create( float x, float y, FakkInventory *parent );
bool HasAnyItems( void );
void Draw( void );
void Draw( void ) override;
void OnLeftMouseDown( Event *ev );
void OnRightMouseDown( Event *ev );
void OnLeftMouseUp( Event *ev );
@@ -75,7 +75,7 @@ public:
~FakkInventory();
void setInventory( inventory_t *i );
void Draw( void );
void Draw( void ) override;
void OnMouseMove( Event *ev );
void OnMouseLeave( Event *ev );
void OnMouseEnter( Event *ev );
@@ -85,7 +85,7 @@ public:
void NextItem( void );
void PrevItem( void );
qboolean isDying( void );
qboolean KeyEvent( int key, unsigned int time );
qboolean KeyEvent( int key, unsigned int time ) override;
void PlaySound( invsound_t type );
void Timeout( Event *ev );
void ChangeItem( int sign );
+37 -722
View File
@@ -29,14 +29,10 @@ key up events are sent even if in console mode
*/
field_t historyEditLines[COMMAND_HISTORY];
int nextHistoryLine; // the last line in the history buffer, not masked
int historyLine; // the line being displayed from history buffer
// will be <= nextHistoryLine
field_t g_consoleField;
field_t chatField;
qboolean chat_team;
int chat_playerNum;
@@ -45,11 +41,11 @@ int chat_playerNum;
qboolean key_overstrikeMode;
int anykeydown;
qkey_t keys[MAX_KEYS];
qkey_t altkeys[MAX_KEYS];
qkey_t ctrlkeys[MAX_KEYS];
qkey_t keys[K_LASTKEY];
qkey_t altkeys[K_LASTKEY];
qkey_t ctrlkeys[K_LASTKEY];
qboolean menubound[MAX_KEYS];
qboolean menubound[K_LASTKEY];
qboolean alt_down;
qboolean ctrl_down;
@@ -73,15 +69,16 @@ keyname_t keynames[] =
{"LEFTARROW", K_LEFTARROW},
{"RIGHTARROW", K_RIGHTARROW},
{"ALT", K_ALT},
{"LALT", K_LALT},
{"ALT", K_LALT},
// wombat: mohaa knows LCTRL and RCTRL, LSHIFT, RSHIFT
{"CTRL", K_CTRL},
{"LCTRL", K_CTRL},
{"RCTRL", K_CTRL},
{"SHIFT", K_SHIFT},
{"LSHIFT", K_SHIFT},
{"RSHIFT", K_SHIFT},
{"LCTRL", K_LCTRL},
{"CTRL", K_LCTRL},
{"LSHIFT", K_LSHIFT},
{"SHIFT", K_LSHIFT},
{"RALT", K_RALT},
{"RCTRL", K_RCTRL},
{"RSHIFT", K_RSHIFT},
{"COMMAND", K_COMMAND},
@@ -193,539 +190,13 @@ keyname_t keynames[] =
{"SEMICOLON", ';'}, // because a raw semicolon seperates commands
{"WORLD_0", K_WORLD_0},
{"WORLD_1", K_WORLD_1},
{"WORLD_2", K_WORLD_2},
{"WORLD_3", K_WORLD_3},
{"WORLD_4", K_WORLD_4},
{"WORLD_5", K_WORLD_5},
{"WORLD_6", K_WORLD_6},
{"WORLD_7", K_WORLD_7},
{"WORLD_8", K_WORLD_8},
{"WORLD_9", K_WORLD_9},
{"WORLD_10", K_WORLD_10},
{"WORLD_11", K_WORLD_11},
{"WORLD_12", K_WORLD_12},
{"WORLD_13", K_WORLD_13},
{"WORLD_14", K_WORLD_14},
{"WORLD_15", K_WORLD_15},
{"WORLD_16", K_WORLD_16},
{"WORLD_17", K_WORLD_17},
{"WORLD_18", K_WORLD_18},
{"WORLD_19", K_WORLD_19},
{"WORLD_20", K_WORLD_20},
{"WORLD_21", K_WORLD_21},
{"WORLD_22", K_WORLD_22},
{"WORLD_23", K_WORLD_23},
{"WORLD_24", K_WORLD_24},
{"WORLD_25", K_WORLD_25},
{"WORLD_26", K_WORLD_26},
{"WORLD_27", K_WORLD_27},
{"WORLD_28", K_WORLD_28},
{"WORLD_29", K_WORLD_29},
{"WORLD_30", K_WORLD_30},
{"WORLD_31", K_WORLD_31},
{"WORLD_32", K_WORLD_32},
{"WORLD_33", K_WORLD_33},
{"WORLD_34", K_WORLD_34},
{"WORLD_35", K_WORLD_35},
{"WORLD_36", K_WORLD_36},
{"WORLD_37", K_WORLD_37},
{"WORLD_38", K_WORLD_38},
{"WORLD_39", K_WORLD_39},
{"WORLD_40", K_WORLD_40},
{"WORLD_41", K_WORLD_41},
{"WORLD_42", K_WORLD_42},
{"WORLD_43", K_WORLD_43},
{"WORLD_44", K_WORLD_44},
{"WORLD_45", K_WORLD_45},
{"WORLD_46", K_WORLD_46},
{"WORLD_47", K_WORLD_47},
{"WORLD_48", K_WORLD_48},
{"WORLD_49", K_WORLD_49},
{"WORLD_50", K_WORLD_50},
{"WORLD_51", K_WORLD_51},
{"WORLD_52", K_WORLD_52},
{"WORLD_53", K_WORLD_53},
{"WORLD_54", K_WORLD_54},
{"WORLD_55", K_WORLD_55},
{"WORLD_56", K_WORLD_56},
{"WORLD_57", K_WORLD_57},
{"WORLD_58", K_WORLD_58},
{"WORLD_59", K_WORLD_59},
{"WORLD_60", K_WORLD_60},
{"WORLD_61", K_WORLD_61},
{"WORLD_62", K_WORLD_62},
{"WORLD_63", K_WORLD_63},
{"WORLD_64", K_WORLD_64},
{"WORLD_65", K_WORLD_65},
{"WORLD_66", K_WORLD_66},
{"WORLD_67", K_WORLD_67},
{"WORLD_68", K_WORLD_68},
{"WORLD_69", K_WORLD_69},
{"WORLD_70", K_WORLD_70},
{"WORLD_71", K_WORLD_71},
{"WORLD_72", K_WORLD_72},
{"WORLD_73", K_WORLD_73},
{"WORLD_74", K_WORLD_74},
{"WORLD_75", K_WORLD_75},
{"WORLD_76", K_WORLD_76},
{"WORLD_77", K_WORLD_77},
{"WORLD_78", K_WORLD_78},
{"WORLD_79", K_WORLD_79},
{"WORLD_80", K_WORLD_80},
{"WORLD_81", K_WORLD_81},
{"WORLD_82", K_WORLD_82},
{"WORLD_83", K_WORLD_83},
{"WORLD_84", K_WORLD_84},
{"WORLD_85", K_WORLD_85},
{"WORLD_86", K_WORLD_86},
{"WORLD_87", K_WORLD_87},
{"WORLD_88", K_WORLD_88},
{"WORLD_89", K_WORLD_89},
{"WORLD_90", K_WORLD_90},
{"WORLD_91", K_WORLD_91},
{"WORLD_92", K_WORLD_92},
{"WORLD_93", K_WORLD_93},
{"WORLD_94", K_WORLD_94},
{"WORLD_95", K_WORLD_95},
{"WINDOWS", K_SUPER},
{"COMPOSE", K_COMPOSE},
{"MODE", K_MODE},
{"HELP", K_HELP},
{"PRINT", K_PRINT},
{"SYSREQ", K_SYSREQ},
{"SCROLLOCK", K_SCROLLOCK },
{"BREAK", K_BREAK},
{"MENU", K_MENU},
{"POWER", K_POWER},
{"EURO", K_EURO},
{"UNDO", K_UNDO},
{ "LWINKEY", K_LWINKEY },
{ "RWINKEY", K_RWINKEY },
{ "MENUKEY", K_MENUKEY },
{NULL,0}
};
/*
=============================================================================
EDIT FIELDS
=============================================================================
*/
/*
===================
Field_Draw
Handles horizontal scrolling and cursor blinking
x, y, and width are in pixels
===================
*/
void Field_VariableSizeDraw(fontInfo_t *font, field_t *edit, int x, int y, int width, qboolean showCursor,
qboolean noColorEscape ) {
int len;
int drawLen;
int prestep;
int cursorChar;
char str[MAX_STRING_CHARS];
// int i;
drawLen = edit->widthInChars - 1; // - 1 so there is always a space for the cursor
len = strlen( edit->buffer );
// guarantee that cursor will be visible
if ( len <= drawLen ) {
prestep = 0;
} else {
if ( edit->scroll + drawLen > len ) {
edit->scroll = len - drawLen;
if ( edit->scroll < 0 ) {
edit->scroll = 0;
}
}
prestep = edit->scroll;
}
if ( prestep + drawLen > len ) {
drawLen = len - prestep;
}
// extract <drawLen> characters from the field at <prestep>
if ( drawLen >= MAX_STRING_CHARS ) {
Com_Error( ERR_DROP, "drawLen >= MAX_STRING_CHARS" );
}
Com_Memcpy( str, edit->buffer + prestep, drawLen );
str[ drawLen ] = 0;
// draw it
/*if ( size == SMALLCHAR_WIDTH ) {
float color[4];
color[0] = color[1] = color[2] = color[3] = 1.0;
SCR_DrawSmallStringExt( x, y, str, color, qfalse, noColorEscape );
} else {
// draw big string with drop shadow
SCR_DrawBigString( x, y, str, 1.0, noColorEscape );
}*/
re.Text_Paint(font, x, y, 1.f, 1.f, str, 0, 0, !noColorEscape,0);
// draw the cursor
if ( showCursor ) {
if ( (int)( cls.realtime >> 8 ) & 1 ) {
return; // off blink
}
if ( key_overstrikeMode ) {
cursorChar = '|';
} else {
cursorChar = '_';
}
// i = drawLen - strlen( str );
str[edit->cursor] = 0;
/*if ( size == SMALLCHAR_WIDTH ) {
SCR_DrawSmallChar( x + ( edit->cursor - prestep - i ) * size, y, cursorChar );
} else {
str[0] = cursorChar;
str[1] = 0;
SCR_DrawBigString( x + ( edit->cursor - prestep - i ) * size, y, str, 1.0, qfalse );
}*/
//str[edit->cursor - prestep - i] = cursorChar;
//str[edit->cursor - prestep - i + 1] = 0;
re.Text_PaintChar(&cls.consoleFont, x + re.Text_Width(&cls.consoleFont, str, 0, !noColorEscape), y, 1.f, cursorChar,0);
}
}
void Field_Draw(fontInfo_t *font, field_t *edit, int x, int y, int width, qboolean showCursor, qboolean noColorEscape )
{
Field_VariableSizeDraw(font, edit, x, y, width, showCursor, noColorEscape );
}
void Field_BigDraw(fontInfo_t *font, field_t *edit, int x, int y, int width, qboolean showCursor, qboolean noColorEscape )
{
Field_VariableSizeDraw(font, edit, x, y, width, showCursor, noColorEscape );
}
/*
================
Field_Paste
================
*/
void Field_Paste( field_t *edit ) {
char *cbd;
int pasteLen, i;
cbd = Sys_GetClipboardData();
if ( !cbd ) {
return;
}
// send as if typed, so insert / overstrike works properly
pasteLen = strlen( cbd );
for ( i = 0 ; i < pasteLen ; i++ ) {
Field_CharEvent( edit, cbd[i] );
}
Z_Free( cbd );
}
/*
=================
Field_KeyDownEvent
Performs the basic line editing functions for the console,
in-game talk, and menu fields
Key events are used for non-printable characters, others are gotten from char events.
=================
*/
void Field_KeyDownEvent( field_t *edit, int key ) {
int len;
// shift-insert is paste
if ( ( ( key == K_INS ) || ( key == K_KP_INS ) ) && keys[K_SHIFT].down ) {
Field_Paste( edit );
return;
}
key = tolower( key );
len = strlen( edit->buffer );
switch ( key ) {
case K_DEL:
if ( edit->cursor < len ) {
memmove( edit->buffer + edit->cursor,
edit->buffer + edit->cursor + 1, len - edit->cursor );
}
break;
case K_RIGHTARROW:
if ( edit->cursor < len ) {
edit->cursor++;
}
break;
case K_LEFTARROW:
if ( edit->cursor > 0 ) {
edit->cursor--;
}
break;
case K_HOME:
edit->cursor = 0;
break;
case K_END:
edit->cursor = len;
break;
case K_INS:
key_overstrikeMode = !key_overstrikeMode;
break;
default:
break;
}
// Change scroll if cursor is no longer visible
if ( edit->cursor < edit->scroll ) {
edit->scroll = edit->cursor;
} else if ( edit->cursor >= edit->scroll + edit->widthInChars && edit->cursor <= len ) {
edit->scroll = edit->cursor - edit->widthInChars + 1;
}
}
/*
==================
Field_CharEvent
==================
*/
void Field_CharEvent( field_t *edit, int ch ) {
int len;
if ( ch == 'v' - 'a' + 1 ) { // ctrl-v is paste
Field_Paste( edit );
return;
}
if ( ch == 'c' - 'a' + 1 ) { // ctrl-c clears the field
Field_Clear( edit );
return;
}
len = strlen( edit->buffer );
if ( ch == 'h' - 'a' + 1 ) { // ctrl-h is backspace
if ( edit->cursor > 0 ) {
memmove( edit->buffer + edit->cursor - 1,
edit->buffer + edit->cursor, len + 1 - edit->cursor );
edit->cursor--;
if ( edit->cursor < edit->scroll )
{
edit->scroll--;
}
}
return;
}
if ( ch == 'a' - 'a' + 1 ) { // ctrl-a is home
edit->cursor = 0;
edit->scroll = 0;
return;
}
if ( ch == 'e' - 'a' + 1 ) { // ctrl-e is end
edit->cursor = len;
edit->scroll = edit->cursor - edit->widthInChars;
return;
}
//
// ignore any other non printable chars
//
if ( ch < 32 ) {
return;
}
if ( key_overstrikeMode ) {
if ( edit->cursor == MAX_EDIT_LINE - 1 )
return;
edit->buffer[edit->cursor] = ch;
edit->cursor++;
} else { // insert mode
if ( len == MAX_EDIT_LINE - 1 ) {
return; // all full
}
memmove( edit->buffer + edit->cursor + 1,
edit->buffer + edit->cursor, len + 1 - edit->cursor );
edit->buffer[edit->cursor] = ch;
edit->cursor++;
}
if ( edit->cursor >= edit->widthInChars ) {
edit->scroll++;
}
if ( edit->cursor == len + 1) {
edit->buffer[edit->cursor] = 0;
}
}
/*
=============================================================================
CONSOLE LINE EDITING
==============================================================================
*/
/*
====================
Console_Key
Handles history and console scrollback
====================
*/
void Console_Key (int key) {
// ctrl-L clears screen
if ( key == 'l' && keys[K_CTRL].down ) {
Cbuf_AddText ("clear\n");
return;
}
// enter finishes the line
if ( key == K_ENTER || key == K_KP_ENTER ) {
// if not in the game explicitly prepend a slash if needed
if ( cls.state != CA_ACTIVE && g_consoleField.buffer[0] != '\\'
&& g_consoleField.buffer[0] != '/' ) {
char temp[MAX_EDIT_LINE-1];
Q_strncpyz( temp, g_consoleField.buffer, sizeof( temp ) );
Com_sprintf( g_consoleField.buffer, sizeof( g_consoleField.buffer ), "\\%s", temp );
g_consoleField.cursor++;
}
Com_Printf ( "]%s\n", g_consoleField.buffer );
// leading slash is an explicit command
if ( g_consoleField.buffer[0] == '\\' || g_consoleField.buffer[0] == '/' ) {
Cbuf_AddText( g_consoleField.buffer+1 ); // valid command
Cbuf_AddText ("\n");
} else {
// other text will be chat messages
if ( !g_consoleField.buffer[0] ) {
return; // empty lines just scroll the console without adding to history
} else {
Cbuf_AddText ("cmd say ");
Cbuf_AddText( g_consoleField.buffer );
Cbuf_AddText ("\n");
}
}
// copy line to history buffer
historyEditLines[nextHistoryLine % COMMAND_HISTORY] = g_consoleField;
nextHistoryLine++;
historyLine = nextHistoryLine;
Field_Clear( &g_consoleField );
g_consoleField.widthInChars = g_console_field_width;
CL_SaveConsoleHistory( );
if ( cls.state == CA_DISCONNECTED ) {
SCR_UpdateScreen (); // force an update, because the command
} // may take some time
return;
}
// command completion
if (key == K_TAB) {
Field_AutoComplete(&g_consoleField);
return;
}
// command history (ctrl-p ctrl-n for unix style)
if ( (key == K_MWHEELUP && keys[K_SHIFT].down) || ( key == K_UPARROW ) || ( key == K_KP_UPARROW ) ||
( ( tolower(key) == 'p' ) && keys[K_CTRL].down ) ) {
if ( nextHistoryLine - historyLine < COMMAND_HISTORY
&& historyLine > 0 ) {
historyLine--;
}
g_consoleField = historyEditLines[ historyLine % COMMAND_HISTORY ];
return;
}
if ( (key == K_MWHEELDOWN && keys[K_SHIFT].down) || ( key == K_DOWNARROW ) || ( key == K_KP_DOWNARROW ) ||
( ( tolower(key) == 'n' ) && keys[K_CTRL].down ) ) {
historyLine++;
if (historyLine >= nextHistoryLine) {
historyLine = nextHistoryLine;
Field_Clear( &g_consoleField );
g_consoleField.widthInChars = g_console_field_width;
return;
}
g_consoleField = historyEditLines[ historyLine % COMMAND_HISTORY ];
return;
}
// console scrolling
if ( key == K_PGUP ) {
Con_PageUp();
return;
}
if ( key == K_PGDN) {
Con_PageDown();
return;
}
if ( key == K_MWHEELUP) { //----(SA) added some mousewheel functionality to the console
Con_PageUp();
if(keys[K_CTRL].down) { // hold <ctrl> to accelerate scrolling
Con_PageUp();
Con_PageUp();
}
return;
}
if ( key == K_MWHEELDOWN) { //----(SA) added some mousewheel functionality to the console
Con_PageDown();
if(keys[K_CTRL].down) { // hold <ctrl> to accelerate scrolling
Con_PageDown();
Con_PageDown();
}
return;
}
// ctrl-home = top of console
if ( key == K_HOME && keys[K_CTRL].down ) {
Con_Top();
return;
}
// ctrl-end = bottom of console
if ( key == K_END && keys[K_CTRL].down ) {
Con_Bottom();
return;
}
// pass to the normal editline routine
Field_KeyDownEvent( &g_consoleField, key );
}
//============================================================================
/*
================
Message_Key
@@ -740,33 +211,14 @@ void Message_Key( int key ) {
if (key == K_ESCAPE) {
Key_SetCatcher( Key_GetCatcher( ) & ~KEYCATCH_MESSAGE );
Field_Clear( &chatField );
return;
}
if ( key == K_ENTER || key == K_KP_ENTER )
{
if ( chatField.buffer[0] && cls.state == CA_ACTIVE ) {
if (chat_playerNum != -1 )
Com_sprintf( buffer, sizeof( buffer ), "tell %i \"%s\"\n", chat_playerNum, chatField.buffer );
else if (chat_team)
Com_sprintf( buffer, sizeof( buffer ), "say_team \"%s\"\n", chatField.buffer );
else
Com_sprintf( buffer, sizeof( buffer ), "say \"%s\"\n", chatField.buffer );
CL_AddReliableCommand( buffer );
}
Key_SetCatcher( Key_GetCatcher( ) & ~KEYCATCH_MESSAGE );
Field_Clear( &chatField );
return;
}
Field_KeyDownEvent( &chatField, key );
}
//============================================================================
@@ -788,7 +240,7 @@ Key_IsDown
===================
*/
qboolean Key_IsDown( int keynum ) {
if ( keynum < 0 || keynum >= MAX_KEYS ) {
if ( keynum < 0 || keynum >= K_LASTKEY ) {
return qfalse;
}
@@ -870,7 +322,7 @@ const char *Key_KeynumToString( int keynum ) {
return "<KEY NOT FOUND>";
}
if ( keynum < 0 || keynum >= MAX_KEYS ) {
if ( keynum < 0 || keynum >= K_LASTKEY ) {
return "<OUT OF RANGE>";
}
@@ -917,7 +369,7 @@ const char *Key_KeynumToBindString( int keynum ) {
return "Not Bound";
}
if ( keynum < 0 || keynum >= MAX_KEYS ) {
if ( keynum < 0 || keynum >= K_LASTKEY ) {
return "Out of Range";
}
@@ -945,7 +397,7 @@ Key_SetBinding
===================
*/
void Key_SetBinding( int keynum, const char *binding ) {
if ( keynum < 0 || keynum >= MAX_KEYS ) {
if ( keynum < 0 || keynum >= K_LASTKEY ) {
return;
}
@@ -968,7 +420,7 @@ Key_SetAltBinding
===================
*/
void Key_SetAltBinding( int keynum, const char *binding ) {
if ( keynum < 0 || keynum >= MAX_KEYS ) {
if ( keynum < 0 || keynum >= K_LASTKEY ) {
return;
}
@@ -991,7 +443,7 @@ Key_SetCtrlBinding
===================
*/
void Key_SetCtrlBinding( int keynum, const char *binding ) {
if ( keynum < 0 || keynum >= MAX_KEYS ) {
if ( keynum < 0 || keynum >= K_LASTKEY ) {
return;
}
@@ -1015,7 +467,7 @@ Key_GetBinding
===================
*/
char *Key_GetBinding( int keynum ) {
if ( keynum < 0 || keynum >= MAX_KEYS ) {
if ( keynum < 0 || keynum >= K_LASTKEY ) {
return "";
}
@@ -1032,7 +484,7 @@ int Key_GetKey(const char *binding) {
int i;
if (binding) {
for (i=0 ; i < MAX_KEYS ; i++) {
for (i=0 ; i < K_LASTKEY ; i++) {
if (keys[i].binding && Q_stricmp(binding, keys[i].binding) == 0) {
return i;
}
@@ -1049,7 +501,7 @@ Key_GetKeynameForCommand
const char *Key_GetKeynameForCommand( const char *command ) {
int i;
for( i = 0; i < MAX_KEYS; i++ ) {
for( i = 0; i < K_LASTKEY; i++ ) {
if( !keys[ i ].binding ) {
continue;
}
@@ -1071,7 +523,7 @@ void Key_GetKeysForCommand( const char *command, int *key1, int *key2 ) {
*key1 = *key2 = 0;
for( i = 0; i < MAX_KEYS; i++ ) {
for( i = 0; i < K_LASTKEY; i++ ) {
if( !keys[ i ].binding ) {
continue;
}
@@ -1170,7 +622,7 @@ void Key_Unbindall_f (void)
{
int i;
for (i=0 ; i < MAX_KEYS; i++)
for (i=0 ; i < K_LASTKEY; i++)
if (keys[i].binding)
Key_SetBinding (i, "");
}
@@ -1323,7 +775,7 @@ void Key_WriteBindings( fileHandle_t f ) {
FS_Printf (f, "unbindall\n" );
for (i=0 ; i<MAX_KEYS ; i++) {
for (i=0 ; i<K_LASTKEY ; i++) {
if (keys[i].binding && keys[i].binding[0] ) {
FS_Printf (f, "bind %s \"%s\"\n", Key_KeynumToString(i), keys[i].binding);
@@ -1342,7 +794,7 @@ Key_Bindlist_f
void Key_Bindlist_f( void ) {
int i;
for ( i = 0 ; i < MAX_KEYS ; i++ ) {
for ( i = 0 ; i < K_LASTKEY ; i++ ) {
if ( keys[i].binding && keys[i].binding[0] ) {
Com_Printf( "%s \"%s\"\n", Key_KeynumToString(i), keys[i].binding );
}
@@ -1358,7 +810,7 @@ Key_AltBindlist_f
void Key_AltBindlist_f( void ) {
int i;
for ( i = 0 ; i < MAX_KEYS ; i++ ) {
for ( i = 0 ; i < K_LASTKEY ; i++ ) {
if ( altkeys[i].binding && altkeys[i].binding[0] ) {
Com_Printf( "%s \"%s\"\n", Key_KeynumToString(i), altkeys[i].binding );
}
@@ -1374,7 +826,7 @@ Key_CtrlBindlist_f
void Key_CtrlBindlist_f( void ) {
int i;
for ( i = 0 ; i < MAX_KEYS ; i++ ) {
for ( i = 0 ; i < K_LASTKEY ; i++ ) {
if ( ctrlkeys[i].binding && ctrlkeys[i].binding[0] ) {
Com_Printf( "%s \"%s\"\n", Key_KeynumToString(i), ctrlkeys[i].binding );
}
@@ -1487,11 +939,11 @@ void CL_KeyEvent (int key, qboolean down, unsigned time) {
}
}
if( ( key == K_ALT || key == K_INS ) && cl_altbindings->integer ) {
if( ( key == K_LALT || key == K_INS ) && cl_altbindings->integer ) {
alt_down = down;
}
if( ( key == K_CTRL || key == K_DEL ) && cl_ctrlbindings->integer ) {
if( ( key == K_LCTRL || key == K_DEL ) && cl_ctrlbindings->integer ) {
ctrl_down = down;
}
@@ -1521,10 +973,10 @@ void CL_KeyEvent (int key, qboolean down, unsigned time) {
if( down )
{
if( alt_down && key != K_ALT && key != K_INS ) {
if( alt_down && key != K_LALT && key != K_INS ) {
altkeys[ key ].down = down;
}
if( down && ctrl_down && key != K_CTRL ) {
if( down && ctrl_down && key != K_LCTRL ) {
ctrlkeys[ key ].down = down;
}
}
@@ -1537,7 +989,7 @@ void CL_KeyEvent (int key, qboolean down, unsigned time) {
{
if (down)
{
if (keys[K_ALT].down)
if (keys[K_LALT].down)
{
Key_ClearStates();
Cvar_SetValue( "r_fullscreen",
@@ -1713,7 +1165,7 @@ void Key_ClearStates (void)
anykeydown = 0;
for ( i=0 ; i < MAX_KEYS ; i++ ) {
for ( i=0 ; i < K_LASTKEY ; i++ ) {
if ( keys[i].down ) {
CL_KeyEvent( i, qfalse, 0 );
@@ -1740,142 +1192,5 @@ Key_SetCatcher
====================
*/
void Key_SetCatcher( int catcher ) {
// If the catcher state is changing, clear all key states
if( catcher != keyCatchers )
Key_ClearStates( );
keyCatchers = catcher;
}
// This must not exceed MAX_CMD_LINE
#define MAX_CONSOLE_SAVE_BUFFER 1024
#define CONSOLE_HISTORY_FILE "omhistory"
static char consoleSaveBuffer[ MAX_CONSOLE_SAVE_BUFFER ];
static int consoleSaveBufferSize = 0;
/*
================
CL_LoadConsoleHistory
Load the console history from cl_consoleHistory
================
*/
void CL_LoadConsoleHistory( void )
{
const char *token;
char *text_p;
int i, numChars, numLines = 0;
fileHandle_t f;
consoleSaveBufferSize = FS_FOpenFileRead( CONSOLE_HISTORY_FILE, &f, qfalse, qtrue );
if( !f )
{
Com_Printf( "Couldn't read %s.\n", CONSOLE_HISTORY_FILE );
return;
}
if( consoleSaveBufferSize <= MAX_CONSOLE_SAVE_BUFFER &&
FS_Read( consoleSaveBuffer, consoleSaveBufferSize, f ) == consoleSaveBufferSize )
{
text_p = consoleSaveBuffer;
for( i = COMMAND_HISTORY - 1; i >= 0; i-- )
{
if( !*( token = COM_Parse( &text_p ) ) )
break;
historyEditLines[ i ].cursor = atoi( token );
if( !*( token = COM_Parse( &text_p ) ) )
break;
historyEditLines[ i ].scroll = atoi( token );
if( !*( token = COM_Parse( &text_p ) ) )
break;
numChars = atoi( token );
text_p++;
if( numChars > ( strlen( consoleSaveBuffer ) - ( text_p - consoleSaveBuffer ) ) )
{
Com_DPrintf( S_COLOR_YELLOW "WARNING: probable corrupt history\n" );
break;
}
Com_Memcpy( historyEditLines[ i ].buffer,
text_p, numChars );
historyEditLines[ i ].buffer[ numChars ] = '\0';
text_p += numChars;
numLines++;
}
memmove( &historyEditLines[ 0 ], &historyEditLines[ i + 1 ],
numLines * sizeof( field_t ) );
for( i = numLines; i < COMMAND_HISTORY; i++ )
Field_Clear( &historyEditLines[ i ] );
historyLine = nextHistoryLine = numLines;
}
else
Com_Printf( "Couldn't read %s.\n", CONSOLE_HISTORY_FILE );
FS_FCloseFile( f );
}
/*
================
CL_SaveConsoleHistory
Save the console history into the cvar cl_consoleHistory
so that it persists across invocations of q3
================
*/
void CL_SaveConsoleHistory( void )
{
int i;
int lineLength, saveBufferLength, additionalLength;
fileHandle_t f;
consoleSaveBuffer[ 0 ] = '\0';
i = ( nextHistoryLine - 1 ) % COMMAND_HISTORY;
do
{
if( historyEditLines[ i ].buffer[ 0 ] )
{
lineLength = strlen( historyEditLines[ i ].buffer );
saveBufferLength = strlen( consoleSaveBuffer );
//ICK
additionalLength = lineLength + strlen( "999 999 999 " );
if( saveBufferLength + additionalLength < MAX_CONSOLE_SAVE_BUFFER )
{
Q_strcat( consoleSaveBuffer, MAX_CONSOLE_SAVE_BUFFER,
va( "%d %d %d %s ",
historyEditLines[ i ].cursor,
historyEditLines[ i ].scroll,
lineLength,
historyEditLines[ i ].buffer ) );
}
else
break;
}
i = ( i - 1 + COMMAND_HISTORY ) % COMMAND_HISTORY;
}
while( i != ( nextHistoryLine - 1 ) % COMMAND_HISTORY );
consoleSaveBufferSize = strlen( consoleSaveBuffer );
f = FS_FOpenFileWrite( CONSOLE_HISTORY_FILE );
if( !f )
{
Com_Printf( "Couldn't write %s.\n", CONSOLE_HISTORY_FILE );
return;
}
if( FS_Write( consoleSaveBuffer, consoleSaveBufferSize, f ) < consoleSaveBufferSize )
Com_Printf( "Couldn't write %s.\n", CONSOLE_HISTORY_FILE );
FS_FCloseFile( f );
}
+84 -140
View File
@@ -24,6 +24,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#include "client.h"
#include "server.h"
#include "cl_ui.h"
#include "tiki.h"
#include <cm_terrain.h>
#include "../sys/sys_local.h"
#include <limits.h>
@@ -97,6 +98,17 @@ cvar_t *cl_r_fullscreen;
cvar_t *cl_consoleKeys;
cvar_t* j_pitch;
cvar_t* j_yaw;
cvar_t* j_forward;
cvar_t* j_side;
cvar_t* j_up;
cvar_t* j_pitch_axis;
cvar_t* j_yaw_axis;
cvar_t* j_forward_axis;
cvar_t* j_side_axis;
cvar_t* j_up_axis;
clientActive_t cl;
clientConnection_t clc;
clientStatic_t cls;
@@ -407,7 +419,8 @@ void CL_Record_f( void ) {
continue;
}
MSG_WriteByte (&buf, svc_baseline);
MSG_WriteDeltaEntity (&buf, &nullstate, ent, qtrue );
// FIXME
MSG_WriteDeltaEntity (&buf, &nullstate, ent, qtrue, 0.0 );
}
MSG_WriteByte( &buf, svc_EOF );
@@ -675,7 +688,7 @@ void CL_PlayDemo_f( void ) {
}
Q_strncpyz( clc.demoName, Cmd_Argv(1), sizeof( clc.demoName ) );
Con_Close();
UI_CloseConsole();
cls.state = CA_CONNECTED;
clc.demoplaying = qtrue;
@@ -789,40 +802,38 @@ memory on the hunk from cgame, ui, and renderer
=====================
*/
void CL_MapLoading( qboolean flush, const char *pszMapName ) {
if ( com_dedicated->integer ) {
cls.state = CA_DISCONNECTED;
Key_SetCatcher( KEYCATCH_CONSOLE );
return;
}
if ( !com_cl_running->integer ) {
return;
}
Con_Close();
Key_SetCatcher( 0 );
UI_ClearState();
UI_ForceMenuOff(false);
// if we are already connected to the local host, stay connected
if ( cls.state >= CA_CONNECTED && !Q_stricmp( cls.servername, "localhost" ) ) {
cls.state = CA_CONNECTED; // so the connect screen is drawn
Com_Memset( cls.updateInfoString, 0, sizeof( cls.updateInfoString ) );
Com_Memset( clc.serverMessage, 0, sizeof( clc.serverMessage ) );
Com_Memset( &cl.gameState, 0, sizeof( cl.gameState ) );
clc.lastPacketSentTime = -9999;
SCR_UpdateScreen();
} else {
// clear nextmap so the cinematic shutdown doesn't execute it
Cvar_Set( "nextmap", "" );
CL_Disconnect( qtrue );
Q_strncpyz( cls.servername, "localhost", sizeof(cls.servername) );
cls.state = CA_CHALLENGING; // so the connect screen is drawn
Key_SetCatcher( 0 );
SCR_UpdateScreen();
clc.connectTime = -RETRANSMIT_TIMEOUT;
NET_StringToAdr( cls.servername, &clc.serverAddress);
// we don't need a challenge on the localhost
if (pszMapName) {
// if we are already connected to the local host, stay connected
if (cls.state >= CA_CONNECTED && !Q_stricmp(cls.servername, "localhost")) {
cls.state = CA_CONNECTED; // so the connect screen is drawn
Com_Memset(cls.updateInfoString, 0, sizeof(cls.updateInfoString));
Com_Memset(clc.serverMessage, 0, sizeof(clc.serverMessage));
Com_Memset(&cl.gameState, 0, sizeof(cl.gameState));
clc.lastPacketSentTime = -9999;
}
else {
// clear nextmap so the cinematic shutdown doesn't execute it
Cvar_Set("nextmap", "");
CL_Disconnect(qtrue);
Q_strncpyz(cls.servername, "localhost", sizeof(cls.servername));
cls.state = CA_CHALLENGING; // so the connect screen is drawn
clc.connectStartTime = cls.realtime;
clc.connectTime = -RETRANSMIT_TIMEOUT;
NET_StringToAdr(cls.servername, &clc.serverAddress);
// we don't need a challenge on the localhost
CL_CheckForResend();
CL_CheckForResend();
}
CL_FlushMemory();
UI_BeginLoad(pszMapName);
}
}
@@ -1205,7 +1216,7 @@ void CL_Connect( const char *server ) {
SV_Frame( 0 );
CL_Disconnect( qtrue );
Con_Close();
UI_CloseConsole();
/* MrE: 2000-09-13: now called in CL_DownloadsComplete
CL_FlushMemory( );
@@ -1228,11 +1239,6 @@ void CL_Connect( const char *server ) {
Com_Printf( "%s resolved to %s\n", cls.servername, serverString );
if( cl_guidServerUniq->integer )
CL_UpdateGUID( serverString, strlen( serverString ) );
else
CL_UpdateGUID( NULL, 0 );
// if we aren't playing on a lan, we need to authenticate
// with the cd key
// wombat: no authorization in mohaa. need to send challenge to server though
@@ -1243,9 +1249,9 @@ void CL_Connect( const char *server ) {
cls.state = CA_CONNECTING;
}
Key_SetCatcher( 0 );
clc.connectTime = -99999; // CL_CheckForResend() will fire immediately
clc.connectPacketCount = 0;
clc.connectStartTime = 0;
// server connection string
Cvar_Set( "cl_currentServerAddress", server );
@@ -1265,7 +1271,7 @@ void CL_Connect_f( void ) {
Com_Printf( "usage: connect [server]\n");
return;
}
server = Cmd_Argv (1);
CL_Connect( server );
@@ -1595,34 +1601,11 @@ void CL_DownloadsComplete( void ) {
// let the client game init and load data
cls.state = CA_LOADING;
// Pump the loop, this may change gamestate!
Com_EventLoop();
CL_StartHunkUsers();
// Pump the loop, this may change gamestate!
Com_EventLoop();
// if the gamestate was changed by calling Com_EventLoop
// then we loaded everything already and we don't want to do it again.
if ( cls.state != CA_LOADING ) {
return;
}
// starting to load a map so we get out of full screen ui mode
Cvar_Set("r_uiFullScreen", "0");
// flush client memory and start loading stuff
// this will also (re)load the UI
// if this is a local client then only the client part of the hunk
// will be cleared, note that this is done after the hunk mark has been set
CL_FlushMemory();
// initialize the CGame
cls.cgameStarted = qtrue;
CL_InitCGame();
// set pure checksums
CL_SendPureChecksums();
CL_WritePacket();
CL_WritePacket();
CL_WritePacket();
CL_StartHunkUsers();
}
/*
@@ -2322,6 +2305,10 @@ void CL_CheckUserinfo( void ) {
}
}
void CL_SetFrameNumber(int frameNumber) {
re.SetFrameNumber(frameNumber);
}
/*
==================
CL_Frame
@@ -2346,14 +2333,13 @@ void CL_Frame ( int msec ) {
cls.realtime += cls.frametime;
SCR_UpdateScreen();
S_Update();
Con_RunConsole();
cls.framecount++;
return;
}
}
#endif
if ( cls.state == CA_DISCONNECTED && !( Key_GetCatcher( ) & KEYCATCH_UI )
if ( cls.state == CA_DISCONNECTED && !UI_MenuActive()
&& !com_sv_running->integer ) {
// if disconnected, bring up the menu
S_StopAllSounds( qtrue );
@@ -2461,8 +2447,6 @@ void CL_Frame ( int msec ) {
// advance local effects for next frame
SCR_RunCinematic();
Con_RunConsole();
cls.framecount++;
}
@@ -2480,16 +2464,18 @@ void QDECL CL_RefPrintf( int print_level, const char *fmt, ...) {
va_list argptr;
char msg[MAXPRINTMSG];
va_start (argptr,fmt);
Q_vsnprintf (msg, sizeof(msg), fmt, argptr);
va_end (argptr);
va_start(argptr, fmt);
Q_vsnprintf(msg, sizeof(msg), fmt, argptr);
va_end(argptr);
if ( print_level == PRINT_ALL ) {
Com_Printf ("%s", msg);
} else if ( print_level == PRINT_WARNING ) {
Com_Printf (S_COLOR_YELLOW "%s", msg); // yellow
} else if ( print_level == PRINT_DEVELOPER ) {
Com_DPrintf (S_COLOR_RED "%s", msg); // red
if (print_level == PRINT_ALL) {
Com_Printf("%s", msg);
}
else if (print_level == PRINT_WARNING || print_level == PRINT_DEVELOPER) {
Com_DPrintf("%s", msg);
}
else if (print_level == PRINT_DEVELOPER_2 && developer->integer) {
Com_DPrintf("%s", msg);
}
}
@@ -2528,27 +2514,6 @@ void CL_ShutdownRef( void ) {
#endif
}
/*
============
CL_InitRenderer
============
*/
void CL_InitRenderer( void ) {
// this sets up the renderer and calls R_Init
re.BeginRegistration( &cls.glconfig );
// load character sets
cls.charSetShader = re.RegisterShader( "gfx/2d/bigchars" );
cls.whiteShader = re.RegisterShader( "*white" );
// cls.consoleShader = re.RegisterShader( "console" );
re.RegisterFont("courier-16", 0, &cls.consoleFont);
g_console_field_width = cls.glconfig.vidWidth / SMALLCHAR_WIDTH - 2;
g_consoleField.widthInChars = g_console_field_width;
// IneQuation
g_console_charWidth = re.Text_Width(&cls.consoleFont, "=", 0, qfalse);
g_console_charHeight = re.Text_Height(&cls.consoleFont, "|", 0, qfalse);
}
/*
============================
CL_StartHunkUsers
@@ -2588,7 +2553,7 @@ void CL_StartHunkUsers( void ) {
CL_RefMalloc
============
*/
void *CL_RefMalloc( int size ) {
void *CL_RefMalloc(size_t size) {
return Z_TagMalloc( size, TAG_RENDERER );
}
@@ -2607,7 +2572,7 @@ void CL_RefClear( void )
CL_RefStaticMalloc
============
*/
void *CL_RefStaticMalloc( int size ) {
void *CL_RefStaticMalloc( size_t size ) {
void *ptr = Z_TagMalloc( size, TAG_STATIC_RENDERER );
Com_Memset( ptr, 0, size );
return ptr;
@@ -2627,7 +2592,7 @@ void CL_RefStaticClear( void ) {
CL_CG_PermanentMark
============
*/
int CL_CG_PermanentMark( vec3_t origin, vec3_t dir, float orientation,
int CL_CG_PermanentMark(const vec3_t origin, const vec3_t dir, float orientation,
float fSScale, float fTScale, float red, float green, float blue, float alpha,
qboolean dolighting, float fSCenter, float fTCenter,
markFragment_t *pMarkFragments, void *pPolyVerts )
@@ -2720,14 +2685,17 @@ void CL_InitRef( void ) {
ri.Malloc = CL_RefMalloc;
ri.Free = Z_Free;
ri.Clear = CL_RefClear;
ri.Hunk_Clear = CL_RefStaticClear;
ri.Hunk_Alloc = Hunk_Alloc;
ri.Hunk_Clear = CL_RefStaticClear;
#ifdef HUNK_DEBUG
ri.Hunk_AllocDebug = Hunk_AllocDebug;
#else
ri.Hunk_Alloc = CL_RefStaticMalloc;
#endif
ri.Hunk_AllocateTempMemory = Hunk_AllocateTempMemory;
ri.Hunk_FreeTempMemory = Hunk_FreeTempMemory;
ri.CM_DrawDebugSurface = CM_DrawDebugSurface;
ri.CM_ClusterPVS = CM_ClusterPVS;
ri.FS_FOpenFile = FS_FOpenFileRead;
ri.FS_OpenFile = FS_FOpenFileRead;
ri.FS_CloseFile = FS_FCloseFile;
ri.FS_Read = FS_Read;
ri.FS_Seek = FS_Seek;
@@ -2767,18 +2735,6 @@ void CL_InitRef( void ) {
ri.GetCentroidRadiusInternal = TIKI_GetCentroidRadiusInternal;
ri.GetFrameInternal = TIKI_GetFrameInternal;
// cinematic stuff
ri.CIN_UploadCinematic = CIN_UploadCinematic;
ri.CIN_PlayCinematic = CIN_PlayCinematic;
ri.CIN_RunCinematic = CIN_RunCinematic;
ri.CL_WriteAVIVideoFrame = CL_WriteAVIVideoFrame;
ri.IN_Init = IN_Init;
ri.IN_Shutdown = IN_Shutdown;
//ri.IN_Restart = IN_Restart;
#ifdef USE_RENDERER_DLL
// su44: load renderer dll
cl_renderer = Cvar_Get("cl_renderer", "glom", CVAR_ARCHIVE);
@@ -2847,27 +2803,13 @@ qboolean CL_SetVidMode( int mode ) {
}
void CL_SetFullscreen( qboolean fullscreen ) {
re.SetFullscreen( fullscreen, &cls.glconfig );
re.SetFullscreen( fullscreen );
if( cge ) {
cge->CG_GetRendererConfig();
}
}
void CL_SetModel_f( void ) {
char *arg;
char name[256];
arg = Cmd_Argv( 1 );
if (arg[0]) {
Cvar_Set( "model", arg );
Cvar_Set( "headmodel", arg );
} else {
Cvar_VariableStringBuffer( "model", name, sizeof(name) );
Com_Printf("model is set to %s\n", name);
}
}
void CL_VidMode_f( void ) {
char text[ 16 ];
int mode;
@@ -2994,6 +2936,8 @@ it by filling it with 2048 bytes of random data.
*/
static void CL_GenerateQKey(void)
{
// FIXME: unimplemented
/*
int len = 0;
unsigned char buff[ QKEY_SIZE ];
fileHandle_t f;
@@ -3023,6 +2967,7 @@ static void CL_GenerateQKey(void)
FS_FCloseFile( f );
Com_Printf( "QKEY generated\n" );
}
*/
}
/*
@@ -3043,13 +2988,11 @@ void CL_Init( void ) {
start = Sys_Milliseconds();
Con_Init ();
CL_ClearState ();
S_StopAllSounds( qtrue );
cls.state = CA_DISCONNECTED; // no longer CA_UNINITIALIZED
cls.keyCatchers = 2;
Key_SetCatcher(KEYCATCH_UI);
cls.realtime = 0;
CL_InitInput ();
@@ -3208,7 +3151,6 @@ void CL_Init( void ) {
Cmd_AddCommand ("showip", CL_ShowIP_f );
Cmd_AddCommand ("fs_openedList", CL_OpenedPK3List_f );
Cmd_AddCommand ("fs_referencedList", CL_ReferencedPK3List_f );
Cmd_AddCommand ("model", CL_SetModel_f );
Cmd_AddCommand ("video", CL_Video_f );
Cmd_AddCommand ("stopvideo", CL_StopVideo_f );
CL_InitConsoleCommands();
@@ -3292,10 +3234,9 @@ void CL_Shutdown( void ) {
recursive = qfalse;
Com_Memset( &cls, 0, sizeof( cls ) );
Key_SetCatcher( 0 );
Com_Printf( "-----------------------\n" );
Z_FreeTags(TAG_CLIENT);
cl_bCLSystemStarted = qfalse;
}
@@ -3688,6 +3629,8 @@ CL_GamespyServers_f
#define MAX_GAMESPYSERVERS 16
void CL_GamespyServers_f( void ) {
// FIXME: unimplemented
#if 0
char buffer[10240];
int bytesRead;
@@ -3793,6 +3736,7 @@ void CL_GamespyServers_f( void ) {
Com_Printf("%d servers parsed (total %d)\n", numservers, total);
Cvar_Set( "dm_serverstatus", "Server List Received.");
Cvar_SetValue( "dm_servercount", total );
#endif
}
+20 -9
View File
@@ -22,6 +22,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
// cl_parse.c -- parse a message received from the server
#include "client.h"
#include "cl_ui.h"
char *svc_strings[256] = {
"svc_bad",
@@ -74,7 +75,8 @@ void CL_DeltaEntity (msg_t *msg, clSnapshot_t *frame, int newnum, entityState_t
if ( unchanged ) {
*state = *old;
} else {
MSG_ReadDeltaEntity( msg, old, state, newnum );
// FIXME: frametime
MSG_ReadDeltaEntity( msg, old, state, newnum, 0.0);
}
if ( state->number == (MAX_GENTITIES-1) ) {
@@ -271,11 +273,12 @@ void CL_ParseSnapshot( msg_t *msg ) {
MSG_ReadData( msg, &newSnap.areamask, len);
// read playerinfo
SHOWNET( msg, "playerstate" );
SHOWNET(msg, "playerstate");
// FIXME: frametime
if ( old ) {
MSG_ReadDeltaPlayerstate( msg, &old->ps, &newSnap.ps );
MSG_ReadDeltaPlayerstate( msg, &old->ps, &newSnap.ps, 0.0 );
} else {
MSG_ReadDeltaPlayerstate( msg, NULL, &newSnap.ps );
MSG_ReadDeltaPlayerstate( msg, NULL, &newSnap.ps, 0.0);
}
// read packet entities
@@ -456,9 +459,12 @@ void CL_ParseGamestate( msg_t *msg ) {
int cmd;
char *s;
Con_Close();
UI_CloseConsole();
clc.connectPacketCount = 0;
if (cls.cgameStarted) {
CL_FlushMemory();
}
// wipe local client state
CL_ClearState();
@@ -500,7 +506,8 @@ void CL_ParseGamestate( msg_t *msg ) {
//Com_Memset (&nullstate, 0, sizeof(nullstate));
MSG_GetNullEntityState(&nullstate);
es = &cl.entityBaselines[ newnum ];
MSG_ReadDeltaEntity( msg, &nullstate, es, newnum );
// FIXME: frametime
MSG_ReadDeltaEntity( msg, &nullstate, es, newnum, 0.0);
} else {
Com_Error( ERR_DROP, "CL_ParseGamestate: bad command byte %i", cmd );
}
@@ -510,9 +517,6 @@ void CL_ParseGamestate( msg_t *msg ) {
// read the checksum feed
clc.checksumFeed = MSG_ReadLong( msg );
// parse useful values out of CS_SERVERINFO
CL_ParseServerInfo();
// parse serverId and other cvars
CL_SystemInfoChanged();
@@ -523,6 +527,13 @@ void CL_ParseGamestate( msg_t *msg ) {
// reinitialize the filesystem if the game directory has changed
FS_ConditionalRestart( clc.checksumFeed );
if (!com_sv_running->integer)
{
const char *info = cl.gameState.stringData + cl.gameState.stringOffsets[CS_SERVERINFO];
UI_ClearState();
UI_BeginLoad(Info_ValueForKey(info, "mapname"));
}
// This used to call CL_StartHunkUsers, but now we enter the download state before loading the
// cgame
CL_InitDownloads();
+1 -1
View File
@@ -535,7 +535,7 @@ void SCR_UpdateScreen( void ) {
return;
}
recursive = 1;
CL_StartHunkUsers();
SCR_SimpleUpdateScreen();
-1212
View File
File diff suppressed because it is too large. Load diff
+688 -674
View File
File diff suppressed because it is too large. Load diff
+4 -2
View File
@@ -42,11 +42,12 @@ void CL_ShutdownUI( void );
//
extern inventory_t client_inv;
extern bind_t client_bind;
extern cvar_t* cl_greenfps;
const char *CvarGetForUI( const char *name, const char *defval );
void UI_ClearState( void );
void CL_BeginRegistration( void );
void CL_EndRegistration( void );
void CL_EndRegistration(void);
//
// menu
@@ -72,7 +73,7 @@ void UI_HideScoreboard_f( void );
void UI_SetScoreBoardItem( int iItemNumber,
const char *pszData1, const char *pszData2, const char *pszData3, const char *pszData4,
const char *pszData5, const char *pszData6, const char *pszData7, const char *pszData8,
vec4_t pTextColor, vec4_t pBackColor, qboolean bIsHeader );
const vec4_t pTextColor, const vec4_t pBackColor, qboolean bIsHeader );
void UI_DeleteScoreBoardItems( int iMaxIndex );
//
@@ -107,6 +108,7 @@ void UI_CloseDMConsole( void );
void UI_ToggleDMConsole( int iMode );
void UI_OpenDeveloperConsole( void );
void UI_CloseDeveloperConsole( void );
void UI_PrintConsole(const char* msg);
//
// callbacks
+316 -21
View File
@@ -22,100 +22,395 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#include "cl_ui.h"
Event EV_DMBox_Goin
(
"_dmbox_goin",
EV_DEFAULT,
NULL,
NULL,
"Event to make the dmbox disappear"
);
Event EV_DMBox_Decay
(
"_dmbox_decay",
EV_DEFAULT,
NULL,
NULL,
"Event to make the dmbox console line decay"
);
static float s_dmboxWidth = 384.0;
CLASS_DECLARATION( UIWidget, UIDMBox, NULL )
{
{ &W_SizeChanged, &UIDMBox::OnSizeChanged },
{ &EV_DMBox_Goin, &UIDMBox::MoveInEvent },
{ &EV_DMBox_Decay, &UIDMBox::DecayEvent },
{ NULL, NULL }
};
UIDMBox::UIDMBox()
{
m_numitems = 0;
m_reallyshown = true;
m_fontbold = NULL;
m_boxstate = boxstate_t::box_out;
m_iBeginDecay = 0;
m_boxtime = uid.time;
m_movespeed = 500;
}
void UIDMBox::VerifyBoxOut( void )
{
// FIXME: stub
PostMoveinEvent();
if (m_boxstate != boxstate_t::box_moving_out && m_boxstate != boxstate_t::box_out)
{
ChangeBoxState(boxstate_t::box_moving_out);
}
}
void UIDMBox::ChangeBoxState( boxstate_t state )
{
// FIXME: stub
m_boxstate = state;
m_boxtime = uid.time;
setShowState();
if (state == box_out) {
PostMoveinEvent();
}
}
void UIDMBox::HandleBoxMoving( void )
{
// FIXME: stub
int delta;
UIRect2D newRect;
if (m_boxstate != boxstate_t::box_moving_out && m_boxstate != boxstate_t::box_moving_in) {
return;
}
delta = m_movespeed * (uid.time - m_boxtime) / 1000;
m_boxtime = 1000 * delta / m_movespeed + m_boxtime;
if (m_boxstate == boxstate_t::box_moving_out)
{
newRect.size.width = m_frame.size.width;
newRect.size.height = m_frame.size.height;
newRect.pos.x = m_frame.pos.x;
newRect.pos.y = delta + m_frame.pos.y;
if (newRect.pos.y <= 0.0)
{
newRect.pos.y = 0.0;
ChangeBoxState(boxstate_t::box_out);
}
}
else if (m_boxstate == boxstate_t::box_moving_in)
{
newRect.size.width = m_frame.size.width;
newRect.size.height = m_frame.size.height;
newRect.pos.x = m_frame.pos.x;
newRect.pos.y = delta - m_frame.pos.y;
if (newRect.pos.y <= -newRect.size.height)
{
newRect.pos.y = -newRect.size.height;
ChangeBoxState(boxstate_t::box_in);
}
}
else {
newRect = m_frame;
}
setFrame(newRect);
}
void UIDMBox::PostMoveinEvent( void )
{
// FIXME: stub
if (m_boxstate != boxstate_t::box_out) {
return;
}
if (!EventPending(EV_DMBox_Goin)) {
PostEvent(EV_DMBox_Goin, 10.0);
}
else {
PostponeEvent(EV_DMBox_Goin, 10.0);
}
}
void UIDMBox::PostDecayEvent( void )
{
// FIXME: stub
if (!EventPending(EV_DMBox_Decay))
{
float fDelayTime;
int iNumLines;
int i;
const char* pszString = m_items[0].string.c_str();
//
// Calculate the number of lines
//
iNumLines = 1;
for (i = 0; pszString[i]; i++)
{
if (pszString[i] == '\n') {
iNumLines++;
}
}
//
// Bold as twice more decay
//
if (m_items[0].flags & DMBOX_ITEM_FLAG_BOLD) {
fDelayTime = iNumLines * 6.0;
}
else {
fDelayTime = iNumLines * 5.0;
}
m_iBeginDecay = cls.realtime;
m_iEndDecay = (int)(fDelayTime * 1000.0);
PostEvent(EV_DMBox_Decay, fDelayTime);
}
}
void UIDMBox::setShowState( void )
{
// FIXME: stub
if (m_reallyshown) {
setShow(m_boxstate != box_in);
} else {
setShow(false);
}
}
void UIDMBox::RemoveTopItem( void )
{
// FIXME: stub
int i;
for (i = 0; i < m_numitems - 1; i++) {
m_items[i] = m_items[i + 1];
}
m_numitems--;
}
str UIDMBox::CalculateBreaks( UIFont *font, str text, float max_width )
{
// FIXME: stub
return "";
str newText, sTmp;
int i;
float fX;
float fwX, fsX;
Cmd_TokenizeString(text.c_str());
if (Cmd_Argc())
{
fX = 0.0;
fsX = font->getCharWidth(' ');
for (i = 0; i < Cmd_Argc(); i++)
{
sTmp = Cmd_Argv(i);
fwX = font->getWidth(sTmp.c_str(), -1);
if (fwX + i <= max_width)
{
if (fwX + i + fX <= max_width)
{
newText += sTmp + " ";
} else {
newText += "\n" + sTmp + " ";
}
}
else
{
sTmp += "\n";
fX = 0.0;
}
}
} else {
newText = "";
}
return newText;
}
float UIDMBox::PrintWrap( UIFont *font, float x, float y, str text )
{
// FIXME: stub
return 0.0f;
const char* p1, * p2;
size_t n, l;
float fY;
fY = y;
p1 = text.c_str();
l = text.length();
for (;;)
{
p2 = strchr(p1, '\n');
if (!p2) {
break;
}
n = p2 - p1;
if (n >= l) {
break;
}
font->Print(x, fY, p1, p2 - p1, qfalse);
p1 = p2 + 1;
l -= n;
fY += font->getHeight(qfalse);
}
font->Print(x, fY, p1, l, qfalse);
return font->getHeight(qfalse) + (fY - y);
}
float UIDMBox::DrawItem( item_t *in, float x, float y, float alpha )
{
// FIXME: stub
return 0.0f;
in->font->setColor(in->color);
in->font->setAlpha(alpha);
return PrintWrap(in->font, x, y, in->string);
}
void UIDMBox::Print( const char *text )
{
// FIXME: stub
const char* text1 = text;
if (m_numitems > 4)
{
//
// Overwrite an item
//
RemoveTopItem();
}
m_items[m_numitems].flags = 0;
if (*text == 2)
{
m_items[m_numitems].color = UGrey;
m_items[m_numitems].font = m_fontbold;
m_items[m_numitems].flags |= GMBOX_ITEM_FLAG_BOLD;
text1 = text + 1;
}
else if (*text == 4)
{
m_items[m_numitems].color = ULightRed;
m_items[m_numitems].font = m_fontbold;
m_items[m_numitems].flags |= GMBOX_ITEM_FLAG_BOLD;
text1 = text + 1;
}
else
{
m_items[m_numitems].color = m_foreground_color;
m_items[m_numitems].font = m_font;
}
m_items[m_numitems].string = CalculateBreaks(m_items[m_numitems].font, text1, s_dmboxWidth);
m_numitems++;
VerifyBoxOut();
PostDecayEvent();
}
void UIDMBox::OnSizeChanged( Event *ev )
{
// FIXME: stub
s_dmboxWidth = m_frame.size.width;
}
void UIDMBox::Create( const UIRect2D& rect, const UColor& fore, const UColor& back, float alpha )
{
// FIXME: stub
InitFrame(NULL, rect, 0, "facfont-20");
if (!m_fontbold) {
m_fontbold = new UIFont("facfont-20");
}
m_fontbold->setColor(URed);
setBackgroundColor(back, true);
setForegroundColor(fore);
setBackgroundAlpha(alpha);
Connect(this, W_SizeChanged, W_SizeChanged);
OnSizeChanged(NULL);
m_movespeed = rect.size.height * 3.0;
setShowState();
}
void UIDMBox::MoveInEvent( Event *ev )
{
// FIXME: stub
}
void UIDMBox::DecayEvent( Event *ev )
{
// FIXME: stub
RemoveTopItem();
if (m_numitems) {
PostDecayEvent();
}
}
void UIDMBox::Draw( void )
{
// FIXME: stub
float fsY;
int i;
float alpha;
float alphaScale;
alphaScale = 0.8;
HandleBoxMoving();
if (!m_numitems) {
//
// Nothing to show
//
return;
}
m_font->setColor(m_foreground_color);
alpha = (float)(cls.realtime - m_iBeginDecay) / (float)m_iEndDecay;
if (alpha > 1.0) alpha = 1.0;
alpha = (1.0 - alpha) * 4.0;
if (alpha > 1.0) alpha = 1.0;
if (cge) {
alphaScale = 1.0 - cge->CG_GetObjectiveAlpha();
}
fsY = DrawItem(m_items, 0.0, 8.0, alpha * alphaScale);
fsY = alpha <= 0.2 ? 8.0 : fsY + 8.0;
for (i = 1; i < m_numitems; i++)
{
fsY += DrawItem(&m_items[i], 0.0, fsY, alphaScale);
if (fsY > m_frame.size.height)
{
if (EventPending(EV_DMBox_Decay)) {
CancelEventsOfType(EV_DMBox_Decay);
}
PostEvent(EV_DMBox_Decay, 0.0);
break;
}
}
}
void UIDMBox::setRealShow( bool b )
{
// FIXME: stub
this->m_reallyshown = b;
setShowState();
}
void UIDMBox::Clear( void )
{
// FIXME: stub
m_numitems = 0;
}
+12 -1
View File
@@ -23,9 +23,18 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#ifndef __CL_UIDMBOX_H__
#define __CL_UIDMBOX_H__
static constexpr unsigned int DMBOX_ITEM_FLAG_BOLD = 1u;
typedef enum { box_moving_out, box_moving_in, box_out, box_in } boxstate_t;
class UIDMBox : public UIWidget {
struct item_t {
str string;
UColor color;
UIFont* font;
int flags;
};
protected:
item_t m_items[ 10 ];
int m_numitems;
@@ -54,12 +63,14 @@ protected:
float DrawItem( item_t *in, float x, float y, float alpha );
public:
UIDMBox();
void Print( const char *text );
void OnSizeChanged( Event *ev );
void Create( const UIRect2D& rect, const UColor& fore, const UColor& back, float alpha );
void MoveInEvent( Event *ev );
void DecayEvent( Event *ev );
void Draw( void );
void Draw( void ) override;
void setRealShow( bool b );
void Clear( void );
};
+301 -22
View File
@@ -22,106 +22,385 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#include "cl_ui.h"
Event EV_GMBox_Goin
(
"_gmbox_goin",
EV_DEFAULT,
NULL,
NULL,
"Event to make the gmbox disappear"
);
Event EV_GMBox_Decay
(
"_gmbox_decay",
EV_DEFAULT,
NULL,
NULL,
"Event to make the gmbox console line decay"
);
static float s_gmboxWidth = 640.0;
CLASS_DECLARATION( UIWidget, UIGMBox, NULL )
{
{ &W_SizeChanged, &UIGMBox::OnSizeChanged },
{ &EV_GMBox_Goin, &UIGMBox::MoveInEvent },
{ &EV_GMBox_Decay, &UIGMBox::DecayEvent },
{ NULL, NULL }
};
UIGMBox::UIGMBox()
{
// FIXME: stub
m_numitems = 0;
m_reallyshown = true;
m_fontbold = NULL;
m_boxstate = boxstate_t::box_out;
m_iBeginDecay = 0;
m_boxtime = uid.time;
m_movespeed = 500;
}
void UIGMBox::VerifyBoxOut( void )
{
// FIXME: stub
PostMoveinEvent();
if (m_boxstate != boxstate_t::box_moving_out && m_boxstate != boxstate_t::box_out)
{
ChangeBoxState(boxstate_t::box_moving_out);
}
}
void UIGMBox::ChangeBoxState( boxstate_t state )
{
// FIXME: stub
m_boxstate = state;
m_boxtime = uid.time;
setShowState();
if (state == box_out) {
PostMoveinEvent();
}
}
void UIGMBox::HandleBoxMoving( void )
{
// FIXME: stub
int delta;
UIRect2D newRect;
if (m_boxstate != boxstate_t::box_moving_out && m_boxstate != boxstate_t::box_moving_in) {
return;
}
delta = m_movespeed * (uid.time - m_boxtime) / 1000;
m_boxtime = 1000 * delta / m_movespeed + m_boxtime;
if (m_boxstate == boxstate_t::box_moving_out)
{
newRect.size.width = m_frame.size.width;
newRect.size.height = m_frame.size.height;
newRect.pos.x = m_frame.pos.x;
newRect.pos.y = delta + m_frame.pos.y;
if (newRect.pos.y <= 0.0)
{
newRect.pos.y = 0.0;
ChangeBoxState(boxstate_t::box_out);
}
}
else if (m_boxstate == boxstate_t::box_moving_in)
{
newRect.size.width = m_frame.size.width;
newRect.size.height = m_frame.size.height;
newRect.pos.x = m_frame.pos.x;
newRect.pos.y = delta - m_frame.pos.y;
if (newRect.pos.y <= -newRect.size.height)
{
newRect.pos.y = -newRect.size.height;
ChangeBoxState(boxstate_t::box_in);
}
} else {
newRect = m_frame;
}
setFrame(newRect);
}
void UIGMBox::PostMoveinEvent( void )
{
// FIXME: stub
if (m_boxstate != boxstate_t::box_out) {
return;
}
if (!EventPending(EV_GMBox_Goin)) {
PostEvent(EV_GMBox_Goin, 10.0);
} else {
PostponeEvent(EV_GMBox_Goin, 10.0);
}
}
void UIGMBox::PostDecayEvent( void )
{
// FIXME: stub
if (!EventPending(EV_GMBox_Decay))
{
float fDelayTime;
int iNumLines;
int i;
const char* pszString = m_items[0].string.c_str();
//
// Calculate the number of lines
//
iNumLines = 1;
for (i = 0; pszString[i]; i++)
{
if (pszString[i] == '\n') {
iNumLines++;
}
}
//
// Bold as twice more decay
//
if (m_items[0].flags & GMBOX_ITEM_FLAG_BOLD) {
fDelayTime = iNumLines * 10.0;
} else {
fDelayTime = iNumLines * 5.0;
}
m_iBeginDecay = cls.realtime;
m_iEndDecay = (int)(fDelayTime * 1000.0);
PostEvent(EV_GMBox_Decay, fDelayTime);
}
}
void UIGMBox::setShowState( void )
{
// FIXME: stub
if (m_reallyshown) {
setShow(m_boxstate != box_in);
} else {
setShow(false);
}
}
void UIGMBox::RemoveTopItem( void )
{
// FIXME: stub
int i;
for (i = 0; i < m_numitems - 1; i++) {
m_items[i] = m_items[i + 1];
}
m_numitems--;
}
str UIGMBox::CalculateBreaks( UIFont *font, str text, float max_width )
{
// FIXME: stub
return "";
str newText, sTmp;
int i;
float fX;
float fwX, fsX;
Cmd_TokenizeString(text.c_str());
if (Cmd_Argc())
{
fX = 0.0;
fsX = font->getCharWidth(' ');
for (i = 0; i < Cmd_Argc(); i++)
{
sTmp = Cmd_Argv(i);
fwX = font->getWidth(sTmp.c_str(), -1);
if (fwX + i <= max_width)
{
if (fwX + i + fX <= max_width)
{
newText += sTmp + " ";
} else {
newText += "\n" + sTmp + " ";
}
}
else
{
sTmp += "\n";
fX = 0.0;
}
}
} else {
newText = "";
}
return newText;
}
float UIGMBox::PrintWrap( UIFont *font, float x, float y, str text )
{
// FIXME: stub
return 0.0f;
const char* p1, * p2;
size_t n, l;
float fY;
fY = y;
p1 = text.c_str();
l = text.length();
for (;;)
{
p2 = strchr(p1, '\n');
if (!p2) {
break;
}
n = p2 - p1;
if (n >= l) {
break;
}
font->Print(x, fY, p1, p2 - p1, qfalse);
p1 = p2 + 1;
l -= n;
fY += font->getHeight(qfalse);
}
font->Print(x, fY, p1, l, qfalse);
return font->getHeight(qfalse) + (fY - y);
}
float UIGMBox::DrawItem( item_t *in, float x, float y, float alpha )
{
// FIXME: stub
return 0.0f;
in->font->setColor(in->color);
in->font->setAlpha(alpha);
return PrintWrap(in->font, x, y, in->string);
}
void UIGMBox::Print( const char *text )
{
// FIXME: stub
const char* text1 = text;
if (m_numitems > 4)
{
//
// Overwrite an item
//
RemoveTopItem();
}
m_items[m_numitems].flags = 0;
if (*text == 3)
{
m_items[m_numitems].color = UWhite;
m_items[m_numitems].font = m_fontbold;
m_items[m_numitems].flags |= GMBOX_ITEM_FLAG_BOLD;
text1 = text + 1;
}
else
{
m_items[m_numitems].color = m_foreground_color;
m_items[m_numitems].font = m_font;
}
m_items[m_numitems].string = CalculateBreaks(m_items[m_numitems].font, text1, s_gmboxWidth);
m_numitems++;
VerifyBoxOut();
PostDecayEvent();
}
void UIGMBox::OnSizeChanged( Event *ev )
{
// FIXME: stub
s_gmboxWidth = m_frame.size.width;
}
void UIGMBox::Create( const UIRect2D& rect, const UColor& fore, const UColor& back, float alpha )
{
// FIXME: stub
InitFrame(NULL, rect, 0, "facfont-20");
if (!m_fontbold) {
m_fontbold = new UIFont("facfont-20");
}
m_fontbold->setColor(URed);
setBackgroundColor(back, true);
setForegroundColor(fore);
setBackgroundAlpha(alpha);
Connect(this, W_SizeChanged, W_SizeChanged);
OnSizeChanged(NULL);
m_movespeed = rect.size.height * 3.0;
setShowState();
}
void UIGMBox::MoveInEvent( Event *ev )
{
// FIXME: stub
}
void UIGMBox::DecayEvent( Event *ev )
{
// FIXME: stub
RemoveTopItem();
if (m_numitems) {
PostDecayEvent();
}
}
void UIGMBox::Draw( void )
{
// FIXME: stub
float fsY;
int i;
float alpha;
float alphaScale;
alphaScale = 1.0;
HandleBoxMoving();
if (!m_numitems) {
//
// Nothing to show
//
return;
}
m_font->setColor(m_foreground_color);
alpha = (float)(cls.realtime - m_iBeginDecay) / (float)m_iEndDecay;
if (alpha > 1.0) alpha = 1.0;
alpha = (1.0 - alpha) * 4.0;
if (alpha > 1.0) alpha = 1.0;
if (cge) {
alphaScale = 1.0 - cge->CG_GetObjectiveAlpha();
}
fsY = DrawItem(m_items, 0.0, 120.0, alpha * alphaScale);
fsY = alpha <= 0.2 ? 120.0 : fsY + 120.0;
for (i = 1; i < m_numitems; i++)
{
fsY += DrawItem(&m_items[i], 0.0, fsY, alphaScale);
if (fsY > m_frame.size.height)
{
if (EventPending(EV_GMBox_Decay)) {
CancelEventsOfType(EV_GMBox_Decay);
}
PostEvent(EV_GMBox_Decay, 0.0);
break;
}
}
}
void UIGMBox::setRealShow( bool b )
{
// FIXME: stub
this->m_reallyshown = b;
setShowState();
}
void UIGMBox::Clear( void )
{
// FIXME: stub
m_numitems = 0;
}
+10 -1
View File
@@ -23,7 +23,16 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#ifndef __CL_UIGMBOX_H__
#define __CL_UIGMBOX_H__
static constexpr unsigned int GMBOX_ITEM_FLAG_BOLD = 1u;
class UIGMBox : public UIWidget {
struct item_t {
str string;
UColor color;
UIFont* font;
int flags;
};
protected:
item_t m_items[ 5 ];
int m_numitems;
@@ -59,7 +68,7 @@ public:
void Create( const UIRect2D& rect, const UColor& fore, const UColor& back, float alpha );
void MoveInEvent( Event *ev );
void DecayEvent( Event *ev );
void Draw( void );
void Draw( void ) override;
void setRealShow( bool b );
void Clear( void );
};
+3 -3
View File
@@ -35,11 +35,11 @@ private:
void SetupServers( void );
protected:
void Draw( void );
void Draw( void ) override;
void SelectServer( Event *ev );
void JoinServer( Event *ev );
qboolean KeyEvent( int key, unsigned int time );
void UpdateUIElement( void );
qboolean KeyEvent( int key, unsigned int time ) override;
void UpdateUIElement( void ) override;
public:
UILANGameClass();
+2 -2
View File
@@ -36,8 +36,8 @@ protected:
void RemoveGame( Event *ev );
void DeleteGame( Event *ev );
void NoDeleteGame( Event *ev );
qboolean KeyEvent( int key, unsigned int time );
void UpdateUIElement( void );
qboolean KeyEvent( int key, unsigned int time ) override;
void UpdateUIElement( void ) override;
public:
UIFAKKLoadGameClass();
+4 -4
View File
@@ -27,21 +27,21 @@ class MapRunnerClass : public FilePickerClass {
public:
CLASS_PROTOTYPE( MapRunnerClass );
void FileChosen( str &currentDirectory, str &partialName, str &fullname );
void FileChosen( str &currentDirectory, str &partialName, str &fullname ) override;
};
class ViewSpawnerClass : public FilePickerClass {
public:
CLASS_PROTOTYPE( ViewSpawnerClass );
void FileChosen( str &currentDirectory, str &partialName, str &fullname );
void FileChosen( str &currentDirectory, str &partialName, str &fullname ) override;
};
class LODSpawnerClass : public FilePickerClass {
public:
CLASS_PROTOTYPE( LODSpawnerClass );
void FileChosen( str &currentDirectory, str &partialName, str &fullname );
void FileChosen( str &currentDirectory, str &partialName, str &fullname ) override;
};
class UIPickFileClass : public FilePickerClass {
@@ -51,7 +51,7 @@ public:
CLASS_PROTOTYPE( UIPickFileClass );
void FileChosen( str &currentDirectory, str &partialName, str &fullname );
void FileChosen( str &currentDirectory, str &partialName, str &fullname ) override;
};
void PickFile( const char *name, Listener *obj, Event& event );
+1 -1
View File
@@ -50,7 +50,7 @@ public:
void Print( const char *text );
void Create( const UISize2D& size, const UColor& fore, const UColor& back, float alpha );
void MoveInEvent( Event *ev );
void Draw( void );
void Draw( void ) override;
void setRealShow( bool b );
};
+4 -4
View File
@@ -39,8 +39,8 @@ public:
protected:
void SelectServer( Event *ev );
void ConnectServer( Event *ev );
qboolean KeyEvent( int key, unsigned int time );
void UpdateUIElement( void );
qboolean KeyEvent( int key, unsigned int time ) override;
void UpdateUIElement( void ) override;
void RefreshServerList( Event *ev );
void RefreshLANServerList( Event *ev );
void CancelRefresh( Event *ev );
@@ -51,8 +51,8 @@ protected:
public:
UIFAKKServerList();
void Draw( void );
void SortByColumn( int column );
void Draw( void ) override;
void SortByColumn( int column ) override;
};
#endif /* __CL_UISERVERLIST_H__ */
+393 -25
View File
@@ -271,7 +271,7 @@ void UIFakkLabel::ClearInvItemReference( Event *ev )
void UIFakkLabel::LayoutStatbar( Event *ev )
{
str or = ev->GetString( 1 );
str _or = ev->GetString( 1 );
if( ev->NumArgs() > 1 )
{
@@ -279,27 +279,27 @@ void UIFakkLabel::LayoutStatbar( Event *ev )
m_statbar_max = ev->GetFloat( 3 );
}
if( !str::icmp( or, "horizontal" ) )
if( !str::icmp( _or, "horizontal" ) )
{
m_statbar_or = L_STATBAR_HORIZONTAL;
}
else if( !str::icmp( or, "vertical_stagger_even" ) )
else if( !str::icmp( _or, "vertical_stagger_even" ) )
{
m_statbar_or = L_STATBAR_VERTICAL_STAGGER_EVEN;
}
else if( !str::icmp( or, "vertical_stagger_odd" ) )
else if( !str::icmp( _or, "vertical_stagger_odd" ) )
{
m_statbar_or = L_STATBAR_VERTICAL_STAGGER_ODD;
}
else if( !str::icmp( or, "vertical" ) )
else if( !str::icmp( _or, "vertical" ) )
{
m_statbar_or = L_STATBAR_VERTICAL;
}
else if( !str::icmp( or, "vertical_reverse" ) )
else if( !str::icmp( _or, "vertical_reverse" ) )
{
m_statbar_or = L_STATBAR_VERTICAL_REVERSE;
}
else if( !str::icmp( or, "circular" ) )
else if( !str::icmp( _or, "circular" ) )
{
m_statbar_or = L_STATBAR_CIRCULAR;
@@ -308,7 +308,7 @@ void UIFakkLabel::LayoutStatbar( Event *ev )
m_statbar_material = uWinMan.RegisterShader( "blank" );
}
}
else if( !str::icmp( or, "needle" ) )
else if( !str::icmp( _or, "needle" ) )
{
m_statbar_or = L_STATBAR_NEEDLE;
@@ -317,7 +317,7 @@ void UIFakkLabel::LayoutStatbar( Event *ev )
m_statbar_material = uWinMan.RegisterShader( "blank" );
}
}
else if( !str::icmp( or, "rotator" ) )
else if( !str::icmp( _or, "rotator" ) )
{
m_statbar_or = L_STATBAR_ROTATOR;
@@ -326,7 +326,7 @@ void UIFakkLabel::LayoutStatbar( Event *ev )
m_statbar_material = uWinMan.RegisterShader( "blank" );
}
}
else if( !str::icmp( or, "compass" ) )
else if( !str::icmp( _or, "compass" ) )
{
m_statbar_or = L_STATBAR_COMPASS;
@@ -335,7 +335,7 @@ void UIFakkLabel::LayoutStatbar( Event *ev )
m_statbar_material = uWinMan.RegisterShader( "blank" );
}
}
else if( !str::icmp( or, "spinner" ) )
else if( !str::icmp( _or, "spinner" ) )
{
m_statbar_or = L_STATBAR_SPINNER;
@@ -344,7 +344,7 @@ void UIFakkLabel::LayoutStatbar( Event *ev )
m_statbar_material = uWinMan.RegisterShader( "blank" );
}
}
else if( !str::icmp( or, "headingspinner" ) )
else if( !str::icmp( _or, "headingspinner" ) )
{
m_statbar_or = L_STATBAR_HEADING_SPINNER;
@@ -355,7 +355,7 @@ void UIFakkLabel::LayoutStatbar( Event *ev )
}
else
{
warning( "LayoutPlayerStat", "Invalid statbar orientation: \"%s\"", or.c_str() );
warning( "LayoutPlayerStat", "Invalid statbar orientation: \"%s\"", _or.c_str() );
}
}
@@ -438,7 +438,173 @@ void UIFakkLabel::LayoutRenderModelAnim( Event *ev )
void UIFakkLabel::DrawStatbar( float frac )
{
// FIXME: stub
vec4_t col;
float alpha;
col[0] = col[1] = col[2] = col[3] = 1.0;
switch (m_statbar_or)
{
case L_STATBAR_CIRCULAR:
DrawStatCircle(frac);
return;
case L_STATBAR_NEEDLE:
DrawStatNeedle(frac);
return;
case L_STATBAR_ROTATOR:
DrawStatRotator(frac);
return;
case L_STATBAR_COMPASS:
DrawStatCompass(frac);
return;
case L_STATBAR_SPINNER:
case L_STATBAR_HEADING_SPINNER:
DrawStatSpinner(frac);
return;
default:
break;
}
if (!frac) {
return;
}
if (frac != m_lastfrac) {
m_flashtime = uid.time;
}
m_lastfrac = frac;
alpha = 1.0 - ((float)uid.time - m_flashtime) / 1500.0;
if (alpha < 0.0) alpha = 0.0;
else if (alpha > 1.0) alpha = 1.0;
col[3] = alpha;
if (m_statbar_material)
{
if (m_flags & WF_TILESHADER)
{
switch (m_statbar_or)
{
case L_STATBAR_HORIZONTAL:
{
float width = frac * m_frame.size.width;
m_statbar_material->ReregisterMaterial();
re.DrawTilePic(0.0, 0.0, width, m_frame.size.height, m_statbar_material->GetMaterial());
if (alpha != 0.0 && m_statbar_material_flash)
{
re.SetColor(col);
m_statbar_material_flash->ReregisterMaterial();
re.DrawTilePic(0.0, 0.0, width, m_frame.size.height, m_statbar_material_flash->GetMaterial());
}
break;
}
case L_STATBAR_VERTICAL:
case L_STATBAR_VERTICAL_REVERSE:
case L_STATBAR_VERTICAL_STAGGER_EVEN:
case L_STATBAR_VERTICAL_STAGGER_ODD:
{
float y = m_frame.size.height * (1.0 - frac);
m_statbar_material->ReregisterMaterial();
re.DrawTilePic(0.0, y, m_frame.size.width, m_frame.size.height, m_statbar_material->GetMaterial());
if (alpha != 0.0 && m_statbar_material_flash)
{
re.SetColor(col);
m_statbar_material_flash->ReregisterMaterial();
re.DrawTilePic(0.0, y, m_frame.size.width, m_frame.size.height, m_statbar_material_flash->GetMaterial());
}
break;
}
}
}
else
{
switch (m_statbar_or)
{
case L_STATBAR_HORIZONTAL:
{
float width = frac * m_frame.size.width;
m_statbar_material->ReregisterMaterial();
re.DrawStretchPic(0.0, 0.0, width, m_frame.size.height, 0.0, 0.0, 1.0, 1.0, m_statbar_material->GetMaterial());
if(alpha != 0.0 && m_statbar_material_flash)
{
re.SetColor(col);
m_statbar_material_flash->ReregisterMaterial();
re.DrawStretchPic(0.0, 0.0, width, m_frame.size.height, 0.0, 0.0, 1.0, 1.0, m_statbar_material_flash->GetMaterial());
}
break;
}
case L_STATBAR_VERTICAL:
case L_STATBAR_VERTICAL_STAGGER_EVEN:
case L_STATBAR_VERTICAL_STAGGER_ODD:
{
float y = m_frame.size.height * (1.0 - frac);
float height = m_frame.size.height * frac;
m_statbar_material->ReregisterMaterial();
re.DrawStretchPic(0.0, y, m_frame.size.width, height, 0.0, 1.0 - frac, 1.0, 1.0, m_statbar_material->GetMaterial());
if (alpha != 0.0 && m_statbar_material_flash)
{
re.SetColor(col);
m_statbar_material_flash->ReregisterMaterial();
re.DrawStretchPic(0.0, y, m_frame.size.width, height, 0.0, 1.0 - frac, 1.0, 1.0, m_statbar_material_flash->GetMaterial());
}
break;
}
case L_STATBAR_VERTICAL_REVERSE:
{
float height = m_frame.size.height * frac;
m_statbar_material->ReregisterMaterial();
re.DrawStretchPic(0.0, 0.0, m_frame.size.width, height, 0.0, 0.0, 1.0, frac, m_statbar_material->GetMaterial());
if (alpha != 0.0 && m_statbar_material_flash)
{
re.SetColor(col);
m_statbar_material_flash->ReregisterMaterial();
re.DrawStretchPic(0.0, 0.0, m_frame.size.width, height, 0.0, 0.0, 1.0, frac, m_statbar_material_flash->GetMaterial());
}
break;
}
}
}
}
else
{
switch (m_statbar_or)
{
case L_STATBAR_VERTICAL:
case L_STATBAR_VERTICAL_STAGGER_EVEN:
case L_STATBAR_VERTICAL_STAGGER_ODD:
DrawBox(
0.0,
m_frame.size.height * (1.0 - frac),
m_frame.size.width,
m_frame.size.height,
m_foreground_color,
1.0
);
break;
case L_STATBAR_HORIZONTAL:
DrawBox(
0.0,
0.0,
frac * m_frame.size.width,
m_frame.size.height,
m_foreground_color,
1.0
);
break;
}
}
}
void UIFakkLabel::DrawStatCircle( float frac )
@@ -458,7 +624,212 @@ void UIFakkLabel::DrawStatRotator( float frac )
void UIFakkLabel::DrawStatCompass( float frac )
{
// FIXME: stub
vec4_t col;
float fTargAng;
float fSinVal, fCosVal;
vec2_t vCenter;
vec2_t vVerts[3];
vec2_t vTexCoords[3];
vec2_t vCompassDir;
vec2_t vSideDir;
col[0] = col[1] = col[2] = col[3] = 1.0;
if (!cge) {
return;
}
static int iLastCompassTime = -9999, iLastTimeDelta = 0;
static float fLastPitch = 0, fLastYaw = 0, fLastYawDelta = 0;
static float fYawOffset = 0, fYawSpeed = 0;
static float fNeedleOffset = 0, fNeedleSpeed = 0;
int iTimeCount, iTimeDelta;
float fYawDelta, fYawDeltaDiff;
vec3_t vViewAngles;
cge->CG_EyeAngles(&vViewAngles);
vViewAngles[1] -= cl.snap.ps.stats[STAT_COMPASSNORTH] / 182.0f;
iTimeCount = uid.time - iLastCompassTime;
if (iTimeCount <= 1000)
{
fYawDelta = AngleSubtract(vViewAngles[1], fLastYaw);
if (fYawDelta > 0.1)
{
if ((fYawDelta > 0.0 && fLastYawDelta < fYawDelta)
|| (fYawDelta < 0.0 && fLastYawDelta > fYawDelta))
{
fYawSpeed += (fYawDelta - fLastYawDelta) * 0.75;
fYawOffset += (fYawDelta - fLastYawDelta) * 0.75;
}
if (fYawSpeed > 90.0) {
fYawSpeed = 90.0;
}
else if (fYawSpeed < 0.05) {
fYawSpeed = 0.05;
}
}
while (iTimeCount > 0)
{
iTimeDelta = iTimeCount;
if (iTimeCount > 15) {
iTimeDelta = 15;
}
iTimeCount -= iTimeDelta;
if (fabs(fYawOffset) >= 0.1 || fabs(fYawSpeed) >= 0.01)
{
fYawOffset += fYawSpeed * iTimeDelta;
if (fYawOffset > 0.0) {
fYawSpeed -= iTimeDelta * 0.00175;
}
else if (fYawOffset < 0.0) {
fYawSpeed += iTimeDelta * 0.00175;
}
if (fYawOffset > 40.0) {
fYawOffset = 40.0;
fYawSpeed = 0.0;
}
else if (fYawOffset < -40.0) {
fYawOffset = -40.0;
fYawSpeed = 0.0;
}
fYawSpeed -= iTimeDelta * 0.003;
if (fYawSpeed > 0.0) {
fYawSpeed -= iTimeDelta * 0.0004;
}
else {
fYawSpeed += iTimeDelta * 0.0004;
if (fYawSpeed > 0.0) {
fYawSpeed = 0.0;
}
}
}
else
{
iTimeCount = 0;
fYawOffset = 0.0;
fYawSpeed = 0.0;
}
}
fLastYawDelta = fYawDelta;
iLastTimeDelta = uid.time - iLastCompassTime;
}
else
{
fLastYawDelta = 0;
fYawOffset = 0;
fYawSpeed = 0;
iLastTimeDelta = 0;
}
fLastPitch = vViewAngles[0];
fLastYaw = vViewAngles[1];
iLastCompassTime = uid.time;
if (iLastTimeDelta)
{
if (fabs(fLastYawDelta) > 0.1) {
fNeedleOffset -= fLastYawDelta;
}
iTimeCount = iLastTimeDelta;
while (iTimeCount > 0)
{
iTimeDelta = iTimeCount;
if (iTimeCount > 15) {
iTimeDelta = 15;
}
iTimeCount -= iTimeDelta;
if (fabs(fNeedleOffset) >= 0.1 || fabs(fNeedleSpeed) >= 0.01) {
fNeedleOffset += iTimeDelta * fNeedleSpeed;
if (fNeedleOffset > 180.0) {
fNeedleOffset -= 360.0;
}
else if (fNeedleOffset < -180.0) {
fNeedleOffset += 360.0;
}
if (fNeedleOffset > 0.0) {
fNeedleSpeed -= iTimeDelta * 0.00175;
}
else if (fNeedleOffset < 0.0) {
fNeedleSpeed += iTimeDelta * 0.00175;
}
fNeedleSpeed -= fNeedleSpeed * 0.0025 * iTimeDelta;
if (fNeedleSpeed > 0.0) {
fNeedleSpeed -= iTimeDelta * 0.00035;
if (fNeedleSpeed < 0.0) {
fNeedleSpeed = 0.0;
}
}
else {
fNeedleSpeed += iTimeDelta * 0.00035;
if (fNeedleSpeed > 0.0) {
fNeedleSpeed = 0.0;
}
}
} else {
iTimeCount = 0;
fNeedleOffset = 0.0;
fNeedleSpeed = 0.0;
}
}
}
else
{
fNeedleOffset = 0.0;
fNeedleSpeed = 0.0;
}
fSinVal = sin(anglemod(fNeedleOffset + fLastYaw) / (180 / M_PI));
fCosVal = cos(anglemod(fNeedleOffset + fLastYaw) / (180 / M_PI));
vCompassDir[0] = fSinVal;
vCompassDir[1] = -fCosVal;
vCenter[0] = m_frame.size.width * 0.5;
vCenter[1] = m_frame.size.height * 0.5;
vTexCoords[0][0] = 0.0;
vTexCoords[0][1] = 0.0;
vTexCoords[1][0] = 1.0;
vTexCoords[1][1] = 0.0;
vTexCoords[2][0] = 0.0;
vTexCoords[2][1] = 1.0;
vVerts[0][0] = vCenter[0] + vCompassDir[0] * vCenter[0] - fCosVal * vCenter[1];
vVerts[1][0] = vCenter[0] + vCompassDir[0] * vCenter[0] + fCosVal * vCenter[1];
vVerts[2][0] = vCenter[0] - vCompassDir[0] * vCenter[0] - fCosVal * vCenter[1];
vVerts[0][1] = vCenter[1] + vCompassDir[1] * vCenter[1] - fSinVal * vCenter[0];
vVerts[1][1] = vCenter[1] + vCompassDir[1] * vCenter[1] + fSinVal * vCenter[0];
vVerts[2][1] = vCenter[1] - vCompassDir[1] * vCenter[1] - fSinVal * vCenter[0];
m_statbar_material->ReregisterMaterial();
re.DrawTrianglePic(vVerts, vTexCoords, m_statbar_material->GetMaterial());
vVerts[0][0] = vVerts[2][0];
vVerts[0][1] = vVerts[2][1];
vTexCoords[0][0] = vTexCoords[2][0];
vTexCoords[0][1] = vTexCoords[2][1];
vTexCoords[2][0] = 1.0;
vTexCoords[2][1] = 1.0;
vVerts[2][0] = vCenter[0] + fCosVal * vCenter[1] - vCompassDir[0] * vCenter[0];
vVerts[2][1] = vCenter[1] * fSinVal + vCenter[0] - vCompassDir[1] * vCenter[1];
m_statbar_material->ReregisterMaterial();
re.DrawTrianglePic(vVerts, vTexCoords, m_statbar_material->GetMaterial());
}
void UIFakkLabel::DrawStatSpinner( float frac )
@@ -506,7 +877,7 @@ void UIFakkLabel::Draw( void )
return;
}
if( m_stat != -1 )
if( m_stat == -1 )
{
float scale;
qhandle_t handle;
@@ -516,7 +887,7 @@ void UIFakkLabel::Draw( void )
vec3_t angles;
vec3_t offset;
vec3_t rotateoffset;
vec3_t color;
vec4_t color;
str sAnimName;
float height;
@@ -686,23 +1057,20 @@ _shitlabel01:
float frac;
if( m_maxstat )
if( m_maxstat >= 0 )
{
frac = delta / ( m_statbar_max - m_statbar_min );
frac = (float)delta / (float)cl.snap.ps.stats[m_maxstat];
}
else
{
frac = delta / cl.snap.ps.stats[ m_maxstat ];
frac = (float)delta / (float)(m_statbar_max - m_statbar_min);
}
if( frac > 1.0 )
frac = 1.0;
if( frac < 0.0 )
frac = 0.0;
if( frac > 1.0 ) frac = 1.0;
else if( frac < 0.0 ) frac = 0.0;
DrawStatbar( frac );
return;
}
+1 -1
View File
@@ -97,7 +97,7 @@ public:
void DrawStatSpinner( float frac );
void StatCircleTexCoord( float fAng, vec3_t vTexCoord );
void Draw( void );
void Draw( void ) override;
};
#endif
+140 -13
View File
@@ -21,16 +21,26 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "cl_ui.h"
#include "cl_screen.h"
CLASS_DECLARATION( UIWidget, View3D, NULL )
{
{ &W_Activated, &View3D::OnActivate },
{ &W_Deactivated, &View3D::OnDeactivate },
{ &W_LeftMouseDown, &View3D::Pressed },
{ NULL, NULL }
};
View3D::View3D()
{
// FIXME: stub
// set as transparent
setBackgroundColor(UClear, true);
// no border
setBorderStyle(border_none);
AllowActivate(true);
m_printfadetime = 0.0;
m_print_mat = NULL;
m_locationprint = qfalse;
}
void View3D::Draw
@@ -39,15 +49,14 @@ void View3D::Draw
)
{
// FIXME: stub
if (cls.state != CA_DISCONNECTED)
{
if (cls.state != CA_DISCONNECTED) {
SCR_DrawScreenField();
}
//dword_893691C(v1, v2, v3, v4);
set2D();
re.SavePerformanceCounters();
Draw2D();
}
@@ -75,7 +84,40 @@ void View3D::Draw2D
)
{
// FIXME: stub
if (!cls.no_menus) {
DrawFades();
}
DrawLetterbox();
if ((cl_debuggraph->integer || cl_timegraph->integer) && !cls.no_menus)
{
SCR_DrawDebugGraph();
}
else if (!cls.no_menus)
{
if (cge) {
cge->CG_Draw2D();
}
if (m_locationprint) {
LocationPrint();
} else {
CenterPrint();
}
if (!cls.no_menus)
{
DrawSoundOverlay();
DrawSubtitleOverlay();
}
}
if (fps->integer && !cls.no_menus)
{
DrawFPS();
DrawProf();
}
}
void View3D::DrawFPS
@@ -84,7 +126,72 @@ void View3D::DrawFPS
)
{
// FIXME: stub
char string[128];
setFont("verdana-14");
if (fps->integer == 2)
{
re.SetColor(UBlack);
re.DrawBox(
0.0,
m_frame.pos.y + m_frame.size.height - m_font->getHeight(qfalse) * 4.0,
m_frame.pos.x + m_frame.size.width,
m_font->getHeight(qfalse) * 4.0
);
}
sprintf(string, "FPS %4.1f", currentfps);
if (currentfps > 23.94) {
if (cl_greenfps->integer) {
m_font->setColor(UGreen);
} else {
m_font->setColor(UWhite);
}
} else if (currentfps > 18.0) {
m_font->setColor(UYellow);
} else {
// low fps
m_font->setColor(URed);
}
m_font->Print(
m_font->getHeight(qfalse) * 10.0,
m_frame.pos.y + m_frame.size.height - m_font->getHeight(qfalse) * 3.0,
string,
-1,
qfalse
);
// Draw elements count
if (cl_greenfps->integer) {
m_font->setColor(UGreen);
}
else {
m_font->setColor(UWhite);
}
sprintf(string, "wt%5d wv%5d cl%d", cls.world_tris, cls.world_verts, cls.character_lights);
m_font->Print(
m_font->getHeight(qfalse) * 10.0,
m_frame.pos.y + m_frame.size.height - m_font->getHeight(qfalse) * 2.0,
string,
-1,
qfalse
);
sprintf(string, "t%5d v%5d Mtex%5.2f", cls.total_tris, cls.total_verts, (float)cls.total_texels * 0.00000095367432);
m_font->Print(
m_font->getHeight(qfalse) * 10.0,
m_frame.pos.y + m_frame.size.height - m_font->getHeight(qfalse),
string,
-1,
qfalse
);
m_font->setColor(UBlack);
}
void View3D::DrawProf
@@ -144,7 +251,25 @@ void View3D::OnActivate
)
{
// FIXME: stub
UIWidget* wid;
UList<UIWidget*> widgets;
UI_CloseInventory();
cls.keyCatchers &= ~KEYCATCH_UI;
for (wid = getParent()->getFirstChild(); wid; wid = getParent()->getNextChild(wid))
{
if (wid->getAlwaysOnBottom() && wid != this) {
widgets.AddTail(wid);
}
}
widgets.IterateFromHead();
while (widgets.IsCurrentValid())
{
widgets.getCurrent()->BringToFrontPropogated();
widgets.IterateNext();
}
}
void View3D::OnDeactivate
@@ -153,7 +278,7 @@ void View3D::OnDeactivate
)
{
// FIXME: stub
cls.keyCatchers |= KEYCATCH_UI;
}
void View3D::DrawSubtitleOverlay
@@ -220,7 +345,8 @@ void View3D::FrameInitialized
)
{
// FIXME: stub
Connect(this, W_Activated, W_Activated);
Connect(this, W_Deactivated, W_Deactivated);
}
void View3D::Pressed
@@ -229,7 +355,8 @@ void View3D::Pressed
)
{
// FIXME: stub
IN_MouseOff();
OnActivate(ev);
}
CLASS_DECLARATION( UIWidget, ConsoleView, NULL )
+2 -2
View File
@@ -37,7 +37,7 @@ public:
CLASS_PROTOTYPE( View3D );
protected:
void Draw( void );
void Draw( void ) override;
void DrawLetterbox( void );
void DrawFades( void );
void Draw2D( void );
@@ -68,7 +68,7 @@ public:
CLASS_PROTOTYPE( ConsoleView );
protected:
void Draw( void );
void Draw( void ) override;
};
#endif /* __CL_UIVIEW3D__ */
+22 -8
View File
@@ -26,7 +26,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#include "../qcommon/q_shared.h"
#include "../qcommon/qcommon.h"
#include "../renderercommon/tr_public.h"
#include "../renderer/tr_public.h"
#include "keys.h"
#include "snd_public.h"
#include "../cgame/cg_public.h"
@@ -182,6 +182,7 @@ typedef struct {
netadr_t serverAddress;
int connectTime; // for connection retransmits
int connectStartTime;
int connectPacketCount; // for display on connection dialog
char serverMessage[MAX_STRING_TOKENS]; // for display on connection dialog
@@ -246,6 +247,9 @@ typedef struct {
// big stuff at end of structure so most offsets are 15 bits or less
netchan_t netchan;
float aviVideoFrameRemainder;
float aviSoundFrameRemainder;
} clientConnection_t;
extern clientConnection_t clc;
@@ -347,7 +351,7 @@ typedef struct {
int character_lights;
hdelement_t HudDrawElements[ MAX_HUDDRAW_ELEMENTS ];
clientAnim_t anim;
stopwatch_t stopwatch;
stopWatch_t stopwatch;
qhandle_t charSetShader;
qhandle_t whiteShader;
qhandle_t consoleShader;
@@ -363,6 +367,8 @@ extern clientGameExport_t *cge;
extern refexport_t re; // interface to refresh .dll
extern qboolean scr_initialized;
//
// cvars
//
@@ -370,6 +376,7 @@ extern cvar_t *cl_nodelta;
extern cvar_t *cl_debugMove;
extern cvar_t *cl_noprint;
extern cvar_t *cl_timegraph;
extern cvar_t *cl_debuggraph;
extern cvar_t *cl_timeout;
extern cvar_t *cl_connect_timeout;
extern cvar_t *cl_maxpackets;
@@ -422,6 +429,17 @@ extern cvar_t *cl_consoleKeys;
extern cvar_t *cg_gametype;
extern cvar_t* j_pitch;
extern cvar_t* j_yaw;
extern cvar_t* j_forward;
extern cvar_t* j_side;
extern cvar_t* j_up;
extern cvar_t* j_pitch_axis;
extern cvar_t* j_yaw_axis;
extern cvar_t* j_forward_axis;
extern cvar_t* j_side_axis;
extern cvar_t* j_up_axis;
//=================================================
//
@@ -503,8 +521,7 @@ void Key_GetKeysForCommand( const char *command, int *key1, int *key2 );
int Key_GetCatcher( void );
void Key_SetCatcher( int catcher );
void CL_GetEyeInfo(usereyes_t *info); //su44
void CL_SetEyeInfo(vec3_t origin, vec3_t angles); //su44
void CL_EyeInfo(usereyes_t *info);
//
// cl_parse.c
@@ -560,15 +577,12 @@ void Con_PageUp( void );
void Con_PageDown( void );
void Con_Top( void );
void Con_Bottom( void );
void Con_Close( void );
void CL_LoadConsoleHistory( void );
void CL_SaveConsoleHistory( void );
//
// cl_scrn.c
//
void SCR_Init (void);
void SCR_DrawDebugGraph(void);
void SCR_DrawScreenField(void);
void SCR_UpdateScreen (void);
+10 -115
View File
@@ -47,9 +47,12 @@ typedef enum {
K_LEFTARROW,
K_RIGHTARROW,
K_ALT,
K_CTRL,
K_SHIFT,
K_LALT,
K_LCTRL,
K_LSHIFT,
K_RALT,
K_RCTRL,
K_RSHIFT,
K_INS,
K_DEL,
K_PGDN,
@@ -151,119 +154,11 @@ typedef enum {
K_AUX15,
K_AUX16,
K_WORLD_0,
K_WORLD_1,
K_WORLD_2,
K_WORLD_3,
K_WORLD_4,
K_WORLD_5,
K_WORLD_6,
K_WORLD_7,
K_WORLD_8,
K_WORLD_9,
K_WORLD_10,
K_WORLD_11,
K_WORLD_12,
K_WORLD_13,
K_WORLD_14,
K_WORLD_15,
K_WORLD_16,
K_WORLD_17,
K_WORLD_18,
K_WORLD_19,
K_WORLD_20,
K_WORLD_21,
K_WORLD_22,
K_WORLD_23,
K_WORLD_24,
K_WORLD_25,
K_WORLD_26,
K_WORLD_27,
K_WORLD_28,
K_WORLD_29,
K_WORLD_30,
K_WORLD_31,
K_WORLD_32,
K_WORLD_33,
K_WORLD_34,
K_WORLD_35,
K_WORLD_36,
K_WORLD_37,
K_WORLD_38,
K_WORLD_39,
K_WORLD_40,
K_WORLD_41,
K_WORLD_42,
K_WORLD_43,
K_WORLD_44,
K_WORLD_45,
K_WORLD_46,
K_WORLD_47,
K_WORLD_48,
K_WORLD_49,
K_WORLD_50,
K_WORLD_51,
K_WORLD_52,
K_WORLD_53,
K_WORLD_54,
K_WORLD_55,
K_WORLD_56,
K_WORLD_57,
K_WORLD_58,
K_WORLD_59,
K_WORLD_60,
K_WORLD_61,
K_WORLD_62,
K_WORLD_63,
K_WORLD_64,
K_WORLD_65,
K_WORLD_66,
K_WORLD_67,
K_WORLD_68,
K_WORLD_69,
K_WORLD_70,
K_WORLD_71,
K_WORLD_72,
K_WORLD_73,
K_WORLD_74,
K_WORLD_75,
K_WORLD_76,
K_WORLD_77,
K_WORLD_78,
K_WORLD_79,
K_WORLD_80,
K_WORLD_81,
K_WORLD_82,
K_WORLD_83,
K_WORLD_84,
K_WORLD_85,
K_WORLD_86,
K_WORLD_87,
K_WORLD_88,
K_WORLD_89,
K_WORLD_90,
K_WORLD_91,
K_WORLD_92,
K_WORLD_93,
K_WORLD_94,
K_WORLD_95,
K_LWINKEY,
K_RWINKEY,
K_MENUKEY,
K_SUPER,
K_COMPOSE,
K_MODE,
K_HELP,
K_PRINT,
K_SYSREQ,
K_SCROLLOCK,
K_BREAK,
K_MENU,
K_EURO,
K_UNDO,
// Pseudo-key that brings the console down
K_CONSOLE,
MAX_KEYS
K_LASTKEY
} keyNum_t;
// MAX_KEYS replaces K_LAST_KEY, however some mods may have used K_LAST_KEY
+3 -12
View File
@@ -32,23 +32,13 @@ typedef struct {
} qkey_t;
extern qboolean key_overstrikeMode;
extern qkey_t keys[MAX_KEYS];
extern qkey_t keys[K_LASTKEY];
// NOTE TTimo the declaration of field_t and Field_Clear is now in qcommon/qcommon.h
void Field_KeyDownEvent( field_t *edit, int key );
void Field_CharEvent( field_t *edit, int ch );
void Field_Draw(fontInfo_t *font, field_t *edit, int x, int y, int width, qboolean showCursor, qboolean noColorEscape );
void Field_BigDraw(fontInfo_t *font, field_t *edit, int x, int y, int width, qboolean showCursor, qboolean noColorEscape );
#define COMMAND_HISTORY 32
extern field_t historyEditLines[COMMAND_HISTORY];
extern field_t g_consoleField;
extern field_t chatField;
extern int anykeydown;
extern qboolean chat_team;
extern int chat_playerNum;
#if defined(APP_MODULE)
int Key_StringToKeynum( const char *str );
void Key_WriteBindings( fileHandle_t f );
void Key_SetBinding( int keynum, const char *binding );
@@ -59,6 +49,7 @@ void Key_SetOverstrikeMode( qboolean state );
void Key_ClearStates( void );
int Key_GetKey(const char *binding);
const char *Key_GetKeynameForCommand( const char *command );
#endif
#ifdef __cplusplus
}
+2 -1
View File
@@ -37,8 +37,9 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#include "../AL/al.h"
#include "../AL/alc.h"
#else
#ifdef _MSC_VER
#if defined(_MSC_VER) || defined(__APPLE__)
// MSVC users must install the OpenAL SDK which doesn't use the AL/*.h scheme.
// OSX framework also needs this
#include <al.h>
#include <alc.h>
#else
+121 -124
View File
@@ -2,12 +2,12 @@
Copyright 1992 by Stichting Mathematisch Centrum, Amsterdam, The
Netherlands.
All Rights Reserved
All Rights Reserved
Permission to use, copy, modify, and distribute this software and its
documentation for any purpose and without fee is hereby granted,
Permission to use, copy, modify, and distribute this software and its
documentation for any purpose and without fee is hereby granted,
provided that the above copyright notice appear in all copies and that
both that copyright notice and this permission notice appear in
both that copyright notice and this permission notice appear in
supporting documentation, and that the names of Stichting Mathematisch
Centrum or CWI not be used in advertising or publicity pertaining to
distribution of the software without specific, written prior permission.
@@ -35,55 +35,55 @@ OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
/* Intel ADPCM step variation table */
static int indexTable[ 16 ] = {
-1, -1, -1, -1, 2, 4, 6, 8,
-1, -1, -1, -1, 2, 4, 6, 8,
static int indexTable[16] = {
-1, -1, -1, -1, 2, 4, 6, 8,
-1, -1, -1, -1, 2, 4, 6, 8,
};
static int stepsizeTable[ 89 ] = {
7, 8, 9, 10, 11, 12, 13, 14, 16, 17,
19, 21, 23, 25, 28, 31, 34, 37, 41, 45,
50, 55, 60, 66, 73, 80, 88, 97, 107, 118,
130, 143, 157, 173, 190, 209, 230, 253, 279, 307,
337, 371, 408, 449, 494, 544, 598, 658, 724, 796,
876, 963, 1060, 1166, 1282, 1411, 1552, 1707, 1878, 2066,
2272, 2499, 2749, 3024, 3327, 3660, 4026, 4428, 4871, 5358,
5894, 6484, 7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899,
15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, 32767
static int stepsizeTable[89] = {
7, 8, 9, 10, 11, 12, 13, 14, 16, 17,
19, 21, 23, 25, 28, 31, 34, 37, 41, 45,
50, 55, 60, 66, 73, 80, 88, 97, 107, 118,
130, 143, 157, 173, 190, 209, 230, 253, 279, 307,
337, 371, 408, 449, 494, 544, 598, 658, 724, 796,
876, 963, 1060, 1166, 1282, 1411, 1552, 1707, 1878, 2066,
2272, 2499, 2749, 3024, 3327, 3660, 4026, 4428, 4871, 5358,
5894, 6484, 7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899,
15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, 32767
};
void S_AdpcmEncode( short indata[], char outdata[], int len, struct adpcm_state *state ) {
short *inp; /* Input buffer pointer */
signed char *outp; /* output buffer pointer */
int val; /* Current input sample value */
int sign; /* Current adpcm sign bit */
int delta; /* Current adpcm output value */
int diff; /* Difference between val and sample */
int step; /* Stepsize */
int valpred; /* Predicted output value */
int vpdiff; /* Current change to valpred */
int index; /* Current step change index */
int outputbuffer; /* place to keep previous 4-bit value */
int bufferstep; /* toggle between outputbuffer/output */
short *inp; /* Input buffer pointer */
signed char *outp; /* output buffer pointer */
int val; /* Current input sample value */
int sign; /* Current adpcm sign bit */
int delta; /* Current adpcm output value */
int diff; /* Difference between val and sample */
int step; /* Stepsize */
int valpred; /* Predicted output value */
int vpdiff; /* Current change to valpred */
int index; /* Current step change index */
int outputbuffer; /* place to keep previous 4-bit value */
int bufferstep; /* toggle between outputbuffer/output */
outp = ( signed char * )outdata;
inp = indata;
valpred = state->sample;
index = state->index;
step = stepsizeTable[ index ];
outp = (signed char *)outdata;
inp = indata;
valpred = state->sample;
index = state->index;
step = stepsizeTable[index];
outputbuffer = 0; // quiet a compiler warning
bufferstep = 1;
bufferstep = 1;
for( ; len > 0; len-- ) {
for ( ; len > 0 ; len-- ) {
val = *inp++;
/* Step 1 - compute difference with previous value */
diff = val - valpred;
sign = ( diff < 0 ) ? 8 : 0;
if( sign ) diff = ( -diff );
sign = (diff < 0) ? 8 : 0;
if ( sign ) diff = (-diff);
/* Step 2 - Divide and clamp */
/* Note:
@@ -95,101 +95,99 @@ void S_AdpcmEncode( short indata[], char outdata[], int len, struct adpcm_state
** good use since the fixup would be too expensive.
*/
delta = 0;
vpdiff = ( step >> 3 );
if( diff >= step ) {
vpdiff = (step >> 3);
if ( diff >= step ) {
delta = 4;
diff -= step;
vpdiff += step;
}
step >>= 1;
if( diff >= step ) {
if ( diff >= step ) {
delta |= 2;
diff -= step;
vpdiff += step;
}
step >>= 1;
if( diff >= step ) {
if ( diff >= step ) {
delta |= 1;
vpdiff += step;
}
/* Step 3 - Update previous value */
if( sign )
valpred -= vpdiff;
if ( sign )
valpred -= vpdiff;
else
valpred += vpdiff;
valpred += vpdiff;
/* Step 4 - Clamp previous value to 16 bits */
if( valpred > 32767 )
valpred = 32767;
else if( valpred < -32768 )
valpred = -32768;
if ( valpred > 32767 )
valpred = 32767;
else if ( valpred < -32768 )
valpred = -32768;
/* Step 5 - Assemble value, update index and step values */
delta |= sign;
index += indexTable[ delta ];
if( index < 0 ) index = 0;
if( index > 88 ) index = 88;
step = stepsizeTable[ index ];
index += indexTable[delta];
if ( index < 0 ) index = 0;
if ( index > 88 ) index = 88;
step = stepsizeTable[index];
/* Step 6 - Output value */
if( bufferstep ) {
outputbuffer = ( delta << 4 ) & 0xf0;
}
else {
*outp++ = ( delta & 0x0f ) | outputbuffer;
if ( bufferstep ) {
outputbuffer = (delta << 4) & 0xf0;
} else {
*outp++ = (delta & 0x0f) | outputbuffer;
}
bufferstep = !bufferstep;
}
}
/* Output last step, if needed */
if( !bufferstep )
*outp++ = outputbuffer;
state->sample = valpred;
state->index = index;
/* Output last step, if needed */
if ( !bufferstep )
*outp++ = outputbuffer;
state->sample = valpred;
state->index = index;
}
/* static */ void S_AdpcmDecode( const char indata[], short *outdata, int len, struct adpcm_state *state ) {
signed char *inp; /* Input buffer pointer */
int outp; /* output buffer pointer */
int sign; /* Current adpcm sign bit */
int delta; /* Current adpcm output value */
int step; /* Stepsize */
int valpred; /* Predicted value */
int vpdiff; /* Current change to valpred */
int index; /* Current step change index */
int inputbuffer; /* place to keep next 4-bit value */
int bufferstep; /* toggle between inputbuffer/input */
signed char *inp; /* Input buffer pointer */
int outp; /* output buffer pointer */
int sign; /* Current adpcm sign bit */
int delta; /* Current adpcm output value */
int step; /* Stepsize */
int valpred; /* Predicted value */
int vpdiff; /* Current change to valpred */
int index; /* Current step change index */
int inputbuffer; /* place to keep next 4-bit value */
int bufferstep; /* toggle between inputbuffer/input */
outp = 0;
inp = ( signed char * )indata;
outp = 0;
inp = (signed char *)indata;
valpred = state->sample;
index = state->index;
step = stepsizeTable[ index ];
bufferstep = 0;
inputbuffer = 0; // quiet a compiler warning
for( ; len > 0; len-- ) {
valpred = state->sample;
index = state->index;
step = stepsizeTable[index];
bufferstep = 0;
inputbuffer = 0; // quiet a compiler warning
for ( ; len > 0 ; len-- ) {
/* Step 1 - get the delta value */
if( bufferstep ) {
if ( bufferstep ) {
delta = inputbuffer & 0xf;
}
else {
} else {
inputbuffer = *inp++;
delta = ( inputbuffer >> 4 ) & 0xf;
delta = (inputbuffer >> 4) & 0xf;
}
bufferstep = !bufferstep;
/* Step 2 - Find new index value (for later) */
index += indexTable[ delta ];
if( index < 0 ) index = 0;
if( index > 88 ) index = 88;
index += indexTable[delta];
if ( index < 0 ) index = 0;
if ( index > 88 ) index = 88;
/* Step 3 - Separate sign and magnitude */
sign = delta & 8;
@@ -201,31 +199,31 @@ void S_AdpcmEncode( short indata[], char outdata[], int len, struct adpcm_state
** in adpcm_coder.
*/
vpdiff = step >> 3;
if( delta & 4 ) vpdiff += step;
if( delta & 2 ) vpdiff += step >> 1;
if( delta & 1 ) vpdiff += step >> 2;
if ( delta & 4 ) vpdiff += step;
if ( delta & 2 ) vpdiff += step>>1;
if ( delta & 1 ) vpdiff += step>>2;
if( sign )
valpred -= vpdiff;
if ( sign )
valpred -= vpdiff;
else
valpred += vpdiff;
valpred += vpdiff;
/* Step 5 - clamp output value */
if( valpred > 32767 )
valpred = 32767;
else if( valpred < -32768 )
valpred = -32768;
if ( valpred > 32767 )
valpred = 32767;
else if ( valpred < -32768 )
valpred = -32768;
/* Step 6 - Update step value */
step = stepsizeTable[ index ];
step = stepsizeTable[index];
/* Step 7 - Output value */
outdata[ outp ] = valpred;
outdata[outp] = valpred;
outp++;
}
}
state->sample = valpred;
state->index = index;
state->sample = valpred;
state->index = index;
}
@@ -244,7 +242,7 @@ int S_AdpcmMemoryNeeded( const wavinfo_t *info ) {
int headerMemory;
// determine scale to convert from input sampling rate to desired sampling rate
scale = ( float )info->rate / dma.speed;
scale = (float)info->rate / dma.speed;
// calc number of samples at playback sampling rate
scaledSampleCount = info->samples / scale;
@@ -259,7 +257,7 @@ int S_AdpcmMemoryNeeded( const wavinfo_t *info ) {
}
// calc memory needed to store the block headers
headerMemory = blockCount * sizeof( adpcm_state_t );
headerMemory = blockCount * sizeof(adpcm_state_t);
return sampleMemory + headerMemory;
}
@@ -270,7 +268,7 @@ int S_AdpcmMemoryNeeded( const wavinfo_t *info ) {
S_AdpcmGetSamples
====================
*/
void S_AdpcmGetSamples( sndBuffer *chunk, short *to ) {
void S_AdpcmGetSamples(sndBuffer *chunk, short *to) {
adpcm_state_t state;
byte *out;
@@ -278,9 +276,9 @@ void S_AdpcmGetSamples( sndBuffer *chunk, short *to ) {
state.index = chunk->adpcm.index;
state.sample = chunk->adpcm.sample;
out = ( byte * )chunk->sndChunk;
out = (byte *)chunk->sndChunk;
// get samples
S_AdpcmDecode( ( char * )out, to, SND_CHUNK_SIZE_BYTE * 2, &state );
S_AdpcmDecode( out, to, SND_CHUNK_SIZE_BYTE*2, &state );
}
@@ -300,32 +298,31 @@ void S_AdpcmEncodeSound( sfx_t *sfx, short *samples ) {
inOffset = 0;
count = sfx->soundLength;
state.index = 0;
state.sample = samples[ 0 ];
state.sample = samples[0];
chunk = NULL;
while( count ) {
n = count;
if( n > SND_CHUNK_SIZE_BYTE * 2 ) {
n = SND_CHUNK_SIZE_BYTE * 2;
if( n > SND_CHUNK_SIZE_BYTE*2 ) {
n = SND_CHUNK_SIZE_BYTE*2;
}
newchunk = SND_malloc();
if( sfx->soundData == NULL ) {
if (sfx->soundData == NULL) {
sfx->soundData = newchunk;
}
else if( chunk != NULL ) {
} else {
chunk->next = newchunk;
}
chunk = newchunk;
// output the header
chunk->adpcm.index = state.index;
chunk->adpcm.index = state.index;
chunk->adpcm.sample = state.sample;
out = ( byte * )chunk->sndChunk;
out = (byte *)chunk->sndChunk;
// encode the samples
S_AdpcmEncode( samples + inOffset, ( char * )out, n, &state );
S_AdpcmEncode( samples + inOffset, out, n, &state );
inOffset += n;
count -= n;
-240
View File
@@ -1,240 +0,0 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
Copyright (C) 2005 Stuart Dalton (badcdev@gmail.com)
This file is part of Quake III Arena source code.
Quake III Arena source code is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the License,
or (at your option) any later version.
Quake III Arena source code is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Quake III Arena source code; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
#include "client.h"
#include "snd_codec.h"
static snd_codec_t *codecs;
/*
=================
S_FileExtension
=================
*/
static char *S_FileExtension(const char *fni)
{
// we should search from the ending to the last '/'
char *fn = (char *) fni + strlen(fni) - 1;
char *eptr = NULL;
while(*fn != '/' && fn != fni)
{
if(*fn == '.')
{
eptr = fn;
break;
}
fn--;
}
return eptr;
}
/*
=================
S_FindCodecForFile
Select an appropriate codec for a file based on its extension
=================
*/
static snd_codec_t *S_FindCodecForFile(const char *filename)
{
char *ext = S_FileExtension(filename);
snd_codec_t *codec = codecs;
if(!ext)
{
// No extension - auto-detect
while(codec)
{
char fn[MAX_QPATH];
// there is no extension so we do not need to subtract 4 chars
Q_strncpyz(fn, filename, MAX_QPATH);
COM_DefaultExtension(fn, MAX_QPATH, codec->ext);
// Check it exists
if( FS_ReadFile( fn, NULL ) != -1 )
return codec;
// Nope. Next!
codec = codec->next;
}
// Nothin'
return NULL;
}
while(codec)
{
if(!Q_stricmp(ext, codec->ext))
return codec;
codec = codec->next;
}
return NULL;
}
/*
=================
S_CodecInit
=================
*/
void S_CodecInit()
{
codecs = NULL;
S_CodecRegister(&wav_codec);
#ifdef USE_CODEC_VORBIS
S_CodecRegister(&ogg_codec);
#endif
#if USE_CODEC_MP3
S_CodecRegister(&mp3_codec);
#endif
}
/*
=================
S_CodecShutdown
=================
*/
void S_CodecShutdown()
{
codecs = NULL;
}
/*
=================
S_CodecRegister
=================
*/
void S_CodecRegister(snd_codec_t *codec)
{
codec->next = codecs;
codecs = codec;
}
/*
=================
S_CodecLoad
=================
*/
void *S_CodecLoad(const char *filename, snd_info_t *info)
{
snd_codec_t *codec;
char fn[MAX_QPATH];
codec = S_FindCodecForFile(filename);
if(!codec)
{
Com_Printf("Unknown extension for %s\n", filename);
return NULL;
}
strncpy(fn, filename, sizeof(fn));
COM_DefaultExtension(fn, sizeof(fn), codec->ext);
return codec->load(fn, info);
}
/*
=================
S_CodecOpenStream
=================
*/
snd_stream_t *S_CodecOpenStream(const char *filename)
{
snd_codec_t *codec;
char fn[MAX_QPATH];
codec = S_FindCodecForFile(filename);
if(!codec)
{
Com_Printf("Unknown extension for %s\n", filename);
return NULL;
}
strncpy(fn, filename, sizeof(fn));
COM_DefaultExtension(fn, sizeof(fn), codec->ext);
return codec->open(fn);
}
void S_CodecCloseStream(snd_stream_t *stream)
{
stream->codec->close(stream);
}
int S_CodecReadStream(snd_stream_t *stream, int bytes, void *buffer)
{
return stream->codec->read(stream, bytes, buffer);
}
//=======================================================================
// Util functions (used by codecs)
/*
=================
S_CodecUtilOpen
=================
*/
snd_stream_t *S_CodecUtilOpen(const char *filename, snd_codec_t *codec)
{
snd_stream_t *stream;
fileHandle_t hnd;
int length;
// Try to open the file
length = FS_FOpenFileRead(filename, &hnd, qtrue, qtrue);
if(!hnd)
{
Com_Printf("Can't read sound file %s\n", filename);
return NULL;
}
// Allocate a stream
stream = Z_Malloc(sizeof(snd_stream_t));
if(!stream)
{
FS_FCloseFile(hnd);
return NULL;
}
// Copy over, return
stream->codec = codec;
stream->file = hnd;
stream->length = length;
return stream;
}
/*
=================
S_CodecUtilClose
=================
*/
void S_CodecUtilClose(snd_stream_t **stream)
{
FS_FCloseFile((*stream)->file);
Z_Free(*stream);
*stream = NULL;
}
-115
View File
@@ -1,115 +0,0 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
Copyright (C) 2005 Stuart Dalton (badcdev@gmail.com)
This file is part of Quake III Arena source code.
Quake III Arena source code is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the License,
or (at your option) any later version.
Quake III Arena source code is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Quake III Arena source code; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
#ifndef _SND_CODEC_H_
#define _SND_CODEC_H_
#include "../qcommon/q_shared.h"
#include "../qcommon/qcommon.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef struct snd_info_s
{
int rate;
int width;
int channels;
int samples;
int size;
int dataofs;
} snd_info_t;
typedef struct snd_codec_s snd_codec_t;
typedef struct snd_stream_s
{
snd_codec_t *codec;
fileHandle_t file;
snd_info_t info;
int length;
int pos;
void *ptr;
} snd_stream_t;
// Codec functions
typedef void *(*CODEC_LOAD)(const char *filename, snd_info_t *info);
typedef snd_stream_t *(*CODEC_OPEN)(const char *filename);
typedef int (*CODEC_READ)(snd_stream_t *stream, int bytes, void *buffer);
typedef void (*CODEC_CLOSE)(snd_stream_t *stream);
// Codec data structure
struct snd_codec_s
{
char *ext;
CODEC_LOAD load;
CODEC_OPEN open;
CODEC_READ read;
CODEC_CLOSE close;
snd_codec_t *next;
};
// Codec management
void S_CodecInit( void );
void S_CodecShutdown( void );
void S_CodecRegister(snd_codec_t *codec);
void *S_CodecLoad(const char *filename, snd_info_t *info);
snd_stream_t *S_CodecOpenStream(const char *filename);
void S_CodecCloseStream(snd_stream_t *stream);
int S_CodecReadStream(snd_stream_t *stream, int bytes, void *buffer);
// Util functions (used by codecs)
snd_stream_t *S_CodecUtilOpen(const char *filename, snd_codec_t *codec);
void S_CodecUtilClose(snd_stream_t **stream);
// WAV Codec
extern snd_codec_t wav_codec;
void *S_WAV_CodecLoad(const char *filename, snd_info_t *info);
snd_stream_t *S_WAV_CodecOpenStream(const char *filename);
void S_WAV_CodecCloseStream(snd_stream_t *stream);
int S_WAV_CodecReadStream(snd_stream_t *stream, int bytes, void *buffer);
// Ogg Vorbis codec
#ifdef USE_CODEC_VORBIS
extern snd_codec_t ogg_codec;
void *S_OGG_CodecLoad(const char *filename, snd_info_t *info);
snd_stream_t *S_OGG_CodecOpenStream(const char *filename);
void S_OGG_CodecCloseStream(snd_stream_t *stream);
int S_OGG_CodecReadStream(snd_stream_t *stream, int bytes, void *buffer);
#endif // USE_CODEC_VORBIS
#if USE_CODEC_MP3
// MP3 codec
extern snd_codec_t mp3_codec;
void *S_MP3_CodecLoad(const char *filename, snd_info_t *info);
snd_stream_t *S_MP3_CodecOpenStream(const char *filename);
void S_MP3_CodecCloseStream(snd_stream_t *stream);
int S_MP3_CodecReadStream(snd_stream_t *stream, int bytes, void *buffer);
#endif
#ifdef __cplusplus
}
#endif
#endif // !_SND_CODEC_H_
-717
View File
@@ -1,717 +0,0 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
Copyright (C) 2005 Stuart Dalton (badcdev@gmail.com)
Copyright (C) 2005-2006 Joerg Dietrich <dietrich_joerg@gmx.de>
Copyright (C) 2006 Thilo Schulz <arny@ats.s.bawue.de>
This file is part of Quake III Arena source code.
Quake III Arena source code is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the License,
or (at your option) any later version.
Quake III Arena source code is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Quake III Arena source code; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
#if USE_CODEC_MP3
// includes for the Q3 sound system
#include "client.h"
#include "snd_codec.h"
// includes for the MP3 codec
#include <mad.h>
#define MP3_SAMPLE_WIDTH 2
#define MP3_PCMSAMPLES_PERSLICE 32
// buffer size used when reading through the mp3
#define MP3_DATA_BUFSIZ 128*1024
// undefine this if you don't want any dithering.
#define MP3_DITHERING
// Q3 MP3 codec
snd_codec_t mp3_codec =
{
".mp3",
S_MP3_CodecLoad,
S_MP3_CodecOpenStream,
S_MP3_CodecReadStream,
S_MP3_CodecCloseStream,
NULL
};
// structure used for info purposes
struct snd_codec_mp3_info
{
byte encbuf[MP3_DATA_BUFSIZ]; // left over bytes not consumed
// by the decoder.
struct mad_stream madstream; // uses encbuf as buffer.
struct mad_frame madframe; // control structures for libmad.
struct mad_synth madsynth;
byte *pcmbuf; // buffer for not-used samples.
int buflen; // length of buffer data.
int pcmbufsize; // amount of allocated memory for
// pcmbuf. This should have at least
// the size of a decoded mp3 frame.
byte *dest; // copy decoded data here.
int destlen; // amount of already copied data.
int destsize; // amount of bytes we must decode.
};
/*************** MP3 utility functions ***************/
/*
=================
S_MP3_ReadData
=================
*/
// feed libmad with data
int S_MP3_ReadData(snd_stream_t *stream, struct mad_stream *madstream, byte *encbuf, int encbufsize)
{
int retval;
int leftover;
if(!stream)
return -1;
leftover = madstream->bufend - madstream->next_frame;
if(leftover > 0)
memmove(encbuf, madstream->this_frame, leftover);
// Fill the buffer right to the end
retval = FS_Read(&encbuf[leftover], encbufsize - leftover, stream->file);
if(retval <= 0)
{
// EOF reached, that's ok.
return 0;
}
mad_stream_buffer(madstream, encbuf, retval + leftover);
return retval;
}
/*
=================
S_MP3_Scanfile
to determine the samplecount, we apparently must get *all* headers :(
I basically used the xmms-mad plugin source to see how this stuff works.
returns a value < 0 on error.
=================
*/
int S_MP3_Scanfile(snd_stream_t *stream)
{
struct mad_stream madstream;
struct mad_header madheader;
int retval;
int samplecount;
byte encbuf[MP3_DATA_BUFSIZ];
// error out on invalid input.
if(!stream)
return -1;
mad_stream_init(&madstream);
mad_header_init(&madheader);
while(1)
{
retval = S_MP3_ReadData(stream, &madstream, encbuf, sizeof(encbuf));
if(retval < 0)
return -1;
else if(retval == 0)
break;
// Start decoding the headers.
while(1)
{
if((retval = mad_header_decode(&madheader, &madstream)) < 0)
{
if(madstream.error == MAD_ERROR_BUFLEN)
{
// We need to read more data
break;
}
if(!MAD_RECOVERABLE (madstream.error))
{
// unrecoverable error... we must bail out.
return retval;
}
mad_stream_skip(&madstream, madstream.skiplen);
continue;
}
// we got a valid header.
if(madheader.layer != MAD_LAYER_III)
{
// we don't support non-mp3s
return -1;
}
if(!stream->info.samples)
{
// This here is the very first frame. Set initial values now,
// that we expect to stay constant throughout the whole mp3.
stream->info.rate = madheader.samplerate;
stream->info.width = MP3_SAMPLE_WIDTH;
stream->info.channels = MAD_NCHANNELS(&madheader);
stream->info.samples = 0;
stream->info.size = 0; // same here.
stream->info.dataofs = 0;
}
else
{
// Check whether something changed that shouldn't.
if(stream->info.rate != madheader.samplerate ||
stream->info.channels != MAD_NCHANNELS(&madheader))
return -1;
}
// Update the counters
samplecount = MAD_NSBSAMPLES(&madheader) * MP3_PCMSAMPLES_PERSLICE;
stream->info.samples += samplecount;
stream->info.size += samplecount * stream->info.channels * stream->info.width;
}
}
// Reset the file pointer so we can do the real decoding.
FS_Seek(stream->file, 0, FS_SEEK_SET);
return 0;
}
/************************ dithering functions ***************************/
#ifdef MP3_DITHERING
// All dithering done here is taken from the GPL'ed xmms-mad plugin.
/* Copyright (C) 1997 Makoto Matsumoto and Takuji Nishimura. */
/* Any feedback is very welcome. For any question, comments, */
/* see http://www.math.keio.ac.jp/matumoto/emt.html or email */
/* matumoto@math.keio.ac.jp */
/* Period parameters */
#define MP3_DITH_N 624
#define MP3_DITH_M 397
#define MATRIX_A 0x9908b0df /* constant vector a */
#define UPPER_MASK 0x80000000 /* most significant w-r bits */
#define LOWER_MASK 0x7fffffff /* least significant r bits */
/* Tempering parameters */
#define TEMPERING_MASK_B 0x9d2c5680
#define TEMPERING_MASK_C 0xefc60000
#define TEMPERING_SHIFT_U(y) (y >> 11)
#define TEMPERING_SHIFT_S(y) (y << 7)
#define TEMPERING_SHIFT_T(y) (y << 15)
#define TEMPERING_SHIFT_L(y) (y >> 18)
static unsigned long mt[MP3_DITH_N]; /* the array for the state vector */
static int mti=MP3_DITH_N+1; /* mti==MP3_DITH_N+1 means mt[MP3_DITH_N] is not initialized */
/* initializing the array with a NONZERO seed */
void sgenrand(unsigned long seed)
{
/* setting initial seeds to mt[MP3_DITH_N] using */
/* the generator Line 25 of Table 1 in */
/* [KNUTH 1981, The Art of Computer Programming */
/* Vol. 2 (2nd Ed.), pp102] */
mt[0]= seed & 0xffffffff;
for (mti=1; mti<MP3_DITH_N; mti++)
mt[mti] = (69069 * mt[mti-1]) & 0xffffffff;
}
unsigned long genrand(void)
{
unsigned long y;
static unsigned long mag01[2]={0x0, MATRIX_A};
/* mag01[x] = x * MATRIX_A for x=0,1 */
if (mti >= MP3_DITH_N) { /* generate MP3_DITH_N words at one time */
int kk;
if (mti == MP3_DITH_N+1) /* if sgenrand() has not been called, */
sgenrand(4357); /* a default initial seed is used */
for (kk=0;kk<MP3_DITH_N-MP3_DITH_M;kk++) {
y = (mt[kk]&UPPER_MASK)|(mt[kk+1]&LOWER_MASK);
mt[kk] = mt[kk+MP3_DITH_M] ^ (y >> 1) ^ mag01[y & 0x1];
}
for (;kk<MP3_DITH_N-1;kk++) {
y = (mt[kk]&UPPER_MASK)|(mt[kk+1]&LOWER_MASK);
mt[kk] = mt[kk+(MP3_DITH_M-MP3_DITH_N)] ^ (y >> 1) ^ mag01[y & 0x1];
}
y = (mt[MP3_DITH_N-1]&UPPER_MASK)|(mt[0]&LOWER_MASK);
mt[MP3_DITH_N-1] = mt[MP3_DITH_M-1] ^ (y >> 1) ^ mag01[y & 0x1];
mti = 0;
}
y = mt[mti++];
y ^= TEMPERING_SHIFT_U(y);
y ^= TEMPERING_SHIFT_S(y) & TEMPERING_MASK_B;
y ^= TEMPERING_SHIFT_T(y) & TEMPERING_MASK_C;
y ^= TEMPERING_SHIFT_L(y);
return y;
}
long triangular_dither_noise(int nbits) {
// parameter nbits : the peak-to-peak amplitude desired (in bits)
// use with nbits set to 2 + nber of bits to be trimmed.
// (because triangular is made from two uniformly distributed processes,
// it starts at 2 bits peak-to-peak amplitude)
// see The Theory of Dithered Quantization by Robert Alexander Wannamaker
// for complete proof of why that's optimal
long v = (genrand()/2 - genrand()/2); // in ]-2^31, 2^31[
//int signe = (v>0) ? 1 : -1;
long P = 1 << (32 - nbits); // the power of 2
v /= P;
// now v in ]-2^(nbits-1), 2^(nbits-1) [
return v;
}
#endif // MP3_DITHERING
/************************ decoder functions ***************************/
/*
=================
S_MP3_Scale
Converts the signal to 16 bit LE-PCM data and does dithering.
- borrowed from xmms-mad plugin source.
=================
*/
/*
* xmms-mad - mp3 plugin for xmms
* Copyright (C) 2001-2002 Sam Clegg
*/
signed int S_MP3_Scale(mad_fixed_t sample)
{
int n_bits_to_loose = MAD_F_FRACBITS + 1 - 16;
#ifdef MP3_DITHERING
int dither;
#endif
// round
sample += (1L << (n_bits_to_loose - 1));
#ifdef MP3_DITHERING
dither = triangular_dither_noise(n_bits_to_loose + 1);
sample += dither;
#endif
/* clip */
if (sample >= MAD_F_ONE)
sample = MAD_F_ONE - 1;
else if (sample < -MAD_F_ONE)
sample = -MAD_F_ONE;
/* quantize */
return sample >> n_bits_to_loose;
}
/*
=================
S_MP3_PCMCopy
Copy and convert pcm data until bytecount bytes have been written.
return the position in pcm->samples.
indicate the amount of actually written bytes in wrotecnt.
=================
*/
int S_MP3_PCMCopy(byte *buf, struct mad_pcm *pcm, int bufofs,
int sampleofs, int bytecount, int *wrotecnt)
{
int written = 0;
signed int sample;
int framesize = pcm->channels * MP3_SAMPLE_WIDTH;
// add new pcm data.
while(written < bytecount && sampleofs < pcm->length)
{
sample = S_MP3_Scale(pcm->samples[0][sampleofs]);
#ifdef Q3_BIG_ENDIAN
// output to 16 bit big endian PCM
buf[bufofs++] = (sample >> 8) & 0xff;
buf[bufofs++] = sample & 0xff;
#else
// output to 16 bit little endian PCM
buf[bufofs++] = sample & 0xff;
buf[bufofs++] = (sample >> 8) & 0xff;
#endif
if(pcm->channels == 2)
{
sample = S_MP3_Scale(pcm->samples[1][sampleofs]);
#ifdef Q3_BIG_ENDIAN
buf[bufofs++] = (sample >> 8) & 0xff;
buf[bufofs++] = sample & 0xff;
#else
buf[bufofs++] = sample & 0xff;
buf[bufofs++] = (sample >> 8) & 0xff;
#endif
}
sampleofs++;
written += framesize;
}
if(wrotecnt)
*wrotecnt = written;
return sampleofs;
}
/*
=================
S_MP3_Decode
=================
*/
// gets executed for every decoded frame.
int S_MP3_Decode(snd_stream_t *stream)
{
struct snd_codec_mp3_info *mp3info;
struct mad_stream *madstream;
struct mad_frame *madframe;
struct mad_synth *madsynth;
struct mad_pcm *pcm;
int cursize;
int samplecount;
int needcount;
int wrote;
int retval;
if(!stream)
return -1;
mp3info = stream->ptr;
madstream = &mp3info->madstream;
madframe = &mp3info->madframe;
if(mad_frame_decode(madframe, madstream))
{
if(madstream->error == MAD_ERROR_BUFLEN)
{
// we need more data. Read another chunk.
retval = S_MP3_ReadData(stream, madstream, mp3info->encbuf, sizeof(mp3info->encbuf));
// call myself again now that buffer is full.
if(retval > 0)
retval = S_MP3_Decode(stream);
}
else if(MAD_RECOVERABLE(madstream->error))
{
mad_stream_skip(madstream, madstream->skiplen);
return S_MP3_Decode(stream);
}
else
retval = -1;
return retval;
}
// check whether this really is an mp3
if(madframe->header.layer != MAD_LAYER_III)
return -1;
// generate pcm data
madsynth = &mp3info->madsynth;
mad_synth_frame(madsynth, madframe);
pcm = &madsynth->pcm;
// perform a few checks to see whether something changed that shouldn't.
if(stream->info.rate != pcm->samplerate ||
stream->info.channels != pcm->channels)
{
return -1;
}
// see whether we have got enough data now.
cursize = pcm->length * pcm->channels * stream->info.width;
needcount = mp3info->destsize - mp3info->destlen;
// Copy exactly as many samples as required.
samplecount = S_MP3_PCMCopy(mp3info->dest, pcm,
mp3info->destlen, 0, needcount, &wrote);
mp3info->destlen += wrote;
if(samplecount < pcm->length)
{
// Not all samples got copied. Copy the rest into the pcm buffer.
samplecount = S_MP3_PCMCopy(mp3info->pcmbuf, pcm,
mp3info->buflen,
samplecount,
mp3info->pcmbufsize - mp3info->buflen,
&wrote);
mp3info->buflen += wrote;
if(samplecount < pcm->length)
{
// The pcm buffer was not large enough. Make it bigger.
byte *newbuf = Z_Malloc(cursize);
if(mp3info->pcmbuf)
{
memcpy(newbuf, mp3info->pcmbuf, mp3info->buflen);
Z_Free(mp3info->pcmbuf);
}
mp3info->pcmbuf = newbuf;
mp3info->pcmbufsize = cursize;
samplecount = S_MP3_PCMCopy(mp3info->pcmbuf, pcm,
mp3info->buflen,
samplecount,
mp3info->pcmbufsize - mp3info->buflen,
&wrote);
mp3info->buflen += wrote;
}
// we're definitely done.
retval = 0;
}
else if(mp3info->destlen >= mp3info->destsize)
retval = 0;
else
retval = 1;
return retval;
}
/*************** Callback functions for quake3 ***************/
/*
=================
S_MP3_CodecOpenStream
=================
*/
snd_stream_t *S_MP3_CodecOpenStream(const char *filename)
{
snd_stream_t *stream;
struct snd_codec_mp3_info *mp3info;
// Open the stream
stream = S_CodecUtilOpen(filename, &mp3_codec);
if(!stream || stream->length <= 0)
return NULL;
// We have to scan through the MP3 to determine the important mp3 info.
if(S_MP3_Scanfile(stream) < 0)
{
// scanning didn't work out...
S_CodecUtilClose(&stream);
return NULL;
}
// Initialize the mp3 info structure we need for streaming
mp3info = Z_Malloc(sizeof(*mp3info));
if(!mp3info)
{
S_CodecUtilClose(&stream);
return NULL;
}
stream->ptr = mp3info;
// initialize the libmad control structures.
mad_stream_init(&mp3info->madstream);
mad_frame_init(&mp3info->madframe);
mad_synth_init(&mp3info->madsynth);
if(S_MP3_ReadData(stream, &mp3info->madstream, mp3info->encbuf, sizeof(mp3info->encbuf)) <= 0)
{
// we didnt read anything, that's bad.
S_MP3_CodecCloseStream(stream);
return NULL;
}
return stream;
}
/*
=================
S_MP3_CodecCloseStream
=================
*/
// free all memory we allocated.
void S_MP3_CodecCloseStream(snd_stream_t *stream)
{
struct snd_codec_mp3_info *mp3info;
if(!stream)
return;
// free all data in our mp3info tree
if(stream->ptr)
{
mp3info = stream->ptr;
if(mp3info->pcmbuf)
Z_Free(mp3info->pcmbuf);
mad_synth_finish(&mp3info->madsynth);
mad_frame_finish(&mp3info->madframe);
mad_stream_finish(&mp3info->madstream);
Z_Free(stream->ptr);
}
S_CodecUtilClose(&stream);
}
/*
=================
S_MP3_CodecReadStream
=================
*/
int S_MP3_CodecReadStream(snd_stream_t *stream, int bytes, void *buffer)
{
struct snd_codec_mp3_info *mp3info;
int retval;
if(!stream)
return -1;
mp3info = stream->ptr;
// Make sure we get complete frames all the way through.
bytes -= bytes % (stream->info.channels * stream->info.width);
if(mp3info->buflen)
{
if(bytes < mp3info->buflen)
{
// we still have enough bytes in our decoded pcm buffer
memcpy(buffer, mp3info->pcmbuf, bytes);
// remove the portion from our buffer.
mp3info->buflen -= bytes;
memmove(mp3info->pcmbuf, &mp3info->pcmbuf[bytes], mp3info->buflen);
return bytes;
}
else
{
// copy over the samples we already have.
memcpy(buffer, mp3info->pcmbuf, mp3info->buflen);
mp3info->destlen = mp3info->buflen;
mp3info->buflen = 0;
}
}
else
mp3info->destlen = 0;
mp3info->dest = buffer;
mp3info->destsize = bytes;
do
{
retval = S_MP3_Decode(stream);
} while(retval > 0);
// if there was an error return nothing.
if(retval < 0)
return 0;
return mp3info->destlen;
}
/*
=====================================================================
S_MP3_CodecLoad
We handle S_MP3_CodecLoad as a special case of the streaming functions
where we read the whole stream at once.
======================================================================
*/
void *S_MP3_CodecLoad(const char *filename, snd_info_t *info)
{
snd_stream_t *stream;
byte *pcmbuffer;
// check if input is valid
if(!filename)
return NULL;
stream = S_MP3_CodecOpenStream(filename);
if(!stream)
return NULL;
// copy over the info
info->rate = stream->info.rate;
info->width = stream->info.width;
info->channels = stream->info.channels;
info->samples = stream->info.samples;
info->dataofs = stream->info.dataofs;
// allocate enough buffer for all pcm data
// pcmbuffer = Z_Malloc(stream->info.size);
pcmbuffer = Hunk_AllocateTempMemory(stream->info.size);
if(!pcmbuffer)
{
S_MP3_CodecCloseStream(stream);
return NULL;
}
info->size = S_MP3_CodecReadStream(stream, stream->info.size, pcmbuffer);
if(info->size <= 0)
{
// we didn't read anything at all. darn.
// Z_Free(pcmbuffer);
Hunk_FreeTempMemory(pcmbuffer);
pcmbuffer = NULL;
}
S_MP3_CodecCloseStream(stream);
return pcmbuffer;
}
#endif
-474
View File
@@ -1,474 +0,0 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
Copyright (C) 2005 Stuart Dalton (badcdev@gmail.com)
Copyright (C) 2005-2006 Joerg Dietrich <dietrich_joerg@gmx.de>
This file is part of Quake III Arena source code.
Quake III Arena source code is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the License,
or (at your option) any later version.
Quake III Arena source code is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Quake III Arena source code; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
// OGG support is enabled by this define
#ifdef USE_CODEC_VORBIS
// includes for the Q3 sound system
#include "client.h"
#include "snd_codec.h"
// includes for the OGG codec
#include <errno.h>
#include <vorbis/vorbisfile.h>
// The OGG codec can return the samples in a number of different formats,
// we use the standard signed short format.
#define OGG_SAMPLEWIDTH 2
// Q3 OGG codec
snd_codec_t ogg_codec =
{
".ogg",
S_OGG_CodecLoad,
S_OGG_CodecOpenStream,
S_OGG_CodecReadStream,
S_OGG_CodecCloseStream,
NULL
};
// callbacks for vobisfile
// fread() replacement
size_t S_OGG_Callback_read(void *ptr, size_t size, size_t nmemb, void *datasource)
{
snd_stream_t *stream;
int byteSize = 0;
int bytesRead = 0;
size_t nMembRead = 0;
// check if input is valid
if(!ptr)
{
errno = EFAULT;
return 0;
}
if(!(size && nmemb))
{
// It's not an error, caller just wants zero bytes!
errno = 0;
return 0;
}
if(!datasource)
{
errno = EBADF;
return 0;
}
// we use a snd_stream_t in the generic pointer to pass around
stream = (snd_stream_t *) datasource;
// FS_Read does not support multi-byte elements
byteSize = nmemb * size;
// read it with the Q3 function FS_Read()
bytesRead = FS_Read(ptr, byteSize, stream->file);
// update the file position
stream->pos += bytesRead;
// this function returns the number of elements read not the number of bytes
nMembRead = bytesRead / size;
// even if the last member is only read partially
// it is counted as a whole in the return value
if(bytesRead % size)
{
nMembRead++;
}
return nMembRead;
}
// fseek() replacement
int S_OGG_Callback_seek(void *datasource, ogg_int64_t offset, int whence)
{
snd_stream_t *stream;
int retVal = 0;
// check if input is valid
if(!datasource)
{
errno = EBADF;
return -1;
}
// snd_stream_t in the generic pointer
stream = (snd_stream_t *) datasource;
// we must map the whence to its Q3 counterpart
switch(whence)
{
case SEEK_SET :
{
// set the file position in the actual file with the Q3 function
retVal = FS_Seek(stream->file, (long) offset, FS_SEEK_SET);
// something has gone wrong, so we return here
if(!(retVal == 0))
{
return retVal;
}
// keep track of file position
stream->pos = (int) offset;
break;
}
case SEEK_CUR :
{
// set the file position in the actual file with the Q3 function
retVal = FS_Seek(stream->file, (long) offset, FS_SEEK_CUR);
// something has gone wrong, so we return here
if(!(retVal == 0))
{
return retVal;
}
// keep track of file position
stream->pos += (int) offset;
break;
}
case SEEK_END :
{
// Quake 3 seems to have trouble with FS_SEEK_END
// so we use the file length and FS_SEEK_SET
// set the file position in the actual file with the Q3 function
retVal = FS_Seek(stream->file, (long) stream->length + (long) offset, FS_SEEK_SET);
// something has gone wrong, so we return here
if(!(retVal == 0))
{
return retVal;
}
// keep track of file position
stream->pos = stream->length + (int) offset;
break;
}
default :
{
// unknown whence, so we return an error
errno = EINVAL;
return -1;
}
}
// stream->pos shouldn't be smaller than zero or bigger than the filesize
stream->pos = (stream->pos < 0) ? 0 : stream->pos;
stream->pos = (stream->pos > stream->length) ? stream->length : stream->pos;
return 0;
}
// fclose() replacement
int S_OGG_Callback_close(void *datasource)
{
// we do nothing here and close all things manually in S_OGG_CodecCloseStream()
return 0;
}
// ftell() replacement
long S_OGG_Callback_tell(void *datasource)
{
// check if input is valid
if(!datasource)
{
errno = EBADF;
return -1;
}
// we keep track of the file position in stream->pos
return (long) (((snd_stream_t *) datasource) -> pos);
}
// the callback structure
const ov_callbacks S_OGG_Callbacks =
{
&S_OGG_Callback_read,
&S_OGG_Callback_seek,
&S_OGG_Callback_close,
&S_OGG_Callback_tell
};
/*
=================
S_OGG_CodecOpenStream
=================
*/
snd_stream_t *S_OGG_CodecOpenStream(const char *filename)
{
snd_stream_t *stream;
// OGG codec control structure
OggVorbis_File *vf;
// some variables used to get informations about the OGG
vorbis_info *OGGInfo;
ogg_int64_t numSamples;
// check if input is valid
if(!filename)
{
return NULL;
}
// Open the stream
stream = S_CodecUtilOpen(filename, &ogg_codec);
if(!stream)
{
return NULL;
}
// alloctate the OggVorbis_File
vf = Z_Malloc(sizeof(OggVorbis_File));
if(!vf)
{
S_CodecUtilClose(&stream);
return NULL;
}
// open the codec with our callbacks and stream as the generic pointer
if(ov_open_callbacks(stream, vf, NULL, 0, S_OGG_Callbacks) != 0)
{
Z_Free(vf);
S_CodecUtilClose(&stream);
return NULL;
}
// the stream must be seekable
if(!ov_seekable(vf))
{
ov_clear(vf);
Z_Free(vf);
S_CodecUtilClose(&stream);
return NULL;
}
// we only support OGGs with one substream
if(ov_streams(vf) != 1)
{
ov_clear(vf);
Z_Free(vf);
S_CodecUtilClose(&stream);
return NULL;
}
// get the info about channels and rate
OGGInfo = ov_info(vf, 0);
if(!OGGInfo)
{
ov_clear(vf);
Z_Free(vf);
S_CodecUtilClose(&stream);
return NULL;
}
// get the number of sample-frames in the OGG
numSamples = ov_pcm_total(vf, 0);
// fill in the info-structure in the stream
stream->info.rate = OGGInfo->rate;
stream->info.width = OGG_SAMPLEWIDTH;
stream->info.channels = OGGInfo->channels;
stream->info.samples = numSamples;
stream->info.size = stream->info.samples * stream->info.channels * stream->info.width;
stream->info.dataofs = 0;
// We use stream->pos for the file pointer in the compressed ogg file
stream->pos = 0;
// We use the generic pointer in stream for the OGG codec control structure
stream->ptr = vf;
return stream;
}
/*
=================
S_OGG_CodecCloseStream
=================
*/
void S_OGG_CodecCloseStream(snd_stream_t *stream)
{
// check if input is valid
if(!stream)
{
return;
}
// let the OGG codec cleanup its stuff
ov_clear((OggVorbis_File *) stream->ptr);
// free the OGG codec control struct
Z_Free(stream->ptr);
// close the stream
S_CodecUtilClose(&stream);
}
/*
=================
S_OGG_CodecReadStream
=================
*/
int S_OGG_CodecReadStream(snd_stream_t *stream, int bytes, void *buffer)
{
// buffer handling
int bytesRead, bytesLeft, c;
char *bufPtr;
// Bitstream for the decoder
int BS = 0;
// big endian machines want their samples in big endian order
int IsBigEndian = 0;
# ifdef Q3_BIG_ENDIAN
IsBigEndian = 1;
# endif // Q3_BIG_ENDIAN
// check if input is valid
if(!(stream && buffer))
{
return 0;
}
if(bytes <= 0)
{
return 0;
}
bytesRead = 0;
bytesLeft = bytes;
bufPtr = buffer;
// cycle until we have the requested or all available bytes read
while(-1)
{
// read some bytes from the OGG codec
c = ov_read((OggVorbis_File *) stream->ptr, bufPtr, bytesLeft, IsBigEndian, OGG_SAMPLEWIDTH, 1, &BS);
// no more bytes are left
if(c <= 0)
{
break;
}
bytesRead += c;
bytesLeft -= c;
bufPtr += c;
// we have enough bytes
if(bytesLeft <= 0)
{
break;
}
}
return bytesRead;
}
/*
=====================================================================
S_OGG_CodecLoad
We handle S_OGG_CodecLoad as a special case of the streaming functions
where we read the whole stream at once.
======================================================================
*/
void *S_OGG_CodecLoad(const char *filename, snd_info_t *info)
{
snd_stream_t *stream;
byte *buffer;
int bytesRead;
// check if input is valid
if(!(filename && info))
{
return NULL;
}
// open the file as a stream
stream = S_OGG_CodecOpenStream(filename);
if(!stream)
{
return NULL;
}
// copy over the info
info->rate = stream->info.rate;
info->width = stream->info.width;
info->channels = stream->info.channels;
info->samples = stream->info.samples;
info->size = stream->info.size;
info->dataofs = stream->info.dataofs;
// allocate a buffer
// this buffer must be free-ed by the caller of this function
// buffer = Z_Malloc(info->size);
buffer = Hunk_AllocateTempMemory(info->size);
if(!buffer)
{
S_OGG_CodecCloseStream(stream);
return NULL;
}
// fill the buffer
bytesRead = S_OGG_CodecReadStream(stream, info->size, buffer);
// we don't even have read a single byte
if(bytesRead <= 0)
{
Z_Free(buffer);
S_OGG_CodecCloseStream(stream);
return NULL;
}
S_OGG_CodecCloseStream(stream);
return buffer;
}
#endif // USE_CODEC_VORBIS
-296
View File
@@ -1,296 +0,0 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
Copyright (C) 2005 Stuart Dalton (badcdev@gmail.com)
This file is part of Quake III Arena source code.
Quake III Arena source code is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the License,
or (at your option) any later version.
Quake III Arena source code is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Quake III Arena source code; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
#include "client.h"
#include "snd_codec.h"
/*
=================
FGetLittleLong
=================
*/
static int FGetLittleLong( fileHandle_t f ) {
int v;
FS_Read( &v, sizeof(v), f );
return LittleLong( v);
}
/*
=================
FGetLittleShort
=================
*/
static short FGetLittleShort( fileHandle_t f ) {
short v;
FS_Read( &v, sizeof(v), f );
return LittleShort( v);
}
/*
=================
S_ReadChunkInfo
=================
*/
static int S_ReadChunkInfo(fileHandle_t f, char *name)
{
int len, r;
name[4] = 0;
r = FS_Read(name, 4, f);
if(r != 4)
return -1;
len = FGetLittleLong(f);
if( len < 0 ) {
Com_Printf( S_COLOR_YELLOW "WARNING: Negative chunk length\n" );
return -1;
}
return len;
}
/*
=================
S_FindRIFFChunk
Returns the length of the data in the chunk, or -1 if not found
=================
*/
static int S_FindRIFFChunk( fileHandle_t f, char *chunk ) {
char name[5];
int len;
while( ( len = S_ReadChunkInfo(f, name) ) >= 0 )
{
// If this is the right chunk, return
if( !Q_strncmp( name, chunk, 4 ) )
return len;
len = PAD( len, 2 );
// Not the right chunk - skip it
FS_Seek( f, len, FS_SEEK_CUR );
}
return -1;
}
/*
=================
S_ByteSwapRawSamples
=================
*/
static void S_ByteSwapRawSamples( int samples, int width, int s_channels, const byte *data ) {
int i;
if ( width != 2 ) {
return;
}
if ( LittleShort( 256 ) == 256 ) {
return;
}
if ( s_channels == 2 ) {
samples <<= 1;
}
for ( i = 0 ; i < samples ; i++ ) {
((short *)data)[i] = LittleShort( ((short *)data)[i] );
}
}
/*
=================
S_ReadRIFFHeader
=================
*/
static qboolean S_ReadRIFFHeader(fileHandle_t file, snd_info_t *info)
{
char dump[16];
int wav_format;
int bits;
int fmtlen = 0;
// skip the riff wav header
FS_Read(dump, 12, file);
// Scan for the format chunk
if((fmtlen = S_FindRIFFChunk(file, "fmt ")) < 0)
{
Com_Printf( S_COLOR_RED "ERROR: Couldn't find \"fmt\" chunk\n");
return qfalse;
}
// Save the parameters
wav_format = FGetLittleShort(file);
info->channels = FGetLittleShort(file);
info->rate = FGetLittleLong(file);
FGetLittleLong(file);
FGetLittleShort(file);
bits = FGetLittleShort(file);
if( bits < 8 )
{
Com_Printf( S_COLOR_RED "ERROR: Less than 8 bit sound is not supported\n");
return qfalse;
}
info->width = bits / 8;
info->dataofs = 0;
// Skip the rest of the format chunk if required
if(fmtlen > 16)
{
fmtlen -= 16;
FS_Seek( file, fmtlen, FS_SEEK_CUR );
}
// Scan for the data chunk
if( (info->size = S_FindRIFFChunk(file, "data")) < 0)
{
Com_Printf( S_COLOR_RED "ERROR: Couldn't find \"data\" chunk\n");
return qfalse;
}
info->samples = (info->size / info->width) / info->channels;
return qtrue;
}
// WAV codec
snd_codec_t wav_codec =
{
".wav",
S_WAV_CodecLoad,
S_WAV_CodecOpenStream,
S_WAV_CodecReadStream,
S_WAV_CodecCloseStream,
NULL
};
/*
=================
S_WAV_CodecLoad
=================
*/
void *S_WAV_CodecLoad(const char *filename, snd_info_t *info)
{
fileHandle_t file;
void *buffer;
// Try to open the file
FS_FOpenFileRead(filename, &file, qtrue, qtrue);
if(!file)
{
Com_Printf( S_COLOR_RED "ERROR: Could not open \"%s\"\n",
filename);
return NULL;
}
// Read the RIFF header
if(!S_ReadRIFFHeader(file, info))
{
FS_FCloseFile(file);
Com_Printf( S_COLOR_RED "ERROR: Incorrect/unsupported format in \"%s\"\n",
filename);
return NULL;
}
// Allocate some memory
// buffer = Z_Malloc(info->size);
buffer = Hunk_AllocateTempMemory(info->size);
if(!buffer)
{
FS_FCloseFile(file);
Com_Printf( S_COLOR_RED "ERROR: Out of memory reading \"%s\"\n",
filename);
return NULL;
}
// Read, byteswap
FS_Read(buffer, info->size, file);
S_ByteSwapRawSamples(info->samples, info->width, info->channels, (byte *)buffer);
// Close and return
FS_FCloseFile(file);
return buffer;
}
/*
=================
S_WAV_CodecOpenStream
=================
*/
snd_stream_t *S_WAV_CodecOpenStream(const char *filename)
{
snd_stream_t *rv;
// Open
rv = S_CodecUtilOpen(filename, &wav_codec);
if(!rv)
return NULL;
// Read the RIFF header
if(!S_ReadRIFFHeader(rv->file, &rv->info))
{
S_CodecUtilClose(&rv);
return NULL;
}
return rv;
}
/*
=================
S_WAV_CodecCloseStream
=================
*/
void S_WAV_CodecCloseStream(snd_stream_t *stream)
{
S_CodecUtilClose(&stream);
}
/*
=================
S_WAV_CodecReadStream
=================
*/
int S_WAV_CodecReadStream(snd_stream_t *stream, int bytes, void *buffer)
{
int remaining = stream->info.size - stream->pos;
int samples;
if(remaining <= 0)
return 0;
if(bytes > remaining)
bytes = remaining;
stream->pos += bytes;
samples = (bytes / stream->info.width) / stream->info.channels;
FS_Read(buffer, bytes, stream->file);
S_ByteSwapRawSamples(samples, stream->info.width, stream->info.channels, buffer);
return bytes;
}
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
+48 -169
View File
@@ -15,14 +15,14 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Quake III Arena source code; if not, write to the Free Software
along with Foobar; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
// snd_local.h -- private sound definations
#include "../qcommon/q_shared.h"
#include "q_shared.h"
#include "../qcommon/qcommon.h"
#include "snd_public.h"
@@ -36,8 +36,6 @@ extern "C" {
#define SND_CHUNK_SIZE_FLOAT (SND_CHUNK_SIZE/2) // floats
#define SND_CHUNK_SIZE_BYTE (SND_CHUNK_SIZE*2) // floats
#define SFX_FLAG_STREAMED 4
typedef struct {
int left; // the final values will be clamped to +/- 0x00ffff00 and shifted down
int right;
@@ -55,6 +53,18 @@ typedef struct sndBuffer_s {
adpcm_state_t adpcm;
} sndBuffer;
typedef struct sfx_s {
sndBuffer *soundData;
qboolean defaultSound; // couldn't be loaded, so use buzz
qboolean inMemory; // not in Memory
qboolean soundCompressed; // not in Memory
int soundCompressionMethod;
int soundLength;
char soundName[MAX_QPATH];
int lastTimeUsed;
struct sfx_s *next;
} sfx_t;
typedef struct {
int channels;
int samples; // mono samples in buffer
@@ -64,87 +74,8 @@ typedef struct {
byte *buffer;
} dma_t;
typedef struct sfx_s {
sndBuffer *soundData;
qboolean defaultSound; // couldn't be loaded, so use buzz
qboolean inMemory; // not in Memory
qboolean soundCompressed; // not in Memory
int soundCompressionMethod;
int soundLength;
int soundChannels;
char soundName[MAX_QPATH];
int lastTimeUsed;
int iFlags;
struct sfx_s *next;
} sfx_t;
typedef struct {
char name[ MAX_QPATH ];
int loop_start;
int loop_end;
int max_number_playing;
float max_factor;
} sfx_info_t;
typedef struct {
vec3_t position;
vec3_t velocity;
int time;
qboolean use_listener;
} s_entity_t;
typedef struct {
char alias[ 32 ];
char path[ MAX_QPATH ];
int mood_num;
int flags;
float volume;
float fadetime;
int current_pos;
int current_state;
} song_t;
typedef struct {
int iFlags;
char szName[ MAX_QPATH ];
} sfxsavegame_t;
typedef struct channelbasesavegame_s {
qboolean bPlaying;
int iStatus;
sfxsavegame_t sfx;
int iEntNum;
int iEntChannel;
vec3_t vOrigin;
float fVolume;
int iBaseRate;
float fNewPitchMult;
float fMinDist;
float fMaxDist;
int iStartTime;
int iTime;
int iNextCheckObstructionTime;
int iEndTime;
int iFlags;
int iOffset;
int iLoopCount;
} channelbasesavegame_t;
typedef struct soundsystemsavegame_s {
channelbasesavegame_t Channels[ 96 ];
} soundsystemsavegame_t;
#define START_SAMPLE_IMMEDIATE 0x7fffffff
#define MAX_DOPPLER_SCALE 50.0f //arbitrary
#define THIRD_PERSON_THRESHOLD_SQ (48.0f*48.0f)
typedef struct loopSound_s {
vec3_t origin;
vec3_t velocity;
@@ -158,7 +89,8 @@ typedef struct loopSound_s {
int framenum;
} loopSound_t;
typedef struct channel_s {
typedef struct
{
int allocTime;
int startSample; // START_SAMPLE_IMMEDIATE = set immediately on next mix
int entnum; // to allow overriding a specific sound
@@ -172,7 +104,6 @@ typedef struct channel_s {
qboolean fixed_origin; // use origin instead of fetching entnum's origin
sfx_t *thesfx; // sfx structure
qboolean doppler;
qboolean fullVolume;
} channel_t;
@@ -188,48 +119,6 @@ typedef struct {
int dataofs; // chunk starts this many bytes from file start
} wavinfo_t;
typedef struct {
float volume;
float minDist;
float pitch;
float maxDist;
qboolean streamed;
int flags;
} sndparm_t;
// Interface between Q3 sound "api" and the sound backend
typedef struct
{
void (*Shutdown)(void);
void (*StartSound)( const vec3_t origin, int entnum, int entchannel, sfxHandle_t sfx );
void (*StartLocalSound)( sfxHandle_t sfx, int channelNum );
void (*StartBackgroundTrack)( const char *intro, const char *loop );
void (*StopBackgroundTrack)( void );
void (*RawSamples)(int stream, int samples, int rate, int width, int channels, const byte *data, float volume, int entityNum);
void (*StopAllSounds)( void );
void (*ClearLoopingSounds)( qboolean killall );
void (*AddLoopingSound)( int entityNum, const vec3_t origin, const vec3_t velocity, sfxHandle_t sfx );
void (*AddRealLoopingSound)( int entityNum, const vec3_t origin, const vec3_t velocity, sfxHandle_t sfx );
void (*StopLoopingSound)(int entityNum );
void (*Respatialize)( int entityNum, const vec3_t origin, vec3_t axis[3], int inwater );
void (*UpdateEntity)( int entityNum, const vec3_t origin, const vec3_t velocity );
void (*Update)( void );
void (*DisableSounds)( void );
void (*BeginRegistration)( void );
sfxHandle_t (*RegisterSound)( const char *sample, qboolean compressed );
qboolean (*IsSoundPlaying)( int channelNumber, const char *name );
void (*ClearSoundBuffer)( void );
void (*SoundInfo)( void );
void (*SoundList)( void );
#ifdef USE_VOIP
void (*StartCapture)( void );
int (*AvailableCaptureSamples)( void );
void (*Capture)( int samples, byte *data );
void (*StopCapture)( void );
void (*MasterGain)( float gain );
#endif
} soundInterface_t;
/*
====================================================================
@@ -254,86 +143,76 @@ void SNDDMA_Submit(void);
//====================================================================
#define MAX_SOUNDCHANNELS 96
#define MAX_CHANNELS 96
extern channel_t s_channels[MAX_SOUNDCHANNELS];
extern channel_t loop_channels[MAX_SOUNDCHANNELS];
extern channel_t s_channels[MAX_CHANNELS];
extern channel_t loop_channels[MAX_CHANNELS];
extern int numLoopChannels;
extern int s_paintedtime;
extern int s_rawend;
extern vec3_t listener_forward;
extern vec3_t listener_right;
extern vec3_t listener_up;
extern dma_t dma;
#define MAX_RAW_SAMPLES 16384
#define MAX_RAW_STREAMS (MAX_CLIENTS * 2 + 1)
extern portable_samplepair_t s_rawsamples[MAX_RAW_STREAMS][MAX_RAW_SAMPLES];
extern int s_rawend[MAX_RAW_STREAMS];
extern portable_samplepair_t s_rawsamples[MAX_RAW_SAMPLES];
extern cvar_t *s_volume;
extern cvar_t *s_musicVolume;
extern cvar_t *s_muted;
extern cvar_t *s_doppler;
extern cvar_t *s_volume;
extern cvar_t *s_nosound;
extern cvar_t *s_khz;
extern cvar_t *s_show;
extern cvar_t *s_mixahead;
extern cvar_t *s_testsound;
extern sndparm_t soundparm;
extern cvar_t *s_testsound;
extern cvar_t *s_separation;
qboolean S_LoadSound( sfx_t *sfx );
void SND_free( sndBuffer *v );
sndBuffer* SND_malloc( void );
void SND_setup( void );
void SND_shutdown( void );
void SND_free(sndBuffer *v);
sndBuffer* SND_malloc();
void SND_setup();
void S_PaintChannels( int endtime );
void S_PaintChannels(int endtime);
void S_memoryLoad( sfx_t *sfx );
void S_memoryLoad(sfx_t *sfx);
portable_samplepair_t *S_GetRawSamplePointer();
// spatializes a channel
void S_Spatialize( channel_t *ch );
void S_Spatialize(channel_t *ch);
// adpcm functions
int S_AdpcmMemoryNeeded( const wavinfo_t *info );
void S_AdpcmEncodeSound( sfx_t *sfx, short *samples );
void S_AdpcmGetSamples( sndBuffer *chunk, short *to );
void S_AdpcmGetSamples(sndBuffer *chunk, short *to);
// wavelet function
#define SENTINEL_MULAW_ZERO_RUN 127
#define SENTINEL_MULAW_FOUR_BIT_RUN 126
void S_FreeOldestSound( void );
void S_FreeOldestSound();
#define NXStream byte
void encodeWavelet( sfx_t *sfx, short *packets );
void decodeWavelet( sndBuffer *stream, short *packets );
void encodeWavelet(sfx_t *sfx, short *packets);
void decodeWavelet( sndBuffer *stream, short *packets);
void encodeMuLaw( sfx_t *sfx, short *packets );
extern short mulawToShort[ 256 ];
void encodeMuLaw( sfx_t *sfx, short *packets);
extern short mulawToShort[256];
extern short *sfxScratchBuffer;
extern sfx_t *sfxScratchPointer;
extern int sfxScratchIndex;
qboolean S_Base_Init( soundInterface_t *si );
// OpenAL stuff
typedef enum
{
SRCPRI_AMBIENT = 0, // Ambient sound effects
SRCPRI_ENTITY, // Entity sound effects
SRCPRI_ONESHOT, // One-shot sounds
SRCPRI_LOCAL, // Local sounds
SRCPRI_STREAM // Streams (music, cutscenes)
} alSrcPriority_t;
typedef int srcHandle_t;
void callbackServer( int entnum, int channel_number, const char *name );
qboolean S_AL_Init( soundInterface_t *si );
#ifdef __linux__
// https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=371
// custom Snd_Memset implementation for glibc memset bug workaround
void Snd_Memset(void* dest, const int val, const size_t count);
#else
#define Snd_Memset Com_Memset
#endif
#ifdef __cplusplus
}
+479 -572
View File
File diff suppressed because it is too large. Load diff
+236 -108
View File
@@ -15,22 +15,21 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Quake III Arena source code; if not, write to the Free Software
along with Foobar; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
/*****************************************************************************
* name: snd_mem.c
*
* desc: sound caching
*
* $Archive: /MissionPack/code/client/snd_mem.c $
*
*****************************************************************************/
* name: snd_mem.c
*
* desc: sound caching
*
* $Archive: /MissionPack/code/client/snd_mem.c $
*
*****************************************************************************/
#include "snd_local.h"
#include "snd_codec.h"
#define DEF_COMSOUNDMEGS "8"
@@ -51,61 +50,186 @@ short *sfxScratchBuffer = NULL;
sfx_t *sfxScratchPointer = NULL;
int sfxScratchIndex = 0;
void SND_free( sndBuffer *v ) {
*( sndBuffer ** )v = freelist;
freelist = ( sndBuffer* )v;
inUse += sizeof( sndBuffer );
void SND_free(sndBuffer *v) {
*(sndBuffer **)v = freelist;
freelist = (sndBuffer*)v;
inUse += sizeof(sndBuffer);
}
sndBuffer* SND_malloc( void ) {
sndBuffer* SND_malloc() {
sndBuffer *v;
redo:
if( freelist == NULL ) {
if (freelist == NULL) {
S_FreeOldestSound();
goto redo;
}
inUse -= sizeof( sndBuffer );
totalInUse += sizeof( sndBuffer );
inUse -= sizeof(sndBuffer);
totalInUse += sizeof(sndBuffer);
v = freelist;
freelist = *( sndBuffer ** )freelist;
freelist = *(sndBuffer **)freelist;
v->next = NULL;
return v;
}
void SND_setup( void ) {
void SND_setup() {
sndBuffer *p, *q;
cvar_t *cv;
int scs;
cv = Cvar_Get( "com_soundMegs", DEF_COMSOUNDMEGS, CVAR_LATCH | CVAR_ARCHIVE );
scs = ( cv->integer * 1536 );
scs = (cv->integer*1536);
buffer = malloc( scs*sizeof( sndBuffer ) );
buffer = malloc(scs*sizeof(sndBuffer) );
// allocate the stack based hunk allocator
sfxScratchBuffer = malloc( SND_CHUNK_SIZE * sizeof( short ) * 4 ); //Hunk_Alloc(SND_CHUNK_SIZE * sizeof(short) * 4);
sfxScratchBuffer = malloc(SND_CHUNK_SIZE * sizeof(short) * 4); //Hunk_Alloc(SND_CHUNK_SIZE * sizeof(short) * 4);
sfxScratchPointer = NULL;
inUse = scs*sizeof( sndBuffer );
inUse = scs*sizeof(sndBuffer);
p = buffer;;
q = p + scs;
while( --q > p )
*( sndBuffer ** )q = q - 1;
*( sndBuffer ** )q = NULL;
while (--q > p)
*(sndBuffer **)q = q-1;
*(sndBuffer **)q = NULL;
freelist = p + scs - 1;
Com_Printf( "Sound memory manager started\n" );
Com_Printf("Sound memory manager started\n");
}
void SND_shutdown( void )
/*
===============================================================================
WAV loading
===============================================================================
*/
static byte *data_p;
static byte *iff_end;
static byte *last_chunk;
static byte *iff_data;
static int iff_chunk_len;
static short GetLittleShort(void)
{
free( sfxScratchBuffer );
free( buffer );
short val = 0;
val = *data_p;
val = val + (*(data_p+1)<<8);
data_p += 2;
return val;
}
static int GetLittleLong(void)
{
int val = 0;
val = *data_p;
val = val + (*(data_p+1)<<8);
val = val + (*(data_p+2)<<16);
val = val + (*(data_p+3)<<24);
data_p += 4;
return val;
}
static void FindNextChunk(char *name)
{
while (1)
{
data_p=last_chunk;
if (data_p >= iff_end)
{ // didn't find the chunk
data_p = NULL;
return;
}
data_p += 4;
iff_chunk_len = GetLittleLong();
if (iff_chunk_len < 0)
{
data_p = NULL;
return;
}
data_p -= 8;
last_chunk = data_p + 8 + ( (iff_chunk_len + 1) & ~1 );
if (!strncmp((char *)data_p, name, 4))
return;
}
}
static void FindChunk(char *name)
{
last_chunk = iff_data;
FindNextChunk (name);
}
/*
============
GetWavinfo
============
*/
static wavinfo_t GetWavinfo (char *name, byte *wav, int wavlength)
{
wavinfo_t info;
Com_Memset (&info, 0, sizeof(info));
if (!wav)
return info;
iff_data = wav;
iff_end = wav + wavlength;
// find "RIFF" chunk
FindChunk("RIFF");
if (!(data_p && !strncmp((char *)data_p+8, "WAVE", 4)))
{
Com_Printf("Missing RIFF/WAVE chunks\n");
return info;
}
// get "fmt " chunk
iff_data = data_p + 12;
// DumpChunks ();
FindChunk("fmt ");
if (!data_p)
{
Com_Printf("Missing fmt chunk\n");
return info;
}
data_p += 8;
info.format = GetLittleShort();
info.channels = GetLittleShort();
info.rate = GetLittleLong();
data_p += 4+2;
info.width = GetLittleShort() / 8;
if (info.format != 1)
{
Com_Printf("Microsoft PCM format only\n");
return info;
}
// find data chunk
FindChunk("data");
if (!data_p)
{
Com_Printf("Missing data chunk\n");
return info;
}
data_p += 4;
info.samples = GetLittleLong () / info.width;
info.dataofs = data_p - wav;
return info;
}
/*
================
ResampleSfx
@@ -113,53 +237,47 @@ ResampleSfx
resample / decimate to the current source rate
================
*/
static int ResampleSfx( sfx_t *sfx, int channels, int inrate, int inwidth, int samples, byte *data, qboolean compressed ) {
static void ResampleSfx( sfx_t *sfx, int inrate, int inwidth, byte *data, qboolean compressed ) {
int outcount;
int srcsample;
float stepscale;
int i, j;
int i;
int sample, samplefrac, fracstep;
int part;
sndBuffer *chunk;
stepscale = (float)inrate / dma.speed; // this is usually 0.5, 1, or 2
stepscale = ( float )inrate / dma.speed; // this is usually 0.5, 1, or 2
outcount = samples / stepscale;
outcount = sfx->soundLength / stepscale;
sfx->soundLength = outcount;
samplefrac = 0;
fracstep = stepscale * 256 * channels;
fracstep = stepscale * 256;
chunk = sfx->soundData;
for( i = 0; i<outcount; i++ )
for (i=0 ; i<outcount ; i++)
{
srcsample = samplefrac >> 8;
samplefrac += fracstep;
for( j = 0; j<channels; j++ )
{
if( inwidth == 2 ) {
sample = ( ( ( short * )data )[ srcsample + j ] );
if( inwidth == 2 ) {
sample = LittleShort ( ((short *)data)[srcsample] );
} else {
sample = (int)( (unsigned char)(data[srcsample]) - 128) << 8;
}
part = (i&(SND_CHUNK_SIZE-1));
if (part == 0) {
sndBuffer *newchunk;
newchunk = SND_malloc();
if (chunk == NULL) {
sfx->soundData = newchunk;
} else {
chunk->next = newchunk;
}
else {
sample = ( int )( ( unsigned char )( data[ srcsample + j ] ) - 128 ) << 8;
}
part = ( i*channels + j )&( SND_CHUNK_SIZE - 1 );
if( part == 0 ) {
sndBuffer *newchunk;
newchunk = SND_malloc();
if( chunk == NULL ) {
sfx->soundData = newchunk;
}
else {
chunk->next = newchunk;
}
chunk = newchunk;
}
chunk->sndChunk[ part ] = sample;
chunk = newchunk;
}
}
return outcount;
chunk->sndChunk[part] = sample;
}
}
/*
@@ -169,38 +287,35 @@ ResampleSfx
resample / decimate to the current source rate
================
*/
static int ResampleSfxRaw( short *sfx, int channels, int inrate, int inwidth, int samples, byte *data ) {
static int ResampleSfxRaw( short *sfx, int inrate, int inwidth, int samples, byte *data ) {
int outcount;
int srcsample;
float stepscale;
int i, j;
int i;
int sample, samplefrac, fracstep;
stepscale = ( float )inrate / dma.speed; // this is usually 0.5, 1, or 2
stepscale = (float)inrate / dma.speed; // this is usually 0.5, 1, or 2
outcount = samples / stepscale;
samplefrac = 0;
fracstep = stepscale * 256 * channels;
fracstep = stepscale * 256;
for( i = 0; i<outcount; i++ )
for (i=0 ; i<outcount ; i++)
{
srcsample = samplefrac >> 8;
samplefrac += fracstep;
for( j = 0; j<channels; j++ )
{
if( inwidth == 2 ) {
sample = LittleShort( ( ( short * )data )[ srcsample + j ] );
}
else {
sample = ( int )( ( unsigned char )( data[ srcsample + j ] ) - 128 ) << 8;
}
sfx[ i*channels + j ] = sample;
if( inwidth == 2 ) {
sample = LittleShort ( ((short *)data)[srcsample] );
} else {
sample = (int)( (unsigned char)(data[srcsample]) - 128) << 8;
}
sfx[i] = sample;
}
return outcount;
}
//=============================================================================
/*
@@ -215,25 +330,42 @@ qboolean S_LoadSound( sfx_t *sfx )
{
byte *data;
short *samples;
snd_info_t info;
// int size;
wavinfo_t info;
int size;
// player specific sounds are never directly loaded
if ( sfx->soundName[0] == '*') {
return qfalse;
}
// load it in
data = S_CodecLoad( sfx->soundName, &info );
if( !data )
size = FS_ReadFile( sfx->soundName, (void **)&data );
if ( !data ) {
return qfalse;
if( info.width == 1 ) {
Com_DPrintf( S_COLOR_YELLOW "WARNING: %s is a 8 bit audio file\n", sfx->soundName );
}
if( info.rate != 22050 ) {
Com_DPrintf( S_COLOR_YELLOW "WARNING: %s is not a 22kHz audio file\n", sfx->soundName );
info = GetWavinfo( sfx->soundName, data, size );
if ( info.channels != 1 ) {
Com_Printf ("%s is a stereo wav file\n", sfx->soundName);
FS_FreeFile (data);
return qfalse;
}
samples = Hunk_AllocateTempMemory( info.channels * info.samples * sizeof( short ) * 2 );
if ( info.width == 1 ) {
Com_DPrintf(S_COLOR_YELLOW "WARNING: %s is a 8 bit wav file\n", sfx->soundName);
}
sfx->lastTimeUsed = Com_Milliseconds() + 1;
if ( info.rate != 22050 ) {
Com_DPrintf(S_COLOR_YELLOW "WARNING: %s is not a 22kHz wav file\n", sfx->soundName);
}
if (!info.samples) {
return qfalse;
}
samples = Hunk_AllocateTempMemory(info.samples * sizeof(short) * 2);
sfx->lastTimeUsed = Com_Milliseconds()+1;
// each of these compression schemes works just fine
// but the 16bit quality is much nicer and with a local
@@ -241,40 +373,36 @@ qboolean S_LoadSound( sfx_t *sfx )
// manager to do the right thing for us and page
// sound in as needed
if( info.channels == 1 && sfx->soundCompressed == qtrue ) {
if( sfx->soundCompressed == qtrue) {
sfx->soundCompressionMethod = 1;
sfx->soundData = NULL;
sfx->soundLength = ResampleSfxRaw( samples, info.channels, info.rate, info.width, info.samples, data + info.dataofs );
S_AdpcmEncodeSound( sfx, samples );
sfx->soundLength = ResampleSfxRaw( samples, info.rate, info.width, info.samples, (data + info.dataofs) );
S_AdpcmEncodeSound(sfx, samples);
#if 0
}
else if( info.channels == 1 && info.samples>( SND_CHUNK_SIZE * 16 ) && info.width >1 ) {
} else if (info.samples>(SND_CHUNK_SIZE*16) && info.width >1) {
sfx->soundCompressionMethod = 3;
sfx->soundData = NULL;
sfx->soundLength = ResampleSfxRaw( samples, info.channels, info.rate, info.width, info.samples, ( data + info.dataofs ) );
encodeMuLaw( sfx, samples );
}
else if( info.channels == 1 && info.samples>( SND_CHUNK_SIZE * 6400 ) && info.width >1 ) {
sfx->soundLength = ResampleSfxRaw( samples, info.rate, info.width, info.samples, (data + info.dataofs) );
encodeMuLaw( sfx, samples);
} else if (info.samples>(SND_CHUNK_SIZE*6400) && info.width >1) {
sfx->soundCompressionMethod = 2;
sfx->soundData = NULL;
sfx->soundLength = ResampleSfxRaw( samples, info.channels, info.rate, info.width, info.samples, ( data + info.dataofs ) );
encodeWavelet( sfx, samples );
sfx->soundLength = ResampleSfxRaw( samples, info.rate, info.width, info.samples, (data + info.dataofs) );
encodeWavelet( sfx, samples);
#endif
}
else {
} else {
sfx->soundCompressionMethod = 0;
sfx->soundLength = info.samples;
sfx->soundData = NULL;
sfx->soundLength = ResampleSfx( sfx, info.channels, info.rate, info.width, info.samples, data + info.dataofs, qfalse );
ResampleSfx( sfx, info.rate, info.width, data + info.dataofs, qfalse );
}
sfx->soundChannels = info.channels;
Hunk_FreeTempMemory( samples );
Hunk_FreeTempMemory( data );
Hunk_FreeTempMemory(samples);
FS_FreeFile( data );
return qtrue;
}
void S_DisplayFreeMemory( void ) {
Com_Printf( "%d bytes free sound buffer memory, %d total used\n", inUse, totalInUse );
void S_DisplayFreeMemory() {
Com_Printf("%d bytes free sound buffer memory, %d total used\n", inUse, totalInUse);
}
+292 -410
View File
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
+44 -52
View File
@@ -24,70 +24,53 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
extern "C" {
#endif
typedef struct soundsystemsavegame_s soundsystemsavegame_t;
typedef struct channelbasesavegame_s channelbasesavegame_t;
typedef struct channel_s channel_t;
void S_Init( void );
void S_SaveData( soundsystemsavegame_t *pSave );
void S_LoadData( soundsystemsavegame_t *pSave );
void S_InitBase( channelbasesavegame_t *pBase );
void S_StoreBase( channelbasesavegame_t *pBase, channel_t *channel );
void S_Shutdown( void );
void S_FadeSound( float fTime );
// if origin is NULL, the sound will be dynamically sourced from the entity
void S_StartSound( const vec3_t origin, int entNum, int entChannel, sfxHandle_t sfxHandle, float volume, float minDist, float pitch, float maxDist, qboolean streamed );
void S_StartLocalSound( const char *sound_name, qboolean force_load );
void S_StartSound(const vec3_t origin, int entNum, int entChannel, sfxHandle_t sfxHandle, float volume, float minDist, float pitch, float maxDist, int streamed);
void S_StopSound(int entnum, int channel);
void S_StartLocalSound(sfxHandle_t sfx, int channelNum);
void S_StartLocalSoundByName(const char* sound_name, qboolean force_load);
void S_StartBackgroundTrack( const char *intro, const char *loop );
void S_StopBackgroundTrack( void );
// cinematics and voice-over-network will send raw samples
// 1.0 volume will be direct output of source samples
void S_RawSamples( int stream, int samples, int rate, int width, int channels,
const byte *data, float volume, int entityNum );
void S_StopSound( int entNum, int channel );
void S_RawSamples (int samples, int rate, int width, int channels,
const byte *data, float volume);
// stop all sounds and the background track
void S_StopAllSounds( qboolean stop_music );
void S_StopAllSounds(qboolean stop_music);
// all continuous looping sounds must be added before calling S_Update
void S_ClearLoopingSounds( void );
void S_AddLoopingSound( const vec3_t origin, const vec3_t velocity, sfxHandle_t sfx, float volume, float minDist, float maxDist, float pitch, int flags );
void S_ClearLoopingSoundsNoParam(void);
void S_ClearLoopingSounds( qboolean killall );
void S_AddLoopingSound(const vec3_t origin, const vec3_t velocity, sfxHandle_t sfxHandle, float volume, float minDist, float maxDist, float pitch, int flags);
void S_AddRealLoopingSound( int entityNum, const vec3_t origin, const vec3_t velocity, sfxHandle_t sfx );
void S_StopLoopingSound( int entityNum );
void S_StopLoopingSound(int entityNum );
// recompute the reletive volumes for all running sounds
// reletive to the given entityNum / orientation
void S_Respatialize( int entityNum, const vec3_t origin, vec3_t axis[ 3 ] );
void S_RespatializeEx( int entityNum, const vec3_t origin, vec3_t axis[ 3 ], int inwater );
float S_GetSoundTime( sfxHandle_t handle );
void S_SetGlobalAmbientVolumeLevel( float volume );
void S_SetReverb( int reverb_type, float reverb_level );
int S_IsSoundPlaying( int channelNumber, const char *name );
void S_Respatialize( int entityNum, const vec3_t origin, vec3_t axis[3], int inwater );
// let the sound system know where an entity currently is
void S_UpdateEntity( int entityNum, const vec3_t origin, const vec3_t velocity, qboolean use_listener );
void S_UpdateEntityPosition( int entityNum, const vec3_t origin );
void S_Update( void );
void S_DisableSounds( void );
void S_BeginRegistration( void );
void S_EndRegistration( void );
qboolean S_IsSoundRegistered( const char *name );
void S_EndRegistration(void);
qboolean S_IsSoundRegistered(const char* name);
// RegisterSound will allways return a valid sample, even if it
// has to create a placeholder. This prevents continuous filesystem
// checks for missing files
sfxHandle_t S_RegisterSound( const char *sample, qboolean compressed, qboolean force_load );
sfxHandle_t S_RegisterSound(const char *sample, qboolean compressed, qboolean streamed);
void S_DisplayFreeMemory( void );
void S_DisplayFreeMemory(void);
void S_ClearSoundBuffer( void );
@@ -99,24 +82,33 @@ void S_UpdateBackgroundTrack( void );
void MUSIC_Pause();
void MUSIC_Unpause();
qboolean MUSIC_LoadSoundtrackFile( const char *filename );
qboolean MUSIC_SongValid( const char *mood );
qboolean MUSIC_Loaded( void );
void Music_Update( void );
void MUSIC_SongEnded( void );
void MUSIC_NewSoundtrack( const char *name );
void MUSIC_UpdateMood( int current, int fallback );
void MUSIC_UpdateVolume( float volume, float fade_time );
void MUSIC_StopAllSongs( void );
void MUSIC_FreeAllSongs( void );
qboolean MUSIC_Playing( void );
int MUSIC_FindSong( const char *name );
int MUSIC_CurrentSongChannel( void );
void MUSIC_StopChannel( int channel_number );
qboolean MUSIC_PlaySong( const char *alias );
void MUSIC_UpdateMusicVolumes( void );
void MUSIC_CheckForStoppedSongs( void );
qboolean MUSIC_LoadSoundtrackFile(const char* filename);
qboolean MUSIC_SongValid(const char* mood);
qboolean MUSIC_Loaded(void);
void Music_Update(void);
void MUSIC_SongEnded(void);
void MUSIC_NewSoundtrack(const char* name);
void MUSIC_UpdateMood(int current, int fallback);
void MUSIC_UpdateVolume(float volume, float fade_time);
void MUSIC_StopAllSongs(void);
void MUSIC_FreeAllSongs(void);
qboolean MUSIC_Playing(void);
int MUSIC_FindSong(const char* name);
int MUSIC_CurrentSongChannel(void);
void MUSIC_StopChannel(int channel_number);
qboolean MUSIC_PlaySong(const char* alias);
void MUSIC_UpdateMusicVolumes(void);
void MUSIC_CheckForStoppedSongs(void);
float S_GetSoundTime(sfxHandle_t handle);
void S_SetGlobalAmbientVolumeLevel(float volume);
void S_SetReverb(int reverb_type, float reverb_level);
int S_IsSoundPlaying(int channelNumber, const char* name);
void S_RespatializeOld(int entityNum, const vec3_t origin, vec3_t axis[3]);
void S_UpdateEntity(int entityNum, const vec3_t origin, const vec3_t velocity, qboolean use_listener);
void S_FadeSound(float fTime);
#ifdef __cplusplus
}
#endif
#endif
+105 -108
View File
@@ -15,155 +15,154 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Quake III Arena source code; if not, write to the Free Software
along with Foobar; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
#include "snd_local.h"
long myftol( float f );
#define C0 0.4829629131445341
#define C1 0.8365163037378079
#define C2 0.2241438680420134
#define C3 -0.1294095225512604
void daub4( float b[], unsigned long n, int isign )
void daub4(float b[], unsigned long n, int isign)
{
float wksp[ 4097 ] = { 0.0f };
float *a = b - 1; // numerical recipies so a[1] = b[0]
float wksp[4097];
float *a=b-1; // numerical recipies so a[1] = b[0]
unsigned long nh, nh1, i, j;
unsigned long nh,nh1,i,j;
if( n < 4 ) return;
if (n < 4) return;
nh1 = ( nh = n >> 1 ) + 1;
if( isign >= 0 ) {
for( i = 1, j = 1; j <= n - 3; j += 2, i++ ) {
wksp[ i ] = C0*a[ j ] + C1*a[ j + 1 ] + C2*a[ j + 2 ] + C3*a[ j + 3 ];
wksp[ i + nh ] = C3*a[ j ] - C2*a[ j + 1 ] + C1*a[ j + 2 ] - C0*a[ j + 3 ];
nh1=(nh=n >> 1)+1;
if (isign >= 0) {
for (i=1,j=1;j<=n-3;j+=2,i++) {
wksp[i] = C0*a[j]+C1*a[j+1]+C2*a[j+2]+C3*a[j+3];
wksp[i+nh] = C3*a[j]-C2*a[j+1]+C1*a[j+2]-C0*a[j+3];
}
wksp[ i ] = C0*a[ n - 1 ] + C1*a[ n ] + C2*a[ 1 ] + C3*a[ 2 ];
wksp[ i + nh ] = C3*a[ n - 1 ] - C2*a[ n ] + C1*a[ 1 ] - C0*a[ 2 ];
}
else {
wksp[ 1 ] = C2*a[ nh ] + C1*a[ n ] + C0*a[ 1 ] + C3*a[ nh1 ];
wksp[ 2 ] = C3*a[ nh ] - C0*a[ n ] + C1*a[ 1 ] - C2*a[ nh1 ];
for( i = 1, j = 3; i<nh; i++ ) {
wksp[ j++ ] = C2*a[ i ] + C1*a[ i + nh ] + C0*a[ i + 1 ] + C3*a[ i + nh1 ];
wksp[ j++ ] = C3*a[ i ] - C0*a[ i + nh ] + C1*a[ i + 1 ] - C2*a[ i + nh1 ];
wksp[i ] = C0*a[n-1]+C1*a[n]+C2*a[1]+C3*a[2];
wksp[i+nh] = C3*a[n-1]-C2*a[n]+C1*a[1]-C0*a[2];
} else {
wksp[1] = C2*a[nh]+C1*a[n]+C0*a[1]+C3*a[nh1];
wksp[2] = C3*a[nh]-C0*a[n]+C1*a[1]-C2*a[nh1];
for (i=1,j=3;i<nh;i++) {
wksp[j++] = C2*a[i]+C1*a[i+nh]+C0*a[i+1]+C3*a[i+nh1];
wksp[j++] = C3*a[i]-C0*a[i+nh]+C1*a[i+1]-C2*a[i+nh1];
}
}
for( i = 1; i <= n; i++ ) {
a[ i ] = wksp[ i ];
for (i=1;i<=n;i++) {
a[i]=wksp[i];
}
}
void wt1( float a[], unsigned long n, int isign )
void wt1(float a[], unsigned long n, int isign)
{
unsigned long nn;
int inverseStartLength = n / 4;
if( n < inverseStartLength ) return;
if( isign >= 0 ) {
for( nn = n; nn >= inverseStartLength; nn >>= 1 ) daub4( a, nn, isign );
}
else {
for( nn = inverseStartLength; nn <= n; nn <<= 1 ) daub4( a, nn, isign );
int inverseStartLength = n/4;
if (n < inverseStartLength) return;
if (isign >= 0) {
for (nn=n;nn>=inverseStartLength;nn>>=1) daub4(a,nn,isign);
} else {
for (nn=inverseStartLength;nn<=n;nn<<=1) daub4(a,nn,isign);
}
}
/* The number of bits required by each value */
static unsigned char numBits[] = {
0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
0,1,2,2,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
};
byte MuLawEncode( short s ) {
byte MuLawEncode(short s) {
unsigned long adjusted;
byte sign, exponent, mantissa;
sign = ( s<0 ) ? 0 : 0x80;
sign = (s<0)?0:0x80;
if( s<0 ) s = -s;
adjusted = ( long )s << ( 16 - sizeof( short ) * 8 );
if (s<0) s=-s;
adjusted = (long)s << (16-sizeof(short)*8);
adjusted += 128L + 4L;
if( adjusted > 32767 ) adjusted = 32767;
exponent = numBits[ ( adjusted >> 7 ) & 0xff ] - 1;
mantissa = ( adjusted >> ( exponent + 3 ) ) & 0xf;
return ~( sign | ( exponent << 4 ) | mantissa );
if (adjusted > 32767) adjusted = 32767;
exponent = numBits[(adjusted>>7)&0xff] - 1;
mantissa = (adjusted>>(exponent+3))&0xf;
return ~(sign | (exponent<<4) | mantissa);
}
short MuLawDecode( byte uLaw ) {
short MuLawDecode(byte uLaw) {
signed long adjusted;
byte exponent, mantissa;
uLaw = ~uLaw;
exponent = ( uLaw >> 4 ) & 0x7;
mantissa = ( uLaw & 0xf ) + 16;
adjusted = ( mantissa << ( exponent + 3 ) ) - 128 - 4;
exponent = (uLaw>>4) & 0x7;
mantissa = (uLaw&0xf) + 16;
adjusted = (mantissa << (exponent +3)) - 128 - 4;
return ( uLaw & 0x80 ) ? adjusted : -adjusted;
return (uLaw & 0x80)? adjusted : -adjusted;
}
short mulawToShort[ 256 ];
short mulawToShort[256];
static qboolean madeTable = qfalse;
static int NXStreamCount;
void NXPutc( NXStream *stream, char out ) {
stream[ NXStreamCount++ ] = out;
void NXPutc(NXStream *stream, char out) {
stream[NXStreamCount++] = out;
}
void encodeWavelet( sfx_t *sfx, short *packets ) {
float wksp[ 4097 ] = { 0 }, temp;
void encodeWavelet( sfx_t *sfx, short *packets) {
float wksp[4097], temp;
int i, samples, size;
sndBuffer *newchunk, *chunk;
byte *out;
if( !madeTable ) {
for( i = 0; i<256; i++ ) {
mulawToShort[ i ] = ( float )MuLawDecode( ( byte )i );
if (!madeTable) {
for (i=0;i<256;i++) {
mulawToShort[i] = (float)MuLawDecode((byte)i);
}
madeTable = qtrue;
}
chunk = NULL;
samples = sfx->soundLength;
while( samples>0 ) {
while(samples>0) {
size = samples;
if( size>( SND_CHUNK_SIZE * 2 ) ) {
size = ( SND_CHUNK_SIZE * 2 );
if (size>(SND_CHUNK_SIZE*2)) {
size = (SND_CHUNK_SIZE*2);
}
if( size<4 ) {
if (size<4) {
size = 4;
}
newchunk = SND_malloc();
if( sfx->soundData == NULL ) {
if (sfx->soundData == NULL) {
sfx->soundData = newchunk;
}
else if( chunk != NULL ) {
} else {
chunk->next = newchunk;
}
chunk = newchunk;
for( i = 0; i<size; i++ ) {
wksp[ i ] = *packets;
for(i=0; i<size; i++) {
wksp[i] = *packets;
packets++;
}
wt1( wksp, size, 1 );
out = ( byte * )chunk->sndChunk;
wt1(wksp, size, 1);
out = (byte *)chunk->sndChunk;
for( i = 0; i<size; i++ ) {
temp = wksp[ i ];
if( temp > 32767 ) temp = 32767; else if( temp<-32768 ) temp = -32768;
out[ i ] = MuLawEncode( ( short )temp );
for(i=0;i<size;i++) {
temp = wksp[i];
if (temp > 32767) temp = 32767; else if (temp<-32768) temp = -32768;
out[i] = MuLawEncode((short)temp);
}
chunk->size = size;
@@ -171,36 +170,36 @@ void encodeWavelet( sfx_t *sfx, short *packets ) {
}
}
void decodeWavelet( sndBuffer *chunk, short *to ) {
float wksp[ 4097 ] = { 0 };
void decodeWavelet(sndBuffer *chunk, short *to) {
float wksp[4097];
int i;
byte *out;
int size = chunk->size;
out = ( byte * )chunk->sndChunk;
for( i = 0; i<size; i++ ) {
wksp[ i ] = mulawToShort[ out[ i ] ];
out = (byte *)chunk->sndChunk;
for(i=0;i<size;i++) {
wksp[i] = mulawToShort[out[i]];
}
wt1( wksp, size, -1 );
wt1(wksp, size, -1);
if (!to) return;
if( !to ) return;
for( i = 0; i<size; i++ ) {
to[ i ] = wksp[ i ];
for(i=0; i<size; i++) {
to[i] = wksp[i];
}
}
void encodeMuLaw( sfx_t *sfx, short *packets ) {
void encodeMuLaw( sfx_t *sfx, short *packets) {
int i, samples, size, grade, poop;
sndBuffer *newchunk, *chunk;
byte *out;
if( !madeTable ) {
for( i = 0; i<256; i++ ) {
mulawToShort[ i ] = ( float )MuLawDecode( ( byte )i );
if (!madeTable) {
for (i=0;i<256;i++) {
mulawToShort[i] = (float)MuLawDecode((byte)i);
}
madeTable = qtrue;
}
@@ -209,31 +208,29 @@ void encodeMuLaw( sfx_t *sfx, short *packets ) {
samples = sfx->soundLength;
grade = 0;
while( samples>0 ) {
while(samples>0) {
size = samples;
if( size>( SND_CHUNK_SIZE * 2 ) ) {
size = ( SND_CHUNK_SIZE * 2 );
if (size>(SND_CHUNK_SIZE*2)) {
size = (SND_CHUNK_SIZE*2);
}
newchunk = SND_malloc();
if( sfx->soundData == NULL ) {
if (sfx->soundData == NULL) {
sfx->soundData = newchunk;
}
else if( chunk != NULL ) {
} else {
chunk->next = newchunk;
}
chunk = newchunk;
out = ( byte * )chunk->sndChunk;
for( i = 0; i<size; i++ ) {
poop = packets[ 0 ] + grade;
if( poop>32767 ) {
out = (byte *)chunk->sndChunk;
for(i=0; i<size; i++) {
poop = packets[0]+grade;
if (poop>32767) {
poop = 32767;
}
else if( poop<-32768 ) {
} else if (poop<-32768) {
poop = -32768;
}
out[ i ] = MuLawEncode( ( short )poop );
grade = poop - mulawToShort[ out[ i ] ];
out[i] = MuLawEncode((short)poop);
grade = poop - mulawToShort[out[i]];
packets++;
}
chunk->size = size;
@@ -241,15 +238,15 @@ void encodeMuLaw( sfx_t *sfx, short *packets ) {
}
}
void decodeMuLaw( sndBuffer *chunk, short *to ) {
void decodeMuLaw(sndBuffer *chunk, short *to) {
int i;
byte *out;
int size = chunk->size;
out = ( byte * )chunk->sndChunk;
for( i = 0; i<size; i++ ) {
to[ i ] = mulawToShort[ out[ i ] ];
out = (byte *)chunk->sndChunk;
for(i=0;i<size;i++) {
to[i] = mulawToShort[out[i]];
}
}
+13 -3
View File
@@ -22,6 +22,16 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#include "ui_local.h"
UConnection::UConnection()
{
}
UConnection::UConnection(const Event& inevent, const Event& outevent)
: m_inevent(inevent)
, m_outevent(outevent)
{
}
bool UConnection::TypeIs
(
Event& ev
@@ -47,12 +57,12 @@ bool UConnection::AddListener
ptr = object;
// don't add the same listener
if( m_listeners.ObjectInList( ptr ) )
if (m_listeners.ObjectInList(ptr))
{
return false;
}
m_listeners.AddUniqueObject( ptr );
m_listeners.AddObject( ptr );
e = new Event( ev );
m_events.AddObject( e );
@@ -183,7 +193,7 @@ bool USignal::Connect
}
}
c = new UConnection;
c = new UConnection(inevent, outevent);
m_connections.AddObject( c );
return c->AddListener( object, outevent );
+1
View File
@@ -22,6 +22,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
// VehicleCollisionEntity.cpp : MOHAA Vehicle Collision
#include "VehicleCollisionEntity.h"
#include "g_phys.h"
CLASS_DECLARATION( Entity, VehicleCollisionEntity, NULL )
{
Loaded 100 of 1209 files, more files were not shown because too many files have changed in this diff. Show more