]> icculus.org git repositories - taylor/freespace2.git/blob - src/network/multilag.cpp
Initial revision
[taylor/freespace2.git] / src / network / multilag.cpp
1 /*
2  * $Logfile: /Freespace2/code/Network/multilag.cpp $
3  * $Revision$
4  * $Date$
5  * $Author$
6  *
7  * $Log$
8  * Revision 1.1  2002/05/03 03:28:10  root
9  * Initial revision
10  *
11  * 
12  * 4     11/19/98 8:03a Dave
13  * Full support for D3-style reliable sockets. Revamped packet lag/loss
14  * system, made it receiver side and at the lowest possible level.
15  * 
16  * 3     11/17/98 11:12a Dave
17  * Removed player identification by address. Now assign explicit id #'s.
18  * 
19  * 2     10/07/98 10:53a Dave
20  * Initial checkin.
21  * 
22  * 1     10/07/98 10:50a Dave
23  * 
24  * 15    6/05/98 9:54a Lawrance
25  * OEM changes
26  * 
27  * 14    4/27/98 6:02p Dave
28  * Modify how missile scoring works. Fixed a team select ui bug. Speed up
29  * multi_lag system. Put in new main hall.
30  * 
31  * 13    4/18/98 5:00p Dave
32  * Put in observer zoom key. Made mission sync screen more informative.
33  * 
34  * 12    4/06/98 12:37a Lawrance
35  * fix compile bug with demo
36  * 
37  * 11    4/04/98 8:42p Dave
38  * Tested and debugged UDP reliable socket layer. Modified lag system to
39  * take this into account. 
40  * 
41  * 10    4/02/98 6:29p Lawrance
42  * compile out multilag code for demo
43  * 
44  * 9     3/14/98 2:48p Dave
45  * Cleaned up observer joining code. Put in support for file xfers to
46  * ingame joiners (observers or not). Revamped and reinstalled pseudo
47  * lag/loss system.
48  * 
49  * 8     1/11/98 10:03p Allender
50  * removed <winsock.h> from headers which included it.  Made psnet_socket
51  * type which is defined just as SOCKET type is.
52  * 
53  * 7     12/29/97 5:21p Dave
54  * Put in object update sequencing for multiplayer.
55  * 
56  * 6     12/16/97 6:17p Dave
57  * Put in primary weapon support for multiplayer weapon select screen.
58  * 
59  * 5     12/10/97 4:45p Dave
60  * Added in more detailed support for multiplayer packet lag/loss. Fixed
61  * some multiplayer stuff. Added some controls to the standalone.
62  * 
63  * 4     12/01/97 4:59p Dave
64  * Synchronized multiplayer debris objects. Put in pilot popup in main
65  * hall. Optimized simulated multiplayer lag module. Fixed a potential
66  * file_xfer bug.
67  * 
68  * 3     11/28/97 7:04p Dave
69  * Emergency checkin due to big system crash.
70  * 
71  * 2     11/28/97 5:06p Dave
72  * Put in facilities for simulating multiplayer lag.
73  * 
74  * 1     11/28/97 4:38p Dave
75  * Initial Revision
76  * 
77  * $NoKeywords: $
78  */
79
80 #include <winsock.h>
81 #include <wsipx.h>
82 #include "pstypes.h"
83 #include "multi.h"
84 #include "multilag.h"
85 #include "cmdline.h"
86 #include "timer.h"
87 #include "linklist.h"
88
89 // ----------------------------------------------------------------------------------------------------
90 // LAGLOSS DEFINES/VARS
91 //
92
93 // default LAGLOSS values
94 #define MULTI_LAGLOSS_DEF_LAG                           (-1)
95 #define MULTI_LAGLOSS_DEF_LAGMIN                        (-1)
96 #define MULTI_LAGLOSS_DEF_LAGMAX                        (-1)
97 #define MULTI_LAGLOSS_DEF_LOSS                  (-1.0f)
98 #define MULTI_LAGLOSS_DEF_LOSSMIN               (-1.0f)
99 #define MULTI_LAGLOSS_DEF_LOSSMAX               (-1.0f)
100 #define MULTI_LAGLOSS_DEF_STREAK                        (2500)
101
102 // if we're running
103 int Multi_lag_inited = 0;
104
105 // lag values (base - max and min)
106 int Multi_lag_base = -1;
107 int Multi_lag_min = -1;
108 int Multi_lag_max = -1;
109
110 // packet loss values (base - max and min)
111 float Multi_loss_base = -1.0f;
112 float Multi_loss_min = -1.0f;
113 float Multi_loss_max = -1.0f;
114
115 // streaks for lagging
116 int Multi_streak_stamp = -1;                            // timestamp telling when the streak of a certain lag is done
117 int Multi_streak_time = 0;                                      // how long each streak will last
118 int Multi_current_streak = -1;                  // what lag the current streak has
119
120 // struct for buffering stuff on receives
121 typedef struct lag_buf {
122         ubyte data[700];                                                        // the data from the packet
123         int data_len;                                                           // length of the data
124         uint socket;                                                            // this can be either a PSNET_SOCKET or a PSNET_SOCKET_RELIABLE
125         int stamp;                                                                      // when this expires, make this packet available        
126         SOCKADDR_IN ip_addr;                                            // ip address when in TCP
127         SOCKADDR_IPX ipx_addr;                                  // ipx address when in IPX mode
128
129         struct  lag_buf * prev;                         // prev in the list
130         struct  lag_buf * next;                         // next in the list
131 } lag_buf;
132
133 // lag buffers - malloced
134 #ifdef NDEBUG
135         #define MAX_LAG_BUFFERS                 1               // only 1 buffer in non-debug builds
136 #else
137         #define MAX_LAG_BUFFERS                 1000
138 #endif
139 lag_buf *Lag_buffers[MAX_LAG_BUFFERS];
140 int Lag_buf_count = 0;                                          // how many lag_buf's are currently in use
141
142 lag_buf Lag_free_list;
143 lag_buf Lag_used_list;
144
145
146 // ----------------------------------------------------------------------------------------------------
147 // LAGLOSS FORWARD DECLARATIONS
148 //
149
150 // get a value to lag a packet with (in ms)
151 int multi_lag_get_random_lag();
152
153 // boolean yes or no - should this packet be lost?
154 int multi_lag_should_be_lost();             
155
156 // get a free packet buffer, return NULL on fail
157 lag_buf *multi_lag_get_free();
158
159 // put a lag buffer back
160 void multi_lag_put_free(lag_buf *buf);
161
162 // ----------------------------------------------------------------------------------------------------
163 // LAGLOSS FUNCTIONS
164 //
165
166 void multi_lag_init()
167 {       
168         // never do lag in a non-debug build
169 #if defined(NDEBUG) || !defined(MULTI_USE_LAG)
170         Multi_lag_inited = 0;
171 #else
172         int idx;
173
174         // if we're already inited, don't do anything
175         if(Multi_lag_inited){
176                 return;
177         }
178
179         // try and allocate lag bufs
180         for(idx=0; idx<MAX_LAG_BUFFERS; idx++){
181                 Lag_buffers[idx] = (lag_buf*)malloc(sizeof(lag_buf));
182                 if(Lag_buffers[idx] == NULL){
183                         return;
184                 }
185         }
186
187         // initialize lag buffer lists
188         list_init( &Lag_free_list );
189         list_init( &Lag_used_list );
190
191         // Link all object slots into the free list
192         for (idx=0; idx<MAX_LAG_BUFFERS; idx++) {
193                 list_append(&Lag_free_list, Lag_buffers[idx]);
194         }
195         
196         // set the default lag values
197         Multi_lag_base = MULTI_LAGLOSS_DEF_LAG;
198         Multi_lag_min = MULTI_LAGLOSS_DEF_LAGMIN;
199         Multi_lag_max = MULTI_LAGLOSS_DEF_LAGMAX;
200
201         // set the default loss values
202         Multi_loss_base = MULTI_LAGLOSS_DEF_LOSS;
203         Multi_loss_min  = MULTI_LAGLOSS_DEF_LOSSMIN;
204         Multi_loss_max = MULTI_LAGLOSS_DEF_LOSSMAX;
205
206         // set the default lag streak time      
207         Multi_streak_time = MULTI_LAGLOSS_DEF_STREAK;
208         
209         Multi_lag_inited = 1;
210 #endif
211 }
212
213 void multi_lag_close()
214 {       
215         int idx;
216
217         // if we're not inited already, don't do anything
218         if(!Multi_lag_inited){
219                 return;
220         }       
221
222         // free up lag buffers
223         for(idx=0; idx<MAX_LAG_BUFFERS; idx++){
224                 if(Lag_buffers[idx] != NULL){
225                         free(Lag_buffers[idx]);
226                         Lag_buffers[idx] = NULL;
227                 }
228         }
229
230         Multi_lag_inited = 0;
231 }
232
233 // select for multi_lag
234 int multi_lag_select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *except_fds, const timeval *timeout)
235 {               
236         char t_buf[1024];
237         int t_from_len;
238         SOCKADDR_IN ip_addr;
239         SOCKADDR_IPX ipx_addr;
240         int ret_val;
241         lag_buf *moveup, *item;
242
243         Assert(readfds != NULL);
244         Assert(writefds == NULL);
245         Assert(except_fds == NULL);
246
247         // clear out addresses
248         memset(&ip_addr, 0, sizeof(SOCKADDR_IN));
249         memset(&ipx_addr, 0, sizeof(SOCKADDR_IPX));
250
251         // if there's data on the socket, read it
252         if(select(nfds, readfds, writefds, except_fds, timeout)){               
253                 // read the data and stuff it
254                 if(Tcp_active){                                         
255                         t_from_len = sizeof(SOCKADDR_IN);
256                         ret_val = recvfrom(readfds->fd_array[0], t_buf, 1024, 0, (SOCKADDR*)&ip_addr, &t_from_len);
257                 } else {
258                         t_from_len = sizeof(SOCKADDR_IPX);
259                         ret_val = recvfrom(readfds->fd_array[0], t_buf, 1024, 0, (SOCKADDR*)&ipx_addr, &t_from_len);
260                 }
261                         
262                 // wacky socket error
263                 if(ret_val == SOCKET_ERROR){
264                         return SOCKET_ERROR;
265                 }
266
267                 // if we should be dropping this packet
268                 if(!multi_lag_should_be_lost()){
269                         // get a free packet buf and stuff the data
270                         item = multi_lag_get_free();
271                         if(item){
272                                 Assert(ret_val < 700);
273                                 memcpy(item->data, t_buf, ret_val);                     
274                                 item->data_len = ret_val;
275                                 item->ip_addr = ip_addr;
276                                 item->ipx_addr = ipx_addr;
277                                 item->socket = readfds->fd_array[0];
278                                 item->stamp = timestamp(multi_lag_get_random_lag());
279                         }               
280                 }
281         }
282
283         // always unset the readfds
284         readfds->fd_count = 0;
285
286         // now determine if we have any pending packets - find the first one
287         // NOTE : this _could_ be the packet we just read. In fact, with a 0 lag, this will always be the case
288         moveup=GET_FIRST(&Lag_used_list);
289         while ( moveup!=END_OF_LIST(&Lag_used_list) )   {               
290                 // if the timestamp has elapsed and we have a matching socket
291                 if((readfds->fd_array[0] == (SOCKET)moveup->socket) && ((moveup->stamp <= 0) || timestamp_elapsed(moveup->stamp))){
292                         // set this so we think select returned yes
293                         readfds->fd_count = 1;
294                         return 1;
295                 }
296
297                 moveup = GET_NEXT(moveup);
298         }
299
300         // no data
301         return 0;
302 }
303
304 // recvfrom for multilag
305 int multi_lag_recvfrom(uint s, char *buf, int len, int flags, struct sockaddr *from, int *fromlen)
306 {
307         lag_buf *moveup = NULL;
308         lag_buf *item = NULL;
309
310         // now determine if we have any pending packets - find the first one
311         moveup=GET_FIRST(&Lag_used_list);
312         while ( moveup!=END_OF_LIST(&Lag_used_list) )   {               
313                 // if the timestamp has elapsed
314                 if((s == (SOCKET)moveup->socket) && ((moveup->stamp <= 0) || timestamp_elapsed(moveup->stamp))){
315                         item = moveup;
316                         break;
317                 }
318
319                 moveup = GET_NEXT(moveup);
320         }
321
322         // if this happens, it means that the multi_lag_select() returned an improper value
323         Assert(item);
324         // stuff the data
325         Assert(item->data_len <= len);
326         memcpy(buf, item->data, item->data_len);
327         if(Tcp_active){
328                 memcpy(from, &item->ip_addr, sizeof(SOCKADDR_IN));
329         } else {
330                 memcpy(from, &item->ipx_addr, sizeof(SOCKADDR_IPX));
331         }
332
333         // stick the item back on the free list
334         multi_lag_put_free(item);
335
336         // return the size in bytes
337         return item->data_len;
338 }
339
340 // ----------------------------------------------------------------------------------------------------
341 // LAGLOSS FORWARD DEFINITIONS
342 //
343
344 int multi_lag_get_random_lag()
345 {
346         // first determine the percentage we'll be checking against
347         int ret;
348         int mod;        
349
350         // if the lag system isn't inited, don't do anything (no lag)
351         if(!Multi_lag_inited){
352                 return 0;
353         }
354                 
355         // pick a value
356         // see if we should be going up or down (loss max/loss min)
357         mod = 0;
358         if((float)rand()/(float)RAND_MAX < 0.5){
359                 // down
360                 if(Multi_lag_min >= 0){
361                         mod = - (int)((float)(Multi_lag_base - Multi_lag_min) * ((float)rand()/(float)RAND_MAX));
362                 }
363         } else {
364                 // up
365                 if(Multi_lag_max >= 0){
366                         mod = (int)((float)(Multi_lag_max - Multi_lag_base) * ((float)rand()/(float)RAND_MAX));
367                 }
368         }
369         
370         // if the current streak has elapsed, calculate a new one
371         if((Multi_streak_stamp == -1) || (timestamp_elapsed(Multi_streak_stamp))){
372                 // timestamp the new streak
373                 Multi_streak_stamp = timestamp(Multi_streak_time);
374
375                 // set the return value
376                 ret = Multi_lag_base + mod;
377                 
378                 // set the lag value of this current streak
379                 Multi_current_streak = ret;
380         } 
381         // otherwise use the lag for the current streak
382         else {
383                 ret = Multi_current_streak;
384         }
385                         
386         return ret;     
387 }
388
389 // this _may_ be a bit heavyweight, but it _is_ debug code
390 int multi_lag_should_be_lost()
391 {       
392         // first determine the percentage we'll be checking against
393         float mod;      
394
395         // if the lag system isn't inited, don't do anything
396         if(!Multi_lag_inited){
397                 return 0;
398         }
399                 
400         // see if we should be going up or down (loss max/loss min)
401         mod = 0.0f;
402         if((float)rand()/(float)RAND_MAX < 0.5){
403                 // down
404                 if(Multi_loss_min >= 0.0f){
405                         mod = - ((Multi_loss_base - Multi_loss_min) * ((float)rand()/(float)RAND_MAX));
406                 }
407         } else {
408                 // up
409                 if(Multi_loss_max >= 0.0f){
410                         mod = ((Multi_loss_max - Multi_loss_base) * ((float)rand()/(float)RAND_MAX));
411                 }
412         }       
413         
414         if((float)rand()/(float)RAND_MAX <= Multi_loss_base + mod){
415                 return 1;
416         }       
417
418         return 0;
419 }
420
421 // get a free packet buffer, return NULL on fail
422 lag_buf *multi_lag_get_free()
423 {
424         lag_buf *lagp;
425
426         // if we're out of buffers
427         if(Lag_buf_count >= MAX_LAG_BUFFERS){
428                 nprintf(("Network", "Out of lag buffers!\n"));
429                 return NULL;
430         }
431
432         // get a free item
433         lagp = GET_FIRST(&Lag_free_list);
434         Assert( lagp != &Lag_free_list );               // shouldn't have the dummy element
435
436         // remove trailp from the free list
437         list_remove( &Lag_free_list, lagp );
438         
439         // insert trailp onto the end of used list
440         list_append( &Lag_used_list, lagp );
441
442         // increase the count
443         Lag_buf_count++;
444         return lagp;
445 }
446
447 // put a lag buffer back
448 void multi_lag_put_free(lag_buf *buf)
449 {
450         // remove objp from the used list
451         list_remove( &Lag_used_list, buf);
452
453         // add objp to the end of the free
454         list_append( &Lag_free_list, buf );
455
456         // decrement counter
457         Lag_buf_count--;
458 }
459
460 void multi_lagloss_dcf()
461 {
462         // if the lag system isn't inited, don't do anything
463         if(!Multi_lag_inited){
464                 dc_printf("Lag System Not Initialized!\n");
465                 return;
466         }
467
468         // display all available commands
469         dc_printf("Usage :\nlag <ms>  (-1 to disable)\nlag_min <ms>\nlag_max <ms>\nloss <0-100>  (-1 to disable)\nloss_min <0-100>\nloss_max <0-100>\nlag_streak <ms>\nlagloss\n");
470
471         // display lag settings
472         dc_printf("Lag : ");            
473         dc_printf("\n   Base %d\n   Min %d\n   Max %d\n   Streak %d\n", Multi_lag_base, Multi_lag_min, Multi_lag_max, Multi_streak_time);       
474
475         // display loss settings
476         dc_printf("Loss : ");           
477         dc_printf("\n   Base %f\n   Min %f\n   Max %f\n", Multi_loss_base, Multi_loss_min, Multi_loss_max);     
478 }
479
480 DCF(lag, "")
481 {
482         // if the lag system isn't inited, don't do anything
483         if(!Multi_lag_inited){
484                 dc_printf("Lag System Not Initialized!\n");
485                 return;
486         }
487
488         dc_get_arg(ARG_INT);            
489         // parse the argument and change things around accordingly
490         if(Dc_arg_type & ARG_INT){                      
491                 if(Dc_arg_int < 0){
492                         // switch the lag sim off
493                         Multi_lag_base = -1;
494                         Multi_lag_min = -1;
495                         Multi_lag_max = -1;
496                         dc_printf("Turning simulated lag off\n");
497                         multi_lagloss_dcf();
498                 } else if((Multi_lag_max >= 0) && (Dc_arg_int > Multi_lag_max)){
499                         dc_printf("Base value greater than max value, ignoring...");
500                 } else if((Multi_lag_min >= 0) && (Dc_arg_int < Multi_lag_min)){
501                         dc_printf("Base value smaller than min value, ignoring...");
502                 } else {
503                         Multi_lag_base = Dc_arg_int;
504                         multi_lagloss_dcf();
505                 }
506         }       
507 }
508
509 DCF(lag_min, "")
510 {
511         // if the lag system isn't inited, don't do anything
512         if(!Multi_lag_inited){
513                 dc_printf("Lag System Not Initialized!\n");
514                 return;
515         }
516
517         dc_get_arg(ARG_INT);            
518         // parse the argument and change things around accordingly
519         if(Dc_arg_type & ARG_INT){                      
520                 if(Dc_arg_int > Multi_lag_base){
521                         dc_printf("Min value greater than base value, ignoring...");
522                 } else {
523                         if(Dc_arg_int < 0){
524                                 Multi_lag_min = -1;
525                         } else {
526                                 Multi_lag_min = Dc_arg_int;
527                         }
528                         multi_lagloss_dcf();
529                 }
530         }                       
531 }
532
533 DCF(lag_max, "")
534 {
535         // if the lag system isn't inited, don't do anything
536         if(!Multi_lag_inited){
537                 dc_printf("Lag System Not Initialized!\n");
538                 return;
539         }
540
541         // parse the argument and change things around accordingly
542         dc_get_arg(ARG_INT);
543         if(Dc_arg_type & ARG_INT){                      
544                 if((Dc_arg >=0) && (Dc_arg_int < Multi_lag_base)){
545                         dc_printf("Max value smaller than base value, ignoring...");
546                 } else {
547                         if(Dc_arg_int < 0){
548                                 Multi_lag_max = -1;
549                         } else {
550                                 Multi_lag_max = Dc_arg_int;
551                         }
552                         multi_lagloss_dcf();
553                 }
554         }               
555 }
556
557 DCF(loss, "")
558 {
559         // if the lag system isn't inited, don't do anything
560         if(!Multi_lag_inited){
561                 dc_printf("Lag System Not Initialized!\n");
562                 return;
563         }
564
565         // parse the argument and change things around accordingly
566         dc_get_arg(ARG_INT);
567         if(Dc_arg_type & ARG_INT){
568                 float val = (float)Dc_arg_int / 100.0f;
569                         
570                 if(Dc_arg_int > 100){
571                         dc_printf("Illegal loss base value, ignoring...");
572                 } else if(Dc_arg_int < 0){
573                         // switch the loss sim off
574                         dc_printf("Turning simulated loss off\n");
575                         Multi_loss_base = -1.0f;
576                         Multi_loss_min = -1.0f;
577                         Multi_loss_max = -1.0f;
578                         multi_lagloss_dcf();
579                 } else if((Multi_loss_max >= 0.0f) && (val > Multi_loss_max)){
580                         dc_printf("Base value greater than max value, ignoring...");
581                 } else if((Multi_loss_min >= 0.0f) && (val < Multi_loss_min)){
582                         dc_printf("Base value smaller than min value, ignoring...");
583                 } else {
584                         Multi_loss_base = val;
585                         multi_lagloss_dcf();
586                 }
587         }                       
588 }
589
590 DCF(loss_min, "")
591 {
592         // if the lag system isn't inited, don't do anything
593         if(!Multi_lag_inited){
594                 dc_printf("Lag System Not Initialized!\n");
595                 return;
596         }
597
598         // parse the argument and change things around accordingly
599         dc_get_arg(ARG_INT);
600         if(Dc_arg_type & ARG_INT){                      
601       float val = (float)Dc_arg_int / 100.0f;
602
603                 if(val > Multi_loss_base){
604                         dc_printf("Min value greater than base value, ignoring...");
605                 } else {
606                         // otherwise set the value
607                         if(Dc_arg_int < 0){
608                                 Multi_loss_min = -1.0f;
609                         } else {
610                                 Multi_loss_min = val;
611                         }
612                         multi_lagloss_dcf();
613                 }
614         }
615 }
616
617 DCF(loss_max, "")
618 {       
619         // if the lag system isn't inited, don't do anything
620         if(!Multi_lag_inited){
621                 dc_printf("Lag System Not Initialized!\n");
622                 return;
623         }
624
625         // parse the argument and change things around accordingly
626         dc_get_arg(ARG_INT);
627         if(Dc_arg_type & ARG_INT){                      
628       float val = (float)Dc_arg_int / 100.0f;
629
630                 if(val < Multi_loss_base){
631                         dc_printf("Max value smaller than base value, ignoring...");
632                 } else {
633                         // otherwise set the value
634                         if(Dc_arg_int < 0){
635                                 Multi_loss_max = -1.0f;
636                         } else {
637                                 Multi_loss_min = val;
638                         }
639                         multi_lagloss_dcf();
640                 }
641         }                       
642 }
643
644 DCF(lagloss, "")
645 {
646         // if the lag system isn't inited, don't do anything
647         if(!Multi_lag_inited){
648                 dc_printf("Lag System Not Initialized!\n");
649                 return;
650         }
651
652         multi_lagloss_dcf();
653 }
654
655 DCF(lag_streak, "")
656 {
657         // if the lag system isn't inited, don't do anything
658         if(!Multi_lag_inited){
659                 dc_printf("Lag System Not Initialized!\n");
660                 return;
661         }
662
663         dc_get_arg(ARG_INT);
664         if(Dc_arg_type & ARG_INT){                                      
665                 if(Dc_arg_int >= 0){
666                         Multi_streak_time = Dc_arg_int;
667                 } 
668         }
669 }
670
671 DCF(lag_bad, "")
672 {
673         // if the lag system isn't inited, don't do anything
674         if(!Multi_lag_inited){
675                 dc_printf("Lag System Not Initialized!\n");
676                 return;
677         }
678
679         dc_printf("Setting bad lag/loss parameters\n");
680
681         // set good lagloss parameters
682         Multi_lag_base = 500;
683         Multi_lag_min = 400;
684         Multi_lag_max = 600;
685         
686         Multi_loss_base = 0.2f;
687         Multi_loss_min = 0.15f;
688         Multi_loss_max = 0.23f;
689
690         Multi_streak_time = 800;
691         Multi_streak_stamp = -1;
692         Multi_current_streak = -1;
693 }
694
695 DCF(lag_avg, "")
696 {
697         // if the lag system isn't inited, don't do anything
698         if(!Multi_lag_inited){
699                 dc_printf("Lag System Not Initialized!\n");
700                 return;
701         }
702
703         dc_printf("Setting avg lag/loss parameters\n");
704
705         // set good lagloss parameters
706         Multi_lag_base = 275;
707         Multi_lag_min = 200;
708         Multi_lag_max = 400;
709         
710         Multi_loss_base = 0.15f;
711         Multi_loss_min = 0.1f;
712         Multi_loss_max = 0.20f;
713
714         Multi_streak_time = 900;
715         Multi_streak_stamp = -1;
716         Multi_current_streak = -1;
717 }
718
719 DCF(lag_good, "")
720 {
721         // if the lag system isn't inited, don't do anything
722         if(!Multi_lag_inited){
723                 dc_printf("Lag System Not Initialized!\n");
724                 return;
725         }
726
727         dc_printf("Setting good lag/loss parameters\n");
728
729         // set good lagloss parameters
730         Multi_lag_base = 100;
731         Multi_lag_min = 35;
732         Multi_lag_max = 200;
733         
734         Multi_loss_base = 0.08f;
735         Multi_loss_min = 0.0f;
736         Multi_loss_max = 0.1f;
737
738         Multi_streak_time = 1000;
739         Multi_streak_stamp = -1;
740         Multi_current_streak = -1;
741 }