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
21 #include "quakedef.h"
22
23 extern cvar_t pausable;
24
25 int current_skill;
26
27 void Mod_Print (void);
28
29 /*
30 ==================
31 Host_Quit_f
32 ==================
33 */
34
35 extern void M_Menu_Quit_f (void);
36
37 void Host_Quit();
38
Host_Quit_f(void)39 void Host_Quit_f (void)
40 {
41 if (key_dest != key_console && cls.state != ca_dedicated)
42 {
43 M_Menu_Quit_f ();
44 return;
45 }
46 Host_Quit();
47 }
48
Host_Quit()49 void Host_Quit()
50 {
51 CL_Disconnect ();
52 Host_ShutdownServer(false);
53
54 Sys_Quit ();
55 }
56
57
58 /*
59 ==================
60 Host_Status_f
61 ==================
62 */
Host_Status_f(void)63 void Host_Status_f (void)
64 {
65 client_t *client;
66 int seconds;
67 int minutes;
68 int hours = 0;
69 int j;
70 void (*print) (const char *fmt, ...);
71
72 if (cmd_source == src_command)
73 {
74 if (!sv.active)
75 {
76 Cmd_ForwardToServer ();
77 return;
78 }
79 print = Con_Printf;
80 }
81 else
82 print = SV_ClientPrintf;
83
84 print ("host: %s\n", Cvar_VariableString ("hostname"));
85 print ("version: %4.2f\n", VERSION);
86 if (tcpipAvailable)
87 print ("tcp/ip: %s\n", my_tcpip_address);
88 if (ipxAvailable)
89 print ("ipx: %s\n", my_ipx_address);
90 print ("map: %s\n", sv.name);
91 print ("players: %i active (%i max)\n\n", net_activeconnections, svs.maxclients);
92 for (j=0, client = svs.clients ; j<svs.maxclients ; j++, client++)
93 {
94 if (!client->active)
95 continue;
96 seconds = (int)(net_time - client->netconnection->connecttime);
97 minutes = seconds / 60;
98 if (minutes)
99 {
100 seconds -= (minutes * 60);
101 hours = minutes / 60;
102 if (hours)
103 minutes -= (hours * 60);
104 }
105 else
106 hours = 0;
107 print ("#%-2u %-16.16s %3i %2i:%02i:%02i\n", j+1, client->name, (int)client->edict->u.v.frags, hours, minutes, seconds);
108 print (" %s\n", client->netconnection->address);
109 }
110 }
111
112
113 /*
114 ==================
115 Host_God_f
116
117 Sets client to godmode
118 ==================
119 */
Host_God_f(void)120 void Host_God_f (void)
121 {
122 if (cmd_source == src_command)
123 {
124 Cmd_ForwardToServer ();
125 return;
126 }
127
128 if (pr_global_struct->deathmatch && !host_client->privileged)
129 return;
130
131 sv_player->u.v.flags = (int)sv_player->u.v.flags ^ FL_GODMODE;
132 if (!((int)sv_player->u.v.flags & FL_GODMODE) )
133 SV_ClientPrintf ("godmode OFF\n");
134 else
135 SV_ClientPrintf ("godmode ON\n");
136 }
137
Host_Notarget_f(void)138 void Host_Notarget_f (void)
139 {
140 if (cmd_source == src_command)
141 {
142 Cmd_ForwardToServer ();
143 return;
144 }
145
146 if (pr_global_struct->deathmatch && !host_client->privileged)
147 return;
148
149 sv_player->u.v.flags = (int)sv_player->u.v.flags ^ FL_NOTARGET;
150 if (!((int)sv_player->u.v.flags & FL_NOTARGET) )
151 SV_ClientPrintf ("notarget OFF\n");
152 else
153 SV_ClientPrintf ("notarget ON\n");
154 }
155
156 qboolean noclip_anglehack;
157
Host_Noclip_f(void)158 void Host_Noclip_f (void)
159 {
160 if (cmd_source == src_command)
161 {
162 Cmd_ForwardToServer ();
163 return;
164 }
165
166 if (pr_global_struct->deathmatch && !host_client->privileged)
167 return;
168
169 if (sv_player->u.v.movetype != MOVETYPE_NOCLIP)
170 {
171 noclip_anglehack = true;
172 sv_player->u.v.movetype = MOVETYPE_NOCLIP;
173 SV_ClientPrintf ("noclip ON\n");
174 }
175 else
176 {
177 noclip_anglehack = false;
178 sv_player->u.v.movetype = MOVETYPE_WALK;
179 SV_ClientPrintf ("noclip OFF\n");
180 }
181 }
182
183 /*
184 ==================
185 Host_Fly_f
186
187 Sets client to flymode
188 ==================
189 */
Host_Fly_f(void)190 void Host_Fly_f (void)
191 {
192 if (cmd_source == src_command)
193 {
194 Cmd_ForwardToServer ();
195 return;
196 }
197
198 if (pr_global_struct->deathmatch && !host_client->privileged)
199 return;
200
201 if (sv_player->u.v.movetype != MOVETYPE_FLY)
202 {
203 sv_player->u.v.movetype = MOVETYPE_FLY;
204 SV_ClientPrintf ("flymode ON\n");
205 }
206 else
207 {
208 sv_player->u.v.movetype = MOVETYPE_WALK;
209 SV_ClientPrintf ("flymode OFF\n");
210 }
211 }
212
213
214 /*
215 ==================
216 Host_Ping_f
217
218 ==================
219 */
Host_Ping_f(void)220 void Host_Ping_f (void)
221 {
222 int i, j;
223 float total;
224 client_t *client;
225
226 if (cmd_source == src_command)
227 {
228 Cmd_ForwardToServer ();
229 return;
230 }
231
232 SV_ClientPrintf ("Client ping times:\n");
233 for (i=0, client = svs.clients ; i<svs.maxclients ; i++, client++)
234 {
235 if (!client->active)
236 continue;
237 total = 0;
238 for (j=0 ; j<NUM_PING_TIMES ; j++)
239 total+=client->ping_times[j];
240 total /= NUM_PING_TIMES;
241 SV_ClientPrintf ("%4i %s\n", (int)(total*1000), client->name);
242 }
243 }
244
245 /*
246 ===============================================================================
247
248 SERVER TRANSITIONS
249
250 ===============================================================================
251 */
252
253
254 /*
255 ======================
256 Host_Map_f
257
258 handle a
259 map <servername>
260 command from the console. Active clients are kicked off.
261 ======================
262 */
Host_Map_f(void)263 void Host_Map_f (void)
264 {
265 int i;
266 char name[MAX_QPATH];
267
268 if (cmd_source != src_command)
269 return;
270
271 cls.demonum = -1; // stop demo loop in case this fails
272
273 CL_Disconnect ();
274 Host_ShutdownServer(false);
275
276 key_dest = key_game; // remove console or menu
277 SCR_BeginLoadingPlaque ();
278
279 cls.mapstring[0] = 0;
280 for (i=0 ; i<Cmd_Argc() ; i++)
281 {
282 strcat (cls.mapstring, Cmd_Argv(i));
283 strcat (cls.mapstring, " ");
284 }
285 strcat (cls.mapstring, "\n");
286
287 svs.serverflags = 0; // haven't completed an episode yet
288 strcpy (name, Cmd_Argv(1));
289 #ifdef QUAKE2
290 SV_SpawnServer (name, NULL);
291 #else
292 SV_SpawnServer (name);
293 #endif
294 if (!sv.active)
295 return;
296
297 if (cls.state != ca_dedicated)
298 {
299 strcpy (cls.spawnparms, "");
300
301 for (i=2 ; i<Cmd_Argc() ; i++)
302 {
303 strcat (cls.spawnparms, Cmd_Argv(i));
304 strcat (cls.spawnparms, " ");
305 }
306
307 Cmd_ExecuteString2 ("connect local", src_command);
308 }
309 }
310
311 /*
312 ==================
313 Host_Changelevel_f
314
315 Goes to a new map, taking all clients along
316 ==================
317 */
Host_Changelevel_f(void)318 void Host_Changelevel_f (void)
319 {
320 #ifdef QUAKE2
321 char level[MAX_QPATH];
322 char _startspot[MAX_QPATH];
323 char *startspot;
324
325 if (Cmd_Argc() < 2)
326 {
327 Con_Printf ("changelevel <levelname> : continue game on a new level\n");
328 return;
329 }
330 if (!sv.active || cls.demoplayback)
331 {
332 Con_Printf ("Only the server may changelevel\n");
333 return;
334 }
335
336 strcpy (level, Cmd_Argv(1));
337 if (Cmd_Argc() == 2)
338 startspot = NULL;
339 else
340 {
341 strcpy (_startspot, Cmd_Argv(2));
342 startspot = _startspot;
343 }
344
345 SV_SaveSpawnparms ();
346 SV_SpawnServer (level, startspot);
347 #else
348 char level[MAX_QPATH];
349
350 if (Cmd_Argc() != 2)
351 {
352 Con_Printf ("changelevel <levelname> : continue game on a new level\n");
353 return;
354 }
355 if (!sv.active || cls.demoplayback)
356 {
357 Con_Printf ("Only the server may changelevel\n");
358 return;
359 }
360 SV_SaveSpawnparms ();
361 strcpy (level, Cmd_Argv(1));
362 SV_SpawnServer (level);
363 #endif
364 }
365
366 /*
367 ==================
368 Host_Restart_f
369
370 Restarts the current server for a dead player
371 ==================
372 */
Host_Restart_f(void)373 void Host_Restart_f (void)
374 {
375 char mapname[MAX_QPATH];
376 #ifdef QUAKE2
377 char startspot[MAX_QPATH];
378 #endif
379
380 if (cls.demoplayback || !sv.active)
381 return;
382
383 if (cmd_source != src_command)
384 return;
385 strcpy (mapname, sv.name); // must copy out, because it gets cleared
386 // in sv_spawnserver
387 #ifdef QUAKE2
388 strcpy(startspot, sv.startspot);
389 SV_SpawnServer (mapname, startspot);
390 #else
391 SV_SpawnServer (mapname);
392 #endif
393 }
394
395 /*
396 ==================
397 Host_Reconnect_f
398
399 This command causes the client to wait for the signon messages again.
400 This is sent just before a server changes levels
401 ==================
402 */
Host_Reconnect_f(void)403 void Host_Reconnect_f (void)
404 {
405 SCR_BeginLoadingPlaque ();
406 cls.signon = 0; // need new connection messages
407 }
408
409 /*
410 =====================
411 Host_Connect_f
412
413 User command to connect to server
414 =====================
415 */
Host_Connect_f(void)416 void Host_Connect_f (void)
417 {
418 char name[MAX_QPATH];
419
420 cls.demonum = -1; // stop demo loop in case this fails
421 if (cls.demoplayback)
422 {
423 CL_StopPlayback ();
424 CL_Disconnect ();
425 }
426 strcpy (name, Cmd_Argv(1));
427 CL_EstablishConnection (name);
428 Host_Reconnect_f ();
429 }
430
431
432 /*
433 ===============================================================================
434
435 LOAD / SAVE GAME
436
437 ===============================================================================
438 */
439
440 #define SAVEGAME_VERSION 5
441
442 /*
443 ===============
444 Host_SavegameComment
445
446 Writes a SAVEGAME_COMMENT_LENGTH character comment describing the current
447 ===============
448 */
Host_SavegameComment(char * text)449 void Host_SavegameComment (char *text)
450 {
451 int i;
452 char kills[20];
453
454 for (i=0 ; i<SAVEGAME_COMMENT_LENGTH ; i++)
455 text[i] = ' ';
456 memcpy (text, cl.levelname, strlen(cl.levelname));
457 sprintf (kills,"kills:%3i/%3i", cl.stats[STAT_MONSTERS], cl.stats[STAT_TOTALMONSTERS]);
458 memcpy (text+22, kills, strlen(kills));
459 // convert space to _ to make stdio happy
460 for (i=0 ; i<SAVEGAME_COMMENT_LENGTH ; i++)
461 if (text[i] == ' ')
462 text[i] = '_';
463 text[SAVEGAME_COMMENT_LENGTH] = '\0';
464 }
465
466
467 /*
468 ===============
469 Host_Savegame_f
470 ===============
471 */
Host_Savegame_f(void)472 void Host_Savegame_f (void)
473 {
474 char name[256];
475 FILE *f;
476 int i;
477 char comment[SAVEGAME_COMMENT_LENGTH+1];
478
479 if (cmd_source != src_command)
480 return;
481
482 if (!sv.active)
483 {
484 Con_Printf ("Not playing a local game.\n");
485 return;
486 }
487
488 if (cl.intermission)
489 {
490 Con_Printf ("Can't save in intermission.\n");
491 return;
492 }
493
494 if (svs.maxclients != 1)
495 {
496 Con_Printf ("Can't save multiplayer games.\n");
497 return;
498 }
499
500 if (Cmd_Argc() != 2)
501 {
502 Con_Printf ("save <savename> : save a game\n");
503 return;
504 }
505
506 if (strstr(Cmd_Argv(1), ".."))
507 {
508 Con_Printf ("Relative pathnames are not allowed.\n");
509 return;
510 }
511
512 for (i=0 ; i<svs.maxclients ; i++)
513 {
514 if (svs.clients[i].active && (svs.clients[i].edict->u.v.health <= 0) )
515 {
516 Con_Printf ("Can't savegame with a dead player\n");
517 return;
518 }
519 }
520
521 sprintf (name, "%s/%s", com_gamedir, Cmd_Argv(1));
522 COM_DefaultExtension (name, ".sav");
523
524 Con_Printf ("Saving game to %s...\n", name);
525 f = fopen (name, "w");
526 if (!f)
527 {
528 Con_Printf ("ERROR: couldn't open.\n");
529 return;
530 }
531
532 fprintf (f, "%i\n", SAVEGAME_VERSION);
533 Host_SavegameComment (comment);
534 fprintf (f, "%s\n", comment);
535 for (i=0 ; i<NUM_SPAWN_PARMS ; i++)
536 fprintf (f, "%f\n", svs.clients->spawn_parms[i]);
537 fprintf (f, "%d\n", current_skill);
538 fprintf (f, "%s\n", sv.name);
539 fprintf (f, "%f\n",sv.time);
540
541 // write the light styles
542
543 for (i=0 ; i<MAX_LIGHTSTYLES ; i++)
544 {
545 if (sv.lightstyles[i])
546 fprintf (f, "%s\n", sv.lightstyles[i]);
547 else
548 fprintf (f,"m\n");
549 }
550
551
552 ED_WriteGlobals (f);
553 for (i=0 ; i<sv.num_edicts ; i++)
554 {
555 ED_Write (f, EDICT_NUM(i));
556 fflush (f);
557 }
558 fclose (f);
559 Con_Printf ("done.\n");
560 }
561
562
563 /*
564 ===============
565 Host_Loadgame_f
566 ===============
567 */
Host_Loadgame_f(void)568 void Host_Loadgame_f (void)
569 {
570 char name[MAX_OSPATH];
571 FILE *f;
572 char mapname[MAX_QPATH];
573 float time, tfloat;
574 char str[32768], *start;
575 int i, r;
576 edict_t *ent;
577 int entnum;
578 int version;
579 float spawn_parms[NUM_SPAWN_PARMS];
580
581 if (cmd_source != src_command)
582 return;
583
584 if (Cmd_Argc() != 2)
585 {
586 Con_Printf ("load <savename> : load a game\n");
587 return;
588 }
589
590 cls.demonum = -1; // stop demo loop in case this fails
591
592 sprintf (name, "%s/%s", com_gamedir, Cmd_Argv(1));
593 COM_DefaultExtension (name, ".sav");
594
595 // we can't call SCR_BeginLoadingPlaque, because too much stack space has
596 // been used. The menu calls it before stuffing loadgame command
597 // SCR_BeginLoadingPlaque ();
598
599 Con_Printf ("Loading game from %s...\n", name);
600 f = fopen (name, "r");
601 if (!f)
602 {
603 Con_Printf ("ERROR: couldn't open.\n");
604 return;
605 }
606
607 fscanf (f, "%i\n", &version);
608 if (version != SAVEGAME_VERSION)
609 {
610 fclose (f);
611 Con_Printf ("Savegame is version %i, not %i\n", version, SAVEGAME_VERSION);
612 return;
613 }
614 fscanf (f, "%s\n", str);
615 for (i=0 ; i<NUM_SPAWN_PARMS ; i++)
616 fscanf (f, "%f\n", &spawn_parms[i]);
617 // this silliness is so we can load 1.06 save files, which have float skill values
618 fscanf (f, "%f\n", &tfloat);
619 current_skill = (int)(tfloat + 0.1);
620 Cvar_SetValue ("skill", (float)current_skill);
621
622 #ifdef QUAKE2
623 Cvar_SetValue ("deathmatch", 0);
624 Cvar_SetValue ("coop", 0);
625 Cvar_SetValue ("teamplay", 0);
626 #endif
627
628 fscanf (f, "%s\n",mapname);
629 fscanf (f, "%f\n",&time);
630
631 CL_Disconnect_f ();
632
633 #ifdef QUAKE2
634 SV_SpawnServer (mapname, NULL);
635 #else
636 SV_SpawnServer (mapname);
637 #endif
638 if (!sv.active)
639 {
640 Con_Printf ("Couldn't load map\n");
641 return;
642 }
643 sv.paused = true; // pause until all clients connect
644 sv.loadgame = true;
645
646 // load the light styles
647
648 for (i=0 ; i<MAX_LIGHTSTYLES ; i++)
649 {
650 fscanf (f, "%s\n", str);
651 sv.lightstyles[i] = (char*) Hunk_Alloc (strlen(str)+1);
652 strcpy (sv.lightstyles[i], str);
653 }
654
655 // load the edicts out of the savegame file
656 entnum = -1; // -1 is the globals
657 while (!feof(f))
658 {
659 for (i=0 ; i< (int) (sizeof(str)-1) ; i++)
660 {
661 r = fgetc (f);
662 if (r == EOF || !r)
663 break;
664 str[i] = r;
665 if (r == '}')
666 {
667 i++;
668 break;
669 }
670 }
671 if (i == sizeof(str)-1)
672 Sys_Error ("Loadgame buffer overflow");
673 str[i] = 0;
674 start = str;
675 start = COM_Parse(str);
676 if (!com_token[0])
677 break; // end of file
678 if (strcmp(com_token,"{"))
679 Sys_Error ("First token isn't a brace");
680
681 if (entnum == -1)
682 { // parse the global vars
683 ED_ParseGlobals (start);
684 }
685 else
686 { // parse an edict
687
688 ent = EDICT_NUM(entnum);
689 memset (&ent->u.v, 0, progs->entityfields * 4);
690 ent->free = false;
691 ED_ParseEdict (start, ent);
692
693 // link it into the bsp tree
694 if (!ent->free)
695 SV_LinkEdict (ent, false);
696 }
697
698 entnum++;
699 }
700
701 sv.num_edicts = entnum;
702 sv.time = time;
703
704 fclose (f);
705
706 for (i=0 ; i<NUM_SPAWN_PARMS ; i++)
707 svs.clients->spawn_parms[i] = spawn_parms[i];
708
709 if (cls.state != ca_dedicated)
710 {
711 CL_EstablishConnection ("local");
712 Host_Reconnect_f ();
713 }
714 }
715
716 #ifdef QUAKE2
SaveGamestate()717 void SaveGamestate()
718 {
719 char name[256];
720 FILE *f;
721 int i;
722 char comment[SAVEGAME_COMMENT_LENGTH+1];
723 edict_t *ent;
724
725 sprintf (name, "%s/%s.gip", com_gamedir, sv.name);
726
727 Con_Printf ("Saving game to %s...\n", name);
728 f = fopen (name, "w");
729 if (!f)
730 {
731 Con_Printf ("ERROR: couldn't open.\n");
732 return;
733 }
734
735 fprintf (f, "%i\n", SAVEGAME_VERSION);
736 Host_SavegameComment (comment);
737 fprintf (f, "%s\n", comment);
738 // for (i=0 ; i<NUM_SPAWN_PARMS ; i++)
739 // fprintf (f, "%f\n", svs.clients->spawn_parms[i]);
740 fprintf (f, "%f\n", skill.value);
741 fprintf (f, "%s\n", sv.name);
742 fprintf (f, "%f\n", sv.time);
743
744 // write the light styles
745
746 for (i=0 ; i<MAX_LIGHTSTYLES ; i++)
747 {
748 if (sv.lightstyles[i])
749 fprintf (f, "%s\n", sv.lightstyles[i]);
750 else
751 fprintf (f,"m\n");
752 }
753
754
755 for (i=svs.maxclients+1 ; i<sv.num_edicts ; i++)
756 {
757 ent = EDICT_NUM(i);
758 if ((int)ent->u.v.flags & FL_ARCHIVE_OVERRIDE)
759 continue;
760 fprintf (f, "%i\n",i);
761 ED_Write (f, ent);
762 fflush (f);
763 }
764 fclose (f);
765 Con_Printf ("done.\n");
766 }
767
LoadGamestate(char * level,char * startspot)768 int LoadGamestate(char *level, char *startspot)
769 {
770 char name[MAX_OSPATH];
771 FILE *f;
772 char mapname[MAX_QPATH];
773 float time, sk;
774 char str[32768], *start;
775 int i, r;
776 edict_t *ent;
777 int entnum;
778 int version;
779 // float spawn_parms[NUM_SPAWN_PARMS];
780
781 sprintf (name, "%s/%s.gip", com_gamedir, level);
782
783 Con_Printf ("Loading game from %s...\n", name);
784 f = fopen (name, "r");
785 if (!f)
786 {
787 Con_Printf ("ERROR: couldn't open.\n");
788 return -1;
789 }
790
791 fscanf (f, "%i\n", &version);
792 if (version != SAVEGAME_VERSION)
793 {
794 fclose (f);
795 Con_Printf ("Savegame is version %i, not %i\n", version, SAVEGAME_VERSION);
796 return -1;
797 }
798 fscanf (f, "%s\n", str);
799 // for (i=0 ; i<NUM_SPAWN_PARMS ; i++)
800 // fscanf (f, "%f\n", &spawn_parms[i]);
801 fscanf (f, "%f\n", &sk);
802 Cvar_SetValue ("skill", sk);
803
804 fscanf (f, "%s\n",mapname);
805 fscanf (f, "%f\n",&time);
806
807 SV_SpawnServer (mapname, startspot);
808
809 if (!sv.active)
810 {
811 Con_Printf ("Couldn't load map\n");
812 return -1;
813 }
814
815 // load the light styles
816 for (i=0 ; i<MAX_LIGHTSTYLES ; i++)
817 {
818 fscanf (f, "%s\n", str);
819 sv.lightstyles[i] = Hunk_Alloc (strlen(str)+1);
820 strcpy (sv.lightstyles[i], str);
821 }
822
823 // load the edicts out of the savegame file
824 while (!feof(f))
825 {
826 fscanf (f, "%i\n",&entnum);
827 for (i=0 ; i<sizeof(str)-1 ; i++)
828 {
829 r = fgetc (f);
830 if (r == EOF || !r)
831 break;
832 str[i] = r;
833 if (r == '}')
834 {
835 i++;
836 break;
837 }
838 }
839 if (i == sizeof(str)-1)
840 Sys_Error ("Loadgame buffer overflow");
841 str[i] = 0;
842 start = str;
843 start = COM_Parse(str);
844 if (!com_token[0])
845 break; // end of file
846 if (strcmp(com_token,"{"))
847 Sys_Error ("First token isn't a brace");
848
849 // parse an edict
850
851 ent = EDICT_NUM(entnum);
852 memset (&ent->v, 0, progs->entityfields * 4);
853 ent->free = false;
854 ED_ParseEdict (start, ent);
855
856 // link it into the bsp tree
857 if (!ent->free)
858 SV_LinkEdict (ent, false);
859 }
860
861 // sv.num_edicts = entnum;
862 sv.time = time;
863 fclose (f);
864
865 // for (i=0 ; i<NUM_SPAWN_PARMS ; i++)
866 // svs.clients->spawn_parms[i] = spawn_parms[i];
867
868 return 0;
869 }
870
871 // changing levels within a unit
Host_Changelevel2_f(void)872 void Host_Changelevel2_f (void)
873 {
874 char level[MAX_QPATH];
875 char _startspot[MAX_QPATH];
876 char *startspot;
877
878 if (Cmd_Argc() < 2)
879 {
880 Con_Printf ("changelevel2 <levelname> : continue game on a new level in the unit\n");
881 return;
882 }
883 if (!sv.active || cls.demoplayback)
884 {
885 Con_Printf ("Only the server may changelevel\n");
886 return;
887 }
888
889 strcpy (level, Cmd_Argv(1));
890 if (Cmd_Argc() == 2)
891 startspot = NULL;
892 else
893 {
894 strcpy (_startspot, Cmd_Argv(2));
895 startspot = _startspot;
896 }
897
898 SV_SaveSpawnparms ();
899
900 // save the current level's state
901 SaveGamestate ();
902
903 // try to restore the new level
904 if (LoadGamestate (level, startspot))
905 SV_SpawnServer (level, startspot);
906 }
907 #endif
908
909
910 //============================================================================
911
912 /*
913 ======================
914 Host_Name_f
915 ======================
916 */
Host_Name_f(void)917 void Host_Name_f (void)
918 {
919 char *newName;
920
921 if (Cmd_Argc () == 1)
922 {
923 Con_Printf ("\"name\" is \"%s\"\n", cl_name.string);
924 return;
925 }
926 if (Cmd_Argc () == 2)
927 newName = Cmd_Argv(1);
928 else
929 newName = Cmd_Args();
930 newName[15] = 0;
931
932 if (cmd_source == src_command)
933 {
934 if (Q_strcmp(cl_name.string, newName) == 0)
935 return;
936 Cvar_Set ("_cl_name", newName);
937 if (cls.state == ca_connected)
938 Cmd_ForwardToServer ();
939 return;
940 }
941
942 if (host_client->name[0] && strcmp(host_client->name, "unconnected") )
943 if (Q_strcmp(host_client->name, newName) != 0)
944 Con_Printf ("%s renamed to %s\n", host_client->name, newName);
945 Q_strcpy (host_client->name, newName);
946 host_client->edict->u.v.netname = host_client->name - pr_strings;
947
948 // send notification to all clients
949
950 MSG_WriteByte (&sv.reliable_datagram, svc_updatename);
951 MSG_WriteByte (&sv.reliable_datagram, host_client - svs.clients);
952 MSG_WriteString (&sv.reliable_datagram, host_client->name);
953 }
954
955
Host_Version_f(void)956 void Host_Version_f (void)
957 {
958 Con_Printf ("Version %4.2f\n", VERSION);
959 Con_Printf ("Exe: " __TIME__ " " __DATE__ "\n");
960 }
961
962 #ifdef IDGODS
Host_Please_f(void)963 void Host_Please_f (void)
964 {
965 client_t *cl;
966 int j;
967
968 if (cmd_source != src_command)
969 return;
970
971 if ((Cmd_Argc () == 3) && Q_strcmp(Cmd_Argv(1), "#") == 0)
972 {
973 j = Q_atof(Cmd_Argv(2)) - 1;
974 if (j < 0 || j >= svs.maxclients)
975 return;
976 if (!svs.clients[j].active)
977 return;
978 cl = &svs.clients[j];
979 if (cl->privileged)
980 {
981 cl->privileged = false;
982 cl->edict->u.v.flags = (int)cl->edict->u.v.flags & ~(FL_GODMODE|FL_NOTARGET);
983 cl->edict->u.v.movetype = MOVETYPE_WALK;
984 noclip_anglehack = false;
985 }
986 else
987 cl->privileged = true;
988 }
989
990 if (Cmd_Argc () != 2)
991 return;
992
993 for (j=0, cl = svs.clients ; j<svs.maxclients ; j++, cl++)
994 {
995 if (!cl->active)
996 continue;
997 if (Q_strcasecmp(cl->name, Cmd_Argv(1)) == 0)
998 {
999 if (cl->privileged)
1000 {
1001 cl->privileged = false;
1002 cl->edict->u.v.flags = (int)cl->edict->u.v.flags & ~(FL_GODMODE|FL_NOTARGET);
1003 cl->edict->u.v.movetype = MOVETYPE_WALK;
1004 noclip_anglehack = false;
1005 }
1006 else
1007 cl->privileged = true;
1008 break;
1009 }
1010 }
1011 }
1012 #endif
1013
1014
Host_Say(qboolean teamonly)1015 void Host_Say(qboolean teamonly)
1016 {
1017 client_t *client;
1018 client_t *save;
1019 int j;
1020 char *p;
1021 unsigned char text[64];
1022 qboolean fromServer = false;
1023
1024 if (cmd_source == src_command)
1025 {
1026 if (cls.state == ca_dedicated)
1027 {
1028 fromServer = true;
1029 teamonly = false;
1030 }
1031 else
1032 {
1033 Cmd_ForwardToServer ();
1034 return;
1035 }
1036 }
1037
1038 if (Cmd_Argc () < 2)
1039 return;
1040
1041 save = host_client;
1042
1043 p = Cmd_Args();
1044 // remove quotes if present
1045 if (*p == '"')
1046 {
1047 p++;
1048 p[Q_strlen(p)-1] = 0;
1049 }
1050
1051 // turn on color set 1
1052 if (!fromServer)
1053 sprintf ((char*) text, "%c%s: ", 1, save->name);
1054 else
1055 sprintf ((char*) text, "%c<%s> ", 1, hostname.string);
1056
1057 j = sizeof(text) - 2 - Q_strlen((char*) text); // -2 for /n and null terminator
1058 if (Q_strlen((char*) p) > j)
1059 p[j] = 0;
1060
1061 strcat ((char*) text, p);
1062 strcat ((char*) text, "\n");
1063
1064 for (j = 0, client = svs.clients; j < svs.maxclients; j++, client++)
1065 {
1066 if (!client || !client->active || !client->spawned)
1067 continue;
1068 if (teamplay.value && teamonly && client->edict->u.v.team != save->edict->u.v.team)
1069 continue;
1070 host_client = client;
1071 SV_ClientPrintf("%s", text);
1072 }
1073 host_client = save;
1074
1075 Sys_Printf("%s", &text[1]);
1076 }
1077
1078
Host_Say_f(void)1079 void Host_Say_f(void)
1080 {
1081 Host_Say(false);
1082 }
1083
1084
Host_Say_Team_f(void)1085 void Host_Say_Team_f(void)
1086 {
1087 Host_Say(true);
1088 }
1089
1090
Host_Tell_f(void)1091 void Host_Tell_f(void)
1092 {
1093 client_t *client;
1094 client_t *save;
1095 int j;
1096 char *p;
1097 char text[64];
1098
1099 if (cmd_source == src_command)
1100 {
1101 Cmd_ForwardToServer ();
1102 return;
1103 }
1104
1105 if (Cmd_Argc () < 3)
1106 return;
1107
1108 Q_strcpy(text, host_client->name);
1109 Q_strcat(text, ": ");
1110
1111 p = Cmd_Args();
1112
1113 // remove quotes if present
1114 if (*p == '"')
1115 {
1116 p++;
1117 p[Q_strlen(p)-1] = 0;
1118 }
1119
1120 // check length & truncate if necessary
1121 j = sizeof(text) - 2 - Q_strlen(text); // -2 for /n and null terminator
1122 if (Q_strlen(p) > j)
1123 p[j] = 0;
1124
1125 strcat (text, p);
1126 strcat (text, "\n");
1127
1128 save = host_client;
1129 for (j = 0, client = svs.clients; j < svs.maxclients; j++, client++)
1130 {
1131 if (!client->active || !client->spawned)
1132 continue;
1133 if (Q_strcasecmp(client->name, Cmd_Argv(1)))
1134 continue;
1135 host_client = client;
1136 SV_ClientPrintf("%s", text);
1137 break;
1138 }
1139 host_client = save;
1140 }
1141
1142
1143 /*
1144 ==================
1145 Host_Color_f
1146 ==================
1147 */
Host_Color_f(void)1148 void Host_Color_f(void)
1149 {
1150 int top, bottom;
1151 int playercolor;
1152
1153 if (Cmd_Argc() == 1)
1154 {
1155 Con_Printf ("\"color\" is \"%i %i\"\n", ((int)cl_color.value) >> 4, ((int)cl_color.value) & 0x0f);
1156 Con_Printf ("color <0-13> [0-13]\n");
1157 return;
1158 }
1159
1160 if (Cmd_Argc() == 2)
1161 top = bottom = atoi(Cmd_Argv(1));
1162 else
1163 {
1164 top = atoi(Cmd_Argv(1));
1165 bottom = atoi(Cmd_Argv(2));
1166 }
1167
1168 top &= 15;
1169 if (top > 13)
1170 top = 13;
1171 bottom &= 15;
1172 if (bottom > 13)
1173 bottom = 13;
1174
1175 playercolor = top*16 + bottom;
1176
1177 if (cmd_source == src_command)
1178 {
1179 Cvar_SetValue ("_cl_color", playercolor);
1180 if (cls.state == ca_connected)
1181 Cmd_ForwardToServer ();
1182 return;
1183 }
1184
1185 host_client->colors = playercolor;
1186 host_client->edict->u.v.team = bottom + 1;
1187
1188 // send notification to all clients
1189 MSG_WriteByte (&sv.reliable_datagram, svc_updatecolors);
1190 MSG_WriteByte (&sv.reliable_datagram, host_client - svs.clients);
1191 MSG_WriteByte (&sv.reliable_datagram, host_client->colors);
1192 }
1193
1194 /*
1195 ==================
1196 Host_Kill_f
1197 ==================
1198 */
Host_Kill_f(void)1199 void Host_Kill_f (void)
1200 {
1201 if (cmd_source == src_command)
1202 {
1203 Cmd_ForwardToServer ();
1204 return;
1205 }
1206
1207 if (sv_player->u.v.health <= 0)
1208 {
1209 SV_ClientPrintf ("Can't suicide -- allready dead!\n");
1210 return;
1211 }
1212
1213 pr_global_struct->time = sv.time;
1214 pr_global_struct->self = EDICT_TO_PROG(sv_player);
1215 PR_ExecuteProgram (pr_global_struct->ClientKill);
1216 }
1217
1218
1219 /*
1220 ==================
1221 Host_Pause_f
1222 ==================
1223 */
Host_Pause_f(void)1224 void Host_Pause_f (void)
1225 {
1226
1227 if (cmd_source == src_command)
1228 {
1229 Cmd_ForwardToServer ();
1230 return;
1231 }
1232 if (!pausable.value)
1233 SV_ClientPrintf ("Pause not allowed.\n");
1234 else
1235 {
1236 sv.paused ^= 1;
1237
1238 if (sv.paused)
1239 {
1240 SV_BroadcastPrintf ("%s paused the game\n", pr_strings + sv_player->u.v.netname);
1241 }
1242 else
1243 {
1244 SV_BroadcastPrintf ("%s unpaused the game\n",pr_strings + sv_player->u.v.netname);
1245 }
1246
1247 // send notification to all clients
1248 MSG_WriteByte (&sv.reliable_datagram, svc_setpause);
1249 MSG_WriteByte (&sv.reliable_datagram, sv.paused);
1250 }
1251 }
1252
1253 //===========================================================================
1254
1255
1256 /*
1257 ==================
1258 Host_PreSpawn_f
1259 ==================
1260 */
Host_PreSpawn_f(void)1261 void Host_PreSpawn_f (void)
1262 {
1263 if (cmd_source == src_command)
1264 {
1265 Con_Printf ("prespawn is not valid from the console\n");
1266 return;
1267 }
1268
1269 if (host_client->spawned)
1270 {
1271 Con_Printf ("prespawn not valid -- allready spawned\n");
1272 return;
1273 }
1274
1275 SZ_Write (&host_client->message, sv.signon.data, sv.signon.cursize);
1276 MSG_WriteByte (&host_client->message, svc_signonnum);
1277 MSG_WriteByte (&host_client->message, 2);
1278 host_client->sendsignon = true;
1279 }
1280
1281 /*
1282 ==================
1283 Host_Spawn_f
1284 ==================
1285 */
Host_Spawn_f(void)1286 void Host_Spawn_f (void)
1287 {
1288 int i;
1289 client_t *client;
1290 edict_t *ent;
1291
1292 if (cmd_source == src_command)
1293 {
1294 Con_Printf ("spawn is not valid from the console\n");
1295 return;
1296 }
1297
1298 if (host_client->spawned)
1299 {
1300 Con_Printf ("Spawn not valid -- allready spawned\n");
1301 return;
1302 }
1303
1304 // run the entrance script
1305 if (sv.loadgame)
1306 { // loaded games are fully inited allready
1307 // if this is the last client to be connected, unpause
1308 sv.paused = false;
1309 }
1310 else
1311 {
1312 // set up the edict
1313 ent = host_client->edict;
1314
1315 memset (&ent->u.v, 0, progs->entityfields * 4);
1316 ent->u.v.colormap = NUM_FOR_EDICT(ent);
1317 ent->u.v.team = (host_client->colors & 15) + 1;
1318 ent->u.v.netname = host_client->name - pr_strings;
1319
1320 // copy spawn parms out of the client_t
1321
1322 for (i=0 ; i< NUM_SPAWN_PARMS ; i++)
1323 (&pr_global_struct->parm1)[i] = host_client->spawn_parms[i];
1324
1325 // call the spawn function
1326
1327 pr_global_struct->time = sv.time;
1328 pr_global_struct->self = EDICT_TO_PROG(sv_player);
1329 PR_ExecuteProgram (pr_global_struct->ClientConnect);
1330
1331 if ((Sys_FloatTime() - host_client->netconnection->connecttime) <= sv.time)
1332 Sys_Printf ("%s entered the game\n", host_client->name);
1333
1334 PR_ExecuteProgram (pr_global_struct->PutClientInServer);
1335 }
1336
1337
1338 // send all current names, colors, and frag counts
1339 SZ_Clear (&host_client->message);
1340
1341 // send time of update
1342 MSG_WriteByte (&host_client->message, svc_time);
1343 MSG_WriteFloat (&host_client->message, sv.time);
1344
1345 for (i=0, client = svs.clients ; i<svs.maxclients ; i++, client++)
1346 {
1347 MSG_WriteByte (&host_client->message, svc_updatename);
1348 MSG_WriteByte (&host_client->message, i);
1349 MSG_WriteString (&host_client->message, client->name);
1350 MSG_WriteByte (&host_client->message, svc_updatefrags);
1351 MSG_WriteByte (&host_client->message, i);
1352 MSG_WriteShort (&host_client->message, client->old_frags);
1353 MSG_WriteByte (&host_client->message, svc_updatecolors);
1354 MSG_WriteByte (&host_client->message, i);
1355 MSG_WriteByte (&host_client->message, client->colors);
1356 }
1357
1358 // send all current light styles
1359 for (i=0 ; i<MAX_LIGHTSTYLES ; i++)
1360 {
1361 MSG_WriteByte (&host_client->message, svc_lightstyle);
1362 MSG_WriteByte (&host_client->message, (char)i);
1363 MSG_WriteString (&host_client->message, sv.lightstyles[i]);
1364 }
1365
1366 //
1367 // send some stats
1368 //
1369 MSG_WriteByte (&host_client->message, svc_updatestat);
1370 MSG_WriteByte (&host_client->message, STAT_TOTALSECRETS);
1371 MSG_WriteLong (&host_client->message, (int) pr_global_struct->total_secrets);
1372
1373 MSG_WriteByte (&host_client->message, svc_updatestat);
1374 MSG_WriteByte (&host_client->message, STAT_TOTALMONSTERS);
1375 MSG_WriteLong (&host_client->message, (int) pr_global_struct->total_monsters);
1376
1377 MSG_WriteByte (&host_client->message, svc_updatestat);
1378 MSG_WriteByte (&host_client->message, STAT_SECRETS);
1379 MSG_WriteLong (&host_client->message, (int) pr_global_struct->found_secrets);
1380
1381 MSG_WriteByte (&host_client->message, svc_updatestat);
1382 MSG_WriteByte (&host_client->message, STAT_MONSTERS);
1383 MSG_WriteLong (&host_client->message, (int) pr_global_struct->killed_monsters);
1384
1385
1386 //
1387 // send a fixangle
1388 // Never send a roll angle, because savegames can catch the server
1389 // in a state where it is expecting the client to correct the angle
1390 // and it won't happen if the game was just loaded, so you wind up
1391 // with a permanent head tilt
1392 ent = EDICT_NUM( 1 + (host_client - svs.clients) );
1393 MSG_WriteByte (&host_client->message, svc_setangle);
1394 for (i=0 ; i < 2 ; i++)
1395 MSG_WriteAngle (&host_client->message, ent->u.v.angles[i] );
1396 MSG_WriteAngle (&host_client->message, 0 );
1397
1398 SV_WriteClientdataToMessage (sv_player, &host_client->message);
1399
1400 MSG_WriteByte (&host_client->message, svc_signonnum);
1401 MSG_WriteByte (&host_client->message, 3);
1402 host_client->sendsignon = true;
1403 }
1404
1405 /*
1406 ==================
1407 Host_Begin_f
1408 ==================
1409 */
Host_Begin_f(void)1410 void Host_Begin_f (void)
1411 {
1412 if (cmd_source == src_command)
1413 {
1414 Con_Printf ("begin is not valid from the console\n");
1415 return;
1416 }
1417
1418 host_client->spawned = true;
1419 }
1420
1421 //===========================================================================
1422
1423
1424 /*
1425 ==================
1426 Host_Kick_f
1427
1428 Kicks a user off of the server
1429 ==================
1430 */
Host_Kick_f(void)1431 void Host_Kick_f (void)
1432 {
1433 const char *who;
1434 const char *message = NULL;
1435 client_t *save;
1436 int i;
1437 qboolean byNumber = false;
1438
1439 if (cmd_source == src_command)
1440 {
1441 if (!sv.active)
1442 {
1443 Cmd_ForwardToServer ();
1444 return;
1445 }
1446 }
1447 else if (pr_global_struct->deathmatch && !host_client->privileged)
1448 return;
1449
1450 save = host_client;
1451
1452 if (Cmd_Argc() > 2 && Q_strcmp(Cmd_Argv(1), "#") == 0)
1453 {
1454 i = (int) Q_atof(Cmd_Argv(2)) - 1;
1455 if (i < 0 || i >= svs.maxclients)
1456 return;
1457 if (!svs.clients[i].active)
1458 return;
1459 host_client = &svs.clients[i];
1460 byNumber = true;
1461 }
1462 else
1463 {
1464 for (i = 0, host_client = svs.clients; i < svs.maxclients; i++, host_client++)
1465 {
1466 if (!host_client->active)
1467 continue;
1468 if (Q_strcasecmp(host_client->name, Cmd_Argv(1)) == 0)
1469 break;
1470 }
1471 }
1472
1473 if (i < svs.maxclients)
1474 {
1475 if (cmd_source == src_command)
1476 if (cls.state == ca_dedicated)
1477 who = "Console";
1478 else
1479 who = cl_name.string;
1480 else
1481 who = save->name;
1482
1483 // can't kick yourself!
1484 if (host_client == save)
1485 return;
1486
1487 if (Cmd_Argc() > 2)
1488 {
1489 message = COM_Parse(Cmd_Args());
1490 if (byNumber)
1491 {
1492 message++; // skip the #
1493 while (*message == ' ') // skip white space
1494 message++;
1495 message += Q_strlen(Cmd_Argv(2)); // skip the number
1496 }
1497 while (*message && *message == ' ')
1498 message++;
1499 }
1500 if (message)
1501 SV_ClientPrintf ("Kicked by %s: %s\n", who, message);
1502 else
1503 SV_ClientPrintf ("Kicked by %s\n", who);
1504 SV_DropClient (false);
1505 }
1506
1507 host_client = save;
1508 }
1509
1510 /*
1511 ===============================================================================
1512
1513 DEBUGGING TOOLS
1514
1515 ===============================================================================
1516 */
1517
1518 /*
1519 ==================
1520 Host_Give_f
1521 ==================
1522 */
Host_Give_f(void)1523 void Host_Give_f (void)
1524 {
1525 char *t;
1526 int v, w;
1527 eval_t *val;
1528
1529 if (cmd_source == src_command)
1530 {
1531 Cmd_ForwardToServer ();
1532 return;
1533 }
1534
1535 if (pr_global_struct->deathmatch && !host_client->privileged)
1536 return;
1537
1538 t = Cmd_Argv(1);
1539 v = atoi (Cmd_Argv(2));
1540
1541 switch (t[0])
1542 {
1543 case '0':
1544 case '1':
1545 case '2':
1546 case '3':
1547 case '4':
1548 case '5':
1549 case '6':
1550 case '7':
1551 case '8':
1552 case '9':
1553 // MED 01/04/97 added hipnotic give stuff
1554 if (hipnotic)
1555 {
1556 if (t[0] == '6')
1557 {
1558 if (t[1] == 'a')
1559 sv_player->u.v.items = (int)sv_player->u.v.items | HIT_PROXIMITY_GUN;
1560 else
1561 sv_player->u.v.items = (int)sv_player->u.v.items | IT_GRENADE_LAUNCHER;
1562 }
1563 else if (t[0] == '9')
1564 sv_player->u.v.items = (int)sv_player->u.v.items | HIT_LASER_CANNON;
1565 else if (t[0] == '0')
1566 sv_player->u.v.items = (int)sv_player->u.v.items | HIT_MJOLNIR;
1567 else if (t[0] >= '2')
1568 sv_player->u.v.items = (int)sv_player->u.v.items | (IT_SHOTGUN << (t[0] - '2'));
1569 }
1570 else
1571 {
1572 if (t[0] >= '2')
1573 sv_player->u.v.items = (int)sv_player->u.v.items | (IT_SHOTGUN << (t[0] - '2'));
1574 }
1575 break;
1576
1577 case 's':
1578 if (rogue)
1579 {
1580 val = GetEdictFieldValue(sv_player, "ammo_shells1");
1581 if (val)
1582 val->_float = v;
1583 }
1584
1585 sv_player->u.v.ammo_shells = v;
1586 break;
1587 case 'n':
1588 if (rogue)
1589 {
1590 val = GetEdictFieldValue(sv_player, "ammo_nails1");
1591 if (val)
1592 {
1593 val->_float = v;
1594 if (sv_player->u.v.weapon <= IT_LIGHTNING)
1595 sv_player->u.v.ammo_nails = v;
1596 }
1597 }
1598 else
1599 {
1600 sv_player->u.v.ammo_nails = v;
1601 }
1602 break;
1603 case 'l':
1604 if (rogue)
1605 {
1606 val = GetEdictFieldValue(sv_player, "ammo_lava_nails");
1607 if (val)
1608 {
1609 val->_float = v;
1610 if (sv_player->u.v.weapon > IT_LIGHTNING)
1611 sv_player->u.v.ammo_nails = v;
1612 }
1613 }
1614 break;
1615 case 'r':
1616 if (rogue)
1617 {
1618 val = GetEdictFieldValue(sv_player, "ammo_rockets1");
1619 if (val)
1620 {
1621 val->_float = v;
1622 if (sv_player->u.v.weapon <= IT_LIGHTNING)
1623 sv_player->u.v.ammo_rockets = v;
1624 }
1625 }
1626 else
1627 {
1628 sv_player->u.v.ammo_rockets = v;
1629 }
1630 break;
1631 case 'm':
1632 if (rogue)
1633 {
1634 val = GetEdictFieldValue(sv_player, "ammo_multi_rockets");
1635 if (val)
1636 {
1637 val->_float = v;
1638 if (sv_player->u.v.weapon > IT_LIGHTNING)
1639 sv_player->u.v.ammo_rockets = v;
1640 }
1641 }
1642 break;
1643 case 'h':
1644 sv_player->u.v.health = v;
1645 break;
1646 case 'c':
1647 if (rogue)
1648 {
1649 val = GetEdictFieldValue(sv_player, "ammo_cells1");
1650 if (val)
1651 {
1652 val->_float = v;
1653 if (sv_player->u.v.weapon <= IT_LIGHTNING)
1654 sv_player->u.v.ammo_cells = v;
1655 }
1656 }
1657 else
1658 {
1659 sv_player->u.v.ammo_cells = v;
1660 }
1661 break;
1662 case 'p':
1663 if (rogue)
1664 {
1665 val = GetEdictFieldValue(sv_player, "ammo_plasma");
1666 if (val)
1667 {
1668 val->_float = v;
1669 if (sv_player->u.v.weapon > IT_LIGHTNING)
1670 sv_player->u.v.ammo_cells = v;
1671 }
1672 }
1673 break;
1674 }
1675 }
1676
FindViewthing(void)1677 edict_t *FindViewthing (void)
1678 {
1679 int i;
1680 edict_t *e;
1681
1682 for (i=0 ; i<sv.num_edicts ; i++)
1683 {
1684 e = EDICT_NUM(i);
1685 if ( !strcmp (pr_strings + e->u.v.classname, "viewthing") )
1686 return e;
1687 }
1688 Con_Printf ("No viewthing on map\n");
1689 return NULL;
1690 }
1691
1692 /*
1693 ==================
1694 Host_Viewmodel_f
1695 ==================
1696 */
Host_Viewmodel_f(void)1697 void Host_Viewmodel_f (void)
1698 {
1699 edict_t *e;
1700 model_t *m;
1701
1702 e = FindViewthing ();
1703 if (!e)
1704 return;
1705
1706 m = Mod_ForName (Cmd_Argv(1), false);
1707 if (!m)
1708 {
1709 Con_Printf ("Can't load %s\n", Cmd_Argv(1));
1710 return;
1711 }
1712
1713 e->u.v.frame = 0;
1714 cl.model_precache[(int)e->u.v.modelindex] = m;
1715 }
1716
1717 /*
1718 ==================
1719 Host_Viewframe_f
1720 ==================
1721 */
Host_Viewframe_f(void)1722 void Host_Viewframe_f (void)
1723 {
1724 edict_t *e;
1725 int f;
1726 model_t *m;
1727
1728 e = FindViewthing ();
1729 if (!e)
1730 return;
1731 m = cl.model_precache[(int)e->u.v.modelindex];
1732
1733 f = atoi(Cmd_Argv(1));
1734 if (f >= m->numframes)
1735 f = m->numframes-1;
1736
1737 e->u.v.frame = f;
1738 }
1739
1740
PrintFrameName(model_t * m,int frame)1741 void PrintFrameName (model_t *m, int frame)
1742 {
1743 aliashdr_t *hdr;
1744 maliasframedesc_t *pframedesc;
1745
1746 hdr = (aliashdr_t *)Mod_Extradata (m);
1747 if (!hdr)
1748 return;
1749 pframedesc = &hdr->frames[frame];
1750
1751 Con_Printf ("frame %i: %s\n", frame, pframedesc->name);
1752 }
1753
1754 /*
1755 ==================
1756 Host_Viewnext_f
1757 ==================
1758 */
Host_Viewnext_f(void)1759 void Host_Viewnext_f (void)
1760 {
1761 edict_t *e;
1762 model_t *m;
1763
1764 e = FindViewthing ();
1765 if (!e)
1766 return;
1767 m = cl.model_precache[(int)e->u.v.modelindex];
1768
1769 e->u.v.frame = e->u.v.frame + 1;
1770 if (e->u.v.frame >= m->numframes)
1771 e->u.v.frame = m->numframes - 1;
1772
1773 PrintFrameName (m, (int) e->u.v.frame);
1774 }
1775
1776 /*
1777 ==================
1778 Host_Viewprev_f
1779 ==================
1780 */
Host_Viewprev_f(void)1781 void Host_Viewprev_f (void)
1782 {
1783 edict_t *e;
1784 model_t *m;
1785
1786 e = FindViewthing ();
1787 if (!e)
1788 return;
1789
1790 m = cl.model_precache[(int)e->u.v.modelindex];
1791
1792 e->u.v.frame = e->u.v.frame - 1;
1793 if (e->u.v.frame < 0)
1794 e->u.v.frame = 0;
1795
1796 PrintFrameName (m, (int) e->u.v.frame);
1797 }
1798
1799 /*
1800 ===============================================================================
1801
1802 DEMO LOOP CONTROL
1803
1804 ===============================================================================
1805 */
1806
1807
1808 /*
1809 ==================
1810 Host_Startdemos_f
1811 ==================
1812 */
Host_Startdemos_f(void)1813 void Host_Startdemos_f (void)
1814 {
1815 int i, c;
1816
1817 if (cls.state == ca_dedicated)
1818 {
1819 if (!sv.active)
1820 Cbuf_AddText ("map start\n");
1821 return;
1822 }
1823
1824 c = Cmd_Argc() - 1;
1825 if (c > MAX_DEMOS)
1826 {
1827 Con_Printf ("Max %i demos in demoloop\n", MAX_DEMOS);
1828 c = MAX_DEMOS;
1829 }
1830 Con_Printf ("%i demo(s) in loop\n", c);
1831
1832 for (i=1 ; i<c+1 ; i++)
1833 strncpy (cls.demos[i-1], Cmd_Argv(i), sizeof(cls.demos[0])-1);
1834
1835 if (!sv.active && cls.demonum != -1 && !cls.demoplayback)
1836 {
1837 cls.demonum = 0;
1838 CL_NextDemo ();
1839 }
1840 else
1841 cls.demonum = -1;
1842 }
1843
1844
1845 /*
1846 ==================
1847 Host_Demos_f
1848
1849 Return to looping demos
1850 ==================
1851 */
Host_Demos_f(void)1852 void Host_Demos_f (void)
1853 {
1854 if (cls.state == ca_dedicated)
1855 return;
1856 if (cls.demonum == -1)
1857 cls.demonum = 1;
1858 CL_Disconnect_f ();
1859 CL_NextDemo ();
1860 }
1861
1862 /*
1863 ==================
1864 Host_Stopdemo_f
1865
1866 Return to looping demos
1867 ==================
1868 */
Host_Stopdemo_f(void)1869 void Host_Stopdemo_f (void)
1870 {
1871 if (cls.state == ca_dedicated)
1872 return;
1873 if (!cls.demoplayback)
1874 return;
1875 CL_StopPlayback ();
1876 CL_Disconnect ();
1877 }
1878
1879 //=============================================================================
1880
1881 /*
1882 ==================
1883 Host_InitCommands
1884 ==================
1885 */
Host_InitCommands(void)1886 void Host_InitCommands (void)
1887 {
1888 Cmd_AddCommand ("status", Host_Status_f);
1889 Cmd_AddCommand ("quit", Host_Quit_f);
1890 Cmd_AddCommand ("god", Host_God_f);
1891 Cmd_AddCommand ("notarget", Host_Notarget_f);
1892 Cmd_AddCommand ("fly", Host_Fly_f);
1893 Cmd_AddCommand ("map", Host_Map_f);
1894 Cmd_AddCommand ("restart", Host_Restart_f);
1895 Cmd_AddCommand ("changelevel", Host_Changelevel_f);
1896 #ifdef QUAKE2
1897 Cmd_AddCommand ("changelevel2", Host_Changelevel2_f);
1898 #endif
1899 Cmd_AddCommand ("connect", Host_Connect_f);
1900 Cmd_AddCommand ("reconnect", Host_Reconnect_f);
1901 Cmd_AddCommand ("name", Host_Name_f);
1902 Cmd_AddCommand ("noclip", Host_Noclip_f);
1903 Cmd_AddCommand ("version", Host_Version_f);
1904 #ifdef IDGODS
1905 Cmd_AddCommand ("please", Host_Please_f);
1906 #endif
1907 Cmd_AddCommand ("say", Host_Say_f);
1908 Cmd_AddCommand ("say_team", Host_Say_Team_f);
1909 Cmd_AddCommand ("tell", Host_Tell_f);
1910 Cmd_AddCommand ("color", Host_Color_f);
1911 Cmd_AddCommand ("kill", Host_Kill_f);
1912 Cmd_AddCommand ("pause", Host_Pause_f);
1913 Cmd_AddCommand ("spawn", Host_Spawn_f);
1914 Cmd_AddCommand ("begin", Host_Begin_f);
1915 Cmd_AddCommand ("prespawn", Host_PreSpawn_f);
1916 Cmd_AddCommand ("kick", Host_Kick_f);
1917 Cmd_AddCommand ("ping", Host_Ping_f);
1918 Cmd_AddCommand ("load", Host_Loadgame_f);
1919 Cmd_AddCommand ("save", Host_Savegame_f);
1920 Cmd_AddCommand ("give", Host_Give_f);
1921
1922 Cmd_AddCommand ("startdemos", Host_Startdemos_f);
1923 Cmd_AddCommand ("demos", Host_Demos_f);
1924 Cmd_AddCommand ("stopdemo", Host_Stopdemo_f);
1925
1926 Cmd_AddCommand ("viewmodel", Host_Viewmodel_f);
1927 Cmd_AddCommand ("viewframe", Host_Viewframe_f);
1928 Cmd_AddCommand ("viewnext", Host_Viewnext_f);
1929 Cmd_AddCommand ("viewprev", Host_Viewprev_f);
1930
1931 Cmd_AddCommand ("mcache", Mod_Print);
1932 }
1933