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", "0", 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 lookspring
= {"lookspring","0", true};
35 cvar_t lookstrafe
= {"lookstrafe","0", true};
36 cvar_t sensitivity
= {"sensitivity","3", true};
38 cvar_t m_pitch
= {"m_pitch","0.022", true};
39 cvar_t m_yaw
= {"m_yaw","0.022", true};
40 cvar_t m_forward
= {"m_forward","1", true};
41 cvar_t m_side
= {"m_side","0.8", true};
46 // FIXME: put these on hunk?
47 efrag_t cl_efrags
[MAX_EFRAGS
];
48 entity_t cl_entities
[MAX_EDICTS
];
49 entity_t cl_static_entities
[MAX_STATIC_ENTITIES
];
50 lightstyle_t cl_lightstyle
[MAX_LIGHTSTYLES
];
51 dlight_t cl_dlights
[MAX_DLIGHTS
];
54 entity_t
*cl_visedicts
[MAX_VISEDICTS
];
62 void CL_ClearState (void)
69 // wipe the entire cl structure
70 memset (&cl
, 0, sizeof(cl
));
72 SZ_Clear (&cls
.message
);
75 memset (cl_efrags
, 0, sizeof(cl_efrags
));
76 memset (cl_entities
, 0, sizeof(cl_entities
));
77 memset (cl_dlights
, 0, sizeof(cl_dlights
));
78 memset (cl_lightstyle
, 0, sizeof(cl_lightstyle
));
79 memset (cl_temp_entities
, 0, sizeof(cl_temp_entities
));
80 memset (cl_beams
, 0, sizeof(cl_beams
));
83 // allocate the efrags and chain together into a free list
85 cl
.free_efrags
= cl_efrags
;
86 for (i
=0 ; i
<MAX_EFRAGS
-1 ; i
++)
87 cl
.free_efrags
[i
].entnext
= &cl
.free_efrags
[i
+1];
88 cl
.free_efrags
[i
].entnext
= NULL
;
95 Sends a disconnect message to the server
96 This is also called on Host_Error, so it shouldn't cause any errors
99 void CL_Disconnect (void)
101 // stop sounds (especially looping!)
102 S_StopAllSounds (true);
104 // bring the console down and fade the colors back to normal
105 // SCR_BringDownConsole ();
107 // if running a local server, shut it down
108 if (cls
.demoplayback
)
110 else if (cls
.state
== ca_connected
)
112 if (cls
.demorecording
)
115 Con_DPrintf ("Sending clc_disconnect\n");
116 SZ_Clear (&cls
.message
);
117 MSG_WriteByte (&cls
.message
, clc_disconnect
);
118 NET_SendUnreliableMessage (cls
.netcon
, &cls
.message
);
119 SZ_Clear (&cls
.message
);
120 NET_Close (cls
.netcon
);
122 cls
.state
= ca_disconnected
;
124 Host_ShutdownServer(false);
127 cls
.demoplayback
= cls
.timedemo
= false;
131 void CL_Disconnect_f (void)
135 Host_ShutdownServer (false);
142 =====================
143 CL_EstablishConnection
145 Host should be either "local" or a net address to be passed on
146 =====================
148 void CL_EstablishConnection (char *host
)
150 if (cls
.state
== ca_dedicated
)
153 if (cls
.demoplayback
)
158 cls
.netcon
= NET_Connect (host
);
160 Host_Error ("CL_Connect: connect failed\n");
161 Con_DPrintf ("CL_EstablishConnection: connected to %s\n", host
);
163 cls
.demonum
= -1; // not in the demo loop now
164 cls
.state
= ca_connected
;
165 cls
.signon
= 0; // need all the signon messages before playing
169 =====================
172 An svc_signonnum has been received, perform a client side setup
173 =====================
175 void CL_SignonReply (void)
179 Con_DPrintf ("CL_SignonReply: %i\n", cls
.signon
);
184 MSG_WriteByte (&cls
.message
, clc_stringcmd
);
185 MSG_WriteString (&cls
.message
, "prespawn");
189 MSG_WriteByte (&cls
.message
, clc_stringcmd
);
190 MSG_WriteString (&cls
.message
, va("name \"%s\"\n", cl_name
.string
));
192 MSG_WriteByte (&cls
.message
, clc_stringcmd
);
193 MSG_WriteString (&cls
.message
, va("color %i %i\n", ((int)cl_color
.value
)>>4, ((int)cl_color
.value
)&15));
195 MSG_WriteByte (&cls
.message
, clc_stringcmd
);
196 sprintf (str
, "spawn %s", cls
.spawnparms
);
197 MSG_WriteString (&cls
.message
, str
);
201 MSG_WriteByte (&cls
.message
, clc_stringcmd
);
202 MSG_WriteString (&cls
.message
, "begin");
203 Cache_Report (); // print remaining memory
207 SCR_EndLoadingPlaque (); // allow normal screen updates
213 =====================
216 Called to play the next demo in the demo loop
217 =====================
219 void CL_NextDemo (void)
223 if (cls
.demonum
== -1)
224 return; // don't play demos
226 SCR_BeginLoadingPlaque ();
228 if (!cls
.demos
[cls
.demonum
][0] || cls
.demonum
== MAX_DEMOS
)
231 if (!cls
.demos
[cls
.demonum
][0])
233 Con_Printf ("No demos listed with startdemos\n");
239 sprintf (str
,"playdemo %s\n", cls
.demos
[cls
.demonum
]);
240 Cbuf_InsertText (str
);
249 void CL_PrintEntities_f (void)
254 for (i
=0,ent
=cl_entities
; i
<cl
.num_entities
; i
++,ent
++)
256 Con_Printf ("%3i:",i
);
259 Con_Printf ("EMPTY\n");
262 Con_Printf ("%s:%2i (%5.1f,%5.1f,%5.1f) [%5.1f %5.1f %5.1f]\n"
263 ,ent
->model
->name
,ent
->frame
, ent
->origin
[0], ent
->origin
[1], ent
->origin
[2], ent
->angles
[0], ent
->angles
[1], ent
->angles
[2]);
272 Debugging tool, just flashes the screen
287 VID_SetPalette (host_basepal
);
290 for (c
=0 ; c
<768 ; c
+=3)
296 VID_SetPalette (pal
);
300 for (c
=0 ; c
<768 ; c
+=3)
306 VID_SetPalette (pal
);
317 dlight_t
*CL_AllocDlight (int key
)
322 // first look for an exact key match
326 for (i
=0 ; i
<MAX_DLIGHTS
; i
++, dl
++)
330 memset (dl
, 0, sizeof(*dl
));
337 // then look for anything else
339 for (i
=0 ; i
<MAX_DLIGHTS
; i
++, dl
++)
341 if (dl
->die
< cl
.time
)
343 memset (dl
, 0, sizeof(*dl
));
350 memset (dl
, 0, sizeof(*dl
));
362 void CL_DecayLights (void)
368 time
= cl
.time
- cl
.oldtime
;
371 for (i
=0 ; i
<MAX_DLIGHTS
; i
++, dl
++)
373 if (dl
->die
< cl
.time
|| !dl
->radius
)
376 dl
->radius
-= time
*dl
->decay
;
387 Determines the fraction between the last two messages that the objects
391 float CL_LerpPoint (void)
395 f
= cl
.mtime
[0] - cl
.mtime
[1];
397 if (!f
|| cl_nolerp
.value
|| cls
.timedemo
|| sv
.active
)
399 cl
.time
= cl
.mtime
[0];
404 { // dropped packet, or start of demo
405 cl
.mtime
[1] = cl
.mtime
[0] - 0.1;
408 frac
= (cl
.time
- cl
.mtime
[1]) / f
;
409 //Con_Printf ("frac: %f\n",frac);
415 cl
.time
= cl
.mtime
[1];
416 // Con_Printf ("low frac\n");
425 cl
.time
= cl
.mtime
[0];
426 // Con_Printf ("high frac\n");
442 void CL_RelinkEntities (void)
452 // determine partial update time
453 frac
= CL_LerpPoint ();
458 // interpolate player info
460 for (i
=0 ; i
<3 ; i
++)
461 cl
.velocity
[i
] = cl
.mvelocity
[1][i
] +
462 frac
* (cl
.mvelocity
[0][i
] - cl
.mvelocity
[1][i
]);
464 if (cls
.demoplayback
)
466 // interpolate the angles
467 for (j
=0 ; j
<3 ; j
++)
469 d
= cl
.mviewangles
[0][j
] - cl
.mviewangles
[1][j
];
474 cl
.viewangles
[j
] = cl
.mviewangles
[1][j
] + frac
*d
;
478 bobjrotate
= anglemod(100*cl
.time
);
480 // start on the entity after the world
481 for (i
=1,ent
=cl_entities
+1 ; i
<cl
.num_entities
; i
++,ent
++)
486 R_RemoveEfrags (ent
); // just became empty
490 // if the object wasn't included in the last packet, remove it
491 if (ent
->msgtime
!= cl
.mtime
[0])
497 VectorCopy (ent
->origin
, oldorg
);
500 { // the entity was not updated in the last message
501 // so move to the final spot
502 VectorCopy (ent
->msg_origins
[0], ent
->origin
);
503 VectorCopy (ent
->msg_angles
[0], ent
->angles
);
506 { // if the delta is large, assume a teleport and don't lerp
508 for (j
=0 ; j
<3 ; j
++)
510 delta
[j
] = ent
->msg_origins
[0][j
] - ent
->msg_origins
[1][j
];
511 if (delta
[j
] > 100 || delta
[j
] < -100)
512 f
= 1; // assume a teleportation, not a motion
515 // interpolate the origin and angles
516 for (j
=0 ; j
<3 ; j
++)
518 ent
->origin
[j
] = ent
->msg_origins
[1][j
] + f
*delta
[j
];
520 d
= ent
->msg_angles
[0][j
] - ent
->msg_angles
[1][j
];
525 ent
->angles
[j
] = ent
->msg_angles
[1][j
] + f
*d
;
530 // rotate binary objects locally
531 if (ent
->model
->flags
& EF_ROTATE
)
532 ent
->angles
[1] = bobjrotate
;
534 if (ent
->effects
& EF_BRIGHTFIELD
)
535 R_EntityParticles (ent
);
537 if (ent
->effects
& EF_DARKFIELD
)
538 R_DarkFieldParticles (ent
);
540 if (ent
->effects
& EF_MUZZLEFLASH
)
544 dl
= CL_AllocDlight (i
);
545 VectorCopy (ent
->origin
, dl
->origin
);
547 AngleVectors (ent
->angles
, fv
, rv
, uv
);
549 VectorMA (dl
->origin
, 18, fv
, dl
->origin
);
550 dl
->radius
= 200 + (rand()&31);
552 dl
->die
= cl
.time
+ 0.1;
554 if (ent
->effects
& EF_BRIGHTLIGHT
)
556 dl
= CL_AllocDlight (i
);
557 VectorCopy (ent
->origin
, dl
->origin
);
559 dl
->radius
= 400 + (rand()&31);
560 dl
->die
= cl
.time
+ 0.001;
562 if (ent
->effects
& EF_DIMLIGHT
)
564 dl
= CL_AllocDlight (i
);
565 VectorCopy (ent
->origin
, dl
->origin
);
566 dl
->radius
= 200 + (rand()&31);
567 dl
->die
= cl
.time
+ 0.001;
570 if (ent
->effects
& EF_DARKLIGHT
)
572 dl
= CL_AllocDlight (i
);
573 VectorCopy (ent
->origin
, dl
->origin
);
574 dl
->radius
= 200.0 + (rand()&31);
575 dl
->die
= cl
.time
+ 0.001;
578 if (ent
->effects
& EF_LIGHT
)
580 dl
= CL_AllocDlight (i
);
581 VectorCopy (ent
->origin
, dl
->origin
);
583 dl
->die
= cl
.time
+ 0.001;
587 if (ent
->model
->flags
& EF_GIB
)
588 R_RocketTrail (oldorg
, ent
->origin
, 2);
589 else if (ent
->model
->flags
& EF_ZOMGIB
)
590 R_RocketTrail (oldorg
, ent
->origin
, 4);
591 else if (ent
->model
->flags
& EF_TRACER
)
592 R_RocketTrail (oldorg
, ent
->origin
, 3);
593 else if (ent
->model
->flags
& EF_TRACER2
)
594 R_RocketTrail (oldorg
, ent
->origin
, 5);
595 else if (ent
->model
->flags
& EF_ROCKET
)
597 R_RocketTrail (oldorg
, ent
->origin
, 0);
598 dl
= CL_AllocDlight (i
);
599 VectorCopy (ent
->origin
, dl
->origin
);
601 dl
->die
= cl
.time
+ 0.01;
603 else if (ent
->model
->flags
& EF_GRENADE
)
604 R_RocketTrail (oldorg
, ent
->origin
, 1);
605 else if (ent
->model
->flags
& EF_TRACER3
)
606 R_RocketTrail (oldorg
, ent
->origin
, 6);
608 ent
->forcelink
= false;
610 if (i
== cl
.viewentity
&& !chase_active
.value
)
614 if ( ent
->effects
& EF_NODRAW
)
617 if (cl_numvisedicts
< MAX_VISEDICTS
)
619 cl_visedicts
[cl_numvisedicts
] = ent
;
631 Read all incoming data from the server
634 int CL_ReadFromServer (void)
638 cl
.oldtime
= cl
.time
;
639 cl
.time
+= host_frametime
;
643 ret
= CL_GetMessage ();
645 Host_Error ("CL_ReadFromServer: lost server connection");
649 cl
.last_received_message
= realtime
;
650 CL_ParseServerMessage ();
651 } while (ret
&& cls
.state
== ca_connected
);
653 if (cl_shownet
.value
)
656 CL_RelinkEntities ();
660 // bring the links up to date
670 void CL_SendCmd (void)
674 if (cls
.state
!= ca_connected
)
677 if (cls
.signon
== SIGNONS
)
679 // get basic movement from keyboard
682 // allow mice or other external controllers to add to the move
685 // send the unreliable message
690 if (cls
.demoplayback
)
692 SZ_Clear (&cls
.message
);
696 // send the reliable message
697 if (!cls
.message
.cursize
)
698 return; // no message at all
700 if (!NET_CanSendMessage (cls
.netcon
))
702 Con_DPrintf ("CL_WriteToServer: can't send\n");
706 if (NET_SendMessage (cls
.netcon
, &cls
.message
) == -1)
707 Host_Error ("CL_WriteToServer: lost server connection");
709 SZ_Clear (&cls
.message
);
719 SZ_Alloc (&cls
.message
, 1024);
725 // register our commands
727 Cvar_RegisterVariable (&cl_name
);
728 Cvar_RegisterVariable (&cl_color
);
729 Cvar_RegisterVariable (&cl_upspeed
);
730 Cvar_RegisterVariable (&cl_forwardspeed
);
731 Cvar_RegisterVariable (&cl_backspeed
);
732 Cvar_RegisterVariable (&cl_sidespeed
);
733 Cvar_RegisterVariable (&cl_movespeedkey
);
734 Cvar_RegisterVariable (&cl_yawspeed
);
735 Cvar_RegisterVariable (&cl_pitchspeed
);
736 Cvar_RegisterVariable (&cl_anglespeedkey
);
737 Cvar_RegisterVariable (&cl_shownet
);
738 Cvar_RegisterVariable (&cl_nolerp
);
739 Cvar_RegisterVariable (&lookspring
);
740 Cvar_RegisterVariable (&lookstrafe
);
741 Cvar_RegisterVariable (&sensitivity
);
743 Cvar_RegisterVariable (&m_pitch
);
744 Cvar_RegisterVariable (&m_yaw
);
745 Cvar_RegisterVariable (&m_forward
);
746 Cvar_RegisterVariable (&m_side
);
748 // Cvar_RegisterVariable (&cl_autofire);
750 Cmd_AddCommand ("entities", CL_PrintEntities_f
);
751 Cmd_AddCommand ("disconnect", CL_Disconnect_f
);
752 Cmd_AddCommand ("record", CL_Record_f
);
753 Cmd_AddCommand ("stop", CL_Stop_f
);
754 Cmd_AddCommand ("playdemo", CL_PlayDemo_f
);
755 Cmd_AddCommand ("timedemo", CL_TimeDemo_f
);