rnd-19981025-1
[rocksndiamonds.git] / src / misc.c
1 /***********************************************************
2 *  Rocks'n'Diamonds -- McDuffin Strikes Back!              *
3 *----------------------------------------------------------*
4 *  (c) 1995-98 Artsoft Entertainment                       *
5 *              Holger Schemel                              *
6 *              Oststrasse 11a                              *
7 *              33604 Bielefeld                             *
8 *              phone: ++49 +521 290471                     *
9 *              email: aeglos@valinor.owl.de                *
10 *----------------------------------------------------------*
11 *  misc.c                                                  *
12 ***********************************************************/
13
14 #include <pwd.h>
15 #include <unistd.h>
16 #include <time.h>
17 #include <sys/time.h>
18 #include <sys/param.h>
19 #include <sys/types.h>
20 #include <stdarg.h>
21
22 #include "misc.h"
23 #include "init.h"
24 #include "tools.h"
25 #include "sound.h"
26 #include "random.h"
27 #include "joystick.h"
28
29 static unsigned long mainCounter(int mode)
30 {
31   static struct timeval base_time = { 0, 0 };
32   struct timeval current_time;
33   unsigned long counter_ms;
34
35   gettimeofday(&current_time, NULL);
36
37   if (mode == INIT_COUNTER || current_time.tv_sec < base_time.tv_sec)
38     base_time = current_time;
39
40   counter_ms = (current_time.tv_sec  - base_time.tv_sec)  * 1000
41              + (current_time.tv_usec - base_time.tv_usec) / 1000;
42
43   return counter_ms;            /* return milliseconds since last init */
44 }
45
46 void InitCounter()              /* set counter back to zero */
47 {
48   mainCounter(INIT_COUNTER);
49 }
50
51 unsigned long Counter() /* get milliseconds since last call of InitCounter() */
52 {
53   return(mainCounter(READ_COUNTER));
54 }
55
56 static void sleep_milliseconds(unsigned long milliseconds_delay)
57 {
58   if (milliseconds_delay < 5)
59   {
60     /* we want to wait only a few ms -- if we assume that we have a
61        kernel timer resolution of 10 ms, we would wait far to long;
62        therefore it's better to do a short interval of busy waiting
63        to get our sleeping time more accurate */
64
65     unsigned long base_counter = Counter(), actual_counter = Counter();
66
67     while (actual_counter < base_counter + milliseconds_delay &&
68            actual_counter >= base_counter)
69       actual_counter = Counter();
70   }
71   else
72   {
73     struct timeval delay;
74
75     delay.tv_sec  = milliseconds_delay / 1000;
76     delay.tv_usec = 1000 * (milliseconds_delay % 1000);
77
78     if (select(0, NULL, NULL, NULL, &delay) != 0)
79       Error(ERR_RETURN, "sleep_milliseconds(): select() failed");
80   }
81 }
82
83 void Delay(unsigned long delay) /* Sleep specified number of milliseconds */
84 {
85   sleep_milliseconds(delay);
86 }
87
88 boolean FrameReached(unsigned long *frame_counter_var,
89                      unsigned long frame_delay)
90 {
91   unsigned long actual_frame_counter = FrameCounter;
92
93   if (actual_frame_counter < *frame_counter_var+frame_delay &&
94       actual_frame_counter >= *frame_counter_var)
95     return(FALSE);
96
97   *frame_counter_var = actual_frame_counter;
98   return(TRUE);
99 }
100
101 boolean DelayReached(unsigned long *counter_var,
102                      unsigned long delay)
103 {
104   unsigned long actual_counter = Counter();
105
106   if (actual_counter < *counter_var + delay &&
107       actual_counter >= *counter_var)
108     return(FALSE);
109
110   *counter_var = actual_counter;
111   return(TRUE);
112 }
113
114 void WaitUntilDelayReached(unsigned long *counter_var, unsigned long delay)
115 {
116   unsigned long actual_counter;
117
118   while(1)
119   {
120     actual_counter = Counter();
121
122     if (actual_counter < *counter_var + delay &&
123         actual_counter >= *counter_var)
124       sleep_milliseconds((*counter_var + delay - actual_counter) / 2);
125     else
126       break;
127   }
128
129   *counter_var = actual_counter;
130 }
131
132 char *int2str(int ct, int nr)
133 {
134   static char str[20];
135
136   sprintf(str,"%09d",ct);
137   return(&str[strlen(str)-nr]);
138 }
139
140 unsigned int SimpleRND(unsigned int max)
141 {
142   static unsigned long root = 654321;
143   struct timeval current_time;
144
145   gettimeofday(&current_time,NULL);
146   root = root * 4253261 + current_time.tv_sec + current_time.tv_usec;
147   return(root % max);
148 }
149
150 unsigned int RND(unsigned int max)
151 {
152   return(random_linux_libc() % max);
153 }
154
155 unsigned int InitRND(long seed)
156 {
157   struct timeval current_time;
158
159   if (seed==NEW_RANDOMIZE)
160   {
161     gettimeofday(&current_time,NULL);
162     srandom_linux_libc((unsigned int) current_time.tv_usec);
163     return((unsigned int) current_time.tv_usec);
164   }
165   else
166   {
167     srandom_linux_libc((unsigned int) seed);
168     return((unsigned int) seed);
169   }
170 }
171
172 char *GetLoginName()
173 {
174   struct passwd *pwd;
175
176   if (!(pwd=getpwuid(getuid())))
177     return("ANONYMOUS");
178   else
179     return(pwd->pw_name);
180 }
181
182 void MarkTileDirty(int x, int y)
183 {
184   int xx = redraw_x1 + x;
185   int yy = redraw_y1 + y;
186
187   if (!redraw[xx][yy])
188   {
189     redraw[xx][yy] = TRUE;
190     redraw_tiles++;
191     redraw_mask |= REDRAW_TILES;
192   }
193 }
194
195 void GetOptions(char *argv[])
196 {
197   char **options_left = &argv[1];
198
199   /* initialize global program options */
200   options.display_name = NULL;
201   options.server_host = NULL;
202   options.server_port = 0;
203   options.serveronly = FALSE;
204   options.network = FALSE;
205   options.verbose = FALSE;
206
207   while (*options_left)
208   {
209     char option_str[MAX_OPTION_LEN];
210     char *option = options_left[0];
211     char *next_option = options_left[1];
212     char *option_arg = NULL;
213     int option_len = strlen(option);
214
215     strcpy(option_str, option);                 /* copy argument into buffer */
216     option = option_str;
217
218     if (strcmp(option, "--") == 0)              /* stop scanning arguments */
219       break;
220
221     if (option_len >= MAX_OPTION_LEN)
222       Error(ERR_EXIT_HELP, "unrecognized option '%s'", option);
223
224     if (strncmp(option, "--", 2) == 0)          /* treat '--' like '-' */
225       option++;
226
227     option_arg = strchr(option, '=');
228     if (option_arg == NULL)                     /* no '=' in option */
229       option_arg = next_option;
230     else
231     {
232       *option_arg++ = '\0';                     /* cut argument from option */
233       if (*option_arg == '\0')                  /* no argument after '=' */
234         Error(ERR_EXIT_HELP, "option '%s' has invalid argument", option_str);
235     }
236
237     option_len = strlen(option);
238
239     if (strcmp(option, "-") == 0)
240       Error(ERR_EXIT_HELP, "unrecognized option '%s'", option);
241     else if (strncmp(option, "-help", option_len) == 0)
242     {
243       printf("Usage: %s [options] [server.name [port]]\n"
244              "Options:\n"
245              "  -d, --display machine:0       X server display\n"
246              "  -l, --levels directory        alternative level directory\n"
247              "  -s, --serveronly              only start network server\n"
248              "  -n, --network                 network multiplayer game\n"
249              "  -v, --verbose                 verbose mode\n",
250              program_name);
251       exit(0);
252     }
253     else if (strncmp(option, "-display", option_len) == 0)
254     {
255       if (option_arg == NULL)
256         Error(ERR_EXIT_HELP, "option '%s' requires an argument", option_str);
257
258       options.display_name = option_arg;
259       if (option_arg == next_option)
260         options_left++;
261
262       printf("--display == '%s'\n", options.display_name);
263     }
264     else if (strncmp(option, "-levels", option_len) == 0)
265     {
266       if (option_arg == NULL)
267         Error(ERR_EXIT_HELP, "option '%s' requires an argument", option_str);
268
269       level_directory = option_arg;
270       if (option_arg == next_option)
271         options_left++;
272
273       printf("--levels == '%s'\n", level_directory);
274     }
275     else if (strncmp(option, "-network", option_len) == 0)
276     {
277       printf("--network\n");
278
279       options.network = TRUE;
280     }
281     else if (strncmp(option, "-serveronly", option_len) == 0)
282     {
283       printf("--serveronly\n");
284
285       options.serveronly = TRUE;
286     }
287     else if (strncmp(option, "-verbose", option_len) == 0)
288     {
289       printf("--verbose\n");
290
291       options.verbose = TRUE;
292     }
293     else if (*option == '-')
294       Error(ERR_EXIT_HELP, "unrecognized option '%s'", option_str);
295     else if (options.server_host == NULL)
296     {
297       options.server_host = *options_left;
298
299       printf("server.name == '%s'\n", options.server_host);
300     }
301     else if (options.server_port == 0)
302     {
303       options.server_port = atoi(*options_left);
304       if (options.server_port < 1024)
305         Error(ERR_EXIT_HELP, "bad port number '%d'", options.server_port);
306
307       printf("port == %d\n", options.server_port);
308     }
309     else
310       Error(ERR_EXIT_HELP, "too many arguments");
311
312     options_left++;
313   }
314 }
315
316 void Error(int mode, char *format_str, ...)
317 {
318   FILE *output_stream = stderr;
319   char *process_name = "";
320
321   if (mode == ERR_EXIT_SOUNDSERVER)
322     process_name = " sound server";
323
324   if (format_str)
325   {
326     va_list ap;
327     char *format_ptr;
328     char *s_value;
329     int i_value;
330     double d_value;
331
332     fprintf(output_stream, "%s%s: ", program_name, process_name);
333
334     va_start(ap, format_str);   /* ap points to first unnamed argument */
335   
336     for(format_ptr=format_str; *format_ptr; format_ptr++)
337     {
338       if (*format_ptr != '%')
339       {
340         fprintf(output_stream, "%c", *format_ptr);
341         continue;
342       }
343   
344       switch(*++format_ptr)
345       {
346         case 'd':
347           i_value = va_arg(ap, int);
348           fprintf(output_stream, "%d", i_value);
349           break;
350   
351         case 'f':
352           d_value = va_arg(ap, double);
353           fprintf(output_stream, "%f", d_value);
354           break;
355   
356         case 's':
357           s_value = va_arg(ap, char *);
358           fprintf(output_stream, "%s", s_value);
359           break;
360   
361         default:
362           fprintf(stderr, "\n%s: Error(): invalid format string: %s\n",
363                   program_name, format_str);
364           CloseAllAndExit(10);
365       }
366     }
367
368     va_end(ap);
369   
370     fprintf(output_stream, "\n");
371   }
372   
373   if (mode == ERR_EXIT_HELP)
374     fprintf(output_stream, "%s: Try option '--help' for more information.\n",
375             program_name);
376
377   if (mode != ERR_RETURN)
378   {
379     fprintf(output_stream, "%s%s: aborting\n", program_name, process_name);
380     CloseAllAndExit(1);
381   }
382 }
383
384 void *checked_malloc(unsigned long size)
385 {
386   void *ptr;
387
388   ptr = malloc(size);
389
390   if (ptr == NULL)
391     Error(ERR_EXIT, "cannot allocate %d bytes -- out of memory", size);
392
393   return ptr;
394 }
395
396 #define TRANSLATE_KEYSYM_TO_KEYNAME     0
397 #define TRANSLATE_KEYSYM_TO_X11KEYNAME  1
398 #define TRANSLATE_X11KEYNAME_TO_KEYSYM  2
399
400 void translate_keyname(KeySym *keysym, char **x11name, char **name, int mode)
401 {
402   static struct
403   {
404     KeySym keysym;
405     char *x11name;
406     char *name;
407   } translate_key[] =
408   {
409     /* normal cursor keys */
410     { XK_Left,          "XK_Left",              "cursor left" },
411     { XK_Right,         "XK_Right",             "cursor right" },
412     { XK_Up,            "XK_Up",                "cursor up" },
413     { XK_Down,          "XK_Down",              "cursor down" },
414
415     /* keypad cursor keys */
416 #ifdef XK_KP_Left
417     { XK_KP_Left,       "XK_KP_Left",           "keypad left" },
418     { XK_KP_Right,      "XK_KP_Right",          "keypad right" },
419     { XK_KP_Up,         "XK_KP_Up",             "keypad up" },
420     { XK_KP_Down,       "XK_KP_Down",           "keypad down" },
421 #endif
422
423     /* other keypad keys */
424 #ifdef XK_KP_Enter
425     { XK_KP_Enter,      "XK_KP_Enter",          "keypad enter" },
426     { XK_KP_Add,        "XK_KP_Add",            "keypad +" },
427     { XK_KP_Subtract,   "XK_KP_Subtract",       "keypad -" },
428     { XK_KP_Multiply,   "XK_KP_Multiply",       "keypad mltply" },
429     { XK_KP_Divide,     "XK_KP_Divide",         "keypad /" },
430     { XK_KP_Separator,  "XK_KP_Separator",      "keypad ," },
431 #endif
432
433     /* modifier keys */
434     { XK_Shift_L,       "XK_Shift_L",           "left shift" },
435     { XK_Shift_R,       "XK_Shift_R",           "right shift" },
436     { XK_Control_L,     "XK_Control_L",         "left control" },
437     { XK_Control_R,     "XK_Control_R",         "right control" },
438     { XK_Meta_L,        "XK_Meta_L",            "left meta" },
439     { XK_Meta_R,        "XK_Meta_R",            "right meta" },
440     { XK_Alt_L,         "XK_Alt_L",             "left alt" },
441     { XK_Alt_R,         "XK_Alt_R",             "right alt" },
442     { XK_Mode_switch,   "XK_Mode_switch",       "mode switch" },
443     { XK_Multi_key,     "XK_Multi_key",         "multi key" },
444
445     /* some special keys */
446     { XK_BackSpace,     "XK_BackSpace",         "backspace" },
447     { XK_Delete,        "XK_Delete",            "delete" },
448     { XK_Insert,        "XK_Insert",            "insert" },
449     { XK_Tab,           "XK_Tab",               "tab" },
450     { XK_Home,          "XK_Home",              "home" },
451     { XK_End,           "XK_End",               "end" },
452     { XK_Page_Up,       "XK_Page_Up",           "page up" },
453     { XK_Page_Down,     "XK_Page_Down",         "page down" },
454     { XK_space,         "XK_space",             "space" },
455
456     /* even more special keys */
457     { XK_adiaeresis,    "XK_adiaeresis",        "ä" },
458     { XK_odiaeresis,    "XK_odiaeresis",        "ö" },
459     { XK_udiaeresis,    "XK_udiaeresis",        "ü" },
460     { XK_apostrophe,    "XK_apostrophe",        "'" },
461     { XK_plus,          "XK_plus",              "+" },
462     { XK_minus,         "XK_minus",             "-" },
463     { XK_comma,         "XK_comma",             "," },
464     { XK_period,        "XK_period",            "." },
465     { XK_numbersign,    "XK_numbersign",        "#" },
466     { XK_less,          "XK_less",              "less" },
467     { XK_greater,       "XK_greater",           "greater" },
468     { XK_asciicircum,   "XK_asciicircum",       "circumflex" },
469     { XK_ssharp,        "XK_ssharp",            "sharp s" },
470
471     /* end-of-array identifier */
472     { 0,                NULL,                   NULL }
473   };
474
475   int i;
476
477   if (mode == TRANSLATE_KEYSYM_TO_KEYNAME)
478   {
479     static char name_buffer[30];
480     KeySym key = *keysym;
481
482     if (key >= XK_A && key <= XK_Z)
483       sprintf(name_buffer, "%c", 'A' + (char)(key - XK_A));
484     else if (key >= XK_a && key <= XK_z)
485       sprintf(name_buffer, "%c", 'a' + (char)(key - XK_a));
486     else if (key >= XK_0 && key <= XK_9)
487       sprintf(name_buffer, "%c", '0' + (char)(key - XK_0));
488     else if (key >= XK_KP_0 && key <= XK_KP_9)
489       sprintf(name_buffer, "keypad %c", '0' + (char)(key - XK_KP_0));
490     else if (key >= XK_F1 && key <= XK_F24)
491       sprintf(name_buffer, "function F%d", (int)(key - XK_F1 + 1));
492     else if (key == KEY_UNDEFINDED)
493       strcpy(name_buffer, "(undefined)");
494     else
495     {
496       i = 0;
497
498       do
499       {
500         if (key == translate_key[i].keysym)
501         {
502           strcpy(name_buffer, translate_key[i].name);
503           break;
504         }
505       }
506       while (translate_key[++i].name);
507
508       if (!translate_key[i].name)
509         strcpy(name_buffer, "(unknown)");
510     }
511
512     *name = name_buffer;
513   }
514   else if (mode == TRANSLATE_KEYSYM_TO_X11KEYNAME)
515   {
516     static char name_buffer[30];
517     KeySym key = *keysym;
518
519     if (key >= XK_A && key <= XK_Z)
520       sprintf(name_buffer, "XK_%c", 'A' + (char)(key - XK_A));
521     else if (key >= XK_a && key <= XK_z)
522       sprintf(name_buffer, "XK_%c", 'a' + (char)(key - XK_a));
523     else if (key >= XK_0 && key <= XK_9)
524       sprintf(name_buffer, "XK_%c", '0' + (char)(key - XK_0));
525     else if (key >= XK_KP_0 && key <= XK_KP_9)
526       sprintf(name_buffer, "XK_KP_%c", '0' + (char)(key - XK_KP_0));
527     else if (key >= XK_F1 && key <= XK_F24)
528       sprintf(name_buffer, "XK_F%d", (int)(key - XK_F1 + 1));
529     else if (key == KEY_UNDEFINDED)
530       strcpy(name_buffer, "[undefined]");
531     else
532     {
533       i = 0;
534
535       do
536       {
537         if (key == translate_key[i].keysym)
538         {
539           strcpy(name_buffer, translate_key[i].x11name);
540           break;
541         }
542       }
543       while (translate_key[++i].x11name);
544
545       if (!translate_key[i].x11name)
546         sprintf(name_buffer, "0x%04lx", (unsigned long)key);
547     }
548
549     *x11name = name_buffer;
550   }
551   else if (mode == TRANSLATE_X11KEYNAME_TO_KEYSYM)
552   {
553     KeySym key = XK_VoidSymbol;
554     char *name_ptr = *x11name;
555
556     if (strncmp(name_ptr, "XK_", 3) == 0 && strlen(name_ptr) == 4)
557     {
558       char c = name_ptr[3];
559
560       if (c >= 'A' && c <= 'Z')
561         key = XK_A + (KeySym)(c - 'A');
562       else if (c >= 'a' && c <= 'z')
563         key = XK_a + (KeySym)(c - 'a');
564       else if (c >= '0' && c <= '9')
565         key = XK_0 + (KeySym)(c - '0');
566     }
567     else if (strncmp(name_ptr, "XK_KP_", 6) == 0 && strlen(name_ptr) == 7)
568     {
569       char c = name_ptr[6];
570
571       if (c >= '0' && c <= '9')
572         key = XK_0 + (KeySym)(c - '0');
573     }
574     else if (strncmp(name_ptr, "XK_F", 4) == 0 && strlen(name_ptr) <= 6)
575     {
576       char c1 = name_ptr[4];
577       char c2 = name_ptr[5];
578       int d = 0;
579
580       if ((c1 >= '0' && c1 <= '9') &&
581           ((c2 >= '0' && c1 <= '9') || c2 == '\0'))
582         d = atoi(&name_ptr[4]);
583
584       if (d >=1 && d <= 24)
585         key = XK_F1 + (KeySym)(d - 1);
586     }
587     else if (strncmp(name_ptr, "XK_", 3) == 0)
588     {
589       i = 0;
590
591       do
592       {
593         if (strcmp(name_ptr, translate_key[i].x11name) == 0)
594         {
595           key = translate_key[i].keysym;
596           break;
597         }
598       }
599       while (translate_key[++i].x11name);
600     }
601     else if (strncmp(name_ptr, "0x", 2) == 0)
602     {
603       unsigned long value = 0;
604
605       name_ptr += 2;
606
607       while (name_ptr)
608       {
609         char c = *name_ptr++;
610         int d = -1;
611
612         if (c >= '0' && c <= '9')
613           d = (int)(c - '0');
614         else if (c >= 'a' && c <= 'f')
615           d = (int)(c - 'a' + 10);
616         else if (c >= 'A' && c <= 'F')
617           d = (int)(c - 'A' + 10);
618
619         if (d == -1)
620         {
621           value = -1;
622           break;
623         }
624
625         value = value * 16 + d;
626       }
627
628       if (value != -1)
629         key = (KeySym)value;
630     }
631
632     *keysym = key;
633   }
634 }
635
636 char *getKeyNameFromKeySym(KeySym keysym)
637 {
638   char *name;
639
640   translate_keyname(&keysym, NULL, &name, TRANSLATE_KEYSYM_TO_KEYNAME);
641   return name;
642 }
643
644 char *getX11KeyNameFromKeySym(KeySym keysym)
645 {
646   char *x11name;
647
648   translate_keyname(&keysym, &x11name, NULL, TRANSLATE_KEYSYM_TO_X11KEYNAME);
649   return x11name;
650 }
651
652 KeySym getKeySymFromX11KeyName(char *x11name)
653 {
654   KeySym keysym;
655
656   translate_keyname(&keysym, &x11name, NULL, TRANSLATE_X11KEYNAME_TO_KEYSYM);
657   return keysym;
658 }
659
660 #define TRANSLATE_JOYSYMBOL_TO_JOYNAME  0
661 #define TRANSLATE_JOYNAME_TO_JOYSYMBOL  1
662
663 void translate_joyname(int *joysymbol, char **name, int mode)
664 {
665   static struct
666   {
667     int joysymbol;
668     char *name;
669   } translate_joy[] =
670   {
671     { JOY_LEFT,         "joystick_left" },
672     { JOY_RIGHT,        "joystick_right" },
673     { JOY_UP,           "joystick_up" },
674     { JOY_DOWN,         "joystick_down" },
675     { JOY_BUTTON_1,     "joystick_button_1" },
676     { JOY_BUTTON_2,     "joystick_button_2" },
677   };
678
679   int i;
680
681   if (mode == TRANSLATE_JOYSYMBOL_TO_JOYNAME)
682   {
683     *name = "[undefined]";
684
685     for (i=0; i<6; i++)
686     {
687       if (*joysymbol == translate_joy[i].joysymbol)
688       {
689         *name = translate_joy[i].name;
690         break;
691       }
692     }
693   }
694   else if (mode == TRANSLATE_JOYNAME_TO_JOYSYMBOL)
695   {
696     *joysymbol = 0;
697
698     for (i=0; i<6; i++)
699     {
700       if (strcmp(*name, translate_joy[i].name) == 0)
701       {
702         *joysymbol = translate_joy[i].joysymbol;
703         break;
704       }
705     }
706   }
707 }
708
709 char *getJoyNameFromJoySymbol(int joysymbol)
710 {
711   char *name;
712
713   translate_joyname(&joysymbol, &name, TRANSLATE_JOYSYMBOL_TO_JOYNAME);
714   return name;
715 }
716
717 int getJoySymbolFromJoyName(char *name)
718 {
719   int joysymbol;
720
721   translate_joyname(&joysymbol, &name, TRANSLATE_JOYNAME_TO_JOYSYMBOL);
722   return joysymbol;
723 }