rnd-19981017-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
28 static unsigned long mainCounter(int mode)
29 {
30   static struct timeval base_time = { 0, 0 };
31   struct timeval current_time;
32   unsigned long counter_ms;
33
34   gettimeofday(&current_time, NULL);
35
36   if (mode == INIT_COUNTER || current_time.tv_sec < base_time.tv_sec)
37     base_time = current_time;
38
39   counter_ms = (current_time.tv_sec  - base_time.tv_sec)  * 1000
40              + (current_time.tv_usec - base_time.tv_usec) / 1000;
41
42   return counter_ms;            /* return milliseconds since last init */
43 }
44
45 void InitCounter()              /* set counter back to zero */
46 {
47   mainCounter(INIT_COUNTER);
48 }
49
50 unsigned long Counter() /* get milliseconds since last call of InitCounter() */
51 {
52   return(mainCounter(READ_COUNTER));
53 }
54
55 static void sleep_milliseconds(unsigned long milliseconds_delay)
56 {
57   if (milliseconds_delay < 5)
58   {
59     /* we want to wait only a few ms -- if we assume that we have a
60        kernel timer resolution of 10 ms, we would wait far to long;
61        therefore it's better to do a short interval of busy waiting
62        to get our sleeping time more accurate */
63
64     unsigned long base_counter = Counter(), actual_counter = Counter();
65
66     while (actual_counter < base_counter + milliseconds_delay &&
67            actual_counter >= base_counter)
68       actual_counter = Counter();
69   }
70   else
71   {
72     struct timeval delay;
73
74     delay.tv_sec  = milliseconds_delay / 1000;
75     delay.tv_usec = 1000 * (milliseconds_delay % 1000);
76
77     if (select(0, NULL, NULL, NULL, &delay) != 0)
78       Error(ERR_RETURN, "sleep_milliseconds(): select() failed");
79   }
80 }
81
82 void Delay(unsigned long delay) /* Sleep specified number of milliseconds */
83 {
84   sleep_milliseconds(delay);
85 }
86
87 boolean FrameReached(unsigned long *frame_counter_var,
88                      unsigned long frame_delay)
89 {
90   unsigned long actual_frame_counter = FrameCounter;
91
92   if (actual_frame_counter < *frame_counter_var+frame_delay &&
93       actual_frame_counter >= *frame_counter_var)
94     return(FALSE);
95
96   *frame_counter_var = actual_frame_counter;
97   return(TRUE);
98 }
99
100 boolean DelayReached(unsigned long *counter_var,
101                      unsigned long delay)
102 {
103   unsigned long actual_counter = Counter();
104
105   if (actual_counter < *counter_var + delay &&
106       actual_counter >= *counter_var)
107     return(FALSE);
108
109   *counter_var = actual_counter;
110   return(TRUE);
111 }
112
113 void WaitUntilDelayReached(unsigned long *counter_var, unsigned long delay)
114 {
115   unsigned long actual_counter;
116
117   while(1)
118   {
119     actual_counter = Counter();
120
121     if (actual_counter < *counter_var + delay &&
122         actual_counter >= *counter_var)
123       sleep_milliseconds((*counter_var + delay - actual_counter) / 2);
124     else
125       break;
126   }
127
128   *counter_var = actual_counter;
129 }
130
131 char *int2str(int ct, int nr)
132 {
133   static char str[20];
134
135   sprintf(str,"%09d",ct);
136   return(&str[strlen(str)-nr]);
137 }
138
139 unsigned int SimpleRND(unsigned int max)
140 {
141   static unsigned long root = 654321;
142   struct timeval current_time;
143
144   gettimeofday(&current_time,NULL);
145   root = root * 4253261 + current_time.tv_sec + current_time.tv_usec;
146   return(root % max);
147 }
148
149 unsigned int RND(unsigned int max)
150 {
151   return(random_linux_libc() % max);
152 }
153
154 unsigned int InitRND(long seed)
155 {
156   struct timeval current_time;
157
158   if (seed==NEW_RANDOMIZE)
159   {
160     gettimeofday(&current_time,NULL);
161     srandom_linux_libc((unsigned int) current_time.tv_usec);
162     return((unsigned int) current_time.tv_usec);
163   }
164   else
165   {
166     srandom_linux_libc((unsigned int) seed);
167     return((unsigned int) seed);
168   }
169 }
170
171 char *GetLoginName()
172 {
173   struct passwd *pwd;
174
175   if (!(pwd=getpwuid(getuid())))
176     return("ANONYMOUS");
177   else
178     return(pwd->pw_name);
179 }
180
181 void MarkTileDirty(int x, int y)
182 {
183   int xx = redraw_x1 + x;
184   int yy = redraw_y1 + y;
185
186   if (!redraw[xx][yy])
187   {
188     redraw[xx][yy] = TRUE;
189     redraw_tiles++;
190     redraw_mask |= REDRAW_TILES;
191   }
192 }
193
194 void GetOptions(char *argv[])
195 {
196   char **options_left = &argv[1];
197
198   /* initialize global program options */
199   options.display_name = NULL;
200   options.server_host = NULL;
201   options.server_port = 0;
202   options.serveronly = FALSE;
203   options.network = FALSE;
204   options.verbose = FALSE;
205
206   while (*options_left)
207   {
208     char option_str[MAX_OPTION_LEN];
209     char *option = options_left[0];
210     char *next_option = options_left[1];
211     char *option_arg = NULL;
212     int option_len = strlen(option);
213
214     strcpy(option_str, option);                 /* copy argument into buffer */
215     option = option_str;
216
217     if (strcmp(option, "--") == 0)              /* stop scanning arguments */
218       break;
219
220     if (option_len >= MAX_OPTION_LEN)
221       Error(ERR_EXIT_HELP, "unrecognized option '%s'", option);
222
223     if (strncmp(option, "--", 2) == 0)          /* treat '--' like '-' */
224       option++;
225
226     option_arg = strchr(option, '=');
227     if (option_arg == NULL)                     /* no '=' in option */
228       option_arg = next_option;
229     else
230     {
231       *option_arg++ = '\0';                     /* cut argument from option */
232       if (*option_arg == '\0')                  /* no argument after '=' */
233         Error(ERR_EXIT_HELP, "option '%s' has invalid argument", option_str);
234     }
235
236     option_len = strlen(option);
237
238     if (strcmp(option, "-") == 0)
239       Error(ERR_EXIT_HELP, "unrecognized option '%s'", option);
240     else if (strncmp(option, "-help", option_len) == 0)
241     {
242       printf("Usage: %s [options] [server.name [port]]\n"
243              "Options:\n"
244              "  -d, --display machine:0       X server display\n"
245              "  -l, --levels directory        alternative level directory\n"
246              "  -s, --serveronly              only start network server\n"
247              "  -n, --network                 network multiplayer game\n"
248              "  -v, --verbose                 verbose mode\n",
249              program_name);
250       exit(0);
251     }
252     else if (strncmp(option, "-display", option_len) == 0)
253     {
254       if (option_arg == NULL)
255         Error(ERR_EXIT_HELP, "option '%s' requires an argument", option_str);
256
257       options.display_name = option_arg;
258       if (option_arg == next_option)
259         options_left++;
260
261       printf("--display == '%s'\n", options.display_name);
262     }
263     else if (strncmp(option, "-levels", option_len) == 0)
264     {
265       if (option_arg == NULL)
266         Error(ERR_EXIT_HELP, "option '%s' requires an argument", option_str);
267
268       level_directory = option_arg;
269       if (option_arg == next_option)
270         options_left++;
271
272       printf("--levels == '%s'\n", level_directory);
273     }
274     else if (strncmp(option, "-network", option_len) == 0)
275     {
276       printf("--network\n");
277
278       options.network = TRUE;
279     }
280     else if (strncmp(option, "-serveronly", option_len) == 0)
281     {
282       printf("--serveronly\n");
283
284       options.serveronly = TRUE;
285     }
286     else if (strncmp(option, "-verbose", option_len) == 0)
287     {
288       printf("--verbose\n");
289
290       options.verbose = TRUE;
291     }
292     else if (*option == '-')
293       Error(ERR_EXIT_HELP, "unrecognized option '%s'", option_str);
294     else if (options.server_host == NULL)
295     {
296       options.server_host = *options_left;
297
298       printf("server.name == '%s'\n", options.server_host);
299     }
300     else if (options.server_port == 0)
301     {
302       options.server_port = atoi(*options_left);
303       if (options.server_port < 1024)
304         Error(ERR_EXIT_HELP, "bad port number '%d'", options.server_port);
305
306       printf("port == %d\n", options.server_port);
307     }
308     else
309       Error(ERR_EXIT_HELP, "too many arguments");
310
311     options_left++;
312   }
313 }
314
315 void Error(int mode, char *format_str, ...)
316 {
317   FILE *output_stream = stderr;
318   char *process_name = "";
319
320   if (mode == ERR_EXIT_SOUNDSERVER)
321     process_name = " sound server";
322
323   if (format_str)
324   {
325     va_list ap;
326     char *format_ptr;
327     char *s_value;
328     int i_value;
329     double d_value;
330
331     fprintf(output_stream, "%s%s: ", program_name, process_name);
332
333     va_start(ap, format_str);   /* ap points to first unnamed argument */
334   
335     for(format_ptr=format_str; *format_ptr; format_ptr++)
336     {
337       if (*format_ptr != '%')
338       {
339         fprintf(output_stream, "%c", *format_ptr);
340         continue;
341       }
342   
343       switch(*++format_ptr)
344       {
345         case 'd':
346           i_value = va_arg(ap, int);
347           fprintf(output_stream, "%d", i_value);
348           break;
349   
350         case 'f':
351           d_value = va_arg(ap, double);
352           fprintf(output_stream, "%f", d_value);
353           break;
354   
355         case 's':
356           s_value = va_arg(ap, char *);
357           fprintf(output_stream, "%s", s_value);
358           break;
359   
360         default:
361           fprintf(stderr, "\n%s: Error(): invalid format string: %s\n",
362                   program_name, format_str);
363           CloseAllAndExit(10);
364       }
365     }
366
367     va_end(ap);
368   
369     fprintf(output_stream, "\n");
370   }
371   
372   if (mode == ERR_EXIT_HELP)
373     fprintf(output_stream, "%s: Try option '--help' for more information.\n",
374             program_name);
375
376   if (mode != ERR_RETURN)
377   {
378     fprintf(output_stream, "%s%s: aborting\n", program_name, process_name);
379     CloseAllAndExit(1);
380   }
381 }
382
383 void *checked_malloc(unsigned long size)
384 {
385   void *ptr;
386
387   ptr = malloc(size);
388
389   if (ptr == NULL)
390     Error(ERR_EXIT, "cannot allocate %d bytes -- out of memory", size);
391
392   return ptr;
393 }