1 /*
2 Copyright (C) 1996-1997 Id Software, Inc.
3
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.
8
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.
12
13 See the GNU General Public License for more details.
14
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.
18
19 */
20 // sv_send.c
21
22 #include "model.h"
23 #include "qwsvdef.h"
24 #include "server.h"
25 #include "sys.h"
26
27 #define CHAN_AUTO 0
28 #define CHAN_WEAPON 1
29 #define CHAN_VOICE 2
30 #define CHAN_ITEM 3
31 #define CHAN_BODY 4
32
33 /*
34 =============================================================================
35
36 Con_Printf redirection
37
38 =============================================================================
39 */
40
41 static char outputbuf[8000];
42
43 redirect_t sv_redirected;
44
45 /*
46 ==================
47 SV_FlushRedirect
48 ==================
49 */
50 static void
SV_FlushRedirect(void)51 SV_FlushRedirect(void)
52 {
53 char send[8000 + 6];
54
55 if (sv_redirected == RD_PACKET) {
56 send[0] = 0xff;
57 send[1] = 0xff;
58 send[2] = 0xff;
59 send[3] = 0xff;
60 send[4] = A2C_PRINT;
61 memcpy(send + 5, outputbuf, strlen(outputbuf) + 1);
62
63 NET_SendPacket(strlen(send) + 1, send, net_from);
64 } else if (sv_redirected == RD_CLIENT) {
65 ClientReliableWrite_Begin(host_client, svc_print,
66 strlen(outputbuf) + 3);
67 ClientReliableWrite_Byte(host_client, PRINT_HIGH);
68 ClientReliableWrite_String(host_client, outputbuf);
69 }
70 // clear it
71 outputbuf[0] = 0;
72 }
73
74
75 /*
76 ==================
77 SV_BeginRedirect
78
79 Send Con_Printf data to the remote client
80 instead of the console
81 ==================
82 */
83 void
SV_BeginRedirect(redirect_t rd)84 SV_BeginRedirect(redirect_t rd)
85 {
86 sv_redirected = rd;
87 outputbuf[0] = 0;
88 }
89
90 void
SV_EndRedirect(void)91 SV_EndRedirect(void)
92 {
93 SV_FlushRedirect();
94 sv_redirected = RD_NONE;
95 }
96
97
98 /*
99 ================
100 Con_Printf
101
102 Handles cursor positioning, line wrapping, etc
103 ================
104 */
105 void
Con_Printf(const char * fmt,...)106 Con_Printf(const char *fmt, ...)
107 {
108 va_list argptr;
109 char msg[MAX_PRINTMSG];
110
111 va_start(argptr, fmt);
112 vsnprintf(msg, sizeof(msg), fmt, argptr);
113 va_end(argptr);
114
115 // add to redirected message
116 if (sv_redirected) {
117 if (strlen(msg) + strlen(outputbuf) > sizeof(outputbuf) - 1)
118 SV_FlushRedirect();
119 strcat(outputbuf, msg);
120 return;
121 }
122
123 Sys_Printf("%s", msg); // also echo to debugging console
124 if (sv_logfile)
125 fprintf(sv_logfile, "%s", msg);
126 }
127
128 /*
129 ================
130 Con_DPrintf
131
132 A Con_Printf that only shows up if the "developer" cvar is set
133 ================
134 */
135 void
Con_DPrintf(const char * fmt,...)136 Con_DPrintf(const char *fmt, ...)
137 {
138 va_list argptr;
139 char msg[MAX_PRINTMSG];
140
141 if (!developer.value)
142 return;
143
144 va_start(argptr, fmt);
145 vsnprintf(msg, sizeof(msg), fmt, argptr);
146 va_end(argptr);
147
148 Con_Printf("%s", msg);
149 }
150
151 /*
152 =============================================================================
153
154 EVENT MESSAGES
155
156 =============================================================================
157 */
158
159 static void
SV_PrintToClient(client_t * cl,int level,char * string)160 SV_PrintToClient(client_t *cl, int level, char *string)
161 {
162 ClientReliableWrite_Begin(cl, svc_print, strlen(string) + 3);
163 ClientReliableWrite_Byte(cl, level);
164 ClientReliableWrite_String(cl, string);
165 }
166
167
168 /*
169 =================
170 SV_ClientPrintf
171
172 Sends text across to be displayed if the level passes
173 =================
174 */
175 void
SV_ClientPrintf(client_t * cl,int level,const char * fmt,...)176 SV_ClientPrintf(client_t *cl, int level, const char *fmt, ...)
177 {
178 va_list argptr;
179 char string[MAX_PRINTMSG];
180
181 if (level < cl->messagelevel)
182 return;
183
184 va_start(argptr, fmt);
185 vsnprintf(string, sizeof(string), fmt, argptr);
186 va_end(argptr);
187
188 SV_PrintToClient(cl, level, string);
189 }
190
191 /*
192 =================
193 SV_BroadcastPrintf
194
195 Sends text to all active clients
196 =================
197 */
198 void
SV_BroadcastPrintf(int level,const char * fmt,...)199 SV_BroadcastPrintf(int level, const char *fmt, ...)
200 {
201 va_list argptr;
202 char string[MAX_PRINTMSG];
203 client_t *cl;
204 int i;
205
206 va_start(argptr, fmt);
207 vsnprintf(string, sizeof(string), fmt, argptr);
208 va_end(argptr);
209
210 Sys_Printf("%s", string); // print to the console
211
212 for (i = 0, cl = svs.clients; i < MAX_CLIENTS; i++, cl++) {
213 if (level < cl->messagelevel)
214 continue;
215 if (!cl->state)
216 continue;
217
218 SV_PrintToClient(cl, level, string);
219 }
220 }
221
222 /*
223 =================
224 SV_BroadcastCommand
225
226 Sends text to all active clients
227 =================
228 */
229 void
SV_BroadcastCommand(const char * fmt,...)230 SV_BroadcastCommand(const char *fmt, ...)
231 {
232 va_list argptr;
233 char string[MAX_PRINTMSG];
234
235 if (!sv.state)
236 return;
237 va_start(argptr, fmt);
238 vsnprintf(string, sizeof(string), fmt, argptr);
239 va_end(argptr);
240
241 MSG_WriteByte(&sv.reliable_datagram, svc_stufftext);
242 MSG_WriteString(&sv.reliable_datagram, string);
243 }
244
245
246 /*
247 =================
248 SV_Multicast
249
250 Sends the contents of sv.multicast to a subset of the clients,
251 then clears sv.multicast.
252
253 MULTICAST_ALL same as broadcast
254 MULTICAST_PVS send to clients potentially visible from org
255 MULTICAST_PHS send to clients potentially hearable from org
256 =================
257 */
258 void
SV_Multicast(vec3_t origin,int to)259 SV_Multicast(vec3_t origin, int to)
260 {
261 client_t *client;
262 const leafbits_t *mask;
263 mleaf_t *leaf;
264 int leafnum;
265 int j;
266 qboolean reliable;
267
268 leaf = Mod_PointInLeaf(sv.worldmodel, origin);
269 if (!leaf)
270 leafnum = 0;
271 else
272 leafnum = leaf - sv.worldmodel->leafs;
273
274 reliable = false;
275
276 switch (to) {
277 case MULTICAST_ALL_R:
278 reliable = true; // intentional fallthrough
279 case MULTICAST_ALL:
280 mask = sv.pvs[0]; // leaf 0 is everything;
281 break;
282
283 case MULTICAST_PHS_R:
284 reliable = true; // intentional fallthrough
285 case MULTICAST_PHS:
286 mask = sv.phs[leafnum];
287 break;
288
289 case MULTICAST_PVS_R:
290 reliable = true; // intentional fallthrough
291 case MULTICAST_PVS:
292 mask = sv.pvs[leafnum];
293 break;
294
295 default:
296 mask = NULL;
297 SV_Error("SV_Multicast: bad to:%i", to);
298 }
299
300 // send the data to all relevent clients
301 for (j = 0, client = svs.clients; j < MAX_CLIENTS; j++, client++) {
302 if (client->state != cs_spawned)
303 continue;
304
305 if (to == MULTICAST_PHS_R || to == MULTICAST_PHS) {
306 vec3_t delta;
307
308 VectorSubtract(origin, client->edict->v.origin, delta);
309 if (Length(delta) <= 1024)
310 goto inrange;
311 }
312
313 leaf = Mod_PointInLeaf(sv.worldmodel, client->edict->v.origin);
314 if (leaf) {
315 // -1 is because pvs rows are 1 based, not 0 based like leafs
316 leafnum = leaf - sv.worldmodel->leafs - 1;
317 if (!Mod_TestLeafBit(mask, leafnum)) {
318 // Con_Printf ("supressed multicast\n");
319 continue;
320 }
321 }
322
323 inrange:
324 if (reliable) {
325 ClientReliableCheckBlock(client, sv.multicast.cursize);
326 ClientReliableWrite_SZ(client, sv.multicast.data,
327 sv.multicast.cursize);
328 } else
329 SZ_Write(&client->datagram, sv.multicast.data,
330 sv.multicast.cursize);
331 }
332
333 SZ_Clear(&sv.multicast);
334 }
335
336
337 /*
338 ==================
339 SV_StartSound
340
341 Each entity can have eight independant sound sources, like voice,
342 weapon, feet, etc.
343
344 Channel 0 is an auto-allocate channel, the others override anything
345 allready running on that entity/channel pair.
346
347 An attenuation of 0 will play full volume everywhere in the level.
348 Larger attenuations will drop off. (max 4 attenuation)
349
350 ==================
351 */
352 void
SV_StartSound(edict_t * entity,int channel,const char * sample,int volume,float attenuation)353 SV_StartSound(edict_t *entity, int channel, const char *sample, int volume,
354 float attenuation)
355 {
356 int sound_num;
357 int i;
358 int ent;
359 vec3_t origin;
360 qboolean use_phs;
361 qboolean reliable = false;
362
363 if (volume < 0 || volume > 255)
364 SV_Error("SV_StartSound: volume = %i", volume);
365
366 if (attenuation < 0 || attenuation > 4)
367 SV_Error("SV_StartSound: attenuation = %f", attenuation);
368
369 if (channel < 0 || channel > 15)
370 SV_Error("SV_StartSound: channel = %i", channel);
371
372 // find precache number for sound
373 for (sound_num = 1; sound_num < MAX_SOUNDS
374 && sv.sound_precache[sound_num]; sound_num++)
375 if (!strcmp(sample, sv.sound_precache[sound_num]))
376 break;
377
378 if (sound_num == MAX_SOUNDS || !sv.sound_precache[sound_num]) {
379 Con_Printf("SV_StartSound: %s not precacheed\n", sample);
380 return;
381 }
382
383 ent = NUM_FOR_EDICT(entity);
384
385 if ((channel & 8) || !sv_phs.value) // no PHS flag
386 {
387 if (channel & 8)
388 reliable = true; // sounds that break the phs are reliable
389 use_phs = false;
390 channel &= 7;
391 } else
392 use_phs = true;
393
394 // if (channel == CHAN_BODY || channel == CHAN_VOICE)
395 // reliable = true;
396
397 channel = (ent << 3) | channel;
398
399 if (volume != DEFAULT_SOUND_PACKET_VOLUME)
400 channel |= SND_VOLUME;
401 if (attenuation != DEFAULT_SOUND_PACKET_ATTENUATION)
402 channel |= SND_ATTENUATION;
403
404 // use the entity origin unless it is a bmodel
405 if (entity->v.solid == SOLID_BSP) {
406 for (i = 0; i < 3; i++)
407 origin[i] =
408 entity->v.origin[i] + 0.5 * (entity->v.mins[i] +
409 entity->v.maxs[i]);
410 } else {
411 VectorCopy(entity->v.origin, origin);
412 }
413
414 MSG_WriteByte(&sv.multicast, svc_sound);
415 MSG_WriteShort(&sv.multicast, channel);
416 if (channel & SND_VOLUME)
417 MSG_WriteByte(&sv.multicast, volume);
418 if (channel & SND_ATTENUATION)
419 MSG_WriteByte(&sv.multicast, attenuation * 64);
420 MSG_WriteByte(&sv.multicast, sound_num);
421 for (i = 0; i < 3; i++)
422 MSG_WriteCoord(&sv.multicast, origin[i]);
423
424 if (use_phs)
425 SV_Multicast(origin, reliable ? MULTICAST_PHS_R : MULTICAST_PHS);
426 else
427 SV_Multicast(origin, reliable ? MULTICAST_ALL_R : MULTICAST_ALL);
428 }
429
430
431 /*
432 ===============================================================================
433
434 FRAME UPDATES
435
436 ===============================================================================
437 */
438
439 int sv_nailmodel, sv_supernailmodel, sv_playermodel;
440
441 void
SV_FindModelNumbers(void)442 SV_FindModelNumbers(void)
443 {
444 int i;
445
446 sv_nailmodel = -1;
447 sv_supernailmodel = -1;
448 sv_playermodel = -1;
449
450 for (i = 0; i < MAX_MODELS; i++) {
451 if (!sv.model_precache[i])
452 break;
453 if (!strcmp(sv.model_precache[i], "progs/spike.mdl"))
454 sv_nailmodel = i;
455 if (!strcmp(sv.model_precache[i], "progs/s_spike.mdl"))
456 sv_supernailmodel = i;
457 if (!strcmp(sv.model_precache[i], "progs/player.mdl"))
458 sv_playermodel = i;
459 }
460 }
461
462
463 /*
464 ==================
465 SV_WriteClientdataToMessage
466
467 ==================
468 */
469 void
SV_WriteClientdataToMessage(client_t * client,sizebuf_t * msg)470 SV_WriteClientdataToMessage(client_t *client, sizebuf_t *msg)
471 {
472 int i;
473 edict_t *other;
474 edict_t *ent;
475
476 ent = client->edict;
477
478 // send the chokecount for r_netgraph
479 if (client->chokecount) {
480 MSG_WriteByte(msg, svc_chokecount);
481 MSG_WriteByte(msg, client->chokecount);
482 client->chokecount = 0;
483 }
484 // send a damage message if the player got hit this frame
485 if (ent->v.dmg_take || ent->v.dmg_save) {
486 other = PROG_TO_EDICT(ent->v.dmg_inflictor);
487 MSG_WriteByte(msg, svc_damage);
488 MSG_WriteByte(msg, ent->v.dmg_save);
489 MSG_WriteByte(msg, ent->v.dmg_take);
490 for (i = 0; i < 3; i++)
491 MSG_WriteCoord(msg,
492 other->v.origin[i] + 0.5 * (other->v.mins[i] +
493 other->v.maxs[i]));
494
495 ent->v.dmg_take = 0;
496 ent->v.dmg_save = 0;
497 }
498 // a fixangle might get lost in a dropped packet. Oh well.
499 if (ent->v.fixangle) {
500 MSG_WriteByte(msg, svc_setangle);
501 for (i = 0; i < 3; i++)
502 MSG_WriteAngle(msg, ent->v.angles[i]);
503 ent->v.fixangle = 0;
504 }
505 }
506
507 /*
508 =======================
509 SV_UpdateClientStats
510
511 Performs a delta update of the stats array. This should only be performed
512 when a reliable message can be delivered this frame.
513 =======================
514 */
515 static void
SV_UpdateClientStats(client_t * client)516 SV_UpdateClientStats(client_t *client)
517 {
518 edict_t *ent;
519 int stats[MAX_CL_STATS];
520 int i;
521
522 ent = client->edict;
523 memset(stats, 0, sizeof(stats));
524
525 // if we are a spectator and we are tracking a player, we get his stats
526 // so our status bar reflects his
527 if (client->spectator && client->spec_track > 0)
528 ent = svs.clients[client->spec_track - 1].edict;
529
530 stats[STAT_HEALTH] = ent->v.health;
531 stats[STAT_WEAPON] = SV_ModelIndex(PR_GetString(ent->v.weaponmodel));
532 stats[STAT_AMMO] = ent->v.currentammo;
533 stats[STAT_ARMOR] = ent->v.armorvalue;
534 stats[STAT_SHELLS] = ent->v.ammo_shells;
535 stats[STAT_NAILS] = ent->v.ammo_nails;
536 stats[STAT_ROCKETS] = ent->v.ammo_rockets;
537 stats[STAT_CELLS] = ent->v.ammo_cells;
538 if (!client->spectator)
539 stats[STAT_ACTIVEWEAPON] = ent->v.weapon;
540 // stuff the sigil bits into the high bits of items for sbar
541 stats[STAT_ITEMS] =
542 (int)ent->v.items | ((int)pr_global_struct->serverflags << 28);
543
544 for (i = 0; i < MAX_CL_STATS; i++)
545 if (stats[i] != client->stats[i]) {
546 client->stats[i] = stats[i];
547 if (stats[i] >= 0 && stats[i] <= 255) {
548 ClientReliableWrite_Begin(client, svc_updatestat, 3);
549 ClientReliableWrite_Byte(client, i);
550 ClientReliableWrite_Byte(client, stats[i]);
551 } else {
552 ClientReliableWrite_Begin(client, svc_updatestatlong, 6);
553 ClientReliableWrite_Byte(client, i);
554 ClientReliableWrite_Long(client, stats[i]);
555 }
556 }
557 }
558
559 /*
560 =======================
561 SV_SendClientDatagram
562 =======================
563 */
564 static qboolean
SV_SendClientDatagram(client_t * client)565 SV_SendClientDatagram(client_t *client)
566 {
567 byte buf[MAX_DATAGRAM];
568 sizebuf_t msg;
569
570 msg.data = buf;
571 msg.maxsize = sizeof(buf);
572 msg.cursize = 0;
573 msg.allowoverflow = true;
574 msg.overflowed = false;
575
576 // add the client specific data to the datagram
577 SV_WriteClientdataToMessage(client, &msg);
578
579 // send over all the objects that are in the PVS
580 // this will include clients, a packetentities, and
581 // possibly a nails update
582 SV_WriteEntitiesToClient(client, &msg);
583
584 // copy the accumulated multicast datagram
585 // for this client out to the message
586 if (client->datagram.overflowed)
587 Con_Printf("WARNING: datagram overflowed for %s\n", client->name);
588 else
589 SZ_Write(&msg, client->datagram.data, client->datagram.cursize);
590 SZ_Clear(&client->datagram);
591
592 // send deltas over reliable stream
593 if (Netchan_CanReliable(&client->netchan))
594 SV_UpdateClientStats(client);
595
596 if (msg.overflowed) {
597 Con_Printf("WARNING: msg overflowed for %s\n", client->name);
598 SZ_Clear(&msg);
599 }
600 // send the datagram
601 Netchan_Transmit(&client->netchan, msg.cursize, buf);
602
603 return true;
604 }
605
606 /*
607 =======================
608 SV_UpdateToReliableMessages
609 =======================
610 */
611 static void
SV_UpdateToReliableMessages(void)612 SV_UpdateToReliableMessages(void)
613 {
614 int i, j;
615 client_t *client;
616 eval_t *val;
617 edict_t *ent;
618
619 // check for changes to be sent over the reliable streams to all clients
620 for (i = 0, host_client = svs.clients; i < MAX_CLIENTS;
621 i++, host_client++) {
622 if (host_client->state != cs_spawned)
623 continue;
624 if (host_client->sendinfo) {
625 host_client->sendinfo = false;
626 SV_FullClientUpdate(host_client, &sv.reliable_datagram);
627 }
628 if (host_client->old_frags != host_client->edict->v.frags) {
629 for (j = 0, client = svs.clients; j < MAX_CLIENTS; j++, client++) {
630 if (client->state < cs_connected)
631 continue;
632 ClientReliableWrite_Begin(client, svc_updatefrags, 4);
633 ClientReliableWrite_Byte(client, i);
634 ClientReliableWrite_Short(client,
635 host_client->edict->v.frags);
636 }
637
638 host_client->old_frags = host_client->edict->v.frags;
639 }
640 // maxspeed/entgravity changes
641 ent = host_client->edict;
642
643 val = GetEdictFieldValue(ent, "gravity");
644 if (val && host_client->entgravity != val->_float) {
645 host_client->entgravity = val->_float;
646 ClientReliableWrite_Begin(host_client, svc_entgravity, 5);
647 ClientReliableWrite_Float(host_client, host_client->entgravity);
648 }
649 val = GetEdictFieldValue(ent, "maxspeed");
650 if (val && host_client->maxspeed != val->_float) {
651 host_client->maxspeed = val->_float;
652 ClientReliableWrite_Begin(host_client, svc_maxspeed, 5);
653 ClientReliableWrite_Float(host_client, host_client->maxspeed);
654 }
655
656 }
657
658 if (sv.datagram.overflowed)
659 SZ_Clear(&sv.datagram);
660
661 // append the broadcast messages to each client messages
662 for (j = 0, client = svs.clients; j < MAX_CLIENTS; j++, client++) {
663 if (client->state < cs_connected)
664 continue; // reliables go to all connected or spawned
665
666 ClientReliableCheckBlock(client, sv.reliable_datagram.cursize);
667 ClientReliableWrite_SZ(client, sv.reliable_datagram.data,
668 sv.reliable_datagram.cursize);
669
670 if (client->state != cs_spawned)
671 continue; // datagrams only go to spawned
672 SZ_Write(&client->datagram, sv.datagram.data, sv.datagram.cursize);
673 }
674
675 SZ_Clear(&sv.reliable_datagram);
676 SZ_Clear(&sv.datagram);
677 }
678
679
680 /*
681 =======================
682 SV_SendClientMessages
683 =======================
684 */
685 void
SV_SendClientMessages(void)686 SV_SendClientMessages(void)
687 {
688 int i, j;
689 client_t *c;
690
691 // update frags, names, etc
692 SV_UpdateToReliableMessages();
693
694 // build individual updates
695 for (i = 0, c = svs.clients; i < MAX_CLIENTS; i++, c++) {
696 if (!c->state)
697 continue;
698
699 if (c->drop) {
700 SV_DropClient(c);
701 c->drop = false;
702 continue;
703 }
704 // check to see if we have a backbuf to stick in the reliable
705 if (c->num_backbuf) {
706 // will it fit?
707 if (c->netchan.message.cursize + c->backbuf_size[0] <
708 c->netchan.message.maxsize) {
709
710 Con_DPrintf("%s: backbuf %d bytes\n",
711 c->name, c->backbuf_size[0]);
712
713 // it'll fit
714 SZ_Write(&c->netchan.message, c->backbuf_data[0],
715 c->backbuf_size[0]);
716
717 //move along, move along
718 for (j = 1; j < c->num_backbuf; j++) {
719 memcpy(c->backbuf_data[j - 1], c->backbuf_data[j],
720 c->backbuf_size[j]);
721 c->backbuf_size[j - 1] = c->backbuf_size[j];
722 }
723
724 c->num_backbuf--;
725 if (c->num_backbuf) {
726 memset(&c->backbuf, 0, sizeof(c->backbuf));
727 c->backbuf.data = c->backbuf_data[c->num_backbuf - 1];
728 c->backbuf.cursize = c->backbuf_size[c->num_backbuf - 1];
729 c->backbuf.maxsize =
730 sizeof(c->backbuf_data[c->num_backbuf - 1]);
731 }
732 }
733 }
734 // if the reliable message overflowed,
735 // drop the client
736 if (c->netchan.message.overflowed) {
737 SZ_Clear(&c->netchan.message);
738 SZ_Clear(&c->datagram);
739 SV_BroadcastPrintf(PRINT_HIGH, "%s overflowed\n", c->name);
740 Con_Printf("WARNING: reliable overflow for %s\n", c->name);
741 SV_DropClient(c);
742 c->send_message = true;
743 c->netchan.cleartime = 0; // don't choke this message
744 }
745 // only send messages if the client has sent one
746 // and the bandwidth is not choked
747 if (!c->send_message)
748 continue;
749 c->send_message = false; // try putting this after choke?
750 if (!sv.paused && !Netchan_CanPacket(&c->netchan)) {
751 c->chokecount++;
752 continue; // bandwidth choke
753 }
754
755 if (c->state == cs_spawned)
756 SV_SendClientDatagram(c);
757 else
758 Netchan_Transmit(&c->netchan, 0, NULL); // just update reliable
759
760 }
761 }
762
763
764 /*
765 =======================
766 SV_SendMessagesToAll
767
768 FIXME: does this sequence right?
769 =======================
770 */
771 void
SV_SendMessagesToAll(void)772 SV_SendMessagesToAll(void)
773 {
774 int i;
775 client_t *c;
776
777 for (i = 0, c = svs.clients; i < MAX_CLIENTS; i++, c++)
778 if (c->state) // FIXME: should this only send to active?
779 c->send_message = true;
780
781 SV_SendClientMessages();
782 }
783