rnd-19981003-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              "  -v, --verbose                 verbose mode\n",
237              program_name);
238       exit(0);
239     }
240     else if (strncmp(option, "-display", option_len) == 0)
241     {
242       if (option_arg == NULL)
243         Error(ERR_EXIT_HELP, "option '%s' requires an argument", option_str);
244
245       display_name = option_arg;
246       if (option_arg == next_option)
247         options_left++;
248
249       printf("--display == '%s'\n", display_name);
250     }
251     else if (strncmp(option, "-levels", option_len) == 0)
252     {
253       if (option_arg == NULL)
254         Error(ERR_EXIT_HELP, "option '%s' requires an argument", option_str);
255
256       level_directory = option_arg;
257       if (option_arg == next_option)
258         options_left++;
259
260       printf("--levels == '%s'\n", level_directory);
261     }
262     else if (strncmp(option, "-verbose", option_len) == 0)
263     {
264       printf("--verbose\n");
265
266       verbose = TRUE;
267     }
268     else if (*option == '-')
269       Error(ERR_EXIT_HELP, "unrecognized option '%s'", option_str);
270     else if (server_host == NULL)
271     {
272       server_host = *options_left;
273
274       printf("server.name == '%s'\n", server_host);
275     }
276     else if (server_port == 0)
277     {
278       server_port = atoi(*options_left);
279       if (server_port < 1024)
280         Error(ERR_EXIT_HELP, "bad port number '%d'", server_port);
281
282       printf("port == %d\n", server_port);
283     }
284     else
285       Error(ERR_EXIT_HELP, "too many arguments");
286
287     options_left++;
288   }
289 }
290
291 void Error(int mode, char *format_str, ...)
292 {
293   FILE *output_stream = stderr;
294   char *process_name = "";
295
296   if (mode == ERR_EXIT_SOUNDSERVER)
297     process_name = " sound server";
298
299   if (format_str)
300   {
301     va_list ap;
302     char *format_ptr;
303     char *s_value;
304     int i_value;
305     double d_value;
306
307     fprintf(output_stream, "%s%s: ", program_name, process_name);
308
309     va_start(ap, format_str);   /* ap points to first unnamed argument */
310   
311     for(format_ptr=format_str; *format_ptr; format_ptr++)
312     {
313       if (*format_ptr != '%')
314       {
315         fprintf(output_stream, "%c", *format_ptr);
316         continue;
317       }
318   
319       switch(*++format_ptr)
320       {
321         case 'd':
322           i_value = va_arg(ap, int);
323           fprintf(output_stream, "%d", i_value);
324           break;
325   
326         case 'f':
327           d_value = va_arg(ap, double);
328           fprintf(output_stream, "%f", d_value);
329           break;
330   
331         case 's':
332           s_value = va_arg(ap, char *);
333           fprintf(output_stream, "%s", s_value);
334           break;
335   
336         default:
337           fprintf(stderr, "\n%s: Error(): invalid format string: %s\n",
338                   program_name, format_str);
339           CloseAllAndExit(10);
340       }
341     }
342
343     va_end(ap);
344   
345     fprintf(output_stream, "\n");
346   }
347   
348   if (mode == ERR_EXIT_HELP)
349     fprintf(output_stream, "%s: Try option '--help' for more information.\n",
350             program_name);
351
352   if (mode != ERR_RETURN)
353   {
354     fprintf(output_stream, "%s%s: aborting\n", program_name, process_name);
355     CloseAllAndExit(1);
356   }
357 }