1 /***********************************************************
2 * Rocks'n'Diamonds -- McDuffin Strikes Back! *
3 *----------------------------------------------------------*
4 * ©1995 Artsoft Development *
6 * 33659 Bielefeld-Senne *
7 * Telefon: (0521) 493245 *
8 * eMail: aeglos@valinor.owl.de *
9 * aeglos@uni-paderborn.de *
10 * q99492@pbhrzx.uni-paderborn.de *
11 *----------------------------------------------------------*
13 ***********************************************************/
25 /* allegro driver declarations */
26 DECLARE_GFX_DRIVER_LIST(GFX_DRIVER_VBEAF GFX_DRIVER_VESA2L GFX_DRIVER_VESA1)
27 DECLARE_COLOR_DEPTH_LIST(COLOR_DEPTH_8)
28 DECLARE_DIGI_DRIVER_LIST(DIGI_DRIVER_SB)
29 DECLARE_MIDI_DRIVER_LIST()
30 DECLARE_JOYSTICK_DRIVER_LIST(JOYSTICK_DRIVER_STANDARD)
32 /* allegro global variables */
33 extern volatile int key_shifts;
34 extern int num_joysticks;
35 extern JOYSTICK_INFO joy[];
36 extern int i_love_bill;
38 /* internal variables of msdos.c */
39 static int key_press_state[MAX_SCANCODES];
40 static XEvent event_buffer[MAX_EVENT_BUFFER];
41 static int pending_events;
42 static boolean joystick_event;
43 static boolean mouse_installed = FALSE;
44 static int last_mouse_pos;
45 static int last_mouse_b;
46 static int last_joystick_state;
47 static BITMAP* video_bitmap;
49 static RGB global_colormap[MAX_COLORS];
50 static int global_colormap_entries_used = 0;
52 boolean wait_for_vsync;
54 extern int playing_sounds;
55 extern struct SoundControl playlist[MAX_SOUNDS_PLAYING];
56 extern struct SoundControl emptySoundControl;
58 static BITMAP *Read_PCX_to_AllegroBitmap(char *);
60 static void allegro_drivers()
64 for (i=0; i<MAX_EVENT_BUFFER; i++)
65 event_buffer[i].type = 0;
67 for (i=0; i<MAX_SCANCODES; i++)
68 key_press_state[i] = KeyReleaseMask;
70 last_mouse_pos = mouse_pos;
76 /* enable Windows friendly timer mode (already default under Windows) */
81 if (install_mouse() > 0)
82 mouse_installed = TRUE;
84 last_joystick_state = 0;
85 joystick_event = FALSE;
87 reserve_voices(MAX_SOUNDS_PLAYING, 0);
88 if (install_sound(DIGI_AUTODETECT, MIDI_NONE, "ROCKS.SND") == -1)
89 if (install_sound(DIGI_SB, MIDI_NONE, NULL) == -1)
90 sound_status = SOUND_OFF;
93 static boolean hide_mouse(Display *display, int x, int y,
94 unsigned int width, unsigned int height)
96 if (mouse_x + display->mouse_ptr->w < x || mouse_x > x + width)
98 if (mouse_y + display->mouse_ptr->h < y || mouse_y > y + height)
106 static void unhide_mouse(Display *display)
109 show_mouse(video_bitmap);
112 static KeySym ScancodeToKeySym(byte scancode)
116 case KEY_ESC: return XK_Escape;
117 case KEY_1: return XK_1;
118 case KEY_2: return XK_2;
119 case KEY_3: return XK_3;
120 case KEY_4: return XK_4;
121 case KEY_5: return XK_5;
122 case KEY_6: return XK_6;
123 case KEY_7: return XK_7;
124 case KEY_8: return XK_8;
125 case KEY_9: return XK_9;
126 case KEY_0: return XK_0;
127 case KEY_MINUS: return XK_minus;
128 case KEY_EQUALS: return XK_equal;
129 case KEY_BACKSPACE: return XK_BackSpace;
130 case KEY_TAB: return XK_Tab;
131 case KEY_Q: return XK_q;
132 case KEY_W: return XK_w;
133 case KEY_E: return XK_e;
134 case KEY_R: return XK_r;
135 case KEY_T: return XK_t;
136 case KEY_Y: return XK_y;
137 case KEY_U: return XK_u;
138 case KEY_I: return XK_i;
139 case KEY_O: return XK_o;
140 case KEY_P: return XK_p;
141 case KEY_OPENBRACE: return XK_braceleft;
142 case KEY_CLOSEBRACE: return XK_braceright;
143 case KEY_ENTER: return XK_Return;
144 case KEY_LCONTROL: return XK_Control_L;
145 case KEY_A: return XK_a;
146 case KEY_S: return XK_s;
147 case KEY_D: return XK_d;
148 case KEY_F: return XK_f;
149 case KEY_G: return XK_g;
150 case KEY_H: return XK_h;
151 case KEY_J: return XK_j;
152 case KEY_K: return XK_k;
153 case KEY_L: return XK_l;
154 case KEY_COLON: return XK_colon;
155 case KEY_QUOTE: return XK_apostrophe;
156 case KEY_TILDE: return XK_asciitilde;
157 case KEY_LSHIFT: return XK_Shift_L;
158 case KEY_BACKSLASH: return XK_backslash;
159 case KEY_Z: return XK_z;
160 case KEY_X: return XK_x;
161 case KEY_C: return XK_c;
162 case KEY_V: return XK_v;
163 case KEY_B: return XK_b;
164 case KEY_N: return XK_n;
165 case KEY_M: return XK_m;
166 case KEY_COMMA: return XK_comma;
167 case KEY_STOP: return XK_period;
168 case KEY_SLASH: return XK_slash;
169 case KEY_RSHIFT: return XK_Shift_R;
170 case KEY_ASTERISK: return XK_KP_Multiply;
171 case KEY_ALT: return XK_Alt_L;
172 case KEY_SPACE: return XK_space;
173 case KEY_CAPSLOCK: return XK_Caps_Lock;
174 case KEY_F1: return XK_F1;
175 case KEY_F2: return XK_F2;
176 case KEY_F3: return XK_F3;
177 case KEY_F4: return XK_F4;
178 case KEY_F5: return XK_F5;
179 case KEY_F6: return XK_F6;
180 case KEY_F7: return XK_F7;
181 case KEY_F8: return XK_F8;
182 case KEY_F9: return XK_F9;
183 case KEY_F10: return XK_F10;
184 case KEY_NUMLOCK: return XK_Num_Lock;
185 case KEY_SCRLOCK: return XK_Scroll_Lock;
186 case KEY_HOME: return XK_Home;
187 case KEY_UP: return XK_Up;
188 case KEY_PGUP: return XK_Page_Up;
189 case KEY_MINUS_PAD: return XK_KP_Subtract;
190 case KEY_LEFT: return XK_Left;
191 case KEY_5_PAD: return XK_KP_5;
192 case KEY_RIGHT: return XK_Right;
193 case KEY_PLUS_PAD: return XK_KP_Add;
194 case KEY_END: return XK_End;
195 case KEY_DOWN: return XK_Down;
196 case KEY_PGDN: return XK_Page_Down;
197 case KEY_INSERT: return XK_Insert;
198 case KEY_DEL: return XK_Delete;
199 case KEY_PRTSCR: return XK_Print;
200 case KEY_F11: return XK_F11;
201 case KEY_F12: return XK_F12;
202 case KEY_LWIN: return XK_Meta_L;
203 case KEY_RWIN: return XK_Meta_R;
204 case KEY_MENU: return XK_Menu;
205 case KEY_PAD: return XK_VoidSymbol;
206 case KEY_RCONTROL: return XK_Control_R;
207 case KEY_ALTGR: return XK_Alt_R;
208 case KEY_SLASH2: return XK_KP_Divide;
209 case KEY_PAUSE: return XK_Pause;
211 case NEW_KEY_BACKSLASH: return XK_backslash;
212 case NEW_KEY_1_PAD: return XK_KP_1;
213 case NEW_KEY_2_PAD: return XK_KP_2;
214 case NEW_KEY_3_PAD: return XK_KP_3;
215 case NEW_KEY_4_PAD: return XK_KP_4;
216 case NEW_KEY_5_PAD: return XK_KP_5;
217 case NEW_KEY_6_PAD: return XK_KP_6;
218 case NEW_KEY_7_PAD: return XK_KP_7;
219 case NEW_KEY_8_PAD: return XK_KP_8;
220 case NEW_KEY_9_PAD: return XK_KP_9;
221 case NEW_KEY_0_PAD: return XK_KP_0;
222 case NEW_KEY_STOP_PAD: return XK_KP_Separator;
223 case NEW_KEY_EQUALS_PAD: return XK_KP_Equal;
224 case NEW_KEY_SLASH_PAD: return XK_KP_Divide;
225 case NEW_KEY_ASTERISK_PAD: return XK_KP_Multiply;
226 case NEW_KEY_ENTER_PAD: return XK_KP_Enter;
228 default: return XK_VoidSymbol;
232 void XMapWindow(Display *display, Window window)
235 unsigned int width, height;
238 x = display->screens[display->default_screen].x;
239 y = display->screens[display->default_screen].y;
240 width = display->screens[display->default_screen].width;
241 height = display->screens[display->default_screen].height;
243 mouse_off = hide_mouse(display, x, y, width, height);
244 blit((BITMAP *)window, video_bitmap, 0, 0, x, y, width, height);
247 unhide_mouse(display);
250 Display *XOpenDisplay(char *display_name)
254 BITMAP *mouse_bitmap = NULL;
257 filename = getPath3(options.base_directory, GRAPHICS_DIRECTORY,
260 mouse_bitmap = Read_PCX_to_AllegroBitmap(filename);
263 if (mouse_bitmap == NULL)
266 screen = malloc(sizeof(Screen));
267 display = malloc(sizeof(Display));
271 screen[0].white_pixel = 0xFF;
272 screen[0].black_pixel = 0x00;
273 screen[0].video_bitmap = NULL;
275 display->default_screen = 0;
276 display->screens = screen;
277 display->mouse_ptr = mouse_bitmap;
283 /* force Windows 95 to switch to fullscreen mode */
284 set_gfx_mode(GFX_AUTODETECT, 320, 200, 0, 0);
286 set_gfx_mode(GFX_AUTODETECT, XRES, YRES, 0, 0);
291 Window XCreateSimpleWindow(Display *display, Window parent, int x, int y,
292 unsigned int width, unsigned int height,
293 unsigned int border_width, unsigned long border,
294 unsigned long background)
296 video_bitmap = create_video_bitmap(XRES, YRES);
297 clear_to_color(video_bitmap, background);
299 display->screens[display->default_screen].video_bitmap = video_bitmap;
300 display->screens[display->default_screen].x = x;
301 display->screens[display->default_screen].y = y;
302 display->screens[display->default_screen].width = XRES;
303 display->screens[display->default_screen].height = YRES;
305 set_mouse_sprite(display->mouse_ptr);
306 set_mouse_speed(1, 1);
307 set_mouse_range(display->screens[display->default_screen].x + 1,
308 display->screens[display->default_screen].y + 1,
309 display->screens[display->default_screen].x + WIN_XSIZE + 1,
310 display->screens[display->default_screen].y + WIN_YSIZE + 1);
312 show_video_bitmap(video_bitmap);
314 return (Window)video_bitmap;
317 Status XStringListToTextProperty(char **list, int count,
318 XTextProperty *text_prop_return)
324 string = malloc(strlen(list[0] + 1));
325 strcpy(string, list[0]);
326 text_prop_return->value = (unsigned char *)string;
330 text_prop_return = NULL;
335 void XFree(void *data)
341 GC XCreateGC(Display *display, Drawable d, unsigned long value_mask,
345 gcv = malloc(sizeof(XGCValues));
346 gcv->foreground = values->foreground;
347 gcv->background = values->background;
348 gcv->graphics_exposures = values->graphics_exposures;
349 gcv->clip_mask = values->clip_mask;
350 gcv->clip_x_origin = values->clip_x_origin;
351 gcv->clip_y_origin = values->clip_y_origin;
352 gcv->value_mask = value_mask;
356 void XSetClipMask(Display *display, GC gc, Pixmap pixmap)
358 XGCValues *gcv = (XGCValues *)gc;
360 gcv->clip_mask = pixmap;
361 gcv->value_mask |= GCClipMask;
364 void XSetClipOrigin(Display *display, GC gc, int x, int y)
366 XGCValues *gcv = (XGCValues *)gc;
368 gcv->clip_x_origin = x;
369 gcv->clip_x_origin = y;
372 void XFillRectangle(Display *display, Drawable d, GC gc, int x, int y,
373 unsigned int width, unsigned int height)
375 boolean mouse_off = FALSE;
377 if ((BITMAP *)d == video_bitmap)
379 x += display->screens[display->default_screen].x;
380 y += display->screens[display->default_screen].y;
381 freeze_mouse_flag = TRUE;
382 mouse_off = hide_mouse(display, x, y, width, height);
385 rectfill((BITMAP *)d, x, y, x + width, y + height,
386 ((XGCValues *)gc)->foreground);
389 unhide_mouse(display);
391 freeze_mouse_flag = FALSE;
394 Pixmap XCreatePixmap(Display *display, Drawable d, unsigned int width,
395 unsigned int height, unsigned int depth)
397 BITMAP *bitmap = NULL;
399 if (gfx_capabilities & GFX_HW_VRAM_BLIT &&
400 width == FXSIZE && height == FYSIZE)
401 bitmap = create_video_bitmap(width, height);
404 bitmap = create_bitmap(width, height);
406 return (Pixmap)bitmap;
409 void XSync(Display *display, Bool discard_events)
411 wait_for_vsync = TRUE;
414 inline void XCopyArea(Display *display, Drawable src, Drawable dest, GC gc,
415 int src_x, int src_y,
416 unsigned int width, unsigned int height,
417 int dest_x, int dest_y)
419 boolean mouse_off = FALSE;
421 if ((BITMAP *)src == video_bitmap)
423 src_x += display->screens[display->default_screen].x;
424 src_y += display->screens[display->default_screen].y;
427 if ((BITMAP *)dest == video_bitmap)
429 dest_x += display->screens[display->default_screen].x;
430 dest_y += display->screens[display->default_screen].y;
431 freeze_mouse_flag = TRUE;
432 mouse_off = hide_mouse(display, dest_x, dest_y, width, height);
437 wait_for_vsync = FALSE;
441 if (((XGCValues *)gc)->value_mask & GCClipMask)
442 masked_blit((BITMAP *)src, (BITMAP *)dest, src_x, src_y, dest_x, dest_y,
445 blit((BITMAP *)src, (BITMAP *)dest, src_x, src_y, dest_x, dest_y,
449 unhide_mouse(display);
451 freeze_mouse_flag = FALSE;
454 static BITMAP *Image_to_AllegroBitmap(Image *image)
457 byte *src_ptr = image->data;
458 byte pixel_mapping[MAX_COLORS];
459 unsigned int depth = 8;
462 /* allocate new allegro bitmap structure */
463 if ((bitmap = create_bitmap_ex(depth, image->width, image->height)) == NULL)
468 /* try to use existing colors from the global colormap */
469 for (i=0; i<MAX_COLORS; i++)
473 if (!image->rgb.color_used[i])
476 r = image->rgb.red[i] >> 10;
477 g = image->rgb.green[i] >> 10;
478 b = image->rgb.blue[i] >> 10;
480 for (j=0; j<global_colormap_entries_used; j++)
482 if (r == global_colormap[j].r &&
483 g == global_colormap[j].g &&
484 b == global_colormap[j].b) /* color found */
486 pixel_mapping[i] = j;
491 if (j == global_colormap_entries_used) /* color not found */
493 if (global_colormap_entries_used < MAX_COLORS)
494 global_colormap_entries_used++;
496 global_colormap[j].r = r;
497 global_colormap[j].g = g;
498 global_colormap[j].b = b;
500 pixel_mapping[i] = j;
504 /* copy bitmap data */
505 for (y=0; y<image->height; y++)
506 for (x=0; x<image->width; x++)
507 putpixel(bitmap, x, y, pixel_mapping[*src_ptr++]);
512 static BITMAP *Read_PCX_to_AllegroBitmap(char *filename)
517 /* read the graphic file in PCX format to internal image structure */
518 if ((image = Read_PCX_to_Image(filename)) == NULL)
521 /* convert internal image structure to allegro bitmap structure */
522 if ((bitmap = Image_to_AllegroBitmap(image)) == NULL)
525 set_pallete(global_colormap);
530 int Read_PCX_to_Pixmap(Display *display, Window window, GC gc, char *filename,
531 Pixmap *pixmap, Pixmap *pixmap_mask)
535 if ((bitmap = Read_PCX_to_AllegroBitmap(filename)) == NULL)
536 return PCX_FileInvalid;
538 *pixmap = (Pixmap)bitmap;
539 *pixmap_mask = (Pixmap)bitmap;
544 int XpmReadFileToPixmap(Display *display, Drawable d, char *filename,
545 Pixmap *pixmap_return, Pixmap *shapemask_return,
546 XpmAttributes *attributes)
550 if ((bitmap = Read_PCX_to_AllegroBitmap(filename)) == NULL)
551 return XpmOpenFailed;
553 *pixmap_return = (Pixmap)bitmap;
558 int XReadBitmapFile(Display *display, Drawable d, char *filename,
559 unsigned int *width_return, unsigned int *height_return,
560 Pixmap *bitmap_return,
561 int *x_hot_return, int *y_hot_return)
565 if ((bitmap = Read_PCX_to_AllegroBitmap(filename)) == NULL)
566 return BitmapOpenFailed;
568 *width_return = bitmap->w;
569 *height_return = bitmap->h;
572 *bitmap_return = (Pixmap)bitmap;
574 return BitmapSuccess;
577 void XFreePixmap(Display *display, Pixmap pixmap)
579 if (pixmap != DUMMY_MASK &&
580 (is_memory_bitmap((BITMAP *)pixmap) ||
581 is_screen_bitmap((BITMAP *)pixmap)))
582 destroy_bitmap((BITMAP *)pixmap);
585 void XFreeGC(Display *display, GC gc)
589 gcv = (XGCValues *)gc;
594 void XCloseDisplay(Display *display)
596 BITMAP *bitmap = video_bitmap;
598 if (is_screen_bitmap(bitmap))
599 destroy_bitmap(bitmap);
601 if (display->screens)
602 free(display->screens);
607 /* return to text mode (or DOS box on Windows screen) */
608 set_gfx_mode(GFX_TEXT, 0, 0, 0, 0);
611 void XNextEvent(Display *display, XEvent *event_return)
613 while (!pending_events)
616 memcpy(event_return, &event_buffer[pending_events], sizeof(XEvent));
620 static void NewKeyEvent(int key_press_state, KeySym keysym)
624 if (pending_events >= MAX_EVENT_BUFFER)
628 xkey = (XKeyEvent *)&event_buffer[pending_events];
629 xkey->type = key_press_state;
630 xkey->state = (unsigned int)keysym;
633 #define HANDLE_RAW_KB_ALL_KEYS 0
634 #define HANDLE_RAW_KB_MODIFIER_KEYS_ONLY 1
636 static int modifier_scancode[] =
652 static void HandleKeyboardRaw(int mode)
656 for (i=0; i<MAX_SCANCODES; i++)
658 int scancode, new_state, event_type;
661 if (mode == HANDLE_RAW_KB_MODIFIER_KEYS_ONLY)
663 if ((scancode = modifier_scancode[i]) == -1)
669 key_pressed = key[scancode];
670 new_state = (key_pressed ? KeyPressMask : KeyReleaseMask);
671 event_type = (key_pressed ? KeyPress : KeyRelease);
673 if (key_press_state[i] == new_state) /* state not changed */
676 key_press_state[i] = new_state;
678 NewKeyEvent(event_type, ScancodeToKeySym(scancode));
682 static void HandleKeyboardEvent()
686 int key_info = readkey();
687 int scancode = (key_info >> 8);
688 int ascii = (key_info & 0xff);
689 KeySym keysym = ScancodeToKeySym(scancode);
691 if (scancode == KEY_PAD)
693 /* keys on the numeric keypad return just scancode 'KEY_PAD'
694 for some reason, so we must handle them separately */
696 if (ascii >= '0' && ascii <= '9')
697 keysym = XK_KP_0 + (KeySym)(ascii - '0');
698 else if (ascii == '.')
699 keysym = XK_KP_Separator;
702 NewKeyEvent(KeyPress, keysym);
704 else if (key_shifts & (KB_SHIFT_FLAG | KB_CTRL_FLAG | KB_ALT_FLAG))
706 /* the allegro function keypressed() does not give us single pressed
707 modifier keys, so we must detect them with the internal global
708 allegro variable 'key_shifts' and then handle them separately */
710 HandleKeyboardRaw(HANDLE_RAW_KB_MODIFIER_KEYS_ONLY);
714 int XPending(Display *display)
716 XButtonEvent *xbutton;
717 XMotionEvent *xmotion;
721 if (game_status == PLAYING)
722 HandleKeyboardRaw(HANDLE_RAW_KB_ALL_KEYS);
724 HandleKeyboardEvent();
726 /* mouse motion event */
727 /* generate mouse motion event only if any mouse buttons are pressed */
728 if (mouse_pos != last_mouse_pos && mouse_b)
730 last_mouse_pos = mouse_pos;
732 xmotion = (XMotionEvent *)&event_buffer[pending_events];
733 xmotion->type = MotionNotify;
734 xmotion->x = mouse_x - display->screens[display->default_screen].x;
735 xmotion->y = mouse_y - display->screens[display->default_screen].y;
738 /* mouse button event */
739 if (mouse_b != last_mouse_b)
741 for (i=1; i<4; i<<=1)
743 if ((last_mouse_b & i) != (mouse_b & i))
746 xbutton = (XButtonEvent *)&event_buffer[pending_events];
747 xbutton->type = (mouse_b & i ? ButtonPress : ButtonRelease);
749 xbutton->x = mouse_x - display->screens[display->default_screen].x;
750 xbutton->y = mouse_y - display->screens[display->default_screen].y;
753 last_mouse_b = mouse_b;
756 return pending_events;
759 KeySym XLookupKeysym(XKeyEvent *key_event, int index)
761 return key_event->state;
764 void sound_handler(struct SoundControl snd_ctrl)
768 if (snd_ctrl.fade_sound)
773 for (i=0; i<MAX_SOUNDS_PLAYING; i++)
774 if ((snd_ctrl.stop_all_sounds || playlist[i].nr == snd_ctrl.nr) &&
775 !playlist[i].fade_sound)
777 playlist[i].fade_sound = TRUE;
778 if (voice_check(playlist[i].voice))
779 voice_ramp_volume(playlist[i].voice, 1000, 0);
780 playlist[i].loop = PSND_NO_LOOP;
783 else if (snd_ctrl.stop_all_sounds)
787 SoundServer_StopAllSounds();
789 else if (snd_ctrl.stop_sound)
793 SoundServer_StopSound(snd_ctrl.nr);
796 for (i=0; i<MAX_SOUNDS_PLAYING; i++)
798 if (!playlist[i].active || playlist[i].loop)
801 playlist[i].playingpos = voice_get_position(playlist[i].voice);
802 playlist[i].volume = voice_get_volume(playlist[i].voice);
803 if (playlist[i].playingpos == -1 || !playlist[i].volume)
805 deallocate_voice(playlist[i].voice);
806 playlist[i] = emptySoundControl;
812 SoundServer_InsertNewSound(snd_ctrl);
815 void NetworkServer(int port, int serveronly)
817 Error(ERR_WARN, "networking not supported in DOS version");