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