rnd-20020324-1-src
[rocksndiamonds.git] / src / libgame / system.c
1 /***********************************************************
2 * Artsoft Retro-Game Library                               *
3 *----------------------------------------------------------*
4 * (c) 1994-2001 Artsoft Entertainment                      *
5 *               Holger Schemel                             *
6 *               Detmolder Strasse 189                      *
7 *               33604 Bielefeld                            *
8 *               Germany                                    *
9 *               e-mail: info@artsoft.org                   *
10 *----------------------------------------------------------*
11 * system.c                                                 *
12 ***********************************************************/
13
14 #include <string.h>
15 #include <signal.h>
16
17 #include "platform.h"
18
19 #if defined(PLATFORM_MSDOS)
20 #include <fcntl.h>
21 #endif
22
23 #include "system.h"
24 #include "sound.h"
25 #include "setup.h"
26 #include "joystick.h"
27 #include "misc.h"
28
29
30 /* ========================================================================= */
31 /* exported variables                                                        */
32 /* ========================================================================= */
33
34 struct ProgramInfo      program;
35 struct OptionInfo       options;
36 struct VideoSystemInfo  video;
37 struct AudioSystemInfo  audio;
38 struct GfxInfo          gfx;
39 struct JoystickInfo     joystick;
40 struct SetupInfo        setup;
41
42 struct LevelDirInfo    *leveldir_first = NULL;
43 struct LevelDirInfo    *leveldir_current = NULL;
44 int                     level_nr;
45
46 Display                *display = NULL;
47 Visual                 *visual = NULL;
48 int                     screen = 0;
49 Colormap                cmap = None;
50
51 DrawWindow             *window = NULL;
52 DrawBuffer             *backbuffer = NULL;
53 DrawBuffer             *drawto = NULL;
54
55 int                     button_status = MB_NOT_PRESSED;
56 boolean                 motion_status = FALSE;
57
58 int                     redraw_mask = REDRAW_NONE;
59 int                     redraw_tiles = 0;
60
61 int                     FrameCounter = 0;
62
63
64 /* ========================================================================= */
65 /* init/close functions                                                      */
66 /* ========================================================================= */
67
68 void InitCommandName(char *argv0)
69 {
70   program.command_basename =
71     (strrchr(argv0, '/') ? strrchr(argv0, '/') + 1 : argv0);
72 }
73
74 void InitExitFunction(void (*exit_function)(int))
75 {
76   program.exit_function = exit_function;
77
78   /* set signal handlers to custom exit function */
79   signal(SIGINT, exit_function);
80   signal(SIGTERM, exit_function);
81
82 #if defined(TARGET_SDL)
83   /* set exit function to automatically cleanup SDL stuff after exit() */
84   atexit(SDL_Quit);
85 #endif
86 }
87
88 void InitPlatformDependantStuff(void)
89 {
90 #if defined(PLATFORM_MSDOS)
91   _fmode = O_BINARY;
92 #endif
93
94 #if !defined(PLATFORM_UNIX)
95   program.userdata_directory = "userdata";
96   initErrorFile();
97 #endif
98
99 #if defined(TARGET_SDL)
100   if (SDL_Init(SDL_INIT_EVENTTHREAD | SDL_INIT_NOPARACHUTE) < 0)
101     Error(ERR_EXIT, "SDL_Init() failed: %s", SDL_GetError());
102 #endif
103 }
104
105 void ClosePlatformDependantStuff(void)
106 {
107 #if !defined(PLATFORM_UNIX)
108   dumpErrorFile();
109 #endif
110 }
111
112 void InitProgramInfo(char *unix_userdata_directory, char *program_title,
113                      char *window_title, char *icon_title,
114                      char *x11_icon_basename, char *x11_iconmask_basename,
115                      char *msdos_pointer_basename,
116                      char *cookie_prefix, int program_version)
117 {
118   char *x11_icon_filename =
119     getPath2(options.graphics_directory, x11_icon_basename);
120   char *x11_iconmask_filename =
121     getPath2(options.graphics_directory, x11_iconmask_basename);
122   char *msdos_pointer_filename =
123     getPath2(options.graphics_directory, msdos_pointer_basename);
124
125 #if defined(PLATFORM_UNIX)
126   program.userdata_directory = unix_userdata_directory;
127 #else
128   program.userdata_directory = "userdata";
129 #endif
130
131   program.program_title = program_title;
132   program.window_title = window_title;
133   program.icon_title = icon_title;
134   program.x11_icon_filename = x11_icon_filename;
135   program.x11_iconmask_filename = x11_iconmask_filename;
136   program.msdos_pointer_filename = msdos_pointer_filename;
137   program.cookie_prefix = cookie_prefix;
138   program.version_major = VERSION_MAJOR(program_version);
139   program.version_minor = VERSION_MINOR(program_version);
140   program.version_patch = VERSION_PATCH(program_version);
141 }
142
143 void InitGfxFieldInfo(int sx, int sy, int sxsize, int sysize,
144                       int real_sx, int real_sy,
145                       int full_sxsize, int full_sysize)
146 {
147   gfx.sx = sx;
148   gfx.sy = sy;
149   gfx.sxsize = sxsize;
150   gfx.sysize = sysize;
151   gfx.real_sx = real_sx;
152   gfx.real_sy = real_sy;
153   gfx.full_sxsize = full_sxsize;
154   gfx.full_sysize = full_sysize;
155 }
156
157 void InitGfxDoor1Info(int dx, int dy, int dxsize, int dysize)
158 {
159   gfx.dx = dx;
160   gfx.dy = dy;
161   gfx.dxsize = dxsize;
162   gfx.dysize = dysize;
163 }
164
165 void InitGfxDoor2Info(int vx, int vy, int vxsize, int vysize)
166 {
167   gfx.vx = vx;
168   gfx.vy = vy;
169   gfx.vxsize = vxsize;
170   gfx.vysize = vysize;
171 }
172
173 void InitGfxScrollbufferInfo(int scrollbuffer_width, int scrollbuffer_height)
174 {
175   /* currently only used by MSDOS code to alloc VRAM buffer, if available */
176   gfx.scrollbuffer_width = scrollbuffer_width;
177   gfx.scrollbuffer_height = scrollbuffer_height;
178 }
179
180
181 /* ========================================================================= */
182 /* video functions                                                           */
183 /* ========================================================================= */
184
185 inline static int GetRealDepth(int depth)
186 {
187   return (depth == DEFAULT_DEPTH ? video.default_depth : depth);
188 }
189
190 inline void InitVideoDisplay(void)
191 {
192 #if defined(TARGET_SDL)
193   SDLInitVideoDisplay();
194 #else
195   X11InitVideoDisplay();
196 #endif
197 }
198
199 inline void CloseVideoDisplay(void)
200 {
201   KeyboardAutoRepeatOn();
202
203 #if defined(TARGET_SDL)
204   SDL_QuitSubSystem(SDL_INIT_VIDEO);
205 #else
206   if (display)
207     XCloseDisplay(display);
208 #endif
209 }
210
211 inline void InitVideoBuffer(DrawBuffer **backbuffer, DrawWindow **window,
212                             int width, int height, int depth,
213                             boolean fullscreen)
214 {
215   video.width = width;
216   video.height = height;
217   video.depth = GetRealDepth(depth);
218   video.fullscreen_available = FULLSCREEN_STATUS;
219   video.fullscreen_enabled = FALSE;
220
221 #ifdef TARGET_SDL
222   SDLInitVideoBuffer(backbuffer, window, fullscreen);
223 #else
224   X11InitVideoBuffer(backbuffer, window);
225 #endif
226 }
227
228 inline Bitmap *CreateBitmapStruct(void)
229 {
230 #ifdef TARGET_SDL
231   return checked_calloc(sizeof(struct SDLSurfaceInfo));
232 #else
233   return checked_calloc(sizeof(struct X11DrawableInfo));
234 #endif
235 }
236
237 inline Bitmap *CreateBitmap(int width, int height, int depth)
238 {
239   Bitmap *new_bitmap = CreateBitmapStruct();
240   int real_depth = GetRealDepth(depth);
241
242 #ifdef TARGET_SDL
243   SDL_Surface *surface_tmp, *surface_native;
244
245   if ((surface_tmp = SDL_CreateRGBSurface(SURFACE_FLAGS, width, height,
246                                           real_depth, 0, 0, 0, 0))
247       == NULL)
248     Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
249
250   if ((surface_native = SDL_DisplayFormat(surface_tmp)) == NULL)
251     Error(ERR_EXIT, "SDL_DisplayFormat() failed: %s", SDL_GetError());
252
253   SDL_FreeSurface(surface_tmp);
254
255   new_bitmap->surface = surface_native;
256 #else
257   Pixmap pixmap;
258
259   if ((pixmap = XCreatePixmap(display, window->drawable,
260                               width, height, real_depth))
261       == None)
262     Error(ERR_EXIT, "cannot create pixmap");
263
264   new_bitmap->drawable = pixmap;
265
266   if (window == NULL)
267     Error(ERR_EXIT, "Window GC needed for Bitmap -- create Window first");
268
269   new_bitmap->gc = window->gc;
270
271   new_bitmap->line_gc[0] = window->line_gc[0];
272   new_bitmap->line_gc[1] = window->line_gc[1];
273 #endif
274
275   return new_bitmap;
276 }
277
278 inline void FreeBitmap(Bitmap *bitmap)
279 {
280   if (bitmap == NULL)
281     return;
282
283 #ifdef TARGET_SDL
284   if (bitmap->surface)
285     SDL_FreeSurface(bitmap->surface);
286   if (bitmap->surface_masked)
287     SDL_FreeSurface(bitmap->surface_masked);
288 #else
289   if (bitmap->drawable)
290     XFreePixmap(display, bitmap->drawable);
291   if (bitmap->clip_mask)
292     XFreePixmap(display, bitmap->clip_mask);
293   if (bitmap->stored_clip_gc)
294     XFreeGC(display, bitmap->stored_clip_gc);
295 #endif
296
297   free(bitmap);
298 }
299
300 inline void CloseWindow(DrawWindow *window)
301 {
302 #ifdef TARGET_X11
303   if (window->drawable)
304   {
305     XUnmapWindow(display, window->drawable);
306     XDestroyWindow(display, window->drawable);
307   }
308   if (window->gc)
309     XFreeGC(display, window->gc);
310 #endif
311 }
312
313 inline void BlitBitmap(Bitmap *src_bitmap, Bitmap *dst_bitmap,
314                        int src_x, int src_y,
315                        int width, int height,
316                        int dst_x, int dst_y)
317 {
318 #ifdef TARGET_SDL
319   SDLCopyArea(src_bitmap, dst_bitmap,
320               src_x, src_y, width, height, dst_x, dst_y, SDLCOPYAREA_OPAQUE);
321 #else
322   XCopyArea(display, src_bitmap->drawable, dst_bitmap->drawable,
323             dst_bitmap->gc, src_x, src_y, width, height, dst_x, dst_y);
324 #endif
325 }
326
327 inline void ClearRectangle(Bitmap *bitmap, int x, int y, int width, int height)
328 {
329 #ifdef TARGET_SDL
330   SDLFillRectangle(bitmap, x, y, width, height, 0x000000);
331 #else
332   XFillRectangle(display, bitmap->drawable, bitmap->gc, x, y, width, height);
333 #endif
334 }
335
336 #if 0
337 #ifndef TARGET_SDL
338 static GC last_clip_gc = 0;     /* needed for XCopyArea() through clip mask */
339 #endif
340 #endif
341
342 inline void SetClipMask(Bitmap *bitmap, GC clip_gc, Pixmap clip_pixmap)
343 {
344 #ifdef TARGET_X11
345   if (clip_gc)
346   {
347     bitmap->clip_gc = clip_gc;
348     XSetClipMask(display, bitmap->clip_gc, clip_pixmap);
349   }
350 #if 0
351   last_clip_gc = clip_gc;
352 #endif
353 #endif
354 }
355
356 inline void SetClipOrigin(Bitmap *bitmap, GC clip_gc, int clip_x, int clip_y)
357 {
358 #ifdef TARGET_X11
359   if (clip_gc)
360   {
361     bitmap->clip_gc = clip_gc;
362     XSetClipOrigin(display, bitmap->clip_gc, clip_x, clip_y);
363   }
364 #if 0
365   last_clip_gc = clip_gc;
366 #endif
367 #endif
368 }
369
370 inline void BlitBitmapMasked(Bitmap *src_bitmap, Bitmap *dst_bitmap,
371                              int src_x, int src_y,
372                              int width, int height,
373                              int dst_x, int dst_y)
374 {
375 #ifdef TARGET_SDL
376   SDLCopyArea(src_bitmap, dst_bitmap,
377               src_x, src_y, width, height, dst_x, dst_y, SDLCOPYAREA_MASKED);
378 #else
379   XCopyArea(display, src_bitmap->drawable, dst_bitmap->drawable,
380             src_bitmap->clip_gc, src_x, src_y, width, height, dst_x, dst_y);
381 #endif
382 }
383
384 inline void DrawSimpleWhiteLine(Bitmap *bitmap, int from_x, int from_y,
385                                 int to_x, int to_y)
386 {
387 #ifdef TARGET_SDL
388   SDLDrawSimpleLine(bitmap, from_x, from_y, to_x, to_y, 0xffffff);
389 #else
390   XSetForeground(display, bitmap->gc, WhitePixel(display, screen));
391   XDrawLine(display, bitmap->drawable, bitmap->gc, from_x, from_y, to_x, to_y);
392   XSetForeground(display, bitmap->gc, BlackPixel(display, screen));
393 #endif
394 }
395
396 #if !defined(TARGET_X11_NATIVE)
397 inline void DrawLine(Bitmap *bitmap, int from_x, int from_y,
398                      int to_x, int to_y, Pixel pixel, int line_width)
399 {
400   int x, y;
401
402   for (x=0; x<line_width; x++)
403   {
404     for (y=0; y<line_width; y++)
405     {
406       int dx = x - line_width / 2;
407       int dy = y - line_width / 2;
408
409       if ((x == 0 && y == 0) ||
410           (x == 0 && y == line_width - 1) ||
411           (x == line_width - 1 && y == 0) ||
412           (x == line_width - 1 && y == line_width - 1))
413         continue;
414
415 #if defined(TARGET_SDL)
416       SDLDrawLine(bitmap,
417                   from_x + dx, from_y + dy, to_x + dx, to_y + dy, pixel);
418 #elif defined(TARGET_ALLEGRO)
419       AllegroDrawLine(bitmap->drawable, from_x + dx, from_y + dy,
420                       to_x + dx, to_y + dy, pixel);
421 #endif
422     }
423   }
424 }
425 #endif
426
427 inline void DrawLines(Bitmap *bitmap, struct XY *points, int num_points,
428                       Pixel pixel)
429 {
430 #if !defined(TARGET_X11_NATIVE)
431   int line_width = 4;
432   int i;
433
434   for (i=0; i<num_points - 1; i++)
435     DrawLine(bitmap, points[i].x, points[i].y,
436              points[i + 1].x, points[i + 1].y, pixel, line_width);
437
438   /*
439   SDLDrawLines(bitmap->surface, points, num_points, pixel);
440   */
441 #else
442   XSetForeground(display, bitmap->line_gc[1], pixel);
443   XDrawLines(display, bitmap->drawable, bitmap->line_gc[1],
444              (XPoint *)points, num_points, CoordModeOrigin);
445   /*
446   XSetForeground(display, gc, BlackPixel(display, screen));
447   */
448 #endif
449 }
450
451 inline Pixel GetPixel(Bitmap *bitmap, int x, int y)
452 {
453 #if defined(TARGET_SDL)
454   return SDLGetPixel(bitmap, x, y);
455 #elif defined(TARGET_ALLEGRO)
456   return AllegroGetPixel(bitmap->drawable, x, y);
457 #else
458   unsigned long pixel_value;
459   XImage *pixel_image;
460
461   pixel_image = XGetImage(display, bitmap->drawable, x, y, 1, 1,
462                           AllPlanes, ZPixmap);
463   pixel_value = XGetPixel(pixel_image, 0, 0);
464
465   XDestroyImage(pixel_image);
466
467   return pixel_value;
468 #endif
469 }
470
471 inline Pixel GetPixelFromRGB(Bitmap *bitmap, unsigned int color_r,
472                              unsigned int color_g, unsigned int color_b)
473 {
474   Pixel pixel;
475
476 #if defined(TARGET_SDL)
477   pixel = SDL_MapRGB(bitmap->surface->format, color_r, color_g, color_b);
478 #elif defined(TARGET_ALLEGRO)
479   pixel = AllegroAllocColorCell(color_r << 8, color_g << 8, color_b << 8);
480 #elif defined(TARGET_X11_NATIVE)
481   XColor xcolor;
482
483   xcolor.flags = DoRed | DoGreen | DoBlue;
484   xcolor.red = (color_r << 8);
485   xcolor.green = (color_g << 8);
486   xcolor.blue = (color_b << 8);
487   XAllocColor(display, cmap, &xcolor);
488   pixel = xcolor.pixel;
489 #endif
490
491   return pixel;
492 }
493
494 inline Pixel GetPixelFromRGBcompact(Bitmap *bitmap, unsigned int color)
495 {
496   unsigned int color_r = (color >> 16) & 0xff;
497   unsigned int color_g = (color >>  8) & 0xff;
498   unsigned int color_b = (color >>  0) & 0xff;
499
500   return GetPixelFromRGB(bitmap, color_r, color_g, color_b);
501 }
502
503 /* execute all pending screen drawing operations */
504 inline void FlushDisplay(void)
505 {
506 #ifndef TARGET_SDL
507   XFlush(display);
508 #endif
509 }
510
511 /* execute and wait for all pending screen drawing operations */
512 inline void SyncDisplay(void)
513 {
514 #ifndef TARGET_SDL
515   XSync(display, FALSE);
516 #endif
517 }
518
519 inline void KeyboardAutoRepeatOn(void)
520 {
521 #ifdef TARGET_SDL
522   SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY / 2,
523                       SDL_DEFAULT_REPEAT_INTERVAL / 2);
524   SDL_EnableUNICODE(1);
525 #else
526   if (display)
527     XAutoRepeatOn(display);
528 #endif
529 }
530
531 inline void KeyboardAutoRepeatOff(void)
532 {
533 #ifdef TARGET_SDL
534   SDL_EnableKeyRepeat(0, SDL_DEFAULT_REPEAT_INTERVAL);
535   SDL_EnableUNICODE(0);
536 #else
537   if (display)
538     XAutoRepeatOff(display);
539 #endif
540 }
541
542 inline boolean PointerInWindow(DrawWindow *window)
543 {
544 #ifdef TARGET_SDL
545   return TRUE;
546 #else
547   Window root, child;
548   int root_x, root_y;
549   unsigned int mask;
550   int win_x, win_y;
551
552   /* if XQueryPointer() returns False, the pointer
553      is not on the same screen as the specified window */
554   return XQueryPointer(display, window->drawable, &root, &child,
555                        &root_x, &root_y, &win_x, &win_y, &mask);
556 #endif
557 }
558
559 inline boolean SetVideoMode(boolean fullscreen)
560 {
561 #ifdef TARGET_SDL
562   return SDLSetVideoMode(&backbuffer, fullscreen);
563 #else
564   boolean success = TRUE;
565
566   if (fullscreen && video.fullscreen_available)
567   {
568     Error(ERR_WARN, "fullscreen not available in X11 version");
569
570     /* display error message only once */
571     video.fullscreen_available = FALSE;
572
573     success = FALSE;
574   }
575
576   return success;
577 #endif
578 }
579
580 inline boolean ChangeVideoModeIfNeeded(boolean fullscreen)
581 {
582 #ifdef TARGET_SDL
583   if ((fullscreen && !video.fullscreen_enabled && video.fullscreen_available)||
584       (!fullscreen && video.fullscreen_enabled))
585     fullscreen = SetVideoMode(fullscreen);
586 #endif
587
588   return fullscreen;
589 }
590
591 Bitmap *LoadImage(char *basename)
592 {
593   Bitmap *new_bitmap;
594   char *filename = getPath2(options.graphics_directory, basename);
595
596 #if defined(TARGET_SDL)
597   new_bitmap = SDLLoadImage(filename);
598 #else
599   new_bitmap = X11LoadImage(filename);
600 #endif
601
602   free(filename);
603
604   return new_bitmap;
605 }
606
607
608 /* ========================================================================= */
609 /* audio functions                                                           */
610 /* ========================================================================= */
611
612 inline void OpenAudio(void)
613 {
614   /* always start with reliable default values */
615   audio.sound_available = FALSE;
616   audio.music_available = FALSE;
617   audio.loops_available = FALSE;
618   audio.mods_available = FALSE;
619   audio.sound_enabled = FALSE;
620
621   audio.soundserver_pipe[0] = audio.soundserver_pipe[1] = 0;
622   audio.soundserver_pid = 0;
623   audio.device_name = NULL;
624   audio.device_fd = 0;
625
626   audio.channels = 0;
627   audio.music_channel = 0;
628   audio.music_nr = 0;
629
630 #if defined(TARGET_SDL)
631   SDLOpenAudio();
632 #elif defined(PLATFORM_UNIX)
633   UnixOpenAudio();
634 #elif defined(PLATFORM_MSDOS)
635   MSDOSOpenAudio();
636 #endif
637 }
638
639 inline void CloseAudio(void)
640 {
641 #if defined(TARGET_SDL)
642   SDLCloseAudio();
643 #elif defined(PLATFORM_UNIX)
644   UnixCloseAudio();
645 #elif defined(PLATFORM_MSDOS)
646   MSDOSCloseAudio();
647 #endif
648
649   audio.sound_enabled = FALSE;
650 }
651
652 inline void SetAudioMode(boolean enabled)
653 {
654   if (!audio.sound_available)
655     return;
656
657   audio.sound_enabled = enabled;
658 }
659
660
661 /* ========================================================================= */
662 /* event functions                                                           */
663 /* ========================================================================= */
664
665 inline void InitEventFilter(EventFilter filter_function)
666 {
667 #ifdef TARGET_SDL
668   /* set event filter to filter out certain events */
669   SDL_SetEventFilter(filter_function);
670 #endif
671 }
672
673 inline boolean PendingEvent(void)
674 {
675 #ifdef TARGET_SDL
676   return (SDL_PollEvent(NULL) ? TRUE : FALSE);
677 #else
678   return (XPending(display) ? TRUE : FALSE);
679 #endif
680 }
681
682 inline void NextEvent(Event *event)
683 {
684 #ifdef TARGET_SDL
685   SDLNextEvent(event);
686 #else
687   XNextEvent(display, event);
688 #endif
689 }
690
691 inline Key GetEventKey(KeyEvent *event, boolean with_modifiers)
692 {
693 #ifdef TARGET_SDL
694 #if 0
695   printf("unicode == '%d', sym == '%d', mod == '0x%04x'\n",
696          (int)event->keysym.unicode,
697          (int)event->keysym.sym,
698          (int)SDL_GetModState());
699 #endif
700
701   if (with_modifiers && event->keysym.unicode != 0)
702     return event->keysym.unicode;
703   else
704     return event->keysym.sym;
705 #else
706 #if 0
707   printf("with modifiers == '0x%04x', without modifiers == '0x%04x'\n",
708          (int)XLookupKeysym(event, event->state),
709          (int)XLookupKeysym(event, 0));
710 #endif
711
712   if (with_modifiers)
713     return XLookupKeysym(event, event->state);
714   else
715     return XLookupKeysym(event, 0);
716 #endif
717 }
718
719 inline boolean CheckCloseWindowEvent(ClientMessageEvent *event)
720 {
721   if (event->type != EVENT_CLIENTMESSAGE)
722     return FALSE;
723
724 #if defined(TARGET_SDL)
725   return TRUE;          /* the only possible message here is SDL_QUIT */
726 #elif defined(PLATFORM_UNIX)
727   if ((event->window == window->drawable) &&
728       (event->data.l[0] == XInternAtom(display, "WM_DELETE_WINDOW", FALSE)))
729     return TRUE;
730 #endif
731
732   return FALSE;
733 }
734
735
736 /* ========================================================================= */
737 /* joystick functions                                                        */
738 /* ========================================================================= */
739
740 inline void InitJoysticks()
741 {
742   int i;
743
744 #ifdef NO_JOYSTICK
745   return;       /* joysticks generally deactivated by compile-time directive */
746 #endif
747
748   /* always start with reliable default values */
749   joystick.status = JOYSTICK_NOT_AVAILABLE;
750   for (i=0; i<MAX_PLAYERS; i++)
751     joystick.fd[i] = -1;                /* joystick device closed */
752
753 #if defined(TARGET_SDL)
754   SDLInitJoysticks();
755 #elif defined(PLATFORM_UNIX)
756   UnixInitJoysticks();
757 #elif defined(PLATFORM_MSDOS)
758   MSDOSInitJoysticks();
759 #endif
760 }
761
762 inline boolean ReadJoystick(int nr, int *x, int *y, boolean *b1, boolean *b2)
763 {
764 #if defined(TARGET_SDL)
765   return SDLReadJoystick(nr, x, y, b1, b2);
766 #elif defined(PLATFORM_UNIX)
767   return UnixReadJoystick(nr, x, y, b1, b2);
768 #elif defined(PLATFORM_MSDOS)
769   return MSDOSReadJoystick(nr, x, y, b1, b2);
770 #endif
771 }