2 Copyright (C) 1996-1997 Id Software, Inc.
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 See the GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 // cl_main.c -- client main loop
24 // we need to declare some mouse variables here, because the menu system
25 // references them even when on a unix system.
27 // these two are not intended to be set directly
28 cvar_t cl_name
= {"_cl_name", "player", true};
29 cvar_t cl_color
= {"_cl_color", "13", true};
31 cvar_t cl_shownet
= {"cl_shownet","0"}; // can be 0, 1, or 2
32 cvar_t cl_nolerp
= {"cl_nolerp","0"};
34 cvar_t cl_autoaim
= {"cl_autoaim", "1", true};
36 cvar_t lookspring
= {"lookspring","0", true};
37 cvar_t lookstrafe
= {"lookstrafe","0", true};
38 cvar_t lookcenter
= {"lookcenter","1", true};
39 cvar_t in_sensitivity
= {"sensitivity","3", true};
40 cvar_t in_tolerance
= {"tolerance","0.25", true};
41 cvar_t in_acceleration
= {"acceleration","1.0", true};
43 cvar_t m_pitch
= {"m_pitch","0.022", true};
44 cvar_t m_yaw
= {"m_yaw","0.022", true};
45 cvar_t m_forward
= {"m_forward","1", true};
46 cvar_t m_side
= {"m_side","0.8", true};
48 cvar_t in_freelook_analog
= {"in_freelook_analog", "0", true};
49 cvar_t in_disable_analog
= {"in_disable_analog", "0", true};
50 cvar_t in_analog_strafe
= {"in_analog_strafe", "0", true};
52 cvar_t in_x_axis_adjust
= {"in_x_axis_adjust", "0", true};
53 cvar_t in_y_axis_adjust
= {"in_y_axis_adjust", "0", true};
57 // FIXME: put these on hunk?
58 efrag_t cl_efrags
[MAX_EFRAGS
];
59 entity_t cl_entities
[MAX_EDICTS
];
60 entity_t cl_static_entities
[MAX_STATIC_ENTITIES
];
61 lightstyle_t cl_lightstyle
[MAX_LIGHTSTYLES
];
62 dlight_t cl_dlights
[MAX_DLIGHTS
];
65 entity_t
*cl_visedicts
[MAX_VISEDICTS
];
67 modelindex_t cl_modelindex
[NUM_MODELINDEX
];
68 char *cl_modelnames
[NUM_MODELINDEX
];
76 void CL_ClearState (void)
83 // wipe the entire cl structure
84 memset (&cl
, 0, sizeof(cl
));
86 SZ_Clear (&cls
.message
);
89 memset (cl_efrags
, 0, sizeof(cl_efrags
));
90 memset (cl_entities
, 0, sizeof(cl_entities
));
91 memset (cl_dlights
, 0, sizeof(cl_dlights
));
92 memset (cl_lightstyle
, 0, sizeof(cl_lightstyle
));
93 memset (cl_temp_entities
, 0, sizeof(cl_temp_entities
));
94 memset (cl_beams
, 0, sizeof(cl_beams
));
97 // allocate the efrags and chain together into a free list
99 cl
.free_efrags
= cl_efrags
;
100 for (i
=0 ; i
<MAX_EFRAGS
-1 ; i
++)
101 cl
.free_efrags
[i
].entnext
= &cl
.free_efrags
[i
+1];
102 cl
.free_efrags
[i
].entnext
= NULL
;
106 =====================
109 Sends a disconnect message to the server
110 This is also called on Host_Error, so it shouldn't cause any errors
111 =====================
113 void CL_Disconnect (void)
115 // stop sounds (especially looping!)
116 S_StopAllSounds (true);
118 // bring the console down and fade the colors back to normal
119 // SCR_BringDownConsole ();
121 // if running a local server, shut it down
122 if (cls
.demoplayback
)
124 else if (cls
.state
== ca_connected
)
126 if (cls
.demorecording
)
129 Con_DPrintf ("Sending clc_disconnect\n");
130 SZ_Clear (&cls
.message
);
131 MSG_WriteByte (&cls
.message
, clc_disconnect
);
132 NET_SendUnreliableMessage (cls
.netcon
, &cls
.message
);
133 SZ_Clear (&cls
.message
);
134 NET_Close (cls
.netcon
);
136 cls
.state
= ca_disconnected
;
138 Host_ShutdownServer(false);
141 cls
.demoplayback
= cls
.timedemo
= false;
145 void CL_Disconnect_f (void)
149 Host_ShutdownServer (false);
156 =====================
157 CL_EstablishConnection
159 Host should be either "local" or a net address to be passed on
160 =====================
162 void CL_EstablishConnection (char *host
)
164 if (cls
.state
== ca_dedicated
)
167 if (cls
.demoplayback
)
172 cls
.netcon
= NET_Connect (host
);
174 Host_Error ("CL_Connect: connect failed\n");
175 Con_DPrintf ("CL_EstablishConnection: connected to %s\n", host
);
177 cls
.demonum
= -1; // not in the demo loop now
178 cls
.state
= ca_connected
;
179 cls
.signon
= 0; // need all the signon messages before playing
183 =====================
186 An svc_signonnum has been received, perform a client side setup
187 =====================
189 void CL_SignonReply (void)
193 Con_DPrintf ("CL_SignonReply: %i\n", cls
.signon
);
198 MSG_WriteByte (&cls
.message
, clc_stringcmd
);
199 MSG_WriteString (&cls
.message
, "prespawn");
203 MSG_WriteByte (&cls
.message
, clc_stringcmd
);
204 MSG_WriteString (&cls
.message
, va("name \"%s\"\n", cl_name
.string
));
206 MSG_WriteByte (&cls
.message
, clc_stringcmd
);
207 MSG_WriteString (&cls
.message
, va("color %i %i\n", ((int)cl_color
.value
)>>4, ((int)cl_color
.value
)&15));
209 MSG_WriteByte (&cls
.message
, clc_stringcmd
);
210 sprintf (str
, "spawn %s", cls
.spawnparms
);
211 MSG_WriteString (&cls
.message
, str
);
215 MSG_WriteByte (&cls
.message
, clc_stringcmd
);
216 MSG_WriteString (&cls
.message
, "begin");
217 Cache_Report (); // print remaining memory
221 SCR_EndLoadingPlaque (); // allow normal screen updates
227 =====================
230 Called to play the next demo in the demo loop
231 =====================
233 void CL_NextDemo (void)
237 if (cls
.demonum
== -1)
238 return; // don't play demos
240 SCR_BeginLoadingPlaque ();
242 if (!cls
.demos
[cls
.demonum
][0] || cls
.demonum
== MAX_DEMOS
)
245 if (!cls
.demos
[cls
.demonum
][0])
247 Con_Printf ("No demos listed with startdemos\n");
253 sprintf (str
,"playdemo %s\n", cls
.demos
[cls
.demonum
]);
254 Cbuf_InsertText (str
);
263 void CL_PrintEntities_f (void)
268 for (i
=0,ent
=cl_entities
; i
<cl
.num_entities
; i
++,ent
++)
270 Con_Printf ("%3i:",i
);
273 Con_Printf ("EMPTY\n");
276 Con_Printf ("%s:%2i (%5.1f,%5.1f,%5.1f) [%5.1f %5.1f %5.1f]\n"
277 ,ent
->model
->name
,ent
->frame
, ent
->origin
[0], ent
->origin
[1], ent
->origin
[2], ent
->angles
[0], ent
->angles
[1], ent
->angles
[2]);
286 Debugging tool, just flashes the screen
301 VID_SetPalette (host_basepal
);
304 for (c
=0 ; c
<768 ; c
+=3)
310 VID_SetPalette (pal
);
314 for (c
=0 ; c
<768 ; c
+=3)
320 VID_SetPalette (pal
);
331 dlight_t
*CL_AllocDlight (int key
)
336 // first look for an exact key match
340 for (i
=0 ; i
<MAX_DLIGHTS
; i
++, dl
++)
344 memset (dl
, 0, sizeof(*dl
));
346 dl
->color
[0] = dl
->color
[1] = dl
->color
[2] = 1; // LordHavoc: .lit support
352 // then look for anything else
354 for (i
=0 ; i
<MAX_DLIGHTS
; i
++, dl
++)
356 if (dl
->die
< cl
.time
)
358 memset (dl
, 0, sizeof(*dl
));
360 dl
->color
[0] = dl
->color
[1] = dl
->color
[2] = 1; // LordHavoc: .lit support
366 memset (dl
, 0, sizeof(*dl
));
368 dl
->color
[0] = dl
->color
[1] = dl
->color
[2] = 1; // LordHavoc: .lit support
379 void CL_DecayLights (void)
385 time
= cl
.time
- cl
.oldtime
;
388 for (i
=0 ; i
<MAX_DLIGHTS
; i
++, dl
++)
390 if (dl
->die
< cl
.time
|| !dl
->radius
)
393 dl
->radius
-= time
*dl
->decay
;
404 Determines the fraction between the last two messages that the objects
408 float CL_LerpPoint (void)
412 f
= cl
.mtime
[0] - cl
.mtime
[1];
414 if (!f
|| cl_nolerp
.value
|| cls
.timedemo
|| sv
.active
)
416 cl
.time
= cl
.mtime
[0];
421 { // dropped packet, or start of demo
422 cl
.mtime
[1] = cl
.mtime
[0] - 0.1;
425 frac
= (cl
.time
- cl
.mtime
[1]) / f
;
426 // Con_Printf ("frac: %f\n",frac);
432 cl
.time
= cl
.mtime
[1];
433 // Con_Printf ("low frac\n");
442 cl
.time
= cl
.mtime
[0];
443 // Con_Printf ("high frac\n");
459 void CL_RelinkEntities (void)
469 // determine partial update time
470 frac
= CL_LerpPoint ();
475 // interpolate player info
477 for (i
=0 ; i
<3 ; i
++)
478 cl
.velocity
[i
] = cl
.mvelocity
[1][i
] +
479 frac
* (cl
.mvelocity
[0][i
] - cl
.mvelocity
[1][i
]);
481 if (cls
.demoplayback
)
483 // interpolate the angles
484 for (j
=0 ; j
<3 ; j
++)
486 d
= cl
.mviewangles
[0][j
] - cl
.mviewangles
[1][j
];
491 cl
.viewangles
[j
] = cl
.mviewangles
[1][j
] + frac
*d
;
495 bobjrotate
= anglemod(100*cl
.time
);
497 // start on the entity after the world
498 for (i
=1,ent
=cl_entities
+1 ; i
<cl
.num_entities
; i
++,ent
++)
503 R_RemoveEfrags (ent
); // just became empty
507 // if the object wasn't included in the last packet, remove it
508 if (ent
->msgtime
!= cl
.mtime
[0])
512 // fenix@io.com: model transform interpolation
513 ent
->frame_start_time
= 0;
514 ent
->translate_start_time
= 0;
515 ent
->rotate_start_time
= 0;
520 VectorCopy (ent
->origin
, oldorg
);
523 { // the entity was not updated in the last message
524 // so move to the final spot
525 VectorCopy (ent
->msg_origins
[0], ent
->origin
);
526 VectorCopy (ent
->msg_angles
[0], ent
->angles
);
529 { // if the delta is large, assume a teleport and don't lerp
531 for (j
=0 ; j
<3 ; j
++)
533 delta
[j
] = ent
->msg_origins
[0][j
] - ent
->msg_origins
[1][j
];
534 if (delta
[j
] > 100 || delta
[j
] < -100)
535 f
= 1; // assume a teleportation, not a motion
537 // fenix@io.com: model transform interpolation
538 // interpolation should be reset in the event of a large delta
542 // ent->frame_start_time = 0;
543 ent
->translate_start_time
= 0;
544 ent
->rotate_start_time
= 0;
547 // interpolate the origin and angles
548 for (j
=0 ; j
<3 ; j
++)
550 ent
->origin
[j
] = ent
->msg_origins
[1][j
] + f
*delta
[j
];
552 d
= ent
->msg_angles
[0][j
] - ent
->msg_angles
[1][j
];
557 ent
->angles
[j
] = ent
->msg_angles
[1][j
] + f
*d
;
562 // rotate binary objects locally
563 if (ent
->model
->flags
& EF_ROTATE
)
564 ent
->angles
[1] = bobjrotate
;
566 if (ent
->effects
& EF_BRIGHTFIELD
)
567 R_EntityParticles (ent
);
569 if (ent
->effects
& EF_DARKFIELD
)
570 R_DarkFieldParticles (ent
);
572 if (ent
->effects
& EF_MUZZLEFLASH
)
576 dl
= CL_AllocDlight (i
);
577 VectorCopy (ent
->origin
, dl
->origin
);
579 AngleVectors (ent
->angles
, fv
, rv
, uv
);
581 VectorMA (dl
->origin
, 18, fv
, dl
->origin
);
582 dl
->radius
= 200 + (rand()&31);
584 dl
->die
= cl
.time
+ 0.1;
590 if (ent
->effects
& EF_BRIGHTLIGHT
)
592 dl
= CL_AllocDlight (i
);
593 VectorCopy (ent
->origin
, dl
->origin
);
595 dl
->radius
= 400 + (rand()&31);
596 dl
->die
= cl
.time
+ 0.001;
601 if (ent
->effects
& EF_DIMLIGHT
)
603 dl
= CL_AllocDlight (i
);
604 VectorCopy (ent
->origin
, dl
->origin
);
605 dl
->radius
= 200 + (rand()&31);
606 dl
->die
= cl
.time
+ 0.001;
607 dl
->radius
= 100 + (rand()&31);
614 if (ent
->effects
& EF_REDLIGHT
)
616 dl
= CL_AllocDlight (i
);
617 VectorCopy (ent
->origin
, dl
->origin
);
618 dl
->radius
= 200 + (rand()&31);
619 dl
->die
= cl
.time
+ 0.001;
620 dl
->radius
= 150 + (rand()&31);
625 if (ent
->effects
& EF_BLUELIGHT
)
627 dl
= CL_AllocDlight (i
);
628 VectorCopy (ent
->origin
, dl
->origin
);
629 dl
->radius
= 200 + (rand()&31);
630 dl
->die
= cl
.time
+ 0.001;
631 dl
->radius
= 150 + (rand()&31);
638 if (ent
->effects
& EF_DARKLIGHT
)
640 dl
= CL_AllocDlight (i
);
641 VectorCopy (ent
->origin
, dl
->origin
);
642 dl
->radius
= 200.0 + (rand()&31);
643 dl
->die
= cl
.time
+ 0.001;
646 if (ent
->effects
& EF_LIGHT
)
648 dl
= CL_AllocDlight (i
);
649 VectorCopy (ent
->origin
, dl
->origin
);
651 dl
->die
= cl
.time
+ 0.001;
655 if (ent
->model
->flags
& EF_GIB
)
656 R_RocketTrail (oldorg
, ent
->origin
, 2);
657 else if (ent
->model
->flags
& EF_ZOMGIB
)
658 R_RocketTrail (oldorg
, ent
->origin
, 4);
659 else if (ent
->model
->flags
& EF_TRACER
)
660 R_RocketTrail (oldorg
, ent
->origin
, 3);
661 else if (ent
->model
->flags
& EF_TRACER2
)
662 R_RocketTrail (oldorg
, ent
->origin
, 5);
663 else if (ent
->model
->flags
& EF_ROCKET
)
665 R_RocketTrail (oldorg
, ent
->origin
, 0);
666 dl
= CL_AllocDlight (i
);
667 VectorCopy (ent
->origin
, dl
->origin
);
669 dl
->die
= cl
.time
+ 0.01;
671 else if (ent
->model
->flags
& EF_GRENADE
)
672 R_RocketTrail (oldorg
, ent
->origin
, 1);
673 else if (ent
->model
->flags
& EF_TRACER3
)
674 R_RocketTrail (oldorg
, ent
->origin
, 6);
676 // Tomaz - QC Glow Begin
678 else if (ent
->glow_size
)
680 dl
= CL_AllocDlight (i
);
681 VectorCopy (ent
->origin
, dl
->origin
);
682 dl
->radius
= ent
->glow_size
;
683 dl
->die
= cl
.time
+ 0.001;
684 dl
->color
[0] = ent
->glow_red
;
685 dl
->color
[1] = ent
->glow_green
;
686 dl
->color
[2] = ent
->glow_blue
;
689 // Tomaz - QC Glow End
691 ent
->forcelink
= false;
693 if (i
== cl
.viewentity
&& !chase_active
.value
)
697 if ( ent
->effects
& EF_NODRAW
)
700 if (cl_numvisedicts
< MAX_VISEDICTS
)
702 cl_visedicts
[cl_numvisedicts
] = ent
;
714 Read all incoming data from the server
717 int CL_ReadFromServer (void)
721 cl
.oldtime
= cl
.time
;
722 cl
.time
+= host_frametime
;
726 ret
= CL_GetMessage ();
728 Host_Error ("CL_ReadFromServer: lost server connection");
732 cl
.last_received_message
= realtime
;
733 CL_ParseServerMessage ();
734 } while (ret
&& cls
.state
== ca_connected
);
736 if (cl_shownet
.value
)
739 CL_RelinkEntities ();
743 // bring the links up to date
753 void CL_SendCmd (void)
757 if (cls
.state
!= ca_connected
)
760 if (cls
.signon
== SIGNONS
)
762 // get basic movement from keyboard
765 // allow mice or other external controllers to add to the move
766 if (!in_disable_analog
.value
)
769 // send the unreliable message
774 if (cls
.demoplayback
)
776 SZ_Clear (&cls
.message
);
780 // send the reliable message
781 if (!cls
.message
.cursize
)
782 return; // no message at all
784 if (!NET_CanSendMessage (cls
.netcon
))
786 Con_DPrintf ("CL_WriteToServer: can't send\n");
790 if (NET_SendMessage (cls
.netcon
, &cls
.message
) == -1)
791 Host_Error ("CL_WriteToServer: lost server connection");
793 SZ_Clear (&cls
.message
);
803 SZ_Alloc (&cls
.message
, 1024);
809 // register our commands
811 Cvar_RegisterVariable (&cl_name
);
812 Cvar_RegisterVariable (&cl_color
);
813 Cvar_RegisterVariable (&cl_upspeed
);
814 Cvar_RegisterVariable (&cl_forwardspeed
);
815 Cvar_RegisterVariable (&cl_backspeed
);
816 Cvar_RegisterVariable (&cl_sidespeed
);
817 Cvar_RegisterVariable (&cl_movespeedkey
);
818 Cvar_RegisterVariable (&cl_yawspeed
);
819 Cvar_RegisterVariable (&cl_pitchspeed
);
820 Cvar_RegisterVariable (&cl_anglespeedkey
);
821 Cvar_RegisterVariable (&cl_shownet
);
822 Cvar_RegisterVariable (&cl_nolerp
);
823 Cvar_RegisterVariable (&cl_autoaim
);
824 Cvar_RegisterVariable (&lookspring
);
825 Cvar_RegisterVariable (&lookstrafe
);
826 Cvar_RegisterVariable (&lookcenter
);
828 Cvar_RegisterVariable (&in_sensitivity
);
829 Cvar_RegisterVariable (&in_tolerance
);
830 Cvar_RegisterVariable (&in_acceleration
);
831 Cvar_RegisterVariable (&in_freelook_analog
);
832 Cvar_RegisterVariable (&in_disable_analog
);
833 Cvar_RegisterVariable (&in_analog_strafe
);
835 Cvar_RegisterVariable (&in_x_axis_adjust
);
836 Cvar_RegisterVariable (&in_y_axis_adjust
);
838 Cvar_RegisterVariable (&m_pitch
);
839 Cvar_RegisterVariable (&m_yaw
);
840 Cvar_RegisterVariable (&m_forward
);
841 Cvar_RegisterVariable (&m_side
);
843 // Cvar_RegisterVariable (&cl_autofire);
845 Cmd_AddCommand ("entities", CL_PrintEntities_f
);
846 Cmd_AddCommand ("disconnect", CL_Disconnect_f
);
847 Cmd_AddCommand ("record", CL_Record_f
);
848 Cmd_AddCommand ("stop", CL_Stop_f
);
849 Cmd_AddCommand ("playdemo", CL_PlayDemo_f
);
850 Cmd_AddCommand ("timedemo", CL_TimeDemo_f
);